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
);
72 static void bgp_evpn_es_path_all_update(struct bgp_evpn_es_vtep
*es_vtep
,
75 esi_t zero_esi_buf
, *zero_esi
= &zero_esi_buf
;
77 /******************************************************************************
78 * per-ES (Ethernet Segment) routing table
80 * Following routes are added to the ES's routing table -
81 * 1. Local and remote ESR (Type-4)
82 * 2. Local EAD-per-ES (Type-1).
84 * Key for these routes is {ESI, VTEP-IP} so the path selection is practically
85 * a no-op i.e. all paths lead to same VTEP-IP (i.e. result in the same VTEP
86 * being added to same ES).
88 * Note the following routes go into the VNI routing table (instead of the
90 * 1. Remote EAD-per-ES
91 * 2. Local and remote EAD-per-EVI
94 /* Calculate the best path for a multi-homing (Type-1 or Type-4) route
95 * installed in the ES's routing table.
97 static int bgp_evpn_es_route_select_install(struct bgp
*bgp
,
98 struct bgp_evpn_es
*es
,
99 struct bgp_dest
*dest
)
102 afi_t afi
= AFI_L2VPN
;
103 safi_t safi
= SAFI_EVPN
;
104 struct bgp_path_info
*old_select
; /* old best */
105 struct bgp_path_info
*new_select
; /* new best */
106 struct bgp_path_info_pair old_and_new
;
108 /* Compute the best path. */
109 bgp_best_selection(bgp
, dest
, &bgp
->maxpaths
[afi
][safi
], &old_and_new
,
111 old_select
= old_and_new
.old
;
112 new_select
= old_and_new
.new;
115 * If the best path hasn't changed - see if something needs to be
118 if (old_select
&& old_select
== new_select
119 && old_select
->type
== ZEBRA_ROUTE_BGP
120 && old_select
->sub_type
== BGP_ROUTE_IMPORTED
121 && !CHECK_FLAG(dest
->flags
, BGP_NODE_USER_CLEAR
)
122 && !CHECK_FLAG(old_select
->flags
, BGP_PATH_ATTR_CHANGED
)
123 && !bgp_addpath_is_addpath_used(&bgp
->tx_addpath
, afi
, safi
)) {
124 if (bgp_zebra_has_route_changed(old_select
)) {
125 bgp_evpn_es_vtep_add(bgp
, es
, old_select
->attr
->nexthop
,
127 old_select
->attr
->df_alg
,
128 old_select
->attr
->df_pref
);
130 UNSET_FLAG(old_select
->flags
, BGP_PATH_MULTIPATH_CHG
);
131 bgp_zebra_clear_route_change_flags(dest
);
135 /* If the user did a "clear" this flag will be set */
136 UNSET_FLAG(dest
->flags
, BGP_NODE_USER_CLEAR
);
138 /* bestpath has changed; update relevant fields and install or uninstall
139 * into the zebra RIB.
141 if (old_select
|| new_select
)
142 bgp_bump_version(dest
);
145 bgp_path_info_unset_flag(dest
, old_select
, BGP_PATH_SELECTED
);
147 bgp_path_info_set_flag(dest
, new_select
, BGP_PATH_SELECTED
);
148 bgp_path_info_unset_flag(dest
, new_select
,
149 BGP_PATH_ATTR_CHANGED
);
150 UNSET_FLAG(new_select
->flags
, BGP_PATH_MULTIPATH_CHG
);
153 if (new_select
&& new_select
->type
== ZEBRA_ROUTE_BGP
154 && new_select
->sub_type
== BGP_ROUTE_IMPORTED
) {
155 bgp_evpn_es_vtep_add(bgp
, es
, new_select
->attr
->nexthop
,
156 true /*esr */, new_select
->attr
->df_alg
,
157 new_select
->attr
->df_pref
);
159 if (old_select
&& old_select
->type
== ZEBRA_ROUTE_BGP
160 && old_select
->sub_type
== BGP_ROUTE_IMPORTED
)
161 bgp_evpn_es_vtep_del(
162 bgp
, es
, old_select
->attr
->nexthop
,
166 /* Clear any route change flags. */
167 bgp_zebra_clear_route_change_flags(dest
);
169 /* Reap old select bgp_path_info, if it has been removed */
170 if (old_select
&& CHECK_FLAG(old_select
->flags
, BGP_PATH_REMOVED
))
171 bgp_path_info_reap(dest
, old_select
);
176 /* Install Type-1/Type-4 route entry in the per-ES routing table */
177 static int bgp_evpn_es_route_install(struct bgp
*bgp
,
178 struct bgp_evpn_es
*es
, struct prefix_evpn
*p
,
179 struct bgp_path_info
*parent_pi
)
182 struct bgp_dest
*dest
= NULL
;
183 struct bgp_path_info
*pi
= NULL
;
184 struct attr
*attr_new
= NULL
;
186 /* Create (or fetch) route within the VNI.
187 * NOTE: There is no RD here.
189 dest
= bgp_node_get(es
->route_table
, (struct prefix
*)p
);
191 /* Check if route entry is already present. */
192 for (pi
= bgp_dest_get_bgp_path_info(dest
); pi
; pi
= pi
->next
)
194 && (struct bgp_path_info
*)pi
->extra
->parent
==
199 /* Add (or update) attribute to hash. */
200 attr_new
= bgp_attr_intern(parent_pi
->attr
);
202 /* Create new route with its attribute. */
203 pi
= info_make(parent_pi
->type
, BGP_ROUTE_IMPORTED
, 0,
204 parent_pi
->peer
, attr_new
, dest
);
205 SET_FLAG(pi
->flags
, BGP_PATH_VALID
);
206 bgp_path_info_extra_get(pi
);
207 pi
->extra
->parent
= bgp_path_info_lock(parent_pi
);
208 bgp_dest_lock_node((struct bgp_dest
*)parent_pi
->net
);
209 bgp_path_info_add(dest
, pi
);
211 if (attrhash_cmp(pi
->attr
, parent_pi
->attr
)
212 && !CHECK_FLAG(pi
->flags
, BGP_PATH_REMOVED
)) {
213 bgp_dest_unlock_node(dest
);
216 /* The attribute has changed. */
217 /* Add (or update) attribute to hash. */
218 attr_new
= bgp_attr_intern(parent_pi
->attr
);
220 /* Restore route, if needed. */
221 if (CHECK_FLAG(pi
->flags
, BGP_PATH_REMOVED
))
222 bgp_path_info_restore(dest
, pi
);
224 /* Mark if nexthop has changed. */
225 if (!IPV4_ADDR_SAME(&pi
->attr
->nexthop
, &attr_new
->nexthop
))
226 SET_FLAG(pi
->flags
, BGP_PATH_IGP_CHANGED
);
228 /* Unintern existing, set to new. */
229 bgp_attr_unintern(&pi
->attr
);
231 pi
->uptime
= bgp_clock();
234 /* Perform route selection and update zebra, if required. */
235 ret
= bgp_evpn_es_route_select_install(bgp
, es
, dest
);
237 bgp_dest_unlock_node(dest
);
242 /* Uninstall Type-1/Type-4 route entry from the ES routing table */
243 static int bgp_evpn_es_route_uninstall(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
244 struct prefix_evpn
*p
, struct bgp_path_info
*parent_pi
)
247 struct bgp_dest
*dest
;
248 struct bgp_path_info
*pi
;
250 if (!es
->route_table
)
253 /* Locate route within the ESI.
254 * NOTE: There is no RD here.
256 dest
= bgp_node_lookup(es
->route_table
, (struct prefix
*)p
);
260 /* Find matching route entry. */
261 for (pi
= bgp_dest_get_bgp_path_info(dest
); pi
; pi
= pi
->next
)
263 && (struct bgp_path_info
*)pi
->extra
->parent
==
270 /* Mark entry for deletion */
271 bgp_path_info_delete(dest
, pi
);
273 /* Perform route selection and update zebra, if required. */
274 ret
= bgp_evpn_es_route_select_install(bgp
, es
, dest
);
276 /* Unlock route node. */
277 bgp_dest_unlock_node(dest
);
282 /* Install or unistall a Tyoe-4 route in the per-ES routing table */
283 int bgp_evpn_es_route_install_uninstall(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
284 afi_t afi
, safi_t safi
, struct prefix_evpn
*evp
,
285 struct bgp_path_info
*pi
, int install
)
290 ret
= bgp_evpn_es_route_install(bgp
, es
, evp
, pi
);
292 ret
= bgp_evpn_es_route_uninstall(bgp
, es
, evp
, pi
);
297 "%u: Failed to %s EVPN %s route in ESI %s",
299 install
? "install" : "uninstall",
306 /* Delete (and withdraw) local routes for specified ES from global and ES table.
307 * Also remove all remote routes from the per ES table. Invoked when ES
310 static void bgp_evpn_es_route_del_all(struct bgp
*bgp
, struct bgp_evpn_es
*es
)
312 struct bgp_dest
*dest
;
313 struct bgp_path_info
*pi
, *nextpi
;
315 /* de-activate the ES */
316 bgp_evpn_local_es_down(bgp
, es
);
317 bgp_evpn_local_type1_evi_route_del(bgp
, es
);
319 /* Walk this ES's routing table and delete all routes. */
320 for (dest
= bgp_table_top(es
->route_table
); dest
;
321 dest
= bgp_route_next(dest
)) {
322 for (pi
= bgp_dest_get_bgp_path_info(dest
);
323 (pi
!= NULL
) && (nextpi
= pi
->next
, 1); pi
= nextpi
) {
324 bgp_path_info_delete(dest
, pi
);
325 bgp_path_info_reap(dest
, pi
);
330 /*****************************************************************************
331 * Base APIs for creating MH routes (Type-1 or Type-4) on local ethernet
335 /* create or update local EVPN type1/type4 route entry.
338 * the ES table if ESR/EAD-ES (or)
339 * the VNI table if EAD-EVI (or)
340 * the global table if ESR/EAD-ES/EAD-EVI
342 * Note: vpn is applicable only to EAD-EVI routes (NULL for EAD-ES and
345 static int bgp_evpn_mh_route_update(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
346 struct bgpevpn
*vpn
, afi_t afi
, safi_t safi
,
347 struct bgp_dest
*dest
, struct attr
*attr
,
348 int add
, struct bgp_path_info
**ri
,
351 struct bgp_path_info
*tmp_pi
= NULL
;
352 struct bgp_path_info
*local_pi
= NULL
; /* local route entry if any */
353 struct bgp_path_info
*remote_pi
= NULL
; /* remote route entry if any */
354 struct attr
*attr_new
= NULL
;
355 struct prefix_evpn
*evp
;
358 evp
= (struct prefix_evpn
*)bgp_dest_get_prefix(dest
);
361 /* locate the local and remote entries if any */
362 for (tmp_pi
= bgp_dest_get_bgp_path_info(dest
); tmp_pi
;
363 tmp_pi
= tmp_pi
->next
) {
364 if (tmp_pi
->peer
== bgp
->peer_self
365 && tmp_pi
->type
== ZEBRA_ROUTE_BGP
366 && tmp_pi
->sub_type
== BGP_ROUTE_STATIC
)
368 if (tmp_pi
->type
== ZEBRA_ROUTE_BGP
369 && tmp_pi
->sub_type
== BGP_ROUTE_IMPORTED
370 && CHECK_FLAG(tmp_pi
->flags
, BGP_PATH_VALID
))
374 /* we don't expect to see a remote_ri at this point as
375 * an ES route has {esi, vtep_ip} as the key in the ES-rt-table
376 * in the VNI-rt-table.
381 "%u ERROR: local es route for ESI: %s Vtep %pI4 also learnt from remote",
382 bgp
->vrf_id
, es
->esi_str
, &es
->originator_ip
);
386 if (!local_pi
&& !add
)
389 /* create or update the entry */
392 /* Add or update attribute to hash */
393 attr_new
= bgp_attr_intern(attr
);
395 /* Create new route with its attribute. */
396 tmp_pi
= info_make(ZEBRA_ROUTE_BGP
, BGP_ROUTE_STATIC
, 0,
397 bgp
->peer_self
, attr_new
, dest
);
398 SET_FLAG(tmp_pi
->flags
, BGP_PATH_VALID
);
400 if (evp
->prefix
.route_type
== BGP_EVPN_AD_ROUTE
) {
401 bgp_path_info_extra_get(tmp_pi
);
402 tmp_pi
->extra
->num_labels
= 1;
404 vni2label(vpn
->vni
, &tmp_pi
->extra
->label
[0]);
406 tmp_pi
->extra
->label
[0] = 0;
409 /* add the newly created path to the route-node */
410 bgp_path_info_add(dest
, tmp_pi
);
413 if (attrhash_cmp(tmp_pi
->attr
, attr
)
414 && !CHECK_FLAG(tmp_pi
->flags
, BGP_PATH_REMOVED
))
417 /* The attribute has changed.
418 * Add (or update) attribute to hash.
420 attr_new
= bgp_attr_intern(attr
);
421 bgp_path_info_set_flag(dest
, tmp_pi
,
422 BGP_PATH_ATTR_CHANGED
);
424 /* Restore route, if needed. */
425 if (CHECK_FLAG(tmp_pi
->flags
, BGP_PATH_REMOVED
))
426 bgp_path_info_restore(dest
, tmp_pi
);
428 /* Unintern existing, set to new. */
429 bgp_attr_unintern(&tmp_pi
->attr
);
430 tmp_pi
->attr
= attr_new
;
431 tmp_pi
->uptime
= bgp_clock();
435 if (*route_changed
) {
436 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
438 "local ES %s vni %u route-type %s nexthop %pI4 updated",
439 es
->esi_str
, vpn
? vpn
->vni
: 0,
440 evp
->prefix
.route_type
== BGP_EVPN_ES_ROUTE
442 : (vpn
? "ead-evi" : "ead-es"),
443 &attr
->mp_nexthop_global_in
);
446 /* Return back the route entry. */
451 /* Delete local EVPN ESR (type-4) and EAD (type-1) route
453 * Note: vpn is applicable only to EAD-EVI routes (NULL for EAD-ES and
456 static int bgp_evpn_mh_route_delete(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
457 struct bgpevpn
*vpn
, struct prefix_evpn
*p
)
459 afi_t afi
= AFI_L2VPN
;
460 safi_t safi
= SAFI_EVPN
;
461 struct bgp_path_info
*pi
;
462 struct bgp_dest
*dest
= NULL
; /* dest in esi table */
463 struct bgp_dest
*global_dest
= NULL
; /* dest in global table */
464 struct bgp_table
*rt_table
;
465 struct prefix_rd
*prd
;
468 rt_table
= vpn
->route_table
;
471 rt_table
= es
->route_table
;
475 /* First, locate the route node within the ESI or VNI.
476 * If it doesn't exist, ther is nothing to do.
477 * Note: there is no RD here.
479 dest
= bgp_node_lookup(rt_table
, (struct prefix
*)p
);
483 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
485 "local ES %s vni %u route-type %s nexthop %pI4 delete",
486 es
->esi_str
, vpn
? vpn
->vni
: 0,
487 p
->prefix
.route_type
== BGP_EVPN_ES_ROUTE
489 : (vpn
? "ead-evi" : "ead-es"),
492 /* Next, locate route node in the global EVPN routing table.
493 * Note that this table is a 2-level tree (RD-level + Prefix-level)
496 bgp_global_evpn_node_lookup(bgp
->rib
[afi
][safi
], afi
, safi
,
497 (const struct prefix_evpn
*)p
, prd
);
500 /* Delete route entry in the global EVPN table. */
501 delete_evpn_route_entry(bgp
, afi
, safi
, global_dest
, &pi
);
503 /* Schedule for processing - withdraws to peers happen from
507 bgp_process(bgp
, global_dest
, afi
, safi
);
508 bgp_dest_unlock_node(global_dest
);
512 * Delete route entry in the ESI or VNI routing table.
513 * This can just be removed.
515 delete_evpn_route_entry(bgp
, afi
, safi
, dest
, &pi
);
517 bgp_path_info_reap(dest
, pi
);
518 bgp_dest_unlock_node(dest
);
522 /*****************************************************************************
523 * Ethernet Segment (Type-4) Routes
524 * ESRs are used for DF election. Currently service-carving described in
525 * RFC 7432 is NOT supported. Instead preference based DF election is
527 * Reference: draft-ietf-bess-evpn-pref-df
529 /* Build extended community for EVPN ES (type-4) route */
530 static void bgp_evpn_type4_route_extcomm_build(struct bgp_evpn_es
*es
,
533 struct ecommunity ecom_encap
;
534 struct ecommunity ecom_es_rt
;
535 struct ecommunity ecom_df
;
536 struct ecommunity_val eval
;
537 struct ecommunity_val eval_es_rt
;
538 struct ecommunity_val eval_df
;
539 bgp_encap_types tnl_type
;
543 tnl_type
= BGP_ENCAP_TYPE_VXLAN
;
544 memset(&ecom_encap
, 0, sizeof(ecom_encap
));
545 encode_encap_extcomm(tnl_type
, &eval
);
547 ecom_encap
.unit_size
= ECOMMUNITY_SIZE
;
548 ecom_encap
.val
= (uint8_t *)eval
.val
;
549 attr
->ecommunity
= ecommunity_dup(&ecom_encap
);
552 memset(&mac
, 0, sizeof(struct ethaddr
));
553 memset(&ecom_es_rt
, 0, sizeof(ecom_es_rt
));
554 es_get_system_mac(&es
->esi
, &mac
);
555 encode_es_rt_extcomm(&eval_es_rt
, &mac
);
557 ecom_es_rt
.unit_size
= ECOMMUNITY_SIZE
;
558 ecom_es_rt
.val
= (uint8_t *)eval_es_rt
.val
;
560 ecommunity_merge(attr
->ecommunity
, &ecom_es_rt
);
562 /* DF election extended community */
563 memset(&ecom_df
, 0, sizeof(ecom_df
));
564 encode_df_elect_extcomm(&eval_df
, es
->df_pref
);
566 ecom_df
.val
= (uint8_t *)eval_df
.val
;
567 attr
->ecommunity
= ecommunity_merge(attr
->ecommunity
, &ecom_df
);
569 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES
);
572 /* Create or update local type-4 route */
573 static int bgp_evpn_type4_route_update(struct bgp
*bgp
,
574 struct bgp_evpn_es
*es
, struct prefix_evpn
*p
)
577 int route_changed
= 0;
578 afi_t afi
= AFI_L2VPN
;
579 safi_t safi
= SAFI_EVPN
;
581 struct attr
*attr_new
= NULL
;
582 struct bgp_dest
*dest
= NULL
;
583 struct bgp_path_info
*pi
= NULL
;
585 memset(&attr
, 0, sizeof(struct attr
));
587 /* Build path-attribute for this route. */
588 bgp_attr_default_set(&attr
, BGP_ORIGIN_IGP
);
589 attr
.nexthop
= es
->originator_ip
;
590 attr
.mp_nexthop_global_in
= es
->originator_ip
;
591 attr
.mp_nexthop_len
= BGP_ATTR_NHLEN_IPV4
;
593 /* Set up extended community. */
594 bgp_evpn_type4_route_extcomm_build(es
, &attr
);
596 /* First, create (or fetch) route node within the ESI. */
597 /* NOTE: There is no RD here. */
598 dest
= bgp_node_get(es
->route_table
, (struct prefix
*)p
);
600 /* Create or update route entry. */
601 ret
= bgp_evpn_mh_route_update(bgp
, es
, NULL
, afi
, safi
, dest
, &attr
, 1,
602 &pi
, &route_changed
);
606 "%u ERROR: Failed to updated ES route ESI: %s VTEP %pI4",
607 bgp
->vrf_id
, es
->esi_str
, &es
->originator_ip
);
612 /* Perform route selection;
613 * this is just to set the flags correctly
614 * as local route in the ES always wins.
616 bgp_evpn_es_route_select_install(bgp
, es
, dest
);
617 bgp_dest_unlock_node(dest
);
619 /* If this is a new route or some attribute has changed, export the
620 * route to the global table. The route will be advertised to peers
621 * from there. Note that this table is a 2-level tree (RD-level +
622 * Prefix-level) similar to L3VPN routes.
625 struct bgp_path_info
*global_pi
;
627 dest
= bgp_global_evpn_node_get(bgp
->rib
[afi
][safi
], afi
, safi
,
629 bgp_evpn_mh_route_update(bgp
, es
, NULL
, afi
, safi
, dest
,
630 attr_new
, 1, &global_pi
,
633 /* Schedule for processing and unlock node. */
634 bgp_process(bgp
, dest
, afi
, safi
);
635 bgp_dest_unlock_node(dest
);
638 /* Unintern temporary. */
639 aspath_unintern(&attr
.aspath
);
643 /* Delete local type-4 route */
644 static int bgp_evpn_type4_route_delete(struct bgp
*bgp
,
645 struct bgp_evpn_es
*es
, struct prefix_evpn
*p
)
647 return bgp_evpn_mh_route_delete(bgp
, es
, NULL
/* l2vni */, p
);
650 /* Process remote/received EVPN type-4 route (advertise or withdraw) */
651 int bgp_evpn_type4_route_process(struct peer
*peer
, afi_t afi
, safi_t safi
,
652 struct attr
*attr
, uint8_t *pfx
, int psize
,
658 struct in_addr vtep_ip
;
659 struct prefix_rd prd
;
660 struct prefix_evpn p
;
662 /* Type-4 route should be either 23 or 35 bytes
663 * RD (8), ESI (10), ip-len (1), ip (4 or 16)
665 if (psize
!= BGP_EVPN_TYPE4_V4_PSIZE
&&
666 psize
!= BGP_EVPN_TYPE4_V6_PSIZE
) {
667 flog_err(EC_BGP_EVPN_ROUTE_INVALID
,
668 "%u:%s - Rx EVPN Type-4 NLRI with invalid length %d",
669 peer
->bgp
->vrf_id
, peer
->host
, psize
);
674 prd
.family
= AF_UNSPEC
;
676 memcpy(&prd
.val
, pfx
, RD_BYTES
);
680 memcpy(&esi
, pfx
, ESI_BYTES
);
686 if (ipaddr_len
== IPV4_MAX_BITLEN
) {
687 memcpy(&vtep_ip
, pfx
, IPV4_MAX_BYTELEN
);
690 EC_BGP_EVPN_ROUTE_INVALID
,
691 "%u:%s - Rx EVPN Type-4 NLRI with unsupported IP address length %d",
692 peer
->bgp
->vrf_id
, peer
->host
, ipaddr_len
);
696 build_evpn_type4_prefix(&p
, &esi
, vtep_ip
);
697 /* Process the route. */
699 ret
= bgp_update(peer
, (struct prefix
*)&p
, addpath_id
, attr
,
700 afi
, safi
, ZEBRA_ROUTE_BGP
, BGP_ROUTE_NORMAL
,
701 &prd
, NULL
, 0, 0, NULL
);
703 ret
= bgp_withdraw(peer
, (struct prefix
*)&p
, addpath_id
, attr
,
704 afi
, safi
, ZEBRA_ROUTE_BGP
, BGP_ROUTE_NORMAL
,
705 &prd
, NULL
, 0, NULL
);
710 /* Check if a prefix belongs to the local ES */
711 static bool bgp_evpn_type4_prefix_match(struct prefix_evpn
*p
,
712 struct bgp_evpn_es
*es
)
714 return (p
->prefix
.route_type
== BGP_EVPN_ES_ROUTE
) &&
715 !memcmp(&p
->prefix
.es_addr
.esi
, &es
->esi
, sizeof(esi_t
));
718 /* Import remote ESRs on local ethernet segment add */
719 static int bgp_evpn_type4_remote_routes_import(struct bgp
*bgp
,
720 struct bgp_evpn_es
*es
, bool install
)
725 struct bgp_dest
*rd_dest
, *dest
;
726 struct bgp_table
*table
;
727 struct bgp_path_info
*pi
;
732 /* Walk entire global routing table and evaluate routes which could be
733 * imported into this Ethernet Segment.
735 for (rd_dest
= bgp_table_top(bgp
->rib
[afi
][safi
]); rd_dest
;
736 rd_dest
= bgp_route_next(rd_dest
)) {
737 table
= bgp_dest_get_bgp_table_info(rd_dest
);
741 for (dest
= bgp_table_top(table
); dest
;
742 dest
= bgp_route_next(dest
)) {
743 struct prefix_evpn
*evp
=
744 (struct prefix_evpn
*)bgp_dest_get_prefix(dest
);
746 for (pi
= bgp_dest_get_bgp_path_info(dest
); pi
;
749 * Consider "valid" remote routes applicable for
752 if (!(CHECK_FLAG(pi
->flags
, BGP_PATH_VALID
)
753 && pi
->type
== ZEBRA_ROUTE_BGP
754 && pi
->sub_type
== BGP_ROUTE_NORMAL
))
757 if (!bgp_evpn_type4_prefix_match(evp
, es
))
761 ret
= bgp_evpn_es_route_install(
764 ret
= bgp_evpn_es_route_uninstall(
770 "Failed to %s EVPN %pFX route in ESI %s",
775 bgp_dest_unlock_node(rd_dest
);
776 bgp_dest_unlock_node(dest
);
785 /*****************************************************************************
786 * Ethernet Auto Discovery (EAD/Type-1) route handling
787 * There are two types of EAD routes -
788 * 1. EAD-per-ES - Key: {ESI, ET=0xffffffff}
789 * 2. EAD-per-EVI - Key: {ESI, ET=0}
792 /* Extended communities associated with EAD-per-ES */
793 static void bgp_evpn_type1_es_route_extcomm_build(struct bgp_evpn_es
*es
,
796 struct ecommunity ecom_encap
;
797 struct ecommunity ecom_esi_label
;
798 struct ecommunity_val eval
;
799 struct ecommunity_val eval_esi_label
;
800 bgp_encap_types tnl_type
;
801 struct listnode
*evi_node
, *rt_node
;
802 struct ecommunity
*ecom
;
803 struct bgp_evpn_es_evi
*es_evi
;
806 tnl_type
= BGP_ENCAP_TYPE_VXLAN
;
807 memset(&ecom_encap
, 0, sizeof(ecom_encap
));
808 encode_encap_extcomm(tnl_type
, &eval
);
810 ecom_encap
.unit_size
= ECOMMUNITY_SIZE
;
811 ecom_encap
.val
= (uint8_t *)eval
.val
;
812 attr
->ecommunity
= ecommunity_dup(&ecom_encap
);
815 encode_esi_label_extcomm(&eval_esi_label
,
816 false /*single_active*/);
817 ecom_esi_label
.size
= 1;
818 ecom_esi_label
.unit_size
= ECOMMUNITY_SIZE
;
819 ecom_esi_label
.val
= (uint8_t *)eval_esi_label
.val
;
821 ecommunity_merge(attr
->ecommunity
, &ecom_esi_label
);
823 /* Add export RTs for all L2-VNIs associated with this ES */
824 /* XXX - suppress EAD-ES advertisment if there are no EVIs associated
827 for (ALL_LIST_ELEMENTS_RO(es
->es_evi_list
,
829 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
831 for (ALL_LIST_ELEMENTS_RO(es_evi
->vpn
->export_rtl
,
833 attr
->ecommunity
= ecommunity_merge(attr
->ecommunity
,
837 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES
);
840 /* Extended communities associated with EAD-per-EVI */
841 static void bgp_evpn_type1_evi_route_extcomm_build(struct bgp_evpn_es
*es
,
842 struct bgpevpn
*vpn
, struct attr
*attr
)
844 struct ecommunity ecom_encap
;
845 struct ecommunity_val eval
;
846 bgp_encap_types tnl_type
;
847 struct listnode
*rt_node
;
848 struct ecommunity
*ecom
;
851 tnl_type
= BGP_ENCAP_TYPE_VXLAN
;
852 memset(&ecom_encap
, 0, sizeof(ecom_encap
));
853 encode_encap_extcomm(tnl_type
, &eval
);
855 ecom_encap
.unit_size
= ECOMMUNITY_SIZE
;
856 ecom_encap
.val
= (uint8_t *)eval
.val
;
857 attr
->ecommunity
= ecommunity_dup(&ecom_encap
);
859 /* Add export RTs for the L2-VNI */
860 for (ALL_LIST_ELEMENTS_RO(vpn
->export_rtl
, rt_node
, ecom
))
861 attr
->ecommunity
= ecommunity_merge(attr
->ecommunity
, ecom
);
863 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES
);
866 /* Update EVPN EAD (type-1) route -
867 * vpn - valid for EAD-EVI routes and NULL for EAD-ES routes
869 static int bgp_evpn_type1_route_update(struct bgp
*bgp
,
870 struct bgp_evpn_es
*es
, struct bgpevpn
*vpn
,
871 struct prefix_evpn
*p
)
874 afi_t afi
= AFI_L2VPN
;
875 safi_t safi
= SAFI_EVPN
;
877 struct attr
*attr_new
= NULL
;
878 struct bgp_dest
*dest
= NULL
;
879 struct bgp_path_info
*pi
= NULL
;
880 int route_changed
= 0;
881 struct prefix_rd
*global_rd
;
883 memset(&attr
, 0, sizeof(struct attr
));
885 /* Build path-attribute for this route. */
886 bgp_attr_default_set(&attr
, BGP_ORIGIN_IGP
);
887 attr
.nexthop
= es
->originator_ip
;
888 attr
.mp_nexthop_global_in
= es
->originator_ip
;
889 attr
.mp_nexthop_len
= BGP_ATTR_NHLEN_IPV4
;
892 /* EAD-EVI route update */
894 vni2label(vpn
->vni
, &(attr
.label
));
896 /* Set up extended community */
897 bgp_evpn_type1_evi_route_extcomm_build(es
, vpn
, &attr
);
899 /* First, create (or fetch) route node within the VNI. */
900 dest
= bgp_node_get(vpn
->route_table
, (struct prefix
*)p
);
902 /* Create or update route entry. */
903 ret
= bgp_evpn_mh_route_update(bgp
, es
, vpn
, afi
, safi
, dest
,
904 &attr
, 1, &pi
, &route_changed
);
908 "%u Failed to update EAD-EVI route ESI: %s VNI %u VTEP %pI4",
909 bgp
->vrf_id
, es
->esi_str
, vpn
->vni
,
911 global_rd
= &vpn
->prd
;
913 /* EAD-ES route update */
914 /* MPLS label is 0 for EAD-ES route */
916 /* Set up extended community */
917 bgp_evpn_type1_es_route_extcomm_build(es
, &attr
);
919 /* First, create (or fetch) route node within the ES. */
920 /* NOTE: There is no RD here. */
921 /* XXX: fragment ID must be included as a part of the prefix. */
922 dest
= bgp_node_get(es
->route_table
, (struct prefix
*)p
);
924 /* Create or update route entry. */
925 ret
= bgp_evpn_mh_route_update(bgp
, es
, vpn
, afi
, safi
, dest
,
926 &attr
, 1, &pi
, &route_changed
);
930 "%u ERROR: Failed to updated EAD-EVI route ESI: %s VTEP %pI4",
931 bgp
->vrf_id
, es
->esi_str
, &es
->originator_ip
);
933 global_rd
= &es
->prd
;
940 /* Perform route selection;
941 * this is just to set the flags correctly as local route in
942 * the ES always wins.
944 evpn_route_select_install(bgp
, vpn
, dest
);
945 bgp_dest_unlock_node(dest
);
947 /* If this is a new route or some attribute has changed, export the
948 * route to the global table. The route will be advertised to peers
949 * from there. Note that this table is a 2-level tree (RD-level +
950 * Prefix-level) similar to L3VPN routes.
953 struct bgp_path_info
*global_pi
;
955 dest
= bgp_global_evpn_node_get(bgp
->rib
[afi
][safi
], afi
, safi
,
957 bgp_evpn_mh_route_update(bgp
, es
, vpn
, afi
, safi
, dest
,
958 attr_new
, 1, &global_pi
,
961 /* Schedule for processing and unlock node. */
962 bgp_process(bgp
, dest
, afi
, safi
);
963 bgp_dest_unlock_node(dest
);
966 /* Unintern temporary. */
967 aspath_unintern(&attr
.aspath
);
971 /* Delete local Type-1 route */
972 static int bgp_evpn_type1_es_route_delete(struct bgp
*bgp
,
973 struct bgp_evpn_es
*es
, struct prefix_evpn
*p
)
975 return bgp_evpn_mh_route_delete(bgp
, es
, NULL
/* l2vni */, p
);
978 static int bgp_evpn_type1_evi_route_delete(struct bgp
*bgp
,
979 struct bgp_evpn_es
*es
, struct bgpevpn
*vpn
,
980 struct prefix_evpn
*p
)
982 return bgp_evpn_mh_route_delete(bgp
, es
, vpn
, p
);
985 /* Generate EAD-EVI for all VNIs */
986 static void bgp_evpn_local_type1_evi_route_add(struct bgp
*bgp
,
987 struct bgp_evpn_es
*es
)
989 struct listnode
*evi_node
;
990 struct prefix_evpn p
;
991 struct bgp_evpn_es_evi
*es_evi
;
993 /* EAD-per-EVI routes have been suppressed */
994 if (!bgp_mh_info
->ead_evi_tx
)
997 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
))
998 /* EAD-EVI route add for this ES is already done */
1001 SET_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
);
1002 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_EVI_ETH_TAG
,
1003 &es
->esi
, es
->originator_ip
);
1005 for (ALL_LIST_ELEMENTS_RO(es
->es_evi_list
, evi_node
, es_evi
)) {
1006 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
1008 if (bgp_evpn_type1_route_update(bgp
, es
, es_evi
->vpn
, &p
))
1009 flog_err(EC_BGP_EVPN_ROUTE_CREATE
,
1010 "%u: Type4 route creation failure for ESI %s",
1011 bgp
->vrf_id
, es
->esi_str
);
1016 * Withdraw EAD-EVI for all VNIs
1018 static void bgp_evpn_local_type1_evi_route_del(struct bgp
*bgp
,
1019 struct bgp_evpn_es
*es
)
1021 struct listnode
*evi_node
;
1022 struct prefix_evpn p
;
1023 struct bgp_evpn_es_evi
*es_evi
;
1025 /* Delete and withdraw locally learnt EAD-EVI route */
1026 if (!CHECK_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
))
1027 /* EAD-EVI route has not been advertised for this ES */
1030 UNSET_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
);
1031 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_EVI_ETH_TAG
,
1032 &es
->esi
, es
->originator_ip
);
1033 for (ALL_LIST_ELEMENTS_RO(es
->es_evi_list
, evi_node
, es_evi
)) {
1034 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
1036 if (bgp_evpn_mh_route_delete(bgp
, es
, es_evi
->vpn
, &p
))
1037 flog_err(EC_BGP_EVPN_ROUTE_CREATE
,
1038 "%u: Type4 route creation failure for ESI %s",
1039 bgp
->vrf_id
, es
->esi_str
);
1044 * Process received EVPN type-1 route (advertise or withdraw).
1046 int bgp_evpn_type1_route_process(struct peer
*peer
, afi_t afi
, safi_t safi
,
1047 struct attr
*attr
, uint8_t *pfx
, int psize
,
1048 uint32_t addpath_id
)
1051 struct prefix_rd prd
;
1055 struct in_addr vtep_ip
;
1056 struct prefix_evpn p
;
1058 if (psize
!= BGP_EVPN_TYPE1_PSIZE
) {
1059 flog_err(EC_BGP_EVPN_ROUTE_INVALID
,
1060 "%u:%s - Rx EVPN Type-1 NLRI with invalid length %d",
1061 peer
->bgp
->vrf_id
, peer
->host
, psize
);
1065 /* Make prefix_rd */
1066 prd
.family
= AF_UNSPEC
;
1068 memcpy(&prd
.val
, pfx
, RD_BYTES
);
1072 memcpy(&esi
, pfx
, ESI_BYTES
);
1075 /* Copy Ethernet Tag */
1076 memcpy(ð_tag
, pfx
, EVPN_ETH_TAG_BYTES
);
1077 eth_tag
= ntohl(eth_tag
);
1078 pfx
+= EVPN_ETH_TAG_BYTES
;
1080 memcpy(&label
, pfx
, BGP_LABEL_BYTES
);
1082 /* EAD route prefix doesn't include the nexthop in the global
1086 build_evpn_type1_prefix(&p
, eth_tag
, &esi
, vtep_ip
);
1087 /* Process the route. */
1089 ret
= bgp_update(peer
, (struct prefix
*)&p
, addpath_id
, attr
,
1090 afi
, safi
, ZEBRA_ROUTE_BGP
, BGP_ROUTE_NORMAL
,
1091 &prd
, NULL
, 0, 0, NULL
);
1093 ret
= bgp_withdraw(peer
, (struct prefix
*)&p
, addpath_id
, attr
,
1094 afi
, safi
, ZEBRA_ROUTE_BGP
, BGP_ROUTE_NORMAL
,
1095 &prd
, NULL
, 0, NULL
);
1100 /*****************************************************************************/
1101 /* Ethernet Segment Management
1102 * 1. Ethernet Segment is a collection of links attached to the same
1103 * server (MHD) or switch (MHN)
1104 * 2. An Ethernet Segment can span multiple PEs and is identified by the
1106 * 3. Local ESs are configured in zebra and sent to BGP
1107 * 4. Remote ESs are created by BGP when one or more ES-EVIs reference it i.e.
1108 * created on first reference and release on last de-reference
1109 * 5. An ES can be both local and remote. Infact most local ESs are expected
1110 * to have an ES peer.
1113 /* A list of remote VTEPs is maintained for each ES. This list includes -
1114 * 1. VTEPs for which we have imported the ESR i.e. ES-peers
1115 * 2. VTEPs that have an "active" ES-EVI VTEP i.e. EAD-per-ES and EAD-per-EVI
1116 * have been imported into one or more VNIs
1118 static int bgp_evpn_es_vtep_cmp(void *p1
, void *p2
)
1120 const struct bgp_evpn_es_vtep
*es_vtep1
= p1
;
1121 const struct bgp_evpn_es_vtep
*es_vtep2
= p2
;
1123 return es_vtep1
->vtep_ip
.s_addr
- es_vtep2
->vtep_ip
.s_addr
;
1126 static struct bgp_evpn_es_vtep
*bgp_evpn_es_vtep_new(struct bgp_evpn_es
*es
,
1127 struct in_addr vtep_ip
)
1129 struct bgp_evpn_es_vtep
*es_vtep
;
1131 es_vtep
= XCALLOC(MTYPE_BGP_EVPN_ES_VTEP
, sizeof(*es_vtep
));
1134 es_vtep
->vtep_ip
.s_addr
= vtep_ip
.s_addr
;
1135 listnode_init(&es_vtep
->es_listnode
, es_vtep
);
1136 listnode_add_sort(es
->es_vtep_list
, &es_vtep
->es_listnode
);
1141 static void bgp_evpn_es_vtep_free(struct bgp_evpn_es_vtep
*es_vtep
)
1143 struct bgp_evpn_es
*es
= es_vtep
->es
;
1145 if (CHECK_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ESR
) ||
1147 /* as long as there is some reference we can't free it */
1150 list_delete_node(es
->es_vtep_list
, &es_vtep
->es_listnode
);
1151 XFREE(MTYPE_BGP_EVPN_ES_VTEP
, es_vtep
);
1154 /* check if VTEP is already part of the list */
1155 static struct bgp_evpn_es_vtep
*bgp_evpn_es_vtep_find(struct bgp_evpn_es
*es
,
1156 struct in_addr vtep_ip
)
1158 struct listnode
*node
= NULL
;
1159 struct bgp_evpn_es_vtep
*es_vtep
;
1161 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
1162 if (es_vtep
->vtep_ip
.s_addr
== vtep_ip
.s_addr
)
1168 /* Send the remote ES to zebra for NHG programming */
1169 static int bgp_zebra_send_remote_es_vtep(struct bgp
*bgp
,
1170 struct bgp_evpn_es_vtep
*es_vtep
, bool add
)
1172 struct bgp_evpn_es
*es
= es_vtep
->es
;
1177 if (!zclient
|| zclient
->sock
< 0)
1180 /* Don't try to register if Zebra doesn't know of this instance. */
1181 if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp
)) {
1182 if (BGP_DEBUG(zebra
, ZEBRA
))
1183 zlog_debug("No zebra instance, not installing remote es %s",
1188 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ESR
)
1189 flags
|= ZAPI_ES_VTEP_FLAG_ESR_RXED
;
1194 zclient_create_header(s
,
1195 add
? ZEBRA_REMOTE_ES_VTEP_ADD
: ZEBRA_REMOTE_ES_VTEP_DEL
,
1197 stream_put(s
, &es
->esi
, sizeof(esi_t
));
1198 stream_put_ipv4(s
, es_vtep
->vtep_ip
.s_addr
);
1200 stream_putl(s
, flags
);
1201 stream_putc(s
, es_vtep
->df_alg
);
1202 stream_putw(s
, es_vtep
->df_pref
);
1205 stream_putw_at(s
, 0, stream_get_endp(s
));
1207 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1208 zlog_debug("Tx %s Remote ESI %s VTEP %pI4", add
? "ADD" : "DEL",
1209 es
->esi_str
, &es_vtep
->vtep_ip
);
1211 return zclient_send_message(zclient
);
1214 static void bgp_evpn_es_vtep_re_eval_active(struct bgp
*bgp
,
1215 struct bgp_evpn_es_vtep
*es_vtep
,
1221 old_active
= !!CHECK_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
);
1222 /* currently we need an active EVI reference to use the VTEP as
1223 * a nexthop. this may change...
1225 if (es_vtep
->evi_cnt
)
1226 SET_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
);
1228 UNSET_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
);
1230 new_active
= !!CHECK_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
);
1232 if ((old_active
!= new_active
) || (new_active
&& param_change
)) {
1234 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1235 zlog_debug("es %s vtep %pI4 %s df %u/%u",
1236 es_vtep
->es
->esi_str
, &es_vtep
->vtep_ip
,
1237 new_active
? "active" : "inactive",
1238 es_vtep
->df_alg
, es_vtep
->df_pref
);
1240 /* send remote ES to zebra */
1241 bgp_zebra_send_remote_es_vtep(bgp
, es_vtep
, new_active
);
1243 /* The NHG is updated first for efficient failover handling.
1244 * Note the NHG can be de-activated while there are bgp
1245 * routes referencing it. Zebra is capable of handling that
1246 * elegantly by holding the NHG till all routes using it are
1249 bgp_evpn_l3nhg_update_on_vtep_chg(es_vtep
->es
);
1250 bgp_evpn_es_path_all_update(es_vtep
, new_active
);
1252 /* queue up the es for background consistency checks */
1253 bgp_evpn_es_cons_checks_pend_add(es_vtep
->es
);
1257 static struct bgp_evpn_es_vtep
*bgp_evpn_es_vtep_add(struct bgp
*bgp
,
1258 struct bgp_evpn_es
*es
,
1259 struct in_addr vtep_ip
,
1260 bool esr
, uint8_t df_alg
,
1263 struct bgp_evpn_es_vtep
*es_vtep
;
1264 bool param_change
= false;
1266 es_vtep
= bgp_evpn_es_vtep_find(es
, vtep_ip
);
1269 es_vtep
= bgp_evpn_es_vtep_new(es
, vtep_ip
);
1271 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1272 zlog_debug("es %s vtep %pI4 add %s df %u/%u",
1273 es_vtep
->es
->esi_str
, &es_vtep
->vtep_ip
,
1274 esr
? "esr" : "ead", df_alg
, df_pref
);
1277 SET_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ESR
);
1278 if ((es_vtep
->df_pref
!= df_pref
)
1279 || (es_vtep
->df_alg
!= df_alg
)) {
1280 param_change
= true;
1281 es_vtep
->df_pref
= df_pref
;
1282 es_vtep
->df_alg
= df_alg
;
1288 bgp_evpn_es_vtep_re_eval_active(bgp
, es_vtep
, param_change
);
1293 static void bgp_evpn_es_vtep_do_del(struct bgp
*bgp
,
1294 struct bgp_evpn_es_vtep
*es_vtep
, bool esr
)
1296 bool param_change
= false;
1298 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1299 zlog_debug("es %s vtep %pI4 del %s", es_vtep
->es
->esi_str
,
1300 &es_vtep
->vtep_ip
, esr
? "esr" : "ead");
1302 UNSET_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ESR
);
1303 if (es_vtep
->df_pref
|| es_vtep
->df_alg
) {
1304 param_change
= true;
1305 es_vtep
->df_pref
= 0;
1306 es_vtep
->df_alg
= 0;
1309 if (es_vtep
->evi_cnt
)
1313 bgp_evpn_es_vtep_re_eval_active(bgp
, es_vtep
, param_change
);
1314 bgp_evpn_es_vtep_free(es_vtep
);
1317 static void bgp_evpn_es_vtep_del(struct bgp
*bgp
,
1318 struct bgp_evpn_es
*es
, struct in_addr vtep_ip
, bool esr
)
1320 struct bgp_evpn_es_vtep
*es_vtep
;
1322 es_vtep
= bgp_evpn_es_vtep_find(es
, vtep_ip
);
1324 bgp_evpn_es_vtep_do_del(bgp
, es_vtep
, esr
);
1327 bool bgp_evpn_es_is_vtep_active(esi_t
*esi
, struct in_addr nh
)
1329 struct bgp_evpn_es
*es
;
1330 struct bgp_evpn_es_vtep
*es_vtep
;
1331 struct listnode
*node
= NULL
;
1334 if (!memcmp(esi
, zero_esi
, sizeof(*esi
)) || !nh
.s_addr
)
1337 es
= bgp_evpn_es_find(esi
);
1341 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
1342 if (es_vtep
->vtep_ip
.s_addr
== nh
.s_addr
) {
1343 if (CHECK_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
))
1351 /********************** ES MAC-IP paths *************************************
1352 * MAC-IP routes in the VNI routing table are linked to the destination
1353 * ES for efficient updates on ES changes (such as VTEP add/del).
1354 ****************************************************************************/
1355 void bgp_evpn_path_es_info_free(struct bgp_path_es_info
*es_info
)
1357 bgp_evpn_path_es_unlink(es_info
);
1358 XFREE(MTYPE_BGP_EVPN_PATH_ES_INFO
, es_info
);
1361 static struct bgp_path_es_info
*
1362 bgp_evpn_path_es_info_new(struct bgp_path_info
*pi
, vni_t vni
)
1364 struct bgp_path_info_extra
*e
;
1366 e
= bgp_path_info_extra_get(pi
);
1368 /* If es_info doesn't exist allocate it */
1370 e
->es_info
= XCALLOC(MTYPE_BGP_EVPN_PATH_ES_INFO
,
1371 sizeof(struct bgp_path_es_info
));
1372 e
->es_info
->pi
= pi
;
1373 e
->es_info
->vni
= vni
;
1379 void bgp_evpn_path_es_unlink(struct bgp_path_es_info
*es_info
)
1381 struct bgp_evpn_es
*es
= es_info
->es
;
1382 struct bgp_path_info
*pi
;
1388 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
1389 zlog_debug("vni %u path %pFX unlinked from es %s", es_info
->vni
,
1390 &pi
->net
->p
, es
->esi_str
);
1392 list_delete_node(es
->macip_path_list
, &es_info
->es_listnode
);
1395 /* if there are no other references against the ES it
1398 bgp_evpn_es_free(es
, __func__
);
1400 /* Note we don't free the path es_info on unlink; it will be freed up
1401 * along with the path.
1405 void bgp_evpn_path_es_link(struct bgp_path_info
*pi
, vni_t vni
, esi_t
*esi
)
1407 struct bgp_path_es_info
*es_info
;
1408 struct bgp_evpn_es
*es
;
1409 struct bgp
*bgp_evpn
= bgp_get_evpn();
1411 es_info
= pi
->extra
? pi
->extra
->es_info
: NULL
;
1412 /* if the esi is zero just unlink the path from the old es */
1413 if (!esi
|| !memcmp(esi
, zero_esi
, sizeof(*esi
))) {
1415 bgp_evpn_path_es_unlink(es_info
);
1422 /* setup es_info against the path if it doesn't aleady exist */
1424 es_info
= bgp_evpn_path_es_info_new(pi
, vni
);
1426 /* find-create ES */
1427 es
= bgp_evpn_es_find(esi
);
1429 es
= bgp_evpn_es_new(bgp_evpn
, esi
);
1432 if (es_info
->es
== es
)
1435 /* unlink old ES if any */
1436 bgp_evpn_path_es_unlink(es_info
);
1438 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
1439 zlog_debug("vni %u path %pFX linked to es %s", vni
, &pi
->net
->p
,
1442 /* link mac-ip path to the new destination ES */
1444 listnode_init(&es_info
->es_listnode
, es_info
);
1445 listnode_add(es
->macip_path_list
, &es_info
->es_listnode
);
1448 static void bgp_evpn_es_path_all_update(struct bgp_evpn_es_vtep
*es_vtep
,
1451 struct listnode
*node
;
1452 struct bgp_path_es_info
*es_info
;
1453 struct bgp_path_info
*pi
;
1454 struct bgp_path_info
*parent_pi
;
1455 struct bgp_evpn_es
*es
= es_vtep
->es
;
1456 char prefix_buf
[PREFIX_STRLEN
];
1458 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
1459 zlog_debug("update all paths linked to es %s", es
->esi_str
);
1461 for (ALL_LIST_ELEMENTS_RO(es
->macip_path_list
, node
, es_info
)) {
1463 if (!CHECK_FLAG(pi
->flags
, BGP_PATH_VALID
))
1466 if (pi
->sub_type
!= BGP_ROUTE_IMPORTED
)
1469 parent_pi
= pi
->extra
? pi
->extra
->parent
: NULL
;
1470 if (!parent_pi
|| !parent_pi
->attr
)
1473 if (es_vtep
->vtep_ip
.s_addr
!= parent_pi
->attr
->nexthop
.s_addr
)
1476 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
1477 zlog_debug("update path %s linked to es %s",
1478 prefix2str(&parent_pi
->net
->p
, prefix_buf
,
1479 sizeof(prefix_buf
)),
1481 bgp_evpn_import_route_in_vrfs(parent_pi
, active
? 1 : 0);
1485 /* compare ES-IDs for the global ES RB tree */
1486 static int bgp_es_rb_cmp(const struct bgp_evpn_es
*es1
,
1487 const struct bgp_evpn_es
*es2
)
1489 return memcmp(&es1
->esi
, &es2
->esi
, ESI_BYTES
);
1491 RB_GENERATE(bgp_es_rb_head
, bgp_evpn_es
, rb_node
, bgp_es_rb_cmp
);
1493 struct bgp_evpn_es
*bgp_evpn_es_find(const esi_t
*esi
)
1495 struct bgp_evpn_es tmp
;
1497 memcpy(&tmp
.esi
, esi
, sizeof(esi_t
));
1498 return RB_FIND(bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
, &tmp
);
1501 static struct bgp_evpn_es
*bgp_evpn_es_new(struct bgp
*bgp
, const esi_t
*esi
)
1503 struct bgp_evpn_es
*es
;
1508 es
= XCALLOC(MTYPE_BGP_EVPN_ES
, sizeof(struct bgp_evpn_es
));
1511 memcpy(&es
->esi
, esi
, sizeof(esi_t
));
1513 /* Initialise the VTEP list */
1514 es
->es_vtep_list
= list_new();
1515 listset_app_node_mem(es
->es_vtep_list
);
1516 es
->es_vtep_list
->cmp
= bgp_evpn_es_vtep_cmp
;
1518 esi_to_str(&es
->esi
, es
->esi_str
, sizeof(es
->esi_str
));
1520 /* Initialize the ES routing table */
1521 es
->route_table
= bgp_table_init(bgp
, AFI_L2VPN
, SAFI_EVPN
);
1523 /* Add to rb_tree */
1524 if (RB_INSERT(bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
, es
)) {
1525 XFREE(MTYPE_BGP_EVPN_ES
, es
);
1529 /* Initialise the ES-EVI list */
1530 es
->es_evi_list
= list_new();
1531 listset_app_node_mem(es
->es_evi_list
);
1533 /* Initialise the ES-VRF list used for L3NHG management */
1534 es
->es_vrf_list
= list_new();
1535 listset_app_node_mem(es
->es_vrf_list
);
1537 /* Initialise the route list used for efficient event handling */
1538 es
->macip_path_list
= list_new();
1539 listset_app_node_mem(es
->macip_path_list
);
1541 QOBJ_REG(es
, bgp_evpn_es
);
1546 /* Free a given ES -
1547 * This just frees appropriate memory, caller should have taken other
1550 static void bgp_evpn_es_free(struct bgp_evpn_es
*es
, const char *caller
)
1552 if ((es
->flags
& (BGP_EVPNES_LOCAL
| BGP_EVPNES_REMOTE
))
1553 || listcount(es
->macip_path_list
))
1556 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1557 zlog_debug("%s: es %s free", caller
, es
->esi_str
);
1559 /* cleanup resources maintained against the ES */
1560 list_delete(&es
->es_evi_list
);
1561 list_delete(&es
->es_vrf_list
);
1562 list_delete(&es
->es_vtep_list
);
1563 list_delete(&es
->macip_path_list
);
1564 bgp_table_unlock(es
->route_table
);
1566 /* remove the entry from various databases */
1567 RB_REMOVE(bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
, es
);
1568 bgp_evpn_es_cons_checks_pend_del(es
);
1571 XFREE(MTYPE_BGP_EVPN_ES
, es
);
1574 /* init local info associated with the ES */
1575 static void bgp_evpn_es_local_info_set(struct bgp
*bgp
, struct bgp_evpn_es
*es
)
1577 char buf
[BGP_EVPN_PREFIX_RD_LEN
];
1579 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_LOCAL
))
1582 SET_FLAG(es
->flags
, BGP_EVPNES_LOCAL
);
1583 listnode_init(&es
->es_listnode
, es
);
1584 listnode_add(bgp_mh_info
->local_es_list
, &es
->es_listnode
);
1586 /* auto derive RD for this es */
1587 bf_assign_index(bm
->rd_idspace
, es
->rd_id
);
1588 es
->prd
.family
= AF_UNSPEC
;
1589 es
->prd
.prefixlen
= 64;
1590 snprintfrr(buf
, sizeof(buf
), "%pI4:%hu", &bgp
->router_id
, es
->rd_id
);
1591 (void)str2prefix_rd(buf
, &es
->prd
);
1594 /* clear any local info associated with the ES */
1595 static void bgp_evpn_es_local_info_clear(struct bgp_evpn_es
*es
)
1597 if (!CHECK_FLAG(es
->flags
, BGP_EVPNES_LOCAL
))
1600 UNSET_FLAG(es
->flags
, BGP_EVPNES_LOCAL
);
1602 /* remove from the ES local list */
1603 list_delete_node(bgp_mh_info
->local_es_list
, &es
->es_listnode
);
1605 bf_release_index(bm
->rd_idspace
, es
->rd_id
);
1607 bgp_evpn_es_free(es
, __func__
);
1610 /* eval remote info associated with the ES */
1611 static void bgp_evpn_es_remote_info_re_eval(struct bgp_evpn_es
*es
)
1613 if (es
->remote_es_evi_cnt
) {
1614 SET_FLAG(es
->flags
, BGP_EVPNES_REMOTE
);
1616 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_REMOTE
)) {
1617 UNSET_FLAG(es
->flags
, BGP_EVPNES_REMOTE
);
1618 bgp_evpn_es_free(es
, __func__
);
1623 /* Process ES link oper-down by withdrawing ES-EAD and ESR */
1624 static void bgp_evpn_local_es_down(struct bgp
*bgp
,
1625 struct bgp_evpn_es
*es
)
1627 struct prefix_evpn p
;
1630 if (!CHECK_FLAG(es
->flags
, BGP_EVPNES_OPER_UP
))
1633 UNSET_FLAG(es
->flags
, BGP_EVPNES_OPER_UP
);
1635 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1636 zlog_debug("local es %s down", es
->esi_str
);
1639 /* Delete and withdraw locally learnt ES route */
1640 build_evpn_type4_prefix(&p
, &es
->esi
, es
->originator_ip
);
1641 ret
= bgp_evpn_type4_route_delete(bgp
, es
, &p
);
1643 flog_err(EC_BGP_EVPN_ROUTE_DELETE
,
1644 "%u failed to delete type-4 route for ESI %s",
1645 bgp
->vrf_id
, es
->esi_str
);
1648 /* withdraw EAD-EVI */
1649 if (!bgp_mh_info
->ead_evi_adv_for_down_links
)
1650 bgp_evpn_local_type1_evi_route_del(bgp
, es
);
1652 /* withdraw EAD-ES */
1653 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_ES_ETH_TAG
,
1654 &es
->esi
, es
->originator_ip
);
1655 ret
= bgp_evpn_type1_es_route_delete(bgp
, es
, &p
);
1657 flog_err(EC_BGP_EVPN_ROUTE_DELETE
,
1658 "%u failed to delete type-1 route for ESI %s",
1659 bgp
->vrf_id
, es
->esi_str
);
1663 /* Process ES link oper-up by generating ES-EAD and ESR */
1664 static void bgp_evpn_local_es_up(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
1667 struct prefix_evpn p
;
1668 bool regen_ead
= false;
1670 if (!CHECK_FLAG(es
->flags
, BGP_EVPNES_OPER_UP
)) {
1671 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1672 zlog_debug("local es %s up", es
->esi_str
);
1674 SET_FLAG(es
->flags
, BGP_EVPNES_OPER_UP
);
1680 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1681 zlog_debug("local es %s generate ESR", es
->esi_str
);
1683 build_evpn_type4_prefix(&p
, &es
->esi
, es
->originator_ip
);
1684 if (bgp_evpn_type4_route_update(bgp
, es
, &p
))
1685 flog_err(EC_BGP_EVPN_ROUTE_CREATE
,
1686 "%u: Type4 route creation failure for ESI %s",
1687 bgp
->vrf_id
, es
->esi_str
);
1691 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1692 zlog_debug("local es %s generate EAD", es
->esi_str
);
1693 /* generate EAD-EVI */
1694 bgp_evpn_local_type1_evi_route_add(bgp
, es
);
1696 /* generate EAD-ES */
1697 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_ES_ETH_TAG
, &es
->esi
,
1699 bgp_evpn_type1_route_update(bgp
, es
, NULL
, &p
);
1703 static void bgp_evpn_local_es_do_del(struct bgp
*bgp
, struct bgp_evpn_es
*es
)
1705 struct bgp_evpn_es_evi
*es_evi
;
1706 struct listnode
*evi_node
, *evi_next_node
;
1708 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1709 zlog_debug("del local es %s", es
->esi_str
);
1711 /* Delete all local EVPN ES routes from ESI table
1712 * and schedule for processing (to withdraw from peers))
1714 bgp_evpn_es_route_del_all(bgp
, es
);
1716 /* release all local ES EVIs associated with the ES */
1717 for (ALL_LIST_ELEMENTS(es
->es_evi_list
, evi_node
,
1718 evi_next_node
, es_evi
)) {
1719 bgp_evpn_local_es_evi_do_del(es_evi
);
1722 /* Clear local info associated with the ES and free it up if there is
1723 * no remote reference
1725 bgp_evpn_es_local_info_clear(es
);
1728 bool bgp_evpn_is_esi_local(esi_t
*esi
)
1730 struct bgp_evpn_es
*es
= NULL
;
1732 /* Lookup ESI hash - should exist. */
1733 es
= bgp_evpn_es_find(esi
);
1734 return es
? !!(es
->flags
& BGP_EVPNES_LOCAL
) : false;
1737 int bgp_evpn_local_es_del(struct bgp
*bgp
, esi_t
*esi
)
1739 struct bgp_evpn_es
*es
= NULL
;
1741 /* Lookup ESI hash - should exist. */
1742 es
= bgp_evpn_es_find(esi
);
1744 flog_warn(EC_BGP_EVPN_ESI
,
1745 "%u: ES %s missing at local ES DEL",
1746 bgp
->vrf_id
, es
->esi_str
);
1750 bgp_evpn_local_es_do_del(bgp
, es
);
1754 /* Handle device to ES id association. Results in the creation of a local
1757 int bgp_evpn_local_es_add(struct bgp
*bgp
, esi_t
*esi
,
1758 struct in_addr originator_ip
, bool oper_up
,
1761 char buf
[ESI_STR_LEN
];
1762 struct bgp_evpn_es
*es
;
1764 bool regen_esr
= false;
1766 /* create the new es */
1767 es
= bgp_evpn_es_find(esi
);
1769 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_LOCAL
))
1772 es
= bgp_evpn_es_new(bgp
, esi
);
1774 flog_err(EC_BGP_ES_CREATE
,
1775 "%u: Failed to allocate ES entry for ESI %s - at Local ES Add",
1776 bgp
->vrf_id
, esi_to_str(esi
, buf
, sizeof(buf
)));
1781 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1782 zlog_debug("add local es %s orig-ip %pI4 df_pref %u", es
->esi_str
,
1783 &originator_ip
, df_pref
);
1785 es
->originator_ip
= originator_ip
;
1786 if (df_pref
!= es
->df_pref
) {
1787 es
->df_pref
= df_pref
;
1790 bgp_evpn_es_local_info_set(bgp
, es
);
1792 /* import all remote Type-4 routes in the ES table */
1794 bgp_evpn_type4_remote_routes_import(bgp
, es
,
1795 true /* install */);
1797 /* create and advertise EAD-EVI routes for the ES -
1798 * XXX - till an ES-EVI reference is created there is really nothing to
1801 if (bgp_mh_info
->ead_evi_adv_for_down_links
)
1802 bgp_evpn_local_type1_evi_route_add(bgp
, es
);
1804 /* If the ES link is operationally up generate EAD-ES. EAD-EVI
1805 * can be generated even if the link is inactive.
1808 bgp_evpn_local_es_up(bgp
, es
, regen_esr
);
1810 bgp_evpn_local_es_down(bgp
, es
);
1815 static char *bgp_evpn_es_vteps_str(char *vtep_str
, struct bgp_evpn_es
*es
,
1816 uint8_t vtep_str_size
)
1818 char vtep_flag_str
[BGP_EVPN_FLAG_STR_SZ
];
1819 struct listnode
*node
;
1820 struct bgp_evpn_es_vtep
*es_vtep
;
1822 char ip_buf
[INET6_ADDRSTRLEN
];
1825 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
1826 vtep_flag_str
[0] = '\0';
1828 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ESR
)
1829 strlcat(vtep_flag_str
, "E", sizeof(vtep_flag_str
));
1830 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ACTIVE
)
1831 strlcat(vtep_flag_str
, "A", sizeof(vtep_flag_str
));
1833 if (!strlen(vtep_flag_str
))
1834 strlcat(vtep_flag_str
, "-", sizeof(vtep_flag_str
));
1838 strlcat(vtep_str
, ",", vtep_str_size
);
1840 inet_ntop(AF_INET
, &es_vtep
->vtep_ip
, ip_buf
,
1843 strlcat(vtep_str
, "(", vtep_str_size
);
1844 strlcat(vtep_str
, vtep_flag_str
, vtep_str_size
);
1845 strlcat(vtep_str
, ")", vtep_str_size
);
1851 static void bgp_evpn_es_json_vtep_fill(json_object
*json_vteps
,
1852 struct bgp_evpn_es_vtep
*es_vtep
)
1854 json_object
*json_vtep_entry
;
1855 json_object
*json_flags
;
1856 char ip_buf
[INET6_ADDRSTRLEN
];
1858 json_vtep_entry
= json_object_new_object();
1860 json_object_string_add(
1861 json_vtep_entry
, "vtep_ip",
1862 inet_ntop(AF_INET
, &es_vtep
->vtep_ip
, ip_buf
, sizeof(ip_buf
)));
1863 if (es_vtep
->flags
& (BGP_EVPNES_VTEP_ESR
|
1864 BGP_EVPNES_VTEP_ACTIVE
)) {
1865 json_flags
= json_object_new_array();
1866 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ESR
)
1867 json_array_string_add(json_flags
, "esr");
1868 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ACTIVE
)
1869 json_array_string_add(json_flags
, "active");
1870 json_object_object_add(json_vtep_entry
, "flags", json_flags
);
1871 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ESR
) {
1872 json_object_int_add(json_vtep_entry
, "dfPreference",
1874 json_object_int_add(json_vtep_entry
, "dfAlgorithm",
1879 json_object_array_add(json_vteps
,
1883 static void bgp_evpn_es_vteps_show_detail(struct vty
*vty
,
1884 struct bgp_evpn_es
*es
)
1886 char vtep_flag_str
[BGP_EVPN_FLAG_STR_SZ
];
1887 struct listnode
*node
;
1888 struct bgp_evpn_es_vtep
*es_vtep
;
1889 char alg_buf
[EVPN_DF_ALG_STR_LEN
];
1891 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
1892 vtep_flag_str
[0] = '\0';
1893 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ESR
)
1894 strlcat(vtep_flag_str
, "E", sizeof(vtep_flag_str
));
1895 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ACTIVE
)
1896 strlcat(vtep_flag_str
, "A", sizeof(vtep_flag_str
));
1898 if (!strlen(vtep_flag_str
))
1899 strlcat(vtep_flag_str
, "-", sizeof(vtep_flag_str
));
1901 vty_out(vty
, " %pI4 flags: %s", &es_vtep
->vtep_ip
,
1904 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ESR
)
1905 vty_out(vty
, " df_alg: %s df_pref: %u\n",
1906 evpn_es_df_alg2str(es_vtep
->df_alg
, alg_buf
,
1914 static void bgp_evpn_es_show_entry(struct vty
*vty
,
1915 struct bgp_evpn_es
*es
, json_object
*json
)
1917 char buf1
[RD_ADDRSTRLEN
];
1918 struct listnode
*node
;
1919 struct bgp_evpn_es_vtep
*es_vtep
;
1922 json_object
*json_vteps
;
1923 json_object
*json_types
;
1925 json_object_string_add(json
, "esi", es
->esi_str
);
1926 json_object_string_add(json
, "rd",
1927 prefix_rd2str(&es
->prd
, buf1
,
1930 if (es
->flags
& (BGP_EVPNES_LOCAL
| BGP_EVPNES_REMOTE
)) {
1931 json_types
= json_object_new_array();
1932 if (es
->flags
& BGP_EVPNES_LOCAL
)
1933 json_array_string_add(json_types
, "local");
1934 if (es
->flags
& BGP_EVPNES_REMOTE
)
1935 json_array_string_add(json_types
, "remote");
1936 json_object_object_add(json
, "type", json_types
);
1939 if (listcount(es
->es_vtep_list
)) {
1940 json_vteps
= json_object_new_array();
1941 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
,
1943 bgp_evpn_es_json_vtep_fill(json_vteps
, es_vtep
);
1945 json_object_object_add(json
, "vteps", json_vteps
);
1947 json_object_int_add(json
, "vniCount",
1948 listcount(es
->es_evi_list
));
1951 char vtep_str
[ES_VTEP_LIST_STR_SZ
+ BGP_EVPN_VTEPS_FLAG_STR_SZ
];
1954 if (es
->flags
& BGP_EVPNES_LOCAL
)
1955 strlcat(type_str
, "L", sizeof(type_str
));
1956 if (es
->flags
& BGP_EVPNES_REMOTE
)
1957 strlcat(type_str
, "R", sizeof(type_str
));
1958 if (es
->inconsistencies
)
1959 strlcat(type_str
, "I", sizeof(type_str
));
1961 bgp_evpn_es_vteps_str(vtep_str
, es
, sizeof(vtep_str
));
1963 if (es
->flags
& BGP_EVPNES_LOCAL
)
1964 prefix_rd2str(&es
->prd
, buf1
, sizeof(buf1
));
1966 strlcpy(buf1
, "-", sizeof(buf1
));
1968 vty_out(vty
, "%-30s %-5s %-21s %-8d %s\n",
1969 es
->esi_str
, type_str
, buf1
,
1970 listcount(es
->es_evi_list
), vtep_str
);
1974 static void bgp_evpn_es_show_entry_detail(struct vty
*vty
,
1975 struct bgp_evpn_es
*es
, json_object
*json
)
1977 char ip_buf
[INET6_ADDRSTRLEN
];
1980 json_object
*json_flags
;
1981 json_object
*json_incons
;
1982 json_object
*json_vteps
;
1983 struct listnode
*node
;
1984 struct bgp_evpn_es_vtep
*es_vtep
;
1986 /* Add the "brief" info first */
1987 bgp_evpn_es_show_entry(vty
, es
, json
);
1988 if (es
->flags
& (BGP_EVPNES_OPER_UP
| BGP_EVPNES_ADV_EVI
)) {
1989 json_flags
= json_object_new_array();
1990 if (es
->flags
& BGP_EVPNES_OPER_UP
)
1991 json_array_string_add(json_flags
, "up");
1992 if (es
->flags
& BGP_EVPNES_ADV_EVI
)
1993 json_array_string_add(json_flags
,
1995 json_object_object_add(json
, "flags", json_flags
);
1997 json_object_string_add(json
, "originator_ip",
1998 inet_ntop(AF_INET
, &es
->originator_ip
,
1999 ip_buf
, sizeof(ip_buf
)));
2000 json_object_int_add(json
, "remoteVniCount",
2001 es
->remote_es_evi_cnt
);
2002 json_object_int_add(json
, "vrfCount",
2003 listcount(es
->es_vrf_list
));
2004 json_object_int_add(json
, "macipPathCount",
2005 listcount(es
->macip_path_list
));
2006 json_object_int_add(json
, "inconsistentVniVtepCount",
2007 es
->incons_evi_vtep_cnt
);
2008 if (listcount(es
->es_vtep_list
)) {
2009 json_vteps
= json_object_new_array();
2010 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
,
2012 bgp_evpn_es_json_vtep_fill(json_vteps
, es_vtep
);
2014 json_object_object_add(json
, "vteps", json_vteps
);
2016 if (es
->inconsistencies
) {
2017 json_incons
= json_object_new_array();
2018 if (es
->inconsistencies
& BGP_EVPNES_INCONS_VTEP_LIST
)
2019 json_array_string_add(json_incons
,
2020 "vni-vtep-mismatch");
2021 json_object_object_add(json
, "inconsistencies",
2025 char incons_str
[BGP_EVPNES_INCONS_STR_SZ
];
2027 char buf1
[RD_ADDRSTRLEN
];
2030 if (es
->flags
& BGP_EVPNES_LOCAL
)
2031 strlcat(type_str
, "L", sizeof(type_str
));
2032 if (es
->flags
& BGP_EVPNES_REMOTE
)
2033 strlcat(type_str
, "R", sizeof(type_str
));
2035 if (es
->flags
& BGP_EVPNES_LOCAL
)
2036 prefix_rd2str(&es
->prd
, buf1
, sizeof(buf1
));
2038 strlcpy(buf1
, "-", sizeof(buf1
));
2040 vty_out(vty
, "ESI: %s\n", es
->esi_str
);
2041 vty_out(vty
, " Type: %s\n", type_str
);
2042 vty_out(vty
, " RD: %s\n", buf1
);
2043 vty_out(vty
, " Originator-IP: %pI4\n", &es
->originator_ip
);
2044 if (es
->flags
& BGP_EVPNES_LOCAL
)
2045 vty_out(vty
, " Local ES DF preference: %u\n",
2047 vty_out(vty
, " VNI Count: %d\n", listcount(es
->es_evi_list
));
2048 vty_out(vty
, " Remote VNI Count: %d\n",
2049 es
->remote_es_evi_cnt
);
2050 vty_out(vty
, " VRF Count: %d\n", listcount(es
->es_vrf_list
));
2051 vty_out(vty
, " MACIP Path Count: %d\n",
2052 listcount(es
->macip_path_list
));
2053 vty_out(vty
, " Inconsistent VNI VTEP Count: %d\n",
2054 es
->incons_evi_vtep_cnt
);
2055 if (es
->inconsistencies
) {
2056 incons_str
[0] = '\0';
2057 if (es
->inconsistencies
& BGP_EVPNES_INCONS_VTEP_LIST
)
2058 strlcat(incons_str
, "vni-vtep-mismatch",
2059 sizeof(incons_str
));
2061 strlcpy(incons_str
, "-", sizeof(incons_str
));
2063 vty_out(vty
, " Inconsistencies: %s\n",
2065 if (listcount(es
->es_vtep_list
)) {
2066 vty_out(vty
, " VTEPs:\n");
2067 bgp_evpn_es_vteps_show_detail(vty
, es
);
2073 /* Display all ESs */
2074 void bgp_evpn_es_show(struct vty
*vty
, bool uj
, bool detail
)
2076 struct bgp_evpn_es
*es
;
2077 json_object
*json_array
= NULL
;
2078 json_object
*json
= NULL
;
2081 /* create an array of ESs */
2082 json_array
= json_object_new_array();
2086 "ES Flags: L local, R remote, I inconsistent\n");
2088 "VTEP Flags: E ESR/Type-4, A active nexthop\n");
2090 "%-30s %-5s %-21s %-8s %s\n",
2091 "ESI", "Flags", "RD", "#VNIs", "VTEPs");
2095 RB_FOREACH(es
, bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
) {
2097 /* create a separate json object for each ES */
2098 json
= json_object_new_object();
2100 bgp_evpn_es_show_entry_detail(vty
, es
, json
);
2102 bgp_evpn_es_show_entry(vty
, es
, json
);
2103 /* add ES to the json array */
2105 json_object_array_add(json_array
, json
);
2108 /* print the array of json-ESs */
2110 vty_out(vty
, "%s\n", json_object_to_json_string_ext(
2111 json_array
, JSON_C_TO_STRING_PRETTY
));
2112 json_object_free(json_array
);
2116 /* Display specific ES */
2117 void bgp_evpn_es_show_esi(struct vty
*vty
, esi_t
*esi
, bool uj
)
2119 struct bgp_evpn_es
*es
;
2120 json_object
*json
= NULL
;
2123 json
= json_object_new_object();
2125 es
= bgp_evpn_es_find(esi
);
2127 bgp_evpn_es_show_entry_detail(vty
, es
, json
);
2130 vty_out(vty
, "ESI not found\n");
2134 vty_out(vty
, "%s\n", json_object_to_json_string_ext(
2135 json
, JSON_C_TO_STRING_PRETTY
));
2136 json_object_free(json
);
2140 /*****************************************************************************/
2141 /* Ethernet Segment to VRF association -
2142 * 1. Each ES-EVI entry is associated with a tenant VRF. This associaton
2143 * triggers the creation of an ES-VRF entry.
2144 * 2. The ES-VRF entry is maintained for the purpose of L3-NHG creation
2145 * 3. Type-2/MAC-IP routes are imported into a tenant VRF and programmed as
2146 * a /32 or host route entry in the dataplane. If the destination of
2147 * the host route is a remote-ES the route is programmed with the
2148 * corresponding (keyed in by {vrf,ES-id}) L3-NHG.
2149 * 4. The reason for this indirection (route->L3-NHG, L3-NHG->list-of-VTEPs)
2150 * is to avoid route updates to the dplane when a remote-ES link flaps i.e.
2151 * instead of updating all the dependent routes the NHG's contents are updated.
2152 * This reduces the amount of datplane updates (nhg updates vs. route updates)
2153 * allowing for a faster failover.
2155 * XXX - can the L3 SVI index change without change in vpn->bgp_vrf
2156 * association? If yes we need to handle that by updating all the L3 NHGs
2159 /******************************** L3 NHG management *************************/
2160 static void bgp_evpn_l3nhg_zebra_add_v4_or_v6(struct bgp_evpn_es_vrf
*es_vrf
,
2163 uint32_t nhg_id
= v4_nhg
? es_vrf
->nhg_id
: es_vrf
->v6_nhg_id
;
2164 struct bgp_evpn_es
*es
= es_vrf
->es
;
2165 struct listnode
*node
;
2166 struct bgp_evpn_es_vtep
*es_vtep
;
2168 struct zapi_nexthop
*api_nh
;
2169 struct zapi_nhg api_nhg
= {};
2171 /* Skip installation of L3-NHG if host routes used */
2175 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2176 zlog_debug("es %s vrf %u %s nhg %u to zebra", es
->esi_str
,
2177 es_vrf
->bgp_vrf
->vrf_id
,
2178 v4_nhg
? "v4_nhg" : "v6_nhg", nhg_id
);
2180 /* only the gateway ip changes for each NH. rest of the params
2183 memset(&nh
, 0, sizeof(nh
));
2184 nh
.vrf_id
= es_vrf
->bgp_vrf
->vrf_id
;
2185 nh
.flags
= NEXTHOP_FLAG_ONLINK
;
2186 nh
.ifindex
= es_vrf
->bgp_vrf
->l3vni_svi_ifindex
;
2189 v4_nhg
? NEXTHOP_TYPE_IPV4_IFINDEX
: NEXTHOP_TYPE_IPV6_IFINDEX
;
2191 api_nhg
.id
= nhg_id
;
2192 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
2193 if (!CHECK_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
))
2196 /* overwrite the gw */
2198 nh
.gate
.ipv4
= es_vtep
->vtep_ip
;
2200 ipv4_to_ipv4_mapped_ipv6(&nh
.gate
.ipv6
,
2203 /* convert to zapi format */
2204 api_nh
= &api_nhg
.nexthops
[api_nhg
.nexthop_num
];
2205 zapi_nexthop_from_nexthop(api_nh
, &nh
);
2207 ++api_nhg
.nexthop_num
;
2208 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2209 zlog_debug("nhg %u vtep %pI4 l3-svi %d", api_nhg
.id
,
2211 es_vrf
->bgp_vrf
->l3vni_svi_ifindex
);
2214 if (!api_nhg
.nexthop_num
)
2217 if (api_nhg
.nexthop_num
> MULTIPATH_NUM
)
2220 zclient_nhg_send(zclient
, ZEBRA_NHG_ADD
, &api_nhg
);
2223 static bool bgp_evpn_l3nhg_zebra_ok(struct bgp_evpn_es_vrf
*es_vrf
)
2225 if (!bgp_mh_info
->host_routes_use_l3nhg
&& !bgp_mh_info
->install_l3nhg
)
2229 if (!zclient
|| zclient
->sock
< 0)
2235 static void bgp_evpn_l3nhg_zebra_add(struct bgp_evpn_es_vrf
*es_vrf
)
2237 if (!bgp_evpn_l3nhg_zebra_ok(es_vrf
))
2240 bgp_evpn_l3nhg_zebra_add_v4_or_v6(es_vrf
, true /*v4_nhg*/);
2241 bgp_evpn_l3nhg_zebra_add_v4_or_v6(es_vrf
, false /*v4_nhg*/);
2244 static void bgp_evpn_l3nhg_zebra_del_v4_or_v6(struct bgp_evpn_es_vrf
*es_vrf
,
2247 struct zapi_nhg api_nhg
= {};
2249 api_nhg
.id
= v4_nhg
? es_vrf
->nhg_id
: es_vrf
->v6_nhg_id
;
2251 /* Skip installation of L3-NHG if host routes used */
2255 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2256 zlog_debug("es %s vrf %u %s nhg %u to zebra",
2257 es_vrf
->es
->esi_str
, es_vrf
->bgp_vrf
->vrf_id
,
2258 v4_nhg
? "v4_nhg" : "v6_nhg", api_nhg
.id
);
2260 zclient_nhg_send(zclient
, ZEBRA_NHG_DEL
, &api_nhg
);
2263 static void bgp_evpn_l3nhg_zebra_del(struct bgp_evpn_es_vrf
*es_vrf
)
2265 if (!bgp_evpn_l3nhg_zebra_ok(es_vrf
))
2268 bgp_evpn_l3nhg_zebra_del_v4_or_v6(es_vrf
, true /*v4_nhg*/);
2269 bgp_evpn_l3nhg_zebra_del_v4_or_v6(es_vrf
, false /*v4_nhg*/);
2272 static void bgp_evpn_l3nhg_deactivate(struct bgp_evpn_es_vrf
*es_vrf
)
2274 if (!(es_vrf
->flags
& BGP_EVPNES_VRF_NHG_ACTIVE
))
2277 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2278 zlog_debug("es %s vrf %u nhg %u de-activate",
2279 es_vrf
->es
->esi_str
, es_vrf
->bgp_vrf
->vrf_id
,
2281 bgp_evpn_l3nhg_zebra_del(es_vrf
);
2282 es_vrf
->flags
&= ~BGP_EVPNES_VRF_NHG_ACTIVE
;
2285 static void bgp_evpn_l3nhg_activate(struct bgp_evpn_es_vrf
*es_vrf
, bool update
)
2287 if (!bgp_evpn_es_get_active_vtep_cnt(es_vrf
->es
)) {
2288 bgp_evpn_l3nhg_deactivate(es_vrf
);
2292 if (es_vrf
->flags
& BGP_EVPNES_VRF_NHG_ACTIVE
) {
2296 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2297 zlog_debug("es %s vrf %u nhg %u activate",
2298 es_vrf
->es
->esi_str
, es_vrf
->bgp_vrf
->vrf_id
,
2300 es_vrf
->flags
|= BGP_EVPNES_VRF_NHG_ACTIVE
;
2303 bgp_evpn_l3nhg_zebra_add(es_vrf
);
2306 /* when a VTEP is activated or de-activated against an ES associated
2307 * VRFs' NHG needs to be updated
2309 static void bgp_evpn_l3nhg_update_on_vtep_chg(struct bgp_evpn_es
*es
)
2311 struct bgp_evpn_es_vrf
*es_vrf
;
2312 struct listnode
*es_vrf_node
;
2314 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2315 zlog_debug("es %s nhg update on vtep chg", es
->esi_str
);
2317 for (ALL_LIST_ELEMENTS_RO(es
->es_vrf_list
, es_vrf_node
, es_vrf
))
2318 bgp_evpn_l3nhg_activate(es_vrf
, true /* update */);
2321 /* compare ES-IDs for the ES-VRF RB tree maintained per-VRF */
2322 static int bgp_es_vrf_rb_cmp(const struct bgp_evpn_es_vrf
*es_vrf1
,
2323 const struct bgp_evpn_es_vrf
*es_vrf2
)
2325 return memcmp(&es_vrf1
->es
->esi
, &es_vrf2
->es
->esi
, ESI_BYTES
);
2327 RB_GENERATE(bgp_es_vrf_rb_head
, bgp_evpn_es_vrf
, rb_node
, bgp_es_vrf_rb_cmp
);
2329 /* Initialize the ES tables maintained per-tenant vrf */
2330 void bgp_evpn_vrf_es_init(struct bgp
*bgp_vrf
)
2332 /* Initialize the ES-VRF RB tree */
2333 RB_INIT(bgp_es_vrf_rb_head
, &bgp_vrf
->es_vrf_rb_tree
);
2336 /* find the ES-VRF in the per-VRF RB tree */
2337 static struct bgp_evpn_es_vrf
*bgp_evpn_es_vrf_find(struct bgp_evpn_es
*es
,
2338 struct bgp
*bgp_vrf
)
2340 struct bgp_evpn_es_vrf es_vrf
;
2344 return RB_FIND(bgp_es_vrf_rb_head
, &bgp_vrf
->es_vrf_rb_tree
, &es_vrf
);
2347 /* allocate a new ES-VRF and setup L3NHG for it */
2348 static struct bgp_evpn_es_vrf
*bgp_evpn_es_vrf_create(struct bgp_evpn_es
*es
,
2349 struct bgp
*bgp_vrf
)
2351 struct bgp_evpn_es_vrf
*es_vrf
;
2353 es_vrf
= XCALLOC(MTYPE_BGP_EVPN_ES_VRF
, sizeof(*es_vrf
));
2356 es_vrf
->bgp_vrf
= bgp_vrf
;
2358 /* insert into the VRF-ESI rb tree */
2359 if (RB_INSERT(bgp_es_vrf_rb_head
, &bgp_vrf
->es_vrf_rb_tree
, es_vrf
)) {
2360 XFREE(MTYPE_BGP_EVPN_ES_VRF
, es_vrf
);
2364 /* add to the ES's VRF list */
2365 listnode_init(&es_vrf
->es_listnode
, es_vrf
);
2366 listnode_add(es
->es_vrf_list
, &es_vrf
->es_listnode
);
2368 /* setup the L3 NHG id for the ES */
2369 es_vrf
->nhg_id
= bgp_l3nhg_id_alloc();
2370 es_vrf
->v6_nhg_id
= bgp_l3nhg_id_alloc();
2372 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2373 zlog_debug("es %s vrf %u nhg %u v6_nhg %d create", es
->esi_str
,
2374 bgp_vrf
->vrf_id
, es_vrf
->nhg_id
, es_vrf
->v6_nhg_id
);
2375 bgp_evpn_l3nhg_activate(es_vrf
, false /* update */);
2380 /* remove the L3-NHG associated with the ES-VRF and free it */
2381 static void bgp_evpn_es_vrf_delete(struct bgp_evpn_es_vrf
*es_vrf
)
2383 struct bgp_evpn_es
*es
= es_vrf
->es
;
2384 struct bgp
*bgp_vrf
= es_vrf
->bgp_vrf
;
2386 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2387 zlog_debug("es %s vrf %u nhg %u delete", es
->esi_str
,
2388 bgp_vrf
->vrf_id
, es_vrf
->nhg_id
);
2390 /* Remove the NHG resources */
2391 bgp_evpn_l3nhg_deactivate(es_vrf
);
2393 bgp_l3nhg_id_free(es_vrf
->nhg_id
);
2395 if (es_vrf
->v6_nhg_id
)
2396 bgp_l3nhg_id_free(es_vrf
->v6_nhg_id
);
2397 es_vrf
->v6_nhg_id
= 0;
2399 /* remove from the ES's VRF list */
2400 list_delete_node(es
->es_vrf_list
, &es_vrf
->es_listnode
);
2402 /* remove from the VRF-ESI rb tree */
2403 RB_REMOVE(bgp_es_vrf_rb_head
, &bgp_vrf
->es_vrf_rb_tree
, es_vrf
);
2405 XFREE(MTYPE_BGP_EVPN_ES_VRF
, es_vrf
);
2408 /* deref and delete if there are no references */
2409 void bgp_evpn_es_vrf_deref(struct bgp_evpn_es_evi
*es_evi
)
2411 struct bgp_evpn_es_vrf
*es_vrf
= es_evi
->es_vrf
;
2416 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2417 zlog_debug("es-evi %s vni %u vrf %u de-ref",
2418 es_evi
->es
->esi_str
, es_evi
->vpn
->vni
,
2419 es_vrf
->bgp_vrf
->vrf_id
);
2421 es_evi
->es_vrf
= NULL
;
2422 if (es_vrf
->ref_cnt
)
2425 if (!es_vrf
->ref_cnt
)
2426 bgp_evpn_es_vrf_delete(es_vrf
);
2429 /* find or create and reference */
2430 void bgp_evpn_es_vrf_ref(struct bgp_evpn_es_evi
*es_evi
, struct bgp
*bgp_vrf
)
2432 struct bgp_evpn_es
*es
= es_evi
->es
;
2433 struct bgp_evpn_es_vrf
*es_vrf
= es_evi
->es_vrf
;
2434 struct bgp
*old_bgp_vrf
= NULL
;
2437 old_bgp_vrf
= es_vrf
->bgp_vrf
;
2439 if (old_bgp_vrf
== bgp_vrf
)
2442 /* deref the old ES-VRF */
2443 bgp_evpn_es_vrf_deref(es_evi
);
2448 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2449 zlog_debug("es-evi %s vni %u vrf %u ref", es_evi
->es
->esi_str
,
2450 es_evi
->vpn
->vni
, bgp_vrf
->vrf_id
);
2452 /* find-create the new ES-VRF */
2453 es_vrf
= bgp_evpn_es_vrf_find(es
, bgp_vrf
);
2455 es_vrf
= bgp_evpn_es_vrf_create(es
, bgp_vrf
);
2459 es_evi
->es_vrf
= es_vrf
;
2463 /* When the L2-VNI is associated with a L3-VNI/VRF update all the
2464 * associated ES-EVI entries
2466 void bgp_evpn_es_evi_vrf_deref(struct bgpevpn
*vpn
)
2468 struct bgp_evpn_es_evi
*es_evi
;
2470 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2471 zlog_debug("es-vrf de-ref for vni %u", vpn
->vni
);
2473 RB_FOREACH (es_evi
, bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
)
2474 bgp_evpn_es_vrf_deref(es_evi
);
2476 void bgp_evpn_es_evi_vrf_ref(struct bgpevpn
*vpn
)
2478 struct bgp_evpn_es_evi
*es_evi
;
2480 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2481 zlog_debug("es-vrf ref for vni %u", vpn
->vni
);
2483 RB_FOREACH (es_evi
, bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
)
2484 bgp_evpn_es_vrf_ref(es_evi
, vpn
->bgp_vrf
);
2487 /* returns false if legacy-exploded mp needs to be used for route install */
2488 bool bgp_evpn_path_es_use_nhg(struct bgp
*bgp_vrf
, struct bgp_path_info
*pi
,
2492 struct bgp_evpn_es
*es
;
2493 struct bgp_evpn_es_vrf
*es_vrf
;
2494 struct bgp_path_info
*parent_pi
;
2495 struct bgp_node
*rn
;
2496 struct prefix_evpn
*evp
;
2497 struct bgp_path_info
*mpinfo
;
2501 /* L3NHG support is disabled, use legacy-exploded multipath */
2502 if (!bgp_mh_info
->host_routes_use_l3nhg
)
2505 parent_pi
= get_route_parent_evpn(pi
);
2509 rn
= parent_pi
->net
;
2513 evp
= (struct prefix_evpn
*)&rn
->p
;
2514 if (evp
->prefix
.route_type
!= BGP_EVPN_MAC_IP_ROUTE
)
2517 /* non-es path, use legacy-exploded multipath */
2518 esi
= bgp_evpn_attr_get_esi(parent_pi
->attr
);
2519 if (!memcmp(esi
, zero_esi
, sizeof(*esi
)))
2522 /* if the ES-VRF is not setup or if the NHG has not been installed
2523 * we cannot install the route yet, return a 0-NHG to indicate
2526 es
= bgp_evpn_es_find(esi
);
2529 es_vrf
= bgp_evpn_es_vrf_find(es
, bgp_vrf
);
2530 if (!es_vrf
|| !(es_vrf
->flags
& BGP_EVPNES_VRF_NHG_ACTIVE
))
2533 /* this needs to be set the v6NHG if v6route */
2534 if (is_evpn_prefix_ipaddr_v6(evp
))
2535 *nhg_p
= es_vrf
->v6_nhg_id
;
2537 *nhg_p
= es_vrf
->nhg_id
;
2539 for (mpinfo
= bgp_path_info_mpath_next(pi
); mpinfo
;
2540 mpinfo
= bgp_path_info_mpath_next(mpinfo
)) {
2541 /* if any of the paths of have a different ESI we can't use
2542 * the NHG associated with the ES. fallback to legacy-exploded
2545 if (memcmp(esi
, bgp_evpn_attr_get_esi(mpinfo
->attr
),
2553 static void bgp_evpn_es_vrf_show_entry(struct vty
*vty
,
2554 struct bgp_evpn_es_vrf
*es_vrf
,
2557 struct bgp_evpn_es
*es
= es_vrf
->es
;
2558 struct bgp
*bgp_vrf
= es_vrf
->bgp_vrf
;
2561 json_object
*json_types
;
2563 json_object_string_add(json
, "esi", es
->esi_str
);
2564 json_object_string_add(json
, "vrf", bgp_vrf
->name
);
2566 if (es_vrf
->flags
& (BGP_EVPNES_VRF_NHG_ACTIVE
)) {
2567 json_types
= json_object_new_array();
2568 if (es_vrf
->flags
& BGP_EVPNES_VRF_NHG_ACTIVE
)
2569 json_array_string_add(json_types
, "active");
2570 json_object_object_add(json
, "flags", json_types
);
2573 json_object_int_add(json
, "ipv4NHG", es_vrf
->nhg_id
);
2574 json_object_int_add(json
, "ipv6NHG", es_vrf
->v6_nhg_id
);
2575 json_object_int_add(json
, "refCount", es_vrf
->ref_cnt
);
2579 flags_str
[0] = '\0';
2580 if (es_vrf
->flags
& BGP_EVPNES_VRF_NHG_ACTIVE
)
2581 strlcat(flags_str
, "A", sizeof(flags_str
));
2583 vty_out(vty
, "%-30s %-15s %-5s %-8u %-8u %u\n", es
->esi_str
,
2584 bgp_vrf
->name
, flags_str
, es_vrf
->nhg_id
,
2585 es_vrf
->v6_nhg_id
, es_vrf
->ref_cnt
);
2589 static void bgp_evpn_es_vrf_show_es(struct vty
*vty
, json_object
*json_array
,
2590 struct bgp_evpn_es
*es
)
2592 json_object
*json
= NULL
;
2593 struct listnode
*es_vrf_node
;
2594 struct bgp_evpn_es_vrf
*es_vrf
;
2596 for (ALL_LIST_ELEMENTS_RO(es
->es_vrf_list
, es_vrf_node
, es_vrf
)) {
2597 /* create a separate json object for each ES-VRF */
2599 json
= json_object_new_object();
2600 bgp_evpn_es_vrf_show_entry(vty
, es_vrf
, json
);
2601 /* add ES-VRF to the json array */
2603 json_object_array_add(json_array
, json
);
2607 /* Display all ES VRFs */
2608 void bgp_evpn_es_vrf_show(struct vty
*vty
, bool uj
, struct bgp_evpn_es
*es
)
2610 json_object
*json_array
= NULL
;
2613 /* create an array of ESs */
2614 json_array
= json_object_new_array();
2616 vty_out(vty
, "ES-VRF Flags: A Active\n");
2617 vty_out(vty
, "%-30s %-15s %-5s %-8s %-8s %s\n", "ESI", "VRF",
2618 "Flags", "IPv4-NHG", "IPv6-NHG", "Ref");
2622 bgp_evpn_es_vrf_show_es(vty
, json_array
, es
);
2624 RB_FOREACH (es
, bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
)
2625 bgp_evpn_es_vrf_show_es(vty
, json_array
, es
);
2628 /* print the array of json-ESs */
2630 vty_out(vty
, "%s\n",
2631 json_object_to_json_string_ext(
2632 json_array
, JSON_C_TO_STRING_PRETTY
));
2633 json_object_free(json_array
);
2637 /* Display specific ES VRF */
2638 void bgp_evpn_es_vrf_show_esi(struct vty
*vty
, esi_t
*esi
, bool uj
)
2640 struct bgp_evpn_es
*es
;
2642 es
= bgp_evpn_es_find(esi
);
2644 bgp_evpn_es_vrf_show(vty
, uj
, es
);
2647 vty_out(vty
, "ESI not found\n");
2651 /*****************************************************************************/
2652 /* Ethernet Segment to EVI association -
2653 * 1. The ES-EVI entry is maintained as a RB tree per L2-VNI
2654 * (bgpevpn->es_evi_rb_tree).
2655 * 2. Each local ES-EVI entry is rxed from zebra and then used by BGP to
2656 * advertises an EAD-EVI (Type-1 EVPN) route
2657 * 3. The remote ES-EVI is created when a bgp_evpn_es_evi_vtep references
2661 /* A list of remote VTEPs is maintained for each ES-EVI. This list includes -
2662 * 1. VTEPs for which we have imported the EAD-per-ES Type1 route
2663 * 2. VTEPs for which we have imported the EAD-per-EVI Type1 route
2664 * VTEPs for which both routes have been rxed are activated. Activation
2665 * creates a NHG in the parent ES.
2667 static int bgp_evpn_es_evi_vtep_cmp(void *p1
, void *p2
)
2669 const struct bgp_evpn_es_evi_vtep
*evi_vtep1
= p1
;
2670 const struct bgp_evpn_es_evi_vtep
*evi_vtep2
= p2
;
2672 return evi_vtep1
->vtep_ip
.s_addr
- evi_vtep2
->vtep_ip
.s_addr
;
2675 static struct bgp_evpn_es_evi_vtep
*bgp_evpn_es_evi_vtep_new(
2676 struct bgp_evpn_es_evi
*es_evi
, struct in_addr vtep_ip
)
2678 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
2680 evi_vtep
= XCALLOC(MTYPE_BGP_EVPN_ES_EVI_VTEP
, sizeof(*evi_vtep
));
2682 evi_vtep
->es_evi
= es_evi
;
2683 evi_vtep
->vtep_ip
.s_addr
= vtep_ip
.s_addr
;
2684 listnode_init(&evi_vtep
->es_evi_listnode
, evi_vtep
);
2685 listnode_add_sort(es_evi
->es_evi_vtep_list
, &evi_vtep
->es_evi_listnode
);
2690 static void bgp_evpn_es_evi_vtep_free(struct bgp_evpn_es_evi_vtep
*evi_vtep
)
2692 struct bgp_evpn_es_evi
*es_evi
= evi_vtep
->es_evi
;
2694 if (evi_vtep
->flags
& (BGP_EVPN_EVI_VTEP_EAD
))
2695 /* as long as there is some reference we can't free it */
2698 list_delete_node(es_evi
->es_evi_vtep_list
, &evi_vtep
->es_evi_listnode
);
2699 XFREE(MTYPE_BGP_EVPN_ES_EVI_VTEP
, evi_vtep
);
2702 /* check if VTEP is already part of the list */
2703 static struct bgp_evpn_es_evi_vtep
*bgp_evpn_es_evi_vtep_find(
2704 struct bgp_evpn_es_evi
*es_evi
, struct in_addr vtep_ip
)
2706 struct listnode
*node
= NULL
;
2707 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
2709 for (ALL_LIST_ELEMENTS_RO(es_evi
->es_evi_vtep_list
, node
, evi_vtep
)) {
2710 if (evi_vtep
->vtep_ip
.s_addr
== vtep_ip
.s_addr
)
2716 /* A VTEP can be added as "active" attach to an ES if EAD-per-ES and
2717 * EAD-per-EVI routes are rxed from it.
2719 static void bgp_evpn_es_evi_vtep_re_eval_active(struct bgp
*bgp
,
2720 struct bgp_evpn_es_evi_vtep
*evi_vtep
)
2724 uint32_t ead_activity_flags
;
2726 old_active
= !!CHECK_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
);
2728 if (bgp_mh_info
->ead_evi_rx
)
2729 /* Both EAD-per-ES and EAD-per-EVI routes must be rxed from a PE
2730 * before it can be activated.
2732 ead_activity_flags
= BGP_EVPN_EVI_VTEP_EAD
;
2734 /* EAD-per-ES is sufficent to activate the PE */
2735 ead_activity_flags
= BGP_EVPN_EVI_VTEP_EAD_PER_ES
;
2737 if ((evi_vtep
->flags
& ead_activity_flags
) == ead_activity_flags
)
2738 SET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
);
2740 UNSET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
);
2742 new_active
= !!CHECK_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
);
2744 if (old_active
== new_active
)
2747 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2748 zlog_debug("es %s evi %u vtep %pI4 %s",
2749 evi_vtep
->es_evi
->es
->esi_str
,
2750 evi_vtep
->es_evi
->vpn
->vni
, &evi_vtep
->vtep_ip
,
2751 new_active
? "active" : "inactive");
2753 /* add VTEP to parent es */
2755 struct bgp_evpn_es_vtep
*es_vtep
;
2757 es_vtep
= bgp_evpn_es_vtep_add(bgp
, evi_vtep
->es_evi
->es
,
2758 evi_vtep
->vtep_ip
, false /*esr*/,
2760 evi_vtep
->es_vtep
= es_vtep
;
2762 if (evi_vtep
->es_vtep
) {
2763 bgp_evpn_es_vtep_do_del(bgp
, evi_vtep
->es_vtep
,
2765 evi_vtep
->es_vtep
= NULL
;
2768 /* queue up the parent es for background consistency checks */
2769 bgp_evpn_es_cons_checks_pend_add(evi_vtep
->es_evi
->es
);
2772 static void bgp_evpn_es_evi_vtep_add(struct bgp
*bgp
,
2773 struct bgp_evpn_es_evi
*es_evi
, struct in_addr vtep_ip
,
2776 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
2778 evi_vtep
= bgp_evpn_es_evi_vtep_find(es_evi
, vtep_ip
);
2781 evi_vtep
= bgp_evpn_es_evi_vtep_new(es_evi
, vtep_ip
);
2783 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2784 zlog_debug("add es %s evi %u vtep %pI4 %s",
2785 evi_vtep
->es_evi
->es
->esi_str
,
2786 evi_vtep
->es_evi
->vpn
->vni
, &evi_vtep
->vtep_ip
,
2787 ead_es
? "ead_es" : "ead_evi");
2790 SET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_EAD_PER_ES
);
2792 SET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_EAD_PER_EVI
);
2794 bgp_evpn_es_evi_vtep_re_eval_active(bgp
, evi_vtep
);
2797 static void bgp_evpn_es_evi_vtep_del(struct bgp
*bgp
,
2798 struct bgp_evpn_es_evi
*es_evi
, struct in_addr vtep_ip
,
2801 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
2803 evi_vtep
= bgp_evpn_es_evi_vtep_find(es_evi
, vtep_ip
);
2807 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2808 zlog_debug("del es %s evi %u vtep %pI4 %s",
2809 evi_vtep
->es_evi
->es
->esi_str
,
2810 evi_vtep
->es_evi
->vpn
->vni
, &evi_vtep
->vtep_ip
,
2811 ead_es
? "ead_es" : "ead_evi");
2814 UNSET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_EAD_PER_ES
);
2816 UNSET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_EAD_PER_EVI
);
2818 bgp_evpn_es_evi_vtep_re_eval_active(bgp
, evi_vtep
);
2819 bgp_evpn_es_evi_vtep_free(evi_vtep
);
2822 /* compare ES-IDs for the ES-EVI RB tree maintained per-VNI */
2823 static int bgp_es_evi_rb_cmp(const struct bgp_evpn_es_evi
*es_evi1
,
2824 const struct bgp_evpn_es_evi
*es_evi2
)
2826 return memcmp(&es_evi1
->es
->esi
, &es_evi2
->es
->esi
, ESI_BYTES
);
2828 RB_GENERATE(bgp_es_evi_rb_head
, bgp_evpn_es_evi
, rb_node
, bgp_es_evi_rb_cmp
);
2830 /* find the ES-EVI in the per-L2-VNI RB tree */
2831 static struct bgp_evpn_es_evi
*bgp_evpn_es_evi_find(struct bgp_evpn_es
*es
,
2832 struct bgpevpn
*vpn
)
2834 struct bgp_evpn_es_evi es_evi
;
2838 return RB_FIND(bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
, &es_evi
);
2841 /* allocate a new ES-EVI and insert it into the per-L2-VNI and per-ES
2844 static struct bgp_evpn_es_evi
*bgp_evpn_es_evi_new(struct bgp_evpn_es
*es
,
2845 struct bgpevpn
*vpn
)
2847 struct bgp_evpn_es_evi
*es_evi
;
2849 es_evi
= XCALLOC(MTYPE_BGP_EVPN_ES_EVI
, sizeof(*es_evi
));
2854 /* Initialise the VTEP list */
2855 es_evi
->es_evi_vtep_list
= list_new();
2856 listset_app_node_mem(es_evi
->es_evi_vtep_list
);
2857 es_evi
->es_evi_vtep_list
->cmp
= bgp_evpn_es_evi_vtep_cmp
;
2859 /* insert into the VNI-ESI rb tree */
2860 if (RB_INSERT(bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
, es_evi
)) {
2861 XFREE(MTYPE_BGP_EVPN_ES_EVI
, es_evi
);
2865 /* add to the ES's VNI list */
2866 listnode_init(&es_evi
->es_listnode
, es_evi
);
2867 listnode_add(es
->es_evi_list
, &es_evi
->es_listnode
);
2869 bgp_evpn_es_vrf_ref(es_evi
, vpn
->bgp_vrf
);
2874 /* remove the ES-EVI from the per-L2-VNI and per-ES tables and free
2877 static void bgp_evpn_es_evi_free(struct bgp_evpn_es_evi
*es_evi
)
2879 struct bgp_evpn_es
*es
= es_evi
->es
;
2880 struct bgpevpn
*vpn
= es_evi
->vpn
;
2882 /* cannot free the element as long as there is a local or remote
2885 if (es_evi
->flags
& (BGP_EVPNES_EVI_LOCAL
| BGP_EVPNES_EVI_REMOTE
))
2888 bgp_evpn_es_vrf_deref(es_evi
);
2890 /* remove from the ES's VNI list */
2891 list_delete_node(es
->es_evi_list
, &es_evi
->es_listnode
);
2893 /* remove from the VNI-ESI rb tree */
2894 RB_REMOVE(bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
, es_evi
);
2896 /* free the VTEP list */
2897 list_delete(&es_evi
->es_evi_vtep_list
);
2899 /* remove from the VNI-ESI rb tree */
2900 XFREE(MTYPE_BGP_EVPN_ES_EVI
, es_evi
);
2903 /* init local info associated with the ES-EVI */
2904 static void bgp_evpn_es_evi_local_info_set(struct bgp_evpn_es_evi
*es_evi
)
2906 struct bgpevpn
*vpn
= es_evi
->vpn
;
2908 if (CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
2911 SET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
);
2912 listnode_init(&es_evi
->l2vni_listnode
, es_evi
);
2913 listnode_add(vpn
->local_es_evi_list
, &es_evi
->l2vni_listnode
);
2916 /* clear any local info associated with the ES-EVI */
2917 static void bgp_evpn_es_evi_local_info_clear(struct bgp_evpn_es_evi
*es_evi
)
2919 struct bgpevpn
*vpn
= es_evi
->vpn
;
2921 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
2924 UNSET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
);
2925 list_delete_node(vpn
->local_es_evi_list
, &es_evi
->l2vni_listnode
);
2927 bgp_evpn_es_evi_free(es_evi
);
2930 /* eval remote info associated with the ES */
2931 static void bgp_evpn_es_evi_remote_info_re_eval(struct bgp_evpn_es_evi
*es_evi
)
2933 struct bgp_evpn_es
*es
= es_evi
->es
;
2935 /* if there are remote VTEPs the ES-EVI is classified as "remote" */
2936 if (listcount(es_evi
->es_evi_vtep_list
)) {
2937 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_REMOTE
)) {
2938 SET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_REMOTE
);
2939 ++es
->remote_es_evi_cnt
;
2940 /* set remote on the parent es */
2941 bgp_evpn_es_remote_info_re_eval(es
);
2944 if (CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_REMOTE
)) {
2945 UNSET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_REMOTE
);
2946 if (es
->remote_es_evi_cnt
)
2947 --es
->remote_es_evi_cnt
;
2948 bgp_evpn_es_evi_free(es_evi
);
2949 /* check if "remote" can be cleared from the
2952 bgp_evpn_es_remote_info_re_eval(es
);
2957 static void bgp_evpn_local_es_evi_do_del(struct bgp_evpn_es_evi
*es_evi
)
2959 struct prefix_evpn p
;
2960 struct bgp_evpn_es
*es
= es_evi
->es
;
2963 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
2966 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2967 zlog_debug("del local es %s evi %u",
2968 es_evi
->es
->esi_str
,
2971 bgp
= bgp_get_evpn();
2974 /* update EAD-ES with new list of VNIs */
2975 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_OPER_UP
)) {
2976 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_ES_ETH_TAG
,
2977 &es
->esi
, es
->originator_ip
);
2978 if (bgp_evpn_type1_route_update(bgp
, es
, NULL
, &p
))
2979 flog_err(EC_BGP_EVPN_ROUTE_CREATE
,
2980 "%u: EAD-ES route update failure for ESI %s VNI %u",
2981 bgp
->vrf_id
, es
->esi_str
,
2985 /* withdraw and delete EAD-EVI */
2986 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
)) {
2987 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_EVI_ETH_TAG
,
2988 &es
->esi
, es
->originator_ip
);
2989 if (bgp_evpn_type1_evi_route_delete(bgp
,
2990 es
, es_evi
->vpn
, &p
))
2991 flog_err(EC_BGP_EVPN_ROUTE_DELETE
,
2992 "%u: EAD-EVI route deletion failure for ESI %s VNI %u",
2993 bgp
->vrf_id
, es
->esi_str
,
2998 bgp_evpn_es_evi_local_info_clear(es_evi
);
3002 int bgp_evpn_local_es_evi_del(struct bgp
*bgp
, esi_t
*esi
, vni_t vni
)
3004 struct bgpevpn
*vpn
;
3005 struct bgp_evpn_es
*es
;
3006 struct bgp_evpn_es_evi
*es_evi
;
3007 char buf
[ESI_STR_LEN
];
3009 es
= bgp_evpn_es_find(esi
);
3013 "%u: Failed to deref VNI %d from ESI %s; ES not present",
3015 esi_to_str(esi
, buf
, sizeof(buf
)));
3019 vpn
= bgp_evpn_lookup_vni(bgp
, vni
);
3023 "%u: Failed to deref VNI %d from ESI %s; VNI not present",
3024 bgp
->vrf_id
, vni
, es
->esi_str
);
3028 es_evi
= bgp_evpn_es_evi_find(es
, vpn
);
3032 "%u: Failed to deref VNI %d from ESI %s; ES-VNI not present",
3033 bgp
->vrf_id
, vni
, es
->esi_str
);
3037 bgp_evpn_local_es_evi_do_del(es_evi
);
3041 /* Create ES-EVI and advertise the corresponding EAD routes */
3042 int bgp_evpn_local_es_evi_add(struct bgp
*bgp
, esi_t
*esi
, vni_t vni
)
3044 struct bgpevpn
*vpn
;
3045 struct prefix_evpn p
;
3046 struct bgp_evpn_es
*es
;
3047 struct bgp_evpn_es_evi
*es_evi
;
3048 char buf
[ESI_STR_LEN
];
3050 es
= bgp_evpn_es_find(esi
);
3054 "%u: Failed to associate VNI %d with ESI %s; ES not present",
3056 esi_to_str(esi
, buf
, sizeof(buf
)));
3060 vpn
= bgp_evpn_lookup_vni(bgp
, vni
);
3064 "%u: Failed to associate VNI %d with ESI %s; VNI not present",
3065 bgp
->vrf_id
, vni
, es
->esi_str
);
3069 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3070 zlog_debug("add local es %s evi %u",
3073 es_evi
= bgp_evpn_es_evi_find(es
, vpn
);
3076 if (CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
3080 es_evi
= bgp_evpn_es_evi_new(es
, vpn
);
3085 bgp_evpn_es_evi_local_info_set(es_evi
);
3087 /* generate an EAD-EVI for this new VNI */
3088 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
)) {
3089 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_EVI_ETH_TAG
, &es
->esi
,
3091 if (bgp_evpn_type1_route_update(bgp
, es
, vpn
, &p
))
3092 flog_err(EC_BGP_EVPN_ROUTE_CREATE
,
3093 "%u: EAD-EVI route creation failure for ESI %s VNI %u",
3094 bgp
->vrf_id
, es
->esi_str
, vni
);
3098 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_ES_ETH_TAG
,
3099 &es
->esi
, es
->originator_ip
);
3100 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_OPER_UP
)) {
3101 if (bgp_evpn_type1_route_update(bgp
, es
, NULL
, &p
))
3102 flog_err(EC_BGP_EVPN_ROUTE_CREATE
,
3103 "%u: EAD-ES route creation failure for ESI %s VNI %u",
3104 bgp
->vrf_id
, es
->esi_str
, vni
);
3110 /* Add remote ES-EVI entry. This is actually the remote VTEP add and the
3111 * ES-EVI is implicity created on first VTEP's reference.
3113 int bgp_evpn_remote_es_evi_add(struct bgp
*bgp
, struct bgpevpn
*vpn
,
3114 const struct prefix_evpn
*p
)
3116 char buf
[ESI_STR_LEN
];
3117 struct bgp_evpn_es
*es
;
3118 struct bgp_evpn_es_evi
*es_evi
;
3120 const esi_t
*esi
= &p
->prefix
.ead_addr
.esi
;
3123 /* local EAD-ES need not be sent back to zebra */
3126 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3127 zlog_debug("add remote %s es %s evi %u vtep %pI4",
3128 p
->prefix
.ead_addr
.eth_tag
? "ead-es" : "ead-evi",
3129 esi_to_str(esi
, buf
, sizeof(buf
)), vpn
->vni
,
3130 &p
->prefix
.ead_addr
.ip
.ipaddr_v4
);
3132 es
= bgp_evpn_es_find(esi
);
3134 es
= bgp_evpn_es_new(bgp
, esi
);
3136 flog_err(EC_BGP_ES_CREATE
,
3137 "%u: Failed to allocate ES entry for ESI %s - at remote ES Add",
3138 bgp
->vrf_id
, esi_to_str(esi
, buf
, sizeof(buf
)));
3143 es_evi
= bgp_evpn_es_evi_find(es
, vpn
);
3145 es_evi
= bgp_evpn_es_evi_new(es
, vpn
);
3147 bgp_evpn_es_free(es
, __func__
);
3152 ead_es
= !!p
->prefix
.ead_addr
.eth_tag
;
3153 bgp_evpn_es_evi_vtep_add(bgp
, es_evi
, p
->prefix
.ead_addr
.ip
.ipaddr_v4
,
3156 bgp_evpn_es_evi_remote_info_re_eval(es_evi
);
3160 /* A remote VTEP has withdrawn. The es-evi-vtep will be deleted and the
3161 * parent es-evi freed up implicitly in last VTEP's deref.
3163 int bgp_evpn_remote_es_evi_del(struct bgp
*bgp
, struct bgpevpn
*vpn
,
3164 const struct prefix_evpn
*p
)
3166 char buf
[ESI_STR_LEN
];
3167 struct bgp_evpn_es
*es
;
3168 struct bgp_evpn_es_evi
*es_evi
;
3172 /* local EAD-ES need not be sent back to zebra */
3175 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3177 "del remote %s es %s evi %u vtep %pI4",
3178 p
->prefix
.ead_addr
.eth_tag
? "ead-es" : "ead-evi",
3179 esi_to_str(&p
->prefix
.ead_addr
.esi
, buf
, sizeof(buf
)),
3180 vpn
->vni
, &p
->prefix
.ead_addr
.ip
.ipaddr_v4
);
3182 es
= bgp_evpn_es_find(&p
->prefix
.ead_addr
.esi
);
3184 /* XXX - error logs */
3186 es_evi
= bgp_evpn_es_evi_find(es
, vpn
);
3188 /* XXX - error logs */
3191 ead_es
= !!p
->prefix
.ead_addr
.eth_tag
;
3192 bgp_evpn_es_evi_vtep_del(bgp
, es_evi
, p
->prefix
.ead_addr
.ip
.ipaddr_v4
,
3194 bgp_evpn_es_evi_remote_info_re_eval(es_evi
);
3198 /* Initialize the ES tables maintained per-L2_VNI */
3199 void bgp_evpn_vni_es_init(struct bgpevpn
*vpn
)
3201 /* Initialize the ES-EVI RB tree */
3202 RB_INIT(bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
);
3204 /* Initialize the local list maintained for quick walks by type */
3205 vpn
->local_es_evi_list
= list_new();
3206 listset_app_node_mem(vpn
->local_es_evi_list
);
3209 /* Cleanup the ES info maintained per-L2_VNI */
3210 void bgp_evpn_vni_es_cleanup(struct bgpevpn
*vpn
)
3212 struct bgp_evpn_es_evi
*es_evi
;
3213 struct bgp_evpn_es_evi
*es_evi_next
;
3215 RB_FOREACH_SAFE(es_evi
, bgp_es_evi_rb_head
,
3216 &vpn
->es_evi_rb_tree
, es_evi_next
) {
3217 bgp_evpn_local_es_evi_do_del(es_evi
);
3220 list_delete(&vpn
->local_es_evi_list
);
3223 static char *bgp_evpn_es_evi_vteps_str(char *vtep_str
,
3224 struct bgp_evpn_es_evi
*es_evi
,
3225 uint8_t vtep_str_size
)
3227 char vtep_flag_str
[BGP_EVPN_FLAG_STR_SZ
];
3228 struct listnode
*node
;
3229 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
3231 char ip_buf
[INET6_ADDRSTRLEN
];
3234 for (ALL_LIST_ELEMENTS_RO(es_evi
->es_evi_vtep_list
, node
, evi_vtep
)) {
3235 vtep_flag_str
[0] = '\0';
3236 if (evi_vtep
->flags
& BGP_EVPN_EVI_VTEP_EAD_PER_ES
)
3237 strlcat(vtep_flag_str
, "E", sizeof(vtep_flag_str
));
3238 if (evi_vtep
->flags
& BGP_EVPN_EVI_VTEP_EAD_PER_EVI
)
3239 strlcat(vtep_flag_str
, "V", sizeof(vtep_flag_str
));
3241 if (!strnlen(vtep_flag_str
, sizeof(vtep_flag_str
)))
3242 strlcpy(vtep_flag_str
, "-", sizeof(vtep_flag_str
));
3246 strlcat(vtep_str
, ",", vtep_str_size
);
3248 inet_ntop(AF_INET
, &evi_vtep
->vtep_ip
, ip_buf
,
3251 strlcat(vtep_str
, "(", vtep_str_size
);
3252 strlcat(vtep_str
, vtep_flag_str
, vtep_str_size
);
3253 strlcat(vtep_str
, ")", vtep_str_size
);
3259 static void bgp_evpn_es_evi_json_vtep_fill(json_object
*json_vteps
,
3260 struct bgp_evpn_es_evi_vtep
*evi_vtep
)
3262 json_object
*json_vtep_entry
;
3263 json_object
*json_flags
;
3264 char ip_buf
[INET6_ADDRSTRLEN
];
3266 json_vtep_entry
= json_object_new_object();
3268 json_object_string_add(
3269 json_vtep_entry
, "vtep_ip",
3270 inet_ntop(AF_INET
, &evi_vtep
->vtep_ip
, ip_buf
, sizeof(ip_buf
)));
3271 if (evi_vtep
->flags
& (BGP_EVPN_EVI_VTEP_EAD_PER_ES
|
3272 BGP_EVPN_EVI_VTEP_EAD_PER_EVI
)) {
3273 json_flags
= json_object_new_array();
3274 if (evi_vtep
->flags
& BGP_EVPN_EVI_VTEP_EAD_PER_ES
)
3275 json_array_string_add(json_flags
, "ead-per-es");
3276 if (evi_vtep
->flags
& BGP_EVPN_EVI_VTEP_EAD_PER_EVI
)
3277 json_array_string_add(json_flags
, "ed-per-evi");
3278 json_object_object_add(json_vtep_entry
,
3279 "flags", json_flags
);
3282 json_object_array_add(json_vteps
,
3286 static void bgp_evpn_es_evi_show_entry(struct vty
*vty
,
3287 struct bgp_evpn_es_evi
*es_evi
, json_object
*json
)
3289 struct listnode
*node
;
3290 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
3293 json_object
*json_vteps
;
3294 json_object
*json_types
;
3296 json_object_string_add(json
, "esi", es_evi
->es
->esi_str
);
3297 json_object_int_add(json
, "vni", es_evi
->vpn
->vni
);
3299 if (es_evi
->flags
& (BGP_EVPNES_EVI_LOCAL
|
3300 BGP_EVPNES_EVI_REMOTE
)) {
3301 json_types
= json_object_new_array();
3302 if (es_evi
->flags
& BGP_EVPNES_EVI_LOCAL
)
3303 json_array_string_add(json_types
, "local");
3304 if (es_evi
->flags
& BGP_EVPNES_EVI_REMOTE
)
3305 json_array_string_add(json_types
, "remote");
3306 json_object_object_add(json
, "type", json_types
);
3309 if (listcount(es_evi
->es_evi_vtep_list
)) {
3310 json_vteps
= json_object_new_array();
3311 for (ALL_LIST_ELEMENTS_RO(es_evi
->es_evi_vtep_list
,
3313 bgp_evpn_es_evi_json_vtep_fill(json_vteps
,
3316 json_object_object_add(json
, "vteps", json_vteps
);
3320 char vtep_str
[ES_VTEP_LIST_STR_SZ
+ BGP_EVPN_VTEPS_FLAG_STR_SZ
];
3323 if (es_evi
->flags
& BGP_EVPNES_EVI_LOCAL
)
3324 strlcat(type_str
, "L", sizeof(type_str
));
3325 if (es_evi
->flags
& BGP_EVPNES_EVI_REMOTE
)
3326 strlcat(type_str
, "R", sizeof(type_str
));
3327 if (es_evi
->flags
& BGP_EVPNES_EVI_INCONS_VTEP_LIST
)
3328 strlcat(type_str
, "I", sizeof(type_str
));
3330 bgp_evpn_es_evi_vteps_str(vtep_str
, es_evi
, sizeof(vtep_str
));
3332 vty_out(vty
, "%-8d %-30s %-5s %s\n",
3333 es_evi
->vpn
->vni
, es_evi
->es
->esi_str
,
3334 type_str
, vtep_str
);
3338 static void bgp_evpn_es_evi_show_entry_detail(struct vty
*vty
,
3339 struct bgp_evpn_es_evi
*es_evi
, json_object
*json
)
3342 json_object
*json_flags
;
3344 /* Add the "brief" info first */
3345 bgp_evpn_es_evi_show_entry(vty
, es_evi
, json
);
3346 if (es_evi
->flags
& BGP_EVPNES_EVI_INCONS_VTEP_LIST
) {
3347 json_flags
= json_object_new_array();
3348 json_array_string_add(json_flags
, "es-vtep-mismatch");
3349 json_object_object_add(json
, "flags", json_flags
);
3352 char vtep_str
[ES_VTEP_LIST_STR_SZ
+ BGP_EVPN_VTEPS_FLAG_STR_SZ
];
3356 if (es_evi
->flags
& BGP_EVPNES_EVI_LOCAL
)
3357 strlcat(type_str
, "L", sizeof(type_str
));
3358 if (es_evi
->flags
& BGP_EVPNES_EVI_REMOTE
)
3359 strlcat(type_str
, "R", sizeof(type_str
));
3361 bgp_evpn_es_evi_vteps_str(vtep_str
, es_evi
, sizeof(vtep_str
));
3362 if (!strlen(vtep_str
))
3363 strlcpy(vtep_str
, "-", sizeof(type_str
));
3365 vty_out(vty
, "VNI: %d ESI: %s\n",
3366 es_evi
->vpn
->vni
, es_evi
->es
->esi_str
);
3367 vty_out(vty
, " Type: %s\n", type_str
);
3368 vty_out(vty
, " Inconsistencies: %s\n",
3369 (es_evi
->flags
& BGP_EVPNES_EVI_INCONS_VTEP_LIST
) ?
3370 "es-vtep-mismatch":"-");
3371 vty_out(vty
, " VTEPs: %s\n", vtep_str
);
3376 static void bgp_evpn_es_evi_show_one_vni(struct bgpevpn
*vpn
, struct vty
*vty
,
3377 json_object
*json_array
, bool detail
)
3379 struct bgp_evpn_es_evi
*es_evi
;
3380 json_object
*json
= NULL
;
3382 RB_FOREACH(es_evi
, bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
) {
3384 /* create a separate json object for each ES */
3385 json
= json_object_new_object();
3387 bgp_evpn_es_evi_show_entry_detail(vty
, es_evi
, json
);
3389 bgp_evpn_es_evi_show_entry(vty
, es_evi
, json
);
3390 /* add ES to the json array */
3392 json_object_array_add(json_array
, json
);
3396 struct es_evi_show_ctx
{
3402 static void bgp_evpn_es_evi_show_one_vni_hash_cb(struct hash_bucket
*bucket
,
3405 struct bgpevpn
*vpn
= (struct bgpevpn
*)bucket
->data
;
3406 struct es_evi_show_ctx
*wctx
= (struct es_evi_show_ctx
*)ctxt
;
3408 bgp_evpn_es_evi_show_one_vni(vpn
, wctx
->vty
, wctx
->json
, wctx
->detail
);
3411 /* Display all ES EVIs */
3412 void bgp_evpn_es_evi_show(struct vty
*vty
, bool uj
, bool detail
)
3414 json_object
*json_array
= NULL
;
3415 struct es_evi_show_ctx wctx
;
3419 /* create an array of ES-EVIs */
3420 json_array
= json_object_new_array();
3424 wctx
.json
= json_array
;
3425 wctx
.detail
= detail
;
3427 bgp
= bgp_get_evpn();
3429 if (!json_array
&& !detail
) {
3430 vty_out(vty
, "Flags: L local, R remote, I inconsistent\n");
3431 vty_out(vty
, "VTEP-Flags: E EAD-per-ES, V EAD-per-EVI\n");
3432 vty_out(vty
, "%-8s %-30s %-5s %s\n",
3433 "VNI", "ESI", "Flags", "VTEPs");
3437 hash_iterate(bgp
->vnihash
,
3438 (void (*)(struct hash_bucket
*,
3439 void *))bgp_evpn_es_evi_show_one_vni_hash_cb
,
3442 vty_out(vty
, "%s\n", json_object_to_json_string_ext(
3443 json_array
, JSON_C_TO_STRING_PRETTY
));
3444 json_object_free(json_array
);
3448 /* Display specific ES EVI */
3449 void bgp_evpn_es_evi_show_vni(struct vty
*vty
, vni_t vni
,
3450 bool uj
, bool detail
)
3452 struct bgpevpn
*vpn
= NULL
;
3453 json_object
*json_array
= NULL
;
3457 /* create an array of ES-EVIs */
3458 json_array
= json_object_new_array();
3461 bgp
= bgp_get_evpn();
3463 vpn
= bgp_evpn_lookup_vni(bgp
, vni
);
3466 if (!json_array
&& !detail
) {
3467 vty_out(vty
, "Flags: L local, R remote, I inconsistent\n");
3468 vty_out(vty
, "VTEP-Flags: E EAD-per-ES, V EAD-per-EVI\n");
3469 vty_out(vty
, "%-8s %-30s %-5s %s\n",
3470 "VNI", "ESI", "Flags", "VTEPs");
3473 bgp_evpn_es_evi_show_one_vni(vpn
, vty
, json_array
, detail
);
3476 vty_out(vty
, "VNI not found\n");
3480 vty_out(vty
, "%s\n", json_object_to_json_string_ext(
3481 json_array
, JSON_C_TO_STRING_PRETTY
));
3482 json_object_free(json_array
);
3486 /*****************************************************************************
3487 * Ethernet Segment Consistency checks
3488 * Consistency checking is done to detect misconfig or mis-cabling. When
3489 * an inconsistency is detected it is simply logged (and displayed via
3490 * show commands) at this point. A more drastic action can be executed (based
3491 * on user config) in the future.
3493 /* queue up the es for background consistency checks */
3494 static void bgp_evpn_es_cons_checks_pend_add(struct bgp_evpn_es
*es
)
3496 if (!bgp_mh_info
->consistency_checking
)
3497 /* consistency checking is not enabled */
3500 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_CONS_CHECK_PEND
))
3501 /* already queued for consistency checking */
3504 SET_FLAG(es
->flags
, BGP_EVPNES_CONS_CHECK_PEND
);
3505 listnode_init(&es
->pend_es_listnode
, es
);
3506 listnode_add_after(bgp_mh_info
->pend_es_list
,
3507 listtail_unchecked(bgp_mh_info
->pend_es_list
),
3508 &es
->pend_es_listnode
);
3511 /* pull the ES from the consistency check list */
3512 static void bgp_evpn_es_cons_checks_pend_del(struct bgp_evpn_es
*es
)
3514 if (!CHECK_FLAG(es
->flags
, BGP_EVPNES_CONS_CHECK_PEND
))
3517 UNSET_FLAG(es
->flags
, BGP_EVPNES_CONS_CHECK_PEND
);
3518 list_delete_node(bgp_mh_info
->pend_es_list
,
3519 &es
->pend_es_listnode
);
3522 /* Number of active VTEPs associated with the ES-per-EVI */
3523 static uint32_t bgp_evpn_es_evi_get_active_vtep_cnt(
3524 struct bgp_evpn_es_evi
*es_evi
)
3526 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
3527 struct listnode
*node
;
3528 uint32_t vtep_cnt
= 0;
3530 for (ALL_LIST_ELEMENTS_RO(es_evi
->es_evi_vtep_list
, node
, evi_vtep
)) {
3531 if (CHECK_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
))
3538 /* Number of active VTEPs associated with the ES */
3539 static uint32_t bgp_evpn_es_get_active_vtep_cnt(struct bgp_evpn_es
*es
)
3541 struct listnode
*node
;
3542 uint32_t vtep_cnt
= 0;
3543 struct bgp_evpn_es_vtep
*es_vtep
;
3545 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
3546 if (CHECK_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
))
3553 static struct bgp_evpn_es_vtep
*bgp_evpn_es_get_next_active_vtep(
3554 struct bgp_evpn_es
*es
, struct bgp_evpn_es_vtep
*es_vtep
)
3556 struct listnode
*node
;
3557 struct bgp_evpn_es_vtep
*next_es_vtep
;
3560 node
= listnextnode_unchecked(&es_vtep
->es_listnode
);
3562 node
= listhead(es
->es_vtep_list
);
3564 for (; node
; node
= listnextnode_unchecked(node
)) {
3565 next_es_vtep
= listgetdata(node
);
3566 if (CHECK_FLAG(next_es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
))
3567 return next_es_vtep
;
3573 static struct bgp_evpn_es_evi_vtep
*bgp_evpn_es_evi_get_next_active_vtep(
3574 struct bgp_evpn_es_evi
*es_evi
,
3575 struct bgp_evpn_es_evi_vtep
*evi_vtep
)
3577 struct listnode
*node
;
3578 struct bgp_evpn_es_evi_vtep
*next_evi_vtep
;
3581 node
= listnextnode_unchecked(&evi_vtep
->es_evi_listnode
);
3583 node
= listhead(es_evi
->es_evi_vtep_list
);
3585 for (; node
; node
= listnextnode_unchecked(node
)) {
3586 next_evi_vtep
= listgetdata(node
);
3587 if (CHECK_FLAG(next_evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
))
3588 return next_evi_vtep
;
3594 static void bgp_evpn_es_evi_set_inconsistent(struct bgp_evpn_es_evi
*es_evi
)
3596 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_INCONS_VTEP_LIST
)) {
3597 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3598 zlog_debug("inconsistency detected - es %s evi %u vtep list mismatch",
3599 es_evi
->es
->esi_str
,
3601 SET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_INCONS_VTEP_LIST
);
3603 /* update parent ES with the incosistency setting */
3604 if (!es_evi
->es
->incons_evi_vtep_cnt
&&
3605 BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3606 zlog_debug("inconsistency detected - es %s vtep list mismatch",
3607 es_evi
->es
->esi_str
);
3608 ++es_evi
->es
->incons_evi_vtep_cnt
;
3609 SET_FLAG(es_evi
->es
->inconsistencies
,
3610 BGP_EVPNES_INCONS_VTEP_LIST
);
3614 static uint32_t bgp_evpn_es_run_consistency_checks(struct bgp_evpn_es
*es
)
3617 int es_active_vtep_cnt
;
3618 int evi_active_vtep_cnt
;
3619 struct bgp_evpn_es_evi
*es_evi
;
3620 struct listnode
*evi_node
;
3621 struct bgp_evpn_es_vtep
*es_vtep
;
3622 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
3624 /* reset the inconsistencies and re-evaluate */
3625 es
->incons_evi_vtep_cnt
= 0;
3626 es
->inconsistencies
= 0;
3628 es_active_vtep_cnt
= bgp_evpn_es_get_active_vtep_cnt(es
);
3629 for (ALL_LIST_ELEMENTS_RO(es
->es_evi_list
,
3630 evi_node
, es_evi
)) {
3633 /* reset the inconsistencies on the EVI and re-evaluate*/
3634 UNSET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_INCONS_VTEP_LIST
);
3636 evi_active_vtep_cnt
=
3637 bgp_evpn_es_evi_get_active_vtep_cnt(es_evi
);
3638 if (es_active_vtep_cnt
!= evi_active_vtep_cnt
) {
3639 bgp_evpn_es_evi_set_inconsistent(es_evi
);
3643 if (!es_active_vtep_cnt
)
3648 while ((es_vtep
= bgp_evpn_es_get_next_active_vtep(
3650 evi_vtep
= bgp_evpn_es_evi_get_next_active_vtep(es_evi
,
3653 bgp_evpn_es_evi_set_inconsistent(es_evi
);
3656 if (es_vtep
->vtep_ip
.s_addr
!=
3657 evi_vtep
->vtep_ip
.s_addr
) {
3658 /* inconsistency detected; set it and move
3661 bgp_evpn_es_evi_set_inconsistent(es_evi
);
3670 static int bgp_evpn_run_consistency_checks(struct thread
*t
)
3674 struct listnode
*node
;
3675 struct listnode
*nextnode
;
3676 struct bgp_evpn_es
*es
;
3678 for (ALL_LIST_ELEMENTS(bgp_mh_info
->pend_es_list
,
3679 node
, nextnode
, es
)) {
3682 /* run consistency checks on the ES and remove it from the
3685 proc_cnt
+= bgp_evpn_es_run_consistency_checks(es
);
3686 bgp_evpn_es_cons_checks_pend_del(es
);
3691 /* restart the timer */
3692 thread_add_timer(bm
->master
, bgp_evpn_run_consistency_checks
, NULL
,
3693 BGP_EVPN_CONS_CHECK_INTERVAL
,
3694 &bgp_mh_info
->t_cons_check
);
3699 /*****************************************************************************/
3700 void bgp_evpn_mh_init(void)
3702 bm
->mh_info
= XCALLOC(MTYPE_BGP_EVPN_MH_INFO
, sizeof(*bm
->mh_info
));
3704 /* setup ES tables */
3705 RB_INIT(bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
);
3707 bgp_mh_info
->local_es_list
= list_new();
3708 listset_app_node_mem(bgp_mh_info
->local_es_list
);
3709 /* list of ESs with pending processing */
3710 bgp_mh_info
->pend_es_list
= list_new();
3711 listset_app_node_mem(bgp_mh_info
->pend_es_list
);
3713 bgp_mh_info
->ead_evi_rx
= BGP_EVPN_MH_EAD_EVI_RX_DEF
;
3714 bgp_mh_info
->ead_evi_tx
= BGP_EVPN_MH_EAD_EVI_TX_DEF
;
3716 /* config knobs - XXX add cli to control it */
3717 bgp_mh_info
->ead_evi_adv_for_down_links
= true;
3718 bgp_mh_info
->consistency_checking
= true;
3719 bgp_mh_info
->install_l3nhg
= false;
3720 bgp_mh_info
->host_routes_use_l3nhg
= BGP_EVPN_MH_USE_ES_L3NHG_DEF
;
3722 if (bgp_mh_info
->consistency_checking
)
3723 thread_add_timer(bm
->master
, bgp_evpn_run_consistency_checks
,
3724 NULL
, BGP_EVPN_CONS_CHECK_INTERVAL
,
3725 &bgp_mh_info
->t_cons_check
);
3727 memset(&zero_esi_buf
, 0, sizeof(esi_t
));
3730 void bgp_evpn_mh_finish(void)
3732 struct bgp_evpn_es
*es
;
3733 struct bgp_evpn_es
*es_next
;
3735 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
3736 zlog_debug("evpn mh finish");
3738 RB_FOREACH_SAFE (es
, bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
,
3740 bgp_evpn_es_local_info_clear(es
);
3742 thread_cancel(&bgp_mh_info
->t_cons_check
);
3743 list_delete(&bgp_mh_info
->local_es_list
);
3744 list_delete(&bgp_mh_info
->pend_es_list
);
3746 XFREE(MTYPE_BGP_EVPN_MH_INFO
, bgp_mh_info
);