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