]> git.proxmox.com Git - mirror_frr.git/blob - zebra/zebra_snmp.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / zebra / zebra_snmp.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* FIB SNMP.
3 * Copyright (C) 1999 Kunihiro Ishiguro
4 */
5
6 /*
7 * Currently SNMP is only running properly for MIBs in the default VRF.
8 */
9
10 #include <zebra.h>
11
12 #include <net-snmp/net-snmp-config.h>
13 #include <net-snmp/net-snmp-includes.h>
14
15 #include "if.h"
16 #include "log.h"
17 #include "prefix.h"
18 #include "command.h"
19 #include "smux.h"
20 #include "table.h"
21 #include "vrf.h"
22 #include "hook.h"
23 #include "libfrr.h"
24 #include "lib/version.h"
25
26 #include "zebra/rib.h"
27 #include "zebra/zserv.h"
28 #include "zebra/zebra_vrf.h"
29
30 #define IPFWMIB 1,3,6,1,2,1,4,24
31
32 /* ipForwardTable */
33 #define IPFORWARDDEST 1
34 #define IPFORWARDMASK 2
35 #define IPFORWARDPOLICY 3
36 #define IPFORWARDNEXTHOP 4
37 #define IPFORWARDIFINDEX 5
38 #define IPFORWARDTYPE 6
39 #define IPFORWARDPROTO 7
40 #define IPFORWARDAGE 8
41 #define IPFORWARDINFO 9
42 #define IPFORWARDNEXTHOPAS 10
43 #define IPFORWARDMETRIC1 11
44 #define IPFORWARDMETRIC2 12
45 #define IPFORWARDMETRIC3 13
46 #define IPFORWARDMETRIC4 14
47 #define IPFORWARDMETRIC5 15
48
49 /* ipCidrRouteTable */
50 #define IPCIDRROUTEDEST 1
51 #define IPCIDRROUTEMASK 2
52 #define IPCIDRROUTETOS 3
53 #define IPCIDRROUTENEXTHOP 4
54 #define IPCIDRROUTEIFINDEX 5
55 #define IPCIDRROUTETYPE 6
56 #define IPCIDRROUTEPROTO 7
57 #define IPCIDRROUTEAGE 8
58 #define IPCIDRROUTEINFO 9
59 #define IPCIDRROUTENEXTHOPAS 10
60 #define IPCIDRROUTEMETRIC1 11
61 #define IPCIDRROUTEMETRIC2 12
62 #define IPCIDRROUTEMETRIC3 13
63 #define IPCIDRROUTEMETRIC4 14
64 #define IPCIDRROUTEMETRIC5 15
65 #define IPCIDRROUTESTATUS 16
66
67 #define INTEGER32 ASN_INTEGER
68 #define GAUGE32 ASN_GAUGE
69 #define ENUMERATION ASN_INTEGER
70 #define ROWSTATUS ASN_INTEGER
71 #define IPADDRESS ASN_IPADDRESS
72 #define OBJECTIDENTIFIER ASN_OBJECT_ID
73
74 static oid ipfw_oid[] = {IPFWMIB};
75
76 /* Hook functions. */
77 static uint8_t *ipFwNumber(struct variable *, oid[], size_t *, int, size_t *,
78 WriteMethod **);
79 static uint8_t *ipFwTable(struct variable *, oid[], size_t *, int, size_t *,
80 WriteMethod **);
81 static uint8_t *ipCidrNumber(struct variable *, oid[], size_t *, int, size_t *,
82 WriteMethod **);
83 static uint8_t *ipCidrTable(struct variable *, oid[], size_t *, int, size_t *,
84 WriteMethod **);
85
86 static struct variable zebra_variables[] = {
87 {0, GAUGE32, RONLY, ipFwNumber, 1, {1}},
88 {IPFORWARDDEST, IPADDRESS, RONLY, ipFwTable, 3, {2, 1, 1}},
89 {IPFORWARDMASK, IPADDRESS, RONLY, ipFwTable, 3, {2, 1, 2}},
90 {IPFORWARDPOLICY, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 3}},
91 {IPFORWARDNEXTHOP, IPADDRESS, RONLY, ipFwTable, 3, {2, 1, 4}},
92 {IPFORWARDIFINDEX, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 5}},
93 {IPFORWARDTYPE, ENUMERATION, RONLY, ipFwTable, 3, {2, 1, 6}},
94 {IPFORWARDPROTO, ENUMERATION, RONLY, ipFwTable, 3, {2, 1, 7}},
95 {IPFORWARDAGE, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 8}},
96 {IPFORWARDINFO, OBJECTIDENTIFIER, RONLY, ipFwTable, 3, {2, 1, 9}},
97 {IPFORWARDNEXTHOPAS, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 10}},
98 {IPFORWARDMETRIC1, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 11}},
99 {IPFORWARDMETRIC2, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 12}},
100 {IPFORWARDMETRIC3, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 13}},
101 {IPFORWARDMETRIC4, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 14}},
102 {IPFORWARDMETRIC5, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 15}},
103 {0, GAUGE32, RONLY, ipCidrNumber, 1, {3}},
104 {IPCIDRROUTEDEST, IPADDRESS, RONLY, ipCidrTable, 3, {4, 1, 1}},
105 {IPCIDRROUTEMASK, IPADDRESS, RONLY, ipCidrTable, 3, {4, 1, 2}},
106 {IPCIDRROUTETOS, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 3}},
107 {IPCIDRROUTENEXTHOP, IPADDRESS, RONLY, ipCidrTable, 3, {4, 1, 4}},
108 {IPCIDRROUTEIFINDEX, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 5}},
109 {IPCIDRROUTETYPE, ENUMERATION, RONLY, ipCidrTable, 3, {4, 1, 6}},
110 {IPCIDRROUTEPROTO, ENUMERATION, RONLY, ipCidrTable, 3, {4, 1, 7}},
111 {IPCIDRROUTEAGE, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 8}},
112 {IPCIDRROUTEINFO, OBJECTIDENTIFIER, RONLY, ipCidrTable, 3, {4, 1, 9}},
113 {IPCIDRROUTENEXTHOPAS, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 10}},
114 {IPCIDRROUTEMETRIC1, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 11}},
115 {IPCIDRROUTEMETRIC2, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 12}},
116 {IPCIDRROUTEMETRIC3, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 13}},
117 {IPCIDRROUTEMETRIC4, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 14}},
118 {IPCIDRROUTEMETRIC5, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 15}},
119 {IPCIDRROUTESTATUS, ROWSTATUS, RONLY, ipCidrTable, 3, {4, 1, 16}}};
120
121
122 static uint8_t *ipFwNumber(struct variable *v, oid objid[], size_t *objid_len,
123 int exact, size_t *val_len,
124 WriteMethod **write_method)
125 {
126 static int result;
127 struct route_table *table;
128 struct route_node *rn;
129 struct route_entry *re;
130
131 if (smux_header_generic(v, objid, objid_len, exact, val_len,
132 write_method)
133 == MATCH_FAILED)
134 return NULL;
135
136 table = zebra_vrf_table(AFI_IP, SAFI_UNICAST, VRF_DEFAULT);
137 if (!table)
138 return NULL;
139
140 /* Return number of routing entries. */
141 result = 0;
142 for (rn = route_top(table); rn; rn = route_next(rn))
143 RNODE_FOREACH_RE (rn, re) {
144 result++;
145 }
146
147 return (uint8_t *)&result;
148 }
149
150 static uint8_t *ipCidrNumber(struct variable *v, oid objid[], size_t *objid_len,
151 int exact, size_t *val_len,
152 WriteMethod **write_method)
153 {
154 static int result;
155 struct route_table *table;
156 struct route_node *rn;
157 struct route_entry *re;
158
159 if (smux_header_generic(v, objid, objid_len, exact, val_len,
160 write_method)
161 == MATCH_FAILED)
162 return NULL;
163
164 table = zebra_vrf_table(AFI_IP, SAFI_UNICAST, VRF_DEFAULT);
165 if (!table)
166 return 0;
167
168 /* Return number of routing entries. */
169 result = 0;
170 for (rn = route_top(table); rn; rn = route_next(rn))
171 RNODE_FOREACH_RE (rn, re) {
172 result++;
173 }
174
175 return (uint8_t *)&result;
176 }
177
178 static int in_addr_cmp(uint8_t *p1, uint8_t *p2)
179 {
180 int i;
181
182 for (i = 0; i < 4; i++) {
183 if (*p1 < *p2)
184 return -1;
185 if (*p1 > *p2)
186 return 1;
187 p1++;
188 p2++;
189 }
190 return 0;
191 }
192
193 static int in_addr_add(uint8_t *p, int num)
194 {
195 int i, ip0;
196
197 ip0 = *p;
198 p += 4;
199 for (i = 3; 0 <= i; i--) {
200 p--;
201 if (*p + num > 255) {
202 *p += num;
203 num = 1;
204 } else {
205 *p += num;
206 return 1;
207 }
208 }
209 if (ip0 > *p) {
210 /* ip + num > 0xffffffff */
211 return 0;
212 }
213
214 return 1;
215 }
216
217 static int proto_trans(int type)
218 {
219 switch (type) {
220 case ZEBRA_ROUTE_SYSTEM:
221 return 1; /* other */
222 case ZEBRA_ROUTE_KERNEL:
223 return 1; /* other */
224 case ZEBRA_ROUTE_CONNECT:
225 return 2; /* local interface */
226 case ZEBRA_ROUTE_STATIC:
227 return 3; /* static route */
228 case ZEBRA_ROUTE_RIP:
229 return 8; /* rip */
230 case ZEBRA_ROUTE_RIPNG:
231 return 1; /* shouldn't happen */
232 case ZEBRA_ROUTE_OSPF:
233 return 13; /* ospf */
234 case ZEBRA_ROUTE_OSPF6:
235 return 1; /* shouldn't happen */
236 case ZEBRA_ROUTE_BGP:
237 return 14; /* bgp */
238 default:
239 return 1; /* other */
240 }
241 }
242
243 static void check_replace(struct route_node *np2, struct route_entry *re2,
244 struct route_node **np, struct route_entry **re)
245 {
246 int proto, proto2;
247
248 if (!*np) {
249 *np = np2;
250 *re = re2;
251 return;
252 }
253
254 if (prefix_cmp(&(*np)->p, &np2->p) < 0)
255 return;
256 if (prefix_cmp(&(*np)->p, &np2->p) > 0) {
257 *np = np2;
258 *re = re2;
259 return;
260 }
261
262 proto = proto_trans((*re)->type);
263 proto2 = proto_trans(re2->type);
264
265 if (proto2 > proto)
266 return;
267 if (proto2 < proto) {
268 *np = np2;
269 *re = re2;
270 return;
271 }
272
273 if (in_addr_cmp((uint8_t *)&(*re)->nhe->nhg.nexthop->gate.ipv4,
274 (uint8_t *)&re2->nhe->nhg.nexthop->gate.ipv4)
275 <= 0)
276 return;
277
278 *np = np2;
279 *re = re2;
280 return;
281 }
282
283 static void get_fwtable_route_node(struct variable *v, oid objid[],
284 size_t *objid_len, int exact,
285 struct route_node **np,
286 struct route_entry **re)
287 {
288 struct in_addr dest;
289 struct route_table *table;
290 struct route_node *np2;
291 struct route_entry *re2;
292 int proto;
293 int policy;
294 struct in_addr nexthop;
295 uint8_t *pnt;
296 int i;
297
298 /* Init index variables */
299
300 pnt = (uint8_t *)&dest;
301 for (i = 0; i < 4; i++)
302 *pnt++ = 0;
303
304 pnt = (uint8_t *)&nexthop;
305 for (i = 0; i < 4; i++)
306 *pnt++ = 0;
307
308 proto = 0;
309 policy = 0;
310
311 /* Init return variables */
312
313 *np = NULL;
314 *re = NULL;
315
316 /* Short circuit exact matches of wrong length */
317
318 if (exact && (*objid_len != (unsigned)v->namelen + 10))
319 return;
320
321 table = zebra_vrf_table(AFI_IP, SAFI_UNICAST, VRF_DEFAULT);
322 if (!table)
323 return;
324
325 /* Get INDEX information out of OID.
326 * ipForwardDest, ipForwardProto, ipForwardPolicy, ipForwardNextHop
327 */
328
329 if (*objid_len > (unsigned)v->namelen)
330 oid2in_addr(objid + v->namelen,
331 MIN(4U, *objid_len - v->namelen), &dest);
332
333 if (*objid_len > (unsigned)v->namelen + 4)
334 proto = objid[v->namelen + 4];
335
336 if (*objid_len > (unsigned)v->namelen + 5)
337 policy = objid[v->namelen + 5];
338
339 if (*objid_len > (unsigned)v->namelen + 6)
340 oid2in_addr(objid + v->namelen + 6,
341 MIN(4U, *objid_len - v->namelen - 6), &nexthop);
342
343 /* Apply GETNEXT on not exact search */
344
345 if (!exact && (*objid_len >= (unsigned)v->namelen + 10)) {
346 if (!in_addr_add((uint8_t *)&nexthop, 1))
347 return;
348 }
349
350 /* For exact: search matching entry in rib table. */
351
352 if (exact) {
353 if (policy) /* Not supported (yet?) */
354 return;
355 for (*np = route_top(table); *np; *np = route_next(*np)) {
356 if (!in_addr_cmp(&(*np)->p.u.prefix,
357 (uint8_t *)&dest)) {
358 RNODE_FOREACH_RE (*np, *re) {
359 if (!in_addr_cmp((uint8_t *)&(*re)->nhe
360 ->nhg.nexthop
361 ->gate.ipv4,
362 (uint8_t *)&nexthop))
363 if (proto
364 == proto_trans((*re)->type))
365 return;
366 }
367 }
368 }
369 return;
370 }
371
372 /* Search next best entry */
373
374 for (np2 = route_top(table); np2; np2 = route_next(np2)) {
375
376 /* Check destination first */
377 if (in_addr_cmp(&np2->p.u.prefix, (uint8_t *)&dest) > 0)
378 RNODE_FOREACH_RE (np2, re2) {
379 check_replace(np2, re2, np, re);
380 }
381
382 if (in_addr_cmp(&np2->p.u.prefix, (uint8_t *)&dest)
383 == 0) { /* have to look at each re individually */
384 RNODE_FOREACH_RE (np2, re2) {
385 int proto2, policy2;
386
387 proto2 = proto_trans(re2->type);
388 policy2 = 0;
389
390 if ((policy < policy2)
391 || ((policy == policy2) && (proto < proto2))
392 || ((policy == policy2) && (proto == proto2)
393 && (in_addr_cmp(
394 (uint8_t *)&re2->nhe
395 ->nhg.nexthop->gate.ipv4,
396 (uint8_t *)&nexthop)
397 >= 0)))
398 check_replace(np2, re2, np, re);
399 }
400 }
401 }
402
403 if (!*re)
404 return;
405
406 policy = 0;
407 proto = proto_trans((*re)->type);
408
409 *objid_len = v->namelen + 10;
410 pnt = (uint8_t *)&(*np)->p.u.prefix;
411 for (i = 0; i < 4; i++)
412 objid[v->namelen + i] = *pnt++;
413
414 objid[v->namelen + 4] = proto;
415 objid[v->namelen + 5] = policy;
416
417 {
418 struct nexthop *nexthop;
419
420 nexthop = (*re)->nhe->nhg.nexthop;
421 if (nexthop) {
422 pnt = (uint8_t *)&nexthop->gate.ipv4;
423 for (i = 0; i < 4; i++)
424 objid[i + v->namelen + 6] = *pnt++;
425 }
426 }
427
428 return;
429 }
430
431 static uint8_t *ipFwTable(struct variable *v, oid objid[], size_t *objid_len,
432 int exact, size_t *val_len,
433 WriteMethod **write_method)
434 {
435 struct route_node *np;
436 struct route_entry *re;
437 static int result;
438 static int resarr[2];
439 static struct in_addr netmask;
440 struct nexthop *nexthop;
441
442 if (smux_header_table(v, objid, objid_len, exact, val_len, write_method)
443 == MATCH_FAILED)
444 return NULL;
445
446 get_fwtable_route_node(v, objid, objid_len, exact, &np, &re);
447 if (!np)
448 return NULL;
449
450 nexthop = re->nhe->nhg.nexthop;
451 if (!nexthop)
452 return NULL;
453
454 switch (v->magic) {
455 case IPFORWARDDEST:
456 *val_len = 4;
457 return &np->p.u.prefix;
458 case IPFORWARDMASK:
459 masklen2ip(np->p.prefixlen, &netmask);
460 *val_len = 4;
461 return (uint8_t *)&netmask;
462 case IPFORWARDPOLICY:
463 result = 0;
464 *val_len = sizeof(int);
465 return (uint8_t *)&result;
466 case IPFORWARDNEXTHOP:
467 *val_len = 4;
468 return (uint8_t *)&nexthop->gate.ipv4;
469 case IPFORWARDIFINDEX:
470 *val_len = sizeof(int);
471 return (uint8_t *)&nexthop->ifindex;
472 case IPFORWARDTYPE:
473 if (nexthop->type == NEXTHOP_TYPE_IFINDEX)
474 result = 3;
475 else
476 result = 4;
477 *val_len = sizeof(int);
478 return (uint8_t *)&result;
479 case IPFORWARDPROTO:
480 result = proto_trans(re->type);
481 *val_len = sizeof(int);
482 return (uint8_t *)&result;
483 case IPFORWARDAGE:
484 result = 0;
485 *val_len = sizeof(int);
486 return (uint8_t *)&result;
487 case IPFORWARDINFO:
488 resarr[0] = 0;
489 resarr[1] = 0;
490 *val_len = 2 * sizeof(int);
491 return (uint8_t *)resarr;
492 case IPFORWARDNEXTHOPAS:
493 result = -1;
494 *val_len = sizeof(int);
495 return (uint8_t *)&result;
496 case IPFORWARDMETRIC1:
497 result = 0;
498 *val_len = sizeof(int);
499 return (uint8_t *)&result;
500 case IPFORWARDMETRIC2:
501 result = 0;
502 *val_len = sizeof(int);
503 return (uint8_t *)&result;
504 case IPFORWARDMETRIC3:
505 result = 0;
506 *val_len = sizeof(int);
507 return (uint8_t *)&result;
508 case IPFORWARDMETRIC4:
509 result = 0;
510 *val_len = sizeof(int);
511 return (uint8_t *)&result;
512 case IPFORWARDMETRIC5:
513 result = 0;
514 *val_len = sizeof(int);
515 return (uint8_t *)&result;
516 default:
517 return NULL;
518 }
519 return NULL;
520 }
521
522 static uint8_t *ipCidrTable(struct variable *v, oid objid[], size_t *objid_len,
523 int exact, size_t *val_len,
524 WriteMethod **write_method)
525 {
526 if (smux_header_table(v, objid, objid_len, exact, val_len, write_method)
527 == MATCH_FAILED)
528 return NULL;
529
530 switch (v->magic) {
531 case IPCIDRROUTEDEST:
532 break;
533 default:
534 return NULL;
535 }
536 return NULL;
537 }
538
539 static int zebra_snmp_init(struct thread_master *tm)
540 {
541 smux_init(tm);
542 REGISTER_MIB("mibII/ipforward", zebra_variables, variable, ipfw_oid);
543 return 0;
544 }
545
546 static int zebra_snmp_module_init(void)
547 {
548 hook_register(frr_late_init, zebra_snmp_init);
549 return 0;
550 }
551
552 FRR_MODULE_SETUP(.name = "zebra_snmp", .version = FRR_VERSION,
553 .description = "zebra AgentX SNMP module",
554 .init = zebra_snmp_module_init,
555 );