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