Import Upstream version 1.2.2
[quagga-debian.git] / bgpd / bgp_snmp.c
1 /* BGP4 SNMP support
2    Copyright (C) 1999, 2000 Kunihiro Ishiguro
3
4 This file is part of GNU Zebra.
5
6 GNU Zebra is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
9 later version.
10
11 GNU Zebra is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Zebra; see the file COPYING.  If not, write to the Free
18 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 02111-1307, USA.  */
20
21 #include <zebra.h>
22
23 #ifdef HAVE_SNMP
24 #include <net-snmp/net-snmp-config.h>
25 #include <net-snmp/net-snmp-includes.h>
26
27 #include "if.h"
28 #include "log.h"
29 #include "prefix.h"
30 #include "command.h"
31 #include "thread.h"
32 #include "smux.h"
33 #include "filter.h"
34
35 #include "bgpd/bgpd.h"
36 #include "bgpd/bgp_table.h"
37 #include "bgpd/bgp_aspath.h"
38 #include "bgpd/bgp_attr.h"
39 #include "bgpd/bgp_route.h"
40 #include "bgpd/bgp_fsm.h"
41 #include "bgpd/bgp_snmp.h"
42
43 /* BGP4-MIB described in RFC1657. */
44 #define BGP4MIB 1,3,6,1,2,1,15
45
46 /* BGP TRAP. */
47 #define BGPESTABLISHED                  1
48 #define BGPBACKWARDTRANSITION           2       
49
50 /* BGP MIB bgpVersion. */
51 #define BGPVERSION                            0
52
53 /* BGP MIB bgpLocalAs. */
54 #define BGPLOCALAS                            0
55
56 /* BGP MIB bgpPeerTable. */
57 #define BGPPEERIDENTIFIER                     1
58 #define BGPPEERSTATE                          2
59 #define BGPPEERADMINSTATUS                    3
60 #define BGPPEERNEGOTIATEDVERSION              4
61 #define BGPPEERLOCALADDR                      5
62 #define BGPPEERLOCALPORT                      6
63 #define BGPPEERREMOTEADDR                     7
64 #define BGPPEERREMOTEPORT                     8
65 #define BGPPEERREMOTEAS                       9
66 #define BGPPEERINUPDATES                     10
67 #define BGPPEEROUTUPDATES                    11
68 #define BGPPEERINTOTALMESSAGES               12
69 #define BGPPEEROUTTOTALMESSAGES              13
70 #define BGPPEERLASTERROR                     14
71 #define BGPPEERFSMESTABLISHEDTRANSITIONS     15
72 #define BGPPEERFSMESTABLISHEDTIME            16
73 #define BGPPEERCONNECTRETRYINTERVAL          17
74 #define BGPPEERHOLDTIME                      18
75 #define BGPPEERKEEPALIVE                     19
76 #define BGPPEERHOLDTIMECONFIGURED            20
77 #define BGPPEERKEEPALIVECONFIGURED           21
78 #define BGPPEERMINROUTEADVERTISEMENTINTERVAL 22
79 #define BGPPEERINUPDATEELAPSEDTIME           23
80
81 /* BGP MIB bgpIdentifier. */
82 #define BGPIDENTIFIER                         0
83
84 /* BGP MIB bgpRcvdPathAttrTable */
85 #define BGPPATHATTRPEER                       1
86 #define BGPPATHATTRDESTNETWORK                2
87 #define BGPPATHATTRORIGIN                     3
88 #define BGPPATHATTRASPATH                     4
89 #define BGPPATHATTRNEXTHOP                    5
90 #define BGPPATHATTRINTERASMETRIC              6
91
92 /* BGP MIB bgp4PathAttrTable. */
93 #define BGP4PATHATTRPEER                      1
94 #define BGP4PATHATTRIPADDRPREFIXLEN           2
95 #define BGP4PATHATTRIPADDRPREFIX              3
96 #define BGP4PATHATTRORIGIN                    4
97 #define BGP4PATHATTRASPATHSEGMENT             5
98 #define BGP4PATHATTRNEXTHOP                   6
99 #define BGP4PATHATTRMULTIEXITDISC             7
100 #define BGP4PATHATTRLOCALPREF                 8
101 #define BGP4PATHATTRATOMICAGGREGATE           9
102 #define BGP4PATHATTRAGGREGATORAS             10
103 #define BGP4PATHATTRAGGREGATORADDR           11
104 #define BGP4PATHATTRCALCLOCALPREF            12
105 #define BGP4PATHATTRBEST                     13
106 #define BGP4PATHATTRUNKNOWN                  14
107
108 /* SNMP value hack. */
109 #define INTEGER ASN_INTEGER
110 #define INTEGER32 ASN_INTEGER
111 #define COUNTER32 ASN_COUNTER
112 #define OCTET_STRING ASN_OCTET_STR
113 #define IPADDRESS ASN_IPADDRESS
114 #define GAUGE32 ASN_UNSIGNED
115
116 /* Declare static local variables for convenience. */
117 SNMP_LOCAL_VARIABLES
118
119 /* BGP-MIB instances. */
120 oid bgp_oid [] = { BGP4MIB };
121 oid bgp_trap_oid [] = { BGP4MIB, 0 };
122
123 /* IP address 0.0.0.0. */
124 static struct in_addr bgp_empty_addr = { .s_addr = 0 };
125
126 /* Hook functions. */
127 static u_char *bgpVersion (struct variable *, oid [], size_t *, int,
128                            size_t *, WriteMethod **);
129 static u_char *bgpLocalAs (struct variable *, oid [], size_t *,
130                            int, size_t *, WriteMethod **);
131 static u_char *bgpPeerTable (struct variable *, oid [], size_t *,
132                              int, size_t *, WriteMethod **);
133 static u_char *bgpRcvdPathAttrTable (struct variable *, oid [], size_t *,
134                                      int, size_t *, WriteMethod **);
135 static u_char *bgpIdentifier (struct variable *, oid [], size_t *,
136                               int, size_t *, WriteMethod **);
137 static u_char *bgp4PathAttrTable (struct variable *, oid [], size_t *,
138                                   int, size_t *, WriteMethod **);
139 /* static u_char *bgpTraps (); */
140
141 struct variable bgp_variables[] = 
142 {
143   /* BGP version. */
144   {BGPVERSION,                OCTET_STRING, RONLY, bgpVersion,
145    1, {1}},
146   /* BGP local AS. */
147   {BGPLOCALAS,                INTEGER, RONLY, bgpLocalAs,
148    1, {2}},
149   /* BGP peer table. */
150   {BGPPEERIDENTIFIER,         IPADDRESS, RONLY, bgpPeerTable,
151    3, {3, 1, 1}},
152   {BGPPEERSTATE,              INTEGER, RONLY, bgpPeerTable,
153    3, {3, 1, 2}},
154   {BGPPEERADMINSTATUS,        INTEGER, RWRITE, bgpPeerTable,
155    3, {3, 1, 3}},
156   {BGPPEERNEGOTIATEDVERSION,  INTEGER32, RONLY, bgpPeerTable,
157    3, {3, 1, 4}},
158   {BGPPEERLOCALADDR,          IPADDRESS, RONLY, bgpPeerTable,
159    3, {3, 1, 5}},
160   {BGPPEERLOCALPORT,          INTEGER, RONLY, bgpPeerTable,
161    3, {3, 1, 6}},
162   {BGPPEERREMOTEADDR,         IPADDRESS, RONLY, bgpPeerTable,
163    3, {3, 1, 7}},
164   {BGPPEERREMOTEPORT,         INTEGER, RONLY, bgpPeerTable,
165    3, {3, 1, 8}},
166   {BGPPEERREMOTEAS,           INTEGER, RONLY, bgpPeerTable,
167    3, {3, 1, 9}},
168   {BGPPEERINUPDATES,          COUNTER32, RONLY, bgpPeerTable,
169    3, {3, 1, 10}},
170   {BGPPEEROUTUPDATES,         COUNTER32, RONLY, bgpPeerTable,
171    3, {3, 1, 11}},
172   {BGPPEERINTOTALMESSAGES,    COUNTER32, RONLY, bgpPeerTable,
173    3, {3, 1, 12}},
174   {BGPPEEROUTTOTALMESSAGES,   COUNTER32, RONLY, bgpPeerTable,
175    3, {3, 1, 13}},
176   {BGPPEERLASTERROR,          OCTET_STRING, RONLY, bgpPeerTable,
177    3, {3, 1, 14}},
178   {BGPPEERFSMESTABLISHEDTRANSITIONS, COUNTER32, RONLY, bgpPeerTable,
179    3, {3, 1, 15}},
180   {BGPPEERFSMESTABLISHEDTIME, GAUGE32, RONLY, bgpPeerTable,
181    3, {3, 1, 16}},
182   {BGPPEERCONNECTRETRYINTERVAL, INTEGER, RWRITE, bgpPeerTable,
183    3, {3, 1, 17}},
184   {BGPPEERHOLDTIME,           INTEGER, RONLY, bgpPeerTable,
185    3, {3, 1, 18}},
186   {BGPPEERKEEPALIVE,          INTEGER, RONLY, bgpPeerTable,
187    3, {3, 1, 19}},
188   {BGPPEERHOLDTIMECONFIGURED, INTEGER, RWRITE, bgpPeerTable,
189    3, {3, 1, 20}},
190   {BGPPEERKEEPALIVECONFIGURED, INTEGER, RWRITE, bgpPeerTable,
191    3, {3, 1, 21}},
192   {BGPPEERMINROUTEADVERTISEMENTINTERVAL, INTEGER, RWRITE, bgpPeerTable,
193    3, {3, 1, 23}},
194   {BGPPEERINUPDATEELAPSEDTIME, GAUGE32, RONLY, bgpPeerTable,
195    3, {3, 1, 24}},
196   /* BGP identifier. */
197   {BGPIDENTIFIER,             IPADDRESS, RONLY, bgpIdentifier,
198    1, {4}},
199   /* BGP received path attribute table. */
200   {BGPPATHATTRPEER,           IPADDRESS, RONLY, bgpRcvdPathAttrTable,
201    3, {5, 1, 1}},
202   {BGPPATHATTRDESTNETWORK,    IPADDRESS, RONLY, bgpRcvdPathAttrTable,
203    3, {5, 1, 2}},
204   {BGPPATHATTRORIGIN,         INTEGER, RONLY, bgpRcvdPathAttrTable,
205    3, {5, 1, 3}},
206   {BGPPATHATTRASPATH,         OCTET_STRING, RONLY, bgpRcvdPathAttrTable,
207    3, {5, 1, 4}},
208   {BGPPATHATTRNEXTHOP,        IPADDRESS, RONLY, bgpRcvdPathAttrTable,
209    3, {5, 1, 5}},
210   {BGPPATHATTRINTERASMETRIC,  INTEGER32, RONLY, bgpRcvdPathAttrTable,
211    3, {5, 1, 6}},
212   /* BGP-4 received path attribute table. */
213   {BGP4PATHATTRPEER, IPADDRESS, RONLY, bgp4PathAttrTable,
214    3, {6, 1, 1}},
215   {BGP4PATHATTRIPADDRPREFIXLEN, INTEGER, RONLY, bgp4PathAttrTable,
216    3, {6, 1, 2}},
217   {BGP4PATHATTRIPADDRPREFIX,  IPADDRESS, RONLY, bgp4PathAttrTable,
218    3, {6, 1, 3}},
219   {BGP4PATHATTRORIGIN,        INTEGER, RONLY, bgp4PathAttrTable,
220    3, {6, 1, 4}},
221   {BGP4PATHATTRASPATHSEGMENT, OCTET_STRING, RONLY, bgp4PathAttrTable,
222    3, {6, 1, 5}},
223   {BGP4PATHATTRNEXTHOP,       IPADDRESS, RONLY, bgp4PathAttrTable,
224    3, {6, 1, 6}},
225   {BGP4PATHATTRMULTIEXITDISC, INTEGER, RONLY, bgp4PathAttrTable,
226    3, {6, 1, 7}},
227   {BGP4PATHATTRLOCALPREF,     INTEGER, RONLY, bgp4PathAttrTable,
228    3, {6, 1, 8}},
229   {BGP4PATHATTRATOMICAGGREGATE, INTEGER, RONLY, bgp4PathAttrTable,
230    3, {6, 1, 9}},
231   {BGP4PATHATTRAGGREGATORAS,  INTEGER, RONLY, bgp4PathAttrTable,
232    3, {6, 1, 10}},
233   {BGP4PATHATTRAGGREGATORADDR, IPADDRESS, RONLY, bgp4PathAttrTable,
234    3, {6, 1, 11}},
235   {BGP4PATHATTRCALCLOCALPREF, INTEGER, RONLY, bgp4PathAttrTable,
236    3, {6, 1, 12}},
237   {BGP4PATHATTRBEST,          INTEGER, RONLY, bgp4PathAttrTable,
238    3, {6, 1, 13}},
239   {BGP4PATHATTRUNKNOWN,       OCTET_STRING, RONLY, bgp4PathAttrTable,
240    3, {6, 1, 14}},
241 };
242
243
244 static u_char *
245 bgpVersion (struct variable *v, oid name[], size_t *length, int exact,
246             size_t *var_len, WriteMethod **write_method)
247 {
248   static u_char version;
249
250   if (smux_header_generic(v, name, length, exact, var_len, write_method)
251       == MATCH_FAILED)
252     return NULL;
253
254   /* Retrun BGP version.  Zebra bgpd only support version 4. */
255   version = (0x80 >> (BGP_VERSION_4 - 1));
256
257   /* Return octet string length 1. */
258   *var_len = 1;
259   return (u_char *)&version;
260 }
261
262 static u_char *
263 bgpLocalAs (struct variable *v, oid name[], size_t *length,
264             int exact, size_t *var_len, WriteMethod **write_method)
265 {
266   struct bgp *bgp;
267
268   if (smux_header_generic(v, name, length, exact, var_len, write_method)
269       == MATCH_FAILED)
270     return NULL;
271
272   /* Get BGP structure. */
273   bgp = bgp_get_default ();
274   if (! bgp)
275     return NULL;
276
277   return SNMP_INTEGER (bgp->as);
278 }
279
280 static struct peer *
281 peer_lookup_addr_ipv4 (struct in_addr *src)
282 {
283   struct bgp *bgp;
284   struct peer *peer;
285   struct listnode *node;
286   struct in_addr addr;
287   int ret;
288
289   bgp = bgp_get_default ();
290   if (! bgp)
291     return NULL;
292
293   for (ALL_LIST_ELEMENTS_RO (bgp->peer, node, peer))
294     {
295       ret = inet_pton (AF_INET, peer->host, &addr);
296       if (ret > 0)
297         {
298           if (IPV4_ADDR_SAME (&addr, src))
299             return peer;
300         }
301     }
302   return NULL;
303 }
304
305 static struct peer *
306 bgp_peer_lookup_next (struct in_addr *src)
307 {
308   struct bgp *bgp;
309   struct peer *peer;
310   struct listnode *node;
311   struct in_addr *p;
312   union sockunion su;
313   int ret;
314
315   memset (&su, 0, sizeof (union sockunion));
316
317   bgp = bgp_get_default ();
318   if (! bgp)
319     return NULL;
320
321   for (ALL_LIST_ELEMENTS_RO (bgp->peer, node, peer))
322     {
323       ret = inet_pton (AF_INET, peer->host, &su.sin.sin_addr);
324       if (ret > 0)
325         {
326           p = &su.sin.sin_addr;
327
328           if (ntohl (p->s_addr) > ntohl (src->s_addr))
329             {
330               src->s_addr = p->s_addr;
331               return peer;
332             }
333         }
334     }
335   return NULL;
336 }
337
338 /* 1.3.6.1.2.1.15.3.1.x  = 10 */
339 #define PEERTAB_NAMELEN 10
340
341 static struct peer *
342 bgpPeerTable_lookup (struct variable *v, oid name[], size_t *length, 
343                      struct in_addr *addr, int exact)
344 {
345   struct peer *peer = NULL;
346   size_t namelen = v ? v->namelen : PEERTAB_NAMELEN;
347   int len;
348
349   if (exact)
350     {
351       /* Check the length. */
352       if (*length - namelen != sizeof (struct in_addr))
353         return NULL;
354
355       oid2in_addr (name + namelen, IN_ADDR_SIZE, addr);
356
357       peer = peer_lookup_addr_ipv4 (addr);
358       return peer;
359     }
360   else
361     {
362       len = *length - namelen;
363       if (len > 4) len = 4;
364       
365       oid2in_addr (name + namelen, len, addr);
366       
367       peer = bgp_peer_lookup_next (addr);
368
369       if (peer == NULL)
370         return NULL;
371
372       oid_copy_addr (name + namelen, addr, sizeof (struct in_addr));
373       *length = sizeof (struct in_addr) + namelen;
374
375       return peer;
376     }
377   return NULL;
378 }
379
380 /* BGP write methods. */
381 static int
382 write_bgpPeerTable (int action, u_char *var_val,
383                     u_char var_val_type, size_t var_val_len,
384                     u_char *statP, oid *name, size_t length)
385 {
386   struct in_addr addr;
387   struct peer *peer;
388   long intval;
389
390   if (var_val_type != ASN_INTEGER) 
391     {
392       return SNMP_ERR_WRONGTYPE;
393     }
394   if (var_val_len != sizeof (long)) 
395     {
396       return SNMP_ERR_WRONGLENGTH;
397     }
398
399   intval = *(long *)var_val;
400
401   memset (&addr, 0, sizeof (struct in_addr));
402
403   peer = bgpPeerTable_lookup (NULL, name, &length, &addr, 1);
404   if (! peer)
405     return SNMP_ERR_NOSUCHNAME;
406
407   if (action != SNMP_MSG_INTERNAL_SET_COMMIT)
408     return SNMP_ERR_NOERROR;
409
410   zlog_info ("%s: SNMP write .%ld = %ld",
411              peer->host, (long)name[PEERTAB_NAMELEN - 1], intval);
412
413   switch (name[PEERTAB_NAMELEN - 1])
414     {
415     case BGPPEERADMINSTATUS:
416 #define BGP_PeerAdmin_stop  1
417 #define BGP_PeerAdmin_start 2
418       /* When the peer is established,   */
419       if (intval == BGP_PeerAdmin_stop)
420         BGP_EVENT_ADD (peer, BGP_Stop);
421       else if (intval == BGP_PeerAdmin_start)
422         ;                       /* Do nothing. */
423       else
424         return SNMP_ERR_NOSUCHNAME;
425       break;
426     case BGPPEERCONNECTRETRYINTERVAL:
427       SET_FLAG (peer->config, PEER_CONFIG_CONNECT);
428       peer->connect = intval;
429       peer->v_connect = intval;
430       break;
431     case BGPPEERHOLDTIMECONFIGURED:
432       SET_FLAG (peer->config, PEER_CONFIG_TIMER);
433       peer->holdtime = intval;
434       peer->v_holdtime = intval;
435       break;
436     case BGPPEERKEEPALIVECONFIGURED:
437       SET_FLAG (peer->config, PEER_CONFIG_TIMER);
438       peer->keepalive = intval;
439       peer->v_keepalive = intval;
440       break;
441     case BGPPEERMINROUTEADVERTISEMENTINTERVAL:
442       peer->v_routeadv = intval;
443       break;
444     }
445   return SNMP_ERR_NOERROR;
446 }
447
448 static u_char *
449 bgpPeerTable (struct variable *v, oid name[], size_t *length,
450               int exact, size_t *var_len, WriteMethod **write_method)
451 {
452   static struct in_addr addr;
453   struct peer *peer;
454
455   if (smux_header_table(v, name, length, exact, var_len, write_method)
456       == MATCH_FAILED)
457     return NULL;
458   memset (&addr, 0, sizeof (struct in_addr));
459
460   peer = bgpPeerTable_lookup (v, name, length, &addr, exact);
461   if (! peer)
462     return NULL;
463
464   switch (v->magic)
465     {
466     case BGPPEERIDENTIFIER:
467       return SNMP_IPADDRESS (peer->remote_id);
468       break;
469     case BGPPEERSTATE:
470       return SNMP_INTEGER (peer->status);
471       break;
472     case BGPPEERADMINSTATUS:
473       *write_method = write_bgpPeerTable;
474 #define BGP_PeerAdmin_stop  1
475 #define BGP_PeerAdmin_start 2
476       if (CHECK_FLAG (peer->flags, PEER_FLAG_SHUTDOWN))
477         return SNMP_INTEGER (BGP_PeerAdmin_stop);
478       else
479         return SNMP_INTEGER (BGP_PeerAdmin_start);
480       break;
481     case BGPPEERNEGOTIATEDVERSION:
482       return SNMP_INTEGER (BGP_VERSION_4);
483       break;
484     case BGPPEERLOCALADDR:
485       if (peer->su_local)
486         return SNMP_IPADDRESS (peer->su_local->sin.sin_addr);
487       else
488         return SNMP_IPADDRESS (bgp_empty_addr);
489       break;
490     case BGPPEERLOCALPORT:
491       if (peer->su_local)
492         return SNMP_INTEGER (ntohs (peer->su_local->sin.sin_port));
493       else
494         return SNMP_INTEGER (0);
495       break;
496     case BGPPEERREMOTEADDR:
497       if (peer->su_remote)
498         return SNMP_IPADDRESS (peer->su_remote->sin.sin_addr);
499       else
500         return SNMP_IPADDRESS (bgp_empty_addr);
501       break;
502     case BGPPEERREMOTEPORT:
503       if (peer->su_remote)
504         return SNMP_INTEGER (ntohs (peer->su_remote->sin.sin_port));
505       else
506         return SNMP_INTEGER (0);
507       break;
508     case BGPPEERREMOTEAS:
509       return SNMP_INTEGER (peer->as);
510       break;
511     case BGPPEERINUPDATES:
512       return SNMP_INTEGER (peer->update_in);
513       break;
514     case BGPPEEROUTUPDATES:
515       return SNMP_INTEGER (peer->update_out);
516       break;
517     case BGPPEERINTOTALMESSAGES:
518       return SNMP_INTEGER (peer->open_in + peer->update_in
519                            + peer->keepalive_in + peer->notify_in
520                            + peer->refresh_in + peer->dynamic_cap_in);
521       break;
522     case BGPPEEROUTTOTALMESSAGES:
523       return SNMP_INTEGER (peer->open_out + peer->update_out
524                            + peer->keepalive_out + peer->notify_out
525                            + peer->refresh_out + peer->dynamic_cap_out);
526       break;
527     case BGPPEERLASTERROR:
528       {
529         static u_char lasterror[2];
530         lasterror[0] = peer->notify.code;
531         lasterror[1] = peer->notify.subcode;
532         *var_len = 2;
533         return (u_char *)&lasterror;
534       }
535       break;
536     case BGPPEERFSMESTABLISHEDTRANSITIONS:
537       return SNMP_INTEGER (peer->established);
538       break;
539     case BGPPEERFSMESTABLISHEDTIME:
540       if (peer->uptime == 0)
541         return SNMP_INTEGER (0);
542       else
543         return SNMP_INTEGER (bgp_clock () - peer->uptime);
544       break;
545     case BGPPEERCONNECTRETRYINTERVAL:
546       *write_method = write_bgpPeerTable;
547       return SNMP_INTEGER (peer->v_connect);
548       break;
549     case BGPPEERHOLDTIME:
550       return SNMP_INTEGER (peer->v_holdtime);
551       break;
552     case BGPPEERKEEPALIVE:
553       return SNMP_INTEGER (peer->v_keepalive);
554       break;
555     case BGPPEERHOLDTIMECONFIGURED:
556       *write_method = write_bgpPeerTable;
557       if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER))
558         return SNMP_INTEGER (peer->holdtime);
559       else
560         return SNMP_INTEGER (peer->v_holdtime);
561       break;
562     case BGPPEERKEEPALIVECONFIGURED:
563       *write_method = write_bgpPeerTable;
564       if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER))
565         return SNMP_INTEGER (peer->keepalive);
566       else
567         return SNMP_INTEGER (peer->v_keepalive);
568       break;
569     case BGPPEERMINROUTEADVERTISEMENTINTERVAL:
570       *write_method = write_bgpPeerTable;
571       return SNMP_INTEGER (peer->v_routeadv);
572       break;
573     case BGPPEERINUPDATEELAPSEDTIME:
574       if (peer->update_time == 0)
575         return SNMP_INTEGER (0);
576       else
577         return SNMP_INTEGER (bgp_clock () - peer->update_time);
578       break;
579     default:
580       return NULL;
581       break;
582     }  
583   return NULL;
584 }
585
586 static u_char *
587 bgpIdentifier (struct variable *v, oid name[], size_t *length,
588                int exact, size_t *var_len, WriteMethod **write_method)
589 {
590   struct bgp *bgp;
591
592   if (smux_header_generic(v, name, length, exact, var_len, write_method)
593       == MATCH_FAILED)
594     return NULL;
595
596   bgp = bgp_get_default ();
597   if (!bgp)
598     return NULL;
599
600   return SNMP_IPADDRESS (bgp->router_id);
601 }
602
603 static u_char *
604 bgpRcvdPathAttrTable (struct variable *v, oid name[], size_t *length,
605                       int exact, size_t *var_len, WriteMethod **write_method)
606 {
607   /* Received Path Attribute Table.  This table contains, one entry
608      per path to a network, path attributes received from all peers
609      running BGP version 3 or less.  This table is obsolete, having
610      been replaced in functionality with the bgp4PathAttrTable.  */
611   return NULL;
612 }
613
614 static struct bgp_info *
615 bgp4PathAttrLookup (struct variable *v, oid name[], size_t *length,
616                     struct bgp *bgp, struct prefix_ipv4 *addr, int exact)
617 {
618   oid *offset;
619   int offsetlen;
620   struct bgp_info *binfo;
621   struct bgp_info *min;
622   struct bgp_node *rn;
623   union sockunion su;
624   unsigned int len;
625   struct in_addr paddr;
626
627 #define BGP_PATHATTR_ENTRY_OFFSET \
628           (IN_ADDR_SIZE + 1 + IN_ADDR_SIZE)
629
630   if (exact)
631     {
632       if (*length - v->namelen != BGP_PATHATTR_ENTRY_OFFSET)
633         return NULL;
634
635       /* Set OID offset for prefix. */
636       offset = name + v->namelen;
637       oid2in_addr (offset, IN_ADDR_SIZE, &addr->prefix);
638       offset += IN_ADDR_SIZE;
639
640       /* Prefix length. */
641       addr->prefixlen = *offset;
642       offset++;
643
644       /* Peer address. */
645       su.sin.sin_family = AF_INET;
646       oid2in_addr (offset, IN_ADDR_SIZE, &su.sin.sin_addr);
647
648       /* Lookup node. */
649       rn = bgp_node_lookup (bgp->rib[AFI_IP][SAFI_UNICAST], 
650                               (struct prefix *) addr);
651       if (rn)
652         {
653           bgp_unlock_node (rn);
654
655           for (binfo = rn->info; binfo; binfo = binfo->next)
656             if (sockunion_same (&binfo->peer->su, &su))
657               return binfo;
658         }
659     }
660   else
661     {
662       offset = name + v->namelen;
663       offsetlen = *length - v->namelen;
664       len = offsetlen;
665
666       if (offsetlen == 0)
667         rn = bgp_table_top (bgp->rib[AFI_IP][SAFI_UNICAST]);
668       else
669         {
670           if (len > IN_ADDR_SIZE)
671             len = IN_ADDR_SIZE;
672       
673           oid2in_addr (offset, len, &addr->prefix);
674
675           offset += IN_ADDR_SIZE;
676           offsetlen -= IN_ADDR_SIZE;
677
678           if (offsetlen > 0)
679             addr->prefixlen = *offset;
680           else
681             addr->prefixlen = len * 8;
682
683           rn = bgp_node_get (bgp->rib[AFI_IP][SAFI_UNICAST],
684                                (struct prefix *) addr);
685
686           offset++;
687           offsetlen--;
688         }
689
690       if (offsetlen > 0)
691         {
692           len = offsetlen;
693           if (len > IN_ADDR_SIZE)
694             len = IN_ADDR_SIZE;
695
696           oid2in_addr (offset, len, &paddr);
697         }
698       else
699         paddr.s_addr = 0;
700
701       if (! rn)
702         return NULL;
703
704       do
705         {
706           min = NULL;
707
708           for (binfo = rn->info; binfo; binfo = binfo->next)
709             {
710               if (binfo->peer->su.sin.sin_family == AF_INET
711                   && ntohl (paddr.s_addr) 
712                   < ntohl (binfo->peer->su.sin.sin_addr.s_addr))
713                 {
714                   if (min)
715                     {
716                       if (ntohl (binfo->peer->su.sin.sin_addr.s_addr) 
717                           < ntohl (min->peer->su.sin.sin_addr.s_addr))
718                         min = binfo;
719                     }
720                   else
721                     min = binfo;
722                 }
723             }
724
725           if (min)
726             {
727               *length = v->namelen + BGP_PATHATTR_ENTRY_OFFSET;
728
729               offset = name + v->namelen;
730               oid_copy_addr (offset, &rn->p.u.prefix4, IN_ADDR_SIZE);
731               offset += IN_ADDR_SIZE;
732               *offset = rn->p.prefixlen;
733               offset++;
734               oid_copy_addr (offset, &min->peer->su.sin.sin_addr, 
735                              IN_ADDR_SIZE);
736               addr->prefix = rn->p.u.prefix4;
737               addr->prefixlen = rn->p.prefixlen;
738
739               bgp_unlock_node (rn);
740
741               return min;
742             }
743
744           paddr.s_addr = 0;
745         }
746       while ((rn = bgp_route_next (rn)) != NULL);
747     }
748   return NULL;
749 }
750
751 static u_char *
752 bgp4PathAttrTable (struct variable *v, oid name[], size_t *length,
753                    int exact, size_t *var_len, WriteMethod **write_method)
754 {
755   struct bgp *bgp;
756   struct bgp_info *binfo;
757   struct prefix_ipv4 addr;
758   
759   bgp = bgp_get_default ();
760   if (! bgp)
761     return NULL;
762
763   if (smux_header_table(v, name, length, exact, var_len, write_method)
764       == MATCH_FAILED)
765     return NULL;
766   memset (&addr, 0, sizeof (struct prefix_ipv4));
767
768   binfo = bgp4PathAttrLookup (v, name, length, bgp, &addr, exact);
769   if (! binfo)
770     return NULL;
771
772   switch (v->magic)
773     {
774     case BGP4PATHATTRPEER:      /* 1 */
775       return SNMP_IPADDRESS (binfo->peer->su.sin.sin_addr);
776       break;
777     case BGP4PATHATTRIPADDRPREFIXLEN: /* 2 */
778       return SNMP_INTEGER (addr.prefixlen);
779       break;
780     case BGP4PATHATTRIPADDRPREFIX: /* 3 */
781       return SNMP_IPADDRESS (addr.prefix);
782       break;
783     case BGP4PATHATTRORIGIN:    /* 4 */
784       return SNMP_INTEGER (binfo->attr->origin);
785       break;
786     case BGP4PATHATTRASPATHSEGMENT: /* 5 */
787       return aspath_snmp_pathseg (binfo->attr->aspath, var_len);
788       break;
789     case BGP4PATHATTRNEXTHOP:   /* 6 */
790       return SNMP_IPADDRESS (binfo->attr->nexthop);
791       break;
792     case BGP4PATHATTRMULTIEXITDISC: /* 7 */
793       return SNMP_INTEGER (binfo->attr->med);
794       break;
795     case BGP4PATHATTRLOCALPREF: /* 8 */
796       return SNMP_INTEGER (binfo->attr->local_pref);
797       break;
798     case BGP4PATHATTRATOMICAGGREGATE: /* 9 */
799       return SNMP_INTEGER (1);
800       break;
801     case BGP4PATHATTRAGGREGATORAS: /* 10 */
802       if (binfo->attr->extra)
803         return SNMP_INTEGER (binfo->attr->extra->aggregator_as);
804       else
805         return SNMP_INTEGER (0);
806       break;
807     case BGP4PATHATTRAGGREGATORADDR: /* 11 */
808       if (binfo->attr->extra)
809         return SNMP_IPADDRESS (binfo->attr->extra->aggregator_addr);
810       else
811         return SNMP_INTEGER (0);
812       break;
813     case BGP4PATHATTRCALCLOCALPREF: /* 12 */
814       return SNMP_INTEGER (-1);
815       break;
816     case BGP4PATHATTRBEST:      /* 13 */
817 #define BGP4_PathAttrBest_false 1
818 #define BGP4_PathAttrBest_true  2
819       if (CHECK_FLAG (binfo->flags, BGP_INFO_SELECTED))
820         return SNMP_INTEGER (BGP4_PathAttrBest_true);
821       else
822         return SNMP_INTEGER (BGP4_PathAttrBest_false);
823       break;
824     case BGP4PATHATTRUNKNOWN:   /* 14 */
825       *var_len = 0;
826       return NULL;
827       break;
828     }
829   return NULL;
830 }
831
832 /* BGP Traps. */
833 struct trap_object bgpTrapList[] =
834 {
835   {3, {3, 1, BGPPEERLASTERROR}},
836   {3, {3, 1, BGPPEERSTATE}}
837 };
838
839 void
840 bgpTrapEstablished (struct peer *peer)
841 {
842   int ret;
843   struct in_addr addr;
844   oid index[sizeof (oid) * IN_ADDR_SIZE];
845
846   ret = inet_aton (peer->host, &addr);
847   if (ret == 0)
848     return;
849
850   oid_copy_addr (index, &addr, IN_ADDR_SIZE);
851
852   smux_trap (bgp_variables, sizeof bgp_variables / sizeof (struct variable),
853              bgp_trap_oid, sizeof bgp_trap_oid / sizeof (oid),
854              bgp_oid, sizeof bgp_oid / sizeof (oid),
855              index, IN_ADDR_SIZE,
856              bgpTrapList, sizeof bgpTrapList / sizeof (struct trap_object),
857              BGPESTABLISHED);
858 }
859
860 void
861 bgpTrapBackwardTransition (struct peer *peer)
862 {
863   int ret;
864   struct in_addr addr;
865   oid index[sizeof (oid) * IN_ADDR_SIZE];
866
867   ret = inet_aton (peer->host, &addr);
868   if (ret == 0)
869     return;
870
871   oid_copy_addr (index, &addr, IN_ADDR_SIZE);
872
873   smux_trap (bgp_variables, sizeof bgp_variables / sizeof (struct variable),
874              bgp_trap_oid, sizeof bgp_trap_oid / sizeof (oid),
875              bgp_oid, sizeof bgp_oid / sizeof (oid),
876              index, IN_ADDR_SIZE,
877              bgpTrapList, sizeof bgpTrapList / sizeof (struct trap_object),
878              BGPBACKWARDTRANSITION);
879 }
880
881 void
882 bgp_snmp_init (void)
883 {
884   smux_init (bm->master);
885   REGISTER_MIB("mibII/bgp", bgp_variables, variable, bgp_oid);
886 }
887 #endif /* HAVE_SNMP */