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 RB_INSERT(zebra_es_evi_rb_head
, &zevpn
->es_evi_rb_tree
, es_evi
);
118 /* add to the ES's VNI list */
119 listnode_init(&es_evi
->es_listnode
, es_evi
);
120 listnode_add(es
->es_evi_list
, &es_evi
->es_listnode
);
122 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
123 zlog_debug("es %s evi %d new",
124 es_evi
->es
->esi_str
, es_evi
->zevpn
->vni
);
129 /* Evaluate if the es_evi is ready to be sent BGP -
130 * 1. If it is ready an add is sent to BGP
131 * 2. If it is not ready a del is sent (if the ES had been previously added
134 static void zebra_evpn_es_evi_re_eval_send_to_client(
135 struct zebra_evpn_es_evi
*es_evi
)
140 old_ready
= !!(es_evi
->flags
& ZEBRA_EVPNES_EVI_READY_FOR_BGP
);
142 /* ES and L2-VNI have to be individually ready for BGP */
143 if ((es_evi
->flags
& ZEBRA_EVPNES_EVI_LOCAL
) &&
144 (es_evi
->es
->flags
& ZEBRA_EVPNES_READY_FOR_BGP
) &&
145 zebra_evpn_send_to_client_ok(es_evi
->zevpn
))
146 es_evi
->flags
|= ZEBRA_EVPNES_EVI_READY_FOR_BGP
;
148 es_evi
->flags
&= ~ZEBRA_EVPNES_EVI_READY_FOR_BGP
;
150 new_ready
= !!(es_evi
->flags
& ZEBRA_EVPNES_EVI_READY_FOR_BGP
);
152 if (old_ready
== new_ready
)
156 zebra_evpn_es_evi_send_to_client(es_evi
->es
, es_evi
->zevpn
,
159 zebra_evpn_es_evi_send_to_client(es_evi
->es
, es_evi
->zevpn
,
163 /* remove the ES-EVI from the per-L2-VNI and per-ES tables and free
166 static void zebra_evpn_es_evi_free(struct zebra_evpn_es_evi
*es_evi
)
168 struct zebra_evpn_es
*es
= es_evi
->es
;
169 struct zebra_evpn
*zevpn
= es_evi
->zevpn
;
171 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
172 zlog_debug("es %s evi %d free",
173 es_evi
->es
->esi_str
, es_evi
->zevpn
->vni
);
175 /* remove from the ES's VNI list */
176 list_delete_node(es
->es_evi_list
, &es_evi
->es_listnode
);
178 /* remove from the VNI-ESI rb tree */
179 RB_REMOVE(zebra_es_evi_rb_head
, &zevpn
->es_evi_rb_tree
, es_evi
);
181 /* remove from the VNI-ESI rb tree */
182 XFREE(MTYPE_ZES_EVI
, es_evi
);
185 /* find the ES-EVI in the per-L2-VNI RB tree */
186 struct zebra_evpn_es_evi
*zebra_evpn_es_evi_find(struct zebra_evpn_es
*es
,
187 struct zebra_evpn
*zevpn
)
189 struct zebra_evpn_es_evi es_evi
;
193 return RB_FIND(zebra_es_evi_rb_head
, &zevpn
->es_evi_rb_tree
, &es_evi
);
196 /* Tell BGP about an ES-EVI deletion and then delete it */
197 static void zebra_evpn_local_es_evi_do_del(struct zebra_evpn_es_evi
*es_evi
)
199 if (!(es_evi
->flags
& ZEBRA_EVPNES_EVI_LOCAL
))
202 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
203 zlog_debug("local es %s evi %d del",
204 es_evi
->es
->esi_str
, es_evi
->zevpn
->vni
);
206 if (es_evi
->flags
& ZEBRA_EVPNES_EVI_READY_FOR_BGP
) {
207 /* send a del only if add was sent for it earlier */
208 zebra_evpn_es_evi_send_to_client(es_evi
->es
,
209 es_evi
->zevpn
, false /* add */);
212 /* delete it from the EVPN's local list */
213 list_delete_node(es_evi
->zevpn
->local_es_evi_list
,
214 &es_evi
->l2vni_listnode
);
216 es_evi
->flags
&= ~ZEBRA_EVPNES_EVI_LOCAL
;
217 zebra_evpn_es_evi_free(es_evi
);
219 static void zebra_evpn_local_es_evi_del(struct zebra_evpn_es
*es
,
220 struct zebra_evpn
*zevpn
)
222 struct zebra_evpn_es_evi
*es_evi
;
224 es_evi
= zebra_evpn_es_evi_find(es
, zevpn
);
226 zebra_evpn_local_es_evi_do_del(es_evi
);
229 /* If there are any existing MAC entries for this es/zevpn we need
230 * to install it in the dataplane.
232 * Note: primary purpose of this is to handle es del/re-add windows where
233 * sync MAC entries may be added by bgpd before the es-evi membership is
234 * created in the dataplane and in zebra
236 static void zebra_evpn_es_evi_mac_install(struct zebra_evpn_es_evi
*es_evi
)
238 struct zebra_mac
*mac
;
239 struct listnode
*node
;
240 struct zebra_evpn_es
*es
= es_evi
->es
;
242 if (listcount(es
->mac_list
) && IS_ZEBRA_DEBUG_EVPN_MH_ES
)
243 zlog_debug("dp-mac install on es %s evi %d add", es
->esi_str
,
246 for (ALL_LIST_ELEMENTS_RO(es
->mac_list
, node
, mac
)) {
247 if (mac
->zevpn
!= es_evi
->zevpn
)
250 if (!CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
))
253 zebra_evpn_sync_mac_dp_install(mac
, false, false, __func__
);
257 /* Create an ES-EVI if it doesn't already exist and tell BGP */
258 static void zebra_evpn_local_es_evi_add(struct zebra_evpn_es
*es
,
259 struct zebra_evpn
*zevpn
)
261 struct zebra_evpn_es_evi
*es_evi
;
263 es_evi
= zebra_evpn_es_evi_find(es
, zevpn
);
265 es_evi
= zebra_evpn_es_evi_new(es
, zevpn
);
269 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
270 zlog_debug("local es %s evi %d add",
271 es_evi
->es
->esi_str
, es_evi
->zevpn
->vni
);
272 es_evi
->flags
|= ZEBRA_EVPNES_EVI_LOCAL
;
273 /* add to the EVPN's local list */
274 listnode_init(&es_evi
->l2vni_listnode
, es_evi
);
275 listnode_add(zevpn
->local_es_evi_list
, &es_evi
->l2vni_listnode
);
277 zebra_evpn_es_evi_re_eval_send_to_client(es_evi
);
279 zebra_evpn_es_evi_mac_install(es_evi
);
283 static void zebra_evpn_es_evi_show_entry(struct vty
*vty
,
284 struct zebra_evpn_es_evi
*es_evi
,
285 json_object
*json_array
)
291 json_object
*json_types
;
293 /* Separate JSON object for each es-evi entry */
294 json
= json_object_new_object();
296 json_object_string_add(json
, "esi", es_evi
->es
->esi_str
);
297 json_object_int_add(json
, "vni", es_evi
->zevpn
->vni
);
298 if (es_evi
->flags
& ZEBRA_EVPNES_EVI_LOCAL
) {
299 json_types
= json_object_new_array();
300 if (es_evi
->flags
& ZEBRA_EVPNES_EVI_LOCAL
)
301 json_array_string_add(json_types
, "local");
302 json_object_object_add(json
, "type", json_types
);
305 /* Add es-evi entry to json array */
306 json_object_array_add(json_array
, json
);
309 if (es_evi
->flags
& ZEBRA_EVPNES_EVI_LOCAL
)
310 strlcat(type_str
, "L", sizeof(type_str
));
312 vty_out(vty
, "%-8d %-30s %-4s\n",
313 es_evi
->zevpn
->vni
, es_evi
->es
->esi_str
,
319 zebra_evpn_es_evi_show_entry_detail(struct vty
*vty
,
320 struct zebra_evpn_es_evi
*es_evi
,
321 json_object
*json_array
)
327 json_object
*json_flags
;
329 /* Separate JSON object for each es-evi entry */
330 json
= json_object_new_object();
332 json_object_string_add(json
, "esi", es_evi
->es
->esi_str
);
333 json_object_int_add(json
, "vni", es_evi
->zevpn
->vni
);
335 & (ZEBRA_EVPNES_EVI_LOCAL
336 | ZEBRA_EVPNES_EVI_READY_FOR_BGP
)) {
337 json_flags
= json_object_new_array();
338 if (es_evi
->flags
& ZEBRA_EVPNES_EVI_LOCAL
)
339 json_array_string_add(json_flags
, "local");
340 if (es_evi
->flags
& ZEBRA_EVPNES_EVI_READY_FOR_BGP
)
341 json_array_string_add(json_flags
,
343 json_object_object_add(json
, "flags", json_flags
);
346 /* Add es-evi entry to json array */
347 json_object_array_add(json_array
, json
);
350 if (es_evi
->flags
& ZEBRA_EVPNES_EVI_LOCAL
)
351 strlcat(type_str
, "L", sizeof(type_str
));
353 vty_out(vty
, "VNI %d ESI: %s\n",
354 es_evi
->zevpn
->vni
, es_evi
->es
->esi_str
);
355 vty_out(vty
, " Type: %s\n", type_str
);
356 vty_out(vty
, " Ready for BGP: %s\n",
358 ZEBRA_EVPNES_EVI_READY_FOR_BGP
) ?
364 static void zebra_evpn_es_evi_show_one_evpn(struct zebra_evpn
*zevpn
,
366 json_object
*json_array
, int detail
)
368 struct zebra_evpn_es_evi
*es_evi
;
370 RB_FOREACH(es_evi
, zebra_es_evi_rb_head
, &zevpn
->es_evi_rb_tree
) {
372 zebra_evpn_es_evi_show_entry_detail(vty
, es_evi
,
375 zebra_evpn_es_evi_show_entry(vty
, es_evi
, json_array
);
379 struct evpn_mh_show_ctx
{
385 static void zebra_evpn_es_evi_show_one_evpn_hash_cb(struct hash_bucket
*bucket
,
388 struct zebra_evpn
*zevpn
= (struct zebra_evpn
*)bucket
->data
;
389 struct evpn_mh_show_ctx
*wctx
= (struct evpn_mh_show_ctx
*)ctxt
;
391 zebra_evpn_es_evi_show_one_evpn(zevpn
, wctx
->vty
,
392 wctx
->json
, wctx
->detail
);
395 void zebra_evpn_es_evi_show(struct vty
*vty
, bool uj
, int detail
)
397 json_object
*json_array
= NULL
;
398 struct zebra_vrf
*zvrf
;
399 struct evpn_mh_show_ctx wctx
;
401 zvrf
= zebra_vrf_get_evpn();
403 json_array
= json_object_new_array();
405 memset(&wctx
, 0, sizeof(wctx
));
407 wctx
.json
= json_array
;
408 wctx
.detail
= detail
;
410 if (!detail
&& !json_array
) {
411 vty_out(vty
, "Type: L local, R remote\n");
412 vty_out(vty
, "%-8s %-30s %-4s\n", "VNI", "ESI", "Type");
414 /* Display all L2-VNIs */
415 hash_iterate(zvrf
->evpn_table
, zebra_evpn_es_evi_show_one_evpn_hash_cb
,
419 vty_json(vty
, json_array
);
422 void zebra_evpn_es_evi_show_vni(struct vty
*vty
, bool uj
, vni_t vni
, int detail
)
424 json_object
*json_array
= NULL
;
425 struct zebra_evpn
*zevpn
;
427 zevpn
= zebra_evpn_lookup(vni
);
429 json_array
= json_object_new_array();
432 if (!detail
&& !json_array
) {
433 vty_out(vty
, "Type: L local, R remote\n");
434 vty_out(vty
, "%-8s %-30s %-4s\n", "VNI", "ESI", "Type");
436 zebra_evpn_es_evi_show_one_evpn(zevpn
, vty
, json_array
, detail
);
439 vty_out(vty
, "VNI %d doesn't exist\n", vni
);
443 vty_json(vty
, json_array
);
446 /* Initialize the ES tables maintained per-L2_VNI */
447 void zebra_evpn_es_evi_init(struct zebra_evpn
*zevpn
)
449 /* Initialize the ES-EVI RB tree */
450 RB_INIT(zebra_es_evi_rb_head
, &zevpn
->es_evi_rb_tree
);
452 /* Initialize the local and remote ES lists maintained for quick
455 zevpn
->local_es_evi_list
= list_new();
456 listset_app_node_mem(zevpn
->local_es_evi_list
);
459 /* Cleanup the ES info maintained per- EVPN */
460 void zebra_evpn_es_evi_cleanup(struct zebra_evpn
*zevpn
)
462 struct zebra_evpn_es_evi
*es_evi
;
463 struct zebra_evpn_es_evi
*es_evi_next
;
465 RB_FOREACH_SAFE(es_evi
, zebra_es_evi_rb_head
,
466 &zevpn
->es_evi_rb_tree
, es_evi_next
) {
467 zebra_evpn_local_es_evi_do_del(es_evi
);
470 list_delete(&zevpn
->local_es_evi_list
);
471 zebra_evpn_es_clear_base_evpn(zevpn
);
474 /* called when the oper state or bridge membership changes for the
477 void zebra_evpn_update_all_es(struct zebra_evpn
*zevpn
)
479 struct zebra_evpn_es_evi
*es_evi
;
480 struct listnode
*node
;
481 struct interface
*vlan_if
;
482 struct interface
*vxlan_if
;
483 struct zebra_if
*vxlan_zif
;
484 struct zebra_vxlan_vni
*vni
;
486 /* the EVPN is now elgible as a base for EVPN-MH */
487 if (zebra_evpn_send_to_client_ok(zevpn
))
488 zebra_evpn_es_set_base_evpn(zevpn
);
490 zebra_evpn_es_clear_base_evpn(zevpn
);
492 for (ALL_LIST_ELEMENTS_RO(zevpn
->local_es_evi_list
, node
, es_evi
))
493 zebra_evpn_es_evi_re_eval_send_to_client(es_evi
);
495 /* reinstall SVI MAC */
496 vxlan_if
= zevpn
->vxlan_if
;
498 vxlan_zif
= vxlan_if
->info
;
499 if (if_is_operative(vxlan_if
)
500 && vxlan_zif
->brslave_info
.br_if
) {
501 vni
= zebra_vxlan_if_vni_find(vxlan_zif
, zevpn
->vni
);
503 zvni_map_to_svi(vni
->access_vlan
,
504 vxlan_zif
->brslave_info
.br_if
);
506 zebra_evpn_acc_bd_svi_mac_add(vlan_if
);
511 /*****************************************************************************/
512 /* Access broadcast domains (BD)
513 * 1. These broadcast domains can be VLAN aware (in which case
514 * the key is VID) or VLAN unaware (in which case the key is
515 * 2. A VID-BD is created when a VLAN is associated with an access port or
516 * when the VLAN is associated with VXLAN_IF
517 * 3. A BD is translated into ES-EVI entries when a VNI is associated
518 * with the broadcast domain
520 /* Hash key for VLAN based broadcast domains */
521 static unsigned int zebra_evpn_acc_vl_hash_keymake(const void *p
)
523 const struct zebra_evpn_access_bd
*acc_bd
= p
;
525 return jhash_1word(acc_bd
->vid
, 0);
528 /* Compare two VLAN based broadcast domains */
529 static bool zebra_evpn_acc_vl_cmp(const void *p1
, const void *p2
)
531 const struct zebra_evpn_access_bd
*acc_bd1
= p1
;
532 const struct zebra_evpn_access_bd
*acc_bd2
= p2
;
534 if (acc_bd1
== NULL
&& acc_bd2
== NULL
)
537 if (acc_bd1
== NULL
|| acc_bd2
== NULL
)
540 return (acc_bd1
->vid
== acc_bd2
->vid
);
543 /* Lookup VLAN based broadcast domain */
544 static struct zebra_evpn_access_bd
*zebra_evpn_acc_vl_find(vlanid_t vid
)
546 struct zebra_evpn_access_bd
*acc_bd
;
547 struct zebra_evpn_access_bd tmp
;
550 acc_bd
= hash_lookup(zmh_info
->evpn_vlan_table
, &tmp
);
555 /* A new broadcast domain can be created when a VLAN member or VLAN<=>VxLAN_IF
558 static struct zebra_evpn_access_bd
*
559 zebra_evpn_acc_vl_new(vlanid_t vid
, struct interface
*br_if
)
561 struct zebra_evpn_access_bd
*acc_bd
;
562 struct interface
*vlan_if
;
564 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
565 zlog_debug("access vlan %d add", vid
);
567 acc_bd
= XCALLOC(MTYPE_ZACC_BD
, sizeof(struct zebra_evpn_access_bd
));
571 /* Initialize the mbr list */
572 acc_bd
->mbr_zifs
= list_new();
575 (void)hash_get(zmh_info
->evpn_vlan_table
, acc_bd
, hash_alloc_intern
);
577 /* check if an svi exists for the vlan */
579 vlan_if
= zvni_map_to_svi(vid
, br_if
);
581 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
582 zlog_debug("vlan %d SVI %s set", vid
,
584 acc_bd
->vlan_zif
= vlan_if
->info
;
590 /* Free VLAN based broadcast domain -
591 * This just frees appropriate memory, caller should have taken other
594 static void zebra_evpn_acc_vl_free(struct zebra_evpn_access_bd
*acc_bd
)
596 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
597 zlog_debug("access vlan %d del", acc_bd
->vid
);
599 if (acc_bd
->vlan_zif
&& acc_bd
->zevpn
&& acc_bd
->zevpn
->mac_table
)
600 zebra_evpn_mac_svi_del(acc_bd
->vlan_zif
->ifp
, acc_bd
->zevpn
);
602 /* cleanup resources maintained against the ES */
603 list_delete(&acc_bd
->mbr_zifs
);
605 /* remove EVI from various tables */
606 hash_release(zmh_info
->evpn_vlan_table
, acc_bd
);
608 XFREE(MTYPE_ZACC_BD
, acc_bd
);
611 static void zebra_evpn_acc_vl_cleanup_all(struct hash_bucket
*bucket
, void *arg
)
613 struct zebra_evpn_access_bd
*acc_bd
= bucket
->data
;
615 zebra_evpn_acc_vl_free(acc_bd
);
618 /* called when a bd mbr is removed or VxLAN_IF is diassociated from the access
621 static void zebra_evpn_acc_bd_free_on_deref(struct zebra_evpn_access_bd
*acc_bd
)
623 if (!list_isempty(acc_bd
->mbr_zifs
) || acc_bd
->vxlan_zif
)
626 /* if there are no references free the EVI */
627 zebra_evpn_acc_vl_free(acc_bd
);
630 /* called when a SVI is goes up/down */
631 void zebra_evpn_acc_bd_svi_set(struct zebra_if
*vlan_zif
,
632 struct zebra_if
*br_zif
, bool is_up
)
634 struct zebra_evpn_access_bd
*acc_bd
;
635 struct zebra_l2info_bridge
*br
;
637 struct zebra_if
*tmp_br_zif
= br_zif
;
640 if (!vlan_zif
->link
|| !vlan_zif
->link
->info
)
643 tmp_br_zif
= vlan_zif
->link
->info
;
646 br
= &tmp_br_zif
->l2info
.br
;
647 /* ignore vlan unaware bridges */
651 vid
= vlan_zif
->l2info
.vl
.vid
;
652 acc_bd
= zebra_evpn_acc_vl_find(vid
);
657 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
658 zlog_debug("vlan %d SVI %s set", vid
,
659 vlan_zif
->ifp
->name
);
661 acc_bd
->vlan_zif
= vlan_zif
;
663 zebra_evpn_mac_svi_add(acc_bd
->vlan_zif
->ifp
,
665 } else if (acc_bd
->vlan_zif
) {
666 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
667 zlog_debug("vlan %d SVI clear", vid
);
668 acc_bd
->vlan_zif
= NULL
;
669 if (acc_bd
->zevpn
&& acc_bd
->zevpn
->mac_table
)
670 zebra_evpn_mac_svi_del(vlan_zif
->ifp
, acc_bd
->zevpn
);
674 /* On some events macs are force-flushed. This api can be used to reinstate
675 * the svi-mac after such cleanup-events.
677 void zebra_evpn_acc_bd_svi_mac_add(struct interface
*vlan_if
)
679 zebra_evpn_acc_bd_svi_set(vlan_if
->info
, NULL
,
680 if_is_operative(vlan_if
));
683 /* called when a EVPN-L2VNI is set or cleared against a BD */
684 static void zebra_evpn_acc_bd_evpn_set(struct zebra_evpn_access_bd
*acc_bd
,
685 struct zebra_evpn
*zevpn
,
686 struct zebra_evpn
*old_zevpn
)
688 struct zebra_if
*zif
;
689 struct listnode
*node
;
691 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
692 zlog_debug("access vlan %d l2-vni %u set",
693 acc_bd
->vid
, zevpn
? zevpn
->vni
: 0);
695 for (ALL_LIST_ELEMENTS_RO(acc_bd
->mbr_zifs
, node
, zif
)) {
696 if (!zif
->es_info
.es
)
700 zebra_evpn_local_es_evi_add(zif
->es_info
.es
, zevpn
);
702 zebra_evpn_local_es_evi_del(zif
->es_info
.es
, old_zevpn
);
705 if (acc_bd
->vlan_zif
) {
707 zebra_evpn_mac_svi_add(acc_bd
->vlan_zif
->ifp
,
709 else if (old_zevpn
&& old_zevpn
->mac_table
)
710 zebra_evpn_mac_svi_del(acc_bd
->vlan_zif
->ifp
,
715 /* handle VLAN->VxLAN_IF association */
716 void zebra_evpn_vl_vxl_ref(uint16_t vid
, vni_t vni_id
,
717 struct zebra_if
*vxlan_zif
)
720 struct zebra_evpn_access_bd
*acc_bd
;
721 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_vni
= acc_bd
->vni
;
736 if (vni_id
== old_vni
)
739 acc_bd
->vni
= vni_id
;
740 acc_bd
->vxlan_zif
= vxlan_zif
;
742 old_zevpn
= acc_bd
->zevpn
;
743 acc_bd
->zevpn
= zebra_evpn_lookup(vni_id
);
744 if (acc_bd
->zevpn
== old_zevpn
)
747 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
748 zlog_debug("access vlan %d vni %u ref", acc_bd
->vid
, vni_id
);
750 zlog_err("access vlan %d vni %u ref", acc_bd
->vid
, vni_id
);
753 zebra_evpn_acc_bd_evpn_set(acc_bd
, NULL
, old_zevpn
);
756 zebra_evpn_acc_bd_evpn_set(acc_bd
, acc_bd
->zevpn
, NULL
);
759 /* handle VLAN->VxLAN_IF deref */
760 void zebra_evpn_vl_vxl_deref(uint16_t vid
, vni_t vni_id
,
761 struct zebra_if
*vxlan_zif
)
763 struct zebra_evpn_access_bd
*acc_bd
;
771 acc_bd
= zebra_evpn_acc_vl_find(vid
);
775 /* clear vxlan_if only if it matches */
776 if (acc_bd
->vni
!= vni_id
)
779 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
780 zlog_debug("access vlan %d vni %u deref", acc_bd
->vid
, vni_id
);
783 zebra_evpn_acc_bd_evpn_set(acc_bd
, NULL
, acc_bd
->zevpn
);
785 acc_bd
->zevpn
= NULL
;
786 acc_bd
->vxlan_zif
= NULL
;
789 /* if there are no other references the access_bd can be freed */
790 zebra_evpn_acc_bd_free_on_deref(acc_bd
);
793 /* handle EVPN add/del */
794 void zebra_evpn_vxl_evpn_set(struct zebra_if
*zif
, struct zebra_evpn
*zevpn
,
797 struct zebra_vxlan_vni
*vni
;
798 struct zebra_evpn_access_bd
*acc_bd
;
803 /* locate access_bd associated with the vxlan device */
804 vni
= zebra_vxlan_if_vni_find(zif
, zevpn
->vni
);
808 acc_bd
= zebra_evpn_acc_vl_find(vni
->access_vlan
);
813 zebra_evpn_es_set_base_evpn(zevpn
);
814 if (acc_bd
->zevpn
!= zevpn
) {
815 acc_bd
->zevpn
= zevpn
;
816 zebra_evpn_acc_bd_evpn_set(acc_bd
, zevpn
, NULL
);
820 struct zebra_evpn
*old_zevpn
= acc_bd
->zevpn
;
821 acc_bd
->zevpn
= NULL
;
822 zebra_evpn_acc_bd_evpn_set(acc_bd
, NULL
, old_zevpn
);
827 /* handle addition of new VLAN members */
828 void zebra_evpn_vl_mbr_ref(uint16_t vid
, struct zebra_if
*zif
)
830 struct zebra_evpn_access_bd
*acc_bd
;
835 acc_bd
= zebra_evpn_acc_vl_find(vid
);
837 acc_bd
= zebra_evpn_acc_vl_new(vid
, zif
->brslave_info
.br_if
);
839 if (listnode_lookup(acc_bd
->mbr_zifs
, zif
))
842 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
843 zlog_debug("access vlan %d mbr %s ref",
844 vid
, zif
->ifp
->name
);
846 listnode_add(acc_bd
->mbr_zifs
, zif
);
847 if (acc_bd
->zevpn
&& zif
->es_info
.es
)
848 zebra_evpn_local_es_evi_add(zif
->es_info
.es
, acc_bd
->zevpn
);
851 /* handle deletion of VLAN members */
852 void zebra_evpn_vl_mbr_deref(uint16_t vid
, struct zebra_if
*zif
)
854 struct zebra_evpn_access_bd
*acc_bd
;
855 struct listnode
*node
;
860 acc_bd
= zebra_evpn_acc_vl_find(vid
);
864 node
= listnode_lookup(acc_bd
->mbr_zifs
, zif
);
868 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
869 zlog_debug("access vlan %d mbr %s deref",
870 vid
, zif
->ifp
->name
);
872 list_delete_node(acc_bd
->mbr_zifs
, node
);
874 if (acc_bd
->zevpn
&& zif
->es_info
.es
)
875 zebra_evpn_local_es_evi_del(zif
->es_info
.es
, acc_bd
->zevpn
);
877 /* if there are no other references the access_bd can be freed */
878 zebra_evpn_acc_bd_free_on_deref(acc_bd
);
881 static void zebra_evpn_acc_vl_adv_svi_mac_cb(struct hash_bucket
*bucket
,
884 struct zebra_evpn_access_bd
*acc_bd
= bucket
->data
;
886 if (acc_bd
->vlan_zif
&& acc_bd
->zevpn
)
887 zebra_evpn_mac_svi_add(acc_bd
->vlan_zif
->ifp
, acc_bd
->zevpn
);
890 /* called when advertise SVI MAC is enabled on the switch */
891 static void zebra_evpn_acc_vl_adv_svi_mac_all(void)
893 hash_iterate(zmh_info
->evpn_vlan_table
,
894 zebra_evpn_acc_vl_adv_svi_mac_cb
, NULL
);
897 static void zebra_evpn_acc_vl_json_fill(struct zebra_evpn_access_bd
*acc_bd
,
898 json_object
*json
, bool detail
)
900 json_object_int_add(json
, "vlan", acc_bd
->vid
);
901 if (acc_bd
->vxlan_zif
)
902 json_object_string_add(json
, "vxlanIf",
903 acc_bd
->vxlan_zif
->ifp
->name
);
905 json_object_int_add(json
, "vni", acc_bd
->zevpn
->vni
);
906 if (acc_bd
->mbr_zifs
)
907 json_object_int_add(json
, "memberIfCount",
908 listcount(acc_bd
->mbr_zifs
));
911 json_object
*json_mbrs
;
912 json_object
*json_mbr
;
913 struct zebra_if
*zif
;
914 struct listnode
*node
;
917 json_mbrs
= json_object_new_array();
918 for (ALL_LIST_ELEMENTS_RO(acc_bd
->mbr_zifs
, node
, zif
)) {
919 json_mbr
= json_object_new_object();
920 json_object_string_add(json_mbr
, "ifName",
922 json_object_array_add(json_mbrs
, json_mbr
);
924 json_object_object_add(json
, "members", json_mbrs
);
928 static void zebra_evpn_acc_vl_show_entry_detail(struct vty
*vty
,
929 struct zebra_evpn_access_bd
*acc_bd
, json_object
*json
)
931 struct zebra_if
*zif
;
932 struct listnode
*node
;
935 zebra_evpn_acc_vl_json_fill(acc_bd
, json
, true);
937 vty_out(vty
, "VLAN: %u\n", acc_bd
->vid
);
938 vty_out(vty
, " VxLAN Interface: %s\n",
940 acc_bd
->vxlan_zif
->ifp
->name
: "-");
941 vty_out(vty
, " SVI: %s\n",
942 acc_bd
->vlan_zif
? acc_bd
->vlan_zif
->ifp
->name
: "-");
943 vty_out(vty
, " L2-VNI: %d\n",
944 acc_bd
->zevpn
? acc_bd
->zevpn
->vni
: 0);
945 vty_out(vty
, " Member Count: %d\n",
946 listcount(acc_bd
->mbr_zifs
));
947 vty_out(vty
, " Members: \n");
948 for (ALL_LIST_ELEMENTS_RO(acc_bd
->mbr_zifs
, node
, zif
))
949 vty_out(vty
, " %s\n", zif
->ifp
->name
);
954 static void zebra_evpn_acc_vl_show_entry(struct vty
*vty
,
955 struct zebra_evpn_access_bd
*acc_bd
, json_object
*json
)
958 zebra_evpn_acc_vl_json_fill(acc_bd
, json
, false);
960 vty_out(vty
, "%-5u %-15s %-8d %-15s %u\n", acc_bd
->vid
,
961 acc_bd
->vlan_zif
? acc_bd
->vlan_zif
->ifp
->name
: "-",
962 acc_bd
->zevpn
? acc_bd
->zevpn
->vni
: 0,
963 acc_bd
->vxlan_zif
? acc_bd
->vxlan_zif
->ifp
->name
: "-",
964 listcount(acc_bd
->mbr_zifs
));
968 static void zebra_evpn_acc_vl_show_hash(struct hash_bucket
*bucket
, void *ctxt
)
970 struct evpn_mh_show_ctx
*wctx
= ctxt
;
971 struct zebra_evpn_access_bd
*acc_bd
= bucket
->data
;
972 json_object
*json
= NULL
;
975 json
= json_object_new_object();
977 zebra_evpn_acc_vl_show_entry_detail(wctx
->vty
, acc_bd
, json
);
979 zebra_evpn_acc_vl_show_entry(wctx
->vty
, acc_bd
, json
);
981 json_object_array_add(wctx
->json
, json
);
984 void zebra_evpn_acc_vl_show(struct vty
*vty
, bool uj
)
986 struct evpn_mh_show_ctx wctx
;
987 json_object
*json_array
= NULL
;
990 json_array
= json_object_new_array();
992 memset(&wctx
, 0, sizeof(wctx
));
994 wctx
.json
= json_array
;
998 vty_out(vty
, "%-5s %-15s %-8s %-15s %s\n", "VLAN", "SVI",
999 "L2-VNI", "VXLAN-IF", "# Members");
1001 hash_iterate(zmh_info
->evpn_vlan_table
, zebra_evpn_acc_vl_show_hash
,
1005 vty_json(vty
, json_array
);
1008 void zebra_evpn_acc_vl_show_detail(struct vty
*vty
, bool uj
)
1010 struct evpn_mh_show_ctx wctx
;
1011 json_object
*json_array
= NULL
;
1014 json_array
= json_object_new_array();
1015 memset(&wctx
, 0, sizeof(wctx
));
1017 wctx
.json
= json_array
;
1020 hash_iterate(zmh_info
->evpn_vlan_table
, zebra_evpn_acc_vl_show_hash
,
1024 vty_json(vty
, json_array
);
1027 void zebra_evpn_acc_vl_show_vid(struct vty
*vty
, bool uj
, vlanid_t vid
)
1029 json_object
*json
= NULL
;
1030 struct zebra_evpn_access_bd
*acc_bd
;
1033 json
= json_object_new_object();
1035 acc_bd
= zebra_evpn_acc_vl_find(vid
);
1037 zebra_evpn_acc_vl_show_entry_detail(vty
, acc_bd
, json
);
1040 vty_out(vty
, "VLAN %u not present\n", vid
);
1044 vty_json(vty
, json
);
1047 /* Initialize VLAN member bitmap on an interface. Although VLAN membership
1048 * is independent of EVPN we only process it if its of interest to EVPN-MH
1049 * i.e. on access ports that can be setup as Ethernet Segments. And that is
1050 * intended as an optimization.
1052 void zebra_evpn_if_init(struct zebra_if
*zif
)
1054 if (!zebra_evpn_is_if_es_capable(zif
))
1057 if (!bf_is_inited(zif
->vlan_bitmap
))
1058 bf_init(zif
->vlan_bitmap
, IF_VLAN_BITMAP_MAX
);
1060 /* if an es_id and sysmac are already present against the interface
1063 zebra_evpn_local_es_update(zif
, &zif
->es_info
.esi
);
1066 /* handle deletion of an access port by removing it from all associated
1067 * broadcast domains.
1069 void zebra_evpn_if_cleanup(struct zebra_if
*zif
)
1072 struct zebra_evpn_es
*es
;
1074 if (bf_is_inited(zif
->vlan_bitmap
)) {
1075 bf_for_each_set_bit(zif
->vlan_bitmap
, vid
, IF_VLAN_BITMAP_MAX
)
1077 zebra_evpn_vl_mbr_deref(vid
, zif
);
1080 bf_free(zif
->vlan_bitmap
);
1083 /* Delete associated Ethernet Segment */
1084 es
= zif
->es_info
.es
;
1086 zebra_evpn_local_es_del(&es
);
1089 /*****************************************************************************
1090 * L2 NH/NHG Management
1091 * A L2 NH entry is programmed in the kernel for every ES-VTEP entry. This
1092 * NH is then added to the L2-ECMP-NHG associated with the ES.
1094 static uint32_t zebra_evpn_nhid_alloc(struct zebra_evpn_es
*es
)
1099 bf_assign_index(zmh_info
->nh_id_bitmap
, id
);
1105 nh_id
= id
| EVPN_NHG_ID_TYPE_BIT
;
1106 /* Add to NHG hash */
1108 (void)hash_get(zmh_info
->nhg_table
, es
, hash_alloc_intern
);
1110 nh_id
= id
| EVPN_NH_ID_TYPE_BIT
;
1116 static void zebra_evpn_nhid_free(uint32_t nh_id
, struct zebra_evpn_es
*es
)
1118 uint32_t id
= (nh_id
& EVPN_NH_ID_VAL_MASK
);
1124 hash_release(zmh_info
->nhg_table
, es
);
1128 bf_release_index(zmh_info
->nh_id_bitmap
, id
);
1131 static unsigned int zebra_evpn_nh_ip_hash_keymake(const void *p
)
1133 const struct zebra_evpn_l2_nh
*nh
= p
;
1135 return jhash_1word(nh
->vtep_ip
.s_addr
, 0);
1138 static bool zebra_evpn_nh_ip_cmp(const void *p1
, const void *p2
)
1140 const struct zebra_evpn_l2_nh
*nh1
= p1
;
1141 const struct zebra_evpn_l2_nh
*nh2
= p2
;
1143 if (nh1
== NULL
&& nh2
== NULL
)
1146 if (nh1
== NULL
|| nh2
== NULL
)
1149 return (nh1
->vtep_ip
.s_addr
== nh2
->vtep_ip
.s_addr
);
1152 static unsigned int zebra_evpn_nhg_hash_keymake(const void *p
)
1154 const struct zebra_evpn_es
*es
= p
;
1156 return jhash_1word(es
->nhg_id
, 0);
1159 static bool zebra_evpn_nhg_cmp(const void *p1
, const void *p2
)
1161 const struct zebra_evpn_es
*es1
= p1
;
1162 const struct zebra_evpn_es
*es2
= p2
;
1164 if (es1
== NULL
&& es2
== NULL
)
1167 if (es1
== NULL
|| es2
== NULL
)
1170 return (es1
->nhg_id
== es2
->nhg_id
);
1173 /* Lookup ES using the NHG id associated with it */
1174 static struct zebra_evpn_es
*zebra_evpn_nhg_find(uint32_t nhg_id
)
1176 struct zebra_evpn_es
*es
;
1177 struct zebra_evpn_es tmp
;
1179 tmp
.nhg_id
= nhg_id
;
1180 es
= hash_lookup(zmh_info
->nhg_table
, &tmp
);
1185 /* Returns TRUE if the NHG is associated with a local ES */
1186 bool zebra_evpn_nhg_is_local_es(uint32_t nhg_id
,
1187 struct zebra_evpn_es
**local_es
)
1189 struct zebra_evpn_es
*es
;
1191 es
= zebra_evpn_nhg_find(nhg_id
);
1192 if (es
&& (es
->flags
& ZEBRA_EVPNES_LOCAL
)) {
1201 /* update remote macs associated with the ES */
1202 static void zebra_evpn_nhg_mac_update(struct zebra_evpn_es
*es
)
1204 struct zebra_mac
*mac
;
1205 struct listnode
*node
;
1208 local_via_nw
= zebra_evpn_es_local_mac_via_network_port(es
);
1209 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
|| IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
1210 zlog_debug("mac update on es %s nhg %s", es
->esi_str
,
1211 (es
->flags
& ZEBRA_EVPNES_NHG_ACTIVE
)
1215 for (ALL_LIST_ELEMENTS_RO(es
->mac_list
, node
, mac
)) {
1216 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE
)
1217 || (local_via_nw
&& CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
)
1218 && zebra_evpn_mac_is_static(mac
))) {
1219 if (es
->flags
& ZEBRA_EVPNES_NHG_ACTIVE
) {
1220 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
1222 "%smac %pEA install via es %s nhg 0x%x",
1223 (mac
->flags
& ZEBRA_MAC_REMOTE
)
1226 &mac
->macaddr
, es
->esi_str
,
1228 zebra_evpn_rem_mac_install(
1229 mac
->zevpn
, mac
, false /*was_static*/);
1231 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
1233 "%smac %pEA un-install es %s",
1234 (mac
->flags
& ZEBRA_MAC_REMOTE
)
1237 &mac
->macaddr
, es
->esi_str
);
1238 zebra_evpn_rem_mac_uninstall(mac
->zevpn
, mac
,
1245 /* The MAC ECMP group is activated on the first VTEP */
1246 static void zebra_evpn_nhg_update(struct zebra_evpn_es
*es
)
1248 uint32_t nh_cnt
= 0;
1249 struct nh_grp nh_ids
[ES_VTEP_MAX_CNT
];
1250 struct zebra_evpn_es_vtep
*es_vtep
;
1251 struct listnode
*node
;
1256 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
1260 if (nh_cnt
>= ES_VTEP_MAX_CNT
)
1263 memset(&nh_ids
[nh_cnt
], 0, sizeof(struct nh_grp
));
1264 nh_ids
[nh_cnt
].id
= es_vtep
->nh
->nh_id
;
1269 if (IS_ZEBRA_DEBUG_EVPN_MH_NH
) {
1270 char nh_str
[ES_VTEP_LIST_STR_SZ
];
1275 for (i
= 0; i
< nh_cnt
; ++i
) {
1276 snprintf(nh_buf
, sizeof(nh_buf
), "%u ",
1278 strlcat(nh_str
, nh_buf
, sizeof(nh_str
));
1280 zlog_debug("es %s nhg %u add %s", es
->esi_str
,
1281 es
->nhg_id
, nh_str
);
1284 kernel_upd_mac_nhg(es
->nhg_id
, nh_cnt
, nh_ids
);
1285 if (!(es
->flags
& ZEBRA_EVPNES_NHG_ACTIVE
)) {
1286 es
->flags
|= ZEBRA_EVPNES_NHG_ACTIVE
;
1287 /* add backup NHG to the br-port */
1288 if ((es
->flags
& ZEBRA_EVPNES_LOCAL
))
1289 zebra_evpn_es_br_port_dplane_update(es
,
1291 zebra_evpn_nhg_mac_update(es
);
1294 if (es
->flags
& ZEBRA_EVPNES_NHG_ACTIVE
) {
1295 if (IS_ZEBRA_DEBUG_EVPN_MH_NH
)
1296 zlog_debug("es %s nhg %u del", es
->esi_str
,
1298 es
->flags
&= ~ZEBRA_EVPNES_NHG_ACTIVE
;
1299 /* remove backup NHG from the br-port */
1300 if ((es
->flags
& ZEBRA_EVPNES_LOCAL
))
1301 zebra_evpn_es_br_port_dplane_update(es
,
1303 zebra_evpn_nhg_mac_update(es
);
1304 kernel_del_mac_nhg(es
->nhg_id
);
1310 static void zebra_evpn_es_l2_nh_show_entry(struct zebra_evpn_l2_nh
*nh
,
1312 json_object
*json_array
)
1315 json_object
*json
= NULL
;
1317 json
= json_object_new_object();
1318 json_object_string_addf(json
, "vtep", "%pI4", &nh
->vtep_ip
);
1319 json_object_int_add(json
, "nhId", nh
->nh_id
);
1320 json_object_int_add(json
, "refCnt", nh
->ref_cnt
);
1322 json_object_array_add(json_array
, json
);
1324 vty_out(vty
, "%-16pI4 %-10u %u\n", &nh
->vtep_ip
, nh
->nh_id
,
1329 static void zebra_evpn_l2_nh_show_cb(struct hash_bucket
*bucket
, void *ctxt
)
1331 struct zebra_evpn_l2_nh
*nh
= (struct zebra_evpn_l2_nh
*)bucket
->data
;
1332 struct evpn_mh_show_ctx
*wctx
= (struct evpn_mh_show_ctx
*)ctxt
;
1334 zebra_evpn_es_l2_nh_show_entry(nh
, wctx
->vty
, wctx
->json
);
1337 void zebra_evpn_l2_nh_show(struct vty
*vty
, bool uj
)
1339 struct evpn_mh_show_ctx wctx
;
1340 json_object
*json_array
= NULL
;
1343 json_array
= json_object_new_array();
1345 vty_out(vty
, "%-16s %-10s %s\n", "VTEP", "NH id", "#ES");
1348 memset(&wctx
, 0, sizeof(wctx
));
1350 wctx
.json
= json_array
;
1352 hash_iterate(zmh_info
->nh_ip_table
, zebra_evpn_l2_nh_show_cb
, &wctx
);
1355 vty_json(vty
, json_array
);
1358 static struct zebra_evpn_l2_nh
*zebra_evpn_l2_nh_find(struct in_addr vtep_ip
)
1360 struct zebra_evpn_l2_nh
*nh
;
1361 struct zebra_evpn_l2_nh tmp
;
1363 tmp
.vtep_ip
.s_addr
= vtep_ip
.s_addr
;
1364 nh
= hash_lookup(zmh_info
->nh_ip_table
, &tmp
);
1369 static struct zebra_evpn_l2_nh
*zebra_evpn_l2_nh_alloc(struct in_addr vtep_ip
)
1371 struct zebra_evpn_l2_nh
*nh
;
1373 nh
= XCALLOC(MTYPE_L2_NH
, sizeof(*nh
));
1374 nh
->vtep_ip
= vtep_ip
;
1375 (void)hash_get(zmh_info
->nh_ip_table
, nh
, hash_alloc_intern
);
1377 nh
->nh_id
= zebra_evpn_nhid_alloc(NULL
);
1379 hash_release(zmh_info
->nh_ip_table
, nh
);
1380 XFREE(MTYPE_L2_NH
, nh
);
1384 /* install the NH in the dataplane */
1385 kernel_upd_mac_nh(nh
->nh_id
, nh
->vtep_ip
);
1390 static void zebra_evpn_l2_nh_free(struct zebra_evpn_l2_nh
*nh
)
1392 /* delete the NH from the dataplane */
1393 kernel_del_mac_nh(nh
->nh_id
);
1395 zebra_evpn_nhid_free(nh
->nh_id
, NULL
);
1396 hash_release(zmh_info
->nh_ip_table
, nh
);
1397 XFREE(MTYPE_L2_NH
, nh
);
1400 static void zebra_evpn_l2_nh_es_vtep_ref(struct zebra_evpn_es_vtep
*es_vtep
)
1405 es_vtep
->nh
= zebra_evpn_l2_nh_find(es_vtep
->vtep_ip
);
1407 es_vtep
->nh
= zebra_evpn_l2_nh_alloc(es_vtep
->vtep_ip
);
1410 zlog_warn("es %s vtep %pI4 nh ref failed", es_vtep
->es
->esi_str
,
1415 ++es_vtep
->nh
->ref_cnt
;
1417 if (IS_ZEBRA_DEBUG_EVPN_MH_NH
)
1418 zlog_debug("es %s vtep %pI4 nh %u ref %u", es_vtep
->es
->esi_str
,
1419 &es_vtep
->vtep_ip
, es_vtep
->nh
->nh_id
,
1420 es_vtep
->nh
->ref_cnt
);
1422 /* add the NH to the parent NHG */
1423 zebra_evpn_nhg_update(es_vtep
->es
);
1426 static void zebra_evpn_l2_nh_es_vtep_deref(struct zebra_evpn_es_vtep
*es_vtep
)
1428 struct zebra_evpn_l2_nh
*nh
= es_vtep
->nh
;
1437 if (IS_ZEBRA_DEBUG_EVPN_MH_NH
)
1438 zlog_debug("es %s vtep %pI4 nh %u deref %u",
1439 es_vtep
->es
->esi_str
, &es_vtep
->vtep_ip
, nh
->nh_id
,
1442 /* remove the NH from the parent NHG */
1443 zebra_evpn_nhg_update(es_vtep
->es
);
1445 /* uninstall the NH */
1447 zebra_evpn_l2_nh_free(nh
);
1450 /*****************************************************************************/
1451 /* Ethernet Segment Management
1452 * 1. Ethernet Segment is a collection of links attached to the same
1453 * server (MHD) or switch (MHN)
1454 * 2. An Ethernet Segment can span multiple PEs and is identified by the
1456 * 3. Zebra manages the local ESI configuration.
1457 * 4. It also maintains the aliasing that maps an ESI (local or remote)
1458 * to one or more PEs/VTEPs.
1459 * 5. remote ESs are added by BGP (on rxing EAD Type-1 routes)
1461 /* A list of remote VTEPs is maintained for each ES. This list includes -
1462 * 1. VTEPs for which we have imported the ESR i.e. ES-peers
1463 * 2. VTEPs that have an "active" ES-EVI VTEP i.e. EAD-per-ES and EAD-per-EVI
1464 * have been imported into one or more EVPNs
1466 static int zebra_evpn_es_vtep_cmp(void *p1
, void *p2
)
1468 const struct zebra_evpn_es_vtep
*es_vtep1
= p1
;
1469 const struct zebra_evpn_es_vtep
*es_vtep2
= p2
;
1471 return es_vtep1
->vtep_ip
.s_addr
- es_vtep2
->vtep_ip
.s_addr
;
1474 static struct zebra_evpn_es_vtep
*zebra_evpn_es_vtep_new(
1475 struct zebra_evpn_es
*es
, struct in_addr vtep_ip
)
1477 struct zebra_evpn_es_vtep
*es_vtep
;
1479 es_vtep
= XCALLOC(MTYPE_ZES_VTEP
, sizeof(*es_vtep
));
1482 es_vtep
->vtep_ip
.s_addr
= vtep_ip
.s_addr
;
1483 listnode_init(&es_vtep
->es_listnode
, es_vtep
);
1484 listnode_add_sort(es
->es_vtep_list
, &es_vtep
->es_listnode
);
1489 static void zebra_evpn_es_vtep_free(struct zebra_evpn_es_vtep
*es_vtep
)
1491 struct zebra_evpn_es
*es
= es_vtep
->es
;
1493 list_delete_node(es
->es_vtep_list
, &es_vtep
->es_listnode
);
1494 /* update the L2-NHG associated with the ES */
1495 zebra_evpn_l2_nh_es_vtep_deref(es_vtep
);
1496 XFREE(MTYPE_ZES_VTEP
, es_vtep
);
1500 /* check if VTEP is already part of the list */
1501 static struct zebra_evpn_es_vtep
*zebra_evpn_es_vtep_find(
1502 struct zebra_evpn_es
*es
, struct in_addr vtep_ip
)
1504 struct listnode
*node
= NULL
;
1505 struct zebra_evpn_es_vtep
*es_vtep
;
1507 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
1508 if (es_vtep
->vtep_ip
.s_addr
== vtep_ip
.s_addr
)
1514 /* flush all the dataplane br-port info associated with the ES */
1515 static bool zebra_evpn_es_br_port_dplane_clear(struct zebra_evpn_es
*es
)
1517 struct in_addr sph_filters
[ES_VTEP_MAX_CNT
];
1519 if (!(es
->flags
& ZEBRA_EVPNES_BR_PORT
))
1522 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
1523 zlog_debug("es %s br-port dplane clear", es
->esi_str
);
1525 memset(&sph_filters
, 0, sizeof(sph_filters
));
1526 dplane_br_port_update(es
->zif
->ifp
, false /* non_df */, 0, sph_filters
,
1527 0 /* backup_nhg_id */);
1532 zebra_evpn_es_br_port_dplane_update_needed(struct zebra_evpn_es
*es
)
1534 return (es
->flags
& ZEBRA_EVPNES_NON_DF
)
1535 || (es
->flags
& ZEBRA_EVPNES_NHG_ACTIVE
)
1536 || listcount(es
->es_vtep_list
);
1539 /* returns TRUE if dplane entry was updated */
1540 static bool zebra_evpn_es_br_port_dplane_update(struct zebra_evpn_es
*es
,
1543 uint32_t backup_nhg_id
;
1544 struct in_addr sph_filters
[ES_VTEP_MAX_CNT
];
1545 struct listnode
*node
= NULL
;
1546 struct zebra_evpn_es_vtep
*es_vtep
;
1547 uint32_t sph_filter_cnt
= 0;
1549 if (!(es
->flags
& ZEBRA_EVPNES_LOCAL
))
1550 return zebra_evpn_es_br_port_dplane_clear(es
);
1552 /* If the ES is not a bridge port there is nothing
1555 if (!(es
->flags
& ZEBRA_EVPNES_BR_PORT
))
1558 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
1559 zlog_debug("es %s br-port dplane update by %s", es
->esi_str
,
1561 backup_nhg_id
= (es
->flags
& ZEBRA_EVPNES_NHG_ACTIVE
) ? es
->nhg_id
: 0;
1563 memset(&sph_filters
, 0, sizeof(sph_filters
));
1564 if (es
->flags
& ZEBRA_EVPNES_BYPASS
) {
1565 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
1567 "es %s SPH filter disabled as it is in bypass",
1570 if (listcount(es
->es_vtep_list
) > ES_VTEP_MAX_CNT
) {
1571 zlog_warn("es %s vtep count %d exceeds filter cnt %d",
1572 es
->esi_str
, listcount(es
->es_vtep_list
),
1575 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
,
1578 & ZEBRA_EVPNES_VTEP_DEL_IN_PROG
)
1580 sph_filters
[sph_filter_cnt
] = es_vtep
->vtep_ip
;
1586 dplane_br_port_update(es
->zif
->ifp
, !!(es
->flags
& ZEBRA_EVPNES_NON_DF
),
1587 sph_filter_cnt
, sph_filters
, backup_nhg_id
);
1592 /* returns TRUE if dplane entry was updated */
1593 static bool zebra_evpn_es_df_change(struct zebra_evpn_es
*es
, bool new_non_df
,
1594 const char *caller
, const char *reason
)
1598 old_non_df
= !!(es
->flags
& ZEBRA_EVPNES_NON_DF
);
1600 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
1601 zlog_debug("df-change es %s %s to %s; %s: %s", es
->esi_str
,
1602 old_non_df
? "non-df" : "df",
1603 new_non_df
? "non-df" : "df", caller
, reason
);
1605 if (old_non_df
== new_non_df
)
1609 es
->flags
|= ZEBRA_EVPNES_NON_DF
;
1611 es
->flags
&= ~ZEBRA_EVPNES_NON_DF
;
1613 /* update non-DF block filter in the dataplane */
1614 return zebra_evpn_es_br_port_dplane_update(es
, __func__
);
1618 /* returns TRUE if dplane entry was updated */
1619 static bool zebra_evpn_es_run_df_election(struct zebra_evpn_es
*es
,
1622 struct listnode
*node
= NULL
;
1623 struct zebra_evpn_es_vtep
*es_vtep
;
1624 bool new_non_df
= false;
1626 /* If the ES is not ready (i.e. not completely configured) there
1627 * is no need to setup the BUM block filter
1629 if (!(es
->flags
& ZEBRA_EVPNES_LOCAL
)
1630 || (es
->flags
& ZEBRA_EVPNES_BYPASS
)
1631 || !zmh_info
->es_originator_ip
.s_addr
)
1632 return zebra_evpn_es_df_change(es
, new_non_df
, caller
,
1635 /* if oper-state is down DF filtering must be on. when the link comes
1636 * up again dataplane should block BUM till FRR has had the chance
1637 * to run DF election again
1639 if (!(es
->flags
& ZEBRA_EVPNES_OPER_UP
)) {
1641 return zebra_evpn_es_df_change(es
, new_non_df
, caller
,
1645 /* ES was just created; we need to wait for the peers to rx the
1646 * our Type-4 routes and for the switch to import the peers' Type-4
1649 if (es
->df_delay_timer
) {
1651 return zebra_evpn_es_df_change(es
, new_non_df
, caller
,
1655 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
1656 /* Only VTEPs that have advertised the ESR can participate
1659 if (!(es_vtep
->flags
& ZEBRA_EVPNES_VTEP_RXED_ESR
))
1662 /* If the DF alg is not the same we should fall back to
1663 * service-carving. But as service-carving is not supported
1664 * we will stop forwarding BUM
1666 if (es_vtep
->df_alg
!= EVPN_MH_DF_ALG_PREF
) {
1671 /* Peer VTEP wins DF election if -
1672 * the peer-VTEP has higher preference (or)
1673 * the pref is the same but peer's IP address is lower
1675 if ((es_vtep
->df_pref
> es
->df_pref
)
1676 || ((es_vtep
->df_pref
== es
->df_pref
)
1677 && (es_vtep
->vtep_ip
.s_addr
1678 < zmh_info
->es_originator_ip
.s_addr
))) {
1684 return zebra_evpn_es_df_change(es
, new_non_df
, caller
, "elected");
1687 static void zebra_evpn_es_vtep_add(struct zebra_evpn_es
*es
,
1688 struct in_addr vtep_ip
, bool esr_rxed
,
1689 uint8_t df_alg
, uint16_t df_pref
)
1691 struct zebra_evpn_es_vtep
*es_vtep
;
1693 bool dplane_updated
= false;
1695 es_vtep
= zebra_evpn_es_vtep_find(es
, vtep_ip
);
1698 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
1699 zlog_debug("es %s vtep %pI4 add",
1700 es
->esi_str
, &vtep_ip
);
1701 es_vtep
= zebra_evpn_es_vtep_new(es
, vtep_ip
);
1702 /* update the L2-NHG associated with the ES */
1703 zebra_evpn_l2_nh_es_vtep_ref(es_vtep
);
1706 old_esr_rxed
= !!(es_vtep
->flags
& ZEBRA_EVPNES_VTEP_RXED_ESR
);
1707 if ((old_esr_rxed
!= esr_rxed
) || (es_vtep
->df_alg
!= df_alg
)
1708 || (es_vtep
->df_pref
!= df_pref
)) {
1709 /* If any of the DF election params changed we need to re-run
1713 es_vtep
->flags
|= ZEBRA_EVPNES_VTEP_RXED_ESR
;
1715 es_vtep
->flags
&= ~ZEBRA_EVPNES_VTEP_RXED_ESR
;
1716 es_vtep
->df_alg
= df_alg
;
1717 es_vtep
->df_pref
= df_pref
;
1718 dplane_updated
= zebra_evpn_es_run_df_election(es
, __func__
);
1720 /* add the vtep to the SPH list */
1721 if (!dplane_updated
&& (es
->flags
& ZEBRA_EVPNES_LOCAL
))
1722 zebra_evpn_es_br_port_dplane_update(es
, __func__
);
1725 static void zebra_evpn_es_vtep_del(struct zebra_evpn_es
*es
,
1726 struct in_addr vtep_ip
)
1728 struct zebra_evpn_es_vtep
*es_vtep
;
1729 bool dplane_updated
= false;
1731 es_vtep
= zebra_evpn_es_vtep_find(es
, vtep_ip
);
1734 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
1735 zlog_debug("es %s vtep %pI4 del",
1736 es
->esi_str
, &vtep_ip
);
1737 es_vtep
->flags
|= ZEBRA_EVPNES_VTEP_DEL_IN_PROG
;
1738 if (es_vtep
->flags
& ZEBRA_EVPNES_VTEP_RXED_ESR
) {
1739 es_vtep
->flags
&= ~ZEBRA_EVPNES_VTEP_RXED_ESR
;
1741 zebra_evpn_es_run_df_election(es
, __func__
);
1743 /* remove the vtep from the SPH list */
1744 if (!dplane_updated
&& (es
->flags
& ZEBRA_EVPNES_LOCAL
))
1745 zebra_evpn_es_br_port_dplane_update(es
, __func__
);
1746 zebra_evpn_es_vtep_free(es_vtep
);
1750 /* compare ES-IDs for the global ES RB tree */
1751 static int zebra_es_rb_cmp(const struct zebra_evpn_es
*es1
,
1752 const struct zebra_evpn_es
*es2
)
1754 return memcmp(&es1
->esi
, &es2
->esi
, ESI_BYTES
);
1756 RB_GENERATE(zebra_es_rb_head
, zebra_evpn_es
, rb_node
, zebra_es_rb_cmp
);
1759 struct zebra_evpn_es
*zebra_evpn_es_find(const esi_t
*esi
)
1761 struct zebra_evpn_es tmp
;
1763 memcpy(&tmp
.esi
, esi
, sizeof(esi_t
));
1764 return RB_FIND(zebra_es_rb_head
, &zmh_info
->es_rb_tree
, &tmp
);
1767 /* A new local es is created when a local-es-id and sysmac is configured
1768 * against an interface.
1770 static struct zebra_evpn_es
*zebra_evpn_es_new(const esi_t
*esi
)
1772 struct zebra_evpn_es
*es
;
1774 if (!memcmp(esi
, zero_esi
, sizeof(esi_t
)))
1777 es
= XCALLOC(MTYPE_ZES
, sizeof(struct zebra_evpn_es
));
1780 memcpy(&es
->esi
, esi
, sizeof(esi_t
));
1781 esi_to_str(&es
->esi
, es
->esi_str
, sizeof(es
->esi_str
));
1783 /* Add to rb_tree */
1784 RB_INSERT(zebra_es_rb_head
, &zmh_info
->es_rb_tree
, es
);
1786 /* Initialise the ES-EVI list */
1787 es
->es_evi_list
= list_new();
1788 listset_app_node_mem(es
->es_evi_list
);
1790 /* Initialise the VTEP list */
1791 es
->es_vtep_list
= list_new();
1792 listset_app_node_mem(es
->es_vtep_list
);
1793 es
->es_vtep_list
->cmp
= zebra_evpn_es_vtep_cmp
;
1795 /* mac entries associated with the ES */
1796 es
->mac_list
= list_new();
1797 listset_app_node_mem(es
->mac_list
);
1800 es
->nhg_id
= zebra_evpn_nhid_alloc(es
);
1802 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
1803 zlog_debug("es %s nhg %u new", es
->esi_str
, es
->nhg_id
);
1808 /* Free a given ES -
1809 * This just frees appropriate memory, caller should have taken other
1812 static void zebra_evpn_es_free(struct zebra_evpn_es
**esp
)
1814 struct zebra_evpn_es
*es
= *esp
;
1816 /* If the ES has a local or remote reference it cannot be freed.
1817 * Free is also prevented if there are MAC entries referencing
1820 if ((es
->flags
& (ZEBRA_EVPNES_LOCAL
| ZEBRA_EVPNES_REMOTE
)) ||
1821 listcount(es
->mac_list
))
1824 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
1825 zlog_debug("es %s free", es
->esi_str
);
1827 /* If the NHG is still installed uninstall it and free the id */
1828 if (es
->flags
& ZEBRA_EVPNES_NHG_ACTIVE
) {
1829 es
->flags
&= ~ZEBRA_EVPNES_NHG_ACTIVE
;
1830 kernel_del_mac_nhg(es
->nhg_id
);
1832 zebra_evpn_nhid_free(es
->nhg_id
, es
);
1834 /* cleanup resources maintained against the ES */
1835 list_delete(&es
->es_evi_list
);
1836 list_delete(&es
->es_vtep_list
);
1837 list_delete(&es
->mac_list
);
1839 /* remove from the VNI-ESI rb tree */
1840 RB_REMOVE(zebra_es_rb_head
, &zmh_info
->es_rb_tree
, es
);
1842 XFREE(MTYPE_ZES
, es
);
1847 /* Inform BGP about local ES addition */
1848 static int zebra_evpn_es_send_add_to_client(struct zebra_evpn_es
*es
)
1850 struct zserv
*client
;
1855 client
= zserv_find_client(ZEBRA_ROUTE_BGP
, 0);
1856 /* BGP may not be running. */
1860 s
= stream_new(ZEBRA_MAX_PACKET_SIZ
);
1862 zclient_create_header(s
, ZEBRA_LOCAL_ES_ADD
, zebra_vrf_get_evpn_id());
1863 stream_put(s
, &es
->esi
, sizeof(esi_t
));
1864 stream_put_ipv4(s
, zmh_info
->es_originator_ip
.s_addr
);
1865 oper_up
= !!(es
->flags
& ZEBRA_EVPNES_OPER_UP
);
1866 stream_putc(s
, oper_up
);
1867 stream_putw(s
, es
->df_pref
);
1868 bypass
= !!(es
->flags
& ZEBRA_EVPNES_BYPASS
);
1869 stream_putc(s
, bypass
);
1871 /* Write packet size. */
1872 stream_putw_at(s
, 0, stream_get_endp(s
));
1874 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
1876 "send add local es %s %pI4 active %u df_pref %u%s to %s",
1877 es
->esi_str
, &zmh_info
->es_originator_ip
, oper_up
,
1878 es
->df_pref
, bypass
? " bypass" : "",
1879 zebra_route_string(client
->proto
));
1881 client
->local_es_add_cnt
++;
1882 return zserv_send_message(client
, s
);
1885 /* Inform BGP about local ES deletion */
1886 static int zebra_evpn_es_send_del_to_client(struct zebra_evpn_es
*es
)
1888 struct zserv
*client
;
1891 client
= zserv_find_client(ZEBRA_ROUTE_BGP
, 0);
1892 /* BGP may not be running. */
1896 s
= stream_new(ZEBRA_MAX_PACKET_SIZ
);
1899 zclient_create_header(s
, ZEBRA_LOCAL_ES_DEL
, zebra_vrf_get_evpn_id());
1900 stream_put(s
, &es
->esi
, sizeof(esi_t
));
1902 /* Write packet size. */
1903 stream_putw_at(s
, 0, stream_get_endp(s
));
1905 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
1906 zlog_debug("send del local es %s to %s", es
->esi_str
,
1907 zebra_route_string(client
->proto
));
1909 client
->local_es_del_cnt
++;
1910 return zserv_send_message(client
, s
);
1913 static void zebra_evpn_es_re_eval_send_to_client(struct zebra_evpn_es
*es
,
1914 bool es_evi_re_reval
)
1918 struct listnode
*node
;
1919 struct zebra_evpn_es_evi
*es_evi
;
1921 old_ready
= !!(es
->flags
& ZEBRA_EVPNES_READY_FOR_BGP
);
1923 if ((es
->flags
& ZEBRA_EVPNES_LOCAL
) &&
1924 zmh_info
->es_originator_ip
.s_addr
)
1925 es
->flags
|= ZEBRA_EVPNES_READY_FOR_BGP
;
1927 es
->flags
&= ~ZEBRA_EVPNES_READY_FOR_BGP
;
1929 new_ready
= !!(es
->flags
& ZEBRA_EVPNES_READY_FOR_BGP
);
1930 if (old_ready
== new_ready
)
1934 zebra_evpn_es_send_add_to_client(es
);
1936 zebra_evpn_es_send_del_to_client(es
);
1938 /* re-eval associated EVIs */
1939 if (es_evi_re_reval
) {
1940 for (ALL_LIST_ELEMENTS_RO(es
->es_evi_list
, node
, es_evi
)) {
1941 if (!(es_evi
->flags
& ZEBRA_EVPNES_EVI_LOCAL
))
1943 zebra_evpn_es_evi_re_eval_send_to_client(es_evi
);
1948 void zebra_evpn_es_send_all_to_client(bool add
)
1950 struct listnode
*es_node
;
1951 struct listnode
*evi_node
;
1952 struct zebra_evpn_es
*es
;
1953 struct zebra_evpn_es_evi
*es_evi
;
1958 for (ALL_LIST_ELEMENTS_RO(zmh_info
->local_es_list
, es_node
, es
)) {
1959 if (es
->flags
& ZEBRA_EVPNES_READY_FOR_BGP
) {
1961 zebra_evpn_es_send_add_to_client(es
);
1962 for (ALL_LIST_ELEMENTS_RO(es
->es_evi_list
,
1963 evi_node
, es_evi
)) {
1964 if (!(es_evi
->flags
&
1965 ZEBRA_EVPNES_EVI_READY_FOR_BGP
))
1969 zebra_evpn_es_evi_send_to_client(
1973 zebra_evpn_es_evi_send_to_client(
1978 zebra_evpn_es_send_del_to_client(es
);
1983 /* walk the vlan bitmap associated with the zif and create or delete
1984 * es_evis for all vlans associated with a VNI.
1985 * XXX: This API is really expensive. optimize later if possible.
1987 static void zebra_evpn_es_setup_evis(struct zebra_evpn_es
*es
)
1989 struct zebra_if
*zif
= es
->zif
;
1991 struct zebra_evpn_access_bd
*acc_bd
;
1993 if (!bf_is_inited(zif
->vlan_bitmap
))
1996 bf_for_each_set_bit(zif
->vlan_bitmap
, vid
, IF_VLAN_BITMAP_MAX
) {
1997 acc_bd
= zebra_evpn_acc_vl_find(vid
);
1999 zebra_evpn_local_es_evi_add(es
, acc_bd
->zevpn
);
2003 static void zebra_evpn_flush_local_mac(struct zebra_mac
*mac
,
2004 struct interface
*ifp
)
2007 struct zebra_if
*zif
;
2008 struct interface
*br_ifp
;
2009 struct zebra_vxlan_vni
*vni
;
2012 br_ifp
= zif
->brslave_info
.br_if
;
2016 if (mac
->zevpn
->vxlan_if
) {
2017 zif
= mac
->zevpn
->vxlan_if
->info
;
2018 vni
= zebra_vxlan_if_vni_find(zif
, mac
->zevpn
->vni
);
2019 vid
= vni
->access_vlan
;
2024 /* delete the local mac from the dataplane */
2025 dplane_local_mac_del(ifp
, br_ifp
, vid
, &mac
->macaddr
);
2026 /* delete the local mac in zebra */
2027 zebra_evpn_del_local_mac(mac
->zevpn
, mac
, true);
2030 static void zebra_evpn_es_flush_local_macs(struct zebra_evpn_es
*es
,
2031 struct interface
*ifp
, bool add
)
2033 struct zebra_mac
*mac
;
2034 struct listnode
*node
;
2035 struct listnode
*nnode
;
2037 for (ALL_LIST_ELEMENTS(es
->mac_list
, node
, nnode
, mac
)) {
2038 if (!CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
))
2041 /* If ES is being attached/detached from the access port we
2042 * need to clear local activity and peer activity and start
2044 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
2045 zlog_debug("VNI %u mac %pEA update; local ES %s %s",
2048 es
->esi_str
, add
? "add" : "del");
2049 zebra_evpn_flush_local_mac(mac
, ifp
);
2053 void zebra_evpn_es_local_br_port_update(struct zebra_if
*zif
)
2055 struct zebra_evpn_es
*es
= zif
->es_info
.es
;
2056 bool old_br_port
= !!(es
->flags
& ZEBRA_EVPNES_BR_PORT
);
2059 if (zif
->brslave_info
.bridge_ifindex
!= IFINDEX_INTERNAL
)
2060 es
->flags
|= ZEBRA_EVPNES_BR_PORT
;
2062 es
->flags
&= ~ZEBRA_EVPNES_BR_PORT
;
2064 new_br_port
= !!(es
->flags
& ZEBRA_EVPNES_BR_PORT
);
2065 if (old_br_port
== new_br_port
)
2068 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2069 zlog_debug("es %s br_port change old %u new %u", es
->esi_str
,
2070 old_br_port
, new_br_port
);
2072 /* update the dataplane br_port attrs */
2073 if (new_br_port
&& zebra_evpn_es_br_port_dplane_update_needed(es
))
2074 zebra_evpn_es_br_port_dplane_update(es
, __func__
);
2077 /* On config of first local-ES turn off DAD */
2078 static void zebra_evpn_mh_dup_addr_detect_off(void)
2080 struct zebra_vrf
*zvrf
;
2084 if (zmh_info
->flags
& ZEBRA_EVPN_MH_DUP_ADDR_DETECT_OFF
)
2087 zvrf
= zebra_vrf_get_evpn();
2088 old_detect
= zebra_evpn_do_dup_addr_detect(zvrf
);
2089 zmh_info
->flags
|= ZEBRA_EVPN_MH_DUP_ADDR_DETECT_OFF
;
2090 new_detect
= zebra_evpn_do_dup_addr_detect(zvrf
);
2092 if (old_detect
&& !new_detect
) {
2093 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2095 "evpn-mh config caused DAD addr detect chg from %s to %s",
2096 old_detect
? "on" : "off",
2097 new_detect
? "on" : "off");
2098 zebra_vxlan_clear_dup_detect_vni_all(zvrf
);
2102 /* On config of first local-ES turn off advertisement of STALE/DELAY/PROBE
2105 static void zebra_evpn_mh_advertise_reach_neigh_only(void)
2107 if (zmh_info
->flags
& ZEBRA_EVPN_MH_ADV_REACHABLE_NEIGH_ONLY
)
2110 zmh_info
->flags
|= ZEBRA_EVPN_MH_ADV_REACHABLE_NEIGH_ONLY
;
2111 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2112 zlog_debug("evpn-mh: only REACHABLE neigh advertised");
2114 /* XXX - if STALE/DELAY/PROBE neighs were previously advertised we
2115 * need to withdraw them
2119 /* On config of first local-ES turn on advertisement of local SVI-MAC */
2120 static void zebra_evpn_mh_advertise_svi_mac(void)
2122 if (zmh_info
->flags
& ZEBRA_EVPN_MH_ADV_SVI_MAC
)
2125 zmh_info
->flags
|= ZEBRA_EVPN_MH_ADV_SVI_MAC
;
2126 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2127 zlog_debug("evpn-mh: advertise SVI MAC");
2129 /* walk through all SVIs and see if we need to advertise the MAC */
2130 zebra_evpn_acc_vl_adv_svi_mac_all();
2133 static void zebra_evpn_es_df_delay_exp_cb(struct thread
*t
)
2135 struct zebra_evpn_es
*es
;
2139 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2140 zlog_debug("es %s df-delay expired", es
->esi_str
);
2142 zebra_evpn_es_run_df_election(es
, __func__
);
2145 /* currently there is no global config to turn on MH instead we use
2146 * the addition of the first local Ethernet Segment as the trigger to
2147 * init MH specific processing
2149 static void zebra_evpn_mh_on_first_local_es(void)
2151 zebra_evpn_mh_dup_addr_detect_off();
2152 zebra_evpn_mh_advertise_reach_neigh_only();
2153 zebra_evpn_mh_advertise_svi_mac();
2156 static void zebra_evpn_es_local_info_set(struct zebra_evpn_es
*es
,
2157 struct zebra_if
*zif
)
2159 if (es
->flags
& ZEBRA_EVPNES_LOCAL
)
2162 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2163 zlog_debug("local es %s add; nhg %u if %s", es
->esi_str
,
2164 es
->nhg_id
, zif
->ifp
->name
);
2166 zebra_evpn_mh_on_first_local_es();
2168 es
->flags
|= ZEBRA_EVPNES_LOCAL
;
2169 listnode_init(&es
->local_es_listnode
, es
);
2170 listnode_add(zmh_info
->local_es_list
, &es
->local_es_listnode
);
2172 /* attach es to interface */
2173 zif
->es_info
.es
= es
;
2174 es
->df_pref
= zif
->es_info
.df_pref
? zif
->es_info
.df_pref
2175 : EVPN_MH_DF_PREF_DEFAULT
;
2177 /* attach interface to es */
2179 if (if_is_operative(zif
->ifp
))
2180 es
->flags
|= ZEBRA_EVPNES_OPER_UP
;
2182 if (zif
->brslave_info
.bridge_ifindex
!= IFINDEX_INTERNAL
)
2183 es
->flags
|= ZEBRA_EVPNES_BR_PORT
;
2185 /* inherit the bypass flag from the interface */
2186 if (zif
->flags
& ZIF_FLAG_LACP_BYPASS
)
2187 es
->flags
|= ZEBRA_EVPNES_BYPASS
;
2189 /* setup base-vni if one doesn't already exist; the ES will get sent
2190 * to BGP as a part of that process
2192 if (!zmh_info
->es_base_evpn
)
2193 zebra_evpn_es_get_one_base_evpn();
2195 /* send notification to bgp */
2196 zebra_evpn_es_re_eval_send_to_client(es
,
2197 false /* es_evi_re_reval */);
2199 /* Start the DF delay timer on the local ES */
2200 if (!es
->df_delay_timer
)
2201 thread_add_timer(zrouter
.master
, zebra_evpn_es_df_delay_exp_cb
,
2202 es
, ZEBRA_EVPN_MH_DF_DELAY_TIME
,
2203 &es
->df_delay_timer
);
2205 /* See if the local VTEP can function as DF on the ES */
2206 if (!zebra_evpn_es_run_df_election(es
, __func__
)) {
2207 /* check if the dplane entry needs to be re-programmed as a
2208 * result of some thing other than DF status change
2210 if (zebra_evpn_es_br_port_dplane_update_needed(es
))
2211 zebra_evpn_es_br_port_dplane_update(es
, __func__
);
2215 /* Setup ES-EVIs for all VxLAN stretched VLANs associated with
2218 zebra_evpn_es_setup_evis(es
);
2219 /* if there any local macs referring to the ES as dest we
2220 * need to clear the contents and start over
2222 zebra_evpn_es_flush_local_macs(es
, zif
->ifp
, true);
2224 /* inherit EVPN protodown flags on the access port */
2225 zebra_evpn_mh_update_protodown_es(es
, true /*resync_dplane*/);
2228 static void zebra_evpn_es_local_info_clear(struct zebra_evpn_es
**esp
)
2230 struct zebra_if
*zif
;
2231 struct zebra_evpn_es
*es
= *esp
;
2232 bool dplane_updated
= false;
2234 if (!(es
->flags
& ZEBRA_EVPNES_LOCAL
))
2239 /* if there any local macs referring to the ES as dest we
2240 * need to clear the contents and start over
2242 zebra_evpn_es_flush_local_macs(es
, zif
->ifp
, false);
2244 es
->flags
&= ~(ZEBRA_EVPNES_LOCAL
| ZEBRA_EVPNES_READY_FOR_BGP
);
2246 THREAD_OFF(es
->df_delay_timer
);
2248 /* clear EVPN protodown flags on the access port */
2249 zebra_evpn_mh_clear_protodown_es(es
);
2251 /* remove the DF filter */
2252 dplane_updated
= zebra_evpn_es_run_df_election(es
, __func__
);
2254 /* flush the BUM filters and backup NHG */
2255 if (!dplane_updated
)
2256 zebra_evpn_es_br_port_dplane_clear(es
);
2258 /* clear the es from the parent interface */
2259 zif
->es_info
.es
= NULL
;
2262 /* clear all local flags associated with the ES */
2263 es
->flags
&= ~(ZEBRA_EVPNES_OPER_UP
| ZEBRA_EVPNES_BR_PORT
2264 | ZEBRA_EVPNES_BYPASS
);
2266 /* remove from the ES list */
2267 list_delete_node(zmh_info
->local_es_list
, &es
->local_es_listnode
);
2269 /* free up the ES if there is no remote reference */
2270 zebra_evpn_es_free(esp
);
2273 /* Delete an ethernet segment and inform BGP */
2274 static void zebra_evpn_local_es_del(struct zebra_evpn_es
**esp
)
2276 struct zebra_evpn_es_evi
*es_evi
;
2277 struct listnode
*node
= NULL
;
2278 struct listnode
*nnode
= NULL
;
2279 struct zebra_if
*zif
;
2280 struct zebra_evpn_es
*es
= *esp
;
2282 if (!CHECK_FLAG(es
->flags
, ZEBRA_EVPNES_LOCAL
))
2285 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
) {
2287 zlog_debug("local es %s del; nhg %u if %s", es
->esi_str
,
2288 es
->nhg_id
, zif
? zif
->ifp
->name
: "-");
2291 /* remove all ES-EVIs associated with the ES */
2292 for (ALL_LIST_ELEMENTS(es
->es_evi_list
, node
, nnode
, es_evi
))
2293 zebra_evpn_local_es_evi_do_del(es_evi
);
2295 /* send a del if the ES had been sent to BGP earlier */
2296 if (es
->flags
& ZEBRA_EVPNES_READY_FOR_BGP
)
2297 zebra_evpn_es_send_del_to_client(es
);
2299 zebra_evpn_es_local_info_clear(esp
);
2302 /* eval remote info associated with the ES */
2303 static void zebra_evpn_es_remote_info_re_eval(struct zebra_evpn_es
**esp
)
2305 struct zebra_evpn_es
*es
= *esp
;
2307 /* if there are remote VTEPs the ES-EVI is classified as "remote" */
2308 if (listcount(es
->es_vtep_list
)) {
2309 if (!(es
->flags
& ZEBRA_EVPNES_REMOTE
)) {
2310 es
->flags
|= ZEBRA_EVPNES_REMOTE
;
2311 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2312 zlog_debug("remote es %s add; nhg %u",
2313 es
->esi_str
, es
->nhg_id
);
2316 if (es
->flags
& ZEBRA_EVPNES_REMOTE
) {
2317 es
->flags
&= ~ZEBRA_EVPNES_REMOTE
;
2318 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2319 zlog_debug("remote es %s del; nhg %u",
2320 es
->esi_str
, es
->nhg_id
);
2321 zebra_evpn_es_free(esp
);
2326 /* A new local es is created when a local-es-id and sysmac is configured
2327 * against an interface.
2329 static int zebra_evpn_local_es_update(struct zebra_if
*zif
, esi_t
*esi
)
2331 struct zebra_evpn_es
*old_es
= zif
->es_info
.es
;
2332 struct zebra_evpn_es
*es
;
2334 if (old_es
&& !memcmp(&old_es
->esi
, esi
, sizeof(*esi
)))
2335 /* dup - nothing to be done */
2338 /* release the old_es against the zif */
2340 zebra_evpn_local_es_del(&old_es
);
2342 es
= zebra_evpn_es_find(esi
);
2344 /* if it exists against another interface flag an error */
2345 if (es
->zif
&& es
->zif
!= zif
)
2349 es
= zebra_evpn_es_new(esi
);
2352 memcpy(&zif
->es_info
.esi
, esi
, sizeof(*esi
));
2354 zebra_evpn_es_local_info_set(es
, zif
);
2359 static int zebra_evpn_type3_esi_update(struct zebra_if
*zif
, uint32_t lid
,
2360 struct ethaddr
*sysmac
)
2362 struct zebra_evpn_es
*old_es
= zif
->es_info
.es
;
2365 int field_bytes
= 0;
2367 /* Complete config of the ES-ID bootstraps the ES */
2368 if (!lid
|| is_zero_mac(sysmac
)) {
2370 memset(&zif
->es_info
.esi
, 0, sizeof(zif
->es_info
.esi
));
2371 /* if in ES is attached to zif delete it */
2373 zebra_evpn_local_es_del(&old_es
);
2377 /* build 10-byte type-3-ESI -
2378 * Type(1-byte), MAC(6-bytes), ES-LID (3-bytes)
2381 esi
.val
[offset
] = ESI_TYPE_MAC
;
2382 offset
+= field_bytes
;
2384 field_bytes
= ETH_ALEN
;
2385 memcpy(&esi
.val
[offset
], (uint8_t *)sysmac
, field_bytes
);
2386 offset
+= field_bytes
;
2388 esi
.val
[offset
++] = (uint8_t)(lid
>> 16);
2389 esi
.val
[offset
++] = (uint8_t)(lid
>> 8);
2390 esi
.val
[offset
++] = (uint8_t)lid
;
2392 return zebra_evpn_local_es_update(zif
, &esi
);
2395 int zebra_evpn_remote_es_del(const esi_t
*esi
, struct in_addr vtep_ip
)
2397 char buf
[ESI_STR_LEN
];
2398 struct zebra_evpn_es
*es
;
2400 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2401 zlog_debug("remote es %s vtep %pI4 del",
2402 esi_to_str(esi
, buf
, sizeof(buf
)), &vtep_ip
);
2404 es
= zebra_evpn_es_find(esi
);
2406 zlog_warn("remote es %s vtep %pI4 del failed, es missing",
2407 esi_to_str(esi
, buf
, sizeof(buf
)), &vtep_ip
);
2411 zebra_evpn_es_vtep_del(es
, vtep_ip
);
2412 zebra_evpn_es_remote_info_re_eval(&es
);
2417 /* force delete a remote ES on the way down */
2418 static void zebra_evpn_remote_es_flush(struct zebra_evpn_es
**esp
)
2420 struct zebra_evpn_es_vtep
*es_vtep
;
2421 struct listnode
*node
;
2422 struct listnode
*nnode
;
2423 struct zebra_evpn_es
*es
= *esp
;
2425 for (ALL_LIST_ELEMENTS(es
->es_vtep_list
, node
, nnode
, es_vtep
)) {
2426 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2427 zlog_debug("es %s vtep %pI4 flush",
2430 zebra_evpn_es_vtep_free(es_vtep
);
2432 zebra_evpn_es_remote_info_re_eval(esp
);
2435 int zebra_evpn_remote_es_add(const esi_t
*esi
, struct in_addr vtep_ip
,
2436 bool esr_rxed
, uint8_t df_alg
, uint16_t df_pref
)
2438 char buf
[ESI_STR_LEN
];
2439 struct zebra_evpn_es
*es
;
2441 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2442 zlog_debug("remote es %s vtep %pI4 add %s df_alg %d df_pref %d",
2443 esi_to_str(esi
, buf
, sizeof(buf
)),
2444 &vtep_ip
, esr_rxed
? "esr" : "", df_alg
,
2447 es
= zebra_evpn_es_find(esi
);
2449 es
= zebra_evpn_es_new(esi
);
2452 "remote es %s vtep %pI4 add failed, es missing",
2453 esi_to_str(esi
, buf
, sizeof(buf
)), &vtep_ip
);
2458 if (df_alg
!= EVPN_MH_DF_ALG_PREF
)
2460 "remote es %s vtep %pI4 add %s with unsupported df_alg %d",
2461 esi_to_str(esi
, buf
, sizeof(buf
)), &vtep_ip
,
2462 esr_rxed
? "esr" : "", df_alg
);
2464 zebra_evpn_es_vtep_add(es
, vtep_ip
, esr_rxed
, df_alg
, df_pref
);
2465 zebra_evpn_es_remote_info_re_eval(&es
);
2470 void zebra_evpn_proc_remote_es(ZAPI_HANDLER_ARGS
)
2473 struct in_addr vtep_ip
;
2476 if (!is_evpn_enabled()) {
2478 "%s: EVPN not enabled yet we received a es_add zapi call",
2483 memset(&esi
, 0, sizeof(esi_t
));
2486 STREAM_GET(&esi
, s
, sizeof(esi_t
));
2487 STREAM_GET(&vtep_ip
.s_addr
, s
, sizeof(vtep_ip
.s_addr
));
2489 if (hdr
->command
== ZEBRA_REMOTE_ES_VTEP_ADD
) {
2490 uint32_t zapi_flags
;
2495 STREAM_GETL(s
, zapi_flags
);
2496 esr_rxed
= (zapi_flags
& ZAPI_ES_VTEP_FLAG_ESR_RXED
) ? true
2498 STREAM_GETC(s
, df_alg
);
2499 STREAM_GETW(s
, df_pref
);
2500 zebra_rib_queue_evpn_rem_es_add(&esi
, &vtep_ip
, esr_rxed
,
2503 zebra_rib_queue_evpn_rem_es_del(&esi
, &vtep_ip
);
2510 void zebra_evpn_es_mac_deref_entry(struct zebra_mac
*mac
)
2512 struct zebra_evpn_es
*es
= mac
->es
;
2518 list_delete_node(es
->mac_list
, &mac
->es_listnode
);
2519 if (!listcount(es
->mac_list
))
2520 zebra_evpn_es_free(&es
);
2523 /* Associate a MAC entry with a local or remote ES. Returns false if there
2526 bool zebra_evpn_es_mac_ref_entry(struct zebra_mac
*mac
,
2527 struct zebra_evpn_es
*es
)
2533 zebra_evpn_es_mac_deref_entry(mac
);
2539 listnode_init(&mac
->es_listnode
, mac
);
2540 listnode_add(es
->mac_list
, &mac
->es_listnode
);
2545 bool zebra_evpn_es_mac_ref(struct zebra_mac
*mac
, const esi_t
*esi
)
2547 struct zebra_evpn_es
*es
;
2549 es
= zebra_evpn_es_find(esi
);
2551 /* If non-zero esi implicitly create a new ES */
2552 if (memcmp(esi
, zero_esi
, sizeof(esi_t
))) {
2553 es
= zebra_evpn_es_new(esi
);
2554 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2555 zlog_debug("auto es %s add on mac ref",
2560 return zebra_evpn_es_mac_ref_entry(mac
, es
);
2563 /* Inform BGP about local ES-EVI add or del */
2564 static int zebra_evpn_es_evi_send_to_client(struct zebra_evpn_es
*es
,
2565 struct zebra_evpn
*zevpn
, bool add
)
2567 struct zserv
*client
;
2570 client
= zserv_find_client(ZEBRA_ROUTE_BGP
, 0);
2571 /* BGP may not be running. */
2575 s
= stream_new(ZEBRA_MAX_PACKET_SIZ
);
2577 zclient_create_header(s
,
2578 add
? ZEBRA_LOCAL_ES_EVI_ADD
: ZEBRA_LOCAL_ES_EVI_DEL
,
2579 zebra_vrf_get_evpn_id());
2580 stream_put(s
, &es
->esi
, sizeof(esi_t
));
2581 stream_putl(s
, zevpn
->vni
);
2583 /* Write packet size. */
2584 stream_putw_at(s
, 0, stream_get_endp(s
));
2586 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2587 zlog_debug("send %s local es %s evi %u to %s",
2588 add
? "add" : "del",
2589 es
->esi_str
, zevpn
->vni
,
2590 zebra_route_string(client
->proto
));
2592 client
->local_es_add_cnt
++;
2593 return zserv_send_message(client
, s
);
2596 /* sysmac part of a local ESI has changed */
2597 static int zebra_evpn_es_sys_mac_update(struct zebra_if
*zif
,
2598 struct ethaddr
*sysmac
)
2602 rv
= zebra_evpn_type3_esi_update(zif
, zif
->es_info
.lid
, sysmac
);
2604 memcpy(&zif
->es_info
.sysmac
, sysmac
, sizeof(struct ethaddr
));
2609 /* local-ID part of ESI has changed */
2610 static int zebra_evpn_es_lid_update(struct zebra_if
*zif
, uint32_t lid
)
2614 rv
= zebra_evpn_type3_esi_update(zif
, lid
, &zif
->es_info
.sysmac
);
2616 zif
->es_info
.lid
= lid
;
2621 /* type-0 esi has changed */
2622 static int zebra_evpn_es_type0_esi_update(struct zebra_if
*zif
, esi_t
*esi
)
2626 rv
= zebra_evpn_local_es_update(zif
, esi
);
2628 /* clear the old es_lid, es_sysmac - type-0 is being set so old
2629 * type-3 params need to be flushed
2631 memset(&zif
->es_info
.sysmac
, 0, sizeof(struct ethaddr
));
2632 zif
->es_info
.lid
= 0;
2637 void zebra_evpn_es_cleanup(void)
2639 struct zebra_evpn_es
*es
;
2640 struct zebra_evpn_es
*es_next
;
2642 RB_FOREACH_SAFE(es
, zebra_es_rb_head
,
2643 &zmh_info
->es_rb_tree
, es_next
) {
2644 zebra_evpn_local_es_del(&es
);
2646 zebra_evpn_remote_es_flush(&es
);
2650 static void zebra_evpn_es_df_pref_update(struct zebra_if
*zif
, uint16_t df_pref
)
2652 struct zebra_evpn_es
*es
;
2655 if (zif
->es_info
.df_pref
== df_pref
)
2658 zif
->es_info
.df_pref
= df_pref
;
2659 es
= zif
->es_info
.es
;
2664 tmp_pref
= zif
->es_info
.df_pref
? zif
->es_info
.df_pref
2665 : EVPN_MH_DF_PREF_DEFAULT
;
2667 if (es
->df_pref
== tmp_pref
)
2670 es
->df_pref
= tmp_pref
;
2671 /* run df election */
2672 zebra_evpn_es_run_df_election(es
, __func__
);
2674 if (es
->flags
& ZEBRA_EVPNES_READY_FOR_BGP
)
2675 zebra_evpn_es_send_add_to_client(es
);
2678 /* If bypass mode on an es changed we set all local macs to
2679 * inactive and drop the sync info
2681 static void zebra_evpn_es_bypass_update_macs(struct zebra_evpn_es
*es
,
2682 struct interface
*ifp
, bool bypass
)
2684 struct zebra_mac
*mac
;
2685 struct listnode
*node
;
2686 struct listnode
*nnode
;
2687 struct zebra_if
*zif
;
2689 /* Flush all MACs linked to the ES */
2690 for (ALL_LIST_ELEMENTS(es
->mac_list
, node
, nnode
, mac
)) {
2691 if (!CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
))
2694 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
2695 zlog_debug("VNI %u mac %pEA %s update es %s",
2698 bypass
? "bypass" : "non-bypass",
2700 zebra_evpn_flush_local_mac(mac
, ifp
);
2703 /* While in bypass-mode locally learnt MACs are linked
2704 * to the access port instead of the ES
2710 for (ALL_LIST_ELEMENTS(zif
->mac_list
, node
, nnode
, mac
)) {
2711 if (!CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
))
2714 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
2715 zlog_debug("VNI %u mac %pEA %s update ifp %s",
2718 bypass
? "bypass" : "non-bypass", ifp
->name
);
2719 zebra_evpn_flush_local_mac(mac
, ifp
);
2723 void zebra_evpn_es_bypass_update(struct zebra_evpn_es
*es
,
2724 struct interface
*ifp
, bool bypass
)
2727 bool dplane_updated
;
2729 old_bypass
= !!(es
->flags
& ZEBRA_EVPNES_BYPASS
);
2730 if (old_bypass
== bypass
)
2734 es
->flags
|= ZEBRA_EVPNES_BYPASS
;
2736 es
->flags
&= ~ZEBRA_EVPNES_BYPASS
;
2738 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2739 zlog_debug("bond %s es %s lacp bypass changed to %s", ifp
->name
,
2740 es
->esi_str
, bypass
? "on" : "off");
2742 /* send bypass update to BGP */
2743 if (es
->flags
& ZEBRA_EVPNES_READY_FOR_BGP
)
2744 zebra_evpn_es_send_add_to_client(es
);
2746 zebra_evpn_es_bypass_update_macs(es
, ifp
, bypass
);
2748 /* re-run DF election */
2749 dplane_updated
= zebra_evpn_es_run_df_election(es
, __func__
);
2751 /* disable SPH filter */
2752 if (!dplane_updated
&& (es
->flags
& ZEBRA_EVPNES_LOCAL
)
2753 && (listcount(es
->es_vtep_list
) > ES_VTEP_MAX_CNT
))
2754 zebra_evpn_es_br_port_dplane_update(es
, __func__
);
2757 static void zebra_evpn_es_bypass_cfg_update(struct zebra_if
*zif
, bool bypass
)
2759 bool old_bypass
= !!(zif
->es_info
.flags
& ZIF_CFG_ES_FLAG_BYPASS
);
2761 if (old_bypass
== bypass
)
2765 zif
->es_info
.flags
|= ZIF_CFG_ES_FLAG_BYPASS
;
2767 zif
->es_info
.flags
&= ~ZIF_CFG_ES_FLAG_BYPASS
;
2770 if (zif
->es_info
.es
)
2771 zebra_evpn_es_bypass_update(zif
->es_info
.es
, zif
->ifp
, bypass
);
2775 /* Only certain types of access ports can be setup as an Ethernet Segment */
2776 bool zebra_evpn_is_if_es_capable(struct zebra_if
*zif
)
2778 if (zif
->zif_type
== ZEBRA_IF_BOND
)
2781 /* relax the checks to allow config to be applied in zebra
2782 * before interface is rxed from the kernel
2784 if (zif
->ifp
->ifindex
== IFINDEX_INTERNAL
)
2787 /* XXX: allow swpX i.e. a regular ethernet port to be an ES link too */
2791 void zebra_evpn_if_es_print(struct vty
*vty
, json_object
*json
,
2792 struct zebra_if
*zif
)
2794 char buf
[ETHER_ADDR_STRLEN
];
2795 char esi_buf
[ESI_STR_LEN
];
2798 json_object
*json_evpn
;
2800 json_evpn
= json_object_new_object();
2801 json_object_object_add(json
, "evpnMh", json_evpn
);
2803 if (zif
->es_info
.lid
|| !is_zero_mac(&zif
->es_info
.sysmac
)) {
2804 json_object_int_add(json_evpn
, "esId",
2806 json_object_string_add(
2807 json_evpn
, "esSysmac",
2808 prefix_mac2str(&zif
->es_info
.sysmac
, buf
,
2810 } else if (memcmp(&zif
->es_info
.esi
, zero_esi
,
2811 sizeof(*zero_esi
))) {
2812 json_object_string_add(json_evpn
, "esId",
2813 esi_to_str(&zif
->es_info
.esi
,
2818 if (zif
->flags
& ZIF_FLAG_EVPN_MH_UPLINK
)
2819 json_object_string_add(
2820 json_evpn
, "uplink",
2821 CHECK_FLAG(zif
->flags
,
2822 ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP
)
2827 bool vty_print
= false;
2830 strlcat(mh_buf
, " EVPN-MH:", sizeof(mh_buf
));
2831 if (zif
->es_info
.lid
|| !is_zero_mac(&zif
->es_info
.sysmac
)) {
2833 snprintf(mh_buf
+ strlen(mh_buf
),
2834 sizeof(mh_buf
) - strlen(mh_buf
),
2835 " ES id %u ES sysmac %s", zif
->es_info
.lid
,
2836 prefix_mac2str(&zif
->es_info
.sysmac
, buf
,
2838 } else if (memcmp(&zif
->es_info
.esi
, zero_esi
,
2839 sizeof(*zero_esi
))) {
2841 snprintf(mh_buf
+ strnlen(mh_buf
, sizeof(mh_buf
)),
2843 - strnlen(mh_buf
, sizeof(mh_buf
)),
2845 esi_to_str(&zif
->es_info
.esi
, esi_buf
,
2849 if (zif
->flags
& ZIF_FLAG_EVPN_MH_UPLINK
) {
2851 if (zif
->flags
& ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP
)
2852 strlcat(mh_buf
, " uplink (up)", sizeof(mh_buf
));
2854 strlcat(mh_buf
, " uplink (down)",
2859 vty_out(vty
, "%s\n", mh_buf
);
2863 static void zebra_evpn_local_mac_oper_state_change(struct zebra_evpn_es
*es
)
2865 struct zebra_mac
*mac
;
2866 struct listnode
*node
;
2868 /* If fast-failover is supported by the dataplane via the use
2869 * of an ES backup NHG there is nothing to be done in the
2872 if (!(zmh_info
->flags
& ZEBRA_EVPN_MH_REDIRECT_OFF
))
2875 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
|| IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
2876 zlog_debug("mac slow-fail on es %s %s ", es
->esi_str
,
2877 (es
->flags
& ZEBRA_EVPNES_OPER_UP
) ? "up" : "down");
2879 for (ALL_LIST_ELEMENTS_RO(es
->mac_list
, node
, mac
)) {
2880 if (!(mac
->flags
& ZEBRA_MAC_LOCAL
)
2881 || !zebra_evpn_mac_is_static(mac
))
2884 if (es
->flags
& ZEBRA_EVPNES_OPER_UP
) {
2885 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
2887 "VNI %u mac %pEA move to acc %s es %s %s ",
2890 es
->zif
->ifp
->name
, es
->esi_str
,
2891 (es
->flags
& ZEBRA_EVPNES_OPER_UP
)
2894 /* switch the local macs to access port */
2895 if (zebra_evpn_sync_mac_dp_install(
2896 mac
, false /*set_inactive*/,
2897 false /*force_clear_static*/, __func__
)
2899 /* if the local mac install fails get rid of the
2902 zebra_evpn_rem_mac_uninstall(mac
->zevpn
, mac
,
2905 /* switch the local macs to network port. if there
2906 * is no active NHG we don't bother deleting the MAC;
2907 * that is left up to the dataplane to handle.
2909 if (!(es
->flags
& ZEBRA_EVPNES_NHG_ACTIVE
))
2911 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
2913 "VNI %u mac %pEA move to nhg %u es %s %s ",
2916 es
->nhg_id
, es
->esi_str
,
2917 (es
->flags
& ZEBRA_EVPNES_OPER_UP
)
2920 zebra_evpn_rem_mac_install(mac
->zevpn
, mac
,
2921 true /*was_static*/);
2926 void zebra_evpn_es_if_oper_state_change(struct zebra_if
*zif
, bool up
)
2928 struct zebra_evpn_es
*es
= zif
->es_info
.es
;
2929 bool old_up
= !!(es
->flags
& ZEBRA_EVPNES_OPER_UP
);
2934 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2935 zlog_debug("es %s state changed to %s ",
2937 up
? "up" : "down");
2939 es
->flags
|= ZEBRA_EVPNES_OPER_UP
;
2941 es
->flags
&= ~ZEBRA_EVPNES_OPER_UP
;
2943 zebra_evpn_es_run_df_election(es
, __func__
);
2944 zebra_evpn_local_mac_oper_state_change(es
);
2946 /* inform BGP of the ES oper state change */
2947 if (es
->flags
& ZEBRA_EVPNES_READY_FOR_BGP
)
2948 zebra_evpn_es_send_add_to_client(es
);
2951 static char *zebra_evpn_es_vtep_str(char *vtep_str
, struct zebra_evpn_es
*es
,
2952 uint8_t vtep_str_size
)
2954 struct zebra_evpn_es_vtep
*zvtep
;
2955 struct listnode
*node
;
2957 char ip_buf
[INET6_ADDRSTRLEN
];
2960 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, zvtep
)) {
2964 inet_ntop(AF_INET
, &zvtep
->vtep_ip
, ip_buf
,
2968 strlcat(vtep_str
, ",", vtep_str_size
);
2970 inet_ntop(AF_INET
, &zvtep
->vtep_ip
, ip_buf
,
2978 static void zebra_evpn_es_json_vtep_fill(struct zebra_evpn_es
*es
,
2979 json_object
*json_vteps
)
2981 struct zebra_evpn_es_vtep
*es_vtep
;
2982 struct listnode
*node
;
2983 json_object
*json_vtep_entry
;
2984 char alg_buf
[EVPN_DF_ALG_STR_LEN
];
2986 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
2987 json_vtep_entry
= json_object_new_object();
2988 json_object_string_addf(json_vtep_entry
, "vtep", "%pI4",
2990 if (es_vtep
->flags
& ZEBRA_EVPNES_VTEP_RXED_ESR
) {
2991 json_object_string_add(
2992 json_vtep_entry
, "dfAlgorithm",
2993 evpn_es_df_alg2str(es_vtep
->df_alg
, alg_buf
,
2995 json_object_int_add(json_vtep_entry
, "dfPreference",
2999 json_object_int_add(json_vtep_entry
, "nexthopId",
3000 es_vtep
->nh
->nh_id
);
3001 json_object_array_add(json_vteps
, json_vtep_entry
);
3005 static void zebra_evpn_es_show_entry(struct vty
*vty
, struct zebra_evpn_es
*es
,
3006 json_object
*json_array
)
3009 char vtep_str
[ES_VTEP_LIST_STR_SZ
];
3012 json_object
*json
= NULL
;
3013 json_object
*json_vteps
;
3014 json_object
*json_flags
;
3016 json
= json_object_new_object();
3017 json_object_string_add(json
, "esi", es
->esi_str
);
3020 & (ZEBRA_EVPNES_LOCAL
| ZEBRA_EVPNES_REMOTE
3021 | ZEBRA_EVPNES_NON_DF
)) {
3022 json_flags
= json_object_new_array();
3023 if (es
->flags
& ZEBRA_EVPNES_LOCAL
)
3024 json_array_string_add(json_flags
, "local");
3025 if (es
->flags
& ZEBRA_EVPNES_REMOTE
)
3026 json_array_string_add(json_flags
, "remote");
3027 if (es
->flags
& ZEBRA_EVPNES_NON_DF
)
3028 json_array_string_add(json_flags
, "nonDF");
3029 if (es
->flags
& ZEBRA_EVPNES_BYPASS
)
3030 json_array_string_add(json_flags
, "bypass");
3031 json_object_object_add(json
, "flags", json_flags
);
3035 json_object_string_add(json
, "accessPort",
3036 es
->zif
->ifp
->name
);
3038 if (listcount(es
->es_vtep_list
)) {
3039 json_vteps
= json_object_new_array();
3040 zebra_evpn_es_json_vtep_fill(es
, json_vteps
);
3041 json_object_object_add(json
, "vteps", json_vteps
);
3043 json_object_array_add(json_array
, json
);
3046 if (es
->flags
& ZEBRA_EVPNES_LOCAL
)
3047 strlcat(type_str
, "L", sizeof(type_str
));
3048 if (es
->flags
& ZEBRA_EVPNES_REMOTE
)
3049 strlcat(type_str
, "R", sizeof(type_str
));
3050 if (es
->flags
& ZEBRA_EVPNES_NON_DF
)
3051 strlcat(type_str
, "N", sizeof(type_str
));
3052 if (es
->flags
& ZEBRA_EVPNES_BYPASS
)
3053 strlcat(type_str
, "B", sizeof(type_str
));
3055 zebra_evpn_es_vtep_str(vtep_str
, es
, sizeof(vtep_str
));
3057 vty_out(vty
, "%-30s %-4s %-21s %s\n",
3058 es
->esi_str
, type_str
,
3059 es
->zif
? es
->zif
->ifp
->name
: "-",
3064 static void zebra_evpn_es_show_entry_detail(struct vty
*vty
,
3065 struct zebra_evpn_es
*es
, json_object
*json
)
3068 char alg_buf
[EVPN_DF_ALG_STR_LEN
];
3069 struct zebra_evpn_es_vtep
*es_vtep
;
3070 struct listnode
*node
;
3071 char thread_buf
[THREAD_TIMER_STRLEN
];
3074 json_object
*json_vteps
;
3075 json_object
*json_flags
;
3077 json_object_string_add(json
, "esi", es
->esi_str
);
3079 json_object_string_add(json
, "accessPort",
3080 es
->zif
->ifp
->name
);
3084 json_flags
= json_object_new_array();
3085 if (es
->flags
& ZEBRA_EVPNES_LOCAL
)
3086 json_array_string_add(json_flags
, "local");
3087 if (es
->flags
& ZEBRA_EVPNES_REMOTE
)
3088 json_array_string_add(json_flags
, "remote");
3089 if (es
->flags
& ZEBRA_EVPNES_NON_DF
)
3090 json_array_string_add(json_flags
, "nonDF");
3091 if (es
->flags
& ZEBRA_EVPNES_BYPASS
)
3092 json_array_string_add(json_flags
, "bypass");
3093 if (es
->flags
& ZEBRA_EVPNES_READY_FOR_BGP
)
3094 json_array_string_add(json_flags
,
3096 if (es
->flags
& ZEBRA_EVPNES_BR_PORT
)
3097 json_array_string_add(json_flags
, "bridgePort");
3098 if (es
->flags
& ZEBRA_EVPNES_OPER_UP
)
3099 json_array_string_add(json_flags
, "operUp");
3100 if (es
->flags
& ZEBRA_EVPNES_NHG_ACTIVE
)
3101 json_array_string_add(json_flags
,
3102 "nexthopGroupActive");
3103 json_object_object_add(json
, "flags", json_flags
);
3106 json_object_int_add(json
, "vniCount",
3107 listcount(es
->es_evi_list
));
3108 json_object_int_add(json
, "macCount", listcount(es
->mac_list
));
3109 json_object_int_add(json
, "dfPreference", es
->df_pref
);
3110 if (es
->df_delay_timer
)
3111 json_object_string_add(
3112 json
, "dfDelayTimer",
3113 thread_timer_to_hhmmss(thread_buf
,
3115 es
->df_delay_timer
));
3116 json_object_int_add(json
, "nexthopGroup", es
->nhg_id
);
3117 if (listcount(es
->es_vtep_list
)) {
3118 json_vteps
= json_object_new_array();
3119 zebra_evpn_es_json_vtep_fill(es
, json_vteps
);
3120 json_object_object_add(json
, "vteps", json_vteps
);
3124 if (es
->flags
& ZEBRA_EVPNES_LOCAL
)
3125 strlcat(type_str
, "Local", sizeof(type_str
));
3126 if (es
->flags
& ZEBRA_EVPNES_REMOTE
) {
3127 if (strnlen(type_str
, sizeof(type_str
)))
3128 strlcat(type_str
, ",", sizeof(type_str
));
3129 strlcat(type_str
, "Remote", sizeof(type_str
));
3132 vty_out(vty
, "ESI: %s\n", es
->esi_str
);
3133 vty_out(vty
, " Type: %s\n", type_str
);
3134 vty_out(vty
, " Interface: %s\n",
3136 es
->zif
->ifp
->name
: "-");
3137 if (es
->flags
& ZEBRA_EVPNES_LOCAL
) {
3138 vty_out(vty
, " State: %s\n",
3139 (es
->flags
& ZEBRA_EVPNES_OPER_UP
) ? "up"
3141 vty_out(vty
, " Bridge port: %s\n",
3142 (es
->flags
& ZEBRA_EVPNES_BR_PORT
) ? "yes"
3145 vty_out(vty
, " Ready for BGP: %s\n",
3146 (es
->flags
& ZEBRA_EVPNES_READY_FOR_BGP
) ?
3148 if (es
->flags
& ZEBRA_EVPNES_BYPASS
)
3149 vty_out(vty
, " LACP bypass: on\n");
3150 vty_out(vty
, " VNI Count: %d\n", listcount(es
->es_evi_list
));
3151 vty_out(vty
, " MAC Count: %d\n", listcount(es
->mac_list
));
3152 if (es
->flags
& ZEBRA_EVPNES_LOCAL
)
3153 vty_out(vty
, " DF status: %s \n",
3154 (es
->flags
& ZEBRA_EVPNES_NON_DF
) ? "non-df"
3156 if (es
->df_delay_timer
)
3157 vty_out(vty
, " DF delay: %s\n",
3158 thread_timer_to_hhmmss(thread_buf
,
3160 es
->df_delay_timer
));
3161 vty_out(vty
, " DF preference: %u\n", es
->df_pref
);
3162 vty_out(vty
, " Nexthop group: %u\n", es
->nhg_id
);
3163 vty_out(vty
, " VTEPs:\n");
3164 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
3165 vty_out(vty
, " %pI4",
3167 if (es_vtep
->flags
& ZEBRA_EVPNES_VTEP_RXED_ESR
)
3168 vty_out(vty
, " df_alg: %s df_pref: %d",
3169 evpn_es_df_alg2str(es_vtep
->df_alg
,
3173 vty_out(vty
, " nh: %u\n",
3174 es_vtep
->nh
? es_vtep
->nh
->nh_id
: 0);
3181 void zebra_evpn_es_show(struct vty
*vty
, bool uj
)
3183 struct zebra_evpn_es
*es
;
3184 json_object
*json_array
= NULL
;
3187 json_array
= json_object_new_array();
3189 vty_out(vty
, "Type: B bypass, L local, R remote, N non-DF\n");
3190 vty_out(vty
, "%-30s %-4s %-21s %s\n",
3191 "ESI", "Type", "ES-IF", "VTEPs");
3194 RB_FOREACH(es
, zebra_es_rb_head
, &zmh_info
->es_rb_tree
)
3195 zebra_evpn_es_show_entry(vty
, es
, json_array
);
3198 vty_json(vty
, json_array
);
3201 void zebra_evpn_es_show_detail(struct vty
*vty
, bool uj
)
3203 struct zebra_evpn_es
*es
;
3204 json_object
*json_array
= NULL
;
3207 json_array
= json_object_new_array();
3209 RB_FOREACH (es
, zebra_es_rb_head
, &zmh_info
->es_rb_tree
) {
3210 json_object
*json
= NULL
;
3213 json
= json_object_new_object();
3214 zebra_evpn_es_show_entry_detail(vty
, es
, json
);
3216 json_object_array_add(json_array
, json
);
3220 vty_json(vty
, json_array
);
3223 void zebra_evpn_es_show_esi(struct vty
*vty
, bool uj
, esi_t
*esi
)
3225 struct zebra_evpn_es
*es
;
3226 char esi_str
[ESI_STR_LEN
];
3227 json_object
*json
= NULL
;
3230 json
= json_object_new_object();
3232 es
= zebra_evpn_es_find(esi
);
3235 zebra_evpn_es_show_entry_detail(vty
, es
, json
);
3238 esi_to_str(esi
, esi_str
, sizeof(esi_str
));
3239 vty_out(vty
, "ESI %s does not exist\n", esi_str
);
3244 vty_json(vty
, json
);
3247 int zebra_evpn_mh_if_write(struct vty
*vty
, struct interface
*ifp
)
3249 struct zebra_if
*zif
= ifp
->info
;
3250 char buf
[ETHER_ADDR_STRLEN
];
3251 bool type_3_esi
= false;
3252 char esi_buf
[ESI_STR_LEN
];
3254 if (zif
->es_info
.lid
) {
3255 vty_out(vty
, " evpn mh es-id %u\n", zif
->es_info
.lid
);
3259 if (!is_zero_mac(&zif
->es_info
.sysmac
)) {
3260 vty_out(vty
, " evpn mh es-sys-mac %s\n",
3261 prefix_mac2str(&zif
->es_info
.sysmac
,
3267 && memcmp(&zif
->es_info
.esi
, zero_esi
, sizeof(*zero_esi
)))
3268 vty_out(vty
, " evpn mh es-id %s\n",
3269 esi_to_str(&zif
->es_info
.esi
, esi_buf
, sizeof(esi_buf
)));
3271 if (zif
->es_info
.df_pref
)
3272 vty_out(vty
, " evpn mh es-df-pref %u\n", zif
->es_info
.df_pref
);
3274 if (zif
->flags
& ZIF_FLAG_EVPN_MH_UPLINK
)
3275 vty_out(vty
, " evpn mh uplink\n");
3280 #include "zebra/zebra_evpn_mh_clippy.c"
3281 /* CLI for setting an ES in bypass mode */
3282 DEFPY_HIDDEN(zebra_evpn_es_bypass
, zebra_evpn_es_bypass_cmd
,
3283 "[no] evpn mh bypass",
3284 NO_STR
"EVPN\n" EVPN_MH_VTY_STR
"set bypass mode\n")
3286 VTY_DECLVAR_CONTEXT(interface
, ifp
);
3287 struct zebra_if
*zif
;
3292 zebra_evpn_es_bypass_cfg_update(zif
, false);
3294 if (!zebra_evpn_is_if_es_capable(zif
)) {
3296 "%% DF bypass cannot be associated with this interface type\n");
3299 zebra_evpn_es_bypass_cfg_update(zif
, true);
3304 /* CLI for configuring DF preference part for an ES */
3305 DEFPY(zebra_evpn_es_pref
, zebra_evpn_es_pref_cmd
,
3306 "[no$no] evpn mh es-df-pref [(1-65535)$df_pref]",
3307 NO_STR
"EVPN\n" EVPN_MH_VTY_STR
3308 "preference value used for DF election\n"
3311 VTY_DECLVAR_CONTEXT(interface
, ifp
);
3312 struct zebra_if
*zif
;
3317 zebra_evpn_es_df_pref_update(zif
, 0);
3319 if (!zebra_evpn_is_if_es_capable(zif
)) {
3321 "%% DF preference cannot be associated with this interface type\n");
3324 zebra_evpn_es_df_pref_update(zif
, df_pref
);
3329 /* CLI for setting up sysmac part of ESI on an access port */
3330 DEFPY(zebra_evpn_es_sys_mac
,
3331 zebra_evpn_es_sys_mac_cmd
,
3332 "[no$no] evpn mh es-sys-mac [X:X:X:X:X:X$mac]",
3336 "Ethernet segment system MAC\n"
3340 VTY_DECLVAR_CONTEXT(interface
, ifp
);
3341 struct zebra_if
*zif
;
3347 static struct ethaddr zero_mac
;
3349 ret
= zebra_evpn_es_sys_mac_update(zif
, &zero_mac
);
3351 vty_out(vty
, "%% Failed to clear ES sysmac\n");
3356 if (!zebra_evpn_is_if_es_capable(zif
)) {
3358 "%% ESI cannot be associated with this interface type\n");
3362 if (!mac
|| is_zero_mac(&mac
->eth_addr
)) {
3363 vty_out(vty
, "%% ES sysmac value is invalid\n");
3367 ret
= zebra_evpn_es_sys_mac_update(zif
, &mac
->eth_addr
);
3370 "%% ESI already exists on a different interface\n");
3377 /* CLI for setting up local-ID part of ESI on an access port */
3378 DEFPY(zebra_evpn_es_id
,
3379 zebra_evpn_es_id_cmd
,
3380 "[no$no] evpn mh es-id [(1-16777215)$es_lid | NAME$esi_str]",
3384 "Ethernet segment identifier\n"
3385 "local discriminator\n"
3386 "10-byte ID - 00:AA:BB:CC:DD:EE:FF:GG:HH:II\n"
3389 VTY_DECLVAR_CONTEXT(interface
, ifp
);
3390 struct zebra_if
*zif
;
3397 if (zif
->es_info
.lid
)
3398 ret
= zebra_evpn_es_lid_update(zif
, 0);
3399 else if (memcmp(&zif
->es_info
.esi
, zero_esi
, sizeof(*zero_esi
)))
3400 ret
= zebra_evpn_es_type0_esi_update(zif
, zero_esi
);
3404 "%% Failed to clear ES local id or ESI name\n");
3408 if (!zebra_evpn_is_if_es_capable(zif
)) {
3410 "%% ESI cannot be associated with this interface type\n");
3415 if (!str_to_esi(esi_str
, &esi
)) {
3416 vty_out(vty
, "%% Malformed ESI name\n");
3419 ret
= zebra_evpn_es_type0_esi_update(zif
, &esi
);
3423 "%% Specify ES local id or ESI name\n");
3426 ret
= zebra_evpn_es_lid_update(zif
, es_lid
);
3431 "%% ESI already exists on a different interface\n");
3438 /* CLI for tagging an interface as an uplink */
3439 DEFPY(zebra_evpn_mh_uplink
, zebra_evpn_mh_uplink_cmd
, "[no] evpn mh uplink",
3440 NO_STR
"EVPN\n" EVPN_MH_VTY_STR
"uplink to the VxLAN core\n")
3442 VTY_DECLVAR_CONTEXT(interface
, ifp
);
3443 struct zebra_if
*zif
;
3446 zebra_evpn_mh_uplink_cfg_update(zif
, no
? false : true);
3451 void zebra_evpn_mh_json(json_object
*json
)
3453 json_object
*json_array
;
3454 char thread_buf
[THREAD_TIMER_STRLEN
];
3456 json_object_int_add(json
, "macHoldtime", zmh_info
->mac_hold_time
);
3457 json_object_int_add(json
, "neighHoldtime", zmh_info
->neigh_hold_time
);
3458 json_object_int_add(json
, "startupDelay", zmh_info
->startup_delay_time
);
3459 json_object_string_add(
3460 json
, "startupDelayTimer",
3461 thread_timer_to_hhmmss(thread_buf
, sizeof(thread_buf
),
3462 zmh_info
->startup_delay_timer
));
3463 json_object_int_add(json
, "uplinkConfigCount",
3464 zmh_info
->uplink_cfg_cnt
);
3465 json_object_int_add(json
, "uplinkActiveCount",
3466 zmh_info
->uplink_oper_up_cnt
);
3468 if (zmh_info
->protodown_rc
) {
3469 json_array
= json_object_new_array();
3470 if (CHECK_FLAG(zmh_info
->protodown_rc
,
3471 ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY
))
3472 json_object_array_add(
3474 json_object_new_string("startupDelay"));
3475 if (CHECK_FLAG(zmh_info
->protodown_rc
,
3476 ZEBRA_PROTODOWN_EVPN_UPLINK_DOWN
))
3477 json_object_array_add(
3479 json_object_new_string("uplinkDown"));
3480 json_object_object_add(json
, "protodownReasons", json_array
);
3484 void zebra_evpn_mh_print(struct vty
*vty
)
3486 char pd_buf
[ZEBRA_PROTODOWN_RC_STR_LEN
];
3487 char thread_buf
[THREAD_TIMER_STRLEN
];
3489 vty_out(vty
, "EVPN MH:\n");
3490 vty_out(vty
, " mac-holdtime: %ds, neigh-holdtime: %ds\n",
3491 zmh_info
->mac_hold_time
, zmh_info
->neigh_hold_time
);
3492 vty_out(vty
, " startup-delay: %ds, start-delay-timer: %s\n",
3493 zmh_info
->startup_delay_time
,
3494 thread_timer_to_hhmmss(thread_buf
, sizeof(thread_buf
),
3495 zmh_info
->startup_delay_timer
));
3496 vty_out(vty
, " uplink-cfg-cnt: %u, uplink-active-cnt: %u\n",
3497 zmh_info
->uplink_cfg_cnt
, zmh_info
->uplink_oper_up_cnt
);
3498 if (zmh_info
->protodown_rc
)
3499 vty_out(vty
, " protodown reasons: %s\n",
3500 zebra_protodown_rc_str(zmh_info
->protodown_rc
, pd_buf
,
3504 /*****************************************************************************/
3505 /* A base L2-VNI is maintained to derive parameters such as ES originator-IP.
3506 * XXX: once single vxlan device model becomes available this will not be
3509 /* called when a new vni is added or becomes oper up or becomes a bridge port */
3510 void zebra_evpn_es_set_base_evpn(struct zebra_evpn
*zevpn
)
3512 struct listnode
*node
;
3513 struct zebra_evpn_es
*es
;
3515 if (zmh_info
->es_base_evpn
) {
3516 if (zmh_info
->es_base_evpn
!= zevpn
) {
3517 /* unrelated EVPN; ignore it */
3520 /* check if the local vtep-ip has changed */
3522 /* check if the EVPN can be used as base EVPN */
3523 if (!zebra_evpn_send_to_client_ok(zevpn
))
3526 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3527 zlog_debug("es base vni set to %d",
3529 zmh_info
->es_base_evpn
= zevpn
;
3532 /* update local VTEP-IP */
3533 if (zmh_info
->es_originator_ip
.s_addr
==
3534 zmh_info
->es_base_evpn
->local_vtep_ip
.s_addr
)
3537 zmh_info
->es_originator_ip
.s_addr
=
3538 zmh_info
->es_base_evpn
->local_vtep_ip
.s_addr
;
3540 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3541 zlog_debug("es originator ip set to %pI4",
3542 &zmh_info
->es_base_evpn
->local_vtep_ip
);
3544 /* if originator ip changes we need to update bgp */
3545 for (ALL_LIST_ELEMENTS_RO(zmh_info
->local_es_list
, node
, es
)) {
3546 zebra_evpn_es_run_df_election(es
, __func__
);
3548 if (es
->flags
& ZEBRA_EVPNES_READY_FOR_BGP
)
3549 zebra_evpn_es_send_add_to_client(es
);
3551 zebra_evpn_es_re_eval_send_to_client(es
,
3552 true /* es_evi_re_reval */);
3556 /* called when a vni is removed or becomes oper down or is removed from a
3559 void zebra_evpn_es_clear_base_evpn(struct zebra_evpn
*zevpn
)
3561 struct listnode
*node
;
3562 struct zebra_evpn_es
*es
;
3564 if (zmh_info
->es_base_evpn
!= zevpn
)
3567 zmh_info
->es_base_evpn
= NULL
;
3568 /* lost current base EVPN; try to find a new one */
3569 zebra_evpn_es_get_one_base_evpn();
3571 /* couldn't locate an eligible base evpn */
3572 if (!zmh_info
->es_base_evpn
&& zmh_info
->es_originator_ip
.s_addr
) {
3573 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3574 zlog_debug("es originator ip cleared");
3576 zmh_info
->es_originator_ip
.s_addr
= 0;
3577 /* lost originator ip */
3578 for (ALL_LIST_ELEMENTS_RO(zmh_info
->local_es_list
, node
, es
)) {
3579 zebra_evpn_es_re_eval_send_to_client(es
,
3580 true /* es_evi_re_reval */);
3585 /* Locate an "eligible" L2-VNI to follow */
3586 static int zebra_evpn_es_get_one_base_evpn_cb(struct hash_bucket
*b
, void *data
)
3588 struct zebra_evpn
*zevpn
= b
->data
;
3590 zebra_evpn_es_set_base_evpn(zevpn
);
3592 if (zmh_info
->es_base_evpn
)
3593 return HASHWALK_ABORT
;
3595 return HASHWALK_CONTINUE
;
3598 /* locate a base_evpn to follow for the purposes of common params like
3601 static void zebra_evpn_es_get_one_base_evpn(void)
3603 struct zebra_vrf
*zvrf
;
3605 zvrf
= zebra_vrf_get_evpn();
3606 hash_walk(zvrf
->evpn_table
, zebra_evpn_es_get_one_base_evpn_cb
, NULL
);
3609 /*****************************************************************************
3610 * local ethernet segments can be error-disabled if the switch is not
3611 * ready to start transmitting traffic via the VxLAN overlay
3613 bool zebra_evpn_is_es_bond(struct interface
*ifp
)
3615 struct zebra_if
*zif
= ifp
->info
;
3617 return !!(struct zebra_if
*)zif
->es_info
.es
;
3620 bool zebra_evpn_is_es_bond_member(struct interface
*ifp
)
3622 struct zebra_if
*zif
= ifp
->info
;
3624 return IS_ZEBRA_IF_BOND_SLAVE(zif
->ifp
) && zif
->bondslave_info
.bond_if
3625 && ((struct zebra_if
*)zif
->bondslave_info
.bond_if
->info
)
3629 void zebra_evpn_mh_update_protodown_bond_mbr(struct zebra_if
*zif
, bool clear
,
3633 uint32_t old_protodown_rc
= 0;
3634 uint32_t new_protodown_rc
= 0;
3635 uint32_t protodown_rc
= 0;
3638 struct zebra_if
*bond_zif
;
3640 bond_zif
= zif
->bondslave_info
.bond_if
->info
;
3641 protodown_rc
= bond_zif
->protodown_rc
;
3644 old_protodown_rc
= zif
->protodown_rc
;
3645 new_protodown_rc
= (old_protodown_rc
& ~ZEBRA_PROTODOWN_EVPN_ALL
);
3646 new_protodown_rc
|= (protodown_rc
& ZEBRA_PROTODOWN_EVPN_ALL
);
3647 new_protodown
= !!new_protodown_rc
;
3649 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
&& (new_protodown_rc
!= old_protodown_rc
))
3651 "%s bond mbr %s protodown_rc changed; old 0x%x new 0x%x",
3652 caller
, zif
->ifp
->name
, old_protodown_rc
,
3655 if (zebra_if_update_protodown_rc(zif
->ifp
, new_protodown
,
3656 new_protodown_rc
) == 0) {
3657 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3658 zlog_debug("%s protodown %s", zif
->ifp
->name
,
3659 new_protodown
? "on" : "off");
3663 /* The bond members inherit the protodown reason code from the bond */
3664 static void zebra_evpn_mh_update_protodown_bond(struct zebra_if
*bond_zif
)
3666 struct zebra_if
*zif
;
3667 struct listnode
*node
;
3669 if (!bond_zif
->bond_info
.mbr_zifs
)
3672 for (ALL_LIST_ELEMENTS_RO(bond_zif
->bond_info
.mbr_zifs
, node
, zif
)) {
3673 zebra_evpn_mh_update_protodown_bond_mbr(zif
, false /*clear*/,
3678 /* The global EVPN MH protodown rc is applied to all local ESs */
3679 static void zebra_evpn_mh_update_protodown_es(struct zebra_evpn_es
*es
,
3682 struct zebra_if
*zif
;
3683 uint32_t old_protodown_rc
;
3686 /* if the reason code is the same bail unless it is a new
3687 * ES bond in that case we would need to ensure that the
3688 * dplane is really in sync with zebra
3691 && (zif
->protodown_rc
& ZEBRA_PROTODOWN_EVPN_ALL
)
3692 == (zmh_info
->protodown_rc
& ZEBRA_PROTODOWN_EVPN_ALL
))
3695 old_protodown_rc
= zif
->protodown_rc
;
3696 zif
->protodown_rc
&= ~ZEBRA_PROTODOWN_EVPN_ALL
;
3697 zif
->protodown_rc
|=
3698 (zmh_info
->protodown_rc
& ZEBRA_PROTODOWN_EVPN_ALL
);
3700 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
3701 && (old_protodown_rc
!= zif
->protodown_rc
))
3703 "es %s ifp %s protodown_rc changed; old 0x%x new 0x%x",
3704 es
->esi_str
, zif
->ifp
->name
, old_protodown_rc
,
3707 /* update dataplane with the new protodown setting */
3708 zebra_evpn_mh_update_protodown_bond(zif
);
3711 static void zebra_evpn_mh_clear_protodown_es(struct zebra_evpn_es
*es
)
3713 struct zebra_if
*zif
;
3714 uint32_t old_protodown_rc
;
3717 if (!(zif
->protodown_rc
& ZEBRA_PROTODOWN_EVPN_ALL
))
3720 old_protodown_rc
= zif
->protodown_rc
;
3721 zif
->protodown_rc
&= ~ZEBRA_PROTODOWN_EVPN_ALL
;
3723 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3725 "clear: es %s ifp %s protodown_rc cleared; old 0x%x new 0x%x",
3726 es
->esi_str
, zif
->ifp
->name
, old_protodown_rc
,
3729 /* update dataplane with the new protodown setting */
3730 zebra_evpn_mh_update_protodown_bond(zif
);
3733 static void zebra_evpn_mh_update_protodown_es_all(void)
3735 struct listnode
*node
;
3736 struct zebra_evpn_es
*es
;
3738 for (ALL_LIST_ELEMENTS_RO(zmh_info
->local_es_list
, node
, es
))
3739 zebra_evpn_mh_update_protodown_es(es
, false /*resync_dplane*/);
3742 static void zebra_evpn_mh_update_protodown(uint32_t protodown_rc
, bool set
)
3744 uint32_t old_protodown_rc
= zmh_info
->protodown_rc
;
3747 if ((protodown_rc
& zmh_info
->protodown_rc
) == protodown_rc
)
3750 zmh_info
->protodown_rc
|= protodown_rc
;
3752 if (!(protodown_rc
& zmh_info
->protodown_rc
))
3754 zmh_info
->protodown_rc
&= ~protodown_rc
;
3757 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3758 zlog_debug("mh protodown_rc changed; old 0x%x new 0x%x",
3759 old_protodown_rc
, zmh_info
->protodown_rc
);
3760 zebra_evpn_mh_update_protodown_es_all();
3763 static inline bool zebra_evpn_mh_is_all_uplinks_down(void)
3765 return zmh_info
->uplink_cfg_cnt
&& !zmh_info
->uplink_oper_up_cnt
;
3768 static void zebra_evpn_mh_uplink_oper_flags_update(struct zebra_if
*zif
,
3771 if (set
&& if_is_operative(zif
->ifp
)) {
3772 if (!(zif
->flags
& ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP
)) {
3773 zif
->flags
|= ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP
;
3774 ++zmh_info
->uplink_oper_up_cnt
;
3777 if (zif
->flags
& ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP
) {
3778 zif
->flags
&= ~ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP
;
3779 if (zmh_info
->uplink_oper_up_cnt
)
3780 --zmh_info
->uplink_oper_up_cnt
;
3785 static void zebra_evpn_mh_uplink_cfg_update(struct zebra_if
*zif
, bool set
)
3787 bool old_protodown
= zebra_evpn_mh_is_all_uplinks_down();
3791 if (zif
->flags
& ZIF_FLAG_EVPN_MH_UPLINK
)
3794 zif
->flags
|= ZIF_FLAG_EVPN_MH_UPLINK
;
3795 ++zmh_info
->uplink_cfg_cnt
;
3797 if (!(zif
->flags
& ZIF_FLAG_EVPN_MH_UPLINK
))
3800 zif
->flags
&= ~ZIF_FLAG_EVPN_MH_UPLINK
;
3801 if (zmh_info
->uplink_cfg_cnt
)
3802 --zmh_info
->uplink_cfg_cnt
;
3805 zebra_evpn_mh_uplink_oper_flags_update(zif
, set
);
3806 new_protodown
= zebra_evpn_mh_is_all_uplinks_down();
3807 if (old_protodown
== new_protodown
)
3810 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3812 "mh-uplink-cfg-chg on if %s/%d %s uplinks cfg %u up %u",
3813 zif
->ifp
->name
, zif
->ifp
->ifindex
, set
? "set" : "down",
3814 zmh_info
->uplink_cfg_cnt
, zmh_info
->uplink_oper_up_cnt
);
3816 zebra_evpn_mh_update_protodown(ZEBRA_PROTODOWN_EVPN_UPLINK_DOWN
,
3820 void zebra_evpn_mh_uplink_oper_update(struct zebra_if
*zif
)
3822 bool old_protodown
= zebra_evpn_mh_is_all_uplinks_down();
3825 zebra_evpn_mh_uplink_oper_flags_update(zif
, true /*set*/);
3827 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3829 "mh-uplink-oper-chg on if %s/%d %s; uplinks cfg %u up %u",
3830 zif
->ifp
->name
, zif
->ifp
->ifindex
,
3831 if_is_operative(zif
->ifp
) ? "up" : "down",
3832 zmh_info
->uplink_cfg_cnt
, zmh_info
->uplink_oper_up_cnt
);
3834 new_protodown
= zebra_evpn_mh_is_all_uplinks_down();
3835 if (old_protodown
== new_protodown
)
3838 /* if protodown_rc XXX_UPLINK_DOWN is about to be cleared
3839 * fire up the start-up delay timer to allow the EVPN network
3840 * to converge (Type-2 routes need to be advertised and processed)
3842 if (!new_protodown
&& (zmh_info
->uplink_oper_up_cnt
== 1))
3843 zebra_evpn_mh_startup_delay_timer_start("uplink-up");
3845 zebra_evpn_mh_update_protodown(ZEBRA_PROTODOWN_EVPN_UPLINK_DOWN
,
3849 static void zebra_evpn_mh_startup_delay_exp_cb(struct thread
*t
)
3851 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3852 zlog_debug("startup-delay expired");
3854 zebra_evpn_mh_update_protodown(ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY
,
3858 static void zebra_evpn_mh_startup_delay_timer_start(const char *rc
)
3860 if (zmh_info
->startup_delay_timer
) {
3861 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3862 zlog_debug("startup-delay timer cancelled");
3863 THREAD_OFF(zmh_info
->startup_delay_timer
);
3866 if (zmh_info
->startup_delay_time
) {
3867 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3869 "startup-delay timer started for %d sec on %s",
3870 zmh_info
->startup_delay_time
, rc
);
3871 thread_add_timer(zrouter
.master
,
3872 zebra_evpn_mh_startup_delay_exp_cb
, NULL
,
3873 zmh_info
->startup_delay_time
,
3874 &zmh_info
->startup_delay_timer
);
3875 zebra_evpn_mh_update_protodown(
3876 ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY
, true /* set */);
3878 zebra_evpn_mh_update_protodown(
3879 ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY
, false /* set */);
3883 /*****************************************************************************
3884 * Nexthop management: nexthops associated with Type-2 routes that have
3885 * an ES as destination are consolidated by BGP into a per-VRF nh->rmac
3886 * mapping which is the installed as a remote neigh/fdb entry with a
3887 * dummy (type-1) prefix referencing it.
3888 * This handling is needed because Type-2 routes with ES as dest use NHG
3889 * that are setup using EAD routes (i.e. such NHGs do not include the
3891 ****************************************************************************/
3892 void zebra_evpn_proc_remote_nh(ZAPI_HANDLER_ARGS
)
3897 struct ethaddr rmac
;
3898 struct prefix_evpn dummy_prefix
;
3899 size_t min_len
= 4 + sizeof(nh
);
3904 * Ensure that the stream sent to us is long enough
3906 if (hdr
->command
== ZEBRA_EVPN_REMOTE_NH_ADD
)
3907 min_len
+= sizeof(rmac
);
3908 if (hdr
->length
< min_len
)
3911 vrf_id
= stream_getl(s
);
3912 stream_get(&nh
, s
, sizeof(nh
));
3914 memset(&dummy_prefix
, 0, sizeof(dummy_prefix
));
3915 dummy_prefix
.family
= AF_EVPN
;
3916 dummy_prefix
.prefixlen
= (sizeof(struct evpn_addr
) * 8);
3917 dummy_prefix
.prefix
.route_type
= 1; /* XXX - fixup to type-1 def */
3918 dummy_prefix
.prefix
.ead_addr
.ip
.ipa_type
= nh
.ipa_type
;
3920 if (hdr
->command
== ZEBRA_EVPN_REMOTE_NH_ADD
) {
3921 stream_get(&rmac
, s
, sizeof(rmac
));
3922 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3924 "evpn remote nh %d %pIA rmac %pEA add pfx %pFX",
3925 vrf_id
, &nh
, &rmac
, &dummy_prefix
);
3926 zebra_rib_queue_evpn_route_add(vrf_id
, &rmac
, &nh
,
3927 (struct prefix
*)&dummy_prefix
);
3929 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3930 zlog_debug("evpn remote nh %d %pIA del pfx %pFX",
3931 vrf_id
, &nh
, &dummy_prefix
);
3932 zebra_rib_queue_evpn_route_del(vrf_id
, &nh
,
3933 (struct prefix
*)&dummy_prefix
);
3937 /*****************************************************************************/
3938 void zebra_evpn_mh_config_write(struct vty
*vty
)
3940 if (zmh_info
->mac_hold_time
!= ZEBRA_EVPN_MH_MAC_HOLD_TIME_DEF
)
3941 vty_out(vty
, "evpn mh mac-holdtime %d\n",
3942 zmh_info
->mac_hold_time
);
3944 if (zmh_info
->neigh_hold_time
!= ZEBRA_EVPN_MH_NEIGH_HOLD_TIME_DEF
)
3945 vty_out(vty
, "evpn mh neigh-holdtime %d\n",
3946 zmh_info
->neigh_hold_time
);
3948 if (zmh_info
->startup_delay_time
!= ZEBRA_EVPN_MH_STARTUP_DELAY_DEF
)
3949 vty_out(vty
, "evpn mh startup-delay %d\n",
3950 zmh_info
->startup_delay_time
);
3952 if (zmh_info
->flags
& ZEBRA_EVPN_MH_REDIRECT_OFF
)
3953 vty_out(vty
, "evpn mh redirect-off\n");
3956 int zebra_evpn_mh_neigh_holdtime_update(struct vty
*vty
,
3957 uint32_t duration
, bool set_default
)
3960 duration
= ZEBRA_EVPN_MH_NEIGH_HOLD_TIME_DEF
;
3962 zmh_info
->neigh_hold_time
= duration
;
3967 int zebra_evpn_mh_mac_holdtime_update(struct vty
*vty
,
3968 uint32_t duration
, bool set_default
)
3971 duration
= ZEBRA_EVPN_MH_MAC_HOLD_TIME_DEF
;
3973 zmh_info
->mac_hold_time
= duration
;
3978 int zebra_evpn_mh_startup_delay_update(struct vty
*vty
, uint32_t duration
,
3982 duration
= ZEBRA_EVPN_MH_STARTUP_DELAY_DEF
;
3984 zmh_info
->startup_delay_time
= duration
;
3986 /* if startup_delay_timer is running allow it to be adjusted
3989 if (zmh_info
->startup_delay_timer
)
3990 zebra_evpn_mh_startup_delay_timer_start("config");
3995 int zebra_evpn_mh_redirect_off(struct vty
*vty
, bool redirect_off
)
3997 /* This knob needs to be set before ESs are configured
3998 * i.e. cannot be changed on the fly
4001 zmh_info
->flags
|= ZEBRA_EVPN_MH_REDIRECT_OFF
;
4003 zmh_info
->flags
&= ~ZEBRA_EVPN_MH_REDIRECT_OFF
;
4008 void zebra_evpn_interface_init(void)
4010 install_element(INTERFACE_NODE
, &zebra_evpn_es_id_cmd
);
4011 install_element(INTERFACE_NODE
, &zebra_evpn_es_sys_mac_cmd
);
4012 install_element(INTERFACE_NODE
, &zebra_evpn_es_pref_cmd
);
4013 install_element(INTERFACE_NODE
, &zebra_evpn_es_bypass_cmd
);
4014 install_element(INTERFACE_NODE
, &zebra_evpn_mh_uplink_cmd
);
4017 void zebra_evpn_mh_init(void)
4019 zrouter
.mh_info
= XCALLOC(MTYPE_ZMH_INFO
, sizeof(*zrouter
.mh_info
));
4021 zmh_info
->mac_hold_time
= ZEBRA_EVPN_MH_MAC_HOLD_TIME_DEF
;
4022 zmh_info
->neigh_hold_time
= ZEBRA_EVPN_MH_NEIGH_HOLD_TIME_DEF
;
4023 /* setup ES tables */
4024 RB_INIT(zebra_es_rb_head
, &zmh_info
->es_rb_tree
);
4025 zmh_info
->local_es_list
= list_new();
4026 listset_app_node_mem(zmh_info
->local_es_list
);
4028 bf_init(zmh_info
->nh_id_bitmap
, EVPN_NH_ID_MAX
);
4029 bf_assign_zero_index(zmh_info
->nh_id_bitmap
);
4030 zmh_info
->nhg_table
= hash_create(zebra_evpn_nhg_hash_keymake
,
4031 zebra_evpn_nhg_cmp
, "l2 NHG table");
4032 zmh_info
->nh_ip_table
=
4033 hash_create(zebra_evpn_nh_ip_hash_keymake
, zebra_evpn_nh_ip_cmp
,
4036 /* setup broadcast domain tables */
4037 zmh_info
->evpn_vlan_table
= hash_create(zebra_evpn_acc_vl_hash_keymake
,
4038 zebra_evpn_acc_vl_cmp
, "access VLAN hash table");
4040 zmh_info
->startup_delay_time
= ZEBRA_EVPN_MH_STARTUP_DELAY_DEF
;
4041 zebra_evpn_mh_startup_delay_timer_start("init");
4044 void zebra_evpn_mh_terminate(void)
4046 list_delete(&zmh_info
->local_es_list
);
4048 hash_iterate(zmh_info
->evpn_vlan_table
,
4049 zebra_evpn_acc_vl_cleanup_all
, NULL
);
4050 hash_free(zmh_info
->evpn_vlan_table
);
4051 hash_free(zmh_info
->nhg_table
);
4052 hash_free(zmh_info
->nh_ip_table
);
4053 bf_free(zmh_info
->nh_id_bitmap
);
4055 XFREE(MTYPE_ZMH_INFO
, zrouter
.mh_info
);