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