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