[ospfd] Raise ExchangeDone earlier, avoid often needless round of DD packets
[jleu-quagga.git] / ripd / rip_snmp.c
blobc1bec762b90b873fbf2544ddf29909f9fde3bb64
1 /* RIP SNMP support
2 * Copyright (C) 1999 Kunihiro Ishiguro <kunihiro@zebra.org>
4 * This file is part of GNU Zebra.
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.
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.
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.
22 #include <zebra.h>
24 #ifdef HAVE_SNMP
25 #ifdef HAVE_NETSNMP
26 #include <net-snmp/net-snmp-config.h>
27 #endif
28 #include <asn1.h>
29 #include <snmp.h>
30 #include <snmp_impl.h>
32 #include "if.h"
33 #include "log.h"
34 #include "prefix.h"
35 #include "command.h"
36 #include "table.h"
37 #include "smux.h"
39 #include "ripd/ripd.h"
41 /* RIPv2-MIB. */
42 #define RIPV2MIB 1,3,6,1,2,1,23
44 /* RIPv2-MIB rip2Globals values. */
45 #define RIP2GLOBALROUTECHANGES 1
46 #define RIP2GLOBALQUERIES 2
48 /* RIPv2-MIB rip2IfStatEntry. */
49 #define RIP2IFSTATENTRY 1
51 /* RIPv2-MIB rip2IfStatTable. */
52 #define RIP2IFSTATADDRESS 1
53 #define RIP2IFSTATRCVBADPACKETS 2
54 #define RIP2IFSTATRCVBADROUTES 3
55 #define RIP2IFSTATSENTUPDATES 4
56 #define RIP2IFSTATSTATUS 5
58 /* RIPv2-MIB rip2IfConfTable. */
59 #define RIP2IFCONFADDRESS 1
60 #define RIP2IFCONFDOMAIN 2
61 #define RIP2IFCONFAUTHTYPE 3
62 #define RIP2IFCONFAUTHKEY 4
63 #define RIP2IFCONFSEND 5
64 #define RIP2IFCONFRECEIVE 6
65 #define RIP2IFCONFDEFAULTMETRIC 7
66 #define RIP2IFCONFSTATUS 8
67 #define RIP2IFCONFSRCADDRESS 9
69 /* RIPv2-MIB rip2PeerTable. */
70 #define RIP2PEERADDRESS 1
71 #define RIP2PEERDOMAIN 2
72 #define RIP2PEERLASTUPDATE 3
73 #define RIP2PEERVERSION 4
74 #define RIP2PEERRCVBADPACKETS 5
75 #define RIP2PEERRCVBADROUTES 6
77 /* SNMP value hack. */
78 #define COUNTER ASN_COUNTER
79 #define INTEGER ASN_INTEGER
80 #define TIMETICKS ASN_TIMETICKS
81 #define IPADDRESS ASN_IPADDRESS
82 #define STRING ASN_OCTET_STR
84 /* Define SNMP local variables. */
85 SNMP_LOCAL_VARIABLES
87 /* RIP-MIB instances. */
88 oid rip_oid [] = { RIPV2MIB };
90 /* Interface cache table sorted by interface's address. */
91 struct route_table *rip_ifaddr_table;
93 /* Hook functions. */
94 static u_char *rip2Globals ();
95 static u_char *rip2IfStatEntry ();
96 static u_char *rip2IfConfAddress ();
97 static u_char *rip2PeerTable ();
99 struct variable rip_variables[] =
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}},
139 {RIP2PEERDOMAIN, STRING, RONLY, rip2PeerTable,
140 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}}
151 extern struct thread_master *master;
153 static u_char *
154 rip2Globals (struct variable *v, oid name[], size_t *length,
155 int exact, size_t *var_len, WriteMethod **write_method)
157 if (smux_header_generic(v, name, length, exact, var_len, write_method)
158 == MATCH_FAILED)
159 return NULL;
161 /* Retrun global counter. */
162 switch (v->magic)
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;
174 return NULL;
177 void
178 rip_ifaddr_add (struct interface *ifp, struct connected *ifc)
180 struct prefix *p;
181 struct route_node *rn;
183 p = ifc->address;
185 if (p->family != AF_INET)
186 return;
188 rn = route_node_get (rip_ifaddr_table, p);
189 rn->info = ifp;
192 void
193 rip_ifaddr_delete (struct interface *ifp, struct connected *ifc)
195 struct prefix *p;
196 struct route_node *rn;
197 struct interface *i;
199 p = ifc->address;
201 if (p->family != AF_INET)
202 return;
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))
210 rn->info = NULL;
211 route_unlock_node (rn);
212 route_unlock_node (rn);
216 struct interface *
217 rip_ifaddr_lookup_next (struct in_addr *addr)
219 struct prefix_ipv4 p;
220 struct route_node *rn;
221 struct interface *ifp;
223 p.family = AF_INET;
224 p.prefixlen = IPV4_MAX_BITLEN;
225 p.prefix = *addr;
227 rn = route_node_get (rip_ifaddr_table, (struct prefix *) &p);
229 for (rn = route_next (rn); rn; rn = route_next (rn))
230 if (rn->info)
231 break;
233 if (rn && rn->info)
235 ifp = rn->info;
236 *addr = rn->p.u.prefix4;
237 route_unlock_node (rn);
238 return ifp;
240 return NULL;
243 static struct interface *
244 rip2IfLookup (struct variable *v, oid name[], size_t *length,
245 struct in_addr *addr, int exact)
247 int len;
248 struct interface *ifp;
250 if (exact)
252 /* Check the length. */
253 if (*length - v->namelen != sizeof (struct in_addr))
254 return NULL;
256 oid2in_addr (name + v->namelen, sizeof (struct in_addr), addr);
258 return if_lookup_exact_address (*addr);
260 else
262 len = *length - v->namelen;
263 if (len > 4) len = 4;
265 oid2in_addr (name + v->namelen, len, addr);
267 ifp = rip_ifaddr_lookup_next (addr);
269 if (ifp == NULL)
270 return NULL;
272 oid_copy_addr (name + v->namelen, addr, sizeof (struct in_addr));
274 *length = v->namelen + sizeof (struct in_addr);
276 return ifp;
278 return NULL;
281 static struct rip_peer *
282 rip2PeerLookup (struct variable *v, oid name[], size_t *length,
283 struct in_addr *addr, int exact)
285 int len;
286 struct rip_peer *peer;
288 if (exact)
290 /* Check the length. */
291 if (*length - v->namelen != sizeof (struct in_addr) + 1)
292 return NULL;
294 oid2in_addr (name + v->namelen, sizeof (struct in_addr), addr);
296 peer = rip_peer_lookup (addr);
298 if (peer->domain == name[v->namelen + sizeof (struct in_addr)])
299 return peer;
301 return NULL;
303 else
305 len = *length - v->namelen;
306 if (len > 4) len = 4;
308 oid2in_addr (name + v->namelen, len, addr);
310 len = *length - v->namelen;
311 peer = rip_peer_lookup (addr);
312 if (peer)
314 if ((len < sizeof (struct in_addr) + 1) ||
315 (peer->domain > name[v->namelen + sizeof (struct in_addr)]))
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;
324 peer = rip_peer_lookup_next (addr);
326 if (! peer)
327 return NULL;
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;
334 return peer;
336 return NULL;
339 static u_char *
340 rip2IfStatEntry (struct variable *v, oid name[], size_t *length,
341 int exact, size_t *var_len, WriteMethod **write_method)
343 struct interface *ifp;
344 struct rip_interface *ri;
345 static struct in_addr addr;
346 static long valid = SNMP_VALID;
348 memset (&addr, 0, sizeof (struct in_addr));
350 /* Lookup interface. */
351 ifp = rip2IfLookup (v, name, length, &addr, exact);
352 if (! ifp)
353 return NULL;
355 /* Fetch rip_interface information. */
356 ri = ifp->info;
358 switch (v->magic)
360 case RIP2IFSTATADDRESS:
361 return SNMP_IPADDRESS (addr);
362 break;
363 case RIP2IFSTATRCVBADPACKETS:
364 *var_len = sizeof (long);
365 return (u_char *) &ri->recv_badpackets;
367 case RIP2IFSTATRCVBADROUTES:
368 *var_len = sizeof (long);
369 return (u_char *) &ri->recv_badroutes;
371 case RIP2IFSTATSENTUPDATES:
372 *var_len = sizeof (long);
373 return (u_char *) &ri->sent_updates;
375 case RIP2IFSTATSTATUS:
376 *var_len = sizeof (long);
377 v->type = ASN_INTEGER;
378 return (u_char *) &valid;
380 default:
381 return NULL;
384 return NULL;
387 static long
388 rip2IfConfSend (struct rip_interface *ri)
390 #define doNotSend 1
391 #define ripVersion1 2
392 #define rip1Compatible 3
393 #define ripVersion2 4
394 #define ripV1Demand 5
395 #define ripV2Demand 6
397 if (! ri->running)
398 return doNotSend;
400 if (ri->ri_send & RIPv2)
401 return ripVersion2;
402 else if (ri->ri_send & RIPv1)
403 return ripVersion1;
404 else if (rip)
406 if (rip->version_send == RIPv2)
407 return ripVersion2;
408 else if (rip->version_send == RIPv1)
409 return ripVersion1;
411 return doNotSend;
414 static long
415 rip2IfConfReceive (struct rip_interface *ri)
417 #define rip1 1
418 #define rip2 2
419 #define rip1OrRip2 3
420 #define doNotReceive 4
422 int recvv;
424 if (! ri->running)
425 return doNotReceive;
427 recvv = (ri->ri_receive == RI_RIP_UNSPEC) ? rip->version_recv :
428 ri->ri_receive;
429 if (recvv == RI_RIP_VERSION_1_AND_2)
430 return rip1OrRip2;
431 else if (recvv & RIPv2)
432 return rip2;
433 else if (recvv & RIPv1)
434 return rip1;
435 else
436 return doNotReceive;
439 static u_char *
440 rip2IfConfAddress (struct variable *v, oid name[], size_t *length,
441 int exact, size_t *val_len, WriteMethod **write_method)
443 static struct in_addr addr;
444 static long valid = SNMP_INVALID;
445 static long domain = 0;
446 static long config = 0;
447 static u_int auth = 0;
448 struct interface *ifp;
449 struct rip_interface *ri;
451 memset (&addr, 0, sizeof (struct in_addr));
453 /* Lookup interface. */
454 ifp = rip2IfLookup (v, name, length, &addr, exact);
455 if (! ifp)
456 return NULL;
458 /* Fetch rip_interface information. */
459 ri = ifp->info;
461 switch (v->magic)
463 case RIP2IFCONFADDRESS:
464 *val_len = sizeof (struct in_addr);
465 return (u_char *) &addr;
467 case RIP2IFCONFDOMAIN:
468 *val_len = 2;
469 return (u_char *) &domain;
471 case RIP2IFCONFAUTHTYPE:
472 auth = ri->auth_type;
473 *val_len = sizeof (long);
474 v->type = ASN_INTEGER;
475 return (u_char *)&auth;
477 case RIP2IFCONFAUTHKEY:
478 *val_len = 0;
479 return (u_char *) &domain;
480 case RIP2IFCONFSEND:
481 config = rip2IfConfSend (ri);
482 *val_len = sizeof (long);
483 v->type = ASN_INTEGER;
484 return (u_char *) &config;
485 case RIP2IFCONFRECEIVE:
486 config = rip2IfConfReceive (ri);
487 *val_len = sizeof (long);
488 v->type = ASN_INTEGER;
489 return (u_char *) &config;
491 case RIP2IFCONFDEFAULTMETRIC:
492 *val_len = sizeof (long);
493 v->type = ASN_INTEGER;
494 return (u_char *) &ifp->metric;
495 case RIP2IFCONFSTATUS:
496 *val_len = sizeof (long);
497 v->type = ASN_INTEGER;
498 return (u_char *) &valid;
499 case RIP2IFCONFSRCADDRESS:
500 *val_len = sizeof (struct in_addr);
501 return (u_char *) &addr;
503 default:
504 return NULL;
507 return NULL;
510 static u_char *
511 rip2PeerTable (struct variable *v, oid name[], size_t *length,
512 int exact, size_t *val_len, WriteMethod **write_method)
514 static struct in_addr addr;
515 static int domain = 0;
516 static int version;
517 /* static time_t uptime; */
519 struct rip_peer *peer;
521 memset (&addr, 0, sizeof (struct in_addr));
523 /* Lookup interface. */
524 peer = rip2PeerLookup (v, name, length, &addr, exact);
525 if (! peer)
526 return NULL;
528 switch (v->magic)
530 case RIP2PEERADDRESS:
531 *val_len = sizeof (struct in_addr);
532 return (u_char *) &peer->addr;
534 case RIP2PEERDOMAIN:
535 *val_len = 2;
536 return (u_char *) &domain;
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...
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
552 case RIP2PEERVERSION:
553 *val_len = sizeof (int);
554 version = peer->version;
555 return (u_char *) &version;
557 case RIP2PEERRCVBADPACKETS:
558 *val_len = sizeof (int);
559 return (u_char *) &peer->recv_badpackets;
561 case RIP2PEERRCVBADROUTES:
562 *val_len = sizeof (int);
563 return (u_char *) &peer->recv_badroutes;
565 default:
566 return NULL;
569 return NULL;
572 /* Register RIPv2-MIB. */
573 void
574 rip_snmp_init ()
576 rip_ifaddr_table = route_table_init ();
578 smux_init (master);
579 REGISTER_MIB("mibII/rip", rip_variables, variable, rip_oid);
581 #endif /* HAVE_SNMP */