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