3 * Copyright 2009-2016, LabN Consulting, L.L.C.
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.
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.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 * File: rfapi_import.c
23 * Purpose: Handle import of routes from BGP to RFAPI
26 #include "lib/zebra.h"
27 #include "lib/prefix.h"
28 #include "lib/agg_table.h"
30 #include "lib/memory.h"
32 #include "lib/skiplist.h"
33 #include "lib/thread.h"
34 #include "lib/stream.h"
35 #include "lib/lib_errors.h"
37 #include "bgpd/bgpd.h"
38 #include "bgpd/bgp_ecommunity.h"
39 #include "bgpd/bgp_attr.h"
40 #include "bgpd/bgp_route.h"
41 #include "bgpd/bgp_mplsvpn.h" /* prefix_rd2str() */
42 #include "bgpd/bgp_vnc_types.h"
43 #include "bgpd/bgp_rd.h"
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"
62 #ifdef HAVE_GLIBC_BACKTRACE
63 /* for backtrace and friends */
65 #endif /* HAVE_GLIBC_BACKTRACE */
67 #undef DEBUG_MONITOR_MOVE_SHORTER
68 #undef DEBUG_RETURNED_NHL
69 #undef DEBUG_ROUTE_COUNTERS
70 #undef DEBUG_ENCAP_MONITOR
73 #undef DEBUG_BI_SEARCH
76 * Allocated for each withdraw timer instance; freed when the timer
77 * expires or is canceled
79 struct rfapi_withdraw
{
80 struct rfapi_import_table
*import_table
;
81 struct agg_node
*node
;
82 struct bgp_path_info
*info
;
83 safi_t safi
; /* used only for bulk operations */
85 * For import table node reference count checking (i.e., debugging).
86 * Normally when a timer expires, lockoffset should be 0. However, if
87 * the timer expiration function is called directly (e.g.,
88 * rfapiExpireVpnNow), the node could be locked by a preceding
89 * agg_route_top() or agg_route_next() in a loop, so we need to pass
97 * It's evil and fiendish. It's compiler-dependent.
98 * ? Might need LDFLAGS -rdynamic to produce all function names
100 void rfapiDebugBacktrace(void)
102 #ifdef HAVE_GLIBC_BACKTRACE
103 #define RFAPI_DEBUG_BACKTRACE_NENTRIES 200
104 void *buf
[RFAPI_DEBUG_BACKTRACE_NENTRIES
];
109 size
= backtrace(buf
, RFAPI_DEBUG_BACKTRACE_NENTRIES
);
110 syms
= backtrace_symbols(buf
, size
);
112 for (i
= 0; i
< size
&& i
< RFAPI_DEBUG_BACKTRACE_NENTRIES
; ++i
) {
113 vnc_zlog_debug_verbose("backtrace[%2zu]: %s", i
, syms
[i
]);
123 * Count remote routes and compare with actively-maintained values.
124 * Abort if they disagree.
126 void rfapiCheckRouteCount()
128 struct bgp
*bgp
= bgp_get_default();
130 struct rfapi_import_table
*it
;
138 for (it
= h
->imports
; it
; it
= it
->next
) {
139 for (afi
= AFI_IP
; afi
< AFI_MAX
; ++afi
) {
141 struct agg_table
*rt
;
144 int holddown_count
= 0;
146 int imported_count
= 0;
147 int remote_count
= 0;
149 rt
= it
->imported_vpn
[afi
];
151 for (rn
= agg_route_top(rt
); rn
;
152 rn
= agg_route_next(rn
)) {
153 struct bgp_path_info
*bpi
;
154 struct bgp_path_info
*next
;
156 for (bpi
= rn
->info
; bpi
; bpi
= next
) {
159 if (CHECK_FLAG(bpi
->flags
,
164 if (RFAPI_LOCAL_BI(bpi
)) {
167 if (RFAPI_DIRECT_IMPORT_BI(
178 if (it
->holddown_count
[afi
] != holddown_count
) {
179 vnc_zlog_debug_verbose(
180 "%s: it->holddown_count %d != holddown_count %d",
181 __func__
, it
->holddown_count
[afi
],
185 if (it
->remote_count
[afi
] != remote_count
) {
186 vnc_zlog_debug_verbose(
187 "%s: it->remote_count %d != remote_count %d",
188 __func__
, it
->remote_count
[afi
],
192 if (it
->imported_count
[afi
] != imported_count
) {
193 vnc_zlog_debug_verbose(
194 "%s: it->imported_count %d != imported_count %d",
195 __func__
, it
->imported_count
[afi
],
203 #if DEBUG_ROUTE_COUNTERS
204 #define VNC_ITRCCK do {rfapiCheckRouteCount();} while (0)
210 * Validate reference count for a node in an import table
212 * Normally lockoffset is 0 for nodes in quiescent state. However,
213 * agg_unlock_node will delete the node if it is called when
214 * node->lock == 1, and we have to validate the refcount before
215 * the node is deleted. In this case, we specify lockoffset 1.
217 void rfapiCheckRefcount(struct agg_node
*rn
, safi_t safi
, int lockoffset
)
219 unsigned int count_bpi
= 0;
220 unsigned int count_monitor
= 0;
221 struct bgp_path_info
*bpi
;
222 struct rfapi_monitor_encap
*hme
;
223 struct rfapi_monitor_vpn
*hmv
;
225 for (bpi
= rn
->info
; bpi
; bpi
= bpi
->next
)
230 ++count_monitor
; /* rfapi_it_extra */
237 for (hme
= RFAPI_MONITOR_ENCAP(rn
); hme
;
244 for (hmv
= RFAPI_MONITOR_VPN(rn
); hmv
; hmv
= hmv
->next
)
247 if (RFAPI_MONITOR_EXTERIOR(rn
)->source
) {
248 ++count_monitor
; /* sl */
250 for (rc
= skiplist_next(
251 RFAPI_MONITOR_EXTERIOR(rn
)->source
,
252 NULL
, NULL
, &cursor
);
255 RFAPI_MONITOR_EXTERIOR(rn
)->source
,
256 NULL
, NULL
, &cursor
)) {
258 ++count_monitor
; /* sl entry */
268 if (count_bpi
+ count_monitor
+ lockoffset
!= rn
->lock
) {
269 vnc_zlog_debug_verbose(
270 "%s: count_bpi=%d, count_monitor=%d, lockoffset=%d, rn->lock=%d",
271 __func__
, count_bpi
, count_monitor
, lockoffset
,
278 * Perform deferred rfapi_close operations that were queued
281 static wq_item_status
rfapi_deferred_close_workfunc(struct work_queue
*q
,
284 struct rfapi_descriptor
*rfd
= data
;
285 struct rfapi
*h
= q
->spec
.data
;
287 assert(!(h
->flags
& RFAPI_INCALLBACK
));
289 vnc_zlog_debug_verbose("%s: completed deferred close on handle %p",
295 * Extract layer 2 option from Encap TLVS in BGP attrs
297 int rfapiGetL2o(struct attr
*attr
, struct rfapi_l2address_option
*l2o
)
301 struct bgp_attr_encap_subtlv
*pEncap
;
303 for (pEncap
= attr
->vnc_subtlvs
; pEncap
;
304 pEncap
= pEncap
->next
) {
306 if (pEncap
->type
== BGP_VNC_SUBTLV_TYPE_RFPOPTION
) {
308 == RFAPI_VN_OPTION_TYPE_L2ADDR
) {
310 if (pEncap
->value
[1] == 14) {
311 memcpy(l2o
->macaddr
.octet
,
328 l2o
->logical_net_id
=
331 + ((pEncap
->value
[14]
334 + ((pEncap
->value
[13]
349 * Extract the lifetime from the Tunnel Encap attribute of a route in
352 int rfapiGetVncLifetime(struct attr
*attr
, uint32_t *lifetime
)
354 struct bgp_attr_encap_subtlv
*pEncap
;
356 *lifetime
= RFAPI_INFINITE_LIFETIME
; /* default to infinite */
360 for (pEncap
= attr
->vnc_subtlvs
; pEncap
;
361 pEncap
= pEncap
->next
) {
364 == BGP_VNC_SUBTLV_TYPE_LIFETIME
) { /* lifetime */
365 if (pEncap
->length
== 4) {
366 memcpy(lifetime
, pEncap
->value
, 4);
367 *lifetime
= ntohl(*lifetime
);
378 * Extract the tunnel type from the extended community
380 int rfapiGetTunnelType(struct attr
*attr
, bgp_encap_types
*type
)
382 *type
= BGP_ENCAP_TYPE_MPLS
; /* default to MPLS */
383 if (attr
&& attr
->ecommunity
) {
384 struct ecommunity
*ecom
= attr
->ecommunity
;
387 for (i
= 0; i
< (ecom
->size
* ECOMMUNITY_SIZE
);
388 i
+= ECOMMUNITY_SIZE
) {
392 if (ep
[0] == ECOMMUNITY_ENCODE_OPAQUE
393 && ep
[1] == ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP
) {
394 *type
= (ep
[6] << 8) + ep
[7];
405 * Look for UN address in Encap attribute
407 int rfapiGetVncTunnelUnAddr(struct attr
*attr
, struct prefix
*p
)
409 struct bgp_attr_encap_subtlv
*pEncap
;
410 bgp_encap_types tun_type
;
412 rfapiGetTunnelType(attr
, &tun_type
);
413 if (tun_type
== BGP_ENCAP_TYPE_MPLS
) {
416 /* MPLS carries UN address in next hop */
417 rfapiNexthop2Prefix(attr
, p
);
424 for (pEncap
= attr
->encap_subtlvs
; pEncap
;
425 pEncap
= pEncap
->next
) {
428 == BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT
) { /* un
431 switch (pEncap
->length
) {
436 memcpy(p
->u
.val
, pEncap
->value
,
443 p
->family
= AF_INET6
;
445 memcpy(p
->u
.val
, pEncap
->value
,
458 * Get UN address wherever it might be
460 int rfapiGetUnAddrOfVpnBi(struct bgp_path_info
*bpi
, struct prefix
*p
)
462 /* If it's in this route's VNC attribute, we're done */
463 if (!rfapiGetVncTunnelUnAddr(bpi
->attr
, p
))
466 * Otherwise, see if it's cached from a corresponding ENCAP SAFI
470 switch (bpi
->extra
->vnc
.import
.un_family
) {
473 p
->family
= bpi
->extra
->vnc
.import
.un_family
;
474 p
->u
.prefix4
= bpi
->extra
->vnc
.import
.un
.addr4
;
480 p
->family
= bpi
->extra
->vnc
.import
.un_family
;
481 p
->u
.prefix6
= bpi
->extra
->vnc
.import
.un
.addr6
;
488 #if DEBUG_ENCAP_MONITOR
489 vnc_zlog_debug_verbose(
490 "%s: bpi->extra->vnc.import.un_family is 0, no UN addr",
502 * Make a new bgp_path_info from gathered parameters
504 static struct bgp_path_info
*rfapiBgpInfoCreate(struct attr
*attr
,
505 struct peer
*peer
, void *rfd
,
506 struct prefix_rd
*prd
,
507 uint8_t type
, uint8_t sub_type
,
510 struct bgp_path_info
*new;
512 new = bgp_path_info_new();
517 new->attr
= bgp_attr_intern(attr
);
519 bgp_path_info_extra_get(new);
521 new->extra
->vnc
.import
.rd
= *prd
;
522 rfapi_time(&new->extra
->vnc
.import
.create_time
);
525 encode_label(*label
, &new->extra
->label
[0]);
527 new->sub_type
= sub_type
;
535 * Frees bgp_path_info as used in import tables (parts are not
536 * allocated exactly the way they are in the main RIBs)
538 static void rfapiBgpInfoFree(struct bgp_path_info
*goner
)
544 vnc_zlog_debug_verbose("%s: calling peer_unlock(%p), #%d",
545 __func__
, goner
->peer
,
547 peer_unlock(goner
->peer
);
551 bgp_attr_unintern(&goner
->attr
);
554 bgp_path_info_extra_free(&goner
->extra
);
555 XFREE(MTYPE_BGP_ROUTE
, goner
);
558 struct rfapi_import_table
*rfapiMacImportTableGetNoAlloc(struct bgp
*bgp
,
562 struct rfapi_import_table
*it
= NULL
;
563 uintptr_t lni_as_ptr
= lni
;
572 if (skiplist_search(h
->import_mac
, (void *)lni_as_ptr
, (void **)&it
))
578 struct rfapi_import_table
*rfapiMacImportTableGet(struct bgp
*bgp
, uint32_t lni
)
581 struct rfapi_import_table
*it
= NULL
;
582 uintptr_t lni_as_ptr
= lni
;
587 if (!h
->import_mac
) {
588 /* default cmp is good enough for LNI */
589 h
->import_mac
= skiplist_new(0, NULL
, NULL
);
592 if (skiplist_search(h
->import_mac
, (void *)lni_as_ptr
, (void **)&it
)) {
594 struct ecommunity
*enew
;
595 struct ecommunity_val eval
;
598 it
= XCALLOC(MTYPE_RFAPI_IMPORTTABLE
,
599 sizeof(struct rfapi_import_table
));
600 /* set RT list of new import table based on LNI */
601 memset((char *)&eval
, 0, sizeof(eval
));
602 eval
.val
[0] = 0; /* VNC L2VPN */
603 eval
.val
[1] = 2; /* VNC L2VPN */
604 eval
.val
[5] = (lni
>> 16) & 0xff;
605 eval
.val
[6] = (lni
>> 8) & 0xff;
606 eval
.val
[7] = (lni
>> 0) & 0xff;
608 enew
= ecommunity_new();
609 ecommunity_add_val(enew
, &eval
);
610 it
->rt_import_list
= enew
;
612 for (afi
= AFI_IP
; afi
< AFI_MAX
; ++afi
) {
613 it
->imported_vpn
[afi
] = agg_table_init();
614 it
->imported_encap
[afi
] = agg_table_init();
617 it
->l2_logical_net_id
= lni
;
619 skiplist_insert(h
->import_mac
, (void *)lni_as_ptr
, it
);
627 * Implement MONITOR_MOVE_SHORTER(original_node) from
628 * RFAPI-Import-Event-Handling.txt
630 * Returns pointer to the list of moved monitors
632 static struct rfapi_monitor_vpn
*
633 rfapiMonitorMoveShorter(struct agg_node
*original_vpn_node
, int lockoffset
)
635 struct bgp_path_info
*bpi
;
636 struct agg_node
*par
;
637 struct rfapi_monitor_vpn
*m
;
638 struct rfapi_monitor_vpn
*mlast
;
639 struct rfapi_monitor_vpn
*moved
;
641 int parent_already_refcounted
= 0;
643 RFAPI_CHECK_REFCOUNT(original_vpn_node
, SAFI_MPLS_VPN
, lockoffset
);
645 #if DEBUG_MONITOR_MOVE_SHORTER
647 char buf
[PREFIX_STRLEN
];
649 prefix2str(&original_vpn_node
->p
, buf
, sizeof(buf
));
650 vnc_zlog_debug_verbose("%s: called with node pfx=%s", __func__
,
656 * 1. If there is at least one bpi (either regular route or
657 * route marked as withdrawn, with a pending timer) at
658 * original_node with a valid UN address, we're done. Return.
660 for (bpi
= original_vpn_node
->info
; bpi
; bpi
= bpi
->next
) {
663 if (!rfapiGetUnAddrOfVpnBi(bpi
, &pfx
)) {
664 #if DEBUG_MONITOR_MOVE_SHORTER
665 vnc_zlog_debug_verbose(
666 "%s: have valid UN at original node, no change",
674 * 2. Travel up the tree (toward less-specific prefixes) from
675 * original_node to find the first node that has at least
676 * one route (even if it is only a withdrawn route) with a
677 * valid UN address. Call this node "Node P."
679 for (par
= agg_node_parent(original_vpn_node
); par
;
680 par
= agg_node_parent(par
)) {
681 for (bpi
= par
->info
; bpi
; bpi
= bpi
->next
) {
683 if (!rfapiGetUnAddrOfVpnBi(bpi
, &pfx
)) {
692 RFAPI_CHECK_REFCOUNT(par
, SAFI_MPLS_VPN
, 0);
696 * If no less-specific routes, try to use the 0/0 node
699 /* this isn't necessarily 0/0 */
700 par
= agg_route_table_top(original_vpn_node
);
703 * If we got the top node but it wasn't 0/0,
706 if (par
&& par
->p
.prefixlen
) {
707 agg_unlock_node(par
); /* maybe free */
712 ++parent_already_refcounted
;
717 * Create 0/0 node if it isn't there
720 struct prefix pfx_default
;
722 memset(&pfx_default
, 0, sizeof(pfx_default
));
723 pfx_default
.family
= original_vpn_node
->p
.family
;
725 /* creates default node if none exists */
726 par
= agg_node_get(agg_get_table(original_vpn_node
),
728 ++parent_already_refcounted
;
732 * 3. Move each of the monitors found at original_node to Node P.
733 * These are "Moved Monitors."
738 * Attach at end so that the list pointer we return points
739 * only to the moved routes
741 for (m
= RFAPI_MONITOR_VPN(par
), mlast
= NULL
; m
;
742 mlast
= m
, m
= m
->next
)
746 moved
= mlast
->next
= RFAPI_MONITOR_VPN(original_vpn_node
);
748 moved
= RFAPI_MONITOR_VPN_W_ALLOC(par
) =
749 RFAPI_MONITOR_VPN(original_vpn_node
);
751 if (RFAPI_MONITOR_VPN(
752 original_vpn_node
)) /* check agg, so not allocated */
753 RFAPI_MONITOR_VPN_W_ALLOC(original_vpn_node
) = NULL
;
756 * update the node pointers on the monitors
758 for (m
= moved
; m
; m
= m
->next
) {
763 RFAPI_CHECK_REFCOUNT(par
, SAFI_MPLS_VPN
,
764 parent_already_refcounted
- movecount
);
765 while (movecount
> parent_already_refcounted
) {
767 ++parent_already_refcounted
;
769 while (movecount
< parent_already_refcounted
) {
770 /* unlikely, but code defensively */
771 agg_unlock_node(par
);
772 --parent_already_refcounted
;
774 RFAPI_CHECK_REFCOUNT(original_vpn_node
, SAFI_MPLS_VPN
,
775 movecount
+ lockoffset
);
776 while (movecount
--) {
777 agg_unlock_node(original_vpn_node
);
780 #if DEBUG_MONITOR_MOVE_SHORTER
782 char buf
[PREFIX_STRLEN
];
784 prefix2str(&par
->p
, buf
, sizeof(buf
));
785 vnc_zlog_debug_verbose("%s: moved to node pfx=%s", __func__
,
795 * Implement MONITOR_MOVE_LONGER(new_node) from
796 * RFAPI-Import-Event-Handling.txt
798 static void rfapiMonitorMoveLonger(struct agg_node
*new_vpn_node
)
800 struct rfapi_monitor_vpn
*monitor
;
801 struct rfapi_monitor_vpn
*mlast
;
802 struct bgp_path_info
*bpi
;
803 struct agg_node
*par
;
805 RFAPI_CHECK_REFCOUNT(new_vpn_node
, SAFI_MPLS_VPN
, 0);
808 * Make sure we have at least one valid route at the new node
810 for (bpi
= new_vpn_node
->info
; bpi
; bpi
= bpi
->next
) {
812 if (!rfapiGetUnAddrOfVpnBi(bpi
, &pfx
))
817 vnc_zlog_debug_verbose(
818 "%s: no valid routes at node %p, so not attempting moves",
819 __func__
, new_vpn_node
);
824 * Find first parent node that has monitors
826 for (par
= agg_node_parent(new_vpn_node
); par
;
827 par
= agg_node_parent(par
)) {
828 if (RFAPI_MONITOR_VPN(par
))
833 vnc_zlog_debug_verbose(
834 "%s: no parent nodes with monitors, done", __func__
);
839 * Check each of these monitors to see of their longest-match
840 * is now the updated node. Move any such monitors to the more-
841 * specific updated node
843 for (mlast
= NULL
, monitor
= RFAPI_MONITOR_VPN(par
); monitor
;) {
846 * If new longest match for monitor prefix is the new
847 * route's prefix, move monitor to new route's prefix
849 if (prefix_match(&new_vpn_node
->p
, &monitor
->p
)) {
852 mlast
->next
= monitor
->next
;
854 RFAPI_MONITOR_VPN_W_ALLOC(par
) = monitor
->next
;
859 monitor
->next
= RFAPI_MONITOR_VPN(new_vpn_node
);
860 RFAPI_MONITOR_VPN_W_ALLOC(new_vpn_node
) = monitor
;
861 monitor
->node
= new_vpn_node
;
863 agg_lock_node(new_vpn_node
); /* incr refcount */
865 monitor
= mlast
? mlast
->next
: RFAPI_MONITOR_VPN(par
);
867 RFAPI_CHECK_REFCOUNT(par
, SAFI_MPLS_VPN
, 1);
868 /* decr refcount after we're done with par as this might
870 agg_unlock_node(par
);
875 monitor
= monitor
->next
;
878 RFAPI_CHECK_REFCOUNT(new_vpn_node
, SAFI_MPLS_VPN
, 0);
882 static void rfapiBgpInfoChainFree(struct bgp_path_info
*bpi
)
884 struct bgp_path_info
*next
;
889 * If there is a timer waiting to delete this bpi, cancel
890 * the timer and delete immediately
892 if (CHECK_FLAG(bpi
->flags
, BGP_PATH_REMOVED
)
893 && bpi
->extra
->vnc
.import
.timer
) {
896 (struct thread
*)bpi
->extra
->vnc
.import
.timer
;
897 struct rfapi_withdraw
*wcb
= t
->arg
;
899 XFREE(MTYPE_RFAPI_WITHDRAW
, wcb
);
905 rfapiBgpInfoFree(bpi
);
910 static void rfapiImportTableFlush(struct rfapi_import_table
*it
)
917 ecommunity_free(&it
->rt_import_list
);
918 it
->rt_import_list
= NULL
;
920 for (afi
= AFI_IP
; afi
< AFI_MAX
; ++afi
) {
924 for (rn
= agg_route_top(it
->imported_vpn
[afi
]); rn
;
925 rn
= agg_route_next(rn
)) {
927 * Each route_node has:
928 * aggregate: points to rfapi_it_extra with monitor
930 * info: points to chain of bgp_path_info
932 /* free bgp_path_info and its children */
933 rfapiBgpInfoChainFree(rn
->info
);
936 rfapiMonitorExtraFlush(SAFI_MPLS_VPN
, rn
);
939 for (rn
= agg_route_top(it
->imported_encap
[afi
]); rn
;
940 rn
= agg_route_next(rn
)) {
941 /* free bgp_path_info and its children */
942 rfapiBgpInfoChainFree(rn
->info
);
945 rfapiMonitorExtraFlush(SAFI_ENCAP
, rn
);
948 agg_table_finish(it
->imported_vpn
[afi
]);
949 agg_table_finish(it
->imported_encap
[afi
]);
951 if (it
->monitor_exterior_orphans
) {
952 skiplist_free(it
->monitor_exterior_orphans
);
956 void rfapiImportTableRefDelByIt(struct bgp
*bgp
,
957 struct rfapi_import_table
*it_target
)
960 struct rfapi_import_table
*it
;
961 struct rfapi_import_table
*prev
= NULL
;
968 for (it
= h
->imports
; it
; prev
= it
, it
= it
->next
) {
974 assert(it
->refcount
);
980 prev
->next
= it
->next
;
982 h
->imports
= it
->next
;
984 rfapiImportTableFlush(it
);
985 XFREE(MTYPE_RFAPI_IMPORTTABLE
, it
);
989 #if RFAPI_REQUIRE_ENCAP_BEEC
991 * Look for magic BGP Encapsulation Extended Community value
992 * Format in RFC 5512 Sect. 4.5
994 static int rfapiEcommunitiesMatchBeec(struct ecommunity
*ecom
,
995 bgp_encap_types type
)
1002 for (i
= 0; i
< (ecom
->size
* ECOMMUNITY_SIZE
); i
+= ECOMMUNITY_SIZE
) {
1008 if (ep
[0] == ECOMMUNITY_ENCODE_OPAQUE
1009 && ep
[1] == ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP
1010 && ep
[6] == ((type
&& 0xff00) >> 8)
1011 && ep
[7] == (type
& 0xff)) {
1020 int rfapiEcommunitiesIntersect(struct ecommunity
*e1
, struct ecommunity
*e2
)
1029 s1
= ecommunity_ecom2str(e1
, ECOMMUNITY_FORMAT_DISPLAY
, 0);
1030 s2
= ecommunity_ecom2str(e2
, ECOMMUNITY_FORMAT_DISPLAY
, 0);
1031 vnc_zlog_debug_verbose("%s: e1[%s], e2[%s]", __func__
, s1
, s2
);
1032 XFREE(MTYPE_ECOMMUNITY_STR
, s1
);
1033 XFREE(MTYPE_ECOMMUNITY_STR
, s2
);
1036 for (i
= 0; i
< e1
->size
; ++i
) {
1037 for (j
= 0; j
< e2
->size
; ++j
) {
1038 if (!memcmp(e1
->val
+ (i
* ECOMMUNITY_SIZE
),
1039 e2
->val
+ (j
* ECOMMUNITY_SIZE
),
1049 int rfapiEcommunityGetLNI(struct ecommunity
*ecom
, uint32_t *lni
)
1053 for (i
= 0; i
< ecom
->size
; ++i
) {
1054 uint8_t *p
= ecom
->val
+ (i
* ECOMMUNITY_SIZE
);
1056 if ((*(p
+ 0) == 0x00) && (*(p
+ 1) == 0x02)) {
1058 *lni
= (*(p
+ 5) << 16) | (*(p
+ 6) << 8)
1067 int rfapiEcommunityGetEthernetTag(struct ecommunity
*ecom
, uint16_t *tag_id
)
1069 struct bgp
*bgp
= bgp_get_default();
1070 *tag_id
= 0; /* default to untagged */
1073 for (i
= 0; i
< ecom
->size
; ++i
) {
1076 uint8_t *p
= ecom
->val
+ (i
* ECOMMUNITY_SIZE
);
1078 /* High-order octet of type. */
1081 if (*p
++ == ECOMMUNITY_ROUTE_TARGET
) {
1082 if (encode
== ECOMMUNITY_ENCODE_AS4
) {
1083 p
= ptr_get_be32(p
, &as
);
1084 } else if (encode
== ECOMMUNITY_ENCODE_AS
) {
1087 p
+= 2; /* skip next two, tag/vid
1088 always in lowest bytes */
1090 if (as
== bgp
->as
) {
1091 *tag_id
= *p
++ << 8;
1101 static int rfapiVpnBiNhEqualsPt(struct bgp_path_info
*bpi
,
1102 struct rfapi_ip_addr
*hpt
)
1109 family
= BGP_MP_NEXTHOP_FAMILY(bpi
->attr
->mp_nexthop_len
);
1111 if (hpt
->addr_family
!= family
)
1116 if (bpi
->attr
->mp_nexthop_global_in
.s_addr
1117 != hpt
->addr
.v4
.s_addr
)
1122 if (IPV6_ADDR_CMP(&bpi
->attr
->mp_nexthop_global
, &hpt
->addr
.v6
))
1136 * Compare 2 VPN BIs. Return true if they have the same VN and UN addresses
1138 static int rfapiVpnBiSamePtUn(struct bgp_path_info
*bpi1
,
1139 struct bgp_path_info
*bpi2
)
1141 struct prefix pfx_un1
;
1142 struct prefix pfx_un2
;
1147 if (!bpi1
->attr
|| !bpi2
->attr
)
1151 * VN address comparisons
1154 if (BGP_MP_NEXTHOP_FAMILY(bpi1
->attr
->mp_nexthop_len
)
1155 != BGP_MP_NEXTHOP_FAMILY(bpi2
->attr
->mp_nexthop_len
)) {
1159 switch (BGP_MP_NEXTHOP_FAMILY(bpi1
->attr
->mp_nexthop_len
)) {
1161 if (bpi1
->attr
->mp_nexthop_global_in
.s_addr
1162 != bpi2
->attr
->mp_nexthop_global_in
.s_addr
)
1167 if (IPV6_ADDR_CMP(&bpi1
->attr
->mp_nexthop_global
,
1168 &bpi2
->attr
->mp_nexthop_global
))
1178 * UN address comparisons
1180 if (rfapiGetVncTunnelUnAddr(bpi1
->attr
, &pfx_un1
)) {
1182 pfx_un1
.family
= bpi1
->extra
->vnc
.import
.un_family
;
1183 switch (bpi1
->extra
->vnc
.import
.un_family
) {
1186 bpi1
->extra
->vnc
.import
.un
.addr4
;
1190 bpi1
->extra
->vnc
.import
.un
.addr6
;
1199 if (rfapiGetVncTunnelUnAddr(bpi2
->attr
, &pfx_un2
)) {
1201 pfx_un2
.family
= bpi2
->extra
->vnc
.import
.un_family
;
1202 switch (bpi2
->extra
->vnc
.import
.un_family
) {
1205 bpi2
->extra
->vnc
.import
.un
.addr4
;
1209 bpi2
->extra
->vnc
.import
.un
.addr6
;
1218 if (!pfx_un1
.family
|| !pfx_un2
.family
)
1221 if (pfx_un1
.family
!= pfx_un2
.family
)
1224 switch (pfx_un1
.family
) {
1226 if (!IPV4_ADDR_SAME(&pfx_un1
.u
.prefix4
, &pfx_un2
.u
.prefix4
))
1230 if (!IPV6_ADDR_SAME(&pfx_un1
.u
.prefix6
, &pfx_un2
.u
.prefix6
))
1239 uint8_t rfapiRfpCost(struct attr
*attr
)
1241 if (attr
->flag
& ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF
)) {
1242 if (attr
->local_pref
> 255) {
1245 return 255 - attr
->local_pref
;
1251 /*------------------------------------------
1254 * Find Layer 2 options in an option chain
1260 * l2o layer 2 options extracted
1264 * 1 no options found
1266 --------------------------------------------*/
1267 int rfapi_extract_l2o(
1268 struct bgp_tea_options
*pHop
, /* chain of options */
1269 struct rfapi_l2address_option
*l2o
) /* return extracted value */
1271 struct bgp_tea_options
*p
;
1273 for (p
= pHop
; p
; p
= p
->next
) {
1274 if ((p
->type
== RFAPI_VN_OPTION_TYPE_L2ADDR
)
1275 && (p
->length
>= 8)) {
1279 memcpy(&l2o
->macaddr
, v
, 6);
1281 l2o
->label
= ((v
[6] << 12) & 0xff000)
1282 + ((v
[7] << 4) & 0xff0)
1283 + ((v
[8] >> 4) & 0xf);
1285 l2o
->local_nve_id
= (uint8_t)v
[10];
1287 l2o
->logical_net_id
=
1288 (v
[11] << 16) + (v
[12] << 8) + (v
[13] << 0);
1296 static struct rfapi_next_hop_entry
*
1297 rfapiRouteInfo2NextHopEntry(struct rfapi_ip_prefix
*rprefix
,
1298 struct bgp_path_info
*bpi
, /* route to encode */
1299 uint32_t lifetime
, /* use this in nhe */
1300 struct agg_node
*rn
) /* req for L2 eth addr */
1302 struct rfapi_next_hop_entry
*new;
1303 int have_vnc_tunnel_un
= 0;
1305 #if DEBUG_ENCAP_MONITOR
1306 vnc_zlog_debug_verbose("%s: entry, bpi %p, rn %p", __func__
, bpi
, rn
);
1309 new = XCALLOC(MTYPE_RFAPI_NEXTHOP
, sizeof(struct rfapi_next_hop_entry
));
1312 new->prefix
= *rprefix
;
1315 && decode_rd_type(bpi
->extra
->vnc
.import
.rd
.val
)
1316 == RD_TYPE_VNC_ETH
) {
1319 struct rfapi_vn_option
*vo
;
1321 vo
= XCALLOC(MTYPE_RFAPI_VN_OPTION
,
1322 sizeof(struct rfapi_vn_option
));
1325 vo
->type
= RFAPI_VN_OPTION_TYPE_L2ADDR
;
1327 memcpy(&vo
->v
.l2addr
.macaddr
, &rn
->p
.u
.prefix_eth
.octet
,
1329 /* only low 3 bytes of this are significant */
1331 (void)rfapiEcommunityGetLNI(
1332 bpi
->attr
->ecommunity
,
1333 &vo
->v
.l2addr
.logical_net_id
);
1334 (void)rfapiEcommunityGetEthernetTag(
1335 bpi
->attr
->ecommunity
, &vo
->v
.l2addr
.tag_id
);
1338 /* local_nve_id comes from lower byte of RD type */
1339 vo
->v
.l2addr
.local_nve_id
= bpi
->extra
->vnc
.import
.rd
.val
[1];
1341 /* label comes from MP_REACH_NLRI label */
1342 vo
->v
.l2addr
.label
= decode_label(&bpi
->extra
->label
[0]);
1344 new->vn_options
= vo
;
1347 * If there is an auxiliary prefix (i.e., host IP address),
1348 * use it as the nexthop prefix instead of the query prefix
1350 if (bpi
->extra
->vnc
.import
.aux_prefix
.family
) {
1351 rfapiQprefix2Rprefix(&bpi
->extra
->vnc
.import
.aux_prefix
,
1357 bgp_encap_types tun_type
;
1358 new->prefix
.cost
= rfapiRfpCost(bpi
->attr
);
1360 struct bgp_attr_encap_subtlv
*pEncap
;
1362 switch (BGP_MP_NEXTHOP_FAMILY(bpi
->attr
->mp_nexthop_len
)) {
1364 new->vn_address
.addr_family
= AF_INET
;
1365 new->vn_address
.addr
.v4
=
1366 bpi
->attr
->mp_nexthop_global_in
;
1370 new->vn_address
.addr_family
= AF_INET6
;
1371 new->vn_address
.addr
.v6
= bpi
->attr
->mp_nexthop_global
;
1375 zlog_warn("%s: invalid vpn nexthop length: %d",
1376 __func__
, bpi
->attr
->mp_nexthop_len
);
1377 rfapi_free_next_hop_list(new);
1381 for (pEncap
= bpi
->attr
->vnc_subtlvs
; pEncap
;
1382 pEncap
= pEncap
->next
) {
1383 switch (pEncap
->type
) {
1384 case BGP_VNC_SUBTLV_TYPE_LIFETIME
:
1385 /* use configured lifetime, not attr lifetime */
1389 zlog_warn("%s: unknown VNC option type %d",
1390 __func__
, pEncap
->type
);
1397 rfapiGetTunnelType(bpi
->attr
, &tun_type
);
1398 if (tun_type
== BGP_ENCAP_TYPE_MPLS
) {
1400 /* MPLS carries UN address in next hop */
1401 rfapiNexthop2Prefix(bpi
->attr
, &p
);
1402 if (p
.family
!= 0) {
1403 rfapiQprefix2Raddr(&p
, &new->un_address
);
1404 have_vnc_tunnel_un
= 1;
1408 for (pEncap
= bpi
->attr
->encap_subtlvs
; pEncap
;
1409 pEncap
= pEncap
->next
) {
1410 switch (pEncap
->type
) {
1411 case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT
:
1413 * Overrides ENCAP UN address, if any
1415 switch (pEncap
->length
) {
1418 new->un_address
.addr_family
= AF_INET
;
1419 memcpy(&new->un_address
.addr
.v4
,
1421 have_vnc_tunnel_un
= 1;
1425 new->un_address
.addr_family
= AF_INET6
;
1426 memcpy(&new->un_address
.addr
.v6
,
1428 have_vnc_tunnel_un
= 1;
1433 "%s: invalid tunnel subtlv UN addr length (%d) for bpi %p",
1434 __func__
, pEncap
->length
, bpi
);
1440 "%s: unknown Encap Attribute option type %d",
1441 __func__
, pEncap
->type
);
1448 new->un_options
= rfapi_encap_tlv_to_un_option(bpi
->attr
);
1450 #if DEBUG_ENCAP_MONITOR
1451 vnc_zlog_debug_verbose("%s: line %d: have_vnc_tunnel_un=%d",
1452 __func__
, __LINE__
, have_vnc_tunnel_un
);
1455 if (!have_vnc_tunnel_un
&& bpi
->extra
) {
1457 * use cached UN address from ENCAP route
1459 new->un_address
.addr_family
=
1460 bpi
->extra
->vnc
.import
.un_family
;
1461 switch (new->un_address
.addr_family
) {
1463 new->un_address
.addr
.v4
=
1464 bpi
->extra
->vnc
.import
.un
.addr4
;
1467 new->un_address
.addr
.v6
=
1468 bpi
->extra
->vnc
.import
.un
.addr6
;
1472 "%s: invalid UN addr family (%d) for bpi %p",
1473 __func__
, new->un_address
.addr_family
,
1475 rfapi_free_next_hop_list(new);
1482 new->lifetime
= lifetime
;
1486 int rfapiHasNonRemovedRoutes(struct agg_node
*rn
)
1488 struct bgp_path_info
*bpi
;
1490 for (bpi
= rn
->info
; bpi
; bpi
= bpi
->next
) {
1493 if (!CHECK_FLAG(bpi
->flags
, BGP_PATH_REMOVED
)
1494 && (bpi
->extra
&& !rfapiGetUnAddrOfVpnBi(bpi
, &pfx
))) {
1506 void rfapiDumpNode(struct agg_node
*rn
)
1508 struct bgp_path_info
*bpi
;
1510 vnc_zlog_debug_verbose("%s: rn=%p", __func__
, rn
);
1511 for (bpi
= rn
->info
; bpi
; bpi
= bpi
->next
) {
1513 int ctrc
= rfapiGetUnAddrOfVpnBi(bpi
, &pfx
);
1516 if (!CHECK_FLAG(bpi
->flags
, BGP_PATH_REMOVED
)
1517 && (bpi
->extra
&& !ctrc
)) {
1524 vnc_zlog_debug_verbose(
1525 " bpi=%p, nr=%d, flags=0x%x, extra=%p, ctrc=%d", bpi
,
1526 nr
, bpi
->flags
, bpi
->extra
, ctrc
);
1531 static int rfapiNhlAddNodeRoutes(
1532 struct agg_node
*rn
, /* in */
1533 struct rfapi_ip_prefix
*rprefix
, /* in */
1534 uint32_t lifetime
, /* in */
1535 int removed
, /* in */
1536 struct rfapi_next_hop_entry
**head
, /* in/out */
1537 struct rfapi_next_hop_entry
**tail
, /* in/out */
1538 struct rfapi_ip_addr
*exclude_vnaddr
, /* omit routes to same NVE */
1539 struct agg_node
*rfd_rib_node
, /* preload this NVE rib node */
1540 struct prefix
*pfx_target_original
) /* query target */
1542 struct bgp_path_info
*bpi
;
1543 struct rfapi_next_hop_entry
*new;
1544 struct prefix pfx_un
;
1545 struct skiplist
*seen_nexthops
;
1547 int is_l2
= (rn
->p
.family
== AF_ETHERNET
);
1550 struct agg_table
*atable
= agg_get_table(rfd_rib_node
);
1551 struct rfapi_descriptor
*rfd
;
1554 rfd
= agg_get_table_info(atable
);
1556 if (rfapiRibFTDFilterRecentPrefix(rfd
, rn
,
1557 pfx_target_original
))
1563 skiplist_new(0, vnc_prefix_cmp
, (void (*)(void *))prefix_free
);
1565 for (bpi
= rn
->info
; bpi
; bpi
= bpi
->next
) {
1567 struct prefix pfx_vn
;
1568 struct prefix
*newpfx
;
1570 if (removed
&& !CHECK_FLAG(bpi
->flags
, BGP_PATH_REMOVED
)) {
1571 #if DEBUG_RETURNED_NHL
1572 vnc_zlog_debug_verbose(
1573 "%s: want holddown, this route not holddown, skip",
1578 if (!removed
&& CHECK_FLAG(bpi
->flags
, BGP_PATH_REMOVED
)) {
1587 * Check for excluded VN address
1589 if (rfapiVpnBiNhEqualsPt(bpi
, exclude_vnaddr
))
1593 * Check for VN address (nexthop) copied already
1596 /* L2 routes: semantic nexthop in aux_prefix; VN addr
1598 pfx_vn
= bpi
->extra
->vnc
.import
.aux_prefix
;
1600 rfapiNexthop2Prefix(bpi
->attr
, &pfx_vn
);
1602 if (!skiplist_search(seen_nexthops
, &pfx_vn
, NULL
)) {
1603 #if DEBUG_RETURNED_NHL
1604 char buf
[PREFIX_STRLEN
];
1606 prefix2str(&pfx_vn
, buf
, sizeof(buf
));
1607 vnc_zlog_debug_verbose(
1608 "%s: already put VN/nexthop %s, skip", __func__
,
1614 if (rfapiGetUnAddrOfVpnBi(bpi
, &pfx_un
)) {
1615 #if DEBUG_ENCAP_MONITOR
1616 vnc_zlog_debug_verbose(
1617 "%s: failed to get UN address of this VPN bpi",
1623 newpfx
= prefix_new();
1625 skiplist_insert(seen_nexthops
, newpfx
, newpfx
);
1627 new = rfapiRouteInfo2NextHopEntry(rprefix
, bpi
, lifetime
, rn
);
1629 if (rfapiRibPreloadBi(rfd_rib_node
, &pfx_vn
, &pfx_un
,
1631 /* duplicate filtered by RIB */
1632 rfapi_free_next_hop_list(new);
1639 (*tail
)->next
= new;
1648 skiplist_free(seen_nexthops
);
1657 * omit_node is meant for the situation where we are adding a subtree
1658 * of a parent of some original requested node. The response already
1659 * contains the original requested node, and we don't want to duplicate
1660 * its routes in the list, so we skip it if the right or left node
1661 * matches (of course, we still travel down its child subtrees).
1663 static int rfapiNhlAddSubtree(
1664 struct agg_node
*rn
, /* in */
1665 uint32_t lifetime
, /* in */
1666 struct rfapi_next_hop_entry
**head
, /* in/out */
1667 struct rfapi_next_hop_entry
**tail
, /* in/out */
1668 struct agg_node
*omit_node
, /* in */
1669 struct rfapi_ip_addr
*exclude_vnaddr
, /* omit routes to same NVE */
1670 struct agg_table
*rfd_rib_table
, /* preload here */
1671 struct prefix
*pfx_target_original
) /* query target */
1673 struct rfapi_ip_prefix rprefix
;
1676 /* FIXME: need to find a better way here to work without sticking our
1677 * hands in node->link */
1678 if (agg_node_left(rn
) && agg_node_left(rn
) != omit_node
) {
1679 if (agg_node_left(rn
)->info
) {
1681 struct agg_node
*rib_rn
= NULL
;
1683 rfapiQprefix2Rprefix(&agg_node_left(rn
)->p
, &rprefix
);
1684 if (rfd_rib_table
) {
1685 rib_rn
= agg_node_get(rfd_rib_table
,
1686 &agg_node_left(rn
)->p
);
1689 count
= rfapiNhlAddNodeRoutes(
1690 agg_node_left(rn
), &rprefix
, lifetime
, 0, head
,
1691 tail
, exclude_vnaddr
, rib_rn
,
1692 pfx_target_original
);
1694 count
= rfapiNhlAddNodeRoutes(
1695 agg_node_left(rn
), &rprefix
, lifetime
,
1696 1, head
, tail
, exclude_vnaddr
, rib_rn
,
1697 pfx_target_original
);
1701 agg_unlock_node(rib_rn
);
1705 if (agg_node_right(rn
) && agg_node_right(rn
) != omit_node
) {
1706 if (agg_node_right(rn
)->info
) {
1708 struct agg_node
*rib_rn
= NULL
;
1710 rfapiQprefix2Rprefix(&agg_node_right(rn
)->p
, &rprefix
);
1711 if (rfd_rib_table
) {
1712 rib_rn
= agg_node_get(rfd_rib_table
,
1713 &agg_node_right(rn
)->p
);
1715 count
= rfapiNhlAddNodeRoutes(
1716 agg_node_right(rn
), &rprefix
, lifetime
, 0, head
,
1717 tail
, exclude_vnaddr
, rib_rn
,
1718 pfx_target_original
);
1720 count
= rfapiNhlAddNodeRoutes(
1721 agg_node_right(rn
), &rprefix
, lifetime
,
1722 1, head
, tail
, exclude_vnaddr
, rib_rn
,
1723 pfx_target_original
);
1727 agg_unlock_node(rib_rn
);
1731 if (agg_node_left(rn
)) {
1732 rcount
+= rfapiNhlAddSubtree(
1733 agg_node_left(rn
), lifetime
, head
, tail
, omit_node
,
1734 exclude_vnaddr
, rfd_rib_table
, pfx_target_original
);
1736 if (agg_node_right(rn
)) {
1737 rcount
+= rfapiNhlAddSubtree(
1738 agg_node_right(rn
), lifetime
, head
, tail
, omit_node
,
1739 exclude_vnaddr
, rfd_rib_table
, pfx_target_original
);
1746 * Implementation of ROUTE_LIST(node) from RFAPI-Import-Event-Handling.txt
1748 * Construct an rfapi nexthop list based on the routes attached to
1749 * the specified node.
1751 * If there are any routes that do NOT have BGP_PATH_REMOVED set,
1752 * return those only. If there are ONLY routes with BGP_PATH_REMOVED,
1753 * then return those, and also include all the non-removed routes from the
1754 * next less-specific node (i.e., this node's parent) at the end.
1756 struct rfapi_next_hop_entry
*rfapiRouteNode2NextHopList(
1757 struct agg_node
*rn
, uint32_t lifetime
, /* put into nexthop entries */
1758 struct rfapi_ip_addr
*exclude_vnaddr
, /* omit routes to same NVE */
1759 struct agg_table
*rfd_rib_table
, /* preload here */
1760 struct prefix
*pfx_target_original
) /* query target */
1762 struct rfapi_ip_prefix rprefix
;
1763 struct rfapi_next_hop_entry
*answer
= NULL
;
1764 struct rfapi_next_hop_entry
*last
= NULL
;
1765 struct agg_node
*parent
;
1767 struct agg_node
*rib_rn
;
1769 #if DEBUG_RETURNED_NHL
1771 char buf
[PREFIX_STRLEN
];
1773 prefix2str(&rn
->p
, buf
, sizeof(buf
));
1774 vnc_zlog_debug_verbose("%s: called with node pfx=%s", __func__
,
1777 rfapiDebugBacktrace();
1780 rfapiQprefix2Rprefix(&rn
->p
, &rprefix
);
1782 rib_rn
= rfd_rib_table
? agg_node_get(rfd_rib_table
, &rn
->p
) : NULL
;
1785 * Add non-withdrawn routes at this node
1787 count
= rfapiNhlAddNodeRoutes(rn
, &rprefix
, lifetime
, 0, &answer
, &last
,
1788 exclude_vnaddr
, rib_rn
,
1789 pfx_target_original
);
1792 * If the list has at least one entry, it's finished
1795 count
+= rfapiNhlAddSubtree(rn
, lifetime
, &answer
, &last
, NULL
,
1796 exclude_vnaddr
, rfd_rib_table
,
1797 pfx_target_original
);
1798 vnc_zlog_debug_verbose("%s: %d nexthops, answer=%p", __func__
,
1800 #if DEBUG_RETURNED_NHL
1801 rfapiPrintNhl(NULL
, answer
);
1804 agg_unlock_node(rib_rn
);
1809 * Add withdrawn routes at this node
1811 count
= rfapiNhlAddNodeRoutes(rn
, &rprefix
, lifetime
, 1, &answer
, &last
,
1812 exclude_vnaddr
, rib_rn
,
1813 pfx_target_original
);
1815 agg_unlock_node(rib_rn
);
1817 // rfapiPrintNhl(NULL, answer);
1820 * walk up the tree until we find a node with non-deleted
1821 * routes, then add them
1823 for (parent
= agg_node_parent(rn
); parent
;
1824 parent
= agg_node_parent(parent
)) {
1825 if (rfapiHasNonRemovedRoutes(parent
)) {
1831 * Add non-withdrawn routes from less-specific prefix
1834 rib_rn
= rfd_rib_table
? agg_node_get(rfd_rib_table
, &parent
->p
)
1836 rfapiQprefix2Rprefix(&parent
->p
, &rprefix
);
1837 count
+= rfapiNhlAddNodeRoutes(parent
, &rprefix
, lifetime
, 0,
1838 &answer
, &last
, exclude_vnaddr
,
1839 rib_rn
, pfx_target_original
);
1840 count
+= rfapiNhlAddSubtree(parent
, lifetime
, &answer
, &last
,
1841 rn
, exclude_vnaddr
, rfd_rib_table
,
1842 pfx_target_original
);
1844 agg_unlock_node(rib_rn
);
1847 * There is no parent with non-removed routes. Still need to
1848 * add subtree of original node if it contributed routes to the
1852 count
+= rfapiNhlAddSubtree(rn
, lifetime
, &answer
,
1853 &last
, rn
, exclude_vnaddr
,
1855 pfx_target_original
);
1858 vnc_zlog_debug_verbose("%s: %d nexthops, answer=%p", __func__
, count
,
1860 #if DEBUG_RETURNED_NHL
1861 rfapiPrintNhl(NULL
, answer
);
1867 * Construct nexthop list of all routes in table
1869 struct rfapi_next_hop_entry
*rfapiRouteTable2NextHopList(
1870 struct agg_table
*rt
, uint32_t lifetime
, /* put into nexthop entries */
1871 struct rfapi_ip_addr
*exclude_vnaddr
, /* omit routes to same NVE */
1872 struct agg_table
*rfd_rib_table
, /* preload this NVE rib table */
1873 struct prefix
*pfx_target_original
) /* query target */
1875 struct agg_node
*rn
;
1876 struct rfapi_next_hop_entry
*biglist
= NULL
;
1877 struct rfapi_next_hop_entry
*nhl
;
1878 struct rfapi_next_hop_entry
*tail
= NULL
;
1881 for (rn
= agg_route_top(rt
); rn
; rn
= agg_route_next(rn
)) {
1883 nhl
= rfapiRouteNode2NextHopList(rn
, lifetime
, exclude_vnaddr
,
1885 pfx_target_original
);
1887 tail
= biglist
= nhl
;
1894 while (tail
->next
) {
1901 vnc_zlog_debug_verbose("%s: returning %d routes", __func__
, count
);
1905 struct rfapi_next_hop_entry
*rfapiEthRouteNode2NextHopList(
1906 struct agg_node
*rn
, struct rfapi_ip_prefix
*rprefix
,
1907 uint32_t lifetime
, /* put into nexthop entries */
1908 struct rfapi_ip_addr
*exclude_vnaddr
, /* omit routes to same NVE */
1909 struct agg_table
*rfd_rib_table
, /* preload NVE rib table */
1910 struct prefix
*pfx_target_original
) /* query target */
1913 struct rfapi_next_hop_entry
*answer
= NULL
;
1914 struct rfapi_next_hop_entry
*last
= NULL
;
1915 struct agg_node
*rib_rn
;
1917 rib_rn
= rfd_rib_table
? agg_node_get(rfd_rib_table
, &rn
->p
) : NULL
;
1919 count
= rfapiNhlAddNodeRoutes(rn
, rprefix
, lifetime
, 0, &answer
, &last
,
1920 NULL
, rib_rn
, pfx_target_original
);
1922 #if DEBUG_ENCAP_MONITOR
1923 vnc_zlog_debug_verbose("%s: node %p: %d non-holddown routes", __func__
,
1928 count
= rfapiNhlAddNodeRoutes(rn
, rprefix
, lifetime
, 1, &answer
,
1929 &last
, exclude_vnaddr
, rib_rn
,
1930 pfx_target_original
);
1931 vnc_zlog_debug_verbose("%s: node %p: %d holddown routes",
1932 __func__
, rn
, count
);
1936 agg_unlock_node(rib_rn
);
1938 #if DEBUG_RETURNED_NHL
1939 rfapiPrintNhl(NULL
, answer
);
1947 * Construct nexthop list of all routes in table
1949 struct rfapi_next_hop_entry
*rfapiEthRouteTable2NextHopList(
1950 uint32_t logical_net_id
, struct rfapi_ip_prefix
*rprefix
,
1951 uint32_t lifetime
, /* put into nexthop entries */
1952 struct rfapi_ip_addr
*exclude_vnaddr
, /* omit routes to same NVE */
1953 struct agg_table
*rfd_rib_table
, /* preload NVE rib node */
1954 struct prefix
*pfx_target_original
) /* query target */
1956 struct rfapi_import_table
*it
;
1957 struct bgp
*bgp
= bgp_get_default();
1958 struct agg_table
*rt
;
1959 struct agg_node
*rn
;
1960 struct rfapi_next_hop_entry
*biglist
= NULL
;
1961 struct rfapi_next_hop_entry
*nhl
;
1962 struct rfapi_next_hop_entry
*tail
= NULL
;
1966 it
= rfapiMacImportTableGet(bgp
, logical_net_id
);
1967 rt
= it
->imported_vpn
[AFI_L2VPN
];
1969 for (rn
= agg_route_top(rt
); rn
; rn
= agg_route_next(rn
)) {
1971 nhl
= rfapiEthRouteNode2NextHopList(
1972 rn
, rprefix
, lifetime
, exclude_vnaddr
, rfd_rib_table
,
1973 pfx_target_original
);
1975 tail
= biglist
= nhl
;
1982 while (tail
->next
) {
1989 vnc_zlog_debug_verbose("%s: returning %d routes", __func__
, count
);
1994 * Insert a new bpi to the imported route table node,
1995 * keeping the list of BPIs sorted best route first
1997 static void rfapiBgpInfoAttachSorted(struct agg_node
*rn
,
1998 struct bgp_path_info
*info_new
, afi_t afi
,
2002 struct bgp_path_info
*prev
;
2003 struct bgp_path_info
*next
;
2004 char pfx_buf
[PREFIX2STR_BUFFER
];
2007 bgp
= bgp_get_default(); /* assume 1 instance for now */
2009 if (VNC_DEBUG(IMPORT_BI_ATTACH
)) {
2010 vnc_zlog_debug_verbose("%s: info_new->peer=%p", __func__
,
2012 vnc_zlog_debug_verbose("%s: info_new->peer->su_remote=%p",
2013 __func__
, info_new
->peer
->su_remote
);
2016 for (prev
= NULL
, next
= rn
->info
; next
;
2017 prev
= next
, next
= next
->next
) {
2019 || (!CHECK_FLAG(info_new
->flags
, BGP_PATH_REMOVED
)
2020 && CHECK_FLAG(next
->flags
, BGP_PATH_REMOVED
))
2021 || bgp_path_info_cmp_compatible(bgp
, info_new
, next
,
2023 == -1) { /* -1 if 1st is better */
2027 vnc_zlog_debug_verbose("%s: prev=%p, next=%p", __func__
, prev
, next
);
2029 prev
->next
= info_new
;
2031 rn
->info
= info_new
;
2033 info_new
->prev
= prev
;
2034 info_new
->next
= next
;
2036 next
->prev
= info_new
;
2037 bgp_attr_intern(info_new
->attr
);
2040 static void rfapiBgpInfoDetach(struct agg_node
*rn
, struct bgp_path_info
*bpi
)
2043 * Remove the route (doubly-linked)
2045 // bgp_attr_unintern (&bpi->attr);
2047 bpi
->next
->prev
= bpi
->prev
;
2049 bpi
->prev
->next
= bpi
->next
;
2051 rn
->info
= bpi
->next
;
2055 * For L3-indexed import tables
2057 static int rfapi_bi_peer_rd_cmp(void *b1
, void *b2
)
2059 struct bgp_path_info
*bpi1
= b1
;
2060 struct bgp_path_info
*bpi2
= b2
;
2065 if (bpi1
->peer
< bpi2
->peer
)
2067 if (bpi1
->peer
> bpi2
->peer
)
2073 return vnc_prefix_cmp((struct prefix
*)&bpi1
->extra
->vnc
.import
.rd
,
2074 (struct prefix
*)&bpi2
->extra
->vnc
.import
.rd
);
2078 * For L2-indexed import tables
2079 * The BPIs in these tables should ALWAYS have an aux_prefix set because
2080 * they arrive via IPv4 or IPv6 advertisements.
2082 static int rfapi_bi_peer_rd_aux_cmp(void *b1
, void *b2
)
2084 struct bgp_path_info
*bpi1
= b1
;
2085 struct bgp_path_info
*bpi2
= b2
;
2091 if (bpi1
->peer
< bpi2
->peer
)
2093 if (bpi1
->peer
> bpi2
->peer
)
2099 rc
= vnc_prefix_cmp((struct prefix
*)&bpi1
->extra
->vnc
.import
.rd
,
2100 (struct prefix
*)&bpi2
->extra
->vnc
.import
.rd
);
2106 * L2 import tables can have multiple entries with the
2107 * same MAC address, same RD, but different L3 addresses.
2109 * Use presence of aux_prefix with AF=ethernet and prefixlen=1
2110 * as magic value to signify explicit wildcarding of the aux_prefix.
2111 * This magic value will not appear in bona fide bpi entries in
2112 * the import table, but is allowed in the "fake" bpi used to
2113 * probe the table when searching. (We have to test both b1 and b2
2114 * because there is no guarantee of the order the test key and
2115 * the real key will be passed)
2117 if ((bpi1
->extra
->vnc
.import
.aux_prefix
.family
== AF_ETHERNET
2118 && (bpi1
->extra
->vnc
.import
.aux_prefix
.prefixlen
== 1))
2119 || (bpi2
->extra
->vnc
.import
.aux_prefix
.family
== AF_ETHERNET
2120 && (bpi2
->extra
->vnc
.import
.aux_prefix
.prefixlen
== 1))) {
2123 * wildcard aux address specified
2128 return vnc_prefix_cmp(&bpi1
->extra
->vnc
.import
.aux_prefix
,
2129 &bpi2
->extra
->vnc
.import
.aux_prefix
);
2134 * Index on RD and Peer
2136 static void rfapiItBiIndexAdd(struct agg_node
*rn
, /* Import table VPN node */
2137 struct bgp_path_info
*bpi
) /* new BPI */
2139 struct skiplist
*sl
;
2146 char buf
[RD_ADDRSTRLEN
];
2148 vnc_zlog_debug_verbose("%s: bpi %p, peer %p, rd %s", __func__
,
2150 prefix_rd2str(&bpi
->extra
->vnc
.import
.rd
,
2154 sl
= RFAPI_RDINDEX_W_ALLOC(rn
);
2156 if (AF_ETHERNET
== rn
->p
.family
) {
2157 sl
= skiplist_new(0, rfapi_bi_peer_rd_aux_cmp
, NULL
);
2159 sl
= skiplist_new(0, rfapi_bi_peer_rd_cmp
, NULL
);
2161 RFAPI_IT_EXTRA_GET(rn
)->u
.vpn
.idx_rd
= sl
;
2162 agg_lock_node(rn
); /* for skiplist */
2164 assert(!skiplist_insert(sl
, (void *)bpi
, (void *)bpi
));
2165 agg_lock_node(rn
); /* for skiplist entry */
2167 /* NB: BPIs in import tables are not refcounted */
2170 static void rfapiItBiIndexDump(struct agg_node
*rn
)
2172 struct skiplist
*sl
;
2173 void *cursor
= NULL
;
2174 struct bgp_path_info
*k
;
2175 struct bgp_path_info
*v
;
2178 sl
= RFAPI_RDINDEX(rn
);
2182 for (rc
= skiplist_next(sl
, (void **)&k
, (void **)&v
, &cursor
); !rc
;
2183 rc
= skiplist_next(sl
, (void **)&k
, (void **)&v
, &cursor
)) {
2185 char buf
[RD_ADDRSTRLEN
];
2186 char buf_aux_pfx
[PREFIX_STRLEN
];
2188 prefix_rd2str(&k
->extra
->vnc
.import
.rd
, buf
, sizeof(buf
));
2189 if (k
->extra
->vnc
.import
.aux_prefix
.family
) {
2190 prefix2str(&k
->extra
->vnc
.import
.aux_prefix
,
2191 buf_aux_pfx
, sizeof(buf_aux_pfx
));
2193 strncpy(buf_aux_pfx
, "(none)", PREFIX_STRLEN
);
2195 vnc_zlog_debug_verbose("bpi %p, peer %p, rd %s, aux_prefix %s",
2196 k
, k
->peer
, buf
, buf_aux_pfx
);
2200 static struct bgp_path_info
*rfapiItBiIndexSearch(
2201 struct agg_node
*rn
, /* Import table VPN node */
2202 struct prefix_rd
*prd
, struct peer
*peer
,
2203 struct prefix
*aux_prefix
) /* optional L3 addr for L2 ITs */
2205 struct skiplist
*sl
;
2207 struct bgp_path_info bpi_fake
;
2208 struct bgp_path_info_extra bpi_extra
;
2209 struct bgp_path_info
*bpi_result
;
2211 sl
= RFAPI_RDINDEX(rn
);
2217 char buf
[RD_ADDRSTRLEN
];
2218 char buf_aux_pfx
[PREFIX_STRLEN
];
2221 prefix2str(aux_prefix
, buf_aux_pfx
,
2222 sizeof(buf_aux_pfx
));
2224 strncpy(buf_aux_pfx
, "(nil)", sizeof(buf_aux_pfx
));
2226 vnc_zlog_debug_verbose("%s want prd=%s, peer=%p, aux_prefix=%s",
2228 prefix_rd2str(prd
, buf
, sizeof(buf
)),
2230 rfapiItBiIndexDump(rn
);
2234 /* threshold is a WAG */
2235 if (sl
->count
< 3) {
2237 vnc_zlog_debug_verbose("%s: short list algorithm", __func__
);
2239 /* if short list, linear search might be faster */
2240 for (bpi_result
= rn
->info
; bpi_result
;
2241 bpi_result
= bpi_result
->next
) {
2244 char buf
[RD_ADDRSTRLEN
];
2246 vnc_zlog_debug_verbose(
2247 "%s: bpi has prd=%s, peer=%p", __func__
,
2248 prefix_rd2str(&bpi_result
->extra
->vnc
2254 if (peer
== bpi_result
->peer
2255 && !prefix_cmp((struct prefix
*)&bpi_result
->extra
2257 (struct prefix
*)prd
)) {
2260 vnc_zlog_debug_verbose(
2261 "%s: peer and RD same, doing aux_prefix check",
2267 &bpi_result
->extra
->vnc
.import
2271 vnc_zlog_debug_verbose("%s: match",
2281 bpi_fake
.peer
= peer
;
2282 bpi_fake
.extra
= &bpi_extra
;
2283 bpi_fake
.extra
->vnc
.import
.rd
= *(struct prefix_rd
*)prd
;
2285 bpi_fake
.extra
->vnc
.import
.aux_prefix
= *aux_prefix
;
2288 bpi_fake
.extra
->vnc
.import
.aux_prefix
.family
= AF_ETHERNET
;
2289 bpi_fake
.extra
->vnc
.import
.aux_prefix
.prefixlen
= 1;
2292 rc
= skiplist_search(sl
, (void *)&bpi_fake
, (void *)&bpi_result
);
2296 vnc_zlog_debug_verbose("%s: no match", __func__
);
2302 vnc_zlog_debug_verbose("%s: matched bpi=%p", __func__
, bpi_result
);
2308 static void rfapiItBiIndexDel(struct agg_node
*rn
, /* Import table VPN node */
2309 struct bgp_path_info
*bpi
) /* old BPI */
2311 struct skiplist
*sl
;
2315 char buf
[RD_ADDRSTRLEN
];
2317 vnc_zlog_debug_verbose("%s: bpi %p, peer %p, rd %s", __func__
,
2319 prefix_rd2str(&bpi
->extra
->vnc
.import
.rd
,
2323 sl
= RFAPI_RDINDEX(rn
);
2326 rc
= skiplist_delete(sl
, (void *)(bpi
), (void *)bpi
);
2328 rfapiItBiIndexDump(rn
);
2332 agg_unlock_node(rn
); /* for skiplist entry */
2334 /* NB: BPIs in import tables are not refcounted */
2338 * Add a backreference at the ENCAP node to the VPN route that
2342 rfapiMonitorEncapAdd(struct rfapi_import_table
*import_table
,
2343 struct prefix
*p
, /* VN address */
2344 struct agg_node
*vpn_rn
, /* VPN node */
2345 struct bgp_path_info
*vpn_bpi
) /* VPN bpi/route */
2347 afi_t afi
= family2afi(p
->family
);
2348 struct agg_node
*rn
;
2349 struct rfapi_monitor_encap
*m
;
2352 rn
= agg_node_get(import_table
->imported_encap
[afi
], p
); /* locks rn */
2355 m
= XCALLOC(MTYPE_RFAPI_MONITOR_ENCAP
,
2356 sizeof(struct rfapi_monitor_encap
));
2363 /* insert to encap node's list */
2364 m
->next
= RFAPI_MONITOR_ENCAP(rn
);
2367 RFAPI_MONITOR_ENCAP_W_ALLOC(rn
) = m
;
2369 /* for easy lookup when deleting vpn route */
2370 vpn_bpi
->extra
->vnc
.import
.hme
= m
;
2372 vnc_zlog_debug_verbose(
2373 "%s: it=%p, vpn_bpi=%p, afi=%d, encap rn=%p, setting vpn_bpi->extra->vnc.import.hme=%p",
2374 __func__
, import_table
, vpn_bpi
, afi
, rn
, m
);
2376 RFAPI_CHECK_REFCOUNT(rn
, SAFI_ENCAP
, 0);
2377 bgp_attr_intern(vpn_bpi
->attr
);
2380 static void rfapiMonitorEncapDelete(struct bgp_path_info
*vpn_bpi
)
2383 * Remove encap monitor
2385 vnc_zlog_debug_verbose("%s: vpn_bpi=%p", __func__
, vpn_bpi
);
2386 if (vpn_bpi
->extra
) {
2387 struct rfapi_monitor_encap
*hme
=
2388 vpn_bpi
->extra
->vnc
.import
.hme
;
2392 vnc_zlog_debug_verbose("%s: hme=%p", __func__
, hme
);
2394 /* Refcount checking takes too long here */
2395 // RFAPI_CHECK_REFCOUNT(hme->rn, SAFI_ENCAP, 0);
2397 hme
->next
->prev
= hme
->prev
;
2399 hme
->prev
->next
= hme
->next
;
2401 RFAPI_MONITOR_ENCAP_W_ALLOC(hme
->rn
) =
2403 /* Refcount checking takes too long here */
2404 // RFAPI_CHECK_REFCOUNT(hme->rn, SAFI_ENCAP, 1);
2406 /* see if the struct rfapi_it_extra is empty and can be
2408 rfapiMonitorExtraPrune(SAFI_ENCAP
, hme
->rn
);
2410 agg_unlock_node(hme
->rn
); /* decr ref count */
2411 XFREE(MTYPE_RFAPI_MONITOR_ENCAP
, hme
);
2412 vpn_bpi
->extra
->vnc
.import
.hme
= NULL
;
2418 * quagga lib/thread.h says this must return int even though
2419 * it doesn't do anything with the return value
2421 static int rfapiWithdrawTimerVPN(struct thread
*t
)
2423 struct rfapi_withdraw
*wcb
= t
->arg
;
2424 struct bgp_path_info
*bpi
= wcb
->info
;
2425 struct bgp
*bgp
= bgp_get_default();
2427 struct rfapi_monitor_vpn
*moved
;
2432 assert(wcb
->import_table
);
2435 RFAPI_CHECK_REFCOUNT(wcb
->node
, SAFI_MPLS_VPN
, wcb
->lockoffset
);
2440 vnc_zlog_debug_verbose(
2441 "%s: removing bpi %p at prefix %s/%d", __func__
, bpi
,
2442 rfapi_ntop(wcb
->node
->p
.family
, &wcb
->node
->p
.u
.prefix
,
2444 wcb
->node
->p
.prefixlen
);
2448 * Remove the route (doubly-linked)
2450 if (CHECK_FLAG(bpi
->flags
, BGP_PATH_VALID
)
2451 && VALID_INTERIOR_TYPE(bpi
->type
))
2452 RFAPI_MONITOR_EXTERIOR(wcb
->node
)->valid_interior_count
--;
2454 afi
= family2afi(wcb
->node
->p
.family
);
2455 wcb
->import_table
->holddown_count
[afi
] -= 1; /* keep count consistent */
2456 rfapiItBiIndexDel(wcb
->node
, bpi
);
2457 rfapiBgpInfoDetach(wcb
->node
, bpi
); /* with removed bpi */
2459 vnc_import_bgp_exterior_del_route_interior(bgp
, wcb
->import_table
,
2464 * If VNC is configured to send response remove messages, AND
2465 * if the removed route had a UN address, do response removal
2468 if (!(bgp
->rfapi_cfg
->flags
2469 & BGP_VNC_CONFIG_RESPONSE_REMOVAL_DISABLE
)) {
2471 int has_valid_duplicate
= 0;
2472 struct bgp_path_info
*bpii
;
2475 * First check if there are any OTHER routes at this node
2476 * that have the same nexthop and a valid UN address. If
2477 * there are (e.g., from other peers), then the route isn't
2478 * really gone, so skip sending a response removal message.
2480 for (bpii
= wcb
->node
->info
; bpii
; bpii
= bpii
->next
) {
2481 if (rfapiVpnBiSamePtUn(bpi
, bpii
)) {
2482 has_valid_duplicate
= 1;
2487 vnc_zlog_debug_verbose("%s: has_valid_duplicate=%d", __func__
,
2488 has_valid_duplicate
);
2490 if (!has_valid_duplicate
) {
2491 rfapiRibPendingDeleteRoute(bgp
, wcb
->import_table
, afi
,
2496 rfapiMonitorEncapDelete(bpi
);
2499 * If there are no VPN monitors at this VPN Node A,
2502 if (!RFAPI_MONITOR_VPN(wcb
->node
)) {
2503 vnc_zlog_debug_verbose("%s: no VPN monitors at this node",
2509 * rfapiMonitorMoveShorter only moves monitors if there are
2510 * no remaining valid routes at the current node
2512 moved
= rfapiMonitorMoveShorter(wcb
->node
, 1);
2515 rfapiMonitorMovedUp(wcb
->import_table
, wcb
->node
, moved
->node
,
2523 rfapiBgpInfoFree(bpi
);
2527 * If route count at this node has gone to 0, withdraw exported prefix
2529 if (!wcb
->node
->info
) {
2530 /* see if the struct rfapi_it_extra is empty and can be freed */
2531 rfapiMonitorExtraPrune(SAFI_MPLS_VPN
, wcb
->node
);
2532 vnc_direct_bgp_del_prefix(bgp
, wcb
->import_table
, wcb
->node
);
2533 vnc_zebra_del_prefix(bgp
, wcb
->import_table
, wcb
->node
);
2536 * nexthop change event
2537 * vnc_direct_bgp_add_prefix() will recompute the VN addr
2540 vnc_direct_bgp_add_prefix(bgp
, wcb
->import_table
, wcb
->node
);
2543 RFAPI_CHECK_REFCOUNT(wcb
->node
, SAFI_MPLS_VPN
, 1 + wcb
->lockoffset
);
2544 agg_unlock_node(wcb
->node
); /* decr ref count */
2545 XFREE(MTYPE_RFAPI_WITHDRAW
, wcb
);
2550 * This works for multiprotocol extension, but not for plain ol'
2551 * unicast IPv4 because that nexthop is stored in attr->nexthop
2553 void rfapiNexthop2Prefix(struct attr
*attr
, struct prefix
*p
)
2558 memset(p
, 0, sizeof(struct prefix
));
2560 switch (p
->family
= BGP_MP_NEXTHOP_FAMILY(attr
->mp_nexthop_len
)) {
2562 p
->u
.prefix4
= attr
->mp_nexthop_global_in
;
2567 p
->u
.prefix6
= attr
->mp_nexthop_global
;
2572 vnc_zlog_debug_verbose("%s: Family is unknown = %d", __func__
,
2577 void rfapiUnicastNexthop2Prefix(afi_t afi
, struct attr
*attr
, struct prefix
*p
)
2579 if (afi
== AFI_IP
) {
2580 p
->family
= AF_INET
;
2582 p
->u
.prefix4
= attr
->nexthop
;
2584 rfapiNexthop2Prefix(attr
, p
);
2588 static int rfapiAttrNexthopAddrDifferent(struct prefix
*p1
, struct prefix
*p2
)
2591 vnc_zlog_debug_verbose("%s: p1 or p2 is NULL", __func__
);
2596 * Are address families the same?
2598 if (p1
->family
!= p2
->family
) {
2602 switch (p1
->family
) {
2604 if (IPV4_ADDR_SAME(&p1
->u
.prefix4
, &p2
->u
.prefix4
))
2609 if (IPV6_ADDR_SAME(&p1
->u
.prefix6
, &p2
->u
.prefix6
))
2620 static void rfapiCopyUnEncap2VPN(struct bgp_path_info
*encap_bpi
,
2621 struct bgp_path_info
*vpn_bpi
)
2623 if (!encap_bpi
->attr
) {
2624 zlog_warn("%s: no encap bpi attr/extra, can't copy UN address",
2629 if (!vpn_bpi
|| !vpn_bpi
->extra
) {
2630 zlog_warn("%s: no vpn bpi attr/extra, can't copy UN address",
2635 switch (BGP_MP_NEXTHOP_FAMILY(encap_bpi
->attr
->mp_nexthop_len
)) {
2639 * instrumentation to debug segfault of 091127
2641 vnc_zlog_debug_verbose("%s: vpn_bpi=%p", __func__
, vpn_bpi
);
2643 vnc_zlog_debug_verbose("%s: vpn_bpi->extra=%p",
2644 __func__
, vpn_bpi
->extra
);
2647 vpn_bpi
->extra
->vnc
.import
.un_family
= AF_INET
;
2648 vpn_bpi
->extra
->vnc
.import
.un
.addr4
=
2649 encap_bpi
->attr
->mp_nexthop_global_in
;
2653 vpn_bpi
->extra
->vnc
.import
.un_family
= AF_INET6
;
2654 vpn_bpi
->extra
->vnc
.import
.un
.addr6
=
2655 encap_bpi
->attr
->mp_nexthop_global
;
2659 zlog_warn("%s: invalid encap nexthop length: %d", __func__
,
2660 encap_bpi
->attr
->mp_nexthop_len
);
2661 vpn_bpi
->extra
->vnc
.import
.un_family
= 0;
2667 * returns 0 on success, nonzero on error
2670 rfapiWithdrawEncapUpdateCachedUn(struct rfapi_import_table
*import_table
,
2671 struct bgp_path_info
*encap_bpi
,
2672 struct agg_node
*vpn_rn
,
2673 struct bgp_path_info
*vpn_bpi
)
2678 * clear cached UN address
2680 if (!vpn_bpi
|| !vpn_bpi
->extra
) {
2682 "%s: missing VPN bpi/extra, can't clear UN addr",
2686 vpn_bpi
->extra
->vnc
.import
.un_family
= 0;
2687 memset(&vpn_bpi
->extra
->vnc
.import
.un
, 0,
2688 sizeof(vpn_bpi
->extra
->vnc
.import
.un
));
2689 if (CHECK_FLAG(vpn_bpi
->flags
, BGP_PATH_VALID
)) {
2690 if (rfapiGetVncTunnelUnAddr(vpn_bpi
->attr
, NULL
)) {
2691 UNSET_FLAG(vpn_bpi
->flags
, BGP_PATH_VALID
);
2692 if (VALID_INTERIOR_TYPE(vpn_bpi
->type
))
2693 RFAPI_MONITOR_EXTERIOR(vpn_rn
)
2694 ->valid_interior_count
--;
2695 /* signal interior route withdrawal to
2696 * import-exterior */
2697 vnc_import_bgp_exterior_del_route_interior(
2698 bgp_get_default(), import_table
, vpn_rn
,
2705 zlog_warn("%s: missing VPN bpi, can't clear UN addr",
2709 rfapiCopyUnEncap2VPN(encap_bpi
, vpn_bpi
);
2710 if (!CHECK_FLAG(vpn_bpi
->flags
, BGP_PATH_VALID
)) {
2711 SET_FLAG(vpn_bpi
->flags
, BGP_PATH_VALID
);
2712 if (VALID_INTERIOR_TYPE(vpn_bpi
->type
))
2713 RFAPI_MONITOR_EXTERIOR(vpn_rn
)
2714 ->valid_interior_count
++;
2715 /* signal interior route withdrawal to import-exterior
2717 vnc_import_bgp_exterior_add_route_interior(
2718 bgp_get_default(), import_table
, vpn_rn
,
2725 static int rfapiWithdrawTimerEncap(struct thread
*t
)
2727 struct rfapi_withdraw
*wcb
= t
->arg
;
2728 struct bgp_path_info
*bpi
= wcb
->info
;
2729 int was_first_route
= 0;
2730 struct rfapi_monitor_encap
*em
;
2731 struct skiplist
*vpn_node_sl
= skiplist_new(0, NULL
, NULL
);
2735 assert(wcb
->import_table
);
2737 RFAPI_CHECK_REFCOUNT(wcb
->node
, SAFI_ENCAP
, 0);
2739 if (wcb
->node
->info
== bpi
)
2740 was_first_route
= 1;
2743 * Remove the route/bpi and free it
2745 rfapiBgpInfoDetach(wcb
->node
, bpi
);
2746 rfapiBgpInfoFree(bpi
);
2748 if (!was_first_route
)
2751 for (em
= RFAPI_MONITOR_ENCAP(wcb
->node
); em
; em
= em
->next
) {
2754 * Update monitoring VPN BPIs with new encap info at the
2755 * head of the encap bpi chain (which could be NULL after
2756 * removing the expiring bpi above)
2758 if (rfapiWithdrawEncapUpdateCachedUn(wcb
->import_table
,
2759 wcb
->node
->info
, em
->node
,
2764 * Build a list of unique VPN nodes referenced by these
2766 * Use a skiplist for speed.
2768 skiplist_insert(vpn_node_sl
, em
->node
, em
->node
);
2773 * for each VPN node referenced in the ENCAP monitors:
2775 struct agg_node
*rn
;
2776 while (!skiplist_first(vpn_node_sl
, (void **)&rn
, NULL
)) {
2777 if (!wcb
->node
->info
) {
2778 struct rfapi_monitor_vpn
*moved
;
2780 moved
= rfapiMonitorMoveShorter(rn
, 0);
2782 // rfapiDoRouteCallback(wcb->import_table,
2783 // moved->node, moved);
2784 rfapiMonitorMovedUp(wcb
->import_table
, rn
,
2785 moved
->node
, moved
);
2788 // rfapiDoRouteCallback(wcb->import_table, rn, NULL);
2789 rfapiMonitorItNodeChanged(wcb
->import_table
, rn
, NULL
);
2791 skiplist_delete_first(vpn_node_sl
);
2795 RFAPI_CHECK_REFCOUNT(wcb
->node
, SAFI_ENCAP
, 1);
2796 agg_unlock_node(wcb
->node
); /* decr ref count */
2797 XFREE(MTYPE_RFAPI_WITHDRAW
, wcb
);
2798 skiplist_free(vpn_node_sl
);
2804 * Works for both VPN and ENCAP routes; timer_service_func is different
2808 rfapiBiStartWithdrawTimer(struct rfapi_import_table
*import_table
,
2809 struct agg_node
*rn
, struct bgp_path_info
*bpi
,
2810 afi_t afi
, safi_t safi
,
2811 int (*timer_service_func
)(struct thread
*))
2814 struct rfapi_withdraw
*wcb
;
2816 if (CHECK_FLAG(bpi
->flags
, BGP_PATH_REMOVED
)) {
2818 * Already on the path to being withdrawn,
2819 * should already have a timer set up to
2822 vnc_zlog_debug_verbose(
2823 "%s: already being withdrawn, do nothing", __func__
);
2827 rfapiGetVncLifetime(bpi
->attr
, &lifetime
);
2828 vnc_zlog_debug_verbose("%s: VNC lifetime is %u", __func__
, lifetime
);
2831 * withdrawn routes get to hang around for a while
2833 SET_FLAG(bpi
->flags
, BGP_PATH_REMOVED
);
2835 /* set timer to remove the route later */
2836 lifetime
= rfapiGetHolddownFromLifetime(lifetime
);
2837 vnc_zlog_debug_verbose("%s: using timeout %u", __func__
, lifetime
);
2840 * Stash import_table, node, and info for use by timer
2841 * service routine, which is supposed to free the wcb.
2843 wcb
= XCALLOC(MTYPE_RFAPI_WITHDRAW
, sizeof(struct rfapi_withdraw
));
2847 wcb
->import_table
= import_table
;
2848 bgp_attr_intern(bpi
->attr
);
2850 if (VNC_DEBUG(VERBOSE
)) {
2851 vnc_zlog_debug_verbose(
2852 "%s: wcb values: node=%p, info=%p, import_table=%p (bpi follows)",
2853 __func__
, wcb
->node
, wcb
->info
, wcb
->import_table
);
2854 rfapiPrintBi(NULL
, bpi
);
2859 if (lifetime
> UINT32_MAX
/ 1001) {
2860 /* sub-optimal case, but will probably never happen */
2861 bpi
->extra
->vnc
.import
.timer
= NULL
;
2862 thread_add_timer(bm
->master
, timer_service_func
, wcb
, lifetime
,
2863 &bpi
->extra
->vnc
.import
.timer
);
2865 static uint32_t jitter
;
2866 uint32_t lifetime_msec
;
2869 * the goal here is to spread out the timers so they are
2870 * sortable in the skip list
2872 if (++jitter
>= 1000)
2875 lifetime_msec
= (lifetime
* 1000) + jitter
;
2877 bpi
->extra
->vnc
.import
.timer
= NULL
;
2878 thread_add_timer_msec(bm
->master
, timer_service_func
, wcb
,
2880 &bpi
->extra
->vnc
.import
.timer
);
2883 /* re-sort route list (BGP_PATH_REMOVED routes are last) */
2884 if (((struct bgp_path_info
*)rn
->info
)->next
) {
2885 rfapiBgpInfoDetach(rn
, bpi
);
2886 rfapiBgpInfoAttachSorted(rn
, bpi
, afi
, safi
);
2891 typedef void(rfapi_bi_filtered_import_f
)(struct rfapi_import_table
*, int,
2892 struct peer
*, void *, struct prefix
*,
2893 struct prefix
*, afi_t
,
2894 struct prefix_rd
*, struct attr
*,
2895 uint8_t, uint8_t, uint32_t *);
2898 static void rfapiExpireEncapNow(struct rfapi_import_table
*it
,
2899 struct agg_node
*rn
, struct bgp_path_info
*bpi
)
2901 struct rfapi_withdraw
*wcb
;
2905 * pretend we're an expiring timer
2907 wcb
= XCALLOC(MTYPE_RFAPI_WITHDRAW
, sizeof(struct rfapi_withdraw
));
2910 wcb
->import_table
= it
;
2911 memset(&t
, 0, sizeof(t
));
2913 rfapiWithdrawTimerEncap(&t
); /* frees wcb */
2916 static int rfapiGetNexthop(struct attr
*attr
, struct prefix
*prefix
)
2918 switch (BGP_MP_NEXTHOP_FAMILY(attr
->mp_nexthop_len
)) {
2920 prefix
->family
= AF_INET
;
2921 prefix
->prefixlen
= 32;
2922 prefix
->u
.prefix4
= attr
->mp_nexthop_global_in
;
2925 prefix
->family
= AF_INET6
;
2926 prefix
->prefixlen
= 128;
2927 prefix
->u
.prefix6
= attr
->mp_nexthop_global
;
2930 vnc_zlog_debug_verbose("%s: unknown attr->mp_nexthop_len %d",
2931 __func__
, attr
->mp_nexthop_len
);
2938 * import a bgp_path_info if its route target list intersects with the
2939 * import table's route target list
2941 static void rfapiBgpInfoFilteredImportEncap(
2942 struct rfapi_import_table
*import_table
, int action
, struct peer
*peer
,
2943 void *rfd
, /* set for looped back routes */
2945 struct prefix
*aux_prefix
, /* Unused for encap routes */
2946 afi_t afi
, struct prefix_rd
*prd
,
2947 struct attr
*attr
, /* part of bgp_path_info */
2948 uint8_t type
, /* part of bgp_path_info */
2949 uint8_t sub_type
, /* part of bgp_path_info */
2950 uint32_t *label
) /* part of bgp_path_info */
2952 struct agg_table
*rt
= NULL
;
2953 struct agg_node
*rn
;
2954 struct bgp_path_info
*info_new
;
2955 struct bgp_path_info
*bpi
;
2956 struct bgp_path_info
*next
;
2959 struct prefix p_firstbpi_old
;
2960 struct prefix p_firstbpi_new
;
2962 const char *action_str
= NULL
;
2963 struct prefix un_prefix
;
2966 bgp
= bgp_get_default(); /* assume 1 instance for now */
2969 case FIF_ACTION_UPDATE
:
2970 action_str
= "update";
2972 case FIF_ACTION_WITHDRAW
:
2973 action_str
= "withdraw";
2975 case FIF_ACTION_KILL
:
2976 action_str
= "kill";
2983 vnc_zlog_debug_verbose(
2984 "%s: entry: %s: prefix %s/%d", __func__
, action_str
,
2985 inet_ntop(p
->family
, &p
->u
.prefix
, buf
, BUFSIZ
), p
->prefixlen
);
2987 memset(&p_firstbpi_old
, 0, sizeof(p_firstbpi_old
));
2988 memset(&p_firstbpi_new
, 0, sizeof(p_firstbpi_new
));
2990 if (action
== FIF_ACTION_UPDATE
) {
2992 * Compare rt lists. If no intersection, don't import this route
2993 * On a withdraw, peer and RD are sufficient to determine if
2996 if (!attr
|| !attr
->ecommunity
) {
2998 vnc_zlog_debug_verbose(
2999 "%s: attr, extra, or ecommunity missing, not importing",
3003 #if RFAPI_REQUIRE_ENCAP_BEEC
3004 if (!rfapiEcommunitiesMatchBeec(attr
->ecommunity
)) {
3005 vnc_zlog_debug_verbose(
3006 "%s: it=%p: no match for BGP Encapsulation ecommunity",
3007 __func__
, import_table
);
3011 if (!rfapiEcommunitiesIntersect(import_table
->rt_import_list
,
3012 attr
->ecommunity
)) {
3014 vnc_zlog_debug_verbose(
3015 "%s: it=%p: no ecommunity intersection",
3016 __func__
, import_table
);
3021 * Updates must also have a nexthop address
3023 memset(&un_prefix
, 0,
3024 sizeof(un_prefix
)); /* keep valgrind happy */
3025 if (rfapiGetNexthop(attr
, &un_prefix
)) {
3026 vnc_zlog_debug_verbose("%s: missing nexthop address",
3033 * Figure out which radix tree the route would go into
3038 rt
= import_table
->imported_encap
[afi
];
3042 flog_err(EC_LIB_DEVELOPMENT
, "%s: bad afi %d", __func__
, afi
);
3047 * agg_node_lookup returns a node only if there is at least
3048 * one route attached.
3050 rn
= agg_node_lookup(rt
, p
);
3052 #if DEBUG_ENCAP_MONITOR
3053 vnc_zlog_debug_verbose("%s: initial encap lookup(it=%p) rn=%p",
3054 __func__
, import_table
, rn
);
3059 RFAPI_CHECK_REFCOUNT(rn
, SAFI_ENCAP
, 1);
3060 agg_unlock_node(rn
); /* undo lock in agg_node_lookup */
3064 * capture nexthop of first bpi
3067 rfapiNexthop2Prefix(
3068 ((struct bgp_path_info
*)(rn
->info
))->attr
,
3072 for (bpi
= rn
->info
; bpi
; bpi
= bpi
->next
) {
3075 * Does this bgp_path_info refer to the same route
3076 * as we are trying to add?
3078 vnc_zlog_debug_verbose("%s: comparing BPI %p", __func__
,
3085 * RD of import table bpi is in
3086 * bpi->extra->vnc.import.rd RD of info_orig is in prd
3089 vnc_zlog_debug_verbose("%s: no bpi->extra",
3094 (struct prefix
*)&bpi
->extra
->vnc
.import
.rd
,
3095 (struct prefix
*)prd
)) {
3097 vnc_zlog_debug_verbose("%s: prd does not match",
3105 if (bpi
->peer
!= peer
) {
3106 vnc_zlog_debug_verbose(
3107 "%s: peer does not match", __func__
);
3111 vnc_zlog_debug_verbose("%s: found matching bpi",
3114 /* Same route. Delete this bpi, replace with new one */
3116 if (action
== FIF_ACTION_WITHDRAW
) {
3118 vnc_zlog_debug_verbose(
3119 "%s: withdrawing at prefix %s/%d",
3121 inet_ntop(rn
->p
.family
, &rn
->p
.u
.prefix
,
3125 rfapiBiStartWithdrawTimer(
3126 import_table
, rn
, bpi
, afi
, SAFI_ENCAP
,
3127 rfapiWithdrawTimerEncap
);
3130 vnc_zlog_debug_verbose(
3131 "%s: %s at prefix %s/%d", __func__
,
3132 ((action
== FIF_ACTION_KILL
)
3135 inet_ntop(rn
->p
.family
, &rn
->p
.u
.prefix
,
3140 * If this route is waiting to be deleted
3142 * a previous withdraw, we must cancel its
3145 if (CHECK_FLAG(bpi
->flags
, BGP_PATH_REMOVED
)
3146 && bpi
->extra
->vnc
.import
.timer
) {
3149 (struct thread
*)bpi
->extra
->vnc
3151 struct rfapi_withdraw
*wcb
= t
->arg
;
3153 XFREE(MTYPE_RFAPI_WITHDRAW
, wcb
);
3157 if (action
== FIF_ACTION_UPDATE
) {
3158 rfapiBgpInfoDetach(rn
, bpi
);
3159 rfapiBgpInfoFree(bpi
);
3163 * Kill: do export stuff when removing
3166 struct rfapi_withdraw
*wcb
;
3170 * pretend we're an expiring timer
3173 MTYPE_RFAPI_WITHDRAW
,
3174 sizeof(struct rfapi_withdraw
));
3177 wcb
->import_table
= import_table
;
3178 memset(&t
, 0, sizeof(t
));
3180 rfapiWithdrawTimerEncap(
3181 &t
); /* frees wcb */
3190 RFAPI_CHECK_REFCOUNT(rn
, SAFI_ENCAP
, replacing
? 1 : 0);
3192 if (action
== FIF_ACTION_WITHDRAW
|| action
== FIF_ACTION_KILL
)
3196 rfapiBgpInfoCreate(attr
, peer
, rfd
, prd
, type
, sub_type
, NULL
);
3200 agg_lock_node(rn
); /* incr ref count for new BPI */
3202 rn
= agg_node_get(rt
, p
);
3205 vnc_zlog_debug_verbose(
3206 "%s: (afi=%d, rn=%p) inserting at prefix %s/%d", __func__
, afi
,
3207 rn
, inet_ntop(rn
->p
.family
, &rn
->p
.u
.prefix
, buf
, BUFSIZ
),
3210 rfapiBgpInfoAttachSorted(rn
, info_new
, afi
, SAFI_ENCAP
);
3213 * Delete holddown routes from same NVE. See details in
3214 * rfapiBgpInfoFilteredImportVPN()
3216 for (bpi
= info_new
->next
; bpi
; bpi
= next
) {
3218 struct prefix pfx_un
;
3222 if (!CHECK_FLAG(bpi
->flags
, BGP_PATH_REMOVED
))
3226 * We already match the VN address (it is the prefix
3227 * of the route node)
3230 if (!rfapiGetNexthop(bpi
->attr
, &pfx_un
)
3231 && prefix_same(&pfx_un
, &un_prefix
)) {
3239 vnc_zlog_debug_verbose(
3240 "%s: removing holddown bpi matching NVE of new route",
3242 if (bpi
->extra
->vnc
.import
.timer
) {
3244 (struct thread
*)bpi
->extra
->vnc
.import
.timer
;
3245 struct rfapi_withdraw
*wcb
= t
->arg
;
3247 XFREE(MTYPE_RFAPI_WITHDRAW
, wcb
);
3250 rfapiExpireEncapNow(import_table
, rn
, bpi
);
3253 rfapiNexthop2Prefix(((struct bgp_path_info
*)(rn
->info
))->attr
,
3257 * If the nexthop address of the selected Encap route (i.e.,
3258 * the UN address) has changed, then we must update the VPN
3259 * routes that refer to this Encap route and possibly force
3262 if (rfapiAttrNexthopAddrDifferent(&p_firstbpi_old
, &p_firstbpi_new
)) {
3264 struct rfapi_monitor_encap
*m
;
3265 struct rfapi_monitor_encap
*mnext
;
3267 struct agg_node
*referenced_vpn_prefix
;
3270 * Optimized approach: build radix tree on the fly to
3271 * hold list of VPN nodes referenced by the ENCAP monitors
3273 * The nodes in this table correspond to prefixes of VPN routes.
3274 * The "info" pointer of the node points to a chain of
3275 * struct rfapi_monitor_encap, each of which refers to a
3276 * specific VPN node.
3278 struct agg_table
*referenced_vpn_table
;
3280 referenced_vpn_table
= agg_table_init();
3281 assert(referenced_vpn_table
);
3284 * iterate over the set of monitors at this ENCAP node.
3286 #if DEBUG_ENCAP_MONITOR
3287 vnc_zlog_debug_verbose("%s: examining monitors at rn=%p",
3290 for (m
= RFAPI_MONITOR_ENCAP(rn
); m
; m
= m
->next
) {
3293 * For each referenced bpi/route, copy the ENCAP route's
3294 * nexthop to the VPN route's cached UN address field
3296 * the address family of the cached UN address field.
3298 rfapiCopyUnEncap2VPN(info_new
, m
->bpi
);
3299 if (!CHECK_FLAG(m
->bpi
->flags
, BGP_PATH_VALID
)) {
3300 SET_FLAG(m
->bpi
->flags
, BGP_PATH_VALID
);
3301 if (VALID_INTERIOR_TYPE(m
->bpi
->type
))
3302 RFAPI_MONITOR_EXTERIOR(m
->node
)
3303 ->valid_interior_count
++;
3304 vnc_import_bgp_exterior_add_route_interior(
3305 bgp
, import_table
, m
->node
, m
->bpi
);
3309 * Build a list of unique VPN nodes referenced by these
3312 * There could be more than one VPN node here with a
3314 * prefix. Those are currently in an unsorted linear
3319 referenced_vpn_prefix
=
3320 agg_node_get(referenced_vpn_table
, &m
->node
->p
);
3321 assert(referenced_vpn_prefix
);
3322 for (mnext
= referenced_vpn_prefix
->info
; mnext
;
3323 mnext
= mnext
->next
) {
3325 if (mnext
->node
== m
->node
)
3331 * already have an entry for this VPN node
3333 agg_unlock_node(referenced_vpn_prefix
);
3336 MTYPE_RFAPI_MONITOR_ENCAP
,
3337 sizeof(struct rfapi_monitor_encap
));
3339 mnext
->node
= m
->node
;
3340 mnext
->next
= referenced_vpn_prefix
->info
;
3341 referenced_vpn_prefix
->info
= mnext
;
3346 * for each VPN node referenced in the ENCAP monitors:
3348 for (referenced_vpn_prefix
=
3349 agg_route_top(referenced_vpn_table
);
3350 referenced_vpn_prefix
;
3351 referenced_vpn_prefix
=
3352 agg_route_next(referenced_vpn_prefix
)) {
3354 while ((m
= referenced_vpn_prefix
->info
)) {
3358 rfapiMonitorMoveLonger(m
->node
);
3359 for (n
= m
->node
; n
; n
= agg_node_parent(n
)) {
3360 // rfapiDoRouteCallback(import_table, n,
3363 rfapiMonitorItNodeChanged(import_table
, m
->node
,
3366 referenced_vpn_prefix
->info
= m
->next
;
3367 agg_unlock_node(referenced_vpn_prefix
);
3368 XFREE(MTYPE_RFAPI_MONITOR_ENCAP
, m
);
3371 agg_table_finish(referenced_vpn_table
);
3374 RFAPI_CHECK_REFCOUNT(rn
, SAFI_ENCAP
, 0);
3377 static void rfapiExpireVpnNow(struct rfapi_import_table
*it
,
3378 struct agg_node
*rn
, struct bgp_path_info
*bpi
,
3381 struct rfapi_withdraw
*wcb
;
3385 * pretend we're an expiring timer
3387 wcb
= XCALLOC(MTYPE_RFAPI_WITHDRAW
, sizeof(struct rfapi_withdraw
));
3390 wcb
->import_table
= it
;
3391 wcb
->lockoffset
= lockoffset
;
3392 memset(&t
, 0, sizeof(t
));
3394 rfapiWithdrawTimerVPN(&t
); /* frees wcb */
3399 * import a bgp_path_info if its route target list intersects with the
3400 * import table's route target list
3402 void rfapiBgpInfoFilteredImportVPN(
3403 struct rfapi_import_table
*import_table
, int action
, struct peer
*peer
,
3404 void *rfd
, /* set for looped back routes */
3406 struct prefix
*aux_prefix
, /* AFI_L2VPN: optional IP */
3407 afi_t afi
, struct prefix_rd
*prd
,
3408 struct attr
*attr
, /* part of bgp_path_info */
3409 uint8_t type
, /* part of bgp_path_info */
3410 uint8_t sub_type
, /* part of bgp_path_info */
3411 uint32_t *label
) /* part of bgp_path_info */
3413 struct agg_table
*rt
= NULL
;
3414 struct agg_node
*rn
;
3416 struct bgp_path_info
*info_new
;
3417 struct bgp_path_info
*bpi
;
3418 struct bgp_path_info
*next
;
3420 struct prefix vn_prefix
;
3421 struct prefix un_prefix
;
3422 int un_prefix_valid
= 0;
3423 struct agg_node
*ern
;
3425 int original_had_routes
= 0;
3426 struct prefix original_nexthop
;
3427 const char *action_str
= NULL
;
3431 bgp
= bgp_get_default(); /* assume 1 instance for now */
3434 case FIF_ACTION_UPDATE
:
3435 action_str
= "update";
3437 case FIF_ACTION_WITHDRAW
:
3438 action_str
= "withdraw";
3440 case FIF_ACTION_KILL
:
3441 action_str
= "kill";
3448 if (import_table
== bgp
->rfapi
->it_ce
)
3451 vnc_zlog_debug_verbose("%s: entry: %s%s: prefix %s/%d: it %p, afi %s",
3452 __func__
, (is_it_ce
? "CE-IT " : ""), action_str
,
3453 rfapi_ntop(p
->family
, &p
->u
.prefix
, buf
, BUFSIZ
),
3454 p
->prefixlen
, import_table
, afi2str(afi
));
3459 * Compare rt lists. If no intersection, don't import this route
3460 * On a withdraw, peer and RD are sufficient to determine if
3463 if (action
== FIF_ACTION_UPDATE
) {
3464 if (!attr
|| !attr
->ecommunity
) {
3466 vnc_zlog_debug_verbose(
3467 "%s: attr, extra, or ecommunity missing, not importing",
3471 if ((import_table
!= bgp
->rfapi
->it_ce
)
3472 && !rfapiEcommunitiesIntersect(import_table
->rt_import_list
,
3473 attr
->ecommunity
)) {
3475 vnc_zlog_debug_verbose(
3476 "%s: it=%p: no ecommunity intersection",
3477 __func__
, import_table
);
3481 memset(&vn_prefix
, 0,
3482 sizeof(vn_prefix
)); /* keep valgrind happy */
3483 if (rfapiGetNexthop(attr
, &vn_prefix
)) {
3484 /* missing nexthop address would be a bad, bad thing */
3485 vnc_zlog_debug_verbose("%s: missing nexthop", __func__
);
3491 * Figure out which radix tree the route would go into
3497 rt
= import_table
->imported_vpn
[afi
];
3501 flog_err(EC_LIB_DEVELOPMENT
, "%s: bad afi %d", __func__
, afi
);
3506 memset(&original_nexthop
, 0, sizeof(original_nexthop
));
3509 * agg_node_lookup returns a node only if there is at least
3510 * one route attached.
3512 rn
= agg_node_lookup(rt
, p
);
3514 vnc_zlog_debug_verbose("%s: rn=%p", __func__
, rn
);
3518 RFAPI_CHECK_REFCOUNT(rn
, SAFI_MPLS_VPN
, 1);
3519 agg_unlock_node(rn
); /* undo lock in agg_node_lookup */
3522 original_had_routes
= 1;
3524 if (VNC_DEBUG(VERBOSE
)) {
3525 vnc_zlog_debug_verbose("%s: showing IT node on entry",
3527 rfapiShowItNode(NULL
, rn
); /* debug */
3531 * Look for same route (will have same RD and peer)
3533 bpi
= rfapiItBiIndexSearch(rn
, prd
, peer
, aux_prefix
);
3538 * This was an old test when we iterated over the
3539 * BPIs linearly. Since we're now looking up with
3540 * RD and peer, comparing types should not be
3541 * needed. Changed to assertion.
3543 * Compare types. Doing so prevents a RFP-originated
3544 * route from matching an imported route, for example.
3546 if (VNC_DEBUG(VERBOSE
) && bpi
->type
!= type
)
3547 /* should be handled by RDs, but warn for now */
3548 zlog_warn("%s: type mismatch! (bpi=%d, arg=%d)",
3549 __func__
, bpi
->type
, type
);
3551 vnc_zlog_debug_verbose("%s: found matching bpi",
3555 * In the special CE table, withdrawals occur without
3558 if (import_table
== bgp
->rfapi
->it_ce
) {
3559 vnc_direct_bgp_del_route_ce(bgp
, rn
, bpi
);
3560 if (action
== FIF_ACTION_WITHDRAW
)
3561 action
= FIF_ACTION_KILL
;
3564 if (action
== FIF_ACTION_WITHDRAW
) {
3566 int washolddown
= CHECK_FLAG(bpi
->flags
,
3569 vnc_zlog_debug_verbose(
3570 "%s: withdrawing at prefix %s/%d%s",
3571 __func__
, rfapi_ntop(rn
->p
.family
,
3576 ? " (already being withdrawn)"
3581 rfapiBiStartWithdrawTimer(
3582 import_table
, rn
, bpi
, afi
,
3584 rfapiWithdrawTimerVPN
);
3586 RFAPI_UPDATE_ITABLE_COUNT(
3587 bpi
, import_table
, afi
, -1);
3588 import_table
->holddown_count
[afi
] += 1;
3592 vnc_zlog_debug_verbose(
3593 "%s: %s at prefix %s/%d", __func__
,
3594 ((action
== FIF_ACTION_KILL
)
3597 rfapi_ntop(rn
->p
.family
,
3598 &rn
->p
.u
.prefix
, buf
,
3603 * If this route is waiting to be deleted
3605 * a previous withdraw, we must cancel its
3608 if (CHECK_FLAG(bpi
->flags
, BGP_PATH_REMOVED
)
3609 && bpi
->extra
->vnc
.import
.timer
) {
3612 (struct thread
*)bpi
->extra
->vnc
3614 struct rfapi_withdraw
*wcb
= t
->arg
;
3616 XFREE(MTYPE_RFAPI_WITHDRAW
, wcb
);
3619 import_table
->holddown_count
[afi
] -= 1;
3620 RFAPI_UPDATE_ITABLE_COUNT(
3621 bpi
, import_table
, afi
, 1);
3624 * decrement remote count (if route is remote)
3626 * we are going to remove it below
3628 RFAPI_UPDATE_ITABLE_COUNT(bpi
, import_table
,
3630 if (action
== FIF_ACTION_UPDATE
) {
3634 * make copy of original nexthop so we
3635 * can see if it changed
3637 rfapiGetNexthop(bpi
->attr
,
3641 * remove bpi without doing any export
3644 if (CHECK_FLAG(bpi
->flags
,
3646 && VALID_INTERIOR_TYPE(bpi
->type
))
3647 RFAPI_MONITOR_EXTERIOR(rn
)
3648 ->valid_interior_count
--;
3649 rfapiItBiIndexDel(rn
, bpi
);
3650 rfapiBgpInfoDetach(rn
, bpi
);
3651 rfapiMonitorEncapDelete(bpi
);
3652 vnc_import_bgp_exterior_del_route_interior(
3653 bgp
, import_table
, rn
, bpi
);
3654 rfapiBgpInfoFree(bpi
);
3658 * remove bpi and do export processing
3660 import_table
->holddown_count
[afi
] += 1;
3661 rfapiExpireVpnNow(import_table
, rn
, bpi
,
3669 RFAPI_CHECK_REFCOUNT(rn
, SAFI_MPLS_VPN
, replacing
? 1 : 0);
3671 if (action
== FIF_ACTION_WITHDRAW
|| action
== FIF_ACTION_KILL
) {
3677 rfapiBgpInfoCreate(attr
, peer
, rfd
, prd
, type
, sub_type
, label
);
3680 * lookup un address in encap table
3682 ern
= agg_node_match(import_table
->imported_encap
[afi
], &vn_prefix
);
3684 rfapiCopyUnEncap2VPN(ern
->info
, info_new
);
3685 agg_unlock_node(ern
); /* undo lock in route_note_match */
3687 char bpf
[PREFIX_STRLEN
];
3689 prefix2str(&vn_prefix
, bpf
, sizeof(bpf
));
3690 /* Not a big deal, just means VPN route got here first */
3691 vnc_zlog_debug_verbose("%s: no encap route for vn addr %s",
3693 info_new
->extra
->vnc
.import
.un_family
= 0;
3701 * No need to increment reference count, so only "get"
3702 * if the node is not there already
3704 rn
= agg_node_get(rt
, p
);
3708 * For ethernet routes, if there is an accompanying IP address,
3709 * save it in the bpi
3711 if ((AFI_L2VPN
== afi
) && aux_prefix
) {
3713 vnc_zlog_debug_verbose("%s: setting BPI's aux_prefix",
3715 info_new
->extra
->vnc
.import
.aux_prefix
= *aux_prefix
;
3718 vnc_zlog_debug_verbose(
3719 "%s: inserting bpi %p at prefix %s/%d #%d", __func__
, info_new
,
3720 rfapi_ntop(rn
->p
.family
, &rn
->p
.u
.prefix
, buf
, BUFSIZ
),
3721 rn
->p
.prefixlen
, rn
->lock
);
3723 rfapiBgpInfoAttachSorted(rn
, info_new
, afi
, SAFI_MPLS_VPN
);
3724 rfapiItBiIndexAdd(rn
, info_new
);
3725 if (!rfapiGetUnAddrOfVpnBi(info_new
, NULL
)) {
3726 if (VALID_INTERIOR_TYPE(info_new
->type
))
3727 RFAPI_MONITOR_EXTERIOR(rn
)->valid_interior_count
++;
3728 SET_FLAG(info_new
->flags
, BGP_PATH_VALID
);
3730 RFAPI_UPDATE_ITABLE_COUNT(info_new
, import_table
, afi
, 1);
3731 vnc_import_bgp_exterior_add_route_interior(bgp
, import_table
, rn
,
3734 if (import_table
== bgp
->rfapi
->it_ce
)
3735 vnc_direct_bgp_add_route_ce(bgp
, rn
, info_new
);
3737 if (VNC_DEBUG(VERBOSE
)) {
3738 vnc_zlog_debug_verbose("%s: showing IT node", __func__
);
3739 rfapiShowItNode(NULL
, rn
); /* debug */
3742 rfapiMonitorEncapAdd(import_table
, &vn_prefix
, rn
, info_new
);
3744 if (!rfapiGetUnAddrOfVpnBi(info_new
, &un_prefix
)) {
3747 * if we have a valid UN address (either via Encap route
3748 * or via tunnel attribute), then we should attempt
3749 * to move any monitors at less-specific nodes to this node
3751 rfapiMonitorMoveLonger(rn
);
3753 un_prefix_valid
= 1;
3757 * 101129 Enhancement: if we add a route (implication: it is not
3758 * in holddown), delete all other routes from this nve at this
3759 * node that are in holddown, regardless of peer.
3761 * Reasons it's OK to do that:
3763 * - if the holddown route being deleted originally came from BGP VPN,
3764 * it is already gone from BGP (implication of holddown), so there
3765 * won't be any added inconsistency with the BGP RIB.
3767 * - once a fresh route is added at a prefix, any routes in holddown
3768 * at that prefix will not show up in RFP responses, so deleting
3769 * the holddown routes won't affect the contents of responses.
3771 * - lifetimes are supposed to be consistent, so there should not
3772 * be a case where the fresh route has a shorter lifetime than
3773 * the holddown route, so we don't expect the fresh route to
3774 * disappear and complete its holddown time before the existing
3775 * holddown routes time out. Therefore, we won't have a situation
3776 * where we expect the existing holddown routes to be hidden and
3777 * then to reappear sometime later (as holddown routes) in a
3780 * Among other things, this would enable us to skirt the problem
3781 * of local holddown routes that refer to NVE descriptors that
3782 * have already been closed (if the same NVE triggers a subsequent
3783 * rfapi_open(), the new peer is different and doesn't match the
3784 * peer of the holddown route, so the stale holddown route still
3785 * hangs around until it times out instead of just being replaced
3786 * by the fresh route).
3789 * We know that the new bpi will have been inserted before any routes
3790 * in holddown, so we can skip any that came before it
3792 for (bpi
= info_new
->next
; bpi
; bpi
= next
) {
3794 struct prefix pfx_vn
;
3795 struct prefix pfx_un
;
3797 int remote_peer_match
= 0;
3804 if (!CHECK_FLAG(bpi
->flags
, BGP_PATH_REMOVED
))
3808 * Must match VN address (nexthop of VPN route)
3810 if (rfapiGetNexthop(bpi
->attr
, &pfx_vn
))
3812 if (!prefix_same(&pfx_vn
, &vn_prefix
))
3815 if (un_prefix_valid
&& /* new route UN addr */
3816 !rfapiGetUnAddrOfVpnBi(bpi
, &pfx_un
)
3817 && /* old route UN addr */
3818 prefix_same(&pfx_un
, &un_prefix
)) { /* compare */
3821 if (!RFAPI_LOCAL_BI(bpi
) && !RFAPI_LOCAL_BI(info_new
)
3822 && sockunion_same(&bpi
->peer
->su
, &info_new
->peer
->su
)) {
3823 /* old & new are both remote, same peer */
3824 remote_peer_match
= 1;
3827 if (!un_match
& !remote_peer_match
)
3830 vnc_zlog_debug_verbose(
3831 "%s: removing holddown bpi matching NVE of new route",
3833 if (bpi
->extra
->vnc
.import
.timer
) {
3835 (struct thread
*)bpi
->extra
->vnc
.import
.timer
;
3836 struct rfapi_withdraw
*wcb
= t
->arg
;
3838 XFREE(MTYPE_RFAPI_WITHDRAW
, wcb
);
3841 rfapiExpireVpnNow(import_table
, rn
, bpi
, 0);
3844 if (!original_had_routes
) {
3846 * We went from 0 usable routes to 1 usable route. Perform the
3847 * "Adding a Route" export process.
3849 vnc_direct_bgp_add_prefix(bgp
, import_table
, rn
);
3850 vnc_zebra_add_prefix(bgp
, import_table
, rn
);
3853 * Check for nexthop change event
3854 * Note: the prefix_same() test below detects two situations:
3855 * 1. route is replaced, new route has different nexthop
3856 * 2. new route is added (original_nexthop is 0)
3858 struct prefix new_nexthop
;
3860 rfapiGetNexthop(attr
, &new_nexthop
);
3861 if (!prefix_same(&original_nexthop
, &new_nexthop
)) {
3863 * nexthop change event
3864 * vnc_direct_bgp_add_prefix() will recompute VN addr
3867 vnc_direct_bgp_add_prefix(bgp
, import_table
, rn
);
3871 if (!(bgp
->rfapi_cfg
->flags
& BGP_VNC_CONFIG_CALLBACK_DISABLE
)) {
3872 for (n
= rn
; n
; n
= agg_node_parent(n
)) {
3873 // rfapiDoRouteCallback(import_table, n, NULL);
3875 rfapiMonitorItNodeChanged(import_table
, rn
, NULL
);
3877 RFAPI_CHECK_REFCOUNT(rn
, SAFI_MPLS_VPN
, 0);
3881 static void rfapiBgpInfoFilteredImportBadSafi(
3882 struct rfapi_import_table
*import_table
, int action
, struct peer
*peer
,
3883 void *rfd
, /* set for looped back routes */
3885 struct prefix
*aux_prefix
, /* AFI_L2VPN: optional IP */
3886 afi_t afi
, struct prefix_rd
*prd
,
3887 struct attr
*attr
, /* part of bgp_path_info */
3888 uint8_t type
, /* part of bgp_path_info */
3889 uint8_t sub_type
, /* part of bgp_path_info */
3890 uint32_t *label
) /* part of bgp_path_info */
3892 vnc_zlog_debug_verbose("%s: Error, bad safi", __func__
);
3895 static rfapi_bi_filtered_import_f
*
3896 rfapiBgpInfoFilteredImportFunction(safi_t safi
)
3900 return rfapiBgpInfoFilteredImportVPN
;
3903 return rfapiBgpInfoFilteredImportEncap
;
3907 flog_err(EC_LIB_DEVELOPMENT
, "%s: bad safi %d", __func__
, safi
);
3908 return rfapiBgpInfoFilteredImportBadSafi
;
3912 void rfapiProcessUpdate(struct peer
*peer
,
3913 void *rfd
, /* set when looped from RFP/RFAPI */
3914 struct prefix
*p
, struct prefix_rd
*prd
,
3915 struct attr
*attr
, afi_t afi
, safi_t safi
, uint8_t type
,
3916 uint8_t sub_type
, uint32_t *label
)
3920 struct rfapi_import_table
*it
;
3921 int has_ip_route
= 1;
3924 bgp
= bgp_get_default(); /* assume 1 instance for now */
3931 * look at high-order byte of RD. FF means MAC
3932 * address is present (VNC L2VPN)
3934 if ((safi
== SAFI_MPLS_VPN
)
3935 && (decode_rd_type(prd
->val
) == RD_TYPE_VNC_ETH
)) {
3936 struct prefix pfx_mac_buf
;
3937 struct prefix pfx_nexthop_buf
;
3941 * Set flag if prefix and nexthop are the same - don't
3942 * add the route to normal IP-based import tables
3944 if (!rfapiGetNexthop(attr
, &pfx_nexthop_buf
)) {
3945 if (!prefix_cmp(&pfx_nexthop_buf
, p
)) {
3950 memset(&pfx_mac_buf
, 0, sizeof(pfx_mac_buf
));
3951 pfx_mac_buf
.family
= AF_ETHERNET
;
3952 pfx_mac_buf
.prefixlen
= 48;
3953 memcpy(&pfx_mac_buf
.u
.prefix_eth
.octet
, prd
->val
+ 2, 6);
3956 * Find rt containing LNI (Logical Network ID), which
3957 * _should_ always be present when mac address is present
3959 rc
= rfapiEcommunityGetLNI(attr
->ecommunity
, &lni
);
3961 vnc_zlog_debug_verbose(
3962 "%s: rfapiEcommunityGetLNI returned %d, lni=%d, attr=%p",
3963 __func__
, rc
, lni
, attr
);
3965 it
= rfapiMacImportTableGet(bgp
, lni
);
3967 rfapiBgpInfoFilteredImportVPN(
3968 it
, FIF_ACTION_UPDATE
, peer
, rfd
,
3969 &pfx_mac_buf
, /* prefix */
3970 p
, /* aux prefix: IP addr */
3971 AFI_L2VPN
, prd
, attr
, type
, sub_type
, label
);
3979 * Iterate over all import tables; do a filtered import
3980 * for the afi/safi combination
3982 for (it
= h
->imports
; it
; it
= it
->next
) {
3983 (*rfapiBgpInfoFilteredImportFunction(safi
))(
3984 it
, FIF_ACTION_UPDATE
, peer
, rfd
, p
, /* prefix */
3985 NULL
, afi
, prd
, attr
, type
, sub_type
, label
);
3988 if (safi
== SAFI_MPLS_VPN
) {
3989 vnc_direct_bgp_rh_add_route(bgp
, afi
, p
, peer
, attr
);
3990 rfapiBgpInfoFilteredImportVPN(
3991 bgp
->rfapi
->it_ce
, FIF_ACTION_UPDATE
, peer
, rfd
,
3993 NULL
, afi
, prd
, attr
, type
, sub_type
, label
);
3998 void rfapiProcessWithdraw(struct peer
*peer
, void *rfd
, struct prefix
*p
,
3999 struct prefix_rd
*prd
, struct attr
*attr
, afi_t afi
,
4000 safi_t safi
, uint8_t type
, int kill
)
4004 struct rfapi_import_table
*it
;
4006 bgp
= bgp_get_default(); /* assume 1 instance for now */
4013 * look at high-order byte of RD. FF means MAC
4014 * address is present (VNC L2VPN)
4016 if (h
->import_mac
!= NULL
&& safi
== SAFI_MPLS_VPN
4017 && decode_rd_type(prd
->val
) == RD_TYPE_VNC_ETH
) {
4018 struct prefix pfx_mac_buf
;
4019 void *cursor
= NULL
;
4022 memset(&pfx_mac_buf
, 0, sizeof(pfx_mac_buf
));
4023 pfx_mac_buf
.family
= AF_ETHERNET
;
4024 pfx_mac_buf
.prefixlen
= 48;
4025 memcpy(&pfx_mac_buf
.u
.prefix_eth
, prd
->val
+ 2, 6);
4028 * withdraw does not contain attrs, so we don't have
4029 * access to the route's LNI, which would ordinarily
4030 * select the specific mac-based import table. Instead,
4031 * we must iterate over all mac-based tables and rely
4032 * on the RD to match.
4034 * If this approach is too slow, add an index where
4035 * key is {RD, peer} and value is the import table
4037 for (rc
= skiplist_next(h
->import_mac
, NULL
, (void **)&it
,
4039 rc
== 0; rc
= skiplist_next(h
->import_mac
, NULL
,
4040 (void **)&it
, &cursor
)) {
4043 vnc_zlog_debug_verbose(
4044 "%s: calling rfapiBgpInfoFilteredImportVPN(it=%p, afi=AFI_L2VPN)",
4048 rfapiBgpInfoFilteredImportVPN(
4050 (kill
? FIF_ACTION_KILL
: FIF_ACTION_WITHDRAW
),
4051 peer
, rfd
, &pfx_mac_buf
, /* prefix */
4052 p
, /* aux_prefix: IP */
4053 AFI_L2VPN
, prd
, attr
, type
, 0,
4054 NULL
); /* sub_type & label unused for withdraw
4060 * XXX For the case where the withdraw involves an L2
4061 * route with no IP information, we rely on the lack
4062 * of RT-list intersection to filter out the withdraw
4063 * from the IP-based import tables below
4067 * Iterate over all import tables; do a filtered import
4068 * for the afi/safi combination
4071 for (it
= h
->imports
; it
; it
= it
->next
) {
4072 (*rfapiBgpInfoFilteredImportFunction(safi
))(
4073 it
, (kill
? FIF_ACTION_KILL
: FIF_ACTION_WITHDRAW
),
4074 peer
, rfd
, p
, /* prefix */
4075 NULL
, afi
, prd
, attr
, type
, 0,
4076 NULL
); /* sub_type & label unused for withdraw */
4079 /* TBD the deletion should happen after the lifetime expires */
4080 if (safi
== SAFI_MPLS_VPN
)
4081 vnc_direct_bgp_rh_del_route(bgp
, afi
, p
, peer
);
4083 if (safi
== SAFI_MPLS_VPN
) {
4084 rfapiBgpInfoFilteredImportVPN(
4086 (kill
? FIF_ACTION_KILL
: FIF_ACTION_WITHDRAW
), peer
,
4087 rfd
, p
, /* prefix */
4088 NULL
, afi
, prd
, attr
, type
, 0,
4089 NULL
); /* sub_type & label unused for withdraw */
4094 * TBD optimized withdraw timer algorithm for case of many
4095 * routes expiring at the same time due to peer drop.
4098 * 1. Visit all BPIs in all ENCAP import tables.
4100 * a. If a bpi's peer is the failed peer, remove the bpi.
4101 * b. If the removed ENCAP bpi was first in the list of
4102 * BPIs at this ENCAP node, loop over all monitors
4105 * (1) for each ENCAP monitor, loop over all its
4106 * VPN node monitors and set their RFAPI_MON_FLAG_NEEDCALLBACK
4109 * 2. Visit all BPIs in all VPN import tables.
4110 * a. If a bpi's peer is the failed peer, remove the bpi.
4111 * b. loop over all the VPN node monitors and set their
4112 * RFAPI_MON_FLAG_NEEDCALLBACK flags
4113 * c. If there are no BPIs left at this VPN node,
4118 /* surprise, this gets called from peer_delete(), from rfapi_close() */
4119 static void rfapiProcessPeerDownRt(struct peer
*peer
,
4120 struct rfapi_import_table
*import_table
,
4121 afi_t afi
, safi_t safi
)
4123 struct agg_node
*rn
;
4124 struct bgp_path_info
*bpi
;
4125 struct agg_table
*rt
;
4126 int (*timer_service_func
)(struct thread
*);
4128 assert(afi
== AFI_IP
|| afi
== AFI_IP6
);
4134 rt
= import_table
->imported_vpn
[afi
];
4135 timer_service_func
= rfapiWithdrawTimerVPN
;
4138 rt
= import_table
->imported_encap
[afi
];
4139 timer_service_func
= rfapiWithdrawTimerEncap
;
4146 for (rn
= agg_route_top(rt
); rn
; rn
= agg_route_next(rn
)) {
4147 for (bpi
= rn
->info
; bpi
; bpi
= bpi
->next
) {
4148 if (bpi
->peer
== peer
) {
4150 if (CHECK_FLAG(bpi
->flags
, BGP_PATH_REMOVED
)) {
4151 /* already in holddown, skip */
4155 if (safi
== SAFI_MPLS_VPN
) {
4156 RFAPI_UPDATE_ITABLE_COUNT(
4157 bpi
, import_table
, afi
, -1);
4158 import_table
->holddown_count
[afi
] += 1;
4160 rfapiBiStartWithdrawTimer(import_table
, rn
, bpi
,
4162 timer_service_func
);
4170 * This gets called when a peer connection drops. We have to remove
4171 * all the routes from this peer.
4173 * Current approach is crude. TBD Optimize by setting fewer timers and
4174 * grouping withdrawn routes so we can generate callbacks more
4177 void rfapiProcessPeerDown(struct peer
*peer
)
4181 struct rfapi_import_table
*it
;
4184 * If this peer is a "dummy" peer structure atached to a RFAPI
4185 * nve_descriptor, we don't need to walk the import tables
4186 * because the routes are already withdrawn by rfapi_close()
4188 if (CHECK_FLAG(peer
->flags
, PEER_FLAG_IS_RFAPI_HD
))
4192 * 1. Visit all BPIs in all ENCAP import tables.
4193 * Start withdraw timer on the BPIs that match peer.
4195 * 2. Visit All BPIs in all VPN import tables.
4196 * Start withdraw timer on the BPIs that match peer.
4199 bgp
= bgp_get_default(); /* assume 1 instance for now */
4206 for (it
= h
->imports
; it
; it
= it
->next
) {
4207 rfapiProcessPeerDownRt(peer
, it
, AFI_IP
, SAFI_ENCAP
);
4208 rfapiProcessPeerDownRt(peer
, it
, AFI_IP6
, SAFI_ENCAP
);
4209 rfapiProcessPeerDownRt(peer
, it
, AFI_IP
, SAFI_MPLS_VPN
);
4210 rfapiProcessPeerDownRt(peer
, it
, AFI_IP6
, SAFI_MPLS_VPN
);
4214 rfapiProcessPeerDownRt(peer
, h
->it_ce
, AFI_IP
, SAFI_MPLS_VPN
);
4215 rfapiProcessPeerDownRt(peer
, h
->it_ce
, AFI_IP6
, SAFI_MPLS_VPN
);
4220 * Import an entire RIB (for an afi/safi) to an import table RIB,
4221 * filtered according to the import table's RT list
4223 * TBD: does this function need additions to match rfapiProcessUpdate()
4224 * for, e.g., L2 handling?
4226 static void rfapiBgpTableFilteredImport(struct bgp
*bgp
,
4227 struct rfapi_import_table
*it
,
4228 afi_t afi
, safi_t safi
)
4230 struct bgp_node
*rn1
;
4231 struct bgp_node
*rn2
;
4233 /* Only these SAFIs have 2-level RIBS */
4234 assert(safi
== SAFI_MPLS_VPN
|| safi
== SAFI_ENCAP
);
4237 * Now visit all the rd nodes and the nodes of all the
4238 * route tables attached to them, and import the routes
4239 * if they have matching route targets
4241 for (rn1
= bgp_table_top(bgp
->rib
[afi
][safi
]); rn1
;
4242 rn1
= bgp_route_next(rn1
)) {
4244 if (bgp_node_has_bgp_path_info_data(rn1
)) {
4246 for (rn2
= bgp_table_top(bgp_node_get_bgp_table_info(rn1
)); rn2
;
4247 rn2
= bgp_route_next(rn2
)) {
4249 struct bgp_path_info
*bpi
;
4251 for (bpi
= bgp_node_get_bgp_path_info(rn2
);
4252 bpi
; bpi
= bpi
->next
) {
4255 if (CHECK_FLAG(bpi
->flags
,
4260 label
= decode_label(
4261 &bpi
->extra
->label
[0]);
4262 (*rfapiBgpInfoFilteredImportFunction(
4264 it
, /* which import table */
4265 FIF_ACTION_UPDATE
, bpi
->peer
,
4266 NULL
, &rn2
->p
, /* prefix */
4268 (struct prefix_rd
*)&rn1
->p
,
4269 bpi
->attr
, bpi
->type
,
4270 bpi
->sub_type
, &label
);
4278 /* per-bgp-instance rfapi data */
4279 struct rfapi
*bgp_rfapi_new(struct bgp
*bgp
)
4283 struct rfapi_rfp_cfg
*cfg
= NULL
;
4284 struct rfapi_rfp_cb_methods
*cbm
= NULL
;
4286 assert(bgp
->rfapi_cfg
== NULL
);
4288 h
= (struct rfapi
*)XCALLOC(MTYPE_RFAPI
, sizeof(struct rfapi
));
4290 for (afi
= AFI_IP
; afi
< AFI_MAX
; afi
++) {
4291 h
->un
[afi
] = agg_table_init();
4295 * initialize the ce import table
4297 h
->it_ce
= XCALLOC(MTYPE_RFAPI_IMPORTTABLE
,
4298 sizeof(struct rfapi_import_table
));
4299 h
->it_ce
->imported_vpn
[AFI_IP
] = agg_table_init();
4300 h
->it_ce
->imported_vpn
[AFI_IP6
] = agg_table_init();
4301 h
->it_ce
->imported_encap
[AFI_IP
] = agg_table_init();
4302 h
->it_ce
->imported_encap
[AFI_IP6
] = agg_table_init();
4303 rfapiBgpTableFilteredImport(bgp
, h
->it_ce
, AFI_IP
, SAFI_MPLS_VPN
);
4304 rfapiBgpTableFilteredImport(bgp
, h
->it_ce
, AFI_IP6
, SAFI_MPLS_VPN
);
4307 * Set up work queue for deferred rfapi_close operations
4309 h
->deferred_close_q
=
4310 work_queue_new(bm
->master
, "rfapi deferred close");
4311 h
->deferred_close_q
->spec
.workfunc
= rfapi_deferred_close_workfunc
;
4312 h
->deferred_close_q
->spec
.data
= h
;
4314 h
->rfp
= rfp_start(bm
->master
, &cfg
, &cbm
);
4315 bgp
->rfapi_cfg
= bgp_rfapi_cfg_new(cfg
);
4317 h
->rfp_methods
= *cbm
;
4322 void bgp_rfapi_destroy(struct bgp
*bgp
, struct rfapi
*h
)
4326 if (bgp
== NULL
|| h
== NULL
)
4329 if (h
->resolve_nve_nexthop
) {
4330 skiplist_free(h
->resolve_nve_nexthop
);
4331 h
->resolve_nve_nexthop
= NULL
;
4334 agg_table_finish(h
->it_ce
->imported_vpn
[AFI_IP
]);
4335 agg_table_finish(h
->it_ce
->imported_vpn
[AFI_IP6
]);
4336 agg_table_finish(h
->it_ce
->imported_encap
[AFI_IP
]);
4337 agg_table_finish(h
->it_ce
->imported_encap
[AFI_IP6
]);
4339 if (h
->import_mac
) {
4340 struct rfapi_import_table
*it
;
4345 rc
= skiplist_next(h
->import_mac
, NULL
, (void **)&it
,
4347 !rc
; rc
= skiplist_next(h
->import_mac
, NULL
, (void **)&it
,
4350 rfapiImportTableFlush(it
);
4351 XFREE(MTYPE_RFAPI_IMPORTTABLE
, it
);
4353 skiplist_free(h
->import_mac
);
4354 h
->import_mac
= NULL
;
4357 work_queue_free_and_null(&h
->deferred_close_q
);
4362 for (afi
= AFI_IP
; afi
< AFI_MAX
; afi
++) {
4363 agg_table_finish(h
->un
[afi
]);
4366 XFREE(MTYPE_RFAPI_IMPORTTABLE
, h
->it_ce
);
4367 XFREE(MTYPE_RFAPI
, h
);
4370 struct rfapi_import_table
*
4371 rfapiImportTableRefAdd(struct bgp
*bgp
, struct ecommunity
*rt_import_list
,
4372 struct rfapi_nve_group_cfg
*rfg
)
4375 struct rfapi_import_table
*it
;
4381 for (it
= h
->imports
; it
; it
= it
->next
) {
4382 if (ecommunity_cmp(it
->rt_import_list
, rt_import_list
))
4386 vnc_zlog_debug_verbose("%s: matched it=%p", __func__
, it
);
4389 it
= XCALLOC(MTYPE_RFAPI_IMPORTTABLE
,
4390 sizeof(struct rfapi_import_table
));
4392 it
->next
= h
->imports
;
4395 it
->rt_import_list
= ecommunity_dup(rt_import_list
);
4397 it
->monitor_exterior_orphans
=
4398 skiplist_new(0, NULL
, (void (*)(void *))prefix_free
);
4401 * fill import route tables from RIBs
4403 * Potential area for optimization. If this occurs when
4404 * tables are large (e.g., the operator adds a nve group
4405 * with a new RT list to a running system), it could take
4409 for (afi
= AFI_IP
; afi
< AFI_MAX
; ++afi
) {
4411 it
->imported_vpn
[afi
] = agg_table_init();
4412 it
->imported_encap
[afi
] = agg_table_init();
4414 rfapiBgpTableFilteredImport(bgp
, it
, afi
,
4416 rfapiBgpTableFilteredImport(bgp
, it
, afi
, SAFI_ENCAP
);
4418 vnc_import_bgp_exterior_redist_enable_it(bgp
, afi
, it
);
4428 * skiplist element free function
4430 static void delete_rem_pfx_na_free(void *na
)
4432 uint32_t *pCounter
= ((struct rfapi_nve_addr
*)na
)->info
;
4435 XFREE(MTYPE_RFAPI_NVE_ADDR
, na
);
4439 * Common deleter for IP and MAC import tables
4441 static void rfapiDeleteRemotePrefixesIt(
4442 struct bgp
*bgp
, struct rfapi_import_table
*it
, struct prefix
*un
,
4443 struct prefix
*vn
, struct prefix
*p
, int delete_active
,
4444 int delete_holddown
, uint32_t *pARcount
, uint32_t *pAHcount
,
4445 uint32_t *pHRcount
, uint32_t *pHHcount
,
4446 struct skiplist
*uniq_active_nves
, struct skiplist
*uniq_holddown_nves
)
4452 char buf_pfx
[PREFIX_STRLEN
];
4455 prefix2str(p
, buf_pfx
, sizeof(buf_pfx
));
4461 vnc_zlog_debug_verbose(
4462 "%s: entry, p=%s, delete_active=%d, delete_holddown=%d",
4463 __func__
, buf_pfx
, delete_active
, delete_holddown
);
4467 for (afi
= AFI_IP
; afi
< AFI_MAX
; ++afi
) {
4469 struct agg_table
*rt
;
4470 struct agg_node
*rn
;
4472 if (p
&& (family2afi(p
->family
) != afi
)) {
4476 rt
= it
->imported_vpn
[afi
];
4480 vnc_zlog_debug_verbose("%s: scanning rt for afi=%d", __func__
,
4483 for (rn
= agg_route_top(rt
); rn
; rn
= agg_route_next(rn
)) {
4484 struct bgp_path_info
*bpi
;
4485 struct bgp_path_info
*next
;
4487 if (p
&& VNC_DEBUG(IMPORT_DEL_REMOTE
)) {
4488 char p1line
[PREFIX_STRLEN
];
4489 char p2line
[PREFIX_STRLEN
];
4491 prefix2str(p
, p1line
, sizeof(p1line
));
4492 prefix2str(&rn
->p
, p2line
, sizeof(p2line
));
4493 vnc_zlog_debug_any("%s: want %s, have %s",
4494 __func__
, p1line
, p2line
);
4497 if (p
&& prefix_cmp(p
, &rn
->p
))
4501 char buf_pfx
[PREFIX_STRLEN
];
4503 prefix2str(&rn
->p
, buf_pfx
, sizeof(buf_pfx
));
4504 vnc_zlog_debug_verbose("%s: rn pfx=%s",
4508 /* TBD is this valid for afi == AFI_L2VPN? */
4509 RFAPI_CHECK_REFCOUNT(rn
, SAFI_MPLS_VPN
, 1);
4511 for (bpi
= rn
->info
; bpi
; bpi
= next
) {
4520 vnc_zlog_debug_verbose("%s: examining bpi %p",
4524 if (!rfapiGetNexthop(bpi
->attr
, &qpt
))
4529 || !prefix_match(vn
, &qpt
)) {
4531 vnc_zlog_debug_verbose(
4532 "%s: continue at vn && !qpt_valid || !prefix_match(vn, &qpt)",
4539 if (!rfapiGetUnAddrOfVpnBi(bpi
, &qct
))
4544 || !prefix_match(un
, &qct
)) {
4546 vnc_zlog_debug_verbose(
4547 "%s: continue at un && !qct_valid || !prefix_match(un, &qct)",
4559 * If this route is waiting to be deleted
4561 * a previous withdraw, we must cancel its
4564 if (CHECK_FLAG(bpi
->flags
, BGP_PATH_REMOVED
)) {
4565 if (!delete_holddown
)
4567 if (bpi
->extra
->vnc
.import
.timer
) {
4570 (struct thread
*)bpi
4573 struct rfapi_withdraw
*wcb
=
4577 ->holddown_count
[afi
] -=
4579 RFAPI_UPDATE_ITABLE_COUNT(
4580 bpi
, wcb
->import_table
,
4582 XFREE(MTYPE_RFAPI_WITHDRAW
,
4592 vnc_zlog_debug_verbose(
4593 "%s: deleting bpi %p (qct_valid=%d, qpt_valid=%d, delete_holddown=%d, delete_active=%d)",
4594 __func__
, bpi
, qct_valid
, qpt_valid
,
4595 delete_holddown
, delete_active
);
4601 if (qct_valid
&& qpt_valid
) {
4603 struct rfapi_nve_addr na
;
4604 struct rfapi_nve_addr
*nap
;
4606 memset(&na
, 0, sizeof(na
));
4607 assert(!rfapiQprefix2Raddr(&qct
,
4609 assert(!rfapiQprefix2Raddr(&qpt
,
4612 if (skiplist_search(
4615 : uniq_holddown_nves
),
4616 &na
, (void **)&nap
)) {
4620 MTYPE_RFAPI_NVE_ADDR
,
4625 nap
->info
= is_active
4631 : uniq_holddown_nves
),
4634 rfapiNveAddr2Str(nap
, line
,
4639 vnc_direct_bgp_rh_del_route(bgp
, afi
, &rn
->p
,
4642 RFAPI_UPDATE_ITABLE_COUNT(bpi
, it
, afi
, -1);
4643 it
->holddown_count
[afi
] += 1;
4644 rfapiExpireVpnNow(it
, rn
, bpi
, 1);
4646 vnc_zlog_debug_verbose(
4647 "%s: incrementing count (is_active=%d)",
4648 __func__
, is_active
);
4661 * For use by the "clear vnc prefixes" command
4663 /*------------------------------------------
4664 * rfapiDeleteRemotePrefixes
4666 * UI helper: For use by the "clear vnc prefixes" command
4669 * un if set, tunnel must match this prefix
4670 * vn if set, nexthop prefix must match this prefix
4671 * p if set, prefix must match this prefix
4672 * it if set, only look in this import table
4675 * pARcount number of active routes deleted
4676 * pAHcount number of active nves deleted
4677 * pHRcount number of holddown routes deleted
4678 * pHHcount number of holddown nves deleted
4682 --------------------------------------------*/
4683 void rfapiDeleteRemotePrefixes(struct prefix
*un
, struct prefix
*vn
,
4685 struct rfapi_import_table
*arg_it
,
4686 int delete_active
, int delete_holddown
,
4687 uint32_t *pARcount
, uint32_t *pAHcount
,
4688 uint32_t *pHRcount
, uint32_t *pHHcount
)
4692 struct rfapi_import_table
*it
;
4693 uint32_t deleted_holddown_route_count
= 0;
4694 uint32_t deleted_active_route_count
= 0;
4695 uint32_t deleted_holddown_nve_count
= 0;
4696 uint32_t deleted_active_nve_count
= 0;
4697 struct skiplist
*uniq_holddown_nves
;
4698 struct skiplist
*uniq_active_nves
;
4702 bgp
= bgp_get_default(); /* assume 1 instance for now */
4703 /* If no bgp instantiated yet, no vnc prefixes exist */
4710 uniq_holddown_nves
=
4711 skiplist_new(0, rfapi_nve_addr_cmp
, delete_rem_pfx_na_free
);
4713 skiplist_new(0, rfapi_nve_addr_cmp
, delete_rem_pfx_na_free
);
4716 * Iterate over all import tables; do a filtered import
4717 * for the afi/safi combination
4726 vnc_zlog_debug_verbose(
4727 "%s: calling rfapiDeleteRemotePrefixesIt() on (IP) import %p",
4730 rfapiDeleteRemotePrefixesIt(
4731 bgp
, it
, un
, vn
, p
, delete_active
, delete_holddown
,
4732 &deleted_active_route_count
, &deleted_active_nve_count
,
4733 &deleted_holddown_route_count
,
4734 &deleted_holddown_nve_count
, uniq_active_nves
,
4735 uniq_holddown_nves
);
4744 * Now iterate over L2 import tables
4746 if (h
->import_mac
&& !(p
&& (p
->family
!= AF_ETHERNET
))) {
4748 void *cursor
= NULL
;
4752 rc
= skiplist_next(h
->import_mac
, NULL
, (void **)&it
,
4754 !rc
; rc
= skiplist_next(h
->import_mac
, NULL
, (void **)&it
,
4757 vnc_zlog_debug_verbose(
4758 "%s: calling rfapiDeleteRemotePrefixesIt() on import_mac %p",
4761 rfapiDeleteRemotePrefixesIt(
4762 bgp
, it
, un
, vn
, p
, delete_active
,
4763 delete_holddown
, &deleted_active_route_count
,
4764 &deleted_active_nve_count
,
4765 &deleted_holddown_route_count
,
4766 &deleted_holddown_nve_count
, uniq_active_nves
,
4767 uniq_holddown_nves
);
4772 * our custom element freeing function above counts as it deletes
4774 skiplist_free(uniq_holddown_nves
);
4775 skiplist_free(uniq_active_nves
);
4778 *pARcount
= deleted_active_route_count
;
4780 *pAHcount
= deleted_active_nve_count
;
4782 *pHRcount
= deleted_holddown_route_count
;
4784 *pHHcount
= deleted_holddown_nve_count
;
4789 /*------------------------------------------
4790 * rfapiCountRemoteRoutes
4792 * UI helper: count VRF routes from BGP side
4797 * pALRcount count of active local routes
4798 * pARRcount count of active remote routes
4799 * pHRcount count of holddown routes
4800 * pIRcount count of direct imported routes
4804 --------------------------------------------*/
4805 void rfapiCountAllItRoutes(int *pALRcount
, /* active local routes */
4806 int *pARRcount
, /* active remote routes */
4807 int *pHRcount
, /* holddown routes */
4808 int *pIRcount
) /* imported routes */
4812 struct rfapi_import_table
*it
;
4815 int total_active_local
= 0;
4816 int total_active_remote
= 0;
4817 int total_holddown
= 0;
4818 int total_imported
= 0;
4820 bgp
= bgp_get_default(); /* assume 1 instance for now */
4827 * Iterate over all import tables; do a filtered import
4828 * for the afi/safi combination
4831 for (it
= h
->imports
; it
; it
= it
->next
) {
4833 for (afi
= AFI_IP
; afi
< AFI_MAX
; ++afi
) {
4835 total_active_local
+= it
->local_count
[afi
];
4836 total_active_remote
+= it
->remote_count
[afi
];
4837 total_holddown
+= it
->holddown_count
[afi
];
4838 total_imported
+= it
->imported_count
[afi
];
4845 if (h
->import_mac
) {
4847 rc
= skiplist_next(h
->import_mac
, NULL
, (void **)&it
,
4849 !rc
; rc
= skiplist_next(h
->import_mac
, NULL
, (void **)&it
,
4852 total_active_local
+= it
->local_count
[AFI_L2VPN
];
4853 total_active_remote
+= it
->remote_count
[AFI_L2VPN
];
4854 total_holddown
+= it
->holddown_count
[AFI_L2VPN
];
4855 total_imported
+= it
->imported_count
[AFI_L2VPN
];
4861 *pALRcount
= total_active_local
;
4864 *pARRcount
= total_active_remote
;
4867 *pHRcount
= total_holddown
;
4870 *pIRcount
= total_imported
;
4874 /*------------------------------------------
4875 * rfapiGetHolddownFromLifetime
4877 * calculate holddown value based on lifetime
4883 * Holddown value based on lifetime, holddown_factor,
4884 * and RFAPI_LIFETIME_INFINITE_WITHDRAW_DELAY
4886 --------------------------------------------*/
4887 /* hold down time maxes out at RFAPI_LIFETIME_INFINITE_WITHDRAW_DELAY */
4888 uint32_t rfapiGetHolddownFromLifetime(uint32_t lifetime
)
4893 bgp
= bgp_get_default();
4894 if (bgp
&& bgp
->rfapi_cfg
)
4895 factor
= bgp
->rfapi_cfg
->rfp_cfg
.holddown_factor
;
4897 factor
= RFAPI_RFP_CFG_DEFAULT_HOLDDOWN_FACTOR
;
4899 if (factor
< 100 || lifetime
< RFAPI_LIFETIME_INFINITE_WITHDRAW_DELAY
)
4900 lifetime
= lifetime
* factor
/ 100;
4901 if (lifetime
< RFAPI_LIFETIME_INFINITE_WITHDRAW_DELAY
)
4904 return RFAPI_LIFETIME_INFINITE_WITHDRAW_DELAY
;