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