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