]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_evpn_mh.c
Merge pull request #7879 from AnuradhaKaruppiah/advertise-svi-mac
[mirror_frr.git] / zebra / zebra_evpn_mh.c
CommitLineData
ce5160c0
AK
1/*
2 * Zebra EVPN multihoming code
3 *
4 * Copyright (C) 2019 Cumulus Networks, Inc.
5 * Anuradha Karuppiah
6 *
7 * This file is part of FRR.
8 *
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
12 * later version.
13 *
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.
18 */
19
20#include <zebra.h>
21
22#include "command.h"
23#include "hash.h"
24#include "if.h"
25#include "jhash.h"
26#include "linklist.h"
27#include "log.h"
28#include "memory.h"
29#include "prefix.h"
30#include "stream.h"
31#include "table.h"
32#include "vlan.h"
33#include "vxlan.h"
34
35#include "zebra/zebra_router.h"
36#include "zebra/debug.h"
37#include "zebra/interface.h"
38#include "zebra/rib.h"
39#include "zebra/rt.h"
40#include "zebra/rt_netlink.h"
c36e442c 41#include "zebra/if_netlink.h"
ce5160c0
AK
42#include "zebra/zebra_errors.h"
43#include "zebra/zebra_l2.h"
44#include "zebra/zebra_memory.h"
45#include "zebra/zebra_ns.h"
46#include "zebra/zebra_vrf.h"
47#include "zebra/zebra_vxlan.h"
b2998086
PR
48#include "zebra/zebra_evpn.h"
49#include "zebra/zebra_evpn_mac.h"
ce5160c0
AK
50#include "zebra/zebra_vxlan_private.h"
51#include "zebra/zebra_router.h"
52#include "zebra/zebra_evpn_mh.h"
53#include "zebra/zebra_nhg.h"
54
55DEFINE_MTYPE_STATIC(ZEBRA, ZACC_BD, "Access Broadcast Domain");
56DEFINE_MTYPE_STATIC(ZEBRA, ZES, "Ethernet Segment");
57DEFINE_MTYPE_STATIC(ZEBRA, ZES_EVI, "ES info per-EVI");
58DEFINE_MTYPE_STATIC(ZEBRA, ZMH_INFO, "MH global info");
59DEFINE_MTYPE_STATIC(ZEBRA, ZES_VTEP, "VTEP attached to the ES");
5de10c37 60DEFINE_MTYPE_STATIC(ZEBRA, L2_NH, "L2 nexthop");
ce5160c0 61
87d76d54 62static void zebra_evpn_es_get_one_base_evpn(void);
ce5160c0 63static int zebra_evpn_es_evi_send_to_client(struct zebra_evpn_es *es,
87d76d54 64 zebra_evpn_t *zevpn, bool add);
e378f502 65static void zebra_evpn_local_es_del(struct zebra_evpn_es **esp);
325d694b 66static int zebra_evpn_local_es_update(struct zebra_if *zif, esi_t *esi);
28e80a03
AK
67static bool zebra_evpn_es_br_port_dplane_update(struct zebra_evpn_es *es,
68 const char *caller);
c36e442c 69static void zebra_evpn_mh_uplink_cfg_update(struct zebra_if *zif, bool set);
2bcf92e1
AK
70static void zebra_evpn_mh_update_protodown_es(struct zebra_evpn_es *es,
71 bool resync_dplane);
c36e442c 72static void zebra_evpn_mh_clear_protodown_es(struct zebra_evpn_es *es);
dc261b8d 73static void zebra_evpn_mh_startup_delay_timer_start(const char *rc);
ce5160c0
AK
74
75esi_t zero_esi_buf, *zero_esi = &zero_esi_buf;
76
77/*****************************************************************************/
78/* Ethernet Segment to EVI association -
79 * 1. The ES-EVI entry is maintained as a RB tree per L2-VNI
87d76d54 80 * (zebra_evpn_t.es_evi_rb_tree).
ce5160c0
AK
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.
92 */
93
87d76d54 94/* compare ES-IDs for the ES-EVI RB tree maintained per-EVPN */
ce5160c0
AK
95static int zebra_es_evi_rb_cmp(const struct zebra_evpn_es_evi *es_evi1,
96 const struct zebra_evpn_es_evi *es_evi2)
97{
98 return memcmp(&es_evi1->es->esi, &es_evi2->es->esi, ESI_BYTES);
99}
100RB_GENERATE(zebra_es_evi_rb_head, zebra_evpn_es_evi,
101 rb_node, zebra_es_evi_rb_cmp);
102
103/* allocate a new ES-EVI and insert it into the per-L2-VNI and per-ES
104 * tables.
105 */
106static struct zebra_evpn_es_evi *zebra_evpn_es_evi_new(struct zebra_evpn_es *es,
87d76d54 107 zebra_evpn_t *zevpn)
ce5160c0
AK
108{
109 struct zebra_evpn_es_evi *es_evi;
110
111 es_evi = XCALLOC(MTYPE_ZES_EVI, sizeof(struct zebra_evpn_es_evi));
112
113 es_evi->es = es;
87d76d54 114 es_evi->zevpn = zevpn;
ce5160c0 115
87d76d54
PR
116 /* insert into the EVPN-ESI rb tree */
117 if (RB_INSERT(zebra_es_evi_rb_head, &zevpn->es_evi_rb_tree, es_evi)) {
ce5160c0
AK
118 XFREE(MTYPE_ZES_EVI, es_evi);
119 return NULL;
120 }
121
122 /* add to the ES's VNI list */
123 listnode_init(&es_evi->es_listnode, es_evi);
124 listnode_add(es->es_evi_list, &es_evi->es_listnode);
125
126 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
127 zlog_debug("es %s evi %d new",
87d76d54 128 es_evi->es->esi_str, es_evi->zevpn->vni);
ce5160c0
AK
129
130 return es_evi;
131}
132
ce5160c0
AK
133/* Evaluate if the es_evi is ready to be sent BGP -
134 * 1. If it is ready an add is sent to BGP
135 * 2. If it is not ready a del is sent (if the ES had been previously added
136 * to BGP).
137 */
138static void zebra_evpn_es_evi_re_eval_send_to_client(
139 struct zebra_evpn_es_evi *es_evi)
140{
141 bool old_ready;
142 bool new_ready;
143
144 old_ready = !!(es_evi->flags & ZEBRA_EVPNES_EVI_READY_FOR_BGP);
145
146 /* ES and L2-VNI have to be individually ready for BGP */
147 if ((es_evi->flags & ZEBRA_EVPNES_EVI_LOCAL) &&
148 (es_evi->es->flags & ZEBRA_EVPNES_READY_FOR_BGP) &&
87d76d54 149 zebra_evpn_send_to_client_ok(es_evi->zevpn))
ce5160c0
AK
150 es_evi->flags |= ZEBRA_EVPNES_EVI_READY_FOR_BGP;
151 else
152 es_evi->flags &= ~ZEBRA_EVPNES_EVI_READY_FOR_BGP;
153
154 new_ready = !!(es_evi->flags & ZEBRA_EVPNES_EVI_READY_FOR_BGP);
155
156 if (old_ready == new_ready)
157 return;
158
159 if (new_ready)
87d76d54 160 zebra_evpn_es_evi_send_to_client(es_evi->es, es_evi->zevpn,
ce5160c0
AK
161 true /* add */);
162 else
87d76d54 163 zebra_evpn_es_evi_send_to_client(es_evi->es, es_evi->zevpn,
ce5160c0
AK
164 false /* add */);
165}
166
167/* remove the ES-EVI from the per-L2-VNI and per-ES tables and free
168 * up the memory.
169 */
170static void zebra_evpn_es_evi_free(struct zebra_evpn_es_evi *es_evi)
171{
172 struct zebra_evpn_es *es = es_evi->es;
87d76d54 173 zebra_evpn_t *zevpn = es_evi->zevpn;
ce5160c0
AK
174
175 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
176 zlog_debug("es %s evi %d free",
87d76d54 177 es_evi->es->esi_str, es_evi->zevpn->vni);
ce5160c0
AK
178
179 /* remove from the ES's VNI list */
180 list_delete_node(es->es_evi_list, &es_evi->es_listnode);
181
182 /* remove from the VNI-ESI rb tree */
87d76d54 183 RB_REMOVE(zebra_es_evi_rb_head, &zevpn->es_evi_rb_tree, es_evi);
ce5160c0
AK
184
185 /* remove from the VNI-ESI rb tree */
186 XFREE(MTYPE_ZES_EVI, es_evi);
187}
188
189/* find the ES-EVI in the per-L2-VNI RB tree */
190static struct zebra_evpn_es_evi *zebra_evpn_es_evi_find(
87d76d54 191 struct zebra_evpn_es *es, zebra_evpn_t *zevpn)
ce5160c0
AK
192{
193 struct zebra_evpn_es_evi es_evi;
194
195 es_evi.es = es;
196
87d76d54 197 return RB_FIND(zebra_es_evi_rb_head, &zevpn->es_evi_rb_tree, &es_evi);
ce5160c0
AK
198}
199
200/* Tell BGP about an ES-EVI deletion and then delete it */
201static void zebra_evpn_local_es_evi_do_del(struct zebra_evpn_es_evi *es_evi)
202{
203 if (!(es_evi->flags & ZEBRA_EVPNES_EVI_LOCAL))
204 return;
205
206 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
207 zlog_debug("local es %s evi %d del",
87d76d54 208 es_evi->es->esi_str, es_evi->zevpn->vni);
ce5160c0
AK
209
210 if (es_evi->flags & ZEBRA_EVPNES_EVI_READY_FOR_BGP) {
211 /* send a del only if add was sent for it earlier */
212 zebra_evpn_es_evi_send_to_client(es_evi->es,
87d76d54 213 es_evi->zevpn, false /* add */);
ce5160c0
AK
214 }
215
87d76d54
PR
216 /* delete it from the EVPN's local list */
217 list_delete_node(es_evi->zevpn->local_es_evi_list,
ce5160c0
AK
218 &es_evi->l2vni_listnode);
219
220 es_evi->flags &= ~ZEBRA_EVPNES_EVI_LOCAL;
221 zebra_evpn_es_evi_free(es_evi);
222}
223static void zebra_evpn_local_es_evi_del(struct zebra_evpn_es *es,
87d76d54 224 zebra_evpn_t *zevpn)
ce5160c0
AK
225{
226 struct zebra_evpn_es_evi *es_evi;
227
87d76d54 228 es_evi = zebra_evpn_es_evi_find(es, zevpn);
ce5160c0
AK
229 if (es_evi)
230 zebra_evpn_local_es_evi_do_del(es_evi);
231}
232
233/* Create an ES-EVI if it doesn't already exist and tell BGP */
234static void zebra_evpn_local_es_evi_add(struct zebra_evpn_es *es,
87d76d54 235 zebra_evpn_t *zevpn)
ce5160c0
AK
236{
237 struct zebra_evpn_es_evi *es_evi;
238
87d76d54 239 es_evi = zebra_evpn_es_evi_find(es, zevpn);
ce5160c0 240 if (!es_evi) {
87d76d54 241 es_evi = zebra_evpn_es_evi_new(es, zevpn);
ce5160c0
AK
242 if (!es_evi)
243 return;
244
245 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
246 zlog_debug("local es %s evi %d add",
87d76d54 247 es_evi->es->esi_str, es_evi->zevpn->vni);
ce5160c0 248 es_evi->flags |= ZEBRA_EVPNES_EVI_LOCAL;
87d76d54 249 /* add to the EVPN's local list */
ce5160c0 250 listnode_init(&es_evi->l2vni_listnode, es_evi);
87d76d54 251 listnode_add(zevpn->local_es_evi_list, &es_evi->l2vni_listnode);
ce5160c0
AK
252
253 zebra_evpn_es_evi_re_eval_send_to_client(es_evi);
254 }
255}
256
257static void zebra_evpn_es_evi_show_entry(struct vty *vty,
acffa256
AK
258 struct zebra_evpn_es_evi *es_evi,
259 json_object *json_array)
ce5160c0
AK
260{
261 char type_str[4];
262
acffa256
AK
263 if (json_array) {
264 json_object *json;
265 json_object *json_types;
266
267 /* Separate JSON object for each es-evi entry */
268 json = json_object_new_object();
269
270 json_object_string_add(json, "esi", es_evi->es->esi_str);
271 json_object_int_add(json, "vni", es_evi->zevpn->vni);
272 if (es_evi->flags & ZEBRA_EVPNES_EVI_LOCAL) {
273 json_types = json_object_new_array();
274 if (es_evi->flags & ZEBRA_EVPNES_EVI_LOCAL)
275 json_array_string_add(json_types, "local");
276 json_object_object_add(json, "type", json_types);
277 }
278
279 /* Add es-evi entry to json array */
280 json_object_array_add(json_array, json);
ce5160c0
AK
281 } else {
282 type_str[0] = '\0';
283 if (es_evi->flags & ZEBRA_EVPNES_EVI_LOCAL)
9e0c2fd1 284 strlcat(type_str, "L", sizeof(type_str));
ce5160c0
AK
285
286 vty_out(vty, "%-8d %-30s %-4s\n",
87d76d54 287 es_evi->zevpn->vni, es_evi->es->esi_str,
ce5160c0
AK
288 type_str);
289 }
290}
291
acffa256
AK
292static void
293zebra_evpn_es_evi_show_entry_detail(struct vty *vty,
294 struct zebra_evpn_es_evi *es_evi,
295 json_object *json_array)
ce5160c0
AK
296{
297 char type_str[4];
298
acffa256
AK
299 if (json_array) {
300 json_object *json;
301 json_object *json_flags;
302
303 /* Separate JSON object for each es-evi entry */
304 json = json_object_new_object();
305
306 json_object_string_add(json, "esi", es_evi->es->esi_str);
307 json_object_int_add(json, "vni", es_evi->zevpn->vni);
308 if (es_evi->flags
309 & (ZEBRA_EVPNES_EVI_LOCAL
310 | ZEBRA_EVPNES_EVI_READY_FOR_BGP)) {
311 json_flags = json_object_new_array();
312 if (es_evi->flags & ZEBRA_EVPNES_EVI_LOCAL)
313 json_array_string_add(json_flags, "local");
314 if (es_evi->flags & ZEBRA_EVPNES_EVI_READY_FOR_BGP)
315 json_array_string_add(json_flags,
316 "readyForBgp");
317 json_object_object_add(json, "flags", json_flags);
318 }
319
320 /* Add es-evi entry to json array */
321 json_object_array_add(json_array, json);
ce5160c0
AK
322 } else {
323 type_str[0] = '\0';
324 if (es_evi->flags & ZEBRA_EVPNES_EVI_LOCAL)
9e0c2fd1 325 strlcat(type_str, "L", sizeof(type_str));
ce5160c0
AK
326
327 vty_out(vty, "VNI %d ESI: %s\n",
87d76d54 328 es_evi->zevpn->vni, es_evi->es->esi_str);
ce5160c0
AK
329 vty_out(vty, " Type: %s\n", type_str);
330 vty_out(vty, " Ready for BGP: %s\n",
331 (es_evi->flags &
332 ZEBRA_EVPNES_EVI_READY_FOR_BGP) ?
333 "yes" : "no");
334 vty_out(vty, "\n");
335 }
336}
337
87d76d54 338static void zebra_evpn_es_evi_show_one_evpn(zebra_evpn_t *zevpn,
acffa256
AK
339 struct vty *vty,
340 json_object *json_array, int detail)
ce5160c0
AK
341{
342 struct zebra_evpn_es_evi *es_evi;
343
87d76d54 344 RB_FOREACH(es_evi, zebra_es_evi_rb_head, &zevpn->es_evi_rb_tree) {
ce5160c0 345 if (detail)
acffa256
AK
346 zebra_evpn_es_evi_show_entry_detail(vty, es_evi,
347 json_array);
ce5160c0 348 else
acffa256 349 zebra_evpn_es_evi_show_entry(vty, es_evi, json_array);
ce5160c0
AK
350 }
351}
352
353struct evpn_mh_show_ctx {
354 struct vty *vty;
355 json_object *json;
356 int detail;
357};
358
87d76d54 359static void zebra_evpn_es_evi_show_one_evpn_hash_cb(struct hash_bucket *bucket,
ce5160c0
AK
360 void *ctxt)
361{
87d76d54 362 zebra_evpn_t *zevpn = (zebra_evpn_t *)bucket->data;
ce5160c0
AK
363 struct evpn_mh_show_ctx *wctx = (struct evpn_mh_show_ctx *)ctxt;
364
87d76d54 365 zebra_evpn_es_evi_show_one_evpn(zevpn, wctx->vty,
ce5160c0
AK
366 wctx->json, wctx->detail);
367}
368
369void zebra_evpn_es_evi_show(struct vty *vty, bool uj, int detail)
370{
acffa256 371 json_object *json_array = NULL;
ce5160c0
AK
372 struct zebra_vrf *zvrf;
373 struct evpn_mh_show_ctx wctx;
374
375 zvrf = zebra_vrf_get_evpn();
acffa256
AK
376 if (uj)
377 json_array = json_object_new_array();
ce5160c0
AK
378
379 memset(&wctx, 0, sizeof(wctx));
380 wctx.vty = vty;
acffa256 381 wctx.json = json_array;
ce5160c0
AK
382 wctx.detail = detail;
383
acffa256 384 if (!detail && !json_array) {
ce5160c0
AK
385 vty_out(vty, "Type: L local, R remote\n");
386 vty_out(vty, "%-8s %-30s %-4s\n", "VNI", "ESI", "Type");
387 }
388 /* Display all L2-VNIs */
87d76d54 389 hash_iterate(zvrf->evpn_table, zebra_evpn_es_evi_show_one_evpn_hash_cb,
ce5160c0 390 &wctx);
acffa256
AK
391
392 if (uj) {
393 vty_out(vty, "%s\n",
394 json_object_to_json_string_ext(
395 json_array, JSON_C_TO_STRING_PRETTY));
396 json_object_free(json_array);
397 }
ce5160c0
AK
398}
399
400void zebra_evpn_es_evi_show_vni(struct vty *vty, bool uj, vni_t vni, int detail)
401{
acffa256 402 json_object *json_array = NULL;
87d76d54 403 zebra_evpn_t *zevpn;
ce5160c0 404
8b5fdf2e 405 zevpn = zebra_evpn_lookup(vni);
acffa256
AK
406 if (uj)
407 json_array = json_object_new_array();
408
87d76d54 409 if (zevpn) {
acffa256 410 if (!detail && !json_array) {
ce5160c0
AK
411 vty_out(vty, "Type: L local, R remote\n");
412 vty_out(vty, "%-8s %-30s %-4s\n", "VNI", "ESI", "Type");
413 }
362c8f2d 414 zebra_evpn_es_evi_show_one_evpn(zevpn, vty, json_array, detail);
ce5160c0
AK
415 } else {
416 if (!uj)
1718bc78 417 vty_out(vty, "VNI %d doesn't exist\n", vni);
ce5160c0 418 }
acffa256 419
acffa256
AK
420 if (uj) {
421 vty_out(vty, "%s\n",
422 json_object_to_json_string_ext(
423 json_array, JSON_C_TO_STRING_PRETTY));
424 json_object_free(json_array);
425 }
ce5160c0
AK
426}
427
428/* Initialize the ES tables maintained per-L2_VNI */
945ee7b2 429void zebra_evpn_es_evi_init(zebra_evpn_t *zevpn)
ce5160c0
AK
430{
431 /* Initialize the ES-EVI RB tree */
87d76d54 432 RB_INIT(zebra_es_evi_rb_head, &zevpn->es_evi_rb_tree);
ce5160c0
AK
433
434 /* Initialize the local and remote ES lists maintained for quick
435 * walks by type
436 */
87d76d54
PR
437 zevpn->local_es_evi_list = list_new();
438 listset_app_node_mem(zevpn->local_es_evi_list);
ce5160c0
AK
439}
440
87d76d54 441/* Cleanup the ES info maintained per- EVPN */
945ee7b2 442void zebra_evpn_es_evi_cleanup(zebra_evpn_t *zevpn)
ce5160c0
AK
443{
444 struct zebra_evpn_es_evi *es_evi;
445 struct zebra_evpn_es_evi *es_evi_next;
446
447 RB_FOREACH_SAFE(es_evi, zebra_es_evi_rb_head,
87d76d54 448 &zevpn->es_evi_rb_tree, es_evi_next) {
ce5160c0
AK
449 zebra_evpn_local_es_evi_do_del(es_evi);
450 }
451
87d76d54
PR
452 list_delete(&zevpn->local_es_evi_list);
453 zebra_evpn_es_clear_base_evpn(zevpn);
ce5160c0
AK
454}
455
456/* called when the oper state or bridge membership changes for the
457 * vxlan device
458 */
87d76d54 459void zebra_evpn_update_all_es(zebra_evpn_t *zevpn)
ce5160c0
AK
460{
461 struct zebra_evpn_es_evi *es_evi;
462 struct listnode *node;
e4c3ece6
AK
463 struct interface *vlan_if;
464 struct interface *vxlan_if;
465 struct zebra_if *vxlan_zif;
ce5160c0 466
87d76d54
PR
467 /* the EVPN is now elgible as a base for EVPN-MH */
468 if (zebra_evpn_send_to_client_ok(zevpn))
469 zebra_evpn_es_set_base_evpn(zevpn);
ce5160c0 470 else
87d76d54 471 zebra_evpn_es_clear_base_evpn(zevpn);
ce5160c0 472
87d76d54 473 for (ALL_LIST_ELEMENTS_RO(zevpn->local_es_evi_list, node, es_evi))
ce5160c0 474 zebra_evpn_es_evi_re_eval_send_to_client(es_evi);
e4c3ece6
AK
475
476 /* reinstall SVI MAC */
477 vxlan_if = zevpn->vxlan_if;
478 if (vxlan_if) {
479 vxlan_zif = vxlan_if->info;
480 if (if_is_operative(vxlan_if)
481 && vxlan_zif->brslave_info.br_if) {
482 vlan_if = zvni_map_to_svi(
483 vxlan_zif->l2info.vxl.access_vlan,
484 vxlan_zif->brslave_info.br_if);
485 if (vlan_if)
486 zebra_evpn_acc_bd_svi_mac_add(vlan_if);
487 }
488 }
ce5160c0
AK
489}
490
491/*****************************************************************************/
492/* Access broadcast domains (BD)
493 * 1. These broadcast domains can be VLAN aware (in which case
494 * the key is VID) or VLAN unaware (in which case the key is
495 * 2. A VID-BD is created when a VLAN is associated with an access port or
496 * when the VLAN is associated with VXLAN_IF
497 * 3. A BD is translated into ES-EVI entries when a VNI is associated
498 * with the broadcast domain
499 */
500/* Hash key for VLAN based broadcast domains */
501static unsigned int zebra_evpn_acc_vl_hash_keymake(const void *p)
502{
503 const struct zebra_evpn_access_bd *acc_bd = p;
504
505 return jhash_1word(acc_bd->vid, 0);
506}
507
508/* Compare two VLAN based broadcast domains */
509static bool zebra_evpn_acc_vl_cmp(const void *p1, const void *p2)
510{
511 const struct zebra_evpn_access_bd *acc_bd1 = p1;
512 const struct zebra_evpn_access_bd *acc_bd2 = p2;
513
514 if (acc_bd1 == NULL && acc_bd2 == NULL)
515 return true;
516
517 if (acc_bd1 == NULL || acc_bd2 == NULL)
518 return false;
519
520 return (acc_bd1->vid == acc_bd2->vid);
521}
522
523/* Lookup VLAN based broadcast domain */
524static struct zebra_evpn_access_bd *zebra_evpn_acc_vl_find(vlanid_t vid)
525{
526 struct zebra_evpn_access_bd *acc_bd;
527 struct zebra_evpn_access_bd tmp;
528
529 tmp.vid = vid;
530 acc_bd = hash_lookup(zmh_info->evpn_vlan_table, &tmp);
531
532 return acc_bd;
533}
534
535/* A new broadcast domain can be created when a VLAN member or VLAN<=>VxLAN_IF
536 * mapping is added.
537 */
243b74ed
AK
538static struct zebra_evpn_access_bd *
539zebra_evpn_acc_vl_new(vlanid_t vid, struct interface *br_if)
ce5160c0
AK
540{
541 struct zebra_evpn_access_bd *acc_bd;
243b74ed 542 struct interface *vlan_if;
ce5160c0
AK
543
544 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
545 zlog_debug("access vlan %d add", vid);
546
547 acc_bd = XCALLOC(MTYPE_ZACC_BD, sizeof(struct zebra_evpn_access_bd));
548
549 acc_bd->vid = vid;
550
551 /* Initialize the mbr list */
552 acc_bd->mbr_zifs = list_new();
553
554 /* Add to hash */
555 if (!hash_get(zmh_info->evpn_vlan_table, acc_bd, hash_alloc_intern)) {
556 XFREE(MTYPE_ZACC_BD, acc_bd);
557 return NULL;
558 }
559
243b74ed
AK
560 /* check if an svi exists for the vlan */
561 if (br_if) {
562 vlan_if = zvni_map_to_svi(vid, br_if);
563 if (vlan_if) {
564 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
565 zlog_debug("vlan %d SVI %s set", vid,
566 vlan_if->name);
567 acc_bd->vlan_zif = vlan_if->info;
568 }
569 }
ce5160c0
AK
570 return acc_bd;
571}
572
573/* Free VLAN based broadcast domain -
574 * This just frees appropriate memory, caller should have taken other
575 * needed actions.
576 */
577static void zebra_evpn_acc_vl_free(struct zebra_evpn_access_bd *acc_bd)
578{
579 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
580 zlog_debug("access vlan %d del", acc_bd->vid);
581
243b74ed
AK
582 if (acc_bd->vlan_zif && acc_bd->zevpn && acc_bd->zevpn->mac_table)
583 zebra_evpn_mac_svi_del(acc_bd->vlan_zif->ifp, acc_bd->zevpn);
584
ce5160c0
AK
585 /* cleanup resources maintained against the ES */
586 list_delete(&acc_bd->mbr_zifs);
587
588 /* remove EVI from various tables */
589 hash_release(zmh_info->evpn_vlan_table, acc_bd);
590
591 XFREE(MTYPE_ZACC_BD, acc_bd);
592}
593
594static void zebra_evpn_acc_vl_cleanup_all(struct hash_bucket *bucket, void *arg)
595{
596 struct zebra_evpn_access_bd *acc_bd = bucket->data;
597
598 zebra_evpn_acc_vl_free(acc_bd);
599}
600
601/* called when a bd mbr is removed or VxLAN_IF is diassociated from the access
602 * VLAN
603 */
604static void zebra_evpn_acc_bd_free_on_deref(struct zebra_evpn_access_bd *acc_bd)
605{
606 if (!list_isempty(acc_bd->mbr_zifs) || acc_bd->vxlan_zif)
607 return;
608
609 /* if there are no references free the EVI */
610 zebra_evpn_acc_vl_free(acc_bd);
611}
612
243b74ed
AK
613/* called when a SVI is goes up/down */
614void zebra_evpn_acc_bd_svi_set(struct zebra_if *vlan_zif,
615 struct zebra_if *br_zif, bool is_up)
616{
617 struct zebra_evpn_access_bd *acc_bd;
618 struct zebra_l2info_bridge *br;
619 uint16_t vid;
620 struct zebra_if *tmp_br_zif = br_zif;
621
622 if (!tmp_br_zif) {
3b63732a 623 if (!vlan_zif->link || !vlan_zif->link->info)
243b74ed
AK
624 return;
625
626 tmp_br_zif = vlan_zif->link->info;
627 }
628
629 br = &tmp_br_zif->l2info.br;
630 /* ignore vlan unaware bridges */
631 if (!br->vlan_aware)
632 return;
633
634 vid = vlan_zif->l2info.vl.vid;
635 acc_bd = zebra_evpn_acc_vl_find(vid);
636 if (!acc_bd)
637 return;
638
639 if (is_up) {
640 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
641 zlog_debug("vlan %d SVI %s set", vid,
642 vlan_zif->ifp->name);
643
644 acc_bd->vlan_zif = vlan_zif;
645 if (acc_bd->zevpn)
646 zebra_evpn_mac_svi_add(acc_bd->vlan_zif->ifp,
647 acc_bd->zevpn);
648 } else if (acc_bd->vlan_zif) {
649 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
650 zlog_debug("vlan %d SVI clear", vid);
651 acc_bd->vlan_zif = NULL;
652 if (acc_bd->zevpn && acc_bd->zevpn->mac_table)
653 zebra_evpn_mac_svi_del(vlan_zif->ifp, acc_bd->zevpn);
654 }
655}
656
657/* On some events macs are force-flushed. This api can be used to reinstate
658 * the svi-mac after such cleanup-events.
659 */
660void zebra_evpn_acc_bd_svi_mac_add(struct interface *vlan_if)
661{
662 zebra_evpn_acc_bd_svi_set(vlan_if->info, NULL,
663 if_is_operative(vlan_if));
664}
665
ce5160c0 666/* called when a EVPN-L2VNI is set or cleared against a BD */
87d76d54
PR
667static void zebra_evpn_acc_bd_evpn_set(struct zebra_evpn_access_bd *acc_bd,
668 zebra_evpn_t *zevpn, zebra_evpn_t *old_zevpn)
ce5160c0
AK
669{
670 struct zebra_if *zif;
671 struct listnode *node;
672
673 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
674 zlog_debug("access vlan %d l2-vni %u set",
87d76d54 675 acc_bd->vid, zevpn ? zevpn->vni : 0);
ce5160c0
AK
676
677 for (ALL_LIST_ELEMENTS_RO(acc_bd->mbr_zifs, node, zif)) {
678 if (!zif->es_info.es)
679 continue;
680
87d76d54
PR
681 if (zevpn)
682 zebra_evpn_local_es_evi_add(zif->es_info.es, zevpn);
683 else if (old_zevpn)
684 zebra_evpn_local_es_evi_del(zif->es_info.es, old_zevpn);
ce5160c0 685 }
243b74ed
AK
686
687 if (acc_bd->vlan_zif) {
688 if (zevpn)
689 zebra_evpn_mac_svi_add(acc_bd->vlan_zif->ifp,
690 acc_bd->zevpn);
691 else if (old_zevpn && old_zevpn->mac_table)
692 zebra_evpn_mac_svi_del(acc_bd->vlan_zif->ifp,
693 old_zevpn);
694 }
ce5160c0
AK
695}
696
697/* handle VLAN->VxLAN_IF association */
698void zebra_evpn_vl_vxl_ref(uint16_t vid, struct zebra_if *vxlan_zif)
699{
700 struct zebra_evpn_access_bd *acc_bd;
701 struct zebra_if *old_vxlan_zif;
87d76d54 702 zebra_evpn_t *old_zevpn;
ce5160c0
AK
703
704 if (!vid)
705 return;
706
707 acc_bd = zebra_evpn_acc_vl_find(vid);
708 if (!acc_bd)
243b74ed
AK
709 acc_bd = zebra_evpn_acc_vl_new(vid,
710 vxlan_zif->brslave_info.br_if);
ce5160c0
AK
711
712 old_vxlan_zif = acc_bd->vxlan_zif;
713 acc_bd->vxlan_zif = vxlan_zif;
714 if (vxlan_zif == old_vxlan_zif)
715 return;
716
87d76d54 717 old_zevpn = acc_bd->zevpn;
8b5fdf2e 718 acc_bd->zevpn = zebra_evpn_lookup(vxlan_zif->l2info.vxl.vni);
87d76d54 719 if (acc_bd->zevpn == old_zevpn)
ce5160c0
AK
720 return;
721
722 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
723 zlog_debug("access vlan %d vni %u ref",
724 acc_bd->vid, vxlan_zif->l2info.vxl.vni);
725
87d76d54
PR
726 if (old_zevpn)
727 zebra_evpn_acc_bd_evpn_set(acc_bd, NULL, old_zevpn);
ce5160c0 728
87d76d54
PR
729 if (acc_bd->zevpn)
730 zebra_evpn_acc_bd_evpn_set(acc_bd, acc_bd->zevpn, NULL);
ce5160c0
AK
731}
732
733/* handle VLAN->VxLAN_IF deref */
734void zebra_evpn_vl_vxl_deref(uint16_t vid, struct zebra_if *vxlan_zif)
735{
736 struct zebra_evpn_access_bd *acc_bd;
737
738 if (!vid)
739 return;
740
741 acc_bd = zebra_evpn_acc_vl_find(vid);
742 if (!acc_bd)
743 return;
744
745 /* clear vxlan_if only if it matches */
746 if (acc_bd->vxlan_zif != vxlan_zif)
747 return;
748
749 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
750 zlog_debug("access vlan %d vni %u deref",
751 acc_bd->vid, vxlan_zif->l2info.vxl.vni);
752
87d76d54
PR
753 if (acc_bd->zevpn)
754 zebra_evpn_acc_bd_evpn_set(acc_bd, NULL, acc_bd->zevpn);
ce5160c0 755
87d76d54 756 acc_bd->zevpn = NULL;
ce5160c0
AK
757 acc_bd->vxlan_zif = NULL;
758
759 /* if there are no other references the access_bd can be freed */
760 zebra_evpn_acc_bd_free_on_deref(acc_bd);
761}
762
87d76d54
PR
763/* handle EVPN add/del */
764void zebra_evpn_vxl_evpn_set(struct zebra_if *zif, zebra_evpn_t *zevpn,
ce5160c0
AK
765 bool set)
766{
767 struct zebra_l2info_vxlan *vxl;
768 struct zebra_evpn_access_bd *acc_bd;
769
770 if (!zif)
771 return;
772
773 /* locate access_bd associated with the vxlan device */
774 vxl = &zif->l2info.vxl;
775 acc_bd = zebra_evpn_acc_vl_find(vxl->access_vlan);
776 if (!acc_bd)
777 return;
778
779 if (set) {
87d76d54
PR
780 zebra_evpn_es_set_base_evpn(zevpn);
781 if (acc_bd->zevpn != zevpn) {
782 acc_bd->zevpn = zevpn;
783 zebra_evpn_acc_bd_evpn_set(acc_bd, zevpn, NULL);
ce5160c0
AK
784 }
785 } else {
87d76d54
PR
786 if (acc_bd->zevpn) {
787 zebra_evpn_t *old_zevpn = acc_bd->zevpn;
788 acc_bd->zevpn = NULL;
789 zebra_evpn_acc_bd_evpn_set(acc_bd, NULL, old_zevpn);
ce5160c0
AK
790 }
791 }
792}
793
794/* handle addition of new VLAN members */
795void zebra_evpn_vl_mbr_ref(uint16_t vid, struct zebra_if *zif)
796{
797 struct zebra_evpn_access_bd *acc_bd;
798
799 if (!vid)
800 return;
801
802 acc_bd = zebra_evpn_acc_vl_find(vid);
803 if (!acc_bd)
243b74ed 804 acc_bd = zebra_evpn_acc_vl_new(vid, zif->brslave_info.br_if);
ce5160c0
AK
805
806 if (listnode_lookup(acc_bd->mbr_zifs, zif))
807 return;
808
809 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
810 zlog_debug("access vlan %d mbr %s ref",
811 vid, zif->ifp->name);
812
813 listnode_add(acc_bd->mbr_zifs, zif);
87d76d54
PR
814 if (acc_bd->zevpn && zif->es_info.es)
815 zebra_evpn_local_es_evi_add(zif->es_info.es, acc_bd->zevpn);
ce5160c0
AK
816}
817
818/* handle deletion of VLAN members */
819void zebra_evpn_vl_mbr_deref(uint16_t vid, struct zebra_if *zif)
820{
821 struct zebra_evpn_access_bd *acc_bd;
822 struct listnode *node;
823
824 if (!vid)
825 return;
826
827 acc_bd = zebra_evpn_acc_vl_find(vid);
828 if (!acc_bd)
829 return;
830
831 node = listnode_lookup(acc_bd->mbr_zifs, zif);
832 if (!node)
833 return;
834
835 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
836 zlog_debug("access vlan %d mbr %s deref",
837 vid, zif->ifp->name);
838
839 list_delete_node(acc_bd->mbr_zifs, node);
840
87d76d54
PR
841 if (acc_bd->zevpn && zif->es_info.es)
842 zebra_evpn_local_es_evi_del(zif->es_info.es, acc_bd->zevpn);
ce5160c0
AK
843
844 /* if there are no other references the access_bd can be freed */
845 zebra_evpn_acc_bd_free_on_deref(acc_bd);
846}
847
243b74ed
AK
848static void zebra_evpn_acc_vl_adv_svi_mac_cb(struct hash_bucket *bucket,
849 void *ctxt)
850{
851 struct zebra_evpn_access_bd *acc_bd = bucket->data;
852
853 if (acc_bd->vlan_zif && acc_bd->zevpn)
854 zebra_evpn_mac_svi_add(acc_bd->vlan_zif->ifp, acc_bd->zevpn);
855}
856
857/* called when advertise SVI MAC is enabled on the switch */
858static void zebra_evpn_acc_vl_adv_svi_mac_all(void)
859{
860 hash_iterate(zmh_info->evpn_vlan_table,
861 zebra_evpn_acc_vl_adv_svi_mac_cb, NULL);
862}
863
acffa256
AK
864static void zebra_evpn_acc_vl_json_fill(struct zebra_evpn_access_bd *acc_bd,
865 json_object *json, bool detail)
866{
867 json_object_int_add(json, "vlan", acc_bd->vid);
868 if (acc_bd->vxlan_zif)
869 json_object_string_add(json, "vxlanIf",
870 acc_bd->vxlan_zif->ifp->name);
871 if (acc_bd->zevpn)
872 json_object_int_add(json, "vni", acc_bd->zevpn->vni);
873 if (acc_bd->mbr_zifs)
874 json_object_int_add(json, "memberIfCount",
875 listcount(acc_bd->mbr_zifs));
876
877 if (detail) {
878 json_object *json_mbrs;
879 json_object *json_mbr;
880 struct zebra_if *zif;
881 struct listnode *node;
882
883
884 json_mbrs = json_object_new_array();
885 for (ALL_LIST_ELEMENTS_RO(acc_bd->mbr_zifs, node, zif)) {
886 json_mbr = json_object_new_object();
887 json_object_string_add(json_mbr, "ifName",
888 zif->ifp->name);
889 json_object_array_add(json_mbrs, json_mbr);
890 }
891 json_object_object_add(json, "members", json_mbrs);
892 }
893}
894
ce5160c0
AK
895static void zebra_evpn_acc_vl_show_entry_detail(struct vty *vty,
896 struct zebra_evpn_access_bd *acc_bd, json_object *json)
897{
898 struct zebra_if *zif;
899 struct listnode *node;
900
901 if (json) {
acffa256 902 zebra_evpn_acc_vl_json_fill(acc_bd, json, true);
ce5160c0
AK
903 } else {
904 vty_out(vty, "VLAN: %u\n", acc_bd->vid);
905 vty_out(vty, " VxLAN Interface: %s\n",
906 acc_bd->vxlan_zif ?
907 acc_bd->vxlan_zif->ifp->name : "-");
243b74ed
AK
908 vty_out(vty, " SVI: %s\n",
909 acc_bd->vlan_zif ? acc_bd->vlan_zif->ifp->name : "-");
ce5160c0 910 vty_out(vty, " L2-VNI: %d\n",
87d76d54 911 acc_bd->zevpn ? acc_bd->zevpn->vni : 0);
ce5160c0
AK
912 vty_out(vty, " Member Count: %d\n",
913 listcount(acc_bd->mbr_zifs));
914 vty_out(vty, " Members: \n");
915 for (ALL_LIST_ELEMENTS_RO(acc_bd->mbr_zifs, node, zif))
916 vty_out(vty, " %s\n", zif->ifp->name);
917 vty_out(vty, "\n");
918 }
919}
920
921static void zebra_evpn_acc_vl_show_entry(struct vty *vty,
922 struct zebra_evpn_access_bd *acc_bd, json_object *json)
923{
acffa256
AK
924 if (json) {
925 zebra_evpn_acc_vl_json_fill(acc_bd, json, false);
926 } else {
243b74ed
AK
927 vty_out(vty, "%-5u %-15s %-8d %-15s %u\n", acc_bd->vid,
928 acc_bd->vlan_zif ? acc_bd->vlan_zif->ifp->name : "-",
929 acc_bd->zevpn ? acc_bd->zevpn->vni : 0,
930 acc_bd->vxlan_zif ? acc_bd->vxlan_zif->ifp->name : "-",
931 listcount(acc_bd->mbr_zifs));
acffa256 932 }
ce5160c0
AK
933}
934
935static void zebra_evpn_acc_vl_show_hash(struct hash_bucket *bucket, void *ctxt)
936{
937 struct evpn_mh_show_ctx *wctx = ctxt;
938 struct zebra_evpn_access_bd *acc_bd = bucket->data;
acffa256 939 json_object *json = NULL;
ce5160c0 940
acffa256
AK
941 if (wctx->json)
942 json = json_object_new_object();
ce5160c0 943 if (wctx->detail)
acffa256 944 zebra_evpn_acc_vl_show_entry_detail(wctx->vty, acc_bd, json);
ce5160c0 945 else
acffa256
AK
946 zebra_evpn_acc_vl_show_entry(wctx->vty, acc_bd, json);
947 if (json)
948 json_object_array_add(wctx->json, json);
ce5160c0
AK
949}
950
951void zebra_evpn_acc_vl_show(struct vty *vty, bool uj)
952{
ce5160c0 953 struct evpn_mh_show_ctx wctx;
acffa256
AK
954 json_object *json_array = NULL;
955
956 if (uj)
957 json_array = json_object_new_array();
ce5160c0
AK
958
959 memset(&wctx, 0, sizeof(wctx));
960 wctx.vty = vty;
acffa256 961 wctx.json = json_array;
ce5160c0
AK
962 wctx.detail = false;
963
acffa256 964 if (!uj)
243b74ed
AK
965 vty_out(vty, "%-5s %-15s %-8s %-15s %s\n", "VLAN", "SVI",
966 "L2-VNI", "VXLAN-IF", "# Members");
ce5160c0
AK
967
968 hash_iterate(zmh_info->evpn_vlan_table, zebra_evpn_acc_vl_show_hash,
969 &wctx);
acffa256
AK
970
971 if (uj) {
972 vty_out(vty, "%s\n",
973 json_object_to_json_string_ext(
974 json_array, JSON_C_TO_STRING_PRETTY));
975 json_object_free(json_array);
976 }
ce5160c0
AK
977}
978
979void zebra_evpn_acc_vl_show_detail(struct vty *vty, bool uj)
980{
ce5160c0 981 struct evpn_mh_show_ctx wctx;
acffa256 982 json_object *json_array = NULL;
ce5160c0 983
acffa256
AK
984 if (uj)
985 json_array = json_object_new_array();
ce5160c0
AK
986 memset(&wctx, 0, sizeof(wctx));
987 wctx.vty = vty;
acffa256 988 wctx.json = json_array;
ce5160c0
AK
989 wctx.detail = true;
990
991 hash_iterate(zmh_info->evpn_vlan_table, zebra_evpn_acc_vl_show_hash,
992 &wctx);
acffa256
AK
993
994 if (uj) {
995 vty_out(vty, "%s\n",
996 json_object_to_json_string_ext(
997 json_array, JSON_C_TO_STRING_PRETTY));
998 json_object_free(json_array);
999 }
ce5160c0
AK
1000}
1001
1002void zebra_evpn_acc_vl_show_vid(struct vty *vty, bool uj, vlanid_t vid)
1003{
1004 json_object *json = NULL;
1005 struct zebra_evpn_access_bd *acc_bd;
1006
acffa256
AK
1007 if (uj)
1008 json = json_object_new_object();
1009
ce5160c0 1010 acc_bd = zebra_evpn_acc_vl_find(vid);
acffa256
AK
1011 if (acc_bd) {
1012 zebra_evpn_acc_vl_show_entry_detail(vty, acc_bd, json);
1013 } else {
1014 if (!json)
ce5160c0 1015 vty_out(vty, "VLAN %u not present\n", vid);
ce5160c0 1016 }
acffa256
AK
1017
1018 if (uj) {
1019 vty_out(vty, "%s\n",
1020 json_object_to_json_string_ext(
1021 json, JSON_C_TO_STRING_PRETTY));
1022 json_object_free(json);
1023 }
ce5160c0
AK
1024}
1025
1026/* Initialize VLAN member bitmap on an interface. Although VLAN membership
1027 * is independent of EVPN we only process it if its of interest to EVPN-MH
1028 * i.e. on access ports that can be setup as Ethernet Segments. And that is
1029 * intended as an optimization.
1030 */
1031void zebra_evpn_if_init(struct zebra_if *zif)
1032{
1033 if (!zebra_evpn_is_if_es_capable(zif))
1034 return;
1035
1036 if (!bf_is_inited(zif->vlan_bitmap))
1037 bf_init(zif->vlan_bitmap, IF_VLAN_BITMAP_MAX);
1038
1039 /* if an es_id and sysmac are already present against the interface
1040 * activate it
1041 */
325d694b 1042 zebra_evpn_local_es_update(zif, &zif->es_info.esi);
ce5160c0
AK
1043}
1044
1045/* handle deletion of an access port by removing it from all associated
1046 * broadcast domains.
1047 */
1048void zebra_evpn_if_cleanup(struct zebra_if *zif)
1049{
1050 vlanid_t vid;
ab06b033 1051 struct zebra_evpn_es *es;
ce5160c0
AK
1052
1053 if (!bf_is_inited(zif->vlan_bitmap))
1054 return;
1055
1056 bf_for_each_set_bit(zif->vlan_bitmap, vid, IF_VLAN_BITMAP_MAX) {
1057 zebra_evpn_vl_mbr_deref(vid, zif);
1058 }
1059
1060 bf_free(zif->vlan_bitmap);
1061
1062 /* Delete associated Ethernet Segment */
ab06b033
AK
1063 es = zif->es_info.es;
1064 if (es)
1065 zebra_evpn_local_es_del(&es);
ce5160c0
AK
1066}
1067
1068/*****************************************************************************
1069 * L2 NH/NHG Management
1070 * A L2 NH entry is programmed in the kernel for every ES-VTEP entry. This
1071 * NH is then added to the L2-ECMP-NHG associated with the ES.
1072 */
15400f95 1073static uint32_t zebra_evpn_nhid_alloc(struct zebra_evpn_es *es)
ce5160c0
AK
1074{
1075 uint32_t id;
15400f95 1076 uint32_t nh_id;
ce5160c0
AK
1077
1078 bf_assign_index(zmh_info->nh_id_bitmap, id);
1079
1080 if (!id)
1081 return 0;
1082
15400f95
AK
1083 if (es) {
1084 nh_id = id | EVPN_NHG_ID_TYPE_BIT;
1085 /* Add to NHG hash */
1086 es->nhg_id = nh_id;
1087 if (!hash_get(zmh_info->nhg_table, es, hash_alloc_intern)) {
1088 bf_release_index(zmh_info->nh_id_bitmap, id);
1089 return 0;
1090 }
1091 } else {
1092 nh_id = id | EVPN_NH_ID_TYPE_BIT;
1093 }
1094
1095 return nh_id;
ce5160c0
AK
1096}
1097
15400f95 1098static void zebra_evpn_nhid_free(uint32_t nh_id, struct zebra_evpn_es *es)
ce5160c0
AK
1099{
1100 uint32_t id = (nh_id & EVPN_NH_ID_VAL_MASK);
1101
1102 if (!id)
1103 return;
1104
15400f95
AK
1105 if (es) {
1106 hash_release(zmh_info->nhg_table, es);
1107 es->nhg_id = 0;
1108 }
1109
ce5160c0
AK
1110 bf_release_index(zmh_info->nh_id_bitmap, id);
1111}
1112
5de10c37
AK
1113static unsigned int zebra_evpn_nh_ip_hash_keymake(const void *p)
1114{
1115 const struct zebra_evpn_l2_nh *nh = p;
1116
1117 return jhash_1word(nh->vtep_ip.s_addr, 0);
1118}
1119
1120static bool zebra_evpn_nh_ip_cmp(const void *p1, const void *p2)
1121{
1122 const struct zebra_evpn_l2_nh *nh1 = p1;
1123 const struct zebra_evpn_l2_nh *nh2 = p2;
1124
1125 if (nh1 == NULL && nh2 == NULL)
1126 return true;
1127
1128 if (nh1 == NULL || nh2 == NULL)
1129 return false;
1130
1131 return (nh1->vtep_ip.s_addr == nh2->vtep_ip.s_addr);
1132}
1133
15400f95
AK
1134static unsigned int zebra_evpn_nhg_hash_keymake(const void *p)
1135{
1136 const struct zebra_evpn_es *es = p;
1137
1138 return jhash_1word(es->nhg_id, 0);
1139}
1140
1141static bool zebra_evpn_nhg_cmp(const void *p1, const void *p2)
1142{
1143 const struct zebra_evpn_es *es1 = p1;
1144 const struct zebra_evpn_es *es2 = p2;
1145
1146 if (es1 == NULL && es2 == NULL)
1147 return true;
1148
1149 if (es1 == NULL || es2 == NULL)
1150 return false;
1151
1152 return (es1->nhg_id == es2->nhg_id);
1153}
1154
1155/* Lookup ES using the NHG id associated with it */
1156static struct zebra_evpn_es *zebra_evpn_nhg_find(uint32_t nhg_id)
1157{
1158 struct zebra_evpn_es *es;
1159 struct zebra_evpn_es tmp;
1160
1161 tmp.nhg_id = nhg_id;
1162 es = hash_lookup(zmh_info->nhg_table, &tmp);
1163
1164 return es;
1165}
1166
1167/* Returns TRUE if the NHG is associated with a local ES */
1168bool zebra_evpn_nhg_is_local_es(uint32_t nhg_id,
1169 struct zebra_evpn_es **local_es)
1170{
1171 struct zebra_evpn_es *es;
1172
1173 es = zebra_evpn_nhg_find(nhg_id);
1174 if (es && (es->flags & ZEBRA_EVPNES_LOCAL)) {
1175 *local_es = es;
1176 return true;
1177 }
1178
1179 *local_es = NULL;
1180 return false;
1181}
1182
f3722826
AK
1183/* update remote macs associated with the ES */
1184static void zebra_evpn_nhg_mac_update(struct zebra_evpn_es *es)
1185{
1186 zebra_mac_t *mac;
1187 struct listnode *node;
15400f95 1188 bool local_via_nw;
f3722826 1189
15400f95
AK
1190 local_via_nw = zebra_evpn_es_local_mac_via_network_port(es);
1191 if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_EVPN_MH_MAC)
1192 zlog_debug("mac update on es %s nhg %s", es->esi_str,
1193 (es->flags & ZEBRA_EVPNES_NHG_ACTIVE)
1194 ? "activate"
1195 : "de-activate");
f3722826 1196
15400f95
AK
1197 for (ALL_LIST_ELEMENTS_RO(es->mac_list, node, mac)) {
1198 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
1199 || (local_via_nw && CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)
1200 && zebra_evpn_mac_is_static(mac))) {
1201 if (es->flags & ZEBRA_EVPNES_NHG_ACTIVE) {
1202 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
1203 zlog_debug(
1204 "%smac %pEA install via es %s nhg 0x%x",
1205 (mac->flags & ZEBRA_MAC_REMOTE)
1206 ? "rem"
1207 : "local-nw",
1208 &mac->macaddr, es->esi_str,
1209 es->nhg_id);
1210 zebra_evpn_rem_mac_install(
1211 mac->zevpn, mac, false /*was_static*/);
1212 } else {
1213 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
1214 zlog_debug(
1215 "%smac %pEA un-install es %s",
1216 (mac->flags & ZEBRA_MAC_REMOTE)
1217 ? "rem"
1218 : "local-nw",
1219 &mac->macaddr, es->esi_str);
1220 zebra_evpn_rem_mac_uninstall(mac->zevpn, mac,
1221 true /*force*/);
1222 }
1223 }
f3722826
AK
1224 }
1225}
1226
ce5160c0
AK
1227/* The MAC ECMP group is activated on the first VTEP */
1228static void zebra_evpn_nhg_update(struct zebra_evpn_es *es)
1229{
1230 uint32_t nh_cnt = 0;
1231 struct nh_grp nh_ids[ES_VTEP_MAX_CNT];
1232 struct zebra_evpn_es_vtep *es_vtep;
1233 struct listnode *node;
1234
1235 if (!es->nhg_id)
1236 return;
1237
1238 for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
5de10c37 1239 if (!es_vtep->nh)
ce5160c0
AK
1240 continue;
1241
1242 if (nh_cnt >= ES_VTEP_MAX_CNT)
1243 break;
1244
1245 memset(&nh_ids[nh_cnt], 0, sizeof(struct nh_grp));
5de10c37 1246 nh_ids[nh_cnt].id = es_vtep->nh->nh_id;
ce5160c0
AK
1247 ++nh_cnt;
1248 }
1249
1250 if (nh_cnt) {
1251 if (IS_ZEBRA_DEBUG_EVPN_MH_NH) {
1252 char nh_str[ES_VTEP_LIST_STR_SZ];
1253 uint32_t i;
9e0c2fd1 1254 char nh_buf[16];
ce5160c0
AK
1255
1256 nh_str[0] = '\0';
9e0c2fd1
AK
1257 for (i = 0; i < nh_cnt; ++i) {
1258 snprintf(nh_buf, sizeof(nh_buf), "%u ",
1259 nh_ids[i].id);
1260 strlcat(nh_str, nh_buf, sizeof(nh_str));
1261 }
dfa3d3d7
AK
1262 zlog_debug("es %s nhg %u add %s", es->esi_str,
1263 es->nhg_id, nh_str);
ce5160c0
AK
1264 }
1265
ce5160c0 1266 kernel_upd_mac_nhg(es->nhg_id, nh_cnt, nh_ids);
28e80a03
AK
1267 if (!(es->flags & ZEBRA_EVPNES_NHG_ACTIVE)) {
1268 es->flags |= ZEBRA_EVPNES_NHG_ACTIVE;
1269 /* add backup NHG to the br-port */
1270 if ((es->flags & ZEBRA_EVPNES_LOCAL))
1271 zebra_evpn_es_br_port_dplane_update(es,
1272 __func__);
f3722826 1273 zebra_evpn_nhg_mac_update(es);
28e80a03 1274 }
ce5160c0
AK
1275 } else {
1276 if (es->flags & ZEBRA_EVPNES_NHG_ACTIVE) {
1277 if (IS_ZEBRA_DEBUG_EVPN_MH_NH)
dfa3d3d7
AK
1278 zlog_debug("es %s nhg %u del", es->esi_str,
1279 es->nhg_id);
ce5160c0 1280 es->flags &= ~ZEBRA_EVPNES_NHG_ACTIVE;
28e80a03
AK
1281 /* remove backup NHG from the br-port */
1282 if ((es->flags & ZEBRA_EVPNES_LOCAL))
1283 zebra_evpn_es_br_port_dplane_update(es,
1284 __func__);
f3722826 1285 zebra_evpn_nhg_mac_update(es);
ce5160c0
AK
1286 kernel_del_mac_nhg(es->nhg_id);
1287 }
1288 }
1289
ce5160c0
AK
1290}
1291
5de10c37
AK
1292static void zebra_evpn_es_l2_nh_show_entry(struct zebra_evpn_l2_nh *nh,
1293 struct vty *vty,
1294 json_object *json_array)
ce5160c0 1295{
5de10c37
AK
1296 if (json_array) {
1297 json_object *json = NULL;
1298 char ip_buf[INET6_ADDRSTRLEN];
1299
1300 json = json_object_new_object();
1301 json_object_string_add(json, "vtep",
1302 inet_ntop(AF_INET, &nh->vtep_ip, ip_buf,
1303 sizeof(ip_buf)));
1304 json_object_int_add(json, "nhId", nh->nh_id);
1305 json_object_int_add(json, "refCnt", nh->ref_cnt);
1306
1307 json_object_array_add(json_array, json);
1308 } else {
1309 vty_out(vty, "%-16pI4 %-10u %u\n", &nh->vtep_ip, nh->nh_id,
1310 nh->ref_cnt);
1311 }
1312}
1313
1314static void zebra_evpn_l2_nh_show_cb(struct hash_bucket *bucket, void *ctxt)
1315{
1316 struct zebra_evpn_l2_nh *nh = (struct zebra_evpn_l2_nh *)bucket->data;
1317 struct evpn_mh_show_ctx *wctx = (struct evpn_mh_show_ctx *)ctxt;
1318
1319 zebra_evpn_es_l2_nh_show_entry(nh, wctx->vty, wctx->json);
1320}
1321
1322void zebra_evpn_l2_nh_show(struct vty *vty, bool uj)
1323{
1324 struct evpn_mh_show_ctx wctx;
1325 json_object *json_array = NULL;
1326
1327 if (uj) {
1328 json_array = json_object_new_array();
1329 } else {
1330 vty_out(vty, "%-16s %-10s %s\n", "VTEP", "NH id", "#ES");
1331 }
1332
1333 memset(&wctx, 0, sizeof(wctx));
1334 wctx.vty = vty;
1335 wctx.json = json_array;
1336
1337 hash_iterate(zmh_info->nh_ip_table, zebra_evpn_l2_nh_show_cb, &wctx);
1338
1339 if (uj) {
1340 vty_out(vty, "%s\n",
1341 json_object_to_json_string_ext(
1342 json_array, JSON_C_TO_STRING_PRETTY));
1343 json_object_free(json_array);
1344 }
1345}
1346
1347static struct zebra_evpn_l2_nh *zebra_evpn_l2_nh_find(struct in_addr vtep_ip)
1348{
1349 struct zebra_evpn_l2_nh *nh;
1350 struct zebra_evpn_l2_nh tmp;
1351
1352 tmp.vtep_ip.s_addr = vtep_ip.s_addr;
1353 nh = hash_lookup(zmh_info->nh_ip_table, &tmp);
1354
1355 return nh;
1356}
1357
1358static struct zebra_evpn_l2_nh *zebra_evpn_l2_nh_alloc(struct in_addr vtep_ip)
1359{
1360 struct zebra_evpn_l2_nh *nh;
1361
1362 nh = XCALLOC(MTYPE_L2_NH, sizeof(*nh));
1363 nh->vtep_ip = vtep_ip;
1364 if (!hash_get(zmh_info->nh_ip_table, nh, hash_alloc_intern)) {
1365 XFREE(MTYPE_L2_NH, nh);
1366 return NULL;
1367 }
1368
1369 nh->nh_id = zebra_evpn_nhid_alloc(NULL);
1370 if (!nh->nh_id) {
1371 hash_release(zmh_info->nh_ip_table, nh);
1372 XFREE(MTYPE_L2_NH, nh);
1373 return NULL;
1374 }
1375
1376 /* install the NH in the dataplane */
1377 kernel_upd_mac_nh(nh->nh_id, nh->vtep_ip);
1378
1379 return nh;
1380}
1381
1382static void zebra_evpn_l2_nh_free(struct zebra_evpn_l2_nh *nh)
1383{
1384 /* delete the NH from the dataplane */
1385 kernel_del_mac_nh(nh->nh_id);
1386
1387 zebra_evpn_nhid_free(nh->nh_id, NULL);
1388 hash_release(zmh_info->nh_ip_table, nh);
1389 XFREE(MTYPE_L2_NH, nh);
1390}
1391
1392static void zebra_evpn_l2_nh_es_vtep_ref(struct zebra_evpn_es_vtep *es_vtep)
1393{
1394 if (es_vtep->nh)
ce5160c0
AK
1395 return;
1396
5de10c37
AK
1397 es_vtep->nh = zebra_evpn_l2_nh_find(es_vtep->vtep_ip);
1398 if (!es_vtep->nh)
1399 es_vtep->nh = zebra_evpn_l2_nh_alloc(es_vtep->vtep_ip);
ce5160c0 1400
5de10c37
AK
1401 if (!es_vtep->nh) {
1402 zlog_warn("es %s vtep %pI4 nh ref failed", es_vtep->es->esi_str,
1403 &es_vtep->vtep_ip);
ce5160c0 1404 return;
5de10c37
AK
1405 }
1406
1407 ++es_vtep->nh->ref_cnt;
ce5160c0
AK
1408
1409 if (IS_ZEBRA_DEBUG_EVPN_MH_NH)
5de10c37
AK
1410 zlog_debug("es %s vtep %pI4 nh %u ref %u", es_vtep->es->esi_str,
1411 &es_vtep->vtep_ip, es_vtep->nh->nh_id,
1412 es_vtep->nh->ref_cnt);
1413
ce5160c0
AK
1414 /* add the NH to the parent NHG */
1415 zebra_evpn_nhg_update(es_vtep->es);
1416}
1417
5de10c37 1418static void zebra_evpn_l2_nh_es_vtep_deref(struct zebra_evpn_es_vtep *es_vtep)
ce5160c0 1419{
5de10c37 1420 struct zebra_evpn_l2_nh *nh = es_vtep->nh;
ce5160c0 1421
5de10c37 1422 if (!nh)
ce5160c0
AK
1423 return;
1424
5de10c37
AK
1425 es_vtep->nh = NULL;
1426 if (nh->ref_cnt)
1427 --nh->ref_cnt;
ce5160c0 1428
5de10c37
AK
1429 if (IS_ZEBRA_DEBUG_EVPN_MH_NH)
1430 zlog_debug("es %s vtep %pI4 nh %u deref %u",
1431 es_vtep->es->esi_str, &es_vtep->vtep_ip, nh->nh_id,
1432 nh->ref_cnt);
ce5160c0
AK
1433
1434 /* remove the NH from the parent NHG */
1435 zebra_evpn_nhg_update(es_vtep->es);
5de10c37 1436
ce5160c0 1437 /* uninstall the NH */
5de10c37
AK
1438 if (!nh->ref_cnt)
1439 zebra_evpn_l2_nh_free(nh);
ce5160c0
AK
1440}
1441
1442/*****************************************************************************/
1443/* Ethernet Segment Management
1444 * 1. Ethernet Segment is a collection of links attached to the same
1445 * server (MHD) or switch (MHN)
1446 * 2. An Ethernet Segment can span multiple PEs and is identified by the
1447 * 10-byte ES-ID.
1448 * 3. Zebra manages the local ESI configuration.
1449 * 4. It also maintains the aliasing that maps an ESI (local or remote)
1450 * to one or more PEs/VTEPs.
1451 * 5. remote ESs are added by BGP (on rxing EAD Type-1 routes)
1452 */
1453/* A list of remote VTEPs is maintained for each ES. This list includes -
1454 * 1. VTEPs for which we have imported the ESR i.e. ES-peers
1455 * 2. VTEPs that have an "active" ES-EVI VTEP i.e. EAD-per-ES and EAD-per-EVI
87d76d54 1456 * have been imported into one or more EVPNs
ce5160c0
AK
1457 */
1458static int zebra_evpn_es_vtep_cmp(void *p1, void *p2)
1459{
1460 const struct zebra_evpn_es_vtep *es_vtep1 = p1;
1461 const struct zebra_evpn_es_vtep *es_vtep2 = p2;
1462
1463 return es_vtep1->vtep_ip.s_addr - es_vtep2->vtep_ip.s_addr;
1464}
1465
1466static struct zebra_evpn_es_vtep *zebra_evpn_es_vtep_new(
1467 struct zebra_evpn_es *es, struct in_addr vtep_ip)
1468{
1469 struct zebra_evpn_es_vtep *es_vtep;
1470
1471 es_vtep = XCALLOC(MTYPE_ZES_VTEP, sizeof(*es_vtep));
1472
1473 es_vtep->es = es;
1474 es_vtep->vtep_ip.s_addr = vtep_ip.s_addr;
1475 listnode_init(&es_vtep->es_listnode, es_vtep);
1476 listnode_add_sort(es->es_vtep_list, &es_vtep->es_listnode);
1477
1478 return es_vtep;
1479}
1480
1481static void zebra_evpn_es_vtep_free(struct zebra_evpn_es_vtep *es_vtep)
1482{
1483 struct zebra_evpn_es *es = es_vtep->es;
1484
1485 list_delete_node(es->es_vtep_list, &es_vtep->es_listnode);
1486 /* update the L2-NHG associated with the ES */
5de10c37 1487 zebra_evpn_l2_nh_es_vtep_deref(es_vtep);
ce5160c0
AK
1488 XFREE(MTYPE_ZES_VTEP, es_vtep);
1489}
1490
1491
1492/* check if VTEP is already part of the list */
1493static struct zebra_evpn_es_vtep *zebra_evpn_es_vtep_find(
1494 struct zebra_evpn_es *es, struct in_addr vtep_ip)
1495{
1496 struct listnode *node = NULL;
1497 struct zebra_evpn_es_vtep *es_vtep;
1498
1499 for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
1500 if (es_vtep->vtep_ip.s_addr == vtep_ip.s_addr)
1501 return es_vtep;
1502 }
1503 return NULL;
1504}
1505
28e80a03
AK
1506/* flush all the dataplane br-port info associated with the ES */
1507static bool zebra_evpn_es_br_port_dplane_clear(struct zebra_evpn_es *es)
1508{
1509 struct in_addr sph_filters[ES_VTEP_MAX_CNT];
1510
1511 if (!(es->flags & ZEBRA_EVPNES_BR_PORT))
1512 return false;
1513
1514 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1515 zlog_debug("es %s br-port dplane clear", es->esi_str);
1516
1517 memset(&sph_filters, 0, sizeof(sph_filters));
1518 dplane_br_port_update(es->zif->ifp, false /* non_df */, 0, sph_filters,
1519 0 /* backup_nhg_id */);
1520 return true;
1521}
1522
1523static inline bool
1524zebra_evpn_es_br_port_dplane_update_needed(struct zebra_evpn_es *es)
1525{
1526 return (es->flags & ZEBRA_EVPNES_NON_DF)
1527 || (es->flags & ZEBRA_EVPNES_NHG_ACTIVE)
1528 || listcount(es->es_vtep_list);
1529}
1530
1531/* returns TRUE if dplane entry was updated */
1532static bool zebra_evpn_es_br_port_dplane_update(struct zebra_evpn_es *es,
1533 const char *caller)
1534{
1535 uint32_t backup_nhg_id;
1536 struct in_addr sph_filters[ES_VTEP_MAX_CNT];
1537 struct listnode *node = NULL;
1538 struct zebra_evpn_es_vtep *es_vtep;
1539 uint32_t sph_filter_cnt = 0;
1540
1541 if (!(es->flags & ZEBRA_EVPNES_LOCAL))
1542 return zebra_evpn_es_br_port_dplane_clear(es);
1543
1544 /* If the ES is not a bridge port there is nothing
1545 * in the dataplane
1546 */
1547 if (!(es->flags & ZEBRA_EVPNES_BR_PORT))
1548 return false;
1549
1550 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1551 zlog_debug("es %s br-port dplane update by %s", es->esi_str, caller);
1552 backup_nhg_id = (es->flags & ZEBRA_EVPNES_NHG_ACTIVE) ? es->nhg_id : 0;
1553
1554 memset(&sph_filters, 0, sizeof(sph_filters));
1555 if (listcount(es->es_vtep_list) > ES_VTEP_MAX_CNT) {
1556 zlog_warn("es %s vtep count %d exceeds filter cnt %d",
1557 es->esi_str, listcount(es->es_vtep_list),
1558 ES_VTEP_MAX_CNT);
1559 } else {
1560 for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
1561 if (es_vtep->flags & ZEBRA_EVPNES_VTEP_DEL_IN_PROG)
1562 continue;
1563 sph_filters[sph_filter_cnt] = es_vtep->vtep_ip;
1564 ++sph_filter_cnt;
1565 }
1566 }
1567
1568 dplane_br_port_update(es->zif->ifp, !!(es->flags & ZEBRA_EVPNES_NON_DF),
1569 sph_filter_cnt, sph_filters, backup_nhg_id);
1570
1571 return true;
1572}
1573
1574/* returns TRUE if dplane entry was updated */
1575static bool zebra_evpn_es_df_change(struct zebra_evpn_es *es, bool new_non_df,
35f5c31b 1576 const char *caller, const char *reason)
1103c5c6
AK
1577{
1578 bool old_non_df;
1579
1580 old_non_df = !!(es->flags & ZEBRA_EVPNES_NON_DF);
1581
1582 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
35f5c31b
AK
1583 zlog_debug("df-change es %s %s to %s; %s: %s", es->esi_str,
1584 old_non_df ? "non-df" : "df",
1585 new_non_df ? "non-df" : "df", caller, reason);
1103c5c6
AK
1586
1587 if (old_non_df == new_non_df)
28e80a03 1588 return false;
1103c5c6 1589
28e80a03 1590 if (new_non_df)
1103c5c6 1591 es->flags |= ZEBRA_EVPNES_NON_DF;
28e80a03 1592 else
1103c5c6 1593 es->flags &= ~ZEBRA_EVPNES_NON_DF;
28e80a03
AK
1594
1595 /* update non-DF block filter in the dataplane */
1596 return zebra_evpn_es_br_port_dplane_update(es, __func__);
1103c5c6
AK
1597}
1598
28e80a03
AK
1599
1600/* returns TRUE if dplane entry was updated */
1601static bool zebra_evpn_es_run_df_election(struct zebra_evpn_es *es,
1103c5c6
AK
1602 const char *caller)
1603{
1604 struct listnode *node = NULL;
1605 struct zebra_evpn_es_vtep *es_vtep;
1606 bool new_non_df = false;
1607
1608 /* If the ES is not ready (i.e. not completely configured) there
1609 * is no need to setup the BUM block filter
1610 */
1611 if (!(es->flags & ZEBRA_EVPNES_LOCAL)
28e80a03 1612 || !zmh_info->es_originator_ip.s_addr)
35f5c31b
AK
1613 return zebra_evpn_es_df_change(es, new_non_df, caller,
1614 "not-ready");
1103c5c6
AK
1615
1616 /* if oper-state is down DF filtering must be on. when the link comes
1617 * up again dataplane should block BUM till FRR has had the chance
1618 * to run DF election again
1619 */
1620 if (!(es->flags & ZEBRA_EVPNES_OPER_UP)) {
1621 new_non_df = true;
35f5c31b
AK
1622 return zebra_evpn_es_df_change(es, new_non_df, caller,
1623 "oper-down");
1624 }
1625
1626 /* ES was just created; we need to wait for the peers to rx the
1627 * our Type-4 routes and for the switch to import the peers' Type-4
1628 * routes
1629 */
1630 if (es->df_delay_timer) {
1631 new_non_df = true;
1632 return zebra_evpn_es_df_change(es, new_non_df, caller,
1633 "df-delay");
1103c5c6
AK
1634 }
1635
1636 for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
1637 /* Only VTEPs that have advertised the ESR can participate
1638 * in DF election
1639 */
1640 if (!(es_vtep->flags & ZEBRA_EVPNES_VTEP_RXED_ESR))
1641 continue;
1642
1643 /* If the DF alg is not the same we should fall back to
1644 * service-carving. But as service-carving is not supported
1645 * we will stop forwarding BUM
1646 */
1647 if (es_vtep->df_alg != EVPN_MH_DF_ALG_PREF) {
1648 new_non_df = true;
1649 break;
1650 }
1651
1652 /* Peer VTEP wins DF election if -
1653 * the peer-VTEP has higher preference (or)
1654 * the pref is the same but peer's IP address is lower
1655 */
1656 if ((es_vtep->df_pref > es->df_pref)
1657 || ((es_vtep->df_pref == es->df_pref)
1658 && (es_vtep->vtep_ip.s_addr
1659 < zmh_info->es_originator_ip.s_addr))) {
1660 new_non_df = true;
1661 break;
1662 }
1663 }
1664
35f5c31b 1665 return zebra_evpn_es_df_change(es, new_non_df, caller, "elected");
1103c5c6
AK
1666}
1667
ce5160c0 1668static void zebra_evpn_es_vtep_add(struct zebra_evpn_es *es,
1103c5c6
AK
1669 struct in_addr vtep_ip, bool esr_rxed,
1670 uint8_t df_alg, uint16_t df_pref)
ce5160c0
AK
1671{
1672 struct zebra_evpn_es_vtep *es_vtep;
1103c5c6 1673 bool old_esr_rxed;
28e80a03 1674 bool dplane_updated = false;
ce5160c0
AK
1675
1676 es_vtep = zebra_evpn_es_vtep_find(es, vtep_ip);
1677
1678 if (!es_vtep) {
1679 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
9bcef951
MS
1680 zlog_debug("es %s vtep %pI4 add",
1681 es->esi_str, &vtep_ip);
ce5160c0
AK
1682 es_vtep = zebra_evpn_es_vtep_new(es, vtep_ip);
1683 /* update the L2-NHG associated with the ES */
5de10c37 1684 zebra_evpn_l2_nh_es_vtep_ref(es_vtep);
ce5160c0 1685 }
1103c5c6
AK
1686
1687 old_esr_rxed = !!(es_vtep->flags & ZEBRA_EVPNES_VTEP_RXED_ESR);
1688 if ((old_esr_rxed != esr_rxed) || (es_vtep->df_alg != df_alg)
1689 || (es_vtep->df_pref != df_pref)) {
1690 /* If any of the DF election params changed we need to re-run
1691 * DF election
1692 */
1693 if (esr_rxed)
1694 es_vtep->flags |= ZEBRA_EVPNES_VTEP_RXED_ESR;
1695 else
1696 es_vtep->flags &= ~ZEBRA_EVPNES_VTEP_RXED_ESR;
1697 es_vtep->df_alg = df_alg;
1698 es_vtep->df_pref = df_pref;
28e80a03 1699 dplane_updated = zebra_evpn_es_run_df_election(es, __func__);
1103c5c6 1700 }
28e80a03
AK
1701 /* add the vtep to the SPH list */
1702 if (!dplane_updated && (es->flags & ZEBRA_EVPNES_LOCAL))
1703 zebra_evpn_es_br_port_dplane_update(es, __func__);
ce5160c0
AK
1704}
1705
1706static void zebra_evpn_es_vtep_del(struct zebra_evpn_es *es,
1707 struct in_addr vtep_ip)
1708{
1709 struct zebra_evpn_es_vtep *es_vtep;
28e80a03 1710 bool dplane_updated = false;
ce5160c0
AK
1711
1712 es_vtep = zebra_evpn_es_vtep_find(es, vtep_ip);
1713
1714 if (es_vtep) {
1715 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
9bcef951
MS
1716 zlog_debug("es %s vtep %pI4 del",
1717 es->esi_str, &vtep_ip);
28e80a03 1718 es_vtep->flags |= ZEBRA_EVPNES_VTEP_DEL_IN_PROG;
1103c5c6
AK
1719 if (es_vtep->flags & ZEBRA_EVPNES_VTEP_RXED_ESR) {
1720 es_vtep->flags &= ~ZEBRA_EVPNES_VTEP_RXED_ESR;
28e80a03
AK
1721 dplane_updated =
1722 zebra_evpn_es_run_df_election(es, __func__);
1103c5c6 1723 }
28e80a03
AK
1724 /* remove the vtep from the SPH list */
1725 if (!dplane_updated && (es->flags & ZEBRA_EVPNES_LOCAL))
1726 zebra_evpn_es_br_port_dplane_update(es, __func__);
ce5160c0
AK
1727 zebra_evpn_es_vtep_free(es_vtep);
1728 }
1729}
1730
1731/* compare ES-IDs for the global ES RB tree */
1732static int zebra_es_rb_cmp(const struct zebra_evpn_es *es1,
1733 const struct zebra_evpn_es *es2)
1734{
1735 return memcmp(&es1->esi, &es2->esi, ESI_BYTES);
1736}
1737RB_GENERATE(zebra_es_rb_head, zebra_evpn_es, rb_node, zebra_es_rb_cmp);
1738
1739/* Lookup ES */
1740struct zebra_evpn_es *zebra_evpn_es_find(esi_t *esi)
1741{
1742 struct zebra_evpn_es tmp;
1743
1744 memcpy(&tmp.esi, esi, sizeof(esi_t));
1745 return RB_FIND(zebra_es_rb_head, &zmh_info->es_rb_tree, &tmp);
1746}
1747
1748/* A new local es is created when a local-es-id and sysmac is configured
1749 * against an interface.
1750 */
1751static struct zebra_evpn_es *zebra_evpn_es_new(esi_t *esi)
1752{
1753 struct zebra_evpn_es *es;
1754
325d694b
AK
1755 if (!memcmp(esi, zero_esi, sizeof(esi_t)))
1756 return NULL;
1757
ce5160c0
AK
1758 es = XCALLOC(MTYPE_ZES, sizeof(struct zebra_evpn_es));
1759
1760 /* fill in ESI */
1761 memcpy(&es->esi, esi, sizeof(esi_t));
1762 esi_to_str(&es->esi, es->esi_str, sizeof(es->esi_str));
1763
1764 /* Add to rb_tree */
1765 if (RB_INSERT(zebra_es_rb_head, &zmh_info->es_rb_tree, es)) {
1766 XFREE(MTYPE_ZES, es);
1767 return NULL;
1768 }
1769
1770 /* Initialise the ES-EVI list */
1771 es->es_evi_list = list_new();
1772 listset_app_node_mem(es->es_evi_list);
1773
1774 /* Initialise the VTEP list */
1775 es->es_vtep_list = list_new();
1776 listset_app_node_mem(es->es_vtep_list);
1777 es->es_vtep_list->cmp = zebra_evpn_es_vtep_cmp;
1778
b169fd6f
AK
1779 /* mac entries associated with the ES */
1780 es->mac_list = list_new();
1781 listset_app_node_mem(es->mac_list);
1782
ce5160c0 1783 /* reserve a NHG */
15400f95 1784 es->nhg_id = zebra_evpn_nhid_alloc(es);
ce5160c0
AK
1785
1786 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
dfa3d3d7 1787 zlog_debug("es %s nhg %u new", es->esi_str, es->nhg_id);
ce5160c0
AK
1788
1789 return es;
1790}
1791
1792/* Free a given ES -
1793 * This just frees appropriate memory, caller should have taken other
1794 * needed actions.
1795 */
e378f502 1796static void zebra_evpn_es_free(struct zebra_evpn_es **esp)
ce5160c0 1797{
e378f502
AK
1798 struct zebra_evpn_es *es = *esp;
1799
ce5160c0
AK
1800 /* If the ES has a local or remote reference it cannot be freed.
1801 * Free is also prevented if there are MAC entries referencing
1802 * it.
1803 */
1804 if ((es->flags & (ZEBRA_EVPNES_LOCAL | ZEBRA_EVPNES_REMOTE)) ||
b169fd6f 1805 listcount(es->mac_list))
e378f502 1806 return;
ce5160c0
AK
1807
1808 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1809 zlog_debug("es %s free", es->esi_str);
1810
1811 /* If the NHG is still installed uninstall it and free the id */
1812 if (es->flags & ZEBRA_EVPNES_NHG_ACTIVE) {
1813 es->flags &= ~ZEBRA_EVPNES_NHG_ACTIVE;
1814 kernel_del_mac_nhg(es->nhg_id);
1815 }
15400f95 1816 zebra_evpn_nhid_free(es->nhg_id, es);
ce5160c0
AK
1817
1818 /* cleanup resources maintained against the ES */
1819 list_delete(&es->es_evi_list);
1820 list_delete(&es->es_vtep_list);
b169fd6f 1821 list_delete(&es->mac_list);
ce5160c0
AK
1822
1823 /* remove from the VNI-ESI rb tree */
1824 RB_REMOVE(zebra_es_rb_head, &zmh_info->es_rb_tree, es);
1825
1826 XFREE(MTYPE_ZES, es);
b169fd6f 1827
e378f502 1828 *esp = NULL;
ce5160c0
AK
1829}
1830
1831/* Inform BGP about local ES addition */
1832static int zebra_evpn_es_send_add_to_client(struct zebra_evpn_es *es)
1833{
1834 struct zserv *client;
1835 struct stream *s;
1836 uint8_t oper_up;
1837
1838 client = zserv_find_client(ZEBRA_ROUTE_BGP, 0);
1839 /* BGP may not be running. */
1840 if (!client)
1841 return 0;
1842
1843 s = stream_new(ZEBRA_MAX_PACKET_SIZ);
1844
1845 zclient_create_header(s, ZEBRA_LOCAL_ES_ADD, zebra_vrf_get_evpn_id());
1846 stream_put(s, &es->esi, sizeof(esi_t));
1847 stream_put_ipv4(s, zmh_info->es_originator_ip.s_addr);
1848 oper_up = !!(es->flags & ZEBRA_EVPNES_OPER_UP);
1849 stream_putc(s, oper_up);
1103c5c6 1850 stream_putw(s, es->df_pref);
ce5160c0
AK
1851
1852 /* Write packet size. */
1853 stream_putw_at(s, 0, stream_get_endp(s));
1854
1855 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1103c5c6
AK
1856 zlog_debug("send add local es %s %pI4 active %u df_pref %u to %s",
1857 es->esi_str, &zmh_info->es_originator_ip,
1858 oper_up, es->df_pref,
1859 zebra_route_string(client->proto));
ce5160c0
AK
1860
1861 client->local_es_add_cnt++;
1862 return zserv_send_message(client, s);
1863}
1864
1865/* Inform BGP about local ES deletion */
1866static int zebra_evpn_es_send_del_to_client(struct zebra_evpn_es *es)
1867{
1868 struct zserv *client;
1869 struct stream *s;
1870
1871 client = zserv_find_client(ZEBRA_ROUTE_BGP, 0);
1872 /* BGP may not be running. */
1873 if (!client)
1874 return 0;
1875
1876 s = stream_new(ZEBRA_MAX_PACKET_SIZ);
1877 stream_reset(s);
1878
1879 zclient_create_header(s, ZEBRA_LOCAL_ES_DEL, zebra_vrf_get_evpn_id());
1880 stream_put(s, &es->esi, sizeof(esi_t));
1881
1882 /* Write packet size. */
1883 stream_putw_at(s, 0, stream_get_endp(s));
1884
1885 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1886 zlog_debug("send del local es %s to %s", es->esi_str,
1887 zebra_route_string(client->proto));
1888
1889 client->local_es_del_cnt++;
1890 return zserv_send_message(client, s);
1891}
1892
ce5160c0
AK
1893static void zebra_evpn_es_re_eval_send_to_client(struct zebra_evpn_es *es,
1894 bool es_evi_re_reval)
1895{
1896 bool old_ready;
1897 bool new_ready;
1898 struct listnode *node;
1899 struct zebra_evpn_es_evi *es_evi;
1900
1901 old_ready = !!(es->flags & ZEBRA_EVPNES_READY_FOR_BGP);
1902
1903 if ((es->flags & ZEBRA_EVPNES_LOCAL) &&
1904 zmh_info->es_originator_ip.s_addr)
1905 es->flags |= ZEBRA_EVPNES_READY_FOR_BGP;
1906 else
1907 es->flags &= ~ZEBRA_EVPNES_READY_FOR_BGP;
1908
1909 new_ready = !!(es->flags & ZEBRA_EVPNES_READY_FOR_BGP);
1910 if (old_ready == new_ready)
1911 return;
1912
1913 if (new_ready)
1914 zebra_evpn_es_send_add_to_client(es);
1915 else
1916 zebra_evpn_es_send_del_to_client(es);
1917
1918 /* re-eval associated EVIs */
1919 if (es_evi_re_reval) {
1920 for (ALL_LIST_ELEMENTS_RO(es->es_evi_list, node, es_evi)) {
1921 if (!(es_evi->flags & ZEBRA_EVPNES_EVI_LOCAL))
1922 continue;
1923 zebra_evpn_es_evi_re_eval_send_to_client(es_evi);
1924 }
1925 }
1926}
1927
1928void zebra_evpn_es_send_all_to_client(bool add)
1929{
1930 struct listnode *es_node;
1931 struct listnode *evi_node;
1932 struct zebra_evpn_es *es;
1933 struct zebra_evpn_es_evi *es_evi;
1934
1935 if (!zmh_info)
1936 return;
1937
1938 for (ALL_LIST_ELEMENTS_RO(zmh_info->local_es_list, es_node, es)) {
1939 if (es->flags & ZEBRA_EVPNES_READY_FOR_BGP) {
1940 if (add)
1941 zebra_evpn_es_send_add_to_client(es);
1942 for (ALL_LIST_ELEMENTS_RO(es->es_evi_list,
1943 evi_node, es_evi)) {
1944 if (!(es_evi->flags &
1945 ZEBRA_EVPNES_EVI_READY_FOR_BGP))
1946 continue;
1947
1948 if (add)
1949 zebra_evpn_es_evi_send_to_client(
87d76d54 1950 es, es_evi->zevpn,
ce5160c0
AK
1951 true /* add */);
1952 else
1953 zebra_evpn_es_evi_send_to_client(
87d76d54 1954 es, es_evi->zevpn,
ce5160c0
AK
1955 false /* add */);
1956 }
1957 if (!add)
1958 zebra_evpn_es_send_del_to_client(es);
1959 }
1960 }
1961}
1962
1963/* walk the vlan bitmap associated with the zif and create or delete
1964 * es_evis for all vlans associated with a VNI.
1965 * XXX: This API is really expensive. optimize later if possible.
1966 */
1967static void zebra_evpn_es_setup_evis(struct zebra_evpn_es *es)
1968{
1969 struct zebra_if *zif = es->zif;
1970 uint16_t vid;
1971 struct zebra_evpn_access_bd *acc_bd;
1972
0b05c9bb
AK
1973 if (!bf_is_inited(zif->vlan_bitmap))
1974 return;
ce5160c0
AK
1975
1976 bf_for_each_set_bit(zif->vlan_bitmap, vid, IF_VLAN_BITMAP_MAX) {
1977 acc_bd = zebra_evpn_acc_vl_find(vid);
87d76d54
PR
1978 if (acc_bd->zevpn)
1979 zebra_evpn_local_es_evi_add(es, acc_bd->zevpn);
ce5160c0
AK
1980 }
1981}
1982
b169fd6f
AK
1983static void zebra_evpn_es_local_mac_update(struct zebra_evpn_es *es,
1984 bool force_clear_static)
1985{
1986 zebra_mac_t *mac;
1987 struct listnode *node;
1988
1989 for (ALL_LIST_ELEMENTS_RO(es->mac_list, node, mac)) {
1990 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE)) {
b2998086
PR
1991 zebra_evpn_sync_mac_dp_install(
1992 mac, false /* set_inactive */,
1993 force_clear_static, __func__);
b169fd6f
AK
1994 }
1995 }
1996}
1997
72f2674a
AK
1998void zebra_evpn_es_local_br_port_update(struct zebra_if *zif)
1999{
2000 struct zebra_evpn_es *es = zif->es_info.es;
2001 bool old_br_port = !!(es->flags & ZEBRA_EVPNES_BR_PORT);
2002 bool new_br_port;
2003
2004 if (zif->brslave_info.bridge_ifindex != IFINDEX_INTERNAL)
2005 es->flags |= ZEBRA_EVPNES_BR_PORT;
2006 else
2007 es->flags &= ~ZEBRA_EVPNES_BR_PORT;
2008
2009 new_br_port = !!(es->flags & ZEBRA_EVPNES_BR_PORT);
2010 if (old_br_port == new_br_port)
2011 return;
2012
2013 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
2014 zlog_debug("es %s br_port change old %u new %u", es->esi_str,
2015 old_br_port, new_br_port);
2016
2017 /* update the dataplane br_port attrs */
2018 if (new_br_port && zebra_evpn_es_br_port_dplane_update_needed(es))
2019 zebra_evpn_es_br_port_dplane_update(es, __func__);
2020}
2021
b2ee2b71
AK
2022/* On config of first local-ES turn off DAD */
2023static void zebra_evpn_mh_dup_addr_detect_off(void)
2024{
2025 struct zebra_vrf *zvrf;
2026 bool old_detect;
2027 bool new_detect;
2028
2029 if (zmh_info->flags & ZEBRA_EVPN_MH_DUP_ADDR_DETECT_OFF)
2030 return;
2031
2032 zvrf = zebra_vrf_get_evpn();
2033 if (!zvrf) {
2034 zmh_info->flags |= ZEBRA_EVPN_MH_DUP_ADDR_DETECT_OFF;
2035 return;
2036 }
2037
2038 old_detect = zebra_evpn_do_dup_addr_detect(zvrf);
2039 zmh_info->flags |= ZEBRA_EVPN_MH_DUP_ADDR_DETECT_OFF;
2040 new_detect = zebra_evpn_do_dup_addr_detect(zvrf);
2041
2042 if (old_detect && !new_detect) {
2043 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
2044 zlog_debug(
2045 "evpn-mh config caused DAD addr detect chg from %s to %s",
2046 old_detect ? "on" : "off",
2047 new_detect ? "on" : "off");
2048 zebra_vxlan_clear_dup_detect_vni_all(zvrf);
2049 }
2050}
2051
c7bfd085
AK
2052/* On config of first local-ES turn off advertisement of STALE/DELAY/PROBE
2053 * neighbors
2054 */
2055static void zebra_evpn_mh_advertise_reach_neigh_only(void)
2056{
2057 if (zmh_info->flags & ZEBRA_EVPN_MH_ADV_REACHABLE_NEIGH_ONLY)
2058 return;
2059
2060 zmh_info->flags |= ZEBRA_EVPN_MH_ADV_REACHABLE_NEIGH_ONLY;
2061 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
2062 zlog_debug("evpn-mh: only REACHABLE neigh advertised");
2063
2064 /* XXX - if STALE/DELAY/PROBE neighs were previously advertised we
2065 * need to withdraw them
2066 */
2067}
2068
243b74ed
AK
2069/* On config of first local-ES turn on advertisement of local SVI-MAC */
2070static void zebra_evpn_mh_advertise_svi_mac(void)
2071{
2072 if (zmh_info->flags & ZEBRA_EVPN_MH_ADV_SVI_MAC)
2073 return;
2074
2075 zmh_info->flags |= ZEBRA_EVPN_MH_ADV_SVI_MAC;
2076 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
2077 zlog_debug("evpn-mh: advertise SVI MAC");
2078
2079 /* walk through all SVIs and see if we need to advertise the MAC */
2080 zebra_evpn_acc_vl_adv_svi_mac_all();
2081}
2082
35f5c31b
AK
2083static int zebra_evpn_es_df_delay_exp_cb(struct thread *t)
2084{
2085 struct zebra_evpn_es *es;
2086
2087 es = THREAD_ARG(t);
2088
2089 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
2090 zlog_debug("es %s df-delay expired", es->esi_str);
2091
2092 zebra_evpn_es_run_df_election(es, __func__);
2093
2094 return 0;
2095}
2096
243b74ed
AK
2097/* currently there is no global config to turn on MH instead we use
2098 * the addition of the first local Ethernet Segment as the trigger to
2099 * init MH specific processing
2100 */
2101static void zebra_evpn_mh_on_first_local_es(void)
2102{
2103 zebra_evpn_mh_dup_addr_detect_off();
2104 zebra_evpn_mh_advertise_reach_neigh_only();
2105 zebra_evpn_mh_advertise_svi_mac();
2106}
2107
ce5160c0
AK
2108static void zebra_evpn_es_local_info_set(struct zebra_evpn_es *es,
2109 struct zebra_if *zif)
2110{
2111 if (es->flags & ZEBRA_EVPNES_LOCAL)
2112 return;
2113
2114 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
dfa3d3d7
AK
2115 zlog_debug("local es %s add; nhg %u if %s", es->esi_str,
2116 es->nhg_id, zif->ifp->name);
ce5160c0 2117
243b74ed 2118 zebra_evpn_mh_on_first_local_es();
b2ee2b71 2119
ce5160c0
AK
2120 es->flags |= ZEBRA_EVPNES_LOCAL;
2121 listnode_init(&es->local_es_listnode, es);
2122 listnode_add(zmh_info->local_es_list, &es->local_es_listnode);
2123
2124 /* attach es to interface */
2125 zif->es_info.es = es;
1103c5c6
AK
2126 es->df_pref = zif->es_info.df_pref ? zif->es_info.df_pref
2127 : EVPN_MH_DF_PREF_DEFAULT;
ce5160c0
AK
2128
2129 /* attach interface to es */
2130 es->zif = zif;
2131 if (if_is_operative(zif->ifp))
2132 es->flags |= ZEBRA_EVPNES_OPER_UP;
2133
72f2674a
AK
2134 if (zif->brslave_info.bridge_ifindex != IFINDEX_INTERNAL)
2135 es->flags |= ZEBRA_EVPNES_BR_PORT;
2136
ce5160c0
AK
2137 /* setup base-vni if one doesn't already exist; the ES will get sent
2138 * to BGP as a part of that process
2139 */
87d76d54
PR
2140 if (!zmh_info->es_base_evpn)
2141 zebra_evpn_es_get_one_base_evpn();
ce5160c0
AK
2142 else
2143 /* send notification to bgp */
2144 zebra_evpn_es_re_eval_send_to_client(es,
2145 false /* es_evi_re_reval */);
2146
35f5c31b
AK
2147 /* Start the DF delay timer on the local ES */
2148 if (!es->df_delay_timer)
2149 thread_add_timer(zrouter.master, zebra_evpn_es_df_delay_exp_cb,
2150 es, ZEBRA_EVPN_MH_DF_DELAY_TIME,
2151 &es->df_delay_timer);
2152
1103c5c6 2153 /* See if the local VTEP can function as DF on the ES */
28e80a03
AK
2154 if (!zebra_evpn_es_run_df_election(es, __func__)) {
2155 /* check if the dplane entry needs to be re-programmed as a
2156 * result of some thing other than DF status change
2157 */
2158 if (zebra_evpn_es_br_port_dplane_update_needed(es))
2159 zebra_evpn_es_br_port_dplane_update(es, __func__);
2160 }
2161
1103c5c6 2162
ce5160c0
AK
2163 /* Setup ES-EVIs for all VxLAN stretched VLANs associated with
2164 * the zif
2165 */
2166 zebra_evpn_es_setup_evis(es);
b169fd6f
AK
2167 /* if there any local macs referring to the ES as dest we
2168 * need to set the static reference on them if the MAC is
2169 * synced from an ES peer
2170 */
2171 zebra_evpn_es_local_mac_update(es,
2172 false /* force_clear_static */);
c36e442c
AK
2173
2174 /* inherit EVPN protodown flags on the access port */
2bcf92e1 2175 zebra_evpn_mh_update_protodown_es(es, true /*resync_dplane*/);
ce5160c0
AK
2176}
2177
e378f502 2178static void zebra_evpn_es_local_info_clear(struct zebra_evpn_es **esp)
ce5160c0
AK
2179{
2180 struct zebra_if *zif;
e378f502 2181 struct zebra_evpn_es *es = *esp;
28e80a03 2182 bool dplane_updated = false;
ce5160c0
AK
2183
2184 if (!(es->flags & ZEBRA_EVPNES_LOCAL))
2185 return;
2186
4cd94050
AK
2187 es->flags &= ~(ZEBRA_EVPNES_LOCAL | ZEBRA_EVPNES_READY_FOR_BGP);
2188
35f5c31b
AK
2189 THREAD_OFF(es->df_delay_timer);
2190
1103c5c6 2191 /* remove the DF filter */
28e80a03 2192 dplane_updated = zebra_evpn_es_run_df_election(es, __func__);
1103c5c6 2193
c36e442c
AK
2194 /* clear EVPN protodown flags on the access port */
2195 zebra_evpn_mh_clear_protodown_es(es);
2196
b169fd6f
AK
2197 /* if there any local macs referring to the ES as dest we
2198 * need to clear the static reference on them
2199 */
2200 zebra_evpn_es_local_mac_update(es,
2201 true /* force_clear_static */);
2202
28e80a03
AK
2203 /* flush the BUM filters and backup NHG */
2204 if (!dplane_updated)
2205 zebra_evpn_es_br_port_dplane_clear(es);
2206
ce5160c0
AK
2207 /* clear the es from the parent interface */
2208 zif = es->zif;
2209 zif->es_info.es = NULL;
2210 es->zif = NULL;
2211
72f2674a
AK
2212 /* clear all local flags associated with the ES */
2213 es->flags &= ~(ZEBRA_EVPNES_OPER_UP | ZEBRA_EVPNES_BR_PORT);
2214
ce5160c0
AK
2215 /* remove from the ES list */
2216 list_delete_node(zmh_info->local_es_list, &es->local_es_listnode);
2217
2218 /* free up the ES if there is no remote reference */
e378f502 2219 zebra_evpn_es_free(esp);
ce5160c0
AK
2220}
2221
2222/* Delete an ethernet segment and inform BGP */
e378f502 2223static void zebra_evpn_local_es_del(struct zebra_evpn_es **esp)
ce5160c0
AK
2224{
2225 struct zebra_evpn_es_evi *es_evi;
2226 struct listnode *node = NULL;
2227 struct listnode *nnode = NULL;
2228 struct zebra_if *zif;
e378f502 2229 struct zebra_evpn_es *es = *esp;
ce5160c0
AK
2230
2231 if (!CHECK_FLAG(es->flags, ZEBRA_EVPNES_LOCAL))
2232 return;
2233
2234 if (IS_ZEBRA_DEBUG_EVPN_MH_ES) {
2235 zif = es->zif;
dfa3d3d7
AK
2236 zlog_debug("local es %s del; nhg %u if %s", es->esi_str,
2237 es->nhg_id, zif ? zif->ifp->name : "-");
ce5160c0
AK
2238 }
2239
2240 /* remove all ES-EVIs associated with the ES */
2241 for (ALL_LIST_ELEMENTS(es->es_evi_list, node, nnode, es_evi))
2242 zebra_evpn_local_es_evi_do_del(es_evi);
2243
2244 /* send a del if the ES had been sent to BGP earlier */
2245 if (es->flags & ZEBRA_EVPNES_READY_FOR_BGP)
2246 zebra_evpn_es_send_del_to_client(es);
2247
e378f502 2248 zebra_evpn_es_local_info_clear(esp);
ce5160c0
AK
2249}
2250
2251/* eval remote info associated with the ES */
e378f502 2252static void zebra_evpn_es_remote_info_re_eval(struct zebra_evpn_es **esp)
ce5160c0 2253{
e378f502
AK
2254 struct zebra_evpn_es *es = *esp;
2255
ce5160c0
AK
2256 /* if there are remote VTEPs the ES-EVI is classified as "remote" */
2257 if (listcount(es->es_vtep_list)) {
2258 if (!(es->flags & ZEBRA_EVPNES_REMOTE)) {
2259 es->flags |= ZEBRA_EVPNES_REMOTE;
2260 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
dfa3d3d7
AK
2261 zlog_debug("remote es %s add; nhg %u",
2262 es->esi_str, es->nhg_id);
ce5160c0
AK
2263 }
2264 } else {
2265 if (es->flags & ZEBRA_EVPNES_REMOTE) {
2266 es->flags &= ~ZEBRA_EVPNES_REMOTE;
2267 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
dfa3d3d7
AK
2268 zlog_debug("remote es %s del; nhg %u",
2269 es->esi_str, es->nhg_id);
e378f502 2270 zebra_evpn_es_free(esp);
ce5160c0
AK
2271 }
2272 }
2273}
2274
2275/* A new local es is created when a local-es-id and sysmac is configured
2276 * against an interface.
2277 */
325d694b 2278static int zebra_evpn_local_es_update(struct zebra_if *zif, esi_t *esi)
ce5160c0
AK
2279{
2280 struct zebra_evpn_es *old_es = zif->es_info.es;
2281 struct zebra_evpn_es *es;
325d694b
AK
2282
2283 memcpy(&zif->es_info.esi, esi, sizeof(*esi));
2284 if (old_es && !memcmp(&old_es->esi, esi, sizeof(*esi)))
2285 /* dup - nothing to be done */
2286 return 0;
2287
2288 /* release the old_es against the zif */
2289 if (old_es)
2290 zebra_evpn_local_es_del(&old_es);
2291
2292 es = zebra_evpn_es_find(esi);
2293 if (es) {
2294 /* if it exists against another interface flag an error */
2295 if (es->zif && es->zif != zif) {
2296 memset(&zif->es_info.esi, 0, sizeof(*esi));
2297 return -1;
2298 }
2299 } else {
2300 /* create new es */
2301 es = zebra_evpn_es_new(esi);
2302 }
2303
2304 if (es)
2305 zebra_evpn_es_local_info_set(es, zif);
2306
2307 return 0;
2308}
2309
2310static int zebra_evpn_type3_esi_update(struct zebra_if *zif, uint32_t lid,
2311 struct ethaddr *sysmac)
2312{
2313 struct zebra_evpn_es *old_es = zif->es_info.es;
ce5160c0
AK
2314 esi_t esi;
2315 int offset = 0;
2316 int field_bytes = 0;
2317
2318 /* Complete config of the ES-ID bootstraps the ES */
2319 if (!lid || is_zero_mac(sysmac)) {
325d694b
AK
2320 /* clear old esi */
2321 memset(&zif->es_info.esi, 0, sizeof(zif->es_info.esi));
ce5160c0
AK
2322 /* if in ES is attached to zif delete it */
2323 if (old_es)
ab06b033 2324 zebra_evpn_local_es_del(&old_es);
ce5160c0
AK
2325 return 0;
2326 }
2327
2328 /* build 10-byte type-3-ESI -
2329 * Type(1-byte), MAC(6-bytes), ES-LID (3-bytes)
2330 */
2331 field_bytes = 1;
2332 esi.val[offset] = ESI_TYPE_MAC;
2333 offset += field_bytes;
2334
2335 field_bytes = ETH_ALEN;
2336 memcpy(&esi.val[offset], (uint8_t *)sysmac, field_bytes);
2337 offset += field_bytes;
2338
2339 esi.val[offset++] = (uint8_t)(lid >> 16);
2340 esi.val[offset++] = (uint8_t)(lid >> 8);
2341 esi.val[offset++] = (uint8_t)lid;
2342
325d694b 2343 return zebra_evpn_local_es_update(zif, &esi);
ce5160c0
AK
2344}
2345
2346static int zebra_evpn_remote_es_del(esi_t *esi, struct in_addr vtep_ip)
2347{
2348 char buf[ESI_STR_LEN];
2349 struct zebra_evpn_es *es;
2350
2351 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
9bcef951
MS
2352 zlog_debug("remote es %s vtep %pI4 del",
2353 esi_to_str(esi, buf, sizeof(buf)), &vtep_ip);
ce5160c0
AK
2354
2355 es = zebra_evpn_es_find(esi);
2356 if (!es) {
4d8b658c 2357 zlog_warn("remote es %s vtep %pI4 del failed, es missing",
e378f502 2358 esi_to_str(esi, buf, sizeof(buf)), &vtep_ip);
ce5160c0
AK
2359 return -1;
2360 }
2361
2362 zebra_evpn_es_vtep_del(es, vtep_ip);
e378f502 2363 zebra_evpn_es_remote_info_re_eval(&es);
ce5160c0
AK
2364
2365 return 0;
2366}
2367
2368/* force delete a remote ES on the way down */
e378f502 2369static void zebra_evpn_remote_es_flush(struct zebra_evpn_es **esp)
ce5160c0
AK
2370{
2371 struct zebra_evpn_es_vtep *es_vtep;
2372 struct listnode *node;
2373 struct listnode *nnode;
e378f502 2374 struct zebra_evpn_es *es = *esp;
ce5160c0
AK
2375
2376 for (ALL_LIST_ELEMENTS(es->es_vtep_list, node, nnode, es_vtep)) {
2377 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
9bcef951 2378 zlog_debug("es %s vtep %pI4 flush",
ce5160c0 2379 es->esi_str,
9bcef951 2380 &es_vtep->vtep_ip);
ce5160c0 2381 zebra_evpn_es_vtep_free(es_vtep);
ce5160c0 2382 }
e378f502 2383 zebra_evpn_es_remote_info_re_eval(esp);
ce5160c0
AK
2384}
2385
1103c5c6
AK
2386static int zebra_evpn_remote_es_add(esi_t *esi, struct in_addr vtep_ip,
2387 bool esr_rxed, uint8_t df_alg,
2388 uint16_t df_pref)
ce5160c0
AK
2389{
2390 char buf[ESI_STR_LEN];
2391 struct zebra_evpn_es *es;
2392
2393 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1103c5c6
AK
2394 zlog_debug("remote es %s vtep %pI4 add %s df_alg %d df_pref %d",
2395 esi_to_str(esi, buf, sizeof(buf)),
2396 &vtep_ip, esr_rxed ? "esr" : "", df_alg,
2397 df_pref);
ce5160c0
AK
2398
2399 es = zebra_evpn_es_find(esi);
2400 if (!es) {
2401 es = zebra_evpn_es_new(esi);
2402 if (!es) {
e378f502
AK
2403 zlog_warn(
2404 "remote es %s vtep %pI4 add failed, es missing",
2405 esi_to_str(esi, buf, sizeof(buf)), &vtep_ip);
ce5160c0
AK
2406 return -1;
2407 }
2408 }
2409
28e80a03 2410 if (df_alg != EVPN_MH_DF_ALG_PREF)
2747f6f7
AK
2411 zlog_warn(
2412 "remote es %s vtep %pI4 add %s with unsupported df_alg %d",
2413 esi_to_str(esi, buf, sizeof(buf)), &vtep_ip,
2414 esr_rxed ? "esr" : "", df_alg);
28e80a03 2415
1103c5c6 2416 zebra_evpn_es_vtep_add(es, vtep_ip, esr_rxed, df_alg, df_pref);
e378f502 2417 zebra_evpn_es_remote_info_re_eval(&es);
ce5160c0
AK
2418
2419 return 0;
2420}
2421
2422void zebra_evpn_proc_remote_es(ZAPI_HANDLER_ARGS)
2423{
2424 struct stream *s;
2425 struct in_addr vtep_ip;
2426 esi_t esi;
2427
2428 if (!is_evpn_enabled()) {
2429 zlog_debug(
2430 "%s: EVPN not enabled yet we received a es_add zapi call",
2431 __PRETTY_FUNCTION__);
2432 return;
2433 }
2434
2435 memset(&esi, 0, sizeof(esi_t));
2436 s = msg;
2437
2438 stream_get(&esi, s, sizeof(esi_t));
2439 vtep_ip.s_addr = stream_get_ipv4(s);
2440
1103c5c6
AK
2441 if (hdr->command == ZEBRA_REMOTE_ES_VTEP_ADD) {
2442 uint32_t zapi_flags;
2443 uint8_t df_alg;
2444 uint16_t df_pref;
2445 bool esr_rxed;
2446
2447 zapi_flags = stream_getl(s);
2448 esr_rxed = (zapi_flags & ZAPI_ES_VTEP_FLAG_ESR_RXED) ? true
2449 : false;
2450 df_alg = stream_getc(s);
2451 df_pref = stream_getw(s);
2452 zebra_evpn_remote_es_add(&esi, vtep_ip, esr_rxed, df_alg,
2453 df_pref);
2454 } else {
ce5160c0 2455 zebra_evpn_remote_es_del(&esi, vtep_ip);
1103c5c6 2456 }
ce5160c0
AK
2457}
2458
2459void zebra_evpn_es_mac_deref_entry(zebra_mac_t *mac)
2460{
2461 struct zebra_evpn_es *es = mac->es;
2462
2463 mac->es = NULL;
b169fd6f 2464 if (!es)
ce5160c0
AK
2465 return;
2466
b169fd6f
AK
2467 list_delete_node(es->mac_list, &mac->es_listnode);
2468 if (!listcount(es->mac_list))
e378f502 2469 zebra_evpn_es_free(&es);
ce5160c0
AK
2470}
2471
2472/* Associate a MAC entry with a local or remote ES. Returns false if there
2473 * was no ES change.
2474 */
2475bool zebra_evpn_es_mac_ref_entry(zebra_mac_t *mac, struct zebra_evpn_es *es)
2476{
2477 if (mac->es == es)
2478 return false;
2479
2480 if (mac->es)
2481 zebra_evpn_es_mac_deref_entry(mac);
2482
2483 if (!es)
2484 return true;
2485
2486 mac->es = es;
b169fd6f
AK
2487 listnode_init(&mac->es_listnode, mac);
2488 listnode_add(es->mac_list, &mac->es_listnode);
2489
ce5160c0
AK
2490 return true;
2491}
2492
b169fd6f 2493bool zebra_evpn_es_mac_ref(zebra_mac_t *mac, esi_t *esi)
ce5160c0
AK
2494{
2495 struct zebra_evpn_es *es;
2496
2497 es = zebra_evpn_es_find(esi);
2498 if (!es) {
4cd94050
AK
2499 /* If non-zero esi implicitly create a new ES */
2500 if (memcmp(esi, zero_esi, sizeof(esi_t))) {
2501 es = zebra_evpn_es_new(esi);
2502 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
2503 zlog_debug("auto es %s add on mac ref",
2504 es->esi_str);
2505 }
ce5160c0
AK
2506 }
2507
b169fd6f 2508 return zebra_evpn_es_mac_ref_entry(mac, es);
ce5160c0
AK
2509}
2510
2511/* Inform BGP about local ES-EVI add or del */
2512static int zebra_evpn_es_evi_send_to_client(struct zebra_evpn_es *es,
87d76d54 2513 zebra_evpn_t *zevpn, bool add)
ce5160c0
AK
2514{
2515 struct zserv *client;
2516 struct stream *s;
2517
2518 client = zserv_find_client(ZEBRA_ROUTE_BGP, 0);
2519 /* BGP may not be running. */
2520 if (!client)
2521 return 0;
2522
2523 s = stream_new(ZEBRA_MAX_PACKET_SIZ);
2524
2525 zclient_create_header(s,
2526 add ? ZEBRA_LOCAL_ES_EVI_ADD : ZEBRA_LOCAL_ES_EVI_DEL,
2527 zebra_vrf_get_evpn_id());
2528 stream_put(s, &es->esi, sizeof(esi_t));
87d76d54 2529 stream_putl(s, zevpn->vni);
ce5160c0
AK
2530
2531 /* Write packet size. */
2532 stream_putw_at(s, 0, stream_get_endp(s));
2533
2534 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
2535 zlog_debug("send %s local es %s evi %u to %s",
2536 add ? "add" : "del",
87d76d54 2537 es->esi_str, zevpn->vni,
ce5160c0
AK
2538 zebra_route_string(client->proto));
2539
2540 client->local_es_add_cnt++;
2541 return zserv_send_message(client, s);
2542}
2543
2544/* sysmac part of a local ESI has changed */
2545static int zebra_evpn_es_sys_mac_update(struct zebra_if *zif,
2546 struct ethaddr *sysmac)
2547{
2548 int rv;
2549
325d694b 2550 rv = zebra_evpn_type3_esi_update(zif, zif->es_info.lid, sysmac);
ce5160c0
AK
2551 if (!rv)
2552 memcpy(&zif->es_info.sysmac, sysmac, sizeof(struct ethaddr));
2553
2554 return rv;
2555}
2556
2557/* local-ID part of ESI has changed */
2558static int zebra_evpn_es_lid_update(struct zebra_if *zif, uint32_t lid)
2559{
2560 int rv;
2561
325d694b 2562 rv = zebra_evpn_type3_esi_update(zif, lid, &zif->es_info.sysmac);
ce5160c0
AK
2563 if (!rv)
2564 zif->es_info.lid = lid;
2565
2566 return rv;
2567}
2568
325d694b
AK
2569/* type-0 esi has changed */
2570static int zebra_evpn_es_type0_esi_update(struct zebra_if *zif, esi_t *esi)
2571{
2572 int rv;
2573
2574 rv = zebra_evpn_local_es_update(zif, esi);
2575
2576 /* clear the old es_lid, es_sysmac - type-0 is being set so old
2577 * type-3 params need to be flushed
2578 */
2579 memset(&zif->es_info.sysmac, 0, sizeof(struct ethaddr));
2580 zif->es_info.lid = 0;
2581
2582 return rv;
2583}
2584
ce5160c0
AK
2585void zebra_evpn_es_cleanup(void)
2586{
2587 struct zebra_evpn_es *es;
2588 struct zebra_evpn_es *es_next;
2589
2590 RB_FOREACH_SAFE(es, zebra_es_rb_head,
2591 &zmh_info->es_rb_tree, es_next) {
e378f502
AK
2592 zebra_evpn_local_es_del(&es);
2593 if (es)
2594 zebra_evpn_remote_es_flush(&es);
ce5160c0
AK
2595 }
2596}
2597
1103c5c6
AK
2598static void zebra_evpn_es_df_pref_update(struct zebra_if *zif, uint16_t df_pref)
2599{
2600 struct zebra_evpn_es *es;
2601 uint16_t tmp_pref;
2602
2603 if (zif->es_info.df_pref == df_pref)
2604 return;
2605
2606 zif->es_info.df_pref = df_pref;
2607 es = zif->es_info.es;
2608
2609 if (!es)
2610 return;
2611
2612 tmp_pref = zif->es_info.df_pref ? zif->es_info.df_pref
2613 : EVPN_MH_DF_PREF_DEFAULT;
2614
2615 if (es->df_pref == tmp_pref)
2616 return;
2617
2618 es->df_pref = tmp_pref;
2619 /* run df election */
2620 zebra_evpn_es_run_df_election(es, __func__);
2621 /* notify bgp */
2622 if (es->flags & ZEBRA_EVPNES_READY_FOR_BGP)
2623 zebra_evpn_es_send_add_to_client(es);
2624}
2625
2626
ce5160c0
AK
2627/* Only certain types of access ports can be setup as an Ethernet Segment */
2628bool zebra_evpn_is_if_es_capable(struct zebra_if *zif)
2629{
2630 if (zif->zif_type == ZEBRA_IF_BOND)
2631 return true;
2632
2633 /* XXX: allow swpX i.e. a regular ethernet port to be an ES link too */
2634 return false;
2635}
2636
2637void zebra_evpn_if_es_print(struct vty *vty, struct zebra_if *zif)
2638{
2639 char buf[ETHER_ADDR_STRLEN];
c36e442c
AK
2640 char mh_buf[80];
2641 bool vty_print = false;
325d694b 2642 char esi_buf[ESI_STR_LEN];
c36e442c
AK
2643
2644 mh_buf[0] = '\0';
2bcf92e1 2645 strlcat(mh_buf, " EVPN-MH:", sizeof(mh_buf));
c36e442c
AK
2646 if (zif->es_info.lid || !is_zero_mac(&zif->es_info.sysmac)) {
2647 vty_print = true;
2648 snprintf(
2649 mh_buf + strlen(mh_buf),
2650 sizeof(mh_buf) - strlen(mh_buf),
2651 " ES id %u ES sysmac %s", zif->es_info.lid,
2652 prefix_mac2str(&zif->es_info.sysmac, buf, sizeof(buf)));
325d694b
AK
2653 } else if (memcmp(&zif->es_info.esi, zero_esi, sizeof(*zero_esi))) {
2654 vty_print = true;
2655 snprintf(mh_buf + strnlen(mh_buf, sizeof(mh_buf)),
2656 sizeof(mh_buf) - strnlen(mh_buf, sizeof(mh_buf)),
2657 " ES id %s",
2658 esi_to_str(&zif->es_info.esi, esi_buf,
2659 sizeof(esi_buf)));
c36e442c
AK
2660 }
2661
2662 if (zif->flags & ZIF_FLAG_EVPN_MH_UPLINK) {
2663 vty_print = true;
2664 if (zif->flags & ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP)
2bcf92e1 2665 strlcat(mh_buf, " uplink (up)", sizeof(mh_buf));
c36e442c 2666 else
2bcf92e1 2667 strlcat(mh_buf, " uplink (down)", sizeof(mh_buf));
c36e442c 2668 }
ce5160c0 2669
c36e442c
AK
2670 if (vty_print)
2671 vty_out(vty, "%s\n", mh_buf);
ce5160c0
AK
2672}
2673
1a4f9efd
AK
2674static void zebra_evpn_local_mac_oper_state_change(struct zebra_evpn_es *es)
2675{
2676 zebra_mac_t *mac;
2677 struct listnode *node;
2678
2679 /* If fast-failover is supported by the dataplane via the use
2680 * of an ES backup NHG there is nothing to be done in the
2681 * control plane
2682 */
2683 if (!(zmh_info->flags & ZEBRA_EVPN_MH_REDIRECT_OFF))
2684 return;
2685
2686 if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_EVPN_MH_MAC)
2687 zlog_debug("mac slow-fail on es %s %s ", es->esi_str,
2688 (es->flags & ZEBRA_EVPNES_OPER_UP) ? "up" : "down");
2689
2690 for (ALL_LIST_ELEMENTS_RO(es->mac_list, node, mac)) {
2691 if (!(mac->flags & ZEBRA_MAC_LOCAL)
2692 || !zebra_evpn_mac_is_static(mac))
2693 continue;
2694
2695 if (es->flags & ZEBRA_EVPNES_OPER_UP) {
2696 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
2697 zlog_debug(
2698 "VNI %u mac %pEA move to acc %s es %s %s ",
2699 mac->zevpn->vni,
2700 &mac->macaddr,
2701 es->zif->ifp->name, es->esi_str,
2702 (es->flags & ZEBRA_EVPNES_OPER_UP)
2703 ? "up"
2704 : "down");
2705 /* switch the local macs to access port */
2706 if (zebra_evpn_sync_mac_dp_install(
2707 mac, false /*set_inactive*/,
2708 false /*force_clear_static*/, __func__)
2709 < 0)
2710 /* if the local mac install fails get rid of the
2711 * old rem entry
2712 */
2713 zebra_evpn_rem_mac_uninstall(mac->zevpn, mac,
2714 true /*force*/);
2715 } else {
2716 /* switch the local macs to network port. if there
2717 * is no active NHG we don't bother deleting the MAC;
2718 * that is left up to the dataplane to handle.
2719 */
2720 if (!(es->flags & ZEBRA_EVPNES_NHG_ACTIVE))
2721 continue;
2722 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
2723 zlog_debug(
2724 "VNI %u mac %pEA move to nhg %u es %s %s ",
2725 mac->zevpn->vni,
2726 &mac->macaddr,
2727 es->nhg_id, es->esi_str,
2728 (es->flags & ZEBRA_EVPNES_OPER_UP)
2729 ? "up"
2730 : "down");
2731 zebra_evpn_rem_mac_install(mac->zevpn, mac,
2732 true /*was_static*/);
2733 }
2734 }
2735}
2736
ce5160c0
AK
2737void zebra_evpn_es_if_oper_state_change(struct zebra_if *zif, bool up)
2738{
2739 struct zebra_evpn_es *es = zif->es_info.es;
2740 bool old_up = !!(es->flags & ZEBRA_EVPNES_OPER_UP);
2741
2742 if (old_up == up)
2743 return;
2744
2745 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
2746 zlog_debug("es %s state changed to %s ",
2747 es->esi_str,
2748 up ? "up" : "down");
2749 if (up)
2750 es->flags |= ZEBRA_EVPNES_OPER_UP;
2751 else
2752 es->flags &= ~ZEBRA_EVPNES_OPER_UP;
2753
1103c5c6 2754 zebra_evpn_es_run_df_election(es, __func__);
15400f95 2755 zebra_evpn_local_mac_oper_state_change(es);
1103c5c6 2756
ce5160c0
AK
2757 /* inform BGP of the ES oper state change */
2758 if (es->flags & ZEBRA_EVPNES_READY_FOR_BGP)
2759 zebra_evpn_es_send_add_to_client(es);
2760}
2761
9e0c2fd1
AK
2762static char *zebra_evpn_es_vtep_str(char *vtep_str, struct zebra_evpn_es *es,
2763 uint8_t vtep_str_size)
ce5160c0
AK
2764{
2765 struct zebra_evpn_es_vtep *zvtep;
2766 struct listnode *node;
2767 bool first = true;
2747f6f7 2768 char ip_buf[INET6_ADDRSTRLEN];
ce5160c0
AK
2769
2770 vtep_str[0] = '\0';
2771 for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, zvtep)) {
2772 if (first) {
2773 first = false;
2747f6f7
AK
2774 strlcat(vtep_str,
2775 inet_ntop(AF_INET, &zvtep->vtep_ip, ip_buf,
2776 sizeof(ip_buf)),
9e0c2fd1 2777 vtep_str_size);
ce5160c0 2778 } else {
9e0c2fd1 2779 strlcat(vtep_str, ",", vtep_str_size);
2747f6f7
AK
2780 strlcat(vtep_str,
2781 inet_ntop(AF_INET, &zvtep->vtep_ip, ip_buf,
2782 sizeof(ip_buf)),
9e0c2fd1 2783 vtep_str_size);
ce5160c0
AK
2784 }
2785 }
2786 return vtep_str;
2787}
2788
acffa256
AK
2789static void zebra_evpn_es_json_vtep_fill(struct zebra_evpn_es *es,
2790 json_object *json_vteps)
2791{
2792 struct zebra_evpn_es_vtep *es_vtep;
2793 struct listnode *node;
2794 json_object *json_vtep_entry;
2795 char alg_buf[EVPN_DF_ALG_STR_LEN];
2747f6f7 2796 char ip_buf[INET6_ADDRSTRLEN];
acffa256
AK
2797
2798 for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
2799 json_vtep_entry = json_object_new_object();
2800 json_object_string_add(json_vtep_entry, "vtep",
2747f6f7
AK
2801 inet_ntop(AF_INET, &es_vtep->vtep_ip,
2802 ip_buf, sizeof(ip_buf)));
acffa256
AK
2803 if (es_vtep->flags & ZEBRA_EVPNES_VTEP_RXED_ESR) {
2804 json_object_string_add(
2805 json_vtep_entry, "dfAlgorithm",
2806 evpn_es_df_alg2str(es_vtep->df_alg, alg_buf,
2807 sizeof(alg_buf)));
2808 json_object_int_add(json_vtep_entry, "dfPreference",
2809 es_vtep->df_pref);
2810 }
5de10c37
AK
2811 if (es_vtep->nh)
2812 json_object_int_add(json_vtep_entry, "nexthopId",
2813 es_vtep->nh->nh_id);
acffa256
AK
2814 json_object_array_add(json_vteps, json_vtep_entry);
2815 }
2816}
2817
2818static void zebra_evpn_es_show_entry(struct vty *vty, struct zebra_evpn_es *es,
2819 json_object *json_array)
ce5160c0
AK
2820{
2821 char type_str[4];
2822 char vtep_str[ES_VTEP_LIST_STR_SZ];
2823
acffa256
AK
2824 if (json_array) {
2825 json_object *json = NULL;
2826 json_object *json_vteps;
2827 json_object *json_flags;
2828
2829 json = json_object_new_object();
2830 json_object_string_add(json, "esi", es->esi_str);
2831
2832 if (es->flags
2833 & (ZEBRA_EVPNES_LOCAL | ZEBRA_EVPNES_REMOTE
2834 | ZEBRA_EVPNES_NON_DF)) {
2835 json_flags = json_object_new_array();
2836 if (es->flags & ZEBRA_EVPNES_LOCAL)
2837 json_array_string_add(json_flags, "local");
2838 if (es->flags & ZEBRA_EVPNES_REMOTE)
2839 json_array_string_add(json_flags, "remote");
2840 if (es->flags & ZEBRA_EVPNES_NON_DF)
2841 json_array_string_add(json_flags, "nonDF");
2842 json_object_object_add(json, "flags", json_flags);
2843 }
2844
2845 if (es->zif)
2846 json_object_string_add(json, "accessPort",
2847 es->zif->ifp->name);
2848
2849 if (listcount(es->es_vtep_list)) {
2850 json_vteps = json_object_new_array();
2851 zebra_evpn_es_json_vtep_fill(es, json_vteps);
2852 json_object_object_add(json, "vteps", json_vteps);
2853 }
2854 json_object_array_add(json_array, json);
ce5160c0
AK
2855 } else {
2856 type_str[0] = '\0';
2857 if (es->flags & ZEBRA_EVPNES_LOCAL)
9e0c2fd1 2858 strlcat(type_str, "L", sizeof(type_str));
ce5160c0 2859 if (es->flags & ZEBRA_EVPNES_REMOTE)
9e0c2fd1 2860 strlcat(type_str, "R", sizeof(type_str));
1103c5c6
AK
2861 if (es->flags & ZEBRA_EVPNES_NON_DF)
2862 strlcat(type_str, "N", sizeof(type_str));
ce5160c0 2863
9e0c2fd1 2864 zebra_evpn_es_vtep_str(vtep_str, es, sizeof(vtep_str));
ce5160c0
AK
2865
2866 vty_out(vty, "%-30s %-4s %-21s %s\n",
2867 es->esi_str, type_str,
2868 es->zif ? es->zif->ifp->name : "-",
2869 vtep_str);
2870 }
2871}
2872
2873static void zebra_evpn_es_show_entry_detail(struct vty *vty,
2874 struct zebra_evpn_es *es, json_object *json)
2875{
2876 char type_str[80];
1103c5c6
AK
2877 char alg_buf[EVPN_DF_ALG_STR_LEN];
2878 struct zebra_evpn_es_vtep *es_vtep;
ce5160c0 2879 struct listnode *node;
35f5c31b 2880 char thread_buf[THREAD_TIMER_STRLEN];
ce5160c0
AK
2881
2882 if (json) {
acffa256
AK
2883 json_object *json_vteps;
2884 json_object *json_flags;
2885
2886 json_object_string_add(json, "esi", es->esi_str);
2887 if (es->zif)
2888 json_object_string_add(json, "accessPort",
2889 es->zif->ifp->name);
2890
2891
2892 if (es->flags) {
2893 json_flags = json_object_new_array();
2894 if (es->flags & ZEBRA_EVPNES_LOCAL)
2895 json_array_string_add(json_flags, "local");
2896 if (es->flags & ZEBRA_EVPNES_REMOTE)
2897 json_array_string_add(json_flags, "remote");
2898 if (es->flags & ZEBRA_EVPNES_NON_DF)
2899 json_array_string_add(json_flags, "nonDF");
2900 if (es->flags & ZEBRA_EVPNES_READY_FOR_BGP)
2901 json_array_string_add(json_flags,
2902 "readyForBgp");
2903 if (es->flags & ZEBRA_EVPNES_BR_PORT)
2904 json_array_string_add(json_flags, "bridgePort");
2905 if (es->flags & ZEBRA_EVPNES_OPER_UP)
2906 json_array_string_add(json_flags, "operUp");
2907 if (es->flags & ZEBRA_EVPNES_NHG_ACTIVE)
2908 json_array_string_add(json_flags,
2909 "nexthopGroupActive");
2910 json_object_object_add(json, "flags", json_flags);
2911 }
2912
2913 json_object_int_add(json, "vniCount",
2914 listcount(es->es_evi_list));
2915 json_object_int_add(json, "macCount", listcount(es->mac_list));
2916 json_object_int_add(json, "dfPreference", es->df_pref);
35f5c31b
AK
2917 if (es->df_delay_timer)
2918 json_object_string_add(
2919 json, "dfDelayTimer",
2920 thread_timer_to_hhmmss(thread_buf,
2921 sizeof(thread_buf),
2922 es->df_delay_timer));
acffa256
AK
2923 json_object_int_add(json, "nexthopGroup", es->nhg_id);
2924 if (listcount(es->es_vtep_list)) {
2925 json_vteps = json_object_new_array();
2926 zebra_evpn_es_json_vtep_fill(es, json_vteps);
2927 json_object_object_add(json, "vteps", json_vteps);
2928 }
ce5160c0
AK
2929 } else {
2930 type_str[0] = '\0';
2931 if (es->flags & ZEBRA_EVPNES_LOCAL)
9e0c2fd1 2932 strlcat(type_str, "Local", sizeof(type_str));
ce5160c0 2933 if (es->flags & ZEBRA_EVPNES_REMOTE) {
9e0c2fd1
AK
2934 if (strnlen(type_str, sizeof(type_str)))
2935 strlcat(type_str, ",", sizeof(type_str));
2936 strlcat(type_str, "Remote", sizeof(type_str));
ce5160c0
AK
2937 }
2938
2939 vty_out(vty, "ESI: %s\n", es->esi_str);
2940 vty_out(vty, " Type: %s\n", type_str);
2941 vty_out(vty, " Interface: %s\n",
2942 (es->zif) ?
2943 es->zif->ifp->name : "-");
72f2674a
AK
2944 if (es->flags & ZEBRA_EVPNES_LOCAL) {
2945 vty_out(vty, " State: %s\n",
2946 (es->flags & ZEBRA_EVPNES_OPER_UP) ? "up"
2947 : "down");
2948 vty_out(vty, " Bridge port: %s\n",
2949 (es->flags & ZEBRA_EVPNES_BR_PORT) ? "yes"
2950 : "no");
2951 }
ce5160c0
AK
2952 vty_out(vty, " Ready for BGP: %s\n",
2953 (es->flags & ZEBRA_EVPNES_READY_FOR_BGP) ?
2954 "yes" : "no");
2955 vty_out(vty, " VNI Count: %d\n", listcount(es->es_evi_list));
b169fd6f 2956 vty_out(vty, " MAC Count: %d\n", listcount(es->mac_list));
35f5c31b
AK
2957 if (es->flags & ZEBRA_EVPNES_LOCAL)
2958 vty_out(vty, " DF status: %s \n",
2959 (es->flags & ZEBRA_EVPNES_NON_DF) ? "non-df"
2960 : "df");
2961 if (es->df_delay_timer)
2962 vty_out(vty, " DF delay: %s\n",
2963 thread_timer_to_hhmmss(thread_buf,
2964 sizeof(thread_buf),
2965 es->df_delay_timer));
2966 vty_out(vty, " DF preference: %u\n", es->df_pref);
dfa3d3d7 2967 vty_out(vty, " Nexthop group: %u\n", es->nhg_id);
ce5160c0 2968 vty_out(vty, " VTEPs:\n");
1103c5c6
AK
2969 for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
2970 vty_out(vty, " %pI4",
2971 &es_vtep->vtep_ip);
2972 if (es_vtep->flags & ZEBRA_EVPNES_VTEP_RXED_ESR)
2973 vty_out(vty, " df_alg: %s df_pref: %d",
2974 evpn_es_df_alg2str(es_vtep->df_alg,
2975 alg_buf,
2976 sizeof(alg_buf)),
2977 es_vtep->df_pref);
5de10c37
AK
2978 vty_out(vty, " nh: %u\n",
2979 es_vtep->nh ? es_vtep->nh->nh_id : 0);
1103c5c6 2980 }
ce5160c0
AK
2981
2982 vty_out(vty, "\n");
2983 }
2984}
2985
2986void zebra_evpn_es_show(struct vty *vty, bool uj)
2987{
2988 struct zebra_evpn_es *es;
acffa256 2989 json_object *json_array = NULL;
ce5160c0
AK
2990
2991 if (uj) {
acffa256 2992 json_array = json_object_new_array();
ce5160c0 2993 } else {
1103c5c6 2994 vty_out(vty, "Type: L local, R remote, N non-DF\n");
ce5160c0
AK
2995 vty_out(vty, "%-30s %-4s %-21s %s\n",
2996 "ESI", "Type", "ES-IF", "VTEPs");
2997 }
2998
2999 RB_FOREACH(es, zebra_es_rb_head, &zmh_info->es_rb_tree)
acffa256
AK
3000 zebra_evpn_es_show_entry(vty, es, json_array);
3001
3002 if (uj) {
3003 vty_out(vty, "%s\n",
3004 json_object_to_json_string_ext(
3005 json_array, JSON_C_TO_STRING_PRETTY));
3006 json_object_free(json_array);
3007 }
ce5160c0
AK
3008}
3009
3010void zebra_evpn_es_show_detail(struct vty *vty, bool uj)
3011{
3012 struct zebra_evpn_es *es;
acffa256 3013 json_object *json_array = NULL;
ce5160c0 3014
acffa256
AK
3015 if (uj)
3016 json_array = json_object_new_array();
3017
3018 RB_FOREACH (es, zebra_es_rb_head, &zmh_info->es_rb_tree) {
3019 json_object *json = NULL;
3020
3021 if (uj)
3022 json = json_object_new_object();
ce5160c0 3023 zebra_evpn_es_show_entry_detail(vty, es, json);
acffa256
AK
3024 if (uj)
3025 json_object_array_add(json_array, json);
3026 }
3027
3028 if (uj) {
3029 vty_out(vty, "%s\n",
3030 json_object_to_json_string_ext(
3031 json_array, JSON_C_TO_STRING_PRETTY));
3032 json_object_free(json_array);
3033 }
ce5160c0
AK
3034}
3035
3036void zebra_evpn_es_show_esi(struct vty *vty, bool uj, esi_t *esi)
3037{
3038 struct zebra_evpn_es *es;
3039 char esi_str[ESI_STR_LEN];
3040 json_object *json = NULL;
3041
acffa256
AK
3042 if (uj)
3043 json = json_object_new_object();
3044
ce5160c0
AK
3045 es = zebra_evpn_es_find(esi);
3046
acffa256
AK
3047 if (es) {
3048 zebra_evpn_es_show_entry_detail(vty, es, json);
3049 } else {
3050 if (!uj) {
3051 esi_to_str(esi, esi_str, sizeof(esi_str));
3052 vty_out(vty, "ESI %s does not exist\n", esi_str);
3053 }
ce5160c0
AK
3054 }
3055
acffa256
AK
3056 if (uj) {
3057 vty_out(vty, "%s\n",
3058 json_object_to_json_string_ext(
3059 json, JSON_C_TO_STRING_PRETTY));
3060 json_object_free(json);
3061 }
ce5160c0
AK
3062}
3063
3064int zebra_evpn_mh_if_write(struct vty *vty, struct interface *ifp)
3065{
3066 struct zebra_if *zif = ifp->info;
3067 char buf[ETHER_ADDR_STRLEN];
325d694b
AK
3068 bool type_3_esi = false;
3069 char esi_buf[ESI_STR_LEN];
ce5160c0 3070
325d694b 3071 if (zif->es_info.lid) {
ce5160c0 3072 vty_out(vty, " evpn mh es-id %u\n", zif->es_info.lid);
325d694b
AK
3073 type_3_esi = true;
3074 }
ce5160c0 3075
325d694b 3076 if (!is_zero_mac(&zif->es_info.sysmac)) {
ce5160c0
AK
3077 vty_out(vty, " evpn mh es-sys-mac %s\n",
3078 prefix_mac2str(&zif->es_info.sysmac,
3079 buf, sizeof(buf)));
325d694b
AK
3080 type_3_esi = true;
3081 }
3082
3083 if (!type_3_esi
3084 && memcmp(&zif->es_info.esi, zero_esi, sizeof(*zero_esi)))
3085 vty_out(vty, " evpn mh es-id %s\n",
3086 esi_to_str(&zif->es_info.esi, esi_buf, sizeof(esi_buf)));
1103c5c6
AK
3087
3088 if (zif->es_info.df_pref)
3089 vty_out(vty, " evpn mh es-df-pref %u\n", zif->es_info.df_pref);
3090
c36e442c
AK
3091 if (zif->flags & ZIF_FLAG_EVPN_MH_UPLINK)
3092 vty_out(vty, " evpn mh uplink\n");
3093
ce5160c0
AK
3094 return 0;
3095}
3096
3097#ifndef VTYSH_EXTRACT_PL
3098#include "zebra/zebra_evpn_mh_clippy.c"
3099#endif
1103c5c6
AK
3100/* CLI for configuring DF preference part for an ES */
3101DEFPY(zebra_evpn_es_pref, zebra_evpn_es_pref_cmd,
3102 "[no$no] evpn mh es-df-pref [(1-65535)$df_pref]",
3103 NO_STR "EVPN\n" EVPN_MH_VTY_STR
3104 "preference value used for DF election\n"
3105 "ID\n")
3106{
3107 VTY_DECLVAR_CONTEXT(interface, ifp);
3108 struct zebra_if *zif;
3109
3110 zif = ifp->info;
3111
3112 if (no) {
3113 zebra_evpn_es_df_pref_update(zif, 0);
3114 } else {
3115 if (!zebra_evpn_is_if_es_capable(zif)) {
3116 vty_out(vty,
3117 "%%DF preference cannot be associated with this interface type\n");
3118 return CMD_WARNING;
3119 }
3120 zebra_evpn_es_df_pref_update(zif, df_pref);
3121 }
3122 return CMD_SUCCESS;
3123}
3124
ce5160c0
AK
3125/* CLI for setting up sysmac part of ESI on an access port */
3126DEFPY(zebra_evpn_es_sys_mac,
3127 zebra_evpn_es_sys_mac_cmd,
3128 "[no$no] evpn mh es-sys-mac [X:X:X:X:X:X$mac]",
3129 NO_STR
3130 "EVPN\n"
3131 EVPN_MH_VTY_STR
3132 "Ethernet segment system MAC\n"
3133 MAC_STR
3134)
3135{
3136 VTY_DECLVAR_CONTEXT(interface, ifp);
3137 struct zebra_if *zif;
3138 int ret = 0;
3139
3140 zif = ifp->info;
3141
3142 if (no) {
3143 static struct ethaddr zero_mac;
3144
3145 ret = zebra_evpn_es_sys_mac_update(zif, &zero_mac);
3146 if (ret == -1) {
3147 vty_out(vty, "%%Failed to clear ES sysmac\n");
3148 return CMD_WARNING;
3149 }
3150 } else {
3151
3152 if (!zebra_evpn_is_if_es_capable(zif)) {
3153 vty_out(vty,
3154 "%%ESI cannot be associated with this interface type\n");
3155 return CMD_WARNING;
3156 }
3157
3158 if (!mac || is_zero_mac(&mac->eth_addr)) {
3159 vty_out(vty, "%%ES sysmac value is invalid\n");
3160 return CMD_WARNING;
3161 }
3162
3163 ret = zebra_evpn_es_sys_mac_update(zif, &mac->eth_addr);
3164 if (ret == -1) {
3165 vty_out(vty, "%%ESI already exists on a different interface\n");
3166 return CMD_WARNING;
3167 }
3168 }
3169 return CMD_SUCCESS;
3170}
3171
3172/* CLI for setting up local-ID part of ESI on an access port */
3173DEFPY(zebra_evpn_es_id,
3174 zebra_evpn_es_id_cmd,
325d694b 3175 "[no$no] evpn mh es-id [(1-16777215)$es_lid | NAME$esi_str]",
ce5160c0
AK
3176 NO_STR
3177 "EVPN\n"
3178 EVPN_MH_VTY_STR
325d694b
AK
3179 "Ethernet segment identifier\n"
3180 "local discriminator\n"
3181 "10-byte ID - 00:AA:BB:CC:DD:EE:FF:GG:HH:II\n"
ce5160c0
AK
3182)
3183{
3184 VTY_DECLVAR_CONTEXT(interface, ifp);
3185 struct zebra_if *zif;
325d694b
AK
3186 int ret = 0;
3187 esi_t esi;
ce5160c0
AK
3188
3189 zif = ifp->info;
3190
3191 if (no) {
325d694b
AK
3192 if (zif->es_info.lid)
3193 ret = zebra_evpn_es_lid_update(zif, 0);
3194 else if (memcmp(&zif->es_info.esi, zero_esi, sizeof(*zero_esi)))
3195 ret = zebra_evpn_es_type0_esi_update(zif, zero_esi);
3196
ce5160c0
AK
3197 if (ret == -1) {
3198 vty_out(vty, "%%Failed to clear ES local id\n");
3199 return CMD_WARNING;
3200 }
3201 } else {
3202 if (!zebra_evpn_is_if_es_capable(zif)) {
3203 vty_out(vty,
3204 "%%ESI cannot be associated with this interface type\n");
3205 return CMD_WARNING;
3206 }
3207
325d694b
AK
3208 if (esi_str) {
3209 if (!str_to_esi(esi_str, &esi)) {
3210 vty_out(vty, "%% Malformed ESI\n");
3211 return CMD_WARNING;
3212 }
3213 ret = zebra_evpn_es_type0_esi_update(zif, &esi);
3214 } else {
3215 if (!es_lid) {
3216 vty_out(vty, "%%Specify local ES ID\n");
3217 return CMD_WARNING;
3218 }
3219 ret = zebra_evpn_es_lid_update(zif, es_lid);
ce5160c0 3220 }
325d694b 3221
ce5160c0
AK
3222 if (ret == -1) {
3223 vty_out(vty,
325d694b 3224 "%%ESI already exists on a different interface\n");
ce5160c0
AK
3225 return CMD_WARNING;
3226 }
3227 }
3228 return CMD_SUCCESS;
3229}
3230
c36e442c
AK
3231/* CLI for tagging an interface as an uplink */
3232DEFPY(zebra_evpn_mh_uplink, zebra_evpn_mh_uplink_cmd, "[no] evpn mh uplink",
3233 NO_STR "EVPN\n" EVPN_MH_VTY_STR "uplink to the VxLAN core\n")
3234{
3235 VTY_DECLVAR_CONTEXT(interface, ifp);
3236 struct zebra_if *zif;
3237
3238 zif = ifp->info;
3239 zebra_evpn_mh_uplink_cfg_update(zif, no ? false : true);
3240
3241 return CMD_SUCCESS;
3242}
3243
3244void zebra_evpn_mh_json(json_object *json)
3245{
3246 json_object *json_array;
3247 char thread_buf[THREAD_TIMER_STRLEN];
3248
3249 json_object_int_add(json, "macHoldtime", zmh_info->mac_hold_time);
3250 json_object_int_add(json, "neighHoldtime", zmh_info->neigh_hold_time);
3251 json_object_int_add(json, "startupDelay", zmh_info->startup_delay_time);
3252 json_object_string_add(
3253 json, "startupDelayTimer",
3254 thread_timer_to_hhmmss(thread_buf, sizeof(thread_buf),
3255 zmh_info->startup_delay_timer));
3256 json_object_int_add(json, "uplinkConfigCount",
3257 zmh_info->uplink_cfg_cnt);
3258 json_object_int_add(json, "uplinkActiveCount",
3259 zmh_info->uplink_oper_up_cnt);
3260
3261 if (zmh_info->protodown_rc) {
3262 json_array = json_object_new_array();
3263 if (zmh_info->protodown_rc & ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY)
3264 json_object_array_add(
3265 json_array,
3266 json_object_new_string("startupDelay"));
3267 if (zmh_info->protodown_rc & ZEBRA_PROTODOWN_EVPN_UPLINK_DOWN)
3268 json_object_array_add(
3269 json_array,
3270 json_object_new_string("uplinkDown"));
3271 json_object_object_add(json, "protodownReasons", json_array);
3272 }
3273}
3274
3275void zebra_evpn_mh_print(struct vty *vty)
3276{
3277 char pd_buf[ZEBRA_PROTODOWN_RC_STR_LEN];
3278 char thread_buf[THREAD_TIMER_STRLEN];
3279
3280 vty_out(vty, "EVPN MH:\n");
3281 vty_out(vty, " mac-holdtime: %ds, neigh-holdtime: %ds\n",
3282 zmh_info->mac_hold_time, zmh_info->neigh_hold_time);
3283 vty_out(vty, " startup-delay: %ds, start-delay-timer: %s\n",
3284 zmh_info->startup_delay_time,
3285 thread_timer_to_hhmmss(thread_buf, sizeof(thread_buf),
3286 zmh_info->startup_delay_timer));
3287 vty_out(vty, " uplink-cfg-cnt: %u, uplink-active-cnt: %u\n",
3288 zmh_info->uplink_cfg_cnt, zmh_info->uplink_oper_up_cnt);
3289 if (zmh_info->protodown_rc)
26ba45e3 3290 vty_out(vty, " protodown reasons: %s\n",
c36e442c
AK
3291 zebra_protodown_rc_str(zmh_info->protodown_rc, pd_buf,
3292 sizeof(pd_buf)));
3293}
3294
ce5160c0
AK
3295/*****************************************************************************/
3296/* A base L2-VNI is maintained to derive parameters such as ES originator-IP.
3297 * XXX: once single vxlan device model becomes available this will not be
3298 * necessary
3299 */
3300/* called when a new vni is added or becomes oper up or becomes a bridge port */
87d76d54 3301void zebra_evpn_es_set_base_evpn(zebra_evpn_t *zevpn)
ce5160c0
AK
3302{
3303 struct listnode *node;
3304 struct zebra_evpn_es *es;
3305
87d76d54
PR
3306 if (zmh_info->es_base_evpn) {
3307 if (zmh_info->es_base_evpn != zevpn) {
3308 /* unrelated EVPN; ignore it */
ce5160c0
AK
3309 return;
3310 }
3311 /* check if the local vtep-ip has changed */
3312 } else {
87d76d54
PR
3313 /* check if the EVPN can be used as base EVPN */
3314 if (!zebra_evpn_send_to_client_ok(zevpn))
ce5160c0
AK
3315 return;
3316
3317 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
3318 zlog_debug("es base vni set to %d",
87d76d54
PR
3319 zevpn->vni);
3320 zmh_info->es_base_evpn = zevpn;
ce5160c0
AK
3321 }
3322
3323 /* update local VTEP-IP */
3324 if (zmh_info->es_originator_ip.s_addr ==
87d76d54 3325 zmh_info->es_base_evpn->local_vtep_ip.s_addr)
ce5160c0
AK
3326 return;
3327
3328 zmh_info->es_originator_ip.s_addr =
87d76d54 3329 zmh_info->es_base_evpn->local_vtep_ip.s_addr;
ce5160c0
AK
3330
3331 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
9bcef951
MS
3332 zlog_debug("es originator ip set to %pI4",
3333 &zmh_info->es_base_evpn->local_vtep_ip);
ce5160c0
AK
3334
3335 /* if originator ip changes we need to update bgp */
3336 for (ALL_LIST_ELEMENTS_RO(zmh_info->local_es_list, node, es)) {
1103c5c6
AK
3337 zebra_evpn_es_run_df_election(es, __func__);
3338
ce5160c0
AK
3339 if (es->flags & ZEBRA_EVPNES_READY_FOR_BGP)
3340 zebra_evpn_es_send_add_to_client(es);
3341 else
3342 zebra_evpn_es_re_eval_send_to_client(es,
3343 true /* es_evi_re_reval */);
3344 }
3345}
3346
3347/* called when a vni is removed or becomes oper down or is removed from a
3348 * bridge
3349 */
87d76d54 3350void zebra_evpn_es_clear_base_evpn(zebra_evpn_t *zevpn)
ce5160c0
AK
3351{
3352 struct listnode *node;
3353 struct zebra_evpn_es *es;
3354
87d76d54 3355 if (zmh_info->es_base_evpn != zevpn)
ce5160c0
AK
3356 return;
3357
87d76d54
PR
3358 zmh_info->es_base_evpn = NULL;
3359 /* lost current base EVPN; try to find a new one */
3360 zebra_evpn_es_get_one_base_evpn();
ce5160c0 3361
87d76d54
PR
3362 /* couldn't locate an eligible base evpn */
3363 if (!zmh_info->es_base_evpn && zmh_info->es_originator_ip.s_addr) {
ce5160c0
AK
3364 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
3365 zlog_debug("es originator ip cleared");
3366
3367 zmh_info->es_originator_ip.s_addr = 0;
3368 /* lost originator ip */
3369 for (ALL_LIST_ELEMENTS_RO(zmh_info->local_es_list, node, es)) {
3370 zebra_evpn_es_re_eval_send_to_client(es,
3371 true /* es_evi_re_reval */);
3372 }
3373 }
3374}
3375
3376/* Locate an "eligible" L2-VNI to follow */
87d76d54 3377static int zebra_evpn_es_get_one_base_evpn_cb(struct hash_bucket *b, void *data)
ce5160c0 3378{
87d76d54 3379 zebra_evpn_t *zevpn = b->data;
ce5160c0 3380
87d76d54 3381 zebra_evpn_es_set_base_evpn(zevpn);
ce5160c0 3382
87d76d54 3383 if (zmh_info->es_base_evpn)
ce5160c0
AK
3384 return HASHWALK_ABORT;
3385
3386 return HASHWALK_CONTINUE;
3387}
3388
87d76d54 3389/* locate a base_evpn to follow for the purposes of common params like
ce5160c0
AK
3390 * originator IP
3391 */
87d76d54 3392static void zebra_evpn_es_get_one_base_evpn(void)
ce5160c0
AK
3393{
3394 struct zebra_vrf *zvrf;
3395
3396 zvrf = zebra_vrf_get_evpn();
87d76d54 3397 hash_walk(zvrf->evpn_table, zebra_evpn_es_get_one_base_evpn_cb, NULL);
ce5160c0
AK
3398}
3399
c36e442c
AK
3400/*****************************************************************************
3401 * local ethernet segments can be error-disabled if the switch is not
3402 * ready to start transmitting traffic via the VxLAN overlay
3403 */
3404bool zebra_evpn_is_es_bond(struct interface *ifp)
3405{
3406 struct zebra_if *zif = ifp->info;
3407
3408 return !!(struct zebra_if *)zif->es_info.es;
3409}
3410
3411bool zebra_evpn_is_es_bond_member(struct interface *ifp)
3412{
3413 struct zebra_if *zif = ifp->info;
3414
3415 return IS_ZEBRA_IF_BOND_SLAVE(zif->ifp) && zif->bondslave_info.bond_if
3416 && ((struct zebra_if *)zif->bondslave_info.bond_if->info)
3417 ->es_info.es;
3418}
3419
3420void zebra_evpn_mh_update_protodown_bond_mbr(struct zebra_if *zif, bool clear,
3421 const char *caller)
3422{
3423 bool old_protodown;
3424 bool new_protodown;
3425 enum protodown_reasons old_protodown_rc = 0;
3426 enum protodown_reasons protodown_rc = 0;
3427
3428 if (!clear) {
3429 struct zebra_if *bond_zif;
3430
3431 bond_zif = zif->bondslave_info.bond_if->info;
3432 protodown_rc = bond_zif->protodown_rc;
3433 }
3434
c36e442c
AK
3435 old_protodown = !!(zif->flags & ZIF_FLAG_PROTODOWN);
3436 old_protodown_rc = zif->protodown_rc;
3437 zif->protodown_rc &= ~ZEBRA_PROTODOWN_EVPN_ALL;
3438 zif->protodown_rc |= (protodown_rc & ZEBRA_PROTODOWN_EVPN_ALL);
3439 new_protodown = !!zif->protodown_rc;
3440
5c843270
AK
3441 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
3442 && (zif->protodown_rc != old_protodown_rc))
c36e442c
AK
3443 zlog_debug(
3444 "%s bond mbr %s protodown_rc changed; old 0x%x new 0x%x",
3445 caller, zif->ifp->name, old_protodown_rc,
3446 zif->protodown_rc);
3447
3448 if (old_protodown == new_protodown)
3449 return;
3450
3451 if (new_protodown)
3452 zif->flags |= ZIF_FLAG_PROTODOWN;
3453 else
3454 zif->flags &= ~ZIF_FLAG_PROTODOWN;
3455
3456 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
3457 zlog_debug("%s protodown %s", zif->ifp->name,
3458 new_protodown ? "on" : "off");
3459
3460 zebra_if_set_protodown(zif->ifp, new_protodown);
3461}
3462
3463/* The bond members inherit the protodown reason code from the bond */
3464static void zebra_evpn_mh_update_protodown_bond(struct zebra_if *bond_zif)
3465{
3466 struct zebra_if *zif;
3467 struct listnode *node;
3468
3469 if (!bond_zif->bond_info.mbr_zifs)
3470 return;
3471
3472 for (ALL_LIST_ELEMENTS_RO(bond_zif->bond_info.mbr_zifs, node, zif)) {
3473 zebra_evpn_mh_update_protodown_bond_mbr(zif, false /*clear*/,
3474 __func__);
3475 }
3476}
3477
3478/* The global EVPN MH protodown rc is applied to all local ESs */
2bcf92e1
AK
3479static void zebra_evpn_mh_update_protodown_es(struct zebra_evpn_es *es,
3480 bool resync_dplane)
c36e442c
AK
3481{
3482 struct zebra_if *zif;
3483 enum protodown_reasons old_protodown_rc;
3484
3485 zif = es->zif;
2bcf92e1
AK
3486 /* if the reason code is the same bail unless it is a new
3487 * ES bond in that case we would need to ensure that the
3488 * dplane is really in sync with zebra
3489 */
3490 if (!resync_dplane
3491 && (zif->protodown_rc & ZEBRA_PROTODOWN_EVPN_ALL)
3492 == (zmh_info->protodown_rc & ZEBRA_PROTODOWN_EVPN_ALL))
c36e442c
AK
3493 return;
3494
3495 old_protodown_rc = zif->protodown_rc;
3496 zif->protodown_rc &= ~ZEBRA_PROTODOWN_EVPN_ALL;
3497 zif->protodown_rc |=
3498 (zmh_info->protodown_rc & ZEBRA_PROTODOWN_EVPN_ALL);
3499
2bcf92e1
AK
3500 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
3501 && (old_protodown_rc != zif->protodown_rc))
c36e442c
AK
3502 zlog_debug(
3503 "es %s ifp %s protodown_rc changed; old 0x%x new 0x%x",
3504 es->esi_str, zif->ifp->name, old_protodown_rc,
3505 zif->protodown_rc);
3506
3507 /* update dataplane with the new protodown setting */
3508 zebra_evpn_mh_update_protodown_bond(zif);
3509}
3510
3511static void zebra_evpn_mh_clear_protodown_es(struct zebra_evpn_es *es)
3512{
3513 struct zebra_if *zif;
3514 enum protodown_reasons old_protodown_rc;
3515
3516 zif = es->zif;
3517 if (!(zif->protodown_rc & ZEBRA_PROTODOWN_EVPN_ALL))
3518 return;
3519
3520 old_protodown_rc = zif->protodown_rc;
3521 zif->protodown_rc &= ~ZEBRA_PROTODOWN_EVPN_ALL;
3522
3523 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
3524 zlog_debug(
3525 "clear: es %s ifp %s protodown_rc cleared; old 0x%x new 0x%x",
3526 es->esi_str, zif->ifp->name, old_protodown_rc,
3527 zif->protodown_rc);
3528
3529 /* update dataplane with the new protodown setting */
3530 zebra_evpn_mh_update_protodown_bond(zif);
3531}
3532
3533static void zebra_evpn_mh_update_protodown_es_all(void)
3534{
3535 struct listnode *node;
3536 struct zebra_evpn_es *es;
3537
3538 for (ALL_LIST_ELEMENTS_RO(zmh_info->local_es_list, node, es))
2bcf92e1 3539 zebra_evpn_mh_update_protodown_es(es, false /*resync_dplane*/);
c36e442c
AK
3540}
3541
3542static void zebra_evpn_mh_update_protodown(enum protodown_reasons protodown_rc,
3543 bool set)
3544{
3545 enum protodown_reasons old_protodown_rc = zmh_info->protodown_rc;
3546
3547 if (set) {
3548 if ((protodown_rc & zmh_info->protodown_rc) == protodown_rc)
3549 return;
3550
3551 zmh_info->protodown_rc |= protodown_rc;
3552 } else {
3553 if (!(protodown_rc & zmh_info->protodown_rc))
3554 return;
3555 zmh_info->protodown_rc &= ~protodown_rc;
3556 }
3557
3558 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
3559 zlog_debug("mh protodown_rc changed; old 0x%x new 0x%x",
3560 old_protodown_rc, zmh_info->protodown_rc);
3561 zebra_evpn_mh_update_protodown_es_all();
3562}
3563
3564static inline bool zebra_evpn_mh_is_all_uplinks_down(void)
3565{
3566 return zmh_info->uplink_cfg_cnt && !zmh_info->uplink_oper_up_cnt;
3567}
3568
3569static void zebra_evpn_mh_uplink_oper_flags_update(struct zebra_if *zif,
3570 bool set)
3571{
3572 if (set) {
3573 if (if_is_operative(zif->ifp)) {
3574 if (!(zif->flags & ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP)) {
3575 zif->flags |= ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP;
3576 ++zmh_info->uplink_oper_up_cnt;
3577 }
3578 } else {
3579 if (zif->flags & ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP) {
3580 zif->flags &= ~ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP;
3581 if (zmh_info->uplink_oper_up_cnt)
3582 --zmh_info->uplink_oper_up_cnt;
3583 }
3584 }
3585 } else {
3586 if (zif->flags & ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP) {
3587 zif->flags &= ~ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP;
3588 if (zmh_info->uplink_oper_up_cnt)
3589 --zmh_info->uplink_oper_up_cnt;
3590 }
3591 }
3592}
3593
3594static void zebra_evpn_mh_uplink_cfg_update(struct zebra_if *zif, bool set)
3595{
3596 bool old_protodown = zebra_evpn_mh_is_all_uplinks_down();
3597 bool new_protodown;
3598
3599 if (set) {
3600 if (zif->flags & ZIF_FLAG_EVPN_MH_UPLINK)
3601 return;
3602
3603 zif->flags |= ZIF_FLAG_EVPN_MH_UPLINK;
3604 ++zmh_info->uplink_cfg_cnt;
3605 } else {
3606 if (!(zif->flags & ZIF_FLAG_EVPN_MH_UPLINK))
3607 return;
3608
3609 zif->flags &= ~ZIF_FLAG_EVPN_MH_UPLINK;
3610 if (zmh_info->uplink_cfg_cnt)
3611 --zmh_info->uplink_cfg_cnt;
3612 }
3613
3614 zebra_evpn_mh_uplink_oper_flags_update(zif, set);
3615 new_protodown = zebra_evpn_mh_is_all_uplinks_down();
3616 if (old_protodown == new_protodown)
3617 return;
3618
3619 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
3620 zlog_debug(
3621 "mh-uplink-cfg-chg on if %s/%d %s uplinks cfg %u up %u",
3622 zif->ifp->name, zif->ifp->ifindex, set ? "set" : "down",
3623 zmh_info->uplink_cfg_cnt, zmh_info->uplink_oper_up_cnt);
3624
3625 zebra_evpn_mh_update_protodown(ZEBRA_PROTODOWN_EVPN_UPLINK_DOWN,
3626 new_protodown);
3627}
3628
3629void zebra_evpn_mh_uplink_oper_update(struct zebra_if *zif)
3630{
3631 bool old_protodown = zebra_evpn_mh_is_all_uplinks_down();
3632 bool new_protodown;
3633
3634 zebra_evpn_mh_uplink_oper_flags_update(zif, true /*set*/);
3635
3636 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
3637 zlog_debug(
3638 "mh-uplink-oper-chg on if %s/%d %s; uplinks cfg %u up %u",
3639 zif->ifp->name, zif->ifp->ifindex,
3640 if_is_operative(zif->ifp) ? "up" : "down",
3641 zmh_info->uplink_cfg_cnt, zmh_info->uplink_oper_up_cnt);
3642
3643 new_protodown = zebra_evpn_mh_is_all_uplinks_down();
3644 if (old_protodown == new_protodown)
3645 return;
3646
dc261b8d
AK
3647 /* if protodown_rc XXX_UPLINK_DOWN is about to be cleared
3648 * fire up the start-up delay timer to allow the EVPN network
3649 * to converge (Type-2 routes need to be advertised and processed)
3650 */
3651 if (!new_protodown && (zmh_info->uplink_oper_up_cnt == 1))
3652 zebra_evpn_mh_startup_delay_timer_start("uplink-up");
3653
c36e442c
AK
3654 zebra_evpn_mh_update_protodown(ZEBRA_PROTODOWN_EVPN_UPLINK_DOWN,
3655 new_protodown);
3656}
3657
3658static int zebra_evpn_mh_startup_delay_exp_cb(struct thread *t)
3659{
3660 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
3661 zlog_debug("startup-delay expired");
3662
3663 zebra_evpn_mh_update_protodown(ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY,
3664 false /* set */);
3665
3666 return 0;
3667}
3668
dc261b8d 3669static void zebra_evpn_mh_startup_delay_timer_start(const char *rc)
c36e442c 3670{
c36e442c
AK
3671 if (zmh_info->startup_delay_timer) {
3672 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
3673 zlog_debug("startup-delay timer cancelled");
35f5c31b 3674 THREAD_OFF(zmh_info->startup_delay_timer);
c36e442c
AK
3675 }
3676
3677 if (zmh_info->startup_delay_time) {
3678 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
dc261b8d
AK
3679 zlog_debug(
3680 "startup-delay timer started for %d sec on %s",
3681 zmh_info->startup_delay_time, rc);
c36e442c
AK
3682 thread_add_timer(zrouter.master,
3683 zebra_evpn_mh_startup_delay_exp_cb, NULL,
3684 zmh_info->startup_delay_time,
3685 &zmh_info->startup_delay_timer);
3686 zebra_evpn_mh_update_protodown(
3687 ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY, true /* set */);
3688 } else {
3689 zebra_evpn_mh_update_protodown(
3690 ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY, false /* set */);
3691 }
3692}
3693
ce5160c0 3694/*****************************************************************************/
b169fd6f
AK
3695void zebra_evpn_mh_config_write(struct vty *vty)
3696{
c36e442c
AK
3697 if (zmh_info->mac_hold_time != ZEBRA_EVPN_MH_MAC_HOLD_TIME_DEF)
3698 vty_out(vty, "evpn mh mac-holdtime %d\n",
b169fd6f
AK
3699 zmh_info->mac_hold_time);
3700
c36e442c
AK
3701 if (zmh_info->neigh_hold_time != ZEBRA_EVPN_MH_NEIGH_HOLD_TIME_DEF)
3702 vty_out(vty, "evpn mh neigh-holdtime %d\n",
b169fd6f 3703 zmh_info->neigh_hold_time);
c36e442c
AK
3704
3705 if (zmh_info->startup_delay_time != ZEBRA_EVPN_MH_STARTUP_DELAY_DEF)
3706 vty_out(vty, "evpn mh startup-delay %d\n",
3707 zmh_info->startup_delay_time);
15400f95
AK
3708
3709 if (zmh_info->flags & ZEBRA_EVPN_MH_REDIRECT_OFF)
3710 vty_out(vty, "evpn mh redirect-off\n");
b169fd6f
AK
3711}
3712
3713int zebra_evpn_mh_neigh_holdtime_update(struct vty *vty,
3714 uint32_t duration, bool set_default)
3715{
3716 if (set_default)
c36e442c 3717 duration = ZEBRA_EVPN_MH_NEIGH_HOLD_TIME_DEF;
b169fd6f
AK
3718
3719 zmh_info->neigh_hold_time = duration;
3720
3721 return 0;
3722}
3723
3724int zebra_evpn_mh_mac_holdtime_update(struct vty *vty,
3725 uint32_t duration, bool set_default)
3726{
3727 if (set_default)
c36e442c 3728 duration = ZEBRA_EVPN_MH_MAC_HOLD_TIME_DEF;
b169fd6f
AK
3729
3730 zmh_info->mac_hold_time = duration;
3731
3732 return 0;
3733}
3734
c36e442c
AK
3735int zebra_evpn_mh_startup_delay_update(struct vty *vty, uint32_t duration,
3736 bool set_default)
3737{
3738 if (set_default)
3739 duration = ZEBRA_EVPN_MH_STARTUP_DELAY_DEF;
3740
3741 zmh_info->startup_delay_time = duration;
dc261b8d
AK
3742
3743 /* if startup_delay_timer is running allow it to be adjusted
3744 * up or down
3745 */
3746 if (zmh_info->startup_delay_timer)
3747 zebra_evpn_mh_startup_delay_timer_start("config");
c36e442c
AK
3748
3749 return 0;
3750}
3751
15400f95
AK
3752int zebra_evpn_mh_redirect_off(struct vty *vty, bool redirect_off)
3753{
3754 /* This knob needs to be set before ESs are configured
3755 * i.e. cannot be changed on the fly
3756 */
3757 if (redirect_off)
3758 zmh_info->flags |= ZEBRA_EVPN_MH_REDIRECT_OFF;
3759 else
3760 zmh_info->flags &= ~ZEBRA_EVPN_MH_REDIRECT_OFF;
3761
3762 return 0;
3763}
3764
ce5160c0
AK
3765void zebra_evpn_interface_init(void)
3766{
3767 install_element(INTERFACE_NODE, &zebra_evpn_es_id_cmd);
3768 install_element(INTERFACE_NODE, &zebra_evpn_es_sys_mac_cmd);
1103c5c6 3769 install_element(INTERFACE_NODE, &zebra_evpn_es_pref_cmd);
c36e442c 3770 install_element(INTERFACE_NODE, &zebra_evpn_mh_uplink_cmd);
ce5160c0
AK
3771}
3772
3773void zebra_evpn_mh_init(void)
3774{
3775 zrouter.mh_info = XCALLOC(MTYPE_ZMH_INFO, sizeof(*zrouter.mh_info));
3776
c36e442c
AK
3777 zmh_info->mac_hold_time = ZEBRA_EVPN_MH_MAC_HOLD_TIME_DEF;
3778 zmh_info->neigh_hold_time = ZEBRA_EVPN_MH_NEIGH_HOLD_TIME_DEF;
ce5160c0
AK
3779 /* setup ES tables */
3780 RB_INIT(zebra_es_rb_head, &zmh_info->es_rb_tree);
3781 zmh_info->local_es_list = list_new();
3782 listset_app_node_mem(zmh_info->local_es_list);
3783
3784 bf_init(zmh_info->nh_id_bitmap, EVPN_NH_ID_MAX);
3785 bf_assign_zero_index(zmh_info->nh_id_bitmap);
15400f95
AK
3786 zmh_info->nhg_table = hash_create(zebra_evpn_nhg_hash_keymake,
3787 zebra_evpn_nhg_cmp, "l2 NHG table");
5de10c37
AK
3788 zmh_info->nh_ip_table =
3789 hash_create(zebra_evpn_nh_ip_hash_keymake, zebra_evpn_nh_ip_cmp,
3790 "l2 NH IP table");
ce5160c0
AK
3791
3792 /* setup broadcast domain tables */
3793 zmh_info->evpn_vlan_table = hash_create(zebra_evpn_acc_vl_hash_keymake,
3794 zebra_evpn_acc_vl_cmp, "access VLAN hash table");
c36e442c
AK
3795
3796 zmh_info->startup_delay_time = ZEBRA_EVPN_MH_STARTUP_DELAY_DEF;
dc261b8d 3797 zebra_evpn_mh_startup_delay_timer_start("init");
ce5160c0
AK
3798}
3799
3800void zebra_evpn_mh_terminate(void)
3801{
3802 list_delete(&zmh_info->local_es_list);
3803
3804 hash_iterate(zmh_info->evpn_vlan_table,
3805 zebra_evpn_acc_vl_cleanup_all, NULL);
3806 hash_free(zmh_info->evpn_vlan_table);
5de10c37
AK
3807 hash_free(zmh_info->nhg_table);
3808 hash_free(zmh_info->nh_ip_table);
de86cc5b 3809 bf_free(zmh_info->nh_id_bitmap);
ce5160c0 3810}