1 /* EVPN Multihoming procedures
3 * Copyright (C) 2019 Cumulus Networks, Inc.
6 * This file is part of FRR.
8 * FRRouting is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2, or (at your option) any
13 * FRRouting is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
32 #include "lib/printfrr.h"
34 #include "bgpd/bgp_attr_evpn.h"
35 #include "bgpd/bgpd.h"
36 #include "bgpd/bgp_table.h"
37 #include "bgpd/bgp_route.h"
38 #include "bgpd/bgp_attr.h"
39 #include "bgpd/bgp_mplsvpn.h"
40 #include "bgpd/bgp_evpn.h"
41 #include "bgpd/bgp_evpn_private.h"
42 #include "bgpd/bgp_evpn_mh.h"
43 #include "bgpd/bgp_ecommunity.h"
44 #include "bgpd/bgp_encap_types.h"
45 #include "bgpd/bgp_debug.h"
46 #include "bgpd/bgp_errors.h"
47 #include "bgpd/bgp_aspath.h"
48 #include "bgpd/bgp_zebra.h"
49 #include "bgpd/bgp_addpath.h"
50 #include "bgpd/bgp_label.h"
51 #include "bgpd/bgp_nht.h"
52 #include "bgpd/bgp_mpath.h"
54 static void bgp_evpn_local_es_down(struct bgp
*bgp
,
55 struct bgp_evpn_es
*es
);
56 static void bgp_evpn_local_type1_evi_route_del(struct bgp
*bgp
,
57 struct bgp_evpn_es
*es
);
58 static struct bgp_evpn_es_vtep
*bgp_evpn_es_vtep_add(struct bgp
*bgp
,
59 struct bgp_evpn_es
*es
,
60 struct in_addr vtep_ip
,
61 bool esr
, uint8_t df_alg
,
63 static void bgp_evpn_es_vtep_del(struct bgp
*bgp
,
64 struct bgp_evpn_es
*es
, struct in_addr vtep_ip
, bool esr
);
65 static void bgp_evpn_es_cons_checks_pend_add(struct bgp_evpn_es
*es
);
66 static void bgp_evpn_es_cons_checks_pend_del(struct bgp_evpn_es
*es
);
67 static void bgp_evpn_local_es_evi_do_del(struct bgp_evpn_es_evi
*es_evi
);
68 static uint32_t bgp_evpn_es_get_active_vtep_cnt(struct bgp_evpn_es
*es
);
69 static void bgp_evpn_l3nhg_update_on_vtep_chg(struct bgp_evpn_es
*es
);
70 static struct bgp_evpn_es
*bgp_evpn_es_new(struct bgp
*bgp
, const esi_t
*esi
);
71 static void bgp_evpn_es_free(struct bgp_evpn_es
*es
, const char *caller
);
73 bgp_evpn_es_path_update_on_vtep_chg(struct bgp_evpn_es_vtep
*es_vtep
,
76 esi_t zero_esi_buf
, *zero_esi
= &zero_esi_buf
;
78 /******************************************************************************
79 * per-ES (Ethernet Segment) routing table
81 * Following routes are added to the ES's routing table -
82 * 1. Local and remote ESR (Type-4)
83 * 2. Local EAD-per-ES (Type-1).
85 * Key for these routes is {ESI, VTEP-IP} so the path selection is practically
86 * a no-op i.e. all paths lead to same VTEP-IP (i.e. result in the same VTEP
87 * being added to same ES).
89 * Note the following routes go into the VNI routing table (instead of the
91 * 1. Remote EAD-per-ES
92 * 2. Local and remote EAD-per-EVI
95 /* Calculate the best path for a multi-homing (Type-1 or Type-4) route
96 * installed in the ES's routing table.
98 static int bgp_evpn_es_route_select_install(struct bgp
*bgp
,
99 struct bgp_evpn_es
*es
,
100 struct bgp_dest
*dest
)
103 afi_t afi
= AFI_L2VPN
;
104 safi_t safi
= SAFI_EVPN
;
105 struct bgp_path_info
*old_select
; /* old best */
106 struct bgp_path_info
*new_select
; /* new best */
107 struct bgp_path_info_pair old_and_new
;
109 /* Compute the best path. */
110 bgp_best_selection(bgp
, dest
, &bgp
->maxpaths
[afi
][safi
], &old_and_new
,
112 old_select
= old_and_new
.old
;
113 new_select
= old_and_new
.new;
116 * If the best path hasn't changed - see if something needs to be
119 if (old_select
&& old_select
== new_select
120 && old_select
->type
== ZEBRA_ROUTE_BGP
121 && old_select
->sub_type
== BGP_ROUTE_IMPORTED
122 && !CHECK_FLAG(dest
->flags
, BGP_NODE_USER_CLEAR
)
123 && !CHECK_FLAG(old_select
->flags
, BGP_PATH_ATTR_CHANGED
)
124 && !bgp_addpath_is_addpath_used(&bgp
->tx_addpath
, afi
, safi
)) {
125 if (bgp_zebra_has_route_changed(old_select
)) {
126 bgp_evpn_es_vtep_add(bgp
, es
, old_select
->attr
->nexthop
,
128 old_select
->attr
->df_alg
,
129 old_select
->attr
->df_pref
);
131 UNSET_FLAG(old_select
->flags
, BGP_PATH_MULTIPATH_CHG
);
132 bgp_zebra_clear_route_change_flags(dest
);
136 /* If the user did a "clear" this flag will be set */
137 UNSET_FLAG(dest
->flags
, BGP_NODE_USER_CLEAR
);
139 /* bestpath has changed; update relevant fields and install or uninstall
140 * into the zebra RIB.
142 if (old_select
|| new_select
)
143 bgp_bump_version(dest
);
146 bgp_path_info_unset_flag(dest
, old_select
, BGP_PATH_SELECTED
);
148 bgp_path_info_set_flag(dest
, new_select
, BGP_PATH_SELECTED
);
149 bgp_path_info_unset_flag(dest
, new_select
,
150 BGP_PATH_ATTR_CHANGED
);
151 UNSET_FLAG(new_select
->flags
, BGP_PATH_MULTIPATH_CHG
);
154 if (new_select
&& new_select
->type
== ZEBRA_ROUTE_BGP
155 && new_select
->sub_type
== BGP_ROUTE_IMPORTED
) {
156 bgp_evpn_es_vtep_add(bgp
, es
, new_select
->attr
->nexthop
,
157 true /*esr */, new_select
->attr
->df_alg
,
158 new_select
->attr
->df_pref
);
160 if (old_select
&& old_select
->type
== ZEBRA_ROUTE_BGP
161 && old_select
->sub_type
== BGP_ROUTE_IMPORTED
)
162 bgp_evpn_es_vtep_del(
163 bgp
, es
, old_select
->attr
->nexthop
,
167 /* Clear any route change flags. */
168 bgp_zebra_clear_route_change_flags(dest
);
170 /* Reap old select bgp_path_info, if it has been removed */
171 if (old_select
&& CHECK_FLAG(old_select
->flags
, BGP_PATH_REMOVED
))
172 bgp_path_info_reap(dest
, old_select
);
177 /* Install Type-1/Type-4 route entry in the per-ES routing table */
178 static int bgp_evpn_es_route_install(struct bgp
*bgp
,
179 struct bgp_evpn_es
*es
, struct prefix_evpn
*p
,
180 struct bgp_path_info
*parent_pi
)
183 struct bgp_dest
*dest
= NULL
;
184 struct bgp_path_info
*pi
= NULL
;
185 struct attr
*attr_new
= NULL
;
187 /* Create (or fetch) route within the VNI.
188 * NOTE: There is no RD here.
190 dest
= bgp_node_get(es
->route_table
, (struct prefix
*)p
);
192 /* Check if route entry is already present. */
193 for (pi
= bgp_dest_get_bgp_path_info(dest
); pi
; pi
= pi
->next
)
195 && (struct bgp_path_info
*)pi
->extra
->parent
==
200 /* Add (or update) attribute to hash. */
201 attr_new
= bgp_attr_intern(parent_pi
->attr
);
203 /* Create new route with its attribute. */
204 pi
= info_make(parent_pi
->type
, BGP_ROUTE_IMPORTED
, 0,
205 parent_pi
->peer
, attr_new
, dest
);
206 SET_FLAG(pi
->flags
, BGP_PATH_VALID
);
207 bgp_path_info_extra_get(pi
);
208 pi
->extra
->parent
= bgp_path_info_lock(parent_pi
);
209 bgp_dest_lock_node((struct bgp_dest
*)parent_pi
->net
);
210 bgp_path_info_add(dest
, pi
);
212 if (attrhash_cmp(pi
->attr
, parent_pi
->attr
)
213 && !CHECK_FLAG(pi
->flags
, BGP_PATH_REMOVED
)) {
214 bgp_dest_unlock_node(dest
);
217 /* The attribute has changed. */
218 /* Add (or update) attribute to hash. */
219 attr_new
= bgp_attr_intern(parent_pi
->attr
);
221 /* Restore route, if needed. */
222 if (CHECK_FLAG(pi
->flags
, BGP_PATH_REMOVED
))
223 bgp_path_info_restore(dest
, pi
);
225 /* Mark if nexthop has changed. */
226 if (!IPV4_ADDR_SAME(&pi
->attr
->nexthop
, &attr_new
->nexthop
))
227 SET_FLAG(pi
->flags
, BGP_PATH_IGP_CHANGED
);
229 /* Unintern existing, set to new. */
230 bgp_attr_unintern(&pi
->attr
);
232 pi
->uptime
= bgp_clock();
235 /* Perform route selection and update zebra, if required. */
236 ret
= bgp_evpn_es_route_select_install(bgp
, es
, dest
);
238 bgp_dest_unlock_node(dest
);
243 /* Uninstall Type-1/Type-4 route entry from the ES routing table */
244 static int bgp_evpn_es_route_uninstall(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
245 struct prefix_evpn
*p
, struct bgp_path_info
*parent_pi
)
248 struct bgp_dest
*dest
;
249 struct bgp_path_info
*pi
;
251 if (!es
->route_table
)
254 /* Locate route within the ESI.
255 * NOTE: There is no RD here.
257 dest
= bgp_node_lookup(es
->route_table
, (struct prefix
*)p
);
261 /* Find matching route entry. */
262 for (pi
= bgp_dest_get_bgp_path_info(dest
); pi
; pi
= pi
->next
)
264 && (struct bgp_path_info
*)pi
->extra
->parent
==
271 /* Mark entry for deletion */
272 bgp_path_info_delete(dest
, pi
);
274 /* Perform route selection and update zebra, if required. */
275 ret
= bgp_evpn_es_route_select_install(bgp
, es
, dest
);
277 /* Unlock route node. */
278 bgp_dest_unlock_node(dest
);
283 /* Install or unistall a Tyoe-4 route in the per-ES routing table */
284 int bgp_evpn_es_route_install_uninstall(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
285 afi_t afi
, safi_t safi
, struct prefix_evpn
*evp
,
286 struct bgp_path_info
*pi
, int install
)
291 ret
= bgp_evpn_es_route_install(bgp
, es
, evp
, pi
);
293 ret
= bgp_evpn_es_route_uninstall(bgp
, es
, evp
, pi
);
298 "%u: Failed to %s EVPN %s route in ESI %s",
300 install
? "install" : "uninstall",
307 /* Delete (and withdraw) local routes for specified ES from global and ES table.
308 * Also remove all remote routes from the per ES table. Invoked when ES
311 static void bgp_evpn_es_route_del_all(struct bgp
*bgp
, struct bgp_evpn_es
*es
)
313 struct bgp_dest
*dest
;
314 struct bgp_path_info
*pi
, *nextpi
;
316 /* de-activate the ES */
317 bgp_evpn_local_es_down(bgp
, es
);
318 bgp_evpn_local_type1_evi_route_del(bgp
, es
);
320 /* Walk this ES's routing table and delete all routes. */
321 for (dest
= bgp_table_top(es
->route_table
); dest
;
322 dest
= bgp_route_next(dest
)) {
323 for (pi
= bgp_dest_get_bgp_path_info(dest
);
324 (pi
!= NULL
) && (nextpi
= pi
->next
, 1); pi
= nextpi
) {
325 bgp_path_info_delete(dest
, pi
);
326 bgp_path_info_reap(dest
, pi
);
331 /*****************************************************************************
332 * Base APIs for creating MH routes (Type-1 or Type-4) on local ethernet
336 /* create or update local EVPN type1/type4 route entry.
339 * the ES table if ESR/EAD-ES (or)
340 * the VNI table if EAD-EVI (or)
341 * the global table if ESR/EAD-ES/EAD-EVI
343 * Note: vpn is applicable only to EAD-EVI routes (NULL for EAD-ES and
346 static int bgp_evpn_mh_route_update(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
347 struct bgpevpn
*vpn
, afi_t afi
, safi_t safi
,
348 struct bgp_dest
*dest
, struct attr
*attr
,
349 int add
, struct bgp_path_info
**ri
,
352 struct bgp_path_info
*tmp_pi
= NULL
;
353 struct bgp_path_info
*local_pi
= NULL
; /* local route entry if any */
354 struct bgp_path_info
*remote_pi
= NULL
; /* remote route entry if any */
355 struct attr
*attr_new
= NULL
;
356 struct prefix_evpn
*evp
;
359 evp
= (struct prefix_evpn
*)bgp_dest_get_prefix(dest
);
362 /* locate the local and remote entries if any */
363 for (tmp_pi
= bgp_dest_get_bgp_path_info(dest
); tmp_pi
;
364 tmp_pi
= tmp_pi
->next
) {
365 if (tmp_pi
->peer
== bgp
->peer_self
366 && tmp_pi
->type
== ZEBRA_ROUTE_BGP
367 && tmp_pi
->sub_type
== BGP_ROUTE_STATIC
)
369 if (tmp_pi
->type
== ZEBRA_ROUTE_BGP
370 && tmp_pi
->sub_type
== BGP_ROUTE_IMPORTED
371 && CHECK_FLAG(tmp_pi
->flags
, BGP_PATH_VALID
))
375 /* we don't expect to see a remote_ri at this point as
376 * an ES route has {esi, vtep_ip} as the key in the ES-rt-table
377 * in the VNI-rt-table.
382 "%u ERROR: local es route for ESI: %s Vtep %pI4 also learnt from remote",
383 bgp
->vrf_id
, es
->esi_str
, &es
->originator_ip
);
387 if (!local_pi
&& !add
)
390 /* create or update the entry */
393 /* Add or update attribute to hash */
394 attr_new
= bgp_attr_intern(attr
);
396 /* Create new route with its attribute. */
397 tmp_pi
= info_make(ZEBRA_ROUTE_BGP
, BGP_ROUTE_STATIC
, 0,
398 bgp
->peer_self
, attr_new
, dest
);
399 SET_FLAG(tmp_pi
->flags
, BGP_PATH_VALID
);
401 if (evp
->prefix
.route_type
== BGP_EVPN_AD_ROUTE
) {
402 bgp_path_info_extra_get(tmp_pi
);
403 tmp_pi
->extra
->num_labels
= 1;
405 vni2label(vpn
->vni
, &tmp_pi
->extra
->label
[0]);
407 tmp_pi
->extra
->label
[0] = 0;
410 /* add the newly created path to the route-node */
411 bgp_path_info_add(dest
, tmp_pi
);
414 if (attrhash_cmp(tmp_pi
->attr
, attr
)
415 && !CHECK_FLAG(tmp_pi
->flags
, BGP_PATH_REMOVED
))
418 /* The attribute has changed.
419 * Add (or update) attribute to hash.
421 attr_new
= bgp_attr_intern(attr
);
422 bgp_path_info_set_flag(dest
, tmp_pi
,
423 BGP_PATH_ATTR_CHANGED
);
425 /* Restore route, if needed. */
426 if (CHECK_FLAG(tmp_pi
->flags
, BGP_PATH_REMOVED
))
427 bgp_path_info_restore(dest
, tmp_pi
);
429 /* Unintern existing, set to new. */
430 bgp_attr_unintern(&tmp_pi
->attr
);
431 tmp_pi
->attr
= attr_new
;
432 tmp_pi
->uptime
= bgp_clock();
436 if (*route_changed
) {
437 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
439 "local ES %s vni %u route-type %s nexthop %pI4 updated",
440 es
->esi_str
, vpn
? vpn
->vni
: 0,
441 evp
->prefix
.route_type
== BGP_EVPN_ES_ROUTE
443 : (vpn
? "ead-evi" : "ead-es"),
444 &attr
->mp_nexthop_global_in
);
447 /* Return back the route entry. */
452 /* Delete local EVPN ESR (type-4) and EAD (type-1) route
454 * Note: vpn is applicable only to EAD-EVI routes (NULL for EAD-ES and
457 static int bgp_evpn_mh_route_delete(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
458 struct bgpevpn
*vpn
, struct prefix_evpn
*p
)
460 afi_t afi
= AFI_L2VPN
;
461 safi_t safi
= SAFI_EVPN
;
462 struct bgp_path_info
*pi
;
463 struct bgp_dest
*dest
= NULL
; /* dest in esi table */
464 struct bgp_dest
*global_dest
= NULL
; /* dest in global table */
465 struct bgp_table
*rt_table
;
466 struct prefix_rd
*prd
;
469 rt_table
= vpn
->route_table
;
472 rt_table
= es
->route_table
;
476 /* First, locate the route node within the ESI or VNI.
477 * If it doesn't exist, ther is nothing to do.
478 * Note: there is no RD here.
480 dest
= bgp_node_lookup(rt_table
, (struct prefix
*)p
);
484 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
486 "local ES %s vni %u route-type %s nexthop %pI4 delete",
487 es
->esi_str
, vpn
? vpn
->vni
: 0,
488 p
->prefix
.route_type
== BGP_EVPN_ES_ROUTE
490 : (vpn
? "ead-evi" : "ead-es"),
493 /* Next, locate route node in the global EVPN routing table.
494 * Note that this table is a 2-level tree (RD-level + Prefix-level)
497 bgp_global_evpn_node_lookup(bgp
->rib
[afi
][safi
], afi
, safi
,
498 (const struct prefix_evpn
*)p
, prd
);
501 /* Delete route entry in the global EVPN table. */
502 delete_evpn_route_entry(bgp
, afi
, safi
, global_dest
, &pi
);
504 /* Schedule for processing - withdraws to peers happen from
508 bgp_process(bgp
, global_dest
, afi
, safi
);
509 bgp_dest_unlock_node(global_dest
);
513 * Delete route entry in the ESI or VNI routing table.
514 * This can just be removed.
516 delete_evpn_route_entry(bgp
, afi
, safi
, dest
, &pi
);
518 bgp_path_info_reap(dest
, pi
);
519 bgp_dest_unlock_node(dest
);
523 /*****************************************************************************
524 * Ethernet Segment (Type-4) Routes
525 * ESRs are used for DF election. Currently service-carving described in
526 * RFC 7432 is NOT supported. Instead preference based DF election is
528 * Reference: draft-ietf-bess-evpn-pref-df
530 /* Build extended community for EVPN ES (type-4) route */
531 static void bgp_evpn_type4_route_extcomm_build(struct bgp_evpn_es
*es
,
534 struct ecommunity ecom_encap
;
535 struct ecommunity ecom_es_rt
;
536 struct ecommunity ecom_df
;
537 struct ecommunity_val eval
;
538 struct ecommunity_val eval_es_rt
;
539 struct ecommunity_val eval_df
;
540 bgp_encap_types tnl_type
;
544 tnl_type
= BGP_ENCAP_TYPE_VXLAN
;
545 memset(&ecom_encap
, 0, sizeof(ecom_encap
));
546 encode_encap_extcomm(tnl_type
, &eval
);
548 ecom_encap
.unit_size
= ECOMMUNITY_SIZE
;
549 ecom_encap
.val
= (uint8_t *)eval
.val
;
550 attr
->ecommunity
= ecommunity_dup(&ecom_encap
);
553 memset(&mac
, 0, sizeof(struct ethaddr
));
554 memset(&ecom_es_rt
, 0, sizeof(ecom_es_rt
));
555 es_get_system_mac(&es
->esi
, &mac
);
556 encode_es_rt_extcomm(&eval_es_rt
, &mac
);
558 ecom_es_rt
.unit_size
= ECOMMUNITY_SIZE
;
559 ecom_es_rt
.val
= (uint8_t *)eval_es_rt
.val
;
561 ecommunity_merge(attr
->ecommunity
, &ecom_es_rt
);
563 /* DF election extended community */
564 memset(&ecom_df
, 0, sizeof(ecom_df
));
565 encode_df_elect_extcomm(&eval_df
, es
->df_pref
);
567 ecom_df
.val
= (uint8_t *)eval_df
.val
;
568 attr
->ecommunity
= ecommunity_merge(attr
->ecommunity
, &ecom_df
);
570 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES
);
573 /* Create or update local type-4 route */
574 static int bgp_evpn_type4_route_update(struct bgp
*bgp
,
575 struct bgp_evpn_es
*es
, struct prefix_evpn
*p
)
578 int route_changed
= 0;
579 afi_t afi
= AFI_L2VPN
;
580 safi_t safi
= SAFI_EVPN
;
582 struct attr
*attr_new
= NULL
;
583 struct bgp_dest
*dest
= NULL
;
584 struct bgp_path_info
*pi
= NULL
;
586 memset(&attr
, 0, sizeof(struct attr
));
588 /* Build path-attribute for this route. */
589 bgp_attr_default_set(&attr
, BGP_ORIGIN_IGP
);
590 attr
.nexthop
= es
->originator_ip
;
591 attr
.mp_nexthop_global_in
= es
->originator_ip
;
592 attr
.mp_nexthop_len
= BGP_ATTR_NHLEN_IPV4
;
594 /* Set up extended community. */
595 bgp_evpn_type4_route_extcomm_build(es
, &attr
);
597 /* First, create (or fetch) route node within the ESI. */
598 /* NOTE: There is no RD here. */
599 dest
= bgp_node_get(es
->route_table
, (struct prefix
*)p
);
601 /* Create or update route entry. */
602 ret
= bgp_evpn_mh_route_update(bgp
, es
, NULL
, afi
, safi
, dest
, &attr
, 1,
603 &pi
, &route_changed
);
607 "%u ERROR: Failed to updated ES route ESI: %s VTEP %pI4",
608 bgp
->vrf_id
, es
->esi_str
, &es
->originator_ip
);
613 /* Perform route selection;
614 * this is just to set the flags correctly
615 * as local route in the ES always wins.
617 bgp_evpn_es_route_select_install(bgp
, es
, dest
);
618 bgp_dest_unlock_node(dest
);
620 /* If this is a new route or some attribute has changed, export the
621 * route to the global table. The route will be advertised to peers
622 * from there. Note that this table is a 2-level tree (RD-level +
623 * Prefix-level) similar to L3VPN routes.
626 struct bgp_path_info
*global_pi
;
628 dest
= bgp_global_evpn_node_get(bgp
->rib
[afi
][safi
], afi
, safi
,
630 bgp_evpn_mh_route_update(bgp
, es
, NULL
, afi
, safi
, dest
,
631 attr_new
, 1, &global_pi
,
634 /* Schedule for processing and unlock node. */
635 bgp_process(bgp
, dest
, afi
, safi
);
636 bgp_dest_unlock_node(dest
);
639 /* Unintern temporary. */
640 aspath_unintern(&attr
.aspath
);
644 /* Delete local type-4 route */
645 static int bgp_evpn_type4_route_delete(struct bgp
*bgp
,
646 struct bgp_evpn_es
*es
, struct prefix_evpn
*p
)
648 return bgp_evpn_mh_route_delete(bgp
, es
, NULL
/* l2vni */, p
);
651 /* Process remote/received EVPN type-4 route (advertise or withdraw) */
652 int bgp_evpn_type4_route_process(struct peer
*peer
, afi_t afi
, safi_t safi
,
653 struct attr
*attr
, uint8_t *pfx
, int psize
,
659 struct in_addr vtep_ip
;
660 struct prefix_rd prd
;
661 struct prefix_evpn p
;
663 /* Type-4 route should be either 23 or 35 bytes
664 * RD (8), ESI (10), ip-len (1), ip (4 or 16)
666 if (psize
!= BGP_EVPN_TYPE4_V4_PSIZE
&&
667 psize
!= BGP_EVPN_TYPE4_V6_PSIZE
) {
668 flog_err(EC_BGP_EVPN_ROUTE_INVALID
,
669 "%u:%s - Rx EVPN Type-4 NLRI with invalid length %d",
670 peer
->bgp
->vrf_id
, peer
->host
, psize
);
675 prd
.family
= AF_UNSPEC
;
677 memcpy(&prd
.val
, pfx
, RD_BYTES
);
681 memcpy(&esi
, pfx
, ESI_BYTES
);
687 if (ipaddr_len
== IPV4_MAX_BITLEN
) {
688 memcpy(&vtep_ip
, pfx
, IPV4_MAX_BYTELEN
);
691 EC_BGP_EVPN_ROUTE_INVALID
,
692 "%u:%s - Rx EVPN Type-4 NLRI with unsupported IP address length %d",
693 peer
->bgp
->vrf_id
, peer
->host
, ipaddr_len
);
697 build_evpn_type4_prefix(&p
, &esi
, vtep_ip
);
698 /* Process the route. */
700 ret
= bgp_update(peer
, (struct prefix
*)&p
, addpath_id
, attr
,
701 afi
, safi
, ZEBRA_ROUTE_BGP
, BGP_ROUTE_NORMAL
,
702 &prd
, NULL
, 0, 0, NULL
);
704 ret
= bgp_withdraw(peer
, (struct prefix
*)&p
, addpath_id
, attr
,
705 afi
, safi
, ZEBRA_ROUTE_BGP
, BGP_ROUTE_NORMAL
,
706 &prd
, NULL
, 0, NULL
);
711 /* Check if a prefix belongs to the local ES */
712 static bool bgp_evpn_type4_prefix_match(struct prefix_evpn
*p
,
713 struct bgp_evpn_es
*es
)
715 return (p
->prefix
.route_type
== BGP_EVPN_ES_ROUTE
) &&
716 !memcmp(&p
->prefix
.es_addr
.esi
, &es
->esi
, sizeof(esi_t
));
719 /* Import remote ESRs on local ethernet segment add */
720 static int bgp_evpn_type4_remote_routes_import(struct bgp
*bgp
,
721 struct bgp_evpn_es
*es
, bool install
)
726 struct bgp_dest
*rd_dest
, *dest
;
727 struct bgp_table
*table
;
728 struct bgp_path_info
*pi
;
733 /* Walk entire global routing table and evaluate routes which could be
734 * imported into this Ethernet Segment.
736 for (rd_dest
= bgp_table_top(bgp
->rib
[afi
][safi
]); rd_dest
;
737 rd_dest
= bgp_route_next(rd_dest
)) {
738 table
= bgp_dest_get_bgp_table_info(rd_dest
);
742 for (dest
= bgp_table_top(table
); dest
;
743 dest
= bgp_route_next(dest
)) {
744 struct prefix_evpn
*evp
=
745 (struct prefix_evpn
*)bgp_dest_get_prefix(dest
);
747 for (pi
= bgp_dest_get_bgp_path_info(dest
); pi
;
750 * Consider "valid" remote routes applicable for
753 if (!(CHECK_FLAG(pi
->flags
, BGP_PATH_VALID
)
754 && pi
->type
== ZEBRA_ROUTE_BGP
755 && pi
->sub_type
== BGP_ROUTE_NORMAL
))
758 if (!bgp_evpn_type4_prefix_match(evp
, es
))
762 ret
= bgp_evpn_es_route_install(
765 ret
= bgp_evpn_es_route_uninstall(
771 "Failed to %s EVPN %pFX route in ESI %s",
776 bgp_dest_unlock_node(rd_dest
);
777 bgp_dest_unlock_node(dest
);
786 /*****************************************************************************
787 * Ethernet Auto Discovery (EAD/Type-1) route handling
788 * There are two types of EAD routes -
789 * 1. EAD-per-ES - Key: {ESI, ET=0xffffffff}
790 * 2. EAD-per-EVI - Key: {ESI, ET=0}
793 /* Extended communities associated with EAD-per-ES */
794 static void bgp_evpn_type1_es_route_extcomm_build(struct bgp_evpn_es
*es
,
797 struct ecommunity ecom_encap
;
798 struct ecommunity ecom_esi_label
;
799 struct ecommunity_val eval
;
800 struct ecommunity_val eval_esi_label
;
801 bgp_encap_types tnl_type
;
802 struct listnode
*evi_node
, *rt_node
;
803 struct ecommunity
*ecom
;
804 struct bgp_evpn_es_evi
*es_evi
;
807 tnl_type
= BGP_ENCAP_TYPE_VXLAN
;
808 memset(&ecom_encap
, 0, sizeof(ecom_encap
));
809 encode_encap_extcomm(tnl_type
, &eval
);
811 ecom_encap
.unit_size
= ECOMMUNITY_SIZE
;
812 ecom_encap
.val
= (uint8_t *)eval
.val
;
813 attr
->ecommunity
= ecommunity_dup(&ecom_encap
);
816 encode_esi_label_extcomm(&eval_esi_label
,
817 false /*single_active*/);
818 ecom_esi_label
.size
= 1;
819 ecom_esi_label
.unit_size
= ECOMMUNITY_SIZE
;
820 ecom_esi_label
.val
= (uint8_t *)eval_esi_label
.val
;
822 ecommunity_merge(attr
->ecommunity
, &ecom_esi_label
);
824 /* Add export RTs for all L2-VNIs associated with this ES */
825 /* XXX - suppress EAD-ES advertisment if there are no EVIs associated
828 for (ALL_LIST_ELEMENTS_RO(es
->es_evi_list
,
830 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
832 for (ALL_LIST_ELEMENTS_RO(es_evi
->vpn
->export_rtl
,
834 attr
->ecommunity
= ecommunity_merge(attr
->ecommunity
,
838 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES
);
841 /* Extended communities associated with EAD-per-EVI */
842 static void bgp_evpn_type1_evi_route_extcomm_build(struct bgp_evpn_es
*es
,
843 struct bgpevpn
*vpn
, struct attr
*attr
)
845 struct ecommunity ecom_encap
;
846 struct ecommunity_val eval
;
847 bgp_encap_types tnl_type
;
848 struct listnode
*rt_node
;
849 struct ecommunity
*ecom
;
852 tnl_type
= BGP_ENCAP_TYPE_VXLAN
;
853 memset(&ecom_encap
, 0, sizeof(ecom_encap
));
854 encode_encap_extcomm(tnl_type
, &eval
);
856 ecom_encap
.unit_size
= ECOMMUNITY_SIZE
;
857 ecom_encap
.val
= (uint8_t *)eval
.val
;
858 attr
->ecommunity
= ecommunity_dup(&ecom_encap
);
860 /* Add export RTs for the L2-VNI */
861 for (ALL_LIST_ELEMENTS_RO(vpn
->export_rtl
, rt_node
, ecom
))
862 attr
->ecommunity
= ecommunity_merge(attr
->ecommunity
, ecom
);
864 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES
);
867 /* Update EVPN EAD (type-1) route -
868 * vpn - valid for EAD-EVI routes and NULL for EAD-ES routes
870 static int bgp_evpn_type1_route_update(struct bgp
*bgp
,
871 struct bgp_evpn_es
*es
, struct bgpevpn
*vpn
,
872 struct prefix_evpn
*p
)
875 afi_t afi
= AFI_L2VPN
;
876 safi_t safi
= SAFI_EVPN
;
878 struct attr
*attr_new
= NULL
;
879 struct bgp_dest
*dest
= NULL
;
880 struct bgp_path_info
*pi
= NULL
;
881 int route_changed
= 0;
882 struct prefix_rd
*global_rd
;
884 memset(&attr
, 0, sizeof(struct attr
));
886 /* Build path-attribute for this route. */
887 bgp_attr_default_set(&attr
, BGP_ORIGIN_IGP
);
888 attr
.nexthop
= es
->originator_ip
;
889 attr
.mp_nexthop_global_in
= es
->originator_ip
;
890 attr
.mp_nexthop_len
= BGP_ATTR_NHLEN_IPV4
;
893 /* EAD-EVI route update */
895 vni2label(vpn
->vni
, &(attr
.label
));
897 /* Set up extended community */
898 bgp_evpn_type1_evi_route_extcomm_build(es
, vpn
, &attr
);
900 /* First, create (or fetch) route node within the VNI. */
901 dest
= bgp_node_get(vpn
->route_table
, (struct prefix
*)p
);
903 /* Create or update route entry. */
904 ret
= bgp_evpn_mh_route_update(bgp
, es
, vpn
, afi
, safi
, dest
,
905 &attr
, 1, &pi
, &route_changed
);
909 "%u Failed to update EAD-EVI route ESI: %s VNI %u VTEP %pI4",
910 bgp
->vrf_id
, es
->esi_str
, vpn
->vni
,
912 global_rd
= &vpn
->prd
;
914 /* EAD-ES route update */
915 /* MPLS label is 0 for EAD-ES route */
917 /* Set up extended community */
918 bgp_evpn_type1_es_route_extcomm_build(es
, &attr
);
920 /* First, create (or fetch) route node within the ES. */
921 /* NOTE: There is no RD here. */
922 /* XXX: fragment ID must be included as a part of the prefix. */
923 dest
= bgp_node_get(es
->route_table
, (struct prefix
*)p
);
925 /* Create or update route entry. */
926 ret
= bgp_evpn_mh_route_update(bgp
, es
, vpn
, afi
, safi
, dest
,
927 &attr
, 1, &pi
, &route_changed
);
931 "%u ERROR: Failed to updated EAD-EVI route ESI: %s VTEP %pI4",
932 bgp
->vrf_id
, es
->esi_str
, &es
->originator_ip
);
934 global_rd
= &es
->prd
;
941 /* Perform route selection;
942 * this is just to set the flags correctly as local route in
943 * the ES always wins.
945 evpn_route_select_install(bgp
, vpn
, dest
);
946 bgp_dest_unlock_node(dest
);
948 /* If this is a new route or some attribute has changed, export the
949 * route to the global table. The route will be advertised to peers
950 * from there. Note that this table is a 2-level tree (RD-level +
951 * Prefix-level) similar to L3VPN routes.
954 struct bgp_path_info
*global_pi
;
956 dest
= bgp_global_evpn_node_get(bgp
->rib
[afi
][safi
], afi
, safi
,
958 bgp_evpn_mh_route_update(bgp
, es
, vpn
, afi
, safi
, dest
,
959 attr_new
, 1, &global_pi
,
962 /* Schedule for processing and unlock node. */
963 bgp_process(bgp
, dest
, afi
, safi
);
964 bgp_dest_unlock_node(dest
);
967 /* Unintern temporary. */
968 aspath_unintern(&attr
.aspath
);
972 /* Delete local Type-1 route */
973 static int bgp_evpn_type1_es_route_delete(struct bgp
*bgp
,
974 struct bgp_evpn_es
*es
, struct prefix_evpn
*p
)
976 return bgp_evpn_mh_route_delete(bgp
, es
, NULL
/* l2vni */, p
);
979 static int bgp_evpn_type1_evi_route_delete(struct bgp
*bgp
,
980 struct bgp_evpn_es
*es
, struct bgpevpn
*vpn
,
981 struct prefix_evpn
*p
)
983 return bgp_evpn_mh_route_delete(bgp
, es
, vpn
, p
);
986 /* Generate EAD-EVI for all VNIs */
987 static void bgp_evpn_local_type1_evi_route_add(struct bgp
*bgp
,
988 struct bgp_evpn_es
*es
)
990 struct listnode
*evi_node
;
991 struct prefix_evpn p
;
992 struct bgp_evpn_es_evi
*es_evi
;
994 /* EAD-per-EVI routes have been suppressed */
995 if (!bgp_mh_info
->ead_evi_tx
)
998 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
))
999 /* EAD-EVI route add for this ES is already done */
1002 SET_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
);
1003 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_EVI_ETH_TAG
,
1004 &es
->esi
, es
->originator_ip
);
1006 for (ALL_LIST_ELEMENTS_RO(es
->es_evi_list
, evi_node
, es_evi
)) {
1007 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
1009 if (bgp_evpn_type1_route_update(bgp
, es
, es_evi
->vpn
, &p
))
1010 flog_err(EC_BGP_EVPN_ROUTE_CREATE
,
1011 "%u: Type4 route creation failure for ESI %s",
1012 bgp
->vrf_id
, es
->esi_str
);
1017 * Withdraw EAD-EVI for all VNIs
1019 static void bgp_evpn_local_type1_evi_route_del(struct bgp
*bgp
,
1020 struct bgp_evpn_es
*es
)
1022 struct listnode
*evi_node
;
1023 struct prefix_evpn p
;
1024 struct bgp_evpn_es_evi
*es_evi
;
1026 /* Delete and withdraw locally learnt EAD-EVI route */
1027 if (!CHECK_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
))
1028 /* EAD-EVI route has not been advertised for this ES */
1031 UNSET_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
);
1032 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_EVI_ETH_TAG
,
1033 &es
->esi
, es
->originator_ip
);
1034 for (ALL_LIST_ELEMENTS_RO(es
->es_evi_list
, evi_node
, es_evi
)) {
1035 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
1037 if (bgp_evpn_mh_route_delete(bgp
, es
, es_evi
->vpn
, &p
))
1038 flog_err(EC_BGP_EVPN_ROUTE_CREATE
,
1039 "%u: Type4 route creation failure for ESI %s",
1040 bgp
->vrf_id
, es
->esi_str
);
1045 * Process received EVPN type-1 route (advertise or withdraw).
1047 int bgp_evpn_type1_route_process(struct peer
*peer
, afi_t afi
, safi_t safi
,
1048 struct attr
*attr
, uint8_t *pfx
, int psize
,
1049 uint32_t addpath_id
)
1052 struct prefix_rd prd
;
1056 struct in_addr vtep_ip
;
1057 struct prefix_evpn p
;
1059 if (psize
!= BGP_EVPN_TYPE1_PSIZE
) {
1060 flog_err(EC_BGP_EVPN_ROUTE_INVALID
,
1061 "%u:%s - Rx EVPN Type-1 NLRI with invalid length %d",
1062 peer
->bgp
->vrf_id
, peer
->host
, psize
);
1066 /* Make prefix_rd */
1067 prd
.family
= AF_UNSPEC
;
1069 memcpy(&prd
.val
, pfx
, RD_BYTES
);
1073 memcpy(&esi
, pfx
, ESI_BYTES
);
1076 /* Copy Ethernet Tag */
1077 memcpy(ð_tag
, pfx
, EVPN_ETH_TAG_BYTES
);
1078 eth_tag
= ntohl(eth_tag
);
1079 pfx
+= EVPN_ETH_TAG_BYTES
;
1081 memcpy(&label
, pfx
, BGP_LABEL_BYTES
);
1083 /* EAD route prefix doesn't include the nexthop in the global
1086 vtep_ip
.s_addr
= INADDR_ANY
;
1087 build_evpn_type1_prefix(&p
, eth_tag
, &esi
, vtep_ip
);
1088 /* Process the route. */
1090 ret
= bgp_update(peer
, (struct prefix
*)&p
, addpath_id
, attr
,
1091 afi
, safi
, ZEBRA_ROUTE_BGP
, BGP_ROUTE_NORMAL
,
1092 &prd
, NULL
, 0, 0, NULL
);
1094 ret
= bgp_withdraw(peer
, (struct prefix
*)&p
, addpath_id
, attr
,
1095 afi
, safi
, ZEBRA_ROUTE_BGP
, BGP_ROUTE_NORMAL
,
1096 &prd
, NULL
, 0, NULL
);
1101 /*****************************************************************************/
1102 /* Ethernet Segment Management
1103 * 1. Ethernet Segment is a collection of links attached to the same
1104 * server (MHD) or switch (MHN)
1105 * 2. An Ethernet Segment can span multiple PEs and is identified by the
1107 * 3. Local ESs are configured in zebra and sent to BGP
1108 * 4. Remote ESs are created by BGP when one or more ES-EVIs reference it i.e.
1109 * created on first reference and release on last de-reference
1110 * 5. An ES can be both local and remote. Infact most local ESs are expected
1111 * to have an ES peer.
1114 /* A list of remote VTEPs is maintained for each ES. This list includes -
1115 * 1. VTEPs for which we have imported the ESR i.e. ES-peers
1116 * 2. VTEPs that have an "active" ES-EVI VTEP i.e. EAD-per-ES and EAD-per-EVI
1117 * have been imported into one or more VNIs
1119 static int bgp_evpn_es_vtep_cmp(void *p1
, void *p2
)
1121 const struct bgp_evpn_es_vtep
*es_vtep1
= p1
;
1122 const struct bgp_evpn_es_vtep
*es_vtep2
= p2
;
1124 return es_vtep1
->vtep_ip
.s_addr
- es_vtep2
->vtep_ip
.s_addr
;
1127 static struct bgp_evpn_es_vtep
*bgp_evpn_es_vtep_new(struct bgp_evpn_es
*es
,
1128 struct in_addr vtep_ip
)
1130 struct bgp_evpn_es_vtep
*es_vtep
;
1132 es_vtep
= XCALLOC(MTYPE_BGP_EVPN_ES_VTEP
, sizeof(*es_vtep
));
1135 es_vtep
->vtep_ip
.s_addr
= vtep_ip
.s_addr
;
1136 listnode_init(&es_vtep
->es_listnode
, es_vtep
);
1137 listnode_add_sort(es
->es_vtep_list
, &es_vtep
->es_listnode
);
1142 static void bgp_evpn_es_vtep_free(struct bgp_evpn_es_vtep
*es_vtep
)
1144 struct bgp_evpn_es
*es
= es_vtep
->es
;
1146 if (CHECK_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ESR
) ||
1148 /* as long as there is some reference we can't free it */
1151 list_delete_node(es
->es_vtep_list
, &es_vtep
->es_listnode
);
1152 XFREE(MTYPE_BGP_EVPN_ES_VTEP
, es_vtep
);
1155 /* check if VTEP is already part of the list */
1156 static struct bgp_evpn_es_vtep
*bgp_evpn_es_vtep_find(struct bgp_evpn_es
*es
,
1157 struct in_addr vtep_ip
)
1159 struct listnode
*node
= NULL
;
1160 struct bgp_evpn_es_vtep
*es_vtep
;
1162 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
1163 if (es_vtep
->vtep_ip
.s_addr
== vtep_ip
.s_addr
)
1169 /* Send the remote ES to zebra for NHG programming */
1170 static int bgp_zebra_send_remote_es_vtep(struct bgp
*bgp
,
1171 struct bgp_evpn_es_vtep
*es_vtep
, bool add
)
1173 struct bgp_evpn_es
*es
= es_vtep
->es
;
1178 if (!zclient
|| zclient
->sock
< 0)
1181 /* Don't try to register if Zebra doesn't know of this instance. */
1182 if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp
)) {
1183 if (BGP_DEBUG(zebra
, ZEBRA
))
1184 zlog_debug("No zebra instance, not installing remote es %s",
1189 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ESR
)
1190 flags
|= ZAPI_ES_VTEP_FLAG_ESR_RXED
;
1195 zclient_create_header(s
,
1196 add
? ZEBRA_REMOTE_ES_VTEP_ADD
: ZEBRA_REMOTE_ES_VTEP_DEL
,
1198 stream_put(s
, &es
->esi
, sizeof(esi_t
));
1199 stream_put_ipv4(s
, es_vtep
->vtep_ip
.s_addr
);
1201 stream_putl(s
, flags
);
1202 stream_putc(s
, es_vtep
->df_alg
);
1203 stream_putw(s
, es_vtep
->df_pref
);
1206 stream_putw_at(s
, 0, stream_get_endp(s
));
1208 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1209 zlog_debug("Tx %s Remote ESI %s VTEP %pI4", add
? "ADD" : "DEL",
1210 es
->esi_str
, &es_vtep
->vtep_ip
);
1212 return zclient_send_message(zclient
);
1215 static void bgp_evpn_es_vtep_re_eval_active(struct bgp
*bgp
,
1216 struct bgp_evpn_es_vtep
*es_vtep
,
1222 old_active
= !!CHECK_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
);
1223 /* currently we need an active EVI reference to use the VTEP as
1224 * a nexthop. this may change...
1226 if (es_vtep
->evi_cnt
)
1227 SET_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
);
1229 UNSET_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
);
1231 new_active
= !!CHECK_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
);
1233 if ((old_active
!= new_active
) || (new_active
&& param_change
)) {
1235 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1236 zlog_debug("es %s vtep %pI4 %s df %u/%u",
1237 es_vtep
->es
->esi_str
, &es_vtep
->vtep_ip
,
1238 new_active
? "active" : "inactive",
1239 es_vtep
->df_alg
, es_vtep
->df_pref
);
1241 /* send remote ES to zebra */
1242 bgp_zebra_send_remote_es_vtep(bgp
, es_vtep
, new_active
);
1244 /* The NHG is updated first for efficient failover handling.
1245 * Note the NHG can be de-activated while there are bgp
1246 * routes referencing it. Zebra is capable of handling that
1247 * elegantly by holding the NHG till all routes using it are
1250 bgp_evpn_l3nhg_update_on_vtep_chg(es_vtep
->es
);
1251 bgp_evpn_es_path_update_on_vtep_chg(es_vtep
, new_active
);
1253 /* queue up the es for background consistency checks */
1254 bgp_evpn_es_cons_checks_pend_add(es_vtep
->es
);
1258 static struct bgp_evpn_es_vtep
*bgp_evpn_es_vtep_add(struct bgp
*bgp
,
1259 struct bgp_evpn_es
*es
,
1260 struct in_addr vtep_ip
,
1261 bool esr
, uint8_t df_alg
,
1264 struct bgp_evpn_es_vtep
*es_vtep
;
1265 bool param_change
= false;
1267 es_vtep
= bgp_evpn_es_vtep_find(es
, vtep_ip
);
1270 es_vtep
= bgp_evpn_es_vtep_new(es
, vtep_ip
);
1272 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1273 zlog_debug("es %s vtep %pI4 add %s df %u/%u",
1274 es_vtep
->es
->esi_str
, &es_vtep
->vtep_ip
,
1275 esr
? "esr" : "ead", df_alg
, df_pref
);
1278 SET_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ESR
);
1279 if ((es_vtep
->df_pref
!= df_pref
)
1280 || (es_vtep
->df_alg
!= df_alg
)) {
1281 param_change
= true;
1282 es_vtep
->df_pref
= df_pref
;
1283 es_vtep
->df_alg
= df_alg
;
1289 bgp_evpn_es_vtep_re_eval_active(bgp
, es_vtep
, param_change
);
1294 static void bgp_evpn_es_vtep_do_del(struct bgp
*bgp
,
1295 struct bgp_evpn_es_vtep
*es_vtep
, bool esr
)
1297 bool param_change
= false;
1299 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1300 zlog_debug("es %s vtep %pI4 del %s", es_vtep
->es
->esi_str
,
1301 &es_vtep
->vtep_ip
, esr
? "esr" : "ead");
1303 UNSET_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ESR
);
1304 if (es_vtep
->df_pref
|| es_vtep
->df_alg
) {
1305 param_change
= true;
1306 es_vtep
->df_pref
= 0;
1307 es_vtep
->df_alg
= 0;
1310 if (es_vtep
->evi_cnt
)
1314 bgp_evpn_es_vtep_re_eval_active(bgp
, es_vtep
, param_change
);
1315 bgp_evpn_es_vtep_free(es_vtep
);
1318 static void bgp_evpn_es_vtep_del(struct bgp
*bgp
,
1319 struct bgp_evpn_es
*es
, struct in_addr vtep_ip
, bool esr
)
1321 struct bgp_evpn_es_vtep
*es_vtep
;
1323 es_vtep
= bgp_evpn_es_vtep_find(es
, vtep_ip
);
1325 bgp_evpn_es_vtep_do_del(bgp
, es_vtep
, esr
);
1328 bool bgp_evpn_es_is_vtep_active(esi_t
*esi
, struct in_addr nh
)
1330 struct bgp_evpn_es
*es
;
1331 struct bgp_evpn_es_vtep
*es_vtep
;
1332 struct listnode
*node
= NULL
;
1335 if (!memcmp(esi
, zero_esi
, sizeof(*esi
)) || !nh
.s_addr
)
1338 es
= bgp_evpn_es_find(esi
);
1342 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
1343 if (es_vtep
->vtep_ip
.s_addr
== nh
.s_addr
) {
1344 if (CHECK_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
))
1352 /********************** ES MAC-IP paths *************************************
1353 * MAC-IP routes in the VNI routing table are linked to the destination
1354 * ES for efficient updates on ES changes (such as VTEP add/del).
1355 ****************************************************************************/
1356 void bgp_evpn_path_es_info_free(struct bgp_path_es_info
*es_info
)
1358 bgp_evpn_path_es_unlink(es_info
);
1359 XFREE(MTYPE_BGP_EVPN_PATH_ES_INFO
, es_info
);
1362 static struct bgp_path_es_info
*
1363 bgp_evpn_path_es_info_new(struct bgp_path_info
*pi
, vni_t vni
)
1365 struct bgp_path_info_extra
*e
;
1367 e
= bgp_path_info_extra_get(pi
);
1369 /* If es_info doesn't exist allocate it */
1371 e
->es_info
= XCALLOC(MTYPE_BGP_EVPN_PATH_ES_INFO
,
1372 sizeof(struct bgp_path_es_info
));
1373 e
->es_info
->pi
= pi
;
1374 e
->es_info
->vni
= vni
;
1380 void bgp_evpn_path_es_unlink(struct bgp_path_es_info
*es_info
)
1382 struct bgp_evpn_es
*es
= es_info
->es
;
1383 struct bgp_path_info
*pi
;
1389 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
1390 zlog_debug("vni %u path %pFX unlinked from es %s", es_info
->vni
,
1391 &pi
->net
->p
, es
->esi_str
);
1393 list_delete_node(es
->macip_path_list
, &es_info
->es_listnode
);
1396 /* if there are no other references against the ES it
1399 bgp_evpn_es_free(es
, __func__
);
1401 /* Note we don't free the path es_info on unlink; it will be freed up
1402 * along with the path.
1406 void bgp_evpn_path_es_link(struct bgp_path_info
*pi
, vni_t vni
, esi_t
*esi
)
1408 struct bgp_path_es_info
*es_info
;
1409 struct bgp_evpn_es
*es
;
1410 struct bgp
*bgp_evpn
= bgp_get_evpn();
1412 es_info
= pi
->extra
? pi
->extra
->es_info
: NULL
;
1413 /* if the esi is zero just unlink the path from the old es */
1414 if (!esi
|| !memcmp(esi
, zero_esi
, sizeof(*esi
))) {
1416 bgp_evpn_path_es_unlink(es_info
);
1423 /* setup es_info against the path if it doesn't aleady exist */
1425 es_info
= bgp_evpn_path_es_info_new(pi
, vni
);
1427 /* find-create ES */
1428 es
= bgp_evpn_es_find(esi
);
1430 es
= bgp_evpn_es_new(bgp_evpn
, esi
);
1433 if (es_info
->es
== es
)
1436 /* unlink old ES if any */
1437 bgp_evpn_path_es_unlink(es_info
);
1439 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
1440 zlog_debug("vni %u path %pFX linked to es %s", vni
, &pi
->net
->p
,
1443 /* link mac-ip path to the new destination ES */
1445 listnode_init(&es_info
->es_listnode
, es_info
);
1446 listnode_add(es
->macip_path_list
, &es_info
->es_listnode
);
1450 bgp_evpn_es_path_update_on_vtep_chg(struct bgp_evpn_es_vtep
*es_vtep
,
1453 struct listnode
*node
;
1454 struct bgp_path_es_info
*es_info
;
1455 struct bgp_path_info
*pi
;
1456 struct bgp_path_info
*parent_pi
;
1457 struct bgp_evpn_es
*es
= es_vtep
->es
;
1459 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
1460 zlog_debug("update paths linked to es %s on vtep chg",
1463 for (ALL_LIST_ELEMENTS_RO(es
->macip_path_list
, node
, es_info
)) {
1465 if (!CHECK_FLAG(pi
->flags
, BGP_PATH_VALID
))
1468 if (pi
->sub_type
!= BGP_ROUTE_IMPORTED
)
1471 parent_pi
= pi
->extra
? pi
->extra
->parent
: NULL
;
1472 if (!parent_pi
|| !parent_pi
->attr
)
1475 if (es_vtep
->vtep_ip
.s_addr
!= parent_pi
->attr
->nexthop
.s_addr
)
1478 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
1480 "update path %pFX linked to es %s on vtep chg",
1481 &parent_pi
->net
->p
, es
->esi_str
);
1482 bgp_evpn_import_route_in_vrfs(parent_pi
, active
? 1 : 0);
1486 /* compare ES-IDs for the global ES RB tree */
1487 static int bgp_es_rb_cmp(const struct bgp_evpn_es
*es1
,
1488 const struct bgp_evpn_es
*es2
)
1490 return memcmp(&es1
->esi
, &es2
->esi
, ESI_BYTES
);
1492 RB_GENERATE(bgp_es_rb_head
, bgp_evpn_es
, rb_node
, bgp_es_rb_cmp
);
1494 struct bgp_evpn_es
*bgp_evpn_es_find(const esi_t
*esi
)
1496 struct bgp_evpn_es tmp
;
1498 memcpy(&tmp
.esi
, esi
, sizeof(esi_t
));
1499 return RB_FIND(bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
, &tmp
);
1502 static struct bgp_evpn_es
*bgp_evpn_es_new(struct bgp
*bgp
, const esi_t
*esi
)
1504 struct bgp_evpn_es
*es
;
1509 es
= XCALLOC(MTYPE_BGP_EVPN_ES
, sizeof(struct bgp_evpn_es
));
1512 memcpy(&es
->esi
, esi
, sizeof(esi_t
));
1514 /* Initialise the VTEP list */
1515 es
->es_vtep_list
= list_new();
1516 listset_app_node_mem(es
->es_vtep_list
);
1517 es
->es_vtep_list
->cmp
= bgp_evpn_es_vtep_cmp
;
1519 esi_to_str(&es
->esi
, es
->esi_str
, sizeof(es
->esi_str
));
1521 /* Initialize the ES routing table */
1522 es
->route_table
= bgp_table_init(bgp
, AFI_L2VPN
, SAFI_EVPN
);
1524 /* Add to rb_tree */
1525 if (RB_INSERT(bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
, es
)) {
1526 XFREE(MTYPE_BGP_EVPN_ES
, es
);
1530 /* Initialise the ES-EVI list */
1531 es
->es_evi_list
= list_new();
1532 listset_app_node_mem(es
->es_evi_list
);
1534 /* Initialise the ES-VRF list used for L3NHG management */
1535 es
->es_vrf_list
= list_new();
1536 listset_app_node_mem(es
->es_vrf_list
);
1538 /* Initialise the route list used for efficient event handling */
1539 es
->macip_path_list
= list_new();
1540 listset_app_node_mem(es
->macip_path_list
);
1542 QOBJ_REG(es
, bgp_evpn_es
);
1547 /* Free a given ES -
1548 * This just frees appropriate memory, caller should have taken other
1551 static void bgp_evpn_es_free(struct bgp_evpn_es
*es
, const char *caller
)
1553 if ((es
->flags
& (BGP_EVPNES_LOCAL
| BGP_EVPNES_REMOTE
))
1554 || listcount(es
->macip_path_list
))
1557 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1558 zlog_debug("%s: es %s free", caller
, es
->esi_str
);
1560 /* cleanup resources maintained against the ES */
1561 list_delete(&es
->es_evi_list
);
1562 list_delete(&es
->es_vrf_list
);
1563 list_delete(&es
->es_vtep_list
);
1564 list_delete(&es
->macip_path_list
);
1565 bgp_table_unlock(es
->route_table
);
1567 /* remove the entry from various databases */
1568 RB_REMOVE(bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
, es
);
1569 bgp_evpn_es_cons_checks_pend_del(es
);
1572 XFREE(MTYPE_BGP_EVPN_ES
, es
);
1575 /* init local info associated with the ES */
1576 static void bgp_evpn_es_local_info_set(struct bgp
*bgp
, struct bgp_evpn_es
*es
)
1578 char buf
[BGP_EVPN_PREFIX_RD_LEN
];
1580 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_LOCAL
))
1583 SET_FLAG(es
->flags
, BGP_EVPNES_LOCAL
);
1584 listnode_init(&es
->es_listnode
, es
);
1585 listnode_add(bgp_mh_info
->local_es_list
, &es
->es_listnode
);
1587 /* auto derive RD for this es */
1588 bf_assign_index(bm
->rd_idspace
, es
->rd_id
);
1589 es
->prd
.family
= AF_UNSPEC
;
1590 es
->prd
.prefixlen
= 64;
1591 snprintfrr(buf
, sizeof(buf
), "%pI4:%hu", &bgp
->router_id
, es
->rd_id
);
1592 (void)str2prefix_rd(buf
, &es
->prd
);
1595 /* clear any local info associated with the ES */
1596 static void bgp_evpn_es_local_info_clear(struct bgp_evpn_es
*es
)
1598 if (!CHECK_FLAG(es
->flags
, BGP_EVPNES_LOCAL
))
1601 UNSET_FLAG(es
->flags
, BGP_EVPNES_LOCAL
);
1603 /* remove from the ES local list */
1604 list_delete_node(bgp_mh_info
->local_es_list
, &es
->es_listnode
);
1606 bf_release_index(bm
->rd_idspace
, es
->rd_id
);
1608 bgp_evpn_es_free(es
, __func__
);
1611 /* eval remote info associated with the ES */
1612 static void bgp_evpn_es_remote_info_re_eval(struct bgp_evpn_es
*es
)
1614 if (es
->remote_es_evi_cnt
) {
1615 SET_FLAG(es
->flags
, BGP_EVPNES_REMOTE
);
1617 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_REMOTE
)) {
1618 UNSET_FLAG(es
->flags
, BGP_EVPNES_REMOTE
);
1619 bgp_evpn_es_free(es
, __func__
);
1624 /* Process ES link oper-down by withdrawing ES-EAD and ESR */
1625 static void bgp_evpn_local_es_down(struct bgp
*bgp
,
1626 struct bgp_evpn_es
*es
)
1628 struct prefix_evpn p
;
1631 if (!CHECK_FLAG(es
->flags
, BGP_EVPNES_OPER_UP
))
1634 UNSET_FLAG(es
->flags
, BGP_EVPNES_OPER_UP
);
1636 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1637 zlog_debug("local es %s down", es
->esi_str
);
1640 /* Delete and withdraw locally learnt ES route */
1641 build_evpn_type4_prefix(&p
, &es
->esi
, es
->originator_ip
);
1642 ret
= bgp_evpn_type4_route_delete(bgp
, es
, &p
);
1644 flog_err(EC_BGP_EVPN_ROUTE_DELETE
,
1645 "%u failed to delete type-4 route for ESI %s",
1646 bgp
->vrf_id
, es
->esi_str
);
1649 /* withdraw EAD-EVI */
1650 if (!bgp_mh_info
->ead_evi_adv_for_down_links
)
1651 bgp_evpn_local_type1_evi_route_del(bgp
, es
);
1653 /* withdraw EAD-ES */
1654 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_ES_ETH_TAG
,
1655 &es
->esi
, es
->originator_ip
);
1656 ret
= bgp_evpn_type1_es_route_delete(bgp
, es
, &p
);
1658 flog_err(EC_BGP_EVPN_ROUTE_DELETE
,
1659 "%u failed to delete type-1 route for ESI %s",
1660 bgp
->vrf_id
, es
->esi_str
);
1664 /* Process ES link oper-up by generating ES-EAD and ESR */
1665 static void bgp_evpn_local_es_up(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
1668 struct prefix_evpn p
;
1669 bool regen_ead
= false;
1671 if (!CHECK_FLAG(es
->flags
, BGP_EVPNES_OPER_UP
)) {
1672 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1673 zlog_debug("local es %s up", es
->esi_str
);
1675 SET_FLAG(es
->flags
, BGP_EVPNES_OPER_UP
);
1681 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1682 zlog_debug("local es %s generate ESR", es
->esi_str
);
1684 build_evpn_type4_prefix(&p
, &es
->esi
, es
->originator_ip
);
1685 if (bgp_evpn_type4_route_update(bgp
, es
, &p
))
1686 flog_err(EC_BGP_EVPN_ROUTE_CREATE
,
1687 "%u: Type4 route creation failure for ESI %s",
1688 bgp
->vrf_id
, es
->esi_str
);
1692 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1693 zlog_debug("local es %s generate EAD", es
->esi_str
);
1694 /* generate EAD-EVI */
1695 bgp_evpn_local_type1_evi_route_add(bgp
, es
);
1697 /* generate EAD-ES */
1698 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_ES_ETH_TAG
, &es
->esi
,
1700 bgp_evpn_type1_route_update(bgp
, es
, NULL
, &p
);
1704 static void bgp_evpn_local_es_do_del(struct bgp
*bgp
, struct bgp_evpn_es
*es
)
1706 struct bgp_evpn_es_evi
*es_evi
;
1707 struct listnode
*evi_node
, *evi_next_node
;
1709 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1710 zlog_debug("del local es %s", es
->esi_str
);
1712 /* Delete all local EVPN ES routes from ESI table
1713 * and schedule for processing (to withdraw from peers))
1715 bgp_evpn_es_route_del_all(bgp
, es
);
1717 /* release all local ES EVIs associated with the ES */
1718 for (ALL_LIST_ELEMENTS(es
->es_evi_list
, evi_node
,
1719 evi_next_node
, es_evi
)) {
1720 bgp_evpn_local_es_evi_do_del(es_evi
);
1723 /* Clear local info associated with the ES and free it up if there is
1724 * no remote reference
1726 bgp_evpn_es_local_info_clear(es
);
1729 bool bgp_evpn_is_esi_local(esi_t
*esi
)
1731 struct bgp_evpn_es
*es
= NULL
;
1733 /* Lookup ESI hash - should exist. */
1734 es
= bgp_evpn_es_find(esi
);
1735 return es
? !!(es
->flags
& BGP_EVPNES_LOCAL
) : false;
1738 int bgp_evpn_local_es_del(struct bgp
*bgp
, esi_t
*esi
)
1740 struct bgp_evpn_es
*es
= NULL
;
1742 /* Lookup ESI hash - should exist. */
1743 es
= bgp_evpn_es_find(esi
);
1745 flog_warn(EC_BGP_EVPN_ESI
,
1746 "%u: ES %s missing at local ES DEL",
1747 bgp
->vrf_id
, es
->esi_str
);
1751 bgp_evpn_local_es_do_del(bgp
, es
);
1755 /* Handle device to ES id association. Results in the creation of a local
1758 int bgp_evpn_local_es_add(struct bgp
*bgp
, esi_t
*esi
,
1759 struct in_addr originator_ip
, bool oper_up
,
1762 char buf
[ESI_STR_LEN
];
1763 struct bgp_evpn_es
*es
;
1765 bool regen_esr
= false;
1767 /* create the new es */
1768 es
= bgp_evpn_es_find(esi
);
1770 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_LOCAL
))
1773 es
= bgp_evpn_es_new(bgp
, esi
);
1775 flog_err(EC_BGP_ES_CREATE
,
1776 "%u: Failed to allocate ES entry for ESI %s - at Local ES Add",
1777 bgp
->vrf_id
, esi_to_str(esi
, buf
, sizeof(buf
)));
1782 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1783 zlog_debug("add local es %s orig-ip %pI4 df_pref %u", es
->esi_str
,
1784 &originator_ip
, df_pref
);
1786 es
->originator_ip
= originator_ip
;
1787 if (df_pref
!= es
->df_pref
) {
1788 es
->df_pref
= df_pref
;
1791 bgp_evpn_es_local_info_set(bgp
, es
);
1793 /* import all remote Type-4 routes in the ES table */
1795 bgp_evpn_type4_remote_routes_import(bgp
, es
,
1796 true /* install */);
1798 /* create and advertise EAD-EVI routes for the ES -
1799 * XXX - till an ES-EVI reference is created there is really nothing to
1802 if (bgp_mh_info
->ead_evi_adv_for_down_links
)
1803 bgp_evpn_local_type1_evi_route_add(bgp
, es
);
1805 /* If the ES link is operationally up generate EAD-ES. EAD-EVI
1806 * can be generated even if the link is inactive.
1809 bgp_evpn_local_es_up(bgp
, es
, regen_esr
);
1811 bgp_evpn_local_es_down(bgp
, es
);
1816 static char *bgp_evpn_es_vteps_str(char *vtep_str
, struct bgp_evpn_es
*es
,
1817 uint8_t vtep_str_size
)
1819 char vtep_flag_str
[BGP_EVPN_FLAG_STR_SZ
];
1820 struct listnode
*node
;
1821 struct bgp_evpn_es_vtep
*es_vtep
;
1823 char ip_buf
[INET6_ADDRSTRLEN
];
1826 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
1827 vtep_flag_str
[0] = '\0';
1829 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ESR
)
1830 strlcat(vtep_flag_str
, "E", sizeof(vtep_flag_str
));
1831 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ACTIVE
)
1832 strlcat(vtep_flag_str
, "A", sizeof(vtep_flag_str
));
1834 if (!strlen(vtep_flag_str
))
1835 strlcat(vtep_flag_str
, "-", sizeof(vtep_flag_str
));
1839 strlcat(vtep_str
, ",", vtep_str_size
);
1841 inet_ntop(AF_INET
, &es_vtep
->vtep_ip
, ip_buf
,
1844 strlcat(vtep_str
, "(", vtep_str_size
);
1845 strlcat(vtep_str
, vtep_flag_str
, vtep_str_size
);
1846 strlcat(vtep_str
, ")", vtep_str_size
);
1852 static void bgp_evpn_es_json_vtep_fill(json_object
*json_vteps
,
1853 struct bgp_evpn_es_vtep
*es_vtep
)
1855 json_object
*json_vtep_entry
;
1856 json_object
*json_flags
;
1857 char ip_buf
[INET6_ADDRSTRLEN
];
1859 json_vtep_entry
= json_object_new_object();
1861 json_object_string_add(
1862 json_vtep_entry
, "vtep_ip",
1863 inet_ntop(AF_INET
, &es_vtep
->vtep_ip
, ip_buf
, sizeof(ip_buf
)));
1864 if (es_vtep
->flags
& (BGP_EVPNES_VTEP_ESR
|
1865 BGP_EVPNES_VTEP_ACTIVE
)) {
1866 json_flags
= json_object_new_array();
1867 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ESR
)
1868 json_array_string_add(json_flags
, "esr");
1869 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ACTIVE
)
1870 json_array_string_add(json_flags
, "active");
1871 json_object_object_add(json_vtep_entry
, "flags", json_flags
);
1872 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ESR
) {
1873 json_object_int_add(json_vtep_entry
, "dfPreference",
1875 json_object_int_add(json_vtep_entry
, "dfAlgorithm",
1880 json_object_array_add(json_vteps
,
1884 static void bgp_evpn_es_vteps_show_detail(struct vty
*vty
,
1885 struct bgp_evpn_es
*es
)
1887 char vtep_flag_str
[BGP_EVPN_FLAG_STR_SZ
];
1888 struct listnode
*node
;
1889 struct bgp_evpn_es_vtep
*es_vtep
;
1890 char alg_buf
[EVPN_DF_ALG_STR_LEN
];
1892 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
1893 vtep_flag_str
[0] = '\0';
1894 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ESR
)
1895 strlcat(vtep_flag_str
, "E", sizeof(vtep_flag_str
));
1896 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ACTIVE
)
1897 strlcat(vtep_flag_str
, "A", sizeof(vtep_flag_str
));
1899 if (!strlen(vtep_flag_str
))
1900 strlcat(vtep_flag_str
, "-", sizeof(vtep_flag_str
));
1902 vty_out(vty
, " %pI4 flags: %s", &es_vtep
->vtep_ip
,
1905 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ESR
)
1906 vty_out(vty
, " df_alg: %s df_pref: %u\n",
1907 evpn_es_df_alg2str(es_vtep
->df_alg
, alg_buf
,
1915 static void bgp_evpn_es_show_entry(struct vty
*vty
,
1916 struct bgp_evpn_es
*es
, json_object
*json
)
1918 char buf1
[RD_ADDRSTRLEN
];
1919 struct listnode
*node
;
1920 struct bgp_evpn_es_vtep
*es_vtep
;
1923 json_object
*json_vteps
;
1924 json_object
*json_types
;
1926 json_object_string_add(json
, "esi", es
->esi_str
);
1927 json_object_string_add(json
, "rd",
1928 prefix_rd2str(&es
->prd
, buf1
,
1931 if (es
->flags
& (BGP_EVPNES_LOCAL
| BGP_EVPNES_REMOTE
)) {
1932 json_types
= json_object_new_array();
1933 if (es
->flags
& BGP_EVPNES_LOCAL
)
1934 json_array_string_add(json_types
, "local");
1935 if (es
->flags
& BGP_EVPNES_REMOTE
)
1936 json_array_string_add(json_types
, "remote");
1937 json_object_object_add(json
, "type", json_types
);
1940 if (listcount(es
->es_vtep_list
)) {
1941 json_vteps
= json_object_new_array();
1942 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
,
1944 bgp_evpn_es_json_vtep_fill(json_vteps
, es_vtep
);
1946 json_object_object_add(json
, "vteps", json_vteps
);
1948 json_object_int_add(json
, "vniCount",
1949 listcount(es
->es_evi_list
));
1952 char vtep_str
[ES_VTEP_LIST_STR_SZ
+ BGP_EVPN_VTEPS_FLAG_STR_SZ
];
1955 if (es
->flags
& BGP_EVPNES_LOCAL
)
1956 strlcat(type_str
, "L", sizeof(type_str
));
1957 if (es
->flags
& BGP_EVPNES_REMOTE
)
1958 strlcat(type_str
, "R", sizeof(type_str
));
1959 if (es
->inconsistencies
)
1960 strlcat(type_str
, "I", sizeof(type_str
));
1962 bgp_evpn_es_vteps_str(vtep_str
, es
, sizeof(vtep_str
));
1964 if (es
->flags
& BGP_EVPNES_LOCAL
)
1965 prefix_rd2str(&es
->prd
, buf1
, sizeof(buf1
));
1967 strlcpy(buf1
, "-", sizeof(buf1
));
1969 vty_out(vty
, "%-30s %-5s %-21s %-8d %s\n",
1970 es
->esi_str
, type_str
, buf1
,
1971 listcount(es
->es_evi_list
), vtep_str
);
1975 static void bgp_evpn_es_show_entry_detail(struct vty
*vty
,
1976 struct bgp_evpn_es
*es
, json_object
*json
)
1978 char ip_buf
[INET6_ADDRSTRLEN
];
1981 json_object
*json_flags
;
1982 json_object
*json_incons
;
1983 json_object
*json_vteps
;
1984 struct listnode
*node
;
1985 struct bgp_evpn_es_vtep
*es_vtep
;
1987 /* Add the "brief" info first */
1988 bgp_evpn_es_show_entry(vty
, es
, json
);
1989 if (es
->flags
& (BGP_EVPNES_OPER_UP
| BGP_EVPNES_ADV_EVI
)) {
1990 json_flags
= json_object_new_array();
1991 if (es
->flags
& BGP_EVPNES_OPER_UP
)
1992 json_array_string_add(json_flags
, "up");
1993 if (es
->flags
& BGP_EVPNES_ADV_EVI
)
1994 json_array_string_add(json_flags
,
1996 json_object_object_add(json
, "flags", json_flags
);
1998 json_object_string_add(json
, "originator_ip",
1999 inet_ntop(AF_INET
, &es
->originator_ip
,
2000 ip_buf
, sizeof(ip_buf
)));
2001 json_object_int_add(json
, "remoteVniCount",
2002 es
->remote_es_evi_cnt
);
2003 json_object_int_add(json
, "vrfCount",
2004 listcount(es
->es_vrf_list
));
2005 json_object_int_add(json
, "macipPathCount",
2006 listcount(es
->macip_path_list
));
2007 json_object_int_add(json
, "inconsistentVniVtepCount",
2008 es
->incons_evi_vtep_cnt
);
2009 if (listcount(es
->es_vtep_list
)) {
2010 json_vteps
= json_object_new_array();
2011 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
,
2013 bgp_evpn_es_json_vtep_fill(json_vteps
, es_vtep
);
2015 json_object_object_add(json
, "vteps", json_vteps
);
2017 if (es
->inconsistencies
) {
2018 json_incons
= json_object_new_array();
2019 if (es
->inconsistencies
& BGP_EVPNES_INCONS_VTEP_LIST
)
2020 json_array_string_add(json_incons
,
2021 "vni-vtep-mismatch");
2022 json_object_object_add(json
, "inconsistencies",
2026 char incons_str
[BGP_EVPNES_INCONS_STR_SZ
];
2028 char buf1
[RD_ADDRSTRLEN
];
2031 if (es
->flags
& BGP_EVPNES_LOCAL
)
2032 strlcat(type_str
, "L", sizeof(type_str
));
2033 if (es
->flags
& BGP_EVPNES_REMOTE
)
2034 strlcat(type_str
, "R", sizeof(type_str
));
2036 if (es
->flags
& BGP_EVPNES_LOCAL
)
2037 prefix_rd2str(&es
->prd
, buf1
, sizeof(buf1
));
2039 strlcpy(buf1
, "-", sizeof(buf1
));
2041 vty_out(vty
, "ESI: %s\n", es
->esi_str
);
2042 vty_out(vty
, " Type: %s\n", type_str
);
2043 vty_out(vty
, " RD: %s\n", buf1
);
2044 vty_out(vty
, " Originator-IP: %pI4\n", &es
->originator_ip
);
2045 if (es
->flags
& BGP_EVPNES_LOCAL
)
2046 vty_out(vty
, " Local ES DF preference: %u\n",
2048 vty_out(vty
, " VNI Count: %d\n", listcount(es
->es_evi_list
));
2049 vty_out(vty
, " Remote VNI Count: %d\n",
2050 es
->remote_es_evi_cnt
);
2051 vty_out(vty
, " VRF Count: %d\n", listcount(es
->es_vrf_list
));
2052 vty_out(vty
, " MACIP Path Count: %d\n",
2053 listcount(es
->macip_path_list
));
2054 vty_out(vty
, " Inconsistent VNI VTEP Count: %d\n",
2055 es
->incons_evi_vtep_cnt
);
2056 if (es
->inconsistencies
) {
2057 incons_str
[0] = '\0';
2058 if (es
->inconsistencies
& BGP_EVPNES_INCONS_VTEP_LIST
)
2059 strlcat(incons_str
, "vni-vtep-mismatch",
2060 sizeof(incons_str
));
2062 strlcpy(incons_str
, "-", sizeof(incons_str
));
2064 vty_out(vty
, " Inconsistencies: %s\n",
2066 if (listcount(es
->es_vtep_list
)) {
2067 vty_out(vty
, " VTEPs:\n");
2068 bgp_evpn_es_vteps_show_detail(vty
, es
);
2074 /* Display all ESs */
2075 void bgp_evpn_es_show(struct vty
*vty
, bool uj
, bool detail
)
2077 struct bgp_evpn_es
*es
;
2078 json_object
*json_array
= NULL
;
2079 json_object
*json
= NULL
;
2082 /* create an array of ESs */
2083 json_array
= json_object_new_array();
2087 "ES Flags: L local, R remote, I inconsistent\n");
2089 "VTEP Flags: E ESR/Type-4, A active nexthop\n");
2091 "%-30s %-5s %-21s %-8s %s\n",
2092 "ESI", "Flags", "RD", "#VNIs", "VTEPs");
2096 RB_FOREACH(es
, bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
) {
2098 /* create a separate json object for each ES */
2099 json
= json_object_new_object();
2101 bgp_evpn_es_show_entry_detail(vty
, es
, json
);
2103 bgp_evpn_es_show_entry(vty
, es
, json
);
2104 /* add ES to the json array */
2106 json_object_array_add(json_array
, json
);
2109 /* print the array of json-ESs */
2111 vty_out(vty
, "%s\n", json_object_to_json_string_ext(
2112 json_array
, JSON_C_TO_STRING_PRETTY
));
2113 json_object_free(json_array
);
2117 /* Display specific ES */
2118 void bgp_evpn_es_show_esi(struct vty
*vty
, esi_t
*esi
, bool uj
)
2120 struct bgp_evpn_es
*es
;
2121 json_object
*json
= NULL
;
2124 json
= json_object_new_object();
2126 es
= bgp_evpn_es_find(esi
);
2128 bgp_evpn_es_show_entry_detail(vty
, es
, json
);
2131 vty_out(vty
, "ESI not found\n");
2135 vty_out(vty
, "%s\n", json_object_to_json_string_ext(
2136 json
, JSON_C_TO_STRING_PRETTY
));
2137 json_object_free(json
);
2141 /*****************************************************************************/
2142 /* Ethernet Segment to VRF association -
2143 * 1. Each ES-EVI entry is associated with a tenant VRF. This associaton
2144 * triggers the creation of an ES-VRF entry.
2145 * 2. The ES-VRF entry is maintained for the purpose of L3-NHG creation
2146 * 3. Type-2/MAC-IP routes are imported into a tenant VRF and programmed as
2147 * a /32 or host route entry in the dataplane. If the destination of
2148 * the host route is a remote-ES the route is programmed with the
2149 * corresponding (keyed in by {vrf,ES-id}) L3-NHG.
2150 * 4. The reason for this indirection (route->L3-NHG, L3-NHG->list-of-VTEPs)
2151 * is to avoid route updates to the dplane when a remote-ES link flaps i.e.
2152 * instead of updating all the dependent routes the NHG's contents are updated.
2153 * This reduces the amount of datplane updates (nhg updates vs. route updates)
2154 * allowing for a faster failover.
2156 * XXX - can the L3 SVI index change without change in vpn->bgp_vrf
2157 * association? If yes we need to handle that by updating all the L3 NHGs
2160 /******************************** L3 NHG management *************************/
2161 static void bgp_evpn_l3nhg_zebra_add_v4_or_v6(struct bgp_evpn_es_vrf
*es_vrf
,
2164 uint32_t nhg_id
= v4_nhg
? es_vrf
->nhg_id
: es_vrf
->v6_nhg_id
;
2165 struct bgp_evpn_es
*es
= es_vrf
->es
;
2166 struct listnode
*node
;
2167 struct bgp_evpn_es_vtep
*es_vtep
;
2169 struct zapi_nexthop
*api_nh
;
2170 struct zapi_nhg api_nhg
= {};
2172 /* Skip installation of L3-NHG if host routes used */
2176 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2177 zlog_debug("es %s vrf %u %s nhg %u to zebra", es
->esi_str
,
2178 es_vrf
->bgp_vrf
->vrf_id
,
2179 v4_nhg
? "v4_nhg" : "v6_nhg", nhg_id
);
2181 /* only the gateway ip changes for each NH. rest of the params
2184 memset(&nh
, 0, sizeof(nh
));
2185 nh
.vrf_id
= es_vrf
->bgp_vrf
->vrf_id
;
2186 nh
.flags
= NEXTHOP_FLAG_ONLINK
;
2187 nh
.ifindex
= es_vrf
->bgp_vrf
->l3vni_svi_ifindex
;
2190 v4_nhg
? NEXTHOP_TYPE_IPV4_IFINDEX
: NEXTHOP_TYPE_IPV6_IFINDEX
;
2192 api_nhg
.id
= nhg_id
;
2193 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
2194 if (!CHECK_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
))
2197 /* overwrite the gw */
2199 nh
.gate
.ipv4
= es_vtep
->vtep_ip
;
2201 ipv4_to_ipv4_mapped_ipv6(&nh
.gate
.ipv6
,
2204 /* convert to zapi format */
2205 api_nh
= &api_nhg
.nexthops
[api_nhg
.nexthop_num
];
2206 zapi_nexthop_from_nexthop(api_nh
, &nh
);
2208 ++api_nhg
.nexthop_num
;
2209 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2210 zlog_debug("nhg %u vtep %pI4 l3-svi %d", api_nhg
.id
,
2212 es_vrf
->bgp_vrf
->l3vni_svi_ifindex
);
2215 if (!api_nhg
.nexthop_num
)
2218 if (api_nhg
.nexthop_num
> MULTIPATH_NUM
)
2221 zclient_nhg_send(zclient
, ZEBRA_NHG_ADD
, &api_nhg
);
2224 static bool bgp_evpn_l3nhg_zebra_ok(struct bgp_evpn_es_vrf
*es_vrf
)
2226 if (!bgp_mh_info
->host_routes_use_l3nhg
&& !bgp_mh_info
->install_l3nhg
)
2230 if (!zclient
|| zclient
->sock
< 0)
2236 static void bgp_evpn_l3nhg_zebra_add(struct bgp_evpn_es_vrf
*es_vrf
)
2238 if (!bgp_evpn_l3nhg_zebra_ok(es_vrf
))
2241 bgp_evpn_l3nhg_zebra_add_v4_or_v6(es_vrf
, true /*v4_nhg*/);
2242 bgp_evpn_l3nhg_zebra_add_v4_or_v6(es_vrf
, false /*v4_nhg*/);
2245 static void bgp_evpn_l3nhg_zebra_del_v4_or_v6(struct bgp_evpn_es_vrf
*es_vrf
,
2248 struct zapi_nhg api_nhg
= {};
2250 api_nhg
.id
= v4_nhg
? es_vrf
->nhg_id
: es_vrf
->v6_nhg_id
;
2252 /* Skip installation of L3-NHG if host routes used */
2256 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2257 zlog_debug("es %s vrf %u %s nhg %u to zebra",
2258 es_vrf
->es
->esi_str
, es_vrf
->bgp_vrf
->vrf_id
,
2259 v4_nhg
? "v4_nhg" : "v6_nhg", api_nhg
.id
);
2261 zclient_nhg_send(zclient
, ZEBRA_NHG_DEL
, &api_nhg
);
2264 static void bgp_evpn_l3nhg_zebra_del(struct bgp_evpn_es_vrf
*es_vrf
)
2266 if (!bgp_evpn_l3nhg_zebra_ok(es_vrf
))
2269 bgp_evpn_l3nhg_zebra_del_v4_or_v6(es_vrf
, true /*v4_nhg*/);
2270 bgp_evpn_l3nhg_zebra_del_v4_or_v6(es_vrf
, false /*v4_nhg*/);
2273 static void bgp_evpn_l3nhg_deactivate(struct bgp_evpn_es_vrf
*es_vrf
)
2275 if (!(es_vrf
->flags
& BGP_EVPNES_VRF_NHG_ACTIVE
))
2278 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2279 zlog_debug("es %s vrf %u nhg %u de-activate",
2280 es_vrf
->es
->esi_str
, es_vrf
->bgp_vrf
->vrf_id
,
2282 bgp_evpn_l3nhg_zebra_del(es_vrf
);
2283 es_vrf
->flags
&= ~BGP_EVPNES_VRF_NHG_ACTIVE
;
2286 static void bgp_evpn_l3nhg_activate(struct bgp_evpn_es_vrf
*es_vrf
, bool update
)
2288 if (!bgp_evpn_es_get_active_vtep_cnt(es_vrf
->es
)) {
2289 bgp_evpn_l3nhg_deactivate(es_vrf
);
2293 if (es_vrf
->flags
& BGP_EVPNES_VRF_NHG_ACTIVE
) {
2297 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2298 zlog_debug("es %s vrf %u nhg %u activate",
2299 es_vrf
->es
->esi_str
, es_vrf
->bgp_vrf
->vrf_id
,
2301 es_vrf
->flags
|= BGP_EVPNES_VRF_NHG_ACTIVE
;
2304 bgp_evpn_l3nhg_zebra_add(es_vrf
);
2307 /* when a VTEP is activated or de-activated against an ES associated
2308 * VRFs' NHG needs to be updated
2310 static void bgp_evpn_l3nhg_update_on_vtep_chg(struct bgp_evpn_es
*es
)
2312 struct bgp_evpn_es_vrf
*es_vrf
;
2313 struct listnode
*es_vrf_node
;
2315 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2316 zlog_debug("es %s nhg update on vtep chg", es
->esi_str
);
2318 for (ALL_LIST_ELEMENTS_RO(es
->es_vrf_list
, es_vrf_node
, es_vrf
))
2319 bgp_evpn_l3nhg_activate(es_vrf
, true /* update */);
2322 /* compare ES-IDs for the ES-VRF RB tree maintained per-VRF */
2323 static int bgp_es_vrf_rb_cmp(const struct bgp_evpn_es_vrf
*es_vrf1
,
2324 const struct bgp_evpn_es_vrf
*es_vrf2
)
2326 return memcmp(&es_vrf1
->es
->esi
, &es_vrf2
->es
->esi
, ESI_BYTES
);
2328 RB_GENERATE(bgp_es_vrf_rb_head
, bgp_evpn_es_vrf
, rb_node
, bgp_es_vrf_rb_cmp
);
2330 /* Initialize the ES tables maintained per-tenant vrf */
2331 void bgp_evpn_vrf_es_init(struct bgp
*bgp_vrf
)
2333 /* Initialize the ES-VRF RB tree */
2334 RB_INIT(bgp_es_vrf_rb_head
, &bgp_vrf
->es_vrf_rb_tree
);
2337 /* find the ES-VRF in the per-VRF RB tree */
2338 static struct bgp_evpn_es_vrf
*bgp_evpn_es_vrf_find(struct bgp_evpn_es
*es
,
2339 struct bgp
*bgp_vrf
)
2341 struct bgp_evpn_es_vrf es_vrf
;
2345 return RB_FIND(bgp_es_vrf_rb_head
, &bgp_vrf
->es_vrf_rb_tree
, &es_vrf
);
2348 /* allocate a new ES-VRF and setup L3NHG for it */
2349 static struct bgp_evpn_es_vrf
*bgp_evpn_es_vrf_create(struct bgp_evpn_es
*es
,
2350 struct bgp
*bgp_vrf
)
2352 struct bgp_evpn_es_vrf
*es_vrf
;
2354 es_vrf
= XCALLOC(MTYPE_BGP_EVPN_ES_VRF
, sizeof(*es_vrf
));
2357 es_vrf
->bgp_vrf
= bgp_vrf
;
2359 /* insert into the VRF-ESI rb tree */
2360 if (RB_INSERT(bgp_es_vrf_rb_head
, &bgp_vrf
->es_vrf_rb_tree
, es_vrf
)) {
2361 XFREE(MTYPE_BGP_EVPN_ES_VRF
, es_vrf
);
2365 /* add to the ES's VRF list */
2366 listnode_init(&es_vrf
->es_listnode
, es_vrf
);
2367 listnode_add(es
->es_vrf_list
, &es_vrf
->es_listnode
);
2369 /* setup the L3 NHG id for the ES */
2370 es_vrf
->nhg_id
= bgp_l3nhg_id_alloc();
2371 es_vrf
->v6_nhg_id
= bgp_l3nhg_id_alloc();
2373 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2374 zlog_debug("es %s vrf %u nhg %u v6_nhg %d create", es
->esi_str
,
2375 bgp_vrf
->vrf_id
, es_vrf
->nhg_id
, es_vrf
->v6_nhg_id
);
2376 bgp_evpn_l3nhg_activate(es_vrf
, false /* update */);
2381 /* remove the L3-NHG associated with the ES-VRF and free it */
2382 static void bgp_evpn_es_vrf_delete(struct bgp_evpn_es_vrf
*es_vrf
)
2384 struct bgp_evpn_es
*es
= es_vrf
->es
;
2385 struct bgp
*bgp_vrf
= es_vrf
->bgp_vrf
;
2387 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2388 zlog_debug("es %s vrf %u nhg %u delete", es
->esi_str
,
2389 bgp_vrf
->vrf_id
, es_vrf
->nhg_id
);
2391 /* Remove the NHG resources */
2392 bgp_evpn_l3nhg_deactivate(es_vrf
);
2394 bgp_l3nhg_id_free(es_vrf
->nhg_id
);
2396 if (es_vrf
->v6_nhg_id
)
2397 bgp_l3nhg_id_free(es_vrf
->v6_nhg_id
);
2398 es_vrf
->v6_nhg_id
= 0;
2400 /* remove from the ES's VRF list */
2401 list_delete_node(es
->es_vrf_list
, &es_vrf
->es_listnode
);
2403 /* remove from the VRF-ESI rb tree */
2404 RB_REMOVE(bgp_es_vrf_rb_head
, &bgp_vrf
->es_vrf_rb_tree
, es_vrf
);
2406 XFREE(MTYPE_BGP_EVPN_ES_VRF
, es_vrf
);
2409 /* deref and delete if there are no references */
2410 void bgp_evpn_es_vrf_deref(struct bgp_evpn_es_evi
*es_evi
)
2412 struct bgp_evpn_es_vrf
*es_vrf
= es_evi
->es_vrf
;
2417 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2418 zlog_debug("es-evi %s vni %u vrf %u de-ref",
2419 es_evi
->es
->esi_str
, es_evi
->vpn
->vni
,
2420 es_vrf
->bgp_vrf
->vrf_id
);
2422 es_evi
->es_vrf
= NULL
;
2423 if (es_vrf
->ref_cnt
)
2426 if (!es_vrf
->ref_cnt
)
2427 bgp_evpn_es_vrf_delete(es_vrf
);
2430 /* find or create and reference */
2431 void bgp_evpn_es_vrf_ref(struct bgp_evpn_es_evi
*es_evi
, struct bgp
*bgp_vrf
)
2433 struct bgp_evpn_es
*es
= es_evi
->es
;
2434 struct bgp_evpn_es_vrf
*es_vrf
= es_evi
->es_vrf
;
2435 struct bgp
*old_bgp_vrf
= NULL
;
2438 old_bgp_vrf
= es_vrf
->bgp_vrf
;
2440 if (old_bgp_vrf
== bgp_vrf
)
2443 /* deref the old ES-VRF */
2444 bgp_evpn_es_vrf_deref(es_evi
);
2449 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2450 zlog_debug("es-evi %s vni %u vrf %u ref", es_evi
->es
->esi_str
,
2451 es_evi
->vpn
->vni
, bgp_vrf
->vrf_id
);
2453 /* find-create the new ES-VRF */
2454 es_vrf
= bgp_evpn_es_vrf_find(es
, bgp_vrf
);
2456 es_vrf
= bgp_evpn_es_vrf_create(es
, bgp_vrf
);
2460 es_evi
->es_vrf
= es_vrf
;
2464 /* When the L2-VNI is associated with a L3-VNI/VRF update all the
2465 * associated ES-EVI entries
2467 void bgp_evpn_es_evi_vrf_deref(struct bgpevpn
*vpn
)
2469 struct bgp_evpn_es_evi
*es_evi
;
2471 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2472 zlog_debug("es-vrf de-ref for vni %u", vpn
->vni
);
2474 RB_FOREACH (es_evi
, bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
)
2475 bgp_evpn_es_vrf_deref(es_evi
);
2477 void bgp_evpn_es_evi_vrf_ref(struct bgpevpn
*vpn
)
2479 struct bgp_evpn_es_evi
*es_evi
;
2481 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2482 zlog_debug("es-vrf ref for vni %u", vpn
->vni
);
2484 RB_FOREACH (es_evi
, bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
)
2485 bgp_evpn_es_vrf_ref(es_evi
, vpn
->bgp_vrf
);
2488 /* returns false if legacy-exploded mp needs to be used for route install */
2489 bool bgp_evpn_path_es_use_nhg(struct bgp
*bgp_vrf
, struct bgp_path_info
*pi
,
2493 struct bgp_evpn_es
*es
;
2494 struct bgp_evpn_es_vrf
*es_vrf
;
2495 struct bgp_path_info
*parent_pi
;
2496 struct bgp_node
*rn
;
2497 struct prefix_evpn
*evp
;
2498 struct bgp_path_info
*mpinfo
;
2502 /* L3NHG support is disabled, use legacy-exploded multipath */
2503 if (!bgp_mh_info
->host_routes_use_l3nhg
)
2506 parent_pi
= get_route_parent_evpn(pi
);
2510 rn
= parent_pi
->net
;
2514 evp
= (struct prefix_evpn
*)&rn
->p
;
2515 if (evp
->prefix
.route_type
!= BGP_EVPN_MAC_IP_ROUTE
)
2518 /* non-es path, use legacy-exploded multipath */
2519 esi
= bgp_evpn_attr_get_esi(parent_pi
->attr
);
2520 if (!memcmp(esi
, zero_esi
, sizeof(*esi
)))
2523 /* if the ES-VRF is not setup or if the NHG has not been installed
2524 * we cannot install the route yet, return a 0-NHG to indicate
2527 es
= bgp_evpn_es_find(esi
);
2530 es_vrf
= bgp_evpn_es_vrf_find(es
, bgp_vrf
);
2531 if (!es_vrf
|| !(es_vrf
->flags
& BGP_EVPNES_VRF_NHG_ACTIVE
))
2534 /* this needs to be set the v6NHG if v6route */
2535 if (is_evpn_prefix_ipaddr_v6(evp
))
2536 *nhg_p
= es_vrf
->v6_nhg_id
;
2538 *nhg_p
= es_vrf
->nhg_id
;
2540 for (mpinfo
= bgp_path_info_mpath_next(pi
); mpinfo
;
2541 mpinfo
= bgp_path_info_mpath_next(mpinfo
)) {
2542 /* if any of the paths of have a different ESI we can't use
2543 * the NHG associated with the ES. fallback to legacy-exploded
2546 if (memcmp(esi
, bgp_evpn_attr_get_esi(mpinfo
->attr
),
2554 static void bgp_evpn_es_vrf_show_entry(struct vty
*vty
,
2555 struct bgp_evpn_es_vrf
*es_vrf
,
2558 struct bgp_evpn_es
*es
= es_vrf
->es
;
2559 struct bgp
*bgp_vrf
= es_vrf
->bgp_vrf
;
2562 json_object
*json_types
;
2564 json_object_string_add(json
, "esi", es
->esi_str
);
2565 json_object_string_add(json
, "vrf", bgp_vrf
->name
);
2567 if (es_vrf
->flags
& (BGP_EVPNES_VRF_NHG_ACTIVE
)) {
2568 json_types
= json_object_new_array();
2569 if (es_vrf
->flags
& BGP_EVPNES_VRF_NHG_ACTIVE
)
2570 json_array_string_add(json_types
, "active");
2571 json_object_object_add(json
, "flags", json_types
);
2574 json_object_int_add(json
, "ipv4NHG", es_vrf
->nhg_id
);
2575 json_object_int_add(json
, "ipv6NHG", es_vrf
->v6_nhg_id
);
2576 json_object_int_add(json
, "refCount", es_vrf
->ref_cnt
);
2580 flags_str
[0] = '\0';
2581 if (es_vrf
->flags
& BGP_EVPNES_VRF_NHG_ACTIVE
)
2582 strlcat(flags_str
, "A", sizeof(flags_str
));
2584 vty_out(vty
, "%-30s %-15s %-5s %-8u %-8u %u\n", es
->esi_str
,
2585 bgp_vrf
->name
, flags_str
, es_vrf
->nhg_id
,
2586 es_vrf
->v6_nhg_id
, es_vrf
->ref_cnt
);
2590 static void bgp_evpn_es_vrf_show_es(struct vty
*vty
, json_object
*json_array
,
2591 struct bgp_evpn_es
*es
)
2593 json_object
*json
= NULL
;
2594 struct listnode
*es_vrf_node
;
2595 struct bgp_evpn_es_vrf
*es_vrf
;
2597 for (ALL_LIST_ELEMENTS_RO(es
->es_vrf_list
, es_vrf_node
, es_vrf
)) {
2598 /* create a separate json object for each ES-VRF */
2600 json
= json_object_new_object();
2601 bgp_evpn_es_vrf_show_entry(vty
, es_vrf
, json
);
2602 /* add ES-VRF to the json array */
2604 json_object_array_add(json_array
, json
);
2608 /* Display all ES VRFs */
2609 void bgp_evpn_es_vrf_show(struct vty
*vty
, bool uj
, struct bgp_evpn_es
*es
)
2611 json_object
*json_array
= NULL
;
2614 /* create an array of ESs */
2615 json_array
= json_object_new_array();
2617 vty_out(vty
, "ES-VRF Flags: A Active\n");
2618 vty_out(vty
, "%-30s %-15s %-5s %-8s %-8s %s\n", "ESI", "VRF",
2619 "Flags", "IPv4-NHG", "IPv6-NHG", "Ref");
2623 bgp_evpn_es_vrf_show_es(vty
, json_array
, es
);
2625 RB_FOREACH (es
, bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
)
2626 bgp_evpn_es_vrf_show_es(vty
, json_array
, es
);
2629 /* print the array of json-ESs */
2631 vty_out(vty
, "%s\n",
2632 json_object_to_json_string_ext(
2633 json_array
, JSON_C_TO_STRING_PRETTY
));
2634 json_object_free(json_array
);
2638 /* Display specific ES VRF */
2639 void bgp_evpn_es_vrf_show_esi(struct vty
*vty
, esi_t
*esi
, bool uj
)
2641 struct bgp_evpn_es
*es
;
2643 es
= bgp_evpn_es_find(esi
);
2645 bgp_evpn_es_vrf_show(vty
, uj
, es
);
2648 vty_out(vty
, "ESI not found\n");
2652 /*****************************************************************************/
2653 /* Ethernet Segment to EVI association -
2654 * 1. The ES-EVI entry is maintained as a RB tree per L2-VNI
2655 * (bgpevpn->es_evi_rb_tree).
2656 * 2. Each local ES-EVI entry is rxed from zebra and then used by BGP to
2657 * advertises an EAD-EVI (Type-1 EVPN) route
2658 * 3. The remote ES-EVI is created when a bgp_evpn_es_evi_vtep references
2662 /* A list of remote VTEPs is maintained for each ES-EVI. This list includes -
2663 * 1. VTEPs for which we have imported the EAD-per-ES Type1 route
2664 * 2. VTEPs for which we have imported the EAD-per-EVI Type1 route
2665 * VTEPs for which both routes have been rxed are activated. Activation
2666 * creates a NHG in the parent ES.
2668 static int bgp_evpn_es_evi_vtep_cmp(void *p1
, void *p2
)
2670 const struct bgp_evpn_es_evi_vtep
*evi_vtep1
= p1
;
2671 const struct bgp_evpn_es_evi_vtep
*evi_vtep2
= p2
;
2673 return evi_vtep1
->vtep_ip
.s_addr
- evi_vtep2
->vtep_ip
.s_addr
;
2676 static struct bgp_evpn_es_evi_vtep
*bgp_evpn_es_evi_vtep_new(
2677 struct bgp_evpn_es_evi
*es_evi
, struct in_addr vtep_ip
)
2679 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
2681 evi_vtep
= XCALLOC(MTYPE_BGP_EVPN_ES_EVI_VTEP
, sizeof(*evi_vtep
));
2683 evi_vtep
->es_evi
= es_evi
;
2684 evi_vtep
->vtep_ip
.s_addr
= vtep_ip
.s_addr
;
2685 listnode_init(&evi_vtep
->es_evi_listnode
, evi_vtep
);
2686 listnode_add_sort(es_evi
->es_evi_vtep_list
, &evi_vtep
->es_evi_listnode
);
2691 static void bgp_evpn_es_evi_vtep_free(struct bgp_evpn_es_evi_vtep
*evi_vtep
)
2693 struct bgp_evpn_es_evi
*es_evi
= evi_vtep
->es_evi
;
2695 if (evi_vtep
->flags
& (BGP_EVPN_EVI_VTEP_EAD
))
2696 /* as long as there is some reference we can't free it */
2699 list_delete_node(es_evi
->es_evi_vtep_list
, &evi_vtep
->es_evi_listnode
);
2700 XFREE(MTYPE_BGP_EVPN_ES_EVI_VTEP
, evi_vtep
);
2703 /* check if VTEP is already part of the list */
2704 static struct bgp_evpn_es_evi_vtep
*bgp_evpn_es_evi_vtep_find(
2705 struct bgp_evpn_es_evi
*es_evi
, struct in_addr vtep_ip
)
2707 struct listnode
*node
= NULL
;
2708 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
2710 for (ALL_LIST_ELEMENTS_RO(es_evi
->es_evi_vtep_list
, node
, evi_vtep
)) {
2711 if (evi_vtep
->vtep_ip
.s_addr
== vtep_ip
.s_addr
)
2717 /* A VTEP can be added as "active" attach to an ES if EAD-per-ES and
2718 * EAD-per-EVI routes are rxed from it.
2720 static void bgp_evpn_es_evi_vtep_re_eval_active(struct bgp
*bgp
,
2721 struct bgp_evpn_es_evi_vtep
*evi_vtep
)
2725 uint32_t ead_activity_flags
;
2727 old_active
= !!CHECK_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
);
2729 if (bgp_mh_info
->ead_evi_rx
)
2730 /* Both EAD-per-ES and EAD-per-EVI routes must be rxed from a PE
2731 * before it can be activated.
2733 ead_activity_flags
= BGP_EVPN_EVI_VTEP_EAD
;
2735 /* EAD-per-ES is sufficent to activate the PE */
2736 ead_activity_flags
= BGP_EVPN_EVI_VTEP_EAD_PER_ES
;
2738 if ((evi_vtep
->flags
& ead_activity_flags
) == ead_activity_flags
)
2739 SET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
);
2741 UNSET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
);
2743 new_active
= !!CHECK_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
);
2745 if (old_active
== new_active
)
2748 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2749 zlog_debug("es %s evi %u vtep %pI4 %s",
2750 evi_vtep
->es_evi
->es
->esi_str
,
2751 evi_vtep
->es_evi
->vpn
->vni
, &evi_vtep
->vtep_ip
,
2752 new_active
? "active" : "inactive");
2754 /* add VTEP to parent es */
2756 struct bgp_evpn_es_vtep
*es_vtep
;
2758 es_vtep
= bgp_evpn_es_vtep_add(bgp
, evi_vtep
->es_evi
->es
,
2759 evi_vtep
->vtep_ip
, false /*esr*/,
2761 evi_vtep
->es_vtep
= es_vtep
;
2763 if (evi_vtep
->es_vtep
) {
2764 bgp_evpn_es_vtep_do_del(bgp
, evi_vtep
->es_vtep
,
2766 evi_vtep
->es_vtep
= NULL
;
2769 /* queue up the parent es for background consistency checks */
2770 bgp_evpn_es_cons_checks_pend_add(evi_vtep
->es_evi
->es
);
2773 static void bgp_evpn_es_evi_vtep_add(struct bgp
*bgp
,
2774 struct bgp_evpn_es_evi
*es_evi
, struct in_addr vtep_ip
,
2777 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
2779 evi_vtep
= bgp_evpn_es_evi_vtep_find(es_evi
, vtep_ip
);
2782 evi_vtep
= bgp_evpn_es_evi_vtep_new(es_evi
, vtep_ip
);
2784 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2785 zlog_debug("add es %s evi %u vtep %pI4 %s",
2786 evi_vtep
->es_evi
->es
->esi_str
,
2787 evi_vtep
->es_evi
->vpn
->vni
, &evi_vtep
->vtep_ip
,
2788 ead_es
? "ead_es" : "ead_evi");
2791 SET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_EAD_PER_ES
);
2793 SET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_EAD_PER_EVI
);
2795 bgp_evpn_es_evi_vtep_re_eval_active(bgp
, evi_vtep
);
2798 static void bgp_evpn_es_evi_vtep_del(struct bgp
*bgp
,
2799 struct bgp_evpn_es_evi
*es_evi
, struct in_addr vtep_ip
,
2802 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
2804 evi_vtep
= bgp_evpn_es_evi_vtep_find(es_evi
, vtep_ip
);
2808 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2809 zlog_debug("del es %s evi %u vtep %pI4 %s",
2810 evi_vtep
->es_evi
->es
->esi_str
,
2811 evi_vtep
->es_evi
->vpn
->vni
, &evi_vtep
->vtep_ip
,
2812 ead_es
? "ead_es" : "ead_evi");
2815 UNSET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_EAD_PER_ES
);
2817 UNSET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_EAD_PER_EVI
);
2819 bgp_evpn_es_evi_vtep_re_eval_active(bgp
, evi_vtep
);
2820 bgp_evpn_es_evi_vtep_free(evi_vtep
);
2823 /* compare ES-IDs for the ES-EVI RB tree maintained per-VNI */
2824 static int bgp_es_evi_rb_cmp(const struct bgp_evpn_es_evi
*es_evi1
,
2825 const struct bgp_evpn_es_evi
*es_evi2
)
2827 return memcmp(&es_evi1
->es
->esi
, &es_evi2
->es
->esi
, ESI_BYTES
);
2829 RB_GENERATE(bgp_es_evi_rb_head
, bgp_evpn_es_evi
, rb_node
, bgp_es_evi_rb_cmp
);
2831 /* find the ES-EVI in the per-L2-VNI RB tree */
2832 static struct bgp_evpn_es_evi
*bgp_evpn_es_evi_find(struct bgp_evpn_es
*es
,
2833 struct bgpevpn
*vpn
)
2835 struct bgp_evpn_es_evi es_evi
;
2839 return RB_FIND(bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
, &es_evi
);
2842 /* allocate a new ES-EVI and insert it into the per-L2-VNI and per-ES
2845 static struct bgp_evpn_es_evi
*bgp_evpn_es_evi_new(struct bgp_evpn_es
*es
,
2846 struct bgpevpn
*vpn
)
2848 struct bgp_evpn_es_evi
*es_evi
;
2850 es_evi
= XCALLOC(MTYPE_BGP_EVPN_ES_EVI
, sizeof(*es_evi
));
2855 /* Initialise the VTEP list */
2856 es_evi
->es_evi_vtep_list
= list_new();
2857 listset_app_node_mem(es_evi
->es_evi_vtep_list
);
2858 es_evi
->es_evi_vtep_list
->cmp
= bgp_evpn_es_evi_vtep_cmp
;
2860 /* insert into the VNI-ESI rb tree */
2861 if (RB_INSERT(bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
, es_evi
)) {
2862 XFREE(MTYPE_BGP_EVPN_ES_EVI
, es_evi
);
2866 /* add to the ES's VNI list */
2867 listnode_init(&es_evi
->es_listnode
, es_evi
);
2868 listnode_add(es
->es_evi_list
, &es_evi
->es_listnode
);
2870 bgp_evpn_es_vrf_ref(es_evi
, vpn
->bgp_vrf
);
2875 /* remove the ES-EVI from the per-L2-VNI and per-ES tables and free
2878 static void bgp_evpn_es_evi_free(struct bgp_evpn_es_evi
*es_evi
)
2880 struct bgp_evpn_es
*es
= es_evi
->es
;
2881 struct bgpevpn
*vpn
= es_evi
->vpn
;
2883 /* cannot free the element as long as there is a local or remote
2886 if (es_evi
->flags
& (BGP_EVPNES_EVI_LOCAL
| BGP_EVPNES_EVI_REMOTE
))
2889 bgp_evpn_es_vrf_deref(es_evi
);
2891 /* remove from the ES's VNI list */
2892 list_delete_node(es
->es_evi_list
, &es_evi
->es_listnode
);
2894 /* remove from the VNI-ESI rb tree */
2895 RB_REMOVE(bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
, es_evi
);
2897 /* free the VTEP list */
2898 list_delete(&es_evi
->es_evi_vtep_list
);
2900 /* remove from the VNI-ESI rb tree */
2901 XFREE(MTYPE_BGP_EVPN_ES_EVI
, es_evi
);
2904 /* init local info associated with the ES-EVI */
2905 static void bgp_evpn_es_evi_local_info_set(struct bgp_evpn_es_evi
*es_evi
)
2907 struct bgpevpn
*vpn
= es_evi
->vpn
;
2909 if (CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
2912 SET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
);
2913 listnode_init(&es_evi
->l2vni_listnode
, es_evi
);
2914 listnode_add(vpn
->local_es_evi_list
, &es_evi
->l2vni_listnode
);
2917 /* clear any local info associated with the ES-EVI */
2918 static void bgp_evpn_es_evi_local_info_clear(struct bgp_evpn_es_evi
*es_evi
)
2920 struct bgpevpn
*vpn
= es_evi
->vpn
;
2922 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
2925 UNSET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
);
2926 list_delete_node(vpn
->local_es_evi_list
, &es_evi
->l2vni_listnode
);
2928 bgp_evpn_es_evi_free(es_evi
);
2931 /* eval remote info associated with the ES */
2932 static void bgp_evpn_es_evi_remote_info_re_eval(struct bgp_evpn_es_evi
*es_evi
)
2934 struct bgp_evpn_es
*es
= es_evi
->es
;
2936 /* if there are remote VTEPs the ES-EVI is classified as "remote" */
2937 if (listcount(es_evi
->es_evi_vtep_list
)) {
2938 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_REMOTE
)) {
2939 SET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_REMOTE
);
2940 ++es
->remote_es_evi_cnt
;
2941 /* set remote on the parent es */
2942 bgp_evpn_es_remote_info_re_eval(es
);
2945 if (CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_REMOTE
)) {
2946 UNSET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_REMOTE
);
2947 if (es
->remote_es_evi_cnt
)
2948 --es
->remote_es_evi_cnt
;
2949 bgp_evpn_es_evi_free(es_evi
);
2950 /* check if "remote" can be cleared from the
2953 bgp_evpn_es_remote_info_re_eval(es
);
2958 static void bgp_evpn_local_es_evi_do_del(struct bgp_evpn_es_evi
*es_evi
)
2960 struct prefix_evpn p
;
2961 struct bgp_evpn_es
*es
= es_evi
->es
;
2964 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
2967 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2968 zlog_debug("del local es %s evi %u",
2969 es_evi
->es
->esi_str
,
2972 bgp
= bgp_get_evpn();
2975 /* update EAD-ES with new list of VNIs */
2976 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_OPER_UP
)) {
2977 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_ES_ETH_TAG
,
2978 &es
->esi
, es
->originator_ip
);
2979 if (bgp_evpn_type1_route_update(bgp
, es
, NULL
, &p
))
2980 flog_err(EC_BGP_EVPN_ROUTE_CREATE
,
2981 "%u: EAD-ES route update failure for ESI %s VNI %u",
2982 bgp
->vrf_id
, es
->esi_str
,
2986 /* withdraw and delete EAD-EVI */
2987 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
)) {
2988 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_EVI_ETH_TAG
,
2989 &es
->esi
, es
->originator_ip
);
2990 if (bgp_evpn_type1_evi_route_delete(bgp
,
2991 es
, es_evi
->vpn
, &p
))
2992 flog_err(EC_BGP_EVPN_ROUTE_DELETE
,
2993 "%u: EAD-EVI route deletion failure for ESI %s VNI %u",
2994 bgp
->vrf_id
, es
->esi_str
,
2999 bgp_evpn_es_evi_local_info_clear(es_evi
);
3003 int bgp_evpn_local_es_evi_del(struct bgp
*bgp
, esi_t
*esi
, vni_t vni
)
3005 struct bgpevpn
*vpn
;
3006 struct bgp_evpn_es
*es
;
3007 struct bgp_evpn_es_evi
*es_evi
;
3008 char buf
[ESI_STR_LEN
];
3010 es
= bgp_evpn_es_find(esi
);
3014 "%u: Failed to deref VNI %d from ESI %s; ES not present",
3016 esi_to_str(esi
, buf
, sizeof(buf
)));
3020 vpn
= bgp_evpn_lookup_vni(bgp
, vni
);
3024 "%u: Failed to deref VNI %d from ESI %s; VNI not present",
3025 bgp
->vrf_id
, vni
, es
->esi_str
);
3029 es_evi
= bgp_evpn_es_evi_find(es
, vpn
);
3033 "%u: Failed to deref VNI %d from ESI %s; ES-VNI not present",
3034 bgp
->vrf_id
, vni
, es
->esi_str
);
3038 bgp_evpn_local_es_evi_do_del(es_evi
);
3042 /* Create ES-EVI and advertise the corresponding EAD routes */
3043 int bgp_evpn_local_es_evi_add(struct bgp
*bgp
, esi_t
*esi
, vni_t vni
)
3045 struct bgpevpn
*vpn
;
3046 struct prefix_evpn p
;
3047 struct bgp_evpn_es
*es
;
3048 struct bgp_evpn_es_evi
*es_evi
;
3049 char buf
[ESI_STR_LEN
];
3051 es
= bgp_evpn_es_find(esi
);
3055 "%u: Failed to associate VNI %d with ESI %s; ES not present",
3057 esi_to_str(esi
, buf
, sizeof(buf
)));
3061 vpn
= bgp_evpn_lookup_vni(bgp
, vni
);
3065 "%u: Failed to associate VNI %d with ESI %s; VNI not present",
3066 bgp
->vrf_id
, vni
, es
->esi_str
);
3070 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3071 zlog_debug("add local es %s evi %u",
3074 es_evi
= bgp_evpn_es_evi_find(es
, vpn
);
3077 if (CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
3081 es_evi
= bgp_evpn_es_evi_new(es
, vpn
);
3086 bgp_evpn_es_evi_local_info_set(es_evi
);
3088 /* generate an EAD-EVI for this new VNI */
3089 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
)) {
3090 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_EVI_ETH_TAG
, &es
->esi
,
3092 if (bgp_evpn_type1_route_update(bgp
, es
, vpn
, &p
))
3093 flog_err(EC_BGP_EVPN_ROUTE_CREATE
,
3094 "%u: EAD-EVI route creation failure for ESI %s VNI %u",
3095 bgp
->vrf_id
, es
->esi_str
, vni
);
3099 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_ES_ETH_TAG
,
3100 &es
->esi
, es
->originator_ip
);
3101 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_OPER_UP
)) {
3102 if (bgp_evpn_type1_route_update(bgp
, es
, NULL
, &p
))
3103 flog_err(EC_BGP_EVPN_ROUTE_CREATE
,
3104 "%u: EAD-ES route creation failure for ESI %s VNI %u",
3105 bgp
->vrf_id
, es
->esi_str
, vni
);
3111 /* Add remote ES-EVI entry. This is actually the remote VTEP add and the
3112 * ES-EVI is implicity created on first VTEP's reference.
3114 int bgp_evpn_remote_es_evi_add(struct bgp
*bgp
, struct bgpevpn
*vpn
,
3115 const struct prefix_evpn
*p
)
3117 char buf
[ESI_STR_LEN
];
3118 struct bgp_evpn_es
*es
;
3119 struct bgp_evpn_es_evi
*es_evi
;
3121 const esi_t
*esi
= &p
->prefix
.ead_addr
.esi
;
3124 /* local EAD-ES need not be sent back to zebra */
3127 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3128 zlog_debug("add remote %s es %s evi %u vtep %pI4",
3129 p
->prefix
.ead_addr
.eth_tag
? "ead-es" : "ead-evi",
3130 esi_to_str(esi
, buf
, sizeof(buf
)), vpn
->vni
,
3131 &p
->prefix
.ead_addr
.ip
.ipaddr_v4
);
3133 es
= bgp_evpn_es_find(esi
);
3135 es
= bgp_evpn_es_new(bgp
, esi
);
3137 flog_err(EC_BGP_ES_CREATE
,
3138 "%u: Failed to allocate ES entry for ESI %s - at remote ES Add",
3139 bgp
->vrf_id
, esi_to_str(esi
, buf
, sizeof(buf
)));
3144 es_evi
= bgp_evpn_es_evi_find(es
, vpn
);
3146 es_evi
= bgp_evpn_es_evi_new(es
, vpn
);
3148 bgp_evpn_es_free(es
, __func__
);
3153 ead_es
= !!p
->prefix
.ead_addr
.eth_tag
;
3154 bgp_evpn_es_evi_vtep_add(bgp
, es_evi
, p
->prefix
.ead_addr
.ip
.ipaddr_v4
,
3157 bgp_evpn_es_evi_remote_info_re_eval(es_evi
);
3161 /* A remote VTEP has withdrawn. The es-evi-vtep will be deleted and the
3162 * parent es-evi freed up implicitly in last VTEP's deref.
3164 int bgp_evpn_remote_es_evi_del(struct bgp
*bgp
, struct bgpevpn
*vpn
,
3165 const struct prefix_evpn
*p
)
3167 char buf
[ESI_STR_LEN
];
3168 struct bgp_evpn_es
*es
;
3169 struct bgp_evpn_es_evi
*es_evi
;
3173 /* local EAD-ES need not be sent back to zebra */
3176 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3178 "del remote %s es %s evi %u vtep %pI4",
3179 p
->prefix
.ead_addr
.eth_tag
? "ead-es" : "ead-evi",
3180 esi_to_str(&p
->prefix
.ead_addr
.esi
, buf
, sizeof(buf
)),
3181 vpn
->vni
, &p
->prefix
.ead_addr
.ip
.ipaddr_v4
);
3183 es
= bgp_evpn_es_find(&p
->prefix
.ead_addr
.esi
);
3185 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3186 zlog_debug("del remote %s es %s evi %u vtep %pI4, NO es",
3187 p
->prefix
.ead_addr
.eth_tag
? "ead-es"
3189 esi_to_str(&p
->prefix
.ead_addr
.esi
, buf
,
3192 &p
->prefix
.ead_addr
.ip
.ipaddr_v4
);
3195 es_evi
= bgp_evpn_es_evi_find(es
, vpn
);
3197 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3199 "del remote %s es %s evi %u vtep %pI4, NO es-evi",
3200 p
->prefix
.ead_addr
.eth_tag
? "ead-es"
3202 esi_to_str(&p
->prefix
.ead_addr
.esi
, buf
,
3205 &p
->prefix
.ead_addr
.ip
.ipaddr_v4
);
3209 ead_es
= !!p
->prefix
.ead_addr
.eth_tag
;
3210 bgp_evpn_es_evi_vtep_del(bgp
, es_evi
, p
->prefix
.ead_addr
.ip
.ipaddr_v4
,
3212 bgp_evpn_es_evi_remote_info_re_eval(es_evi
);
3216 /* Initialize the ES tables maintained per-L2_VNI */
3217 void bgp_evpn_vni_es_init(struct bgpevpn
*vpn
)
3219 /* Initialize the ES-EVI RB tree */
3220 RB_INIT(bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
);
3222 /* Initialize the local list maintained for quick walks by type */
3223 vpn
->local_es_evi_list
= list_new();
3224 listset_app_node_mem(vpn
->local_es_evi_list
);
3227 /* Cleanup the ES info maintained per-L2_VNI */
3228 void bgp_evpn_vni_es_cleanup(struct bgpevpn
*vpn
)
3230 struct bgp_evpn_es_evi
*es_evi
;
3231 struct bgp_evpn_es_evi
*es_evi_next
;
3233 RB_FOREACH_SAFE(es_evi
, bgp_es_evi_rb_head
,
3234 &vpn
->es_evi_rb_tree
, es_evi_next
) {
3235 bgp_evpn_local_es_evi_do_del(es_evi
);
3238 list_delete(&vpn
->local_es_evi_list
);
3241 static char *bgp_evpn_es_evi_vteps_str(char *vtep_str
,
3242 struct bgp_evpn_es_evi
*es_evi
,
3243 uint8_t vtep_str_size
)
3245 char vtep_flag_str
[BGP_EVPN_FLAG_STR_SZ
];
3246 struct listnode
*node
;
3247 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
3249 char ip_buf
[INET6_ADDRSTRLEN
];
3252 for (ALL_LIST_ELEMENTS_RO(es_evi
->es_evi_vtep_list
, node
, evi_vtep
)) {
3253 vtep_flag_str
[0] = '\0';
3254 if (evi_vtep
->flags
& BGP_EVPN_EVI_VTEP_EAD_PER_ES
)
3255 strlcat(vtep_flag_str
, "E", sizeof(vtep_flag_str
));
3256 if (evi_vtep
->flags
& BGP_EVPN_EVI_VTEP_EAD_PER_EVI
)
3257 strlcat(vtep_flag_str
, "V", sizeof(vtep_flag_str
));
3259 if (!strnlen(vtep_flag_str
, sizeof(vtep_flag_str
)))
3260 strlcpy(vtep_flag_str
, "-", sizeof(vtep_flag_str
));
3264 strlcat(vtep_str
, ",", vtep_str_size
);
3266 inet_ntop(AF_INET
, &evi_vtep
->vtep_ip
, ip_buf
,
3269 strlcat(vtep_str
, "(", vtep_str_size
);
3270 strlcat(vtep_str
, vtep_flag_str
, vtep_str_size
);
3271 strlcat(vtep_str
, ")", vtep_str_size
);
3277 static void bgp_evpn_es_evi_json_vtep_fill(json_object
*json_vteps
,
3278 struct bgp_evpn_es_evi_vtep
*evi_vtep
)
3280 json_object
*json_vtep_entry
;
3281 json_object
*json_flags
;
3282 char ip_buf
[INET6_ADDRSTRLEN
];
3284 json_vtep_entry
= json_object_new_object();
3286 json_object_string_add(
3287 json_vtep_entry
, "vtep_ip",
3288 inet_ntop(AF_INET
, &evi_vtep
->vtep_ip
, ip_buf
, sizeof(ip_buf
)));
3289 if (evi_vtep
->flags
& (BGP_EVPN_EVI_VTEP_EAD_PER_ES
|
3290 BGP_EVPN_EVI_VTEP_EAD_PER_EVI
)) {
3291 json_flags
= json_object_new_array();
3292 if (evi_vtep
->flags
& BGP_EVPN_EVI_VTEP_EAD_PER_ES
)
3293 json_array_string_add(json_flags
, "ead-per-es");
3294 if (evi_vtep
->flags
& BGP_EVPN_EVI_VTEP_EAD_PER_EVI
)
3295 json_array_string_add(json_flags
, "ead-per-evi");
3296 json_object_object_add(json_vtep_entry
,
3297 "flags", json_flags
);
3300 json_object_array_add(json_vteps
,
3304 static void bgp_evpn_es_evi_show_entry(struct vty
*vty
,
3305 struct bgp_evpn_es_evi
*es_evi
, json_object
*json
)
3307 struct listnode
*node
;
3308 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
3311 json_object
*json_vteps
;
3312 json_object
*json_types
;
3314 json_object_string_add(json
, "esi", es_evi
->es
->esi_str
);
3315 json_object_int_add(json
, "vni", es_evi
->vpn
->vni
);
3317 if (es_evi
->flags
& (BGP_EVPNES_EVI_LOCAL
|
3318 BGP_EVPNES_EVI_REMOTE
)) {
3319 json_types
= json_object_new_array();
3320 if (es_evi
->flags
& BGP_EVPNES_EVI_LOCAL
)
3321 json_array_string_add(json_types
, "local");
3322 if (es_evi
->flags
& BGP_EVPNES_EVI_REMOTE
)
3323 json_array_string_add(json_types
, "remote");
3324 json_object_object_add(json
, "type", json_types
);
3327 if (listcount(es_evi
->es_evi_vtep_list
)) {
3328 json_vteps
= json_object_new_array();
3329 for (ALL_LIST_ELEMENTS_RO(es_evi
->es_evi_vtep_list
,
3331 bgp_evpn_es_evi_json_vtep_fill(json_vteps
,
3334 json_object_object_add(json
, "vteps", json_vteps
);
3338 char vtep_str
[ES_VTEP_LIST_STR_SZ
+ BGP_EVPN_VTEPS_FLAG_STR_SZ
];
3341 if (es_evi
->flags
& BGP_EVPNES_EVI_LOCAL
)
3342 strlcat(type_str
, "L", sizeof(type_str
));
3343 if (es_evi
->flags
& BGP_EVPNES_EVI_REMOTE
)
3344 strlcat(type_str
, "R", sizeof(type_str
));
3345 if (es_evi
->flags
& BGP_EVPNES_EVI_INCONS_VTEP_LIST
)
3346 strlcat(type_str
, "I", sizeof(type_str
));
3348 bgp_evpn_es_evi_vteps_str(vtep_str
, es_evi
, sizeof(vtep_str
));
3350 vty_out(vty
, "%-8d %-30s %-5s %s\n",
3351 es_evi
->vpn
->vni
, es_evi
->es
->esi_str
,
3352 type_str
, vtep_str
);
3356 static void bgp_evpn_es_evi_show_entry_detail(struct vty
*vty
,
3357 struct bgp_evpn_es_evi
*es_evi
, json_object
*json
)
3360 json_object
*json_flags
;
3362 /* Add the "brief" info first */
3363 bgp_evpn_es_evi_show_entry(vty
, es_evi
, json
);
3364 if (es_evi
->flags
& BGP_EVPNES_EVI_INCONS_VTEP_LIST
) {
3365 json_flags
= json_object_new_array();
3366 json_array_string_add(json_flags
, "es-vtep-mismatch");
3367 json_object_object_add(json
, "flags", json_flags
);
3370 char vtep_str
[ES_VTEP_LIST_STR_SZ
+ BGP_EVPN_VTEPS_FLAG_STR_SZ
];
3374 if (es_evi
->flags
& BGP_EVPNES_EVI_LOCAL
)
3375 strlcat(type_str
, "L", sizeof(type_str
));
3376 if (es_evi
->flags
& BGP_EVPNES_EVI_REMOTE
)
3377 strlcat(type_str
, "R", sizeof(type_str
));
3379 bgp_evpn_es_evi_vteps_str(vtep_str
, es_evi
, sizeof(vtep_str
));
3380 if (!strlen(vtep_str
))
3381 strlcpy(vtep_str
, "-", sizeof(type_str
));
3383 vty_out(vty
, "VNI: %d ESI: %s\n",
3384 es_evi
->vpn
->vni
, es_evi
->es
->esi_str
);
3385 vty_out(vty
, " Type: %s\n", type_str
);
3386 vty_out(vty
, " Inconsistencies: %s\n",
3387 (es_evi
->flags
& BGP_EVPNES_EVI_INCONS_VTEP_LIST
) ?
3388 "es-vtep-mismatch":"-");
3389 vty_out(vty
, " VTEPs: %s\n", vtep_str
);
3394 static void bgp_evpn_es_evi_show_one_vni(struct bgpevpn
*vpn
, struct vty
*vty
,
3395 json_object
*json_array
, bool detail
)
3397 struct bgp_evpn_es_evi
*es_evi
;
3398 json_object
*json
= NULL
;
3400 RB_FOREACH(es_evi
, bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
) {
3402 /* create a separate json object for each ES */
3403 json
= json_object_new_object();
3405 bgp_evpn_es_evi_show_entry_detail(vty
, es_evi
, json
);
3407 bgp_evpn_es_evi_show_entry(vty
, es_evi
, json
);
3408 /* add ES to the json array */
3410 json_object_array_add(json_array
, json
);
3414 struct es_evi_show_ctx
{
3420 static void bgp_evpn_es_evi_show_one_vni_hash_cb(struct hash_bucket
*bucket
,
3423 struct bgpevpn
*vpn
= (struct bgpevpn
*)bucket
->data
;
3424 struct es_evi_show_ctx
*wctx
= (struct es_evi_show_ctx
*)ctxt
;
3426 bgp_evpn_es_evi_show_one_vni(vpn
, wctx
->vty
, wctx
->json
, wctx
->detail
);
3429 /* Display all ES EVIs */
3430 void bgp_evpn_es_evi_show(struct vty
*vty
, bool uj
, bool detail
)
3432 json_object
*json_array
= NULL
;
3433 struct es_evi_show_ctx wctx
;
3437 /* create an array of ES-EVIs */
3438 json_array
= json_object_new_array();
3442 wctx
.json
= json_array
;
3443 wctx
.detail
= detail
;
3445 bgp
= bgp_get_evpn();
3447 if (!json_array
&& !detail
) {
3448 vty_out(vty
, "Flags: L local, R remote, I inconsistent\n");
3449 vty_out(vty
, "VTEP-Flags: E EAD-per-ES, V EAD-per-EVI\n");
3450 vty_out(vty
, "%-8s %-30s %-5s %s\n",
3451 "VNI", "ESI", "Flags", "VTEPs");
3455 hash_iterate(bgp
->vnihash
,
3456 (void (*)(struct hash_bucket
*,
3457 void *))bgp_evpn_es_evi_show_one_vni_hash_cb
,
3460 vty_out(vty
, "%s\n", json_object_to_json_string_ext(
3461 json_array
, JSON_C_TO_STRING_PRETTY
));
3462 json_object_free(json_array
);
3466 /* Display specific ES EVI */
3467 void bgp_evpn_es_evi_show_vni(struct vty
*vty
, vni_t vni
,
3468 bool uj
, bool detail
)
3470 struct bgpevpn
*vpn
= NULL
;
3471 json_object
*json_array
= NULL
;
3475 /* create an array of ES-EVIs */
3476 json_array
= json_object_new_array();
3479 bgp
= bgp_get_evpn();
3481 vpn
= bgp_evpn_lookup_vni(bgp
, vni
);
3484 if (!json_array
&& !detail
) {
3485 vty_out(vty
, "Flags: L local, R remote, I inconsistent\n");
3486 vty_out(vty
, "VTEP-Flags: E EAD-per-ES, V EAD-per-EVI\n");
3487 vty_out(vty
, "%-8s %-30s %-5s %s\n",
3488 "VNI", "ESI", "Flags", "VTEPs");
3491 bgp_evpn_es_evi_show_one_vni(vpn
, vty
, json_array
, detail
);
3494 vty_out(vty
, "VNI not found\n");
3498 vty_out(vty
, "%s\n", json_object_to_json_string_ext(
3499 json_array
, JSON_C_TO_STRING_PRETTY
));
3500 json_object_free(json_array
);
3504 /*****************************************************************************
3505 * Ethernet Segment Consistency checks
3506 * Consistency checking is done to detect misconfig or mis-cabling. When
3507 * an inconsistency is detected it is simply logged (and displayed via
3508 * show commands) at this point. A more drastic action can be executed (based
3509 * on user config) in the future.
3511 /* queue up the es for background consistency checks */
3512 static void bgp_evpn_es_cons_checks_pend_add(struct bgp_evpn_es
*es
)
3514 if (!bgp_mh_info
->consistency_checking
)
3515 /* consistency checking is not enabled */
3518 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_CONS_CHECK_PEND
))
3519 /* already queued for consistency checking */
3522 SET_FLAG(es
->flags
, BGP_EVPNES_CONS_CHECK_PEND
);
3523 listnode_init(&es
->pend_es_listnode
, es
);
3524 listnode_add_after(bgp_mh_info
->pend_es_list
,
3525 listtail_unchecked(bgp_mh_info
->pend_es_list
),
3526 &es
->pend_es_listnode
);
3529 /* pull the ES from the consistency check list */
3530 static void bgp_evpn_es_cons_checks_pend_del(struct bgp_evpn_es
*es
)
3532 if (!CHECK_FLAG(es
->flags
, BGP_EVPNES_CONS_CHECK_PEND
))
3535 UNSET_FLAG(es
->flags
, BGP_EVPNES_CONS_CHECK_PEND
);
3536 list_delete_node(bgp_mh_info
->pend_es_list
,
3537 &es
->pend_es_listnode
);
3540 /* Number of active VTEPs associated with the ES-per-EVI */
3541 static uint32_t bgp_evpn_es_evi_get_active_vtep_cnt(
3542 struct bgp_evpn_es_evi
*es_evi
)
3544 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
3545 struct listnode
*node
;
3546 uint32_t vtep_cnt
= 0;
3548 for (ALL_LIST_ELEMENTS_RO(es_evi
->es_evi_vtep_list
, node
, evi_vtep
)) {
3549 if (CHECK_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
))
3556 /* Number of active VTEPs associated with the ES */
3557 static uint32_t bgp_evpn_es_get_active_vtep_cnt(struct bgp_evpn_es
*es
)
3559 struct listnode
*node
;
3560 uint32_t vtep_cnt
= 0;
3561 struct bgp_evpn_es_vtep
*es_vtep
;
3563 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
3564 if (CHECK_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
))
3571 static struct bgp_evpn_es_vtep
*bgp_evpn_es_get_next_active_vtep(
3572 struct bgp_evpn_es
*es
, struct bgp_evpn_es_vtep
*es_vtep
)
3574 struct listnode
*node
;
3575 struct bgp_evpn_es_vtep
*next_es_vtep
;
3578 node
= listnextnode_unchecked(&es_vtep
->es_listnode
);
3580 node
= listhead(es
->es_vtep_list
);
3582 for (; node
; node
= listnextnode_unchecked(node
)) {
3583 next_es_vtep
= listgetdata(node
);
3584 if (CHECK_FLAG(next_es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
))
3585 return next_es_vtep
;
3591 static struct bgp_evpn_es_evi_vtep
*bgp_evpn_es_evi_get_next_active_vtep(
3592 struct bgp_evpn_es_evi
*es_evi
,
3593 struct bgp_evpn_es_evi_vtep
*evi_vtep
)
3595 struct listnode
*node
;
3596 struct bgp_evpn_es_evi_vtep
*next_evi_vtep
;
3599 node
= listnextnode_unchecked(&evi_vtep
->es_evi_listnode
);
3601 node
= listhead(es_evi
->es_evi_vtep_list
);
3603 for (; node
; node
= listnextnode_unchecked(node
)) {
3604 next_evi_vtep
= listgetdata(node
);
3605 if (CHECK_FLAG(next_evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
))
3606 return next_evi_vtep
;
3612 static void bgp_evpn_es_evi_set_inconsistent(struct bgp_evpn_es_evi
*es_evi
)
3614 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_INCONS_VTEP_LIST
)) {
3615 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3616 zlog_debug("inconsistency detected - es %s evi %u vtep list mismatch",
3617 es_evi
->es
->esi_str
,
3619 SET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_INCONS_VTEP_LIST
);
3621 /* update parent ES with the incosistency setting */
3622 if (!es_evi
->es
->incons_evi_vtep_cnt
&&
3623 BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3624 zlog_debug("inconsistency detected - es %s vtep list mismatch",
3625 es_evi
->es
->esi_str
);
3626 ++es_evi
->es
->incons_evi_vtep_cnt
;
3627 SET_FLAG(es_evi
->es
->inconsistencies
,
3628 BGP_EVPNES_INCONS_VTEP_LIST
);
3632 static uint32_t bgp_evpn_es_run_consistency_checks(struct bgp_evpn_es
*es
)
3635 int es_active_vtep_cnt
;
3636 int evi_active_vtep_cnt
;
3637 struct bgp_evpn_es_evi
*es_evi
;
3638 struct listnode
*evi_node
;
3639 struct bgp_evpn_es_vtep
*es_vtep
;
3640 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
3642 /* reset the inconsistencies and re-evaluate */
3643 es
->incons_evi_vtep_cnt
= 0;
3644 es
->inconsistencies
= 0;
3646 es_active_vtep_cnt
= bgp_evpn_es_get_active_vtep_cnt(es
);
3647 for (ALL_LIST_ELEMENTS_RO(es
->es_evi_list
,
3648 evi_node
, es_evi
)) {
3651 /* reset the inconsistencies on the EVI and re-evaluate*/
3652 UNSET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_INCONS_VTEP_LIST
);
3654 evi_active_vtep_cnt
=
3655 bgp_evpn_es_evi_get_active_vtep_cnt(es_evi
);
3656 if (es_active_vtep_cnt
!= evi_active_vtep_cnt
) {
3657 bgp_evpn_es_evi_set_inconsistent(es_evi
);
3661 if (!es_active_vtep_cnt
)
3666 while ((es_vtep
= bgp_evpn_es_get_next_active_vtep(
3668 evi_vtep
= bgp_evpn_es_evi_get_next_active_vtep(es_evi
,
3671 bgp_evpn_es_evi_set_inconsistent(es_evi
);
3674 if (es_vtep
->vtep_ip
.s_addr
!=
3675 evi_vtep
->vtep_ip
.s_addr
) {
3676 /* inconsistency detected; set it and move
3679 bgp_evpn_es_evi_set_inconsistent(es_evi
);
3688 static int bgp_evpn_run_consistency_checks(struct thread
*t
)
3692 struct listnode
*node
;
3693 struct listnode
*nextnode
;
3694 struct bgp_evpn_es
*es
;
3696 for (ALL_LIST_ELEMENTS(bgp_mh_info
->pend_es_list
,
3697 node
, nextnode
, es
)) {
3700 /* run consistency checks on the ES and remove it from the
3703 proc_cnt
+= bgp_evpn_es_run_consistency_checks(es
);
3704 bgp_evpn_es_cons_checks_pend_del(es
);
3709 /* restart the timer */
3710 thread_add_timer(bm
->master
, bgp_evpn_run_consistency_checks
, NULL
,
3711 BGP_EVPN_CONS_CHECK_INTERVAL
,
3712 &bgp_mh_info
->t_cons_check
);
3717 /*****************************************************************************/
3718 void bgp_evpn_mh_init(void)
3720 bm
->mh_info
= XCALLOC(MTYPE_BGP_EVPN_MH_INFO
, sizeof(*bm
->mh_info
));
3722 /* setup ES tables */
3723 RB_INIT(bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
);
3725 bgp_mh_info
->local_es_list
= list_new();
3726 listset_app_node_mem(bgp_mh_info
->local_es_list
);
3727 /* list of ESs with pending processing */
3728 bgp_mh_info
->pend_es_list
= list_new();
3729 listset_app_node_mem(bgp_mh_info
->pend_es_list
);
3731 bgp_mh_info
->ead_evi_rx
= BGP_EVPN_MH_EAD_EVI_RX_DEF
;
3732 bgp_mh_info
->ead_evi_tx
= BGP_EVPN_MH_EAD_EVI_TX_DEF
;
3734 /* config knobs - XXX add cli to control it */
3735 bgp_mh_info
->ead_evi_adv_for_down_links
= true;
3736 bgp_mh_info
->consistency_checking
= true;
3737 bgp_mh_info
->install_l3nhg
= false;
3738 bgp_mh_info
->host_routes_use_l3nhg
= BGP_EVPN_MH_USE_ES_L3NHG_DEF
;
3740 if (bgp_mh_info
->consistency_checking
)
3741 thread_add_timer(bm
->master
, bgp_evpn_run_consistency_checks
,
3742 NULL
, BGP_EVPN_CONS_CHECK_INTERVAL
,
3743 &bgp_mh_info
->t_cons_check
);
3745 memset(&zero_esi_buf
, 0, sizeof(esi_t
));
3748 void bgp_evpn_mh_finish(void)
3750 struct bgp_evpn_es
*es
;
3751 struct bgp_evpn_es
*es_next
;
3753 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
3754 zlog_debug("evpn mh finish");
3756 RB_FOREACH_SAFE (es
, bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
,
3758 bgp_evpn_es_local_info_clear(es
);
3760 thread_cancel(&bgp_mh_info
->t_cons_check
);
3761 list_delete(&bgp_mh_info
->local_es_list
);
3762 list_delete(&bgp_mh_info
->pend_es_list
);
3764 XFREE(MTYPE_BGP_EVPN_MH_INFO
, bgp_mh_info
);