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