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