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