]> git.proxmox.com Git - mirror_frr.git/blob - ripd/rip_snmp.c
pbrd: initial fwmark support for pbr matches #4460
[mirror_frr.git] / ripd / rip_snmp.c
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 *
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
19 */
20
21 #include <zebra.h>
22
23 #include <net-snmp/net-snmp-config.h>
24 #include <net-snmp/net-snmp-includes.h>
25
26 #include "if.h"
27 #include "vrf.h"
28 #include "log.h"
29 #include "prefix.h"
30 #include "command.h"
31 #include "table.h"
32 #include "smux.h"
33 #include "libfrr.h"
34 #include "version.h"
35
36 #include "ripd/ripd.h"
37
38 /* RIPv2-MIB. */
39 #define RIPV2MIB 1,3,6,1,2,1,23
40
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
80
81 /* Define SNMP local variables. */
82 SNMP_LOCAL_VARIABLES
83
84 /* RIP-MIB instances. */
85 static oid rip_oid[] = {RIPV2MIB};
86
87 /* Interface cache table sorted by interface's address. */
88 static struct route_table *rip_ifaddr_table;
89
90 /* Hook functions. */
91 static uint8_t *rip2Globals(struct variable *, oid[], size_t *, int, size_t *,
92 WriteMethod **);
93 static uint8_t *rip2IfStatEntry(struct variable *, oid[], size_t *, int,
94 size_t *, WriteMethod **);
95 static uint8_t *rip2IfConfAddress(struct variable *, oid[], size_t *, int,
96 size_t *, WriteMethod **);
97 static uint8_t *rip2PeerTable(struct variable *, oid[], size_t *, int, size_t *,
98 WriteMethod **);
99
100 static 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}}};
152
153 extern struct thread_master *master;
154
155 static uint8_t *rip2Globals(struct variable *v, oid name[], size_t *length,
156 int exact, size_t *var_len,
157 WriteMethod **write_method)
158 {
159 struct rip *rip;
160
161 if (smux_header_generic(v, name, length, exact, var_len, write_method)
162 == MATCH_FAILED)
163 return NULL;
164
165 rip = rip_lookup_by_vrf_id(VRF_DEFAULT);
166 if (!rip)
167 return NULL;
168
169 /* Retrun global counter. */
170 switch (v->magic) {
171 case RIP2GLOBALROUTECHANGES:
172 return SNMP_INTEGER(rip->counters.route_changes);
173 break;
174 case RIP2GLOBALQUERIES:
175 return SNMP_INTEGER(rip->counters.queries);
176 break;
177 default:
178 return NULL;
179 break;
180 }
181 return NULL;
182 }
183
184 static int rip_snmp_ifaddr_add(struct connected *ifc)
185 {
186 struct interface *ifp = ifc->ifp;
187 struct prefix *p;
188 struct route_node *rn;
189
190 p = ifc->address;
191
192 if (p->family != AF_INET)
193 return 0;
194
195 rn = route_node_get(rip_ifaddr_table, p);
196 rn->info = ifp;
197 return 0;
198 }
199
200 static int rip_snmp_ifaddr_del(struct connected *ifc)
201 {
202 struct interface *ifp = ifc->ifp;
203 struct prefix *p;
204 struct route_node *rn;
205 struct interface *i;
206
207 p = ifc->address;
208
209 if (p->family != AF_INET)
210 return 0;
211
212 rn = route_node_lookup(rip_ifaddr_table, p);
213 if (!rn)
214 return 0;
215 i = rn->info;
216 if (!strncmp(i->name, ifp->name, INTERFACE_NAMSIZ)) {
217 rn->info = NULL;
218 route_unlock_node(rn);
219 route_unlock_node(rn);
220 }
221 return 0;
222 }
223
224 static struct interface *rip_ifaddr_lookup_next(struct in_addr *addr)
225 {
226 struct prefix_ipv4 p;
227 struct route_node *rn;
228 struct interface *ifp;
229
230 p.family = AF_INET;
231 p.prefixlen = IPV4_MAX_BITLEN;
232 p.prefix = *addr;
233
234 rn = route_node_get(rip_ifaddr_table, (struct prefix *)&p);
235
236 for (rn = route_next(rn); rn; rn = route_next(rn))
237 if (rn->info)
238 break;
239
240 if (rn && rn->info) {
241 ifp = rn->info;
242 *addr = rn->p.u.prefix4;
243 route_unlock_node(rn);
244 return ifp;
245 }
246 return NULL;
247 }
248
249 static struct interface *rip2IfLookup(struct variable *v, oid name[],
250 size_t *length, struct in_addr *addr,
251 int exact)
252 {
253 int len;
254 struct interface *ifp;
255
256 if (exact) {
257 /* Check the length. */
258 if (*length - v->namelen != sizeof(struct in_addr))
259 return NULL;
260
261 oid2in_addr(name + v->namelen, sizeof(struct in_addr), addr);
262
263 return if_lookup_exact_address((void *)addr, AF_INET,
264 VRF_DEFAULT);
265 } else {
266 len = *length - v->namelen;
267 if (len > 4)
268 len = 4;
269
270 oid2in_addr(name + v->namelen, len, addr);
271
272 ifp = rip_ifaddr_lookup_next(addr);
273
274 if (ifp == NULL)
275 return NULL;
276
277 oid_copy_addr(name + v->namelen, addr, sizeof(struct in_addr));
278
279 *length = v->namelen + sizeof(struct in_addr);
280
281 return ifp;
282 }
283 return NULL;
284 }
285
286 static struct rip_peer *rip2PeerLookup(struct variable *v, oid name[],
287 size_t *length, struct in_addr *addr,
288 int exact)
289 {
290 struct rip *rip;
291 int len;
292 struct rip_peer *peer;
293
294 rip = rip_lookup_by_vrf_id(VRF_DEFAULT);
295 if (!rip)
296 return NULL;
297
298 if (exact) {
299 /* Check the length. */
300 if (*length - v->namelen != sizeof(struct in_addr) + 1)
301 return NULL;
302
303 oid2in_addr(name + v->namelen, sizeof(struct in_addr), addr);
304
305 peer = rip_peer_lookup(rip, addr);
306
307 if (peer->domain
308 == (int)name[v->namelen + sizeof(struct in_addr)])
309 return peer;
310
311 return NULL;
312 } else {
313 len = *length - v->namelen;
314 if (len > 4)
315 len = 4;
316
317 oid2in_addr(name + v->namelen, len, addr);
318
319 len = *length - v->namelen;
320 peer = rip_peer_lookup(rip, addr);
321 if (peer) {
322 if ((len < (int)sizeof(struct in_addr) + 1)
323 || (peer->domain
324 > (int)name[v->namelen
325 + sizeof(struct in_addr)])) {
326 oid_copy_addr(name + v->namelen, &peer->addr,
327 sizeof(struct in_addr));
328 name[v->namelen + sizeof(struct in_addr)] =
329 peer->domain;
330 *length =
331 sizeof(struct in_addr) + v->namelen + 1;
332 return peer;
333 }
334 }
335 peer = rip_peer_lookup_next(rip, addr);
336
337 if (!peer)
338 return NULL;
339
340 oid_copy_addr(name + v->namelen, &peer->addr,
341 sizeof(struct in_addr));
342 name[v->namelen + sizeof(struct in_addr)] = peer->domain;
343 *length = sizeof(struct in_addr) + v->namelen + 1;
344
345 return peer;
346 }
347 return NULL;
348 }
349
350 static uint8_t *rip2IfStatEntry(struct variable *v, oid name[], size_t *length,
351 int exact, size_t *var_len,
352 WriteMethod **write_method)
353 {
354 struct interface *ifp;
355 struct rip_interface *ri;
356 static struct in_addr addr;
357 static long valid = SNMP_VALID;
358
359 if (smux_header_table(v, name, length, exact, var_len, write_method)
360 == MATCH_FAILED)
361 return NULL;
362
363 memset(&addr, 0, sizeof(struct in_addr));
364
365 /* Lookup interface. */
366 ifp = rip2IfLookup(v, name, length, &addr, exact);
367 if (!ifp)
368 return NULL;
369
370 /* Fetch rip_interface information. */
371 ri = ifp->info;
372
373 switch (v->magic) {
374 case RIP2IFSTATADDRESS:
375 return SNMP_IPADDRESS(addr);
376 break;
377 case RIP2IFSTATRCVBADPACKETS:
378 *var_len = sizeof(long);
379 return (uint8_t *)&ri->recv_badpackets;
380
381 case RIP2IFSTATRCVBADROUTES:
382 *var_len = sizeof(long);
383 return (uint8_t *)&ri->recv_badroutes;
384
385 case RIP2IFSTATSENTUPDATES:
386 *var_len = sizeof(long);
387 return (uint8_t *)&ri->sent_updates;
388
389 case RIP2IFSTATSTATUS:
390 *var_len = sizeof(long);
391 v->type = ASN_INTEGER;
392 return (uint8_t *)&valid;
393
394 default:
395 return NULL;
396 }
397 return NULL;
398 }
399
400 static long rip2IfConfSend(struct rip_interface *ri)
401 {
402 #define doNotSend 1
403 #define ripVersion1 2
404 #define rip1Compatible 3
405 #define ripVersion2 4
406 #define ripV1Demand 5
407 #define ripV2Demand 6
408
409 if (!ri->running)
410 return doNotSend;
411
412 if (ri->ri_send & RIPv2)
413 return ripVersion2;
414 else if (ri->ri_send & RIPv1)
415 return ripVersion1;
416 else if (ri->rip) {
417 if (ri->rip->version_send == RIPv2)
418 return ripVersion2;
419 else if (ri->rip->version_send == RIPv1)
420 return ripVersion1;
421 }
422 return doNotSend;
423 }
424
425 static long rip2IfConfReceive(struct rip_interface *ri)
426 {
427 #define rip1 1
428 #define rip2 2
429 #define rip1OrRip2 3
430 #define doNotReceive 4
431
432 int recvv;
433
434 if (!ri->running)
435 return doNotReceive;
436
437 recvv = (ri->ri_receive == RI_RIP_UNSPEC) ? ri->rip->version_recv
438 : ri->ri_receive;
439 if (recvv == RI_RIP_VERSION_1_AND_2)
440 return rip1OrRip2;
441 else if (recvv & RIPv2)
442 return rip2;
443 else if (recvv & RIPv1)
444 return rip1;
445 else
446 return doNotReceive;
447 }
448
449 static uint8_t *rip2IfConfAddress(struct variable *v, oid name[],
450 size_t *length, int exact, size_t *val_len,
451 WriteMethod **write_method)
452 {
453 static struct in_addr addr;
454 static long valid = SNMP_INVALID;
455 static long domain = 0;
456 static long config = 0;
457 static unsigned int auth = 0;
458 struct interface *ifp;
459 struct rip_interface *ri;
460
461 if (smux_header_table(v, name, length, exact, val_len, write_method)
462 == MATCH_FAILED)
463 return NULL;
464
465 memset(&addr, 0, sizeof(struct in_addr));
466
467 /* Lookup interface. */
468 ifp = rip2IfLookup(v, name, length, &addr, exact);
469 if (!ifp)
470 return NULL;
471
472 /* Fetch rip_interface information. */
473 ri = ifp->info;
474
475 switch (v->magic) {
476 case RIP2IFCONFADDRESS:
477 *val_len = sizeof(struct in_addr);
478 return (uint8_t *)&addr;
479
480 case RIP2IFCONFDOMAIN:
481 *val_len = 2;
482 return (uint8_t *)&domain;
483
484 case RIP2IFCONFAUTHTYPE:
485 auth = ri->auth_type;
486 *val_len = sizeof(long);
487 v->type = ASN_INTEGER;
488 return (uint8_t *)&auth;
489
490 case RIP2IFCONFAUTHKEY:
491 *val_len = 0;
492 return (uint8_t *)&domain;
493 case RIP2IFCONFSEND:
494 config = rip2IfConfSend(ri);
495 *val_len = sizeof(long);
496 v->type = ASN_INTEGER;
497 return (uint8_t *)&config;
498 case RIP2IFCONFRECEIVE:
499 config = rip2IfConfReceive(ri);
500 *val_len = sizeof(long);
501 v->type = ASN_INTEGER;
502 return (uint8_t *)&config;
503
504 case RIP2IFCONFDEFAULTMETRIC:
505 *val_len = sizeof(long);
506 v->type = ASN_INTEGER;
507 return (uint8_t *)&ifp->metric;
508 case RIP2IFCONFSTATUS:
509 *val_len = sizeof(long);
510 v->type = ASN_INTEGER;
511 return (uint8_t *)&valid;
512 case RIP2IFCONFSRCADDRESS:
513 *val_len = sizeof(struct in_addr);
514 return (uint8_t *)&addr;
515
516 default:
517 return NULL;
518 }
519 return NULL;
520 }
521
522 static uint8_t *rip2PeerTable(struct variable *v, oid name[], size_t *length,
523 int exact, size_t *val_len,
524 WriteMethod **write_method)
525 {
526 static struct in_addr addr;
527 static int domain = 0;
528 static int version;
529 /* static time_t uptime; */
530
531 struct rip_peer *peer;
532
533 if (smux_header_table(v, name, length, exact, val_len, write_method)
534 == MATCH_FAILED)
535 return NULL;
536
537 memset(&addr, 0, sizeof(struct in_addr));
538
539 /* Lookup interface. */
540 peer = rip2PeerLookup(v, name, length, &addr, exact);
541 if (!peer)
542 return NULL;
543
544 switch (v->magic) {
545 case RIP2PEERADDRESS:
546 *val_len = sizeof(struct in_addr);
547 return (uint8_t *)&peer->addr;
548
549 case RIP2PEERDOMAIN:
550 *val_len = 2;
551 return (uint8_t *)&domain;
552
553 case RIP2PEERLASTUPDATE:
554 #if 0
555 /* We don't know the SNMP agent startup time. We have two choices here:
556 * - assume ripd startup time equals SNMP agent startup time
557 * - don't support this variable, at all
558 * Currently, we do the latter...
559 */
560 *val_len = sizeof (time_t);
561 uptime = peer->uptime; /* now - snmp_agent_startup - peer->uptime */
562 return (uint8_t *) &uptime;
563 #else
564 return (uint8_t *)NULL;
565 #endif
566
567 case RIP2PEERVERSION:
568 *val_len = sizeof(int);
569 version = peer->version;
570 return (uint8_t *)&version;
571
572 case RIP2PEERRCVBADPACKETS:
573 *val_len = sizeof(int);
574 return (uint8_t *)&peer->recv_badpackets;
575
576 case RIP2PEERRCVBADROUTES:
577 *val_len = sizeof(int);
578 return (uint8_t *)&peer->recv_badroutes;
579
580 default:
581 return NULL;
582 }
583 return NULL;
584 }
585
586 /* Register RIPv2-MIB. */
587 static int rip_snmp_init(struct thread_master *master)
588 {
589 rip_ifaddr_table = route_table_init();
590
591 smux_init(master);
592 REGISTER_MIB("mibII/rip", rip_variables, variable, rip_oid);
593 return 0;
594 }
595
596 static int rip_snmp_module_init(void)
597 {
598 hook_register(rip_ifaddr_add, rip_snmp_ifaddr_add);
599 hook_register(rip_ifaddr_del, rip_snmp_ifaddr_del);
600
601 hook_register(frr_late_init, rip_snmp_init);
602 return 0;
603 }
604
605 FRR_MODULE_SETUP(.name = "ripd_snmp", .version = FRR_VERSION,
606 .description = "ripd AgentX SNMP module",
607 .init = rip_snmp_module_init, )