]> git.proxmox.com Git - mirror_frr.git/blob - bgpd/bgp_mplsvpn_snmp.c
*: auto-convert to SPDX License IDs
[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 "thread.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 else if (CHECK_FLAG(l3vpn_bgp->vpn_policy[AFI_IP6].flags,
947 BGP_VPN_POLICY_TOVPN_RD_SET))
948 prefix_rd2str(&l3vpn_bgp->vpn_policy[AFI_IP6].tovpn_rd,
949 rd_buf, sizeof(rd_buf));
950
951 *var_len = strnlen(rd_buf, RD_ADDRSTRLEN);
952 return (uint8_t *)rd_buf;
953 case MPLSL3VPNVRFCREATIONTIME:
954 return SNMP_INTEGER(
955 (uint32_t)l3vpn_bgp->snmp_stats->creation_time);
956 case MPLSL3VPNVRFOPERSTATUS:
957 if (l3vpn_bgp->snmp_stats->active)
958 return SNMP_INTEGER(1);
959 else
960 return SNMP_INTEGER(2);
961 case MPLSL3VPNVRFACTIVEINTERFACES:
962 return SNMP_INTEGER(bgp_vrf_interfaces(l3vpn_bgp, true));
963 case MPLSL3VPNVRFASSOCIATEDINTERFACES:
964 return SNMP_INTEGER(bgp_vrf_interfaces(l3vpn_bgp, false));
965 case MPLSL3VPNVRFCONFMIDRTETHRESH:
966 return SNMP_INTEGER(0);
967 case MPLSL3VPNVRFCONFHIGHRTETHRSH:
968 return SNMP_INTEGER(0);
969 case MPLSL3VPNVRFCONFMAXROUTES:
970 return SNMP_INTEGER(0);
971 case MPLSL3VPNVRFCONFLASTCHANGED:
972 return SNMP_INTEGER(
973 (uint32_t)l3vpn_bgp->snmp_stats->modify_time);
974 case MPLSL3VPNVRFCONFROWSTATUS:
975 return SNMP_INTEGER(1);
976 case MPLSL3VPNVRFCONFADMINSTATUS:
977 return SNMP_INTEGER(1);
978 case MPLSL3VPNVRFCONFSTORAGETYPE:
979 return SNMP_INTEGER(2);
980 }
981 return NULL;
982 }
983
984 /* 1.3.6.1.2.1.10.166.11.1.2.3.1.x = 14*/
985 #define VRFRTTAB_NAMELEN 14
986 static struct bgp *bgpL3vpnVrfRt_lookup(struct variable *v, oid name[],
987 size_t *length, char *vrf_name,
988 uint32_t *rt_index, uint8_t *rt_type,
989 int exact)
990 {
991 uint32_t type_index_size;
992 struct bgp *l3vpn_bgp;
993 size_t namelen = v ? v->namelen : VRFRTTAB_NAMELEN;
994 int vrf_name_len, len;
995
996 /* too long ? */
997 if (*length - namelen
998 > (VRF_NAMSIZ + sizeof(uint32_t)) + sizeof(uint8_t))
999 return NULL;
1000
1001 type_index_size = sizeof(uint32_t) + sizeof(uint8_t);
1002 /* do we have index info in the oid ? */
1003 if (*length - namelen != 0 && *length - namelen >= type_index_size) {
1004 /* copy the info from the oid */
1005 vrf_name_len = *length - (namelen + type_index_size);
1006 oid2string(name + namelen, vrf_name_len, vrf_name);
1007 oid2int(name + namelen + vrf_name_len, (int *)rt_index);
1008 *rt_type = name[namelen + vrf_name_len + sizeof(uint32_t)];
1009 }
1010
1011 /* validate the RT index is in range */
1012 if (*rt_index > AFI_IP6)
1013 return NULL;
1014
1015 if (exact) {
1016 l3vpn_bgp = bgp_lookup_by_name(vrf_name);
1017 if (l3vpn_bgp && !is_bgp_vrf_mplsvpn(l3vpn_bgp))
1018 return NULL;
1019 if (!l3vpn_bgp)
1020 return NULL;
1021 if ((*rt_index != AFI_IP) && (*rt_index != AFI_IP6))
1022 return NULL;
1023 /* do we have RT config */
1024 if (!(l3vpn_bgp->vpn_policy[*rt_index]
1025 .rtlist[BGP_VPN_POLICY_DIR_FROMVPN]
1026 || l3vpn_bgp->vpn_policy[*rt_index]
1027 .rtlist[BGP_VPN_POLICY_DIR_TOVPN]))
1028 return NULL;
1029 return l3vpn_bgp;
1030 }
1031 if (strnlen(vrf_name, VRF_NAMSIZ) == 0)
1032 l3vpn_bgp = bgp_lookup_by_name_next(vrf_name);
1033 else
1034 l3vpn_bgp = bgp_lookup_by_name(vrf_name);
1035 while (l3vpn_bgp) {
1036 switch (*rt_index) {
1037 case 0:
1038 *rt_index = AFI_IP;
1039 break;
1040 case AFI_IP:
1041 *rt_index = AFI_IP6;
1042 break;
1043 case AFI_IP6:
1044 *rt_index = 0;
1045 continue;
1046 }
1047 if (*rt_index) {
1048 switch (*rt_type) {
1049 case 0:
1050 *rt_type = MPLSVPNVRFRTTYPEIMPORT;
1051 break;
1052 case MPLSVPNVRFRTTYPEIMPORT:
1053 *rt_type = MPLSVPNVRFRTTYPEEXPORT;
1054 break;
1055 case MPLSVPNVRFRTTYPEEXPORT:
1056 case MPLSVPNVRFRTTYPEBOTH:
1057 *rt_type = 0;
1058 break;
1059 }
1060 if (*rt_type) {
1061 bool import, export;
1062
1063 import =
1064 (!!l3vpn_bgp->vpn_policy[*rt_index].rtlist
1065 [BGP_VPN_POLICY_DIR_FROMVPN]);
1066 export =
1067 (!!l3vpn_bgp->vpn_policy[*rt_index].rtlist
1068 [BGP_VPN_POLICY_DIR_TOVPN]);
1069 if (*rt_type == MPLSVPNVRFRTTYPEIMPORT
1070 && !import)
1071 continue;
1072 if (*rt_type == MPLSVPNVRFRTTYPEEXPORT
1073 && !export)
1074 continue;
1075 /* ckeck for both */
1076 if (*rt_type == MPLSVPNVRFRTTYPEIMPORT && import
1077 && export
1078 && ecommunity_cmp(
1079 l3vpn_bgp->vpn_policy[*rt_index].rtlist
1080 [BGP_VPN_POLICY_DIR_FROMVPN],
1081 l3vpn_bgp->vpn_policy[*rt_index].rtlist
1082 [BGP_VPN_POLICY_DIR_TOVPN]))
1083 *rt_type = MPLSVPNVRFRTTYPEBOTH;
1084
1085 /* we have a match copy the oid info */
1086 vrf_name_len =
1087 strnlen(l3vpn_bgp->name, VRF_NAMSIZ);
1088 len = vrf_name_len + sizeof(uint32_t)
1089 + sizeof(uint8_t);
1090 oid_copy_str(name + namelen, l3vpn_bgp->name,
1091 vrf_name_len);
1092 oid_copy_int(name + namelen + vrf_name_len,
1093 (int *)rt_index);
1094 name[(namelen + len) - 1] = *rt_type;
1095 *length = len + namelen;
1096 return l3vpn_bgp;
1097 }
1098 l3vpn_bgp = bgp_lookup_by_name_next(l3vpn_bgp->name);
1099 }
1100 }
1101 return NULL;
1102 }
1103
1104 static const char *rt_type2str(uint8_t rt_type)
1105 {
1106 switch (rt_type) {
1107 case MPLSVPNVRFRTTYPEIMPORT:
1108 return "import";
1109 case MPLSVPNVRFRTTYPEEXPORT:
1110 return "export";
1111 case MPLSVPNVRFRTTYPEBOTH:
1112 return "both";
1113 default:
1114 return "unknown";
1115 }
1116 }
1117 static uint8_t *mplsL3vpnVrfRtTable(struct variable *v, oid name[],
1118 size_t *length, int exact, size_t *var_len,
1119 WriteMethod **write_method)
1120 {
1121 char vrf_name[VRF_NAMSIZ];
1122 struct bgp *l3vpn_bgp;
1123 uint32_t rt_index = 0;
1124 uint8_t rt_type = 0;
1125 char *rt_b;
1126
1127 if (smux_header_table(v, name, length, exact, var_len, write_method)
1128 == MATCH_FAILED)
1129 return NULL;
1130
1131 memset(vrf_name, 0, VRF_NAMSIZ);
1132 l3vpn_bgp = bgpL3vpnVrfRt_lookup(v, name, length, vrf_name, &rt_index,
1133 &rt_type, exact);
1134
1135 if (!l3vpn_bgp)
1136 return NULL;
1137
1138 switch (v->magic) {
1139 case MPLSL3VPNVRFRT:
1140 switch (rt_type) {
1141 case MPLSVPNVRFRTTYPEIMPORT:
1142 rt_b = ecommunity_ecom2str(
1143 l3vpn_bgp->vpn_policy[rt_index]
1144 .rtlist[BGP_VPN_POLICY_DIR_FROMVPN],
1145 ECOMMUNITY_FORMAT_ROUTE_MAP,
1146 ECOMMUNITY_ROUTE_TARGET);
1147 break;
1148 case MPLSVPNVRFRTTYPEEXPORT:
1149 case MPLSVPNVRFRTTYPEBOTH:
1150 rt_b = ecommunity_ecom2str(
1151 l3vpn_bgp->vpn_policy[rt_index]
1152 .rtlist[BGP_VPN_POLICY_DIR_TOVPN],
1153 ECOMMUNITY_FORMAT_ROUTE_MAP,
1154 ECOMMUNITY_ROUTE_TARGET);
1155 break;
1156 default:
1157 rt_b = NULL;
1158 break;
1159 }
1160 if (rt_b)
1161 *var_len = strnlen(rt_b, ECOMMUNITY_STRLEN);
1162 else
1163 *var_len = 0;
1164 return (uint8_t *)rt_b;
1165 case MPLSL3VPNVRFRTDESCR:
1166 /* since we dont have a description generate one */
1167 memset(rt_description, 0, VRF_NAMSIZ + RT_PREAMBLE_SIZE);
1168 snprintf(rt_description, VRF_NAMSIZ + RT_PREAMBLE_SIZE,
1169 "RT %s for VRF %s", rt_type2str(rt_type),
1170 l3vpn_bgp->name);
1171 *var_len =
1172 strnlen(rt_description, VRF_NAMSIZ + RT_PREAMBLE_SIZE);
1173 return (uint8_t *)rt_description;
1174 case MPLSL3VPNVRFRTROWSTATUS:
1175 return SNMP_INTEGER(1);
1176 case MPLSL3VPNVRFRTSTORAGETYPE:
1177 return SNMP_INTEGER(2);
1178 }
1179 return NULL;
1180 }
1181
1182 /* 1.3.6.1.2.1.10.166.11.1.3.1.1.x = 14*/
1183 #define PERFTAB_NAMELEN 14
1184
1185 static uint8_t *mplsL3vpnPerfTable(struct variable *v, oid name[],
1186 size_t *length, int exact, size_t *var_len,
1187 WriteMethod **write_method)
1188 {
1189 char vrf_name[VRF_NAMSIZ];
1190 struct bgp *l3vpn_bgp;
1191
1192 if (smux_header_table(v, name, length, exact, var_len, write_method)
1193 == MATCH_FAILED)
1194 return NULL;
1195
1196 memset(vrf_name, 0, VRF_NAMSIZ);
1197 l3vpn_bgp = bgpL3vpnVrf_lookup(v, name, length, vrf_name, exact);
1198
1199 if (!l3vpn_bgp)
1200 return NULL;
1201
1202 switch (v->magic) {
1203 case MPLSL3VPNVRFPERFROUTESADDED:
1204 return SNMP_INTEGER(l3vpn_bgp->snmp_stats->routes_added);
1205 case MPLSL3VPNVRFPERFROUTESDELETED:
1206 return SNMP_INTEGER(l3vpn_bgp->snmp_stats->routes_deleted);
1207 case MPLSL3VPNVRFPERFCURRNUMROUTES:
1208 return SNMP_INTEGER(bgp_mpls_l3vpn_current_routes(l3vpn_bgp));
1209 }
1210 return NULL;
1211 }
1212
1213 static struct bgp_path_info *
1214 bgp_lookup_route(struct bgp *l3vpn_bgp, struct bgp_dest **dest,
1215 struct prefix *prefix, uint16_t policy, struct ipaddr *nexthop)
1216 {
1217 struct bgp_path_info *pi = NULL;
1218 struct bgp_table *table;
1219
1220 switch (prefix->family) {
1221 case AF_INET:
1222 table = l3vpn_bgp->rib[AFI_IP][SAFI_UNICAST];
1223 break;
1224 case AF_INET6:
1225 table = l3vpn_bgp->rib[AFI_IP6][SAFI_UNICAST];
1226 break;
1227 default:
1228 return NULL;
1229 }
1230
1231 /*get the prefix */
1232 *dest = bgp_node_lookup(table, prefix);
1233 if (*dest == NULL)
1234 return NULL;
1235
1236 /* now find the right path */
1237 pi = bgp_dest_get_bgp_path_info(*dest);
1238 for (; pi; pi = pi->next) {
1239 switch (nexthop->ipa_type) {
1240 case IPADDR_V4:
1241 if (nexthop->ip._v4_addr.s_addr
1242 == pi->attr->nexthop.s_addr)
1243 return pi;
1244 break;
1245 case IPADDR_V6:
1246 if (memcmp(&nexthop->ip._v6_addr,
1247 &pi->attr->mp_nexthop_global,
1248 sizeof(struct in6_addr))
1249 == 0)
1250 return pi;
1251 break;
1252 case IPADDR_NONE:
1253 return pi;
1254 }
1255 }
1256 return NULL;
1257 }
1258
1259 static struct bgp_path_info *bgp_lookup_route_next(struct bgp **l3vpn_bgp,
1260 struct bgp_dest **dest,
1261 struct prefix *prefix,
1262 uint16_t *policy,
1263 struct ipaddr *nexthop)
1264 {
1265 struct bgp_path_info *pi = NULL;
1266 struct bgp_table *table;
1267 const struct prefix *p;
1268 uint8_t family;
1269
1270 /* First route?*/
1271 if (prefix->prefixlen == 0) {
1272 /* try V4 table */
1273 table = (*l3vpn_bgp)->rib[AFI_IP][SAFI_UNICAST];
1274 for (*dest = bgp_table_top(table); *dest;
1275 *dest = bgp_route_next(*dest)) {
1276 pi = bgp_dest_get_bgp_path_info(*dest);
1277 if (pi)
1278 break;
1279 }
1280
1281 if (!pi) {
1282 /* try V6 table */
1283 table = (*l3vpn_bgp)->rib[AFI_IP6][SAFI_UNICAST];
1284 for (*dest = bgp_table_top(table); *dest;
1285 *dest = bgp_route_next(*dest)) {
1286 pi = bgp_dest_get_bgp_path_info(*dest);
1287 if (pi)
1288 break;
1289 }
1290 }
1291 return pi;
1292 }
1293 /* real next search for the entry first use exact lookup */
1294 pi = bgp_lookup_route(*l3vpn_bgp, dest, prefix, *policy, nexthop);
1295
1296 if (pi == NULL)
1297 return NULL;
1298
1299 p = bgp_dest_get_prefix(*dest);
1300 family = p->family;
1301
1302 /* We have found the input path let's find the next one in the list */
1303 if (pi->next) {
1304 /* ensure OID is always higher for multipath routes by
1305 * incrementing opaque policy oid
1306 */
1307 *policy += 1;
1308 return pi->next;
1309 }
1310
1311 /* No more paths in the input route so find the next route */
1312 for (; *l3vpn_bgp;
1313 *l3vpn_bgp = bgp_lookup_by_name_next((*l3vpn_bgp)->name)) {
1314 *policy = 0;
1315 if (!*dest) {
1316 table = (*l3vpn_bgp)->rib[AFI_IP][SAFI_UNICAST];
1317 *dest = bgp_table_top(table);
1318 family = AF_INET;
1319 } else
1320 *dest = bgp_route_next(*dest);
1321
1322 while (true) {
1323 for (; *dest; *dest = bgp_route_next(*dest)) {
1324 pi = bgp_dest_get_bgp_path_info(*dest);
1325
1326 if (pi)
1327 return pi;
1328 }
1329 if (family == AF_INET) {
1330 table = (*l3vpn_bgp)
1331 ->rib[AFI_IP6][SAFI_UNICAST];
1332 *dest = bgp_table_top(table);
1333 family = AF_INET6;
1334 continue;
1335 }
1336 break;
1337 }
1338 }
1339
1340 return NULL;
1341 }
1342
1343 static bool is_addr_type(oid id)
1344 {
1345 switch (id) {
1346 case INETADDRESSTYPEUNKNOWN:
1347 case INETADDRESSTYPEIPV4:
1348 case INETADDRESSTYPEIPV6:
1349 return true;
1350 }
1351 return false;
1352 }
1353
1354 /* 1.3.6.1.2.1.10.166.11.1.4.1.1.x = 14*/
1355 #define PERFTAB_NAMELEN 14
1356
1357 static struct bgp_path_info *bgpL3vpnRte_lookup(struct variable *v, oid name[],
1358 size_t *length, char *vrf_name,
1359 struct bgp **l3vpn_bgp,
1360 struct bgp_dest **dest,
1361 uint16_t *policy, int exact)
1362 {
1363 uint8_t i;
1364 uint8_t vrf_name_len = 0;
1365 struct bgp_path_info *pi = NULL;
1366 size_t namelen = v ? v->namelen : IFCONFTAB_NAMELEN;
1367 struct prefix prefix = {0};
1368 struct ipaddr nexthop = {0};
1369 uint8_t prefix_type;
1370 uint8_t nexthop_type;
1371
1372 if ((uint32_t)(*length - namelen) > (VRF_NAMSIZ + 37))
1373 return NULL;
1374
1375 if (*length - namelen != 0) {
1376 /* parse incoming OID */
1377 for (i = namelen; i < (*length); i++) {
1378 if (is_addr_type(name[i]))
1379 break;
1380 vrf_name_len++;
1381 }
1382 if (vrf_name_len > VRF_NAMSIZ)
1383 return NULL;
1384
1385 oid2string(name + namelen, vrf_name_len, vrf_name);
1386 prefix_type = name[i++];
1387 switch (prefix_type) {
1388 case INETADDRESSTYPEUNKNOWN:
1389 prefix.family = AF_UNSPEC;
1390 break;
1391 case INETADDRESSTYPEIPV4:
1392 prefix.family = AF_INET;
1393 oid2in_addr(&name[i], sizeof(struct in_addr),
1394 &prefix.u.prefix4);
1395 i += sizeof(struct in_addr);
1396 break;
1397 case INETADDRESSTYPEIPV6:
1398 prefix.family = AF_INET6;
1399 oid2in6_addr(&name[i], &prefix.u.prefix6);
1400 i += sizeof(struct in6_addr);
1401 break;
1402 }
1403 prefix.prefixlen = (uint8_t)name[i++];
1404 *policy |= name[i++] << 8;
1405 *policy |= name[i++];
1406 nexthop_type = name[i++];
1407 switch (nexthop_type) {
1408 case INETADDRESSTYPEUNKNOWN:
1409 nexthop.ipa_type = (prefix.family == AF_INET)
1410 ? IPADDR_V4
1411 : IPADDR_V6;
1412 break;
1413 case INETADDRESSTYPEIPV4:
1414 nexthop.ipa_type = IPADDR_V4;
1415 oid2in_addr(&name[i], sizeof(struct in_addr),
1416 &nexthop.ip._v4_addr);
1417 /* i += sizeof(struct in_addr); */
1418 break;
1419 case INETADDRESSTYPEIPV6:
1420 nexthop.ipa_type = IPADDR_V6;
1421 oid2in6_addr(&name[i], &nexthop.ip._v6_addr);
1422 /* i += sizeof(struct in6_addr); */
1423 break;
1424 }
1425 }
1426
1427 if (exact) {
1428 *l3vpn_bgp = bgp_lookup_by_name(vrf_name);
1429 if (*l3vpn_bgp && !is_bgp_vrf_mplsvpn(*l3vpn_bgp))
1430 return NULL;
1431 if (*l3vpn_bgp == NULL)
1432 return NULL;
1433
1434 /* now lookup the route in this bgp table */
1435 pi = bgp_lookup_route(*l3vpn_bgp, dest, &prefix, *policy,
1436 &nexthop);
1437 } else {
1438 int str_len;
1439
1440 str_len = strnlen(vrf_name, VRF_NAMSIZ);
1441 if (str_len == 0) {
1442 *l3vpn_bgp = bgp_lookup_by_name_next(vrf_name);
1443 } else
1444 /* otherwise lookup the one we have */
1445 *l3vpn_bgp = bgp_lookup_by_name(vrf_name);
1446
1447 if (*l3vpn_bgp == NULL)
1448 return NULL;
1449
1450 pi = bgp_lookup_route_next(l3vpn_bgp, dest, &prefix, policy,
1451 &nexthop);
1452 if (pi) {
1453 uint8_t vrf_name_len =
1454 strnlen((*l3vpn_bgp)->name, VRF_NAMSIZ);
1455 const struct prefix *p = bgp_dest_get_prefix(*dest);
1456 uint8_t oid_index;
1457 bool v4 = (p->family == AF_INET);
1458 uint8_t addr_len = v4 ? sizeof(struct in_addr)
1459 : sizeof(struct in6_addr);
1460 struct attr *attr = pi->attr;
1461
1462 /* copy the index parameters */
1463 oid_copy_str(&name[namelen], (*l3vpn_bgp)->name,
1464 vrf_name_len);
1465 oid_index = namelen + vrf_name_len;
1466 if (v4) {
1467 name[oid_index++] = INETADDRESSTYPEIPV4;
1468 oid_copy_in_addr(&name[oid_index],
1469 &p->u.prefix4);
1470 } else {
1471 name[oid_index++] = INETADDRESSTYPEIPV6;
1472 oid_copy_in6_addr(&name[oid_index],
1473 &p->u.prefix6);
1474 }
1475
1476 oid_index += addr_len;
1477 name[oid_index++] = p->prefixlen;
1478 name[oid_index++] = *policy >> 8;
1479 name[oid_index++] = *policy & 0xff;
1480
1481 if (!BGP_ATTR_NEXTHOP_AFI_IP6(attr)) {
1482 if (attr->nexthop.s_addr == INADDR_ANY)
1483 name[oid_index++] =
1484 INETADDRESSTYPEUNKNOWN;
1485 else {
1486 name[oid_index++] = INETADDRESSTYPEIPV4;
1487 oid_copy_in_addr(&name[oid_index],
1488 &attr->nexthop);
1489 oid_index += sizeof(struct in_addr);
1490 }
1491 } else {
1492 if (IN6_IS_ADDR_UNSPECIFIED(
1493 &attr->mp_nexthop_global))
1494 name[oid_index++] =
1495 INETADDRESSTYPEUNKNOWN;
1496 else {
1497 name[oid_index++] = INETADDRESSTYPEIPV6;
1498 oid_copy_in6_addr(
1499 &name[oid_index],
1500 &attr->mp_nexthop_global);
1501 oid_index += sizeof(struct in6_addr);
1502 }
1503 }
1504 *length = oid_index;
1505 }
1506 }
1507 return pi;
1508 }
1509
1510 static uint8_t *mplsL3vpnRteTable(struct variable *v, oid name[],
1511 size_t *length, int exact, size_t *var_len,
1512 WriteMethod **write_method)
1513 {
1514 char vrf_name[VRF_NAMSIZ];
1515 struct bgp *l3vpn_bgp;
1516 struct bgp_dest *dest;
1517 struct bgp_path_info *pi, *bpi_ultimate;
1518 const struct prefix *p;
1519 uint16_t policy = 0;
1520
1521 if (smux_header_table(v, name, length, exact, var_len, write_method)
1522 == MATCH_FAILED)
1523 return NULL;
1524
1525 memset(vrf_name, 0, VRF_NAMSIZ);
1526 pi = bgpL3vpnRte_lookup(v, name, length, vrf_name, &l3vpn_bgp, &dest,
1527 &policy, exact);
1528
1529
1530 if (!pi)
1531 return NULL;
1532
1533 bpi_ultimate = bgp_get_imported_bpi_ultimate(pi);
1534
1535 p = bgp_dest_get_prefix(dest);
1536
1537 if (!p)
1538 return NULL;
1539
1540 switch (v->magic) {
1541 case MPLSL3VPNVRFRTEINETCIDRDESTTYPE:
1542 switch (p->family) {
1543 case AF_INET:
1544 return SNMP_INTEGER(INETADDRESSTYPEIPV4);
1545 case AF_INET6:
1546 return SNMP_INTEGER(INETADDRESSTYPEIPV6);
1547 default:
1548 return SNMP_INTEGER(INETADDRESSTYPEUNKNOWN);
1549 }
1550 case MPLSL3VPNVRFRTEINETCIDRDEST:
1551 switch (p->family) {
1552 case AF_INET:
1553 return SNMP_IPADDRESS(p->u.prefix4);
1554 case AF_INET6:
1555 return SNMP_IP6ADDRESS(p->u.prefix6);
1556 default:
1557 *var_len = 0;
1558 return NULL;
1559 }
1560 case MPLSL3VPNVRFRTEINETCIDRPFXLEN:
1561 return SNMP_INTEGER(p->prefixlen);
1562 case MPLSL3VPNVRFRTEINETCIDRPOLICY:
1563 *var_len = sizeof(mpls_l3vpn_policy_oid);
1564 mpls_l3vpn_policy_oid[0] = policy >> 8;
1565 mpls_l3vpn_policy_oid[1] = policy & 0xff;
1566 return (uint8_t *)mpls_l3vpn_policy_oid;
1567 case MPLSL3VPNVRFRTEINETCIDRNHOPTYPE:
1568 if (!BGP_ATTR_NEXTHOP_AFI_IP6(pi->attr)) {
1569 if (pi->attr->nexthop.s_addr == INADDR_ANY)
1570 return SNMP_INTEGER(INETADDRESSTYPEUNKNOWN);
1571 else
1572 return SNMP_INTEGER(INETADDRESSTYPEIPV4);
1573 } else if (IN6_IS_ADDR_UNSPECIFIED(
1574 &pi->attr->mp_nexthop_global))
1575 return SNMP_INTEGER(INETADDRESSTYPEUNKNOWN);
1576 else
1577 return SNMP_INTEGER(INETADDRESSTYPEIPV6);
1578
1579 case MPLSL3VPNVRFRTEINETCIDRNEXTHOP:
1580 if (!BGP_ATTR_NEXTHOP_AFI_IP6(pi->attr))
1581 if (pi->attr->nexthop.s_addr == INADDR_ANY) {
1582 *var_len = 0;
1583 return (uint8_t *)empty_nhop;
1584 } else
1585 return SNMP_IPADDRESS(pi->attr->nexthop);
1586 else if (IN6_IS_ADDR_UNSPECIFIED(
1587 &pi->attr->mp_nexthop_global)) {
1588 *var_len = 0;
1589 return (uint8_t *)empty_nhop;
1590 } else
1591 return SNMP_IP6ADDRESS(pi->attr->mp_nexthop_global);
1592
1593 case MPLSL3VPNVRFRTEINETCIDRIFINDEX:
1594 if (pi->nexthop && pi->nexthop->nexthop)
1595 return SNMP_INTEGER(pi->nexthop->nexthop->ifindex);
1596 else
1597 return SNMP_INTEGER(0);
1598 case MPLSL3VPNVRFRTEINETCIDRTYPE:
1599 if (pi->nexthop && pi->nexthop->nexthop) {
1600 switch (pi->nexthop->nexthop->type) {
1601 case NEXTHOP_TYPE_IFINDEX:
1602 return SNMP_INTEGER(
1603 MPLSL3VPNVRFRTECIDRTYPELOCAL);
1604 case NEXTHOP_TYPE_IPV4:
1605 case NEXTHOP_TYPE_IPV4_IFINDEX:
1606 case NEXTHOP_TYPE_IPV6:
1607 case NEXTHOP_TYPE_IPV6_IFINDEX:
1608 return SNMP_INTEGER(
1609 MPLSL3VPNVRFRTECIDRTYPEREMOTE);
1610 case NEXTHOP_TYPE_BLACKHOLE:
1611 switch (pi->nexthop->nexthop->bh_type) {
1612 case BLACKHOLE_REJECT:
1613 return SNMP_INTEGER(
1614 MPLSL3VPNVRFRTECIDRTYPEREJECT);
1615 case BLACKHOLE_UNSPEC:
1616 case BLACKHOLE_NULL:
1617 case BLACKHOLE_ADMINPROHIB:
1618 return SNMP_INTEGER(
1619 MPLSL3VPNVRFRTECIDRTYPEBLACKHOLE);
1620 }
1621 break;
1622 }
1623 } else
1624 return SNMP_INTEGER(MPLSL3VPNVRFRTECIDRTYPEOTHER);
1625 case MPLSL3VPNVRFRTEINETCIDRPROTO:
1626 switch (pi->type) {
1627 case ZEBRA_ROUTE_CONNECT:
1628 return SNMP_INTEGER(IANAIPROUTEPROTOCOLLOCAL);
1629 case ZEBRA_ROUTE_STATIC:
1630 return SNMP_INTEGER(IANAIPROUTEPROTOCOLNETMGMT);
1631 case ZEBRA_ROUTE_RIP:
1632 case ZEBRA_ROUTE_RIPNG:
1633 return SNMP_INTEGER(IANAIPROUTEPROTOCOLRIP);
1634 case ZEBRA_ROUTE_OSPF:
1635 case ZEBRA_ROUTE_OSPF6:
1636 return SNMP_INTEGER(IANAIPROUTEPROTOCOLOSPF);
1637 case ZEBRA_ROUTE_ISIS:
1638 return SNMP_INTEGER(IANAIPROUTEPROTOCOLISIS);
1639 case ZEBRA_ROUTE_BGP:
1640 return SNMP_INTEGER(IANAIPROUTEPROTOCOLBGP);
1641 case ZEBRA_ROUTE_EIGRP:
1642 return SNMP_INTEGER(IANAIPROUTEPROTOCOLCISCOEIGRP);
1643 default:
1644 return SNMP_INTEGER(IANAIPROUTEPROTOCOLOTHER);
1645 }
1646 case MPLSL3VPNVRFRTEINETCIDRAGE:
1647 return SNMP_INTEGER(pi->uptime);
1648 case MPLSL3VPNVRFRTEINETCIDRNEXTHOPAS:
1649 return SNMP_INTEGER(pi->peer ? pi->peer->as : 0);
1650 case MPLSL3VPNVRFRTEINETCIDRMETRIC1:
1651 if (bpi_ultimate->extra)
1652 return SNMP_INTEGER(bpi_ultimate->extra->igpmetric);
1653 else
1654 return SNMP_INTEGER(0);
1655 case MPLSL3VPNVRFRTEINETCIDRMETRIC2:
1656 return SNMP_INTEGER(-1);
1657 case MPLSL3VPNVRFRTEINETCIDRMETRIC3:
1658 return SNMP_INTEGER(-1);
1659 case MPLSL3VPNVRFRTEINETCIDRMETRIC4:
1660 return SNMP_INTEGER(-1);
1661 case MPLSL3VPNVRFRTEINETCIDRMETRIC5:
1662 return SNMP_INTEGER(-1);
1663 case MPLSL3VPNVRFRTEINETCIDRXCPOINTER:
1664 return SNMP_OCTET(0);
1665 case MPLSL3VPNVRFRTEINETCIDRSTATUS:
1666 return SNMP_INTEGER(1);
1667 }
1668 return NULL;
1669 }
1670
1671 void bgp_mpls_l3vpn_module_init(void)
1672 {
1673 hook_register(bgp_vrf_status_changed, bgp_vrf_check_update_active);
1674 hook_register(bgp_snmp_init_stats, bgp_init_snmp_stats);
1675 hook_register(bgp_snmp_update_last_changed,
1676 bgp_mpls_l3vpn_update_last_changed);
1677 hook_register(bgp_snmp_update_stats, bgp_snmp_update_route_stats);
1678 REGISTER_MIB("mplsL3VpnMIB", mpls_l3vpn_variables, variable,
1679 mpls_l3vpn_oid);
1680 }