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