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