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"
54 static void bgp_evpn_local_es_down(struct bgp
*bgp
,
55 struct bgp_evpn_es
*es
);
56 static void bgp_evpn_local_type1_evi_route_del(struct bgp
*bgp
,
57 struct bgp_evpn_es
*es
);
58 static struct bgp_evpn_es_vtep
*bgp_evpn_es_vtep_add(struct bgp
*bgp
,
59 struct bgp_evpn_es
*es
,
60 struct in_addr vtep_ip
,
61 bool esr
, uint8_t df_alg
,
63 static void bgp_evpn_es_vtep_del(struct bgp
*bgp
,
64 struct bgp_evpn_es
*es
, struct in_addr vtep_ip
, bool esr
);
65 static void bgp_evpn_es_cons_checks_pend_add(struct bgp_evpn_es
*es
);
66 static void bgp_evpn_es_cons_checks_pend_del(struct bgp_evpn_es
*es
);
67 static void bgp_evpn_local_es_evi_do_del(struct bgp_evpn_es_evi
*es_evi
);
68 static uint32_t bgp_evpn_es_get_active_vtep_cnt(struct bgp_evpn_es
*es
);
69 static void bgp_evpn_l3nhg_update_on_vtep_chg(struct bgp_evpn_es
*es
);
70 static struct bgp_evpn_es
*bgp_evpn_es_new(struct bgp
*bgp
, const esi_t
*esi
);
71 static void bgp_evpn_es_free(struct bgp_evpn_es
*es
, const char *caller
);
73 esi_t zero_esi_buf
, *zero_esi
= &zero_esi_buf
;
74 static int bgp_evpn_run_consistency_checks(struct thread
*t
);
76 /******************************************************************************
77 * per-ES (Ethernet Segment) routing table
79 * Following routes are added to the ES's routing table -
80 * 1. Local and remote ESR (Type-4)
81 * 2. Local EAD-per-ES (Type-1).
83 * Key for these routes is {ESI, VTEP-IP} so the path selection is practically
84 * a no-op i.e. all paths lead to same VTEP-IP (i.e. result in the same VTEP
85 * being added to same ES).
87 * Note the following routes go into the VNI routing table (instead of the
89 * 1. Remote EAD-per-ES
90 * 2. Local and remote EAD-per-EVI
93 /* Calculate the best path for a multi-homing (Type-1 or Type-4) route
94 * installed in the ES's routing table.
96 static int bgp_evpn_es_route_select_install(struct bgp
*bgp
,
97 struct bgp_evpn_es
*es
,
98 struct bgp_dest
*dest
)
101 afi_t afi
= AFI_L2VPN
;
102 safi_t safi
= SAFI_EVPN
;
103 struct bgp_path_info
*old_select
; /* old best */
104 struct bgp_path_info
*new_select
; /* new best */
105 struct bgp_path_info_pair old_and_new
;
107 /* Compute the best path. */
108 bgp_best_selection(bgp
, dest
, &bgp
->maxpaths
[afi
][safi
], &old_and_new
,
110 old_select
= old_and_new
.old
;
111 new_select
= old_and_new
.new;
114 * If the best path hasn't changed - see if something needs to be
117 if (old_select
&& old_select
== new_select
118 && old_select
->type
== ZEBRA_ROUTE_BGP
119 && old_select
->sub_type
== BGP_ROUTE_IMPORTED
120 && !CHECK_FLAG(dest
->flags
, BGP_NODE_USER_CLEAR
)
121 && !CHECK_FLAG(old_select
->flags
, BGP_PATH_ATTR_CHANGED
)
122 && !bgp_addpath_is_addpath_used(&bgp
->tx_addpath
, afi
, safi
)) {
123 if (bgp_zebra_has_route_changed(old_select
)) {
124 bgp_evpn_es_vtep_add(bgp
, es
, old_select
->attr
->nexthop
,
126 old_select
->attr
->df_alg
,
127 old_select
->attr
->df_pref
);
129 UNSET_FLAG(old_select
->flags
, BGP_PATH_MULTIPATH_CHG
);
130 bgp_zebra_clear_route_change_flags(dest
);
134 /* If the user did a "clear" this flag will be set */
135 UNSET_FLAG(dest
->flags
, BGP_NODE_USER_CLEAR
);
137 /* bestpath has changed; update relevant fields and install or uninstall
138 * into the zebra RIB.
140 if (old_select
|| new_select
)
141 bgp_bump_version(dest
);
144 bgp_path_info_unset_flag(dest
, old_select
, BGP_PATH_SELECTED
);
146 bgp_path_info_set_flag(dest
, new_select
, BGP_PATH_SELECTED
);
147 bgp_path_info_unset_flag(dest
, new_select
,
148 BGP_PATH_ATTR_CHANGED
);
149 UNSET_FLAG(new_select
->flags
, BGP_PATH_MULTIPATH_CHG
);
152 if (new_select
&& new_select
->type
== ZEBRA_ROUTE_BGP
153 && new_select
->sub_type
== BGP_ROUTE_IMPORTED
) {
154 bgp_evpn_es_vtep_add(bgp
, es
, new_select
->attr
->nexthop
,
155 true /*esr */, new_select
->attr
->df_alg
,
156 new_select
->attr
->df_pref
);
158 if (old_select
&& old_select
->type
== ZEBRA_ROUTE_BGP
159 && old_select
->sub_type
== BGP_ROUTE_IMPORTED
)
160 bgp_evpn_es_vtep_del(
161 bgp
, es
, old_select
->attr
->nexthop
,
165 /* Clear any route change flags. */
166 bgp_zebra_clear_route_change_flags(dest
);
168 /* Reap old select bgp_path_info, if it has been removed */
169 if (old_select
&& CHECK_FLAG(old_select
->flags
, BGP_PATH_REMOVED
))
170 bgp_path_info_reap(dest
, old_select
);
175 /* Install Type-1/Type-4 route entry in the per-ES routing table */
176 static int bgp_evpn_es_route_install(struct bgp
*bgp
,
177 struct bgp_evpn_es
*es
, struct prefix_evpn
*p
,
178 struct bgp_path_info
*parent_pi
)
181 struct bgp_dest
*dest
= NULL
;
182 struct bgp_path_info
*pi
= NULL
;
183 struct attr
*attr_new
= NULL
;
185 /* Create (or fetch) route within the VNI.
186 * NOTE: There is no RD here.
188 dest
= bgp_node_get(es
->route_table
, (struct prefix
*)p
);
190 /* Check if route entry is already present. */
191 for (pi
= bgp_dest_get_bgp_path_info(dest
); pi
; pi
= pi
->next
)
193 && (struct bgp_path_info
*)pi
->extra
->parent
==
198 /* Add (or update) attribute to hash. */
199 attr_new
= bgp_attr_intern(parent_pi
->attr
);
201 /* Create new route with its attribute. */
202 pi
= info_make(parent_pi
->type
, BGP_ROUTE_IMPORTED
, 0,
203 parent_pi
->peer
, attr_new
, dest
);
204 SET_FLAG(pi
->flags
, BGP_PATH_VALID
);
205 bgp_path_info_extra_get(pi
);
206 pi
->extra
->parent
= bgp_path_info_lock(parent_pi
);
207 bgp_dest_lock_node((struct bgp_dest
*)parent_pi
->net
);
208 bgp_path_info_add(dest
, pi
);
210 if (attrhash_cmp(pi
->attr
, parent_pi
->attr
)
211 && !CHECK_FLAG(pi
->flags
, BGP_PATH_REMOVED
)) {
212 bgp_dest_unlock_node(dest
);
215 /* The attribute has changed. */
216 /* Add (or update) attribute to hash. */
217 attr_new
= bgp_attr_intern(parent_pi
->attr
);
219 /* Restore route, if needed. */
220 if (CHECK_FLAG(pi
->flags
, BGP_PATH_REMOVED
))
221 bgp_path_info_restore(dest
, pi
);
223 /* Mark if nexthop has changed. */
224 if (!IPV4_ADDR_SAME(&pi
->attr
->nexthop
, &attr_new
->nexthop
))
225 SET_FLAG(pi
->flags
, BGP_PATH_IGP_CHANGED
);
227 /* Unintern existing, set to new. */
228 bgp_attr_unintern(&pi
->attr
);
230 pi
->uptime
= bgp_clock();
233 /* Perform route selection and update zebra, if required. */
234 ret
= bgp_evpn_es_route_select_install(bgp
, es
, dest
);
236 bgp_dest_unlock_node(dest
);
241 /* Uninstall Type-1/Type-4 route entry from the ES routing table */
242 static int bgp_evpn_es_route_uninstall(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
243 struct prefix_evpn
*p
, struct bgp_path_info
*parent_pi
)
246 struct bgp_dest
*dest
;
247 struct bgp_path_info
*pi
;
249 if (!es
->route_table
)
252 /* Locate route within the ESI.
253 * NOTE: There is no RD here.
255 dest
= bgp_node_lookup(es
->route_table
, (struct prefix
*)p
);
259 /* Find matching route entry. */
260 for (pi
= bgp_dest_get_bgp_path_info(dest
); pi
; pi
= pi
->next
)
262 && (struct bgp_path_info
*)pi
->extra
->parent
==
269 /* Mark entry for deletion */
270 bgp_path_info_delete(dest
, pi
);
272 /* Perform route selection and update zebra, if required. */
273 ret
= bgp_evpn_es_route_select_install(bgp
, es
, dest
);
275 /* Unlock route node. */
276 bgp_dest_unlock_node(dest
);
281 /* Install or unistall a Tyoe-4 route in the per-ES routing table */
282 int bgp_evpn_es_route_install_uninstall(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
283 afi_t afi
, safi_t safi
, struct prefix_evpn
*evp
,
284 struct bgp_path_info
*pi
, int install
)
289 ret
= bgp_evpn_es_route_install(bgp
, es
, evp
, pi
);
291 ret
= bgp_evpn_es_route_uninstall(bgp
, es
, evp
, pi
);
296 "%u: Failed to %s EVPN %s route in ESI %s",
298 install
? "install" : "uninstall",
305 /* Delete (and withdraw) local routes for specified ES from global and ES table.
306 * Also remove all remote routes from the per ES table. Invoked when ES
309 static void bgp_evpn_es_route_del_all(struct bgp
*bgp
, struct bgp_evpn_es
*es
)
311 struct bgp_dest
*dest
;
312 struct bgp_path_info
*pi
, *nextpi
;
314 /* de-activate the ES */
315 bgp_evpn_local_es_down(bgp
, es
);
316 bgp_evpn_local_type1_evi_route_del(bgp
, es
);
318 /* Walk this ES's routing table and delete all routes. */
319 for (dest
= bgp_table_top(es
->route_table
); dest
;
320 dest
= bgp_route_next(dest
)) {
321 for (pi
= bgp_dest_get_bgp_path_info(dest
);
322 (pi
!= NULL
) && (nextpi
= pi
->next
, 1); pi
= nextpi
) {
323 bgp_path_info_delete(dest
, pi
);
324 bgp_path_info_reap(dest
, pi
);
329 /*****************************************************************************
330 * Base APIs for creating MH routes (Type-1 or Type-4) on local ethernet
334 /* create or update local EVPN type1/type4 route entry.
337 * the ES table if ESR/EAD-ES (or)
338 * the VNI table if EAD-EVI (or)
339 * the global table if ESR/EAD-ES/EAD-EVI
341 * Note: vpn is applicable only to EAD-EVI routes (NULL for EAD-ES and
344 static int bgp_evpn_mh_route_update(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
345 struct bgpevpn
*vpn
, afi_t afi
, safi_t safi
,
346 struct bgp_dest
*dest
, struct attr
*attr
,
347 int add
, struct bgp_path_info
**ri
,
350 struct bgp_path_info
*tmp_pi
= NULL
;
351 struct bgp_path_info
*local_pi
= NULL
; /* local route entry if any */
352 struct bgp_path_info
*remote_pi
= NULL
; /* remote route entry if any */
353 struct attr
*attr_new
= NULL
;
354 struct prefix_evpn
*evp
;
357 evp
= (struct prefix_evpn
*)bgp_dest_get_prefix(dest
);
360 /* locate the local and remote entries if any */
361 for (tmp_pi
= bgp_dest_get_bgp_path_info(dest
); tmp_pi
;
362 tmp_pi
= tmp_pi
->next
) {
363 if (tmp_pi
->peer
== bgp
->peer_self
364 && tmp_pi
->type
== ZEBRA_ROUTE_BGP
365 && tmp_pi
->sub_type
== BGP_ROUTE_STATIC
)
367 if (tmp_pi
->type
== ZEBRA_ROUTE_BGP
368 && tmp_pi
->sub_type
== BGP_ROUTE_IMPORTED
369 && CHECK_FLAG(tmp_pi
->flags
, BGP_PATH_VALID
))
373 /* we don't expect to see a remote_ri at this point as
374 * an ES route has {esi, vtep_ip} as the key in the ES-rt-table
375 * in the VNI-rt-table.
380 "%u ERROR: local es route for ESI: %s Vtep %pI4 also learnt from remote",
381 bgp
->vrf_id
, es
->esi_str
, &es
->originator_ip
);
385 if (!local_pi
&& !add
)
388 /* create or update the entry */
391 /* Add or update attribute to hash */
392 attr_new
= bgp_attr_intern(attr
);
394 /* Create new route with its attribute. */
395 tmp_pi
= info_make(ZEBRA_ROUTE_BGP
, BGP_ROUTE_STATIC
, 0,
396 bgp
->peer_self
, attr_new
, dest
);
397 SET_FLAG(tmp_pi
->flags
, BGP_PATH_VALID
);
399 if (evp
->prefix
.route_type
== BGP_EVPN_AD_ROUTE
) {
400 bgp_path_info_extra_get(tmp_pi
);
401 tmp_pi
->extra
->num_labels
= 1;
403 vni2label(vpn
->vni
, &tmp_pi
->extra
->label
[0]);
405 tmp_pi
->extra
->label
[0] = 0;
408 /* add the newly created path to the route-node */
409 bgp_path_info_add(dest
, tmp_pi
);
412 if (attrhash_cmp(tmp_pi
->attr
, attr
)
413 && !CHECK_FLAG(tmp_pi
->flags
, BGP_PATH_REMOVED
))
416 /* The attribute has changed.
417 * Add (or update) attribute to hash.
419 attr_new
= bgp_attr_intern(attr
);
420 bgp_path_info_set_flag(dest
, tmp_pi
,
421 BGP_PATH_ATTR_CHANGED
);
423 /* Restore route, if needed. */
424 if (CHECK_FLAG(tmp_pi
->flags
, BGP_PATH_REMOVED
))
425 bgp_path_info_restore(dest
, tmp_pi
);
427 /* Unintern existing, set to new. */
428 bgp_attr_unintern(&tmp_pi
->attr
);
429 tmp_pi
->attr
= attr_new
;
430 tmp_pi
->uptime
= bgp_clock();
434 if (*route_changed
) {
435 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
437 "local ES %s vni %u route-type %s nexthop %pI4 updated",
438 es
->esi_str
, vpn
? vpn
->vni
: 0,
439 evp
->prefix
.route_type
== BGP_EVPN_ES_ROUTE
441 : (vpn
? "ead-evi" : "ead-es"),
442 &attr
->mp_nexthop_global_in
);
445 /* Return back the route entry. */
450 /* Delete local EVPN ESR (type-4) and EAD (type-1) route
452 * Note: vpn is applicable only to EAD-EVI routes (NULL for EAD-ES and
455 static int bgp_evpn_mh_route_delete(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
456 struct bgpevpn
*vpn
, struct prefix_evpn
*p
)
458 afi_t afi
= AFI_L2VPN
;
459 safi_t safi
= SAFI_EVPN
;
460 struct bgp_path_info
*pi
;
461 struct bgp_dest
*dest
= NULL
; /* dest in esi table */
462 struct bgp_dest
*global_dest
= NULL
; /* dest in global table */
463 struct bgp_table
*rt_table
;
464 struct prefix_rd
*prd
;
467 rt_table
= vpn
->route_table
;
470 rt_table
= es
->route_table
;
474 /* First, locate the route node within the ESI or VNI.
475 * If it doesn't exist, ther is nothing to do.
476 * Note: there is no RD here.
478 dest
= bgp_node_lookup(rt_table
, (struct prefix
*)p
);
482 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
484 "local ES %s vni %u route-type %s nexthop %pI4 delete",
485 es
->esi_str
, vpn
? vpn
->vni
: 0,
486 p
->prefix
.route_type
== BGP_EVPN_ES_ROUTE
488 : (vpn
? "ead-evi" : "ead-es"),
491 /* Next, locate route node in the global EVPN routing table.
492 * Note that this table is a 2-level tree (RD-level + Prefix-level)
495 bgp_global_evpn_node_lookup(bgp
->rib
[afi
][safi
], afi
, safi
,
496 (const struct prefix_evpn
*)p
, prd
);
499 /* Delete route entry in the global EVPN table. */
500 delete_evpn_route_entry(bgp
, afi
, safi
, global_dest
, &pi
);
502 /* Schedule for processing - withdraws to peers happen from
506 bgp_process(bgp
, global_dest
, afi
, safi
);
507 bgp_dest_unlock_node(global_dest
);
511 * Delete route entry in the ESI or VNI routing table.
512 * This can just be removed.
514 delete_evpn_route_entry(bgp
, afi
, safi
, dest
, &pi
);
516 bgp_path_info_reap(dest
, pi
);
517 bgp_dest_unlock_node(dest
);
521 /*****************************************************************************
522 * Ethernet Segment (Type-4) Routes
523 * ESRs are used for DF election. Currently service-carving described in
524 * RFC 7432 is NOT supported. Instead preference based DF election is
526 * Reference: draft-ietf-bess-evpn-pref-df
528 /* Build extended community for EVPN ES (type-4) route */
529 static void bgp_evpn_type4_route_extcomm_build(struct bgp_evpn_es
*es
,
532 struct ecommunity ecom_encap
;
533 struct ecommunity ecom_es_rt
;
534 struct ecommunity ecom_df
;
535 struct ecommunity_val eval
;
536 struct ecommunity_val eval_es_rt
;
537 struct ecommunity_val eval_df
;
538 bgp_encap_types tnl_type
;
542 tnl_type
= BGP_ENCAP_TYPE_VXLAN
;
543 memset(&ecom_encap
, 0, sizeof(ecom_encap
));
544 encode_encap_extcomm(tnl_type
, &eval
);
546 ecom_encap
.unit_size
= ECOMMUNITY_SIZE
;
547 ecom_encap
.val
= (uint8_t *)eval
.val
;
548 attr
->ecommunity
= ecommunity_dup(&ecom_encap
);
551 memset(&mac
, 0, sizeof(struct ethaddr
));
552 memset(&ecom_es_rt
, 0, sizeof(ecom_es_rt
));
553 es_get_system_mac(&es
->esi
, &mac
);
554 encode_es_rt_extcomm(&eval_es_rt
, &mac
);
556 ecom_es_rt
.unit_size
= ECOMMUNITY_SIZE
;
557 ecom_es_rt
.val
= (uint8_t *)eval_es_rt
.val
;
559 ecommunity_merge(attr
->ecommunity
, &ecom_es_rt
);
561 /* DF election extended community */
562 memset(&ecom_df
, 0, sizeof(ecom_df
));
563 encode_df_elect_extcomm(&eval_df
, es
->df_pref
);
565 ecom_df
.val
= (uint8_t *)eval_df
.val
;
566 attr
->ecommunity
= ecommunity_merge(attr
->ecommunity
, &ecom_df
);
568 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES
);
571 /* Create or update local type-4 route */
572 static int bgp_evpn_type4_route_update(struct bgp
*bgp
,
573 struct bgp_evpn_es
*es
, struct prefix_evpn
*p
)
576 int route_changed
= 0;
577 afi_t afi
= AFI_L2VPN
;
578 safi_t safi
= SAFI_EVPN
;
580 struct attr
*attr_new
= NULL
;
581 struct bgp_dest
*dest
= NULL
;
582 struct bgp_path_info
*pi
= NULL
;
584 memset(&attr
, 0, sizeof(struct attr
));
586 /* Build path-attribute for this route. */
587 bgp_attr_default_set(&attr
, BGP_ORIGIN_IGP
);
588 attr
.nexthop
= es
->originator_ip
;
589 attr
.mp_nexthop_global_in
= es
->originator_ip
;
590 attr
.mp_nexthop_len
= BGP_ATTR_NHLEN_IPV4
;
592 /* Set up extended community. */
593 bgp_evpn_type4_route_extcomm_build(es
, &attr
);
595 /* First, create (or fetch) route node within the ESI. */
596 /* NOTE: There is no RD here. */
597 dest
= bgp_node_get(es
->route_table
, (struct prefix
*)p
);
599 /* Create or update route entry. */
600 ret
= bgp_evpn_mh_route_update(bgp
, es
, NULL
, afi
, safi
, dest
, &attr
, 1,
601 &pi
, &route_changed
);
605 "%u ERROR: Failed to updated ES route ESI: %s VTEP %pI4",
606 bgp
->vrf_id
, es
->esi_str
, &es
->originator_ip
);
611 /* Perform route selection;
612 * this is just to set the flags correctly
613 * as local route in the ES always wins.
615 bgp_evpn_es_route_select_install(bgp
, es
, dest
);
616 bgp_dest_unlock_node(dest
);
618 /* If this is a new route or some attribute has changed, export the
619 * route to the global table. The route will be advertised to peers
620 * from there. Note that this table is a 2-level tree (RD-level +
621 * Prefix-level) similar to L3VPN routes.
624 struct bgp_path_info
*global_pi
;
626 dest
= bgp_global_evpn_node_get(bgp
->rib
[afi
][safi
], afi
, safi
,
628 bgp_evpn_mh_route_update(bgp
, es
, NULL
, afi
, safi
, dest
,
629 attr_new
, 1, &global_pi
,
632 /* Schedule for processing and unlock node. */
633 bgp_process(bgp
, dest
, afi
, safi
);
634 bgp_dest_unlock_node(dest
);
637 /* Unintern temporary. */
638 aspath_unintern(&attr
.aspath
);
642 /* Delete local type-4 route */
643 static int bgp_evpn_type4_route_delete(struct bgp
*bgp
,
644 struct bgp_evpn_es
*es
, struct prefix_evpn
*p
)
646 return bgp_evpn_mh_route_delete(bgp
, es
, NULL
/* l2vni */, p
);
649 /* Process remote/received EVPN type-4 route (advertise or withdraw) */
650 int bgp_evpn_type4_route_process(struct peer
*peer
, afi_t afi
, safi_t safi
,
651 struct attr
*attr
, uint8_t *pfx
, int psize
,
657 struct in_addr vtep_ip
;
658 struct prefix_rd prd
;
659 struct prefix_evpn p
;
661 /* Type-4 route should be either 23 or 35 bytes
662 * RD (8), ESI (10), ip-len (1), ip (4 or 16)
664 if (psize
!= BGP_EVPN_TYPE4_V4_PSIZE
&&
665 psize
!= BGP_EVPN_TYPE4_V6_PSIZE
) {
666 flog_err(EC_BGP_EVPN_ROUTE_INVALID
,
667 "%u:%s - Rx EVPN Type-4 NLRI with invalid length %d",
668 peer
->bgp
->vrf_id
, peer
->host
, psize
);
673 prd
.family
= AF_UNSPEC
;
675 memcpy(&prd
.val
, pfx
, RD_BYTES
);
679 memcpy(&esi
, pfx
, ESI_BYTES
);
685 if (ipaddr_len
== IPV4_MAX_BITLEN
) {
686 memcpy(&vtep_ip
, pfx
, IPV4_MAX_BYTELEN
);
689 EC_BGP_EVPN_ROUTE_INVALID
,
690 "%u:%s - Rx EVPN Type-4 NLRI with unsupported IP address length %d",
691 peer
->bgp
->vrf_id
, peer
->host
, ipaddr_len
);
695 build_evpn_type4_prefix(&p
, &esi
, vtep_ip
);
696 /* Process the route. */
698 ret
= bgp_update(peer
, (struct prefix
*)&p
, addpath_id
, attr
,
699 afi
, safi
, ZEBRA_ROUTE_BGP
, BGP_ROUTE_NORMAL
,
700 &prd
, NULL
, 0, 0, NULL
);
702 ret
= bgp_withdraw(peer
, (struct prefix
*)&p
, addpath_id
, attr
,
703 afi
, safi
, ZEBRA_ROUTE_BGP
, BGP_ROUTE_NORMAL
,
704 &prd
, NULL
, 0, NULL
);
709 /* Check if a prefix belongs to the local ES */
710 static bool bgp_evpn_type4_prefix_match(struct prefix_evpn
*p
,
711 struct bgp_evpn_es
*es
)
713 return (p
->prefix
.route_type
== BGP_EVPN_ES_ROUTE
) &&
714 !memcmp(&p
->prefix
.es_addr
.esi
, &es
->esi
, sizeof(esi_t
));
717 /* Import remote ESRs on local ethernet segment add */
718 static int bgp_evpn_type4_remote_routes_import(struct bgp
*bgp
,
719 struct bgp_evpn_es
*es
, bool install
)
724 struct bgp_dest
*rd_dest
, *dest
;
725 struct bgp_table
*table
;
726 struct bgp_path_info
*pi
;
731 /* Walk entire global routing table and evaluate routes which could be
732 * imported into this Ethernet Segment.
734 for (rd_dest
= bgp_table_top(bgp
->rib
[afi
][safi
]); rd_dest
;
735 rd_dest
= bgp_route_next(rd_dest
)) {
736 table
= bgp_dest_get_bgp_table_info(rd_dest
);
740 for (dest
= bgp_table_top(table
); dest
;
741 dest
= bgp_route_next(dest
)) {
742 struct prefix_evpn
*evp
=
743 (struct prefix_evpn
*)bgp_dest_get_prefix(dest
);
745 for (pi
= bgp_dest_get_bgp_path_info(dest
); pi
;
748 * Consider "valid" remote routes applicable for
751 if (!(CHECK_FLAG(pi
->flags
, BGP_PATH_VALID
)
752 && pi
->type
== ZEBRA_ROUTE_BGP
753 && pi
->sub_type
== BGP_ROUTE_NORMAL
))
756 if (!bgp_evpn_type4_prefix_match(evp
, es
))
760 ret
= bgp_evpn_es_route_install(
763 ret
= bgp_evpn_es_route_uninstall(
769 "Failed to %s EVPN %pFX route in ESI %s",
774 bgp_dest_unlock_node(rd_dest
);
775 bgp_dest_unlock_node(dest
);
784 /*****************************************************************************
785 * Ethernet Auto Discovery (EAD/Type-1) route handling
786 * There are two types of EAD routes -
787 * 1. EAD-per-ES - Key: {ESI, ET=0xffffffff}
788 * 2. EAD-per-EVI - Key: {ESI, ET=0}
791 /* Extended communities associated with EAD-per-ES */
792 static void bgp_evpn_type1_es_route_extcomm_build(struct bgp_evpn_es
*es
,
795 struct ecommunity ecom_encap
;
796 struct ecommunity ecom_esi_label
;
797 struct ecommunity_val eval
;
798 struct ecommunity_val eval_esi_label
;
799 bgp_encap_types tnl_type
;
800 struct listnode
*evi_node
, *rt_node
;
801 struct ecommunity
*ecom
;
802 struct bgp_evpn_es_evi
*es_evi
;
805 tnl_type
= BGP_ENCAP_TYPE_VXLAN
;
806 memset(&ecom_encap
, 0, sizeof(ecom_encap
));
807 encode_encap_extcomm(tnl_type
, &eval
);
809 ecom_encap
.unit_size
= ECOMMUNITY_SIZE
;
810 ecom_encap
.val
= (uint8_t *)eval
.val
;
811 attr
->ecommunity
= ecommunity_dup(&ecom_encap
);
814 encode_esi_label_extcomm(&eval_esi_label
,
815 false /*single_active*/);
816 ecom_esi_label
.size
= 1;
817 ecom_esi_label
.unit_size
= ECOMMUNITY_SIZE
;
818 ecom_esi_label
.val
= (uint8_t *)eval_esi_label
.val
;
820 ecommunity_merge(attr
->ecommunity
, &ecom_esi_label
);
822 /* Add export RTs for all L2-VNIs associated with this ES */
823 /* XXX - suppress EAD-ES advertisment if there are no EVIs associated
826 for (ALL_LIST_ELEMENTS_RO(es
->es_evi_list
,
828 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
830 for (ALL_LIST_ELEMENTS_RO(es_evi
->vpn
->export_rtl
,
832 attr
->ecommunity
= ecommunity_merge(attr
->ecommunity
,
836 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES
);
839 /* Extended communities associated with EAD-per-EVI */
840 static void bgp_evpn_type1_evi_route_extcomm_build(struct bgp_evpn_es
*es
,
841 struct bgpevpn
*vpn
, struct attr
*attr
)
843 struct ecommunity ecom_encap
;
844 struct ecommunity_val eval
;
845 bgp_encap_types tnl_type
;
846 struct listnode
*rt_node
;
847 struct ecommunity
*ecom
;
850 tnl_type
= BGP_ENCAP_TYPE_VXLAN
;
851 memset(&ecom_encap
, 0, sizeof(ecom_encap
));
852 encode_encap_extcomm(tnl_type
, &eval
);
854 ecom_encap
.unit_size
= ECOMMUNITY_SIZE
;
855 ecom_encap
.val
= (uint8_t *)eval
.val
;
856 attr
->ecommunity
= ecommunity_dup(&ecom_encap
);
858 /* Add export RTs for the L2-VNI */
859 for (ALL_LIST_ELEMENTS_RO(vpn
->export_rtl
, rt_node
, ecom
))
860 attr
->ecommunity
= ecommunity_merge(attr
->ecommunity
, ecom
);
862 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES
);
865 /* Update EVPN EAD (type-1) route -
866 * vpn - valid for EAD-EVI routes and NULL for EAD-ES routes
868 static int bgp_evpn_type1_route_update(struct bgp
*bgp
,
869 struct bgp_evpn_es
*es
, struct bgpevpn
*vpn
,
870 struct prefix_evpn
*p
)
873 afi_t afi
= AFI_L2VPN
;
874 safi_t safi
= SAFI_EVPN
;
876 struct attr
*attr_new
= NULL
;
877 struct bgp_dest
*dest
= NULL
;
878 struct bgp_path_info
*pi
= NULL
;
879 int route_changed
= 0;
880 struct prefix_rd
*global_rd
;
882 memset(&attr
, 0, sizeof(struct attr
));
884 /* Build path-attribute for this route. */
885 bgp_attr_default_set(&attr
, BGP_ORIGIN_IGP
);
886 attr
.nexthop
= es
->originator_ip
;
887 attr
.mp_nexthop_global_in
= es
->originator_ip
;
888 attr
.mp_nexthop_len
= BGP_ATTR_NHLEN_IPV4
;
891 /* EAD-EVI route update */
893 vni2label(vpn
->vni
, &(attr
.label
));
895 /* Set up extended community */
896 bgp_evpn_type1_evi_route_extcomm_build(es
, vpn
, &attr
);
898 /* First, create (or fetch) route node within the VNI. */
899 dest
= bgp_node_get(vpn
->route_table
, (struct prefix
*)p
);
901 /* Create or update route entry. */
902 ret
= bgp_evpn_mh_route_update(bgp
, es
, vpn
, afi
, safi
, dest
,
903 &attr
, 1, &pi
, &route_changed
);
907 "%u Failed to update EAD-EVI route ESI: %s VNI %u VTEP %pI4",
908 bgp
->vrf_id
, es
->esi_str
, vpn
->vni
,
910 global_rd
= &vpn
->prd
;
912 /* EAD-ES route update */
913 /* MPLS label is 0 for EAD-ES route */
915 /* Set up extended community */
916 bgp_evpn_type1_es_route_extcomm_build(es
, &attr
);
918 /* First, create (or fetch) route node within the ES. */
919 /* NOTE: There is no RD here. */
920 /* XXX: fragment ID must be included as a part of the prefix. */
921 dest
= bgp_node_get(es
->route_table
, (struct prefix
*)p
);
923 /* Create or update route entry. */
924 ret
= bgp_evpn_mh_route_update(bgp
, es
, vpn
, afi
, safi
, dest
,
925 &attr
, 1, &pi
, &route_changed
);
929 "%u ERROR: Failed to updated EAD-EVI route ESI: %s VTEP %pI4",
930 bgp
->vrf_id
, es
->esi_str
, &es
->originator_ip
);
932 global_rd
= &es
->prd
;
939 /* Perform route selection;
940 * this is just to set the flags correctly as local route in
941 * the ES always wins.
943 evpn_route_select_install(bgp
, vpn
, dest
);
944 bgp_dest_unlock_node(dest
);
946 /* If this is a new route or some attribute has changed, export the
947 * route to the global table. The route will be advertised to peers
948 * from there. Note that this table is a 2-level tree (RD-level +
949 * Prefix-level) similar to L3VPN routes.
952 struct bgp_path_info
*global_pi
;
954 dest
= bgp_global_evpn_node_get(bgp
->rib
[afi
][safi
], afi
, safi
,
956 bgp_evpn_mh_route_update(bgp
, es
, vpn
, afi
, safi
, dest
,
957 attr_new
, 1, &global_pi
,
960 /* Schedule for processing and unlock node. */
961 bgp_process(bgp
, dest
, afi
, safi
);
962 bgp_dest_unlock_node(dest
);
965 /* Unintern temporary. */
966 aspath_unintern(&attr
.aspath
);
971 * This function is called when the export RT for a VNI changes.
972 * Update all type-1 local routes for this VNI from VNI/ES tables and the global
973 * table and advertise these routes to peers.
976 void update_type1_routes_for_evi(struct bgp
*bgp
, struct bgpevpn
*vpn
)
978 struct prefix_evpn p
;
979 struct bgp_evpn_es
*es
;
980 struct bgp_evpn_es_evi
*es_evi
;
981 struct bgp_evpn_es_evi
*es_evi_next
;
983 RB_FOREACH_SAFE(es_evi
, bgp_es_evi_rb_head
,
984 &vpn
->es_evi_rb_tree
, es_evi_next
) {
988 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_OPER_UP
)) {
989 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_ES_ETH_TAG
,
990 &es
->esi
, es
->originator_ip
);
991 if (bgp_evpn_type1_route_update(bgp
, es
, NULL
, &p
))
992 flog_err(EC_BGP_EVPN_ROUTE_CREATE
,
993 "%u: EAD-ES route update failure for ESI %s VNI %u",
994 bgp
->vrf_id
, es
->esi_str
,
999 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
)) {
1000 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_EVI_ETH_TAG
,
1001 &es
->esi
, es
->originator_ip
);
1002 if (bgp_evpn_type1_route_update(bgp
, es
, es_evi
->vpn
,
1004 flog_err(EC_BGP_EVPN_ROUTE_DELETE
,
1005 "%u: EAD-EVI route update failure for ESI %s VNI %u",
1006 bgp
->vrf_id
, es
->esi_str
,
1012 /* Delete local Type-1 route */
1013 static int bgp_evpn_type1_es_route_delete(struct bgp
*bgp
,
1014 struct bgp_evpn_es
*es
, struct prefix_evpn
*p
)
1016 return bgp_evpn_mh_route_delete(bgp
, es
, NULL
/* l2vni */, p
);
1019 static int bgp_evpn_type1_evi_route_delete(struct bgp
*bgp
,
1020 struct bgp_evpn_es
*es
, struct bgpevpn
*vpn
,
1021 struct prefix_evpn
*p
)
1023 return bgp_evpn_mh_route_delete(bgp
, es
, vpn
, p
);
1026 /* Generate EAD-EVI for all VNIs */
1027 static void bgp_evpn_local_type1_evi_route_add(struct bgp
*bgp
,
1028 struct bgp_evpn_es
*es
)
1030 struct listnode
*evi_node
;
1031 struct prefix_evpn p
;
1032 struct bgp_evpn_es_evi
*es_evi
;
1034 /* EAD-per-EVI routes have been suppressed */
1035 if (!bgp_mh_info
->ead_evi_tx
)
1038 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
))
1039 /* EAD-EVI route add for this ES is already done */
1042 SET_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
);
1043 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_EVI_ETH_TAG
,
1044 &es
->esi
, es
->originator_ip
);
1046 for (ALL_LIST_ELEMENTS_RO(es
->es_evi_list
, evi_node
, es_evi
)) {
1047 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
1049 if (bgp_evpn_type1_route_update(bgp
, es
, es_evi
->vpn
, &p
))
1050 flog_err(EC_BGP_EVPN_ROUTE_CREATE
,
1051 "%u: Type4 route creation failure for ESI %s",
1052 bgp
->vrf_id
, es
->esi_str
);
1057 * Withdraw EAD-EVI for all VNIs
1059 static void bgp_evpn_local_type1_evi_route_del(struct bgp
*bgp
,
1060 struct bgp_evpn_es
*es
)
1062 struct listnode
*evi_node
;
1063 struct prefix_evpn p
;
1064 struct bgp_evpn_es_evi
*es_evi
;
1066 /* Delete and withdraw locally learnt EAD-EVI route */
1067 if (!CHECK_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
))
1068 /* EAD-EVI route has not been advertised for this ES */
1071 UNSET_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
);
1072 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_EVI_ETH_TAG
,
1073 &es
->esi
, es
->originator_ip
);
1074 for (ALL_LIST_ELEMENTS_RO(es
->es_evi_list
, evi_node
, es_evi
)) {
1075 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
1077 if (bgp_evpn_mh_route_delete(bgp
, es
, es_evi
->vpn
, &p
))
1078 flog_err(EC_BGP_EVPN_ROUTE_CREATE
,
1079 "%u: Type4 route creation failure for ESI %s",
1080 bgp
->vrf_id
, es
->esi_str
);
1085 * Process received EVPN type-1 route (advertise or withdraw).
1087 int bgp_evpn_type1_route_process(struct peer
*peer
, afi_t afi
, safi_t safi
,
1088 struct attr
*attr
, uint8_t *pfx
, int psize
,
1089 uint32_t addpath_id
)
1092 struct prefix_rd prd
;
1096 struct in_addr vtep_ip
;
1097 struct prefix_evpn p
;
1099 if (psize
!= BGP_EVPN_TYPE1_PSIZE
) {
1100 flog_err(EC_BGP_EVPN_ROUTE_INVALID
,
1101 "%u:%s - Rx EVPN Type-1 NLRI with invalid length %d",
1102 peer
->bgp
->vrf_id
, peer
->host
, psize
);
1106 /* Make prefix_rd */
1107 prd
.family
= AF_UNSPEC
;
1109 memcpy(&prd
.val
, pfx
, RD_BYTES
);
1113 memcpy(&esi
, pfx
, ESI_BYTES
);
1116 /* Copy Ethernet Tag */
1117 memcpy(ð_tag
, pfx
, EVPN_ETH_TAG_BYTES
);
1118 eth_tag
= ntohl(eth_tag
);
1119 pfx
+= EVPN_ETH_TAG_BYTES
;
1121 memcpy(&label
, pfx
, BGP_LABEL_BYTES
);
1123 /* EAD route prefix doesn't include the nexthop in the global
1126 vtep_ip
.s_addr
= INADDR_ANY
;
1127 build_evpn_type1_prefix(&p
, eth_tag
, &esi
, vtep_ip
);
1128 /* Process the route. */
1130 ret
= bgp_update(peer
, (struct prefix
*)&p
, addpath_id
, attr
,
1131 afi
, safi
, ZEBRA_ROUTE_BGP
, BGP_ROUTE_NORMAL
,
1132 &prd
, NULL
, 0, 0, NULL
);
1134 ret
= bgp_withdraw(peer
, (struct prefix
*)&p
, addpath_id
, attr
,
1135 afi
, safi
, ZEBRA_ROUTE_BGP
, BGP_ROUTE_NORMAL
,
1136 &prd
, NULL
, 0, NULL
);
1141 /*****************************************************************************/
1142 /* Ethernet Segment Management
1143 * 1. Ethernet Segment is a collection of links attached to the same
1144 * server (MHD) or switch (MHN)
1145 * 2. An Ethernet Segment can span multiple PEs and is identified by the
1147 * 3. Local ESs are configured in zebra and sent to BGP
1148 * 4. Remote ESs are created by BGP when one or more ES-EVIs reference it i.e.
1149 * created on first reference and release on last de-reference
1150 * 5. An ES can be both local and remote. Infact most local ESs are expected
1151 * to have an ES peer.
1154 /* A list of remote VTEPs is maintained for each ES. This list includes -
1155 * 1. VTEPs for which we have imported the ESR i.e. ES-peers
1156 * 2. VTEPs that have an "active" ES-EVI VTEP i.e. EAD-per-ES and EAD-per-EVI
1157 * have been imported into one or more VNIs
1159 static int bgp_evpn_es_vtep_cmp(void *p1
, void *p2
)
1161 const struct bgp_evpn_es_vtep
*es_vtep1
= p1
;
1162 const struct bgp_evpn_es_vtep
*es_vtep2
= p2
;
1164 return es_vtep1
->vtep_ip
.s_addr
- es_vtep2
->vtep_ip
.s_addr
;
1167 static struct bgp_evpn_es_vtep
*bgp_evpn_es_vtep_new(struct bgp_evpn_es
*es
,
1168 struct in_addr vtep_ip
)
1170 struct bgp_evpn_es_vtep
*es_vtep
;
1172 es_vtep
= XCALLOC(MTYPE_BGP_EVPN_ES_VTEP
, sizeof(*es_vtep
));
1175 es_vtep
->vtep_ip
.s_addr
= vtep_ip
.s_addr
;
1176 listnode_init(&es_vtep
->es_listnode
, es_vtep
);
1177 listnode_add_sort(es
->es_vtep_list
, &es_vtep
->es_listnode
);
1182 static void bgp_evpn_es_vtep_free(struct bgp_evpn_es_vtep
*es_vtep
)
1184 struct bgp_evpn_es
*es
= es_vtep
->es
;
1186 if (CHECK_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ESR
) ||
1188 /* as long as there is some reference we can't free it */
1191 list_delete_node(es
->es_vtep_list
, &es_vtep
->es_listnode
);
1192 XFREE(MTYPE_BGP_EVPN_ES_VTEP
, es_vtep
);
1195 /* check if VTEP is already part of the list */
1196 static struct bgp_evpn_es_vtep
*bgp_evpn_es_vtep_find(struct bgp_evpn_es
*es
,
1197 struct in_addr vtep_ip
)
1199 struct listnode
*node
= NULL
;
1200 struct bgp_evpn_es_vtep
*es_vtep
;
1202 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
1203 if (es_vtep
->vtep_ip
.s_addr
== vtep_ip
.s_addr
)
1209 /* Send the remote ES to zebra for NHG programming */
1210 static int bgp_zebra_send_remote_es_vtep(struct bgp
*bgp
,
1211 struct bgp_evpn_es_vtep
*es_vtep
, bool add
)
1213 struct bgp_evpn_es
*es
= es_vtep
->es
;
1218 if (!zclient
|| zclient
->sock
< 0)
1221 /* Don't try to register if Zebra doesn't know of this instance. */
1222 if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp
)) {
1223 if (BGP_DEBUG(zebra
, ZEBRA
))
1224 zlog_debug("No zebra instance, not installing remote es %s",
1229 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ESR
)
1230 flags
|= ZAPI_ES_VTEP_FLAG_ESR_RXED
;
1235 zclient_create_header(s
,
1236 add
? ZEBRA_REMOTE_ES_VTEP_ADD
: ZEBRA_REMOTE_ES_VTEP_DEL
,
1238 stream_put(s
, &es
->esi
, sizeof(esi_t
));
1239 stream_put_ipv4(s
, es_vtep
->vtep_ip
.s_addr
);
1241 stream_putl(s
, flags
);
1242 stream_putc(s
, es_vtep
->df_alg
);
1243 stream_putw(s
, es_vtep
->df_pref
);
1246 stream_putw_at(s
, 0, stream_get_endp(s
));
1248 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1249 zlog_debug("Tx %s Remote ESI %s VTEP %pI4", add
? "ADD" : "DEL",
1250 es
->esi_str
, &es_vtep
->vtep_ip
);
1252 return zclient_send_message(zclient
);
1255 static void bgp_evpn_es_vtep_re_eval_active(struct bgp
*bgp
,
1256 struct bgp_evpn_es_vtep
*es_vtep
,
1262 old_active
= !!CHECK_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
);
1263 /* currently we need an active EVI reference to use the VTEP as
1264 * a nexthop. this may change...
1266 if (es_vtep
->evi_cnt
)
1267 SET_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
);
1269 UNSET_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
);
1271 new_active
= !!CHECK_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
);
1273 if ((old_active
!= new_active
) || (new_active
&& param_change
)) {
1275 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1276 zlog_debug("es %s vtep %pI4 %s df %u/%u",
1277 es_vtep
->es
->esi_str
, &es_vtep
->vtep_ip
,
1278 new_active
? "active" : "inactive",
1279 es_vtep
->df_alg
, es_vtep
->df_pref
);
1281 /* send remote ES to zebra */
1282 bgp_zebra_send_remote_es_vtep(bgp
, es_vtep
, new_active
);
1284 /* The NHG is updated first for efficient failover handling.
1285 * Note the NHG can be de-activated while there are bgp
1286 * routes referencing it. Zebra is capable of handling that
1287 * elegantly by holding the NHG till all routes using it are
1290 bgp_evpn_l3nhg_update_on_vtep_chg(es_vtep
->es
);
1291 /* queue up the es for background consistency checks */
1292 bgp_evpn_es_cons_checks_pend_add(es_vtep
->es
);
1296 static struct bgp_evpn_es_vtep
*bgp_evpn_es_vtep_add(struct bgp
*bgp
,
1297 struct bgp_evpn_es
*es
,
1298 struct in_addr vtep_ip
,
1299 bool esr
, uint8_t df_alg
,
1302 struct bgp_evpn_es_vtep
*es_vtep
;
1303 bool param_change
= false;
1305 es_vtep
= bgp_evpn_es_vtep_find(es
, vtep_ip
);
1308 es_vtep
= bgp_evpn_es_vtep_new(es
, vtep_ip
);
1310 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1311 zlog_debug("es %s vtep %pI4 add %s df %u/%u",
1312 es_vtep
->es
->esi_str
, &es_vtep
->vtep_ip
,
1313 esr
? "esr" : "ead", df_alg
, df_pref
);
1316 SET_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ESR
);
1317 if ((es_vtep
->df_pref
!= df_pref
)
1318 || (es_vtep
->df_alg
!= df_alg
)) {
1319 param_change
= true;
1320 es_vtep
->df_pref
= df_pref
;
1321 es_vtep
->df_alg
= df_alg
;
1327 bgp_evpn_es_vtep_re_eval_active(bgp
, es_vtep
, param_change
);
1332 static void bgp_evpn_es_vtep_do_del(struct bgp
*bgp
,
1333 struct bgp_evpn_es_vtep
*es_vtep
, bool esr
)
1335 bool param_change
= false;
1337 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1338 zlog_debug("es %s vtep %pI4 del %s", es_vtep
->es
->esi_str
,
1339 &es_vtep
->vtep_ip
, esr
? "esr" : "ead");
1341 UNSET_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ESR
);
1342 if (es_vtep
->df_pref
|| es_vtep
->df_alg
) {
1343 param_change
= true;
1344 es_vtep
->df_pref
= 0;
1345 es_vtep
->df_alg
= 0;
1348 if (es_vtep
->evi_cnt
)
1352 bgp_evpn_es_vtep_re_eval_active(bgp
, es_vtep
, param_change
);
1353 bgp_evpn_es_vtep_free(es_vtep
);
1356 static void bgp_evpn_es_vtep_del(struct bgp
*bgp
,
1357 struct bgp_evpn_es
*es
, struct in_addr vtep_ip
, bool esr
)
1359 struct bgp_evpn_es_vtep
*es_vtep
;
1361 es_vtep
= bgp_evpn_es_vtep_find(es
, vtep_ip
);
1363 bgp_evpn_es_vtep_do_del(bgp
, es_vtep
, esr
);
1366 /********************** ES MAC-IP paths *************************************
1367 * 1. Local MAC-IP routes in the VNI routing table are linked to the
1368 * destination ES (macip_evi_path_list) for efficient updates on ES oper
1370 * 2. Non-local MAC-IP routes in the global routing table are linked to
1371 * the detination for efficient updates on -
1372 * a. VTEP add/del - this results in a L3NHG update.
1373 * b. ES-VRF add/del - this may result in the host route being migrated to
1374 * L3NHG or vice versa (flat multipath list).
1375 ****************************************************************************/
1376 void bgp_evpn_path_es_info_free(struct bgp_path_es_info
*es_info
)
1378 bgp_evpn_path_es_unlink(es_info
);
1379 XFREE(MTYPE_BGP_EVPN_PATH_ES_INFO
, es_info
);
1382 static struct bgp_path_es_info
*
1383 bgp_evpn_path_es_info_new(struct bgp_path_info
*pi
, vni_t vni
)
1385 struct bgp_path_info_extra
*e
;
1387 e
= bgp_path_info_extra_get(pi
);
1389 /* If es_info doesn't exist allocate it */
1391 e
->es_info
= XCALLOC(MTYPE_BGP_EVPN_PATH_ES_INFO
,
1392 sizeof(struct bgp_path_es_info
));
1393 e
->es_info
->pi
= pi
;
1394 e
->es_info
->vni
= vni
;
1400 void bgp_evpn_path_es_unlink(struct bgp_path_es_info
*es_info
)
1402 struct bgp_evpn_es
*es
= es_info
->es
;
1403 struct bgp_path_info
*pi
;
1409 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
1410 zlog_debug("vni %u path %pFX unlinked from es %s", es_info
->vni
,
1411 &pi
->net
->p
, es
->esi_str
);
1414 list_delete_node(es
->macip_evi_path_list
,
1415 &es_info
->es_listnode
);
1417 list_delete_node(es
->macip_global_path_list
,
1418 &es_info
->es_listnode
);
1421 /* if there are no other references against the ES it
1424 bgp_evpn_es_free(es
, __func__
);
1426 /* Note we don't free the path es_info on unlink; it will be freed up
1427 * along with the path.
1431 void bgp_evpn_path_es_link(struct bgp_path_info
*pi
, vni_t vni
, esi_t
*esi
)
1433 struct bgp_path_es_info
*es_info
;
1434 struct bgp_evpn_es
*es
;
1435 struct bgp
*bgp_evpn
;
1436 struct prefix_evpn
*evp
;
1438 es_info
= pi
->extra
? pi
->extra
->es_info
: NULL
;
1439 /* if the esi is zero just unlink the path from the old es */
1440 if (!esi
|| !memcmp(esi
, zero_esi
, sizeof(*esi
))) {
1442 bgp_evpn_path_es_unlink(es_info
);
1446 bgp_evpn
= bgp_get_evpn();
1450 /* Only MAC-IP routes need to be linked (MAC-only routes can be
1451 * skipped) as these lists are maintained for managing
1452 * host routes in the tenant VRF
1454 evp
= (struct prefix_evpn
*)&pi
->net
->p
;
1455 if (!(is_evpn_prefix_ipaddr_v4(evp
) || is_evpn_prefix_ipaddr_v6(evp
)))
1458 /* setup es_info against the path if it doesn't aleady exist */
1460 es_info
= bgp_evpn_path_es_info_new(pi
, vni
);
1462 /* find-create ES */
1463 es
= bgp_evpn_es_find(esi
);
1465 es
= bgp_evpn_es_new(bgp_evpn
, esi
);
1468 if (es_info
->es
== es
)
1471 /* unlink old ES if any */
1472 bgp_evpn_path_es_unlink(es_info
);
1474 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
1475 zlog_debug("vni %u path %pFX linked to es %s", vni
, &pi
->net
->p
,
1478 /* link mac-ip path to the new destination ES */
1480 listnode_init(&es_info
->es_listnode
, es_info
);
1482 listnode_add(es
->macip_evi_path_list
, &es_info
->es_listnode
);
1484 listnode_add(es
->macip_global_path_list
, &es_info
->es_listnode
);
1487 /* When a remote ES is added to a VRF, routes using that as
1488 * a destination need to be migrated to a L3NHG or viceversa.
1489 * This is done indirectly by re-attempting an install of the
1490 * route in the associated VRFs. As a part of the VRF install use
1491 * of l3 NHG is evaluated and this results in the
1492 * attr.es_flag ATTR_ES_USE_L3_NHG being set or cleared.
1495 bgp_evpn_es_path_update_on_es_vrf_chg(struct bgp_evpn_es_vrf
*es_vrf
,
1498 struct listnode
*node
;
1499 struct bgp_path_es_info
*es_info
;
1500 struct bgp_path_info
*pi
;
1501 struct bgp_evpn_es
*es
= es_vrf
->es
;
1503 if (!bgp_mh_info
->host_routes_use_l3nhg
)
1506 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
1507 zlog_debug("update paths linked to es %s on es-vrf %s %s",
1508 es
->esi_str
, es_vrf
->bgp_vrf
->name
, reason
);
1510 for (ALL_LIST_ELEMENTS_RO(es
->macip_global_path_list
, node
, es_info
)) {
1513 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
1515 "update path %pFX linked to es %s on vrf chg",
1516 &pi
->net
->p
, es
->esi_str
);
1517 bgp_evpn_route_entry_install_if_vrf_match(es_vrf
->bgp_vrf
, pi
,
1522 /* compare ES-IDs for the global ES RB tree */
1523 static int bgp_es_rb_cmp(const struct bgp_evpn_es
*es1
,
1524 const struct bgp_evpn_es
*es2
)
1526 return memcmp(&es1
->esi
, &es2
->esi
, ESI_BYTES
);
1528 RB_GENERATE(bgp_es_rb_head
, bgp_evpn_es
, rb_node
, bgp_es_rb_cmp
);
1530 struct bgp_evpn_es
*bgp_evpn_es_find(const esi_t
*esi
)
1532 struct bgp_evpn_es tmp
;
1534 memcpy(&tmp
.esi
, esi
, sizeof(esi_t
));
1535 return RB_FIND(bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
, &tmp
);
1538 static struct bgp_evpn_es
*bgp_evpn_es_new(struct bgp
*bgp
, const esi_t
*esi
)
1540 struct bgp_evpn_es
*es
;
1545 es
= XCALLOC(MTYPE_BGP_EVPN_ES
, sizeof(struct bgp_evpn_es
));
1548 memcpy(&es
->esi
, esi
, sizeof(esi_t
));
1550 /* Initialise the VTEP list */
1551 es
->es_vtep_list
= list_new();
1552 listset_app_node_mem(es
->es_vtep_list
);
1553 es
->es_vtep_list
->cmp
= bgp_evpn_es_vtep_cmp
;
1555 esi_to_str(&es
->esi
, es
->esi_str
, sizeof(es
->esi_str
));
1557 /* Initialize the ES routing table */
1558 es
->route_table
= bgp_table_init(bgp
, AFI_L2VPN
, SAFI_EVPN
);
1560 /* Add to rb_tree */
1561 if (RB_INSERT(bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
, es
)) {
1562 XFREE(MTYPE_BGP_EVPN_ES
, es
);
1566 /* Initialise the ES-EVI list */
1567 es
->es_evi_list
= list_new();
1568 listset_app_node_mem(es
->es_evi_list
);
1570 /* Initialise the ES-VRF list used for L3NHG management */
1571 es
->es_vrf_list
= list_new();
1572 listset_app_node_mem(es
->es_vrf_list
);
1574 /* Initialise the route list used for efficient event handling */
1575 es
->macip_evi_path_list
= list_new();
1576 listset_app_node_mem(es
->macip_evi_path_list
);
1577 es
->macip_global_path_list
= list_new();
1578 listset_app_node_mem(es
->macip_global_path_list
);
1580 QOBJ_REG(es
, bgp_evpn_es
);
1585 /* Free a given ES -
1586 * This just frees appropriate memory, caller should have taken other
1589 static void bgp_evpn_es_free(struct bgp_evpn_es
*es
, const char *caller
)
1591 if ((es
->flags
& (BGP_EVPNES_LOCAL
| BGP_EVPNES_REMOTE
))
1592 || listcount(es
->macip_evi_path_list
)
1593 || listcount(es
->macip_global_path_list
))
1596 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1597 zlog_debug("%s: es %s free", caller
, es
->esi_str
);
1599 /* cleanup resources maintained against the ES */
1600 list_delete(&es
->es_evi_list
);
1601 list_delete(&es
->es_vrf_list
);
1602 list_delete(&es
->es_vtep_list
);
1603 list_delete(&es
->macip_evi_path_list
);
1604 list_delete(&es
->macip_global_path_list
);
1605 bgp_table_unlock(es
->route_table
);
1607 /* remove the entry from various databases */
1608 RB_REMOVE(bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
, es
);
1609 bgp_evpn_es_cons_checks_pend_del(es
);
1612 XFREE(MTYPE_BGP_EVPN_ES
, es
);
1615 /* init local info associated with the ES */
1616 static void bgp_evpn_es_local_info_set(struct bgp
*bgp
, struct bgp_evpn_es
*es
)
1618 char buf
[BGP_EVPN_PREFIX_RD_LEN
];
1620 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_LOCAL
))
1623 SET_FLAG(es
->flags
, BGP_EVPNES_LOCAL
);
1624 listnode_init(&es
->es_listnode
, es
);
1625 listnode_add(bgp_mh_info
->local_es_list
, &es
->es_listnode
);
1627 /* auto derive RD for this es */
1628 bf_assign_index(bm
->rd_idspace
, es
->rd_id
);
1629 es
->prd
.family
= AF_UNSPEC
;
1630 es
->prd
.prefixlen
= 64;
1631 snprintfrr(buf
, sizeof(buf
), "%pI4:%hu", &bgp
->router_id
, es
->rd_id
);
1632 (void)str2prefix_rd(buf
, &es
->prd
);
1635 /* clear any local info associated with the ES */
1636 static void bgp_evpn_es_local_info_clear(struct bgp_evpn_es
*es
)
1638 if (!CHECK_FLAG(es
->flags
, BGP_EVPNES_LOCAL
))
1641 UNSET_FLAG(es
->flags
, BGP_EVPNES_LOCAL
);
1643 /* remove from the ES local list */
1644 list_delete_node(bgp_mh_info
->local_es_list
, &es
->es_listnode
);
1646 bf_release_index(bm
->rd_idspace
, es
->rd_id
);
1648 bgp_evpn_es_free(es
, __func__
);
1651 /* eval remote info associated with the ES */
1652 static void bgp_evpn_es_remote_info_re_eval(struct bgp_evpn_es
*es
)
1654 if (es
->remote_es_evi_cnt
) {
1655 SET_FLAG(es
->flags
, BGP_EVPNES_REMOTE
);
1657 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_REMOTE
)) {
1658 UNSET_FLAG(es
->flags
, BGP_EVPNES_REMOTE
);
1659 bgp_evpn_es_free(es
, __func__
);
1664 /* If ES is present and local it needs to be active/oper-up for
1667 bool bgp_evpn_es_add_l3_ecomm_ok(esi_t
*esi
)
1669 struct bgp_evpn_es
*es
;
1671 if (!esi
|| !bgp_mh_info
->suppress_l3_ecomm_on_inactive_es
)
1674 es
= bgp_evpn_es_find(esi
);
1676 return (!es
|| !(es
->flags
& BGP_EVPNES_LOCAL
)
1677 || bgp_evpn_local_es_is_active(es
));
1680 /* Update all local MAC-IP routes in the VNI routing table associated
1681 * with the ES. When the ES is down the routes are advertised without
1684 static void bgp_evpn_mac_update_on_es_oper_chg(struct bgp_evpn_es
*es
)
1686 struct listnode
*node
;
1687 struct bgp_path_es_info
*es_info
;
1688 struct bgp_path_info
*pi
;
1689 char prefix_buf
[PREFIX_STRLEN
];
1691 struct bgpevpn
*vpn
;
1693 if (!bgp_mh_info
->suppress_l3_ecomm_on_inactive_es
)
1696 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1697 zlog_debug("update paths linked to es %s on oper chg",
1700 bgp
= bgp_get_evpn();
1701 for (ALL_LIST_ELEMENTS_RO(es
->macip_evi_path_list
, node
, es_info
)) {
1703 if (!CHECK_FLAG(pi
->flags
, BGP_PATH_VALID
))
1706 if (pi
->type
!= ZEBRA_ROUTE_BGP
1707 || pi
->sub_type
!= BGP_ROUTE_STATIC
)
1710 vpn
= bgp_evpn_lookup_vni(bgp
, es_info
->vni
);
1714 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
1716 "update path %d %s linked to es %s on oper chg",
1718 prefix2str(&pi
->net
->p
, prefix_buf
,
1719 sizeof(prefix_buf
)),
1722 bgp_evpn_update_type2_route_entry(bgp
, vpn
, pi
->net
, pi
,
1727 static void bgp_evpn_local_es_deactivate(struct bgp
*bgp
,
1728 struct bgp_evpn_es
*es
)
1730 struct prefix_evpn p
;
1734 /* Delete and withdraw locally learnt ES route */
1735 build_evpn_type4_prefix(&p
, &es
->esi
, es
->originator_ip
);
1736 ret
= bgp_evpn_type4_route_delete(bgp
, es
, &p
);
1738 flog_err(EC_BGP_EVPN_ROUTE_DELETE
,
1739 "%u failed to delete type-4 route for ESI %s",
1740 bgp
->vrf_id
, es
->esi_str
);
1743 /* withdraw EAD-EVI */
1744 if (!bgp_mh_info
->ead_evi_adv_for_down_links
)
1745 bgp_evpn_local_type1_evi_route_del(bgp
, es
);
1747 /* withdraw EAD-ES */
1748 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_ES_ETH_TAG
,
1749 &es
->esi
, es
->originator_ip
);
1750 ret
= bgp_evpn_type1_es_route_delete(bgp
, es
, &p
);
1752 flog_err(EC_BGP_EVPN_ROUTE_DELETE
,
1753 "%u failed to delete type-1 route for ESI %s",
1754 bgp
->vrf_id
, es
->esi_str
);
1757 bgp_evpn_mac_update_on_es_oper_chg(es
);
1760 /* Process ES link oper-down by withdrawing ES-EAD and ESR */
1761 static void bgp_evpn_local_es_down(struct bgp
*bgp
, struct bgp_evpn_es
*es
)
1765 if (!CHECK_FLAG(es
->flags
, BGP_EVPNES_OPER_UP
))
1768 old_active
= bgp_evpn_local_es_is_active(es
);
1769 UNSET_FLAG(es
->flags
, BGP_EVPNES_OPER_UP
);
1771 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1772 zlog_debug("local es %s down", es
->esi_str
);
1775 bgp_evpn_local_es_deactivate(bgp
, es
);
1778 static void bgp_evpn_local_es_activate(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
1779 bool regen_ead
, bool regen_esr
)
1781 struct prefix_evpn p
;
1784 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1785 zlog_debug("local es %s generate ESR", es
->esi_str
);
1787 build_evpn_type4_prefix(&p
, &es
->esi
, es
->originator_ip
);
1788 if (bgp_evpn_type4_route_update(bgp
, es
, &p
))
1789 flog_err(EC_BGP_EVPN_ROUTE_CREATE
,
1790 "%u: Type4 route creation failure for ESI %s",
1791 bgp
->vrf_id
, es
->esi_str
);
1795 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1796 zlog_debug("local es %s generate EAD", es
->esi_str
);
1797 /* generate EAD-EVI */
1798 bgp_evpn_local_type1_evi_route_add(bgp
, es
);
1800 /* generate EAD-ES */
1801 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_ES_ETH_TAG
, &es
->esi
,
1803 (void)bgp_evpn_type1_route_update(bgp
, es
, NULL
, &p
);
1806 bgp_evpn_mac_update_on_es_oper_chg(es
);
1809 /* Process ES link oper-up by generating ES-EAD and ESR */
1810 static void bgp_evpn_local_es_up(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
1813 bool regen_ead
= false;
1814 bool active
= false;
1816 if (!CHECK_FLAG(es
->flags
, BGP_EVPNES_OPER_UP
)) {
1817 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1818 zlog_debug("local es %s up", es
->esi_str
);
1820 SET_FLAG(es
->flags
, BGP_EVPNES_OPER_UP
);
1825 active
= bgp_evpn_local_es_is_active(es
);
1826 if (active
&& (regen_ead
|| regen_esr
))
1827 bgp_evpn_local_es_activate(bgp
, es
, regen_ead
, regen_esr
);
1830 /* If an ethernet segment is in LACP bypass we cannot advertise
1831 * reachability to it i.e. EAD-per-ES and ESR is not advertised in
1833 * PS: EAD-per-EVI will continue to be advertised
1835 static void bgp_evpn_local_es_bypass_update(struct bgp
*bgp
,
1836 struct bgp_evpn_es
*es
, bool bypass
)
1838 bool old_bypass
= !!(es
->flags
& BGP_EVPNES_BYPASS
);
1842 if (bypass
== old_bypass
)
1845 old_active
= bgp_evpn_local_es_is_active(es
);
1847 SET_FLAG(es
->flags
, BGP_EVPNES_BYPASS
);
1849 UNSET_FLAG(es
->flags
, BGP_EVPNES_BYPASS
);
1851 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1852 zlog_debug("local es %s bypass %s", es
->esi_str
,
1853 bypass
? "set" : "clear");
1855 new_active
= bgp_evpn_local_es_is_active(es
);
1856 if (old_active
!= new_active
) {
1858 bgp_evpn_local_es_activate(bgp
, es
, true, true);
1860 bgp_evpn_local_es_deactivate(bgp
, es
);
1864 static void bgp_evpn_local_es_do_del(struct bgp
*bgp
, struct bgp_evpn_es
*es
)
1866 struct bgp_evpn_es_evi
*es_evi
;
1867 struct listnode
*evi_node
, *evi_next_node
;
1869 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1870 zlog_debug("del local es %s", es
->esi_str
);
1872 /* Delete all local EVPN ES routes from ESI table
1873 * and schedule for processing (to withdraw from peers))
1875 bgp_evpn_es_route_del_all(bgp
, es
);
1877 /* release all local ES EVIs associated with the ES */
1878 for (ALL_LIST_ELEMENTS(es
->es_evi_list
, evi_node
,
1879 evi_next_node
, es_evi
)) {
1880 bgp_evpn_local_es_evi_do_del(es_evi
);
1883 /* Clear local info associated with the ES and free it up if there is
1884 * no remote reference
1886 bgp_evpn_es_local_info_clear(es
);
1889 bool bgp_evpn_is_esi_local(esi_t
*esi
)
1891 struct bgp_evpn_es
*es
= NULL
;
1893 /* Lookup ESI hash - should exist. */
1894 es
= bgp_evpn_es_find(esi
);
1895 return es
? !!(es
->flags
& BGP_EVPNES_LOCAL
) : false;
1898 int bgp_evpn_local_es_del(struct bgp
*bgp
, esi_t
*esi
)
1900 struct bgp_evpn_es
*es
= NULL
;
1902 /* Lookup ESI hash - should exist. */
1903 es
= bgp_evpn_es_find(esi
);
1905 flog_warn(EC_BGP_EVPN_ESI
,
1906 "%u: ES %s missing at local ES DEL",
1907 bgp
->vrf_id
, es
->esi_str
);
1911 bgp_evpn_local_es_do_del(bgp
, es
);
1915 /* Handle device to ES id association. Results in the creation of a local
1918 int bgp_evpn_local_es_add(struct bgp
*bgp
, esi_t
*esi
,
1919 struct in_addr originator_ip
, bool oper_up
,
1920 uint16_t df_pref
, bool bypass
)
1922 char buf
[ESI_STR_LEN
];
1923 struct bgp_evpn_es
*es
;
1925 bool regen_esr
= false;
1927 /* create the new es */
1928 es
= bgp_evpn_es_find(esi
);
1930 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_LOCAL
))
1933 es
= bgp_evpn_es_new(bgp
, esi
);
1935 flog_err(EC_BGP_ES_CREATE
,
1936 "%u: Failed to allocate ES entry for ESI %s - at Local ES Add",
1937 bgp
->vrf_id
, esi_to_str(esi
, buf
, sizeof(buf
)));
1942 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1943 zlog_debug("add local es %s orig-ip %pI4 df_pref %u %s",
1944 es
->esi_str
, &originator_ip
, df_pref
,
1945 bypass
? "bypass" : "");
1947 es
->originator_ip
= originator_ip
;
1948 if (df_pref
!= es
->df_pref
) {
1949 es
->df_pref
= df_pref
;
1952 bgp_evpn_es_local_info_set(bgp
, es
);
1954 /* import all remote Type-4 routes in the ES table */
1956 bgp_evpn_type4_remote_routes_import(bgp
, es
,
1957 true /* install */);
1959 /* create and advertise EAD-EVI routes for the ES -
1960 * XXX - till an ES-EVI reference is created there is really nothing to
1963 if (bgp_mh_info
->ead_evi_adv_for_down_links
)
1964 bgp_evpn_local_type1_evi_route_add(bgp
, es
);
1966 bgp_evpn_local_es_bypass_update(bgp
, es
, bypass
);
1968 /* If the ES link is operationally up generate EAD-ES. EAD-EVI
1969 * can be generated even if the link is inactive.
1972 bgp_evpn_local_es_up(bgp
, es
, regen_esr
);
1974 bgp_evpn_local_es_down(bgp
, es
);
1979 static char *bgp_evpn_es_vteps_str(char *vtep_str
, struct bgp_evpn_es
*es
,
1980 uint8_t vtep_str_size
)
1982 char vtep_flag_str
[BGP_EVPN_FLAG_STR_SZ
];
1983 struct listnode
*node
;
1984 struct bgp_evpn_es_vtep
*es_vtep
;
1986 char ip_buf
[INET6_ADDRSTRLEN
];
1989 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
1990 vtep_flag_str
[0] = '\0';
1992 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ESR
)
1993 strlcat(vtep_flag_str
, "E", sizeof(vtep_flag_str
));
1994 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ACTIVE
)
1995 strlcat(vtep_flag_str
, "A", sizeof(vtep_flag_str
));
1997 if (!strlen(vtep_flag_str
))
1998 strlcat(vtep_flag_str
, "-", sizeof(vtep_flag_str
));
2002 strlcat(vtep_str
, ",", vtep_str_size
);
2004 inet_ntop(AF_INET
, &es_vtep
->vtep_ip
, ip_buf
,
2007 strlcat(vtep_str
, "(", vtep_str_size
);
2008 strlcat(vtep_str
, vtep_flag_str
, vtep_str_size
);
2009 strlcat(vtep_str
, ")", vtep_str_size
);
2015 static void bgp_evpn_es_json_vtep_fill(json_object
*json_vteps
,
2016 struct bgp_evpn_es_vtep
*es_vtep
)
2018 json_object
*json_vtep_entry
;
2019 json_object
*json_flags
;
2020 char ip_buf
[INET6_ADDRSTRLEN
];
2022 json_vtep_entry
= json_object_new_object();
2024 json_object_string_add(
2025 json_vtep_entry
, "vtep_ip",
2026 inet_ntop(AF_INET
, &es_vtep
->vtep_ip
, ip_buf
, sizeof(ip_buf
)));
2027 if (es_vtep
->flags
& (BGP_EVPNES_VTEP_ESR
|
2028 BGP_EVPNES_VTEP_ACTIVE
)) {
2029 json_flags
= json_object_new_array();
2030 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ESR
)
2031 json_array_string_add(json_flags
, "esr");
2032 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ACTIVE
)
2033 json_array_string_add(json_flags
, "active");
2034 json_object_object_add(json_vtep_entry
, "flags", json_flags
);
2035 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ESR
) {
2036 json_object_int_add(json_vtep_entry
, "dfPreference",
2038 json_object_int_add(json_vtep_entry
, "dfAlgorithm",
2043 json_object_array_add(json_vteps
,
2047 static void bgp_evpn_es_vteps_show_detail(struct vty
*vty
,
2048 struct bgp_evpn_es
*es
)
2050 char vtep_flag_str
[BGP_EVPN_FLAG_STR_SZ
];
2051 struct listnode
*node
;
2052 struct bgp_evpn_es_vtep
*es_vtep
;
2053 char alg_buf
[EVPN_DF_ALG_STR_LEN
];
2055 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
2056 vtep_flag_str
[0] = '\0';
2057 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ESR
)
2058 strlcat(vtep_flag_str
, "E", sizeof(vtep_flag_str
));
2059 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ACTIVE
)
2060 strlcat(vtep_flag_str
, "A", sizeof(vtep_flag_str
));
2062 if (!strlen(vtep_flag_str
))
2063 strlcat(vtep_flag_str
, "-", sizeof(vtep_flag_str
));
2065 vty_out(vty
, " %pI4 flags: %s", &es_vtep
->vtep_ip
,
2068 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ESR
)
2069 vty_out(vty
, " df_alg: %s df_pref: %u\n",
2070 evpn_es_df_alg2str(es_vtep
->df_alg
, alg_buf
,
2078 static void bgp_evpn_es_show_entry(struct vty
*vty
,
2079 struct bgp_evpn_es
*es
, json_object
*json
)
2081 char buf1
[RD_ADDRSTRLEN
];
2082 struct listnode
*node
;
2083 struct bgp_evpn_es_vtep
*es_vtep
;
2086 json_object
*json_vteps
;
2087 json_object
*json_types
;
2089 json_object_string_add(json
, "esi", es
->esi_str
);
2090 json_object_string_add(json
, "rd",
2091 prefix_rd2str(&es
->prd
, buf1
,
2094 if (es
->flags
& (BGP_EVPNES_LOCAL
| BGP_EVPNES_REMOTE
)) {
2095 json_types
= json_object_new_array();
2096 if (es
->flags
& BGP_EVPNES_LOCAL
)
2097 json_array_string_add(json_types
, "local");
2098 if (es
->flags
& BGP_EVPNES_REMOTE
)
2099 json_array_string_add(json_types
, "remote");
2100 json_object_object_add(json
, "type", json_types
);
2103 if (listcount(es
->es_vtep_list
)) {
2104 json_vteps
= json_object_new_array();
2105 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
,
2107 bgp_evpn_es_json_vtep_fill(json_vteps
, es_vtep
);
2109 json_object_object_add(json
, "vteps", json_vteps
);
2111 json_object_int_add(json
, "vniCount",
2112 listcount(es
->es_evi_list
));
2115 char vtep_str
[ES_VTEP_LIST_STR_SZ
+ BGP_EVPN_VTEPS_FLAG_STR_SZ
];
2118 if (es
->flags
& BGP_EVPNES_BYPASS
)
2119 strlcat(type_str
, "B", sizeof(type_str
));
2120 if (es
->flags
& BGP_EVPNES_LOCAL
)
2121 strlcat(type_str
, "L", sizeof(type_str
));
2122 if (es
->flags
& BGP_EVPNES_REMOTE
)
2123 strlcat(type_str
, "R", sizeof(type_str
));
2124 if (es
->inconsistencies
)
2125 strlcat(type_str
, "I", sizeof(type_str
));
2127 bgp_evpn_es_vteps_str(vtep_str
, es
, sizeof(vtep_str
));
2129 if (es
->flags
& BGP_EVPNES_LOCAL
)
2130 prefix_rd2str(&es
->prd
, buf1
, sizeof(buf1
));
2132 strlcpy(buf1
, "-", sizeof(buf1
));
2134 vty_out(vty
, "%-30s %-5s %-21s %-8d %s\n",
2135 es
->esi_str
, type_str
, buf1
,
2136 listcount(es
->es_evi_list
), vtep_str
);
2140 static void bgp_evpn_es_show_entry_detail(struct vty
*vty
,
2141 struct bgp_evpn_es
*es
, json_object
*json
)
2143 char ip_buf
[INET6_ADDRSTRLEN
];
2146 json_object
*json_flags
;
2147 json_object
*json_incons
;
2148 json_object
*json_vteps
;
2149 struct listnode
*node
;
2150 struct bgp_evpn_es_vtep
*es_vtep
;
2152 /* Add the "brief" info first */
2153 bgp_evpn_es_show_entry(vty
, es
, json
);
2155 & (BGP_EVPNES_OPER_UP
| BGP_EVPNES_ADV_EVI
2156 | BGP_EVPNES_BYPASS
)) {
2157 json_flags
= json_object_new_array();
2158 if (es
->flags
& BGP_EVPNES_OPER_UP
)
2159 json_array_string_add(json_flags
, "up");
2160 if (es
->flags
& BGP_EVPNES_ADV_EVI
)
2161 json_array_string_add(json_flags
,
2163 if (es
->flags
& BGP_EVPNES_BYPASS
)
2164 json_array_string_add(json_flags
, "bypass");
2165 json_object_object_add(json
, "flags", json_flags
);
2167 json_object_string_add(json
, "originator_ip",
2168 inet_ntop(AF_INET
, &es
->originator_ip
,
2169 ip_buf
, sizeof(ip_buf
)));
2170 json_object_int_add(json
, "remoteVniCount",
2171 es
->remote_es_evi_cnt
);
2172 json_object_int_add(json
, "vrfCount",
2173 listcount(es
->es_vrf_list
));
2174 json_object_int_add(json
, "macipPathCount",
2175 listcount(es
->macip_evi_path_list
));
2176 json_object_int_add(json
, "macipGlobalPathCount",
2177 listcount(es
->macip_global_path_list
));
2178 json_object_int_add(json
, "inconsistentVniVtepCount",
2179 es
->incons_evi_vtep_cnt
);
2180 if (listcount(es
->es_vtep_list
)) {
2181 json_vteps
= json_object_new_array();
2182 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
,
2184 bgp_evpn_es_json_vtep_fill(json_vteps
, es_vtep
);
2186 json_object_object_add(json
, "vteps", json_vteps
);
2188 if (es
->inconsistencies
) {
2189 json_incons
= json_object_new_array();
2190 if (es
->inconsistencies
& BGP_EVPNES_INCONS_VTEP_LIST
)
2191 json_array_string_add(json_incons
,
2192 "vni-vtep-mismatch");
2193 json_object_object_add(json
, "inconsistencies",
2197 char incons_str
[BGP_EVPNES_INCONS_STR_SZ
];
2199 char buf1
[RD_ADDRSTRLEN
];
2202 if (es
->flags
& BGP_EVPNES_LOCAL
)
2203 strlcat(type_str
, "L", sizeof(type_str
));
2204 if (es
->flags
& BGP_EVPNES_REMOTE
)
2205 strlcat(type_str
, "R", sizeof(type_str
));
2207 if (es
->flags
& BGP_EVPNES_LOCAL
)
2208 prefix_rd2str(&es
->prd
, buf1
, sizeof(buf1
));
2210 strlcpy(buf1
, "-", sizeof(buf1
));
2212 vty_out(vty
, "ESI: %s\n", es
->esi_str
);
2213 vty_out(vty
, " Type: %s\n", type_str
);
2214 vty_out(vty
, " RD: %s\n", buf1
);
2215 vty_out(vty
, " Originator-IP: %pI4\n", &es
->originator_ip
);
2216 if (es
->flags
& BGP_EVPNES_LOCAL
)
2217 vty_out(vty
, " Local ES DF preference: %u\n",
2219 if (es
->flags
& BGP_EVPNES_BYPASS
)
2220 vty_out(vty
, " LACP bypass: on\n");
2221 vty_out(vty
, " VNI Count: %d\n", listcount(es
->es_evi_list
));
2222 vty_out(vty
, " Remote VNI Count: %d\n",
2223 es
->remote_es_evi_cnt
);
2224 vty_out(vty
, " VRF Count: %d\n", listcount(es
->es_vrf_list
));
2225 vty_out(vty
, " MACIP EVI Path Count: %d\n",
2226 listcount(es
->macip_evi_path_list
));
2227 vty_out(vty
, " MACIP Global Path Count: %d\n",
2228 listcount(es
->macip_global_path_list
));
2229 vty_out(vty
, " Inconsistent VNI VTEP Count: %d\n",
2230 es
->incons_evi_vtep_cnt
);
2231 if (es
->inconsistencies
) {
2232 incons_str
[0] = '\0';
2233 if (es
->inconsistencies
& BGP_EVPNES_INCONS_VTEP_LIST
)
2234 strlcat(incons_str
, "vni-vtep-mismatch",
2235 sizeof(incons_str
));
2237 strlcpy(incons_str
, "-", sizeof(incons_str
));
2239 vty_out(vty
, " Inconsistencies: %s\n",
2241 if (listcount(es
->es_vtep_list
)) {
2242 vty_out(vty
, " VTEPs:\n");
2243 bgp_evpn_es_vteps_show_detail(vty
, es
);
2249 /* Display all ESs */
2250 void bgp_evpn_es_show(struct vty
*vty
, bool uj
, bool detail
)
2252 struct bgp_evpn_es
*es
;
2253 json_object
*json_array
= NULL
;
2254 json_object
*json
= NULL
;
2257 /* create an array of ESs */
2258 json_array
= json_object_new_array();
2262 "ES Flags: B - bypass, L local, R remote, I inconsistent\n");
2264 "VTEP Flags: E ESR/Type-4, A active nexthop\n");
2266 "%-30s %-5s %-21s %-8s %s\n",
2267 "ESI", "Flags", "RD", "#VNIs", "VTEPs");
2271 RB_FOREACH(es
, bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
) {
2273 /* create a separate json object for each ES */
2274 json
= json_object_new_object();
2276 bgp_evpn_es_show_entry_detail(vty
, es
, json
);
2278 bgp_evpn_es_show_entry(vty
, es
, json
);
2279 /* add ES to the json array */
2281 json_object_array_add(json_array
, json
);
2284 /* print the array of json-ESs */
2286 vty_out(vty
, "%s\n", json_object_to_json_string_ext(
2287 json_array
, JSON_C_TO_STRING_PRETTY
));
2288 json_object_free(json_array
);
2292 /* Display specific ES */
2293 void bgp_evpn_es_show_esi(struct vty
*vty
, esi_t
*esi
, bool uj
)
2295 struct bgp_evpn_es
*es
;
2296 json_object
*json
= NULL
;
2299 json
= json_object_new_object();
2301 es
= bgp_evpn_es_find(esi
);
2303 bgp_evpn_es_show_entry_detail(vty
, es
, json
);
2306 vty_out(vty
, "ESI not found\n");
2310 vty_out(vty
, "%s\n", json_object_to_json_string_ext(
2311 json
, JSON_C_TO_STRING_PRETTY
));
2312 json_object_free(json
);
2316 /*****************************************************************************/
2317 /* Ethernet Segment to VRF association -
2318 * 1. Each ES-EVI entry is associated with a tenant VRF. This associaton
2319 * triggers the creation of an ES-VRF entry.
2320 * 2. The ES-VRF entry is maintained for the purpose of L3-NHG creation
2321 * 3. Type-2/MAC-IP routes are imported into a tenant VRF and programmed as
2322 * a /32 or host route entry in the dataplane. If the destination of
2323 * the host route is a remote-ES the route is programmed with the
2324 * corresponding (keyed in by {vrf,ES-id}) L3-NHG.
2325 * 4. The reason for this indirection (route->L3-NHG, L3-NHG->list-of-VTEPs)
2326 * is to avoid route updates to the dplane when a remote-ES link flaps i.e.
2327 * instead of updating all the dependent routes the NHG's contents are updated.
2328 * This reduces the amount of datplane updates (nhg updates vs. route updates)
2329 * allowing for a faster failover.
2331 * XXX - can the L3 SVI index change without change in vpn->bgp_vrf
2332 * association? If yes we need to handle that by updating all the L3 NHGs
2335 /******************************** L3 NHG management *************************/
2336 static void bgp_evpn_l3nhg_zebra_add_v4_or_v6(struct bgp_evpn_es_vrf
*es_vrf
,
2339 uint32_t nhg_id
= v4_nhg
? es_vrf
->nhg_id
: es_vrf
->v6_nhg_id
;
2340 struct bgp_evpn_es
*es
= es_vrf
->es
;
2341 struct listnode
*node
;
2342 struct bgp_evpn_es_vtep
*es_vtep
;
2344 struct zapi_nexthop
*api_nh
;
2345 struct zapi_nhg api_nhg
= {};
2347 /* Skip installation of L3-NHG if host routes used */
2351 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2352 zlog_debug("es %s vrf %u %s nhg %u to zebra", es
->esi_str
,
2353 es_vrf
->bgp_vrf
->vrf_id
,
2354 v4_nhg
? "v4_nhg" : "v6_nhg", nhg_id
);
2356 /* only the gateway ip changes for each NH. rest of the params
2359 memset(&nh
, 0, sizeof(nh
));
2360 nh
.vrf_id
= es_vrf
->bgp_vrf
->vrf_id
;
2361 nh
.flags
= NEXTHOP_FLAG_ONLINK
;
2362 nh
.ifindex
= es_vrf
->bgp_vrf
->l3vni_svi_ifindex
;
2365 v4_nhg
? NEXTHOP_TYPE_IPV4_IFINDEX
: NEXTHOP_TYPE_IPV6_IFINDEX
;
2367 api_nhg
.id
= nhg_id
;
2368 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
2369 if (!CHECK_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
))
2372 /* overwrite the gw */
2374 nh
.gate
.ipv4
= es_vtep
->vtep_ip
;
2376 ipv4_to_ipv4_mapped_ipv6(&nh
.gate
.ipv6
,
2379 /* convert to zapi format */
2380 api_nh
= &api_nhg
.nexthops
[api_nhg
.nexthop_num
];
2381 zapi_nexthop_from_nexthop(api_nh
, &nh
);
2383 ++api_nhg
.nexthop_num
;
2384 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2385 zlog_debug("nhg %u vtep %pI4 l3-svi %d", api_nhg
.id
,
2387 es_vrf
->bgp_vrf
->l3vni_svi_ifindex
);
2390 if (!api_nhg
.nexthop_num
)
2393 if (api_nhg
.nexthop_num
> MULTIPATH_NUM
)
2396 zclient_nhg_send(zclient
, ZEBRA_NHG_ADD
, &api_nhg
);
2399 static bool bgp_evpn_l3nhg_zebra_ok(struct bgp_evpn_es_vrf
*es_vrf
)
2401 if (!bgp_mh_info
->host_routes_use_l3nhg
&& !bgp_mh_info
->install_l3nhg
)
2405 if (!zclient
|| zclient
->sock
< 0)
2411 static void bgp_evpn_l3nhg_zebra_add(struct bgp_evpn_es_vrf
*es_vrf
)
2413 if (!bgp_evpn_l3nhg_zebra_ok(es_vrf
))
2416 bgp_evpn_l3nhg_zebra_add_v4_or_v6(es_vrf
, true /*v4_nhg*/);
2417 bgp_evpn_l3nhg_zebra_add_v4_or_v6(es_vrf
, false /*v4_nhg*/);
2420 static void bgp_evpn_l3nhg_zebra_del_v4_or_v6(struct bgp_evpn_es_vrf
*es_vrf
,
2423 struct zapi_nhg api_nhg
= {};
2425 api_nhg
.id
= v4_nhg
? es_vrf
->nhg_id
: es_vrf
->v6_nhg_id
;
2427 /* Skip installation of L3-NHG if host routes used */
2431 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2432 zlog_debug("es %s vrf %u %s nhg %u to zebra",
2433 es_vrf
->es
->esi_str
, es_vrf
->bgp_vrf
->vrf_id
,
2434 v4_nhg
? "v4_nhg" : "v6_nhg", api_nhg
.id
);
2436 zclient_nhg_send(zclient
, ZEBRA_NHG_DEL
, &api_nhg
);
2439 static void bgp_evpn_l3nhg_zebra_del(struct bgp_evpn_es_vrf
*es_vrf
)
2441 if (!bgp_evpn_l3nhg_zebra_ok(es_vrf
))
2444 bgp_evpn_l3nhg_zebra_del_v4_or_v6(es_vrf
, true /*v4_nhg*/);
2445 bgp_evpn_l3nhg_zebra_del_v4_or_v6(es_vrf
, false /*v4_nhg*/);
2448 static void bgp_evpn_l3nhg_deactivate(struct bgp_evpn_es_vrf
*es_vrf
)
2450 if (!(es_vrf
->flags
& BGP_EVPNES_VRF_NHG_ACTIVE
))
2453 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2454 zlog_debug("es %s vrf %u nhg %u de-activate",
2455 es_vrf
->es
->esi_str
, es_vrf
->bgp_vrf
->vrf_id
,
2457 bgp_evpn_l3nhg_zebra_del(es_vrf
);
2458 es_vrf
->flags
&= ~BGP_EVPNES_VRF_NHG_ACTIVE
;
2459 /* MAC-IPs can now be installed via the L3NHG */
2460 bgp_evpn_es_path_update_on_es_vrf_chg(es_vrf
, "l3nhg-deactivate");
2463 static void bgp_evpn_l3nhg_activate(struct bgp_evpn_es_vrf
*es_vrf
, bool update
)
2465 if (!bgp_evpn_es_get_active_vtep_cnt(es_vrf
->es
)) {
2466 bgp_evpn_l3nhg_deactivate(es_vrf
);
2470 if (es_vrf
->flags
& BGP_EVPNES_VRF_NHG_ACTIVE
) {
2474 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2475 zlog_debug("es %s vrf %u nhg %u activate",
2476 es_vrf
->es
->esi_str
, es_vrf
->bgp_vrf
->vrf_id
,
2478 es_vrf
->flags
|= BGP_EVPNES_VRF_NHG_ACTIVE
;
2479 /* MAC-IPs can now be installed via the L3NHG */
2480 bgp_evpn_es_path_update_on_es_vrf_chg(es_vrf
, "l3nhg_activate");
2483 bgp_evpn_l3nhg_zebra_add(es_vrf
);
2486 /* when a VTEP is activated or de-activated against an ES associated
2487 * VRFs' NHG needs to be updated
2489 static void bgp_evpn_l3nhg_update_on_vtep_chg(struct bgp_evpn_es
*es
)
2491 struct bgp_evpn_es_vrf
*es_vrf
;
2492 struct listnode
*es_vrf_node
;
2494 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2495 zlog_debug("es %s nhg update on vtep chg", es
->esi_str
);
2497 for (ALL_LIST_ELEMENTS_RO(es
->es_vrf_list
, es_vrf_node
, es_vrf
))
2498 bgp_evpn_l3nhg_activate(es_vrf
, true /* update */);
2501 /* compare ES-IDs for the ES-VRF RB tree maintained per-VRF */
2502 static int bgp_es_vrf_rb_cmp(const struct bgp_evpn_es_vrf
*es_vrf1
,
2503 const struct bgp_evpn_es_vrf
*es_vrf2
)
2505 return memcmp(&es_vrf1
->es
->esi
, &es_vrf2
->es
->esi
, ESI_BYTES
);
2507 RB_GENERATE(bgp_es_vrf_rb_head
, bgp_evpn_es_vrf
, rb_node
, bgp_es_vrf_rb_cmp
);
2509 /* Initialize the ES tables maintained per-tenant vrf */
2510 void bgp_evpn_vrf_es_init(struct bgp
*bgp_vrf
)
2512 /* Initialize the ES-VRF RB tree */
2513 RB_INIT(bgp_es_vrf_rb_head
, &bgp_vrf
->es_vrf_rb_tree
);
2516 /* find the ES-VRF in the per-VRF RB tree */
2517 static struct bgp_evpn_es_vrf
*bgp_evpn_es_vrf_find(struct bgp_evpn_es
*es
,
2518 struct bgp
*bgp_vrf
)
2520 struct bgp_evpn_es_vrf es_vrf
;
2524 return RB_FIND(bgp_es_vrf_rb_head
, &bgp_vrf
->es_vrf_rb_tree
, &es_vrf
);
2527 /* allocate a new ES-VRF and setup L3NHG for it */
2528 static struct bgp_evpn_es_vrf
*bgp_evpn_es_vrf_create(struct bgp_evpn_es
*es
,
2529 struct bgp
*bgp_vrf
)
2531 struct bgp_evpn_es_vrf
*es_vrf
;
2533 es_vrf
= XCALLOC(MTYPE_BGP_EVPN_ES_VRF
, sizeof(*es_vrf
));
2536 es_vrf
->bgp_vrf
= bgp_vrf
;
2538 /* insert into the VRF-ESI rb tree */
2539 if (RB_INSERT(bgp_es_vrf_rb_head
, &bgp_vrf
->es_vrf_rb_tree
, es_vrf
)) {
2540 XFREE(MTYPE_BGP_EVPN_ES_VRF
, es_vrf
);
2544 /* add to the ES's VRF list */
2545 listnode_init(&es_vrf
->es_listnode
, es_vrf
);
2546 listnode_add(es
->es_vrf_list
, &es_vrf
->es_listnode
);
2548 /* setup the L3 NHG id for the ES */
2549 es_vrf
->nhg_id
= bgp_l3nhg_id_alloc();
2550 es_vrf
->v6_nhg_id
= bgp_l3nhg_id_alloc();
2552 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2553 zlog_debug("es %s vrf %u nhg %u v6_nhg %d create", es
->esi_str
,
2554 bgp_vrf
->vrf_id
, es_vrf
->nhg_id
, es_vrf
->v6_nhg_id
);
2555 bgp_evpn_l3nhg_activate(es_vrf
, false /* update */);
2557 /* update paths in the VRF that may already be associated with
2558 * this destination ES
2560 bgp_evpn_es_path_update_on_es_vrf_chg(es_vrf
, "es-vrf-create");
2565 /* remove the L3-NHG associated with the ES-VRF and free it */
2566 static void bgp_evpn_es_vrf_delete(struct bgp_evpn_es_vrf
*es_vrf
)
2568 struct bgp_evpn_es
*es
= es_vrf
->es
;
2569 struct bgp
*bgp_vrf
= es_vrf
->bgp_vrf
;
2571 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2572 zlog_debug("es %s vrf %u nhg %u delete", es
->esi_str
,
2573 bgp_vrf
->vrf_id
, es_vrf
->nhg_id
);
2575 /* Remove the NHG resources */
2576 bgp_evpn_l3nhg_deactivate(es_vrf
);
2578 bgp_l3nhg_id_free(es_vrf
->nhg_id
);
2580 if (es_vrf
->v6_nhg_id
)
2581 bgp_l3nhg_id_free(es_vrf
->v6_nhg_id
);
2582 es_vrf
->v6_nhg_id
= 0;
2584 /* remove from the ES's VRF list */
2585 list_delete_node(es
->es_vrf_list
, &es_vrf
->es_listnode
);
2587 /* remove from the VRF-ESI rb tree */
2588 RB_REMOVE(bgp_es_vrf_rb_head
, &bgp_vrf
->es_vrf_rb_tree
, es_vrf
);
2590 /* update paths in the VRF that may already be associated with
2591 * this destination ES
2593 bgp_evpn_es_path_update_on_es_vrf_chg(es_vrf
, "es-vrf-delete");
2595 XFREE(MTYPE_BGP_EVPN_ES_VRF
, es_vrf
);
2598 /* deref and delete if there are no references */
2599 void bgp_evpn_es_vrf_deref(struct bgp_evpn_es_evi
*es_evi
)
2601 struct bgp_evpn_es_vrf
*es_vrf
= es_evi
->es_vrf
;
2606 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2607 zlog_debug("es-evi %s vni %u vrf %u de-ref",
2608 es_evi
->es
->esi_str
, es_evi
->vpn
->vni
,
2609 es_vrf
->bgp_vrf
->vrf_id
);
2611 es_evi
->es_vrf
= NULL
;
2612 if (es_vrf
->ref_cnt
)
2615 if (!es_vrf
->ref_cnt
)
2616 bgp_evpn_es_vrf_delete(es_vrf
);
2619 /* find or create and reference */
2620 void bgp_evpn_es_vrf_ref(struct bgp_evpn_es_evi
*es_evi
, struct bgp
*bgp_vrf
)
2622 struct bgp_evpn_es
*es
= es_evi
->es
;
2623 struct bgp_evpn_es_vrf
*es_vrf
= es_evi
->es_vrf
;
2624 struct bgp
*old_bgp_vrf
= NULL
;
2627 old_bgp_vrf
= es_vrf
->bgp_vrf
;
2629 if (old_bgp_vrf
== bgp_vrf
)
2632 /* deref the old ES-VRF */
2633 bgp_evpn_es_vrf_deref(es_evi
);
2638 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2639 zlog_debug("es-evi %s vni %u vrf %u ref", es_evi
->es
->esi_str
,
2640 es_evi
->vpn
->vni
, bgp_vrf
->vrf_id
);
2642 /* find-create the new ES-VRF */
2643 es_vrf
= bgp_evpn_es_vrf_find(es
, bgp_vrf
);
2645 es_vrf
= bgp_evpn_es_vrf_create(es
, bgp_vrf
);
2649 es_evi
->es_vrf
= es_vrf
;
2653 /* When the L2-VNI is associated with a L3-VNI/VRF update all the
2654 * associated ES-EVI entries
2656 void bgp_evpn_es_evi_vrf_deref(struct bgpevpn
*vpn
)
2658 struct bgp_evpn_es_evi
*es_evi
;
2660 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2661 zlog_debug("es-vrf de-ref for vni %u", vpn
->vni
);
2663 RB_FOREACH (es_evi
, bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
)
2664 bgp_evpn_es_vrf_deref(es_evi
);
2666 void bgp_evpn_es_evi_vrf_ref(struct bgpevpn
*vpn
)
2668 struct bgp_evpn_es_evi
*es_evi
;
2670 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2671 zlog_debug("es-vrf ref for vni %u", vpn
->vni
);
2673 RB_FOREACH (es_evi
, bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
)
2674 bgp_evpn_es_vrf_ref(es_evi
, vpn
->bgp_vrf
);
2677 /* 1. If ES-VRF is not present install the host route with the exploded/flat
2679 * 2. If ES-VRF is present -
2680 * - if L3NHG has not been activated for the ES-VRF (this could be because
2681 * all the PEs attached to the VRF are down) do not install the route
2683 * - if L3NHG has been activated install the route via that L3NHG
2685 void bgp_evpn_es_vrf_use_nhg(struct bgp
*bgp_vrf
, esi_t
*esi
, bool *use_l3nhg
,
2686 bool *is_l3nhg_active
,
2687 struct bgp_evpn_es_vrf
**es_vrf_p
)
2689 struct bgp_evpn_es
*es
;
2690 struct bgp_evpn_es_vrf
*es_vrf
;
2692 if (!bgp_mh_info
->host_routes_use_l3nhg
)
2695 es
= bgp_evpn_es_find(esi
);
2699 es_vrf
= bgp_evpn_es_vrf_find(es
, bgp_vrf
);
2704 if (es_vrf
->flags
& BGP_EVPNES_VRF_NHG_ACTIVE
)
2705 *is_l3nhg_active
= true;
2710 /* returns false if legacy-exploded mp needs to be used for route install */
2711 bool bgp_evpn_path_es_use_nhg(struct bgp
*bgp_vrf
, struct bgp_path_info
*pi
,
2715 struct bgp_evpn_es_vrf
*es_vrf
= NULL
;
2716 struct bgp_path_info
*parent_pi
;
2717 struct bgp_node
*rn
;
2718 struct prefix_evpn
*evp
;
2719 struct bgp_path_info
*mpinfo
;
2720 bool use_l3nhg
= false;
2721 bool is_l3nhg_active
= false;
2725 parent_pi
= get_route_parent_evpn(pi
);
2729 rn
= parent_pi
->net
;
2733 evp
= (struct prefix_evpn
*)&rn
->p
;
2734 if (evp
->prefix
.route_type
!= BGP_EVPN_MAC_IP_ROUTE
)
2737 /* non-es path, use legacy-exploded multipath */
2738 esi
= bgp_evpn_attr_get_esi(parent_pi
->attr
);
2739 if (!memcmp(esi
, zero_esi
, sizeof(*esi
)))
2742 bgp_evpn_es_vrf_use_nhg(bgp_vrf
, esi
, &use_l3nhg
, &is_l3nhg_active
,
2745 /* L3NHG support is disabled, use legacy-exploded multipath */
2749 /* if the NHG has not been installed we cannot install the route yet,
2750 * return a 0-NHG to indicate that
2752 if (!is_l3nhg_active
)
2755 /* this needs to be set the v6NHG if v6route */
2756 if (is_evpn_prefix_ipaddr_v6(evp
))
2757 *nhg_p
= es_vrf
->v6_nhg_id
;
2759 *nhg_p
= es_vrf
->nhg_id
;
2761 for (mpinfo
= bgp_path_info_mpath_next(pi
); mpinfo
;
2762 mpinfo
= bgp_path_info_mpath_next(mpinfo
)) {
2763 /* if any of the paths have a different ESI we can't use
2764 * the NHG associated with the ES. fallback to legacy-exploded
2767 if (memcmp(esi
, bgp_evpn_attr_get_esi(mpinfo
->attr
),
2775 static void bgp_evpn_es_vrf_show_entry(struct vty
*vty
,
2776 struct bgp_evpn_es_vrf
*es_vrf
,
2779 struct bgp_evpn_es
*es
= es_vrf
->es
;
2780 struct bgp
*bgp_vrf
= es_vrf
->bgp_vrf
;
2783 json_object
*json_types
;
2785 json_object_string_add(json
, "esi", es
->esi_str
);
2786 json_object_string_add(json
, "vrf", bgp_vrf
->name
);
2788 if (es_vrf
->flags
& (BGP_EVPNES_VRF_NHG_ACTIVE
)) {
2789 json_types
= json_object_new_array();
2790 if (es_vrf
->flags
& BGP_EVPNES_VRF_NHG_ACTIVE
)
2791 json_array_string_add(json_types
, "active");
2792 json_object_object_add(json
, "flags", json_types
);
2795 json_object_int_add(json
, "ipv4NHG", es_vrf
->nhg_id
);
2796 json_object_int_add(json
, "ipv6NHG", es_vrf
->v6_nhg_id
);
2797 json_object_int_add(json
, "refCount", es_vrf
->ref_cnt
);
2801 flags_str
[0] = '\0';
2802 if (es_vrf
->flags
& BGP_EVPNES_VRF_NHG_ACTIVE
)
2803 strlcat(flags_str
, "A", sizeof(flags_str
));
2805 vty_out(vty
, "%-30s %-15s %-5s %-8u %-8u %u\n", es
->esi_str
,
2806 bgp_vrf
->name
, flags_str
, es_vrf
->nhg_id
,
2807 es_vrf
->v6_nhg_id
, es_vrf
->ref_cnt
);
2811 static void bgp_evpn_es_vrf_show_es(struct vty
*vty
, json_object
*json_array
,
2812 struct bgp_evpn_es
*es
)
2814 json_object
*json
= NULL
;
2815 struct listnode
*es_vrf_node
;
2816 struct bgp_evpn_es_vrf
*es_vrf
;
2818 for (ALL_LIST_ELEMENTS_RO(es
->es_vrf_list
, es_vrf_node
, es_vrf
)) {
2819 /* create a separate json object for each ES-VRF */
2821 json
= json_object_new_object();
2822 bgp_evpn_es_vrf_show_entry(vty
, es_vrf
, json
);
2823 /* add ES-VRF to the json array */
2825 json_object_array_add(json_array
, json
);
2829 /* Display all ES VRFs */
2830 void bgp_evpn_es_vrf_show(struct vty
*vty
, bool uj
, struct bgp_evpn_es
*es
)
2832 json_object
*json_array
= NULL
;
2835 /* create an array of ESs */
2836 json_array
= json_object_new_array();
2838 vty_out(vty
, "ES-VRF Flags: A Active\n");
2839 vty_out(vty
, "%-30s %-15s %-5s %-8s %-8s %s\n", "ESI", "VRF",
2840 "Flags", "IPv4-NHG", "IPv6-NHG", "Ref");
2844 bgp_evpn_es_vrf_show_es(vty
, json_array
, es
);
2846 RB_FOREACH (es
, bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
)
2847 bgp_evpn_es_vrf_show_es(vty
, json_array
, es
);
2850 /* print the array of json-ESs */
2852 vty_out(vty
, "%s\n",
2853 json_object_to_json_string_ext(
2854 json_array
, JSON_C_TO_STRING_PRETTY
));
2855 json_object_free(json_array
);
2859 /* Display specific ES VRF */
2860 void bgp_evpn_es_vrf_show_esi(struct vty
*vty
, esi_t
*esi
, bool uj
)
2862 struct bgp_evpn_es
*es
;
2864 es
= bgp_evpn_es_find(esi
);
2866 bgp_evpn_es_vrf_show(vty
, uj
, es
);
2869 vty_out(vty
, "ESI not found\n");
2873 /*****************************************************************************/
2874 /* Ethernet Segment to EVI association -
2875 * 1. The ES-EVI entry is maintained as a RB tree per L2-VNI
2876 * (bgpevpn->es_evi_rb_tree).
2877 * 2. Each local ES-EVI entry is rxed from zebra and then used by BGP to
2878 * advertises an EAD-EVI (Type-1 EVPN) route
2879 * 3. The remote ES-EVI is created when a bgp_evpn_es_evi_vtep references
2883 /* A list of remote VTEPs is maintained for each ES-EVI. This list includes -
2884 * 1. VTEPs for which we have imported the EAD-per-ES Type1 route
2885 * 2. VTEPs for which we have imported the EAD-per-EVI Type1 route
2886 * VTEPs for which both routes have been rxed are activated. Activation
2887 * creates a NHG in the parent ES.
2889 static int bgp_evpn_es_evi_vtep_cmp(void *p1
, void *p2
)
2891 const struct bgp_evpn_es_evi_vtep
*evi_vtep1
= p1
;
2892 const struct bgp_evpn_es_evi_vtep
*evi_vtep2
= p2
;
2894 return evi_vtep1
->vtep_ip
.s_addr
- evi_vtep2
->vtep_ip
.s_addr
;
2897 static struct bgp_evpn_es_evi_vtep
*bgp_evpn_es_evi_vtep_new(
2898 struct bgp_evpn_es_evi
*es_evi
, struct in_addr vtep_ip
)
2900 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
2902 evi_vtep
= XCALLOC(MTYPE_BGP_EVPN_ES_EVI_VTEP
, sizeof(*evi_vtep
));
2904 evi_vtep
->es_evi
= es_evi
;
2905 evi_vtep
->vtep_ip
.s_addr
= vtep_ip
.s_addr
;
2906 listnode_init(&evi_vtep
->es_evi_listnode
, evi_vtep
);
2907 listnode_add_sort(es_evi
->es_evi_vtep_list
, &evi_vtep
->es_evi_listnode
);
2912 static void bgp_evpn_es_evi_vtep_free(struct bgp_evpn_es_evi_vtep
*evi_vtep
)
2914 struct bgp_evpn_es_evi
*es_evi
= evi_vtep
->es_evi
;
2916 if (evi_vtep
->flags
& (BGP_EVPN_EVI_VTEP_EAD
))
2917 /* as long as there is some reference we can't free it */
2920 list_delete_node(es_evi
->es_evi_vtep_list
, &evi_vtep
->es_evi_listnode
);
2921 XFREE(MTYPE_BGP_EVPN_ES_EVI_VTEP
, evi_vtep
);
2924 /* check if VTEP is already part of the list */
2925 static struct bgp_evpn_es_evi_vtep
*bgp_evpn_es_evi_vtep_find(
2926 struct bgp_evpn_es_evi
*es_evi
, struct in_addr vtep_ip
)
2928 struct listnode
*node
= NULL
;
2929 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
2931 for (ALL_LIST_ELEMENTS_RO(es_evi
->es_evi_vtep_list
, node
, evi_vtep
)) {
2932 if (evi_vtep
->vtep_ip
.s_addr
== vtep_ip
.s_addr
)
2938 /* A VTEP can be added as "active" attach to an ES if EAD-per-ES and
2939 * EAD-per-EVI routes are rxed from it.
2941 static void bgp_evpn_es_evi_vtep_re_eval_active(struct bgp
*bgp
,
2942 struct bgp_evpn_es_evi_vtep
*evi_vtep
)
2946 uint32_t ead_activity_flags
;
2948 old_active
= !!CHECK_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
);
2950 if (bgp_mh_info
->ead_evi_rx
)
2951 /* Both EAD-per-ES and EAD-per-EVI routes must be rxed from a PE
2952 * before it can be activated.
2954 ead_activity_flags
= BGP_EVPN_EVI_VTEP_EAD
;
2956 /* EAD-per-ES is sufficent to activate the PE */
2957 ead_activity_flags
= BGP_EVPN_EVI_VTEP_EAD_PER_ES
;
2959 if ((evi_vtep
->flags
& ead_activity_flags
) == ead_activity_flags
)
2960 SET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
);
2962 UNSET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
);
2964 new_active
= !!CHECK_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
);
2966 if (old_active
== new_active
)
2969 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2970 zlog_debug("es %s evi %u vtep %pI4 %s",
2971 evi_vtep
->es_evi
->es
->esi_str
,
2972 evi_vtep
->es_evi
->vpn
->vni
, &evi_vtep
->vtep_ip
,
2973 new_active
? "active" : "inactive");
2975 /* add VTEP to parent es */
2977 struct bgp_evpn_es_vtep
*es_vtep
;
2979 es_vtep
= bgp_evpn_es_vtep_add(bgp
, evi_vtep
->es_evi
->es
,
2980 evi_vtep
->vtep_ip
, false /*esr*/,
2982 evi_vtep
->es_vtep
= es_vtep
;
2984 if (evi_vtep
->es_vtep
) {
2985 bgp_evpn_es_vtep_do_del(bgp
, evi_vtep
->es_vtep
,
2987 evi_vtep
->es_vtep
= NULL
;
2990 /* queue up the parent es for background consistency checks */
2991 bgp_evpn_es_cons_checks_pend_add(evi_vtep
->es_evi
->es
);
2994 static void bgp_evpn_es_evi_vtep_add(struct bgp
*bgp
,
2995 struct bgp_evpn_es_evi
*es_evi
, struct in_addr vtep_ip
,
2998 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
3000 evi_vtep
= bgp_evpn_es_evi_vtep_find(es_evi
, vtep_ip
);
3003 evi_vtep
= bgp_evpn_es_evi_vtep_new(es_evi
, vtep_ip
);
3005 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3006 zlog_debug("add es %s evi %u vtep %pI4 %s",
3007 evi_vtep
->es_evi
->es
->esi_str
,
3008 evi_vtep
->es_evi
->vpn
->vni
, &evi_vtep
->vtep_ip
,
3009 ead_es
? "ead_es" : "ead_evi");
3012 SET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_EAD_PER_ES
);
3014 SET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_EAD_PER_EVI
);
3016 bgp_evpn_es_evi_vtep_re_eval_active(bgp
, evi_vtep
);
3019 static void bgp_evpn_es_evi_vtep_del(struct bgp
*bgp
,
3020 struct bgp_evpn_es_evi
*es_evi
, struct in_addr vtep_ip
,
3023 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
3025 evi_vtep
= bgp_evpn_es_evi_vtep_find(es_evi
, vtep_ip
);
3029 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3030 zlog_debug("del es %s evi %u vtep %pI4 %s",
3031 evi_vtep
->es_evi
->es
->esi_str
,
3032 evi_vtep
->es_evi
->vpn
->vni
, &evi_vtep
->vtep_ip
,
3033 ead_es
? "ead_es" : "ead_evi");
3036 UNSET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_EAD_PER_ES
);
3038 UNSET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_EAD_PER_EVI
);
3040 bgp_evpn_es_evi_vtep_re_eval_active(bgp
, evi_vtep
);
3041 bgp_evpn_es_evi_vtep_free(evi_vtep
);
3044 /* compare ES-IDs for the ES-EVI RB tree maintained per-VNI */
3045 static int bgp_es_evi_rb_cmp(const struct bgp_evpn_es_evi
*es_evi1
,
3046 const struct bgp_evpn_es_evi
*es_evi2
)
3048 return memcmp(&es_evi1
->es
->esi
, &es_evi2
->es
->esi
, ESI_BYTES
);
3050 RB_GENERATE(bgp_es_evi_rb_head
, bgp_evpn_es_evi
, rb_node
, bgp_es_evi_rb_cmp
);
3052 /* find the ES-EVI in the per-L2-VNI RB tree */
3053 static struct bgp_evpn_es_evi
*bgp_evpn_es_evi_find(struct bgp_evpn_es
*es
,
3054 struct bgpevpn
*vpn
)
3056 struct bgp_evpn_es_evi es_evi
;
3060 return RB_FIND(bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
, &es_evi
);
3063 /* allocate a new ES-EVI and insert it into the per-L2-VNI and per-ES
3066 static struct bgp_evpn_es_evi
*bgp_evpn_es_evi_new(struct bgp_evpn_es
*es
,
3067 struct bgpevpn
*vpn
)
3069 struct bgp_evpn_es_evi
*es_evi
;
3071 es_evi
= XCALLOC(MTYPE_BGP_EVPN_ES_EVI
, sizeof(*es_evi
));
3076 /* Initialise the VTEP list */
3077 es_evi
->es_evi_vtep_list
= list_new();
3078 listset_app_node_mem(es_evi
->es_evi_vtep_list
);
3079 es_evi
->es_evi_vtep_list
->cmp
= bgp_evpn_es_evi_vtep_cmp
;
3081 /* insert into the VNI-ESI rb tree */
3082 if (RB_INSERT(bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
, es_evi
)) {
3083 XFREE(MTYPE_BGP_EVPN_ES_EVI
, es_evi
);
3087 /* add to the ES's VNI list */
3088 listnode_init(&es_evi
->es_listnode
, es_evi
);
3089 listnode_add(es
->es_evi_list
, &es_evi
->es_listnode
);
3091 bgp_evpn_es_vrf_ref(es_evi
, vpn
->bgp_vrf
);
3096 /* remove the ES-EVI from the per-L2-VNI and per-ES tables and free
3099 static void bgp_evpn_es_evi_free(struct bgp_evpn_es_evi
*es_evi
)
3101 struct bgp_evpn_es
*es
= es_evi
->es
;
3102 struct bgpevpn
*vpn
= es_evi
->vpn
;
3104 /* cannot free the element as long as there is a local or remote
3107 if (es_evi
->flags
& (BGP_EVPNES_EVI_LOCAL
| BGP_EVPNES_EVI_REMOTE
))
3110 bgp_evpn_es_vrf_deref(es_evi
);
3112 /* remove from the ES's VNI list */
3113 list_delete_node(es
->es_evi_list
, &es_evi
->es_listnode
);
3115 /* remove from the VNI-ESI rb tree */
3116 RB_REMOVE(bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
, es_evi
);
3118 /* free the VTEP list */
3119 list_delete(&es_evi
->es_evi_vtep_list
);
3121 /* remove from the VNI-ESI rb tree */
3122 XFREE(MTYPE_BGP_EVPN_ES_EVI
, es_evi
);
3125 /* init local info associated with the ES-EVI */
3126 static void bgp_evpn_es_evi_local_info_set(struct bgp_evpn_es_evi
*es_evi
)
3128 struct bgpevpn
*vpn
= es_evi
->vpn
;
3130 if (CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
3133 SET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
);
3134 listnode_init(&es_evi
->l2vni_listnode
, es_evi
);
3135 listnode_add(vpn
->local_es_evi_list
, &es_evi
->l2vni_listnode
);
3138 /* clear any local info associated with the ES-EVI */
3139 static void bgp_evpn_es_evi_local_info_clear(struct bgp_evpn_es_evi
*es_evi
)
3141 struct bgpevpn
*vpn
= es_evi
->vpn
;
3143 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
3146 UNSET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
);
3147 list_delete_node(vpn
->local_es_evi_list
, &es_evi
->l2vni_listnode
);
3149 bgp_evpn_es_evi_free(es_evi
);
3152 /* eval remote info associated with the ES */
3153 static void bgp_evpn_es_evi_remote_info_re_eval(struct bgp_evpn_es_evi
*es_evi
)
3155 struct bgp_evpn_es
*es
= es_evi
->es
;
3157 /* if there are remote VTEPs the ES-EVI is classified as "remote" */
3158 if (listcount(es_evi
->es_evi_vtep_list
)) {
3159 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_REMOTE
)) {
3160 SET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_REMOTE
);
3161 ++es
->remote_es_evi_cnt
;
3162 /* set remote on the parent es */
3163 bgp_evpn_es_remote_info_re_eval(es
);
3166 if (CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_REMOTE
)) {
3167 UNSET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_REMOTE
);
3168 if (es
->remote_es_evi_cnt
)
3169 --es
->remote_es_evi_cnt
;
3170 bgp_evpn_es_evi_free(es_evi
);
3171 /* check if "remote" can be cleared from the
3174 bgp_evpn_es_remote_info_re_eval(es
);
3179 static void bgp_evpn_local_es_evi_do_del(struct bgp_evpn_es_evi
*es_evi
)
3181 struct prefix_evpn p
;
3182 struct bgp_evpn_es
*es
= es_evi
->es
;
3185 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
3188 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3189 zlog_debug("del local es %s evi %u",
3190 es_evi
->es
->esi_str
,
3193 bgp
= bgp_get_evpn();
3196 /* update EAD-ES with new list of VNIs */
3197 if (bgp_evpn_local_es_is_active(es
)) {
3198 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_ES_ETH_TAG
,
3199 &es
->esi
, es
->originator_ip
);
3200 if (bgp_evpn_type1_route_update(bgp
, es
, NULL
, &p
))
3201 flog_err(EC_BGP_EVPN_ROUTE_CREATE
,
3202 "%u: EAD-ES route update failure for ESI %s VNI %u",
3203 bgp
->vrf_id
, es
->esi_str
,
3207 /* withdraw and delete EAD-EVI */
3208 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
)) {
3209 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_EVI_ETH_TAG
,
3210 &es
->esi
, es
->originator_ip
);
3211 if (bgp_evpn_type1_evi_route_delete(bgp
,
3212 es
, es_evi
->vpn
, &p
))
3213 flog_err(EC_BGP_EVPN_ROUTE_DELETE
,
3214 "%u: EAD-EVI route deletion failure for ESI %s VNI %u",
3215 bgp
->vrf_id
, es
->esi_str
,
3220 bgp_evpn_es_evi_local_info_clear(es_evi
);
3224 int bgp_evpn_local_es_evi_del(struct bgp
*bgp
, esi_t
*esi
, vni_t vni
)
3226 struct bgpevpn
*vpn
;
3227 struct bgp_evpn_es
*es
;
3228 struct bgp_evpn_es_evi
*es_evi
;
3229 char buf
[ESI_STR_LEN
];
3231 es
= bgp_evpn_es_find(esi
);
3235 "%u: Failed to deref VNI %d from ESI %s; ES not present",
3237 esi_to_str(esi
, buf
, sizeof(buf
)));
3241 vpn
= bgp_evpn_lookup_vni(bgp
, vni
);
3245 "%u: Failed to deref VNI %d from ESI %s; VNI not present",
3246 bgp
->vrf_id
, vni
, es
->esi_str
);
3250 es_evi
= bgp_evpn_es_evi_find(es
, vpn
);
3254 "%u: Failed to deref VNI %d from ESI %s; ES-VNI not present",
3255 bgp
->vrf_id
, vni
, es
->esi_str
);
3259 bgp_evpn_local_es_evi_do_del(es_evi
);
3263 /* Create ES-EVI and advertise the corresponding EAD routes */
3264 int bgp_evpn_local_es_evi_add(struct bgp
*bgp
, esi_t
*esi
, vni_t vni
)
3266 struct bgpevpn
*vpn
;
3267 struct prefix_evpn p
;
3268 struct bgp_evpn_es
*es
;
3269 struct bgp_evpn_es_evi
*es_evi
;
3270 char buf
[ESI_STR_LEN
];
3272 es
= bgp_evpn_es_find(esi
);
3276 "%u: Failed to associate VNI %d with ESI %s; ES not present",
3278 esi_to_str(esi
, buf
, sizeof(buf
)));
3282 vpn
= bgp_evpn_lookup_vni(bgp
, vni
);
3286 "%u: Failed to associate VNI %d with ESI %s; VNI not present",
3287 bgp
->vrf_id
, vni
, es
->esi_str
);
3291 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3292 zlog_debug("add local es %s evi %u",
3295 es_evi
= bgp_evpn_es_evi_find(es
, vpn
);
3298 if (CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
3302 es_evi
= bgp_evpn_es_evi_new(es
, vpn
);
3307 bgp_evpn_es_evi_local_info_set(es_evi
);
3309 /* generate an EAD-EVI for this new VNI */
3310 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
)) {
3311 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_EVI_ETH_TAG
, &es
->esi
,
3313 if (bgp_evpn_type1_route_update(bgp
, es
, vpn
, &p
))
3314 flog_err(EC_BGP_EVPN_ROUTE_CREATE
,
3315 "%u: EAD-EVI route creation failure for ESI %s VNI %u",
3316 bgp
->vrf_id
, es
->esi_str
, vni
);
3320 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_ES_ETH_TAG
,
3321 &es
->esi
, es
->originator_ip
);
3322 if (bgp_evpn_local_es_is_active(es
)) {
3323 if (bgp_evpn_type1_route_update(bgp
, es
, NULL
, &p
))
3324 flog_err(EC_BGP_EVPN_ROUTE_CREATE
,
3325 "%u: EAD-ES route creation failure for ESI %s VNI %u",
3326 bgp
->vrf_id
, es
->esi_str
, vni
);
3332 /* Add remote ES-EVI entry. This is actually the remote VTEP add and the
3333 * ES-EVI is implicity created on first VTEP's reference.
3335 int bgp_evpn_remote_es_evi_add(struct bgp
*bgp
, struct bgpevpn
*vpn
,
3336 const struct prefix_evpn
*p
)
3338 char buf
[ESI_STR_LEN
];
3339 struct bgp_evpn_es
*es
;
3340 struct bgp_evpn_es_evi
*es_evi
;
3342 const esi_t
*esi
= &p
->prefix
.ead_addr
.esi
;
3345 /* local EAD-ES need not be sent back to zebra */
3348 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3349 zlog_debug("add remote %s es %s evi %u vtep %pI4",
3350 p
->prefix
.ead_addr
.eth_tag
? "ead-es" : "ead-evi",
3351 esi_to_str(esi
, buf
, sizeof(buf
)), vpn
->vni
,
3352 &p
->prefix
.ead_addr
.ip
.ipaddr_v4
);
3354 es
= bgp_evpn_es_find(esi
);
3356 es
= bgp_evpn_es_new(bgp
, esi
);
3358 flog_err(EC_BGP_ES_CREATE
,
3359 "%u: Failed to allocate ES entry for ESI %s - at remote ES Add",
3360 bgp
->vrf_id
, esi_to_str(esi
, buf
, sizeof(buf
)));
3365 es_evi
= bgp_evpn_es_evi_find(es
, vpn
);
3367 es_evi
= bgp_evpn_es_evi_new(es
, vpn
);
3369 bgp_evpn_es_free(es
, __func__
);
3374 ead_es
= !!p
->prefix
.ead_addr
.eth_tag
;
3375 bgp_evpn_es_evi_vtep_add(bgp
, es_evi
, p
->prefix
.ead_addr
.ip
.ipaddr_v4
,
3378 bgp_evpn_es_evi_remote_info_re_eval(es_evi
);
3382 /* A remote VTEP has withdrawn. The es-evi-vtep will be deleted and the
3383 * parent es-evi freed up implicitly in last VTEP's deref.
3385 int bgp_evpn_remote_es_evi_del(struct bgp
*bgp
, struct bgpevpn
*vpn
,
3386 const struct prefix_evpn
*p
)
3388 char buf
[ESI_STR_LEN
];
3389 struct bgp_evpn_es
*es
;
3390 struct bgp_evpn_es_evi
*es_evi
;
3394 /* local EAD-ES need not be sent back to zebra */
3397 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3399 "del remote %s es %s evi %u vtep %pI4",
3400 p
->prefix
.ead_addr
.eth_tag
? "ead-es" : "ead-evi",
3401 esi_to_str(&p
->prefix
.ead_addr
.esi
, buf
, sizeof(buf
)),
3402 vpn
->vni
, &p
->prefix
.ead_addr
.ip
.ipaddr_v4
);
3404 es
= bgp_evpn_es_find(&p
->prefix
.ead_addr
.esi
);
3406 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3407 zlog_debug("del remote %s es %s evi %u vtep %pI4, NO es",
3408 p
->prefix
.ead_addr
.eth_tag
? "ead-es"
3410 esi_to_str(&p
->prefix
.ead_addr
.esi
, buf
,
3413 &p
->prefix
.ead_addr
.ip
.ipaddr_v4
);
3416 es_evi
= bgp_evpn_es_evi_find(es
, vpn
);
3418 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3420 "del remote %s es %s evi %u vtep %pI4, NO es-evi",
3421 p
->prefix
.ead_addr
.eth_tag
? "ead-es"
3423 esi_to_str(&p
->prefix
.ead_addr
.esi
, buf
,
3426 &p
->prefix
.ead_addr
.ip
.ipaddr_v4
);
3430 ead_es
= !!p
->prefix
.ead_addr
.eth_tag
;
3431 bgp_evpn_es_evi_vtep_del(bgp
, es_evi
, p
->prefix
.ead_addr
.ip
.ipaddr_v4
,
3433 bgp_evpn_es_evi_remote_info_re_eval(es_evi
);
3437 /* Initialize the ES tables maintained per-L2_VNI */
3438 void bgp_evpn_vni_es_init(struct bgpevpn
*vpn
)
3440 /* Initialize the ES-EVI RB tree */
3441 RB_INIT(bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
);
3443 /* Initialize the local list maintained for quick walks by type */
3444 vpn
->local_es_evi_list
= list_new();
3445 listset_app_node_mem(vpn
->local_es_evi_list
);
3448 /* Cleanup the ES info maintained per-L2_VNI */
3449 void bgp_evpn_vni_es_cleanup(struct bgpevpn
*vpn
)
3451 struct bgp_evpn_es_evi
*es_evi
;
3452 struct bgp_evpn_es_evi
*es_evi_next
;
3454 RB_FOREACH_SAFE(es_evi
, bgp_es_evi_rb_head
,
3455 &vpn
->es_evi_rb_tree
, es_evi_next
) {
3456 bgp_evpn_local_es_evi_do_del(es_evi
);
3459 list_delete(&vpn
->local_es_evi_list
);
3462 static char *bgp_evpn_es_evi_vteps_str(char *vtep_str
,
3463 struct bgp_evpn_es_evi
*es_evi
,
3464 uint8_t vtep_str_size
)
3466 char vtep_flag_str
[BGP_EVPN_FLAG_STR_SZ
];
3467 struct listnode
*node
;
3468 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
3470 char ip_buf
[INET6_ADDRSTRLEN
];
3473 for (ALL_LIST_ELEMENTS_RO(es_evi
->es_evi_vtep_list
, node
, evi_vtep
)) {
3474 vtep_flag_str
[0] = '\0';
3475 if (evi_vtep
->flags
& BGP_EVPN_EVI_VTEP_EAD_PER_ES
)
3476 strlcat(vtep_flag_str
, "E", sizeof(vtep_flag_str
));
3477 if (evi_vtep
->flags
& BGP_EVPN_EVI_VTEP_EAD_PER_EVI
)
3478 strlcat(vtep_flag_str
, "V", sizeof(vtep_flag_str
));
3480 if (!strnlen(vtep_flag_str
, sizeof(vtep_flag_str
)))
3481 strlcpy(vtep_flag_str
, "-", sizeof(vtep_flag_str
));
3485 strlcat(vtep_str
, ",", vtep_str_size
);
3487 inet_ntop(AF_INET
, &evi_vtep
->vtep_ip
, ip_buf
,
3490 strlcat(vtep_str
, "(", vtep_str_size
);
3491 strlcat(vtep_str
, vtep_flag_str
, vtep_str_size
);
3492 strlcat(vtep_str
, ")", vtep_str_size
);
3498 static void bgp_evpn_es_evi_json_vtep_fill(json_object
*json_vteps
,
3499 struct bgp_evpn_es_evi_vtep
*evi_vtep
)
3501 json_object
*json_vtep_entry
;
3502 json_object
*json_flags
;
3503 char ip_buf
[INET6_ADDRSTRLEN
];
3505 json_vtep_entry
= json_object_new_object();
3507 json_object_string_add(
3508 json_vtep_entry
, "vtep_ip",
3509 inet_ntop(AF_INET
, &evi_vtep
->vtep_ip
, ip_buf
, sizeof(ip_buf
)));
3510 if (evi_vtep
->flags
& (BGP_EVPN_EVI_VTEP_EAD_PER_ES
|
3511 BGP_EVPN_EVI_VTEP_EAD_PER_EVI
)) {
3512 json_flags
= json_object_new_array();
3513 if (evi_vtep
->flags
& BGP_EVPN_EVI_VTEP_EAD_PER_ES
)
3514 json_array_string_add(json_flags
, "ead-per-es");
3515 if (evi_vtep
->flags
& BGP_EVPN_EVI_VTEP_EAD_PER_EVI
)
3516 json_array_string_add(json_flags
, "ead-per-evi");
3517 json_object_object_add(json_vtep_entry
,
3518 "flags", json_flags
);
3521 json_object_array_add(json_vteps
,
3525 static void bgp_evpn_es_evi_show_entry(struct vty
*vty
,
3526 struct bgp_evpn_es_evi
*es_evi
, json_object
*json
)
3528 struct listnode
*node
;
3529 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
3532 json_object
*json_vteps
;
3533 json_object
*json_types
;
3535 json_object_string_add(json
, "esi", es_evi
->es
->esi_str
);
3536 json_object_int_add(json
, "vni", es_evi
->vpn
->vni
);
3538 if (es_evi
->flags
& (BGP_EVPNES_EVI_LOCAL
|
3539 BGP_EVPNES_EVI_REMOTE
)) {
3540 json_types
= json_object_new_array();
3541 if (es_evi
->flags
& BGP_EVPNES_EVI_LOCAL
)
3542 json_array_string_add(json_types
, "local");
3543 if (es_evi
->flags
& BGP_EVPNES_EVI_REMOTE
)
3544 json_array_string_add(json_types
, "remote");
3545 json_object_object_add(json
, "type", json_types
);
3548 if (listcount(es_evi
->es_evi_vtep_list
)) {
3549 json_vteps
= json_object_new_array();
3550 for (ALL_LIST_ELEMENTS_RO(es_evi
->es_evi_vtep_list
,
3552 bgp_evpn_es_evi_json_vtep_fill(json_vteps
,
3555 json_object_object_add(json
, "vteps", json_vteps
);
3559 char vtep_str
[ES_VTEP_LIST_STR_SZ
+ BGP_EVPN_VTEPS_FLAG_STR_SZ
];
3562 if (es_evi
->flags
& BGP_EVPNES_EVI_LOCAL
)
3563 strlcat(type_str
, "L", sizeof(type_str
));
3564 if (es_evi
->flags
& BGP_EVPNES_EVI_REMOTE
)
3565 strlcat(type_str
, "R", sizeof(type_str
));
3566 if (es_evi
->flags
& BGP_EVPNES_EVI_INCONS_VTEP_LIST
)
3567 strlcat(type_str
, "I", sizeof(type_str
));
3569 bgp_evpn_es_evi_vteps_str(vtep_str
, es_evi
, sizeof(vtep_str
));
3571 vty_out(vty
, "%-8d %-30s %-5s %s\n",
3572 es_evi
->vpn
->vni
, es_evi
->es
->esi_str
,
3573 type_str
, vtep_str
);
3577 static void bgp_evpn_es_evi_show_entry_detail(struct vty
*vty
,
3578 struct bgp_evpn_es_evi
*es_evi
, json_object
*json
)
3581 json_object
*json_flags
;
3583 /* Add the "brief" info first */
3584 bgp_evpn_es_evi_show_entry(vty
, es_evi
, json
);
3585 if (es_evi
->flags
& BGP_EVPNES_EVI_INCONS_VTEP_LIST
) {
3586 json_flags
= json_object_new_array();
3587 json_array_string_add(json_flags
, "es-vtep-mismatch");
3588 json_object_object_add(json
, "flags", json_flags
);
3591 char vtep_str
[ES_VTEP_LIST_STR_SZ
+ BGP_EVPN_VTEPS_FLAG_STR_SZ
];
3595 if (es_evi
->flags
& BGP_EVPNES_EVI_LOCAL
)
3596 strlcat(type_str
, "L", sizeof(type_str
));
3597 if (es_evi
->flags
& BGP_EVPNES_EVI_REMOTE
)
3598 strlcat(type_str
, "R", sizeof(type_str
));
3600 bgp_evpn_es_evi_vteps_str(vtep_str
, es_evi
, sizeof(vtep_str
));
3601 if (!strlen(vtep_str
))
3602 strlcpy(vtep_str
, "-", sizeof(type_str
));
3604 vty_out(vty
, "VNI: %d ESI: %s\n",
3605 es_evi
->vpn
->vni
, es_evi
->es
->esi_str
);
3606 vty_out(vty
, " Type: %s\n", type_str
);
3607 vty_out(vty
, " Inconsistencies: %s\n",
3608 (es_evi
->flags
& BGP_EVPNES_EVI_INCONS_VTEP_LIST
) ?
3609 "es-vtep-mismatch":"-");
3610 vty_out(vty
, " VTEPs: %s\n", vtep_str
);
3615 static void bgp_evpn_es_evi_show_one_vni(struct bgpevpn
*vpn
, struct vty
*vty
,
3616 json_object
*json_array
, bool detail
)
3618 struct bgp_evpn_es_evi
*es_evi
;
3619 json_object
*json
= NULL
;
3621 RB_FOREACH(es_evi
, bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
) {
3623 /* create a separate json object for each ES */
3624 json
= json_object_new_object();
3626 bgp_evpn_es_evi_show_entry_detail(vty
, es_evi
, json
);
3628 bgp_evpn_es_evi_show_entry(vty
, es_evi
, json
);
3629 /* add ES to the json array */
3631 json_object_array_add(json_array
, json
);
3635 struct es_evi_show_ctx
{
3641 static void bgp_evpn_es_evi_show_one_vni_hash_cb(struct hash_bucket
*bucket
,
3644 struct bgpevpn
*vpn
= (struct bgpevpn
*)bucket
->data
;
3645 struct es_evi_show_ctx
*wctx
= (struct es_evi_show_ctx
*)ctxt
;
3647 bgp_evpn_es_evi_show_one_vni(vpn
, wctx
->vty
, wctx
->json
, wctx
->detail
);
3650 /* Display all ES EVIs */
3651 void bgp_evpn_es_evi_show(struct vty
*vty
, bool uj
, bool detail
)
3653 json_object
*json_array
= NULL
;
3654 struct es_evi_show_ctx wctx
;
3658 /* create an array of ES-EVIs */
3659 json_array
= json_object_new_array();
3663 wctx
.json
= json_array
;
3664 wctx
.detail
= detail
;
3666 bgp
= bgp_get_evpn();
3668 if (!json_array
&& !detail
) {
3669 vty_out(vty
, "Flags: L local, R remote, I inconsistent\n");
3670 vty_out(vty
, "VTEP-Flags: E EAD-per-ES, V EAD-per-EVI\n");
3671 vty_out(vty
, "%-8s %-30s %-5s %s\n",
3672 "VNI", "ESI", "Flags", "VTEPs");
3676 hash_iterate(bgp
->vnihash
,
3677 (void (*)(struct hash_bucket
*,
3678 void *))bgp_evpn_es_evi_show_one_vni_hash_cb
,
3681 vty_out(vty
, "%s\n", json_object_to_json_string_ext(
3682 json_array
, JSON_C_TO_STRING_PRETTY
));
3683 json_object_free(json_array
);
3687 /* Display specific ES EVI */
3688 void bgp_evpn_es_evi_show_vni(struct vty
*vty
, vni_t vni
,
3689 bool uj
, bool detail
)
3691 struct bgpevpn
*vpn
= NULL
;
3692 json_object
*json_array
= NULL
;
3696 /* create an array of ES-EVIs */
3697 json_array
= json_object_new_array();
3700 bgp
= bgp_get_evpn();
3702 vpn
= bgp_evpn_lookup_vni(bgp
, vni
);
3705 if (!json_array
&& !detail
) {
3706 vty_out(vty
, "Flags: L local, R remote, I inconsistent\n");
3707 vty_out(vty
, "VTEP-Flags: E EAD-per-ES, V EAD-per-EVI\n");
3708 vty_out(vty
, "%-8s %-30s %-5s %s\n",
3709 "VNI", "ESI", "Flags", "VTEPs");
3712 bgp_evpn_es_evi_show_one_vni(vpn
, vty
, json_array
, detail
);
3715 vty_out(vty
, "VNI not found\n");
3719 vty_out(vty
, "%s\n", json_object_to_json_string_ext(
3720 json_array
, JSON_C_TO_STRING_PRETTY
));
3721 json_object_free(json_array
);
3725 /*****************************************************************************
3726 * Ethernet Segment Consistency checks
3727 * Consistency checking is done to detect misconfig or mis-cabling. When
3728 * an inconsistency is detected it is simply logged (and displayed via
3729 * show commands) at this point. A more drastic action can be executed (based
3730 * on user config) in the future.
3732 static void bgp_evpn_es_cons_checks_timer_start(void)
3734 if (!bgp_mh_info
->consistency_checking
|| bgp_mh_info
->t_cons_check
)
3737 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3738 zlog_debug("periodic consistency checking started");
3740 thread_add_timer(bm
->master
, bgp_evpn_run_consistency_checks
, NULL
,
3741 BGP_EVPN_CONS_CHECK_INTERVAL
,
3742 &bgp_mh_info
->t_cons_check
);
3745 /* queue up the es for background consistency checks */
3746 static void bgp_evpn_es_cons_checks_pend_add(struct bgp_evpn_es
*es
)
3748 if (!bgp_mh_info
->consistency_checking
)
3749 /* consistency checking is not enabled */
3752 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_CONS_CHECK_PEND
))
3753 /* already queued for consistency checking */
3756 /* start the periodic timer for consistency checks if it is not
3757 * already running */
3758 bgp_evpn_es_cons_checks_timer_start();
3760 SET_FLAG(es
->flags
, BGP_EVPNES_CONS_CHECK_PEND
);
3761 listnode_init(&es
->pend_es_listnode
, es
);
3762 listnode_add_after(bgp_mh_info
->pend_es_list
,
3763 listtail_unchecked(bgp_mh_info
->pend_es_list
),
3764 &es
->pend_es_listnode
);
3767 /* pull the ES from the consistency check list */
3768 static void bgp_evpn_es_cons_checks_pend_del(struct bgp_evpn_es
*es
)
3770 if (!CHECK_FLAG(es
->flags
, BGP_EVPNES_CONS_CHECK_PEND
))
3773 UNSET_FLAG(es
->flags
, BGP_EVPNES_CONS_CHECK_PEND
);
3774 list_delete_node(bgp_mh_info
->pend_es_list
,
3775 &es
->pend_es_listnode
);
3778 /* Number of active VTEPs associated with the ES-per-EVI */
3779 static uint32_t bgp_evpn_es_evi_get_active_vtep_cnt(
3780 struct bgp_evpn_es_evi
*es_evi
)
3782 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
3783 struct listnode
*node
;
3784 uint32_t vtep_cnt
= 0;
3786 for (ALL_LIST_ELEMENTS_RO(es_evi
->es_evi_vtep_list
, node
, evi_vtep
)) {
3787 if (CHECK_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
))
3794 /* Number of active VTEPs associated with the ES */
3795 static uint32_t bgp_evpn_es_get_active_vtep_cnt(struct bgp_evpn_es
*es
)
3797 struct listnode
*node
;
3798 uint32_t vtep_cnt
= 0;
3799 struct bgp_evpn_es_vtep
*es_vtep
;
3801 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
3802 if (CHECK_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
))
3809 static struct bgp_evpn_es_vtep
*bgp_evpn_es_get_next_active_vtep(
3810 struct bgp_evpn_es
*es
, struct bgp_evpn_es_vtep
*es_vtep
)
3812 struct listnode
*node
;
3813 struct bgp_evpn_es_vtep
*next_es_vtep
;
3816 node
= listnextnode_unchecked(&es_vtep
->es_listnode
);
3818 node
= listhead(es
->es_vtep_list
);
3820 for (; node
; node
= listnextnode_unchecked(node
)) {
3821 next_es_vtep
= listgetdata(node
);
3822 if (CHECK_FLAG(next_es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
))
3823 return next_es_vtep
;
3829 static struct bgp_evpn_es_evi_vtep
*bgp_evpn_es_evi_get_next_active_vtep(
3830 struct bgp_evpn_es_evi
*es_evi
,
3831 struct bgp_evpn_es_evi_vtep
*evi_vtep
)
3833 struct listnode
*node
;
3834 struct bgp_evpn_es_evi_vtep
*next_evi_vtep
;
3837 node
= listnextnode_unchecked(&evi_vtep
->es_evi_listnode
);
3839 node
= listhead(es_evi
->es_evi_vtep_list
);
3841 for (; node
; node
= listnextnode_unchecked(node
)) {
3842 next_evi_vtep
= listgetdata(node
);
3843 if (CHECK_FLAG(next_evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
))
3844 return next_evi_vtep
;
3850 static void bgp_evpn_es_evi_set_inconsistent(struct bgp_evpn_es_evi
*es_evi
)
3852 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_INCONS_VTEP_LIST
)) {
3853 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3854 zlog_debug("inconsistency detected - es %s evi %u vtep list mismatch",
3855 es_evi
->es
->esi_str
,
3857 SET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_INCONS_VTEP_LIST
);
3859 /* update parent ES with the incosistency setting */
3860 if (!es_evi
->es
->incons_evi_vtep_cnt
&&
3861 BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3862 zlog_debug("inconsistency detected - es %s vtep list mismatch",
3863 es_evi
->es
->esi_str
);
3864 ++es_evi
->es
->incons_evi_vtep_cnt
;
3865 SET_FLAG(es_evi
->es
->inconsistencies
,
3866 BGP_EVPNES_INCONS_VTEP_LIST
);
3870 static uint32_t bgp_evpn_es_run_consistency_checks(struct bgp_evpn_es
*es
)
3873 int es_active_vtep_cnt
;
3874 int evi_active_vtep_cnt
;
3875 struct bgp_evpn_es_evi
*es_evi
;
3876 struct listnode
*evi_node
;
3877 struct bgp_evpn_es_vtep
*es_vtep
;
3878 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
3880 /* reset the inconsistencies and re-evaluate */
3881 es
->incons_evi_vtep_cnt
= 0;
3882 es
->inconsistencies
= 0;
3884 es_active_vtep_cnt
= bgp_evpn_es_get_active_vtep_cnt(es
);
3885 for (ALL_LIST_ELEMENTS_RO(es
->es_evi_list
,
3886 evi_node
, es_evi
)) {
3889 /* reset the inconsistencies on the EVI and re-evaluate*/
3890 UNSET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_INCONS_VTEP_LIST
);
3892 evi_active_vtep_cnt
=
3893 bgp_evpn_es_evi_get_active_vtep_cnt(es_evi
);
3894 if (es_active_vtep_cnt
!= evi_active_vtep_cnt
) {
3895 bgp_evpn_es_evi_set_inconsistent(es_evi
);
3899 if (!es_active_vtep_cnt
)
3904 while ((es_vtep
= bgp_evpn_es_get_next_active_vtep(
3906 evi_vtep
= bgp_evpn_es_evi_get_next_active_vtep(es_evi
,
3909 bgp_evpn_es_evi_set_inconsistent(es_evi
);
3912 if (es_vtep
->vtep_ip
.s_addr
!=
3913 evi_vtep
->vtep_ip
.s_addr
) {
3914 /* inconsistency detected; set it and move
3917 bgp_evpn_es_evi_set_inconsistent(es_evi
);
3926 static int bgp_evpn_run_consistency_checks(struct thread
*t
)
3930 struct listnode
*node
;
3931 struct listnode
*nextnode
;
3932 struct bgp_evpn_es
*es
;
3934 for (ALL_LIST_ELEMENTS(bgp_mh_info
->pend_es_list
,
3935 node
, nextnode
, es
)) {
3938 /* run consistency checks on the ES and remove it from the
3941 proc_cnt
+= bgp_evpn_es_run_consistency_checks(es
);
3942 bgp_evpn_es_cons_checks_pend_del(es
);
3947 /* restart the timer */
3948 thread_add_timer(bm
->master
, bgp_evpn_run_consistency_checks
, NULL
,
3949 BGP_EVPN_CONS_CHECK_INTERVAL
,
3950 &bgp_mh_info
->t_cons_check
);
3955 /*****************************************************************************/
3956 void bgp_evpn_mh_init(void)
3958 bm
->mh_info
= XCALLOC(MTYPE_BGP_EVPN_MH_INFO
, sizeof(*bm
->mh_info
));
3960 /* setup ES tables */
3961 RB_INIT(bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
);
3963 bgp_mh_info
->local_es_list
= list_new();
3964 listset_app_node_mem(bgp_mh_info
->local_es_list
);
3965 /* list of ESs with pending processing */
3966 bgp_mh_info
->pend_es_list
= list_new();
3967 listset_app_node_mem(bgp_mh_info
->pend_es_list
);
3969 bgp_mh_info
->ead_evi_rx
= BGP_EVPN_MH_EAD_EVI_RX_DEF
;
3970 bgp_mh_info
->ead_evi_tx
= BGP_EVPN_MH_EAD_EVI_TX_DEF
;
3972 /* config knobs - XXX add cli to control it */
3973 bgp_mh_info
->ead_evi_adv_for_down_links
= true;
3974 bgp_mh_info
->consistency_checking
= true;
3975 bgp_mh_info
->install_l3nhg
= false;
3976 bgp_mh_info
->host_routes_use_l3nhg
= BGP_EVPN_MH_USE_ES_L3NHG_DEF
;
3977 bgp_mh_info
->suppress_l3_ecomm_on_inactive_es
= true;
3979 memset(&zero_esi_buf
, 0, sizeof(esi_t
));
3982 void bgp_evpn_mh_finish(void)
3984 struct bgp_evpn_es
*es
;
3985 struct bgp_evpn_es
*es_next
;
3987 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
3988 zlog_debug("evpn mh finish");
3990 RB_FOREACH_SAFE (es
, bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
,
3992 bgp_evpn_es_local_info_clear(es
);
3994 if (bgp_mh_info
->t_cons_check
)
3995 thread_cancel(&bgp_mh_info
->t_cons_check
);
3996 list_delete(&bgp_mh_info
->local_es_list
);
3997 list_delete(&bgp_mh_info
->pend_es_list
);
3999 XFREE(MTYPE_BGP_EVPN_MH_INFO
, bgp_mh_info
);
4002 /* This function is called when disable-ead-evi-rx knob flaps */
4003 void bgp_evpn_switch_ead_evi_rx(void)
4006 struct bgp_evpn_es
*es
;
4007 struct bgp_evpn_es_evi
*es_evi
;
4008 struct listnode
*evi_node
= NULL
;
4009 struct listnode
*evi_next
= NULL
;
4010 struct bgp_evpn_es_evi_vtep
*vtep
;
4011 struct listnode
*vtep_node
= NULL
;
4012 struct listnode
*vtep_next
= NULL
;
4014 bgp
= bgp_get_evpn();
4019 * Process all the remote es_evi_vteps and reevaluate if the es_evi_vtep
4022 RB_FOREACH(es
, bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
) {
4023 if (!CHECK_FLAG(es
->flags
, BGP_EVPNES_REMOTE
))
4026 for (ALL_LIST_ELEMENTS(es
->es_evi_list
, evi_node
, evi_next
,
4028 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_REMOTE
))
4031 for (ALL_LIST_ELEMENTS(es_evi
->es_evi_vtep_list
,
4032 vtep_node
, vtep_next
, vtep
))
4033 bgp_evpn_es_evi_vtep_re_eval_active(bgp
, vtep
);