3 * Copyright 2009-2016, LabN Consulting, L.L.C.
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 * File: rfapi_import.c
23 * Purpose: Handle import of routes from BGP to RFAPI
28 #include "lib/zebra.h"
29 #include "lib/prefix.h"
30 #include "lib/table.h"
32 #include "lib/memory.h"
34 #include "lib/skiplist.h"
35 #include "lib/thread.h"
37 #include "bgpd/bgpd.h"
38 #include "bgpd/bgp_ecommunity.h"
39 #include "bgpd/bgp_attr.h"
40 #include "bgpd/bgp_route.h"
41 #include "bgpd/bgp_mplsvpn.h" /* prefix_rd2str() */
42 #include "bgpd/bgp_vnc_types.h"
44 #include "bgpd/rfapi/rfapi.h"
45 #include "bgpd/rfapi/bgp_rfapi_cfg.h"
46 #include "bgpd/rfapi/rfapi_backend.h"
47 #include "bgpd/rfapi/rfapi_import.h"
48 #include "bgpd/rfapi/rfapi_private.h"
49 #include "bgpd/rfapi/rfapi_monitor.h"
50 #include "bgpd/rfapi/rfapi_nve_addr.h"
51 #include "bgpd/rfapi/rfapi_vty.h"
52 #include "bgpd/rfapi/vnc_export_bgp.h"
53 #include "bgpd/rfapi/vnc_export_bgp_p.h"
54 #include "bgpd/rfapi/vnc_zebra.h"
55 #include "bgpd/rfapi/vnc_import_bgp.h"
56 #include "bgpd/rfapi/vnc_import_bgp_p.h"
57 #include "bgpd/rfapi/rfapi_rib.h"
58 #include "bgpd/rfapi/rfapi_encap_tlv.h"
59 #include "bgpd/rfapi/vnc_debug.h"
61 #ifdef HAVE_GLIBC_BACKTRACE
62 /* for backtrace and friends */
64 #endif /* HAVE_GLIBC_BACKTRACE */
66 #undef DEBUG_MONITOR_MOVE_SHORTER
67 #undef DEBUG_RETURNED_NHL
68 #undef DEBUG_ROUTE_COUNTERS
69 #undef DEBUG_ENCAP_MONITOR
72 #undef DEBUG_BI_SEARCH
75 * Allocated for each withdraw timer instance; freed when the timer
76 * expires or is canceled
80 struct rfapi_import_table
*import_table
;
81 struct route_node
*node
;
82 struct bgp_info
*info
;
83 safi_t safi
; /* used only for bulk operations */
85 * For import table node reference count checking (i.e., debugging).
86 * Normally when a timer expires, lockoffset should be 0. However, if
87 * the timer expiration function is called directly (e.g.,
88 * rfapiExpireVpnNow), the node could be locked by a preceding
89 * route_top() or route_next() in a loop, so we need to pass this
97 * It's evil and fiendish. It's compiler-dependent.
98 * ? Might need LDFLAGS -rdynamic to produce all function names
101 rfapiDebugBacktrace (void)
103 #ifdef HAVE_GLIBC_BACKTRACE
104 #define RFAPI_DEBUG_BACKTRACE_NENTRIES 200
105 void *buf
[RFAPI_DEBUG_BACKTRACE_NENTRIES
];
110 size
= backtrace (buf
, RFAPI_DEBUG_BACKTRACE_NENTRIES
);
111 syms
= backtrace_symbols (buf
, size
);
113 for (i
= 0; i
< size
&& i
< RFAPI_DEBUG_BACKTRACE_NENTRIES
; ++i
)
115 vnc_zlog_debug_verbose ("backtrace[%2zu]: %s", i
, syms
[i
]);
125 * Count remote routes and compare with actively-maintained values.
126 * Abort if they disagree.
129 rfapiCheckRouteCount ()
131 struct bgp
*bgp
= bgp_get_default ();
133 struct rfapi_import_table
*it
;
141 for (it
= h
->imports
; it
; it
= it
->next
)
143 for (afi
= AFI_IP
; afi
< AFI_MAX
; ++afi
)
146 struct route_table
*rt
;
147 struct route_node
*rn
;
149 int holddown_count
= 0;
151 int imported_count
= 0;
152 int remote_count
= 0;
154 rt
= it
->imported_vpn
[afi
];
156 for (rn
= route_top (rt
); rn
; rn
= route_next (rn
))
159 struct bgp_info
*next
;
161 for (bi
= rn
->info
; bi
; bi
= next
)
165 if (CHECK_FLAG (bi
->flags
, BGP_INFO_REMOVED
))
172 if (RFAPI_LOCAL_BI (bi
))
178 if (RFAPI_DIRECT_IMPORT_BI (bi
))
191 if (it
->holddown_count
[afi
] != holddown_count
)
193 vnc_zlog_debug_verbose ("%s: it->holddown_count %d != holddown_count %d",
194 __func__
, it
->holddown_count
[afi
], holddown_count
);
197 if (it
->remote_count
[afi
] != remote_count
)
199 vnc_zlog_debug_verbose ("%s: it->remote_count %d != remote_count %d",
200 __func__
, it
->remote_count
[afi
], remote_count
);
203 if (it
->imported_count
[afi
] != imported_count
)
205 vnc_zlog_debug_verbose ("%s: it->imported_count %d != imported_count %d",
206 __func__
, it
->imported_count
[afi
], imported_count
);
213 #if DEBUG_ROUTE_COUNTERS
214 #define VNC_ITRCCK do {rfapiCheckRouteCount();} while (0)
220 * Validate reference count for a node in an import table
222 * Normally lockoffset is 0 for nodes in quiescent state. However,
223 * route_unlock_node will delete the node if it is called when
224 * node->lock == 1, and we have to validate the refcount before
225 * the node is deleted. In this case, we specify lockoffset 1.
228 rfapiCheckRefcount (struct route_node
*rn
, safi_t safi
, int lockoffset
)
230 unsigned int count_bi
= 0;
231 unsigned int count_monitor
= 0;
233 struct rfapi_monitor_encap
*hme
;
234 struct rfapi_monitor_vpn
*hmv
;
236 for (bi
= rn
->info
; bi
; bi
= bi
->next
)
242 ++count_monitor
; /* rfapi_it_extra */
250 for (hme
= RFAPI_MONITOR_ENCAP (rn
); hme
; hme
= hme
->next
)
256 for (hmv
= RFAPI_MONITOR_VPN (rn
); hmv
; hmv
= hmv
->next
)
259 if (RFAPI_MONITOR_EXTERIOR (rn
)->source
)
261 ++count_monitor
; /* sl */
263 for (rc
= skiplist_next (RFAPI_MONITOR_EXTERIOR (rn
)->source
,
264 NULL
, NULL
, &cursor
);
266 rc
= skiplist_next (RFAPI_MONITOR_EXTERIOR (rn
)->source
,
267 NULL
, NULL
, &cursor
))
270 ++count_monitor
; /* sl entry */
280 if (count_bi
+ count_monitor
+ lockoffset
!= rn
->lock
)
282 vnc_zlog_debug_verbose
283 ("%s: count_bi=%d, count_monitor=%d, lockoffset=%d, rn->lock=%d",
284 __func__
, count_bi
, count_monitor
, lockoffset
, rn
->lock
);
290 * Perform deferred rfapi_close operations that were queued
293 static wq_item_status
294 rfapi_deferred_close_workfunc (struct work_queue
*q
, void *data
)
296 struct rfapi_descriptor
*rfd
= data
;
297 struct rfapi
*h
= q
->spec
.data
;
299 assert (!(h
->flags
& RFAPI_INCALLBACK
));
301 vnc_zlog_debug_verbose ("%s: completed deferred close on handle %p", __func__
, rfd
);
306 * Extract layer 2 option from Encap TLVS in BGP attrs
309 rfapiGetL2o (struct attr
*attr
, struct rfapi_l2address_option
*l2o
)
311 if (attr
&& attr
->extra
)
314 struct bgp_attr_encap_subtlv
*pEncap
;
316 for (pEncap
= attr
->extra
->vnc_subtlvs
; pEncap
; pEncap
= pEncap
->next
)
319 if (pEncap
->type
== BGP_VNC_SUBTLV_TYPE_RFPOPTION
)
321 if (pEncap
->value
[0] == RFAPI_VN_OPTION_TYPE_L2ADDR
)
324 if (pEncap
->value
[1] == 14)
326 memcpy (l2o
->macaddr
.octet
, pEncap
->value
+ 2,
329 ((pEncap
->value
[10] >> 4) & 0x0f) +
330 ((pEncap
->value
[9] << 4) & 0xff0) +
331 ((pEncap
->value
[8] << 12) & 0xff000);
333 l2o
->local_nve_id
= pEncap
->value
[12];
335 l2o
->logical_net_id
=
336 (pEncap
->value
[15] & 0xff) +
337 ((pEncap
->value
[14] << 8) & 0xff00) +
338 ((pEncap
->value
[13] << 16) & 0xff0000);
351 * Extract the lifetime from the Tunnel Encap attribute of a route in
355 rfapiGetVncLifetime (struct attr
*attr
, uint32_t * lifetime
)
357 struct bgp_attr_encap_subtlv
*pEncap
;
359 *lifetime
= RFAPI_INFINITE_LIFETIME
; /* default to infinite */
361 if (attr
&& attr
->extra
)
364 for (pEncap
= attr
->extra
->vnc_subtlvs
; pEncap
; pEncap
= pEncap
->next
)
367 if (pEncap
->type
== BGP_VNC_SUBTLV_TYPE_LIFETIME
)
369 if (pEncap
->length
== 4)
371 memcpy (lifetime
, pEncap
->value
, 4);
372 *lifetime
= ntohl (*lifetime
);
383 * Extract the tunnel type from the extended community
386 rfapiGetTunnelType (struct attr
*attr
,
387 bgp_encap_types
*type
)
389 *type
= BGP_ENCAP_TYPE_MPLS
; /* default to MPLS */
390 if (attr
&& attr
->extra
&& attr
->extra
->ecommunity
)
392 struct ecommunity
*ecom
= attr
->extra
->ecommunity
;
395 for (i
= 0; i
< (ecom
->size
* ECOMMUNITY_SIZE
); i
+= ECOMMUNITY_SIZE
)
400 if (ep
[0] == ECOMMUNITY_ENCODE_OPAQUE
&&
401 ep
[1] == ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP
)
403 *type
= (ep
[6]<<8) + ep
[7];
414 * Look for UN address in Encap attribute
417 rfapiGetVncTunnelUnAddr (struct attr
*attr
, struct prefix
*p
)
419 struct bgp_attr_encap_subtlv
*pEncap
;
420 bgp_encap_types tun_type
;
422 rfapiGetTunnelType (attr
, &tun_type
);
423 if (tun_type
== BGP_ENCAP_TYPE_MPLS
)
427 /* MPLS carries UN address in next hop */
428 rfapiNexthop2Prefix (attr
, p
);
434 if (attr
&& attr
->extra
)
436 for (pEncap
= attr
->extra
->encap_subtlvs
; pEncap
; pEncap
= pEncap
->next
)
439 if (pEncap
->type
== BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT
)
441 switch (pEncap
->length
)
448 memcpy (p
->u
.val
, pEncap
->value
, 4);
455 p
->family
= AF_INET6
;
457 memcpy (p
->u
.val
, pEncap
->value
, 16);
469 * Get UN address wherever it might be
472 rfapiGetUnAddrOfVpnBi (struct bgp_info
*bi
, struct prefix
*p
)
474 /* If it's in this route's VNC attribute, we're done */
475 if (!rfapiGetVncTunnelUnAddr (bi
->attr
, p
))
478 * Otherwise, see if it's cached from a corresponding ENCAP SAFI
483 switch (bi
->extra
->vnc
.import
.un_family
)
488 p
->family
= bi
->extra
->vnc
.import
.un_family
;
489 p
->u
.prefix4
= bi
->extra
->vnc
.import
.un
.addr4
;
496 p
->family
= bi
->extra
->vnc
.import
.un_family
;
497 p
->u
.prefix6
= bi
->extra
->vnc
.import
.un
.addr6
;
504 #if DEBUG_ENCAP_MONITOR
505 vnc_zlog_debug_verbose ("%s: bi->extra->vnc.import.un_family is 0, no UN addr",
517 * Make a new bgp_info from gathered parameters
519 static struct bgp_info
*
524 struct prefix_rd
*prd
,
529 struct bgp_info
*new;
531 new = bgp_info_new ();
537 new->attr
= bgp_attr_intern (attr
);
539 bgp_info_extra_get (new);
542 new->extra
->vnc
.import
.rd
= *prd
;
543 rfapi_time (&new->extra
->vnc
.import
.create_time
);
546 encode_label (*label
, new->extra
->tag
);
548 new->sub_type
= sub_type
;
556 * Frees bgp_info as used in import tables (parts are not
557 * allocated exactly the way they are in the main RIBs)
560 rfapiBgpInfoFree (struct bgp_info
*goner
)
567 vnc_zlog_debug_verbose ("%s: calling peer_unlock(%p), #%d",
568 __func__
, goner
->peer
, goner
->peer
->lock
);
569 peer_unlock (goner
->peer
);
574 bgp_attr_unintern (&goner
->attr
);
578 assert (!goner
->extra
->damp_info
); /* Not used in import tbls */
579 XFREE (MTYPE_BGP_ROUTE_EXTRA
, goner
->extra
);
582 XFREE (MTYPE_BGP_ROUTE
, goner
);
585 struct rfapi_import_table
*
586 rfapiMacImportTableGetNoAlloc (struct bgp
*bgp
, uint32_t lni
)
589 struct rfapi_import_table
*it
= NULL
;
590 uintptr_t lni_as_ptr
= lni
;
599 if (skiplist_search (h
->import_mac
, (void *) lni_as_ptr
, (void **) &it
))
605 struct rfapi_import_table
*
606 rfapiMacImportTableGet (struct bgp
*bgp
, uint32_t lni
)
609 struct rfapi_import_table
*it
= NULL
;
610 uintptr_t lni_as_ptr
= lni
;
617 /* default cmp is good enough for LNI */
618 h
->import_mac
= skiplist_new (0, NULL
, NULL
);
621 if (skiplist_search (h
->import_mac
, (void *) lni_as_ptr
, (void **) &it
))
624 struct ecommunity
*enew
;
625 struct ecommunity_val eval
;
629 XCALLOC (MTYPE_RFAPI_IMPORTTABLE
, sizeof (struct rfapi_import_table
));
630 /* set RT list of new import table based on LNI */
631 memset ((char *) &eval
, 0, sizeof (eval
));
632 eval
.val
[0] = 0; /* VNC L2VPN */
633 eval
.val
[1] = 2; /* VNC L2VPN */
634 eval
.val
[5] = (lni
>> 16) & 0xff;
635 eval
.val
[6] = (lni
>> 8) & 0xff;
636 eval
.val
[7] = (lni
>> 0) & 0xff;
638 enew
= ecommunity_new ();
639 ecommunity_add_val (enew
, &eval
);
640 it
->rt_import_list
= enew
;
642 for (afi
= AFI_IP
; afi
< AFI_MAX
; ++afi
)
644 it
->imported_vpn
[afi
] = route_table_init ();
645 it
->imported_encap
[afi
] = route_table_init ();
648 it
->l2_logical_net_id
= lni
;
650 skiplist_insert (h
->import_mac
, (void *) lni_as_ptr
, it
);
658 * Implement MONITOR_MOVE_SHORTER(original_node) from
659 * RFAPI-Import-Event-Handling.txt
661 * Returns pointer to the list of moved monitors
663 static struct rfapi_monitor_vpn
*
664 rfapiMonitorMoveShorter (struct route_node
*original_vpn_node
, int lockoffset
)
667 struct route_node
*par
;
668 struct rfapi_monitor_vpn
*m
;
669 struct rfapi_monitor_vpn
*mlast
;
670 struct rfapi_monitor_vpn
*moved
;
672 int parent_already_refcounted
= 0;
674 RFAPI_CHECK_REFCOUNT (original_vpn_node
, SAFI_MPLS_VPN
, lockoffset
);
676 #if DEBUG_MONITOR_MOVE_SHORTER
680 prefix2str (&original_vpn_node
->p
, buf
, BUFSIZ
);
682 vnc_zlog_debug_verbose ("%s: called with node pfx=%s", __func__
, buf
);
687 * 1. If there is at least one bi (either regular route or
688 * route marked as withdrawn, with a pending timer) at
689 * original_node with a valid UN address, we're done. Return.
691 for (bi
= original_vpn_node
->info
; bi
; bi
= bi
->next
)
695 if (!rfapiGetUnAddrOfVpnBi (bi
, &pfx
))
697 #if DEBUG_MONITOR_MOVE_SHORTER
698 vnc_zlog_debug_verbose ("%s: have valid UN at original node, no change",
706 * 2. Travel up the tree (toward less-specific prefixes) from
707 * original_node to find the first node that has at least
708 * one route (even if it is only a withdrawn route) with a
709 * valid UN address. Call this node "Node P."
711 for (par
= original_vpn_node
->parent
; par
; par
= par
->parent
)
713 for (bi
= par
->info
; bi
; bi
= bi
->next
)
716 if (!rfapiGetUnAddrOfVpnBi (bi
, &pfx
))
727 RFAPI_CHECK_REFCOUNT (par
, SAFI_MPLS_VPN
, 0);
731 * If no less-specific routes, try to use the 0/0 node
735 /* this isn't necessarily 0/0 */
736 par
= route_top (original_vpn_node
->table
);
739 * If we got the top node but it wasn't 0/0,
742 if (par
&& par
->p
.prefixlen
)
744 route_unlock_node (par
); /* maybe free */
750 ++parent_already_refcounted
;
755 * Create 0/0 node if it isn't there
759 struct prefix pfx_default
;
761 memset (&pfx_default
, 0, sizeof (pfx_default
));
762 pfx_default
.family
= original_vpn_node
->p
.family
;
764 /* creates default node if none exists */
765 par
= route_node_get (original_vpn_node
->table
, &pfx_default
);
766 ++parent_already_refcounted
;
770 * 3. Move each of the monitors found at original_node to Node P.
771 * These are "Moved Monitors."
776 * Attach at end so that the list pointer we return points
777 * only to the moved routes
779 for (m
= RFAPI_MONITOR_VPN (par
), mlast
= NULL
; m
; mlast
= m
, m
= m
->next
);
783 moved
= mlast
->next
= RFAPI_MONITOR_VPN (original_vpn_node
);
787 moved
= RFAPI_MONITOR_VPN_W_ALLOC (par
) =
788 RFAPI_MONITOR_VPN (original_vpn_node
);
790 if (RFAPI_MONITOR_VPN (original_vpn_node
)) /* check agg, so not allocated */
791 RFAPI_MONITOR_VPN_W_ALLOC (original_vpn_node
) = NULL
;
794 * update the node pointers on the monitors
796 for (m
= moved
; m
; m
= m
->next
)
802 RFAPI_CHECK_REFCOUNT (par
, SAFI_MPLS_VPN
,
803 parent_already_refcounted
- movecount
);
804 while (movecount
> parent_already_refcounted
)
806 route_lock_node (par
);
807 ++parent_already_refcounted
;
809 while (movecount
< parent_already_refcounted
)
811 /* unlikely, but code defensively */
812 route_unlock_node (par
);
813 --parent_already_refcounted
;
815 RFAPI_CHECK_REFCOUNT (original_vpn_node
, SAFI_MPLS_VPN
,
816 movecount
+ lockoffset
);
819 route_unlock_node (original_vpn_node
);
822 #if DEBUG_MONITOR_MOVE_SHORTER
826 prefix2str (&par
->p
, buf
, BUFSIZ
);
828 vnc_zlog_debug_verbose ("%s: moved to node pfx=%s", __func__
, buf
);
837 * Implement MONITOR_MOVE_LONGER(new_node) from
838 * RFAPI-Import-Event-Handling.txt
841 rfapiMonitorMoveLonger (struct route_node
*new_vpn_node
)
843 struct rfapi_monitor_vpn
*monitor
;
844 struct rfapi_monitor_vpn
*mlast
;
846 struct route_node
*par
;
848 RFAPI_CHECK_REFCOUNT (new_vpn_node
, SAFI_MPLS_VPN
, 0);
851 * Make sure we have at least one valid route at the new node
853 for (bi
= new_vpn_node
->info
; bi
; bi
= bi
->next
)
856 if (!rfapiGetUnAddrOfVpnBi (bi
, &pfx
))
862 vnc_zlog_debug_verbose ("%s: no valid routes at node %p, so not attempting moves",
863 __func__
, new_vpn_node
);
868 * Find first parent node that has monitors
870 for (par
= new_vpn_node
->parent
; par
; par
= par
->parent
)
872 if (RFAPI_MONITOR_VPN (par
))
878 vnc_zlog_debug_verbose ("%s: no parent nodes with monitors, done", __func__
);
883 * Check each of these monitors to see of their longest-match
884 * is now the updated node. Move any such monitors to the more-
885 * specific updated node
887 for (mlast
= NULL
, monitor
= RFAPI_MONITOR_VPN (par
); monitor
;)
891 * If new longest match for monitor prefix is the new
892 * route's prefix, move monitor to new route's prefix
894 if (prefix_match (&new_vpn_node
->p
, &monitor
->p
))
899 mlast
->next
= monitor
->next
;
903 RFAPI_MONITOR_VPN_W_ALLOC (par
) = monitor
->next
;
908 monitor
->next
= RFAPI_MONITOR_VPN (new_vpn_node
);
909 RFAPI_MONITOR_VPN_W_ALLOC (new_vpn_node
) = monitor
;
910 monitor
->node
= new_vpn_node
;
912 route_lock_node (new_vpn_node
); /* incr refcount */
914 monitor
= mlast
? mlast
->next
: RFAPI_MONITOR_VPN (par
);
916 RFAPI_CHECK_REFCOUNT (par
, SAFI_MPLS_VPN
, 1);
917 /* decr refcount after we're done with par as this might free it */
918 route_unlock_node (par
);
923 monitor
= monitor
->next
;
926 RFAPI_CHECK_REFCOUNT (new_vpn_node
, SAFI_MPLS_VPN
, 0);
931 rfapiBgpInfoChainFree (struct bgp_info
*bi
)
933 struct bgp_info
*next
;
939 * If there is a timer waiting to delete this bi, cancel
940 * the timer and delete immediately
942 if (CHECK_FLAG (bi
->flags
, BGP_INFO_REMOVED
) &&
943 bi
->extra
->vnc
.import
.timer
)
946 struct thread
*t
= (struct thread
*) bi
->extra
->vnc
.import
.timer
;
947 struct rfapi_withdraw
*wcb
= t
->arg
;
949 XFREE (MTYPE_RFAPI_WITHDRAW
, wcb
);
955 rfapiBgpInfoFree (bi
);
961 rfapiImportTableFlush (struct rfapi_import_table
*it
)
968 ecommunity_free (&it
->rt_import_list
);
969 it
->rt_import_list
= NULL
;
971 for (afi
= AFI_IP
; afi
< AFI_MAX
; ++afi
)
974 struct route_node
*rn
;
976 for (rn
= route_top (it
->imported_vpn
[afi
]); rn
; rn
= route_next (rn
))
979 * Each route_node has:
980 * aggregate: points to rfapi_it_extra with monitor chain(s)
981 * info: points to chain of bgp_info
983 /* free bgp_info and its children */
984 rfapiBgpInfoChainFree (rn
->info
);
987 rfapiMonitorExtraFlush (SAFI_MPLS_VPN
, rn
);
990 for (rn
= route_top (it
->imported_encap
[afi
]); rn
; rn
= route_next (rn
))
992 /* free bgp_info and its children */
993 rfapiBgpInfoChainFree (rn
->info
);
996 rfapiMonitorExtraFlush (SAFI_ENCAP
, rn
);
999 route_table_finish (it
->imported_vpn
[afi
]);
1000 route_table_finish (it
->imported_encap
[afi
]);
1002 if (it
->monitor_exterior_orphans
)
1004 skiplist_free (it
->monitor_exterior_orphans
);
1009 rfapiImportTableRefDelByIt (
1011 struct rfapi_import_table
*it_target
)
1014 struct rfapi_import_table
*it
;
1015 struct rfapi_import_table
*prev
= NULL
;
1022 for (it
= h
->imports
; it
; prev
= it
, it
= it
->next
)
1024 if (it
== it_target
)
1029 assert (it
->refcount
);
1037 prev
->next
= it
->next
;
1041 h
->imports
= it
->next
;
1043 rfapiImportTableFlush (it
);
1044 XFREE (MTYPE_RFAPI_IMPORTTABLE
, it
);
1048 #if RFAPI_REQUIRE_ENCAP_BEEC
1050 * Look for magic BGP Encapsulation Extended Community value
1051 * Format in RFC 5512 Sect. 4.5
1054 rfapiEcommunitiesMatchBeec (struct ecommunity
*ecom
,
1055 bgp_encap_types type
)
1062 for (i
= 0; i
< (ecom
->size
* ECOMMUNITY_SIZE
); i
+= ECOMMUNITY_SIZE
)
1069 if (ep
[0] == ECOMMUNITY_ENCODE_OPAQUE
&&
1070 ep
[1] == ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP
&&
1071 ep
[6] == ((type
&& 0xff00)>>8) &&
1072 ep
[7] == (type
&0xff))
1084 rfapiEcommunitiesIntersect (struct ecommunity
*e1
, struct ecommunity
*e2
)
1093 s1
= ecommunity_ecom2str (e1
, ECOMMUNITY_FORMAT_DISPLAY
, 0);
1094 s2
= ecommunity_ecom2str (e2
, ECOMMUNITY_FORMAT_DISPLAY
, 0);
1095 vnc_zlog_debug_verbose ("%s: e1[%s], e2[%s]", __func__
, s1
, s2
);
1096 XFREE (MTYPE_ECOMMUNITY_STR
, s1
);
1097 XFREE (MTYPE_ECOMMUNITY_STR
, s2
);
1100 for (i
= 0; i
< e1
->size
; ++i
)
1102 for (j
= 0; j
< e2
->size
; ++j
)
1104 if (!memcmp (e1
->val
+ (i
* ECOMMUNITY_SIZE
),
1105 e2
->val
+ (j
* ECOMMUNITY_SIZE
), ECOMMUNITY_SIZE
))
1116 rfapiEcommunityGetLNI (struct ecommunity
*ecom
, uint32_t * lni
)
1121 for (i
= 0; i
< ecom
->size
; ++i
)
1123 uint8_t *p
= ecom
->val
+ (i
* ECOMMUNITY_SIZE
);
1125 if ((*(p
+ 0) == 0x00) && (*(p
+ 1) == 0x02))
1128 *lni
= (*(p
+ 5) << 16) | (*(p
+ 6) << 8) | (*(p
+ 7));
1137 rfapiEcommunityGetEthernetTag (struct ecommunity
*ecom
, uint16_t * tag_id
)
1139 struct bgp
*bgp
= bgp_get_default ();
1140 *tag_id
= 0; /* default to untagged */
1144 for (i
= 0; i
< ecom
->size
; ++i
)
1148 uint8_t *p
= ecom
->val
+ (i
* ECOMMUNITY_SIZE
);
1150 /* High-order octet of type. */
1153 if (*p
++ == ECOMMUNITY_ROUTE_TARGET
) {
1154 if (encode
== ECOMMUNITY_ENCODE_AS4
)
1161 else if (encode
== ECOMMUNITY_ENCODE_AS
)
1165 p
+= 2; /* skip next two, tag/vid always in lowest bytes */
1169 *tag_id
= *p
++ << 8;
1180 rfapiVpnBiNhEqualsPt (struct bgp_info
*bi
, struct rfapi_ip_addr
*hpt
)
1187 family
= BGP_MP_NEXTHOP_FAMILY (bi
->attr
->extra
->mp_nexthop_len
);
1189 if (hpt
->addr_family
!= family
)
1195 if (bi
->attr
->extra
->mp_nexthop_global_in
.s_addr
!= hpt
->addr
.v4
.s_addr
)
1200 if (IPV6_ADDR_CMP (&bi
->attr
->extra
->mp_nexthop_global
, &hpt
->addr
.v6
))
1214 * Compare 2 VPN BIs. Return true if they have the same VN and UN addresses
1217 rfapiVpnBiSamePtUn (struct bgp_info
*bi1
, struct bgp_info
*bi2
)
1219 struct prefix pfx_un1
;
1220 struct prefix pfx_un2
;
1225 if (!bi1
->attr
|| !bi2
->attr
)
1228 if (!bi1
->attr
->extra
|| !bi2
->attr
->extra
)
1232 * VN address comparisons
1235 if (BGP_MP_NEXTHOP_FAMILY (bi1
->attr
->extra
->mp_nexthop_len
) !=
1236 BGP_MP_NEXTHOP_FAMILY (bi2
->attr
->extra
->mp_nexthop_len
))
1241 switch (BGP_MP_NEXTHOP_FAMILY (bi1
->attr
->extra
->mp_nexthop_len
))
1245 if (bi1
->attr
->extra
->mp_nexthop_global_in
.s_addr
!=
1246 bi2
->attr
->extra
->mp_nexthop_global_in
.s_addr
)
1251 if (IPV6_ADDR_CMP (&bi1
->attr
->extra
->mp_nexthop_global
,
1252 &bi2
->attr
->extra
->mp_nexthop_global
))
1262 * UN address comparisons
1264 if (rfapiGetVncTunnelUnAddr (bi1
->attr
, &pfx_un1
))
1268 pfx_un1
.family
= bi1
->extra
->vnc
.import
.un_family
;
1269 switch (bi1
->extra
->vnc
.import
.un_family
)
1272 pfx_un1
.u
.prefix4
= bi1
->extra
->vnc
.import
.un
.addr4
;
1275 pfx_un1
.u
.prefix6
= bi1
->extra
->vnc
.import
.un
.addr6
;
1284 if (rfapiGetVncTunnelUnAddr (bi2
->attr
, &pfx_un2
))
1288 pfx_un2
.family
= bi2
->extra
->vnc
.import
.un_family
;
1289 switch (bi2
->extra
->vnc
.import
.un_family
)
1292 pfx_un2
.u
.prefix4
= bi2
->extra
->vnc
.import
.un
.addr4
;
1295 pfx_un2
.u
.prefix6
= bi2
->extra
->vnc
.import
.un
.addr6
;
1304 if (!pfx_un1
.family
|| !pfx_un2
.family
)
1307 if (pfx_un1
.family
!= pfx_un2
.family
)
1310 switch (pfx_un1
.family
)
1314 (&pfx_un1
.u
.prefix4
.s_addr
, &pfx_un2
.u
.prefix4
.s_addr
))
1318 if (!IPV6_ADDR_SAME (&pfx_un1
.u
.prefix6
, &pfx_un2
.u
.prefix6
))
1329 rfapiRfpCost (struct attr
* attr
)
1331 if (attr
->flag
& ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF
))
1333 if (attr
->local_pref
> 255)
1337 return 255 - attr
->local_pref
;
1343 /*------------------------------------------
1346 * Find Layer 2 options in an option chain
1352 * l2o layer 2 options extracted
1356 * 1 no options found
1358 --------------------------------------------*/
1360 rfapi_extract_l2o (struct bgp_tea_options
*pHop
, /* chain of options */
1361 struct rfapi_l2address_option
*l2o
) /* return extracted value */
1363 struct bgp_tea_options
*p
;
1365 for (p
= pHop
; p
; p
= p
->next
)
1367 if ((p
->type
== RFAPI_VN_OPTION_TYPE_L2ADDR
) && (p
->length
>= 8))
1372 memcpy (&l2o
->macaddr
, v
, 6);
1375 ((v
[6] << 12) & 0xff000) +
1376 ((v
[7] << 4) & 0xff0) + ((v
[8] >> 4) & 0xf);
1378 l2o
->local_nve_id
= (uint8_t) v
[10];
1380 l2o
->logical_net_id
= (v
[11] << 16) + (v
[12] << 8) + (v
[13] << 0);
1388 static struct rfapi_next_hop_entry
*
1389 rfapiRouteInfo2NextHopEntry (
1390 struct rfapi_ip_prefix
*rprefix
,
1391 struct bgp_info
*bi
, /* route to encode */
1392 uint32_t lifetime
, /* use this in nhe */
1393 struct route_node
*rn
) /* req for L2 eth addr */
1395 struct rfapi_next_hop_entry
*new;
1396 int have_vnc_tunnel_un
= 0;
1398 #if DEBUG_ENCAP_MONITOR
1399 vnc_zlog_debug_verbose ("%s: entry, bi %p, rn %p", __func__
, bi
, rn
);
1402 new = XCALLOC (MTYPE_RFAPI_NEXTHOP
, sizeof (struct rfapi_next_hop_entry
));
1405 new->prefix
= *rprefix
;
1408 decode_rd_type(bi
->extra
->vnc
.import
.rd
.val
) == RD_TYPE_VNC_ETH
)
1412 struct rfapi_vn_option
*vo
;
1414 vo
= XCALLOC (MTYPE_RFAPI_VN_OPTION
, sizeof (struct rfapi_vn_option
));
1417 vo
->type
= RFAPI_VN_OPTION_TYPE_L2ADDR
;
1419 memcpy (&vo
->v
.l2addr
.macaddr
, &rn
->p
.u
.prefix_eth
.octet
,
1421 /* only low 3 bytes of this are significant */
1422 if (bi
->attr
&& bi
->attr
->extra
)
1424 (void) rfapiEcommunityGetLNI (bi
->attr
->extra
->ecommunity
,
1425 &vo
->v
.l2addr
.logical_net_id
);
1426 (void) rfapiEcommunityGetEthernetTag (bi
->attr
->extra
->ecommunity
,
1427 &vo
->v
.l2addr
.tag_id
);
1430 /* local_nve_id comes from lower byte of RD type */
1431 vo
->v
.l2addr
.local_nve_id
= bi
->extra
->vnc
.import
.rd
.val
[1];
1433 /* label comes from MP_REACH_NLRI label */
1434 vo
->v
.l2addr
.label
= decode_label (bi
->extra
->tag
);
1436 new->vn_options
= vo
;
1439 * If there is an auxiliary prefix (i.e., host IP address),
1440 * use it as the nexthop prefix instead of the query prefix
1442 if (bi
->extra
->vnc
.import
.aux_prefix
.family
)
1444 rfapiQprefix2Rprefix (&bi
->extra
->vnc
.import
.aux_prefix
,
1451 bgp_encap_types tun_type
;
1452 new->prefix
.cost
= rfapiRfpCost (bi
->attr
);
1454 if (bi
->attr
->extra
)
1457 struct bgp_attr_encap_subtlv
*pEncap
;
1459 switch (BGP_MP_NEXTHOP_FAMILY (bi
->attr
->extra
->mp_nexthop_len
))
1462 new->vn_address
.addr_family
= AF_INET
;
1463 new->vn_address
.addr
.v4
= bi
->attr
->extra
->mp_nexthop_global_in
;
1467 new->vn_address
.addr_family
= AF_INET6
;
1468 new->vn_address
.addr
.v6
= bi
->attr
->extra
->mp_nexthop_global
;
1472 zlog_warn ("%s: invalid vpn nexthop length: %d",
1473 __func__
, bi
->attr
->extra
->mp_nexthop_len
);
1474 rfapi_free_next_hop_list (new);
1478 for (pEncap
= bi
->attr
->extra
->vnc_subtlvs
; pEncap
;
1479 pEncap
= pEncap
->next
)
1481 switch (pEncap
->type
)
1483 case BGP_VNC_SUBTLV_TYPE_LIFETIME
:
1484 /* use configured lifetime, not attr lifetime */
1488 zlog_warn ("%s: unknown VNC option type %d",
1489 __func__
, pEncap
->type
);
1496 rfapiGetTunnelType (bi
->attr
, &tun_type
);
1497 if (tun_type
== BGP_ENCAP_TYPE_MPLS
)
1500 /* MPLS carries UN address in next hop */
1501 rfapiNexthop2Prefix (bi
->attr
, &p
);
1504 rfapiQprefix2Raddr(&p
, &new->un_address
);
1505 have_vnc_tunnel_un
= 1;
1509 for (pEncap
= bi
->attr
->extra
->encap_subtlvs
; pEncap
;
1510 pEncap
= pEncap
->next
)
1512 switch (pEncap
->type
)
1514 case BGP_ENCAP_SUBTLV_TYPE_REMOTE_ENDPOINT
:
1516 * Overrides ENCAP UN address, if any
1518 switch (pEncap
->length
)
1522 new->un_address
.addr_family
= AF_INET
;
1523 memcpy (&new->un_address
.addr
.v4
, pEncap
->value
, 4);
1524 have_vnc_tunnel_un
= 1;
1528 new->un_address
.addr_family
= AF_INET6
;
1529 memcpy (&new->un_address
.addr
.v6
, pEncap
->value
, 16);
1530 have_vnc_tunnel_un
= 1;
1535 ("%s: invalid tunnel subtlv UN addr length (%d) for bi %p",
1536 __func__
, pEncap
->length
, bi
);
1541 zlog_warn ("%s: unknown Encap Attribute option type %d",
1542 __func__
, pEncap
->type
);
1549 new->un_options
= rfapi_encap_tlv_to_un_option (bi
->attr
);
1551 #if DEBUG_ENCAP_MONITOR
1552 vnc_zlog_debug_verbose ("%s: line %d: have_vnc_tunnel_un=%d",
1553 __func__
, __LINE__
, have_vnc_tunnel_un
);
1556 if (!have_vnc_tunnel_un
&& bi
&& bi
->extra
)
1559 * use cached UN address from ENCAP route
1561 new->un_address
.addr_family
= bi
->extra
->vnc
.import
.un_family
;
1562 switch (new->un_address
.addr_family
)
1565 new->un_address
.addr
.v4
= bi
->extra
->vnc
.import
.un
.addr4
;
1568 new->un_address
.addr
.v6
= bi
->extra
->vnc
.import
.un
.addr6
;
1571 zlog_warn ("%s: invalid UN addr family (%d) for bi %p",
1572 __func__
, new->un_address
.addr_family
, bi
);
1573 rfapi_free_next_hop_list (new);
1580 new->lifetime
= lifetime
;
1585 rfapiHasNonRemovedRoutes (struct route_node
*rn
)
1587 struct bgp_info
*bi
;
1589 for (bi
= rn
->info
; bi
; bi
= bi
->next
)
1593 if (!CHECK_FLAG (bi
->flags
, BGP_INFO_REMOVED
) &&
1594 (bi
->extra
&& !rfapiGetUnAddrOfVpnBi (bi
, &pfx
)))
1608 rfapiDumpNode (struct route_node
*rn
)
1610 struct bgp_info
*bi
;
1612 vnc_zlog_debug_verbose ("%s: rn=%p", __func__
, rn
);
1613 for (bi
= rn
->info
; bi
; bi
= bi
->next
)
1616 int ctrc
= rfapiGetUnAddrOfVpnBi (bi
, &pfx
);
1619 if (!CHECK_FLAG (bi
->flags
, BGP_INFO_REMOVED
) && (bi
->extra
&& !ctrc
))
1629 vnc_zlog_debug_verbose (" bi=%p, nr=%d, flags=0x%x, extra=%p, ctrc=%d",
1630 bi
, nr
, bi
->flags
, bi
->extra
, ctrc
);
1636 rfapiNhlAddNodeRoutes (
1637 struct route_node
*rn
, /* in */
1638 struct rfapi_ip_prefix
*rprefix
, /* in */
1639 uint32_t lifetime
, /* in */
1640 int removed
, /* in */
1641 struct rfapi_next_hop_entry
**head
, /* in/out */
1642 struct rfapi_next_hop_entry
**tail
, /* in/out */
1643 struct rfapi_ip_addr
*exclude_vnaddr
, /* omit routes to same NVE */
1644 struct route_node
*rfd_rib_node
,/* preload this NVE rib node */
1645 struct prefix
*pfx_target_original
) /* query target */
1647 struct bgp_info
*bi
;
1648 struct rfapi_next_hop_entry
*new;
1649 struct prefix pfx_un
;
1650 struct skiplist
*seen_nexthops
;
1652 int is_l2
= (rn
->p
.family
== AF_ETHERNET
);
1654 if (rfapiRibFTDFilterRecentPrefix(
1655 (struct rfapi_descriptor
*)(rfd_rib_node
->table
->info
), rn
,
1656 pfx_target_original
))
1662 skiplist_new (0, vnc_prefix_cmp
, (void (*)(void *)) prefix_free
);
1664 for (bi
= rn
->info
; bi
; bi
= bi
->next
)
1667 struct prefix pfx_vn
;
1668 struct prefix
*newpfx
;
1670 if (removed
&& !CHECK_FLAG (bi
->flags
, BGP_INFO_REMOVED
))
1672 #if DEBUG_RETURNED_NHL
1673 vnc_zlog_debug_verbose ("%s: want holddown, this route not holddown, skip",
1678 if (!removed
&& CHECK_FLAG (bi
->flags
, BGP_INFO_REMOVED
))
1689 * Check for excluded VN address
1691 if (rfapiVpnBiNhEqualsPt (bi
, exclude_vnaddr
))
1695 * Check for VN address (nexthop) copied already
1699 /* L2 routes: semantic nexthop in aux_prefix; VN addr ain't it */
1700 pfx_vn
= bi
->extra
->vnc
.import
.aux_prefix
;
1704 rfapiNexthop2Prefix (bi
->attr
, &pfx_vn
);
1706 if (!skiplist_search (seen_nexthops
, &pfx_vn
, NULL
))
1708 #if DEBUG_RETURNED_NHL
1711 prefix2str (&pfx_vn
, buf
, BUFSIZ
);
1712 buf
[BUFSIZ
- 1] = 0; /* guarantee NUL-terminated */
1713 vnc_zlog_debug_verbose ("%s: already put VN/nexthop %s, skip", __func__
, buf
);
1718 if (rfapiGetUnAddrOfVpnBi (bi
, &pfx_un
))
1720 #if DEBUG_ENCAP_MONITOR
1721 vnc_zlog_debug_verbose ("%s: failed to get UN address of this VPN bi",
1727 newpfx
= prefix_new ();
1729 skiplist_insert (seen_nexthops
, newpfx
, newpfx
);
1731 new = rfapiRouteInfo2NextHopEntry(rprefix
, bi
, lifetime
, rn
);
1734 if (rfapiRibPreloadBi(rfd_rib_node
, &pfx_vn
, &pfx_un
, lifetime
, bi
))
1736 /* duplicate filtered by RIB */
1737 rfapi_free_next_hop_list (new);
1746 (*tail
)->next
= new;
1757 skiplist_free (seen_nexthops
);
1766 * omit_node is meant for the situation where we are adding a subtree
1767 * of a parent of some original requested node. The response already
1768 * contains the original requested node, and we don't want to duplicate
1769 * its routes in the list, so we skip it if the right or left node
1770 * matches (of course, we still travel down its child subtrees).
1773 rfapiNhlAddSubtree (
1774 struct route_node
*rn
, /* in */
1775 uint32_t lifetime
, /* in */
1776 struct rfapi_next_hop_entry
**head
, /* in/out */
1777 struct rfapi_next_hop_entry
**tail
, /* in/out */
1778 struct route_node
*omit_node
, /* in */
1779 struct rfapi_ip_addr
*exclude_vnaddr
,/* omit routes to same NVE */
1780 struct route_table
*rfd_rib_table
,/* preload here */
1781 struct prefix
*pfx_target_original
) /* query target */
1783 struct rfapi_ip_prefix rprefix
;
1786 if (rn
->l_left
&& rn
->l_left
!= omit_node
)
1788 if (rn
->l_left
->info
)
1791 struct route_node
*rib_rn
= NULL
;
1793 rfapiQprefix2Rprefix (&rn
->l_left
->p
, &rprefix
);
1796 rib_rn
= route_node_get(rfd_rib_table
, &rn
->l_left
->p
);
1799 count
= rfapiNhlAddNodeRoutes (rn
->l_left
, &rprefix
, lifetime
, 0,
1800 head
, tail
, exclude_vnaddr
, rib_rn
, pfx_target_original
);
1803 count
= rfapiNhlAddNodeRoutes (rn
->l_left
, &rprefix
, lifetime
, 1,
1804 head
, tail
, exclude_vnaddr
, rib_rn
, pfx_target_original
);
1808 route_unlock_node(rib_rn
);
1812 if (rn
->l_right
&& rn
->l_right
!= omit_node
)
1814 if (rn
->l_right
->info
)
1817 struct route_node
*rib_rn
= NULL
;
1819 rfapiQprefix2Rprefix (&rn
->l_right
->p
, &rprefix
);
1822 rib_rn
= route_node_get(rfd_rib_table
, &rn
->l_right
->p
);
1824 count
= rfapiNhlAddNodeRoutes (rn
->l_right
, &rprefix
, lifetime
, 0,
1825 head
, tail
, exclude_vnaddr
, rib_rn
, pfx_target_original
);
1828 count
= rfapiNhlAddNodeRoutes (rn
->l_right
, &rprefix
, lifetime
, 1,
1829 head
, tail
, exclude_vnaddr
, rib_rn
, pfx_target_original
);
1833 route_unlock_node(rib_rn
);
1839 rcount
+= rfapiNhlAddSubtree (rn
->l_left
, lifetime
, head
, tail
, omit_node
,
1840 exclude_vnaddr
, rfd_rib_table
, pfx_target_original
);
1844 rcount
+= rfapiNhlAddSubtree (rn
->l_right
, lifetime
, head
, tail
,
1845 omit_node
, exclude_vnaddr
, rfd_rib_table
, pfx_target_original
);
1852 * Implementation of ROUTE_LIST(node) from RFAPI-Import-Event-Handling.txt
1854 * Construct an rfapi nexthop list based on the routes attached to
1855 * the specified node.
1857 * If there are any routes that do NOT have BGP_INFO_REMOVED set,
1858 * return those only. If there are ONLY routes with BGP_INFO_REMOVED,
1859 * then return those, and also include all the non-removed routes from the
1860 * next less-specific node (i.e., this node's parent) at the end.
1862 struct rfapi_next_hop_entry
*
1863 rfapiRouteNode2NextHopList (
1864 struct route_node
*rn
,
1865 uint32_t lifetime
, /* put into nexthop entries */
1866 struct rfapi_ip_addr
*exclude_vnaddr
,/* omit routes to same NVE */
1867 struct route_table
*rfd_rib_table
,/* preload here */
1868 struct prefix
*pfx_target_original
) /* query target */
1870 struct rfapi_ip_prefix rprefix
;
1871 struct rfapi_next_hop_entry
*answer
= NULL
;
1872 struct rfapi_next_hop_entry
*last
= NULL
;
1873 struct route_node
*parent
;
1875 struct route_node
*rib_rn
;
1877 #if DEBUG_RETURNED_NHL
1881 prefix2str (&rn
->p
, buf
, BUFSIZ
);
1882 buf
[BUFSIZ
- 1] = 0;
1883 vnc_zlog_debug_verbose ("%s: called with node pfx=%s", __func__
, buf
);
1885 rfapiDebugBacktrace ();
1888 rfapiQprefix2Rprefix (&rn
->p
, &rprefix
);
1890 rib_rn
= rfd_rib_table
? route_node_get(rfd_rib_table
, &rn
->p
): NULL
;
1893 * Add non-withdrawn routes at this node
1895 count
= rfapiNhlAddNodeRoutes (rn
, &rprefix
, lifetime
, 0, &answer
, &last
,
1896 exclude_vnaddr
, rib_rn
, pfx_target_original
);
1899 * If the list has at least one entry, it's finished
1903 count
+= rfapiNhlAddSubtree (rn
, lifetime
, &answer
, &last
, NULL
,
1904 exclude_vnaddr
, rfd_rib_table
, pfx_target_original
);
1905 vnc_zlog_debug_verbose ("%s: %d nexthops, answer=%p", __func__
, count
, answer
);
1906 #if DEBUG_RETURNED_NHL
1907 rfapiPrintNhl (NULL
, answer
);
1910 route_unlock_node(rib_rn
);
1915 * Add withdrawn routes at this node
1917 count
= rfapiNhlAddNodeRoutes (rn
, &rprefix
, lifetime
, 1, &answer
, &last
,
1918 exclude_vnaddr
, rib_rn
, pfx_target_original
);
1920 route_unlock_node(rib_rn
);
1922 // rfapiPrintNhl(NULL, answer);
1925 * walk up the tree until we find a node with non-deleted
1926 * routes, then add them
1928 for (parent
= rn
->parent
; parent
; parent
= parent
->parent
)
1930 if (rfapiHasNonRemovedRoutes (parent
))
1937 * Add non-withdrawn routes from less-specific prefix
1941 rib_rn
= rfd_rib_table
? route_node_get(rfd_rib_table
, &parent
->p
): NULL
;
1942 rfapiQprefix2Rprefix (&parent
->p
, &rprefix
);
1943 count
+= rfapiNhlAddNodeRoutes (parent
, &rprefix
, lifetime
, 0,
1944 &answer
, &last
, exclude_vnaddr
, rib_rn
, pfx_target_original
);
1945 count
+= rfapiNhlAddSubtree (parent
, lifetime
, &answer
, &last
, rn
,
1946 exclude_vnaddr
, rfd_rib_table
, pfx_target_original
);
1948 route_unlock_node(rib_rn
);
1953 * There is no parent with non-removed routes. Still need to
1954 * add subtree of original node if it contributed routes to the
1958 count
+= rfapiNhlAddSubtree (rn
, lifetime
, &answer
, &last
, rn
,
1959 exclude_vnaddr
, rfd_rib_table
, pfx_target_original
);
1962 vnc_zlog_debug_verbose ("%s: %d nexthops, answer=%p", __func__
, count
, answer
);
1963 #if DEBUG_RETURNED_NHL
1964 rfapiPrintNhl (NULL
, answer
);
1970 * Construct nexthop list of all routes in table
1972 struct rfapi_next_hop_entry
*
1973 rfapiRouteTable2NextHopList (
1974 struct route_table
*rt
,
1975 uint32_t lifetime
, /* put into nexthop entries */
1976 struct rfapi_ip_addr
*exclude_vnaddr
,/* omit routes to same NVE */
1977 struct route_table
*rfd_rib_table
, /* preload this NVE rib table */
1978 struct prefix
*pfx_target_original
) /* query target */
1980 struct route_node
*rn
;
1981 struct rfapi_next_hop_entry
*biglist
= NULL
;
1982 struct rfapi_next_hop_entry
*nhl
;
1983 struct rfapi_next_hop_entry
*tail
= NULL
;
1986 for (rn
= route_top (rt
); rn
; rn
= route_next (rn
))
1989 nhl
= rfapiRouteNode2NextHopList (rn
, lifetime
, exclude_vnaddr
,
1990 rfd_rib_table
, pfx_target_original
);
1993 tail
= biglist
= nhl
;
2011 vnc_zlog_debug_verbose ("%s: returning %d routes", __func__
, count
);
2015 struct rfapi_next_hop_entry
*
2016 rfapiEthRouteNode2NextHopList (
2017 struct route_node
*rn
,
2018 struct rfapi_ip_prefix
*rprefix
,
2019 uint32_t lifetime
, /* put into nexthop entries */
2020 struct rfapi_ip_addr
*exclude_vnaddr
,/* omit routes to same NVE */
2021 struct route_table
*rfd_rib_table
,/* preload NVE rib table */
2022 struct prefix
*pfx_target_original
) /* query target */
2025 struct rfapi_next_hop_entry
*answer
= NULL
;
2026 struct rfapi_next_hop_entry
*last
= NULL
;
2027 struct route_node
*rib_rn
;
2029 rib_rn
= rfd_rib_table
? route_node_get(rfd_rib_table
, &rn
->p
): NULL
;
2031 count
= rfapiNhlAddNodeRoutes (rn
, rprefix
, lifetime
, 0, &answer
, &last
,
2032 NULL
, rib_rn
, pfx_target_original
);
2034 #if DEBUG_ENCAP_MONITOR
2035 vnc_zlog_debug_verbose ("%s: node %p: %d non-holddown routes", __func__
, rn
, count
);
2040 count
= rfapiNhlAddNodeRoutes (rn
, rprefix
, lifetime
, 1, &answer
, &last
,
2041 exclude_vnaddr
, rib_rn
, pfx_target_original
);
2042 vnc_zlog_debug_verbose ("%s: node %p: %d holddown routes", __func__
, rn
, count
);
2046 route_unlock_node(rib_rn
);
2048 #if DEBUG_RETURNED_NHL
2049 rfapiPrintNhl (NULL
, answer
);
2057 * Construct nexthop list of all routes in table
2059 struct rfapi_next_hop_entry
*
2060 rfapiEthRouteTable2NextHopList (
2061 uint32_t logical_net_id
,
2062 struct rfapi_ip_prefix
*rprefix
,
2063 uint32_t lifetime
, /* put into nexthop entries */
2064 struct rfapi_ip_addr
*exclude_vnaddr
,/* omit routes to same NVE */
2065 struct route_table
*rfd_rib_table
, /* preload NVE rib node */
2066 struct prefix
*pfx_target_original
) /* query target */
2068 struct rfapi_import_table
*it
;
2069 struct bgp
*bgp
= bgp_get_default ();
2070 struct route_table
*rt
;
2071 struct route_node
*rn
;
2072 struct rfapi_next_hop_entry
*biglist
= NULL
;
2073 struct rfapi_next_hop_entry
*nhl
;
2074 struct rfapi_next_hop_entry
*tail
= NULL
;
2078 it
= rfapiMacImportTableGet (bgp
, logical_net_id
);
2079 rt
= it
->imported_vpn
[AFI_L2VPN
];
2081 for (rn
= route_top (rt
); rn
; rn
= route_next (rn
))
2084 nhl
= rfapiEthRouteNode2NextHopList(rn
, rprefix
, lifetime
,
2085 exclude_vnaddr
, rfd_rib_table
, pfx_target_original
);
2088 tail
= biglist
= nhl
;
2106 vnc_zlog_debug_verbose ("%s: returning %d routes", __func__
, count
);
2111 * Insert a new bi to the imported route table node,
2112 * keeping the list of BIs sorted best route first
2115 rfapiBgpInfoAttachSorted (
2116 struct route_node
*rn
,
2117 struct bgp_info
*info_new
,
2122 struct bgp_info
*prev
;
2123 struct bgp_info
*next
;
2125 bgp
= bgp_get_default (); /* assume 1 instance for now */
2127 if (VNC_DEBUG(IMPORT_BI_ATTACH
))
2129 vnc_zlog_debug_verbose ("%s: info_new->peer=%p", __func__
, info_new
->peer
);
2130 vnc_zlog_debug_verbose ("%s: info_new->peer->su_remote=%p", __func__
,
2131 info_new
->peer
->su_remote
);
2134 for (prev
= NULL
, next
= rn
->info
; next
; prev
= next
, next
= next
->next
)
2137 (!CHECK_FLAG (info_new
->flags
, BGP_INFO_REMOVED
) &&
2138 CHECK_FLAG (next
->flags
, BGP_INFO_REMOVED
)) ||
2139 bgp_info_cmp_compatible (bgp
, info_new
, next
, afi
, safi
) == -1)
2140 { /* -1 if 1st is better */
2144 vnc_zlog_debug_verbose ("%s: prev=%p, next=%p", __func__
, prev
, next
);
2147 prev
->next
= info_new
;
2151 rn
->info
= info_new
;
2153 info_new
->prev
= prev
;
2154 info_new
->next
= next
;
2156 next
->prev
= info_new
;
2157 bgp_attr_intern (info_new
->attr
);
2161 rfapiBgpInfoDetach (struct route_node
*rn
, struct bgp_info
*bi
)
2164 * Remove the route (doubly-linked)
2166 // bgp_attr_unintern (&bi->attr);
2168 bi
->next
->prev
= bi
->prev
;
2170 bi
->prev
->next
= bi
->next
;
2172 rn
->info
= bi
->next
;
2176 * For L3-indexed import tables
2179 rfapi_bi_peer_rd_cmp (void *b1
, void *b2
)
2181 struct bgp_info
*bi1
= b1
;
2182 struct bgp_info
*bi2
= b2
;
2187 if (bi1
->peer
< bi2
->peer
)
2189 if (bi1
->peer
> bi2
->peer
)
2195 return vnc_prefix_cmp ((struct prefix
*) &bi1
->extra
->vnc
.import
.rd
,
2196 (struct prefix
*) &bi2
->extra
->vnc
.import
.rd
);
2200 * For L2-indexed import tables
2201 * The BIs in these tables should ALWAYS have an aux_prefix set because
2202 * they arrive via IPv4 or IPv6 advertisements.
2205 rfapi_bi_peer_rd_aux_cmp (void *b1
, void *b2
)
2207 struct bgp_info
*bi1
= b1
;
2208 struct bgp_info
*bi2
= b2
;
2214 if (bi1
->peer
< bi2
->peer
)
2216 if (bi1
->peer
> bi2
->peer
)
2222 rc
= vnc_prefix_cmp ((struct prefix
*) &bi1
->extra
->vnc
.import
.rd
,
2223 (struct prefix
*) &bi2
->extra
->vnc
.import
.rd
);
2230 * L2 import tables can have multiple entries with the
2231 * same MAC address, same RD, but different L3 addresses.
2233 * Use presence of aux_prefix with AF=ethernet and prefixlen=1
2234 * as magic value to signify explicit wildcarding of the aux_prefix.
2235 * This magic value will not appear in bona fide bi entries in
2236 * the import table, but is allowed in the "fake" bi used to
2237 * probe the table when searching. (We have to test both b1 and b2
2238 * because there is no guarantee of the order the test key and
2239 * the real key will be passed)
2241 if ((bi1
->extra
->vnc
.import
.aux_prefix
.family
== AF_ETHERNET
&&
2242 (bi1
->extra
->vnc
.import
.aux_prefix
.prefixlen
== 1)) ||
2243 (bi2
->extra
->vnc
.import
.aux_prefix
.family
== AF_ETHERNET
&&
2244 (bi2
->extra
->vnc
.import
.aux_prefix
.prefixlen
== 1)))
2248 * wildcard aux address specified
2253 return vnc_prefix_cmp (&bi1
->extra
->vnc
.import
.aux_prefix
,
2254 &bi2
->extra
->vnc
.import
.aux_prefix
);
2259 * Index on RD and Peer
2263 struct route_node
*rn
, /* Import table VPN node */
2264 struct bgp_info
*bi
) /* new BI */
2266 struct skiplist
*sl
;
2274 prefix_rd2str (&bi
->extra
->vnc
.import
.rd
, buf
, BUFSIZ
);
2275 vnc_zlog_debug_verbose ("%s: bi %p, peer %p, rd %s", __func__
, bi
, bi
->peer
, buf
);
2278 sl
= RFAPI_RDINDEX_W_ALLOC (rn
);
2281 if (AF_ETHERNET
== rn
->p
.family
)
2283 sl
= skiplist_new (0, rfapi_bi_peer_rd_aux_cmp
, NULL
);
2287 sl
= skiplist_new (0, rfapi_bi_peer_rd_cmp
, NULL
);
2289 RFAPI_IT_EXTRA_GET (rn
)->u
.vpn
.idx_rd
= sl
;
2290 route_lock_node (rn
); /* for skiplist */
2292 assert (!skiplist_insert (sl
, (void *) bi
, (void *) bi
));
2293 route_lock_node (rn
); /* for skiplist entry */
2295 /* NB: BIs in import tables are not refcounted */
2299 rfapiItBiIndexDump (struct route_node
*rn
)
2301 struct skiplist
*sl
;
2302 void *cursor
= NULL
;
2307 sl
= RFAPI_RDINDEX (rn
);
2311 for (rc
= skiplist_next (sl
, (void **) &k
, (void **) &v
, &cursor
);
2312 !rc
; rc
= skiplist_next (sl
, (void **) &k
, (void **) &v
, &cursor
))
2316 char buf_aux_pfx
[BUFSIZ
];
2318 prefix_rd2str (&k
->extra
->vnc
.import
.rd
, buf
, BUFSIZ
);
2320 if (k
->extra
->vnc
.import
.aux_prefix
.family
)
2322 prefix2str (&k
->extra
->vnc
.import
.aux_prefix
, buf_aux_pfx
, BUFSIZ
);
2326 strncpy (buf_aux_pfx
, "(none)", BUFSIZ
);
2327 buf_aux_pfx
[BUFSIZ
- 1] = 0;
2330 vnc_zlog_debug_verbose ("bi %p, peer %p, rd %s, aux_prefix %s", k
, k
->peer
, buf
,
2335 static struct bgp_info
*
2336 rfapiItBiIndexSearch (
2337 struct route_node
*rn
, /* Import table VPN node */
2338 struct prefix_rd
*prd
,
2340 struct prefix
*aux_prefix
) /* optional L3 addr for L2 ITs */
2342 struct skiplist
*sl
;
2344 struct bgp_info bi_fake
;
2345 struct bgp_info_extra bi_extra
;
2346 struct bgp_info
*bi_result
;
2348 sl
= RFAPI_RDINDEX (rn
);
2355 char buf_aux_pfx
[BUFSIZ
];
2357 prefix_rd2str (prd
, buf
, BUFSIZ
);
2360 prefix2str (aux_prefix
, buf_aux_pfx
, BUFSIZ
);
2364 strncpy (buf_aux_pfx
, "(nil)", BUFSIZ
- 1);
2365 buf_aux_pfx
[BUFSIZ
- 1] = 0;
2368 vnc_zlog_debug_verbose ("%s want prd=%s, peer=%p, aux_prefix=%s",
2369 __func__
, buf
, peer
, buf_aux_pfx
);
2370 rfapiItBiIndexDump (rn
);
2374 /* threshold is a WAG */
2378 vnc_zlog_debug_verbose ("%s: short list algorithm", __func__
);
2380 /* if short list, linear search might be faster */
2381 for (bi_result
= rn
->info
; bi_result
; bi_result
= bi_result
->next
)
2386 prefix_rd2str (&bi_result
->extra
->vnc
.import
.rd
, buf
, BUFSIZ
);
2387 vnc_zlog_debug_verbose ("%s: bi has prd=%s, peer=%p", __func__
,
2388 buf
, bi_result
->peer
);
2391 if (peer
== bi_result
->peer
&&
2392 !prefix_cmp ((struct prefix
*) &bi_result
->extra
->vnc
.import
.rd
,
2393 (struct prefix
*) prd
))
2397 vnc_zlog_debug_verbose ("%s: peer and RD same, doing aux_prefix check",
2401 !prefix_cmp (aux_prefix
,
2402 &bi_result
->extra
->vnc
.import
.aux_prefix
))
2406 vnc_zlog_debug_verbose ("%s: match", __func__
);
2416 bi_fake
.peer
= peer
;
2417 bi_fake
.extra
= &bi_extra
;
2418 bi_fake
.extra
->vnc
.import
.rd
= *(struct prefix_rd
*) prd
;
2421 bi_fake
.extra
->vnc
.import
.aux_prefix
= *aux_prefix
;
2426 bi_fake
.extra
->vnc
.import
.aux_prefix
.family
= AF_ETHERNET
;
2427 bi_fake
.extra
->vnc
.import
.aux_prefix
.prefixlen
= 1;
2430 rc
= skiplist_search (sl
, (void *) &bi_fake
, (void *) &bi_result
);
2435 vnc_zlog_debug_verbose ("%s: no match", __func__
);
2441 vnc_zlog_debug_verbose ("%s: matched bi=%p", __func__
, bi_result
);
2449 struct route_node
*rn
, /* Import table VPN node */
2450 struct bgp_info
*bi
) /* old BI */
2452 struct skiplist
*sl
;
2457 prefix_rd2str (&bi
->extra
->vnc
.import
.rd
, buf
, BUFSIZ
);
2458 vnc_zlog_debug_verbose ("%s: bi %p, peer %p, rd %s", __func__
, bi
, bi
->peer
, buf
);
2461 sl
= RFAPI_RDINDEX (rn
);
2464 rc
= skiplist_delete (sl
, (void *) (bi
), (void *) bi
);
2467 rfapiItBiIndexDump (rn
);
2471 route_unlock_node (rn
); /* for skiplist entry */
2473 /* NB: BIs in import tables are not refcounted */
2477 * Add a backreference at the ENCAP node to the VPN route that
2481 rfapiMonitorEncapAdd (
2482 struct rfapi_import_table
*import_table
,
2483 struct prefix
*p
, /* VN address */
2484 struct route_node
*vpn_rn
, /* VPN node */
2485 struct bgp_info
*vpn_bi
) /* VPN bi/route */
2487 afi_t afi
= family2afi (p
->family
);
2488 struct route_node
*rn
;
2489 struct rfapi_monitor_encap
*m
;
2492 rn
= route_node_get (import_table
->imported_encap
[afi
], p
); /* locks rn */
2496 XCALLOC (MTYPE_RFAPI_MONITOR_ENCAP
, sizeof (struct rfapi_monitor_encap
));
2503 /* insert to encap node's list */
2504 m
->next
= RFAPI_MONITOR_ENCAP (rn
);
2507 RFAPI_MONITOR_ENCAP_W_ALLOC (rn
) = m
;
2509 /* for easy lookup when deleting vpn route */
2510 vpn_bi
->extra
->vnc
.import
.hme
= m
;
2512 vnc_zlog_debug_verbose
2513 ("%s: it=%p, vpn_bi=%p, afi=%d, encap rn=%p, setting vpn_bi->extra->vnc.import.hme=%p",
2514 __func__
, import_table
, vpn_bi
, afi
, rn
, m
);
2516 RFAPI_CHECK_REFCOUNT (rn
, SAFI_ENCAP
, 0);
2517 bgp_attr_intern (vpn_bi
->attr
);
2521 rfapiMonitorEncapDelete (struct bgp_info
*vpn_bi
)
2524 * Remove encap monitor
2526 vnc_zlog_debug_verbose ("%s: vpn_bi=%p", __func__
, vpn_bi
);
2529 struct rfapi_monitor_encap
*hme
= vpn_bi
->extra
->vnc
.import
.hme
;
2534 vnc_zlog_debug_verbose ("%s: hme=%p", __func__
, hme
);
2536 /* Refcount checking takes too long here */
2537 //RFAPI_CHECK_REFCOUNT(hme->rn, SAFI_ENCAP, 0);
2539 hme
->next
->prev
= hme
->prev
;
2541 hme
->prev
->next
= hme
->next
;
2543 RFAPI_MONITOR_ENCAP_W_ALLOC (hme
->rn
) = hme
->next
;
2544 /* Refcount checking takes too long here */
2545 //RFAPI_CHECK_REFCOUNT(hme->rn, SAFI_ENCAP, 1);
2547 /* see if the struct rfapi_it_extra is empty and can be freed */
2548 rfapiMonitorExtraPrune (SAFI_ENCAP
, hme
->rn
);
2550 route_unlock_node (hme
->rn
); /* decr ref count */
2551 XFREE (MTYPE_RFAPI_MONITOR_ENCAP
, hme
);
2552 vpn_bi
->extra
->vnc
.import
.hme
= NULL
;
2558 * quagga lib/thread.h says this must return int even though
2559 * it doesn't do anything with the return value
2562 rfapiWithdrawTimerVPN (struct thread
*t
)
2564 struct rfapi_withdraw
*wcb
= t
->arg
;
2565 struct bgp_info
*bi
= wcb
->info
;
2566 struct bgp
*bgp
= bgp_get_default ();
2568 struct rfapi_monitor_vpn
*moved
;
2573 assert (wcb
->import_table
);
2576 RFAPI_CHECK_REFCOUNT (wcb
->node
, SAFI_MPLS_VPN
, wcb
->lockoffset
);
2581 vnc_zlog_debug_verbose ("%s: removing bi %p at prefix %s/%d",
2584 rfapi_ntop (wcb
->node
->p
.family
, &wcb
->node
->p
.u
.prefix
, buf
,
2585 BUFSIZ
), wcb
->node
->p
.prefixlen
);
2589 * Remove the route (doubly-linked)
2591 if (CHECK_FLAG (bi
->flags
, BGP_INFO_VALID
)
2592 && VALID_INTERIOR_TYPE (bi
->type
))
2593 RFAPI_MONITOR_EXTERIOR (wcb
->node
)->valid_interior_count
--;
2595 afi
= family2afi (wcb
->node
->p
.family
);
2596 wcb
->import_table
->holddown_count
[afi
] -= 1; /* keep count consistent */
2597 rfapiItBiIndexDel (wcb
->node
, bi
);
2598 rfapiBgpInfoDetach (wcb
->node
, bi
); /* with removed bi */
2600 vnc_import_bgp_exterior_del_route_interior (bgp
, wcb
->import_table
,
2605 * If VNC is configured to send response remove messages, AND
2606 * if the removed route had a UN address, do response removal
2609 if (!(bgp
->rfapi_cfg
->flags
& BGP_VNC_CONFIG_RESPONSE_REMOVAL_DISABLE
))
2612 int has_valid_duplicate
= 0;
2613 struct bgp_info
*bii
;
2616 * First check if there are any OTHER routes at this node
2617 * that have the same nexthop and a valid UN address. If
2618 * there are (e.g., from other peers), then the route isn't
2619 * really gone, so skip sending a response removal message.
2621 for (bii
= wcb
->node
->info
; bii
; bii
= bii
->next
)
2623 if (rfapiVpnBiSamePtUn (bi
, bii
))
2625 has_valid_duplicate
= 1;
2630 vnc_zlog_debug_verbose ("%s: has_valid_duplicate=%d", __func__
,
2631 has_valid_duplicate
);
2633 if (!has_valid_duplicate
)
2635 rfapiRibPendingDeleteRoute (bgp
, wcb
->import_table
, afi
, wcb
->node
);
2639 rfapiMonitorEncapDelete (bi
);
2642 * If there are no VPN monitors at this VPN Node A,
2645 if (!RFAPI_MONITOR_VPN (wcb
->node
))
2647 vnc_zlog_debug_verbose ("%s: no VPN monitors at this node", __func__
);
2652 * rfapiMonitorMoveShorter only moves monitors if there are
2653 * no remaining valid routes at the current node
2655 moved
= rfapiMonitorMoveShorter (wcb
->node
, 1);
2659 rfapiMonitorMovedUp (wcb
->import_table
, wcb
->node
, moved
->node
, moved
);
2666 rfapiBgpInfoFree (bi
);
2670 * If route count at this node has gone to 0, withdraw exported prefix
2672 if (!wcb
->node
->info
)
2674 /* see if the struct rfapi_it_extra is empty and can be freed */
2675 rfapiMonitorExtraPrune (SAFI_MPLS_VPN
, wcb
->node
);
2676 vnc_direct_bgp_del_prefix (bgp
, wcb
->import_table
, wcb
->node
);
2677 vnc_zebra_del_prefix (bgp
, wcb
->import_table
, wcb
->node
);
2682 * nexthop change event
2683 * vnc_direct_bgp_add_prefix() will recompute the VN addr ecommunity
2685 vnc_direct_bgp_add_prefix (bgp
, wcb
->import_table
, wcb
->node
);
2688 RFAPI_CHECK_REFCOUNT (wcb
->node
, SAFI_MPLS_VPN
, 1 + wcb
->lockoffset
);
2689 route_unlock_node (wcb
->node
); /* decr ref count */
2690 XFREE (MTYPE_RFAPI_WITHDRAW
, wcb
);
2695 * This works for multiprotocol extension, but not for plain ol'
2696 * unicast IPv4 because that nexthop is stored in attr->nexthop
2699 rfapiNexthop2Prefix (struct attr
*attr
, struct prefix
*p
)
2703 assert (attr
->extra
);
2705 memset (p
, 0, sizeof (struct prefix
));
2707 switch (p
->family
= BGP_MP_NEXTHOP_FAMILY (attr
->extra
->mp_nexthop_len
))
2710 p
->u
.prefix4
= attr
->extra
->mp_nexthop_global_in
;
2715 p
->u
.prefix6
= attr
->extra
->mp_nexthop_global
;
2720 vnc_zlog_debug_verbose ("%s: Family is unknown = %d",
2721 __func__
, p
->family
);
2726 rfapiUnicastNexthop2Prefix (afi_t afi
, struct attr
*attr
, struct prefix
*p
)
2730 p
->family
= AF_INET
;
2732 p
->u
.prefix4
= attr
->nexthop
;
2736 rfapiNexthop2Prefix (attr
, p
);
2741 rfapiAttrNexthopAddrDifferent (struct prefix
*p1
, struct prefix
*p2
)
2745 vnc_zlog_debug_verbose ("%s: p1 or p2 is NULL", __func__
);
2750 * Are address families the same?
2752 if (p1
->family
!= p2
->family
)
2760 if (IPV4_ADDR_SAME (&p1
->u
.prefix4
, &p2
->u
.prefix4
))
2765 if (IPV6_ADDR_SAME (&p1
->u
.prefix6
, &p2
->u
.prefix6
))
2778 rfapiCopyUnEncap2VPN (struct bgp_info
*encap_bi
, struct bgp_info
*vpn_bi
)
2780 struct attr_extra
*attre
;
2782 if (!encap_bi
->attr
|| !encap_bi
->attr
->extra
)
2784 zlog_warn ("%s: no encap bi attr/extra, can't copy UN address",
2789 if (!vpn_bi
|| !vpn_bi
->extra
)
2791 zlog_warn ("%s: no vpn bi attr/extra, can't copy UN address",
2796 attre
= encap_bi
->attr
->extra
;
2798 switch (BGP_MP_NEXTHOP_FAMILY (attre
->mp_nexthop_len
))
2803 * instrumentation to debug segfault of 091127
2805 vnc_zlog_debug_verbose ("%s: vpn_bi=%p", __func__
, vpn_bi
);
2808 vnc_zlog_debug_verbose ("%s: vpn_bi->extra=%p", __func__
, vpn_bi
->extra
);
2811 vpn_bi
->extra
->vnc
.import
.un_family
= AF_INET
;
2812 vpn_bi
->extra
->vnc
.import
.un
.addr4
= attre
->mp_nexthop_global_in
;
2816 vpn_bi
->extra
->vnc
.import
.un_family
= AF_INET6
;
2817 vpn_bi
->extra
->vnc
.import
.un
.addr6
= attre
->mp_nexthop_global
;
2821 zlog_warn ("%s: invalid encap nexthop length: %d",
2822 __func__
, attre
->mp_nexthop_len
);
2823 vpn_bi
->extra
->vnc
.import
.un_family
= 0;
2829 * returns 0 on success, nonzero on error
2832 rfapiWithdrawEncapUpdateCachedUn (
2833 struct rfapi_import_table
*import_table
,
2834 struct bgp_info
*encap_bi
,
2835 struct route_node
*vpn_rn
,
2836 struct bgp_info
*vpn_bi
)
2842 * clear cached UN address
2844 if (!vpn_bi
|| !vpn_bi
->extra
)
2846 zlog_warn ("%s: missing VPN bi/extra, can't clear UN addr",
2850 vpn_bi
->extra
->vnc
.import
.un_family
= 0;
2851 memset (&vpn_bi
->extra
->vnc
.import
.un
, 0,
2852 sizeof (vpn_bi
->extra
->vnc
.import
.un
));
2853 if (CHECK_FLAG (vpn_bi
->flags
, BGP_INFO_VALID
))
2855 if (rfapiGetVncTunnelUnAddr (vpn_bi
->attr
, NULL
))
2857 UNSET_FLAG (vpn_bi
->flags
, BGP_INFO_VALID
);
2858 if (VALID_INTERIOR_TYPE (vpn_bi
->type
))
2859 RFAPI_MONITOR_EXTERIOR (vpn_rn
)->valid_interior_count
--;
2860 /* signal interior route withdrawal to import-exterior */
2861 vnc_import_bgp_exterior_del_route_interior (bgp_get_default (),
2872 zlog_warn ("%s: missing VPN bi, can't clear UN addr", __func__
);
2875 rfapiCopyUnEncap2VPN (encap_bi
, vpn_bi
);
2876 if (!CHECK_FLAG (vpn_bi
->flags
, BGP_INFO_VALID
))
2878 SET_FLAG (vpn_bi
->flags
, BGP_INFO_VALID
);
2879 if (VALID_INTERIOR_TYPE (vpn_bi
->type
))
2880 RFAPI_MONITOR_EXTERIOR (vpn_rn
)->valid_interior_count
++;
2881 /* signal interior route withdrawal to import-exterior */
2882 vnc_import_bgp_exterior_add_route_interior (bgp_get_default (),
2891 rfapiWithdrawTimerEncap (struct thread
*t
)
2893 struct rfapi_withdraw
*wcb
= t
->arg
;
2894 struct bgp_info
*bi
= wcb
->info
;
2895 int was_first_route
= 0;
2896 struct rfapi_monitor_encap
*em
;
2897 struct skiplist
*vpn_node_sl
= skiplist_new (0, NULL
, NULL
);
2901 assert (wcb
->import_table
);
2903 RFAPI_CHECK_REFCOUNT (wcb
->node
, SAFI_ENCAP
, 0);
2905 if (wcb
->node
->info
== bi
)
2906 was_first_route
= 1;
2909 * Remove the route/bi and free it
2911 rfapiBgpInfoDetach (wcb
->node
, bi
);
2912 rfapiBgpInfoFree (bi
);
2914 if (!was_first_route
)
2917 for (em
= RFAPI_MONITOR_ENCAP (wcb
->node
); em
; em
= em
->next
)
2921 * Update monitoring VPN BIs with new encap info at the
2922 * head of the encap bi chain (which could be NULL after
2923 * removing the expiring bi above)
2925 if (rfapiWithdrawEncapUpdateCachedUn
2926 (wcb
->import_table
, wcb
->node
->info
, em
->node
, em
->bi
))
2930 * Build a list of unique VPN nodes referenced by these monitors.
2931 * Use a skiplist for speed.
2933 skiplist_insert (vpn_node_sl
, em
->node
, em
->node
);
2938 * for each VPN node referenced in the ENCAP monitors:
2940 struct route_node
*rn
;
2941 while (!skiplist_first (vpn_node_sl
, (void **) &rn
, NULL
))
2943 if (!wcb
->node
->info
)
2945 struct rfapi_monitor_vpn
*moved
;
2947 moved
= rfapiMonitorMoveShorter (rn
, 0);
2950 //rfapiDoRouteCallback(wcb->import_table, moved->node, moved);
2951 rfapiMonitorMovedUp (wcb
->import_table
, rn
, moved
->node
, moved
);
2956 //rfapiDoRouteCallback(wcb->import_table, rn, NULL);
2957 rfapiMonitorItNodeChanged (wcb
->import_table
, rn
, NULL
);
2959 skiplist_delete_first (vpn_node_sl
);
2963 RFAPI_CHECK_REFCOUNT (wcb
->node
, SAFI_ENCAP
, 1);
2964 route_unlock_node (wcb
->node
); /* decr ref count */
2965 XFREE (MTYPE_RFAPI_WITHDRAW
, wcb
);
2966 skiplist_free (vpn_node_sl
);
2972 * Works for both VPN and ENCAP routes; timer_service_func is different
2976 rfapiBiStartWithdrawTimer (
2977 struct rfapi_import_table
*import_table
,
2978 struct route_node
*rn
,
2979 struct bgp_info
*bi
,
2982 int (*timer_service_func
) (struct thread
*))
2985 struct rfapi_withdraw
*wcb
;
2988 (bi
->flags
, BGP_INFO_REMOVED
)
2991 * Already on the path to being withdrawn,
2992 * should already have a timer set up to
2995 vnc_zlog_debug_verbose ("%s: already being withdrawn, do nothing", __func__
);
2999 rfapiGetVncLifetime (bi
->attr
, &lifetime
);
3000 vnc_zlog_debug_verbose ("%s: VNC lifetime is %u", __func__
, lifetime
);
3003 * withdrawn routes get to hang around for a while
3005 SET_FLAG (bi
->flags
, BGP_INFO_REMOVED
);
3007 /* set timer to remove the route later */
3008 lifetime
= rfapiGetHolddownFromLifetime (lifetime
);
3009 vnc_zlog_debug_verbose ("%s: using timeout %u", __func__
, lifetime
);
3012 * Stash import_table, node, and info for use by timer
3013 * service routine, which is supposed to free the wcb.
3015 wcb
= XCALLOC (MTYPE_RFAPI_WITHDRAW
, sizeof (struct rfapi_withdraw
));
3019 wcb
->import_table
= import_table
;
3020 bgp_attr_intern (bi
->attr
);
3022 if (VNC_DEBUG(VERBOSE
))
3024 vnc_zlog_debug_verbose
3025 ("%s: wcb values: node=%p, info=%p, import_table=%p (bi follows)",
3026 __func__
, wcb
->node
, wcb
->info
, wcb
->import_table
);
3027 rfapiPrintBi (NULL
, bi
);
3032 if (lifetime
> UINT32_MAX
/ 1001)
3034 /* sub-optimal case, but will probably never happen */
3035 bi
->extra
->vnc
.import
.timer
= NULL
;
3036 thread_add_timer(bm
->master
, timer_service_func
, wcb
, lifetime
,
3037 &bi
->extra
->vnc
.import
.timer
);
3041 static uint32_t jitter
;
3042 uint32_t lifetime_msec
;
3045 * the goal here is to spread out the timers so they are
3046 * sortable in the skip list
3048 if (++jitter
>= 1000)
3051 lifetime_msec
= (lifetime
* 1000) + jitter
;
3053 bi
->extra
->vnc
.import
.timer
= NULL
;
3054 thread_add_background(bm
->master
, timer_service_func
, wcb
, lifetime_msec
,
3055 &bi
->extra
->vnc
.import
.timer
);
3058 /* re-sort route list (BGP_INFO_REMOVED routes are last) */
3059 if (((struct bgp_info
*) rn
->info
)->next
)
3061 rfapiBgpInfoDetach (rn
, bi
);
3062 rfapiBgpInfoAttachSorted (rn
, bi
, afi
, safi
);
3067 typedef void (rfapi_bi_filtered_import_f
) (struct rfapi_import_table
*,
3076 u_char
, u_char
, uint32_t *);
3080 rfapiExpireEncapNow (
3081 struct rfapi_import_table
*it
,
3082 struct route_node
*rn
,
3083 struct bgp_info
*bi
)
3085 struct rfapi_withdraw
*wcb
;
3089 * pretend we're an expiring timer
3091 wcb
= XCALLOC (MTYPE_RFAPI_WITHDRAW
, sizeof (struct rfapi_withdraw
));
3094 wcb
->import_table
= it
;
3095 memset (&t
, 0, sizeof (t
));
3097 rfapiWithdrawTimerEncap (&t
); /* frees wcb */
3101 rfapiGetNexthop (struct attr
*attr
, struct prefix
*prefix
)
3103 switch (BGP_MP_NEXTHOP_FAMILY (attr
->extra
->mp_nexthop_len
))
3106 prefix
->family
= AF_INET
;
3107 prefix
->prefixlen
= 32;
3108 prefix
->u
.prefix4
= attr
->extra
->mp_nexthop_global_in
;
3111 prefix
->family
= AF_INET6
;
3112 prefix
->prefixlen
= 128;
3113 prefix
->u
.prefix6
= attr
->extra
->mp_nexthop_global
;
3116 vnc_zlog_debug_verbose ("%s: unknown attr->extra->mp_nexthop_len %d", __func__
,
3117 attr
->extra
->mp_nexthop_len
);
3124 * import a bgp_info if its route target list intersects with the
3125 * import table's route target list
3128 rfapiBgpInfoFilteredImportEncap (
3129 struct rfapi_import_table
*import_table
,
3132 void *rfd
, /* set for looped back routes */
3134 struct prefix
*aux_prefix
, /* Unused for encap routes */
3136 struct prefix_rd
*prd
,
3137 struct attr
*attr
, /* part of bgp_info */
3138 u_char type
, /* part of bgp_info */
3139 u_char sub_type
, /* part of bgp_info */
3140 uint32_t *label
) /* part of bgp_info */
3142 struct route_table
*rt
= NULL
;
3143 struct route_node
*rn
;
3144 struct bgp_info
*info_new
;
3145 struct bgp_info
*bi
;
3146 struct bgp_info
*next
;
3149 struct prefix p_firstbi_old
;
3150 struct prefix p_firstbi_new
;
3152 const char *action_str
= NULL
;
3153 struct prefix un_prefix
;
3156 bgp
= bgp_get_default (); /* assume 1 instance for now */
3160 case FIF_ACTION_UPDATE
:
3161 action_str
= "update";
3163 case FIF_ACTION_WITHDRAW
:
3164 action_str
= "withdraw";
3166 case FIF_ACTION_KILL
:
3167 action_str
= "kill";
3174 vnc_zlog_debug_verbose ("%s: entry: %s: prefix %s/%d", __func__
,
3176 inet_ntop (p
->family
, &p
->u
.prefix
, buf
, BUFSIZ
), p
->prefixlen
);
3178 memset (&p_firstbi_old
, 0, sizeof (p_firstbi_old
));
3179 memset (&p_firstbi_new
, 0, sizeof (p_firstbi_new
));
3181 if (action
== FIF_ACTION_UPDATE
)
3184 * Compare rt lists. If no intersection, don't import this route
3185 * On a withdraw, peer and RD are sufficient to determine if
3188 if (!attr
|| !attr
->extra
|| !attr
->extra
->ecommunity
)
3191 vnc_zlog_debug_verbose ("%s: attr, extra, or ecommunity missing, not importing",
3195 #if RFAPI_REQUIRE_ENCAP_BEEC
3196 if (!rfapiEcommunitiesMatchBeec (attr
->extra
->ecommunity
))
3198 vnc_zlog_debug_verbose ("%s: it=%p: no match for BGP Encapsulation ecommunity",
3199 __func__
, import_table
);
3203 if (!rfapiEcommunitiesIntersect (import_table
->rt_import_list
,
3204 attr
->extra
->ecommunity
))
3207 vnc_zlog_debug_verbose ("%s: it=%p: no ecommunity intersection",
3208 __func__
, import_table
);
3213 * Updates must also have a nexthop address
3215 memset (&un_prefix
, 0, sizeof (un_prefix
)); /* keep valgrind happy */
3216 if (rfapiGetNexthop (attr
, &un_prefix
))
3218 vnc_zlog_debug_verbose ("%s: missing nexthop address", __func__
);
3224 * Figure out which radix tree the route would go into
3230 rt
= import_table
->imported_encap
[afi
];
3234 zlog_err ("%s: bad afi %d", __func__
, afi
);
3239 * route_node_lookup returns a node only if there is at least
3240 * one route attached.
3242 rn
= route_node_lookup (rt
, p
);
3244 #if DEBUG_ENCAP_MONITOR
3245 vnc_zlog_debug_verbose ("%s: initial encap lookup (it=%p) rn=%p",
3246 __func__
, import_table
, rn
);
3252 RFAPI_CHECK_REFCOUNT (rn
, SAFI_ENCAP
, 1);
3253 route_unlock_node (rn
); /* undo lock in route_node_lookup */
3257 * capture nexthop of first bi
3261 rfapiNexthop2Prefix (((struct bgp_info
*) (rn
->info
))->attr
,
3265 for (bi
= rn
->info
; bi
; bi
= bi
->next
)
3269 * Does this bgp_info refer to the same route
3270 * as we are trying to add?
3272 vnc_zlog_debug_verbose ("%s: comparing BI %p", __func__
, bi
);
3278 * RD of import table bi is in bi->extra->vnc.import.rd
3279 * RD of info_orig is in prd
3283 vnc_zlog_debug_verbose ("%s: no bi->extra", __func__
);
3286 if (prefix_cmp ((struct prefix
*) &bi
->extra
->vnc
.import
.rd
,
3287 (struct prefix
*) prd
))
3290 vnc_zlog_debug_verbose ("%s: prd does not match", __func__
);
3297 if (bi
->peer
!= peer
)
3299 vnc_zlog_debug_verbose ("%s: peer does not match", __func__
);
3303 vnc_zlog_debug_verbose ("%s: found matching bi", __func__
);
3305 /* Same route. Delete this bi, replace with new one */
3307 if (action
== FIF_ACTION_WITHDRAW
)
3310 vnc_zlog_debug_verbose ("%s: withdrawing at prefix %s/%d",
3312 inet_ntop (rn
->p
.family
, &rn
->p
.u
.prefix
, buf
,
3313 BUFSIZ
), rn
->p
.prefixlen
);
3315 rfapiBiStartWithdrawTimer (import_table
, rn
, bi
,
3317 rfapiWithdrawTimerEncap
);
3322 vnc_zlog_debug_verbose ("%s: %s at prefix %s/%d",
3325 FIF_ACTION_KILL
) ? "killing" : "replacing"),
3326 inet_ntop (rn
->p
.family
, &rn
->p
.u
.prefix
, buf
,
3327 BUFSIZ
), rn
->p
.prefixlen
);
3330 * If this route is waiting to be deleted because of
3331 * a previous withdraw, we must cancel its timer.
3333 if (CHECK_FLAG (bi
->flags
, BGP_INFO_REMOVED
)
3334 && bi
->extra
->vnc
.import
.timer
)
3338 (struct thread
*) bi
->extra
->vnc
.import
.timer
;
3339 struct rfapi_withdraw
*wcb
= t
->arg
;
3341 XFREE (MTYPE_RFAPI_WITHDRAW
, wcb
);
3345 if (action
== FIF_ACTION_UPDATE
)
3347 rfapiBgpInfoDetach (rn
, bi
);
3348 rfapiBgpInfoFree (bi
);
3354 * Kill: do export stuff when removing bi
3356 struct rfapi_withdraw
*wcb
;
3360 * pretend we're an expiring timer
3363 XCALLOC (MTYPE_RFAPI_WITHDRAW
,
3364 sizeof (struct rfapi_withdraw
));
3367 wcb
->import_table
= import_table
;
3368 memset (&t
, 0, sizeof (t
));
3370 rfapiWithdrawTimerEncap (&t
); /* frees wcb */
3379 RFAPI_CHECK_REFCOUNT (rn
, SAFI_ENCAP
, replacing
? 1 : 0);
3381 if (action
== FIF_ACTION_WITHDRAW
|| action
== FIF_ACTION_KILL
)
3384 info_new
= rfapiBgpInfoCreate (attr
, peer
, rfd
, prd
, type
, sub_type
, NULL
);
3389 route_lock_node (rn
); /* incr ref count for new BI */
3393 rn
= route_node_get (rt
, p
);
3396 vnc_zlog_debug_verbose ("%s: (afi=%d, rn=%p) inserting at prefix %s/%d",
3400 inet_ntop (rn
->p
.family
, &rn
->p
.u
.prefix
, buf
, BUFSIZ
),
3403 rfapiBgpInfoAttachSorted (rn
, info_new
, afi
, SAFI_ENCAP
);
3406 * Delete holddown routes from same NVE. See details in
3407 * rfapiBgpInfoFilteredImportVPN()
3409 for (bi
= info_new
->next
; bi
; bi
= next
)
3412 struct prefix pfx_un
;
3416 if (!CHECK_FLAG (bi
->flags
, BGP_INFO_REMOVED
))
3420 * We already match the VN address (it is the prefix
3421 * of the route node)
3424 if (!rfapiGetNexthop (bi
->attr
, &pfx_un
) &&
3425 prefix_same (&pfx_un
, &un_prefix
))
3434 vnc_zlog_debug_verbose ("%s: removing holddown bi matching NVE of new route",
3436 if (bi
->extra
->vnc
.import
.timer
)
3438 struct thread
*t
= (struct thread
*) bi
->extra
->vnc
.import
.timer
;
3439 struct rfapi_withdraw
*wcb
= t
->arg
;
3441 XFREE (MTYPE_RFAPI_WITHDRAW
, wcb
);
3444 rfapiExpireEncapNow (import_table
, rn
, bi
);
3447 rfapiNexthop2Prefix (((struct bgp_info
*) (rn
->info
))->attr
,
3451 * If the nexthop address of the selected Encap route (i.e.,
3452 * the UN address) has changed, then we must update the VPN
3453 * routes that refer to this Encap route and possibly force
3456 if (rfapiAttrNexthopAddrDifferent (&p_firstbi_old
, &p_firstbi_new
))
3459 struct rfapi_monitor_encap
*m
;
3460 struct rfapi_monitor_encap
*mnext
;
3462 struct route_node
*referenced_vpn_prefix
;
3465 * Optimized approach: build radix tree on the fly to
3466 * hold list of VPN nodes referenced by the ENCAP monitors
3468 * The nodes in this table correspond to prefixes of VPN routes.
3469 * The "info" pointer of the node points to a chain of
3470 * struct rfapi_monitor_encap, each of which refers to a
3471 * specific VPN node.
3473 struct route_table
*referenced_vpn_table
;
3475 referenced_vpn_table
= route_table_init ();
3476 assert (referenced_vpn_table
);
3479 * iterate over the set of monitors at this ENCAP node.
3481 #if DEBUG_ENCAP_MONITOR
3482 vnc_zlog_debug_verbose ("%s: examining monitors at rn=%p", __func__
, rn
);
3484 for (m
= RFAPI_MONITOR_ENCAP (rn
); m
; m
= m
->next
)
3488 * For each referenced bi/route, copy the ENCAP route's
3489 * nexthop to the VPN route's cached UN address field and set
3490 * the address family of the cached UN address field.
3492 rfapiCopyUnEncap2VPN (info_new
, m
->bi
);
3493 if (!CHECK_FLAG (m
->bi
->flags
, BGP_INFO_VALID
))
3495 SET_FLAG (m
->bi
->flags
, BGP_INFO_VALID
);
3496 if (VALID_INTERIOR_TYPE (m
->bi
->type
))
3497 RFAPI_MONITOR_EXTERIOR (m
->node
)->valid_interior_count
++;
3498 vnc_import_bgp_exterior_add_route_interior (bgp
,
3504 * Build a list of unique VPN nodes referenced by these monitors
3506 * There could be more than one VPN node here with a given
3507 * prefix. Those are currently in an unsorted linear list
3511 referenced_vpn_prefix
=
3512 route_node_get (referenced_vpn_table
, &m
->node
->p
);
3513 assert (referenced_vpn_prefix
);
3514 for (mnext
= referenced_vpn_prefix
->info
; mnext
;
3515 mnext
= mnext
->next
)
3518 if (mnext
->node
== m
->node
)
3525 * already have an entry for this VPN node
3527 route_unlock_node (referenced_vpn_prefix
);
3531 mnext
= XCALLOC (MTYPE_RFAPI_MONITOR_ENCAP
,
3532 sizeof (struct rfapi_monitor_encap
));
3534 mnext
->node
= m
->node
;
3535 mnext
->next
= referenced_vpn_prefix
->info
;
3536 referenced_vpn_prefix
->info
= mnext
;
3542 * for each VPN node referenced in the ENCAP monitors:
3544 for (referenced_vpn_prefix
= route_top (referenced_vpn_table
);
3545 referenced_vpn_prefix
;
3546 referenced_vpn_prefix
= route_next (referenced_vpn_prefix
))
3549 while ((m
= referenced_vpn_prefix
->info
))
3552 struct route_node
*n
;
3554 rfapiMonitorMoveLonger (m
->node
);
3555 for (n
= m
->node
; n
; n
= n
->parent
)
3557 //rfapiDoRouteCallback(import_table, n, NULL);
3559 rfapiMonitorItNodeChanged (import_table
, m
->node
, NULL
);
3561 referenced_vpn_prefix
->info
= m
->next
;
3562 route_unlock_node (referenced_vpn_prefix
);
3563 XFREE (MTYPE_RFAPI_MONITOR_ENCAP
, m
);
3567 route_table_finish (referenced_vpn_table
);
3570 RFAPI_CHECK_REFCOUNT (rn
, SAFI_ENCAP
, 0);
3575 struct rfapi_import_table
*it
,
3576 struct route_node
*rn
,
3577 struct bgp_info
*bi
,
3580 struct rfapi_withdraw
*wcb
;
3584 * pretend we're an expiring timer
3586 wcb
= XCALLOC (MTYPE_RFAPI_WITHDRAW
, sizeof (struct rfapi_withdraw
));
3589 wcb
->import_table
= it
;
3590 wcb
->lockoffset
= lockoffset
;
3591 memset (&t
, 0, sizeof (t
));
3593 rfapiWithdrawTimerVPN (&t
); /* frees wcb */
3598 * import a bgp_info if its route target list intersects with the
3599 * import table's route target list
3602 rfapiBgpInfoFilteredImportVPN (
3603 struct rfapi_import_table
*import_table
,
3606 void *rfd
, /* set for looped back routes */
3608 struct prefix
*aux_prefix
, /* AFI_L2VPN: optional IP */
3610 struct prefix_rd
*prd
,
3611 struct attr
*attr
, /* part of bgp_info */
3612 u_char type
, /* part of bgp_info */
3613 u_char sub_type
, /* part of bgp_info */
3614 uint32_t *label
) /* part of bgp_info */
3616 struct route_table
*rt
= NULL
;
3617 struct route_node
*rn
;
3618 struct route_node
*n
;
3619 struct bgp_info
*info_new
;
3620 struct bgp_info
*bi
;
3621 struct bgp_info
*next
;
3623 struct prefix vn_prefix
;
3624 struct prefix un_prefix
;
3625 int un_prefix_valid
= 0;
3626 struct route_node
*ern
;
3628 int original_had_routes
= 0;
3629 struct prefix original_nexthop
;
3630 const char *action_str
= NULL
;
3634 bgp
= bgp_get_default (); /* assume 1 instance for now */
3638 case FIF_ACTION_UPDATE
:
3639 action_str
= "update";
3641 case FIF_ACTION_WITHDRAW
:
3642 action_str
= "withdraw";
3644 case FIF_ACTION_KILL
:
3645 action_str
= "kill";
3652 if (import_table
== bgp
->rfapi
->it_ce
)
3655 vnc_zlog_debug_verbose ("%s: entry: %s%s: prefix %s/%d: it %p, afi %s", __func__
,
3656 (is_it_ce
? "CE-IT " : ""),
3658 rfapi_ntop (p
->family
, &p
->u
.prefix
, buf
, BUFSIZ
),
3659 p
->prefixlen
, import_table
, afi2str (afi
));
3664 * Compare rt lists. If no intersection, don't import this route
3665 * On a withdraw, peer and RD are sufficient to determine if
3668 if (action
== FIF_ACTION_UPDATE
)
3670 if (!attr
|| !attr
->extra
|| !attr
->extra
->ecommunity
)
3673 vnc_zlog_debug_verbose ("%s: attr, extra, or ecommunity missing, not importing",
3677 if ((import_table
!= bgp
->rfapi
->it_ce
) &&
3678 !rfapiEcommunitiesIntersect (import_table
->rt_import_list
,
3679 attr
->extra
->ecommunity
))
3682 vnc_zlog_debug_verbose ("%s: it=%p: no ecommunity intersection",
3683 __func__
, import_table
);
3687 memset (&vn_prefix
, 0, sizeof (vn_prefix
)); /* keep valgrind happy */
3688 if (rfapiGetNexthop (attr
, &vn_prefix
))
3690 /* missing nexthop address would be a bad, bad thing */
3691 vnc_zlog_debug_verbose ("%s: missing nexthop", __func__
);
3697 * Figure out which radix tree the route would go into
3704 rt
= import_table
->imported_vpn
[afi
];
3708 zlog_err ("%s: bad afi %d", __func__
, afi
);
3713 memset (&original_nexthop
, 0, sizeof (original_nexthop
));
3716 * route_node_lookup returns a node only if there is at least
3717 * one route attached.
3719 rn
= route_node_lookup (rt
, p
);
3721 vnc_zlog_debug_verbose ("%s: rn=%p", __func__
, rn
);
3726 RFAPI_CHECK_REFCOUNT (rn
, SAFI_MPLS_VPN
, 1);
3727 route_unlock_node (rn
); /* undo lock in route_node_lookup */
3730 original_had_routes
= 1;
3732 if (VNC_DEBUG(VERBOSE
))
3734 vnc_zlog_debug_verbose ("%s: showing IT node on entry", __func__
);
3735 rfapiShowItNode (NULL
, rn
); /* debug */
3739 * Look for same route (will have same RD and peer)
3741 bi
= rfapiItBiIndexSearch (rn
, prd
, peer
, aux_prefix
);
3747 * This was an old test when we iterated over the
3748 * BIs linearly. Since we're now looking up with
3749 * RD and peer, comparing types should not be
3750 * needed. Changed to assertion.
3752 * Compare types. Doing so prevents a RFP-originated
3753 * route from matching an imported route, for example.
3755 assert (bi
->type
== type
);
3757 vnc_zlog_debug_verbose ("%s: found matching bi", __func__
);
3760 * In the special CE table, withdrawals occur without holddown
3762 if (import_table
== bgp
->rfapi
->it_ce
)
3764 vnc_direct_bgp_del_route_ce (bgp
, rn
, bi
);
3765 if (action
== FIF_ACTION_WITHDRAW
)
3766 action
= FIF_ACTION_KILL
;
3769 if (action
== FIF_ACTION_WITHDRAW
)
3772 int washolddown
= CHECK_FLAG (bi
->flags
, BGP_INFO_REMOVED
);
3774 vnc_zlog_debug_verbose ("%s: withdrawing at prefix %s/%d%s",
3776 rfapi_ntop (rn
->p
.family
, &rn
->p
.u
.prefix
, buf
,
3777 BUFSIZ
), rn
->p
.prefixlen
,
3778 (washolddown
? " (already being withdrawn)" : ""));
3783 rfapiBiStartWithdrawTimer (import_table
, rn
, bi
,
3785 rfapiWithdrawTimerVPN
);
3787 RFAPI_UPDATE_ITABLE_COUNT (bi
, import_table
, afi
, -1);
3788 import_table
->holddown_count
[afi
] += 1;
3794 vnc_zlog_debug_verbose ("%s: %s at prefix %s/%d",
3797 FIF_ACTION_KILL
) ? "killing" : "replacing"),
3798 rfapi_ntop (rn
->p
.family
, &rn
->p
.u
.prefix
, buf
,
3799 BUFSIZ
), rn
->p
.prefixlen
);
3802 * If this route is waiting to be deleted because of
3803 * a previous withdraw, we must cancel its timer.
3805 if (CHECK_FLAG (bi
->flags
, BGP_INFO_REMOVED
) &&
3806 bi
->extra
->vnc
.import
.timer
)
3810 (struct thread
*) bi
->extra
->vnc
.import
.timer
;
3811 struct rfapi_withdraw
*wcb
= t
->arg
;
3813 XFREE (MTYPE_RFAPI_WITHDRAW
, wcb
);
3816 import_table
->holddown_count
[afi
] -= 1;
3817 RFAPI_UPDATE_ITABLE_COUNT (bi
, import_table
, afi
, 1);
3820 * decrement remote count (if route is remote) because
3821 * we are going to remove it below
3823 RFAPI_UPDATE_ITABLE_COUNT (bi
, import_table
, afi
, -1);
3824 if (action
== FIF_ACTION_UPDATE
)
3829 * make copy of original nexthop so we can see if it changed
3831 rfapiGetNexthop (bi
->attr
, &original_nexthop
);
3834 * remove bi without doing any export processing
3836 if (CHECK_FLAG (bi
->flags
, BGP_INFO_VALID
)
3837 && VALID_INTERIOR_TYPE (bi
->type
))
3838 RFAPI_MONITOR_EXTERIOR (rn
)->valid_interior_count
--;
3839 rfapiItBiIndexDel (rn
, bi
);
3840 rfapiBgpInfoDetach (rn
, bi
);
3841 rfapiMonitorEncapDelete (bi
);
3842 vnc_import_bgp_exterior_del_route_interior (bgp
,
3845 rfapiBgpInfoFree (bi
);
3851 * remove bi and do export processing
3853 import_table
->holddown_count
[afi
] += 1;
3854 rfapiExpireVpnNow (import_table
, rn
, bi
, 0);
3863 RFAPI_CHECK_REFCOUNT (rn
, SAFI_MPLS_VPN
, replacing
? 1 : 0);
3865 if (action
== FIF_ACTION_WITHDRAW
|| action
== FIF_ACTION_KILL
)
3871 info_new
= rfapiBgpInfoCreate (attr
, peer
, rfd
, prd
, type
, sub_type
, label
);
3874 * lookup un address in encap table
3876 ern
= route_node_match (import_table
->imported_encap
[afi
], &vn_prefix
);
3879 rfapiCopyUnEncap2VPN (ern
->info
, info_new
);
3880 route_unlock_node (ern
); /* undo lock in route_note_match */
3885 prefix2str (&vn_prefix
, buf
, sizeof (buf
));
3886 buf
[BUFSIZ
- 1] = 0;
3887 /* Not a big deal, just means VPN route got here first */
3888 vnc_zlog_debug_verbose ("%s: no encap route for vn addr %s", __func__
, buf
);
3889 info_new
->extra
->vnc
.import
.un_family
= 0;
3895 route_lock_node (rn
);
3900 * No need to increment reference count, so only "get"
3901 * if the node is not there already
3903 rn
= route_node_get (rt
, p
);
3907 * For ethernet routes, if there is an accompanying IP address,
3910 if ((AFI_L2VPN
== afi
) && aux_prefix
)
3913 vnc_zlog_debug_verbose ("%s: setting BI's aux_prefix", __func__
);
3914 info_new
->extra
->vnc
.import
.aux_prefix
= *aux_prefix
;
3917 vnc_zlog_debug_verbose ("%s: inserting bi %p at prefix %s/%d #%d",
3920 rfapi_ntop (rn
->p
.family
, &rn
->p
.u
.prefix
, buf
, BUFSIZ
),
3921 rn
->p
.prefixlen
, rn
->lock
);
3923 rfapiBgpInfoAttachSorted (rn
, info_new
, afi
, SAFI_MPLS_VPN
);
3924 rfapiItBiIndexAdd (rn
, info_new
);
3925 if (!rfapiGetUnAddrOfVpnBi (info_new
, NULL
))
3927 if (VALID_INTERIOR_TYPE (info_new
->type
))
3928 RFAPI_MONITOR_EXTERIOR (rn
)->valid_interior_count
++;
3929 SET_FLAG (info_new
->flags
, BGP_INFO_VALID
);
3931 RFAPI_UPDATE_ITABLE_COUNT (info_new
, import_table
, afi
, 1);
3932 vnc_import_bgp_exterior_add_route_interior (bgp
, import_table
, rn
,
3935 if (import_table
== bgp
->rfapi
->it_ce
)
3936 vnc_direct_bgp_add_route_ce (bgp
, rn
, info_new
);
3938 if (VNC_DEBUG(VERBOSE
))
3940 vnc_zlog_debug_verbose ("%s: showing IT node", __func__
);
3941 rfapiShowItNode (NULL
, rn
); /* debug */
3944 rfapiMonitorEncapAdd (import_table
, &vn_prefix
, rn
, info_new
);
3946 if (!rfapiGetUnAddrOfVpnBi (info_new
, &un_prefix
))
3950 * if we have a valid UN address (either via Encap route
3951 * or via tunnel attribute), then we should attempt
3952 * to move any monitors at less-specific nodes to this node
3954 rfapiMonitorMoveLonger (rn
);
3956 un_prefix_valid
= 1;
3961 * 101129 Enhancement: if we add a route (implication: it is not
3962 * in holddown), delete all other routes from this nve at this
3963 * node that are in holddown, regardless of peer.
3965 * Reasons it's OK to do that:
3967 * - if the holddown route being deleted originally came from BGP VPN,
3968 * it is already gone from BGP (implication of holddown), so there
3969 * won't be any added inconsistency with the BGP RIB.
3971 * - once a fresh route is added at a prefix, any routes in holddown
3972 * at that prefix will not show up in RFP responses, so deleting
3973 * the holddown routes won't affect the contents of responses.
3975 * - lifetimes are supposed to be consistent, so there should not
3976 * be a case where the fresh route has a shorter lifetime than
3977 * the holddown route, so we don't expect the fresh route to
3978 * disappear and complete its holddown time before the existing
3979 * holddown routes time out. Therefore, we won't have a situation
3980 * where we expect the existing holddown routes to be hidden and
3981 * then to reappear sometime later (as holddown routes) in a
3984 * Among other things, this would enable us to skirt the problem
3985 * of local holddown routes that refer to NVE descriptors that
3986 * have already been closed (if the same NVE triggers a subsequent
3987 * rfapi_open(), the new peer is different and doesn't match the
3988 * peer of the holddown route, so the stale holddown route still
3989 * hangs around until it times out instead of just being replaced
3990 * by the fresh route).
3993 * We know that the new bi will have been inserted before any routes
3994 * in holddown, so we can skip any that came before it
3996 for (bi
= info_new
->next
; bi
; bi
= next
)
3999 struct prefix pfx_vn
;
4000 struct prefix pfx_un
;
4002 int remote_peer_match
= 0;
4009 if (!CHECK_FLAG (bi
->flags
, BGP_INFO_REMOVED
))
4013 * Must match VN address (nexthop of VPN route)
4015 if (rfapiGetNexthop (bi
->attr
, &pfx_vn
))
4017 if (!prefix_same (&pfx_vn
, &vn_prefix
))
4020 if (un_prefix_valid
&& /* new route UN addr */
4021 !rfapiGetUnAddrOfVpnBi (bi
, &pfx_un
) && /* old route UN addr */
4022 prefix_same (&pfx_un
, &un_prefix
))
4026 if (!RFAPI_LOCAL_BI (bi
) && !RFAPI_LOCAL_BI (info_new
) &&
4027 sockunion_same (&bi
->peer
->su
, &info_new
->peer
->su
))
4029 /* old & new are both remote, same peer */
4030 remote_peer_match
= 1;
4033 if (!un_match
& !remote_peer_match
)
4036 vnc_zlog_debug_verbose ("%s: removing holddown bi matching NVE of new route",
4038 if (bi
->extra
->vnc
.import
.timer
)
4040 struct thread
*t
= (struct thread
*) bi
->extra
->vnc
.import
.timer
;
4041 struct rfapi_withdraw
*wcb
= t
->arg
;
4043 XFREE (MTYPE_RFAPI_WITHDRAW
, wcb
);
4046 rfapiExpireVpnNow (import_table
, rn
, bi
, 0);
4049 if (!original_had_routes
)
4052 * We went from 0 usable routes to 1 usable route. Perform the
4053 * "Adding a Route" export process.
4055 vnc_direct_bgp_add_prefix (bgp
, import_table
, rn
);
4056 vnc_zebra_add_prefix (bgp
, import_table
, rn
);
4061 * Check for nexthop change event
4062 * Note: the prefix_same() test below detects two situations:
4063 * 1. route is replaced, new route has different nexthop
4064 * 2. new route is added (original_nexthop is 0)
4066 struct prefix new_nexthop
;
4068 rfapiGetNexthop (attr
, &new_nexthop
);
4069 if (!prefix_same (&original_nexthop
, &new_nexthop
))
4072 * nexthop change event
4073 * vnc_direct_bgp_add_prefix() will recompute VN addr ecommunity
4075 vnc_direct_bgp_add_prefix (bgp
, import_table
, rn
);
4079 if (!(bgp
->rfapi_cfg
->flags
& BGP_VNC_CONFIG_CALLBACK_DISABLE
))
4081 for (n
= rn
; n
; n
= n
->parent
)
4083 //rfapiDoRouteCallback(import_table, n, NULL);
4085 rfapiMonitorItNodeChanged (import_table
, rn
, NULL
);
4087 RFAPI_CHECK_REFCOUNT (rn
, SAFI_MPLS_VPN
, 0);
4091 static rfapi_bi_filtered_import_f
*
4092 rfapiBgpInfoFilteredImportFunction (safi_t safi
)
4097 return rfapiBgpInfoFilteredImportVPN
;
4100 return rfapiBgpInfoFilteredImportEncap
;
4102 zlog_err ("%s: bad safi %d", __func__
, safi
);
4107 rfapiProcessUpdate (
4109 void *rfd
, /* set when looped from RFP/RFAPI */
4111 struct prefix_rd
*prd
,
4121 struct rfapi_import_table
*it
;
4122 int has_ip_route
= 1;
4125 bgp
= bgp_get_default (); /* assume 1 instance for now */
4132 * look at high-order byte of RD. FF means MAC
4133 * address is present (VNC L2VPN)
4135 if ((safi
== SAFI_MPLS_VPN
) &&
4136 (decode_rd_type(prd
->val
) == RD_TYPE_VNC_ETH
))
4138 struct prefix pfx_mac_buf
;
4139 struct prefix pfx_nexthop_buf
;
4143 * Set flag if prefix and nexthop are the same - don't
4144 * add the route to normal IP-based import tables
4146 if (!rfapiGetNexthop (attr
, &pfx_nexthop_buf
))
4148 if (!prefix_cmp (&pfx_nexthop_buf
, p
))
4154 memset (&pfx_mac_buf
, 0, sizeof (pfx_mac_buf
));
4155 pfx_mac_buf
.family
= AF_ETHERNET
;
4156 pfx_mac_buf
.prefixlen
= 48;
4157 memcpy (&pfx_mac_buf
.u
.prefix_eth
.octet
, prd
->val
+ 2, 6);
4160 * Find rt containing LNI (Logical Network ID), which
4161 * _should_ always be present when mac address is present
4163 rc
= rfapiEcommunityGetLNI (attr
->extra
->ecommunity
, &lni
);
4165 vnc_zlog_debug_verbose
4166 ("%s: rfapiEcommunityGetLNI returned %d, lni=%d, attr=%p, attr->extra=%p",
4167 __func__
, rc
, lni
, attr
, attr
->extra
);
4168 if (attr
&& attr
->extra
&& !rc
)
4170 it
= rfapiMacImportTableGet (bgp
, lni
);
4172 rfapiBgpInfoFilteredImportVPN (
4177 &pfx_mac_buf
, /* prefix */
4178 p
, /* aux prefix: IP addr */
4193 * Iterate over all import tables; do a filtered import
4194 * for the afi/safi combination
4196 for (it
= h
->imports
; it
; it
= it
->next
)
4198 (*rfapiBgpInfoFilteredImportFunction (safi
)) (
4213 if (safi
== SAFI_MPLS_VPN
)
4215 vnc_direct_bgp_rh_add_route (bgp
, afi
, p
, peer
, attr
);
4218 if (safi
== SAFI_MPLS_VPN
)
4220 rfapiBgpInfoFilteredImportVPN (
4238 rfapiProcessWithdraw (
4242 struct prefix_rd
*prd
,
4251 struct rfapi_import_table
*it
;
4253 bgp
= bgp_get_default (); /* assume 1 instance for now */
4260 * look at high-order byte of RD. FF means MAC
4261 * address is present (VNC L2VPN)
4263 if (h
->import_mac
!= NULL
&& safi
== SAFI_MPLS_VPN
&&
4264 decode_rd_type(prd
->val
) == RD_TYPE_VNC_ETH
)
4266 struct prefix pfx_mac_buf
;
4267 void *cursor
= NULL
;
4270 memset (&pfx_mac_buf
, 0, sizeof (pfx_mac_buf
));
4271 pfx_mac_buf
.family
= AF_ETHERNET
;
4272 pfx_mac_buf
.prefixlen
= 48;
4273 memcpy (&pfx_mac_buf
.u
.prefix_eth
, prd
->val
+ 2, 6);
4276 * withdraw does not contain attrs, so we don't have
4277 * access to the route's LNI, which would ordinarily
4278 * select the specific mac-based import table. Instead,
4279 * we must iterate over all mac-based tables and rely
4280 * on the RD to match.
4282 * If this approach is too slow, add an index where
4283 * key is {RD, peer} and value is the import table
4285 for (rc
= skiplist_next (h
->import_mac
, NULL
, (void **) &it
, &cursor
);
4287 rc
= skiplist_next (h
->import_mac
, NULL
, (void **) &it
, &cursor
))
4291 vnc_zlog_debug_verbose
4292 ("%s: calling rfapiBgpInfoFilteredImportVPN(it=%p, afi=AFI_L2VPN)",
4296 rfapiBgpInfoFilteredImportVPN (
4298 (kill
? FIF_ACTION_KILL
: FIF_ACTION_WITHDRAW
),
4301 &pfx_mac_buf
, /* prefix */
4302 p
, /* aux_prefix: IP */
4308 NULL
); /* sub_type & label unused for withdraw */
4313 * XXX For the case where the withdraw involves an L2
4314 * route with no IP information, we rely on the lack
4315 * of RT-list intersection to filter out the withdraw
4316 * from the IP-based import tables below
4320 * Iterate over all import tables; do a filtered import
4321 * for the afi/safi combination
4324 for (it
= h
->imports
; it
; it
= it
->next
)
4326 (*rfapiBgpInfoFilteredImportFunction (safi
)) (
4328 (kill
? FIF_ACTION_KILL
: FIF_ACTION_WITHDRAW
),
4338 NULL
); /* sub_type & label unused for withdraw */
4341 /* TBD the deletion should happen after the lifetime expires */
4342 if (safi
== SAFI_MPLS_VPN
)
4343 vnc_direct_bgp_rh_del_route (bgp
, afi
, p
, peer
);
4345 if (safi
== SAFI_MPLS_VPN
)
4347 rfapiBgpInfoFilteredImportVPN (
4349 (kill
? FIF_ACTION_KILL
: FIF_ACTION_WITHDRAW
),
4359 NULL
); /* sub_type & label unused for withdraw */
4364 * TBD optimized withdraw timer algorithm for case of many
4365 * routes expiring at the same time due to peer drop.
4368 * 1. Visit all BIs in all ENCAP import tables.
4370 * a. If a bi's peer is the failed peer, remove the bi.
4371 * b. If the removed ENCAP bi was first in the list of
4372 * BIs at this ENCAP node, loop over all monitors
4375 * (1) for each ENCAP monitor, loop over all its
4376 * VPN node monitors and set their RFAPI_MON_FLAG_NEEDCALLBACK
4379 * 2. Visit all BIs in all VPN import tables.
4380 * a. If a bi's peer is the failed peer, remove the bi.
4381 * b. loop over all the VPN node monitors and set their
4382 * RFAPI_MON_FLAG_NEEDCALLBACK flags
4383 * c. If there are no BIs left at this VPN node,
4388 /* surprise, this gets called from peer_delete(), from rfapi_close() */
4390 rfapiProcessPeerDownRt (
4392 struct rfapi_import_table
*import_table
,
4396 struct route_node
*rn
;
4397 struct bgp_info
*bi
;
4398 struct route_table
*rt
;
4399 int (*timer_service_func
) (struct thread
*);
4401 assert (afi
== AFI_IP
|| afi
== AFI_IP6
);
4408 rt
= import_table
->imported_vpn
[afi
];
4409 timer_service_func
= rfapiWithdrawTimerVPN
;
4412 rt
= import_table
->imported_encap
[afi
];
4413 timer_service_func
= rfapiWithdrawTimerEncap
;
4420 for (rn
= route_top (rt
); rn
; rn
= route_next (rn
))
4422 for (bi
= rn
->info
; bi
; bi
= bi
->next
)
4424 if (bi
->peer
== peer
)
4427 if (CHECK_FLAG (bi
->flags
, BGP_INFO_REMOVED
))
4429 /* already in holddown, skip */
4433 if (safi
== SAFI_MPLS_VPN
)
4435 RFAPI_UPDATE_ITABLE_COUNT (bi
, import_table
, afi
, -1);
4436 import_table
->holddown_count
[afi
] += 1;
4438 rfapiBiStartWithdrawTimer (import_table
, rn
, bi
,
4440 timer_service_func
);
4448 * This gets called when a peer connection drops. We have to remove
4449 * all the routes from this peer.
4451 * Current approach is crude. TBD Optimize by setting fewer timers and
4452 * grouping withdrawn routes so we can generate callbacks more
4456 rfapiProcessPeerDown (struct peer
*peer
)
4460 struct rfapi_import_table
*it
;
4463 * If this peer is a "dummy" peer structure atached to a RFAPI
4464 * nve_descriptor, we don't need to walk the import tables
4465 * because the routes are already withdrawn by rfapi_close()
4467 if (CHECK_FLAG (peer
->flags
, PEER_FLAG_IS_RFAPI_HD
))
4471 * 1. Visit all BIs in all ENCAP import tables.
4472 * Start withdraw timer on the BIs that match peer.
4474 * 2. Visit All BIs in all VPN import tables.
4475 * Start withdraw timer on the BIs that match peer.
4478 bgp
= bgp_get_default (); /* assume 1 instance for now */
4485 for (it
= h
->imports
; it
; it
= it
->next
)
4487 rfapiProcessPeerDownRt (peer
, it
, AFI_IP
, SAFI_ENCAP
);
4488 rfapiProcessPeerDownRt (peer
, it
, AFI_IP6
, SAFI_ENCAP
);
4489 rfapiProcessPeerDownRt (peer
, it
, AFI_IP
, SAFI_MPLS_VPN
);
4490 rfapiProcessPeerDownRt (peer
, it
, AFI_IP6
, SAFI_MPLS_VPN
);
4495 rfapiProcessPeerDownRt (peer
, h
->it_ce
, AFI_IP
, SAFI_MPLS_VPN
);
4496 rfapiProcessPeerDownRt (peer
, h
->it_ce
, AFI_IP6
, SAFI_MPLS_VPN
);
4501 * Import an entire RIB (for an afi/safi) to an import table RIB,
4502 * filtered according to the import table's RT list
4504 * TBD: does this function need additions to match rfapiProcessUpdate()
4505 * for, e.g., L2 handling?
4508 rfapiBgpTableFilteredImport (
4510 struct rfapi_import_table
*it
,
4514 struct bgp_node
*rn1
;
4515 struct bgp_node
*rn2
;
4517 /* Only these SAFIs have 2-level RIBS */
4518 assert (safi
== SAFI_MPLS_VPN
|| safi
== SAFI_ENCAP
);
4521 * Now visit all the rd nodes and the nodes of all the
4522 * route tables attached to them, and import the routes
4523 * if they have matching route targets
4525 for (rn1
= bgp_table_top (bgp
->rib
[afi
][safi
]);
4526 rn1
; rn1
= bgp_route_next (rn1
))
4531 for (rn2
= bgp_table_top (rn1
->info
);
4532 rn2
; rn2
= bgp_route_next (rn2
))
4535 struct bgp_info
*bi
;
4537 for (bi
= rn2
->info
; bi
; bi
= bi
->next
)
4539 u_int32_t label
= 0;
4541 if (CHECK_FLAG (bi
->flags
, BGP_INFO_REMOVED
))
4545 label
= decode_label (bi
->extra
->tag
);
4546 (*rfapiBgpInfoFilteredImportFunction (safi
)) (
4547 it
, /* which import table */
4551 &rn2
->p
, /* prefix */
4554 (struct prefix_rd
*) &rn1
->p
,
4566 /* per-bgp-instance rfapi data */
4568 bgp_rfapi_new (struct bgp
*bgp
)
4572 struct rfapi_rfp_cfg
*cfg
= NULL
;
4573 struct rfapi_rfp_cb_methods
*cbm
= NULL
;
4575 assert (bgp
->rfapi_cfg
== NULL
);
4577 h
= (struct rfapi
*) XCALLOC (MTYPE_RFAPI
, sizeof (struct rfapi
));
4579 for (afi
= AFI_IP
; afi
< AFI_MAX
; afi
++)
4581 /* ugly, to deal with addition of delegates, part of 0.99.24.1 merge */
4582 h
->un
[afi
].delegate
= route_table_get_default_delegate ();
4586 * initialize the ce import table
4589 XCALLOC (MTYPE_RFAPI_IMPORTTABLE
, sizeof (struct rfapi_import_table
));
4590 h
->it_ce
->imported_vpn
[AFI_IP
] = route_table_init ();
4591 h
->it_ce
->imported_vpn
[AFI_IP6
] = route_table_init ();
4592 h
->it_ce
->imported_encap
[AFI_IP
] = route_table_init ();
4593 h
->it_ce
->imported_encap
[AFI_IP6
] = route_table_init ();
4594 rfapiBgpTableFilteredImport (bgp
, h
->it_ce
, AFI_IP
, SAFI_MPLS_VPN
);
4595 rfapiBgpTableFilteredImport (bgp
, h
->it_ce
, AFI_IP6
, SAFI_MPLS_VPN
);
4598 * Set up work queue for deferred rfapi_close operations
4600 h
->deferred_close_q
= work_queue_new (bm
->master
, "rfapi deferred close");
4601 h
->deferred_close_q
->spec
.workfunc
= rfapi_deferred_close_workfunc
;
4602 h
->deferred_close_q
->spec
.data
= h
;
4604 h
->rfp
= rfp_start (bm
->master
, &cfg
, &cbm
);
4605 bgp
->rfapi_cfg
= bgp_rfapi_cfg_new (cfg
);
4608 h
->rfp_methods
= *cbm
;
4614 bgp_rfapi_destroy (struct bgp
*bgp
, struct rfapi
*h
)
4616 if (bgp
== NULL
|| h
== NULL
)
4619 if (h
->resolve_nve_nexthop
)
4621 skiplist_free (h
->resolve_nve_nexthop
);
4622 h
->resolve_nve_nexthop
= NULL
;
4625 route_table_finish (h
->it_ce
->imported_vpn
[AFI_IP
]);
4626 route_table_finish (h
->it_ce
->imported_vpn
[AFI_IP6
]);
4627 route_table_finish (h
->it_ce
->imported_encap
[AFI_IP
]);
4628 route_table_finish (h
->it_ce
->imported_encap
[AFI_IP6
]);
4632 struct rfapi_import_table
*it
;
4637 rc
= skiplist_next (h
->import_mac
, NULL
, (void **) &it
, &cursor
);
4639 rc
= skiplist_next (h
->import_mac
, NULL
, (void **) &it
, &cursor
))
4642 rfapiImportTableFlush (it
);
4643 XFREE (MTYPE_RFAPI_IMPORTTABLE
, it
);
4645 skiplist_free (h
->import_mac
);
4646 h
->import_mac
= NULL
;
4649 work_queue_free (h
->deferred_close_q
);
4653 XFREE (MTYPE_RFAPI_IMPORTTABLE
, h
->it_ce
);
4654 XFREE (MTYPE_RFAPI
, h
);
4657 struct rfapi_import_table
*
4658 rfapiImportTableRefAdd (struct bgp
*bgp
, struct ecommunity
*rt_import_list
,
4659 struct rfapi_nve_group_cfg
*rfg
)
4662 struct rfapi_import_table
*it
;
4668 for (it
= h
->imports
; it
; it
= it
->next
)
4670 if (ecommunity_cmp (it
->rt_import_list
, rt_import_list
))
4674 vnc_zlog_debug_verbose ("%s: matched it=%p", __func__
, it
);
4679 XCALLOC (MTYPE_RFAPI_IMPORTTABLE
, sizeof (struct rfapi_import_table
));
4681 it
->next
= h
->imports
;
4684 it
->rt_import_list
= ecommunity_dup (rt_import_list
);
4686 it
->monitor_exterior_orphans
=
4687 skiplist_new (0, NULL
, (void (*)(void *)) prefix_free
);
4690 * fill import route tables from RIBs
4692 * Potential area for optimization. If this occurs when
4693 * tables are large (e.g., the operator adds a nve group
4694 * with a new RT list to a running system), it could take
4698 for (afi
= AFI_IP
; afi
< AFI_MAX
; ++afi
)
4701 it
->imported_vpn
[afi
] = route_table_init ();
4702 it
->imported_encap
[afi
] = route_table_init ();
4704 rfapiBgpTableFilteredImport (bgp
, it
, afi
, SAFI_MPLS_VPN
);
4705 rfapiBgpTableFilteredImport (bgp
, it
, afi
, SAFI_ENCAP
);
4707 vnc_import_bgp_exterior_redist_enable_it (bgp
, afi
, it
);
4717 * skiplist element free function
4720 delete_rem_pfx_na_free (void *na
)
4722 uint32_t *pCounter
= ((struct rfapi_nve_addr
*) na
)->info
;
4725 XFREE (MTYPE_RFAPI_NVE_ADDR
, na
);
4729 * Common deleter for IP and MAC import tables
4732 rfapiDeleteRemotePrefixesIt (
4734 struct rfapi_import_table
*it
,
4739 int delete_holddown
,
4744 struct skiplist
*uniq_active_nves
,
4745 struct skiplist
*uniq_holddown_nves
)
4751 char buf_pfx
[BUFSIZ
];
4755 prefix2str (p
, buf_pfx
, BUFSIZ
);
4763 vnc_zlog_debug_verbose ("%s: entry, p=%s, delete_active=%d, delete_holddown=%d",
4764 __func__
, buf_pfx
, delete_active
, delete_holddown
);
4768 for (afi
= AFI_IP
; afi
< AFI_MAX
; ++afi
)
4771 struct route_table
*rt
;
4772 struct route_node
*rn
;
4774 if (p
&& (family2afi (p
->family
) != afi
))
4779 rt
= it
->imported_vpn
[afi
];
4783 vnc_zlog_debug_verbose ("%s: scanning rt for afi=%d", __func__
, afi
);
4785 for (rn
= route_top (rt
); rn
; rn
= route_next (rn
))
4787 struct bgp_info
*bi
;
4788 struct bgp_info
*next
;
4790 if (VNC_DEBUG(IMPORT_DEL_REMOTE
))
4792 char p1line
[BUFSIZ
];
4793 char p2line
[BUFSIZ
];
4795 prefix2str (p
, p1line
, BUFSIZ
);
4796 prefix2str (&rn
->p
, p2line
, BUFSIZ
);
4797 vnc_zlog_debug_any ("%s: want %s, have %s", __func__
, p1line
, p2line
);
4800 if (p
&& prefix_cmp (p
, &rn
->p
))
4804 char buf_pfx
[BUFSIZ
];
4805 prefix2str (&rn
->p
, buf_pfx
, BUFSIZ
);
4806 vnc_zlog_debug_verbose ("%s: rn pfx=%s", __func__
, buf_pfx
);
4809 /* TBD is this valid for afi == AFI_L2VPN? */
4810 RFAPI_CHECK_REFCOUNT (rn
, SAFI_MPLS_VPN
, 1);
4812 for (bi
= rn
->info
; bi
; bi
= next
)
4822 vnc_zlog_debug_verbose ("%s: examining bi %p", __func__
, bi
);
4826 if (!rfapiGetNexthop (bi
->attr
, &qpt
))
4831 if (!qpt_valid
|| !prefix_match (vn
, &qpt
))
4834 vnc_zlog_debug_verbose
4835 ("%s: continue at vn && !qpt_valid || !prefix_match(vn, &qpt)",
4842 if (!rfapiGetUnAddrOfVpnBi (bi
, &qct
))
4847 if (!qct_valid
|| !prefix_match (un
, &qct
))
4850 vnc_zlog_debug_verbose
4851 ("%s: continue at un && !qct_valid || !prefix_match(un, &qct)",
4863 * If this route is waiting to be deleted because of
4864 * a previous withdraw, we must cancel its timer.
4866 if (CHECK_FLAG (bi
->flags
, BGP_INFO_REMOVED
))
4868 if (!delete_holddown
)
4870 if (bi
->extra
->vnc
.import
.timer
)
4874 (struct thread
*) bi
->extra
->vnc
.import
.timer
;
4875 struct rfapi_withdraw
*wcb
= t
->arg
;
4877 wcb
->import_table
->holddown_count
[afi
] -= 1;
4878 RFAPI_UPDATE_ITABLE_COUNT (bi
, wcb
->import_table
, afi
,
4880 XFREE (MTYPE_RFAPI_WITHDRAW
, wcb
);
4891 vnc_zlog_debug_verbose
4892 ("%s: deleting bi %p (qct_valid=%d, qpt_valid=%d, delete_holddown=%d, delete_active=%d)",
4893 __func__
, bi
, qct_valid
, qpt_valid
, delete_holddown
,
4900 if (qct_valid
&& qpt_valid
)
4903 struct rfapi_nve_addr na
;
4904 struct rfapi_nve_addr
*nap
;
4906 memset (&na
, 0, sizeof (na
));
4907 assert (!rfapiQprefix2Raddr (&qct
, &na
.un
));
4908 assert (!rfapiQprefix2Raddr (&qpt
, &na
.vn
));
4910 if (skiplist_search ((is_active
? uniq_active_nves
:
4911 uniq_holddown_nves
), &na
,
4916 nap
= XCALLOC (MTYPE_RFAPI_NVE_ADDR
,
4917 sizeof (struct rfapi_nve_addr
));
4920 nap
->info
= is_active
? pAHcount
: pHHcount
;
4921 skiplist_insert ((is_active
? uniq_active_nves
:
4922 uniq_holddown_nves
), nap
, nap
);
4924 rfapiNveAddr2Str (nap
, line
, BUFSIZ
);
4928 vnc_direct_bgp_rh_del_route (bgp
, afi
, &rn
->p
, bi
->peer
);
4930 RFAPI_UPDATE_ITABLE_COUNT (bi
, it
, afi
, -1);
4931 it
->holddown_count
[afi
] += 1;
4932 rfapiExpireVpnNow (it
, rn
, bi
, 1);
4934 vnc_zlog_debug_verbose ("%s: incrementing count (is_active=%d)",
4935 __func__
, is_active
);
4948 * For use by the "clear vnc prefixes" command
4950 /*------------------------------------------
4951 * rfapiDeleteRemotePrefixes
4953 * UI helper: For use by the "clear vnc prefixes" command
4956 * un if set, tunnel must match this prefix
4957 * vn if set, nexthop prefix must match this prefix
4958 * p if set, prefix must match this prefix
4959 * it if set, only look in this import table
4962 * pARcount number of active routes deleted
4963 * pAHcount number of active nves deleted
4964 * pHRcount number of holddown routes deleted
4965 * pHHcount number of holddown nves deleted
4969 --------------------------------------------*/
4971 rfapiDeleteRemotePrefixes (
4975 struct rfapi_import_table
*arg_it
,
4977 int delete_holddown
,
4985 struct rfapi_import_table
*it
;
4986 uint32_t deleted_holddown_route_count
= 0;
4987 uint32_t deleted_active_route_count
= 0;
4988 uint32_t deleted_holddown_nve_count
= 0;
4989 uint32_t deleted_active_nve_count
= 0;
4990 struct skiplist
*uniq_holddown_nves
;
4991 struct skiplist
*uniq_active_nves
;
4995 bgp
= bgp_get_default (); /* assume 1 instance for now */
4996 /* If no bgp instantiated yet, no vnc prefixes exist */
5003 uniq_holddown_nves
=
5004 skiplist_new (0, rfapi_nve_addr_cmp
, delete_rem_pfx_na_free
);
5006 skiplist_new (0, rfapi_nve_addr_cmp
, delete_rem_pfx_na_free
);
5009 * Iterate over all import tables; do a filtered import
5010 * for the afi/safi combination
5020 vnc_zlog_debug_verbose
5021 ("%s: calling rfapiDeleteRemotePrefixesIt() on (IP) import %p",
5024 rfapiDeleteRemotePrefixesIt (
5032 &deleted_active_route_count
,
5033 &deleted_active_nve_count
,
5034 &deleted_holddown_route_count
,
5035 &deleted_holddown_nve_count
,
5037 uniq_holddown_nves
);
5046 * Now iterate over L2 import tables
5048 if (h
->import_mac
&& !(p
&& (p
->family
!= AF_ETHERNET
)))
5051 void *cursor
= NULL
;
5055 rc
= skiplist_next (h
->import_mac
, NULL
, (void **) &it
, &cursor
);
5057 rc
= skiplist_next (h
->import_mac
, NULL
, (void **) &it
, &cursor
))
5060 vnc_zlog_debug_verbose
5061 ("%s: calling rfapiDeleteRemotePrefixesIt() on import_mac %p",
5064 rfapiDeleteRemotePrefixesIt (
5072 &deleted_active_route_count
,
5073 &deleted_active_nve_count
,
5074 &deleted_holddown_route_count
,
5075 &deleted_holddown_nve_count
,
5077 uniq_holddown_nves
);
5082 * our custom element freeing function above counts as it deletes
5084 skiplist_free (uniq_holddown_nves
);
5085 skiplist_free (uniq_active_nves
);
5088 *pARcount
= deleted_active_route_count
;
5090 *pAHcount
= deleted_active_nve_count
;
5092 *pHRcount
= deleted_holddown_route_count
;
5094 *pHHcount
= deleted_holddown_nve_count
;
5099 /*------------------------------------------
5100 * rfapiCountRemoteRoutes
5102 * UI helper: count VRF routes from BGP side
5107 * pALRcount count of active local routes
5108 * pARRcount count of active remote routes
5109 * pHRcount count of holddown routes
5110 * pIRcount count of direct imported routes
5114 --------------------------------------------*/
5116 rfapiCountAllItRoutes (int *pALRcount
, /* active local routes */
5117 int *pARRcount
, /* active remote routes */
5118 int *pHRcount
, /* holddown routes */
5119 int *pIRcount
) /* imported routes */
5123 struct rfapi_import_table
*it
;
5126 int total_active_local
= 0;
5127 int total_active_remote
= 0;
5128 int total_holddown
= 0;
5129 int total_imported
= 0;
5131 bgp
= bgp_get_default (); /* assume 1 instance for now */
5138 * Iterate over all import tables; do a filtered import
5139 * for the afi/safi combination
5142 for (it
= h
->imports
; it
; it
= it
->next
)
5145 for (afi
= AFI_IP
; afi
< AFI_MAX
; ++afi
)
5148 total_active_local
+= it
->local_count
[afi
];
5149 total_active_remote
+= it
->remote_count
[afi
];
5150 total_holddown
+= it
->holddown_count
[afi
];
5151 total_imported
+= it
->imported_count
[afi
];
5162 rc
= skiplist_next (h
->import_mac
, NULL
, (void **) &it
, &cursor
);
5164 rc
= skiplist_next (h
->import_mac
, NULL
, (void **) &it
, &cursor
))
5167 total_active_local
+= it
->local_count
[AFI_L2VPN
];
5168 total_active_remote
+= it
->remote_count
[AFI_L2VPN
];
5169 total_holddown
+= it
->holddown_count
[AFI_L2VPN
];
5170 total_imported
+= it
->imported_count
[AFI_L2VPN
];
5178 *pALRcount
= total_active_local
;
5182 *pARRcount
= total_active_remote
;
5186 *pHRcount
= total_holddown
;
5190 *pIRcount
= total_imported
;
5194 /*------------------------------------------
5195 * rfapiGetHolddownFromLifetime
5197 * calculate holddown value based on lifetime
5203 * Holddown value based on lifetime, holddown_factor,
5204 * and RFAPI_LIFETIME_INFINITE_WITHDRAW_DELAY
5206 --------------------------------------------*/
5207 /* hold down time maxes out at RFAPI_LIFETIME_INFINITE_WITHDRAW_DELAY */
5209 rfapiGetHolddownFromLifetime (uint32_t lifetime
)
5214 bgp
= bgp_get_default ();
5215 if (bgp
&& bgp
->rfapi_cfg
)
5216 factor
= bgp
->rfapi_cfg
->rfp_cfg
.holddown_factor
;
5218 factor
= RFAPI_RFP_CFG_DEFAULT_HOLDDOWN_FACTOR
;
5220 if (factor
< 100 || lifetime
< RFAPI_LIFETIME_INFINITE_WITHDRAW_DELAY
)
5221 lifetime
= lifetime
* factor
/ 100;
5222 if (lifetime
< RFAPI_LIFETIME_INFINITE_WITHDRAW_DELAY
)
5225 return RFAPI_LIFETIME_INFINITE_WITHDRAW_DELAY
;