]> git.proxmox.com Git - mirror_frr.git/blob - bgpd/rfapi/rfapi_import.c
Merge pull request #12963 from anlancs/fix/bgpd-keep-common
[mirror_frr.git] / bgpd / rfapi / rfapi_import.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright 2009-2016, LabN Consulting, L.L.C.
4 */
5
6 /*
7 * File: rfapi_import.c
8 * Purpose: Handle import of routes from BGP to RFAPI
9 */
10
11 #include "lib/zebra.h"
12 #include "lib/prefix.h"
13 #include "lib/agg_table.h"
14 #include "lib/vty.h"
15 #include "lib/memory.h"
16 #include "lib/log.h"
17 #include "lib/skiplist.h"
18 #include "lib/thread.h"
19 #include "lib/stream.h"
20 #include "lib/lib_errors.h"
21
22 #include "bgpd/bgpd.h"
23 #include "bgpd/bgp_ecommunity.h"
24 #include "bgpd/bgp_attr.h"
25 #include "bgpd/bgp_route.h"
26 #include "bgpd/bgp_mplsvpn.h" /* prefix_rd2str() */
27 #include "bgpd/bgp_vnc_types.h"
28 #include "bgpd/bgp_rd.h"
29
30 #include "bgpd/rfapi/rfapi.h"
31 #include "bgpd/rfapi/bgp_rfapi_cfg.h"
32 #include "bgpd/rfapi/rfapi_backend.h"
33 #include "bgpd/rfapi/rfapi_import.h"
34 #include "bgpd/rfapi/rfapi_private.h"
35 #include "bgpd/rfapi/rfapi_monitor.h"
36 #include "bgpd/rfapi/rfapi_nve_addr.h"
37 #include "bgpd/rfapi/rfapi_vty.h"
38 #include "bgpd/rfapi/vnc_export_bgp.h"
39 #include "bgpd/rfapi/vnc_export_bgp_p.h"
40 #include "bgpd/rfapi/vnc_zebra.h"
41 #include "bgpd/rfapi/vnc_import_bgp.h"
42 #include "bgpd/rfapi/vnc_import_bgp_p.h"
43 #include "bgpd/rfapi/rfapi_rib.h"
44 #include "bgpd/rfapi/rfapi_encap_tlv.h"
45 #include "bgpd/rfapi/vnc_debug.h"
46
47 #ifdef HAVE_GLIBC_BACKTRACE
48 /* for backtrace and friends */
49 #include <execinfo.h>
50 #endif /* HAVE_GLIBC_BACKTRACE */
51
52 #undef DEBUG_MONITOR_MOVE_SHORTER
53 #undef DEBUG_RETURNED_NHL
54 #undef DEBUG_ROUTE_COUNTERS
55 #undef DEBUG_ENCAP_MONITOR
56 #undef DEBUG_L2_EXTRA
57 #undef DEBUG_IT_NODES
58 #undef DEBUG_BI_SEARCH
59
60 /*
61 * Allocated for each withdraw timer instance; freed when the timer
62 * expires or is canceled
63 */
64 struct rfapi_withdraw {
65 struct rfapi_import_table *import_table;
66 struct agg_node *node;
67 struct bgp_path_info *info;
68 safi_t safi; /* used only for bulk operations */
69 /*
70 * For import table node reference count checking (i.e., debugging).
71 * Normally when a timer expires, lockoffset should be 0. However, if
72 * the timer expiration function is called directly (e.g.,
73 * rfapiExpireVpnNow), the node could be locked by a preceding
74 * agg_route_top() or agg_route_next() in a loop, so we need to pass
75 * this value in.
76 */
77 int lockoffset;
78 };
79
80 /*
81 * DEBUG FUNCTION
82 * It's evil and fiendish. It's compiler-dependent.
83 * ? Might need LDFLAGS -rdynamic to produce all function names
84 */
85 void rfapiDebugBacktrace(void)
86 {
87 #ifdef HAVE_GLIBC_BACKTRACE
88 #define RFAPI_DEBUG_BACKTRACE_NENTRIES 200
89 void *buf[RFAPI_DEBUG_BACKTRACE_NENTRIES];
90 char **syms;
91 size_t i;
92 size_t size;
93
94 size = backtrace(buf, RFAPI_DEBUG_BACKTRACE_NENTRIES);
95 syms = backtrace_symbols(buf, size);
96
97 for (i = 0; i < size && i < RFAPI_DEBUG_BACKTRACE_NENTRIES; ++i) {
98 vnc_zlog_debug_verbose("backtrace[%2zu]: %s", i, syms[i]);
99 }
100
101 free(syms);
102 #else
103 #endif
104 }
105
106 /*
107 * DEBUG FUNCTION
108 * Count remote routes and compare with actively-maintained values.
109 * Abort if they disagree.
110 */
111 void rfapiCheckRouteCount(void)
112 {
113 struct bgp *bgp = bgp_get_default();
114 struct rfapi *h;
115 struct rfapi_import_table *it;
116 afi_t afi;
117
118 assert(bgp);
119
120 h = bgp->rfapi;
121 assert(h);
122
123 for (it = h->imports; it; it = it->next) {
124 for (afi = AFI_IP; afi < AFI_MAX; ++afi) {
125
126 struct agg_table *rt;
127 struct agg_node *rn;
128
129 int holddown_count = 0;
130 int local_count = 0;
131 int imported_count = 0;
132 int remote_count = 0;
133
134 rt = it->imported_vpn[afi];
135
136 for (rn = agg_route_top(rt); rn;
137 rn = agg_route_next(rn)) {
138 struct bgp_path_info *bpi;
139 struct bgp_path_info *next;
140
141 for (bpi = rn->info; bpi; bpi = next) {
142 next = bpi->next;
143
144 if (CHECK_FLAG(bpi->flags,
145 BGP_PATH_REMOVED)) {
146 ++holddown_count;
147
148 } else {
149 if (RFAPI_LOCAL_BI(bpi)) {
150 ++local_count;
151 } else {
152 if (RFAPI_DIRECT_IMPORT_BI(
153 bpi)) {
154 ++imported_count;
155 } else {
156 ++remote_count;
157 }
158 }
159 }
160 }
161 }
162
163 if (it->holddown_count[afi] != holddown_count) {
164 vnc_zlog_debug_verbose(
165 "%s: it->holddown_count %d != holddown_count %d",
166 __func__, it->holddown_count[afi],
167 holddown_count);
168 assert(0);
169 }
170 if (it->remote_count[afi] != remote_count) {
171 vnc_zlog_debug_verbose(
172 "%s: it->remote_count %d != remote_count %d",
173 __func__, it->remote_count[afi],
174 remote_count);
175 assert(0);
176 }
177 if (it->imported_count[afi] != imported_count) {
178 vnc_zlog_debug_verbose(
179 "%s: it->imported_count %d != imported_count %d",
180 __func__, it->imported_count[afi],
181 imported_count);
182 assert(0);
183 }
184 }
185 }
186 }
187
188 #ifdef DEBUG_ROUTE_COUNTERS
189 #define VNC_ITRCCK do {rfapiCheckRouteCount();} while (0)
190 #else
191 #define VNC_ITRCCK
192 #endif
193
194 /*
195 * Validate reference count for a node in an import table
196 *
197 * Normally lockoffset is 0 for nodes in quiescent state. However,
198 * agg_unlock_node will delete the node if it is called when
199 * node->lock == 1, and we have to validate the refcount before
200 * the node is deleted. In this case, we specify lockoffset 1.
201 */
202 void rfapiCheckRefcount(struct agg_node *rn, safi_t safi, int lockoffset)
203 {
204 unsigned int count_bpi = 0;
205 unsigned int count_monitor = 0;
206 struct bgp_path_info *bpi;
207 struct rfapi_monitor_encap *hme;
208 struct rfapi_monitor_vpn *hmv;
209
210 for (bpi = rn->info; bpi; bpi = bpi->next)
211 ++count_bpi;
212
213
214 if (rn->aggregate) {
215 ++count_monitor; /* rfapi_it_extra */
216
217 switch (safi) {
218 void *cursor;
219 int rc;
220
221 case SAFI_ENCAP:
222 for (hme = RFAPI_MONITOR_ENCAP(rn); hme;
223 hme = hme->next)
224 ++count_monitor;
225 break;
226
227 case SAFI_MPLS_VPN:
228
229 for (hmv = RFAPI_MONITOR_VPN(rn); hmv; hmv = hmv->next)
230 ++count_monitor;
231
232 if (RFAPI_MONITOR_EXTERIOR(rn)->source) {
233 ++count_monitor; /* sl */
234 cursor = NULL;
235 for (rc = skiplist_next(
236 RFAPI_MONITOR_EXTERIOR(rn)->source,
237 NULL, NULL, &cursor);
238 !rc;
239 rc = skiplist_next(
240 RFAPI_MONITOR_EXTERIOR(rn)->source,
241 NULL, NULL, &cursor)) {
242
243 ++count_monitor; /* sl entry */
244 }
245 }
246 break;
247
248 case SAFI_UNSPEC:
249 case SAFI_UNICAST:
250 case SAFI_MULTICAST:
251 case SAFI_EVPN:
252 case SAFI_LABELED_UNICAST:
253 case SAFI_FLOWSPEC:
254 case SAFI_MAX:
255 assert(!"Passed in safi should be impossible");
256 }
257 }
258
259 if (count_bpi + count_monitor + lockoffset
260 != agg_node_get_lock_count(rn)) {
261 vnc_zlog_debug_verbose(
262 "%s: count_bpi=%d, count_monitor=%d, lockoffset=%d, rn->lock=%d",
263 __func__, count_bpi, count_monitor, lockoffset,
264 agg_node_get_lock_count(rn));
265 assert(0);
266 }
267 }
268
269 /*
270 * Perform deferred rfapi_close operations that were queued
271 * during callbacks.
272 */
273 static wq_item_status rfapi_deferred_close_workfunc(struct work_queue *q,
274 void *data)
275 {
276 struct rfapi_descriptor *rfd = data;
277 struct rfapi *h = q->spec.data;
278
279 assert(!(h->flags & RFAPI_INCALLBACK));
280 rfapi_close(rfd);
281 vnc_zlog_debug_verbose("%s: completed deferred close on handle %p",
282 __func__, rfd);
283 return WQ_SUCCESS;
284 }
285
286 /*
287 * Extract layer 2 option from Encap TLVS in BGP attrs
288 */
289 int rfapiGetL2o(struct attr *attr, struct rfapi_l2address_option *l2o)
290 {
291 if (attr) {
292 struct bgp_attr_encap_subtlv *pEncap;
293
294 for (pEncap = bgp_attr_get_vnc_subtlvs(attr); pEncap;
295 pEncap = pEncap->next) {
296
297 if (pEncap->type == BGP_VNC_SUBTLV_TYPE_RFPOPTION) {
298 if (pEncap->value[0]
299 == RFAPI_VN_OPTION_TYPE_L2ADDR) {
300
301 if (pEncap->value[1] == 14) {
302 memcpy(l2o->macaddr.octet,
303 pEncap->value + 2,
304 ETH_ALEN);
305 l2o->label =
306 ((pEncap->value[10]
307 >> 4)
308 & 0x0f)
309 + ((pEncap->value[9]
310 << 4)
311 & 0xff0)
312 + ((pEncap->value[8]
313 << 12)
314 & 0xff000);
315
316 l2o->local_nve_id =
317 pEncap->value[12];
318
319 l2o->logical_net_id =
320 (pEncap->value[15]
321 & 0xff)
322 + ((pEncap->value[14]
323 << 8)
324 & 0xff00)
325 + ((pEncap->value[13]
326 << 16)
327 & 0xff0000);
328 }
329
330 return 0;
331 }
332 }
333 }
334 }
335
336 return ENOENT;
337 }
338
339 /*
340 * Extract the lifetime from the Tunnel Encap attribute of a route in
341 * an import table
342 */
343 int rfapiGetVncLifetime(struct attr *attr, uint32_t *lifetime)
344 {
345 struct bgp_attr_encap_subtlv *pEncap;
346
347 *lifetime = RFAPI_INFINITE_LIFETIME; /* default to infinite */
348
349 if (attr) {
350
351 for (pEncap = bgp_attr_get_vnc_subtlvs(attr); pEncap;
352 pEncap = pEncap->next) {
353
354 if (pEncap->type
355 == BGP_VNC_SUBTLV_TYPE_LIFETIME) { /* lifetime */
356 if (pEncap->length == 4) {
357 memcpy(lifetime, pEncap->value, 4);
358 *lifetime = ntohl(*lifetime);
359 return 0;
360 }
361 }
362 }
363 }
364
365 return ENOENT;
366 }
367
368 /*
369 * Look for UN address in Encap attribute
370 */
371 int rfapiGetVncTunnelUnAddr(struct attr *attr, struct prefix *p)
372 {
373 struct bgp_attr_encap_subtlv *pEncap;
374 bgp_encap_types tun_type = BGP_ENCAP_TYPE_MPLS;/*Default tunnel type*/
375
376 bgp_attr_extcom_tunnel_type(attr, &tun_type);
377 if (tun_type == BGP_ENCAP_TYPE_MPLS) {
378 if (!p)
379 return 0;
380 /* MPLS carries UN address in next hop */
381 rfapiNexthop2Prefix(attr, p);
382 if (p->family != AF_UNSPEC)
383 return 0;
384
385 return ENOENT;
386 }
387 if (attr) {
388 for (pEncap = attr->encap_subtlvs; pEncap;
389 pEncap = pEncap->next) {
390
391 if (pEncap->type
392 == BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT) { /* un
393 addr
394 */
395 switch (pEncap->length) {
396 case 8:
397 if (p) {
398 p->family = AF_INET;
399 p->prefixlen = IPV4_MAX_BITLEN;
400 memcpy(p->u.val, pEncap->value,
401 4);
402 }
403 return 0;
404
405 case 20:
406 if (p) {
407 p->family = AF_INET6;
408 p->prefixlen = IPV6_MAX_BITLEN;
409 memcpy(p->u.val, pEncap->value,
410 16);
411 }
412 return 0;
413 }
414 }
415 }
416 }
417
418 return ENOENT;
419 }
420
421 /*
422 * Get UN address wherever it might be
423 */
424 int rfapiGetUnAddrOfVpnBi(struct bgp_path_info *bpi, struct prefix *p)
425 {
426 /* If it's in this route's VNC attribute, we're done */
427 if (!rfapiGetVncTunnelUnAddr(bpi->attr, p))
428 return 0;
429 /*
430 * Otherwise, see if it's cached from a corresponding ENCAP SAFI
431 * advertisement
432 */
433 if (bpi->extra) {
434 switch (bpi->extra->vnc.import.un_family) {
435 case AF_INET:
436 if (p) {
437 p->family = bpi->extra->vnc.import.un_family;
438 p->u.prefix4 = bpi->extra->vnc.import.un.addr4;
439 p->prefixlen = IPV4_MAX_BITLEN;
440 }
441 return 0;
442 case AF_INET6:
443 if (p) {
444 p->family = bpi->extra->vnc.import.un_family;
445 p->u.prefix6 = bpi->extra->vnc.import.un.addr6;
446 p->prefixlen = IPV6_MAX_BITLEN;
447 }
448 return 0;
449 default:
450 if (p)
451 p->family = AF_UNSPEC;
452 #ifdef DEBUG_ENCAP_MONITOR
453 vnc_zlog_debug_verbose(
454 "%s: bpi->extra->vnc.import.un_family is 0, no UN addr",
455 __func__);
456 #endif
457 break;
458 }
459 }
460
461 return ENOENT;
462 }
463
464
465 /*
466 * Make a new bgp_path_info from gathered parameters
467 */
468 static struct bgp_path_info *rfapiBgpInfoCreate(struct attr *attr,
469 struct peer *peer, void *rfd,
470 struct prefix_rd *prd,
471 uint8_t type, uint8_t sub_type,
472 uint32_t *label)
473 {
474 struct bgp_path_info *new;
475
476 new = info_make(type, sub_type, 0, peer, attr, NULL);
477
478 new->attr = bgp_attr_intern(attr);
479
480 bgp_path_info_extra_get(new);
481 if (prd) {
482 new->extra->vnc.import.rd = *prd;
483 new->extra->vnc.import.create_time = monotime(NULL);
484 }
485 if (label)
486 encode_label(*label, &new->extra->label[0]);
487
488 peer_lock(peer);
489
490 return new;
491 }
492
493 /*
494 * Frees bgp_path_info as used in import tables (parts are not
495 * allocated exactly the way they are in the main RIBs)
496 */
497 static void rfapiBgpInfoFree(struct bgp_path_info *goner)
498 {
499 if (!goner)
500 return;
501
502 if (goner->peer) {
503 vnc_zlog_debug_verbose("%s: calling peer_unlock(%p), #%d",
504 __func__, goner->peer,
505 goner->peer->lock);
506 peer_unlock(goner->peer);
507 }
508
509 bgp_attr_unintern(&goner->attr);
510
511 if (goner->extra)
512 bgp_path_info_extra_free(&goner->extra);
513 XFREE(MTYPE_BGP_ROUTE, goner);
514 }
515
516 struct rfapi_import_table *rfapiMacImportTableGetNoAlloc(struct bgp *bgp,
517 uint32_t lni)
518 {
519 struct rfapi *h;
520 struct rfapi_import_table *it = NULL;
521 uintptr_t lni_as_ptr = lni;
522
523 h = bgp->rfapi;
524 if (!h)
525 return NULL;
526
527 if (!h->import_mac)
528 return NULL;
529
530 if (skiplist_search(h->import_mac, (void *)lni_as_ptr, (void **)&it))
531 return NULL;
532
533 return it;
534 }
535
536 struct rfapi_import_table *rfapiMacImportTableGet(struct bgp *bgp, uint32_t lni)
537 {
538 struct rfapi *h;
539 struct rfapi_import_table *it = NULL;
540 uintptr_t lni_as_ptr = lni;
541
542 h = bgp->rfapi;
543 assert(h);
544
545 if (!h->import_mac) {
546 /* default cmp is good enough for LNI */
547 h->import_mac = skiplist_new(0, NULL, NULL);
548 }
549
550 if (skiplist_search(h->import_mac, (void *)lni_as_ptr, (void **)&it)) {
551
552 struct ecommunity *enew;
553 struct ecommunity_val eval;
554 afi_t afi;
555
556 it = XCALLOC(MTYPE_RFAPI_IMPORTTABLE,
557 sizeof(struct rfapi_import_table));
558 /* set RT list of new import table based on LNI */
559 memset((char *)&eval, 0, sizeof(eval));
560 eval.val[0] = 0; /* VNC L2VPN */
561 eval.val[1] = 2; /* VNC L2VPN */
562 eval.val[5] = (lni >> 16) & 0xff;
563 eval.val[6] = (lni >> 8) & 0xff;
564 eval.val[7] = (lni >> 0) & 0xff;
565
566 enew = ecommunity_new();
567 ecommunity_add_val(enew, &eval, false, false);
568 it->rt_import_list = enew;
569
570 for (afi = AFI_IP; afi < AFI_MAX; ++afi) {
571 it->imported_vpn[afi] = agg_table_init();
572 it->imported_encap[afi] = agg_table_init();
573 }
574
575 it->l2_logical_net_id = lni;
576
577 skiplist_insert(h->import_mac, (void *)lni_as_ptr, it);
578 }
579
580 assert(it);
581 return it;
582 }
583
584 /*
585 * Implement MONITOR_MOVE_SHORTER(original_node) from
586 * RFAPI-Import-Event-Handling.txt
587 *
588 * Returns pointer to the list of moved monitors
589 */
590 static struct rfapi_monitor_vpn *
591 rfapiMonitorMoveShorter(struct agg_node *original_vpn_node, int lockoffset)
592 {
593 struct bgp_path_info *bpi;
594 struct agg_node *par;
595 struct rfapi_monitor_vpn *m;
596 struct rfapi_monitor_vpn *mlast;
597 struct rfapi_monitor_vpn *moved;
598 int movecount = 0;
599 int parent_already_refcounted = 0;
600
601 RFAPI_CHECK_REFCOUNT(original_vpn_node, SAFI_MPLS_VPN, lockoffset);
602
603 #ifdef DEBUG_MONITOR_MOVE_SHORTER
604 {
605 vnc_zlog_debug_verbose("%s: called with node pfx=%pFX",
606 __func__, &original_vpn_node->p);
607 }
608 #endif
609
610 /*
611 * 1. If there is at least one bpi (either regular route or
612 * route marked as withdrawn, with a pending timer) at
613 * original_node with a valid UN address, we're done. Return.
614 */
615 for (bpi = original_vpn_node->info; bpi; bpi = bpi->next) {
616 struct prefix pfx;
617
618 if (!rfapiGetUnAddrOfVpnBi(bpi, &pfx)) {
619 #ifdef DEBUG_MONITOR_MOVE_SHORTER
620 vnc_zlog_debug_verbose(
621 "%s: have valid UN at original node, no change",
622 __func__);
623 #endif
624 return NULL;
625 }
626 }
627
628 /*
629 * 2. Travel up the tree (toward less-specific prefixes) from
630 * original_node to find the first node that has at least
631 * one route (even if it is only a withdrawn route) with a
632 * valid UN address. Call this node "Node P."
633 */
634 for (par = agg_node_parent(original_vpn_node); par;
635 par = agg_node_parent(par)) {
636 for (bpi = par->info; bpi; bpi = bpi->next) {
637 struct prefix pfx;
638 if (!rfapiGetUnAddrOfVpnBi(bpi, &pfx)) {
639 break;
640 }
641 }
642 if (bpi)
643 break;
644 }
645
646 if (par) {
647 RFAPI_CHECK_REFCOUNT(par, SAFI_MPLS_VPN, 0);
648 }
649
650 /*
651 * If no less-specific routes, try to use the 0/0 node
652 */
653 if (!par) {
654 const struct prefix *p;
655 /* this isn't necessarily 0/0 */
656 par = agg_route_table_top(original_vpn_node);
657
658 if (par)
659 p = agg_node_get_prefix(par);
660 /*
661 * If we got the top node but it wasn't 0/0,
662 * ignore it
663 */
664 if (par && p->prefixlen) {
665 agg_unlock_node(par); /* maybe free */
666 par = NULL;
667 }
668
669 if (par) {
670 ++parent_already_refcounted;
671 }
672 }
673
674 /*
675 * Create 0/0 node if it isn't there
676 */
677 if (!par) {
678 struct prefix pfx_default;
679 const struct prefix *p = agg_node_get_prefix(original_vpn_node);
680
681 memset(&pfx_default, 0, sizeof(pfx_default));
682 pfx_default.family = p->family;
683
684 /* creates default node if none exists */
685 par = agg_node_get(agg_get_table(original_vpn_node),
686 &pfx_default);
687 ++parent_already_refcounted;
688 }
689
690 /*
691 * 3. Move each of the monitors found at original_node to Node P.
692 * These are "Moved Monitors."
693 *
694 */
695
696 /*
697 * Attach at end so that the list pointer we return points
698 * only to the moved routes
699 */
700 for (m = RFAPI_MONITOR_VPN(par), mlast = NULL; m;
701 mlast = m, m = m->next)
702 ;
703
704 if (mlast) {
705 moved = mlast->next = RFAPI_MONITOR_VPN(original_vpn_node);
706 } else {
707 moved = RFAPI_MONITOR_VPN_W_ALLOC(par) =
708 RFAPI_MONITOR_VPN(original_vpn_node);
709 }
710 if (RFAPI_MONITOR_VPN(
711 original_vpn_node)) /* check agg, so not allocated */
712 RFAPI_MONITOR_VPN_W_ALLOC(original_vpn_node) = NULL;
713
714 /*
715 * update the node pointers on the monitors
716 */
717 for (m = moved; m; m = m->next) {
718 ++movecount;
719 m->node = par;
720 }
721
722 RFAPI_CHECK_REFCOUNT(par, SAFI_MPLS_VPN,
723 parent_already_refcounted - movecount);
724 while (movecount > parent_already_refcounted) {
725 agg_lock_node(par);
726 ++parent_already_refcounted;
727 }
728 while (movecount < parent_already_refcounted) {
729 /* unlikely, but code defensively */
730 agg_unlock_node(par);
731 --parent_already_refcounted;
732 }
733 RFAPI_CHECK_REFCOUNT(original_vpn_node, SAFI_MPLS_VPN,
734 movecount + lockoffset);
735 while (movecount--) {
736 agg_unlock_node(original_vpn_node);
737 }
738
739 #ifdef DEBUG_MONITOR_MOVE_SHORTER
740 {
741 vnc_zlog_debug_verbose("%s: moved to node pfx=%pFX", __func__,
742 &par->p);
743 }
744 #endif
745
746
747 return moved;
748 }
749
750 /*
751 * Implement MONITOR_MOVE_LONGER(new_node) from
752 * RFAPI-Import-Event-Handling.txt
753 */
754 static void rfapiMonitorMoveLonger(struct agg_node *new_vpn_node)
755 {
756 struct rfapi_monitor_vpn *monitor;
757 struct rfapi_monitor_vpn *mlast;
758 struct bgp_path_info *bpi;
759 struct agg_node *par;
760 const struct prefix *new_vpn_node_p = agg_node_get_prefix(new_vpn_node);
761
762 RFAPI_CHECK_REFCOUNT(new_vpn_node, SAFI_MPLS_VPN, 0);
763
764 /*
765 * Make sure we have at least one valid route at the new node
766 */
767 for (bpi = new_vpn_node->info; bpi; bpi = bpi->next) {
768 struct prefix pfx;
769 if (!rfapiGetUnAddrOfVpnBi(bpi, &pfx))
770 break;
771 }
772
773 if (!bpi) {
774 vnc_zlog_debug_verbose(
775 "%s: no valid routes at node %p, so not attempting moves",
776 __func__, new_vpn_node);
777 return;
778 }
779
780 /*
781 * Find first parent node that has monitors
782 */
783 for (par = agg_node_parent(new_vpn_node); par;
784 par = agg_node_parent(par)) {
785 if (RFAPI_MONITOR_VPN(par))
786 break;
787 }
788
789 if (!par) {
790 vnc_zlog_debug_verbose(
791 "%s: no parent nodes with monitors, done", __func__);
792 return;
793 }
794
795 /*
796 * Check each of these monitors to see of their longest-match
797 * is now the updated node. Move any such monitors to the more-
798 * specific updated node
799 */
800 for (mlast = NULL, monitor = RFAPI_MONITOR_VPN(par); monitor;) {
801 /*
802 * If new longest match for monitor prefix is the new
803 * route's prefix, move monitor to new route's prefix
804 */
805 if (prefix_match(new_vpn_node_p, &monitor->p)) {
806 /* detach */
807 if (mlast) {
808 mlast->next = monitor->next;
809 } else {
810 RFAPI_MONITOR_VPN_W_ALLOC(par) = monitor->next;
811 }
812
813
814 /* attach */
815 monitor->next = RFAPI_MONITOR_VPN(new_vpn_node);
816 RFAPI_MONITOR_VPN_W_ALLOC(new_vpn_node) = monitor;
817 monitor->node = new_vpn_node;
818
819 agg_lock_node(new_vpn_node); /* incr refcount */
820
821 monitor = mlast ? mlast->next : RFAPI_MONITOR_VPN(par);
822
823 RFAPI_CHECK_REFCOUNT(par, SAFI_MPLS_VPN, 1);
824 /* decr refcount after we're done with par as this might
825 * free it */
826 agg_unlock_node(par);
827
828 continue;
829 }
830 mlast = monitor;
831 monitor = monitor->next;
832 }
833
834 RFAPI_CHECK_REFCOUNT(new_vpn_node, SAFI_MPLS_VPN, 0);
835 }
836
837
838 static void rfapiBgpInfoChainFree(struct bgp_path_info *bpi)
839 {
840 struct bgp_path_info *next;
841
842 while (bpi) {
843
844 /*
845 * If there is a timer waiting to delete this bpi, cancel
846 * the timer and delete immediately
847 */
848 if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)
849 && bpi->extra->vnc.import.timer) {
850 struct rfapi_withdraw *wcb =
851 THREAD_ARG(bpi->extra->vnc.import.timer);
852
853 XFREE(MTYPE_RFAPI_WITHDRAW, wcb);
854 THREAD_OFF(bpi->extra->vnc.import.timer);
855 }
856
857 next = bpi->next;
858 bpi->next = NULL;
859 rfapiBgpInfoFree(bpi);
860 bpi = next;
861 }
862 }
863
864 static void rfapiImportTableFlush(struct rfapi_import_table *it)
865 {
866 afi_t afi;
867
868 /*
869 * Free ecommunity
870 */
871 ecommunity_free(&it->rt_import_list);
872 it->rt_import_list = NULL;
873
874 for (afi = AFI_IP; afi < AFI_MAX; ++afi) {
875
876 struct agg_node *rn;
877 struct agg_table *at;
878
879 at = it->imported_vpn[afi];
880 if (at) {
881 for (rn = agg_route_top(at); rn;
882 rn = agg_route_next(rn)) {
883 /*
884 * Each route_node has:
885 * aggregate: points to rfapi_it_extra with
886 * monitor chain(s)
887 * info: points to chain of bgp_path_info
888 */
889 /* free bgp_path_info and its children */
890 rfapiBgpInfoChainFree(rn->info);
891 rn->info = NULL;
892
893 rfapiMonitorExtraFlush(SAFI_MPLS_VPN, rn);
894 }
895 agg_table_finish(at);
896 }
897
898 if (at) {
899 at = it->imported_encap[afi];
900 for (rn = agg_route_top(at); rn;
901 rn = agg_route_next(rn)) {
902 /* free bgp_path_info and its children */
903 rfapiBgpInfoChainFree(rn->info);
904 rn->info = NULL;
905
906 rfapiMonitorExtraFlush(SAFI_ENCAP, rn);
907 }
908 agg_table_finish(at);
909 }
910 }
911 if (it->monitor_exterior_orphans) {
912 skiplist_free(it->monitor_exterior_orphans);
913 }
914 }
915
916 void rfapiImportTableRefDelByIt(struct bgp *bgp,
917 struct rfapi_import_table *it_target)
918 {
919 struct rfapi *h;
920 struct rfapi_import_table *it;
921 struct rfapi_import_table *prev = NULL;
922
923 assert(it_target);
924
925 h = bgp->rfapi;
926 assert(h);
927
928 for (it = h->imports; it; prev = it, it = it->next) {
929 if (it == it_target)
930 break;
931 }
932
933 assert(it);
934 assert(it->refcount);
935
936 it->refcount -= 1;
937
938 if (!it->refcount) {
939 if (prev) {
940 prev->next = it->next;
941 } else {
942 h->imports = it->next;
943 }
944 rfapiImportTableFlush(it);
945 XFREE(MTYPE_RFAPI_IMPORTTABLE, it);
946 }
947 }
948
949 #ifdef RFAPI_REQUIRE_ENCAP_BEEC
950 /*
951 * Look for magic BGP Encapsulation Extended Community value
952 * Format in RFC 5512 Sect. 4.5
953 */
954 static int rfapiEcommunitiesMatchBeec(struct ecommunity *ecom,
955 bgp_encap_types type)
956 {
957 int i;
958
959 if (!ecom)
960 return 0;
961
962 for (i = 0; i < (ecom->size * ECOMMUNITY_SIZE); i += ECOMMUNITY_SIZE) {
963
964 uint8_t *ep;
965
966 ep = ecom->val + i;
967
968 if (ep[0] == ECOMMUNITY_ENCODE_OPAQUE
969 && ep[1] == ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP
970 && ep[6] == ((type && 0xff00) >> 8)
971 && ep[7] == (type & 0xff)) {
972
973 return 1;
974 }
975 }
976 return 0;
977 }
978 #endif
979
980 int rfapiEcommunitiesIntersect(struct ecommunity *e1, struct ecommunity *e2)
981 {
982 uint32_t i, j;
983
984 if (!e1 || !e2)
985 return 0;
986
987 {
988 char *s1, *s2;
989 s1 = ecommunity_ecom2str(e1, ECOMMUNITY_FORMAT_DISPLAY, 0);
990 s2 = ecommunity_ecom2str(e2, ECOMMUNITY_FORMAT_DISPLAY, 0);
991 vnc_zlog_debug_verbose("%s: e1[%s], e2[%s]", __func__, s1, s2);
992 XFREE(MTYPE_ECOMMUNITY_STR, s1);
993 XFREE(MTYPE_ECOMMUNITY_STR, s2);
994 }
995
996 for (i = 0; i < e1->size; ++i) {
997 for (j = 0; j < e2->size; ++j) {
998 if (!memcmp(e1->val + (i * ECOMMUNITY_SIZE),
999 e2->val + (j * ECOMMUNITY_SIZE),
1000 ECOMMUNITY_SIZE)) {
1001
1002 return 1;
1003 }
1004 }
1005 }
1006 return 0;
1007 }
1008
1009 int rfapiEcommunityGetLNI(struct ecommunity *ecom, uint32_t *lni)
1010 {
1011 if (ecom) {
1012 uint32_t i;
1013
1014 for (i = 0; i < ecom->size; ++i) {
1015 uint8_t *p = ecom->val + (i * ECOMMUNITY_SIZE);
1016
1017 if ((*(p + 0) == 0x00) && (*(p + 1) == 0x02)) {
1018
1019 *lni = (*(p + 5) << 16) | (*(p + 6) << 8)
1020 | (*(p + 7));
1021 return 0;
1022 }
1023 }
1024 }
1025 return ENOENT;
1026 }
1027
1028 int rfapiEcommunityGetEthernetTag(struct ecommunity *ecom, uint16_t *tag_id)
1029 {
1030 struct bgp *bgp = bgp_get_default();
1031 *tag_id = 0; /* default to untagged */
1032 if (ecom) {
1033 uint32_t i;
1034
1035 for (i = 0; i < ecom->size; ++i) {
1036 as_t as = 0;
1037 int encode = 0;
1038 const uint8_t *p = ecom->val + (i * ECOMMUNITY_SIZE);
1039
1040 /* High-order octet of type. */
1041 encode = *p++;
1042
1043 if (*p++ == ECOMMUNITY_ROUTE_TARGET) {
1044 if (encode == ECOMMUNITY_ENCODE_AS4) {
1045 p = ptr_get_be32(p, &as);
1046 } else if (encode == ECOMMUNITY_ENCODE_AS) {
1047 as = (*p++ << 8);
1048 as |= (*p++);
1049 p += 2; /* skip next two, tag/vid
1050 always in lowest bytes */
1051 }
1052 if (as == bgp->as) {
1053 *tag_id = *p++ << 8;
1054 *tag_id |= (*p++);
1055 return 0;
1056 }
1057 }
1058 }
1059 }
1060 return ENOENT;
1061 }
1062
1063 static int rfapiVpnBiNhEqualsPt(struct bgp_path_info *bpi,
1064 struct rfapi_ip_addr *hpt)
1065 {
1066 uint8_t family;
1067
1068 if (!hpt || !bpi)
1069 return 0;
1070
1071 family = BGP_MP_NEXTHOP_FAMILY(bpi->attr->mp_nexthop_len);
1072
1073 if (hpt->addr_family != family)
1074 return 0;
1075
1076 switch (family) {
1077 case AF_INET:
1078 if (bpi->attr->mp_nexthop_global_in.s_addr
1079 != hpt->addr.v4.s_addr)
1080 return 0;
1081 break;
1082
1083 case AF_INET6:
1084 if (IPV6_ADDR_CMP(&bpi->attr->mp_nexthop_global, &hpt->addr.v6))
1085 return 0;
1086 break;
1087
1088 default:
1089 return 0;
1090 }
1091
1092 return 1;
1093 }
1094
1095
1096 /*
1097 * Compare 2 VPN BIs. Return true if they have the same VN and UN addresses
1098 */
1099 static int rfapiVpnBiSamePtUn(struct bgp_path_info *bpi1,
1100 struct bgp_path_info *bpi2)
1101 {
1102 struct prefix pfx_un1;
1103 struct prefix pfx_un2;
1104
1105 if (!bpi1 || !bpi2)
1106 return 0;
1107
1108 /*
1109 * VN address comparisons
1110 */
1111
1112 if (BGP_MP_NEXTHOP_FAMILY(bpi1->attr->mp_nexthop_len)
1113 != BGP_MP_NEXTHOP_FAMILY(bpi2->attr->mp_nexthop_len)) {
1114 return 0;
1115 }
1116
1117 switch (BGP_MP_NEXTHOP_FAMILY(bpi1->attr->mp_nexthop_len)) {
1118 case AF_INET:
1119 if (bpi1->attr->mp_nexthop_global_in.s_addr
1120 != bpi2->attr->mp_nexthop_global_in.s_addr)
1121 return 0;
1122 break;
1123
1124 case AF_INET6:
1125 if (IPV6_ADDR_CMP(&bpi1->attr->mp_nexthop_global,
1126 &bpi2->attr->mp_nexthop_global))
1127 return 0;
1128 break;
1129
1130 default:
1131 return 0;
1132 }
1133
1134 memset(&pfx_un1, 0, sizeof(pfx_un1));
1135 memset(&pfx_un2, 0, sizeof(pfx_un2));
1136
1137 /*
1138 * UN address comparisons
1139 */
1140 if (rfapiGetVncTunnelUnAddr(bpi1->attr, &pfx_un1)) {
1141 if (bpi1->extra) {
1142 pfx_un1.family = bpi1->extra->vnc.import.un_family;
1143 switch (bpi1->extra->vnc.import.un_family) {
1144 case AF_INET:
1145 pfx_un1.u.prefix4 =
1146 bpi1->extra->vnc.import.un.addr4;
1147 break;
1148 case AF_INET6:
1149 pfx_un1.u.prefix6 =
1150 bpi1->extra->vnc.import.un.addr6;
1151 break;
1152 default:
1153 pfx_un1.family = AF_UNSPEC;
1154 break;
1155 }
1156 }
1157 }
1158
1159 if (rfapiGetVncTunnelUnAddr(bpi2->attr, &pfx_un2)) {
1160 if (bpi2->extra) {
1161 pfx_un2.family = bpi2->extra->vnc.import.un_family;
1162 switch (bpi2->extra->vnc.import.un_family) {
1163 case AF_INET:
1164 pfx_un2.u.prefix4 =
1165 bpi2->extra->vnc.import.un.addr4;
1166 break;
1167 case AF_INET6:
1168 pfx_un2.u.prefix6 =
1169 bpi2->extra->vnc.import.un.addr6;
1170 break;
1171 default:
1172 pfx_un2.family = AF_UNSPEC;
1173 break;
1174 }
1175 }
1176 }
1177
1178 if (pfx_un1.family == AF_UNSPEC || pfx_un2.family == AF_UNSPEC)
1179 return 0;
1180
1181 if (pfx_un1.family != pfx_un2.family)
1182 return 0;
1183
1184 switch (pfx_un1.family) {
1185 case AF_INET:
1186 if (!IPV4_ADDR_SAME(&pfx_un1.u.prefix4, &pfx_un2.u.prefix4))
1187 return 0;
1188 break;
1189 case AF_INET6:
1190 if (!IPV6_ADDR_SAME(&pfx_un1.u.prefix6, &pfx_un2.u.prefix6))
1191 return 0;
1192 break;
1193 }
1194
1195
1196 return 1;
1197 }
1198
1199 uint8_t rfapiRfpCost(struct attr *attr)
1200 {
1201 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)) {
1202 if (attr->local_pref > 255) {
1203 return 0;
1204 }
1205 return 255 - attr->local_pref;
1206 }
1207
1208 return 255;
1209 }
1210
1211 /*------------------------------------------
1212 * rfapi_extract_l2o
1213 *
1214 * Find Layer 2 options in an option chain
1215 *
1216 * input:
1217 * pHop option chain
1218 *
1219 * output:
1220 * l2o layer 2 options extracted
1221 *
1222 * return value:
1223 * 0 OK
1224 * 1 no options found
1225 *
1226 --------------------------------------------*/
1227 int rfapi_extract_l2o(
1228 struct bgp_tea_options *pHop, /* chain of options */
1229 struct rfapi_l2address_option *l2o) /* return extracted value */
1230 {
1231 struct bgp_tea_options *p;
1232
1233 for (p = pHop; p; p = p->next) {
1234 if ((p->type == RFAPI_VN_OPTION_TYPE_L2ADDR)
1235 && (p->length >= 8)) {
1236
1237 char *v = p->value;
1238
1239 memcpy(&l2o->macaddr, v, 6);
1240
1241 l2o->label = ((v[6] << 12) & 0xff000)
1242 + ((v[7] << 4) & 0xff0)
1243 + ((v[8] >> 4) & 0xf);
1244
1245 l2o->local_nve_id = (uint8_t)v[10];
1246
1247 l2o->logical_net_id =
1248 (v[11] << 16) + (v[12] << 8) + (v[13] << 0);
1249
1250 return 0;
1251 }
1252 }
1253 return 1;
1254 }
1255
1256 static struct rfapi_next_hop_entry *
1257 rfapiRouteInfo2NextHopEntry(struct rfapi_ip_prefix *rprefix,
1258 struct bgp_path_info *bpi, /* route to encode */
1259 uint32_t lifetime, /* use this in nhe */
1260 struct agg_node *rn) /* req for L2 eth addr */
1261 {
1262 struct rfapi_next_hop_entry *new;
1263 int have_vnc_tunnel_un = 0;
1264 const struct prefix *p = agg_node_get_prefix(rn);
1265
1266 #ifdef DEBUG_ENCAP_MONITOR
1267 vnc_zlog_debug_verbose("%s: entry, bpi %p, rn %p", __func__, bpi, rn);
1268 #endif
1269
1270 new = XCALLOC(MTYPE_RFAPI_NEXTHOP, sizeof(struct rfapi_next_hop_entry));
1271
1272 new->prefix = *rprefix;
1273
1274 if (bpi->extra
1275 && decode_rd_type(bpi->extra->vnc.import.rd.val)
1276 == RD_TYPE_VNC_ETH) {
1277 /* ethernet */
1278
1279 struct rfapi_vn_option *vo;
1280
1281 vo = XCALLOC(MTYPE_RFAPI_VN_OPTION,
1282 sizeof(struct rfapi_vn_option));
1283
1284 vo->type = RFAPI_VN_OPTION_TYPE_L2ADDR;
1285
1286 memcpy(&vo->v.l2addr.macaddr, &p->u.prefix_eth.octet, ETH_ALEN);
1287 /* only low 3 bytes of this are significant */
1288 (void)rfapiEcommunityGetLNI(bgp_attr_get_ecommunity(bpi->attr),
1289 &vo->v.l2addr.logical_net_id);
1290 (void)rfapiEcommunityGetEthernetTag(
1291 bgp_attr_get_ecommunity(bpi->attr),
1292 &vo->v.l2addr.tag_id);
1293
1294 /* local_nve_id comes from lower byte of RD type */
1295 vo->v.l2addr.local_nve_id = bpi->extra->vnc.import.rd.val[1];
1296
1297 /* label comes from MP_REACH_NLRI label */
1298 vo->v.l2addr.label = decode_label(&bpi->extra->label[0]);
1299
1300 new->vn_options = vo;
1301
1302 /*
1303 * If there is an auxiliary prefix (i.e., host IP address),
1304 * use it as the nexthop prefix instead of the query prefix
1305 */
1306 if (bpi->extra->vnc.import.aux_prefix.family) {
1307 rfapiQprefix2Rprefix(&bpi->extra->vnc.import.aux_prefix,
1308 &new->prefix);
1309 }
1310 }
1311
1312 bgp_encap_types tun_type = BGP_ENCAP_TYPE_MPLS; /*Default*/
1313 new->prefix.cost = rfapiRfpCost(bpi->attr);
1314
1315 struct bgp_attr_encap_subtlv *pEncap;
1316
1317 switch (BGP_MP_NEXTHOP_FAMILY(bpi->attr->mp_nexthop_len)) {
1318 case AF_INET:
1319 new->vn_address.addr_family = AF_INET;
1320 new->vn_address.addr.v4 = bpi->attr->mp_nexthop_global_in;
1321 break;
1322
1323 case AF_INET6:
1324 new->vn_address.addr_family = AF_INET6;
1325 new->vn_address.addr.v6 = bpi->attr->mp_nexthop_global;
1326 break;
1327
1328 default:
1329 zlog_warn("%s: invalid vpn nexthop length: %d", __func__,
1330 bpi->attr->mp_nexthop_len);
1331 rfapi_free_next_hop_list(new);
1332 return NULL;
1333 }
1334
1335 for (pEncap = bgp_attr_get_vnc_subtlvs(bpi->attr); pEncap;
1336 pEncap = pEncap->next) {
1337 switch (pEncap->type) {
1338 case BGP_VNC_SUBTLV_TYPE_LIFETIME:
1339 /* use configured lifetime, not attr lifetime */
1340 break;
1341
1342 default:
1343 zlog_warn("%s: unknown VNC option type %d", __func__,
1344 pEncap->type);
1345
1346 break;
1347 }
1348 }
1349
1350 bgp_attr_extcom_tunnel_type(bpi->attr, &tun_type);
1351 if (tun_type == BGP_ENCAP_TYPE_MPLS) {
1352 struct prefix p;
1353 /* MPLS carries UN address in next hop */
1354 rfapiNexthop2Prefix(bpi->attr, &p);
1355 if (p.family != AF_UNSPEC) {
1356 rfapiQprefix2Raddr(&p, &new->un_address);
1357 have_vnc_tunnel_un = 1;
1358 }
1359 }
1360
1361 for (pEncap = bpi->attr->encap_subtlvs; pEncap; pEncap = pEncap->next) {
1362 switch (pEncap->type) {
1363 case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT:
1364 /*
1365 * Overrides ENCAP UN address, if any
1366 */
1367 switch (pEncap->length) {
1368
1369 case 8:
1370 new->un_address.addr_family = AF_INET;
1371 memcpy(&new->un_address.addr.v4, pEncap->value,
1372 4);
1373 have_vnc_tunnel_un = 1;
1374 break;
1375
1376 case 20:
1377 new->un_address.addr_family = AF_INET6;
1378 memcpy(&new->un_address.addr.v6, pEncap->value,
1379 16);
1380 have_vnc_tunnel_un = 1;
1381 break;
1382
1383 default:
1384 zlog_warn(
1385 "%s: invalid tunnel subtlv UN addr length (%d) for bpi %p",
1386 __func__, pEncap->length, bpi);
1387 }
1388 break;
1389
1390 default:
1391 zlog_warn("%s: unknown Encap Attribute option type %d",
1392 __func__, pEncap->type);
1393 break;
1394 }
1395 }
1396
1397 new->un_options = rfapi_encap_tlv_to_un_option(bpi->attr);
1398
1399 #ifdef DEBUG_ENCAP_MONITOR
1400 vnc_zlog_debug_verbose("%s: line %d: have_vnc_tunnel_un=%d", __func__,
1401 __LINE__, have_vnc_tunnel_un);
1402 #endif
1403
1404 if (!have_vnc_tunnel_un && bpi->extra) {
1405 /*
1406 * use cached UN address from ENCAP route
1407 */
1408 new->un_address.addr_family = bpi->extra->vnc.import.un_family;
1409 switch (new->un_address.addr_family) {
1410 case AF_INET:
1411 new->un_address.addr.v4 =
1412 bpi->extra->vnc.import.un.addr4;
1413 break;
1414 case AF_INET6:
1415 new->un_address.addr.v6 =
1416 bpi->extra->vnc.import.un.addr6;
1417 break;
1418 default:
1419 zlog_warn("%s: invalid UN addr family (%d) for bpi %p",
1420 __func__, new->un_address.addr_family, bpi);
1421 rfapi_free_next_hop_list(new);
1422 return NULL;
1423 }
1424 }
1425
1426 new->lifetime = lifetime;
1427 return new;
1428 }
1429
1430 int rfapiHasNonRemovedRoutes(struct agg_node *rn)
1431 {
1432 struct bgp_path_info *bpi;
1433
1434 for (bpi = rn->info; bpi; bpi = bpi->next) {
1435 struct prefix pfx;
1436
1437 if (!CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)
1438 && (bpi->extra && !rfapiGetUnAddrOfVpnBi(bpi, &pfx))) {
1439
1440 return 1;
1441 }
1442 }
1443 return 0;
1444 }
1445
1446 #ifdef DEBUG_IT_NODES
1447 /*
1448 * DEBUG FUNCTION
1449 */
1450 void rfapiDumpNode(struct agg_node *rn)
1451 {
1452 struct bgp_path_info *bpi;
1453
1454 vnc_zlog_debug_verbose("%s: rn=%p", __func__, rn);
1455 for (bpi = rn->info; bpi; bpi = bpi->next) {
1456 struct prefix pfx;
1457 int ctrc = rfapiGetUnAddrOfVpnBi(bpi, &pfx);
1458 int nr;
1459
1460 if (!CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)
1461 && (bpi->extra && !ctrc)) {
1462
1463 nr = 1;
1464 } else {
1465 nr = 0;
1466 }
1467
1468 vnc_zlog_debug_verbose(
1469 " bpi=%p, nr=%d, flags=0x%x, extra=%p, ctrc=%d", bpi,
1470 nr, bpi->flags, bpi->extra, ctrc);
1471 }
1472 }
1473 #endif
1474
1475 static int rfapiNhlAddNodeRoutes(
1476 struct agg_node *rn, /* in */
1477 struct rfapi_ip_prefix *rprefix, /* in */
1478 uint32_t lifetime, /* in */
1479 int removed, /* in */
1480 struct rfapi_next_hop_entry **head, /* in/out */
1481 struct rfapi_next_hop_entry **tail, /* in/out */
1482 struct rfapi_ip_addr *exclude_vnaddr, /* omit routes to same NVE */
1483 struct agg_node *rfd_rib_node, /* preload this NVE rib node */
1484 struct prefix *pfx_target_original) /* query target */
1485 {
1486 struct bgp_path_info *bpi;
1487 struct rfapi_next_hop_entry *new;
1488 struct prefix pfx_un;
1489 struct skiplist *seen_nexthops;
1490 int count = 0;
1491 const struct prefix *p = agg_node_get_prefix(rn);
1492 int is_l2 = (p->family == AF_ETHERNET);
1493
1494 if (rfd_rib_node) {
1495 struct agg_table *atable = agg_get_table(rfd_rib_node);
1496 struct rfapi_descriptor *rfd;
1497
1498 if (atable) {
1499 rfd = agg_get_table_info(atable);
1500
1501 if (rfapiRibFTDFilterRecentPrefix(rfd, rn,
1502 pfx_target_original))
1503 return 0;
1504 }
1505 }
1506
1507 seen_nexthops =
1508 skiplist_new(0, vnc_prefix_cmp, prefix_free_lists);
1509
1510 for (bpi = rn->info; bpi; bpi = bpi->next) {
1511
1512 struct prefix pfx_vn;
1513 struct prefix *newpfx;
1514
1515 if (removed && !CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) {
1516 #ifdef DEBUG_RETURNED_NHL
1517 vnc_zlog_debug_verbose(
1518 "%s: want holddown, this route not holddown, skip",
1519 __func__);
1520 #endif
1521 continue;
1522 }
1523 if (!removed && CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) {
1524 continue;
1525 }
1526
1527 if (!bpi->extra) {
1528 continue;
1529 }
1530
1531 /*
1532 * Check for excluded VN address
1533 */
1534 if (rfapiVpnBiNhEqualsPt(bpi, exclude_vnaddr))
1535 continue;
1536
1537 /*
1538 * Check for VN address (nexthop) copied already
1539 */
1540 if (is_l2) {
1541 /* L2 routes: semantic nexthop in aux_prefix; VN addr
1542 * ain't it */
1543 pfx_vn = bpi->extra->vnc.import.aux_prefix;
1544 } else {
1545 rfapiNexthop2Prefix(bpi->attr, &pfx_vn);
1546 }
1547 if (!skiplist_search(seen_nexthops, &pfx_vn, NULL)) {
1548 #ifdef DEBUG_RETURNED_NHL
1549 vnc_zlog_debug_verbose(
1550 "%s: already put VN/nexthop %pFX, skip",
1551 __func__, &pfx_vn);
1552 #endif
1553 continue;
1554 }
1555
1556 if (rfapiGetUnAddrOfVpnBi(bpi, &pfx_un)) {
1557 #ifdef DEBUG_ENCAP_MONITOR
1558 vnc_zlog_debug_verbose(
1559 "%s: failed to get UN address of this VPN bpi",
1560 __func__);
1561 #endif
1562 continue;
1563 }
1564
1565 newpfx = prefix_new();
1566 *newpfx = pfx_vn;
1567 skiplist_insert(seen_nexthops, newpfx, newpfx);
1568
1569 new = rfapiRouteInfo2NextHopEntry(rprefix, bpi, lifetime, rn);
1570 if (new) {
1571 if (rfapiRibPreloadBi(rfd_rib_node, &pfx_vn, &pfx_un,
1572 lifetime, bpi)) {
1573 /* duplicate filtered by RIB */
1574 rfapi_free_next_hop_list(new);
1575 new = NULL;
1576 }
1577 }
1578
1579 if (new) {
1580 if (*tail) {
1581 (*tail)->next = new;
1582 } else {
1583 *head = new;
1584 }
1585 *tail = new;
1586 ++count;
1587 }
1588 }
1589
1590 skiplist_free(seen_nexthops);
1591
1592 return count;
1593 }
1594
1595
1596 /*
1597 * Breadth-first
1598 *
1599 * omit_node is meant for the situation where we are adding a subtree
1600 * of a parent of some original requested node. The response already
1601 * contains the original requested node, and we don't want to duplicate
1602 * its routes in the list, so we skip it if the right or left node
1603 * matches (of course, we still travel down its child subtrees).
1604 */
1605 static int rfapiNhlAddSubtree(
1606 struct agg_node *rn, /* in */
1607 uint32_t lifetime, /* in */
1608 struct rfapi_next_hop_entry **head, /* in/out */
1609 struct rfapi_next_hop_entry **tail, /* in/out */
1610 struct agg_node *omit_node, /* in */
1611 struct rfapi_ip_addr *exclude_vnaddr, /* omit routes to same NVE */
1612 struct agg_table *rfd_rib_table, /* preload here */
1613 struct prefix *pfx_target_original) /* query target */
1614 {
1615 struct rfapi_ip_prefix rprefix;
1616 int rcount = 0;
1617
1618 /* FIXME: need to find a better way here to work without sticking our
1619 * hands in node->link */
1620 if (agg_node_left(rn) && agg_node_left(rn) != omit_node) {
1621 if (agg_node_left(rn)->info) {
1622 const struct prefix *p =
1623 agg_node_get_prefix(agg_node_left(rn));
1624 int count = 0;
1625 struct agg_node *rib_rn = NULL;
1626
1627 rfapiQprefix2Rprefix(p, &rprefix);
1628 if (rfd_rib_table)
1629 rib_rn = agg_node_get(rfd_rib_table, p);
1630
1631 count = rfapiNhlAddNodeRoutes(
1632 agg_node_left(rn), &rprefix, lifetime, 0, head,
1633 tail, exclude_vnaddr, rib_rn,
1634 pfx_target_original);
1635 if (!count) {
1636 count = rfapiNhlAddNodeRoutes(
1637 agg_node_left(rn), &rprefix, lifetime,
1638 1, head, tail, exclude_vnaddr, rib_rn,
1639 pfx_target_original);
1640 }
1641 rcount += count;
1642 if (rib_rn)
1643 agg_unlock_node(rib_rn);
1644 }
1645 }
1646
1647 if (agg_node_right(rn) && agg_node_right(rn) != omit_node) {
1648 if (agg_node_right(rn)->info) {
1649 const struct prefix *p =
1650 agg_node_get_prefix(agg_node_right(rn));
1651 int count = 0;
1652 struct agg_node *rib_rn = NULL;
1653
1654 rfapiQprefix2Rprefix(p, &rprefix);
1655 if (rfd_rib_table)
1656 rib_rn = agg_node_get(rfd_rib_table, p);
1657
1658 count = rfapiNhlAddNodeRoutes(
1659 agg_node_right(rn), &rprefix, lifetime, 0, head,
1660 tail, exclude_vnaddr, rib_rn,
1661 pfx_target_original);
1662 if (!count) {
1663 count = rfapiNhlAddNodeRoutes(
1664 agg_node_right(rn), &rprefix, lifetime,
1665 1, head, tail, exclude_vnaddr, rib_rn,
1666 pfx_target_original);
1667 }
1668 rcount += count;
1669 if (rib_rn)
1670 agg_unlock_node(rib_rn);
1671 }
1672 }
1673
1674 if (agg_node_left(rn)) {
1675 rcount += rfapiNhlAddSubtree(
1676 agg_node_left(rn), lifetime, head, tail, omit_node,
1677 exclude_vnaddr, rfd_rib_table, pfx_target_original);
1678 }
1679 if (agg_node_right(rn)) {
1680 rcount += rfapiNhlAddSubtree(
1681 agg_node_right(rn), lifetime, head, tail, omit_node,
1682 exclude_vnaddr, rfd_rib_table, pfx_target_original);
1683 }
1684
1685 return rcount;
1686 }
1687
1688 /*
1689 * Implementation of ROUTE_LIST(node) from RFAPI-Import-Event-Handling.txt
1690 *
1691 * Construct an rfapi nexthop list based on the routes attached to
1692 * the specified node.
1693 *
1694 * If there are any routes that do NOT have BGP_PATH_REMOVED set,
1695 * return those only. If there are ONLY routes with BGP_PATH_REMOVED,
1696 * then return those, and also include all the non-removed routes from the
1697 * next less-specific node (i.e., this node's parent) at the end.
1698 */
1699 struct rfapi_next_hop_entry *rfapiRouteNode2NextHopList(
1700 struct agg_node *rn, uint32_t lifetime, /* put into nexthop entries */
1701 struct rfapi_ip_addr *exclude_vnaddr, /* omit routes to same NVE */
1702 struct agg_table *rfd_rib_table, /* preload here */
1703 struct prefix *pfx_target_original) /* query target */
1704 {
1705 struct rfapi_ip_prefix rprefix;
1706 struct rfapi_next_hop_entry *answer = NULL;
1707 struct rfapi_next_hop_entry *last = NULL;
1708 struct agg_node *parent;
1709 const struct prefix *p = agg_node_get_prefix(rn);
1710 int count = 0;
1711 struct agg_node *rib_rn;
1712
1713 #ifdef DEBUG_RETURNED_NHL
1714 vnc_zlog_debug_verbose("%s: called with node pfx=%rRN", __func__, rn);
1715 rfapiDebugBacktrace();
1716 #endif
1717
1718 rfapiQprefix2Rprefix(p, &rprefix);
1719
1720 rib_rn = rfd_rib_table ? agg_node_get(rfd_rib_table, p) : NULL;
1721
1722 /*
1723 * Add non-withdrawn routes at this node
1724 */
1725 count = rfapiNhlAddNodeRoutes(rn, &rprefix, lifetime, 0, &answer, &last,
1726 exclude_vnaddr, rib_rn,
1727 pfx_target_original);
1728
1729 /*
1730 * If the list has at least one entry, it's finished
1731 */
1732 if (count) {
1733 count += rfapiNhlAddSubtree(rn, lifetime, &answer, &last, NULL,
1734 exclude_vnaddr, rfd_rib_table,
1735 pfx_target_original);
1736 vnc_zlog_debug_verbose("%s: %d nexthops, answer=%p", __func__,
1737 count, answer);
1738 #ifdef DEBUG_RETURNED_NHL
1739 rfapiPrintNhl(NULL, answer);
1740 #endif
1741 if (rib_rn)
1742 agg_unlock_node(rib_rn);
1743 return answer;
1744 }
1745
1746 /*
1747 * Add withdrawn routes at this node
1748 */
1749 count = rfapiNhlAddNodeRoutes(rn, &rprefix, lifetime, 1, &answer, &last,
1750 exclude_vnaddr, rib_rn,
1751 pfx_target_original);
1752 if (rib_rn)
1753 agg_unlock_node(rib_rn);
1754
1755 // rfapiPrintNhl(NULL, answer);
1756
1757 /*
1758 * walk up the tree until we find a node with non-deleted
1759 * routes, then add them
1760 */
1761 for (parent = agg_node_parent(rn); parent;
1762 parent = agg_node_parent(parent)) {
1763 if (rfapiHasNonRemovedRoutes(parent)) {
1764 break;
1765 }
1766 }
1767
1768 /*
1769 * Add non-withdrawn routes from less-specific prefix
1770 */
1771 if (parent) {
1772 const struct prefix *p = agg_node_get_prefix(parent);
1773
1774 rib_rn = rfd_rib_table ? agg_node_get(rfd_rib_table, p) : NULL;
1775 rfapiQprefix2Rprefix(p, &rprefix);
1776 count += rfapiNhlAddNodeRoutes(parent, &rprefix, lifetime, 0,
1777 &answer, &last, exclude_vnaddr,
1778 rib_rn, pfx_target_original);
1779 count += rfapiNhlAddSubtree(parent, lifetime, &answer, &last,
1780 rn, exclude_vnaddr, rfd_rib_table,
1781 pfx_target_original);
1782 if (rib_rn)
1783 agg_unlock_node(rib_rn);
1784 } else {
1785 /*
1786 * There is no parent with non-removed routes. Still need to
1787 * add subtree of original node if it contributed routes to the
1788 * answer.
1789 */
1790 if (count)
1791 count += rfapiNhlAddSubtree(rn, lifetime, &answer,
1792 &last, rn, exclude_vnaddr,
1793 rfd_rib_table,
1794 pfx_target_original);
1795 }
1796
1797 vnc_zlog_debug_verbose("%s: %d nexthops, answer=%p", __func__, count,
1798 answer);
1799 #ifdef DEBUG_RETURNED_NHL
1800 rfapiPrintNhl(NULL, answer);
1801 #endif
1802 return answer;
1803 }
1804
1805 /*
1806 * Construct nexthop list of all routes in table
1807 */
1808 struct rfapi_next_hop_entry *rfapiRouteTable2NextHopList(
1809 struct agg_table *rt, uint32_t lifetime, /* put into nexthop entries */
1810 struct rfapi_ip_addr *exclude_vnaddr, /* omit routes to same NVE */
1811 struct agg_table *rfd_rib_table, /* preload this NVE rib table */
1812 struct prefix *pfx_target_original) /* query target */
1813 {
1814 struct agg_node *rn;
1815 struct rfapi_next_hop_entry *biglist = NULL;
1816 struct rfapi_next_hop_entry *nhl;
1817 struct rfapi_next_hop_entry *tail = NULL;
1818 int count = 0;
1819
1820 for (rn = agg_route_top(rt); rn; rn = agg_route_next(rn)) {
1821
1822 nhl = rfapiRouteNode2NextHopList(rn, lifetime, exclude_vnaddr,
1823 rfd_rib_table,
1824 pfx_target_original);
1825 if (!tail) {
1826 tail = biglist = nhl;
1827 if (tail)
1828 count = 1;
1829 } else {
1830 tail->next = nhl;
1831 }
1832 if (tail) {
1833 while (tail->next) {
1834 ++count;
1835 tail = tail->next;
1836 }
1837 }
1838 }
1839
1840 vnc_zlog_debug_verbose("%s: returning %d routes", __func__, count);
1841 return biglist;
1842 }
1843
1844 struct rfapi_next_hop_entry *rfapiEthRouteNode2NextHopList(
1845 struct agg_node *rn, struct rfapi_ip_prefix *rprefix,
1846 uint32_t lifetime, /* put into nexthop entries */
1847 struct rfapi_ip_addr *exclude_vnaddr, /* omit routes to same NVE */
1848 struct agg_table *rfd_rib_table, /* preload NVE rib table */
1849 struct prefix *pfx_target_original) /* query target */
1850 {
1851 int count = 0;
1852 struct rfapi_next_hop_entry *answer = NULL;
1853 struct rfapi_next_hop_entry *last = NULL;
1854 struct agg_node *rib_rn;
1855
1856 rib_rn = rfd_rib_table
1857 ? agg_node_get(rfd_rib_table, agg_node_get_prefix(rn))
1858 : NULL;
1859
1860 count = rfapiNhlAddNodeRoutes(rn, rprefix, lifetime, 0, &answer, &last,
1861 NULL, rib_rn, pfx_target_original);
1862
1863 #ifdef DEBUG_ENCAP_MONITOR
1864 vnc_zlog_debug_verbose("%s: node %p: %d non-holddown routes", __func__,
1865 rn, count);
1866 #endif
1867
1868 if (!count) {
1869 count = rfapiNhlAddNodeRoutes(rn, rprefix, lifetime, 1, &answer,
1870 &last, exclude_vnaddr, rib_rn,
1871 pfx_target_original);
1872 vnc_zlog_debug_verbose("%s: node %p: %d holddown routes",
1873 __func__, rn, count);
1874 }
1875
1876 if (rib_rn)
1877 agg_unlock_node(rib_rn);
1878
1879 #ifdef DEBUG_RETURNED_NHL
1880 rfapiPrintNhl(NULL, answer);
1881 #endif
1882
1883 return answer;
1884 }
1885
1886
1887 /*
1888 * Construct nexthop list of all routes in table
1889 */
1890 struct rfapi_next_hop_entry *rfapiEthRouteTable2NextHopList(
1891 uint32_t logical_net_id, struct rfapi_ip_prefix *rprefix,
1892 uint32_t lifetime, /* put into nexthop entries */
1893 struct rfapi_ip_addr *exclude_vnaddr, /* omit routes to same NVE */
1894 struct agg_table *rfd_rib_table, /* preload NVE rib node */
1895 struct prefix *pfx_target_original) /* query target */
1896 {
1897 struct rfapi_import_table *it;
1898 struct bgp *bgp = bgp_get_default();
1899 struct agg_table *rt;
1900 struct agg_node *rn;
1901 struct rfapi_next_hop_entry *biglist = NULL;
1902 struct rfapi_next_hop_entry *nhl;
1903 struct rfapi_next_hop_entry *tail = NULL;
1904 int count = 0;
1905
1906
1907 it = rfapiMacImportTableGet(bgp, logical_net_id);
1908 rt = it->imported_vpn[AFI_L2VPN];
1909
1910 for (rn = agg_route_top(rt); rn; rn = agg_route_next(rn)) {
1911
1912 nhl = rfapiEthRouteNode2NextHopList(
1913 rn, rprefix, lifetime, exclude_vnaddr, rfd_rib_table,
1914 pfx_target_original);
1915 if (!tail) {
1916 tail = biglist = nhl;
1917 if (tail)
1918 count = 1;
1919 } else {
1920 tail->next = nhl;
1921 }
1922 if (tail) {
1923 while (tail->next) {
1924 ++count;
1925 tail = tail->next;
1926 }
1927 }
1928 }
1929
1930 vnc_zlog_debug_verbose("%s: returning %d routes", __func__, count);
1931 return biglist;
1932 }
1933
1934 /*
1935 * Insert a new bpi to the imported route table node,
1936 * keeping the list of BPIs sorted best route first
1937 */
1938 static void rfapiBgpInfoAttachSorted(struct agg_node *rn,
1939 struct bgp_path_info *info_new, afi_t afi,
1940 safi_t safi)
1941 {
1942 struct bgp *bgp;
1943 struct bgp_path_info *prev;
1944 struct bgp_path_info *next;
1945 char pfx_buf[PREFIX2STR_BUFFER];
1946
1947
1948 bgp = bgp_get_default(); /* assume 1 instance for now */
1949
1950 if (VNC_DEBUG(IMPORT_BI_ATTACH)) {
1951 vnc_zlog_debug_verbose("%s: info_new->peer=%p", __func__,
1952 info_new->peer);
1953 vnc_zlog_debug_verbose("%s: info_new->peer->su_remote=%p",
1954 __func__, info_new->peer->su_remote);
1955 }
1956
1957 for (prev = NULL, next = rn->info; next;
1958 prev = next, next = next->next) {
1959 enum bgp_path_selection_reason reason;
1960
1961 if (!bgp
1962 || (!CHECK_FLAG(info_new->flags, BGP_PATH_REMOVED)
1963 && CHECK_FLAG(next->flags, BGP_PATH_REMOVED))
1964 || bgp_path_info_cmp_compatible(bgp, info_new, next,
1965 pfx_buf, afi, safi,
1966 &reason)
1967 == -1) { /* -1 if 1st is better */
1968 break;
1969 }
1970 }
1971 vnc_zlog_debug_verbose("%s: prev=%p, next=%p", __func__, prev, next);
1972 if (prev) {
1973 prev->next = info_new;
1974 } else {
1975 rn->info = info_new;
1976 }
1977 info_new->prev = prev;
1978 info_new->next = next;
1979 if (next)
1980 next->prev = info_new;
1981 bgp_attr_intern(info_new->attr);
1982 }
1983
1984 static void rfapiBgpInfoDetach(struct agg_node *rn, struct bgp_path_info *bpi)
1985 {
1986 /*
1987 * Remove the route (doubly-linked)
1988 */
1989 // bgp_attr_unintern (&bpi->attr);
1990 if (bpi->next)
1991 bpi->next->prev = bpi->prev;
1992 if (bpi->prev)
1993 bpi->prev->next = bpi->next;
1994 else
1995 rn->info = bpi->next;
1996 }
1997
1998 /*
1999 * For L3-indexed import tables
2000 */
2001 static int rfapi_bi_peer_rd_cmp(const void *b1, const void *b2)
2002 {
2003 const struct bgp_path_info *bpi1 = b1;
2004 const struct bgp_path_info *bpi2 = b2;
2005
2006 /*
2007 * Compare peers
2008 */
2009 if (bpi1->peer < bpi2->peer)
2010 return -1;
2011 if (bpi1->peer > bpi2->peer)
2012 return 1;
2013
2014 /*
2015 * compare RDs
2016 */
2017 return vnc_prefix_cmp(
2018 (const struct prefix *)&bpi1->extra->vnc.import.rd,
2019 (const struct prefix *)&bpi2->extra->vnc.import.rd);
2020 }
2021
2022 /*
2023 * For L2-indexed import tables
2024 * The BPIs in these tables should ALWAYS have an aux_prefix set because
2025 * they arrive via IPv4 or IPv6 advertisements.
2026 */
2027 static int rfapi_bi_peer_rd_aux_cmp(const void *b1, const void *b2)
2028 {
2029 const struct bgp_path_info *bpi1 = b1;
2030 const struct bgp_path_info *bpi2 = b2;
2031 int rc;
2032
2033 /*
2034 * Compare peers
2035 */
2036 if (bpi1->peer < bpi2->peer)
2037 return -1;
2038 if (bpi1->peer > bpi2->peer)
2039 return 1;
2040
2041 /*
2042 * compare RDs
2043 */
2044 rc = vnc_prefix_cmp((struct prefix *)&bpi1->extra->vnc.import.rd,
2045 (struct prefix *)&bpi2->extra->vnc.import.rd);
2046 if (rc) {
2047 return rc;
2048 }
2049
2050 /*
2051 * L2 import tables can have multiple entries with the
2052 * same MAC address, same RD, but different L3 addresses.
2053 *
2054 * Use presence of aux_prefix with AF=ethernet and prefixlen=1
2055 * as magic value to signify explicit wildcarding of the aux_prefix.
2056 * This magic value will not appear in bona fide bpi entries in
2057 * the import table, but is allowed in the "fake" bpi used to
2058 * probe the table when searching. (We have to test both b1 and b2
2059 * because there is no guarantee of the order the test key and
2060 * the real key will be passed)
2061 */
2062 if ((bpi1->extra->vnc.import.aux_prefix.family == AF_ETHERNET
2063 && (bpi1->extra->vnc.import.aux_prefix.prefixlen == 1))
2064 || (bpi2->extra->vnc.import.aux_prefix.family == AF_ETHERNET
2065 && (bpi2->extra->vnc.import.aux_prefix.prefixlen == 1))) {
2066
2067 /*
2068 * wildcard aux address specified
2069 */
2070 return 0;
2071 }
2072
2073 return vnc_prefix_cmp(&bpi1->extra->vnc.import.aux_prefix,
2074 &bpi2->extra->vnc.import.aux_prefix);
2075 }
2076
2077
2078 /*
2079 * Index on RD and Peer
2080 */
2081 static void rfapiItBiIndexAdd(struct agg_node *rn, /* Import table VPN node */
2082 struct bgp_path_info *bpi) /* new BPI */
2083 {
2084 struct skiplist *sl;
2085 const struct prefix *p;
2086
2087 assert(rn);
2088 assert(bpi);
2089 assert(bpi->extra);
2090
2091 vnc_zlog_debug_verbose("%s: bpi %p, peer %p, rd %pRDP", __func__, bpi,
2092 bpi->peer, &bpi->extra->vnc.import.rd);
2093
2094 sl = RFAPI_RDINDEX_W_ALLOC(rn);
2095 if (!sl) {
2096 p = agg_node_get_prefix(rn);
2097 if (AF_ETHERNET == p->family) {
2098 sl = skiplist_new(0, rfapi_bi_peer_rd_aux_cmp, NULL);
2099 } else {
2100 sl = skiplist_new(0, rfapi_bi_peer_rd_cmp, NULL);
2101 }
2102 RFAPI_IT_EXTRA_GET(rn)->u.vpn.idx_rd = sl;
2103 agg_lock_node(rn); /* for skiplist */
2104 }
2105 assert(!skiplist_insert(sl, (void *)bpi, (void *)bpi));
2106 agg_lock_node(rn); /* for skiplist entry */
2107
2108 /* NB: BPIs in import tables are not refcounted */
2109 }
2110
2111 static void rfapiItBiIndexDump(struct agg_node *rn)
2112 {
2113 struct skiplist *sl;
2114 void *cursor = NULL;
2115 struct bgp_path_info *k;
2116 struct bgp_path_info *v;
2117 int rc;
2118
2119 sl = RFAPI_RDINDEX(rn);
2120 if (!sl)
2121 return;
2122
2123 for (rc = skiplist_next(sl, (void **)&k, (void **)&v, &cursor); !rc;
2124 rc = skiplist_next(sl, (void **)&k, (void **)&v, &cursor)) {
2125
2126 char buf[RD_ADDRSTRLEN];
2127 char buf_aux_pfx[PREFIX_STRLEN];
2128
2129 prefix_rd2str(
2130 &k->extra->vnc.import.rd, buf, sizeof(buf),
2131 bgp_get_asnotation(k->peer ? k->peer->bgp : NULL));
2132 if (k->extra->vnc.import.aux_prefix.family) {
2133 prefix2str(&k->extra->vnc.import.aux_prefix,
2134 buf_aux_pfx, sizeof(buf_aux_pfx));
2135 } else
2136 strlcpy(buf_aux_pfx, "(none)", sizeof(buf_aux_pfx));
2137
2138 vnc_zlog_debug_verbose("bpi %p, peer %p, rd %s, aux_prefix %s",
2139 k, k->peer, buf, buf_aux_pfx);
2140 }
2141 }
2142
2143 static struct bgp_path_info *rfapiItBiIndexSearch(
2144 struct agg_node *rn, /* Import table VPN node */
2145 struct prefix_rd *prd, struct peer *peer,
2146 const struct prefix *aux_prefix) /* optional L3 addr for L2 ITs */
2147 {
2148 struct skiplist *sl;
2149 int rc;
2150 struct bgp_path_info bpi_fake = {0};
2151 struct bgp_path_info_extra bpi_extra = {0};
2152 struct bgp_path_info *bpi_result;
2153
2154 sl = RFAPI_RDINDEX(rn);
2155 if (!sl)
2156 return NULL;
2157
2158 #ifdef DEBUG_BI_SEARCH
2159 {
2160 char buf_aux_pfx[PREFIX_STRLEN];
2161
2162 if (aux_prefix) {
2163 prefix2str(aux_prefix, buf_aux_pfx,
2164 sizeof(buf_aux_pfx));
2165 } else
2166 strlcpy(buf_aux_pfx, "(nil)", sizeof(buf_aux_pfx));
2167
2168 vnc_zlog_debug_verbose(
2169 "%s want prd=%pRDP, peer=%p, aux_prefix=%s", __func__,
2170 prd, peer, buf_aux_pfx);
2171 rfapiItBiIndexDump(rn);
2172 }
2173 #endif
2174
2175 /* threshold is a WAG */
2176 if (sl->count < 3) {
2177 #ifdef DEBUG_BI_SEARCH
2178 vnc_zlog_debug_verbose("%s: short list algorithm", __func__);
2179 #endif
2180 /* if short list, linear search might be faster */
2181 for (bpi_result = rn->info; bpi_result;
2182 bpi_result = bpi_result->next) {
2183 #ifdef DEBUG_BI_SEARCH
2184 vnc_zlog_debug_verbose(
2185 "%s: bpi has prd=%pRDP, peer=%p", __func__,
2186 &bpi_result->extra->vnc.import.rd,
2187 bpi_result->peer);
2188 #endif
2189 if (peer == bpi_result->peer
2190 && !prefix_cmp((struct prefix *)&bpi_result->extra
2191 ->vnc.import.rd,
2192 (struct prefix *)prd)) {
2193
2194 #ifdef DEBUG_BI_SEARCH
2195 vnc_zlog_debug_verbose(
2196 "%s: peer and RD same, doing aux_prefix check",
2197 __func__);
2198 #endif
2199 if (!aux_prefix
2200 || !prefix_cmp(
2201 aux_prefix,
2202 &bpi_result->extra->vnc.import
2203 .aux_prefix)) {
2204
2205 #ifdef DEBUG_BI_SEARCH
2206 vnc_zlog_debug_verbose("%s: match",
2207 __func__);
2208 #endif
2209 break;
2210 }
2211 }
2212 }
2213 return bpi_result;
2214 }
2215
2216 bpi_fake.peer = peer;
2217 bpi_fake.extra = &bpi_extra;
2218 bpi_fake.extra->vnc.import.rd = *prd;
2219 if (aux_prefix) {
2220 bpi_fake.extra->vnc.import.aux_prefix = *aux_prefix;
2221 } else {
2222 /* wildcard */
2223 bpi_fake.extra->vnc.import.aux_prefix.family = AF_ETHERNET;
2224 bpi_fake.extra->vnc.import.aux_prefix.prefixlen = 1;
2225 }
2226
2227 rc = skiplist_search(sl, (void *)&bpi_fake, (void *)&bpi_result);
2228
2229 if (rc) {
2230 #ifdef DEBUG_BI_SEARCH
2231 vnc_zlog_debug_verbose("%s: no match", __func__);
2232 #endif
2233 return NULL;
2234 }
2235
2236 #ifdef DEBUG_BI_SEARCH
2237 vnc_zlog_debug_verbose("%s: matched bpi=%p", __func__, bpi_result);
2238 #endif
2239
2240 return bpi_result;
2241 }
2242
2243 static void rfapiItBiIndexDel(struct agg_node *rn, /* Import table VPN node */
2244 struct bgp_path_info *bpi) /* old BPI */
2245 {
2246 struct skiplist *sl;
2247 int rc;
2248
2249 vnc_zlog_debug_verbose("%s: bpi %p, peer %p, rd %pRDP", __func__, bpi,
2250 bpi->peer, &bpi->extra->vnc.import.rd);
2251
2252 sl = RFAPI_RDINDEX(rn);
2253 assert(sl);
2254
2255 rc = skiplist_delete(sl, (void *)(bpi), (void *)bpi);
2256 if (rc) {
2257 rfapiItBiIndexDump(rn);
2258 }
2259 assert(!rc);
2260
2261 agg_unlock_node(rn); /* for skiplist entry */
2262
2263 /* NB: BPIs in import tables are not refcounted */
2264 }
2265
2266 /*
2267 * Add a backreference at the ENCAP node to the VPN route that
2268 * refers to it
2269 */
2270 static void
2271 rfapiMonitorEncapAdd(struct rfapi_import_table *import_table,
2272 struct prefix *p, /* VN address */
2273 struct agg_node *vpn_rn, /* VPN node */
2274 struct bgp_path_info *vpn_bpi) /* VPN bpi/route */
2275 {
2276 afi_t afi = family2afi(p->family);
2277 struct agg_node *rn;
2278 struct rfapi_monitor_encap *m;
2279
2280 assert(afi);
2281 rn = agg_node_get(import_table->imported_encap[afi], p); /* locks rn */
2282 assert(rn);
2283
2284 m = XCALLOC(MTYPE_RFAPI_MONITOR_ENCAP,
2285 sizeof(struct rfapi_monitor_encap));
2286
2287 m->node = vpn_rn;
2288 m->bpi = vpn_bpi;
2289 m->rn = rn;
2290
2291 /* insert to encap node's list */
2292 m->next = RFAPI_MONITOR_ENCAP(rn);
2293 if (m->next)
2294 m->next->prev = m;
2295 RFAPI_MONITOR_ENCAP_W_ALLOC(rn) = m;
2296
2297 /* for easy lookup when deleting vpn route */
2298 vpn_bpi->extra->vnc.import.hme = m;
2299
2300 vnc_zlog_debug_verbose(
2301 "%s: it=%p, vpn_bpi=%p, afi=%d, encap rn=%p, setting vpn_bpi->extra->vnc.import.hme=%p",
2302 __func__, import_table, vpn_bpi, afi, rn, m);
2303
2304 RFAPI_CHECK_REFCOUNT(rn, SAFI_ENCAP, 0);
2305 bgp_attr_intern(vpn_bpi->attr);
2306 }
2307
2308 static void rfapiMonitorEncapDelete(struct bgp_path_info *vpn_bpi)
2309 {
2310 /*
2311 * Remove encap monitor
2312 */
2313 vnc_zlog_debug_verbose("%s: vpn_bpi=%p", __func__, vpn_bpi);
2314 if (vpn_bpi->extra) {
2315 struct rfapi_monitor_encap *hme =
2316 vpn_bpi->extra->vnc.import.hme;
2317
2318 if (hme) {
2319
2320 vnc_zlog_debug_verbose("%s: hme=%p", __func__, hme);
2321
2322 /* Refcount checking takes too long here */
2323 // RFAPI_CHECK_REFCOUNT(hme->rn, SAFI_ENCAP, 0);
2324 if (hme->next)
2325 hme->next->prev = hme->prev;
2326 if (hme->prev)
2327 hme->prev->next = hme->next;
2328 else
2329 RFAPI_MONITOR_ENCAP_W_ALLOC(hme->rn) =
2330 hme->next;
2331 /* Refcount checking takes too long here */
2332 // RFAPI_CHECK_REFCOUNT(hme->rn, SAFI_ENCAP, 1);
2333
2334 /* see if the struct rfapi_it_extra is empty and can be
2335 * freed */
2336 rfapiMonitorExtraPrune(SAFI_ENCAP, hme->rn);
2337
2338 agg_unlock_node(hme->rn); /* decr ref count */
2339 XFREE(MTYPE_RFAPI_MONITOR_ENCAP, hme);
2340 vpn_bpi->extra->vnc.import.hme = NULL;
2341 }
2342 }
2343 }
2344
2345 /*
2346 * Timer callback for withdraw
2347 */
2348 static void rfapiWithdrawTimerVPN(struct thread *t)
2349 {
2350 struct rfapi_withdraw *wcb = THREAD_ARG(t);
2351 struct bgp_path_info *bpi = wcb->info;
2352 struct bgp *bgp = bgp_get_default();
2353 const struct prefix *p;
2354 struct rfapi_monitor_vpn *moved;
2355 afi_t afi;
2356 bool early_exit = false;
2357
2358 if (bgp == NULL) {
2359 vnc_zlog_debug_verbose(
2360 "%s: NULL BGP pointer, assume shutdown race condition!!!",
2361 __func__);
2362 early_exit = true;
2363 }
2364 if (bgp && CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS)) {
2365 vnc_zlog_debug_verbose(
2366 "%s: BGP delete in progress, assume shutdown race condition!!!",
2367 __func__);
2368 early_exit = true;
2369 }
2370
2371 /* This callback is responsible for the withdraw object's memory */
2372 if (early_exit) {
2373 XFREE(MTYPE_RFAPI_WITHDRAW, wcb);
2374 return;
2375 }
2376
2377 assert(wcb->node);
2378 assert(bpi);
2379 assert(wcb->import_table);
2380 assert(bpi->extra);
2381
2382 RFAPI_CHECK_REFCOUNT(wcb->node, SAFI_MPLS_VPN, wcb->lockoffset);
2383
2384 vnc_zlog_debug_verbose("%s: removing bpi %p at prefix %pRN", __func__,
2385 bpi, wcb->node);
2386
2387 /*
2388 * Remove the route (doubly-linked)
2389 */
2390 if (CHECK_FLAG(bpi->flags, BGP_PATH_VALID)
2391 && VALID_INTERIOR_TYPE(bpi->type))
2392 RFAPI_MONITOR_EXTERIOR(wcb->node)->valid_interior_count--;
2393
2394 p = agg_node_get_prefix(wcb->node);
2395 afi = family2afi(p->family);
2396 wcb->import_table->holddown_count[afi] -= 1; /* keep count consistent */
2397 rfapiItBiIndexDel(wcb->node, bpi);
2398 rfapiBgpInfoDetach(wcb->node, bpi); /* with removed bpi */
2399
2400 vnc_import_bgp_exterior_del_route_interior(bgp, wcb->import_table,
2401 wcb->node, bpi);
2402
2403
2404 /*
2405 * If VNC is configured to send response remove messages, AND
2406 * if the removed route had a UN address, do response removal
2407 * processing.
2408 */
2409 if (!(bgp->rfapi_cfg->flags
2410 & BGP_VNC_CONFIG_RESPONSE_REMOVAL_DISABLE)) {
2411
2412 int has_valid_duplicate = 0;
2413 struct bgp_path_info *bpii;
2414
2415 /*
2416 * First check if there are any OTHER routes at this node
2417 * that have the same nexthop and a valid UN address. If
2418 * there are (e.g., from other peers), then the route isn't
2419 * really gone, so skip sending a response removal message.
2420 */
2421 for (bpii = wcb->node->info; bpii; bpii = bpii->next) {
2422 if (rfapiVpnBiSamePtUn(bpi, bpii)) {
2423 has_valid_duplicate = 1;
2424 break;
2425 }
2426 }
2427
2428 vnc_zlog_debug_verbose("%s: has_valid_duplicate=%d", __func__,
2429 has_valid_duplicate);
2430
2431 if (!has_valid_duplicate) {
2432 rfapiRibPendingDeleteRoute(bgp, wcb->import_table, afi,
2433 wcb->node);
2434 }
2435 }
2436
2437 rfapiMonitorEncapDelete(bpi);
2438
2439 /*
2440 * If there are no VPN monitors at this VPN Node A,
2441 * we are done
2442 */
2443 if (!RFAPI_MONITOR_VPN(wcb->node)) {
2444 vnc_zlog_debug_verbose("%s: no VPN monitors at this node",
2445 __func__);
2446 goto done;
2447 }
2448
2449 /*
2450 * rfapiMonitorMoveShorter only moves monitors if there are
2451 * no remaining valid routes at the current node
2452 */
2453 moved = rfapiMonitorMoveShorter(wcb->node, 1);
2454
2455 if (moved) {
2456 rfapiMonitorMovedUp(wcb->import_table, wcb->node, moved->node,
2457 moved);
2458 }
2459
2460 done:
2461 /*
2462 * Free VPN bpi
2463 */
2464 rfapiBgpInfoFree(bpi);
2465 wcb->info = NULL;
2466
2467 /*
2468 * If route count at this node has gone to 0, withdraw exported prefix
2469 */
2470 if (!wcb->node->info) {
2471 /* see if the struct rfapi_it_extra is empty and can be freed */
2472 rfapiMonitorExtraPrune(SAFI_MPLS_VPN, wcb->node);
2473 vnc_direct_bgp_del_prefix(bgp, wcb->import_table, wcb->node);
2474 vnc_zebra_del_prefix(bgp, wcb->import_table, wcb->node);
2475 } else {
2476 /*
2477 * nexthop change event
2478 * vnc_direct_bgp_add_prefix() will recompute the VN addr
2479 * ecommunity
2480 */
2481 vnc_direct_bgp_add_prefix(bgp, wcb->import_table, wcb->node);
2482 }
2483
2484 RFAPI_CHECK_REFCOUNT(wcb->node, SAFI_MPLS_VPN, 1 + wcb->lockoffset);
2485 agg_unlock_node(wcb->node); /* decr ref count */
2486 XFREE(MTYPE_RFAPI_WITHDRAW, wcb);
2487 }
2488
2489 /*
2490 * This works for multiprotocol extension, but not for plain ol'
2491 * unicast IPv4 because that nexthop is stored in attr->nexthop
2492 */
2493 void rfapiNexthop2Prefix(struct attr *attr, struct prefix *p)
2494 {
2495 assert(p);
2496 assert(attr);
2497
2498 memset(p, 0, sizeof(struct prefix));
2499
2500 switch (p->family = BGP_MP_NEXTHOP_FAMILY(attr->mp_nexthop_len)) {
2501 case AF_INET:
2502 p->u.prefix4 = attr->mp_nexthop_global_in;
2503 p->prefixlen = IPV4_MAX_BITLEN;
2504 break;
2505
2506 case AF_INET6:
2507 p->u.prefix6 = attr->mp_nexthop_global;
2508 p->prefixlen = IPV6_MAX_BITLEN;
2509 break;
2510
2511 default:
2512 vnc_zlog_debug_verbose("%s: Family is unknown = %d", __func__,
2513 p->family);
2514 }
2515 }
2516
2517 void rfapiUnicastNexthop2Prefix(afi_t afi, struct attr *attr, struct prefix *p)
2518 {
2519 if (afi == AFI_IP) {
2520 p->family = AF_INET;
2521 p->prefixlen = IPV4_MAX_BITLEN;
2522 p->u.prefix4 = attr->nexthop;
2523 } else {
2524 rfapiNexthop2Prefix(attr, p);
2525 }
2526 }
2527
2528 static int rfapiAttrNexthopAddrDifferent(struct prefix *p1, struct prefix *p2)
2529 {
2530 if (!p1 || !p2) {
2531 vnc_zlog_debug_verbose("%s: p1 or p2 is NULL", __func__);
2532 return 1;
2533 }
2534
2535 /*
2536 * Are address families the same?
2537 */
2538 if (p1->family != p2->family) {
2539 return 1;
2540 }
2541
2542 switch (p1->family) {
2543 case AF_INET:
2544 if (IPV4_ADDR_SAME(&p1->u.prefix4, &p2->u.prefix4))
2545 return 0;
2546 break;
2547
2548 case AF_INET6:
2549 if (IPV6_ADDR_SAME(&p1->u.prefix6, &p2->u.prefix6))
2550 return 0;
2551 break;
2552
2553 default:
2554 assert(1);
2555 }
2556
2557 return 1;
2558 }
2559
2560 static void rfapiCopyUnEncap2VPN(struct bgp_path_info *encap_bpi,
2561 struct bgp_path_info *vpn_bpi)
2562 {
2563 if (!vpn_bpi || !vpn_bpi->extra) {
2564 zlog_warn("%s: no vpn bpi attr/extra, can't copy UN address",
2565 __func__);
2566 return;
2567 }
2568
2569 switch (BGP_MP_NEXTHOP_FAMILY(encap_bpi->attr->mp_nexthop_len)) {
2570 case AF_INET:
2571
2572 /*
2573 * instrumentation to debug segfault of 091127
2574 */
2575 vnc_zlog_debug_verbose("%s: vpn_bpi=%p", __func__, vpn_bpi);
2576 vnc_zlog_debug_verbose("%s: vpn_bpi->extra=%p", __func__,
2577 vpn_bpi->extra);
2578
2579 vpn_bpi->extra->vnc.import.un_family = AF_INET;
2580 vpn_bpi->extra->vnc.import.un.addr4 =
2581 encap_bpi->attr->mp_nexthop_global_in;
2582 break;
2583
2584 case AF_INET6:
2585 vpn_bpi->extra->vnc.import.un_family = AF_INET6;
2586 vpn_bpi->extra->vnc.import.un.addr6 =
2587 encap_bpi->attr->mp_nexthop_global;
2588 break;
2589
2590 default:
2591 zlog_warn("%s: invalid encap nexthop length: %d", __func__,
2592 encap_bpi->attr->mp_nexthop_len);
2593 vpn_bpi->extra->vnc.import.un_family = AF_UNSPEC;
2594 break;
2595 }
2596 }
2597
2598 /*
2599 * returns 0 on success, nonzero on error
2600 */
2601 static int
2602 rfapiWithdrawEncapUpdateCachedUn(struct rfapi_import_table *import_table,
2603 struct bgp_path_info *encap_bpi,
2604 struct agg_node *vpn_rn,
2605 struct bgp_path_info *vpn_bpi)
2606 {
2607 if (!encap_bpi) {
2608
2609 /*
2610 * clear cached UN address
2611 */
2612 if (!vpn_bpi || !vpn_bpi->extra) {
2613 zlog_warn(
2614 "%s: missing VPN bpi/extra, can't clear UN addr",
2615 __func__);
2616 return 1;
2617 }
2618 vpn_bpi->extra->vnc.import.un_family = AF_UNSPEC;
2619 memset(&vpn_bpi->extra->vnc.import.un, 0,
2620 sizeof(vpn_bpi->extra->vnc.import.un));
2621 if (CHECK_FLAG(vpn_bpi->flags, BGP_PATH_VALID)) {
2622 if (rfapiGetVncTunnelUnAddr(vpn_bpi->attr, NULL)) {
2623 UNSET_FLAG(vpn_bpi->flags, BGP_PATH_VALID);
2624 if (VALID_INTERIOR_TYPE(vpn_bpi->type))
2625 RFAPI_MONITOR_EXTERIOR(vpn_rn)
2626 ->valid_interior_count--;
2627 /* signal interior route withdrawal to
2628 * import-exterior */
2629 vnc_import_bgp_exterior_del_route_interior(
2630 bgp_get_default(), import_table, vpn_rn,
2631 vpn_bpi);
2632 }
2633 }
2634
2635 } else {
2636 if (!vpn_bpi) {
2637 zlog_warn("%s: missing VPN bpi, can't clear UN addr",
2638 __func__);
2639 return 1;
2640 }
2641 rfapiCopyUnEncap2VPN(encap_bpi, vpn_bpi);
2642 if (!CHECK_FLAG(vpn_bpi->flags, BGP_PATH_VALID)) {
2643 SET_FLAG(vpn_bpi->flags, BGP_PATH_VALID);
2644 if (VALID_INTERIOR_TYPE(vpn_bpi->type))
2645 RFAPI_MONITOR_EXTERIOR(vpn_rn)
2646 ->valid_interior_count++;
2647 /* signal interior route withdrawal to import-exterior
2648 */
2649 vnc_import_bgp_exterior_add_route_interior(
2650 bgp_get_default(), import_table, vpn_rn,
2651 vpn_bpi);
2652 }
2653 }
2654 return 0;
2655 }
2656
2657 static void rfapiWithdrawTimerEncap(struct thread *t)
2658 {
2659 struct rfapi_withdraw *wcb = THREAD_ARG(t);
2660 struct bgp_path_info *bpi = wcb->info;
2661 int was_first_route = 0;
2662 struct rfapi_monitor_encap *em;
2663 struct skiplist *vpn_node_sl = skiplist_new(0, NULL, NULL);
2664
2665 assert(wcb->node);
2666 assert(bpi);
2667 assert(wcb->import_table);
2668
2669 RFAPI_CHECK_REFCOUNT(wcb->node, SAFI_ENCAP, 0);
2670
2671 if (wcb->node->info == bpi)
2672 was_first_route = 1;
2673
2674 /*
2675 * Remove the route/bpi and free it
2676 */
2677 rfapiBgpInfoDetach(wcb->node, bpi);
2678 rfapiBgpInfoFree(bpi);
2679
2680 if (!was_first_route)
2681 goto done;
2682
2683 for (em = RFAPI_MONITOR_ENCAP(wcb->node); em; em = em->next) {
2684
2685 /*
2686 * Update monitoring VPN BPIs with new encap info at the
2687 * head of the encap bpi chain (which could be NULL after
2688 * removing the expiring bpi above)
2689 */
2690 if (rfapiWithdrawEncapUpdateCachedUn(wcb->import_table,
2691 wcb->node->info, em->node,
2692 em->bpi))
2693 continue;
2694
2695 /*
2696 * Build a list of unique VPN nodes referenced by these
2697 * monitors.
2698 * Use a skiplist for speed.
2699 */
2700 skiplist_insert(vpn_node_sl, em->node, em->node);
2701 }
2702
2703
2704 /*
2705 * for each VPN node referenced in the ENCAP monitors:
2706 */
2707 struct agg_node *rn;
2708 while (!skiplist_first(vpn_node_sl, (void **)&rn, NULL)) {
2709 if (!wcb->node->info) {
2710 struct rfapi_monitor_vpn *moved;
2711
2712 moved = rfapiMonitorMoveShorter(rn, 0);
2713 if (moved) {
2714 // rfapiDoRouteCallback(wcb->import_table,
2715 // moved->node, moved);
2716 rfapiMonitorMovedUp(wcb->import_table, rn,
2717 moved->node, moved);
2718 }
2719 } else {
2720 // rfapiDoRouteCallback(wcb->import_table, rn, NULL);
2721 rfapiMonitorItNodeChanged(wcb->import_table, rn, NULL);
2722 }
2723 skiplist_delete_first(vpn_node_sl);
2724 }
2725
2726 done:
2727 RFAPI_CHECK_REFCOUNT(wcb->node, SAFI_ENCAP, 1);
2728 agg_unlock_node(wcb->node); /* decr ref count */
2729 XFREE(MTYPE_RFAPI_WITHDRAW, wcb);
2730 skiplist_free(vpn_node_sl);
2731 }
2732
2733
2734 /*
2735 * Works for both VPN and ENCAP routes; timer_service_func is different
2736 * in each case
2737 */
2738 static void
2739 rfapiBiStartWithdrawTimer(struct rfapi_import_table *import_table,
2740 struct agg_node *rn, struct bgp_path_info *bpi,
2741 afi_t afi, safi_t safi,
2742 void (*timer_service_func)(struct thread *))
2743 {
2744 uint32_t lifetime;
2745 struct rfapi_withdraw *wcb;
2746
2747 if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) {
2748 /*
2749 * Already on the path to being withdrawn,
2750 * should already have a timer set up to
2751 * delete it.
2752 */
2753 vnc_zlog_debug_verbose(
2754 "%s: already being withdrawn, do nothing", __func__);
2755 return;
2756 }
2757
2758 rfapiGetVncLifetime(bpi->attr, &lifetime);
2759 vnc_zlog_debug_verbose("%s: VNC lifetime is %u", __func__, lifetime);
2760
2761 /*
2762 * withdrawn routes get to hang around for a while
2763 */
2764 SET_FLAG(bpi->flags, BGP_PATH_REMOVED);
2765
2766 /* set timer to remove the route later */
2767 lifetime = rfapiGetHolddownFromLifetime(lifetime);
2768 vnc_zlog_debug_verbose("%s: using timeout %u", __func__, lifetime);
2769
2770 /*
2771 * Stash import_table, node, and info for use by timer
2772 * service routine, which is supposed to free the wcb.
2773 */
2774 wcb = XCALLOC(MTYPE_RFAPI_WITHDRAW, sizeof(struct rfapi_withdraw));
2775 wcb->node = rn;
2776 wcb->info = bpi;
2777 wcb->import_table = import_table;
2778 bgp_attr_intern(bpi->attr);
2779
2780 if (VNC_DEBUG(VERBOSE)) {
2781 vnc_zlog_debug_verbose(
2782 "%s: wcb values: node=%p, info=%p, import_table=%p (bpi follows)",
2783 __func__, wcb->node, wcb->info, wcb->import_table);
2784 rfapiPrintBi(NULL, bpi);
2785 }
2786
2787
2788 assert(bpi->extra);
2789 if (lifetime > UINT32_MAX / 1001) {
2790 /* sub-optimal case, but will probably never happen */
2791 bpi->extra->vnc.import.timer = NULL;
2792 thread_add_timer(bm->master, timer_service_func, wcb, lifetime,
2793 &bpi->extra->vnc.import.timer);
2794 } else {
2795 static uint32_t jitter;
2796 uint32_t lifetime_msec;
2797
2798 /*
2799 * the goal here is to spread out the timers so they are
2800 * sortable in the skip list
2801 */
2802 if (++jitter >= 1000)
2803 jitter = 0;
2804
2805 lifetime_msec = (lifetime * 1000) + jitter;
2806
2807 bpi->extra->vnc.import.timer = NULL;
2808 thread_add_timer_msec(bm->master, timer_service_func, wcb,
2809 lifetime_msec,
2810 &bpi->extra->vnc.import.timer);
2811 }
2812
2813 /* re-sort route list (BGP_PATH_REMOVED routes are last) */
2814 if (((struct bgp_path_info *)rn->info)->next) {
2815 rfapiBgpInfoDetach(rn, bpi);
2816 rfapiBgpInfoAttachSorted(rn, bpi, afi, safi);
2817 }
2818 }
2819
2820
2821 typedef void(rfapi_bi_filtered_import_f)(struct rfapi_import_table *table,
2822 int action, struct peer *peer,
2823 void *rfd, const struct prefix *prefix,
2824 const struct prefix *aux_prefix,
2825 afi_t afi, struct prefix_rd *prd,
2826 struct attr *attr, uint8_t type,
2827 uint8_t sub_type, uint32_t *label);
2828
2829
2830 static void rfapiExpireEncapNow(struct rfapi_import_table *it,
2831 struct agg_node *rn, struct bgp_path_info *bpi)
2832 {
2833 struct rfapi_withdraw *wcb;
2834 struct thread t;
2835
2836 /*
2837 * pretend we're an expiring timer
2838 */
2839 wcb = XCALLOC(MTYPE_RFAPI_WITHDRAW, sizeof(struct rfapi_withdraw));
2840 wcb->info = bpi;
2841 wcb->node = rn;
2842 wcb->import_table = it;
2843 memset(&t, 0, sizeof(t));
2844 t.arg = wcb;
2845 rfapiWithdrawTimerEncap(&t); /* frees wcb */
2846 }
2847
2848 static int rfapiGetNexthop(struct attr *attr, struct prefix *prefix)
2849 {
2850 switch (BGP_MP_NEXTHOP_FAMILY(attr->mp_nexthop_len)) {
2851 case AF_INET:
2852 prefix->family = AF_INET;
2853 prefix->prefixlen = IPV4_MAX_BITLEN;
2854 prefix->u.prefix4 = attr->mp_nexthop_global_in;
2855 break;
2856 case AF_INET6:
2857 prefix->family = AF_INET6;
2858 prefix->prefixlen = IPV6_MAX_BITLEN;
2859 prefix->u.prefix6 = attr->mp_nexthop_global;
2860 break;
2861 default:
2862 vnc_zlog_debug_verbose("%s: unknown attr->mp_nexthop_len %d",
2863 __func__, attr->mp_nexthop_len);
2864 return EINVAL;
2865 }
2866 return 0;
2867 }
2868
2869 /*
2870 * import a bgp_path_info if its route target list intersects with the
2871 * import table's route target list
2872 */
2873 static void rfapiBgpInfoFilteredImportEncap(
2874 struct rfapi_import_table *import_table, int action, struct peer *peer,
2875 void *rfd, /* set for looped back routes */
2876 const struct prefix *p,
2877 const struct prefix *aux_prefix, /* Unused for encap routes */
2878 afi_t afi, struct prefix_rd *prd,
2879 struct attr *attr, /* part of bgp_path_info */
2880 uint8_t type, /* part of bgp_path_info */
2881 uint8_t sub_type, /* part of bgp_path_info */
2882 uint32_t *label) /* part of bgp_path_info */
2883 {
2884 struct agg_table *rt = NULL;
2885 struct agg_node *rn;
2886 struct bgp_path_info *info_new;
2887 struct bgp_path_info *bpi;
2888 struct bgp_path_info *next;
2889 char buf[BUFSIZ];
2890
2891 struct prefix p_firstbpi_old;
2892 struct prefix p_firstbpi_new;
2893 int replacing = 0;
2894 const char *action_str = NULL;
2895 struct prefix un_prefix;
2896
2897 struct bgp *bgp;
2898 bgp = bgp_get_default(); /* assume 1 instance for now */
2899
2900 switch (action) {
2901 case FIF_ACTION_UPDATE:
2902 action_str = "update";
2903 break;
2904 case FIF_ACTION_WITHDRAW:
2905 action_str = "withdraw";
2906 break;
2907 case FIF_ACTION_KILL:
2908 action_str = "kill";
2909 break;
2910 default:
2911 assert(0);
2912 break;
2913 }
2914
2915 vnc_zlog_debug_verbose(
2916 "%s: entry: %s: prefix %s/%d", __func__, action_str,
2917 inet_ntop(p->family, &p->u.prefix, buf, sizeof(buf)),
2918 p->prefixlen);
2919
2920 memset(&p_firstbpi_old, 0, sizeof(p_firstbpi_old));
2921 memset(&p_firstbpi_new, 0, sizeof(p_firstbpi_new));
2922
2923 if (action == FIF_ACTION_UPDATE) {
2924 /*
2925 * Compare rt lists. If no intersection, don't import this route
2926 * On a withdraw, peer and RD are sufficient to determine if
2927 * we should act.
2928 */
2929 if (!attr || !bgp_attr_get_ecommunity(attr)) {
2930
2931 vnc_zlog_debug_verbose(
2932 "%s: attr, extra, or ecommunity missing, not importing",
2933 __func__);
2934 return;
2935 }
2936 #ifdef RFAPI_REQUIRE_ENCAP_BEEC
2937 if (!rfapiEcommunitiesMatchBeec(
2938 bgp_attr_get_ecommunity(attr))) {
2939 vnc_zlog_debug_verbose(
2940 "%s: it=%p: no match for BGP Encapsulation ecommunity",
2941 __func__, import_table);
2942 return;
2943 }
2944 #endif
2945 if (!rfapiEcommunitiesIntersect(
2946 import_table->rt_import_list,
2947 bgp_attr_get_ecommunity(attr))) {
2948
2949 vnc_zlog_debug_verbose(
2950 "%s: it=%p: no ecommunity intersection",
2951 __func__, import_table);
2952 return;
2953 }
2954
2955 /*
2956 * Updates must also have a nexthop address
2957 */
2958 memset(&un_prefix, 0,
2959 sizeof(un_prefix)); /* keep valgrind happy */
2960 if (rfapiGetNexthop(attr, &un_prefix)) {
2961 vnc_zlog_debug_verbose("%s: missing nexthop address",
2962 __func__);
2963 return;
2964 }
2965 }
2966
2967 /*
2968 * Figure out which radix tree the route would go into
2969 */
2970 switch (afi) {
2971 case AFI_IP:
2972 case AFI_IP6:
2973 rt = import_table->imported_encap[afi];
2974 break;
2975
2976 case AFI_UNSPEC:
2977 case AFI_L2VPN:
2978 case AFI_MAX:
2979 flog_err(EC_LIB_DEVELOPMENT, "%s: bad afi %d", __func__, afi);
2980 return;
2981 }
2982
2983 /*
2984 * agg_node_lookup returns a node only if there is at least
2985 * one route attached.
2986 */
2987 rn = agg_node_lookup(rt, p);
2988
2989 #ifdef DEBUG_ENCAP_MONITOR
2990 vnc_zlog_debug_verbose("%s: initial encap lookup(it=%p) rn=%p",
2991 __func__, import_table, rn);
2992 #endif
2993
2994 if (rn) {
2995
2996 RFAPI_CHECK_REFCOUNT(rn, SAFI_ENCAP, 1);
2997 agg_unlock_node(rn); /* undo lock in agg_node_lookup */
2998
2999
3000 /*
3001 * capture nexthop of first bpi
3002 */
3003 if (rn->info) {
3004 rfapiNexthop2Prefix(
3005 ((struct bgp_path_info *)(rn->info))->attr,
3006 &p_firstbpi_old);
3007 }
3008
3009 for (bpi = rn->info; bpi; bpi = bpi->next) {
3010
3011 /*
3012 * Does this bgp_path_info refer to the same route
3013 * as we are trying to add?
3014 */
3015 vnc_zlog_debug_verbose("%s: comparing BPI %p", __func__,
3016 bpi);
3017
3018
3019 /*
3020 * Compare RDs
3021 *
3022 * RD of import table bpi is in
3023 * bpi->extra->vnc.import.rd RD of info_orig is in prd
3024 */
3025 if (!bpi->extra) {
3026 vnc_zlog_debug_verbose("%s: no bpi->extra",
3027 __func__);
3028 continue;
3029 }
3030 if (prefix_cmp(
3031 (struct prefix *)&bpi->extra->vnc.import.rd,
3032 (struct prefix *)prd)) {
3033
3034 vnc_zlog_debug_verbose("%s: prd does not match",
3035 __func__);
3036 continue;
3037 }
3038
3039 /*
3040 * Compare peers
3041 */
3042 if (bpi->peer != peer) {
3043 vnc_zlog_debug_verbose(
3044 "%s: peer does not match", __func__);
3045 continue;
3046 }
3047
3048 vnc_zlog_debug_verbose("%s: found matching bpi",
3049 __func__);
3050
3051 /* Same route. Delete this bpi, replace with new one */
3052
3053 if (action == FIF_ACTION_WITHDRAW) {
3054
3055 vnc_zlog_debug_verbose(
3056 "%s: withdrawing at prefix %pRN",
3057 __func__, rn);
3058
3059 rfapiBiStartWithdrawTimer(
3060 import_table, rn, bpi, afi, SAFI_ENCAP,
3061 rfapiWithdrawTimerEncap);
3062
3063 } else {
3064 vnc_zlog_debug_verbose(
3065 "%s: %s at prefix %pRN", __func__,
3066 ((action == FIF_ACTION_KILL)
3067 ? "killing"
3068 : "replacing"),
3069 rn);
3070
3071 /*
3072 * If this route is waiting to be deleted
3073 * because of
3074 * a previous withdraw, we must cancel its
3075 * timer.
3076 */
3077 if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)
3078 && bpi->extra->vnc.import.timer) {
3079 struct rfapi_withdraw *wcb = THREAD_ARG(
3080 bpi->extra->vnc.import.timer);
3081
3082 XFREE(MTYPE_RFAPI_WITHDRAW, wcb);
3083 THREAD_OFF(
3084 bpi->extra->vnc.import.timer);
3085 }
3086
3087 if (action == FIF_ACTION_UPDATE) {
3088 rfapiBgpInfoDetach(rn, bpi);
3089 rfapiBgpInfoFree(bpi);
3090 replacing = 1;
3091 } else {
3092 /*
3093 * Kill: do export stuff when removing
3094 * bpi
3095 */
3096 struct rfapi_withdraw *wcb;
3097 struct thread t;
3098
3099 /*
3100 * pretend we're an expiring timer
3101 */
3102 wcb = XCALLOC(
3103 MTYPE_RFAPI_WITHDRAW,
3104 sizeof(struct rfapi_withdraw));
3105 wcb->info = bpi;
3106 wcb->node = rn;
3107 wcb->import_table = import_table;
3108 memset(&t, 0, sizeof(t));
3109 t.arg = wcb;
3110 rfapiWithdrawTimerEncap(
3111 &t); /* frees wcb */
3112 }
3113 }
3114
3115 break;
3116 }
3117 }
3118
3119 if (rn)
3120 RFAPI_CHECK_REFCOUNT(rn, SAFI_ENCAP, replacing ? 1 : 0);
3121
3122 if (action == FIF_ACTION_WITHDRAW || action == FIF_ACTION_KILL)
3123 return;
3124
3125 info_new =
3126 rfapiBgpInfoCreate(attr, peer, rfd, prd, type, sub_type, NULL);
3127
3128 if (rn) {
3129 if (!replacing)
3130 agg_lock_node(rn); /* incr ref count for new BPI */
3131 } else {
3132 rn = agg_node_get(rt, p);
3133 }
3134
3135 vnc_zlog_debug_verbose("%s: (afi=%d, rn=%p) inserting at prefix %pRN",
3136 __func__, afi, rn, rn);
3137
3138 rfapiBgpInfoAttachSorted(rn, info_new, afi, SAFI_ENCAP);
3139
3140 /*
3141 * Delete holddown routes from same NVE. See details in
3142 * rfapiBgpInfoFilteredImportVPN()
3143 */
3144 for (bpi = info_new->next; bpi; bpi = next) {
3145
3146 struct prefix pfx_un;
3147 int un_match = 0;
3148
3149 next = bpi->next;
3150 if (!CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED))
3151 continue;
3152
3153 /*
3154 * We already match the VN address (it is the prefix
3155 * of the route node)
3156 */
3157
3158 if (!rfapiGetNexthop(bpi->attr, &pfx_un)
3159 && prefix_same(&pfx_un, &un_prefix)) {
3160
3161 un_match = 1;
3162 }
3163
3164 if (!un_match)
3165 continue;
3166
3167 vnc_zlog_debug_verbose(
3168 "%s: removing holddown bpi matching NVE of new route",
3169 __func__);
3170 if (bpi->extra->vnc.import.timer) {
3171 struct rfapi_withdraw *wcb =
3172 THREAD_ARG(bpi->extra->vnc.import.timer);
3173
3174 XFREE(MTYPE_RFAPI_WITHDRAW, wcb);
3175 THREAD_OFF(bpi->extra->vnc.import.timer);
3176 }
3177 rfapiExpireEncapNow(import_table, rn, bpi);
3178 }
3179
3180 rfapiNexthop2Prefix(((struct bgp_path_info *)(rn->info))->attr,
3181 &p_firstbpi_new);
3182
3183 /*
3184 * If the nexthop address of the selected Encap route (i.e.,
3185 * the UN address) has changed, then we must update the VPN
3186 * routes that refer to this Encap route and possibly force
3187 * rfapi callbacks.
3188 */
3189 if (rfapiAttrNexthopAddrDifferent(&p_firstbpi_old, &p_firstbpi_new)) {
3190
3191 struct rfapi_monitor_encap *m;
3192 struct rfapi_monitor_encap *mnext;
3193
3194 struct agg_node *referenced_vpn_prefix;
3195
3196 /*
3197 * Optimized approach: build radix tree on the fly to
3198 * hold list of VPN nodes referenced by the ENCAP monitors
3199 *
3200 * The nodes in this table correspond to prefixes of VPN routes.
3201 * The "info" pointer of the node points to a chain of
3202 * struct rfapi_monitor_encap, each of which refers to a
3203 * specific VPN node.
3204 */
3205 struct agg_table *referenced_vpn_table;
3206
3207 referenced_vpn_table = agg_table_init();
3208
3209 /*
3210 * iterate over the set of monitors at this ENCAP node.
3211 */
3212 #ifdef DEBUG_ENCAP_MONITOR
3213 vnc_zlog_debug_verbose("%s: examining monitors at rn=%p",
3214 __func__, rn);
3215 #endif
3216 for (m = RFAPI_MONITOR_ENCAP(rn); m; m = m->next) {
3217 const struct prefix *p;
3218
3219 /*
3220 * For each referenced bpi/route, copy the ENCAP route's
3221 * nexthop to the VPN route's cached UN address field
3222 * and set
3223 * the address family of the cached UN address field.
3224 */
3225 rfapiCopyUnEncap2VPN(info_new, m->bpi);
3226 if (!CHECK_FLAG(m->bpi->flags, BGP_PATH_VALID)) {
3227 SET_FLAG(m->bpi->flags, BGP_PATH_VALID);
3228 if (VALID_INTERIOR_TYPE(m->bpi->type))
3229 RFAPI_MONITOR_EXTERIOR(m->node)
3230 ->valid_interior_count++;
3231 vnc_import_bgp_exterior_add_route_interior(
3232 bgp, import_table, m->node, m->bpi);
3233 }
3234
3235 /*
3236 * Build a list of unique VPN nodes referenced by these
3237 * monitors
3238 *
3239 * There could be more than one VPN node here with a
3240 * given
3241 * prefix. Those are currently in an unsorted linear
3242 * list
3243 * per prefix.
3244 */
3245 p = agg_node_get_prefix(m->node);
3246 referenced_vpn_prefix =
3247 agg_node_get(referenced_vpn_table, p);
3248 assert(referenced_vpn_prefix);
3249 for (mnext = referenced_vpn_prefix->info; mnext;
3250 mnext = mnext->next) {
3251
3252 if (mnext->node == m->node)
3253 break;
3254 }
3255
3256 if (mnext) {
3257 /*
3258 * already have an entry for this VPN node
3259 */
3260 agg_unlock_node(referenced_vpn_prefix);
3261 } else {
3262 mnext = XCALLOC(
3263 MTYPE_RFAPI_MONITOR_ENCAP,
3264 sizeof(struct rfapi_monitor_encap));
3265 mnext->node = m->node;
3266 mnext->next = referenced_vpn_prefix->info;
3267 referenced_vpn_prefix->info = mnext;
3268 }
3269 }
3270
3271 /*
3272 * for each VPN node referenced in the ENCAP monitors:
3273 */
3274 for (referenced_vpn_prefix =
3275 agg_route_top(referenced_vpn_table);
3276 referenced_vpn_prefix;
3277 referenced_vpn_prefix =
3278 agg_route_next(referenced_vpn_prefix)) {
3279
3280 while ((m = referenced_vpn_prefix->info)) {
3281
3282 struct agg_node *n;
3283
3284 rfapiMonitorMoveLonger(m->node);
3285 for (n = m->node; n; n = agg_node_parent(n)) {
3286 // rfapiDoRouteCallback(import_table, n,
3287 // NULL);
3288 }
3289 rfapiMonitorItNodeChanged(import_table, m->node,
3290 NULL);
3291
3292 referenced_vpn_prefix->info = m->next;
3293 agg_unlock_node(referenced_vpn_prefix);
3294 XFREE(MTYPE_RFAPI_MONITOR_ENCAP, m);
3295 }
3296 }
3297 agg_table_finish(referenced_vpn_table);
3298 }
3299
3300 RFAPI_CHECK_REFCOUNT(rn, SAFI_ENCAP, 0);
3301 }
3302
3303 static void rfapiExpireVpnNow(struct rfapi_import_table *it,
3304 struct agg_node *rn, struct bgp_path_info *bpi,
3305 int lockoffset)
3306 {
3307 struct rfapi_withdraw *wcb;
3308 struct thread t;
3309
3310 /*
3311 * pretend we're an expiring timer
3312 */
3313 wcb = XCALLOC(MTYPE_RFAPI_WITHDRAW, sizeof(struct rfapi_withdraw));
3314 wcb->info = bpi;
3315 wcb->node = rn;
3316 wcb->import_table = it;
3317 wcb->lockoffset = lockoffset;
3318 memset(&t, 0, sizeof(t));
3319 t.arg = wcb;
3320 rfapiWithdrawTimerVPN(&t); /* frees wcb */
3321 }
3322
3323
3324 /*
3325 * import a bgp_path_info if its route target list intersects with the
3326 * import table's route target list
3327 */
3328 void rfapiBgpInfoFilteredImportVPN(
3329 struct rfapi_import_table *import_table, int action, struct peer *peer,
3330 void *rfd, /* set for looped back routes */
3331 const struct prefix *p,
3332 const struct prefix *aux_prefix, /* AFI_L2VPN: optional IP */
3333 afi_t afi, struct prefix_rd *prd,
3334 struct attr *attr, /* part of bgp_path_info */
3335 uint8_t type, /* part of bgp_path_info */
3336 uint8_t sub_type, /* part of bgp_path_info */
3337 uint32_t *label) /* part of bgp_path_info */
3338 {
3339 struct agg_table *rt = NULL;
3340 struct agg_node *rn;
3341 struct agg_node *n;
3342 struct bgp_path_info *info_new;
3343 struct bgp_path_info *bpi;
3344 struct bgp_path_info *next;
3345 char buf[BUFSIZ];
3346 struct prefix vn_prefix;
3347 struct prefix un_prefix;
3348 int un_prefix_valid = 0;
3349 struct agg_node *ern;
3350 int replacing = 0;
3351 int original_had_routes = 0;
3352 struct prefix original_nexthop;
3353 const char *action_str = NULL;
3354 int is_it_ce = 0;
3355
3356 struct bgp *bgp;
3357 bgp = bgp_get_default(); /* assume 1 instance for now */
3358
3359 switch (action) {
3360 case FIF_ACTION_UPDATE:
3361 action_str = "update";
3362 break;
3363 case FIF_ACTION_WITHDRAW:
3364 action_str = "withdraw";
3365 break;
3366 case FIF_ACTION_KILL:
3367 action_str = "kill";
3368 break;
3369 default:
3370 assert(0);
3371 break;
3372 }
3373
3374 if (import_table == bgp->rfapi->it_ce)
3375 is_it_ce = 1;
3376
3377 vnc_zlog_debug_verbose("%s: entry: %s%s: prefix %s/%d: it %p, afi %s",
3378 __func__, (is_it_ce ? "CE-IT " : ""), action_str,
3379 rfapi_ntop(p->family, &p->u.prefix, buf, BUFSIZ),
3380 p->prefixlen, import_table, afi2str(afi));
3381
3382 VNC_ITRCCK;
3383
3384 /*
3385 * Compare rt lists. If no intersection, don't import this route
3386 * On a withdraw, peer and RD are sufficient to determine if
3387 * we should act.
3388 */
3389 if (action == FIF_ACTION_UPDATE) {
3390 if (!attr || !bgp_attr_get_ecommunity(attr)) {
3391
3392 vnc_zlog_debug_verbose(
3393 "%s: attr, extra, or ecommunity missing, not importing",
3394 __func__);
3395 return;
3396 }
3397 if ((import_table != bgp->rfapi->it_ce) &&
3398 !rfapiEcommunitiesIntersect(
3399 import_table->rt_import_list,
3400 bgp_attr_get_ecommunity(attr))) {
3401
3402 vnc_zlog_debug_verbose(
3403 "%s: it=%p: no ecommunity intersection",
3404 __func__, import_table);
3405 return;
3406 }
3407
3408 memset(&vn_prefix, 0,
3409 sizeof(vn_prefix)); /* keep valgrind happy */
3410 if (rfapiGetNexthop(attr, &vn_prefix)) {
3411 /* missing nexthop address would be a bad, bad thing */
3412 vnc_zlog_debug_verbose("%s: missing nexthop", __func__);
3413 return;
3414 }
3415 }
3416
3417 /*
3418 * Figure out which radix tree the route would go into
3419 */
3420 switch (afi) {
3421 case AFI_IP:
3422 case AFI_IP6:
3423 case AFI_L2VPN:
3424 rt = import_table->imported_vpn[afi];
3425 break;
3426
3427 case AFI_UNSPEC:
3428 case AFI_MAX:
3429 flog_err(EC_LIB_DEVELOPMENT, "%s: bad afi %d", __func__, afi);
3430 return;
3431 }
3432
3433 /* clear it */
3434 memset(&original_nexthop, 0, sizeof(original_nexthop));
3435
3436 /*
3437 * agg_node_lookup returns a node only if there is at least
3438 * one route attached.
3439 */
3440 rn = agg_node_lookup(rt, p);
3441
3442 vnc_zlog_debug_verbose("%s: rn=%p", __func__, rn);
3443
3444 if (rn) {
3445
3446 RFAPI_CHECK_REFCOUNT(rn, SAFI_MPLS_VPN, 1);
3447 agg_unlock_node(rn); /* undo lock in agg_node_lookup */
3448
3449 if (rn->info)
3450 original_had_routes = 1;
3451
3452 if (VNC_DEBUG(VERBOSE)) {
3453 vnc_zlog_debug_verbose("%s: showing IT node on entry",
3454 __func__);
3455 rfapiShowItNode(NULL, rn); /* debug */
3456 }
3457
3458 /*
3459 * Look for same route (will have same RD and peer)
3460 */
3461 bpi = rfapiItBiIndexSearch(rn, prd, peer, aux_prefix);
3462
3463 if (bpi) {
3464
3465 /*
3466 * This was an old test when we iterated over the
3467 * BPIs linearly. Since we're now looking up with
3468 * RD and peer, comparing types should not be
3469 * needed. Changed to assertion.
3470 *
3471 * Compare types. Doing so prevents a RFP-originated
3472 * route from matching an imported route, for example.
3473 */
3474 if (VNC_DEBUG(VERBOSE) && bpi->type != type)
3475 /* should be handled by RDs, but warn for now */
3476 zlog_warn("%s: type mismatch! (bpi=%d, arg=%d)",
3477 __func__, bpi->type, type);
3478
3479 vnc_zlog_debug_verbose("%s: found matching bpi",
3480 __func__);
3481
3482 /*
3483 * In the special CE table, withdrawals occur without
3484 * holddown
3485 */
3486 if (import_table == bgp->rfapi->it_ce) {
3487 vnc_direct_bgp_del_route_ce(bgp, rn, bpi);
3488 if (action == FIF_ACTION_WITHDRAW)
3489 action = FIF_ACTION_KILL;
3490 }
3491
3492 if (action == FIF_ACTION_WITHDRAW) {
3493
3494 int washolddown = CHECK_FLAG(bpi->flags,
3495 BGP_PATH_REMOVED);
3496
3497 vnc_zlog_debug_verbose(
3498 "%s: withdrawing at prefix %pRN%s",
3499 __func__, rn,
3500 (washolddown
3501 ? " (already being withdrawn)"
3502 : ""));
3503
3504 VNC_ITRCCK;
3505 if (!washolddown) {
3506 rfapiBiStartWithdrawTimer(
3507 import_table, rn, bpi, afi,
3508 SAFI_MPLS_VPN,
3509 rfapiWithdrawTimerVPN);
3510
3511 RFAPI_UPDATE_ITABLE_COUNT(
3512 bpi, import_table, afi, -1);
3513 import_table->holddown_count[afi] += 1;
3514 }
3515 VNC_ITRCCK;
3516 } else {
3517 vnc_zlog_debug_verbose(
3518 "%s: %s at prefix %pRN", __func__,
3519 ((action == FIF_ACTION_KILL)
3520 ? "killing"
3521 : "replacing"),
3522 rn);
3523
3524 /*
3525 * If this route is waiting to be deleted
3526 * because of
3527 * a previous withdraw, we must cancel its
3528 * timer.
3529 */
3530 if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)
3531 && bpi->extra->vnc.import.timer) {
3532 struct rfapi_withdraw *wcb = THREAD_ARG(
3533 bpi->extra->vnc.import.timer);
3534
3535 XFREE(MTYPE_RFAPI_WITHDRAW, wcb);
3536 THREAD_OFF(
3537 bpi->extra->vnc.import.timer);
3538
3539 import_table->holddown_count[afi] -= 1;
3540 RFAPI_UPDATE_ITABLE_COUNT(
3541 bpi, import_table, afi, 1);
3542 }
3543 /*
3544 * decrement remote count (if route is remote)
3545 * because
3546 * we are going to remove it below
3547 */
3548 RFAPI_UPDATE_ITABLE_COUNT(bpi, import_table,
3549 afi, -1);
3550 if (action == FIF_ACTION_UPDATE) {
3551 replacing = 1;
3552
3553 /*
3554 * make copy of original nexthop so we
3555 * can see if it changed
3556 */
3557 rfapiGetNexthop(bpi->attr,
3558 &original_nexthop);
3559
3560 /*
3561 * remove bpi without doing any export
3562 * processing
3563 */
3564 if (CHECK_FLAG(bpi->flags,
3565 BGP_PATH_VALID)
3566 && VALID_INTERIOR_TYPE(bpi->type))
3567 RFAPI_MONITOR_EXTERIOR(rn)
3568 ->valid_interior_count--;
3569 rfapiItBiIndexDel(rn, bpi);
3570 rfapiBgpInfoDetach(rn, bpi);
3571 rfapiMonitorEncapDelete(bpi);
3572 vnc_import_bgp_exterior_del_route_interior(
3573 bgp, import_table, rn, bpi);
3574 rfapiBgpInfoFree(bpi);
3575 } else {
3576 /* Kill */
3577 /*
3578 * remove bpi and do export processing
3579 */
3580 import_table->holddown_count[afi] += 1;
3581 rfapiExpireVpnNow(import_table, rn, bpi,
3582 0);
3583 }
3584 }
3585 }
3586 }
3587
3588 if (rn)
3589 RFAPI_CHECK_REFCOUNT(rn, SAFI_MPLS_VPN, replacing ? 1 : 0);
3590
3591 if (action == FIF_ACTION_WITHDRAW || action == FIF_ACTION_KILL) {
3592 VNC_ITRCCK;
3593 return;
3594 }
3595
3596 info_new =
3597 rfapiBgpInfoCreate(attr, peer, rfd, prd, type, sub_type, label);
3598
3599 /*
3600 * lookup un address in encap table
3601 */
3602 ern = agg_node_match(import_table->imported_encap[afi], &vn_prefix);
3603 if (ern) {
3604 rfapiCopyUnEncap2VPN(ern->info, info_new);
3605 agg_unlock_node(ern); /* undo lock in route_note_match */
3606 } else {
3607 /* Not a big deal, just means VPN route got here first */
3608 vnc_zlog_debug_verbose("%s: no encap route for vn addr %pFX",
3609 __func__, &vn_prefix);
3610 info_new->extra->vnc.import.un_family = AF_UNSPEC;
3611 }
3612
3613 if (rn) {
3614 if (!replacing)
3615 agg_lock_node(rn);
3616 } else {
3617 /*
3618 * No need to increment reference count, so only "get"
3619 * if the node is not there already
3620 */
3621 rn = agg_node_get(rt, p);
3622 }
3623
3624 /*
3625 * For ethernet routes, if there is an accompanying IP address,
3626 * save it in the bpi
3627 */
3628 if ((AFI_L2VPN == afi) && aux_prefix) {
3629
3630 vnc_zlog_debug_verbose("%s: setting BPI's aux_prefix",
3631 __func__);
3632 info_new->extra->vnc.import.aux_prefix = *aux_prefix;
3633 }
3634
3635 vnc_zlog_debug_verbose("%s: inserting bpi %p at prefix %pRN #%d",
3636 __func__, info_new, rn,
3637 agg_node_get_lock_count(rn));
3638
3639 rfapiBgpInfoAttachSorted(rn, info_new, afi, SAFI_MPLS_VPN);
3640 rfapiItBiIndexAdd(rn, info_new);
3641 if (!rfapiGetUnAddrOfVpnBi(info_new, NULL)) {
3642 if (VALID_INTERIOR_TYPE(info_new->type))
3643 RFAPI_MONITOR_EXTERIOR(rn)->valid_interior_count++;
3644 SET_FLAG(info_new->flags, BGP_PATH_VALID);
3645 }
3646 RFAPI_UPDATE_ITABLE_COUNT(info_new, import_table, afi, 1);
3647 vnc_import_bgp_exterior_add_route_interior(bgp, import_table, rn,
3648 info_new);
3649
3650 if (import_table == bgp->rfapi->it_ce)
3651 vnc_direct_bgp_add_route_ce(bgp, rn, info_new);
3652
3653 if (VNC_DEBUG(VERBOSE)) {
3654 vnc_zlog_debug_verbose("%s: showing IT node", __func__);
3655 rfapiShowItNode(NULL, rn); /* debug */
3656 }
3657
3658 rfapiMonitorEncapAdd(import_table, &vn_prefix, rn, info_new);
3659
3660 if (!rfapiGetUnAddrOfVpnBi(info_new, &un_prefix)) {
3661
3662 /*
3663 * if we have a valid UN address (either via Encap route
3664 * or via tunnel attribute), then we should attempt
3665 * to move any monitors at less-specific nodes to this node
3666 */
3667 rfapiMonitorMoveLonger(rn);
3668
3669 un_prefix_valid = 1;
3670 }
3671
3672 /*
3673 * 101129 Enhancement: if we add a route (implication: it is not
3674 * in holddown), delete all other routes from this nve at this
3675 * node that are in holddown, regardless of peer.
3676 *
3677 * Reasons it's OK to do that:
3678 *
3679 * - if the holddown route being deleted originally came from BGP VPN,
3680 * it is already gone from BGP (implication of holddown), so there
3681 * won't be any added inconsistency with the BGP RIB.
3682 *
3683 * - once a fresh route is added at a prefix, any routes in holddown
3684 * at that prefix will not show up in RFP responses, so deleting
3685 * the holddown routes won't affect the contents of responses.
3686 *
3687 * - lifetimes are supposed to be consistent, so there should not
3688 * be a case where the fresh route has a shorter lifetime than
3689 * the holddown route, so we don't expect the fresh route to
3690 * disappear and complete its holddown time before the existing
3691 * holddown routes time out. Therefore, we won't have a situation
3692 * where we expect the existing holddown routes to be hidden and
3693 * then to reappear sometime later (as holddown routes) in a
3694 * RFP response.
3695 *
3696 * Among other things, this would enable us to skirt the problem
3697 * of local holddown routes that refer to NVE descriptors that
3698 * have already been closed (if the same NVE triggers a subsequent
3699 * rfapi_open(), the new peer is different and doesn't match the
3700 * peer of the holddown route, so the stale holddown route still
3701 * hangs around until it times out instead of just being replaced
3702 * by the fresh route).
3703 */
3704 /*
3705 * We know that the new bpi will have been inserted before any routes
3706 * in holddown, so we can skip any that came before it
3707 */
3708 for (bpi = info_new->next; bpi; bpi = next) {
3709
3710 struct prefix pfx_vn;
3711 struct prefix pfx_un;
3712 int un_match = 0;
3713 int remote_peer_match = 0;
3714
3715 next = bpi->next;
3716
3717 /*
3718 * Must be holddown
3719 */
3720 if (!CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED))
3721 continue;
3722
3723 /*
3724 * Must match VN address (nexthop of VPN route)
3725 */
3726 if (rfapiGetNexthop(bpi->attr, &pfx_vn))
3727 continue;
3728 if (!prefix_same(&pfx_vn, &vn_prefix))
3729 continue;
3730
3731 if (un_prefix_valid && /* new route UN addr */
3732 !rfapiGetUnAddrOfVpnBi(bpi, &pfx_un)
3733 && /* old route UN addr */
3734 prefix_same(&pfx_un, &un_prefix)) { /* compare */
3735 un_match = 1;
3736 }
3737 if (!RFAPI_LOCAL_BI(bpi) && !RFAPI_LOCAL_BI(info_new)
3738 && sockunion_same(&bpi->peer->su, &info_new->peer->su)) {
3739 /* old & new are both remote, same peer */
3740 remote_peer_match = 1;
3741 }
3742
3743 if (!un_match && !remote_peer_match)
3744 continue;
3745
3746 vnc_zlog_debug_verbose(
3747 "%s: removing holddown bpi matching NVE of new route",
3748 __func__);
3749 if (bpi->extra->vnc.import.timer) {
3750 struct rfapi_withdraw *wcb =
3751 THREAD_ARG(bpi->extra->vnc.import.timer);
3752
3753 XFREE(MTYPE_RFAPI_WITHDRAW, wcb);
3754 THREAD_OFF(bpi->extra->vnc.import.timer);
3755 }
3756 rfapiExpireVpnNow(import_table, rn, bpi, 0);
3757 }
3758
3759 if (!original_had_routes) {
3760 /*
3761 * We went from 0 usable routes to 1 usable route. Perform the
3762 * "Adding a Route" export process.
3763 */
3764 vnc_direct_bgp_add_prefix(bgp, import_table, rn);
3765 vnc_zebra_add_prefix(bgp, import_table, rn);
3766 } else {
3767 /*
3768 * Check for nexthop change event
3769 * Note: the prefix_same() test below detects two situations:
3770 * 1. route is replaced, new route has different nexthop
3771 * 2. new route is added (original_nexthop is 0)
3772 */
3773 struct prefix new_nexthop;
3774
3775 rfapiGetNexthop(attr, &new_nexthop);
3776 if (!prefix_same(&original_nexthop, &new_nexthop)) {
3777 /*
3778 * nexthop change event
3779 * vnc_direct_bgp_add_prefix() will recompute VN addr
3780 * ecommunity
3781 */
3782 vnc_direct_bgp_add_prefix(bgp, import_table, rn);
3783 }
3784 }
3785
3786 if (!(bgp->rfapi_cfg->flags & BGP_VNC_CONFIG_CALLBACK_DISABLE)) {
3787 for (n = rn; n; n = agg_node_parent(n)) {
3788 // rfapiDoRouteCallback(import_table, n, NULL);
3789 }
3790 rfapiMonitorItNodeChanged(import_table, rn, NULL);
3791 }
3792 RFAPI_CHECK_REFCOUNT(rn, SAFI_MPLS_VPN, 0);
3793 VNC_ITRCCK;
3794 }
3795
3796 static void rfapiBgpInfoFilteredImportBadSafi(
3797 struct rfapi_import_table *import_table, int action, struct peer *peer,
3798 void *rfd, /* set for looped back routes */
3799 const struct prefix *p,
3800 const struct prefix *aux_prefix, /* AFI_L2VPN: optional IP */
3801 afi_t afi, struct prefix_rd *prd,
3802 struct attr *attr, /* part of bgp_path_info */
3803 uint8_t type, /* part of bgp_path_info */
3804 uint8_t sub_type, /* part of bgp_path_info */
3805 uint32_t *label) /* part of bgp_path_info */
3806 {
3807 vnc_zlog_debug_verbose("%s: Error, bad safi", __func__);
3808 }
3809
3810 static rfapi_bi_filtered_import_f *
3811 rfapiBgpInfoFilteredImportFunction(safi_t safi)
3812 {
3813 switch (safi) {
3814 case SAFI_MPLS_VPN:
3815 return rfapiBgpInfoFilteredImportVPN;
3816
3817 case SAFI_ENCAP:
3818 return rfapiBgpInfoFilteredImportEncap;
3819
3820 case SAFI_UNSPEC:
3821 case SAFI_UNICAST:
3822 case SAFI_MULTICAST:
3823 case SAFI_EVPN:
3824 case SAFI_LABELED_UNICAST:
3825 case SAFI_FLOWSPEC:
3826 case SAFI_MAX:
3827 /* not expected */
3828 flog_err(EC_LIB_DEVELOPMENT, "%s: bad safi %d", __func__, safi);
3829 return rfapiBgpInfoFilteredImportBadSafi;
3830 }
3831
3832 assert(!"Reached end of function when we were not expecting to");
3833 }
3834
3835 void rfapiProcessUpdate(struct peer *peer,
3836 void *rfd, /* set when looped from RFP/RFAPI */
3837 const struct prefix *p, struct prefix_rd *prd,
3838 struct attr *attr, afi_t afi, safi_t safi, uint8_t type,
3839 uint8_t sub_type, uint32_t *label)
3840 {
3841 struct bgp *bgp;
3842 struct rfapi *h;
3843 struct rfapi_import_table *it;
3844 int has_ip_route = 1;
3845 uint32_t lni = 0;
3846
3847 bgp = bgp_get_default(); /* assume 1 instance for now */
3848 assert(bgp);
3849
3850 h = bgp->rfapi;
3851 assert(h);
3852
3853 /*
3854 * look at high-order byte of RD. FF means MAC
3855 * address is present (VNC L2VPN)
3856 */
3857 if ((safi == SAFI_MPLS_VPN)
3858 && (decode_rd_type(prd->val) == RD_TYPE_VNC_ETH)) {
3859 struct prefix pfx_mac_buf;
3860 struct prefix pfx_nexthop_buf;
3861 int rc;
3862
3863 /*
3864 * Set flag if prefix and nexthop are the same - don't
3865 * add the route to normal IP-based import tables
3866 */
3867 if (!rfapiGetNexthop(attr, &pfx_nexthop_buf)) {
3868 if (!prefix_cmp(&pfx_nexthop_buf, p)) {
3869 has_ip_route = 0;
3870 }
3871 }
3872
3873 memset(&pfx_mac_buf, 0, sizeof(pfx_mac_buf));
3874 pfx_mac_buf.family = AF_ETHERNET;
3875 pfx_mac_buf.prefixlen = 48;
3876 memcpy(&pfx_mac_buf.u.prefix_eth.octet, prd->val + 2, 6);
3877
3878 /*
3879 * Find rt containing LNI (Logical Network ID), which
3880 * _should_ always be present when mac address is present
3881 */
3882 rc = rfapiEcommunityGetLNI(bgp_attr_get_ecommunity(attr), &lni);
3883
3884 vnc_zlog_debug_verbose(
3885 "%s: rfapiEcommunityGetLNI returned %d, lni=%d, attr=%p",
3886 __func__, rc, lni, attr);
3887 if (!rc) {
3888 it = rfapiMacImportTableGet(bgp, lni);
3889
3890 rfapiBgpInfoFilteredImportVPN(
3891 it, FIF_ACTION_UPDATE, peer, rfd,
3892 &pfx_mac_buf, /* prefix */
3893 p, /* aux prefix: IP addr */
3894 AFI_L2VPN, prd, attr, type, sub_type, label);
3895 }
3896 }
3897
3898 if (!has_ip_route)
3899 return;
3900
3901 /*
3902 * Iterate over all import tables; do a filtered import
3903 * for the afi/safi combination
3904 */
3905 for (it = h->imports; it; it = it->next) {
3906 (*rfapiBgpInfoFilteredImportFunction(safi))(
3907 it, FIF_ACTION_UPDATE, peer, rfd, p, /* prefix */
3908 NULL, afi, prd, attr, type, sub_type, label);
3909 }
3910
3911 if (safi == SAFI_MPLS_VPN) {
3912 vnc_direct_bgp_rh_add_route(bgp, afi, p, peer, attr);
3913 rfapiBgpInfoFilteredImportVPN(
3914 bgp->rfapi->it_ce, FIF_ACTION_UPDATE, peer, rfd,
3915 p, /* prefix */
3916 NULL, afi, prd, attr, type, sub_type, label);
3917 }
3918 }
3919
3920
3921 void rfapiProcessWithdraw(struct peer *peer, void *rfd, const struct prefix *p,
3922 struct prefix_rd *prd, struct attr *attr, afi_t afi,
3923 safi_t safi, uint8_t type, int kill)
3924 {
3925 struct bgp *bgp;
3926 struct rfapi *h;
3927 struct rfapi_import_table *it;
3928
3929 bgp = bgp_get_default(); /* assume 1 instance for now */
3930 assert(bgp);
3931
3932 h = bgp->rfapi;
3933 assert(h);
3934
3935 /*
3936 * look at high-order byte of RD. FF means MAC
3937 * address is present (VNC L2VPN)
3938 */
3939 if (h->import_mac != NULL && safi == SAFI_MPLS_VPN
3940 && decode_rd_type(prd->val) == RD_TYPE_VNC_ETH) {
3941 struct prefix pfx_mac_buf;
3942 void *cursor = NULL;
3943 int rc;
3944
3945 memset(&pfx_mac_buf, 0, sizeof(pfx_mac_buf));
3946 pfx_mac_buf.family = AF_ETHERNET;
3947 pfx_mac_buf.prefixlen = 48;
3948 memcpy(&pfx_mac_buf.u.prefix_eth, prd->val + 2, 6);
3949
3950 /*
3951 * withdraw does not contain attrs, so we don't have
3952 * access to the route's LNI, which would ordinarily
3953 * select the specific mac-based import table. Instead,
3954 * we must iterate over all mac-based tables and rely
3955 * on the RD to match.
3956 *
3957 * If this approach is too slow, add an index where
3958 * key is {RD, peer} and value is the import table
3959 */
3960 for (rc = skiplist_next(h->import_mac, NULL, (void **)&it,
3961 &cursor);
3962 rc == 0; rc = skiplist_next(h->import_mac, NULL,
3963 (void **)&it, &cursor)) {
3964
3965 #ifdef DEBUG_L2_EXTRA
3966 vnc_zlog_debug_verbose(
3967 "%s: calling rfapiBgpInfoFilteredImportVPN(it=%p, afi=AFI_L2VPN)",
3968 __func__, it);
3969 #endif
3970
3971 rfapiBgpInfoFilteredImportVPN(
3972 it,
3973 (kill ? FIF_ACTION_KILL : FIF_ACTION_WITHDRAW),
3974 peer, rfd, &pfx_mac_buf, /* prefix */
3975 p, /* aux_prefix: IP */
3976 AFI_L2VPN, prd, attr, type, 0,
3977 NULL); /* sub_type & label unused for withdraw
3978 */
3979 }
3980 }
3981
3982 /*
3983 * XXX For the case where the withdraw involves an L2
3984 * route with no IP information, we rely on the lack
3985 * of RT-list intersection to filter out the withdraw
3986 * from the IP-based import tables below
3987 */
3988
3989 /*
3990 * Iterate over all import tables; do a filtered import
3991 * for the afi/safi combination
3992 */
3993
3994 for (it = h->imports; it; it = it->next) {
3995 (*rfapiBgpInfoFilteredImportFunction(safi))(
3996 it, (kill ? FIF_ACTION_KILL : FIF_ACTION_WITHDRAW),
3997 peer, rfd, p, /* prefix */
3998 NULL, afi, prd, attr, type, 0,
3999 NULL); /* sub_type & label unused for withdraw */
4000 }
4001
4002 /* TBD the deletion should happen after the lifetime expires */
4003 if (safi == SAFI_MPLS_VPN)
4004 vnc_direct_bgp_rh_del_route(bgp, afi, p, peer);
4005
4006 if (safi == SAFI_MPLS_VPN) {
4007 rfapiBgpInfoFilteredImportVPN(
4008 bgp->rfapi->it_ce,
4009 (kill ? FIF_ACTION_KILL : FIF_ACTION_WITHDRAW), peer,
4010 rfd, p, /* prefix */
4011 NULL, afi, prd, attr, type, 0,
4012 NULL); /* sub_type & label unused for withdraw */
4013 }
4014 }
4015
4016 /*
4017 * TBD optimized withdraw timer algorithm for case of many
4018 * routes expiring at the same time due to peer drop.
4019 */
4020 /*
4021 * 1. Visit all BPIs in all ENCAP import tables.
4022 *
4023 * a. If a bpi's peer is the failed peer, remove the bpi.
4024 * b. If the removed ENCAP bpi was first in the list of
4025 * BPIs at this ENCAP node, loop over all monitors
4026 * at this node:
4027 *
4028 * (1) for each ENCAP monitor, loop over all its
4029 * VPN node monitors and set their RFAPI_MON_FLAG_NEEDCALLBACK
4030 * flags.
4031 *
4032 * 2. Visit all BPIs in all VPN import tables.
4033 * a. If a bpi's peer is the failed peer, remove the bpi.
4034 * b. loop over all the VPN node monitors and set their
4035 * RFAPI_MON_FLAG_NEEDCALLBACK flags
4036 * c. If there are no BPIs left at this VPN node,
4037 *
4038 */
4039
4040
4041 /* surprise, this gets called from peer_delete(), from rfapi_close() */
4042 static void rfapiProcessPeerDownRt(struct peer *peer,
4043 struct rfapi_import_table *import_table,
4044 afi_t afi, safi_t safi)
4045 {
4046 struct agg_node *rn;
4047 struct bgp_path_info *bpi;
4048 struct agg_table *rt = NULL;
4049 void (*timer_service_func)(struct thread *) = NULL;
4050
4051 assert(afi == AFI_IP || afi == AFI_IP6);
4052
4053 VNC_ITRCCK;
4054
4055 switch (safi) {
4056 case SAFI_MPLS_VPN:
4057 rt = import_table->imported_vpn[afi];
4058 timer_service_func = rfapiWithdrawTimerVPN;
4059 break;
4060 case SAFI_ENCAP:
4061 rt = import_table->imported_encap[afi];
4062 timer_service_func = rfapiWithdrawTimerEncap;
4063 break;
4064 case SAFI_UNSPEC:
4065 case SAFI_UNICAST:
4066 case SAFI_MULTICAST:
4067 case SAFI_EVPN:
4068 case SAFI_LABELED_UNICAST:
4069 case SAFI_FLOWSPEC:
4070 case SAFI_MAX:
4071 /* Suppress uninitialized variable warning */
4072 rt = NULL;
4073 timer_service_func = NULL;
4074 assert(0);
4075 }
4076
4077 for (rn = agg_route_top(rt); rn; rn = agg_route_next(rn)) {
4078 for (bpi = rn->info; bpi; bpi = bpi->next) {
4079 if (bpi->peer == peer) {
4080
4081 if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) {
4082 /* already in holddown, skip */
4083 continue;
4084 }
4085
4086 if (safi == SAFI_MPLS_VPN) {
4087 RFAPI_UPDATE_ITABLE_COUNT(
4088 bpi, import_table, afi, -1);
4089 import_table->holddown_count[afi] += 1;
4090 }
4091 rfapiBiStartWithdrawTimer(import_table, rn, bpi,
4092 afi, safi,
4093 timer_service_func);
4094 }
4095 }
4096 }
4097 VNC_ITRCCK;
4098 }
4099
4100 /*
4101 * This gets called when a peer connection drops. We have to remove
4102 * all the routes from this peer.
4103 *
4104 * Current approach is crude. TBD Optimize by setting fewer timers and
4105 * grouping withdrawn routes so we can generate callbacks more
4106 * efficiently.
4107 */
4108 void rfapiProcessPeerDown(struct peer *peer)
4109 {
4110 struct bgp *bgp;
4111 struct rfapi *h;
4112 struct rfapi_import_table *it;
4113
4114 /*
4115 * If this peer is a "dummy" peer structure atached to a RFAPI
4116 * nve_descriptor, we don't need to walk the import tables
4117 * because the routes are already withdrawn by rfapi_close()
4118 */
4119 if (CHECK_FLAG(peer->flags, PEER_FLAG_IS_RFAPI_HD))
4120 return;
4121
4122 /*
4123 * 1. Visit all BPIs in all ENCAP import tables.
4124 * Start withdraw timer on the BPIs that match peer.
4125 *
4126 * 2. Visit All BPIs in all VPN import tables.
4127 * Start withdraw timer on the BPIs that match peer.
4128 */
4129
4130 bgp = bgp_get_default(); /* assume 1 instance for now */
4131 if (!bgp)
4132 return;
4133
4134 h = bgp->rfapi;
4135 assert(h);
4136
4137 for (it = h->imports; it; it = it->next) {
4138 rfapiProcessPeerDownRt(peer, it, AFI_IP, SAFI_ENCAP);
4139 rfapiProcessPeerDownRt(peer, it, AFI_IP6, SAFI_ENCAP);
4140 rfapiProcessPeerDownRt(peer, it, AFI_IP, SAFI_MPLS_VPN);
4141 rfapiProcessPeerDownRt(peer, it, AFI_IP6, SAFI_MPLS_VPN);
4142 }
4143
4144 if (h->it_ce) {
4145 rfapiProcessPeerDownRt(peer, h->it_ce, AFI_IP, SAFI_MPLS_VPN);
4146 rfapiProcessPeerDownRt(peer, h->it_ce, AFI_IP6, SAFI_MPLS_VPN);
4147 }
4148 }
4149
4150 /*
4151 * Import an entire RIB (for an afi/safi) to an import table RIB,
4152 * filtered according to the import table's RT list
4153 *
4154 * TBD: does this function need additions to match rfapiProcessUpdate()
4155 * for, e.g., L2 handling?
4156 */
4157 static void rfapiBgpTableFilteredImport(struct bgp *bgp,
4158 struct rfapi_import_table *it,
4159 afi_t afi, safi_t safi)
4160 {
4161 struct bgp_dest *dest1;
4162 struct bgp_dest *dest2;
4163
4164 /* Only these SAFIs have 2-level RIBS */
4165 assert(safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP);
4166
4167 /*
4168 * Now visit all the rd nodes and the nodes of all the
4169 * route tables attached to them, and import the routes
4170 * if they have matching route targets
4171 */
4172 for (dest1 = bgp_table_top(bgp->rib[afi][safi]); dest1;
4173 dest1 = bgp_route_next(dest1)) {
4174
4175 if (bgp_dest_has_bgp_path_info_data(dest1)) {
4176
4177 for (dest2 = bgp_table_top(
4178 bgp_dest_get_bgp_table_info(dest1));
4179 dest2; dest2 = bgp_route_next(dest2)) {
4180
4181 struct bgp_path_info *bpi;
4182
4183 for (bpi = bgp_dest_get_bgp_path_info(dest2);
4184 bpi; bpi = bpi->next) {
4185 uint32_t label = 0;
4186
4187 if (CHECK_FLAG(bpi->flags,
4188 BGP_PATH_REMOVED))
4189 continue;
4190
4191 if (bpi->extra)
4192 label = decode_label(
4193 &bpi->extra->label[0]);
4194 (*rfapiBgpInfoFilteredImportFunction(
4195 safi))(
4196 it, /* which import table */
4197 FIF_ACTION_UPDATE, bpi->peer,
4198 NULL,
4199 bgp_dest_get_prefix(dest2),
4200 NULL, afi,
4201 (struct prefix_rd *)
4202 bgp_dest_get_prefix(
4203 dest1),
4204 bpi->attr, bpi->type,
4205 bpi->sub_type, &label);
4206 }
4207 }
4208 }
4209 }
4210 }
4211
4212
4213 /* per-bgp-instance rfapi data */
4214 struct rfapi *bgp_rfapi_new(struct bgp *bgp)
4215 {
4216 struct rfapi *h;
4217 afi_t afi;
4218 struct rfapi_rfp_cfg *cfg = NULL;
4219 struct rfapi_rfp_cb_methods *cbm = NULL;
4220
4221 assert(bgp->rfapi_cfg == NULL);
4222
4223 h = XCALLOC(MTYPE_RFAPI, sizeof(struct rfapi));
4224
4225 for (afi = AFI_IP; afi < AFI_MAX; afi++) {
4226 h->un[afi] = agg_table_init();
4227 }
4228
4229 /*
4230 * initialize the ce import table
4231 */
4232 h->it_ce = XCALLOC(MTYPE_RFAPI_IMPORTTABLE,
4233 sizeof(struct rfapi_import_table));
4234 h->it_ce->imported_vpn[AFI_IP] = agg_table_init();
4235 h->it_ce->imported_vpn[AFI_IP6] = agg_table_init();
4236 h->it_ce->imported_encap[AFI_IP] = agg_table_init();
4237 h->it_ce->imported_encap[AFI_IP6] = agg_table_init();
4238 rfapiBgpTableFilteredImport(bgp, h->it_ce, AFI_IP, SAFI_MPLS_VPN);
4239 rfapiBgpTableFilteredImport(bgp, h->it_ce, AFI_IP6, SAFI_MPLS_VPN);
4240
4241 /*
4242 * Set up work queue for deferred rfapi_close operations
4243 */
4244 h->deferred_close_q =
4245 work_queue_new(bm->master, "rfapi deferred close");
4246 h->deferred_close_q->spec.workfunc = rfapi_deferred_close_workfunc;
4247 h->deferred_close_q->spec.data = h;
4248
4249 h->rfp = rfp_start(bm->master, &cfg, &cbm);
4250 bgp->rfapi_cfg = bgp_rfapi_cfg_new(cfg);
4251 if (cbm != NULL) {
4252 h->rfp_methods = *cbm;
4253 }
4254 return h;
4255 }
4256
4257 void bgp_rfapi_destroy(struct bgp *bgp, struct rfapi *h)
4258 {
4259 afi_t afi;
4260
4261 if (bgp == NULL || h == NULL)
4262 return;
4263
4264 if (h->resolve_nve_nexthop) {
4265 skiplist_free(h->resolve_nve_nexthop);
4266 h->resolve_nve_nexthop = NULL;
4267 }
4268
4269 rfapiImportTableFlush(h->it_ce);
4270
4271 if (h->import_mac) {
4272 struct rfapi_import_table *it;
4273 void *cursor;
4274 int rc;
4275
4276 for (cursor = NULL,
4277 rc = skiplist_next(h->import_mac, NULL, (void **)&it,
4278 &cursor);
4279 !rc; rc = skiplist_next(h->import_mac, NULL, (void **)&it,
4280 &cursor)) {
4281
4282 rfapiImportTableFlush(it);
4283 XFREE(MTYPE_RFAPI_IMPORTTABLE, it);
4284 }
4285 skiplist_free(h->import_mac);
4286 h->import_mac = NULL;
4287 }
4288
4289 work_queue_free_and_null(&h->deferred_close_q);
4290
4291 if (h->rfp != NULL)
4292 rfp_stop(h->rfp);
4293
4294 for (afi = AFI_IP; afi < AFI_MAX; afi++) {
4295 agg_table_finish(h->un[afi]);
4296 }
4297
4298 XFREE(MTYPE_RFAPI_IMPORTTABLE, h->it_ce);
4299 XFREE(MTYPE_RFAPI, h);
4300 }
4301
4302 struct rfapi_import_table *
4303 rfapiImportTableRefAdd(struct bgp *bgp, struct ecommunity *rt_import_list,
4304 struct rfapi_nve_group_cfg *rfg)
4305 {
4306 struct rfapi *h;
4307 struct rfapi_import_table *it;
4308 afi_t afi;
4309
4310 h = bgp->rfapi;
4311 assert(h);
4312
4313 for (it = h->imports; it; it = it->next) {
4314 if (ecommunity_cmp(it->rt_import_list, rt_import_list))
4315 break;
4316 }
4317
4318 vnc_zlog_debug_verbose("%s: matched it=%p", __func__, it);
4319
4320 if (!it) {
4321 it = XCALLOC(MTYPE_RFAPI_IMPORTTABLE,
4322 sizeof(struct rfapi_import_table));
4323 it->next = h->imports;
4324 h->imports = it;
4325
4326 it->rt_import_list = ecommunity_dup(rt_import_list);
4327 it->rfg = rfg;
4328 it->monitor_exterior_orphans =
4329 skiplist_new(0, NULL, prefix_free_lists);
4330
4331 /*
4332 * fill import route tables from RIBs
4333 *
4334 * Potential area for optimization. If this occurs when
4335 * tables are large (e.g., the operator adds a nve group
4336 * with a new RT list to a running system), it could take
4337 * a while.
4338 *
4339 */
4340 for (afi = AFI_IP; afi < AFI_MAX; ++afi) {
4341
4342 it->imported_vpn[afi] = agg_table_init();
4343 it->imported_encap[afi] = agg_table_init();
4344
4345 rfapiBgpTableFilteredImport(bgp, it, afi,
4346 SAFI_MPLS_VPN);
4347 rfapiBgpTableFilteredImport(bgp, it, afi, SAFI_ENCAP);
4348
4349 vnc_import_bgp_exterior_redist_enable_it(bgp, afi, it);
4350 }
4351 }
4352
4353 it->refcount += 1;
4354
4355 return it;
4356 }
4357
4358 /*
4359 * skiplist element free function
4360 */
4361 static void delete_rem_pfx_na_free(void *na)
4362 {
4363 uint32_t *pCounter = ((struct rfapi_nve_addr *)na)->info;
4364
4365 *pCounter += 1;
4366 XFREE(MTYPE_RFAPI_NVE_ADDR, na);
4367 }
4368
4369 /*
4370 * Common deleter for IP and MAC import tables
4371 */
4372 static void rfapiDeleteRemotePrefixesIt(
4373 struct bgp *bgp, struct rfapi_import_table *it, struct prefix *un,
4374 struct prefix *vn, struct prefix *p, int delete_active,
4375 int delete_holddown, uint32_t *pARcount, uint32_t *pAHcount,
4376 uint32_t *pHRcount, uint32_t *pHHcount,
4377 struct skiplist *uniq_active_nves, struct skiplist *uniq_holddown_nves)
4378 {
4379 afi_t afi;
4380
4381 #ifdef DEBUG_L2_EXTRA
4382 {
4383 char buf_pfx[PREFIX_STRLEN];
4384
4385 if (p) {
4386 prefix2str(p, buf_pfx, sizeof(buf_pfx));
4387 } else {
4388 buf_pfx[0] = '*';
4389 buf_pfx[1] = 0;
4390 }
4391
4392 vnc_zlog_debug_verbose(
4393 "%s: entry, p=%s, delete_active=%d, delete_holddown=%d",
4394 __func__, buf_pfx, delete_active, delete_holddown);
4395 }
4396 #endif
4397
4398 for (afi = AFI_IP; afi < AFI_MAX; ++afi) {
4399
4400 struct agg_table *rt;
4401 struct agg_node *rn;
4402
4403 if (p && (family2afi(p->family) != afi)) {
4404 continue;
4405 }
4406
4407 rt = it->imported_vpn[afi];
4408 if (!rt)
4409 continue;
4410
4411 vnc_zlog_debug_verbose("%s: scanning rt for afi=%d", __func__,
4412 afi);
4413
4414 for (rn = agg_route_top(rt); rn; rn = agg_route_next(rn)) {
4415 struct bgp_path_info *bpi;
4416 struct bgp_path_info *next;
4417 const struct prefix *rn_p = agg_node_get_prefix(rn);
4418
4419 if (p && VNC_DEBUG(IMPORT_DEL_REMOTE))
4420 vnc_zlog_debug_any("%s: want %pFX, have %pRN",
4421 __func__, p, rn);
4422
4423 if (p && prefix_cmp(p, rn_p))
4424 continue;
4425
4426 vnc_zlog_debug_verbose("%s: rn pfx=%pRN", __func__, rn);
4427
4428 /* TBD is this valid for afi == AFI_L2VPN? */
4429 RFAPI_CHECK_REFCOUNT(rn, SAFI_MPLS_VPN, 1);
4430
4431 for (bpi = rn->info; bpi; bpi = next) {
4432 next = bpi->next;
4433
4434 struct prefix qpt;
4435 struct prefix qct;
4436 int qpt_valid = 0;
4437 int qct_valid = 0;
4438 int is_active = 0;
4439
4440 vnc_zlog_debug_verbose("%s: examining bpi %p",
4441 __func__, bpi);
4442
4443 if (!rfapiGetNexthop(bpi->attr, &qpt))
4444 qpt_valid = 1;
4445
4446 if (vn) {
4447 if (!qpt_valid
4448 || !prefix_match(vn, &qpt)) {
4449 #ifdef DEBUG_L2_EXTRA
4450 vnc_zlog_debug_verbose(
4451 "%s: continue at vn && !qpt_valid || !prefix_match(vn, &qpt)",
4452 __func__);
4453 #endif
4454 continue;
4455 }
4456 }
4457
4458 if (!rfapiGetUnAddrOfVpnBi(bpi, &qct))
4459 qct_valid = 1;
4460
4461 if (un) {
4462 if (!qct_valid
4463 || !prefix_match(un, &qct)) {
4464 #ifdef DEBUG_L2_EXTRA
4465 vnc_zlog_debug_verbose(
4466 "%s: continue at un && !qct_valid || !prefix_match(un, &qct)",
4467 __func__);
4468 #endif
4469 continue;
4470 }
4471 }
4472
4473
4474 /*
4475 * Blow bpi away
4476 */
4477 /*
4478 * If this route is waiting to be deleted
4479 * because of
4480 * a previous withdraw, we must cancel its
4481 * timer.
4482 */
4483 if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) {
4484 if (!delete_holddown)
4485 continue;
4486 if (bpi->extra->vnc.import.timer) {
4487 struct rfapi_withdraw *wcb =
4488 THREAD_ARG(
4489 bpi->extra->vnc
4490 .import
4491 .timer);
4492
4493 wcb->import_table
4494 ->holddown_count[afi] -=
4495 1;
4496 RFAPI_UPDATE_ITABLE_COUNT(
4497 bpi, wcb->import_table,
4498 afi, 1);
4499 XFREE(MTYPE_RFAPI_WITHDRAW,
4500 wcb);
4501 THREAD_OFF(
4502 bpi->extra->vnc.import
4503 .timer);
4504 }
4505 } else {
4506 if (!delete_active)
4507 continue;
4508 is_active = 1;
4509 }
4510
4511 vnc_zlog_debug_verbose(
4512 "%s: deleting bpi %p (qct_valid=%d, qpt_valid=%d, delete_holddown=%d, delete_active=%d)",
4513 __func__, bpi, qct_valid, qpt_valid,
4514 delete_holddown, delete_active);
4515
4516
4517 /*
4518 * add nve to list
4519 */
4520 if (qct_valid && qpt_valid) {
4521
4522 struct rfapi_nve_addr na;
4523 struct rfapi_nve_addr *nap;
4524
4525 memset(&na, 0, sizeof(na));
4526 assert(!rfapiQprefix2Raddr(&qct,
4527 &na.un));
4528 assert(!rfapiQprefix2Raddr(&qpt,
4529 &na.vn));
4530
4531 if (skiplist_search(
4532 (is_active
4533 ? uniq_active_nves
4534 : uniq_holddown_nves),
4535 &na, (void **)&nap)) {
4536 char line[BUFSIZ];
4537
4538 nap = XCALLOC(
4539 MTYPE_RFAPI_NVE_ADDR,
4540 sizeof(struct
4541 rfapi_nve_addr));
4542 *nap = na;
4543 nap->info = is_active
4544 ? pAHcount
4545 : pHHcount;
4546 skiplist_insert(
4547 (is_active
4548 ? uniq_active_nves
4549 : uniq_holddown_nves),
4550 nap, nap);
4551
4552 rfapiNveAddr2Str(nap, line,
4553 BUFSIZ);
4554 }
4555 }
4556
4557 vnc_direct_bgp_rh_del_route(bgp, afi, rn_p,
4558 bpi->peer);
4559
4560 RFAPI_UPDATE_ITABLE_COUNT(bpi, it, afi, -1);
4561 it->holddown_count[afi] += 1;
4562 rfapiExpireVpnNow(it, rn, bpi, 1);
4563
4564 vnc_zlog_debug_verbose(
4565 "%s: incrementing count (is_active=%d)",
4566 __func__, is_active);
4567
4568 if (is_active)
4569 ++*pARcount;
4570 else
4571 ++*pHRcount;
4572 }
4573 }
4574 }
4575 }
4576
4577
4578 /*
4579 * For use by the "clear vnc prefixes" command
4580 */
4581 /*------------------------------------------
4582 * rfapiDeleteRemotePrefixes
4583 *
4584 * UI helper: For use by the "clear vnc prefixes" command
4585 *
4586 * input:
4587 * un if set, tunnel must match this prefix
4588 * vn if set, nexthop prefix must match this prefix
4589 * p if set, prefix must match this prefix
4590 * it if set, only look in this import table
4591 *
4592 * output
4593 * pARcount number of active routes deleted
4594 * pAHcount number of active nves deleted
4595 * pHRcount number of holddown routes deleted
4596 * pHHcount number of holddown nves deleted
4597 *
4598 * return value:
4599 * void
4600 --------------------------------------------*/
4601 void rfapiDeleteRemotePrefixes(struct prefix *un, struct prefix *vn,
4602 struct prefix *p,
4603 struct rfapi_import_table *arg_it,
4604 int delete_active, int delete_holddown,
4605 uint32_t *pARcount, uint32_t *pAHcount,
4606 uint32_t *pHRcount, uint32_t *pHHcount)
4607 {
4608 struct bgp *bgp;
4609 struct rfapi *h;
4610 struct rfapi_import_table *it;
4611 uint32_t deleted_holddown_route_count = 0;
4612 uint32_t deleted_active_route_count = 0;
4613 uint32_t deleted_holddown_nve_count = 0;
4614 uint32_t deleted_active_nve_count = 0;
4615 struct skiplist *uniq_holddown_nves;
4616 struct skiplist *uniq_active_nves;
4617
4618 VNC_ITRCCK;
4619
4620 bgp = bgp_get_default(); /* assume 1 instance for now */
4621 /* If no bgp instantiated yet, no vnc prefixes exist */
4622 if (!bgp)
4623 return;
4624
4625 h = bgp->rfapi;
4626 assert(h);
4627
4628 uniq_holddown_nves =
4629 skiplist_new(0, rfapi_nve_addr_cmp, delete_rem_pfx_na_free);
4630 uniq_active_nves =
4631 skiplist_new(0, rfapi_nve_addr_cmp, delete_rem_pfx_na_free);
4632
4633 /*
4634 * Iterate over all import tables; do a filtered import
4635 * for the afi/safi combination
4636 */
4637
4638 if (arg_it)
4639 it = arg_it;
4640 else
4641 it = h->imports;
4642 for (; it;) {
4643
4644 vnc_zlog_debug_verbose(
4645 "%s: calling rfapiDeleteRemotePrefixesIt() on (IP) import %p",
4646 __func__, it);
4647
4648 rfapiDeleteRemotePrefixesIt(
4649 bgp, it, un, vn, p, delete_active, delete_holddown,
4650 &deleted_active_route_count, &deleted_active_nve_count,
4651 &deleted_holddown_route_count,
4652 &deleted_holddown_nve_count, uniq_active_nves,
4653 uniq_holddown_nves);
4654
4655 if (arg_it)
4656 it = NULL;
4657 else
4658 it = it->next;
4659 }
4660
4661 /*
4662 * Now iterate over L2 import tables
4663 */
4664 if (h->import_mac && !(p && (p->family != AF_ETHERNET))) {
4665
4666 void *cursor = NULL;
4667 int rc;
4668
4669 for (cursor = NULL,
4670 rc = skiplist_next(h->import_mac, NULL, (void **)&it,
4671 &cursor);
4672 !rc; rc = skiplist_next(h->import_mac, NULL, (void **)&it,
4673 &cursor)) {
4674
4675 vnc_zlog_debug_verbose(
4676 "%s: calling rfapiDeleteRemotePrefixesIt() on import_mac %p",
4677 __func__, it);
4678
4679 rfapiDeleteRemotePrefixesIt(
4680 bgp, it, un, vn, p, delete_active,
4681 delete_holddown, &deleted_active_route_count,
4682 &deleted_active_nve_count,
4683 &deleted_holddown_route_count,
4684 &deleted_holddown_nve_count, uniq_active_nves,
4685 uniq_holddown_nves);
4686 }
4687 }
4688
4689 /*
4690 * our custom element freeing function above counts as it deletes
4691 */
4692 skiplist_free(uniq_holddown_nves);
4693 skiplist_free(uniq_active_nves);
4694
4695 if (pARcount)
4696 *pARcount = deleted_active_route_count;
4697 if (pAHcount)
4698 *pAHcount = deleted_active_nve_count;
4699 if (pHRcount)
4700 *pHRcount = deleted_holddown_route_count;
4701 if (pHHcount)
4702 *pHHcount = deleted_holddown_nve_count;
4703
4704 VNC_ITRCCK;
4705 }
4706
4707 /*------------------------------------------
4708 * rfapiCountRemoteRoutes
4709 *
4710 * UI helper: count VRF routes from BGP side
4711 *
4712 * input:
4713 *
4714 * output
4715 * pALRcount count of active local routes
4716 * pARRcount count of active remote routes
4717 * pHRcount count of holddown routes
4718 * pIRcount count of direct imported routes
4719 *
4720 * return value:
4721 * void
4722 --------------------------------------------*/
4723 void rfapiCountAllItRoutes(int *pALRcount, /* active local routes */
4724 int *pARRcount, /* active remote routes */
4725 int *pHRcount, /* holddown routes */
4726 int *pIRcount) /* imported routes */
4727 {
4728 struct bgp *bgp;
4729 struct rfapi *h;
4730 struct rfapi_import_table *it;
4731 afi_t afi;
4732
4733 int total_active_local = 0;
4734 int total_active_remote = 0;
4735 int total_holddown = 0;
4736 int total_imported = 0;
4737
4738 bgp = bgp_get_default(); /* assume 1 instance for now */
4739 assert(bgp);
4740
4741 h = bgp->rfapi;
4742 assert(h);
4743
4744 /*
4745 * Iterate over all import tables; do a filtered import
4746 * for the afi/safi combination
4747 */
4748
4749 for (it = h->imports; it; it = it->next) {
4750
4751 for (afi = AFI_IP; afi < AFI_MAX; ++afi) {
4752
4753 total_active_local += it->local_count[afi];
4754 total_active_remote += it->remote_count[afi];
4755 total_holddown += it->holddown_count[afi];
4756 total_imported += it->imported_count[afi];
4757 }
4758 }
4759
4760 void *cursor;
4761 int rc;
4762
4763 if (h->import_mac) {
4764 for (cursor = NULL,
4765 rc = skiplist_next(h->import_mac, NULL, (void **)&it,
4766 &cursor);
4767 !rc; rc = skiplist_next(h->import_mac, NULL, (void **)&it,
4768 &cursor)) {
4769
4770 total_active_local += it->local_count[AFI_L2VPN];
4771 total_active_remote += it->remote_count[AFI_L2VPN];
4772 total_holddown += it->holddown_count[AFI_L2VPN];
4773 total_imported += it->imported_count[AFI_L2VPN];
4774 }
4775 }
4776
4777
4778 if (pALRcount) {
4779 *pALRcount = total_active_local;
4780 }
4781 if (pARRcount) {
4782 *pARRcount = total_active_remote;
4783 }
4784 if (pHRcount) {
4785 *pHRcount = total_holddown;
4786 }
4787 if (pIRcount) {
4788 *pIRcount = total_imported;
4789 }
4790 }
4791
4792 /*------------------------------------------
4793 * rfapiGetHolddownFromLifetime
4794 *
4795 * calculate holddown value based on lifetime
4796 *
4797 * input:
4798 * lifetime lifetime
4799 *
4800 * return value:
4801 * Holddown value based on lifetime, holddown_factor,
4802 * and RFAPI_LIFETIME_INFINITE_WITHDRAW_DELAY
4803 *
4804 --------------------------------------------*/
4805 /* hold down time maxes out at RFAPI_LIFETIME_INFINITE_WITHDRAW_DELAY */
4806 uint32_t rfapiGetHolddownFromLifetime(uint32_t lifetime)
4807 {
4808 uint32_t factor;
4809 struct bgp *bgp;
4810
4811 bgp = bgp_get_default();
4812 if (bgp && bgp->rfapi_cfg)
4813 factor = bgp->rfapi_cfg->rfp_cfg.holddown_factor;
4814 else
4815 factor = RFAPI_RFP_CFG_DEFAULT_HOLDDOWN_FACTOR;
4816
4817 if (factor < 100 || lifetime < RFAPI_LIFETIME_INFINITE_WITHDRAW_DELAY)
4818 lifetime = lifetime * factor / 100;
4819 if (lifetime < RFAPI_LIFETIME_INFINITE_WITHDRAW_DELAY)
4820 return lifetime;
4821 else
4822 return RFAPI_LIFETIME_INFINITE_WITHDRAW_DELAY;
4823 }