1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* EVPN Multihoming procedures
4 * Copyright (C) 2019 Cumulus Networks, Inc.
21 #include "lib/printfrr.h"
23 #include "bgpd/bgp_attr_evpn.h"
24 #include "bgpd/bgpd.h"
25 #include "bgpd/bgp_table.h"
26 #include "bgpd/bgp_route.h"
27 #include "bgpd/bgp_attr.h"
28 #include "bgpd/bgp_mplsvpn.h"
29 #include "bgpd/bgp_evpn.h"
30 #include "bgpd/bgp_evpn_private.h"
31 #include "bgpd/bgp_evpn_mh.h"
32 #include "bgpd/bgp_ecommunity.h"
33 #include "bgpd/bgp_encap_types.h"
34 #include "bgpd/bgp_debug.h"
35 #include "bgpd/bgp_errors.h"
36 #include "bgpd/bgp_aspath.h"
37 #include "bgpd/bgp_zebra.h"
38 #include "bgpd/bgp_addpath.h"
39 #include "bgpd/bgp_label.h"
40 #include "bgpd/bgp_nht.h"
41 #include "bgpd/bgp_mpath.h"
42 #include "bgpd/bgp_trace.h"
44 static void bgp_evpn_local_es_down(struct bgp
*bgp
,
45 struct bgp_evpn_es
*es
);
46 static void bgp_evpn_local_type1_evi_route_del(struct bgp
*bgp
,
47 struct bgp_evpn_es
*es
);
48 static struct bgp_evpn_es_vtep
*bgp_evpn_es_vtep_add(struct bgp
*bgp
,
49 struct bgp_evpn_es
*es
,
50 struct in_addr vtep_ip
,
51 bool esr
, uint8_t df_alg
,
53 static void bgp_evpn_es_vtep_del(struct bgp
*bgp
,
54 struct bgp_evpn_es
*es
, struct in_addr vtep_ip
, bool esr
);
55 static void bgp_evpn_es_cons_checks_pend_add(struct bgp_evpn_es
*es
);
56 static void bgp_evpn_es_cons_checks_pend_del(struct bgp_evpn_es
*es
);
57 static struct bgp_evpn_es_evi
*
58 bgp_evpn_local_es_evi_do_del(struct bgp_evpn_es_evi
*es_evi
);
59 static uint32_t bgp_evpn_es_get_active_vtep_cnt(struct bgp_evpn_es
*es
);
60 static void bgp_evpn_l3nhg_update_on_vtep_chg(struct bgp_evpn_es
*es
);
61 static struct bgp_evpn_es
*bgp_evpn_es_new(struct bgp
*bgp
, const esi_t
*esi
);
62 static void bgp_evpn_es_free(struct bgp_evpn_es
*es
, const char *caller
);
63 static void bgp_evpn_path_es_unlink(struct bgp_path_es_info
*es_info
);
64 static void bgp_evpn_mac_update_on_es_local_chg(struct bgp_evpn_es
*es
,
67 esi_t zero_esi_buf
, *zero_esi
= &zero_esi_buf
;
68 static void bgp_evpn_run_consistency_checks(struct event
*t
);
69 static void bgp_evpn_path_nh_info_free(struct bgp_path_evpn_nh_info
*nh_info
);
70 static void bgp_evpn_path_nh_unlink(struct bgp_path_evpn_nh_info
*nh_info
);
72 /******************************************************************************
73 * per-ES (Ethernet Segment) routing table
75 * Following routes are added to the ES's routing table -
76 * 1. Local and remote ESR (Type-4)
77 * 2. Local EAD-per-ES (Type-1).
79 * Key for these routes is {ESI, VTEP-IP} so the path selection is practically
80 * a no-op i.e. all paths lead to same VTEP-IP (i.e. result in the same VTEP
81 * being added to same ES).
83 * Note the following routes go into the VNI routing table (instead of the
85 * 1. Remote EAD-per-ES
86 * 2. Local and remote EAD-per-EVI
89 /* Calculate the best path for a multi-homing (Type-1 or Type-4) route
90 * installed in the ES's routing table.
92 static int bgp_evpn_es_route_select_install(struct bgp
*bgp
,
93 struct bgp_evpn_es
*es
,
94 struct bgp_dest
*dest
)
97 afi_t afi
= AFI_L2VPN
;
98 safi_t safi
= SAFI_EVPN
;
99 struct bgp_path_info
*old_select
; /* old best */
100 struct bgp_path_info
*new_select
; /* new best */
101 struct bgp_path_info_pair old_and_new
;
103 /* Compute the best path. */
104 bgp_best_selection(bgp
, dest
, &bgp
->maxpaths
[afi
][safi
], &old_and_new
,
106 old_select
= old_and_new
.old
;
107 new_select
= old_and_new
.new;
110 * If the best path hasn't changed - see if something needs to be
113 if (old_select
&& old_select
== new_select
114 && old_select
->type
== ZEBRA_ROUTE_BGP
115 && old_select
->sub_type
== BGP_ROUTE_IMPORTED
116 && !CHECK_FLAG(dest
->flags
, BGP_NODE_USER_CLEAR
)
117 && !CHECK_FLAG(old_select
->flags
, BGP_PATH_ATTR_CHANGED
)
118 && !bgp_addpath_is_addpath_used(&bgp
->tx_addpath
, afi
, safi
)) {
119 if (bgp_zebra_has_route_changed(old_select
)) {
120 bgp_evpn_es_vtep_add(bgp
, es
, old_select
->attr
->nexthop
,
122 old_select
->attr
->df_alg
,
123 old_select
->attr
->df_pref
);
125 UNSET_FLAG(old_select
->flags
, BGP_PATH_MULTIPATH_CHG
);
126 bgp_zebra_clear_route_change_flags(dest
);
130 /* If the user did a "clear" this flag will be set */
131 UNSET_FLAG(dest
->flags
, BGP_NODE_USER_CLEAR
);
133 /* bestpath has changed; update relevant fields and install or uninstall
134 * into the zebra RIB.
136 if (old_select
|| new_select
)
137 bgp_bump_version(dest
);
140 bgp_path_info_unset_flag(dest
, old_select
, BGP_PATH_SELECTED
);
142 bgp_path_info_set_flag(dest
, new_select
, BGP_PATH_SELECTED
);
143 bgp_path_info_unset_flag(dest
, new_select
,
144 BGP_PATH_ATTR_CHANGED
);
145 UNSET_FLAG(new_select
->flags
, BGP_PATH_MULTIPATH_CHG
);
148 if (new_select
&& new_select
->type
== ZEBRA_ROUTE_BGP
149 && new_select
->sub_type
== BGP_ROUTE_IMPORTED
) {
150 bgp_evpn_es_vtep_add(bgp
, es
, new_select
->attr
->nexthop
,
151 true /*esr */, new_select
->attr
->df_alg
,
152 new_select
->attr
->df_pref
);
154 if (old_select
&& old_select
->type
== ZEBRA_ROUTE_BGP
155 && old_select
->sub_type
== BGP_ROUTE_IMPORTED
)
156 bgp_evpn_es_vtep_del(
157 bgp
, es
, old_select
->attr
->nexthop
,
161 /* Clear any route change flags. */
162 bgp_zebra_clear_route_change_flags(dest
);
164 /* Reap old select bgp_path_info, if it has been removed */
165 if (old_select
&& CHECK_FLAG(old_select
->flags
, BGP_PATH_REMOVED
))
166 bgp_path_info_reap(dest
, old_select
);
171 /* Install Type-1/Type-4 route entry in the per-ES routing table */
172 static int bgp_evpn_es_route_install(struct bgp
*bgp
,
173 struct bgp_evpn_es
*es
, struct prefix_evpn
*p
,
174 struct bgp_path_info
*parent_pi
)
177 struct bgp_dest
*dest
= NULL
;
178 struct bgp_path_info
*pi
= NULL
;
179 struct attr
*attr_new
= NULL
;
181 /* Create (or fetch) route within the VNI.
182 * NOTE: There is no RD here.
184 dest
= bgp_node_get(es
->route_table
, (struct prefix
*)p
);
186 /* Check if route entry is already present. */
187 for (pi
= bgp_dest_get_bgp_path_info(dest
); pi
; pi
= pi
->next
)
189 (struct bgp_path_info
*)pi
->extra
->parent
== parent_pi
)
193 /* Add (or update) attribute to hash. */
194 attr_new
= bgp_attr_intern(parent_pi
->attr
);
196 /* Create new route with its attribute. */
197 pi
= info_make(parent_pi
->type
, BGP_ROUTE_IMPORTED
, 0,
198 parent_pi
->peer
, attr_new
, dest
);
199 SET_FLAG(pi
->flags
, BGP_PATH_VALID
);
200 bgp_path_info_extra_get(pi
);
201 pi
->extra
->parent
= bgp_path_info_lock(parent_pi
);
202 bgp_dest_lock_node((struct bgp_dest
*)parent_pi
->net
);
203 bgp_path_info_add(dest
, pi
);
205 if (attrhash_cmp(pi
->attr
, parent_pi
->attr
)
206 && !CHECK_FLAG(pi
->flags
, BGP_PATH_REMOVED
)) {
207 bgp_dest_unlock_node(dest
);
210 /* The attribute has changed. */
211 /* Add (or update) attribute to hash. */
212 attr_new
= bgp_attr_intern(parent_pi
->attr
);
214 /* Restore route, if needed. */
215 if (CHECK_FLAG(pi
->flags
, BGP_PATH_REMOVED
))
216 bgp_path_info_restore(dest
, pi
);
218 /* Mark if nexthop has changed. */
219 if (!IPV4_ADDR_SAME(&pi
->attr
->nexthop
, &attr_new
->nexthop
))
220 SET_FLAG(pi
->flags
, BGP_PATH_IGP_CHANGED
);
222 /* Unintern existing, set to new. */
223 bgp_attr_unintern(&pi
->attr
);
225 pi
->uptime
= monotime(NULL
);
228 /* Perform route selection and update zebra, if required. */
229 ret
= bgp_evpn_es_route_select_install(bgp
, es
, dest
);
231 bgp_dest_unlock_node(dest
);
236 /* Uninstall Type-1/Type-4 route entry from the ES routing table */
237 static int bgp_evpn_es_route_uninstall(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
238 struct prefix_evpn
*p
, struct bgp_path_info
*parent_pi
)
241 struct bgp_dest
*dest
;
242 struct bgp_path_info
*pi
;
244 if (!es
->route_table
)
247 /* Locate route within the ESI.
248 * NOTE: There is no RD here.
250 dest
= bgp_node_lookup(es
->route_table
, (struct prefix
*)p
);
254 /* Find matching route entry. */
255 for (pi
= bgp_dest_get_bgp_path_info(dest
); pi
; pi
= pi
->next
)
257 && (struct bgp_path_info
*)pi
->extra
->parent
==
262 bgp_dest_unlock_node(dest
);
266 /* Mark entry for deletion */
267 bgp_path_info_delete(dest
, pi
);
269 /* Perform route selection and update zebra, if required. */
270 ret
= bgp_evpn_es_route_select_install(bgp
, es
, dest
);
272 /* Unlock route node. */
273 bgp_dest_unlock_node(dest
);
278 /* Install or unistall a Type-4 route in the per-ES routing table */
279 int bgp_evpn_es_route_install_uninstall(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
280 afi_t afi
, safi_t safi
, struct prefix_evpn
*evp
,
281 struct bgp_path_info
*pi
, int install
)
286 ret
= bgp_evpn_es_route_install(bgp
, es
, evp
, pi
);
288 ret
= bgp_evpn_es_route_uninstall(bgp
, es
, evp
, pi
);
293 "%u: Failed to %s EVPN %s route in ESI %s",
295 install
? "install" : "uninstall",
302 /* Delete (and withdraw) local routes for specified ES from global and ES table.
303 * Also remove all remote routes from the per ES table. Invoked when ES
306 static void bgp_evpn_es_route_del_all(struct bgp
*bgp
, struct bgp_evpn_es
*es
)
308 struct bgp_dest
*dest
;
309 struct bgp_path_info
*pi
, *nextpi
;
311 /* de-activate the ES */
312 bgp_evpn_local_es_down(bgp
, es
);
313 bgp_evpn_local_type1_evi_route_del(bgp
, es
);
315 /* Walk this ES's routing table and delete all routes. */
316 for (dest
= bgp_table_top(es
->route_table
); dest
;
317 dest
= bgp_route_next(dest
)) {
318 for (pi
= bgp_dest_get_bgp_path_info(dest
);
319 (pi
!= NULL
) && (nextpi
= pi
->next
, 1); pi
= nextpi
) {
320 bgp_path_info_delete(dest
, pi
);
321 bgp_path_info_reap(dest
, pi
);
326 /*****************************************************************************
327 * Base APIs for creating MH routes (Type-1 or Type-4) on local ethernet
331 /* create or update local EVPN type1/type4 route entry.
334 * the ES table if ESR/EAD-ES (or)
335 * the VNI table if EAD-EVI (or)
336 * the global table if ESR/EAD-ES/EAD-EVI
338 * Note: vpn is applicable only to EAD-EVI routes (NULL for EAD-ES and
341 int bgp_evpn_mh_route_update(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
342 struct bgpevpn
*vpn
, afi_t afi
, safi_t safi
,
343 struct bgp_dest
*dest
, struct attr
*attr
,
344 struct bgp_path_info
**ri
, int *route_changed
)
346 struct bgp_path_info
*tmp_pi
= NULL
;
347 struct bgp_path_info
*local_pi
= NULL
; /* local route entry if any */
348 struct bgp_path_info
*remote_pi
= NULL
; /* remote route entry if any */
349 struct attr
*attr_new
= NULL
;
350 struct prefix_evpn
*evp
;
353 evp
= (struct prefix_evpn
*)bgp_dest_get_prefix(dest
);
356 /* locate the local and remote entries if any */
357 for (tmp_pi
= bgp_dest_get_bgp_path_info(dest
); tmp_pi
;
358 tmp_pi
= tmp_pi
->next
) {
359 if (tmp_pi
->peer
== bgp
->peer_self
360 && tmp_pi
->type
== ZEBRA_ROUTE_BGP
361 && tmp_pi
->sub_type
== BGP_ROUTE_STATIC
)
363 if (tmp_pi
->type
== ZEBRA_ROUTE_BGP
364 && tmp_pi
->sub_type
== BGP_ROUTE_IMPORTED
365 && CHECK_FLAG(tmp_pi
->flags
, BGP_PATH_VALID
))
369 /* we don't expect to see a remote_pi at this point as
370 * an ES route has {esi, vtep_ip} as the key in the ES-rt-table
371 * in the VNI-rt-table.
376 "%u ERROR: local es route for ESI: %s vtep %pI4 also learnt from remote",
377 bgp
->vrf_id
, es
? es
->esi_str
: "Null",
378 es
? &es
->originator_ip
: NULL
);
382 /* create or update the entry */
385 /* Add or update attribute to hash */
386 attr_new
= bgp_attr_intern(attr
);
388 /* Create new route with its attribute. */
389 tmp_pi
= info_make(ZEBRA_ROUTE_BGP
, BGP_ROUTE_STATIC
, 0,
390 bgp
->peer_self
, attr_new
, dest
);
391 SET_FLAG(tmp_pi
->flags
, BGP_PATH_VALID
);
393 if (evp
->prefix
.route_type
== BGP_EVPN_AD_ROUTE
) {
394 bgp_path_info_extra_get(tmp_pi
);
395 tmp_pi
->extra
->num_labels
= 1;
397 vni2label(vpn
->vni
, &tmp_pi
->extra
->label
[0]);
399 tmp_pi
->extra
->label
[0] = 0;
402 /* add the newly created path to the route-node */
403 bgp_path_info_add(dest
, tmp_pi
);
406 if (attrhash_cmp(tmp_pi
->attr
, attr
)
407 && !CHECK_FLAG(tmp_pi
->flags
, BGP_PATH_REMOVED
))
410 /* The attribute has changed.
411 * Add (or update) attribute to hash.
413 attr_new
= bgp_attr_intern(attr
);
414 bgp_path_info_set_flag(dest
, tmp_pi
,
415 BGP_PATH_ATTR_CHANGED
);
417 /* Restore route, if needed. */
418 if (CHECK_FLAG(tmp_pi
->flags
, BGP_PATH_REMOVED
))
419 bgp_path_info_restore(dest
, tmp_pi
);
421 /* Unintern existing, set to new. */
422 bgp_attr_unintern(&tmp_pi
->attr
);
423 tmp_pi
->attr
= attr_new
;
424 tmp_pi
->uptime
= monotime(NULL
);
428 if (*route_changed
) {
429 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
431 "local ES %s vni %u route-type %s nexthop %pI4 updated",
432 es
? es
->esi_str
: "Null", vpn
? vpn
->vni
: 0,
433 evp
->prefix
.route_type
== BGP_EVPN_ES_ROUTE
435 : (vpn
? "ead-evi" : "ead-es"),
436 &attr
->mp_nexthop_global_in
);
439 /* Return back the route entry. */
444 /* Delete local EVPN ESR (type-4) and EAD (type-1) route
446 * Note: vpn is applicable only to EAD-EVI routes (NULL for EAD-ES and
449 static int bgp_evpn_mh_route_delete(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
451 struct bgp_evpn_es_frag
*es_frag
,
452 struct prefix_evpn
*p
)
454 afi_t afi
= AFI_L2VPN
;
455 safi_t safi
= SAFI_EVPN
;
456 struct bgp_path_info
*pi
;
457 struct bgp_dest
*dest
= NULL
; /* dest in esi table */
458 struct bgp_dest
*global_dest
= NULL
; /* dest in global table */
459 struct bgp_table
*rt_table
;
460 struct prefix_rd
*prd
;
463 rt_table
= vpn
->ip_table
;
466 rt_table
= es
->route_table
;
470 /* First, locate the route node within the ESI or VNI.
471 * If it doesn't exist, ther is nothing to do.
472 * Note: there is no RD here.
474 dest
= bgp_node_lookup(rt_table
, (struct prefix
*)p
);
478 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
480 "local ES %s vni %u route-type %s nexthop %pI4 delete",
481 es
->esi_str
, vpn
? vpn
->vni
: 0,
482 p
->prefix
.route_type
== BGP_EVPN_ES_ROUTE
484 : (vpn
? "ead-evi" : "ead-es"),
487 /* Next, locate route node in the global EVPN routing table.
488 * Note that this table is a 2-level tree (RD-level + Prefix-level)
490 global_dest
= bgp_evpn_global_node_lookup(bgp
->rib
[afi
][safi
], safi
, p
,
494 /* Delete route entry in the global EVPN table. */
495 delete_evpn_route_entry(bgp
, afi
, safi
, global_dest
, &pi
);
497 /* Schedule for processing - withdraws to peers happen from
501 bgp_process(bgp
, global_dest
, afi
, safi
);
502 bgp_dest_unlock_node(global_dest
);
506 * Delete route entry in the ESI or VNI routing table.
507 * This can just be removed.
509 delete_evpn_route_entry(bgp
, afi
, safi
, dest
, &pi
);
511 bgp_path_info_reap(dest
, pi
);
512 bgp_dest_unlock_node(dest
);
517 * This function is called when the VNI RD changes.
518 * Delete all EAD/EVI local routes for this VNI from the global routing table.
519 * These routes are scheduled for withdraw from peers.
521 int delete_global_ead_evi_routes(struct bgp
*bgp
, struct bgpevpn
*vpn
)
525 struct bgp_dest
*rdrn
, *rn
;
526 struct bgp_table
*table
;
527 struct bgp_path_info
*pi
;
532 /* Find the RD node for the VNI in the global table */
533 rdrn
= bgp_node_lookup(bgp
->rib
[afi
][safi
], (struct prefix
*)&vpn
->prd
);
534 if (rdrn
&& bgp_dest_has_bgp_path_info_data(rdrn
)) {
535 table
= bgp_dest_get_bgp_table_info(rdrn
);
538 * Iterate over all the routes in this table and delete EAD/EVI
541 for (rn
= bgp_table_top(table
); rn
; rn
= bgp_route_next(rn
)) {
542 struct prefix_evpn
*evp
= (struct prefix_evpn
*)&rn
->p
;
544 if (evp
->prefix
.route_type
!= BGP_EVPN_AD_ROUTE
)
547 delete_evpn_route_entry(bgp
, afi
, safi
, rn
, &pi
);
549 bgp_process(bgp
, rn
, afi
, safi
);
553 /* Unlock RD node. */
555 bgp_dest_unlock_node(rdrn
);
560 /*****************************************************************************
561 * Ethernet Segment (Type-4) Routes
562 * ESRs are used for DF election. Currently service-carving described in
563 * RFC 7432 is NOT supported. Instead preference based DF election is
565 * Reference: draft-ietf-bess-evpn-pref-df
567 /* Build extended community for EVPN ES (type-4) route */
568 static void bgp_evpn_type4_route_extcomm_build(struct bgp_evpn_es
*es
,
571 struct ecommunity ecom_encap
;
572 struct ecommunity ecom_es_rt
;
573 struct ecommunity ecom_df
;
574 struct ecommunity_val eval
;
575 struct ecommunity_val eval_es_rt
;
576 struct ecommunity_val eval_df
;
577 bgp_encap_types tnl_type
;
581 tnl_type
= BGP_ENCAP_TYPE_VXLAN
;
582 memset(&ecom_encap
, 0, sizeof(ecom_encap
));
583 encode_encap_extcomm(tnl_type
, &eval
);
585 ecom_encap
.unit_size
= ECOMMUNITY_SIZE
;
586 ecom_encap
.val
= (uint8_t *)eval
.val
;
587 bgp_attr_set_ecommunity(attr
, ecommunity_dup(&ecom_encap
));
590 memset(&mac
, 0, sizeof(mac
));
591 memset(&ecom_es_rt
, 0, sizeof(ecom_es_rt
));
592 es_get_system_mac(&es
->esi
, &mac
);
593 encode_es_rt_extcomm(&eval_es_rt
, &mac
);
595 ecom_es_rt
.unit_size
= ECOMMUNITY_SIZE
;
596 ecom_es_rt
.val
= (uint8_t *)eval_es_rt
.val
;
597 bgp_attr_set_ecommunity(
599 ecommunity_merge(bgp_attr_get_ecommunity(attr
), &ecom_es_rt
));
601 /* DF election extended community */
602 memset(&ecom_df
, 0, sizeof(ecom_df
));
603 encode_df_elect_extcomm(&eval_df
, es
->df_pref
);
605 ecom_df
.val
= (uint8_t *)eval_df
.val
;
606 bgp_attr_set_ecommunity(
608 ecommunity_merge(bgp_attr_get_ecommunity(attr
), &ecom_df
));
611 /* Create or update local type-4 route */
612 static int bgp_evpn_type4_route_update(struct bgp
*bgp
,
613 struct bgp_evpn_es
*es
, struct prefix_evpn
*p
)
616 int route_changed
= 0;
617 afi_t afi
= AFI_L2VPN
;
618 safi_t safi
= SAFI_EVPN
;
620 struct attr
*attr_new
= NULL
;
621 struct bgp_dest
*dest
= NULL
;
622 struct bgp_path_info
*pi
= NULL
;
624 memset(&attr
, 0, sizeof(attr
));
626 /* Build path-attribute for this route. */
627 bgp_attr_default_set(&attr
, bgp
, BGP_ORIGIN_IGP
);
628 attr
.nexthop
= es
->originator_ip
;
629 attr
.mp_nexthop_global_in
= es
->originator_ip
;
630 attr
.mp_nexthop_len
= BGP_ATTR_NHLEN_IPV4
;
632 /* Set up extended community. */
633 bgp_evpn_type4_route_extcomm_build(es
, &attr
);
635 /* First, create (or fetch) route node within the ESI. */
636 /* NOTE: There is no RD here. */
637 dest
= bgp_node_get(es
->route_table
, (struct prefix
*)p
);
639 /* Create or update route entry. */
640 ret
= bgp_evpn_mh_route_update(bgp
, es
, NULL
, afi
, safi
, dest
, &attr
,
641 &pi
, &route_changed
);
645 "%u ERROR: Failed to updated ES route ESI: %s VTEP %pI4",
646 bgp
->vrf_id
, es
->esi_str
, &es
->originator_ip
);
651 /* Perform route selection;
652 * this is just to set the flags correctly
653 * as local route in the ES always wins.
655 bgp_evpn_es_route_select_install(bgp
, es
, dest
);
656 bgp_dest_unlock_node(dest
);
658 /* If this is a new route or some attribute has changed, export the
659 * route to the global table. The route will be advertised to peers
660 * from there. Note that this table is a 2-level tree (RD-level +
661 * Prefix-level) similar to L3VPN routes.
664 struct bgp_path_info
*global_pi
;
666 dest
= bgp_evpn_global_node_get(bgp
->rib
[afi
][safi
], afi
, safi
,
667 p
, &es
->es_base_frag
->prd
,
669 bgp_evpn_mh_route_update(bgp
, es
, NULL
, afi
, safi
, dest
,
670 attr_new
, &global_pi
, &route_changed
);
672 /* Schedule for processing and unlock node. */
673 bgp_process(bgp
, dest
, afi
, safi
);
674 bgp_dest_unlock_node(dest
);
677 /* Unintern temporary. */
678 aspath_unintern(&attr
.aspath
);
682 /* Delete local type-4 route */
683 static int bgp_evpn_type4_route_delete(struct bgp
*bgp
,
684 struct bgp_evpn_es
*es
, struct prefix_evpn
*p
)
686 if (!es
->es_base_frag
)
689 return bgp_evpn_mh_route_delete(bgp
, es
, NULL
/* l2vni */,
690 es
->es_base_frag
, p
);
693 /* Process remote/received EVPN type-4 route (advertise or withdraw) */
694 int bgp_evpn_type4_route_process(struct peer
*peer
, afi_t afi
, safi_t safi
,
695 struct attr
*attr
, uint8_t *pfx
, int psize
,
700 struct in_addr vtep_ip
;
701 struct prefix_rd prd
;
702 struct prefix_evpn p
;
704 /* Type-4 route should be either 23 or 35 bytes
705 * RD (8), ESI (10), ip-len (1), ip (4 or 16)
707 if (psize
!= BGP_EVPN_TYPE4_V4_PSIZE
&&
708 psize
!= BGP_EVPN_TYPE4_V6_PSIZE
) {
709 flog_err(EC_BGP_EVPN_ROUTE_INVALID
,
710 "%u:%s - Rx EVPN Type-4 NLRI with invalid length %d",
711 peer
->bgp
->vrf_id
, peer
->host
, psize
);
716 prd
.family
= AF_UNSPEC
;
718 memcpy(&prd
.val
, pfx
, RD_BYTES
);
722 memcpy(&esi
, pfx
, ESI_BYTES
);
728 if (ipaddr_len
== IPV4_MAX_BITLEN
) {
729 memcpy(&vtep_ip
, pfx
, IPV4_MAX_BYTELEN
);
732 EC_BGP_EVPN_ROUTE_INVALID
,
733 "%u:%s - Rx EVPN Type-4 NLRI with unsupported IP address length %d",
734 peer
->bgp
->vrf_id
, peer
->host
, ipaddr_len
);
738 build_evpn_type4_prefix(&p
, &esi
, vtep_ip
);
739 /* Process the route. */
741 bgp_update(peer
, (struct prefix
*)&p
, addpath_id
, attr
, afi
,
742 safi
, ZEBRA_ROUTE_BGP
, BGP_ROUTE_NORMAL
, &prd
, NULL
,
745 bgp_withdraw(peer
, (struct prefix
*)&p
, addpath_id
, afi
, safi
,
746 ZEBRA_ROUTE_BGP
, BGP_ROUTE_NORMAL
, &prd
, NULL
, 0,
752 /* Check if a prefix belongs to the local ES */
753 static bool bgp_evpn_type4_prefix_match(struct prefix_evpn
*p
,
754 struct bgp_evpn_es
*es
)
756 return (p
->prefix
.route_type
== BGP_EVPN_ES_ROUTE
) &&
757 !memcmp(&p
->prefix
.es_addr
.esi
, &es
->esi
, sizeof(esi_t
));
760 /* Import remote ESRs on local ethernet segment add */
761 static int bgp_evpn_type4_remote_routes_import(struct bgp
*bgp
,
762 struct bgp_evpn_es
*es
, bool install
)
767 struct bgp_dest
*rd_dest
, *dest
;
768 struct bgp_table
*table
;
769 struct bgp_path_info
*pi
;
774 /* Walk entire global routing table and evaluate routes which could be
775 * imported into this Ethernet Segment.
777 for (rd_dest
= bgp_table_top(bgp
->rib
[afi
][safi
]); rd_dest
;
778 rd_dest
= bgp_route_next(rd_dest
)) {
779 table
= bgp_dest_get_bgp_table_info(rd_dest
);
783 for (dest
= bgp_table_top(table
); dest
;
784 dest
= bgp_route_next(dest
)) {
785 struct prefix_evpn
*evp
=
786 (struct prefix_evpn
*)bgp_dest_get_prefix(dest
);
788 for (pi
= bgp_dest_get_bgp_path_info(dest
); pi
;
791 * Consider "valid" remote routes applicable for
794 if (!(CHECK_FLAG(pi
->flags
, BGP_PATH_VALID
)
795 && pi
->type
== ZEBRA_ROUTE_BGP
796 && pi
->sub_type
== BGP_ROUTE_NORMAL
))
799 if (!bgp_evpn_type4_prefix_match(evp
, es
))
803 ret
= bgp_evpn_es_route_install(
806 ret
= bgp_evpn_es_route_uninstall(
812 "Failed to %s EVPN %pFX route in ESI %s",
817 bgp_dest_unlock_node(rd_dest
);
818 bgp_dest_unlock_node(dest
);
827 /*****************************************************************************
828 * Ethernet Auto Discovery (EAD/Type-1) route handling
829 * There are two types of EAD routes -
830 * 1. EAD-per-ES - Key: {ESI, ET=0xffffffff}
831 * 2. EAD-per-EVI - Key: {ESI, ET=0}
834 /* Extended communities associated with EAD-per-ES */
836 bgp_evpn_type1_es_route_extcomm_build(struct bgp_evpn_es_frag
*es_frag
,
839 struct ecommunity ecom_encap
;
840 struct ecommunity ecom_esi_label
;
841 struct ecommunity_val eval
;
842 struct ecommunity_val eval_esi_label
;
843 bgp_encap_types tnl_type
;
844 struct listnode
*evi_node
, *rt_node
;
845 struct ecommunity
*ecom
;
846 struct bgp_evpn_es_evi
*es_evi
;
849 tnl_type
= BGP_ENCAP_TYPE_VXLAN
;
850 memset(&ecom_encap
, 0, sizeof(ecom_encap
));
851 encode_encap_extcomm(tnl_type
, &eval
);
853 ecom_encap
.unit_size
= ECOMMUNITY_SIZE
;
854 ecom_encap
.val
= (uint8_t *)eval
.val
;
855 bgp_attr_set_ecommunity(attr
, ecommunity_dup(&ecom_encap
));
858 encode_esi_label_extcomm(&eval_esi_label
,
859 false /*single_active*/);
860 ecom_esi_label
.size
= 1;
861 ecom_esi_label
.unit_size
= ECOMMUNITY_SIZE
;
862 ecom_esi_label
.val
= (uint8_t *)eval_esi_label
.val
;
863 bgp_attr_set_ecommunity(attr
,
864 ecommunity_merge(bgp_attr_get_ecommunity(attr
),
867 /* Add export RTs for all L2-VNIs associated with this ES */
868 /* XXX - suppress EAD-ES advertisment if there are no EVIs associated
871 if (listcount(bgp_mh_info
->ead_es_export_rtl
)) {
872 for (ALL_LIST_ELEMENTS_RO(bgp_mh_info
->ead_es_export_rtl
,
874 bgp_attr_set_ecommunity(
875 attr
, ecommunity_merge(attr
->ecommunity
, ecom
));
877 for (ALL_LIST_ELEMENTS_RO(es_frag
->es_evi_frag_list
, evi_node
,
879 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
881 for (ALL_LIST_ELEMENTS_RO(es_evi
->vpn
->export_rtl
,
883 bgp_attr_set_ecommunity(
884 attr
, ecommunity_merge(attr
->ecommunity
,
890 /* Extended communities associated with EAD-per-EVI */
891 static void bgp_evpn_type1_evi_route_extcomm_build(struct bgp_evpn_es
*es
,
892 struct bgpevpn
*vpn
, struct attr
*attr
)
894 struct ecommunity ecom_encap
;
895 struct ecommunity_val eval
;
896 bgp_encap_types tnl_type
;
897 struct listnode
*rt_node
;
898 struct ecommunity
*ecom
;
901 tnl_type
= BGP_ENCAP_TYPE_VXLAN
;
902 memset(&ecom_encap
, 0, sizeof(ecom_encap
));
903 encode_encap_extcomm(tnl_type
, &eval
);
905 ecom_encap
.unit_size
= ECOMMUNITY_SIZE
;
906 ecom_encap
.val
= (uint8_t *)eval
.val
;
907 bgp_attr_set_ecommunity(attr
, ecommunity_dup(&ecom_encap
));
909 /* Add export RTs for the L2-VNI */
910 for (ALL_LIST_ELEMENTS_RO(vpn
->export_rtl
, rt_node
, ecom
))
911 bgp_attr_set_ecommunity(
913 ecommunity_merge(bgp_attr_get_ecommunity(attr
), ecom
));
916 /* Update EVPN EAD (type-1) route -
917 * vpn - valid for EAD-EVI routes and NULL for EAD-ES routes
919 static int bgp_evpn_type1_route_update(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
921 struct bgp_evpn_es_frag
*es_frag
,
922 struct prefix_evpn
*p
)
925 afi_t afi
= AFI_L2VPN
;
926 safi_t safi
= SAFI_EVPN
;
928 struct attr
*attr_new
= NULL
;
929 struct bgp_dest
*dest
= NULL
;
930 struct bgp_path_info
*pi
= NULL
;
931 int route_changed
= 0;
932 struct prefix_rd
*global_rd
;
934 memset(&attr
, 0, sizeof(attr
));
936 /* Build path-attribute for this route. */
937 bgp_attr_default_set(&attr
, bgp
, BGP_ORIGIN_IGP
);
938 attr
.nexthop
= es
->originator_ip
;
939 attr
.mp_nexthop_global_in
= es
->originator_ip
;
940 attr
.mp_nexthop_len
= BGP_ATTR_NHLEN_IPV4
;
943 /* EAD-EVI route update */
945 vni2label(vpn
->vni
, &(attr
.label
));
947 /* Set up extended community */
948 bgp_evpn_type1_evi_route_extcomm_build(es
, vpn
, &attr
);
950 /* First, create (or fetch) route node within the VNI. */
951 dest
= bgp_node_get(vpn
->ip_table
, (struct prefix
*)p
);
953 /* Create or update route entry. */
954 ret
= bgp_evpn_mh_route_update(bgp
, es
, vpn
, afi
, safi
, dest
,
955 &attr
, &pi
, &route_changed
);
959 "%u Failed to update EAD-EVI route ESI: %s VNI %u VTEP %pI4",
960 bgp
->vrf_id
, es
->esi_str
, vpn
->vni
,
962 global_rd
= &vpn
->prd
;
964 /* EAD-ES route update */
965 /* MPLS label is 0 for EAD-ES route */
967 /* Set up extended community */
968 bgp_evpn_type1_es_route_extcomm_build(es_frag
, &attr
);
970 /* First, create (or fetch) route node within the ES. */
971 /* NOTE: There is no RD here. */
972 /* XXX: fragment ID must be included as a part of the prefix. */
973 dest
= bgp_node_get(es
->route_table
, (struct prefix
*)p
);
975 /* Create or update route entry. */
976 ret
= bgp_evpn_mh_route_update(bgp
, es
, vpn
, afi
, safi
, dest
,
977 &attr
, &pi
, &route_changed
);
981 "%u ERROR: Failed to updated EAD-ES route ESI: %s VTEP %pI4",
982 bgp
->vrf_id
, es
->esi_str
, &es
->originator_ip
);
984 global_rd
= &es_frag
->prd
;
991 /* Perform route selection;
992 * this is just to set the flags correctly as local route in
993 * the ES always wins.
995 evpn_route_select_install(bgp
, vpn
, dest
);
996 bgp_dest_unlock_node(dest
);
998 /* If this is a new route or some attribute has changed, export the
999 * route to the global table. The route will be advertised to peers
1000 * from there. Note that this table is a 2-level tree (RD-level +
1001 * Prefix-level) similar to L3VPN routes.
1003 if (route_changed
) {
1004 struct bgp_path_info
*global_pi
;
1006 dest
= bgp_evpn_global_node_get(bgp
->rib
[afi
][safi
], afi
, safi
,
1007 p
, global_rd
, NULL
);
1008 bgp_evpn_mh_route_update(bgp
, es
, vpn
, afi
, safi
, dest
,
1009 attr_new
, &global_pi
, &route_changed
);
1011 /* Schedule for processing and unlock node. */
1012 bgp_process(bgp
, dest
, afi
, safi
);
1013 bgp_dest_unlock_node(dest
);
1016 /* Unintern temporary. */
1017 aspath_unintern(&attr
.aspath
);
1022 * This function is called when the export RT for a VNI changes.
1023 * Update all type-1 local routes for this VNI from VNI/ES tables and the global
1024 * table and advertise these routes to peers.
1027 static void bgp_evpn_ead_es_route_update(struct bgp
*bgp
,
1028 struct bgp_evpn_es
*es
)
1030 struct listnode
*node
;
1031 struct bgp_evpn_es_frag
*es_frag
;
1032 struct prefix_evpn p
;
1034 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_ES_ETH_TAG
, &es
->esi
,
1036 for (ALL_LIST_ELEMENTS_RO(es
->es_frag_list
, node
, es_frag
)) {
1037 if (!listcount(es_frag
->es_evi_frag_list
))
1040 p
.prefix
.ead_addr
.frag_id
= es_frag
->rd_id
;
1041 if (bgp_evpn_type1_route_update(bgp
, es
, NULL
, es_frag
, &p
))
1043 EC_BGP_EVPN_ROUTE_CREATE
,
1044 "EAD-ES route creation failure for ESI %s frag %u",
1045 es
->esi_str
, es_frag
->rd_id
);
1049 static void bgp_evpn_ead_evi_route_update(struct bgp
*bgp
,
1050 struct bgp_evpn_es
*es
,
1051 struct bgpevpn
*vpn
,
1052 struct prefix_evpn
*p
)
1054 if (bgp_evpn_type1_route_update(bgp
, es
, vpn
, NULL
, p
))
1055 flog_err(EC_BGP_EVPN_ROUTE_CREATE
,
1056 "EAD-EVI route creation failure for ESI %s VNI %u",
1057 es
->esi_str
, vpn
->vni
);
1060 void update_type1_routes_for_evi(struct bgp
*bgp
, struct bgpevpn
*vpn
)
1062 struct prefix_evpn p
;
1063 struct bgp_evpn_es
*es
;
1064 struct bgp_evpn_es_evi
*es_evi
;
1067 RB_FOREACH (es_evi
, bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
) {
1070 if (es_evi
->vpn
!= vpn
)
1074 if (bgp_evpn_local_es_is_active(es
))
1075 bgp_evpn_ead_es_route_update(bgp
, es
);
1077 /* Update EAD-EVI */
1078 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
)) {
1079 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_EVI_ETH_TAG
,
1080 &es
->esi
, es
->originator_ip
);
1081 bgp_evpn_ead_evi_route_update(bgp
, es
, vpn
, &p
);
1086 /* Delete local Type-1 route */
1087 static void bgp_evpn_ead_es_route_delete(struct bgp
*bgp
,
1088 struct bgp_evpn_es
*es
)
1090 struct listnode
*node
;
1091 struct bgp_evpn_es_frag
*es_frag
;
1092 struct prefix_evpn p
;
1094 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_ES_ETH_TAG
, &es
->esi
,
1096 for (ALL_LIST_ELEMENTS_RO(es
->es_frag_list
, node
, es_frag
)) {
1097 p
.prefix
.ead_addr
.frag_id
= es_frag
->rd_id
;
1098 bgp_evpn_mh_route_delete(bgp
, es
, NULL
, es_frag
, &p
);
1102 static int bgp_evpn_ead_evi_route_delete(struct bgp
*bgp
,
1103 struct bgp_evpn_es
*es
,
1104 struct bgpevpn
*vpn
,
1105 struct prefix_evpn
*p
)
1107 return bgp_evpn_mh_route_delete(bgp
, es
, vpn
, NULL
, p
);
1110 /* Generate EAD-EVI for all VNIs */
1111 static void bgp_evpn_local_type1_evi_route_add(struct bgp
*bgp
,
1112 struct bgp_evpn_es
*es
)
1114 struct listnode
*evi_node
;
1115 struct prefix_evpn p
;
1116 struct bgp_evpn_es_evi
*es_evi
;
1118 /* EAD-per-EVI routes have been suppressed */
1119 if (!bgp_mh_info
->ead_evi_tx
)
1122 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
))
1123 /* EAD-EVI route add for this ES is already done */
1126 SET_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
);
1127 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_EVI_ETH_TAG
,
1128 &es
->esi
, es
->originator_ip
);
1130 for (ALL_LIST_ELEMENTS_RO(es
->es_evi_list
, evi_node
, es_evi
)) {
1131 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
1133 bgp_evpn_ead_evi_route_update(bgp
, es
, es_evi
->vpn
, &p
);
1138 * Withdraw EAD-EVI for all VNIs
1140 static void bgp_evpn_local_type1_evi_route_del(struct bgp
*bgp
,
1141 struct bgp_evpn_es
*es
)
1143 struct listnode
*evi_node
;
1144 struct prefix_evpn p
;
1145 struct bgp_evpn_es_evi
*es_evi
;
1147 /* Delete and withdraw locally learnt EAD-EVI route */
1148 if (!CHECK_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
))
1149 /* EAD-EVI route has not been advertised for this ES */
1152 UNSET_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
);
1153 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_EVI_ETH_TAG
,
1154 &es
->esi
, es
->originator_ip
);
1155 for (ALL_LIST_ELEMENTS_RO(es
->es_evi_list
, evi_node
, es_evi
)) {
1156 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
1158 if (bgp_evpn_mh_route_delete(bgp
, es
, es_evi
->vpn
, NULL
, &p
))
1159 flog_err(EC_BGP_EVPN_ROUTE_CREATE
,
1160 "%u: Type4 route creation failure for ESI %s",
1161 bgp
->vrf_id
, es
->esi_str
);
1166 * Process received EVPN type-1 route (advertise or withdraw).
1168 int bgp_evpn_type1_route_process(struct peer
*peer
, afi_t afi
, safi_t safi
,
1169 struct attr
*attr
, uint8_t *pfx
, int psize
,
1170 uint32_t addpath_id
)
1172 struct prefix_rd prd
;
1176 struct in_addr vtep_ip
;
1177 struct prefix_evpn p
;
1179 if (psize
!= BGP_EVPN_TYPE1_PSIZE
) {
1180 flog_err(EC_BGP_EVPN_ROUTE_INVALID
,
1181 "%u:%s - Rx EVPN Type-1 NLRI with invalid length %d",
1182 peer
->bgp
->vrf_id
, peer
->host
, psize
);
1186 /* Make prefix_rd */
1187 prd
.family
= AF_UNSPEC
;
1189 memcpy(&prd
.val
, pfx
, RD_BYTES
);
1193 memcpy(&esi
, pfx
, ESI_BYTES
);
1196 /* Copy Ethernet Tag */
1197 memcpy(ð_tag
, pfx
, EVPN_ETH_TAG_BYTES
);
1198 eth_tag
= ntohl(eth_tag
);
1199 pfx
+= EVPN_ETH_TAG_BYTES
;
1201 memcpy(&label
, pfx
, BGP_LABEL_BYTES
);
1203 /* EAD route prefix doesn't include the nexthop in the global
1206 vtep_ip
.s_addr
= INADDR_ANY
;
1207 build_evpn_type1_prefix(&p
, eth_tag
, &esi
, vtep_ip
);
1208 /* Process the route. */
1210 bgp_update(peer
, (struct prefix
*)&p
, addpath_id
, attr
, afi
,
1211 safi
, ZEBRA_ROUTE_BGP
, BGP_ROUTE_NORMAL
, &prd
, NULL
,
1214 bgp_withdraw(peer
, (struct prefix
*)&p
, addpath_id
, afi
, safi
,
1215 ZEBRA_ROUTE_BGP
, BGP_ROUTE_NORMAL
, &prd
, NULL
, 0,
1221 void bgp_evpn_mh_config_ead_export_rt(struct bgp
*bgp
,
1222 struct ecommunity
*ecomcfg
, bool del
)
1224 struct listnode
*node
, *nnode
, *node_to_del
;
1225 struct ecommunity
*ecom
;
1226 struct bgp_evpn_es
*es
;
1229 if (ecomcfg
== NULL
) {
1230 /* Reset to default and process all routes. */
1231 for (ALL_LIST_ELEMENTS(bgp_mh_info
->ead_es_export_rtl
,
1232 node
, nnode
, ecom
)) {
1233 ecommunity_free(&ecom
);
1234 list_delete_node(bgp_mh_info
->ead_es_export_rtl
,
1239 /* Delete a specific export RT */
1243 for (ALL_LIST_ELEMENTS(bgp_mh_info
->ead_es_export_rtl
,
1244 node
, nnode
, ecom
)) {
1245 if (ecommunity_match(ecom
, ecomcfg
)) {
1246 ecommunity_free(&ecom
);
1252 assert(node_to_del
);
1253 list_delete_node(bgp_mh_info
->ead_es_export_rtl
,
1257 listnode_add_sort(bgp_mh_info
->ead_es_export_rtl
, ecomcfg
);
1260 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
1261 zlog_debug("local ES del/re-add EAD route on export RT change");
1263 * walk through all active ESs withdraw the old EAD and
1264 * generate a new one
1266 RB_FOREACH (es
, bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
) {
1267 if (!bgp_evpn_is_es_local(es
) ||
1268 !bgp_evpn_local_es_is_active(es
))
1271 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
1273 "local ES %s del/re-add EAD route on export RT change",
1277 * withdraw EAD-ES. XXX - this should technically not be
1278 * needed; can be removed after testing
1280 bgp_evpn_ead_es_route_delete(bgp
, es
);
1282 /* generate EAD-ES */
1283 bgp_evpn_ead_es_route_update(bgp
, es
);
1287 /*****************************************************************************/
1288 /* Ethernet Segment Management
1289 * 1. Ethernet Segment is a collection of links attached to the same
1290 * server (MHD) or switch (MHN)
1291 * 2. An Ethernet Segment can span multiple PEs and is identified by the
1293 * 3. Local ESs are configured in zebra and sent to BGP
1294 * 4. Remote ESs are created by BGP when one or more ES-EVIs reference it i.e.
1295 * created on first reference and release on last de-reference
1296 * 5. An ES can be both local and remote. Infact most local ESs are expected
1297 * to have an ES peer.
1300 /* A list of remote VTEPs is maintained for each ES. This list includes -
1301 * 1. VTEPs for which we have imported the ESR i.e. ES-peers
1302 * 2. VTEPs that have an "active" ES-EVI VTEP i.e. EAD-per-ES and EAD-per-EVI
1303 * have been imported into one or more VNIs
1305 static int bgp_evpn_es_vtep_cmp(void *p1
, void *p2
)
1307 const struct bgp_evpn_es_vtep
*es_vtep1
= p1
;
1308 const struct bgp_evpn_es_vtep
*es_vtep2
= p2
;
1310 return es_vtep1
->vtep_ip
.s_addr
- es_vtep2
->vtep_ip
.s_addr
;
1313 static struct bgp_evpn_es_vtep
*bgp_evpn_es_vtep_new(struct bgp_evpn_es
*es
,
1314 struct in_addr vtep_ip
)
1316 struct bgp_evpn_es_vtep
*es_vtep
;
1318 es_vtep
= XCALLOC(MTYPE_BGP_EVPN_ES_VTEP
, sizeof(*es_vtep
));
1321 es_vtep
->vtep_ip
.s_addr
= vtep_ip
.s_addr
;
1322 inet_ntop(AF_INET
, &es_vtep
->vtep_ip
, es_vtep
->vtep_str
,
1323 sizeof(es_vtep
->vtep_str
));
1324 listnode_init(&es_vtep
->es_listnode
, es_vtep
);
1325 listnode_add_sort(es
->es_vtep_list
, &es_vtep
->es_listnode
);
1330 static void bgp_evpn_es_vtep_free(struct bgp_evpn_es_vtep
*es_vtep
)
1332 struct bgp_evpn_es
*es
= es_vtep
->es
;
1334 if (CHECK_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ESR
) ||
1336 /* as long as there is some reference we can't free it */
1339 list_delete_node(es
->es_vtep_list
, &es_vtep
->es_listnode
);
1340 XFREE(MTYPE_BGP_EVPN_ES_VTEP
, es_vtep
);
1343 /* check if VTEP is already part of the list */
1344 static struct bgp_evpn_es_vtep
*bgp_evpn_es_vtep_find(struct bgp_evpn_es
*es
,
1345 struct in_addr vtep_ip
)
1347 struct listnode
*node
= NULL
;
1348 struct bgp_evpn_es_vtep
*es_vtep
;
1350 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
1351 if (es_vtep
->vtep_ip
.s_addr
== vtep_ip
.s_addr
)
1357 /* Send the remote ES to zebra for NHG programming */
1358 static int bgp_zebra_send_remote_es_vtep(struct bgp
*bgp
,
1359 struct bgp_evpn_es_vtep
*es_vtep
, bool add
)
1361 struct bgp_evpn_es
*es
= es_vtep
->es
;
1366 if (!zclient
|| zclient
->sock
< 0)
1369 /* Don't try to register if Zebra doesn't know of this instance. */
1370 if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp
)) {
1371 if (BGP_DEBUG(zebra
, ZEBRA
))
1372 zlog_debug("No zebra instance, not installing remote es %s",
1377 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ESR
)
1378 flags
|= ZAPI_ES_VTEP_FLAG_ESR_RXED
;
1383 zclient_create_header(s
,
1384 add
? ZEBRA_REMOTE_ES_VTEP_ADD
: ZEBRA_REMOTE_ES_VTEP_DEL
,
1386 stream_put(s
, &es
->esi
, sizeof(esi_t
));
1387 stream_put_ipv4(s
, es_vtep
->vtep_ip
.s_addr
);
1389 stream_putl(s
, flags
);
1390 stream_putc(s
, es_vtep
->df_alg
);
1391 stream_putw(s
, es_vtep
->df_pref
);
1394 stream_putw_at(s
, 0, stream_get_endp(s
));
1396 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1397 zlog_debug("Tx %s Remote ESI %s VTEP %pI4", add
? "ADD" : "DEL",
1398 es
->esi_str
, &es_vtep
->vtep_ip
);
1400 frrtrace(3, frr_bgp
, evpn_mh_vtep_zsend
, add
, es
, es_vtep
);
1402 return zclient_send_message(zclient
);
1405 static void bgp_evpn_es_vtep_re_eval_active(struct bgp
*bgp
,
1406 struct bgp_evpn_es_vtep
*es_vtep
,
1412 old_active
= CHECK_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
);
1413 /* currently we need an active EVI reference to use the VTEP as
1414 * a nexthop. this may change...
1416 if (es_vtep
->evi_cnt
)
1417 SET_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
);
1419 UNSET_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
);
1421 new_active
= CHECK_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
);
1423 if ((old_active
!= new_active
) || (new_active
&& param_change
)) {
1425 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1426 zlog_debug("es %s vtep %pI4 %s df %u/%u",
1427 es_vtep
->es
->esi_str
, &es_vtep
->vtep_ip
,
1428 new_active
? "active" : "inactive",
1429 es_vtep
->df_alg
, es_vtep
->df_pref
);
1431 /* send remote ES to zebra */
1432 bgp_zebra_send_remote_es_vtep(bgp
, es_vtep
, new_active
);
1434 /* The NHG is updated first for efficient failover handling.
1435 * Note the NHG can be de-activated while there are bgp
1436 * routes referencing it. Zebra is capable of handling that
1437 * elegantly by holding the NHG till all routes using it are
1440 bgp_evpn_l3nhg_update_on_vtep_chg(es_vtep
->es
);
1441 /* queue up the es for background consistency checks */
1442 bgp_evpn_es_cons_checks_pend_add(es_vtep
->es
);
1446 static struct bgp_evpn_es_vtep
*bgp_evpn_es_vtep_add(struct bgp
*bgp
,
1447 struct bgp_evpn_es
*es
,
1448 struct in_addr vtep_ip
,
1449 bool esr
, uint8_t df_alg
,
1452 struct bgp_evpn_es_vtep
*es_vtep
;
1453 bool param_change
= false;
1455 es_vtep
= bgp_evpn_es_vtep_find(es
, vtep_ip
);
1458 es_vtep
= bgp_evpn_es_vtep_new(es
, vtep_ip
);
1460 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1461 zlog_debug("es %s vtep %pI4 add %s df %u/%u",
1462 es_vtep
->es
->esi_str
, &es_vtep
->vtep_ip
,
1463 esr
? "esr" : "ead", df_alg
, df_pref
);
1466 SET_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ESR
);
1467 if ((es_vtep
->df_pref
!= df_pref
)
1468 || (es_vtep
->df_alg
!= df_alg
)) {
1469 param_change
= true;
1470 es_vtep
->df_pref
= df_pref
;
1471 es_vtep
->df_alg
= df_alg
;
1477 bgp_evpn_es_vtep_re_eval_active(bgp
, es_vtep
, param_change
);
1482 static void bgp_evpn_es_vtep_do_del(struct bgp
*bgp
,
1483 struct bgp_evpn_es_vtep
*es_vtep
, bool esr
)
1485 bool param_change
= false;
1487 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1488 zlog_debug("es %s vtep %pI4 del %s", es_vtep
->es
->esi_str
,
1489 &es_vtep
->vtep_ip
, esr
? "esr" : "ead");
1491 UNSET_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ESR
);
1492 if (es_vtep
->df_pref
|| es_vtep
->df_alg
) {
1493 param_change
= true;
1494 es_vtep
->df_pref
= 0;
1495 es_vtep
->df_alg
= 0;
1498 if (es_vtep
->evi_cnt
)
1502 bgp_evpn_es_vtep_re_eval_active(bgp
, es_vtep
, param_change
);
1503 bgp_evpn_es_vtep_free(es_vtep
);
1506 static void bgp_evpn_es_vtep_del(struct bgp
*bgp
,
1507 struct bgp_evpn_es
*es
, struct in_addr vtep_ip
, bool esr
)
1509 struct bgp_evpn_es_vtep
*es_vtep
;
1511 es_vtep
= bgp_evpn_es_vtep_find(es
, vtep_ip
);
1513 bgp_evpn_es_vtep_do_del(bgp
, es_vtep
, esr
);
1516 /********************** ES MAC-IP paths *************************************
1517 * 1. Local MAC-IP routes in the VNI routing table are linked to the
1518 * destination ES (macip_evi_path_list) for efficient updates on ES oper
1520 * 2. Non-local MAC-IP routes in the global routing table are linked to
1521 * the detination for efficient updates on -
1522 * a. VTEP add/del - this results in a L3NHG update.
1523 * b. ES-VRF add/del - this may result in the host route being migrated to
1524 * L3NHG or vice versa (flat multipath list).
1525 ****************************************************************************/
1526 static void bgp_evpn_path_es_info_free(struct bgp_path_es_info
*es_info
)
1528 bgp_evpn_path_es_unlink(es_info
);
1529 XFREE(MTYPE_BGP_EVPN_PATH_ES_INFO
, es_info
);
1532 void bgp_evpn_path_mh_info_free(struct bgp_path_mh_info
*mh_info
)
1534 if (mh_info
->es_info
)
1535 bgp_evpn_path_es_info_free(mh_info
->es_info
);
1536 if (mh_info
->nh_info
)
1537 bgp_evpn_path_nh_info_free(mh_info
->nh_info
);
1538 XFREE(MTYPE_BGP_EVPN_PATH_MH_INFO
, mh_info
);
1541 static struct bgp_path_es_info
*
1542 bgp_evpn_path_es_info_new(struct bgp_path_info
*pi
, vni_t vni
)
1544 struct bgp_path_info_extra
*e
;
1545 struct bgp_path_mh_info
*mh_info
;
1546 struct bgp_path_es_info
*es_info
;
1548 e
= bgp_path_info_extra_get(pi
);
1550 /* If mh_info doesn't exist allocate it */
1551 mh_info
= e
->mh_info
;
1553 e
->mh_info
= mh_info
= XCALLOC(MTYPE_BGP_EVPN_PATH_MH_INFO
,
1554 sizeof(struct bgp_path_mh_info
));
1556 /* If es_info doesn't exist allocate it */
1557 es_info
= mh_info
->es_info
;
1559 mh_info
->es_info
= es_info
=
1560 XCALLOC(MTYPE_BGP_EVPN_PATH_ES_INFO
,
1561 sizeof(struct bgp_path_es_info
));
1569 static void bgp_evpn_path_es_unlink(struct bgp_path_es_info
*es_info
)
1571 struct bgp_evpn_es
*es
= es_info
->es
;
1572 struct bgp_path_info
*pi
;
1578 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
1579 zlog_debug("vni %u path %pFX unlinked from es %s", es_info
->vni
,
1580 &pi
->net
->p
, es
->esi_str
);
1583 list_delete_node(es
->macip_evi_path_list
,
1584 &es_info
->es_listnode
);
1586 list_delete_node(es
->macip_global_path_list
,
1587 &es_info
->es_listnode
);
1591 /* if there are no other references against the ES it
1594 bgp_evpn_es_free(es
, __func__
);
1596 /* Note we don't free the path es_info on unlink; it will be freed up
1597 * along with the path.
1601 void bgp_evpn_path_es_link(struct bgp_path_info
*pi
, vni_t vni
, esi_t
*esi
)
1603 struct bgp_path_es_info
*es_info
;
1604 struct bgp_evpn_es
*es
;
1605 struct bgp
*bgp_evpn
;
1607 es_info
= (pi
->extra
&& pi
->extra
->mh_info
)
1608 ? pi
->extra
->mh_info
->es_info
1610 /* if the esi is zero just unlink the path from the old es */
1611 if (!esi
|| !memcmp(esi
, zero_esi
, sizeof(*esi
))) {
1613 bgp_evpn_path_es_unlink(es_info
);
1617 bgp_evpn
= bgp_get_evpn();
1621 /* setup es_info against the path if it doesn't aleady exist */
1623 es_info
= bgp_evpn_path_es_info_new(pi
, vni
);
1625 /* find-create ES */
1626 es
= bgp_evpn_es_find(esi
);
1628 es
= bgp_evpn_es_new(bgp_evpn
, esi
);
1631 if (es_info
->es
== es
)
1634 /* unlink old ES if any */
1635 bgp_evpn_path_es_unlink(es_info
);
1637 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
1638 zlog_debug("vni %u path %pFX linked to es %s", vni
, &pi
->net
->p
,
1641 /* link mac-ip path to the new destination ES */
1643 listnode_init(&es_info
->es_listnode
, es_info
);
1645 listnode_add(es
->macip_evi_path_list
, &es_info
->es_listnode
);
1647 listnode_add(es
->macip_global_path_list
, &es_info
->es_listnode
);
1650 static bool bgp_evpn_is_macip_path(struct bgp_path_info
*pi
)
1652 struct prefix_evpn
*evp
;
1654 /* Only MAC-IP routes need to be linked (MAC-only routes can be
1655 * skipped) as these lists are maintained for managing
1656 * host routes in the tenant VRF
1658 evp
= (struct prefix_evpn
*)&pi
->net
->p
;
1659 return is_evpn_prefix_ipaddr_v4(evp
) || is_evpn_prefix_ipaddr_v6(evp
);
1662 /* When a remote ES is added to a VRF, routes using that as
1663 * a destination need to be migrated to a L3NHG or viceversa.
1664 * This is done indirectly by re-attempting an install of the
1665 * route in the associated VRFs. As a part of the VRF install use
1666 * of l3 NHG is evaluated and this results in the
1667 * attr.es_flag ATTR_ES_L3_NHG_USE being set or cleared.
1670 bgp_evpn_es_path_update_on_es_vrf_chg(struct bgp_evpn_es_vrf
*es_vrf
,
1673 struct listnode
*node
;
1674 struct bgp_path_es_info
*es_info
;
1675 struct bgp_path_info
*pi
;
1676 struct bgp_evpn_es
*es
= es_vrf
->es
;
1678 if (!bgp_mh_info
->host_routes_use_l3nhg
)
1681 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
1682 zlog_debug("update paths linked to es %s on es-vrf %s %s",
1683 es
->esi_str
, es_vrf
->bgp_vrf
->name_pretty
, reason
);
1685 for (ALL_LIST_ELEMENTS_RO(es
->macip_global_path_list
, node
, es_info
)) {
1688 if (!bgp_evpn_is_macip_path(pi
))
1691 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
1693 "update path %pFX linked to es %s on vrf chg",
1694 &pi
->net
->p
, es
->esi_str
);
1695 bgp_evpn_route_entry_install_if_vrf_match(es_vrf
->bgp_vrf
, pi
,
1700 static void bgp_evpn_es_frag_free(struct bgp_evpn_es_frag
*es_frag
)
1702 struct bgp_evpn_es
*es
= es_frag
->es
;
1704 if (es
->es_base_frag
== es_frag
)
1705 es
->es_base_frag
= NULL
;
1707 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1708 zlog_debug("es %s frag %u free", es
->esi_str
, es_frag
->rd_id
);
1709 list_delete_node(es
->es_frag_list
, &es_frag
->es_listnode
);
1711 /* EVIs that are advertised using the info in this fragment */
1712 list_delete(&es_frag
->es_evi_frag_list
);
1714 bf_release_index(bm
->rd_idspace
, es_frag
->rd_id
);
1717 XFREE(MTYPE_BGP_EVPN_ES_FRAG
, es_frag
);
1720 static void bgp_evpn_es_frag_free_unused(struct bgp_evpn_es_frag
*es_frag
)
1722 if ((es_frag
->es
->es_base_frag
== es_frag
) ||
1723 listcount(es_frag
->es_evi_frag_list
))
1726 bgp_evpn_es_frag_free(es_frag
);
1729 static void bgp_evpn_es_frag_free_all(struct bgp_evpn_es
*es
)
1731 struct listnode
*node
;
1732 struct listnode
*nnode
;
1733 struct bgp_evpn_es_frag
*es_frag
;
1735 for (ALL_LIST_ELEMENTS(es
->es_frag_list
, node
, nnode
, es_frag
))
1736 bgp_evpn_es_frag_free(es_frag
);
1739 static struct bgp_evpn_es_frag
*bgp_evpn_es_frag_new(struct bgp_evpn_es
*es
)
1741 struct bgp_evpn_es_frag
*es_frag
;
1742 char buf
[BGP_EVPN_PREFIX_RD_LEN
];
1745 es_frag
= XCALLOC(MTYPE_BGP_EVPN_ES_FRAG
, sizeof(*es_frag
));
1746 bf_assign_index(bm
->rd_idspace
, es_frag
->rd_id
);
1747 es_frag
->prd
.family
= AF_UNSPEC
;
1748 es_frag
->prd
.prefixlen
= 64;
1749 bgp
= bgp_get_evpn();
1750 snprintfrr(buf
, sizeof(buf
), "%pI4:%hu", &bgp
->router_id
,
1752 (void)str2prefix_rd(buf
, &es_frag
->prd
);
1754 /* EVIs that are advertised using the info in this fragment */
1755 es_frag
->es_evi_frag_list
= list_new();
1756 listset_app_node_mem(es_frag
->es_evi_frag_list
);
1758 /* Link the fragment to the parent ES */
1760 listnode_init(&es_frag
->es_listnode
, es_frag
);
1761 listnode_add(es
->es_frag_list
, &es_frag
->es_listnode
);
1763 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1764 zlog_debug("es %s frag %u new", es
->esi_str
, es_frag
->rd_id
);
1768 static struct bgp_evpn_es_frag
*
1769 bgp_evpn_es_find_frag_with_space(struct bgp_evpn_es
*es
)
1771 struct listnode
*node
;
1772 struct bgp_evpn_es_frag
*es_frag
;
1774 for (ALL_LIST_ELEMENTS_RO(es
->es_frag_list
, node
, es_frag
)) {
1775 if (listcount(es_frag
->es_evi_frag_list
) <
1776 bgp_mh_info
->evi_per_es_frag
)
1780 /* No frags where found with space; allocate a new one */
1781 return bgp_evpn_es_frag_new(es
);
1784 /* Link the ES-EVI to one of the ES fragments */
1785 static void bgp_evpn_es_frag_evi_add(struct bgp_evpn_es_evi
*es_evi
)
1787 struct bgp_evpn_es_frag
*es_frag
;
1788 struct bgp_evpn_es
*es
= es_evi
->es
;
1790 if (es_evi
->es_frag
||
1791 !(CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
)))
1794 es_frag
= bgp_evpn_es_find_frag_with_space(es
);
1796 es_evi
->es_frag
= es_frag
;
1797 listnode_init(&es_evi
->es_frag_listnode
, es_evi
);
1798 listnode_add(es_frag
->es_evi_frag_list
, &es_evi
->es_frag_listnode
);
1800 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1801 zlog_debug("es %s vni %d linked to frag %u", es
->esi_str
,
1802 es_evi
->vpn
->vni
, es_frag
->rd_id
);
1805 /* UnLink the ES-EVI from the ES fragment */
1806 static void bgp_evpn_es_frag_evi_del(struct bgp_evpn_es_evi
*es_evi
,
1807 bool send_ead_del_if_empty
)
1809 struct bgp_evpn_es_frag
*es_frag
= es_evi
->es_frag
;
1810 struct prefix_evpn p
;
1811 struct bgp_evpn_es
*es
;
1818 es_evi
->es_frag
= NULL
;
1819 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1820 zlog_debug("es %s vni %d unlinked from frag %u", es
->esi_str
,
1821 es_evi
->vpn
->vni
, es_frag
->rd_id
);
1823 list_delete_node(es_frag
->es_evi_frag_list
, &es_evi
->es_frag_listnode
);
1826 * if there are no other EVIs on the fragment deleted the EAD-ES for
1829 if (send_ead_del_if_empty
&& !listcount(es_frag
->es_evi_frag_list
)) {
1830 bgp
= bgp_get_evpn();
1832 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1833 zlog_debug("es %s frag %u ead-es route delete",
1834 es
->esi_str
, es_frag
->rd_id
);
1835 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_ES_ETH_TAG
, &es
->esi
,
1837 p
.prefix
.ead_addr
.frag_id
= es_frag
->rd_id
;
1838 bgp_evpn_mh_route_delete(bgp
, es
, NULL
, es_frag
, &p
);
1841 /* We don't attempt to coalesce frags that may not be full. Instead we
1842 * only free up the frag when it is completely empty.
1844 bgp_evpn_es_frag_free_unused(es_frag
);
1847 /* Link the ES-EVIs to one of the ES fragments */
1848 static void bgp_evpn_es_frag_evi_update_all(struct bgp_evpn_es
*es
, bool add
)
1850 struct listnode
*node
;
1851 struct bgp_evpn_es_evi
*es_evi
;
1853 for (ALL_LIST_ELEMENTS_RO(es
->es_evi_list
, node
, es_evi
)) {
1855 bgp_evpn_es_frag_evi_add(es_evi
);
1857 bgp_evpn_es_frag_evi_del(es_evi
, false);
1861 /* compare ES-IDs for the global ES RB tree */
1862 static int bgp_es_rb_cmp(const struct bgp_evpn_es
*es1
,
1863 const struct bgp_evpn_es
*es2
)
1865 return memcmp(&es1
->esi
, &es2
->esi
, ESI_BYTES
);
1867 RB_GENERATE(bgp_es_rb_head
, bgp_evpn_es
, rb_node
, bgp_es_rb_cmp
);
1869 struct bgp_evpn_es
*bgp_evpn_es_find(const esi_t
*esi
)
1871 struct bgp_evpn_es tmp
;
1873 memcpy(&tmp
.esi
, esi
, sizeof(esi_t
));
1874 return RB_FIND(bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
, &tmp
);
1877 static struct bgp_evpn_es
*bgp_evpn_es_new(struct bgp
*bgp
, const esi_t
*esi
)
1879 struct bgp_evpn_es
*es
;
1881 es
= XCALLOC(MTYPE_BGP_EVPN_ES
, sizeof(struct bgp_evpn_es
));
1884 memcpy(&es
->esi
, esi
, sizeof(esi_t
));
1886 /* Initialise the VTEP list */
1887 es
->es_vtep_list
= list_new();
1888 listset_app_node_mem(es
->es_vtep_list
);
1889 es
->es_vtep_list
->cmp
= bgp_evpn_es_vtep_cmp
;
1891 esi_to_str(&es
->esi
, es
->esi_str
, sizeof(es
->esi_str
));
1893 /* Initialize the ES routing table */
1894 es
->route_table
= bgp_table_init(bgp
, AFI_L2VPN
, SAFI_EVPN
);
1896 /* Add to rb_tree */
1897 RB_INSERT(bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
, es
);
1899 /* Initialise the ES-EVI list */
1900 es
->es_evi_list
= list_new();
1901 listset_app_node_mem(es
->es_evi_list
);
1903 /* Initialise the ES-VRF list used for L3NHG management */
1904 es
->es_vrf_list
= list_new();
1905 listset_app_node_mem(es
->es_vrf_list
);
1907 /* Initialise the route list used for efficient event handling */
1908 es
->macip_evi_path_list
= list_new();
1909 listset_app_node_mem(es
->macip_evi_path_list
);
1910 es
->macip_global_path_list
= list_new();
1911 listset_app_node_mem(es
->macip_global_path_list
);
1912 es
->es_frag_list
= list_new();
1913 listset_app_node_mem(es
->es_frag_list
);
1915 QOBJ_REG(es
, bgp_evpn_es
);
1920 /* Free a given ES -
1921 * This just frees appropriate memory, caller should have taken other
1924 static void bgp_evpn_es_free(struct bgp_evpn_es
*es
, const char *caller
)
1926 if ((es
->flags
& (BGP_EVPNES_LOCAL
| BGP_EVPNES_REMOTE
))
1927 || listcount(es
->macip_evi_path_list
)
1928 || listcount(es
->macip_global_path_list
))
1931 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1932 zlog_debug("%s: es %s free", caller
, es
->esi_str
);
1934 /* cleanup resources maintained against the ES */
1935 list_delete(&es
->es_evi_list
);
1936 list_delete(&es
->es_vrf_list
);
1937 list_delete(&es
->es_vtep_list
);
1938 list_delete(&es
->macip_evi_path_list
);
1939 list_delete(&es
->macip_global_path_list
);
1940 list_delete(&es
->es_frag_list
);
1941 bgp_table_unlock(es
->route_table
);
1943 /* remove the entry from various databases */
1944 RB_REMOVE(bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
, es
);
1945 bgp_evpn_es_cons_checks_pend_del(es
);
1948 XFREE(MTYPE_BGP_EVPN_ES
, es
);
1951 static inline bool bgp_evpn_is_es_local_and_non_bypass(struct bgp_evpn_es
*es
)
1953 return (es
->flags
& BGP_EVPNES_LOCAL
)
1954 && !(es
->flags
& BGP_EVPNES_BYPASS
);
1957 /* init local info associated with the ES */
1958 static void bgp_evpn_es_local_info_set(struct bgp
*bgp
, struct bgp_evpn_es
*es
)
1963 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_LOCAL
))
1966 old_is_local
= bgp_evpn_is_es_local_and_non_bypass(es
);
1967 SET_FLAG(es
->flags
, BGP_EVPNES_LOCAL
);
1969 listnode_init(&es
->es_listnode
, es
);
1970 listnode_add(bgp_mh_info
->local_es_list
, &es
->es_listnode
);
1972 /* setup the first ES fragment; more fragments may be allocated based
1973 * on the the number of EVI entries
1975 es
->es_base_frag
= bgp_evpn_es_frag_new(es
);
1976 /* distribute ES-EVIs to one or more ES fragments */
1977 bgp_evpn_es_frag_evi_update_all(es
, true);
1979 is_local
= bgp_evpn_is_es_local_and_non_bypass(es
);
1980 if (old_is_local
!= is_local
)
1981 bgp_evpn_mac_update_on_es_local_chg(es
, is_local
);
1984 /* clear any local info associated with the ES */
1985 static void bgp_evpn_es_local_info_clear(struct bgp_evpn_es
*es
, bool finish
)
1990 if (!CHECK_FLAG(es
->flags
, BGP_EVPNES_LOCAL
))
1993 /* clear the es frag references and free them up */
1994 bgp_evpn_es_frag_evi_update_all(es
, false);
1995 es
->es_base_frag
= NULL
;
1996 bgp_evpn_es_frag_free_all(es
);
1998 old_is_local
= bgp_evpn_is_es_local_and_non_bypass(es
);
1999 UNSET_FLAG(es
->flags
, BGP_EVPNES_LOCAL
);
2001 is_local
= bgp_evpn_is_es_local_and_non_bypass(es
);
2002 if (!finish
&& (old_is_local
!= is_local
))
2003 bgp_evpn_mac_update_on_es_local_chg(es
, is_local
);
2005 /* remove from the ES local list */
2006 list_delete_node(bgp_mh_info
->local_es_list
, &es
->es_listnode
);
2008 bgp_evpn_es_free(es
, __func__
);
2011 /* eval remote info associated with the ES */
2012 static void bgp_evpn_es_remote_info_re_eval(struct bgp_evpn_es
*es
)
2014 if (es
->remote_es_evi_cnt
) {
2015 SET_FLAG(es
->flags
, BGP_EVPNES_REMOTE
);
2017 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_REMOTE
)) {
2018 UNSET_FLAG(es
->flags
, BGP_EVPNES_REMOTE
);
2019 bgp_evpn_es_free(es
, __func__
);
2024 /* If ES is present and local it needs to be active/oper-up for
2027 bool bgp_evpn_es_add_l3_ecomm_ok(esi_t
*esi
)
2029 struct bgp_evpn_es
*es
;
2031 if (!esi
|| !bgp_mh_info
->suppress_l3_ecomm_on_inactive_es
)
2034 es
= bgp_evpn_es_find(esi
);
2036 return (!es
|| !(es
->flags
& BGP_EVPNES_LOCAL
)
2037 || bgp_evpn_local_es_is_active(es
));
2040 static bool bgp_evpn_is_valid_local_path(struct bgp_path_info
*pi
)
2042 return (CHECK_FLAG(pi
->flags
, BGP_PATH_VALID
)
2043 && pi
->type
== ZEBRA_ROUTE_BGP
2044 && pi
->sub_type
== BGP_ROUTE_STATIC
);
2047 /* Update all local MAC-IP routes in the VNI routing table associated
2048 * with the ES. When the ES is down the routes are advertised without
2051 static void bgp_evpn_mac_update_on_es_oper_chg(struct bgp_evpn_es
*es
)
2053 struct listnode
*node
;
2054 struct bgp_path_es_info
*es_info
;
2055 struct bgp_path_info
*pi
;
2057 struct bgpevpn
*vpn
;
2059 if (!bgp_mh_info
->suppress_l3_ecomm_on_inactive_es
)
2062 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2063 zlog_debug("update paths linked to es %s on oper chg",
2066 bgp
= bgp_get_evpn();
2067 for (ALL_LIST_ELEMENTS_RO(es
->macip_evi_path_list
, node
, es_info
)) {
2070 if (!bgp_evpn_is_valid_local_path(pi
))
2073 if (!bgp_evpn_is_macip_path(pi
))
2076 vpn
= bgp_evpn_lookup_vni(bgp
, es_info
->vni
);
2080 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
2082 "update path %d %pFX linked to es %s on oper chg",
2083 es_info
->vni
, &pi
->net
->p
, es
->esi_str
);
2085 bgp_evpn_update_type2_route_entry(bgp
, vpn
, pi
->net
, pi
,
2090 static bool bgp_evpn_is_valid_bgp_path(struct bgp_path_info
*pi
)
2092 return (CHECK_FLAG(pi
->flags
, BGP_PATH_VALID
)
2093 && pi
->type
== ZEBRA_ROUTE_BGP
2094 && pi
->sub_type
== BGP_ROUTE_NORMAL
);
2097 /* If an ES is no longer local (or becomes local) we need to re-install
2098 * paths using that ES as destination. This is needed as the criteria
2099 * for best path selection has changed.
2101 static void bgp_evpn_mac_update_on_es_local_chg(struct bgp_evpn_es
*es
,
2104 struct listnode
*node
;
2105 struct bgp_path_es_info
*es_info
;
2106 struct bgp_path_info
*pi
;
2108 struct attr
*attr_new
;
2109 struct attr attr_tmp
;
2111 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2112 zlog_debug("update paths linked to es %s on chg to %s",
2113 es
->esi_str
, is_local
? "local" : "non-local");
2115 for (ALL_LIST_ELEMENTS_RO(es
->macip_global_path_list
, node
, es_info
)) {
2118 /* Consider "valid" remote routes */
2119 if (!bgp_evpn_is_valid_bgp_path(pi
))
2125 tmp_local
= !!(pi
->attr
->es_flags
& ATTR_ES_IS_LOCAL
);
2126 if (tmp_local
== is_local
)
2129 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
2131 "update path %pFX linked to es %s on chg to %s",
2132 &pi
->net
->p
, es
->esi_str
,
2133 is_local
? "local" : "non-local");
2135 attr_tmp
= *pi
->attr
;
2137 attr_tmp
.es_flags
|= ATTR_ES_IS_LOCAL
;
2139 attr_tmp
.es_flags
&= ~ATTR_ES_IS_LOCAL
;
2140 attr_new
= bgp_attr_intern(&attr_tmp
);
2141 bgp_attr_unintern(&pi
->attr
);
2142 pi
->attr
= attr_new
;
2143 bgp_evpn_import_type2_route(pi
, 1);
2147 static void bgp_evpn_local_es_deactivate(struct bgp
*bgp
,
2148 struct bgp_evpn_es
*es
)
2150 struct prefix_evpn p
;
2154 /* Delete and withdraw locally learnt ES route */
2155 build_evpn_type4_prefix(&p
, &es
->esi
, es
->originator_ip
);
2156 ret
= bgp_evpn_type4_route_delete(bgp
, es
, &p
);
2158 flog_err(EC_BGP_EVPN_ROUTE_DELETE
,
2159 "%u failed to delete type-4 route for ESI %s",
2160 bgp
->vrf_id
, es
->esi_str
);
2163 /* withdraw EAD-EVI */
2164 if (!bgp_mh_info
->ead_evi_adv_for_down_links
)
2165 bgp_evpn_local_type1_evi_route_del(bgp
, es
);
2167 /* withdraw EAD-ES */
2168 bgp_evpn_ead_es_route_delete(bgp
, es
);
2170 bgp_evpn_mac_update_on_es_oper_chg(es
);
2173 /* Process ES link oper-down by withdrawing ES-EAD and ESR */
2174 static void bgp_evpn_local_es_down(struct bgp
*bgp
, struct bgp_evpn_es
*es
)
2178 if (!CHECK_FLAG(es
->flags
, BGP_EVPNES_OPER_UP
))
2181 old_active
= bgp_evpn_local_es_is_active(es
);
2182 UNSET_FLAG(es
->flags
, BGP_EVPNES_OPER_UP
);
2184 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2185 zlog_debug("local es %s down", es
->esi_str
);
2188 bgp_evpn_local_es_deactivate(bgp
, es
);
2191 static void bgp_evpn_local_es_activate(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
2192 bool regen_ead
, bool regen_esr
)
2194 struct prefix_evpn p
;
2197 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2198 zlog_debug("local es %s generate ESR", es
->esi_str
);
2200 build_evpn_type4_prefix(&p
, &es
->esi
, es
->originator_ip
);
2201 if (bgp_evpn_type4_route_update(bgp
, es
, &p
))
2202 flog_err(EC_BGP_EVPN_ROUTE_CREATE
,
2203 "%u: Type4 route creation failure for ESI %s",
2204 bgp
->vrf_id
, es
->esi_str
);
2208 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2209 zlog_debug("local es %s generate EAD", es
->esi_str
);
2210 /* generate EAD-EVI */
2211 bgp_evpn_local_type1_evi_route_add(bgp
, es
);
2213 /* generate EAD-ES */
2214 bgp_evpn_ead_es_route_update(bgp
, es
);
2217 bgp_evpn_mac_update_on_es_oper_chg(es
);
2220 /* Process ES link oper-up by generating ES-EAD and ESR */
2221 static void bgp_evpn_local_es_up(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
2224 bool regen_ead
= false;
2225 bool active
= false;
2227 if (!CHECK_FLAG(es
->flags
, BGP_EVPNES_OPER_UP
)) {
2228 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2229 zlog_debug("local es %s up", es
->esi_str
);
2231 SET_FLAG(es
->flags
, BGP_EVPNES_OPER_UP
);
2236 active
= bgp_evpn_local_es_is_active(es
);
2237 if (active
&& (regen_ead
|| regen_esr
))
2238 bgp_evpn_local_es_activate(bgp
, es
, regen_ead
, regen_esr
);
2241 /* If an ethernet segment is in LACP bypass we cannot advertise
2242 * reachability to it i.e. EAD-per-ES and ESR is not advertised in
2244 * PS: EAD-per-EVI will continue to be advertised
2246 static void bgp_evpn_local_es_bypass_update(struct bgp
*bgp
,
2247 struct bgp_evpn_es
*es
, bool bypass
)
2249 bool old_bypass
= !!(es
->flags
& BGP_EVPNES_BYPASS
);
2255 if (bypass
== old_bypass
)
2258 old_active
= bgp_evpn_local_es_is_active(es
);
2259 old_is_local
= bgp_evpn_is_es_local_and_non_bypass(es
);
2261 SET_FLAG(es
->flags
, BGP_EVPNES_BYPASS
);
2263 UNSET_FLAG(es
->flags
, BGP_EVPNES_BYPASS
);
2265 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2266 zlog_debug("local es %s bypass %s", es
->esi_str
,
2267 bypass
? "set" : "clear");
2269 new_active
= bgp_evpn_local_es_is_active(es
);
2270 if (old_active
!= new_active
) {
2272 bgp_evpn_local_es_activate(bgp
, es
, true, true);
2274 bgp_evpn_local_es_deactivate(bgp
, es
);
2277 is_local
= bgp_evpn_is_es_local_and_non_bypass(es
);
2278 if (old_is_local
!= is_local
)
2279 bgp_evpn_mac_update_on_es_local_chg(es
, is_local
);
2282 static void bgp_evpn_local_es_do_del(struct bgp
*bgp
, struct bgp_evpn_es
*es
)
2284 struct bgp_evpn_es_evi
*es_evi
;
2285 struct listnode
*evi_node
, *evi_next_node
;
2287 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2288 zlog_debug("del local es %s", es
->esi_str
);
2290 /* Delete all local EVPN ES routes from ESI table
2291 * and schedule for processing (to withdraw from peers))
2293 bgp_evpn_es_route_del_all(bgp
, es
);
2295 /* release all local ES EVIs associated with the ES */
2296 for (ALL_LIST_ELEMENTS(es
->es_evi_list
, evi_node
,
2297 evi_next_node
, es_evi
)) {
2298 bgp_evpn_local_es_evi_do_del(es_evi
);
2301 /* Clear local info associated with the ES and free it up if there is
2302 * no remote reference
2304 bgp_evpn_es_local_info_clear(es
, false);
2307 bool bgp_evpn_is_esi_local_and_non_bypass(esi_t
*esi
)
2309 struct bgp_evpn_es
*es
= NULL
;
2311 /* Lookup ESI hash - should exist. */
2312 es
= bgp_evpn_es_find(esi
);
2314 return es
&& bgp_evpn_is_es_local_and_non_bypass(es
);
2317 int bgp_evpn_local_es_del(struct bgp
*bgp
, esi_t
*esi
)
2319 struct bgp_evpn_es
*es
= NULL
;
2321 /* Lookup ESI hash - should exist. */
2322 es
= bgp_evpn_es_find(esi
);
2324 flog_warn(EC_BGP_EVPN_ESI
, "%u: ES missing at local ES DEL",
2329 bgp_evpn_local_es_do_del(bgp
, es
);
2333 /* Handle device to ES id association. Results in the creation of a local
2336 int bgp_evpn_local_es_add(struct bgp
*bgp
, esi_t
*esi
,
2337 struct in_addr originator_ip
, bool oper_up
,
2338 uint16_t df_pref
, bool bypass
)
2340 struct bgp_evpn_es
*es
;
2342 bool regen_esr
= false;
2344 /* create the new es */
2345 es
= bgp_evpn_es_find(esi
);
2347 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_LOCAL
))
2350 es
= bgp_evpn_es_new(bgp
, esi
);
2352 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2353 zlog_debug("add local es %s orig-ip %pI4 df_pref %u %s",
2354 es
->esi_str
, &originator_ip
, df_pref
,
2355 bypass
? "bypass" : "");
2357 es
->originator_ip
= originator_ip
;
2358 if (df_pref
!= es
->df_pref
) {
2359 es
->df_pref
= df_pref
;
2362 bgp_evpn_es_local_info_set(bgp
, es
);
2364 /* import all remote Type-4 routes in the ES table */
2366 bgp_evpn_type4_remote_routes_import(bgp
, es
,
2367 true /* install */);
2369 /* create and advertise EAD-EVI routes for the ES -
2370 * XXX - till an ES-EVI reference is created there is really nothing to
2373 if (bgp_mh_info
->ead_evi_adv_for_down_links
)
2374 bgp_evpn_local_type1_evi_route_add(bgp
, es
);
2376 bgp_evpn_local_es_bypass_update(bgp
, es
, bypass
);
2378 /* If the ES link is operationally up generate EAD-ES. EAD-EVI
2379 * can be generated even if the link is inactive.
2382 bgp_evpn_local_es_up(bgp
, es
, regen_esr
);
2384 bgp_evpn_local_es_down(bgp
, es
);
2389 static void bgp_evpn_es_json_frag_fill(json_object
*json_frags
,
2390 struct bgp_evpn_es
*es
)
2392 json_object
*json_frag
;
2393 struct listnode
*node
;
2394 struct bgp_evpn_es_frag
*es_frag
;
2396 for (ALL_LIST_ELEMENTS_RO(es
->es_frag_list
, node
, es_frag
)) {
2397 json_frag
= json_object_new_object();
2399 json_object_string_addf(json_frag
, "rd", "%pRDP",
2401 json_object_int_add(json_frag
, "eviCount",
2402 listcount(es_frag
->es_evi_frag_list
));
2404 json_object_array_add(json_frags
, json_frag
);
2408 static void bgp_evpn_es_frag_show_detail(struct vty
*vty
,
2409 struct bgp_evpn_es
*es
)
2411 struct listnode
*node
;
2412 struct bgp_evpn_es_frag
*es_frag
;
2414 for (ALL_LIST_ELEMENTS_RO(es
->es_frag_list
, node
, es_frag
)) {
2415 vty_out(vty
, " %pRDP EVIs: %d\n", &es_frag
->prd
,
2416 listcount(es_frag
->es_evi_frag_list
));
2420 static char *bgp_evpn_es_vteps_str(char *vtep_str
, struct bgp_evpn_es
*es
,
2421 uint8_t vtep_str_size
)
2423 char vtep_flag_str
[BGP_EVPN_FLAG_STR_SZ
];
2424 struct listnode
*node
;
2425 struct bgp_evpn_es_vtep
*es_vtep
;
2427 char ip_buf
[INET_ADDRSTRLEN
];
2430 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
2431 vtep_flag_str
[0] = '\0';
2433 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ESR
)
2434 strlcat(vtep_flag_str
, "E", sizeof(vtep_flag_str
));
2435 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ACTIVE
)
2436 strlcat(vtep_flag_str
, "A", sizeof(vtep_flag_str
));
2438 if (!strlen(vtep_flag_str
))
2439 strlcat(vtep_flag_str
, "-", sizeof(vtep_flag_str
));
2443 strlcat(vtep_str
, ",", vtep_str_size
);
2445 inet_ntop(AF_INET
, &es_vtep
->vtep_ip
, ip_buf
,
2448 strlcat(vtep_str
, "(", vtep_str_size
);
2449 strlcat(vtep_str
, vtep_flag_str
, vtep_str_size
);
2450 strlcat(vtep_str
, ")", vtep_str_size
);
2456 static void bgp_evpn_es_json_vtep_fill(json_object
*json_vteps
,
2457 struct bgp_evpn_es_vtep
*es_vtep
)
2459 json_object
*json_vtep_entry
;
2460 json_object
*json_flags
;
2461 char alg_buf
[EVPN_DF_ALG_STR_LEN
];
2463 json_vtep_entry
= json_object_new_object();
2465 json_object_string_addf(json_vtep_entry
, "vtep_ip", "%pI4",
2467 if (es_vtep
->flags
& (BGP_EVPNES_VTEP_ESR
|
2468 BGP_EVPNES_VTEP_ACTIVE
)) {
2469 json_flags
= json_object_new_array();
2470 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ESR
)
2471 json_array_string_add(json_flags
, "esr");
2472 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ACTIVE
)
2473 json_array_string_add(json_flags
, "active");
2474 json_object_object_add(json_vtep_entry
, "flags", json_flags
);
2475 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ESR
) {
2476 json_object_int_add(json_vtep_entry
, "dfPreference",
2478 json_object_string_add(
2479 json_vtep_entry
, "dfAlgorithm",
2480 evpn_es_df_alg2str(es_vtep
->df_alg
, alg_buf
,
2485 json_object_array_add(json_vteps
,
2489 static void bgp_evpn_es_vteps_show_detail(struct vty
*vty
,
2490 struct bgp_evpn_es
*es
)
2492 char vtep_flag_str
[BGP_EVPN_FLAG_STR_SZ
];
2493 struct listnode
*node
;
2494 struct bgp_evpn_es_vtep
*es_vtep
;
2495 char alg_buf
[EVPN_DF_ALG_STR_LEN
];
2497 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
2498 vtep_flag_str
[0] = '\0';
2499 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ESR
)
2500 strlcat(vtep_flag_str
, "E", sizeof(vtep_flag_str
));
2501 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ACTIVE
)
2502 strlcat(vtep_flag_str
, "A", sizeof(vtep_flag_str
));
2504 if (!strlen(vtep_flag_str
))
2505 strlcat(vtep_flag_str
, "-", sizeof(vtep_flag_str
));
2507 vty_out(vty
, " %pI4 flags: %s", &es_vtep
->vtep_ip
,
2510 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ESR
)
2511 vty_out(vty
, " df_alg: %s df_pref: %u\n",
2512 evpn_es_df_alg2str(es_vtep
->df_alg
, alg_buf
,
2520 static void bgp_evpn_es_show_entry(struct vty
*vty
,
2521 struct bgp_evpn_es
*es
, json_object
*json
)
2523 struct listnode
*node
;
2524 struct bgp_evpn_es_vtep
*es_vtep
;
2527 json_object
*json_vteps
;
2528 json_object
*json_types
;
2530 json_object_string_add(json
, "esi", es
->esi_str
);
2531 if (es
->es_base_frag
)
2532 json_object_string_addf(json
, "rd", "%pRDP",
2533 &es
->es_base_frag
->prd
);
2535 if (es
->flags
& (BGP_EVPNES_LOCAL
| BGP_EVPNES_REMOTE
)) {
2536 json_types
= json_object_new_array();
2537 if (es
->flags
& BGP_EVPNES_LOCAL
)
2538 json_array_string_add(json_types
, "local");
2539 if (es
->flags
& BGP_EVPNES_REMOTE
)
2540 json_array_string_add(json_types
, "remote");
2541 json_object_object_add(json
, "type", json_types
);
2544 if (listcount(es
->es_vtep_list
)) {
2545 json_vteps
= json_object_new_array();
2546 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
,
2548 bgp_evpn_es_json_vtep_fill(json_vteps
, es_vtep
);
2550 json_object_object_add(json
, "vteps", json_vteps
);
2552 json_object_int_add(json
, "vniCount",
2553 listcount(es
->es_evi_list
));
2556 char vtep_str
[ES_VTEP_LIST_STR_SZ
+ BGP_EVPN_VTEPS_FLAG_STR_SZ
];
2559 if (es
->flags
& BGP_EVPNES_BYPASS
)
2560 strlcat(type_str
, "B", sizeof(type_str
));
2561 if (es
->flags
& BGP_EVPNES_LOCAL
)
2562 strlcat(type_str
, "L", sizeof(type_str
));
2563 if (es
->flags
& BGP_EVPNES_REMOTE
)
2564 strlcat(type_str
, "R", sizeof(type_str
));
2565 if (es
->inconsistencies
)
2566 strlcat(type_str
, "I", sizeof(type_str
));
2568 bgp_evpn_es_vteps_str(vtep_str
, es
, sizeof(vtep_str
));
2570 vty_out(vty
, "%-30s %-5s %-21pRDP %-8d %s\n", es
->esi_str
,
2572 es
->es_base_frag
? &es
->es_base_frag
->prd
: NULL
,
2573 listcount(es
->es_evi_list
), vtep_str
);
2577 static void bgp_evpn_es_show_entry_detail(struct vty
*vty
,
2578 struct bgp_evpn_es
*es
, json_object
*json
)
2581 json_object
*json_flags
;
2582 json_object
*json_incons
;
2583 json_object
*json_vteps
;
2584 json_object
*json_frags
;
2585 struct listnode
*node
;
2586 struct bgp_evpn_es_vtep
*es_vtep
;
2588 /* Add the "brief" info first */
2589 bgp_evpn_es_show_entry(vty
, es
, json
);
2591 & (BGP_EVPNES_OPER_UP
| BGP_EVPNES_ADV_EVI
2592 | BGP_EVPNES_BYPASS
)) {
2593 json_flags
= json_object_new_array();
2594 if (es
->flags
& BGP_EVPNES_OPER_UP
)
2595 json_array_string_add(json_flags
, "up");
2596 if (es
->flags
& BGP_EVPNES_ADV_EVI
)
2597 json_array_string_add(json_flags
,
2599 if (es
->flags
& BGP_EVPNES_BYPASS
)
2600 json_array_string_add(json_flags
, "bypass");
2601 json_object_object_add(json
, "flags", json_flags
);
2603 json_object_string_addf(json
, "originator_ip", "%pI4",
2604 &es
->originator_ip
);
2605 json_object_int_add(json
, "remoteVniCount",
2606 es
->remote_es_evi_cnt
);
2607 json_object_int_add(json
, "vrfCount",
2608 listcount(es
->es_vrf_list
));
2609 json_object_int_add(json
, "macipPathCount",
2610 listcount(es
->macip_evi_path_list
));
2611 json_object_int_add(json
, "macipGlobalPathCount",
2612 listcount(es
->macip_global_path_list
));
2613 json_object_int_add(json
, "inconsistentVniVtepCount",
2614 es
->incons_evi_vtep_cnt
);
2615 if (es
->flags
& BGP_EVPNES_LOCAL
)
2616 json_object_int_add(json
, "localEsDfPreference",
2618 if (listcount(es
->es_vtep_list
)) {
2619 json_vteps
= json_object_new_array();
2620 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
,
2622 bgp_evpn_es_json_vtep_fill(json_vteps
, es_vtep
);
2624 json_object_object_add(json
, "vteps", json_vteps
);
2626 if (listcount(es
->es_frag_list
)) {
2627 json_frags
= json_object_new_array();
2628 bgp_evpn_es_json_frag_fill(json_frags
, es
);
2629 json_object_object_add(json
, "fragments", json_frags
);
2631 if (es
->inconsistencies
) {
2632 json_incons
= json_object_new_array();
2633 if (es
->inconsistencies
& BGP_EVPNES_INCONS_VTEP_LIST
)
2634 json_array_string_add(json_incons
,
2635 "vni-vtep-mismatch");
2636 json_object_object_add(json
, "inconsistencies",
2640 char incons_str
[BGP_EVPNES_INCONS_STR_SZ
];
2644 if (es
->flags
& BGP_EVPNES_LOCAL
)
2645 strlcat(type_str
, "L", sizeof(type_str
));
2646 if (es
->flags
& BGP_EVPNES_REMOTE
)
2647 strlcat(type_str
, "R", sizeof(type_str
));
2649 vty_out(vty
, "ESI: %s\n", es
->esi_str
);
2650 vty_out(vty
, " Type: %s\n", type_str
);
2651 vty_out(vty
, " RD: %pRDP\n",
2652 es
->es_base_frag
? &es
->es_base_frag
->prd
: NULL
);
2653 vty_out(vty
, " Originator-IP: %pI4\n", &es
->originator_ip
);
2654 if (es
->flags
& BGP_EVPNES_LOCAL
)
2655 vty_out(vty
, " Local ES DF preference: %u\n",
2657 if (es
->flags
& BGP_EVPNES_BYPASS
)
2658 vty_out(vty
, " LACP bypass: on\n");
2659 vty_out(vty
, " VNI Count: %d\n", listcount(es
->es_evi_list
));
2660 vty_out(vty
, " Remote VNI Count: %d\n",
2661 es
->remote_es_evi_cnt
);
2662 vty_out(vty
, " VRF Count: %d\n", listcount(es
->es_vrf_list
));
2663 vty_out(vty
, " MACIP EVI Path Count: %d\n",
2664 listcount(es
->macip_evi_path_list
));
2665 vty_out(vty
, " MACIP Global Path Count: %d\n",
2666 listcount(es
->macip_global_path_list
));
2667 vty_out(vty
, " Inconsistent VNI VTEP Count: %d\n",
2668 es
->incons_evi_vtep_cnt
);
2669 if (es
->inconsistencies
) {
2670 incons_str
[0] = '\0';
2671 if (es
->inconsistencies
& BGP_EVPNES_INCONS_VTEP_LIST
)
2672 strlcat(incons_str
, "vni-vtep-mismatch",
2673 sizeof(incons_str
));
2675 strlcpy(incons_str
, "-", sizeof(incons_str
));
2677 vty_out(vty
, " Inconsistencies: %s\n",
2679 if (listcount(es
->es_frag_list
)) {
2680 vty_out(vty
, " Fragments:\n");
2681 bgp_evpn_es_frag_show_detail(vty
, es
);
2683 if (listcount(es
->es_vtep_list
)) {
2684 vty_out(vty
, " VTEPs:\n");
2685 bgp_evpn_es_vteps_show_detail(vty
, es
);
2691 /* Display all ESs */
2692 void bgp_evpn_es_show(struct vty
*vty
, bool uj
, bool detail
)
2694 struct bgp_evpn_es
*es
;
2695 json_object
*json_array
= NULL
;
2696 json_object
*json
= NULL
;
2699 /* create an array of ESs */
2700 json_array
= json_object_new_array();
2704 "ES Flags: B - bypass, L local, R remote, I inconsistent\n");
2706 "VTEP Flags: E ESR/Type-4, A active nexthop\n");
2708 "%-30s %-5s %-21s %-8s %s\n",
2709 "ESI", "Flags", "RD", "#VNIs", "VTEPs");
2713 RB_FOREACH(es
, bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
) {
2715 /* create a separate json object for each ES */
2716 json
= json_object_new_object();
2718 bgp_evpn_es_show_entry_detail(vty
, es
, json
);
2720 bgp_evpn_es_show_entry(vty
, es
, json
);
2721 /* add ES to the json array */
2723 json_object_array_add(json_array
, json
);
2726 /* print the array of json-ESs */
2728 vty_json(vty
, json_array
);
2731 /* Display specific ES */
2732 void bgp_evpn_es_show_esi(struct vty
*vty
, esi_t
*esi
, bool uj
)
2734 struct bgp_evpn_es
*es
;
2735 json_object
*json
= NULL
;
2738 json
= json_object_new_object();
2740 es
= bgp_evpn_es_find(esi
);
2742 bgp_evpn_es_show_entry_detail(vty
, es
, json
);
2745 vty_out(vty
, "ESI not found\n");
2749 vty_json(vty
, json
);
2752 /*****************************************************************************/
2753 /* Ethernet Segment to VRF association -
2754 * 1. Each ES-EVI entry is associated with a tenant VRF. This associaton
2755 * triggers the creation of an ES-VRF entry.
2756 * 2. The ES-VRF entry is maintained for the purpose of L3-NHG creation
2757 * 3. Type-2/MAC-IP routes are imported into a tenant VRF and programmed as
2758 * a /32 or host route entry in the dataplane. If the destination of
2759 * the host route is a remote-ES the route is programmed with the
2760 * corresponding (keyed in by {vrf,ES-id}) L3-NHG.
2761 * 4. The reason for this indirection (route->L3-NHG, L3-NHG->list-of-VTEPs)
2762 * is to avoid route updates to the dplane when a remote-ES link flaps i.e.
2763 * instead of updating all the dependent routes the NHG's contents are updated.
2764 * This reduces the amount of datplane updates (nhg updates vs. route updates)
2765 * allowing for a faster failover.
2767 * XXX - can the L3 SVI index change without change in vpn->bgp_vrf
2768 * association? If yes we need to handle that by updating all the L3 NHGs
2771 /******************************** L3 NHG management *************************/
2772 static void bgp_evpn_l3nhg_zebra_add_v4_or_v6(struct bgp_evpn_es_vrf
*es_vrf
,
2775 uint32_t nhg_id
= v4_nhg
? es_vrf
->nhg_id
: es_vrf
->v6_nhg_id
;
2776 struct bgp_evpn_es
*es
= es_vrf
->es
;
2777 struct listnode
*node
;
2778 struct bgp_evpn_es_vtep
*es_vtep
;
2780 struct zapi_nexthop
*api_nh
;
2781 struct zapi_nhg api_nhg
= {};
2783 /* Skip installation of L3-NHG if host routes used */
2787 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2788 zlog_debug("es %s vrf %u %s nhg %u to zebra", es
->esi_str
,
2789 es_vrf
->bgp_vrf
->vrf_id
,
2790 v4_nhg
? "v4_nhg" : "v6_nhg", nhg_id
);
2792 frrtrace(4, frr_bgp
, evpn_mh_nhg_zsend
, true, v4_nhg
, nhg_id
, es_vrf
);
2794 /* only the gateway ip changes for each NH. rest of the params
2797 memset(&nh
, 0, sizeof(nh
));
2798 nh
.vrf_id
= es_vrf
->bgp_vrf
->vrf_id
;
2799 nh
.flags
= NEXTHOP_FLAG_ONLINK
;
2800 nh
.ifindex
= es_vrf
->bgp_vrf
->l3vni_svi_ifindex
;
2803 v4_nhg
? NEXTHOP_TYPE_IPV4_IFINDEX
: NEXTHOP_TYPE_IPV6_IFINDEX
;
2805 api_nhg
.id
= nhg_id
;
2806 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
2807 if (!CHECK_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
))
2810 /* Don't overrun the zapi buffer. */
2811 if (api_nhg
.nexthop_num
== MULTIPATH_NUM
)
2814 /* overwrite the gw */
2816 nh
.gate
.ipv4
= es_vtep
->vtep_ip
;
2818 ipv4_to_ipv4_mapped_ipv6(&nh
.gate
.ipv6
,
2821 /* convert to zapi format */
2822 api_nh
= &api_nhg
.nexthops
[api_nhg
.nexthop_num
];
2823 zapi_nexthop_from_nexthop(api_nh
, &nh
);
2825 ++api_nhg
.nexthop_num
;
2826 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2827 zlog_debug("nhg %u vtep %pI4 l3-svi %d", api_nhg
.id
,
2829 es_vrf
->bgp_vrf
->l3vni_svi_ifindex
);
2831 frrtrace(3, frr_bgp
, evpn_mh_nh_zsend
, nhg_id
, es_vtep
, es_vrf
);
2834 if (!api_nhg
.nexthop_num
)
2837 zclient_nhg_send(zclient
, ZEBRA_NHG_ADD
, &api_nhg
);
2840 static bool bgp_evpn_l3nhg_zebra_ok(struct bgp_evpn_es_vrf
*es_vrf
)
2842 if (!bgp_mh_info
->host_routes_use_l3nhg
)
2846 if (!zclient
|| zclient
->sock
< 0)
2852 static void bgp_evpn_l3nhg_zebra_add(struct bgp_evpn_es_vrf
*es_vrf
)
2854 if (!bgp_evpn_l3nhg_zebra_ok(es_vrf
))
2857 bgp_evpn_l3nhg_zebra_add_v4_or_v6(es_vrf
, true /*v4_nhg*/);
2858 bgp_evpn_l3nhg_zebra_add_v4_or_v6(es_vrf
, false /*v4_nhg*/);
2861 static void bgp_evpn_l3nhg_zebra_del_v4_or_v6(struct bgp_evpn_es_vrf
*es_vrf
,
2864 struct zapi_nhg api_nhg
= {};
2866 api_nhg
.id
= v4_nhg
? es_vrf
->nhg_id
: es_vrf
->v6_nhg_id
;
2868 /* Skip installation of L3-NHG if host routes used */
2872 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2873 zlog_debug("es %s vrf %u %s nhg %u to zebra",
2874 es_vrf
->es
->esi_str
, es_vrf
->bgp_vrf
->vrf_id
,
2875 v4_nhg
? "v4_nhg" : "v6_nhg", api_nhg
.id
);
2878 frrtrace(4, frr_bgp
, evpn_mh_nhg_zsend
, false, v4_nhg
, api_nhg
.id
,
2881 zclient_nhg_send(zclient
, ZEBRA_NHG_DEL
, &api_nhg
);
2884 static void bgp_evpn_l3nhg_zebra_del(struct bgp_evpn_es_vrf
*es_vrf
)
2886 if (!bgp_evpn_l3nhg_zebra_ok(es_vrf
))
2889 bgp_evpn_l3nhg_zebra_del_v4_or_v6(es_vrf
, true /*v4_nhg*/);
2890 bgp_evpn_l3nhg_zebra_del_v4_or_v6(es_vrf
, false /*v4_nhg*/);
2893 static void bgp_evpn_l3nhg_deactivate(struct bgp_evpn_es_vrf
*es_vrf
)
2895 if (!(es_vrf
->flags
& BGP_EVPNES_VRF_NHG_ACTIVE
))
2898 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2899 zlog_debug("es %s vrf %u nhg %u de-activate",
2900 es_vrf
->es
->esi_str
, es_vrf
->bgp_vrf
->vrf_id
,
2902 bgp_evpn_l3nhg_zebra_del(es_vrf
);
2903 es_vrf
->flags
&= ~BGP_EVPNES_VRF_NHG_ACTIVE
;
2904 /* MAC-IPs can now be installed via the L3NHG */
2905 bgp_evpn_es_path_update_on_es_vrf_chg(es_vrf
, "l3nhg-deactivate");
2908 static void bgp_evpn_l3nhg_activate(struct bgp_evpn_es_vrf
*es_vrf
, bool update
)
2910 if (!bgp_evpn_es_get_active_vtep_cnt(es_vrf
->es
)) {
2911 bgp_evpn_l3nhg_deactivate(es_vrf
);
2915 if (es_vrf
->flags
& BGP_EVPNES_VRF_NHG_ACTIVE
) {
2919 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2920 zlog_debug("es %s vrf %u nhg %u activate",
2921 es_vrf
->es
->esi_str
, es_vrf
->bgp_vrf
->vrf_id
,
2923 es_vrf
->flags
|= BGP_EVPNES_VRF_NHG_ACTIVE
;
2924 /* MAC-IPs can now be installed via the L3NHG */
2925 bgp_evpn_es_path_update_on_es_vrf_chg(es_vrf
, "l3nhg_activate");
2928 bgp_evpn_l3nhg_zebra_add(es_vrf
);
2931 /* when a VTEP is activated or de-activated against an ES associated
2932 * VRFs' NHG needs to be updated
2934 static void bgp_evpn_l3nhg_update_on_vtep_chg(struct bgp_evpn_es
*es
)
2936 struct bgp_evpn_es_vrf
*es_vrf
;
2937 struct listnode
*es_vrf_node
;
2939 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2940 zlog_debug("es %s nhg update on vtep chg", es
->esi_str
);
2942 for (ALL_LIST_ELEMENTS_RO(es
->es_vrf_list
, es_vrf_node
, es_vrf
))
2943 bgp_evpn_l3nhg_activate(es_vrf
, true /* update */);
2946 /* compare ES-IDs for the ES-VRF RB tree maintained per-VRF */
2947 static int bgp_es_vrf_rb_cmp(const struct bgp_evpn_es_vrf
*es_vrf1
,
2948 const struct bgp_evpn_es_vrf
*es_vrf2
)
2950 return memcmp(&es_vrf1
->es
->esi
, &es_vrf2
->es
->esi
, ESI_BYTES
);
2952 RB_GENERATE(bgp_es_vrf_rb_head
, bgp_evpn_es_vrf
, rb_node
, bgp_es_vrf_rb_cmp
);
2954 /* Initialize the ES tables maintained per-tenant vrf */
2955 void bgp_evpn_vrf_es_init(struct bgp
*bgp_vrf
)
2957 /* Initialize the ES-VRF RB tree */
2958 RB_INIT(bgp_es_vrf_rb_head
, &bgp_vrf
->es_vrf_rb_tree
);
2961 /* find the ES-VRF in the per-VRF RB tree */
2962 static struct bgp_evpn_es_vrf
*bgp_evpn_es_vrf_find(struct bgp_evpn_es
*es
,
2963 struct bgp
*bgp_vrf
)
2965 struct bgp_evpn_es_vrf es_vrf
;
2969 return RB_FIND(bgp_es_vrf_rb_head
, &bgp_vrf
->es_vrf_rb_tree
, &es_vrf
);
2972 /* allocate a new ES-VRF and setup L3NHG for it */
2973 static struct bgp_evpn_es_vrf
*bgp_evpn_es_vrf_create(struct bgp_evpn_es
*es
,
2974 struct bgp
*bgp_vrf
)
2976 struct bgp_evpn_es_vrf
*es_vrf
;
2978 es_vrf
= XCALLOC(MTYPE_BGP_EVPN_ES_VRF
, sizeof(*es_vrf
));
2981 es_vrf
->bgp_vrf
= bgp_vrf
;
2983 /* insert into the VRF-ESI rb tree */
2984 RB_INSERT(bgp_es_vrf_rb_head
, &bgp_vrf
->es_vrf_rb_tree
, es_vrf
);
2986 /* add to the ES's VRF list */
2987 listnode_init(&es_vrf
->es_listnode
, es_vrf
);
2988 listnode_add(es
->es_vrf_list
, &es_vrf
->es_listnode
);
2990 /* setup the L3 NHG id for the ES */
2991 es_vrf
->nhg_id
= bgp_l3nhg_id_alloc();
2992 es_vrf
->v6_nhg_id
= bgp_l3nhg_id_alloc();
2994 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2995 zlog_debug("es %s vrf %u nhg %u v6_nhg %d create", es
->esi_str
,
2996 bgp_vrf
->vrf_id
, es_vrf
->nhg_id
, es_vrf
->v6_nhg_id
);
2997 bgp_evpn_l3nhg_activate(es_vrf
, false /* update */);
2999 /* update paths in the VRF that may already be associated with
3000 * this destination ES
3002 bgp_evpn_es_path_update_on_es_vrf_chg(es_vrf
, "es-vrf-create");
3007 /* remove the L3-NHG associated with the ES-VRF and free it */
3008 static void bgp_evpn_es_vrf_delete(struct bgp_evpn_es_vrf
*es_vrf
)
3010 struct bgp_evpn_es
*es
= es_vrf
->es
;
3011 struct bgp
*bgp_vrf
= es_vrf
->bgp_vrf
;
3013 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3014 zlog_debug("es %s vrf %u nhg %u delete", es
->esi_str
,
3015 bgp_vrf
->vrf_id
, es_vrf
->nhg_id
);
3017 /* Remove the NHG resources */
3018 bgp_evpn_l3nhg_deactivate(es_vrf
);
3020 bgp_l3nhg_id_free(es_vrf
->nhg_id
);
3022 if (es_vrf
->v6_nhg_id
)
3023 bgp_l3nhg_id_free(es_vrf
->v6_nhg_id
);
3024 es_vrf
->v6_nhg_id
= 0;
3026 /* remove from the ES's VRF list */
3027 list_delete_node(es
->es_vrf_list
, &es_vrf
->es_listnode
);
3029 /* remove from the VRF-ESI rb tree */
3030 RB_REMOVE(bgp_es_vrf_rb_head
, &bgp_vrf
->es_vrf_rb_tree
, es_vrf
);
3032 /* update paths in the VRF that may already be associated with
3033 * this destination ES
3035 bgp_evpn_es_path_update_on_es_vrf_chg(es_vrf
, "es-vrf-delete");
3037 XFREE(MTYPE_BGP_EVPN_ES_VRF
, es_vrf
);
3040 /* deref and delete if there are no references */
3041 void bgp_evpn_es_vrf_deref(struct bgp_evpn_es_evi
*es_evi
)
3043 struct bgp_evpn_es_vrf
*es_vrf
= es_evi
->es_vrf
;
3048 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3049 zlog_debug("es-evi %s vni %u vrf %u de-ref",
3050 es_evi
->es
->esi_str
, es_evi
->vpn
->vni
,
3051 es_vrf
->bgp_vrf
->vrf_id
);
3053 es_evi
->es_vrf
= NULL
;
3054 if (es_vrf
->ref_cnt
)
3057 if (!es_vrf
->ref_cnt
)
3058 bgp_evpn_es_vrf_delete(es_vrf
);
3061 /* find or create and reference */
3062 void bgp_evpn_es_vrf_ref(struct bgp_evpn_es_evi
*es_evi
, struct bgp
*bgp_vrf
)
3064 struct bgp_evpn_es
*es
= es_evi
->es
;
3065 struct bgp_evpn_es_vrf
*es_vrf
= es_evi
->es_vrf
;
3066 struct bgp
*old_bgp_vrf
= NULL
;
3069 old_bgp_vrf
= es_vrf
->bgp_vrf
;
3071 if (old_bgp_vrf
== bgp_vrf
)
3074 /* deref the old ES-VRF */
3075 bgp_evpn_es_vrf_deref(es_evi
);
3080 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3081 zlog_debug("es-evi %s vni %u vrf %u ref", es_evi
->es
->esi_str
,
3082 es_evi
->vpn
->vni
, bgp_vrf
->vrf_id
);
3084 /* find-create the new ES-VRF */
3085 es_vrf
= bgp_evpn_es_vrf_find(es
, bgp_vrf
);
3087 es_vrf
= bgp_evpn_es_vrf_create(es
, bgp_vrf
);
3089 es_evi
->es_vrf
= es_vrf
;
3093 /* When the L2-VNI is associated with a L3-VNI/VRF update all the
3094 * associated ES-EVI entries
3096 void bgp_evpn_es_evi_vrf_deref(struct bgpevpn
*vpn
)
3098 struct bgp_evpn_es_evi
*es_evi
;
3100 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3101 zlog_debug("es-vrf de-ref for vni %u", vpn
->vni
);
3103 RB_FOREACH (es_evi
, bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
)
3104 bgp_evpn_es_vrf_deref(es_evi
);
3106 void bgp_evpn_es_evi_vrf_ref(struct bgpevpn
*vpn
)
3108 struct bgp_evpn_es_evi
*es_evi
;
3110 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3111 zlog_debug("es-vrf ref for vni %u", vpn
->vni
);
3113 RB_FOREACH (es_evi
, bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
)
3114 bgp_evpn_es_vrf_ref(es_evi
, vpn
->bgp_vrf
);
3117 /* 1. If ES-VRF is not present install the host route with the exploded/flat
3119 * 2. If ES-VRF is present -
3120 * - if L3NHG has not been activated for the ES-VRF (this could be because
3121 * all the PEs attached to the VRF are down) do not install the route
3123 * - if L3NHG has been activated install the route via that L3NHG
3125 void bgp_evpn_es_vrf_use_nhg(struct bgp
*bgp_vrf
, esi_t
*esi
, bool *use_l3nhg
,
3126 bool *is_l3nhg_active
,
3127 struct bgp_evpn_es_vrf
**es_vrf_p
)
3129 struct bgp_evpn_es
*es
;
3130 struct bgp_evpn_es_vrf
*es_vrf
;
3132 if (!bgp_mh_info
->host_routes_use_l3nhg
)
3135 es
= bgp_evpn_es_find(esi
);
3139 es_vrf
= bgp_evpn_es_vrf_find(es
, bgp_vrf
);
3144 if (es_vrf
->flags
& BGP_EVPNES_VRF_NHG_ACTIVE
)
3145 *is_l3nhg_active
= true;
3150 /* returns false if legacy-exploded mp needs to be used for route install */
3151 bool bgp_evpn_path_es_use_nhg(struct bgp
*bgp_vrf
, struct bgp_path_info
*pi
,
3155 struct bgp_evpn_es_vrf
*es_vrf
= NULL
;
3156 struct bgp_path_info
*parent_pi
;
3157 struct bgp_node
*rn
;
3158 struct prefix_evpn
*evp
;
3159 struct bgp_path_info
*mpinfo
;
3160 bool use_l3nhg
= false;
3161 bool is_l3nhg_active
= false;
3165 /* we don't support NHG for routes leaked from another VRF yet */
3166 if (pi
->extra
&& pi
->extra
->bgp_orig
)
3169 parent_pi
= get_route_parent_evpn(pi
);
3173 rn
= parent_pi
->net
;
3177 evp
= (struct prefix_evpn
*)&rn
->p
;
3178 if (evp
->prefix
.route_type
!= BGP_EVPN_MAC_IP_ROUTE
)
3181 /* non-es path, use legacy-exploded multipath */
3182 esi
= bgp_evpn_attr_get_esi(parent_pi
->attr
);
3183 if (!memcmp(esi
, zero_esi
, sizeof(*esi
)))
3186 /* we don't support NHG for d-vni yet */
3187 if (bgp_evpn_mpath_has_dvni(bgp_vrf
, pi
))
3190 bgp_evpn_es_vrf_use_nhg(bgp_vrf
, esi
, &use_l3nhg
, &is_l3nhg_active
,
3193 /* L3NHG support is disabled, use legacy-exploded multipath */
3197 /* if the NHG has not been installed we cannot install the route yet,
3198 * return a 0-NHG to indicate that
3200 if (!is_l3nhg_active
)
3203 /* this needs to be set the v6NHG if v6route */
3204 if (is_evpn_prefix_ipaddr_v6(evp
))
3205 *nhg_p
= es_vrf
->v6_nhg_id
;
3207 *nhg_p
= es_vrf
->nhg_id
;
3209 for (mpinfo
= bgp_path_info_mpath_next(pi
); mpinfo
;
3210 mpinfo
= bgp_path_info_mpath_next(mpinfo
)) {
3211 /* if any of the paths have a different ESI we can't use
3212 * the NHG associated with the ES. fallback to legacy-exploded
3215 if (memcmp(esi
, bgp_evpn_attr_get_esi(mpinfo
->attr
),
3223 static void bgp_evpn_es_vrf_show_entry(struct vty
*vty
,
3224 struct bgp_evpn_es_vrf
*es_vrf
,
3227 struct bgp_evpn_es
*es
= es_vrf
->es
;
3228 struct bgp
*bgp_vrf
= es_vrf
->bgp_vrf
;
3231 json_object
*json_types
;
3233 json_object_string_add(json
, "esi", es
->esi_str
);
3234 json_object_string_add(json
, "vrf", bgp_vrf
->name_pretty
);
3236 if (es_vrf
->flags
& (BGP_EVPNES_VRF_NHG_ACTIVE
)) {
3237 json_types
= json_object_new_array();
3238 if (es_vrf
->flags
& BGP_EVPNES_VRF_NHG_ACTIVE
)
3239 json_array_string_add(json_types
, "active");
3240 json_object_object_add(json
, "flags", json_types
);
3243 json_object_int_add(json
, "ipv4NHG", es_vrf
->nhg_id
);
3244 json_object_int_add(json
, "ipv6NHG", es_vrf
->v6_nhg_id
);
3245 json_object_int_add(json
, "refCount", es_vrf
->ref_cnt
);
3249 flags_str
[0] = '\0';
3250 if (es_vrf
->flags
& BGP_EVPNES_VRF_NHG_ACTIVE
)
3251 strlcat(flags_str
, "A", sizeof(flags_str
));
3253 vty_out(vty
, "%-30s %-15s %-5s %-8u %-8u %u\n", es
->esi_str
,
3254 bgp_vrf
->name_pretty
, flags_str
, es_vrf
->nhg_id
,
3255 es_vrf
->v6_nhg_id
, es_vrf
->ref_cnt
);
3259 static void bgp_evpn_es_vrf_show_es(struct vty
*vty
, json_object
*json_array
,
3260 struct bgp_evpn_es
*es
)
3262 json_object
*json
= NULL
;
3263 struct listnode
*es_vrf_node
;
3264 struct bgp_evpn_es_vrf
*es_vrf
;
3266 for (ALL_LIST_ELEMENTS_RO(es
->es_vrf_list
, es_vrf_node
, es_vrf
)) {
3267 /* create a separate json object for each ES-VRF */
3269 json
= json_object_new_object();
3270 bgp_evpn_es_vrf_show_entry(vty
, es_vrf
, json
);
3271 /* add ES-VRF to the json array */
3273 json_object_array_add(json_array
, json
);
3277 /* Display all ES VRFs */
3278 void bgp_evpn_es_vrf_show(struct vty
*vty
, bool uj
, struct bgp_evpn_es
*es
)
3280 json_object
*json_array
= NULL
;
3283 /* create an array of ESs */
3284 json_array
= json_object_new_array();
3286 vty_out(vty
, "ES-VRF Flags: A Active\n");
3287 vty_out(vty
, "%-30s %-15s %-5s %-8s %-8s %s\n", "ESI", "VRF",
3288 "Flags", "IPv4-NHG", "IPv6-NHG", "Ref");
3292 bgp_evpn_es_vrf_show_es(vty
, json_array
, es
);
3294 RB_FOREACH (es
, bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
)
3295 bgp_evpn_es_vrf_show_es(vty
, json_array
, es
);
3298 /* print the array of json-ESs */
3300 vty_json(vty
, json_array
);
3303 /* Display specific ES VRF */
3304 void bgp_evpn_es_vrf_show_esi(struct vty
*vty
, esi_t
*esi
, bool uj
)
3306 struct bgp_evpn_es
*es
;
3308 es
= bgp_evpn_es_find(esi
);
3310 bgp_evpn_es_vrf_show(vty
, uj
, es
);
3313 vty_out(vty
, "ESI not found\n");
3317 /*****************************************************************************/
3318 /* Ethernet Segment to EVI association -
3319 * 1. The ES-EVI entry is maintained as a RB tree per L2-VNI
3320 * (bgpevpn->es_evi_rb_tree).
3321 * 2. Each local ES-EVI entry is rxed from zebra and then used by BGP to
3322 * advertises an EAD-EVI (Type-1 EVPN) route
3323 * 3. The remote ES-EVI is created when a bgp_evpn_es_evi_vtep references
3327 /* A list of remote VTEPs is maintained for each ES-EVI. This list includes -
3328 * 1. VTEPs for which we have imported the EAD-per-ES Type1 route
3329 * 2. VTEPs for which we have imported the EAD-per-EVI Type1 route
3330 * VTEPs for which both routes have been rxed are activated. Activation
3331 * creates a NHG in the parent ES.
3333 static int bgp_evpn_es_evi_vtep_cmp(void *p1
, void *p2
)
3335 const struct bgp_evpn_es_evi_vtep
*evi_vtep1
= p1
;
3336 const struct bgp_evpn_es_evi_vtep
*evi_vtep2
= p2
;
3338 return evi_vtep1
->vtep_ip
.s_addr
- evi_vtep2
->vtep_ip
.s_addr
;
3341 static struct bgp_evpn_es_evi_vtep
*bgp_evpn_es_evi_vtep_new(
3342 struct bgp_evpn_es_evi
*es_evi
, struct in_addr vtep_ip
)
3344 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
3346 evi_vtep
= XCALLOC(MTYPE_BGP_EVPN_ES_EVI_VTEP
, sizeof(*evi_vtep
));
3348 evi_vtep
->es_evi
= es_evi
;
3349 evi_vtep
->vtep_ip
.s_addr
= vtep_ip
.s_addr
;
3350 listnode_init(&evi_vtep
->es_evi_listnode
, evi_vtep
);
3351 listnode_add_sort(es_evi
->es_evi_vtep_list
, &evi_vtep
->es_evi_listnode
);
3356 static void bgp_evpn_es_evi_vtep_free(struct bgp_evpn_es_evi_vtep
*evi_vtep
)
3358 struct bgp_evpn_es_evi
*es_evi
= evi_vtep
->es_evi
;
3360 if (evi_vtep
->flags
& (BGP_EVPN_EVI_VTEP_EAD
))
3361 /* as long as there is some reference we can't free it */
3364 list_delete_node(es_evi
->es_evi_vtep_list
, &evi_vtep
->es_evi_listnode
);
3365 XFREE(MTYPE_BGP_EVPN_ES_EVI_VTEP
, evi_vtep
);
3368 /* check if VTEP is already part of the list */
3369 static struct bgp_evpn_es_evi_vtep
*bgp_evpn_es_evi_vtep_find(
3370 struct bgp_evpn_es_evi
*es_evi
, struct in_addr vtep_ip
)
3372 struct listnode
*node
= NULL
;
3373 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
3375 for (ALL_LIST_ELEMENTS_RO(es_evi
->es_evi_vtep_list
, node
, evi_vtep
)) {
3376 if (evi_vtep
->vtep_ip
.s_addr
== vtep_ip
.s_addr
)
3382 /* A VTEP can be added as "active" attach to an ES if EAD-per-ES and
3383 * EAD-per-EVI routes are rxed from it.
3385 static void bgp_evpn_es_evi_vtep_re_eval_active(struct bgp
*bgp
,
3386 struct bgp_evpn_es_evi_vtep
*evi_vtep
)
3390 uint32_t ead_activity_flags
;
3392 old_active
= CHECK_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
);
3394 if (bgp_mh_info
->ead_evi_rx
)
3395 /* Both EAD-per-ES and EAD-per-EVI routes must be rxed from a PE
3396 * before it can be activated.
3398 ead_activity_flags
= BGP_EVPN_EVI_VTEP_EAD
;
3400 /* EAD-per-ES is sufficent to activate the PE */
3401 ead_activity_flags
= BGP_EVPN_EVI_VTEP_EAD_PER_ES
;
3403 if ((evi_vtep
->flags
& ead_activity_flags
) == ead_activity_flags
)
3404 SET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
);
3406 UNSET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
);
3408 new_active
= CHECK_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
);
3410 if (old_active
== new_active
)
3413 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3414 zlog_debug("es %s evi %u vtep %pI4 %s",
3415 evi_vtep
->es_evi
->es
->esi_str
,
3416 evi_vtep
->es_evi
->vpn
->vni
, &evi_vtep
->vtep_ip
,
3417 new_active
? "active" : "inactive");
3419 /* add VTEP to parent es */
3421 evi_vtep
->es_vtep
= bgp_evpn_es_vtep_add(
3422 bgp
, evi_vtep
->es_evi
->es
, evi_vtep
->vtep_ip
,
3423 false /*esr*/, 0, 0);
3425 if (evi_vtep
->es_vtep
) {
3426 bgp_evpn_es_vtep_do_del(bgp
, evi_vtep
->es_vtep
,
3428 evi_vtep
->es_vtep
= NULL
;
3431 /* queue up the parent es for background consistency checks */
3432 bgp_evpn_es_cons_checks_pend_add(evi_vtep
->es_evi
->es
);
3435 static void bgp_evpn_es_evi_vtep_add(struct bgp
*bgp
,
3436 struct bgp_evpn_es_evi
*es_evi
, struct in_addr vtep_ip
,
3439 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
3441 evi_vtep
= bgp_evpn_es_evi_vtep_find(es_evi
, vtep_ip
);
3444 evi_vtep
= bgp_evpn_es_evi_vtep_new(es_evi
, vtep_ip
);
3446 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3447 zlog_debug("add es %s evi %u vtep %pI4 %s",
3448 evi_vtep
->es_evi
->es
->esi_str
,
3449 evi_vtep
->es_evi
->vpn
->vni
, &evi_vtep
->vtep_ip
,
3450 ead_es
? "ead_es" : "ead_evi");
3453 SET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_EAD_PER_ES
);
3455 SET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_EAD_PER_EVI
);
3457 bgp_evpn_es_evi_vtep_re_eval_active(bgp
, evi_vtep
);
3460 static void bgp_evpn_es_evi_vtep_del(struct bgp
*bgp
,
3461 struct bgp_evpn_es_evi
*es_evi
, struct in_addr vtep_ip
,
3464 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
3466 evi_vtep
= bgp_evpn_es_evi_vtep_find(es_evi
, vtep_ip
);
3470 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3471 zlog_debug("del es %s evi %u vtep %pI4 %s",
3472 evi_vtep
->es_evi
->es
->esi_str
,
3473 evi_vtep
->es_evi
->vpn
->vni
, &evi_vtep
->vtep_ip
,
3474 ead_es
? "ead_es" : "ead_evi");
3477 UNSET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_EAD_PER_ES
);
3479 UNSET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_EAD_PER_EVI
);
3481 bgp_evpn_es_evi_vtep_re_eval_active(bgp
, evi_vtep
);
3482 bgp_evpn_es_evi_vtep_free(evi_vtep
);
3485 /* compare ES-IDs for the ES-EVI RB tree maintained per-VNI */
3486 static int bgp_es_evi_rb_cmp(const struct bgp_evpn_es_evi
*es_evi1
,
3487 const struct bgp_evpn_es_evi
*es_evi2
)
3489 return memcmp(&es_evi1
->es
->esi
, &es_evi2
->es
->esi
, ESI_BYTES
);
3491 RB_GENERATE(bgp_es_evi_rb_head
, bgp_evpn_es_evi
, rb_node
, bgp_es_evi_rb_cmp
);
3493 /* find the ES-EVI in the per-L2-VNI RB tree */
3494 static struct bgp_evpn_es_evi
*bgp_evpn_es_evi_find(struct bgp_evpn_es
*es
,
3495 struct bgpevpn
*vpn
)
3497 struct bgp_evpn_es_evi es_evi
;
3501 return RB_FIND(bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
, &es_evi
);
3504 /* allocate a new ES-EVI and insert it into the per-L2-VNI and per-ES
3507 static struct bgp_evpn_es_evi
*bgp_evpn_es_evi_new(struct bgp_evpn_es
*es
,
3508 struct bgpevpn
*vpn
)
3510 struct bgp_evpn_es_evi
*es_evi
;
3512 es_evi
= XCALLOC(MTYPE_BGP_EVPN_ES_EVI
, sizeof(*es_evi
));
3517 /* Initialise the VTEP list */
3518 es_evi
->es_evi_vtep_list
= list_new();
3519 listset_app_node_mem(es_evi
->es_evi_vtep_list
);
3520 es_evi
->es_evi_vtep_list
->cmp
= bgp_evpn_es_evi_vtep_cmp
;
3522 /* insert into the VNI-ESI rb tree */
3523 RB_INSERT(bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
, es_evi
);
3525 /* add to the ES's VNI list */
3526 listnode_init(&es_evi
->es_listnode
, es_evi
);
3527 listnode_add(es
->es_evi_list
, &es_evi
->es_listnode
);
3529 bgp_evpn_es_vrf_ref(es_evi
, vpn
->bgp_vrf
);
3534 /* remove the ES-EVI from the per-L2-VNI and per-ES tables and free
3537 static struct bgp_evpn_es_evi
*
3538 bgp_evpn_es_evi_free(struct bgp_evpn_es_evi
*es_evi
)
3540 struct bgp_evpn_es
*es
= es_evi
->es
;
3541 struct bgpevpn
*vpn
= es_evi
->vpn
;
3543 /* cannot free the element as long as there is a local or remote
3546 if (es_evi
->flags
& (BGP_EVPNES_EVI_LOCAL
| BGP_EVPNES_EVI_REMOTE
))
3548 bgp_evpn_es_frag_evi_del(es_evi
, false);
3549 bgp_evpn_es_vrf_deref(es_evi
);
3551 /* remove from the ES's VNI list */
3552 list_delete_node(es
->es_evi_list
, &es_evi
->es_listnode
);
3554 /* remove from the VNI-ESI rb tree */
3555 RB_REMOVE(bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
, es_evi
);
3557 /* free the VTEP list */
3558 list_delete(&es_evi
->es_evi_vtep_list
);
3560 /* remove from the VNI-ESI rb tree */
3561 XFREE(MTYPE_BGP_EVPN_ES_EVI
, es_evi
);
3566 /* init local info associated with the ES-EVI */
3567 static void bgp_evpn_es_evi_local_info_set(struct bgp_evpn_es_evi
*es_evi
)
3569 struct bgpevpn
*vpn
= es_evi
->vpn
;
3571 if (CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
3574 SET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
);
3575 listnode_init(&es_evi
->l2vni_listnode
, es_evi
);
3576 listnode_add(vpn
->local_es_evi_list
, &es_evi
->l2vni_listnode
);
3577 bgp_evpn_es_frag_evi_add(es_evi
);
3580 /* clear any local info associated with the ES-EVI */
3581 static struct bgp_evpn_es_evi
*
3582 bgp_evpn_es_evi_local_info_clear(struct bgp_evpn_es_evi
*es_evi
)
3584 struct bgpevpn
*vpn
= es_evi
->vpn
;
3586 UNSET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
);
3587 list_delete_node(vpn
->local_es_evi_list
, &es_evi
->l2vni_listnode
);
3589 return bgp_evpn_es_evi_free(es_evi
);
3592 /* eval remote info associated with the ES */
3593 static void bgp_evpn_es_evi_remote_info_re_eval(struct bgp_evpn_es_evi
*es_evi
)
3595 struct bgp_evpn_es
*es
= es_evi
->es
;
3597 /* if there are remote VTEPs the ES-EVI is classified as "remote" */
3598 if (listcount(es_evi
->es_evi_vtep_list
)) {
3599 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_REMOTE
)) {
3600 SET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_REMOTE
);
3601 ++es
->remote_es_evi_cnt
;
3602 /* set remote on the parent es */
3603 bgp_evpn_es_remote_info_re_eval(es
);
3606 if (CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_REMOTE
)) {
3607 UNSET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_REMOTE
);
3608 if (es
->remote_es_evi_cnt
)
3609 --es
->remote_es_evi_cnt
;
3610 bgp_evpn_es_evi_free(es_evi
);
3611 /* check if "remote" can be cleared from the
3614 bgp_evpn_es_remote_info_re_eval(es
);
3619 static struct bgp_evpn_es_evi
*
3620 bgp_evpn_local_es_evi_do_del(struct bgp_evpn_es_evi
*es_evi
)
3622 struct prefix_evpn p
;
3623 struct bgp_evpn_es
*es
= es_evi
->es
;
3626 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
3629 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3630 zlog_debug("del local es %s evi %u",
3631 es_evi
->es
->esi_str
,
3634 bgp
= bgp_get_evpn();
3636 /* remove the es_evi from the es_frag before sending the update */
3637 bgp_evpn_es_frag_evi_del(es_evi
, true);
3639 /* update EAD-ES with new list of VNIs */
3640 if (bgp_evpn_local_es_is_active(es
))
3641 bgp_evpn_ead_es_route_update(bgp
, es
);
3643 /* withdraw and delete EAD-EVI */
3644 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
)) {
3645 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_EVI_ETH_TAG
,
3646 &es
->esi
, es
->originator_ip
);
3647 if (bgp_evpn_ead_evi_route_delete(bgp
, es
, es_evi
->vpn
,
3649 flog_err(EC_BGP_EVPN_ROUTE_DELETE
,
3650 "%u: EAD-EVI route deletion failure for ESI %s VNI %u",
3651 bgp
->vrf_id
, es
->esi_str
,
3656 return bgp_evpn_es_evi_local_info_clear(es_evi
);
3659 int bgp_evpn_local_es_evi_del(struct bgp
*bgp
, esi_t
*esi
, vni_t vni
)
3661 struct bgpevpn
*vpn
;
3662 struct bgp_evpn_es
*es
;
3663 struct bgp_evpn_es_evi
*es_evi
;
3664 char buf
[ESI_STR_LEN
];
3666 es
= bgp_evpn_es_find(esi
);
3670 "%u: Failed to deref VNI %d from ESI %s; ES not present",
3672 esi_to_str(esi
, buf
, sizeof(buf
)));
3676 vpn
= bgp_evpn_lookup_vni(bgp
, vni
);
3680 "%u: Failed to deref VNI %d from ESI %s; VNI not present",
3681 bgp
->vrf_id
, vni
, es
->esi_str
);
3685 es_evi
= bgp_evpn_es_evi_find(es
, vpn
);
3689 "%u: Failed to deref VNI %d from ESI %s; ES-VNI not present",
3690 bgp
->vrf_id
, vni
, es
->esi_str
);
3694 bgp_evpn_local_es_evi_do_del(es_evi
);
3698 /* Create ES-EVI and advertise the corresponding EAD routes */
3699 int bgp_evpn_local_es_evi_add(struct bgp
*bgp
, esi_t
*esi
, vni_t vni
)
3701 struct bgpevpn
*vpn
;
3702 struct prefix_evpn p
;
3703 struct bgp_evpn_es
*es
;
3704 struct bgp_evpn_es_evi
*es_evi
;
3705 char buf
[ESI_STR_LEN
];
3707 es
= bgp_evpn_es_find(esi
);
3711 "%u: Failed to associate VNI %d with ESI %s; ES not present",
3713 esi_to_str(esi
, buf
, sizeof(buf
)));
3717 vpn
= bgp_evpn_lookup_vni(bgp
, vni
);
3721 "%u: Failed to associate VNI %d with ESI %s; VNI not present",
3722 bgp
->vrf_id
, vni
, es
->esi_str
);
3726 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3727 zlog_debug("add local es %s evi %u",
3730 es_evi
= bgp_evpn_es_evi_find(es
, vpn
);
3733 if (CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
3737 es_evi
= bgp_evpn_es_evi_new(es
, vpn
);
3739 bgp_evpn_es_evi_local_info_set(es_evi
);
3741 /* generate an EAD-EVI for this new VNI */
3742 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
)) {
3743 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_EVI_ETH_TAG
, &es
->esi
,
3745 bgp_evpn_ead_evi_route_update(bgp
, es
, vpn
, &p
);
3749 if (bgp_evpn_local_es_is_active(es
))
3750 bgp_evpn_ead_es_route_update(bgp
, es
);
3755 /* Add remote ES-EVI entry. This is actually the remote VTEP add and the
3756 * ES-EVI is implicity created on first VTEP's reference.
3758 int bgp_evpn_remote_es_evi_add(struct bgp
*bgp
, struct bgpevpn
*vpn
,
3759 const struct prefix_evpn
*p
)
3761 char buf
[ESI_STR_LEN
];
3762 struct bgp_evpn_es
*es
;
3763 struct bgp_evpn_es_evi
*es_evi
;
3765 const esi_t
*esi
= &p
->prefix
.ead_addr
.esi
;
3768 /* local EAD-ES need not be sent back to zebra */
3771 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3772 zlog_debug("add remote %s es %s evi %u vtep %pI4",
3773 p
->prefix
.ead_addr
.eth_tag
? "ead-es" : "ead-evi",
3774 esi_to_str(esi
, buf
, sizeof(buf
)), vpn
->vni
,
3775 &p
->prefix
.ead_addr
.ip
.ipaddr_v4
);
3777 es
= bgp_evpn_es_find(esi
);
3779 es
= bgp_evpn_es_new(bgp
, esi
);
3781 es_evi
= bgp_evpn_es_evi_find(es
, vpn
);
3783 es_evi
= bgp_evpn_es_evi_new(es
, vpn
);
3785 ead_es
= !!p
->prefix
.ead_addr
.eth_tag
;
3786 bgp_evpn_es_evi_vtep_add(bgp
, es_evi
, p
->prefix
.ead_addr
.ip
.ipaddr_v4
,
3789 bgp_evpn_es_evi_remote_info_re_eval(es_evi
);
3793 /* A remote VTEP has withdrawn. The es-evi-vtep will be deleted and the
3794 * parent es-evi freed up implicitly in last VTEP's deref.
3796 int bgp_evpn_remote_es_evi_del(struct bgp
*bgp
, struct bgpevpn
*vpn
,
3797 const struct prefix_evpn
*p
)
3799 char buf
[ESI_STR_LEN
];
3800 struct bgp_evpn_es
*es
;
3801 struct bgp_evpn_es_evi
*es_evi
;
3805 /* local EAD-ES need not be sent back to zebra */
3808 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3810 "del remote %s es %s evi %u vtep %pI4",
3811 p
->prefix
.ead_addr
.eth_tag
? "ead-es" : "ead-evi",
3812 esi_to_str(&p
->prefix
.ead_addr
.esi
, buf
, sizeof(buf
)),
3813 vpn
->vni
, &p
->prefix
.ead_addr
.ip
.ipaddr_v4
);
3815 es
= bgp_evpn_es_find(&p
->prefix
.ead_addr
.esi
);
3817 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3819 "del remote %s es %s evi %u vtep %pI4, NO es",
3820 p
->prefix
.ead_addr
.eth_tag
? "ead-es"
3822 esi_to_str(&p
->prefix
.ead_addr
.esi
, buf
,
3824 vpn
->vni
, &p
->prefix
.ead_addr
.ip
.ipaddr_v4
);
3827 es_evi
= bgp_evpn_es_evi_find(es
, vpn
);
3829 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3831 "del remote %s es %s evi %u vtep %pI4, NO es-evi",
3832 p
->prefix
.ead_addr
.eth_tag
? "ead-es"
3834 esi_to_str(&p
->prefix
.ead_addr
.esi
, buf
,
3837 &p
->prefix
.ead_addr
.ip
.ipaddr_v4
);
3841 ead_es
= !!p
->prefix
.ead_addr
.eth_tag
;
3842 bgp_evpn_es_evi_vtep_del(bgp
, es_evi
, p
->prefix
.ead_addr
.ip
.ipaddr_v4
,
3844 bgp_evpn_es_evi_remote_info_re_eval(es_evi
);
3848 /* If a VNI is being deleted we need to force del all remote VTEPs */
3849 static void bgp_evpn_remote_es_evi_flush(struct bgp_evpn_es_evi
*es_evi
)
3851 struct listnode
*node
= NULL
;
3852 struct listnode
*nnode
= NULL
;
3853 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
3856 bgp
= bgp_get_evpn();
3860 /* delete all VTEPs */
3861 for (ALL_LIST_ELEMENTS(es_evi
->es_evi_vtep_list
, node
, nnode
,
3863 evi_vtep
->flags
&= ~(BGP_EVPN_EVI_VTEP_EAD_PER_ES
3864 | BGP_EVPN_EVI_VTEP_EAD_PER_EVI
);
3865 bgp_evpn_es_evi_vtep_re_eval_active(bgp
, evi_vtep
);
3866 bgp_evpn_es_evi_vtep_free(evi_vtep
);
3868 /* delete the EVI */
3869 bgp_evpn_es_evi_remote_info_re_eval(es_evi
);
3872 /* Initialize the ES tables maintained per-L2_VNI */
3873 void bgp_evpn_vni_es_init(struct bgpevpn
*vpn
)
3875 /* Initialize the ES-EVI RB tree */
3876 RB_INIT(bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
);
3878 /* Initialize the local list maintained for quick walks by type */
3879 vpn
->local_es_evi_list
= list_new();
3880 listset_app_node_mem(vpn
->local_es_evi_list
);
3883 /* Cleanup the ES info maintained per-L2_VNI */
3884 void bgp_evpn_vni_es_cleanup(struct bgpevpn
*vpn
)
3886 struct bgp_evpn_es_evi
*es_evi
;
3887 struct bgp_evpn_es_evi
*es_evi_next
;
3889 RB_FOREACH_SAFE(es_evi
, bgp_es_evi_rb_head
,
3890 &vpn
->es_evi_rb_tree
, es_evi_next
) {
3891 es_evi
= bgp_evpn_local_es_evi_do_del(es_evi
);
3893 bgp_evpn_remote_es_evi_flush(es_evi
);
3896 list_delete(&vpn
->local_es_evi_list
);
3899 static char *bgp_evpn_es_evi_vteps_str(char *vtep_str
,
3900 struct bgp_evpn_es_evi
*es_evi
,
3901 uint8_t vtep_str_size
)
3903 char vtep_flag_str
[BGP_EVPN_FLAG_STR_SZ
];
3904 struct listnode
*node
;
3905 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
3907 char ip_buf
[INET_ADDRSTRLEN
];
3910 for (ALL_LIST_ELEMENTS_RO(es_evi
->es_evi_vtep_list
, node
, evi_vtep
)) {
3911 vtep_flag_str
[0] = '\0';
3912 if (evi_vtep
->flags
& BGP_EVPN_EVI_VTEP_EAD_PER_ES
)
3913 strlcat(vtep_flag_str
, "E", sizeof(vtep_flag_str
));
3914 if (evi_vtep
->flags
& BGP_EVPN_EVI_VTEP_EAD_PER_EVI
)
3915 strlcat(vtep_flag_str
, "V", sizeof(vtep_flag_str
));
3917 if (!strnlen(vtep_flag_str
, sizeof(vtep_flag_str
)))
3918 strlcpy(vtep_flag_str
, "-", sizeof(vtep_flag_str
));
3922 strlcat(vtep_str
, ",", vtep_str_size
);
3924 inet_ntop(AF_INET
, &evi_vtep
->vtep_ip
, ip_buf
,
3927 strlcat(vtep_str
, "(", vtep_str_size
);
3928 strlcat(vtep_str
, vtep_flag_str
, vtep_str_size
);
3929 strlcat(vtep_str
, ")", vtep_str_size
);
3935 static void bgp_evpn_es_evi_json_vtep_fill(json_object
*json_vteps
,
3936 struct bgp_evpn_es_evi_vtep
*evi_vtep
)
3938 json_object
*json_vtep_entry
;
3939 json_object
*json_flags
;
3941 json_vtep_entry
= json_object_new_object();
3943 json_object_string_addf(json_vtep_entry
, "vtep_ip", "%pI4",
3944 &evi_vtep
->vtep_ip
);
3945 if (evi_vtep
->flags
& (BGP_EVPN_EVI_VTEP_EAD_PER_ES
|
3946 BGP_EVPN_EVI_VTEP_EAD_PER_EVI
)) {
3947 json_flags
= json_object_new_array();
3948 if (evi_vtep
->flags
& BGP_EVPN_EVI_VTEP_EAD_PER_ES
)
3949 json_array_string_add(json_flags
, "ead-per-es");
3950 if (evi_vtep
->flags
& BGP_EVPN_EVI_VTEP_EAD_PER_EVI
)
3951 json_array_string_add(json_flags
, "ead-per-evi");
3952 json_object_object_add(json_vtep_entry
,
3953 "flags", json_flags
);
3956 json_object_array_add(json_vteps
,
3960 static void bgp_evpn_es_evi_show_entry(struct vty
*vty
,
3961 struct bgp_evpn_es_evi
*es_evi
, json_object
*json
)
3963 struct listnode
*node
;
3964 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
3967 json_object
*json_vteps
;
3968 json_object
*json_types
;
3970 json_object_string_add(json
, "esi", es_evi
->es
->esi_str
);
3972 json_object_int_add(json
, "vni", es_evi
->vpn
->vni
);
3974 if (es_evi
->flags
& (BGP_EVPNES_EVI_LOCAL
|
3975 BGP_EVPNES_EVI_REMOTE
)) {
3976 json_types
= json_object_new_array();
3977 if (es_evi
->flags
& BGP_EVPNES_EVI_LOCAL
)
3978 json_array_string_add(json_types
, "local");
3979 if (es_evi
->flags
& BGP_EVPNES_EVI_REMOTE
)
3980 json_array_string_add(json_types
, "remote");
3981 json_object_object_add(json
, "type", json_types
);
3984 if (listcount(es_evi
->es_evi_vtep_list
)) {
3985 json_vteps
= json_object_new_array();
3986 for (ALL_LIST_ELEMENTS_RO(es_evi
->es_evi_vtep_list
,
3988 bgp_evpn_es_evi_json_vtep_fill(json_vteps
,
3991 json_object_object_add(json
, "vteps", json_vteps
);
3995 char vtep_str
[ES_VTEP_LIST_STR_SZ
+ BGP_EVPN_VTEPS_FLAG_STR_SZ
];
3998 if (es_evi
->flags
& BGP_EVPNES_EVI_LOCAL
)
3999 strlcat(type_str
, "L", sizeof(type_str
));
4000 if (es_evi
->flags
& BGP_EVPNES_EVI_REMOTE
)
4001 strlcat(type_str
, "R", sizeof(type_str
));
4002 if (es_evi
->flags
& BGP_EVPNES_EVI_INCONS_VTEP_LIST
)
4003 strlcat(type_str
, "I", sizeof(type_str
));
4005 bgp_evpn_es_evi_vteps_str(vtep_str
, es_evi
, sizeof(vtep_str
));
4007 vty_out(vty
, "%-8d %-30s %-5s %s\n",
4008 es_evi
->vpn
->vni
, es_evi
->es
->esi_str
,
4009 type_str
, vtep_str
);
4013 static void bgp_evpn_es_evi_show_entry_detail(struct vty
*vty
,
4014 struct bgp_evpn_es_evi
*es_evi
, json_object
*json
)
4016 enum asnotation_mode mode
;
4018 mode
= bgp_get_asnotation(es_evi
->vpn
->bgp_vrf
);
4021 json_object
*json_flags
;
4023 /* Add the "brief" info first */
4024 bgp_evpn_es_evi_show_entry(vty
, es_evi
, json
);
4025 if (es_evi
->es_frag
)
4026 json_object_string_addf(json
, "esFragmentRd",
4027 BGP_RD_AS_FORMAT(mode
),
4028 &es_evi
->es_frag
->prd
);
4029 if (es_evi
->flags
& BGP_EVPNES_EVI_INCONS_VTEP_LIST
) {
4030 json_flags
= json_object_new_array();
4031 json_array_string_add(json_flags
, "es-vtep-mismatch");
4032 json_object_object_add(json
, "flags", json_flags
);
4035 char vtep_str
[ES_VTEP_LIST_STR_SZ
+ BGP_EVPN_VTEPS_FLAG_STR_SZ
];
4039 if (es_evi
->flags
& BGP_EVPNES_EVI_LOCAL
)
4040 strlcat(type_str
, "L", sizeof(type_str
));
4041 if (es_evi
->flags
& BGP_EVPNES_EVI_REMOTE
)
4042 strlcat(type_str
, "R", sizeof(type_str
));
4044 bgp_evpn_es_evi_vteps_str(vtep_str
, es_evi
, sizeof(vtep_str
));
4045 if (!strlen(vtep_str
))
4046 strlcpy(vtep_str
, "-", sizeof(type_str
));
4048 vty_out(vty
, "VNI: %d ESI: %s\n",
4049 es_evi
->vpn
->vni
, es_evi
->es
->esi_str
);
4050 vty_out(vty
, " Type: %s\n", type_str
);
4051 if (es_evi
->es_frag
) {
4052 vty_out(vty
, " ES fragment RD: ");
4053 vty_out(vty
, BGP_RD_AS_FORMAT(mode
),
4054 &es_evi
->es_frag
->prd
);
4057 vty_out(vty
, " Inconsistencies: %s\n",
4058 (es_evi
->flags
& BGP_EVPNES_EVI_INCONS_VTEP_LIST
) ?
4059 "es-vtep-mismatch":"-");
4060 vty_out(vty
, " VTEPs: %s\n", vtep_str
);
4065 static void bgp_evpn_es_evi_show_one_vni(struct bgpevpn
*vpn
, struct vty
*vty
,
4066 json_object
*json_array
, bool detail
)
4068 struct bgp_evpn_es_evi
*es_evi
;
4069 json_object
*json
= NULL
;
4071 RB_FOREACH(es_evi
, bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
) {
4073 /* create a separate json object for each ES */
4074 json
= json_object_new_object();
4076 bgp_evpn_es_evi_show_entry_detail(vty
, es_evi
, json
);
4078 bgp_evpn_es_evi_show_entry(vty
, es_evi
, json
);
4079 /* add ES to the json array */
4081 json_object_array_add(json_array
, json
);
4085 struct es_evi_show_ctx
{
4091 static void bgp_evpn_es_evi_show_one_vni_hash_cb(struct hash_bucket
*bucket
,
4094 struct bgpevpn
*vpn
= (struct bgpevpn
*)bucket
->data
;
4095 struct es_evi_show_ctx
*wctx
= (struct es_evi_show_ctx
*)ctxt
;
4097 bgp_evpn_es_evi_show_one_vni(vpn
, wctx
->vty
, wctx
->json
, wctx
->detail
);
4100 /* Display all ES EVIs */
4101 void bgp_evpn_es_evi_show(struct vty
*vty
, bool uj
, bool detail
)
4103 json_object
*json_array
= NULL
;
4104 struct es_evi_show_ctx wctx
;
4108 /* create an array of ES-EVIs */
4109 json_array
= json_object_new_array();
4113 wctx
.json
= json_array
;
4114 wctx
.detail
= detail
;
4116 bgp
= bgp_get_evpn();
4118 if (!json_array
&& !detail
) {
4119 vty_out(vty
, "Flags: L local, R remote, I inconsistent\n");
4120 vty_out(vty
, "VTEP-Flags: E EAD-per-ES, V EAD-per-EVI\n");
4121 vty_out(vty
, "%-8s %-30s %-5s %s\n",
4122 "VNI", "ESI", "Flags", "VTEPs");
4126 hash_iterate(bgp
->vnihash
,
4127 (void (*)(struct hash_bucket
*,
4128 void *))bgp_evpn_es_evi_show_one_vni_hash_cb
,
4131 vty_json(vty
, json_array
);
4134 /* Display specific ES EVI */
4135 void bgp_evpn_es_evi_show_vni(struct vty
*vty
, vni_t vni
,
4136 bool uj
, bool detail
)
4138 struct bgpevpn
*vpn
= NULL
;
4139 json_object
*json_array
= NULL
;
4143 /* create an array of ES-EVIs */
4144 json_array
= json_object_new_array();
4147 bgp
= bgp_get_evpn();
4149 vpn
= bgp_evpn_lookup_vni(bgp
, vni
);
4152 if (!json_array
&& !detail
) {
4153 vty_out(vty
, "Flags: L local, R remote, I inconsistent\n");
4154 vty_out(vty
, "VTEP-Flags: E EAD-per-ES, V EAD-per-EVI\n");
4155 vty_out(vty
, "%-8s %-30s %-5s %s\n",
4156 "VNI", "ESI", "Flags", "VTEPs");
4159 bgp_evpn_es_evi_show_one_vni(vpn
, vty
, json_array
, detail
);
4162 vty_out(vty
, "VNI not found\n");
4166 vty_json(vty
, json_array
);
4169 /*****************************************************************************
4170 * Ethernet Segment Consistency checks
4171 * Consistency checking is done to detect misconfig or mis-cabling. When
4172 * an inconsistency is detected it is simply logged (and displayed via
4173 * show commands) at this point. A more drastic action can be executed (based
4174 * on user config) in the future.
4176 static void bgp_evpn_es_cons_checks_timer_start(void)
4178 if (!bgp_mh_info
->consistency_checking
|| bgp_mh_info
->t_cons_check
)
4181 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
4182 zlog_debug("periodic consistency checking started");
4184 event_add_timer(bm
->master
, bgp_evpn_run_consistency_checks
, NULL
,
4185 BGP_EVPN_CONS_CHECK_INTERVAL
,
4186 &bgp_mh_info
->t_cons_check
);
4189 /* queue up the es for background consistency checks */
4190 static void bgp_evpn_es_cons_checks_pend_add(struct bgp_evpn_es
*es
)
4192 if (!bgp_mh_info
->consistency_checking
)
4193 /* consistency checking is not enabled */
4196 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_CONS_CHECK_PEND
))
4197 /* already queued for consistency checking */
4200 /* start the periodic timer for consistency checks if it is not
4201 * already running */
4202 bgp_evpn_es_cons_checks_timer_start();
4204 SET_FLAG(es
->flags
, BGP_EVPNES_CONS_CHECK_PEND
);
4205 listnode_init(&es
->pend_es_listnode
, es
);
4206 listnode_add_after(bgp_mh_info
->pend_es_list
,
4207 listtail_unchecked(bgp_mh_info
->pend_es_list
),
4208 &es
->pend_es_listnode
);
4211 /* pull the ES from the consistency check list */
4212 static void bgp_evpn_es_cons_checks_pend_del(struct bgp_evpn_es
*es
)
4214 if (!CHECK_FLAG(es
->flags
, BGP_EVPNES_CONS_CHECK_PEND
))
4217 UNSET_FLAG(es
->flags
, BGP_EVPNES_CONS_CHECK_PEND
);
4218 list_delete_node(bgp_mh_info
->pend_es_list
,
4219 &es
->pend_es_listnode
);
4222 /* Number of active VTEPs associated with the ES-per-EVI */
4223 static uint32_t bgp_evpn_es_evi_get_active_vtep_cnt(
4224 struct bgp_evpn_es_evi
*es_evi
)
4226 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
4227 struct listnode
*node
;
4228 uint32_t vtep_cnt
= 0;
4230 for (ALL_LIST_ELEMENTS_RO(es_evi
->es_evi_vtep_list
, node
, evi_vtep
)) {
4231 if (CHECK_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
))
4238 /* Number of active VTEPs associated with the ES */
4239 static uint32_t bgp_evpn_es_get_active_vtep_cnt(struct bgp_evpn_es
*es
)
4241 struct listnode
*node
;
4242 uint32_t vtep_cnt
= 0;
4243 struct bgp_evpn_es_vtep
*es_vtep
;
4245 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
4246 if (CHECK_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
))
4253 static struct bgp_evpn_es_vtep
*bgp_evpn_es_get_next_active_vtep(
4254 struct bgp_evpn_es
*es
, struct bgp_evpn_es_vtep
*es_vtep
)
4256 struct listnode
*node
;
4257 struct bgp_evpn_es_vtep
*next_es_vtep
;
4260 node
= listnextnode_unchecked(&es_vtep
->es_listnode
);
4262 node
= listhead(es
->es_vtep_list
);
4264 for (; node
; node
= listnextnode_unchecked(node
)) {
4265 next_es_vtep
= listgetdata(node
);
4266 if (CHECK_FLAG(next_es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
))
4267 return next_es_vtep
;
4273 static struct bgp_evpn_es_evi_vtep
*bgp_evpn_es_evi_get_next_active_vtep(
4274 struct bgp_evpn_es_evi
*es_evi
,
4275 struct bgp_evpn_es_evi_vtep
*evi_vtep
)
4277 struct listnode
*node
;
4278 struct bgp_evpn_es_evi_vtep
*next_evi_vtep
;
4281 node
= listnextnode_unchecked(&evi_vtep
->es_evi_listnode
);
4283 node
= listhead(es_evi
->es_evi_vtep_list
);
4285 for (; node
; node
= listnextnode_unchecked(node
)) {
4286 next_evi_vtep
= listgetdata(node
);
4287 if (CHECK_FLAG(next_evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
))
4288 return next_evi_vtep
;
4294 static void bgp_evpn_es_evi_set_inconsistent(struct bgp_evpn_es_evi
*es_evi
)
4296 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_INCONS_VTEP_LIST
)) {
4297 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
4298 zlog_debug("inconsistency detected - es %s evi %u vtep list mismatch",
4299 es_evi
->es
->esi_str
,
4301 SET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_INCONS_VTEP_LIST
);
4303 /* update parent ES with the incosistency setting */
4304 if (!es_evi
->es
->incons_evi_vtep_cnt
&&
4305 BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
4306 zlog_debug("inconsistency detected - es %s vtep list mismatch",
4307 es_evi
->es
->esi_str
);
4308 ++es_evi
->es
->incons_evi_vtep_cnt
;
4309 SET_FLAG(es_evi
->es
->inconsistencies
,
4310 BGP_EVPNES_INCONS_VTEP_LIST
);
4314 static uint32_t bgp_evpn_es_run_consistency_checks(struct bgp_evpn_es
*es
)
4317 int es_active_vtep_cnt
;
4318 int evi_active_vtep_cnt
;
4319 struct bgp_evpn_es_evi
*es_evi
;
4320 struct listnode
*evi_node
;
4321 struct bgp_evpn_es_vtep
*es_vtep
;
4322 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
4324 /* reset the inconsistencies and re-evaluate */
4325 es
->incons_evi_vtep_cnt
= 0;
4326 es
->inconsistencies
= 0;
4328 es_active_vtep_cnt
= bgp_evpn_es_get_active_vtep_cnt(es
);
4329 for (ALL_LIST_ELEMENTS_RO(es
->es_evi_list
,
4330 evi_node
, es_evi
)) {
4333 /* reset the inconsistencies on the EVI and re-evaluate*/
4334 UNSET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_INCONS_VTEP_LIST
);
4336 evi_active_vtep_cnt
=
4337 bgp_evpn_es_evi_get_active_vtep_cnt(es_evi
);
4338 if (es_active_vtep_cnt
!= evi_active_vtep_cnt
) {
4339 bgp_evpn_es_evi_set_inconsistent(es_evi
);
4343 if (!es_active_vtep_cnt
)
4348 while ((es_vtep
= bgp_evpn_es_get_next_active_vtep(
4350 evi_vtep
= bgp_evpn_es_evi_get_next_active_vtep(es_evi
,
4353 bgp_evpn_es_evi_set_inconsistent(es_evi
);
4356 if (es_vtep
->vtep_ip
.s_addr
!=
4357 evi_vtep
->vtep_ip
.s_addr
) {
4358 /* inconsistency detected; set it and move
4361 bgp_evpn_es_evi_set_inconsistent(es_evi
);
4370 static void bgp_evpn_run_consistency_checks(struct event
*t
)
4373 struct listnode
*node
;
4374 struct listnode
*nextnode
;
4375 struct bgp_evpn_es
*es
;
4377 for (ALL_LIST_ELEMENTS(bgp_mh_info
->pend_es_list
,
4378 node
, nextnode
, es
)) {
4380 /* run consistency checks on the ES and remove it from the
4383 proc_cnt
+= bgp_evpn_es_run_consistency_checks(es
);
4384 bgp_evpn_es_cons_checks_pend_del(es
);
4389 /* restart the timer */
4390 event_add_timer(bm
->master
, bgp_evpn_run_consistency_checks
, NULL
,
4391 BGP_EVPN_CONS_CHECK_INTERVAL
,
4392 &bgp_mh_info
->t_cons_check
);
4395 /*****************************************************************************
4396 * EVPN-Nexthop and RMAC management: nexthops associated with Type-2 routes
4397 * that have an ES as destination are consolidated by BGP into a per-VRF
4398 * nh->rmac mapping which is sent to zebra. Zebra installs the nexthop
4399 * as a remote neigh/fdb entry with a dummy (type-1) prefix referencing it.
4401 * This handling is needed because Type-2 routes with ES as dest use NHG
4402 * that is setup using EAD routes (i.e. such NHGs do not include the
4404 ****************************************************************************/
4405 static void bgp_evpn_nh_zebra_update_send(struct bgp_evpn_nh
*nh
, bool add
)
4408 struct bgp
*bgp_vrf
= nh
->bgp_vrf
;
4411 if (!zclient
|| zclient
->sock
< 0)
4414 /* Don't try to register if Zebra doesn't know of this instance. */
4415 if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp_vrf
)) {
4416 if (BGP_DEBUG(zebra
, ZEBRA
))
4417 zlog_debug("No zebra instance, not %s remote nh %s",
4418 add
? "adding" : "deleting", nh
->nh_str
);
4425 zclient_create_header(
4426 s
, add
? ZEBRA_EVPN_REMOTE_NH_ADD
: ZEBRA_EVPN_REMOTE_NH_DEL
,
4428 stream_putl(s
, bgp_vrf
->vrf_id
);
4429 stream_put(s
, &nh
->ip
, sizeof(nh
->ip
));
4431 stream_put(s
, &nh
->rmac
, sizeof(nh
->rmac
));
4433 stream_putw_at(s
, 0, stream_get_endp(s
));
4435 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
)) {
4437 zlog_debug("evpn vrf %s nh %s rmac %pEA add to zebra",
4438 nh
->bgp_vrf
->name_pretty
, nh
->nh_str
,
4440 else if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
4441 zlog_debug("evpn vrf %s nh %s del to zebra",
4442 nh
->bgp_vrf
->name_pretty
, nh
->nh_str
);
4445 frrtrace(2, frr_bgp
, evpn_mh_nh_rmac_zsend
, add
, nh
);
4447 zclient_send_message(zclient
);
4450 static void bgp_evpn_nh_zebra_update(struct bgp_evpn_nh
*nh
, bool add
)
4452 if (add
&& !is_zero_mac(&nh
->rmac
)) {
4453 nh
->flags
|= BGP_EVPN_NH_READY_FOR_ZEBRA
;
4454 bgp_evpn_nh_zebra_update_send(nh
, true);
4456 if (!(nh
->flags
& BGP_EVPN_NH_READY_FOR_ZEBRA
))
4458 nh
->flags
&= ~BGP_EVPN_NH_READY_FOR_ZEBRA
;
4459 bgp_evpn_nh_zebra_update_send(nh
, false);
4463 static void *bgp_evpn_nh_alloc(void *p
)
4465 struct bgp_evpn_nh
*tmp_n
= p
;
4466 struct bgp_evpn_nh
*n
;
4468 n
= XCALLOC(MTYPE_BGP_EVPN_NH
, sizeof(struct bgp_evpn_nh
));
4474 static struct bgp_evpn_nh
*bgp_evpn_nh_find(struct bgp
*bgp_vrf
,
4477 struct bgp_evpn_nh tmp
;
4478 struct bgp_evpn_nh
*n
;
4480 memset(&tmp
, 0, sizeof(tmp
));
4481 memcpy(&tmp
.ip
, ip
, sizeof(struct ipaddr
));
4482 n
= hash_lookup(bgp_vrf
->evpn_nh_table
, &tmp
);
4487 /* Add nexthop entry - implicitly created on first path reference */
4488 static struct bgp_evpn_nh
*bgp_evpn_nh_add(struct bgp
*bgp_vrf
,
4490 struct bgp_path_info
*pi
)
4492 struct bgp_evpn_nh tmp_n
;
4493 struct bgp_evpn_nh
*n
= NULL
;
4495 memset(&tmp_n
, 0, sizeof(tmp_n
));
4496 memcpy(&tmp_n
.ip
, ip
, sizeof(struct ipaddr
));
4497 n
= hash_get(bgp_vrf
->evpn_nh_table
, &tmp_n
, bgp_evpn_nh_alloc
);
4498 ipaddr2str(ip
, n
->nh_str
, sizeof(n
->nh_str
));
4499 n
->bgp_vrf
= bgp_vrf
;
4501 n
->pi_list
= list_new();
4502 listset_app_node_mem(n
->pi_list
);
4504 /* Setup ref_pi when the nh is created */
4505 if (CHECK_FLAG(pi
->flags
, BGP_PATH_VALID
) && pi
->attr
) {
4507 memcpy(&n
->rmac
, &pi
->attr
->rmac
, ETH_ALEN
);
4510 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
4511 zlog_debug("evpn vrf %s nh %s rmac %pEA add",
4512 n
->bgp_vrf
->name_pretty
, n
->nh_str
, &n
->rmac
);
4513 bgp_evpn_nh_zebra_update(n
, true);
4517 /* Delete nexthop entry if there are no paths referencing it */
4518 static void bgp_evpn_nh_del(struct bgp_evpn_nh
*n
)
4520 struct bgp_evpn_nh
*tmp_n
;
4521 struct bgp
*bgp_vrf
= n
->bgp_vrf
;
4523 if (listcount(n
->pi_list
))
4526 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
4527 zlog_debug("evpn vrf %s nh %s del to zebra",
4528 bgp_vrf
->name_pretty
, n
->nh_str
);
4530 bgp_evpn_nh_zebra_update(n
, false);
4531 list_delete(&n
->pi_list
);
4532 tmp_n
= hash_release(bgp_vrf
->evpn_nh_table
, n
);
4533 XFREE(MTYPE_BGP_EVPN_NH
, tmp_n
);
4536 static void hash_evpn_nh_free(struct bgp_evpn_nh
*ben
)
4538 XFREE(MTYPE_BGP_EVPN_NH
, ben
);
4541 static unsigned int bgp_evpn_nh_hash_keymake(const void *p
)
4543 const struct bgp_evpn_nh
*n
= p
;
4544 const struct ipaddr
*ip
= &n
->ip
;
4546 if (IS_IPADDR_V4(ip
))
4547 return jhash_1word(ip
->ipaddr_v4
.s_addr
, 0);
4549 return jhash2(ip
->ipaddr_v6
.s6_addr32
,
4550 array_size(ip
->ipaddr_v6
.s6_addr32
), 0);
4553 static bool bgp_evpn_nh_cmp(const void *p1
, const void *p2
)
4555 const struct bgp_evpn_nh
*n1
= p1
;
4556 const struct bgp_evpn_nh
*n2
= p2
;
4558 if (n1
== NULL
&& n2
== NULL
)
4561 if (n1
== NULL
|| n2
== NULL
)
4564 return (ipaddr_cmp(&n1
->ip
, &n2
->ip
) == 0);
4567 void bgp_evpn_nh_init(struct bgp
*bgp_vrf
)
4569 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
4570 zlog_debug("evpn vrf %s nh init", bgp_vrf
->name_pretty
);
4571 bgp_vrf
->evpn_nh_table
= hash_create(
4572 bgp_evpn_nh_hash_keymake
, bgp_evpn_nh_cmp
, "BGP EVPN NH table");
4575 static void bgp_evpn_nh_flush_entry(struct bgp_evpn_nh
*nh
)
4577 struct listnode
*node
;
4578 struct listnode
*nnode
;
4579 struct bgp_path_evpn_nh_info
*nh_info
;
4581 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
4582 zlog_debug("evpn vrf %s nh %s flush", nh
->bgp_vrf
->name_pretty
,
4585 /* force flush paths */
4586 for (ALL_LIST_ELEMENTS(nh
->pi_list
, node
, nnode
, nh_info
))
4587 bgp_evpn_path_nh_del(nh
->bgp_vrf
, nh_info
->pi
);
4590 static void bgp_evpn_nh_flush_cb(struct hash_bucket
*bucket
, void *ctxt
)
4592 struct bgp_evpn_nh
*nh
= (struct bgp_evpn_nh
*)bucket
->data
;
4594 bgp_evpn_nh_flush_entry(nh
);
4597 void bgp_evpn_nh_finish(struct bgp
*bgp_vrf
)
4599 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
4600 zlog_debug("evpn vrf %s nh finish", bgp_vrf
->name_pretty
);
4602 bgp_vrf
->evpn_nh_table
,
4603 (void (*)(struct hash_bucket
*, void *))bgp_evpn_nh_flush_cb
,
4605 hash_clean_and_free(&bgp_vrf
->evpn_nh_table
,
4606 (void (*)(void *))hash_evpn_nh_free
);
4609 static void bgp_evpn_nh_update_ref_pi(struct bgp_evpn_nh
*nh
)
4611 struct listnode
*node
;
4612 struct bgp_path_info
*pi
;
4613 struct bgp_path_evpn_nh_info
*nh_info
;
4618 for (ALL_LIST_ELEMENTS_RO(nh
->pi_list
, node
, nh_info
)) {
4620 if (!CHECK_FLAG(pi
->flags
, BGP_PATH_VALID
) || !pi
->attr
)
4623 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
4624 zlog_debug("evpn vrf %s nh %s ref_pi update",
4625 nh
->bgp_vrf
->name_pretty
, nh
->nh_str
);
4627 /* If we have a new pi copy rmac from it and update
4628 * zebra if the new rmac is different
4630 if (memcmp(&nh
->rmac
, &nh
->ref_pi
->attr
->rmac
, ETH_ALEN
)) {
4631 memcpy(&nh
->rmac
, &nh
->ref_pi
->attr
->rmac
, ETH_ALEN
);
4632 bgp_evpn_nh_zebra_update(nh
, true);
4638 static void bgp_evpn_nh_clear_ref_pi(struct bgp_evpn_nh
*nh
,
4639 struct bgp_path_info
*pi
)
4641 if (nh
->ref_pi
!= pi
)
4644 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
4645 zlog_debug("evpn vrf %s nh %s ref_pi clear",
4646 nh
->bgp_vrf
->name_pretty
, nh
->nh_str
);
4648 /* try to find another ref_pi */
4649 bgp_evpn_nh_update_ref_pi(nh
);
4650 /* couldn't find one - clear the old rmac and notify zebra */
4652 memset(&nh
->rmac
, 0, ETH_ALEN
);
4653 bgp_evpn_nh_zebra_update(nh
, true);
4657 static void bgp_evpn_path_nh_info_free(struct bgp_path_evpn_nh_info
*nh_info
)
4659 bgp_evpn_path_nh_unlink(nh_info
);
4660 XFREE(MTYPE_BGP_EVPN_PATH_NH_INFO
, nh_info
);
4663 static struct bgp_path_evpn_nh_info
*
4664 bgp_evpn_path_nh_info_new(struct bgp_path_info
*pi
)
4666 struct bgp_path_info_extra
*e
;
4667 struct bgp_path_mh_info
*mh_info
;
4668 struct bgp_path_evpn_nh_info
*nh_info
;
4670 e
= bgp_path_info_extra_get(pi
);
4672 /* If mh_info doesn't exist allocate it */
4673 mh_info
= e
->mh_info
;
4675 e
->mh_info
= mh_info
= XCALLOC(MTYPE_BGP_EVPN_PATH_MH_INFO
,
4676 sizeof(struct bgp_path_mh_info
));
4678 /* If nh_info doesn't exist allocate it */
4679 nh_info
= mh_info
->nh_info
;
4681 mh_info
->nh_info
= nh_info
=
4682 XCALLOC(MTYPE_BGP_EVPN_PATH_NH_INFO
,
4683 sizeof(struct bgp_path_evpn_nh_info
));
4690 static void bgp_evpn_path_nh_unlink(struct bgp_path_evpn_nh_info
*nh_info
)
4692 struct bgp_evpn_nh
*nh
= nh_info
->nh
;
4693 struct bgp_path_info
*pi
;
4694 char prefix_buf
[PREFIX_STRLEN
];
4700 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
4701 zlog_debug("path %s unlinked from nh %s %s",
4702 pi
->net
? prefix2str(&pi
->net
->p
, prefix_buf
,
4705 nh
->bgp_vrf
->name_pretty
, nh
->nh_str
);
4707 list_delete_node(nh
->pi_list
, &nh_info
->nh_listnode
);
4711 /* check if the ref_pi need to be updated */
4712 bgp_evpn_nh_clear_ref_pi(nh
, pi
);
4714 /* if there are no other references against the nh it
4717 bgp_evpn_nh_del(nh
);
4719 /* Note we don't free the path nh_info on unlink; it will be freed up
4720 * along with the path.
4724 static void bgp_evpn_path_nh_link(struct bgp
*bgp_vrf
, struct bgp_path_info
*pi
)
4726 struct bgp_path_evpn_nh_info
*nh_info
;
4727 struct bgp_evpn_nh
*nh
;
4730 /* EVPN nexthop setup in bgp has been turned off */
4731 if (!bgp_mh_info
->bgp_evpn_nh_setup
)
4734 if (!bgp_vrf
->evpn_nh_table
) {
4735 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
4736 zlog_debug("path %pFX linked to vrf %s failed",
4737 &pi
->net
->p
, bgp_vrf
->name_pretty
);
4741 nh_info
= (pi
->extra
&& pi
->extra
->mh_info
)
4742 ? pi
->extra
->mh_info
->nh_info
4745 /* if NHG is not being used for this path we don't need to manage the
4746 * nexthops in bgp (they are managed by zebra instead)
4748 if (!(pi
->attr
->es_flags
& ATTR_ES_L3_NHG_USE
)) {
4750 bgp_evpn_path_nh_unlink(nh_info
);
4754 /* setup nh_info against the path if it doesn't aleady exist */
4756 nh_info
= bgp_evpn_path_nh_info_new(pi
);
4758 /* find-create nh */
4759 memset(&ip
, 0, sizeof(ip
));
4760 if (pi
->net
->p
.family
== AF_INET6
) {
4762 memcpy(&ip
.ipaddr_v6
, &pi
->attr
->mp_nexthop_global
,
4763 sizeof(ip
.ipaddr_v6
));
4766 memcpy(&ip
.ipaddr_v4
, &pi
->attr
->nexthop
, sizeof(ip
.ipaddr_v4
));
4769 nh
= bgp_evpn_nh_find(bgp_vrf
, &ip
);
4771 nh
= bgp_evpn_nh_add(bgp_vrf
, &ip
, pi
);
4774 if (nh_info
->nh
== nh
) {
4775 /* Check if any of the paths are now valid */
4776 bgp_evpn_nh_update_ref_pi(nh
);
4780 /* unlink old nh if any */
4781 bgp_evpn_path_nh_unlink(nh_info
);
4783 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
4784 zlog_debug("path %pFX linked to nh %s %s", &pi
->net
->p
,
4785 nh
->bgp_vrf
->name_pretty
, nh
->nh_str
);
4787 /* link mac-ip path to the new nh */
4789 listnode_init(&nh_info
->nh_listnode
, nh_info
);
4790 listnode_add(nh
->pi_list
, &nh_info
->nh_listnode
);
4791 /* If a new valid path got linked to the nh see if can get the rmac
4794 bgp_evpn_nh_update_ref_pi(nh
);
4795 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
)) {
4798 "path %pFX linked to nh %s %s with no valid pi",
4799 &pi
->net
->p
, nh
->bgp_vrf
->name_pretty
,
4804 void bgp_evpn_path_nh_del(struct bgp
*bgp_vrf
, struct bgp_path_info
*pi
)
4806 struct bgp_path_evpn_nh_info
*nh_info
;
4808 nh_info
= (pi
->extra
&& pi
->extra
->mh_info
)
4809 ? pi
->extra
->mh_info
->nh_info
4815 bgp_evpn_path_nh_unlink(nh_info
);
4818 void bgp_evpn_path_nh_add(struct bgp
*bgp_vrf
, struct bgp_path_info
*pi
)
4820 bgp_evpn_path_nh_link(bgp_vrf
, pi
);
4823 static void bgp_evpn_nh_show_entry(struct bgp_evpn_nh
*nh
, struct vty
*vty
,
4824 json_object
*json_array
)
4826 json_object
*json
= NULL
;
4827 char mac_buf
[ETHER_ADDR_STRLEN
];
4828 char prefix_buf
[PREFIX_STRLEN
];
4831 /* create a separate json object for each ES */
4832 json
= json_object_new_object();
4834 prefix_mac2str(&nh
->rmac
, mac_buf
, sizeof(mac_buf
));
4835 if (nh
->ref_pi
&& nh
->ref_pi
->net
)
4836 prefix2str(&nh
->ref_pi
->net
->p
, prefix_buf
, sizeof(prefix_buf
));
4838 prefix_buf
[0] = '\0';
4840 json_object_string_add(json
, "vrf", nh
->bgp_vrf
->name_pretty
);
4841 json_object_string_add(json
, "ip", nh
->nh_str
);
4842 json_object_string_add(json
, "rmac", mac_buf
);
4843 json_object_string_add(json
, "basePath", prefix_buf
);
4844 json_object_int_add(json
, "pathCount", listcount(nh
->pi_list
));
4846 vty_out(vty
, "%-15s %-15s %-17s %-10d %s\n",
4847 nh
->bgp_vrf
->name_pretty
, nh
->nh_str
, mac_buf
,
4848 listcount(nh
->pi_list
), prefix_buf
);
4851 /* add ES to the json array */
4853 json_object_array_add(json_array
, json
);
4856 struct nh_show_ctx
{
4861 static void bgp_evpn_nh_show_hash_cb(struct hash_bucket
*bucket
, void *ctxt
)
4863 struct bgp_evpn_nh
*nh
= (struct bgp_evpn_nh
*)bucket
->data
;
4864 struct nh_show_ctx
*wctx
= (struct nh_show_ctx
*)ctxt
;
4866 bgp_evpn_nh_show_entry(nh
, wctx
->vty
, wctx
->json
);
4869 /* Display all evpn nexthops */
4870 void bgp_evpn_nh_show(struct vty
*vty
, bool uj
)
4872 json_object
*json_array
= NULL
;
4873 struct bgp
*bgp_vrf
;
4874 struct listnode
*node
;
4875 struct nh_show_ctx wctx
;
4878 /* create an array of nexthops */
4879 json_array
= json_object_new_array();
4881 vty_out(vty
, "%-15s %-15s %-17s %-10s %s\n", "VRF", "IP",
4882 "RMAC", "#Paths", "Base Path");
4886 wctx
.json
= json_array
;
4888 /* walk through all vrfs */
4889 for (ALL_LIST_ELEMENTS_RO(bm
->bgp
, node
, bgp_vrf
)) {
4890 hash_iterate(bgp_vrf
->evpn_nh_table
,
4891 (void (*)(struct hash_bucket
*,
4892 void *))bgp_evpn_nh_show_hash_cb
,
4896 /* print the array of json-ESs */
4898 vty_json(vty
, json_array
);
4901 /*****************************************************************************/
4902 void bgp_evpn_mh_init(void)
4904 bm
->mh_info
= XCALLOC(MTYPE_BGP_EVPN_MH_INFO
, sizeof(*bm
->mh_info
));
4906 /* setup ES tables */
4907 RB_INIT(bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
);
4909 bgp_mh_info
->local_es_list
= list_new();
4910 listset_app_node_mem(bgp_mh_info
->local_es_list
);
4911 /* list of ESs with pending processing */
4912 bgp_mh_info
->pend_es_list
= list_new();
4913 listset_app_node_mem(bgp_mh_info
->pend_es_list
);
4915 bgp_mh_info
->ead_evi_rx
= BGP_EVPN_MH_EAD_EVI_RX_DEF
;
4916 bgp_mh_info
->ead_evi_tx
= BGP_EVPN_MH_EAD_EVI_TX_DEF
;
4917 bgp_mh_info
->ead_es_export_rtl
= list_new();
4918 bgp_mh_info
->ead_es_export_rtl
->cmp
=
4919 (int (*)(void *, void *))bgp_evpn_route_target_cmp
;
4920 bgp_mh_info
->ead_es_export_rtl
->del
= bgp_evpn_xxport_delete_ecomm
;
4922 /* config knobs - XXX add cli to control it */
4923 bgp_mh_info
->ead_evi_adv_for_down_links
= true;
4924 bgp_mh_info
->consistency_checking
= true;
4925 bgp_mh_info
->host_routes_use_l3nhg
= BGP_EVPN_MH_USE_ES_L3NHG_DEF
;
4926 bgp_mh_info
->suppress_l3_ecomm_on_inactive_es
= true;
4927 bgp_mh_info
->bgp_evpn_nh_setup
= true;
4928 bgp_mh_info
->evi_per_es_frag
= BGP_EVPN_MAX_EVI_PER_ES_FRAG
;
4930 memset(&zero_esi_buf
, 0, sizeof(esi_t
));
4933 void bgp_evpn_mh_finish(void)
4935 struct bgp_evpn_es
*es
;
4936 struct bgp_evpn_es
*es_next
;
4938 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
4939 zlog_debug("evpn mh finish");
4941 RB_FOREACH_SAFE (es
, bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
,
4943 bgp_evpn_es_local_info_clear(es
, true);
4945 if (bgp_mh_info
->t_cons_check
)
4946 EVENT_OFF(bgp_mh_info
->t_cons_check
);
4947 list_delete(&bgp_mh_info
->local_es_list
);
4948 list_delete(&bgp_mh_info
->pend_es_list
);
4949 list_delete(&bgp_mh_info
->ead_es_export_rtl
);
4951 XFREE(MTYPE_BGP_EVPN_MH_INFO
, bgp_mh_info
);
4954 /* This function is called when disable-ead-evi-rx knob flaps */
4955 void bgp_evpn_switch_ead_evi_rx(void)
4958 struct bgp_evpn_es
*es
;
4959 struct bgp_evpn_es_evi
*es_evi
;
4960 struct listnode
*evi_node
= NULL
;
4961 struct listnode
*evi_next
= NULL
;
4962 struct bgp_evpn_es_evi_vtep
*vtep
;
4963 struct listnode
*vtep_node
= NULL
;
4964 struct listnode
*vtep_next
= NULL
;
4966 bgp
= bgp_get_evpn();
4971 * Process all the remote es_evi_vteps and reevaluate if the es_evi_vtep
4974 RB_FOREACH(es
, bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
) {
4975 if (!CHECK_FLAG(es
->flags
, BGP_EVPNES_REMOTE
))
4978 for (ALL_LIST_ELEMENTS(es
->es_evi_list
, evi_node
, evi_next
,
4980 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_REMOTE
))
4983 for (ALL_LIST_ELEMENTS(es_evi
->es_evi_vtep_list
,
4984 vtep_node
, vtep_next
, vtep
))
4985 bgp_evpn_es_evi_vtep_re_eval_active(bgp
, vtep
);