Import Upstream version 1.2.2
[quagga-debian.git] / ripd / rip_snmp.c
1 /* RIP SNMP support
2  * Copyright (C) 1999 Kunihiro Ishiguro <kunihiro@zebra.org>
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 <net-snmp/net-snmp-config.h>
26 #include <net-snmp/net-snmp-includes.h>
27
28 #include "if.h"
29 #include "log.h"
30 #include "prefix.h"
31 #include "command.h"
32 #include "table.h"
33 #include "smux.h"
34
35 #include "ripd/ripd.h"
36
37 /* RIPv2-MIB. */
38 #define RIPV2MIB 1,3,6,1,2,1,23
39
40 /* RIPv2-MIB rip2Globals values. */
41 #define RIP2GLOBALROUTECHANGES  1
42 #define RIP2GLOBALQUERIES       2
43
44 /* RIPv2-MIB rip2IfStatEntry. */
45 #define RIP2IFSTATENTRY         1
46
47 /* RIPv2-MIB rip2IfStatTable. */
48 #define RIP2IFSTATADDRESS       1
49 #define RIP2IFSTATRCVBADPACKETS 2
50 #define RIP2IFSTATRCVBADROUTES  3
51 #define RIP2IFSTATSENTUPDATES   4
52 #define RIP2IFSTATSTATUS        5
53
54 /* RIPv2-MIB rip2IfConfTable. */
55 #define RIP2IFCONFADDRESS       1
56 #define RIP2IFCONFDOMAIN        2
57 #define RIP2IFCONFAUTHTYPE      3
58 #define RIP2IFCONFAUTHKEY       4
59 #define RIP2IFCONFSEND          5
60 #define RIP2IFCONFRECEIVE       6
61 #define RIP2IFCONFDEFAULTMETRIC 7
62 #define RIP2IFCONFSTATUS        8
63 #define RIP2IFCONFSRCADDRESS    9
64
65 /* RIPv2-MIB rip2PeerTable. */
66 #define RIP2PEERADDRESS         1
67 #define RIP2PEERDOMAIN          2
68 #define RIP2PEERLASTUPDATE      3
69 #define RIP2PEERVERSION         4
70 #define RIP2PEERRCVBADPACKETS   5
71 #define RIP2PEERRCVBADROUTES    6
72
73 /* SNMP value hack. */
74 #define COUNTER     ASN_COUNTER
75 #define INTEGER     ASN_INTEGER
76 #define TIMETICKS   ASN_TIMETICKS
77 #define IPADDRESS   ASN_IPADDRESS
78 #define STRING      ASN_OCTET_STR
79
80 /* Define SNMP local variables. */
81 SNMP_LOCAL_VARIABLES
82
83 /* RIP-MIB instances. */
84 oid rip_oid [] = { RIPV2MIB };
85
86 /* Interface cache table sorted by interface's address. */
87 struct route_table *rip_ifaddr_table;
88
89 /* Hook functions. */
90 static u_char *rip2Globals (struct variable *, oid [], size_t *,
91                             int, size_t *, WriteMethod **);
92 static u_char *rip2IfStatEntry (struct variable *, oid [], size_t *,
93                                 int, size_t *, WriteMethod **);
94 static u_char *rip2IfConfAddress (struct variable *, oid [], size_t *,
95                                   int, size_t *, WriteMethod **);
96 static u_char *rip2PeerTable (struct variable *, oid [], size_t *,
97                               int, size_t *, WriteMethod **);
98
99 struct variable rip_variables[] = 
100 {
101   /* RIP Global Counters. */
102   {RIP2GLOBALROUTECHANGES,    COUNTER, RONLY, rip2Globals,
103    2, {1, 1}},
104   {RIP2GLOBALQUERIES,         COUNTER, RONLY, rip2Globals,
105    2, {1, 2}},
106   /* RIP Interface Tables. */
107   {RIP2IFSTATADDRESS,         IPADDRESS, RONLY, rip2IfStatEntry,
108    3, {2, 1, 1}},
109   {RIP2IFSTATRCVBADPACKETS,   COUNTER, RONLY, rip2IfStatEntry,
110    3, {2, 1, 2}},
111   {RIP2IFSTATRCVBADROUTES,    COUNTER, RONLY, rip2IfStatEntry,
112    3, {2, 1, 3}},
113   {RIP2IFSTATSENTUPDATES,     COUNTER, RONLY, rip2IfStatEntry,
114    3, {2, 1, 4}},
115   {RIP2IFSTATSTATUS,          COUNTER, RWRITE, rip2IfStatEntry,
116    3, {2, 1, 5}},
117   {RIP2IFCONFADDRESS,         IPADDRESS, RONLY, rip2IfConfAddress,
118    /* RIP Interface Configuration Table. */
119    3, {3, 1, 1}},
120   {RIP2IFCONFDOMAIN,          STRING, RONLY, rip2IfConfAddress,
121    3, {3, 1, 2}},
122   {RIP2IFCONFAUTHTYPE,        COUNTER, RONLY, rip2IfConfAddress,
123    3, {3, 1, 3}},
124   {RIP2IFCONFAUTHKEY,         STRING, RONLY, rip2IfConfAddress,
125    3, {3, 1, 4}},
126   {RIP2IFCONFSEND,            COUNTER, RONLY, rip2IfConfAddress,
127    3, {3, 1, 5}},
128   {RIP2IFCONFRECEIVE,         COUNTER, RONLY, rip2IfConfAddress,
129    3, {3, 1, 6}},
130   {RIP2IFCONFDEFAULTMETRIC,   COUNTER, RONLY, rip2IfConfAddress,
131    3, {3, 1, 7}},
132   {RIP2IFCONFSTATUS,          COUNTER, RONLY, rip2IfConfAddress,
133    3, {3, 1, 8}},
134   {RIP2IFCONFSRCADDRESS,      IPADDRESS, RONLY, rip2IfConfAddress,
135    3, {3, 1, 9}},
136   {RIP2PEERADDRESS,           IPADDRESS, RONLY, rip2PeerTable,
137    /* RIP Peer Table. */
138    3, {4, 1, 1}},
139   {RIP2PEERDOMAIN,            STRING, RONLY, rip2PeerTable,
140    3, {4, 1, 2}},
141   {RIP2PEERLASTUPDATE,        TIMETICKS, RONLY, rip2PeerTable,
142    3, {4, 1, 3}},
143   {RIP2PEERVERSION,           INTEGER, RONLY, rip2PeerTable,
144    3, {4, 1, 4}},
145   {RIP2PEERRCVBADPACKETS,     COUNTER, RONLY, rip2PeerTable,
146    3, {4, 1, 5}},
147   {RIP2PEERRCVBADROUTES,      COUNTER, RONLY, rip2PeerTable,
148    3, {4, 1, 6}}
149 };
150
151 extern struct thread_master *master;
152
153 static u_char *
154 rip2Globals (struct variable *v, oid name[], size_t *length,
155              int exact, size_t *var_len, WriteMethod **write_method)
156 {
157   if (smux_header_generic(v, name, length, exact, var_len, write_method)
158       == MATCH_FAILED)
159     return NULL;
160
161   /* Retrun global counter. */
162   switch (v->magic)
163     {
164     case RIP2GLOBALROUTECHANGES:
165       return SNMP_INTEGER (rip_global_route_changes);
166       break;
167     case RIP2GLOBALQUERIES:
168       return SNMP_INTEGER (rip_global_queries);
169       break;
170     default:
171       return NULL;
172       break;
173     }
174   return NULL;
175 }
176
177 void
178 rip_ifaddr_add (struct interface *ifp, struct connected *ifc)
179 {
180   struct prefix *p;
181   struct route_node *rn;
182
183   p = ifc->address;
184
185   if (p->family != AF_INET)
186     return;
187
188   rn = route_node_get (rip_ifaddr_table, p);
189   rn->info = ifp;
190 }
191
192 void
193 rip_ifaddr_delete (struct interface *ifp, struct connected *ifc)
194 {
195   struct prefix *p;
196   struct route_node *rn;
197   struct interface *i;
198
199   p = ifc->address;
200
201   if (p->family != AF_INET)
202     return;
203
204   rn = route_node_lookup (rip_ifaddr_table, p);
205   if (! rn)
206     return;
207   i = rn->info;
208   if (rn && !strncmp(i->name,ifp->name,INTERFACE_NAMSIZ))
209     {
210       rn->info = NULL;
211       route_unlock_node (rn);
212       route_unlock_node (rn);
213     }
214 }
215
216 static struct interface *
217 rip_ifaddr_lookup_next (struct in_addr *addr)
218 {
219   struct prefix_ipv4 p;
220   struct route_node *rn;
221   struct interface *ifp;
222
223   p.family = AF_INET;
224   p.prefixlen = IPV4_MAX_BITLEN;
225   p.prefix = *addr;
226
227   rn = route_node_get (rip_ifaddr_table, (struct prefix *) &p);
228
229   for (rn = route_next (rn); rn; rn = route_next (rn))
230     if (rn->info)
231       break;
232
233   if (rn && rn->info)
234     {
235       ifp = rn->info;
236       *addr = rn->p.u.prefix4;
237       route_unlock_node (rn);
238       return ifp;
239     }
240   return NULL;
241 }
242
243 static struct interface *
244 rip2IfLookup (struct variable *v, oid name[], size_t *length, 
245               struct in_addr *addr, int exact)
246 {
247   int len;
248   struct interface *ifp;
249   
250   if (exact)
251     {
252       /* Check the length. */
253       if (*length - v->namelen != sizeof (struct in_addr))
254         return NULL;
255
256       oid2in_addr (name + v->namelen, sizeof (struct in_addr), addr);
257
258       return if_lookup_exact_address (*addr);
259     }
260   else
261     {
262       len = *length - v->namelen;
263       if (len > 4) len = 4;
264
265       oid2in_addr (name + v->namelen, len, addr);
266
267       ifp = rip_ifaddr_lookup_next (addr);
268
269       if (ifp == NULL)
270         return NULL;
271
272       oid_copy_addr (name + v->namelen, addr, sizeof (struct in_addr));
273
274       *length = v->namelen + sizeof (struct in_addr);
275
276       return ifp;
277     }
278   return NULL;
279 }
280
281 static struct rip_peer *
282 rip2PeerLookup (struct variable *v, oid name[], size_t *length, 
283                 struct in_addr *addr, int exact)
284 {
285   int len;
286   struct rip_peer *peer;
287   
288   if (exact)
289     {
290       /* Check the length. */
291       if (*length - v->namelen != sizeof (struct in_addr) + 1)
292         return NULL;
293
294       oid2in_addr (name + v->namelen, sizeof (struct in_addr), addr);
295
296       peer = rip_peer_lookup (addr);
297
298       if (peer->domain == (int)name[v->namelen + sizeof (struct in_addr)])
299         return peer;
300
301       return NULL;
302     }
303   else
304     {
305       len = *length - v->namelen;
306       if (len > 4) len = 4;
307
308       oid2in_addr (name + v->namelen, len, addr);
309
310       len = *length - v->namelen;
311       peer = rip_peer_lookup (addr);
312       if (peer)
313         {
314           if ((len < (int)sizeof (struct in_addr) + 1) ||
315               (peer->domain > (int)name[v->namelen + sizeof (struct in_addr)]))
316             {
317               oid_copy_addr (name + v->namelen, &peer->addr,
318                              sizeof (struct in_addr));
319               name[v->namelen + sizeof (struct in_addr)] = peer->domain;
320               *length = sizeof (struct in_addr) + v->namelen + 1;
321               return peer;
322             }
323         } 
324       peer = rip_peer_lookup_next (addr);
325
326       if (! peer)
327         return NULL;
328
329       oid_copy_addr (name + v->namelen, &peer->addr,
330                      sizeof (struct in_addr));
331       name[v->namelen + sizeof (struct in_addr)] = peer->domain;
332       *length = sizeof (struct in_addr) + v->namelen + 1;
333
334       return peer;
335     }
336   return NULL;
337 }
338
339 static u_char *
340 rip2IfStatEntry (struct variable *v, oid name[], size_t *length,
341                  int exact, size_t *var_len, WriteMethod **write_method)
342 {
343   struct interface *ifp;
344   struct rip_interface *ri;
345   static struct in_addr addr;
346   static long valid = SNMP_VALID;
347
348   if (smux_header_table(v, name, length, exact, var_len, write_method)
349       == MATCH_FAILED)
350     return NULL;
351
352   memset (&addr, 0, sizeof (struct in_addr));
353   
354   /* Lookup interface. */
355   ifp = rip2IfLookup (v, name, length, &addr, exact);
356   if (! ifp)
357     return NULL;
358
359   /* Fetch rip_interface information. */
360   ri = ifp->info;
361
362   switch (v->magic)
363     {
364     case RIP2IFSTATADDRESS:
365       return SNMP_IPADDRESS (addr);
366       break;
367     case RIP2IFSTATRCVBADPACKETS:
368       *var_len = sizeof (long);
369       return (u_char *) &ri->recv_badpackets;
370
371     case RIP2IFSTATRCVBADROUTES:
372       *var_len = sizeof (long);
373       return (u_char *) &ri->recv_badroutes;
374
375     case RIP2IFSTATSENTUPDATES:
376       *var_len = sizeof (long);
377       return (u_char *) &ri->sent_updates;
378
379     case RIP2IFSTATSTATUS:
380       *var_len = sizeof (long);
381       v->type = ASN_INTEGER;
382       return (u_char *) &valid;
383
384     default:
385       return NULL;
386
387     }
388   return NULL;
389 }
390
391 static long
392 rip2IfConfSend (struct rip_interface *ri)
393 {
394 #define doNotSend       1
395 #define ripVersion1     2
396 #define rip1Compatible  3
397 #define ripVersion2     4
398 #define ripV1Demand     5
399 #define ripV2Demand     6
400
401   if (! ri->running)
402     return doNotSend;
403     
404   if (ri->ri_send & RIPv2)
405     return ripVersion2;
406   else if (ri->ri_send & RIPv1)
407     return ripVersion1;
408   else if (rip)
409     {
410       if (rip->version_send == RIPv2)
411         return ripVersion2;
412       else if (rip->version_send == RIPv1)
413         return ripVersion1;
414     }
415   return doNotSend;
416 }
417
418 static long
419 rip2IfConfReceive (struct rip_interface *ri)
420 {
421 #define rip1            1
422 #define rip2            2
423 #define rip1OrRip2      3
424 #define doNotReceive    4
425
426   int recvv;
427
428   if (! ri->running)
429     return doNotReceive;
430
431   recvv = (ri->ri_receive == RI_RIP_UNSPEC) ?  rip->version_recv :
432                                                ri->ri_receive;
433   if (recvv == RI_RIP_VERSION_1_AND_2)
434     return rip1OrRip2;
435   else if (recvv & RIPv2)
436     return rip2;
437   else if (recvv & RIPv1)
438     return rip1;
439   else
440     return doNotReceive;
441 }
442
443 static u_char *
444 rip2IfConfAddress (struct variable *v, oid name[], size_t *length,
445                    int exact, size_t *val_len, WriteMethod **write_method)
446 {
447   static struct in_addr addr;
448   static long valid = SNMP_INVALID;
449   static long domain = 0;
450   static long config = 0;
451   static u_int auth = 0;
452   struct interface *ifp;
453   struct rip_interface *ri;
454
455   if (smux_header_table(v, name, length, exact, val_len, write_method)
456       == MATCH_FAILED)
457     return NULL;
458
459   memset (&addr, 0, sizeof (struct in_addr));
460   
461   /* Lookup interface. */
462   ifp = rip2IfLookup (v, name, length, &addr, exact);
463   if (! ifp)
464     return NULL;
465
466   /* Fetch rip_interface information. */
467   ri = ifp->info;
468
469   switch (v->magic)
470     {
471     case RIP2IFCONFADDRESS:
472       *val_len = sizeof (struct in_addr);
473       return (u_char *) &addr;
474
475     case RIP2IFCONFDOMAIN:
476       *val_len = 2;
477       return (u_char *) &domain;
478
479     case RIP2IFCONFAUTHTYPE:
480       auth = ri->auth_type;
481       *val_len = sizeof (long);
482       v->type = ASN_INTEGER;
483       return (u_char *)&auth;
484
485     case RIP2IFCONFAUTHKEY:
486       *val_len = 0;
487       return (u_char *) &domain;
488     case RIP2IFCONFSEND:
489       config = rip2IfConfSend (ri);
490       *val_len = sizeof (long);
491       v->type = ASN_INTEGER;
492       return (u_char *) &config;
493     case RIP2IFCONFRECEIVE:
494       config = rip2IfConfReceive (ri);
495       *val_len = sizeof (long);
496       v->type = ASN_INTEGER;
497       return (u_char *) &config;
498
499     case RIP2IFCONFDEFAULTMETRIC:
500       *val_len = sizeof (long);
501       v->type = ASN_INTEGER;
502       return (u_char *) &ifp->metric;
503     case RIP2IFCONFSTATUS:
504       *val_len = sizeof (long);
505       v->type = ASN_INTEGER;
506       return (u_char *) &valid;
507     case RIP2IFCONFSRCADDRESS:
508       *val_len = sizeof (struct in_addr);
509       return (u_char *) &addr;
510
511     default:
512       return NULL;
513
514     }
515   return NULL;
516 }
517
518 static u_char *
519 rip2PeerTable (struct variable *v, oid name[], size_t *length,
520                int exact, size_t *val_len, WriteMethod **write_method)
521 {
522   static struct in_addr addr;
523   static int domain = 0;
524   static int version;
525   /* static time_t uptime; */
526
527   struct rip_peer *peer;
528
529   if (smux_header_table(v, name, length, exact, val_len, write_method)
530       == MATCH_FAILED)
531     return NULL;
532
533   memset (&addr, 0, sizeof (struct in_addr));
534   
535   /* Lookup interface. */
536   peer = rip2PeerLookup (v, name, length, &addr, exact);
537   if (! peer)
538     return NULL;
539
540   switch (v->magic)
541     {
542     case RIP2PEERADDRESS:
543       *val_len = sizeof (struct in_addr);
544       return (u_char *) &peer->addr;
545
546     case RIP2PEERDOMAIN:
547       *val_len = 2;
548       return (u_char *) &domain;
549
550     case RIP2PEERLASTUPDATE:
551 #if 0 
552       /* We don't know the SNMP agent startup time. We have two choices here:
553        * - assume ripd startup time equals SNMP agent startup time
554        * - don't support this variable, at all
555        * Currently, we do the latter...
556        */
557       *val_len = sizeof (time_t);
558       uptime = peer->uptime; /* now - snmp_agent_startup - peer->uptime */
559       return (u_char *) &uptime;
560 #else
561       return (u_char *) NULL;
562 #endif
563
564     case RIP2PEERVERSION:
565       *val_len = sizeof (int);
566       version = peer->version;
567       return (u_char *) &version;
568
569     case RIP2PEERRCVBADPACKETS:
570       *val_len = sizeof (int);
571       return (u_char *) &peer->recv_badpackets;
572
573     case RIP2PEERRCVBADROUTES:
574       *val_len = sizeof (int);
575       return (u_char *) &peer->recv_badroutes;
576
577     default:
578       return NULL;
579
580     }
581   return NULL;
582 }
583
584 /* Register RIPv2-MIB. */
585 void
586 rip_snmp_init ()
587 {
588   rip_ifaddr_table = route_table_init ();
589
590   smux_init (master);
591   REGISTER_MIB("mibII/rip", rip_variables, variable, rip_oid);
592 }
593 #endif /* HAVE_SNMP */