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