]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_snmp.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / zebra / zebra_snmp.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: GPL-2.0-or-later
07661cb5 2/* FIB SNMP.
718e3744 3 * Copyright (C) 1999 Kunihiro Ishiguro
718e3744 4 */
5
b72ede27
FL
6/*
7 * Currently SNMP is only running properly for MIBs in the default VRF.
8 */
9
718e3744 10#include <zebra.h>
11
07661cb5 12#include <net-snmp/net-snmp-config.h>
fb62a3ce 13#include <net-snmp/net-snmp-includes.h>
718e3744 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"
b72ede27 21#include "vrf.h"
5986b66b
DL
22#include "hook.h"
23#include "libfrr.h"
09781197 24#include "lib/version.h"
718e3744 25
26#include "zebra/rib.h"
dd488a78 27#include "zebra/zserv.h"
050ceb3b 28#include "zebra/zebra_vrf.h"
6b0655a2 29
718e3744 30#define IPFWMIB 1,3,6,1,2,1,4,24
718e3744 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
6b0655a2 73
d62a17ae 74static oid ipfw_oid[] = {IPFWMIB};
718e3744 75
76/* Hook functions. */
d7c0a89a
QY
77static uint8_t *ipFwNumber(struct variable *, oid[], size_t *, int, size_t *,
78 WriteMethod **);
79static uint8_t *ipFwTable(struct variable *, oid[], size_t *, int, size_t *,
d62a17ae 80 WriteMethod **);
d7c0a89a
QY
81static uint8_t *ipCidrNumber(struct variable *, oid[], size_t *, int, size_t *,
82 WriteMethod **);
83static uint8_t *ipCidrTable(struct variable *, oid[], size_t *, int, size_t *,
d62a17ae 84 WriteMethod **);
d62a17ae 85
86static 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
d7c0a89a
QY
122static uint8_t *ipFwNumber(struct variable *v, oid objid[], size_t *objid_len,
123 int exact, size_t *val_len,
124 WriteMethod **write_method)
718e3744 125{
d62a17ae 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))
a2addae8 143 RNODE_FOREACH_RE (rn, re) {
407c87a6
DS
144 result++;
145 }
d62a17ae 146
d7c0a89a 147 return (uint8_t *)&result;
718e3744 148}
149
d7c0a89a
QY
150static uint8_t *ipCidrNumber(struct variable *v, oid objid[], size_t *objid_len,
151 int exact, size_t *val_len,
152 WriteMethod **write_method)
718e3744 153{
d62a17ae 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))
a2addae8 171 RNODE_FOREACH_RE (rn, re) {
407c87a6
DS
172 result++;
173 }
d62a17ae 174
d7c0a89a 175 return (uint8_t *)&result;
718e3744 176}
177
d7c0a89a 178static int in_addr_cmp(uint8_t *p1, uint8_t *p2)
718e3744 179{
d62a17ae 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;
718e3744 191}
192
d7c0a89a 193static int in_addr_add(uint8_t *p, int num)
718e3744 194{
d62a17ae 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 }
718e3744 213
d62a17ae 214 return 1;
718e3744 215}
216
d62a17ae 217static int proto_trans(int type)
718e3744 218{
d62a17ae 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 }
718e3744 241}
242
d62a17ae 243static void check_replace(struct route_node *np2, struct route_entry *re2,
244 struct route_node **np, struct route_entry **re)
718e3744 245{
d62a17ae 246 int proto, proto2;
718e3744 247
d62a17ae 248 if (!*np) {
249 *np = np2;
250 *re = re2;
251 return;
252 }
718e3744 253
17e2f0bf 254 if (prefix_cmp(&(*np)->p, &np2->p) < 0)
d62a17ae 255 return;
17e2f0bf 256 if (prefix_cmp(&(*np)->p, &np2->p) > 0) {
d62a17ae 257 *np = np2;
258 *re = re2;
259 return;
260 }
718e3744 261
d62a17ae 262 proto = proto_trans((*re)->type);
263 proto2 = proto_trans(re2->type);
718e3744 264
d62a17ae 265 if (proto2 > proto)
266 return;
267 if (proto2 < proto) {
268 *np = np2;
269 *re = re2;
270 return;
271 }
718e3744 272
c415d895
MS
273 if (in_addr_cmp((uint8_t *)&(*re)->nhe->nhg.nexthop->gate.ipv4,
274 (uint8_t *)&re2->nhe->nhg.nexthop->gate.ipv4)
d62a17ae 275 <= 0)
276 return;
718e3744 277
d62a17ae 278 *np = np2;
279 *re = re2;
280 return;
281}
718e3744 282
d62a17ae 283static 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;
d7c0a89a 295 uint8_t *pnt;
d62a17ae 296 int i;
297
298 /* Init index variables */
299
d7c0a89a 300 pnt = (uint8_t *)&dest;
d62a17ae 301 for (i = 0; i < 4; i++)
302 *pnt++ = 0;
718e3744 303
d7c0a89a 304 pnt = (uint8_t *)&nexthop;
d62a17ae 305 for (i = 0; i < 4; i++)
306 *pnt++ = 0;
07661cb5 307
d62a17ae 308 proto = 0;
309 policy = 0;
718e3744 310
d62a17ae 311 /* Init return variables */
718e3744 312
d62a17ae 313 *np = NULL;
314 *re = NULL;
718e3744 315
d62a17ae 316 /* Short circuit exact matches of wrong length */
718e3744 317
d62a17ae 318 if (exact && (*objid_len != (unsigned)v->namelen + 10))
319 return;
718e3744 320
d62a17ae 321 table = zebra_vrf_table(AFI_IP, SAFI_UNICAST, VRF_DEFAULT);
322 if (!table)
323 return;
718e3744 324
d62a17ae 325 /* Get INDEX information out of OID.
326 * ipForwardDest, ipForwardProto, ipForwardPolicy, ipForwardNextHop
327 */
718e3744 328
d62a17ae 329 if (*objid_len > (unsigned)v->namelen)
330 oid2in_addr(objid + v->namelen,
331 MIN(4U, *objid_len - v->namelen), &dest);
718e3744 332
d62a17ae 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)) {
d7c0a89a 346 if (!in_addr_add((uint8_t *)&nexthop, 1))
d62a17ae 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)) {
d7c0a89a
QY
356 if (!in_addr_cmp(&(*np)->p.u.prefix,
357 (uint8_t *)&dest)) {
a2addae8 358 RNODE_FOREACH_RE (*np, *re) {
0eb97b86 359 if (!in_addr_cmp((uint8_t *)&(*re)->nhe
c415d895 360 ->nhg.nexthop
0eb97b86 361 ->gate.ipv4,
d7c0a89a 362 (uint8_t *)&nexthop))
d62a17ae 363 if (proto
364 == proto_trans((*re)->type))
365 return;
366 }
367 }
718e3744 368 }
d62a17ae 369 return;
718e3744 370 }
d62a17ae 371
372 /* Search next best entry */
373
374 for (np2 = route_top(table); np2; np2 = route_next(np2)) {
375
376 /* Check destination first */
d7c0a89a 377 if (in_addr_cmp(&np2->p.u.prefix, (uint8_t *)&dest) > 0)
a2addae8 378 RNODE_FOREACH_RE (np2, re2) {
407c87a6
DS
379 check_replace(np2, re2, np, re);
380 }
d62a17ae 381
d7c0a89a 382 if (in_addr_cmp(&np2->p.u.prefix, (uint8_t *)&dest)
d62a17ae 383 == 0) { /* have to look at each re individually */
a2addae8 384 RNODE_FOREACH_RE (np2, re2) {
d62a17ae 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)
7ee30f28 393 && (in_addr_cmp(
0eb97b86 394 (uint8_t *)&re2->nhe
c415d895 395 ->nhg.nexthop->gate.ipv4,
d7c0a89a 396 (uint8_t *)&nexthop)
d62a17ae 397 >= 0)))
398 check_replace(np2, re2, np, re);
399 }
400 }
718e3744 401 }
718e3744 402
d62a17ae 403 if (!*re)
404 return;
718e3744 405
d62a17ae 406 policy = 0;
407 proto = proto_trans((*re)->type);
718e3744 408
d62a17ae 409 *objid_len = v->namelen + 10;
d7c0a89a 410 pnt = (uint8_t *)&(*np)->p.u.prefix;
d62a17ae 411 for (i = 0; i < 4; i++)
412 objid[v->namelen + i] = *pnt++;
718e3744 413
d62a17ae 414 objid[v->namelen + 4] = proto;
415 objid[v->namelen + 5] = policy;
718e3744 416
d62a17ae 417 {
418 struct nexthop *nexthop;
718e3744 419
c415d895 420 nexthop = (*re)->nhe->nhg.nexthop;
d62a17ae 421 if (nexthop) {
d7c0a89a 422 pnt = (uint8_t *)&nexthop->gate.ipv4;
d62a17ae 423 for (i = 0; i < 4; i++)
424 objid[i + v->namelen + 6] = *pnt++;
425 }
426 }
718e3744 427
d62a17ae 428 return;
718e3744 429}
430
d7c0a89a
QY
431static uint8_t *ipFwTable(struct variable *v, oid objid[], size_t *objid_len,
432 int exact, size_t *val_len,
433 WriteMethod **write_method)
718e3744 434{
d62a17ae 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
c415d895 450 nexthop = re->nhe->nhg.nexthop;
d62a17ae 451 if (!nexthop)
452 return NULL;
453
454 switch (v->magic) {
455 case IPFORWARDDEST:
456 *val_len = 4;
457 return &np->p.u.prefix;
d62a17ae 458 case IPFORWARDMASK:
459 masklen2ip(np->p.prefixlen, &netmask);
460 *val_len = 4;
d7c0a89a 461 return (uint8_t *)&netmask;
d62a17ae 462 case IPFORWARDPOLICY:
463 result = 0;
464 *val_len = sizeof(int);
d7c0a89a 465 return (uint8_t *)&result;
d62a17ae 466 case IPFORWARDNEXTHOP:
467 *val_len = 4;
d7c0a89a 468 return (uint8_t *)&nexthop->gate.ipv4;
d62a17ae 469 case IPFORWARDIFINDEX:
470 *val_len = sizeof(int);
d7c0a89a 471 return (uint8_t *)&nexthop->ifindex;
d62a17ae 472 case IPFORWARDTYPE:
473 if (nexthop->type == NEXTHOP_TYPE_IFINDEX)
474 result = 3;
475 else
476 result = 4;
477 *val_len = sizeof(int);
d7c0a89a 478 return (uint8_t *)&result;
d62a17ae 479 case IPFORWARDPROTO:
480 result = proto_trans(re->type);
481 *val_len = sizeof(int);
d7c0a89a 482 return (uint8_t *)&result;
d62a17ae 483 case IPFORWARDAGE:
484 result = 0;
485 *val_len = sizeof(int);
d7c0a89a 486 return (uint8_t *)&result;
d62a17ae 487 case IPFORWARDINFO:
488 resarr[0] = 0;
489 resarr[1] = 0;
490 *val_len = 2 * sizeof(int);
d7c0a89a 491 return (uint8_t *)resarr;
d62a17ae 492 case IPFORWARDNEXTHOPAS:
493 result = -1;
494 *val_len = sizeof(int);
d7c0a89a 495 return (uint8_t *)&result;
d62a17ae 496 case IPFORWARDMETRIC1:
497 result = 0;
498 *val_len = sizeof(int);
d7c0a89a 499 return (uint8_t *)&result;
d62a17ae 500 case IPFORWARDMETRIC2:
501 result = 0;
502 *val_len = sizeof(int);
d7c0a89a 503 return (uint8_t *)&result;
d62a17ae 504 case IPFORWARDMETRIC3:
505 result = 0;
506 *val_len = sizeof(int);
d7c0a89a 507 return (uint8_t *)&result;
d62a17ae 508 case IPFORWARDMETRIC4:
509 result = 0;
510 *val_len = sizeof(int);
d7c0a89a 511 return (uint8_t *)&result;
d62a17ae 512 case IPFORWARDMETRIC5:
513 result = 0;
514 *val_len = sizeof(int);
d7c0a89a 515 return (uint8_t *)&result;
d62a17ae 516 default:
517 return NULL;
d62a17ae 518 }
519 return NULL;
718e3744 520}
521
d7c0a89a
QY
522static uint8_t *ipCidrTable(struct variable *v, oid objid[], size_t *objid_len,
523 int exact, size_t *val_len,
524 WriteMethod **write_method)
718e3744 525{
d62a17ae 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;
d62a17ae 535 }
536 return NULL;
718e3744 537}
538
d62a17ae 539static int zebra_snmp_init(struct thread_master *tm)
718e3744 540{
d62a17ae 541 smux_init(tm);
542 REGISTER_MIB("mibII/ipforward", zebra_variables, variable, ipfw_oid);
543 return 0;
5986b66b
DL
544}
545
d62a17ae 546static int zebra_snmp_module_init(void)
5986b66b 547{
d62a17ae 548 hook_register(frr_late_init, zebra_snmp_init);
549 return 0;
718e3744 550}
5986b66b 551
d62a17ae 552FRR_MODULE_SETUP(.name = "zebra_snmp", .version = FRR_VERSION,
553 .description = "zebra AgentX SNMP module",
80413c20
DL
554 .init = zebra_snmp_module_init,
555);