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