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