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
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 * File: rfapi_import.c
24 * Purpose: Handle import of routes from BGP to RFAPI
29 #include "lib/zebra.h"
30 #include "lib/prefix.h"
31 #include "lib/table.h"
33 #include "lib/memory.h"
35 #include "lib/skiplist.h"
36 #include "lib/thread.h"
38 #include "bgpd/bgpd.h"
39 #include "bgpd/bgp_ecommunity.h"
40 #include "bgpd/bgp_attr.h"
41 #include "bgpd/bgp_route.h"
42 #include "bgpd/bgp_mplsvpn.h" /* prefix_rd2str() */
43 #include "bgpd/bgp_vnc_types.h"
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
81 struct rfapi_import_table
*import_table
;
82 struct route_node
*node
;
83 struct bgp_info
*info
;
84 safi_t safi
; /* used only for bulk operations */
86 * For import table node reference count checking (i.e., debugging).
87 * Normally when a timer expires, lockoffset should be 0. However, if
88 * the timer expiration function is called directly (e.g.,
89 * rfapiExpireVpnNow), the node could be locked by a preceding
90 * route_top() or route_next() in a loop, so we need to pass this
98 * It's evil and fiendish. It's compiler-dependent.
99 * ? Might need LDFLAGS -rdynamic to produce all function names
102 rfapiDebugBacktrace (void)
104 #ifdef HAVE_GLIBC_BACKTRACE
105 #define RFAPI_DEBUG_BACKTRACE_NENTRIES 200
106 void *buf
[RFAPI_DEBUG_BACKTRACE_NENTRIES
];
111 size
= backtrace (buf
, RFAPI_DEBUG_BACKTRACE_NENTRIES
);
112 syms
= backtrace_symbols (buf
, size
);
114 for (i
= 0; i
< size
&& i
< RFAPI_DEBUG_BACKTRACE_NENTRIES
; ++i
)
116 vnc_zlog_debug_verbose ("backtrace[%2lu]: %s", i
, syms
[i
]);
126 * Count remote routes and compare with actively-maintained values.
127 * Abort if they disagree.
130 rfapiCheckRouteCount ()
132 struct bgp
*bgp
= bgp_get_default ();
134 struct rfapi_import_table
*it
;
142 for (it
= h
->imports
; it
; it
= it
->next
)
144 for (afi
= AFI_IP
; afi
< AFI_MAX
; ++afi
)
147 struct route_table
*rt
;
148 struct route_node
*rn
;
150 int holddown_count
= 0;
152 int imported_count
= 0;
153 int remote_count
= 0;
155 rt
= it
->imported_vpn
[afi
];
157 for (rn
= route_top (rt
); rn
; rn
= route_next (rn
))
160 struct bgp_info
*next
;
162 for (bi
= rn
->info
; bi
; bi
= next
)
166 if (CHECK_FLAG (bi
->flags
, BGP_INFO_REMOVED
))
173 if (RFAPI_LOCAL_BI (bi
))
179 if (RFAPI_DIRECT_IMPORT_BI (bi
))
192 if (it
->holddown_count
[afi
] != holddown_count
)
194 vnc_zlog_debug_verbose ("%s: it->holddown_count %d != holddown_count %d",
195 __func__
, it
->holddown_count
[afi
], holddown_count
);
198 if (it
->remote_count
[afi
] != remote_count
)
200 vnc_zlog_debug_verbose ("%s: it->remote_count %d != remote_count %d",
201 __func__
, it
->remote_count
[afi
], remote_count
);
204 if (it
->imported_count
[afi
] != imported_count
)
206 vnc_zlog_debug_verbose ("%s: it->imported_count %d != imported_count %d",
207 __func__
, it
->imported_count
[afi
], imported_count
);
214 #if DEBUG_ROUTE_COUNTERS
215 #define VNC_ITRCCK do {rfapiCheckRouteCount();} while (0)
221 * Validate reference count for a node in an import table
223 * Normally lockoffset is 0 for nodes in quiescent state. However,
224 * route_unlock_node will delete the node if it is called when
225 * node->lock == 1, and we have to validate the refcount before
226 * the node is deleted. In this case, we specify lockoffset 1.
229 rfapiCheckRefcount (struct route_node
*rn
, safi_t safi
, int lockoffset
)
231 unsigned int count_bi
= 0;
232 unsigned int count_monitor
= 0;
234 struct rfapi_monitor_encap
*hme
;
235 struct rfapi_monitor_vpn
*hmv
;
237 for (bi
= rn
->info
; bi
; bi
= bi
->next
)
243 ++count_monitor
; /* rfapi_it_extra */
251 for (hme
= RFAPI_MONITOR_ENCAP (rn
); hme
; hme
= hme
->next
)
257 for (hmv
= RFAPI_MONITOR_VPN (rn
); hmv
; hmv
= hmv
->next
)
260 if (RFAPI_MONITOR_EXTERIOR (rn
)->source
)
262 ++count_monitor
; /* sl */
264 for (rc
= skiplist_next (RFAPI_MONITOR_EXTERIOR (rn
)->source
,
265 NULL
, NULL
, &cursor
);
267 rc
= skiplist_next (RFAPI_MONITOR_EXTERIOR (rn
)->source
,
268 NULL
, NULL
, &cursor
))
271 ++count_monitor
; /* sl entry */
281 if (count_bi
+ count_monitor
+ lockoffset
!= rn
->lock
)
283 vnc_zlog_debug_verbose
284 ("%s: count_bi=%d, count_monitor=%d, lockoffset=%d, rn->lock=%d",
285 __func__
, count_bi
, count_monitor
, lockoffset
, rn
->lock
);
291 * Perform deferred rfapi_close operations that were queued
294 static wq_item_status
295 rfapi_deferred_close_workfunc (struct work_queue
*q
, void *data
)
297 struct rfapi_descriptor
*rfd
= data
;
298 struct rfapi
*h
= q
->spec
.data
;
300 assert (!(h
->flags
& RFAPI_INCALLBACK
));
302 vnc_zlog_debug_verbose ("%s: completed deferred close on handle %p", __func__
, rfd
);
307 * Extract layer 2 option from Encap TLVS in BGP attrs
310 rfapiGetL2o (struct attr
*attr
, struct rfapi_l2address_option
*l2o
)
312 if (attr
&& attr
->extra
)
315 struct bgp_attr_encap_subtlv
*pEncap
;
317 for (pEncap
= attr
->extra
->vnc_subtlvs
; pEncap
; pEncap
= pEncap
->next
)
320 if (pEncap
->type
== BGP_VNC_SUBTLV_TYPE_RFPOPTION
)
322 if (pEncap
->value
[0] == RFAPI_VN_OPTION_TYPE_L2ADDR
)
325 if (pEncap
->value
[1] == 14)
327 memcpy (l2o
->macaddr
.octet
, pEncap
->value
+ 2,
330 ((pEncap
->value
[10] >> 4) & 0x0f) +
331 ((pEncap
->value
[9] << 4) & 0xff0) +
332 ((pEncap
->value
[8] << 12) & 0xff000);
334 l2o
->local_nve_id
= pEncap
->value
[12];
336 l2o
->logical_net_id
=
337 (pEncap
->value
[15] & 0xff) +
338 ((pEncap
->value
[14] << 8) & 0xff00) +
339 ((pEncap
->value
[13] << 16) & 0xff0000);
352 * Extract the lifetime from the Tunnel Encap attribute of a route in
356 rfapiGetVncLifetime (struct attr
*attr
, uint32_t * lifetime
)
358 struct bgp_attr_encap_subtlv
*pEncap
;
360 *lifetime
= RFAPI_INFINITE_LIFETIME
; /* default to infinite */
362 if (attr
&& attr
->extra
)
365 for (pEncap
= attr
->extra
->vnc_subtlvs
; pEncap
; pEncap
= pEncap
->next
)
368 if (pEncap
->type
== BGP_VNC_SUBTLV_TYPE_LIFETIME
)
370 if (pEncap
->length
== 4)
372 memcpy (lifetime
, pEncap
->value
, 4);
373 *lifetime
= ntohl (*lifetime
);
384 * Extract the tunnel type from the extended community
387 rfapiGetTunnelType (struct attr
*attr
,
388 bgp_encap_types
*type
)
390 *type
= BGP_ENCAP_TYPE_MPLS
; /* default to MPLS */
391 if (attr
&& attr
->extra
&& attr
->extra
->ecommunity
)
393 struct ecommunity
*ecom
= attr
->extra
->ecommunity
;
396 for (i
= 0; i
< (ecom
->size
* ECOMMUNITY_SIZE
); i
+= ECOMMUNITY_SIZE
)
401 if (ep
[0] == ECOMMUNITY_ENCODE_OPAQUE
&&
402 ep
[1] == ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP
)
404 *type
= (ep
[6]<<8) + ep
[7];
415 * Look for UN address in Encap attribute
418 rfapiGetVncTunnelUnAddr (struct attr
*attr
, struct prefix
*p
)
420 struct bgp_attr_encap_subtlv
*pEncap
;
421 bgp_encap_types tun_type
;
423 rfapiGetTunnelType (attr
, &tun_type
);
424 if (p
&& tun_type
== BGP_ENCAP_TYPE_MPLS
)
426 return ENOENT
; /* no UN for MPLS */
428 if (attr
&& attr
->extra
)
430 for (pEncap
= attr
->extra
->encap_subtlvs
; pEncap
; pEncap
= pEncap
->next
)
433 if (pEncap
->type
== BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT
)
435 switch (pEncap
->length
)
442 memcpy (p
->u
.val
, pEncap
->value
, 4);
449 p
->family
= AF_INET6
;
451 memcpy (p
->u
.val
, pEncap
->value
, 16);
463 * Get UN address wherever it might be
466 rfapiGetUnAddrOfVpnBi (struct bgp_info
*bi
, struct prefix
*p
)
468 /* If it's in this route's VNC attribute, we're done */
469 if (!rfapiGetVncTunnelUnAddr (bi
->attr
, p
))
472 * Otherwise, see if it's cached from a corresponding ENCAP SAFI
477 switch (bi
->extra
->vnc
.import
.un_family
)
482 p
->family
= bi
->extra
->vnc
.import
.un_family
;
483 p
->u
.prefix4
= bi
->extra
->vnc
.import
.un
.addr4
;
490 p
->family
= bi
->extra
->vnc
.import
.un_family
;
491 p
->u
.prefix6
= bi
->extra
->vnc
.import
.un
.addr6
;
498 #if DEBUG_ENCAP_MONITOR
499 vnc_zlog_debug_verbose ("%s: bi->extra->vnc.import.un_family is 0, no UN addr",
511 * Make a new bgp_info from gathered parameters
513 static struct bgp_info
*
518 struct prefix_rd
*prd
,
523 struct bgp_info
*new;
525 new = bgp_info_new ();
531 new->attr
= bgp_attr_intern (attr
);
533 bgp_info_extra_get (new);
536 new->extra
->vnc
.import
.rd
= *prd
;
537 rfapi_time (&new->extra
->vnc
.import
.create_time
);
540 encode_label (*label
, new->extra
->tag
);
542 new->sub_type
= sub_type
;
550 * Frees bgp_info as used in import tables (parts are not
551 * allocated exactly the way they are in the main RIBs)
554 rfapiBgpInfoFree (struct bgp_info
*goner
)
561 vnc_zlog_debug_verbose ("%s: calling peer_unlock(%p), #%d",
562 __func__
, goner
->peer
, goner
->peer
->lock
);
563 peer_unlock (goner
->peer
);
568 bgp_attr_unintern (&goner
->attr
);
572 assert (!goner
->extra
->damp_info
); /* Not used in import tbls */
573 XFREE (MTYPE_BGP_ROUTE_EXTRA
, goner
->extra
);
576 XFREE (MTYPE_BGP_ROUTE
, goner
);
579 struct rfapi_import_table
*
580 rfapiMacImportTableGetNoAlloc (struct bgp
*bgp
, uint32_t lni
)
583 struct rfapi_import_table
*it
= NULL
;
584 uintptr_t lni_as_ptr
= lni
;
593 if (skiplist_search (h
->import_mac
, (void *) lni_as_ptr
, (void **) &it
))
599 struct rfapi_import_table
*
600 rfapiMacImportTableGet (struct bgp
*bgp
, uint32_t lni
)
603 struct rfapi_import_table
*it
= NULL
;
604 uintptr_t lni_as_ptr
= lni
;
611 /* default cmp is good enough for LNI */
612 h
->import_mac
= skiplist_new (0, NULL
, NULL
);
615 if (skiplist_search (h
->import_mac
, (void *) lni_as_ptr
, (void **) &it
))
618 struct ecommunity
*enew
;
619 struct ecommunity_val eval
;
623 XCALLOC (MTYPE_RFAPI_IMPORTTABLE
, sizeof (struct rfapi_import_table
));
624 /* set RT list of new import table based on LNI */
625 memset ((char *) &eval
, 0, sizeof (eval
));
626 eval
.val
[0] = 0; /* VNC L2VPN */
627 eval
.val
[1] = 2; /* VNC L2VPN */
628 eval
.val
[5] = (lni
>> 16) & 0xff;
629 eval
.val
[6] = (lni
>> 8) & 0xff;
630 eval
.val
[7] = (lni
>> 0) & 0xff;
632 enew
= ecommunity_new ();
633 ecommunity_add_val (enew
, &eval
);
634 it
->rt_import_list
= enew
;
636 for (afi
= AFI_IP
; afi
< AFI_MAX
; ++afi
)
638 it
->imported_vpn
[afi
] = route_table_init ();
639 it
->imported_encap
[afi
] = route_table_init ();
642 it
->l2_logical_net_id
= lni
;
644 skiplist_insert (h
->import_mac
, (void *) lni_as_ptr
, it
);
652 * Implement MONITOR_MOVE_SHORTER(original_node) from
653 * RFAPI-Import-Event-Handling.txt
655 * Returns pointer to the list of moved monitors
657 static struct rfapi_monitor_vpn
*
658 rfapiMonitorMoveShorter (struct route_node
*original_vpn_node
, int lockoffset
)
661 struct route_node
*par
;
662 struct rfapi_monitor_vpn
*m
;
663 struct rfapi_monitor_vpn
*mlast
;
664 struct rfapi_monitor_vpn
*moved
;
666 int parent_already_refcounted
= 0;
668 RFAPI_CHECK_REFCOUNT (original_vpn_node
, SAFI_MPLS_VPN
, lockoffset
);
670 #if DEBUG_MONITOR_MOVE_SHORTER
674 prefix2str (&original_vpn_node
->p
, buf
, BUFSIZ
);
676 vnc_zlog_debug_verbose ("%s: called with node pfx=%s", __func__
, buf
);
681 * 1. If there is at least one bi (either regular route or
682 * route marked as withdrawn, with a pending timer) at
683 * original_node with a valid UN address, we're done. Return.
685 for (bi
= original_vpn_node
->info
; bi
; bi
= bi
->next
)
689 if (!rfapiGetUnAddrOfVpnBi (bi
, &pfx
))
691 #if DEBUG_MONITOR_MOVE_SHORTER
692 vnc_zlog_debug_verbose ("%s: have valid UN at original node, no change",
700 * 2. Travel up the tree (toward less-specific prefixes) from
701 * original_node to find the first node that has at least
702 * one route (even if it is only a withdrawn route) with a
703 * valid UN address. Call this node "Node P."
705 for (par
= original_vpn_node
->parent
; par
; par
= par
->parent
)
707 for (bi
= par
->info
; bi
; bi
= bi
->next
)
710 if (!rfapiGetUnAddrOfVpnBi (bi
, &pfx
))
721 RFAPI_CHECK_REFCOUNT (par
, SAFI_MPLS_VPN
, 0);
725 * If no less-specific routes, try to use the 0/0 node
729 /* this isn't necessarily 0/0 */
730 par
= route_top (original_vpn_node
->table
);
733 * If we got the top node but it wasn't 0/0,
736 if (par
&& par
->p
.prefixlen
)
738 route_unlock_node (par
); /* maybe free */
744 ++parent_already_refcounted
;
749 * Create 0/0 node if it isn't there
753 struct prefix pfx_default
;
755 memset (&pfx_default
, 0, sizeof (pfx_default
));
756 pfx_default
.family
= original_vpn_node
->p
.family
;
758 /* creates default node if none exists */
759 par
= route_node_get (original_vpn_node
->table
, &pfx_default
);
760 ++parent_already_refcounted
;
764 * 3. Move each of the monitors found at original_node to Node P.
765 * These are "Moved Monitors."
770 * Attach at end so that the list pointer we return points
771 * only to the moved routes
773 for (m
= RFAPI_MONITOR_VPN (par
), mlast
= NULL
; m
; mlast
= m
, m
= m
->next
);
777 moved
= mlast
->next
= RFAPI_MONITOR_VPN (original_vpn_node
);
781 moved
= RFAPI_MONITOR_VPN_W_ALLOC (par
) =
782 RFAPI_MONITOR_VPN (original_vpn_node
);
784 if (RFAPI_MONITOR_VPN (original_vpn_node
)) /* check agg, so not allocated */
785 RFAPI_MONITOR_VPN_W_ALLOC (original_vpn_node
) = NULL
;
788 * update the node pointers on the monitors
790 for (m
= moved
; m
; m
= m
->next
)
796 RFAPI_CHECK_REFCOUNT (par
, SAFI_MPLS_VPN
,
797 parent_already_refcounted
- movecount
);
798 while (movecount
> parent_already_refcounted
)
800 route_lock_node (par
);
801 ++parent_already_refcounted
;
803 while (movecount
< parent_already_refcounted
)
805 /* unlikely, but code defensively */
806 route_unlock_node (par
);
807 --parent_already_refcounted
;
809 RFAPI_CHECK_REFCOUNT (original_vpn_node
, SAFI_MPLS_VPN
,
810 movecount
+ lockoffset
);
813 route_unlock_node (original_vpn_node
);
816 #if DEBUG_MONITOR_MOVE_SHORTER
820 prefix2str (&par
->p
, buf
, BUFSIZ
);
822 vnc_zlog_debug_verbose ("%s: moved to node pfx=%s", __func__
, buf
);
831 * Implement MONITOR_MOVE_LONGER(new_node) from
832 * RFAPI-Import-Event-Handling.txt
835 rfapiMonitorMoveLonger (struct route_node
*new_vpn_node
)
837 struct rfapi_monitor_vpn
*monitor
;
838 struct rfapi_monitor_vpn
*mlast
;
840 struct route_node
*par
;
842 RFAPI_CHECK_REFCOUNT (new_vpn_node
, SAFI_MPLS_VPN
, 0);
845 * Make sure we have at least one valid route at the new node
847 for (bi
= new_vpn_node
->info
; bi
; bi
= bi
->next
)
850 if (!rfapiGetUnAddrOfVpnBi (bi
, &pfx
))
856 vnc_zlog_debug_verbose ("%s: no valid routes at node %p, so not attempting moves",
857 __func__
, new_vpn_node
);
862 * Find first parent node that has monitors
864 for (par
= new_vpn_node
->parent
; par
; par
= par
->parent
)
866 if (RFAPI_MONITOR_VPN (par
))
872 vnc_zlog_debug_verbose ("%s: no parent nodes with monitors, done", __func__
);
877 * Check each of these monitors to see of their longest-match
878 * is now the updated node. Move any such monitors to the more-
879 * specific updated node
881 for (mlast
= NULL
, monitor
= RFAPI_MONITOR_VPN (par
); monitor
;)
885 * If new longest match for monitor prefix is the new
886 * route's prefix, move monitor to new route's prefix
888 if (prefix_match (&new_vpn_node
->p
, &monitor
->p
))
893 mlast
->next
= monitor
->next
;
897 RFAPI_MONITOR_VPN_W_ALLOC (par
) = monitor
->next
;
902 monitor
->next
= RFAPI_MONITOR_VPN (new_vpn_node
);
903 RFAPI_MONITOR_VPN_W_ALLOC (new_vpn_node
) = monitor
;
904 monitor
->node
= new_vpn_node
;
906 route_lock_node (new_vpn_node
); /* incr refcount */
908 monitor
= mlast
? mlast
->next
: RFAPI_MONITOR_VPN (par
);
910 RFAPI_CHECK_REFCOUNT (par
, SAFI_MPLS_VPN
, 1);
911 /* decr refcount after we're done with par as this might free it */
912 route_unlock_node (par
);
917 monitor
= monitor
->next
;
920 RFAPI_CHECK_REFCOUNT (new_vpn_node
, SAFI_MPLS_VPN
, 0);
925 rfapiBgpInfoChainFree (struct bgp_info
*bi
)
927 struct bgp_info
*next
;
933 * If there is a timer waiting to delete this bi, cancel
934 * the timer and delete immediately
936 if (CHECK_FLAG (bi
->flags
, BGP_INFO_REMOVED
) &&
937 bi
->extra
->vnc
.import
.timer
)
940 struct thread
*t
= (struct thread
*) bi
->extra
->vnc
.import
.timer
;
941 struct rfapi_withdraw
*wcb
= t
->arg
;
943 XFREE (MTYPE_RFAPI_WITHDRAW
, wcb
);
949 rfapiBgpInfoFree (bi
);
955 rfapiImportTableFlush (struct rfapi_import_table
*it
)
962 ecommunity_free (&it
->rt_import_list
);
963 it
->rt_import_list
= NULL
;
965 for (afi
= AFI_IP
; afi
< AFI_MAX
; ++afi
)
968 struct route_node
*rn
;
970 for (rn
= route_top (it
->imported_vpn
[afi
]); rn
; rn
= route_next (rn
))
973 * Each route_node has:
974 * aggregate: points to rfapi_it_extra with monitor chain(s)
975 * info: points to chain of bgp_info
977 /* free bgp_info and its children */
978 rfapiBgpInfoChainFree (rn
->info
);
981 rfapiMonitorExtraFlush (SAFI_MPLS_VPN
, rn
);
984 for (rn
= route_top (it
->imported_encap
[afi
]); rn
; rn
= route_next (rn
))
986 /* free bgp_info and its children */
987 rfapiBgpInfoChainFree (rn
->info
);
990 rfapiMonitorExtraFlush (SAFI_ENCAP
, rn
);
993 route_table_finish (it
->imported_vpn
[afi
]);
994 route_table_finish (it
->imported_encap
[afi
]);
996 if (it
->monitor_exterior_orphans
)
998 skiplist_free (it
->monitor_exterior_orphans
);
1003 rfapiImportTableRefDelByIt (
1005 struct rfapi_import_table
*it_target
)
1008 struct rfapi_import_table
*it
;
1009 struct rfapi_import_table
*prev
= NULL
;
1016 for (it
= h
->imports
; it
; prev
= it
, it
= it
->next
)
1018 if (it
== it_target
)
1023 assert (it
->refcount
);
1031 prev
->next
= it
->next
;
1035 h
->imports
= it
->next
;
1037 rfapiImportTableFlush (it
);
1038 XFREE (MTYPE_RFAPI_IMPORTTABLE
, it
);
1042 #if RFAPI_REQUIRE_ENCAP_BEEC
1044 * Look for magic BGP Encapsulation Extended Community value
1045 * Format in RFC 5512 Sect. 4.5
1048 rfapiEcommunitiesMatchBeec (struct ecommunity
*ecom
,
1049 bgp_encap_types type
)
1056 for (i
= 0; i
< (ecom
->size
* ECOMMUNITY_SIZE
); i
+= ECOMMUNITY_SIZE
)
1063 if (ep
[0] == ECOMMUNITY_ENCODE_OPAQUE
&&
1064 ep
[1] == ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP
&&
1065 ep
[6] == ((type
&& 0xff00)>>8) &&
1066 ep
[7] == (type
&0xff))
1078 rfapiEcommunitiesIntersect (struct ecommunity
*e1
, struct ecommunity
*e2
)
1087 s1
= ecommunity_ecom2str (e1
, ECOMMUNITY_FORMAT_DISPLAY
);
1088 s2
= ecommunity_ecom2str (e2
, ECOMMUNITY_FORMAT_DISPLAY
);
1089 vnc_zlog_debug_verbose ("%s: e1[%s], e2[%s]", __func__
, s1
, s2
);
1090 XFREE (MTYPE_ECOMMUNITY_STR
, s1
);
1091 XFREE (MTYPE_ECOMMUNITY_STR
, s2
);
1094 for (i
= 0; i
< e1
->size
; ++i
)
1096 for (j
= 0; j
< e2
->size
; ++j
)
1098 if (!memcmp (e1
->val
+ (i
* ECOMMUNITY_SIZE
),
1099 e2
->val
+ (j
* ECOMMUNITY_SIZE
), ECOMMUNITY_SIZE
))
1110 rfapiEcommunityGetLNI (struct ecommunity
*ecom
, uint32_t * lni
)
1115 for (i
= 0; i
< ecom
->size
; ++i
)
1117 uint8_t *p
= ecom
->val
+ (i
* ECOMMUNITY_SIZE
);
1119 if ((*(p
+ 0) == 0x00) && (*(p
+ 1) == 0x02))
1122 *lni
= (*(p
+ 5) << 16) | (*(p
+ 6) << 8) | (*(p
+ 7));
1131 rfapiEcommunityGetEthernetTag (struct ecommunity
*ecom
, uint16_t * tag_id
)
1133 struct bgp
*bgp
= bgp_get_default ();
1134 *tag_id
= 0; /* default to untagged */
1138 for (i
= 0; i
< ecom
->size
; ++i
)
1142 uint8_t *p
= ecom
->val
+ (i
* ECOMMUNITY_SIZE
);
1144 /* High-order octet of type. */
1147 if (*p
++ == ECOMMUNITY_ROUTE_TARGET
) {
1148 if (encode
== ECOMMUNITY_ENCODE_AS4
)
1155 else if (encode
== ECOMMUNITY_ENCODE_AS
)
1159 p
+= 2; /* skip next two, tag/vid always in lowest bytes */
1163 *tag_id
= *p
++ << 8;
1174 rfapiVpnBiNhEqualsPt (struct bgp_info
*bi
, struct rfapi_ip_addr
*hpt
)
1181 family
= BGP_MP_NEXTHOP_FAMILY (bi
->attr
->extra
->mp_nexthop_len
);
1183 if (hpt
->addr_family
!= family
)
1189 if (bi
->attr
->extra
->mp_nexthop_global_in
.s_addr
!= hpt
->addr
.v4
.s_addr
)
1194 if (IPV6_ADDR_CMP (&bi
->attr
->extra
->mp_nexthop_global
, &hpt
->addr
.v6
))
1208 * Compare 2 VPN BIs. Return true if they have the same VN and UN addresses
1211 rfapiVpnBiSamePtUn (struct bgp_info
*bi1
, struct bgp_info
*bi2
)
1213 struct prefix pfx_un1
;
1214 struct prefix pfx_un2
;
1219 if (!bi1
->attr
|| !bi2
->attr
)
1222 if (!bi1
->attr
->extra
|| !bi2
->attr
->extra
)
1226 * VN address comparisons
1229 if (BGP_MP_NEXTHOP_FAMILY (bi1
->attr
->extra
->mp_nexthop_len
) !=
1230 BGP_MP_NEXTHOP_FAMILY (bi2
->attr
->extra
->mp_nexthop_len
))
1235 switch (BGP_MP_NEXTHOP_FAMILY (bi1
->attr
->extra
->mp_nexthop_len
))
1239 if (bi1
->attr
->extra
->mp_nexthop_global_in
.s_addr
!=
1240 bi2
->attr
->extra
->mp_nexthop_global_in
.s_addr
)
1245 if (IPV6_ADDR_CMP (&bi1
->attr
->extra
->mp_nexthop_global
,
1246 &bi2
->attr
->extra
->mp_nexthop_global
))
1256 * UN address comparisons
1258 if (rfapiGetVncTunnelUnAddr (bi1
->attr
, &pfx_un1
))
1262 pfx_un1
.family
= bi1
->extra
->vnc
.import
.un_family
;
1263 switch (bi1
->extra
->vnc
.import
.un_family
)
1266 pfx_un1
.u
.prefix4
= bi1
->extra
->vnc
.import
.un
.addr4
;
1269 pfx_un1
.u
.prefix6
= bi1
->extra
->vnc
.import
.un
.addr6
;
1278 if (rfapiGetVncTunnelUnAddr (bi2
->attr
, &pfx_un2
))
1282 pfx_un2
.family
= bi2
->extra
->vnc
.import
.un_family
;
1283 switch (bi2
->extra
->vnc
.import
.un_family
)
1286 pfx_un2
.u
.prefix4
= bi2
->extra
->vnc
.import
.un
.addr4
;
1289 pfx_un2
.u
.prefix6
= bi2
->extra
->vnc
.import
.un
.addr6
;
1298 if (!pfx_un1
.family
|| !pfx_un2
.family
)
1301 if (pfx_un1
.family
!= pfx_un2
.family
)
1304 switch (pfx_un1
.family
)
1308 (&pfx_un1
.u
.prefix4
.s_addr
, &pfx_un2
.u
.prefix4
.s_addr
))
1312 if (!IPV6_ADDR_SAME (&pfx_un1
.u
.prefix6
, &pfx_un2
.u
.prefix6
))
1323 rfapiRfpCost (struct attr
* attr
)
1325 if (attr
->flag
& ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF
))
1327 if (attr
->local_pref
> 255)
1331 return 255 - attr
->local_pref
;
1337 /*------------------------------------------
1340 * Find Layer 2 options in an option chain
1346 * l2o layer 2 options extracted
1350 * 1 no options found
1352 --------------------------------------------*/
1354 rfapi_extract_l2o (struct bgp_tea_options
*pHop
, /* chain of options */
1355 struct rfapi_l2address_option
*l2o
) /* return extracted value */
1357 struct bgp_tea_options
*p
;
1359 for (p
= pHop
; p
; p
= p
->next
)
1361 if ((p
->type
== RFAPI_VN_OPTION_TYPE_L2ADDR
) && (p
->length
>= 8))
1366 memcpy (&l2o
->macaddr
, v
, 6);
1369 ((v
[6] << 12) & 0xff000) +
1370 ((v
[7] << 4) & 0xff0) + ((v
[8] >> 4) & 0xf);
1372 l2o
->local_nve_id
= (uint8_t) v
[10];
1374 l2o
->logical_net_id
= (v
[11] << 16) + (v
[12] << 8) + (v
[13] << 0);
1382 static struct rfapi_next_hop_entry
*
1383 rfapiRouteInfo2NextHopEntry (
1384 struct rfapi_ip_prefix
*rprefix
,
1385 struct bgp_info
*bi
, /* route to encode */
1386 uint32_t lifetime
, /* use this in nhe */
1387 struct route_node
*rn
) /* req for L2 eth addr */
1389 struct rfapi_next_hop_entry
*new;
1390 int have_vnc_tunnel_un
= 0;
1392 #if DEBUG_ENCAP_MONITOR
1393 vnc_zlog_debug_verbose ("%s: entry, bi %p, rn %p", __func__
, bi
, rn
);
1396 new = XCALLOC (MTYPE_RFAPI_NEXTHOP
, sizeof (struct rfapi_next_hop_entry
));
1399 new->prefix
= *rprefix
;
1402 decode_rd_type(bi
->extra
->vnc
.import
.rd
.val
) == RD_TYPE_VNC_ETH
)
1406 struct rfapi_vn_option
*vo
;
1408 vo
= XCALLOC (MTYPE_RFAPI_VN_OPTION
, sizeof (struct rfapi_vn_option
));
1411 vo
->type
= RFAPI_VN_OPTION_TYPE_L2ADDR
;
1413 memcpy (&vo
->v
.l2addr
.macaddr
, &rn
->p
.u
.prefix_eth
.octet
,
1415 /* only low 3 bytes of this are significant */
1416 if (bi
->attr
&& bi
->attr
->extra
)
1418 (void) rfapiEcommunityGetLNI (bi
->attr
->extra
->ecommunity
,
1419 &vo
->v
.l2addr
.logical_net_id
);
1420 (void) rfapiEcommunityGetEthernetTag (bi
->attr
->extra
->ecommunity
,
1421 &vo
->v
.l2addr
.tag_id
);
1424 /* local_nve_id comes from lower byte of RD type */
1425 vo
->v
.l2addr
.local_nve_id
= bi
->extra
->vnc
.import
.rd
.val
[1];
1427 /* label comes from MP_REACH_NLRI label */
1428 vo
->v
.l2addr
.label
= decode_label (bi
->extra
->tag
);
1430 new->vn_options
= vo
;
1433 * If there is an auxiliary prefix (i.e., host IP address),
1434 * use it as the nexthop prefix instead of the query prefix
1436 if (bi
->extra
->vnc
.import
.aux_prefix
.family
)
1438 rfapiQprefix2Rprefix (&bi
->extra
->vnc
.import
.aux_prefix
,
1445 bgp_encap_types tun_type
;
1446 new->prefix
.cost
= rfapiRfpCost (bi
->attr
);
1448 if (bi
->attr
->extra
)
1451 struct bgp_attr_encap_subtlv
*pEncap
;
1453 switch (BGP_MP_NEXTHOP_FAMILY (bi
->attr
->extra
->mp_nexthop_len
))
1456 new->vn_address
.addr_family
= AF_INET
;
1457 new->vn_address
.addr
.v4
= bi
->attr
->extra
->mp_nexthop_global_in
;
1461 new->vn_address
.addr_family
= AF_INET6
;
1462 new->vn_address
.addr
.v6
= bi
->attr
->extra
->mp_nexthop_global
;
1466 zlog_warn ("%s: invalid vpn nexthop length: %d",
1467 __func__
, bi
->attr
->extra
->mp_nexthop_len
);
1468 rfapi_free_next_hop_list (new);
1472 for (pEncap
= bi
->attr
->extra
->vnc_subtlvs
; pEncap
;
1473 pEncap
= pEncap
->next
)
1475 switch (pEncap
->type
)
1477 case BGP_VNC_SUBTLV_TYPE_LIFETIME
:
1478 /* use configured lifetime, not attr lifetime */
1482 zlog_warn ("%s: unknown VNC option type %d",
1483 __func__
, pEncap
->type
);
1490 rfapiGetTunnelType (bi
->attr
, &tun_type
);
1491 if (tun_type
== BGP_ENCAP_TYPE_MPLS
)
1494 /* MPLS carries UN address in next hop */
1495 rfapiNexthop2Prefix (bi
->attr
, &p
);
1498 rfapiQprefix2Raddr(&p
, &new->un_address
);
1499 have_vnc_tunnel_un
= 1;
1503 for (pEncap
= bi
->attr
->extra
->encap_subtlvs
; pEncap
;
1504 pEncap
= pEncap
->next
)
1506 switch (pEncap
->type
)
1508 case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT
:
1510 * Overrides ENCAP UN address, if any
1512 switch (pEncap
->length
)
1516 new->un_address
.addr_family
= AF_INET
;
1517 memcpy (&new->un_address
.addr
.v4
, pEncap
->value
, 4);
1518 have_vnc_tunnel_un
= 1;
1522 new->un_address
.addr_family
= AF_INET6
;
1523 memcpy (&new->un_address
.addr
.v6
, pEncap
->value
, 16);
1524 have_vnc_tunnel_un
= 1;
1529 ("%s: invalid tunnel subtlv UN addr length (%d) for bi %p",
1530 __func__
, pEncap
->length
, bi
);
1535 zlog_warn ("%s: unknown Encap Attribute option type %d",
1536 __func__
, pEncap
->type
);
1543 new->un_options
= rfapi_encap_tlv_to_un_option (bi
->attr
);
1545 #if DEBUG_ENCAP_MONITOR
1546 vnc_zlog_debug_verbose ("%s: line %d: have_vnc_tunnel_un=%d",
1547 __func__
, __LINE__
, have_vnc_tunnel_un
);
1550 if (!have_vnc_tunnel_un
&& bi
&& bi
->extra
)
1553 * use cached UN address from ENCAP route
1555 new->un_address
.addr_family
= bi
->extra
->vnc
.import
.un_family
;
1556 switch (new->un_address
.addr_family
)
1559 new->un_address
.addr
.v4
= bi
->extra
->vnc
.import
.un
.addr4
;
1562 new->un_address
.addr
.v6
= bi
->extra
->vnc
.import
.un
.addr6
;
1565 zlog_warn ("%s: invalid UN addr family (%d) for bi %p",
1566 __func__
, new->un_address
.addr_family
, bi
);
1567 rfapi_free_next_hop_list (new);
1574 new->lifetime
= lifetime
;
1579 rfapiHasNonRemovedRoutes (struct route_node
*rn
)
1581 struct bgp_info
*bi
;
1583 for (bi
= rn
->info
; bi
; bi
= bi
->next
)
1587 if (!CHECK_FLAG (bi
->flags
, BGP_INFO_REMOVED
) &&
1588 (bi
->extra
&& !rfapiGetUnAddrOfVpnBi (bi
, &pfx
)))
1602 rfapiDumpNode (struct route_node
*rn
)
1604 struct bgp_info
*bi
;
1606 vnc_zlog_debug_verbose ("%s: rn=%p", __func__
, rn
);
1607 for (bi
= rn
->info
; bi
; bi
= bi
->next
)
1610 int ctrc
= rfapiGetUnAddrOfVpnBi (bi
, &pfx
);
1613 if (!CHECK_FLAG (bi
->flags
, BGP_INFO_REMOVED
) && (bi
->extra
&& !ctrc
))
1623 vnc_zlog_debug_verbose (" bi=%p, nr=%d, flags=0x%x, extra=%p, ctrc=%d",
1624 bi
, nr
, bi
->flags
, bi
->extra
, ctrc
);
1630 rfapiNhlAddNodeRoutes (
1631 struct route_node
*rn
, /* in */
1632 struct rfapi_ip_prefix
*rprefix
, /* in */
1633 uint32_t lifetime
, /* in */
1634 int removed
, /* in */
1635 struct rfapi_next_hop_entry
**head
, /* in/out */
1636 struct rfapi_next_hop_entry
**tail
, /* in/out */
1637 struct rfapi_ip_addr
*exclude_vnaddr
, /* omit routes to same NVE */
1638 struct route_node
*rfd_rib_node
,/* preload this NVE rib node */
1639 struct prefix
*pfx_target_original
) /* query target */
1641 struct bgp_info
*bi
;
1642 struct rfapi_next_hop_entry
*new;
1643 struct prefix pfx_un
;
1644 struct skiplist
*seen_nexthops
;
1646 int is_l2
= (rn
->p
.family
== AF_ETHERNET
);
1648 if (rfapiRibFTDFilterRecentPrefix(
1649 (struct rfapi_descriptor
*)(rfd_rib_node
->table
->info
), rn
,
1650 pfx_target_original
))
1656 skiplist_new (0, vnc_prefix_cmp
, (void (*)(void *)) prefix_free
);
1658 for (bi
= rn
->info
; bi
; bi
= bi
->next
)
1661 struct prefix pfx_vn
;
1662 struct prefix
*newpfx
;
1664 if (removed
&& !CHECK_FLAG (bi
->flags
, BGP_INFO_REMOVED
))
1666 #if DEBUG_RETURNED_NHL
1667 vnc_zlog_debug_verbose ("%s: want holddown, this route not holddown, skip",
1672 if (!removed
&& CHECK_FLAG (bi
->flags
, BGP_INFO_REMOVED
))
1683 * Check for excluded VN address
1685 if (rfapiVpnBiNhEqualsPt (bi
, exclude_vnaddr
))
1689 * Check for VN address (nexthop) copied already
1693 /* L2 routes: semantic nexthop in aux_prefix; VN addr ain't it */
1694 pfx_vn
= bi
->extra
->vnc
.import
.aux_prefix
;
1698 rfapiNexthop2Prefix (bi
->attr
, &pfx_vn
);
1700 if (!skiplist_search (seen_nexthops
, &pfx_vn
, NULL
))
1702 #if DEBUG_RETURNED_NHL
1705 prefix2str (&pfx_vn
, buf
, BUFSIZ
);
1706 buf
[BUFSIZ
- 1] = 0; /* guarantee NUL-terminated */
1707 vnc_zlog_debug_verbose ("%s: already put VN/nexthop %s, skip", __func__
, buf
);
1712 if (rfapiGetUnAddrOfVpnBi (bi
, &pfx_un
))
1714 #if DEBUG_ENCAP_MONITOR
1715 vnc_zlog_debug_verbose ("%s: failed to get UN address of this VPN bi",
1721 newpfx
= prefix_new ();
1723 skiplist_insert (seen_nexthops
, newpfx
, newpfx
);
1725 new = rfapiRouteInfo2NextHopEntry(rprefix
, bi
, lifetime
, rn
);
1728 if (rfapiRibPreloadBi(rfd_rib_node
, &pfx_vn
, &pfx_un
, lifetime
, bi
))
1730 /* duplicate filtered by RIB */
1731 rfapi_free_next_hop_list (new);
1740 (*tail
)->next
= new;
1751 skiplist_free (seen_nexthops
);
1760 * omit_node is meant for the situation where we are adding a subtree
1761 * of a parent of some original requested node. The response already
1762 * contains the original requested node, and we don't want to duplicate
1763 * its routes in the list, so we skip it if the right or left node
1764 * matches (of course, we still travel down its child subtrees).
1767 rfapiNhlAddSubtree (
1768 struct route_node
*rn
, /* in */
1769 uint32_t lifetime
, /* in */
1770 struct rfapi_next_hop_entry
**head
, /* in/out */
1771 struct rfapi_next_hop_entry
**tail
, /* in/out */
1772 struct route_node
*omit_node
, /* in */
1773 struct rfapi_ip_addr
*exclude_vnaddr
,/* omit routes to same NVE */
1774 struct route_table
*rfd_rib_table
,/* preload here */
1775 struct prefix
*pfx_target_original
) /* query target */
1777 struct rfapi_ip_prefix rprefix
;
1780 if (rn
->l_left
&& rn
->l_left
!= omit_node
)
1782 if (rn
->l_left
->info
)
1785 struct route_node
*rib_rn
= NULL
;
1787 rfapiQprefix2Rprefix (&rn
->l_left
->p
, &rprefix
);
1790 rib_rn
= route_node_get(rfd_rib_table
, &rn
->l_left
->p
);
1793 count
= rfapiNhlAddNodeRoutes (rn
->l_left
, &rprefix
, lifetime
, 0,
1794 head
, tail
, exclude_vnaddr
, rib_rn
, pfx_target_original
);
1797 count
= rfapiNhlAddNodeRoutes (rn
->l_left
, &rprefix
, lifetime
, 1,
1798 head
, tail
, exclude_vnaddr
, rib_rn
, pfx_target_original
);
1802 route_unlock_node(rib_rn
);
1806 if (rn
->l_right
&& rn
->l_right
!= omit_node
)
1808 if (rn
->l_right
->info
)
1811 struct route_node
*rib_rn
= NULL
;
1813 rfapiQprefix2Rprefix (&rn
->l_right
->p
, &rprefix
);
1816 rib_rn
= route_node_get(rfd_rib_table
, &rn
->l_right
->p
);
1818 count
= rfapiNhlAddNodeRoutes (rn
->l_right
, &rprefix
, lifetime
, 0,
1819 head
, tail
, exclude_vnaddr
, rib_rn
, pfx_target_original
);
1822 count
= rfapiNhlAddNodeRoutes (rn
->l_right
, &rprefix
, lifetime
, 1,
1823 head
, tail
, exclude_vnaddr
, rib_rn
, pfx_target_original
);
1827 route_unlock_node(rib_rn
);
1833 rcount
+= rfapiNhlAddSubtree (rn
->l_left
, lifetime
, head
, tail
, omit_node
,
1834 exclude_vnaddr
, rfd_rib_table
, pfx_target_original
);
1838 rcount
+= rfapiNhlAddSubtree (rn
->l_right
, lifetime
, head
, tail
,
1839 omit_node
, exclude_vnaddr
, rfd_rib_table
, pfx_target_original
);
1846 * Implementation of ROUTE_LIST(node) from RFAPI-Import-Event-Handling.txt
1848 * Construct an rfapi nexthop list based on the routes attached to
1849 * the specified node.
1851 * If there are any routes that do NOT have BGP_INFO_REMOVED set,
1852 * return those only. If there are ONLY routes with BGP_INFO_REMOVED,
1853 * then return those, and also include all the non-removed routes from the
1854 * next less-specific node (i.e., this node's parent) at the end.
1856 struct rfapi_next_hop_entry
*
1857 rfapiRouteNode2NextHopList (
1858 struct route_node
*rn
,
1859 uint32_t lifetime
, /* put into nexthop entries */
1860 struct rfapi_ip_addr
*exclude_vnaddr
,/* omit routes to same NVE */
1861 struct route_table
*rfd_rib_table
,/* preload here */
1862 struct prefix
*pfx_target_original
) /* query target */
1864 struct rfapi_ip_prefix rprefix
;
1865 struct rfapi_next_hop_entry
*answer
= NULL
;
1866 struct rfapi_next_hop_entry
*last
= NULL
;
1867 struct route_node
*parent
;
1869 struct route_node
*rib_rn
;
1871 #if DEBUG_RETURNED_NHL
1875 prefix2str (&rn
->p
, buf
, BUFSIZ
);
1876 buf
[BUFSIZ
- 1] = 0;
1877 vnc_zlog_debug_verbose ("%s: called with node pfx=%s", __func__
, buf
);
1879 rfapiDebugBacktrace ();
1882 rfapiQprefix2Rprefix (&rn
->p
, &rprefix
);
1884 rib_rn
= rfd_rib_table
? route_node_get(rfd_rib_table
, &rn
->p
): NULL
;
1887 * Add non-withdrawn routes at this node
1889 count
= rfapiNhlAddNodeRoutes (rn
, &rprefix
, lifetime
, 0, &answer
, &last
,
1890 exclude_vnaddr
, rib_rn
, pfx_target_original
);
1893 * If the list has at least one entry, it's finished
1897 count
+= rfapiNhlAddSubtree (rn
, lifetime
, &answer
, &last
, NULL
,
1898 exclude_vnaddr
, rfd_rib_table
, pfx_target_original
);
1899 vnc_zlog_debug_verbose ("%s: %d nexthops, answer=%p", __func__
, count
, answer
);
1900 #if DEBUG_RETURNED_NHL
1901 rfapiPrintNhl (NULL
, answer
);
1904 route_unlock_node(rib_rn
);
1909 * Add withdrawn routes at this node
1911 count
= rfapiNhlAddNodeRoutes (rn
, &rprefix
, lifetime
, 1, &answer
, &last
,
1912 exclude_vnaddr
, rib_rn
, pfx_target_original
);
1914 route_unlock_node(rib_rn
);
1916 // rfapiPrintNhl(NULL, answer);
1919 * walk up the tree until we find a node with non-deleted
1920 * routes, then add them
1922 for (parent
= rn
->parent
; parent
; parent
= parent
->parent
)
1924 if (rfapiHasNonRemovedRoutes (parent
))
1931 * Add non-withdrawn routes from less-specific prefix
1935 rib_rn
= rfd_rib_table
? route_node_get(rfd_rib_table
, &parent
->p
): NULL
;
1936 rfapiQprefix2Rprefix (&parent
->p
, &rprefix
);
1937 count
+= rfapiNhlAddNodeRoutes (parent
, &rprefix
, lifetime
, 0,
1938 &answer
, &last
, exclude_vnaddr
, rib_rn
, pfx_target_original
);
1939 count
+= rfapiNhlAddSubtree (parent
, lifetime
, &answer
, &last
, rn
,
1940 exclude_vnaddr
, rfd_rib_table
, pfx_target_original
);
1942 route_unlock_node(rib_rn
);
1947 * There is no parent with non-removed routes. Still need to
1948 * add subtree of original node if it contributed routes to the
1952 count
+= rfapiNhlAddSubtree (rn
, lifetime
, &answer
, &last
, rn
,
1953 exclude_vnaddr
, rfd_rib_table
, pfx_target_original
);
1956 vnc_zlog_debug_verbose ("%s: %d nexthops, answer=%p", __func__
, count
, answer
);
1957 #if DEBUG_RETURNED_NHL
1958 rfapiPrintNhl (NULL
, answer
);
1964 * Construct nexthop list of all routes in table
1966 struct rfapi_next_hop_entry
*
1967 rfapiRouteTable2NextHopList (
1968 struct route_table
*rt
,
1969 uint32_t lifetime
, /* put into nexthop entries */
1970 struct rfapi_ip_addr
*exclude_vnaddr
,/* omit routes to same NVE */
1971 struct route_table
*rfd_rib_table
, /* preload this NVE rib table */
1972 struct prefix
*pfx_target_original
) /* query target */
1974 struct route_node
*rn
;
1975 struct rfapi_next_hop_entry
*biglist
= NULL
;
1976 struct rfapi_next_hop_entry
*nhl
;
1977 struct rfapi_next_hop_entry
*tail
= NULL
;
1980 for (rn
= route_top (rt
); rn
; rn
= route_next (rn
))
1983 nhl
= rfapiRouteNode2NextHopList (rn
, lifetime
, exclude_vnaddr
,
1984 rfd_rib_table
, pfx_target_original
);
1987 tail
= biglist
= nhl
;
2005 vnc_zlog_debug_verbose ("%s: returning %d routes", __func__
, count
);
2009 struct rfapi_next_hop_entry
*
2010 rfapiEthRouteNode2NextHopList (
2011 struct route_node
*rn
,
2012 struct rfapi_ip_prefix
*rprefix
,
2013 uint32_t lifetime
, /* put into nexthop entries */
2014 struct rfapi_ip_addr
*exclude_vnaddr
,/* omit routes to same NVE */
2015 struct route_table
*rfd_rib_table
,/* preload NVE rib table */
2016 struct prefix
*pfx_target_original
) /* query target */
2019 struct rfapi_next_hop_entry
*answer
= NULL
;
2020 struct rfapi_next_hop_entry
*last
= NULL
;
2021 struct route_node
*rib_rn
;
2023 rib_rn
= rfd_rib_table
? route_node_get(rfd_rib_table
, &rn
->p
): NULL
;
2025 count
= rfapiNhlAddNodeRoutes (rn
, rprefix
, lifetime
, 0, &answer
, &last
,
2026 NULL
, rib_rn
, pfx_target_original
);
2028 #if DEBUG_ENCAP_MONITOR
2029 vnc_zlog_debug_verbose ("%s: node %p: %d non-holddown routes", __func__
, rn
, count
);
2034 count
= rfapiNhlAddNodeRoutes (rn
, rprefix
, lifetime
, 1, &answer
, &last
,
2035 exclude_vnaddr
, rib_rn
, pfx_target_original
);
2036 vnc_zlog_debug_verbose ("%s: node %p: %d holddown routes", __func__
, rn
, count
);
2040 route_unlock_node(rib_rn
);
2042 #if DEBUG_RETURNED_NHL
2043 rfapiPrintNhl (NULL
, answer
);
2051 * Construct nexthop list of all routes in table
2053 struct rfapi_next_hop_entry
*
2054 rfapiEthRouteTable2NextHopList (
2055 uint32_t logical_net_id
,
2056 struct rfapi_ip_prefix
*rprefix
,
2057 uint32_t lifetime
, /* put into nexthop entries */
2058 struct rfapi_ip_addr
*exclude_vnaddr
,/* omit routes to same NVE */
2059 struct route_table
*rfd_rib_table
, /* preload NVE rib node */
2060 struct prefix
*pfx_target_original
) /* query target */
2062 struct rfapi_import_table
*it
;
2063 struct bgp
*bgp
= bgp_get_default ();
2064 struct route_table
*rt
;
2065 struct route_node
*rn
;
2066 struct rfapi_next_hop_entry
*biglist
= NULL
;
2067 struct rfapi_next_hop_entry
*nhl
;
2068 struct rfapi_next_hop_entry
*tail
= NULL
;
2072 it
= rfapiMacImportTableGet (bgp
, logical_net_id
);
2073 rt
= it
->imported_vpn
[AFI_ETHER
];
2075 for (rn
= route_top (rt
); rn
; rn
= route_next (rn
))
2078 nhl
= rfapiEthRouteNode2NextHopList(rn
, rprefix
, lifetime
,
2079 exclude_vnaddr
, rfd_rib_table
, pfx_target_original
);
2082 tail
= biglist
= nhl
;
2100 vnc_zlog_debug_verbose ("%s: returning %d routes", __func__
, count
);
2105 * Insert a new bi to the imported route table node,
2106 * keeping the list of BIs sorted best route first
2109 rfapiBgpInfoAttachSorted (
2110 struct route_node
*rn
,
2111 struct bgp_info
*info_new
,
2116 struct bgp_info
*prev
;
2117 struct bgp_info
*next
;
2119 bgp
= bgp_get_default (); /* assume 1 instance for now */
2121 if (VNC_DEBUG(IMPORT_BI_ATTACH
))
2123 vnc_zlog_debug_verbose ("%s: info_new->peer=%p", __func__
, info_new
->peer
);
2124 vnc_zlog_debug_verbose ("%s: info_new->peer->su_remote=%p", __func__
,
2125 info_new
->peer
->su_remote
);
2128 for (prev
= NULL
, next
= rn
->info
; next
; prev
= next
, next
= next
->next
)
2131 (!CHECK_FLAG (info_new
->flags
, BGP_INFO_REMOVED
) &&
2132 CHECK_FLAG (next
->flags
, BGP_INFO_REMOVED
)) ||
2133 bgp_info_cmp_compatible (bgp
, info_new
, next
, afi
, safi
) == -1)
2134 { /* -1 if 1st is better */
2138 vnc_zlog_debug_verbose ("%s: prev=%p, next=%p", __func__
, prev
, next
);
2141 prev
->next
= info_new
;
2145 rn
->info
= info_new
;
2147 info_new
->prev
= prev
;
2148 info_new
->next
= next
;
2150 next
->prev
= info_new
;
2151 bgp_attr_intern (info_new
->attr
);
2155 rfapiBgpInfoDetach (struct route_node
*rn
, struct bgp_info
*bi
)
2158 * Remove the route (doubly-linked)
2160 // bgp_attr_unintern (&bi->attr);
2162 bi
->next
->prev
= bi
->prev
;
2164 bi
->prev
->next
= bi
->next
;
2166 rn
->info
= bi
->next
;
2170 * For L3-indexed import tables
2173 rfapi_bi_peer_rd_cmp (void *b1
, void *b2
)
2175 struct bgp_info
*bi1
= b1
;
2176 struct bgp_info
*bi2
= b2
;
2181 if (bi1
->peer
< bi2
->peer
)
2183 if (bi1
->peer
> bi2
->peer
)
2189 return vnc_prefix_cmp ((struct prefix
*) &bi1
->extra
->vnc
.import
.rd
,
2190 (struct prefix
*) &bi2
->extra
->vnc
.import
.rd
);
2194 * For L2-indexed import tables
2195 * The BIs in these tables should ALWAYS have an aux_prefix set because
2196 * they arrive via IPv4 or IPv6 advertisements.
2199 rfapi_bi_peer_rd_aux_cmp (void *b1
, void *b2
)
2201 struct bgp_info
*bi1
= b1
;
2202 struct bgp_info
*bi2
= b2
;
2208 if (bi1
->peer
< bi2
->peer
)
2210 if (bi1
->peer
> bi2
->peer
)
2216 rc
= vnc_prefix_cmp ((struct prefix
*) &bi1
->extra
->vnc
.import
.rd
,
2217 (struct prefix
*) &bi2
->extra
->vnc
.import
.rd
);
2224 * L2 import tables can have multiple entries with the
2225 * same MAC address, same RD, but different L3 addresses.
2227 * Use presence of aux_prefix with AF=ethernet and prefixlen=1
2228 * as magic value to signify explicit wildcarding of the aux_prefix.
2229 * This magic value will not appear in bona fide bi entries in
2230 * the import table, but is allowed in the "fake" bi used to
2231 * probe the table when searching. (We have to test both b1 and b2
2232 * because there is no guarantee of the order the test key and
2233 * the real key will be passed)
2235 if ((bi1
->extra
->vnc
.import
.aux_prefix
.family
== AF_ETHERNET
&&
2236 (bi1
->extra
->vnc
.import
.aux_prefix
.prefixlen
== 1)) ||
2237 (bi2
->extra
->vnc
.import
.aux_prefix
.family
== AF_ETHERNET
&&
2238 (bi2
->extra
->vnc
.import
.aux_prefix
.prefixlen
== 1)))
2242 * wildcard aux address specified
2247 return vnc_prefix_cmp (&bi1
->extra
->vnc
.import
.aux_prefix
,
2248 &bi2
->extra
->vnc
.import
.aux_prefix
);
2253 * Index on RD and Peer
2257 struct route_node
*rn
, /* Import table VPN node */
2258 struct bgp_info
*bi
) /* new BI */
2260 struct skiplist
*sl
;
2268 prefix_rd2str (&bi
->extra
->vnc
.import
.rd
, buf
, BUFSIZ
);
2269 vnc_zlog_debug_verbose ("%s: bi %p, peer %p, rd %s", __func__
, bi
, bi
->peer
, buf
);
2272 sl
= RFAPI_RDINDEX_W_ALLOC (rn
);
2275 if (AF_ETHERNET
== rn
->p
.family
)
2277 sl
= skiplist_new (0, rfapi_bi_peer_rd_aux_cmp
, NULL
);
2281 sl
= skiplist_new (0, rfapi_bi_peer_rd_cmp
, NULL
);
2283 RFAPI_IT_EXTRA_GET (rn
)->u
.vpn
.idx_rd
= sl
;
2284 route_lock_node (rn
); /* for skiplist */
2286 assert (!skiplist_insert (sl
, (void *) bi
, (void *) bi
));
2287 route_lock_node (rn
); /* for skiplist entry */
2289 /* NB: BIs in import tables are not refcounted */
2293 rfapiItBiIndexDump (struct route_node
*rn
)
2295 struct skiplist
*sl
;
2296 void *cursor
= NULL
;
2301 sl
= RFAPI_RDINDEX (rn
);
2305 for (rc
= skiplist_next (sl
, (void **) &k
, (void **) &v
, &cursor
);
2306 !rc
; rc
= skiplist_next (sl
, (void **) &k
, (void **) &v
, &cursor
))
2310 char buf_aux_pfx
[BUFSIZ
];
2312 prefix_rd2str (&k
->extra
->vnc
.import
.rd
, buf
, BUFSIZ
);
2314 if (k
->extra
->vnc
.import
.aux_prefix
.family
)
2316 prefix2str (&k
->extra
->vnc
.import
.aux_prefix
, buf_aux_pfx
, BUFSIZ
);
2320 strncpy (buf_aux_pfx
, "(none)", BUFSIZ
);
2321 buf_aux_pfx
[BUFSIZ
- 1] = 0;
2324 vnc_zlog_debug_verbose ("bi %p, peer %p, rd %s, aux_prefix %s", k
, k
->peer
, buf
,
2329 static struct bgp_info
*
2330 rfapiItBiIndexSearch (
2331 struct route_node
*rn
, /* Import table VPN node */
2332 struct prefix_rd
*prd
,
2334 struct prefix
*aux_prefix
) /* optional L3 addr for L2 ITs */
2336 struct skiplist
*sl
;
2338 struct bgp_info bi_fake
;
2339 struct bgp_info_extra bi_extra
;
2340 struct bgp_info
*bi_result
;
2342 sl
= RFAPI_RDINDEX (rn
);
2349 char buf_aux_pfx
[BUFSIZ
];
2351 prefix_rd2str (prd
, buf
, BUFSIZ
);
2354 prefix2str (aux_prefix
, buf_aux_pfx
, BUFSIZ
);
2358 strncpy (buf_aux_pfx
, "(nil)", BUFSIZ
- 1);
2359 buf_aux_pfx
[BUFSIZ
- 1] = 0;
2362 vnc_zlog_debug_verbose ("%s want prd=%s, peer=%p, aux_prefix=%s",
2363 __func__
, buf
, peer
, buf_aux_pfx
);
2364 rfapiItBiIndexDump (rn
);
2368 /* threshold is a WAG */
2372 vnc_zlog_debug_verbose ("%s: short list algorithm", __func__
);
2374 /* if short list, linear search might be faster */
2375 for (bi_result
= rn
->info
; bi_result
; bi_result
= bi_result
->next
)
2380 prefix_rd2str (&bi_result
->extra
->vnc
.import
.rd
, buf
, BUFSIZ
);
2381 vnc_zlog_debug_verbose ("%s: bi has prd=%s, peer=%p", __func__
,
2382 buf
, bi_result
->peer
);
2385 if (peer
== bi_result
->peer
&&
2386 !prefix_cmp ((struct prefix
*) &bi_result
->extra
->vnc
.import
.rd
,
2387 (struct prefix
*) prd
))
2391 vnc_zlog_debug_verbose ("%s: peer and RD same, doing aux_prefix check",
2395 !prefix_cmp (aux_prefix
,
2396 &bi_result
->extra
->vnc
.import
.aux_prefix
))
2400 vnc_zlog_debug_verbose ("%s: match", __func__
);
2410 bi_fake
.peer
= peer
;
2411 bi_fake
.extra
= &bi_extra
;
2412 bi_fake
.extra
->vnc
.import
.rd
= *(struct prefix_rd
*) prd
;
2415 bi_fake
.extra
->vnc
.import
.aux_prefix
= *aux_prefix
;
2420 bi_fake
.extra
->vnc
.import
.aux_prefix
.family
= AF_ETHERNET
;
2421 bi_fake
.extra
->vnc
.import
.aux_prefix
.prefixlen
= 1;
2424 rc
= skiplist_search (sl
, (void *) &bi_fake
, (void *) &bi_result
);
2429 vnc_zlog_debug_verbose ("%s: no match", __func__
);
2435 vnc_zlog_debug_verbose ("%s: matched bi=%p", __func__
, bi_result
);
2443 struct route_node
*rn
, /* Import table VPN node */
2444 struct bgp_info
*bi
) /* old BI */
2446 struct skiplist
*sl
;
2451 prefix_rd2str (&bi
->extra
->vnc
.import
.rd
, buf
, BUFSIZ
);
2452 vnc_zlog_debug_verbose ("%s: bi %p, peer %p, rd %s", __func__
, bi
, bi
->peer
, buf
);
2455 sl
= RFAPI_RDINDEX (rn
);
2458 rc
= skiplist_delete (sl
, (void *) (bi
), (void *) bi
);
2461 rfapiItBiIndexDump (rn
);
2465 route_unlock_node (rn
); /* for skiplist entry */
2467 /* NB: BIs in import tables are not refcounted */
2471 * Add a backreference at the ENCAP node to the VPN route that
2475 rfapiMonitorEncapAdd (
2476 struct rfapi_import_table
*import_table
,
2477 struct prefix
*p
, /* VN address */
2478 struct route_node
*vpn_rn
, /* VPN node */
2479 struct bgp_info
*vpn_bi
) /* VPN bi/route */
2481 afi_t afi
= family2afi (p
->family
);
2482 struct route_node
*rn
;
2483 struct rfapi_monitor_encap
*m
;
2486 rn
= route_node_get (import_table
->imported_encap
[afi
], p
); /* locks rn */
2490 XCALLOC (MTYPE_RFAPI_MONITOR_ENCAP
, sizeof (struct rfapi_monitor_encap
));
2497 /* insert to encap node's list */
2498 m
->next
= RFAPI_MONITOR_ENCAP (rn
);
2501 RFAPI_MONITOR_ENCAP_W_ALLOC (rn
) = m
;
2503 /* for easy lookup when deleting vpn route */
2504 vpn_bi
->extra
->vnc
.import
.hme
= m
;
2506 vnc_zlog_debug_verbose
2507 ("%s: it=%p, vpn_bi=%p, afi=%d, encap rn=%p, setting vpn_bi->extra->vnc.import.hme=%p",
2508 __func__
, import_table
, vpn_bi
, afi
, rn
, m
);
2510 RFAPI_CHECK_REFCOUNT (rn
, SAFI_ENCAP
, 0);
2511 bgp_attr_intern (vpn_bi
->attr
);
2515 rfapiMonitorEncapDelete (struct bgp_info
*vpn_bi
)
2518 * Remove encap monitor
2520 vnc_zlog_debug_verbose ("%s: vpn_bi=%p", __func__
, vpn_bi
);
2523 struct rfapi_monitor_encap
*hme
= vpn_bi
->extra
->vnc
.import
.hme
;
2528 vnc_zlog_debug_verbose ("%s: hme=%p", __func__
, hme
);
2530 /* Refcount checking takes too long here */
2531 //RFAPI_CHECK_REFCOUNT(hme->rn, SAFI_ENCAP, 0);
2533 hme
->next
->prev
= hme
->prev
;
2535 hme
->prev
->next
= hme
->next
;
2537 RFAPI_MONITOR_ENCAP_W_ALLOC (hme
->rn
) = hme
->next
;
2538 /* Refcount checking takes too long here */
2539 //RFAPI_CHECK_REFCOUNT(hme->rn, SAFI_ENCAP, 1);
2541 /* see if the struct rfapi_it_extra is empty and can be freed */
2542 rfapiMonitorExtraPrune (SAFI_ENCAP
, hme
->rn
);
2544 route_unlock_node (hme
->rn
); /* decr ref count */
2545 XFREE (MTYPE_RFAPI_MONITOR_ENCAP
, hme
);
2546 vpn_bi
->extra
->vnc
.import
.hme
= NULL
;
2552 * quagga lib/thread.h says this must return int even though
2553 * it doesn't do anything with the return value
2556 rfapiWithdrawTimerVPN (struct thread
*t
)
2558 struct rfapi_withdraw
*wcb
= t
->arg
;
2559 struct bgp_info
*bi
= wcb
->info
;
2560 struct bgp
*bgp
= bgp_get_default ();
2562 struct rfapi_monitor_vpn
*moved
;
2567 assert (wcb
->import_table
);
2570 RFAPI_CHECK_REFCOUNT (wcb
->node
, SAFI_MPLS_VPN
, wcb
->lockoffset
);
2575 vnc_zlog_debug_verbose ("%s: removing bi %p at prefix %s/%d",
2578 rfapi_ntop (wcb
->node
->p
.family
, &wcb
->node
->p
.u
.prefix
, buf
,
2579 BUFSIZ
), wcb
->node
->p
.prefixlen
);
2583 * Remove the route (doubly-linked)
2585 if (CHECK_FLAG (bi
->flags
, BGP_INFO_VALID
)
2586 && VALID_INTERIOR_TYPE (bi
->type
))
2587 RFAPI_MONITOR_EXTERIOR (wcb
->node
)->valid_interior_count
--;
2589 afi
= family2afi (wcb
->node
->p
.family
);
2590 wcb
->import_table
->holddown_count
[afi
] -= 1; /* keep count consistent */
2591 rfapiItBiIndexDel (wcb
->node
, bi
);
2592 rfapiBgpInfoDetach (wcb
->node
, bi
); /* with removed bi */
2594 vnc_import_bgp_exterior_del_route_interior (bgp
, wcb
->import_table
,
2599 * If VNC is configured to send response remove messages, AND
2600 * if the removed route had a UN address, do response removal
2603 if (!(bgp
->rfapi_cfg
->flags
& BGP_VNC_CONFIG_RESPONSE_REMOVAL_DISABLE
))
2606 int has_valid_duplicate
= 0;
2607 struct bgp_info
*bii
;
2610 * First check if there are any OTHER routes at this node
2611 * that have the same nexthop and a valid UN address. If
2612 * there are (e.g., from other peers), then the route isn't
2613 * really gone, so skip sending a response removal message.
2615 for (bii
= wcb
->node
->info
; bii
; bii
= bii
->next
)
2617 if (rfapiVpnBiSamePtUn (bi
, bii
))
2619 has_valid_duplicate
= 1;
2624 vnc_zlog_debug_verbose ("%s: has_valid_duplicate=%d", __func__
,
2625 has_valid_duplicate
);
2627 if (!has_valid_duplicate
)
2629 rfapiRibPendingDeleteRoute (bgp
, wcb
->import_table
, afi
, wcb
->node
);
2633 rfapiMonitorEncapDelete (bi
);
2636 * If there are no VPN monitors at this VPN Node A,
2639 if (!RFAPI_MONITOR_VPN (wcb
->node
))
2641 vnc_zlog_debug_verbose ("%s: no VPN monitors at this node", __func__
);
2646 * rfapiMonitorMoveShorter only moves monitors if there are
2647 * no remaining valid routes at the current node
2649 moved
= rfapiMonitorMoveShorter (wcb
->node
, 1);
2653 rfapiMonitorMovedUp (wcb
->import_table
, wcb
->node
, moved
->node
, moved
);
2660 rfapiBgpInfoFree (bi
);
2664 * If route count at this node has gone to 0, withdraw exported prefix
2666 if (!wcb
->node
->info
)
2668 /* see if the struct rfapi_it_extra is empty and can be freed */
2669 rfapiMonitorExtraPrune (SAFI_MPLS_VPN
, wcb
->node
);
2670 vnc_direct_bgp_del_prefix (bgp
, wcb
->import_table
, wcb
->node
);
2671 vnc_zebra_del_prefix (bgp
, wcb
->import_table
, wcb
->node
);
2676 * nexthop change event
2677 * vnc_direct_bgp_add_prefix() will recompute the VN addr ecommunity
2679 vnc_direct_bgp_add_prefix (bgp
, wcb
->import_table
, wcb
->node
);
2682 RFAPI_CHECK_REFCOUNT (wcb
->node
, SAFI_MPLS_VPN
, 1 + wcb
->lockoffset
);
2683 route_unlock_node (wcb
->node
); /* decr ref count */
2684 XFREE (MTYPE_RFAPI_WITHDRAW
, wcb
);
2689 * This works for multiprotocol extension, but not for plain ol'
2690 * unicast IPv4 because that nexthop is stored in attr->nexthop
2693 rfapiNexthop2Prefix (struct attr
*attr
, struct prefix
*p
)
2697 assert (attr
->extra
);
2699 memset (p
, 0, sizeof (struct prefix
));
2701 switch (p
->family
= BGP_MP_NEXTHOP_FAMILY (attr
->extra
->mp_nexthop_len
))
2704 p
->u
.prefix4
= attr
->extra
->mp_nexthop_global_in
;
2709 p
->u
.prefix6
= attr
->extra
->mp_nexthop_global
;
2714 vnc_zlog_debug_verbose ("%s: Family is unknown = %d",
2715 __func__
, p
->family
);
2720 rfapiUnicastNexthop2Prefix (afi_t afi
, struct attr
*attr
, struct prefix
*p
)
2724 p
->family
= AF_INET
;
2726 p
->u
.prefix4
= attr
->nexthop
;
2730 rfapiNexthop2Prefix (attr
, p
);
2735 rfapiAttrNexthopAddrDifferent (struct prefix
*p1
, struct prefix
*p2
)
2739 vnc_zlog_debug_verbose ("%s: p1 or p2 is NULL", __func__
);
2744 * Are address families the same?
2746 if (p1
->family
!= p2
->family
)
2754 if (IPV4_ADDR_SAME (&p1
->u
.prefix4
, &p2
->u
.prefix4
))
2759 if (IPV6_ADDR_SAME (&p1
->u
.prefix6
, &p2
->u
.prefix6
))
2772 rfapiCopyUnEncap2VPN (struct bgp_info
*encap_bi
, struct bgp_info
*vpn_bi
)
2774 struct attr_extra
*attre
;
2776 if (!encap_bi
->attr
|| !encap_bi
->attr
->extra
)
2778 zlog_warn ("%s: no encap bi attr/extra, can't copy UN address",
2783 if (!vpn_bi
|| !vpn_bi
->extra
)
2785 zlog_warn ("%s: no vpn bi attr/extra, can't copy UN address",
2790 attre
= encap_bi
->attr
->extra
;
2792 switch (BGP_MP_NEXTHOP_FAMILY (attre
->mp_nexthop_len
))
2797 * instrumentation to debug segfault of 091127
2799 vnc_zlog_debug_verbose ("%s: vpn_bi=%p", __func__
, vpn_bi
);
2802 vnc_zlog_debug_verbose ("%s: vpn_bi->extra=%p", __func__
, vpn_bi
->extra
);
2805 vpn_bi
->extra
->vnc
.import
.un_family
= AF_INET
;
2806 vpn_bi
->extra
->vnc
.import
.un
.addr4
= attre
->mp_nexthop_global_in
;
2810 vpn_bi
->extra
->vnc
.import
.un_family
= AF_INET6
;
2811 vpn_bi
->extra
->vnc
.import
.un
.addr6
= attre
->mp_nexthop_global
;
2815 zlog_warn ("%s: invalid encap nexthop length: %d",
2816 __func__
, attre
->mp_nexthop_len
);
2817 vpn_bi
->extra
->vnc
.import
.un_family
= 0;
2823 * returns 0 on success, nonzero on error
2826 rfapiWithdrawEncapUpdateCachedUn (
2827 struct rfapi_import_table
*import_table
,
2828 struct bgp_info
*encap_bi
,
2829 struct route_node
*vpn_rn
,
2830 struct bgp_info
*vpn_bi
)
2836 * clear cached UN address
2838 if (!vpn_bi
|| !vpn_bi
->extra
)
2840 zlog_warn ("%s: missing VPN bi/extra, can't clear UN addr",
2844 vpn_bi
->extra
->vnc
.import
.un_family
= 0;
2845 memset (&vpn_bi
->extra
->vnc
.import
.un
, 0,
2846 sizeof (vpn_bi
->extra
->vnc
.import
.un
));
2847 if (CHECK_FLAG (vpn_bi
->flags
, BGP_INFO_VALID
))
2849 if (rfapiGetVncTunnelUnAddr (vpn_bi
->attr
, NULL
))
2851 UNSET_FLAG (vpn_bi
->flags
, BGP_INFO_VALID
);
2852 if (VALID_INTERIOR_TYPE (vpn_bi
->type
))
2853 RFAPI_MONITOR_EXTERIOR (vpn_rn
)->valid_interior_count
--;
2854 /* signal interior route withdrawal to import-exterior */
2855 vnc_import_bgp_exterior_del_route_interior (bgp_get_default (),
2866 zlog_warn ("%s: missing VPN bi, can't clear UN addr", __func__
);
2869 rfapiCopyUnEncap2VPN (encap_bi
, vpn_bi
);
2870 if (!CHECK_FLAG (vpn_bi
->flags
, BGP_INFO_VALID
))
2872 SET_FLAG (vpn_bi
->flags
, BGP_INFO_VALID
);
2873 if (VALID_INTERIOR_TYPE (vpn_bi
->type
))
2874 RFAPI_MONITOR_EXTERIOR (vpn_rn
)->valid_interior_count
++;
2875 /* signal interior route withdrawal to import-exterior */
2876 vnc_import_bgp_exterior_add_route_interior (bgp_get_default (),
2885 rfapiWithdrawTimerEncap (struct thread
*t
)
2887 struct rfapi_withdraw
*wcb
= t
->arg
;
2888 struct bgp_info
*bi
= wcb
->info
;
2889 int was_first_route
= 0;
2890 struct rfapi_monitor_encap
*em
;
2891 struct skiplist
*vpn_node_sl
= skiplist_new (0, NULL
, NULL
);
2895 assert (wcb
->import_table
);
2897 RFAPI_CHECK_REFCOUNT (wcb
->node
, SAFI_ENCAP
, 0);
2899 if (wcb
->node
->info
== bi
)
2900 was_first_route
= 1;
2903 * Remove the route/bi and free it
2905 rfapiBgpInfoDetach (wcb
->node
, bi
);
2906 rfapiBgpInfoFree (bi
);
2908 if (!was_first_route
)
2911 for (em
= RFAPI_MONITOR_ENCAP (wcb
->node
); em
; em
= em
->next
)
2915 * Update monitoring VPN BIs with new encap info at the
2916 * head of the encap bi chain (which could be NULL after
2917 * removing the expiring bi above)
2919 if (rfapiWithdrawEncapUpdateCachedUn
2920 (wcb
->import_table
, wcb
->node
->info
, em
->node
, em
->bi
))
2924 * Build a list of unique VPN nodes referenced by these monitors.
2925 * Use a skiplist for speed.
2927 skiplist_insert (vpn_node_sl
, em
->node
, em
->node
);
2932 * for each VPN node referenced in the ENCAP monitors:
2934 struct route_node
*rn
;
2935 while (!skiplist_first (vpn_node_sl
, (void **) &rn
, NULL
))
2937 if (!wcb
->node
->info
)
2939 struct rfapi_monitor_vpn
*moved
;
2941 moved
= rfapiMonitorMoveShorter (rn
, 0);
2944 //rfapiDoRouteCallback(wcb->import_table, moved->node, moved);
2945 rfapiMonitorMovedUp (wcb
->import_table
, rn
, moved
->node
, moved
);
2950 //rfapiDoRouteCallback(wcb->import_table, rn, NULL);
2951 rfapiMonitorItNodeChanged (wcb
->import_table
, rn
, NULL
);
2953 skiplist_delete_first (vpn_node_sl
);
2957 RFAPI_CHECK_REFCOUNT (wcb
->node
, SAFI_ENCAP
, 1);
2958 route_unlock_node (wcb
->node
); /* decr ref count */
2959 XFREE (MTYPE_RFAPI_WITHDRAW
, wcb
);
2960 skiplist_free (vpn_node_sl
);
2966 * Works for both VPN and ENCAP routes; timer_service_func is different
2970 rfapiBiStartWithdrawTimer (
2971 struct rfapi_import_table
*import_table
,
2972 struct route_node
*rn
,
2973 struct bgp_info
*bi
,
2976 int (*timer_service_func
) (struct thread
*))
2979 struct rfapi_withdraw
*wcb
;
2982 (bi
->flags
, BGP_INFO_REMOVED
)
2985 * Already on the path to being withdrawn,
2986 * should already have a timer set up to
2989 vnc_zlog_debug_verbose ("%s: already being withdrawn, do nothing", __func__
);
2993 rfapiGetVncLifetime (bi
->attr
, &lifetime
);
2994 vnc_zlog_debug_verbose ("%s: VNC lifetime is %u", __func__
, lifetime
);
2997 * withdrawn routes get to hang around for a while
2999 SET_FLAG (bi
->flags
, BGP_INFO_REMOVED
);
3001 /* set timer to remove the route later */
3002 lifetime
= rfapiGetHolddownFromLifetime (lifetime
);
3003 vnc_zlog_debug_verbose ("%s: using timeout %u", __func__
, lifetime
);
3006 * Stash import_table, node, and info for use by timer
3007 * service routine, which is supposed to free the wcb.
3009 wcb
= XCALLOC (MTYPE_RFAPI_WITHDRAW
, sizeof (struct rfapi_withdraw
));
3013 wcb
->import_table
= import_table
;
3014 bgp_attr_intern (bi
->attr
);
3016 if (VNC_DEBUG(VERBOSE
))
3018 vnc_zlog_debug_verbose
3019 ("%s: wcb values: node=%p, info=%p, import_table=%p (bi follows)",
3020 __func__
, wcb
->node
, wcb
->info
, wcb
->import_table
);
3021 rfapiPrintBi (NULL
, bi
);
3026 if (lifetime
> UINT32_MAX
/ 1001)
3028 /* sub-optimal case, but will probably never happen */
3029 bi
->extra
->vnc
.import
.timer
= thread_add_timer (bm
->master
,
3035 static uint32_t jitter
;
3036 uint32_t lifetime_msec
;
3039 * the goal here is to spread out the timers so they are
3040 * sortable in the skip list
3042 if (++jitter
>= 1000)
3045 lifetime_msec
= (lifetime
* 1000) + jitter
;
3047 bi
->extra
->vnc
.import
.timer
= thread_add_background (bm
->master
,
3053 /* re-sort route list (BGP_INFO_REMOVED routes are last) */
3054 if (((struct bgp_info
*) rn
->info
)->next
)
3056 rfapiBgpInfoDetach (rn
, bi
);
3057 rfapiBgpInfoAttachSorted (rn
, bi
, afi
, safi
);
3062 typedef void (rfapi_bi_filtered_import_f
) (struct rfapi_import_table
*,
3071 u_char
, u_char
, uint32_t *);
3075 rfapiExpireEncapNow (
3076 struct rfapi_import_table
*it
,
3077 struct route_node
*rn
,
3078 struct bgp_info
*bi
)
3080 struct rfapi_withdraw
*wcb
;
3084 * pretend we're an expiring timer
3086 wcb
= XCALLOC (MTYPE_RFAPI_WITHDRAW
, sizeof (struct rfapi_withdraw
));
3089 wcb
->import_table
= it
;
3090 memset (&t
, 0, sizeof (t
));
3092 rfapiWithdrawTimerEncap (&t
); /* frees wcb */
3096 rfapiGetNexthop (struct attr
*attr
, struct prefix
*prefix
)
3098 switch (BGP_MP_NEXTHOP_FAMILY (attr
->extra
->mp_nexthop_len
))
3101 prefix
->family
= AF_INET
;
3102 prefix
->prefixlen
= 32;
3103 prefix
->u
.prefix4
= attr
->extra
->mp_nexthop_global_in
;
3106 prefix
->family
= AF_INET6
;
3107 prefix
->prefixlen
= 128;
3108 prefix
->u
.prefix6
= attr
->extra
->mp_nexthop_global
;
3111 vnc_zlog_debug_verbose ("%s: unknown attr->extra->mp_nexthop_len %d", __func__
,
3112 attr
->extra
->mp_nexthop_len
);
3119 * import a bgp_info if its route target list intersects with the
3120 * import table's route target list
3123 rfapiBgpInfoFilteredImportEncap (
3124 struct rfapi_import_table
*import_table
,
3127 void *rfd
, /* set for looped back routes */
3129 struct prefix
*aux_prefix
, /* Unused for encap routes */
3131 struct prefix_rd
*prd
,
3132 struct attr
*attr
, /* part of bgp_info */
3133 u_char type
, /* part of bgp_info */
3134 u_char sub_type
, /* part of bgp_info */
3135 uint32_t *label
) /* part of bgp_info */
3137 struct route_table
*rt
= NULL
;
3138 struct route_node
*rn
;
3139 struct bgp_info
*info_new
;
3140 struct bgp_info
*bi
;
3141 struct bgp_info
*next
;
3144 struct prefix p_firstbi_old
;
3145 struct prefix p_firstbi_new
;
3147 const char *action_str
= NULL
;
3148 struct prefix un_prefix
;
3151 bgp
= bgp_get_default (); /* assume 1 instance for now */
3155 case FIF_ACTION_UPDATE
:
3156 action_str
= "update";
3158 case FIF_ACTION_WITHDRAW
:
3159 action_str
= "withdraw";
3161 case FIF_ACTION_KILL
:
3162 action_str
= "kill";
3169 vnc_zlog_debug_verbose ("%s: entry: %s: prefix %s/%d", __func__
,
3171 inet_ntop (p
->family
, &p
->u
.prefix
, buf
, BUFSIZ
), p
->prefixlen
);
3173 memset (&p_firstbi_old
, 0, sizeof (p_firstbi_old
));
3174 memset (&p_firstbi_new
, 0, sizeof (p_firstbi_new
));
3176 if (action
== FIF_ACTION_UPDATE
)
3179 * Compare rt lists. If no intersection, don't import this route
3180 * On a withdraw, peer and RD are sufficient to determine if
3183 if (!attr
|| !attr
->extra
|| !attr
->extra
->ecommunity
)
3186 vnc_zlog_debug_verbose ("%s: attr, extra, or ecommunity missing, not importing",
3190 #if RFAPI_REQUIRE_ENCAP_BEEC
3191 if (!rfapiEcommunitiesMatchBeec (attr
->extra
->ecommunity
))
3193 vnc_zlog_debug_verbose ("%s: it=%p: no match for BGP Encapsulation ecommunity",
3194 __func__
, import_table
);
3198 if (!rfapiEcommunitiesIntersect (import_table
->rt_import_list
,
3199 attr
->extra
->ecommunity
))
3202 vnc_zlog_debug_verbose ("%s: it=%p: no ecommunity intersection",
3203 __func__
, import_table
);
3208 * Updates must also have a nexthop address
3210 memset (&un_prefix
, 0, sizeof (un_prefix
)); /* keep valgrind happy */
3211 if (rfapiGetNexthop (attr
, &un_prefix
))
3213 vnc_zlog_debug_verbose ("%s: missing nexthop address", __func__
);
3219 * Figure out which radix tree the route would go into
3225 rt
= import_table
->imported_encap
[afi
];
3229 zlog_err ("%s: bad afi %d", __func__
, afi
);
3234 * route_node_lookup returns a node only if there is at least
3235 * one route attached.
3237 rn
= route_node_lookup (rt
, p
);
3239 #if DEBUG_ENCAP_MONITOR
3240 vnc_zlog_debug_verbose ("%s: initial encap lookup (it=%p) rn=%p",
3241 __func__
, import_table
, rn
);
3247 RFAPI_CHECK_REFCOUNT (rn
, SAFI_ENCAP
, 1);
3248 route_unlock_node (rn
); /* undo lock in route_node_lookup */
3252 * capture nexthop of first bi
3256 rfapiNexthop2Prefix (((struct bgp_info
*) (rn
->info
))->attr
,
3260 for (bi
= rn
->info
; bi
; bi
= bi
->next
)
3264 * Does this bgp_info refer to the same route
3265 * as we are trying to add?
3267 vnc_zlog_debug_verbose ("%s: comparing BI %p", __func__
, bi
);
3273 * RD of import table bi is in bi->extra->vnc.import.rd
3274 * RD of info_orig is in prd
3278 vnc_zlog_debug_verbose ("%s: no bi->extra", __func__
);
3281 if (prefix_cmp ((struct prefix
*) &bi
->extra
->vnc
.import
.rd
,
3282 (struct prefix
*) prd
))
3285 vnc_zlog_debug_verbose ("%s: prd does not match", __func__
);
3292 if (bi
->peer
!= peer
)
3294 vnc_zlog_debug_verbose ("%s: peer does not match", __func__
);
3298 vnc_zlog_debug_verbose ("%s: found matching bi", __func__
);
3300 /* Same route. Delete this bi, replace with new one */
3302 if (action
== FIF_ACTION_WITHDRAW
)
3305 vnc_zlog_debug_verbose ("%s: withdrawing at prefix %s/%d",
3307 inet_ntop (rn
->p
.family
, &rn
->p
.u
.prefix
, buf
,
3308 BUFSIZ
), rn
->p
.prefixlen
);
3310 rfapiBiStartWithdrawTimer (import_table
, rn
, bi
,
3312 rfapiWithdrawTimerEncap
);
3317 vnc_zlog_debug_verbose ("%s: %s at prefix %s/%d",
3320 FIF_ACTION_KILL
) ? "killing" : "replacing"),
3321 inet_ntop (rn
->p
.family
, &rn
->p
.u
.prefix
, buf
,
3322 BUFSIZ
), rn
->p
.prefixlen
);
3325 * If this route is waiting to be deleted because of
3326 * a previous withdraw, we must cancel its timer.
3328 if (CHECK_FLAG (bi
->flags
, BGP_INFO_REMOVED
)
3329 && bi
->extra
->vnc
.import
.timer
)
3333 (struct thread
*) bi
->extra
->vnc
.import
.timer
;
3334 struct rfapi_withdraw
*wcb
= t
->arg
;
3336 XFREE (MTYPE_RFAPI_WITHDRAW
, wcb
);
3340 if (action
== FIF_ACTION_UPDATE
)
3342 rfapiBgpInfoDetach (rn
, bi
);
3343 rfapiBgpInfoFree (bi
);
3349 * Kill: do export stuff when removing bi
3351 struct rfapi_withdraw
*wcb
;
3355 * pretend we're an expiring timer
3358 XCALLOC (MTYPE_RFAPI_WITHDRAW
,
3359 sizeof (struct rfapi_withdraw
));
3362 wcb
->import_table
= import_table
;
3363 memset (&t
, 0, sizeof (t
));
3365 rfapiWithdrawTimerEncap (&t
); /* frees wcb */
3374 RFAPI_CHECK_REFCOUNT (rn
, SAFI_ENCAP
, replacing
? 1 : 0);
3376 if (action
== FIF_ACTION_WITHDRAW
|| action
== FIF_ACTION_KILL
)
3379 info_new
= rfapiBgpInfoCreate (attr
, peer
, rfd
, prd
, type
, sub_type
, NULL
);
3384 route_lock_node (rn
); /* incr ref count for new BI */
3388 rn
= route_node_get (rt
, p
);
3391 vnc_zlog_debug_verbose ("%s: (afi=%d, rn=%p) inserting at prefix %s/%d",
3395 inet_ntop (rn
->p
.family
, &rn
->p
.u
.prefix
, buf
, BUFSIZ
),
3398 rfapiBgpInfoAttachSorted (rn
, info_new
, afi
, SAFI_ENCAP
);
3401 * Delete holddown routes from same NVE. See details in
3402 * rfapiBgpInfoFilteredImportVPN()
3404 for (bi
= info_new
->next
; bi
; bi
= next
)
3407 struct prefix pfx_un
;
3411 if (!CHECK_FLAG (bi
->flags
, BGP_INFO_REMOVED
))
3415 * We already match the VN address (it is the prefix
3416 * of the route node)
3419 if (!rfapiGetNexthop (bi
->attr
, &pfx_un
) &&
3420 prefix_same (&pfx_un
, &un_prefix
))
3429 vnc_zlog_debug_verbose ("%s: removing holddown bi matching NVE of new route",
3431 if (bi
->extra
->vnc
.import
.timer
)
3433 struct thread
*t
= (struct thread
*) bi
->extra
->vnc
.import
.timer
;
3434 struct rfapi_withdraw
*wcb
= t
->arg
;
3436 XFREE (MTYPE_RFAPI_WITHDRAW
, wcb
);
3439 rfapiExpireEncapNow (import_table
, rn
, bi
);
3442 rfapiNexthop2Prefix (((struct bgp_info
*) (rn
->info
))->attr
,
3446 * If the nexthop address of the selected Encap route (i.e.,
3447 * the UN address) has changed, then we must update the VPN
3448 * routes that refer to this Encap route and possibly force
3451 if (rfapiAttrNexthopAddrDifferent (&p_firstbi_old
, &p_firstbi_new
))
3454 struct rfapi_monitor_encap
*m
;
3455 struct rfapi_monitor_encap
*mnext
;
3457 struct route_node
*referenced_vpn_prefix
;
3460 * Optimized approach: build radix tree on the fly to
3461 * hold list of VPN nodes referenced by the ENCAP monitors
3463 * The nodes in this table correspond to prefixes of VPN routes.
3464 * The "info" pointer of the node points to a chain of
3465 * struct rfapi_monitor_encap, each of which refers to a
3466 * specific VPN node.
3468 struct route_table
*referenced_vpn_table
;
3470 referenced_vpn_table
= route_table_init ();
3471 assert (referenced_vpn_table
);
3474 * iterate over the set of monitors at this ENCAP node.
3476 #if DEBUG_ENCAP_MONITOR
3477 vnc_zlog_debug_verbose ("%s: examining monitors at rn=%p", __func__
, rn
);
3479 for (m
= RFAPI_MONITOR_ENCAP (rn
); m
; m
= m
->next
)
3483 * For each referenced bi/route, copy the ENCAP route's
3484 * nexthop to the VPN route's cached UN address field and set
3485 * the address family of the cached UN address field.
3487 rfapiCopyUnEncap2VPN (info_new
, m
->bi
);
3488 if (!CHECK_FLAG (m
->bi
->flags
, BGP_INFO_VALID
))
3490 SET_FLAG (m
->bi
->flags
, BGP_INFO_VALID
);
3491 if (VALID_INTERIOR_TYPE (m
->bi
->type
))
3492 RFAPI_MONITOR_EXTERIOR (m
->node
)->valid_interior_count
++;
3493 vnc_import_bgp_exterior_add_route_interior (bgp
,
3499 * Build a list of unique VPN nodes referenced by these monitors
3501 * There could be more than one VPN node here with a given
3502 * prefix. Those are currently in an unsorted linear list
3506 referenced_vpn_prefix
=
3507 route_node_get (referenced_vpn_table
, &m
->node
->p
);
3508 assert (referenced_vpn_prefix
);
3509 for (mnext
= referenced_vpn_prefix
->info
; mnext
;
3510 mnext
= mnext
->next
)
3513 if (mnext
->node
== m
->node
)
3520 * already have an entry for this VPN node
3522 route_unlock_node (referenced_vpn_prefix
);
3526 mnext
= XCALLOC (MTYPE_RFAPI_MONITOR_ENCAP
,
3527 sizeof (struct rfapi_monitor_encap
));
3529 mnext
->node
= m
->node
;
3530 mnext
->next
= referenced_vpn_prefix
->info
;
3531 referenced_vpn_prefix
->info
= mnext
;
3537 * for each VPN node referenced in the ENCAP monitors:
3539 for (referenced_vpn_prefix
= route_top (referenced_vpn_table
);
3540 referenced_vpn_prefix
;
3541 referenced_vpn_prefix
= route_next (referenced_vpn_prefix
))
3544 while ((m
= referenced_vpn_prefix
->info
))
3547 struct route_node
*n
;
3549 rfapiMonitorMoveLonger (m
->node
);
3550 for (n
= m
->node
; n
; n
= n
->parent
)
3552 //rfapiDoRouteCallback(import_table, n, NULL);
3554 rfapiMonitorItNodeChanged (import_table
, m
->node
, NULL
);
3556 referenced_vpn_prefix
->info
= m
->next
;
3557 route_unlock_node (referenced_vpn_prefix
);
3558 XFREE (MTYPE_RFAPI_MONITOR_ENCAP
, m
);
3562 route_table_finish (referenced_vpn_table
);
3565 RFAPI_CHECK_REFCOUNT (rn
, SAFI_ENCAP
, 0);
3570 struct rfapi_import_table
*it
,
3571 struct route_node
*rn
,
3572 struct bgp_info
*bi
,
3575 struct rfapi_withdraw
*wcb
;
3579 * pretend we're an expiring timer
3581 wcb
= XCALLOC (MTYPE_RFAPI_WITHDRAW
, sizeof (struct rfapi_withdraw
));
3584 wcb
->import_table
= it
;
3585 wcb
->lockoffset
= lockoffset
;
3586 memset (&t
, 0, sizeof (t
));
3588 rfapiWithdrawTimerVPN (&t
); /* frees wcb */
3593 * import a bgp_info if its route target list intersects with the
3594 * import table's route target list
3597 rfapiBgpInfoFilteredImportVPN (
3598 struct rfapi_import_table
*import_table
,
3601 void *rfd
, /* set for looped back routes */
3603 struct prefix
*aux_prefix
, /* AFI_ETHER: optional IP */
3605 struct prefix_rd
*prd
,
3606 struct attr
*attr
, /* part of bgp_info */
3607 u_char type
, /* part of bgp_info */
3608 u_char sub_type
, /* part of bgp_info */
3609 uint32_t *label
) /* part of bgp_info */
3611 struct route_table
*rt
= NULL
;
3612 struct route_node
*rn
;
3613 struct route_node
*n
;
3614 struct bgp_info
*info_new
;
3615 struct bgp_info
*bi
;
3616 struct bgp_info
*next
;
3618 struct prefix vn_prefix
;
3619 struct prefix un_prefix
;
3620 int un_prefix_valid
= 0;
3621 struct route_node
*ern
;
3623 int original_had_routes
= 0;
3624 struct prefix original_nexthop
;
3625 const char *action_str
= NULL
;
3629 bgp
= bgp_get_default (); /* assume 1 instance for now */
3633 case FIF_ACTION_UPDATE
:
3634 action_str
= "update";
3636 case FIF_ACTION_WITHDRAW
:
3637 action_str
= "withdraw";
3639 case FIF_ACTION_KILL
:
3640 action_str
= "kill";
3647 if (import_table
== bgp
->rfapi
->it_ce
)
3650 vnc_zlog_debug_verbose ("%s: entry: %s%s: prefix %s/%d: it %p, afi %s", __func__
,
3651 (is_it_ce
? "CE-IT " : ""),
3653 rfapi_ntop (p
->family
, &p
->u
.prefix
, buf
, BUFSIZ
),
3654 p
->prefixlen
, import_table
, afi2str (afi
));
3659 * Compare rt lists. If no intersection, don't import this route
3660 * On a withdraw, peer and RD are sufficient to determine if
3663 if (action
== FIF_ACTION_UPDATE
)
3665 if (!attr
|| !attr
->extra
|| !attr
->extra
->ecommunity
)
3668 vnc_zlog_debug_verbose ("%s: attr, extra, or ecommunity missing, not importing",
3672 if ((import_table
!= bgp
->rfapi
->it_ce
) &&
3673 !rfapiEcommunitiesIntersect (import_table
->rt_import_list
,
3674 attr
->extra
->ecommunity
))
3677 vnc_zlog_debug_verbose ("%s: it=%p: no ecommunity intersection",
3678 __func__
, import_table
);
3682 memset (&vn_prefix
, 0, sizeof (vn_prefix
)); /* keep valgrind happy */
3683 if (rfapiGetNexthop (attr
, &vn_prefix
))
3685 /* missing nexthop address would be a bad, bad thing */
3686 vnc_zlog_debug_verbose ("%s: missing nexthop", __func__
);
3692 * Figure out which radix tree the route would go into
3699 rt
= import_table
->imported_vpn
[afi
];
3703 zlog_err ("%s: bad afi %d", __func__
, afi
);
3708 memset (&original_nexthop
, 0, sizeof (original_nexthop
));
3711 * route_node_lookup returns a node only if there is at least
3712 * one route attached.
3714 rn
= route_node_lookup (rt
, p
);
3716 vnc_zlog_debug_verbose ("%s: rn=%p", __func__
, rn
);
3721 RFAPI_CHECK_REFCOUNT (rn
, SAFI_MPLS_VPN
, 1);
3722 route_unlock_node (rn
); /* undo lock in route_node_lookup */
3725 original_had_routes
= 1;
3728 * Look for same route (will have same RD and peer)
3730 bi
= rfapiItBiIndexSearch (rn
, prd
, peer
, aux_prefix
);
3736 * This was an old test when we iterated over the
3737 * BIs linearly. Since we're now looking up with
3738 * RD and peer, comparing types should not be
3739 * needed. Changed to assertion.
3741 * Compare types. Doing so prevents a RFP-originated
3742 * route from matching an imported route, for example.
3744 assert (bi
->type
== type
);
3746 vnc_zlog_debug_verbose ("%s: found matching bi", __func__
);
3749 * In the special CE table, withdrawals occur without holddown
3751 if (import_table
== bgp
->rfapi
->it_ce
)
3753 vnc_direct_bgp_del_route_ce (bgp
, rn
, bi
);
3754 if (action
== FIF_ACTION_WITHDRAW
)
3755 action
= FIF_ACTION_KILL
;
3758 if (action
== FIF_ACTION_WITHDRAW
)
3761 int washolddown
= CHECK_FLAG (bi
->flags
, BGP_INFO_REMOVED
);
3763 vnc_zlog_debug_verbose ("%s: withdrawing at prefix %s/%d%s",
3765 rfapi_ntop (rn
->p
.family
, &rn
->p
.u
.prefix
, buf
,
3766 BUFSIZ
), rn
->p
.prefixlen
,
3767 (washolddown
? " (already being withdrawn)" : ""));
3772 rfapiBiStartWithdrawTimer (import_table
, rn
, bi
,
3774 rfapiWithdrawTimerVPN
);
3776 RFAPI_UPDATE_ITABLE_COUNT (bi
, import_table
, afi
, -1);
3777 import_table
->holddown_count
[afi
] += 1;
3783 vnc_zlog_debug_verbose ("%s: %s at prefix %s/%d",
3786 FIF_ACTION_KILL
) ? "killing" : "replacing"),
3787 rfapi_ntop (rn
->p
.family
, &rn
->p
.u
.prefix
, buf
,
3788 BUFSIZ
), rn
->p
.prefixlen
);
3791 * If this route is waiting to be deleted because of
3792 * a previous withdraw, we must cancel its timer.
3794 if (CHECK_FLAG (bi
->flags
, BGP_INFO_REMOVED
) &&
3795 bi
->extra
->vnc
.import
.timer
)
3799 (struct thread
*) bi
->extra
->vnc
.import
.timer
;
3800 struct rfapi_withdraw
*wcb
= t
->arg
;
3802 XFREE (MTYPE_RFAPI_WITHDRAW
, wcb
);
3805 import_table
->holddown_count
[afi
] -= 1;
3806 RFAPI_UPDATE_ITABLE_COUNT (bi
, import_table
, afi
, 1);
3809 * decrement remote count (if route is remote) because
3810 * we are going to remove it below
3812 RFAPI_UPDATE_ITABLE_COUNT (bi
, import_table
, afi
, -1);
3813 if (action
== FIF_ACTION_UPDATE
)
3818 * make copy of original nexthop so we can see if it changed
3820 rfapiGetNexthop (bi
->attr
, &original_nexthop
);
3823 * remove bi without doing any export processing
3825 if (CHECK_FLAG (bi
->flags
, BGP_INFO_VALID
)
3826 && VALID_INTERIOR_TYPE (bi
->type
))
3827 RFAPI_MONITOR_EXTERIOR (rn
)->valid_interior_count
--;
3828 rfapiItBiIndexDel (rn
, bi
);
3829 rfapiBgpInfoDetach (rn
, bi
);
3830 rfapiMonitorEncapDelete (bi
);
3831 vnc_import_bgp_exterior_del_route_interior (bgp
,
3834 rfapiBgpInfoFree (bi
);
3840 * remove bi and do export processing
3842 import_table
->holddown_count
[afi
] += 1;
3843 rfapiExpireVpnNow (import_table
, rn
, bi
, 0);
3852 RFAPI_CHECK_REFCOUNT (rn
, SAFI_MPLS_VPN
, replacing
? 1 : 0);
3854 if (action
== FIF_ACTION_WITHDRAW
|| action
== FIF_ACTION_KILL
)
3860 info_new
= rfapiBgpInfoCreate (attr
, peer
, rfd
, prd
, type
, sub_type
, label
);
3863 * lookup un address in encap table
3865 ern
= route_node_match (import_table
->imported_encap
[afi
], &vn_prefix
);
3868 rfapiCopyUnEncap2VPN (ern
->info
, info_new
);
3869 route_unlock_node (ern
); /* undo lock in route_note_match */
3874 prefix2str (&vn_prefix
, buf
, sizeof (buf
));
3875 buf
[BUFSIZ
- 1] = 0;
3876 /* Not a big deal, just means VPN route got here first */
3877 vnc_zlog_debug_verbose ("%s: no encap route for vn addr %s", __func__
, buf
);
3878 info_new
->extra
->vnc
.import
.un_family
= 0;
3884 route_lock_node (rn
);
3889 * No need to increment reference count, so only "get"
3890 * if the node is not there already
3892 rn
= route_node_get (rt
, p
);
3896 * For ethernet routes, if there is an accompanying IP address,
3899 if ((AFI_ETHER
== afi
) && aux_prefix
)
3902 vnc_zlog_debug_verbose ("%s: setting BI's aux_prefix", __func__
);
3903 info_new
->extra
->vnc
.import
.aux_prefix
= *aux_prefix
;
3906 vnc_zlog_debug_verbose ("%s: inserting bi %p at prefix %s/%d #%d",
3909 rfapi_ntop (rn
->p
.family
, &rn
->p
.u
.prefix
, buf
, BUFSIZ
),
3910 rn
->p
.prefixlen
, rn
->lock
);
3912 rfapiBgpInfoAttachSorted (rn
, info_new
, afi
, SAFI_MPLS_VPN
);
3913 rfapiItBiIndexAdd (rn
, info_new
);
3914 if (!rfapiGetUnAddrOfVpnBi (info_new
, NULL
))
3916 if (VALID_INTERIOR_TYPE (info_new
->type
))
3917 RFAPI_MONITOR_EXTERIOR (rn
)->valid_interior_count
++;
3918 SET_FLAG (info_new
->flags
, BGP_INFO_VALID
);
3920 RFAPI_UPDATE_ITABLE_COUNT (info_new
, import_table
, afi
, 1);
3921 vnc_import_bgp_exterior_add_route_interior (bgp
, import_table
, rn
,
3924 if (import_table
== bgp
->rfapi
->it_ce
)
3925 vnc_direct_bgp_add_route_ce (bgp
, rn
, info_new
);
3927 if (VNC_DEBUG(VERBOSE
))
3929 vnc_zlog_debug_verbose ("%s: showing IT node", __func__
);
3930 rfapiShowItNode (NULL
, rn
); /* debug */
3933 rfapiMonitorEncapAdd (import_table
, &vn_prefix
, rn
, info_new
);
3935 if (!rfapiGetUnAddrOfVpnBi (info_new
, &un_prefix
))
3939 * if we have a valid UN address (either via Encap route
3940 * or via tunnel attribute), then we should attempt
3941 * to move any monitors at less-specific nodes to this node
3943 rfapiMonitorMoveLonger (rn
);
3945 un_prefix_valid
= 1;
3950 * 101129 Enhancement: if we add a route (implication: it is not
3951 * in holddown), delete all other routes from this nve at this
3952 * node that are in holddown, regardless of peer.
3954 * Reasons it's OK to do that:
3956 * - if the holddown route being deleted originally came from BGP VPN,
3957 * it is already gone from BGP (implication of holddown), so there
3958 * won't be any added inconsistency with the BGP RIB.
3960 * - once a fresh route is added at a prefix, any routes in holddown
3961 * at that prefix will not show up in RFP responses, so deleting
3962 * the holddown routes won't affect the contents of responses.
3964 * - lifetimes are supposed to be consistent, so there should not
3965 * be a case where the fresh route has a shorter lifetime than
3966 * the holddown route, so we don't expect the fresh route to
3967 * disappear and complete its holddown time before the existing
3968 * holddown routes time out. Therefore, we won't have a situation
3969 * where we expect the existing holddown routes to be hidden and
3970 * then to reappear sometime later (as holddown routes) in a
3973 * Among other things, this would enable us to skirt the problem
3974 * of local holddown routes that refer to NVE descriptors that
3975 * have already been closed (if the same NVE triggers a subsequent
3976 * rfapi_open(), the new peer is different and doesn't match the
3977 * peer of the holddown route, so the stale holddown route still
3978 * hangs around until it times out instead of just being replaced
3979 * by the fresh route).
3982 * We know that the new bi will have been inserted before any routes
3983 * in holddown, so we can skip any that came before it
3985 for (bi
= info_new
->next
; bi
; bi
= next
)
3988 struct prefix pfx_vn
;
3989 struct prefix pfx_un
;
3991 int remote_peer_match
= 0;
3998 if (!CHECK_FLAG (bi
->flags
, BGP_INFO_REMOVED
))
4002 * Must match VN address (nexthop of VPN route)
4004 if (rfapiGetNexthop (bi
->attr
, &pfx_vn
))
4006 if (!prefix_same (&pfx_vn
, &vn_prefix
))
4009 if (un_prefix_valid
&& /* new route UN addr */
4010 !rfapiGetUnAddrOfVpnBi (bi
, &pfx_un
) && /* old route UN addr */
4011 prefix_same (&pfx_un
, &un_prefix
))
4015 if (!RFAPI_LOCAL_BI (bi
) && !RFAPI_LOCAL_BI (info_new
) &&
4016 sockunion_same (&bi
->peer
->su
, &info_new
->peer
->su
))
4018 /* old & new are both remote, same peer */
4019 remote_peer_match
= 1;
4022 if (!un_match
& !remote_peer_match
)
4025 vnc_zlog_debug_verbose ("%s: removing holddown bi matching NVE of new route",
4027 if (bi
->extra
->vnc
.import
.timer
)
4029 struct thread
*t
= (struct thread
*) bi
->extra
->vnc
.import
.timer
;
4030 struct rfapi_withdraw
*wcb
= t
->arg
;
4032 XFREE (MTYPE_RFAPI_WITHDRAW
, wcb
);
4035 rfapiExpireVpnNow (import_table
, rn
, bi
, 0);
4038 if (!original_had_routes
)
4041 * We went from 0 usable routes to 1 usable route. Perform the
4042 * "Adding a Route" export process.
4044 vnc_direct_bgp_add_prefix (bgp
, import_table
, rn
);
4045 vnc_zebra_add_prefix (bgp
, import_table
, rn
);
4050 * Check for nexthop change event
4051 * Note: the prefix_same() test below detects two situations:
4052 * 1. route is replaced, new route has different nexthop
4053 * 2. new route is added (original_nexthop is 0)
4055 struct prefix new_nexthop
;
4057 rfapiGetNexthop (attr
, &new_nexthop
);
4058 if (!prefix_same (&original_nexthop
, &new_nexthop
))
4061 * nexthop change event
4062 * vnc_direct_bgp_add_prefix() will recompute VN addr ecommunity
4064 vnc_direct_bgp_add_prefix (bgp
, import_table
, rn
);
4068 if (!(bgp
->rfapi_cfg
->flags
& BGP_VNC_CONFIG_CALLBACK_DISABLE
))
4070 for (n
= rn
; n
; n
= n
->parent
)
4072 //rfapiDoRouteCallback(import_table, n, NULL);
4074 rfapiMonitorItNodeChanged (import_table
, rn
, NULL
);
4076 RFAPI_CHECK_REFCOUNT (rn
, SAFI_MPLS_VPN
, 0);
4080 static rfapi_bi_filtered_import_f
*
4081 rfapiBgpInfoFilteredImportFunction (safi_t safi
)
4086 return rfapiBgpInfoFilteredImportVPN
;
4089 return rfapiBgpInfoFilteredImportEncap
;
4091 zlog_err ("%s: bad safi %d", __func__
, safi
);
4096 rfapiProcessUpdate (
4098 void *rfd
, /* set when looped from RFP/RFAPI */
4100 struct prefix_rd
*prd
,
4110 struct rfapi_import_table
*it
;
4111 int has_ip_route
= 1;
4114 bgp
= bgp_get_default (); /* assume 1 instance for now */
4121 * look at high-order byte of RD. FF means MAC
4122 * address is present (VNC L2VPN)
4124 if ((safi
== SAFI_MPLS_VPN
) &&
4125 (decode_rd_type(prd
->val
) == RD_TYPE_VNC_ETH
))
4127 struct prefix pfx_mac_buf
;
4128 struct prefix pfx_nexthop_buf
;
4132 * Set flag if prefix and nexthop are the same - don't
4133 * add the route to normal IP-based import tables
4135 if (!rfapiGetNexthop (attr
, &pfx_nexthop_buf
))
4137 if (!prefix_cmp (&pfx_nexthop_buf
, p
))
4143 memset (&pfx_mac_buf
, 0, sizeof (pfx_mac_buf
));
4144 pfx_mac_buf
.family
= AF_ETHERNET
;
4145 pfx_mac_buf
.prefixlen
= 48;
4146 memcpy (&pfx_mac_buf
.u
.prefix_eth
.octet
, prd
->val
+ 2, 6);
4149 * Find rt containing LNI (Logical Network ID), which
4150 * _should_ always be present when mac address is present
4152 rc
= rfapiEcommunityGetLNI (attr
->extra
->ecommunity
, &lni
);
4154 vnc_zlog_debug_verbose
4155 ("%s: rfapiEcommunityGetLNI returned %d, lni=%d, attr=%p, attr->extra=%p",
4156 __func__
, rc
, lni
, attr
, attr
->extra
);
4157 if (attr
&& attr
->extra
&& !rc
)
4159 it
= rfapiMacImportTableGet (bgp
, lni
);
4161 rfapiBgpInfoFilteredImportVPN (
4166 &pfx_mac_buf
, /* prefix */
4167 p
, /* aux prefix: IP addr */
4182 * Iterate over all import tables; do a filtered import
4183 * for the afi/safi combination
4185 for (it
= h
->imports
; it
; it
= it
->next
)
4187 (*rfapiBgpInfoFilteredImportFunction (safi
)) (
4202 if (safi
== SAFI_MPLS_VPN
)
4204 vnc_direct_bgp_rh_add_route (bgp
, afi
, p
, peer
, attr
);
4207 if (safi
== SAFI_MPLS_VPN
)
4209 rfapiBgpInfoFilteredImportVPN (
4227 rfapiProcessWithdraw (
4231 struct prefix_rd
*prd
,
4240 struct rfapi_import_table
*it
;
4242 bgp
= bgp_get_default (); /* assume 1 instance for now */
4249 * look at high-order byte of RD. FF means MAC
4250 * address is present (VNC L2VPN)
4252 if (h
->import_mac
!= NULL
&& safi
== SAFI_MPLS_VPN
&&
4253 decode_rd_type(prd
->val
) == RD_TYPE_VNC_ETH
)
4255 struct prefix pfx_mac_buf
;
4256 void *cursor
= NULL
;
4259 memset (&pfx_mac_buf
, 0, sizeof (pfx_mac_buf
));
4260 pfx_mac_buf
.family
= AF_ETHERNET
;
4261 pfx_mac_buf
.prefixlen
= 48;
4262 memcpy (&pfx_mac_buf
.u
.prefix_eth
, prd
->val
+ 2, 6);
4265 * withdraw does not contain attrs, so we don't have
4266 * access to the route's LNI, which would ordinarily
4267 * select the specific mac-based import table. Instead,
4268 * we must iterate over all mac-based tables and rely
4269 * on the RD to match.
4271 * If this approach is too slow, add an index where
4272 * key is {RD, peer} and value is the import table
4274 for (rc
= skiplist_next (h
->import_mac
, NULL
, (void **) &it
, &cursor
);
4276 rc
= skiplist_next (h
->import_mac
, NULL
, (void **) &it
, &cursor
))
4280 vnc_zlog_debug_verbose
4281 ("%s: calling rfapiBgpInfoFilteredImportVPN(it=%p, afi=AFI_ETHER)",
4285 rfapiBgpInfoFilteredImportVPN (
4287 (kill
? FIF_ACTION_KILL
: FIF_ACTION_WITHDRAW
),
4290 &pfx_mac_buf
, /* prefix */
4291 p
, /* aux_prefix: IP */
4297 NULL
); /* sub_type & label unused for withdraw */
4302 * XXX For the case where the withdraw involves an L2
4303 * route with no IP information, we rely on the lack
4304 * of RT-list intersection to filter out the withdraw
4305 * from the IP-based import tables below
4309 * Iterate over all import tables; do a filtered import
4310 * for the afi/safi combination
4313 for (it
= h
->imports
; it
; it
= it
->next
)
4315 (*rfapiBgpInfoFilteredImportFunction (safi
)) (
4317 (kill
? FIF_ACTION_KILL
: FIF_ACTION_WITHDRAW
),
4327 NULL
); /* sub_type & label unused for withdraw */
4330 /* TBD the deletion should happen after the lifetime expires */
4331 if (safi
== SAFI_MPLS_VPN
)
4332 vnc_direct_bgp_rh_del_route (bgp
, afi
, p
, peer
);
4334 if (safi
== SAFI_MPLS_VPN
)
4336 rfapiBgpInfoFilteredImportVPN (
4338 (kill
? FIF_ACTION_KILL
: FIF_ACTION_WITHDRAW
),
4348 NULL
); /* sub_type & label unused for withdraw */
4353 * TBD optimized withdraw timer algorithm for case of many
4354 * routes expiring at the same time due to peer drop.
4357 * 1. Visit all BIs in all ENCAP import tables.
4359 * a. If a bi's peer is the failed peer, remove the bi.
4360 * b. If the removed ENCAP bi was first in the list of
4361 * BIs at this ENCAP node, loop over all monitors
4364 * (1) for each ENCAP monitor, loop over all its
4365 * VPN node monitors and set their RFAPI_MON_FLAG_NEEDCALLBACK
4368 * 2. Visit all BIs in all VPN import tables.
4369 * a. If a bi's peer is the failed peer, remove the bi.
4370 * b. loop over all the VPN node monitors and set their
4371 * RFAPI_MON_FLAG_NEEDCALLBACK flags
4372 * c. If there are no BIs left at this VPN node,
4377 /* surprise, this gets called from peer_delete(), from rfapi_close() */
4379 rfapiProcessPeerDownRt (
4381 struct rfapi_import_table
*import_table
,
4385 struct route_node
*rn
;
4386 struct bgp_info
*bi
;
4387 struct route_table
*rt
;
4388 int (*timer_service_func
) (struct thread
*);
4390 assert (afi
== AFI_IP
|| afi
== AFI_IP6
);
4397 rt
= import_table
->imported_vpn
[afi
];
4398 timer_service_func
= rfapiWithdrawTimerVPN
;
4401 rt
= import_table
->imported_encap
[afi
];
4402 timer_service_func
= rfapiWithdrawTimerEncap
;
4409 for (rn
= route_top (rt
); rn
; rn
= route_next (rn
))
4411 for (bi
= rn
->info
; bi
; bi
= bi
->next
)
4413 if (bi
->peer
== peer
)
4416 if (CHECK_FLAG (bi
->flags
, BGP_INFO_REMOVED
))
4418 /* already in holddown, skip */
4422 if (safi
== SAFI_MPLS_VPN
)
4424 RFAPI_UPDATE_ITABLE_COUNT (bi
, import_table
, afi
, -1);
4425 import_table
->holddown_count
[afi
] += 1;
4427 rfapiBiStartWithdrawTimer (import_table
, rn
, bi
,
4429 timer_service_func
);
4437 * This gets called when a peer connection drops. We have to remove
4438 * all the routes from this peer.
4440 * Current approach is crude. TBD Optimize by setting fewer timers and
4441 * grouping withdrawn routes so we can generate callbacks more
4445 rfapiProcessPeerDown (struct peer
*peer
)
4449 struct rfapi_import_table
*it
;
4452 * If this peer is a "dummy" peer structure atached to a RFAPI
4453 * nve_descriptor, we don't need to walk the import tables
4454 * because the routes are already withdrawn by rfapi_close()
4456 if (CHECK_FLAG (peer
->flags
, PEER_FLAG_IS_RFAPI_HD
))
4460 * 1. Visit all BIs in all ENCAP import tables.
4461 * Start withdraw timer on the BIs that match peer.
4463 * 2. Visit All BIs in all VPN import tables.
4464 * Start withdraw timer on the BIs that match peer.
4467 bgp
= bgp_get_default (); /* assume 1 instance for now */
4474 for (it
= h
->imports
; it
; it
= it
->next
)
4476 rfapiProcessPeerDownRt (peer
, it
, AFI_IP
, SAFI_ENCAP
);
4477 rfapiProcessPeerDownRt (peer
, it
, AFI_IP6
, SAFI_ENCAP
);
4478 rfapiProcessPeerDownRt (peer
, it
, AFI_IP
, SAFI_MPLS_VPN
);
4479 rfapiProcessPeerDownRt (peer
, it
, AFI_IP6
, SAFI_MPLS_VPN
);
4484 rfapiProcessPeerDownRt (peer
, h
->it_ce
, AFI_IP
, SAFI_MPLS_VPN
);
4485 rfapiProcessPeerDownRt (peer
, h
->it_ce
, AFI_IP6
, SAFI_MPLS_VPN
);
4490 * Import an entire RIB (for an afi/safi) to an import table RIB,
4491 * filtered according to the import table's RT list
4493 * TBD: does this function need additions to match rfapiProcessUpdate()
4494 * for, e.g., L2 handling?
4497 rfapiBgpTableFilteredImport (
4499 struct rfapi_import_table
*it
,
4503 struct bgp_node
*rn1
;
4504 struct bgp_node
*rn2
;
4506 /* Only these SAFIs have 2-level RIBS */
4507 assert (safi
== SAFI_MPLS_VPN
|| safi
== SAFI_ENCAP
);
4510 * Now visit all the rd nodes and the nodes of all the
4511 * route tables attached to them, and import the routes
4512 * if they have matching route targets
4514 for (rn1
= bgp_table_top (bgp
->rib
[afi
][safi
]);
4515 rn1
; rn1
= bgp_route_next (rn1
))
4520 for (rn2
= bgp_table_top (rn1
->info
);
4521 rn2
; rn2
= bgp_route_next (rn2
))
4524 struct bgp_info
*bi
;
4526 for (bi
= rn2
->info
; bi
; bi
= bi
->next
)
4528 u_int32_t label
= 0;
4530 if (CHECK_FLAG (bi
->flags
, BGP_INFO_REMOVED
))
4534 label
= decode_label (bi
->extra
->tag
);
4535 (*rfapiBgpInfoFilteredImportFunction (safi
)) (
4536 it
, /* which import table */
4540 &rn2
->p
, /* prefix */
4543 (struct prefix_rd
*) &rn1
->p
,
4555 /* per-bgp-instance rfapi data */
4557 bgp_rfapi_new (struct bgp
*bgp
)
4561 struct rfapi_rfp_cfg
*cfg
= NULL
;
4562 struct rfapi_rfp_cb_methods
*cbm
= NULL
;
4564 assert (bgp
->rfapi_cfg
== NULL
);
4566 h
= (struct rfapi
*) XCALLOC (MTYPE_RFAPI
, sizeof (struct rfapi
));
4568 for (afi
= AFI_IP
; afi
< AFI_MAX
; afi
++)
4570 /* ugly, to deal with addition of delegates, part of 0.99.24.1 merge */
4571 h
->un
[afi
].delegate
= route_table_get_default_delegate ();
4575 * initialize the ce import table
4578 XCALLOC (MTYPE_RFAPI_IMPORTTABLE
, sizeof (struct rfapi_import_table
));
4579 h
->it_ce
->imported_vpn
[AFI_IP
] = route_table_init ();
4580 h
->it_ce
->imported_vpn
[AFI_IP6
] = route_table_init ();
4581 h
->it_ce
->imported_encap
[AFI_IP
] = route_table_init ();
4582 h
->it_ce
->imported_encap
[AFI_IP6
] = route_table_init ();
4583 rfapiBgpTableFilteredImport (bgp
, h
->it_ce
, AFI_IP
, SAFI_MPLS_VPN
);
4584 rfapiBgpTableFilteredImport (bgp
, h
->it_ce
, AFI_IP6
, SAFI_MPLS_VPN
);
4587 * Set up work queue for deferred rfapi_close operations
4589 h
->deferred_close_q
= work_queue_new (bm
->master
, "rfapi deferred close");
4590 h
->deferred_close_q
->spec
.workfunc
= rfapi_deferred_close_workfunc
;
4591 h
->deferred_close_q
->spec
.data
= h
;
4593 h
->rfp
= rfp_start (bm
->master
, &cfg
, &cbm
);
4594 bgp
->rfapi_cfg
= bgp_rfapi_cfg_new (cfg
);
4597 h
->rfp_methods
= *cbm
;
4603 bgp_rfapi_destroy (struct bgp
*bgp
, struct rfapi
*h
)
4605 if (bgp
== NULL
|| h
== NULL
)
4608 if (h
->resolve_nve_nexthop
)
4610 skiplist_free (h
->resolve_nve_nexthop
);
4611 h
->resolve_nve_nexthop
= NULL
;
4614 route_table_finish (h
->it_ce
->imported_vpn
[AFI_IP
]);
4615 route_table_finish (h
->it_ce
->imported_vpn
[AFI_IP6
]);
4616 route_table_finish (h
->it_ce
->imported_encap
[AFI_IP
]);
4617 route_table_finish (h
->it_ce
->imported_encap
[AFI_IP6
]);
4621 struct rfapi_import_table
*it
;
4626 rc
= skiplist_next (h
->import_mac
, NULL
, (void **) &it
, &cursor
);
4628 rc
= skiplist_next (h
->import_mac
, NULL
, (void **) &it
, &cursor
))
4631 rfapiImportTableFlush (it
);
4632 XFREE (MTYPE_RFAPI_IMPORTTABLE
, it
);
4634 skiplist_free (h
->import_mac
);
4635 h
->import_mac
= NULL
;
4638 work_queue_free (h
->deferred_close_q
);
4642 XFREE (MTYPE_RFAPI_IMPORTTABLE
, h
->it_ce
);
4643 XFREE (MTYPE_RFAPI
, h
);
4646 struct rfapi_import_table
*
4647 rfapiImportTableRefAdd (struct bgp
*bgp
, struct ecommunity
*rt_import_list
)
4650 struct rfapi_import_table
*it
;
4656 for (it
= h
->imports
; it
; it
= it
->next
)
4658 if (ecommunity_cmp (it
->rt_import_list
, rt_import_list
))
4662 vnc_zlog_debug_verbose ("%s: matched it=%p", __func__
, it
);
4667 XCALLOC (MTYPE_RFAPI_IMPORTTABLE
, sizeof (struct rfapi_import_table
));
4669 it
->next
= h
->imports
;
4672 it
->rt_import_list
= ecommunity_dup (rt_import_list
);
4673 it
->monitor_exterior_orphans
=
4674 skiplist_new (0, NULL
, (void (*)(void *)) prefix_free
);
4677 * fill import route tables from RIBs
4679 * Potential area for optimization. If this occurs when
4680 * tables are large (e.g., the operator adds a nve group
4681 * with a new RT list to a running system), it could take
4685 for (afi
= AFI_IP
; afi
< AFI_MAX
; ++afi
)
4688 it
->imported_vpn
[afi
] = route_table_init ();
4689 it
->imported_encap
[afi
] = route_table_init ();
4691 rfapiBgpTableFilteredImport (bgp
, it
, afi
, SAFI_MPLS_VPN
);
4692 rfapiBgpTableFilteredImport (bgp
, it
, afi
, SAFI_ENCAP
);
4694 vnc_import_bgp_exterior_redist_enable_it (bgp
, afi
, it
);
4704 * skiplist element free function
4707 delete_rem_pfx_na_free (void *na
)
4709 uint32_t *pCounter
= ((struct rfapi_nve_addr
*) na
)->info
;
4712 XFREE (MTYPE_RFAPI_NVE_ADDR
, na
);
4716 * Common deleter for IP and MAC import tables
4719 rfapiDeleteRemotePrefixesIt (
4721 struct rfapi_import_table
*it
,
4726 int delete_holddown
,
4731 struct skiplist
*uniq_active_nves
,
4732 struct skiplist
*uniq_holddown_nves
)
4738 char buf_pfx
[BUFSIZ
];
4742 prefix2str (p
, buf_pfx
, BUFSIZ
);
4750 vnc_zlog_debug_verbose ("%s: entry, p=%s, delete_active=%d, delete_holddown=%d",
4751 __func__
, buf_pfx
, delete_active
, delete_holddown
);
4755 for (afi
= AFI_IP
; afi
< AFI_MAX
; ++afi
)
4758 struct route_table
*rt
;
4759 struct route_node
*rn
;
4761 if (p
&& (family2afi (p
->family
) != afi
))
4766 rt
= it
->imported_vpn
[afi
];
4770 vnc_zlog_debug_verbose ("%s: scanning rt for afi=%d", __func__
, afi
);
4772 for (rn
= route_top (rt
); rn
; rn
= route_next (rn
))
4774 struct bgp_info
*bi
;
4775 struct bgp_info
*next
;
4777 if (VNC_DEBUG(IMPORT_DEL_REMOTE
))
4779 char p1line
[BUFSIZ
];
4780 char p2line
[BUFSIZ
];
4782 prefix2str (p
, p1line
, BUFSIZ
);
4783 prefix2str (&rn
->p
, p2line
, BUFSIZ
);
4784 vnc_zlog_debug_any ("%s: want %s, have %s", __func__
, p1line
, p2line
);
4787 if (p
&& prefix_cmp (p
, &rn
->p
))
4791 char buf_pfx
[BUFSIZ
];
4792 prefix2str (&rn
->p
, buf_pfx
, BUFSIZ
);
4793 vnc_zlog_debug_verbose ("%s: rn pfx=%s", __func__
, buf_pfx
);
4796 /* TBD is this valid for afi == AFI_ETHER? */
4797 RFAPI_CHECK_REFCOUNT (rn
, SAFI_MPLS_VPN
, 1);
4799 for (bi
= rn
->info
; bi
; bi
= next
)
4809 vnc_zlog_debug_verbose ("%s: examining bi %p", __func__
, bi
);
4813 if (!rfapiGetNexthop (bi
->attr
, &qpt
))
4818 if (!qpt_valid
|| !prefix_match (vn
, &qpt
))
4821 vnc_zlog_debug_verbose
4822 ("%s: continue at vn && !qpt_valid || !prefix_match(vn, &qpt)",
4829 if (!rfapiGetUnAddrOfVpnBi (bi
, &qct
))
4834 if (!qct_valid
|| !prefix_match (un
, &qct
))
4837 vnc_zlog_debug_verbose
4838 ("%s: continue at un && !qct_valid || !prefix_match(un, &qct)",
4850 * If this route is waiting to be deleted because of
4851 * a previous withdraw, we must cancel its timer.
4853 if (CHECK_FLAG (bi
->flags
, BGP_INFO_REMOVED
))
4855 if (!delete_holddown
)
4857 if (bi
->extra
->vnc
.import
.timer
)
4861 (struct thread
*) bi
->extra
->vnc
.import
.timer
;
4862 struct rfapi_withdraw
*wcb
= t
->arg
;
4864 wcb
->import_table
->holddown_count
[afi
] -= 1;
4865 RFAPI_UPDATE_ITABLE_COUNT (bi
, wcb
->import_table
, afi
,
4867 XFREE (MTYPE_RFAPI_WITHDRAW
, wcb
);
4878 vnc_zlog_debug_verbose
4879 ("%s: deleting bi %p (qct_valid=%d, qpt_valid=%d, delete_holddown=%d, delete_active=%d)",
4880 __func__
, bi
, qct_valid
, qpt_valid
, delete_holddown
,
4887 if (qct_valid
&& qpt_valid
)
4890 struct rfapi_nve_addr na
;
4891 struct rfapi_nve_addr
*nap
;
4893 memset (&na
, 0, sizeof (na
));
4894 assert (!rfapiQprefix2Raddr (&qct
, &na
.un
));
4895 assert (!rfapiQprefix2Raddr (&qpt
, &na
.vn
));
4897 if (skiplist_search ((is_active
? uniq_active_nves
:
4898 uniq_holddown_nves
), &na
,
4903 nap
= XCALLOC (MTYPE_RFAPI_NVE_ADDR
,
4904 sizeof (struct rfapi_nve_addr
));
4907 nap
->info
= is_active
? pAHcount
: pHHcount
;
4908 skiplist_insert ((is_active
? uniq_active_nves
:
4909 uniq_holddown_nves
), nap
, nap
);
4911 rfapiNveAddr2Str (nap
, line
, BUFSIZ
);
4915 vnc_direct_bgp_rh_del_route (bgp
, afi
, &rn
->p
, bi
->peer
);
4917 RFAPI_UPDATE_ITABLE_COUNT (bi
, it
, afi
, -1);
4918 it
->holddown_count
[afi
] += 1;
4919 rfapiExpireVpnNow (it
, rn
, bi
, 1);
4921 vnc_zlog_debug_verbose ("%s: incrementing count (is_active=%d)",
4922 __func__
, is_active
);
4935 * For use by the "clear vnc prefixes" command
4937 /*------------------------------------------
4938 * rfapiDeleteRemotePrefixes
4940 * UI helper: For use by the "clear vnc prefixes" command
4943 * un if set, tunnel must match this prefix
4944 * vn if set, nexthop prefix must match this prefix
4945 * p if set, prefix must match this prefix
4946 * it if set, only look in this import table
4949 * pARcount number of active routes deleted
4950 * pAHcount number of active nves deleted
4951 * pHRcount number of holddown routes deleted
4952 * pHHcount number of holddown nves deleted
4956 --------------------------------------------*/
4958 rfapiDeleteRemotePrefixes (
4962 struct rfapi_import_table
*arg_it
,
4964 int delete_holddown
,
4972 struct rfapi_import_table
*it
;
4973 uint32_t deleted_holddown_route_count
= 0;
4974 uint32_t deleted_active_route_count
= 0;
4975 uint32_t deleted_holddown_nve_count
= 0;
4976 uint32_t deleted_active_nve_count
= 0;
4977 struct skiplist
*uniq_holddown_nves
;
4978 struct skiplist
*uniq_active_nves
;
4982 bgp
= bgp_get_default (); /* assume 1 instance for now */
4983 /* If no bgp instantiated yet, no vnc prefixes exist */
4990 uniq_holddown_nves
=
4991 skiplist_new (0, rfapi_nve_addr_cmp
, delete_rem_pfx_na_free
);
4993 skiplist_new (0, rfapi_nve_addr_cmp
, delete_rem_pfx_na_free
);
4996 * Iterate over all import tables; do a filtered import
4997 * for the afi/safi combination
5007 vnc_zlog_debug_verbose
5008 ("%s: calling rfapiDeleteRemotePrefixesIt() on (IP) import %p",
5011 rfapiDeleteRemotePrefixesIt (
5019 &deleted_active_route_count
,
5020 &deleted_active_nve_count
,
5021 &deleted_holddown_route_count
,
5022 &deleted_holddown_nve_count
,
5024 uniq_holddown_nves
);
5033 * Now iterate over L2 import tables
5035 if (h
->import_mac
&& !(p
&& (p
->family
!= AF_ETHERNET
)))
5038 void *cursor
= NULL
;
5042 rc
= skiplist_next (h
->import_mac
, NULL
, (void **) &it
, &cursor
);
5044 rc
= skiplist_next (h
->import_mac
, NULL
, (void **) &it
, &cursor
))
5047 vnc_zlog_debug_verbose
5048 ("%s: calling rfapiDeleteRemotePrefixesIt() on import_mac %p",
5051 rfapiDeleteRemotePrefixesIt (
5059 &deleted_active_route_count
,
5060 &deleted_active_nve_count
,
5061 &deleted_holddown_route_count
,
5062 &deleted_holddown_nve_count
,
5064 uniq_holddown_nves
);
5069 * our custom element freeing function above counts as it deletes
5071 skiplist_free (uniq_holddown_nves
);
5072 skiplist_free (uniq_active_nves
);
5075 *pARcount
= deleted_active_route_count
;
5077 *pAHcount
= deleted_active_nve_count
;
5079 *pHRcount
= deleted_holddown_route_count
;
5081 *pHHcount
= deleted_holddown_nve_count
;
5086 /*------------------------------------------
5087 * rfapiCountRemoteRoutes
5089 * UI helper: count VRF routes from BGP side
5094 * pALRcount count of active local routes
5095 * pARRcount count of active remote routes
5096 * pHRcount count of holddown routes
5097 * pIRcount count of direct imported routes
5101 --------------------------------------------*/
5103 rfapiCountAllItRoutes (int *pALRcount
, /* active local routes */
5104 int *pARRcount
, /* active remote routes */
5105 int *pHRcount
, /* holddown routes */
5106 int *pIRcount
) /* imported routes */
5110 struct rfapi_import_table
*it
;
5113 int total_active_local
= 0;
5114 int total_active_remote
= 0;
5115 int total_holddown
= 0;
5116 int total_imported
= 0;
5118 bgp
= bgp_get_default (); /* assume 1 instance for now */
5125 * Iterate over all import tables; do a filtered import
5126 * for the afi/safi combination
5129 for (it
= h
->imports
; it
; it
= it
->next
)
5132 for (afi
= AFI_IP
; afi
< AFI_MAX
; ++afi
)
5135 total_active_local
+= it
->local_count
[afi
];
5136 total_active_remote
+= it
->remote_count
[afi
];
5137 total_holddown
+= it
->holddown_count
[afi
];
5138 total_imported
+= it
->imported_count
[afi
];
5149 rc
= skiplist_next (h
->import_mac
, NULL
, (void **) &it
, &cursor
);
5151 rc
= skiplist_next (h
->import_mac
, NULL
, (void **) &it
, &cursor
))
5154 total_active_local
+= it
->local_count
[AFI_ETHER
];
5155 total_active_remote
+= it
->remote_count
[AFI_ETHER
];
5156 total_holddown
+= it
->holddown_count
[AFI_ETHER
];
5157 total_imported
+= it
->imported_count
[AFI_ETHER
];
5165 *pALRcount
= total_active_local
;
5169 *pARRcount
= total_active_remote
;
5173 *pHRcount
= total_holddown
;
5177 *pIRcount
= total_imported
;
5181 /*------------------------------------------
5182 * rfapiGetHolddownFromLifetime
5184 * calculate holddown value based on lifetime
5190 * Holddown value based on lifetime, holddown_factor,
5191 * and RFAPI_LIFETIME_INFINITE_WITHDRAW_DELAY
5193 --------------------------------------------*/
5194 /* hold down time maxes out at RFAPI_LIFETIME_INFINITE_WITHDRAW_DELAY */
5196 rfapiGetHolddownFromLifetime (uint32_t lifetime
)
5201 bgp
= bgp_get_default ();
5202 if (bgp
&& bgp
->rfapi_cfg
)
5203 factor
= bgp
->rfapi_cfg
->rfp_cfg
.holddown_factor
;
5205 factor
= RFAPI_RFP_CFG_DEFAULT_HOLDDOWN_FACTOR
;
5207 if (factor
< 100 || lifetime
< RFAPI_LIFETIME_INFINITE_WITHDRAW_DELAY
)
5208 lifetime
= lifetime
* factor
/ 100;
5209 if (lifetime
< RFAPI_LIFETIME_INFINITE_WITHDRAW_DELAY
)
5212 return RFAPI_LIFETIME_INFINITE_WITHDRAW_DELAY
;