]> git.proxmox.com Git - mirror_frr.git/blame - ripd/rip_snmp.c
Merge pull request #3397 from mjstapp/fix_stream_macros
[mirror_frr.git] / ripd / rip_snmp.c
CommitLineData
718e3744 1/* 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 *
896014f4
DL
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
718e3744 19 */
20
21#include <zebra.h>
22
07661cb5 23#include <net-snmp/net-snmp-config.h>
fb62a3ce 24#include <net-snmp/net-snmp-includes.h>
718e3744 25
26#include "if.h"
d6b1bfba 27#include "vrf.h"
718e3744 28#include "log.h"
29#include "prefix.h"
30#include "command.h"
31#include "table.h"
32#include "smux.h"
5986b66b
DL
33#include "libfrr.h"
34#include "version.h"
718e3744 35
36#include "ripd/ripd.h"
6b0655a2 37
718e3744 38/* RIPv2-MIB. */
39#define RIPV2MIB 1,3,6,1,2,1,23
40
718e3744 41/* RIPv2-MIB rip2Globals values. */
42#define RIP2GLOBALROUTECHANGES 1
43#define RIP2GLOBALQUERIES 2
44
45/* RIPv2-MIB rip2IfStatEntry. */
46#define RIP2IFSTATENTRY 1
47
48/* RIPv2-MIB rip2IfStatTable. */
49#define RIP2IFSTATADDRESS 1
50#define RIP2IFSTATRCVBADPACKETS 2
51#define RIP2IFSTATRCVBADROUTES 3
52#define RIP2IFSTATSENTUPDATES 4
53#define RIP2IFSTATSTATUS 5
54
55/* RIPv2-MIB rip2IfConfTable. */
56#define RIP2IFCONFADDRESS 1
57#define RIP2IFCONFDOMAIN 2
58#define RIP2IFCONFAUTHTYPE 3
59#define RIP2IFCONFAUTHKEY 4
60#define RIP2IFCONFSEND 5
61#define RIP2IFCONFRECEIVE 6
62#define RIP2IFCONFDEFAULTMETRIC 7
63#define RIP2IFCONFSTATUS 8
64#define RIP2IFCONFSRCADDRESS 9
65
66/* RIPv2-MIB rip2PeerTable. */
67#define RIP2PEERADDRESS 1
68#define RIP2PEERDOMAIN 2
69#define RIP2PEERLASTUPDATE 3
70#define RIP2PEERVERSION 4
71#define RIP2PEERRCVBADPACKETS 5
72#define RIP2PEERRCVBADROUTES 6
73
74/* SNMP value hack. */
75#define COUNTER ASN_COUNTER
76#define INTEGER ASN_INTEGER
77#define TIMETICKS ASN_TIMETICKS
78#define IPADDRESS ASN_IPADDRESS
79#define STRING ASN_OCTET_STR
6b0655a2 80
718e3744 81/* Define SNMP local variables. */
82SNMP_LOCAL_VARIABLES
83
84/* RIP-MIB instances. */
d62a17ae 85static oid rip_oid[] = {RIPV2MIB};
718e3744 86
87/* Interface cache table sorted by interface's address. */
1c6f50bf 88static struct route_table *rip_ifaddr_table;
718e3744 89
90/* Hook functions. */
d7c0a89a
QY
91static uint8_t *rip2Globals(struct variable *, oid[], size_t *, int, size_t *,
92 WriteMethod **);
93static uint8_t *rip2IfStatEntry(struct variable *, oid[], size_t *, int,
94 size_t *, WriteMethod **);
95static uint8_t *rip2IfConfAddress(struct variable *, oid[], size_t *, int,
96 size_t *, WriteMethod **);
97static uint8_t *rip2PeerTable(struct variable *, oid[], size_t *, int, size_t *,
98 WriteMethod **);
d62a17ae 99
100static struct variable rip_variables[] = {
101 /* RIP Global Counters. */
102 {RIP2GLOBALROUTECHANGES, COUNTER, RONLY, rip2Globals, 2, {1, 1}},
103 {RIP2GLOBALQUERIES, COUNTER, RONLY, rip2Globals, 2, {1, 2}},
104 /* RIP Interface Tables. */
105 {RIP2IFSTATADDRESS, IPADDRESS, RONLY, rip2IfStatEntry, 3, {2, 1, 1}},
106 {RIP2IFSTATRCVBADPACKETS,
107 COUNTER,
108 RONLY,
109 rip2IfStatEntry,
110 3,
111 {2, 1, 2}},
112 {RIP2IFSTATRCVBADROUTES, COUNTER, RONLY, rip2IfStatEntry, 3, {2, 1, 3}},
113 {RIP2IFSTATSENTUPDATES, COUNTER, RONLY, rip2IfStatEntry, 3, {2, 1, 4}},
114 {RIP2IFSTATSTATUS, COUNTER, RWRITE, rip2IfStatEntry, 3, {2, 1, 5}},
115 {RIP2IFCONFADDRESS,
116 IPADDRESS,
117 RONLY,
118 rip2IfConfAddress,
119 /* RIP Interface Configuration Table. */
120 3,
121 {3, 1, 1}},
122 {RIP2IFCONFDOMAIN, STRING, RONLY, rip2IfConfAddress, 3, {3, 1, 2}},
123 {RIP2IFCONFAUTHTYPE, COUNTER, RONLY, rip2IfConfAddress, 3, {3, 1, 3}},
124 {RIP2IFCONFAUTHKEY, STRING, RONLY, rip2IfConfAddress, 3, {3, 1, 4}},
125 {RIP2IFCONFSEND, COUNTER, RONLY, rip2IfConfAddress, 3, {3, 1, 5}},
126 {RIP2IFCONFRECEIVE, COUNTER, RONLY, rip2IfConfAddress, 3, {3, 1, 6}},
127 {RIP2IFCONFDEFAULTMETRIC,
128 COUNTER,
129 RONLY,
130 rip2IfConfAddress,
131 3,
132 {3, 1, 7}},
133 {RIP2IFCONFSTATUS, COUNTER, RONLY, rip2IfConfAddress, 3, {3, 1, 8}},
134 {RIP2IFCONFSRCADDRESS,
135 IPADDRESS,
136 RONLY,
137 rip2IfConfAddress,
138 3,
139 {3, 1, 9}},
140 {RIP2PEERADDRESS,
141 IPADDRESS,
142 RONLY,
143 rip2PeerTable,
144 /* RIP Peer Table. */
145 3,
146 {4, 1, 1}},
147 {RIP2PEERDOMAIN, STRING, RONLY, rip2PeerTable, 3, {4, 1, 2}},
148 {RIP2PEERLASTUPDATE, TIMETICKS, RONLY, rip2PeerTable, 3, {4, 1, 3}},
149 {RIP2PEERVERSION, INTEGER, RONLY, rip2PeerTable, 3, {4, 1, 4}},
150 {RIP2PEERRCVBADPACKETS, COUNTER, RONLY, rip2PeerTable, 3, {4, 1, 5}},
151 {RIP2PEERRCVBADROUTES, COUNTER, RONLY, rip2PeerTable, 3, {4, 1, 6}}};
dd488a78 152
153extern struct thread_master *master;
6b0655a2 154
d7c0a89a
QY
155static uint8_t *rip2Globals(struct variable *v, oid name[], size_t *length,
156 int exact, size_t *var_len,
157 WriteMethod **write_method)
718e3744 158{
d62a17ae 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 case RIP2GLOBALROUTECHANGES:
166 return SNMP_INTEGER(rip_global_route_changes);
167 break;
168 case RIP2GLOBALQUERIES:
169 return SNMP_INTEGER(rip_global_queries);
170 break;
171 default:
172 return NULL;
173 break;
174 }
175 return NULL;
718e3744 176}
177
d62a17ae 178static int rip_snmp_ifaddr_add(struct connected *ifc)
718e3744 179{
d62a17ae 180 struct interface *ifp = ifc->ifp;
181 struct prefix *p;
182 struct route_node *rn;
718e3744 183
d62a17ae 184 p = ifc->address;
718e3744 185
d62a17ae 186 if (p->family != AF_INET)
187 return 0;
718e3744 188
d62a17ae 189 rn = route_node_get(rip_ifaddr_table, p);
190 rn->info = ifp;
191 return 0;
718e3744 192}
193
d62a17ae 194static int rip_snmp_ifaddr_del(struct connected *ifc)
718e3744 195{
d62a17ae 196 struct interface *ifp = ifc->ifp;
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 0;
205
206 rn = route_node_lookup(rip_ifaddr_table, p);
207 if (!rn)
208 return 0;
209 i = rn->info;
47e5a60f 210 if (!strncmp(i->name, ifp->name, INTERFACE_NAMSIZ)) {
d62a17ae 211 rn->info = NULL;
212 route_unlock_node(rn);
213 route_unlock_node(rn);
214 }
215 return 0;
718e3744 216}
217
d62a17ae 218static struct interface *rip_ifaddr_lookup_next(struct in_addr *addr)
718e3744 219{
d62a17ae 220 struct prefix_ipv4 p;
221 struct route_node *rn;
222 struct interface *ifp;
223
224 p.family = AF_INET;
225 p.prefixlen = IPV4_MAX_BITLEN;
226 p.prefix = *addr;
227
228 rn = route_node_get(rip_ifaddr_table, (struct prefix *)&p);
229
230 for (rn = route_next(rn); rn; rn = route_next(rn))
231 if (rn->info)
232 break;
233
234 if (rn && rn->info) {
235 ifp = rn->info;
236 *addr = rn->p.u.prefix4;
237 route_unlock_node(rn);
238 return ifp;
239 }
240 return NULL;
718e3744 241}
242
d62a17ae 243static struct interface *rip2IfLookup(struct variable *v, oid name[],
244 size_t *length, struct in_addr *addr,
245 int exact)
718e3744 246{
d62a17ae 247 int len;
248 struct interface *ifp;
718e3744 249
d62a17ae 250 if (exact) {
251 /* Check the length. */
252 if (*length - v->namelen != sizeof(struct in_addr))
253 return NULL;
718e3744 254
d62a17ae 255 oid2in_addr(name + v->namelen, sizeof(struct in_addr), addr);
718e3744 256
d62a17ae 257 return if_lookup_exact_address((void *)addr, AF_INET,
258 VRF_DEFAULT);
259 } else {
260 len = *length - v->namelen;
261 if (len > 4)
262 len = 4;
718e3744 263
d62a17ae 264 oid2in_addr(name + v->namelen, len, addr);
718e3744 265
d62a17ae 266 ifp = rip_ifaddr_lookup_next(addr);
718e3744 267
d62a17ae 268 if (ifp == NULL)
269 return NULL;
718e3744 270
d62a17ae 271 oid_copy_addr(name + v->namelen, addr, sizeof(struct in_addr));
718e3744 272
d62a17ae 273 *length = v->namelen + sizeof(struct in_addr);
718e3744 274
d62a17ae 275 return ifp;
276 }
718e3744 277 return NULL;
d62a17ae 278}
718e3744 279
d62a17ae 280static struct rip_peer *rip2PeerLookup(struct variable *v, oid name[],
281 size_t *length, struct in_addr *addr,
282 int exact)
283{
284 int len;
285 struct rip_peer *peer;
286
287 if (exact) {
288 /* Check the length. */
289 if (*length - v->namelen != sizeof(struct in_addr) + 1)
290 return NULL;
291
292 oid2in_addr(name + v->namelen, sizeof(struct in_addr), addr);
293
294 peer = rip_peer_lookup(addr);
295
296 if (peer->domain
297 == (int)name[v->namelen + sizeof(struct in_addr)])
298 return peer;
299
300 return NULL;
301 } else {
302 len = *length - v->namelen;
303 if (len > 4)
304 len = 4;
305
306 oid2in_addr(name + v->namelen, len, addr);
307
308 len = *length - v->namelen;
309 peer = rip_peer_lookup(addr);
310 if (peer) {
311 if ((len < (int)sizeof(struct in_addr) + 1)
312 || (peer->domain
313 > (int)name[v->namelen
314 + sizeof(struct in_addr)])) {
315 oid_copy_addr(name + v->namelen, &peer->addr,
316 sizeof(struct in_addr));
317 name[v->namelen + sizeof(struct in_addr)] =
318 peer->domain;
319 *length =
320 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 }
718e3744 336 return NULL;
718e3744 337}
338
d7c0a89a
QY
339static uint8_t *rip2IfStatEntry(struct variable *v, oid name[], size_t *length,
340 int exact, size_t *var_len,
341 WriteMethod **write_method)
718e3744 342{
d62a17ae 343 struct interface *ifp;
344 struct rip_interface *ri;
345 static struct in_addr addr;
346 static long valid = SNMP_VALID;
347
348 if (smux_header_table(v, name, length, exact, var_len, write_method)
349 == MATCH_FAILED)
350 return NULL;
351
352 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 case RIP2IFSTATADDRESS:
364 return SNMP_IPADDRESS(addr);
365 break;
366 case RIP2IFSTATRCVBADPACKETS:
367 *var_len = sizeof(long);
d7c0a89a 368 return (uint8_t *)&ri->recv_badpackets;
d62a17ae 369
370 case RIP2IFSTATRCVBADROUTES:
371 *var_len = sizeof(long);
d7c0a89a 372 return (uint8_t *)&ri->recv_badroutes;
d62a17ae 373
374 case RIP2IFSTATSENTUPDATES:
375 *var_len = sizeof(long);
d7c0a89a 376 return (uint8_t *)&ri->sent_updates;
d62a17ae 377
378 case RIP2IFSTATSTATUS:
379 *var_len = sizeof(long);
380 v->type = ASN_INTEGER;
d7c0a89a 381 return (uint8_t *)&valid;
d62a17ae 382
383 default:
384 return NULL;
385 }
386 return NULL;
718e3744 387}
388
d62a17ae 389static long rip2IfConfSend(struct rip_interface *ri)
718e3744 390{
391#define doNotSend 1
392#define ripVersion1 2
393#define rip1Compatible 3
394#define ripVersion2 4
395#define ripV1Demand 5
396#define ripV2Demand 6
397
d62a17ae 398 if (!ri->running)
399 return doNotSend;
400
401 if (ri->ri_send & RIPv2)
402 return ripVersion2;
403 else if (ri->ri_send & RIPv1)
404 return ripVersion1;
405 else if (rip) {
406 if (rip->version_send == RIPv2)
407 return ripVersion2;
408 else if (rip->version_send == RIPv1)
409 return ripVersion1;
410 }
411 return doNotSend;
718e3744 412}
413
d62a17ae 414static long rip2IfConfReceive(struct rip_interface *ri)
718e3744 415{
416#define rip1 1
417#define rip2 2
418#define rip1OrRip2 3
419#define doNotReceive 4
420
d62a17ae 421 int recvv;
422
423 if (!ri->running)
424 return doNotReceive;
425
426 recvv = (ri->ri_receive == RI_RIP_UNSPEC) ? rip->version_recv
427 : ri->ri_receive;
428 if (recvv == RI_RIP_VERSION_1_AND_2)
429 return rip1OrRip2;
430 else if (recvv & RIPv2)
431 return rip2;
432 else if (recvv & RIPv1)
433 return rip1;
434 else
435 return doNotReceive;
718e3744 436}
437
d7c0a89a
QY
438static uint8_t *rip2IfConfAddress(struct variable *v, oid name[],
439 size_t *length, int exact, size_t *val_len,
440 WriteMethod **write_method)
718e3744 441{
d62a17ae 442 static struct in_addr addr;
443 static long valid = SNMP_INVALID;
444 static long domain = 0;
445 static long config = 0;
d7c0a89a 446 static unsigned int auth = 0;
d62a17ae 447 struct interface *ifp;
448 struct rip_interface *ri;
449
450 if (smux_header_table(v, name, length, exact, val_len, write_method)
451 == MATCH_FAILED)
452 return NULL;
453
454 memset(&addr, 0, sizeof(struct in_addr));
455
456 /* Lookup interface. */
457 ifp = rip2IfLookup(v, name, length, &addr, exact);
458 if (!ifp)
459 return NULL;
460
461 /* Fetch rip_interface information. */
462 ri = ifp->info;
463
464 switch (v->magic) {
465 case RIP2IFCONFADDRESS:
466 *val_len = sizeof(struct in_addr);
d7c0a89a 467 return (uint8_t *)&addr;
d62a17ae 468
469 case RIP2IFCONFDOMAIN:
470 *val_len = 2;
d7c0a89a 471 return (uint8_t *)&domain;
d62a17ae 472
473 case RIP2IFCONFAUTHTYPE:
474 auth = ri->auth_type;
475 *val_len = sizeof(long);
476 v->type = ASN_INTEGER;
d7c0a89a 477 return (uint8_t *)&auth;
d62a17ae 478
479 case RIP2IFCONFAUTHKEY:
480 *val_len = 0;
d7c0a89a 481 return (uint8_t *)&domain;
d62a17ae 482 case RIP2IFCONFSEND:
483 config = rip2IfConfSend(ri);
484 *val_len = sizeof(long);
485 v->type = ASN_INTEGER;
d7c0a89a 486 return (uint8_t *)&config;
d62a17ae 487 case RIP2IFCONFRECEIVE:
488 config = rip2IfConfReceive(ri);
489 *val_len = sizeof(long);
490 v->type = ASN_INTEGER;
d7c0a89a 491 return (uint8_t *)&config;
d62a17ae 492
493 case RIP2IFCONFDEFAULTMETRIC:
494 *val_len = sizeof(long);
495 v->type = ASN_INTEGER;
d7c0a89a 496 return (uint8_t *)&ifp->metric;
d62a17ae 497 case RIP2IFCONFSTATUS:
498 *val_len = sizeof(long);
499 v->type = ASN_INTEGER;
d7c0a89a 500 return (uint8_t *)&valid;
d62a17ae 501 case RIP2IFCONFSRCADDRESS:
502 *val_len = sizeof(struct in_addr);
d7c0a89a 503 return (uint8_t *)&addr;
d62a17ae 504
505 default:
506 return NULL;
507 }
508 return NULL;
718e3744 509}
510
d7c0a89a
QY
511static uint8_t *rip2PeerTable(struct variable *v, oid name[], size_t *length,
512 int exact, size_t *val_len,
513 WriteMethod **write_method)
718e3744 514{
d62a17ae 515 static struct in_addr addr;
516 static int domain = 0;
517 static int version;
518 /* static time_t uptime; */
519
520 struct rip_peer *peer;
521
522 if (smux_header_table(v, name, length, exact, val_len, write_method)
523 == MATCH_FAILED)
524 return NULL;
525
526 memset(&addr, 0, sizeof(struct in_addr));
527
528 /* Lookup interface. */
529 peer = rip2PeerLookup(v, name, length, &addr, exact);
530 if (!peer)
531 return NULL;
532
533 switch (v->magic) {
534 case RIP2PEERADDRESS:
535 *val_len = sizeof(struct in_addr);
d7c0a89a 536 return (uint8_t *)&peer->addr;
d62a17ae 537
538 case RIP2PEERDOMAIN:
539 *val_len = 2;
d7c0a89a 540 return (uint8_t *)&domain;
d62a17ae 541
542 case RIP2PEERLASTUPDATE:
718e3744 543#if 0
544 /* We don't know the SNMP agent startup time. We have two choices here:
545 * - assume ripd startup time equals SNMP agent startup time
546 * - don't support this variable, at all
547 * Currently, we do the latter...
548 */
549 *val_len = sizeof (time_t);
550 uptime = peer->uptime; /* now - snmp_agent_startup - peer->uptime */
d7c0a89a 551 return (uint8_t *) &uptime;
718e3744 552#else
d7c0a89a 553 return (uint8_t *)NULL;
718e3744 554#endif
555
d62a17ae 556 case RIP2PEERVERSION:
557 *val_len = sizeof(int);
558 version = peer->version;
d7c0a89a 559 return (uint8_t *)&version;
718e3744 560
d62a17ae 561 case RIP2PEERRCVBADPACKETS:
562 *val_len = sizeof(int);
d7c0a89a 563 return (uint8_t *)&peer->recv_badpackets;
718e3744 564
d62a17ae 565 case RIP2PEERRCVBADROUTES:
566 *val_len = sizeof(int);
d7c0a89a 567 return (uint8_t *)&peer->recv_badroutes;
718e3744 568
d62a17ae 569 default:
570 return NULL;
571 }
572 return NULL;
718e3744 573}
574
575/* Register RIPv2-MIB. */
d62a17ae 576static int rip_snmp_init(struct thread_master *master)
718e3744 577{
d62a17ae 578 rip_ifaddr_table = route_table_init();
718e3744 579
d62a17ae 580 smux_init(master);
581 REGISTER_MIB("mibII/rip", rip_variables, variable, rip_oid);
582 return 0;
718e3744 583}
5986b66b 584
d62a17ae 585static int rip_snmp_module_init(void)
5986b66b 586{
d62a17ae 587 hook_register(rip_ifaddr_add, rip_snmp_ifaddr_add);
588 hook_register(rip_ifaddr_del, rip_snmp_ifaddr_del);
5986b66b 589
d62a17ae 590 hook_register(frr_late_init, rip_snmp_init);
591 return 0;
5986b66b
DL
592}
593
d62a17ae 594FRR_MODULE_SETUP(.name = "ripd_snmp", .version = FRR_VERSION,
595 .description = "ripd AgentX SNMP module",
596 .init = rip_snmp_module_init, )