]> git.proxmox.com Git - mirror_frr.git/blob - bgpd/bgp_mplsvpn_snmp.c
*: Rename thread.[ch] to event.[ch]
[mirror_frr.git] / bgpd / bgp_mplsvpn_snmp.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* MPLS/BGP L3VPN MIB
3 * Copyright (C) 2020 Volta Networks Inc
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 "log.h"
13 #include "prefix.h"
14 #include "command.h"
15 #include "event.h"
16 #include "smux.h"
17 #include "filter.h"
18 #include "hook.h"
19 #include "libfrr.h"
20 #include "lib/version.h"
21
22 #include "bgpd/bgpd.h"
23 #include "bgpd/bgp_route.h"
24 #include "bgpd/bgp_attr.h"
25 #include "bgpd/bgp_ecommunity.h"
26 #include "bgpd/bgp_mplsvpn.h"
27 #include "bgpd/bgp_mplsvpn_snmp.h"
28
29 #define BGP_mplsvpn_notif_enable_true 1
30 #define BGP_mplsvpn_notif_enable_false 2
31
32 /* MPLSL3VPN MIB described in RFC4382 */
33 #define MPLSL3VPNMIB 1, 3, 6, 1, 2, 1, 10, 166, 11
34
35 /* MPLSL3VPN Scalars */
36 #define MPLSL3VPNCONFIGUREDVRFS 1
37 #define MPLSL3VPNACTIVEVRFS 2
38 #define MPLSL3VPNCONNECTEDINTERFACES 3
39 #define MPLSL3VPNNOTIFICATIONENABLE 4
40 #define MPLSL3VPNCONFMAXPOSSRTS 5
41 #define MPLSL3VPNVRFCONFRTEMXTHRSHTIME 6
42 #define MPLSL3VPNILLLBLRCVTHRSH 7
43
44 /* MPLSL3VPN IFConf Table */
45 #define MPLSL3VPNIFVPNCLASSIFICATION 1
46 #define MPLSL3VPNIFCONFSTORAGETYPE 2
47 #define MPLSL3VPNIFCONFROWSTATUS 3
48
49 /* MPLSL3VPN VRF Table */
50 #define MPLSL3VPNVRFVPNID 1
51 #define MPLSL3VPNVRFDESC 2
52 #define MPLSL3VPNVRFRD 3
53 #define MPLSL3VPNVRFCREATIONTIME 4
54 #define MPLSL3VPNVRFOPERSTATUS 5
55 #define MPLSL3VPNVRFACTIVEINTERFACES 6
56 #define MPLSL3VPNVRFASSOCIATEDINTERFACES 7
57 #define MPLSL3VPNVRFCONFMIDRTETHRESH 8
58 #define MPLSL3VPNVRFCONFHIGHRTETHRSH 9
59 #define MPLSL3VPNVRFCONFMAXROUTES 10
60 #define MPLSL3VPNVRFCONFLASTCHANGED 11
61 #define MPLSL3VPNVRFCONFROWSTATUS 12
62 #define MPLSL3VPNVRFCONFADMINSTATUS 13
63 #define MPLSL3VPNVRFCONFSTORAGETYPE 14
64
65 /* MPLSL3VPN RT Table */
66 #define MPLSL3VPNVRFRT 1
67 #define MPLSL3VPNVRFRTDESCR 2
68 #define MPLSL3VPNVRFRTROWSTATUS 3
69 #define MPLSL3VPNVRFRTSTORAGETYPE 4
70
71 /* MPLSL3VPN PERF Table */
72 #define MPLSL3VPNVRFPERFROUTESADDED 1
73 #define MPLSL3VPNVRFPERFROUTESDELETED 2
74 #define MPLSL3VPNVRFPERFCURRNUMROUTES 3
75
76 /* MPLSL3VPN RTE Table */
77 #define MPLSL3VPNVRFRTEINETCIDRDESTTYPE 1
78 #define MPLSL3VPNVRFRTEINETCIDRDEST 2
79 #define MPLSL3VPNVRFRTEINETCIDRPFXLEN 3
80 #define MPLSL3VPNVRFRTEINETCIDRPOLICY 4
81 #define MPLSL3VPNVRFRTEINETCIDRNHOPTYPE 5
82 #define MPLSL3VPNVRFRTEINETCIDRNEXTHOP 6
83 #define MPLSL3VPNVRFRTEINETCIDRIFINDEX 7
84 #define MPLSL3VPNVRFRTEINETCIDRTYPE 8
85 #define MPLSL3VPNVRFRTEINETCIDRPROTO 9
86 #define MPLSL3VPNVRFRTEINETCIDRAGE 10
87 #define MPLSL3VPNVRFRTEINETCIDRNEXTHOPAS 11
88 #define MPLSL3VPNVRFRTEINETCIDRMETRIC1 12
89 #define MPLSL3VPNVRFRTEINETCIDRMETRIC2 13
90 #define MPLSL3VPNVRFRTEINETCIDRMETRIC3 14
91 #define MPLSL3VPNVRFRTEINETCIDRMETRIC4 15
92 #define MPLSL3VPNVRFRTEINETCIDRMETRIC5 16
93 #define MPLSL3VPNVRFRTEINETCIDRXCPOINTER 17
94 #define MPLSL3VPNVRFRTEINETCIDRSTATUS 18
95
96 /* BGP Trap */
97 #define MPLSL3VPNVRFUP 1
98 #define MPLSL3VPNDOWN 2
99
100 /* SNMP value hack. */
101 #define INTEGER ASN_INTEGER
102 #define INTEGER32 ASN_INTEGER
103 #define COUNTER32 ASN_COUNTER
104 #define OCTET_STRING ASN_OCTET_STR
105 #define IPADDRESS ASN_IPADDRESS
106 #define GAUGE32 ASN_UNSIGNED
107 #define TIMETICKS ASN_TIMETICKS
108 #define OID ASN_OBJECT_ID
109
110 /* Declare static local variables for convenience. */
111 SNMP_LOCAL_VARIABLES
112
113 #define RT_PREAMBLE_SIZE 20
114
115 /* BGP-MPLS-MIB instances */
116 static oid mpls_l3vpn_oid[] = {MPLSL3VPNMIB};
117 static oid mpls_l3vpn_trap_oid[] = {MPLSL3VPNMIB, 0};
118 static char rd_buf[RD_ADDRSTRLEN];
119 /* Notifications enabled by default */
120 static uint8_t bgp_mplsvpn_notif_enable = SNMP_TRUE;
121 static oid mpls_l3vpn_policy_oid[2] = {0, 0};
122 static const char *empty_nhop = "";
123 char rt_description[VRF_NAMSIZ + RT_PREAMBLE_SIZE];
124
125 static uint8_t *mplsL3vpnConfiguredVrfs(struct variable *, oid[], size_t *, int,
126 size_t *, WriteMethod **);
127
128 static uint8_t *mplsL3vpnActiveVrfs(struct variable *, oid[], size_t *, int,
129 size_t *, WriteMethod **);
130
131 static uint8_t *mplsL3vpnConnectedInterfaces(struct variable *, oid[], size_t *,
132 int, size_t *, WriteMethod **);
133
134 static uint8_t *mplsL3vpnNotificationEnable(struct variable *, oid[], size_t *,
135 int, size_t *, WriteMethod **);
136
137 static uint8_t *mplsL3vpnVrfConfMaxPossRts(struct variable *, oid[], size_t *,
138 int, size_t *, WriteMethod **);
139
140 static uint8_t *mplsL3vpnVrfConfRteMxThrshTime(struct variable *, oid[],
141 size_t *, int, size_t *,
142 WriteMethod **);
143
144 static uint8_t *mplsL3vpnIllLblRcvThrsh(struct variable *, oid[], size_t *, int,
145 size_t *, WriteMethod **);
146
147 static uint8_t *mplsL3vpnVrfTable(struct variable *, oid[], size_t *, int,
148 size_t *, WriteMethod **);
149
150 static uint8_t *mplsL3vpnVrfRtTable(struct variable *, oid[], size_t *, int,
151 size_t *, WriteMethod **);
152
153 static uint8_t *mplsL3vpnIfConfTable(struct variable *, oid[], size_t *, int,
154 size_t *, WriteMethod **);
155
156 static uint8_t *mplsL3vpnPerfTable(struct variable *, oid[], size_t *, int,
157 size_t *, WriteMethod **);
158
159 static uint8_t *mplsL3vpnRteTable(struct variable *, oid[], size_t *, int,
160 size_t *, WriteMethod **);
161
162
163 static struct variable mpls_l3vpn_variables[] = {
164 /* BGP version. */
165 {MPLSL3VPNCONFIGUREDVRFS,
166 GAUGE32,
167 RONLY,
168 mplsL3vpnConfiguredVrfs,
169 3,
170 {1, 1, 1} },
171 {MPLSL3VPNACTIVEVRFS,
172 GAUGE32,
173 RONLY,
174 mplsL3vpnActiveVrfs,
175 3,
176 {1, 1, 2} },
177 {MPLSL3VPNCONNECTEDINTERFACES,
178 GAUGE32,
179 RONLY,
180 mplsL3vpnConnectedInterfaces,
181 3,
182 {1, 1, 3} },
183 {MPLSL3VPNNOTIFICATIONENABLE,
184 INTEGER,
185 RWRITE,
186 mplsL3vpnNotificationEnable,
187 3,
188 {1, 1, 4} },
189 {MPLSL3VPNCONFMAXPOSSRTS,
190 GAUGE32,
191 RONLY,
192 mplsL3vpnVrfConfMaxPossRts,
193 3,
194 {1, 1, 5} },
195 {MPLSL3VPNVRFCONFRTEMXTHRSHTIME,
196 GAUGE32,
197 RONLY,
198 mplsL3vpnVrfConfRteMxThrshTime,
199 3,
200 {1, 1, 6} },
201 {MPLSL3VPNILLLBLRCVTHRSH,
202 GAUGE32,
203 RONLY,
204 mplsL3vpnIllLblRcvThrsh,
205 3,
206 {1, 1, 7} },
207
208 /* Ifconf Table */
209 {MPLSL3VPNIFVPNCLASSIFICATION,
210 INTEGER,
211 RONLY,
212 mplsL3vpnIfConfTable,
213 5,
214 {1, 2, 1, 1, 2} },
215 {MPLSL3VPNIFCONFSTORAGETYPE,
216 INTEGER,
217 RONLY,
218 mplsL3vpnIfConfTable,
219 5,
220 {1, 2, 1, 1, 4} },
221 {MPLSL3VPNIFCONFROWSTATUS,
222 INTEGER,
223 RONLY,
224 mplsL3vpnIfConfTable,
225 5,
226 {1, 2, 1, 1, 5} },
227
228 /* mplsL3VpnVrf Table */
229 {MPLSL3VPNVRFVPNID,
230 OCTET_STRING,
231 RONLY,
232 mplsL3vpnVrfTable,
233 5,
234 {1, 2, 2, 1, 2} },
235 {MPLSL3VPNVRFDESC,
236 OCTET_STRING,
237 RONLY,
238 mplsL3vpnVrfTable,
239 5,
240 {1, 2, 2, 1, 3} },
241 {MPLSL3VPNVRFRD,
242 OCTET_STRING,
243 RONLY,
244 mplsL3vpnVrfTable,
245 5,
246 {1, 2, 2, 1, 4} },
247 {MPLSL3VPNVRFCREATIONTIME,
248 TIMETICKS,
249 RONLY,
250 mplsL3vpnVrfTable,
251 5,
252 {1, 2, 2, 1, 5} },
253 {MPLSL3VPNVRFOPERSTATUS,
254 INTEGER,
255 RONLY,
256 mplsL3vpnVrfTable,
257 5,
258 {1, 2, 2, 1, 6} },
259 {MPLSL3VPNVRFACTIVEINTERFACES,
260 GAUGE32,
261 RONLY,
262 mplsL3vpnVrfTable,
263 5,
264 {1, 2, 2, 1, 7} },
265 {MPLSL3VPNVRFASSOCIATEDINTERFACES,
266 GAUGE32,
267 RONLY,
268 mplsL3vpnVrfTable,
269 5,
270 {1, 2, 2, 1, 8} },
271 {MPLSL3VPNVRFCONFMIDRTETHRESH,
272 GAUGE32,
273 RONLY,
274 mplsL3vpnVrfTable,
275 5,
276 {1, 2, 2, 1, 9} },
277 {MPLSL3VPNVRFCONFHIGHRTETHRSH,
278 GAUGE32,
279 RONLY,
280 mplsL3vpnVrfTable,
281 5,
282 {1, 2, 2, 1, 10} },
283 {MPLSL3VPNVRFCONFMAXROUTES,
284 GAUGE32,
285 RONLY,
286 mplsL3vpnVrfTable,
287 5,
288 {1, 2, 2, 1, 11} },
289 {MPLSL3VPNVRFCONFLASTCHANGED,
290 TIMETICKS,
291 RONLY,
292 mplsL3vpnVrfTable,
293 5,
294 {1, 2, 2, 1, 12} },
295 {MPLSL3VPNVRFCONFROWSTATUS,
296 INTEGER,
297 RONLY,
298 mplsL3vpnVrfTable,
299 5,
300 {1, 2, 2, 1, 13} },
301 {MPLSL3VPNVRFCONFADMINSTATUS,
302 INTEGER,
303 RONLY,
304 mplsL3vpnVrfTable,
305 5,
306 {1, 2, 2, 1, 14} },
307 {MPLSL3VPNVRFCONFSTORAGETYPE,
308 INTEGER,
309 RONLY,
310 mplsL3vpnVrfTable,
311 5,
312 {1, 2, 2, 1, 15} },
313
314 /* mplsL3vpnVrfRt Table */
315 {MPLSL3VPNVRFRT,
316 OCTET_STRING,
317 RONLY,
318 mplsL3vpnVrfRtTable,
319 5,
320 {1, 2, 3, 1, 4} },
321 {MPLSL3VPNVRFRTDESCR,
322 OCTET_STRING,
323 RONLY,
324 mplsL3vpnVrfRtTable,
325 5,
326 {1, 2, 3, 1, 5} },
327 {MPLSL3VPNVRFRTROWSTATUS,
328 INTEGER,
329 RONLY,
330 mplsL3vpnVrfRtTable,
331 5,
332 {1, 2, 3, 1, 6} },
333 {MPLSL3VPNVRFRTSTORAGETYPE,
334 INTEGER,
335 RONLY,
336 mplsL3vpnVrfRtTable,
337 5,
338 {1, 2, 3, 1, 7} },
339
340 /* mplsL3VpnPerfTable */
341 {MPLSL3VPNVRFPERFROUTESADDED,
342 COUNTER32,
343 RONLY,
344 mplsL3vpnPerfTable,
345 5,
346 {1, 3, 1, 1, 1} },
347 {MPLSL3VPNVRFPERFROUTESDELETED,
348 COUNTER32,
349 RONLY,
350 mplsL3vpnPerfTable,
351 5,
352 {1, 3, 1, 1, 2} },
353 {MPLSL3VPNVRFPERFCURRNUMROUTES,
354 GAUGE32,
355 RONLY,
356 mplsL3vpnPerfTable,
357 5,
358 {1, 3, 1, 1, 3} },
359
360 /* mplsVpnRteTable */
361 {MPLSL3VPNVRFRTEINETCIDRDESTTYPE,
362 INTEGER,
363 RONLY,
364 mplsL3vpnRteTable,
365 5,
366 {1, 4, 1, 1, 1} },
367 {MPLSL3VPNVRFRTEINETCIDRDEST,
368 OCTET_STRING,
369 RONLY,
370 mplsL3vpnRteTable,
371 5,
372 {1, 4, 1, 1, 2} },
373 {MPLSL3VPNVRFRTEINETCIDRPFXLEN,
374 GAUGE32,
375 RONLY,
376 mplsL3vpnRteTable,
377 5,
378 {1, 4, 1, 1, 3} },
379 {MPLSL3VPNVRFRTEINETCIDRPOLICY,
380 OID,
381 RONLY,
382 mplsL3vpnRteTable,
383 5,
384 {1, 4, 1, 1, 4} },
385 {MPLSL3VPNVRFRTEINETCIDRNHOPTYPE,
386 INTEGER,
387 RONLY,
388 mplsL3vpnRteTable,
389 5,
390 {1, 4, 1, 1, 5} },
391 {MPLSL3VPNVRFRTEINETCIDRNEXTHOP,
392 OCTET_STRING,
393 RONLY,
394 mplsL3vpnRteTable,
395 5,
396 {1, 4, 1, 1, 6} },
397 {MPLSL3VPNVRFRTEINETCIDRIFINDEX,
398 INTEGER,
399 RONLY,
400 mplsL3vpnRteTable,
401 5,
402 {1, 4, 1, 1, 7} },
403 {MPLSL3VPNVRFRTEINETCIDRTYPE,
404 INTEGER,
405 RONLY,
406 mplsL3vpnRteTable,
407 5,
408 {1, 4, 1, 1, 8} },
409 {MPLSL3VPNVRFRTEINETCIDRPROTO,
410 INTEGER,
411 RONLY,
412 mplsL3vpnRteTable,
413 5,
414 {1, 4, 1, 1, 9} },
415 {MPLSL3VPNVRFRTEINETCIDRAGE,
416 GAUGE32,
417 RONLY,
418 mplsL3vpnRteTable,
419 5,
420 {1, 4, 1, 1, 10} },
421 {MPLSL3VPNVRFRTEINETCIDRNEXTHOPAS,
422 GAUGE32,
423 RONLY,
424 mplsL3vpnRteTable,
425 5,
426 {1, 4, 1, 1, 11} },
427 {MPLSL3VPNVRFRTEINETCIDRMETRIC1,
428 INTEGER,
429 RONLY,
430 mplsL3vpnRteTable,
431 5,
432 {1, 4, 1, 1, 12} },
433 {MPLSL3VPNVRFRTEINETCIDRMETRIC2,
434 INTEGER,
435 RONLY,
436 mplsL3vpnRteTable,
437 5,
438 {1, 4, 1, 1, 13} },
439 {MPLSL3VPNVRFRTEINETCIDRMETRIC3,
440 INTEGER,
441 RONLY,
442 mplsL3vpnRteTable,
443 5,
444 {1, 4, 1, 1, 14} },
445 {MPLSL3VPNVRFRTEINETCIDRMETRIC4,
446 INTEGER,
447 RONLY,
448 mplsL3vpnRteTable,
449 5,
450 {1, 4, 1, 1, 15} },
451 {MPLSL3VPNVRFRTEINETCIDRMETRIC5,
452 INTEGER,
453 RONLY,
454 mplsL3vpnRteTable,
455 5,
456 {1, 4, 1, 1, 16} },
457 {MPLSL3VPNVRFRTEINETCIDRXCPOINTER,
458 OCTET_STRING,
459 RONLY,
460 mplsL3vpnRteTable,
461 5,
462 {1, 4, 1, 1, 17} },
463 {MPLSL3VPNVRFRTEINETCIDRSTATUS,
464 INTEGER,
465 RONLY,
466 mplsL3vpnRteTable,
467 5,
468 {1, 4, 1, 1, 18} },
469 };
470
471 /* timeticks are in hundredths of a second */
472 static void bgp_mpls_l3vpn_update_timeticks(time_t *counter)
473 {
474 struct timeval tv;
475
476 monotime(&tv);
477 *counter = (tv.tv_sec * 100) + (tv.tv_usec / 10000);
478 }
479
480 static int bgp_mpls_l3vpn_update_last_changed(struct bgp *bgp)
481 {
482 if (bgp->snmp_stats)
483 bgp_mpls_l3vpn_update_timeticks(
484 &(bgp->snmp_stats->modify_time));
485 return 0;
486 }
487
488 static uint32_t bgp_mpls_l3vpn_current_routes(struct bgp *l3vpn_bgp)
489 {
490 uint32_t count = 0;
491 struct bgp_table *table;
492 struct bgp_dest *dest;
493 struct bgp_path_info *pi;
494
495 table = l3vpn_bgp->rib[AFI_IP][SAFI_UNICAST];
496 for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) {
497 pi = bgp_dest_get_bgp_path_info(dest);
498 for (; pi; pi = pi->next)
499 count++;
500 }
501 table = l3vpn_bgp->rib[AFI_IP6][SAFI_UNICAST];
502 for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) {
503 pi = bgp_dest_get_bgp_path_info(dest);
504 for (; pi; pi = pi->next)
505 count++;
506 }
507 return count;
508 }
509
510 static int bgp_init_snmp_stats(struct bgp *bgp)
511 {
512 if (is_bgp_vrf_mplsvpn(bgp)) {
513 if (bgp->snmp_stats == NULL) {
514 bgp->snmp_stats = XCALLOC(
515 MTYPE_BGP, sizeof(struct bgp_snmp_stats));
516 /* fix up added routes */
517 if (bgp->snmp_stats) {
518 bgp->snmp_stats->routes_added =
519 bgp_mpls_l3vpn_current_routes(bgp);
520 bgp_mpls_l3vpn_update_timeticks(
521 &(bgp->snmp_stats->creation_time));
522 }
523 }
524 } else {
525 if (bgp->snmp_stats) {
526 XFREE(MTYPE_BGP, bgp->snmp_stats);
527 bgp->snmp_stats = NULL;
528 }
529 }
530 /* Something changed - update the timestamp */
531 bgp_mpls_l3vpn_update_last_changed(bgp);
532 return 0;
533 }
534
535 static int bgp_snmp_update_route_stats(struct bgp_dest *dest,
536 struct bgp_path_info *pi, bool added)
537 {
538 struct bgp_table *table;
539
540 if (dest) {
541 table = bgp_dest_table(dest);
542 /* only update if we have a stats block - MPLSVPN vrfs for now*/
543 if (table && table->bgp && table->bgp->snmp_stats) {
544 if (added)
545 table->bgp->snmp_stats->routes_added++;
546 else
547 table->bgp->snmp_stats->routes_deleted++;
548 }
549 }
550 return 0;
551 }
552
553 static bool is_bgp_vrf_active(struct bgp *bgp)
554 {
555 struct vrf *vrf;
556 struct interface *ifp;
557
558 /* if there is one interface in the vrf which is up then it is deemed
559 * active
560 */
561 vrf = vrf_lookup_by_id(bgp->vrf_id);
562 if (vrf == NULL)
563 return false;
564 RB_FOREACH (ifp, if_name_head, &vrf->ifaces_by_name) {
565 /* if we are in a vrf skip the l3mdev */
566 if (bgp->name && strncmp(ifp->name, bgp->name, VRF_NAMSIZ) == 0)
567 continue;
568
569 if (if_is_up(ifp))
570 return true;
571 }
572 return false;
573 }
574
575 /* BGP Traps. */
576 static struct trap_object l3vpn_trap_list[] = {{5, {1, 2, 1, 1, 5} },
577 {5, {1, 2, 2, 1, 6} } };
578
579 static int bgp_vrf_check_update_active(struct bgp *bgp, struct interface *ifp)
580 {
581 bool new_active = false;
582 oid trap;
583 struct index_oid trap_index[2];
584
585 if (!is_bgp_vrf_mplsvpn(bgp) || bgp->snmp_stats == NULL
586 || !bgp_mplsvpn_notif_enable)
587 return 0;
588 new_active = is_bgp_vrf_active(bgp);
589 if (bgp->snmp_stats->active != new_active) {
590 /* add trap in here */
591 bgp->snmp_stats->active = new_active;
592
593 /* send relevent trap */
594 if (bgp->snmp_stats->active)
595 trap = MPLSL3VPNVRFUP;
596 else
597 trap = MPLSL3VPNDOWN;
598
599 /*
600 * first index vrf_name + ifindex
601 * second index vrf_name
602 */
603 trap_index[1].indexlen = strnlen(bgp->name, VRF_NAMSIZ);
604 oid_copy_str(trap_index[0].indexname, bgp->name,
605 trap_index[1].indexlen);
606 oid_copy_str(trap_index[1].indexname, bgp->name,
607 trap_index[1].indexlen);
608 trap_index[0].indexlen =
609 trap_index[1].indexlen + sizeof(ifindex_t);
610 oid_copy_int(trap_index[0].indexname + trap_index[1].indexlen,
611 (int *)&(ifp->ifindex));
612
613 smux_trap_multi_index(
614 mpls_l3vpn_variables, array_size(mpls_l3vpn_variables),
615 mpls_l3vpn_trap_oid, array_size(mpls_l3vpn_trap_oid),
616 mpls_l3vpn_oid, sizeof(mpls_l3vpn_oid) / sizeof(oid),
617 trap_index, array_size(trap_index), l3vpn_trap_list,
618 array_size(l3vpn_trap_list), trap);
619 }
620 bgp_mpls_l3vpn_update_last_changed(bgp);
621 return 0;
622 }
623
624 static uint8_t *mplsL3vpnConfiguredVrfs(struct variable *v, oid name[],
625 size_t *length, int exact,
626 size_t *var_len,
627 WriteMethod **write_method)
628 {
629 struct listnode *node, *nnode;
630 struct bgp *bgp;
631 uint32_t count = 0;
632
633 if (smux_header_generic(v, name, length, exact, var_len, write_method)
634 == MATCH_FAILED)
635 return NULL;
636
637 for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
638 if (is_bgp_vrf_mplsvpn(bgp))
639 count++;
640 }
641 return SNMP_INTEGER(count);
642 }
643
644 static uint8_t *mplsL3vpnActiveVrfs(struct variable *v, oid name[],
645 size_t *length, int exact, size_t *var_len,
646 WriteMethod **write_method)
647 {
648 struct listnode *node, *nnode;
649 struct bgp *bgp;
650 uint32_t count = 0;
651
652 if (smux_header_generic(v, name, length, exact, var_len, write_method)
653 == MATCH_FAILED)
654 return NULL;
655
656 for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
657 if (is_bgp_vrf_mplsvpn(bgp) && is_bgp_vrf_active(bgp))
658 count++;
659 }
660 return SNMP_INTEGER(count);
661 }
662
663 static uint8_t *mplsL3vpnConnectedInterfaces(struct variable *v, oid name[],
664 size_t *length, int exact,
665 size_t *var_len,
666 WriteMethod **write_method)
667 {
668 struct listnode *node, *nnode;
669 struct bgp *bgp;
670 uint32_t count = 0;
671 struct vrf *vrf;
672
673 if (smux_header_generic(v, name, length, exact, var_len, write_method)
674 == MATCH_FAILED)
675 return NULL;
676
677 for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
678 if (is_bgp_vrf_mplsvpn(bgp)) {
679 vrf = vrf_lookup_by_name(bgp->name);
680 if (vrf == NULL)
681 continue;
682
683 count += vrf_interface_count(vrf);
684 }
685 }
686
687 return SNMP_INTEGER(count);
688 }
689
690 static int write_mplsL3vpnNotificationEnable(int action, uint8_t *var_val,
691 uint8_t var_val_type,
692 size_t var_val_len, uint8_t *statP,
693 oid *name, size_t length)
694 {
695 uint32_t intval;
696
697 if (var_val_type != ASN_INTEGER)
698 return SNMP_ERR_WRONGTYPE;
699
700 if (var_val_len != sizeof(long))
701 return SNMP_ERR_WRONGLENGTH;
702
703 intval = *(long *)var_val;
704 bgp_mplsvpn_notif_enable = intval;
705 return SNMP_ERR_NOERROR;
706 }
707
708 static uint8_t *mplsL3vpnNotificationEnable(struct variable *v, oid name[],
709 size_t *length, int exact,
710 size_t *var_len,
711 WriteMethod **write_method)
712 {
713 if (smux_header_generic(v, name, length, exact, var_len, write_method)
714 == MATCH_FAILED)
715 return NULL;
716
717 *write_method = write_mplsL3vpnNotificationEnable;
718 return SNMP_INTEGER(bgp_mplsvpn_notif_enable);
719 }
720
721 static uint8_t *mplsL3vpnVrfConfMaxPossRts(struct variable *v, oid name[],
722 size_t *length, int exact,
723 size_t *var_len,
724 WriteMethod **write_method)
725 {
726 if (smux_header_generic(v, name, length, exact, var_len, write_method)
727 == MATCH_FAILED)
728 return NULL;
729
730 return SNMP_INTEGER(0);
731 }
732
733 static uint8_t *mplsL3vpnVrfConfRteMxThrshTime(struct variable *v, oid name[],
734 size_t *length, int exact,
735 size_t *var_len,
736 WriteMethod **write_method)
737 {
738 if (smux_header_generic(v, name, length, exact, var_len, write_method)
739 == MATCH_FAILED)
740 return NULL;
741
742 return SNMP_INTEGER(0);
743 }
744
745 static uint8_t *mplsL3vpnIllLblRcvThrsh(struct variable *v, oid name[],
746 size_t *length, int exact,
747 size_t *var_len,
748 WriteMethod **write_method)
749 {
750 if (smux_header_generic(v, name, length, exact, var_len, write_method)
751 == MATCH_FAILED)
752 return NULL;
753
754 return SNMP_INTEGER(0);
755 }
756
757
758 static struct bgp *bgp_lookup_by_name_next(char *vrf_name)
759 {
760 struct bgp *bgp, *bgp_next = NULL;
761 struct listnode *node, *nnode;
762 bool first = false;
763
764 /*
765 * the vrfs are not stored alphabetically but since we are using the
766 * vrf name as an index we need the getnext function to return them
767 * in a atrict order. Thus run through and find the best next one.
768 */
769 for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
770 if (!is_bgp_vrf_mplsvpn(bgp))
771 continue;
772 if (strnlen(vrf_name, VRF_NAMSIZ) == 0 && bgp_next == NULL) {
773 first = true;
774 bgp_next = bgp;
775 continue;
776 }
777 if (first || strncmp(bgp->name, vrf_name, VRF_NAMSIZ) > 0) {
778 if (bgp_next == NULL)
779 bgp_next = bgp;
780 else if (strncmp(bgp->name, bgp_next->name, VRF_NAMSIZ)
781 < 0)
782 bgp_next = bgp;
783 }
784 }
785 return bgp_next;
786 }
787
788 /* 1.3.6.1.2.1.10.166.11.1.2.1.1.x = 14*/
789 #define IFCONFTAB_NAMELEN 14
790 static struct bgp *bgpL3vpnIfConf_lookup(struct variable *v, oid name[],
791 size_t *length, char *vrf_name,
792 ifindex_t *ifindex, int exact)
793 {
794 struct bgp *bgp = NULL;
795 size_t namelen = v ? v->namelen : IFCONFTAB_NAMELEN;
796 struct interface *ifp;
797 int vrf_name_len, len;
798
799 /* too long ? */
800 if (*length - namelen > (VRF_NAMSIZ + sizeof(uint32_t)))
801 return NULL;
802 /* do we have index info in the oid ? */
803 if (*length - namelen != 0 && *length - namelen >= sizeof(uint32_t)) {
804 /* copy the info from the oid */
805 vrf_name_len = *length - (namelen + sizeof(ifindex_t));
806 oid2string(name + namelen, vrf_name_len, vrf_name);
807 oid2int(name + namelen + vrf_name_len, ifindex);
808 }
809
810 if (exact) {
811 /* Check the length. */
812 bgp = bgp_lookup_by_name(vrf_name);
813 if (bgp && !is_bgp_vrf_mplsvpn(bgp))
814 return NULL;
815 if (!bgp)
816 return NULL;
817 ifp = if_lookup_by_index(*ifindex, bgp->vrf_id);
818 if (!ifp)
819 return NULL;
820 } else {
821 if (strnlen(vrf_name, VRF_NAMSIZ) == 0)
822 bgp = bgp_lookup_by_name_next(vrf_name);
823 else
824 bgp = bgp_lookup_by_name(vrf_name);
825
826 while (bgp) {
827 ifp = if_vrf_lookup_by_index_next(*ifindex,
828 bgp->vrf_id);
829 if (ifp) {
830 vrf_name_len = strnlen(bgp->name, VRF_NAMSIZ);
831 *ifindex = ifp->ifindex;
832 len = vrf_name_len + sizeof(ifindex_t);
833 oid_copy_str(name + namelen, bgp->name,
834 vrf_name_len);
835 oid_copy_int(name + namelen + vrf_name_len,
836 ifindex);
837 *length = len + namelen;
838
839 return bgp;
840 }
841 *ifindex = 0;
842 bgp = bgp_lookup_by_name_next(bgp->name);
843 }
844
845 return NULL;
846 }
847 return bgp;
848 }
849
850 static uint8_t *mplsL3vpnIfConfTable(struct variable *v, oid name[],
851 size_t *length, int exact, size_t *var_len,
852 WriteMethod **write_method)
853 {
854 char vrf_name[VRF_NAMSIZ];
855 ifindex_t ifindex = 0;
856 struct bgp *l3vpn_bgp;
857
858 if (smux_header_table(v, name, length, exact, var_len, write_method)
859 == MATCH_FAILED)
860 return NULL;
861
862 memset(vrf_name, 0, VRF_NAMSIZ);
863 l3vpn_bgp = bgpL3vpnIfConf_lookup(v, name, length, vrf_name, &ifindex,
864 exact);
865 if (!l3vpn_bgp)
866 return NULL;
867
868 switch (v->magic) {
869 case MPLSL3VPNIFVPNCLASSIFICATION:
870 return SNMP_INTEGER(2);
871 case MPLSL3VPNIFCONFSTORAGETYPE:
872 return SNMP_INTEGER(2);
873 case MPLSL3VPNIFCONFROWSTATUS:
874 return SNMP_INTEGER(1);
875 }
876 return NULL;
877 }
878
879 /* 1.3.6.1.2.1.10.166.11.1.2.2.1.x = 14*/
880 #define VRFTAB_NAMELEN 14
881
882 static struct bgp *bgpL3vpnVrf_lookup(struct variable *v, oid name[],
883 size_t *length, char *vrf_name, int exact)
884 {
885 struct bgp *bgp = NULL;
886 size_t namelen = v ? v->namelen : VRFTAB_NAMELEN;
887 int len;
888
889 if (*length - namelen > VRF_NAMSIZ)
890 return NULL;
891 oid2string(name + namelen, *length - namelen, vrf_name);
892 if (exact) {
893 /* Check the length. */
894 bgp = bgp_lookup_by_name(vrf_name);
895 if (bgp && !is_bgp_vrf_mplsvpn(bgp))
896 return NULL;
897 } else {
898 bgp = bgp_lookup_by_name_next(vrf_name);
899
900 if (bgp == NULL)
901 return NULL;
902
903 len = strnlen(bgp->name, VRF_NAMSIZ);
904 oid_copy_str(name + namelen, bgp->name, len);
905 *length = len + namelen;
906 }
907 return bgp;
908 }
909
910 static uint8_t *mplsL3vpnVrfTable(struct variable *v, oid name[],
911 size_t *length, int exact, size_t *var_len,
912 WriteMethod **write_method)
913 {
914 char vrf_name[VRF_NAMSIZ];
915 struct bgp *l3vpn_bgp;
916
917 if (smux_header_table(v, name, length, exact, var_len, write_method)
918 == MATCH_FAILED)
919 return NULL;
920
921 memset(vrf_name, 0, VRF_NAMSIZ);
922 l3vpn_bgp = bgpL3vpnVrf_lookup(v, name, length, vrf_name, exact);
923
924 if (!l3vpn_bgp)
925 return NULL;
926
927 switch (v->magic) {
928 case MPLSL3VPNVRFVPNID:
929 *var_len = 0;
930 return NULL;
931 case MPLSL3VPNVRFDESC:
932 *var_len = strnlen(l3vpn_bgp->name, VRF_NAMSIZ);
933 return (uint8_t *)l3vpn_bgp->name;
934 case MPLSL3VPNVRFRD:
935 /*
936 * this is a horror show but the MIB dicates one RD per vrf
937 * and not one RD per AFI as we (FRR) have. So this little gem
938 * returns the V4 one if it's set OR the v6 one if it's set or
939 * zero-length string id neither are set
940 */
941 memset(rd_buf, 0, RD_ADDRSTRLEN);
942 if (CHECK_FLAG(l3vpn_bgp->vpn_policy[AFI_IP].flags,
943 BGP_VPN_POLICY_TOVPN_RD_SET))
944 prefix_rd2str(&l3vpn_bgp->vpn_policy[AFI_IP].tovpn_rd,
945 rd_buf, sizeof(rd_buf),
946 bgp_get_asnotation(l3vpn_bgp));
947 else if (CHECK_FLAG(l3vpn_bgp->vpn_policy[AFI_IP6].flags,
948 BGP_VPN_POLICY_TOVPN_RD_SET))
949 prefix_rd2str(&l3vpn_bgp->vpn_policy[AFI_IP6].tovpn_rd,
950 rd_buf, sizeof(rd_buf),
951 bgp_get_asnotation(l3vpn_bgp));
952
953 *var_len = strnlen(rd_buf, RD_ADDRSTRLEN);
954 return (uint8_t *)rd_buf;
955 case MPLSL3VPNVRFCREATIONTIME:
956 return SNMP_INTEGER(
957 (uint32_t)l3vpn_bgp->snmp_stats->creation_time);
958 case MPLSL3VPNVRFOPERSTATUS:
959 if (l3vpn_bgp->snmp_stats->active)
960 return SNMP_INTEGER(1);
961 else
962 return SNMP_INTEGER(2);
963 case MPLSL3VPNVRFACTIVEINTERFACES:
964 return SNMP_INTEGER(bgp_vrf_interfaces(l3vpn_bgp, true));
965 case MPLSL3VPNVRFASSOCIATEDINTERFACES:
966 return SNMP_INTEGER(bgp_vrf_interfaces(l3vpn_bgp, false));
967 case MPLSL3VPNVRFCONFMIDRTETHRESH:
968 return SNMP_INTEGER(0);
969 case MPLSL3VPNVRFCONFHIGHRTETHRSH:
970 return SNMP_INTEGER(0);
971 case MPLSL3VPNVRFCONFMAXROUTES:
972 return SNMP_INTEGER(0);
973 case MPLSL3VPNVRFCONFLASTCHANGED:
974 return SNMP_INTEGER(
975 (uint32_t)l3vpn_bgp->snmp_stats->modify_time);
976 case MPLSL3VPNVRFCONFROWSTATUS:
977 return SNMP_INTEGER(1);
978 case MPLSL3VPNVRFCONFADMINSTATUS:
979 return SNMP_INTEGER(1);
980 case MPLSL3VPNVRFCONFSTORAGETYPE:
981 return SNMP_INTEGER(2);
982 }
983 return NULL;
984 }
985
986 /* 1.3.6.1.2.1.10.166.11.1.2.3.1.x = 14*/
987 #define VRFRTTAB_NAMELEN 14
988 static struct bgp *bgpL3vpnVrfRt_lookup(struct variable *v, oid name[],
989 size_t *length, char *vrf_name,
990 uint32_t *rt_index, uint8_t *rt_type,
991 int exact)
992 {
993 uint32_t type_index_size;
994 struct bgp *l3vpn_bgp;
995 size_t namelen = v ? v->namelen : VRFRTTAB_NAMELEN;
996 int vrf_name_len, len;
997
998 /* too long ? */
999 if (*length - namelen
1000 > (VRF_NAMSIZ + sizeof(uint32_t)) + sizeof(uint8_t))
1001 return NULL;
1002
1003 type_index_size = sizeof(uint32_t) + sizeof(uint8_t);
1004 /* do we have index info in the oid ? */
1005 if (*length - namelen != 0 && *length - namelen >= type_index_size) {
1006 /* copy the info from the oid */
1007 vrf_name_len = *length - (namelen + type_index_size);
1008 oid2string(name + namelen, vrf_name_len, vrf_name);
1009 oid2int(name + namelen + vrf_name_len, (int *)rt_index);
1010 *rt_type = name[namelen + vrf_name_len + sizeof(uint32_t)];
1011 }
1012
1013 /* validate the RT index is in range */
1014 if (*rt_index > AFI_IP6)
1015 return NULL;
1016
1017 if (exact) {
1018 l3vpn_bgp = bgp_lookup_by_name(vrf_name);
1019 if (l3vpn_bgp && !is_bgp_vrf_mplsvpn(l3vpn_bgp))
1020 return NULL;
1021 if (!l3vpn_bgp)
1022 return NULL;
1023 if ((*rt_index != AFI_IP) && (*rt_index != AFI_IP6))
1024 return NULL;
1025 /* do we have RT config */
1026 if (!(l3vpn_bgp->vpn_policy[*rt_index]
1027 .rtlist[BGP_VPN_POLICY_DIR_FROMVPN]
1028 || l3vpn_bgp->vpn_policy[*rt_index]
1029 .rtlist[BGP_VPN_POLICY_DIR_TOVPN]))
1030 return NULL;
1031 return l3vpn_bgp;
1032 }
1033 if (strnlen(vrf_name, VRF_NAMSIZ) == 0)
1034 l3vpn_bgp = bgp_lookup_by_name_next(vrf_name);
1035 else
1036 l3vpn_bgp = bgp_lookup_by_name(vrf_name);
1037 while (l3vpn_bgp) {
1038 switch (*rt_index) {
1039 case 0:
1040 *rt_index = AFI_IP;
1041 break;
1042 case AFI_IP:
1043 *rt_index = AFI_IP6;
1044 break;
1045 case AFI_IP6:
1046 *rt_index = 0;
1047 continue;
1048 }
1049 if (*rt_index) {
1050 switch (*rt_type) {
1051 case 0:
1052 *rt_type = MPLSVPNVRFRTTYPEIMPORT;
1053 break;
1054 case MPLSVPNVRFRTTYPEIMPORT:
1055 *rt_type = MPLSVPNVRFRTTYPEEXPORT;
1056 break;
1057 case MPLSVPNVRFRTTYPEEXPORT:
1058 case MPLSVPNVRFRTTYPEBOTH:
1059 *rt_type = 0;
1060 break;
1061 }
1062 if (*rt_type) {
1063 bool import, export;
1064
1065 import =
1066 (!!l3vpn_bgp->vpn_policy[*rt_index].rtlist
1067 [BGP_VPN_POLICY_DIR_FROMVPN]);
1068 export =
1069 (!!l3vpn_bgp->vpn_policy[*rt_index].rtlist
1070 [BGP_VPN_POLICY_DIR_TOVPN]);
1071 if (*rt_type == MPLSVPNVRFRTTYPEIMPORT
1072 && !import)
1073 continue;
1074 if (*rt_type == MPLSVPNVRFRTTYPEEXPORT
1075 && !export)
1076 continue;
1077 /* ckeck for both */
1078 if (*rt_type == MPLSVPNVRFRTTYPEIMPORT && import
1079 && export
1080 && ecommunity_cmp(
1081 l3vpn_bgp->vpn_policy[*rt_index].rtlist
1082 [BGP_VPN_POLICY_DIR_FROMVPN],
1083 l3vpn_bgp->vpn_policy[*rt_index].rtlist
1084 [BGP_VPN_POLICY_DIR_TOVPN]))
1085 *rt_type = MPLSVPNVRFRTTYPEBOTH;
1086
1087 /* we have a match copy the oid info */
1088 vrf_name_len =
1089 strnlen(l3vpn_bgp->name, VRF_NAMSIZ);
1090 len = vrf_name_len + sizeof(uint32_t)
1091 + sizeof(uint8_t);
1092 oid_copy_str(name + namelen, l3vpn_bgp->name,
1093 vrf_name_len);
1094 oid_copy_int(name + namelen + vrf_name_len,
1095 (int *)rt_index);
1096 name[(namelen + len) - 1] = *rt_type;
1097 *length = len + namelen;
1098 return l3vpn_bgp;
1099 }
1100 l3vpn_bgp = bgp_lookup_by_name_next(l3vpn_bgp->name);
1101 }
1102 }
1103 return NULL;
1104 }
1105
1106 static const char *rt_type2str(uint8_t rt_type)
1107 {
1108 switch (rt_type) {
1109 case MPLSVPNVRFRTTYPEIMPORT:
1110 return "import";
1111 case MPLSVPNVRFRTTYPEEXPORT:
1112 return "export";
1113 case MPLSVPNVRFRTTYPEBOTH:
1114 return "both";
1115 default:
1116 return "unknown";
1117 }
1118 }
1119 static uint8_t *mplsL3vpnVrfRtTable(struct variable *v, oid name[],
1120 size_t *length, int exact, size_t *var_len,
1121 WriteMethod **write_method)
1122 {
1123 char vrf_name[VRF_NAMSIZ];
1124 struct bgp *l3vpn_bgp;
1125 uint32_t rt_index = 0;
1126 uint8_t rt_type = 0;
1127 char *rt_b = NULL;
1128 static char rt_b_str[BUFSIZ] = {};
1129
1130 if (smux_header_table(v, name, length, exact, var_len, write_method)
1131 == MATCH_FAILED)
1132 return NULL;
1133
1134 memset(vrf_name, 0, VRF_NAMSIZ);
1135 l3vpn_bgp = bgpL3vpnVrfRt_lookup(v, name, length, vrf_name, &rt_index,
1136 &rt_type, exact);
1137
1138 if (!l3vpn_bgp)
1139 return NULL;
1140
1141 switch (v->magic) {
1142 case MPLSL3VPNVRFRT:
1143 switch (rt_type) {
1144 case MPLSVPNVRFRTTYPEIMPORT:
1145 rt_b = ecommunity_ecom2str(
1146 l3vpn_bgp->vpn_policy[rt_index]
1147 .rtlist[BGP_VPN_POLICY_DIR_FROMVPN],
1148 ECOMMUNITY_FORMAT_ROUTE_MAP,
1149 ECOMMUNITY_ROUTE_TARGET);
1150 break;
1151 case MPLSVPNVRFRTTYPEEXPORT:
1152 case MPLSVPNVRFRTTYPEBOTH:
1153 rt_b = ecommunity_ecom2str(
1154 l3vpn_bgp->vpn_policy[rt_index]
1155 .rtlist[BGP_VPN_POLICY_DIR_TOVPN],
1156 ECOMMUNITY_FORMAT_ROUTE_MAP,
1157 ECOMMUNITY_ROUTE_TARGET);
1158 break;
1159 default:
1160 break;
1161 }
1162 if (rt_b) {
1163 *var_len = strnlen(rt_b, ECOMMUNITY_STRLEN);
1164 strlcpy(rt_b_str, rt_b, sizeof(rt_b_str));
1165 XFREE(MTYPE_ECOMMUNITY_STR, rt_b);
1166 } else {
1167 *var_len = 0;
1168 }
1169 return (uint8_t *)rt_b_str;
1170 case MPLSL3VPNVRFRTDESCR:
1171 /* since we dont have a description generate one */
1172 memset(rt_description, 0, VRF_NAMSIZ + RT_PREAMBLE_SIZE);
1173 snprintf(rt_description, VRF_NAMSIZ + RT_PREAMBLE_SIZE,
1174 "RT %s for VRF %s", rt_type2str(rt_type),
1175 l3vpn_bgp->name);
1176 *var_len =
1177 strnlen(rt_description, VRF_NAMSIZ + RT_PREAMBLE_SIZE);
1178 return (uint8_t *)rt_description;
1179 case MPLSL3VPNVRFRTROWSTATUS:
1180 return SNMP_INTEGER(1);
1181 case MPLSL3VPNVRFRTSTORAGETYPE:
1182 return SNMP_INTEGER(2);
1183 }
1184 return NULL;
1185 }
1186
1187 /* 1.3.6.1.2.1.10.166.11.1.3.1.1.x = 14*/
1188 #define PERFTAB_NAMELEN 14
1189
1190 static uint8_t *mplsL3vpnPerfTable(struct variable *v, oid name[],
1191 size_t *length, int exact, size_t *var_len,
1192 WriteMethod **write_method)
1193 {
1194 char vrf_name[VRF_NAMSIZ];
1195 struct bgp *l3vpn_bgp;
1196
1197 if (smux_header_table(v, name, length, exact, var_len, write_method)
1198 == MATCH_FAILED)
1199 return NULL;
1200
1201 memset(vrf_name, 0, VRF_NAMSIZ);
1202 l3vpn_bgp = bgpL3vpnVrf_lookup(v, name, length, vrf_name, exact);
1203
1204 if (!l3vpn_bgp)
1205 return NULL;
1206
1207 switch (v->magic) {
1208 case MPLSL3VPNVRFPERFROUTESADDED:
1209 return SNMP_INTEGER(l3vpn_bgp->snmp_stats->routes_added);
1210 case MPLSL3VPNVRFPERFROUTESDELETED:
1211 return SNMP_INTEGER(l3vpn_bgp->snmp_stats->routes_deleted);
1212 case MPLSL3VPNVRFPERFCURRNUMROUTES:
1213 return SNMP_INTEGER(bgp_mpls_l3vpn_current_routes(l3vpn_bgp));
1214 }
1215 return NULL;
1216 }
1217
1218 static struct bgp_path_info *
1219 bgp_lookup_route(struct bgp *l3vpn_bgp, struct bgp_dest **dest,
1220 struct prefix *prefix, uint16_t policy, struct ipaddr *nexthop)
1221 {
1222 struct bgp_path_info *pi = NULL;
1223 struct bgp_table *table;
1224
1225 switch (prefix->family) {
1226 case AF_INET:
1227 table = l3vpn_bgp->rib[AFI_IP][SAFI_UNICAST];
1228 break;
1229 case AF_INET6:
1230 table = l3vpn_bgp->rib[AFI_IP6][SAFI_UNICAST];
1231 break;
1232 default:
1233 return NULL;
1234 }
1235
1236 /*get the prefix */
1237 *dest = bgp_node_lookup(table, prefix);
1238 if (*dest == NULL)
1239 return NULL;
1240
1241 /* now find the right path */
1242 pi = bgp_dest_get_bgp_path_info(*dest);
1243 for (; pi; pi = pi->next) {
1244 switch (nexthop->ipa_type) {
1245 case IPADDR_V4:
1246 if (nexthop->ip._v4_addr.s_addr
1247 == pi->attr->nexthop.s_addr)
1248 return pi;
1249 break;
1250 case IPADDR_V6:
1251 if (memcmp(&nexthop->ip._v6_addr,
1252 &pi->attr->mp_nexthop_global,
1253 sizeof(struct in6_addr))
1254 == 0)
1255 return pi;
1256 break;
1257 case IPADDR_NONE:
1258 return pi;
1259 }
1260 }
1261 return NULL;
1262 }
1263
1264 static struct bgp_path_info *bgp_lookup_route_next(struct bgp **l3vpn_bgp,
1265 struct bgp_dest **dest,
1266 struct prefix *prefix,
1267 uint16_t *policy,
1268 struct ipaddr *nexthop)
1269 {
1270 struct bgp_path_info *pi = NULL;
1271 struct bgp_table *table;
1272 const struct prefix *p;
1273 uint8_t family;
1274
1275 /* First route?*/
1276 if (prefix->prefixlen == 0) {
1277 /* try V4 table */
1278 table = (*l3vpn_bgp)->rib[AFI_IP][SAFI_UNICAST];
1279 for (*dest = bgp_table_top(table); *dest;
1280 *dest = bgp_route_next(*dest)) {
1281 pi = bgp_dest_get_bgp_path_info(*dest);
1282 if (pi)
1283 break;
1284 }
1285
1286 if (!pi) {
1287 /* try V6 table */
1288 table = (*l3vpn_bgp)->rib[AFI_IP6][SAFI_UNICAST];
1289 for (*dest = bgp_table_top(table); *dest;
1290 *dest = bgp_route_next(*dest)) {
1291 pi = bgp_dest_get_bgp_path_info(*dest);
1292 if (pi)
1293 break;
1294 }
1295 }
1296 return pi;
1297 }
1298 /* real next search for the entry first use exact lookup */
1299 pi = bgp_lookup_route(*l3vpn_bgp, dest, prefix, *policy, nexthop);
1300
1301 if (pi == NULL)
1302 return NULL;
1303
1304 p = bgp_dest_get_prefix(*dest);
1305 family = p->family;
1306
1307 /* We have found the input path let's find the next one in the list */
1308 if (pi->next) {
1309 /* ensure OID is always higher for multipath routes by
1310 * incrementing opaque policy oid
1311 */
1312 *policy += 1;
1313 return pi->next;
1314 }
1315
1316 /* No more paths in the input route so find the next route */
1317 for (; *l3vpn_bgp;
1318 *l3vpn_bgp = bgp_lookup_by_name_next((*l3vpn_bgp)->name)) {
1319 *policy = 0;
1320 if (!*dest) {
1321 table = (*l3vpn_bgp)->rib[AFI_IP][SAFI_UNICAST];
1322 *dest = bgp_table_top(table);
1323 family = AF_INET;
1324 } else
1325 *dest = bgp_route_next(*dest);
1326
1327 while (true) {
1328 for (; *dest; *dest = bgp_route_next(*dest)) {
1329 pi = bgp_dest_get_bgp_path_info(*dest);
1330
1331 if (pi)
1332 return pi;
1333 }
1334 if (family == AF_INET) {
1335 table = (*l3vpn_bgp)
1336 ->rib[AFI_IP6][SAFI_UNICAST];
1337 *dest = bgp_table_top(table);
1338 family = AF_INET6;
1339 continue;
1340 }
1341 break;
1342 }
1343 }
1344
1345 return NULL;
1346 }
1347
1348 static bool is_addr_type(oid id)
1349 {
1350 switch (id) {
1351 case INETADDRESSTYPEUNKNOWN:
1352 case INETADDRESSTYPEIPV4:
1353 case INETADDRESSTYPEIPV6:
1354 return true;
1355 }
1356 return false;
1357 }
1358
1359 /* 1.3.6.1.2.1.10.166.11.1.4.1.1.x = 14*/
1360 #define PERFTAB_NAMELEN 14
1361
1362 static struct bgp_path_info *bgpL3vpnRte_lookup(struct variable *v, oid name[],
1363 size_t *length, char *vrf_name,
1364 struct bgp **l3vpn_bgp,
1365 struct bgp_dest **dest,
1366 uint16_t *policy, int exact)
1367 {
1368 uint8_t i;
1369 uint8_t vrf_name_len = 0;
1370 struct bgp_path_info *pi = NULL;
1371 size_t namelen = v ? v->namelen : IFCONFTAB_NAMELEN;
1372 struct prefix prefix = {0};
1373 struct ipaddr nexthop = {0};
1374 uint8_t prefix_type;
1375 uint8_t nexthop_type;
1376
1377 if ((uint32_t)(*length - namelen) > (VRF_NAMSIZ + 37))
1378 return NULL;
1379
1380 if (*length - namelen != 0) {
1381 /* parse incoming OID */
1382 for (i = namelen; i < (*length); i++) {
1383 if (is_addr_type(name[i]))
1384 break;
1385 vrf_name_len++;
1386 }
1387 if (vrf_name_len > VRF_NAMSIZ)
1388 return NULL;
1389
1390 oid2string(name + namelen, vrf_name_len, vrf_name);
1391 prefix_type = name[i++];
1392 switch (prefix_type) {
1393 case INETADDRESSTYPEUNKNOWN:
1394 prefix.family = AF_UNSPEC;
1395 break;
1396 case INETADDRESSTYPEIPV4:
1397 prefix.family = AF_INET;
1398 oid2in_addr(&name[i], sizeof(struct in_addr),
1399 &prefix.u.prefix4);
1400 i += sizeof(struct in_addr);
1401 break;
1402 case INETADDRESSTYPEIPV6:
1403 prefix.family = AF_INET6;
1404 oid2in6_addr(&name[i], &prefix.u.prefix6);
1405 i += sizeof(struct in6_addr);
1406 break;
1407 }
1408 prefix.prefixlen = (uint8_t)name[i++];
1409 *policy |= name[i++] << 8;
1410 *policy |= name[i++];
1411 nexthop_type = name[i++];
1412 switch (nexthop_type) {
1413 case INETADDRESSTYPEUNKNOWN:
1414 nexthop.ipa_type = (prefix.family == AF_INET)
1415 ? IPADDR_V4
1416 : IPADDR_V6;
1417 break;
1418 case INETADDRESSTYPEIPV4:
1419 nexthop.ipa_type = IPADDR_V4;
1420 oid2in_addr(&name[i], sizeof(struct in_addr),
1421 &nexthop.ip._v4_addr);
1422 /* i += sizeof(struct in_addr); */
1423 break;
1424 case INETADDRESSTYPEIPV6:
1425 nexthop.ipa_type = IPADDR_V6;
1426 oid2in6_addr(&name[i], &nexthop.ip._v6_addr);
1427 /* i += sizeof(struct in6_addr); */
1428 break;
1429 }
1430 }
1431
1432 if (exact) {
1433 *l3vpn_bgp = bgp_lookup_by_name(vrf_name);
1434 if (*l3vpn_bgp && !is_bgp_vrf_mplsvpn(*l3vpn_bgp))
1435 return NULL;
1436 if (*l3vpn_bgp == NULL)
1437 return NULL;
1438
1439 /* now lookup the route in this bgp table */
1440 pi = bgp_lookup_route(*l3vpn_bgp, dest, &prefix, *policy,
1441 &nexthop);
1442 } else {
1443 int str_len;
1444
1445 str_len = strnlen(vrf_name, VRF_NAMSIZ);
1446 if (str_len == 0) {
1447 *l3vpn_bgp = bgp_lookup_by_name_next(vrf_name);
1448 } else
1449 /* otherwise lookup the one we have */
1450 *l3vpn_bgp = bgp_lookup_by_name(vrf_name);
1451
1452 if (*l3vpn_bgp == NULL)
1453 return NULL;
1454
1455 pi = bgp_lookup_route_next(l3vpn_bgp, dest, &prefix, policy,
1456 &nexthop);
1457 if (pi) {
1458 uint8_t vrf_name_len =
1459 strnlen((*l3vpn_bgp)->name, VRF_NAMSIZ);
1460 const struct prefix *p = bgp_dest_get_prefix(*dest);
1461 uint8_t oid_index;
1462 bool v4 = (p->family == AF_INET);
1463 uint8_t addr_len = v4 ? sizeof(struct in_addr)
1464 : sizeof(struct in6_addr);
1465 struct attr *attr = pi->attr;
1466
1467 /* copy the index parameters */
1468 oid_copy_str(&name[namelen], (*l3vpn_bgp)->name,
1469 vrf_name_len);
1470 oid_index = namelen + vrf_name_len;
1471 if (v4) {
1472 name[oid_index++] = INETADDRESSTYPEIPV4;
1473 oid_copy_in_addr(&name[oid_index],
1474 &p->u.prefix4);
1475 } else {
1476 name[oid_index++] = INETADDRESSTYPEIPV6;
1477 oid_copy_in6_addr(&name[oid_index],
1478 &p->u.prefix6);
1479 }
1480
1481 oid_index += addr_len;
1482 name[oid_index++] = p->prefixlen;
1483 name[oid_index++] = *policy >> 8;
1484 name[oid_index++] = *policy & 0xff;
1485
1486 if (!BGP_ATTR_NEXTHOP_AFI_IP6(attr)) {
1487 if (attr->nexthop.s_addr == INADDR_ANY)
1488 name[oid_index++] =
1489 INETADDRESSTYPEUNKNOWN;
1490 else {
1491 name[oid_index++] = INETADDRESSTYPEIPV4;
1492 oid_copy_in_addr(&name[oid_index],
1493 &attr->nexthop);
1494 oid_index += sizeof(struct in_addr);
1495 }
1496 } else {
1497 if (IN6_IS_ADDR_UNSPECIFIED(
1498 &attr->mp_nexthop_global))
1499 name[oid_index++] =
1500 INETADDRESSTYPEUNKNOWN;
1501 else {
1502 name[oid_index++] = INETADDRESSTYPEIPV6;
1503 oid_copy_in6_addr(
1504 &name[oid_index],
1505 &attr->mp_nexthop_global);
1506 oid_index += sizeof(struct in6_addr);
1507 }
1508 }
1509 *length = oid_index;
1510 }
1511 }
1512 return pi;
1513 }
1514
1515 static uint8_t *mplsL3vpnRteTable(struct variable *v, oid name[],
1516 size_t *length, int exact, size_t *var_len,
1517 WriteMethod **write_method)
1518 {
1519 char vrf_name[VRF_NAMSIZ];
1520 struct bgp *l3vpn_bgp;
1521 struct bgp_dest *dest;
1522 struct bgp_path_info *pi, *bpi_ultimate;
1523 const struct prefix *p;
1524 uint16_t policy = 0;
1525
1526 if (smux_header_table(v, name, length, exact, var_len, write_method)
1527 == MATCH_FAILED)
1528 return NULL;
1529
1530 memset(vrf_name, 0, VRF_NAMSIZ);
1531 pi = bgpL3vpnRte_lookup(v, name, length, vrf_name, &l3vpn_bgp, &dest,
1532 &policy, exact);
1533
1534
1535 if (!pi)
1536 return NULL;
1537
1538 bpi_ultimate = bgp_get_imported_bpi_ultimate(pi);
1539
1540 p = bgp_dest_get_prefix(dest);
1541
1542 if (!p)
1543 return NULL;
1544
1545 switch (v->magic) {
1546 case MPLSL3VPNVRFRTEINETCIDRDESTTYPE:
1547 switch (p->family) {
1548 case AF_INET:
1549 return SNMP_INTEGER(INETADDRESSTYPEIPV4);
1550 case AF_INET6:
1551 return SNMP_INTEGER(INETADDRESSTYPEIPV6);
1552 default:
1553 return SNMP_INTEGER(INETADDRESSTYPEUNKNOWN);
1554 }
1555 case MPLSL3VPNVRFRTEINETCIDRDEST:
1556 switch (p->family) {
1557 case AF_INET:
1558 return SNMP_IPADDRESS(p->u.prefix4);
1559 case AF_INET6:
1560 return SNMP_IP6ADDRESS(p->u.prefix6);
1561 default:
1562 *var_len = 0;
1563 return NULL;
1564 }
1565 case MPLSL3VPNVRFRTEINETCIDRPFXLEN:
1566 return SNMP_INTEGER(p->prefixlen);
1567 case MPLSL3VPNVRFRTEINETCIDRPOLICY:
1568 *var_len = sizeof(mpls_l3vpn_policy_oid);
1569 mpls_l3vpn_policy_oid[0] = policy >> 8;
1570 mpls_l3vpn_policy_oid[1] = policy & 0xff;
1571 return (uint8_t *)mpls_l3vpn_policy_oid;
1572 case MPLSL3VPNVRFRTEINETCIDRNHOPTYPE:
1573 if (!BGP_ATTR_NEXTHOP_AFI_IP6(pi->attr)) {
1574 if (pi->attr->nexthop.s_addr == INADDR_ANY)
1575 return SNMP_INTEGER(INETADDRESSTYPEUNKNOWN);
1576 else
1577 return SNMP_INTEGER(INETADDRESSTYPEIPV4);
1578 } else if (IN6_IS_ADDR_UNSPECIFIED(
1579 &pi->attr->mp_nexthop_global))
1580 return SNMP_INTEGER(INETADDRESSTYPEUNKNOWN);
1581 else
1582 return SNMP_INTEGER(INETADDRESSTYPEIPV6);
1583
1584 case MPLSL3VPNVRFRTEINETCIDRNEXTHOP:
1585 if (!BGP_ATTR_NEXTHOP_AFI_IP6(pi->attr))
1586 if (pi->attr->nexthop.s_addr == INADDR_ANY) {
1587 *var_len = 0;
1588 return (uint8_t *)empty_nhop;
1589 } else
1590 return SNMP_IPADDRESS(pi->attr->nexthop);
1591 else if (IN6_IS_ADDR_UNSPECIFIED(
1592 &pi->attr->mp_nexthop_global)) {
1593 *var_len = 0;
1594 return (uint8_t *)empty_nhop;
1595 } else
1596 return SNMP_IP6ADDRESS(pi->attr->mp_nexthop_global);
1597
1598 case MPLSL3VPNVRFRTEINETCIDRIFINDEX:
1599 if (pi->nexthop && pi->nexthop->nexthop)
1600 return SNMP_INTEGER(pi->nexthop->nexthop->ifindex);
1601 else
1602 return SNMP_INTEGER(0);
1603 case MPLSL3VPNVRFRTEINETCIDRTYPE:
1604 if (pi->nexthop && pi->nexthop->nexthop) {
1605 switch (pi->nexthop->nexthop->type) {
1606 case NEXTHOP_TYPE_IFINDEX:
1607 return SNMP_INTEGER(
1608 MPLSL3VPNVRFRTECIDRTYPELOCAL);
1609 case NEXTHOP_TYPE_IPV4:
1610 case NEXTHOP_TYPE_IPV4_IFINDEX:
1611 case NEXTHOP_TYPE_IPV6:
1612 case NEXTHOP_TYPE_IPV6_IFINDEX:
1613 return SNMP_INTEGER(
1614 MPLSL3VPNVRFRTECIDRTYPEREMOTE);
1615 case NEXTHOP_TYPE_BLACKHOLE:
1616 switch (pi->nexthop->nexthop->bh_type) {
1617 case BLACKHOLE_REJECT:
1618 return SNMP_INTEGER(
1619 MPLSL3VPNVRFRTECIDRTYPEREJECT);
1620 case BLACKHOLE_UNSPEC:
1621 case BLACKHOLE_NULL:
1622 case BLACKHOLE_ADMINPROHIB:
1623 return SNMP_INTEGER(
1624 MPLSL3VPNVRFRTECIDRTYPEBLACKHOLE);
1625 }
1626 break;
1627 }
1628 } else
1629 return SNMP_INTEGER(MPLSL3VPNVRFRTECIDRTYPEOTHER);
1630 case MPLSL3VPNVRFRTEINETCIDRPROTO:
1631 switch (pi->type) {
1632 case ZEBRA_ROUTE_CONNECT:
1633 return SNMP_INTEGER(IANAIPROUTEPROTOCOLLOCAL);
1634 case ZEBRA_ROUTE_STATIC:
1635 return SNMP_INTEGER(IANAIPROUTEPROTOCOLNETMGMT);
1636 case ZEBRA_ROUTE_RIP:
1637 case ZEBRA_ROUTE_RIPNG:
1638 return SNMP_INTEGER(IANAIPROUTEPROTOCOLRIP);
1639 case ZEBRA_ROUTE_OSPF:
1640 case ZEBRA_ROUTE_OSPF6:
1641 return SNMP_INTEGER(IANAIPROUTEPROTOCOLOSPF);
1642 case ZEBRA_ROUTE_ISIS:
1643 return SNMP_INTEGER(IANAIPROUTEPROTOCOLISIS);
1644 case ZEBRA_ROUTE_BGP:
1645 return SNMP_INTEGER(IANAIPROUTEPROTOCOLBGP);
1646 case ZEBRA_ROUTE_EIGRP:
1647 return SNMP_INTEGER(IANAIPROUTEPROTOCOLCISCOEIGRP);
1648 default:
1649 return SNMP_INTEGER(IANAIPROUTEPROTOCOLOTHER);
1650 }
1651 case MPLSL3VPNVRFRTEINETCIDRAGE:
1652 return SNMP_INTEGER(pi->uptime);
1653 case MPLSL3VPNVRFRTEINETCIDRNEXTHOPAS:
1654 return SNMP_INTEGER(pi->peer ? pi->peer->as : 0);
1655 case MPLSL3VPNVRFRTEINETCIDRMETRIC1:
1656 if (bpi_ultimate->extra)
1657 return SNMP_INTEGER(bpi_ultimate->extra->igpmetric);
1658 else
1659 return SNMP_INTEGER(0);
1660 case MPLSL3VPNVRFRTEINETCIDRMETRIC2:
1661 return SNMP_INTEGER(-1);
1662 case MPLSL3VPNVRFRTEINETCIDRMETRIC3:
1663 return SNMP_INTEGER(-1);
1664 case MPLSL3VPNVRFRTEINETCIDRMETRIC4:
1665 return SNMP_INTEGER(-1);
1666 case MPLSL3VPNVRFRTEINETCIDRMETRIC5:
1667 return SNMP_INTEGER(-1);
1668 case MPLSL3VPNVRFRTEINETCIDRXCPOINTER:
1669 return SNMP_OCTET(0);
1670 case MPLSL3VPNVRFRTEINETCIDRSTATUS:
1671 return SNMP_INTEGER(1);
1672 }
1673 return NULL;
1674 }
1675
1676 void bgp_mpls_l3vpn_module_init(void)
1677 {
1678 hook_register(bgp_vrf_status_changed, bgp_vrf_check_update_active);
1679 hook_register(bgp_snmp_init_stats, bgp_init_snmp_stats);
1680 hook_register(bgp_snmp_update_last_changed,
1681 bgp_mpls_l3vpn_update_last_changed);
1682 hook_register(bgp_snmp_update_stats, bgp_snmp_update_route_stats);
1683 REGISTER_MIB("mplsL3VpnMIB", mpls_l3vpn_variables, variable,
1684 mpls_l3vpn_oid);
1685 }