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