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