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"
52 static void bgp_evpn_local_es_down(struct bgp
*bgp
,
53 struct bgp_evpn_es
*es
);
54 static void bgp_evpn_local_type1_evi_route_del(struct bgp
*bgp
,
55 struct bgp_evpn_es
*es
);
56 static struct bgp_evpn_es_vtep
*bgp_evpn_es_vtep_add(struct bgp
*bgp
,
57 struct bgp_evpn_es
*es
, struct in_addr vtep_ip
, bool esr
);
58 static void bgp_evpn_es_vtep_del(struct bgp
*bgp
,
59 struct bgp_evpn_es
*es
, struct in_addr vtep_ip
, bool esr
);
60 static void bgp_evpn_es_cons_checks_pend_add(struct bgp_evpn_es
*es
);
61 static void bgp_evpn_es_cons_checks_pend_del(struct bgp_evpn_es
*es
);
62 static void bgp_evpn_local_es_evi_do_del(struct bgp_evpn_es_evi
*es_evi
);
64 esi_t zero_esi_buf
, *zero_esi
= &zero_esi_buf
;
66 /******************************************************************************
67 * per-ES (Ethernet Segment) routing table
69 * Following routes are added to the ES's routing table -
70 * 1. Local and remote ESR (Type-4)
71 * 2. Local EAD-per-ES (Type-1).
73 * Key for these routes is {ESI, VTEP-IP} so the path selection is practically
74 * a no-op i.e. all paths lead to same VTEP-IP (i.e. result in the same VTEP
75 * being added to same ES).
77 * Note the following routes go into the VNI routing table (instead of the
79 * 1. Remote EAD-per-ES
80 * 2. Local and remote EAD-per-EVI
83 /* Calculate the best path for a multi-homing (Type-1 or Type-4) route
84 * installed in the ES's routing table.
86 static int bgp_evpn_es_route_select_install(struct bgp
*bgp
,
87 struct bgp_evpn_es
*es
,
88 struct bgp_dest
*dest
)
91 afi_t afi
= AFI_L2VPN
;
92 safi_t safi
= SAFI_EVPN
;
93 struct bgp_path_info
*old_select
; /* old best */
94 struct bgp_path_info
*new_select
; /* new best */
95 struct bgp_path_info_pair old_and_new
;
97 /* Compute the best path. */
98 bgp_best_selection(bgp
, dest
, &bgp
->maxpaths
[afi
][safi
], &old_and_new
,
100 old_select
= old_and_new
.old
;
101 new_select
= old_and_new
.new;
104 * If the best path hasn't changed - see if something needs to be
107 if (old_select
&& old_select
== new_select
108 && old_select
->type
== ZEBRA_ROUTE_BGP
109 && old_select
->sub_type
== BGP_ROUTE_IMPORTED
110 && !CHECK_FLAG(dest
->flags
, BGP_NODE_USER_CLEAR
)
111 && !CHECK_FLAG(old_select
->flags
, BGP_PATH_ATTR_CHANGED
)
112 && !bgp_addpath_is_addpath_used(&bgp
->tx_addpath
, afi
, safi
)) {
113 if (bgp_zebra_has_route_changed(old_select
)) {
114 bgp_evpn_es_vtep_add(bgp
, es
,
115 old_select
->attr
->nexthop
,
118 UNSET_FLAG(old_select
->flags
, BGP_PATH_MULTIPATH_CHG
);
119 bgp_zebra_clear_route_change_flags(dest
);
123 /* If the user did a "clear" this flag will be set */
124 UNSET_FLAG(dest
->flags
, BGP_NODE_USER_CLEAR
);
126 /* bestpath has changed; update relevant fields and install or uninstall
127 * into the zebra RIB.
129 if (old_select
|| new_select
)
130 bgp_bump_version(dest
);
133 bgp_path_info_unset_flag(dest
, old_select
, BGP_PATH_SELECTED
);
135 bgp_path_info_set_flag(dest
, new_select
, BGP_PATH_SELECTED
);
136 bgp_path_info_unset_flag(dest
, new_select
,
137 BGP_PATH_ATTR_CHANGED
);
138 UNSET_FLAG(new_select
->flags
, BGP_PATH_MULTIPATH_CHG
);
141 if (new_select
&& new_select
->type
== ZEBRA_ROUTE_BGP
142 && new_select
->sub_type
== BGP_ROUTE_IMPORTED
) {
143 bgp_evpn_es_vtep_add(bgp
, es
,
144 new_select
->attr
->nexthop
, true /*esr */);
146 if (old_select
&& old_select
->type
== ZEBRA_ROUTE_BGP
147 && old_select
->sub_type
== BGP_ROUTE_IMPORTED
)
148 bgp_evpn_es_vtep_del(
149 bgp
, es
, old_select
->attr
->nexthop
,
153 /* Clear any route change flags. */
154 bgp_zebra_clear_route_change_flags(dest
);
156 /* Reap old select bgp_path_info, if it has been removed */
157 if (old_select
&& CHECK_FLAG(old_select
->flags
, BGP_PATH_REMOVED
))
158 bgp_path_info_reap(dest
, old_select
);
163 /* Install Type-1/Type-4 route entry in the per-ES routing table */
164 static int bgp_evpn_es_route_install(struct bgp
*bgp
,
165 struct bgp_evpn_es
*es
, struct prefix_evpn
*p
,
166 struct bgp_path_info
*parent_pi
)
169 struct bgp_dest
*dest
= NULL
;
170 struct bgp_path_info
*pi
= NULL
;
171 struct attr
*attr_new
= NULL
;
173 /* Create (or fetch) route within the VNI.
174 * NOTE: There is no RD here.
176 dest
= bgp_node_get(es
->route_table
, (struct prefix
*)p
);
178 /* Check if route entry is already present. */
179 for (pi
= bgp_dest_get_bgp_path_info(dest
); pi
; pi
= pi
->next
)
181 && (struct bgp_path_info
*)pi
->extra
->parent
==
186 /* Add (or update) attribute to hash. */
187 attr_new
= bgp_attr_intern(parent_pi
->attr
);
189 /* Create new route with its attribute. */
190 pi
= info_make(parent_pi
->type
, BGP_ROUTE_IMPORTED
, 0,
191 parent_pi
->peer
, attr_new
, dest
);
192 SET_FLAG(pi
->flags
, BGP_PATH_VALID
);
193 bgp_path_info_extra_get(pi
);
194 pi
->extra
->parent
= bgp_path_info_lock(parent_pi
);
195 bgp_dest_lock_node((struct bgp_dest
*)parent_pi
->net
);
196 bgp_path_info_add(dest
, pi
);
198 if (attrhash_cmp(pi
->attr
, parent_pi
->attr
)
199 && !CHECK_FLAG(pi
->flags
, BGP_PATH_REMOVED
)) {
200 bgp_dest_unlock_node(dest
);
203 /* The attribute has changed. */
204 /* Add (or update) attribute to hash. */
205 attr_new
= bgp_attr_intern(parent_pi
->attr
);
207 /* Restore route, if needed. */
208 if (CHECK_FLAG(pi
->flags
, BGP_PATH_REMOVED
))
209 bgp_path_info_restore(dest
, pi
);
211 /* Mark if nexthop has changed. */
212 if (!IPV4_ADDR_SAME(&pi
->attr
->nexthop
, &attr_new
->nexthop
))
213 SET_FLAG(pi
->flags
, BGP_PATH_IGP_CHANGED
);
215 /* Unintern existing, set to new. */
216 bgp_attr_unintern(&pi
->attr
);
218 pi
->uptime
= bgp_clock();
221 /* Perform route selection and update zebra, if required. */
222 ret
= bgp_evpn_es_route_select_install(bgp
, es
, dest
);
224 bgp_dest_unlock_node(dest
);
229 /* Uninstall Type-1/Type-4 route entry from the ES routing table */
230 static int bgp_evpn_es_route_uninstall(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
231 struct prefix_evpn
*p
, struct bgp_path_info
*parent_pi
)
234 struct bgp_dest
*dest
;
235 struct bgp_path_info
*pi
;
237 if (!es
->route_table
)
240 /* Locate route within the ESI.
241 * NOTE: There is no RD here.
243 dest
= bgp_node_lookup(es
->route_table
, (struct prefix
*)p
);
247 /* Find matching route entry. */
248 for (pi
= bgp_dest_get_bgp_path_info(dest
); pi
; pi
= pi
->next
)
250 && (struct bgp_path_info
*)pi
->extra
->parent
==
257 /* Mark entry for deletion */
258 bgp_path_info_delete(dest
, pi
);
260 /* Perform route selection and update zebra, if required. */
261 ret
= bgp_evpn_es_route_select_install(bgp
, es
, dest
);
263 /* Unlock route node. */
264 bgp_dest_unlock_node(dest
);
269 /* Install or unistall a Tyoe-4 route in the per-ES routing table */
270 int bgp_evpn_es_route_install_uninstall(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
271 afi_t afi
, safi_t safi
, struct prefix_evpn
*evp
,
272 struct bgp_path_info
*pi
, int install
)
277 ret
= bgp_evpn_es_route_install(bgp
, es
, evp
, pi
);
279 ret
= bgp_evpn_es_route_uninstall(bgp
, es
, evp
, pi
);
284 "%u: Failed to %s EVPN %s route in ESI %s",
286 install
? "install" : "uninstall",
293 /* Delete (and withdraw) local routes for specified ES from global and ES table.
294 * Also remove all remote routes from the per ES table. Invoked when ES
297 static void bgp_evpn_es_route_del_all(struct bgp
*bgp
, struct bgp_evpn_es
*es
)
299 struct bgp_dest
*dest
;
300 struct bgp_path_info
*pi
, *nextpi
;
302 /* de-activate the ES */
303 bgp_evpn_local_es_down(bgp
, es
);
304 bgp_evpn_local_type1_evi_route_del(bgp
, es
);
306 /* Walk this ES's routing table and delete all routes. */
307 for (dest
= bgp_table_top(es
->route_table
); dest
;
308 dest
= bgp_route_next(dest
)) {
309 for (pi
= bgp_dest_get_bgp_path_info(dest
);
310 (pi
!= NULL
) && (nextpi
= pi
->next
, 1); pi
= nextpi
) {
311 bgp_path_info_delete(dest
, pi
);
312 bgp_path_info_reap(dest
, pi
);
317 /*****************************************************************************
318 * Base APIs for creating MH routes (Type-1 or Type-4) on local ethernet
322 /* create or update local EVPN type1/type4 route entry.
325 * the ES table if ESR/EAD-ES (or)
326 * the VNI table if EAD-EVI (or)
327 * the global table if ESR/EAD-ES/EAD-EVI
329 * Note: vpn is applicable only to EAD-EVI routes (NULL for EAD-ES and
332 static int bgp_evpn_mh_route_update(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
333 struct bgpevpn
*vpn
, afi_t afi
, safi_t safi
,
334 struct bgp_dest
*dest
, struct attr
*attr
,
335 int add
, struct bgp_path_info
**ri
,
338 struct bgp_path_info
*tmp_pi
= NULL
;
339 struct bgp_path_info
*local_pi
= NULL
; /* local route entry if any */
340 struct bgp_path_info
*remote_pi
= NULL
; /* remote route entry if any */
341 struct attr
*attr_new
= NULL
;
342 struct prefix_evpn
*evp
;
345 evp
= (struct prefix_evpn
*)bgp_dest_get_prefix(dest
);
348 /* locate the local and remote entries if any */
349 for (tmp_pi
= bgp_dest_get_bgp_path_info(dest
); tmp_pi
;
350 tmp_pi
= tmp_pi
->next
) {
351 if (tmp_pi
->peer
== bgp
->peer_self
352 && tmp_pi
->type
== ZEBRA_ROUTE_BGP
353 && tmp_pi
->sub_type
== BGP_ROUTE_STATIC
)
355 if (tmp_pi
->type
== ZEBRA_ROUTE_BGP
356 && tmp_pi
->sub_type
== BGP_ROUTE_IMPORTED
357 && CHECK_FLAG(tmp_pi
->flags
, BGP_PATH_VALID
))
361 /* we don't expect to see a remote_ri at this point as
362 * an ES route has {esi, vtep_ip} as the key in the ES-rt-table
363 * in the VNI-rt-table.
368 "%u ERROR: local es route for ESI: %s Vtep %pI4 also learnt from remote",
369 bgp
->vrf_id
, es
->esi_str
, &es
->originator_ip
);
373 if (!local_pi
&& !add
)
376 /* create or update the entry */
379 /* Add or update attribute to hash */
380 attr_new
= bgp_attr_intern(attr
);
382 /* Create new route with its attribute. */
383 tmp_pi
= info_make(ZEBRA_ROUTE_BGP
, BGP_ROUTE_STATIC
, 0,
384 bgp
->peer_self
, attr_new
, dest
);
385 SET_FLAG(tmp_pi
->flags
, BGP_PATH_VALID
);
387 if (evp
->prefix
.route_type
== BGP_EVPN_AD_ROUTE
) {
388 bgp_path_info_extra_get(tmp_pi
);
389 tmp_pi
->extra
->num_labels
= 1;
391 vni2label(vpn
->vni
, &tmp_pi
->extra
->label
[0]);
393 tmp_pi
->extra
->label
[0] = 0;
396 /* add the newly created path to the route-node */
397 bgp_path_info_add(dest
, tmp_pi
);
400 if (attrhash_cmp(tmp_pi
->attr
, attr
)
401 && !CHECK_FLAG(tmp_pi
->flags
, BGP_PATH_REMOVED
))
404 /* The attribute has changed.
405 * Add (or update) attribute to hash.
407 attr_new
= bgp_attr_intern(attr
);
408 bgp_path_info_set_flag(dest
, tmp_pi
,
409 BGP_PATH_ATTR_CHANGED
);
411 /* Restore route, if needed. */
412 if (CHECK_FLAG(tmp_pi
->flags
, BGP_PATH_REMOVED
))
413 bgp_path_info_restore(dest
, tmp_pi
);
415 /* Unintern existing, set to new. */
416 bgp_attr_unintern(&tmp_pi
->attr
);
417 tmp_pi
->attr
= attr_new
;
418 tmp_pi
->uptime
= bgp_clock();
422 if (*route_changed
) {
423 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
425 "local ES %s vni %u route-type %s nexthop %pI4 updated",
426 es
->esi_str
, vpn
? vpn
->vni
: 0,
427 evp
->prefix
.route_type
== BGP_EVPN_ES_ROUTE
429 : (vpn
? "ead-evi" : "ead-es"),
430 &attr
->mp_nexthop_global_in
);
433 /* Return back the route entry. */
438 /* Delete local EVPN ESR (type-4) and EAD (type-1) route
440 * Note: vpn is applicable only to EAD-EVI routes (NULL for EAD-ES and
443 static int bgp_evpn_mh_route_delete(struct bgp
*bgp
, struct bgp_evpn_es
*es
,
444 struct bgpevpn
*vpn
, struct prefix_evpn
*p
)
446 afi_t afi
= AFI_L2VPN
;
447 safi_t safi
= SAFI_EVPN
;
448 struct bgp_path_info
*pi
;
449 struct bgp_dest
*dest
= NULL
; /* dest in esi table */
450 struct bgp_dest
*global_dest
= NULL
; /* dest in global table */
451 struct bgp_table
*rt_table
;
452 struct prefix_rd
*prd
;
455 rt_table
= vpn
->route_table
;
458 rt_table
= es
->route_table
;
462 /* First, locate the route node within the ESI or VNI.
463 * If it doesn't exist, ther is nothing to do.
464 * Note: there is no RD here.
466 dest
= bgp_node_lookup(rt_table
, (struct prefix
*)p
);
470 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
472 "local ES %s vni %u route-type %s nexthop %pI4 delete",
473 es
->esi_str
, vpn
? vpn
->vni
: 0,
474 p
->prefix
.route_type
== BGP_EVPN_ES_ROUTE
476 : (vpn
? "ead-evi" : "ead-es"),
479 /* Next, locate route node in the global EVPN routing table.
480 * Note that this table is a 2-level tree (RD-level + Prefix-level)
483 bgp_global_evpn_node_lookup(bgp
->rib
[afi
][safi
], afi
, safi
,
484 (const struct prefix_evpn
*)p
, prd
);
487 /* Delete route entry in the global EVPN table. */
488 delete_evpn_route_entry(bgp
, afi
, safi
, global_dest
, &pi
);
490 /* Schedule for processing - withdraws to peers happen from
494 bgp_process(bgp
, global_dest
, afi
, safi
);
495 bgp_dest_unlock_node(global_dest
);
499 * Delete route entry in the ESI or VNI routing table.
500 * This can just be removed.
502 delete_evpn_route_entry(bgp
, afi
, safi
, dest
, &pi
);
504 bgp_path_info_reap(dest
, pi
);
505 bgp_dest_unlock_node(dest
);
509 /*****************************************************************************
510 * Ethernet Segment (Type-4) Routes
511 * ESRs are used for BUM handling. XXX - BUM support is planned for phase-2 i.e.
512 * this code is just a place holder for now
514 /* Build extended community for EVPN ES (type-4) route */
515 static void bgp_evpn_type4_route_extcomm_build(struct bgp_evpn_es
*es
,
518 struct ecommunity ecom_encap
;
519 struct ecommunity ecom_es_rt
;
520 struct ecommunity_val eval
;
521 struct ecommunity_val eval_es_rt
;
522 bgp_encap_types tnl_type
;
526 tnl_type
= BGP_ENCAP_TYPE_VXLAN
;
527 memset(&ecom_encap
, 0, sizeof(ecom_encap
));
528 encode_encap_extcomm(tnl_type
, &eval
);
530 ecom_encap
.unit_size
= ECOMMUNITY_SIZE
;
531 ecom_encap
.val
= (uint8_t *)eval
.val
;
532 attr
->ecommunity
= ecommunity_dup(&ecom_encap
);
535 memset(&mac
, 0, sizeof(struct ethaddr
));
536 memset(&ecom_es_rt
, 0, sizeof(ecom_es_rt
));
537 es_get_system_mac(&es
->esi
, &mac
);
538 encode_es_rt_extcomm(&eval_es_rt
, &mac
);
540 ecom_es_rt
.unit_size
= ECOMMUNITY_SIZE
;
541 ecom_es_rt
.val
= (uint8_t *)eval_es_rt
.val
;
543 ecommunity_merge(attr
->ecommunity
, &ecom_es_rt
);
545 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES
);
548 /* Create or update local type-4 route */
549 static int bgp_evpn_type4_route_update(struct bgp
*bgp
,
550 struct bgp_evpn_es
*es
, struct prefix_evpn
*p
)
553 int route_changed
= 0;
554 afi_t afi
= AFI_L2VPN
;
555 safi_t safi
= SAFI_EVPN
;
557 struct attr
*attr_new
= NULL
;
558 struct bgp_dest
*dest
= NULL
;
559 struct bgp_path_info
*pi
= NULL
;
561 memset(&attr
, 0, sizeof(struct attr
));
563 /* Build path-attribute for this route. */
564 bgp_attr_default_set(&attr
, BGP_ORIGIN_IGP
);
565 attr
.nexthop
= es
->originator_ip
;
566 attr
.mp_nexthop_global_in
= es
->originator_ip
;
567 attr
.mp_nexthop_len
= BGP_ATTR_NHLEN_IPV4
;
569 /* Set up extended community. */
570 bgp_evpn_type4_route_extcomm_build(es
, &attr
);
572 /* First, create (or fetch) route node within the ESI. */
573 /* NOTE: There is no RD here. */
574 dest
= bgp_node_get(es
->route_table
, (struct prefix
*)p
);
576 /* Create or update route entry. */
577 ret
= bgp_evpn_mh_route_update(bgp
, es
, NULL
, afi
, safi
, dest
, &attr
, 1,
578 &pi
, &route_changed
);
582 "%u ERROR: Failed to updated ES route ESI: %s VTEP %pI4",
583 bgp
->vrf_id
, es
->esi_str
, &es
->originator_ip
);
589 /* Perform route selection;
590 * this is just to set the flags correctly
591 * as local route in the ES always wins.
593 bgp_evpn_es_route_select_install(bgp
, es
, dest
);
594 bgp_dest_unlock_node(dest
);
596 /* If this is a new route or some attribute has changed, export the
597 * route to the global table. The route will be advertised to peers
598 * from there. Note that this table is a 2-level tree (RD-level +
599 * Prefix-level) similar to L3VPN routes.
602 struct bgp_path_info
*global_pi
;
604 dest
= bgp_global_evpn_node_get(bgp
->rib
[afi
][safi
], afi
, safi
,
606 bgp_evpn_mh_route_update(bgp
, es
, NULL
, afi
, safi
, dest
,
607 attr_new
, 1, &global_pi
,
610 /* Schedule for processing and unlock node. */
611 bgp_process(bgp
, dest
, afi
, safi
);
612 bgp_dest_unlock_node(dest
);
615 /* Unintern temporary. */
616 aspath_unintern(&attr
.aspath
);
620 /* Delete local type-4 route */
621 static int bgp_evpn_type4_route_delete(struct bgp
*bgp
,
622 struct bgp_evpn_es
*es
, struct prefix_evpn
*p
)
624 return bgp_evpn_mh_route_delete(bgp
, es
, NULL
/* l2vni */, p
);
627 /* Process remote/received EVPN type-4 route (advertise or withdraw) */
628 int bgp_evpn_type4_route_process(struct peer
*peer
, afi_t afi
, safi_t safi
,
629 struct attr
*attr
, uint8_t *pfx
, int psize
,
635 struct in_addr vtep_ip
;
636 struct prefix_rd prd
;
637 struct prefix_evpn p
;
639 /* Type-4 route should be either 23 or 35 bytes
640 * RD (8), ESI (10), ip-len (1), ip (4 or 16)
642 if (psize
!= BGP_EVPN_TYPE4_V4_PSIZE
&&
643 psize
!= BGP_EVPN_TYPE4_V6_PSIZE
) {
644 flog_err(EC_BGP_EVPN_ROUTE_INVALID
,
645 "%u:%s - Rx EVPN Type-4 NLRI with invalid length %d",
646 peer
->bgp
->vrf_id
, peer
->host
, psize
);
651 prd
.family
= AF_UNSPEC
;
653 memcpy(&prd
.val
, pfx
, RD_BYTES
);
657 memcpy(&esi
, pfx
, ESI_BYTES
);
663 if (ipaddr_len
== IPV4_MAX_BITLEN
) {
664 memcpy(&vtep_ip
, pfx
, IPV4_MAX_BYTELEN
);
667 EC_BGP_EVPN_ROUTE_INVALID
,
668 "%u:%s - Rx EVPN Type-4 NLRI with unsupported IP address length %d",
669 peer
->bgp
->vrf_id
, peer
->host
, ipaddr_len
);
673 build_evpn_type4_prefix(&p
, &esi
, vtep_ip
);
674 /* Process the route. */
676 ret
= bgp_update(peer
, (struct prefix
*)&p
, addpath_id
, attr
,
677 afi
, safi
, ZEBRA_ROUTE_BGP
, BGP_ROUTE_NORMAL
,
678 &prd
, NULL
, 0, 0, NULL
);
680 ret
= bgp_withdraw(peer
, (struct prefix
*)&p
, addpath_id
, attr
,
681 afi
, safi
, ZEBRA_ROUTE_BGP
, BGP_ROUTE_NORMAL
,
682 &prd
, NULL
, 0, NULL
);
687 /* Check if a prefix belongs to the local ES */
688 static bool bgp_evpn_type4_prefix_match(struct prefix_evpn
*p
,
689 struct bgp_evpn_es
*es
)
691 return (p
->prefix
.route_type
== BGP_EVPN_ES_ROUTE
) &&
692 !memcmp(&p
->prefix
.es_addr
.esi
, &es
->esi
, sizeof(esi_t
));
695 /* Import remote ESRs on local ethernet segment add */
696 static int bgp_evpn_type4_remote_routes_import(struct bgp
*bgp
,
697 struct bgp_evpn_es
*es
, bool install
)
702 struct bgp_dest
*rd_dest
, *dest
;
703 struct bgp_table
*table
;
704 struct bgp_path_info
*pi
;
709 /* Walk entire global routing table and evaluate routes which could be
710 * imported into this Ethernet Segment.
712 for (rd_dest
= bgp_table_top(bgp
->rib
[afi
][safi
]); rd_dest
;
713 rd_dest
= bgp_route_next(rd_dest
)) {
714 table
= bgp_dest_get_bgp_table_info(rd_dest
);
718 for (dest
= bgp_table_top(table
); dest
;
719 dest
= bgp_route_next(dest
)) {
720 struct prefix_evpn
*evp
=
721 (struct prefix_evpn
*)bgp_dest_get_prefix(dest
);
723 for (pi
= bgp_dest_get_bgp_path_info(dest
); pi
;
726 * Consider "valid" remote routes applicable for
729 if (!(CHECK_FLAG(pi
->flags
, BGP_PATH_VALID
)
730 && pi
->type
== ZEBRA_ROUTE_BGP
731 && pi
->sub_type
== BGP_ROUTE_NORMAL
))
734 if (!bgp_evpn_type4_prefix_match(evp
, es
))
738 ret
= bgp_evpn_es_route_install(
741 ret
= bgp_evpn_es_route_uninstall(
747 "Failed to %s EVPN %pFX route in ESI %s",
759 /*****************************************************************************
760 * Ethernet Auto Discovery (EAD/Type-1) route handling
761 * There are two types of EAD routes -
762 * 1. EAD-per-ES - Key: {ESI, ET=0xffffffff}
763 * 2. EAD-per-EVI - Key: {ESI, ET=0}
766 /* Extended communities associated with EAD-per-ES */
767 static void bgp_evpn_type1_es_route_extcomm_build(struct bgp_evpn_es
*es
,
770 struct ecommunity ecom_encap
;
771 struct ecommunity ecom_esi_label
;
772 struct ecommunity_val eval
;
773 struct ecommunity_val eval_esi_label
;
774 bgp_encap_types tnl_type
;
775 struct listnode
*evi_node
, *rt_node
;
776 struct ecommunity
*ecom
;
777 struct bgp_evpn_es_evi
*es_evi
;
780 tnl_type
= BGP_ENCAP_TYPE_VXLAN
;
781 memset(&ecom_encap
, 0, sizeof(ecom_encap
));
782 encode_encap_extcomm(tnl_type
, &eval
);
784 ecom_encap
.unit_size
= ECOMMUNITY_SIZE
;
785 ecom_encap
.val
= (uint8_t *)eval
.val
;
786 attr
->ecommunity
= ecommunity_dup(&ecom_encap
);
789 encode_esi_label_extcomm(&eval_esi_label
,
790 false /*single_active*/);
791 ecom_esi_label
.size
= 1;
792 ecom_esi_label
.unit_size
= ECOMMUNITY_SIZE
;
793 ecom_esi_label
.val
= (uint8_t *)eval_esi_label
.val
;
795 ecommunity_merge(attr
->ecommunity
, &ecom_esi_label
);
797 /* Add export RTs for all L2-VNIs associated with this ES */
798 /* XXX - suppress EAD-ES advertisment if there are no EVIs associated
801 for (ALL_LIST_ELEMENTS_RO(es
->es_evi_list
,
803 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
805 for (ALL_LIST_ELEMENTS_RO(es_evi
->vpn
->export_rtl
,
807 attr
->ecommunity
= ecommunity_merge(attr
->ecommunity
,
811 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES
);
814 /* Extended communities associated with EAD-per-EVI */
815 static void bgp_evpn_type1_evi_route_extcomm_build(struct bgp_evpn_es
*es
,
816 struct bgpevpn
*vpn
, struct attr
*attr
)
818 struct ecommunity ecom_encap
;
819 struct ecommunity_val eval
;
820 bgp_encap_types tnl_type
;
821 struct listnode
*rt_node
;
822 struct ecommunity
*ecom
;
825 tnl_type
= BGP_ENCAP_TYPE_VXLAN
;
826 memset(&ecom_encap
, 0, sizeof(ecom_encap
));
827 encode_encap_extcomm(tnl_type
, &eval
);
829 ecom_encap
.unit_size
= ECOMMUNITY_SIZE
;
830 ecom_encap
.val
= (uint8_t *)eval
.val
;
831 attr
->ecommunity
= ecommunity_dup(&ecom_encap
);
833 /* Add export RTs for the L2-VNI */
834 for (ALL_LIST_ELEMENTS_RO(vpn
->export_rtl
, rt_node
, ecom
))
835 attr
->ecommunity
= ecommunity_merge(attr
->ecommunity
, ecom
);
837 attr
->flag
|= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES
);
840 /* Update EVPN EAD (type-1) route -
841 * vpn - valid for EAD-EVI routes and NULL for EAD-ES routes
843 static int bgp_evpn_type1_route_update(struct bgp
*bgp
,
844 struct bgp_evpn_es
*es
, struct bgpevpn
*vpn
,
845 struct prefix_evpn
*p
)
848 afi_t afi
= AFI_L2VPN
;
849 safi_t safi
= SAFI_EVPN
;
851 struct attr
*attr_new
= NULL
;
852 struct bgp_dest
*dest
= NULL
;
853 struct bgp_path_info
*pi
= NULL
;
854 int route_changed
= 0;
855 struct prefix_rd
*global_rd
;
857 memset(&attr
, 0, sizeof(struct attr
));
859 /* Build path-attribute for this route. */
860 bgp_attr_default_set(&attr
, BGP_ORIGIN_IGP
);
861 attr
.nexthop
= es
->originator_ip
;
862 attr
.mp_nexthop_global_in
= es
->originator_ip
;
863 attr
.mp_nexthop_len
= BGP_ATTR_NHLEN_IPV4
;
866 /* EAD-EVI route update */
868 vni2label(vpn
->vni
, &(attr
.label
));
870 /* Set up extended community */
871 bgp_evpn_type1_evi_route_extcomm_build(es
, vpn
, &attr
);
873 /* First, create (or fetch) route node within the VNI. */
874 dest
= bgp_node_get(vpn
->route_table
, (struct prefix
*)p
);
876 /* Create or update route entry. */
877 ret
= bgp_evpn_mh_route_update(bgp
, es
, vpn
, afi
, safi
, dest
,
878 &attr
, 1, &pi
, &route_changed
);
882 "%u Failed to update EAD-EVI route ESI: %s VNI %u VTEP %pI4",
883 bgp
->vrf_id
, es
->esi_str
, vpn
->vni
,
886 global_rd
= &vpn
->prd
;
888 /* EAD-ES route update */
889 /* MPLS label is 0 for EAD-ES route */
891 /* Set up extended community */
892 bgp_evpn_type1_es_route_extcomm_build(es
, &attr
);
894 /* First, create (or fetch) route node within the ES. */
895 /* NOTE: There is no RD here. */
896 /* XXX: fragment ID must be included as a part of the prefix. */
897 dest
= bgp_node_get(es
->route_table
, (struct prefix
*)p
);
899 /* Create or update route entry. */
900 ret
= bgp_evpn_mh_route_update(bgp
, es
, vpn
, afi
, safi
, dest
,
901 &attr
, 1, &pi
, &route_changed
);
905 "%u ERROR: Failed to updated EAD-EVI route ESI: %s VTEP %pI4",
906 bgp
->vrf_id
, es
->esi_str
, &es
->originator_ip
);
908 global_rd
= &es
->prd
;
915 /* Perform route selection;
916 * this is just to set the flags correctly as local route in
917 * the ES always wins.
919 evpn_route_select_install(bgp
, vpn
, dest
);
920 bgp_dest_unlock_node(dest
);
922 /* If this is a new route or some attribute has changed, export the
923 * route to the global table. The route will be advertised to peers
924 * from there. Note that this table is a 2-level tree (RD-level +
925 * Prefix-level) similar to L3VPN routes.
928 struct bgp_path_info
*global_pi
;
930 dest
= bgp_global_evpn_node_get(bgp
->rib
[afi
][safi
], afi
, safi
,
932 bgp_evpn_mh_route_update(bgp
, es
, vpn
, afi
, safi
, dest
,
933 attr_new
, 1, &global_pi
,
936 /* Schedule for processing and unlock node. */
937 bgp_process(bgp
, dest
, afi
, safi
);
938 bgp_dest_unlock_node(dest
);
941 /* Unintern temporary. */
942 aspath_unintern(&attr
.aspath
);
946 /* Delete local Type-1 route */
947 static int bgp_evpn_type1_es_route_delete(struct bgp
*bgp
,
948 struct bgp_evpn_es
*es
, struct prefix_evpn
*p
)
950 return bgp_evpn_mh_route_delete(bgp
, es
, NULL
/* l2vni */, p
);
953 static int bgp_evpn_type1_evi_route_delete(struct bgp
*bgp
,
954 struct bgp_evpn_es
*es
, struct bgpevpn
*vpn
,
955 struct prefix_evpn
*p
)
957 return bgp_evpn_mh_route_delete(bgp
, es
, vpn
, p
);
960 /* Generate EAD-EVI for all VNIs */
961 static void bgp_evpn_local_type1_evi_route_add(struct bgp
*bgp
,
962 struct bgp_evpn_es
*es
)
964 struct listnode
*evi_node
;
965 struct prefix_evpn p
;
966 struct bgp_evpn_es_evi
*es_evi
;
968 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
))
969 /* EAD-EVI route add for this ES is already done */
972 SET_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
);
973 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_EVI_ETH_TAG
,
974 &es
->esi
, es
->originator_ip
);
976 for (ALL_LIST_ELEMENTS_RO(es
->es_evi_list
, evi_node
, es_evi
)) {
977 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
979 if (bgp_evpn_type1_route_update(bgp
, es
, es_evi
->vpn
, &p
))
980 flog_err(EC_BGP_EVPN_ROUTE_CREATE
,
981 "%u: Type4 route creation failure for ESI %s",
982 bgp
->vrf_id
, es
->esi_str
);
987 * Withdraw EAD-EVI for all VNIs
989 static void bgp_evpn_local_type1_evi_route_del(struct bgp
*bgp
,
990 struct bgp_evpn_es
*es
)
992 struct listnode
*evi_node
;
993 struct prefix_evpn p
;
994 struct bgp_evpn_es_evi
*es_evi
;
996 /* Delete and withdraw locally learnt EAD-EVI route */
997 if (!CHECK_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
))
998 /* EAD-EVI route has not been advertised for this ES */
1001 UNSET_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
);
1002 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_EVI_ETH_TAG
,
1003 &es
->esi
, es
->originator_ip
);
1004 for (ALL_LIST_ELEMENTS_RO(es
->es_evi_list
, evi_node
, es_evi
)) {
1005 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
1007 if (bgp_evpn_mh_route_delete(bgp
, es
, es_evi
->vpn
, &p
))
1008 flog_err(EC_BGP_EVPN_ROUTE_CREATE
,
1009 "%u: Type4 route creation failure for ESI %s",
1010 bgp
->vrf_id
, es
->esi_str
);
1015 * Process received EVPN type-1 route (advertise or withdraw).
1017 int bgp_evpn_type1_route_process(struct peer
*peer
, afi_t afi
, safi_t safi
,
1018 struct attr
*attr
, uint8_t *pfx
, int psize
,
1019 uint32_t addpath_id
)
1022 struct prefix_rd prd
;
1026 struct in_addr vtep_ip
;
1027 struct prefix_evpn p
;
1029 if (psize
!= BGP_EVPN_TYPE1_PSIZE
) {
1030 flog_err(EC_BGP_EVPN_ROUTE_INVALID
,
1031 "%u:%s - Rx EVPN Type-1 NLRI with invalid length %d",
1032 peer
->bgp
->vrf_id
, peer
->host
, psize
);
1036 /* Make prefix_rd */
1037 prd
.family
= AF_UNSPEC
;
1039 memcpy(&prd
.val
, pfx
, RD_BYTES
);
1043 memcpy(&esi
, pfx
, ESI_BYTES
);
1046 /* Copy Ethernet Tag */
1047 memcpy(ð_tag
, pfx
, EVPN_ETH_TAG_BYTES
);
1048 eth_tag
= ntohl(eth_tag
);
1049 pfx
+= EVPN_ETH_TAG_BYTES
;
1051 memcpy(&label
, pfx
, BGP_LABEL_BYTES
);
1053 /* EAD route prefix doesn't include the nexthop in the global
1057 build_evpn_type1_prefix(&p
, eth_tag
, &esi
, vtep_ip
);
1058 /* Process the route. */
1060 ret
= bgp_update(peer
, (struct prefix
*)&p
, addpath_id
, attr
,
1061 afi
, safi
, ZEBRA_ROUTE_BGP
, BGP_ROUTE_NORMAL
,
1062 &prd
, NULL
, 0, 0, NULL
);
1064 ret
= bgp_withdraw(peer
, (struct prefix
*)&p
, addpath_id
, attr
,
1065 afi
, safi
, ZEBRA_ROUTE_BGP
, BGP_ROUTE_NORMAL
,
1066 &prd
, NULL
, 0, NULL
);
1071 /*****************************************************************************/
1072 /* Ethernet Segment Management
1073 * 1. Ethernet Segment is a collection of links attached to the same
1074 * server (MHD) or switch (MHN)
1075 * 2. An Ethernet Segment can span multiple PEs and is identified by the
1077 * 3. Local ESs are configured in zebra and sent to BGP
1078 * 4. Remote ESs are created by BGP when one or more ES-EVIs reference it i.e.
1079 * created on first reference and release on last de-reference
1080 * 5. An ES can be both local and remote. Infact most local ESs are expected
1081 * to have an ES peer.
1084 /* A list of remote VTEPs is maintained for each ES. This list includes -
1085 * 1. VTEPs for which we have imported the ESR i.e. ES-peers
1086 * 2. VTEPs that have an "active" ES-EVI VTEP i.e. EAD-per-ES and EAD-per-EVI
1087 * have been imported into one or more VNIs
1089 static int bgp_evpn_es_vtep_cmp(void *p1
, void *p2
)
1091 const struct bgp_evpn_es_vtep
*es_vtep1
= p1
;
1092 const struct bgp_evpn_es_vtep
*es_vtep2
= p2
;
1094 return es_vtep1
->vtep_ip
.s_addr
- es_vtep2
->vtep_ip
.s_addr
;
1097 static struct bgp_evpn_es_vtep
*bgp_evpn_es_vtep_new(struct bgp_evpn_es
*es
,
1098 struct in_addr vtep_ip
)
1100 struct bgp_evpn_es_vtep
*es_vtep
;
1102 es_vtep
= XCALLOC(MTYPE_BGP_EVPN_ES_VTEP
, sizeof(*es_vtep
));
1105 es_vtep
->vtep_ip
.s_addr
= vtep_ip
.s_addr
;
1106 listnode_init(&es_vtep
->es_listnode
, es_vtep
);
1107 listnode_add_sort(es
->es_vtep_list
, &es_vtep
->es_listnode
);
1112 static void bgp_evpn_es_vtep_free(struct bgp_evpn_es_vtep
*es_vtep
)
1114 struct bgp_evpn_es
*es
= es_vtep
->es
;
1116 if (CHECK_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ESR
) ||
1118 /* as long as there is some reference we can't free it */
1121 list_delete_node(es
->es_vtep_list
, &es_vtep
->es_listnode
);
1122 XFREE(MTYPE_BGP_EVPN_ES_VTEP
, es_vtep
);
1125 /* check if VTEP is already part of the list */
1126 static struct bgp_evpn_es_vtep
*bgp_evpn_es_vtep_find(struct bgp_evpn_es
*es
,
1127 struct in_addr vtep_ip
)
1129 struct listnode
*node
= NULL
;
1130 struct bgp_evpn_es_vtep
*es_vtep
;
1132 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
1133 if (es_vtep
->vtep_ip
.s_addr
== vtep_ip
.s_addr
)
1139 /* Send the remote ES to zebra for NHG programming */
1140 static int bgp_zebra_send_remote_es_vtep(struct bgp
*bgp
,
1141 struct bgp_evpn_es_vtep
*es_vtep
, bool add
)
1143 struct bgp_evpn_es
*es
= es_vtep
->es
;
1147 if (!zclient
|| zclient
->sock
< 0)
1150 /* Don't try to register if Zebra doesn't know of this instance. */
1151 if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp
)) {
1152 if (BGP_DEBUG(zebra
, ZEBRA
))
1153 zlog_debug("No zebra instance, not installing remote es %s",
1161 zclient_create_header(s
,
1162 add
? ZEBRA_REMOTE_ES_VTEP_ADD
: ZEBRA_REMOTE_ES_VTEP_DEL
,
1164 stream_put(s
, &es
->esi
, sizeof(esi_t
));
1165 stream_put_ipv4(s
, es_vtep
->vtep_ip
.s_addr
);
1167 stream_putw_at(s
, 0, stream_get_endp(s
));
1169 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1170 zlog_debug("Tx %s Remote ESI %s VTEP %pI4", add
? "ADD" : "DEL",
1171 es
->esi_str
, &es_vtep
->vtep_ip
);
1173 return zclient_send_message(zclient
);
1176 static void bgp_evpn_es_vtep_re_eval_active(struct bgp
*bgp
,
1177 struct bgp_evpn_es_vtep
*es_vtep
)
1182 old_active
= !!CHECK_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
);
1183 /* currently we need an active EVI reference to use the VTEP as
1184 * a nexthop. this may change...
1186 if (es_vtep
->evi_cnt
)
1187 SET_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
);
1189 UNSET_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
);
1191 new_active
= !!CHECK_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
);
1193 if (old_active
== new_active
)
1196 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1197 zlog_debug("es %s vtep %pI4 %s", es_vtep
->es
->esi_str
,
1199 new_active
? "active" : "inactive");
1201 /* send remote ES to zebra */
1202 bgp_zebra_send_remote_es_vtep(bgp
, es_vtep
, new_active
);
1204 /* queue up the es for background consistency checks */
1205 bgp_evpn_es_cons_checks_pend_add(es_vtep
->es
);
1208 static struct bgp_evpn_es_vtep
*bgp_evpn_es_vtep_add(struct bgp
*bgp
,
1209 struct bgp_evpn_es
*es
, struct in_addr vtep_ip
, bool esr
)
1211 struct bgp_evpn_es_vtep
*es_vtep
;
1213 es_vtep
= bgp_evpn_es_vtep_find(es
, vtep_ip
);
1216 es_vtep
= bgp_evpn_es_vtep_new(es
, vtep_ip
);
1218 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1219 zlog_debug("es %s vtep %pI4 add %s", es_vtep
->es
->esi_str
,
1220 &es_vtep
->vtep_ip
, esr
? "esr" : "ead");
1223 SET_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ESR
);
1227 bgp_evpn_es_vtep_re_eval_active(bgp
, es_vtep
);
1232 static void bgp_evpn_es_vtep_do_del(struct bgp
*bgp
,
1233 struct bgp_evpn_es_vtep
*es_vtep
, bool esr
)
1235 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1236 zlog_debug("es %s vtep %pI4 del %s", es_vtep
->es
->esi_str
,
1237 &es_vtep
->vtep_ip
, esr
? "esr" : "ead");
1239 UNSET_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ESR
);
1241 if (es_vtep
->evi_cnt
)
1245 bgp_evpn_es_vtep_re_eval_active(bgp
, es_vtep
);
1246 bgp_evpn_es_vtep_free(es_vtep
);
1249 static void bgp_evpn_es_vtep_del(struct bgp
*bgp
,
1250 struct bgp_evpn_es
*es
, struct in_addr vtep_ip
, bool esr
)
1252 struct bgp_evpn_es_vtep
*es_vtep
;
1254 es_vtep
= bgp_evpn_es_vtep_find(es
, vtep_ip
);
1256 bgp_evpn_es_vtep_do_del(bgp
, es_vtep
, esr
);
1259 /* compare ES-IDs for the global ES RB tree */
1260 static int bgp_es_rb_cmp(const struct bgp_evpn_es
*es1
,
1261 const struct bgp_evpn_es
*es2
)
1263 return memcmp(&es1
->esi
, &es2
->esi
, ESI_BYTES
);
1265 RB_GENERATE(bgp_es_rb_head
, bgp_evpn_es
, rb_node
, bgp_es_rb_cmp
);
1267 struct bgp_evpn_es
*bgp_evpn_es_find(const esi_t
*esi
)
1269 struct bgp_evpn_es tmp
;
1271 memcpy(&tmp
.esi
, esi
, sizeof(esi_t
));
1272 return RB_FIND(bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
, &tmp
);
1275 static struct bgp_evpn_es
*bgp_evpn_es_new(struct bgp
*bgp
, const esi_t
*esi
)
1277 struct bgp_evpn_es
*es
;
1282 es
= XCALLOC(MTYPE_BGP_EVPN_ES
, sizeof(struct bgp_evpn_es
));
1285 memcpy(&es
->esi
, esi
, sizeof(esi_t
));
1287 /* Initialise the VTEP list */
1288 es
->es_vtep_list
= list_new();
1289 listset_app_node_mem(es
->es_vtep_list
);
1290 es
->es_vtep_list
->cmp
= bgp_evpn_es_vtep_cmp
;
1292 esi_to_str(&es
->esi
, es
->esi_str
, sizeof(es
->esi_str
));
1294 /* Initialize the ES routing table */
1295 es
->route_table
= bgp_table_init(bgp
, AFI_L2VPN
, SAFI_EVPN
);
1297 /* Add to rb_tree */
1298 if (RB_INSERT(bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
, es
)) {
1299 XFREE(MTYPE_BGP_EVPN_ES
, es
);
1303 /* Initialise the ES-EVI list */
1304 es
->es_evi_list
= list_new();
1305 listset_app_node_mem(es
->es_evi_list
);
1307 QOBJ_REG(es
, bgp_evpn_es
);
1312 /* Free a given ES -
1313 * This just frees appropriate memory, caller should have taken other
1316 static void bgp_evpn_es_free(struct bgp_evpn_es
*es
, const char *caller
)
1318 if (es
->flags
& (BGP_EVPNES_LOCAL
| BGP_EVPNES_REMOTE
))
1321 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1322 zlog_debug("%s: es %s free", caller
, es
->esi_str
);
1324 /* cleanup resources maintained against the ES */
1325 list_delete(&es
->es_evi_list
);
1326 list_delete(&es
->es_vtep_list
);
1327 bgp_table_unlock(es
->route_table
);
1329 /* remove the entry from various databases */
1330 RB_REMOVE(bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
, es
);
1331 bgp_evpn_es_cons_checks_pend_del(es
);
1334 XFREE(MTYPE_BGP_EVPN_ES
, es
);
1337 /* init local info associated with the ES */
1338 static void bgp_evpn_es_local_info_set(struct bgp
*bgp
, struct bgp_evpn_es
*es
)
1340 char buf
[BGP_EVPN_PREFIX_RD_LEN
];
1342 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_LOCAL
))
1345 SET_FLAG(es
->flags
, BGP_EVPNES_LOCAL
);
1346 listnode_init(&es
->es_listnode
, es
);
1347 listnode_add(bgp_mh_info
->local_es_list
, &es
->es_listnode
);
1349 /* auto derive RD for this es */
1350 bf_assign_index(bm
->rd_idspace
, es
->rd_id
);
1351 es
->prd
.family
= AF_UNSPEC
;
1352 es
->prd
.prefixlen
= 64;
1353 snprintfrr(buf
, sizeof(buf
), "%pI4:%hu", &bgp
->router_id
, es
->rd_id
);
1354 (void)str2prefix_rd(buf
, &es
->prd
);
1357 /* clear any local info associated with the ES */
1358 static void bgp_evpn_es_local_info_clear(struct bgp_evpn_es
*es
)
1360 if (!CHECK_FLAG(es
->flags
, BGP_EVPNES_LOCAL
))
1363 UNSET_FLAG(es
->flags
, BGP_EVPNES_LOCAL
);
1365 /* remove from the ES local list */
1366 list_delete_node(bgp_mh_info
->local_es_list
, &es
->es_listnode
);
1368 bf_release_index(bm
->rd_idspace
, es
->rd_id
);
1370 bgp_evpn_es_free(es
, __func__
);
1373 /* eval remote info associated with the ES */
1374 static void bgp_evpn_es_remote_info_re_eval(struct bgp_evpn_es
*es
)
1376 if (es
->remote_es_evi_cnt
) {
1377 SET_FLAG(es
->flags
, BGP_EVPNES_REMOTE
);
1379 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_REMOTE
)) {
1380 UNSET_FLAG(es
->flags
, BGP_EVPNES_REMOTE
);
1381 bgp_evpn_es_free(es
, __func__
);
1386 /* Process ES link oper-down by withdrawing ES-EAD and ESR */
1387 static void bgp_evpn_local_es_down(struct bgp
*bgp
,
1388 struct bgp_evpn_es
*es
)
1390 struct prefix_evpn p
;
1393 if (!CHECK_FLAG(es
->flags
, BGP_EVPNES_OPER_UP
))
1396 UNSET_FLAG(es
->flags
, BGP_EVPNES_OPER_UP
);
1398 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1399 zlog_debug("local es %s down", es
->esi_str
);
1402 /* Delete and withdraw locally learnt ES route */
1403 build_evpn_type4_prefix(&p
, &es
->esi
, es
->originator_ip
);
1404 ret
= bgp_evpn_type4_route_delete(bgp
, es
, &p
);
1406 flog_err(EC_BGP_EVPN_ROUTE_DELETE
,
1407 "%u failed to delete type-4 route for ESI %s",
1408 bgp
->vrf_id
, es
->esi_str
);
1411 /* withdraw EAD-EVI */
1412 if (!bgp_mh_info
->ead_evi_adv_for_down_links
)
1413 bgp_evpn_local_type1_evi_route_del(bgp
, es
);
1415 /* withdraw EAD-ES */
1416 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_ES_ETH_TAG
,
1417 &es
->esi
, es
->originator_ip
);
1418 ret
= bgp_evpn_type1_es_route_delete(bgp
, es
, &p
);
1420 flog_err(EC_BGP_EVPN_ROUTE_DELETE
,
1421 "%u failed to delete type-1 route for ESI %s",
1422 bgp
->vrf_id
, es
->esi_str
);
1426 /* Process ES link oper-up by generating ES-EAD and ESR */
1427 static void bgp_evpn_local_es_up(struct bgp
*bgp
, struct bgp_evpn_es
*es
)
1429 struct prefix_evpn p
;
1431 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_OPER_UP
))
1434 SET_FLAG(es
->flags
, BGP_EVPNES_OPER_UP
);
1436 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1437 zlog_debug("local es %s up", es
->esi_str
);
1440 build_evpn_type4_prefix(&p
, &es
->esi
, es
->originator_ip
);
1441 if (bgp_evpn_type4_route_update(bgp
, es
, &p
))
1442 flog_err(EC_BGP_EVPN_ROUTE_CREATE
,
1443 "%u: Type4 route creation failure for ESI %s",
1444 bgp
->vrf_id
, es
->esi_str
);
1446 /* generate EAD-EVI */
1447 bgp_evpn_local_type1_evi_route_add(bgp
, es
);
1449 /* generate EAD-ES */
1450 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_ES_ETH_TAG
,
1451 &es
->esi
, es
->originator_ip
);
1452 bgp_evpn_type1_route_update(bgp
, es
, NULL
, &p
);
1455 static void bgp_evpn_local_es_do_del(struct bgp
*bgp
, struct bgp_evpn_es
*es
)
1457 struct bgp_evpn_es_evi
*es_evi
;
1458 struct listnode
*evi_node
, *evi_next_node
;
1460 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1461 zlog_debug("del local es %s", es
->esi_str
);
1463 /* Delete all local EVPN ES routes from ESI table
1464 * and schedule for processing (to withdraw from peers))
1466 bgp_evpn_es_route_del_all(bgp
, es
);
1468 /* release all local ES EVIs associated with the ES */
1469 for (ALL_LIST_ELEMENTS(es
->es_evi_list
, evi_node
,
1470 evi_next_node
, es_evi
)) {
1471 bgp_evpn_local_es_evi_do_del(es_evi
);
1474 /* Clear local info associated with the ES and free it up if there is
1475 * no remote reference
1477 bgp_evpn_es_local_info_clear(es
);
1480 bool bgp_evpn_is_esi_local(esi_t
*esi
)
1482 struct bgp_evpn_es
*es
= NULL
;
1484 /* Lookup ESI hash - should exist. */
1485 es
= bgp_evpn_es_find(esi
);
1486 return es
? !!(es
->flags
& BGP_EVPNES_LOCAL
) : false;
1489 int bgp_evpn_local_es_del(struct bgp
*bgp
, esi_t
*esi
)
1491 struct bgp_evpn_es
*es
= NULL
;
1493 /* Lookup ESI hash - should exist. */
1494 es
= bgp_evpn_es_find(esi
);
1496 flog_warn(EC_BGP_EVPN_ESI
,
1497 "%u: ES %s missing at local ES DEL",
1498 bgp
->vrf_id
, es
->esi_str
);
1502 bgp_evpn_local_es_do_del(bgp
, es
);
1506 /* Handle device to ES id association. Results in the creation of a local
1509 int bgp_evpn_local_es_add(struct bgp
*bgp
, esi_t
*esi
,
1510 struct in_addr originator_ip
, bool oper_up
)
1512 char buf
[ESI_STR_LEN
];
1513 struct bgp_evpn_es
*es
;
1516 /* create the new es */
1517 es
= bgp_evpn_es_find(esi
);
1519 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_LOCAL
))
1522 es
= bgp_evpn_es_new(bgp
, esi
);
1524 flog_err(EC_BGP_ES_CREATE
,
1525 "%u: Failed to allocate ES entry for ESI %s - at Local ES Add",
1526 bgp
->vrf_id
, esi_to_str(esi
, buf
, sizeof(buf
)));
1531 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1532 zlog_debug("add local es %s orig-ip %pI4", es
->esi_str
,
1535 es
->originator_ip
= originator_ip
;
1536 bgp_evpn_es_local_info_set(bgp
, es
);
1538 /* import all remote Type-4 routes in the ES table */
1540 bgp_evpn_type4_remote_routes_import(bgp
, es
,
1541 true /* install */);
1543 /* create and advertise EAD-EVI routes for the ES -
1544 * XXX - till an ES-EVI reference is created there is really nothing to
1547 if (bgp_mh_info
->ead_evi_adv_for_down_links
)
1548 bgp_evpn_local_type1_evi_route_add(bgp
, es
);
1550 /* If the ES link is operationally up generate EAD-ES. EAD-EVI
1551 * can be generated even if the link is inactive.
1554 bgp_evpn_local_es_up(bgp
, es
);
1556 bgp_evpn_local_es_down(bgp
, es
);
1561 static char *bgp_evpn_es_vteps_str(char *vtep_str
, struct bgp_evpn_es
*es
,
1562 uint8_t vtep_str_size
)
1564 char vtep_flag_str
[BGP_EVPN_FLAG_STR_SZ
];
1565 struct listnode
*node
;
1566 struct bgp_evpn_es_vtep
*es_vtep
;
1568 char vtep_ip
[BUFSIZ
] = {0};
1571 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
1572 vtep_flag_str
[0] = '\0';
1574 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ESR
)
1575 strlcat(vtep_flag_str
, "E", sizeof(vtep_flag_str
));
1576 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ACTIVE
)
1577 strlcat(vtep_flag_str
, "A", sizeof(vtep_flag_str
));
1579 if (!strlen(vtep_flag_str
))
1580 strlcat(vtep_flag_str
, "-", sizeof(vtep_flag_str
));
1584 strlcat(vtep_str
, ",", vtep_str_size
);
1587 inet_ntop(AF_INET
, &es_vtep
->vtep_ip
, vtep_ip
,
1590 strlcat(vtep_str
, "(", vtep_str_size
);
1591 strlcat(vtep_str
, vtep_flag_str
, vtep_str_size
);
1592 strlcat(vtep_str
, ")", vtep_str_size
);
1598 static inline void json_array_string_add(json_object
*json
, const char *str
)
1600 json_object_array_add(json
, json_object_new_string(str
));
1603 static void bgp_evpn_es_json_vtep_fill(json_object
*json_vteps
,
1604 struct bgp_evpn_es_vtep
*es_vtep
)
1606 json_object
*json_vtep_entry
;
1607 json_object
*json_flags
;
1608 char vtep_ip
[BUFSIZ
] = {0};
1610 json_vtep_entry
= json_object_new_object();
1612 json_object_string_add(json_vtep_entry
, "vtep_ip",
1613 inet_ntop(AF_INET
, &es_vtep
->vtep_ip
, vtep_ip
,
1616 if (es_vtep
->flags
& (BGP_EVPNES_VTEP_ESR
|
1617 BGP_EVPNES_VTEP_ACTIVE
)) {
1618 json_flags
= json_object_new_array();
1619 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ESR
)
1620 json_array_string_add(json_flags
, "esr");
1621 if (es_vtep
->flags
& BGP_EVPNES_VTEP_ACTIVE
)
1622 json_array_string_add(json_flags
, "active");
1623 json_object_object_add(json_vtep_entry
, "flags", json_flags
);
1626 json_object_array_add(json_vteps
,
1630 static void bgp_evpn_es_show_entry(struct vty
*vty
,
1631 struct bgp_evpn_es
*es
, json_object
*json
)
1633 char buf1
[RD_ADDRSTRLEN
];
1634 struct listnode
*node
;
1635 struct bgp_evpn_es_vtep
*es_vtep
;
1638 json_object
*json_vteps
;
1639 json_object
*json_types
;
1641 json_object_string_add(json
, "esi", es
->esi_str
);
1642 json_object_string_add(json
, "rd",
1643 prefix_rd2str(&es
->prd
, buf1
,
1646 if (es
->flags
& (BGP_EVPNES_LOCAL
| BGP_EVPNES_REMOTE
)) {
1647 json_types
= json_object_new_array();
1648 if (es
->flags
& BGP_EVPNES_LOCAL
)
1649 json_array_string_add(json_types
, "local");
1650 if (es
->flags
& BGP_EVPNES_REMOTE
)
1651 json_array_string_add(json_types
, "remote");
1652 json_object_object_add(json
, "type", json_types
);
1655 if (listcount(es
->es_vtep_list
)) {
1656 json_vteps
= json_object_new_array();
1657 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
,
1659 bgp_evpn_es_json_vtep_fill(json_vteps
, es_vtep
);
1661 json_object_object_add(json
, "vteps", json_vteps
);
1663 json_object_int_add(json
, "vniCount",
1664 listcount(es
->es_evi_list
));
1667 char vtep_str
[ES_VTEP_LIST_STR_SZ
+ BGP_EVPN_VTEPS_FLAG_STR_SZ
];
1670 if (es
->flags
& BGP_EVPNES_LOCAL
)
1671 strlcat(type_str
, "L", sizeof(type_str
));
1672 if (es
->flags
& BGP_EVPNES_REMOTE
)
1673 strlcat(type_str
, "R", sizeof(type_str
));
1674 if (es
->inconsistencies
)
1675 strlcat(type_str
, "I", sizeof(type_str
));
1677 bgp_evpn_es_vteps_str(vtep_str
, es
, sizeof(vtep_str
));
1679 if (es
->flags
& BGP_EVPNES_LOCAL
)
1680 prefix_rd2str(&es
->prd
, buf1
, sizeof(buf1
));
1682 strlcpy(buf1
, "-", sizeof(buf1
));
1684 vty_out(vty
, "%-30s %-5s %-21s %-8d %s\n",
1685 es
->esi_str
, type_str
, buf1
,
1686 listcount(es
->es_evi_list
), vtep_str
);
1690 static void bgp_evpn_es_show_entry_detail(struct vty
*vty
,
1691 struct bgp_evpn_es
*es
, json_object
*json
)
1693 char originator_ip
[BUFSIZ
] = {0};
1696 json_object
*json_flags
;
1697 json_object
*json_incons
;
1699 /* Add the "brief" info first */
1700 bgp_evpn_es_show_entry(vty
, es
, json
);
1701 if (es
->flags
& (BGP_EVPNES_OPER_UP
| BGP_EVPNES_ADV_EVI
)) {
1702 json_flags
= json_object_new_array();
1703 if (es
->flags
& BGP_EVPNES_OPER_UP
)
1704 json_array_string_add(json_flags
, "up");
1705 if (es
->flags
& BGP_EVPNES_ADV_EVI
)
1706 json_array_string_add(json_flags
,
1708 json_object_object_add(json
, "flags", json_flags
);
1710 json_object_string_add(json
, "originator_ip",
1711 inet_ntop(AF_INET
, &es
->originator_ip
,
1713 sizeof(originator_ip
)));
1714 json_object_int_add(json
, "remoteVniCount",
1715 es
->remote_es_evi_cnt
);
1716 json_object_int_add(json
, "inconsistentVniVtepCount",
1717 es
->incons_evi_vtep_cnt
);
1718 if (es
->inconsistencies
) {
1719 json_incons
= json_object_new_array();
1720 if (es
->inconsistencies
& BGP_EVPNES_INCONS_VTEP_LIST
)
1721 json_array_string_add(json_incons
,
1722 "vni-vtep-mismatch");
1723 json_object_object_add(json
, "inconsistencies",
1727 char incons_str
[BGP_EVPNES_INCONS_STR_SZ
];
1729 char vtep_str
[ES_VTEP_LIST_STR_SZ
+ BGP_EVPN_VTEPS_FLAG_STR_SZ
];
1730 char buf1
[RD_ADDRSTRLEN
];
1733 if (es
->flags
& BGP_EVPNES_LOCAL
)
1734 strlcat(type_str
, "L", sizeof(type_str
));
1735 if (es
->flags
& BGP_EVPNES_REMOTE
)
1736 strlcat(type_str
, "R", sizeof(type_str
));
1738 bgp_evpn_es_vteps_str(vtep_str
, es
, sizeof(vtep_str
));
1739 if (!strlen(vtep_str
))
1740 strlcpy(buf1
, "-", sizeof(buf1
));
1742 if (es
->flags
& BGP_EVPNES_LOCAL
)
1743 prefix_rd2str(&es
->prd
, buf1
, sizeof(buf1
));
1745 strlcpy(buf1
, "-", sizeof(buf1
));
1747 vty_out(vty
, "ESI: %s\n", es
->esi_str
);
1748 vty_out(vty
, " Type: %s\n", type_str
);
1749 vty_out(vty
, " RD: %s\n", buf1
);
1750 vty_out(vty
, " Originator-IP: %pI4\n", &es
->originator_ip
);
1751 vty_out(vty
, " VNI Count: %d\n", listcount(es
->es_evi_list
));
1752 vty_out(vty
, " Remote VNI Count: %d\n",
1753 es
->remote_es_evi_cnt
);
1754 vty_out(vty
, " Inconsistent VNI VTEP Count: %d\n",
1755 es
->incons_evi_vtep_cnt
);
1756 if (es
->inconsistencies
) {
1757 incons_str
[0] = '\0';
1758 if (es
->inconsistencies
& BGP_EVPNES_INCONS_VTEP_LIST
)
1759 strlcat(incons_str
, "vni-vtep-mismatch",
1760 sizeof(incons_str
));
1762 strlcpy(incons_str
, "-", sizeof(incons_str
));
1764 vty_out(vty
, " Inconsistencies: %s\n",
1766 vty_out(vty
, " VTEPs: %s\n", vtep_str
);
1771 /* Display all ESs */
1772 void bgp_evpn_es_show(struct vty
*vty
, bool uj
, bool detail
)
1774 struct bgp_evpn_es
*es
;
1775 json_object
*json_array
= NULL
;
1776 json_object
*json
= NULL
;
1779 /* create an array of ESs */
1780 json_array
= json_object_new_array();
1784 "ES Flags: L local, R remote, I inconsistent\n");
1786 "VTEP Flags: E ESR/Type-4, A active nexthop\n");
1788 "%-30s %-5s %-21s %-8s %s\n",
1789 "ESI", "Flags", "RD", "#VNIs", "VTEPs");
1793 RB_FOREACH(es
, bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
) {
1795 /* create a separate json object for each ES */
1796 json
= json_object_new_object();
1798 bgp_evpn_es_show_entry_detail(vty
, es
, json
);
1800 bgp_evpn_es_show_entry(vty
, es
, json
);
1801 /* add ES to the json array */
1803 json_object_array_add(json_array
, json
);
1806 /* print the array of json-ESs */
1808 vty_out(vty
, "%s\n", json_object_to_json_string_ext(
1809 json_array
, JSON_C_TO_STRING_PRETTY
));
1810 json_object_free(json_array
);
1814 /* Display specific ES */
1815 void bgp_evpn_es_show_esi(struct vty
*vty
, esi_t
*esi
, bool uj
)
1817 struct bgp_evpn_es
*es
;
1818 json_object
*json
= NULL
;
1821 json
= json_object_new_object();
1823 es
= bgp_evpn_es_find(esi
);
1825 bgp_evpn_es_show_entry_detail(vty
, es
, json
);
1828 vty_out(vty
, "ESI not found\n");
1832 vty_out(vty
, "%s\n", json_object_to_json_string_ext(
1833 json
, JSON_C_TO_STRING_PRETTY
));
1834 json_object_free(json
);
1838 /*****************************************************************************/
1839 /* Ethernet Segment to EVI association -
1840 * 1. The ES-EVI entry is maintained as a RB tree per L2-VNI
1841 * (bgpevpn->es_evi_rb_tree).
1842 * 2. Each local ES-EVI entry is rxed from zebra and then used by BGP to
1843 * advertises an EAD-EVI (Type-1 EVPN) route
1844 * 3. The remote ES-EVI is created when a bgp_evpn_es_evi_vtep references
1848 /* A list of remote VTEPs is maintained for each ES-EVI. This list includes -
1849 * 1. VTEPs for which we have imported the EAD-per-ES Type1 route
1850 * 2. VTEPs for which we have imported the EAD-per-EVI Type1 route
1851 * VTEPs for which both routes have been rxed are activated. Activation
1852 * creates a NHG in the parent ES.
1854 static int bgp_evpn_es_evi_vtep_cmp(void *p1
, void *p2
)
1856 const struct bgp_evpn_es_evi_vtep
*evi_vtep1
= p1
;
1857 const struct bgp_evpn_es_evi_vtep
*evi_vtep2
= p2
;
1859 return evi_vtep1
->vtep_ip
.s_addr
- evi_vtep2
->vtep_ip
.s_addr
;
1862 static struct bgp_evpn_es_evi_vtep
*bgp_evpn_es_evi_vtep_new(
1863 struct bgp_evpn_es_evi
*es_evi
, struct in_addr vtep_ip
)
1865 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
1867 evi_vtep
= XCALLOC(MTYPE_BGP_EVPN_ES_EVI_VTEP
, sizeof(*evi_vtep
));
1869 evi_vtep
->es_evi
= es_evi
;
1870 evi_vtep
->vtep_ip
.s_addr
= vtep_ip
.s_addr
;
1871 listnode_init(&evi_vtep
->es_evi_listnode
, evi_vtep
);
1872 listnode_add_sort(es_evi
->es_evi_vtep_list
, &evi_vtep
->es_evi_listnode
);
1877 static void bgp_evpn_es_evi_vtep_free(struct bgp_evpn_es_evi_vtep
*evi_vtep
)
1879 struct bgp_evpn_es_evi
*es_evi
= evi_vtep
->es_evi
;
1881 if (evi_vtep
->flags
& (BGP_EVPN_EVI_VTEP_EAD
))
1882 /* as long as there is some reference we can't free it */
1885 list_delete_node(es_evi
->es_evi_vtep_list
, &evi_vtep
->es_evi_listnode
);
1886 XFREE(MTYPE_BGP_EVPN_ES_EVI_VTEP
, evi_vtep
);
1889 /* check if VTEP is already part of the list */
1890 static struct bgp_evpn_es_evi_vtep
*bgp_evpn_es_evi_vtep_find(
1891 struct bgp_evpn_es_evi
*es_evi
, struct in_addr vtep_ip
)
1893 struct listnode
*node
= NULL
;
1894 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
1896 for (ALL_LIST_ELEMENTS_RO(es_evi
->es_evi_vtep_list
, node
, evi_vtep
)) {
1897 if (evi_vtep
->vtep_ip
.s_addr
== vtep_ip
.s_addr
)
1903 /* A VTEP can be added as "active" attach to an ES if EAD-per-ES and
1904 * EAD-per-EVI routes are rxed from it.
1906 static void bgp_evpn_es_evi_vtep_re_eval_active(struct bgp
*bgp
,
1907 struct bgp_evpn_es_evi_vtep
*evi_vtep
)
1912 old_active
= !!CHECK_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
);
1914 /* Both EAD-per-ES and EAD-per-EVI routes must be rxed from a PE
1915 * before it can be activated.
1917 if ((evi_vtep
->flags
& BGP_EVPN_EVI_VTEP_EAD
) ==
1918 BGP_EVPN_EVI_VTEP_EAD
)
1919 SET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
);
1921 UNSET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
);
1923 new_active
= !!CHECK_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
);
1925 if (old_active
== new_active
)
1928 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1929 zlog_debug("es %s evi %u vtep %pI4 %s",
1930 evi_vtep
->es_evi
->es
->esi_str
,
1931 evi_vtep
->es_evi
->vpn
->vni
, &evi_vtep
->vtep_ip
,
1932 new_active
? "active" : "inactive");
1934 /* add VTEP to parent es */
1936 struct bgp_evpn_es_vtep
*es_vtep
;
1938 es_vtep
= bgp_evpn_es_vtep_add(bgp
, evi_vtep
->es_evi
->es
,
1939 evi_vtep
->vtep_ip
, false /*esr*/);
1940 evi_vtep
->es_vtep
= es_vtep
;
1942 if (evi_vtep
->es_vtep
) {
1943 bgp_evpn_es_vtep_do_del(bgp
, evi_vtep
->es_vtep
,
1945 evi_vtep
->es_vtep
= NULL
;
1948 /* queue up the parent es for background consistency checks */
1949 bgp_evpn_es_cons_checks_pend_add(evi_vtep
->es_evi
->es
);
1952 static void bgp_evpn_es_evi_vtep_add(struct bgp
*bgp
,
1953 struct bgp_evpn_es_evi
*es_evi
, struct in_addr vtep_ip
,
1956 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
1958 evi_vtep
= bgp_evpn_es_evi_vtep_find(es_evi
, vtep_ip
);
1961 evi_vtep
= bgp_evpn_es_evi_vtep_new(es_evi
, vtep_ip
);
1963 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1964 zlog_debug("add es %s evi %u vtep %pI4 %s",
1965 evi_vtep
->es_evi
->es
->esi_str
,
1966 evi_vtep
->es_evi
->vpn
->vni
, &evi_vtep
->vtep_ip
,
1967 ead_es
? "ead_es" : "ead_evi");
1970 SET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_EAD_PER_ES
);
1972 SET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_EAD_PER_EVI
);
1974 bgp_evpn_es_evi_vtep_re_eval_active(bgp
, evi_vtep
);
1977 static void bgp_evpn_es_evi_vtep_del(struct bgp
*bgp
,
1978 struct bgp_evpn_es_evi
*es_evi
, struct in_addr vtep_ip
,
1981 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
1983 evi_vtep
= bgp_evpn_es_evi_vtep_find(es_evi
, vtep_ip
);
1987 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
1988 zlog_debug("del es %s evi %u vtep %pI4 %s",
1989 evi_vtep
->es_evi
->es
->esi_str
,
1990 evi_vtep
->es_evi
->vpn
->vni
, &evi_vtep
->vtep_ip
,
1991 ead_es
? "ead_es" : "ead_evi");
1994 UNSET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_EAD_PER_ES
);
1996 UNSET_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_EAD_PER_EVI
);
1998 bgp_evpn_es_evi_vtep_re_eval_active(bgp
, evi_vtep
);
1999 bgp_evpn_es_evi_vtep_free(evi_vtep
);
2002 /* compare ES-IDs for the ES-EVI RB tree maintained per-VNI */
2003 static int bgp_es_evi_rb_cmp(const struct bgp_evpn_es_evi
*es_evi1
,
2004 const struct bgp_evpn_es_evi
*es_evi2
)
2006 return memcmp(&es_evi1
->es
->esi
, &es_evi2
->es
->esi
, ESI_BYTES
);
2008 RB_GENERATE(bgp_es_evi_rb_head
, bgp_evpn_es_evi
, rb_node
, bgp_es_evi_rb_cmp
);
2010 /* find the ES-EVI in the per-L2-VNI RB tree */
2011 static struct bgp_evpn_es_evi
*bgp_evpn_es_evi_find(struct bgp_evpn_es
*es
,
2012 struct bgpevpn
*vpn
)
2014 struct bgp_evpn_es_evi es_evi
;
2018 return RB_FIND(bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
, &es_evi
);
2021 /* allocate a new ES-EVI and insert it into the per-L2-VNI and per-ES
2024 static struct bgp_evpn_es_evi
*bgp_evpn_es_evi_new(struct bgp_evpn_es
*es
,
2025 struct bgpevpn
*vpn
)
2027 struct bgp_evpn_es_evi
*es_evi
;
2029 es_evi
= XCALLOC(MTYPE_BGP_EVPN_ES_EVI
, sizeof(*es_evi
));
2034 /* Initialise the VTEP list */
2035 es_evi
->es_evi_vtep_list
= list_new();
2036 listset_app_node_mem(es_evi
->es_evi_vtep_list
);
2037 es_evi
->es_evi_vtep_list
->cmp
= bgp_evpn_es_evi_vtep_cmp
;
2039 /* insert into the VNI-ESI rb tree */
2040 if (RB_INSERT(bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
, es_evi
)) {
2041 XFREE(MTYPE_BGP_EVPN_ES_EVI
, es_evi
);
2045 /* add to the ES's VNI list */
2046 listnode_init(&es_evi
->es_listnode
, es_evi
);
2047 listnode_add(es
->es_evi_list
, &es_evi
->es_listnode
);
2052 /* remove the ES-EVI from the per-L2-VNI and per-ES tables and free
2055 static void bgp_evpn_es_evi_free(struct bgp_evpn_es_evi
*es_evi
)
2057 struct bgp_evpn_es
*es
= es_evi
->es
;
2058 struct bgpevpn
*vpn
= es_evi
->vpn
;
2060 /* cannot free the element as long as there is a local or remote
2063 if (es_evi
->flags
& (BGP_EVPNES_EVI_LOCAL
| BGP_EVPNES_EVI_REMOTE
))
2066 /* remove from the ES's VNI list */
2067 list_delete_node(es
->es_evi_list
, &es_evi
->es_listnode
);
2069 /* remove from the VNI-ESI rb tree */
2070 RB_REMOVE(bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
, es_evi
);
2072 /* free the VTEP list */
2073 list_delete(&es_evi
->es_evi_vtep_list
);
2075 /* remove from the VNI-ESI rb tree */
2076 XFREE(MTYPE_BGP_EVPN_ES_EVI
, es_evi
);
2079 /* init local info associated with the ES-EVI */
2080 static void bgp_evpn_es_evi_local_info_set(struct bgp_evpn_es_evi
*es_evi
)
2082 struct bgpevpn
*vpn
= es_evi
->vpn
;
2084 if (CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
2087 SET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
);
2088 listnode_init(&es_evi
->l2vni_listnode
, es_evi
);
2089 listnode_add(vpn
->local_es_evi_list
, &es_evi
->l2vni_listnode
);
2092 /* clear any local info associated with the ES-EVI */
2093 static void bgp_evpn_es_evi_local_info_clear(struct bgp_evpn_es_evi
*es_evi
)
2095 struct bgpevpn
*vpn
= es_evi
->vpn
;
2097 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
2100 UNSET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
);
2101 list_delete_node(vpn
->local_es_evi_list
, &es_evi
->l2vni_listnode
);
2103 bgp_evpn_es_evi_free(es_evi
);
2106 /* eval remote info associated with the ES */
2107 static void bgp_evpn_es_evi_remote_info_re_eval(struct bgp_evpn_es_evi
*es_evi
)
2109 struct bgp_evpn_es
*es
= es_evi
->es
;
2111 /* if there are remote VTEPs the ES-EVI is classified as "remote" */
2112 if (listcount(es_evi
->es_evi_vtep_list
)) {
2113 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_REMOTE
)) {
2114 SET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_REMOTE
);
2115 ++es
->remote_es_evi_cnt
;
2116 /* set remote on the parent es */
2117 bgp_evpn_es_remote_info_re_eval(es
);
2120 if (CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_REMOTE
)) {
2121 UNSET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_REMOTE
);
2122 if (es
->remote_es_evi_cnt
)
2123 --es
->remote_es_evi_cnt
;
2124 bgp_evpn_es_evi_free(es_evi
);
2125 /* check if "remote" can be cleared from the
2128 bgp_evpn_es_remote_info_re_eval(es
);
2133 static void bgp_evpn_local_es_evi_do_del(struct bgp_evpn_es_evi
*es_evi
)
2135 struct prefix_evpn p
;
2136 struct bgp_evpn_es
*es
= es_evi
->es
;
2139 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
2142 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2143 zlog_debug("del local es %s evi %u",
2144 es_evi
->es
->esi_str
,
2147 bgp
= bgp_get_evpn();
2150 /* update EAD-ES with new list of VNIs */
2151 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_OPER_UP
)) {
2152 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_ES_ETH_TAG
,
2153 &es
->esi
, es
->originator_ip
);
2154 if (bgp_evpn_type1_route_update(bgp
, es
, NULL
, &p
))
2155 flog_err(EC_BGP_EVPN_ROUTE_CREATE
,
2156 "%u: EAD-ES route update failure for ESI %s VNI %u",
2157 bgp
->vrf_id
, es
->esi_str
,
2161 /* withdraw and delete EAD-EVI */
2162 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
)) {
2163 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_EVI_ETH_TAG
,
2164 &es
->esi
, es
->originator_ip
);
2165 if (bgp_evpn_type1_evi_route_delete(bgp
,
2166 es
, es_evi
->vpn
, &p
))
2167 flog_err(EC_BGP_EVPN_ROUTE_DELETE
,
2168 "%u: EAD-EVI route deletion failure for ESI %s VNI %u",
2169 bgp
->vrf_id
, es
->esi_str
,
2174 bgp_evpn_es_evi_local_info_clear(es_evi
);
2178 int bgp_evpn_local_es_evi_del(struct bgp
*bgp
, esi_t
*esi
, vni_t vni
)
2180 struct bgpevpn
*vpn
;
2181 struct bgp_evpn_es
*es
;
2182 struct bgp_evpn_es_evi
*es_evi
;
2183 char buf
[ESI_STR_LEN
];
2185 es
= bgp_evpn_es_find(esi
);
2189 "%u: Failed to deref VNI %d from ESI %s; ES not present",
2191 esi_to_str(esi
, buf
, sizeof(buf
)));
2195 vpn
= bgp_evpn_lookup_vni(bgp
, vni
);
2199 "%u: Failed to deref VNI %d from ESI %s; VNI not present",
2200 bgp
->vrf_id
, vni
, es
->esi_str
);
2204 es_evi
= bgp_evpn_es_evi_find(es
, vpn
);
2208 "%u: Failed to deref VNI %d from ESI %s; ES-VNI not present",
2209 bgp
->vrf_id
, vni
, es
->esi_str
);
2213 bgp_evpn_local_es_evi_do_del(es_evi
);
2217 /* Create ES-EVI and advertise the corresponding EAD routes */
2218 int bgp_evpn_local_es_evi_add(struct bgp
*bgp
, esi_t
*esi
, vni_t vni
)
2220 struct bgpevpn
*vpn
;
2221 struct prefix_evpn p
;
2222 struct bgp_evpn_es
*es
;
2223 struct bgp_evpn_es_evi
*es_evi
;
2224 char buf
[ESI_STR_LEN
];
2226 es
= bgp_evpn_es_find(esi
);
2230 "%u: Failed to associate VNI %d with ESI %s; ES not present",
2232 esi_to_str(esi
, buf
, sizeof(buf
)));
2236 vpn
= bgp_evpn_lookup_vni(bgp
, vni
);
2240 "%u: Failed to associate VNI %d with ESI %s; VNI not present",
2241 bgp
->vrf_id
, vni
, es
->esi_str
);
2245 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2246 zlog_debug("add local es %s evi %u",
2249 es_evi
= bgp_evpn_es_evi_find(es
, vpn
);
2252 if (CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_LOCAL
))
2256 es_evi
= bgp_evpn_es_evi_new(es
, vpn
);
2261 bgp_evpn_es_evi_local_info_set(es_evi
);
2263 /* generate an EAD-EVI for this new VNI */
2264 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_EVI_ETH_TAG
,
2265 &es
->esi
, es
->originator_ip
);
2266 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_ADV_EVI
)) {
2267 if (bgp_evpn_type1_route_update(bgp
, es
, vpn
, &p
))
2268 flog_err(EC_BGP_EVPN_ROUTE_CREATE
,
2269 "%u: EAD-EVI route creation failure for ESI %s VNI %u",
2270 bgp
->vrf_id
, es
->esi_str
, vni
);
2274 build_evpn_type1_prefix(&p
, BGP_EVPN_AD_ES_ETH_TAG
,
2275 &es
->esi
, es
->originator_ip
);
2276 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_OPER_UP
)) {
2277 if (bgp_evpn_type1_route_update(bgp
, es
, NULL
, &p
))
2278 flog_err(EC_BGP_EVPN_ROUTE_CREATE
,
2279 "%u: EAD-ES route creation failure for ESI %s VNI %u",
2280 bgp
->vrf_id
, es
->esi_str
, vni
);
2286 /* Add remote ES-EVI entry. This is actually the remote VTEP add and the
2287 * ES-EVI is implicity created on first VTEP's reference.
2289 int bgp_evpn_remote_es_evi_add(struct bgp
*bgp
, struct bgpevpn
*vpn
,
2290 const struct prefix_evpn
*p
)
2292 char buf
[ESI_STR_LEN
];
2293 struct bgp_evpn_es
*es
;
2294 struct bgp_evpn_es_evi
*es_evi
;
2296 const esi_t
*esi
= &p
->prefix
.ead_addr
.esi
;
2299 /* local EAD-ES need not be sent back to zebra */
2302 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2303 zlog_debug("add remote %s es %s evi %u vtep %pI4",
2304 p
->prefix
.ead_addr
.eth_tag
? "ead-es" : "ead-evi",
2305 esi_to_str(esi
, buf
, sizeof(buf
)), vpn
->vni
,
2306 &p
->prefix
.ead_addr
.ip
.ipaddr_v4
);
2308 es
= bgp_evpn_es_find(esi
);
2310 es
= bgp_evpn_es_new(bgp
, esi
);
2312 flog_err(EC_BGP_ES_CREATE
,
2313 "%u: Failed to allocate ES entry for ESI %s - at remote ES Add",
2314 bgp
->vrf_id
, esi_to_str(esi
, buf
, sizeof(buf
)));
2319 es_evi
= bgp_evpn_es_evi_find(es
, vpn
);
2321 es_evi
= bgp_evpn_es_evi_new(es
, vpn
);
2323 bgp_evpn_es_free(es
, __func__
);
2328 ead_es
= !!p
->prefix
.ead_addr
.eth_tag
;
2329 bgp_evpn_es_evi_vtep_add(bgp
, es_evi
, p
->prefix
.ead_addr
.ip
.ipaddr_v4
,
2332 bgp_evpn_es_evi_remote_info_re_eval(es_evi
);
2336 /* A remote VTEP has withdrawn. The es-evi-vtep will be deleted and the
2337 * parent es-evi freed up implicitly in last VTEP's deref.
2339 int bgp_evpn_remote_es_evi_del(struct bgp
*bgp
, struct bgpevpn
*vpn
,
2340 const struct prefix_evpn
*p
)
2342 char buf
[ESI_STR_LEN
];
2343 struct bgp_evpn_es
*es
;
2344 struct bgp_evpn_es_evi
*es_evi
;
2348 /* local EAD-ES need not be sent back to zebra */
2351 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2353 "del remote %s es %s evi %u vtep %pI4",
2354 p
->prefix
.ead_addr
.eth_tag
? "ead-es" : "ead-evi",
2355 esi_to_str(&p
->prefix
.ead_addr
.esi
, buf
, sizeof(buf
)),
2356 vpn
->vni
, &p
->prefix
.ead_addr
.ip
.ipaddr_v4
);
2358 es
= bgp_evpn_es_find(&p
->prefix
.ead_addr
.esi
);
2360 /* XXX - error logs */
2362 es_evi
= bgp_evpn_es_evi_find(es
, vpn
);
2364 /* XXX - error logs */
2367 ead_es
= !!p
->prefix
.ead_addr
.eth_tag
;
2368 bgp_evpn_es_evi_vtep_del(bgp
, es_evi
, p
->prefix
.ead_addr
.ip
.ipaddr_v4
,
2370 bgp_evpn_es_evi_remote_info_re_eval(es_evi
);
2374 /* Initialize the ES tables maintained per-L2_VNI */
2375 void bgp_evpn_vni_es_init(struct bgpevpn
*vpn
)
2377 /* Initialize the ES-EVI RB tree */
2378 RB_INIT(bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
);
2380 /* Initialize the local list maintained for quick walks by type */
2381 vpn
->local_es_evi_list
= list_new();
2382 listset_app_node_mem(vpn
->local_es_evi_list
);
2385 /* Cleanup the ES info maintained per-L2_VNI */
2386 void bgp_evpn_vni_es_cleanup(struct bgpevpn
*vpn
)
2388 struct bgp_evpn_es_evi
*es_evi
;
2389 struct bgp_evpn_es_evi
*es_evi_next
;
2391 RB_FOREACH_SAFE(es_evi
, bgp_es_evi_rb_head
,
2392 &vpn
->es_evi_rb_tree
, es_evi_next
) {
2393 bgp_evpn_local_es_evi_do_del(es_evi
);
2396 list_delete(&vpn
->local_es_evi_list
);
2399 static char *bgp_evpn_es_evi_vteps_str(char *vtep_str
,
2400 struct bgp_evpn_es_evi
*es_evi
,
2401 uint8_t vtep_str_size
)
2403 char vtep_flag_str
[BGP_EVPN_FLAG_STR_SZ
];
2404 struct listnode
*node
;
2405 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
2407 char vtep_ip
[BUFSIZ
] = {0};
2410 for (ALL_LIST_ELEMENTS_RO(es_evi
->es_evi_vtep_list
, node
, evi_vtep
)) {
2411 vtep_flag_str
[0] = '\0';
2412 if (evi_vtep
->flags
& BGP_EVPN_EVI_VTEP_EAD_PER_ES
)
2413 strlcat(vtep_flag_str
, "E", sizeof(vtep_flag_str
));
2414 if (evi_vtep
->flags
& BGP_EVPN_EVI_VTEP_EAD_PER_EVI
)
2415 strlcat(vtep_flag_str
, "V", sizeof(vtep_flag_str
));
2417 if (!strnlen(vtep_flag_str
, sizeof(vtep_flag_str
)))
2418 strlcpy(vtep_flag_str
, "-", sizeof(vtep_flag_str
));
2422 strlcat(vtep_str
, ",", vtep_str_size
);
2424 inet_ntop(AF_INET
, &evi_vtep
->vtep_ip
, vtep_ip
,
2427 strlcat(vtep_str
, "(", vtep_str_size
);
2428 strlcat(vtep_str
, vtep_flag_str
, vtep_str_size
);
2429 strlcat(vtep_str
, ")", vtep_str_size
);
2435 static void bgp_evpn_es_evi_json_vtep_fill(json_object
*json_vteps
,
2436 struct bgp_evpn_es_evi_vtep
*evi_vtep
)
2438 json_object
*json_vtep_entry
;
2439 json_object
*json_flags
;
2440 char vtep_ip
[BUFSIZ
] = {0};
2442 json_vtep_entry
= json_object_new_object();
2444 json_object_string_add(json_vtep_entry
, "vtep_ip",
2445 inet_ntop(AF_INET
, &evi_vtep
->vtep_ip
, vtep_ip
,
2448 if (evi_vtep
->flags
& (BGP_EVPN_EVI_VTEP_EAD_PER_ES
|
2449 BGP_EVPN_EVI_VTEP_EAD_PER_EVI
)) {
2450 json_flags
= json_object_new_array();
2451 if (evi_vtep
->flags
& BGP_EVPN_EVI_VTEP_EAD_PER_ES
)
2452 json_array_string_add(json_flags
, "ead-per-es");
2453 if (evi_vtep
->flags
& BGP_EVPN_EVI_VTEP_EAD_PER_EVI
)
2454 json_array_string_add(json_flags
, "ed-per-evi");
2455 json_object_object_add(json_vtep_entry
,
2456 "flags", json_flags
);
2459 json_object_array_add(json_vteps
,
2463 static void bgp_evpn_es_evi_show_entry(struct vty
*vty
,
2464 struct bgp_evpn_es_evi
*es_evi
, json_object
*json
)
2466 struct listnode
*node
;
2467 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
2470 json_object
*json_vteps
;
2471 json_object
*json_types
;
2473 json_object_string_add(json
, "esi", es_evi
->es
->esi_str
);
2474 json_object_int_add(json
, "vni", es_evi
->vpn
->vni
);
2476 if (es_evi
->flags
& (BGP_EVPNES_EVI_LOCAL
|
2477 BGP_EVPNES_EVI_REMOTE
)) {
2478 json_types
= json_object_new_array();
2479 if (es_evi
->flags
& BGP_EVPNES_EVI_LOCAL
)
2480 json_array_string_add(json_types
, "local");
2481 if (es_evi
->flags
& BGP_EVPNES_EVI_REMOTE
)
2482 json_array_string_add(json_types
, "remote");
2483 json_object_object_add(json
, "type", json_types
);
2486 if (listcount(es_evi
->es_evi_vtep_list
)) {
2487 json_vteps
= json_object_new_array();
2488 for (ALL_LIST_ELEMENTS_RO(es_evi
->es_evi_vtep_list
,
2490 bgp_evpn_es_evi_json_vtep_fill(json_vteps
,
2493 json_object_object_add(json
, "vteps", json_vteps
);
2497 char vtep_str
[ES_VTEP_LIST_STR_SZ
+ BGP_EVPN_VTEPS_FLAG_STR_SZ
];
2500 if (es_evi
->flags
& BGP_EVPNES_EVI_LOCAL
)
2501 strlcat(type_str
, "L", sizeof(type_str
));
2502 if (es_evi
->flags
& BGP_EVPNES_EVI_REMOTE
)
2503 strlcat(type_str
, "R", sizeof(type_str
));
2504 if (es_evi
->flags
& BGP_EVPNES_EVI_INCONS_VTEP_LIST
)
2505 strlcat(type_str
, "I", sizeof(type_str
));
2507 bgp_evpn_es_evi_vteps_str(vtep_str
, es_evi
, sizeof(vtep_str
));
2509 vty_out(vty
, "%-8d %-30s %-5s %s\n",
2510 es_evi
->vpn
->vni
, es_evi
->es
->esi_str
,
2511 type_str
, vtep_str
);
2515 static void bgp_evpn_es_evi_show_entry_detail(struct vty
*vty
,
2516 struct bgp_evpn_es_evi
*es_evi
, json_object
*json
)
2519 json_object
*json_flags
;
2521 /* Add the "brief" info first */
2522 bgp_evpn_es_evi_show_entry(vty
, es_evi
, json
);
2523 if (es_evi
->flags
& BGP_EVPNES_EVI_INCONS_VTEP_LIST
) {
2524 json_flags
= json_object_new_array();
2525 json_array_string_add(json_flags
, "es-vtep-mismatch");
2526 json_object_object_add(json
, "flags", json_flags
);
2529 char vtep_str
[ES_VTEP_LIST_STR_SZ
+ BGP_EVPN_VTEPS_FLAG_STR_SZ
];
2533 if (es_evi
->flags
& BGP_EVPNES_EVI_LOCAL
)
2534 strlcat(type_str
, "L", sizeof(type_str
));
2535 if (es_evi
->flags
& BGP_EVPNES_EVI_REMOTE
)
2536 strlcat(type_str
, "R", sizeof(type_str
));
2538 bgp_evpn_es_evi_vteps_str(vtep_str
, es_evi
, sizeof(vtep_str
));
2539 if (!strlen(vtep_str
))
2540 strlcpy(vtep_str
, "-", sizeof(type_str
));
2542 vty_out(vty
, "VNI: %d ESI: %s\n",
2543 es_evi
->vpn
->vni
, es_evi
->es
->esi_str
);
2544 vty_out(vty
, " Type: %s\n", type_str
);
2545 vty_out(vty
, " Inconsistencies: %s\n",
2546 (es_evi
->flags
& BGP_EVPNES_EVI_INCONS_VTEP_LIST
) ?
2547 "es-vtep-mismatch":"-");
2548 vty_out(vty
, " VTEPs: %s\n", vtep_str
);
2553 static void bgp_evpn_es_evi_show_one_vni(struct bgpevpn
*vpn
, struct vty
*vty
,
2554 json_object
*json_array
, bool detail
)
2556 struct bgp_evpn_es_evi
*es_evi
;
2557 json_object
*json
= NULL
;
2559 RB_FOREACH(es_evi
, bgp_es_evi_rb_head
, &vpn
->es_evi_rb_tree
) {
2561 /* create a separate json object for each ES */
2562 json
= json_object_new_object();
2564 bgp_evpn_es_evi_show_entry_detail(vty
, es_evi
, json
);
2566 bgp_evpn_es_evi_show_entry(vty
, es_evi
, json
);
2567 /* add ES to the json array */
2569 json_object_array_add(json_array
, json
);
2573 struct es_evi_show_ctx
{
2579 static void bgp_evpn_es_evi_show_one_vni_hash_cb(struct hash_bucket
*bucket
,
2582 struct bgpevpn
*vpn
= (struct bgpevpn
*)bucket
->data
;
2583 struct es_evi_show_ctx
*wctx
= (struct es_evi_show_ctx
*)ctxt
;
2585 bgp_evpn_es_evi_show_one_vni(vpn
, wctx
->vty
, wctx
->json
, wctx
->detail
);
2588 /* Display all ES EVIs */
2589 void bgp_evpn_es_evi_show(struct vty
*vty
, bool uj
, bool detail
)
2591 json_object
*json_array
= NULL
;
2592 struct es_evi_show_ctx wctx
;
2596 /* create an array of ES-EVIs */
2597 json_array
= json_object_new_array();
2601 wctx
.json
= json_array
;
2602 wctx
.detail
= detail
;
2604 bgp
= bgp_get_evpn();
2606 if (!json_array
&& !detail
) {
2607 vty_out(vty
, "Flags: L local, R remote, I inconsistent\n");
2608 vty_out(vty
, "VTEP-Flags: E EAD-per-ES, V EAD-per-EVI\n");
2609 vty_out(vty
, "%-8s %-30s %-5s %s\n",
2610 "VNI", "ESI", "Flags", "VTEPs");
2614 hash_iterate(bgp
->vnihash
,
2615 (void (*)(struct hash_bucket
*,
2616 void *))bgp_evpn_es_evi_show_one_vni_hash_cb
,
2619 vty_out(vty
, "%s\n", json_object_to_json_string_ext(
2620 json_array
, JSON_C_TO_STRING_PRETTY
));
2621 json_object_free(json_array
);
2625 /* Display specific ES EVI */
2626 void bgp_evpn_es_evi_show_vni(struct vty
*vty
, vni_t vni
,
2627 bool uj
, bool detail
)
2629 struct bgpevpn
*vpn
= NULL
;
2630 json_object
*json_array
= NULL
;
2634 /* create an array of ES-EVIs */
2635 json_array
= json_object_new_array();
2638 bgp
= bgp_get_evpn();
2640 vpn
= bgp_evpn_lookup_vni(bgp
, vni
);
2643 if (!json_array
&& !detail
) {
2644 vty_out(vty
, "Flags: L local, R remote, I inconsistent\n");
2645 vty_out(vty
, "VTEP-Flags: E EAD-per-ES, V EAD-per-EVI\n");
2646 vty_out(vty
, "%-8s %-30s %-5s %s\n",
2647 "VNI", "ESI", "Flags", "VTEPs");
2650 bgp_evpn_es_evi_show_one_vni(vpn
, vty
, json_array
, detail
);
2653 vty_out(vty
, "VNI not found\n");
2657 vty_out(vty
, "%s\n", json_object_to_json_string_ext(
2658 json_array
, JSON_C_TO_STRING_PRETTY
));
2659 json_object_free(json_array
);
2663 /*****************************************************************************
2664 * Ethernet Segment Consistency checks
2665 * Consistency checking is done to detect misconfig or mis-cabling. When
2666 * an inconsistency is detected it is simply logged (and displayed via
2667 * show commands) at this point. A more drastic action can be executed (based
2668 * on user config) in the future.
2670 /* queue up the es for background consistency checks */
2671 static void bgp_evpn_es_cons_checks_pend_add(struct bgp_evpn_es
*es
)
2673 if (!bgp_mh_info
->consistency_checking
)
2674 /* consistency checking is not enabled */
2677 if (CHECK_FLAG(es
->flags
, BGP_EVPNES_CONS_CHECK_PEND
))
2678 /* already queued for consistency checking */
2681 SET_FLAG(es
->flags
, BGP_EVPNES_CONS_CHECK_PEND
);
2682 listnode_init(&es
->pend_es_listnode
, es
);
2683 listnode_add_after(bgp_mh_info
->pend_es_list
,
2684 listtail_unchecked(bgp_mh_info
->pend_es_list
),
2685 &es
->pend_es_listnode
);
2688 /* pull the ES from the consistency check list */
2689 static void bgp_evpn_es_cons_checks_pend_del(struct bgp_evpn_es
*es
)
2691 if (!CHECK_FLAG(es
->flags
, BGP_EVPNES_CONS_CHECK_PEND
))
2694 UNSET_FLAG(es
->flags
, BGP_EVPNES_CONS_CHECK_PEND
);
2695 list_delete_node(bgp_mh_info
->pend_es_list
,
2696 &es
->pend_es_listnode
);
2699 /* Number of active VTEPs associated with the ES-per-EVI */
2700 static uint32_t bgp_evpn_es_evi_get_active_vtep_cnt(
2701 struct bgp_evpn_es_evi
*es_evi
)
2703 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
2704 struct listnode
*node
;
2705 uint32_t vtep_cnt
= 0;
2707 for (ALL_LIST_ELEMENTS_RO(es_evi
->es_evi_vtep_list
, node
, evi_vtep
)) {
2708 if (CHECK_FLAG(evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
))
2715 /* Number of active VTEPs associated with the ES */
2716 static uint32_t bgp_evpn_es_get_active_vtep_cnt(struct bgp_evpn_es
*es
)
2718 struct listnode
*node
;
2719 uint32_t vtep_cnt
= 0;
2720 struct bgp_evpn_es_vtep
*es_vtep
;
2722 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
2723 if (CHECK_FLAG(es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
))
2730 static struct bgp_evpn_es_vtep
*bgp_evpn_es_get_next_active_vtep(
2731 struct bgp_evpn_es
*es
, struct bgp_evpn_es_vtep
*es_vtep
)
2733 struct listnode
*node
;
2734 struct bgp_evpn_es_vtep
*next_es_vtep
;
2737 node
= listnextnode_unchecked(&es_vtep
->es_listnode
);
2739 node
= listhead(es
->es_vtep_list
);
2741 for (; node
; node
= listnextnode_unchecked(node
)) {
2742 next_es_vtep
= listgetdata(node
);
2743 if (CHECK_FLAG(next_es_vtep
->flags
, BGP_EVPNES_VTEP_ACTIVE
))
2744 return next_es_vtep
;
2750 static struct bgp_evpn_es_evi_vtep
*bgp_evpn_es_evi_get_next_active_vtep(
2751 struct bgp_evpn_es_evi
*es_evi
,
2752 struct bgp_evpn_es_evi_vtep
*evi_vtep
)
2754 struct listnode
*node
;
2755 struct bgp_evpn_es_evi_vtep
*next_evi_vtep
;
2758 node
= listnextnode_unchecked(&evi_vtep
->es_evi_listnode
);
2760 node
= listhead(es_evi
->es_evi_vtep_list
);
2762 for (; node
; node
= listnextnode_unchecked(node
)) {
2763 next_evi_vtep
= listgetdata(node
);
2764 if (CHECK_FLAG(next_evi_vtep
->flags
, BGP_EVPN_EVI_VTEP_ACTIVE
))
2765 return next_evi_vtep
;
2771 static void bgp_evpn_es_evi_set_inconsistent(struct bgp_evpn_es_evi
*es_evi
)
2773 if (!CHECK_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_INCONS_VTEP_LIST
)) {
2774 if (BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2775 zlog_debug("inconsistency detected - es %s evi %u vtep list mismatch",
2776 es_evi
->es
->esi_str
,
2778 SET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_INCONS_VTEP_LIST
);
2780 /* update parent ES with the incosistency setting */
2781 if (!es_evi
->es
->incons_evi_vtep_cnt
&&
2782 BGP_DEBUG(evpn_mh
, EVPN_MH_ES
))
2783 zlog_debug("inconsistency detected - es %s vtep list mismatch",
2784 es_evi
->es
->esi_str
);
2785 ++es_evi
->es
->incons_evi_vtep_cnt
;
2786 SET_FLAG(es_evi
->es
->inconsistencies
,
2787 BGP_EVPNES_INCONS_VTEP_LIST
);
2791 static uint32_t bgp_evpn_es_run_consistency_checks(struct bgp_evpn_es
*es
)
2794 int es_active_vtep_cnt
;
2795 int evi_active_vtep_cnt
;
2796 struct bgp_evpn_es_evi
*es_evi
;
2797 struct listnode
*evi_node
;
2798 struct bgp_evpn_es_vtep
*es_vtep
;
2799 struct bgp_evpn_es_evi_vtep
*evi_vtep
;
2801 /* reset the inconsistencies and re-evaluate */
2802 es
->incons_evi_vtep_cnt
= 0;
2803 es
->inconsistencies
= 0;
2805 es_active_vtep_cnt
= bgp_evpn_es_get_active_vtep_cnt(es
);
2806 for (ALL_LIST_ELEMENTS_RO(es
->es_evi_list
,
2807 evi_node
, es_evi
)) {
2810 /* reset the inconsistencies on the EVI and re-evaluate*/
2811 UNSET_FLAG(es_evi
->flags
, BGP_EVPNES_EVI_INCONS_VTEP_LIST
);
2813 evi_active_vtep_cnt
=
2814 bgp_evpn_es_evi_get_active_vtep_cnt(es_evi
);
2815 if (es_active_vtep_cnt
!= evi_active_vtep_cnt
) {
2816 bgp_evpn_es_evi_set_inconsistent(es_evi
);
2820 if (!es_active_vtep_cnt
)
2825 while ((es_vtep
= bgp_evpn_es_get_next_active_vtep(
2827 evi_vtep
= bgp_evpn_es_evi_get_next_active_vtep(es_evi
,
2830 bgp_evpn_es_evi_set_inconsistent(es_evi
);
2833 if (es_vtep
->vtep_ip
.s_addr
!=
2834 evi_vtep
->vtep_ip
.s_addr
) {
2835 /* inconsistency detected; set it and move
2838 bgp_evpn_es_evi_set_inconsistent(es_evi
);
2847 static int bgp_evpn_run_consistency_checks(struct thread
*t
)
2851 struct listnode
*node
;
2852 struct listnode
*nextnode
;
2853 struct bgp_evpn_es
*es
;
2855 for (ALL_LIST_ELEMENTS(bgp_mh_info
->pend_es_list
,
2856 node
, nextnode
, es
)) {
2859 /* run consistency checks on the ES and remove it from the
2862 proc_cnt
+= bgp_evpn_es_run_consistency_checks(es
);
2863 bgp_evpn_es_cons_checks_pend_del(es
);
2868 /* restart the timer */
2869 thread_add_timer(bm
->master
, bgp_evpn_run_consistency_checks
, NULL
,
2870 BGP_EVPN_CONS_CHECK_INTERVAL
,
2871 &bgp_mh_info
->t_cons_check
);
2876 /*****************************************************************************/
2877 void bgp_evpn_mh_init(void)
2879 bm
->mh_info
= XCALLOC(MTYPE_BGP_EVPN_MH_INFO
, sizeof(*bm
->mh_info
));
2881 /* setup ES tables */
2882 RB_INIT(bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
);
2884 bgp_mh_info
->local_es_list
= list_new();
2885 listset_app_node_mem(bgp_mh_info
->local_es_list
);
2886 /* list of ESs with pending processing */
2887 bgp_mh_info
->pend_es_list
= list_new();
2888 listset_app_node_mem(bgp_mh_info
->pend_es_list
);
2890 /* config knobs - XXX add cli to control it */
2891 bgp_mh_info
->ead_evi_adv_for_down_links
= true;
2892 bgp_mh_info
->consistency_checking
= true;
2894 if (bgp_mh_info
->consistency_checking
)
2895 thread_add_timer(bm
->master
, bgp_evpn_run_consistency_checks
,
2896 NULL
, BGP_EVPN_CONS_CHECK_INTERVAL
,
2897 &bgp_mh_info
->t_cons_check
);
2899 memset(&zero_esi_buf
, 0, sizeof(esi_t
));
2902 void bgp_evpn_mh_finish(void)
2904 struct bgp_evpn_es
*es
;
2905 struct bgp_evpn_es
*es_next
;
2907 if (BGP_DEBUG(evpn_mh
, EVPN_MH_RT
))
2908 zlog_debug("evpn mh finish");
2910 RB_FOREACH_SAFE (es
, bgp_es_rb_head
, &bgp_mh_info
->es_rb_tree
,
2912 bgp_evpn_es_local_info_clear(es
);
2914 thread_cancel(bgp_mh_info
->t_cons_check
);
2915 list_delete(&bgp_mh_info
->local_es_list
);
2916 list_delete(&bgp_mh_info
->pend_es_list
);
2918 XFREE(MTYPE_BGP_EVPN_MH_INFO
, bgp_mh_info
);