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