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