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