blob: 2c7cd2c1270086ff2e8d5bbfea59c9b61f68c587 [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#include <net-snmp/net-snmp-config.h>
Joakim Tjernlundfb62a3c2008-05-13 20:03:32 +020026#include <net-snmp/net-snmp-includes.h>
paul718e3742002-12-13 20:15:29 +000027
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"
David Lamparter6b0655a2014-06-04 06:53:35 +020036
paul718e3742002-12-13 20:15:29 +000037/* RIPv2-MIB. */
38#define RIPV2MIB 1,3,6,1,2,1,23
39
paul718e3742002-12-13 20:15:29 +000040/* 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
David Lamparter6b0655a2014-06-04 06:53:35 +020079
paul718e3742002-12-13 20:15:29 +000080/* Define SNMP local variables. */
81SNMP_LOCAL_VARIABLES
82
83/* RIP-MIB instances. */
84oid rip_oid [] = { RIPV2MIB };
paul718e3742002-12-13 20:15:29 +000085
86/* Interface cache table sorted by interface's address. */
87struct route_table *rip_ifaddr_table;
88
89/* Hook functions. */
Chris Caputo0be8dfb2009-06-02 18:40:07 +010090static u_char *rip2Globals (struct variable *, oid [], size_t *,
91 int, size_t *, WriteMethod **);
92static u_char *rip2IfStatEntry (struct variable *, oid [], size_t *,
93 int, size_t *, WriteMethod **);
94static u_char *rip2IfConfAddress (struct variable *, oid [], size_t *,
95 int, size_t *, WriteMethod **);
96static u_char *rip2PeerTable (struct variable *, oid [], size_t *,
97 int, size_t *, WriteMethod **);
paul718e3742002-12-13 20:15:29 +000098
99struct 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}},
vincentfbf5d032005-09-29 11:25:50 +0000139 {RIP2PEERDOMAIN, STRING, RONLY, rip2PeerTable,
paul718e3742002-12-13 20:15:29 +0000140 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};
pauldd488a72003-06-19 01:21:07 +0000150
151extern struct thread_master *master;
David Lamparter6b0655a2014-06-04 06:53:35 +0200152
paul718e3742002-12-13 20:15:29 +0000153static u_char *
154rip2Globals (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
177void
178rip_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
192void
193rip_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
Chris Caputo0be8dfb2009-06-02 18:40:07 +0100216static struct interface *
paul718e3742002-12-13 20:15:29 +0000217rip_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
243static struct interface *
244rip2IfLookup (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
281static struct rip_peer *
282rip2PeerLookup (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
David Lamparterdfee58f2015-03-04 06:44:57 +0100298 if (peer->domain == (int)name[v->namelen + sizeof (struct in_addr)])
paul718e3742002-12-13 20:15:29 +0000299 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 {
David Lamparterdfee58f2015-03-04 06:44:57 +0100314 if ((len < (int)sizeof (struct in_addr) + 1) ||
315 (peer->domain > (int)name[v->namelen + sizeof (struct in_addr)]))
paul718e3742002-12-13 20:15:29 +0000316 {
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
339static u_char *
340rip2IfStatEntry (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
Vincent Bernat8046ba62012-05-31 13:30:28 +0200348 if (smux_header_table(v, name, length, exact, var_len, write_method)
349 == MATCH_FAILED)
350 return NULL;
351
paul718e3742002-12-13 20:15:29 +0000352 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
391static long
392rip2IfConfSend (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 {
pauldd488a72003-06-19 01:21:07 +0000410 if (rip->version_send == RIPv2)
paul718e3742002-12-13 20:15:29 +0000411 return ripVersion2;
pauldd488a72003-06-19 01:21:07 +0000412 else if (rip->version_send == RIPv1)
paul718e3742002-12-13 20:15:29 +0000413 return ripVersion1;
414 }
415 return doNotSend;
416}
417
418static long
419rip2IfConfReceive (struct rip_interface *ri)
420{
421#define rip1 1
422#define rip2 2
423#define rip1OrRip2 3
424#define doNotReceive 4
425
vincentfbf5d032005-09-29 11:25:50 +0000426 int recvv;
427
paul718e3742002-12-13 20:15:29 +0000428 if (! ri->running)
429 return doNotReceive;
430
vincentfbf5d032005-09-29 11:25:50 +0000431 recvv = (ri->ri_receive == RI_RIP_UNSPEC) ? rip->version_recv :
432 ri->ri_receive;
433 if (recvv == RI_RIP_VERSION_1_AND_2)
paul718e3742002-12-13 20:15:29 +0000434 return rip1OrRip2;
vincentfbf5d032005-09-29 11:25:50 +0000435 else if (recvv & RIPv2)
436 return rip2;
437 else if (recvv & RIPv1)
438 return rip1;
paul718e3742002-12-13 20:15:29 +0000439 else
440 return doNotReceive;
441}
442
443static u_char *
444rip2IfConfAddress (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
Vincent Bernat8046ba62012-05-31 13:30:28 +0200455 if (smux_header_table(v, name, length, exact, val_len, write_method)
456 == MATCH_FAILED)
457 return NULL;
458
paul718e3742002-12-13 20:15:29 +0000459 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
518static u_char *
519rip2PeerTable (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;
vincentfbf5d032005-09-29 11:25:50 +0000523 static int domain = 0;
paul718e3742002-12-13 20:15:29 +0000524 static int version;
525 /* static time_t uptime; */
526
527 struct rip_peer *peer;
528
Vincent Bernat8046ba62012-05-31 13:30:28 +0200529 if (smux_header_table(v, name, length, exact, val_len, write_method)
530 == MATCH_FAILED)
531 return NULL;
532
paul718e3742002-12-13 20:15:29 +0000533 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:
vincentfbf5d032005-09-29 11:25:50 +0000547 *val_len = 2;
548 return (u_char *) &domain;
paul718e3742002-12-13 20:15:29 +0000549
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. */
585void
586rip_snmp_init ()
587{
588 rip_ifaddr_table = route_table_init ();
589
hassoc75105a2004-10-13 10:33:26 +0000590 smux_init (master);
paul718e3742002-12-13 20:15:29 +0000591 REGISTER_MIB("mibII/rip", rip_variables, variable, rip_oid);
paul718e3742002-12-13 20:15:29 +0000592}
593#endif /* HAVE_SNMP */