and added files
[bcm963xx.git] / userapps / opensource / zebra / zebra / zebra_snmp.c
1 /* BGP4 SNMP support
2  * Copyright (C) 1999 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
22 #include <zebra.h>
23
24 #ifdef HAVE_SNMP
25 #include <asn1.h>
26 #include <snmp.h>
27 #include <snmp_impl.h>
28
29 #include "if.h"
30 #include "log.h"
31 #include "prefix.h"
32 #include "command.h"
33 #include "smux.h"
34 #include "table.h"
35
36 #include "zebra/rib.h"
37 \f
38 #define IPFWMIB 1,3,6,1,2,1,4,24
39 #define ZEBRAOID 1,3,6,1,4,1,3317,1,2,1
40
41 /* ipForwardTable */
42 #define IPFORWARDDEST                         1
43 #define IPFORWARDMASK                         2
44 #define IPFORWARDPOLICY                       3
45 #define IPFORWARDNEXTHOP                      4
46 #define IPFORWARDIFINDEX                      5
47 #define IPFORWARDTYPE                         6
48 #define IPFORWARDPROTO                        7
49 #define IPFORWARDAGE                          8
50 #define IPFORWARDINFO                         9
51 #define IPFORWARDNEXTHOPAS                   10
52 #define IPFORWARDMETRIC1                     11
53 #define IPFORWARDMETRIC2                     12
54 #define IPFORWARDMETRIC3                     13
55 #define IPFORWARDMETRIC4                     14
56 #define IPFORWARDMETRIC5                     15
57
58 /* ipCidrRouteTable */
59 #define IPCIDRROUTEDEST                       1
60 #define IPCIDRROUTEMASK                       2
61 #define IPCIDRROUTETOS                        3
62 #define IPCIDRROUTENEXTHOP                    4
63 #define IPCIDRROUTEIFINDEX                    5
64 #define IPCIDRROUTETYPE                       6
65 #define IPCIDRROUTEPROTO                      7
66 #define IPCIDRROUTEAGE                        8
67 #define IPCIDRROUTEINFO                       9
68 #define IPCIDRROUTENEXTHOPAS                 10
69 #define IPCIDRROUTEMETRIC1                   11
70 #define IPCIDRROUTEMETRIC2                   12
71 #define IPCIDRROUTEMETRIC3                   13
72 #define IPCIDRROUTEMETRIC4                   14
73 #define IPCIDRROUTEMETRIC5                   15
74 #define IPCIDRROUTESTATUS                    16
75
76 #define INTEGER32 ASN_INTEGER
77 #define GAUGE32 ASN_GAUGE
78 #define ENUMERATION ASN_INTEGER
79 #define ROWSTATUS ASN_INTEGER
80 #define IPADDRESS ASN_IPADDRESS
81 #define OBJECTIDENTIFIER ASN_OBJECT_ID
82 \f
83 oid ipfw_oid [] = { IPFWMIB };
84 oid zebra_oid [] = { ZEBRAOID };
85
86 /* Hook functions. */
87 u_char * ipFwNumber ();
88 u_char * ipFwTable ();
89 u_char * ipCidrNumber ();
90 u_char * ipCidrTable ();
91
92 struct variable zebra_variables[] = 
93 {
94   {0, GAUGE32, RONLY, ipFwNumber, 1, {1}},
95   {IPFORWARDDEST, IPADDRESS, RONLY, ipFwTable, 3, {2, 1, 1}},
96   {IPFORWARDMASK, IPADDRESS, RONLY, ipFwTable, 3, {2, 1, 2}},
97   {IPFORWARDPOLICY, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 3}},
98   {IPFORWARDNEXTHOP, IPADDRESS, RONLY, ipFwTable, 3, {2, 1, 4}},
99   {IPFORWARDIFINDEX, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 5}},
100   {IPFORWARDTYPE, ENUMERATION, RONLY, ipFwTable, 3, {2, 1, 6}},
101   {IPFORWARDPROTO, ENUMERATION, RONLY, ipFwTable, 3, {2, 1, 7}},
102   {IPFORWARDAGE, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 8}},
103   {IPFORWARDINFO, OBJECTIDENTIFIER, RONLY, ipFwTable, 3, {2, 1, 9}},
104   {IPFORWARDNEXTHOPAS, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 10}},
105   {IPFORWARDMETRIC1, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 11}},
106   {IPFORWARDMETRIC2, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 12}},
107   {IPFORWARDMETRIC3, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 13}},
108   {IPFORWARDMETRIC4, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 14}},
109   {IPFORWARDMETRIC5, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 15}},
110   {0, GAUGE32, RONLY, ipCidrNumber, 1, {3}},
111   {IPCIDRROUTEDEST, IPADDRESS, RONLY, ipCidrTable, 3, {4, 1, 1}},
112   {IPCIDRROUTEMASK, IPADDRESS, RONLY, ipCidrTable, 3, {4, 1, 2}},
113   {IPCIDRROUTETOS, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 3}},
114   {IPCIDRROUTENEXTHOP, IPADDRESS, RONLY, ipCidrTable, 3, {4, 1, 4}},
115   {IPCIDRROUTEIFINDEX, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 5}},
116   {IPCIDRROUTETYPE, ENUMERATION, RONLY, ipCidrTable, 3, {4, 1, 6}},
117   {IPCIDRROUTEPROTO, ENUMERATION, RONLY, ipCidrTable, 3, {4, 1, 7}},
118   {IPCIDRROUTEAGE, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 8}},
119   {IPCIDRROUTEINFO, OBJECTIDENTIFIER, RONLY, ipCidrTable, 3, {4, 1, 9}},
120   {IPCIDRROUTENEXTHOPAS, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 10}},
121   {IPCIDRROUTEMETRIC1, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 11}},
122   {IPCIDRROUTEMETRIC2, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 12}},
123   {IPCIDRROUTEMETRIC3, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 13}},
124   {IPCIDRROUTEMETRIC4, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 14}},
125   {IPCIDRROUTEMETRIC5, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 15}},
126   {IPCIDRROUTESTATUS, ROWSTATUS, RONLY, ipCidrTable, 3, {4, 1, 16}}
127 };
128
129 \f
130 u_char *
131 ipFwNumber (struct variable *v, oid objid[], size_t *objid_len,
132             int exact, size_t *val_len, WriteMethod **write_method)
133 {
134   static int result;
135   struct route_node *np;
136   struct rib *rib;
137
138   if (smux_header_generic(v, objid, objid_len, exact, val_len, write_method) == MATCH_FAILED)
139     return NULL;
140
141   /* Return number of routing entries. */
142   result = 0;
143   for (np = route_top (rib_table_ipv4); np; np = route_next (np))
144     for (rib = np->info; rib; rib = rib->next)
145       result++;
146
147   return (u_char *)&result;
148 }
149
150 u_char *
151 ipCidrNumber (struct variable *v, oid objid[], size_t *objid_len,
152             int exact, size_t *val_len, WriteMethod **write_method)
153 {
154   static int result;
155   struct route_node *np;
156   struct rib *rib;
157
158   if (smux_header_generic(v, objid, objid_len, exact, val_len, write_method) == MATCH_FAILED)
159     return NULL;
160
161   /* Return number of routing entries. */
162   result = 0;
163   for (np = route_top (rib_table_ipv4); np; np = route_next (np))
164     for (rib = np->info; rib; rib = rib->next)
165       result++;
166
167   return (u_char *)&result;
168 }
169
170 int
171 in_addr_cmp(u_char *p1, u_char *p2)
172 {
173   int i;
174
175   for (i=0; i<4; i++)
176     {
177       if (*p1 < *p2)
178         return -1;
179       if (*p1 > *p2)
180         return 1;
181       p1++; p2++;
182     }
183   return 0;
184 }
185
186 int 
187 in_addr_add(u_char *p, int num)
188 {
189   int i, ip0;
190
191   ip0 = *p;
192   p += 4;
193   for (i = 3; 0 <= i; i--) {
194     p--;
195     if (*p + num > 255) {
196         *p += num;
197         num = 1;
198     } else {
199         *p += num;
200         return 1;
201     }
202   }
203   if (ip0 > *p) {
204         /* ip + num > 0xffffffff */
205         return 0;
206   }
207   
208   return 1;
209 }
210
211 int proto_trans(int type)
212 {
213   switch (type)
214     {
215       case ZEBRA_ROUTE_SYSTEM:
216         return 1; /* other */
217       case ZEBRA_ROUTE_KERNEL:
218         return 1; /* other */
219       case ZEBRA_ROUTE_CONNECT:
220         return 2; /* local interface */
221       case ZEBRA_ROUTE_STATIC:
222         return 3; /* static route */
223       case ZEBRA_ROUTE_RIP:
224         return 8; /* rip */
225       case ZEBRA_ROUTE_RIPNG:
226         return 1; /* shouldn't happen */
227       case ZEBRA_ROUTE_OSPF:
228         return 13; /* ospf */
229       case ZEBRA_ROUTE_OSPF6:
230         return 1; /* shouldn't happen */
231       case ZEBRA_ROUTE_BGP:
232         return 14; /* bgp */
233       default:
234         return 1; /* other */
235     }
236 }
237
238 void
239 check_replace(struct route_node *np2, struct rib *rib2, 
240               struct route_node **np, struct rib **rib)
241 {
242   int proto, proto2;
243
244   if (!*np)
245     {
246       *np = np2;
247       *rib = rib2;
248       return;
249     }
250
251   if (in_addr_cmp(&(*np)->p.u.prefix, &np2->p.u.prefix) < 0)
252     return;
253   if (in_addr_cmp(&(*np)->p.u.prefix, &np2->p.u.prefix) > 0)
254     {
255       *np = np2;
256       *rib = rib2;
257       return;
258     }
259
260   proto = proto_trans((*rib)->type);
261   proto2 = proto_trans(rib2->type);
262
263   if (proto2 > proto)
264     return;
265   if (proto2 < proto)
266     {
267       *np = np2;
268       *rib = rib2;
269       return;
270     }
271
272   if (in_addr_cmp((u_char *)&(*rib)->nexthop->gate.ipv4, 
273                   (u_char *)&rib2->nexthop->gate.ipv4) <= 0)
274     return;
275
276   *np = np2;
277   *rib = rib2;
278   return;
279 }
280
281 void
282 get_fwtable_route_node(struct variable *v, oid objid[], size_t *objid_len, 
283                        int exact, struct route_node **np, struct rib **rib)
284 {
285   struct in_addr dest;
286   struct route_node *np2;
287   struct rib *rib2;
288   int proto;
289   int policy;
290   struct in_addr nexthop;
291   u_char *pnt;
292   int i;
293
294 /* Init index variables */
295
296   pnt = (u_char *) &dest;
297   for (i = 0; i < 4; i++)
298     *pnt++ = 0;
299
300   pnt = (u_char *) &nexthop;
301   for (i = 0; i < 4; i++)
302     *pnt++ = 0;
303
304   proto = 0;
305   policy = 0;
306  
307 /* Init return variables */
308
309   *np = NULL;
310   *rib = NULL;
311
312 /* Short circuit exact matches of wrong length */
313
314   if (exact && (*objid_len != v->namelen + 10))
315     return;
316
317 /* Get INDEX information out of OID.
318  * ipForwardDest, ipForwardProto, ipForwardPolicy, ipForwardNextHop
319  */
320
321   if (*objid_len > v->namelen)
322     oid2in_addr (objid + v->namelen, MIN(4, *objid_len - v->namelen), &dest);
323
324   if (*objid_len > v->namelen + 4)
325     proto = objid[v->namelen + 4];
326
327   if (*objid_len > v->namelen + 5)
328     policy = objid[v->namelen + 5];
329
330   if (*objid_len > v->namelen + 6)
331     oid2in_addr (objid + v->namelen + 6, MIN(4, *objid_len - v->namelen - 6),
332       &nexthop);
333
334   /* Apply GETNEXT on not exact search */
335
336   if (!exact && (*objid_len >= v->namelen + 10))
337     {
338       if (! in_addr_add((u_char *) &nexthop, 1)) 
339         return;
340     }
341
342   /* For exact: search matching entry in rib table. */
343
344   if (exact)
345     {
346       if (policy) /* Not supported (yet?) */
347         return;
348       for (*np = route_top (rib_table_ipv4); *np; *np = route_next (*np))
349         {
350           if (!in_addr_cmp(&(*np)->p.u.prefix, (u_char *)&dest))
351             {
352               for (*rib = (*np)->info; *rib; *rib = (*rib)->next)
353                 {
354                   if (!in_addr_cmp((u_char *)&(*rib)->nexthop->gate.ipv4,
355                     (u_char *)&nexthop))
356                     if (proto == proto_trans((*rib)->type))
357                       return;
358                 }
359             }
360         }
361       return;
362     }
363
364 /* Search next best entry */
365
366   for (np2 = route_top (rib_table_ipv4); np2; np2 = route_next (np2))
367     {
368
369       /* Check destination first */
370       if (in_addr_cmp(&np2->p.u.prefix, (u_char *)&dest) > 0)
371         for (rib2 = np2->info; rib2; rib2 = rib2->next)
372           check_replace(np2, rib2, np, rib);
373
374       if (in_addr_cmp(&np2->p.u.prefix, (u_char *)&dest) == 0)
375         { /* have to look at each rib individually */
376           for (rib2 = np2->info; rib2; rib2 = rib2->next)
377             {
378               int proto2, policy2;
379
380               proto2 = proto_trans(rib2->type);
381               policy2 = 0;
382
383               if ((policy < policy2)
384                   || ((policy == policy2) && (proto < proto2))
385                   || ((policy == policy2) && (proto == proto2)
386                       && (in_addr_cmp((u_char *)&rib2->nexthop->gate.ipv4,
387                                       (u_char *) &nexthop) >= 0)
388                       ))
389                 check_replace(np2, rib2, np, rib);
390             }
391         }
392     }
393
394   if (!*rib)
395     return;
396
397   policy = 0;
398   proto = proto_trans((*rib)->type);
399
400   *objid_len = v->namelen + 10;
401   pnt = (u_char *) &(*np)->p.u.prefix;
402   for (i = 0; i < 4; i++)
403     objid[v->namelen + i] = *pnt++;
404
405   objid[v->namelen + 4] = proto;
406   objid[v->namelen + 5] = policy;
407
408   {
409     struct nexthop *nexthop;
410
411     nexthop = (*rib)->nexthop;
412     if (nexthop)
413       {
414         pnt = (u_char *) &nexthop->gate.ipv4;
415         for (i = 0; i < 4; i++)
416           objid[i + v->namelen + 6] = *pnt++;
417       }
418   }
419
420   return;
421 }
422
423 u_char *
424 ipFwTable (struct variable *v, oid objid[], size_t *objid_len,
425            int exact, size_t *val_len, WriteMethod **write_method)
426 {
427   struct route_node *np;
428   struct rib *rib;
429   static int result;
430   static int resarr[2];
431   static struct in_addr netmask;
432   struct nexthop *nexthop;
433
434   get_fwtable_route_node(v, objid, objid_len, exact, &np, &rib);
435   if (!np)
436     return NULL;
437
438   nexthop = rib->nexthop;
439   if (! nexthop)
440     return NULL;
441
442   switch (v->magic)
443     {
444     case IPFORWARDDEST:
445       *val_len = 4;
446       return &np->p.u.prefix;
447       break;
448     case IPFORWARDMASK:
449       masklen2ip(np->p.prefixlen, &netmask);
450       *val_len = 4;
451       return (u_char *)&netmask;
452       break;
453     case IPFORWARDPOLICY:
454       result = 0;
455       *val_len  = sizeof(int);
456       return (u_char *)&result;
457       break;
458     case IPFORWARDNEXTHOP:
459       *val_len = 4;
460       return (u_char *)&nexthop->gate.ipv4;
461       break;
462     case IPFORWARDIFINDEX:
463       *val_len = sizeof(int);
464       return (u_char *)&nexthop->ifindex;
465       break;
466     case IPFORWARDTYPE:
467       if (nexthop->type == NEXTHOP_TYPE_IFINDEX
468           || nexthop->type == NEXTHOP_TYPE_IFNAME)
469         result = 3;
470       else
471         result = 4;
472       *val_len  = sizeof(int);
473       return (u_char *)&result;
474       break;
475     case IPFORWARDPROTO:
476       result = proto_trans(rib->type);
477       *val_len  = sizeof(int);
478       return (u_char *)&result;
479       break;
480     case IPFORWARDAGE:
481       result = 0;
482       *val_len  = sizeof(int);
483       return (u_char *)&result;
484       break;
485     case IPFORWARDINFO:
486       resarr[0] = 0;
487       resarr[1] = 0;
488       *val_len  = 2 * sizeof(int);
489       return (u_char *)resarr;
490       break;
491     case IPFORWARDNEXTHOPAS:
492       result = -1;
493       *val_len  = sizeof(int);
494       return (u_char *)&result;
495       break;
496     case IPFORWARDMETRIC1:
497       result = 0;
498       *val_len  = sizeof(int);
499       return (u_char *)&result;
500       break;
501     case IPFORWARDMETRIC2:
502       result = 0;
503       *val_len  = sizeof(int);
504       return (u_char *)&result;
505       break;
506     case IPFORWARDMETRIC3:
507       result = 0;
508       *val_len  = sizeof(int);
509       return (u_char *)&result;
510       break;
511     case IPFORWARDMETRIC4:
512       result = 0;
513       *val_len  = sizeof(int);
514       return (u_char *)&result;
515       break;
516     case IPFORWARDMETRIC5:
517       result = 0;
518       *val_len  = sizeof(int);
519       return (u_char *)&result;
520       break;
521     default:
522       return NULL;
523       break;
524     }  
525   return NULL;
526 }
527
528 u_char *
529 ipCidrTable (struct variable *v, oid objid[], size_t *objid_len,
530            int exact, size_t *val_len, WriteMethod **write_method)
531 {
532   switch (v->magic)
533     {
534     case IPCIDRROUTEDEST:
535       break;
536     default:
537       return NULL;
538       break;
539     }  
540   return NULL;
541 }
542
543 void
544 zebra_snmp_init ()
545 {
546   smux_init (zebra_oid, sizeof (zebra_oid) / sizeof (oid));
547   REGISTER_MIB("mibII/ipforward", zebra_variables, variable, ipfw_oid);
548   smux_start ();
549 }
550 #endif /* HAVE_SNMP */