]> git.proxmox.com Git - mirror_frr.git/blob - ripd/rip_snmp.c
Merge pull request #13276 from pguibert6WIND/explicit_null_complement
[mirror_frr.git] / ripd / rip_snmp.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* RIP SNMP support
3 * Copyright (C) 1999 Kunihiro Ishiguro <kunihiro@zebra.org>
4 */
5
6 #include <zebra.h>
7
8 #include <net-snmp/net-snmp-config.h>
9 #include <net-snmp/net-snmp-includes.h>
10
11 #include "if.h"
12 #include "vrf.h"
13 #include "log.h"
14 #include "prefix.h"
15 #include "command.h"
16 #include "table.h"
17 #include "smux.h"
18 #include "libfrr.h"
19 #include "lib/version.h"
20
21 #include "ripd/ripd.h"
22
23 /* RIPv2-MIB. */
24 #define RIPV2MIB 1,3,6,1,2,1,23
25
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
65
66 /* Define SNMP local variables. */
67 SNMP_LOCAL_VARIABLES
68
69 /* RIP-MIB instances. */
70 static oid rip_oid[] = {RIPV2MIB};
71
72 /* Interface cache table sorted by interface's address. */
73 static struct route_table *rip_ifaddr_table;
74
75 /* Hook functions. */
76 static uint8_t *rip2Globals(struct variable *, oid[], size_t *, int, size_t *,
77 WriteMethod **);
78 static uint8_t *rip2IfStatEntry(struct variable *, oid[], size_t *, int,
79 size_t *, WriteMethod **);
80 static uint8_t *rip2IfConfAddress(struct variable *, oid[], size_t *, int,
81 size_t *, WriteMethod **);
82 static uint8_t *rip2PeerTable(struct variable *, oid[], size_t *, int, size_t *,
83 WriteMethod **);
84
85 static 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}}};
137
138 extern struct event_loop *master;
139
140 static uint8_t *rip2Globals(struct variable *v, oid name[], size_t *length,
141 int exact, size_t *var_len,
142 WriteMethod **write_method)
143 {
144 struct rip *rip;
145
146 if (smux_header_generic(v, name, length, exact, var_len, write_method)
147 == MATCH_FAILED)
148 return NULL;
149
150 rip = rip_lookup_by_vrf_id(VRF_DEFAULT);
151 if (!rip)
152 return NULL;
153
154 /* Return global counter. */
155 switch (v->magic) {
156 case RIP2GLOBALROUTECHANGES:
157 return SNMP_INTEGER(rip->counters.route_changes);
158 case RIP2GLOBALQUERIES:
159 return SNMP_INTEGER(rip->counters.queries);
160 default:
161 return NULL;
162 }
163 return NULL;
164 }
165
166 static int rip_snmp_ifaddr_add(struct connected *ifc)
167 {
168 struct interface *ifp = ifc->ifp;
169 struct prefix *p;
170 struct route_node *rn;
171
172 p = ifc->address;
173
174 if (p->family != AF_INET)
175 return 0;
176
177 rn = route_node_get(rip_ifaddr_table, p);
178 rn->info = ifp;
179 return 0;
180 }
181
182 static int rip_snmp_ifaddr_del(struct connected *ifc)
183 {
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;
198 if (!strncmp(i->name, ifp->name, INTERFACE_NAMSIZ)) {
199 rn->info = NULL;
200 route_unlock_node(rn);
201 route_unlock_node(rn);
202 }
203 return 0;
204 }
205
206 static struct interface *rip_ifaddr_lookup_next(struct in_addr *addr)
207 {
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;
229 }
230
231 static struct interface *rip2IfLookup(struct variable *v, oid name[],
232 size_t *length, struct in_addr *addr,
233 int exact)
234 {
235 int len;
236 struct interface *ifp;
237
238 if (exact) {
239 /* Check the length. */
240 if (*length - v->namelen != sizeof(struct in_addr))
241 return NULL;
242
243 oid2in_addr(name + v->namelen, sizeof(struct in_addr), addr);
244
245 return if_lookup_address_local((void *)addr, AF_INET,
246 VRF_DEFAULT);
247 } else {
248 len = *length - v->namelen;
249 if (len > 4)
250 len = 4;
251
252 oid2in_addr(name + v->namelen, len, addr);
253
254 ifp = rip_ifaddr_lookup_next(addr);
255
256 if (ifp == NULL)
257 return NULL;
258
259 oid_copy_in_addr(name + v->namelen, addr);
260
261 *length = v->namelen + sizeof(struct in_addr);
262
263 return ifp;
264 }
265 return NULL;
266 }
267
268 static struct rip_peer *rip2PeerLookup(struct variable *v, oid name[],
269 size_t *length, struct in_addr *addr,
270 int exact)
271 {
272 struct rip *rip;
273 int len;
274 struct rip_peer *peer;
275
276 rip = rip_lookup_by_vrf_id(VRF_DEFAULT);
277 if (!rip)
278 return NULL;
279
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
287 peer = rip_peer_lookup(rip, addr);
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;
302 peer = rip_peer_lookup(rip, addr);
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)])) {
308 oid_copy_in_addr(name + v->namelen,
309 &peer->addr);
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 }
317 peer = rip_peer_lookup_next(rip, addr);
318
319 if (!peer)
320 return NULL;
321
322 oid_copy_in_addr(name + v->namelen, &peer->addr);
323 name[v->namelen + sizeof(struct in_addr)] = peer->domain;
324 *length = sizeof(struct in_addr) + v->namelen + 1;
325
326 return peer;
327 }
328 return NULL;
329 }
330
331 static uint8_t *rip2IfStatEntry(struct variable *v, oid name[], size_t *length,
332 int exact, size_t *var_len,
333 WriteMethod **write_method)
334 {
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
344 memset(&addr, 0, sizeof(addr));
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);
357 case RIP2IFSTATRCVBADPACKETS:
358 *var_len = sizeof(long);
359 return (uint8_t *)&ri->recv_badpackets;
360
361 case RIP2IFSTATRCVBADROUTES:
362 *var_len = sizeof(long);
363 return (uint8_t *)&ri->recv_badroutes;
364
365 case RIP2IFSTATSENTUPDATES:
366 *var_len = sizeof(long);
367 return (uint8_t *)&ri->sent_updates;
368
369 case RIP2IFSTATSTATUS:
370 *var_len = sizeof(long);
371 v->type = ASN_INTEGER;
372 return (uint8_t *)&valid;
373
374 default:
375 return NULL;
376 }
377 return NULL;
378 }
379
380 static long rip2IfConfSend(struct rip_interface *ri)
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
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;
396 else if (ri->rip) {
397 if (ri->rip->version_send == RIPv2)
398 return ripVersion2;
399 else if (ri->rip->version_send == RIPv1)
400 return ripVersion1;
401 }
402 return doNotSend;
403 }
404
405 static long rip2IfConfReceive(struct rip_interface *ri)
406 {
407 #define rip1 1
408 #define rip2 2
409 #define rip1OrRip2 3
410 #define doNotReceive 4
411
412 int recvv;
413
414 if (!ri->running)
415 return doNotReceive;
416
417 recvv = (ri->ri_receive == RI_RIP_UNSPEC) ? ri->rip->version_recv
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;
427 }
428
429 static uint8_t *rip2IfConfAddress(struct variable *v, oid name[],
430 size_t *length, int exact, size_t *val_len,
431 WriteMethod **write_method)
432 {
433 static struct in_addr addr;
434 static long valid = SNMP_INVALID;
435 static long domain = 0;
436 static long config = 0;
437 static unsigned int auth = 0;
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
445 memset(&addr, 0, sizeof(addr));
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);
458 return (uint8_t *)&addr;
459
460 case RIP2IFCONFDOMAIN:
461 *val_len = 2;
462 return (uint8_t *)&domain;
463
464 case RIP2IFCONFAUTHTYPE:
465 auth = ri->auth_type;
466 *val_len = sizeof(long);
467 v->type = ASN_INTEGER;
468 return (uint8_t *)&auth;
469
470 case RIP2IFCONFAUTHKEY:
471 *val_len = 0;
472 return (uint8_t *)&domain;
473 case RIP2IFCONFSEND:
474 config = rip2IfConfSend(ri);
475 *val_len = sizeof(long);
476 v->type = ASN_INTEGER;
477 return (uint8_t *)&config;
478 case RIP2IFCONFRECEIVE:
479 config = rip2IfConfReceive(ri);
480 *val_len = sizeof(long);
481 v->type = ASN_INTEGER;
482 return (uint8_t *)&config;
483
484 case RIP2IFCONFDEFAULTMETRIC:
485 *val_len = sizeof(long);
486 v->type = ASN_INTEGER;
487 return (uint8_t *)&ifp->metric;
488 case RIP2IFCONFSTATUS:
489 *val_len = sizeof(long);
490 v->type = ASN_INTEGER;
491 return (uint8_t *)&valid;
492 case RIP2IFCONFSRCADDRESS:
493 *val_len = sizeof(struct in_addr);
494 return (uint8_t *)&addr;
495
496 default:
497 return NULL;
498 }
499 return NULL;
500 }
501
502 static uint8_t *rip2PeerTable(struct variable *v, oid name[], size_t *length,
503 int exact, size_t *val_len,
504 WriteMethod **write_method)
505 {
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
517 memset(&addr, 0, sizeof(addr));
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);
527 return (uint8_t *)&peer->addr;
528
529 case RIP2PEERDOMAIN:
530 *val_len = 2;
531 return (uint8_t *)&domain;
532
533 case RIP2PEERLASTUPDATE:
534 return (uint8_t *)NULL;
535
536 case RIP2PEERVERSION:
537 *val_len = sizeof(int);
538 version = peer->version;
539 return (uint8_t *)&version;
540
541 case RIP2PEERRCVBADPACKETS:
542 *val_len = sizeof(int);
543 return (uint8_t *)&peer->recv_badpackets;
544
545 case RIP2PEERRCVBADROUTES:
546 *val_len = sizeof(int);
547 return (uint8_t *)&peer->recv_badroutes;
548
549 default:
550 return NULL;
551 }
552 return NULL;
553 }
554
555 /* Register RIPv2-MIB. */
556 static int rip_snmp_init(struct event_loop *master)
557 {
558 rip_ifaddr_table = route_table_init();
559
560 smux_init(master);
561 REGISTER_MIB("mibII/rip", rip_variables, variable, rip_oid);
562 return 0;
563 }
564
565 static int rip_snmp_module_init(void)
566 {
567 hook_register(rip_ifaddr_add, rip_snmp_ifaddr_add);
568 hook_register(rip_ifaddr_del, rip_snmp_ifaddr_del);
569
570 hook_register(frr_late_init, rip_snmp_init);
571 return 0;
572 }
573
574 FRR_MODULE_SETUP(.name = "ripd_snmp", .version = FRR_VERSION,
575 .description = "ripd AgentX SNMP module",
576 .init = rip_snmp_module_init,
577 );