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