1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Zebra EVPN multihoming code
5 * Copyright (C) 2019 Cumulus Networks, Inc.
24 #include "zebra/zebra_router.h"
25 #include "zebra/debug.h"
26 #include "zebra/interface.h"
27 #include "zebra/rib.h"
29 #include "zebra/rt_netlink.h"
30 #include "zebra/if_netlink.h"
31 #include "zebra/zebra_errors.h"
32 #include "zebra/zebra_l2.h"
33 #include "zebra/zebra_l2_bridge_if.h"
34 #include "zebra/zebra_ns.h"
35 #include "zebra/zebra_vrf.h"
36 #include "zebra/zebra_vxlan.h"
37 #include "zebra/zebra_vxlan_private.h"
38 #include "zebra/zebra_evpn.h"
39 #include "zebra/zebra_evpn_mac.h"
40 #include "zebra/zebra_router.h"
41 #include "zebra/zebra_evpn_mh.h"
42 #include "zebra/zebra_nhg.h"
44 DEFINE_MTYPE_STATIC(ZEBRA
, ZACC_BD
, "Access Broadcast Domain");
45 DEFINE_MTYPE_STATIC(ZEBRA
, ZES
, "Ethernet Segment");
46 DEFINE_MTYPE_STATIC(ZEBRA
, ZES_EVI
, "ES info per-EVI");
47 DEFINE_MTYPE_STATIC(ZEBRA
, ZMH_INFO
, "MH global info");
48 DEFINE_MTYPE_STATIC(ZEBRA
, ZES_VTEP
, "VTEP attached to the ES");
49 DEFINE_MTYPE_STATIC(ZEBRA
, L2_NH
, "L2 nexthop");
51 static void zebra_evpn_es_get_one_base_evpn(void);
52 static int zebra_evpn_es_evi_send_to_client(struct zebra_evpn_es
*es
,
53 struct zebra_evpn
*zevpn
, bool add
);
54 static void zebra_evpn_local_es_del(struct zebra_evpn_es
**esp
);
55 static int zebra_evpn_local_es_update(struct zebra_if
*zif
, esi_t
*esi
);
56 static bool zebra_evpn_es_br_port_dplane_update(struct zebra_evpn_es
*es
,
58 static void zebra_evpn_mh_uplink_cfg_update(struct zebra_if
*zif
, bool set
);
59 static void zebra_evpn_mh_update_protodown_es(struct zebra_evpn_es
*es
,
61 static void zebra_evpn_mh_clear_protodown_es(struct zebra_evpn_es
*es
);
62 static void zebra_evpn_mh_startup_delay_timer_start(const char *rc
);
64 esi_t zero_esi_buf
, *zero_esi
= &zero_esi_buf
;
66 /*****************************************************************************/
67 /* Ethernet Segment to EVI association -
68 * 1. The ES-EVI entry is maintained as a RB tree per L2-VNI
69 * (struct zebra_evpn.es_evi_rb_tree).
70 * 2. Each local ES-EVI entry is sent to BGP which advertises it as an
71 * EAD-EVI (Type-1 EVPN) route
72 * 3. Local ES-EVI setup is re-evaluated on the following triggers -
73 * a. When an ESI is set or cleared on an access port.
74 * b. When an access port associated with an ESI is deleted.
75 * c. When VLAN member ship changes on an access port.
76 * d. When a VXLAN_IF is set or cleared on an access broadcast domain.
77 * e. When a L2-VNI is added or deleted for a VxLAN_IF.
78 * 4. Currently zebra doesn't remote ES-EVIs. Those are managed and maintained
79 * entirely in BGP which consolidates them into a remote ES. The remote ES
80 * is then sent to zebra which allocates a NHG for it.
83 /* compare ES-IDs for the ES-EVI RB tree maintained per-EVPN */
84 static int zebra_es_evi_rb_cmp(const struct zebra_evpn_es_evi
*es_evi1
,
85 const struct zebra_evpn_es_evi
*es_evi2
)
87 return memcmp(&es_evi1
->es
->esi
, &es_evi2
->es
->esi
, ESI_BYTES
);
89 RB_GENERATE(zebra_es_evi_rb_head
, zebra_evpn_es_evi
,
90 rb_node
, zebra_es_evi_rb_cmp
);
92 /* allocate a new ES-EVI and insert it into the per-L2-VNI and per-ES
95 static struct zebra_evpn_es_evi
*zebra_evpn_es_evi_new(struct zebra_evpn_es
*es
,
96 struct zebra_evpn
*zevpn
)
98 struct zebra_evpn_es_evi
*es_evi
;
100 es_evi
= XCALLOC(MTYPE_ZES_EVI
, sizeof(struct zebra_evpn_es_evi
));
103 es_evi
->zevpn
= zevpn
;
105 /* insert into the EVPN-ESI rb tree */
106 RB_INSERT(zebra_es_evi_rb_head
, &zevpn
->es_evi_rb_tree
, es_evi
);
108 /* add to the ES's VNI list */
109 listnode_init(&es_evi
->es_listnode
, es_evi
);
110 listnode_add(es
->es_evi_list
, &es_evi
->es_listnode
);
112 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
113 zlog_debug("es %s evi %d new",
114 es_evi
->es
->esi_str
, es_evi
->zevpn
->vni
);
119 /* Evaluate if the es_evi is ready to be sent BGP -
120 * 1. If it is ready an add is sent to BGP
121 * 2. If it is not ready a del is sent (if the ES had been previously added
124 static void zebra_evpn_es_evi_re_eval_send_to_client(
125 struct zebra_evpn_es_evi
*es_evi
)
130 old_ready
= !!(es_evi
->flags
& ZEBRA_EVPNES_EVI_READY_FOR_BGP
);
132 /* ES and L2-VNI have to be individually ready for BGP */
133 if ((es_evi
->flags
& ZEBRA_EVPNES_EVI_LOCAL
) &&
134 (es_evi
->es
->flags
& ZEBRA_EVPNES_READY_FOR_BGP
) &&
135 zebra_evpn_send_to_client_ok(es_evi
->zevpn
))
136 es_evi
->flags
|= ZEBRA_EVPNES_EVI_READY_FOR_BGP
;
138 es_evi
->flags
&= ~ZEBRA_EVPNES_EVI_READY_FOR_BGP
;
140 new_ready
= !!(es_evi
->flags
& ZEBRA_EVPNES_EVI_READY_FOR_BGP
);
142 if (old_ready
== new_ready
)
146 zebra_evpn_es_evi_send_to_client(es_evi
->es
, es_evi
->zevpn
,
149 zebra_evpn_es_evi_send_to_client(es_evi
->es
, es_evi
->zevpn
,
153 /* remove the ES-EVI from the per-L2-VNI and per-ES tables and free
156 static void zebra_evpn_es_evi_free(struct zebra_evpn_es_evi
*es_evi
)
158 struct zebra_evpn_es
*es
= es_evi
->es
;
159 struct zebra_evpn
*zevpn
= es_evi
->zevpn
;
161 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
162 zlog_debug("es %s evi %d free",
163 es_evi
->es
->esi_str
, es_evi
->zevpn
->vni
);
165 /* remove from the ES's VNI list */
166 list_delete_node(es
->es_evi_list
, &es_evi
->es_listnode
);
168 /* remove from the VNI-ESI rb tree */
169 RB_REMOVE(zebra_es_evi_rb_head
, &zevpn
->es_evi_rb_tree
, es_evi
);
171 /* remove from the VNI-ESI rb tree */
172 XFREE(MTYPE_ZES_EVI
, es_evi
);
175 /* find the ES-EVI in the per-L2-VNI RB tree */
176 struct zebra_evpn_es_evi
*zebra_evpn_es_evi_find(struct zebra_evpn_es
*es
,
177 struct zebra_evpn
*zevpn
)
179 struct zebra_evpn_es_evi es_evi
;
183 return RB_FIND(zebra_es_evi_rb_head
, &zevpn
->es_evi_rb_tree
, &es_evi
);
186 /* Tell BGP about an ES-EVI deletion and then delete it */
187 static void zebra_evpn_local_es_evi_do_del(struct zebra_evpn_es_evi
*es_evi
)
189 if (!(es_evi
->flags
& ZEBRA_EVPNES_EVI_LOCAL
))
192 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
193 zlog_debug("local es %s evi %d del",
194 es_evi
->es
->esi_str
, es_evi
->zevpn
->vni
);
196 if (es_evi
->flags
& ZEBRA_EVPNES_EVI_READY_FOR_BGP
) {
197 /* send a del only if add was sent for it earlier */
198 zebra_evpn_es_evi_send_to_client(es_evi
->es
,
199 es_evi
->zevpn
, false /* add */);
202 /* delete it from the EVPN's local list */
203 list_delete_node(es_evi
->zevpn
->local_es_evi_list
,
204 &es_evi
->l2vni_listnode
);
206 es_evi
->flags
&= ~ZEBRA_EVPNES_EVI_LOCAL
;
207 zebra_evpn_es_evi_free(es_evi
);
209 static void zebra_evpn_local_es_evi_del(struct zebra_evpn_es
*es
,
210 struct zebra_evpn
*zevpn
)
212 struct zebra_evpn_es_evi
*es_evi
;
214 es_evi
= zebra_evpn_es_evi_find(es
, zevpn
);
216 zebra_evpn_local_es_evi_do_del(es_evi
);
219 /* If there are any existing MAC entries for this es/zevpn we need
220 * to install it in the dataplane.
222 * Note: primary purpose of this is to handle es del/re-add windows where
223 * sync MAC entries may be added by bgpd before the es-evi membership is
224 * created in the dataplane and in zebra
226 static void zebra_evpn_es_evi_mac_install(struct zebra_evpn_es_evi
*es_evi
)
228 struct zebra_mac
*mac
;
229 struct listnode
*node
;
230 struct zebra_evpn_es
*es
= es_evi
->es
;
232 if (listcount(es
->mac_list
) && IS_ZEBRA_DEBUG_EVPN_MH_ES
)
233 zlog_debug("dp-mac install on es %s evi %d add", es
->esi_str
,
236 for (ALL_LIST_ELEMENTS_RO(es
->mac_list
, node
, mac
)) {
237 if (mac
->zevpn
!= es_evi
->zevpn
)
240 if (!CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
))
243 zebra_evpn_sync_mac_dp_install(mac
, false, false, __func__
);
247 /* Create an ES-EVI if it doesn't already exist and tell BGP */
248 static void zebra_evpn_local_es_evi_add(struct zebra_evpn_es
*es
,
249 struct zebra_evpn
*zevpn
)
251 struct zebra_evpn_es_evi
*es_evi
;
253 es_evi
= zebra_evpn_es_evi_find(es
, zevpn
);
255 es_evi
= zebra_evpn_es_evi_new(es
, zevpn
);
259 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
260 zlog_debug("local es %s evi %d add",
261 es_evi
->es
->esi_str
, es_evi
->zevpn
->vni
);
262 es_evi
->flags
|= ZEBRA_EVPNES_EVI_LOCAL
;
263 /* add to the EVPN's local list */
264 listnode_init(&es_evi
->l2vni_listnode
, es_evi
);
265 listnode_add(zevpn
->local_es_evi_list
, &es_evi
->l2vni_listnode
);
267 zebra_evpn_es_evi_re_eval_send_to_client(es_evi
);
269 zebra_evpn_es_evi_mac_install(es_evi
);
273 static void zebra_evpn_es_evi_show_entry(struct vty
*vty
,
274 struct zebra_evpn_es_evi
*es_evi
,
275 json_object
*json_array
)
281 json_object
*json_types
;
283 /* Separate JSON object for each es-evi entry */
284 json
= json_object_new_object();
286 json_object_string_add(json
, "esi", es_evi
->es
->esi_str
);
287 json_object_int_add(json
, "vni", es_evi
->zevpn
->vni
);
288 if (es_evi
->flags
& ZEBRA_EVPNES_EVI_LOCAL
) {
289 json_types
= json_object_new_array();
290 if (es_evi
->flags
& ZEBRA_EVPNES_EVI_LOCAL
)
291 json_array_string_add(json_types
, "local");
292 json_object_object_add(json
, "type", json_types
);
295 /* Add es-evi entry to json array */
296 json_object_array_add(json_array
, json
);
299 if (es_evi
->flags
& ZEBRA_EVPNES_EVI_LOCAL
)
300 strlcat(type_str
, "L", sizeof(type_str
));
302 vty_out(vty
, "%-8d %-30s %-4s\n",
303 es_evi
->zevpn
->vni
, es_evi
->es
->esi_str
,
309 zebra_evpn_es_evi_show_entry_detail(struct vty
*vty
,
310 struct zebra_evpn_es_evi
*es_evi
,
311 json_object
*json_array
)
317 json_object
*json_flags
;
319 /* Separate JSON object for each es-evi entry */
320 json
= json_object_new_object();
322 json_object_string_add(json
, "esi", es_evi
->es
->esi_str
);
323 json_object_int_add(json
, "vni", es_evi
->zevpn
->vni
);
325 & (ZEBRA_EVPNES_EVI_LOCAL
326 | ZEBRA_EVPNES_EVI_READY_FOR_BGP
)) {
327 json_flags
= json_object_new_array();
328 if (es_evi
->flags
& ZEBRA_EVPNES_EVI_LOCAL
)
329 json_array_string_add(json_flags
, "local");
330 if (es_evi
->flags
& ZEBRA_EVPNES_EVI_READY_FOR_BGP
)
331 json_array_string_add(json_flags
,
333 json_object_object_add(json
, "flags", json_flags
);
336 /* Add es-evi entry to json array */
337 json_object_array_add(json_array
, json
);
340 if (es_evi
->flags
& ZEBRA_EVPNES_EVI_LOCAL
)
341 strlcat(type_str
, "L", sizeof(type_str
));
343 vty_out(vty
, "VNI %d ESI: %s\n",
344 es_evi
->zevpn
->vni
, es_evi
->es
->esi_str
);
345 vty_out(vty
, " Type: %s\n", type_str
);
346 vty_out(vty
, " Ready for BGP: %s\n",
348 ZEBRA_EVPNES_EVI_READY_FOR_BGP
) ?
354 static void zebra_evpn_es_evi_show_one_evpn(struct zebra_evpn
*zevpn
,
356 json_object
*json_array
, int detail
)
358 struct zebra_evpn_es_evi
*es_evi
;
360 RB_FOREACH(es_evi
, zebra_es_evi_rb_head
, &zevpn
->es_evi_rb_tree
) {
362 zebra_evpn_es_evi_show_entry_detail(vty
, es_evi
,
365 zebra_evpn_es_evi_show_entry(vty
, es_evi
, json_array
);
369 struct evpn_mh_show_ctx
{
375 static void zebra_evpn_es_evi_show_one_evpn_hash_cb(struct hash_bucket
*bucket
,
378 struct zebra_evpn
*zevpn
= (struct zebra_evpn
*)bucket
->data
;
379 struct evpn_mh_show_ctx
*wctx
= (struct evpn_mh_show_ctx
*)ctxt
;
381 zebra_evpn_es_evi_show_one_evpn(zevpn
, wctx
->vty
,
382 wctx
->json
, wctx
->detail
);
385 void zebra_evpn_es_evi_show(struct vty
*vty
, bool uj
, int detail
)
387 json_object
*json_array
= NULL
;
388 struct zebra_vrf
*zvrf
;
389 struct evpn_mh_show_ctx wctx
;
391 zvrf
= zebra_vrf_get_evpn();
393 json_array
= json_object_new_array();
395 memset(&wctx
, 0, sizeof(wctx
));
397 wctx
.json
= json_array
;
398 wctx
.detail
= detail
;
400 if (!detail
&& !json_array
) {
401 vty_out(vty
, "Type: L local, R remote\n");
402 vty_out(vty
, "%-8s %-30s %-4s\n", "VNI", "ESI", "Type");
404 /* Display all L2-VNIs */
405 hash_iterate(zvrf
->evpn_table
, zebra_evpn_es_evi_show_one_evpn_hash_cb
,
409 vty_json(vty
, json_array
);
412 void zebra_evpn_es_evi_show_vni(struct vty
*vty
, bool uj
, vni_t vni
, int detail
)
414 json_object
*json_array
= NULL
;
415 struct zebra_evpn
*zevpn
;
417 zevpn
= zebra_evpn_lookup(vni
);
419 json_array
= json_object_new_array();
422 if (!detail
&& !json_array
) {
423 vty_out(vty
, "Type: L local, R remote\n");
424 vty_out(vty
, "%-8s %-30s %-4s\n", "VNI", "ESI", "Type");
426 zebra_evpn_es_evi_show_one_evpn(zevpn
, vty
, json_array
, detail
);
429 vty_out(vty
, "VNI %d doesn't exist\n", vni
);
433 vty_json(vty
, json_array
);
436 /* Initialize the ES tables maintained per-L2_VNI */
437 void zebra_evpn_es_evi_init(struct zebra_evpn
*zevpn
)
439 /* Initialize the ES-EVI RB tree */
440 RB_INIT(zebra_es_evi_rb_head
, &zevpn
->es_evi_rb_tree
);
442 /* Initialize the local and remote ES lists maintained for quick
445 zevpn
->local_es_evi_list
= list_new();
446 listset_app_node_mem(zevpn
->local_es_evi_list
);
449 /* Cleanup the ES info maintained per- EVPN */
450 void zebra_evpn_es_evi_cleanup(struct zebra_evpn
*zevpn
)
452 struct zebra_evpn_es_evi
*es_evi
;
453 struct zebra_evpn_es_evi
*es_evi_next
;
455 RB_FOREACH_SAFE(es_evi
, zebra_es_evi_rb_head
,
456 &zevpn
->es_evi_rb_tree
, es_evi_next
) {
457 zebra_evpn_local_es_evi_do_del(es_evi
);
460 list_delete(&zevpn
->local_es_evi_list
);
461 zebra_evpn_es_clear_base_evpn(zevpn
);
464 /* called when the oper state or bridge membership changes for the
467 void zebra_evpn_update_all_es(struct zebra_evpn
*zevpn
)
469 struct zebra_evpn_es_evi
*es_evi
;
470 struct listnode
*node
;
471 struct interface
*vlan_if
;
472 struct interface
*vxlan_if
;
473 struct zebra_if
*vxlan_zif
;
474 struct zebra_vxlan_vni
*vni
;
476 /* the EVPN is now elgible as a base for EVPN-MH */
477 if (zebra_evpn_send_to_client_ok(zevpn
))
478 zebra_evpn_es_set_base_evpn(zevpn
);
480 zebra_evpn_es_clear_base_evpn(zevpn
);
482 for (ALL_LIST_ELEMENTS_RO(zevpn
->local_es_evi_list
, node
, es_evi
))
483 zebra_evpn_es_evi_re_eval_send_to_client(es_evi
);
485 /* reinstall SVI MAC */
486 vxlan_if
= zevpn
->vxlan_if
;
488 vxlan_zif
= vxlan_if
->info
;
489 if (if_is_operative(vxlan_if
)
490 && vxlan_zif
->brslave_info
.br_if
) {
491 vni
= zebra_vxlan_if_vni_find(vxlan_zif
, zevpn
->vni
);
492 /* VLAN-VNI mappings may not exist */
494 vlan_if
= zvni_map_to_svi(
496 vxlan_zif
->brslave_info
.br_if
);
498 zebra_evpn_acc_bd_svi_mac_add(vlan_if
);
504 /*****************************************************************************/
505 /* Access broadcast domains (BD)
506 * 1. These broadcast domains can be VLAN aware (in which case
507 * the key is VID) or VLAN unaware (in which case the key is
508 * 2. A VID-BD is created when a VLAN is associated with an access port or
509 * when the VLAN is associated with VXLAN_IF
510 * 3. A BD is translated into ES-EVI entries when a VNI is associated
511 * with the broadcast domain
513 /* Hash key for VLAN based broadcast domains */
514 static unsigned int zebra_evpn_acc_vl_hash_keymake(const void *p
)
516 const struct zebra_evpn_access_bd
*acc_bd
= p
;
518 return jhash_2words(acc_bd
->vid
, acc_bd
->bridge_ifindex
, 0);
521 /* Compare two VLAN based broadcast domains */
522 static bool zebra_evpn_acc_vl_cmp(const void *p1
, const void *p2
)
524 const struct zebra_evpn_access_bd
*acc_bd1
= p1
;
525 const struct zebra_evpn_access_bd
*acc_bd2
= p2
;
527 if (acc_bd1
== NULL
&& acc_bd2
== NULL
)
530 if (acc_bd1
== NULL
|| acc_bd2
== NULL
)
533 return ((acc_bd1
->vid
== acc_bd2
->vid
) &&
534 (acc_bd1
->bridge_ifindex
== acc_bd2
->bridge_ifindex
));
537 /* Lookup VLAN based broadcast domain */
538 struct zebra_evpn_access_bd
*zebra_evpn_acc_vl_find(vlanid_t vid
,
539 struct interface
*br_if
)
541 struct zebra_evpn_access_bd
*acc_bd
;
542 struct zebra_evpn_access_bd tmp
;
545 tmp
.bridge_ifindex
= br_if
->ifindex
;
546 acc_bd
= hash_lookup(zmh_info
->evpn_vlan_table
, &tmp
);
551 /* A new broadcast domain can be created when a VLAN member or VLAN<=>VxLAN_IF
554 static struct zebra_evpn_access_bd
*
555 zebra_evpn_acc_vl_new(vlanid_t vid
, struct interface
*br_if
)
557 struct zebra_evpn_access_bd
*acc_bd
;
558 struct interface
*vlan_if
;
560 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
561 zlog_debug("access vlan %d bridge %s add", vid
, br_if
->name
);
563 acc_bd
= XCALLOC(MTYPE_ZACC_BD
, sizeof(struct zebra_evpn_access_bd
));
566 acc_bd
->bridge_ifindex
= br_if
->ifindex
;
567 acc_bd
->bridge_zif
= (struct zebra_if
*)br_if
->info
;
569 /* Initialize the mbr list */
570 acc_bd
->mbr_zifs
= list_new();
573 (void)hash_get(zmh_info
->evpn_vlan_table
, acc_bd
, hash_alloc_intern
);
575 /* check if an svi exists for the vlan */
576 vlan_if
= zvni_map_to_svi(vid
, br_if
);
578 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
579 zlog_debug("vlan %d bridge %s SVI %s set", vid
,
580 br_if
->name
, vlan_if
->name
);
581 acc_bd
->vlan_zif
= vlan_if
->info
;
586 /* Free VLAN based broadcast domain -
587 * This just frees appropriate memory, caller should have taken other
590 static void zebra_evpn_acc_vl_free(struct zebra_evpn_access_bd
*acc_bd
)
592 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
593 zlog_debug("access vlan %d del", acc_bd
->vid
);
595 if (acc_bd
->vlan_zif
&& acc_bd
->zevpn
&& acc_bd
->zevpn
->mac_table
)
596 zebra_evpn_mac_svi_del(acc_bd
->vlan_zif
->ifp
, acc_bd
->zevpn
);
598 /* cleanup resources maintained against the ES */
599 list_delete(&acc_bd
->mbr_zifs
);
601 /* remove EVI from various tables */
602 hash_release(zmh_info
->evpn_vlan_table
, acc_bd
);
604 XFREE(MTYPE_ZACC_BD
, acc_bd
);
607 static void zebra_evpn_acc_vl_cleanup_all(struct hash_bucket
*bucket
, void *arg
)
609 struct zebra_evpn_access_bd
*acc_bd
= bucket
->data
;
611 zebra_evpn_acc_vl_free(acc_bd
);
614 /* called when a bd mbr is removed or VxLAN_IF is diassociated from the access
617 static void zebra_evpn_acc_bd_free_on_deref(struct zebra_evpn_access_bd
*acc_bd
)
619 if (!list_isempty(acc_bd
->mbr_zifs
) || acc_bd
->vxlan_zif
)
622 /* Remove this access_bd from bridge hash table */
623 zebra_l2_bridge_if_vlan_access_bd_deref(acc_bd
);
625 /* if there are no references free the EVI */
626 zebra_evpn_acc_vl_free(acc_bd
);
629 static struct zebra_evpn_access_bd
*
630 zebra_evpn_acc_bd_alloc_on_ref(vlanid_t vid
, struct interface
*br_if
)
632 struct zebra_evpn_access_bd
*acc_bd
= NULL
;
634 assert(br_if
&& br_if
->info
);
635 acc_bd
= zebra_evpn_acc_vl_new(vid
, br_if
);
637 /* Add this access_bd to bridge hash table */
638 zebra_l2_bridge_if_vlan_access_bd_ref(acc_bd
);
643 /* called when a SVI is goes up/down */
644 void zebra_evpn_acc_bd_svi_set(struct zebra_if
*vlan_zif
,
645 struct zebra_if
*br_zif
, bool is_up
)
647 struct zebra_evpn_access_bd
*acc_bd
;
649 struct zebra_if
*tmp_br_zif
= br_zif
;
652 if (!vlan_zif
->link
|| !vlan_zif
->link
->info
)
655 tmp_br_zif
= vlan_zif
->link
->info
;
658 /* ignore vlan unaware bridges */
659 if (!IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(tmp_br_zif
))
662 vid
= vlan_zif
->l2info
.vl
.vid
;
663 acc_bd
= zebra_evpn_acc_vl_find(vid
, tmp_br_zif
->ifp
);
668 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
669 zlog_debug("vlan %d bridge %s SVI %s set", vid
,
670 tmp_br_zif
->ifp
->name
, vlan_zif
->ifp
->name
);
672 acc_bd
->vlan_zif
= vlan_zif
;
674 zebra_evpn_mac_svi_add(acc_bd
->vlan_zif
->ifp
,
676 } else if (acc_bd
->vlan_zif
) {
677 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
678 zlog_debug("vlan %d bridge %s SVI clear", vid
,
679 tmp_br_zif
->ifp
->name
);
680 acc_bd
->vlan_zif
= NULL
;
681 if (acc_bd
->zevpn
&& acc_bd
->zevpn
->mac_table
)
682 zebra_evpn_mac_svi_del(vlan_zif
->ifp
, acc_bd
->zevpn
);
686 /* On some events macs are force-flushed. This api can be used to reinstate
687 * the svi-mac after such cleanup-events.
689 void zebra_evpn_acc_bd_svi_mac_add(struct interface
*vlan_if
)
691 zebra_evpn_acc_bd_svi_set(vlan_if
->info
, NULL
,
692 if_is_operative(vlan_if
));
695 /* called when a EVPN-L2VNI is set or cleared against a BD */
696 static void zebra_evpn_acc_bd_evpn_set(struct zebra_evpn_access_bd
*acc_bd
,
697 struct zebra_evpn
*zevpn
,
698 struct zebra_evpn
*old_zevpn
)
700 struct zebra_if
*zif
;
701 struct listnode
*node
;
703 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
704 zlog_debug("access vlan %d bridge %s l2-vni %u set",
705 acc_bd
->vid
, acc_bd
->bridge_zif
->ifp
->name
,
706 zevpn
? zevpn
->vni
: 0);
708 for (ALL_LIST_ELEMENTS_RO(acc_bd
->mbr_zifs
, node
, zif
)) {
709 if (!zif
->es_info
.es
)
713 zebra_evpn_local_es_evi_add(zif
->es_info
.es
, zevpn
);
715 zebra_evpn_local_es_evi_del(zif
->es_info
.es
, old_zevpn
);
718 if (acc_bd
->vlan_zif
) {
720 zebra_evpn_mac_svi_add(acc_bd
->vlan_zif
->ifp
,
722 else if (old_zevpn
&& old_zevpn
->mac_table
)
723 zebra_evpn_mac_svi_del(acc_bd
->vlan_zif
->ifp
,
728 /* handle VLAN->VxLAN_IF association */
729 void zebra_evpn_vl_vxl_ref(uint16_t vid
, vni_t vni_id
,
730 struct zebra_if
*vxlan_zif
)
733 struct zebra_evpn_access_bd
*acc_bd
;
734 struct zebra_evpn
*old_zevpn
;
735 struct interface
*br_if
;
743 br_if
= vxlan_zif
->brslave_info
.br_if
;
748 acc_bd
= zebra_evpn_acc_vl_find(vid
, br_if
);
750 acc_bd
= zebra_evpn_acc_bd_alloc_on_ref(vid
, br_if
);
752 old_vni
= acc_bd
->vni
;
754 if (vni_id
== old_vni
)
757 acc_bd
->vni
= vni_id
;
758 acc_bd
->vxlan_zif
= vxlan_zif
;
760 old_zevpn
= acc_bd
->zevpn
;
761 acc_bd
->zevpn
= zebra_evpn_lookup(vni_id
);
762 if (acc_bd
->zevpn
== old_zevpn
)
765 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
766 zlog_debug("access vlan %d vni %u ref", acc_bd
->vid
, vni_id
);
769 zebra_evpn_acc_bd_evpn_set(acc_bd
, NULL
, old_zevpn
);
772 zebra_evpn_acc_bd_evpn_set(acc_bd
, acc_bd
->zevpn
, NULL
);
775 /* handle VLAN->VxLAN_IF deref */
776 void zebra_evpn_vl_vxl_deref(uint16_t vid
, vni_t vni_id
,
777 struct zebra_if
*vxlan_zif
)
779 struct interface
*br_if
;
780 struct zebra_evpn_access_bd
*acc_bd
;
788 br_if
= vxlan_zif
->brslave_info
.br_if
;
792 acc_bd
= zebra_evpn_acc_vl_find(vid
, br_if
);
796 /* clear vxlan_if only if it matches */
797 if (acc_bd
->vni
!= vni_id
)
800 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
801 zlog_debug("access vlan %d bridge %s vni %u deref", acc_bd
->vid
,
802 br_if
->name
, vni_id
);
805 zebra_evpn_acc_bd_evpn_set(acc_bd
, NULL
, acc_bd
->zevpn
);
807 acc_bd
->zevpn
= NULL
;
808 acc_bd
->vxlan_zif
= NULL
;
811 /* if there are no other references the access_bd can be freed */
812 zebra_evpn_acc_bd_free_on_deref(acc_bd
);
815 /* handle BridgeIf<->AccessBD cleanup */
816 void zebra_evpn_access_bd_bridge_cleanup(vlanid_t vid
, struct interface
*br_if
,
817 struct zebra_evpn_access_bd
*acc_bd
)
819 struct zebra_evpn
*zevpn
;
821 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
822 zlog_debug("access bd vlan %d bridge %s cleanup", acc_bd
->vid
,
825 zevpn
= acc_bd
->zevpn
;
827 zebra_evpn_acc_bd_evpn_set(acc_bd
, NULL
, zevpn
);
829 /* cleanup resources maintained against the ES */
830 list_delete_all_node(acc_bd
->mbr_zifs
);
832 acc_bd
->zevpn
= NULL
;
833 acc_bd
->vxlan_zif
= NULL
;
835 acc_bd
->bridge_zif
= NULL
;
837 /* if there are no other references the access_bd can be freed */
838 zebra_evpn_acc_bd_free_on_deref(acc_bd
);
841 /* handle EVPN add/del */
842 void zebra_evpn_vxl_evpn_set(struct zebra_if
*zif
, struct zebra_evpn
*zevpn
,
845 struct interface
*br_if
;
846 struct zebra_vxlan_vni
*vni
;
847 struct zebra_evpn_access_bd
*acc_bd
;
852 /* locate access_bd associated with the vxlan device */
853 vni
= zebra_vxlan_if_vni_find(zif
, zevpn
->vni
);
857 br_if
= zif
->brslave_info
.br_if
;
861 acc_bd
= zebra_evpn_acc_vl_find(vni
->access_vlan
, br_if
);
866 zebra_evpn_es_set_base_evpn(zevpn
);
867 if (acc_bd
->zevpn
!= zevpn
) {
868 acc_bd
->zevpn
= zevpn
;
869 zebra_evpn_acc_bd_evpn_set(acc_bd
, zevpn
, NULL
);
873 struct zebra_evpn
*old_zevpn
= acc_bd
->zevpn
;
874 acc_bd
->zevpn
= NULL
;
875 zebra_evpn_acc_bd_evpn_set(acc_bd
, NULL
, old_zevpn
);
880 /* handle addition of new VLAN members */
881 void zebra_evpn_vl_mbr_ref(uint16_t vid
, struct zebra_if
*zif
)
883 struct interface
*br_if
;
884 struct zebra_evpn_access_bd
*acc_bd
;
889 br_if
= zif
->brslave_info
.br_if
;
893 acc_bd
= zebra_evpn_acc_vl_find(vid
, br_if
);
895 acc_bd
= zebra_evpn_acc_bd_alloc_on_ref(vid
, br_if
);
897 if (listnode_lookup(acc_bd
->mbr_zifs
, zif
))
900 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
901 zlog_debug("access vlan %d bridge %s mbr %s ref", vid
,
902 br_if
->name
, zif
->ifp
->name
);
904 listnode_add(acc_bd
->mbr_zifs
, zif
);
905 if (acc_bd
->zevpn
&& zif
->es_info
.es
)
906 zebra_evpn_local_es_evi_add(zif
->es_info
.es
, acc_bd
->zevpn
);
909 /* handle deletion of VLAN members */
910 void zebra_evpn_vl_mbr_deref(uint16_t vid
, struct zebra_if
*zif
)
912 struct interface
*br_if
;
913 struct zebra_evpn_access_bd
*acc_bd
;
914 struct listnode
*node
;
919 br_if
= zif
->brslave_info
.br_if
;
923 acc_bd
= zebra_evpn_acc_vl_find(vid
, br_if
);
927 node
= listnode_lookup(acc_bd
->mbr_zifs
, zif
);
931 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
932 zlog_debug("access vlan %d bridge %s mbr %s deref", vid
,
933 br_if
->name
, zif
->ifp
->name
);
935 list_delete_node(acc_bd
->mbr_zifs
, node
);
937 if (acc_bd
->zevpn
&& zif
->es_info
.es
)
938 zebra_evpn_local_es_evi_del(zif
->es_info
.es
, acc_bd
->zevpn
);
940 /* if there are no other references the access_bd can be freed */
941 zebra_evpn_acc_bd_free_on_deref(acc_bd
);
944 static void zebra_evpn_acc_vl_adv_svi_mac_cb(struct hash_bucket
*bucket
,
947 struct zebra_evpn_access_bd
*acc_bd
= bucket
->data
;
949 if (acc_bd
->vlan_zif
&& acc_bd
->zevpn
)
950 zebra_evpn_mac_svi_add(acc_bd
->vlan_zif
->ifp
, acc_bd
->zevpn
);
953 /* called when advertise SVI MAC is enabled on the switch */
954 static void zebra_evpn_acc_vl_adv_svi_mac_all(void)
956 hash_iterate(zmh_info
->evpn_vlan_table
,
957 zebra_evpn_acc_vl_adv_svi_mac_cb
, NULL
);
960 static void zebra_evpn_acc_vl_json_fill(struct zebra_evpn_access_bd
*acc_bd
,
961 json_object
*json
, bool detail
)
963 json_object_int_add(json
, "vlan", acc_bd
->vid
);
964 if (acc_bd
->vxlan_zif
)
965 json_object_string_add(json
, "vxlanIf",
966 acc_bd
->vxlan_zif
->ifp
->name
);
968 json_object_int_add(json
, "vni", acc_bd
->zevpn
->vni
);
969 if (acc_bd
->mbr_zifs
)
970 json_object_int_add(json
, "memberIfCount",
971 listcount(acc_bd
->mbr_zifs
));
974 json_object
*json_mbrs
;
975 json_object
*json_mbr
;
976 struct zebra_if
*zif
;
977 struct listnode
*node
;
980 json_mbrs
= json_object_new_array();
981 for (ALL_LIST_ELEMENTS_RO(acc_bd
->mbr_zifs
, node
, zif
)) {
982 json_mbr
= json_object_new_object();
983 json_object_string_add(json_mbr
, "ifName",
985 json_object_array_add(json_mbrs
, json_mbr
);
987 json_object_object_add(json
, "members", json_mbrs
);
991 static void zebra_evpn_acc_vl_show_entry_detail(struct vty
*vty
,
992 struct zebra_evpn_access_bd
*acc_bd
, json_object
*json
)
994 struct zebra_if
*zif
;
995 struct listnode
*node
;
998 zebra_evpn_acc_vl_json_fill(acc_bd
, json
, true);
1000 vty_out(vty
, "VLAN: %s.%u\n", acc_bd
->bridge_zif
->ifp
->name
,
1002 vty_out(vty
, " VxLAN Interface: %s\n",
1004 acc_bd
->vxlan_zif
->ifp
->name
: "-");
1005 vty_out(vty
, " SVI: %s\n",
1006 acc_bd
->vlan_zif
? acc_bd
->vlan_zif
->ifp
->name
: "-");
1008 vty_out(vty
, " L2-VNI: %d\n", acc_bd
->zevpn
->vni
);
1010 vty_out(vty
, " L2-VNI: 0\n");
1011 vty_out(vty
, " L3-VNI: %d\n", acc_bd
->vni
);
1013 vty_out(vty
, " Member Count: %d\n",
1014 listcount(acc_bd
->mbr_zifs
));
1015 vty_out(vty
, " Members: \n");
1016 for (ALL_LIST_ELEMENTS_RO(acc_bd
->mbr_zifs
, node
, zif
))
1017 vty_out(vty
, " %s\n", zif
->ifp
->name
);
1022 static void zebra_evpn_acc_vl_show_entry(struct vty
*vty
,
1023 struct zebra_evpn_access_bd
*acc_bd
, json_object
*json
)
1026 zebra_evpn_acc_vl_json_fill(acc_bd
, json
, false);
1028 vty_out(vty
, "%-5s.%-5u %-15s %-8d %-15s %u\n",
1029 acc_bd
->bridge_zif
->ifp
->name
, acc_bd
->vid
,
1030 acc_bd
->vlan_zif
? acc_bd
->vlan_zif
->ifp
->name
: "-",
1031 acc_bd
->zevpn
? acc_bd
->zevpn
->vni
: 0,
1032 acc_bd
->vxlan_zif
? acc_bd
->vxlan_zif
->ifp
->name
: "-",
1033 listcount(acc_bd
->mbr_zifs
));
1037 static void zebra_evpn_acc_vl_show_hash(struct hash_bucket
*bucket
, void *ctxt
)
1039 struct evpn_mh_show_ctx
*wctx
= ctxt
;
1040 struct zebra_evpn_access_bd
*acc_bd
= bucket
->data
;
1041 json_object
*json
= NULL
;
1044 json
= json_object_new_object();
1046 zebra_evpn_acc_vl_show_entry_detail(wctx
->vty
, acc_bd
, json
);
1048 zebra_evpn_acc_vl_show_entry(wctx
->vty
, acc_bd
, json
);
1050 json_object_array_add(wctx
->json
, json
);
1053 void zebra_evpn_acc_vl_show(struct vty
*vty
, bool uj
)
1055 struct evpn_mh_show_ctx wctx
;
1056 json_object
*json_array
= NULL
;
1059 json_array
= json_object_new_array();
1061 memset(&wctx
, 0, sizeof(wctx
));
1063 wctx
.json
= json_array
;
1064 wctx
.detail
= false;
1067 vty_out(vty
, "%-12s %-15s %-8s %-15s %s\n", "VLAN", "SVI",
1068 "L2-VNI", "VXLAN-IF", "# Members");
1070 hash_iterate(zmh_info
->evpn_vlan_table
, zebra_evpn_acc_vl_show_hash
,
1074 vty_json(vty
, json_array
);
1077 void zebra_evpn_acc_vl_show_detail(struct vty
*vty
, bool uj
)
1079 struct evpn_mh_show_ctx wctx
;
1080 json_object
*json_array
= NULL
;
1083 json_array
= json_object_new_array();
1084 memset(&wctx
, 0, sizeof(wctx
));
1086 wctx
.json
= json_array
;
1089 hash_iterate(zmh_info
->evpn_vlan_table
, zebra_evpn_acc_vl_show_hash
,
1093 vty_json(vty
, json_array
);
1096 void zebra_evpn_acc_vl_show_vid(struct vty
*vty
, bool uj
, vlanid_t vid
,
1097 struct interface
*br_if
)
1099 json_object
*json
= NULL
;
1100 struct zebra_evpn_access_bd
*acc_bd
;
1103 json
= json_object_new_object();
1105 acc_bd
= zebra_evpn_acc_vl_find(vid
, br_if
);
1107 zebra_evpn_acc_vl_show_entry_detail(vty
, acc_bd
, json
);
1110 vty_out(vty
, "VLAN %s.%u not present\n", br_if
->name
,
1115 vty_json(vty
, json
);
1118 /* Initialize VLAN member bitmap on an interface. Although VLAN membership
1119 * is independent of EVPN we only process it if its of interest to EVPN-MH
1120 * i.e. on access ports that can be setup as Ethernet Segments. And that is
1121 * intended as an optimization.
1123 void zebra_evpn_if_init(struct zebra_if
*zif
)
1125 if (!zebra_evpn_is_if_es_capable(zif
))
1128 if (!bf_is_inited(zif
->vlan_bitmap
))
1129 bf_init(zif
->vlan_bitmap
, IF_VLAN_BITMAP_MAX
);
1131 /* if an es_id and sysmac are already present against the interface
1134 zebra_evpn_local_es_update(zif
, &zif
->es_info
.esi
);
1137 /* handle deletion of an access port by removing it from all associated
1138 * broadcast domains.
1140 void zebra_evpn_if_cleanup(struct zebra_if
*zif
)
1143 struct zebra_evpn_es
*es
;
1145 if (bf_is_inited(zif
->vlan_bitmap
)) {
1146 bf_for_each_set_bit(zif
->vlan_bitmap
, vid
, IF_VLAN_BITMAP_MAX
)
1148 zebra_evpn_vl_mbr_deref(vid
, zif
);
1151 bf_free(zif
->vlan_bitmap
);
1154 /* Delete associated Ethernet Segment */
1155 es
= zif
->es_info
.es
;
1157 zebra_evpn_local_es_del(&es
);
1160 /*****************************************************************************
1161 * L2 NH/NHG Management
1162 * A L2 NH entry is programmed in the kernel for every ES-VTEP entry. This
1163 * NH is then added to the L2-ECMP-NHG associated with the ES.
1165 static uint32_t zebra_evpn_nhid_alloc(struct zebra_evpn_es
*es
)
1170 bf_assign_index(zmh_info
->nh_id_bitmap
, id
);
1176 nh_id
= id
| EVPN_NHG_ID_TYPE_BIT
;
1177 /* Add to NHG hash */
1179 (void)hash_get(zmh_info
->nhg_table
, es
, hash_alloc_intern
);
1181 nh_id
= id
| EVPN_NH_ID_TYPE_BIT
;
1187 static void zebra_evpn_nhid_free(uint32_t nh_id
, struct zebra_evpn_es
*es
)
1189 uint32_t id
= (nh_id
& EVPN_NH_ID_VAL_MASK
);
1195 hash_release(zmh_info
->nhg_table
, es
);
1199 bf_release_index(zmh_info
->nh_id_bitmap
, id
);
1202 static unsigned int zebra_evpn_nh_ip_hash_keymake(const void *p
)
1204 const struct zebra_evpn_l2_nh
*nh
= p
;
1206 return jhash_1word(nh
->vtep_ip
.s_addr
, 0);
1209 static bool zebra_evpn_nh_ip_cmp(const void *p1
, const void *p2
)
1211 const struct zebra_evpn_l2_nh
*nh1
= p1
;
1212 const struct zebra_evpn_l2_nh
*nh2
= p2
;
1214 if (nh1
== NULL
&& nh2
== NULL
)
1217 if (nh1
== NULL
|| nh2
== NULL
)
1220 return (nh1
->vtep_ip
.s_addr
== nh2
->vtep_ip
.s_addr
);
1223 static unsigned int zebra_evpn_nhg_hash_keymake(const void *p
)
1225 const struct zebra_evpn_es
*es
= p
;
1227 return jhash_1word(es
->nhg_id
, 0);
1230 static bool zebra_evpn_nhg_cmp(const void *p1
, const void *p2
)
1232 const struct zebra_evpn_es
*es1
= p1
;
1233 const struct zebra_evpn_es
*es2
= p2
;
1235 if (es1
== NULL
&& es2
== NULL
)
1238 if (es1
== NULL
|| es2
== NULL
)
1241 return (es1
->nhg_id
== es2
->nhg_id
);
1244 /* Lookup ES using the NHG id associated with it */
1245 static struct zebra_evpn_es
*zebra_evpn_nhg_find(uint32_t nhg_id
)
1247 struct zebra_evpn_es
*es
;
1248 struct zebra_evpn_es tmp
;
1250 tmp
.nhg_id
= nhg_id
;
1251 es
= hash_lookup(zmh_info
->nhg_table
, &tmp
);
1256 /* Returns TRUE if the NHG is associated with a local ES */
1257 bool zebra_evpn_nhg_is_local_es(uint32_t nhg_id
,
1258 struct zebra_evpn_es
**local_es
)
1260 struct zebra_evpn_es
*es
;
1262 es
= zebra_evpn_nhg_find(nhg_id
);
1263 if (es
&& (es
->flags
& ZEBRA_EVPNES_LOCAL
)) {
1272 /* update remote macs associated with the ES */
1273 static void zebra_evpn_nhg_mac_update(struct zebra_evpn_es
*es
)
1275 struct zebra_mac
*mac
;
1276 struct listnode
*node
;
1279 local_via_nw
= zebra_evpn_es_local_mac_via_network_port(es
);
1280 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
|| IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
1281 zlog_debug("mac update on es %s nhg %s", es
->esi_str
,
1282 (es
->flags
& ZEBRA_EVPNES_NHG_ACTIVE
)
1286 for (ALL_LIST_ELEMENTS_RO(es
->mac_list
, node
, mac
)) {
1287 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE
)
1288 || (local_via_nw
&& CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
)
1289 && zebra_evpn_mac_is_static(mac
))) {
1290 if (es
->flags
& ZEBRA_EVPNES_NHG_ACTIVE
) {
1291 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
1293 "%smac %pEA install via es %s nhg 0x%x",
1294 (mac
->flags
& ZEBRA_MAC_REMOTE
)
1297 &mac
->macaddr
, es
->esi_str
,
1299 zebra_evpn_rem_mac_install(
1300 mac
->zevpn
, mac
, false /*was_static*/);
1302 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
1304 "%smac %pEA un-install es %s",
1305 (mac
->flags
& ZEBRA_MAC_REMOTE
)
1308 &mac
->macaddr
, es
->esi_str
);
1309 zebra_evpn_rem_mac_uninstall(mac
->zevpn
, mac
,
1316 /* The MAC ECMP group is activated on the first VTEP */
1317 static void zebra_evpn_nhg_update(struct zebra_evpn_es
*es
)
1319 uint32_t nh_cnt
= 0;
1320 struct nh_grp nh_ids
[ES_VTEP_MAX_CNT
];
1321 struct zebra_evpn_es_vtep
*es_vtep
;
1322 struct listnode
*node
;
1327 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
1331 if (nh_cnt
>= ES_VTEP_MAX_CNT
)
1334 memset(&nh_ids
[nh_cnt
], 0, sizeof(struct nh_grp
));
1335 nh_ids
[nh_cnt
].id
= es_vtep
->nh
->nh_id
;
1340 if (IS_ZEBRA_DEBUG_EVPN_MH_NH
) {
1341 char nh_str
[ES_VTEP_LIST_STR_SZ
];
1346 for (i
= 0; i
< nh_cnt
; ++i
) {
1347 snprintf(nh_buf
, sizeof(nh_buf
), "%u ",
1349 strlcat(nh_str
, nh_buf
, sizeof(nh_str
));
1351 zlog_debug("es %s nhg %u add %s", es
->esi_str
,
1352 es
->nhg_id
, nh_str
);
1355 kernel_upd_mac_nhg(es
->nhg_id
, nh_cnt
, nh_ids
);
1356 if (!(es
->flags
& ZEBRA_EVPNES_NHG_ACTIVE
)) {
1357 es
->flags
|= ZEBRA_EVPNES_NHG_ACTIVE
;
1358 /* add backup NHG to the br-port */
1359 if ((es
->flags
& ZEBRA_EVPNES_LOCAL
))
1360 zebra_evpn_es_br_port_dplane_update(es
,
1362 zebra_evpn_nhg_mac_update(es
);
1365 if (es
->flags
& ZEBRA_EVPNES_NHG_ACTIVE
) {
1366 if (IS_ZEBRA_DEBUG_EVPN_MH_NH
)
1367 zlog_debug("es %s nhg %u del", es
->esi_str
,
1369 es
->flags
&= ~ZEBRA_EVPNES_NHG_ACTIVE
;
1370 /* remove backup NHG from the br-port */
1371 if ((es
->flags
& ZEBRA_EVPNES_LOCAL
))
1372 zebra_evpn_es_br_port_dplane_update(es
,
1374 zebra_evpn_nhg_mac_update(es
);
1375 kernel_del_mac_nhg(es
->nhg_id
);
1381 static void zebra_evpn_es_l2_nh_show_entry(struct zebra_evpn_l2_nh
*nh
,
1383 json_object
*json_array
)
1386 json_object
*json
= NULL
;
1388 json
= json_object_new_object();
1389 json_object_string_addf(json
, "vtep", "%pI4", &nh
->vtep_ip
);
1390 json_object_int_add(json
, "nhId", nh
->nh_id
);
1391 json_object_int_add(json
, "refCnt", nh
->ref_cnt
);
1393 json_object_array_add(json_array
, json
);
1395 vty_out(vty
, "%-16pI4 %-10u %u\n", &nh
->vtep_ip
, nh
->nh_id
,
1400 static void zebra_evpn_l2_nh_show_cb(struct hash_bucket
*bucket
, void *ctxt
)
1402 struct zebra_evpn_l2_nh
*nh
= (struct zebra_evpn_l2_nh
*)bucket
->data
;
1403 struct evpn_mh_show_ctx
*wctx
= (struct evpn_mh_show_ctx
*)ctxt
;
1405 zebra_evpn_es_l2_nh_show_entry(nh
, wctx
->vty
, wctx
->json
);
1408 void zebra_evpn_l2_nh_show(struct vty
*vty
, bool uj
)
1410 struct evpn_mh_show_ctx wctx
;
1411 json_object
*json_array
= NULL
;
1414 json_array
= json_object_new_array();
1416 vty_out(vty
, "%-16s %-10s %s\n", "VTEP", "NH id", "#ES");
1419 memset(&wctx
, 0, sizeof(wctx
));
1421 wctx
.json
= json_array
;
1423 hash_iterate(zmh_info
->nh_ip_table
, zebra_evpn_l2_nh_show_cb
, &wctx
);
1426 vty_json(vty
, json_array
);
1429 static struct zebra_evpn_l2_nh
*zebra_evpn_l2_nh_find(struct in_addr vtep_ip
)
1431 struct zebra_evpn_l2_nh
*nh
;
1432 struct zebra_evpn_l2_nh tmp
;
1434 tmp
.vtep_ip
.s_addr
= vtep_ip
.s_addr
;
1435 nh
= hash_lookup(zmh_info
->nh_ip_table
, &tmp
);
1440 static struct zebra_evpn_l2_nh
*zebra_evpn_l2_nh_alloc(struct in_addr vtep_ip
)
1442 struct zebra_evpn_l2_nh
*nh
;
1444 nh
= XCALLOC(MTYPE_L2_NH
, sizeof(*nh
));
1445 nh
->vtep_ip
= vtep_ip
;
1446 (void)hash_get(zmh_info
->nh_ip_table
, nh
, hash_alloc_intern
);
1448 nh
->nh_id
= zebra_evpn_nhid_alloc(NULL
);
1450 hash_release(zmh_info
->nh_ip_table
, nh
);
1451 XFREE(MTYPE_L2_NH
, nh
);
1455 /* install the NH in the dataplane */
1456 kernel_upd_mac_nh(nh
->nh_id
, nh
->vtep_ip
);
1461 static void zebra_evpn_l2_nh_free(struct zebra_evpn_l2_nh
*nh
)
1463 /* delete the NH from the dataplane */
1464 kernel_del_mac_nh(nh
->nh_id
);
1466 zebra_evpn_nhid_free(nh
->nh_id
, NULL
);
1467 hash_release(zmh_info
->nh_ip_table
, nh
);
1468 XFREE(MTYPE_L2_NH
, nh
);
1471 static void zebra_evpn_l2_nh_es_vtep_ref(struct zebra_evpn_es_vtep
*es_vtep
)
1476 es_vtep
->nh
= zebra_evpn_l2_nh_find(es_vtep
->vtep_ip
);
1478 es_vtep
->nh
= zebra_evpn_l2_nh_alloc(es_vtep
->vtep_ip
);
1481 zlog_warn("es %s vtep %pI4 nh ref failed", es_vtep
->es
->esi_str
,
1486 ++es_vtep
->nh
->ref_cnt
;
1488 if (IS_ZEBRA_DEBUG_EVPN_MH_NH
)
1489 zlog_debug("es %s vtep %pI4 nh %u ref %u", es_vtep
->es
->esi_str
,
1490 &es_vtep
->vtep_ip
, es_vtep
->nh
->nh_id
,
1491 es_vtep
->nh
->ref_cnt
);
1493 /* add the NH to the parent NHG */
1494 zebra_evpn_nhg_update(es_vtep
->es
);
1497 static void zebra_evpn_l2_nh_es_vtep_deref(struct zebra_evpn_es_vtep
*es_vtep
)
1499 struct zebra_evpn_l2_nh
*nh
= es_vtep
->nh
;
1508 if (IS_ZEBRA_DEBUG_EVPN_MH_NH
)
1509 zlog_debug("es %s vtep %pI4 nh %u deref %u",
1510 es_vtep
->es
->esi_str
, &es_vtep
->vtep_ip
, nh
->nh_id
,
1513 /* remove the NH from the parent NHG */
1514 zebra_evpn_nhg_update(es_vtep
->es
);
1516 /* uninstall the NH */
1518 zebra_evpn_l2_nh_free(nh
);
1521 /*****************************************************************************/
1522 /* Ethernet Segment Management
1523 * 1. Ethernet Segment is a collection of links attached to the same
1524 * server (MHD) or switch (MHN)
1525 * 2. An Ethernet Segment can span multiple PEs and is identified by the
1527 * 3. Zebra manages the local ESI configuration.
1528 * 4. It also maintains the aliasing that maps an ESI (local or remote)
1529 * to one or more PEs/VTEPs.
1530 * 5. remote ESs are added by BGP (on rxing EAD Type-1 routes)
1532 /* A list of remote VTEPs is maintained for each ES. This list includes -
1533 * 1. VTEPs for which we have imported the ESR i.e. ES-peers
1534 * 2. VTEPs that have an "active" ES-EVI VTEP i.e. EAD-per-ES and EAD-per-EVI
1535 * have been imported into one or more EVPNs
1537 static int zebra_evpn_es_vtep_cmp(void *p1
, void *p2
)
1539 const struct zebra_evpn_es_vtep
*es_vtep1
= p1
;
1540 const struct zebra_evpn_es_vtep
*es_vtep2
= p2
;
1542 return es_vtep1
->vtep_ip
.s_addr
- es_vtep2
->vtep_ip
.s_addr
;
1545 static struct zebra_evpn_es_vtep
*zebra_evpn_es_vtep_new(
1546 struct zebra_evpn_es
*es
, struct in_addr vtep_ip
)
1548 struct zebra_evpn_es_vtep
*es_vtep
;
1550 es_vtep
= XCALLOC(MTYPE_ZES_VTEP
, sizeof(*es_vtep
));
1553 es_vtep
->vtep_ip
.s_addr
= vtep_ip
.s_addr
;
1554 listnode_init(&es_vtep
->es_listnode
, es_vtep
);
1555 listnode_add_sort(es
->es_vtep_list
, &es_vtep
->es_listnode
);
1560 static void zebra_evpn_es_vtep_free(struct zebra_evpn_es_vtep
*es_vtep
)
1562 struct zebra_evpn_es
*es
= es_vtep
->es
;
1564 list_delete_node(es
->es_vtep_list
, &es_vtep
->es_listnode
);
1565 /* update the L2-NHG associated with the ES */
1566 zebra_evpn_l2_nh_es_vtep_deref(es_vtep
);
1567 XFREE(MTYPE_ZES_VTEP
, es_vtep
);
1571 /* check if VTEP is already part of the list */
1572 static struct zebra_evpn_es_vtep
*zebra_evpn_es_vtep_find(
1573 struct zebra_evpn_es
*es
, struct in_addr vtep_ip
)
1575 struct listnode
*node
= NULL
;
1576 struct zebra_evpn_es_vtep
*es_vtep
;
1578 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
1579 if (es_vtep
->vtep_ip
.s_addr
== vtep_ip
.s_addr
)
1585 /* flush all the dataplane br-port info associated with the ES */
1586 static bool zebra_evpn_es_br_port_dplane_clear(struct zebra_evpn_es
*es
)
1588 struct in_addr sph_filters
[ES_VTEP_MAX_CNT
];
1590 if (!(es
->flags
& ZEBRA_EVPNES_BR_PORT
))
1593 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
1594 zlog_debug("es %s br-port dplane clear", es
->esi_str
);
1596 memset(&sph_filters
, 0, sizeof(sph_filters
));
1597 dplane_br_port_update(es
->zif
->ifp
, false /* non_df */, 0, sph_filters
,
1598 0 /* backup_nhg_id */);
1603 zebra_evpn_es_br_port_dplane_update_needed(struct zebra_evpn_es
*es
)
1605 return (es
->flags
& ZEBRA_EVPNES_NON_DF
)
1606 || (es
->flags
& ZEBRA_EVPNES_NHG_ACTIVE
)
1607 || listcount(es
->es_vtep_list
);
1610 /* returns TRUE if dplane entry was updated */
1611 static bool zebra_evpn_es_br_port_dplane_update(struct zebra_evpn_es
*es
,
1614 uint32_t backup_nhg_id
;
1615 struct in_addr sph_filters
[ES_VTEP_MAX_CNT
];
1616 struct listnode
*node
= NULL
;
1617 struct zebra_evpn_es_vtep
*es_vtep
;
1618 uint32_t sph_filter_cnt
= 0;
1620 if (!(es
->flags
& ZEBRA_EVPNES_LOCAL
))
1621 return zebra_evpn_es_br_port_dplane_clear(es
);
1623 /* If the ES is not a bridge port there is nothing
1626 if (!(es
->flags
& ZEBRA_EVPNES_BR_PORT
))
1629 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
1630 zlog_debug("es %s br-port dplane update by %s", es
->esi_str
,
1632 backup_nhg_id
= (es
->flags
& ZEBRA_EVPNES_NHG_ACTIVE
) ? es
->nhg_id
: 0;
1634 memset(&sph_filters
, 0, sizeof(sph_filters
));
1635 if (es
->flags
& ZEBRA_EVPNES_BYPASS
) {
1636 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
1638 "es %s SPH filter disabled as it is in bypass",
1641 if (listcount(es
->es_vtep_list
) > ES_VTEP_MAX_CNT
) {
1642 zlog_warn("es %s vtep count %d exceeds filter cnt %d",
1643 es
->esi_str
, listcount(es
->es_vtep_list
),
1646 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
,
1649 & ZEBRA_EVPNES_VTEP_DEL_IN_PROG
)
1651 sph_filters
[sph_filter_cnt
] = es_vtep
->vtep_ip
;
1657 dplane_br_port_update(es
->zif
->ifp
, !!(es
->flags
& ZEBRA_EVPNES_NON_DF
),
1658 sph_filter_cnt
, sph_filters
, backup_nhg_id
);
1663 /* returns TRUE if dplane entry was updated */
1664 static bool zebra_evpn_es_df_change(struct zebra_evpn_es
*es
, bool new_non_df
,
1665 const char *caller
, const char *reason
)
1669 old_non_df
= !!(es
->flags
& ZEBRA_EVPNES_NON_DF
);
1671 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
1672 zlog_debug("df-change es %s %s to %s; %s: %s", es
->esi_str
,
1673 old_non_df
? "non-df" : "df",
1674 new_non_df
? "non-df" : "df", caller
, reason
);
1676 if (old_non_df
== new_non_df
)
1680 es
->flags
|= ZEBRA_EVPNES_NON_DF
;
1682 es
->flags
&= ~ZEBRA_EVPNES_NON_DF
;
1684 /* update non-DF block filter in the dataplane */
1685 return zebra_evpn_es_br_port_dplane_update(es
, __func__
);
1689 /* returns TRUE if dplane entry was updated */
1690 static bool zebra_evpn_es_run_df_election(struct zebra_evpn_es
*es
,
1693 struct listnode
*node
= NULL
;
1694 struct zebra_evpn_es_vtep
*es_vtep
;
1695 bool new_non_df
= false;
1697 /* If the ES is not ready (i.e. not completely configured) there
1698 * is no need to setup the BUM block filter
1700 if (!(es
->flags
& ZEBRA_EVPNES_LOCAL
)
1701 || (es
->flags
& ZEBRA_EVPNES_BYPASS
)
1702 || !zmh_info
->es_originator_ip
.s_addr
)
1703 return zebra_evpn_es_df_change(es
, new_non_df
, caller
,
1706 /* if oper-state is down DF filtering must be on. when the link comes
1707 * up again dataplane should block BUM till FRR has had the chance
1708 * to run DF election again
1710 if (!(es
->flags
& ZEBRA_EVPNES_OPER_UP
)) {
1712 return zebra_evpn_es_df_change(es
, new_non_df
, caller
,
1716 /* ES was just created; we need to wait for the peers to rx the
1717 * our Type-4 routes and for the switch to import the peers' Type-4
1720 if (es
->df_delay_timer
) {
1722 return zebra_evpn_es_df_change(es
, new_non_df
, caller
,
1726 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
1727 /* Only VTEPs that have advertised the ESR can participate
1730 if (!(es_vtep
->flags
& ZEBRA_EVPNES_VTEP_RXED_ESR
))
1733 /* If the DF alg is not the same we should fall back to
1734 * service-carving. But as service-carving is not supported
1735 * we will stop forwarding BUM
1737 if (es_vtep
->df_alg
!= EVPN_MH_DF_ALG_PREF
) {
1742 /* Peer VTEP wins DF election if -
1743 * the peer-VTEP has higher preference (or)
1744 * the pref is the same but peer's IP address is lower
1746 if ((es_vtep
->df_pref
> es
->df_pref
)
1747 || ((es_vtep
->df_pref
== es
->df_pref
)
1748 && (es_vtep
->vtep_ip
.s_addr
1749 < zmh_info
->es_originator_ip
.s_addr
))) {
1755 return zebra_evpn_es_df_change(es
, new_non_df
, caller
, "elected");
1758 static void zebra_evpn_es_vtep_add(struct zebra_evpn_es
*es
,
1759 struct in_addr vtep_ip
, bool esr_rxed
,
1760 uint8_t df_alg
, uint16_t df_pref
)
1762 struct zebra_evpn_es_vtep
*es_vtep
;
1764 bool dplane_updated
= false;
1766 es_vtep
= zebra_evpn_es_vtep_find(es
, vtep_ip
);
1769 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
1770 zlog_debug("es %s vtep %pI4 add",
1771 es
->esi_str
, &vtep_ip
);
1772 es_vtep
= zebra_evpn_es_vtep_new(es
, vtep_ip
);
1773 /* update the L2-NHG associated with the ES */
1774 zebra_evpn_l2_nh_es_vtep_ref(es_vtep
);
1777 old_esr_rxed
= !!(es_vtep
->flags
& ZEBRA_EVPNES_VTEP_RXED_ESR
);
1778 if ((old_esr_rxed
!= esr_rxed
) || (es_vtep
->df_alg
!= df_alg
)
1779 || (es_vtep
->df_pref
!= df_pref
)) {
1780 /* If any of the DF election params changed we need to re-run
1784 es_vtep
->flags
|= ZEBRA_EVPNES_VTEP_RXED_ESR
;
1786 es_vtep
->flags
&= ~ZEBRA_EVPNES_VTEP_RXED_ESR
;
1787 es_vtep
->df_alg
= df_alg
;
1788 es_vtep
->df_pref
= df_pref
;
1789 dplane_updated
= zebra_evpn_es_run_df_election(es
, __func__
);
1791 /* add the vtep to the SPH list */
1792 if (!dplane_updated
&& (es
->flags
& ZEBRA_EVPNES_LOCAL
))
1793 zebra_evpn_es_br_port_dplane_update(es
, __func__
);
1796 static void zebra_evpn_es_vtep_del(struct zebra_evpn_es
*es
,
1797 struct in_addr vtep_ip
)
1799 struct zebra_evpn_es_vtep
*es_vtep
;
1800 bool dplane_updated
= false;
1802 es_vtep
= zebra_evpn_es_vtep_find(es
, vtep_ip
);
1805 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
1806 zlog_debug("es %s vtep %pI4 del",
1807 es
->esi_str
, &vtep_ip
);
1808 es_vtep
->flags
|= ZEBRA_EVPNES_VTEP_DEL_IN_PROG
;
1809 if (es_vtep
->flags
& ZEBRA_EVPNES_VTEP_RXED_ESR
) {
1810 es_vtep
->flags
&= ~ZEBRA_EVPNES_VTEP_RXED_ESR
;
1812 zebra_evpn_es_run_df_election(es
, __func__
);
1814 /* remove the vtep from the SPH list */
1815 if (!dplane_updated
&& (es
->flags
& ZEBRA_EVPNES_LOCAL
))
1816 zebra_evpn_es_br_port_dplane_update(es
, __func__
);
1817 zebra_evpn_es_vtep_free(es_vtep
);
1821 /* compare ES-IDs for the global ES RB tree */
1822 static int zebra_es_rb_cmp(const struct zebra_evpn_es
*es1
,
1823 const struct zebra_evpn_es
*es2
)
1825 return memcmp(&es1
->esi
, &es2
->esi
, ESI_BYTES
);
1827 RB_GENERATE(zebra_es_rb_head
, zebra_evpn_es
, rb_node
, zebra_es_rb_cmp
);
1830 struct zebra_evpn_es
*zebra_evpn_es_find(const esi_t
*esi
)
1832 struct zebra_evpn_es tmp
;
1834 memcpy(&tmp
.esi
, esi
, sizeof(esi_t
));
1835 return RB_FIND(zebra_es_rb_head
, &zmh_info
->es_rb_tree
, &tmp
);
1838 /* A new local es is created when a local-es-id and sysmac is configured
1839 * against an interface.
1841 static struct zebra_evpn_es
*zebra_evpn_es_new(const esi_t
*esi
)
1843 struct zebra_evpn_es
*es
;
1845 if (!memcmp(esi
, zero_esi
, sizeof(esi_t
)))
1848 es
= XCALLOC(MTYPE_ZES
, sizeof(struct zebra_evpn_es
));
1851 memcpy(&es
->esi
, esi
, sizeof(esi_t
));
1852 esi_to_str(&es
->esi
, es
->esi_str
, sizeof(es
->esi_str
));
1854 /* Add to rb_tree */
1855 RB_INSERT(zebra_es_rb_head
, &zmh_info
->es_rb_tree
, es
);
1857 /* Initialise the ES-EVI list */
1858 es
->es_evi_list
= list_new();
1859 listset_app_node_mem(es
->es_evi_list
);
1861 /* Initialise the VTEP list */
1862 es
->es_vtep_list
= list_new();
1863 listset_app_node_mem(es
->es_vtep_list
);
1864 es
->es_vtep_list
->cmp
= zebra_evpn_es_vtep_cmp
;
1866 /* mac entries associated with the ES */
1867 es
->mac_list
= list_new();
1868 listset_app_node_mem(es
->mac_list
);
1871 es
->nhg_id
= zebra_evpn_nhid_alloc(es
);
1873 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
1874 zlog_debug("es %s nhg %u new", es
->esi_str
, es
->nhg_id
);
1879 /* Free a given ES -
1880 * This just frees appropriate memory, caller should have taken other
1883 static void zebra_evpn_es_free(struct zebra_evpn_es
**esp
)
1885 struct zebra_evpn_es
*es
= *esp
;
1887 /* If the ES has a local or remote reference it cannot be freed.
1888 * Free is also prevented if there are MAC entries referencing
1891 if ((es
->flags
& (ZEBRA_EVPNES_LOCAL
| ZEBRA_EVPNES_REMOTE
)) ||
1892 listcount(es
->mac_list
))
1895 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
1896 zlog_debug("es %s free", es
->esi_str
);
1898 /* If the NHG is still installed uninstall it and free the id */
1899 if (es
->flags
& ZEBRA_EVPNES_NHG_ACTIVE
) {
1900 es
->flags
&= ~ZEBRA_EVPNES_NHG_ACTIVE
;
1901 kernel_del_mac_nhg(es
->nhg_id
);
1903 zebra_evpn_nhid_free(es
->nhg_id
, es
);
1905 /* cleanup resources maintained against the ES */
1906 list_delete(&es
->es_evi_list
);
1907 list_delete(&es
->es_vtep_list
);
1908 list_delete(&es
->mac_list
);
1910 /* remove from the VNI-ESI rb tree */
1911 RB_REMOVE(zebra_es_rb_head
, &zmh_info
->es_rb_tree
, es
);
1913 XFREE(MTYPE_ZES
, es
);
1918 /* Inform BGP about local ES addition */
1919 static int zebra_evpn_es_send_add_to_client(struct zebra_evpn_es
*es
)
1921 struct zserv
*client
;
1926 client
= zserv_find_client(ZEBRA_ROUTE_BGP
, 0);
1927 /* BGP may not be running. */
1931 s
= stream_new(ZEBRA_MAX_PACKET_SIZ
);
1933 zclient_create_header(s
, ZEBRA_LOCAL_ES_ADD
, zebra_vrf_get_evpn_id());
1934 stream_put(s
, &es
->esi
, sizeof(esi_t
));
1935 stream_put_ipv4(s
, zmh_info
->es_originator_ip
.s_addr
);
1936 oper_up
= !!(es
->flags
& ZEBRA_EVPNES_OPER_UP
);
1937 stream_putc(s
, oper_up
);
1938 stream_putw(s
, es
->df_pref
);
1939 bypass
= !!(es
->flags
& ZEBRA_EVPNES_BYPASS
);
1940 stream_putc(s
, bypass
);
1942 /* Write packet size. */
1943 stream_putw_at(s
, 0, stream_get_endp(s
));
1945 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
1947 "send add local es %s %pI4 active %u df_pref %u%s to %s",
1948 es
->esi_str
, &zmh_info
->es_originator_ip
, oper_up
,
1949 es
->df_pref
, bypass
? " bypass" : "",
1950 zebra_route_string(client
->proto
));
1952 client
->local_es_add_cnt
++;
1953 return zserv_send_message(client
, s
);
1956 /* Inform BGP about local ES deletion */
1957 static int zebra_evpn_es_send_del_to_client(struct zebra_evpn_es
*es
)
1959 struct zserv
*client
;
1962 client
= zserv_find_client(ZEBRA_ROUTE_BGP
, 0);
1963 /* BGP may not be running. */
1967 s
= stream_new(ZEBRA_MAX_PACKET_SIZ
);
1970 zclient_create_header(s
, ZEBRA_LOCAL_ES_DEL
, zebra_vrf_get_evpn_id());
1971 stream_put(s
, &es
->esi
, sizeof(esi_t
));
1973 /* Write packet size. */
1974 stream_putw_at(s
, 0, stream_get_endp(s
));
1976 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
1977 zlog_debug("send del local es %s to %s", es
->esi_str
,
1978 zebra_route_string(client
->proto
));
1980 client
->local_es_del_cnt
++;
1981 return zserv_send_message(client
, s
);
1984 static void zebra_evpn_es_re_eval_send_to_client(struct zebra_evpn_es
*es
,
1985 bool es_evi_re_reval
)
1989 struct listnode
*node
;
1990 struct zebra_evpn_es_evi
*es_evi
;
1992 old_ready
= !!(es
->flags
& ZEBRA_EVPNES_READY_FOR_BGP
);
1994 if ((es
->flags
& ZEBRA_EVPNES_LOCAL
) &&
1995 zmh_info
->es_originator_ip
.s_addr
)
1996 es
->flags
|= ZEBRA_EVPNES_READY_FOR_BGP
;
1998 es
->flags
&= ~ZEBRA_EVPNES_READY_FOR_BGP
;
2000 new_ready
= !!(es
->flags
& ZEBRA_EVPNES_READY_FOR_BGP
);
2001 if (old_ready
== new_ready
)
2005 zebra_evpn_es_send_add_to_client(es
);
2007 zebra_evpn_es_send_del_to_client(es
);
2009 /* re-eval associated EVIs */
2010 if (es_evi_re_reval
) {
2011 for (ALL_LIST_ELEMENTS_RO(es
->es_evi_list
, node
, es_evi
)) {
2012 if (!(es_evi
->flags
& ZEBRA_EVPNES_EVI_LOCAL
))
2014 zebra_evpn_es_evi_re_eval_send_to_client(es_evi
);
2019 void zebra_evpn_es_send_all_to_client(bool add
)
2021 struct listnode
*es_node
;
2022 struct listnode
*evi_node
;
2023 struct zebra_evpn_es
*es
;
2024 struct zebra_evpn_es_evi
*es_evi
;
2029 for (ALL_LIST_ELEMENTS_RO(zmh_info
->local_es_list
, es_node
, es
)) {
2030 if (es
->flags
& ZEBRA_EVPNES_READY_FOR_BGP
) {
2032 zebra_evpn_es_send_add_to_client(es
);
2033 for (ALL_LIST_ELEMENTS_RO(es
->es_evi_list
,
2034 evi_node
, es_evi
)) {
2035 if (!(es_evi
->flags
&
2036 ZEBRA_EVPNES_EVI_READY_FOR_BGP
))
2040 zebra_evpn_es_evi_send_to_client(
2044 zebra_evpn_es_evi_send_to_client(
2049 zebra_evpn_es_send_del_to_client(es
);
2054 /* walk the vlan bitmap associated with the zif and create or delete
2055 * es_evis for all vlans associated with a VNI.
2056 * XXX: This API is really expensive. optimize later if possible.
2058 static void zebra_evpn_es_setup_evis(struct zebra_evpn_es
*es
)
2060 struct zebra_if
*zif
= es
->zif
;
2062 struct zebra_evpn_access_bd
*acc_bd
;
2064 if (!bf_is_inited(zif
->vlan_bitmap
))
2067 bf_for_each_set_bit(zif
->vlan_bitmap
, vid
, IF_VLAN_BITMAP_MAX
) {
2068 acc_bd
= zebra_evpn_acc_vl_find(vid
, zif
->brslave_info
.br_if
);
2070 zebra_evpn_local_es_evi_add(es
, acc_bd
->zevpn
);
2074 static void zebra_evpn_flush_local_mac(struct zebra_mac
*mac
,
2075 struct interface
*ifp
)
2078 struct zebra_if
*zif
;
2079 struct interface
*br_ifp
;
2080 struct zebra_vxlan_vni
*vni
;
2083 br_ifp
= zif
->brslave_info
.br_if
;
2087 if (mac
->zevpn
->vxlan_if
) {
2088 zif
= mac
->zevpn
->vxlan_if
->info
;
2089 vni
= zebra_vxlan_if_vni_find(zif
, mac
->zevpn
->vni
);
2090 vid
= vni
->access_vlan
;
2095 /* delete the local mac from the dataplane */
2096 dplane_local_mac_del(ifp
, br_ifp
, vid
, &mac
->macaddr
);
2097 /* delete the local mac in zebra */
2098 zebra_evpn_del_local_mac(mac
->zevpn
, mac
, true);
2101 static void zebra_evpn_es_flush_local_macs(struct zebra_evpn_es
*es
,
2102 struct interface
*ifp
, bool add
)
2104 struct zebra_mac
*mac
;
2105 struct listnode
*node
;
2106 struct listnode
*nnode
;
2108 for (ALL_LIST_ELEMENTS(es
->mac_list
, node
, nnode
, mac
)) {
2109 if (!CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
))
2112 /* If ES is being attached/detached from the access port we
2113 * need to clear local activity and peer activity and start
2115 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
2116 zlog_debug("VNI %u mac %pEA update; local ES %s %s",
2119 es
->esi_str
, add
? "add" : "del");
2120 zebra_evpn_flush_local_mac(mac
, ifp
);
2124 void zebra_evpn_es_local_br_port_update(struct zebra_if
*zif
)
2126 struct zebra_evpn_es
*es
= zif
->es_info
.es
;
2127 bool old_br_port
= !!(es
->flags
& ZEBRA_EVPNES_BR_PORT
);
2130 if (zif
->brslave_info
.bridge_ifindex
!= IFINDEX_INTERNAL
)
2131 es
->flags
|= ZEBRA_EVPNES_BR_PORT
;
2133 es
->flags
&= ~ZEBRA_EVPNES_BR_PORT
;
2135 new_br_port
= !!(es
->flags
& ZEBRA_EVPNES_BR_PORT
);
2136 if (old_br_port
== new_br_port
)
2139 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2140 zlog_debug("es %s br_port change old %u new %u", es
->esi_str
,
2141 old_br_port
, new_br_port
);
2143 /* update the dataplane br_port attrs */
2144 if (new_br_port
&& zebra_evpn_es_br_port_dplane_update_needed(es
))
2145 zebra_evpn_es_br_port_dplane_update(es
, __func__
);
2148 /* On config of first local-ES turn off DAD */
2149 static void zebra_evpn_mh_dup_addr_detect_off(void)
2151 struct zebra_vrf
*zvrf
;
2155 if (zmh_info
->flags
& ZEBRA_EVPN_MH_DUP_ADDR_DETECT_OFF
)
2158 zvrf
= zebra_vrf_get_evpn();
2159 old_detect
= zebra_evpn_do_dup_addr_detect(zvrf
);
2160 zmh_info
->flags
|= ZEBRA_EVPN_MH_DUP_ADDR_DETECT_OFF
;
2161 new_detect
= zebra_evpn_do_dup_addr_detect(zvrf
);
2163 if (old_detect
&& !new_detect
) {
2164 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2166 "evpn-mh config caused DAD addr detect chg from %s to %s",
2167 old_detect
? "on" : "off",
2168 new_detect
? "on" : "off");
2169 zebra_vxlan_clear_dup_detect_vni_all(zvrf
);
2173 /* On config of first local-ES turn off advertisement of STALE/DELAY/PROBE
2176 static void zebra_evpn_mh_advertise_reach_neigh_only(void)
2178 if (zmh_info
->flags
& ZEBRA_EVPN_MH_ADV_REACHABLE_NEIGH_ONLY
)
2181 zmh_info
->flags
|= ZEBRA_EVPN_MH_ADV_REACHABLE_NEIGH_ONLY
;
2182 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2183 zlog_debug("evpn-mh: only REACHABLE neigh advertised");
2185 /* XXX - if STALE/DELAY/PROBE neighs were previously advertised we
2186 * need to withdraw them
2190 /* On config of first local-ES turn on advertisement of local SVI-MAC */
2191 static void zebra_evpn_mh_advertise_svi_mac(void)
2193 if (zmh_info
->flags
& ZEBRA_EVPN_MH_ADV_SVI_MAC
)
2196 zmh_info
->flags
|= ZEBRA_EVPN_MH_ADV_SVI_MAC
;
2197 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2198 zlog_debug("evpn-mh: advertise SVI MAC");
2200 /* walk through all SVIs and see if we need to advertise the MAC */
2201 zebra_evpn_acc_vl_adv_svi_mac_all();
2204 static void zebra_evpn_es_df_delay_exp_cb(struct thread
*t
)
2206 struct zebra_evpn_es
*es
;
2210 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2211 zlog_debug("es %s df-delay expired", es
->esi_str
);
2213 zebra_evpn_es_run_df_election(es
, __func__
);
2216 /* currently there is no global config to turn on MH instead we use
2217 * the addition of the first local Ethernet Segment as the trigger to
2218 * init MH specific processing
2220 static void zebra_evpn_mh_on_first_local_es(void)
2222 zebra_evpn_mh_dup_addr_detect_off();
2223 zebra_evpn_mh_advertise_reach_neigh_only();
2224 zebra_evpn_mh_advertise_svi_mac();
2227 static void zebra_evpn_es_local_info_set(struct zebra_evpn_es
*es
,
2228 struct zebra_if
*zif
)
2230 if (es
->flags
& ZEBRA_EVPNES_LOCAL
)
2233 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2234 zlog_debug("local es %s add; nhg %u if %s", es
->esi_str
,
2235 es
->nhg_id
, zif
->ifp
->name
);
2237 zebra_evpn_mh_on_first_local_es();
2239 es
->flags
|= ZEBRA_EVPNES_LOCAL
;
2240 listnode_init(&es
->local_es_listnode
, es
);
2241 listnode_add(zmh_info
->local_es_list
, &es
->local_es_listnode
);
2243 /* attach es to interface */
2244 zif
->es_info
.es
= es
;
2245 es
->df_pref
= zif
->es_info
.df_pref
? zif
->es_info
.df_pref
2246 : EVPN_MH_DF_PREF_DEFAULT
;
2248 /* attach interface to es */
2250 if (if_is_operative(zif
->ifp
))
2251 es
->flags
|= ZEBRA_EVPNES_OPER_UP
;
2253 if (zif
->brslave_info
.bridge_ifindex
!= IFINDEX_INTERNAL
)
2254 es
->flags
|= ZEBRA_EVPNES_BR_PORT
;
2256 /* inherit the bypass flag from the interface */
2257 if (zif
->flags
& ZIF_FLAG_LACP_BYPASS
)
2258 es
->flags
|= ZEBRA_EVPNES_BYPASS
;
2260 /* setup base-vni if one doesn't already exist; the ES will get sent
2261 * to BGP as a part of that process
2263 if (!zmh_info
->es_base_evpn
)
2264 zebra_evpn_es_get_one_base_evpn();
2266 /* send notification to bgp */
2267 zebra_evpn_es_re_eval_send_to_client(es
,
2268 false /* es_evi_re_reval */);
2270 /* Start the DF delay timer on the local ES */
2271 if (!es
->df_delay_timer
)
2272 thread_add_timer(zrouter
.master
, zebra_evpn_es_df_delay_exp_cb
,
2273 es
, ZEBRA_EVPN_MH_DF_DELAY_TIME
,
2274 &es
->df_delay_timer
);
2276 /* See if the local VTEP can function as DF on the ES */
2277 if (!zebra_evpn_es_run_df_election(es
, __func__
)) {
2278 /* check if the dplane entry needs to be re-programmed as a
2279 * result of some thing other than DF status change
2281 if (zebra_evpn_es_br_port_dplane_update_needed(es
))
2282 zebra_evpn_es_br_port_dplane_update(es
, __func__
);
2286 /* Setup ES-EVIs for all VxLAN stretched VLANs associated with
2289 zebra_evpn_es_setup_evis(es
);
2290 /* if there any local macs referring to the ES as dest we
2291 * need to clear the contents and start over
2293 zebra_evpn_es_flush_local_macs(es
, zif
->ifp
, true);
2295 /* inherit EVPN protodown flags on the access port */
2296 zebra_evpn_mh_update_protodown_es(es
, true /*resync_dplane*/);
2299 static void zebra_evpn_es_local_info_clear(struct zebra_evpn_es
**esp
)
2301 struct zebra_if
*zif
;
2302 struct zebra_evpn_es
*es
= *esp
;
2303 bool dplane_updated
= false;
2305 if (!(es
->flags
& ZEBRA_EVPNES_LOCAL
))
2310 /* if there any local macs referring to the ES as dest we
2311 * need to clear the contents and start over
2313 zebra_evpn_es_flush_local_macs(es
, zif
->ifp
, false);
2315 es
->flags
&= ~(ZEBRA_EVPNES_LOCAL
| ZEBRA_EVPNES_READY_FOR_BGP
);
2317 THREAD_OFF(es
->df_delay_timer
);
2319 /* clear EVPN protodown flags on the access port */
2320 zebra_evpn_mh_clear_protodown_es(es
);
2322 /* remove the DF filter */
2323 dplane_updated
= zebra_evpn_es_run_df_election(es
, __func__
);
2325 /* flush the BUM filters and backup NHG */
2326 if (!dplane_updated
)
2327 zebra_evpn_es_br_port_dplane_clear(es
);
2329 /* clear the es from the parent interface */
2330 zif
->es_info
.es
= NULL
;
2333 /* clear all local flags associated with the ES */
2334 es
->flags
&= ~(ZEBRA_EVPNES_OPER_UP
| ZEBRA_EVPNES_BR_PORT
2335 | ZEBRA_EVPNES_BYPASS
);
2337 /* remove from the ES list */
2338 list_delete_node(zmh_info
->local_es_list
, &es
->local_es_listnode
);
2340 /* free up the ES if there is no remote reference */
2341 zebra_evpn_es_free(esp
);
2344 /* Delete an ethernet segment and inform BGP */
2345 static void zebra_evpn_local_es_del(struct zebra_evpn_es
**esp
)
2347 struct zebra_evpn_es_evi
*es_evi
;
2348 struct listnode
*node
= NULL
;
2349 struct listnode
*nnode
= NULL
;
2350 struct zebra_if
*zif
;
2351 struct zebra_evpn_es
*es
= *esp
;
2353 if (!CHECK_FLAG(es
->flags
, ZEBRA_EVPNES_LOCAL
))
2356 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
) {
2358 zlog_debug("local es %s del; nhg %u if %s", es
->esi_str
,
2359 es
->nhg_id
, zif
? zif
->ifp
->name
: "-");
2362 /* remove all ES-EVIs associated with the ES */
2363 for (ALL_LIST_ELEMENTS(es
->es_evi_list
, node
, nnode
, es_evi
))
2364 zebra_evpn_local_es_evi_do_del(es_evi
);
2366 /* send a del if the ES had been sent to BGP earlier */
2367 if (es
->flags
& ZEBRA_EVPNES_READY_FOR_BGP
)
2368 zebra_evpn_es_send_del_to_client(es
);
2370 zebra_evpn_es_local_info_clear(esp
);
2373 /* eval remote info associated with the ES */
2374 static void zebra_evpn_es_remote_info_re_eval(struct zebra_evpn_es
**esp
)
2376 struct zebra_evpn_es
*es
= *esp
;
2378 /* if there are remote VTEPs the ES-EVI is classified as "remote" */
2379 if (listcount(es
->es_vtep_list
)) {
2380 if (!(es
->flags
& ZEBRA_EVPNES_REMOTE
)) {
2381 es
->flags
|= ZEBRA_EVPNES_REMOTE
;
2382 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2383 zlog_debug("remote es %s add; nhg %u",
2384 es
->esi_str
, es
->nhg_id
);
2387 if (es
->flags
& ZEBRA_EVPNES_REMOTE
) {
2388 es
->flags
&= ~ZEBRA_EVPNES_REMOTE
;
2389 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2390 zlog_debug("remote es %s del; nhg %u",
2391 es
->esi_str
, es
->nhg_id
);
2392 zebra_evpn_es_free(esp
);
2397 /* A new local es is created when a local-es-id and sysmac is configured
2398 * against an interface.
2400 static int zebra_evpn_local_es_update(struct zebra_if
*zif
, esi_t
*esi
)
2402 struct zebra_evpn_es
*old_es
= zif
->es_info
.es
;
2403 struct zebra_evpn_es
*es
;
2405 if (old_es
&& !memcmp(&old_es
->esi
, esi
, sizeof(*esi
)))
2406 /* dup - nothing to be done */
2409 /* release the old_es against the zif */
2411 zebra_evpn_local_es_del(&old_es
);
2413 es
= zebra_evpn_es_find(esi
);
2415 /* if it exists against another interface flag an error */
2416 if (es
->zif
&& es
->zif
!= zif
)
2420 es
= zebra_evpn_es_new(esi
);
2423 memcpy(&zif
->es_info
.esi
, esi
, sizeof(*esi
));
2425 zebra_evpn_es_local_info_set(es
, zif
);
2430 static int zebra_evpn_type3_esi_update(struct zebra_if
*zif
, uint32_t lid
,
2431 struct ethaddr
*sysmac
)
2433 struct zebra_evpn_es
*old_es
= zif
->es_info
.es
;
2436 int field_bytes
= 0;
2438 /* Complete config of the ES-ID bootstraps the ES */
2439 if (!lid
|| is_zero_mac(sysmac
)) {
2441 memset(&zif
->es_info
.esi
, 0, sizeof(zif
->es_info
.esi
));
2442 /* if in ES is attached to zif delete it */
2444 zebra_evpn_local_es_del(&old_es
);
2448 /* build 10-byte type-3-ESI -
2449 * Type(1-byte), MAC(6-bytes), ES-LID (3-bytes)
2452 esi
.val
[offset
] = ESI_TYPE_MAC
;
2453 offset
+= field_bytes
;
2455 field_bytes
= ETH_ALEN
;
2456 memcpy(&esi
.val
[offset
], (uint8_t *)sysmac
, field_bytes
);
2457 offset
+= field_bytes
;
2459 esi
.val
[offset
++] = (uint8_t)(lid
>> 16);
2460 esi
.val
[offset
++] = (uint8_t)(lid
>> 8);
2461 esi
.val
[offset
++] = (uint8_t)lid
;
2463 return zebra_evpn_local_es_update(zif
, &esi
);
2466 int zebra_evpn_remote_es_del(const esi_t
*esi
, struct in_addr vtep_ip
)
2468 char buf
[ESI_STR_LEN
];
2469 struct zebra_evpn_es
*es
;
2471 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2472 zlog_debug("remote es %s vtep %pI4 del",
2473 esi_to_str(esi
, buf
, sizeof(buf
)), &vtep_ip
);
2475 es
= zebra_evpn_es_find(esi
);
2477 zlog_warn("remote es %s vtep %pI4 del failed, es missing",
2478 esi_to_str(esi
, buf
, sizeof(buf
)), &vtep_ip
);
2482 zebra_evpn_es_vtep_del(es
, vtep_ip
);
2483 zebra_evpn_es_remote_info_re_eval(&es
);
2488 /* force delete a remote ES on the way down */
2489 static void zebra_evpn_remote_es_flush(struct zebra_evpn_es
**esp
)
2491 struct zebra_evpn_es_vtep
*es_vtep
;
2492 struct listnode
*node
;
2493 struct listnode
*nnode
;
2494 struct zebra_evpn_es
*es
= *esp
;
2496 for (ALL_LIST_ELEMENTS(es
->es_vtep_list
, node
, nnode
, es_vtep
)) {
2497 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2498 zlog_debug("es %s vtep %pI4 flush",
2501 zebra_evpn_es_vtep_free(es_vtep
);
2503 zebra_evpn_es_remote_info_re_eval(esp
);
2506 int zebra_evpn_remote_es_add(const esi_t
*esi
, struct in_addr vtep_ip
,
2507 bool esr_rxed
, uint8_t df_alg
, uint16_t df_pref
)
2509 char buf
[ESI_STR_LEN
];
2510 struct zebra_evpn_es
*es
;
2512 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2513 zlog_debug("remote es %s vtep %pI4 add %s df_alg %d df_pref %d",
2514 esi_to_str(esi
, buf
, sizeof(buf
)),
2515 &vtep_ip
, esr_rxed
? "esr" : "", df_alg
,
2518 es
= zebra_evpn_es_find(esi
);
2520 es
= zebra_evpn_es_new(esi
);
2523 "remote es %s vtep %pI4 add failed, es missing",
2524 esi_to_str(esi
, buf
, sizeof(buf
)), &vtep_ip
);
2529 if (df_alg
!= EVPN_MH_DF_ALG_PREF
)
2531 "remote es %s vtep %pI4 add %s with unsupported df_alg %d",
2532 esi_to_str(esi
, buf
, sizeof(buf
)), &vtep_ip
,
2533 esr_rxed
? "esr" : "", df_alg
);
2535 zebra_evpn_es_vtep_add(es
, vtep_ip
, esr_rxed
, df_alg
, df_pref
);
2536 zebra_evpn_es_remote_info_re_eval(&es
);
2541 void zebra_evpn_proc_remote_es(ZAPI_HANDLER_ARGS
)
2544 struct in_addr vtep_ip
;
2547 if (!is_evpn_enabled()) {
2549 "%s: EVPN not enabled yet we received a es_add zapi call",
2554 memset(&esi
, 0, sizeof(esi_t
));
2557 STREAM_GET(&esi
, s
, sizeof(esi_t
));
2558 STREAM_GET(&vtep_ip
.s_addr
, s
, sizeof(vtep_ip
.s_addr
));
2560 if (hdr
->command
== ZEBRA_REMOTE_ES_VTEP_ADD
) {
2561 uint32_t zapi_flags
;
2566 STREAM_GETL(s
, zapi_flags
);
2567 esr_rxed
= (zapi_flags
& ZAPI_ES_VTEP_FLAG_ESR_RXED
) ? true
2569 STREAM_GETC(s
, df_alg
);
2570 STREAM_GETW(s
, df_pref
);
2571 zebra_rib_queue_evpn_rem_es_add(&esi
, &vtep_ip
, esr_rxed
,
2574 zebra_rib_queue_evpn_rem_es_del(&esi
, &vtep_ip
);
2581 void zebra_evpn_es_mac_deref_entry(struct zebra_mac
*mac
)
2583 struct zebra_evpn_es
*es
= mac
->es
;
2589 list_delete_node(es
->mac_list
, &mac
->es_listnode
);
2590 if (!listcount(es
->mac_list
))
2591 zebra_evpn_es_free(&es
);
2594 /* Associate a MAC entry with a local or remote ES. Returns false if there
2597 bool zebra_evpn_es_mac_ref_entry(struct zebra_mac
*mac
,
2598 struct zebra_evpn_es
*es
)
2604 zebra_evpn_es_mac_deref_entry(mac
);
2610 listnode_init(&mac
->es_listnode
, mac
);
2611 listnode_add(es
->mac_list
, &mac
->es_listnode
);
2616 bool zebra_evpn_es_mac_ref(struct zebra_mac
*mac
, const esi_t
*esi
)
2618 struct zebra_evpn_es
*es
;
2620 es
= zebra_evpn_es_find(esi
);
2622 /* If non-zero esi implicitly create a new ES */
2623 if (memcmp(esi
, zero_esi
, sizeof(esi_t
))) {
2624 es
= zebra_evpn_es_new(esi
);
2625 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2626 zlog_debug("auto es %s add on mac ref",
2631 return zebra_evpn_es_mac_ref_entry(mac
, es
);
2634 /* Inform BGP about local ES-EVI add or del */
2635 static int zebra_evpn_es_evi_send_to_client(struct zebra_evpn_es
*es
,
2636 struct zebra_evpn
*zevpn
, bool add
)
2638 struct zserv
*client
;
2641 client
= zserv_find_client(ZEBRA_ROUTE_BGP
, 0);
2642 /* BGP may not be running. */
2646 s
= stream_new(ZEBRA_MAX_PACKET_SIZ
);
2648 zclient_create_header(s
,
2649 add
? ZEBRA_LOCAL_ES_EVI_ADD
: ZEBRA_LOCAL_ES_EVI_DEL
,
2650 zebra_vrf_get_evpn_id());
2651 stream_put(s
, &es
->esi
, sizeof(esi_t
));
2652 stream_putl(s
, zevpn
->vni
);
2654 /* Write packet size. */
2655 stream_putw_at(s
, 0, stream_get_endp(s
));
2657 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2658 zlog_debug("send %s local es %s evi %u to %s",
2659 add
? "add" : "del",
2660 es
->esi_str
, zevpn
->vni
,
2661 zebra_route_string(client
->proto
));
2663 client
->local_es_add_cnt
++;
2664 return zserv_send_message(client
, s
);
2667 /* sysmac part of a local ESI has changed */
2668 static int zebra_evpn_es_sys_mac_update(struct zebra_if
*zif
,
2669 struct ethaddr
*sysmac
)
2673 rv
= zebra_evpn_type3_esi_update(zif
, zif
->es_info
.lid
, sysmac
);
2675 memcpy(&zif
->es_info
.sysmac
, sysmac
, sizeof(struct ethaddr
));
2680 /* local-ID part of ESI has changed */
2681 static int zebra_evpn_es_lid_update(struct zebra_if
*zif
, uint32_t lid
)
2685 rv
= zebra_evpn_type3_esi_update(zif
, lid
, &zif
->es_info
.sysmac
);
2687 zif
->es_info
.lid
= lid
;
2692 /* type-0 esi has changed */
2693 static int zebra_evpn_es_type0_esi_update(struct zebra_if
*zif
, esi_t
*esi
)
2697 rv
= zebra_evpn_local_es_update(zif
, esi
);
2699 /* clear the old es_lid, es_sysmac - type-0 is being set so old
2700 * type-3 params need to be flushed
2702 memset(&zif
->es_info
.sysmac
, 0, sizeof(struct ethaddr
));
2703 zif
->es_info
.lid
= 0;
2708 void zebra_evpn_es_cleanup(void)
2710 struct zebra_evpn_es
*es
;
2711 struct zebra_evpn_es
*es_next
;
2713 RB_FOREACH_SAFE(es
, zebra_es_rb_head
,
2714 &zmh_info
->es_rb_tree
, es_next
) {
2715 zebra_evpn_local_es_del(&es
);
2717 zebra_evpn_remote_es_flush(&es
);
2721 static void zebra_evpn_es_df_pref_update(struct zebra_if
*zif
, uint16_t df_pref
)
2723 struct zebra_evpn_es
*es
;
2726 if (zif
->es_info
.df_pref
== df_pref
)
2729 zif
->es_info
.df_pref
= df_pref
;
2730 es
= zif
->es_info
.es
;
2735 tmp_pref
= zif
->es_info
.df_pref
? zif
->es_info
.df_pref
2736 : EVPN_MH_DF_PREF_DEFAULT
;
2738 if (es
->df_pref
== tmp_pref
)
2741 es
->df_pref
= tmp_pref
;
2742 /* run df election */
2743 zebra_evpn_es_run_df_election(es
, __func__
);
2745 if (es
->flags
& ZEBRA_EVPNES_READY_FOR_BGP
)
2746 zebra_evpn_es_send_add_to_client(es
);
2749 /* If bypass mode on an es changed we set all local macs to
2750 * inactive and drop the sync info
2752 static void zebra_evpn_es_bypass_update_macs(struct zebra_evpn_es
*es
,
2753 struct interface
*ifp
, bool bypass
)
2755 struct zebra_mac
*mac
;
2756 struct listnode
*node
;
2757 struct listnode
*nnode
;
2758 struct zebra_if
*zif
;
2760 /* Flush all MACs linked to the ES */
2761 for (ALL_LIST_ELEMENTS(es
->mac_list
, node
, nnode
, mac
)) {
2762 if (!CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
))
2765 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
2766 zlog_debug("VNI %u mac %pEA %s update es %s",
2769 bypass
? "bypass" : "non-bypass",
2771 zebra_evpn_flush_local_mac(mac
, ifp
);
2774 /* While in bypass-mode locally learnt MACs are linked
2775 * to the access port instead of the ES
2781 for (ALL_LIST_ELEMENTS(zif
->mac_list
, node
, nnode
, mac
)) {
2782 if (!CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
))
2785 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
2786 zlog_debug("VNI %u mac %pEA %s update ifp %s",
2789 bypass
? "bypass" : "non-bypass", ifp
->name
);
2790 zebra_evpn_flush_local_mac(mac
, ifp
);
2794 void zebra_evpn_es_bypass_update(struct zebra_evpn_es
*es
,
2795 struct interface
*ifp
, bool bypass
)
2798 bool dplane_updated
;
2800 old_bypass
= !!(es
->flags
& ZEBRA_EVPNES_BYPASS
);
2801 if (old_bypass
== bypass
)
2805 es
->flags
|= ZEBRA_EVPNES_BYPASS
;
2807 es
->flags
&= ~ZEBRA_EVPNES_BYPASS
;
2809 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2810 zlog_debug("bond %s es %s lacp bypass changed to %s", ifp
->name
,
2811 es
->esi_str
, bypass
? "on" : "off");
2813 /* send bypass update to BGP */
2814 if (es
->flags
& ZEBRA_EVPNES_READY_FOR_BGP
)
2815 zebra_evpn_es_send_add_to_client(es
);
2817 zebra_evpn_es_bypass_update_macs(es
, ifp
, bypass
);
2819 /* re-run DF election */
2820 dplane_updated
= zebra_evpn_es_run_df_election(es
, __func__
);
2822 /* disable SPH filter */
2823 if (!dplane_updated
&& (es
->flags
& ZEBRA_EVPNES_LOCAL
)
2824 && (listcount(es
->es_vtep_list
) > ES_VTEP_MAX_CNT
))
2825 zebra_evpn_es_br_port_dplane_update(es
, __func__
);
2828 static void zebra_evpn_es_bypass_cfg_update(struct zebra_if
*zif
, bool bypass
)
2830 bool old_bypass
= !!(zif
->es_info
.flags
& ZIF_CFG_ES_FLAG_BYPASS
);
2832 if (old_bypass
== bypass
)
2836 zif
->es_info
.flags
|= ZIF_CFG_ES_FLAG_BYPASS
;
2838 zif
->es_info
.flags
&= ~ZIF_CFG_ES_FLAG_BYPASS
;
2841 if (zif
->es_info
.es
)
2842 zebra_evpn_es_bypass_update(zif
->es_info
.es
, zif
->ifp
, bypass
);
2846 /* Only certain types of access ports can be setup as an Ethernet Segment */
2847 bool zebra_evpn_is_if_es_capable(struct zebra_if
*zif
)
2849 if (zif
->zif_type
== ZEBRA_IF_BOND
)
2852 /* relax the checks to allow config to be applied in zebra
2853 * before interface is rxed from the kernel
2855 if (zif
->ifp
->ifindex
== IFINDEX_INTERNAL
)
2858 /* XXX: allow swpX i.e. a regular ethernet port to be an ES link too */
2862 void zebra_evpn_if_es_print(struct vty
*vty
, json_object
*json
,
2863 struct zebra_if
*zif
)
2865 char buf
[ETHER_ADDR_STRLEN
];
2866 char esi_buf
[ESI_STR_LEN
];
2869 json_object
*json_evpn
;
2871 json_evpn
= json_object_new_object();
2872 json_object_object_add(json
, "evpnMh", json_evpn
);
2874 if (zif
->es_info
.lid
|| !is_zero_mac(&zif
->es_info
.sysmac
)) {
2875 json_object_int_add(json_evpn
, "esId",
2877 json_object_string_add(
2878 json_evpn
, "esSysmac",
2879 prefix_mac2str(&zif
->es_info
.sysmac
, buf
,
2881 } else if (memcmp(&zif
->es_info
.esi
, zero_esi
,
2882 sizeof(*zero_esi
))) {
2883 json_object_string_add(json_evpn
, "esId",
2884 esi_to_str(&zif
->es_info
.esi
,
2889 if (zif
->flags
& ZIF_FLAG_EVPN_MH_UPLINK
)
2890 json_object_string_add(
2891 json_evpn
, "uplink",
2892 CHECK_FLAG(zif
->flags
,
2893 ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP
)
2898 bool vty_print
= false;
2901 strlcat(mh_buf
, " EVPN-MH:", sizeof(mh_buf
));
2902 if (zif
->es_info
.lid
|| !is_zero_mac(&zif
->es_info
.sysmac
)) {
2904 snprintf(mh_buf
+ strlen(mh_buf
),
2905 sizeof(mh_buf
) - strlen(mh_buf
),
2906 " ES id %u ES sysmac %s", zif
->es_info
.lid
,
2907 prefix_mac2str(&zif
->es_info
.sysmac
, buf
,
2909 } else if (memcmp(&zif
->es_info
.esi
, zero_esi
,
2910 sizeof(*zero_esi
))) {
2912 snprintf(mh_buf
+ strnlen(mh_buf
, sizeof(mh_buf
)),
2914 - strnlen(mh_buf
, sizeof(mh_buf
)),
2916 esi_to_str(&zif
->es_info
.esi
, esi_buf
,
2920 if (zif
->flags
& ZIF_FLAG_EVPN_MH_UPLINK
) {
2922 if (zif
->flags
& ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP
)
2923 strlcat(mh_buf
, " uplink (up)", sizeof(mh_buf
));
2925 strlcat(mh_buf
, " uplink (down)",
2930 vty_out(vty
, "%s\n", mh_buf
);
2934 static void zebra_evpn_local_mac_oper_state_change(struct zebra_evpn_es
*es
)
2936 struct zebra_mac
*mac
;
2937 struct listnode
*node
;
2939 /* If fast-failover is supported by the dataplane via the use
2940 * of an ES backup NHG there is nothing to be done in the
2943 if (!(zmh_info
->flags
& ZEBRA_EVPN_MH_REDIRECT_OFF
))
2946 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
|| IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
2947 zlog_debug("mac slow-fail on es %s %s ", es
->esi_str
,
2948 (es
->flags
& ZEBRA_EVPNES_OPER_UP
) ? "up" : "down");
2950 for (ALL_LIST_ELEMENTS_RO(es
->mac_list
, node
, mac
)) {
2951 if (!(mac
->flags
& ZEBRA_MAC_LOCAL
)
2952 || !zebra_evpn_mac_is_static(mac
))
2955 if (es
->flags
& ZEBRA_EVPNES_OPER_UP
) {
2956 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
2958 "VNI %u mac %pEA move to acc %s es %s %s ",
2961 es
->zif
->ifp
->name
, es
->esi_str
,
2962 (es
->flags
& ZEBRA_EVPNES_OPER_UP
)
2965 /* switch the local macs to access port */
2966 if (zebra_evpn_sync_mac_dp_install(
2967 mac
, false /*set_inactive*/,
2968 false /*force_clear_static*/, __func__
)
2970 /* if the local mac install fails get rid of the
2973 zebra_evpn_rem_mac_uninstall(mac
->zevpn
, mac
,
2976 /* switch the local macs to network port. if there
2977 * is no active NHG we don't bother deleting the MAC;
2978 * that is left up to the dataplane to handle.
2980 if (!(es
->flags
& ZEBRA_EVPNES_NHG_ACTIVE
))
2982 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
2984 "VNI %u mac %pEA move to nhg %u es %s %s ",
2987 es
->nhg_id
, es
->esi_str
,
2988 (es
->flags
& ZEBRA_EVPNES_OPER_UP
)
2991 zebra_evpn_rem_mac_install(mac
->zevpn
, mac
,
2992 true /*was_static*/);
2997 void zebra_evpn_es_if_oper_state_change(struct zebra_if
*zif
, bool up
)
2999 struct zebra_evpn_es
*es
= zif
->es_info
.es
;
3000 bool old_up
= !!(es
->flags
& ZEBRA_EVPNES_OPER_UP
);
3005 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3006 zlog_debug("es %s state changed to %s ",
3008 up
? "up" : "down");
3010 es
->flags
|= ZEBRA_EVPNES_OPER_UP
;
3012 es
->flags
&= ~ZEBRA_EVPNES_OPER_UP
;
3014 zebra_evpn_es_run_df_election(es
, __func__
);
3015 zebra_evpn_local_mac_oper_state_change(es
);
3017 /* inform BGP of the ES oper state change */
3018 if (es
->flags
& ZEBRA_EVPNES_READY_FOR_BGP
)
3019 zebra_evpn_es_send_add_to_client(es
);
3022 static char *zebra_evpn_es_vtep_str(char *vtep_str
, struct zebra_evpn_es
*es
,
3023 uint8_t vtep_str_size
)
3025 struct zebra_evpn_es_vtep
*zvtep
;
3026 struct listnode
*node
;
3028 char ip_buf
[INET6_ADDRSTRLEN
];
3031 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, zvtep
)) {
3035 inet_ntop(AF_INET
, &zvtep
->vtep_ip
, ip_buf
,
3039 strlcat(vtep_str
, ",", vtep_str_size
);
3041 inet_ntop(AF_INET
, &zvtep
->vtep_ip
, ip_buf
,
3049 static void zebra_evpn_es_json_vtep_fill(struct zebra_evpn_es
*es
,
3050 json_object
*json_vteps
)
3052 struct zebra_evpn_es_vtep
*es_vtep
;
3053 struct listnode
*node
;
3054 json_object
*json_vtep_entry
;
3055 char alg_buf
[EVPN_DF_ALG_STR_LEN
];
3057 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
3058 json_vtep_entry
= json_object_new_object();
3059 json_object_string_addf(json_vtep_entry
, "vtep", "%pI4",
3061 if (es_vtep
->flags
& ZEBRA_EVPNES_VTEP_RXED_ESR
) {
3062 json_object_string_add(
3063 json_vtep_entry
, "dfAlgorithm",
3064 evpn_es_df_alg2str(es_vtep
->df_alg
, alg_buf
,
3066 json_object_int_add(json_vtep_entry
, "dfPreference",
3070 json_object_int_add(json_vtep_entry
, "nexthopId",
3071 es_vtep
->nh
->nh_id
);
3072 json_object_array_add(json_vteps
, json_vtep_entry
);
3076 static void zebra_evpn_es_show_entry(struct vty
*vty
, struct zebra_evpn_es
*es
,
3077 json_object
*json_array
)
3080 char vtep_str
[ES_VTEP_LIST_STR_SZ
];
3083 json_object
*json
= NULL
;
3084 json_object
*json_vteps
;
3085 json_object
*json_flags
;
3087 json
= json_object_new_object();
3088 json_object_string_add(json
, "esi", es
->esi_str
);
3091 & (ZEBRA_EVPNES_LOCAL
| ZEBRA_EVPNES_REMOTE
3092 | ZEBRA_EVPNES_NON_DF
)) {
3093 json_flags
= json_object_new_array();
3094 if (es
->flags
& ZEBRA_EVPNES_LOCAL
)
3095 json_array_string_add(json_flags
, "local");
3096 if (es
->flags
& ZEBRA_EVPNES_REMOTE
)
3097 json_array_string_add(json_flags
, "remote");
3098 if (es
->flags
& ZEBRA_EVPNES_NON_DF
)
3099 json_array_string_add(json_flags
, "nonDF");
3100 if (es
->flags
& ZEBRA_EVPNES_BYPASS
)
3101 json_array_string_add(json_flags
, "bypass");
3102 json_object_object_add(json
, "flags", json_flags
);
3106 json_object_string_add(json
, "accessPort",
3107 es
->zif
->ifp
->name
);
3109 if (listcount(es
->es_vtep_list
)) {
3110 json_vteps
= json_object_new_array();
3111 zebra_evpn_es_json_vtep_fill(es
, json_vteps
);
3112 json_object_object_add(json
, "vteps", json_vteps
);
3114 json_object_array_add(json_array
, json
);
3117 if (es
->flags
& ZEBRA_EVPNES_LOCAL
)
3118 strlcat(type_str
, "L", sizeof(type_str
));
3119 if (es
->flags
& ZEBRA_EVPNES_REMOTE
)
3120 strlcat(type_str
, "R", sizeof(type_str
));
3121 if (es
->flags
& ZEBRA_EVPNES_NON_DF
)
3122 strlcat(type_str
, "N", sizeof(type_str
));
3123 if (es
->flags
& ZEBRA_EVPNES_BYPASS
)
3124 strlcat(type_str
, "B", sizeof(type_str
));
3126 zebra_evpn_es_vtep_str(vtep_str
, es
, sizeof(vtep_str
));
3128 vty_out(vty
, "%-30s %-4s %-21s %s\n",
3129 es
->esi_str
, type_str
,
3130 es
->zif
? es
->zif
->ifp
->name
: "-",
3135 static void zebra_evpn_es_show_entry_detail(struct vty
*vty
,
3136 struct zebra_evpn_es
*es
, json_object
*json
)
3139 char alg_buf
[EVPN_DF_ALG_STR_LEN
];
3140 struct zebra_evpn_es_vtep
*es_vtep
;
3141 struct listnode
*node
;
3142 char thread_buf
[THREAD_TIMER_STRLEN
];
3145 json_object
*json_vteps
;
3146 json_object
*json_flags
;
3148 json_object_string_add(json
, "esi", es
->esi_str
);
3150 json_object_string_add(json
, "accessPort",
3151 es
->zif
->ifp
->name
);
3155 json_flags
= json_object_new_array();
3156 if (es
->flags
& ZEBRA_EVPNES_LOCAL
)
3157 json_array_string_add(json_flags
, "local");
3158 if (es
->flags
& ZEBRA_EVPNES_REMOTE
)
3159 json_array_string_add(json_flags
, "remote");
3160 if (es
->flags
& ZEBRA_EVPNES_NON_DF
)
3161 json_array_string_add(json_flags
, "nonDF");
3162 if (es
->flags
& ZEBRA_EVPNES_BYPASS
)
3163 json_array_string_add(json_flags
, "bypass");
3164 if (es
->flags
& ZEBRA_EVPNES_READY_FOR_BGP
)
3165 json_array_string_add(json_flags
,
3167 if (es
->flags
& ZEBRA_EVPNES_BR_PORT
)
3168 json_array_string_add(json_flags
, "bridgePort");
3169 if (es
->flags
& ZEBRA_EVPNES_OPER_UP
)
3170 json_array_string_add(json_flags
, "operUp");
3171 if (es
->flags
& ZEBRA_EVPNES_NHG_ACTIVE
)
3172 json_array_string_add(json_flags
,
3173 "nexthopGroupActive");
3174 json_object_object_add(json
, "flags", json_flags
);
3177 json_object_int_add(json
, "vniCount",
3178 listcount(es
->es_evi_list
));
3179 json_object_int_add(json
, "macCount", listcount(es
->mac_list
));
3180 json_object_int_add(json
, "dfPreference", es
->df_pref
);
3181 if (es
->df_delay_timer
)
3182 json_object_string_add(
3183 json
, "dfDelayTimer",
3184 thread_timer_to_hhmmss(thread_buf
,
3186 es
->df_delay_timer
));
3187 json_object_int_add(json
, "nexthopGroup", es
->nhg_id
);
3188 if (listcount(es
->es_vtep_list
)) {
3189 json_vteps
= json_object_new_array();
3190 zebra_evpn_es_json_vtep_fill(es
, json_vteps
);
3191 json_object_object_add(json
, "vteps", json_vteps
);
3195 if (es
->flags
& ZEBRA_EVPNES_LOCAL
)
3196 strlcat(type_str
, "Local", sizeof(type_str
));
3197 if (es
->flags
& ZEBRA_EVPNES_REMOTE
) {
3198 if (strnlen(type_str
, sizeof(type_str
)))
3199 strlcat(type_str
, ",", sizeof(type_str
));
3200 strlcat(type_str
, "Remote", sizeof(type_str
));
3203 vty_out(vty
, "ESI: %s\n", es
->esi_str
);
3204 vty_out(vty
, " Type: %s\n", type_str
);
3205 vty_out(vty
, " Interface: %s\n",
3207 es
->zif
->ifp
->name
: "-");
3208 if (es
->flags
& ZEBRA_EVPNES_LOCAL
) {
3209 vty_out(vty
, " State: %s\n",
3210 (es
->flags
& ZEBRA_EVPNES_OPER_UP
) ? "up"
3212 vty_out(vty
, " Bridge port: %s\n",
3213 (es
->flags
& ZEBRA_EVPNES_BR_PORT
) ? "yes"
3216 vty_out(vty
, " Ready for BGP: %s\n",
3217 (es
->flags
& ZEBRA_EVPNES_READY_FOR_BGP
) ?
3219 if (es
->flags
& ZEBRA_EVPNES_BYPASS
)
3220 vty_out(vty
, " LACP bypass: on\n");
3221 vty_out(vty
, " VNI Count: %d\n", listcount(es
->es_evi_list
));
3222 vty_out(vty
, " MAC Count: %d\n", listcount(es
->mac_list
));
3223 if (es
->flags
& ZEBRA_EVPNES_LOCAL
)
3224 vty_out(vty
, " DF status: %s \n",
3225 (es
->flags
& ZEBRA_EVPNES_NON_DF
) ? "non-df"
3227 if (es
->df_delay_timer
)
3228 vty_out(vty
, " DF delay: %s\n",
3229 thread_timer_to_hhmmss(thread_buf
,
3231 es
->df_delay_timer
));
3232 vty_out(vty
, " DF preference: %u\n", es
->df_pref
);
3233 vty_out(vty
, " Nexthop group: %u\n", es
->nhg_id
);
3234 vty_out(vty
, " VTEPs:\n");
3235 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
3236 vty_out(vty
, " %pI4",
3238 if (es_vtep
->flags
& ZEBRA_EVPNES_VTEP_RXED_ESR
)
3239 vty_out(vty
, " df_alg: %s df_pref: %d",
3240 evpn_es_df_alg2str(es_vtep
->df_alg
,
3244 vty_out(vty
, " nh: %u\n",
3245 es_vtep
->nh
? es_vtep
->nh
->nh_id
: 0);
3252 void zebra_evpn_es_show(struct vty
*vty
, bool uj
)
3254 struct zebra_evpn_es
*es
;
3255 json_object
*json_array
= NULL
;
3258 json_array
= json_object_new_array();
3260 vty_out(vty
, "Type: B bypass, L local, R remote, N non-DF\n");
3261 vty_out(vty
, "%-30s %-4s %-21s %s\n",
3262 "ESI", "Type", "ES-IF", "VTEPs");
3265 RB_FOREACH(es
, zebra_es_rb_head
, &zmh_info
->es_rb_tree
)
3266 zebra_evpn_es_show_entry(vty
, es
, json_array
);
3269 vty_json(vty
, json_array
);
3272 void zebra_evpn_es_show_detail(struct vty
*vty
, bool uj
)
3274 struct zebra_evpn_es
*es
;
3275 json_object
*json_array
= NULL
;
3278 json_array
= json_object_new_array();
3280 RB_FOREACH (es
, zebra_es_rb_head
, &zmh_info
->es_rb_tree
) {
3281 json_object
*json
= NULL
;
3284 json
= json_object_new_object();
3285 zebra_evpn_es_show_entry_detail(vty
, es
, json
);
3287 json_object_array_add(json_array
, json
);
3291 vty_json(vty
, json_array
);
3294 void zebra_evpn_es_show_esi(struct vty
*vty
, bool uj
, esi_t
*esi
)
3296 struct zebra_evpn_es
*es
;
3297 char esi_str
[ESI_STR_LEN
];
3298 json_object
*json
= NULL
;
3301 json
= json_object_new_object();
3303 es
= zebra_evpn_es_find(esi
);
3306 zebra_evpn_es_show_entry_detail(vty
, es
, json
);
3309 esi_to_str(esi
, esi_str
, sizeof(esi_str
));
3310 vty_out(vty
, "ESI %s does not exist\n", esi_str
);
3315 vty_json(vty
, json
);
3318 int zebra_evpn_mh_if_write(struct vty
*vty
, struct interface
*ifp
)
3320 struct zebra_if
*zif
= ifp
->info
;
3321 char buf
[ETHER_ADDR_STRLEN
];
3322 bool type_3_esi
= false;
3323 char esi_buf
[ESI_STR_LEN
];
3325 if (zif
->es_info
.lid
) {
3326 vty_out(vty
, " evpn mh es-id %u\n", zif
->es_info
.lid
);
3330 if (!is_zero_mac(&zif
->es_info
.sysmac
)) {
3331 vty_out(vty
, " evpn mh es-sys-mac %s\n",
3332 prefix_mac2str(&zif
->es_info
.sysmac
,
3338 && memcmp(&zif
->es_info
.esi
, zero_esi
, sizeof(*zero_esi
)))
3339 vty_out(vty
, " evpn mh es-id %s\n",
3340 esi_to_str(&zif
->es_info
.esi
, esi_buf
, sizeof(esi_buf
)));
3342 if (zif
->es_info
.df_pref
)
3343 vty_out(vty
, " evpn mh es-df-pref %u\n", zif
->es_info
.df_pref
);
3345 if (zif
->flags
& ZIF_FLAG_EVPN_MH_UPLINK
)
3346 vty_out(vty
, " evpn mh uplink\n");
3351 #include "zebra/zebra_evpn_mh_clippy.c"
3352 /* CLI for setting an ES in bypass mode */
3353 DEFPY_HIDDEN(zebra_evpn_es_bypass
, zebra_evpn_es_bypass_cmd
,
3354 "[no] evpn mh bypass",
3355 NO_STR
"EVPN\n" EVPN_MH_VTY_STR
"set bypass mode\n")
3357 VTY_DECLVAR_CONTEXT(interface
, ifp
);
3358 struct zebra_if
*zif
;
3363 zebra_evpn_es_bypass_cfg_update(zif
, false);
3365 if (!zebra_evpn_is_if_es_capable(zif
)) {
3367 "%% DF bypass cannot be associated with this interface type\n");
3370 zebra_evpn_es_bypass_cfg_update(zif
, true);
3375 /* CLI for configuring DF preference part for an ES */
3376 DEFPY(zebra_evpn_es_pref
, zebra_evpn_es_pref_cmd
,
3377 "[no$no] evpn mh es-df-pref [(1-65535)$df_pref]",
3378 NO_STR
"EVPN\n" EVPN_MH_VTY_STR
3379 "preference value used for DF election\n"
3382 VTY_DECLVAR_CONTEXT(interface
, ifp
);
3383 struct zebra_if
*zif
;
3388 zebra_evpn_es_df_pref_update(zif
, 0);
3390 if (!zebra_evpn_is_if_es_capable(zif
)) {
3392 "%% DF preference cannot be associated with this interface type\n");
3395 zebra_evpn_es_df_pref_update(zif
, df_pref
);
3400 /* CLI for setting up sysmac part of ESI on an access port */
3401 DEFPY(zebra_evpn_es_sys_mac
,
3402 zebra_evpn_es_sys_mac_cmd
,
3403 "[no$no] evpn mh es-sys-mac [X:X:X:X:X:X$mac]",
3407 "Ethernet segment system MAC\n"
3411 VTY_DECLVAR_CONTEXT(interface
, ifp
);
3412 struct zebra_if
*zif
;
3418 static struct ethaddr zero_mac
;
3420 ret
= zebra_evpn_es_sys_mac_update(zif
, &zero_mac
);
3422 vty_out(vty
, "%% Failed to clear ES sysmac\n");
3427 if (!zebra_evpn_is_if_es_capable(zif
)) {
3429 "%% ESI cannot be associated with this interface type\n");
3433 if (!mac
|| is_zero_mac(&mac
->eth_addr
)) {
3434 vty_out(vty
, "%% ES sysmac value is invalid\n");
3438 ret
= zebra_evpn_es_sys_mac_update(zif
, &mac
->eth_addr
);
3441 "%% ESI already exists on a different interface\n");
3448 /* CLI for setting up local-ID part of ESI on an access port */
3449 DEFPY(zebra_evpn_es_id
,
3450 zebra_evpn_es_id_cmd
,
3451 "[no$no] evpn mh es-id [(1-16777215)$es_lid | NAME$esi_str]",
3455 "Ethernet segment identifier\n"
3456 "local discriminator\n"
3457 "10-byte ID - 00:AA:BB:CC:DD:EE:FF:GG:HH:II\n"
3460 VTY_DECLVAR_CONTEXT(interface
, ifp
);
3461 struct zebra_if
*zif
;
3468 if (zif
->es_info
.lid
)
3469 ret
= zebra_evpn_es_lid_update(zif
, 0);
3470 else if (memcmp(&zif
->es_info
.esi
, zero_esi
, sizeof(*zero_esi
)))
3471 ret
= zebra_evpn_es_type0_esi_update(zif
, zero_esi
);
3475 "%% Failed to clear ES local id or ESI name\n");
3479 if (!zebra_evpn_is_if_es_capable(zif
)) {
3481 "%% ESI cannot be associated with this interface type\n");
3486 if (!str_to_esi(esi_str
, &esi
)) {
3487 vty_out(vty
, "%% Malformed ESI name\n");
3490 ret
= zebra_evpn_es_type0_esi_update(zif
, &esi
);
3494 "%% Specify ES local id or ESI name\n");
3497 ret
= zebra_evpn_es_lid_update(zif
, es_lid
);
3502 "%% ESI already exists on a different interface\n");
3509 /* CLI for tagging an interface as an uplink */
3510 DEFPY(zebra_evpn_mh_uplink
, zebra_evpn_mh_uplink_cmd
, "[no] evpn mh uplink",
3511 NO_STR
"EVPN\n" EVPN_MH_VTY_STR
"uplink to the VxLAN core\n")
3513 VTY_DECLVAR_CONTEXT(interface
, ifp
);
3514 struct zebra_if
*zif
;
3517 zebra_evpn_mh_uplink_cfg_update(zif
, no
? false : true);
3522 void zebra_evpn_mh_json(json_object
*json
)
3524 json_object
*json_array
;
3525 char thread_buf
[THREAD_TIMER_STRLEN
];
3527 json_object_int_add(json
, "macHoldtime", zmh_info
->mac_hold_time
);
3528 json_object_int_add(json
, "neighHoldtime", zmh_info
->neigh_hold_time
);
3529 json_object_int_add(json
, "startupDelay", zmh_info
->startup_delay_time
);
3530 json_object_string_add(
3531 json
, "startupDelayTimer",
3532 thread_timer_to_hhmmss(thread_buf
, sizeof(thread_buf
),
3533 zmh_info
->startup_delay_timer
));
3534 json_object_int_add(json
, "uplinkConfigCount",
3535 zmh_info
->uplink_cfg_cnt
);
3536 json_object_int_add(json
, "uplinkActiveCount",
3537 zmh_info
->uplink_oper_up_cnt
);
3539 if (zmh_info
->protodown_rc
) {
3540 json_array
= json_object_new_array();
3541 if (CHECK_FLAG(zmh_info
->protodown_rc
,
3542 ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY
))
3543 json_object_array_add(
3545 json_object_new_string("startupDelay"));
3546 if (CHECK_FLAG(zmh_info
->protodown_rc
,
3547 ZEBRA_PROTODOWN_EVPN_UPLINK_DOWN
))
3548 json_object_array_add(
3550 json_object_new_string("uplinkDown"));
3551 json_object_object_add(json
, "protodownReasons", json_array
);
3555 void zebra_evpn_mh_print(struct vty
*vty
)
3557 char pd_buf
[ZEBRA_PROTODOWN_RC_STR_LEN
];
3558 char thread_buf
[THREAD_TIMER_STRLEN
];
3560 vty_out(vty
, "EVPN MH:\n");
3561 vty_out(vty
, " mac-holdtime: %ds, neigh-holdtime: %ds\n",
3562 zmh_info
->mac_hold_time
, zmh_info
->neigh_hold_time
);
3563 vty_out(vty
, " startup-delay: %ds, start-delay-timer: %s\n",
3564 zmh_info
->startup_delay_time
,
3565 thread_timer_to_hhmmss(thread_buf
, sizeof(thread_buf
),
3566 zmh_info
->startup_delay_timer
));
3567 vty_out(vty
, " uplink-cfg-cnt: %u, uplink-active-cnt: %u\n",
3568 zmh_info
->uplink_cfg_cnt
, zmh_info
->uplink_oper_up_cnt
);
3569 if (zmh_info
->protodown_rc
)
3570 vty_out(vty
, " protodown reasons: %s\n",
3571 zebra_protodown_rc_str(zmh_info
->protodown_rc
, pd_buf
,
3575 /*****************************************************************************/
3576 /* A base L2-VNI is maintained to derive parameters such as ES originator-IP.
3577 * XXX: once single vxlan device model becomes available this will not be
3580 /* called when a new vni is added or becomes oper up or becomes a bridge port */
3581 void zebra_evpn_es_set_base_evpn(struct zebra_evpn
*zevpn
)
3583 struct listnode
*node
;
3584 struct zebra_evpn_es
*es
;
3586 if (zmh_info
->es_base_evpn
) {
3587 if (zmh_info
->es_base_evpn
!= zevpn
) {
3588 /* unrelated EVPN; ignore it */
3591 /* check if the local vtep-ip has changed */
3593 /* check if the EVPN can be used as base EVPN */
3594 if (!zebra_evpn_send_to_client_ok(zevpn
))
3597 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3598 zlog_debug("es base vni set to %d",
3600 zmh_info
->es_base_evpn
= zevpn
;
3603 /* update local VTEP-IP */
3604 if (zmh_info
->es_originator_ip
.s_addr
==
3605 zmh_info
->es_base_evpn
->local_vtep_ip
.s_addr
)
3608 zmh_info
->es_originator_ip
.s_addr
=
3609 zmh_info
->es_base_evpn
->local_vtep_ip
.s_addr
;
3611 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3612 zlog_debug("es originator ip set to %pI4",
3613 &zmh_info
->es_base_evpn
->local_vtep_ip
);
3615 /* if originator ip changes we need to update bgp */
3616 for (ALL_LIST_ELEMENTS_RO(zmh_info
->local_es_list
, node
, es
)) {
3617 zebra_evpn_es_run_df_election(es
, __func__
);
3619 if (es
->flags
& ZEBRA_EVPNES_READY_FOR_BGP
)
3620 zebra_evpn_es_send_add_to_client(es
);
3622 zebra_evpn_es_re_eval_send_to_client(es
,
3623 true /* es_evi_re_reval */);
3627 /* called when a vni is removed or becomes oper down or is removed from a
3630 void zebra_evpn_es_clear_base_evpn(struct zebra_evpn
*zevpn
)
3632 struct listnode
*node
;
3633 struct zebra_evpn_es
*es
;
3635 if (zmh_info
->es_base_evpn
!= zevpn
)
3638 zmh_info
->es_base_evpn
= NULL
;
3639 /* lost current base EVPN; try to find a new one */
3640 zebra_evpn_es_get_one_base_evpn();
3642 /* couldn't locate an eligible base evpn */
3643 if (!zmh_info
->es_base_evpn
&& zmh_info
->es_originator_ip
.s_addr
) {
3644 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3645 zlog_debug("es originator ip cleared");
3647 zmh_info
->es_originator_ip
.s_addr
= 0;
3648 /* lost originator ip */
3649 for (ALL_LIST_ELEMENTS_RO(zmh_info
->local_es_list
, node
, es
)) {
3650 zebra_evpn_es_re_eval_send_to_client(es
,
3651 true /* es_evi_re_reval */);
3656 /* Locate an "eligible" L2-VNI to follow */
3657 static int zebra_evpn_es_get_one_base_evpn_cb(struct hash_bucket
*b
, void *data
)
3659 struct zebra_evpn
*zevpn
= b
->data
;
3661 zebra_evpn_es_set_base_evpn(zevpn
);
3663 if (zmh_info
->es_base_evpn
)
3664 return HASHWALK_ABORT
;
3666 return HASHWALK_CONTINUE
;
3669 /* locate a base_evpn to follow for the purposes of common params like
3672 static void zebra_evpn_es_get_one_base_evpn(void)
3674 struct zebra_vrf
*zvrf
;
3676 zvrf
= zebra_vrf_get_evpn();
3677 hash_walk(zvrf
->evpn_table
, zebra_evpn_es_get_one_base_evpn_cb
, NULL
);
3680 /*****************************************************************************
3681 * local ethernet segments can be error-disabled if the switch is not
3682 * ready to start transmitting traffic via the VxLAN overlay
3684 bool zebra_evpn_is_es_bond(struct interface
*ifp
)
3686 struct zebra_if
*zif
= ifp
->info
;
3688 return !!(struct zebra_if
*)zif
->es_info
.es
;
3691 bool zebra_evpn_is_es_bond_member(struct interface
*ifp
)
3693 struct zebra_if
*zif
= ifp
->info
;
3695 return IS_ZEBRA_IF_BOND_SLAVE(zif
->ifp
) && zif
->bondslave_info
.bond_if
3696 && ((struct zebra_if
*)zif
->bondslave_info
.bond_if
->info
)
3700 void zebra_evpn_mh_update_protodown_bond_mbr(struct zebra_if
*zif
, bool clear
,
3704 uint32_t old_protodown_rc
= 0;
3705 uint32_t new_protodown_rc
= 0;
3706 uint32_t protodown_rc
= 0;
3709 struct zebra_if
*bond_zif
;
3711 bond_zif
= zif
->bondslave_info
.bond_if
->info
;
3712 protodown_rc
= bond_zif
->protodown_rc
;
3715 old_protodown_rc
= zif
->protodown_rc
;
3716 new_protodown_rc
= (old_protodown_rc
& ~ZEBRA_PROTODOWN_EVPN_ALL
);
3717 new_protodown_rc
|= (protodown_rc
& ZEBRA_PROTODOWN_EVPN_ALL
);
3718 new_protodown
= !!new_protodown_rc
;
3720 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
&& (new_protodown_rc
!= old_protodown_rc
))
3722 "%s bond mbr %s protodown_rc changed; old 0x%x new 0x%x",
3723 caller
, zif
->ifp
->name
, old_protodown_rc
,
3726 if (zebra_if_update_protodown_rc(zif
->ifp
, new_protodown
,
3727 new_protodown_rc
) == 0) {
3728 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3729 zlog_debug("%s protodown %s", zif
->ifp
->name
,
3730 new_protodown
? "on" : "off");
3734 /* The bond members inherit the protodown reason code from the bond */
3735 static void zebra_evpn_mh_update_protodown_bond(struct zebra_if
*bond_zif
)
3737 struct zebra_if
*zif
;
3738 struct listnode
*node
;
3740 if (!bond_zif
->bond_info
.mbr_zifs
)
3743 for (ALL_LIST_ELEMENTS_RO(bond_zif
->bond_info
.mbr_zifs
, node
, zif
)) {
3744 zebra_evpn_mh_update_protodown_bond_mbr(zif
, false /*clear*/,
3749 /* The global EVPN MH protodown rc is applied to all local ESs */
3750 static void zebra_evpn_mh_update_protodown_es(struct zebra_evpn_es
*es
,
3753 struct zebra_if
*zif
;
3754 uint32_t old_protodown_rc
;
3757 /* if the reason code is the same bail unless it is a new
3758 * ES bond in that case we would need to ensure that the
3759 * dplane is really in sync with zebra
3762 && (zif
->protodown_rc
& ZEBRA_PROTODOWN_EVPN_ALL
)
3763 == (zmh_info
->protodown_rc
& ZEBRA_PROTODOWN_EVPN_ALL
))
3766 old_protodown_rc
= zif
->protodown_rc
;
3767 zif
->protodown_rc
&= ~ZEBRA_PROTODOWN_EVPN_ALL
;
3768 zif
->protodown_rc
|=
3769 (zmh_info
->protodown_rc
& ZEBRA_PROTODOWN_EVPN_ALL
);
3771 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
3772 && (old_protodown_rc
!= zif
->protodown_rc
))
3774 "es %s ifp %s protodown_rc changed; old 0x%x new 0x%x",
3775 es
->esi_str
, zif
->ifp
->name
, old_protodown_rc
,
3778 /* update dataplane with the new protodown setting */
3779 zebra_evpn_mh_update_protodown_bond(zif
);
3782 static void zebra_evpn_mh_clear_protodown_es(struct zebra_evpn_es
*es
)
3784 struct zebra_if
*zif
;
3785 uint32_t old_protodown_rc
;
3788 if (!(zif
->protodown_rc
& ZEBRA_PROTODOWN_EVPN_ALL
))
3791 old_protodown_rc
= zif
->protodown_rc
;
3792 zif
->protodown_rc
&= ~ZEBRA_PROTODOWN_EVPN_ALL
;
3794 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3796 "clear: es %s ifp %s protodown_rc cleared; old 0x%x new 0x%x",
3797 es
->esi_str
, zif
->ifp
->name
, old_protodown_rc
,
3800 /* update dataplane with the new protodown setting */
3801 zebra_evpn_mh_update_protodown_bond(zif
);
3804 static void zebra_evpn_mh_update_protodown_es_all(void)
3806 struct listnode
*node
;
3807 struct zebra_evpn_es
*es
;
3809 for (ALL_LIST_ELEMENTS_RO(zmh_info
->local_es_list
, node
, es
))
3810 zebra_evpn_mh_update_protodown_es(es
, false /*resync_dplane*/);
3813 static void zebra_evpn_mh_update_protodown(uint32_t protodown_rc
, bool set
)
3815 uint32_t old_protodown_rc
= zmh_info
->protodown_rc
;
3818 if ((protodown_rc
& zmh_info
->protodown_rc
) == protodown_rc
)
3821 zmh_info
->protodown_rc
|= protodown_rc
;
3823 if (!(protodown_rc
& zmh_info
->protodown_rc
))
3825 zmh_info
->protodown_rc
&= ~protodown_rc
;
3828 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3829 zlog_debug("mh protodown_rc changed; old 0x%x new 0x%x",
3830 old_protodown_rc
, zmh_info
->protodown_rc
);
3831 zebra_evpn_mh_update_protodown_es_all();
3834 static inline bool zebra_evpn_mh_is_all_uplinks_down(void)
3836 return zmh_info
->uplink_cfg_cnt
&& !zmh_info
->uplink_oper_up_cnt
;
3839 static void zebra_evpn_mh_uplink_oper_flags_update(struct zebra_if
*zif
,
3842 if (set
&& if_is_operative(zif
->ifp
)) {
3843 if (!(zif
->flags
& ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP
)) {
3844 zif
->flags
|= ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP
;
3845 ++zmh_info
->uplink_oper_up_cnt
;
3848 if (zif
->flags
& ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP
) {
3849 zif
->flags
&= ~ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP
;
3850 if (zmh_info
->uplink_oper_up_cnt
)
3851 --zmh_info
->uplink_oper_up_cnt
;
3856 static void zebra_evpn_mh_uplink_cfg_update(struct zebra_if
*zif
, bool set
)
3858 bool old_protodown
= zebra_evpn_mh_is_all_uplinks_down();
3862 if (zif
->flags
& ZIF_FLAG_EVPN_MH_UPLINK
)
3865 zif
->flags
|= ZIF_FLAG_EVPN_MH_UPLINK
;
3866 ++zmh_info
->uplink_cfg_cnt
;
3868 if (!(zif
->flags
& ZIF_FLAG_EVPN_MH_UPLINK
))
3871 zif
->flags
&= ~ZIF_FLAG_EVPN_MH_UPLINK
;
3872 if (zmh_info
->uplink_cfg_cnt
)
3873 --zmh_info
->uplink_cfg_cnt
;
3876 zebra_evpn_mh_uplink_oper_flags_update(zif
, set
);
3877 new_protodown
= zebra_evpn_mh_is_all_uplinks_down();
3878 if (old_protodown
== new_protodown
)
3881 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3883 "mh-uplink-cfg-chg on if %s/%d %s uplinks cfg %u up %u",
3884 zif
->ifp
->name
, zif
->ifp
->ifindex
, set
? "set" : "down",
3885 zmh_info
->uplink_cfg_cnt
, zmh_info
->uplink_oper_up_cnt
);
3887 zebra_evpn_mh_update_protodown(ZEBRA_PROTODOWN_EVPN_UPLINK_DOWN
,
3891 void zebra_evpn_mh_uplink_oper_update(struct zebra_if
*zif
)
3893 bool old_protodown
= zebra_evpn_mh_is_all_uplinks_down();
3896 zebra_evpn_mh_uplink_oper_flags_update(zif
, true /*set*/);
3898 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3900 "mh-uplink-oper-chg on if %s/%d %s; uplinks cfg %u up %u",
3901 zif
->ifp
->name
, zif
->ifp
->ifindex
,
3902 if_is_operative(zif
->ifp
) ? "up" : "down",
3903 zmh_info
->uplink_cfg_cnt
, zmh_info
->uplink_oper_up_cnt
);
3905 new_protodown
= zebra_evpn_mh_is_all_uplinks_down();
3906 if (old_protodown
== new_protodown
)
3909 /* if protodown_rc XXX_UPLINK_DOWN is about to be cleared
3910 * fire up the start-up delay timer to allow the EVPN network
3911 * to converge (Type-2 routes need to be advertised and processed)
3913 if (!new_protodown
&& (zmh_info
->uplink_oper_up_cnt
== 1))
3914 zebra_evpn_mh_startup_delay_timer_start("uplink-up");
3916 zebra_evpn_mh_update_protodown(ZEBRA_PROTODOWN_EVPN_UPLINK_DOWN
,
3920 static void zebra_evpn_mh_startup_delay_exp_cb(struct thread
*t
)
3922 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3923 zlog_debug("startup-delay expired");
3925 zebra_evpn_mh_update_protodown(ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY
,
3929 static void zebra_evpn_mh_startup_delay_timer_start(const char *rc
)
3931 if (zmh_info
->startup_delay_timer
) {
3932 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3933 zlog_debug("startup-delay timer cancelled");
3934 THREAD_OFF(zmh_info
->startup_delay_timer
);
3937 if (zmh_info
->startup_delay_time
) {
3938 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3940 "startup-delay timer started for %d sec on %s",
3941 zmh_info
->startup_delay_time
, rc
);
3942 thread_add_timer(zrouter
.master
,
3943 zebra_evpn_mh_startup_delay_exp_cb
, NULL
,
3944 zmh_info
->startup_delay_time
,
3945 &zmh_info
->startup_delay_timer
);
3946 zebra_evpn_mh_update_protodown(
3947 ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY
, true /* set */);
3949 zebra_evpn_mh_update_protodown(
3950 ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY
, false /* set */);
3954 /*****************************************************************************
3955 * Nexthop management: nexthops associated with Type-2 routes that have
3956 * an ES as destination are consolidated by BGP into a per-VRF nh->rmac
3957 * mapping which is the installed as a remote neigh/fdb entry with a
3958 * dummy (type-1) prefix referencing it.
3959 * This handling is needed because Type-2 routes with ES as dest use NHG
3960 * that are setup using EAD routes (i.e. such NHGs do not include the
3962 ****************************************************************************/
3963 void zebra_evpn_proc_remote_nh(ZAPI_HANDLER_ARGS
)
3968 struct ethaddr rmac
;
3969 struct prefix_evpn dummy_prefix
;
3970 size_t min_len
= 4 + sizeof(nh
);
3975 * Ensure that the stream sent to us is long enough
3977 if (hdr
->command
== ZEBRA_EVPN_REMOTE_NH_ADD
)
3978 min_len
+= sizeof(rmac
);
3979 if (hdr
->length
< min_len
)
3982 vrf_id
= stream_getl(s
);
3983 stream_get(&nh
, s
, sizeof(nh
));
3985 memset(&dummy_prefix
, 0, sizeof(dummy_prefix
));
3986 dummy_prefix
.family
= AF_EVPN
;
3987 dummy_prefix
.prefixlen
= (sizeof(struct evpn_addr
) * 8);
3988 dummy_prefix
.prefix
.route_type
= 1; /* XXX - fixup to type-1 def */
3989 dummy_prefix
.prefix
.ead_addr
.ip
.ipa_type
= nh
.ipa_type
;
3991 if (hdr
->command
== ZEBRA_EVPN_REMOTE_NH_ADD
) {
3992 stream_get(&rmac
, s
, sizeof(rmac
));
3993 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3995 "evpn remote nh %d %pIA rmac %pEA add pfx %pFX",
3996 vrf_id
, &nh
, &rmac
, &dummy_prefix
);
3997 zebra_rib_queue_evpn_route_add(vrf_id
, &rmac
, &nh
,
3998 (struct prefix
*)&dummy_prefix
);
4000 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
4001 zlog_debug("evpn remote nh %d %pIA del pfx %pFX",
4002 vrf_id
, &nh
, &dummy_prefix
);
4003 zebra_rib_queue_evpn_route_del(vrf_id
, &nh
,
4004 (struct prefix
*)&dummy_prefix
);
4008 /*****************************************************************************/
4009 void zebra_evpn_mh_config_write(struct vty
*vty
)
4011 if (zmh_info
->mac_hold_time
!= ZEBRA_EVPN_MH_MAC_HOLD_TIME_DEF
)
4012 vty_out(vty
, "evpn mh mac-holdtime %d\n",
4013 zmh_info
->mac_hold_time
);
4015 if (zmh_info
->neigh_hold_time
!= ZEBRA_EVPN_MH_NEIGH_HOLD_TIME_DEF
)
4016 vty_out(vty
, "evpn mh neigh-holdtime %d\n",
4017 zmh_info
->neigh_hold_time
);
4019 if (zmh_info
->startup_delay_time
!= ZEBRA_EVPN_MH_STARTUP_DELAY_DEF
)
4020 vty_out(vty
, "evpn mh startup-delay %d\n",
4021 zmh_info
->startup_delay_time
);
4023 if (zmh_info
->flags
& ZEBRA_EVPN_MH_REDIRECT_OFF
)
4024 vty_out(vty
, "evpn mh redirect-off\n");
4027 int zebra_evpn_mh_neigh_holdtime_update(struct vty
*vty
,
4028 uint32_t duration
, bool set_default
)
4031 duration
= ZEBRA_EVPN_MH_NEIGH_HOLD_TIME_DEF
;
4033 zmh_info
->neigh_hold_time
= duration
;
4038 int zebra_evpn_mh_mac_holdtime_update(struct vty
*vty
,
4039 uint32_t duration
, bool set_default
)
4042 duration
= ZEBRA_EVPN_MH_MAC_HOLD_TIME_DEF
;
4044 zmh_info
->mac_hold_time
= duration
;
4049 int zebra_evpn_mh_startup_delay_update(struct vty
*vty
, uint32_t duration
,
4053 duration
= ZEBRA_EVPN_MH_STARTUP_DELAY_DEF
;
4055 zmh_info
->startup_delay_time
= duration
;
4057 /* if startup_delay_timer is running allow it to be adjusted
4060 if (zmh_info
->startup_delay_timer
)
4061 zebra_evpn_mh_startup_delay_timer_start("config");
4066 int zebra_evpn_mh_redirect_off(struct vty
*vty
, bool redirect_off
)
4068 /* This knob needs to be set before ESs are configured
4069 * i.e. cannot be changed on the fly
4072 zmh_info
->flags
|= ZEBRA_EVPN_MH_REDIRECT_OFF
;
4074 zmh_info
->flags
&= ~ZEBRA_EVPN_MH_REDIRECT_OFF
;
4079 void zebra_evpn_interface_init(void)
4081 install_element(INTERFACE_NODE
, &zebra_evpn_es_id_cmd
);
4082 install_element(INTERFACE_NODE
, &zebra_evpn_es_sys_mac_cmd
);
4083 install_element(INTERFACE_NODE
, &zebra_evpn_es_pref_cmd
);
4084 install_element(INTERFACE_NODE
, &zebra_evpn_es_bypass_cmd
);
4085 install_element(INTERFACE_NODE
, &zebra_evpn_mh_uplink_cmd
);
4088 void zebra_evpn_mh_init(void)
4090 zrouter
.mh_info
= XCALLOC(MTYPE_ZMH_INFO
, sizeof(*zrouter
.mh_info
));
4092 zmh_info
->mac_hold_time
= ZEBRA_EVPN_MH_MAC_HOLD_TIME_DEF
;
4093 zmh_info
->neigh_hold_time
= ZEBRA_EVPN_MH_NEIGH_HOLD_TIME_DEF
;
4094 /* setup ES tables */
4095 RB_INIT(zebra_es_rb_head
, &zmh_info
->es_rb_tree
);
4096 zmh_info
->local_es_list
= list_new();
4097 listset_app_node_mem(zmh_info
->local_es_list
);
4099 bf_init(zmh_info
->nh_id_bitmap
, EVPN_NH_ID_MAX
);
4100 bf_assign_zero_index(zmh_info
->nh_id_bitmap
);
4101 zmh_info
->nhg_table
= hash_create(zebra_evpn_nhg_hash_keymake
,
4102 zebra_evpn_nhg_cmp
, "l2 NHG table");
4103 zmh_info
->nh_ip_table
=
4104 hash_create(zebra_evpn_nh_ip_hash_keymake
, zebra_evpn_nh_ip_cmp
,
4107 /* setup broadcast domain tables */
4108 zmh_info
->evpn_vlan_table
= hash_create(zebra_evpn_acc_vl_hash_keymake
,
4109 zebra_evpn_acc_vl_cmp
, "access VLAN hash table");
4111 zmh_info
->startup_delay_time
= ZEBRA_EVPN_MH_STARTUP_DELAY_DEF
;
4112 zebra_evpn_mh_startup_delay_timer_start("init");
4115 void zebra_evpn_mh_terminate(void)
4117 list_delete(&zmh_info
->local_es_list
);
4119 hash_iterate(zmh_info
->evpn_vlan_table
,
4120 zebra_evpn_acc_vl_cleanup_all
, NULL
);
4121 hash_free(zmh_info
->evpn_vlan_table
);
4122 hash_free(zmh_info
->nhg_table
);
4123 hash_free(zmh_info
->nh_ip_table
);
4124 bf_free(zmh_info
->nh_id_bitmap
);
4126 XFREE(MTYPE_ZMH_INFO
, zrouter
.mh_info
);