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