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