1 /* EVPN Multihoming procedures
3 * Copyright (C) 2019 Cumulus Networks, Inc.
6 * This file is part of FRR.
8 * FRRouting is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2, or (at your option) any
13 * FRRouting is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
32 #include "lib/printfrr.h"
34 #include "bgpd/bgp_attr_evpn.h"
35 #include "bgpd/bgpd.h"
36 #include "bgpd/bgp_table.h"
37 #include "bgpd/bgp_route.h"
38 #include "bgpd/bgp_attr.h"
39 #include "bgpd/bgp_mplsvpn.h"
40 #include "bgpd/bgp_evpn.h"
41 #include "bgpd/bgp_evpn_private.h"
42 #include "bgpd/bgp_evpn_mh.h"
43 #include "bgpd/bgp_ecommunity.h"
44 #include "bgpd/bgp_encap_types.h"
45 #include "bgpd/bgp_debug.h"
46 #include "bgpd/bgp_errors.h"
47 #include "bgpd/bgp_aspath.h"
48 #include "bgpd/bgp_zebra.h"
49 #include "bgpd/bgp_addpath.h"
50 #include "bgpd/bgp_label.h"
51 #include "bgpd/bgp_nht.h"
52 #include "bgpd/bgp_mpath.h"
53 #include "bgpd/bgp_trace.h"
55 static void bgp_evpn_local_es_down(struct bgp
*bgp
,
56 struct bgp_evpn_es
*es
);
57 static void bgp_evpn_local_type1_evi_route_del(struct bgp
*bgp
,
58 struct bgp_evpn_es
*es
);
59 static struct bgp_evpn_es_vtep
*bgp_evpn_es_vtep_add(struct bgp
*bgp
,
60 struct bgp_evpn_es
*es
,
61 struct in_addr vtep_ip
,
62 bool esr
, uint8_t df_alg
,
64 static void bgp_evpn_es_vtep_del(struct bgp
*bgp
,
65 struct bgp_evpn_es
*es
, struct in_addr vtep_ip
, bool esr
);
66 static void bgp_evpn_es_cons_checks_pend_add(struct bgp_evpn_es
*es
);
67 static void bgp_evpn_es_cons_checks_pend_del(struct bgp_evpn_es
*es
);
68 static struct bgp_evpn_es_evi
*
69 bgp_evpn_local_es_evi_do_del(struct bgp_evpn_es_evi
*es_evi
);
70 static uint32_t bgp_evpn_es_get_active_vtep_cnt(struct bgp_evpn_es
*es
);
71 static void bgp_evpn_l3nhg_update_on_vtep_chg(struct bgp_evpn_es
*es
);
72 static struct bgp_evpn_es
*bgp_evpn_es_new(struct bgp
*bgp
, const esi_t
*esi
);
73 static void bgp_evpn_es_free(struct bgp_evpn_es
*es
, const char *caller
);
74 static void bgp_evpn_path_es_unlink(struct bgp_path_es_info
*es_info
);
75 static void bgp_evpn_mac_update_on_es_local_chg(struct bgp_evpn_es
*es
,
78 esi_t zero_esi_buf
, *zero_esi
= &zero_esi_buf
;
79 static void bgp_evpn_run_consistency_checks(struct thread
*t
);
80 static void bgp_evpn_path_nh_info_free(struct bgp_path_evpn_nh_info
*nh_info
);
81 static void bgp_evpn_path_nh_unlink(struct bgp_path_evpn_nh_info
*nh_info
);
83 /******************************************************************************
84 * per-ES (Ethernet Segment) routing table
86 * Following routes are added to the ES's routing table -
87 * 1. Local and remote ESR (Type-4)
88 * 2. Local EAD-per-ES (Type-1).
90 * Key for these routes is {ESI, VTEP-IP} so the path selection is practically
91 * a no-op i.e. all paths lead to same VTEP-IP (i.e. result in the same VTEP
92 * being added to same ES).
94 * Note the following routes go into the VNI routing table (instead of the
96 * 1. Remote EAD-per-ES
97 * 2. Local and remote EAD-per-EVI
100 /* Calculate the best path for a multi-homing (Type-1 or Type-4) route
101 * installed in the ES's routing table.
103 static int bgp_evpn_es_route_select_install(struct bgp
*bgp
,
104 struct bgp_evpn_es
*es
,
105 struct bgp_dest
*dest
)
108 afi_t afi
= AFI_L2VPN
;
109 safi_t safi
= SAFI_EVPN
;
110 struct bgp_path_info
*old_select
; /* old best */
111 struct bgp_path_info
*new_select
; /* new best */
112 struct bgp_path_info_pair old_and_new
;
114 /* Compute the best path. */
115 bgp_best_selection(bgp
, dest
, &bgp
->maxpaths
[afi
][safi
], &old_and_new
,
117 old_select
= old_and_new
.old
;
118 new_select
= old_and_new
.new;
121 * If the best path hasn't changed - see if something needs to be
124 if (old_select
&& old_select
== new_select
125 && old_select
->type
== ZEBRA_ROUTE_BGP
126 && old_select
->sub_type
== BGP_ROUTE_IMPORTED
127 && !CHECK_FLAG(dest
->flags
, BGP_NODE_USER_CLEAR
)
128 && !CHECK_FLAG(old_select
->flags
, BGP_PATH_ATTR_CHANGED
)
129 && !bgp_addpath_is_addpath_used(&bgp
->tx_addpath
, afi
, safi
)) {
130 if (bgp_zebra_has_route_changed(old_select
)) {
131 bgp_evpn_es_vtep_add(bgp
, es
, old_select
->attr
->nexthop
,
133 old_select
->attr
->df_alg
,
134 old_select
->attr
->df_pref
);
136 UNSET_FLAG(old_select
->flags
, BGP_PATH_MULTIPATH_CHG
);
137 bgp_zebra_clear_route_change_flags(dest
);
141 /* If the user did a "clear" this flag will be set */
142 UNSET_FLAG(dest
->flags
, BGP_NODE_USER_CLEAR
);
144 /* bestpath has changed; update relevant fields and install or uninstall
145 * into the zebra RIB.
147 if (old_select
|| new_select
)
148 bgp_bump_version(dest
);
151 bgp_path_info_unset_flag(dest
, old_select
, BGP_PATH_SELECTED
);
153 bgp_path_info_set_flag(dest
, new_select
, BGP_PATH_SELECTED
);
154 bgp_path_info_unset_flag(dest
, new_select
,
155 BGP_PATH_ATTR_CHANGED
);
156 UNSET_FLAG(new_select
->flags
, BGP_PATH_MULTIPATH_CHG
);
159 if (new_select
&& new_select
->type
== ZEBRA_ROUTE_BGP
160 && new_select
->sub_type
== BGP_ROUTE_IMPORTED
) {
161 bgp_evpn_es_vtep_add(bgp
, es
, new_select
->attr
->nexthop
,
162 true /*esr */, new_select
->attr
->df_alg
,
163 new_select
->attr
->df_pref
);
165 if (old_select
&& old_select
->type
== ZEBRA_ROUTE_BGP
166 && old_select
->sub_type
== BGP_ROUTE_IMPORTED
)
167 bgp_evpn_es_vtep_del(
168 bgp
, es
, old_select
->attr
->nexthop
,
172 /* Clear any route change flags. */
173 bgp_zebra_clear_route_change_flags(dest
);
175 /* Reap old select bgp_path_info, if it has been removed */
176 if (old_select
&& CHECK_FLAG(old_select
->flags
, BGP_PATH_REMOVED
))
177 bgp_path_info_reap(dest
, old_select
);
182 /* Install Type-1/Type-4 route entry in the per-ES routing table */
183 static int bgp_evpn_es_route_install(struct bgp
*bgp
,
184 struct bgp_evpn_es
*es
, struct prefix_evpn
*p
,
185 struct bgp_path_info
*parent_pi
)
188 struct bgp_dest
*dest
= NULL
;
189 struct bgp_path_info
*pi
= NULL
;
190 struct attr
*attr_new
= NULL
;
192 /* Create (or fetch) route within the VNI.
193 * NOTE: There is no RD here.
195 dest
= bgp_node_get(es
->route_table
, (struct prefix
*)p
);
197 /* Check if route entry is already present. */
198 for (pi
= bgp_dest_get_bgp_path_info(dest
); pi
; pi
= pi
->next
)
200 && (struct bgp_path_info
*)pi
->extra
->parent
==
205 /* Add (or update) attribute to hash. */
206 attr_new
= bgp_attr_intern(parent_pi
->attr
);
208 /* Create new route with its attribute. */
209 pi
= info_make(parent_pi
->type
, BGP_ROUTE_IMPORTED
, 0,
210 parent_pi
->peer
, attr_new
, dest
);
211 SET_FLAG(pi
->flags
, BGP_PATH_VALID
);
212 bgp_path_info_extra_get(pi
);
213 pi
->extra
->parent
= bgp_path_info_lock(parent_pi
);
214 bgp_dest_lock_node((struct bgp_dest
*)parent_pi
->net
);
215 bgp_path_info_add(dest
, pi
);
217 if (attrhash_cmp(pi
->attr
, parent_pi
->attr
)
218 && !CHECK_FLAG(pi
->flags
, BGP_PATH_REMOVED
)) {
219 bgp_dest_unlock_node(dest
);
222 /* The attribute has changed. */
223 /* Add (or update) attribute to hash. */
224 attr_new
= bgp_attr_intern(parent_pi
->attr
);
226 /* Restore route, if needed. */
227 if (CHECK_FLAG(pi
->flags
, BGP_PATH_REMOVED
))
228 bgp_path_info_restore(dest
, pi
);
230 /* Mark if nexthop has changed. */
231 if (!IPV4_ADDR_SAME(&pi
->attr
->nexthop
, &attr_new
->nexthop
))
232 SET_FLAG(pi
->flags
, BGP_PATH_IGP_CHANGED
);
234 /* Unintern existing, set to new. */
235 bgp_attr_unintern(&pi
->attr
);
237 pi
->uptime
= bgp_clock();
240 /* Perform route selection and update zebra, if required. */
241 ret
= bgp_evpn_es_route_select_install(bgp
, es
, dest
);
243 bgp_dest_unlock_node(dest
);
248 /* Uninstall Type-1/Type-4 route entry from the ES routing table */
249 static int bgp_evpn_es_route_uninstall(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
250 struct prefix_evpn
*p
, struct bgp_path_info
*parent_pi
)
253 struct bgp_dest
*dest
;
254 struct bgp_path_info
*pi
;
256 if (!es
->route_table
)
259 /* Locate route within the ESI.
260 * NOTE: There is no RD here.
262 dest
= bgp_node_lookup(es
->route_table
, (struct prefix
*)p
);
266 /* Find matching route entry. */
267 for (pi
= bgp_dest_get_bgp_path_info(dest
); pi
; pi
= pi
->next
)
269 && (struct bgp_path_info
*)pi
->extra
->parent
==
274 bgp_dest_unlock_node(dest
);
278 /* Mark entry for deletion */
279 bgp_path_info_delete(dest
, pi
);
281 /* Perform route selection and update zebra, if required. */
282 ret
= bgp_evpn_es_route_select_install(bgp
, es
, dest
);
284 /* Unlock route node. */
285 bgp_dest_unlock_node(dest
);
290 /* Install or unistall a Tyoe-4 route in the per-ES routing table */
291 int bgp_evpn_es_route_install_uninstall(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
292 afi_t afi
, safi_t safi
, struct prefix_evpn
*evp
,
293 struct bgp_path_info
*pi
, int install
)
298 ret
= bgp_evpn_es_route_install(bgp
, es
, evp
, pi
);
300 ret
= bgp_evpn_es_route_uninstall(bgp
, es
, evp
, pi
);
305 "%u: Failed to %s EVPN %s route in ESI %s",
307 install
? "install" : "uninstall",
314 /* Delete (and withdraw) local routes for specified ES from global and ES table.
315 * Also remove all remote routes from the per ES table. Invoked when ES
318 static void bgp_evpn_es_route_del_all(struct bgp
*bgp
, struct bgp_evpn_es
*es
)
320 struct bgp_dest
*dest
;
321 struct bgp_path_info
*pi
, *nextpi
;
323 /* de-activate the ES */
324 bgp_evpn_local_es_down(bgp
, es
);
325 bgp_evpn_local_type1_evi_route_del(bgp
, es
);
327 /* Walk this ES's routing table and delete all routes. */
328 for (dest
= bgp_table_top(es
->route_table
); dest
;
329 dest
= bgp_route_next(dest
)) {
330 for (pi
= bgp_dest_get_bgp_path_info(dest
);
331 (pi
!= NULL
) && (nextpi
= pi
->next
, 1); pi
= nextpi
) {
332 bgp_path_info_delete(dest
, pi
);
333 bgp_path_info_reap(dest
, pi
);
338 /*****************************************************************************
339 * Base APIs for creating MH routes (Type-1 or Type-4) on local ethernet
343 /* create or update local EVPN type1/type4 route entry.
346 * the ES table if ESR/EAD-ES (or)
347 * the VNI table if EAD-EVI (or)
348 * the global table if ESR/EAD-ES/EAD-EVI
350 * Note: vpn is applicable only to EAD-EVI routes (NULL for EAD-ES and
353 int bgp_evpn_mh_route_update(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
354 struct bgpevpn
*vpn
, afi_t afi
, safi_t safi
,
355 struct bgp_dest
*dest
, struct attr
*attr
, int add
,
356 struct bgp_path_info
**ri
, int *route_changed
)
358 struct bgp_path_info
*tmp_pi
= NULL
;
359 struct bgp_path_info
*local_pi
= NULL
; /* local route entry if any */
360 struct bgp_path_info
*remote_pi
= NULL
; /* remote route entry if any */
361 struct attr
*attr_new
= NULL
;
362 struct prefix_evpn
*evp
;
365 evp
= (struct prefix_evpn
*)bgp_dest_get_prefix(dest
);
368 /* locate the local and remote entries if any */
369 for (tmp_pi
= bgp_dest_get_bgp_path_info(dest
); tmp_pi
;
370 tmp_pi
= tmp_pi
->next
) {
371 if (tmp_pi
->peer
== bgp
->peer_self
372 && tmp_pi
->type
== ZEBRA_ROUTE_BGP
373 && tmp_pi
->sub_type
== BGP_ROUTE_STATIC
)
375 if (tmp_pi
->type
== ZEBRA_ROUTE_BGP
376 && tmp_pi
->sub_type
== BGP_ROUTE_IMPORTED
377 && CHECK_FLAG(tmp_pi
->flags
, BGP_PATH_VALID
))
381 /* we don't expect to see a remote_ri at this point as
382 * an ES route has {esi, vtep_ip} as the key in the ES-rt-table
383 * in the VNI-rt-table.
388 "%u ERROR: local es route for ESI: %s Vtep %pI4 also learnt from remote",
389 bgp
->vrf_id
, es
? es
->esi_str
: "Null",
394 if (!local_pi
&& !add
)
397 /* create or update the entry */
400 /* Add or update attribute to hash */
401 attr_new
= bgp_attr_intern(attr
);
403 /* Create new route with its attribute. */
404 tmp_pi
= info_make(ZEBRA_ROUTE_BGP
, BGP_ROUTE_STATIC
, 0,
405 bgp
->peer_self
, attr_new
, dest
);
406 SET_FLAG(tmp_pi
->flags
, BGP_PATH_VALID
);
408 if (evp
->prefix
.route_type
== BGP_EVPN_AD_ROUTE
) {
409 bgp_path_info_extra_get(tmp_pi
);
410 tmp_pi
->extra
->num_labels
= 1;
412 vni2label(vpn
->vni
, &tmp_pi
->extra
->label
[0]);
414 tmp_pi
->extra
->label
[0] = 0;
417 /* add the newly created path to the route-node */
418 bgp_path_info_add(dest
, tmp_pi
);
421 if (attrhash_cmp(tmp_pi
->attr
, attr
)
422 && !CHECK_FLAG(tmp_pi
->flags
, BGP_PATH_REMOVED
))
425 /* The attribute has changed.
426 * Add (or update) attribute to hash.
428 attr_new
= bgp_attr_intern(attr
);
429 bgp_path_info_set_flag(dest
, tmp_pi
,
430 BGP_PATH_ATTR_CHANGED
);
432 /* Restore route, if needed. */
433 if (CHECK_FLAG(tmp_pi
->flags
, BGP_PATH_REMOVED
))
434 bgp_path_info_restore(dest
, tmp_pi
);
436 /* Unintern existing, set to new. */
437 bgp_attr_unintern(&tmp_pi
->attr
);
438 tmp_pi
->attr
= attr_new
;
439 tmp_pi
->uptime
= bgp_clock();
443 if (*route_changed
) {
444 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
446 "local ES %s vni %u route-type %s nexthop %pI4 updated",
447 es
? es
->esi_str
: "Null", vpn
? vpn
->vni
: 0,
448 evp
->prefix
.route_type
== BGP_EVPN_ES_ROUTE
450 : (vpn
? "ead-evi" : "ead-es"),
451 &attr
->mp_nexthop_global_in
);
454 /* Return back the route entry. */
459 /* Delete local EVPN ESR (type-4) and EAD (type-1) route
461 * Note: vpn is applicable only to EAD-EVI routes (NULL for EAD-ES and
464 static int bgp_evpn_mh_route_delete(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
466 struct bgp_evpn_es_frag
*es_frag
,
467 struct prefix_evpn
*p
)
469 afi_t afi
= AFI_L2VPN
;
470 safi_t safi
= SAFI_EVPN
;
471 struct bgp_path_info
*pi
;
472 struct bgp_dest
*dest
= NULL
; /* dest in esi table */
473 struct bgp_dest
*global_dest
= NULL
; /* dest in global table */
474 struct bgp_table
*rt_table
;
475 struct prefix_rd
*prd
;
478 rt_table
= vpn
->route_table
;
481 rt_table
= es
->route_table
;
485 /* First, locate the route node within the ESI or VNI.
486 * If it doesn't exist, ther is nothing to do.
487 * Note: there is no RD here.
489 dest
= bgp_node_lookup(rt_table
, (struct prefix
*)p
);
493 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
495 "local ES %s vni %u route-type %s nexthop %pI4 delete",
496 es
->esi_str
, vpn
? vpn
->vni
: 0,
497 p
->prefix
.route_type
== BGP_EVPN_ES_ROUTE
499 : (vpn
? "ead-evi" : "ead-es"),
502 /* Next, locate route node in the global EVPN routing table.
503 * Note that this table is a 2-level tree (RD-level + Prefix-level)
506 bgp_global_evpn_node_lookup(bgp
->rib
[afi
][safi
], afi
, safi
,
507 (const struct prefix_evpn
*)p
, prd
);
510 /* Delete route entry in the global EVPN table. */
511 delete_evpn_route_entry(bgp
, afi
, safi
, global_dest
, &pi
);
513 /* Schedule for processing - withdraws to peers happen from
517 bgp_process(bgp
, global_dest
, afi
, safi
);
518 bgp_dest_unlock_node(global_dest
);
522 * Delete route entry in the ESI or VNI routing table.
523 * This can just be removed.
525 delete_evpn_route_entry(bgp
, afi
, safi
, dest
, &pi
);
527 bgp_path_info_reap(dest
, pi
);
528 bgp_dest_unlock_node(dest
);
533 * This function is called when the VNI RD changes.
534 * Delete all EAD/EVI local routes for this VNI from the global routing table.
535 * These routes are scheduled for withdraw from peers.
537 int delete_global_ead_evi_routes(struct bgp
*bgp
, struct bgpevpn
*vpn
)
541 struct bgp_dest
*rdrn
, *rn
;
542 struct bgp_table
*table
;
543 struct bgp_path_info
*pi
;
548 /* Find the RD node for the VNI in the global table */
549 rdrn
= bgp_node_lookup(bgp
->rib
[afi
][safi
], (struct prefix
*)&vpn
->prd
);
550 if (rdrn
&& bgp_dest_has_bgp_path_info_data(rdrn
)) {
551 table
= bgp_dest_get_bgp_table_info(rdrn
);
554 * Iterate over all the routes in this table and delete EAD/EVI
557 for (rn
= bgp_table_top(table
); rn
; rn
= bgp_route_next(rn
)) {
558 struct prefix_evpn
*evp
= (struct prefix_evpn
*)&rn
->p
;
560 if (evp
->prefix
.route_type
!= BGP_EVPN_AD_ROUTE
)
563 delete_evpn_route_entry(bgp
, afi
, safi
, rn
, &pi
);
565 bgp_process(bgp
, rn
, afi
, safi
);
569 /* Unlock RD node. */
571 bgp_dest_unlock_node(rdrn
);
576 /*****************************************************************************
577 * Ethernet Segment (Type-4) Routes
578 * ESRs are used for DF election. Currently service-carving described in
579 * RFC 7432 is NOT supported. Instead preference based DF election is
581 * Reference: draft-ietf-bess-evpn-pref-df
583 /* Build extended community for EVPN ES (type-4) route */
584 static void bgp_evpn_type4_route_extcomm_build(struct bgp_evpn_es
*es
,
587 struct ecommunity ecom_encap
;
588 struct ecommunity ecom_es_rt
;
589 struct ecommunity ecom_df
;
590 struct ecommunity_val eval
;
591 struct ecommunity_val eval_es_rt
;
592 struct ecommunity_val eval_df
;
593 bgp_encap_types tnl_type
;
597 tnl_type
= BGP_ENCAP_TYPE_VXLAN
;
598 memset(&ecom_encap
, 0, sizeof(ecom_encap
));
599 encode_encap_extcomm(tnl_type
, &eval
);
601 ecom_encap
.unit_size
= ECOMMUNITY_SIZE
;
602 ecom_encap
.val
= (uint8_t *)eval
.val
;
603 bgp_attr_set_ecommunity(attr
, ecommunity_dup(&ecom_encap
));
606 memset(&mac
, 0, sizeof(struct ethaddr
));
607 memset(&ecom_es_rt
, 0, sizeof(ecom_es_rt
));
608 es_get_system_mac(&es
->esi
, &mac
);
609 encode_es_rt_extcomm(&eval_es_rt
, &mac
);
611 ecom_es_rt
.unit_size
= ECOMMUNITY_SIZE
;
612 ecom_es_rt
.val
= (uint8_t *)eval_es_rt
.val
;
613 bgp_attr_set_ecommunity(
615 ecommunity_merge(bgp_attr_get_ecommunity(attr
), &ecom_es_rt
));
617 /* DF election extended community */
618 memset(&ecom_df
, 0, sizeof(ecom_df
));
619 encode_df_elect_extcomm(&eval_df
, es
->df_pref
);
621 ecom_df
.val
= (uint8_t *)eval_df
.val
;
622 bgp_attr_set_ecommunity(
624 ecommunity_merge(bgp_attr_get_ecommunity(attr
), &ecom_df
));
626 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES
);
629 /* Create or update local type-4 route */
630 static int bgp_evpn_type4_route_update(struct bgp
*bgp
,
631 struct bgp_evpn_es
*es
, struct prefix_evpn
*p
)
634 int route_changed
= 0;
635 afi_t afi
= AFI_L2VPN
;
636 safi_t safi
= SAFI_EVPN
;
638 struct attr
*attr_new
= NULL
;
639 struct bgp_dest
*dest
= NULL
;
640 struct bgp_path_info
*pi
= NULL
;
642 memset(&attr
, 0, sizeof(struct attr
));
644 /* Build path-attribute for this route. */
645 bgp_attr_default_set(&attr
, BGP_ORIGIN_IGP
);
646 attr
.nexthop
= es
->originator_ip
;
647 attr
.mp_nexthop_global_in
= es
->originator_ip
;
648 attr
.mp_nexthop_len
= BGP_ATTR_NHLEN_IPV4
;
650 /* Set up extended community. */
651 bgp_evpn_type4_route_extcomm_build(es
, &attr
);
653 /* First, create (or fetch) route node within the ESI. */
654 /* NOTE: There is no RD here. */
655 dest
= bgp_node_get(es
->route_table
, (struct prefix
*)p
);
657 /* Create or update route entry. */
658 ret
= bgp_evpn_mh_route_update(bgp
, es
, NULL
, afi
, safi
, dest
, &attr
, 1,
659 &pi
, &route_changed
);
663 "%u ERROR: Failed to updated ES route ESI: %s VTEP %pI4",
664 bgp
->vrf_id
, es
->esi_str
, &es
->originator_ip
);
669 /* Perform route selection;
670 * this is just to set the flags correctly
671 * as local route in the ES always wins.
673 bgp_evpn_es_route_select_install(bgp
, es
, dest
);
674 bgp_dest_unlock_node(dest
);
676 /* If this is a new route or some attribute has changed, export the
677 * route to the global table. The route will be advertised to peers
678 * from there. Note that this table is a 2-level tree (RD-level +
679 * Prefix-level) similar to L3VPN routes.
682 struct bgp_path_info
*global_pi
;
684 dest
= bgp_global_evpn_node_get(bgp
->rib
[afi
][safi
], afi
, safi
,
685 p
, &es
->es_base_frag
->prd
);
686 bgp_evpn_mh_route_update(bgp
, es
, NULL
, afi
, safi
, dest
,
687 attr_new
, 1, &global_pi
,
690 /* Schedule for processing and unlock node. */
691 bgp_process(bgp
, dest
, afi
, safi
);
692 bgp_dest_unlock_node(dest
);
695 /* Unintern temporary. */
696 aspath_unintern(&attr
.aspath
);
700 /* Delete local type-4 route */
701 static int bgp_evpn_type4_route_delete(struct bgp
*bgp
,
702 struct bgp_evpn_es
*es
, struct prefix_evpn
*p
)
704 if (!es
->es_base_frag
)
707 return bgp_evpn_mh_route_delete(bgp
, es
, NULL
/* l2vni */,
708 es
->es_base_frag
, p
);
711 /* Process remote/received EVPN type-4 route (advertise or withdraw) */
712 int bgp_evpn_type4_route_process(struct peer
*peer
, afi_t afi
, safi_t safi
,
713 struct attr
*attr
, uint8_t *pfx
, int psize
,
719 struct in_addr vtep_ip
;
720 struct prefix_rd prd
;
721 struct prefix_evpn p
;
723 /* Type-4 route should be either 23 or 35 bytes
724 * RD (8), ESI (10), ip-len (1), ip (4 or 16)
726 if (psize
!= BGP_EVPN_TYPE4_V4_PSIZE
&&
727 psize
!= BGP_EVPN_TYPE4_V6_PSIZE
) {
728 flog_err(EC_BGP_EVPN_ROUTE_INVALID
,
729 "%u:%s - Rx EVPN Type-4 NLRI with invalid length %d",
730 peer
->bgp
->vrf_id
, peer
->host
, psize
);
735 prd
.family
= AF_UNSPEC
;
737 memcpy(&prd
.val
, pfx
, RD_BYTES
);
741 memcpy(&esi
, pfx
, ESI_BYTES
);
747 if (ipaddr_len
== IPV4_MAX_BITLEN
) {
748 memcpy(&vtep_ip
, pfx
, IPV4_MAX_BYTELEN
);
751 EC_BGP_EVPN_ROUTE_INVALID
,
752 "%u:%s - Rx EVPN Type-4 NLRI with unsupported IP address length %d",
753 peer
->bgp
->vrf_id
, peer
->host
, ipaddr_len
);
757 build_evpn_type4_prefix(&p
, &esi
, vtep_ip
);
758 /* Process the route. */
760 ret
= bgp_update(peer
, (struct prefix
*)&p
, addpath_id
, attr
,
761 afi
, safi
, ZEBRA_ROUTE_BGP
, BGP_ROUTE_NORMAL
,
762 &prd
, NULL
, 0, 0, NULL
);
764 ret
= bgp_withdraw(peer
, (struct prefix
*)&p
, addpath_id
, attr
,
765 afi
, safi
, ZEBRA_ROUTE_BGP
, BGP_ROUTE_NORMAL
,
766 &prd
, NULL
, 0, NULL
);
771 /* Check if a prefix belongs to the local ES */
772 static bool bgp_evpn_type4_prefix_match(struct prefix_evpn
*p
,
773 struct bgp_evpn_es
*es
)
775 return (p
->prefix
.route_type
== BGP_EVPN_ES_ROUTE
) &&
776 !memcmp(&p
->prefix
.es_addr
.esi
, &es
->esi
, sizeof(esi_t
));
779 /* Import remote ESRs on local ethernet segment add */
780 static int bgp_evpn_type4_remote_routes_import(struct bgp
*bgp
,
781 struct bgp_evpn_es
*es
, bool install
)
786 struct bgp_dest
*rd_dest
, *dest
;
787 struct bgp_table
*table
;
788 struct bgp_path_info
*pi
;
793 /* Walk entire global routing table and evaluate routes which could be
794 * imported into this Ethernet Segment.
796 for (rd_dest
= bgp_table_top(bgp
->rib
[afi
][safi
]); rd_dest
;
797 rd_dest
= bgp_route_next(rd_dest
)) {
798 table
= bgp_dest_get_bgp_table_info(rd_dest
);
802 for (dest
= bgp_table_top(table
); dest
;
803 dest
= bgp_route_next(dest
)) {
804 struct prefix_evpn
*evp
=
805 (struct prefix_evpn
*)bgp_dest_get_prefix(dest
);
807 for (pi
= bgp_dest_get_bgp_path_info(dest
); pi
;
810 * Consider "valid" remote routes applicable for
813 if (!(CHECK_FLAG(pi
->flags
, BGP_PATH_VALID
)
814 && pi
->type
== ZEBRA_ROUTE_BGP
815 && pi
->sub_type
== BGP_ROUTE_NORMAL
))
818 if (!bgp_evpn_type4_prefix_match(evp
, es
))
822 ret
= bgp_evpn_es_route_install(
825 ret
= bgp_evpn_es_route_uninstall(
831 "Failed to %s EVPN %pFX route in ESI %s",
836 bgp_dest_unlock_node(rd_dest
);
837 bgp_dest_unlock_node(dest
);
846 /*****************************************************************************
847 * Ethernet Auto Discovery (EAD/Type-1) route handling
848 * There are two types of EAD routes -
849 * 1. EAD-per-ES - Key: {ESI, ET=0xffffffff}
850 * 2. EAD-per-EVI - Key: {ESI, ET=0}
853 /* Extended communities associated with EAD-per-ES */
855 bgp_evpn_type1_es_route_extcomm_build(struct bgp_evpn_es_frag
*es_frag
,
858 struct ecommunity ecom_encap
;
859 struct ecommunity ecom_esi_label
;
860 struct ecommunity_val eval
;
861 struct ecommunity_val eval_esi_label
;
862 bgp_encap_types tnl_type
;
863 struct listnode
*evi_node
, *rt_node
;
864 struct ecommunity
*ecom
;
865 struct bgp_evpn_es_evi
*es_evi
;
868 tnl_type
= BGP_ENCAP_TYPE_VXLAN
;
869 memset(&ecom_encap
, 0, sizeof(ecom_encap
));
870 encode_encap_extcomm(tnl_type
, &eval
);
872 ecom_encap
.unit_size
= ECOMMUNITY_SIZE
;
873 ecom_encap
.val
= (uint8_t *)eval
.val
;
874 bgp_attr_set_ecommunity(attr
, ecommunity_dup(&ecom_encap
));
877 encode_esi_label_extcomm(&eval_esi_label
,
878 false /*single_active*/);
879 ecom_esi_label
.size
= 1;
880 ecom_esi_label
.unit_size
= ECOMMUNITY_SIZE
;
881 ecom_esi_label
.val
= (uint8_t *)eval_esi_label
.val
;
882 bgp_attr_set_ecommunity(attr
,
883 ecommunity_merge(bgp_attr_get_ecommunity(attr
),
886 /* Add export RTs for all L2-VNIs associated with this ES */
887 /* XXX - suppress EAD-ES advertisment if there are no EVIs associated
890 if (listcount(bgp_mh_info
->ead_es_export_rtl
)) {
891 for (ALL_LIST_ELEMENTS_RO(bgp_mh_info
->ead_es_export_rtl
,
893 bgp_attr_set_ecommunity(
894 attr
, ecommunity_merge(attr
->ecommunity
, ecom
));
896 for (ALL_LIST_ELEMENTS_RO(es_frag
->es_evi_frag_list
, evi_node
,
898 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
900 for (ALL_LIST_ELEMENTS_RO(es_evi
->vpn
->export_rtl
,
902 bgp_attr_set_ecommunity(
903 attr
, ecommunity_merge(attr
->ecommunity
,
908 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES
);
911 /* Extended communities associated with EAD-per-EVI */
912 static void bgp_evpn_type1_evi_route_extcomm_build(struct bgp_evpn_es
*es
,
913 struct bgpevpn
*vpn
, struct attr
*attr
)
915 struct ecommunity ecom_encap
;
916 struct ecommunity_val eval
;
917 bgp_encap_types tnl_type
;
918 struct listnode
*rt_node
;
919 struct ecommunity
*ecom
;
922 tnl_type
= BGP_ENCAP_TYPE_VXLAN
;
923 memset(&ecom_encap
, 0, sizeof(ecom_encap
));
924 encode_encap_extcomm(tnl_type
, &eval
);
926 ecom_encap
.unit_size
= ECOMMUNITY_SIZE
;
927 ecom_encap
.val
= (uint8_t *)eval
.val
;
928 bgp_attr_set_ecommunity(attr
, ecommunity_dup(&ecom_encap
));
930 /* Add export RTs for the L2-VNI */
931 for (ALL_LIST_ELEMENTS_RO(vpn
->export_rtl
, rt_node
, ecom
))
932 bgp_attr_set_ecommunity(
934 ecommunity_merge(bgp_attr_get_ecommunity(attr
), ecom
));
936 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES
);
939 /* Update EVPN EAD (type-1) route -
940 * vpn - valid for EAD-EVI routes and NULL for EAD-ES routes
942 static int bgp_evpn_type1_route_update(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
944 struct bgp_evpn_es_frag
*es_frag
,
945 struct prefix_evpn
*p
)
948 afi_t afi
= AFI_L2VPN
;
949 safi_t safi
= SAFI_EVPN
;
951 struct attr
*attr_new
= NULL
;
952 struct bgp_dest
*dest
= NULL
;
953 struct bgp_path_info
*pi
= NULL
;
954 int route_changed
= 0;
955 struct prefix_rd
*global_rd
;
957 memset(&attr
, 0, sizeof(struct attr
));
959 /* Build path-attribute for this route. */
960 bgp_attr_default_set(&attr
, BGP_ORIGIN_IGP
);
961 attr
.nexthop
= es
->originator_ip
;
962 attr
.mp_nexthop_global_in
= es
->originator_ip
;
963 attr
.mp_nexthop_len
= BGP_ATTR_NHLEN_IPV4
;
966 /* EAD-EVI route update */
968 vni2label(vpn
->vni
, &(attr
.label
));
970 /* Set up extended community */
971 bgp_evpn_type1_evi_route_extcomm_build(es
, vpn
, &attr
);
973 /* First, create (or fetch) route node within the VNI. */
974 dest
= bgp_node_get(vpn
->route_table
, (struct prefix
*)p
);
976 /* Create or update route entry. */
977 ret
= bgp_evpn_mh_route_update(bgp
, es
, vpn
, afi
, safi
, dest
,
978 &attr
, 1, &pi
, &route_changed
);
982 "%u Failed to update EAD-EVI route ESI: %s VNI %u VTEP %pI4",
983 bgp
->vrf_id
, es
->esi_str
, vpn
->vni
,
985 global_rd
= &vpn
->prd
;
987 /* EAD-ES route update */
988 /* MPLS label is 0 for EAD-ES route */
990 /* Set up extended community */
991 bgp_evpn_type1_es_route_extcomm_build(es_frag
, &attr
);
993 /* First, create (or fetch) route node within the ES. */
994 /* NOTE: There is no RD here. */
995 /* XXX: fragment ID must be included as a part of the prefix. */
996 dest
= bgp_node_get(es
->route_table
, (struct prefix
*)p
);
998 /* Create or update route entry. */
999 ret
= bgp_evpn_mh_route_update(bgp
, es
, vpn
, afi
, safi
, dest
,
1000 &attr
, 1, &pi
, &route_changed
);
1004 "%u ERROR: Failed to updated EAD-EVI route ESI: %s VTEP %pI4",
1005 bgp
->vrf_id
, es
->esi_str
, &es
->originator_ip
);
1007 global_rd
= &es_frag
->prd
;
1012 attr_new
= pi
->attr
;
1014 /* Perform route selection;
1015 * this is just to set the flags correctly as local route in
1016 * the ES always wins.
1018 evpn_route_select_install(bgp
, vpn
, dest
);
1019 bgp_dest_unlock_node(dest
);
1021 /* If this is a new route or some attribute has changed, export the
1022 * route to the global table. The route will be advertised to peers
1023 * from there. Note that this table is a 2-level tree (RD-level +
1024 * Prefix-level) similar to L3VPN routes.
1026 if (route_changed
) {
1027 struct bgp_path_info
*global_pi
;
1029 dest
= bgp_global_evpn_node_get(bgp
->rib
[afi
][safi
], afi
, safi
,
1031 bgp_evpn_mh_route_update(bgp
, es
, vpn
, afi
, safi
, dest
,
1032 attr_new
, 1, &global_pi
,
1035 /* Schedule for processing and unlock node. */
1036 bgp_process(bgp
, dest
, afi
, safi
);
1037 bgp_dest_unlock_node(dest
);
1040 /* Unintern temporary. */
1041 aspath_unintern(&attr
.aspath
);
1046 * This function is called when the export RT for a VNI changes.
1047 * Update all type-1 local routes for this VNI from VNI/ES tables and the global
1048 * table and advertise these routes to peers.
1051 static void bgp_evpn_ead_es_route_update(struct bgp
*bgp
,
1052 struct bgp_evpn_es
*es
)
1054 struct listnode
*node
;
1055 struct bgp_evpn_es_frag
*es_frag
;
1056 struct prefix_evpn p
;
1058 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_ES_ETH_TAG
, &es
->esi
,
1060 for (ALL_LIST_ELEMENTS_RO(es
->es_frag_list
, node
, es_frag
)) {
1061 if (!listcount(es_frag
->es_evi_frag_list
))
1064 p
.prefix
.ead_addr
.frag_id
= es_frag
->rd_id
;
1065 if (bgp_evpn_type1_route_update(bgp
, es
, NULL
, es_frag
, &p
))
1067 EC_BGP_EVPN_ROUTE_CREATE
,
1068 "EAD-ES route creation failure for ESI %s frag %u",
1069 es
->esi_str
, es_frag
->rd_id
);
1073 static void bgp_evpn_ead_evi_route_update(struct bgp
*bgp
,
1074 struct bgp_evpn_es
*es
,
1075 struct bgpevpn
*vpn
,
1076 struct prefix_evpn
*p
)
1078 if (bgp_evpn_type1_route_update(bgp
, es
, vpn
, NULL
, p
))
1079 flog_err(EC_BGP_EVPN_ROUTE_CREATE
,
1080 "EAD-EVI route creation failure for ESI %s VNI %u",
1081 es
->esi_str
, vpn
->vni
);
1084 void update_type1_routes_for_evi(struct bgp
*bgp
, struct bgpevpn
*vpn
)
1086 struct prefix_evpn p
;
1087 struct bgp_evpn_es
*es
;
1088 struct bgp_evpn_es_evi
*es_evi
;
1091 RB_FOREACH (es_evi
, bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
) {
1094 if (es_evi
->vpn
!= vpn
)
1098 bgp_evpn_ead_es_route_update(bgp
, es
);
1100 /* Update EAD-EVI */
1101 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
)) {
1102 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_EVI_ETH_TAG
,
1103 &es
->esi
, es
->originator_ip
);
1104 bgp_evpn_ead_evi_route_update(bgp
, es
, vpn
, &p
);
1109 /* Delete local Type-1 route */
1110 static void bgp_evpn_ead_es_route_delete(struct bgp
*bgp
,
1111 struct bgp_evpn_es
*es
)
1113 struct listnode
*node
;
1114 struct bgp_evpn_es_frag
*es_frag
;
1115 struct prefix_evpn p
;
1117 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_ES_ETH_TAG
, &es
->esi
,
1119 for (ALL_LIST_ELEMENTS_RO(es
->es_frag_list
, node
, es_frag
)) {
1120 p
.prefix
.ead_addr
.frag_id
= es_frag
->rd_id
;
1121 bgp_evpn_mh_route_delete(bgp
, es
, NULL
, es_frag
, &p
);
1125 static int bgp_evpn_ead_evi_route_delete(struct bgp
*bgp
,
1126 struct bgp_evpn_es
*es
,
1127 struct bgpevpn
*vpn
,
1128 struct prefix_evpn
*p
)
1130 return bgp_evpn_mh_route_delete(bgp
, es
, vpn
, NULL
, p
);
1133 /* Generate EAD-EVI for all VNIs */
1134 static void bgp_evpn_local_type1_evi_route_add(struct bgp
*bgp
,
1135 struct bgp_evpn_es
*es
)
1137 struct listnode
*evi_node
;
1138 struct prefix_evpn p
;
1139 struct bgp_evpn_es_evi
*es_evi
;
1141 /* EAD-per-EVI routes have been suppressed */
1142 if (!bgp_mh_info
->ead_evi_tx
)
1145 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
))
1146 /* EAD-EVI route add for this ES is already done */
1149 SET_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
);
1150 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_EVI_ETH_TAG
,
1151 &es
->esi
, es
->originator_ip
);
1153 for (ALL_LIST_ELEMENTS_RO(es
->es_evi_list
, evi_node
, es_evi
)) {
1154 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
1156 bgp_evpn_ead_evi_route_update(bgp
, es
, es_evi
->vpn
, &p
);
1161 * Withdraw EAD-EVI for all VNIs
1163 static void bgp_evpn_local_type1_evi_route_del(struct bgp
*bgp
,
1164 struct bgp_evpn_es
*es
)
1166 struct listnode
*evi_node
;
1167 struct prefix_evpn p
;
1168 struct bgp_evpn_es_evi
*es_evi
;
1170 /* Delete and withdraw locally learnt EAD-EVI route */
1171 if (!CHECK_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
))
1172 /* EAD-EVI route has not been advertised for this ES */
1175 UNSET_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
);
1176 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_EVI_ETH_TAG
,
1177 &es
->esi
, es
->originator_ip
);
1178 for (ALL_LIST_ELEMENTS_RO(es
->es_evi_list
, evi_node
, es_evi
)) {
1179 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
1181 if (bgp_evpn_mh_route_delete(bgp
, es
, es_evi
->vpn
, NULL
, &p
))
1182 flog_err(EC_BGP_EVPN_ROUTE_CREATE
,
1183 "%u: Type4 route creation failure for ESI %s",
1184 bgp
->vrf_id
, es
->esi_str
);
1189 * Process received EVPN type-1 route (advertise or withdraw).
1191 int bgp_evpn_type1_route_process(struct peer
*peer
, afi_t afi
, safi_t safi
,
1192 struct attr
*attr
, uint8_t *pfx
, int psize
,
1193 uint32_t addpath_id
)
1196 struct prefix_rd prd
;
1200 struct in_addr vtep_ip
;
1201 struct prefix_evpn p
;
1203 if (psize
!= BGP_EVPN_TYPE1_PSIZE
) {
1204 flog_err(EC_BGP_EVPN_ROUTE_INVALID
,
1205 "%u:%s - Rx EVPN Type-1 NLRI with invalid length %d",
1206 peer
->bgp
->vrf_id
, peer
->host
, psize
);
1210 /* Make prefix_rd */
1211 prd
.family
= AF_UNSPEC
;
1213 memcpy(&prd
.val
, pfx
, RD_BYTES
);
1217 memcpy(&esi
, pfx
, ESI_BYTES
);
1220 /* Copy Ethernet Tag */
1221 memcpy(ð_tag
, pfx
, EVPN_ETH_TAG_BYTES
);
1222 eth_tag
= ntohl(eth_tag
);
1223 pfx
+= EVPN_ETH_TAG_BYTES
;
1225 memcpy(&label
, pfx
, BGP_LABEL_BYTES
);
1227 /* EAD route prefix doesn't include the nexthop in the global
1230 vtep_ip
.s_addr
= INADDR_ANY
;
1231 build_evpn_type1_prefix(&p
, eth_tag
, &esi
, vtep_ip
);
1232 /* Process the route. */
1234 ret
= bgp_update(peer
, (struct prefix
*)&p
, addpath_id
, attr
,
1235 afi
, safi
, ZEBRA_ROUTE_BGP
, BGP_ROUTE_NORMAL
,
1236 &prd
, NULL
, 0, 0, NULL
);
1238 ret
= bgp_withdraw(peer
, (struct prefix
*)&p
, addpath_id
, attr
,
1239 afi
, safi
, ZEBRA_ROUTE_BGP
, BGP_ROUTE_NORMAL
,
1240 &prd
, NULL
, 0, NULL
);
1245 void bgp_evpn_mh_config_ead_export_rt(struct bgp
*bgp
,
1246 struct ecommunity
*ecomcfg
, bool del
)
1248 struct listnode
*node
, *nnode
, *node_to_del
;
1249 struct ecommunity
*ecom
;
1250 struct bgp_evpn_es
*es
;
1253 if (ecomcfg
== NULL
) {
1254 /* Reset to default and process all routes. */
1255 for (ALL_LIST_ELEMENTS(bgp_mh_info
->ead_es_export_rtl
,
1256 node
, nnode
, ecom
)) {
1257 ecommunity_free(&ecom
);
1258 list_delete_node(bgp_mh_info
->ead_es_export_rtl
,
1263 /* Delete a specific export RT */
1267 for (ALL_LIST_ELEMENTS(bgp_mh_info
->ead_es_export_rtl
,
1268 node
, nnode
, ecom
)) {
1269 if (ecommunity_match(ecom
, ecomcfg
)) {
1270 ecommunity_free(&ecom
);
1277 list_delete_node(bgp_mh_info
->ead_es_export_rtl
,
1281 listnode_add_sort(bgp_mh_info
->ead_es_export_rtl
, ecomcfg
);
1284 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
1285 zlog_debug("local ES del/re-add EAD route on export RT change");
1287 * walk through all active ESs withdraw the old EAD and
1288 * generate a new one
1290 RB_FOREACH (es
, bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
) {
1291 if (!bgp_evpn_is_es_local(es
) ||
1292 !bgp_evpn_local_es_is_active(es
))
1295 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
1297 "local ES %s del/re-add EAD route on export RT change",
1301 * withdraw EAD-ES. XXX - this should technically not be
1302 * needed; can be removed after testing
1304 bgp_evpn_ead_es_route_delete(bgp
, es
);
1306 /* generate EAD-ES */
1307 bgp_evpn_ead_es_route_update(bgp
, es
);
1311 /*****************************************************************************/
1312 /* Ethernet Segment Management
1313 * 1. Ethernet Segment is a collection of links attached to the same
1314 * server (MHD) or switch (MHN)
1315 * 2. An Ethernet Segment can span multiple PEs and is identified by the
1317 * 3. Local ESs are configured in zebra and sent to BGP
1318 * 4. Remote ESs are created by BGP when one or more ES-EVIs reference it i.e.
1319 * created on first reference and release on last de-reference
1320 * 5. An ES can be both local and remote. Infact most local ESs are expected
1321 * to have an ES peer.
1324 /* A list of remote VTEPs is maintained for each ES. This list includes -
1325 * 1. VTEPs for which we have imported the ESR i.e. ES-peers
1326 * 2. VTEPs that have an "active" ES-EVI VTEP i.e. EAD-per-ES and EAD-per-EVI
1327 * have been imported into one or more VNIs
1329 static int bgp_evpn_es_vtep_cmp(void *p1
, void *p2
)
1331 const struct bgp_evpn_es_vtep
*es_vtep1
= p1
;
1332 const struct bgp_evpn_es_vtep
*es_vtep2
= p2
;
1334 return es_vtep1
->vtep_ip
.s_addr
- es_vtep2
->vtep_ip
.s_addr
;
1337 static struct bgp_evpn_es_vtep
*bgp_evpn_es_vtep_new(struct bgp_evpn_es
*es
,
1338 struct in_addr vtep_ip
)
1340 struct bgp_evpn_es_vtep
*es_vtep
;
1342 es_vtep
= XCALLOC(MTYPE_BGP_EVPN_ES_VTEP
, sizeof(*es_vtep
));
1345 es_vtep
->vtep_ip
.s_addr
= vtep_ip
.s_addr
;
1346 inet_ntop(AF_INET
, &es_vtep
->vtep_ip
, es_vtep
->vtep_str
,
1347 sizeof(es_vtep
->vtep_str
));
1348 listnode_init(&es_vtep
->es_listnode
, es_vtep
);
1349 listnode_add_sort(es
->es_vtep_list
, &es_vtep
->es_listnode
);
1354 static void bgp_evpn_es_vtep_free(struct bgp_evpn_es_vtep
*es_vtep
)
1356 struct bgp_evpn_es
*es
= es_vtep
->es
;
1358 if (CHECK_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ESR
) ||
1360 /* as long as there is some reference we can't free it */
1363 list_delete_node(es
->es_vtep_list
, &es_vtep
->es_listnode
);
1364 XFREE(MTYPE_BGP_EVPN_ES_VTEP
, es_vtep
);
1367 /* check if VTEP is already part of the list */
1368 static struct bgp_evpn_es_vtep
*bgp_evpn_es_vtep_find(struct bgp_evpn_es
*es
,
1369 struct in_addr vtep_ip
)
1371 struct listnode
*node
= NULL
;
1372 struct bgp_evpn_es_vtep
*es_vtep
;
1374 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
1375 if (es_vtep
->vtep_ip
.s_addr
== vtep_ip
.s_addr
)
1381 /* Send the remote ES to zebra for NHG programming */
1382 static int bgp_zebra_send_remote_es_vtep(struct bgp
*bgp
,
1383 struct bgp_evpn_es_vtep
*es_vtep
, bool add
)
1385 struct bgp_evpn_es
*es
= es_vtep
->es
;
1390 if (!zclient
|| zclient
->sock
< 0)
1393 /* Don't try to register if Zebra doesn't know of this instance. */
1394 if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp
)) {
1395 if (BGP_DEBUG(zebra
, ZEBRA
))
1396 zlog_debug("No zebra instance, not installing remote es %s",
1401 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ESR
)
1402 flags
|= ZAPI_ES_VTEP_FLAG_ESR_RXED
;
1407 zclient_create_header(s
,
1408 add
? ZEBRA_REMOTE_ES_VTEP_ADD
: ZEBRA_REMOTE_ES_VTEP_DEL
,
1410 stream_put(s
, &es
->esi
, sizeof(esi_t
));
1411 stream_put_ipv4(s
, es_vtep
->vtep_ip
.s_addr
);
1413 stream_putl(s
, flags
);
1414 stream_putc(s
, es_vtep
->df_alg
);
1415 stream_putw(s
, es_vtep
->df_pref
);
1418 stream_putw_at(s
, 0, stream_get_endp(s
));
1420 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1421 zlog_debug("Tx %s Remote ESI %s VTEP %pI4", add
? "ADD" : "DEL",
1422 es
->esi_str
, &es_vtep
->vtep_ip
);
1424 frrtrace(3, frr_bgp
, evpn_mh_vtep_zsend
, add
, es
, es_vtep
);
1426 return zclient_send_message(zclient
);
1429 static void bgp_evpn_es_vtep_re_eval_active(struct bgp
*bgp
,
1430 struct bgp_evpn_es_vtep
*es_vtep
,
1436 old_active
= CHECK_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
);
1437 /* currently we need an active EVI reference to use the VTEP as
1438 * a nexthop. this may change...
1440 if (es_vtep
->evi_cnt
)
1441 SET_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
);
1443 UNSET_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
);
1445 new_active
= CHECK_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
);
1447 if ((old_active
!= new_active
) || (new_active
&& param_change
)) {
1449 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1450 zlog_debug("es %s vtep %pI4 %s df %u/%u",
1451 es_vtep
->es
->esi_str
, &es_vtep
->vtep_ip
,
1452 new_active
? "active" : "inactive",
1453 es_vtep
->df_alg
, es_vtep
->df_pref
);
1455 /* send remote ES to zebra */
1456 bgp_zebra_send_remote_es_vtep(bgp
, es_vtep
, new_active
);
1458 /* The NHG is updated first for efficient failover handling.
1459 * Note the NHG can be de-activated while there are bgp
1460 * routes referencing it. Zebra is capable of handling that
1461 * elegantly by holding the NHG till all routes using it are
1464 bgp_evpn_l3nhg_update_on_vtep_chg(es_vtep
->es
);
1465 /* queue up the es for background consistency checks */
1466 bgp_evpn_es_cons_checks_pend_add(es_vtep
->es
);
1470 static struct bgp_evpn_es_vtep
*bgp_evpn_es_vtep_add(struct bgp
*bgp
,
1471 struct bgp_evpn_es
*es
,
1472 struct in_addr vtep_ip
,
1473 bool esr
, uint8_t df_alg
,
1476 struct bgp_evpn_es_vtep
*es_vtep
;
1477 bool param_change
= false;
1479 es_vtep
= bgp_evpn_es_vtep_find(es
, vtep_ip
);
1482 es_vtep
= bgp_evpn_es_vtep_new(es
, vtep_ip
);
1484 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1485 zlog_debug("es %s vtep %pI4 add %s df %u/%u",
1486 es_vtep
->es
->esi_str
, &es_vtep
->vtep_ip
,
1487 esr
? "esr" : "ead", df_alg
, df_pref
);
1490 SET_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ESR
);
1491 if ((es_vtep
->df_pref
!= df_pref
)
1492 || (es_vtep
->df_alg
!= df_alg
)) {
1493 param_change
= true;
1494 es_vtep
->df_pref
= df_pref
;
1495 es_vtep
->df_alg
= df_alg
;
1501 bgp_evpn_es_vtep_re_eval_active(bgp
, es_vtep
, param_change
);
1506 static void bgp_evpn_es_vtep_do_del(struct bgp
*bgp
,
1507 struct bgp_evpn_es_vtep
*es_vtep
, bool esr
)
1509 bool param_change
= false;
1511 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1512 zlog_debug("es %s vtep %pI4 del %s", es_vtep
->es
->esi_str
,
1513 &es_vtep
->vtep_ip
, esr
? "esr" : "ead");
1515 UNSET_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ESR
);
1516 if (es_vtep
->df_pref
|| es_vtep
->df_alg
) {
1517 param_change
= true;
1518 es_vtep
->df_pref
= 0;
1519 es_vtep
->df_alg
= 0;
1522 if (es_vtep
->evi_cnt
)
1526 bgp_evpn_es_vtep_re_eval_active(bgp
, es_vtep
, param_change
);
1527 bgp_evpn_es_vtep_free(es_vtep
);
1530 static void bgp_evpn_es_vtep_del(struct bgp
*bgp
,
1531 struct bgp_evpn_es
*es
, struct in_addr vtep_ip
, bool esr
)
1533 struct bgp_evpn_es_vtep
*es_vtep
;
1535 es_vtep
= bgp_evpn_es_vtep_find(es
, vtep_ip
);
1537 bgp_evpn_es_vtep_do_del(bgp
, es_vtep
, esr
);
1540 /********************** ES MAC-IP paths *************************************
1541 * 1. Local MAC-IP routes in the VNI routing table are linked to the
1542 * destination ES (macip_evi_path_list) for efficient updates on ES oper
1544 * 2. Non-local MAC-IP routes in the global routing table are linked to
1545 * the detination for efficient updates on -
1546 * a. VTEP add/del - this results in a L3NHG update.
1547 * b. ES-VRF add/del - this may result in the host route being migrated to
1548 * L3NHG or vice versa (flat multipath list).
1549 ****************************************************************************/
1550 static void bgp_evpn_path_es_info_free(struct bgp_path_es_info
*es_info
)
1552 bgp_evpn_path_es_unlink(es_info
);
1553 XFREE(MTYPE_BGP_EVPN_PATH_ES_INFO
, es_info
);
1556 void bgp_evpn_path_mh_info_free(struct bgp_path_mh_info
*mh_info
)
1558 if (mh_info
->es_info
)
1559 bgp_evpn_path_es_info_free(mh_info
->es_info
);
1560 if (mh_info
->nh_info
)
1561 bgp_evpn_path_nh_info_free(mh_info
->nh_info
);
1562 XFREE(MTYPE_BGP_EVPN_PATH_MH_INFO
, mh_info
);
1565 static struct bgp_path_es_info
*
1566 bgp_evpn_path_es_info_new(struct bgp_path_info
*pi
, vni_t vni
)
1568 struct bgp_path_info_extra
*e
;
1569 struct bgp_path_mh_info
*mh_info
;
1570 struct bgp_path_es_info
*es_info
;
1572 e
= bgp_path_info_extra_get(pi
);
1574 /* If mh_info doesn't exist allocate it */
1575 mh_info
= e
->mh_info
;
1577 e
->mh_info
= mh_info
= XCALLOC(MTYPE_BGP_EVPN_PATH_MH_INFO
,
1578 sizeof(struct bgp_path_mh_info
));
1580 /* If es_info doesn't exist allocate it */
1581 es_info
= mh_info
->es_info
;
1583 mh_info
->es_info
= es_info
=
1584 XCALLOC(MTYPE_BGP_EVPN_PATH_ES_INFO
,
1585 sizeof(struct bgp_path_es_info
));
1593 static void bgp_evpn_path_es_unlink(struct bgp_path_es_info
*es_info
)
1595 struct bgp_evpn_es
*es
= es_info
->es
;
1596 struct bgp_path_info
*pi
;
1602 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
1603 zlog_debug("vni %u path %pFX unlinked from es %s", es_info
->vni
,
1604 &pi
->net
->p
, es
->esi_str
);
1607 list_delete_node(es
->macip_evi_path_list
,
1608 &es_info
->es_listnode
);
1610 list_delete_node(es
->macip_global_path_list
,
1611 &es_info
->es_listnode
);
1615 /* if there are no other references against the ES it
1618 bgp_evpn_es_free(es
, __func__
);
1620 /* Note we don't free the path es_info on unlink; it will be freed up
1621 * along with the path.
1625 void bgp_evpn_path_es_link(struct bgp_path_info
*pi
, vni_t vni
, esi_t
*esi
)
1627 struct bgp_path_es_info
*es_info
;
1628 struct bgp_evpn_es
*es
;
1629 struct bgp
*bgp_evpn
;
1631 es_info
= (pi
->extra
&& pi
->extra
->mh_info
)
1632 ? pi
->extra
->mh_info
->es_info
1634 /* if the esi is zero just unlink the path from the old es */
1635 if (!esi
|| !memcmp(esi
, zero_esi
, sizeof(*esi
))) {
1637 bgp_evpn_path_es_unlink(es_info
);
1641 bgp_evpn
= bgp_get_evpn();
1645 /* setup es_info against the path if it doesn't aleady exist */
1647 es_info
= bgp_evpn_path_es_info_new(pi
, vni
);
1649 /* find-create ES */
1650 es
= bgp_evpn_es_find(esi
);
1652 es
= bgp_evpn_es_new(bgp_evpn
, esi
);
1655 if (es_info
->es
== es
)
1658 /* unlink old ES if any */
1659 bgp_evpn_path_es_unlink(es_info
);
1661 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
1662 zlog_debug("vni %u path %pFX linked to es %s", vni
, &pi
->net
->p
,
1665 /* link mac-ip path to the new destination ES */
1667 listnode_init(&es_info
->es_listnode
, es_info
);
1669 listnode_add(es
->macip_evi_path_list
, &es_info
->es_listnode
);
1671 listnode_add(es
->macip_global_path_list
, &es_info
->es_listnode
);
1674 static bool bgp_evpn_is_macip_path(struct bgp_path_info
*pi
)
1676 struct prefix_evpn
*evp
;
1678 /* Only MAC-IP routes need to be linked (MAC-only routes can be
1679 * skipped) as these lists are maintained for managing
1680 * host routes in the tenant VRF
1682 evp
= (struct prefix_evpn
*)&pi
->net
->p
;
1683 return is_evpn_prefix_ipaddr_v4(evp
) || is_evpn_prefix_ipaddr_v6(evp
);
1686 /* When a remote ES is added to a VRF, routes using that as
1687 * a destination need to be migrated to a L3NHG or viceversa.
1688 * This is done indirectly by re-attempting an install of the
1689 * route in the associated VRFs. As a part of the VRF install use
1690 * of l3 NHG is evaluated and this results in the
1691 * attr.es_flag ATTR_ES_USE_L3_NHG being set or cleared.
1694 bgp_evpn_es_path_update_on_es_vrf_chg(struct bgp_evpn_es_vrf
*es_vrf
,
1697 struct listnode
*node
;
1698 struct bgp_path_es_info
*es_info
;
1699 struct bgp_path_info
*pi
;
1700 struct bgp_evpn_es
*es
= es_vrf
->es
;
1702 if (!bgp_mh_info
->host_routes_use_l3nhg
)
1705 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
1706 zlog_debug("update paths linked to es %s on es-vrf %s %s",
1707 es
->esi_str
, es_vrf
->bgp_vrf
->name
, reason
);
1709 for (ALL_LIST_ELEMENTS_RO(es
->macip_global_path_list
, node
, es_info
)) {
1712 if (!bgp_evpn_is_macip_path(pi
))
1715 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
1717 "update path %pFX linked to es %s on vrf chg",
1718 &pi
->net
->p
, es
->esi_str
);
1719 bgp_evpn_route_entry_install_if_vrf_match(es_vrf
->bgp_vrf
, pi
,
1724 static void bgp_evpn_es_frag_free(struct bgp_evpn_es_frag
*es_frag
)
1726 struct bgp_evpn_es
*es
= es_frag
->es
;
1728 if (es
->es_base_frag
== es_frag
)
1729 es
->es_base_frag
= NULL
;
1731 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1732 zlog_debug("es %s frag %u free", es
->esi_str
, es_frag
->rd_id
);
1733 list_delete_node(es
->es_frag_list
, &es_frag
->es_listnode
);
1735 /* EVIs that are advertised using the info in this fragment */
1736 list_delete(&es_frag
->es_evi_frag_list
);
1738 bf_release_index(bm
->rd_idspace
, es_frag
->rd_id
);
1741 XFREE(MTYPE_BGP_EVPN_ES_FRAG
, es_frag
);
1744 static void bgp_evpn_es_frag_free_unused(struct bgp_evpn_es_frag
*es_frag
)
1746 if ((es_frag
->es
->es_base_frag
== es_frag
) ||
1747 listcount(es_frag
->es_evi_frag_list
))
1750 bgp_evpn_es_frag_free(es_frag
);
1753 static void bgp_evpn_es_frag_free_all(struct bgp_evpn_es
*es
)
1755 struct listnode
*node
;
1756 struct listnode
*nnode
;
1757 struct bgp_evpn_es_frag
*es_frag
;
1759 for (ALL_LIST_ELEMENTS(es
->es_frag_list
, node
, nnode
, es_frag
))
1760 bgp_evpn_es_frag_free(es_frag
);
1763 static struct bgp_evpn_es_frag
*bgp_evpn_es_frag_new(struct bgp_evpn_es
*es
)
1765 struct bgp_evpn_es_frag
*es_frag
;
1766 char buf
[BGP_EVPN_PREFIX_RD_LEN
];
1769 es_frag
= XCALLOC(MTYPE_BGP_EVPN_ES_FRAG
, sizeof(*es_frag
));
1770 bf_assign_index(bm
->rd_idspace
, es_frag
->rd_id
);
1771 es_frag
->prd
.family
= AF_UNSPEC
;
1772 es_frag
->prd
.prefixlen
= 64;
1773 bgp
= bgp_get_evpn();
1774 snprintfrr(buf
, sizeof(buf
), "%pI4:%hu", &bgp
->router_id
,
1776 (void)str2prefix_rd(buf
, &es_frag
->prd
);
1778 /* EVIs that are advertised using the info in this fragment */
1779 es_frag
->es_evi_frag_list
= list_new();
1780 listset_app_node_mem(es_frag
->es_evi_frag_list
);
1782 /* Link the fragment to the parent ES */
1784 listnode_init(&es_frag
->es_listnode
, es_frag
);
1785 listnode_add(es
->es_frag_list
, &es_frag
->es_listnode
);
1787 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1788 zlog_debug("es %s frag %u new", es
->esi_str
, es_frag
->rd_id
);
1792 static struct bgp_evpn_es_frag
*
1793 bgp_evpn_es_find_frag_with_space(struct bgp_evpn_es
*es
)
1795 struct listnode
*node
;
1796 struct bgp_evpn_es_frag
*es_frag
;
1798 for (ALL_LIST_ELEMENTS_RO(es
->es_frag_list
, node
, es_frag
)) {
1799 if (listcount(es_frag
->es_evi_frag_list
) <
1800 bgp_mh_info
->evi_per_es_frag
)
1804 /* No frags where found with space; allocate a new one */
1805 return bgp_evpn_es_frag_new(es
);
1808 /* Link the ES-EVI to one of the ES fragments */
1809 static void bgp_evpn_es_frag_evi_add(struct bgp_evpn_es_evi
*es_evi
)
1811 struct bgp_evpn_es_frag
*es_frag
;
1812 struct bgp_evpn_es
*es
= es_evi
->es
;
1814 if (es_evi
->es_frag
||
1815 !(CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
)))
1818 es_frag
= bgp_evpn_es_find_frag_with_space(es
);
1820 es_evi
->es_frag
= es_frag
;
1821 listnode_init(&es_evi
->es_frag_listnode
, es_evi
);
1822 listnode_add(es_frag
->es_evi_frag_list
, &es_evi
->es_frag_listnode
);
1824 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1825 zlog_debug("es %s vni %d linked to frag %u", es
->esi_str
,
1826 es_evi
->vpn
->vni
, es_frag
->rd_id
);
1829 /* UnLink the ES-EVI from the ES fragment */
1830 static void bgp_evpn_es_frag_evi_del(struct bgp_evpn_es_evi
*es_evi
,
1831 bool send_ead_del_if_empty
)
1833 struct bgp_evpn_es_frag
*es_frag
= es_evi
->es_frag
;
1834 struct prefix_evpn p
;
1835 struct bgp_evpn_es
*es
;
1842 es_evi
->es_frag
= NULL
;
1843 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1844 zlog_debug("es %s vni %d unlinked from frag %u", es
->esi_str
,
1845 es_evi
->vpn
->vni
, es_frag
->rd_id
);
1847 list_delete_node(es_frag
->es_evi_frag_list
, &es_evi
->es_frag_listnode
);
1850 * if there are no other EVIs on the fragment deleted the EAD-ES for
1853 if (send_ead_del_if_empty
&& !listcount(es_frag
->es_evi_frag_list
)) {
1854 bgp
= bgp_get_evpn();
1856 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1857 zlog_debug("es %s frag %u ead-es route delete",
1858 es
->esi_str
, es_frag
->rd_id
);
1859 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_ES_ETH_TAG
, &es
->esi
,
1861 p
.prefix
.ead_addr
.frag_id
= es_frag
->rd_id
;
1862 bgp_evpn_mh_route_delete(bgp
, es
, NULL
, es_frag
, &p
);
1865 /* We don't attempt to coalesce frags that may not be full. Instead we
1866 * only free up the frag when it is completely empty.
1868 bgp_evpn_es_frag_free_unused(es_frag
);
1871 /* Link the ES-EVIs to one of the ES fragments */
1872 static void bgp_evpn_es_frag_evi_update_all(struct bgp_evpn_es
*es
, bool add
)
1874 struct listnode
*node
;
1875 struct bgp_evpn_es_evi
*es_evi
;
1877 for (ALL_LIST_ELEMENTS_RO(es
->es_evi_list
, node
, es_evi
)) {
1879 bgp_evpn_es_frag_evi_add(es_evi
);
1881 bgp_evpn_es_frag_evi_del(es_evi
, false);
1885 /* compare ES-IDs for the global ES RB tree */
1886 static int bgp_es_rb_cmp(const struct bgp_evpn_es
*es1
,
1887 const struct bgp_evpn_es
*es2
)
1889 return memcmp(&es1
->esi
, &es2
->esi
, ESI_BYTES
);
1891 RB_GENERATE(bgp_es_rb_head
, bgp_evpn_es
, rb_node
, bgp_es_rb_cmp
);
1893 struct bgp_evpn_es
*bgp_evpn_es_find(const esi_t
*esi
)
1895 struct bgp_evpn_es tmp
;
1897 memcpy(&tmp
.esi
, esi
, sizeof(esi_t
));
1898 return RB_FIND(bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
, &tmp
);
1901 static struct bgp_evpn_es
*bgp_evpn_es_new(struct bgp
*bgp
, const esi_t
*esi
)
1903 struct bgp_evpn_es
*es
;
1908 es
= XCALLOC(MTYPE_BGP_EVPN_ES
, sizeof(struct bgp_evpn_es
));
1911 memcpy(&es
->esi
, esi
, sizeof(esi_t
));
1913 /* Initialise the VTEP list */
1914 es
->es_vtep_list
= list_new();
1915 listset_app_node_mem(es
->es_vtep_list
);
1916 es
->es_vtep_list
->cmp
= bgp_evpn_es_vtep_cmp
;
1918 esi_to_str(&es
->esi
, es
->esi_str
, sizeof(es
->esi_str
));
1920 /* Initialize the ES routing table */
1921 es
->route_table
= bgp_table_init(bgp
, AFI_L2VPN
, SAFI_EVPN
);
1923 /* Add to rb_tree */
1924 RB_INSERT(bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
, es
);
1926 /* Initialise the ES-EVI list */
1927 es
->es_evi_list
= list_new();
1928 listset_app_node_mem(es
->es_evi_list
);
1930 /* Initialise the ES-VRF list used for L3NHG management */
1931 es
->es_vrf_list
= list_new();
1932 listset_app_node_mem(es
->es_vrf_list
);
1934 /* Initialise the route list used for efficient event handling */
1935 es
->macip_evi_path_list
= list_new();
1936 listset_app_node_mem(es
->macip_evi_path_list
);
1937 es
->macip_global_path_list
= list_new();
1938 listset_app_node_mem(es
->macip_global_path_list
);
1939 es
->es_frag_list
= list_new();
1940 listset_app_node_mem(es
->es_frag_list
);
1942 QOBJ_REG(es
, bgp_evpn_es
);
1947 /* Free a given ES -
1948 * This just frees appropriate memory, caller should have taken other
1951 static void bgp_evpn_es_free(struct bgp_evpn_es
*es
, const char *caller
)
1953 if ((es
->flags
& (BGP_EVPNES_LOCAL
| BGP_EVPNES_REMOTE
))
1954 || listcount(es
->macip_evi_path_list
)
1955 || listcount(es
->macip_global_path_list
))
1958 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1959 zlog_debug("%s: es %s free", caller
, es
->esi_str
);
1961 /* cleanup resources maintained against the ES */
1962 list_delete(&es
->es_evi_list
);
1963 list_delete(&es
->es_vrf_list
);
1964 list_delete(&es
->es_vtep_list
);
1965 list_delete(&es
->macip_evi_path_list
);
1966 list_delete(&es
->macip_global_path_list
);
1967 list_delete(&es
->es_frag_list
);
1968 bgp_table_unlock(es
->route_table
);
1970 /* remove the entry from various databases */
1971 RB_REMOVE(bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
, es
);
1972 bgp_evpn_es_cons_checks_pend_del(es
);
1975 XFREE(MTYPE_BGP_EVPN_ES
, es
);
1978 static inline bool bgp_evpn_is_es_local_and_non_bypass(struct bgp_evpn_es
*es
)
1980 return (es
->flags
& BGP_EVPNES_LOCAL
)
1981 && !(es
->flags
& BGP_EVPNES_BYPASS
);
1984 /* init local info associated with the ES */
1985 static void bgp_evpn_es_local_info_set(struct bgp
*bgp
, struct bgp_evpn_es
*es
)
1990 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_LOCAL
))
1993 old_is_local
= bgp_evpn_is_es_local_and_non_bypass(es
);
1994 SET_FLAG(es
->flags
, BGP_EVPNES_LOCAL
);
1996 listnode_init(&es
->es_listnode
, es
);
1997 listnode_add(bgp_mh_info
->local_es_list
, &es
->es_listnode
);
1999 /* setup the first ES fragment; more fragments may be allocated based
2000 * on the the number of EVI entries
2002 es
->es_base_frag
= bgp_evpn_es_frag_new(es
);
2003 /* distribute ES-EVIs to one or more ES fragments */
2004 bgp_evpn_es_frag_evi_update_all(es
, true);
2006 is_local
= bgp_evpn_is_es_local_and_non_bypass(es
);
2007 if (old_is_local
!= is_local
)
2008 bgp_evpn_mac_update_on_es_local_chg(es
, is_local
);
2011 /* clear any local info associated with the ES */
2012 static void bgp_evpn_es_local_info_clear(struct bgp_evpn_es
*es
, bool finish
)
2017 if (!CHECK_FLAG(es
->flags
, BGP_EVPNES_LOCAL
))
2020 /* clear the es frag references and free them up */
2021 bgp_evpn_es_frag_evi_update_all(es
, false);
2022 es
->es_base_frag
= NULL
;
2023 bgp_evpn_es_frag_free_all(es
);
2025 old_is_local
= bgp_evpn_is_es_local_and_non_bypass(es
);
2026 UNSET_FLAG(es
->flags
, BGP_EVPNES_LOCAL
);
2028 is_local
= bgp_evpn_is_es_local_and_non_bypass(es
);
2029 if (!finish
&& (old_is_local
!= is_local
))
2030 bgp_evpn_mac_update_on_es_local_chg(es
, is_local
);
2032 /* remove from the ES local list */
2033 list_delete_node(bgp_mh_info
->local_es_list
, &es
->es_listnode
);
2035 bgp_evpn_es_free(es
, __func__
);
2038 /* eval remote info associated with the ES */
2039 static void bgp_evpn_es_remote_info_re_eval(struct bgp_evpn_es
*es
)
2041 if (es
->remote_es_evi_cnt
) {
2042 SET_FLAG(es
->flags
, BGP_EVPNES_REMOTE
);
2044 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_REMOTE
)) {
2045 UNSET_FLAG(es
->flags
, BGP_EVPNES_REMOTE
);
2046 bgp_evpn_es_free(es
, __func__
);
2051 /* If ES is present and local it needs to be active/oper-up for
2054 bool bgp_evpn_es_add_l3_ecomm_ok(esi_t
*esi
)
2056 struct bgp_evpn_es
*es
;
2058 if (!esi
|| !bgp_mh_info
->suppress_l3_ecomm_on_inactive_es
)
2061 es
= bgp_evpn_es_find(esi
);
2063 return (!es
|| !(es
->flags
& BGP_EVPNES_LOCAL
)
2064 || bgp_evpn_local_es_is_active(es
));
2067 static bool bgp_evpn_is_valid_local_path(struct bgp_path_info
*pi
)
2069 return (CHECK_FLAG(pi
->flags
, BGP_PATH_VALID
)
2070 && pi
->type
== ZEBRA_ROUTE_BGP
2071 && pi
->sub_type
== BGP_ROUTE_STATIC
);
2074 /* Update all local MAC-IP routes in the VNI routing table associated
2075 * with the ES. When the ES is down the routes are advertised without
2078 static void bgp_evpn_mac_update_on_es_oper_chg(struct bgp_evpn_es
*es
)
2080 struct listnode
*node
;
2081 struct bgp_path_es_info
*es_info
;
2082 struct bgp_path_info
*pi
;
2084 struct bgpevpn
*vpn
;
2086 if (!bgp_mh_info
->suppress_l3_ecomm_on_inactive_es
)
2089 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2090 zlog_debug("update paths linked to es %s on oper chg",
2093 bgp
= bgp_get_evpn();
2094 for (ALL_LIST_ELEMENTS_RO(es
->macip_evi_path_list
, node
, es_info
)) {
2097 if (!bgp_evpn_is_valid_local_path(pi
))
2100 if (!bgp_evpn_is_macip_path(pi
))
2103 vpn
= bgp_evpn_lookup_vni(bgp
, es_info
->vni
);
2107 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
2109 "update path %d %pFX linked to es %s on oper chg",
2110 es_info
->vni
, &pi
->net
->p
, es
->esi_str
);
2112 bgp_evpn_update_type2_route_entry(bgp
, vpn
, pi
->net
, pi
,
2117 static bool bgp_evpn_is_valid_bgp_path(struct bgp_path_info
*pi
)
2119 return (CHECK_FLAG(pi
->flags
, BGP_PATH_VALID
)
2120 && pi
->type
== ZEBRA_ROUTE_BGP
2121 && pi
->sub_type
== BGP_ROUTE_NORMAL
);
2124 /* If an ES is no longer local (or becomes local) we need to re-install
2125 * paths using that ES as destination. This is needed as the criteria
2126 * for best path selection has changed.
2128 static void bgp_evpn_mac_update_on_es_local_chg(struct bgp_evpn_es
*es
,
2131 struct listnode
*node
;
2132 struct bgp_path_es_info
*es_info
;
2133 struct bgp_path_info
*pi
;
2135 struct attr
*attr_new
;
2136 struct attr attr_tmp
;
2138 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2139 zlog_debug("update paths linked to es %s on chg to %s",
2140 es
->esi_str
, is_local
? "local" : "non-local");
2142 for (ALL_LIST_ELEMENTS_RO(es
->macip_global_path_list
, node
, es_info
)) {
2145 /* Consider "valid" remote routes */
2146 if (!bgp_evpn_is_valid_bgp_path(pi
))
2152 tmp_local
= !!(pi
->attr
->es_flags
& ATTR_ES_IS_LOCAL
);
2153 if (tmp_local
== is_local
)
2156 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
2158 "update path %pFX linked to es %s on chg to %s",
2159 &pi
->net
->p
, es
->esi_str
,
2160 is_local
? "local" : "non-local");
2162 attr_tmp
= *pi
->attr
;
2164 attr_tmp
.es_flags
|= ATTR_ES_IS_LOCAL
;
2166 attr_tmp
.es_flags
&= ~ATTR_ES_IS_LOCAL
;
2167 attr_new
= bgp_attr_intern(&attr_tmp
);
2168 bgp_attr_unintern(&pi
->attr
);
2169 pi
->attr
= attr_new
;
2170 bgp_evpn_import_type2_route(pi
, 1);
2174 static void bgp_evpn_local_es_deactivate(struct bgp
*bgp
,
2175 struct bgp_evpn_es
*es
)
2177 struct prefix_evpn p
;
2181 /* Delete and withdraw locally learnt ES route */
2182 build_evpn_type4_prefix(&p
, &es
->esi
, es
->originator_ip
);
2183 ret
= bgp_evpn_type4_route_delete(bgp
, es
, &p
);
2185 flog_err(EC_BGP_EVPN_ROUTE_DELETE
,
2186 "%u failed to delete type-4 route for ESI %s",
2187 bgp
->vrf_id
, es
->esi_str
);
2190 /* withdraw EAD-EVI */
2191 if (!bgp_mh_info
->ead_evi_adv_for_down_links
)
2192 bgp_evpn_local_type1_evi_route_del(bgp
, es
);
2194 /* withdraw EAD-ES */
2195 bgp_evpn_ead_es_route_delete(bgp
, es
);
2197 bgp_evpn_mac_update_on_es_oper_chg(es
);
2200 /* Process ES link oper-down by withdrawing ES-EAD and ESR */
2201 static void bgp_evpn_local_es_down(struct bgp
*bgp
, struct bgp_evpn_es
*es
)
2205 if (!CHECK_FLAG(es
->flags
, BGP_EVPNES_OPER_UP
))
2208 old_active
= bgp_evpn_local_es_is_active(es
);
2209 UNSET_FLAG(es
->flags
, BGP_EVPNES_OPER_UP
);
2211 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2212 zlog_debug("local es %s down", es
->esi_str
);
2215 bgp_evpn_local_es_deactivate(bgp
, es
);
2218 static void bgp_evpn_local_es_activate(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
2219 bool regen_ead
, bool regen_esr
)
2221 struct prefix_evpn p
;
2224 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2225 zlog_debug("local es %s generate ESR", es
->esi_str
);
2227 build_evpn_type4_prefix(&p
, &es
->esi
, es
->originator_ip
);
2228 if (bgp_evpn_type4_route_update(bgp
, es
, &p
))
2229 flog_err(EC_BGP_EVPN_ROUTE_CREATE
,
2230 "%u: Type4 route creation failure for ESI %s",
2231 bgp
->vrf_id
, es
->esi_str
);
2235 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2236 zlog_debug("local es %s generate EAD", es
->esi_str
);
2237 /* generate EAD-EVI */
2238 bgp_evpn_local_type1_evi_route_add(bgp
, es
);
2240 /* generate EAD-ES */
2241 bgp_evpn_ead_es_route_update(bgp
, es
);
2244 bgp_evpn_mac_update_on_es_oper_chg(es
);
2247 /* Process ES link oper-up by generating ES-EAD and ESR */
2248 static void bgp_evpn_local_es_up(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
2251 bool regen_ead
= false;
2252 bool active
= false;
2254 if (!CHECK_FLAG(es
->flags
, BGP_EVPNES_OPER_UP
)) {
2255 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2256 zlog_debug("local es %s up", es
->esi_str
);
2258 SET_FLAG(es
->flags
, BGP_EVPNES_OPER_UP
);
2263 active
= bgp_evpn_local_es_is_active(es
);
2264 if (active
&& (regen_ead
|| regen_esr
))
2265 bgp_evpn_local_es_activate(bgp
, es
, regen_ead
, regen_esr
);
2268 /* If an ethernet segment is in LACP bypass we cannot advertise
2269 * reachability to it i.e. EAD-per-ES and ESR is not advertised in
2271 * PS: EAD-per-EVI will continue to be advertised
2273 static void bgp_evpn_local_es_bypass_update(struct bgp
*bgp
,
2274 struct bgp_evpn_es
*es
, bool bypass
)
2276 bool old_bypass
= !!(es
->flags
& BGP_EVPNES_BYPASS
);
2282 if (bypass
== old_bypass
)
2285 old_active
= bgp_evpn_local_es_is_active(es
);
2286 old_is_local
= bgp_evpn_is_es_local_and_non_bypass(es
);
2288 SET_FLAG(es
->flags
, BGP_EVPNES_BYPASS
);
2290 UNSET_FLAG(es
->flags
, BGP_EVPNES_BYPASS
);
2292 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2293 zlog_debug("local es %s bypass %s", es
->esi_str
,
2294 bypass
? "set" : "clear");
2296 new_active
= bgp_evpn_local_es_is_active(es
);
2297 if (old_active
!= new_active
) {
2299 bgp_evpn_local_es_activate(bgp
, es
, true, true);
2301 bgp_evpn_local_es_deactivate(bgp
, es
);
2304 is_local
= bgp_evpn_is_es_local_and_non_bypass(es
);
2305 if (old_is_local
!= is_local
)
2306 bgp_evpn_mac_update_on_es_local_chg(es
, is_local
);
2309 static void bgp_evpn_local_es_do_del(struct bgp
*bgp
, struct bgp_evpn_es
*es
)
2311 struct bgp_evpn_es_evi
*es_evi
;
2312 struct listnode
*evi_node
, *evi_next_node
;
2314 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2315 zlog_debug("del local es %s", es
->esi_str
);
2317 /* Delete all local EVPN ES routes from ESI table
2318 * and schedule for processing (to withdraw from peers))
2320 bgp_evpn_es_route_del_all(bgp
, es
);
2322 /* release all local ES EVIs associated with the ES */
2323 for (ALL_LIST_ELEMENTS(es
->es_evi_list
, evi_node
,
2324 evi_next_node
, es_evi
)) {
2325 bgp_evpn_local_es_evi_do_del(es_evi
);
2328 /* Clear local info associated with the ES and free it up if there is
2329 * no remote reference
2331 bgp_evpn_es_local_info_clear(es
, false);
2334 bool bgp_evpn_is_esi_local_and_non_bypass(esi_t
*esi
)
2336 struct bgp_evpn_es
*es
= NULL
;
2338 /* Lookup ESI hash - should exist. */
2339 es
= bgp_evpn_es_find(esi
);
2341 return es
&& bgp_evpn_is_es_local_and_non_bypass(es
);
2344 int bgp_evpn_local_es_del(struct bgp
*bgp
, esi_t
*esi
)
2346 struct bgp_evpn_es
*es
= NULL
;
2348 /* Lookup ESI hash - should exist. */
2349 es
= bgp_evpn_es_find(esi
);
2351 flog_warn(EC_BGP_EVPN_ESI
, "%u: ES missing at local ES DEL",
2356 bgp_evpn_local_es_do_del(bgp
, es
);
2360 /* Handle device to ES id association. Results in the creation of a local
2363 int bgp_evpn_local_es_add(struct bgp
*bgp
, esi_t
*esi
,
2364 struct in_addr originator_ip
, bool oper_up
,
2365 uint16_t df_pref
, bool bypass
)
2367 char buf
[ESI_STR_LEN
];
2368 struct bgp_evpn_es
*es
;
2370 bool regen_esr
= false;
2372 /* create the new es */
2373 es
= bgp_evpn_es_find(esi
);
2375 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_LOCAL
))
2378 es
= bgp_evpn_es_new(bgp
, esi
);
2380 flog_err(EC_BGP_ES_CREATE
,
2381 "%u: Failed to allocate ES entry for ESI %s - at Local ES Add",
2382 bgp
->vrf_id
, esi_to_str(esi
, buf
, sizeof(buf
)));
2387 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2388 zlog_debug("add local es %s orig-ip %pI4 df_pref %u %s",
2389 es
->esi_str
, &originator_ip
, df_pref
,
2390 bypass
? "bypass" : "");
2392 es
->originator_ip
= originator_ip
;
2393 if (df_pref
!= es
->df_pref
) {
2394 es
->df_pref
= df_pref
;
2397 bgp_evpn_es_local_info_set(bgp
, es
);
2399 /* import all remote Type-4 routes in the ES table */
2401 bgp_evpn_type4_remote_routes_import(bgp
, es
,
2402 true /* install */);
2404 /* create and advertise EAD-EVI routes for the ES -
2405 * XXX - till an ES-EVI reference is created there is really nothing to
2408 if (bgp_mh_info
->ead_evi_adv_for_down_links
)
2409 bgp_evpn_local_type1_evi_route_add(bgp
, es
);
2411 bgp_evpn_local_es_bypass_update(bgp
, es
, bypass
);
2413 /* If the ES link is operationally up generate EAD-ES. EAD-EVI
2414 * can be generated even if the link is inactive.
2417 bgp_evpn_local_es_up(bgp
, es
, regen_esr
);
2419 bgp_evpn_local_es_down(bgp
, es
);
2424 static void bgp_evpn_es_json_frag_fill(json_object
*json_frags
,
2425 struct bgp_evpn_es
*es
)
2427 json_object
*json_frag
;
2428 char buf1
[RD_ADDRSTRLEN
];
2429 struct listnode
*node
;
2430 struct bgp_evpn_es_frag
*es_frag
;
2432 for (ALL_LIST_ELEMENTS_RO(es
->es_frag_list
, node
, es_frag
)) {
2433 json_frag
= json_object_new_object();
2435 json_object_string_add(
2437 prefix_rd2str(&es_frag
->prd
, buf1
, sizeof(buf1
)));
2438 json_object_int_add(json_frag
, "eviCount",
2439 listcount(es_frag
->es_evi_frag_list
));
2441 json_object_array_add(json_frags
, json_frag
);
2445 static void bgp_evpn_es_frag_show_detail(struct vty
*vty
,
2446 struct bgp_evpn_es
*es
)
2448 struct listnode
*node
;
2449 char buf1
[RD_ADDRSTRLEN
];
2450 struct bgp_evpn_es_frag
*es_frag
;
2452 for (ALL_LIST_ELEMENTS_RO(es
->es_frag_list
, node
, es_frag
)) {
2453 vty_out(vty
, " %s EVIs: %d\n",
2454 prefix_rd2str(&es_frag
->prd
, buf1
, sizeof(buf1
)),
2455 listcount(es_frag
->es_evi_frag_list
));
2459 static char *bgp_evpn_es_vteps_str(char *vtep_str
, struct bgp_evpn_es
*es
,
2460 uint8_t vtep_str_size
)
2462 char vtep_flag_str
[BGP_EVPN_FLAG_STR_SZ
];
2463 struct listnode
*node
;
2464 struct bgp_evpn_es_vtep
*es_vtep
;
2466 char ip_buf
[INET6_ADDRSTRLEN
];
2469 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
2470 vtep_flag_str
[0] = '\0';
2472 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ESR
)
2473 strlcat(vtep_flag_str
, "E", sizeof(vtep_flag_str
));
2474 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ACTIVE
)
2475 strlcat(vtep_flag_str
, "A", sizeof(vtep_flag_str
));
2477 if (!strlen(vtep_flag_str
))
2478 strlcat(vtep_flag_str
, "-", sizeof(vtep_flag_str
));
2482 strlcat(vtep_str
, ",", vtep_str_size
);
2484 inet_ntop(AF_INET
, &es_vtep
->vtep_ip
, ip_buf
,
2487 strlcat(vtep_str
, "(", vtep_str_size
);
2488 strlcat(vtep_str
, vtep_flag_str
, vtep_str_size
);
2489 strlcat(vtep_str
, ")", vtep_str_size
);
2495 static void bgp_evpn_es_json_vtep_fill(json_object
*json_vteps
,
2496 struct bgp_evpn_es_vtep
*es_vtep
)
2498 json_object
*json_vtep_entry
;
2499 json_object
*json_flags
;
2501 json_vtep_entry
= json_object_new_object();
2503 json_object_string_addf(json_vtep_entry
, "vtep_ip", "%pI4",
2505 if (es_vtep
->flags
& (BGP_EVPNES_VTEP_ESR
|
2506 BGP_EVPNES_VTEP_ACTIVE
)) {
2507 json_flags
= json_object_new_array();
2508 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ESR
)
2509 json_array_string_add(json_flags
, "esr");
2510 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ACTIVE
)
2511 json_array_string_add(json_flags
, "active");
2512 json_object_object_add(json_vtep_entry
, "flags", json_flags
);
2513 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ESR
) {
2514 json_object_int_add(json_vtep_entry
, "dfPreference",
2516 json_object_int_add(json_vtep_entry
, "dfAlgorithm",
2521 json_object_array_add(json_vteps
,
2525 static void bgp_evpn_es_vteps_show_detail(struct vty
*vty
,
2526 struct bgp_evpn_es
*es
)
2528 char vtep_flag_str
[BGP_EVPN_FLAG_STR_SZ
];
2529 struct listnode
*node
;
2530 struct bgp_evpn_es_vtep
*es_vtep
;
2531 char alg_buf
[EVPN_DF_ALG_STR_LEN
];
2533 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
2534 vtep_flag_str
[0] = '\0';
2535 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ESR
)
2536 strlcat(vtep_flag_str
, "E", sizeof(vtep_flag_str
));
2537 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ACTIVE
)
2538 strlcat(vtep_flag_str
, "A", sizeof(vtep_flag_str
));
2540 if (!strlen(vtep_flag_str
))
2541 strlcat(vtep_flag_str
, "-", sizeof(vtep_flag_str
));
2543 vty_out(vty
, " %pI4 flags: %s", &es_vtep
->vtep_ip
,
2546 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ESR
)
2547 vty_out(vty
, " df_alg: %s df_pref: %u\n",
2548 evpn_es_df_alg2str(es_vtep
->df_alg
, alg_buf
,
2556 static void bgp_evpn_es_show_entry(struct vty
*vty
,
2557 struct bgp_evpn_es
*es
, json_object
*json
)
2559 char buf1
[RD_ADDRSTRLEN
];
2560 struct listnode
*node
;
2561 struct bgp_evpn_es_vtep
*es_vtep
;
2564 json_object
*json_vteps
;
2565 json_object
*json_types
;
2567 json_object_string_add(json
, "esi", es
->esi_str
);
2568 if (es
->es_base_frag
)
2569 json_object_string_add(
2571 prefix_rd2str(&es
->es_base_frag
->prd
, buf1
,
2574 if (es
->flags
& (BGP_EVPNES_LOCAL
| BGP_EVPNES_REMOTE
)) {
2575 json_types
= json_object_new_array();
2576 if (es
->flags
& BGP_EVPNES_LOCAL
)
2577 json_array_string_add(json_types
, "local");
2578 if (es
->flags
& BGP_EVPNES_REMOTE
)
2579 json_array_string_add(json_types
, "remote");
2580 json_object_object_add(json
, "type", json_types
);
2583 if (listcount(es
->es_vtep_list
)) {
2584 json_vteps
= json_object_new_array();
2585 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
,
2587 bgp_evpn_es_json_vtep_fill(json_vteps
, es_vtep
);
2589 json_object_object_add(json
, "vteps", json_vteps
);
2591 json_object_int_add(json
, "vniCount",
2592 listcount(es
->es_evi_list
));
2595 char vtep_str
[ES_VTEP_LIST_STR_SZ
+ BGP_EVPN_VTEPS_FLAG_STR_SZ
];
2598 if (es
->flags
& BGP_EVPNES_BYPASS
)
2599 strlcat(type_str
, "B", sizeof(type_str
));
2600 if (es
->flags
& BGP_EVPNES_LOCAL
)
2601 strlcat(type_str
, "L", sizeof(type_str
));
2602 if (es
->flags
& BGP_EVPNES_REMOTE
)
2603 strlcat(type_str
, "R", sizeof(type_str
));
2604 if (es
->inconsistencies
)
2605 strlcat(type_str
, "I", sizeof(type_str
));
2607 bgp_evpn_es_vteps_str(vtep_str
, es
, sizeof(vtep_str
));
2609 if (es
->es_base_frag
)
2610 prefix_rd2str(&es
->es_base_frag
->prd
, buf1
,
2613 strlcpy(buf1
, "-", sizeof(buf1
));
2615 vty_out(vty
, "%-30s %-5s %-21s %-8d %s\n",
2616 es
->esi_str
, type_str
, buf1
,
2617 listcount(es
->es_evi_list
), vtep_str
);
2621 static void bgp_evpn_es_show_entry_detail(struct vty
*vty
,
2622 struct bgp_evpn_es
*es
, json_object
*json
)
2625 json_object
*json_flags
;
2626 json_object
*json_incons
;
2627 json_object
*json_vteps
;
2628 json_object
*json_frags
;
2629 struct listnode
*node
;
2630 struct bgp_evpn_es_vtep
*es_vtep
;
2632 /* Add the "brief" info first */
2633 bgp_evpn_es_show_entry(vty
, es
, json
);
2635 & (BGP_EVPNES_OPER_UP
| BGP_EVPNES_ADV_EVI
2636 | BGP_EVPNES_BYPASS
)) {
2637 json_flags
= json_object_new_array();
2638 if (es
->flags
& BGP_EVPNES_OPER_UP
)
2639 json_array_string_add(json_flags
, "up");
2640 if (es
->flags
& BGP_EVPNES_ADV_EVI
)
2641 json_array_string_add(json_flags
,
2643 if (es
->flags
& BGP_EVPNES_BYPASS
)
2644 json_array_string_add(json_flags
, "bypass");
2645 json_object_object_add(json
, "flags", json_flags
);
2647 json_object_string_addf(json
, "originator_ip", "%pI4",
2648 &es
->originator_ip
);
2649 json_object_int_add(json
, "remoteVniCount",
2650 es
->remote_es_evi_cnt
);
2651 json_object_int_add(json
, "vrfCount",
2652 listcount(es
->es_vrf_list
));
2653 json_object_int_add(json
, "macipPathCount",
2654 listcount(es
->macip_evi_path_list
));
2655 json_object_int_add(json
, "macipGlobalPathCount",
2656 listcount(es
->macip_global_path_list
));
2657 json_object_int_add(json
, "inconsistentVniVtepCount",
2658 es
->incons_evi_vtep_cnt
);
2659 if (listcount(es
->es_vtep_list
)) {
2660 json_vteps
= json_object_new_array();
2661 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
,
2663 bgp_evpn_es_json_vtep_fill(json_vteps
, es_vtep
);
2665 json_object_object_add(json
, "vteps", json_vteps
);
2667 if (listcount(es
->es_frag_list
)) {
2668 json_frags
= json_object_new_array();
2669 bgp_evpn_es_json_frag_fill(json_frags
, es
);
2670 json_object_object_add(json
, "fragments", json_frags
);
2672 if (es
->inconsistencies
) {
2673 json_incons
= json_object_new_array();
2674 if (es
->inconsistencies
& BGP_EVPNES_INCONS_VTEP_LIST
)
2675 json_array_string_add(json_incons
,
2676 "vni-vtep-mismatch");
2677 json_object_object_add(json
, "inconsistencies",
2681 char incons_str
[BGP_EVPNES_INCONS_STR_SZ
];
2683 char buf1
[RD_ADDRSTRLEN
];
2686 if (es
->flags
& BGP_EVPNES_LOCAL
)
2687 strlcat(type_str
, "L", sizeof(type_str
));
2688 if (es
->flags
& BGP_EVPNES_REMOTE
)
2689 strlcat(type_str
, "R", sizeof(type_str
));
2691 if (es
->es_base_frag
)
2692 prefix_rd2str(&es
->es_base_frag
->prd
, buf1
,
2695 strlcpy(buf1
, "-", sizeof(buf1
));
2697 vty_out(vty
, "ESI: %s\n", es
->esi_str
);
2698 vty_out(vty
, " Type: %s\n", type_str
);
2699 vty_out(vty
, " RD: %s\n", buf1
);
2700 vty_out(vty
, " Originator-IP: %pI4\n", &es
->originator_ip
);
2701 if (es
->flags
& BGP_EVPNES_LOCAL
)
2702 vty_out(vty
, " Local ES DF preference: %u\n",
2704 if (es
->flags
& BGP_EVPNES_BYPASS
)
2705 vty_out(vty
, " LACP bypass: on\n");
2706 vty_out(vty
, " VNI Count: %d\n", listcount(es
->es_evi_list
));
2707 vty_out(vty
, " Remote VNI Count: %d\n",
2708 es
->remote_es_evi_cnt
);
2709 vty_out(vty
, " VRF Count: %d\n", listcount(es
->es_vrf_list
));
2710 vty_out(vty
, " MACIP EVI Path Count: %d\n",
2711 listcount(es
->macip_evi_path_list
));
2712 vty_out(vty
, " MACIP Global Path Count: %d\n",
2713 listcount(es
->macip_global_path_list
));
2714 vty_out(vty
, " Inconsistent VNI VTEP Count: %d\n",
2715 es
->incons_evi_vtep_cnt
);
2716 if (es
->inconsistencies
) {
2717 incons_str
[0] = '\0';
2718 if (es
->inconsistencies
& BGP_EVPNES_INCONS_VTEP_LIST
)
2719 strlcat(incons_str
, "vni-vtep-mismatch",
2720 sizeof(incons_str
));
2722 strlcpy(incons_str
, "-", sizeof(incons_str
));
2724 vty_out(vty
, " Inconsistencies: %s\n",
2726 if (listcount(es
->es_frag_list
)) {
2727 vty_out(vty
, " Fragments:\n");
2728 bgp_evpn_es_frag_show_detail(vty
, es
);
2730 if (listcount(es
->es_vtep_list
)) {
2731 vty_out(vty
, " VTEPs:\n");
2732 bgp_evpn_es_vteps_show_detail(vty
, es
);
2738 /* Display all ESs */
2739 void bgp_evpn_es_show(struct vty
*vty
, bool uj
, bool detail
)
2741 struct bgp_evpn_es
*es
;
2742 json_object
*json_array
= NULL
;
2743 json_object
*json
= NULL
;
2746 /* create an array of ESs */
2747 json_array
= json_object_new_array();
2751 "ES Flags: B - bypass, L local, R remote, I inconsistent\n");
2753 "VTEP Flags: E ESR/Type-4, A active nexthop\n");
2755 "%-30s %-5s %-21s %-8s %s\n",
2756 "ESI", "Flags", "RD", "#VNIs", "VTEPs");
2760 RB_FOREACH(es
, bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
) {
2762 /* create a separate json object for each ES */
2763 json
= json_object_new_object();
2765 bgp_evpn_es_show_entry_detail(vty
, es
, json
);
2767 bgp_evpn_es_show_entry(vty
, es
, json
);
2768 /* add ES to the json array */
2770 json_object_array_add(json_array
, json
);
2773 /* print the array of json-ESs */
2775 vty_json(vty
, json_array
);
2778 /* Display specific ES */
2779 void bgp_evpn_es_show_esi(struct vty
*vty
, esi_t
*esi
, bool uj
)
2781 struct bgp_evpn_es
*es
;
2782 json_object
*json
= NULL
;
2785 json
= json_object_new_object();
2787 es
= bgp_evpn_es_find(esi
);
2789 bgp_evpn_es_show_entry_detail(vty
, es
, json
);
2792 vty_out(vty
, "ESI not found\n");
2796 vty_json(vty
, json
);
2799 /*****************************************************************************/
2800 /* Ethernet Segment to VRF association -
2801 * 1. Each ES-EVI entry is associated with a tenant VRF. This associaton
2802 * triggers the creation of an ES-VRF entry.
2803 * 2. The ES-VRF entry is maintained for the purpose of L3-NHG creation
2804 * 3. Type-2/MAC-IP routes are imported into a tenant VRF and programmed as
2805 * a /32 or host route entry in the dataplane. If the destination of
2806 * the host route is a remote-ES the route is programmed with the
2807 * corresponding (keyed in by {vrf,ES-id}) L3-NHG.
2808 * 4. The reason for this indirection (route->L3-NHG, L3-NHG->list-of-VTEPs)
2809 * is to avoid route updates to the dplane when a remote-ES link flaps i.e.
2810 * instead of updating all the dependent routes the NHG's contents are updated.
2811 * This reduces the amount of datplane updates (nhg updates vs. route updates)
2812 * allowing for a faster failover.
2814 * XXX - can the L3 SVI index change without change in vpn->bgp_vrf
2815 * association? If yes we need to handle that by updating all the L3 NHGs
2818 /******************************** L3 NHG management *************************/
2819 static void bgp_evpn_l3nhg_zebra_add_v4_or_v6(struct bgp_evpn_es_vrf
*es_vrf
,
2822 uint32_t nhg_id
= v4_nhg
? es_vrf
->nhg_id
: es_vrf
->v6_nhg_id
;
2823 struct bgp_evpn_es
*es
= es_vrf
->es
;
2824 struct listnode
*node
;
2825 struct bgp_evpn_es_vtep
*es_vtep
;
2827 struct zapi_nexthop
*api_nh
;
2828 struct zapi_nhg api_nhg
= {};
2830 /* Skip installation of L3-NHG if host routes used */
2834 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2835 zlog_debug("es %s vrf %u %s nhg %u to zebra", es
->esi_str
,
2836 es_vrf
->bgp_vrf
->vrf_id
,
2837 v4_nhg
? "v4_nhg" : "v6_nhg", nhg_id
);
2839 frrtrace(4, frr_bgp
, evpn_mh_nhg_zsend
, true, v4_nhg
, nhg_id
, es_vrf
);
2841 /* only the gateway ip changes for each NH. rest of the params
2844 memset(&nh
, 0, sizeof(nh
));
2845 nh
.vrf_id
= es_vrf
->bgp_vrf
->vrf_id
;
2846 nh
.flags
= NEXTHOP_FLAG_ONLINK
;
2847 nh
.ifindex
= es_vrf
->bgp_vrf
->l3vni_svi_ifindex
;
2850 v4_nhg
? NEXTHOP_TYPE_IPV4_IFINDEX
: NEXTHOP_TYPE_IPV6_IFINDEX
;
2852 api_nhg
.id
= nhg_id
;
2853 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
2854 if (!CHECK_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
))
2857 /* Don't overrun the zapi buffer. */
2858 if (api_nhg
.nexthop_num
== MULTIPATH_NUM
)
2861 /* overwrite the gw */
2863 nh
.gate
.ipv4
= es_vtep
->vtep_ip
;
2865 ipv4_to_ipv4_mapped_ipv6(&nh
.gate
.ipv6
,
2868 /* convert to zapi format */
2869 api_nh
= &api_nhg
.nexthops
[api_nhg
.nexthop_num
];
2870 zapi_nexthop_from_nexthop(api_nh
, &nh
);
2872 ++api_nhg
.nexthop_num
;
2873 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2874 zlog_debug("nhg %u vtep %pI4 l3-svi %d", api_nhg
.id
,
2876 es_vrf
->bgp_vrf
->l3vni_svi_ifindex
);
2878 frrtrace(3, frr_bgp
, evpn_mh_nh_zsend
, nhg_id
, es_vtep
, es_vrf
);
2881 if (!api_nhg
.nexthop_num
)
2884 zclient_nhg_send(zclient
, ZEBRA_NHG_ADD
, &api_nhg
);
2887 static bool bgp_evpn_l3nhg_zebra_ok(struct bgp_evpn_es_vrf
*es_vrf
)
2889 if (!bgp_mh_info
->host_routes_use_l3nhg
&& !bgp_mh_info
->install_l3nhg
)
2893 if (!zclient
|| zclient
->sock
< 0)
2899 static void bgp_evpn_l3nhg_zebra_add(struct bgp_evpn_es_vrf
*es_vrf
)
2901 if (!bgp_evpn_l3nhg_zebra_ok(es_vrf
))
2904 bgp_evpn_l3nhg_zebra_add_v4_or_v6(es_vrf
, true /*v4_nhg*/);
2905 bgp_evpn_l3nhg_zebra_add_v4_or_v6(es_vrf
, false /*v4_nhg*/);
2908 static void bgp_evpn_l3nhg_zebra_del_v4_or_v6(struct bgp_evpn_es_vrf
*es_vrf
,
2911 struct zapi_nhg api_nhg
= {};
2913 api_nhg
.id
= v4_nhg
? es_vrf
->nhg_id
: es_vrf
->v6_nhg_id
;
2915 /* Skip installation of L3-NHG if host routes used */
2919 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2920 zlog_debug("es %s vrf %u %s nhg %u to zebra",
2921 es_vrf
->es
->esi_str
, es_vrf
->bgp_vrf
->vrf_id
,
2922 v4_nhg
? "v4_nhg" : "v6_nhg", api_nhg
.id
);
2925 frrtrace(4, frr_bgp
, evpn_mh_nhg_zsend
, false, v4_nhg
, api_nhg
.id
,
2928 zclient_nhg_send(zclient
, ZEBRA_NHG_DEL
, &api_nhg
);
2931 static void bgp_evpn_l3nhg_zebra_del(struct bgp_evpn_es_vrf
*es_vrf
)
2933 if (!bgp_evpn_l3nhg_zebra_ok(es_vrf
))
2936 bgp_evpn_l3nhg_zebra_del_v4_or_v6(es_vrf
, true /*v4_nhg*/);
2937 bgp_evpn_l3nhg_zebra_del_v4_or_v6(es_vrf
, false /*v4_nhg*/);
2940 static void bgp_evpn_l3nhg_deactivate(struct bgp_evpn_es_vrf
*es_vrf
)
2942 if (!(es_vrf
->flags
& BGP_EVPNES_VRF_NHG_ACTIVE
))
2945 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2946 zlog_debug("es %s vrf %u nhg %u de-activate",
2947 es_vrf
->es
->esi_str
, es_vrf
->bgp_vrf
->vrf_id
,
2949 bgp_evpn_l3nhg_zebra_del(es_vrf
);
2950 es_vrf
->flags
&= ~BGP_EVPNES_VRF_NHG_ACTIVE
;
2951 /* MAC-IPs can now be installed via the L3NHG */
2952 bgp_evpn_es_path_update_on_es_vrf_chg(es_vrf
, "l3nhg-deactivate");
2955 static void bgp_evpn_l3nhg_activate(struct bgp_evpn_es_vrf
*es_vrf
, bool update
)
2957 if (!bgp_evpn_es_get_active_vtep_cnt(es_vrf
->es
)) {
2958 bgp_evpn_l3nhg_deactivate(es_vrf
);
2962 if (es_vrf
->flags
& BGP_EVPNES_VRF_NHG_ACTIVE
) {
2966 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2967 zlog_debug("es %s vrf %u nhg %u activate",
2968 es_vrf
->es
->esi_str
, es_vrf
->bgp_vrf
->vrf_id
,
2970 es_vrf
->flags
|= BGP_EVPNES_VRF_NHG_ACTIVE
;
2971 /* MAC-IPs can now be installed via the L3NHG */
2972 bgp_evpn_es_path_update_on_es_vrf_chg(es_vrf
, "l3nhg_activate");
2975 bgp_evpn_l3nhg_zebra_add(es_vrf
);
2978 /* when a VTEP is activated or de-activated against an ES associated
2979 * VRFs' NHG needs to be updated
2981 static void bgp_evpn_l3nhg_update_on_vtep_chg(struct bgp_evpn_es
*es
)
2983 struct bgp_evpn_es_vrf
*es_vrf
;
2984 struct listnode
*es_vrf_node
;
2986 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2987 zlog_debug("es %s nhg update on vtep chg", es
->esi_str
);
2989 for (ALL_LIST_ELEMENTS_RO(es
->es_vrf_list
, es_vrf_node
, es_vrf
))
2990 bgp_evpn_l3nhg_activate(es_vrf
, true /* update */);
2993 /* compare ES-IDs for the ES-VRF RB tree maintained per-VRF */
2994 static int bgp_es_vrf_rb_cmp(const struct bgp_evpn_es_vrf
*es_vrf1
,
2995 const struct bgp_evpn_es_vrf
*es_vrf2
)
2997 return memcmp(&es_vrf1
->es
->esi
, &es_vrf2
->es
->esi
, ESI_BYTES
);
2999 RB_GENERATE(bgp_es_vrf_rb_head
, bgp_evpn_es_vrf
, rb_node
, bgp_es_vrf_rb_cmp
);
3001 /* Initialize the ES tables maintained per-tenant vrf */
3002 void bgp_evpn_vrf_es_init(struct bgp
*bgp_vrf
)
3004 /* Initialize the ES-VRF RB tree */
3005 RB_INIT(bgp_es_vrf_rb_head
, &bgp_vrf
->es_vrf_rb_tree
);
3008 /* find the ES-VRF in the per-VRF RB tree */
3009 static struct bgp_evpn_es_vrf
*bgp_evpn_es_vrf_find(struct bgp_evpn_es
*es
,
3010 struct bgp
*bgp_vrf
)
3012 struct bgp_evpn_es_vrf es_vrf
;
3016 return RB_FIND(bgp_es_vrf_rb_head
, &bgp_vrf
->es_vrf_rb_tree
, &es_vrf
);
3019 /* allocate a new ES-VRF and setup L3NHG for it */
3020 static struct bgp_evpn_es_vrf
*bgp_evpn_es_vrf_create(struct bgp_evpn_es
*es
,
3021 struct bgp
*bgp_vrf
)
3023 struct bgp_evpn_es_vrf
*es_vrf
;
3025 es_vrf
= XCALLOC(MTYPE_BGP_EVPN_ES_VRF
, sizeof(*es_vrf
));
3028 es_vrf
->bgp_vrf
= bgp_vrf
;
3030 /* insert into the VRF-ESI rb tree */
3031 RB_INSERT(bgp_es_vrf_rb_head
, &bgp_vrf
->es_vrf_rb_tree
, es_vrf
);
3033 /* add to the ES's VRF list */
3034 listnode_init(&es_vrf
->es_listnode
, es_vrf
);
3035 listnode_add(es
->es_vrf_list
, &es_vrf
->es_listnode
);
3037 /* setup the L3 NHG id for the ES */
3038 es_vrf
->nhg_id
= bgp_l3nhg_id_alloc();
3039 es_vrf
->v6_nhg_id
= bgp_l3nhg_id_alloc();
3041 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3042 zlog_debug("es %s vrf %u nhg %u v6_nhg %d create", es
->esi_str
,
3043 bgp_vrf
->vrf_id
, es_vrf
->nhg_id
, es_vrf
->v6_nhg_id
);
3044 bgp_evpn_l3nhg_activate(es_vrf
, false /* update */);
3046 /* update paths in the VRF that may already be associated with
3047 * this destination ES
3049 bgp_evpn_es_path_update_on_es_vrf_chg(es_vrf
, "es-vrf-create");
3054 /* remove the L3-NHG associated with the ES-VRF and free it */
3055 static void bgp_evpn_es_vrf_delete(struct bgp_evpn_es_vrf
*es_vrf
)
3057 struct bgp_evpn_es
*es
= es_vrf
->es
;
3058 struct bgp
*bgp_vrf
= es_vrf
->bgp_vrf
;
3060 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3061 zlog_debug("es %s vrf %u nhg %u delete", es
->esi_str
,
3062 bgp_vrf
->vrf_id
, es_vrf
->nhg_id
);
3064 /* Remove the NHG resources */
3065 bgp_evpn_l3nhg_deactivate(es_vrf
);
3067 bgp_l3nhg_id_free(es_vrf
->nhg_id
);
3069 if (es_vrf
->v6_nhg_id
)
3070 bgp_l3nhg_id_free(es_vrf
->v6_nhg_id
);
3071 es_vrf
->v6_nhg_id
= 0;
3073 /* remove from the ES's VRF list */
3074 list_delete_node(es
->es_vrf_list
, &es_vrf
->es_listnode
);
3076 /* remove from the VRF-ESI rb tree */
3077 RB_REMOVE(bgp_es_vrf_rb_head
, &bgp_vrf
->es_vrf_rb_tree
, es_vrf
);
3079 /* update paths in the VRF that may already be associated with
3080 * this destination ES
3082 bgp_evpn_es_path_update_on_es_vrf_chg(es_vrf
, "es-vrf-delete");
3084 XFREE(MTYPE_BGP_EVPN_ES_VRF
, es_vrf
);
3087 /* deref and delete if there are no references */
3088 void bgp_evpn_es_vrf_deref(struct bgp_evpn_es_evi
*es_evi
)
3090 struct bgp_evpn_es_vrf
*es_vrf
= es_evi
->es_vrf
;
3095 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3096 zlog_debug("es-evi %s vni %u vrf %u de-ref",
3097 es_evi
->es
->esi_str
, es_evi
->vpn
->vni
,
3098 es_vrf
->bgp_vrf
->vrf_id
);
3100 es_evi
->es_vrf
= NULL
;
3101 if (es_vrf
->ref_cnt
)
3104 if (!es_vrf
->ref_cnt
)
3105 bgp_evpn_es_vrf_delete(es_vrf
);
3108 /* find or create and reference */
3109 void bgp_evpn_es_vrf_ref(struct bgp_evpn_es_evi
*es_evi
, struct bgp
*bgp_vrf
)
3111 struct bgp_evpn_es
*es
= es_evi
->es
;
3112 struct bgp_evpn_es_vrf
*es_vrf
= es_evi
->es_vrf
;
3113 struct bgp
*old_bgp_vrf
= NULL
;
3116 old_bgp_vrf
= es_vrf
->bgp_vrf
;
3118 if (old_bgp_vrf
== bgp_vrf
)
3121 /* deref the old ES-VRF */
3122 bgp_evpn_es_vrf_deref(es_evi
);
3127 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3128 zlog_debug("es-evi %s vni %u vrf %u ref", es_evi
->es
->esi_str
,
3129 es_evi
->vpn
->vni
, bgp_vrf
->vrf_id
);
3131 /* find-create the new ES-VRF */
3132 es_vrf
= bgp_evpn_es_vrf_find(es
, bgp_vrf
);
3134 es_vrf
= bgp_evpn_es_vrf_create(es
, bgp_vrf
);
3136 es_evi
->es_vrf
= es_vrf
;
3140 /* When the L2-VNI is associated with a L3-VNI/VRF update all the
3141 * associated ES-EVI entries
3143 void bgp_evpn_es_evi_vrf_deref(struct bgpevpn
*vpn
)
3145 struct bgp_evpn_es_evi
*es_evi
;
3147 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3148 zlog_debug("es-vrf de-ref for vni %u", vpn
->vni
);
3150 RB_FOREACH (es_evi
, bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
)
3151 bgp_evpn_es_vrf_deref(es_evi
);
3153 void bgp_evpn_es_evi_vrf_ref(struct bgpevpn
*vpn
)
3155 struct bgp_evpn_es_evi
*es_evi
;
3157 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3158 zlog_debug("es-vrf ref for vni %u", vpn
->vni
);
3160 RB_FOREACH (es_evi
, bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
)
3161 bgp_evpn_es_vrf_ref(es_evi
, vpn
->bgp_vrf
);
3164 /* 1. If ES-VRF is not present install the host route with the exploded/flat
3166 * 2. If ES-VRF is present -
3167 * - if L3NHG has not been activated for the ES-VRF (this could be because
3168 * all the PEs attached to the VRF are down) do not install the route
3170 * - if L3NHG has been activated install the route via that L3NHG
3172 void bgp_evpn_es_vrf_use_nhg(struct bgp
*bgp_vrf
, esi_t
*esi
, bool *use_l3nhg
,
3173 bool *is_l3nhg_active
,
3174 struct bgp_evpn_es_vrf
**es_vrf_p
)
3176 struct bgp_evpn_es
*es
;
3177 struct bgp_evpn_es_vrf
*es_vrf
;
3179 if (!bgp_mh_info
->host_routes_use_l3nhg
)
3182 es
= bgp_evpn_es_find(esi
);
3186 es_vrf
= bgp_evpn_es_vrf_find(es
, bgp_vrf
);
3191 if (es_vrf
->flags
& BGP_EVPNES_VRF_NHG_ACTIVE
)
3192 *is_l3nhg_active
= true;
3197 /* returns false if legacy-exploded mp needs to be used for route install */
3198 bool bgp_evpn_path_es_use_nhg(struct bgp
*bgp_vrf
, struct bgp_path_info
*pi
,
3202 struct bgp_evpn_es_vrf
*es_vrf
= NULL
;
3203 struct bgp_path_info
*parent_pi
;
3204 struct bgp_node
*rn
;
3205 struct prefix_evpn
*evp
;
3206 struct bgp_path_info
*mpinfo
;
3207 bool use_l3nhg
= false;
3208 bool is_l3nhg_active
= false;
3212 /* we don't support NHG for routes leaked from another VRF yet */
3213 if (pi
->extra
&& pi
->extra
->bgp_orig
)
3216 parent_pi
= get_route_parent_evpn(pi
);
3220 rn
= parent_pi
->net
;
3224 evp
= (struct prefix_evpn
*)&rn
->p
;
3225 if (evp
->prefix
.route_type
!= BGP_EVPN_MAC_IP_ROUTE
)
3228 /* non-es path, use legacy-exploded multipath */
3229 esi
= bgp_evpn_attr_get_esi(parent_pi
->attr
);
3230 if (!memcmp(esi
, zero_esi
, sizeof(*esi
)))
3233 bgp_evpn_es_vrf_use_nhg(bgp_vrf
, esi
, &use_l3nhg
, &is_l3nhg_active
,
3236 /* L3NHG support is disabled, use legacy-exploded multipath */
3240 /* if the NHG has not been installed we cannot install the route yet,
3241 * return a 0-NHG to indicate that
3243 if (!is_l3nhg_active
)
3246 /* this needs to be set the v6NHG if v6route */
3247 if (is_evpn_prefix_ipaddr_v6(evp
))
3248 *nhg_p
= es_vrf
->v6_nhg_id
;
3250 *nhg_p
= es_vrf
->nhg_id
;
3252 for (mpinfo
= bgp_path_info_mpath_next(pi
); mpinfo
;
3253 mpinfo
= bgp_path_info_mpath_next(mpinfo
)) {
3254 /* if any of the paths have a different ESI we can't use
3255 * the NHG associated with the ES. fallback to legacy-exploded
3258 if (memcmp(esi
, bgp_evpn_attr_get_esi(mpinfo
->attr
),
3266 static void bgp_evpn_es_vrf_show_entry(struct vty
*vty
,
3267 struct bgp_evpn_es_vrf
*es_vrf
,
3270 struct bgp_evpn_es
*es
= es_vrf
->es
;
3271 struct bgp
*bgp_vrf
= es_vrf
->bgp_vrf
;
3274 json_object
*json_types
;
3276 json_object_string_add(json
, "esi", es
->esi_str
);
3277 json_object_string_add(json
, "vrf", bgp_vrf
->name
);
3279 if (es_vrf
->flags
& (BGP_EVPNES_VRF_NHG_ACTIVE
)) {
3280 json_types
= json_object_new_array();
3281 if (es_vrf
->flags
& BGP_EVPNES_VRF_NHG_ACTIVE
)
3282 json_array_string_add(json_types
, "active");
3283 json_object_object_add(json
, "flags", json_types
);
3286 json_object_int_add(json
, "ipv4NHG", es_vrf
->nhg_id
);
3287 json_object_int_add(json
, "ipv6NHG", es_vrf
->v6_nhg_id
);
3288 json_object_int_add(json
, "refCount", es_vrf
->ref_cnt
);
3292 flags_str
[0] = '\0';
3293 if (es_vrf
->flags
& BGP_EVPNES_VRF_NHG_ACTIVE
)
3294 strlcat(flags_str
, "A", sizeof(flags_str
));
3296 vty_out(vty
, "%-30s %-15s %-5s %-8u %-8u %u\n", es
->esi_str
,
3297 bgp_vrf
->name
, flags_str
, es_vrf
->nhg_id
,
3298 es_vrf
->v6_nhg_id
, es_vrf
->ref_cnt
);
3302 static void bgp_evpn_es_vrf_show_es(struct vty
*vty
, json_object
*json_array
,
3303 struct bgp_evpn_es
*es
)
3305 json_object
*json
= NULL
;
3306 struct listnode
*es_vrf_node
;
3307 struct bgp_evpn_es_vrf
*es_vrf
;
3309 for (ALL_LIST_ELEMENTS_RO(es
->es_vrf_list
, es_vrf_node
, es_vrf
)) {
3310 /* create a separate json object for each ES-VRF */
3312 json
= json_object_new_object();
3313 bgp_evpn_es_vrf_show_entry(vty
, es_vrf
, json
);
3314 /* add ES-VRF to the json array */
3316 json_object_array_add(json_array
, json
);
3320 /* Display all ES VRFs */
3321 void bgp_evpn_es_vrf_show(struct vty
*vty
, bool uj
, struct bgp_evpn_es
*es
)
3323 json_object
*json_array
= NULL
;
3326 /* create an array of ESs */
3327 json_array
= json_object_new_array();
3329 vty_out(vty
, "ES-VRF Flags: A Active\n");
3330 vty_out(vty
, "%-30s %-15s %-5s %-8s %-8s %s\n", "ESI", "VRF",
3331 "Flags", "IPv4-NHG", "IPv6-NHG", "Ref");
3335 bgp_evpn_es_vrf_show_es(vty
, json_array
, es
);
3337 RB_FOREACH (es
, bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
)
3338 bgp_evpn_es_vrf_show_es(vty
, json_array
, es
);
3341 /* print the array of json-ESs */
3343 vty_json(vty
, json_array
);
3346 /* Display specific ES VRF */
3347 void bgp_evpn_es_vrf_show_esi(struct vty
*vty
, esi_t
*esi
, bool uj
)
3349 struct bgp_evpn_es
*es
;
3351 es
= bgp_evpn_es_find(esi
);
3353 bgp_evpn_es_vrf_show(vty
, uj
, es
);
3356 vty_out(vty
, "ESI not found\n");
3360 /*****************************************************************************/
3361 /* Ethernet Segment to EVI association -
3362 * 1. The ES-EVI entry is maintained as a RB tree per L2-VNI
3363 * (bgpevpn->es_evi_rb_tree).
3364 * 2. Each local ES-EVI entry is rxed from zebra and then used by BGP to
3365 * advertises an EAD-EVI (Type-1 EVPN) route
3366 * 3. The remote ES-EVI is created when a bgp_evpn_es_evi_vtep references
3370 /* A list of remote VTEPs is maintained for each ES-EVI. This list includes -
3371 * 1. VTEPs for which we have imported the EAD-per-ES Type1 route
3372 * 2. VTEPs for which we have imported the EAD-per-EVI Type1 route
3373 * VTEPs for which both routes have been rxed are activated. Activation
3374 * creates a NHG in the parent ES.
3376 static int bgp_evpn_es_evi_vtep_cmp(void *p1
, void *p2
)
3378 const struct bgp_evpn_es_evi_vtep
*evi_vtep1
= p1
;
3379 const struct bgp_evpn_es_evi_vtep
*evi_vtep2
= p2
;
3381 return evi_vtep1
->vtep_ip
.s_addr
- evi_vtep2
->vtep_ip
.s_addr
;
3384 static struct bgp_evpn_es_evi_vtep
*bgp_evpn_es_evi_vtep_new(
3385 struct bgp_evpn_es_evi
*es_evi
, struct in_addr vtep_ip
)
3387 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
3389 evi_vtep
= XCALLOC(MTYPE_BGP_EVPN_ES_EVI_VTEP
, sizeof(*evi_vtep
));
3391 evi_vtep
->es_evi
= es_evi
;
3392 evi_vtep
->vtep_ip
.s_addr
= vtep_ip
.s_addr
;
3393 listnode_init(&evi_vtep
->es_evi_listnode
, evi_vtep
);
3394 listnode_add_sort(es_evi
->es_evi_vtep_list
, &evi_vtep
->es_evi_listnode
);
3399 static void bgp_evpn_es_evi_vtep_free(struct bgp_evpn_es_evi_vtep
*evi_vtep
)
3401 struct bgp_evpn_es_evi
*es_evi
= evi_vtep
->es_evi
;
3403 if (evi_vtep
->flags
& (BGP_EVPN_EVI_VTEP_EAD
))
3404 /* as long as there is some reference we can't free it */
3407 list_delete_node(es_evi
->es_evi_vtep_list
, &evi_vtep
->es_evi_listnode
);
3408 XFREE(MTYPE_BGP_EVPN_ES_EVI_VTEP
, evi_vtep
);
3411 /* check if VTEP is already part of the list */
3412 static struct bgp_evpn_es_evi_vtep
*bgp_evpn_es_evi_vtep_find(
3413 struct bgp_evpn_es_evi
*es_evi
, struct in_addr vtep_ip
)
3415 struct listnode
*node
= NULL
;
3416 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
3418 for (ALL_LIST_ELEMENTS_RO(es_evi
->es_evi_vtep_list
, node
, evi_vtep
)) {
3419 if (evi_vtep
->vtep_ip
.s_addr
== vtep_ip
.s_addr
)
3425 /* A VTEP can be added as "active" attach to an ES if EAD-per-ES and
3426 * EAD-per-EVI routes are rxed from it.
3428 static void bgp_evpn_es_evi_vtep_re_eval_active(struct bgp
*bgp
,
3429 struct bgp_evpn_es_evi_vtep
*evi_vtep
)
3433 uint32_t ead_activity_flags
;
3435 old_active
= CHECK_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
);
3437 if (bgp_mh_info
->ead_evi_rx
)
3438 /* Both EAD-per-ES and EAD-per-EVI routes must be rxed from a PE
3439 * before it can be activated.
3441 ead_activity_flags
= BGP_EVPN_EVI_VTEP_EAD
;
3443 /* EAD-per-ES is sufficent to activate the PE */
3444 ead_activity_flags
= BGP_EVPN_EVI_VTEP_EAD_PER_ES
;
3446 if ((evi_vtep
->flags
& ead_activity_flags
) == ead_activity_flags
)
3447 SET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
);
3449 UNSET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
);
3451 new_active
= CHECK_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
);
3453 if (old_active
== new_active
)
3456 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3457 zlog_debug("es %s evi %u vtep %pI4 %s",
3458 evi_vtep
->es_evi
->es
->esi_str
,
3459 evi_vtep
->es_evi
->vpn
->vni
, &evi_vtep
->vtep_ip
,
3460 new_active
? "active" : "inactive");
3462 /* add VTEP to parent es */
3464 struct bgp_evpn_es_vtep
*es_vtep
;
3466 es_vtep
= bgp_evpn_es_vtep_add(bgp
, evi_vtep
->es_evi
->es
,
3467 evi_vtep
->vtep_ip
, false /*esr*/,
3469 evi_vtep
->es_vtep
= es_vtep
;
3471 if (evi_vtep
->es_vtep
) {
3472 bgp_evpn_es_vtep_do_del(bgp
, evi_vtep
->es_vtep
,
3474 evi_vtep
->es_vtep
= NULL
;
3477 /* queue up the parent es for background consistency checks */
3478 bgp_evpn_es_cons_checks_pend_add(evi_vtep
->es_evi
->es
);
3481 static void bgp_evpn_es_evi_vtep_add(struct bgp
*bgp
,
3482 struct bgp_evpn_es_evi
*es_evi
, struct in_addr vtep_ip
,
3485 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
3487 evi_vtep
= bgp_evpn_es_evi_vtep_find(es_evi
, vtep_ip
);
3490 evi_vtep
= bgp_evpn_es_evi_vtep_new(es_evi
, vtep_ip
);
3492 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3493 zlog_debug("add es %s evi %u vtep %pI4 %s",
3494 evi_vtep
->es_evi
->es
->esi_str
,
3495 evi_vtep
->es_evi
->vpn
->vni
, &evi_vtep
->vtep_ip
,
3496 ead_es
? "ead_es" : "ead_evi");
3499 SET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_EAD_PER_ES
);
3501 SET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_EAD_PER_EVI
);
3503 bgp_evpn_es_evi_vtep_re_eval_active(bgp
, evi_vtep
);
3506 static void bgp_evpn_es_evi_vtep_del(struct bgp
*bgp
,
3507 struct bgp_evpn_es_evi
*es_evi
, struct in_addr vtep_ip
,
3510 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
3512 evi_vtep
= bgp_evpn_es_evi_vtep_find(es_evi
, vtep_ip
);
3516 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3517 zlog_debug("del es %s evi %u vtep %pI4 %s",
3518 evi_vtep
->es_evi
->es
->esi_str
,
3519 evi_vtep
->es_evi
->vpn
->vni
, &evi_vtep
->vtep_ip
,
3520 ead_es
? "ead_es" : "ead_evi");
3523 UNSET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_EAD_PER_ES
);
3525 UNSET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_EAD_PER_EVI
);
3527 bgp_evpn_es_evi_vtep_re_eval_active(bgp
, evi_vtep
);
3528 bgp_evpn_es_evi_vtep_free(evi_vtep
);
3531 /* compare ES-IDs for the ES-EVI RB tree maintained per-VNI */
3532 static int bgp_es_evi_rb_cmp(const struct bgp_evpn_es_evi
*es_evi1
,
3533 const struct bgp_evpn_es_evi
*es_evi2
)
3535 return memcmp(&es_evi1
->es
->esi
, &es_evi2
->es
->esi
, ESI_BYTES
);
3537 RB_GENERATE(bgp_es_evi_rb_head
, bgp_evpn_es_evi
, rb_node
, bgp_es_evi_rb_cmp
);
3539 /* find the ES-EVI in the per-L2-VNI RB tree */
3540 static struct bgp_evpn_es_evi
*bgp_evpn_es_evi_find(struct bgp_evpn_es
*es
,
3541 struct bgpevpn
*vpn
)
3543 struct bgp_evpn_es_evi es_evi
;
3547 return RB_FIND(bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
, &es_evi
);
3550 /* allocate a new ES-EVI and insert it into the per-L2-VNI and per-ES
3553 static struct bgp_evpn_es_evi
*bgp_evpn_es_evi_new(struct bgp_evpn_es
*es
,
3554 struct bgpevpn
*vpn
)
3556 struct bgp_evpn_es_evi
*es_evi
;
3558 es_evi
= XCALLOC(MTYPE_BGP_EVPN_ES_EVI
, sizeof(*es_evi
));
3563 /* Initialise the VTEP list */
3564 es_evi
->es_evi_vtep_list
= list_new();
3565 listset_app_node_mem(es_evi
->es_evi_vtep_list
);
3566 es_evi
->es_evi_vtep_list
->cmp
= bgp_evpn_es_evi_vtep_cmp
;
3568 /* insert into the VNI-ESI rb tree */
3569 RB_INSERT(bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
, es_evi
);
3571 /* add to the ES's VNI list */
3572 listnode_init(&es_evi
->es_listnode
, es_evi
);
3573 listnode_add(es
->es_evi_list
, &es_evi
->es_listnode
);
3575 bgp_evpn_es_vrf_ref(es_evi
, vpn
->bgp_vrf
);
3580 /* remove the ES-EVI from the per-L2-VNI and per-ES tables and free
3583 static struct bgp_evpn_es_evi
*
3584 bgp_evpn_es_evi_free(struct bgp_evpn_es_evi
*es_evi
)
3586 struct bgp_evpn_es
*es
= es_evi
->es
;
3587 struct bgpevpn
*vpn
= es_evi
->vpn
;
3589 /* cannot free the element as long as there is a local or remote
3592 if (es_evi
->flags
& (BGP_EVPNES_EVI_LOCAL
| BGP_EVPNES_EVI_REMOTE
))
3594 bgp_evpn_es_frag_evi_del(es_evi
, false);
3595 bgp_evpn_es_vrf_deref(es_evi
);
3597 /* remove from the ES's VNI list */
3598 list_delete_node(es
->es_evi_list
, &es_evi
->es_listnode
);
3600 /* remove from the VNI-ESI rb tree */
3601 RB_REMOVE(bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
, es_evi
);
3603 /* free the VTEP list */
3604 list_delete(&es_evi
->es_evi_vtep_list
);
3606 /* remove from the VNI-ESI rb tree */
3607 XFREE(MTYPE_BGP_EVPN_ES_EVI
, es_evi
);
3612 /* init local info associated with the ES-EVI */
3613 static void bgp_evpn_es_evi_local_info_set(struct bgp_evpn_es_evi
*es_evi
)
3615 struct bgpevpn
*vpn
= es_evi
->vpn
;
3617 if (CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
3620 SET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
);
3621 listnode_init(&es_evi
->l2vni_listnode
, es_evi
);
3622 listnode_add(vpn
->local_es_evi_list
, &es_evi
->l2vni_listnode
);
3623 bgp_evpn_es_frag_evi_add(es_evi
);
3626 /* clear any local info associated with the ES-EVI */
3627 static struct bgp_evpn_es_evi
*
3628 bgp_evpn_es_evi_local_info_clear(struct bgp_evpn_es_evi
*es_evi
)
3630 struct bgpevpn
*vpn
= es_evi
->vpn
;
3632 UNSET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
);
3633 list_delete_node(vpn
->local_es_evi_list
, &es_evi
->l2vni_listnode
);
3635 return bgp_evpn_es_evi_free(es_evi
);
3638 /* eval remote info associated with the ES */
3639 static void bgp_evpn_es_evi_remote_info_re_eval(struct bgp_evpn_es_evi
*es_evi
)
3641 struct bgp_evpn_es
*es
= es_evi
->es
;
3643 /* if there are remote VTEPs the ES-EVI is classified as "remote" */
3644 if (listcount(es_evi
->es_evi_vtep_list
)) {
3645 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_REMOTE
)) {
3646 SET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_REMOTE
);
3647 ++es
->remote_es_evi_cnt
;
3648 /* set remote on the parent es */
3649 bgp_evpn_es_remote_info_re_eval(es
);
3652 if (CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_REMOTE
)) {
3653 UNSET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_REMOTE
);
3654 if (es
->remote_es_evi_cnt
)
3655 --es
->remote_es_evi_cnt
;
3656 bgp_evpn_es_evi_free(es_evi
);
3657 /* check if "remote" can be cleared from the
3660 bgp_evpn_es_remote_info_re_eval(es
);
3665 static struct bgp_evpn_es_evi
*
3666 bgp_evpn_local_es_evi_do_del(struct bgp_evpn_es_evi
*es_evi
)
3668 struct prefix_evpn p
;
3669 struct bgp_evpn_es
*es
= es_evi
->es
;
3672 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
3675 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3676 zlog_debug("del local es %s evi %u",
3677 es_evi
->es
->esi_str
,
3680 bgp
= bgp_get_evpn();
3682 /* remove the es_evi from the es_frag before sending the update */
3683 bgp_evpn_es_frag_evi_del(es_evi
, true);
3685 /* update EAD-ES with new list of VNIs */
3686 if (bgp_evpn_local_es_is_active(es
))
3687 bgp_evpn_ead_es_route_update(bgp
, es
);
3689 /* withdraw and delete EAD-EVI */
3690 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
)) {
3691 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_EVI_ETH_TAG
,
3692 &es
->esi
, es
->originator_ip
);
3693 if (bgp_evpn_ead_evi_route_delete(bgp
, es
, es_evi
->vpn
,
3695 flog_err(EC_BGP_EVPN_ROUTE_DELETE
,
3696 "%u: EAD-EVI route deletion failure for ESI %s VNI %u",
3697 bgp
->vrf_id
, es
->esi_str
,
3702 return bgp_evpn_es_evi_local_info_clear(es_evi
);
3705 int bgp_evpn_local_es_evi_del(struct bgp
*bgp
, esi_t
*esi
, vni_t vni
)
3707 struct bgpevpn
*vpn
;
3708 struct bgp_evpn_es
*es
;
3709 struct bgp_evpn_es_evi
*es_evi
;
3710 char buf
[ESI_STR_LEN
];
3712 es
= bgp_evpn_es_find(esi
);
3716 "%u: Failed to deref VNI %d from ESI %s; ES not present",
3718 esi_to_str(esi
, buf
, sizeof(buf
)));
3722 vpn
= bgp_evpn_lookup_vni(bgp
, vni
);
3726 "%u: Failed to deref VNI %d from ESI %s; VNI not present",
3727 bgp
->vrf_id
, vni
, es
->esi_str
);
3731 es_evi
= bgp_evpn_es_evi_find(es
, vpn
);
3735 "%u: Failed to deref VNI %d from ESI %s; ES-VNI not present",
3736 bgp
->vrf_id
, vni
, es
->esi_str
);
3740 bgp_evpn_local_es_evi_do_del(es_evi
);
3744 /* Create ES-EVI and advertise the corresponding EAD routes */
3745 int bgp_evpn_local_es_evi_add(struct bgp
*bgp
, esi_t
*esi
, vni_t vni
)
3747 struct bgpevpn
*vpn
;
3748 struct prefix_evpn p
;
3749 struct bgp_evpn_es
*es
;
3750 struct bgp_evpn_es_evi
*es_evi
;
3751 char buf
[ESI_STR_LEN
];
3753 es
= bgp_evpn_es_find(esi
);
3757 "%u: Failed to associate VNI %d with ESI %s; ES not present",
3759 esi_to_str(esi
, buf
, sizeof(buf
)));
3763 vpn
= bgp_evpn_lookup_vni(bgp
, vni
);
3767 "%u: Failed to associate VNI %d with ESI %s; VNI not present",
3768 bgp
->vrf_id
, vni
, es
->esi_str
);
3772 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3773 zlog_debug("add local es %s evi %u",
3776 es_evi
= bgp_evpn_es_evi_find(es
, vpn
);
3779 if (CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
3783 es_evi
= bgp_evpn_es_evi_new(es
, vpn
);
3785 bgp_evpn_es_evi_local_info_set(es_evi
);
3787 /* generate an EAD-EVI for this new VNI */
3788 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
)) {
3789 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_EVI_ETH_TAG
, &es
->esi
,
3791 bgp_evpn_ead_evi_route_update(bgp
, es
, vpn
, &p
);
3795 if (bgp_evpn_local_es_is_active(es
))
3796 bgp_evpn_ead_es_route_update(bgp
, es
);
3801 /* Add remote ES-EVI entry. This is actually the remote VTEP add and the
3802 * ES-EVI is implicity created on first VTEP's reference.
3804 int bgp_evpn_remote_es_evi_add(struct bgp
*bgp
, struct bgpevpn
*vpn
,
3805 const struct prefix_evpn
*p
)
3807 char buf
[ESI_STR_LEN
];
3808 struct bgp_evpn_es
*es
;
3809 struct bgp_evpn_es_evi
*es_evi
;
3811 const esi_t
*esi
= &p
->prefix
.ead_addr
.esi
;
3814 /* local EAD-ES need not be sent back to zebra */
3817 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3818 zlog_debug("add remote %s es %s evi %u vtep %pI4",
3819 p
->prefix
.ead_addr
.eth_tag
? "ead-es" : "ead-evi",
3820 esi_to_str(esi
, buf
, sizeof(buf
)), vpn
->vni
,
3821 &p
->prefix
.ead_addr
.ip
.ipaddr_v4
);
3823 es
= bgp_evpn_es_find(esi
);
3825 es
= bgp_evpn_es_new(bgp
, esi
);
3827 flog_err(EC_BGP_ES_CREATE
,
3828 "%u: Failed to allocate ES entry for ESI %s - at remote ES Add",
3829 bgp
->vrf_id
, esi_to_str(esi
, buf
, sizeof(buf
)));
3834 es_evi
= bgp_evpn_es_evi_find(es
, vpn
);
3836 es_evi
= bgp_evpn_es_evi_new(es
, vpn
);
3838 ead_es
= !!p
->prefix
.ead_addr
.eth_tag
;
3839 bgp_evpn_es_evi_vtep_add(bgp
, es_evi
, p
->prefix
.ead_addr
.ip
.ipaddr_v4
,
3842 bgp_evpn_es_evi_remote_info_re_eval(es_evi
);
3846 /* A remote VTEP has withdrawn. The es-evi-vtep will be deleted and the
3847 * parent es-evi freed up implicitly in last VTEP's deref.
3849 int bgp_evpn_remote_es_evi_del(struct bgp
*bgp
, struct bgpevpn
*vpn
,
3850 const struct prefix_evpn
*p
)
3852 char buf
[ESI_STR_LEN
];
3853 struct bgp_evpn_es
*es
;
3854 struct bgp_evpn_es_evi
*es_evi
;
3858 /* local EAD-ES need not be sent back to zebra */
3861 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3863 "del remote %s es %s evi %u vtep %pI4",
3864 p
->prefix
.ead_addr
.eth_tag
? "ead-es" : "ead-evi",
3865 esi_to_str(&p
->prefix
.ead_addr
.esi
, buf
, sizeof(buf
)),
3866 vpn
->vni
, &p
->prefix
.ead_addr
.ip
.ipaddr_v4
);
3868 es
= bgp_evpn_es_find(&p
->prefix
.ead_addr
.esi
);
3870 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3871 zlog_debug("del remote %s es %s evi %u vtep %pI4, NO es",
3872 p
->prefix
.ead_addr
.eth_tag
? "ead-es"
3874 esi_to_str(&p
->prefix
.ead_addr
.esi
, buf
,
3877 &p
->prefix
.ead_addr
.ip
.ipaddr_v4
);
3880 es_evi
= bgp_evpn_es_evi_find(es
, vpn
);
3882 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3884 "del remote %s es %s evi %u vtep %pI4, NO es-evi",
3885 p
->prefix
.ead_addr
.eth_tag
? "ead-es"
3887 esi_to_str(&p
->prefix
.ead_addr
.esi
, buf
,
3890 &p
->prefix
.ead_addr
.ip
.ipaddr_v4
);
3894 ead_es
= !!p
->prefix
.ead_addr
.eth_tag
;
3895 bgp_evpn_es_evi_vtep_del(bgp
, es_evi
, p
->prefix
.ead_addr
.ip
.ipaddr_v4
,
3897 bgp_evpn_es_evi_remote_info_re_eval(es_evi
);
3901 /* If a VNI is being deleted we need to force del all remote VTEPs */
3902 static void bgp_evpn_remote_es_evi_flush(struct bgp_evpn_es_evi
*es_evi
)
3904 struct listnode
*node
= NULL
;
3905 struct listnode
*nnode
= NULL
;
3906 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
3909 bgp
= bgp_get_evpn();
3913 /* delete all VTEPs */
3914 for (ALL_LIST_ELEMENTS(es_evi
->es_evi_vtep_list
, node
, nnode
,
3916 evi_vtep
->flags
&= ~(BGP_EVPN_EVI_VTEP_EAD_PER_ES
3917 | BGP_EVPN_EVI_VTEP_EAD_PER_EVI
);
3918 bgp_evpn_es_evi_vtep_re_eval_active(bgp
, evi_vtep
);
3919 bgp_evpn_es_evi_vtep_free(evi_vtep
);
3921 /* delete the EVI */
3922 bgp_evpn_es_evi_remote_info_re_eval(es_evi
);
3925 /* Initialize the ES tables maintained per-L2_VNI */
3926 void bgp_evpn_vni_es_init(struct bgpevpn
*vpn
)
3928 /* Initialize the ES-EVI RB tree */
3929 RB_INIT(bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
);
3931 /* Initialize the local list maintained for quick walks by type */
3932 vpn
->local_es_evi_list
= list_new();
3933 listset_app_node_mem(vpn
->local_es_evi_list
);
3936 /* Cleanup the ES info maintained per-L2_VNI */
3937 void bgp_evpn_vni_es_cleanup(struct bgpevpn
*vpn
)
3939 struct bgp_evpn_es_evi
*es_evi
;
3940 struct bgp_evpn_es_evi
*es_evi_next
;
3942 RB_FOREACH_SAFE(es_evi
, bgp_es_evi_rb_head
,
3943 &vpn
->es_evi_rb_tree
, es_evi_next
) {
3944 es_evi
= bgp_evpn_local_es_evi_do_del(es_evi
);
3946 bgp_evpn_remote_es_evi_flush(es_evi
);
3949 list_delete(&vpn
->local_es_evi_list
);
3952 static char *bgp_evpn_es_evi_vteps_str(char *vtep_str
,
3953 struct bgp_evpn_es_evi
*es_evi
,
3954 uint8_t vtep_str_size
)
3956 char vtep_flag_str
[BGP_EVPN_FLAG_STR_SZ
];
3957 struct listnode
*node
;
3958 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
3960 char ip_buf
[INET6_ADDRSTRLEN
];
3963 for (ALL_LIST_ELEMENTS_RO(es_evi
->es_evi_vtep_list
, node
, evi_vtep
)) {
3964 vtep_flag_str
[0] = '\0';
3965 if (evi_vtep
->flags
& BGP_EVPN_EVI_VTEP_EAD_PER_ES
)
3966 strlcat(vtep_flag_str
, "E", sizeof(vtep_flag_str
));
3967 if (evi_vtep
->flags
& BGP_EVPN_EVI_VTEP_EAD_PER_EVI
)
3968 strlcat(vtep_flag_str
, "V", sizeof(vtep_flag_str
));
3970 if (!strnlen(vtep_flag_str
, sizeof(vtep_flag_str
)))
3971 strlcpy(vtep_flag_str
, "-", sizeof(vtep_flag_str
));
3975 strlcat(vtep_str
, ",", vtep_str_size
);
3977 inet_ntop(AF_INET
, &evi_vtep
->vtep_ip
, ip_buf
,
3980 strlcat(vtep_str
, "(", vtep_str_size
);
3981 strlcat(vtep_str
, vtep_flag_str
, vtep_str_size
);
3982 strlcat(vtep_str
, ")", vtep_str_size
);
3988 static void bgp_evpn_es_evi_json_vtep_fill(json_object
*json_vteps
,
3989 struct bgp_evpn_es_evi_vtep
*evi_vtep
)
3991 json_object
*json_vtep_entry
;
3992 json_object
*json_flags
;
3994 json_vtep_entry
= json_object_new_object();
3996 json_object_string_addf(json_vtep_entry
, "vtep_ip", "%pI4",
3997 &evi_vtep
->vtep_ip
);
3998 if (evi_vtep
->flags
& (BGP_EVPN_EVI_VTEP_EAD_PER_ES
|
3999 BGP_EVPN_EVI_VTEP_EAD_PER_EVI
)) {
4000 json_flags
= json_object_new_array();
4001 if (evi_vtep
->flags
& BGP_EVPN_EVI_VTEP_EAD_PER_ES
)
4002 json_array_string_add(json_flags
, "ead-per-es");
4003 if (evi_vtep
->flags
& BGP_EVPN_EVI_VTEP_EAD_PER_EVI
)
4004 json_array_string_add(json_flags
, "ead-per-evi");
4005 json_object_object_add(json_vtep_entry
,
4006 "flags", json_flags
);
4009 json_object_array_add(json_vteps
,
4013 static void bgp_evpn_es_evi_show_entry(struct vty
*vty
,
4014 struct bgp_evpn_es_evi
*es_evi
, json_object
*json
)
4016 struct listnode
*node
;
4017 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
4020 json_object
*json_vteps
;
4021 json_object
*json_types
;
4023 json_object_string_add(json
, "esi", es_evi
->es
->esi_str
);
4024 json_object_int_add(json
, "vni", es_evi
->vpn
->vni
);
4026 if (es_evi
->flags
& (BGP_EVPNES_EVI_LOCAL
|
4027 BGP_EVPNES_EVI_REMOTE
)) {
4028 json_types
= json_object_new_array();
4029 if (es_evi
->flags
& BGP_EVPNES_EVI_LOCAL
)
4030 json_array_string_add(json_types
, "local");
4031 if (es_evi
->flags
& BGP_EVPNES_EVI_REMOTE
)
4032 json_array_string_add(json_types
, "remote");
4033 json_object_object_add(json
, "type", json_types
);
4036 if (listcount(es_evi
->es_evi_vtep_list
)) {
4037 json_vteps
= json_object_new_array();
4038 for (ALL_LIST_ELEMENTS_RO(es_evi
->es_evi_vtep_list
,
4040 bgp_evpn_es_evi_json_vtep_fill(json_vteps
,
4043 json_object_object_add(json
, "vteps", json_vteps
);
4047 char vtep_str
[ES_VTEP_LIST_STR_SZ
+ BGP_EVPN_VTEPS_FLAG_STR_SZ
];
4050 if (es_evi
->flags
& BGP_EVPNES_EVI_LOCAL
)
4051 strlcat(type_str
, "L", sizeof(type_str
));
4052 if (es_evi
->flags
& BGP_EVPNES_EVI_REMOTE
)
4053 strlcat(type_str
, "R", sizeof(type_str
));
4054 if (es_evi
->flags
& BGP_EVPNES_EVI_INCONS_VTEP_LIST
)
4055 strlcat(type_str
, "I", sizeof(type_str
));
4057 bgp_evpn_es_evi_vteps_str(vtep_str
, es_evi
, sizeof(vtep_str
));
4059 vty_out(vty
, "%-8d %-30s %-5s %s\n",
4060 es_evi
->vpn
->vni
, es_evi
->es
->esi_str
,
4061 type_str
, vtep_str
);
4065 static void bgp_evpn_es_evi_show_entry_detail(struct vty
*vty
,
4066 struct bgp_evpn_es_evi
*es_evi
, json_object
*json
)
4068 char buf1
[RD_ADDRSTRLEN
];
4071 json_object
*json_flags
;
4073 /* Add the "brief" info first */
4074 bgp_evpn_es_evi_show_entry(vty
, es_evi
, json
);
4075 if (es_evi
->es_frag
)
4076 json_object_string_add(
4077 json
, "esFragmentRd",
4078 prefix_rd2str(&es_evi
->es_frag
->prd
, buf1
,
4080 if (es_evi
->flags
& BGP_EVPNES_EVI_INCONS_VTEP_LIST
) {
4081 json_flags
= json_object_new_array();
4082 json_array_string_add(json_flags
, "es-vtep-mismatch");
4083 json_object_object_add(json
, "flags", json_flags
);
4086 char vtep_str
[ES_VTEP_LIST_STR_SZ
+ BGP_EVPN_VTEPS_FLAG_STR_SZ
];
4090 if (es_evi
->flags
& BGP_EVPNES_EVI_LOCAL
)
4091 strlcat(type_str
, "L", sizeof(type_str
));
4092 if (es_evi
->flags
& BGP_EVPNES_EVI_REMOTE
)
4093 strlcat(type_str
, "R", sizeof(type_str
));
4095 bgp_evpn_es_evi_vteps_str(vtep_str
, es_evi
, sizeof(vtep_str
));
4096 if (!strlen(vtep_str
))
4097 strlcpy(vtep_str
, "-", sizeof(type_str
));
4099 vty_out(vty
, "VNI: %d ESI: %s\n",
4100 es_evi
->vpn
->vni
, es_evi
->es
->esi_str
);
4101 vty_out(vty
, " Type: %s\n", type_str
);
4102 if (es_evi
->es_frag
)
4103 vty_out(vty
, " ES fragment RD: %s\n",
4104 prefix_rd2str(&es_evi
->es_frag
->prd
, buf1
,
4106 vty_out(vty
, " Inconsistencies: %s\n",
4107 (es_evi
->flags
& BGP_EVPNES_EVI_INCONS_VTEP_LIST
) ?
4108 "es-vtep-mismatch":"-");
4109 vty_out(vty
, " VTEPs: %s\n", vtep_str
);
4114 static void bgp_evpn_es_evi_show_one_vni(struct bgpevpn
*vpn
, struct vty
*vty
,
4115 json_object
*json_array
, bool detail
)
4117 struct bgp_evpn_es_evi
*es_evi
;
4118 json_object
*json
= NULL
;
4120 RB_FOREACH(es_evi
, bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
) {
4122 /* create a separate json object for each ES */
4123 json
= json_object_new_object();
4125 bgp_evpn_es_evi_show_entry_detail(vty
, es_evi
, json
);
4127 bgp_evpn_es_evi_show_entry(vty
, es_evi
, json
);
4128 /* add ES to the json array */
4130 json_object_array_add(json_array
, json
);
4134 struct es_evi_show_ctx
{
4140 static void bgp_evpn_es_evi_show_one_vni_hash_cb(struct hash_bucket
*bucket
,
4143 struct bgpevpn
*vpn
= (struct bgpevpn
*)bucket
->data
;
4144 struct es_evi_show_ctx
*wctx
= (struct es_evi_show_ctx
*)ctxt
;
4146 bgp_evpn_es_evi_show_one_vni(vpn
, wctx
->vty
, wctx
->json
, wctx
->detail
);
4149 /* Display all ES EVIs */
4150 void bgp_evpn_es_evi_show(struct vty
*vty
, bool uj
, bool detail
)
4152 json_object
*json_array
= NULL
;
4153 struct es_evi_show_ctx wctx
;
4157 /* create an array of ES-EVIs */
4158 json_array
= json_object_new_array();
4162 wctx
.json
= json_array
;
4163 wctx
.detail
= detail
;
4165 bgp
= bgp_get_evpn();
4167 if (!json_array
&& !detail
) {
4168 vty_out(vty
, "Flags: L local, R remote, I inconsistent\n");
4169 vty_out(vty
, "VTEP-Flags: E EAD-per-ES, V EAD-per-EVI\n");
4170 vty_out(vty
, "%-8s %-30s %-5s %s\n",
4171 "VNI", "ESI", "Flags", "VTEPs");
4175 hash_iterate(bgp
->vnihash
,
4176 (void (*)(struct hash_bucket
*,
4177 void *))bgp_evpn_es_evi_show_one_vni_hash_cb
,
4180 vty_json(vty
, json_array
);
4183 /* Display specific ES EVI */
4184 void bgp_evpn_es_evi_show_vni(struct vty
*vty
, vni_t vni
,
4185 bool uj
, bool detail
)
4187 struct bgpevpn
*vpn
= NULL
;
4188 json_object
*json_array
= NULL
;
4192 /* create an array of ES-EVIs */
4193 json_array
= json_object_new_array();
4196 bgp
= bgp_get_evpn();
4198 vpn
= bgp_evpn_lookup_vni(bgp
, vni
);
4201 if (!json_array
&& !detail
) {
4202 vty_out(vty
, "Flags: L local, R remote, I inconsistent\n");
4203 vty_out(vty
, "VTEP-Flags: E EAD-per-ES, V EAD-per-EVI\n");
4204 vty_out(vty
, "%-8s %-30s %-5s %s\n",
4205 "VNI", "ESI", "Flags", "VTEPs");
4208 bgp_evpn_es_evi_show_one_vni(vpn
, vty
, json_array
, detail
);
4211 vty_out(vty
, "VNI not found\n");
4215 vty_json(vty
, json_array
);
4218 /*****************************************************************************
4219 * Ethernet Segment Consistency checks
4220 * Consistency checking is done to detect misconfig or mis-cabling. When
4221 * an inconsistency is detected it is simply logged (and displayed via
4222 * show commands) at this point. A more drastic action can be executed (based
4223 * on user config) in the future.
4225 static void bgp_evpn_es_cons_checks_timer_start(void)
4227 if (!bgp_mh_info
->consistency_checking
|| bgp_mh_info
->t_cons_check
)
4230 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
4231 zlog_debug("periodic consistency checking started");
4233 thread_add_timer(bm
->master
, bgp_evpn_run_consistency_checks
, NULL
,
4234 BGP_EVPN_CONS_CHECK_INTERVAL
,
4235 &bgp_mh_info
->t_cons_check
);
4238 /* queue up the es for background consistency checks */
4239 static void bgp_evpn_es_cons_checks_pend_add(struct bgp_evpn_es
*es
)
4241 if (!bgp_mh_info
->consistency_checking
)
4242 /* consistency checking is not enabled */
4245 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_CONS_CHECK_PEND
))
4246 /* already queued for consistency checking */
4249 /* start the periodic timer for consistency checks if it is not
4250 * already running */
4251 bgp_evpn_es_cons_checks_timer_start();
4253 SET_FLAG(es
->flags
, BGP_EVPNES_CONS_CHECK_PEND
);
4254 listnode_init(&es
->pend_es_listnode
, es
);
4255 listnode_add_after(bgp_mh_info
->pend_es_list
,
4256 listtail_unchecked(bgp_mh_info
->pend_es_list
),
4257 &es
->pend_es_listnode
);
4260 /* pull the ES from the consistency check list */
4261 static void bgp_evpn_es_cons_checks_pend_del(struct bgp_evpn_es
*es
)
4263 if (!CHECK_FLAG(es
->flags
, BGP_EVPNES_CONS_CHECK_PEND
))
4266 UNSET_FLAG(es
->flags
, BGP_EVPNES_CONS_CHECK_PEND
);
4267 list_delete_node(bgp_mh_info
->pend_es_list
,
4268 &es
->pend_es_listnode
);
4271 /* Number of active VTEPs associated with the ES-per-EVI */
4272 static uint32_t bgp_evpn_es_evi_get_active_vtep_cnt(
4273 struct bgp_evpn_es_evi
*es_evi
)
4275 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
4276 struct listnode
*node
;
4277 uint32_t vtep_cnt
= 0;
4279 for (ALL_LIST_ELEMENTS_RO(es_evi
->es_evi_vtep_list
, node
, evi_vtep
)) {
4280 if (CHECK_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
))
4287 /* Number of active VTEPs associated with the ES */
4288 static uint32_t bgp_evpn_es_get_active_vtep_cnt(struct bgp_evpn_es
*es
)
4290 struct listnode
*node
;
4291 uint32_t vtep_cnt
= 0;
4292 struct bgp_evpn_es_vtep
*es_vtep
;
4294 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
4295 if (CHECK_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
))
4302 static struct bgp_evpn_es_vtep
*bgp_evpn_es_get_next_active_vtep(
4303 struct bgp_evpn_es
*es
, struct bgp_evpn_es_vtep
*es_vtep
)
4305 struct listnode
*node
;
4306 struct bgp_evpn_es_vtep
*next_es_vtep
;
4309 node
= listnextnode_unchecked(&es_vtep
->es_listnode
);
4311 node
= listhead(es
->es_vtep_list
);
4313 for (; node
; node
= listnextnode_unchecked(node
)) {
4314 next_es_vtep
= listgetdata(node
);
4315 if (CHECK_FLAG(next_es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
))
4316 return next_es_vtep
;
4322 static struct bgp_evpn_es_evi_vtep
*bgp_evpn_es_evi_get_next_active_vtep(
4323 struct bgp_evpn_es_evi
*es_evi
,
4324 struct bgp_evpn_es_evi_vtep
*evi_vtep
)
4326 struct listnode
*node
;
4327 struct bgp_evpn_es_evi_vtep
*next_evi_vtep
;
4330 node
= listnextnode_unchecked(&evi_vtep
->es_evi_listnode
);
4332 node
= listhead(es_evi
->es_evi_vtep_list
);
4334 for (; node
; node
= listnextnode_unchecked(node
)) {
4335 next_evi_vtep
= listgetdata(node
);
4336 if (CHECK_FLAG(next_evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
))
4337 return next_evi_vtep
;
4343 static void bgp_evpn_es_evi_set_inconsistent(struct bgp_evpn_es_evi
*es_evi
)
4345 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_INCONS_VTEP_LIST
)) {
4346 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
4347 zlog_debug("inconsistency detected - es %s evi %u vtep list mismatch",
4348 es_evi
->es
->esi_str
,
4350 SET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_INCONS_VTEP_LIST
);
4352 /* update parent ES with the incosistency setting */
4353 if (!es_evi
->es
->incons_evi_vtep_cnt
&&
4354 BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
4355 zlog_debug("inconsistency detected - es %s vtep list mismatch",
4356 es_evi
->es
->esi_str
);
4357 ++es_evi
->es
->incons_evi_vtep_cnt
;
4358 SET_FLAG(es_evi
->es
->inconsistencies
,
4359 BGP_EVPNES_INCONS_VTEP_LIST
);
4363 static uint32_t bgp_evpn_es_run_consistency_checks(struct bgp_evpn_es
*es
)
4366 int es_active_vtep_cnt
;
4367 int evi_active_vtep_cnt
;
4368 struct bgp_evpn_es_evi
*es_evi
;
4369 struct listnode
*evi_node
;
4370 struct bgp_evpn_es_vtep
*es_vtep
;
4371 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
4373 /* reset the inconsistencies and re-evaluate */
4374 es
->incons_evi_vtep_cnt
= 0;
4375 es
->inconsistencies
= 0;
4377 es_active_vtep_cnt
= bgp_evpn_es_get_active_vtep_cnt(es
);
4378 for (ALL_LIST_ELEMENTS_RO(es
->es_evi_list
,
4379 evi_node
, es_evi
)) {
4382 /* reset the inconsistencies on the EVI and re-evaluate*/
4383 UNSET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_INCONS_VTEP_LIST
);
4385 evi_active_vtep_cnt
=
4386 bgp_evpn_es_evi_get_active_vtep_cnt(es_evi
);
4387 if (es_active_vtep_cnt
!= evi_active_vtep_cnt
) {
4388 bgp_evpn_es_evi_set_inconsistent(es_evi
);
4392 if (!es_active_vtep_cnt
)
4397 while ((es_vtep
= bgp_evpn_es_get_next_active_vtep(
4399 evi_vtep
= bgp_evpn_es_evi_get_next_active_vtep(es_evi
,
4402 bgp_evpn_es_evi_set_inconsistent(es_evi
);
4405 if (es_vtep
->vtep_ip
.s_addr
!=
4406 evi_vtep
->vtep_ip
.s_addr
) {
4407 /* inconsistency detected; set it and move
4410 bgp_evpn_es_evi_set_inconsistent(es_evi
);
4419 static void bgp_evpn_run_consistency_checks(struct thread
*t
)
4423 struct listnode
*node
;
4424 struct listnode
*nextnode
;
4425 struct bgp_evpn_es
*es
;
4427 for (ALL_LIST_ELEMENTS(bgp_mh_info
->pend_es_list
,
4428 node
, nextnode
, es
)) {
4431 /* run consistency checks on the ES and remove it from the
4434 proc_cnt
+= bgp_evpn_es_run_consistency_checks(es
);
4435 bgp_evpn_es_cons_checks_pend_del(es
);
4440 /* restart the timer */
4441 thread_add_timer(bm
->master
, bgp_evpn_run_consistency_checks
, NULL
,
4442 BGP_EVPN_CONS_CHECK_INTERVAL
,
4443 &bgp_mh_info
->t_cons_check
);
4446 /*****************************************************************************
4447 * EVPN-Nexthop and RMAC management: nexthops associated with Type-2 routes
4448 * that have an ES as destination are consolidated by BGP into a per-VRF
4449 * nh->rmac mapping which is sent to zebra. Zebra installs the nexthop
4450 * as a remote neigh/fdb entry with a dummy (type-1) prefix referencing it.
4452 * This handling is needed because Type-2 routes with ES as dest use NHG
4453 * that is setup using EAD routes (i.e. such NHGs do not include the
4455 ****************************************************************************/
4456 static void bgp_evpn_nh_zebra_update_send(struct bgp_evpn_nh
*nh
, bool add
)
4459 struct bgp
*bgp_vrf
= nh
->bgp_vrf
;
4462 if (!zclient
|| zclient
->sock
< 0)
4465 /* Don't try to register if Zebra doesn't know of this instance. */
4466 if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp_vrf
)) {
4467 if (BGP_DEBUG(zebra
, ZEBRA
))
4468 zlog_debug("No zebra instance, not %s remote nh %s",
4469 add
? "adding" : "deleting", nh
->nh_str
);
4476 zclient_create_header(
4477 s
, add
? ZEBRA_EVPN_REMOTE_NH_ADD
: ZEBRA_EVPN_REMOTE_NH_DEL
,
4479 stream_putl(s
, bgp_vrf
->vrf_id
);
4480 stream_put(s
, &nh
->ip
, sizeof(nh
->ip
));
4482 stream_put(s
, &nh
->rmac
, sizeof(nh
->rmac
));
4484 stream_putw_at(s
, 0, stream_get_endp(s
));
4486 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
)) {
4488 zlog_debug("evpn vrf %s nh %s rmac %pEA add to zebra",
4489 nh
->bgp_vrf
->name
, nh
->nh_str
, &nh
->rmac
);
4490 else if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
4491 zlog_debug("evpn vrf %s nh %s del to zebra",
4492 nh
->bgp_vrf
->name
, nh
->nh_str
);
4495 frrtrace(2, frr_bgp
, evpn_mh_nh_rmac_zsend
, add
, nh
);
4497 zclient_send_message(zclient
);
4500 static void bgp_evpn_nh_zebra_update(struct bgp_evpn_nh
*nh
, bool add
)
4502 if (add
&& !is_zero_mac(&nh
->rmac
)) {
4503 nh
->flags
|= BGP_EVPN_NH_READY_FOR_ZEBRA
;
4504 bgp_evpn_nh_zebra_update_send(nh
, true);
4506 if (!(nh
->flags
& BGP_EVPN_NH_READY_FOR_ZEBRA
))
4508 nh
->flags
&= ~BGP_EVPN_NH_READY_FOR_ZEBRA
;
4509 bgp_evpn_nh_zebra_update_send(nh
, false);
4513 static void *bgp_evpn_nh_alloc(void *p
)
4515 struct bgp_evpn_nh
*tmp_n
= p
;
4516 struct bgp_evpn_nh
*n
;
4518 n
= XCALLOC(MTYPE_BGP_EVPN_NH
, sizeof(struct bgp_evpn_nh
));
4524 static struct bgp_evpn_nh
*bgp_evpn_nh_find(struct bgp
*bgp_vrf
,
4527 struct bgp_evpn_nh tmp
;
4528 struct bgp_evpn_nh
*n
;
4530 memset(&tmp
, 0, sizeof(tmp
));
4531 memcpy(&tmp
.ip
, ip
, sizeof(struct ipaddr
));
4532 n
= hash_lookup(bgp_vrf
->evpn_nh_table
, &tmp
);
4537 /* Add nexthop entry - implicitly created on first path reference */
4538 static struct bgp_evpn_nh
*bgp_evpn_nh_add(struct bgp
*bgp_vrf
,
4540 struct bgp_path_info
*pi
)
4542 struct bgp_evpn_nh tmp_n
;
4543 struct bgp_evpn_nh
*n
= NULL
;
4545 memset(&tmp_n
, 0, sizeof(struct bgp_evpn_nh
));
4546 memcpy(&tmp_n
.ip
, ip
, sizeof(struct ipaddr
));
4547 n
= hash_get(bgp_vrf
->evpn_nh_table
, &tmp_n
, bgp_evpn_nh_alloc
);
4548 ipaddr2str(ip
, n
->nh_str
, sizeof(n
->nh_str
));
4549 n
->bgp_vrf
= bgp_vrf
;
4551 n
->pi_list
= list_new();
4552 listset_app_node_mem(n
->pi_list
);
4554 /* Setup ref_pi when the nh is created */
4555 if (CHECK_FLAG(pi
->flags
, BGP_PATH_VALID
) && pi
->attr
) {
4557 memcpy(&n
->rmac
, &pi
->attr
->rmac
, ETH_ALEN
);
4560 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
4561 zlog_debug("evpn vrf %s nh %s rmac %pEA add", n
->bgp_vrf
->name
,
4562 n
->nh_str
, &n
->rmac
);
4563 bgp_evpn_nh_zebra_update(n
, true);
4567 /* Delete nexthop entry if there are no paths referencing it */
4568 static void bgp_evpn_nh_del(struct bgp_evpn_nh
*n
)
4570 struct bgp_evpn_nh
*tmp_n
;
4571 struct bgp
*bgp_vrf
= n
->bgp_vrf
;
4573 if (listcount(n
->pi_list
))
4576 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
4577 zlog_debug("evpn vrf %s nh %s del to zebra", bgp_vrf
->name
,
4580 bgp_evpn_nh_zebra_update(n
, false);
4581 list_delete(&n
->pi_list
);
4582 tmp_n
= hash_release(bgp_vrf
->evpn_nh_table
, n
);
4583 XFREE(MTYPE_BGP_EVPN_NH
, tmp_n
);
4586 static unsigned int bgp_evpn_nh_hash_keymake(const void *p
)
4588 const struct bgp_evpn_nh
*n
= p
;
4589 const struct ipaddr
*ip
= &n
->ip
;
4591 if (IS_IPADDR_V4(ip
))
4592 return jhash_1word(ip
->ipaddr_v4
.s_addr
, 0);
4594 return jhash2(ip
->ipaddr_v6
.s6_addr32
,
4595 array_size(ip
->ipaddr_v6
.s6_addr32
), 0);
4598 static bool bgp_evpn_nh_cmp(const void *p1
, const void *p2
)
4600 const struct bgp_evpn_nh
*n1
= p1
;
4601 const struct bgp_evpn_nh
*n2
= p2
;
4603 if (n1
== NULL
&& n2
== NULL
)
4606 if (n1
== NULL
|| n2
== NULL
)
4609 return (ipaddr_cmp(&n1
->ip
, &n2
->ip
) == 0);
4612 void bgp_evpn_nh_init(struct bgp
*bgp_vrf
)
4614 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
4615 zlog_debug("evpn vrf %s nh init", bgp_vrf
->name
);
4616 bgp_vrf
->evpn_nh_table
= hash_create(
4617 bgp_evpn_nh_hash_keymake
, bgp_evpn_nh_cmp
, "BGP EVPN NH table");
4620 static void bgp_evpn_nh_flush_entry(struct bgp_evpn_nh
*nh
)
4622 struct listnode
*node
;
4623 struct listnode
*nnode
;
4624 struct bgp_path_evpn_nh_info
*nh_info
;
4626 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
4627 zlog_debug("evpn vrf %s nh %s flush", nh
->bgp_vrf
->name
,
4630 /* force flush paths */
4631 for (ALL_LIST_ELEMENTS(nh
->pi_list
, node
, nnode
, nh_info
))
4632 bgp_evpn_path_nh_del(nh
->bgp_vrf
, nh_info
->pi
);
4635 static void bgp_evpn_nh_flush_cb(struct hash_bucket
*bucket
, void *ctxt
)
4637 struct bgp_evpn_nh
*nh
= (struct bgp_evpn_nh
*)bucket
->data
;
4639 bgp_evpn_nh_flush_entry(nh
);
4642 void bgp_evpn_nh_finish(struct bgp
*bgp_vrf
)
4644 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
4645 zlog_debug("evpn vrf %s nh finish", bgp_vrf
->name
);
4647 bgp_vrf
->evpn_nh_table
,
4648 (void (*)(struct hash_bucket
*, void *))bgp_evpn_nh_flush_cb
,
4650 hash_free(bgp_vrf
->evpn_nh_table
);
4651 bgp_vrf
->evpn_nh_table
= NULL
;
4654 static void bgp_evpn_nh_update_ref_pi(struct bgp_evpn_nh
*nh
)
4656 struct listnode
*node
;
4657 struct bgp_path_info
*pi
;
4658 struct bgp_path_evpn_nh_info
*nh_info
;
4663 for (ALL_LIST_ELEMENTS_RO(nh
->pi_list
, node
, nh_info
)) {
4665 if (!CHECK_FLAG(pi
->flags
, BGP_PATH_VALID
) || !pi
->attr
)
4668 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
4669 zlog_debug("evpn vrf %s nh %s ref_pi update",
4670 nh
->bgp_vrf
->name
, nh
->nh_str
);
4672 /* If we have a new pi copy rmac from it and update
4673 * zebra if the new rmac is different
4675 if (memcmp(&nh
->rmac
, &nh
->ref_pi
->attr
->rmac
, ETH_ALEN
)) {
4676 memcpy(&nh
->rmac
, &nh
->ref_pi
->attr
->rmac
, ETH_ALEN
);
4677 bgp_evpn_nh_zebra_update(nh
, true);
4683 static void bgp_evpn_nh_clear_ref_pi(struct bgp_evpn_nh
*nh
,
4684 struct bgp_path_info
*pi
)
4686 if (nh
->ref_pi
!= pi
)
4689 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
4690 zlog_debug("evpn vrf %s nh %s ref_pi clear", nh
->bgp_vrf
->name
,
4693 /* try to find another ref_pi */
4694 bgp_evpn_nh_update_ref_pi(nh
);
4695 /* couldn't find one - clear the old rmac and notify zebra */
4697 memset(&nh
->rmac
, 0, ETH_ALEN
);
4698 bgp_evpn_nh_zebra_update(nh
, true);
4702 static void bgp_evpn_path_nh_info_free(struct bgp_path_evpn_nh_info
*nh_info
)
4704 bgp_evpn_path_nh_unlink(nh_info
);
4705 XFREE(MTYPE_BGP_EVPN_PATH_NH_INFO
, nh_info
);
4708 static struct bgp_path_evpn_nh_info
*
4709 bgp_evpn_path_nh_info_new(struct bgp_path_info
*pi
)
4711 struct bgp_path_info_extra
*e
;
4712 struct bgp_path_mh_info
*mh_info
;
4713 struct bgp_path_evpn_nh_info
*nh_info
;
4715 e
= bgp_path_info_extra_get(pi
);
4717 /* If mh_info doesn't exist allocate it */
4718 mh_info
= e
->mh_info
;
4720 e
->mh_info
= mh_info
= XCALLOC(MTYPE_BGP_EVPN_PATH_MH_INFO
,
4721 sizeof(struct bgp_path_mh_info
));
4723 /* If nh_info doesn't exist allocate it */
4724 nh_info
= mh_info
->nh_info
;
4726 mh_info
->nh_info
= nh_info
=
4727 XCALLOC(MTYPE_BGP_EVPN_PATH_NH_INFO
,
4728 sizeof(struct bgp_path_evpn_nh_info
));
4735 static void bgp_evpn_path_nh_unlink(struct bgp_path_evpn_nh_info
*nh_info
)
4737 struct bgp_evpn_nh
*nh
= nh_info
->nh
;
4738 struct bgp_path_info
*pi
;
4739 char prefix_buf
[PREFIX_STRLEN
];
4745 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
4746 zlog_debug("path %s unlinked from nh %s %s",
4747 pi
->net
? prefix2str(&pi
->net
->p
, prefix_buf
,
4750 nh
->bgp_vrf
->name
, nh
->nh_str
);
4752 list_delete_node(nh
->pi_list
, &nh_info
->nh_listnode
);
4756 /* check if the ref_pi need to be updated */
4757 bgp_evpn_nh_clear_ref_pi(nh
, pi
);
4759 /* if there are no other references against the nh it
4762 bgp_evpn_nh_del(nh
);
4764 /* Note we don't free the path nh_info on unlink; it will be freed up
4765 * along with the path.
4769 static void bgp_evpn_path_nh_link(struct bgp
*bgp_vrf
, struct bgp_path_info
*pi
)
4771 struct bgp_path_evpn_nh_info
*nh_info
;
4772 struct bgp_evpn_nh
*nh
;
4775 /* EVPN nexthop setup in bgp has been turned off */
4776 if (!bgp_mh_info
->bgp_evpn_nh_setup
)
4779 if (!bgp_vrf
->evpn_nh_table
) {
4780 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
4781 zlog_debug("path %pFX linked to vrf %s failed",
4782 &pi
->net
->p
, bgp_vrf
->name
);
4786 nh_info
= (pi
->extra
&& pi
->extra
->mh_info
)
4787 ? pi
->extra
->mh_info
->nh_info
4790 /* if NHG is not being used for this path we don't need to manage the
4791 * nexthops in bgp (they are managed by zebra instead)
4793 if (!(pi
->attr
->es_flags
& ATTR_ES_L3_NHG_USE
)) {
4795 bgp_evpn_path_nh_unlink(nh_info
);
4799 /* setup nh_info against the path if it doesn't aleady exist */
4801 nh_info
= bgp_evpn_path_nh_info_new(pi
);
4803 /* find-create nh */
4804 memset(&ip
, 0, sizeof(ip
));
4805 if (pi
->net
->p
.family
== AF_INET6
) {
4807 memcpy(&ip
.ipaddr_v6
, &pi
->attr
->mp_nexthop_global
,
4808 sizeof(ip
.ipaddr_v6
));
4811 memcpy(&ip
.ipaddr_v4
, &pi
->attr
->nexthop
, sizeof(ip
.ipaddr_v4
));
4814 nh
= bgp_evpn_nh_find(bgp_vrf
, &ip
);
4816 nh
= bgp_evpn_nh_add(bgp_vrf
, &ip
, pi
);
4819 if (nh_info
->nh
== nh
) {
4820 /* Check if any of the paths are now valid */
4821 bgp_evpn_nh_update_ref_pi(nh
);
4825 /* unlink old nh if any */
4826 bgp_evpn_path_nh_unlink(nh_info
);
4828 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
4829 zlog_debug("path %pFX linked to nh %s %s", &pi
->net
->p
,
4830 nh
->bgp_vrf
->name
, nh
->nh_str
);
4832 /* link mac-ip path to the new nh */
4834 listnode_init(&nh_info
->nh_listnode
, nh_info
);
4835 listnode_add(nh
->pi_list
, &nh_info
->nh_listnode
);
4836 /* If a new valid path got linked to the nh see if can get the rmac
4839 bgp_evpn_nh_update_ref_pi(nh
);
4840 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
)) {
4843 "path %pFX linked to nh %s %s with no valid pi",
4844 &pi
->net
->p
, nh
->bgp_vrf
->name
, nh
->nh_str
);
4848 void bgp_evpn_path_nh_del(struct bgp
*bgp_vrf
, struct bgp_path_info
*pi
)
4850 struct bgp_path_evpn_nh_info
*nh_info
;
4852 nh_info
= (pi
->extra
&& pi
->extra
->mh_info
)
4853 ? pi
->extra
->mh_info
->nh_info
4859 bgp_evpn_path_nh_unlink(nh_info
);
4862 void bgp_evpn_path_nh_add(struct bgp
*bgp_vrf
, struct bgp_path_info
*pi
)
4864 bgp_evpn_path_nh_link(bgp_vrf
, pi
);
4867 static void bgp_evpn_nh_show_entry(struct bgp_evpn_nh
*nh
, struct vty
*vty
,
4868 json_object
*json_array
)
4870 json_object
*json
= NULL
;
4871 char mac_buf
[ETHER_ADDR_STRLEN
];
4872 char prefix_buf
[PREFIX_STRLEN
];
4875 /* create a separate json object for each ES */
4876 json
= json_object_new_object();
4878 prefix_mac2str(&nh
->rmac
, mac_buf
, sizeof(mac_buf
));
4879 if (nh
->ref_pi
&& nh
->ref_pi
->net
)
4880 prefix2str(&nh
->ref_pi
->net
->p
, prefix_buf
, sizeof(prefix_buf
));
4882 prefix_buf
[0] = '\0';
4884 json_object_string_add(json
, "vrf", nh
->bgp_vrf
->name
);
4885 json_object_string_add(json
, "ip", nh
->nh_str
);
4886 json_object_string_add(json
, "rmac", mac_buf
);
4887 json_object_string_add(json
, "basePath", prefix_buf
);
4888 json_object_int_add(json
, "pathCount", listcount(nh
->pi_list
));
4890 vty_out(vty
, "%-15s %-15s %-17s %-10d %s\n", nh
->bgp_vrf
->name
,
4891 nh
->nh_str
, mac_buf
, listcount(nh
->pi_list
),
4895 /* add ES to the json array */
4897 json_object_array_add(json_array
, json
);
4900 struct nh_show_ctx
{
4905 static void bgp_evpn_nh_show_hash_cb(struct hash_bucket
*bucket
, void *ctxt
)
4907 struct bgp_evpn_nh
*nh
= (struct bgp_evpn_nh
*)bucket
->data
;
4908 struct nh_show_ctx
*wctx
= (struct nh_show_ctx
*)ctxt
;
4910 bgp_evpn_nh_show_entry(nh
, wctx
->vty
, wctx
->json
);
4913 /* Display all evpn nexthops */
4914 void bgp_evpn_nh_show(struct vty
*vty
, bool uj
)
4916 json_object
*json_array
= NULL
;
4917 struct bgp
*bgp_vrf
;
4918 struct listnode
*node
;
4919 struct nh_show_ctx wctx
;
4922 /* create an array of nexthops */
4923 json_array
= json_object_new_array();
4925 vty_out(vty
, "%-15s %-15s %-17s %-10s %s\n", "VRF", "IP",
4926 "RMAC", "#Paths", "Base Path");
4930 wctx
.json
= json_array
;
4932 /* walk through all vrfs */
4933 for (ALL_LIST_ELEMENTS_RO(bm
->bgp
, node
, bgp_vrf
)) {
4934 hash_iterate(bgp_vrf
->evpn_nh_table
,
4935 (void (*)(struct hash_bucket
*,
4936 void *))bgp_evpn_nh_show_hash_cb
,
4940 /* print the array of json-ESs */
4942 vty_json(vty
, json_array
);
4945 /*****************************************************************************/
4946 void bgp_evpn_mh_init(void)
4948 bm
->mh_info
= XCALLOC(MTYPE_BGP_EVPN_MH_INFO
, sizeof(*bm
->mh_info
));
4950 /* setup ES tables */
4951 RB_INIT(bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
);
4953 bgp_mh_info
->local_es_list
= list_new();
4954 listset_app_node_mem(bgp_mh_info
->local_es_list
);
4955 /* list of ESs with pending processing */
4956 bgp_mh_info
->pend_es_list
= list_new();
4957 listset_app_node_mem(bgp_mh_info
->pend_es_list
);
4959 bgp_mh_info
->ead_evi_rx
= BGP_EVPN_MH_EAD_EVI_RX_DEF
;
4960 bgp_mh_info
->ead_evi_tx
= BGP_EVPN_MH_EAD_EVI_TX_DEF
;
4961 bgp_mh_info
->ead_es_export_rtl
= list_new();
4962 bgp_mh_info
->ead_es_export_rtl
->cmp
=
4963 (int (*)(void *, void *))bgp_evpn_route_target_cmp
;
4964 bgp_mh_info
->ead_es_export_rtl
->del
= bgp_evpn_xxport_delete_ecomm
;
4966 /* config knobs - XXX add cli to control it */
4967 bgp_mh_info
->ead_evi_adv_for_down_links
= true;
4968 bgp_mh_info
->consistency_checking
= true;
4969 bgp_mh_info
->install_l3nhg
= false;
4970 bgp_mh_info
->host_routes_use_l3nhg
= BGP_EVPN_MH_USE_ES_L3NHG_DEF
;
4971 bgp_mh_info
->suppress_l3_ecomm_on_inactive_es
= true;
4972 bgp_mh_info
->bgp_evpn_nh_setup
= true;
4973 bgp_mh_info
->evi_per_es_frag
= BGP_EVPN_MAX_EVI_PER_ES_FRAG
;
4975 memset(&zero_esi_buf
, 0, sizeof(esi_t
));
4978 void bgp_evpn_mh_finish(void)
4980 struct bgp_evpn_es
*es
;
4981 struct bgp_evpn_es
*es_next
;
4983 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
4984 zlog_debug("evpn mh finish");
4986 RB_FOREACH_SAFE (es
, bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
,
4988 bgp_evpn_es_local_info_clear(es
, true);
4990 if (bgp_mh_info
->t_cons_check
)
4991 thread_cancel(&bgp_mh_info
->t_cons_check
);
4992 list_delete(&bgp_mh_info
->local_es_list
);
4993 list_delete(&bgp_mh_info
->pend_es_list
);
4994 list_delete(&bgp_mh_info
->ead_es_export_rtl
);
4996 XFREE(MTYPE_BGP_EVPN_MH_INFO
, bgp_mh_info
);
4999 /* This function is called when disable-ead-evi-rx knob flaps */
5000 void bgp_evpn_switch_ead_evi_rx(void)
5003 struct bgp_evpn_es
*es
;
5004 struct bgp_evpn_es_evi
*es_evi
;
5005 struct listnode
*evi_node
= NULL
;
5006 struct listnode
*evi_next
= NULL
;
5007 struct bgp_evpn_es_evi_vtep
*vtep
;
5008 struct listnode
*vtep_node
= NULL
;
5009 struct listnode
*vtep_next
= NULL
;
5011 bgp
= bgp_get_evpn();
5016 * Process all the remote es_evi_vteps and reevaluate if the es_evi_vtep
5019 RB_FOREACH(es
, bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
) {
5020 if (!CHECK_FLAG(es
->flags
, BGP_EVPNES_REMOTE
))
5023 for (ALL_LIST_ELEMENTS(es
->es_evi_list
, evi_node
, evi_next
,
5025 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_REMOTE
))
5028 for (ALL_LIST_ELEMENTS(es_evi
->es_evi_vtep_list
,
5029 vtep_node
, vtep_next
, vtep
))
5030 bgp_evpn_es_evi_vtep_re_eval_active(bgp
, vtep
);