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