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