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_l2_bridge_if.h"
45 #include "zebra/zebra_ns.h"
46 #include "zebra/zebra_vrf.h"
47 #include "zebra/zebra_vxlan.h"
48 #include "zebra/zebra_vxlan_private.h"
49 #include "zebra/zebra_evpn.h"
50 #include "zebra/zebra_evpn_mac.h"
51 #include "zebra/zebra_router.h"
52 #include "zebra/zebra_evpn_mh.h"
53 #include "zebra/zebra_nhg.h"
55 DEFINE_MTYPE_STATIC(ZEBRA
, ZACC_BD
, "Access Broadcast Domain");
56 DEFINE_MTYPE_STATIC(ZEBRA
, ZES
, "Ethernet Segment");
57 DEFINE_MTYPE_STATIC(ZEBRA
, ZES_EVI
, "ES info per-EVI");
58 DEFINE_MTYPE_STATIC(ZEBRA
, ZMH_INFO
, "MH global info");
59 DEFINE_MTYPE_STATIC(ZEBRA
, ZES_VTEP
, "VTEP attached to the ES");
60 DEFINE_MTYPE_STATIC(ZEBRA
, L2_NH
, "L2 nexthop");
62 static void zebra_evpn_es_get_one_base_evpn(void);
63 static int zebra_evpn_es_evi_send_to_client(struct zebra_evpn_es
*es
,
64 struct zebra_evpn
*zevpn
, bool add
);
65 static void zebra_evpn_local_es_del(struct zebra_evpn_es
**esp
);
66 static int zebra_evpn_local_es_update(struct zebra_if
*zif
, esi_t
*esi
);
67 static bool zebra_evpn_es_br_port_dplane_update(struct zebra_evpn_es
*es
,
69 static void zebra_evpn_mh_uplink_cfg_update(struct zebra_if
*zif
, bool set
);
70 static void zebra_evpn_mh_update_protodown_es(struct zebra_evpn_es
*es
,
72 static void zebra_evpn_mh_clear_protodown_es(struct zebra_evpn_es
*es
);
73 static void zebra_evpn_mh_startup_delay_timer_start(const char *rc
);
75 esi_t zero_esi_buf
, *zero_esi
= &zero_esi_buf
;
77 /*****************************************************************************/
78 /* Ethernet Segment to EVI association -
79 * 1. The ES-EVI entry is maintained as a RB tree per L2-VNI
80 * (struct zebra_evpn.es_evi_rb_tree).
81 * 2. Each local ES-EVI entry is sent to BGP which advertises it as an
82 * EAD-EVI (Type-1 EVPN) route
83 * 3. Local ES-EVI setup is re-evaluated on the following triggers -
84 * a. When an ESI is set or cleared on an access port.
85 * b. When an access port associated with an ESI is deleted.
86 * c. When VLAN member ship changes on an access port.
87 * d. When a VXLAN_IF is set or cleared on an access broadcast domain.
88 * e. When a L2-VNI is added or deleted for a VxLAN_IF.
89 * 4. Currently zebra doesn't remote ES-EVIs. Those are managed and maintained
90 * entirely in BGP which consolidates them into a remote ES. The remote ES
91 * is then sent to zebra which allocates a NHG for it.
94 /* compare ES-IDs for the ES-EVI RB tree maintained per-EVPN */
95 static int zebra_es_evi_rb_cmp(const struct zebra_evpn_es_evi
*es_evi1
,
96 const struct zebra_evpn_es_evi
*es_evi2
)
98 return memcmp(&es_evi1
->es
->esi
, &es_evi2
->es
->esi
, ESI_BYTES
);
100 RB_GENERATE(zebra_es_evi_rb_head
, zebra_evpn_es_evi
,
101 rb_node
, zebra_es_evi_rb_cmp
);
103 /* allocate a new ES-EVI and insert it into the per-L2-VNI and per-ES
106 static struct zebra_evpn_es_evi
*zebra_evpn_es_evi_new(struct zebra_evpn_es
*es
,
107 struct zebra_evpn
*zevpn
)
109 struct zebra_evpn_es_evi
*es_evi
;
111 es_evi
= XCALLOC(MTYPE_ZES_EVI
, sizeof(struct zebra_evpn_es_evi
));
114 es_evi
->zevpn
= zevpn
;
116 /* insert into the EVPN-ESI rb tree */
117 RB_INSERT(zebra_es_evi_rb_head
, &zevpn
->es_evi_rb_tree
, es_evi
);
119 /* add to the ES's VNI list */
120 listnode_init(&es_evi
->es_listnode
, es_evi
);
121 listnode_add(es
->es_evi_list
, &es_evi
->es_listnode
);
123 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
124 zlog_debug("es %s evi %d new",
125 es_evi
->es
->esi_str
, es_evi
->zevpn
->vni
);
130 /* Evaluate if the es_evi is ready to be sent BGP -
131 * 1. If it is ready an add is sent to BGP
132 * 2. If it is not ready a del is sent (if the ES had been previously added
135 static void zebra_evpn_es_evi_re_eval_send_to_client(
136 struct zebra_evpn_es_evi
*es_evi
)
141 old_ready
= !!(es_evi
->flags
& ZEBRA_EVPNES_EVI_READY_FOR_BGP
);
143 /* ES and L2-VNI have to be individually ready for BGP */
144 if ((es_evi
->flags
& ZEBRA_EVPNES_EVI_LOCAL
) &&
145 (es_evi
->es
->flags
& ZEBRA_EVPNES_READY_FOR_BGP
) &&
146 zebra_evpn_send_to_client_ok(es_evi
->zevpn
))
147 es_evi
->flags
|= ZEBRA_EVPNES_EVI_READY_FOR_BGP
;
149 es_evi
->flags
&= ~ZEBRA_EVPNES_EVI_READY_FOR_BGP
;
151 new_ready
= !!(es_evi
->flags
& ZEBRA_EVPNES_EVI_READY_FOR_BGP
);
153 if (old_ready
== new_ready
)
157 zebra_evpn_es_evi_send_to_client(es_evi
->es
, es_evi
->zevpn
,
160 zebra_evpn_es_evi_send_to_client(es_evi
->es
, es_evi
->zevpn
,
164 /* remove the ES-EVI from the per-L2-VNI and per-ES tables and free
167 static void zebra_evpn_es_evi_free(struct zebra_evpn_es_evi
*es_evi
)
169 struct zebra_evpn_es
*es
= es_evi
->es
;
170 struct zebra_evpn
*zevpn
= es_evi
->zevpn
;
172 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
173 zlog_debug("es %s evi %d free",
174 es_evi
->es
->esi_str
, es_evi
->zevpn
->vni
);
176 /* remove from the ES's VNI list */
177 list_delete_node(es
->es_evi_list
, &es_evi
->es_listnode
);
179 /* remove from the VNI-ESI rb tree */
180 RB_REMOVE(zebra_es_evi_rb_head
, &zevpn
->es_evi_rb_tree
, es_evi
);
182 /* remove from the VNI-ESI rb tree */
183 XFREE(MTYPE_ZES_EVI
, es_evi
);
186 /* find the ES-EVI in the per-L2-VNI RB tree */
187 struct zebra_evpn_es_evi
*zebra_evpn_es_evi_find(struct zebra_evpn_es
*es
,
188 struct zebra_evpn
*zevpn
)
190 struct zebra_evpn_es_evi es_evi
;
194 return RB_FIND(zebra_es_evi_rb_head
, &zevpn
->es_evi_rb_tree
, &es_evi
);
197 /* Tell BGP about an ES-EVI deletion and then delete it */
198 static void zebra_evpn_local_es_evi_do_del(struct zebra_evpn_es_evi
*es_evi
)
200 if (!(es_evi
->flags
& ZEBRA_EVPNES_EVI_LOCAL
))
203 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
204 zlog_debug("local es %s evi %d del",
205 es_evi
->es
->esi_str
, es_evi
->zevpn
->vni
);
207 if (es_evi
->flags
& ZEBRA_EVPNES_EVI_READY_FOR_BGP
) {
208 /* send a del only if add was sent for it earlier */
209 zebra_evpn_es_evi_send_to_client(es_evi
->es
,
210 es_evi
->zevpn
, false /* add */);
213 /* delete it from the EVPN's local list */
214 list_delete_node(es_evi
->zevpn
->local_es_evi_list
,
215 &es_evi
->l2vni_listnode
);
217 es_evi
->flags
&= ~ZEBRA_EVPNES_EVI_LOCAL
;
218 zebra_evpn_es_evi_free(es_evi
);
220 static void zebra_evpn_local_es_evi_del(struct zebra_evpn_es
*es
,
221 struct zebra_evpn
*zevpn
)
223 struct zebra_evpn_es_evi
*es_evi
;
225 es_evi
= zebra_evpn_es_evi_find(es
, zevpn
);
227 zebra_evpn_local_es_evi_do_del(es_evi
);
230 /* If there are any existing MAC entries for this es/zevpn we need
231 * to install it in the dataplane.
233 * Note: primary purpose of this is to handle es del/re-add windows where
234 * sync MAC entries may be added by bgpd before the es-evi membership is
235 * created in the dataplane and in zebra
237 static void zebra_evpn_es_evi_mac_install(struct zebra_evpn_es_evi
*es_evi
)
239 struct zebra_mac
*mac
;
240 struct listnode
*node
;
241 struct zebra_evpn_es
*es
= es_evi
->es
;
243 if (listcount(es
->mac_list
) && IS_ZEBRA_DEBUG_EVPN_MH_ES
)
244 zlog_debug("dp-mac install on es %s evi %d add", es
->esi_str
,
247 for (ALL_LIST_ELEMENTS_RO(es
->mac_list
, node
, mac
)) {
248 if (mac
->zevpn
!= es_evi
->zevpn
)
251 if (!CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
))
254 zebra_evpn_sync_mac_dp_install(mac
, false, false, __func__
);
258 /* Create an ES-EVI if it doesn't already exist and tell BGP */
259 static void zebra_evpn_local_es_evi_add(struct zebra_evpn_es
*es
,
260 struct zebra_evpn
*zevpn
)
262 struct zebra_evpn_es_evi
*es_evi
;
264 es_evi
= zebra_evpn_es_evi_find(es
, zevpn
);
266 es_evi
= zebra_evpn_es_evi_new(es
, zevpn
);
270 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
271 zlog_debug("local es %s evi %d add",
272 es_evi
->es
->esi_str
, es_evi
->zevpn
->vni
);
273 es_evi
->flags
|= ZEBRA_EVPNES_EVI_LOCAL
;
274 /* add to the EVPN's local list */
275 listnode_init(&es_evi
->l2vni_listnode
, es_evi
);
276 listnode_add(zevpn
->local_es_evi_list
, &es_evi
->l2vni_listnode
);
278 zebra_evpn_es_evi_re_eval_send_to_client(es_evi
);
280 zebra_evpn_es_evi_mac_install(es_evi
);
284 static void zebra_evpn_es_evi_show_entry(struct vty
*vty
,
285 struct zebra_evpn_es_evi
*es_evi
,
286 json_object
*json_array
)
292 json_object
*json_types
;
294 /* Separate JSON object for each es-evi entry */
295 json
= json_object_new_object();
297 json_object_string_add(json
, "esi", es_evi
->es
->esi_str
);
298 json_object_int_add(json
, "vni", es_evi
->zevpn
->vni
);
299 if (es_evi
->flags
& ZEBRA_EVPNES_EVI_LOCAL
) {
300 json_types
= json_object_new_array();
301 if (es_evi
->flags
& ZEBRA_EVPNES_EVI_LOCAL
)
302 json_array_string_add(json_types
, "local");
303 json_object_object_add(json
, "type", json_types
);
306 /* Add es-evi entry to json array */
307 json_object_array_add(json_array
, json
);
310 if (es_evi
->flags
& ZEBRA_EVPNES_EVI_LOCAL
)
311 strlcat(type_str
, "L", sizeof(type_str
));
313 vty_out(vty
, "%-8d %-30s %-4s\n",
314 es_evi
->zevpn
->vni
, es_evi
->es
->esi_str
,
320 zebra_evpn_es_evi_show_entry_detail(struct vty
*vty
,
321 struct zebra_evpn_es_evi
*es_evi
,
322 json_object
*json_array
)
328 json_object
*json_flags
;
330 /* Separate JSON object for each es-evi entry */
331 json
= json_object_new_object();
333 json_object_string_add(json
, "esi", es_evi
->es
->esi_str
);
334 json_object_int_add(json
, "vni", es_evi
->zevpn
->vni
);
336 & (ZEBRA_EVPNES_EVI_LOCAL
337 | ZEBRA_EVPNES_EVI_READY_FOR_BGP
)) {
338 json_flags
= json_object_new_array();
339 if (es_evi
->flags
& ZEBRA_EVPNES_EVI_LOCAL
)
340 json_array_string_add(json_flags
, "local");
341 if (es_evi
->flags
& ZEBRA_EVPNES_EVI_READY_FOR_BGP
)
342 json_array_string_add(json_flags
,
344 json_object_object_add(json
, "flags", json_flags
);
347 /* Add es-evi entry to json array */
348 json_object_array_add(json_array
, json
);
351 if (es_evi
->flags
& ZEBRA_EVPNES_EVI_LOCAL
)
352 strlcat(type_str
, "L", sizeof(type_str
));
354 vty_out(vty
, "VNI %d ESI: %s\n",
355 es_evi
->zevpn
->vni
, es_evi
->es
->esi_str
);
356 vty_out(vty
, " Type: %s\n", type_str
);
357 vty_out(vty
, " Ready for BGP: %s\n",
359 ZEBRA_EVPNES_EVI_READY_FOR_BGP
) ?
365 static void zebra_evpn_es_evi_show_one_evpn(struct zebra_evpn
*zevpn
,
367 json_object
*json_array
, int detail
)
369 struct zebra_evpn_es_evi
*es_evi
;
371 RB_FOREACH(es_evi
, zebra_es_evi_rb_head
, &zevpn
->es_evi_rb_tree
) {
373 zebra_evpn_es_evi_show_entry_detail(vty
, es_evi
,
376 zebra_evpn_es_evi_show_entry(vty
, es_evi
, json_array
);
380 struct evpn_mh_show_ctx
{
386 static void zebra_evpn_es_evi_show_one_evpn_hash_cb(struct hash_bucket
*bucket
,
389 struct zebra_evpn
*zevpn
= (struct zebra_evpn
*)bucket
->data
;
390 struct evpn_mh_show_ctx
*wctx
= (struct evpn_mh_show_ctx
*)ctxt
;
392 zebra_evpn_es_evi_show_one_evpn(zevpn
, wctx
->vty
,
393 wctx
->json
, wctx
->detail
);
396 void zebra_evpn_es_evi_show(struct vty
*vty
, bool uj
, int detail
)
398 json_object
*json_array
= NULL
;
399 struct zebra_vrf
*zvrf
;
400 struct evpn_mh_show_ctx wctx
;
402 zvrf
= zebra_vrf_get_evpn();
404 json_array
= json_object_new_array();
406 memset(&wctx
, 0, sizeof(wctx
));
408 wctx
.json
= json_array
;
409 wctx
.detail
= detail
;
411 if (!detail
&& !json_array
) {
412 vty_out(vty
, "Type: L local, R remote\n");
413 vty_out(vty
, "%-8s %-30s %-4s\n", "VNI", "ESI", "Type");
415 /* Display all L2-VNIs */
416 hash_iterate(zvrf
->evpn_table
, zebra_evpn_es_evi_show_one_evpn_hash_cb
,
420 vty_json(vty
, json_array
);
423 void zebra_evpn_es_evi_show_vni(struct vty
*vty
, bool uj
, vni_t vni
, int detail
)
425 json_object
*json_array
= NULL
;
426 struct zebra_evpn
*zevpn
;
428 zevpn
= zebra_evpn_lookup(vni
);
430 json_array
= json_object_new_array();
433 if (!detail
&& !json_array
) {
434 vty_out(vty
, "Type: L local, R remote\n");
435 vty_out(vty
, "%-8s %-30s %-4s\n", "VNI", "ESI", "Type");
437 zebra_evpn_es_evi_show_one_evpn(zevpn
, vty
, json_array
, detail
);
440 vty_out(vty
, "VNI %d doesn't exist\n", vni
);
444 vty_json(vty
, json_array
);
447 /* Initialize the ES tables maintained per-L2_VNI */
448 void zebra_evpn_es_evi_init(struct zebra_evpn
*zevpn
)
450 /* Initialize the ES-EVI RB tree */
451 RB_INIT(zebra_es_evi_rb_head
, &zevpn
->es_evi_rb_tree
);
453 /* Initialize the local and remote ES lists maintained for quick
456 zevpn
->local_es_evi_list
= list_new();
457 listset_app_node_mem(zevpn
->local_es_evi_list
);
460 /* Cleanup the ES info maintained per- EVPN */
461 void zebra_evpn_es_evi_cleanup(struct zebra_evpn
*zevpn
)
463 struct zebra_evpn_es_evi
*es_evi
;
464 struct zebra_evpn_es_evi
*es_evi_next
;
466 RB_FOREACH_SAFE(es_evi
, zebra_es_evi_rb_head
,
467 &zevpn
->es_evi_rb_tree
, es_evi_next
) {
468 zebra_evpn_local_es_evi_do_del(es_evi
);
471 list_delete(&zevpn
->local_es_evi_list
);
472 zebra_evpn_es_clear_base_evpn(zevpn
);
475 /* called when the oper state or bridge membership changes for the
478 void zebra_evpn_update_all_es(struct zebra_evpn
*zevpn
)
480 struct zebra_evpn_es_evi
*es_evi
;
481 struct listnode
*node
;
482 struct interface
*vlan_if
;
483 struct interface
*vxlan_if
;
484 struct zebra_if
*vxlan_zif
;
485 struct zebra_vxlan_vni
*vni
;
487 /* the EVPN is now elgible as a base for EVPN-MH */
488 if (zebra_evpn_send_to_client_ok(zevpn
))
489 zebra_evpn_es_set_base_evpn(zevpn
);
491 zebra_evpn_es_clear_base_evpn(zevpn
);
493 for (ALL_LIST_ELEMENTS_RO(zevpn
->local_es_evi_list
, node
, es_evi
))
494 zebra_evpn_es_evi_re_eval_send_to_client(es_evi
);
496 /* reinstall SVI MAC */
497 vxlan_if
= zevpn
->vxlan_if
;
499 vxlan_zif
= vxlan_if
->info
;
500 if (if_is_operative(vxlan_if
)
501 && vxlan_zif
->brslave_info
.br_if
) {
502 vni
= zebra_vxlan_if_vni_find(vxlan_zif
, zevpn
->vni
);
503 /* VLAN-VNI mappings may not exist */
505 vlan_if
= zvni_map_to_svi(
507 vxlan_zif
->brslave_info
.br_if
);
509 zebra_evpn_acc_bd_svi_mac_add(vlan_if
);
515 /*****************************************************************************/
516 /* Access broadcast domains (BD)
517 * 1. These broadcast domains can be VLAN aware (in which case
518 * the key is VID) or VLAN unaware (in which case the key is
519 * 2. A VID-BD is created when a VLAN is associated with an access port or
520 * when the VLAN is associated with VXLAN_IF
521 * 3. A BD is translated into ES-EVI entries when a VNI is associated
522 * with the broadcast domain
524 /* Hash key for VLAN based broadcast domains */
525 static unsigned int zebra_evpn_acc_vl_hash_keymake(const void *p
)
527 const struct zebra_evpn_access_bd
*acc_bd
= p
;
529 return jhash_2words(acc_bd
->vid
, acc_bd
->bridge_ifindex
, 0);
532 /* Compare two VLAN based broadcast domains */
533 static bool zebra_evpn_acc_vl_cmp(const void *p1
, const void *p2
)
535 const struct zebra_evpn_access_bd
*acc_bd1
= p1
;
536 const struct zebra_evpn_access_bd
*acc_bd2
= p2
;
538 if (acc_bd1
== NULL
&& acc_bd2
== NULL
)
541 if (acc_bd1
== NULL
|| acc_bd2
== NULL
)
544 return ((acc_bd1
->vid
== acc_bd2
->vid
) &&
545 (acc_bd1
->bridge_ifindex
== acc_bd2
->bridge_ifindex
));
548 /* Lookup VLAN based broadcast domain */
549 struct zebra_evpn_access_bd
*zebra_evpn_acc_vl_find(vlanid_t vid
,
550 struct interface
*br_if
)
552 struct zebra_evpn_access_bd
*acc_bd
;
553 struct zebra_evpn_access_bd tmp
;
556 tmp
.bridge_ifindex
= br_if
->ifindex
;
557 acc_bd
= hash_lookup(zmh_info
->evpn_vlan_table
, &tmp
);
562 /* A new broadcast domain can be created when a VLAN member or VLAN<=>VxLAN_IF
565 static struct zebra_evpn_access_bd
*
566 zebra_evpn_acc_vl_new(vlanid_t vid
, struct interface
*br_if
)
568 struct zebra_evpn_access_bd
*acc_bd
;
569 struct interface
*vlan_if
;
571 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
572 zlog_debug("access vlan %d bridge %s add", vid
, br_if
->name
);
574 acc_bd
= XCALLOC(MTYPE_ZACC_BD
, sizeof(struct zebra_evpn_access_bd
));
577 acc_bd
->bridge_ifindex
= br_if
->ifindex
;
578 acc_bd
->bridge_zif
= (struct zebra_if
*)br_if
->info
;
580 /* Initialize the mbr list */
581 acc_bd
->mbr_zifs
= list_new();
584 (void)hash_get(zmh_info
->evpn_vlan_table
, acc_bd
, hash_alloc_intern
);
586 /* check if an svi exists for the vlan */
587 vlan_if
= zvni_map_to_svi(vid
, br_if
);
589 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
590 zlog_debug("vlan %d bridge %s SVI %s set", vid
,
591 br_if
->name
, vlan_if
->name
);
592 acc_bd
->vlan_zif
= vlan_if
->info
;
597 /* Free VLAN based broadcast domain -
598 * This just frees appropriate memory, caller should have taken other
601 static void zebra_evpn_acc_vl_free(struct zebra_evpn_access_bd
*acc_bd
)
603 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
604 zlog_debug("access vlan %d del", acc_bd
->vid
);
606 if (acc_bd
->vlan_zif
&& acc_bd
->zevpn
&& acc_bd
->zevpn
->mac_table
)
607 zebra_evpn_mac_svi_del(acc_bd
->vlan_zif
->ifp
, acc_bd
->zevpn
);
609 /* cleanup resources maintained against the ES */
610 list_delete(&acc_bd
->mbr_zifs
);
612 /* remove EVI from various tables */
613 hash_release(zmh_info
->evpn_vlan_table
, acc_bd
);
615 XFREE(MTYPE_ZACC_BD
, acc_bd
);
618 static void zebra_evpn_acc_vl_cleanup_all(struct hash_bucket
*bucket
, void *arg
)
620 struct zebra_evpn_access_bd
*acc_bd
= bucket
->data
;
622 zebra_evpn_acc_vl_free(acc_bd
);
625 /* called when a bd mbr is removed or VxLAN_IF is diassociated from the access
628 static void zebra_evpn_acc_bd_free_on_deref(struct zebra_evpn_access_bd
*acc_bd
)
630 if (!list_isempty(acc_bd
->mbr_zifs
) || acc_bd
->vxlan_zif
)
633 /* Remove this access_bd from bridge hash table */
634 zebra_l2_bridge_if_vlan_access_bd_deref(acc_bd
);
636 /* if there are no references free the EVI */
637 zebra_evpn_acc_vl_free(acc_bd
);
640 static struct zebra_evpn_access_bd
*
641 zebra_evpn_acc_bd_alloc_on_ref(vlanid_t vid
, struct interface
*br_if
)
643 struct zebra_evpn_access_bd
*acc_bd
= NULL
;
645 assert(br_if
&& br_if
->info
);
646 acc_bd
= zebra_evpn_acc_vl_new(vid
, br_if
);
648 /* Add this access_bd to bridge hash table */
649 zebra_l2_bridge_if_vlan_access_bd_ref(acc_bd
);
654 /* called when a SVI is goes up/down */
655 void zebra_evpn_acc_bd_svi_set(struct zebra_if
*vlan_zif
,
656 struct zebra_if
*br_zif
, bool is_up
)
658 struct zebra_evpn_access_bd
*acc_bd
;
660 struct zebra_if
*tmp_br_zif
= br_zif
;
663 if (!vlan_zif
->link
|| !vlan_zif
->link
->info
)
666 tmp_br_zif
= vlan_zif
->link
->info
;
669 /* ignore vlan unaware bridges */
670 if (!IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(tmp_br_zif
))
673 vid
= vlan_zif
->l2info
.vl
.vid
;
674 acc_bd
= zebra_evpn_acc_vl_find(vid
, tmp_br_zif
->ifp
);
679 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
680 zlog_debug("vlan %d bridge %s SVI %s set", vid
,
681 tmp_br_zif
->ifp
->name
, vlan_zif
->ifp
->name
);
683 acc_bd
->vlan_zif
= vlan_zif
;
685 zebra_evpn_mac_svi_add(acc_bd
->vlan_zif
->ifp
,
687 } else if (acc_bd
->vlan_zif
) {
688 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
689 zlog_debug("vlan %d bridge %s SVI clear", vid
,
690 tmp_br_zif
->ifp
->name
);
691 acc_bd
->vlan_zif
= NULL
;
692 if (acc_bd
->zevpn
&& acc_bd
->zevpn
->mac_table
)
693 zebra_evpn_mac_svi_del(vlan_zif
->ifp
, acc_bd
->zevpn
);
697 /* On some events macs are force-flushed. This api can be used to reinstate
698 * the svi-mac after such cleanup-events.
700 void zebra_evpn_acc_bd_svi_mac_add(struct interface
*vlan_if
)
702 zebra_evpn_acc_bd_svi_set(vlan_if
->info
, NULL
,
703 if_is_operative(vlan_if
));
706 /* called when a EVPN-L2VNI is set or cleared against a BD */
707 static void zebra_evpn_acc_bd_evpn_set(struct zebra_evpn_access_bd
*acc_bd
,
708 struct zebra_evpn
*zevpn
,
709 struct zebra_evpn
*old_zevpn
)
711 struct zebra_if
*zif
;
712 struct listnode
*node
;
714 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
715 zlog_debug("access vlan %d bridge %s l2-vni %u set",
716 acc_bd
->vid
, acc_bd
->bridge_zif
->ifp
->name
,
717 zevpn
? zevpn
->vni
: 0);
719 for (ALL_LIST_ELEMENTS_RO(acc_bd
->mbr_zifs
, node
, zif
)) {
720 if (!zif
->es_info
.es
)
724 zebra_evpn_local_es_evi_add(zif
->es_info
.es
, zevpn
);
726 zebra_evpn_local_es_evi_del(zif
->es_info
.es
, old_zevpn
);
729 if (acc_bd
->vlan_zif
) {
731 zebra_evpn_mac_svi_add(acc_bd
->vlan_zif
->ifp
,
733 else if (old_zevpn
&& old_zevpn
->mac_table
)
734 zebra_evpn_mac_svi_del(acc_bd
->vlan_zif
->ifp
,
739 /* handle VLAN->VxLAN_IF association */
740 void zebra_evpn_vl_vxl_ref(uint16_t vid
, vni_t vni_id
,
741 struct zebra_if
*vxlan_zif
)
744 struct zebra_evpn_access_bd
*acc_bd
;
745 struct zebra_evpn
*old_zevpn
;
746 struct interface
*br_if
;
754 br_if
= vxlan_zif
->brslave_info
.br_if
;
759 acc_bd
= zebra_evpn_acc_vl_find(vid
, br_if
);
761 acc_bd
= zebra_evpn_acc_bd_alloc_on_ref(vid
, br_if
);
763 old_vni
= acc_bd
->vni
;
765 if (vni_id
== old_vni
)
768 acc_bd
->vni
= vni_id
;
769 acc_bd
->vxlan_zif
= vxlan_zif
;
771 old_zevpn
= acc_bd
->zevpn
;
772 acc_bd
->zevpn
= zebra_evpn_lookup(vni_id
);
773 if (acc_bd
->zevpn
== old_zevpn
)
776 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
777 zlog_debug("access vlan %d vni %u ref", acc_bd
->vid
, vni_id
);
780 zebra_evpn_acc_bd_evpn_set(acc_bd
, NULL
, old_zevpn
);
783 zebra_evpn_acc_bd_evpn_set(acc_bd
, acc_bd
->zevpn
, NULL
);
786 /* handle VLAN->VxLAN_IF deref */
787 void zebra_evpn_vl_vxl_deref(uint16_t vid
, vni_t vni_id
,
788 struct zebra_if
*vxlan_zif
)
790 struct interface
*br_if
;
791 struct zebra_evpn_access_bd
*acc_bd
;
799 br_if
= vxlan_zif
->brslave_info
.br_if
;
803 acc_bd
= zebra_evpn_acc_vl_find(vid
, br_if
);
807 /* clear vxlan_if only if it matches */
808 if (acc_bd
->vni
!= vni_id
)
811 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
812 zlog_debug("access vlan %d bridge %s vni %u deref", acc_bd
->vid
,
813 br_if
->name
, vni_id
);
816 zebra_evpn_acc_bd_evpn_set(acc_bd
, NULL
, acc_bd
->zevpn
);
818 acc_bd
->zevpn
= NULL
;
819 acc_bd
->vxlan_zif
= NULL
;
822 /* if there are no other references the access_bd can be freed */
823 zebra_evpn_acc_bd_free_on_deref(acc_bd
);
826 /* handle BridgeIf<->AccessBD cleanup */
827 void zebra_evpn_access_bd_bridge_cleanup(vlanid_t vid
, struct interface
*br_if
,
828 struct zebra_evpn_access_bd
*acc_bd
)
830 struct zebra_evpn
*zevpn
;
832 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
833 zlog_debug("access bd vlan %d bridge %s cleanup", acc_bd
->vid
,
836 zevpn
= acc_bd
->zevpn
;
838 zebra_evpn_acc_bd_evpn_set(acc_bd
, NULL
, zevpn
);
840 /* cleanup resources maintained against the ES */
841 list_delete_all_node(acc_bd
->mbr_zifs
);
843 acc_bd
->zevpn
= NULL
;
844 acc_bd
->vxlan_zif
= NULL
;
846 acc_bd
->bridge_zif
= NULL
;
848 /* if there are no other references the access_bd can be freed */
849 zebra_evpn_acc_bd_free_on_deref(acc_bd
);
852 /* handle EVPN add/del */
853 void zebra_evpn_vxl_evpn_set(struct zebra_if
*zif
, struct zebra_evpn
*zevpn
,
856 struct interface
*br_if
;
857 struct zebra_vxlan_vni
*vni
;
858 struct zebra_evpn_access_bd
*acc_bd
;
863 /* locate access_bd associated with the vxlan device */
864 vni
= zebra_vxlan_if_vni_find(zif
, zevpn
->vni
);
868 br_if
= zif
->brslave_info
.br_if
;
872 acc_bd
= zebra_evpn_acc_vl_find(vni
->access_vlan
, br_if
);
877 zebra_evpn_es_set_base_evpn(zevpn
);
878 if (acc_bd
->zevpn
!= zevpn
) {
879 acc_bd
->zevpn
= zevpn
;
880 zebra_evpn_acc_bd_evpn_set(acc_bd
, zevpn
, NULL
);
884 struct zebra_evpn
*old_zevpn
= acc_bd
->zevpn
;
885 acc_bd
->zevpn
= NULL
;
886 zebra_evpn_acc_bd_evpn_set(acc_bd
, NULL
, old_zevpn
);
891 /* handle addition of new VLAN members */
892 void zebra_evpn_vl_mbr_ref(uint16_t vid
, struct zebra_if
*zif
)
894 struct interface
*br_if
;
895 struct zebra_evpn_access_bd
*acc_bd
;
900 br_if
= zif
->brslave_info
.br_if
;
904 acc_bd
= zebra_evpn_acc_vl_find(vid
, br_if
);
906 acc_bd
= zebra_evpn_acc_bd_alloc_on_ref(vid
, br_if
);
908 if (listnode_lookup(acc_bd
->mbr_zifs
, zif
))
911 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
912 zlog_debug("access vlan %d bridge %s mbr %s ref", vid
,
913 br_if
->name
, zif
->ifp
->name
);
915 listnode_add(acc_bd
->mbr_zifs
, zif
);
916 if (acc_bd
->zevpn
&& zif
->es_info
.es
)
917 zebra_evpn_local_es_evi_add(zif
->es_info
.es
, acc_bd
->zevpn
);
920 /* handle deletion of VLAN members */
921 void zebra_evpn_vl_mbr_deref(uint16_t vid
, struct zebra_if
*zif
)
923 struct interface
*br_if
;
924 struct zebra_evpn_access_bd
*acc_bd
;
925 struct listnode
*node
;
930 br_if
= zif
->brslave_info
.br_if
;
934 acc_bd
= zebra_evpn_acc_vl_find(vid
, br_if
);
938 node
= listnode_lookup(acc_bd
->mbr_zifs
, zif
);
942 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
943 zlog_debug("access vlan %d bridge %s mbr %s deref", vid
,
944 br_if
->name
, zif
->ifp
->name
);
946 list_delete_node(acc_bd
->mbr_zifs
, node
);
948 if (acc_bd
->zevpn
&& zif
->es_info
.es
)
949 zebra_evpn_local_es_evi_del(zif
->es_info
.es
, acc_bd
->zevpn
);
951 /* if there are no other references the access_bd can be freed */
952 zebra_evpn_acc_bd_free_on_deref(acc_bd
);
955 static void zebra_evpn_acc_vl_adv_svi_mac_cb(struct hash_bucket
*bucket
,
958 struct zebra_evpn_access_bd
*acc_bd
= bucket
->data
;
960 if (acc_bd
->vlan_zif
&& acc_bd
->zevpn
)
961 zebra_evpn_mac_svi_add(acc_bd
->vlan_zif
->ifp
, acc_bd
->zevpn
);
964 /* called when advertise SVI MAC is enabled on the switch */
965 static void zebra_evpn_acc_vl_adv_svi_mac_all(void)
967 hash_iterate(zmh_info
->evpn_vlan_table
,
968 zebra_evpn_acc_vl_adv_svi_mac_cb
, NULL
);
971 static void zebra_evpn_acc_vl_json_fill(struct zebra_evpn_access_bd
*acc_bd
,
972 json_object
*json
, bool detail
)
974 json_object_int_add(json
, "vlan", acc_bd
->vid
);
975 if (acc_bd
->vxlan_zif
)
976 json_object_string_add(json
, "vxlanIf",
977 acc_bd
->vxlan_zif
->ifp
->name
);
979 json_object_int_add(json
, "vni", acc_bd
->zevpn
->vni
);
980 if (acc_bd
->mbr_zifs
)
981 json_object_int_add(json
, "memberIfCount",
982 listcount(acc_bd
->mbr_zifs
));
985 json_object
*json_mbrs
;
986 json_object
*json_mbr
;
987 struct zebra_if
*zif
;
988 struct listnode
*node
;
991 json_mbrs
= json_object_new_array();
992 for (ALL_LIST_ELEMENTS_RO(acc_bd
->mbr_zifs
, node
, zif
)) {
993 json_mbr
= json_object_new_object();
994 json_object_string_add(json_mbr
, "ifName",
996 json_object_array_add(json_mbrs
, json_mbr
);
998 json_object_object_add(json
, "members", json_mbrs
);
1002 static void zebra_evpn_acc_vl_show_entry_detail(struct vty
*vty
,
1003 struct zebra_evpn_access_bd
*acc_bd
, json_object
*json
)
1005 struct zebra_if
*zif
;
1006 struct listnode
*node
;
1009 zebra_evpn_acc_vl_json_fill(acc_bd
, json
, true);
1011 vty_out(vty
, "VLAN: %s.%u\n", acc_bd
->bridge_zif
->ifp
->name
,
1013 vty_out(vty
, " VxLAN Interface: %s\n",
1015 acc_bd
->vxlan_zif
->ifp
->name
: "-");
1016 vty_out(vty
, " SVI: %s\n",
1017 acc_bd
->vlan_zif
? acc_bd
->vlan_zif
->ifp
->name
: "-");
1019 vty_out(vty
, " L2-VNI: %d\n", acc_bd
->zevpn
->vni
);
1021 vty_out(vty
, " L2-VNI: 0\n");
1022 vty_out(vty
, " L3-VNI: %d\n", acc_bd
->vni
);
1024 vty_out(vty
, " Member Count: %d\n",
1025 listcount(acc_bd
->mbr_zifs
));
1026 vty_out(vty
, " Members: \n");
1027 for (ALL_LIST_ELEMENTS_RO(acc_bd
->mbr_zifs
, node
, zif
))
1028 vty_out(vty
, " %s\n", zif
->ifp
->name
);
1033 static void zebra_evpn_acc_vl_show_entry(struct vty
*vty
,
1034 struct zebra_evpn_access_bd
*acc_bd
, json_object
*json
)
1037 zebra_evpn_acc_vl_json_fill(acc_bd
, json
, false);
1039 vty_out(vty
, "%-5s.%-5u %-15s %-8d %-15s %u\n",
1040 acc_bd
->bridge_zif
->ifp
->name
, acc_bd
->vid
,
1041 acc_bd
->vlan_zif
? acc_bd
->vlan_zif
->ifp
->name
: "-",
1042 acc_bd
->zevpn
? acc_bd
->zevpn
->vni
: 0,
1043 acc_bd
->vxlan_zif
? acc_bd
->vxlan_zif
->ifp
->name
: "-",
1044 listcount(acc_bd
->mbr_zifs
));
1048 static void zebra_evpn_acc_vl_show_hash(struct hash_bucket
*bucket
, void *ctxt
)
1050 struct evpn_mh_show_ctx
*wctx
= ctxt
;
1051 struct zebra_evpn_access_bd
*acc_bd
= bucket
->data
;
1052 json_object
*json
= NULL
;
1055 json
= json_object_new_object();
1057 zebra_evpn_acc_vl_show_entry_detail(wctx
->vty
, acc_bd
, json
);
1059 zebra_evpn_acc_vl_show_entry(wctx
->vty
, acc_bd
, json
);
1061 json_object_array_add(wctx
->json
, json
);
1064 void zebra_evpn_acc_vl_show(struct vty
*vty
, bool uj
)
1066 struct evpn_mh_show_ctx wctx
;
1067 json_object
*json_array
= NULL
;
1070 json_array
= json_object_new_array();
1072 memset(&wctx
, 0, sizeof(wctx
));
1074 wctx
.json
= json_array
;
1075 wctx
.detail
= false;
1078 vty_out(vty
, "%-12s %-15s %-8s %-15s %s\n", "VLAN", "SVI",
1079 "L2-VNI", "VXLAN-IF", "# Members");
1081 hash_iterate(zmh_info
->evpn_vlan_table
, zebra_evpn_acc_vl_show_hash
,
1085 vty_json(vty
, json_array
);
1088 void zebra_evpn_acc_vl_show_detail(struct vty
*vty
, bool uj
)
1090 struct evpn_mh_show_ctx wctx
;
1091 json_object
*json_array
= NULL
;
1094 json_array
= json_object_new_array();
1095 memset(&wctx
, 0, sizeof(wctx
));
1097 wctx
.json
= json_array
;
1100 hash_iterate(zmh_info
->evpn_vlan_table
, zebra_evpn_acc_vl_show_hash
,
1104 vty_json(vty
, json_array
);
1107 void zebra_evpn_acc_vl_show_vid(struct vty
*vty
, bool uj
, vlanid_t vid
,
1108 struct interface
*br_if
)
1110 json_object
*json
= NULL
;
1111 struct zebra_evpn_access_bd
*acc_bd
;
1114 json
= json_object_new_object();
1116 acc_bd
= zebra_evpn_acc_vl_find(vid
, br_if
);
1118 zebra_evpn_acc_vl_show_entry_detail(vty
, acc_bd
, json
);
1121 vty_out(vty
, "VLAN %s.%u not present\n", br_if
->name
,
1126 vty_json(vty
, json
);
1129 /* Initialize VLAN member bitmap on an interface. Although VLAN membership
1130 * is independent of EVPN we only process it if its of interest to EVPN-MH
1131 * i.e. on access ports that can be setup as Ethernet Segments. And that is
1132 * intended as an optimization.
1134 void zebra_evpn_if_init(struct zebra_if
*zif
)
1136 if (!zebra_evpn_is_if_es_capable(zif
))
1139 if (!bf_is_inited(zif
->vlan_bitmap
))
1140 bf_init(zif
->vlan_bitmap
, IF_VLAN_BITMAP_MAX
);
1142 /* if an es_id and sysmac are already present against the interface
1145 zebra_evpn_local_es_update(zif
, &zif
->es_info
.esi
);
1148 /* handle deletion of an access port by removing it from all associated
1149 * broadcast domains.
1151 void zebra_evpn_if_cleanup(struct zebra_if
*zif
)
1154 struct zebra_evpn_es
*es
;
1156 if (bf_is_inited(zif
->vlan_bitmap
)) {
1157 bf_for_each_set_bit(zif
->vlan_bitmap
, vid
, IF_VLAN_BITMAP_MAX
)
1159 zebra_evpn_vl_mbr_deref(vid
, zif
);
1162 bf_free(zif
->vlan_bitmap
);
1165 /* Delete associated Ethernet Segment */
1166 es
= zif
->es_info
.es
;
1168 zebra_evpn_local_es_del(&es
);
1171 /*****************************************************************************
1172 * L2 NH/NHG Management
1173 * A L2 NH entry is programmed in the kernel for every ES-VTEP entry. This
1174 * NH is then added to the L2-ECMP-NHG associated with the ES.
1176 static uint32_t zebra_evpn_nhid_alloc(struct zebra_evpn_es
*es
)
1181 bf_assign_index(zmh_info
->nh_id_bitmap
, id
);
1187 nh_id
= id
| EVPN_NHG_ID_TYPE_BIT
;
1188 /* Add to NHG hash */
1190 (void)hash_get(zmh_info
->nhg_table
, es
, hash_alloc_intern
);
1192 nh_id
= id
| EVPN_NH_ID_TYPE_BIT
;
1198 static void zebra_evpn_nhid_free(uint32_t nh_id
, struct zebra_evpn_es
*es
)
1200 uint32_t id
= (nh_id
& EVPN_NH_ID_VAL_MASK
);
1206 hash_release(zmh_info
->nhg_table
, es
);
1210 bf_release_index(zmh_info
->nh_id_bitmap
, id
);
1213 static unsigned int zebra_evpn_nh_ip_hash_keymake(const void *p
)
1215 const struct zebra_evpn_l2_nh
*nh
= p
;
1217 return jhash_1word(nh
->vtep_ip
.s_addr
, 0);
1220 static bool zebra_evpn_nh_ip_cmp(const void *p1
, const void *p2
)
1222 const struct zebra_evpn_l2_nh
*nh1
= p1
;
1223 const struct zebra_evpn_l2_nh
*nh2
= p2
;
1225 if (nh1
== NULL
&& nh2
== NULL
)
1228 if (nh1
== NULL
|| nh2
== NULL
)
1231 return (nh1
->vtep_ip
.s_addr
== nh2
->vtep_ip
.s_addr
);
1234 static unsigned int zebra_evpn_nhg_hash_keymake(const void *p
)
1236 const struct zebra_evpn_es
*es
= p
;
1238 return jhash_1word(es
->nhg_id
, 0);
1241 static bool zebra_evpn_nhg_cmp(const void *p1
, const void *p2
)
1243 const struct zebra_evpn_es
*es1
= p1
;
1244 const struct zebra_evpn_es
*es2
= p2
;
1246 if (es1
== NULL
&& es2
== NULL
)
1249 if (es1
== NULL
|| es2
== NULL
)
1252 return (es1
->nhg_id
== es2
->nhg_id
);
1255 /* Lookup ES using the NHG id associated with it */
1256 static struct zebra_evpn_es
*zebra_evpn_nhg_find(uint32_t nhg_id
)
1258 struct zebra_evpn_es
*es
;
1259 struct zebra_evpn_es tmp
;
1261 tmp
.nhg_id
= nhg_id
;
1262 es
= hash_lookup(zmh_info
->nhg_table
, &tmp
);
1267 /* Returns TRUE if the NHG is associated with a local ES */
1268 bool zebra_evpn_nhg_is_local_es(uint32_t nhg_id
,
1269 struct zebra_evpn_es
**local_es
)
1271 struct zebra_evpn_es
*es
;
1273 es
= zebra_evpn_nhg_find(nhg_id
);
1274 if (es
&& (es
->flags
& ZEBRA_EVPNES_LOCAL
)) {
1283 /* update remote macs associated with the ES */
1284 static void zebra_evpn_nhg_mac_update(struct zebra_evpn_es
*es
)
1286 struct zebra_mac
*mac
;
1287 struct listnode
*node
;
1290 local_via_nw
= zebra_evpn_es_local_mac_via_network_port(es
);
1291 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
|| IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
1292 zlog_debug("mac update on es %s nhg %s", es
->esi_str
,
1293 (es
->flags
& ZEBRA_EVPNES_NHG_ACTIVE
)
1297 for (ALL_LIST_ELEMENTS_RO(es
->mac_list
, node
, mac
)) {
1298 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE
)
1299 || (local_via_nw
&& CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
)
1300 && zebra_evpn_mac_is_static(mac
))) {
1301 if (es
->flags
& ZEBRA_EVPNES_NHG_ACTIVE
) {
1302 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
1304 "%smac %pEA install via es %s nhg 0x%x",
1305 (mac
->flags
& ZEBRA_MAC_REMOTE
)
1308 &mac
->macaddr
, es
->esi_str
,
1310 zebra_evpn_rem_mac_install(
1311 mac
->zevpn
, mac
, false /*was_static*/);
1313 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
1315 "%smac %pEA un-install es %s",
1316 (mac
->flags
& ZEBRA_MAC_REMOTE
)
1319 &mac
->macaddr
, es
->esi_str
);
1320 zebra_evpn_rem_mac_uninstall(mac
->zevpn
, mac
,
1327 /* The MAC ECMP group is activated on the first VTEP */
1328 static void zebra_evpn_nhg_update(struct zebra_evpn_es
*es
)
1330 uint32_t nh_cnt
= 0;
1331 struct nh_grp nh_ids
[ES_VTEP_MAX_CNT
];
1332 struct zebra_evpn_es_vtep
*es_vtep
;
1333 struct listnode
*node
;
1338 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
1342 if (nh_cnt
>= ES_VTEP_MAX_CNT
)
1345 memset(&nh_ids
[nh_cnt
], 0, sizeof(struct nh_grp
));
1346 nh_ids
[nh_cnt
].id
= es_vtep
->nh
->nh_id
;
1351 if (IS_ZEBRA_DEBUG_EVPN_MH_NH
) {
1352 char nh_str
[ES_VTEP_LIST_STR_SZ
];
1357 for (i
= 0; i
< nh_cnt
; ++i
) {
1358 snprintf(nh_buf
, sizeof(nh_buf
), "%u ",
1360 strlcat(nh_str
, nh_buf
, sizeof(nh_str
));
1362 zlog_debug("es %s nhg %u add %s", es
->esi_str
,
1363 es
->nhg_id
, nh_str
);
1366 kernel_upd_mac_nhg(es
->nhg_id
, nh_cnt
, nh_ids
);
1367 if (!(es
->flags
& ZEBRA_EVPNES_NHG_ACTIVE
)) {
1368 es
->flags
|= ZEBRA_EVPNES_NHG_ACTIVE
;
1369 /* add backup NHG to the br-port */
1370 if ((es
->flags
& ZEBRA_EVPNES_LOCAL
))
1371 zebra_evpn_es_br_port_dplane_update(es
,
1373 zebra_evpn_nhg_mac_update(es
);
1376 if (es
->flags
& ZEBRA_EVPNES_NHG_ACTIVE
) {
1377 if (IS_ZEBRA_DEBUG_EVPN_MH_NH
)
1378 zlog_debug("es %s nhg %u del", es
->esi_str
,
1380 es
->flags
&= ~ZEBRA_EVPNES_NHG_ACTIVE
;
1381 /* remove backup NHG from the br-port */
1382 if ((es
->flags
& ZEBRA_EVPNES_LOCAL
))
1383 zebra_evpn_es_br_port_dplane_update(es
,
1385 zebra_evpn_nhg_mac_update(es
);
1386 kernel_del_mac_nhg(es
->nhg_id
);
1392 static void zebra_evpn_es_l2_nh_show_entry(struct zebra_evpn_l2_nh
*nh
,
1394 json_object
*json_array
)
1397 json_object
*json
= NULL
;
1399 json
= json_object_new_object();
1400 json_object_string_addf(json
, "vtep", "%pI4", &nh
->vtep_ip
);
1401 json_object_int_add(json
, "nhId", nh
->nh_id
);
1402 json_object_int_add(json
, "refCnt", nh
->ref_cnt
);
1404 json_object_array_add(json_array
, json
);
1406 vty_out(vty
, "%-16pI4 %-10u %u\n", &nh
->vtep_ip
, nh
->nh_id
,
1411 static void zebra_evpn_l2_nh_show_cb(struct hash_bucket
*bucket
, void *ctxt
)
1413 struct zebra_evpn_l2_nh
*nh
= (struct zebra_evpn_l2_nh
*)bucket
->data
;
1414 struct evpn_mh_show_ctx
*wctx
= (struct evpn_mh_show_ctx
*)ctxt
;
1416 zebra_evpn_es_l2_nh_show_entry(nh
, wctx
->vty
, wctx
->json
);
1419 void zebra_evpn_l2_nh_show(struct vty
*vty
, bool uj
)
1421 struct evpn_mh_show_ctx wctx
;
1422 json_object
*json_array
= NULL
;
1425 json_array
= json_object_new_array();
1427 vty_out(vty
, "%-16s %-10s %s\n", "VTEP", "NH id", "#ES");
1430 memset(&wctx
, 0, sizeof(wctx
));
1432 wctx
.json
= json_array
;
1434 hash_iterate(zmh_info
->nh_ip_table
, zebra_evpn_l2_nh_show_cb
, &wctx
);
1437 vty_json(vty
, json_array
);
1440 static struct zebra_evpn_l2_nh
*zebra_evpn_l2_nh_find(struct in_addr vtep_ip
)
1442 struct zebra_evpn_l2_nh
*nh
;
1443 struct zebra_evpn_l2_nh tmp
;
1445 tmp
.vtep_ip
.s_addr
= vtep_ip
.s_addr
;
1446 nh
= hash_lookup(zmh_info
->nh_ip_table
, &tmp
);
1451 static struct zebra_evpn_l2_nh
*zebra_evpn_l2_nh_alloc(struct in_addr vtep_ip
)
1453 struct zebra_evpn_l2_nh
*nh
;
1455 nh
= XCALLOC(MTYPE_L2_NH
, sizeof(*nh
));
1456 nh
->vtep_ip
= vtep_ip
;
1457 (void)hash_get(zmh_info
->nh_ip_table
, nh
, hash_alloc_intern
);
1459 nh
->nh_id
= zebra_evpn_nhid_alloc(NULL
);
1461 hash_release(zmh_info
->nh_ip_table
, nh
);
1462 XFREE(MTYPE_L2_NH
, nh
);
1466 /* install the NH in the dataplane */
1467 kernel_upd_mac_nh(nh
->nh_id
, nh
->vtep_ip
);
1472 static void zebra_evpn_l2_nh_free(struct zebra_evpn_l2_nh
*nh
)
1474 /* delete the NH from the dataplane */
1475 kernel_del_mac_nh(nh
->nh_id
);
1477 zebra_evpn_nhid_free(nh
->nh_id
, NULL
);
1478 hash_release(zmh_info
->nh_ip_table
, nh
);
1479 XFREE(MTYPE_L2_NH
, nh
);
1482 static void zebra_evpn_l2_nh_es_vtep_ref(struct zebra_evpn_es_vtep
*es_vtep
)
1487 es_vtep
->nh
= zebra_evpn_l2_nh_find(es_vtep
->vtep_ip
);
1489 es_vtep
->nh
= zebra_evpn_l2_nh_alloc(es_vtep
->vtep_ip
);
1492 zlog_warn("es %s vtep %pI4 nh ref failed", es_vtep
->es
->esi_str
,
1497 ++es_vtep
->nh
->ref_cnt
;
1499 if (IS_ZEBRA_DEBUG_EVPN_MH_NH
)
1500 zlog_debug("es %s vtep %pI4 nh %u ref %u", es_vtep
->es
->esi_str
,
1501 &es_vtep
->vtep_ip
, es_vtep
->nh
->nh_id
,
1502 es_vtep
->nh
->ref_cnt
);
1504 /* add the NH to the parent NHG */
1505 zebra_evpn_nhg_update(es_vtep
->es
);
1508 static void zebra_evpn_l2_nh_es_vtep_deref(struct zebra_evpn_es_vtep
*es_vtep
)
1510 struct zebra_evpn_l2_nh
*nh
= es_vtep
->nh
;
1519 if (IS_ZEBRA_DEBUG_EVPN_MH_NH
)
1520 zlog_debug("es %s vtep %pI4 nh %u deref %u",
1521 es_vtep
->es
->esi_str
, &es_vtep
->vtep_ip
, nh
->nh_id
,
1524 /* remove the NH from the parent NHG */
1525 zebra_evpn_nhg_update(es_vtep
->es
);
1527 /* uninstall the NH */
1529 zebra_evpn_l2_nh_free(nh
);
1532 /*****************************************************************************/
1533 /* Ethernet Segment Management
1534 * 1. Ethernet Segment is a collection of links attached to the same
1535 * server (MHD) or switch (MHN)
1536 * 2. An Ethernet Segment can span multiple PEs and is identified by the
1538 * 3. Zebra manages the local ESI configuration.
1539 * 4. It also maintains the aliasing that maps an ESI (local or remote)
1540 * to one or more PEs/VTEPs.
1541 * 5. remote ESs are added by BGP (on rxing EAD Type-1 routes)
1543 /* A list of remote VTEPs is maintained for each ES. This list includes -
1544 * 1. VTEPs for which we have imported the ESR i.e. ES-peers
1545 * 2. VTEPs that have an "active" ES-EVI VTEP i.e. EAD-per-ES and EAD-per-EVI
1546 * have been imported into one or more EVPNs
1548 static int zebra_evpn_es_vtep_cmp(void *p1
, void *p2
)
1550 const struct zebra_evpn_es_vtep
*es_vtep1
= p1
;
1551 const struct zebra_evpn_es_vtep
*es_vtep2
= p2
;
1553 return es_vtep1
->vtep_ip
.s_addr
- es_vtep2
->vtep_ip
.s_addr
;
1556 static struct zebra_evpn_es_vtep
*zebra_evpn_es_vtep_new(
1557 struct zebra_evpn_es
*es
, struct in_addr vtep_ip
)
1559 struct zebra_evpn_es_vtep
*es_vtep
;
1561 es_vtep
= XCALLOC(MTYPE_ZES_VTEP
, sizeof(*es_vtep
));
1564 es_vtep
->vtep_ip
.s_addr
= vtep_ip
.s_addr
;
1565 listnode_init(&es_vtep
->es_listnode
, es_vtep
);
1566 listnode_add_sort(es
->es_vtep_list
, &es_vtep
->es_listnode
);
1571 static void zebra_evpn_es_vtep_free(struct zebra_evpn_es_vtep
*es_vtep
)
1573 struct zebra_evpn_es
*es
= es_vtep
->es
;
1575 list_delete_node(es
->es_vtep_list
, &es_vtep
->es_listnode
);
1576 /* update the L2-NHG associated with the ES */
1577 zebra_evpn_l2_nh_es_vtep_deref(es_vtep
);
1578 XFREE(MTYPE_ZES_VTEP
, es_vtep
);
1582 /* check if VTEP is already part of the list */
1583 static struct zebra_evpn_es_vtep
*zebra_evpn_es_vtep_find(
1584 struct zebra_evpn_es
*es
, struct in_addr vtep_ip
)
1586 struct listnode
*node
= NULL
;
1587 struct zebra_evpn_es_vtep
*es_vtep
;
1589 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
1590 if (es_vtep
->vtep_ip
.s_addr
== vtep_ip
.s_addr
)
1596 /* flush all the dataplane br-port info associated with the ES */
1597 static bool zebra_evpn_es_br_port_dplane_clear(struct zebra_evpn_es
*es
)
1599 struct in_addr sph_filters
[ES_VTEP_MAX_CNT
];
1601 if (!(es
->flags
& ZEBRA_EVPNES_BR_PORT
))
1604 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
1605 zlog_debug("es %s br-port dplane clear", es
->esi_str
);
1607 memset(&sph_filters
, 0, sizeof(sph_filters
));
1608 dplane_br_port_update(es
->zif
->ifp
, false /* non_df */, 0, sph_filters
,
1609 0 /* backup_nhg_id */);
1614 zebra_evpn_es_br_port_dplane_update_needed(struct zebra_evpn_es
*es
)
1616 return (es
->flags
& ZEBRA_EVPNES_NON_DF
)
1617 || (es
->flags
& ZEBRA_EVPNES_NHG_ACTIVE
)
1618 || listcount(es
->es_vtep_list
);
1621 /* returns TRUE if dplane entry was updated */
1622 static bool zebra_evpn_es_br_port_dplane_update(struct zebra_evpn_es
*es
,
1625 uint32_t backup_nhg_id
;
1626 struct in_addr sph_filters
[ES_VTEP_MAX_CNT
];
1627 struct listnode
*node
= NULL
;
1628 struct zebra_evpn_es_vtep
*es_vtep
;
1629 uint32_t sph_filter_cnt
= 0;
1631 if (!(es
->flags
& ZEBRA_EVPNES_LOCAL
))
1632 return zebra_evpn_es_br_port_dplane_clear(es
);
1634 /* If the ES is not a bridge port there is nothing
1637 if (!(es
->flags
& ZEBRA_EVPNES_BR_PORT
))
1640 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
1641 zlog_debug("es %s br-port dplane update by %s", es
->esi_str
,
1643 backup_nhg_id
= (es
->flags
& ZEBRA_EVPNES_NHG_ACTIVE
) ? es
->nhg_id
: 0;
1645 memset(&sph_filters
, 0, sizeof(sph_filters
));
1646 if (es
->flags
& ZEBRA_EVPNES_BYPASS
) {
1647 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
1649 "es %s SPH filter disabled as it is in bypass",
1652 if (listcount(es
->es_vtep_list
) > ES_VTEP_MAX_CNT
) {
1653 zlog_warn("es %s vtep count %d exceeds filter cnt %d",
1654 es
->esi_str
, listcount(es
->es_vtep_list
),
1657 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
,
1660 & ZEBRA_EVPNES_VTEP_DEL_IN_PROG
)
1662 sph_filters
[sph_filter_cnt
] = es_vtep
->vtep_ip
;
1668 dplane_br_port_update(es
->zif
->ifp
, !!(es
->flags
& ZEBRA_EVPNES_NON_DF
),
1669 sph_filter_cnt
, sph_filters
, backup_nhg_id
);
1674 /* returns TRUE if dplane entry was updated */
1675 static bool zebra_evpn_es_df_change(struct zebra_evpn_es
*es
, bool new_non_df
,
1676 const char *caller
, const char *reason
)
1680 old_non_df
= !!(es
->flags
& ZEBRA_EVPNES_NON_DF
);
1682 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
1683 zlog_debug("df-change es %s %s to %s; %s: %s", es
->esi_str
,
1684 old_non_df
? "non-df" : "df",
1685 new_non_df
? "non-df" : "df", caller
, reason
);
1687 if (old_non_df
== new_non_df
)
1691 es
->flags
|= ZEBRA_EVPNES_NON_DF
;
1693 es
->flags
&= ~ZEBRA_EVPNES_NON_DF
;
1695 /* update non-DF block filter in the dataplane */
1696 return zebra_evpn_es_br_port_dplane_update(es
, __func__
);
1700 /* returns TRUE if dplane entry was updated */
1701 static bool zebra_evpn_es_run_df_election(struct zebra_evpn_es
*es
,
1704 struct listnode
*node
= NULL
;
1705 struct zebra_evpn_es_vtep
*es_vtep
;
1706 bool new_non_df
= false;
1708 /* If the ES is not ready (i.e. not completely configured) there
1709 * is no need to setup the BUM block filter
1711 if (!(es
->flags
& ZEBRA_EVPNES_LOCAL
)
1712 || (es
->flags
& ZEBRA_EVPNES_BYPASS
)
1713 || !zmh_info
->es_originator_ip
.s_addr
)
1714 return zebra_evpn_es_df_change(es
, new_non_df
, caller
,
1717 /* if oper-state is down DF filtering must be on. when the link comes
1718 * up again dataplane should block BUM till FRR has had the chance
1719 * to run DF election again
1721 if (!(es
->flags
& ZEBRA_EVPNES_OPER_UP
)) {
1723 return zebra_evpn_es_df_change(es
, new_non_df
, caller
,
1727 /* ES was just created; we need to wait for the peers to rx the
1728 * our Type-4 routes and for the switch to import the peers' Type-4
1731 if (es
->df_delay_timer
) {
1733 return zebra_evpn_es_df_change(es
, new_non_df
, caller
,
1737 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
1738 /* Only VTEPs that have advertised the ESR can participate
1741 if (!(es_vtep
->flags
& ZEBRA_EVPNES_VTEP_RXED_ESR
))
1744 /* If the DF alg is not the same we should fall back to
1745 * service-carving. But as service-carving is not supported
1746 * we will stop forwarding BUM
1748 if (es_vtep
->df_alg
!= EVPN_MH_DF_ALG_PREF
) {
1753 /* Peer VTEP wins DF election if -
1754 * the peer-VTEP has higher preference (or)
1755 * the pref is the same but peer's IP address is lower
1757 if ((es_vtep
->df_pref
> es
->df_pref
)
1758 || ((es_vtep
->df_pref
== es
->df_pref
)
1759 && (es_vtep
->vtep_ip
.s_addr
1760 < zmh_info
->es_originator_ip
.s_addr
))) {
1766 return zebra_evpn_es_df_change(es
, new_non_df
, caller
, "elected");
1769 static void zebra_evpn_es_vtep_add(struct zebra_evpn_es
*es
,
1770 struct in_addr vtep_ip
, bool esr_rxed
,
1771 uint8_t df_alg
, uint16_t df_pref
)
1773 struct zebra_evpn_es_vtep
*es_vtep
;
1775 bool dplane_updated
= false;
1777 es_vtep
= zebra_evpn_es_vtep_find(es
, vtep_ip
);
1780 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
1781 zlog_debug("es %s vtep %pI4 add",
1782 es
->esi_str
, &vtep_ip
);
1783 es_vtep
= zebra_evpn_es_vtep_new(es
, vtep_ip
);
1784 /* update the L2-NHG associated with the ES */
1785 zebra_evpn_l2_nh_es_vtep_ref(es_vtep
);
1788 old_esr_rxed
= !!(es_vtep
->flags
& ZEBRA_EVPNES_VTEP_RXED_ESR
);
1789 if ((old_esr_rxed
!= esr_rxed
) || (es_vtep
->df_alg
!= df_alg
)
1790 || (es_vtep
->df_pref
!= df_pref
)) {
1791 /* If any of the DF election params changed we need to re-run
1795 es_vtep
->flags
|= ZEBRA_EVPNES_VTEP_RXED_ESR
;
1797 es_vtep
->flags
&= ~ZEBRA_EVPNES_VTEP_RXED_ESR
;
1798 es_vtep
->df_alg
= df_alg
;
1799 es_vtep
->df_pref
= df_pref
;
1800 dplane_updated
= zebra_evpn_es_run_df_election(es
, __func__
);
1802 /* add the vtep to the SPH list */
1803 if (!dplane_updated
&& (es
->flags
& ZEBRA_EVPNES_LOCAL
))
1804 zebra_evpn_es_br_port_dplane_update(es
, __func__
);
1807 static void zebra_evpn_es_vtep_del(struct zebra_evpn_es
*es
,
1808 struct in_addr vtep_ip
)
1810 struct zebra_evpn_es_vtep
*es_vtep
;
1811 bool dplane_updated
= false;
1813 es_vtep
= zebra_evpn_es_vtep_find(es
, vtep_ip
);
1816 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
1817 zlog_debug("es %s vtep %pI4 del",
1818 es
->esi_str
, &vtep_ip
);
1819 es_vtep
->flags
|= ZEBRA_EVPNES_VTEP_DEL_IN_PROG
;
1820 if (es_vtep
->flags
& ZEBRA_EVPNES_VTEP_RXED_ESR
) {
1821 es_vtep
->flags
&= ~ZEBRA_EVPNES_VTEP_RXED_ESR
;
1823 zebra_evpn_es_run_df_election(es
, __func__
);
1825 /* remove the vtep from the SPH list */
1826 if (!dplane_updated
&& (es
->flags
& ZEBRA_EVPNES_LOCAL
))
1827 zebra_evpn_es_br_port_dplane_update(es
, __func__
);
1828 zebra_evpn_es_vtep_free(es_vtep
);
1832 /* compare ES-IDs for the global ES RB tree */
1833 static int zebra_es_rb_cmp(const struct zebra_evpn_es
*es1
,
1834 const struct zebra_evpn_es
*es2
)
1836 return memcmp(&es1
->esi
, &es2
->esi
, ESI_BYTES
);
1838 RB_GENERATE(zebra_es_rb_head
, zebra_evpn_es
, rb_node
, zebra_es_rb_cmp
);
1841 struct zebra_evpn_es
*zebra_evpn_es_find(const esi_t
*esi
)
1843 struct zebra_evpn_es tmp
;
1845 memcpy(&tmp
.esi
, esi
, sizeof(esi_t
));
1846 return RB_FIND(zebra_es_rb_head
, &zmh_info
->es_rb_tree
, &tmp
);
1849 /* A new local es is created when a local-es-id and sysmac is configured
1850 * against an interface.
1852 static struct zebra_evpn_es
*zebra_evpn_es_new(const esi_t
*esi
)
1854 struct zebra_evpn_es
*es
;
1856 if (!memcmp(esi
, zero_esi
, sizeof(esi_t
)))
1859 es
= XCALLOC(MTYPE_ZES
, sizeof(struct zebra_evpn_es
));
1862 memcpy(&es
->esi
, esi
, sizeof(esi_t
));
1863 esi_to_str(&es
->esi
, es
->esi_str
, sizeof(es
->esi_str
));
1865 /* Add to rb_tree */
1866 RB_INSERT(zebra_es_rb_head
, &zmh_info
->es_rb_tree
, es
);
1868 /* Initialise the ES-EVI list */
1869 es
->es_evi_list
= list_new();
1870 listset_app_node_mem(es
->es_evi_list
);
1872 /* Initialise the VTEP list */
1873 es
->es_vtep_list
= list_new();
1874 listset_app_node_mem(es
->es_vtep_list
);
1875 es
->es_vtep_list
->cmp
= zebra_evpn_es_vtep_cmp
;
1877 /* mac entries associated with the ES */
1878 es
->mac_list
= list_new();
1879 listset_app_node_mem(es
->mac_list
);
1882 es
->nhg_id
= zebra_evpn_nhid_alloc(es
);
1884 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
1885 zlog_debug("es %s nhg %u new", es
->esi_str
, es
->nhg_id
);
1890 /* Free a given ES -
1891 * This just frees appropriate memory, caller should have taken other
1894 static void zebra_evpn_es_free(struct zebra_evpn_es
**esp
)
1896 struct zebra_evpn_es
*es
= *esp
;
1898 /* If the ES has a local or remote reference it cannot be freed.
1899 * Free is also prevented if there are MAC entries referencing
1902 if ((es
->flags
& (ZEBRA_EVPNES_LOCAL
| ZEBRA_EVPNES_REMOTE
)) ||
1903 listcount(es
->mac_list
))
1906 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
1907 zlog_debug("es %s free", es
->esi_str
);
1909 /* If the NHG is still installed uninstall it and free the id */
1910 if (es
->flags
& ZEBRA_EVPNES_NHG_ACTIVE
) {
1911 es
->flags
&= ~ZEBRA_EVPNES_NHG_ACTIVE
;
1912 kernel_del_mac_nhg(es
->nhg_id
);
1914 zebra_evpn_nhid_free(es
->nhg_id
, es
);
1916 /* cleanup resources maintained against the ES */
1917 list_delete(&es
->es_evi_list
);
1918 list_delete(&es
->es_vtep_list
);
1919 list_delete(&es
->mac_list
);
1921 /* remove from the VNI-ESI rb tree */
1922 RB_REMOVE(zebra_es_rb_head
, &zmh_info
->es_rb_tree
, es
);
1924 XFREE(MTYPE_ZES
, es
);
1929 /* Inform BGP about local ES addition */
1930 static int zebra_evpn_es_send_add_to_client(struct zebra_evpn_es
*es
)
1932 struct zserv
*client
;
1937 client
= zserv_find_client(ZEBRA_ROUTE_BGP
, 0);
1938 /* BGP may not be running. */
1942 s
= stream_new(ZEBRA_MAX_PACKET_SIZ
);
1944 zclient_create_header(s
, ZEBRA_LOCAL_ES_ADD
, zebra_vrf_get_evpn_id());
1945 stream_put(s
, &es
->esi
, sizeof(esi_t
));
1946 stream_put_ipv4(s
, zmh_info
->es_originator_ip
.s_addr
);
1947 oper_up
= !!(es
->flags
& ZEBRA_EVPNES_OPER_UP
);
1948 stream_putc(s
, oper_up
);
1949 stream_putw(s
, es
->df_pref
);
1950 bypass
= !!(es
->flags
& ZEBRA_EVPNES_BYPASS
);
1951 stream_putc(s
, bypass
);
1953 /* Write packet size. */
1954 stream_putw_at(s
, 0, stream_get_endp(s
));
1956 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
1958 "send add local es %s %pI4 active %u df_pref %u%s to %s",
1959 es
->esi_str
, &zmh_info
->es_originator_ip
, oper_up
,
1960 es
->df_pref
, bypass
? " bypass" : "",
1961 zebra_route_string(client
->proto
));
1963 client
->local_es_add_cnt
++;
1964 return zserv_send_message(client
, s
);
1967 /* Inform BGP about local ES deletion */
1968 static int zebra_evpn_es_send_del_to_client(struct zebra_evpn_es
*es
)
1970 struct zserv
*client
;
1973 client
= zserv_find_client(ZEBRA_ROUTE_BGP
, 0);
1974 /* BGP may not be running. */
1978 s
= stream_new(ZEBRA_MAX_PACKET_SIZ
);
1981 zclient_create_header(s
, ZEBRA_LOCAL_ES_DEL
, zebra_vrf_get_evpn_id());
1982 stream_put(s
, &es
->esi
, sizeof(esi_t
));
1984 /* Write packet size. */
1985 stream_putw_at(s
, 0, stream_get_endp(s
));
1987 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
1988 zlog_debug("send del local es %s to %s", es
->esi_str
,
1989 zebra_route_string(client
->proto
));
1991 client
->local_es_del_cnt
++;
1992 return zserv_send_message(client
, s
);
1995 static void zebra_evpn_es_re_eval_send_to_client(struct zebra_evpn_es
*es
,
1996 bool es_evi_re_reval
)
2000 struct listnode
*node
;
2001 struct zebra_evpn_es_evi
*es_evi
;
2003 old_ready
= !!(es
->flags
& ZEBRA_EVPNES_READY_FOR_BGP
);
2005 if ((es
->flags
& ZEBRA_EVPNES_LOCAL
) &&
2006 zmh_info
->es_originator_ip
.s_addr
)
2007 es
->flags
|= ZEBRA_EVPNES_READY_FOR_BGP
;
2009 es
->flags
&= ~ZEBRA_EVPNES_READY_FOR_BGP
;
2011 new_ready
= !!(es
->flags
& ZEBRA_EVPNES_READY_FOR_BGP
);
2012 if (old_ready
== new_ready
)
2016 zebra_evpn_es_send_add_to_client(es
);
2018 zebra_evpn_es_send_del_to_client(es
);
2020 /* re-eval associated EVIs */
2021 if (es_evi_re_reval
) {
2022 for (ALL_LIST_ELEMENTS_RO(es
->es_evi_list
, node
, es_evi
)) {
2023 if (!(es_evi
->flags
& ZEBRA_EVPNES_EVI_LOCAL
))
2025 zebra_evpn_es_evi_re_eval_send_to_client(es_evi
);
2030 void zebra_evpn_es_send_all_to_client(bool add
)
2032 struct listnode
*es_node
;
2033 struct listnode
*evi_node
;
2034 struct zebra_evpn_es
*es
;
2035 struct zebra_evpn_es_evi
*es_evi
;
2040 for (ALL_LIST_ELEMENTS_RO(zmh_info
->local_es_list
, es_node
, es
)) {
2041 if (es
->flags
& ZEBRA_EVPNES_READY_FOR_BGP
) {
2043 zebra_evpn_es_send_add_to_client(es
);
2044 for (ALL_LIST_ELEMENTS_RO(es
->es_evi_list
,
2045 evi_node
, es_evi
)) {
2046 if (!(es_evi
->flags
&
2047 ZEBRA_EVPNES_EVI_READY_FOR_BGP
))
2051 zebra_evpn_es_evi_send_to_client(
2055 zebra_evpn_es_evi_send_to_client(
2060 zebra_evpn_es_send_del_to_client(es
);
2065 /* walk the vlan bitmap associated with the zif and create or delete
2066 * es_evis for all vlans associated with a VNI.
2067 * XXX: This API is really expensive. optimize later if possible.
2069 static void zebra_evpn_es_setup_evis(struct zebra_evpn_es
*es
)
2071 struct zebra_if
*zif
= es
->zif
;
2073 struct zebra_evpn_access_bd
*acc_bd
;
2075 if (!bf_is_inited(zif
->vlan_bitmap
))
2078 bf_for_each_set_bit(zif
->vlan_bitmap
, vid
, IF_VLAN_BITMAP_MAX
) {
2079 acc_bd
= zebra_evpn_acc_vl_find(vid
, zif
->brslave_info
.br_if
);
2081 zebra_evpn_local_es_evi_add(es
, acc_bd
->zevpn
);
2085 static void zebra_evpn_flush_local_mac(struct zebra_mac
*mac
,
2086 struct interface
*ifp
)
2089 struct zebra_if
*zif
;
2090 struct interface
*br_ifp
;
2091 struct zebra_vxlan_vni
*vni
;
2094 br_ifp
= zif
->brslave_info
.br_if
;
2098 if (mac
->zevpn
->vxlan_if
) {
2099 zif
= mac
->zevpn
->vxlan_if
->info
;
2100 vni
= zebra_vxlan_if_vni_find(zif
, mac
->zevpn
->vni
);
2101 vid
= vni
->access_vlan
;
2106 /* delete the local mac from the dataplane */
2107 dplane_local_mac_del(ifp
, br_ifp
, vid
, &mac
->macaddr
);
2108 /* delete the local mac in zebra */
2109 zebra_evpn_del_local_mac(mac
->zevpn
, mac
, true);
2112 static void zebra_evpn_es_flush_local_macs(struct zebra_evpn_es
*es
,
2113 struct interface
*ifp
, bool add
)
2115 struct zebra_mac
*mac
;
2116 struct listnode
*node
;
2117 struct listnode
*nnode
;
2119 for (ALL_LIST_ELEMENTS(es
->mac_list
, node
, nnode
, mac
)) {
2120 if (!CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
))
2123 /* If ES is being attached/detached from the access port we
2124 * need to clear local activity and peer activity and start
2126 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
2127 zlog_debug("VNI %u mac %pEA update; local ES %s %s",
2130 es
->esi_str
, add
? "add" : "del");
2131 zebra_evpn_flush_local_mac(mac
, ifp
);
2135 void zebra_evpn_es_local_br_port_update(struct zebra_if
*zif
)
2137 struct zebra_evpn_es
*es
= zif
->es_info
.es
;
2138 bool old_br_port
= !!(es
->flags
& ZEBRA_EVPNES_BR_PORT
);
2141 if (zif
->brslave_info
.bridge_ifindex
!= IFINDEX_INTERNAL
)
2142 es
->flags
|= ZEBRA_EVPNES_BR_PORT
;
2144 es
->flags
&= ~ZEBRA_EVPNES_BR_PORT
;
2146 new_br_port
= !!(es
->flags
& ZEBRA_EVPNES_BR_PORT
);
2147 if (old_br_port
== new_br_port
)
2150 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2151 zlog_debug("es %s br_port change old %u new %u", es
->esi_str
,
2152 old_br_port
, new_br_port
);
2154 /* update the dataplane br_port attrs */
2155 if (new_br_port
&& zebra_evpn_es_br_port_dplane_update_needed(es
))
2156 zebra_evpn_es_br_port_dplane_update(es
, __func__
);
2159 /* On config of first local-ES turn off DAD */
2160 static void zebra_evpn_mh_dup_addr_detect_off(void)
2162 struct zebra_vrf
*zvrf
;
2166 if (zmh_info
->flags
& ZEBRA_EVPN_MH_DUP_ADDR_DETECT_OFF
)
2169 zvrf
= zebra_vrf_get_evpn();
2170 old_detect
= zebra_evpn_do_dup_addr_detect(zvrf
);
2171 zmh_info
->flags
|= ZEBRA_EVPN_MH_DUP_ADDR_DETECT_OFF
;
2172 new_detect
= zebra_evpn_do_dup_addr_detect(zvrf
);
2174 if (old_detect
&& !new_detect
) {
2175 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2177 "evpn-mh config caused DAD addr detect chg from %s to %s",
2178 old_detect
? "on" : "off",
2179 new_detect
? "on" : "off");
2180 zebra_vxlan_clear_dup_detect_vni_all(zvrf
);
2184 /* On config of first local-ES turn off advertisement of STALE/DELAY/PROBE
2187 static void zebra_evpn_mh_advertise_reach_neigh_only(void)
2189 if (zmh_info
->flags
& ZEBRA_EVPN_MH_ADV_REACHABLE_NEIGH_ONLY
)
2192 zmh_info
->flags
|= ZEBRA_EVPN_MH_ADV_REACHABLE_NEIGH_ONLY
;
2193 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2194 zlog_debug("evpn-mh: only REACHABLE neigh advertised");
2196 /* XXX - if STALE/DELAY/PROBE neighs were previously advertised we
2197 * need to withdraw them
2201 /* On config of first local-ES turn on advertisement of local SVI-MAC */
2202 static void zebra_evpn_mh_advertise_svi_mac(void)
2204 if (zmh_info
->flags
& ZEBRA_EVPN_MH_ADV_SVI_MAC
)
2207 zmh_info
->flags
|= ZEBRA_EVPN_MH_ADV_SVI_MAC
;
2208 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2209 zlog_debug("evpn-mh: advertise SVI MAC");
2211 /* walk through all SVIs and see if we need to advertise the MAC */
2212 zebra_evpn_acc_vl_adv_svi_mac_all();
2215 static void zebra_evpn_es_df_delay_exp_cb(struct thread
*t
)
2217 struct zebra_evpn_es
*es
;
2221 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2222 zlog_debug("es %s df-delay expired", es
->esi_str
);
2224 zebra_evpn_es_run_df_election(es
, __func__
);
2227 /* currently there is no global config to turn on MH instead we use
2228 * the addition of the first local Ethernet Segment as the trigger to
2229 * init MH specific processing
2231 static void zebra_evpn_mh_on_first_local_es(void)
2233 zebra_evpn_mh_dup_addr_detect_off();
2234 zebra_evpn_mh_advertise_reach_neigh_only();
2235 zebra_evpn_mh_advertise_svi_mac();
2238 static void zebra_evpn_es_local_info_set(struct zebra_evpn_es
*es
,
2239 struct zebra_if
*zif
)
2241 if (es
->flags
& ZEBRA_EVPNES_LOCAL
)
2244 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2245 zlog_debug("local es %s add; nhg %u if %s", es
->esi_str
,
2246 es
->nhg_id
, zif
->ifp
->name
);
2248 zebra_evpn_mh_on_first_local_es();
2250 es
->flags
|= ZEBRA_EVPNES_LOCAL
;
2251 listnode_init(&es
->local_es_listnode
, es
);
2252 listnode_add(zmh_info
->local_es_list
, &es
->local_es_listnode
);
2254 /* attach es to interface */
2255 zif
->es_info
.es
= es
;
2256 es
->df_pref
= zif
->es_info
.df_pref
? zif
->es_info
.df_pref
2257 : EVPN_MH_DF_PREF_DEFAULT
;
2259 /* attach interface to es */
2261 if (if_is_operative(zif
->ifp
))
2262 es
->flags
|= ZEBRA_EVPNES_OPER_UP
;
2264 if (zif
->brslave_info
.bridge_ifindex
!= IFINDEX_INTERNAL
)
2265 es
->flags
|= ZEBRA_EVPNES_BR_PORT
;
2267 /* inherit the bypass flag from the interface */
2268 if (zif
->flags
& ZIF_FLAG_LACP_BYPASS
)
2269 es
->flags
|= ZEBRA_EVPNES_BYPASS
;
2271 /* setup base-vni if one doesn't already exist; the ES will get sent
2272 * to BGP as a part of that process
2274 if (!zmh_info
->es_base_evpn
)
2275 zebra_evpn_es_get_one_base_evpn();
2277 /* send notification to bgp */
2278 zebra_evpn_es_re_eval_send_to_client(es
,
2279 false /* es_evi_re_reval */);
2281 /* Start the DF delay timer on the local ES */
2282 if (!es
->df_delay_timer
)
2283 thread_add_timer(zrouter
.master
, zebra_evpn_es_df_delay_exp_cb
,
2284 es
, ZEBRA_EVPN_MH_DF_DELAY_TIME
,
2285 &es
->df_delay_timer
);
2287 /* See if the local VTEP can function as DF on the ES */
2288 if (!zebra_evpn_es_run_df_election(es
, __func__
)) {
2289 /* check if the dplane entry needs to be re-programmed as a
2290 * result of some thing other than DF status change
2292 if (zebra_evpn_es_br_port_dplane_update_needed(es
))
2293 zebra_evpn_es_br_port_dplane_update(es
, __func__
);
2297 /* Setup ES-EVIs for all VxLAN stretched VLANs associated with
2300 zebra_evpn_es_setup_evis(es
);
2301 /* if there any local macs referring to the ES as dest we
2302 * need to clear the contents and start over
2304 zebra_evpn_es_flush_local_macs(es
, zif
->ifp
, true);
2306 /* inherit EVPN protodown flags on the access port */
2307 zebra_evpn_mh_update_protodown_es(es
, true /*resync_dplane*/);
2310 static void zebra_evpn_es_local_info_clear(struct zebra_evpn_es
**esp
)
2312 struct zebra_if
*zif
;
2313 struct zebra_evpn_es
*es
= *esp
;
2314 bool dplane_updated
= false;
2316 if (!(es
->flags
& ZEBRA_EVPNES_LOCAL
))
2321 /* if there any local macs referring to the ES as dest we
2322 * need to clear the contents and start over
2324 zebra_evpn_es_flush_local_macs(es
, zif
->ifp
, false);
2326 es
->flags
&= ~(ZEBRA_EVPNES_LOCAL
| ZEBRA_EVPNES_READY_FOR_BGP
);
2328 THREAD_OFF(es
->df_delay_timer
);
2330 /* clear EVPN protodown flags on the access port */
2331 zebra_evpn_mh_clear_protodown_es(es
);
2333 /* remove the DF filter */
2334 dplane_updated
= zebra_evpn_es_run_df_election(es
, __func__
);
2336 /* flush the BUM filters and backup NHG */
2337 if (!dplane_updated
)
2338 zebra_evpn_es_br_port_dplane_clear(es
);
2340 /* clear the es from the parent interface */
2341 zif
->es_info
.es
= NULL
;
2344 /* clear all local flags associated with the ES */
2345 es
->flags
&= ~(ZEBRA_EVPNES_OPER_UP
| ZEBRA_EVPNES_BR_PORT
2346 | ZEBRA_EVPNES_BYPASS
);
2348 /* remove from the ES list */
2349 list_delete_node(zmh_info
->local_es_list
, &es
->local_es_listnode
);
2351 /* free up the ES if there is no remote reference */
2352 zebra_evpn_es_free(esp
);
2355 /* Delete an ethernet segment and inform BGP */
2356 static void zebra_evpn_local_es_del(struct zebra_evpn_es
**esp
)
2358 struct zebra_evpn_es_evi
*es_evi
;
2359 struct listnode
*node
= NULL
;
2360 struct listnode
*nnode
= NULL
;
2361 struct zebra_if
*zif
;
2362 struct zebra_evpn_es
*es
= *esp
;
2364 if (!CHECK_FLAG(es
->flags
, ZEBRA_EVPNES_LOCAL
))
2367 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
) {
2369 zlog_debug("local es %s del; nhg %u if %s", es
->esi_str
,
2370 es
->nhg_id
, zif
? zif
->ifp
->name
: "-");
2373 /* remove all ES-EVIs associated with the ES */
2374 for (ALL_LIST_ELEMENTS(es
->es_evi_list
, node
, nnode
, es_evi
))
2375 zebra_evpn_local_es_evi_do_del(es_evi
);
2377 /* send a del if the ES had been sent to BGP earlier */
2378 if (es
->flags
& ZEBRA_EVPNES_READY_FOR_BGP
)
2379 zebra_evpn_es_send_del_to_client(es
);
2381 zebra_evpn_es_local_info_clear(esp
);
2384 /* eval remote info associated with the ES */
2385 static void zebra_evpn_es_remote_info_re_eval(struct zebra_evpn_es
**esp
)
2387 struct zebra_evpn_es
*es
= *esp
;
2389 /* if there are remote VTEPs the ES-EVI is classified as "remote" */
2390 if (listcount(es
->es_vtep_list
)) {
2391 if (!(es
->flags
& ZEBRA_EVPNES_REMOTE
)) {
2392 es
->flags
|= ZEBRA_EVPNES_REMOTE
;
2393 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2394 zlog_debug("remote es %s add; nhg %u",
2395 es
->esi_str
, es
->nhg_id
);
2398 if (es
->flags
& ZEBRA_EVPNES_REMOTE
) {
2399 es
->flags
&= ~ZEBRA_EVPNES_REMOTE
;
2400 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2401 zlog_debug("remote es %s del; nhg %u",
2402 es
->esi_str
, es
->nhg_id
);
2403 zebra_evpn_es_free(esp
);
2408 /* A new local es is created when a local-es-id and sysmac is configured
2409 * against an interface.
2411 static int zebra_evpn_local_es_update(struct zebra_if
*zif
, esi_t
*esi
)
2413 struct zebra_evpn_es
*old_es
= zif
->es_info
.es
;
2414 struct zebra_evpn_es
*es
;
2416 if (old_es
&& !memcmp(&old_es
->esi
, esi
, sizeof(*esi
)))
2417 /* dup - nothing to be done */
2420 /* release the old_es against the zif */
2422 zebra_evpn_local_es_del(&old_es
);
2424 es
= zebra_evpn_es_find(esi
);
2426 /* if it exists against another interface flag an error */
2427 if (es
->zif
&& es
->zif
!= zif
)
2431 es
= zebra_evpn_es_new(esi
);
2434 memcpy(&zif
->es_info
.esi
, esi
, sizeof(*esi
));
2436 zebra_evpn_es_local_info_set(es
, zif
);
2441 static int zebra_evpn_type3_esi_update(struct zebra_if
*zif
, uint32_t lid
,
2442 struct ethaddr
*sysmac
)
2444 struct zebra_evpn_es
*old_es
= zif
->es_info
.es
;
2447 int field_bytes
= 0;
2449 /* Complete config of the ES-ID bootstraps the ES */
2450 if (!lid
|| is_zero_mac(sysmac
)) {
2452 memset(&zif
->es_info
.esi
, 0, sizeof(zif
->es_info
.esi
));
2453 /* if in ES is attached to zif delete it */
2455 zebra_evpn_local_es_del(&old_es
);
2459 /* build 10-byte type-3-ESI -
2460 * Type(1-byte), MAC(6-bytes), ES-LID (3-bytes)
2463 esi
.val
[offset
] = ESI_TYPE_MAC
;
2464 offset
+= field_bytes
;
2466 field_bytes
= ETH_ALEN
;
2467 memcpy(&esi
.val
[offset
], (uint8_t *)sysmac
, field_bytes
);
2468 offset
+= field_bytes
;
2470 esi
.val
[offset
++] = (uint8_t)(lid
>> 16);
2471 esi
.val
[offset
++] = (uint8_t)(lid
>> 8);
2472 esi
.val
[offset
++] = (uint8_t)lid
;
2474 return zebra_evpn_local_es_update(zif
, &esi
);
2477 int zebra_evpn_remote_es_del(const esi_t
*esi
, struct in_addr vtep_ip
)
2479 char buf
[ESI_STR_LEN
];
2480 struct zebra_evpn_es
*es
;
2482 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2483 zlog_debug("remote es %s vtep %pI4 del",
2484 esi_to_str(esi
, buf
, sizeof(buf
)), &vtep_ip
);
2486 es
= zebra_evpn_es_find(esi
);
2488 zlog_warn("remote es %s vtep %pI4 del failed, es missing",
2489 esi_to_str(esi
, buf
, sizeof(buf
)), &vtep_ip
);
2493 zebra_evpn_es_vtep_del(es
, vtep_ip
);
2494 zebra_evpn_es_remote_info_re_eval(&es
);
2499 /* force delete a remote ES on the way down */
2500 static void zebra_evpn_remote_es_flush(struct zebra_evpn_es
**esp
)
2502 struct zebra_evpn_es_vtep
*es_vtep
;
2503 struct listnode
*node
;
2504 struct listnode
*nnode
;
2505 struct zebra_evpn_es
*es
= *esp
;
2507 for (ALL_LIST_ELEMENTS(es
->es_vtep_list
, node
, nnode
, es_vtep
)) {
2508 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2509 zlog_debug("es %s vtep %pI4 flush",
2512 zebra_evpn_es_vtep_free(es_vtep
);
2514 zebra_evpn_es_remote_info_re_eval(esp
);
2517 int zebra_evpn_remote_es_add(const esi_t
*esi
, struct in_addr vtep_ip
,
2518 bool esr_rxed
, uint8_t df_alg
, uint16_t df_pref
)
2520 char buf
[ESI_STR_LEN
];
2521 struct zebra_evpn_es
*es
;
2523 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2524 zlog_debug("remote es %s vtep %pI4 add %s df_alg %d df_pref %d",
2525 esi_to_str(esi
, buf
, sizeof(buf
)),
2526 &vtep_ip
, esr_rxed
? "esr" : "", df_alg
,
2529 es
= zebra_evpn_es_find(esi
);
2531 es
= zebra_evpn_es_new(esi
);
2534 "remote es %s vtep %pI4 add failed, es missing",
2535 esi_to_str(esi
, buf
, sizeof(buf
)), &vtep_ip
);
2540 if (df_alg
!= EVPN_MH_DF_ALG_PREF
)
2542 "remote es %s vtep %pI4 add %s with unsupported df_alg %d",
2543 esi_to_str(esi
, buf
, sizeof(buf
)), &vtep_ip
,
2544 esr_rxed
? "esr" : "", df_alg
);
2546 zebra_evpn_es_vtep_add(es
, vtep_ip
, esr_rxed
, df_alg
, df_pref
);
2547 zebra_evpn_es_remote_info_re_eval(&es
);
2552 void zebra_evpn_proc_remote_es(ZAPI_HANDLER_ARGS
)
2555 struct in_addr vtep_ip
;
2558 if (!is_evpn_enabled()) {
2560 "%s: EVPN not enabled yet we received a es_add zapi call",
2565 memset(&esi
, 0, sizeof(esi_t
));
2568 STREAM_GET(&esi
, s
, sizeof(esi_t
));
2569 STREAM_GET(&vtep_ip
.s_addr
, s
, sizeof(vtep_ip
.s_addr
));
2571 if (hdr
->command
== ZEBRA_REMOTE_ES_VTEP_ADD
) {
2572 uint32_t zapi_flags
;
2577 STREAM_GETL(s
, zapi_flags
);
2578 esr_rxed
= (zapi_flags
& ZAPI_ES_VTEP_FLAG_ESR_RXED
) ? true
2580 STREAM_GETC(s
, df_alg
);
2581 STREAM_GETW(s
, df_pref
);
2582 zebra_rib_queue_evpn_rem_es_add(&esi
, &vtep_ip
, esr_rxed
,
2585 zebra_rib_queue_evpn_rem_es_del(&esi
, &vtep_ip
);
2592 void zebra_evpn_es_mac_deref_entry(struct zebra_mac
*mac
)
2594 struct zebra_evpn_es
*es
= mac
->es
;
2600 list_delete_node(es
->mac_list
, &mac
->es_listnode
);
2601 if (!listcount(es
->mac_list
))
2602 zebra_evpn_es_free(&es
);
2605 /* Associate a MAC entry with a local or remote ES. Returns false if there
2608 bool zebra_evpn_es_mac_ref_entry(struct zebra_mac
*mac
,
2609 struct zebra_evpn_es
*es
)
2615 zebra_evpn_es_mac_deref_entry(mac
);
2621 listnode_init(&mac
->es_listnode
, mac
);
2622 listnode_add(es
->mac_list
, &mac
->es_listnode
);
2627 bool zebra_evpn_es_mac_ref(struct zebra_mac
*mac
, const esi_t
*esi
)
2629 struct zebra_evpn_es
*es
;
2631 es
= zebra_evpn_es_find(esi
);
2633 /* If non-zero esi implicitly create a new ES */
2634 if (memcmp(esi
, zero_esi
, sizeof(esi_t
))) {
2635 es
= zebra_evpn_es_new(esi
);
2636 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2637 zlog_debug("auto es %s add on mac ref",
2642 return zebra_evpn_es_mac_ref_entry(mac
, es
);
2645 /* Inform BGP about local ES-EVI add or del */
2646 static int zebra_evpn_es_evi_send_to_client(struct zebra_evpn_es
*es
,
2647 struct zebra_evpn
*zevpn
, bool add
)
2649 struct zserv
*client
;
2652 client
= zserv_find_client(ZEBRA_ROUTE_BGP
, 0);
2653 /* BGP may not be running. */
2657 s
= stream_new(ZEBRA_MAX_PACKET_SIZ
);
2659 zclient_create_header(s
,
2660 add
? ZEBRA_LOCAL_ES_EVI_ADD
: ZEBRA_LOCAL_ES_EVI_DEL
,
2661 zebra_vrf_get_evpn_id());
2662 stream_put(s
, &es
->esi
, sizeof(esi_t
));
2663 stream_putl(s
, zevpn
->vni
);
2665 /* Write packet size. */
2666 stream_putw_at(s
, 0, stream_get_endp(s
));
2668 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2669 zlog_debug("send %s local es %s evi %u to %s",
2670 add
? "add" : "del",
2671 es
->esi_str
, zevpn
->vni
,
2672 zebra_route_string(client
->proto
));
2674 client
->local_es_add_cnt
++;
2675 return zserv_send_message(client
, s
);
2678 /* sysmac part of a local ESI has changed */
2679 static int zebra_evpn_es_sys_mac_update(struct zebra_if
*zif
,
2680 struct ethaddr
*sysmac
)
2684 rv
= zebra_evpn_type3_esi_update(zif
, zif
->es_info
.lid
, sysmac
);
2686 memcpy(&zif
->es_info
.sysmac
, sysmac
, sizeof(struct ethaddr
));
2691 /* local-ID part of ESI has changed */
2692 static int zebra_evpn_es_lid_update(struct zebra_if
*zif
, uint32_t lid
)
2696 rv
= zebra_evpn_type3_esi_update(zif
, lid
, &zif
->es_info
.sysmac
);
2698 zif
->es_info
.lid
= lid
;
2703 /* type-0 esi has changed */
2704 static int zebra_evpn_es_type0_esi_update(struct zebra_if
*zif
, esi_t
*esi
)
2708 rv
= zebra_evpn_local_es_update(zif
, esi
);
2710 /* clear the old es_lid, es_sysmac - type-0 is being set so old
2711 * type-3 params need to be flushed
2713 memset(&zif
->es_info
.sysmac
, 0, sizeof(struct ethaddr
));
2714 zif
->es_info
.lid
= 0;
2719 void zebra_evpn_es_cleanup(void)
2721 struct zebra_evpn_es
*es
;
2722 struct zebra_evpn_es
*es_next
;
2724 RB_FOREACH_SAFE(es
, zebra_es_rb_head
,
2725 &zmh_info
->es_rb_tree
, es_next
) {
2726 zebra_evpn_local_es_del(&es
);
2728 zebra_evpn_remote_es_flush(&es
);
2732 static void zebra_evpn_es_df_pref_update(struct zebra_if
*zif
, uint16_t df_pref
)
2734 struct zebra_evpn_es
*es
;
2737 if (zif
->es_info
.df_pref
== df_pref
)
2740 zif
->es_info
.df_pref
= df_pref
;
2741 es
= zif
->es_info
.es
;
2746 tmp_pref
= zif
->es_info
.df_pref
? zif
->es_info
.df_pref
2747 : EVPN_MH_DF_PREF_DEFAULT
;
2749 if (es
->df_pref
== tmp_pref
)
2752 es
->df_pref
= tmp_pref
;
2753 /* run df election */
2754 zebra_evpn_es_run_df_election(es
, __func__
);
2756 if (es
->flags
& ZEBRA_EVPNES_READY_FOR_BGP
)
2757 zebra_evpn_es_send_add_to_client(es
);
2760 /* If bypass mode on an es changed we set all local macs to
2761 * inactive and drop the sync info
2763 static void zebra_evpn_es_bypass_update_macs(struct zebra_evpn_es
*es
,
2764 struct interface
*ifp
, bool bypass
)
2766 struct zebra_mac
*mac
;
2767 struct listnode
*node
;
2768 struct listnode
*nnode
;
2769 struct zebra_if
*zif
;
2771 /* Flush all MACs linked to the ES */
2772 for (ALL_LIST_ELEMENTS(es
->mac_list
, node
, nnode
, mac
)) {
2773 if (!CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
))
2776 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
2777 zlog_debug("VNI %u mac %pEA %s update es %s",
2780 bypass
? "bypass" : "non-bypass",
2782 zebra_evpn_flush_local_mac(mac
, ifp
);
2785 /* While in bypass-mode locally learnt MACs are linked
2786 * to the access port instead of the ES
2792 for (ALL_LIST_ELEMENTS(zif
->mac_list
, node
, nnode
, mac
)) {
2793 if (!CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
))
2796 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
2797 zlog_debug("VNI %u mac %pEA %s update ifp %s",
2800 bypass
? "bypass" : "non-bypass", ifp
->name
);
2801 zebra_evpn_flush_local_mac(mac
, ifp
);
2805 void zebra_evpn_es_bypass_update(struct zebra_evpn_es
*es
,
2806 struct interface
*ifp
, bool bypass
)
2809 bool dplane_updated
;
2811 old_bypass
= !!(es
->flags
& ZEBRA_EVPNES_BYPASS
);
2812 if (old_bypass
== bypass
)
2816 es
->flags
|= ZEBRA_EVPNES_BYPASS
;
2818 es
->flags
&= ~ZEBRA_EVPNES_BYPASS
;
2820 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2821 zlog_debug("bond %s es %s lacp bypass changed to %s", ifp
->name
,
2822 es
->esi_str
, bypass
? "on" : "off");
2824 /* send bypass update to BGP */
2825 if (es
->flags
& ZEBRA_EVPNES_READY_FOR_BGP
)
2826 zebra_evpn_es_send_add_to_client(es
);
2828 zebra_evpn_es_bypass_update_macs(es
, ifp
, bypass
);
2830 /* re-run DF election */
2831 dplane_updated
= zebra_evpn_es_run_df_election(es
, __func__
);
2833 /* disable SPH filter */
2834 if (!dplane_updated
&& (es
->flags
& ZEBRA_EVPNES_LOCAL
)
2835 && (listcount(es
->es_vtep_list
) > ES_VTEP_MAX_CNT
))
2836 zebra_evpn_es_br_port_dplane_update(es
, __func__
);
2839 static void zebra_evpn_es_bypass_cfg_update(struct zebra_if
*zif
, bool bypass
)
2841 bool old_bypass
= !!(zif
->es_info
.flags
& ZIF_CFG_ES_FLAG_BYPASS
);
2843 if (old_bypass
== bypass
)
2847 zif
->es_info
.flags
|= ZIF_CFG_ES_FLAG_BYPASS
;
2849 zif
->es_info
.flags
&= ~ZIF_CFG_ES_FLAG_BYPASS
;
2852 if (zif
->es_info
.es
)
2853 zebra_evpn_es_bypass_update(zif
->es_info
.es
, zif
->ifp
, bypass
);
2857 /* Only certain types of access ports can be setup as an Ethernet Segment */
2858 bool zebra_evpn_is_if_es_capable(struct zebra_if
*zif
)
2860 if (zif
->zif_type
== ZEBRA_IF_BOND
)
2863 /* relax the checks to allow config to be applied in zebra
2864 * before interface is rxed from the kernel
2866 if (zif
->ifp
->ifindex
== IFINDEX_INTERNAL
)
2869 /* XXX: allow swpX i.e. a regular ethernet port to be an ES link too */
2873 void zebra_evpn_if_es_print(struct vty
*vty
, json_object
*json
,
2874 struct zebra_if
*zif
)
2876 char buf
[ETHER_ADDR_STRLEN
];
2877 char esi_buf
[ESI_STR_LEN
];
2880 json_object
*json_evpn
;
2882 json_evpn
= json_object_new_object();
2883 json_object_object_add(json
, "evpnMh", json_evpn
);
2885 if (zif
->es_info
.lid
|| !is_zero_mac(&zif
->es_info
.sysmac
)) {
2886 json_object_int_add(json_evpn
, "esId",
2888 json_object_string_add(
2889 json_evpn
, "esSysmac",
2890 prefix_mac2str(&zif
->es_info
.sysmac
, buf
,
2892 } else if (memcmp(&zif
->es_info
.esi
, zero_esi
,
2893 sizeof(*zero_esi
))) {
2894 json_object_string_add(json_evpn
, "esId",
2895 esi_to_str(&zif
->es_info
.esi
,
2900 if (zif
->flags
& ZIF_FLAG_EVPN_MH_UPLINK
)
2901 json_object_string_add(
2902 json_evpn
, "uplink",
2903 CHECK_FLAG(zif
->flags
,
2904 ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP
)
2909 bool vty_print
= false;
2912 strlcat(mh_buf
, " EVPN-MH:", sizeof(mh_buf
));
2913 if (zif
->es_info
.lid
|| !is_zero_mac(&zif
->es_info
.sysmac
)) {
2915 snprintf(mh_buf
+ strlen(mh_buf
),
2916 sizeof(mh_buf
) - strlen(mh_buf
),
2917 " ES id %u ES sysmac %s", zif
->es_info
.lid
,
2918 prefix_mac2str(&zif
->es_info
.sysmac
, buf
,
2920 } else if (memcmp(&zif
->es_info
.esi
, zero_esi
,
2921 sizeof(*zero_esi
))) {
2923 snprintf(mh_buf
+ strnlen(mh_buf
, sizeof(mh_buf
)),
2925 - strnlen(mh_buf
, sizeof(mh_buf
)),
2927 esi_to_str(&zif
->es_info
.esi
, esi_buf
,
2931 if (zif
->flags
& ZIF_FLAG_EVPN_MH_UPLINK
) {
2933 if (zif
->flags
& ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP
)
2934 strlcat(mh_buf
, " uplink (up)", sizeof(mh_buf
));
2936 strlcat(mh_buf
, " uplink (down)",
2941 vty_out(vty
, "%s\n", mh_buf
);
2945 static void zebra_evpn_local_mac_oper_state_change(struct zebra_evpn_es
*es
)
2947 struct zebra_mac
*mac
;
2948 struct listnode
*node
;
2950 /* If fast-failover is supported by the dataplane via the use
2951 * of an ES backup NHG there is nothing to be done in the
2954 if (!(zmh_info
->flags
& ZEBRA_EVPN_MH_REDIRECT_OFF
))
2957 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
|| IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
2958 zlog_debug("mac slow-fail on es %s %s ", es
->esi_str
,
2959 (es
->flags
& ZEBRA_EVPNES_OPER_UP
) ? "up" : "down");
2961 for (ALL_LIST_ELEMENTS_RO(es
->mac_list
, node
, mac
)) {
2962 if (!(mac
->flags
& ZEBRA_MAC_LOCAL
)
2963 || !zebra_evpn_mac_is_static(mac
))
2966 if (es
->flags
& ZEBRA_EVPNES_OPER_UP
) {
2967 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
2969 "VNI %u mac %pEA move to acc %s es %s %s ",
2972 es
->zif
->ifp
->name
, es
->esi_str
,
2973 (es
->flags
& ZEBRA_EVPNES_OPER_UP
)
2976 /* switch the local macs to access port */
2977 if (zebra_evpn_sync_mac_dp_install(
2978 mac
, false /*set_inactive*/,
2979 false /*force_clear_static*/, __func__
)
2981 /* if the local mac install fails get rid of the
2984 zebra_evpn_rem_mac_uninstall(mac
->zevpn
, mac
,
2987 /* switch the local macs to network port. if there
2988 * is no active NHG we don't bother deleting the MAC;
2989 * that is left up to the dataplane to handle.
2991 if (!(es
->flags
& ZEBRA_EVPNES_NHG_ACTIVE
))
2993 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
2995 "VNI %u mac %pEA move to nhg %u es %s %s ",
2998 es
->nhg_id
, es
->esi_str
,
2999 (es
->flags
& ZEBRA_EVPNES_OPER_UP
)
3002 zebra_evpn_rem_mac_install(mac
->zevpn
, mac
,
3003 true /*was_static*/);
3008 void zebra_evpn_es_if_oper_state_change(struct zebra_if
*zif
, bool up
)
3010 struct zebra_evpn_es
*es
= zif
->es_info
.es
;
3011 bool old_up
= !!(es
->flags
& ZEBRA_EVPNES_OPER_UP
);
3016 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3017 zlog_debug("es %s state changed to %s ",
3019 up
? "up" : "down");
3021 es
->flags
|= ZEBRA_EVPNES_OPER_UP
;
3023 es
->flags
&= ~ZEBRA_EVPNES_OPER_UP
;
3025 zebra_evpn_es_run_df_election(es
, __func__
);
3026 zebra_evpn_local_mac_oper_state_change(es
);
3028 /* inform BGP of the ES oper state change */
3029 if (es
->flags
& ZEBRA_EVPNES_READY_FOR_BGP
)
3030 zebra_evpn_es_send_add_to_client(es
);
3033 static char *zebra_evpn_es_vtep_str(char *vtep_str
, struct zebra_evpn_es
*es
,
3034 uint8_t vtep_str_size
)
3036 struct zebra_evpn_es_vtep
*zvtep
;
3037 struct listnode
*node
;
3039 char ip_buf
[INET6_ADDRSTRLEN
];
3042 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, zvtep
)) {
3046 inet_ntop(AF_INET
, &zvtep
->vtep_ip
, ip_buf
,
3050 strlcat(vtep_str
, ",", vtep_str_size
);
3052 inet_ntop(AF_INET
, &zvtep
->vtep_ip
, ip_buf
,
3060 static void zebra_evpn_es_json_vtep_fill(struct zebra_evpn_es
*es
,
3061 json_object
*json_vteps
)
3063 struct zebra_evpn_es_vtep
*es_vtep
;
3064 struct listnode
*node
;
3065 json_object
*json_vtep_entry
;
3066 char alg_buf
[EVPN_DF_ALG_STR_LEN
];
3068 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
3069 json_vtep_entry
= json_object_new_object();
3070 json_object_string_addf(json_vtep_entry
, "vtep", "%pI4",
3072 if (es_vtep
->flags
& ZEBRA_EVPNES_VTEP_RXED_ESR
) {
3073 json_object_string_add(
3074 json_vtep_entry
, "dfAlgorithm",
3075 evpn_es_df_alg2str(es_vtep
->df_alg
, alg_buf
,
3077 json_object_int_add(json_vtep_entry
, "dfPreference",
3081 json_object_int_add(json_vtep_entry
, "nexthopId",
3082 es_vtep
->nh
->nh_id
);
3083 json_object_array_add(json_vteps
, json_vtep_entry
);
3087 static void zebra_evpn_es_show_entry(struct vty
*vty
, struct zebra_evpn_es
*es
,
3088 json_object
*json_array
)
3091 char vtep_str
[ES_VTEP_LIST_STR_SZ
];
3094 json_object
*json
= NULL
;
3095 json_object
*json_vteps
;
3096 json_object
*json_flags
;
3098 json
= json_object_new_object();
3099 json_object_string_add(json
, "esi", es
->esi_str
);
3102 & (ZEBRA_EVPNES_LOCAL
| ZEBRA_EVPNES_REMOTE
3103 | ZEBRA_EVPNES_NON_DF
)) {
3104 json_flags
= json_object_new_array();
3105 if (es
->flags
& ZEBRA_EVPNES_LOCAL
)
3106 json_array_string_add(json_flags
, "local");
3107 if (es
->flags
& ZEBRA_EVPNES_REMOTE
)
3108 json_array_string_add(json_flags
, "remote");
3109 if (es
->flags
& ZEBRA_EVPNES_NON_DF
)
3110 json_array_string_add(json_flags
, "nonDF");
3111 if (es
->flags
& ZEBRA_EVPNES_BYPASS
)
3112 json_array_string_add(json_flags
, "bypass");
3113 json_object_object_add(json
, "flags", json_flags
);
3117 json_object_string_add(json
, "accessPort",
3118 es
->zif
->ifp
->name
);
3120 if (listcount(es
->es_vtep_list
)) {
3121 json_vteps
= json_object_new_array();
3122 zebra_evpn_es_json_vtep_fill(es
, json_vteps
);
3123 json_object_object_add(json
, "vteps", json_vteps
);
3125 json_object_array_add(json_array
, json
);
3128 if (es
->flags
& ZEBRA_EVPNES_LOCAL
)
3129 strlcat(type_str
, "L", sizeof(type_str
));
3130 if (es
->flags
& ZEBRA_EVPNES_REMOTE
)
3131 strlcat(type_str
, "R", sizeof(type_str
));
3132 if (es
->flags
& ZEBRA_EVPNES_NON_DF
)
3133 strlcat(type_str
, "N", sizeof(type_str
));
3134 if (es
->flags
& ZEBRA_EVPNES_BYPASS
)
3135 strlcat(type_str
, "B", sizeof(type_str
));
3137 zebra_evpn_es_vtep_str(vtep_str
, es
, sizeof(vtep_str
));
3139 vty_out(vty
, "%-30s %-4s %-21s %s\n",
3140 es
->esi_str
, type_str
,
3141 es
->zif
? es
->zif
->ifp
->name
: "-",
3146 static void zebra_evpn_es_show_entry_detail(struct vty
*vty
,
3147 struct zebra_evpn_es
*es
, json_object
*json
)
3150 char alg_buf
[EVPN_DF_ALG_STR_LEN
];
3151 struct zebra_evpn_es_vtep
*es_vtep
;
3152 struct listnode
*node
;
3153 char thread_buf
[THREAD_TIMER_STRLEN
];
3156 json_object
*json_vteps
;
3157 json_object
*json_flags
;
3159 json_object_string_add(json
, "esi", es
->esi_str
);
3161 json_object_string_add(json
, "accessPort",
3162 es
->zif
->ifp
->name
);
3166 json_flags
= json_object_new_array();
3167 if (es
->flags
& ZEBRA_EVPNES_LOCAL
)
3168 json_array_string_add(json_flags
, "local");
3169 if (es
->flags
& ZEBRA_EVPNES_REMOTE
)
3170 json_array_string_add(json_flags
, "remote");
3171 if (es
->flags
& ZEBRA_EVPNES_NON_DF
)
3172 json_array_string_add(json_flags
, "nonDF");
3173 if (es
->flags
& ZEBRA_EVPNES_BYPASS
)
3174 json_array_string_add(json_flags
, "bypass");
3175 if (es
->flags
& ZEBRA_EVPNES_READY_FOR_BGP
)
3176 json_array_string_add(json_flags
,
3178 if (es
->flags
& ZEBRA_EVPNES_BR_PORT
)
3179 json_array_string_add(json_flags
, "bridgePort");
3180 if (es
->flags
& ZEBRA_EVPNES_OPER_UP
)
3181 json_array_string_add(json_flags
, "operUp");
3182 if (es
->flags
& ZEBRA_EVPNES_NHG_ACTIVE
)
3183 json_array_string_add(json_flags
,
3184 "nexthopGroupActive");
3185 json_object_object_add(json
, "flags", json_flags
);
3188 json_object_int_add(json
, "vniCount",
3189 listcount(es
->es_evi_list
));
3190 json_object_int_add(json
, "macCount", listcount(es
->mac_list
));
3191 json_object_int_add(json
, "dfPreference", es
->df_pref
);
3192 if (es
->df_delay_timer
)
3193 json_object_string_add(
3194 json
, "dfDelayTimer",
3195 thread_timer_to_hhmmss(thread_buf
,
3197 es
->df_delay_timer
));
3198 json_object_int_add(json
, "nexthopGroup", es
->nhg_id
);
3199 if (listcount(es
->es_vtep_list
)) {
3200 json_vteps
= json_object_new_array();
3201 zebra_evpn_es_json_vtep_fill(es
, json_vteps
);
3202 json_object_object_add(json
, "vteps", json_vteps
);
3206 if (es
->flags
& ZEBRA_EVPNES_LOCAL
)
3207 strlcat(type_str
, "Local", sizeof(type_str
));
3208 if (es
->flags
& ZEBRA_EVPNES_REMOTE
) {
3209 if (strnlen(type_str
, sizeof(type_str
)))
3210 strlcat(type_str
, ",", sizeof(type_str
));
3211 strlcat(type_str
, "Remote", sizeof(type_str
));
3214 vty_out(vty
, "ESI: %s\n", es
->esi_str
);
3215 vty_out(vty
, " Type: %s\n", type_str
);
3216 vty_out(vty
, " Interface: %s\n",
3218 es
->zif
->ifp
->name
: "-");
3219 if (es
->flags
& ZEBRA_EVPNES_LOCAL
) {
3220 vty_out(vty
, " State: %s\n",
3221 (es
->flags
& ZEBRA_EVPNES_OPER_UP
) ? "up"
3223 vty_out(vty
, " Bridge port: %s\n",
3224 (es
->flags
& ZEBRA_EVPNES_BR_PORT
) ? "yes"
3227 vty_out(vty
, " Ready for BGP: %s\n",
3228 (es
->flags
& ZEBRA_EVPNES_READY_FOR_BGP
) ?
3230 if (es
->flags
& ZEBRA_EVPNES_BYPASS
)
3231 vty_out(vty
, " LACP bypass: on\n");
3232 vty_out(vty
, " VNI Count: %d\n", listcount(es
->es_evi_list
));
3233 vty_out(vty
, " MAC Count: %d\n", listcount(es
->mac_list
));
3234 if (es
->flags
& ZEBRA_EVPNES_LOCAL
)
3235 vty_out(vty
, " DF status: %s \n",
3236 (es
->flags
& ZEBRA_EVPNES_NON_DF
) ? "non-df"
3238 if (es
->df_delay_timer
)
3239 vty_out(vty
, " DF delay: %s\n",
3240 thread_timer_to_hhmmss(thread_buf
,
3242 es
->df_delay_timer
));
3243 vty_out(vty
, " DF preference: %u\n", es
->df_pref
);
3244 vty_out(vty
, " Nexthop group: %u\n", es
->nhg_id
);
3245 vty_out(vty
, " VTEPs:\n");
3246 for (ALL_LIST_ELEMENTS_RO(es
->es_vtep_list
, node
, es_vtep
)) {
3247 vty_out(vty
, " %pI4",
3249 if (es_vtep
->flags
& ZEBRA_EVPNES_VTEP_RXED_ESR
)
3250 vty_out(vty
, " df_alg: %s df_pref: %d",
3251 evpn_es_df_alg2str(es_vtep
->df_alg
,
3255 vty_out(vty
, " nh: %u\n",
3256 es_vtep
->nh
? es_vtep
->nh
->nh_id
: 0);
3263 void zebra_evpn_es_show(struct vty
*vty
, bool uj
)
3265 struct zebra_evpn_es
*es
;
3266 json_object
*json_array
= NULL
;
3269 json_array
= json_object_new_array();
3271 vty_out(vty
, "Type: B bypass, L local, R remote, N non-DF\n");
3272 vty_out(vty
, "%-30s %-4s %-21s %s\n",
3273 "ESI", "Type", "ES-IF", "VTEPs");
3276 RB_FOREACH(es
, zebra_es_rb_head
, &zmh_info
->es_rb_tree
)
3277 zebra_evpn_es_show_entry(vty
, es
, json_array
);
3280 vty_json(vty
, json_array
);
3283 void zebra_evpn_es_show_detail(struct vty
*vty
, bool uj
)
3285 struct zebra_evpn_es
*es
;
3286 json_object
*json_array
= NULL
;
3289 json_array
= json_object_new_array();
3291 RB_FOREACH (es
, zebra_es_rb_head
, &zmh_info
->es_rb_tree
) {
3292 json_object
*json
= NULL
;
3295 json
= json_object_new_object();
3296 zebra_evpn_es_show_entry_detail(vty
, es
, json
);
3298 json_object_array_add(json_array
, json
);
3302 vty_json(vty
, json_array
);
3305 void zebra_evpn_es_show_esi(struct vty
*vty
, bool uj
, esi_t
*esi
)
3307 struct zebra_evpn_es
*es
;
3308 char esi_str
[ESI_STR_LEN
];
3309 json_object
*json
= NULL
;
3312 json
= json_object_new_object();
3314 es
= zebra_evpn_es_find(esi
);
3317 zebra_evpn_es_show_entry_detail(vty
, es
, json
);
3320 esi_to_str(esi
, esi_str
, sizeof(esi_str
));
3321 vty_out(vty
, "ESI %s does not exist\n", esi_str
);
3326 vty_json(vty
, json
);
3329 int zebra_evpn_mh_if_write(struct vty
*vty
, struct interface
*ifp
)
3331 struct zebra_if
*zif
= ifp
->info
;
3332 char buf
[ETHER_ADDR_STRLEN
];
3333 bool type_3_esi
= false;
3334 char esi_buf
[ESI_STR_LEN
];
3336 if (zif
->es_info
.lid
) {
3337 vty_out(vty
, " evpn mh es-id %u\n", zif
->es_info
.lid
);
3341 if (!is_zero_mac(&zif
->es_info
.sysmac
)) {
3342 vty_out(vty
, " evpn mh es-sys-mac %s\n",
3343 prefix_mac2str(&zif
->es_info
.sysmac
,
3349 && memcmp(&zif
->es_info
.esi
, zero_esi
, sizeof(*zero_esi
)))
3350 vty_out(vty
, " evpn mh es-id %s\n",
3351 esi_to_str(&zif
->es_info
.esi
, esi_buf
, sizeof(esi_buf
)));
3353 if (zif
->es_info
.df_pref
)
3354 vty_out(vty
, " evpn mh es-df-pref %u\n", zif
->es_info
.df_pref
);
3356 if (zif
->flags
& ZIF_FLAG_EVPN_MH_UPLINK
)
3357 vty_out(vty
, " evpn mh uplink\n");
3362 #include "zebra/zebra_evpn_mh_clippy.c"
3363 /* CLI for setting an ES in bypass mode */
3364 DEFPY_HIDDEN(zebra_evpn_es_bypass
, zebra_evpn_es_bypass_cmd
,
3365 "[no] evpn mh bypass",
3366 NO_STR
"EVPN\n" EVPN_MH_VTY_STR
"set bypass mode\n")
3368 VTY_DECLVAR_CONTEXT(interface
, ifp
);
3369 struct zebra_if
*zif
;
3374 zebra_evpn_es_bypass_cfg_update(zif
, false);
3376 if (!zebra_evpn_is_if_es_capable(zif
)) {
3378 "%% DF bypass cannot be associated with this interface type\n");
3381 zebra_evpn_es_bypass_cfg_update(zif
, true);
3386 /* CLI for configuring DF preference part for an ES */
3387 DEFPY(zebra_evpn_es_pref
, zebra_evpn_es_pref_cmd
,
3388 "[no$no] evpn mh es-df-pref [(1-65535)$df_pref]",
3389 NO_STR
"EVPN\n" EVPN_MH_VTY_STR
3390 "preference value used for DF election\n"
3393 VTY_DECLVAR_CONTEXT(interface
, ifp
);
3394 struct zebra_if
*zif
;
3399 zebra_evpn_es_df_pref_update(zif
, 0);
3401 if (!zebra_evpn_is_if_es_capable(zif
)) {
3403 "%% DF preference cannot be associated with this interface type\n");
3406 zebra_evpn_es_df_pref_update(zif
, df_pref
);
3411 /* CLI for setting up sysmac part of ESI on an access port */
3412 DEFPY(zebra_evpn_es_sys_mac
,
3413 zebra_evpn_es_sys_mac_cmd
,
3414 "[no$no] evpn mh es-sys-mac [X:X:X:X:X:X$mac]",
3418 "Ethernet segment system MAC\n"
3422 VTY_DECLVAR_CONTEXT(interface
, ifp
);
3423 struct zebra_if
*zif
;
3429 static struct ethaddr zero_mac
;
3431 ret
= zebra_evpn_es_sys_mac_update(zif
, &zero_mac
);
3433 vty_out(vty
, "%% Failed to clear ES sysmac\n");
3438 if (!zebra_evpn_is_if_es_capable(zif
)) {
3440 "%% ESI cannot be associated with this interface type\n");
3444 if (!mac
|| is_zero_mac(&mac
->eth_addr
)) {
3445 vty_out(vty
, "%% ES sysmac value is invalid\n");
3449 ret
= zebra_evpn_es_sys_mac_update(zif
, &mac
->eth_addr
);
3452 "%% ESI already exists on a different interface\n");
3459 /* CLI for setting up local-ID part of ESI on an access port */
3460 DEFPY(zebra_evpn_es_id
,
3461 zebra_evpn_es_id_cmd
,
3462 "[no$no] evpn mh es-id [(1-16777215)$es_lid | NAME$esi_str]",
3466 "Ethernet segment identifier\n"
3467 "local discriminator\n"
3468 "10-byte ID - 00:AA:BB:CC:DD:EE:FF:GG:HH:II\n"
3471 VTY_DECLVAR_CONTEXT(interface
, ifp
);
3472 struct zebra_if
*zif
;
3479 if (zif
->es_info
.lid
)
3480 ret
= zebra_evpn_es_lid_update(zif
, 0);
3481 else if (memcmp(&zif
->es_info
.esi
, zero_esi
, sizeof(*zero_esi
)))
3482 ret
= zebra_evpn_es_type0_esi_update(zif
, zero_esi
);
3486 "%% Failed to clear ES local id or ESI name\n");
3490 if (!zebra_evpn_is_if_es_capable(zif
)) {
3492 "%% ESI cannot be associated with this interface type\n");
3497 if (!str_to_esi(esi_str
, &esi
)) {
3498 vty_out(vty
, "%% Malformed ESI name\n");
3501 ret
= zebra_evpn_es_type0_esi_update(zif
, &esi
);
3505 "%% Specify ES local id or ESI name\n");
3508 ret
= zebra_evpn_es_lid_update(zif
, es_lid
);
3513 "%% ESI already exists on a different interface\n");
3520 /* CLI for tagging an interface as an uplink */
3521 DEFPY(zebra_evpn_mh_uplink
, zebra_evpn_mh_uplink_cmd
, "[no] evpn mh uplink",
3522 NO_STR
"EVPN\n" EVPN_MH_VTY_STR
"uplink to the VxLAN core\n")
3524 VTY_DECLVAR_CONTEXT(interface
, ifp
);
3525 struct zebra_if
*zif
;
3528 zebra_evpn_mh_uplink_cfg_update(zif
, no
? false : true);
3533 void zebra_evpn_mh_json(json_object
*json
)
3535 json_object
*json_array
;
3536 char thread_buf
[THREAD_TIMER_STRLEN
];
3538 json_object_int_add(json
, "macHoldtime", zmh_info
->mac_hold_time
);
3539 json_object_int_add(json
, "neighHoldtime", zmh_info
->neigh_hold_time
);
3540 json_object_int_add(json
, "startupDelay", zmh_info
->startup_delay_time
);
3541 json_object_string_add(
3542 json
, "startupDelayTimer",
3543 thread_timer_to_hhmmss(thread_buf
, sizeof(thread_buf
),
3544 zmh_info
->startup_delay_timer
));
3545 json_object_int_add(json
, "uplinkConfigCount",
3546 zmh_info
->uplink_cfg_cnt
);
3547 json_object_int_add(json
, "uplinkActiveCount",
3548 zmh_info
->uplink_oper_up_cnt
);
3550 if (zmh_info
->protodown_rc
) {
3551 json_array
= json_object_new_array();
3552 if (CHECK_FLAG(zmh_info
->protodown_rc
,
3553 ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY
))
3554 json_object_array_add(
3556 json_object_new_string("startupDelay"));
3557 if (CHECK_FLAG(zmh_info
->protodown_rc
,
3558 ZEBRA_PROTODOWN_EVPN_UPLINK_DOWN
))
3559 json_object_array_add(
3561 json_object_new_string("uplinkDown"));
3562 json_object_object_add(json
, "protodownReasons", json_array
);
3566 void zebra_evpn_mh_print(struct vty
*vty
)
3568 char pd_buf
[ZEBRA_PROTODOWN_RC_STR_LEN
];
3569 char thread_buf
[THREAD_TIMER_STRLEN
];
3571 vty_out(vty
, "EVPN MH:\n");
3572 vty_out(vty
, " mac-holdtime: %ds, neigh-holdtime: %ds\n",
3573 zmh_info
->mac_hold_time
, zmh_info
->neigh_hold_time
);
3574 vty_out(vty
, " startup-delay: %ds, start-delay-timer: %s\n",
3575 zmh_info
->startup_delay_time
,
3576 thread_timer_to_hhmmss(thread_buf
, sizeof(thread_buf
),
3577 zmh_info
->startup_delay_timer
));
3578 vty_out(vty
, " uplink-cfg-cnt: %u, uplink-active-cnt: %u\n",
3579 zmh_info
->uplink_cfg_cnt
, zmh_info
->uplink_oper_up_cnt
);
3580 if (zmh_info
->protodown_rc
)
3581 vty_out(vty
, " protodown reasons: %s\n",
3582 zebra_protodown_rc_str(zmh_info
->protodown_rc
, pd_buf
,
3586 /*****************************************************************************/
3587 /* A base L2-VNI is maintained to derive parameters such as ES originator-IP.
3588 * XXX: once single vxlan device model becomes available this will not be
3591 /* called when a new vni is added or becomes oper up or becomes a bridge port */
3592 void zebra_evpn_es_set_base_evpn(struct zebra_evpn
*zevpn
)
3594 struct listnode
*node
;
3595 struct zebra_evpn_es
*es
;
3597 if (zmh_info
->es_base_evpn
) {
3598 if (zmh_info
->es_base_evpn
!= zevpn
) {
3599 /* unrelated EVPN; ignore it */
3602 /* check if the local vtep-ip has changed */
3604 /* check if the EVPN can be used as base EVPN */
3605 if (!zebra_evpn_send_to_client_ok(zevpn
))
3608 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3609 zlog_debug("es base vni set to %d",
3611 zmh_info
->es_base_evpn
= zevpn
;
3614 /* update local VTEP-IP */
3615 if (zmh_info
->es_originator_ip
.s_addr
==
3616 zmh_info
->es_base_evpn
->local_vtep_ip
.s_addr
)
3619 zmh_info
->es_originator_ip
.s_addr
=
3620 zmh_info
->es_base_evpn
->local_vtep_ip
.s_addr
;
3622 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3623 zlog_debug("es originator ip set to %pI4",
3624 &zmh_info
->es_base_evpn
->local_vtep_ip
);
3626 /* if originator ip changes we need to update bgp */
3627 for (ALL_LIST_ELEMENTS_RO(zmh_info
->local_es_list
, node
, es
)) {
3628 zebra_evpn_es_run_df_election(es
, __func__
);
3630 if (es
->flags
& ZEBRA_EVPNES_READY_FOR_BGP
)
3631 zebra_evpn_es_send_add_to_client(es
);
3633 zebra_evpn_es_re_eval_send_to_client(es
,
3634 true /* es_evi_re_reval */);
3638 /* called when a vni is removed or becomes oper down or is removed from a
3641 void zebra_evpn_es_clear_base_evpn(struct zebra_evpn
*zevpn
)
3643 struct listnode
*node
;
3644 struct zebra_evpn_es
*es
;
3646 if (zmh_info
->es_base_evpn
!= zevpn
)
3649 zmh_info
->es_base_evpn
= NULL
;
3650 /* lost current base EVPN; try to find a new one */
3651 zebra_evpn_es_get_one_base_evpn();
3653 /* couldn't locate an eligible base evpn */
3654 if (!zmh_info
->es_base_evpn
&& zmh_info
->es_originator_ip
.s_addr
) {
3655 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3656 zlog_debug("es originator ip cleared");
3658 zmh_info
->es_originator_ip
.s_addr
= 0;
3659 /* lost originator ip */
3660 for (ALL_LIST_ELEMENTS_RO(zmh_info
->local_es_list
, node
, es
)) {
3661 zebra_evpn_es_re_eval_send_to_client(es
,
3662 true /* es_evi_re_reval */);
3667 /* Locate an "eligible" L2-VNI to follow */
3668 static int zebra_evpn_es_get_one_base_evpn_cb(struct hash_bucket
*b
, void *data
)
3670 struct zebra_evpn
*zevpn
= b
->data
;
3672 zebra_evpn_es_set_base_evpn(zevpn
);
3674 if (zmh_info
->es_base_evpn
)
3675 return HASHWALK_ABORT
;
3677 return HASHWALK_CONTINUE
;
3680 /* locate a base_evpn to follow for the purposes of common params like
3683 static void zebra_evpn_es_get_one_base_evpn(void)
3685 struct zebra_vrf
*zvrf
;
3687 zvrf
= zebra_vrf_get_evpn();
3688 hash_walk(zvrf
->evpn_table
, zebra_evpn_es_get_one_base_evpn_cb
, NULL
);
3691 /*****************************************************************************
3692 * local ethernet segments can be error-disabled if the switch is not
3693 * ready to start transmitting traffic via the VxLAN overlay
3695 bool zebra_evpn_is_es_bond(struct interface
*ifp
)
3697 struct zebra_if
*zif
= ifp
->info
;
3699 return !!(struct zebra_if
*)zif
->es_info
.es
;
3702 bool zebra_evpn_is_es_bond_member(struct interface
*ifp
)
3704 struct zebra_if
*zif
= ifp
->info
;
3706 return IS_ZEBRA_IF_BOND_SLAVE(zif
->ifp
) && zif
->bondslave_info
.bond_if
3707 && ((struct zebra_if
*)zif
->bondslave_info
.bond_if
->info
)
3711 void zebra_evpn_mh_update_protodown_bond_mbr(struct zebra_if
*zif
, bool clear
,
3715 uint32_t old_protodown_rc
= 0;
3716 uint32_t new_protodown_rc
= 0;
3717 uint32_t protodown_rc
= 0;
3720 struct zebra_if
*bond_zif
;
3722 bond_zif
= zif
->bondslave_info
.bond_if
->info
;
3723 protodown_rc
= bond_zif
->protodown_rc
;
3726 old_protodown_rc
= zif
->protodown_rc
;
3727 new_protodown_rc
= (old_protodown_rc
& ~ZEBRA_PROTODOWN_EVPN_ALL
);
3728 new_protodown_rc
|= (protodown_rc
& ZEBRA_PROTODOWN_EVPN_ALL
);
3729 new_protodown
= !!new_protodown_rc
;
3731 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
&& (new_protodown_rc
!= old_protodown_rc
))
3733 "%s bond mbr %s protodown_rc changed; old 0x%x new 0x%x",
3734 caller
, zif
->ifp
->name
, old_protodown_rc
,
3737 if (zebra_if_update_protodown_rc(zif
->ifp
, new_protodown
,
3738 new_protodown_rc
) == 0) {
3739 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3740 zlog_debug("%s protodown %s", zif
->ifp
->name
,
3741 new_protodown
? "on" : "off");
3745 /* The bond members inherit the protodown reason code from the bond */
3746 static void zebra_evpn_mh_update_protodown_bond(struct zebra_if
*bond_zif
)
3748 struct zebra_if
*zif
;
3749 struct listnode
*node
;
3751 if (!bond_zif
->bond_info
.mbr_zifs
)
3754 for (ALL_LIST_ELEMENTS_RO(bond_zif
->bond_info
.mbr_zifs
, node
, zif
)) {
3755 zebra_evpn_mh_update_protodown_bond_mbr(zif
, false /*clear*/,
3760 /* The global EVPN MH protodown rc is applied to all local ESs */
3761 static void zebra_evpn_mh_update_protodown_es(struct zebra_evpn_es
*es
,
3764 struct zebra_if
*zif
;
3765 uint32_t old_protodown_rc
;
3768 /* if the reason code is the same bail unless it is a new
3769 * ES bond in that case we would need to ensure that the
3770 * dplane is really in sync with zebra
3773 && (zif
->protodown_rc
& ZEBRA_PROTODOWN_EVPN_ALL
)
3774 == (zmh_info
->protodown_rc
& ZEBRA_PROTODOWN_EVPN_ALL
))
3777 old_protodown_rc
= zif
->protodown_rc
;
3778 zif
->protodown_rc
&= ~ZEBRA_PROTODOWN_EVPN_ALL
;
3779 zif
->protodown_rc
|=
3780 (zmh_info
->protodown_rc
& ZEBRA_PROTODOWN_EVPN_ALL
);
3782 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
3783 && (old_protodown_rc
!= zif
->protodown_rc
))
3785 "es %s ifp %s protodown_rc changed; old 0x%x new 0x%x",
3786 es
->esi_str
, zif
->ifp
->name
, old_protodown_rc
,
3789 /* update dataplane with the new protodown setting */
3790 zebra_evpn_mh_update_protodown_bond(zif
);
3793 static void zebra_evpn_mh_clear_protodown_es(struct zebra_evpn_es
*es
)
3795 struct zebra_if
*zif
;
3796 uint32_t old_protodown_rc
;
3799 if (!(zif
->protodown_rc
& ZEBRA_PROTODOWN_EVPN_ALL
))
3802 old_protodown_rc
= zif
->protodown_rc
;
3803 zif
->protodown_rc
&= ~ZEBRA_PROTODOWN_EVPN_ALL
;
3805 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3807 "clear: es %s ifp %s protodown_rc cleared; old 0x%x new 0x%x",
3808 es
->esi_str
, zif
->ifp
->name
, old_protodown_rc
,
3811 /* update dataplane with the new protodown setting */
3812 zebra_evpn_mh_update_protodown_bond(zif
);
3815 static void zebra_evpn_mh_update_protodown_es_all(void)
3817 struct listnode
*node
;
3818 struct zebra_evpn_es
*es
;
3820 for (ALL_LIST_ELEMENTS_RO(zmh_info
->local_es_list
, node
, es
))
3821 zebra_evpn_mh_update_protodown_es(es
, false /*resync_dplane*/);
3824 static void zebra_evpn_mh_update_protodown(uint32_t protodown_rc
, bool set
)
3826 uint32_t old_protodown_rc
= zmh_info
->protodown_rc
;
3829 if ((protodown_rc
& zmh_info
->protodown_rc
) == protodown_rc
)
3832 zmh_info
->protodown_rc
|= protodown_rc
;
3834 if (!(protodown_rc
& zmh_info
->protodown_rc
))
3836 zmh_info
->protodown_rc
&= ~protodown_rc
;
3839 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3840 zlog_debug("mh protodown_rc changed; old 0x%x new 0x%x",
3841 old_protodown_rc
, zmh_info
->protodown_rc
);
3842 zebra_evpn_mh_update_protodown_es_all();
3845 static inline bool zebra_evpn_mh_is_all_uplinks_down(void)
3847 return zmh_info
->uplink_cfg_cnt
&& !zmh_info
->uplink_oper_up_cnt
;
3850 static void zebra_evpn_mh_uplink_oper_flags_update(struct zebra_if
*zif
,
3853 if (set
&& if_is_operative(zif
->ifp
)) {
3854 if (!(zif
->flags
& ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP
)) {
3855 zif
->flags
|= ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP
;
3856 ++zmh_info
->uplink_oper_up_cnt
;
3859 if (zif
->flags
& ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP
) {
3860 zif
->flags
&= ~ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP
;
3861 if (zmh_info
->uplink_oper_up_cnt
)
3862 --zmh_info
->uplink_oper_up_cnt
;
3867 static void zebra_evpn_mh_uplink_cfg_update(struct zebra_if
*zif
, bool set
)
3869 bool old_protodown
= zebra_evpn_mh_is_all_uplinks_down();
3873 if (zif
->flags
& ZIF_FLAG_EVPN_MH_UPLINK
)
3876 zif
->flags
|= ZIF_FLAG_EVPN_MH_UPLINK
;
3877 ++zmh_info
->uplink_cfg_cnt
;
3879 if (!(zif
->flags
& ZIF_FLAG_EVPN_MH_UPLINK
))
3882 zif
->flags
&= ~ZIF_FLAG_EVPN_MH_UPLINK
;
3883 if (zmh_info
->uplink_cfg_cnt
)
3884 --zmh_info
->uplink_cfg_cnt
;
3887 zebra_evpn_mh_uplink_oper_flags_update(zif
, set
);
3888 new_protodown
= zebra_evpn_mh_is_all_uplinks_down();
3889 if (old_protodown
== new_protodown
)
3892 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3894 "mh-uplink-cfg-chg on if %s/%d %s uplinks cfg %u up %u",
3895 zif
->ifp
->name
, zif
->ifp
->ifindex
, set
? "set" : "down",
3896 zmh_info
->uplink_cfg_cnt
, zmh_info
->uplink_oper_up_cnt
);
3898 zebra_evpn_mh_update_protodown(ZEBRA_PROTODOWN_EVPN_UPLINK_DOWN
,
3902 void zebra_evpn_mh_uplink_oper_update(struct zebra_if
*zif
)
3904 bool old_protodown
= zebra_evpn_mh_is_all_uplinks_down();
3907 zebra_evpn_mh_uplink_oper_flags_update(zif
, true /*set*/);
3909 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3911 "mh-uplink-oper-chg on if %s/%d %s; uplinks cfg %u up %u",
3912 zif
->ifp
->name
, zif
->ifp
->ifindex
,
3913 if_is_operative(zif
->ifp
) ? "up" : "down",
3914 zmh_info
->uplink_cfg_cnt
, zmh_info
->uplink_oper_up_cnt
);
3916 new_protodown
= zebra_evpn_mh_is_all_uplinks_down();
3917 if (old_protodown
== new_protodown
)
3920 /* if protodown_rc XXX_UPLINK_DOWN is about to be cleared
3921 * fire up the start-up delay timer to allow the EVPN network
3922 * to converge (Type-2 routes need to be advertised and processed)
3924 if (!new_protodown
&& (zmh_info
->uplink_oper_up_cnt
== 1))
3925 zebra_evpn_mh_startup_delay_timer_start("uplink-up");
3927 zebra_evpn_mh_update_protodown(ZEBRA_PROTODOWN_EVPN_UPLINK_DOWN
,
3931 static void zebra_evpn_mh_startup_delay_exp_cb(struct thread
*t
)
3933 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3934 zlog_debug("startup-delay expired");
3936 zebra_evpn_mh_update_protodown(ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY
,
3940 static void zebra_evpn_mh_startup_delay_timer_start(const char *rc
)
3942 if (zmh_info
->startup_delay_timer
) {
3943 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3944 zlog_debug("startup-delay timer cancelled");
3945 THREAD_OFF(zmh_info
->startup_delay_timer
);
3948 if (zmh_info
->startup_delay_time
) {
3949 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
3951 "startup-delay timer started for %d sec on %s",
3952 zmh_info
->startup_delay_time
, rc
);
3953 thread_add_timer(zrouter
.master
,
3954 zebra_evpn_mh_startup_delay_exp_cb
, NULL
,
3955 zmh_info
->startup_delay_time
,
3956 &zmh_info
->startup_delay_timer
);
3957 zebra_evpn_mh_update_protodown(
3958 ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY
, true /* set */);
3960 zebra_evpn_mh_update_protodown(
3961 ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY
, false /* set */);
3965 /*****************************************************************************
3966 * Nexthop management: nexthops associated with Type-2 routes that have
3967 * an ES as destination are consolidated by BGP into a per-VRF nh->rmac
3968 * mapping which is the installed as a remote neigh/fdb entry with a
3969 * dummy (type-1) prefix referencing it.
3970 * This handling is needed because Type-2 routes with ES as dest use NHG
3971 * that are setup using EAD routes (i.e. such NHGs do not include the
3973 ****************************************************************************/
3974 void zebra_evpn_proc_remote_nh(ZAPI_HANDLER_ARGS
)
3979 struct ethaddr rmac
;
3980 struct prefix_evpn dummy_prefix
;
3981 size_t min_len
= 4 + sizeof(nh
);
3986 * Ensure that the stream sent to us is long enough
3988 if (hdr
->command
== ZEBRA_EVPN_REMOTE_NH_ADD
)
3989 min_len
+= sizeof(rmac
);
3990 if (hdr
->length
< min_len
)
3993 vrf_id
= stream_getl(s
);
3994 stream_get(&nh
, s
, sizeof(nh
));
3996 memset(&dummy_prefix
, 0, sizeof(dummy_prefix
));
3997 dummy_prefix
.family
= AF_EVPN
;
3998 dummy_prefix
.prefixlen
= (sizeof(struct evpn_addr
) * 8);
3999 dummy_prefix
.prefix
.route_type
= 1; /* XXX - fixup to type-1 def */
4000 dummy_prefix
.prefix
.ead_addr
.ip
.ipa_type
= nh
.ipa_type
;
4002 if (hdr
->command
== ZEBRA_EVPN_REMOTE_NH_ADD
) {
4003 stream_get(&rmac
, s
, sizeof(rmac
));
4004 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
4006 "evpn remote nh %d %pIA rmac %pEA add pfx %pFX",
4007 vrf_id
, &nh
, &rmac
, &dummy_prefix
);
4008 zebra_rib_queue_evpn_route_add(vrf_id
, &rmac
, &nh
,
4009 (struct prefix
*)&dummy_prefix
);
4011 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
4012 zlog_debug("evpn remote nh %d %pIA del pfx %pFX",
4013 vrf_id
, &nh
, &dummy_prefix
);
4014 zebra_rib_queue_evpn_route_del(vrf_id
, &nh
,
4015 (struct prefix
*)&dummy_prefix
);
4019 /*****************************************************************************/
4020 void zebra_evpn_mh_config_write(struct vty
*vty
)
4022 if (zmh_info
->mac_hold_time
!= ZEBRA_EVPN_MH_MAC_HOLD_TIME_DEF
)
4023 vty_out(vty
, "evpn mh mac-holdtime %d\n",
4024 zmh_info
->mac_hold_time
);
4026 if (zmh_info
->neigh_hold_time
!= ZEBRA_EVPN_MH_NEIGH_HOLD_TIME_DEF
)
4027 vty_out(vty
, "evpn mh neigh-holdtime %d\n",
4028 zmh_info
->neigh_hold_time
);
4030 if (zmh_info
->startup_delay_time
!= ZEBRA_EVPN_MH_STARTUP_DELAY_DEF
)
4031 vty_out(vty
, "evpn mh startup-delay %d\n",
4032 zmh_info
->startup_delay_time
);
4034 if (zmh_info
->flags
& ZEBRA_EVPN_MH_REDIRECT_OFF
)
4035 vty_out(vty
, "evpn mh redirect-off\n");
4038 int zebra_evpn_mh_neigh_holdtime_update(struct vty
*vty
,
4039 uint32_t duration
, bool set_default
)
4042 duration
= ZEBRA_EVPN_MH_NEIGH_HOLD_TIME_DEF
;
4044 zmh_info
->neigh_hold_time
= duration
;
4049 int zebra_evpn_mh_mac_holdtime_update(struct vty
*vty
,
4050 uint32_t duration
, bool set_default
)
4053 duration
= ZEBRA_EVPN_MH_MAC_HOLD_TIME_DEF
;
4055 zmh_info
->mac_hold_time
= duration
;
4060 int zebra_evpn_mh_startup_delay_update(struct vty
*vty
, uint32_t duration
,
4064 duration
= ZEBRA_EVPN_MH_STARTUP_DELAY_DEF
;
4066 zmh_info
->startup_delay_time
= duration
;
4068 /* if startup_delay_timer is running allow it to be adjusted
4071 if (zmh_info
->startup_delay_timer
)
4072 zebra_evpn_mh_startup_delay_timer_start("config");
4077 int zebra_evpn_mh_redirect_off(struct vty
*vty
, bool redirect_off
)
4079 /* This knob needs to be set before ESs are configured
4080 * i.e. cannot be changed on the fly
4083 zmh_info
->flags
|= ZEBRA_EVPN_MH_REDIRECT_OFF
;
4085 zmh_info
->flags
&= ~ZEBRA_EVPN_MH_REDIRECT_OFF
;
4090 void zebra_evpn_interface_init(void)
4092 install_element(INTERFACE_NODE
, &zebra_evpn_es_id_cmd
);
4093 install_element(INTERFACE_NODE
, &zebra_evpn_es_sys_mac_cmd
);
4094 install_element(INTERFACE_NODE
, &zebra_evpn_es_pref_cmd
);
4095 install_element(INTERFACE_NODE
, &zebra_evpn_es_bypass_cmd
);
4096 install_element(INTERFACE_NODE
, &zebra_evpn_mh_uplink_cmd
);
4099 void zebra_evpn_mh_init(void)
4101 zrouter
.mh_info
= XCALLOC(MTYPE_ZMH_INFO
, sizeof(*zrouter
.mh_info
));
4103 zmh_info
->mac_hold_time
= ZEBRA_EVPN_MH_MAC_HOLD_TIME_DEF
;
4104 zmh_info
->neigh_hold_time
= ZEBRA_EVPN_MH_NEIGH_HOLD_TIME_DEF
;
4105 /* setup ES tables */
4106 RB_INIT(zebra_es_rb_head
, &zmh_info
->es_rb_tree
);
4107 zmh_info
->local_es_list
= list_new();
4108 listset_app_node_mem(zmh_info
->local_es_list
);
4110 bf_init(zmh_info
->nh_id_bitmap
, EVPN_NH_ID_MAX
);
4111 bf_assign_zero_index(zmh_info
->nh_id_bitmap
);
4112 zmh_info
->nhg_table
= hash_create(zebra_evpn_nhg_hash_keymake
,
4113 zebra_evpn_nhg_cmp
, "l2 NHG table");
4114 zmh_info
->nh_ip_table
=
4115 hash_create(zebra_evpn_nh_ip_hash_keymake
, zebra_evpn_nh_ip_cmp
,
4118 /* setup broadcast domain tables */
4119 zmh_info
->evpn_vlan_table
= hash_create(zebra_evpn_acc_vl_hash_keymake
,
4120 zebra_evpn_acc_vl_cmp
, "access VLAN hash table");
4122 zmh_info
->startup_delay_time
= ZEBRA_EVPN_MH_STARTUP_DELAY_DEF
;
4123 zebra_evpn_mh_startup_delay_timer_start("init");
4126 void zebra_evpn_mh_terminate(void)
4128 list_delete(&zmh_info
->local_es_list
);
4130 hash_iterate(zmh_info
->evpn_vlan_table
,
4131 zebra_evpn_acc_vl_cleanup_all
, NULL
);
4132 hash_free(zmh_info
->evpn_vlan_table
);
4133 hash_free(zmh_info
->nhg_table
);
4134 hash_free(zmh_info
->nh_ip_table
);
4135 bf_free(zmh_info
->nh_id_bitmap
);
4137 XFREE(MTYPE_ZMH_INFO
, zrouter
.mh_info
);