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