1 /* EVPN Multihoming procedures
3 * Copyright (C) 2019 Cumulus Networks, Inc.
6 * This file is part of FRR.
8 * FRRouting is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2, or (at your option) any
13 * FRRouting is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
32 #include "lib/printfrr.h"
34 #include "bgpd/bgp_attr_evpn.h"
35 #include "bgpd/bgpd.h"
36 #include "bgpd/bgp_table.h"
37 #include "bgpd/bgp_route.h"
38 #include "bgpd/bgp_attr.h"
39 #include "bgpd/bgp_mplsvpn.h"
40 #include "bgpd/bgp_evpn.h"
41 #include "bgpd/bgp_evpn_private.h"
42 #include "bgpd/bgp_evpn_mh.h"
43 #include "bgpd/bgp_ecommunity.h"
44 #include "bgpd/bgp_encap_types.h"
45 #include "bgpd/bgp_debug.h"
46 #include "bgpd/bgp_errors.h"
47 #include "bgpd/bgp_aspath.h"
48 #include "bgpd/bgp_zebra.h"
49 #include "bgpd/bgp_addpath.h"
50 #include "bgpd/bgp_label.h"
51 #include "bgpd/bgp_nht.h"
52 #include "bgpd/bgp_mpath.h"
53 #include "bgpd/bgp_trace.h"
55 static void bgp_evpn_local_es_down(struct bgp
*bgp
,
56 struct bgp_evpn_es
*es
);
57 static void bgp_evpn_local_type1_evi_route_del(struct bgp
*bgp
,
58 struct bgp_evpn_es
*es
);
59 static struct bgp_evpn_es_vtep
*bgp_evpn_es_vtep_add(struct bgp
*bgp
,
60 struct bgp_evpn_es
*es
,
61 struct in_addr vtep_ip
,
62 bool esr
, uint8_t df_alg
,
64 static void bgp_evpn_es_vtep_del(struct bgp
*bgp
,
65 struct bgp_evpn_es
*es
, struct in_addr vtep_ip
, bool esr
);
66 static void bgp_evpn_es_cons_checks_pend_add(struct bgp_evpn_es
*es
);
67 static void bgp_evpn_es_cons_checks_pend_del(struct bgp_evpn_es
*es
);
68 static struct bgp_evpn_es_evi
*
69 bgp_evpn_local_es_evi_do_del(struct bgp_evpn_es_evi
*es_evi
);
70 static uint32_t bgp_evpn_es_get_active_vtep_cnt(struct bgp_evpn_es
*es
);
71 static void bgp_evpn_l3nhg_update_on_vtep_chg(struct bgp_evpn_es
*es
);
72 static struct bgp_evpn_es
*bgp_evpn_es_new(struct bgp
*bgp
, const esi_t
*esi
);
73 static void bgp_evpn_es_free(struct bgp_evpn_es
*es
, const char *caller
);
74 static void bgp_evpn_path_es_unlink(struct bgp_path_es_info
*es_info
);
75 static void bgp_evpn_mac_update_on_es_local_chg(struct bgp_evpn_es
*es
,
78 esi_t zero_esi_buf
, *zero_esi
= &zero_esi_buf
;
79 static int bgp_evpn_run_consistency_checks(struct thread
*t
);
80 static void bgp_evpn_path_nh_info_free(struct bgp_path_evpn_nh_info
*nh_info
);
81 static void bgp_evpn_path_nh_unlink(struct bgp_path_evpn_nh_info
*nh_info
);
83 /******************************************************************************
84 * per-ES (Ethernet Segment) routing table
86 * Following routes are added to the ES's routing table -
87 * 1. Local and remote ESR (Type-4)
88 * 2. Local EAD-per-ES (Type-1).
90 * Key for these routes is {ESI, VTEP-IP} so the path selection is practically
91 * a no-op i.e. all paths lead to same VTEP-IP (i.e. result in the same VTEP
92 * being added to same ES).
94 * Note the following routes go into the VNI routing table (instead of the
96 * 1. Remote EAD-per-ES
97 * 2. Local and remote EAD-per-EVI
100 /* Calculate the best path for a multi-homing (Type-1 or Type-4) route
101 * installed in the ES's routing table.
103 static int bgp_evpn_es_route_select_install(struct bgp
*bgp
,
104 struct bgp_evpn_es
*es
,
105 struct bgp_dest
*dest
)
108 afi_t afi
= AFI_L2VPN
;
109 safi_t safi
= SAFI_EVPN
;
110 struct bgp_path_info
*old_select
; /* old best */
111 struct bgp_path_info
*new_select
; /* new best */
112 struct bgp_path_info_pair old_and_new
;
114 /* Compute the best path. */
115 bgp_best_selection(bgp
, dest
, &bgp
->maxpaths
[afi
][safi
], &old_and_new
,
117 old_select
= old_and_new
.old
;
118 new_select
= old_and_new
.new;
121 * If the best path hasn't changed - see if something needs to be
124 if (old_select
&& old_select
== new_select
125 && old_select
->type
== ZEBRA_ROUTE_BGP
126 && old_select
->sub_type
== BGP_ROUTE_IMPORTED
127 && !CHECK_FLAG(dest
->flags
, BGP_NODE_USER_CLEAR
)
128 && !CHECK_FLAG(old_select
->flags
, BGP_PATH_ATTR_CHANGED
)
129 && !bgp_addpath_is_addpath_used(&bgp
->tx_addpath
, afi
, safi
)) {
130 if (bgp_zebra_has_route_changed(old_select
)) {
131 bgp_evpn_es_vtep_add(bgp
, es
, old_select
->attr
->nexthop
,
133 old_select
->attr
->df_alg
,
134 old_select
->attr
->df_pref
);
136 UNSET_FLAG(old_select
->flags
, BGP_PATH_MULTIPATH_CHG
);
137 bgp_zebra_clear_route_change_flags(dest
);
141 /* If the user did a "clear" this flag will be set */
142 UNSET_FLAG(dest
->flags
, BGP_NODE_USER_CLEAR
);
144 /* bestpath has changed; update relevant fields and install or uninstall
145 * into the zebra RIB.
147 if (old_select
|| new_select
)
148 bgp_bump_version(dest
);
151 bgp_path_info_unset_flag(dest
, old_select
, BGP_PATH_SELECTED
);
153 bgp_path_info_set_flag(dest
, new_select
, BGP_PATH_SELECTED
);
154 bgp_path_info_unset_flag(dest
, new_select
,
155 BGP_PATH_ATTR_CHANGED
);
156 UNSET_FLAG(new_select
->flags
, BGP_PATH_MULTIPATH_CHG
);
159 if (new_select
&& new_select
->type
== ZEBRA_ROUTE_BGP
160 && new_select
->sub_type
== BGP_ROUTE_IMPORTED
) {
161 bgp_evpn_es_vtep_add(bgp
, es
, new_select
->attr
->nexthop
,
162 true /*esr */, new_select
->attr
->df_alg
,
163 new_select
->attr
->df_pref
);
165 if (old_select
&& old_select
->type
== ZEBRA_ROUTE_BGP
166 && old_select
->sub_type
== BGP_ROUTE_IMPORTED
)
167 bgp_evpn_es_vtep_del(
168 bgp
, es
, old_select
->attr
->nexthop
,
172 /* Clear any route change flags. */
173 bgp_zebra_clear_route_change_flags(dest
);
175 /* Reap old select bgp_path_info, if it has been removed */
176 if (old_select
&& CHECK_FLAG(old_select
->flags
, BGP_PATH_REMOVED
))
177 bgp_path_info_reap(dest
, old_select
);
182 /* Install Type-1/Type-4 route entry in the per-ES routing table */
183 static int bgp_evpn_es_route_install(struct bgp
*bgp
,
184 struct bgp_evpn_es
*es
, struct prefix_evpn
*p
,
185 struct bgp_path_info
*parent_pi
)
188 struct bgp_dest
*dest
= NULL
;
189 struct bgp_path_info
*pi
= NULL
;
190 struct attr
*attr_new
= NULL
;
192 /* Create (or fetch) route within the VNI.
193 * NOTE: There is no RD here.
195 dest
= bgp_node_get(es
->route_table
, (struct prefix
*)p
);
197 /* Check if route entry is already present. */
198 for (pi
= bgp_dest_get_bgp_path_info(dest
); pi
; pi
= pi
->next
)
200 && (struct bgp_path_info
*)pi
->extra
->parent
==
205 /* Add (or update) attribute to hash. */
206 attr_new
= bgp_attr_intern(parent_pi
->attr
);
208 /* Create new route with its attribute. */
209 pi
= info_make(parent_pi
->type
, BGP_ROUTE_IMPORTED
, 0,
210 parent_pi
->peer
, attr_new
, dest
);
211 SET_FLAG(pi
->flags
, BGP_PATH_VALID
);
212 bgp_path_info_extra_get(pi
);
213 pi
->extra
->parent
= bgp_path_info_lock(parent_pi
);
214 bgp_dest_lock_node((struct bgp_dest
*)parent_pi
->net
);
215 bgp_path_info_add(dest
, pi
);
217 if (attrhash_cmp(pi
->attr
, parent_pi
->attr
)
218 && !CHECK_FLAG(pi
->flags
, BGP_PATH_REMOVED
)) {
219 bgp_dest_unlock_node(dest
);
222 /* The attribute has changed. */
223 /* Add (or update) attribute to hash. */
224 attr_new
= bgp_attr_intern(parent_pi
->attr
);
226 /* Restore route, if needed. */
227 if (CHECK_FLAG(pi
->flags
, BGP_PATH_REMOVED
))
228 bgp_path_info_restore(dest
, pi
);
230 /* Mark if nexthop has changed. */
231 if (!IPV4_ADDR_SAME(&pi
->attr
->nexthop
, &attr_new
->nexthop
))
232 SET_FLAG(pi
->flags
, BGP_PATH_IGP_CHANGED
);
234 /* Unintern existing, set to new. */
235 bgp_attr_unintern(&pi
->attr
);
237 pi
->uptime
= bgp_clock();
240 /* Perform route selection and update zebra, if required. */
241 ret
= bgp_evpn_es_route_select_install(bgp
, es
, dest
);
243 bgp_dest_unlock_node(dest
);
248 /* Uninstall Type-1/Type-4 route entry from the ES routing table */
249 static int bgp_evpn_es_route_uninstall(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
250 struct prefix_evpn
*p
, struct bgp_path_info
*parent_pi
)
253 struct bgp_dest
*dest
;
254 struct bgp_path_info
*pi
;
256 if (!es
->route_table
)
259 /* Locate route within the ESI.
260 * NOTE: There is no RD here.
262 dest
= bgp_node_lookup(es
->route_table
, (struct prefix
*)p
);
266 /* Find matching route entry. */
267 for (pi
= bgp_dest_get_bgp_path_info(dest
); pi
; pi
= pi
->next
)
269 && (struct bgp_path_info
*)pi
->extra
->parent
==
274 bgp_dest_unlock_node(dest
);
278 /* Mark entry for deletion */
279 bgp_path_info_delete(dest
, pi
);
281 /* Perform route selection and update zebra, if required. */
282 ret
= bgp_evpn_es_route_select_install(bgp
, es
, dest
);
284 /* Unlock route node. */
285 bgp_dest_unlock_node(dest
);
290 /* Install or unistall a Tyoe-4 route in the per-ES routing table */
291 int bgp_evpn_es_route_install_uninstall(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
292 afi_t afi
, safi_t safi
, struct prefix_evpn
*evp
,
293 struct bgp_path_info
*pi
, int install
)
298 ret
= bgp_evpn_es_route_install(bgp
, es
, evp
, pi
);
300 ret
= bgp_evpn_es_route_uninstall(bgp
, es
, evp
, pi
);
305 "%u: Failed to %s EVPN %s route in ESI %s",
307 install
? "install" : "uninstall",
314 /* Delete (and withdraw) local routes for specified ES from global and ES table.
315 * Also remove all remote routes from the per ES table. Invoked when ES
318 static void bgp_evpn_es_route_del_all(struct bgp
*bgp
, struct bgp_evpn_es
*es
)
320 struct bgp_dest
*dest
;
321 struct bgp_path_info
*pi
, *nextpi
;
323 /* de-activate the ES */
324 bgp_evpn_local_es_down(bgp
, es
);
325 bgp_evpn_local_type1_evi_route_del(bgp
, es
);
327 /* Walk this ES's routing table and delete all routes. */
328 for (dest
= bgp_table_top(es
->route_table
); dest
;
329 dest
= bgp_route_next(dest
)) {
330 for (pi
= bgp_dest_get_bgp_path_info(dest
);
331 (pi
!= NULL
) && (nextpi
= pi
->next
, 1); pi
= nextpi
) {
332 bgp_path_info_delete(dest
, pi
);
333 bgp_path_info_reap(dest
, pi
);
338 /*****************************************************************************
339 * Base APIs for creating MH routes (Type-1 or Type-4) on local ethernet
343 /* create or update local EVPN type1/type4 route entry.
346 * the ES table if ESR/EAD-ES (or)
347 * the VNI table if EAD-EVI (or)
348 * the global table if ESR/EAD-ES/EAD-EVI
350 * Note: vpn is applicable only to EAD-EVI routes (NULL for EAD-ES and
353 int bgp_evpn_mh_route_update(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
354 struct bgpevpn
*vpn
, afi_t afi
, safi_t safi
,
355 struct bgp_dest
*dest
, struct attr
*attr
, int add
,
356 struct bgp_path_info
**ri
, int *route_changed
)
358 struct bgp_path_info
*tmp_pi
= NULL
;
359 struct bgp_path_info
*local_pi
= NULL
; /* local route entry if any */
360 struct bgp_path_info
*remote_pi
= NULL
; /* remote route entry if any */
361 struct attr
*attr_new
= NULL
;
362 struct prefix_evpn
*evp
;
365 evp
= (struct prefix_evpn
*)bgp_dest_get_prefix(dest
);
368 /* locate the local and remote entries if any */
369 for (tmp_pi
= bgp_dest_get_bgp_path_info(dest
); tmp_pi
;
370 tmp_pi
= tmp_pi
->next
) {
371 if (tmp_pi
->peer
== bgp
->peer_self
372 && tmp_pi
->type
== ZEBRA_ROUTE_BGP
373 && tmp_pi
->sub_type
== BGP_ROUTE_STATIC
)
375 if (tmp_pi
->type
== ZEBRA_ROUTE_BGP
376 && tmp_pi
->sub_type
== BGP_ROUTE_IMPORTED
377 && CHECK_FLAG(tmp_pi
->flags
, BGP_PATH_VALID
))
381 /* we don't expect to see a remote_ri at this point as
382 * an ES route has {esi, vtep_ip} as the key in the ES-rt-table
383 * in the VNI-rt-table.
388 "%u ERROR: local es route for ESI: %s Vtep %pI4 also learnt from remote",
389 bgp
->vrf_id
, es
? es
->esi_str
: "Null",
394 if (!local_pi
&& !add
)
397 /* create or update the entry */
400 /* Add or update attribute to hash */
401 attr_new
= bgp_attr_intern(attr
);
403 /* Create new route with its attribute. */
404 tmp_pi
= info_make(ZEBRA_ROUTE_BGP
, BGP_ROUTE_STATIC
, 0,
405 bgp
->peer_self
, attr_new
, dest
);
406 SET_FLAG(tmp_pi
->flags
, BGP_PATH_VALID
);
408 if (evp
->prefix
.route_type
== BGP_EVPN_AD_ROUTE
) {
409 bgp_path_info_extra_get(tmp_pi
);
410 tmp_pi
->extra
->num_labels
= 1;
412 vni2label(vpn
->vni
, &tmp_pi
->extra
->label
[0]);
414 tmp_pi
->extra
->label
[0] = 0;
417 /* add the newly created path to the route-node */
418 bgp_path_info_add(dest
, tmp_pi
);
421 if (attrhash_cmp(tmp_pi
->attr
, attr
)
422 && !CHECK_FLAG(tmp_pi
->flags
, BGP_PATH_REMOVED
))
425 /* The attribute has changed.
426 * Add (or update) attribute to hash.
428 attr_new
= bgp_attr_intern(attr
);
429 bgp_path_info_set_flag(dest
, tmp_pi
,
430 BGP_PATH_ATTR_CHANGED
);
432 /* Restore route, if needed. */
433 if (CHECK_FLAG(tmp_pi
->flags
, BGP_PATH_REMOVED
))
434 bgp_path_info_restore(dest
, tmp_pi
);
436 /* Unintern existing, set to new. */
437 bgp_attr_unintern(&tmp_pi
->attr
);
438 tmp_pi
->attr
= attr_new
;
439 tmp_pi
->uptime
= bgp_clock();
443 if (*route_changed
) {
444 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
446 "local ES %s vni %u route-type %s nexthop %pI4 updated",
447 es
? es
->esi_str
: "Null", vpn
? vpn
->vni
: 0,
448 evp
->prefix
.route_type
== BGP_EVPN_ES_ROUTE
450 : (vpn
? "ead-evi" : "ead-es"),
451 &attr
->mp_nexthop_global_in
);
454 /* Return back the route entry. */
459 /* Delete local EVPN ESR (type-4) and EAD (type-1) route
461 * Note: vpn is applicable only to EAD-EVI routes (NULL for EAD-ES and
464 static int bgp_evpn_mh_route_delete(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
465 struct bgpevpn
*vpn
, struct prefix_evpn
*p
)
467 afi_t afi
= AFI_L2VPN
;
468 safi_t safi
= SAFI_EVPN
;
469 struct bgp_path_info
*pi
;
470 struct bgp_dest
*dest
= NULL
; /* dest in esi table */
471 struct bgp_dest
*global_dest
= NULL
; /* dest in global table */
472 struct bgp_table
*rt_table
;
473 struct prefix_rd
*prd
;
476 rt_table
= vpn
->route_table
;
479 rt_table
= es
->route_table
;
483 /* First, locate the route node within the ESI or VNI.
484 * If it doesn't exist, ther is nothing to do.
485 * Note: there is no RD here.
487 dest
= bgp_node_lookup(rt_table
, (struct prefix
*)p
);
491 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
493 "local ES %s vni %u route-type %s nexthop %pI4 delete",
494 es
->esi_str
, vpn
? vpn
->vni
: 0,
495 p
->prefix
.route_type
== BGP_EVPN_ES_ROUTE
497 : (vpn
? "ead-evi" : "ead-es"),
500 /* Next, locate route node in the global EVPN routing table.
501 * Note that this table is a 2-level tree (RD-level + Prefix-level)
504 bgp_global_evpn_node_lookup(bgp
->rib
[afi
][safi
], afi
, safi
,
505 (const struct prefix_evpn
*)p
, prd
);
508 /* Delete route entry in the global EVPN table. */
509 delete_evpn_route_entry(bgp
, afi
, safi
, global_dest
, &pi
);
511 /* Schedule for processing - withdraws to peers happen from
515 bgp_process(bgp
, global_dest
, afi
, safi
);
516 bgp_dest_unlock_node(global_dest
);
520 * Delete route entry in the ESI or VNI routing table.
521 * This can just be removed.
523 delete_evpn_route_entry(bgp
, afi
, safi
, dest
, &pi
);
525 bgp_path_info_reap(dest
, pi
);
526 bgp_dest_unlock_node(dest
);
531 * This function is called when the VNI RD changes.
532 * Delete all EAD/EVI local routes for this VNI from the global routing table.
533 * These routes are scheduled for withdraw from peers.
535 int delete_global_ead_evi_routes(struct bgp
*bgp
, struct bgpevpn
*vpn
)
539 struct bgp_dest
*rdrn
, *rn
;
540 struct bgp_table
*table
;
541 struct bgp_path_info
*pi
;
546 /* Find the RD node for the VNI in the global table */
547 rdrn
= bgp_node_lookup(bgp
->rib
[afi
][safi
], (struct prefix
*)&vpn
->prd
);
548 if (rdrn
&& bgp_dest_has_bgp_path_info_data(rdrn
)) {
549 table
= bgp_dest_get_bgp_table_info(rdrn
);
552 * Iterate over all the routes in this table and delete EAD/EVI
555 for (rn
= bgp_table_top(table
); rn
; rn
= bgp_route_next(rn
)) {
556 struct prefix_evpn
*evp
= (struct prefix_evpn
*)&rn
->p
;
558 if (evp
->prefix
.route_type
!= BGP_EVPN_AD_ROUTE
)
561 delete_evpn_route_entry(bgp
, afi
, safi
, rn
, &pi
);
563 bgp_process(bgp
, rn
, afi
, safi
);
567 /* Unlock RD node. */
569 bgp_dest_unlock_node(rdrn
);
574 /*****************************************************************************
575 * Ethernet Segment (Type-4) Routes
576 * ESRs are used for DF election. Currently service-carving described in
577 * RFC 7432 is NOT supported. Instead preference based DF election is
579 * Reference: draft-ietf-bess-evpn-pref-df
581 /* Build extended community for EVPN ES (type-4) route */
582 static void bgp_evpn_type4_route_extcomm_build(struct bgp_evpn_es
*es
,
585 struct ecommunity ecom_encap
;
586 struct ecommunity ecom_es_rt
;
587 struct ecommunity ecom_df
;
588 struct ecommunity_val eval
;
589 struct ecommunity_val eval_es_rt
;
590 struct ecommunity_val eval_df
;
591 bgp_encap_types tnl_type
;
595 tnl_type
= BGP_ENCAP_TYPE_VXLAN
;
596 memset(&ecom_encap
, 0, sizeof(ecom_encap
));
597 encode_encap_extcomm(tnl_type
, &eval
);
599 ecom_encap
.unit_size
= ECOMMUNITY_SIZE
;
600 ecom_encap
.val
= (uint8_t *)eval
.val
;
601 attr
->ecommunity
= ecommunity_dup(&ecom_encap
);
604 memset(&mac
, 0, sizeof(struct ethaddr
));
605 memset(&ecom_es_rt
, 0, sizeof(ecom_es_rt
));
606 es_get_system_mac(&es
->esi
, &mac
);
607 encode_es_rt_extcomm(&eval_es_rt
, &mac
);
609 ecom_es_rt
.unit_size
= ECOMMUNITY_SIZE
;
610 ecom_es_rt
.val
= (uint8_t *)eval_es_rt
.val
;
612 ecommunity_merge(attr
->ecommunity
, &ecom_es_rt
);
614 /* DF election extended community */
615 memset(&ecom_df
, 0, sizeof(ecom_df
));
616 encode_df_elect_extcomm(&eval_df
, es
->df_pref
);
618 ecom_df
.val
= (uint8_t *)eval_df
.val
;
619 attr
->ecommunity
= ecommunity_merge(attr
->ecommunity
, &ecom_df
);
621 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES
);
624 /* Create or update local type-4 route */
625 static int bgp_evpn_type4_route_update(struct bgp
*bgp
,
626 struct bgp_evpn_es
*es
, struct prefix_evpn
*p
)
629 int route_changed
= 0;
630 afi_t afi
= AFI_L2VPN
;
631 safi_t safi
= SAFI_EVPN
;
633 struct attr
*attr_new
= NULL
;
634 struct bgp_dest
*dest
= NULL
;
635 struct bgp_path_info
*pi
= NULL
;
637 memset(&attr
, 0, sizeof(struct attr
));
639 /* Build path-attribute for this route. */
640 bgp_attr_default_set(&attr
, BGP_ORIGIN_IGP
);
641 attr
.nexthop
= es
->originator_ip
;
642 attr
.mp_nexthop_global_in
= es
->originator_ip
;
643 attr
.mp_nexthop_len
= BGP_ATTR_NHLEN_IPV4
;
645 /* Set up extended community. */
646 bgp_evpn_type4_route_extcomm_build(es
, &attr
);
648 /* First, create (or fetch) route node within the ESI. */
649 /* NOTE: There is no RD here. */
650 dest
= bgp_node_get(es
->route_table
, (struct prefix
*)p
);
652 /* Create or update route entry. */
653 ret
= bgp_evpn_mh_route_update(bgp
, es
, NULL
, afi
, safi
, dest
, &attr
, 1,
654 &pi
, &route_changed
);
658 "%u ERROR: Failed to updated ES route ESI: %s VTEP %pI4",
659 bgp
->vrf_id
, es
->esi_str
, &es
->originator_ip
);
664 /* Perform route selection;
665 * this is just to set the flags correctly
666 * as local route in the ES always wins.
668 bgp_evpn_es_route_select_install(bgp
, es
, dest
);
669 bgp_dest_unlock_node(dest
);
671 /* If this is a new route or some attribute has changed, export the
672 * route to the global table. The route will be advertised to peers
673 * from there. Note that this table is a 2-level tree (RD-level +
674 * Prefix-level) similar to L3VPN routes.
677 struct bgp_path_info
*global_pi
;
679 dest
= bgp_global_evpn_node_get(bgp
->rib
[afi
][safi
], afi
, safi
,
681 bgp_evpn_mh_route_update(bgp
, es
, NULL
, afi
, safi
, dest
,
682 attr_new
, 1, &global_pi
,
685 /* Schedule for processing and unlock node. */
686 bgp_process(bgp
, dest
, afi
, safi
);
687 bgp_dest_unlock_node(dest
);
690 /* Unintern temporary. */
691 aspath_unintern(&attr
.aspath
);
695 /* Delete local type-4 route */
696 static int bgp_evpn_type4_route_delete(struct bgp
*bgp
,
697 struct bgp_evpn_es
*es
, struct prefix_evpn
*p
)
699 return bgp_evpn_mh_route_delete(bgp
, es
, NULL
/* l2vni */, p
);
702 /* Process remote/received EVPN type-4 route (advertise or withdraw) */
703 int bgp_evpn_type4_route_process(struct peer
*peer
, afi_t afi
, safi_t safi
,
704 struct attr
*attr
, uint8_t *pfx
, int psize
,
710 struct in_addr vtep_ip
;
711 struct prefix_rd prd
;
712 struct prefix_evpn p
;
714 /* Type-4 route should be either 23 or 35 bytes
715 * RD (8), ESI (10), ip-len (1), ip (4 or 16)
717 if (psize
!= BGP_EVPN_TYPE4_V4_PSIZE
&&
718 psize
!= BGP_EVPN_TYPE4_V6_PSIZE
) {
719 flog_err(EC_BGP_EVPN_ROUTE_INVALID
,
720 "%u:%s - Rx EVPN Type-4 NLRI with invalid length %d",
721 peer
->bgp
->vrf_id
, peer
->host
, psize
);
726 prd
.family
= AF_UNSPEC
;
728 memcpy(&prd
.val
, pfx
, RD_BYTES
);
732 memcpy(&esi
, pfx
, ESI_BYTES
);
738 if (ipaddr_len
== IPV4_MAX_BITLEN
) {
739 memcpy(&vtep_ip
, pfx
, IPV4_MAX_BYTELEN
);
742 EC_BGP_EVPN_ROUTE_INVALID
,
743 "%u:%s - Rx EVPN Type-4 NLRI with unsupported IP address length %d",
744 peer
->bgp
->vrf_id
, peer
->host
, ipaddr_len
);
748 build_evpn_type4_prefix(&p
, &esi
, vtep_ip
);
749 /* Process the route. */
751 ret
= bgp_update(peer
, (struct prefix
*)&p
, addpath_id
, attr
,
752 afi
, safi
, ZEBRA_ROUTE_BGP
, BGP_ROUTE_NORMAL
,
753 &prd
, NULL
, 0, 0, NULL
);
755 ret
= bgp_withdraw(peer
, (struct prefix
*)&p
, addpath_id
, attr
,
756 afi
, safi
, ZEBRA_ROUTE_BGP
, BGP_ROUTE_NORMAL
,
757 &prd
, NULL
, 0, NULL
);
762 /* Check if a prefix belongs to the local ES */
763 static bool bgp_evpn_type4_prefix_match(struct prefix_evpn
*p
,
764 struct bgp_evpn_es
*es
)
766 return (p
->prefix
.route_type
== BGP_EVPN_ES_ROUTE
) &&
767 !memcmp(&p
->prefix
.es_addr
.esi
, &es
->esi
, sizeof(esi_t
));
770 /* Import remote ESRs on local ethernet segment add */
771 static int bgp_evpn_type4_remote_routes_import(struct bgp
*bgp
,
772 struct bgp_evpn_es
*es
, bool install
)
777 struct bgp_dest
*rd_dest
, *dest
;
778 struct bgp_table
*table
;
779 struct bgp_path_info
*pi
;
784 /* Walk entire global routing table and evaluate routes which could be
785 * imported into this Ethernet Segment.
787 for (rd_dest
= bgp_table_top(bgp
->rib
[afi
][safi
]); rd_dest
;
788 rd_dest
= bgp_route_next(rd_dest
)) {
789 table
= bgp_dest_get_bgp_table_info(rd_dest
);
793 for (dest
= bgp_table_top(table
); dest
;
794 dest
= bgp_route_next(dest
)) {
795 struct prefix_evpn
*evp
=
796 (struct prefix_evpn
*)bgp_dest_get_prefix(dest
);
798 for (pi
= bgp_dest_get_bgp_path_info(dest
); pi
;
801 * Consider "valid" remote routes applicable for
804 if (!(CHECK_FLAG(pi
->flags
, BGP_PATH_VALID
)
805 && pi
->type
== ZEBRA_ROUTE_BGP
806 && pi
->sub_type
== BGP_ROUTE_NORMAL
))
809 if (!bgp_evpn_type4_prefix_match(evp
, es
))
813 ret
= bgp_evpn_es_route_install(
816 ret
= bgp_evpn_es_route_uninstall(
822 "Failed to %s EVPN %pFX route in ESI %s",
827 bgp_dest_unlock_node(rd_dest
);
828 bgp_dest_unlock_node(dest
);
837 /*****************************************************************************
838 * Ethernet Auto Discovery (EAD/Type-1) route handling
839 * There are two types of EAD routes -
840 * 1. EAD-per-ES - Key: {ESI, ET=0xffffffff}
841 * 2. EAD-per-EVI - Key: {ESI, ET=0}
844 /* Extended communities associated with EAD-per-ES */
845 static void bgp_evpn_type1_es_route_extcomm_build(struct bgp_evpn_es
*es
,
848 struct ecommunity ecom_encap
;
849 struct ecommunity ecom_esi_label
;
850 struct ecommunity_val eval
;
851 struct ecommunity_val eval_esi_label
;
852 bgp_encap_types tnl_type
;
853 struct listnode
*evi_node
, *rt_node
;
854 struct ecommunity
*ecom
;
855 struct bgp_evpn_es_evi
*es_evi
;
858 tnl_type
= BGP_ENCAP_TYPE_VXLAN
;
859 memset(&ecom_encap
, 0, sizeof(ecom_encap
));
860 encode_encap_extcomm(tnl_type
, &eval
);
862 ecom_encap
.unit_size
= ECOMMUNITY_SIZE
;
863 ecom_encap
.val
= (uint8_t *)eval
.val
;
864 attr
->ecommunity
= ecommunity_dup(&ecom_encap
);
867 encode_esi_label_extcomm(&eval_esi_label
,
868 false /*single_active*/);
869 ecom_esi_label
.size
= 1;
870 ecom_esi_label
.unit_size
= ECOMMUNITY_SIZE
;
871 ecom_esi_label
.val
= (uint8_t *)eval_esi_label
.val
;
873 ecommunity_merge(attr
->ecommunity
, &ecom_esi_label
);
875 /* Add export RTs for all L2-VNIs associated with this ES */
876 /* XXX - suppress EAD-ES advertisment if there are no EVIs associated
879 for (ALL_LIST_ELEMENTS_RO(es
->es_evi_list
,
881 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
883 for (ALL_LIST_ELEMENTS_RO(es_evi
->vpn
->export_rtl
,
885 attr
->ecommunity
= ecommunity_merge(attr
->ecommunity
,
889 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES
);
892 /* Extended communities associated with EAD-per-EVI */
893 static void bgp_evpn_type1_evi_route_extcomm_build(struct bgp_evpn_es
*es
,
894 struct bgpevpn
*vpn
, struct attr
*attr
)
896 struct ecommunity ecom_encap
;
897 struct ecommunity_val eval
;
898 bgp_encap_types tnl_type
;
899 struct listnode
*rt_node
;
900 struct ecommunity
*ecom
;
903 tnl_type
= BGP_ENCAP_TYPE_VXLAN
;
904 memset(&ecom_encap
, 0, sizeof(ecom_encap
));
905 encode_encap_extcomm(tnl_type
, &eval
);
907 ecom_encap
.unit_size
= ECOMMUNITY_SIZE
;
908 ecom_encap
.val
= (uint8_t *)eval
.val
;
909 attr
->ecommunity
= ecommunity_dup(&ecom_encap
);
911 /* Add export RTs for the L2-VNI */
912 for (ALL_LIST_ELEMENTS_RO(vpn
->export_rtl
, rt_node
, ecom
))
913 attr
->ecommunity
= ecommunity_merge(attr
->ecommunity
, ecom
);
915 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES
);
918 /* Update EVPN EAD (type-1) route -
919 * vpn - valid for EAD-EVI routes and NULL for EAD-ES routes
921 static int bgp_evpn_type1_route_update(struct bgp
*bgp
,
922 struct bgp_evpn_es
*es
, struct bgpevpn
*vpn
,
923 struct prefix_evpn
*p
)
926 afi_t afi
= AFI_L2VPN
;
927 safi_t safi
= SAFI_EVPN
;
929 struct attr
*attr_new
= NULL
;
930 struct bgp_dest
*dest
= NULL
;
931 struct bgp_path_info
*pi
= NULL
;
932 int route_changed
= 0;
933 struct prefix_rd
*global_rd
;
935 memset(&attr
, 0, sizeof(struct attr
));
937 /* Build path-attribute for this route. */
938 bgp_attr_default_set(&attr
, BGP_ORIGIN_IGP
);
939 attr
.nexthop
= es
->originator_ip
;
940 attr
.mp_nexthop_global_in
= es
->originator_ip
;
941 attr
.mp_nexthop_len
= BGP_ATTR_NHLEN_IPV4
;
944 /* EAD-EVI route update */
946 vni2label(vpn
->vni
, &(attr
.label
));
948 /* Set up extended community */
949 bgp_evpn_type1_evi_route_extcomm_build(es
, vpn
, &attr
);
951 /* First, create (or fetch) route node within the VNI. */
952 dest
= bgp_node_get(vpn
->route_table
, (struct prefix
*)p
);
954 /* Create or update route entry. */
955 ret
= bgp_evpn_mh_route_update(bgp
, es
, vpn
, afi
, safi
, dest
,
956 &attr
, 1, &pi
, &route_changed
);
960 "%u Failed to update EAD-EVI route ESI: %s VNI %u VTEP %pI4",
961 bgp
->vrf_id
, es
->esi_str
, vpn
->vni
,
963 global_rd
= &vpn
->prd
;
965 /* EAD-ES route update */
966 /* MPLS label is 0 for EAD-ES route */
968 /* Set up extended community */
969 bgp_evpn_type1_es_route_extcomm_build(es
, &attr
);
971 /* First, create (or fetch) route node within the ES. */
972 /* NOTE: There is no RD here. */
973 /* XXX: fragment ID must be included as a part of the prefix. */
974 dest
= bgp_node_get(es
->route_table
, (struct prefix
*)p
);
976 /* Create or update route entry. */
977 ret
= bgp_evpn_mh_route_update(bgp
, es
, vpn
, afi
, safi
, dest
,
978 &attr
, 1, &pi
, &route_changed
);
982 "%u ERROR: Failed to updated EAD-EVI route ESI: %s VTEP %pI4",
983 bgp
->vrf_id
, es
->esi_str
, &es
->originator_ip
);
985 global_rd
= &es
->prd
;
992 /* Perform route selection;
993 * this is just to set the flags correctly as local route in
994 * the ES always wins.
996 evpn_route_select_install(bgp
, vpn
, dest
);
997 bgp_dest_unlock_node(dest
);
999 /* If this is a new route or some attribute has changed, export the
1000 * route to the global table. The route will be advertised to peers
1001 * from there. Note that this table is a 2-level tree (RD-level +
1002 * Prefix-level) similar to L3VPN routes.
1004 if (route_changed
) {
1005 struct bgp_path_info
*global_pi
;
1007 dest
= bgp_global_evpn_node_get(bgp
->rib
[afi
][safi
], afi
, safi
,
1009 bgp_evpn_mh_route_update(bgp
, es
, vpn
, afi
, safi
, dest
,
1010 attr_new
, 1, &global_pi
,
1013 /* Schedule for processing and unlock node. */
1014 bgp_process(bgp
, dest
, afi
, safi
);
1015 bgp_dest_unlock_node(dest
);
1018 /* Unintern temporary. */
1019 aspath_unintern(&attr
.aspath
);
1024 * This function is called when the export RT for a VNI changes.
1025 * Update all type-1 local routes for this VNI from VNI/ES tables and the global
1026 * table and advertise these routes to peers.
1029 void update_type1_routes_for_evi(struct bgp
*bgp
, struct bgpevpn
*vpn
)
1031 struct prefix_evpn p
;
1032 struct bgp_evpn_es
*es
;
1033 struct bgp_evpn_es_evi
*es_evi
;
1034 struct bgp_evpn_es_evi
*es_evi_next
;
1036 RB_FOREACH_SAFE(es_evi
, bgp_es_evi_rb_head
,
1037 &vpn
->es_evi_rb_tree
, es_evi_next
) {
1041 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_OPER_UP
)) {
1042 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_ES_ETH_TAG
,
1043 &es
->esi
, es
->originator_ip
);
1044 if (bgp_evpn_type1_route_update(bgp
, es
, NULL
, &p
))
1045 flog_err(EC_BGP_EVPN_ROUTE_CREATE
,
1046 "%u: EAD-ES route update failure for ESI %s VNI %u",
1047 bgp
->vrf_id
, es
->esi_str
,
1051 /* Update EAD-EVI */
1052 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
)) {
1053 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_EVI_ETH_TAG
,
1054 &es
->esi
, es
->originator_ip
);
1055 if (bgp_evpn_type1_route_update(bgp
, es
, es_evi
->vpn
,
1057 flog_err(EC_BGP_EVPN_ROUTE_DELETE
,
1058 "%u: EAD-EVI route update failure for ESI %s VNI %u",
1059 bgp
->vrf_id
, es
->esi_str
,
1065 /* Delete local Type-1 route */
1066 static int bgp_evpn_type1_es_route_delete(struct bgp
*bgp
,
1067 struct bgp_evpn_es
*es
, struct prefix_evpn
*p
)
1069 return bgp_evpn_mh_route_delete(bgp
, es
, NULL
/* l2vni */, p
);
1072 static int bgp_evpn_type1_evi_route_delete(struct bgp
*bgp
,
1073 struct bgp_evpn_es
*es
, struct bgpevpn
*vpn
,
1074 struct prefix_evpn
*p
)
1076 return bgp_evpn_mh_route_delete(bgp
, es
, vpn
, p
);
1079 /* Generate EAD-EVI for all VNIs */
1080 static void bgp_evpn_local_type1_evi_route_add(struct bgp
*bgp
,
1081 struct bgp_evpn_es
*es
)
1083 struct listnode
*evi_node
;
1084 struct prefix_evpn p
;
1085 struct bgp_evpn_es_evi
*es_evi
;
1087 /* EAD-per-EVI routes have been suppressed */
1088 if (!bgp_mh_info
->ead_evi_tx
)
1091 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
))
1092 /* EAD-EVI route add for this ES is already done */
1095 SET_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
);
1096 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_EVI_ETH_TAG
,
1097 &es
->esi
, es
->originator_ip
);
1099 for (ALL_LIST_ELEMENTS_RO(es
->es_evi_list
, evi_node
, es_evi
)) {
1100 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
1102 if (bgp_evpn_type1_route_update(bgp
, es
, es_evi
->vpn
, &p
))
1103 flog_err(EC_BGP_EVPN_ROUTE_CREATE
,
1104 "%u: Type4 route creation failure for ESI %s",
1105 bgp
->vrf_id
, es
->esi_str
);
1110 * Withdraw EAD-EVI for all VNIs
1112 static void bgp_evpn_local_type1_evi_route_del(struct bgp
*bgp
,
1113 struct bgp_evpn_es
*es
)
1115 struct listnode
*evi_node
;
1116 struct prefix_evpn p
;
1117 struct bgp_evpn_es_evi
*es_evi
;
1119 /* Delete and withdraw locally learnt EAD-EVI route */
1120 if (!CHECK_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
))
1121 /* EAD-EVI route has not been advertised for this ES */
1124 UNSET_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
);
1125 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_EVI_ETH_TAG
,
1126 &es
->esi
, es
->originator_ip
);
1127 for (ALL_LIST_ELEMENTS_RO(es
->es_evi_list
, evi_node
, es_evi
)) {
1128 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
1130 if (bgp_evpn_mh_route_delete(bgp
, es
, es_evi
->vpn
, &p
))
1131 flog_err(EC_BGP_EVPN_ROUTE_CREATE
,
1132 "%u: Type4 route creation failure for ESI %s",
1133 bgp
->vrf_id
, es
->esi_str
);
1138 * Process received EVPN type-1 route (advertise or withdraw).
1140 int bgp_evpn_type1_route_process(struct peer
*peer
, afi_t afi
, safi_t safi
,
1141 struct attr
*attr
, uint8_t *pfx
, int psize
,
1142 uint32_t addpath_id
)
1145 struct prefix_rd prd
;
1149 struct in_addr vtep_ip
;
1150 struct prefix_evpn p
;
1152 if (psize
!= BGP_EVPN_TYPE1_PSIZE
) {
1153 flog_err(EC_BGP_EVPN_ROUTE_INVALID
,
1154 "%u:%s - Rx EVPN Type-1 NLRI with invalid length %d",
1155 peer
->bgp
->vrf_id
, peer
->host
, psize
);
1159 /* Make prefix_rd */
1160 prd
.family
= AF_UNSPEC
;
1162 memcpy(&prd
.val
, pfx
, RD_BYTES
);
1166 memcpy(&esi
, pfx
, ESI_BYTES
);
1169 /* Copy Ethernet Tag */
1170 memcpy(ð_tag
, pfx
, EVPN_ETH_TAG_BYTES
);
1171 eth_tag
= ntohl(eth_tag
);
1172 pfx
+= EVPN_ETH_TAG_BYTES
;
1174 memcpy(&label
, pfx
, BGP_LABEL_BYTES
);
1176 /* EAD route prefix doesn't include the nexthop in the global
1179 vtep_ip
.s_addr
= INADDR_ANY
;
1180 build_evpn_type1_prefix(&p
, eth_tag
, &esi
, vtep_ip
);
1181 /* Process the route. */
1183 ret
= bgp_update(peer
, (struct prefix
*)&p
, addpath_id
, attr
,
1184 afi
, safi
, ZEBRA_ROUTE_BGP
, BGP_ROUTE_NORMAL
,
1185 &prd
, NULL
, 0, 0, NULL
);
1187 ret
= bgp_withdraw(peer
, (struct prefix
*)&p
, addpath_id
, attr
,
1188 afi
, safi
, ZEBRA_ROUTE_BGP
, BGP_ROUTE_NORMAL
,
1189 &prd
, NULL
, 0, NULL
);
1194 /*****************************************************************************/
1195 /* Ethernet Segment Management
1196 * 1. Ethernet Segment is a collection of links attached to the same
1197 * server (MHD) or switch (MHN)
1198 * 2. An Ethernet Segment can span multiple PEs and is identified by the
1200 * 3. Local ESs are configured in zebra and sent to BGP
1201 * 4. Remote ESs are created by BGP when one or more ES-EVIs reference it i.e.
1202 * created on first reference and release on last de-reference
1203 * 5. An ES can be both local and remote. Infact most local ESs are expected
1204 * to have an ES peer.
1207 /* A list of remote VTEPs is maintained for each ES. This list includes -
1208 * 1. VTEPs for which we have imported the ESR i.e. ES-peers
1209 * 2. VTEPs that have an "active" ES-EVI VTEP i.e. EAD-per-ES and EAD-per-EVI
1210 * have been imported into one or more VNIs
1212 static int bgp_evpn_es_vtep_cmp(void *p1
, void *p2
)
1214 const struct bgp_evpn_es_vtep
*es_vtep1
= p1
;
1215 const struct bgp_evpn_es_vtep
*es_vtep2
= p2
;
1217 return es_vtep1
->vtep_ip
.s_addr
- es_vtep2
->vtep_ip
.s_addr
;
1220 static struct bgp_evpn_es_vtep
*bgp_evpn_es_vtep_new(struct bgp_evpn_es
*es
,
1221 struct in_addr vtep_ip
)
1223 struct bgp_evpn_es_vtep
*es_vtep
;
1225 es_vtep
= XCALLOC(MTYPE_BGP_EVPN_ES_VTEP
, sizeof(*es_vtep
));
1228 es_vtep
->vtep_ip
.s_addr
= vtep_ip
.s_addr
;
1229 inet_ntop(AF_INET
, &es_vtep
->vtep_ip
, es_vtep
->vtep_str
,
1230 sizeof(es_vtep
->vtep_str
));
1231 listnode_init(&es_vtep
->es_listnode
, es_vtep
);
1232 listnode_add_sort(es
->es_vtep_list
, &es_vtep
->es_listnode
);
1237 static void bgp_evpn_es_vtep_free(struct bgp_evpn_es_vtep
*es_vtep
)
1239 struct bgp_evpn_es
*es
= es_vtep
->es
;
1241 if (CHECK_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ESR
) ||
1243 /* as long as there is some reference we can't free it */
1246 list_delete_node(es
->es_vtep_list
, &es_vtep
->es_listnode
);
1247 XFREE(MTYPE_BGP_EVPN_ES_VTEP
, es_vtep
);
1250 /* check if VTEP is already part of the list */
1251 static struct bgp_evpn_es_vtep
*bgp_evpn_es_vtep_find(struct bgp_evpn_es
*es
,
1252 struct in_addr vtep_ip
)
1254 struct listnode
*node
= NULL
;
1255 struct bgp_evpn_es_vtep
*es_vtep
;
1257 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
1258 if (es_vtep
->vtep_ip
.s_addr
== vtep_ip
.s_addr
)
1264 /* Send the remote ES to zebra for NHG programming */
1265 static int bgp_zebra_send_remote_es_vtep(struct bgp
*bgp
,
1266 struct bgp_evpn_es_vtep
*es_vtep
, bool add
)
1268 struct bgp_evpn_es
*es
= es_vtep
->es
;
1273 if (!zclient
|| zclient
->sock
< 0)
1276 /* Don't try to register if Zebra doesn't know of this instance. */
1277 if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp
)) {
1278 if (BGP_DEBUG(zebra
, ZEBRA
))
1279 zlog_debug("No zebra instance, not installing remote es %s",
1284 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ESR
)
1285 flags
|= ZAPI_ES_VTEP_FLAG_ESR_RXED
;
1290 zclient_create_header(s
,
1291 add
? ZEBRA_REMOTE_ES_VTEP_ADD
: ZEBRA_REMOTE_ES_VTEP_DEL
,
1293 stream_put(s
, &es
->esi
, sizeof(esi_t
));
1294 stream_put_ipv4(s
, es_vtep
->vtep_ip
.s_addr
);
1296 stream_putl(s
, flags
);
1297 stream_putc(s
, es_vtep
->df_alg
);
1298 stream_putw(s
, es_vtep
->df_pref
);
1301 stream_putw_at(s
, 0, stream_get_endp(s
));
1303 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1304 zlog_debug("Tx %s Remote ESI %s VTEP %pI4", add
? "ADD" : "DEL",
1305 es
->esi_str
, &es_vtep
->vtep_ip
);
1307 frrtrace(3, frr_bgp
, evpn_mh_vtep_zsend
, add
, es
, es_vtep
);
1309 return zclient_send_message(zclient
);
1312 static void bgp_evpn_es_vtep_re_eval_active(struct bgp
*bgp
,
1313 struct bgp_evpn_es_vtep
*es_vtep
,
1319 old_active
= CHECK_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
);
1320 /* currently we need an active EVI reference to use the VTEP as
1321 * a nexthop. this may change...
1323 if (es_vtep
->evi_cnt
)
1324 SET_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
);
1326 UNSET_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
);
1328 new_active
= CHECK_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
);
1330 if ((old_active
!= new_active
) || (new_active
&& param_change
)) {
1332 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1333 zlog_debug("es %s vtep %pI4 %s df %u/%u",
1334 es_vtep
->es
->esi_str
, &es_vtep
->vtep_ip
,
1335 new_active
? "active" : "inactive",
1336 es_vtep
->df_alg
, es_vtep
->df_pref
);
1338 /* send remote ES to zebra */
1339 bgp_zebra_send_remote_es_vtep(bgp
, es_vtep
, new_active
);
1341 /* The NHG is updated first for efficient failover handling.
1342 * Note the NHG can be de-activated while there are bgp
1343 * routes referencing it. Zebra is capable of handling that
1344 * elegantly by holding the NHG till all routes using it are
1347 bgp_evpn_l3nhg_update_on_vtep_chg(es_vtep
->es
);
1348 /* queue up the es for background consistency checks */
1349 bgp_evpn_es_cons_checks_pend_add(es_vtep
->es
);
1353 static struct bgp_evpn_es_vtep
*bgp_evpn_es_vtep_add(struct bgp
*bgp
,
1354 struct bgp_evpn_es
*es
,
1355 struct in_addr vtep_ip
,
1356 bool esr
, uint8_t df_alg
,
1359 struct bgp_evpn_es_vtep
*es_vtep
;
1360 bool param_change
= false;
1362 es_vtep
= bgp_evpn_es_vtep_find(es
, vtep_ip
);
1365 es_vtep
= bgp_evpn_es_vtep_new(es
, vtep_ip
);
1367 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1368 zlog_debug("es %s vtep %pI4 add %s df %u/%u",
1369 es_vtep
->es
->esi_str
, &es_vtep
->vtep_ip
,
1370 esr
? "esr" : "ead", df_alg
, df_pref
);
1373 SET_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ESR
);
1374 if ((es_vtep
->df_pref
!= df_pref
)
1375 || (es_vtep
->df_alg
!= df_alg
)) {
1376 param_change
= true;
1377 es_vtep
->df_pref
= df_pref
;
1378 es_vtep
->df_alg
= df_alg
;
1384 bgp_evpn_es_vtep_re_eval_active(bgp
, es_vtep
, param_change
);
1389 static void bgp_evpn_es_vtep_do_del(struct bgp
*bgp
,
1390 struct bgp_evpn_es_vtep
*es_vtep
, bool esr
)
1392 bool param_change
= false;
1394 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1395 zlog_debug("es %s vtep %pI4 del %s", es_vtep
->es
->esi_str
,
1396 &es_vtep
->vtep_ip
, esr
? "esr" : "ead");
1398 UNSET_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ESR
);
1399 if (es_vtep
->df_pref
|| es_vtep
->df_alg
) {
1400 param_change
= true;
1401 es_vtep
->df_pref
= 0;
1402 es_vtep
->df_alg
= 0;
1405 if (es_vtep
->evi_cnt
)
1409 bgp_evpn_es_vtep_re_eval_active(bgp
, es_vtep
, param_change
);
1410 bgp_evpn_es_vtep_free(es_vtep
);
1413 static void bgp_evpn_es_vtep_del(struct bgp
*bgp
,
1414 struct bgp_evpn_es
*es
, struct in_addr vtep_ip
, bool esr
)
1416 struct bgp_evpn_es_vtep
*es_vtep
;
1418 es_vtep
= bgp_evpn_es_vtep_find(es
, vtep_ip
);
1420 bgp_evpn_es_vtep_do_del(bgp
, es_vtep
, esr
);
1423 /********************** ES MAC-IP paths *************************************
1424 * 1. Local MAC-IP routes in the VNI routing table are linked to the
1425 * destination ES (macip_evi_path_list) for efficient updates on ES oper
1427 * 2. Non-local MAC-IP routes in the global routing table are linked to
1428 * the detination for efficient updates on -
1429 * a. VTEP add/del - this results in a L3NHG update.
1430 * b. ES-VRF add/del - this may result in the host route being migrated to
1431 * L3NHG or vice versa (flat multipath list).
1432 ****************************************************************************/
1433 static void bgp_evpn_path_es_info_free(struct bgp_path_es_info
*es_info
)
1435 bgp_evpn_path_es_unlink(es_info
);
1436 XFREE(MTYPE_BGP_EVPN_PATH_ES_INFO
, es_info
);
1439 void bgp_evpn_path_mh_info_free(struct bgp_path_mh_info
*mh_info
)
1441 if (mh_info
->es_info
)
1442 bgp_evpn_path_es_info_free(mh_info
->es_info
);
1443 if (mh_info
->nh_info
)
1444 bgp_evpn_path_nh_info_free(mh_info
->nh_info
);
1445 XFREE(MTYPE_BGP_EVPN_PATH_MH_INFO
, mh_info
);
1448 static struct bgp_path_es_info
*
1449 bgp_evpn_path_es_info_new(struct bgp_path_info
*pi
, vni_t vni
)
1451 struct bgp_path_info_extra
*e
;
1452 struct bgp_path_mh_info
*mh_info
;
1453 struct bgp_path_es_info
*es_info
;
1455 e
= bgp_path_info_extra_get(pi
);
1457 /* If mh_info doesn't exist allocate it */
1458 mh_info
= e
->mh_info
;
1460 e
->mh_info
= mh_info
= XCALLOC(MTYPE_BGP_EVPN_PATH_MH_INFO
,
1461 sizeof(struct bgp_path_mh_info
));
1463 /* If es_info doesn't exist allocate it */
1464 es_info
= mh_info
->es_info
;
1466 mh_info
->es_info
= es_info
=
1467 XCALLOC(MTYPE_BGP_EVPN_PATH_ES_INFO
,
1468 sizeof(struct bgp_path_es_info
));
1476 static void bgp_evpn_path_es_unlink(struct bgp_path_es_info
*es_info
)
1478 struct bgp_evpn_es
*es
= es_info
->es
;
1479 struct bgp_path_info
*pi
;
1485 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
1486 zlog_debug("vni %u path %pFX unlinked from es %s", es_info
->vni
,
1487 &pi
->net
->p
, es
->esi_str
);
1490 list_delete_node(es
->macip_evi_path_list
,
1491 &es_info
->es_listnode
);
1493 list_delete_node(es
->macip_global_path_list
,
1494 &es_info
->es_listnode
);
1498 /* if there are no other references against the ES it
1501 bgp_evpn_es_free(es
, __func__
);
1503 /* Note we don't free the path es_info on unlink; it will be freed up
1504 * along with the path.
1508 void bgp_evpn_path_es_link(struct bgp_path_info
*pi
, vni_t vni
, esi_t
*esi
)
1510 struct bgp_path_es_info
*es_info
;
1511 struct bgp_evpn_es
*es
;
1512 struct bgp
*bgp_evpn
;
1514 es_info
= (pi
->extra
&& pi
->extra
->mh_info
)
1515 ? pi
->extra
->mh_info
->es_info
1517 /* if the esi is zero just unlink the path from the old es */
1518 if (!esi
|| !memcmp(esi
, zero_esi
, sizeof(*esi
))) {
1520 bgp_evpn_path_es_unlink(es_info
);
1524 bgp_evpn
= bgp_get_evpn();
1528 /* setup es_info against the path if it doesn't aleady exist */
1530 es_info
= bgp_evpn_path_es_info_new(pi
, vni
);
1532 /* find-create ES */
1533 es
= bgp_evpn_es_find(esi
);
1535 es
= bgp_evpn_es_new(bgp_evpn
, esi
);
1538 if (es_info
->es
== es
)
1541 /* unlink old ES if any */
1542 bgp_evpn_path_es_unlink(es_info
);
1544 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
1545 zlog_debug("vni %u path %pFX linked to es %s", vni
, &pi
->net
->p
,
1548 /* link mac-ip path to the new destination ES */
1550 listnode_init(&es_info
->es_listnode
, es_info
);
1552 listnode_add(es
->macip_evi_path_list
, &es_info
->es_listnode
);
1554 listnode_add(es
->macip_global_path_list
, &es_info
->es_listnode
);
1557 static bool bgp_evpn_is_macip_path(struct bgp_path_info
*pi
)
1559 struct prefix_evpn
*evp
;
1561 /* Only MAC-IP routes need to be linked (MAC-only routes can be
1562 * skipped) as these lists are maintained for managing
1563 * host routes in the tenant VRF
1565 evp
= (struct prefix_evpn
*)&pi
->net
->p
;
1566 return is_evpn_prefix_ipaddr_v4(evp
) || is_evpn_prefix_ipaddr_v6(evp
);
1569 /* When a remote ES is added to a VRF, routes using that as
1570 * a destination need to be migrated to a L3NHG or viceversa.
1571 * This is done indirectly by re-attempting an install of the
1572 * route in the associated VRFs. As a part of the VRF install use
1573 * of l3 NHG is evaluated and this results in the
1574 * attr.es_flag ATTR_ES_USE_L3_NHG being set or cleared.
1577 bgp_evpn_es_path_update_on_es_vrf_chg(struct bgp_evpn_es_vrf
*es_vrf
,
1580 struct listnode
*node
;
1581 struct bgp_path_es_info
*es_info
;
1582 struct bgp_path_info
*pi
;
1583 struct bgp_evpn_es
*es
= es_vrf
->es
;
1585 if (!bgp_mh_info
->host_routes_use_l3nhg
)
1588 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
1589 zlog_debug("update paths linked to es %s on es-vrf %s %s",
1590 es
->esi_str
, es_vrf
->bgp_vrf
->name
, reason
);
1592 for (ALL_LIST_ELEMENTS_RO(es
->macip_global_path_list
, node
, es_info
)) {
1595 if (!bgp_evpn_is_macip_path(pi
))
1598 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
1600 "update path %pFX linked to es %s on vrf chg",
1601 &pi
->net
->p
, es
->esi_str
);
1602 bgp_evpn_route_entry_install_if_vrf_match(es_vrf
->bgp_vrf
, pi
,
1607 /* compare ES-IDs for the global ES RB tree */
1608 static int bgp_es_rb_cmp(const struct bgp_evpn_es
*es1
,
1609 const struct bgp_evpn_es
*es2
)
1611 return memcmp(&es1
->esi
, &es2
->esi
, ESI_BYTES
);
1613 RB_GENERATE(bgp_es_rb_head
, bgp_evpn_es
, rb_node
, bgp_es_rb_cmp
);
1615 struct bgp_evpn_es
*bgp_evpn_es_find(const esi_t
*esi
)
1617 struct bgp_evpn_es tmp
;
1619 memcpy(&tmp
.esi
, esi
, sizeof(esi_t
));
1620 return RB_FIND(bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
, &tmp
);
1623 static struct bgp_evpn_es
*bgp_evpn_es_new(struct bgp
*bgp
, const esi_t
*esi
)
1625 struct bgp_evpn_es
*es
;
1630 es
= XCALLOC(MTYPE_BGP_EVPN_ES
, sizeof(struct bgp_evpn_es
));
1633 memcpy(&es
->esi
, esi
, sizeof(esi_t
));
1635 /* Initialise the VTEP list */
1636 es
->es_vtep_list
= list_new();
1637 listset_app_node_mem(es
->es_vtep_list
);
1638 es
->es_vtep_list
->cmp
= bgp_evpn_es_vtep_cmp
;
1640 esi_to_str(&es
->esi
, es
->esi_str
, sizeof(es
->esi_str
));
1642 /* Initialize the ES routing table */
1643 es
->route_table
= bgp_table_init(bgp
, AFI_L2VPN
, SAFI_EVPN
);
1645 /* Add to rb_tree */
1646 if (RB_INSERT(bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
, es
)) {
1647 XFREE(MTYPE_BGP_EVPN_ES
, es
);
1651 /* Initialise the ES-EVI list */
1652 es
->es_evi_list
= list_new();
1653 listset_app_node_mem(es
->es_evi_list
);
1655 /* Initialise the ES-VRF list used for L3NHG management */
1656 es
->es_vrf_list
= list_new();
1657 listset_app_node_mem(es
->es_vrf_list
);
1659 /* Initialise the route list used for efficient event handling */
1660 es
->macip_evi_path_list
= list_new();
1661 listset_app_node_mem(es
->macip_evi_path_list
);
1662 es
->macip_global_path_list
= list_new();
1663 listset_app_node_mem(es
->macip_global_path_list
);
1665 QOBJ_REG(es
, bgp_evpn_es
);
1670 /* Free a given ES -
1671 * This just frees appropriate memory, caller should have taken other
1674 static void bgp_evpn_es_free(struct bgp_evpn_es
*es
, const char *caller
)
1676 if ((es
->flags
& (BGP_EVPNES_LOCAL
| BGP_EVPNES_REMOTE
))
1677 || listcount(es
->macip_evi_path_list
)
1678 || listcount(es
->macip_global_path_list
))
1681 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1682 zlog_debug("%s: es %s free", caller
, es
->esi_str
);
1684 /* cleanup resources maintained against the ES */
1685 list_delete(&es
->es_evi_list
);
1686 list_delete(&es
->es_vrf_list
);
1687 list_delete(&es
->es_vtep_list
);
1688 list_delete(&es
->macip_evi_path_list
);
1689 list_delete(&es
->macip_global_path_list
);
1690 bgp_table_unlock(es
->route_table
);
1692 /* remove the entry from various databases */
1693 RB_REMOVE(bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
, es
);
1694 bgp_evpn_es_cons_checks_pend_del(es
);
1697 XFREE(MTYPE_BGP_EVPN_ES
, es
);
1700 static inline bool bgp_evpn_is_es_local_and_non_bypass(struct bgp_evpn_es
*es
)
1702 return (es
->flags
& BGP_EVPNES_LOCAL
)
1703 && !(es
->flags
& BGP_EVPNES_BYPASS
);
1706 /* init local info associated with the ES */
1707 static void bgp_evpn_es_local_info_set(struct bgp
*bgp
, struct bgp_evpn_es
*es
)
1709 char buf
[BGP_EVPN_PREFIX_RD_LEN
];
1713 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_LOCAL
))
1716 old_is_local
= bgp_evpn_is_es_local_and_non_bypass(es
);
1717 SET_FLAG(es
->flags
, BGP_EVPNES_LOCAL
);
1719 listnode_init(&es
->es_listnode
, es
);
1720 listnode_add(bgp_mh_info
->local_es_list
, &es
->es_listnode
);
1722 /* auto derive RD for this es */
1723 bf_assign_index(bm
->rd_idspace
, es
->rd_id
);
1724 es
->prd
.family
= AF_UNSPEC
;
1725 es
->prd
.prefixlen
= 64;
1726 snprintfrr(buf
, sizeof(buf
), "%pI4:%hu", &bgp
->router_id
, es
->rd_id
);
1727 (void)str2prefix_rd(buf
, &es
->prd
);
1729 is_local
= bgp_evpn_is_es_local_and_non_bypass(es
);
1730 if (old_is_local
!= is_local
)
1731 bgp_evpn_mac_update_on_es_local_chg(es
, is_local
);
1734 /* clear any local info associated with the ES */
1735 static void bgp_evpn_es_local_info_clear(struct bgp_evpn_es
*es
, bool finish
)
1740 if (!CHECK_FLAG(es
->flags
, BGP_EVPNES_LOCAL
))
1743 old_is_local
= bgp_evpn_is_es_local_and_non_bypass(es
);
1744 UNSET_FLAG(es
->flags
, BGP_EVPNES_LOCAL
);
1746 is_local
= bgp_evpn_is_es_local_and_non_bypass(es
);
1747 if (!finish
&& (old_is_local
!= is_local
))
1748 bgp_evpn_mac_update_on_es_local_chg(es
, is_local
);
1750 /* remove from the ES local list */
1751 list_delete_node(bgp_mh_info
->local_es_list
, &es
->es_listnode
);
1753 bf_release_index(bm
->rd_idspace
, es
->rd_id
);
1755 bgp_evpn_es_free(es
, __func__
);
1758 /* eval remote info associated with the ES */
1759 static void bgp_evpn_es_remote_info_re_eval(struct bgp_evpn_es
*es
)
1761 if (es
->remote_es_evi_cnt
) {
1762 SET_FLAG(es
->flags
, BGP_EVPNES_REMOTE
);
1764 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_REMOTE
)) {
1765 UNSET_FLAG(es
->flags
, BGP_EVPNES_REMOTE
);
1766 bgp_evpn_es_free(es
, __func__
);
1771 /* If ES is present and local it needs to be active/oper-up for
1774 bool bgp_evpn_es_add_l3_ecomm_ok(esi_t
*esi
)
1776 struct bgp_evpn_es
*es
;
1778 if (!esi
|| !bgp_mh_info
->suppress_l3_ecomm_on_inactive_es
)
1781 es
= bgp_evpn_es_find(esi
);
1783 return (!es
|| !(es
->flags
& BGP_EVPNES_LOCAL
)
1784 || bgp_evpn_local_es_is_active(es
));
1787 static bool bgp_evpn_is_valid_local_path(struct bgp_path_info
*pi
)
1789 return (CHECK_FLAG(pi
->flags
, BGP_PATH_VALID
)
1790 && pi
->type
== ZEBRA_ROUTE_BGP
1791 && pi
->sub_type
== BGP_ROUTE_STATIC
);
1794 /* Update all local MAC-IP routes in the VNI routing table associated
1795 * with the ES. When the ES is down the routes are advertised without
1798 static void bgp_evpn_mac_update_on_es_oper_chg(struct bgp_evpn_es
*es
)
1800 struct listnode
*node
;
1801 struct bgp_path_es_info
*es_info
;
1802 struct bgp_path_info
*pi
;
1804 struct bgpevpn
*vpn
;
1806 if (!bgp_mh_info
->suppress_l3_ecomm_on_inactive_es
)
1809 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1810 zlog_debug("update paths linked to es %s on oper chg",
1813 bgp
= bgp_get_evpn();
1814 for (ALL_LIST_ELEMENTS_RO(es
->macip_evi_path_list
, node
, es_info
)) {
1817 if (!bgp_evpn_is_valid_local_path(pi
))
1820 if (!bgp_evpn_is_macip_path(pi
))
1823 vpn
= bgp_evpn_lookup_vni(bgp
, es_info
->vni
);
1827 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
1829 "update path %d %pFX linked to es %s on oper chg",
1830 es_info
->vni
, &pi
->net
->p
, es
->esi_str
);
1832 bgp_evpn_update_type2_route_entry(bgp
, vpn
, pi
->net
, pi
,
1837 static bool bgp_evpn_is_valid_bgp_path(struct bgp_path_info
*pi
)
1839 return (CHECK_FLAG(pi
->flags
, BGP_PATH_VALID
)
1840 && pi
->type
== ZEBRA_ROUTE_BGP
1841 && pi
->sub_type
== BGP_ROUTE_NORMAL
);
1844 /* If an ES is no longer local (or becomes local) we need to re-install
1845 * paths using that ES as destination. This is needed as the criteria
1846 * for best path selection has changed.
1848 static void bgp_evpn_mac_update_on_es_local_chg(struct bgp_evpn_es
*es
,
1851 struct listnode
*node
;
1852 struct bgp_path_es_info
*es_info
;
1853 struct bgp_path_info
*pi
;
1855 struct attr
*attr_new
;
1856 struct attr attr_tmp
;
1858 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1859 zlog_debug("update paths linked to es %s on chg to %s",
1860 es
->esi_str
, is_local
? "local" : "non-local");
1862 for (ALL_LIST_ELEMENTS_RO(es
->macip_global_path_list
, node
, es_info
)) {
1865 /* Consider "valid" remote routes */
1866 if (!bgp_evpn_is_valid_bgp_path(pi
))
1872 tmp_local
= !!(pi
->attr
->es_flags
& ATTR_ES_IS_LOCAL
);
1873 if (tmp_local
== is_local
)
1876 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
1878 "update path %pFX linked to es %s on chg to %s",
1879 &pi
->net
->p
, es
->esi_str
,
1880 is_local
? "local" : "non-local");
1882 attr_tmp
= *pi
->attr
;
1884 attr_tmp
.es_flags
|= ATTR_ES_IS_LOCAL
;
1886 attr_tmp
.es_flags
&= ~ATTR_ES_IS_LOCAL
;
1887 attr_new
= bgp_attr_intern(&attr_tmp
);
1888 bgp_attr_unintern(&pi
->attr
);
1889 pi
->attr
= attr_new
;
1890 bgp_evpn_import_type2_route(pi
, 1);
1894 static void bgp_evpn_local_es_deactivate(struct bgp
*bgp
,
1895 struct bgp_evpn_es
*es
)
1897 struct prefix_evpn p
;
1901 /* Delete and withdraw locally learnt ES route */
1902 build_evpn_type4_prefix(&p
, &es
->esi
, es
->originator_ip
);
1903 ret
= bgp_evpn_type4_route_delete(bgp
, es
, &p
);
1905 flog_err(EC_BGP_EVPN_ROUTE_DELETE
,
1906 "%u failed to delete type-4 route for ESI %s",
1907 bgp
->vrf_id
, es
->esi_str
);
1910 /* withdraw EAD-EVI */
1911 if (!bgp_mh_info
->ead_evi_adv_for_down_links
)
1912 bgp_evpn_local_type1_evi_route_del(bgp
, es
);
1914 /* withdraw EAD-ES */
1915 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_ES_ETH_TAG
,
1916 &es
->esi
, es
->originator_ip
);
1917 ret
= bgp_evpn_type1_es_route_delete(bgp
, es
, &p
);
1919 flog_err(EC_BGP_EVPN_ROUTE_DELETE
,
1920 "%u failed to delete type-1 route for ESI %s",
1921 bgp
->vrf_id
, es
->esi_str
);
1924 bgp_evpn_mac_update_on_es_oper_chg(es
);
1927 /* Process ES link oper-down by withdrawing ES-EAD and ESR */
1928 static void bgp_evpn_local_es_down(struct bgp
*bgp
, struct bgp_evpn_es
*es
)
1932 if (!CHECK_FLAG(es
->flags
, BGP_EVPNES_OPER_UP
))
1935 old_active
= bgp_evpn_local_es_is_active(es
);
1936 UNSET_FLAG(es
->flags
, BGP_EVPNES_OPER_UP
);
1938 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1939 zlog_debug("local es %s down", es
->esi_str
);
1942 bgp_evpn_local_es_deactivate(bgp
, es
);
1945 static void bgp_evpn_local_es_activate(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
1946 bool regen_ead
, bool regen_esr
)
1948 struct prefix_evpn p
;
1951 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1952 zlog_debug("local es %s generate ESR", es
->esi_str
);
1954 build_evpn_type4_prefix(&p
, &es
->esi
, es
->originator_ip
);
1955 if (bgp_evpn_type4_route_update(bgp
, es
, &p
))
1956 flog_err(EC_BGP_EVPN_ROUTE_CREATE
,
1957 "%u: Type4 route creation failure for ESI %s",
1958 bgp
->vrf_id
, es
->esi_str
);
1962 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1963 zlog_debug("local es %s generate EAD", es
->esi_str
);
1964 /* generate EAD-EVI */
1965 bgp_evpn_local_type1_evi_route_add(bgp
, es
);
1967 /* generate EAD-ES */
1968 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_ES_ETH_TAG
, &es
->esi
,
1970 (void)bgp_evpn_type1_route_update(bgp
, es
, NULL
, &p
);
1973 bgp_evpn_mac_update_on_es_oper_chg(es
);
1976 /* Process ES link oper-up by generating ES-EAD and ESR */
1977 static void bgp_evpn_local_es_up(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
1980 bool regen_ead
= false;
1981 bool active
= false;
1983 if (!CHECK_FLAG(es
->flags
, BGP_EVPNES_OPER_UP
)) {
1984 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1985 zlog_debug("local es %s up", es
->esi_str
);
1987 SET_FLAG(es
->flags
, BGP_EVPNES_OPER_UP
);
1992 active
= bgp_evpn_local_es_is_active(es
);
1993 if (active
&& (regen_ead
|| regen_esr
))
1994 bgp_evpn_local_es_activate(bgp
, es
, regen_ead
, regen_esr
);
1997 /* If an ethernet segment is in LACP bypass we cannot advertise
1998 * reachability to it i.e. EAD-per-ES and ESR is not advertised in
2000 * PS: EAD-per-EVI will continue to be advertised
2002 static void bgp_evpn_local_es_bypass_update(struct bgp
*bgp
,
2003 struct bgp_evpn_es
*es
, bool bypass
)
2005 bool old_bypass
= !!(es
->flags
& BGP_EVPNES_BYPASS
);
2011 if (bypass
== old_bypass
)
2014 old_active
= bgp_evpn_local_es_is_active(es
);
2015 old_is_local
= bgp_evpn_is_es_local_and_non_bypass(es
);
2017 SET_FLAG(es
->flags
, BGP_EVPNES_BYPASS
);
2019 UNSET_FLAG(es
->flags
, BGP_EVPNES_BYPASS
);
2021 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2022 zlog_debug("local es %s bypass %s", es
->esi_str
,
2023 bypass
? "set" : "clear");
2025 new_active
= bgp_evpn_local_es_is_active(es
);
2026 if (old_active
!= new_active
) {
2028 bgp_evpn_local_es_activate(bgp
, es
, true, true);
2030 bgp_evpn_local_es_deactivate(bgp
, es
);
2033 is_local
= bgp_evpn_is_es_local_and_non_bypass(es
);
2034 if (old_is_local
!= is_local
)
2035 bgp_evpn_mac_update_on_es_local_chg(es
, is_local
);
2038 static void bgp_evpn_local_es_do_del(struct bgp
*bgp
, struct bgp_evpn_es
*es
)
2040 struct bgp_evpn_es_evi
*es_evi
;
2041 struct listnode
*evi_node
, *evi_next_node
;
2043 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2044 zlog_debug("del local es %s", es
->esi_str
);
2046 /* Delete all local EVPN ES routes from ESI table
2047 * and schedule for processing (to withdraw from peers))
2049 bgp_evpn_es_route_del_all(bgp
, es
);
2051 /* release all local ES EVIs associated with the ES */
2052 for (ALL_LIST_ELEMENTS(es
->es_evi_list
, evi_node
,
2053 evi_next_node
, es_evi
)) {
2054 bgp_evpn_local_es_evi_do_del(es_evi
);
2057 /* Clear local info associated with the ES and free it up if there is
2058 * no remote reference
2060 bgp_evpn_es_local_info_clear(es
, false);
2063 bool bgp_evpn_is_esi_local_and_non_bypass(esi_t
*esi
)
2065 struct bgp_evpn_es
*es
= NULL
;
2067 /* Lookup ESI hash - should exist. */
2068 es
= bgp_evpn_es_find(esi
);
2070 return es
&& bgp_evpn_is_es_local_and_non_bypass(es
);
2073 int bgp_evpn_local_es_del(struct bgp
*bgp
, esi_t
*esi
)
2075 struct bgp_evpn_es
*es
= NULL
;
2077 /* Lookup ESI hash - should exist. */
2078 es
= bgp_evpn_es_find(esi
);
2080 flog_warn(EC_BGP_EVPN_ESI
, "%u: ES missing at local ES DEL",
2085 bgp_evpn_local_es_do_del(bgp
, es
);
2089 /* Handle device to ES id association. Results in the creation of a local
2092 int bgp_evpn_local_es_add(struct bgp
*bgp
, esi_t
*esi
,
2093 struct in_addr originator_ip
, bool oper_up
,
2094 uint16_t df_pref
, bool bypass
)
2096 char buf
[ESI_STR_LEN
];
2097 struct bgp_evpn_es
*es
;
2099 bool regen_esr
= false;
2101 /* create the new es */
2102 es
= bgp_evpn_es_find(esi
);
2104 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_LOCAL
))
2107 es
= bgp_evpn_es_new(bgp
, esi
);
2109 flog_err(EC_BGP_ES_CREATE
,
2110 "%u: Failed to allocate ES entry for ESI %s - at Local ES Add",
2111 bgp
->vrf_id
, esi_to_str(esi
, buf
, sizeof(buf
)));
2116 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2117 zlog_debug("add local es %s orig-ip %pI4 df_pref %u %s",
2118 es
->esi_str
, &originator_ip
, df_pref
,
2119 bypass
? "bypass" : "");
2121 es
->originator_ip
= originator_ip
;
2122 if (df_pref
!= es
->df_pref
) {
2123 es
->df_pref
= df_pref
;
2126 bgp_evpn_es_local_info_set(bgp
, es
);
2128 /* import all remote Type-4 routes in the ES table */
2130 bgp_evpn_type4_remote_routes_import(bgp
, es
,
2131 true /* install */);
2133 /* create and advertise EAD-EVI routes for the ES -
2134 * XXX - till an ES-EVI reference is created there is really nothing to
2137 if (bgp_mh_info
->ead_evi_adv_for_down_links
)
2138 bgp_evpn_local_type1_evi_route_add(bgp
, es
);
2140 bgp_evpn_local_es_bypass_update(bgp
, es
, bypass
);
2142 /* If the ES link is operationally up generate EAD-ES. EAD-EVI
2143 * can be generated even if the link is inactive.
2146 bgp_evpn_local_es_up(bgp
, es
, regen_esr
);
2148 bgp_evpn_local_es_down(bgp
, es
);
2153 static char *bgp_evpn_es_vteps_str(char *vtep_str
, struct bgp_evpn_es
*es
,
2154 uint8_t vtep_str_size
)
2156 char vtep_flag_str
[BGP_EVPN_FLAG_STR_SZ
];
2157 struct listnode
*node
;
2158 struct bgp_evpn_es_vtep
*es_vtep
;
2160 char ip_buf
[INET6_ADDRSTRLEN
];
2163 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
2164 vtep_flag_str
[0] = '\0';
2166 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ESR
)
2167 strlcat(vtep_flag_str
, "E", sizeof(vtep_flag_str
));
2168 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ACTIVE
)
2169 strlcat(vtep_flag_str
, "A", sizeof(vtep_flag_str
));
2171 if (!strlen(vtep_flag_str
))
2172 strlcat(vtep_flag_str
, "-", sizeof(vtep_flag_str
));
2176 strlcat(vtep_str
, ",", vtep_str_size
);
2178 inet_ntop(AF_INET
, &es_vtep
->vtep_ip
, ip_buf
,
2181 strlcat(vtep_str
, "(", vtep_str_size
);
2182 strlcat(vtep_str
, vtep_flag_str
, vtep_str_size
);
2183 strlcat(vtep_str
, ")", vtep_str_size
);
2189 static void bgp_evpn_es_json_vtep_fill(json_object
*json_vteps
,
2190 struct bgp_evpn_es_vtep
*es_vtep
)
2192 json_object
*json_vtep_entry
;
2193 json_object
*json_flags
;
2194 char ip_buf
[INET6_ADDRSTRLEN
];
2196 json_vtep_entry
= json_object_new_object();
2198 json_object_string_add(
2199 json_vtep_entry
, "vtep_ip",
2200 inet_ntop(AF_INET
, &es_vtep
->vtep_ip
, ip_buf
, sizeof(ip_buf
)));
2201 if (es_vtep
->flags
& (BGP_EVPNES_VTEP_ESR
|
2202 BGP_EVPNES_VTEP_ACTIVE
)) {
2203 json_flags
= json_object_new_array();
2204 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ESR
)
2205 json_array_string_add(json_flags
, "esr");
2206 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ACTIVE
)
2207 json_array_string_add(json_flags
, "active");
2208 json_object_object_add(json_vtep_entry
, "flags", json_flags
);
2209 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ESR
) {
2210 json_object_int_add(json_vtep_entry
, "dfPreference",
2212 json_object_int_add(json_vtep_entry
, "dfAlgorithm",
2217 json_object_array_add(json_vteps
,
2221 static void bgp_evpn_es_vteps_show_detail(struct vty
*vty
,
2222 struct bgp_evpn_es
*es
)
2224 char vtep_flag_str
[BGP_EVPN_FLAG_STR_SZ
];
2225 struct listnode
*node
;
2226 struct bgp_evpn_es_vtep
*es_vtep
;
2227 char alg_buf
[EVPN_DF_ALG_STR_LEN
];
2229 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
2230 vtep_flag_str
[0] = '\0';
2231 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ESR
)
2232 strlcat(vtep_flag_str
, "E", sizeof(vtep_flag_str
));
2233 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ACTIVE
)
2234 strlcat(vtep_flag_str
, "A", sizeof(vtep_flag_str
));
2236 if (!strlen(vtep_flag_str
))
2237 strlcat(vtep_flag_str
, "-", sizeof(vtep_flag_str
));
2239 vty_out(vty
, " %pI4 flags: %s", &es_vtep
->vtep_ip
,
2242 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ESR
)
2243 vty_out(vty
, " df_alg: %s df_pref: %u\n",
2244 evpn_es_df_alg2str(es_vtep
->df_alg
, alg_buf
,
2252 static void bgp_evpn_es_show_entry(struct vty
*vty
,
2253 struct bgp_evpn_es
*es
, json_object
*json
)
2255 char buf1
[RD_ADDRSTRLEN
];
2256 struct listnode
*node
;
2257 struct bgp_evpn_es_vtep
*es_vtep
;
2260 json_object
*json_vteps
;
2261 json_object
*json_types
;
2263 json_object_string_add(json
, "esi", es
->esi_str
);
2264 json_object_string_add(json
, "rd",
2265 prefix_rd2str(&es
->prd
, buf1
,
2268 if (es
->flags
& (BGP_EVPNES_LOCAL
| BGP_EVPNES_REMOTE
)) {
2269 json_types
= json_object_new_array();
2270 if (es
->flags
& BGP_EVPNES_LOCAL
)
2271 json_array_string_add(json_types
, "local");
2272 if (es
->flags
& BGP_EVPNES_REMOTE
)
2273 json_array_string_add(json_types
, "remote");
2274 json_object_object_add(json
, "type", json_types
);
2277 if (listcount(es
->es_vtep_list
)) {
2278 json_vteps
= json_object_new_array();
2279 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
,
2281 bgp_evpn_es_json_vtep_fill(json_vteps
, es_vtep
);
2283 json_object_object_add(json
, "vteps", json_vteps
);
2285 json_object_int_add(json
, "vniCount",
2286 listcount(es
->es_evi_list
));
2289 char vtep_str
[ES_VTEP_LIST_STR_SZ
+ BGP_EVPN_VTEPS_FLAG_STR_SZ
];
2292 if (es
->flags
& BGP_EVPNES_BYPASS
)
2293 strlcat(type_str
, "B", sizeof(type_str
));
2294 if (es
->flags
& BGP_EVPNES_LOCAL
)
2295 strlcat(type_str
, "L", sizeof(type_str
));
2296 if (es
->flags
& BGP_EVPNES_REMOTE
)
2297 strlcat(type_str
, "R", sizeof(type_str
));
2298 if (es
->inconsistencies
)
2299 strlcat(type_str
, "I", sizeof(type_str
));
2301 bgp_evpn_es_vteps_str(vtep_str
, es
, sizeof(vtep_str
));
2303 if (es
->flags
& BGP_EVPNES_LOCAL
)
2304 prefix_rd2str(&es
->prd
, buf1
, sizeof(buf1
));
2306 strlcpy(buf1
, "-", sizeof(buf1
));
2308 vty_out(vty
, "%-30s %-5s %-21s %-8d %s\n",
2309 es
->esi_str
, type_str
, buf1
,
2310 listcount(es
->es_evi_list
), vtep_str
);
2314 static void bgp_evpn_es_show_entry_detail(struct vty
*vty
,
2315 struct bgp_evpn_es
*es
, json_object
*json
)
2317 char ip_buf
[INET6_ADDRSTRLEN
];
2320 json_object
*json_flags
;
2321 json_object
*json_incons
;
2322 json_object
*json_vteps
;
2323 struct listnode
*node
;
2324 struct bgp_evpn_es_vtep
*es_vtep
;
2326 /* Add the "brief" info first */
2327 bgp_evpn_es_show_entry(vty
, es
, json
);
2329 & (BGP_EVPNES_OPER_UP
| BGP_EVPNES_ADV_EVI
2330 | BGP_EVPNES_BYPASS
)) {
2331 json_flags
= json_object_new_array();
2332 if (es
->flags
& BGP_EVPNES_OPER_UP
)
2333 json_array_string_add(json_flags
, "up");
2334 if (es
->flags
& BGP_EVPNES_ADV_EVI
)
2335 json_array_string_add(json_flags
,
2337 if (es
->flags
& BGP_EVPNES_BYPASS
)
2338 json_array_string_add(json_flags
, "bypass");
2339 json_object_object_add(json
, "flags", json_flags
);
2341 json_object_string_add(json
, "originator_ip",
2342 inet_ntop(AF_INET
, &es
->originator_ip
,
2343 ip_buf
, sizeof(ip_buf
)));
2344 json_object_int_add(json
, "remoteVniCount",
2345 es
->remote_es_evi_cnt
);
2346 json_object_int_add(json
, "vrfCount",
2347 listcount(es
->es_vrf_list
));
2348 json_object_int_add(json
, "macipPathCount",
2349 listcount(es
->macip_evi_path_list
));
2350 json_object_int_add(json
, "macipGlobalPathCount",
2351 listcount(es
->macip_global_path_list
));
2352 json_object_int_add(json
, "inconsistentVniVtepCount",
2353 es
->incons_evi_vtep_cnt
);
2354 if (listcount(es
->es_vtep_list
)) {
2355 json_vteps
= json_object_new_array();
2356 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
,
2358 bgp_evpn_es_json_vtep_fill(json_vteps
, es_vtep
);
2360 json_object_object_add(json
, "vteps", json_vteps
);
2362 if (es
->inconsistencies
) {
2363 json_incons
= json_object_new_array();
2364 if (es
->inconsistencies
& BGP_EVPNES_INCONS_VTEP_LIST
)
2365 json_array_string_add(json_incons
,
2366 "vni-vtep-mismatch");
2367 json_object_object_add(json
, "inconsistencies",
2371 char incons_str
[BGP_EVPNES_INCONS_STR_SZ
];
2373 char buf1
[RD_ADDRSTRLEN
];
2376 if (es
->flags
& BGP_EVPNES_LOCAL
)
2377 strlcat(type_str
, "L", sizeof(type_str
));
2378 if (es
->flags
& BGP_EVPNES_REMOTE
)
2379 strlcat(type_str
, "R", sizeof(type_str
));
2381 if (es
->flags
& BGP_EVPNES_LOCAL
)
2382 prefix_rd2str(&es
->prd
, buf1
, sizeof(buf1
));
2384 strlcpy(buf1
, "-", sizeof(buf1
));
2386 vty_out(vty
, "ESI: %s\n", es
->esi_str
);
2387 vty_out(vty
, " Type: %s\n", type_str
);
2388 vty_out(vty
, " RD: %s\n", buf1
);
2389 vty_out(vty
, " Originator-IP: %pI4\n", &es
->originator_ip
);
2390 if (es
->flags
& BGP_EVPNES_LOCAL
)
2391 vty_out(vty
, " Local ES DF preference: %u\n",
2393 if (es
->flags
& BGP_EVPNES_BYPASS
)
2394 vty_out(vty
, " LACP bypass: on\n");
2395 vty_out(vty
, " VNI Count: %d\n", listcount(es
->es_evi_list
));
2396 vty_out(vty
, " Remote VNI Count: %d\n",
2397 es
->remote_es_evi_cnt
);
2398 vty_out(vty
, " VRF Count: %d\n", listcount(es
->es_vrf_list
));
2399 vty_out(vty
, " MACIP EVI Path Count: %d\n",
2400 listcount(es
->macip_evi_path_list
));
2401 vty_out(vty
, " MACIP Global Path Count: %d\n",
2402 listcount(es
->macip_global_path_list
));
2403 vty_out(vty
, " Inconsistent VNI VTEP Count: %d\n",
2404 es
->incons_evi_vtep_cnt
);
2405 if (es
->inconsistencies
) {
2406 incons_str
[0] = '\0';
2407 if (es
->inconsistencies
& BGP_EVPNES_INCONS_VTEP_LIST
)
2408 strlcat(incons_str
, "vni-vtep-mismatch",
2409 sizeof(incons_str
));
2411 strlcpy(incons_str
, "-", sizeof(incons_str
));
2413 vty_out(vty
, " Inconsistencies: %s\n",
2415 if (listcount(es
->es_vtep_list
)) {
2416 vty_out(vty
, " VTEPs:\n");
2417 bgp_evpn_es_vteps_show_detail(vty
, es
);
2423 /* Display all ESs */
2424 void bgp_evpn_es_show(struct vty
*vty
, bool uj
, bool detail
)
2426 struct bgp_evpn_es
*es
;
2427 json_object
*json_array
= NULL
;
2428 json_object
*json
= NULL
;
2431 /* create an array of ESs */
2432 json_array
= json_object_new_array();
2436 "ES Flags: B - bypass, L local, R remote, I inconsistent\n");
2438 "VTEP Flags: E ESR/Type-4, A active nexthop\n");
2440 "%-30s %-5s %-21s %-8s %s\n",
2441 "ESI", "Flags", "RD", "#VNIs", "VTEPs");
2445 RB_FOREACH(es
, bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
) {
2447 /* create a separate json object for each ES */
2448 json
= json_object_new_object();
2450 bgp_evpn_es_show_entry_detail(vty
, es
, json
);
2452 bgp_evpn_es_show_entry(vty
, es
, json
);
2453 /* add ES to the json array */
2455 json_object_array_add(json_array
, json
);
2458 /* print the array of json-ESs */
2460 vty_out(vty
, "%s\n", json_object_to_json_string_ext(
2461 json_array
, JSON_C_TO_STRING_PRETTY
));
2462 json_object_free(json_array
);
2466 /* Display specific ES */
2467 void bgp_evpn_es_show_esi(struct vty
*vty
, esi_t
*esi
, bool uj
)
2469 struct bgp_evpn_es
*es
;
2470 json_object
*json
= NULL
;
2473 json
= json_object_new_object();
2475 es
= bgp_evpn_es_find(esi
);
2477 bgp_evpn_es_show_entry_detail(vty
, es
, json
);
2480 vty_out(vty
, "ESI not found\n");
2484 vty_out(vty
, "%s\n", json_object_to_json_string_ext(
2485 json
, JSON_C_TO_STRING_PRETTY
));
2486 json_object_free(json
);
2490 /*****************************************************************************/
2491 /* Ethernet Segment to VRF association -
2492 * 1. Each ES-EVI entry is associated with a tenant VRF. This associaton
2493 * triggers the creation of an ES-VRF entry.
2494 * 2. The ES-VRF entry is maintained for the purpose of L3-NHG creation
2495 * 3. Type-2/MAC-IP routes are imported into a tenant VRF and programmed as
2496 * a /32 or host route entry in the dataplane. If the destination of
2497 * the host route is a remote-ES the route is programmed with the
2498 * corresponding (keyed in by {vrf,ES-id}) L3-NHG.
2499 * 4. The reason for this indirection (route->L3-NHG, L3-NHG->list-of-VTEPs)
2500 * is to avoid route updates to the dplane when a remote-ES link flaps i.e.
2501 * instead of updating all the dependent routes the NHG's contents are updated.
2502 * This reduces the amount of datplane updates (nhg updates vs. route updates)
2503 * allowing for a faster failover.
2505 * XXX - can the L3 SVI index change without change in vpn->bgp_vrf
2506 * association? If yes we need to handle that by updating all the L3 NHGs
2509 /******************************** L3 NHG management *************************/
2510 static void bgp_evpn_l3nhg_zebra_add_v4_or_v6(struct bgp_evpn_es_vrf
*es_vrf
,
2513 uint32_t nhg_id
= v4_nhg
? es_vrf
->nhg_id
: es_vrf
->v6_nhg_id
;
2514 struct bgp_evpn_es
*es
= es_vrf
->es
;
2515 struct listnode
*node
;
2516 struct bgp_evpn_es_vtep
*es_vtep
;
2518 struct zapi_nexthop
*api_nh
;
2519 struct zapi_nhg api_nhg
= {};
2521 /* Skip installation of L3-NHG if host routes used */
2525 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2526 zlog_debug("es %s vrf %u %s nhg %u to zebra", es
->esi_str
,
2527 es_vrf
->bgp_vrf
->vrf_id
,
2528 v4_nhg
? "v4_nhg" : "v6_nhg", nhg_id
);
2530 frrtrace(4, frr_bgp
, evpn_mh_nhg_zsend
, true, v4_nhg
, nhg_id
, es_vrf
);
2532 /* only the gateway ip changes for each NH. rest of the params
2535 memset(&nh
, 0, sizeof(nh
));
2536 nh
.vrf_id
= es_vrf
->bgp_vrf
->vrf_id
;
2537 nh
.flags
= NEXTHOP_FLAG_ONLINK
;
2538 nh
.ifindex
= es_vrf
->bgp_vrf
->l3vni_svi_ifindex
;
2541 v4_nhg
? NEXTHOP_TYPE_IPV4_IFINDEX
: NEXTHOP_TYPE_IPV6_IFINDEX
;
2543 api_nhg
.id
= nhg_id
;
2544 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
2545 if (!CHECK_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
))
2548 /* Don't overrun the zapi buffer. */
2549 if (api_nhg
.nexthop_num
== MULTIPATH_NUM
)
2552 /* overwrite the gw */
2554 nh
.gate
.ipv4
= es_vtep
->vtep_ip
;
2556 ipv4_to_ipv4_mapped_ipv6(&nh
.gate
.ipv6
,
2559 /* convert to zapi format */
2560 api_nh
= &api_nhg
.nexthops
[api_nhg
.nexthop_num
];
2561 zapi_nexthop_from_nexthop(api_nh
, &nh
);
2563 ++api_nhg
.nexthop_num
;
2564 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2565 zlog_debug("nhg %u vtep %pI4 l3-svi %d", api_nhg
.id
,
2567 es_vrf
->bgp_vrf
->l3vni_svi_ifindex
);
2569 frrtrace(3, frr_bgp
, evpn_mh_nh_zsend
, nhg_id
, es_vtep
, es_vrf
);
2572 if (!api_nhg
.nexthop_num
)
2575 zclient_nhg_send(zclient
, ZEBRA_NHG_ADD
, &api_nhg
);
2578 static bool bgp_evpn_l3nhg_zebra_ok(struct bgp_evpn_es_vrf
*es_vrf
)
2580 if (!bgp_mh_info
->host_routes_use_l3nhg
&& !bgp_mh_info
->install_l3nhg
)
2584 if (!zclient
|| zclient
->sock
< 0)
2590 static void bgp_evpn_l3nhg_zebra_add(struct bgp_evpn_es_vrf
*es_vrf
)
2592 if (!bgp_evpn_l3nhg_zebra_ok(es_vrf
))
2595 bgp_evpn_l3nhg_zebra_add_v4_or_v6(es_vrf
, true /*v4_nhg*/);
2596 bgp_evpn_l3nhg_zebra_add_v4_or_v6(es_vrf
, false /*v4_nhg*/);
2599 static void bgp_evpn_l3nhg_zebra_del_v4_or_v6(struct bgp_evpn_es_vrf
*es_vrf
,
2602 struct zapi_nhg api_nhg
= {};
2604 api_nhg
.id
= v4_nhg
? es_vrf
->nhg_id
: es_vrf
->v6_nhg_id
;
2606 /* Skip installation of L3-NHG if host routes used */
2610 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2611 zlog_debug("es %s vrf %u %s nhg %u to zebra",
2612 es_vrf
->es
->esi_str
, es_vrf
->bgp_vrf
->vrf_id
,
2613 v4_nhg
? "v4_nhg" : "v6_nhg", api_nhg
.id
);
2616 frrtrace(4, frr_bgp
, evpn_mh_nhg_zsend
, false, v4_nhg
, api_nhg
.id
,
2619 zclient_nhg_send(zclient
, ZEBRA_NHG_DEL
, &api_nhg
);
2622 static void bgp_evpn_l3nhg_zebra_del(struct bgp_evpn_es_vrf
*es_vrf
)
2624 if (!bgp_evpn_l3nhg_zebra_ok(es_vrf
))
2627 bgp_evpn_l3nhg_zebra_del_v4_or_v6(es_vrf
, true /*v4_nhg*/);
2628 bgp_evpn_l3nhg_zebra_del_v4_or_v6(es_vrf
, false /*v4_nhg*/);
2631 static void bgp_evpn_l3nhg_deactivate(struct bgp_evpn_es_vrf
*es_vrf
)
2633 if (!(es_vrf
->flags
& BGP_EVPNES_VRF_NHG_ACTIVE
))
2636 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2637 zlog_debug("es %s vrf %u nhg %u de-activate",
2638 es_vrf
->es
->esi_str
, es_vrf
->bgp_vrf
->vrf_id
,
2640 bgp_evpn_l3nhg_zebra_del(es_vrf
);
2641 es_vrf
->flags
&= ~BGP_EVPNES_VRF_NHG_ACTIVE
;
2642 /* MAC-IPs can now be installed via the L3NHG */
2643 bgp_evpn_es_path_update_on_es_vrf_chg(es_vrf
, "l3nhg-deactivate");
2646 static void bgp_evpn_l3nhg_activate(struct bgp_evpn_es_vrf
*es_vrf
, bool update
)
2648 if (!bgp_evpn_es_get_active_vtep_cnt(es_vrf
->es
)) {
2649 bgp_evpn_l3nhg_deactivate(es_vrf
);
2653 if (es_vrf
->flags
& BGP_EVPNES_VRF_NHG_ACTIVE
) {
2657 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2658 zlog_debug("es %s vrf %u nhg %u activate",
2659 es_vrf
->es
->esi_str
, es_vrf
->bgp_vrf
->vrf_id
,
2661 es_vrf
->flags
|= BGP_EVPNES_VRF_NHG_ACTIVE
;
2662 /* MAC-IPs can now be installed via the L3NHG */
2663 bgp_evpn_es_path_update_on_es_vrf_chg(es_vrf
, "l3nhg_activate");
2666 bgp_evpn_l3nhg_zebra_add(es_vrf
);
2669 /* when a VTEP is activated or de-activated against an ES associated
2670 * VRFs' NHG needs to be updated
2672 static void bgp_evpn_l3nhg_update_on_vtep_chg(struct bgp_evpn_es
*es
)
2674 struct bgp_evpn_es_vrf
*es_vrf
;
2675 struct listnode
*es_vrf_node
;
2677 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2678 zlog_debug("es %s nhg update on vtep chg", es
->esi_str
);
2680 for (ALL_LIST_ELEMENTS_RO(es
->es_vrf_list
, es_vrf_node
, es_vrf
))
2681 bgp_evpn_l3nhg_activate(es_vrf
, true /* update */);
2684 /* compare ES-IDs for the ES-VRF RB tree maintained per-VRF */
2685 static int bgp_es_vrf_rb_cmp(const struct bgp_evpn_es_vrf
*es_vrf1
,
2686 const struct bgp_evpn_es_vrf
*es_vrf2
)
2688 return memcmp(&es_vrf1
->es
->esi
, &es_vrf2
->es
->esi
, ESI_BYTES
);
2690 RB_GENERATE(bgp_es_vrf_rb_head
, bgp_evpn_es_vrf
, rb_node
, bgp_es_vrf_rb_cmp
);
2692 /* Initialize the ES tables maintained per-tenant vrf */
2693 void bgp_evpn_vrf_es_init(struct bgp
*bgp_vrf
)
2695 /* Initialize the ES-VRF RB tree */
2696 RB_INIT(bgp_es_vrf_rb_head
, &bgp_vrf
->es_vrf_rb_tree
);
2699 /* find the ES-VRF in the per-VRF RB tree */
2700 static struct bgp_evpn_es_vrf
*bgp_evpn_es_vrf_find(struct bgp_evpn_es
*es
,
2701 struct bgp
*bgp_vrf
)
2703 struct bgp_evpn_es_vrf es_vrf
;
2707 return RB_FIND(bgp_es_vrf_rb_head
, &bgp_vrf
->es_vrf_rb_tree
, &es_vrf
);
2710 /* allocate a new ES-VRF and setup L3NHG for it */
2711 static struct bgp_evpn_es_vrf
*bgp_evpn_es_vrf_create(struct bgp_evpn_es
*es
,
2712 struct bgp
*bgp_vrf
)
2714 struct bgp_evpn_es_vrf
*es_vrf
;
2716 es_vrf
= XCALLOC(MTYPE_BGP_EVPN_ES_VRF
, sizeof(*es_vrf
));
2719 es_vrf
->bgp_vrf
= bgp_vrf
;
2721 /* insert into the VRF-ESI rb tree */
2722 if (RB_INSERT(bgp_es_vrf_rb_head
, &bgp_vrf
->es_vrf_rb_tree
, es_vrf
)) {
2723 XFREE(MTYPE_BGP_EVPN_ES_VRF
, es_vrf
);
2727 /* add to the ES's VRF list */
2728 listnode_init(&es_vrf
->es_listnode
, es_vrf
);
2729 listnode_add(es
->es_vrf_list
, &es_vrf
->es_listnode
);
2731 /* setup the L3 NHG id for the ES */
2732 es_vrf
->nhg_id
= bgp_l3nhg_id_alloc();
2733 es_vrf
->v6_nhg_id
= bgp_l3nhg_id_alloc();
2735 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2736 zlog_debug("es %s vrf %u nhg %u v6_nhg %d create", es
->esi_str
,
2737 bgp_vrf
->vrf_id
, es_vrf
->nhg_id
, es_vrf
->v6_nhg_id
);
2738 bgp_evpn_l3nhg_activate(es_vrf
, false /* update */);
2740 /* update paths in the VRF that may already be associated with
2741 * this destination ES
2743 bgp_evpn_es_path_update_on_es_vrf_chg(es_vrf
, "es-vrf-create");
2748 /* remove the L3-NHG associated with the ES-VRF and free it */
2749 static void bgp_evpn_es_vrf_delete(struct bgp_evpn_es_vrf
*es_vrf
)
2751 struct bgp_evpn_es
*es
= es_vrf
->es
;
2752 struct bgp
*bgp_vrf
= es_vrf
->bgp_vrf
;
2754 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2755 zlog_debug("es %s vrf %u nhg %u delete", es
->esi_str
,
2756 bgp_vrf
->vrf_id
, es_vrf
->nhg_id
);
2758 /* Remove the NHG resources */
2759 bgp_evpn_l3nhg_deactivate(es_vrf
);
2761 bgp_l3nhg_id_free(es_vrf
->nhg_id
);
2763 if (es_vrf
->v6_nhg_id
)
2764 bgp_l3nhg_id_free(es_vrf
->v6_nhg_id
);
2765 es_vrf
->v6_nhg_id
= 0;
2767 /* remove from the ES's VRF list */
2768 list_delete_node(es
->es_vrf_list
, &es_vrf
->es_listnode
);
2770 /* remove from the VRF-ESI rb tree */
2771 RB_REMOVE(bgp_es_vrf_rb_head
, &bgp_vrf
->es_vrf_rb_tree
, es_vrf
);
2773 /* update paths in the VRF that may already be associated with
2774 * this destination ES
2776 bgp_evpn_es_path_update_on_es_vrf_chg(es_vrf
, "es-vrf-delete");
2778 XFREE(MTYPE_BGP_EVPN_ES_VRF
, es_vrf
);
2781 /* deref and delete if there are no references */
2782 void bgp_evpn_es_vrf_deref(struct bgp_evpn_es_evi
*es_evi
)
2784 struct bgp_evpn_es_vrf
*es_vrf
= es_evi
->es_vrf
;
2789 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2790 zlog_debug("es-evi %s vni %u vrf %u de-ref",
2791 es_evi
->es
->esi_str
, es_evi
->vpn
->vni
,
2792 es_vrf
->bgp_vrf
->vrf_id
);
2794 es_evi
->es_vrf
= NULL
;
2795 if (es_vrf
->ref_cnt
)
2798 if (!es_vrf
->ref_cnt
)
2799 bgp_evpn_es_vrf_delete(es_vrf
);
2802 /* find or create and reference */
2803 void bgp_evpn_es_vrf_ref(struct bgp_evpn_es_evi
*es_evi
, struct bgp
*bgp_vrf
)
2805 struct bgp_evpn_es
*es
= es_evi
->es
;
2806 struct bgp_evpn_es_vrf
*es_vrf
= es_evi
->es_vrf
;
2807 struct bgp
*old_bgp_vrf
= NULL
;
2810 old_bgp_vrf
= es_vrf
->bgp_vrf
;
2812 if (old_bgp_vrf
== bgp_vrf
)
2815 /* deref the old ES-VRF */
2816 bgp_evpn_es_vrf_deref(es_evi
);
2821 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2822 zlog_debug("es-evi %s vni %u vrf %u ref", es_evi
->es
->esi_str
,
2823 es_evi
->vpn
->vni
, bgp_vrf
->vrf_id
);
2825 /* find-create the new ES-VRF */
2826 es_vrf
= bgp_evpn_es_vrf_find(es
, bgp_vrf
);
2828 es_vrf
= bgp_evpn_es_vrf_create(es
, bgp_vrf
);
2832 es_evi
->es_vrf
= es_vrf
;
2836 /* When the L2-VNI is associated with a L3-VNI/VRF update all the
2837 * associated ES-EVI entries
2839 void bgp_evpn_es_evi_vrf_deref(struct bgpevpn
*vpn
)
2841 struct bgp_evpn_es_evi
*es_evi
;
2843 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2844 zlog_debug("es-vrf de-ref for vni %u", vpn
->vni
);
2846 RB_FOREACH (es_evi
, bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
)
2847 bgp_evpn_es_vrf_deref(es_evi
);
2849 void bgp_evpn_es_evi_vrf_ref(struct bgpevpn
*vpn
)
2851 struct bgp_evpn_es_evi
*es_evi
;
2853 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2854 zlog_debug("es-vrf ref for vni %u", vpn
->vni
);
2856 RB_FOREACH (es_evi
, bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
)
2857 bgp_evpn_es_vrf_ref(es_evi
, vpn
->bgp_vrf
);
2860 /* 1. If ES-VRF is not present install the host route with the exploded/flat
2862 * 2. If ES-VRF is present -
2863 * - if L3NHG has not been activated for the ES-VRF (this could be because
2864 * all the PEs attached to the VRF are down) do not install the route
2866 * - if L3NHG has been activated install the route via that L3NHG
2868 void bgp_evpn_es_vrf_use_nhg(struct bgp
*bgp_vrf
, esi_t
*esi
, bool *use_l3nhg
,
2869 bool *is_l3nhg_active
,
2870 struct bgp_evpn_es_vrf
**es_vrf_p
)
2872 struct bgp_evpn_es
*es
;
2873 struct bgp_evpn_es_vrf
*es_vrf
;
2875 if (!bgp_mh_info
->host_routes_use_l3nhg
)
2878 es
= bgp_evpn_es_find(esi
);
2882 es_vrf
= bgp_evpn_es_vrf_find(es
, bgp_vrf
);
2887 if (es_vrf
->flags
& BGP_EVPNES_VRF_NHG_ACTIVE
)
2888 *is_l3nhg_active
= true;
2893 /* returns false if legacy-exploded mp needs to be used for route install */
2894 bool bgp_evpn_path_es_use_nhg(struct bgp
*bgp_vrf
, struct bgp_path_info
*pi
,
2898 struct bgp_evpn_es_vrf
*es_vrf
= NULL
;
2899 struct bgp_path_info
*parent_pi
;
2900 struct bgp_node
*rn
;
2901 struct prefix_evpn
*evp
;
2902 struct bgp_path_info
*mpinfo
;
2903 bool use_l3nhg
= false;
2904 bool is_l3nhg_active
= false;
2908 /* we don't support NHG for routes leaked from another VRF yet */
2909 if (pi
->extra
&& pi
->extra
->bgp_orig
)
2912 parent_pi
= get_route_parent_evpn(pi
);
2916 rn
= parent_pi
->net
;
2920 evp
= (struct prefix_evpn
*)&rn
->p
;
2921 if (evp
->prefix
.route_type
!= BGP_EVPN_MAC_IP_ROUTE
)
2924 /* non-es path, use legacy-exploded multipath */
2925 esi
= bgp_evpn_attr_get_esi(parent_pi
->attr
);
2926 if (!memcmp(esi
, zero_esi
, sizeof(*esi
)))
2929 bgp_evpn_es_vrf_use_nhg(bgp_vrf
, esi
, &use_l3nhg
, &is_l3nhg_active
,
2932 /* L3NHG support is disabled, use legacy-exploded multipath */
2936 /* if the NHG has not been installed we cannot install the route yet,
2937 * return a 0-NHG to indicate that
2939 if (!is_l3nhg_active
)
2942 /* this needs to be set the v6NHG if v6route */
2943 if (is_evpn_prefix_ipaddr_v6(evp
))
2944 *nhg_p
= es_vrf
->v6_nhg_id
;
2946 *nhg_p
= es_vrf
->nhg_id
;
2948 for (mpinfo
= bgp_path_info_mpath_next(pi
); mpinfo
;
2949 mpinfo
= bgp_path_info_mpath_next(mpinfo
)) {
2950 /* if any of the paths have a different ESI we can't use
2951 * the NHG associated with the ES. fallback to legacy-exploded
2954 if (memcmp(esi
, bgp_evpn_attr_get_esi(mpinfo
->attr
),
2962 static void bgp_evpn_es_vrf_show_entry(struct vty
*vty
,
2963 struct bgp_evpn_es_vrf
*es_vrf
,
2966 struct bgp_evpn_es
*es
= es_vrf
->es
;
2967 struct bgp
*bgp_vrf
= es_vrf
->bgp_vrf
;
2970 json_object
*json_types
;
2972 json_object_string_add(json
, "esi", es
->esi_str
);
2973 json_object_string_add(json
, "vrf", bgp_vrf
->name
);
2975 if (es_vrf
->flags
& (BGP_EVPNES_VRF_NHG_ACTIVE
)) {
2976 json_types
= json_object_new_array();
2977 if (es_vrf
->flags
& BGP_EVPNES_VRF_NHG_ACTIVE
)
2978 json_array_string_add(json_types
, "active");
2979 json_object_object_add(json
, "flags", json_types
);
2982 json_object_int_add(json
, "ipv4NHG", es_vrf
->nhg_id
);
2983 json_object_int_add(json
, "ipv6NHG", es_vrf
->v6_nhg_id
);
2984 json_object_int_add(json
, "refCount", es_vrf
->ref_cnt
);
2988 flags_str
[0] = '\0';
2989 if (es_vrf
->flags
& BGP_EVPNES_VRF_NHG_ACTIVE
)
2990 strlcat(flags_str
, "A", sizeof(flags_str
));
2992 vty_out(vty
, "%-30s %-15s %-5s %-8u %-8u %u\n", es
->esi_str
,
2993 bgp_vrf
->name
, flags_str
, es_vrf
->nhg_id
,
2994 es_vrf
->v6_nhg_id
, es_vrf
->ref_cnt
);
2998 static void bgp_evpn_es_vrf_show_es(struct vty
*vty
, json_object
*json_array
,
2999 struct bgp_evpn_es
*es
)
3001 json_object
*json
= NULL
;
3002 struct listnode
*es_vrf_node
;
3003 struct bgp_evpn_es_vrf
*es_vrf
;
3005 for (ALL_LIST_ELEMENTS_RO(es
->es_vrf_list
, es_vrf_node
, es_vrf
)) {
3006 /* create a separate json object for each ES-VRF */
3008 json
= json_object_new_object();
3009 bgp_evpn_es_vrf_show_entry(vty
, es_vrf
, json
);
3010 /* add ES-VRF to the json array */
3012 json_object_array_add(json_array
, json
);
3016 /* Display all ES VRFs */
3017 void bgp_evpn_es_vrf_show(struct vty
*vty
, bool uj
, struct bgp_evpn_es
*es
)
3019 json_object
*json_array
= NULL
;
3022 /* create an array of ESs */
3023 json_array
= json_object_new_array();
3025 vty_out(vty
, "ES-VRF Flags: A Active\n");
3026 vty_out(vty
, "%-30s %-15s %-5s %-8s %-8s %s\n", "ESI", "VRF",
3027 "Flags", "IPv4-NHG", "IPv6-NHG", "Ref");
3031 bgp_evpn_es_vrf_show_es(vty
, json_array
, es
);
3033 RB_FOREACH (es
, bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
)
3034 bgp_evpn_es_vrf_show_es(vty
, json_array
, es
);
3037 /* print the array of json-ESs */
3039 vty_out(vty
, "%s\n",
3040 json_object_to_json_string_ext(
3041 json_array
, JSON_C_TO_STRING_PRETTY
));
3042 json_object_free(json_array
);
3046 /* Display specific ES VRF */
3047 void bgp_evpn_es_vrf_show_esi(struct vty
*vty
, esi_t
*esi
, bool uj
)
3049 struct bgp_evpn_es
*es
;
3051 es
= bgp_evpn_es_find(esi
);
3053 bgp_evpn_es_vrf_show(vty
, uj
, es
);
3056 vty_out(vty
, "ESI not found\n");
3060 /*****************************************************************************/
3061 /* Ethernet Segment to EVI association -
3062 * 1. The ES-EVI entry is maintained as a RB tree per L2-VNI
3063 * (bgpevpn->es_evi_rb_tree).
3064 * 2. Each local ES-EVI entry is rxed from zebra and then used by BGP to
3065 * advertises an EAD-EVI (Type-1 EVPN) route
3066 * 3. The remote ES-EVI is created when a bgp_evpn_es_evi_vtep references
3070 /* A list of remote VTEPs is maintained for each ES-EVI. This list includes -
3071 * 1. VTEPs for which we have imported the EAD-per-ES Type1 route
3072 * 2. VTEPs for which we have imported the EAD-per-EVI Type1 route
3073 * VTEPs for which both routes have been rxed are activated. Activation
3074 * creates a NHG in the parent ES.
3076 static int bgp_evpn_es_evi_vtep_cmp(void *p1
, void *p2
)
3078 const struct bgp_evpn_es_evi_vtep
*evi_vtep1
= p1
;
3079 const struct bgp_evpn_es_evi_vtep
*evi_vtep2
= p2
;
3081 return evi_vtep1
->vtep_ip
.s_addr
- evi_vtep2
->vtep_ip
.s_addr
;
3084 static struct bgp_evpn_es_evi_vtep
*bgp_evpn_es_evi_vtep_new(
3085 struct bgp_evpn_es_evi
*es_evi
, struct in_addr vtep_ip
)
3087 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
3089 evi_vtep
= XCALLOC(MTYPE_BGP_EVPN_ES_EVI_VTEP
, sizeof(*evi_vtep
));
3091 evi_vtep
->es_evi
= es_evi
;
3092 evi_vtep
->vtep_ip
.s_addr
= vtep_ip
.s_addr
;
3093 listnode_init(&evi_vtep
->es_evi_listnode
, evi_vtep
);
3094 listnode_add_sort(es_evi
->es_evi_vtep_list
, &evi_vtep
->es_evi_listnode
);
3099 static void bgp_evpn_es_evi_vtep_free(struct bgp_evpn_es_evi_vtep
*evi_vtep
)
3101 struct bgp_evpn_es_evi
*es_evi
= evi_vtep
->es_evi
;
3103 if (evi_vtep
->flags
& (BGP_EVPN_EVI_VTEP_EAD
))
3104 /* as long as there is some reference we can't free it */
3107 list_delete_node(es_evi
->es_evi_vtep_list
, &evi_vtep
->es_evi_listnode
);
3108 XFREE(MTYPE_BGP_EVPN_ES_EVI_VTEP
, evi_vtep
);
3111 /* check if VTEP is already part of the list */
3112 static struct bgp_evpn_es_evi_vtep
*bgp_evpn_es_evi_vtep_find(
3113 struct bgp_evpn_es_evi
*es_evi
, struct in_addr vtep_ip
)
3115 struct listnode
*node
= NULL
;
3116 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
3118 for (ALL_LIST_ELEMENTS_RO(es_evi
->es_evi_vtep_list
, node
, evi_vtep
)) {
3119 if (evi_vtep
->vtep_ip
.s_addr
== vtep_ip
.s_addr
)
3125 /* A VTEP can be added as "active" attach to an ES if EAD-per-ES and
3126 * EAD-per-EVI routes are rxed from it.
3128 static void bgp_evpn_es_evi_vtep_re_eval_active(struct bgp
*bgp
,
3129 struct bgp_evpn_es_evi_vtep
*evi_vtep
)
3133 uint32_t ead_activity_flags
;
3135 old_active
= CHECK_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
);
3137 if (bgp_mh_info
->ead_evi_rx
)
3138 /* Both EAD-per-ES and EAD-per-EVI routes must be rxed from a PE
3139 * before it can be activated.
3141 ead_activity_flags
= BGP_EVPN_EVI_VTEP_EAD
;
3143 /* EAD-per-ES is sufficent to activate the PE */
3144 ead_activity_flags
= BGP_EVPN_EVI_VTEP_EAD_PER_ES
;
3146 if ((evi_vtep
->flags
& ead_activity_flags
) == ead_activity_flags
)
3147 SET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
);
3149 UNSET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
);
3151 new_active
= CHECK_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
);
3153 if (old_active
== new_active
)
3156 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3157 zlog_debug("es %s evi %u vtep %pI4 %s",
3158 evi_vtep
->es_evi
->es
->esi_str
,
3159 evi_vtep
->es_evi
->vpn
->vni
, &evi_vtep
->vtep_ip
,
3160 new_active
? "active" : "inactive");
3162 /* add VTEP to parent es */
3164 struct bgp_evpn_es_vtep
*es_vtep
;
3166 es_vtep
= bgp_evpn_es_vtep_add(bgp
, evi_vtep
->es_evi
->es
,
3167 evi_vtep
->vtep_ip
, false /*esr*/,
3169 evi_vtep
->es_vtep
= es_vtep
;
3171 if (evi_vtep
->es_vtep
) {
3172 bgp_evpn_es_vtep_do_del(bgp
, evi_vtep
->es_vtep
,
3174 evi_vtep
->es_vtep
= NULL
;
3177 /* queue up the parent es for background consistency checks */
3178 bgp_evpn_es_cons_checks_pend_add(evi_vtep
->es_evi
->es
);
3181 static void bgp_evpn_es_evi_vtep_add(struct bgp
*bgp
,
3182 struct bgp_evpn_es_evi
*es_evi
, struct in_addr vtep_ip
,
3185 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
3187 evi_vtep
= bgp_evpn_es_evi_vtep_find(es_evi
, vtep_ip
);
3190 evi_vtep
= bgp_evpn_es_evi_vtep_new(es_evi
, vtep_ip
);
3192 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3193 zlog_debug("add es %s evi %u vtep %pI4 %s",
3194 evi_vtep
->es_evi
->es
->esi_str
,
3195 evi_vtep
->es_evi
->vpn
->vni
, &evi_vtep
->vtep_ip
,
3196 ead_es
? "ead_es" : "ead_evi");
3199 SET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_EAD_PER_ES
);
3201 SET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_EAD_PER_EVI
);
3203 bgp_evpn_es_evi_vtep_re_eval_active(bgp
, evi_vtep
);
3206 static void bgp_evpn_es_evi_vtep_del(struct bgp
*bgp
,
3207 struct bgp_evpn_es_evi
*es_evi
, struct in_addr vtep_ip
,
3210 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
3212 evi_vtep
= bgp_evpn_es_evi_vtep_find(es_evi
, vtep_ip
);
3216 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3217 zlog_debug("del es %s evi %u vtep %pI4 %s",
3218 evi_vtep
->es_evi
->es
->esi_str
,
3219 evi_vtep
->es_evi
->vpn
->vni
, &evi_vtep
->vtep_ip
,
3220 ead_es
? "ead_es" : "ead_evi");
3223 UNSET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_EAD_PER_ES
);
3225 UNSET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_EAD_PER_EVI
);
3227 bgp_evpn_es_evi_vtep_re_eval_active(bgp
, evi_vtep
);
3228 bgp_evpn_es_evi_vtep_free(evi_vtep
);
3231 /* compare ES-IDs for the ES-EVI RB tree maintained per-VNI */
3232 static int bgp_es_evi_rb_cmp(const struct bgp_evpn_es_evi
*es_evi1
,
3233 const struct bgp_evpn_es_evi
*es_evi2
)
3235 return memcmp(&es_evi1
->es
->esi
, &es_evi2
->es
->esi
, ESI_BYTES
);
3237 RB_GENERATE(bgp_es_evi_rb_head
, bgp_evpn_es_evi
, rb_node
, bgp_es_evi_rb_cmp
);
3239 /* find the ES-EVI in the per-L2-VNI RB tree */
3240 static struct bgp_evpn_es_evi
*bgp_evpn_es_evi_find(struct bgp_evpn_es
*es
,
3241 struct bgpevpn
*vpn
)
3243 struct bgp_evpn_es_evi es_evi
;
3247 return RB_FIND(bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
, &es_evi
);
3250 /* allocate a new ES-EVI and insert it into the per-L2-VNI and per-ES
3253 static struct bgp_evpn_es_evi
*bgp_evpn_es_evi_new(struct bgp_evpn_es
*es
,
3254 struct bgpevpn
*vpn
)
3256 struct bgp_evpn_es_evi
*es_evi
;
3258 es_evi
= XCALLOC(MTYPE_BGP_EVPN_ES_EVI
, sizeof(*es_evi
));
3263 /* Initialise the VTEP list */
3264 es_evi
->es_evi_vtep_list
= list_new();
3265 listset_app_node_mem(es_evi
->es_evi_vtep_list
);
3266 es_evi
->es_evi_vtep_list
->cmp
= bgp_evpn_es_evi_vtep_cmp
;
3268 /* insert into the VNI-ESI rb tree */
3269 if (RB_INSERT(bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
, es_evi
)) {
3270 XFREE(MTYPE_BGP_EVPN_ES_EVI
, es_evi
);
3274 /* add to the ES's VNI list */
3275 listnode_init(&es_evi
->es_listnode
, es_evi
);
3276 listnode_add(es
->es_evi_list
, &es_evi
->es_listnode
);
3278 bgp_evpn_es_vrf_ref(es_evi
, vpn
->bgp_vrf
);
3283 /* remove the ES-EVI from the per-L2-VNI and per-ES tables and free
3286 static struct bgp_evpn_es_evi
*
3287 bgp_evpn_es_evi_free(struct bgp_evpn_es_evi
*es_evi
)
3289 struct bgp_evpn_es
*es
= es_evi
->es
;
3290 struct bgpevpn
*vpn
= es_evi
->vpn
;
3292 /* cannot free the element as long as there is a local or remote
3295 if (es_evi
->flags
& (BGP_EVPNES_EVI_LOCAL
| BGP_EVPNES_EVI_REMOTE
))
3298 bgp_evpn_es_vrf_deref(es_evi
);
3300 /* remove from the ES's VNI list */
3301 list_delete_node(es
->es_evi_list
, &es_evi
->es_listnode
);
3303 /* remove from the VNI-ESI rb tree */
3304 RB_REMOVE(bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
, es_evi
);
3306 /* free the VTEP list */
3307 list_delete(&es_evi
->es_evi_vtep_list
);
3309 /* remove from the VNI-ESI rb tree */
3310 XFREE(MTYPE_BGP_EVPN_ES_EVI
, es_evi
);
3315 /* init local info associated with the ES-EVI */
3316 static void bgp_evpn_es_evi_local_info_set(struct bgp_evpn_es_evi
*es_evi
)
3318 struct bgpevpn
*vpn
= es_evi
->vpn
;
3320 if (CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
3323 SET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
);
3324 listnode_init(&es_evi
->l2vni_listnode
, es_evi
);
3325 listnode_add(vpn
->local_es_evi_list
, &es_evi
->l2vni_listnode
);
3328 /* clear any local info associated with the ES-EVI */
3329 static struct bgp_evpn_es_evi
*
3330 bgp_evpn_es_evi_local_info_clear(struct bgp_evpn_es_evi
*es_evi
)
3332 struct bgpevpn
*vpn
= es_evi
->vpn
;
3334 UNSET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
);
3335 list_delete_node(vpn
->local_es_evi_list
, &es_evi
->l2vni_listnode
);
3337 return bgp_evpn_es_evi_free(es_evi
);
3340 /* eval remote info associated with the ES */
3341 static void bgp_evpn_es_evi_remote_info_re_eval(struct bgp_evpn_es_evi
*es_evi
)
3343 struct bgp_evpn_es
*es
= es_evi
->es
;
3345 /* if there are remote VTEPs the ES-EVI is classified as "remote" */
3346 if (listcount(es_evi
->es_evi_vtep_list
)) {
3347 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_REMOTE
)) {
3348 SET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_REMOTE
);
3349 ++es
->remote_es_evi_cnt
;
3350 /* set remote on the parent es */
3351 bgp_evpn_es_remote_info_re_eval(es
);
3354 if (CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_REMOTE
)) {
3355 UNSET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_REMOTE
);
3356 if (es
->remote_es_evi_cnt
)
3357 --es
->remote_es_evi_cnt
;
3358 bgp_evpn_es_evi_free(es_evi
);
3359 /* check if "remote" can be cleared from the
3362 bgp_evpn_es_remote_info_re_eval(es
);
3367 static struct bgp_evpn_es_evi
*
3368 bgp_evpn_local_es_evi_do_del(struct bgp_evpn_es_evi
*es_evi
)
3370 struct prefix_evpn p
;
3371 struct bgp_evpn_es
*es
= es_evi
->es
;
3374 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
3377 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3378 zlog_debug("del local es %s evi %u",
3379 es_evi
->es
->esi_str
,
3382 bgp
= bgp_get_evpn();
3385 /* update EAD-ES with new list of VNIs */
3386 if (bgp_evpn_local_es_is_active(es
)) {
3387 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_ES_ETH_TAG
,
3388 &es
->esi
, es
->originator_ip
);
3389 if (bgp_evpn_type1_route_update(bgp
, es
, NULL
, &p
))
3390 flog_err(EC_BGP_EVPN_ROUTE_CREATE
,
3391 "%u: EAD-ES route update failure for ESI %s VNI %u",
3392 bgp
->vrf_id
, es
->esi_str
,
3396 /* withdraw and delete EAD-EVI */
3397 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
)) {
3398 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_EVI_ETH_TAG
,
3399 &es
->esi
, es
->originator_ip
);
3400 if (bgp_evpn_type1_evi_route_delete(bgp
,
3401 es
, es_evi
->vpn
, &p
))
3402 flog_err(EC_BGP_EVPN_ROUTE_DELETE
,
3403 "%u: EAD-EVI route deletion failure for ESI %s VNI %u",
3404 bgp
->vrf_id
, es
->esi_str
,
3409 return bgp_evpn_es_evi_local_info_clear(es_evi
);
3412 int bgp_evpn_local_es_evi_del(struct bgp
*bgp
, esi_t
*esi
, vni_t vni
)
3414 struct bgpevpn
*vpn
;
3415 struct bgp_evpn_es
*es
;
3416 struct bgp_evpn_es_evi
*es_evi
;
3417 char buf
[ESI_STR_LEN
];
3419 es
= bgp_evpn_es_find(esi
);
3423 "%u: Failed to deref VNI %d from ESI %s; ES not present",
3425 esi_to_str(esi
, buf
, sizeof(buf
)));
3429 vpn
= bgp_evpn_lookup_vni(bgp
, vni
);
3433 "%u: Failed to deref VNI %d from ESI %s; VNI not present",
3434 bgp
->vrf_id
, vni
, es
->esi_str
);
3438 es_evi
= bgp_evpn_es_evi_find(es
, vpn
);
3442 "%u: Failed to deref VNI %d from ESI %s; ES-VNI not present",
3443 bgp
->vrf_id
, vni
, es
->esi_str
);
3447 bgp_evpn_local_es_evi_do_del(es_evi
);
3451 /* Create ES-EVI and advertise the corresponding EAD routes */
3452 int bgp_evpn_local_es_evi_add(struct bgp
*bgp
, esi_t
*esi
, vni_t vni
)
3454 struct bgpevpn
*vpn
;
3455 struct prefix_evpn p
;
3456 struct bgp_evpn_es
*es
;
3457 struct bgp_evpn_es_evi
*es_evi
;
3458 char buf
[ESI_STR_LEN
];
3460 es
= bgp_evpn_es_find(esi
);
3464 "%u: Failed to associate VNI %d with ESI %s; ES not present",
3466 esi_to_str(esi
, buf
, sizeof(buf
)));
3470 vpn
= bgp_evpn_lookup_vni(bgp
, vni
);
3474 "%u: Failed to associate VNI %d with ESI %s; VNI not present",
3475 bgp
->vrf_id
, vni
, es
->esi_str
);
3479 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3480 zlog_debug("add local es %s evi %u",
3483 es_evi
= bgp_evpn_es_evi_find(es
, vpn
);
3486 if (CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
3490 es_evi
= bgp_evpn_es_evi_new(es
, vpn
);
3495 bgp_evpn_es_evi_local_info_set(es_evi
);
3497 /* generate an EAD-EVI for this new VNI */
3498 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
)) {
3499 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_EVI_ETH_TAG
, &es
->esi
,
3501 if (bgp_evpn_type1_route_update(bgp
, es
, vpn
, &p
))
3502 flog_err(EC_BGP_EVPN_ROUTE_CREATE
,
3503 "%u: EAD-EVI route creation failure for ESI %s VNI %u",
3504 bgp
->vrf_id
, es
->esi_str
, vni
);
3508 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_ES_ETH_TAG
,
3509 &es
->esi
, es
->originator_ip
);
3510 if (bgp_evpn_local_es_is_active(es
)) {
3511 if (bgp_evpn_type1_route_update(bgp
, es
, NULL
, &p
))
3512 flog_err(EC_BGP_EVPN_ROUTE_CREATE
,
3513 "%u: EAD-ES route creation failure for ESI %s VNI %u",
3514 bgp
->vrf_id
, es
->esi_str
, vni
);
3520 /* Add remote ES-EVI entry. This is actually the remote VTEP add and the
3521 * ES-EVI is implicity created on first VTEP's reference.
3523 int bgp_evpn_remote_es_evi_add(struct bgp
*bgp
, struct bgpevpn
*vpn
,
3524 const struct prefix_evpn
*p
)
3526 char buf
[ESI_STR_LEN
];
3527 struct bgp_evpn_es
*es
;
3528 struct bgp_evpn_es_evi
*es_evi
;
3530 const esi_t
*esi
= &p
->prefix
.ead_addr
.esi
;
3533 /* local EAD-ES need not be sent back to zebra */
3536 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3537 zlog_debug("add remote %s es %s evi %u vtep %pI4",
3538 p
->prefix
.ead_addr
.eth_tag
? "ead-es" : "ead-evi",
3539 esi_to_str(esi
, buf
, sizeof(buf
)), vpn
->vni
,
3540 &p
->prefix
.ead_addr
.ip
.ipaddr_v4
);
3542 es
= bgp_evpn_es_find(esi
);
3544 es
= bgp_evpn_es_new(bgp
, esi
);
3546 flog_err(EC_BGP_ES_CREATE
,
3547 "%u: Failed to allocate ES entry for ESI %s - at remote ES Add",
3548 bgp
->vrf_id
, esi_to_str(esi
, buf
, sizeof(buf
)));
3553 es_evi
= bgp_evpn_es_evi_find(es
, vpn
);
3555 es_evi
= bgp_evpn_es_evi_new(es
, vpn
);
3557 bgp_evpn_es_free(es
, __func__
);
3562 ead_es
= !!p
->prefix
.ead_addr
.eth_tag
;
3563 bgp_evpn_es_evi_vtep_add(bgp
, es_evi
, p
->prefix
.ead_addr
.ip
.ipaddr_v4
,
3566 bgp_evpn_es_evi_remote_info_re_eval(es_evi
);
3570 /* A remote VTEP has withdrawn. The es-evi-vtep will be deleted and the
3571 * parent es-evi freed up implicitly in last VTEP's deref.
3573 int bgp_evpn_remote_es_evi_del(struct bgp
*bgp
, struct bgpevpn
*vpn
,
3574 const struct prefix_evpn
*p
)
3576 char buf
[ESI_STR_LEN
];
3577 struct bgp_evpn_es
*es
;
3578 struct bgp_evpn_es_evi
*es_evi
;
3582 /* local EAD-ES need not be sent back to zebra */
3585 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3587 "del remote %s es %s evi %u vtep %pI4",
3588 p
->prefix
.ead_addr
.eth_tag
? "ead-es" : "ead-evi",
3589 esi_to_str(&p
->prefix
.ead_addr
.esi
, buf
, sizeof(buf
)),
3590 vpn
->vni
, &p
->prefix
.ead_addr
.ip
.ipaddr_v4
);
3592 es
= bgp_evpn_es_find(&p
->prefix
.ead_addr
.esi
);
3594 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3595 zlog_debug("del remote %s es %s evi %u vtep %pI4, NO es",
3596 p
->prefix
.ead_addr
.eth_tag
? "ead-es"
3598 esi_to_str(&p
->prefix
.ead_addr
.esi
, buf
,
3601 &p
->prefix
.ead_addr
.ip
.ipaddr_v4
);
3604 es_evi
= bgp_evpn_es_evi_find(es
, vpn
);
3606 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3608 "del remote %s es %s evi %u vtep %pI4, NO es-evi",
3609 p
->prefix
.ead_addr
.eth_tag
? "ead-es"
3611 esi_to_str(&p
->prefix
.ead_addr
.esi
, buf
,
3614 &p
->prefix
.ead_addr
.ip
.ipaddr_v4
);
3618 ead_es
= !!p
->prefix
.ead_addr
.eth_tag
;
3619 bgp_evpn_es_evi_vtep_del(bgp
, es_evi
, p
->prefix
.ead_addr
.ip
.ipaddr_v4
,
3621 bgp_evpn_es_evi_remote_info_re_eval(es_evi
);
3625 /* If a VNI is being deleted we need to force del all remote VTEPs */
3626 static void bgp_evpn_remote_es_evi_flush(struct bgp_evpn_es_evi
*es_evi
)
3628 struct listnode
*node
= NULL
;
3629 struct listnode
*nnode
= NULL
;
3630 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
3633 bgp
= bgp_get_evpn();
3637 /* delete all VTEPs */
3638 for (ALL_LIST_ELEMENTS(es_evi
->es_evi_vtep_list
, node
, nnode
,
3640 evi_vtep
->flags
&= ~(BGP_EVPN_EVI_VTEP_EAD_PER_ES
3641 | BGP_EVPN_EVI_VTEP_EAD_PER_EVI
);
3642 bgp_evpn_es_evi_vtep_re_eval_active(bgp
, evi_vtep
);
3643 bgp_evpn_es_evi_vtep_free(evi_vtep
);
3645 /* delete the EVI */
3646 bgp_evpn_es_evi_remote_info_re_eval(es_evi
);
3649 /* Initialize the ES tables maintained per-L2_VNI */
3650 void bgp_evpn_vni_es_init(struct bgpevpn
*vpn
)
3652 /* Initialize the ES-EVI RB tree */
3653 RB_INIT(bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
);
3655 /* Initialize the local list maintained for quick walks by type */
3656 vpn
->local_es_evi_list
= list_new();
3657 listset_app_node_mem(vpn
->local_es_evi_list
);
3660 /* Cleanup the ES info maintained per-L2_VNI */
3661 void bgp_evpn_vni_es_cleanup(struct bgpevpn
*vpn
)
3663 struct bgp_evpn_es_evi
*es_evi
;
3664 struct bgp_evpn_es_evi
*es_evi_next
;
3666 RB_FOREACH_SAFE(es_evi
, bgp_es_evi_rb_head
,
3667 &vpn
->es_evi_rb_tree
, es_evi_next
) {
3668 es_evi
= bgp_evpn_local_es_evi_do_del(es_evi
);
3670 bgp_evpn_remote_es_evi_flush(es_evi
);
3673 list_delete(&vpn
->local_es_evi_list
);
3676 static char *bgp_evpn_es_evi_vteps_str(char *vtep_str
,
3677 struct bgp_evpn_es_evi
*es_evi
,
3678 uint8_t vtep_str_size
)
3680 char vtep_flag_str
[BGP_EVPN_FLAG_STR_SZ
];
3681 struct listnode
*node
;
3682 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
3684 char ip_buf
[INET6_ADDRSTRLEN
];
3687 for (ALL_LIST_ELEMENTS_RO(es_evi
->es_evi_vtep_list
, node
, evi_vtep
)) {
3688 vtep_flag_str
[0] = '\0';
3689 if (evi_vtep
->flags
& BGP_EVPN_EVI_VTEP_EAD_PER_ES
)
3690 strlcat(vtep_flag_str
, "E", sizeof(vtep_flag_str
));
3691 if (evi_vtep
->flags
& BGP_EVPN_EVI_VTEP_EAD_PER_EVI
)
3692 strlcat(vtep_flag_str
, "V", sizeof(vtep_flag_str
));
3694 if (!strnlen(vtep_flag_str
, sizeof(vtep_flag_str
)))
3695 strlcpy(vtep_flag_str
, "-", sizeof(vtep_flag_str
));
3699 strlcat(vtep_str
, ",", vtep_str_size
);
3701 inet_ntop(AF_INET
, &evi_vtep
->vtep_ip
, ip_buf
,
3704 strlcat(vtep_str
, "(", vtep_str_size
);
3705 strlcat(vtep_str
, vtep_flag_str
, vtep_str_size
);
3706 strlcat(vtep_str
, ")", vtep_str_size
);
3712 static void bgp_evpn_es_evi_json_vtep_fill(json_object
*json_vteps
,
3713 struct bgp_evpn_es_evi_vtep
*evi_vtep
)
3715 json_object
*json_vtep_entry
;
3716 json_object
*json_flags
;
3717 char ip_buf
[INET6_ADDRSTRLEN
];
3719 json_vtep_entry
= json_object_new_object();
3721 json_object_string_add(
3722 json_vtep_entry
, "vtep_ip",
3723 inet_ntop(AF_INET
, &evi_vtep
->vtep_ip
, ip_buf
, sizeof(ip_buf
)));
3724 if (evi_vtep
->flags
& (BGP_EVPN_EVI_VTEP_EAD_PER_ES
|
3725 BGP_EVPN_EVI_VTEP_EAD_PER_EVI
)) {
3726 json_flags
= json_object_new_array();
3727 if (evi_vtep
->flags
& BGP_EVPN_EVI_VTEP_EAD_PER_ES
)
3728 json_array_string_add(json_flags
, "ead-per-es");
3729 if (evi_vtep
->flags
& BGP_EVPN_EVI_VTEP_EAD_PER_EVI
)
3730 json_array_string_add(json_flags
, "ead-per-evi");
3731 json_object_object_add(json_vtep_entry
,
3732 "flags", json_flags
);
3735 json_object_array_add(json_vteps
,
3739 static void bgp_evpn_es_evi_show_entry(struct vty
*vty
,
3740 struct bgp_evpn_es_evi
*es_evi
, json_object
*json
)
3742 struct listnode
*node
;
3743 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
3746 json_object
*json_vteps
;
3747 json_object
*json_types
;
3749 json_object_string_add(json
, "esi", es_evi
->es
->esi_str
);
3750 json_object_int_add(json
, "vni", es_evi
->vpn
->vni
);
3752 if (es_evi
->flags
& (BGP_EVPNES_EVI_LOCAL
|
3753 BGP_EVPNES_EVI_REMOTE
)) {
3754 json_types
= json_object_new_array();
3755 if (es_evi
->flags
& BGP_EVPNES_EVI_LOCAL
)
3756 json_array_string_add(json_types
, "local");
3757 if (es_evi
->flags
& BGP_EVPNES_EVI_REMOTE
)
3758 json_array_string_add(json_types
, "remote");
3759 json_object_object_add(json
, "type", json_types
);
3762 if (listcount(es_evi
->es_evi_vtep_list
)) {
3763 json_vteps
= json_object_new_array();
3764 for (ALL_LIST_ELEMENTS_RO(es_evi
->es_evi_vtep_list
,
3766 bgp_evpn_es_evi_json_vtep_fill(json_vteps
,
3769 json_object_object_add(json
, "vteps", json_vteps
);
3773 char vtep_str
[ES_VTEP_LIST_STR_SZ
+ BGP_EVPN_VTEPS_FLAG_STR_SZ
];
3776 if (es_evi
->flags
& BGP_EVPNES_EVI_LOCAL
)
3777 strlcat(type_str
, "L", sizeof(type_str
));
3778 if (es_evi
->flags
& BGP_EVPNES_EVI_REMOTE
)
3779 strlcat(type_str
, "R", sizeof(type_str
));
3780 if (es_evi
->flags
& BGP_EVPNES_EVI_INCONS_VTEP_LIST
)
3781 strlcat(type_str
, "I", sizeof(type_str
));
3783 bgp_evpn_es_evi_vteps_str(vtep_str
, es_evi
, sizeof(vtep_str
));
3785 vty_out(vty
, "%-8d %-30s %-5s %s\n",
3786 es_evi
->vpn
->vni
, es_evi
->es
->esi_str
,
3787 type_str
, vtep_str
);
3791 static void bgp_evpn_es_evi_show_entry_detail(struct vty
*vty
,
3792 struct bgp_evpn_es_evi
*es_evi
, json_object
*json
)
3795 json_object
*json_flags
;
3797 /* Add the "brief" info first */
3798 bgp_evpn_es_evi_show_entry(vty
, es_evi
, json
);
3799 if (es_evi
->flags
& BGP_EVPNES_EVI_INCONS_VTEP_LIST
) {
3800 json_flags
= json_object_new_array();
3801 json_array_string_add(json_flags
, "es-vtep-mismatch");
3802 json_object_object_add(json
, "flags", json_flags
);
3805 char vtep_str
[ES_VTEP_LIST_STR_SZ
+ BGP_EVPN_VTEPS_FLAG_STR_SZ
];
3809 if (es_evi
->flags
& BGP_EVPNES_EVI_LOCAL
)
3810 strlcat(type_str
, "L", sizeof(type_str
));
3811 if (es_evi
->flags
& BGP_EVPNES_EVI_REMOTE
)
3812 strlcat(type_str
, "R", sizeof(type_str
));
3814 bgp_evpn_es_evi_vteps_str(vtep_str
, es_evi
, sizeof(vtep_str
));
3815 if (!strlen(vtep_str
))
3816 strlcpy(vtep_str
, "-", sizeof(type_str
));
3818 vty_out(vty
, "VNI: %d ESI: %s\n",
3819 es_evi
->vpn
->vni
, es_evi
->es
->esi_str
);
3820 vty_out(vty
, " Type: %s\n", type_str
);
3821 vty_out(vty
, " Inconsistencies: %s\n",
3822 (es_evi
->flags
& BGP_EVPNES_EVI_INCONS_VTEP_LIST
) ?
3823 "es-vtep-mismatch":"-");
3824 vty_out(vty
, " VTEPs: %s\n", vtep_str
);
3829 static void bgp_evpn_es_evi_show_one_vni(struct bgpevpn
*vpn
, struct vty
*vty
,
3830 json_object
*json_array
, bool detail
)
3832 struct bgp_evpn_es_evi
*es_evi
;
3833 json_object
*json
= NULL
;
3835 RB_FOREACH(es_evi
, bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
) {
3837 /* create a separate json object for each ES */
3838 json
= json_object_new_object();
3840 bgp_evpn_es_evi_show_entry_detail(vty
, es_evi
, json
);
3842 bgp_evpn_es_evi_show_entry(vty
, es_evi
, json
);
3843 /* add ES to the json array */
3845 json_object_array_add(json_array
, json
);
3849 struct es_evi_show_ctx
{
3855 static void bgp_evpn_es_evi_show_one_vni_hash_cb(struct hash_bucket
*bucket
,
3858 struct bgpevpn
*vpn
= (struct bgpevpn
*)bucket
->data
;
3859 struct es_evi_show_ctx
*wctx
= (struct es_evi_show_ctx
*)ctxt
;
3861 bgp_evpn_es_evi_show_one_vni(vpn
, wctx
->vty
, wctx
->json
, wctx
->detail
);
3864 /* Display all ES EVIs */
3865 void bgp_evpn_es_evi_show(struct vty
*vty
, bool uj
, bool detail
)
3867 json_object
*json_array
= NULL
;
3868 struct es_evi_show_ctx wctx
;
3872 /* create an array of ES-EVIs */
3873 json_array
= json_object_new_array();
3877 wctx
.json
= json_array
;
3878 wctx
.detail
= detail
;
3880 bgp
= bgp_get_evpn();
3882 if (!json_array
&& !detail
) {
3883 vty_out(vty
, "Flags: L local, R remote, I inconsistent\n");
3884 vty_out(vty
, "VTEP-Flags: E EAD-per-ES, V EAD-per-EVI\n");
3885 vty_out(vty
, "%-8s %-30s %-5s %s\n",
3886 "VNI", "ESI", "Flags", "VTEPs");
3890 hash_iterate(bgp
->vnihash
,
3891 (void (*)(struct hash_bucket
*,
3892 void *))bgp_evpn_es_evi_show_one_vni_hash_cb
,
3895 vty_out(vty
, "%s\n", json_object_to_json_string_ext(
3896 json_array
, JSON_C_TO_STRING_PRETTY
));
3897 json_object_free(json_array
);
3901 /* Display specific ES EVI */
3902 void bgp_evpn_es_evi_show_vni(struct vty
*vty
, vni_t vni
,
3903 bool uj
, bool detail
)
3905 struct bgpevpn
*vpn
= NULL
;
3906 json_object
*json_array
= NULL
;
3910 /* create an array of ES-EVIs */
3911 json_array
= json_object_new_array();
3914 bgp
= bgp_get_evpn();
3916 vpn
= bgp_evpn_lookup_vni(bgp
, vni
);
3919 if (!json_array
&& !detail
) {
3920 vty_out(vty
, "Flags: L local, R remote, I inconsistent\n");
3921 vty_out(vty
, "VTEP-Flags: E EAD-per-ES, V EAD-per-EVI\n");
3922 vty_out(vty
, "%-8s %-30s %-5s %s\n",
3923 "VNI", "ESI", "Flags", "VTEPs");
3926 bgp_evpn_es_evi_show_one_vni(vpn
, vty
, json_array
, detail
);
3929 vty_out(vty
, "VNI not found\n");
3933 vty_out(vty
, "%s\n", json_object_to_json_string_ext(
3934 json_array
, JSON_C_TO_STRING_PRETTY
));
3935 json_object_free(json_array
);
3939 /*****************************************************************************
3940 * Ethernet Segment Consistency checks
3941 * Consistency checking is done to detect misconfig or mis-cabling. When
3942 * an inconsistency is detected it is simply logged (and displayed via
3943 * show commands) at this point. A more drastic action can be executed (based
3944 * on user config) in the future.
3946 static void bgp_evpn_es_cons_checks_timer_start(void)
3948 if (!bgp_mh_info
->consistency_checking
|| bgp_mh_info
->t_cons_check
)
3951 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
3952 zlog_debug("periodic consistency checking started");
3954 thread_add_timer(bm
->master
, bgp_evpn_run_consistency_checks
, NULL
,
3955 BGP_EVPN_CONS_CHECK_INTERVAL
,
3956 &bgp_mh_info
->t_cons_check
);
3959 /* queue up the es for background consistency checks */
3960 static void bgp_evpn_es_cons_checks_pend_add(struct bgp_evpn_es
*es
)
3962 if (!bgp_mh_info
->consistency_checking
)
3963 /* consistency checking is not enabled */
3966 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_CONS_CHECK_PEND
))
3967 /* already queued for consistency checking */
3970 /* start the periodic timer for consistency checks if it is not
3971 * already running */
3972 bgp_evpn_es_cons_checks_timer_start();
3974 SET_FLAG(es
->flags
, BGP_EVPNES_CONS_CHECK_PEND
);
3975 listnode_init(&es
->pend_es_listnode
, es
);
3976 listnode_add_after(bgp_mh_info
->pend_es_list
,
3977 listtail_unchecked(bgp_mh_info
->pend_es_list
),
3978 &es
->pend_es_listnode
);
3981 /* pull the ES from the consistency check list */
3982 static void bgp_evpn_es_cons_checks_pend_del(struct bgp_evpn_es
*es
)
3984 if (!CHECK_FLAG(es
->flags
, BGP_EVPNES_CONS_CHECK_PEND
))
3987 UNSET_FLAG(es
->flags
, BGP_EVPNES_CONS_CHECK_PEND
);
3988 list_delete_node(bgp_mh_info
->pend_es_list
,
3989 &es
->pend_es_listnode
);
3992 /* Number of active VTEPs associated with the ES-per-EVI */
3993 static uint32_t bgp_evpn_es_evi_get_active_vtep_cnt(
3994 struct bgp_evpn_es_evi
*es_evi
)
3996 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
3997 struct listnode
*node
;
3998 uint32_t vtep_cnt
= 0;
4000 for (ALL_LIST_ELEMENTS_RO(es_evi
->es_evi_vtep_list
, node
, evi_vtep
)) {
4001 if (CHECK_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
))
4008 /* Number of active VTEPs associated with the ES */
4009 static uint32_t bgp_evpn_es_get_active_vtep_cnt(struct bgp_evpn_es
*es
)
4011 struct listnode
*node
;
4012 uint32_t vtep_cnt
= 0;
4013 struct bgp_evpn_es_vtep
*es_vtep
;
4015 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
4016 if (CHECK_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
))
4023 static struct bgp_evpn_es_vtep
*bgp_evpn_es_get_next_active_vtep(
4024 struct bgp_evpn_es
*es
, struct bgp_evpn_es_vtep
*es_vtep
)
4026 struct listnode
*node
;
4027 struct bgp_evpn_es_vtep
*next_es_vtep
;
4030 node
= listnextnode_unchecked(&es_vtep
->es_listnode
);
4032 node
= listhead(es
->es_vtep_list
);
4034 for (; node
; node
= listnextnode_unchecked(node
)) {
4035 next_es_vtep
= listgetdata(node
);
4036 if (CHECK_FLAG(next_es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
))
4037 return next_es_vtep
;
4043 static struct bgp_evpn_es_evi_vtep
*bgp_evpn_es_evi_get_next_active_vtep(
4044 struct bgp_evpn_es_evi
*es_evi
,
4045 struct bgp_evpn_es_evi_vtep
*evi_vtep
)
4047 struct listnode
*node
;
4048 struct bgp_evpn_es_evi_vtep
*next_evi_vtep
;
4051 node
= listnextnode_unchecked(&evi_vtep
->es_evi_listnode
);
4053 node
= listhead(es_evi
->es_evi_vtep_list
);
4055 for (; node
; node
= listnextnode_unchecked(node
)) {
4056 next_evi_vtep
= listgetdata(node
);
4057 if (CHECK_FLAG(next_evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
))
4058 return next_evi_vtep
;
4064 static void bgp_evpn_es_evi_set_inconsistent(struct bgp_evpn_es_evi
*es_evi
)
4066 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_INCONS_VTEP_LIST
)) {
4067 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
4068 zlog_debug("inconsistency detected - es %s evi %u vtep list mismatch",
4069 es_evi
->es
->esi_str
,
4071 SET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_INCONS_VTEP_LIST
);
4073 /* update parent ES with the incosistency setting */
4074 if (!es_evi
->es
->incons_evi_vtep_cnt
&&
4075 BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
4076 zlog_debug("inconsistency detected - es %s vtep list mismatch",
4077 es_evi
->es
->esi_str
);
4078 ++es_evi
->es
->incons_evi_vtep_cnt
;
4079 SET_FLAG(es_evi
->es
->inconsistencies
,
4080 BGP_EVPNES_INCONS_VTEP_LIST
);
4084 static uint32_t bgp_evpn_es_run_consistency_checks(struct bgp_evpn_es
*es
)
4087 int es_active_vtep_cnt
;
4088 int evi_active_vtep_cnt
;
4089 struct bgp_evpn_es_evi
*es_evi
;
4090 struct listnode
*evi_node
;
4091 struct bgp_evpn_es_vtep
*es_vtep
;
4092 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
4094 /* reset the inconsistencies and re-evaluate */
4095 es
->incons_evi_vtep_cnt
= 0;
4096 es
->inconsistencies
= 0;
4098 es_active_vtep_cnt
= bgp_evpn_es_get_active_vtep_cnt(es
);
4099 for (ALL_LIST_ELEMENTS_RO(es
->es_evi_list
,
4100 evi_node
, es_evi
)) {
4103 /* reset the inconsistencies on the EVI and re-evaluate*/
4104 UNSET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_INCONS_VTEP_LIST
);
4106 evi_active_vtep_cnt
=
4107 bgp_evpn_es_evi_get_active_vtep_cnt(es_evi
);
4108 if (es_active_vtep_cnt
!= evi_active_vtep_cnt
) {
4109 bgp_evpn_es_evi_set_inconsistent(es_evi
);
4113 if (!es_active_vtep_cnt
)
4118 while ((es_vtep
= bgp_evpn_es_get_next_active_vtep(
4120 evi_vtep
= bgp_evpn_es_evi_get_next_active_vtep(es_evi
,
4123 bgp_evpn_es_evi_set_inconsistent(es_evi
);
4126 if (es_vtep
->vtep_ip
.s_addr
!=
4127 evi_vtep
->vtep_ip
.s_addr
) {
4128 /* inconsistency detected; set it and move
4131 bgp_evpn_es_evi_set_inconsistent(es_evi
);
4140 static int bgp_evpn_run_consistency_checks(struct thread
*t
)
4144 struct listnode
*node
;
4145 struct listnode
*nextnode
;
4146 struct bgp_evpn_es
*es
;
4148 for (ALL_LIST_ELEMENTS(bgp_mh_info
->pend_es_list
,
4149 node
, nextnode
, es
)) {
4152 /* run consistency checks on the ES and remove it from the
4155 proc_cnt
+= bgp_evpn_es_run_consistency_checks(es
);
4156 bgp_evpn_es_cons_checks_pend_del(es
);
4161 /* restart the timer */
4162 thread_add_timer(bm
->master
, bgp_evpn_run_consistency_checks
, NULL
,
4163 BGP_EVPN_CONS_CHECK_INTERVAL
,
4164 &bgp_mh_info
->t_cons_check
);
4169 /*****************************************************************************
4170 * EVPN-Nexthop and RMAC management: nexthops associated with Type-2 routes
4171 * that have an ES as destination are consolidated by BGP into a per-VRF
4172 * nh->rmac mapping which is sent to zebra. Zebra installs the nexthop
4173 * as a remote neigh/fdb entry with a dummy (type-1) prefix referencing it.
4175 * This handling is needed because Type-2 routes with ES as dest use NHG
4176 * that is setup using EAD routes (i.e. such NHGs do not include the
4178 ****************************************************************************/
4179 static void bgp_evpn_nh_zebra_update_send(struct bgp_evpn_nh
*nh
, bool add
)
4182 struct bgp
*bgp_vrf
= nh
->bgp_vrf
;
4185 if (!zclient
|| zclient
->sock
< 0)
4188 /* Don't try to register if Zebra doesn't know of this instance. */
4189 if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp_vrf
)) {
4190 if (BGP_DEBUG(zebra
, ZEBRA
))
4191 zlog_debug("No zebra instance, not %s remote nh %s",
4192 add
? "adding" : "deleting", nh
->nh_str
);
4199 zclient_create_header(
4200 s
, add
? ZEBRA_EVPN_REMOTE_NH_ADD
: ZEBRA_EVPN_REMOTE_NH_DEL
,
4202 stream_putl(s
, bgp_vrf
->vrf_id
);
4203 stream_put(s
, &nh
->ip
, sizeof(nh
->ip
));
4205 stream_put(s
, &nh
->rmac
, sizeof(nh
->rmac
));
4207 stream_putw_at(s
, 0, stream_get_endp(s
));
4209 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
)) {
4211 zlog_debug("evpn vrf %s nh %s rmac %pEA add to zebra",
4212 nh
->bgp_vrf
->name
, nh
->nh_str
, &nh
->rmac
);
4213 else if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
4214 zlog_debug("evpn vrf %s nh %s del to zebra",
4215 nh
->bgp_vrf
->name
, nh
->nh_str
);
4218 frrtrace(2, frr_bgp
, evpn_mh_nh_rmac_zsend
, add
, nh
);
4220 zclient_send_message(zclient
);
4223 static void bgp_evpn_nh_zebra_update(struct bgp_evpn_nh
*nh
, bool add
)
4225 if (add
&& !is_zero_mac(&nh
->rmac
)) {
4226 nh
->flags
|= BGP_EVPN_NH_READY_FOR_ZEBRA
;
4227 bgp_evpn_nh_zebra_update_send(nh
, true);
4229 if (!(nh
->flags
& BGP_EVPN_NH_READY_FOR_ZEBRA
))
4231 nh
->flags
&= ~BGP_EVPN_NH_READY_FOR_ZEBRA
;
4232 bgp_evpn_nh_zebra_update_send(nh
, false);
4236 static void *bgp_evpn_nh_alloc(void *p
)
4238 struct bgp_evpn_nh
*tmp_n
= p
;
4239 struct bgp_evpn_nh
*n
;
4241 n
= XCALLOC(MTYPE_BGP_EVPN_NH
, sizeof(struct bgp_evpn_nh
));
4247 static struct bgp_evpn_nh
*bgp_evpn_nh_find(struct bgp
*bgp_vrf
,
4250 struct bgp_evpn_nh tmp
;
4251 struct bgp_evpn_nh
*n
;
4253 memset(&tmp
, 0, sizeof(tmp
));
4254 memcpy(&tmp
.ip
, ip
, sizeof(struct ipaddr
));
4255 n
= hash_lookup(bgp_vrf
->evpn_nh_table
, &tmp
);
4260 /* Add nexthop entry - implicitly created on first path reference */
4261 static struct bgp_evpn_nh
*bgp_evpn_nh_add(struct bgp
*bgp_vrf
,
4263 struct bgp_path_info
*pi
)
4265 struct bgp_evpn_nh tmp_n
;
4266 struct bgp_evpn_nh
*n
= NULL
;
4268 memset(&tmp_n
, 0, sizeof(struct bgp_evpn_nh
));
4269 memcpy(&tmp_n
.ip
, ip
, sizeof(struct ipaddr
));
4270 n
= hash_get(bgp_vrf
->evpn_nh_table
, &tmp_n
, bgp_evpn_nh_alloc
);
4271 ipaddr2str(ip
, n
->nh_str
, sizeof(n
->nh_str
));
4272 n
->bgp_vrf
= bgp_vrf
;
4274 n
->pi_list
= list_new();
4275 listset_app_node_mem(n
->pi_list
);
4277 /* Setup ref_pi when the nh is created */
4278 if (CHECK_FLAG(pi
->flags
, BGP_PATH_VALID
) && pi
->attr
) {
4280 memcpy(&n
->rmac
, &pi
->attr
->rmac
, ETH_ALEN
);
4283 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
4284 zlog_debug("evpn vrf %s nh %s rmac %pEA add", n
->bgp_vrf
->name
,
4285 n
->nh_str
, &n
->rmac
);
4286 bgp_evpn_nh_zebra_update(n
, true);
4290 /* Delete nexthop entry if there are no paths referencing it */
4291 static void bgp_evpn_nh_del(struct bgp_evpn_nh
*n
)
4293 struct bgp_evpn_nh
*tmp_n
;
4294 struct bgp
*bgp_vrf
= n
->bgp_vrf
;
4296 if (listcount(n
->pi_list
))
4299 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
4300 zlog_debug("evpn vrf %s nh %s del to zebra", bgp_vrf
->name
,
4303 bgp_evpn_nh_zebra_update(n
, false);
4304 list_delete(&n
->pi_list
);
4305 tmp_n
= hash_release(bgp_vrf
->evpn_nh_table
, n
);
4306 XFREE(MTYPE_BGP_EVPN_NH
, tmp_n
);
4309 static unsigned int bgp_evpn_nh_hash_keymake(const void *p
)
4311 const struct bgp_evpn_nh
*n
= p
;
4312 const struct ipaddr
*ip
= &n
->ip
;
4314 if (IS_IPADDR_V4(ip
))
4315 return jhash_1word(ip
->ipaddr_v4
.s_addr
, 0);
4317 return jhash2(ip
->ipaddr_v6
.s6_addr32
,
4318 array_size(ip
->ipaddr_v6
.s6_addr32
), 0);
4321 static bool bgp_evpn_nh_cmp(const void *p1
, const void *p2
)
4323 const struct bgp_evpn_nh
*n1
= p1
;
4324 const struct bgp_evpn_nh
*n2
= p2
;
4326 if (n1
== NULL
&& n2
== NULL
)
4329 if (n1
== NULL
|| n2
== NULL
)
4332 return (memcmp(&n1
->ip
, &n2
->ip
, sizeof(struct ipaddr
)) == 0);
4335 void bgp_evpn_nh_init(struct bgp
*bgp_vrf
)
4337 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
4338 zlog_debug("evpn vrf %s nh init", bgp_vrf
->name
);
4339 bgp_vrf
->evpn_nh_table
= hash_create(
4340 bgp_evpn_nh_hash_keymake
, bgp_evpn_nh_cmp
, "BGP EVPN NH table");
4343 static void bgp_evpn_nh_flush_entry(struct bgp_evpn_nh
*nh
)
4345 struct listnode
*node
;
4346 struct listnode
*nnode
;
4347 struct bgp_path_evpn_nh_info
*nh_info
;
4349 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
4350 zlog_debug("evpn vrf %s nh %s flush", nh
->bgp_vrf
->name
,
4353 /* force flush paths */
4354 for (ALL_LIST_ELEMENTS(nh
->pi_list
, node
, nnode
, nh_info
))
4355 bgp_evpn_path_nh_del(nh
->bgp_vrf
, nh_info
->pi
);
4358 static void bgp_evpn_nh_flush_cb(struct hash_bucket
*bucket
, void *ctxt
)
4360 struct bgp_evpn_nh
*nh
= (struct bgp_evpn_nh
*)bucket
->data
;
4362 bgp_evpn_nh_flush_entry(nh
);
4365 void bgp_evpn_nh_finish(struct bgp
*bgp_vrf
)
4367 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
4368 zlog_debug("evpn vrf %s nh finish", bgp_vrf
->name
);
4370 bgp_vrf
->evpn_nh_table
,
4371 (void (*)(struct hash_bucket
*, void *))bgp_evpn_nh_flush_cb
,
4373 hash_free(bgp_vrf
->evpn_nh_table
);
4374 bgp_vrf
->evpn_nh_table
= NULL
;
4377 static void bgp_evpn_nh_update_ref_pi(struct bgp_evpn_nh
*nh
)
4379 struct listnode
*node
;
4380 struct bgp_path_info
*pi
;
4381 struct bgp_path_evpn_nh_info
*nh_info
;
4386 for (ALL_LIST_ELEMENTS_RO(nh
->pi_list
, node
, nh_info
)) {
4388 if (!CHECK_FLAG(pi
->flags
, BGP_PATH_VALID
) || !pi
->attr
)
4391 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
4392 zlog_debug("evpn vrf %s nh %s ref_pi update",
4393 nh
->bgp_vrf
->name
, nh
->nh_str
);
4395 /* If we have a new pi copy rmac from it and update
4396 * zebra if the new rmac is different
4398 if (memcmp(&nh
->rmac
, &nh
->ref_pi
->attr
->rmac
, ETH_ALEN
)) {
4399 memcpy(&nh
->rmac
, &nh
->ref_pi
->attr
->rmac
, ETH_ALEN
);
4400 bgp_evpn_nh_zebra_update(nh
, true);
4406 static void bgp_evpn_nh_clear_ref_pi(struct bgp_evpn_nh
*nh
,
4407 struct bgp_path_info
*pi
)
4409 if (nh
->ref_pi
!= pi
)
4412 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
4413 zlog_debug("evpn vrf %s nh %s ref_pi clear", nh
->bgp_vrf
->name
,
4416 /* try to find another ref_pi */
4417 bgp_evpn_nh_update_ref_pi(nh
);
4418 /* couldn't find one - clear the old rmac and notify zebra */
4420 memset(&nh
->rmac
, 0, ETH_ALEN
);
4421 bgp_evpn_nh_zebra_update(nh
, true);
4425 static void bgp_evpn_path_nh_info_free(struct bgp_path_evpn_nh_info
*nh_info
)
4427 bgp_evpn_path_nh_unlink(nh_info
);
4428 XFREE(MTYPE_BGP_EVPN_PATH_NH_INFO
, nh_info
);
4431 static struct bgp_path_evpn_nh_info
*
4432 bgp_evpn_path_nh_info_new(struct bgp_path_info
*pi
)
4434 struct bgp_path_info_extra
*e
;
4435 struct bgp_path_mh_info
*mh_info
;
4436 struct bgp_path_evpn_nh_info
*nh_info
;
4438 e
= bgp_path_info_extra_get(pi
);
4440 /* If mh_info doesn't exist allocate it */
4441 mh_info
= e
->mh_info
;
4443 e
->mh_info
= mh_info
= XCALLOC(MTYPE_BGP_EVPN_PATH_MH_INFO
,
4444 sizeof(struct bgp_path_mh_info
));
4446 /* If nh_info doesn't exist allocate it */
4447 nh_info
= mh_info
->nh_info
;
4449 mh_info
->nh_info
= nh_info
=
4450 XCALLOC(MTYPE_BGP_EVPN_PATH_NH_INFO
,
4451 sizeof(struct bgp_path_evpn_nh_info
));
4458 static void bgp_evpn_path_nh_unlink(struct bgp_path_evpn_nh_info
*nh_info
)
4460 struct bgp_evpn_nh
*nh
= nh_info
->nh
;
4461 struct bgp_path_info
*pi
;
4462 char prefix_buf
[PREFIX_STRLEN
];
4468 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
4469 zlog_debug("path %s unlinked from nh %s %s",
4470 pi
->net
? prefix2str(&pi
->net
->p
, prefix_buf
,
4473 nh
->bgp_vrf
->name
, nh
->nh_str
);
4475 list_delete_node(nh
->pi_list
, &nh_info
->nh_listnode
);
4479 /* check if the ref_pi need to be updated */
4480 bgp_evpn_nh_clear_ref_pi(nh
, pi
);
4482 /* if there are no other references against the nh it
4485 bgp_evpn_nh_del(nh
);
4487 /* Note we don't free the path nh_info on unlink; it will be freed up
4488 * along with the path.
4492 static void bgp_evpn_path_nh_link(struct bgp
*bgp_vrf
, struct bgp_path_info
*pi
)
4494 struct bgp_path_evpn_nh_info
*nh_info
;
4495 struct bgp_evpn_nh
*nh
;
4498 /* EVPN nexthop setup in bgp has been turned off */
4499 if (!bgp_mh_info
->bgp_evpn_nh_setup
)
4502 if (!bgp_vrf
->evpn_nh_table
) {
4503 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
4504 zlog_debug("path %pFX linked to vrf %s failed",
4505 &pi
->net
->p
, bgp_vrf
->name
);
4509 nh_info
= (pi
->extra
&& pi
->extra
->mh_info
)
4510 ? pi
->extra
->mh_info
->nh_info
4513 /* if NHG is not being used for this path we don't need to manage the
4514 * nexthops in bgp (they are managed by zebra instead)
4516 if (!(pi
->attr
->es_flags
& ATTR_ES_L3_NHG_USE
)) {
4518 bgp_evpn_path_nh_unlink(nh_info
);
4522 /* setup nh_info against the path if it doesn't aleady exist */
4524 nh_info
= bgp_evpn_path_nh_info_new(pi
);
4526 /* find-create nh */
4527 memset(&ip
, 0, sizeof(ip
));
4528 if (pi
->net
->p
.family
== AF_INET6
) {
4530 memcpy(&ip
.ipaddr_v6
, &pi
->attr
->mp_nexthop_global
,
4531 sizeof(ip
.ipaddr_v6
));
4534 memcpy(&ip
.ipaddr_v4
, &pi
->attr
->nexthop
, sizeof(ip
.ipaddr_v4
));
4537 nh
= bgp_evpn_nh_find(bgp_vrf
, &ip
);
4539 nh
= bgp_evpn_nh_add(bgp_vrf
, &ip
, pi
);
4542 if (nh_info
->nh
== nh
) {
4543 /* Check if any of the paths are now valid */
4544 bgp_evpn_nh_update_ref_pi(nh
);
4548 /* unlink old nh if any */
4549 bgp_evpn_path_nh_unlink(nh_info
);
4551 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
4552 zlog_debug("path %pFX linked to nh %s %s", &pi
->net
->p
,
4553 nh
->bgp_vrf
->name
, nh
->nh_str
);
4555 /* link mac-ip path to the new nh */
4557 listnode_init(&nh_info
->nh_listnode
, nh_info
);
4558 listnode_add(nh
->pi_list
, &nh_info
->nh_listnode
);
4559 /* If a new valid path got linked to the nh see if can get the rmac
4562 bgp_evpn_nh_update_ref_pi(nh
);
4563 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
)) {
4566 "path %pFX linked to nh %s %s with no valid pi",
4567 &pi
->net
->p
, nh
->bgp_vrf
->name
, nh
->nh_str
);
4571 void bgp_evpn_path_nh_del(struct bgp
*bgp_vrf
, struct bgp_path_info
*pi
)
4573 struct bgp_path_evpn_nh_info
*nh_info
;
4575 nh_info
= (pi
->extra
&& pi
->extra
->mh_info
)
4576 ? pi
->extra
->mh_info
->nh_info
4582 bgp_evpn_path_nh_unlink(nh_info
);
4585 void bgp_evpn_path_nh_add(struct bgp
*bgp_vrf
, struct bgp_path_info
*pi
)
4587 bgp_evpn_path_nh_link(bgp_vrf
, pi
);
4590 static void bgp_evpn_nh_show_entry(struct bgp_evpn_nh
*nh
, struct vty
*vty
,
4591 json_object
*json_array
)
4593 json_object
*json
= NULL
;
4594 char mac_buf
[ETHER_ADDR_STRLEN
];
4595 char prefix_buf
[PREFIX_STRLEN
];
4598 /* create a separate json object for each ES */
4599 json
= json_object_new_object();
4601 prefix_mac2str(&nh
->rmac
, mac_buf
, sizeof(mac_buf
));
4602 if (nh
->ref_pi
&& nh
->ref_pi
->net
)
4603 prefix2str(&nh
->ref_pi
->net
->p
, prefix_buf
, sizeof(prefix_buf
));
4605 prefix_buf
[0] = '\0';
4607 json_object_string_add(json
, "vrf", nh
->bgp_vrf
->name
);
4608 json_object_string_add(json
, "ip", nh
->nh_str
);
4609 json_object_string_add(json
, "rmac", mac_buf
);
4610 json_object_string_add(json
, "basePath", prefix_buf
);
4611 json_object_int_add(json
, "pathCount", listcount(nh
->pi_list
));
4613 vty_out(vty
, "%-15s %-15s %-17s %-10d %s\n", nh
->bgp_vrf
->name
,
4614 nh
->nh_str
, mac_buf
, listcount(nh
->pi_list
),
4618 /* add ES to the json array */
4620 json_object_array_add(json_array
, json
);
4623 struct nh_show_ctx
{
4628 static void bgp_evpn_nh_show_hash_cb(struct hash_bucket
*bucket
, void *ctxt
)
4630 struct bgp_evpn_nh
*nh
= (struct bgp_evpn_nh
*)bucket
->data
;
4631 struct nh_show_ctx
*wctx
= (struct nh_show_ctx
*)ctxt
;
4633 bgp_evpn_nh_show_entry(nh
, wctx
->vty
, wctx
->json
);
4636 /* Display all evpn nexthops */
4637 void bgp_evpn_nh_show(struct vty
*vty
, bool uj
)
4639 json_object
*json_array
= NULL
;
4640 struct bgp
*bgp_vrf
;
4641 struct listnode
*node
;
4642 struct nh_show_ctx wctx
;
4645 /* create an array of nexthops */
4646 json_array
= json_object_new_array();
4648 vty_out(vty
, "%-15s %-15s %-17s %-10s %s\n", "VRF", "IP",
4649 "RMAC", "#Paths", "Base Path");
4653 wctx
.json
= json_array
;
4655 /* walk through all vrfs */
4656 for (ALL_LIST_ELEMENTS_RO(bm
->bgp
, node
, bgp_vrf
)) {
4657 hash_iterate(bgp_vrf
->evpn_nh_table
,
4658 (void (*)(struct hash_bucket
*,
4659 void *))bgp_evpn_nh_show_hash_cb
,
4663 /* print the array of json-ESs */
4665 vty_out(vty
, "%s\n",
4666 json_object_to_json_string_ext(
4667 json_array
, JSON_C_TO_STRING_PRETTY
));
4668 json_object_free(json_array
);
4672 /*****************************************************************************/
4673 void bgp_evpn_mh_init(void)
4675 bm
->mh_info
= XCALLOC(MTYPE_BGP_EVPN_MH_INFO
, sizeof(*bm
->mh_info
));
4677 /* setup ES tables */
4678 RB_INIT(bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
);
4680 bgp_mh_info
->local_es_list
= list_new();
4681 listset_app_node_mem(bgp_mh_info
->local_es_list
);
4682 /* list of ESs with pending processing */
4683 bgp_mh_info
->pend_es_list
= list_new();
4684 listset_app_node_mem(bgp_mh_info
->pend_es_list
);
4686 bgp_mh_info
->ead_evi_rx
= BGP_EVPN_MH_EAD_EVI_RX_DEF
;
4687 bgp_mh_info
->ead_evi_tx
= BGP_EVPN_MH_EAD_EVI_TX_DEF
;
4689 /* config knobs - XXX add cli to control it */
4690 bgp_mh_info
->ead_evi_adv_for_down_links
= true;
4691 bgp_mh_info
->consistency_checking
= true;
4692 bgp_mh_info
->install_l3nhg
= false;
4693 bgp_mh_info
->host_routes_use_l3nhg
= BGP_EVPN_MH_USE_ES_L3NHG_DEF
;
4694 bgp_mh_info
->suppress_l3_ecomm_on_inactive_es
= true;
4695 bgp_mh_info
->bgp_evpn_nh_setup
= true;
4697 memset(&zero_esi_buf
, 0, sizeof(esi_t
));
4700 void bgp_evpn_mh_finish(void)
4702 struct bgp_evpn_es
*es
;
4703 struct bgp_evpn_es
*es_next
;
4705 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
4706 zlog_debug("evpn mh finish");
4708 RB_FOREACH_SAFE (es
, bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
,
4710 bgp_evpn_es_local_info_clear(es
, true);
4712 if (bgp_mh_info
->t_cons_check
)
4713 thread_cancel(&bgp_mh_info
->t_cons_check
);
4714 list_delete(&bgp_mh_info
->local_es_list
);
4715 list_delete(&bgp_mh_info
->pend_es_list
);
4717 XFREE(MTYPE_BGP_EVPN_MH_INFO
, bgp_mh_info
);
4720 /* This function is called when disable-ead-evi-rx knob flaps */
4721 void bgp_evpn_switch_ead_evi_rx(void)
4724 struct bgp_evpn_es
*es
;
4725 struct bgp_evpn_es_evi
*es_evi
;
4726 struct listnode
*evi_node
= NULL
;
4727 struct listnode
*evi_next
= NULL
;
4728 struct bgp_evpn_es_evi_vtep
*vtep
;
4729 struct listnode
*vtep_node
= NULL
;
4730 struct listnode
*vtep_next
= NULL
;
4732 bgp
= bgp_get_evpn();
4737 * Process all the remote es_evi_vteps and reevaluate if the es_evi_vtep
4740 RB_FOREACH(es
, bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
) {
4741 if (!CHECK_FLAG(es
->flags
, BGP_EVPNES_REMOTE
))
4744 for (ALL_LIST_ELEMENTS(es
->es_evi_list
, evi_node
, evi_next
,
4746 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_REMOTE
))
4749 for (ALL_LIST_ELEMENTS(es_evi
->es_evi_vtep_list
,
4750 vtep_node
, vtep_next
, vtep
))
4751 bgp_evpn_es_evi_vtep_re_eval_active(bgp
, vtep
);