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