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