2 * Zebra EVPN multihoming code
4 * Copyright (C) 2019 Cumulus Networks, Inc.
7 * This file is part of FRR.
9 * FRR is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2, or (at your option) any
14 * FRR is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
35 #include "zebra/zebra_router.h"
36 #include "zebra/debug.h"
37 #include "zebra/interface.h"
38 #include "zebra/rib.h"
40 #include "zebra/rt_netlink.h"
41 #include "zebra/if_netlink.h"
42 #include "zebra/zebra_errors.h"
43 #include "zebra/zebra_l2.h"
44 #include "zebra/zebra_ns.h"
45 #include "zebra/zebra_vrf.h"
46 #include "zebra/zebra_vxlan.h"
47 #include "zebra/zebra_evpn.h"
48 #include "zebra/zebra_evpn_mac.h"
49 #include "zebra/zebra_vxlan_private.h"
50 #include "zebra/zebra_router.h"
51 #include "zebra/zebra_evpn_mh.h"
52 #include "zebra/zebra_nhg.h"
54 DEFINE_MTYPE_STATIC(ZEBRA
, ZACC_BD
, "Access Broadcast Domain");
55 DEFINE_MTYPE_STATIC(ZEBRA
, ZES
, "Ethernet Segment");
56 DEFINE_MTYPE_STATIC(ZEBRA
, ZES_EVI
, "ES info per-EVI");
57 DEFINE_MTYPE_STATIC(ZEBRA
, ZMH_INFO
, "MH global info");
58 DEFINE_MTYPE_STATIC(ZEBRA
, ZES_VTEP
, "VTEP attached to the ES");
59 DEFINE_MTYPE_STATIC(ZEBRA
, L2_NH
, "L2 nexthop");
61 static void zebra_evpn_es_get_one_base_evpn(void);
62 static int zebra_evpn_es_evi_send_to_client(struct zebra_evpn_es
*es
,
63 struct zebra_evpn
*zevpn
, bool add
);
64 static void zebra_evpn_local_es_del(struct zebra_evpn_es
**esp
);
65 static int zebra_evpn_local_es_update(struct zebra_if
*zif
, esi_t
*esi
);
66 static bool zebra_evpn_es_br_port_dplane_update(struct zebra_evpn_es
*es
,
68 static void zebra_evpn_mh_uplink_cfg_update(struct zebra_if
*zif
, bool set
);
69 static void zebra_evpn_mh_update_protodown_es(struct zebra_evpn_es
*es
,
71 static void zebra_evpn_mh_clear_protodown_es(struct zebra_evpn_es
*es
);
72 static void zebra_evpn_mh_startup_delay_timer_start(const char *rc
);
74 esi_t zero_esi_buf
, *zero_esi
= &zero_esi_buf
;
76 /*****************************************************************************/
77 /* Ethernet Segment to EVI association -
78 * 1. The ES-EVI entry is maintained as a RB tree per L2-VNI
79 * (struct zebra_evpn.es_evi_rb_tree).
80 * 2. Each local ES-EVI entry is sent to BGP which advertises it as an
81 * EAD-EVI (Type-1 EVPN) route
82 * 3. Local ES-EVI setup is re-evaluated on the following triggers -
83 * a. When an ESI is set or cleared on an access port.
84 * b. When an access port associated with an ESI is deleted.
85 * c. When VLAN member ship changes on an access port.
86 * d. When a VXLAN_IF is set or cleared on an access broadcast domain.
87 * e. When a L2-VNI is added or deleted for a VxLAN_IF.
88 * 4. Currently zebra doesn't remote ES-EVIs. Those are managed and maintained
89 * entirely in BGP which consolidates them into a remote ES. The remote ES
90 * is then sent to zebra which allocates a NHG for it.
93 /* compare ES-IDs for the ES-EVI RB tree maintained per-EVPN */
94 static int zebra_es_evi_rb_cmp(const struct zebra_evpn_es_evi
*es_evi1
,
95 const struct zebra_evpn_es_evi
*es_evi2
)
97 return memcmp(&es_evi1
->es
->esi
, &es_evi2
->es
->esi
, ESI_BYTES
);
99 RB_GENERATE(zebra_es_evi_rb_head
, zebra_evpn_es_evi
,
100 rb_node
, zebra_es_evi_rb_cmp
);
102 /* allocate a new ES-EVI and insert it into the per-L2-VNI and per-ES
105 static struct zebra_evpn_es_evi
*zebra_evpn_es_evi_new(struct zebra_evpn_es
*es
,
106 struct zebra_evpn
*zevpn
)
108 struct zebra_evpn_es_evi
*es_evi
;
110 es_evi
= XCALLOC(MTYPE_ZES_EVI
, sizeof(struct zebra_evpn_es_evi
));
113 es_evi
->zevpn
= zevpn
;
115 /* insert into the EVPN-ESI rb tree */
116 if (RB_INSERT(zebra_es_evi_rb_head
, &zevpn
->es_evi_rb_tree
, es_evi
)) {
117 XFREE(MTYPE_ZES_EVI
, es_evi
);
121 /* add to the ES's VNI list */
122 listnode_init(&es_evi
->es_listnode
, es_evi
);
123 listnode_add(es
->es_evi_list
, &es_evi
->es_listnode
);
125 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
126 zlog_debug("es %s evi %d new",
127 es_evi
->es
->esi_str
, es_evi
->zevpn
->vni
);
132 /* Evaluate if the es_evi is ready to be sent BGP -
133 * 1. If it is ready an add is sent to BGP
134 * 2. If it is not ready a del is sent (if the ES had been previously added
137 static void zebra_evpn_es_evi_re_eval_send_to_client(
138 struct zebra_evpn_es_evi
*es_evi
)
143 old_ready
= !!(es_evi
->flags
& ZEBRA_EVPNES_EVI_READY_FOR_BGP
);
145 /* ES and L2-VNI have to be individually ready for BGP */
146 if ((es_evi
->flags
& ZEBRA_EVPNES_EVI_LOCAL
) &&
147 (es_evi
->es
->flags
& ZEBRA_EVPNES_READY_FOR_BGP
) &&
148 zebra_evpn_send_to_client_ok(es_evi
->zevpn
))
149 es_evi
->flags
|= ZEBRA_EVPNES_EVI_READY_FOR_BGP
;
151 es_evi
->flags
&= ~ZEBRA_EVPNES_EVI_READY_FOR_BGP
;
153 new_ready
= !!(es_evi
->flags
& ZEBRA_EVPNES_EVI_READY_FOR_BGP
);
155 if (old_ready
== new_ready
)
159 zebra_evpn_es_evi_send_to_client(es_evi
->es
, es_evi
->zevpn
,
162 zebra_evpn_es_evi_send_to_client(es_evi
->es
, es_evi
->zevpn
,
166 /* remove the ES-EVI from the per-L2-VNI and per-ES tables and free
169 static void zebra_evpn_es_evi_free(struct zebra_evpn_es_evi
*es_evi
)
171 struct zebra_evpn_es
*es
= es_evi
->es
;
172 struct zebra_evpn
*zevpn
= es_evi
->zevpn
;
174 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
175 zlog_debug("es %s evi %d free",
176 es_evi
->es
->esi_str
, es_evi
->zevpn
->vni
);
178 /* remove from the ES's VNI list */
179 list_delete_node(es
->es_evi_list
, &es_evi
->es_listnode
);
181 /* remove from the VNI-ESI rb tree */
182 RB_REMOVE(zebra_es_evi_rb_head
, &zevpn
->es_evi_rb_tree
, es_evi
);
184 /* remove from the VNI-ESI rb tree */
185 XFREE(MTYPE_ZES_EVI
, es_evi
);
188 /* find the ES-EVI in the per-L2-VNI RB tree */
189 struct zebra_evpn_es_evi
*zebra_evpn_es_evi_find(struct zebra_evpn_es
*es
,
190 struct zebra_evpn
*zevpn
)
192 struct zebra_evpn_es_evi es_evi
;
196 return RB_FIND(zebra_es_evi_rb_head
, &zevpn
->es_evi_rb_tree
, &es_evi
);
199 /* Tell BGP about an ES-EVI deletion and then delete it */
200 static void zebra_evpn_local_es_evi_do_del(struct zebra_evpn_es_evi
*es_evi
)
202 if (!(es_evi
->flags
& ZEBRA_EVPNES_EVI_LOCAL
))
205 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
206 zlog_debug("local es %s evi %d del",
207 es_evi
->es
->esi_str
, es_evi
->zevpn
->vni
);
209 if (es_evi
->flags
& ZEBRA_EVPNES_EVI_READY_FOR_BGP
) {
210 /* send a del only if add was sent for it earlier */
211 zebra_evpn_es_evi_send_to_client(es_evi
->es
,
212 es_evi
->zevpn
, false /* add */);
215 /* delete it from the EVPN's local list */
216 list_delete_node(es_evi
->zevpn
->local_es_evi_list
,
217 &es_evi
->l2vni_listnode
);
219 es_evi
->flags
&= ~ZEBRA_EVPNES_EVI_LOCAL
;
220 zebra_evpn_es_evi_free(es_evi
);
222 static void zebra_evpn_local_es_evi_del(struct zebra_evpn_es
*es
,
223 struct zebra_evpn
*zevpn
)
225 struct zebra_evpn_es_evi
*es_evi
;
227 es_evi
= zebra_evpn_es_evi_find(es
, zevpn
);
229 zebra_evpn_local_es_evi_do_del(es_evi
);
232 /* If there are any existing MAC entries for this es/zevpn we need
233 * to install it in the dataplane.
235 * Note: primary purpose of this is to handle es del/re-add windows where
236 * sync MAC entries may be added by bgpd before the es-evi membership is
237 * created in the dataplane and in zebra
239 static void zebra_evpn_es_evi_mac_install(struct zebra_evpn_es_evi
*es_evi
)
241 struct zebra_mac
*mac
;
242 struct listnode
*node
;
243 struct zebra_evpn_es
*es
= es_evi
->es
;
245 if (listcount(es
->mac_list
) && IS_ZEBRA_DEBUG_EVPN_MH_ES
)
246 zlog_debug("dp-mac install on es %s evi %d add", es
->esi_str
,
249 for (ALL_LIST_ELEMENTS_RO(es
->mac_list
, node
, mac
)) {
250 if (mac
->zevpn
!= es_evi
->zevpn
)
253 if (!CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
))
256 zebra_evpn_sync_mac_dp_install(mac
, false, false, __func__
);
260 /* Create an ES-EVI if it doesn't already exist and tell BGP */
261 static void zebra_evpn_local_es_evi_add(struct zebra_evpn_es
*es
,
262 struct zebra_evpn
*zevpn
)
264 struct zebra_evpn_es_evi
*es_evi
;
266 es_evi
= zebra_evpn_es_evi_find(es
, zevpn
);
268 es_evi
= zebra_evpn_es_evi_new(es
, zevpn
);
272 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
273 zlog_debug("local es %s evi %d add",
274 es_evi
->es
->esi_str
, es_evi
->zevpn
->vni
);
275 es_evi
->flags
|= ZEBRA_EVPNES_EVI_LOCAL
;
276 /* add to the EVPN's local list */
277 listnode_init(&es_evi
->l2vni_listnode
, es_evi
);
278 listnode_add(zevpn
->local_es_evi_list
, &es_evi
->l2vni_listnode
);
280 zebra_evpn_es_evi_re_eval_send_to_client(es_evi
);
282 zebra_evpn_es_evi_mac_install(es_evi
);
286 static void zebra_evpn_es_evi_show_entry(struct vty
*vty
,
287 struct zebra_evpn_es_evi
*es_evi
,
288 json_object
*json_array
)
294 json_object
*json_types
;
296 /* Separate JSON object for each es-evi entry */
297 json
= json_object_new_object();
299 json_object_string_add(json
, "esi", es_evi
->es
->esi_str
);
300 json_object_int_add(json
, "vni", es_evi
->zevpn
->vni
);
301 if (es_evi
->flags
& ZEBRA_EVPNES_EVI_LOCAL
) {
302 json_types
= json_object_new_array();
303 if (es_evi
->flags
& ZEBRA_EVPNES_EVI_LOCAL
)
304 json_array_string_add(json_types
, "local");
305 json_object_object_add(json
, "type", json_types
);
308 /* Add es-evi entry to json array */
309 json_object_array_add(json_array
, json
);
312 if (es_evi
->flags
& ZEBRA_EVPNES_EVI_LOCAL
)
313 strlcat(type_str
, "L", sizeof(type_str
));
315 vty_out(vty
, "%-8d %-30s %-4s\n",
316 es_evi
->zevpn
->vni
, es_evi
->es
->esi_str
,
322 zebra_evpn_es_evi_show_entry_detail(struct vty
*vty
,
323 struct zebra_evpn_es_evi
*es_evi
,
324 json_object
*json_array
)
330 json_object
*json_flags
;
332 /* Separate JSON object for each es-evi entry */
333 json
= json_object_new_object();
335 json_object_string_add(json
, "esi", es_evi
->es
->esi_str
);
336 json_object_int_add(json
, "vni", es_evi
->zevpn
->vni
);
338 & (ZEBRA_EVPNES_EVI_LOCAL
339 | ZEBRA_EVPNES_EVI_READY_FOR_BGP
)) {
340 json_flags
= json_object_new_array();
341 if (es_evi
->flags
& ZEBRA_EVPNES_EVI_LOCAL
)
342 json_array_string_add(json_flags
, "local");
343 if (es_evi
->flags
& ZEBRA_EVPNES_EVI_READY_FOR_BGP
)
344 json_array_string_add(json_flags
,
346 json_object_object_add(json
, "flags", json_flags
);
349 /* Add es-evi entry to json array */
350 json_object_array_add(json_array
, json
);
353 if (es_evi
->flags
& ZEBRA_EVPNES_EVI_LOCAL
)
354 strlcat(type_str
, "L", sizeof(type_str
));
356 vty_out(vty
, "VNI %d ESI: %s\n",
357 es_evi
->zevpn
->vni
, es_evi
->es
->esi_str
);
358 vty_out(vty
, " Type: %s\n", type_str
);
359 vty_out(vty
, " Ready for BGP: %s\n",
361 ZEBRA_EVPNES_EVI_READY_FOR_BGP
) ?
367 static void zebra_evpn_es_evi_show_one_evpn(struct zebra_evpn
*zevpn
,
369 json_object
*json_array
, int detail
)
371 struct zebra_evpn_es_evi
*es_evi
;
373 RB_FOREACH(es_evi
, zebra_es_evi_rb_head
, &zevpn
->es_evi_rb_tree
) {
375 zebra_evpn_es_evi_show_entry_detail(vty
, es_evi
,
378 zebra_evpn_es_evi_show_entry(vty
, es_evi
, json_array
);
382 struct evpn_mh_show_ctx
{
388 static void zebra_evpn_es_evi_show_one_evpn_hash_cb(struct hash_bucket
*bucket
,
391 struct zebra_evpn
*zevpn
= (struct zebra_evpn
*)bucket
->data
;
392 struct evpn_mh_show_ctx
*wctx
= (struct evpn_mh_show_ctx
*)ctxt
;
394 zebra_evpn_es_evi_show_one_evpn(zevpn
, wctx
->vty
,
395 wctx
->json
, wctx
->detail
);
398 void zebra_evpn_es_evi_show(struct vty
*vty
, bool uj
, int detail
)
400 json_object
*json_array
= NULL
;
401 struct zebra_vrf
*zvrf
;
402 struct evpn_mh_show_ctx wctx
;
404 zvrf
= zebra_vrf_get_evpn();
406 json_array
= json_object_new_array();
408 memset(&wctx
, 0, sizeof(wctx
));
410 wctx
.json
= json_array
;
411 wctx
.detail
= detail
;
413 if (!detail
&& !json_array
) {
414 vty_out(vty
, "Type: L local, R remote\n");
415 vty_out(vty
, "%-8s %-30s %-4s\n", "VNI", "ESI", "Type");
417 /* Display all L2-VNIs */
418 hash_iterate(zvrf
->evpn_table
, zebra_evpn_es_evi_show_one_evpn_hash_cb
,
422 vty_json(vty
, json_array
);
425 void zebra_evpn_es_evi_show_vni(struct vty
*vty
, bool uj
, vni_t vni
, int detail
)
427 json_object
*json_array
= NULL
;
428 struct zebra_evpn
*zevpn
;
430 zevpn
= zebra_evpn_lookup(vni
);
432 json_array
= json_object_new_array();
435 if (!detail
&& !json_array
) {
436 vty_out(vty
, "Type: L local, R remote\n");
437 vty_out(vty
, "%-8s %-30s %-4s\n", "VNI", "ESI", "Type");
439 zebra_evpn_es_evi_show_one_evpn(zevpn
, vty
, json_array
, detail
);
442 vty_out(vty
, "VNI %d doesn't exist\n", vni
);
446 vty_json(vty
, json_array
);
449 /* Initialize the ES tables maintained per-L2_VNI */
450 void zebra_evpn_es_evi_init(struct zebra_evpn
*zevpn
)
452 /* Initialize the ES-EVI RB tree */
453 RB_INIT(zebra_es_evi_rb_head
, &zevpn
->es_evi_rb_tree
);
455 /* Initialize the local and remote ES lists maintained for quick
458 zevpn
->local_es_evi_list
= list_new();
459 listset_app_node_mem(zevpn
->local_es_evi_list
);
462 /* Cleanup the ES info maintained per- EVPN */
463 void zebra_evpn_es_evi_cleanup(struct zebra_evpn
*zevpn
)
465 struct zebra_evpn_es_evi
*es_evi
;
466 struct zebra_evpn_es_evi
*es_evi_next
;
468 RB_FOREACH_SAFE(es_evi
, zebra_es_evi_rb_head
,
469 &zevpn
->es_evi_rb_tree
, es_evi_next
) {
470 zebra_evpn_local_es_evi_do_del(es_evi
);
473 list_delete(&zevpn
->local_es_evi_list
);
474 zebra_evpn_es_clear_base_evpn(zevpn
);
477 /* called when the oper state or bridge membership changes for the
480 void zebra_evpn_update_all_es(struct zebra_evpn
*zevpn
)
482 struct zebra_evpn_es_evi
*es_evi
;
483 struct listnode
*node
;
484 struct interface
*vlan_if
;
485 struct interface
*vxlan_if
;
486 struct zebra_if
*vxlan_zif
;
488 /* the EVPN is now elgible as a base for EVPN-MH */
489 if (zebra_evpn_send_to_client_ok(zevpn
))
490 zebra_evpn_es_set_base_evpn(zevpn
);
492 zebra_evpn_es_clear_base_evpn(zevpn
);
494 for (ALL_LIST_ELEMENTS_RO(zevpn
->local_es_evi_list
, node
, es_evi
))
495 zebra_evpn_es_evi_re_eval_send_to_client(es_evi
);
497 /* reinstall SVI MAC */
498 vxlan_if
= zevpn
->vxlan_if
;
500 vxlan_zif
= vxlan_if
->info
;
501 if (if_is_operative(vxlan_if
)
502 && vxlan_zif
->brslave_info
.br_if
) {
503 vlan_if
= zvni_map_to_svi(
504 vxlan_zif
->l2info
.vxl
.access_vlan
,
505 vxlan_zif
->brslave_info
.br_if
);
507 zebra_evpn_acc_bd_svi_mac_add(vlan_if
);
512 /*****************************************************************************/
513 /* Access broadcast domains (BD)
514 * 1. These broadcast domains can be VLAN aware (in which case
515 * the key is VID) or VLAN unaware (in which case the key is
516 * 2. A VID-BD is created when a VLAN is associated with an access port or
517 * when the VLAN is associated with VXLAN_IF
518 * 3. A BD is translated into ES-EVI entries when a VNI is associated
519 * with the broadcast domain
521 /* Hash key for VLAN based broadcast domains */
522 static unsigned int zebra_evpn_acc_vl_hash_keymake(const void *p
)
524 const struct zebra_evpn_access_bd
*acc_bd
= p
;
526 return jhash_1word(acc_bd
->vid
, 0);
529 /* Compare two VLAN based broadcast domains */
530 static bool zebra_evpn_acc_vl_cmp(const void *p1
, const void *p2
)
532 const struct zebra_evpn_access_bd
*acc_bd1
= p1
;
533 const struct zebra_evpn_access_bd
*acc_bd2
= p2
;
535 if (acc_bd1
== NULL
&& acc_bd2
== NULL
)
538 if (acc_bd1
== NULL
|| acc_bd2
== NULL
)
541 return (acc_bd1
->vid
== acc_bd2
->vid
);
544 /* Lookup VLAN based broadcast domain */
545 static struct zebra_evpn_access_bd
*zebra_evpn_acc_vl_find(vlanid_t vid
)
547 struct zebra_evpn_access_bd
*acc_bd
;
548 struct zebra_evpn_access_bd tmp
;
551 acc_bd
= hash_lookup(zmh_info
->evpn_vlan_table
, &tmp
);
556 /* A new broadcast domain can be created when a VLAN member or VLAN<=>VxLAN_IF
559 static struct zebra_evpn_access_bd
*
560 zebra_evpn_acc_vl_new(vlanid_t vid
, struct interface
*br_if
)
562 struct zebra_evpn_access_bd
*acc_bd
;
563 struct interface
*vlan_if
;
565 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
566 zlog_debug("access vlan %d add", vid
);
568 acc_bd
= XCALLOC(MTYPE_ZACC_BD
, sizeof(struct zebra_evpn_access_bd
));
572 /* Initialize the mbr list */
573 acc_bd
->mbr_zifs
= list_new();
576 if (!hash_get(zmh_info
->evpn_vlan_table
, acc_bd
, hash_alloc_intern
)) {
577 XFREE(MTYPE_ZACC_BD
, acc_bd
);
581 /* check if an svi exists for the vlan */
583 vlan_if
= zvni_map_to_svi(vid
, br_if
);
585 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
586 zlog_debug("vlan %d SVI %s set", vid
,
588 acc_bd
->vlan_zif
= vlan_if
->info
;
594 /* Free VLAN based broadcast domain -
595 * This just frees appropriate memory, caller should have taken other
598 static void zebra_evpn_acc_vl_free(struct zebra_evpn_access_bd
*acc_bd
)
600 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
601 zlog_debug("access vlan %d del", acc_bd
->vid
);
603 if (acc_bd
->vlan_zif
&& acc_bd
->zevpn
&& acc_bd
->zevpn
->mac_table
)
604 zebra_evpn_mac_svi_del(acc_bd
->vlan_zif
->ifp
, acc_bd
->zevpn
);
606 /* cleanup resources maintained against the ES */
607 list_delete(&acc_bd
->mbr_zifs
);
609 /* remove EVI from various tables */
610 hash_release(zmh_info
->evpn_vlan_table
, acc_bd
);
612 XFREE(MTYPE_ZACC_BD
, acc_bd
);
615 static void zebra_evpn_acc_vl_cleanup_all(struct hash_bucket
*bucket
, void *arg
)
617 struct zebra_evpn_access_bd
*acc_bd
= bucket
->data
;
619 zebra_evpn_acc_vl_free(acc_bd
);
622 /* called when a bd mbr is removed or VxLAN_IF is diassociated from the access
625 static void zebra_evpn_acc_bd_free_on_deref(struct zebra_evpn_access_bd
*acc_bd
)
627 if (!list_isempty(acc_bd
->mbr_zifs
) || acc_bd
->vxlan_zif
)
630 /* if there are no references free the EVI */
631 zebra_evpn_acc_vl_free(acc_bd
);
634 /* called when a SVI is goes up/down */
635 void zebra_evpn_acc_bd_svi_set(struct zebra_if
*vlan_zif
,
636 struct zebra_if
*br_zif
, bool is_up
)
638 struct zebra_evpn_access_bd
*acc_bd
;
639 struct zebra_l2info_bridge
*br
;
641 struct zebra_if
*tmp_br_zif
= br_zif
;
644 if (!vlan_zif
->link
|| !vlan_zif
->link
->info
)
647 tmp_br_zif
= vlan_zif
->link
->info
;
650 br
= &tmp_br_zif
->l2info
.br
;
651 /* ignore vlan unaware bridges */
655 vid
= vlan_zif
->l2info
.vl
.vid
;
656 acc_bd
= zebra_evpn_acc_vl_find(vid
);
661 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
662 zlog_debug("vlan %d SVI %s set", vid
,
663 vlan_zif
->ifp
->name
);
665 acc_bd
->vlan_zif
= vlan_zif
;
667 zebra_evpn_mac_svi_add(acc_bd
->vlan_zif
->ifp
,
669 } else if (acc_bd
->vlan_zif
) {
670 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
671 zlog_debug("vlan %d SVI clear", vid
);
672 acc_bd
->vlan_zif
= NULL
;
673 if (acc_bd
->zevpn
&& acc_bd
->zevpn
->mac_table
)
674 zebra_evpn_mac_svi_del(vlan_zif
->ifp
, acc_bd
->zevpn
);
678 /* On some events macs are force-flushed. This api can be used to reinstate
679 * the svi-mac after such cleanup-events.
681 void zebra_evpn_acc_bd_svi_mac_add(struct interface
*vlan_if
)
683 zebra_evpn_acc_bd_svi_set(vlan_if
->info
, NULL
,
684 if_is_operative(vlan_if
));
687 /* called when a EVPN-L2VNI is set or cleared against a BD */
688 static void zebra_evpn_acc_bd_evpn_set(struct zebra_evpn_access_bd
*acc_bd
,
689 struct zebra_evpn
*zevpn
,
690 struct zebra_evpn
*old_zevpn
)
692 struct zebra_if
*zif
;
693 struct listnode
*node
;
695 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
696 zlog_debug("access vlan %d l2-vni %u set",
697 acc_bd
->vid
, zevpn
? zevpn
->vni
: 0);
699 for (ALL_LIST_ELEMENTS_RO(acc_bd
->mbr_zifs
, node
, zif
)) {
700 if (!zif
->es_info
.es
)
704 zebra_evpn_local_es_evi_add(zif
->es_info
.es
, zevpn
);
706 zebra_evpn_local_es_evi_del(zif
->es_info
.es
, old_zevpn
);
709 if (acc_bd
->vlan_zif
) {
711 zebra_evpn_mac_svi_add(acc_bd
->vlan_zif
->ifp
,
713 else if (old_zevpn
&& old_zevpn
->mac_table
)
714 zebra_evpn_mac_svi_del(acc_bd
->vlan_zif
->ifp
,
719 /* handle VLAN->VxLAN_IF association */
720 void zebra_evpn_vl_vxl_ref(uint16_t vid
, struct zebra_if
*vxlan_zif
)
722 struct zebra_evpn_access_bd
*acc_bd
;
723 struct zebra_if
*old_vxlan_zif
;
724 struct zebra_evpn
*old_zevpn
;
729 acc_bd
= zebra_evpn_acc_vl_find(vid
);
731 acc_bd
= zebra_evpn_acc_vl_new(vid
,
732 vxlan_zif
->brslave_info
.br_if
);
734 old_vxlan_zif
= acc_bd
->vxlan_zif
;
735 acc_bd
->vxlan_zif
= vxlan_zif
;
736 if (vxlan_zif
== old_vxlan_zif
)
739 old_zevpn
= acc_bd
->zevpn
;
740 acc_bd
->zevpn
= zebra_evpn_lookup(vxlan_zif
->l2info
.vxl
.vni
);
741 if (acc_bd
->zevpn
== old_zevpn
)
744 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
745 zlog_debug("access vlan %d vni %u ref",
746 acc_bd
->vid
, vxlan_zif
->l2info
.vxl
.vni
);
749 zebra_evpn_acc_bd_evpn_set(acc_bd
, NULL
, old_zevpn
);
752 zebra_evpn_acc_bd_evpn_set(acc_bd
, acc_bd
->zevpn
, NULL
);
755 /* handle VLAN->VxLAN_IF deref */
756 void zebra_evpn_vl_vxl_deref(uint16_t vid
, struct zebra_if
*vxlan_zif
)
758 struct zebra_evpn_access_bd
*acc_bd
;
763 acc_bd
= zebra_evpn_acc_vl_find(vid
);
767 /* clear vxlan_if only if it matches */
768 if (acc_bd
->vxlan_zif
!= vxlan_zif
)
771 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
772 zlog_debug("access vlan %d vni %u deref",
773 acc_bd
->vid
, vxlan_zif
->l2info
.vxl
.vni
);
776 zebra_evpn_acc_bd_evpn_set(acc_bd
, NULL
, acc_bd
->zevpn
);
778 acc_bd
->zevpn
= NULL
;
779 acc_bd
->vxlan_zif
= NULL
;
781 /* if there are no other references the access_bd can be freed */
782 zebra_evpn_acc_bd_free_on_deref(acc_bd
);
785 /* handle EVPN add/del */
786 void zebra_evpn_vxl_evpn_set(struct zebra_if
*zif
, struct zebra_evpn
*zevpn
,
789 struct zebra_l2info_vxlan
*vxl
;
790 struct zebra_evpn_access_bd
*acc_bd
;
795 /* locate access_bd associated with the vxlan device */
796 vxl
= &zif
->l2info
.vxl
;
797 acc_bd
= zebra_evpn_acc_vl_find(vxl
->access_vlan
);
802 zebra_evpn_es_set_base_evpn(zevpn
);
803 if (acc_bd
->zevpn
!= zevpn
) {
804 acc_bd
->zevpn
= zevpn
;
805 zebra_evpn_acc_bd_evpn_set(acc_bd
, zevpn
, NULL
);
809 struct zebra_evpn
*old_zevpn
= acc_bd
->zevpn
;
810 acc_bd
->zevpn
= NULL
;
811 zebra_evpn_acc_bd_evpn_set(acc_bd
, NULL
, old_zevpn
);
816 /* handle addition of new VLAN members */
817 void zebra_evpn_vl_mbr_ref(uint16_t vid
, struct zebra_if
*zif
)
819 struct zebra_evpn_access_bd
*acc_bd
;
824 acc_bd
= zebra_evpn_acc_vl_find(vid
);
826 acc_bd
= zebra_evpn_acc_vl_new(vid
, zif
->brslave_info
.br_if
);
828 if (listnode_lookup(acc_bd
->mbr_zifs
, zif
))
831 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
832 zlog_debug("access vlan %d mbr %s ref",
833 vid
, zif
->ifp
->name
);
835 listnode_add(acc_bd
->mbr_zifs
, zif
);
836 if (acc_bd
->zevpn
&& zif
->es_info
.es
)
837 zebra_evpn_local_es_evi_add(zif
->es_info
.es
, acc_bd
->zevpn
);
840 /* handle deletion of VLAN members */
841 void zebra_evpn_vl_mbr_deref(uint16_t vid
, struct zebra_if
*zif
)
843 struct zebra_evpn_access_bd
*acc_bd
;
844 struct listnode
*node
;
849 acc_bd
= zebra_evpn_acc_vl_find(vid
);
853 node
= listnode_lookup(acc_bd
->mbr_zifs
, zif
);
857 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
858 zlog_debug("access vlan %d mbr %s deref",
859 vid
, zif
->ifp
->name
);
861 list_delete_node(acc_bd
->mbr_zifs
, node
);
863 if (acc_bd
->zevpn
&& zif
->es_info
.es
)
864 zebra_evpn_local_es_evi_del(zif
->es_info
.es
, acc_bd
->zevpn
);
866 /* if there are no other references the access_bd can be freed */
867 zebra_evpn_acc_bd_free_on_deref(acc_bd
);
870 static void zebra_evpn_acc_vl_adv_svi_mac_cb(struct hash_bucket
*bucket
,
873 struct zebra_evpn_access_bd
*acc_bd
= bucket
->data
;
875 if (acc_bd
->vlan_zif
&& acc_bd
->zevpn
)
876 zebra_evpn_mac_svi_add(acc_bd
->vlan_zif
->ifp
, acc_bd
->zevpn
);
879 /* called when advertise SVI MAC is enabled on the switch */
880 static void zebra_evpn_acc_vl_adv_svi_mac_all(void)
882 hash_iterate(zmh_info
->evpn_vlan_table
,
883 zebra_evpn_acc_vl_adv_svi_mac_cb
, NULL
);
886 static void zebra_evpn_acc_vl_json_fill(struct zebra_evpn_access_bd
*acc_bd
,
887 json_object
*json
, bool detail
)
889 json_object_int_add(json
, "vlan", acc_bd
->vid
);
890 if (acc_bd
->vxlan_zif
)
891 json_object_string_add(json
, "vxlanIf",
892 acc_bd
->vxlan_zif
->ifp
->name
);
894 json_object_int_add(json
, "vni", acc_bd
->zevpn
->vni
);
895 if (acc_bd
->mbr_zifs
)
896 json_object_int_add(json
, "memberIfCount",
897 listcount(acc_bd
->mbr_zifs
));
900 json_object
*json_mbrs
;
901 json_object
*json_mbr
;
902 struct zebra_if
*zif
;
903 struct listnode
*node
;
906 json_mbrs
= json_object_new_array();
907 for (ALL_LIST_ELEMENTS_RO(acc_bd
->mbr_zifs
, node
, zif
)) {
908 json_mbr
= json_object_new_object();
909 json_object_string_add(json_mbr
, "ifName",
911 json_object_array_add(json_mbrs
, json_mbr
);
913 json_object_object_add(json
, "members", json_mbrs
);
917 static void zebra_evpn_acc_vl_show_entry_detail(struct vty
*vty
,
918 struct zebra_evpn_access_bd
*acc_bd
, json_object
*json
)
920 struct zebra_if
*zif
;
921 struct listnode
*node
;
924 zebra_evpn_acc_vl_json_fill(acc_bd
, json
, true);
926 vty_out(vty
, "VLAN: %u\n", acc_bd
->vid
);
927 vty_out(vty
, " VxLAN Interface: %s\n",
929 acc_bd
->vxlan_zif
->ifp
->name
: "-");
930 vty_out(vty
, " SVI: %s\n",
931 acc_bd
->vlan_zif
? acc_bd
->vlan_zif
->ifp
->name
: "-");
932 vty_out(vty
, " L2-VNI: %d\n",
933 acc_bd
->zevpn
? acc_bd
->zevpn
->vni
: 0);
934 vty_out(vty
, " Member Count: %d\n",
935 listcount(acc_bd
->mbr_zifs
));
936 vty_out(vty
, " Members: \n");
937 for (ALL_LIST_ELEMENTS_RO(acc_bd
->mbr_zifs
, node
, zif
))
938 vty_out(vty
, " %s\n", zif
->ifp
->name
);
943 static void zebra_evpn_acc_vl_show_entry(struct vty
*vty
,
944 struct zebra_evpn_access_bd
*acc_bd
, json_object
*json
)
947 zebra_evpn_acc_vl_json_fill(acc_bd
, json
, false);
949 vty_out(vty
, "%-5u %-15s %-8d %-15s %u\n", acc_bd
->vid
,
950 acc_bd
->vlan_zif
? acc_bd
->vlan_zif
->ifp
->name
: "-",
951 acc_bd
->zevpn
? acc_bd
->zevpn
->vni
: 0,
952 acc_bd
->vxlan_zif
? acc_bd
->vxlan_zif
->ifp
->name
: "-",
953 listcount(acc_bd
->mbr_zifs
));
957 static void zebra_evpn_acc_vl_show_hash(struct hash_bucket
*bucket
, void *ctxt
)
959 struct evpn_mh_show_ctx
*wctx
= ctxt
;
960 struct zebra_evpn_access_bd
*acc_bd
= bucket
->data
;
961 json_object
*json
= NULL
;
964 json
= json_object_new_object();
966 zebra_evpn_acc_vl_show_entry_detail(wctx
->vty
, acc_bd
, json
);
968 zebra_evpn_acc_vl_show_entry(wctx
->vty
, acc_bd
, json
);
970 json_object_array_add(wctx
->json
, json
);
973 void zebra_evpn_acc_vl_show(struct vty
*vty
, bool uj
)
975 struct evpn_mh_show_ctx wctx
;
976 json_object
*json_array
= NULL
;
979 json_array
= json_object_new_array();
981 memset(&wctx
, 0, sizeof(wctx
));
983 wctx
.json
= json_array
;
987 vty_out(vty
, "%-5s %-15s %-8s %-15s %s\n", "VLAN", "SVI",
988 "L2-VNI", "VXLAN-IF", "# Members");
990 hash_iterate(zmh_info
->evpn_vlan_table
, zebra_evpn_acc_vl_show_hash
,
994 vty_json(vty
, json_array
);
997 void zebra_evpn_acc_vl_show_detail(struct vty
*vty
, bool uj
)
999 struct evpn_mh_show_ctx wctx
;
1000 json_object
*json_array
= NULL
;
1003 json_array
= json_object_new_array();
1004 memset(&wctx
, 0, sizeof(wctx
));
1006 wctx
.json
= json_array
;
1009 hash_iterate(zmh_info
->evpn_vlan_table
, zebra_evpn_acc_vl_show_hash
,
1013 vty_json(vty
, json_array
);
1016 void zebra_evpn_acc_vl_show_vid(struct vty
*vty
, bool uj
, vlanid_t vid
)
1018 json_object
*json
= NULL
;
1019 struct zebra_evpn_access_bd
*acc_bd
;
1022 json
= json_object_new_object();
1024 acc_bd
= zebra_evpn_acc_vl_find(vid
);
1026 zebra_evpn_acc_vl_show_entry_detail(vty
, acc_bd
, json
);
1029 vty_out(vty
, "VLAN %u not present\n", vid
);
1033 vty_json(vty
, json
);
1036 /* Initialize VLAN member bitmap on an interface. Although VLAN membership
1037 * is independent of EVPN we only process it if its of interest to EVPN-MH
1038 * i.e. on access ports that can be setup as Ethernet Segments. And that is
1039 * intended as an optimization.
1041 void zebra_evpn_if_init(struct zebra_if
*zif
)
1043 if (!zebra_evpn_is_if_es_capable(zif
))
1046 if (!bf_is_inited(zif
->vlan_bitmap
))
1047 bf_init(zif
->vlan_bitmap
, IF_VLAN_BITMAP_MAX
);
1049 /* if an es_id and sysmac are already present against the interface
1052 zebra_evpn_local_es_update(zif
, &zif
->es_info
.esi
);
1055 /* handle deletion of an access port by removing it from all associated
1056 * broadcast domains.
1058 void zebra_evpn_if_cleanup(struct zebra_if
*zif
)
1061 struct zebra_evpn_es
*es
;
1063 if (bf_is_inited(zif
->vlan_bitmap
)) {
1064 bf_for_each_set_bit(zif
->vlan_bitmap
, vid
, IF_VLAN_BITMAP_MAX
)
1066 zebra_evpn_vl_mbr_deref(vid
, zif
);
1069 bf_free(zif
->vlan_bitmap
);
1072 /* Delete associated Ethernet Segment */
1073 es
= zif
->es_info
.es
;
1075 zebra_evpn_local_es_del(&es
);
1078 /*****************************************************************************
1079 * L2 NH/NHG Management
1080 * A L2 NH entry is programmed in the kernel for every ES-VTEP entry. This
1081 * NH is then added to the L2-ECMP-NHG associated with the ES.
1083 static uint32_t zebra_evpn_nhid_alloc(struct zebra_evpn_es
*es
)
1088 bf_assign_index(zmh_info
->nh_id_bitmap
, id
);
1094 nh_id
= id
| EVPN_NHG_ID_TYPE_BIT
;
1095 /* Add to NHG hash */
1097 if (!hash_get(zmh_info
->nhg_table
, es
, hash_alloc_intern
)) {
1098 bf_release_index(zmh_info
->nh_id_bitmap
, id
);
1102 nh_id
= id
| EVPN_NH_ID_TYPE_BIT
;
1108 static void zebra_evpn_nhid_free(uint32_t nh_id
, struct zebra_evpn_es
*es
)
1110 uint32_t id
= (nh_id
& EVPN_NH_ID_VAL_MASK
);
1116 hash_release(zmh_info
->nhg_table
, es
);
1120 bf_release_index(zmh_info
->nh_id_bitmap
, id
);
1123 static unsigned int zebra_evpn_nh_ip_hash_keymake(const void *p
)
1125 const struct zebra_evpn_l2_nh
*nh
= p
;
1127 return jhash_1word(nh
->vtep_ip
.s_addr
, 0);
1130 static bool zebra_evpn_nh_ip_cmp(const void *p1
, const void *p2
)
1132 const struct zebra_evpn_l2_nh
*nh1
= p1
;
1133 const struct zebra_evpn_l2_nh
*nh2
= p2
;
1135 if (nh1
== NULL
&& nh2
== NULL
)
1138 if (nh1
== NULL
|| nh2
== NULL
)
1141 return (nh1
->vtep_ip
.s_addr
== nh2
->vtep_ip
.s_addr
);
1144 static unsigned int zebra_evpn_nhg_hash_keymake(const void *p
)
1146 const struct zebra_evpn_es
*es
= p
;
1148 return jhash_1word(es
->nhg_id
, 0);
1151 static bool zebra_evpn_nhg_cmp(const void *p1
, const void *p2
)
1153 const struct zebra_evpn_es
*es1
= p1
;
1154 const struct zebra_evpn_es
*es2
= p2
;
1156 if (es1
== NULL
&& es2
== NULL
)
1159 if (es1
== NULL
|| es2
== NULL
)
1162 return (es1
->nhg_id
== es2
->nhg_id
);
1165 /* Lookup ES using the NHG id associated with it */
1166 static struct zebra_evpn_es
*zebra_evpn_nhg_find(uint32_t nhg_id
)
1168 struct zebra_evpn_es
*es
;
1169 struct zebra_evpn_es tmp
;
1171 tmp
.nhg_id
= nhg_id
;
1172 es
= hash_lookup(zmh_info
->nhg_table
, &tmp
);
1177 /* Returns TRUE if the NHG is associated with a local ES */
1178 bool zebra_evpn_nhg_is_local_es(uint32_t nhg_id
,
1179 struct zebra_evpn_es
**local_es
)
1181 struct zebra_evpn_es
*es
;
1183 es
= zebra_evpn_nhg_find(nhg_id
);
1184 if (es
&& (es
->flags
& ZEBRA_EVPNES_LOCAL
)) {
1193 /* update remote macs associated with the ES */
1194 static void zebra_evpn_nhg_mac_update(struct zebra_evpn_es
*es
)
1196 struct zebra_mac
*mac
;
1197 struct listnode
*node
;
1200 local_via_nw
= zebra_evpn_es_local_mac_via_network_port(es
);
1201 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
|| IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
1202 zlog_debug("mac update on es %s nhg %s", es
->esi_str
,
1203 (es
->flags
& ZEBRA_EVPNES_NHG_ACTIVE
)
1207 for (ALL_LIST_ELEMENTS_RO(es
->mac_list
, node
, mac
)) {
1208 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE
)
1209 || (local_via_nw
&& CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
)
1210 && zebra_evpn_mac_is_static(mac
))) {
1211 if (es
->flags
& ZEBRA_EVPNES_NHG_ACTIVE
) {
1212 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
1214 "%smac %pEA install via es %s nhg 0x%x",
1215 (mac
->flags
& ZEBRA_MAC_REMOTE
)
1218 &mac
->macaddr
, es
->esi_str
,
1220 zebra_evpn_rem_mac_install(
1221 mac
->zevpn
, mac
, false /*was_static*/);
1223 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
1225 "%smac %pEA un-install es %s",
1226 (mac
->flags
& ZEBRA_MAC_REMOTE
)
1229 &mac
->macaddr
, es
->esi_str
);
1230 zebra_evpn_rem_mac_uninstall(mac
->zevpn
, mac
,
1237 /* The MAC ECMP group is activated on the first VTEP */
1238 static void zebra_evpn_nhg_update(struct zebra_evpn_es
*es
)
1240 uint32_t nh_cnt
= 0;
1241 struct nh_grp nh_ids
[ES_VTEP_MAX_CNT
];
1242 struct zebra_evpn_es_vtep
*es_vtep
;
1243 struct listnode
*node
;
1248 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
1252 if (nh_cnt
>= ES_VTEP_MAX_CNT
)
1255 memset(&nh_ids
[nh_cnt
], 0, sizeof(struct nh_grp
));
1256 nh_ids
[nh_cnt
].id
= es_vtep
->nh
->nh_id
;
1261 if (IS_ZEBRA_DEBUG_EVPN_MH_NH
) {
1262 char nh_str
[ES_VTEP_LIST_STR_SZ
];
1267 for (i
= 0; i
< nh_cnt
; ++i
) {
1268 snprintf(nh_buf
, sizeof(nh_buf
), "%u ",
1270 strlcat(nh_str
, nh_buf
, sizeof(nh_str
));
1272 zlog_debug("es %s nhg %u add %s", es
->esi_str
,
1273 es
->nhg_id
, nh_str
);
1276 kernel_upd_mac_nhg(es
->nhg_id
, nh_cnt
, nh_ids
);
1277 if (!(es
->flags
& ZEBRA_EVPNES_NHG_ACTIVE
)) {
1278 es
->flags
|= ZEBRA_EVPNES_NHG_ACTIVE
;
1279 /* add backup NHG to the br-port */
1280 if ((es
->flags
& ZEBRA_EVPNES_LOCAL
))
1281 zebra_evpn_es_br_port_dplane_update(es
,
1283 zebra_evpn_nhg_mac_update(es
);
1286 if (es
->flags
& ZEBRA_EVPNES_NHG_ACTIVE
) {
1287 if (IS_ZEBRA_DEBUG_EVPN_MH_NH
)
1288 zlog_debug("es %s nhg %u del", es
->esi_str
,
1290 es
->flags
&= ~ZEBRA_EVPNES_NHG_ACTIVE
;
1291 /* remove backup NHG from the br-port */
1292 if ((es
->flags
& ZEBRA_EVPNES_LOCAL
))
1293 zebra_evpn_es_br_port_dplane_update(es
,
1295 zebra_evpn_nhg_mac_update(es
);
1296 kernel_del_mac_nhg(es
->nhg_id
);
1302 static void zebra_evpn_es_l2_nh_show_entry(struct zebra_evpn_l2_nh
*nh
,
1304 json_object
*json_array
)
1307 json_object
*json
= NULL
;
1309 json
= json_object_new_object();
1310 json_object_string_addf(json
, "vtep", "%pI4", &nh
->vtep_ip
);
1311 json_object_int_add(json
, "nhId", nh
->nh_id
);
1312 json_object_int_add(json
, "refCnt", nh
->ref_cnt
);
1314 json_object_array_add(json_array
, json
);
1316 vty_out(vty
, "%-16pI4 %-10u %u\n", &nh
->vtep_ip
, nh
->nh_id
,
1321 static void zebra_evpn_l2_nh_show_cb(struct hash_bucket
*bucket
, void *ctxt
)
1323 struct zebra_evpn_l2_nh
*nh
= (struct zebra_evpn_l2_nh
*)bucket
->data
;
1324 struct evpn_mh_show_ctx
*wctx
= (struct evpn_mh_show_ctx
*)ctxt
;
1326 zebra_evpn_es_l2_nh_show_entry(nh
, wctx
->vty
, wctx
->json
);
1329 void zebra_evpn_l2_nh_show(struct vty
*vty
, bool uj
)
1331 struct evpn_mh_show_ctx wctx
;
1332 json_object
*json_array
= NULL
;
1335 json_array
= json_object_new_array();
1337 vty_out(vty
, "%-16s %-10s %s\n", "VTEP", "NH id", "#ES");
1340 memset(&wctx
, 0, sizeof(wctx
));
1342 wctx
.json
= json_array
;
1344 hash_iterate(zmh_info
->nh_ip_table
, zebra_evpn_l2_nh_show_cb
, &wctx
);
1347 vty_json(vty
, json_array
);
1350 static struct zebra_evpn_l2_nh
*zebra_evpn_l2_nh_find(struct in_addr vtep_ip
)
1352 struct zebra_evpn_l2_nh
*nh
;
1353 struct zebra_evpn_l2_nh tmp
;
1355 tmp
.vtep_ip
.s_addr
= vtep_ip
.s_addr
;
1356 nh
= hash_lookup(zmh_info
->nh_ip_table
, &tmp
);
1361 static struct zebra_evpn_l2_nh
*zebra_evpn_l2_nh_alloc(struct in_addr vtep_ip
)
1363 struct zebra_evpn_l2_nh
*nh
;
1365 nh
= XCALLOC(MTYPE_L2_NH
, sizeof(*nh
));
1366 nh
->vtep_ip
= vtep_ip
;
1367 if (!hash_get(zmh_info
->nh_ip_table
, nh
, hash_alloc_intern
)) {
1368 XFREE(MTYPE_L2_NH
, nh
);
1372 nh
->nh_id
= zebra_evpn_nhid_alloc(NULL
);
1374 hash_release(zmh_info
->nh_ip_table
, nh
);
1375 XFREE(MTYPE_L2_NH
, nh
);
1379 /* install the NH in the dataplane */
1380 kernel_upd_mac_nh(nh
->nh_id
, nh
->vtep_ip
);
1385 static void zebra_evpn_l2_nh_free(struct zebra_evpn_l2_nh
*nh
)
1387 /* delete the NH from the dataplane */
1388 kernel_del_mac_nh(nh
->nh_id
);
1390 zebra_evpn_nhid_free(nh
->nh_id
, NULL
);
1391 hash_release(zmh_info
->nh_ip_table
, nh
);
1392 XFREE(MTYPE_L2_NH
, nh
);
1395 static void zebra_evpn_l2_nh_es_vtep_ref(struct zebra_evpn_es_vtep
*es_vtep
)
1400 es_vtep
->nh
= zebra_evpn_l2_nh_find(es_vtep
->vtep_ip
);
1402 es_vtep
->nh
= zebra_evpn_l2_nh_alloc(es_vtep
->vtep_ip
);
1405 zlog_warn("es %s vtep %pI4 nh ref failed", es_vtep
->es
->esi_str
,
1410 ++es_vtep
->nh
->ref_cnt
;
1412 if (IS_ZEBRA_DEBUG_EVPN_MH_NH
)
1413 zlog_debug("es %s vtep %pI4 nh %u ref %u", es_vtep
->es
->esi_str
,
1414 &es_vtep
->vtep_ip
, es_vtep
->nh
->nh_id
,
1415 es_vtep
->nh
->ref_cnt
);
1417 /* add the NH to the parent NHG */
1418 zebra_evpn_nhg_update(es_vtep
->es
);
1421 static void zebra_evpn_l2_nh_es_vtep_deref(struct zebra_evpn_es_vtep
*es_vtep
)
1423 struct zebra_evpn_l2_nh
*nh
= es_vtep
->nh
;
1432 if (IS_ZEBRA_DEBUG_EVPN_MH_NH
)
1433 zlog_debug("es %s vtep %pI4 nh %u deref %u",
1434 es_vtep
->es
->esi_str
, &es_vtep
->vtep_ip
, nh
->nh_id
,
1437 /* remove the NH from the parent NHG */
1438 zebra_evpn_nhg_update(es_vtep
->es
);
1440 /* uninstall the NH */
1442 zebra_evpn_l2_nh_free(nh
);
1445 /*****************************************************************************/
1446 /* Ethernet Segment Management
1447 * 1. Ethernet Segment is a collection of links attached to the same
1448 * server (MHD) or switch (MHN)
1449 * 2. An Ethernet Segment can span multiple PEs and is identified by the
1451 * 3. Zebra manages the local ESI configuration.
1452 * 4. It also maintains the aliasing that maps an ESI (local or remote)
1453 * to one or more PEs/VTEPs.
1454 * 5. remote ESs are added by BGP (on rxing EAD Type-1 routes)
1456 /* A list of remote VTEPs is maintained for each ES. This list includes -
1457 * 1. VTEPs for which we have imported the ESR i.e. ES-peers
1458 * 2. VTEPs that have an "active" ES-EVI VTEP i.e. EAD-per-ES and EAD-per-EVI
1459 * have been imported into one or more EVPNs
1461 static int zebra_evpn_es_vtep_cmp(void *p1
, void *p2
)
1463 const struct zebra_evpn_es_vtep
*es_vtep1
= p1
;
1464 const struct zebra_evpn_es_vtep
*es_vtep2
= p2
;
1466 return es_vtep1
->vtep_ip
.s_addr
- es_vtep2
->vtep_ip
.s_addr
;
1469 static struct zebra_evpn_es_vtep
*zebra_evpn_es_vtep_new(
1470 struct zebra_evpn_es
*es
, struct in_addr vtep_ip
)
1472 struct zebra_evpn_es_vtep
*es_vtep
;
1474 es_vtep
= XCALLOC(MTYPE_ZES_VTEP
, sizeof(*es_vtep
));
1477 es_vtep
->vtep_ip
.s_addr
= vtep_ip
.s_addr
;
1478 listnode_init(&es_vtep
->es_listnode
, es_vtep
);
1479 listnode_add_sort(es
->es_vtep_list
, &es_vtep
->es_listnode
);
1484 static void zebra_evpn_es_vtep_free(struct zebra_evpn_es_vtep
*es_vtep
)
1486 struct zebra_evpn_es
*es
= es_vtep
->es
;
1488 list_delete_node(es
->es_vtep_list
, &es_vtep
->es_listnode
);
1489 /* update the L2-NHG associated with the ES */
1490 zebra_evpn_l2_nh_es_vtep_deref(es_vtep
);
1491 XFREE(MTYPE_ZES_VTEP
, es_vtep
);
1495 /* check if VTEP is already part of the list */
1496 static struct zebra_evpn_es_vtep
*zebra_evpn_es_vtep_find(
1497 struct zebra_evpn_es
*es
, struct in_addr vtep_ip
)
1499 struct listnode
*node
= NULL
;
1500 struct zebra_evpn_es_vtep
*es_vtep
;
1502 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
1503 if (es_vtep
->vtep_ip
.s_addr
== vtep_ip
.s_addr
)
1509 /* flush all the dataplane br-port info associated with the ES */
1510 static bool zebra_evpn_es_br_port_dplane_clear(struct zebra_evpn_es
*es
)
1512 struct in_addr sph_filters
[ES_VTEP_MAX_CNT
];
1514 if (!(es
->flags
& ZEBRA_EVPNES_BR_PORT
))
1517 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
1518 zlog_debug("es %s br-port dplane clear", es
->esi_str
);
1520 memset(&sph_filters
, 0, sizeof(sph_filters
));
1521 dplane_br_port_update(es
->zif
->ifp
, false /* non_df */, 0, sph_filters
,
1522 0 /* backup_nhg_id */);
1527 zebra_evpn_es_br_port_dplane_update_needed(struct zebra_evpn_es
*es
)
1529 return (es
->flags
& ZEBRA_EVPNES_NON_DF
)
1530 || (es
->flags
& ZEBRA_EVPNES_NHG_ACTIVE
)
1531 || listcount(es
->es_vtep_list
);
1534 /* returns TRUE if dplane entry was updated */
1535 static bool zebra_evpn_es_br_port_dplane_update(struct zebra_evpn_es
*es
,
1538 uint32_t backup_nhg_id
;
1539 struct in_addr sph_filters
[ES_VTEP_MAX_CNT
];
1540 struct listnode
*node
= NULL
;
1541 struct zebra_evpn_es_vtep
*es_vtep
;
1542 uint32_t sph_filter_cnt
= 0;
1544 if (!(es
->flags
& ZEBRA_EVPNES_LOCAL
))
1545 return zebra_evpn_es_br_port_dplane_clear(es
);
1547 /* If the ES is not a bridge port there is nothing
1550 if (!(es
->flags
& ZEBRA_EVPNES_BR_PORT
))
1553 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
1554 zlog_debug("es %s br-port dplane update by %s", es
->esi_str
,
1556 backup_nhg_id
= (es
->flags
& ZEBRA_EVPNES_NHG_ACTIVE
) ? es
->nhg_id
: 0;
1558 memset(&sph_filters
, 0, sizeof(sph_filters
));
1559 if (es
->flags
& ZEBRA_EVPNES_BYPASS
) {
1560 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
1562 "es %s SPH filter disabled as it is in bypass",
1565 if (listcount(es
->es_vtep_list
) > ES_VTEP_MAX_CNT
) {
1566 zlog_warn("es %s vtep count %d exceeds filter cnt %d",
1567 es
->esi_str
, listcount(es
->es_vtep_list
),
1570 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
,
1573 & ZEBRA_EVPNES_VTEP_DEL_IN_PROG
)
1575 sph_filters
[sph_filter_cnt
] = es_vtep
->vtep_ip
;
1581 dplane_br_port_update(es
->zif
->ifp
, !!(es
->flags
& ZEBRA_EVPNES_NON_DF
),
1582 sph_filter_cnt
, sph_filters
, backup_nhg_id
);
1587 /* returns TRUE if dplane entry was updated */
1588 static bool zebra_evpn_es_df_change(struct zebra_evpn_es
*es
, bool new_non_df
,
1589 const char *caller
, const char *reason
)
1593 old_non_df
= !!(es
->flags
& ZEBRA_EVPNES_NON_DF
);
1595 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
1596 zlog_debug("df-change es %s %s to %s; %s: %s", es
->esi_str
,
1597 old_non_df
? "non-df" : "df",
1598 new_non_df
? "non-df" : "df", caller
, reason
);
1600 if (old_non_df
== new_non_df
)
1604 es
->flags
|= ZEBRA_EVPNES_NON_DF
;
1606 es
->flags
&= ~ZEBRA_EVPNES_NON_DF
;
1608 /* update non-DF block filter in the dataplane */
1609 return zebra_evpn_es_br_port_dplane_update(es
, __func__
);
1613 /* returns TRUE if dplane entry was updated */
1614 static bool zebra_evpn_es_run_df_election(struct zebra_evpn_es
*es
,
1617 struct listnode
*node
= NULL
;
1618 struct zebra_evpn_es_vtep
*es_vtep
;
1619 bool new_non_df
= false;
1621 /* If the ES is not ready (i.e. not completely configured) there
1622 * is no need to setup the BUM block filter
1624 if (!(es
->flags
& ZEBRA_EVPNES_LOCAL
)
1625 || (es
->flags
& ZEBRA_EVPNES_BYPASS
)
1626 || !zmh_info
->es_originator_ip
.s_addr
)
1627 return zebra_evpn_es_df_change(es
, new_non_df
, caller
,
1630 /* if oper-state is down DF filtering must be on. when the link comes
1631 * up again dataplane should block BUM till FRR has had the chance
1632 * to run DF election again
1634 if (!(es
->flags
& ZEBRA_EVPNES_OPER_UP
)) {
1636 return zebra_evpn_es_df_change(es
, new_non_df
, caller
,
1640 /* ES was just created; we need to wait for the peers to rx the
1641 * our Type-4 routes and for the switch to import the peers' Type-4
1644 if (es
->df_delay_timer
) {
1646 return zebra_evpn_es_df_change(es
, new_non_df
, caller
,
1650 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
1651 /* Only VTEPs that have advertised the ESR can participate
1654 if (!(es_vtep
->flags
& ZEBRA_EVPNES_VTEP_RXED_ESR
))
1657 /* If the DF alg is not the same we should fall back to
1658 * service-carving. But as service-carving is not supported
1659 * we will stop forwarding BUM
1661 if (es_vtep
->df_alg
!= EVPN_MH_DF_ALG_PREF
) {
1666 /* Peer VTEP wins DF election if -
1667 * the peer-VTEP has higher preference (or)
1668 * the pref is the same but peer's IP address is lower
1670 if ((es_vtep
->df_pref
> es
->df_pref
)
1671 || ((es_vtep
->df_pref
== es
->df_pref
)
1672 && (es_vtep
->vtep_ip
.s_addr
1673 < zmh_info
->es_originator_ip
.s_addr
))) {
1679 return zebra_evpn_es_df_change(es
, new_non_df
, caller
, "elected");
1682 static void zebra_evpn_es_vtep_add(struct zebra_evpn_es
*es
,
1683 struct in_addr vtep_ip
, bool esr_rxed
,
1684 uint8_t df_alg
, uint16_t df_pref
)
1686 struct zebra_evpn_es_vtep
*es_vtep
;
1688 bool dplane_updated
= false;
1690 es_vtep
= zebra_evpn_es_vtep_find(es
, vtep_ip
);
1693 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
1694 zlog_debug("es %s vtep %pI4 add",
1695 es
->esi_str
, &vtep_ip
);
1696 es_vtep
= zebra_evpn_es_vtep_new(es
, vtep_ip
);
1697 /* update the L2-NHG associated with the ES */
1698 zebra_evpn_l2_nh_es_vtep_ref(es_vtep
);
1701 old_esr_rxed
= !!(es_vtep
->flags
& ZEBRA_EVPNES_VTEP_RXED_ESR
);
1702 if ((old_esr_rxed
!= esr_rxed
) || (es_vtep
->df_alg
!= df_alg
)
1703 || (es_vtep
->df_pref
!= df_pref
)) {
1704 /* If any of the DF election params changed we need to re-run
1708 es_vtep
->flags
|= ZEBRA_EVPNES_VTEP_RXED_ESR
;
1710 es_vtep
->flags
&= ~ZEBRA_EVPNES_VTEP_RXED_ESR
;
1711 es_vtep
->df_alg
= df_alg
;
1712 es_vtep
->df_pref
= df_pref
;
1713 dplane_updated
= zebra_evpn_es_run_df_election(es
, __func__
);
1715 /* add the vtep to the SPH list */
1716 if (!dplane_updated
&& (es
->flags
& ZEBRA_EVPNES_LOCAL
))
1717 zebra_evpn_es_br_port_dplane_update(es
, __func__
);
1720 static void zebra_evpn_es_vtep_del(struct zebra_evpn_es
*es
,
1721 struct in_addr vtep_ip
)
1723 struct zebra_evpn_es_vtep
*es_vtep
;
1724 bool dplane_updated
= false;
1726 es_vtep
= zebra_evpn_es_vtep_find(es
, vtep_ip
);
1729 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
1730 zlog_debug("es %s vtep %pI4 del",
1731 es
->esi_str
, &vtep_ip
);
1732 es_vtep
->flags
|= ZEBRA_EVPNES_VTEP_DEL_IN_PROG
;
1733 if (es_vtep
->flags
& ZEBRA_EVPNES_VTEP_RXED_ESR
) {
1734 es_vtep
->flags
&= ~ZEBRA_EVPNES_VTEP_RXED_ESR
;
1736 zebra_evpn_es_run_df_election(es
, __func__
);
1738 /* remove the vtep from the SPH list */
1739 if (!dplane_updated
&& (es
->flags
& ZEBRA_EVPNES_LOCAL
))
1740 zebra_evpn_es_br_port_dplane_update(es
, __func__
);
1741 zebra_evpn_es_vtep_free(es_vtep
);
1745 /* compare ES-IDs for the global ES RB tree */
1746 static int zebra_es_rb_cmp(const struct zebra_evpn_es
*es1
,
1747 const struct zebra_evpn_es
*es2
)
1749 return memcmp(&es1
->esi
, &es2
->esi
, ESI_BYTES
);
1751 RB_GENERATE(zebra_es_rb_head
, zebra_evpn_es
, rb_node
, zebra_es_rb_cmp
);
1754 struct zebra_evpn_es
*zebra_evpn_es_find(const esi_t
*esi
)
1756 struct zebra_evpn_es tmp
;
1758 memcpy(&tmp
.esi
, esi
, sizeof(esi_t
));
1759 return RB_FIND(zebra_es_rb_head
, &zmh_info
->es_rb_tree
, &tmp
);
1762 /* A new local es is created when a local-es-id and sysmac is configured
1763 * against an interface.
1765 static struct zebra_evpn_es
*zebra_evpn_es_new(const esi_t
*esi
)
1767 struct zebra_evpn_es
*es
;
1769 if (!memcmp(esi
, zero_esi
, sizeof(esi_t
)))
1772 es
= XCALLOC(MTYPE_ZES
, sizeof(struct zebra_evpn_es
));
1775 memcpy(&es
->esi
, esi
, sizeof(esi_t
));
1776 esi_to_str(&es
->esi
, es
->esi_str
, sizeof(es
->esi_str
));
1778 /* Add to rb_tree */
1779 if (RB_INSERT(zebra_es_rb_head
, &zmh_info
->es_rb_tree
, es
)) {
1780 XFREE(MTYPE_ZES
, es
);
1784 /* Initialise the ES-EVI list */
1785 es
->es_evi_list
= list_new();
1786 listset_app_node_mem(es
->es_evi_list
);
1788 /* Initialise the VTEP list */
1789 es
->es_vtep_list
= list_new();
1790 listset_app_node_mem(es
->es_vtep_list
);
1791 es
->es_vtep_list
->cmp
= zebra_evpn_es_vtep_cmp
;
1793 /* mac entries associated with the ES */
1794 es
->mac_list
= list_new();
1795 listset_app_node_mem(es
->mac_list
);
1798 es
->nhg_id
= zebra_evpn_nhid_alloc(es
);
1800 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
1801 zlog_debug("es %s nhg %u new", es
->esi_str
, es
->nhg_id
);
1806 /* Free a given ES -
1807 * This just frees appropriate memory, caller should have taken other
1810 static void zebra_evpn_es_free(struct zebra_evpn_es
**esp
)
1812 struct zebra_evpn_es
*es
= *esp
;
1814 /* If the ES has a local or remote reference it cannot be freed.
1815 * Free is also prevented if there are MAC entries referencing
1818 if ((es
->flags
& (ZEBRA_EVPNES_LOCAL
| ZEBRA_EVPNES_REMOTE
)) ||
1819 listcount(es
->mac_list
))
1822 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
1823 zlog_debug("es %s free", es
->esi_str
);
1825 /* If the NHG is still installed uninstall it and free the id */
1826 if (es
->flags
& ZEBRA_EVPNES_NHG_ACTIVE
) {
1827 es
->flags
&= ~ZEBRA_EVPNES_NHG_ACTIVE
;
1828 kernel_del_mac_nhg(es
->nhg_id
);
1830 zebra_evpn_nhid_free(es
->nhg_id
, es
);
1832 /* cleanup resources maintained against the ES */
1833 list_delete(&es
->es_evi_list
);
1834 list_delete(&es
->es_vtep_list
);
1835 list_delete(&es
->mac_list
);
1837 /* remove from the VNI-ESI rb tree */
1838 RB_REMOVE(zebra_es_rb_head
, &zmh_info
->es_rb_tree
, es
);
1840 XFREE(MTYPE_ZES
, es
);
1845 /* Inform BGP about local ES addition */
1846 static int zebra_evpn_es_send_add_to_client(struct zebra_evpn_es
*es
)
1848 struct zserv
*client
;
1853 client
= zserv_find_client(ZEBRA_ROUTE_BGP
, 0);
1854 /* BGP may not be running. */
1858 s
= stream_new(ZEBRA_MAX_PACKET_SIZ
);
1860 zclient_create_header(s
, ZEBRA_LOCAL_ES_ADD
, zebra_vrf_get_evpn_id());
1861 stream_put(s
, &es
->esi
, sizeof(esi_t
));
1862 stream_put_ipv4(s
, zmh_info
->es_originator_ip
.s_addr
);
1863 oper_up
= !!(es
->flags
& ZEBRA_EVPNES_OPER_UP
);
1864 stream_putc(s
, oper_up
);
1865 stream_putw(s
, es
->df_pref
);
1866 bypass
= !!(es
->flags
& ZEBRA_EVPNES_BYPASS
);
1867 stream_putc(s
, bypass
);
1869 /* Write packet size. */
1870 stream_putw_at(s
, 0, stream_get_endp(s
));
1872 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
1874 "send add local es %s %pI4 active %u df_pref %u%s to %s",
1875 es
->esi_str
, &zmh_info
->es_originator_ip
, oper_up
,
1876 es
->df_pref
, bypass
? " bypass" : "",
1877 zebra_route_string(client
->proto
));
1879 client
->local_es_add_cnt
++;
1880 return zserv_send_message(client
, s
);
1883 /* Inform BGP about local ES deletion */
1884 static int zebra_evpn_es_send_del_to_client(struct zebra_evpn_es
*es
)
1886 struct zserv
*client
;
1889 client
= zserv_find_client(ZEBRA_ROUTE_BGP
, 0);
1890 /* BGP may not be running. */
1894 s
= stream_new(ZEBRA_MAX_PACKET_SIZ
);
1897 zclient_create_header(s
, ZEBRA_LOCAL_ES_DEL
, zebra_vrf_get_evpn_id());
1898 stream_put(s
, &es
->esi
, sizeof(esi_t
));
1900 /* Write packet size. */
1901 stream_putw_at(s
, 0, stream_get_endp(s
));
1903 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
1904 zlog_debug("send del local es %s to %s", es
->esi_str
,
1905 zebra_route_string(client
->proto
));
1907 client
->local_es_del_cnt
++;
1908 return zserv_send_message(client
, s
);
1911 static void zebra_evpn_es_re_eval_send_to_client(struct zebra_evpn_es
*es
,
1912 bool es_evi_re_reval
)
1916 struct listnode
*node
;
1917 struct zebra_evpn_es_evi
*es_evi
;
1919 old_ready
= !!(es
->flags
& ZEBRA_EVPNES_READY_FOR_BGP
);
1921 if ((es
->flags
& ZEBRA_EVPNES_LOCAL
) &&
1922 zmh_info
->es_originator_ip
.s_addr
)
1923 es
->flags
|= ZEBRA_EVPNES_READY_FOR_BGP
;
1925 es
->flags
&= ~ZEBRA_EVPNES_READY_FOR_BGP
;
1927 new_ready
= !!(es
->flags
& ZEBRA_EVPNES_READY_FOR_BGP
);
1928 if (old_ready
== new_ready
)
1932 zebra_evpn_es_send_add_to_client(es
);
1934 zebra_evpn_es_send_del_to_client(es
);
1936 /* re-eval associated EVIs */
1937 if (es_evi_re_reval
) {
1938 for (ALL_LIST_ELEMENTS_RO(es
->es_evi_list
, node
, es_evi
)) {
1939 if (!(es_evi
->flags
& ZEBRA_EVPNES_EVI_LOCAL
))
1941 zebra_evpn_es_evi_re_eval_send_to_client(es_evi
);
1946 void zebra_evpn_es_send_all_to_client(bool add
)
1948 struct listnode
*es_node
;
1949 struct listnode
*evi_node
;
1950 struct zebra_evpn_es
*es
;
1951 struct zebra_evpn_es_evi
*es_evi
;
1956 for (ALL_LIST_ELEMENTS_RO(zmh_info
->local_es_list
, es_node
, es
)) {
1957 if (es
->flags
& ZEBRA_EVPNES_READY_FOR_BGP
) {
1959 zebra_evpn_es_send_add_to_client(es
);
1960 for (ALL_LIST_ELEMENTS_RO(es
->es_evi_list
,
1961 evi_node
, es_evi
)) {
1962 if (!(es_evi
->flags
&
1963 ZEBRA_EVPNES_EVI_READY_FOR_BGP
))
1967 zebra_evpn_es_evi_send_to_client(
1971 zebra_evpn_es_evi_send_to_client(
1976 zebra_evpn_es_send_del_to_client(es
);
1981 /* walk the vlan bitmap associated with the zif and create or delete
1982 * es_evis for all vlans associated with a VNI.
1983 * XXX: This API is really expensive. optimize later if possible.
1985 static void zebra_evpn_es_setup_evis(struct zebra_evpn_es
*es
)
1987 struct zebra_if
*zif
= es
->zif
;
1989 struct zebra_evpn_access_bd
*acc_bd
;
1991 if (!bf_is_inited(zif
->vlan_bitmap
))
1994 bf_for_each_set_bit(zif
->vlan_bitmap
, vid
, IF_VLAN_BITMAP_MAX
) {
1995 acc_bd
= zebra_evpn_acc_vl_find(vid
);
1997 zebra_evpn_local_es_evi_add(es
, acc_bd
->zevpn
);
2001 static void zebra_evpn_flush_local_mac(struct zebra_mac
*mac
,
2002 struct interface
*ifp
)
2004 struct zebra_if
*zif
;
2005 struct interface
*br_ifp
;
2009 br_ifp
= zif
->brslave_info
.br_if
;
2013 if (mac
->zevpn
->vxlan_if
) {
2014 zif
= mac
->zevpn
->vxlan_if
->info
;
2015 vid
= zif
->l2info
.vxl
.access_vlan
;
2020 /* delete the local mac from the dataplane */
2021 dplane_local_mac_del(ifp
, br_ifp
, vid
, &mac
->macaddr
);
2022 /* delete the local mac in zebra */
2023 zebra_evpn_del_local_mac(mac
->zevpn
, mac
, true);
2026 static void zebra_evpn_es_flush_local_macs(struct zebra_evpn_es
*es
,
2027 struct interface
*ifp
, bool add
)
2029 struct zebra_mac
*mac
;
2030 struct listnode
*node
;
2031 struct listnode
*nnode
;
2033 for (ALL_LIST_ELEMENTS(es
->mac_list
, node
, nnode
, mac
)) {
2034 if (!CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
))
2037 /* If ES is being attached/detached from the access port we
2038 * need to clear local activity and peer activity and start
2040 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
2041 zlog_debug("VNI %u mac %pEA update; local ES %s %s",
2044 es
->esi_str
, add
? "add" : "del");
2045 zebra_evpn_flush_local_mac(mac
, ifp
);
2049 void zebra_evpn_es_local_br_port_update(struct zebra_if
*zif
)
2051 struct zebra_evpn_es
*es
= zif
->es_info
.es
;
2052 bool old_br_port
= !!(es
->flags
& ZEBRA_EVPNES_BR_PORT
);
2055 if (zif
->brslave_info
.bridge_ifindex
!= IFINDEX_INTERNAL
)
2056 es
->flags
|= ZEBRA_EVPNES_BR_PORT
;
2058 es
->flags
&= ~ZEBRA_EVPNES_BR_PORT
;
2060 new_br_port
= !!(es
->flags
& ZEBRA_EVPNES_BR_PORT
);
2061 if (old_br_port
== new_br_port
)
2064 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2065 zlog_debug("es %s br_port change old %u new %u", es
->esi_str
,
2066 old_br_port
, new_br_port
);
2068 /* update the dataplane br_port attrs */
2069 if (new_br_port
&& zebra_evpn_es_br_port_dplane_update_needed(es
))
2070 zebra_evpn_es_br_port_dplane_update(es
, __func__
);
2073 /* On config of first local-ES turn off DAD */
2074 static void zebra_evpn_mh_dup_addr_detect_off(void)
2076 struct zebra_vrf
*zvrf
;
2080 if (zmh_info
->flags
& ZEBRA_EVPN_MH_DUP_ADDR_DETECT_OFF
)
2083 zvrf
= zebra_vrf_get_evpn();
2085 zmh_info
->flags
|= ZEBRA_EVPN_MH_DUP_ADDR_DETECT_OFF
;
2089 old_detect
= zebra_evpn_do_dup_addr_detect(zvrf
);
2090 zmh_info
->flags
|= ZEBRA_EVPN_MH_DUP_ADDR_DETECT_OFF
;
2091 new_detect
= zebra_evpn_do_dup_addr_detect(zvrf
);
2093 if (old_detect
&& !new_detect
) {
2094 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2096 "evpn-mh config caused DAD addr detect chg from %s to %s",
2097 old_detect
? "on" : "off",
2098 new_detect
? "on" : "off");
2099 zebra_vxlan_clear_dup_detect_vni_all(zvrf
);
2103 /* On config of first local-ES turn off advertisement of STALE/DELAY/PROBE
2106 static void zebra_evpn_mh_advertise_reach_neigh_only(void)
2108 if (zmh_info
->flags
& ZEBRA_EVPN_MH_ADV_REACHABLE_NEIGH_ONLY
)
2111 zmh_info
->flags
|= ZEBRA_EVPN_MH_ADV_REACHABLE_NEIGH_ONLY
;
2112 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2113 zlog_debug("evpn-mh: only REACHABLE neigh advertised");
2115 /* XXX - if STALE/DELAY/PROBE neighs were previously advertised we
2116 * need to withdraw them
2120 /* On config of first local-ES turn on advertisement of local SVI-MAC */
2121 static void zebra_evpn_mh_advertise_svi_mac(void)
2123 if (zmh_info
->flags
& ZEBRA_EVPN_MH_ADV_SVI_MAC
)
2126 zmh_info
->flags
|= ZEBRA_EVPN_MH_ADV_SVI_MAC
;
2127 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2128 zlog_debug("evpn-mh: advertise SVI MAC");
2130 /* walk through all SVIs and see if we need to advertise the MAC */
2131 zebra_evpn_acc_vl_adv_svi_mac_all();
2134 static void zebra_evpn_es_df_delay_exp_cb(struct thread
*t
)
2136 struct zebra_evpn_es
*es
;
2140 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2141 zlog_debug("es %s df-delay expired", es
->esi_str
);
2143 zebra_evpn_es_run_df_election(es
, __func__
);
2146 /* currently there is no global config to turn on MH instead we use
2147 * the addition of the first local Ethernet Segment as the trigger to
2148 * init MH specific processing
2150 static void zebra_evpn_mh_on_first_local_es(void)
2152 zebra_evpn_mh_dup_addr_detect_off();
2153 zebra_evpn_mh_advertise_reach_neigh_only();
2154 zebra_evpn_mh_advertise_svi_mac();
2157 static void zebra_evpn_es_local_info_set(struct zebra_evpn_es
*es
,
2158 struct zebra_if
*zif
)
2160 if (es
->flags
& ZEBRA_EVPNES_LOCAL
)
2163 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2164 zlog_debug("local es %s add; nhg %u if %s", es
->esi_str
,
2165 es
->nhg_id
, zif
->ifp
->name
);
2167 zebra_evpn_mh_on_first_local_es();
2169 es
->flags
|= ZEBRA_EVPNES_LOCAL
;
2170 listnode_init(&es
->local_es_listnode
, es
);
2171 listnode_add(zmh_info
->local_es_list
, &es
->local_es_listnode
);
2173 /* attach es to interface */
2174 zif
->es_info
.es
= es
;
2175 es
->df_pref
= zif
->es_info
.df_pref
? zif
->es_info
.df_pref
2176 : EVPN_MH_DF_PREF_DEFAULT
;
2178 /* attach interface to es */
2180 if (if_is_operative(zif
->ifp
))
2181 es
->flags
|= ZEBRA_EVPNES_OPER_UP
;
2183 if (zif
->brslave_info
.bridge_ifindex
!= IFINDEX_INTERNAL
)
2184 es
->flags
|= ZEBRA_EVPNES_BR_PORT
;
2186 /* inherit the bypass flag from the interface */
2187 if (zif
->flags
& ZIF_FLAG_LACP_BYPASS
)
2188 es
->flags
|= ZEBRA_EVPNES_BYPASS
;
2190 /* setup base-vni if one doesn't already exist; the ES will get sent
2191 * to BGP as a part of that process
2193 if (!zmh_info
->es_base_evpn
)
2194 zebra_evpn_es_get_one_base_evpn();
2196 /* send notification to bgp */
2197 zebra_evpn_es_re_eval_send_to_client(es
,
2198 false /* es_evi_re_reval */);
2200 /* Start the DF delay timer on the local ES */
2201 if (!es
->df_delay_timer
)
2202 thread_add_timer(zrouter
.master
, zebra_evpn_es_df_delay_exp_cb
,
2203 es
, ZEBRA_EVPN_MH_DF_DELAY_TIME
,
2204 &es
->df_delay_timer
);
2206 /* See if the local VTEP can function as DF on the ES */
2207 if (!zebra_evpn_es_run_df_election(es
, __func__
)) {
2208 /* check if the dplane entry needs to be re-programmed as a
2209 * result of some thing other than DF status change
2211 if (zebra_evpn_es_br_port_dplane_update_needed(es
))
2212 zebra_evpn_es_br_port_dplane_update(es
, __func__
);
2216 /* Setup ES-EVIs for all VxLAN stretched VLANs associated with
2219 zebra_evpn_es_setup_evis(es
);
2220 /* if there any local macs referring to the ES as dest we
2221 * need to clear the contents and start over
2223 zebra_evpn_es_flush_local_macs(es
, zif
->ifp
, true);
2225 /* inherit EVPN protodown flags on the access port */
2226 zebra_evpn_mh_update_protodown_es(es
, true /*resync_dplane*/);
2229 static void zebra_evpn_es_local_info_clear(struct zebra_evpn_es
**esp
)
2231 struct zebra_if
*zif
;
2232 struct zebra_evpn_es
*es
= *esp
;
2233 bool dplane_updated
= false;
2235 if (!(es
->flags
& ZEBRA_EVPNES_LOCAL
))
2240 /* if there any local macs referring to the ES as dest we
2241 * need to clear the contents and start over
2243 zebra_evpn_es_flush_local_macs(es
, zif
->ifp
, false);
2245 es
->flags
&= ~(ZEBRA_EVPNES_LOCAL
| ZEBRA_EVPNES_READY_FOR_BGP
);
2247 THREAD_OFF(es
->df_delay_timer
);
2249 /* clear EVPN protodown flags on the access port */
2250 zebra_evpn_mh_clear_protodown_es(es
);
2252 /* remove the DF filter */
2253 dplane_updated
= zebra_evpn_es_run_df_election(es
, __func__
);
2255 /* flush the BUM filters and backup NHG */
2256 if (!dplane_updated
)
2257 zebra_evpn_es_br_port_dplane_clear(es
);
2259 /* clear the es from the parent interface */
2260 zif
->es_info
.es
= NULL
;
2263 /* clear all local flags associated with the ES */
2264 es
->flags
&= ~(ZEBRA_EVPNES_OPER_UP
| ZEBRA_EVPNES_BR_PORT
2265 | ZEBRA_EVPNES_BYPASS
);
2267 /* remove from the ES list */
2268 list_delete_node(zmh_info
->local_es_list
, &es
->local_es_listnode
);
2270 /* free up the ES if there is no remote reference */
2271 zebra_evpn_es_free(esp
);
2274 /* Delete an ethernet segment and inform BGP */
2275 static void zebra_evpn_local_es_del(struct zebra_evpn_es
**esp
)
2277 struct zebra_evpn_es_evi
*es_evi
;
2278 struct listnode
*node
= NULL
;
2279 struct listnode
*nnode
= NULL
;
2280 struct zebra_if
*zif
;
2281 struct zebra_evpn_es
*es
= *esp
;
2283 if (!CHECK_FLAG(es
->flags
, ZEBRA_EVPNES_LOCAL
))
2286 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
) {
2288 zlog_debug("local es %s del; nhg %u if %s", es
->esi_str
,
2289 es
->nhg_id
, zif
? zif
->ifp
->name
: "-");
2292 /* remove all ES-EVIs associated with the ES */
2293 for (ALL_LIST_ELEMENTS(es
->es_evi_list
, node
, nnode
, es_evi
))
2294 zebra_evpn_local_es_evi_do_del(es_evi
);
2296 /* send a del if the ES had been sent to BGP earlier */
2297 if (es
->flags
& ZEBRA_EVPNES_READY_FOR_BGP
)
2298 zebra_evpn_es_send_del_to_client(es
);
2300 zebra_evpn_es_local_info_clear(esp
);
2303 /* eval remote info associated with the ES */
2304 static void zebra_evpn_es_remote_info_re_eval(struct zebra_evpn_es
**esp
)
2306 struct zebra_evpn_es
*es
= *esp
;
2308 /* if there are remote VTEPs the ES-EVI is classified as "remote" */
2309 if (listcount(es
->es_vtep_list
)) {
2310 if (!(es
->flags
& ZEBRA_EVPNES_REMOTE
)) {
2311 es
->flags
|= ZEBRA_EVPNES_REMOTE
;
2312 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2313 zlog_debug("remote es %s add; nhg %u",
2314 es
->esi_str
, es
->nhg_id
);
2317 if (es
->flags
& ZEBRA_EVPNES_REMOTE
) {
2318 es
->flags
&= ~ZEBRA_EVPNES_REMOTE
;
2319 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2320 zlog_debug("remote es %s del; nhg %u",
2321 es
->esi_str
, es
->nhg_id
);
2322 zebra_evpn_es_free(esp
);
2327 /* A new local es is created when a local-es-id and sysmac is configured
2328 * against an interface.
2330 static int zebra_evpn_local_es_update(struct zebra_if
*zif
, esi_t
*esi
)
2332 struct zebra_evpn_es
*old_es
= zif
->es_info
.es
;
2333 struct zebra_evpn_es
*es
;
2335 memcpy(&zif
->es_info
.esi
, esi
, sizeof(*esi
));
2336 if (old_es
&& !memcmp(&old_es
->esi
, esi
, sizeof(*esi
)))
2337 /* dup - nothing to be done */
2340 /* release the old_es against the zif */
2342 zebra_evpn_local_es_del(&old_es
);
2344 es
= zebra_evpn_es_find(esi
);
2346 /* if it exists against another interface flag an error */
2347 if (es
->zif
&& es
->zif
!= zif
) {
2348 memset(&zif
->es_info
.esi
, 0, sizeof(*esi
));
2353 es
= zebra_evpn_es_new(esi
);
2357 zebra_evpn_es_local_info_set(es
, zif
);
2362 static int zebra_evpn_type3_esi_update(struct zebra_if
*zif
, uint32_t lid
,
2363 struct ethaddr
*sysmac
)
2365 struct zebra_evpn_es
*old_es
= zif
->es_info
.es
;
2368 int field_bytes
= 0;
2370 /* Complete config of the ES-ID bootstraps the ES */
2371 if (!lid
|| is_zero_mac(sysmac
)) {
2373 memset(&zif
->es_info
.esi
, 0, sizeof(zif
->es_info
.esi
));
2374 /* if in ES is attached to zif delete it */
2376 zebra_evpn_local_es_del(&old_es
);
2380 /* build 10-byte type-3-ESI -
2381 * Type(1-byte), MAC(6-bytes), ES-LID (3-bytes)
2384 esi
.val
[offset
] = ESI_TYPE_MAC
;
2385 offset
+= field_bytes
;
2387 field_bytes
= ETH_ALEN
;
2388 memcpy(&esi
.val
[offset
], (uint8_t *)sysmac
, field_bytes
);
2389 offset
+= field_bytes
;
2391 esi
.val
[offset
++] = (uint8_t)(lid
>> 16);
2392 esi
.val
[offset
++] = (uint8_t)(lid
>> 8);
2393 esi
.val
[offset
++] = (uint8_t)lid
;
2395 return zebra_evpn_local_es_update(zif
, &esi
);
2398 int zebra_evpn_remote_es_del(const esi_t
*esi
, struct in_addr vtep_ip
)
2400 char buf
[ESI_STR_LEN
];
2401 struct zebra_evpn_es
*es
;
2403 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2404 zlog_debug("remote es %s vtep %pI4 del",
2405 esi_to_str(esi
, buf
, sizeof(buf
)), &vtep_ip
);
2407 es
= zebra_evpn_es_find(esi
);
2409 zlog_warn("remote es %s vtep %pI4 del failed, es missing",
2410 esi_to_str(esi
, buf
, sizeof(buf
)), &vtep_ip
);
2414 zebra_evpn_es_vtep_del(es
, vtep_ip
);
2415 zebra_evpn_es_remote_info_re_eval(&es
);
2420 /* force delete a remote ES on the way down */
2421 static void zebra_evpn_remote_es_flush(struct zebra_evpn_es
**esp
)
2423 struct zebra_evpn_es_vtep
*es_vtep
;
2424 struct listnode
*node
;
2425 struct listnode
*nnode
;
2426 struct zebra_evpn_es
*es
= *esp
;
2428 for (ALL_LIST_ELEMENTS(es
->es_vtep_list
, node
, nnode
, es_vtep
)) {
2429 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2430 zlog_debug("es %s vtep %pI4 flush",
2433 zebra_evpn_es_vtep_free(es_vtep
);
2435 zebra_evpn_es_remote_info_re_eval(esp
);
2438 int zebra_evpn_remote_es_add(const esi_t
*esi
, struct in_addr vtep_ip
,
2439 bool esr_rxed
, uint8_t df_alg
, uint16_t df_pref
)
2441 char buf
[ESI_STR_LEN
];
2442 struct zebra_evpn_es
*es
;
2444 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2445 zlog_debug("remote es %s vtep %pI4 add %s df_alg %d df_pref %d",
2446 esi_to_str(esi
, buf
, sizeof(buf
)),
2447 &vtep_ip
, esr_rxed
? "esr" : "", df_alg
,
2450 es
= zebra_evpn_es_find(esi
);
2452 es
= zebra_evpn_es_new(esi
);
2455 "remote es %s vtep %pI4 add failed, es missing",
2456 esi_to_str(esi
, buf
, sizeof(buf
)), &vtep_ip
);
2461 if (df_alg
!= EVPN_MH_DF_ALG_PREF
)
2463 "remote es %s vtep %pI4 add %s with unsupported df_alg %d",
2464 esi_to_str(esi
, buf
, sizeof(buf
)), &vtep_ip
,
2465 esr_rxed
? "esr" : "", df_alg
);
2467 zebra_evpn_es_vtep_add(es
, vtep_ip
, esr_rxed
, df_alg
, df_pref
);
2468 zebra_evpn_es_remote_info_re_eval(&es
);
2473 void zebra_evpn_proc_remote_es(ZAPI_HANDLER_ARGS
)
2476 struct in_addr vtep_ip
;
2479 if (!is_evpn_enabled()) {
2481 "%s: EVPN not enabled yet we received a es_add zapi call",
2486 memset(&esi
, 0, sizeof(esi_t
));
2489 STREAM_GET(&esi
, s
, sizeof(esi_t
));
2490 STREAM_GET(&vtep_ip
.s_addr
, s
, sizeof(vtep_ip
.s_addr
));
2492 if (hdr
->command
== ZEBRA_REMOTE_ES_VTEP_ADD
) {
2493 uint32_t zapi_flags
;
2498 STREAM_GETL(s
, zapi_flags
);
2499 esr_rxed
= (zapi_flags
& ZAPI_ES_VTEP_FLAG_ESR_RXED
) ? true
2501 STREAM_GETC(s
, df_alg
);
2502 STREAM_GETW(s
, df_pref
);
2503 zebra_rib_queue_evpn_rem_es_add(&esi
, &vtep_ip
, esr_rxed
,
2506 zebra_rib_queue_evpn_rem_es_del(&esi
, &vtep_ip
);
2513 void zebra_evpn_es_mac_deref_entry(struct zebra_mac
*mac
)
2515 struct zebra_evpn_es
*es
= mac
->es
;
2521 list_delete_node(es
->mac_list
, &mac
->es_listnode
);
2522 if (!listcount(es
->mac_list
))
2523 zebra_evpn_es_free(&es
);
2526 /* Associate a MAC entry with a local or remote ES. Returns false if there
2529 bool zebra_evpn_es_mac_ref_entry(struct zebra_mac
*mac
,
2530 struct zebra_evpn_es
*es
)
2536 zebra_evpn_es_mac_deref_entry(mac
);
2542 listnode_init(&mac
->es_listnode
, mac
);
2543 listnode_add(es
->mac_list
, &mac
->es_listnode
);
2548 bool zebra_evpn_es_mac_ref(struct zebra_mac
*mac
, const esi_t
*esi
)
2550 struct zebra_evpn_es
*es
;
2552 es
= zebra_evpn_es_find(esi
);
2554 /* If non-zero esi implicitly create a new ES */
2555 if (memcmp(esi
, zero_esi
, sizeof(esi_t
))) {
2556 es
= zebra_evpn_es_new(esi
);
2557 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2558 zlog_debug("auto es %s add on mac ref",
2563 return zebra_evpn_es_mac_ref_entry(mac
, es
);
2566 /* Inform BGP about local ES-EVI add or del */
2567 static int zebra_evpn_es_evi_send_to_client(struct zebra_evpn_es
*es
,
2568 struct zebra_evpn
*zevpn
, bool add
)
2570 struct zserv
*client
;
2573 client
= zserv_find_client(ZEBRA_ROUTE_BGP
, 0);
2574 /* BGP may not be running. */
2578 s
= stream_new(ZEBRA_MAX_PACKET_SIZ
);
2580 zclient_create_header(s
,
2581 add
? ZEBRA_LOCAL_ES_EVI_ADD
: ZEBRA_LOCAL_ES_EVI_DEL
,
2582 zebra_vrf_get_evpn_id());
2583 stream_put(s
, &es
->esi
, sizeof(esi_t
));
2584 stream_putl(s
, zevpn
->vni
);
2586 /* Write packet size. */
2587 stream_putw_at(s
, 0, stream_get_endp(s
));
2589 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2590 zlog_debug("send %s local es %s evi %u to %s",
2591 add
? "add" : "del",
2592 es
->esi_str
, zevpn
->vni
,
2593 zebra_route_string(client
->proto
));
2595 client
->local_es_add_cnt
++;
2596 return zserv_send_message(client
, s
);
2599 /* sysmac part of a local ESI has changed */
2600 static int zebra_evpn_es_sys_mac_update(struct zebra_if
*zif
,
2601 struct ethaddr
*sysmac
)
2605 rv
= zebra_evpn_type3_esi_update(zif
, zif
->es_info
.lid
, sysmac
);
2607 memcpy(&zif
->es_info
.sysmac
, sysmac
, sizeof(struct ethaddr
));
2612 /* local-ID part of ESI has changed */
2613 static int zebra_evpn_es_lid_update(struct zebra_if
*zif
, uint32_t lid
)
2617 rv
= zebra_evpn_type3_esi_update(zif
, lid
, &zif
->es_info
.sysmac
);
2619 zif
->es_info
.lid
= lid
;
2624 /* type-0 esi has changed */
2625 static int zebra_evpn_es_type0_esi_update(struct zebra_if
*zif
, esi_t
*esi
)
2629 rv
= zebra_evpn_local_es_update(zif
, esi
);
2631 /* clear the old es_lid, es_sysmac - type-0 is being set so old
2632 * type-3 params need to be flushed
2634 memset(&zif
->es_info
.sysmac
, 0, sizeof(struct ethaddr
));
2635 zif
->es_info
.lid
= 0;
2640 void zebra_evpn_es_cleanup(void)
2642 struct zebra_evpn_es
*es
;
2643 struct zebra_evpn_es
*es_next
;
2645 RB_FOREACH_SAFE(es
, zebra_es_rb_head
,
2646 &zmh_info
->es_rb_tree
, es_next
) {
2647 zebra_evpn_local_es_del(&es
);
2649 zebra_evpn_remote_es_flush(&es
);
2653 static void zebra_evpn_es_df_pref_update(struct zebra_if
*zif
, uint16_t df_pref
)
2655 struct zebra_evpn_es
*es
;
2658 if (zif
->es_info
.df_pref
== df_pref
)
2661 zif
->es_info
.df_pref
= df_pref
;
2662 es
= zif
->es_info
.es
;
2667 tmp_pref
= zif
->es_info
.df_pref
? zif
->es_info
.df_pref
2668 : EVPN_MH_DF_PREF_DEFAULT
;
2670 if (es
->df_pref
== tmp_pref
)
2673 es
->df_pref
= tmp_pref
;
2674 /* run df election */
2675 zebra_evpn_es_run_df_election(es
, __func__
);
2677 if (es
->flags
& ZEBRA_EVPNES_READY_FOR_BGP
)
2678 zebra_evpn_es_send_add_to_client(es
);
2681 /* If bypass mode on an es changed we set all local macs to
2682 * inactive and drop the sync info
2684 static void zebra_evpn_es_bypass_update_macs(struct zebra_evpn_es
*es
,
2685 struct interface
*ifp
, bool bypass
)
2687 struct zebra_mac
*mac
;
2688 struct listnode
*node
;
2689 struct listnode
*nnode
;
2690 struct zebra_if
*zif
;
2692 /* Flush all MACs linked to the ES */
2693 for (ALL_LIST_ELEMENTS(es
->mac_list
, node
, nnode
, mac
)) {
2694 if (!CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
))
2697 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
2698 zlog_debug("VNI %u mac %pEA %s update es %s",
2701 bypass
? "bypass" : "non-bypass",
2703 zebra_evpn_flush_local_mac(mac
, ifp
);
2706 /* While in bypass-mode locally learnt MACs are linked
2707 * to the access port instead of the ES
2713 for (ALL_LIST_ELEMENTS(zif
->mac_list
, node
, nnode
, mac
)) {
2714 if (!CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
))
2717 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
2718 zlog_debug("VNI %u mac %pEA %s update ifp %s",
2721 bypass
? "bypass" : "non-bypass", ifp
->name
);
2722 zebra_evpn_flush_local_mac(mac
, ifp
);
2726 void zebra_evpn_es_bypass_update(struct zebra_evpn_es
*es
,
2727 struct interface
*ifp
, bool bypass
)
2730 bool dplane_updated
;
2732 old_bypass
= !!(es
->flags
& ZEBRA_EVPNES_BYPASS
);
2733 if (old_bypass
== bypass
)
2737 es
->flags
|= ZEBRA_EVPNES_BYPASS
;
2739 es
->flags
&= ~ZEBRA_EVPNES_BYPASS
;
2741 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2742 zlog_debug("bond %s es %s lacp bypass changed to %s", ifp
->name
,
2743 es
->esi_str
, bypass
? "on" : "off");
2745 /* send bypass update to BGP */
2746 if (es
->flags
& ZEBRA_EVPNES_READY_FOR_BGP
)
2747 zebra_evpn_es_send_add_to_client(es
);
2749 zebra_evpn_es_bypass_update_macs(es
, ifp
, bypass
);
2751 /* re-run DF election */
2752 dplane_updated
= zebra_evpn_es_run_df_election(es
, __func__
);
2754 /* disable SPH filter */
2755 if (!dplane_updated
&& (es
->flags
& ZEBRA_EVPNES_LOCAL
)
2756 && (listcount(es
->es_vtep_list
) > ES_VTEP_MAX_CNT
))
2757 zebra_evpn_es_br_port_dplane_update(es
, __func__
);
2760 static void zebra_evpn_es_bypass_cfg_update(struct zebra_if
*zif
, bool bypass
)
2762 bool old_bypass
= !!(zif
->es_info
.flags
& ZIF_CFG_ES_FLAG_BYPASS
);
2764 if (old_bypass
== bypass
)
2768 zif
->es_info
.flags
|= ZIF_CFG_ES_FLAG_BYPASS
;
2770 zif
->es_info
.flags
&= ~ZIF_CFG_ES_FLAG_BYPASS
;
2773 if (zif
->es_info
.es
)
2774 zebra_evpn_es_bypass_update(zif
->es_info
.es
, zif
->ifp
, bypass
);
2778 /* Only certain types of access ports can be setup as an Ethernet Segment */
2779 bool zebra_evpn_is_if_es_capable(struct zebra_if
*zif
)
2781 if (zif
->zif_type
== ZEBRA_IF_BOND
)
2784 /* XXX: allow swpX i.e. a regular ethernet port to be an ES link too */
2788 void zebra_evpn_if_es_print(struct vty
*vty
, json_object
*json
,
2789 struct zebra_if
*zif
)
2791 char buf
[ETHER_ADDR_STRLEN
];
2792 char esi_buf
[ESI_STR_LEN
];
2795 json_object
*json_evpn
;
2797 json_evpn
= json_object_new_object();
2798 json_object_object_add(json
, "evpnMh", json_evpn
);
2800 if (zif
->es_info
.lid
|| !is_zero_mac(&zif
->es_info
.sysmac
)) {
2801 json_object_int_add(json_evpn
, "esId",
2803 json_object_string_add(
2804 json_evpn
, "esSysmac",
2805 prefix_mac2str(&zif
->es_info
.sysmac
, buf
,
2807 } else if (memcmp(&zif
->es_info
.esi
, zero_esi
,
2808 sizeof(*zero_esi
))) {
2809 json_object_string_add(json_evpn
, "esId",
2810 esi_to_str(&zif
->es_info
.esi
,
2815 if (zif
->flags
& ZIF_FLAG_EVPN_MH_UPLINK
)
2816 json_object_string_add(
2817 json_evpn
, "uplink",
2818 CHECK_FLAG(zif
->flags
,
2819 ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP
)
2824 bool vty_print
= false;
2827 strlcat(mh_buf
, " EVPN-MH:", sizeof(mh_buf
));
2828 if (zif
->es_info
.lid
|| !is_zero_mac(&zif
->es_info
.sysmac
)) {
2830 snprintf(mh_buf
+ strlen(mh_buf
),
2831 sizeof(mh_buf
) - strlen(mh_buf
),
2832 " ES id %u ES sysmac %s", zif
->es_info
.lid
,
2833 prefix_mac2str(&zif
->es_info
.sysmac
, buf
,
2835 } else if (memcmp(&zif
->es_info
.esi
, zero_esi
,
2836 sizeof(*zero_esi
))) {
2838 snprintf(mh_buf
+ strnlen(mh_buf
, sizeof(mh_buf
)),
2840 - strnlen(mh_buf
, sizeof(mh_buf
)),
2842 esi_to_str(&zif
->es_info
.esi
, esi_buf
,
2846 if (zif
->flags
& ZIF_FLAG_EVPN_MH_UPLINK
) {
2848 if (zif
->flags
& ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP
)
2849 strlcat(mh_buf
, " uplink (up)", sizeof(mh_buf
));
2851 strlcat(mh_buf
, " uplink (down)",
2856 vty_out(vty
, "%s\n", mh_buf
);
2860 static void zebra_evpn_local_mac_oper_state_change(struct zebra_evpn_es
*es
)
2862 struct zebra_mac
*mac
;
2863 struct listnode
*node
;
2865 /* If fast-failover is supported by the dataplane via the use
2866 * of an ES backup NHG there is nothing to be done in the
2869 if (!(zmh_info
->flags
& ZEBRA_EVPN_MH_REDIRECT_OFF
))
2872 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
|| IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
2873 zlog_debug("mac slow-fail on es %s %s ", es
->esi_str
,
2874 (es
->flags
& ZEBRA_EVPNES_OPER_UP
) ? "up" : "down");
2876 for (ALL_LIST_ELEMENTS_RO(es
->mac_list
, node
, mac
)) {
2877 if (!(mac
->flags
& ZEBRA_MAC_LOCAL
)
2878 || !zebra_evpn_mac_is_static(mac
))
2881 if (es
->flags
& ZEBRA_EVPNES_OPER_UP
) {
2882 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
2884 "VNI %u mac %pEA move to acc %s es %s %s ",
2887 es
->zif
->ifp
->name
, es
->esi_str
,
2888 (es
->flags
& ZEBRA_EVPNES_OPER_UP
)
2891 /* switch the local macs to access port */
2892 if (zebra_evpn_sync_mac_dp_install(
2893 mac
, false /*set_inactive*/,
2894 false /*force_clear_static*/, __func__
)
2896 /* if the local mac install fails get rid of the
2899 zebra_evpn_rem_mac_uninstall(mac
->zevpn
, mac
,
2902 /* switch the local macs to network port. if there
2903 * is no active NHG we don't bother deleting the MAC;
2904 * that is left up to the dataplane to handle.
2906 if (!(es
->flags
& ZEBRA_EVPNES_NHG_ACTIVE
))
2908 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
2910 "VNI %u mac %pEA move to nhg %u es %s %s ",
2913 es
->nhg_id
, es
->esi_str
,
2914 (es
->flags
& ZEBRA_EVPNES_OPER_UP
)
2917 zebra_evpn_rem_mac_install(mac
->zevpn
, mac
,
2918 true /*was_static*/);
2923 void zebra_evpn_es_if_oper_state_change(struct zebra_if
*zif
, bool up
)
2925 struct zebra_evpn_es
*es
= zif
->es_info
.es
;
2926 bool old_up
= !!(es
->flags
& ZEBRA_EVPNES_OPER_UP
);
2931 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2932 zlog_debug("es %s state changed to %s ",
2934 up
? "up" : "down");
2936 es
->flags
|= ZEBRA_EVPNES_OPER_UP
;
2938 es
->flags
&= ~ZEBRA_EVPNES_OPER_UP
;
2940 zebra_evpn_es_run_df_election(es
, __func__
);
2941 zebra_evpn_local_mac_oper_state_change(es
);
2943 /* inform BGP of the ES oper state change */
2944 if (es
->flags
& ZEBRA_EVPNES_READY_FOR_BGP
)
2945 zebra_evpn_es_send_add_to_client(es
);
2948 static char *zebra_evpn_es_vtep_str(char *vtep_str
, struct zebra_evpn_es
*es
,
2949 uint8_t vtep_str_size
)
2951 struct zebra_evpn_es_vtep
*zvtep
;
2952 struct listnode
*node
;
2954 char ip_buf
[INET6_ADDRSTRLEN
];
2957 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, zvtep
)) {
2961 inet_ntop(AF_INET
, &zvtep
->vtep_ip
, ip_buf
,
2965 strlcat(vtep_str
, ",", vtep_str_size
);
2967 inet_ntop(AF_INET
, &zvtep
->vtep_ip
, ip_buf
,
2975 static void zebra_evpn_es_json_vtep_fill(struct zebra_evpn_es
*es
,
2976 json_object
*json_vteps
)
2978 struct zebra_evpn_es_vtep
*es_vtep
;
2979 struct listnode
*node
;
2980 json_object
*json_vtep_entry
;
2981 char alg_buf
[EVPN_DF_ALG_STR_LEN
];
2983 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
2984 json_vtep_entry
= json_object_new_object();
2985 json_object_string_addf(json_vtep_entry
, "vtep", "%pI4",
2987 if (es_vtep
->flags
& ZEBRA_EVPNES_VTEP_RXED_ESR
) {
2988 json_object_string_add(
2989 json_vtep_entry
, "dfAlgorithm",
2990 evpn_es_df_alg2str(es_vtep
->df_alg
, alg_buf
,
2992 json_object_int_add(json_vtep_entry
, "dfPreference",
2996 json_object_int_add(json_vtep_entry
, "nexthopId",
2997 es_vtep
->nh
->nh_id
);
2998 json_object_array_add(json_vteps
, json_vtep_entry
);
3002 static void zebra_evpn_es_show_entry(struct vty
*vty
, struct zebra_evpn_es
*es
,
3003 json_object
*json_array
)
3006 char vtep_str
[ES_VTEP_LIST_STR_SZ
];
3009 json_object
*json
= NULL
;
3010 json_object
*json_vteps
;
3011 json_object
*json_flags
;
3013 json
= json_object_new_object();
3014 json_object_string_add(json
, "esi", es
->esi_str
);
3017 & (ZEBRA_EVPNES_LOCAL
| ZEBRA_EVPNES_REMOTE
3018 | ZEBRA_EVPNES_NON_DF
)) {
3019 json_flags
= json_object_new_array();
3020 if (es
->flags
& ZEBRA_EVPNES_LOCAL
)
3021 json_array_string_add(json_flags
, "local");
3022 if (es
->flags
& ZEBRA_EVPNES_REMOTE
)
3023 json_array_string_add(json_flags
, "remote");
3024 if (es
->flags
& ZEBRA_EVPNES_NON_DF
)
3025 json_array_string_add(json_flags
, "nonDF");
3026 if (es
->flags
& ZEBRA_EVPNES_BYPASS
)
3027 json_array_string_add(json_flags
, "bypass");
3028 json_object_object_add(json
, "flags", json_flags
);
3032 json_object_string_add(json
, "accessPort",
3033 es
->zif
->ifp
->name
);
3035 if (listcount(es
->es_vtep_list
)) {
3036 json_vteps
= json_object_new_array();
3037 zebra_evpn_es_json_vtep_fill(es
, json_vteps
);
3038 json_object_object_add(json
, "vteps", json_vteps
);
3040 json_object_array_add(json_array
, json
);
3043 if (es
->flags
& ZEBRA_EVPNES_LOCAL
)
3044 strlcat(type_str
, "L", sizeof(type_str
));
3045 if (es
->flags
& ZEBRA_EVPNES_REMOTE
)
3046 strlcat(type_str
, "R", sizeof(type_str
));
3047 if (es
->flags
& ZEBRA_EVPNES_NON_DF
)
3048 strlcat(type_str
, "N", sizeof(type_str
));
3049 if (es
->flags
& ZEBRA_EVPNES_BYPASS
)
3050 strlcat(type_str
, "B", sizeof(type_str
));
3052 zebra_evpn_es_vtep_str(vtep_str
, es
, sizeof(vtep_str
));
3054 vty_out(vty
, "%-30s %-4s %-21s %s\n",
3055 es
->esi_str
, type_str
,
3056 es
->zif
? es
->zif
->ifp
->name
: "-",
3061 static void zebra_evpn_es_show_entry_detail(struct vty
*vty
,
3062 struct zebra_evpn_es
*es
, json_object
*json
)
3065 char alg_buf
[EVPN_DF_ALG_STR_LEN
];
3066 struct zebra_evpn_es_vtep
*es_vtep
;
3067 struct listnode
*node
;
3068 char thread_buf
[THREAD_TIMER_STRLEN
];
3071 json_object
*json_vteps
;
3072 json_object
*json_flags
;
3074 json_object_string_add(json
, "esi", es
->esi_str
);
3076 json_object_string_add(json
, "accessPort",
3077 es
->zif
->ifp
->name
);
3081 json_flags
= json_object_new_array();
3082 if (es
->flags
& ZEBRA_EVPNES_LOCAL
)
3083 json_array_string_add(json_flags
, "local");
3084 if (es
->flags
& ZEBRA_EVPNES_REMOTE
)
3085 json_array_string_add(json_flags
, "remote");
3086 if (es
->flags
& ZEBRA_EVPNES_NON_DF
)
3087 json_array_string_add(json_flags
, "nonDF");
3088 if (es
->flags
& ZEBRA_EVPNES_BYPASS
)
3089 json_array_string_add(json_flags
, "bypass");
3090 if (es
->flags
& ZEBRA_EVPNES_READY_FOR_BGP
)
3091 json_array_string_add(json_flags
,
3093 if (es
->flags
& ZEBRA_EVPNES_BR_PORT
)
3094 json_array_string_add(json_flags
, "bridgePort");
3095 if (es
->flags
& ZEBRA_EVPNES_OPER_UP
)
3096 json_array_string_add(json_flags
, "operUp");
3097 if (es
->flags
& ZEBRA_EVPNES_NHG_ACTIVE
)
3098 json_array_string_add(json_flags
,
3099 "nexthopGroupActive");
3100 json_object_object_add(json
, "flags", json_flags
);
3103 json_object_int_add(json
, "vniCount",
3104 listcount(es
->es_evi_list
));
3105 json_object_int_add(json
, "macCount", listcount(es
->mac_list
));
3106 json_object_int_add(json
, "dfPreference", es
->df_pref
);
3107 if (es
->df_delay_timer
)
3108 json_object_string_add(
3109 json
, "dfDelayTimer",
3110 thread_timer_to_hhmmss(thread_buf
,
3112 es
->df_delay_timer
));
3113 json_object_int_add(json
, "nexthopGroup", es
->nhg_id
);
3114 if (listcount(es
->es_vtep_list
)) {
3115 json_vteps
= json_object_new_array();
3116 zebra_evpn_es_json_vtep_fill(es
, json_vteps
);
3117 json_object_object_add(json
, "vteps", json_vteps
);
3121 if (es
->flags
& ZEBRA_EVPNES_LOCAL
)
3122 strlcat(type_str
, "Local", sizeof(type_str
));
3123 if (es
->flags
& ZEBRA_EVPNES_REMOTE
) {
3124 if (strnlen(type_str
, sizeof(type_str
)))
3125 strlcat(type_str
, ",", sizeof(type_str
));
3126 strlcat(type_str
, "Remote", sizeof(type_str
));
3129 vty_out(vty
, "ESI: %s\n", es
->esi_str
);
3130 vty_out(vty
, " Type: %s\n", type_str
);
3131 vty_out(vty
, " Interface: %s\n",
3133 es
->zif
->ifp
->name
: "-");
3134 if (es
->flags
& ZEBRA_EVPNES_LOCAL
) {
3135 vty_out(vty
, " State: %s\n",
3136 (es
->flags
& ZEBRA_EVPNES_OPER_UP
) ? "up"
3138 vty_out(vty
, " Bridge port: %s\n",
3139 (es
->flags
& ZEBRA_EVPNES_BR_PORT
) ? "yes"
3142 vty_out(vty
, " Ready for BGP: %s\n",
3143 (es
->flags
& ZEBRA_EVPNES_READY_FOR_BGP
) ?
3145 if (es
->flags
& ZEBRA_EVPNES_BYPASS
)
3146 vty_out(vty
, " LACP bypass: on\n");
3147 vty_out(vty
, " VNI Count: %d\n", listcount(es
->es_evi_list
));
3148 vty_out(vty
, " MAC Count: %d\n", listcount(es
->mac_list
));
3149 if (es
->flags
& ZEBRA_EVPNES_LOCAL
)
3150 vty_out(vty
, " DF status: %s \n",
3151 (es
->flags
& ZEBRA_EVPNES_NON_DF
) ? "non-df"
3153 if (es
->df_delay_timer
)
3154 vty_out(vty
, " DF delay: %s\n",
3155 thread_timer_to_hhmmss(thread_buf
,
3157 es
->df_delay_timer
));
3158 vty_out(vty
, " DF preference: %u\n", es
->df_pref
);
3159 vty_out(vty
, " Nexthop group: %u\n", es
->nhg_id
);
3160 vty_out(vty
, " VTEPs:\n");
3161 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
3162 vty_out(vty
, " %pI4",
3164 if (es_vtep
->flags
& ZEBRA_EVPNES_VTEP_RXED_ESR
)
3165 vty_out(vty
, " df_alg: %s df_pref: %d",
3166 evpn_es_df_alg2str(es_vtep
->df_alg
,
3170 vty_out(vty
, " nh: %u\n",
3171 es_vtep
->nh
? es_vtep
->nh
->nh_id
: 0);
3178 void zebra_evpn_es_show(struct vty
*vty
, bool uj
)
3180 struct zebra_evpn_es
*es
;
3181 json_object
*json_array
= NULL
;
3184 json_array
= json_object_new_array();
3186 vty_out(vty
, "Type: B bypass, L local, R remote, N non-DF\n");
3187 vty_out(vty
, "%-30s %-4s %-21s %s\n",
3188 "ESI", "Type", "ES-IF", "VTEPs");
3191 RB_FOREACH(es
, zebra_es_rb_head
, &zmh_info
->es_rb_tree
)
3192 zebra_evpn_es_show_entry(vty
, es
, json_array
);
3195 vty_json(vty
, json_array
);
3198 void zebra_evpn_es_show_detail(struct vty
*vty
, bool uj
)
3200 struct zebra_evpn_es
*es
;
3201 json_object
*json_array
= NULL
;
3204 json_array
= json_object_new_array();
3206 RB_FOREACH (es
, zebra_es_rb_head
, &zmh_info
->es_rb_tree
) {
3207 json_object
*json
= NULL
;
3210 json
= json_object_new_object();
3211 zebra_evpn_es_show_entry_detail(vty
, es
, json
);
3213 json_object_array_add(json_array
, json
);
3217 vty_json(vty
, json_array
);
3220 void zebra_evpn_es_show_esi(struct vty
*vty
, bool uj
, esi_t
*esi
)
3222 struct zebra_evpn_es
*es
;
3223 char esi_str
[ESI_STR_LEN
];
3224 json_object
*json
= NULL
;
3227 json
= json_object_new_object();
3229 es
= zebra_evpn_es_find(esi
);
3232 zebra_evpn_es_show_entry_detail(vty
, es
, json
);
3235 esi_to_str(esi
, esi_str
, sizeof(esi_str
));
3236 vty_out(vty
, "ESI %s does not exist\n", esi_str
);
3241 vty_json(vty
, json
);
3244 int zebra_evpn_mh_if_write(struct vty
*vty
, struct interface
*ifp
)
3246 struct zebra_if
*zif
= ifp
->info
;
3247 char buf
[ETHER_ADDR_STRLEN
];
3248 bool type_3_esi
= false;
3249 char esi_buf
[ESI_STR_LEN
];
3251 if (zif
->es_info
.lid
) {
3252 vty_out(vty
, " evpn mh es-id %u\n", zif
->es_info
.lid
);
3256 if (!is_zero_mac(&zif
->es_info
.sysmac
)) {
3257 vty_out(vty
, " evpn mh es-sys-mac %s\n",
3258 prefix_mac2str(&zif
->es_info
.sysmac
,
3264 && memcmp(&zif
->es_info
.esi
, zero_esi
, sizeof(*zero_esi
)))
3265 vty_out(vty
, " evpn mh es-id %s\n",
3266 esi_to_str(&zif
->es_info
.esi
, esi_buf
, sizeof(esi_buf
)));
3268 if (zif
->es_info
.df_pref
)
3269 vty_out(vty
, " evpn mh es-df-pref %u\n", zif
->es_info
.df_pref
);
3271 if (zif
->flags
& ZIF_FLAG_EVPN_MH_UPLINK
)
3272 vty_out(vty
, " evpn mh uplink\n");
3277 #ifndef VTYSH_EXTRACT_PL
3278 #include "zebra/zebra_evpn_mh_clippy.c"
3280 /* CLI for setting an ES in bypass mode */
3281 DEFPY_HIDDEN(zebra_evpn_es_bypass
, zebra_evpn_es_bypass_cmd
,
3282 "[no] evpn mh bypass",
3283 NO_STR
"EVPN\n" EVPN_MH_VTY_STR
"set bypass mode\n")
3285 VTY_DECLVAR_CONTEXT(interface
, ifp
);
3286 struct zebra_if
*zif
;
3291 zebra_evpn_es_bypass_cfg_update(zif
, false);
3293 if (!zebra_evpn_is_if_es_capable(zif
)) {
3295 "%%DF bypass cannot be associated with this interface type\n");
3298 zebra_evpn_es_bypass_cfg_update(zif
, true);
3303 /* CLI for configuring DF preference part for an ES */
3304 DEFPY(zebra_evpn_es_pref
, zebra_evpn_es_pref_cmd
,
3305 "[no$no] evpn mh es-df-pref [(1-65535)$df_pref]",
3306 NO_STR
"EVPN\n" EVPN_MH_VTY_STR
3307 "preference value used for DF election\n"
3310 VTY_DECLVAR_CONTEXT(interface
, ifp
);
3311 struct zebra_if
*zif
;
3316 zebra_evpn_es_df_pref_update(zif
, 0);
3318 if (!zebra_evpn_is_if_es_capable(zif
)) {
3320 "%%DF preference cannot be associated with this interface type\n");
3323 zebra_evpn_es_df_pref_update(zif
, df_pref
);
3328 /* CLI for setting up sysmac part of ESI on an access port */
3329 DEFPY(zebra_evpn_es_sys_mac
,
3330 zebra_evpn_es_sys_mac_cmd
,
3331 "[no$no] evpn mh es-sys-mac [X:X:X:X:X:X$mac]",
3335 "Ethernet segment system MAC\n"
3339 VTY_DECLVAR_CONTEXT(interface
, ifp
);
3340 struct zebra_if
*zif
;
3346 static struct ethaddr zero_mac
;
3348 ret
= zebra_evpn_es_sys_mac_update(zif
, &zero_mac
);
3350 vty_out(vty
, "%%Failed to clear ES sysmac\n");
3355 if (!zebra_evpn_is_if_es_capable(zif
)) {
3357 "%%ESI cannot be associated with this interface type\n");
3361 if (!mac
|| is_zero_mac(&mac
->eth_addr
)) {
3362 vty_out(vty
, "%%ES sysmac value is invalid\n");
3366 ret
= zebra_evpn_es_sys_mac_update(zif
, &mac
->eth_addr
);
3368 vty_out(vty
, "%%ESI already exists on a different interface\n");
3375 /* CLI for setting up local-ID part of ESI on an access port */
3376 DEFPY(zebra_evpn_es_id
,
3377 zebra_evpn_es_id_cmd
,
3378 "[no$no] evpn mh es-id [(1-16777215)$es_lid | NAME$esi_str]",
3382 "Ethernet segment identifier\n"
3383 "local discriminator\n"
3384 "10-byte ID - 00:AA:BB:CC:DD:EE:FF:GG:HH:II\n"
3387 VTY_DECLVAR_CONTEXT(interface
, ifp
);
3388 struct zebra_if
*zif
;
3395 if (zif
->es_info
.lid
)
3396 ret
= zebra_evpn_es_lid_update(zif
, 0);
3397 else if (memcmp(&zif
->es_info
.esi
, zero_esi
, sizeof(*zero_esi
)))
3398 ret
= zebra_evpn_es_type0_esi_update(zif
, zero_esi
);
3401 vty_out(vty
, "%%Failed to clear ES local id\n");
3405 if (!zebra_evpn_is_if_es_capable(zif
)) {
3407 "%%ESI cannot be associated with this interface type\n");
3412 if (!str_to_esi(esi_str
, &esi
)) {
3413 vty_out(vty
, "%% Malformed ESI\n");
3416 ret
= zebra_evpn_es_type0_esi_update(zif
, &esi
);
3419 vty_out(vty
, "%%Specify local ES ID\n");
3422 ret
= zebra_evpn_es_lid_update(zif
, es_lid
);
3427 "%%ESI already exists on a different interface\n");
3434 /* CLI for tagging an interface as an uplink */
3435 DEFPY(zebra_evpn_mh_uplink
, zebra_evpn_mh_uplink_cmd
, "[no] evpn mh uplink",
3436 NO_STR
"EVPN\n" EVPN_MH_VTY_STR
"uplink to the VxLAN core\n")
3438 VTY_DECLVAR_CONTEXT(interface
, ifp
);
3439 struct zebra_if
*zif
;
3442 zebra_evpn_mh_uplink_cfg_update(zif
, no
? false : true);
3447 void zebra_evpn_mh_json(json_object
*json
)
3449 json_object
*json_array
;
3450 char thread_buf
[THREAD_TIMER_STRLEN
];
3452 json_object_int_add(json
, "macHoldtime", zmh_info
->mac_hold_time
);
3453 json_object_int_add(json
, "neighHoldtime", zmh_info
->neigh_hold_time
);
3454 json_object_int_add(json
, "startupDelay", zmh_info
->startup_delay_time
);
3455 json_object_string_add(
3456 json
, "startupDelayTimer",
3457 thread_timer_to_hhmmss(thread_buf
, sizeof(thread_buf
),
3458 zmh_info
->startup_delay_timer
));
3459 json_object_int_add(json
, "uplinkConfigCount",
3460 zmh_info
->uplink_cfg_cnt
);
3461 json_object_int_add(json
, "uplinkActiveCount",
3462 zmh_info
->uplink_oper_up_cnt
);
3464 if (zmh_info
->protodown_rc
) {
3465 json_array
= json_object_new_array();
3466 if (zmh_info
->protodown_rc
& ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY
)
3467 json_object_array_add(
3469 json_object_new_string("startupDelay"));
3470 if (zmh_info
->protodown_rc
& ZEBRA_PROTODOWN_EVPN_UPLINK_DOWN
)
3471 json_object_array_add(
3473 json_object_new_string("uplinkDown"));
3474 json_object_object_add(json
, "protodownReasons", json_array
);
3478 void zebra_evpn_mh_print(struct vty
*vty
)
3480 char pd_buf
[ZEBRA_PROTODOWN_RC_STR_LEN
];
3481 char thread_buf
[THREAD_TIMER_STRLEN
];
3483 vty_out(vty
, "EVPN MH:\n");
3484 vty_out(vty
, " mac-holdtime: %ds, neigh-holdtime: %ds\n",
3485 zmh_info
->mac_hold_time
, zmh_info
->neigh_hold_time
);
3486 vty_out(vty
, " startup-delay: %ds, start-delay-timer: %s\n",
3487 zmh_info
->startup_delay_time
,
3488 thread_timer_to_hhmmss(thread_buf
, sizeof(thread_buf
),
3489 zmh_info
->startup_delay_timer
));
3490 vty_out(vty
, " uplink-cfg-cnt: %u, uplink-active-cnt: %u\n",
3491 zmh_info
->uplink_cfg_cnt
, zmh_info
->uplink_oper_up_cnt
);
3492 if (zmh_info
->protodown_rc
)
3493 vty_out(vty
, " protodown reasons: %s\n",
3494 zebra_protodown_rc_str(zmh_info
->protodown_rc
, pd_buf
,
3498 /*****************************************************************************/
3499 /* A base L2-VNI is maintained to derive parameters such as ES originator-IP.
3500 * XXX: once single vxlan device model becomes available this will not be
3503 /* called when a new vni is added or becomes oper up or becomes a bridge port */
3504 void zebra_evpn_es_set_base_evpn(struct zebra_evpn
*zevpn
)
3506 struct listnode
*node
;
3507 struct zebra_evpn_es
*es
;
3509 if (zmh_info
->es_base_evpn
) {
3510 if (zmh_info
->es_base_evpn
!= zevpn
) {
3511 /* unrelated EVPN; ignore it */
3514 /* check if the local vtep-ip has changed */
3516 /* check if the EVPN can be used as base EVPN */
3517 if (!zebra_evpn_send_to_client_ok(zevpn
))
3520 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3521 zlog_debug("es base vni set to %d",
3523 zmh_info
->es_base_evpn
= zevpn
;
3526 /* update local VTEP-IP */
3527 if (zmh_info
->es_originator_ip
.s_addr
==
3528 zmh_info
->es_base_evpn
->local_vtep_ip
.s_addr
)
3531 zmh_info
->es_originator_ip
.s_addr
=
3532 zmh_info
->es_base_evpn
->local_vtep_ip
.s_addr
;
3534 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3535 zlog_debug("es originator ip set to %pI4",
3536 &zmh_info
->es_base_evpn
->local_vtep_ip
);
3538 /* if originator ip changes we need to update bgp */
3539 for (ALL_LIST_ELEMENTS_RO(zmh_info
->local_es_list
, node
, es
)) {
3540 zebra_evpn_es_run_df_election(es
, __func__
);
3542 if (es
->flags
& ZEBRA_EVPNES_READY_FOR_BGP
)
3543 zebra_evpn_es_send_add_to_client(es
);
3545 zebra_evpn_es_re_eval_send_to_client(es
,
3546 true /* es_evi_re_reval */);
3550 /* called when a vni is removed or becomes oper down or is removed from a
3553 void zebra_evpn_es_clear_base_evpn(struct zebra_evpn
*zevpn
)
3555 struct listnode
*node
;
3556 struct zebra_evpn_es
*es
;
3558 if (zmh_info
->es_base_evpn
!= zevpn
)
3561 zmh_info
->es_base_evpn
= NULL
;
3562 /* lost current base EVPN; try to find a new one */
3563 zebra_evpn_es_get_one_base_evpn();
3565 /* couldn't locate an eligible base evpn */
3566 if (!zmh_info
->es_base_evpn
&& zmh_info
->es_originator_ip
.s_addr
) {
3567 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3568 zlog_debug("es originator ip cleared");
3570 zmh_info
->es_originator_ip
.s_addr
= 0;
3571 /* lost originator ip */
3572 for (ALL_LIST_ELEMENTS_RO(zmh_info
->local_es_list
, node
, es
)) {
3573 zebra_evpn_es_re_eval_send_to_client(es
,
3574 true /* es_evi_re_reval */);
3579 /* Locate an "eligible" L2-VNI to follow */
3580 static int zebra_evpn_es_get_one_base_evpn_cb(struct hash_bucket
*b
, void *data
)
3582 struct zebra_evpn
*zevpn
= b
->data
;
3584 zebra_evpn_es_set_base_evpn(zevpn
);
3586 if (zmh_info
->es_base_evpn
)
3587 return HASHWALK_ABORT
;
3589 return HASHWALK_CONTINUE
;
3592 /* locate a base_evpn to follow for the purposes of common params like
3595 static void zebra_evpn_es_get_one_base_evpn(void)
3597 struct zebra_vrf
*zvrf
;
3599 zvrf
= zebra_vrf_get_evpn();
3600 hash_walk(zvrf
->evpn_table
, zebra_evpn_es_get_one_base_evpn_cb
, NULL
);
3603 /*****************************************************************************
3604 * local ethernet segments can be error-disabled if the switch is not
3605 * ready to start transmitting traffic via the VxLAN overlay
3607 bool zebra_evpn_is_es_bond(struct interface
*ifp
)
3609 struct zebra_if
*zif
= ifp
->info
;
3611 return !!(struct zebra_if
*)zif
->es_info
.es
;
3614 bool zebra_evpn_is_es_bond_member(struct interface
*ifp
)
3616 struct zebra_if
*zif
= ifp
->info
;
3618 return IS_ZEBRA_IF_BOND_SLAVE(zif
->ifp
) && zif
->bondslave_info
.bond_if
3619 && ((struct zebra_if
*)zif
->bondslave_info
.bond_if
->info
)
3623 void zebra_evpn_mh_update_protodown_bond_mbr(struct zebra_if
*zif
, bool clear
,
3628 enum protodown_reasons old_protodown_rc
= 0;
3629 enum protodown_reasons protodown_rc
= 0;
3632 struct zebra_if
*bond_zif
;
3634 bond_zif
= zif
->bondslave_info
.bond_if
->info
;
3635 protodown_rc
= bond_zif
->protodown_rc
;
3638 old_protodown
= !!(zif
->flags
& ZIF_FLAG_PROTODOWN
);
3639 old_protodown_rc
= zif
->protodown_rc
;
3640 zif
->protodown_rc
&= ~ZEBRA_PROTODOWN_EVPN_ALL
;
3641 zif
->protodown_rc
|= (protodown_rc
& ZEBRA_PROTODOWN_EVPN_ALL
);
3642 new_protodown
= !!zif
->protodown_rc
;
3644 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
3645 && (zif
->protodown_rc
!= old_protodown_rc
))
3647 "%s bond mbr %s protodown_rc changed; old 0x%x new 0x%x",
3648 caller
, zif
->ifp
->name
, old_protodown_rc
,
3651 if (old_protodown
== new_protodown
)
3655 zif
->flags
|= ZIF_FLAG_PROTODOWN
;
3657 zif
->flags
&= ~ZIF_FLAG_PROTODOWN
;
3659 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3660 zlog_debug("%s protodown %s", zif
->ifp
->name
,
3661 new_protodown
? "on" : "off");
3663 zebra_if_set_protodown(zif
->ifp
, new_protodown
);
3666 /* The bond members inherit the protodown reason code from the bond */
3667 static void zebra_evpn_mh_update_protodown_bond(struct zebra_if
*bond_zif
)
3669 struct zebra_if
*zif
;
3670 struct listnode
*node
;
3672 if (!bond_zif
->bond_info
.mbr_zifs
)
3675 for (ALL_LIST_ELEMENTS_RO(bond_zif
->bond_info
.mbr_zifs
, node
, zif
)) {
3676 zebra_evpn_mh_update_protodown_bond_mbr(zif
, false /*clear*/,
3681 /* The global EVPN MH protodown rc is applied to all local ESs */
3682 static void zebra_evpn_mh_update_protodown_es(struct zebra_evpn_es
*es
,
3685 struct zebra_if
*zif
;
3686 enum protodown_reasons old_protodown_rc
;
3689 /* if the reason code is the same bail unless it is a new
3690 * ES bond in that case we would need to ensure that the
3691 * dplane is really in sync with zebra
3694 && (zif
->protodown_rc
& ZEBRA_PROTODOWN_EVPN_ALL
)
3695 == (zmh_info
->protodown_rc
& ZEBRA_PROTODOWN_EVPN_ALL
))
3698 old_protodown_rc
= zif
->protodown_rc
;
3699 zif
->protodown_rc
&= ~ZEBRA_PROTODOWN_EVPN_ALL
;
3700 zif
->protodown_rc
|=
3701 (zmh_info
->protodown_rc
& ZEBRA_PROTODOWN_EVPN_ALL
);
3703 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
3704 && (old_protodown_rc
!= zif
->protodown_rc
))
3706 "es %s ifp %s protodown_rc changed; old 0x%x new 0x%x",
3707 es
->esi_str
, zif
->ifp
->name
, old_protodown_rc
,
3710 /* update dataplane with the new protodown setting */
3711 zebra_evpn_mh_update_protodown_bond(zif
);
3714 static void zebra_evpn_mh_clear_protodown_es(struct zebra_evpn_es
*es
)
3716 struct zebra_if
*zif
;
3717 enum protodown_reasons old_protodown_rc
;
3720 if (!(zif
->protodown_rc
& ZEBRA_PROTODOWN_EVPN_ALL
))
3723 old_protodown_rc
= zif
->protodown_rc
;
3724 zif
->protodown_rc
&= ~ZEBRA_PROTODOWN_EVPN_ALL
;
3726 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3728 "clear: es %s ifp %s protodown_rc cleared; old 0x%x new 0x%x",
3729 es
->esi_str
, zif
->ifp
->name
, old_protodown_rc
,
3732 /* update dataplane with the new protodown setting */
3733 zebra_evpn_mh_update_protodown_bond(zif
);
3736 static void zebra_evpn_mh_update_protodown_es_all(void)
3738 struct listnode
*node
;
3739 struct zebra_evpn_es
*es
;
3741 for (ALL_LIST_ELEMENTS_RO(zmh_info
->local_es_list
, node
, es
))
3742 zebra_evpn_mh_update_protodown_es(es
, false /*resync_dplane*/);
3745 static void zebra_evpn_mh_update_protodown(enum protodown_reasons protodown_rc
,
3748 enum protodown_reasons old_protodown_rc
= zmh_info
->protodown_rc
;
3751 if ((protodown_rc
& zmh_info
->protodown_rc
) == protodown_rc
)
3754 zmh_info
->protodown_rc
|= protodown_rc
;
3756 if (!(protodown_rc
& zmh_info
->protodown_rc
))
3758 zmh_info
->protodown_rc
&= ~protodown_rc
;
3761 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3762 zlog_debug("mh protodown_rc changed; old 0x%x new 0x%x",
3763 old_protodown_rc
, zmh_info
->protodown_rc
);
3764 zebra_evpn_mh_update_protodown_es_all();
3767 static inline bool zebra_evpn_mh_is_all_uplinks_down(void)
3769 return zmh_info
->uplink_cfg_cnt
&& !zmh_info
->uplink_oper_up_cnt
;
3772 static void zebra_evpn_mh_uplink_oper_flags_update(struct zebra_if
*zif
,
3776 if (if_is_operative(zif
->ifp
)) {
3777 if (!(zif
->flags
& ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP
)) {
3778 zif
->flags
|= ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP
;
3779 ++zmh_info
->uplink_oper_up_cnt
;
3782 if (zif
->flags
& ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP
) {
3783 zif
->flags
&= ~ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP
;
3784 if (zmh_info
->uplink_oper_up_cnt
)
3785 --zmh_info
->uplink_oper_up_cnt
;
3789 if (zif
->flags
& ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP
) {
3790 zif
->flags
&= ~ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP
;
3791 if (zmh_info
->uplink_oper_up_cnt
)
3792 --zmh_info
->uplink_oper_up_cnt
;
3797 static void zebra_evpn_mh_uplink_cfg_update(struct zebra_if
*zif
, bool set
)
3799 bool old_protodown
= zebra_evpn_mh_is_all_uplinks_down();
3803 if (zif
->flags
& ZIF_FLAG_EVPN_MH_UPLINK
)
3806 zif
->flags
|= ZIF_FLAG_EVPN_MH_UPLINK
;
3807 ++zmh_info
->uplink_cfg_cnt
;
3809 if (!(zif
->flags
& ZIF_FLAG_EVPN_MH_UPLINK
))
3812 zif
->flags
&= ~ZIF_FLAG_EVPN_MH_UPLINK
;
3813 if (zmh_info
->uplink_cfg_cnt
)
3814 --zmh_info
->uplink_cfg_cnt
;
3817 zebra_evpn_mh_uplink_oper_flags_update(zif
, set
);
3818 new_protodown
= zebra_evpn_mh_is_all_uplinks_down();
3819 if (old_protodown
== new_protodown
)
3822 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3824 "mh-uplink-cfg-chg on if %s/%d %s uplinks cfg %u up %u",
3825 zif
->ifp
->name
, zif
->ifp
->ifindex
, set
? "set" : "down",
3826 zmh_info
->uplink_cfg_cnt
, zmh_info
->uplink_oper_up_cnt
);
3828 zebra_evpn_mh_update_protodown(ZEBRA_PROTODOWN_EVPN_UPLINK_DOWN
,
3832 void zebra_evpn_mh_uplink_oper_update(struct zebra_if
*zif
)
3834 bool old_protodown
= zebra_evpn_mh_is_all_uplinks_down();
3837 zebra_evpn_mh_uplink_oper_flags_update(zif
, true /*set*/);
3839 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3841 "mh-uplink-oper-chg on if %s/%d %s; uplinks cfg %u up %u",
3842 zif
->ifp
->name
, zif
->ifp
->ifindex
,
3843 if_is_operative(zif
->ifp
) ? "up" : "down",
3844 zmh_info
->uplink_cfg_cnt
, zmh_info
->uplink_oper_up_cnt
);
3846 new_protodown
= zebra_evpn_mh_is_all_uplinks_down();
3847 if (old_protodown
== new_protodown
)
3850 /* if protodown_rc XXX_UPLINK_DOWN is about to be cleared
3851 * fire up the start-up delay timer to allow the EVPN network
3852 * to converge (Type-2 routes need to be advertised and processed)
3854 if (!new_protodown
&& (zmh_info
->uplink_oper_up_cnt
== 1))
3855 zebra_evpn_mh_startup_delay_timer_start("uplink-up");
3857 zebra_evpn_mh_update_protodown(ZEBRA_PROTODOWN_EVPN_UPLINK_DOWN
,
3861 static void zebra_evpn_mh_startup_delay_exp_cb(struct thread
*t
)
3863 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3864 zlog_debug("startup-delay expired");
3866 zebra_evpn_mh_update_protodown(ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY
,
3870 static void zebra_evpn_mh_startup_delay_timer_start(const char *rc
)
3872 if (zmh_info
->startup_delay_timer
) {
3873 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3874 zlog_debug("startup-delay timer cancelled");
3875 THREAD_OFF(zmh_info
->startup_delay_timer
);
3878 if (zmh_info
->startup_delay_time
) {
3879 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3881 "startup-delay timer started for %d sec on %s",
3882 zmh_info
->startup_delay_time
, rc
);
3883 thread_add_timer(zrouter
.master
,
3884 zebra_evpn_mh_startup_delay_exp_cb
, NULL
,
3885 zmh_info
->startup_delay_time
,
3886 &zmh_info
->startup_delay_timer
);
3887 zebra_evpn_mh_update_protodown(
3888 ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY
, true /* set */);
3890 zebra_evpn_mh_update_protodown(
3891 ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY
, false /* set */);
3895 /*****************************************************************************
3896 * Nexthop management: nexthops associated with Type-2 routes that have
3897 * an ES as destination are consolidated by BGP into a per-VRF nh->rmac
3898 * mapping which is the installed as a remote neigh/fdb entry with a
3899 * dummy (type-1) prefix referencing it.
3900 * This handling is needed because Type-2 routes with ES as dest use NHG
3901 * that are setup using EAD routes (i.e. such NHGs do not include the
3903 ****************************************************************************/
3904 void zebra_evpn_proc_remote_nh(ZAPI_HANDLER_ARGS
)
3909 struct ethaddr rmac
;
3910 struct prefix_evpn dummy_prefix
;
3911 size_t min_len
= 4 + sizeof(nh
);
3916 * Ensure that the stream sent to us is long enough
3918 if (hdr
->command
== ZEBRA_EVPN_REMOTE_NH_ADD
)
3919 min_len
+= sizeof(rmac
);
3920 if (hdr
->length
< min_len
)
3923 vrf_id
= stream_getl(s
);
3924 stream_get(&nh
, s
, sizeof(nh
));
3926 memset(&dummy_prefix
, 0, sizeof(dummy_prefix
));
3927 dummy_prefix
.family
= AF_EVPN
;
3928 dummy_prefix
.prefixlen
= (sizeof(struct evpn_addr
) * 8);
3929 dummy_prefix
.prefix
.route_type
= 1; /* XXX - fixup to type-1 def */
3930 dummy_prefix
.prefix
.ead_addr
.ip
.ipa_type
= nh
.ipa_type
;
3932 if (hdr
->command
== ZEBRA_EVPN_REMOTE_NH_ADD
) {
3933 stream_get(&rmac
, s
, sizeof(rmac
));
3934 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3936 "evpn remote nh %d %pIA rmac %pEA add pfx %pFX",
3937 vrf_id
, &nh
, &rmac
, &dummy_prefix
);
3938 zebra_rib_queue_evpn_route_add(vrf_id
, &rmac
, &nh
,
3939 (struct prefix
*)&dummy_prefix
);
3941 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3942 zlog_debug("evpn remote nh %d %pIA del pfx %pFX",
3943 vrf_id
, &nh
, &dummy_prefix
);
3944 zebra_rib_queue_evpn_route_del(vrf_id
, &nh
,
3945 (struct prefix
*)&dummy_prefix
);
3949 /*****************************************************************************/
3950 void zebra_evpn_mh_config_write(struct vty
*vty
)
3952 if (zmh_info
->mac_hold_time
!= ZEBRA_EVPN_MH_MAC_HOLD_TIME_DEF
)
3953 vty_out(vty
, "evpn mh mac-holdtime %d\n",
3954 zmh_info
->mac_hold_time
);
3956 if (zmh_info
->neigh_hold_time
!= ZEBRA_EVPN_MH_NEIGH_HOLD_TIME_DEF
)
3957 vty_out(vty
, "evpn mh neigh-holdtime %d\n",
3958 zmh_info
->neigh_hold_time
);
3960 if (zmh_info
->startup_delay_time
!= ZEBRA_EVPN_MH_STARTUP_DELAY_DEF
)
3961 vty_out(vty
, "evpn mh startup-delay %d\n",
3962 zmh_info
->startup_delay_time
);
3964 if (zmh_info
->flags
& ZEBRA_EVPN_MH_REDIRECT_OFF
)
3965 vty_out(vty
, "evpn mh redirect-off\n");
3968 int zebra_evpn_mh_neigh_holdtime_update(struct vty
*vty
,
3969 uint32_t duration
, bool set_default
)
3972 duration
= ZEBRA_EVPN_MH_NEIGH_HOLD_TIME_DEF
;
3974 zmh_info
->neigh_hold_time
= duration
;
3979 int zebra_evpn_mh_mac_holdtime_update(struct vty
*vty
,
3980 uint32_t duration
, bool set_default
)
3983 duration
= ZEBRA_EVPN_MH_MAC_HOLD_TIME_DEF
;
3985 zmh_info
->mac_hold_time
= duration
;
3990 int zebra_evpn_mh_startup_delay_update(struct vty
*vty
, uint32_t duration
,
3994 duration
= ZEBRA_EVPN_MH_STARTUP_DELAY_DEF
;
3996 zmh_info
->startup_delay_time
= duration
;
3998 /* if startup_delay_timer is running allow it to be adjusted
4001 if (zmh_info
->startup_delay_timer
)
4002 zebra_evpn_mh_startup_delay_timer_start("config");
4007 int zebra_evpn_mh_redirect_off(struct vty
*vty
, bool redirect_off
)
4009 /* This knob needs to be set before ESs are configured
4010 * i.e. cannot be changed on the fly
4013 zmh_info
->flags
|= ZEBRA_EVPN_MH_REDIRECT_OFF
;
4015 zmh_info
->flags
&= ~ZEBRA_EVPN_MH_REDIRECT_OFF
;
4020 void zebra_evpn_interface_init(void)
4022 install_element(INTERFACE_NODE
, &zebra_evpn_es_id_cmd
);
4023 install_element(INTERFACE_NODE
, &zebra_evpn_es_sys_mac_cmd
);
4024 install_element(INTERFACE_NODE
, &zebra_evpn_es_pref_cmd
);
4025 install_element(INTERFACE_NODE
, &zebra_evpn_es_bypass_cmd
);
4026 install_element(INTERFACE_NODE
, &zebra_evpn_mh_uplink_cmd
);
4029 void zebra_evpn_mh_init(void)
4031 zrouter
.mh_info
= XCALLOC(MTYPE_ZMH_INFO
, sizeof(*zrouter
.mh_info
));
4033 zmh_info
->mac_hold_time
= ZEBRA_EVPN_MH_MAC_HOLD_TIME_DEF
;
4034 zmh_info
->neigh_hold_time
= ZEBRA_EVPN_MH_NEIGH_HOLD_TIME_DEF
;
4035 /* setup ES tables */
4036 RB_INIT(zebra_es_rb_head
, &zmh_info
->es_rb_tree
);
4037 zmh_info
->local_es_list
= list_new();
4038 listset_app_node_mem(zmh_info
->local_es_list
);
4040 bf_init(zmh_info
->nh_id_bitmap
, EVPN_NH_ID_MAX
);
4041 bf_assign_zero_index(zmh_info
->nh_id_bitmap
);
4042 zmh_info
->nhg_table
= hash_create(zebra_evpn_nhg_hash_keymake
,
4043 zebra_evpn_nhg_cmp
, "l2 NHG table");
4044 zmh_info
->nh_ip_table
=
4045 hash_create(zebra_evpn_nh_ip_hash_keymake
, zebra_evpn_nh_ip_cmp
,
4048 /* setup broadcast domain tables */
4049 zmh_info
->evpn_vlan_table
= hash_create(zebra_evpn_acc_vl_hash_keymake
,
4050 zebra_evpn_acc_vl_cmp
, "access VLAN hash table");
4052 zmh_info
->startup_delay_time
= ZEBRA_EVPN_MH_STARTUP_DELAY_DEF
;
4053 zebra_evpn_mh_startup_delay_timer_start("init");
4056 void zebra_evpn_mh_terminate(void)
4058 list_delete(&zmh_info
->local_es_list
);
4060 hash_iterate(zmh_info
->evpn_vlan_table
,
4061 zebra_evpn_acc_vl_cleanup_all
, NULL
);
4062 hash_free(zmh_info
->evpn_vlan_table
);
4063 hash_free(zmh_info
->nhg_table
);
4064 hash_free(zmh_info
->nh_ip_table
);
4065 bf_free(zmh_info
->nh_id_bitmap
);