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