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