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
== parent_pi
)
204 /* Add (or update) attribute to hash. */
205 attr_new
= bgp_attr_intern(parent_pi
->attr
);
207 /* Create new route with its attribute. */
208 pi
= info_make(parent_pi
->type
, BGP_ROUTE_IMPORTED
, 0,
209 parent_pi
->peer
, attr_new
, dest
);
210 SET_FLAG(pi
->flags
, BGP_PATH_VALID
);
211 bgp_path_info_extra_get(pi
);
212 pi
->extra
->parent
= bgp_path_info_lock(parent_pi
);
213 bgp_dest_lock_node((struct bgp_dest
*)parent_pi
->net
);
214 bgp_path_info_add(dest
, pi
);
216 if (attrhash_cmp(pi
->attr
, parent_pi
->attr
)
217 && !CHECK_FLAG(pi
->flags
, BGP_PATH_REMOVED
)) {
218 bgp_dest_unlock_node(dest
);
221 /* The attribute has changed. */
222 /* Add (or update) attribute to hash. */
223 attr_new
= bgp_attr_intern(parent_pi
->attr
);
225 /* Restore route, if needed. */
226 if (CHECK_FLAG(pi
->flags
, BGP_PATH_REMOVED
))
227 bgp_path_info_restore(dest
, pi
);
229 /* Mark if nexthop has changed. */
230 if (!IPV4_ADDR_SAME(&pi
->attr
->nexthop
, &attr_new
->nexthop
))
231 SET_FLAG(pi
->flags
, BGP_PATH_IGP_CHANGED
);
233 /* Unintern existing, set to new. */
234 bgp_attr_unintern(&pi
->attr
);
236 pi
->uptime
= bgp_clock();
239 /* Perform route selection and update zebra, if required. */
240 ret
= bgp_evpn_es_route_select_install(bgp
, es
, dest
);
242 bgp_dest_unlock_node(dest
);
247 /* Uninstall Type-1/Type-4 route entry from the ES routing table */
248 static int bgp_evpn_es_route_uninstall(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
249 struct prefix_evpn
*p
, struct bgp_path_info
*parent_pi
)
252 struct bgp_dest
*dest
;
253 struct bgp_path_info
*pi
;
255 if (!es
->route_table
)
258 /* Locate route within the ESI.
259 * NOTE: There is no RD here.
261 dest
= bgp_node_lookup(es
->route_table
, (struct prefix
*)p
);
265 /* Find matching route entry. */
266 for (pi
= bgp_dest_get_bgp_path_info(dest
); pi
; pi
= pi
->next
)
268 && (struct bgp_path_info
*)pi
->extra
->parent
==
273 bgp_dest_unlock_node(dest
);
277 /* Mark entry for deletion */
278 bgp_path_info_delete(dest
, pi
);
280 /* Perform route selection and update zebra, if required. */
281 ret
= bgp_evpn_es_route_select_install(bgp
, es
, dest
);
283 /* Unlock route node. */
284 bgp_dest_unlock_node(dest
);
289 /* Install or unistall a Type-4 route in the per-ES routing table */
290 int bgp_evpn_es_route_install_uninstall(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
291 afi_t afi
, safi_t safi
, struct prefix_evpn
*evp
,
292 struct bgp_path_info
*pi
, int install
)
297 ret
= bgp_evpn_es_route_install(bgp
, es
, evp
, pi
);
299 ret
= bgp_evpn_es_route_uninstall(bgp
, es
, evp
, pi
);
304 "%u: Failed to %s EVPN %s route in ESI %s",
306 install
? "install" : "uninstall",
313 /* Delete (and withdraw) local routes for specified ES from global and ES table.
314 * Also remove all remote routes from the per ES table. Invoked when ES
317 static void bgp_evpn_es_route_del_all(struct bgp
*bgp
, struct bgp_evpn_es
*es
)
319 struct bgp_dest
*dest
;
320 struct bgp_path_info
*pi
, *nextpi
;
322 /* de-activate the ES */
323 bgp_evpn_local_es_down(bgp
, es
);
324 bgp_evpn_local_type1_evi_route_del(bgp
, es
);
326 /* Walk this ES's routing table and delete all routes. */
327 for (dest
= bgp_table_top(es
->route_table
); dest
;
328 dest
= bgp_route_next(dest
)) {
329 for (pi
= bgp_dest_get_bgp_path_info(dest
);
330 (pi
!= NULL
) && (nextpi
= pi
->next
, 1); pi
= nextpi
) {
331 bgp_path_info_delete(dest
, pi
);
332 bgp_path_info_reap(dest
, pi
);
337 /*****************************************************************************
338 * Base APIs for creating MH routes (Type-1 or Type-4) on local ethernet
342 /* create or update local EVPN type1/type4 route entry.
345 * the ES table if ESR/EAD-ES (or)
346 * the VNI table if EAD-EVI (or)
347 * the global table if ESR/EAD-ES/EAD-EVI
349 * Note: vpn is applicable only to EAD-EVI routes (NULL for EAD-ES and
352 int bgp_evpn_mh_route_update(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
353 struct bgpevpn
*vpn
, afi_t afi
, safi_t safi
,
354 struct bgp_dest
*dest
, struct attr
*attr
,
355 struct bgp_path_info
**ri
, int *route_changed
)
357 struct bgp_path_info
*tmp_pi
= NULL
;
358 struct bgp_path_info
*local_pi
= NULL
; /* local route entry if any */
359 struct bgp_path_info
*remote_pi
= NULL
; /* remote route entry if any */
360 struct attr
*attr_new
= NULL
;
361 struct prefix_evpn
*evp
;
364 evp
= (struct prefix_evpn
*)bgp_dest_get_prefix(dest
);
367 /* locate the local and remote entries if any */
368 for (tmp_pi
= bgp_dest_get_bgp_path_info(dest
); tmp_pi
;
369 tmp_pi
= tmp_pi
->next
) {
370 if (tmp_pi
->peer
== bgp
->peer_self
371 && tmp_pi
->type
== ZEBRA_ROUTE_BGP
372 && tmp_pi
->sub_type
== BGP_ROUTE_STATIC
)
374 if (tmp_pi
->type
== ZEBRA_ROUTE_BGP
375 && tmp_pi
->sub_type
== BGP_ROUTE_IMPORTED
376 && CHECK_FLAG(tmp_pi
->flags
, BGP_PATH_VALID
))
380 /* we don't expect to see a remote_pi at this point as
381 * an ES route has {esi, vtep_ip} as the key in the ES-rt-table
382 * in the VNI-rt-table.
387 "%u ERROR: local es route for ESI: %s vtep %pI4 also learnt from remote",
388 bgp
->vrf_id
, es
? es
->esi_str
: "Null",
389 es
? &es
->originator_ip
: NULL
);
393 /* create or update the entry */
396 /* Add or update attribute to hash */
397 attr_new
= bgp_attr_intern(attr
);
399 /* Create new route with its attribute. */
400 tmp_pi
= info_make(ZEBRA_ROUTE_BGP
, BGP_ROUTE_STATIC
, 0,
401 bgp
->peer_self
, attr_new
, dest
);
402 SET_FLAG(tmp_pi
->flags
, BGP_PATH_VALID
);
404 if (evp
->prefix
.route_type
== BGP_EVPN_AD_ROUTE
) {
405 bgp_path_info_extra_get(tmp_pi
);
406 tmp_pi
->extra
->num_labels
= 1;
408 vni2label(vpn
->vni
, &tmp_pi
->extra
->label
[0]);
410 tmp_pi
->extra
->label
[0] = 0;
413 /* add the newly created path to the route-node */
414 bgp_path_info_add(dest
, tmp_pi
);
417 if (attrhash_cmp(tmp_pi
->attr
, attr
)
418 && !CHECK_FLAG(tmp_pi
->flags
, BGP_PATH_REMOVED
))
421 /* The attribute has changed.
422 * Add (or update) attribute to hash.
424 attr_new
= bgp_attr_intern(attr
);
425 bgp_path_info_set_flag(dest
, tmp_pi
,
426 BGP_PATH_ATTR_CHANGED
);
428 /* Restore route, if needed. */
429 if (CHECK_FLAG(tmp_pi
->flags
, BGP_PATH_REMOVED
))
430 bgp_path_info_restore(dest
, tmp_pi
);
432 /* Unintern existing, set to new. */
433 bgp_attr_unintern(&tmp_pi
->attr
);
434 tmp_pi
->attr
= attr_new
;
435 tmp_pi
->uptime
= bgp_clock();
439 if (*route_changed
) {
440 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
442 "local ES %s vni %u route-type %s nexthop %pI4 updated",
443 es
? es
->esi_str
: "Null", vpn
? vpn
->vni
: 0,
444 evp
->prefix
.route_type
== BGP_EVPN_ES_ROUTE
446 : (vpn
? "ead-evi" : "ead-es"),
447 &attr
->mp_nexthop_global_in
);
450 /* Return back the route entry. */
455 /* Delete local EVPN ESR (type-4) and EAD (type-1) route
457 * Note: vpn is applicable only to EAD-EVI routes (NULL for EAD-ES and
460 static int bgp_evpn_mh_route_delete(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
462 struct bgp_evpn_es_frag
*es_frag
,
463 struct prefix_evpn
*p
)
465 afi_t afi
= AFI_L2VPN
;
466 safi_t safi
= SAFI_EVPN
;
467 struct bgp_path_info
*pi
;
468 struct bgp_dest
*dest
= NULL
; /* dest in esi table */
469 struct bgp_dest
*global_dest
= NULL
; /* dest in global table */
470 struct bgp_table
*rt_table
;
471 struct prefix_rd
*prd
;
474 rt_table
= vpn
->route_table
;
477 rt_table
= es
->route_table
;
481 /* First, locate the route node within the ESI or VNI.
482 * If it doesn't exist, ther is nothing to do.
483 * Note: there is no RD here.
485 dest
= bgp_node_lookup(rt_table
, (struct prefix
*)p
);
489 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
491 "local ES %s vni %u route-type %s nexthop %pI4 delete",
492 es
->esi_str
, vpn
? vpn
->vni
: 0,
493 p
->prefix
.route_type
== BGP_EVPN_ES_ROUTE
495 : (vpn
? "ead-evi" : "ead-es"),
498 /* Next, locate route node in the global EVPN routing table.
499 * Note that this table is a 2-level tree (RD-level + Prefix-level)
502 bgp_global_evpn_node_lookup(bgp
->rib
[afi
][safi
], afi
, safi
,
503 (const struct prefix_evpn
*)p
, prd
);
506 /* Delete route entry in the global EVPN table. */
507 delete_evpn_route_entry(bgp
, afi
, safi
, global_dest
, &pi
);
509 /* Schedule for processing - withdraws to peers happen from
513 bgp_process(bgp
, global_dest
, afi
, safi
);
514 bgp_dest_unlock_node(global_dest
);
518 * Delete route entry in the ESI or VNI routing table.
519 * This can just be removed.
521 delete_evpn_route_entry(bgp
, afi
, safi
, dest
, &pi
);
523 bgp_path_info_reap(dest
, pi
);
524 bgp_dest_unlock_node(dest
);
529 * This function is called when the VNI RD changes.
530 * Delete all EAD/EVI local routes for this VNI from the global routing table.
531 * These routes are scheduled for withdraw from peers.
533 int delete_global_ead_evi_routes(struct bgp
*bgp
, struct bgpevpn
*vpn
)
537 struct bgp_dest
*rdrn
, *rn
;
538 struct bgp_table
*table
;
539 struct bgp_path_info
*pi
;
544 /* Find the RD node for the VNI in the global table */
545 rdrn
= bgp_node_lookup(bgp
->rib
[afi
][safi
], (struct prefix
*)&vpn
->prd
);
546 if (rdrn
&& bgp_dest_has_bgp_path_info_data(rdrn
)) {
547 table
= bgp_dest_get_bgp_table_info(rdrn
);
550 * Iterate over all the routes in this table and delete EAD/EVI
553 for (rn
= bgp_table_top(table
); rn
; rn
= bgp_route_next(rn
)) {
554 struct prefix_evpn
*evp
= (struct prefix_evpn
*)&rn
->p
;
556 if (evp
->prefix
.route_type
!= BGP_EVPN_AD_ROUTE
)
559 delete_evpn_route_entry(bgp
, afi
, safi
, rn
, &pi
);
561 bgp_process(bgp
, rn
, afi
, safi
);
565 /* Unlock RD node. */
567 bgp_dest_unlock_node(rdrn
);
572 /*****************************************************************************
573 * Ethernet Segment (Type-4) Routes
574 * ESRs are used for DF election. Currently service-carving described in
575 * RFC 7432 is NOT supported. Instead preference based DF election is
577 * Reference: draft-ietf-bess-evpn-pref-df
579 /* Build extended community for EVPN ES (type-4) route */
580 static void bgp_evpn_type4_route_extcomm_build(struct bgp_evpn_es
*es
,
583 struct ecommunity ecom_encap
;
584 struct ecommunity ecom_es_rt
;
585 struct ecommunity ecom_df
;
586 struct ecommunity_val eval
;
587 struct ecommunity_val eval_es_rt
;
588 struct ecommunity_val eval_df
;
589 bgp_encap_types tnl_type
;
593 tnl_type
= BGP_ENCAP_TYPE_VXLAN
;
594 memset(&ecom_encap
, 0, sizeof(ecom_encap
));
595 encode_encap_extcomm(tnl_type
, &eval
);
597 ecom_encap
.unit_size
= ECOMMUNITY_SIZE
;
598 ecom_encap
.val
= (uint8_t *)eval
.val
;
599 bgp_attr_set_ecommunity(attr
, ecommunity_dup(&ecom_encap
));
602 memset(&mac
, 0, sizeof(mac
));
603 memset(&ecom_es_rt
, 0, sizeof(ecom_es_rt
));
604 es_get_system_mac(&es
->esi
, &mac
);
605 encode_es_rt_extcomm(&eval_es_rt
, &mac
);
607 ecom_es_rt
.unit_size
= ECOMMUNITY_SIZE
;
608 ecom_es_rt
.val
= (uint8_t *)eval_es_rt
.val
;
609 bgp_attr_set_ecommunity(
611 ecommunity_merge(bgp_attr_get_ecommunity(attr
), &ecom_es_rt
));
613 /* DF election extended community */
614 memset(&ecom_df
, 0, sizeof(ecom_df
));
615 encode_df_elect_extcomm(&eval_df
, es
->df_pref
);
617 ecom_df
.val
= (uint8_t *)eval_df
.val
;
618 bgp_attr_set_ecommunity(
620 ecommunity_merge(bgp_attr_get_ecommunity(attr
), &ecom_df
));
623 /* Create or update local type-4 route */
624 static int bgp_evpn_type4_route_update(struct bgp
*bgp
,
625 struct bgp_evpn_es
*es
, struct prefix_evpn
*p
)
628 int route_changed
= 0;
629 afi_t afi
= AFI_L2VPN
;
630 safi_t safi
= SAFI_EVPN
;
632 struct attr
*attr_new
= NULL
;
633 struct bgp_dest
*dest
= NULL
;
634 struct bgp_path_info
*pi
= NULL
;
636 memset(&attr
, 0, sizeof(attr
));
638 /* Build path-attribute for this route. */
639 bgp_attr_default_set(&attr
, bgp
, BGP_ORIGIN_IGP
);
640 attr
.nexthop
= es
->originator_ip
;
641 attr
.mp_nexthop_global_in
= es
->originator_ip
;
642 attr
.mp_nexthop_len
= BGP_ATTR_NHLEN_IPV4
;
644 /* Set up extended community. */
645 bgp_evpn_type4_route_extcomm_build(es
, &attr
);
647 /* First, create (or fetch) route node within the ESI. */
648 /* NOTE: There is no RD here. */
649 dest
= bgp_node_get(es
->route_table
, (struct prefix
*)p
);
651 /* Create or update route entry. */
652 ret
= bgp_evpn_mh_route_update(bgp
, es
, NULL
, afi
, safi
, dest
, &attr
,
653 &pi
, &route_changed
);
657 "%u ERROR: Failed to updated ES route ESI: %s VTEP %pI4",
658 bgp
->vrf_id
, es
->esi_str
, &es
->originator_ip
);
663 /* Perform route selection;
664 * this is just to set the flags correctly
665 * as local route in the ES always wins.
667 bgp_evpn_es_route_select_install(bgp
, es
, dest
);
668 bgp_dest_unlock_node(dest
);
670 /* If this is a new route or some attribute has changed, export the
671 * route to the global table. The route will be advertised to peers
672 * from there. Note that this table is a 2-level tree (RD-level +
673 * Prefix-level) similar to L3VPN routes.
676 struct bgp_path_info
*global_pi
;
678 dest
= bgp_global_evpn_node_get(bgp
->rib
[afi
][safi
], afi
, safi
,
679 p
, &es
->es_base_frag
->prd
);
680 bgp_evpn_mh_route_update(bgp
, es
, NULL
, afi
, safi
, dest
,
681 attr_new
, &global_pi
, &route_changed
);
683 /* Schedule for processing and unlock node. */
684 bgp_process(bgp
, dest
, afi
, safi
);
685 bgp_dest_unlock_node(dest
);
688 /* Unintern temporary. */
689 aspath_unintern(&attr
.aspath
);
693 /* Delete local type-4 route */
694 static int bgp_evpn_type4_route_delete(struct bgp
*bgp
,
695 struct bgp_evpn_es
*es
, struct prefix_evpn
*p
)
697 if (!es
->es_base_frag
)
700 return bgp_evpn_mh_route_delete(bgp
, es
, NULL
/* l2vni */,
701 es
->es_base_frag
, p
);
704 /* Process remote/received EVPN type-4 route (advertise or withdraw) */
705 int bgp_evpn_type4_route_process(struct peer
*peer
, afi_t afi
, safi_t safi
,
706 struct attr
*attr
, uint8_t *pfx
, int psize
,
712 struct in_addr vtep_ip
;
713 struct prefix_rd prd
;
714 struct prefix_evpn p
;
716 /* Type-4 route should be either 23 or 35 bytes
717 * RD (8), ESI (10), ip-len (1), ip (4 or 16)
719 if (psize
!= BGP_EVPN_TYPE4_V4_PSIZE
&&
720 psize
!= BGP_EVPN_TYPE4_V6_PSIZE
) {
721 flog_err(EC_BGP_EVPN_ROUTE_INVALID
,
722 "%u:%s - Rx EVPN Type-4 NLRI with invalid length %d",
723 peer
->bgp
->vrf_id
, peer
->host
, psize
);
728 prd
.family
= AF_UNSPEC
;
730 memcpy(&prd
.val
, pfx
, RD_BYTES
);
734 memcpy(&esi
, pfx
, ESI_BYTES
);
740 if (ipaddr_len
== IPV4_MAX_BITLEN
) {
741 memcpy(&vtep_ip
, pfx
, IPV4_MAX_BYTELEN
);
744 EC_BGP_EVPN_ROUTE_INVALID
,
745 "%u:%s - Rx EVPN Type-4 NLRI with unsupported IP address length %d",
746 peer
->bgp
->vrf_id
, peer
->host
, ipaddr_len
);
750 build_evpn_type4_prefix(&p
, &esi
, vtep_ip
);
751 /* Process the route. */
753 ret
= bgp_update(peer
, (struct prefix
*)&p
, addpath_id
, attr
,
754 afi
, safi
, ZEBRA_ROUTE_BGP
, BGP_ROUTE_NORMAL
,
755 &prd
, NULL
, 0, 0, NULL
);
757 ret
= bgp_withdraw(peer
, (struct prefix
*)&p
, addpath_id
, attr
,
758 afi
, safi
, ZEBRA_ROUTE_BGP
, BGP_ROUTE_NORMAL
,
759 &prd
, NULL
, 0, NULL
);
764 /* Check if a prefix belongs to the local ES */
765 static bool bgp_evpn_type4_prefix_match(struct prefix_evpn
*p
,
766 struct bgp_evpn_es
*es
)
768 return (p
->prefix
.route_type
== BGP_EVPN_ES_ROUTE
) &&
769 !memcmp(&p
->prefix
.es_addr
.esi
, &es
->esi
, sizeof(esi_t
));
772 /* Import remote ESRs on local ethernet segment add */
773 static int bgp_evpn_type4_remote_routes_import(struct bgp
*bgp
,
774 struct bgp_evpn_es
*es
, bool install
)
779 struct bgp_dest
*rd_dest
, *dest
;
780 struct bgp_table
*table
;
781 struct bgp_path_info
*pi
;
786 /* Walk entire global routing table and evaluate routes which could be
787 * imported into this Ethernet Segment.
789 for (rd_dest
= bgp_table_top(bgp
->rib
[afi
][safi
]); rd_dest
;
790 rd_dest
= bgp_route_next(rd_dest
)) {
791 table
= bgp_dest_get_bgp_table_info(rd_dest
);
795 for (dest
= bgp_table_top(table
); dest
;
796 dest
= bgp_route_next(dest
)) {
797 struct prefix_evpn
*evp
=
798 (struct prefix_evpn
*)bgp_dest_get_prefix(dest
);
800 for (pi
= bgp_dest_get_bgp_path_info(dest
); pi
;
803 * Consider "valid" remote routes applicable for
806 if (!(CHECK_FLAG(pi
->flags
, BGP_PATH_VALID
)
807 && pi
->type
== ZEBRA_ROUTE_BGP
808 && pi
->sub_type
== BGP_ROUTE_NORMAL
))
811 if (!bgp_evpn_type4_prefix_match(evp
, es
))
815 ret
= bgp_evpn_es_route_install(
818 ret
= bgp_evpn_es_route_uninstall(
824 "Failed to %s EVPN %pFX route in ESI %s",
829 bgp_dest_unlock_node(rd_dest
);
830 bgp_dest_unlock_node(dest
);
839 /*****************************************************************************
840 * Ethernet Auto Discovery (EAD/Type-1) route handling
841 * There are two types of EAD routes -
842 * 1. EAD-per-ES - Key: {ESI, ET=0xffffffff}
843 * 2. EAD-per-EVI - Key: {ESI, ET=0}
846 /* Extended communities associated with EAD-per-ES */
848 bgp_evpn_type1_es_route_extcomm_build(struct bgp_evpn_es_frag
*es_frag
,
851 struct ecommunity ecom_encap
;
852 struct ecommunity ecom_esi_label
;
853 struct ecommunity_val eval
;
854 struct ecommunity_val eval_esi_label
;
855 bgp_encap_types tnl_type
;
856 struct listnode
*evi_node
, *rt_node
;
857 struct ecommunity
*ecom
;
858 struct bgp_evpn_es_evi
*es_evi
;
861 tnl_type
= BGP_ENCAP_TYPE_VXLAN
;
862 memset(&ecom_encap
, 0, sizeof(ecom_encap
));
863 encode_encap_extcomm(tnl_type
, &eval
);
865 ecom_encap
.unit_size
= ECOMMUNITY_SIZE
;
866 ecom_encap
.val
= (uint8_t *)eval
.val
;
867 bgp_attr_set_ecommunity(attr
, ecommunity_dup(&ecom_encap
));
870 encode_esi_label_extcomm(&eval_esi_label
,
871 false /*single_active*/);
872 ecom_esi_label
.size
= 1;
873 ecom_esi_label
.unit_size
= ECOMMUNITY_SIZE
;
874 ecom_esi_label
.val
= (uint8_t *)eval_esi_label
.val
;
875 bgp_attr_set_ecommunity(attr
,
876 ecommunity_merge(bgp_attr_get_ecommunity(attr
),
879 /* Add export RTs for all L2-VNIs associated with this ES */
880 /* XXX - suppress EAD-ES advertisment if there are no EVIs associated
883 if (listcount(bgp_mh_info
->ead_es_export_rtl
)) {
884 for (ALL_LIST_ELEMENTS_RO(bgp_mh_info
->ead_es_export_rtl
,
886 bgp_attr_set_ecommunity(
887 attr
, ecommunity_merge(attr
->ecommunity
, ecom
));
889 for (ALL_LIST_ELEMENTS_RO(es_frag
->es_evi_frag_list
, evi_node
,
891 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
893 for (ALL_LIST_ELEMENTS_RO(es_evi
->vpn
->export_rtl
,
895 bgp_attr_set_ecommunity(
896 attr
, ecommunity_merge(attr
->ecommunity
,
902 /* Extended communities associated with EAD-per-EVI */
903 static void bgp_evpn_type1_evi_route_extcomm_build(struct bgp_evpn_es
*es
,
904 struct bgpevpn
*vpn
, struct attr
*attr
)
906 struct ecommunity ecom_encap
;
907 struct ecommunity_val eval
;
908 bgp_encap_types tnl_type
;
909 struct listnode
*rt_node
;
910 struct ecommunity
*ecom
;
913 tnl_type
= BGP_ENCAP_TYPE_VXLAN
;
914 memset(&ecom_encap
, 0, sizeof(ecom_encap
));
915 encode_encap_extcomm(tnl_type
, &eval
);
917 ecom_encap
.unit_size
= ECOMMUNITY_SIZE
;
918 ecom_encap
.val
= (uint8_t *)eval
.val
;
919 bgp_attr_set_ecommunity(attr
, ecommunity_dup(&ecom_encap
));
921 /* Add export RTs for the L2-VNI */
922 for (ALL_LIST_ELEMENTS_RO(vpn
->export_rtl
, rt_node
, ecom
))
923 bgp_attr_set_ecommunity(
925 ecommunity_merge(bgp_attr_get_ecommunity(attr
), ecom
));
928 /* Update EVPN EAD (type-1) route -
929 * vpn - valid for EAD-EVI routes and NULL for EAD-ES routes
931 static int bgp_evpn_type1_route_update(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
933 struct bgp_evpn_es_frag
*es_frag
,
934 struct prefix_evpn
*p
)
937 afi_t afi
= AFI_L2VPN
;
938 safi_t safi
= SAFI_EVPN
;
940 struct attr
*attr_new
= NULL
;
941 struct bgp_dest
*dest
= NULL
;
942 struct bgp_path_info
*pi
= NULL
;
943 int route_changed
= 0;
944 struct prefix_rd
*global_rd
;
946 memset(&attr
, 0, sizeof(attr
));
948 /* Build path-attribute for this route. */
949 bgp_attr_default_set(&attr
, bgp
, BGP_ORIGIN_IGP
);
950 attr
.nexthop
= es
->originator_ip
;
951 attr
.mp_nexthop_global_in
= es
->originator_ip
;
952 attr
.mp_nexthop_len
= BGP_ATTR_NHLEN_IPV4
;
955 /* EAD-EVI route update */
957 vni2label(vpn
->vni
, &(attr
.label
));
959 /* Set up extended community */
960 bgp_evpn_type1_evi_route_extcomm_build(es
, vpn
, &attr
);
962 /* First, create (or fetch) route node within the VNI. */
963 dest
= bgp_node_get(vpn
->route_table
, (struct prefix
*)p
);
965 /* Create or update route entry. */
966 ret
= bgp_evpn_mh_route_update(bgp
, es
, vpn
, afi
, safi
, dest
,
967 &attr
, &pi
, &route_changed
);
971 "%u Failed to update EAD-EVI route ESI: %s VNI %u VTEP %pI4",
972 bgp
->vrf_id
, es
->esi_str
, vpn
->vni
,
974 global_rd
= &vpn
->prd
;
976 /* EAD-ES route update */
977 /* MPLS label is 0 for EAD-ES route */
979 /* Set up extended community */
980 bgp_evpn_type1_es_route_extcomm_build(es_frag
, &attr
);
982 /* First, create (or fetch) route node within the ES. */
983 /* NOTE: There is no RD here. */
984 /* XXX: fragment ID must be included as a part of the prefix. */
985 dest
= bgp_node_get(es
->route_table
, (struct prefix
*)p
);
987 /* Create or update route entry. */
988 ret
= bgp_evpn_mh_route_update(bgp
, es
, vpn
, afi
, safi
, dest
,
989 &attr
, &pi
, &route_changed
);
993 "%u ERROR: Failed to updated EAD-ES route ESI: %s VTEP %pI4",
994 bgp
->vrf_id
, es
->esi_str
, &es
->originator_ip
);
996 global_rd
= &es_frag
->prd
;
1001 attr_new
= pi
->attr
;
1003 /* Perform route selection;
1004 * this is just to set the flags correctly as local route in
1005 * the ES always wins.
1007 evpn_route_select_install(bgp
, vpn
, dest
);
1008 bgp_dest_unlock_node(dest
);
1010 /* If this is a new route or some attribute has changed, export the
1011 * route to the global table. The route will be advertised to peers
1012 * from there. Note that this table is a 2-level tree (RD-level +
1013 * Prefix-level) similar to L3VPN routes.
1015 if (route_changed
) {
1016 struct bgp_path_info
*global_pi
;
1018 dest
= bgp_global_evpn_node_get(bgp
->rib
[afi
][safi
], afi
, safi
,
1020 bgp_evpn_mh_route_update(bgp
, es
, vpn
, afi
, safi
, dest
,
1021 attr_new
, &global_pi
, &route_changed
);
1023 /* Schedule for processing and unlock node. */
1024 bgp_process(bgp
, dest
, afi
, safi
);
1025 bgp_dest_unlock_node(dest
);
1028 /* Unintern temporary. */
1029 aspath_unintern(&attr
.aspath
);
1034 * This function is called when the export RT for a VNI changes.
1035 * Update all type-1 local routes for this VNI from VNI/ES tables and the global
1036 * table and advertise these routes to peers.
1039 static void bgp_evpn_ead_es_route_update(struct bgp
*bgp
,
1040 struct bgp_evpn_es
*es
)
1042 struct listnode
*node
;
1043 struct bgp_evpn_es_frag
*es_frag
;
1044 struct prefix_evpn p
;
1046 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_ES_ETH_TAG
, &es
->esi
,
1048 for (ALL_LIST_ELEMENTS_RO(es
->es_frag_list
, node
, es_frag
)) {
1049 if (!listcount(es_frag
->es_evi_frag_list
))
1052 p
.prefix
.ead_addr
.frag_id
= es_frag
->rd_id
;
1053 if (bgp_evpn_type1_route_update(bgp
, es
, NULL
, es_frag
, &p
))
1055 EC_BGP_EVPN_ROUTE_CREATE
,
1056 "EAD-ES route creation failure for ESI %s frag %u",
1057 es
->esi_str
, es_frag
->rd_id
);
1061 static void bgp_evpn_ead_evi_route_update(struct bgp
*bgp
,
1062 struct bgp_evpn_es
*es
,
1063 struct bgpevpn
*vpn
,
1064 struct prefix_evpn
*p
)
1066 if (bgp_evpn_type1_route_update(bgp
, es
, vpn
, NULL
, p
))
1067 flog_err(EC_BGP_EVPN_ROUTE_CREATE
,
1068 "EAD-EVI route creation failure for ESI %s VNI %u",
1069 es
->esi_str
, vpn
->vni
);
1072 void update_type1_routes_for_evi(struct bgp
*bgp
, struct bgpevpn
*vpn
)
1074 struct prefix_evpn p
;
1075 struct bgp_evpn_es
*es
;
1076 struct bgp_evpn_es_evi
*es_evi
;
1079 RB_FOREACH (es_evi
, bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
) {
1082 if (es_evi
->vpn
!= vpn
)
1086 bgp_evpn_ead_es_route_update(bgp
, es
);
1088 /* Update EAD-EVI */
1089 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
)) {
1090 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_EVI_ETH_TAG
,
1091 &es
->esi
, es
->originator_ip
);
1092 bgp_evpn_ead_evi_route_update(bgp
, es
, vpn
, &p
);
1097 /* Delete local Type-1 route */
1098 static void bgp_evpn_ead_es_route_delete(struct bgp
*bgp
,
1099 struct bgp_evpn_es
*es
)
1101 struct listnode
*node
;
1102 struct bgp_evpn_es_frag
*es_frag
;
1103 struct prefix_evpn p
;
1105 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_ES_ETH_TAG
, &es
->esi
,
1107 for (ALL_LIST_ELEMENTS_RO(es
->es_frag_list
, node
, es_frag
)) {
1108 p
.prefix
.ead_addr
.frag_id
= es_frag
->rd_id
;
1109 bgp_evpn_mh_route_delete(bgp
, es
, NULL
, es_frag
, &p
);
1113 static int bgp_evpn_ead_evi_route_delete(struct bgp
*bgp
,
1114 struct bgp_evpn_es
*es
,
1115 struct bgpevpn
*vpn
,
1116 struct prefix_evpn
*p
)
1118 return bgp_evpn_mh_route_delete(bgp
, es
, vpn
, NULL
, p
);
1121 /* Generate EAD-EVI for all VNIs */
1122 static void bgp_evpn_local_type1_evi_route_add(struct bgp
*bgp
,
1123 struct bgp_evpn_es
*es
)
1125 struct listnode
*evi_node
;
1126 struct prefix_evpn p
;
1127 struct bgp_evpn_es_evi
*es_evi
;
1129 /* EAD-per-EVI routes have been suppressed */
1130 if (!bgp_mh_info
->ead_evi_tx
)
1133 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
))
1134 /* EAD-EVI route add for this ES is already done */
1137 SET_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
);
1138 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_EVI_ETH_TAG
,
1139 &es
->esi
, es
->originator_ip
);
1141 for (ALL_LIST_ELEMENTS_RO(es
->es_evi_list
, evi_node
, es_evi
)) {
1142 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
1144 bgp_evpn_ead_evi_route_update(bgp
, es
, es_evi
->vpn
, &p
);
1149 * Withdraw EAD-EVI for all VNIs
1151 static void bgp_evpn_local_type1_evi_route_del(struct bgp
*bgp
,
1152 struct bgp_evpn_es
*es
)
1154 struct listnode
*evi_node
;
1155 struct prefix_evpn p
;
1156 struct bgp_evpn_es_evi
*es_evi
;
1158 /* Delete and withdraw locally learnt EAD-EVI route */
1159 if (!CHECK_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
))
1160 /* EAD-EVI route has not been advertised for this ES */
1163 UNSET_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
);
1164 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_EVI_ETH_TAG
,
1165 &es
->esi
, es
->originator_ip
);
1166 for (ALL_LIST_ELEMENTS_RO(es
->es_evi_list
, evi_node
, es_evi
)) {
1167 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
1169 if (bgp_evpn_mh_route_delete(bgp
, es
, es_evi
->vpn
, NULL
, &p
))
1170 flog_err(EC_BGP_EVPN_ROUTE_CREATE
,
1171 "%u: Type4 route creation failure for ESI %s",
1172 bgp
->vrf_id
, es
->esi_str
);
1177 * Process received EVPN type-1 route (advertise or withdraw).
1179 int bgp_evpn_type1_route_process(struct peer
*peer
, afi_t afi
, safi_t safi
,
1180 struct attr
*attr
, uint8_t *pfx
, int psize
,
1181 uint32_t addpath_id
)
1184 struct prefix_rd prd
;
1188 struct in_addr vtep_ip
;
1189 struct prefix_evpn p
;
1191 if (psize
!= BGP_EVPN_TYPE1_PSIZE
) {
1192 flog_err(EC_BGP_EVPN_ROUTE_INVALID
,
1193 "%u:%s - Rx EVPN Type-1 NLRI with invalid length %d",
1194 peer
->bgp
->vrf_id
, peer
->host
, psize
);
1198 /* Make prefix_rd */
1199 prd
.family
= AF_UNSPEC
;
1201 memcpy(&prd
.val
, pfx
, RD_BYTES
);
1205 memcpy(&esi
, pfx
, ESI_BYTES
);
1208 /* Copy Ethernet Tag */
1209 memcpy(ð_tag
, pfx
, EVPN_ETH_TAG_BYTES
);
1210 eth_tag
= ntohl(eth_tag
);
1211 pfx
+= EVPN_ETH_TAG_BYTES
;
1213 memcpy(&label
, pfx
, BGP_LABEL_BYTES
);
1215 /* EAD route prefix doesn't include the nexthop in the global
1218 vtep_ip
.s_addr
= INADDR_ANY
;
1219 build_evpn_type1_prefix(&p
, eth_tag
, &esi
, vtep_ip
);
1220 /* Process the route. */
1222 ret
= bgp_update(peer
, (struct prefix
*)&p
, addpath_id
, attr
,
1223 afi
, safi
, ZEBRA_ROUTE_BGP
, BGP_ROUTE_NORMAL
,
1224 &prd
, NULL
, 0, 0, NULL
);
1226 ret
= bgp_withdraw(peer
, (struct prefix
*)&p
, addpath_id
, attr
,
1227 afi
, safi
, ZEBRA_ROUTE_BGP
, BGP_ROUTE_NORMAL
,
1228 &prd
, NULL
, 0, NULL
);
1233 void bgp_evpn_mh_config_ead_export_rt(struct bgp
*bgp
,
1234 struct ecommunity
*ecomcfg
, bool del
)
1236 struct listnode
*node
, *nnode
, *node_to_del
;
1237 struct ecommunity
*ecom
;
1238 struct bgp_evpn_es
*es
;
1241 if (ecomcfg
== NULL
) {
1242 /* Reset to default and process all routes. */
1243 for (ALL_LIST_ELEMENTS(bgp_mh_info
->ead_es_export_rtl
,
1244 node
, nnode
, ecom
)) {
1245 ecommunity_free(&ecom
);
1246 list_delete_node(bgp_mh_info
->ead_es_export_rtl
,
1251 /* Delete a specific export RT */
1255 for (ALL_LIST_ELEMENTS(bgp_mh_info
->ead_es_export_rtl
,
1256 node
, nnode
, ecom
)) {
1257 if (ecommunity_match(ecom
, ecomcfg
)) {
1258 ecommunity_free(&ecom
);
1264 assert(node_to_del
);
1265 list_delete_node(bgp_mh_info
->ead_es_export_rtl
,
1269 listnode_add_sort(bgp_mh_info
->ead_es_export_rtl
, ecomcfg
);
1272 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
1273 zlog_debug("local ES del/re-add EAD route on export RT change");
1275 * walk through all active ESs withdraw the old EAD and
1276 * generate a new one
1278 RB_FOREACH (es
, bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
) {
1279 if (!bgp_evpn_is_es_local(es
) ||
1280 !bgp_evpn_local_es_is_active(es
))
1283 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
1285 "local ES %s del/re-add EAD route on export RT change",
1289 * withdraw EAD-ES. XXX - this should technically not be
1290 * needed; can be removed after testing
1292 bgp_evpn_ead_es_route_delete(bgp
, es
);
1294 /* generate EAD-ES */
1295 bgp_evpn_ead_es_route_update(bgp
, es
);
1299 /*****************************************************************************/
1300 /* Ethernet Segment Management
1301 * 1. Ethernet Segment is a collection of links attached to the same
1302 * server (MHD) or switch (MHN)
1303 * 2. An Ethernet Segment can span multiple PEs and is identified by the
1305 * 3. Local ESs are configured in zebra and sent to BGP
1306 * 4. Remote ESs are created by BGP when one or more ES-EVIs reference it i.e.
1307 * created on first reference and release on last de-reference
1308 * 5. An ES can be both local and remote. Infact most local ESs are expected
1309 * to have an ES peer.
1312 /* A list of remote VTEPs is maintained for each ES. This list includes -
1313 * 1. VTEPs for which we have imported the ESR i.e. ES-peers
1314 * 2. VTEPs that have an "active" ES-EVI VTEP i.e. EAD-per-ES and EAD-per-EVI
1315 * have been imported into one or more VNIs
1317 static int bgp_evpn_es_vtep_cmp(void *p1
, void *p2
)
1319 const struct bgp_evpn_es_vtep
*es_vtep1
= p1
;
1320 const struct bgp_evpn_es_vtep
*es_vtep2
= p2
;
1322 return es_vtep1
->vtep_ip
.s_addr
- es_vtep2
->vtep_ip
.s_addr
;
1325 static struct bgp_evpn_es_vtep
*bgp_evpn_es_vtep_new(struct bgp_evpn_es
*es
,
1326 struct in_addr vtep_ip
)
1328 struct bgp_evpn_es_vtep
*es_vtep
;
1330 es_vtep
= XCALLOC(MTYPE_BGP_EVPN_ES_VTEP
, sizeof(*es_vtep
));
1333 es_vtep
->vtep_ip
.s_addr
= vtep_ip
.s_addr
;
1334 inet_ntop(AF_INET
, &es_vtep
->vtep_ip
, es_vtep
->vtep_str
,
1335 sizeof(es_vtep
->vtep_str
));
1336 listnode_init(&es_vtep
->es_listnode
, es_vtep
);
1337 listnode_add_sort(es
->es_vtep_list
, &es_vtep
->es_listnode
);
1342 static void bgp_evpn_es_vtep_free(struct bgp_evpn_es_vtep
*es_vtep
)
1344 struct bgp_evpn_es
*es
= es_vtep
->es
;
1346 if (CHECK_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ESR
) ||
1348 /* as long as there is some reference we can't free it */
1351 list_delete_node(es
->es_vtep_list
, &es_vtep
->es_listnode
);
1352 XFREE(MTYPE_BGP_EVPN_ES_VTEP
, es_vtep
);
1355 /* check if VTEP is already part of the list */
1356 static struct bgp_evpn_es_vtep
*bgp_evpn_es_vtep_find(struct bgp_evpn_es
*es
,
1357 struct in_addr vtep_ip
)
1359 struct listnode
*node
= NULL
;
1360 struct bgp_evpn_es_vtep
*es_vtep
;
1362 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
1363 if (es_vtep
->vtep_ip
.s_addr
== vtep_ip
.s_addr
)
1369 /* Send the remote ES to zebra for NHG programming */
1370 static int bgp_zebra_send_remote_es_vtep(struct bgp
*bgp
,
1371 struct bgp_evpn_es_vtep
*es_vtep
, bool add
)
1373 struct bgp_evpn_es
*es
= es_vtep
->es
;
1378 if (!zclient
|| zclient
->sock
< 0)
1381 /* Don't try to register if Zebra doesn't know of this instance. */
1382 if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp
)) {
1383 if (BGP_DEBUG(zebra
, ZEBRA
))
1384 zlog_debug("No zebra instance, not installing remote es %s",
1389 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ESR
)
1390 flags
|= ZAPI_ES_VTEP_FLAG_ESR_RXED
;
1395 zclient_create_header(s
,
1396 add
? ZEBRA_REMOTE_ES_VTEP_ADD
: ZEBRA_REMOTE_ES_VTEP_DEL
,
1398 stream_put(s
, &es
->esi
, sizeof(esi_t
));
1399 stream_put_ipv4(s
, es_vtep
->vtep_ip
.s_addr
);
1401 stream_putl(s
, flags
);
1402 stream_putc(s
, es_vtep
->df_alg
);
1403 stream_putw(s
, es_vtep
->df_pref
);
1406 stream_putw_at(s
, 0, stream_get_endp(s
));
1408 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1409 zlog_debug("Tx %s Remote ESI %s VTEP %pI4", add
? "ADD" : "DEL",
1410 es
->esi_str
, &es_vtep
->vtep_ip
);
1412 frrtrace(3, frr_bgp
, evpn_mh_vtep_zsend
, add
, es
, es_vtep
);
1414 return zclient_send_message(zclient
);
1417 static void bgp_evpn_es_vtep_re_eval_active(struct bgp
*bgp
,
1418 struct bgp_evpn_es_vtep
*es_vtep
,
1424 old_active
= CHECK_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
);
1425 /* currently we need an active EVI reference to use the VTEP as
1426 * a nexthop. this may change...
1428 if (es_vtep
->evi_cnt
)
1429 SET_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
);
1431 UNSET_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
);
1433 new_active
= CHECK_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
);
1435 if ((old_active
!= new_active
) || (new_active
&& param_change
)) {
1437 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1438 zlog_debug("es %s vtep %pI4 %s df %u/%u",
1439 es_vtep
->es
->esi_str
, &es_vtep
->vtep_ip
,
1440 new_active
? "active" : "inactive",
1441 es_vtep
->df_alg
, es_vtep
->df_pref
);
1443 /* send remote ES to zebra */
1444 bgp_zebra_send_remote_es_vtep(bgp
, es_vtep
, new_active
);
1446 /* The NHG is updated first for efficient failover handling.
1447 * Note the NHG can be de-activated while there are bgp
1448 * routes referencing it. Zebra is capable of handling that
1449 * elegantly by holding the NHG till all routes using it are
1452 bgp_evpn_l3nhg_update_on_vtep_chg(es_vtep
->es
);
1453 /* queue up the es for background consistency checks */
1454 bgp_evpn_es_cons_checks_pend_add(es_vtep
->es
);
1458 static struct bgp_evpn_es_vtep
*bgp_evpn_es_vtep_add(struct bgp
*bgp
,
1459 struct bgp_evpn_es
*es
,
1460 struct in_addr vtep_ip
,
1461 bool esr
, uint8_t df_alg
,
1464 struct bgp_evpn_es_vtep
*es_vtep
;
1465 bool param_change
= false;
1467 es_vtep
= bgp_evpn_es_vtep_find(es
, vtep_ip
);
1470 es_vtep
= bgp_evpn_es_vtep_new(es
, vtep_ip
);
1472 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1473 zlog_debug("es %s vtep %pI4 add %s df %u/%u",
1474 es_vtep
->es
->esi_str
, &es_vtep
->vtep_ip
,
1475 esr
? "esr" : "ead", df_alg
, df_pref
);
1478 SET_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ESR
);
1479 if ((es_vtep
->df_pref
!= df_pref
)
1480 || (es_vtep
->df_alg
!= df_alg
)) {
1481 param_change
= true;
1482 es_vtep
->df_pref
= df_pref
;
1483 es_vtep
->df_alg
= df_alg
;
1489 bgp_evpn_es_vtep_re_eval_active(bgp
, es_vtep
, param_change
);
1494 static void bgp_evpn_es_vtep_do_del(struct bgp
*bgp
,
1495 struct bgp_evpn_es_vtep
*es_vtep
, bool esr
)
1497 bool param_change
= false;
1499 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1500 zlog_debug("es %s vtep %pI4 del %s", es_vtep
->es
->esi_str
,
1501 &es_vtep
->vtep_ip
, esr
? "esr" : "ead");
1503 UNSET_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ESR
);
1504 if (es_vtep
->df_pref
|| es_vtep
->df_alg
) {
1505 param_change
= true;
1506 es_vtep
->df_pref
= 0;
1507 es_vtep
->df_alg
= 0;
1510 if (es_vtep
->evi_cnt
)
1514 bgp_evpn_es_vtep_re_eval_active(bgp
, es_vtep
, param_change
);
1515 bgp_evpn_es_vtep_free(es_vtep
);
1518 static void bgp_evpn_es_vtep_del(struct bgp
*bgp
,
1519 struct bgp_evpn_es
*es
, struct in_addr vtep_ip
, bool esr
)
1521 struct bgp_evpn_es_vtep
*es_vtep
;
1523 es_vtep
= bgp_evpn_es_vtep_find(es
, vtep_ip
);
1525 bgp_evpn_es_vtep_do_del(bgp
, es_vtep
, esr
);
1528 /********************** ES MAC-IP paths *************************************
1529 * 1. Local MAC-IP routes in the VNI routing table are linked to the
1530 * destination ES (macip_evi_path_list) for efficient updates on ES oper
1532 * 2. Non-local MAC-IP routes in the global routing table are linked to
1533 * the detination for efficient updates on -
1534 * a. VTEP add/del - this results in a L3NHG update.
1535 * b. ES-VRF add/del - this may result in the host route being migrated to
1536 * L3NHG or vice versa (flat multipath list).
1537 ****************************************************************************/
1538 static void bgp_evpn_path_es_info_free(struct bgp_path_es_info
*es_info
)
1540 bgp_evpn_path_es_unlink(es_info
);
1541 XFREE(MTYPE_BGP_EVPN_PATH_ES_INFO
, es_info
);
1544 void bgp_evpn_path_mh_info_free(struct bgp_path_mh_info
*mh_info
)
1546 if (mh_info
->es_info
)
1547 bgp_evpn_path_es_info_free(mh_info
->es_info
);
1548 if (mh_info
->nh_info
)
1549 bgp_evpn_path_nh_info_free(mh_info
->nh_info
);
1550 XFREE(MTYPE_BGP_EVPN_PATH_MH_INFO
, mh_info
);
1553 static struct bgp_path_es_info
*
1554 bgp_evpn_path_es_info_new(struct bgp_path_info
*pi
, vni_t vni
)
1556 struct bgp_path_info_extra
*e
;
1557 struct bgp_path_mh_info
*mh_info
;
1558 struct bgp_path_es_info
*es_info
;
1560 e
= bgp_path_info_extra_get(pi
);
1562 /* If mh_info doesn't exist allocate it */
1563 mh_info
= e
->mh_info
;
1565 e
->mh_info
= mh_info
= XCALLOC(MTYPE_BGP_EVPN_PATH_MH_INFO
,
1566 sizeof(struct bgp_path_mh_info
));
1568 /* If es_info doesn't exist allocate it */
1569 es_info
= mh_info
->es_info
;
1571 mh_info
->es_info
= es_info
=
1572 XCALLOC(MTYPE_BGP_EVPN_PATH_ES_INFO
,
1573 sizeof(struct bgp_path_es_info
));
1581 static void bgp_evpn_path_es_unlink(struct bgp_path_es_info
*es_info
)
1583 struct bgp_evpn_es
*es
= es_info
->es
;
1584 struct bgp_path_info
*pi
;
1590 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
1591 zlog_debug("vni %u path %pFX unlinked from es %s", es_info
->vni
,
1592 &pi
->net
->p
, es
->esi_str
);
1595 list_delete_node(es
->macip_evi_path_list
,
1596 &es_info
->es_listnode
);
1598 list_delete_node(es
->macip_global_path_list
,
1599 &es_info
->es_listnode
);
1603 /* if there are no other references against the ES it
1606 bgp_evpn_es_free(es
, __func__
);
1608 /* Note we don't free the path es_info on unlink; it will be freed up
1609 * along with the path.
1613 void bgp_evpn_path_es_link(struct bgp_path_info
*pi
, vni_t vni
, esi_t
*esi
)
1615 struct bgp_path_es_info
*es_info
;
1616 struct bgp_evpn_es
*es
;
1617 struct bgp
*bgp_evpn
;
1619 es_info
= (pi
->extra
&& pi
->extra
->mh_info
)
1620 ? pi
->extra
->mh_info
->es_info
1622 /* if the esi is zero just unlink the path from the old es */
1623 if (!esi
|| !memcmp(esi
, zero_esi
, sizeof(*esi
))) {
1625 bgp_evpn_path_es_unlink(es_info
);
1629 bgp_evpn
= bgp_get_evpn();
1633 /* setup es_info against the path if it doesn't aleady exist */
1635 es_info
= bgp_evpn_path_es_info_new(pi
, vni
);
1637 /* find-create ES */
1638 es
= bgp_evpn_es_find(esi
);
1640 es
= bgp_evpn_es_new(bgp_evpn
, esi
);
1643 if (es_info
->es
== es
)
1646 /* unlink old ES if any */
1647 bgp_evpn_path_es_unlink(es_info
);
1649 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
1650 zlog_debug("vni %u path %pFX linked to es %s", vni
, &pi
->net
->p
,
1653 /* link mac-ip path to the new destination ES */
1655 listnode_init(&es_info
->es_listnode
, es_info
);
1657 listnode_add(es
->macip_evi_path_list
, &es_info
->es_listnode
);
1659 listnode_add(es
->macip_global_path_list
, &es_info
->es_listnode
);
1662 static bool bgp_evpn_is_macip_path(struct bgp_path_info
*pi
)
1664 struct prefix_evpn
*evp
;
1666 /* Only MAC-IP routes need to be linked (MAC-only routes can be
1667 * skipped) as these lists are maintained for managing
1668 * host routes in the tenant VRF
1670 evp
= (struct prefix_evpn
*)&pi
->net
->p
;
1671 return is_evpn_prefix_ipaddr_v4(evp
) || is_evpn_prefix_ipaddr_v6(evp
);
1674 /* When a remote ES is added to a VRF, routes using that as
1675 * a destination need to be migrated to a L3NHG or viceversa.
1676 * This is done indirectly by re-attempting an install of the
1677 * route in the associated VRFs. As a part of the VRF install use
1678 * of l3 NHG is evaluated and this results in the
1679 * attr.es_flag ATTR_ES_L3_NHG_USE being set or cleared.
1682 bgp_evpn_es_path_update_on_es_vrf_chg(struct bgp_evpn_es_vrf
*es_vrf
,
1685 struct listnode
*node
;
1686 struct bgp_path_es_info
*es_info
;
1687 struct bgp_path_info
*pi
;
1688 struct bgp_evpn_es
*es
= es_vrf
->es
;
1690 if (!bgp_mh_info
->host_routes_use_l3nhg
)
1693 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
1694 zlog_debug("update paths linked to es %s on es-vrf %s %s",
1695 es
->esi_str
, es_vrf
->bgp_vrf
->name
, reason
);
1697 for (ALL_LIST_ELEMENTS_RO(es
->macip_global_path_list
, node
, es_info
)) {
1700 if (!bgp_evpn_is_macip_path(pi
))
1703 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
1705 "update path %pFX linked to es %s on vrf chg",
1706 &pi
->net
->p
, es
->esi_str
);
1707 bgp_evpn_route_entry_install_if_vrf_match(es_vrf
->bgp_vrf
, pi
,
1712 static void bgp_evpn_es_frag_free(struct bgp_evpn_es_frag
*es_frag
)
1714 struct bgp_evpn_es
*es
= es_frag
->es
;
1716 if (es
->es_base_frag
== es_frag
)
1717 es
->es_base_frag
= NULL
;
1719 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1720 zlog_debug("es %s frag %u free", es
->esi_str
, es_frag
->rd_id
);
1721 list_delete_node(es
->es_frag_list
, &es_frag
->es_listnode
);
1723 /* EVIs that are advertised using the info in this fragment */
1724 list_delete(&es_frag
->es_evi_frag_list
);
1726 bf_release_index(bm
->rd_idspace
, es_frag
->rd_id
);
1729 XFREE(MTYPE_BGP_EVPN_ES_FRAG
, es_frag
);
1732 static void bgp_evpn_es_frag_free_unused(struct bgp_evpn_es_frag
*es_frag
)
1734 if ((es_frag
->es
->es_base_frag
== es_frag
) ||
1735 listcount(es_frag
->es_evi_frag_list
))
1738 bgp_evpn_es_frag_free(es_frag
);
1741 static void bgp_evpn_es_frag_free_all(struct bgp_evpn_es
*es
)
1743 struct listnode
*node
;
1744 struct listnode
*nnode
;
1745 struct bgp_evpn_es_frag
*es_frag
;
1747 for (ALL_LIST_ELEMENTS(es
->es_frag_list
, node
, nnode
, es_frag
))
1748 bgp_evpn_es_frag_free(es_frag
);
1751 static struct bgp_evpn_es_frag
*bgp_evpn_es_frag_new(struct bgp_evpn_es
*es
)
1753 struct bgp_evpn_es_frag
*es_frag
;
1754 char buf
[BGP_EVPN_PREFIX_RD_LEN
];
1757 es_frag
= XCALLOC(MTYPE_BGP_EVPN_ES_FRAG
, sizeof(*es_frag
));
1758 bf_assign_index(bm
->rd_idspace
, es_frag
->rd_id
);
1759 es_frag
->prd
.family
= AF_UNSPEC
;
1760 es_frag
->prd
.prefixlen
= 64;
1761 bgp
= bgp_get_evpn();
1762 snprintfrr(buf
, sizeof(buf
), "%pI4:%hu", &bgp
->router_id
,
1764 (void)str2prefix_rd(buf
, &es_frag
->prd
);
1766 /* EVIs that are advertised using the info in this fragment */
1767 es_frag
->es_evi_frag_list
= list_new();
1768 listset_app_node_mem(es_frag
->es_evi_frag_list
);
1770 /* Link the fragment to the parent ES */
1772 listnode_init(&es_frag
->es_listnode
, es_frag
);
1773 listnode_add(es
->es_frag_list
, &es_frag
->es_listnode
);
1775 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1776 zlog_debug("es %s frag %u new", es
->esi_str
, es_frag
->rd_id
);
1780 static struct bgp_evpn_es_frag
*
1781 bgp_evpn_es_find_frag_with_space(struct bgp_evpn_es
*es
)
1783 struct listnode
*node
;
1784 struct bgp_evpn_es_frag
*es_frag
;
1786 for (ALL_LIST_ELEMENTS_RO(es
->es_frag_list
, node
, es_frag
)) {
1787 if (listcount(es_frag
->es_evi_frag_list
) <
1788 bgp_mh_info
->evi_per_es_frag
)
1792 /* No frags where found with space; allocate a new one */
1793 return bgp_evpn_es_frag_new(es
);
1796 /* Link the ES-EVI to one of the ES fragments */
1797 static void bgp_evpn_es_frag_evi_add(struct bgp_evpn_es_evi
*es_evi
)
1799 struct bgp_evpn_es_frag
*es_frag
;
1800 struct bgp_evpn_es
*es
= es_evi
->es
;
1802 if (es_evi
->es_frag
||
1803 !(CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
)))
1806 es_frag
= bgp_evpn_es_find_frag_with_space(es
);
1808 es_evi
->es_frag
= es_frag
;
1809 listnode_init(&es_evi
->es_frag_listnode
, es_evi
);
1810 listnode_add(es_frag
->es_evi_frag_list
, &es_evi
->es_frag_listnode
);
1812 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1813 zlog_debug("es %s vni %d linked to frag %u", es
->esi_str
,
1814 es_evi
->vpn
->vni
, es_frag
->rd_id
);
1817 /* UnLink the ES-EVI from the ES fragment */
1818 static void bgp_evpn_es_frag_evi_del(struct bgp_evpn_es_evi
*es_evi
,
1819 bool send_ead_del_if_empty
)
1821 struct bgp_evpn_es_frag
*es_frag
= es_evi
->es_frag
;
1822 struct prefix_evpn p
;
1823 struct bgp_evpn_es
*es
;
1830 es_evi
->es_frag
= NULL
;
1831 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1832 zlog_debug("es %s vni %d unlinked from frag %u", es
->esi_str
,
1833 es_evi
->vpn
->vni
, es_frag
->rd_id
);
1835 list_delete_node(es_frag
->es_evi_frag_list
, &es_evi
->es_frag_listnode
);
1838 * if there are no other EVIs on the fragment deleted the EAD-ES for
1841 if (send_ead_del_if_empty
&& !listcount(es_frag
->es_evi_frag_list
)) {
1842 bgp
= bgp_get_evpn();
1844 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1845 zlog_debug("es %s frag %u ead-es route delete",
1846 es
->esi_str
, es_frag
->rd_id
);
1847 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_ES_ETH_TAG
, &es
->esi
,
1849 p
.prefix
.ead_addr
.frag_id
= es_frag
->rd_id
;
1850 bgp_evpn_mh_route_delete(bgp
, es
, NULL
, es_frag
, &p
);
1853 /* We don't attempt to coalesce frags that may not be full. Instead we
1854 * only free up the frag when it is completely empty.
1856 bgp_evpn_es_frag_free_unused(es_frag
);
1859 /* Link the ES-EVIs to one of the ES fragments */
1860 static void bgp_evpn_es_frag_evi_update_all(struct bgp_evpn_es
*es
, bool add
)
1862 struct listnode
*node
;
1863 struct bgp_evpn_es_evi
*es_evi
;
1865 for (ALL_LIST_ELEMENTS_RO(es
->es_evi_list
, node
, es_evi
)) {
1867 bgp_evpn_es_frag_evi_add(es_evi
);
1869 bgp_evpn_es_frag_evi_del(es_evi
, false);
1873 /* compare ES-IDs for the global ES RB tree */
1874 static int bgp_es_rb_cmp(const struct bgp_evpn_es
*es1
,
1875 const struct bgp_evpn_es
*es2
)
1877 return memcmp(&es1
->esi
, &es2
->esi
, ESI_BYTES
);
1879 RB_GENERATE(bgp_es_rb_head
, bgp_evpn_es
, rb_node
, bgp_es_rb_cmp
);
1881 struct bgp_evpn_es
*bgp_evpn_es_find(const esi_t
*esi
)
1883 struct bgp_evpn_es tmp
;
1885 memcpy(&tmp
.esi
, esi
, sizeof(esi_t
));
1886 return RB_FIND(bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
, &tmp
);
1889 static struct bgp_evpn_es
*bgp_evpn_es_new(struct bgp
*bgp
, const esi_t
*esi
)
1891 struct bgp_evpn_es
*es
;
1893 es
= XCALLOC(MTYPE_BGP_EVPN_ES
, sizeof(struct bgp_evpn_es
));
1896 memcpy(&es
->esi
, esi
, sizeof(esi_t
));
1898 /* Initialise the VTEP list */
1899 es
->es_vtep_list
= list_new();
1900 listset_app_node_mem(es
->es_vtep_list
);
1901 es
->es_vtep_list
->cmp
= bgp_evpn_es_vtep_cmp
;
1903 esi_to_str(&es
->esi
, es
->esi_str
, sizeof(es
->esi_str
));
1905 /* Initialize the ES routing table */
1906 es
->route_table
= bgp_table_init(bgp
, AFI_L2VPN
, SAFI_EVPN
);
1908 /* Add to rb_tree */
1909 RB_INSERT(bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
, es
);
1911 /* Initialise the ES-EVI list */
1912 es
->es_evi_list
= list_new();
1913 listset_app_node_mem(es
->es_evi_list
);
1915 /* Initialise the ES-VRF list used for L3NHG management */
1916 es
->es_vrf_list
= list_new();
1917 listset_app_node_mem(es
->es_vrf_list
);
1919 /* Initialise the route list used for efficient event handling */
1920 es
->macip_evi_path_list
= list_new();
1921 listset_app_node_mem(es
->macip_evi_path_list
);
1922 es
->macip_global_path_list
= list_new();
1923 listset_app_node_mem(es
->macip_global_path_list
);
1924 es
->es_frag_list
= list_new();
1925 listset_app_node_mem(es
->es_frag_list
);
1927 QOBJ_REG(es
, bgp_evpn_es
);
1932 /* Free a given ES -
1933 * This just frees appropriate memory, caller should have taken other
1936 static void bgp_evpn_es_free(struct bgp_evpn_es
*es
, const char *caller
)
1938 if ((es
->flags
& (BGP_EVPNES_LOCAL
| BGP_EVPNES_REMOTE
))
1939 || listcount(es
->macip_evi_path_list
)
1940 || listcount(es
->macip_global_path_list
))
1943 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1944 zlog_debug("%s: es %s free", caller
, es
->esi_str
);
1946 /* cleanup resources maintained against the ES */
1947 list_delete(&es
->es_evi_list
);
1948 list_delete(&es
->es_vrf_list
);
1949 list_delete(&es
->es_vtep_list
);
1950 list_delete(&es
->macip_evi_path_list
);
1951 list_delete(&es
->macip_global_path_list
);
1952 list_delete(&es
->es_frag_list
);
1953 bgp_table_unlock(es
->route_table
);
1955 /* remove the entry from various databases */
1956 RB_REMOVE(bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
, es
);
1957 bgp_evpn_es_cons_checks_pend_del(es
);
1960 XFREE(MTYPE_BGP_EVPN_ES
, es
);
1963 static inline bool bgp_evpn_is_es_local_and_non_bypass(struct bgp_evpn_es
*es
)
1965 return (es
->flags
& BGP_EVPNES_LOCAL
)
1966 && !(es
->flags
& BGP_EVPNES_BYPASS
);
1969 /* init local info associated with the ES */
1970 static void bgp_evpn_es_local_info_set(struct bgp
*bgp
, struct bgp_evpn_es
*es
)
1975 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_LOCAL
))
1978 old_is_local
= bgp_evpn_is_es_local_and_non_bypass(es
);
1979 SET_FLAG(es
->flags
, BGP_EVPNES_LOCAL
);
1981 listnode_init(&es
->es_listnode
, es
);
1982 listnode_add(bgp_mh_info
->local_es_list
, &es
->es_listnode
);
1984 /* setup the first ES fragment; more fragments may be allocated based
1985 * on the the number of EVI entries
1987 es
->es_base_frag
= bgp_evpn_es_frag_new(es
);
1988 /* distribute ES-EVIs to one or more ES fragments */
1989 bgp_evpn_es_frag_evi_update_all(es
, true);
1991 is_local
= bgp_evpn_is_es_local_and_non_bypass(es
);
1992 if (old_is_local
!= is_local
)
1993 bgp_evpn_mac_update_on_es_local_chg(es
, is_local
);
1996 /* clear any local info associated with the ES */
1997 static void bgp_evpn_es_local_info_clear(struct bgp_evpn_es
*es
, bool finish
)
2002 if (!CHECK_FLAG(es
->flags
, BGP_EVPNES_LOCAL
))
2005 /* clear the es frag references and free them up */
2006 bgp_evpn_es_frag_evi_update_all(es
, false);
2007 es
->es_base_frag
= NULL
;
2008 bgp_evpn_es_frag_free_all(es
);
2010 old_is_local
= bgp_evpn_is_es_local_and_non_bypass(es
);
2011 UNSET_FLAG(es
->flags
, BGP_EVPNES_LOCAL
);
2013 is_local
= bgp_evpn_is_es_local_and_non_bypass(es
);
2014 if (!finish
&& (old_is_local
!= is_local
))
2015 bgp_evpn_mac_update_on_es_local_chg(es
, is_local
);
2017 /* remove from the ES local list */
2018 list_delete_node(bgp_mh_info
->local_es_list
, &es
->es_listnode
);
2020 bgp_evpn_es_free(es
, __func__
);
2023 /* eval remote info associated with the ES */
2024 static void bgp_evpn_es_remote_info_re_eval(struct bgp_evpn_es
*es
)
2026 if (es
->remote_es_evi_cnt
) {
2027 SET_FLAG(es
->flags
, BGP_EVPNES_REMOTE
);
2029 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_REMOTE
)) {
2030 UNSET_FLAG(es
->flags
, BGP_EVPNES_REMOTE
);
2031 bgp_evpn_es_free(es
, __func__
);
2036 /* If ES is present and local it needs to be active/oper-up for
2039 bool bgp_evpn_es_add_l3_ecomm_ok(esi_t
*esi
)
2041 struct bgp_evpn_es
*es
;
2043 if (!esi
|| !bgp_mh_info
->suppress_l3_ecomm_on_inactive_es
)
2046 es
= bgp_evpn_es_find(esi
);
2048 return (!es
|| !(es
->flags
& BGP_EVPNES_LOCAL
)
2049 || bgp_evpn_local_es_is_active(es
));
2052 static bool bgp_evpn_is_valid_local_path(struct bgp_path_info
*pi
)
2054 return (CHECK_FLAG(pi
->flags
, BGP_PATH_VALID
)
2055 && pi
->type
== ZEBRA_ROUTE_BGP
2056 && pi
->sub_type
== BGP_ROUTE_STATIC
);
2059 /* Update all local MAC-IP routes in the VNI routing table associated
2060 * with the ES. When the ES is down the routes are advertised without
2063 static void bgp_evpn_mac_update_on_es_oper_chg(struct bgp_evpn_es
*es
)
2065 struct listnode
*node
;
2066 struct bgp_path_es_info
*es_info
;
2067 struct bgp_path_info
*pi
;
2069 struct bgpevpn
*vpn
;
2071 if (!bgp_mh_info
->suppress_l3_ecomm_on_inactive_es
)
2074 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2075 zlog_debug("update paths linked to es %s on oper chg",
2078 bgp
= bgp_get_evpn();
2079 for (ALL_LIST_ELEMENTS_RO(es
->macip_evi_path_list
, node
, es_info
)) {
2082 if (!bgp_evpn_is_valid_local_path(pi
))
2085 if (!bgp_evpn_is_macip_path(pi
))
2088 vpn
= bgp_evpn_lookup_vni(bgp
, es_info
->vni
);
2092 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
2094 "update path %d %pFX linked to es %s on oper chg",
2095 es_info
->vni
, &pi
->net
->p
, es
->esi_str
);
2097 bgp_evpn_update_type2_route_entry(bgp
, vpn
, pi
->net
, pi
,
2102 static bool bgp_evpn_is_valid_bgp_path(struct bgp_path_info
*pi
)
2104 return (CHECK_FLAG(pi
->flags
, BGP_PATH_VALID
)
2105 && pi
->type
== ZEBRA_ROUTE_BGP
2106 && pi
->sub_type
== BGP_ROUTE_NORMAL
);
2109 /* If an ES is no longer local (or becomes local) we need to re-install
2110 * paths using that ES as destination. This is needed as the criteria
2111 * for best path selection has changed.
2113 static void bgp_evpn_mac_update_on_es_local_chg(struct bgp_evpn_es
*es
,
2116 struct listnode
*node
;
2117 struct bgp_path_es_info
*es_info
;
2118 struct bgp_path_info
*pi
;
2120 struct attr
*attr_new
;
2121 struct attr attr_tmp
;
2123 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2124 zlog_debug("update paths linked to es %s on chg to %s",
2125 es
->esi_str
, is_local
? "local" : "non-local");
2127 for (ALL_LIST_ELEMENTS_RO(es
->macip_global_path_list
, node
, es_info
)) {
2130 /* Consider "valid" remote routes */
2131 if (!bgp_evpn_is_valid_bgp_path(pi
))
2137 tmp_local
= !!(pi
->attr
->es_flags
& ATTR_ES_IS_LOCAL
);
2138 if (tmp_local
== is_local
)
2141 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
2143 "update path %pFX linked to es %s on chg to %s",
2144 &pi
->net
->p
, es
->esi_str
,
2145 is_local
? "local" : "non-local");
2147 attr_tmp
= *pi
->attr
;
2149 attr_tmp
.es_flags
|= ATTR_ES_IS_LOCAL
;
2151 attr_tmp
.es_flags
&= ~ATTR_ES_IS_LOCAL
;
2152 attr_new
= bgp_attr_intern(&attr_tmp
);
2153 bgp_attr_unintern(&pi
->attr
);
2154 pi
->attr
= attr_new
;
2155 bgp_evpn_import_type2_route(pi
, 1);
2159 static void bgp_evpn_local_es_deactivate(struct bgp
*bgp
,
2160 struct bgp_evpn_es
*es
)
2162 struct prefix_evpn p
;
2166 /* Delete and withdraw locally learnt ES route */
2167 build_evpn_type4_prefix(&p
, &es
->esi
, es
->originator_ip
);
2168 ret
= bgp_evpn_type4_route_delete(bgp
, es
, &p
);
2170 flog_err(EC_BGP_EVPN_ROUTE_DELETE
,
2171 "%u failed to delete type-4 route for ESI %s",
2172 bgp
->vrf_id
, es
->esi_str
);
2175 /* withdraw EAD-EVI */
2176 if (!bgp_mh_info
->ead_evi_adv_for_down_links
)
2177 bgp_evpn_local_type1_evi_route_del(bgp
, es
);
2179 /* withdraw EAD-ES */
2180 bgp_evpn_ead_es_route_delete(bgp
, es
);
2182 bgp_evpn_mac_update_on_es_oper_chg(es
);
2185 /* Process ES link oper-down by withdrawing ES-EAD and ESR */
2186 static void bgp_evpn_local_es_down(struct bgp
*bgp
, struct bgp_evpn_es
*es
)
2190 if (!CHECK_FLAG(es
->flags
, BGP_EVPNES_OPER_UP
))
2193 old_active
= bgp_evpn_local_es_is_active(es
);
2194 UNSET_FLAG(es
->flags
, BGP_EVPNES_OPER_UP
);
2196 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2197 zlog_debug("local es %s down", es
->esi_str
);
2200 bgp_evpn_local_es_deactivate(bgp
, es
);
2203 static void bgp_evpn_local_es_activate(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
2204 bool regen_ead
, bool regen_esr
)
2206 struct prefix_evpn p
;
2209 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2210 zlog_debug("local es %s generate ESR", es
->esi_str
);
2212 build_evpn_type4_prefix(&p
, &es
->esi
, es
->originator_ip
);
2213 if (bgp_evpn_type4_route_update(bgp
, es
, &p
))
2214 flog_err(EC_BGP_EVPN_ROUTE_CREATE
,
2215 "%u: Type4 route creation failure for ESI %s",
2216 bgp
->vrf_id
, es
->esi_str
);
2220 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2221 zlog_debug("local es %s generate EAD", es
->esi_str
);
2222 /* generate EAD-EVI */
2223 bgp_evpn_local_type1_evi_route_add(bgp
, es
);
2225 /* generate EAD-ES */
2226 bgp_evpn_ead_es_route_update(bgp
, es
);
2229 bgp_evpn_mac_update_on_es_oper_chg(es
);
2232 /* Process ES link oper-up by generating ES-EAD and ESR */
2233 static void bgp_evpn_local_es_up(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
2236 bool regen_ead
= false;
2237 bool active
= false;
2239 if (!CHECK_FLAG(es
->flags
, BGP_EVPNES_OPER_UP
)) {
2240 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2241 zlog_debug("local es %s up", es
->esi_str
);
2243 SET_FLAG(es
->flags
, BGP_EVPNES_OPER_UP
);
2248 active
= bgp_evpn_local_es_is_active(es
);
2249 if (active
&& (regen_ead
|| regen_esr
))
2250 bgp_evpn_local_es_activate(bgp
, es
, regen_ead
, regen_esr
);
2253 /* If an ethernet segment is in LACP bypass we cannot advertise
2254 * reachability to it i.e. EAD-per-ES and ESR is not advertised in
2256 * PS: EAD-per-EVI will continue to be advertised
2258 static void bgp_evpn_local_es_bypass_update(struct bgp
*bgp
,
2259 struct bgp_evpn_es
*es
, bool bypass
)
2261 bool old_bypass
= !!(es
->flags
& BGP_EVPNES_BYPASS
);
2267 if (bypass
== old_bypass
)
2270 old_active
= bgp_evpn_local_es_is_active(es
);
2271 old_is_local
= bgp_evpn_is_es_local_and_non_bypass(es
);
2273 SET_FLAG(es
->flags
, BGP_EVPNES_BYPASS
);
2275 UNSET_FLAG(es
->flags
, BGP_EVPNES_BYPASS
);
2277 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2278 zlog_debug("local es %s bypass %s", es
->esi_str
,
2279 bypass
? "set" : "clear");
2281 new_active
= bgp_evpn_local_es_is_active(es
);
2282 if (old_active
!= new_active
) {
2284 bgp_evpn_local_es_activate(bgp
, es
, true, true);
2286 bgp_evpn_local_es_deactivate(bgp
, es
);
2289 is_local
= bgp_evpn_is_es_local_and_non_bypass(es
);
2290 if (old_is_local
!= is_local
)
2291 bgp_evpn_mac_update_on_es_local_chg(es
, is_local
);
2294 static void bgp_evpn_local_es_do_del(struct bgp
*bgp
, struct bgp_evpn_es
*es
)
2296 struct bgp_evpn_es_evi
*es_evi
;
2297 struct listnode
*evi_node
, *evi_next_node
;
2299 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2300 zlog_debug("del local es %s", es
->esi_str
);
2302 /* Delete all local EVPN ES routes from ESI table
2303 * and schedule for processing (to withdraw from peers))
2305 bgp_evpn_es_route_del_all(bgp
, es
);
2307 /* release all local ES EVIs associated with the ES */
2308 for (ALL_LIST_ELEMENTS(es
->es_evi_list
, evi_node
,
2309 evi_next_node
, es_evi
)) {
2310 bgp_evpn_local_es_evi_do_del(es_evi
);
2313 /* Clear local info associated with the ES and free it up if there is
2314 * no remote reference
2316 bgp_evpn_es_local_info_clear(es
, false);
2319 bool bgp_evpn_is_esi_local_and_non_bypass(esi_t
*esi
)
2321 struct bgp_evpn_es
*es
= NULL
;
2323 /* Lookup ESI hash - should exist. */
2324 es
= bgp_evpn_es_find(esi
);
2326 return es
&& bgp_evpn_is_es_local_and_non_bypass(es
);
2329 int bgp_evpn_local_es_del(struct bgp
*bgp
, esi_t
*esi
)
2331 struct bgp_evpn_es
*es
= NULL
;
2333 /* Lookup ESI hash - should exist. */
2334 es
= bgp_evpn_es_find(esi
);
2336 flog_warn(EC_BGP_EVPN_ESI
, "%u: ES missing at local ES DEL",
2341 bgp_evpn_local_es_do_del(bgp
, es
);
2345 /* Handle device to ES id association. Results in the creation of a local
2348 int bgp_evpn_local_es_add(struct bgp
*bgp
, esi_t
*esi
,
2349 struct in_addr originator_ip
, bool oper_up
,
2350 uint16_t df_pref
, bool bypass
)
2352 struct bgp_evpn_es
*es
;
2354 bool regen_esr
= false;
2356 /* create the new es */
2357 es
= bgp_evpn_es_find(esi
);
2359 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_LOCAL
))
2362 es
= bgp_evpn_es_new(bgp
, esi
);
2364 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2365 zlog_debug("add local es %s orig-ip %pI4 df_pref %u %s",
2366 es
->esi_str
, &originator_ip
, df_pref
,
2367 bypass
? "bypass" : "");
2369 es
->originator_ip
= originator_ip
;
2370 if (df_pref
!= es
->df_pref
) {
2371 es
->df_pref
= df_pref
;
2374 bgp_evpn_es_local_info_set(bgp
, es
);
2376 /* import all remote Type-4 routes in the ES table */
2378 bgp_evpn_type4_remote_routes_import(bgp
, es
,
2379 true /* install */);
2381 /* create and advertise EAD-EVI routes for the ES -
2382 * XXX - till an ES-EVI reference is created there is really nothing to
2385 if (bgp_mh_info
->ead_evi_adv_for_down_links
)
2386 bgp_evpn_local_type1_evi_route_add(bgp
, es
);
2388 bgp_evpn_local_es_bypass_update(bgp
, es
, bypass
);
2390 /* If the ES link is operationally up generate EAD-ES. EAD-EVI
2391 * can be generated even if the link is inactive.
2394 bgp_evpn_local_es_up(bgp
, es
, regen_esr
);
2396 bgp_evpn_local_es_down(bgp
, es
);
2401 static void bgp_evpn_es_json_frag_fill(json_object
*json_frags
,
2402 struct bgp_evpn_es
*es
)
2404 json_object
*json_frag
;
2405 char buf1
[RD_ADDRSTRLEN
];
2406 struct listnode
*node
;
2407 struct bgp_evpn_es_frag
*es_frag
;
2409 for (ALL_LIST_ELEMENTS_RO(es
->es_frag_list
, node
, es_frag
)) {
2410 json_frag
= json_object_new_object();
2412 json_object_string_add(
2414 prefix_rd2str(&es_frag
->prd
, buf1
, sizeof(buf1
)));
2415 json_object_int_add(json_frag
, "eviCount",
2416 listcount(es_frag
->es_evi_frag_list
));
2418 json_object_array_add(json_frags
, json_frag
);
2422 static void bgp_evpn_es_frag_show_detail(struct vty
*vty
,
2423 struct bgp_evpn_es
*es
)
2425 struct listnode
*node
;
2426 char buf1
[RD_ADDRSTRLEN
];
2427 struct bgp_evpn_es_frag
*es_frag
;
2429 for (ALL_LIST_ELEMENTS_RO(es
->es_frag_list
, node
, es_frag
)) {
2430 vty_out(vty
, " %s EVIs: %d\n",
2431 prefix_rd2str(&es_frag
->prd
, buf1
, sizeof(buf1
)),
2432 listcount(es_frag
->es_evi_frag_list
));
2436 static char *bgp_evpn_es_vteps_str(char *vtep_str
, struct bgp_evpn_es
*es
,
2437 uint8_t vtep_str_size
)
2439 char vtep_flag_str
[BGP_EVPN_FLAG_STR_SZ
];
2440 struct listnode
*node
;
2441 struct bgp_evpn_es_vtep
*es_vtep
;
2443 char ip_buf
[INET6_ADDRSTRLEN
];
2446 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
2447 vtep_flag_str
[0] = '\0';
2449 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ESR
)
2450 strlcat(vtep_flag_str
, "E", sizeof(vtep_flag_str
));
2451 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ACTIVE
)
2452 strlcat(vtep_flag_str
, "A", sizeof(vtep_flag_str
));
2454 if (!strlen(vtep_flag_str
))
2455 strlcat(vtep_flag_str
, "-", sizeof(vtep_flag_str
));
2459 strlcat(vtep_str
, ",", vtep_str_size
);
2461 inet_ntop(AF_INET
, &es_vtep
->vtep_ip
, ip_buf
,
2464 strlcat(vtep_str
, "(", vtep_str_size
);
2465 strlcat(vtep_str
, vtep_flag_str
, vtep_str_size
);
2466 strlcat(vtep_str
, ")", vtep_str_size
);
2472 static void bgp_evpn_es_json_vtep_fill(json_object
*json_vteps
,
2473 struct bgp_evpn_es_vtep
*es_vtep
)
2475 json_object
*json_vtep_entry
;
2476 json_object
*json_flags
;
2478 json_vtep_entry
= json_object_new_object();
2480 json_object_string_addf(json_vtep_entry
, "vtep_ip", "%pI4",
2482 if (es_vtep
->flags
& (BGP_EVPNES_VTEP_ESR
|
2483 BGP_EVPNES_VTEP_ACTIVE
)) {
2484 json_flags
= json_object_new_array();
2485 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ESR
)
2486 json_array_string_add(json_flags
, "esr");
2487 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ACTIVE
)
2488 json_array_string_add(json_flags
, "active");
2489 json_object_object_add(json_vtep_entry
, "flags", json_flags
);
2490 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ESR
) {
2491 json_object_int_add(json_vtep_entry
, "dfPreference",
2493 json_object_int_add(json_vtep_entry
, "dfAlgorithm",
2498 json_object_array_add(json_vteps
,
2502 static void bgp_evpn_es_vteps_show_detail(struct vty
*vty
,
2503 struct bgp_evpn_es
*es
)
2505 char vtep_flag_str
[BGP_EVPN_FLAG_STR_SZ
];
2506 struct listnode
*node
;
2507 struct bgp_evpn_es_vtep
*es_vtep
;
2508 char alg_buf
[EVPN_DF_ALG_STR_LEN
];
2510 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
2511 vtep_flag_str
[0] = '\0';
2512 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ESR
)
2513 strlcat(vtep_flag_str
, "E", sizeof(vtep_flag_str
));
2514 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ACTIVE
)
2515 strlcat(vtep_flag_str
, "A", sizeof(vtep_flag_str
));
2517 if (!strlen(vtep_flag_str
))
2518 strlcat(vtep_flag_str
, "-", sizeof(vtep_flag_str
));
2520 vty_out(vty
, " %pI4 flags: %s", &es_vtep
->vtep_ip
,
2523 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ESR
)
2524 vty_out(vty
, " df_alg: %s df_pref: %u\n",
2525 evpn_es_df_alg2str(es_vtep
->df_alg
, alg_buf
,
2533 static void bgp_evpn_es_show_entry(struct vty
*vty
,
2534 struct bgp_evpn_es
*es
, json_object
*json
)
2536 char buf1
[RD_ADDRSTRLEN
];
2537 struct listnode
*node
;
2538 struct bgp_evpn_es_vtep
*es_vtep
;
2541 json_object
*json_vteps
;
2542 json_object
*json_types
;
2544 json_object_string_add(json
, "esi", es
->esi_str
);
2545 if (es
->es_base_frag
)
2546 json_object_string_add(
2548 prefix_rd2str(&es
->es_base_frag
->prd
, buf1
,
2551 if (es
->flags
& (BGP_EVPNES_LOCAL
| BGP_EVPNES_REMOTE
)) {
2552 json_types
= json_object_new_array();
2553 if (es
->flags
& BGP_EVPNES_LOCAL
)
2554 json_array_string_add(json_types
, "local");
2555 if (es
->flags
& BGP_EVPNES_REMOTE
)
2556 json_array_string_add(json_types
, "remote");
2557 json_object_object_add(json
, "type", json_types
);
2560 if (listcount(es
->es_vtep_list
)) {
2561 json_vteps
= json_object_new_array();
2562 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
,
2564 bgp_evpn_es_json_vtep_fill(json_vteps
, es_vtep
);
2566 json_object_object_add(json
, "vteps", json_vteps
);
2568 json_object_int_add(json
, "vniCount",
2569 listcount(es
->es_evi_list
));
2572 char vtep_str
[ES_VTEP_LIST_STR_SZ
+ BGP_EVPN_VTEPS_FLAG_STR_SZ
];
2575 if (es
->flags
& BGP_EVPNES_BYPASS
)
2576 strlcat(type_str
, "B", sizeof(type_str
));
2577 if (es
->flags
& BGP_EVPNES_LOCAL
)
2578 strlcat(type_str
, "L", sizeof(type_str
));
2579 if (es
->flags
& BGP_EVPNES_REMOTE
)
2580 strlcat(type_str
, "R", sizeof(type_str
));
2581 if (es
->inconsistencies
)
2582 strlcat(type_str
, "I", sizeof(type_str
));
2584 bgp_evpn_es_vteps_str(vtep_str
, es
, sizeof(vtep_str
));
2586 if (es
->es_base_frag
)
2587 prefix_rd2str(&es
->es_base_frag
->prd
, buf1
,
2590 strlcpy(buf1
, "-", sizeof(buf1
));
2592 vty_out(vty
, "%-30s %-5s %-21s %-8d %s\n",
2593 es
->esi_str
, type_str
, buf1
,
2594 listcount(es
->es_evi_list
), vtep_str
);
2598 static void bgp_evpn_es_show_entry_detail(struct vty
*vty
,
2599 struct bgp_evpn_es
*es
, json_object
*json
)
2602 json_object
*json_flags
;
2603 json_object
*json_incons
;
2604 json_object
*json_vteps
;
2605 json_object
*json_frags
;
2606 struct listnode
*node
;
2607 struct bgp_evpn_es_vtep
*es_vtep
;
2609 /* Add the "brief" info first */
2610 bgp_evpn_es_show_entry(vty
, es
, json
);
2612 & (BGP_EVPNES_OPER_UP
| BGP_EVPNES_ADV_EVI
2613 | BGP_EVPNES_BYPASS
)) {
2614 json_flags
= json_object_new_array();
2615 if (es
->flags
& BGP_EVPNES_OPER_UP
)
2616 json_array_string_add(json_flags
, "up");
2617 if (es
->flags
& BGP_EVPNES_ADV_EVI
)
2618 json_array_string_add(json_flags
,
2620 if (es
->flags
& BGP_EVPNES_BYPASS
)
2621 json_array_string_add(json_flags
, "bypass");
2622 json_object_object_add(json
, "flags", json_flags
);
2624 json_object_string_addf(json
, "originator_ip", "%pI4",
2625 &es
->originator_ip
);
2626 json_object_int_add(json
, "remoteVniCount",
2627 es
->remote_es_evi_cnt
);
2628 json_object_int_add(json
, "vrfCount",
2629 listcount(es
->es_vrf_list
));
2630 json_object_int_add(json
, "macipPathCount",
2631 listcount(es
->macip_evi_path_list
));
2632 json_object_int_add(json
, "macipGlobalPathCount",
2633 listcount(es
->macip_global_path_list
));
2634 json_object_int_add(json
, "inconsistentVniVtepCount",
2635 es
->incons_evi_vtep_cnt
);
2636 if (listcount(es
->es_vtep_list
)) {
2637 json_vteps
= json_object_new_array();
2638 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
,
2640 bgp_evpn_es_json_vtep_fill(json_vteps
, es_vtep
);
2642 json_object_object_add(json
, "vteps", json_vteps
);
2644 if (listcount(es
->es_frag_list
)) {
2645 json_frags
= json_object_new_array();
2646 bgp_evpn_es_json_frag_fill(json_frags
, es
);
2647 json_object_object_add(json
, "fragments", json_frags
);
2649 if (es
->inconsistencies
) {
2650 json_incons
= json_object_new_array();
2651 if (es
->inconsistencies
& BGP_EVPNES_INCONS_VTEP_LIST
)
2652 json_array_string_add(json_incons
,
2653 "vni-vtep-mismatch");
2654 json_object_object_add(json
, "inconsistencies",
2658 char incons_str
[BGP_EVPNES_INCONS_STR_SZ
];
2660 char buf1
[RD_ADDRSTRLEN
];
2663 if (es
->flags
& BGP_EVPNES_LOCAL
)
2664 strlcat(type_str
, "L", sizeof(type_str
));
2665 if (es
->flags
& BGP_EVPNES_REMOTE
)
2666 strlcat(type_str
, "R", sizeof(type_str
));
2668 if (es
->es_base_frag
)
2669 prefix_rd2str(&es
->es_base_frag
->prd
, buf1
,
2672 strlcpy(buf1
, "-", sizeof(buf1
));
2674 vty_out(vty
, "ESI: %s\n", es
->esi_str
);
2675 vty_out(vty
, " Type: %s\n", type_str
);
2676 vty_out(vty
, " RD: %s\n", buf1
);
2677 vty_out(vty
, " Originator-IP: %pI4\n", &es
->originator_ip
);
2678 if (es
->flags
& BGP_EVPNES_LOCAL
)
2679 vty_out(vty
, " Local ES DF preference: %u\n",
2681 if (es
->flags
& BGP_EVPNES_BYPASS
)
2682 vty_out(vty
, " LACP bypass: on\n");
2683 vty_out(vty
, " VNI Count: %d\n", listcount(es
->es_evi_list
));
2684 vty_out(vty
, " Remote VNI Count: %d\n",
2685 es
->remote_es_evi_cnt
);
2686 vty_out(vty
, " VRF Count: %d\n", listcount(es
->es_vrf_list
));
2687 vty_out(vty
, " MACIP EVI Path Count: %d\n",
2688 listcount(es
->macip_evi_path_list
));
2689 vty_out(vty
, " MACIP Global Path Count: %d\n",
2690 listcount(es
->macip_global_path_list
));
2691 vty_out(vty
, " Inconsistent VNI VTEP Count: %d\n",
2692 es
->incons_evi_vtep_cnt
);
2693 if (es
->inconsistencies
) {
2694 incons_str
[0] = '\0';
2695 if (es
->inconsistencies
& BGP_EVPNES_INCONS_VTEP_LIST
)
2696 strlcat(incons_str
, "vni-vtep-mismatch",
2697 sizeof(incons_str
));
2699 strlcpy(incons_str
, "-", sizeof(incons_str
));
2701 vty_out(vty
, " Inconsistencies: %s\n",
2703 if (listcount(es
->es_frag_list
)) {
2704 vty_out(vty
, " Fragments:\n");
2705 bgp_evpn_es_frag_show_detail(vty
, es
);
2707 if (listcount(es
->es_vtep_list
)) {
2708 vty_out(vty
, " VTEPs:\n");
2709 bgp_evpn_es_vteps_show_detail(vty
, es
);
2715 /* Display all ESs */
2716 void bgp_evpn_es_show(struct vty
*vty
, bool uj
, bool detail
)
2718 struct bgp_evpn_es
*es
;
2719 json_object
*json_array
= NULL
;
2720 json_object
*json
= NULL
;
2723 /* create an array of ESs */
2724 json_array
= json_object_new_array();
2728 "ES Flags: B - bypass, L local, R remote, I inconsistent\n");
2730 "VTEP Flags: E ESR/Type-4, A active nexthop\n");
2732 "%-30s %-5s %-21s %-8s %s\n",
2733 "ESI", "Flags", "RD", "#VNIs", "VTEPs");
2737 RB_FOREACH(es
, bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
) {
2739 /* create a separate json object for each ES */
2740 json
= json_object_new_object();
2742 bgp_evpn_es_show_entry_detail(vty
, es
, json
);
2744 bgp_evpn_es_show_entry(vty
, es
, json
);
2745 /* add ES to the json array */
2747 json_object_array_add(json_array
, json
);
2750 /* print the array of json-ESs */
2752 vty_json(vty
, json_array
);
2755 /* Display specific ES */
2756 void bgp_evpn_es_show_esi(struct vty
*vty
, esi_t
*esi
, bool uj
)
2758 struct bgp_evpn_es
*es
;
2759 json_object
*json
= NULL
;
2762 json
= json_object_new_object();
2764 es
= bgp_evpn_es_find(esi
);
2766 bgp_evpn_es_show_entry_detail(vty
, es
, json
);
2769 vty_out(vty
, "ESI not found\n");
2773 vty_json(vty
, json
);
2776 /*****************************************************************************/
2777 /* Ethernet Segment to VRF association -
2778 * 1. Each ES-EVI entry is associated with a tenant VRF. This associaton
2779 * triggers the creation of an ES-VRF entry.
2780 * 2. The ES-VRF entry is maintained for the purpose of L3-NHG creation
2781 * 3. Type-2/MAC-IP routes are imported into a tenant VRF and programmed as
2782 * a /32 or host route entry in the dataplane. If the destination of
2783 * the host route is a remote-ES the route is programmed with the
2784 * corresponding (keyed in by {vrf,ES-id}) L3-NHG.
2785 * 4. The reason for this indirection (route->L3-NHG, L3-NHG->list-of-VTEPs)
2786 * is to avoid route updates to the dplane when a remote-ES link flaps i.e.
2787 * instead of updating all the dependent routes the NHG's contents are updated.
2788 * This reduces the amount of datplane updates (nhg updates vs. route updates)
2789 * allowing for a faster failover.
2791 * XXX - can the L3 SVI index change without change in vpn->bgp_vrf
2792 * association? If yes we need to handle that by updating all the L3 NHGs
2795 /******************************** L3 NHG management *************************/
2796 static void bgp_evpn_l3nhg_zebra_add_v4_or_v6(struct bgp_evpn_es_vrf
*es_vrf
,
2799 uint32_t nhg_id
= v4_nhg
? es_vrf
->nhg_id
: es_vrf
->v6_nhg_id
;
2800 struct bgp_evpn_es
*es
= es_vrf
->es
;
2801 struct listnode
*node
;
2802 struct bgp_evpn_es_vtep
*es_vtep
;
2804 struct zapi_nexthop
*api_nh
;
2805 struct zapi_nhg api_nhg
= {};
2807 /* Skip installation of L3-NHG if host routes used */
2811 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2812 zlog_debug("es %s vrf %u %s nhg %u to zebra", es
->esi_str
,
2813 es_vrf
->bgp_vrf
->vrf_id
,
2814 v4_nhg
? "v4_nhg" : "v6_nhg", nhg_id
);
2816 frrtrace(4, frr_bgp
, evpn_mh_nhg_zsend
, true, v4_nhg
, nhg_id
, es_vrf
);
2818 /* only the gateway ip changes for each NH. rest of the params
2821 memset(&nh
, 0, sizeof(nh
));
2822 nh
.vrf_id
= es_vrf
->bgp_vrf
->vrf_id
;
2823 nh
.flags
= NEXTHOP_FLAG_ONLINK
;
2824 nh
.ifindex
= es_vrf
->bgp_vrf
->l3vni_svi_ifindex
;
2827 v4_nhg
? NEXTHOP_TYPE_IPV4_IFINDEX
: NEXTHOP_TYPE_IPV6_IFINDEX
;
2829 api_nhg
.id
= nhg_id
;
2830 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
2831 if (!CHECK_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
))
2834 /* Don't overrun the zapi buffer. */
2835 if (api_nhg
.nexthop_num
== MULTIPATH_NUM
)
2838 /* overwrite the gw */
2840 nh
.gate
.ipv4
= es_vtep
->vtep_ip
;
2842 ipv4_to_ipv4_mapped_ipv6(&nh
.gate
.ipv6
,
2845 /* convert to zapi format */
2846 api_nh
= &api_nhg
.nexthops
[api_nhg
.nexthop_num
];
2847 zapi_nexthop_from_nexthop(api_nh
, &nh
);
2849 ++api_nhg
.nexthop_num
;
2850 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2851 zlog_debug("nhg %u vtep %pI4 l3-svi %d", api_nhg
.id
,
2853 es_vrf
->bgp_vrf
->l3vni_svi_ifindex
);
2855 frrtrace(3, frr_bgp
, evpn_mh_nh_zsend
, nhg_id
, es_vtep
, es_vrf
);
2858 if (!api_nhg
.nexthop_num
)
2861 zclient_nhg_send(zclient
, ZEBRA_NHG_ADD
, &api_nhg
);
2864 static bool bgp_evpn_l3nhg_zebra_ok(struct bgp_evpn_es_vrf
*es_vrf
)
2866 if (!bgp_mh_info
->host_routes_use_l3nhg
)
2870 if (!zclient
|| zclient
->sock
< 0)
2876 static void bgp_evpn_l3nhg_zebra_add(struct bgp_evpn_es_vrf
*es_vrf
)
2878 if (!bgp_evpn_l3nhg_zebra_ok(es_vrf
))
2881 bgp_evpn_l3nhg_zebra_add_v4_or_v6(es_vrf
, true /*v4_nhg*/);
2882 bgp_evpn_l3nhg_zebra_add_v4_or_v6(es_vrf
, false /*v4_nhg*/);
2885 static void bgp_evpn_l3nhg_zebra_del_v4_or_v6(struct bgp_evpn_es_vrf
*es_vrf
,
2888 struct zapi_nhg api_nhg
= {};
2890 api_nhg
.id
= v4_nhg
? es_vrf
->nhg_id
: es_vrf
->v6_nhg_id
;
2892 /* Skip installation of L3-NHG if host routes used */
2896 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2897 zlog_debug("es %s vrf %u %s nhg %u to zebra",
2898 es_vrf
->es
->esi_str
, es_vrf
->bgp_vrf
->vrf_id
,
2899 v4_nhg
? "v4_nhg" : "v6_nhg", api_nhg
.id
);
2902 frrtrace(4, frr_bgp
, evpn_mh_nhg_zsend
, false, v4_nhg
, api_nhg
.id
,
2905 zclient_nhg_send(zclient
, ZEBRA_NHG_DEL
, &api_nhg
);
2908 static void bgp_evpn_l3nhg_zebra_del(struct bgp_evpn_es_vrf
*es_vrf
)
2910 if (!bgp_evpn_l3nhg_zebra_ok(es_vrf
))
2913 bgp_evpn_l3nhg_zebra_del_v4_or_v6(es_vrf
, true /*v4_nhg*/);
2914 bgp_evpn_l3nhg_zebra_del_v4_or_v6(es_vrf
, false /*v4_nhg*/);
2917 static void bgp_evpn_l3nhg_deactivate(struct bgp_evpn_es_vrf
*es_vrf
)
2919 if (!(es_vrf
->flags
& BGP_EVPNES_VRF_NHG_ACTIVE
))
2922 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2923 zlog_debug("es %s vrf %u nhg %u de-activate",
2924 es_vrf
->es
->esi_str
, es_vrf
->bgp_vrf
->vrf_id
,
2926 bgp_evpn_l3nhg_zebra_del(es_vrf
);
2927 es_vrf
->flags
&= ~BGP_EVPNES_VRF_NHG_ACTIVE
;
2928 /* MAC-IPs can now be installed via the L3NHG */
2929 bgp_evpn_es_path_update_on_es_vrf_chg(es_vrf
, "l3nhg-deactivate");
2932 static void bgp_evpn_l3nhg_activate(struct bgp_evpn_es_vrf
*es_vrf
, bool update
)
2934 if (!bgp_evpn_es_get_active_vtep_cnt(es_vrf
->es
)) {
2935 bgp_evpn_l3nhg_deactivate(es_vrf
);
2939 if (es_vrf
->flags
& BGP_EVPNES_VRF_NHG_ACTIVE
) {
2943 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2944 zlog_debug("es %s vrf %u nhg %u activate",
2945 es_vrf
->es
->esi_str
, es_vrf
->bgp_vrf
->vrf_id
,
2947 es_vrf
->flags
|= BGP_EVPNES_VRF_NHG_ACTIVE
;
2948 /* MAC-IPs can now be installed via the L3NHG */
2949 bgp_evpn_es_path_update_on_es_vrf_chg(es_vrf
, "l3nhg_activate");
2952 bgp_evpn_l3nhg_zebra_add(es_vrf
);
2955 /* when a VTEP is activated or de-activated against an ES associated
2956 * VRFs' NHG needs to be updated
2958 static void bgp_evpn_l3nhg_update_on_vtep_chg(struct bgp_evpn_es
*es
)
2960 struct bgp_evpn_es_vrf
*es_vrf
;
2961 struct listnode
*es_vrf_node
;
2963 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2964 zlog_debug("es %s nhg update on vtep chg", es
->esi_str
);
2966 for (ALL_LIST_ELEMENTS_RO(es
->es_vrf_list
, es_vrf_node
, es_vrf
))
2967 bgp_evpn_l3nhg_activate(es_vrf
, true /* update */);
2970 /* compare ES-IDs for the ES-VRF RB tree maintained per-VRF */
2971 static int bgp_es_vrf_rb_cmp(const struct bgp_evpn_es_vrf
*es_vrf1
,
2972 const struct bgp_evpn_es_vrf
*es_vrf2
)
2974 return memcmp(&es_vrf1
->es
->esi
, &es_vrf2
->es
->esi
, ESI_BYTES
);
2976 RB_GENERATE(bgp_es_vrf_rb_head
, bgp_evpn_es_vrf
, rb_node
, bgp_es_vrf_rb_cmp
);
2978 /* Initialize the ES tables maintained per-tenant vrf */
2979 void bgp_evpn_vrf_es_init(struct bgp
*bgp_vrf
)
2981 /* Initialize the ES-VRF RB tree */
2982 RB_INIT(bgp_es_vrf_rb_head
, &bgp_vrf
->es_vrf_rb_tree
);
2985 /* find the ES-VRF in the per-VRF RB tree */
2986 static struct bgp_evpn_es_vrf
*bgp_evpn_es_vrf_find(struct bgp_evpn_es
*es
,
2987 struct bgp
*bgp_vrf
)
2989 struct bgp_evpn_es_vrf es_vrf
;
2993 return RB_FIND(bgp_es_vrf_rb_head
, &bgp_vrf
->es_vrf_rb_tree
, &es_vrf
);
2996 /* allocate a new ES-VRF and setup L3NHG for it */
2997 static struct bgp_evpn_es_vrf
*bgp_evpn_es_vrf_create(struct bgp_evpn_es
*es
,
2998 struct bgp
*bgp_vrf
)
3000 struct bgp_evpn_es_vrf
*es_vrf
;
3002 es_vrf
= XCALLOC(MTYPE_BGP_EVPN_ES_VRF
, sizeof(*es_vrf
));
3005 es_vrf
->bgp_vrf
= bgp_vrf
;
3007 /* insert into the VRF-ESI rb tree */
3008 RB_INSERT(bgp_es_vrf_rb_head
, &bgp_vrf
->es_vrf_rb_tree
, es_vrf
);
3010 /* add to the ES's VRF list */
3011 listnode_init(&es_vrf
->es_listnode
, es_vrf
);
3012 listnode_add(es
->es_vrf_list
, &es_vrf
->es_listnode
);
3014 /* setup the L3 NHG id for the ES */
3015 es_vrf
->nhg_id
= bgp_l3nhg_id_alloc();
3016 es_vrf
->v6_nhg_id
= bgp_l3nhg_id_alloc();
3018 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3019 zlog_debug("es %s vrf %u nhg %u v6_nhg %d create", es
->esi_str
,
3020 bgp_vrf
->vrf_id
, es_vrf
->nhg_id
, es_vrf
->v6_nhg_id
);
3021 bgp_evpn_l3nhg_activate(es_vrf
, false /* update */);
3023 /* update paths in the VRF that may already be associated with
3024 * this destination ES
3026 bgp_evpn_es_path_update_on_es_vrf_chg(es_vrf
, "es-vrf-create");
3031 /* remove the L3-NHG associated with the ES-VRF and free it */
3032 static void bgp_evpn_es_vrf_delete(struct bgp_evpn_es_vrf
*es_vrf
)
3034 struct bgp_evpn_es
*es
= es_vrf
->es
;
3035 struct bgp
*bgp_vrf
= es_vrf
->bgp_vrf
;
3037 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3038 zlog_debug("es %s vrf %u nhg %u delete", es
->esi_str
,
3039 bgp_vrf
->vrf_id
, es_vrf
->nhg_id
);
3041 /* Remove the NHG resources */
3042 bgp_evpn_l3nhg_deactivate(es_vrf
);
3044 bgp_l3nhg_id_free(es_vrf
->nhg_id
);
3046 if (es_vrf
->v6_nhg_id
)
3047 bgp_l3nhg_id_free(es_vrf
->v6_nhg_id
);
3048 es_vrf
->v6_nhg_id
= 0;
3050 /* remove from the ES's VRF list */
3051 list_delete_node(es
->es_vrf_list
, &es_vrf
->es_listnode
);
3053 /* remove from the VRF-ESI rb tree */
3054 RB_REMOVE(bgp_es_vrf_rb_head
, &bgp_vrf
->es_vrf_rb_tree
, es_vrf
);
3056 /* update paths in the VRF that may already be associated with
3057 * this destination ES
3059 bgp_evpn_es_path_update_on_es_vrf_chg(es_vrf
, "es-vrf-delete");
3061 XFREE(MTYPE_BGP_EVPN_ES_VRF
, es_vrf
);
3064 /* deref and delete if there are no references */
3065 void bgp_evpn_es_vrf_deref(struct bgp_evpn_es_evi
*es_evi
)
3067 struct bgp_evpn_es_vrf
*es_vrf
= es_evi
->es_vrf
;
3072 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3073 zlog_debug("es-evi %s vni %u vrf %u de-ref",
3074 es_evi
->es
->esi_str
, es_evi
->vpn
->vni
,
3075 es_vrf
->bgp_vrf
->vrf_id
);
3077 es_evi
->es_vrf
= NULL
;
3078 if (es_vrf
->ref_cnt
)
3081 if (!es_vrf
->ref_cnt
)
3082 bgp_evpn_es_vrf_delete(es_vrf
);
3085 /* find or create and reference */
3086 void bgp_evpn_es_vrf_ref(struct bgp_evpn_es_evi
*es_evi
, struct bgp
*bgp_vrf
)
3088 struct bgp_evpn_es
*es
= es_evi
->es
;
3089 struct bgp_evpn_es_vrf
*es_vrf
= es_evi
->es_vrf
;
3090 struct bgp
*old_bgp_vrf
= NULL
;
3093 old_bgp_vrf
= es_vrf
->bgp_vrf
;
3095 if (old_bgp_vrf
== bgp_vrf
)
3098 /* deref the old ES-VRF */
3099 bgp_evpn_es_vrf_deref(es_evi
);
3104 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3105 zlog_debug("es-evi %s vni %u vrf %u ref", es_evi
->es
->esi_str
,
3106 es_evi
->vpn
->vni
, bgp_vrf
->vrf_id
);
3108 /* find-create the new ES-VRF */
3109 es_vrf
= bgp_evpn_es_vrf_find(es
, bgp_vrf
);
3111 es_vrf
= bgp_evpn_es_vrf_create(es
, bgp_vrf
);
3113 es_evi
->es_vrf
= es_vrf
;
3117 /* When the L2-VNI is associated with a L3-VNI/VRF update all the
3118 * associated ES-EVI entries
3120 void bgp_evpn_es_evi_vrf_deref(struct bgpevpn
*vpn
)
3122 struct bgp_evpn_es_evi
*es_evi
;
3124 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3125 zlog_debug("es-vrf de-ref for vni %u", vpn
->vni
);
3127 RB_FOREACH (es_evi
, bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
)
3128 bgp_evpn_es_vrf_deref(es_evi
);
3130 void bgp_evpn_es_evi_vrf_ref(struct bgpevpn
*vpn
)
3132 struct bgp_evpn_es_evi
*es_evi
;
3134 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3135 zlog_debug("es-vrf ref for vni %u", vpn
->vni
);
3137 RB_FOREACH (es_evi
, bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
)
3138 bgp_evpn_es_vrf_ref(es_evi
, vpn
->bgp_vrf
);
3141 /* 1. If ES-VRF is not present install the host route with the exploded/flat
3143 * 2. If ES-VRF is present -
3144 * - if L3NHG has not been activated for the ES-VRF (this could be because
3145 * all the PEs attached to the VRF are down) do not install the route
3147 * - if L3NHG has been activated install the route via that L3NHG
3149 void bgp_evpn_es_vrf_use_nhg(struct bgp
*bgp_vrf
, esi_t
*esi
, bool *use_l3nhg
,
3150 bool *is_l3nhg_active
,
3151 struct bgp_evpn_es_vrf
**es_vrf_p
)
3153 struct bgp_evpn_es
*es
;
3154 struct bgp_evpn_es_vrf
*es_vrf
;
3156 if (!bgp_mh_info
->host_routes_use_l3nhg
)
3159 es
= bgp_evpn_es_find(esi
);
3163 es_vrf
= bgp_evpn_es_vrf_find(es
, bgp_vrf
);
3168 if (es_vrf
->flags
& BGP_EVPNES_VRF_NHG_ACTIVE
)
3169 *is_l3nhg_active
= true;
3174 /* returns false if legacy-exploded mp needs to be used for route install */
3175 bool bgp_evpn_path_es_use_nhg(struct bgp
*bgp_vrf
, struct bgp_path_info
*pi
,
3179 struct bgp_evpn_es_vrf
*es_vrf
= NULL
;
3180 struct bgp_path_info
*parent_pi
;
3181 struct bgp_node
*rn
;
3182 struct prefix_evpn
*evp
;
3183 struct bgp_path_info
*mpinfo
;
3184 bool use_l3nhg
= false;
3185 bool is_l3nhg_active
= false;
3189 /* we don't support NHG for routes leaked from another VRF yet */
3190 if (pi
->extra
&& pi
->extra
->bgp_orig
)
3193 parent_pi
= get_route_parent_evpn(pi
);
3197 rn
= parent_pi
->net
;
3201 evp
= (struct prefix_evpn
*)&rn
->p
;
3202 if (evp
->prefix
.route_type
!= BGP_EVPN_MAC_IP_ROUTE
)
3205 /* non-es path, use legacy-exploded multipath */
3206 esi
= bgp_evpn_attr_get_esi(parent_pi
->attr
);
3207 if (!memcmp(esi
, zero_esi
, sizeof(*esi
)))
3210 bgp_evpn_es_vrf_use_nhg(bgp_vrf
, esi
, &use_l3nhg
, &is_l3nhg_active
,
3213 /* L3NHG support is disabled, use legacy-exploded multipath */
3217 /* if the NHG has not been installed we cannot install the route yet,
3218 * return a 0-NHG to indicate that
3220 if (!is_l3nhg_active
)
3223 /* this needs to be set the v6NHG if v6route */
3224 if (is_evpn_prefix_ipaddr_v6(evp
))
3225 *nhg_p
= es_vrf
->v6_nhg_id
;
3227 *nhg_p
= es_vrf
->nhg_id
;
3229 for (mpinfo
= bgp_path_info_mpath_next(pi
); mpinfo
;
3230 mpinfo
= bgp_path_info_mpath_next(mpinfo
)) {
3231 /* if any of the paths have a different ESI we can't use
3232 * the NHG associated with the ES. fallback to legacy-exploded
3235 if (memcmp(esi
, bgp_evpn_attr_get_esi(mpinfo
->attr
),
3243 static void bgp_evpn_es_vrf_show_entry(struct vty
*vty
,
3244 struct bgp_evpn_es_vrf
*es_vrf
,
3247 struct bgp_evpn_es
*es
= es_vrf
->es
;
3248 struct bgp
*bgp_vrf
= es_vrf
->bgp_vrf
;
3251 json_object
*json_types
;
3253 json_object_string_add(json
, "esi", es
->esi_str
);
3254 json_object_string_add(json
, "vrf", bgp_vrf
->name
);
3256 if (es_vrf
->flags
& (BGP_EVPNES_VRF_NHG_ACTIVE
)) {
3257 json_types
= json_object_new_array();
3258 if (es_vrf
->flags
& BGP_EVPNES_VRF_NHG_ACTIVE
)
3259 json_array_string_add(json_types
, "active");
3260 json_object_object_add(json
, "flags", json_types
);
3263 json_object_int_add(json
, "ipv4NHG", es_vrf
->nhg_id
);
3264 json_object_int_add(json
, "ipv6NHG", es_vrf
->v6_nhg_id
);
3265 json_object_int_add(json
, "refCount", es_vrf
->ref_cnt
);
3269 flags_str
[0] = '\0';
3270 if (es_vrf
->flags
& BGP_EVPNES_VRF_NHG_ACTIVE
)
3271 strlcat(flags_str
, "A", sizeof(flags_str
));
3273 vty_out(vty
, "%-30s %-15s %-5s %-8u %-8u %u\n", es
->esi_str
,
3274 bgp_vrf
->name
, flags_str
, es_vrf
->nhg_id
,
3275 es_vrf
->v6_nhg_id
, es_vrf
->ref_cnt
);
3279 static void bgp_evpn_es_vrf_show_es(struct vty
*vty
, json_object
*json_array
,
3280 struct bgp_evpn_es
*es
)
3282 json_object
*json
= NULL
;
3283 struct listnode
*es_vrf_node
;
3284 struct bgp_evpn_es_vrf
*es_vrf
;
3286 for (ALL_LIST_ELEMENTS_RO(es
->es_vrf_list
, es_vrf_node
, es_vrf
)) {
3287 /* create a separate json object for each ES-VRF */
3289 json
= json_object_new_object();
3290 bgp_evpn_es_vrf_show_entry(vty
, es_vrf
, json
);
3291 /* add ES-VRF to the json array */
3293 json_object_array_add(json_array
, json
);
3297 /* Display all ES VRFs */
3298 void bgp_evpn_es_vrf_show(struct vty
*vty
, bool uj
, struct bgp_evpn_es
*es
)
3300 json_object
*json_array
= NULL
;
3303 /* create an array of ESs */
3304 json_array
= json_object_new_array();
3306 vty_out(vty
, "ES-VRF Flags: A Active\n");
3307 vty_out(vty
, "%-30s %-15s %-5s %-8s %-8s %s\n", "ESI", "VRF",
3308 "Flags", "IPv4-NHG", "IPv6-NHG", "Ref");
3312 bgp_evpn_es_vrf_show_es(vty
, json_array
, es
);
3314 RB_FOREACH (es
, bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
)
3315 bgp_evpn_es_vrf_show_es(vty
, json_array
, es
);
3318 /* print the array of json-ESs */
3320 vty_json(vty
, json_array
);
3323 /* Display specific ES VRF */
3324 void bgp_evpn_es_vrf_show_esi(struct vty
*vty
, esi_t
*esi
, bool uj
)
3326 struct bgp_evpn_es
*es
;
3328 es
= bgp_evpn_es_find(esi
);
3330 bgp_evpn_es_vrf_show(vty
, uj
, es
);
3333 vty_out(vty
, "ESI not found\n");
3337 /*****************************************************************************/
3338 /* Ethernet Segment to EVI association -
3339 * 1. The ES-EVI entry is maintained as a RB tree per L2-VNI
3340 * (bgpevpn->es_evi_rb_tree).
3341 * 2. Each local ES-EVI entry is rxed from zebra and then used by BGP to
3342 * advertises an EAD-EVI (Type-1 EVPN) route
3343 * 3. The remote ES-EVI is created when a bgp_evpn_es_evi_vtep references
3347 /* A list of remote VTEPs is maintained for each ES-EVI. This list includes -
3348 * 1. VTEPs for which we have imported the EAD-per-ES Type1 route
3349 * 2. VTEPs for which we have imported the EAD-per-EVI Type1 route
3350 * VTEPs for which both routes have been rxed are activated. Activation
3351 * creates a NHG in the parent ES.
3353 static int bgp_evpn_es_evi_vtep_cmp(void *p1
, void *p2
)
3355 const struct bgp_evpn_es_evi_vtep
*evi_vtep1
= p1
;
3356 const struct bgp_evpn_es_evi_vtep
*evi_vtep2
= p2
;
3358 return evi_vtep1
->vtep_ip
.s_addr
- evi_vtep2
->vtep_ip
.s_addr
;
3361 static struct bgp_evpn_es_evi_vtep
*bgp_evpn_es_evi_vtep_new(
3362 struct bgp_evpn_es_evi
*es_evi
, struct in_addr vtep_ip
)
3364 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
3366 evi_vtep
= XCALLOC(MTYPE_BGP_EVPN_ES_EVI_VTEP
, sizeof(*evi_vtep
));
3368 evi_vtep
->es_evi
= es_evi
;
3369 evi_vtep
->vtep_ip
.s_addr
= vtep_ip
.s_addr
;
3370 listnode_init(&evi_vtep
->es_evi_listnode
, evi_vtep
);
3371 listnode_add_sort(es_evi
->es_evi_vtep_list
, &evi_vtep
->es_evi_listnode
);
3376 static void bgp_evpn_es_evi_vtep_free(struct bgp_evpn_es_evi_vtep
*evi_vtep
)
3378 struct bgp_evpn_es_evi
*es_evi
= evi_vtep
->es_evi
;
3380 if (evi_vtep
->flags
& (BGP_EVPN_EVI_VTEP_EAD
))
3381 /* as long as there is some reference we can't free it */
3384 list_delete_node(es_evi
->es_evi_vtep_list
, &evi_vtep
->es_evi_listnode
);
3385 XFREE(MTYPE_BGP_EVPN_ES_EVI_VTEP
, evi_vtep
);
3388 /* check if VTEP is already part of the list */
3389 static struct bgp_evpn_es_evi_vtep
*bgp_evpn_es_evi_vtep_find(
3390 struct bgp_evpn_es_evi
*es_evi
, struct in_addr vtep_ip
)
3392 struct listnode
*node
= NULL
;
3393 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
3395 for (ALL_LIST_ELEMENTS_RO(es_evi
->es_evi_vtep_list
, node
, evi_vtep
)) {
3396 if (evi_vtep
->vtep_ip
.s_addr
== vtep_ip
.s_addr
)
3402 /* A VTEP can be added as "active" attach to an ES if EAD-per-ES and
3403 * EAD-per-EVI routes are rxed from it.
3405 static void bgp_evpn_es_evi_vtep_re_eval_active(struct bgp
*bgp
,
3406 struct bgp_evpn_es_evi_vtep
*evi_vtep
)
3410 uint32_t ead_activity_flags
;
3412 old_active
= CHECK_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
);
3414 if (bgp_mh_info
->ead_evi_rx
)
3415 /* Both EAD-per-ES and EAD-per-EVI routes must be rxed from a PE
3416 * before it can be activated.
3418 ead_activity_flags
= BGP_EVPN_EVI_VTEP_EAD
;
3420 /* EAD-per-ES is sufficent to activate the PE */
3421 ead_activity_flags
= BGP_EVPN_EVI_VTEP_EAD_PER_ES
;
3423 if ((evi_vtep
->flags
& ead_activity_flags
) == ead_activity_flags
)
3424 SET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
);
3426 UNSET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
);
3428 new_active
= CHECK_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
);
3430 if (old_active
== new_active
)
3433 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3434 zlog_debug("es %s evi %u vtep %pI4 %s",
3435 evi_vtep
->es_evi
->es
->esi_str
,
3436 evi_vtep
->es_evi
->vpn
->vni
, &evi_vtep
->vtep_ip
,
3437 new_active
? "active" : "inactive");
3439 /* add VTEP to parent es */
3441 evi_vtep
->es_vtep
= bgp_evpn_es_vtep_add(
3442 bgp
, evi_vtep
->es_evi
->es
, evi_vtep
->vtep_ip
,
3443 false /*esr*/, 0, 0);
3445 if (evi_vtep
->es_vtep
) {
3446 bgp_evpn_es_vtep_do_del(bgp
, evi_vtep
->es_vtep
,
3448 evi_vtep
->es_vtep
= NULL
;
3451 /* queue up the parent es for background consistency checks */
3452 bgp_evpn_es_cons_checks_pend_add(evi_vtep
->es_evi
->es
);
3455 static void bgp_evpn_es_evi_vtep_add(struct bgp
*bgp
,
3456 struct bgp_evpn_es_evi
*es_evi
, struct in_addr vtep_ip
,
3459 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
3461 evi_vtep
= bgp_evpn_es_evi_vtep_find(es_evi
, vtep_ip
);
3464 evi_vtep
= bgp_evpn_es_evi_vtep_new(es_evi
, vtep_ip
);
3466 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3467 zlog_debug("add es %s evi %u vtep %pI4 %s",
3468 evi_vtep
->es_evi
->es
->esi_str
,
3469 evi_vtep
->es_evi
->vpn
->vni
, &evi_vtep
->vtep_ip
,
3470 ead_es
? "ead_es" : "ead_evi");
3473 SET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_EAD_PER_ES
);
3475 SET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_EAD_PER_EVI
);
3477 bgp_evpn_es_evi_vtep_re_eval_active(bgp
, evi_vtep
);
3480 static void bgp_evpn_es_evi_vtep_del(struct bgp
*bgp
,
3481 struct bgp_evpn_es_evi
*es_evi
, struct in_addr vtep_ip
,
3484 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
3486 evi_vtep
= bgp_evpn_es_evi_vtep_find(es_evi
, vtep_ip
);
3490 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3491 zlog_debug("del es %s evi %u vtep %pI4 %s",
3492 evi_vtep
->es_evi
->es
->esi_str
,
3493 evi_vtep
->es_evi
->vpn
->vni
, &evi_vtep
->vtep_ip
,
3494 ead_es
? "ead_es" : "ead_evi");
3497 UNSET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_EAD_PER_ES
);
3499 UNSET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_EAD_PER_EVI
);
3501 bgp_evpn_es_evi_vtep_re_eval_active(bgp
, evi_vtep
);
3502 bgp_evpn_es_evi_vtep_free(evi_vtep
);
3505 /* compare ES-IDs for the ES-EVI RB tree maintained per-VNI */
3506 static int bgp_es_evi_rb_cmp(const struct bgp_evpn_es_evi
*es_evi1
,
3507 const struct bgp_evpn_es_evi
*es_evi2
)
3509 return memcmp(&es_evi1
->es
->esi
, &es_evi2
->es
->esi
, ESI_BYTES
);
3511 RB_GENERATE(bgp_es_evi_rb_head
, bgp_evpn_es_evi
, rb_node
, bgp_es_evi_rb_cmp
);
3513 /* find the ES-EVI in the per-L2-VNI RB tree */
3514 static struct bgp_evpn_es_evi
*bgp_evpn_es_evi_find(struct bgp_evpn_es
*es
,
3515 struct bgpevpn
*vpn
)
3517 struct bgp_evpn_es_evi es_evi
;
3521 return RB_FIND(bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
, &es_evi
);
3524 /* allocate a new ES-EVI and insert it into the per-L2-VNI and per-ES
3527 static struct bgp_evpn_es_evi
*bgp_evpn_es_evi_new(struct bgp_evpn_es
*es
,
3528 struct bgpevpn
*vpn
)
3530 struct bgp_evpn_es_evi
*es_evi
;
3532 es_evi
= XCALLOC(MTYPE_BGP_EVPN_ES_EVI
, sizeof(*es_evi
));
3537 /* Initialise the VTEP list */
3538 es_evi
->es_evi_vtep_list
= list_new();
3539 listset_app_node_mem(es_evi
->es_evi_vtep_list
);
3540 es_evi
->es_evi_vtep_list
->cmp
= bgp_evpn_es_evi_vtep_cmp
;
3542 /* insert into the VNI-ESI rb tree */
3543 RB_INSERT(bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
, es_evi
);
3545 /* add to the ES's VNI list */
3546 listnode_init(&es_evi
->es_listnode
, es_evi
);
3547 listnode_add(es
->es_evi_list
, &es_evi
->es_listnode
);
3549 bgp_evpn_es_vrf_ref(es_evi
, vpn
->bgp_vrf
);
3554 /* remove the ES-EVI from the per-L2-VNI and per-ES tables and free
3557 static struct bgp_evpn_es_evi
*
3558 bgp_evpn_es_evi_free(struct bgp_evpn_es_evi
*es_evi
)
3560 struct bgp_evpn_es
*es
= es_evi
->es
;
3561 struct bgpevpn
*vpn
= es_evi
->vpn
;
3563 /* cannot free the element as long as there is a local or remote
3566 if (es_evi
->flags
& (BGP_EVPNES_EVI_LOCAL
| BGP_EVPNES_EVI_REMOTE
))
3568 bgp_evpn_es_frag_evi_del(es_evi
, false);
3569 bgp_evpn_es_vrf_deref(es_evi
);
3571 /* remove from the ES's VNI list */
3572 list_delete_node(es
->es_evi_list
, &es_evi
->es_listnode
);
3574 /* remove from the VNI-ESI rb tree */
3575 RB_REMOVE(bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
, es_evi
);
3577 /* free the VTEP list */
3578 list_delete(&es_evi
->es_evi_vtep_list
);
3580 /* remove from the VNI-ESI rb tree */
3581 XFREE(MTYPE_BGP_EVPN_ES_EVI
, es_evi
);
3586 /* init local info associated with the ES-EVI */
3587 static void bgp_evpn_es_evi_local_info_set(struct bgp_evpn_es_evi
*es_evi
)
3589 struct bgpevpn
*vpn
= es_evi
->vpn
;
3591 if (CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
3594 SET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
);
3595 listnode_init(&es_evi
->l2vni_listnode
, es_evi
);
3596 listnode_add(vpn
->local_es_evi_list
, &es_evi
->l2vni_listnode
);
3597 bgp_evpn_es_frag_evi_add(es_evi
);
3600 /* clear any local info associated with the ES-EVI */
3601 static struct bgp_evpn_es_evi
*
3602 bgp_evpn_es_evi_local_info_clear(struct bgp_evpn_es_evi
*es_evi
)
3604 struct bgpevpn
*vpn
= es_evi
->vpn
;
3606 UNSET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
);
3607 list_delete_node(vpn
->local_es_evi_list
, &es_evi
->l2vni_listnode
);
3609 return bgp_evpn_es_evi_free(es_evi
);
3612 /* eval remote info associated with the ES */
3613 static void bgp_evpn_es_evi_remote_info_re_eval(struct bgp_evpn_es_evi
*es_evi
)
3615 struct bgp_evpn_es
*es
= es_evi
->es
;
3617 /* if there are remote VTEPs the ES-EVI is classified as "remote" */
3618 if (listcount(es_evi
->es_evi_vtep_list
)) {
3619 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_REMOTE
)) {
3620 SET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_REMOTE
);
3621 ++es
->remote_es_evi_cnt
;
3622 /* set remote on the parent es */
3623 bgp_evpn_es_remote_info_re_eval(es
);
3626 if (CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_REMOTE
)) {
3627 UNSET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_REMOTE
);
3628 if (es
->remote_es_evi_cnt
)
3629 --es
->remote_es_evi_cnt
;
3630 bgp_evpn_es_evi_free(es_evi
);
3631 /* check if "remote" can be cleared from the
3634 bgp_evpn_es_remote_info_re_eval(es
);
3639 static struct bgp_evpn_es_evi
*
3640 bgp_evpn_local_es_evi_do_del(struct bgp_evpn_es_evi
*es_evi
)
3642 struct prefix_evpn p
;
3643 struct bgp_evpn_es
*es
= es_evi
->es
;
3646 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
3649 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3650 zlog_debug("del local es %s evi %u",
3651 es_evi
->es
->esi_str
,
3654 bgp
= bgp_get_evpn();
3656 /* remove the es_evi from the es_frag before sending the update */
3657 bgp_evpn_es_frag_evi_del(es_evi
, true);
3659 /* update EAD-ES with new list of VNIs */
3660 if (bgp_evpn_local_es_is_active(es
))
3661 bgp_evpn_ead_es_route_update(bgp
, es
);
3663 /* withdraw and delete EAD-EVI */
3664 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
)) {
3665 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_EVI_ETH_TAG
,
3666 &es
->esi
, es
->originator_ip
);
3667 if (bgp_evpn_ead_evi_route_delete(bgp
, es
, es_evi
->vpn
,
3669 flog_err(EC_BGP_EVPN_ROUTE_DELETE
,
3670 "%u: EAD-EVI route deletion failure for ESI %s VNI %u",
3671 bgp
->vrf_id
, es
->esi_str
,
3676 return bgp_evpn_es_evi_local_info_clear(es_evi
);
3679 int bgp_evpn_local_es_evi_del(struct bgp
*bgp
, esi_t
*esi
, vni_t vni
)
3681 struct bgpevpn
*vpn
;
3682 struct bgp_evpn_es
*es
;
3683 struct bgp_evpn_es_evi
*es_evi
;
3684 char buf
[ESI_STR_LEN
];
3686 es
= bgp_evpn_es_find(esi
);
3690 "%u: Failed to deref VNI %d from ESI %s; ES not present",
3692 esi_to_str(esi
, buf
, sizeof(buf
)));
3696 vpn
= bgp_evpn_lookup_vni(bgp
, vni
);
3700 "%u: Failed to deref VNI %d from ESI %s; VNI not present",
3701 bgp
->vrf_id
, vni
, es
->esi_str
);
3705 es_evi
= bgp_evpn_es_evi_find(es
, vpn
);
3709 "%u: Failed to deref VNI %d from ESI %s; ES-VNI not present",
3710 bgp
->vrf_id
, vni
, es
->esi_str
);
3714 bgp_evpn_local_es_evi_do_del(es_evi
);
3718 /* Create ES-EVI and advertise the corresponding EAD routes */
3719 int bgp_evpn_local_es_evi_add(struct bgp
*bgp
, esi_t
*esi
, vni_t vni
)
3721 struct bgpevpn
*vpn
;
3722 struct prefix_evpn p
;
3723 struct bgp_evpn_es
*es
;
3724 struct bgp_evpn_es_evi
*es_evi
;
3725 char buf
[ESI_STR_LEN
];
3727 es
= bgp_evpn_es_find(esi
);
3731 "%u: Failed to associate VNI %d with ESI %s; ES not present",
3733 esi_to_str(esi
, buf
, sizeof(buf
)));
3737 vpn
= bgp_evpn_lookup_vni(bgp
, vni
);
3741 "%u: Failed to associate VNI %d with ESI %s; VNI not present",
3742 bgp
->vrf_id
, vni
, es
->esi_str
);
3746 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3747 zlog_debug("add local es %s evi %u",
3750 es_evi
= bgp_evpn_es_evi_find(es
, vpn
);
3753 if (CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
3757 es_evi
= bgp_evpn_es_evi_new(es
, vpn
);
3759 bgp_evpn_es_evi_local_info_set(es_evi
);
3761 /* generate an EAD-EVI for this new VNI */
3762 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
)) {
3763 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_EVI_ETH_TAG
, &es
->esi
,
3765 bgp_evpn_ead_evi_route_update(bgp
, es
, vpn
, &p
);
3769 if (bgp_evpn_local_es_is_active(es
))
3770 bgp_evpn_ead_es_route_update(bgp
, es
);
3775 /* Add remote ES-EVI entry. This is actually the remote VTEP add and the
3776 * ES-EVI is implicity created on first VTEP's reference.
3778 int bgp_evpn_remote_es_evi_add(struct bgp
*bgp
, struct bgpevpn
*vpn
,
3779 const struct prefix_evpn
*p
)
3781 char buf
[ESI_STR_LEN
];
3782 struct bgp_evpn_es
*es
;
3783 struct bgp_evpn_es_evi
*es_evi
;
3785 const esi_t
*esi
= &p
->prefix
.ead_addr
.esi
;
3788 /* local EAD-ES need not be sent back to zebra */
3791 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3792 zlog_debug("add remote %s es %s evi %u vtep %pI4",
3793 p
->prefix
.ead_addr
.eth_tag
? "ead-es" : "ead-evi",
3794 esi_to_str(esi
, buf
, sizeof(buf
)), vpn
->vni
,
3795 &p
->prefix
.ead_addr
.ip
.ipaddr_v4
);
3797 es
= bgp_evpn_es_find(esi
);
3799 es
= bgp_evpn_es_new(bgp
, esi
);
3801 es_evi
= bgp_evpn_es_evi_find(es
, vpn
);
3803 es_evi
= bgp_evpn_es_evi_new(es
, vpn
);
3805 ead_es
= !!p
->prefix
.ead_addr
.eth_tag
;
3806 bgp_evpn_es_evi_vtep_add(bgp
, es_evi
, p
->prefix
.ead_addr
.ip
.ipaddr_v4
,
3809 bgp_evpn_es_evi_remote_info_re_eval(es_evi
);
3813 /* A remote VTEP has withdrawn. The es-evi-vtep will be deleted and the
3814 * parent es-evi freed up implicitly in last VTEP's deref.
3816 int bgp_evpn_remote_es_evi_del(struct bgp
*bgp
, struct bgpevpn
*vpn
,
3817 const struct prefix_evpn
*p
)
3819 char buf
[ESI_STR_LEN
];
3820 struct bgp_evpn_es
*es
;
3821 struct bgp_evpn_es_evi
*es_evi
;
3825 /* local EAD-ES need not be sent back to zebra */
3828 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3830 "del remote %s es %s evi %u vtep %pI4",
3831 p
->prefix
.ead_addr
.eth_tag
? "ead-es" : "ead-evi",
3832 esi_to_str(&p
->prefix
.ead_addr
.esi
, buf
, sizeof(buf
)),
3833 vpn
->vni
, &p
->prefix
.ead_addr
.ip
.ipaddr_v4
);
3835 es
= bgp_evpn_es_find(&p
->prefix
.ead_addr
.esi
);
3837 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3839 "del remote %s es %s evi %u vtep %pI4, NO es",
3840 p
->prefix
.ead_addr
.eth_tag
? "ead-es"
3842 esi_to_str(&p
->prefix
.ead_addr
.esi
, buf
,
3844 vpn
->vni
, &p
->prefix
.ead_addr
.ip
.ipaddr_v4
);
3847 es_evi
= bgp_evpn_es_evi_find(es
, vpn
);
3849 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3851 "del remote %s es %s evi %u vtep %pI4, NO es-evi",
3852 p
->prefix
.ead_addr
.eth_tag
? "ead-es"
3854 esi_to_str(&p
->prefix
.ead_addr
.esi
, buf
,
3857 &p
->prefix
.ead_addr
.ip
.ipaddr_v4
);
3861 ead_es
= !!p
->prefix
.ead_addr
.eth_tag
;
3862 bgp_evpn_es_evi_vtep_del(bgp
, es_evi
, p
->prefix
.ead_addr
.ip
.ipaddr_v4
,
3864 bgp_evpn_es_evi_remote_info_re_eval(es_evi
);
3868 /* If a VNI is being deleted we need to force del all remote VTEPs */
3869 static void bgp_evpn_remote_es_evi_flush(struct bgp_evpn_es_evi
*es_evi
)
3871 struct listnode
*node
= NULL
;
3872 struct listnode
*nnode
= NULL
;
3873 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
3876 bgp
= bgp_get_evpn();
3880 /* delete all VTEPs */
3881 for (ALL_LIST_ELEMENTS(es_evi
->es_evi_vtep_list
, node
, nnode
,
3883 evi_vtep
->flags
&= ~(BGP_EVPN_EVI_VTEP_EAD_PER_ES
3884 | BGP_EVPN_EVI_VTEP_EAD_PER_EVI
);
3885 bgp_evpn_es_evi_vtep_re_eval_active(bgp
, evi_vtep
);
3886 bgp_evpn_es_evi_vtep_free(evi_vtep
);
3888 /* delete the EVI */
3889 bgp_evpn_es_evi_remote_info_re_eval(es_evi
);
3892 /* Initialize the ES tables maintained per-L2_VNI */
3893 void bgp_evpn_vni_es_init(struct bgpevpn
*vpn
)
3895 /* Initialize the ES-EVI RB tree */
3896 RB_INIT(bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
);
3898 /* Initialize the local list maintained for quick walks by type */
3899 vpn
->local_es_evi_list
= list_new();
3900 listset_app_node_mem(vpn
->local_es_evi_list
);
3903 /* Cleanup the ES info maintained per-L2_VNI */
3904 void bgp_evpn_vni_es_cleanup(struct bgpevpn
*vpn
)
3906 struct bgp_evpn_es_evi
*es_evi
;
3907 struct bgp_evpn_es_evi
*es_evi_next
;
3909 RB_FOREACH_SAFE(es_evi
, bgp_es_evi_rb_head
,
3910 &vpn
->es_evi_rb_tree
, es_evi_next
) {
3911 es_evi
= bgp_evpn_local_es_evi_do_del(es_evi
);
3913 bgp_evpn_remote_es_evi_flush(es_evi
);
3916 list_delete(&vpn
->local_es_evi_list
);
3919 static char *bgp_evpn_es_evi_vteps_str(char *vtep_str
,
3920 struct bgp_evpn_es_evi
*es_evi
,
3921 uint8_t vtep_str_size
)
3923 char vtep_flag_str
[BGP_EVPN_FLAG_STR_SZ
];
3924 struct listnode
*node
;
3925 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
3927 char ip_buf
[INET6_ADDRSTRLEN
];
3930 for (ALL_LIST_ELEMENTS_RO(es_evi
->es_evi_vtep_list
, node
, evi_vtep
)) {
3931 vtep_flag_str
[0] = '\0';
3932 if (evi_vtep
->flags
& BGP_EVPN_EVI_VTEP_EAD_PER_ES
)
3933 strlcat(vtep_flag_str
, "E", sizeof(vtep_flag_str
));
3934 if (evi_vtep
->flags
& BGP_EVPN_EVI_VTEP_EAD_PER_EVI
)
3935 strlcat(vtep_flag_str
, "V", sizeof(vtep_flag_str
));
3937 if (!strnlen(vtep_flag_str
, sizeof(vtep_flag_str
)))
3938 strlcpy(vtep_flag_str
, "-", sizeof(vtep_flag_str
));
3942 strlcat(vtep_str
, ",", vtep_str_size
);
3944 inet_ntop(AF_INET
, &evi_vtep
->vtep_ip
, ip_buf
,
3947 strlcat(vtep_str
, "(", vtep_str_size
);
3948 strlcat(vtep_str
, vtep_flag_str
, vtep_str_size
);
3949 strlcat(vtep_str
, ")", vtep_str_size
);
3955 static void bgp_evpn_es_evi_json_vtep_fill(json_object
*json_vteps
,
3956 struct bgp_evpn_es_evi_vtep
*evi_vtep
)
3958 json_object
*json_vtep_entry
;
3959 json_object
*json_flags
;
3961 json_vtep_entry
= json_object_new_object();
3963 json_object_string_addf(json_vtep_entry
, "vtep_ip", "%pI4",
3964 &evi_vtep
->vtep_ip
);
3965 if (evi_vtep
->flags
& (BGP_EVPN_EVI_VTEP_EAD_PER_ES
|
3966 BGP_EVPN_EVI_VTEP_EAD_PER_EVI
)) {
3967 json_flags
= json_object_new_array();
3968 if (evi_vtep
->flags
& BGP_EVPN_EVI_VTEP_EAD_PER_ES
)
3969 json_array_string_add(json_flags
, "ead-per-es");
3970 if (evi_vtep
->flags
& BGP_EVPN_EVI_VTEP_EAD_PER_EVI
)
3971 json_array_string_add(json_flags
, "ead-per-evi");
3972 json_object_object_add(json_vtep_entry
,
3973 "flags", json_flags
);
3976 json_object_array_add(json_vteps
,
3980 static void bgp_evpn_es_evi_show_entry(struct vty
*vty
,
3981 struct bgp_evpn_es_evi
*es_evi
, json_object
*json
)
3983 struct listnode
*node
;
3984 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
3987 json_object
*json_vteps
;
3988 json_object
*json_types
;
3990 json_object_string_add(json
, "esi", es_evi
->es
->esi_str
);
3991 json_object_int_add(json
, "vni", es_evi
->vpn
->vni
);
3993 if (es_evi
->flags
& (BGP_EVPNES_EVI_LOCAL
|
3994 BGP_EVPNES_EVI_REMOTE
)) {
3995 json_types
= json_object_new_array();
3996 if (es_evi
->flags
& BGP_EVPNES_EVI_LOCAL
)
3997 json_array_string_add(json_types
, "local");
3998 if (es_evi
->flags
& BGP_EVPNES_EVI_REMOTE
)
3999 json_array_string_add(json_types
, "remote");
4000 json_object_object_add(json
, "type", json_types
);
4003 if (listcount(es_evi
->es_evi_vtep_list
)) {
4004 json_vteps
= json_object_new_array();
4005 for (ALL_LIST_ELEMENTS_RO(es_evi
->es_evi_vtep_list
,
4007 bgp_evpn_es_evi_json_vtep_fill(json_vteps
,
4010 json_object_object_add(json
, "vteps", json_vteps
);
4014 char vtep_str
[ES_VTEP_LIST_STR_SZ
+ BGP_EVPN_VTEPS_FLAG_STR_SZ
];
4017 if (es_evi
->flags
& BGP_EVPNES_EVI_LOCAL
)
4018 strlcat(type_str
, "L", sizeof(type_str
));
4019 if (es_evi
->flags
& BGP_EVPNES_EVI_REMOTE
)
4020 strlcat(type_str
, "R", sizeof(type_str
));
4021 if (es_evi
->flags
& BGP_EVPNES_EVI_INCONS_VTEP_LIST
)
4022 strlcat(type_str
, "I", sizeof(type_str
));
4024 bgp_evpn_es_evi_vteps_str(vtep_str
, es_evi
, sizeof(vtep_str
));
4026 vty_out(vty
, "%-8d %-30s %-5s %s\n",
4027 es_evi
->vpn
->vni
, es_evi
->es
->esi_str
,
4028 type_str
, vtep_str
);
4032 static void bgp_evpn_es_evi_show_entry_detail(struct vty
*vty
,
4033 struct bgp_evpn_es_evi
*es_evi
, json_object
*json
)
4035 char buf1
[RD_ADDRSTRLEN
];
4038 json_object
*json_flags
;
4040 /* Add the "brief" info first */
4041 bgp_evpn_es_evi_show_entry(vty
, es_evi
, json
);
4042 if (es_evi
->es_frag
)
4043 json_object_string_add(
4044 json
, "esFragmentRd",
4045 prefix_rd2str(&es_evi
->es_frag
->prd
, buf1
,
4047 if (es_evi
->flags
& BGP_EVPNES_EVI_INCONS_VTEP_LIST
) {
4048 json_flags
= json_object_new_array();
4049 json_array_string_add(json_flags
, "es-vtep-mismatch");
4050 json_object_object_add(json
, "flags", json_flags
);
4053 char vtep_str
[ES_VTEP_LIST_STR_SZ
+ BGP_EVPN_VTEPS_FLAG_STR_SZ
];
4057 if (es_evi
->flags
& BGP_EVPNES_EVI_LOCAL
)
4058 strlcat(type_str
, "L", sizeof(type_str
));
4059 if (es_evi
->flags
& BGP_EVPNES_EVI_REMOTE
)
4060 strlcat(type_str
, "R", sizeof(type_str
));
4062 bgp_evpn_es_evi_vteps_str(vtep_str
, es_evi
, sizeof(vtep_str
));
4063 if (!strlen(vtep_str
))
4064 strlcpy(vtep_str
, "-", sizeof(type_str
));
4066 vty_out(vty
, "VNI: %d ESI: %s\n",
4067 es_evi
->vpn
->vni
, es_evi
->es
->esi_str
);
4068 vty_out(vty
, " Type: %s\n", type_str
);
4069 if (es_evi
->es_frag
)
4070 vty_out(vty
, " ES fragment RD: %s\n",
4071 prefix_rd2str(&es_evi
->es_frag
->prd
, buf1
,
4073 vty_out(vty
, " Inconsistencies: %s\n",
4074 (es_evi
->flags
& BGP_EVPNES_EVI_INCONS_VTEP_LIST
) ?
4075 "es-vtep-mismatch":"-");
4076 vty_out(vty
, " VTEPs: %s\n", vtep_str
);
4081 static void bgp_evpn_es_evi_show_one_vni(struct bgpevpn
*vpn
, struct vty
*vty
,
4082 json_object
*json_array
, bool detail
)
4084 struct bgp_evpn_es_evi
*es_evi
;
4085 json_object
*json
= NULL
;
4087 RB_FOREACH(es_evi
, bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
) {
4089 /* create a separate json object for each ES */
4090 json
= json_object_new_object();
4092 bgp_evpn_es_evi_show_entry_detail(vty
, es_evi
, json
);
4094 bgp_evpn_es_evi_show_entry(vty
, es_evi
, json
);
4095 /* add ES to the json array */
4097 json_object_array_add(json_array
, json
);
4101 struct es_evi_show_ctx
{
4107 static void bgp_evpn_es_evi_show_one_vni_hash_cb(struct hash_bucket
*bucket
,
4110 struct bgpevpn
*vpn
= (struct bgpevpn
*)bucket
->data
;
4111 struct es_evi_show_ctx
*wctx
= (struct es_evi_show_ctx
*)ctxt
;
4113 bgp_evpn_es_evi_show_one_vni(vpn
, wctx
->vty
, wctx
->json
, wctx
->detail
);
4116 /* Display all ES EVIs */
4117 void bgp_evpn_es_evi_show(struct vty
*vty
, bool uj
, bool detail
)
4119 json_object
*json_array
= NULL
;
4120 struct es_evi_show_ctx wctx
;
4124 /* create an array of ES-EVIs */
4125 json_array
= json_object_new_array();
4129 wctx
.json
= json_array
;
4130 wctx
.detail
= detail
;
4132 bgp
= bgp_get_evpn();
4134 if (!json_array
&& !detail
) {
4135 vty_out(vty
, "Flags: L local, R remote, I inconsistent\n");
4136 vty_out(vty
, "VTEP-Flags: E EAD-per-ES, V EAD-per-EVI\n");
4137 vty_out(vty
, "%-8s %-30s %-5s %s\n",
4138 "VNI", "ESI", "Flags", "VTEPs");
4142 hash_iterate(bgp
->vnihash
,
4143 (void (*)(struct hash_bucket
*,
4144 void *))bgp_evpn_es_evi_show_one_vni_hash_cb
,
4147 vty_json(vty
, json_array
);
4150 /* Display specific ES EVI */
4151 void bgp_evpn_es_evi_show_vni(struct vty
*vty
, vni_t vni
,
4152 bool uj
, bool detail
)
4154 struct bgpevpn
*vpn
= NULL
;
4155 json_object
*json_array
= NULL
;
4159 /* create an array of ES-EVIs */
4160 json_array
= json_object_new_array();
4163 bgp
= bgp_get_evpn();
4165 vpn
= bgp_evpn_lookup_vni(bgp
, vni
);
4168 if (!json_array
&& !detail
) {
4169 vty_out(vty
, "Flags: L local, R remote, I inconsistent\n");
4170 vty_out(vty
, "VTEP-Flags: E EAD-per-ES, V EAD-per-EVI\n");
4171 vty_out(vty
, "%-8s %-30s %-5s %s\n",
4172 "VNI", "ESI", "Flags", "VTEPs");
4175 bgp_evpn_es_evi_show_one_vni(vpn
, vty
, json_array
, detail
);
4178 vty_out(vty
, "VNI not found\n");
4182 vty_json(vty
, json_array
);
4185 /*****************************************************************************
4186 * Ethernet Segment Consistency checks
4187 * Consistency checking is done to detect misconfig or mis-cabling. When
4188 * an inconsistency is detected it is simply logged (and displayed via
4189 * show commands) at this point. A more drastic action can be executed (based
4190 * on user config) in the future.
4192 static void bgp_evpn_es_cons_checks_timer_start(void)
4194 if (!bgp_mh_info
->consistency_checking
|| bgp_mh_info
->t_cons_check
)
4197 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
4198 zlog_debug("periodic consistency checking started");
4200 thread_add_timer(bm
->master
, bgp_evpn_run_consistency_checks
, NULL
,
4201 BGP_EVPN_CONS_CHECK_INTERVAL
,
4202 &bgp_mh_info
->t_cons_check
);
4205 /* queue up the es for background consistency checks */
4206 static void bgp_evpn_es_cons_checks_pend_add(struct bgp_evpn_es
*es
)
4208 if (!bgp_mh_info
->consistency_checking
)
4209 /* consistency checking is not enabled */
4212 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_CONS_CHECK_PEND
))
4213 /* already queued for consistency checking */
4216 /* start the periodic timer for consistency checks if it is not
4217 * already running */
4218 bgp_evpn_es_cons_checks_timer_start();
4220 SET_FLAG(es
->flags
, BGP_EVPNES_CONS_CHECK_PEND
);
4221 listnode_init(&es
->pend_es_listnode
, es
);
4222 listnode_add_after(bgp_mh_info
->pend_es_list
,
4223 listtail_unchecked(bgp_mh_info
->pend_es_list
),
4224 &es
->pend_es_listnode
);
4227 /* pull the ES from the consistency check list */
4228 static void bgp_evpn_es_cons_checks_pend_del(struct bgp_evpn_es
*es
)
4230 if (!CHECK_FLAG(es
->flags
, BGP_EVPNES_CONS_CHECK_PEND
))
4233 UNSET_FLAG(es
->flags
, BGP_EVPNES_CONS_CHECK_PEND
);
4234 list_delete_node(bgp_mh_info
->pend_es_list
,
4235 &es
->pend_es_listnode
);
4238 /* Number of active VTEPs associated with the ES-per-EVI */
4239 static uint32_t bgp_evpn_es_evi_get_active_vtep_cnt(
4240 struct bgp_evpn_es_evi
*es_evi
)
4242 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
4243 struct listnode
*node
;
4244 uint32_t vtep_cnt
= 0;
4246 for (ALL_LIST_ELEMENTS_RO(es_evi
->es_evi_vtep_list
, node
, evi_vtep
)) {
4247 if (CHECK_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
))
4254 /* Number of active VTEPs associated with the ES */
4255 static uint32_t bgp_evpn_es_get_active_vtep_cnt(struct bgp_evpn_es
*es
)
4257 struct listnode
*node
;
4258 uint32_t vtep_cnt
= 0;
4259 struct bgp_evpn_es_vtep
*es_vtep
;
4261 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
4262 if (CHECK_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
))
4269 static struct bgp_evpn_es_vtep
*bgp_evpn_es_get_next_active_vtep(
4270 struct bgp_evpn_es
*es
, struct bgp_evpn_es_vtep
*es_vtep
)
4272 struct listnode
*node
;
4273 struct bgp_evpn_es_vtep
*next_es_vtep
;
4276 node
= listnextnode_unchecked(&es_vtep
->es_listnode
);
4278 node
= listhead(es
->es_vtep_list
);
4280 for (; node
; node
= listnextnode_unchecked(node
)) {
4281 next_es_vtep
= listgetdata(node
);
4282 if (CHECK_FLAG(next_es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
))
4283 return next_es_vtep
;
4289 static struct bgp_evpn_es_evi_vtep
*bgp_evpn_es_evi_get_next_active_vtep(
4290 struct bgp_evpn_es_evi
*es_evi
,
4291 struct bgp_evpn_es_evi_vtep
*evi_vtep
)
4293 struct listnode
*node
;
4294 struct bgp_evpn_es_evi_vtep
*next_evi_vtep
;
4297 node
= listnextnode_unchecked(&evi_vtep
->es_evi_listnode
);
4299 node
= listhead(es_evi
->es_evi_vtep_list
);
4301 for (; node
; node
= listnextnode_unchecked(node
)) {
4302 next_evi_vtep
= listgetdata(node
);
4303 if (CHECK_FLAG(next_evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
))
4304 return next_evi_vtep
;
4310 static void bgp_evpn_es_evi_set_inconsistent(struct bgp_evpn_es_evi
*es_evi
)
4312 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_INCONS_VTEP_LIST
)) {
4313 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
4314 zlog_debug("inconsistency detected - es %s evi %u vtep list mismatch",
4315 es_evi
->es
->esi_str
,
4317 SET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_INCONS_VTEP_LIST
);
4319 /* update parent ES with the incosistency setting */
4320 if (!es_evi
->es
->incons_evi_vtep_cnt
&&
4321 BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
4322 zlog_debug("inconsistency detected - es %s vtep list mismatch",
4323 es_evi
->es
->esi_str
);
4324 ++es_evi
->es
->incons_evi_vtep_cnt
;
4325 SET_FLAG(es_evi
->es
->inconsistencies
,
4326 BGP_EVPNES_INCONS_VTEP_LIST
);
4330 static uint32_t bgp_evpn_es_run_consistency_checks(struct bgp_evpn_es
*es
)
4333 int es_active_vtep_cnt
;
4334 int evi_active_vtep_cnt
;
4335 struct bgp_evpn_es_evi
*es_evi
;
4336 struct listnode
*evi_node
;
4337 struct bgp_evpn_es_vtep
*es_vtep
;
4338 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
4340 /* reset the inconsistencies and re-evaluate */
4341 es
->incons_evi_vtep_cnt
= 0;
4342 es
->inconsistencies
= 0;
4344 es_active_vtep_cnt
= bgp_evpn_es_get_active_vtep_cnt(es
);
4345 for (ALL_LIST_ELEMENTS_RO(es
->es_evi_list
,
4346 evi_node
, es_evi
)) {
4349 /* reset the inconsistencies on the EVI and re-evaluate*/
4350 UNSET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_INCONS_VTEP_LIST
);
4352 evi_active_vtep_cnt
=
4353 bgp_evpn_es_evi_get_active_vtep_cnt(es_evi
);
4354 if (es_active_vtep_cnt
!= evi_active_vtep_cnt
) {
4355 bgp_evpn_es_evi_set_inconsistent(es_evi
);
4359 if (!es_active_vtep_cnt
)
4364 while ((es_vtep
= bgp_evpn_es_get_next_active_vtep(
4366 evi_vtep
= bgp_evpn_es_evi_get_next_active_vtep(es_evi
,
4369 bgp_evpn_es_evi_set_inconsistent(es_evi
);
4372 if (es_vtep
->vtep_ip
.s_addr
!=
4373 evi_vtep
->vtep_ip
.s_addr
) {
4374 /* inconsistency detected; set it and move
4377 bgp_evpn_es_evi_set_inconsistent(es_evi
);
4386 static void bgp_evpn_run_consistency_checks(struct thread
*t
)
4389 struct listnode
*node
;
4390 struct listnode
*nextnode
;
4391 struct bgp_evpn_es
*es
;
4393 for (ALL_LIST_ELEMENTS(bgp_mh_info
->pend_es_list
,
4394 node
, nextnode
, es
)) {
4396 /* run consistency checks on the ES and remove it from the
4399 proc_cnt
+= bgp_evpn_es_run_consistency_checks(es
);
4400 bgp_evpn_es_cons_checks_pend_del(es
);
4405 /* restart the timer */
4406 thread_add_timer(bm
->master
, bgp_evpn_run_consistency_checks
, NULL
,
4407 BGP_EVPN_CONS_CHECK_INTERVAL
,
4408 &bgp_mh_info
->t_cons_check
);
4411 /*****************************************************************************
4412 * EVPN-Nexthop and RMAC management: nexthops associated with Type-2 routes
4413 * that have an ES as destination are consolidated by BGP into a per-VRF
4414 * nh->rmac mapping which is sent to zebra. Zebra installs the nexthop
4415 * as a remote neigh/fdb entry with a dummy (type-1) prefix referencing it.
4417 * This handling is needed because Type-2 routes with ES as dest use NHG
4418 * that is setup using EAD routes (i.e. such NHGs do not include the
4420 ****************************************************************************/
4421 static void bgp_evpn_nh_zebra_update_send(struct bgp_evpn_nh
*nh
, bool add
)
4424 struct bgp
*bgp_vrf
= nh
->bgp_vrf
;
4427 if (!zclient
|| zclient
->sock
< 0)
4430 /* Don't try to register if Zebra doesn't know of this instance. */
4431 if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp_vrf
)) {
4432 if (BGP_DEBUG(zebra
, ZEBRA
))
4433 zlog_debug("No zebra instance, not %s remote nh %s",
4434 add
? "adding" : "deleting", nh
->nh_str
);
4441 zclient_create_header(
4442 s
, add
? ZEBRA_EVPN_REMOTE_NH_ADD
: ZEBRA_EVPN_REMOTE_NH_DEL
,
4444 stream_putl(s
, bgp_vrf
->vrf_id
);
4445 stream_put(s
, &nh
->ip
, sizeof(nh
->ip
));
4447 stream_put(s
, &nh
->rmac
, sizeof(nh
->rmac
));
4449 stream_putw_at(s
, 0, stream_get_endp(s
));
4451 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
)) {
4453 zlog_debug("evpn vrf %s nh %s rmac %pEA add to zebra",
4454 nh
->bgp_vrf
->name
, nh
->nh_str
, &nh
->rmac
);
4455 else if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
4456 zlog_debug("evpn vrf %s nh %s del to zebra",
4457 nh
->bgp_vrf
->name
, nh
->nh_str
);
4460 frrtrace(2, frr_bgp
, evpn_mh_nh_rmac_zsend
, add
, nh
);
4462 zclient_send_message(zclient
);
4465 static void bgp_evpn_nh_zebra_update(struct bgp_evpn_nh
*nh
, bool add
)
4467 if (add
&& !is_zero_mac(&nh
->rmac
)) {
4468 nh
->flags
|= BGP_EVPN_NH_READY_FOR_ZEBRA
;
4469 bgp_evpn_nh_zebra_update_send(nh
, true);
4471 if (!(nh
->flags
& BGP_EVPN_NH_READY_FOR_ZEBRA
))
4473 nh
->flags
&= ~BGP_EVPN_NH_READY_FOR_ZEBRA
;
4474 bgp_evpn_nh_zebra_update_send(nh
, false);
4478 static void *bgp_evpn_nh_alloc(void *p
)
4480 struct bgp_evpn_nh
*tmp_n
= p
;
4481 struct bgp_evpn_nh
*n
;
4483 n
= XCALLOC(MTYPE_BGP_EVPN_NH
, sizeof(struct bgp_evpn_nh
));
4489 static struct bgp_evpn_nh
*bgp_evpn_nh_find(struct bgp
*bgp_vrf
,
4492 struct bgp_evpn_nh tmp
;
4493 struct bgp_evpn_nh
*n
;
4495 memset(&tmp
, 0, sizeof(tmp
));
4496 memcpy(&tmp
.ip
, ip
, sizeof(struct ipaddr
));
4497 n
= hash_lookup(bgp_vrf
->evpn_nh_table
, &tmp
);
4502 /* Add nexthop entry - implicitly created on first path reference */
4503 static struct bgp_evpn_nh
*bgp_evpn_nh_add(struct bgp
*bgp_vrf
,
4505 struct bgp_path_info
*pi
)
4507 struct bgp_evpn_nh tmp_n
;
4508 struct bgp_evpn_nh
*n
= NULL
;
4510 memset(&tmp_n
, 0, sizeof(tmp_n
));
4511 memcpy(&tmp_n
.ip
, ip
, sizeof(struct ipaddr
));
4512 n
= hash_get(bgp_vrf
->evpn_nh_table
, &tmp_n
, bgp_evpn_nh_alloc
);
4513 ipaddr2str(ip
, n
->nh_str
, sizeof(n
->nh_str
));
4514 n
->bgp_vrf
= bgp_vrf
;
4516 n
->pi_list
= list_new();
4517 listset_app_node_mem(n
->pi_list
);
4519 /* Setup ref_pi when the nh is created */
4520 if (CHECK_FLAG(pi
->flags
, BGP_PATH_VALID
) && pi
->attr
) {
4522 memcpy(&n
->rmac
, &pi
->attr
->rmac
, ETH_ALEN
);
4525 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
4526 zlog_debug("evpn vrf %s nh %s rmac %pEA add", n
->bgp_vrf
->name
,
4527 n
->nh_str
, &n
->rmac
);
4528 bgp_evpn_nh_zebra_update(n
, true);
4532 /* Delete nexthop entry if there are no paths referencing it */
4533 static void bgp_evpn_nh_del(struct bgp_evpn_nh
*n
)
4535 struct bgp_evpn_nh
*tmp_n
;
4536 struct bgp
*bgp_vrf
= n
->bgp_vrf
;
4538 if (listcount(n
->pi_list
))
4541 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
4542 zlog_debug("evpn vrf %s nh %s del to zebra", bgp_vrf
->name
,
4545 bgp_evpn_nh_zebra_update(n
, false);
4546 list_delete(&n
->pi_list
);
4547 tmp_n
= hash_release(bgp_vrf
->evpn_nh_table
, n
);
4548 XFREE(MTYPE_BGP_EVPN_NH
, tmp_n
);
4551 static unsigned int bgp_evpn_nh_hash_keymake(const void *p
)
4553 const struct bgp_evpn_nh
*n
= p
;
4554 const struct ipaddr
*ip
= &n
->ip
;
4556 if (IS_IPADDR_V4(ip
))
4557 return jhash_1word(ip
->ipaddr_v4
.s_addr
, 0);
4559 return jhash2(ip
->ipaddr_v6
.s6_addr32
,
4560 array_size(ip
->ipaddr_v6
.s6_addr32
), 0);
4563 static bool bgp_evpn_nh_cmp(const void *p1
, const void *p2
)
4565 const struct bgp_evpn_nh
*n1
= p1
;
4566 const struct bgp_evpn_nh
*n2
= p2
;
4568 if (n1
== NULL
&& n2
== NULL
)
4571 if (n1
== NULL
|| n2
== NULL
)
4574 return (ipaddr_cmp(&n1
->ip
, &n2
->ip
) == 0);
4577 void bgp_evpn_nh_init(struct bgp
*bgp_vrf
)
4579 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
4580 zlog_debug("evpn vrf %s nh init", bgp_vrf
->name
);
4581 bgp_vrf
->evpn_nh_table
= hash_create(
4582 bgp_evpn_nh_hash_keymake
, bgp_evpn_nh_cmp
, "BGP EVPN NH table");
4585 static void bgp_evpn_nh_flush_entry(struct bgp_evpn_nh
*nh
)
4587 struct listnode
*node
;
4588 struct listnode
*nnode
;
4589 struct bgp_path_evpn_nh_info
*nh_info
;
4591 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
4592 zlog_debug("evpn vrf %s nh %s flush", nh
->bgp_vrf
->name
,
4595 /* force flush paths */
4596 for (ALL_LIST_ELEMENTS(nh
->pi_list
, node
, nnode
, nh_info
))
4597 bgp_evpn_path_nh_del(nh
->bgp_vrf
, nh_info
->pi
);
4600 static void bgp_evpn_nh_flush_cb(struct hash_bucket
*bucket
, void *ctxt
)
4602 struct bgp_evpn_nh
*nh
= (struct bgp_evpn_nh
*)bucket
->data
;
4604 bgp_evpn_nh_flush_entry(nh
);
4607 void bgp_evpn_nh_finish(struct bgp
*bgp_vrf
)
4609 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
4610 zlog_debug("evpn vrf %s nh finish", bgp_vrf
->name
);
4612 bgp_vrf
->evpn_nh_table
,
4613 (void (*)(struct hash_bucket
*, void *))bgp_evpn_nh_flush_cb
,
4615 hash_free(bgp_vrf
->evpn_nh_table
);
4616 bgp_vrf
->evpn_nh_table
= NULL
;
4619 static void bgp_evpn_nh_update_ref_pi(struct bgp_evpn_nh
*nh
)
4621 struct listnode
*node
;
4622 struct bgp_path_info
*pi
;
4623 struct bgp_path_evpn_nh_info
*nh_info
;
4628 for (ALL_LIST_ELEMENTS_RO(nh
->pi_list
, node
, nh_info
)) {
4630 if (!CHECK_FLAG(pi
->flags
, BGP_PATH_VALID
) || !pi
->attr
)
4633 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
4634 zlog_debug("evpn vrf %s nh %s ref_pi update",
4635 nh
->bgp_vrf
->name
, nh
->nh_str
);
4637 /* If we have a new pi copy rmac from it and update
4638 * zebra if the new rmac is different
4640 if (memcmp(&nh
->rmac
, &nh
->ref_pi
->attr
->rmac
, ETH_ALEN
)) {
4641 memcpy(&nh
->rmac
, &nh
->ref_pi
->attr
->rmac
, ETH_ALEN
);
4642 bgp_evpn_nh_zebra_update(nh
, true);
4648 static void bgp_evpn_nh_clear_ref_pi(struct bgp_evpn_nh
*nh
,
4649 struct bgp_path_info
*pi
)
4651 if (nh
->ref_pi
!= pi
)
4654 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
4655 zlog_debug("evpn vrf %s nh %s ref_pi clear", nh
->bgp_vrf
->name
,
4658 /* try to find another ref_pi */
4659 bgp_evpn_nh_update_ref_pi(nh
);
4660 /* couldn't find one - clear the old rmac and notify zebra */
4662 memset(&nh
->rmac
, 0, ETH_ALEN
);
4663 bgp_evpn_nh_zebra_update(nh
, true);
4667 static void bgp_evpn_path_nh_info_free(struct bgp_path_evpn_nh_info
*nh_info
)
4669 bgp_evpn_path_nh_unlink(nh_info
);
4670 XFREE(MTYPE_BGP_EVPN_PATH_NH_INFO
, nh_info
);
4673 static struct bgp_path_evpn_nh_info
*
4674 bgp_evpn_path_nh_info_new(struct bgp_path_info
*pi
)
4676 struct bgp_path_info_extra
*e
;
4677 struct bgp_path_mh_info
*mh_info
;
4678 struct bgp_path_evpn_nh_info
*nh_info
;
4680 e
= bgp_path_info_extra_get(pi
);
4682 /* If mh_info doesn't exist allocate it */
4683 mh_info
= e
->mh_info
;
4685 e
->mh_info
= mh_info
= XCALLOC(MTYPE_BGP_EVPN_PATH_MH_INFO
,
4686 sizeof(struct bgp_path_mh_info
));
4688 /* If nh_info doesn't exist allocate it */
4689 nh_info
= mh_info
->nh_info
;
4691 mh_info
->nh_info
= nh_info
=
4692 XCALLOC(MTYPE_BGP_EVPN_PATH_NH_INFO
,
4693 sizeof(struct bgp_path_evpn_nh_info
));
4700 static void bgp_evpn_path_nh_unlink(struct bgp_path_evpn_nh_info
*nh_info
)
4702 struct bgp_evpn_nh
*nh
= nh_info
->nh
;
4703 struct bgp_path_info
*pi
;
4704 char prefix_buf
[PREFIX_STRLEN
];
4710 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
4711 zlog_debug("path %s unlinked from nh %s %s",
4712 pi
->net
? prefix2str(&pi
->net
->p
, prefix_buf
,
4715 nh
->bgp_vrf
->name
, nh
->nh_str
);
4717 list_delete_node(nh
->pi_list
, &nh_info
->nh_listnode
);
4721 /* check if the ref_pi need to be updated */
4722 bgp_evpn_nh_clear_ref_pi(nh
, pi
);
4724 /* if there are no other references against the nh it
4727 bgp_evpn_nh_del(nh
);
4729 /* Note we don't free the path nh_info on unlink; it will be freed up
4730 * along with the path.
4734 static void bgp_evpn_path_nh_link(struct bgp
*bgp_vrf
, struct bgp_path_info
*pi
)
4736 struct bgp_path_evpn_nh_info
*nh_info
;
4737 struct bgp_evpn_nh
*nh
;
4740 /* EVPN nexthop setup in bgp has been turned off */
4741 if (!bgp_mh_info
->bgp_evpn_nh_setup
)
4744 if (!bgp_vrf
->evpn_nh_table
) {
4745 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
4746 zlog_debug("path %pFX linked to vrf %s failed",
4747 &pi
->net
->p
, bgp_vrf
->name
);
4751 nh_info
= (pi
->extra
&& pi
->extra
->mh_info
)
4752 ? pi
->extra
->mh_info
->nh_info
4755 /* if NHG is not being used for this path we don't need to manage the
4756 * nexthops in bgp (they are managed by zebra instead)
4758 if (!(pi
->attr
->es_flags
& ATTR_ES_L3_NHG_USE
)) {
4760 bgp_evpn_path_nh_unlink(nh_info
);
4764 /* setup nh_info against the path if it doesn't aleady exist */
4766 nh_info
= bgp_evpn_path_nh_info_new(pi
);
4768 /* find-create nh */
4769 memset(&ip
, 0, sizeof(ip
));
4770 if (pi
->net
->p
.family
== AF_INET6
) {
4772 memcpy(&ip
.ipaddr_v6
, &pi
->attr
->mp_nexthop_global
,
4773 sizeof(ip
.ipaddr_v6
));
4776 memcpy(&ip
.ipaddr_v4
, &pi
->attr
->nexthop
, sizeof(ip
.ipaddr_v4
));
4779 nh
= bgp_evpn_nh_find(bgp_vrf
, &ip
);
4781 nh
= bgp_evpn_nh_add(bgp_vrf
, &ip
, pi
);
4784 if (nh_info
->nh
== nh
) {
4785 /* Check if any of the paths are now valid */
4786 bgp_evpn_nh_update_ref_pi(nh
);
4790 /* unlink old nh if any */
4791 bgp_evpn_path_nh_unlink(nh_info
);
4793 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
4794 zlog_debug("path %pFX linked to nh %s %s", &pi
->net
->p
,
4795 nh
->bgp_vrf
->name
, nh
->nh_str
);
4797 /* link mac-ip path to the new nh */
4799 listnode_init(&nh_info
->nh_listnode
, nh_info
);
4800 listnode_add(nh
->pi_list
, &nh_info
->nh_listnode
);
4801 /* If a new valid path got linked to the nh see if can get the rmac
4804 bgp_evpn_nh_update_ref_pi(nh
);
4805 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
)) {
4808 "path %pFX linked to nh %s %s with no valid pi",
4809 &pi
->net
->p
, nh
->bgp_vrf
->name
, nh
->nh_str
);
4813 void bgp_evpn_path_nh_del(struct bgp
*bgp_vrf
, struct bgp_path_info
*pi
)
4815 struct bgp_path_evpn_nh_info
*nh_info
;
4817 nh_info
= (pi
->extra
&& pi
->extra
->mh_info
)
4818 ? pi
->extra
->mh_info
->nh_info
4824 bgp_evpn_path_nh_unlink(nh_info
);
4827 void bgp_evpn_path_nh_add(struct bgp
*bgp_vrf
, struct bgp_path_info
*pi
)
4829 bgp_evpn_path_nh_link(bgp_vrf
, pi
);
4832 static void bgp_evpn_nh_show_entry(struct bgp_evpn_nh
*nh
, struct vty
*vty
,
4833 json_object
*json_array
)
4835 json_object
*json
= NULL
;
4836 char mac_buf
[ETHER_ADDR_STRLEN
];
4837 char prefix_buf
[PREFIX_STRLEN
];
4840 /* create a separate json object for each ES */
4841 json
= json_object_new_object();
4843 prefix_mac2str(&nh
->rmac
, mac_buf
, sizeof(mac_buf
));
4844 if (nh
->ref_pi
&& nh
->ref_pi
->net
)
4845 prefix2str(&nh
->ref_pi
->net
->p
, prefix_buf
, sizeof(prefix_buf
));
4847 prefix_buf
[0] = '\0';
4849 json_object_string_add(json
, "vrf", nh
->bgp_vrf
->name
);
4850 json_object_string_add(json
, "ip", nh
->nh_str
);
4851 json_object_string_add(json
, "rmac", mac_buf
);
4852 json_object_string_add(json
, "basePath", prefix_buf
);
4853 json_object_int_add(json
, "pathCount", listcount(nh
->pi_list
));
4855 vty_out(vty
, "%-15s %-15s %-17s %-10d %s\n", nh
->bgp_vrf
->name
,
4856 nh
->nh_str
, mac_buf
, listcount(nh
->pi_list
),
4860 /* add ES to the json array */
4862 json_object_array_add(json_array
, json
);
4865 struct nh_show_ctx
{
4870 static void bgp_evpn_nh_show_hash_cb(struct hash_bucket
*bucket
, void *ctxt
)
4872 struct bgp_evpn_nh
*nh
= (struct bgp_evpn_nh
*)bucket
->data
;
4873 struct nh_show_ctx
*wctx
= (struct nh_show_ctx
*)ctxt
;
4875 bgp_evpn_nh_show_entry(nh
, wctx
->vty
, wctx
->json
);
4878 /* Display all evpn nexthops */
4879 void bgp_evpn_nh_show(struct vty
*vty
, bool uj
)
4881 json_object
*json_array
= NULL
;
4882 struct bgp
*bgp_vrf
;
4883 struct listnode
*node
;
4884 struct nh_show_ctx wctx
;
4887 /* create an array of nexthops */
4888 json_array
= json_object_new_array();
4890 vty_out(vty
, "%-15s %-15s %-17s %-10s %s\n", "VRF", "IP",
4891 "RMAC", "#Paths", "Base Path");
4895 wctx
.json
= json_array
;
4897 /* walk through all vrfs */
4898 for (ALL_LIST_ELEMENTS_RO(bm
->bgp
, node
, bgp_vrf
)) {
4899 hash_iterate(bgp_vrf
->evpn_nh_table
,
4900 (void (*)(struct hash_bucket
*,
4901 void *))bgp_evpn_nh_show_hash_cb
,
4905 /* print the array of json-ESs */
4907 vty_json(vty
, json_array
);
4910 /*****************************************************************************/
4911 void bgp_evpn_mh_init(void)
4913 bm
->mh_info
= XCALLOC(MTYPE_BGP_EVPN_MH_INFO
, sizeof(*bm
->mh_info
));
4915 /* setup ES tables */
4916 RB_INIT(bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
);
4918 bgp_mh_info
->local_es_list
= list_new();
4919 listset_app_node_mem(bgp_mh_info
->local_es_list
);
4920 /* list of ESs with pending processing */
4921 bgp_mh_info
->pend_es_list
= list_new();
4922 listset_app_node_mem(bgp_mh_info
->pend_es_list
);
4924 bgp_mh_info
->ead_evi_rx
= BGP_EVPN_MH_EAD_EVI_RX_DEF
;
4925 bgp_mh_info
->ead_evi_tx
= BGP_EVPN_MH_EAD_EVI_TX_DEF
;
4926 bgp_mh_info
->ead_es_export_rtl
= list_new();
4927 bgp_mh_info
->ead_es_export_rtl
->cmp
=
4928 (int (*)(void *, void *))bgp_evpn_route_target_cmp
;
4929 bgp_mh_info
->ead_es_export_rtl
->del
= bgp_evpn_xxport_delete_ecomm
;
4931 /* config knobs - XXX add cli to control it */
4932 bgp_mh_info
->ead_evi_adv_for_down_links
= true;
4933 bgp_mh_info
->consistency_checking
= true;
4934 bgp_mh_info
->host_routes_use_l3nhg
= BGP_EVPN_MH_USE_ES_L3NHG_DEF
;
4935 bgp_mh_info
->suppress_l3_ecomm_on_inactive_es
= true;
4936 bgp_mh_info
->bgp_evpn_nh_setup
= true;
4937 bgp_mh_info
->evi_per_es_frag
= BGP_EVPN_MAX_EVI_PER_ES_FRAG
;
4939 memset(&zero_esi_buf
, 0, sizeof(esi_t
));
4942 void bgp_evpn_mh_finish(void)
4944 struct bgp_evpn_es
*es
;
4945 struct bgp_evpn_es
*es_next
;
4947 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
4948 zlog_debug("evpn mh finish");
4950 RB_FOREACH_SAFE (es
, bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
,
4952 bgp_evpn_es_local_info_clear(es
, true);
4954 if (bgp_mh_info
->t_cons_check
)
4955 thread_cancel(&bgp_mh_info
->t_cons_check
);
4956 list_delete(&bgp_mh_info
->local_es_list
);
4957 list_delete(&bgp_mh_info
->pend_es_list
);
4958 list_delete(&bgp_mh_info
->ead_es_export_rtl
);
4960 XFREE(MTYPE_BGP_EVPN_MH_INFO
, bgp_mh_info
);
4963 /* This function is called when disable-ead-evi-rx knob flaps */
4964 void bgp_evpn_switch_ead_evi_rx(void)
4967 struct bgp_evpn_es
*es
;
4968 struct bgp_evpn_es_evi
*es_evi
;
4969 struct listnode
*evi_node
= NULL
;
4970 struct listnode
*evi_next
= NULL
;
4971 struct bgp_evpn_es_evi_vtep
*vtep
;
4972 struct listnode
*vtep_node
= NULL
;
4973 struct listnode
*vtep_next
= NULL
;
4975 bgp
= bgp_get_evpn();
4980 * Process all the remote es_evi_vteps and reevaluate if the es_evi_vtep
4983 RB_FOREACH(es
, bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
) {
4984 if (!CHECK_FLAG(es
->flags
, BGP_EVPNES_REMOTE
))
4987 for (ALL_LIST_ELEMENTS(es
->es_evi_list
, evi_node
, evi_next
,
4989 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_REMOTE
))
4992 for (ALL_LIST_ELEMENTS(es_evi
->es_evi_vtep_list
,
4993 vtep_node
, vtep_next
, vtep
))
4994 bgp_evpn_es_evi_vtep_re_eval_active(bgp
, vtep
);