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