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