blob: 5a5060fd9806ed3658478b602d19ac255d90ce6d [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};
155
156static u_char *
157rip2Globals (struct variable *v, oid name[], size_t *length,
158 int exact, size_t *var_len, WriteMethod **write_method)
159{
160 if (smux_header_generic(v, name, length, exact, var_len, write_method)
161 == MATCH_FAILED)
162 return NULL;
163
164 /* Retrun global counter. */
165 switch (v->magic)
166 {
167 case RIP2GLOBALROUTECHANGES:
168 return SNMP_INTEGER (rip_global_route_changes);
169 break;
170 case RIP2GLOBALQUERIES:
171 return SNMP_INTEGER (rip_global_queries);
172 break;
173 default:
174 return NULL;
175 break;
176 }
177 return NULL;
178}
179
180void
181rip_ifaddr_add (struct interface *ifp, struct connected *ifc)
182{
183 struct prefix *p;
184 struct route_node *rn;
185
186 p = ifc->address;
187
188 if (p->family != AF_INET)
189 return;
190
191 rn = route_node_get (rip_ifaddr_table, p);
192 rn->info = ifp;
193}
194
195void
196rip_ifaddr_delete (struct interface *ifp, struct connected *ifc)
197{
198 struct prefix *p;
199 struct route_node *rn;
200 struct interface *i;
201
202 p = ifc->address;
203
204 if (p->family != AF_INET)
205 return;
206
207 rn = route_node_lookup (rip_ifaddr_table, p);
208 if (! rn)
209 return;
210 i = rn->info;
211 if (rn && !strncmp(i->name,ifp->name,INTERFACE_NAMSIZ))
212 {
213 rn->info = NULL;
214 route_unlock_node (rn);
215 route_unlock_node (rn);
216 }
217}
218
219struct interface *
220rip_ifaddr_lookup_next (struct in_addr *addr)
221{
222 struct prefix_ipv4 p;
223 struct route_node *rn;
224 struct interface *ifp;
225
226 p.family = AF_INET;
227 p.prefixlen = IPV4_MAX_BITLEN;
228 p.prefix = *addr;
229
230 rn = route_node_get (rip_ifaddr_table, (struct prefix *) &p);
231
232 for (rn = route_next (rn); rn; rn = route_next (rn))
233 if (rn->info)
234 break;
235
236 if (rn && rn->info)
237 {
238 ifp = rn->info;
239 *addr = rn->p.u.prefix4;
240 route_unlock_node (rn);
241 return ifp;
242 }
243 return NULL;
244}
245
246static struct interface *
247rip2IfLookup (struct variable *v, oid name[], size_t *length,
248 struct in_addr *addr, int exact)
249{
250 int len;
251 struct interface *ifp;
252
253 if (exact)
254 {
255 /* Check the length. */
256 if (*length - v->namelen != sizeof (struct in_addr))
257 return NULL;
258
259 oid2in_addr (name + v->namelen, sizeof (struct in_addr), addr);
260
261 return if_lookup_exact_address (*addr);
262 }
263 else
264 {
265 len = *length - v->namelen;
266 if (len > 4) len = 4;
267
268 oid2in_addr (name + v->namelen, len, addr);
269
270 ifp = rip_ifaddr_lookup_next (addr);
271
272 if (ifp == NULL)
273 return NULL;
274
275 oid_copy_addr (name + v->namelen, addr, sizeof (struct in_addr));
276
277 *length = v->namelen + sizeof (struct in_addr);
278
279 return ifp;
280 }
281 return NULL;
282}
283
284static struct rip_peer *
285rip2PeerLookup (struct variable *v, oid name[], size_t *length,
286 struct in_addr *addr, int exact)
287{
288 int len;
289 struct rip_peer *peer;
290
291 if (exact)
292 {
293 /* Check the length. */
294 if (*length - v->namelen != sizeof (struct in_addr) + 1)
295 return NULL;
296
297 oid2in_addr (name + v->namelen, sizeof (struct in_addr), addr);
298
299 peer = rip_peer_lookup (addr);
300
301 if (peer->domain == name[v->namelen + sizeof (struct in_addr)])
302 return peer;
303
304 return NULL;
305 }
306 else
307 {
308 len = *length - v->namelen;
309 if (len > 4) len = 4;
310
311 oid2in_addr (name + v->namelen, len, addr);
312
313 len = *length - v->namelen;
314 peer = rip_peer_lookup (addr);
315 if (peer)
316 {
317 if ((len < sizeof (struct in_addr) + 1) ||
318 (peer->domain > name[v->namelen + sizeof (struct in_addr)]))
319 {
320 oid_copy_addr (name + v->namelen, &peer->addr,
321 sizeof (struct in_addr));
322 name[v->namelen + sizeof (struct in_addr)] = peer->domain;
323 *length = sizeof (struct in_addr) + v->namelen + 1;
324 return peer;
325 }
326 }
327 peer = rip_peer_lookup_next (addr);
328
329 if (! peer)
330 return NULL;
331
332 oid_copy_addr (name + v->namelen, &peer->addr,
333 sizeof (struct in_addr));
334 name[v->namelen + sizeof (struct in_addr)] = peer->domain;
335 *length = sizeof (struct in_addr) + v->namelen + 1;
336
337 return peer;
338 }
339 return NULL;
340}
341
342static u_char *
343rip2IfStatEntry (struct variable *v, oid name[], size_t *length,
344 int exact, size_t *var_len, WriteMethod **write_method)
345{
346 struct interface *ifp;
347 struct rip_interface *ri;
348 static struct in_addr addr;
349 static long valid = SNMP_VALID;
350
351 memset (&addr, 0, sizeof (struct in_addr));
352
353 /* Lookup interface. */
354 ifp = rip2IfLookup (v, name, length, &addr, exact);
355 if (! ifp)
356 return NULL;
357
358 /* Fetch rip_interface information. */
359 ri = ifp->info;
360
361 switch (v->magic)
362 {
363 case RIP2IFSTATADDRESS:
364 return SNMP_IPADDRESS (addr);
365 break;
366 case RIP2IFSTATRCVBADPACKETS:
367 *var_len = sizeof (long);
368 return (u_char *) &ri->recv_badpackets;
369
370 case RIP2IFSTATRCVBADROUTES:
371 *var_len = sizeof (long);
372 return (u_char *) &ri->recv_badroutes;
373
374 case RIP2IFSTATSENTUPDATES:
375 *var_len = sizeof (long);
376 return (u_char *) &ri->sent_updates;
377
378 case RIP2IFSTATSTATUS:
379 *var_len = sizeof (long);
380 v->type = ASN_INTEGER;
381 return (u_char *) &valid;
382
383 default:
384 return NULL;
385
386 }
387 return NULL;
388}
389
390static long
391rip2IfConfSend (struct rip_interface *ri)
392{
393#define doNotSend 1
394#define ripVersion1 2
395#define rip1Compatible 3
396#define ripVersion2 4
397#define ripV1Demand 5
398#define ripV2Demand 6
399
400 if (! ri->running)
401 return doNotSend;
402
403 if (ri->ri_send & RIPv2)
404 return ripVersion2;
405 else if (ri->ri_send & RIPv1)
406 return ripVersion1;
407 else if (rip)
408 {
409 if (rip->version == RIPv2)
410 return ripVersion2;
411 else if (rip->version == RIPv1)
412 return ripVersion1;
413 }
414 return doNotSend;
415}
416
417static long
418rip2IfConfReceive (struct rip_interface *ri)
419{
420#define rip1 1
421#define rip2 2
422#define rip1OrRip2 3
423#define doNotReceive 4
424
425 if (! ri->running)
426 return doNotReceive;
427
428 if (ri->ri_receive == RI_RIP_VERSION_1_AND_2)
429 return rip1OrRip2;
430 else if (ri->ri_receive & RIPv2)
431 return ripVersion2;
432 else if (ri->ri_receive & RIPv1)
433 return ripVersion1;
434 else
435 return doNotReceive;
436}
437
438static u_char *
439rip2IfConfAddress (struct variable *v, oid name[], size_t *length,
440 int exact, size_t *val_len, WriteMethod **write_method)
441{
442 static struct in_addr addr;
443 static long valid = SNMP_INVALID;
444 static long domain = 0;
445 static long config = 0;
446 static u_int auth = 0;
447 struct interface *ifp;
448 struct rip_interface *ri;
449
450 memset (&addr, 0, sizeof (struct in_addr));
451
452 /* Lookup interface. */
453 ifp = rip2IfLookup (v, name, length, &addr, exact);
454 if (! ifp)
455 return NULL;
456
457 /* Fetch rip_interface information. */
458 ri = ifp->info;
459
460 switch (v->magic)
461 {
462 case RIP2IFCONFADDRESS:
463 *val_len = sizeof (struct in_addr);
464 return (u_char *) &addr;
465
466 case RIP2IFCONFDOMAIN:
467 *val_len = 2;
468 return (u_char *) &domain;
469
470 case RIP2IFCONFAUTHTYPE:
471 auth = ri->auth_type;
472 *val_len = sizeof (long);
473 v->type = ASN_INTEGER;
474 return (u_char *)&auth;
475
476 case RIP2IFCONFAUTHKEY:
477 *val_len = 0;
478 return (u_char *) &domain;
479 case RIP2IFCONFSEND:
480 config = rip2IfConfSend (ri);
481 *val_len = sizeof (long);
482 v->type = ASN_INTEGER;
483 return (u_char *) &config;
484 case RIP2IFCONFRECEIVE:
485 config = rip2IfConfReceive (ri);
486 *val_len = sizeof (long);
487 v->type = ASN_INTEGER;
488 return (u_char *) &config;
489
490 case RIP2IFCONFDEFAULTMETRIC:
491 *val_len = sizeof (long);
492 v->type = ASN_INTEGER;
493 return (u_char *) &ifp->metric;
494 case RIP2IFCONFSTATUS:
495 *val_len = sizeof (long);
496 v->type = ASN_INTEGER;
497 return (u_char *) &valid;
498 case RIP2IFCONFSRCADDRESS:
499 *val_len = sizeof (struct in_addr);
500 return (u_char *) &addr;
501
502 default:
503 return NULL;
504
505 }
506 return NULL;
507}
508
509static u_char *
510rip2PeerTable (struct variable *v, oid name[], size_t *length,
511 int exact, size_t *val_len, WriteMethod **write_method)
512{
513 static struct in_addr addr;
514 static int version;
515 /* static time_t uptime; */
516
517 struct rip_peer *peer;
518
519 memset (&addr, 0, sizeof (struct in_addr));
520
521 /* Lookup interface. */
522 peer = rip2PeerLookup (v, name, length, &addr, exact);
523 if (! peer)
524 return NULL;
525
526 switch (v->magic)
527 {
528 case RIP2PEERADDRESS:
529 *val_len = sizeof (struct in_addr);
530 return (u_char *) &peer->addr;
531
532 case RIP2PEERDOMAIN:
533 *val_len = sizeof (int);
534 return (u_char *) &peer->domain;
535
536 case RIP2PEERLASTUPDATE:
537#if 0
538 /* We don't know the SNMP agent startup time. We have two choices here:
539 * - assume ripd startup time equals SNMP agent startup time
540 * - don't support this variable, at all
541 * Currently, we do the latter...
542 */
543 *val_len = sizeof (time_t);
544 uptime = peer->uptime; /* now - snmp_agent_startup - peer->uptime */
545 return (u_char *) &uptime;
546#else
547 return (u_char *) NULL;
548#endif
549
550 case RIP2PEERVERSION:
551 *val_len = sizeof (int);
552 version = peer->version;
553 return (u_char *) &version;
554
555 case RIP2PEERRCVBADPACKETS:
556 *val_len = sizeof (int);
557 return (u_char *) &peer->recv_badpackets;
558
559 case RIP2PEERRCVBADROUTES:
560 *val_len = sizeof (int);
561 return (u_char *) &peer->recv_badroutes;
562
563 default:
564 return NULL;
565
566 }
567 return NULL;
568}
569
570/* Register RIPv2-MIB. */
571void
572rip_snmp_init ()
573{
574 rip_ifaddr_table = route_table_init ();
575
576 smux_init (ripd_oid, sizeof (ripd_oid) / sizeof (oid));
577 REGISTER_MIB("mibII/rip", rip_variables, variable, rip_oid);
578 smux_start ();
579}
580#endif /* HAVE_SNMP */