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