]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_evpn_mh.c
zebra: dplane APIs for programming evpn-mh access port attributes
[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"
41#include "zebra/zebra_errors.h"
42#include "zebra/zebra_l2.h"
43#include "zebra/zebra_memory.h"
44#include "zebra/zebra_ns.h"
45#include "zebra/zebra_vrf.h"
46#include "zebra/zebra_vxlan.h"
b2998086
PR
47#include "zebra/zebra_evpn.h"
48#include "zebra/zebra_evpn_mac.h"
ce5160c0
AK
49#include "zebra/zebra_vxlan_private.h"
50#include "zebra/zebra_router.h"
51#include "zebra/zebra_evpn_mh.h"
52#include "zebra/zebra_nhg.h"
53
54DEFINE_MTYPE_STATIC(ZEBRA, ZACC_BD, "Access Broadcast Domain");
55DEFINE_MTYPE_STATIC(ZEBRA, ZES, "Ethernet Segment");
56DEFINE_MTYPE_STATIC(ZEBRA, ZES_EVI, "ES info per-EVI");
57DEFINE_MTYPE_STATIC(ZEBRA, ZMH_INFO, "MH global info");
58DEFINE_MTYPE_STATIC(ZEBRA, ZES_VTEP, "VTEP attached to the ES");
59
87d76d54 60static void zebra_evpn_es_get_one_base_evpn(void);
ce5160c0 61static int zebra_evpn_es_evi_send_to_client(struct zebra_evpn_es *es,
87d76d54 62 zebra_evpn_t *zevpn, bool add);
e378f502 63static void zebra_evpn_local_es_del(struct zebra_evpn_es **esp);
ce5160c0
AK
64static int zebra_evpn_local_es_update(struct zebra_if *zif, uint32_t lid,
65 struct ethaddr *sysmac);
66
67esi_t zero_esi_buf, *zero_esi = &zero_esi_buf;
68
69/*****************************************************************************/
70/* Ethernet Segment to EVI association -
71 * 1. The ES-EVI entry is maintained as a RB tree per L2-VNI
87d76d54 72 * (zebra_evpn_t.es_evi_rb_tree).
ce5160c0
AK
73 * 2. Each local ES-EVI entry is sent to BGP which advertises it as an
74 * EAD-EVI (Type-1 EVPN) route
75 * 3. Local ES-EVI setup is re-evaluated on the following triggers -
76 * a. When an ESI is set or cleared on an access port.
77 * b. When an access port associated with an ESI is deleted.
78 * c. When VLAN member ship changes on an access port.
79 * d. When a VXLAN_IF is set or cleared on an access broadcast domain.
80 * e. When a L2-VNI is added or deleted for a VxLAN_IF.
81 * 4. Currently zebra doesn't remote ES-EVIs. Those are managed and maintained
82 * entirely in BGP which consolidates them into a remote ES. The remote ES
83 * is then sent to zebra which allocates a NHG for it.
84 */
85
87d76d54 86/* compare ES-IDs for the ES-EVI RB tree maintained per-EVPN */
ce5160c0
AK
87static int zebra_es_evi_rb_cmp(const struct zebra_evpn_es_evi *es_evi1,
88 const struct zebra_evpn_es_evi *es_evi2)
89{
90 return memcmp(&es_evi1->es->esi, &es_evi2->es->esi, ESI_BYTES);
91}
92RB_GENERATE(zebra_es_evi_rb_head, zebra_evpn_es_evi,
93 rb_node, zebra_es_evi_rb_cmp);
94
95/* allocate a new ES-EVI and insert it into the per-L2-VNI and per-ES
96 * tables.
97 */
98static struct zebra_evpn_es_evi *zebra_evpn_es_evi_new(struct zebra_evpn_es *es,
87d76d54 99 zebra_evpn_t *zevpn)
ce5160c0
AK
100{
101 struct zebra_evpn_es_evi *es_evi;
102
103 es_evi = XCALLOC(MTYPE_ZES_EVI, sizeof(struct zebra_evpn_es_evi));
104
105 es_evi->es = es;
87d76d54 106 es_evi->zevpn = zevpn;
ce5160c0 107
87d76d54
PR
108 /* insert into the EVPN-ESI rb tree */
109 if (RB_INSERT(zebra_es_evi_rb_head, &zevpn->es_evi_rb_tree, es_evi)) {
ce5160c0
AK
110 XFREE(MTYPE_ZES_EVI, es_evi);
111 return NULL;
112 }
113
114 /* add to the ES's VNI list */
115 listnode_init(&es_evi->es_listnode, es_evi);
116 listnode_add(es->es_evi_list, &es_evi->es_listnode);
117
118 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
119 zlog_debug("es %s evi %d new",
87d76d54 120 es_evi->es->esi_str, es_evi->zevpn->vni);
ce5160c0
AK
121
122 return es_evi;
123}
124
87d76d54
PR
125/* returns TRUE if the EVPN is ready to be sent to BGP */
126static inline bool zebra_evpn_send_to_client_ok(zebra_evpn_t *zevpn)
ce5160c0 127{
87d76d54 128 return !!(zevpn->flags & ZEVPN_READY_FOR_BGP);
ce5160c0
AK
129}
130
131/* Evaluate if the es_evi is ready to be sent BGP -
132 * 1. If it is ready an add is sent to BGP
133 * 2. If it is not ready a del is sent (if the ES had been previously added
134 * to BGP).
135 */
136static void zebra_evpn_es_evi_re_eval_send_to_client(
137 struct zebra_evpn_es_evi *es_evi)
138{
139 bool old_ready;
140 bool new_ready;
141
142 old_ready = !!(es_evi->flags & ZEBRA_EVPNES_EVI_READY_FOR_BGP);
143
144 /* ES and L2-VNI have to be individually ready for BGP */
145 if ((es_evi->flags & ZEBRA_EVPNES_EVI_LOCAL) &&
146 (es_evi->es->flags & ZEBRA_EVPNES_READY_FOR_BGP) &&
87d76d54 147 zebra_evpn_send_to_client_ok(es_evi->zevpn))
ce5160c0
AK
148 es_evi->flags |= ZEBRA_EVPNES_EVI_READY_FOR_BGP;
149 else
150 es_evi->flags &= ~ZEBRA_EVPNES_EVI_READY_FOR_BGP;
151
152 new_ready = !!(es_evi->flags & ZEBRA_EVPNES_EVI_READY_FOR_BGP);
153
154 if (old_ready == new_ready)
155 return;
156
157 if (new_ready)
87d76d54 158 zebra_evpn_es_evi_send_to_client(es_evi->es, es_evi->zevpn,
ce5160c0
AK
159 true /* add */);
160 else
87d76d54 161 zebra_evpn_es_evi_send_to_client(es_evi->es, es_evi->zevpn,
ce5160c0
AK
162 false /* add */);
163}
164
165/* remove the ES-EVI from the per-L2-VNI and per-ES tables and free
166 * up the memory.
167 */
168static void zebra_evpn_es_evi_free(struct zebra_evpn_es_evi *es_evi)
169{
170 struct zebra_evpn_es *es = es_evi->es;
87d76d54 171 zebra_evpn_t *zevpn = es_evi->zevpn;
ce5160c0
AK
172
173 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
174 zlog_debug("es %s evi %d free",
87d76d54 175 es_evi->es->esi_str, es_evi->zevpn->vni);
ce5160c0
AK
176
177 /* remove from the ES's VNI list */
178 list_delete_node(es->es_evi_list, &es_evi->es_listnode);
179
180 /* remove from the VNI-ESI rb tree */
87d76d54 181 RB_REMOVE(zebra_es_evi_rb_head, &zevpn->es_evi_rb_tree, es_evi);
ce5160c0
AK
182
183 /* remove from the VNI-ESI rb tree */
184 XFREE(MTYPE_ZES_EVI, es_evi);
185}
186
187/* find the ES-EVI in the per-L2-VNI RB tree */
188static struct zebra_evpn_es_evi *zebra_evpn_es_evi_find(
87d76d54 189 struct zebra_evpn_es *es, zebra_evpn_t *zevpn)
ce5160c0
AK
190{
191 struct zebra_evpn_es_evi es_evi;
192
193 es_evi.es = es;
194
87d76d54 195 return RB_FIND(zebra_es_evi_rb_head, &zevpn->es_evi_rb_tree, &es_evi);
ce5160c0
AK
196}
197
198/* Tell BGP about an ES-EVI deletion and then delete it */
199static void zebra_evpn_local_es_evi_do_del(struct zebra_evpn_es_evi *es_evi)
200{
201 if (!(es_evi->flags & ZEBRA_EVPNES_EVI_LOCAL))
202 return;
203
204 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
205 zlog_debug("local es %s evi %d del",
87d76d54 206 es_evi->es->esi_str, es_evi->zevpn->vni);
ce5160c0
AK
207
208 if (es_evi->flags & ZEBRA_EVPNES_EVI_READY_FOR_BGP) {
209 /* send a del only if add was sent for it earlier */
210 zebra_evpn_es_evi_send_to_client(es_evi->es,
87d76d54 211 es_evi->zevpn, false /* add */);
ce5160c0
AK
212 }
213
87d76d54
PR
214 /* delete it from the EVPN's local list */
215 list_delete_node(es_evi->zevpn->local_es_evi_list,
ce5160c0
AK
216 &es_evi->l2vni_listnode);
217
218 es_evi->flags &= ~ZEBRA_EVPNES_EVI_LOCAL;
219 zebra_evpn_es_evi_free(es_evi);
220}
221static void zebra_evpn_local_es_evi_del(struct zebra_evpn_es *es,
87d76d54 222 zebra_evpn_t *zevpn)
ce5160c0
AK
223{
224 struct zebra_evpn_es_evi *es_evi;
225
87d76d54 226 es_evi = zebra_evpn_es_evi_find(es, zevpn);
ce5160c0
AK
227 if (es_evi)
228 zebra_evpn_local_es_evi_do_del(es_evi);
229}
230
231/* Create an ES-EVI if it doesn't already exist and tell BGP */
232static void zebra_evpn_local_es_evi_add(struct zebra_evpn_es *es,
87d76d54 233 zebra_evpn_t *zevpn)
ce5160c0
AK
234{
235 struct zebra_evpn_es_evi *es_evi;
236
87d76d54 237 es_evi = zebra_evpn_es_evi_find(es, zevpn);
ce5160c0 238 if (!es_evi) {
87d76d54 239 es_evi = zebra_evpn_es_evi_new(es, zevpn);
ce5160c0
AK
240 if (!es_evi)
241 return;
242
243 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
244 zlog_debug("local es %s evi %d add",
87d76d54 245 es_evi->es->esi_str, es_evi->zevpn->vni);
ce5160c0 246 es_evi->flags |= ZEBRA_EVPNES_EVI_LOCAL;
87d76d54 247 /* add to the EVPN's local list */
ce5160c0 248 listnode_init(&es_evi->l2vni_listnode, es_evi);
87d76d54 249 listnode_add(zevpn->local_es_evi_list, &es_evi->l2vni_listnode);
ce5160c0
AK
250
251 zebra_evpn_es_evi_re_eval_send_to_client(es_evi);
252 }
253}
254
255static void zebra_evpn_es_evi_show_entry(struct vty *vty,
256 struct zebra_evpn_es_evi *es_evi, json_object *json)
257{
258 char type_str[4];
259
260 if (json) {
261 /* XXX */
262 } else {
263 type_str[0] = '\0';
264 if (es_evi->flags & ZEBRA_EVPNES_EVI_LOCAL)
9e0c2fd1 265 strlcat(type_str, "L", sizeof(type_str));
ce5160c0
AK
266
267 vty_out(vty, "%-8d %-30s %-4s\n",
87d76d54 268 es_evi->zevpn->vni, es_evi->es->esi_str,
ce5160c0
AK
269 type_str);
270 }
271}
272
273static void zebra_evpn_es_evi_show_entry_detail(struct vty *vty,
274 struct zebra_evpn_es_evi *es_evi, json_object *json)
275{
276 char type_str[4];
277
278 if (json) {
279 /* XXX */
280 } else {
281 type_str[0] = '\0';
282 if (es_evi->flags & ZEBRA_EVPNES_EVI_LOCAL)
9e0c2fd1 283 strlcat(type_str, "L", sizeof(type_str));
ce5160c0
AK
284
285 vty_out(vty, "VNI %d ESI: %s\n",
87d76d54 286 es_evi->zevpn->vni, es_evi->es->esi_str);
ce5160c0
AK
287 vty_out(vty, " Type: %s\n", type_str);
288 vty_out(vty, " Ready for BGP: %s\n",
289 (es_evi->flags &
290 ZEBRA_EVPNES_EVI_READY_FOR_BGP) ?
291 "yes" : "no");
292 vty_out(vty, "\n");
293 }
294}
295
87d76d54 296static void zebra_evpn_es_evi_show_one_evpn(zebra_evpn_t *zevpn,
ce5160c0
AK
297 struct vty *vty, json_object *json, int detail)
298{
299 struct zebra_evpn_es_evi *es_evi;
300
87d76d54 301 RB_FOREACH(es_evi, zebra_es_evi_rb_head, &zevpn->es_evi_rb_tree) {
ce5160c0
AK
302 if (detail)
303 zebra_evpn_es_evi_show_entry_detail(vty, es_evi, json);
304 else
305 zebra_evpn_es_evi_show_entry(vty, es_evi, json);
306 }
307}
308
309struct evpn_mh_show_ctx {
310 struct vty *vty;
311 json_object *json;
312 int detail;
313};
314
87d76d54 315static void zebra_evpn_es_evi_show_one_evpn_hash_cb(struct hash_bucket *bucket,
ce5160c0
AK
316 void *ctxt)
317{
87d76d54 318 zebra_evpn_t *zevpn = (zebra_evpn_t *)bucket->data;
ce5160c0
AK
319 struct evpn_mh_show_ctx *wctx = (struct evpn_mh_show_ctx *)ctxt;
320
87d76d54 321 zebra_evpn_es_evi_show_one_evpn(zevpn, wctx->vty,
ce5160c0
AK
322 wctx->json, wctx->detail);
323}
324
325void zebra_evpn_es_evi_show(struct vty *vty, bool uj, int detail)
326{
327 json_object *json = NULL;
328 struct zebra_vrf *zvrf;
329 struct evpn_mh_show_ctx wctx;
330
331 zvrf = zebra_vrf_get_evpn();
332
333 memset(&wctx, 0, sizeof(wctx));
334 wctx.vty = vty;
335 wctx.json = json;
336 wctx.detail = detail;
337
338 if (!detail && !json) {
339 vty_out(vty, "Type: L local, R remote\n");
340 vty_out(vty, "%-8s %-30s %-4s\n", "VNI", "ESI", "Type");
341 }
342 /* Display all L2-VNIs */
87d76d54 343 hash_iterate(zvrf->evpn_table, zebra_evpn_es_evi_show_one_evpn_hash_cb,
ce5160c0
AK
344 &wctx);
345}
346
347void zebra_evpn_es_evi_show_vni(struct vty *vty, bool uj, vni_t vni, int detail)
348{
349 json_object *json = NULL;
87d76d54 350 zebra_evpn_t *zevpn;
ce5160c0 351
8b5fdf2e 352 zevpn = zebra_evpn_lookup(vni);
87d76d54 353 if (zevpn) {
ce5160c0
AK
354 if (!detail && !json) {
355 vty_out(vty, "Type: L local, R remote\n");
356 vty_out(vty, "%-8s %-30s %-4s\n", "VNI", "ESI", "Type");
357 }
358 } else {
359 if (!uj)
1718bc78 360 vty_out(vty, "VNI %d doesn't exist\n", vni);
ba49e033
DS
361
362 return;
ce5160c0 363 }
87d76d54 364 zebra_evpn_es_evi_show_one_evpn(zevpn, vty, json, detail);
ce5160c0
AK
365}
366
367/* Initialize the ES tables maintained per-L2_VNI */
945ee7b2 368void zebra_evpn_es_evi_init(zebra_evpn_t *zevpn)
ce5160c0
AK
369{
370 /* Initialize the ES-EVI RB tree */
87d76d54 371 RB_INIT(zebra_es_evi_rb_head, &zevpn->es_evi_rb_tree);
ce5160c0
AK
372
373 /* Initialize the local and remote ES lists maintained for quick
374 * walks by type
375 */
87d76d54
PR
376 zevpn->local_es_evi_list = list_new();
377 listset_app_node_mem(zevpn->local_es_evi_list);
ce5160c0
AK
378}
379
87d76d54 380/* Cleanup the ES info maintained per- EVPN */
945ee7b2 381void zebra_evpn_es_evi_cleanup(zebra_evpn_t *zevpn)
ce5160c0
AK
382{
383 struct zebra_evpn_es_evi *es_evi;
384 struct zebra_evpn_es_evi *es_evi_next;
385
386 RB_FOREACH_SAFE(es_evi, zebra_es_evi_rb_head,
87d76d54 387 &zevpn->es_evi_rb_tree, es_evi_next) {
ce5160c0
AK
388 zebra_evpn_local_es_evi_do_del(es_evi);
389 }
390
87d76d54
PR
391 list_delete(&zevpn->local_es_evi_list);
392 zebra_evpn_es_clear_base_evpn(zevpn);
ce5160c0
AK
393}
394
395/* called when the oper state or bridge membership changes for the
396 * vxlan device
397 */
87d76d54 398void zebra_evpn_update_all_es(zebra_evpn_t *zevpn)
ce5160c0
AK
399{
400 struct zebra_evpn_es_evi *es_evi;
401 struct listnode *node;
402
87d76d54
PR
403 /* the EVPN is now elgible as a base for EVPN-MH */
404 if (zebra_evpn_send_to_client_ok(zevpn))
405 zebra_evpn_es_set_base_evpn(zevpn);
ce5160c0 406 else
87d76d54 407 zebra_evpn_es_clear_base_evpn(zevpn);
ce5160c0 408
87d76d54 409 for (ALL_LIST_ELEMENTS_RO(zevpn->local_es_evi_list, node, es_evi))
ce5160c0
AK
410 zebra_evpn_es_evi_re_eval_send_to_client(es_evi);
411}
412
413/*****************************************************************************/
414/* Access broadcast domains (BD)
415 * 1. These broadcast domains can be VLAN aware (in which case
416 * the key is VID) or VLAN unaware (in which case the key is
417 * 2. A VID-BD is created when a VLAN is associated with an access port or
418 * when the VLAN is associated with VXLAN_IF
419 * 3. A BD is translated into ES-EVI entries when a VNI is associated
420 * with the broadcast domain
421 */
422/* Hash key for VLAN based broadcast domains */
423static unsigned int zebra_evpn_acc_vl_hash_keymake(const void *p)
424{
425 const struct zebra_evpn_access_bd *acc_bd = p;
426
427 return jhash_1word(acc_bd->vid, 0);
428}
429
430/* Compare two VLAN based broadcast domains */
431static bool zebra_evpn_acc_vl_cmp(const void *p1, const void *p2)
432{
433 const struct zebra_evpn_access_bd *acc_bd1 = p1;
434 const struct zebra_evpn_access_bd *acc_bd2 = p2;
435
436 if (acc_bd1 == NULL && acc_bd2 == NULL)
437 return true;
438
439 if (acc_bd1 == NULL || acc_bd2 == NULL)
440 return false;
441
442 return (acc_bd1->vid == acc_bd2->vid);
443}
444
445/* Lookup VLAN based broadcast domain */
446static struct zebra_evpn_access_bd *zebra_evpn_acc_vl_find(vlanid_t vid)
447{
448 struct zebra_evpn_access_bd *acc_bd;
449 struct zebra_evpn_access_bd tmp;
450
451 tmp.vid = vid;
452 acc_bd = hash_lookup(zmh_info->evpn_vlan_table, &tmp);
453
454 return acc_bd;
455}
456
457/* A new broadcast domain can be created when a VLAN member or VLAN<=>VxLAN_IF
458 * mapping is added.
459 */
460static struct zebra_evpn_access_bd *zebra_evpn_acc_vl_new(vlanid_t vid)
461{
462 struct zebra_evpn_access_bd *acc_bd;
463
464 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
465 zlog_debug("access vlan %d add", vid);
466
467 acc_bd = XCALLOC(MTYPE_ZACC_BD, sizeof(struct zebra_evpn_access_bd));
468
469 acc_bd->vid = vid;
470
471 /* Initialize the mbr list */
472 acc_bd->mbr_zifs = list_new();
473
474 /* Add to hash */
475 if (!hash_get(zmh_info->evpn_vlan_table, acc_bd, hash_alloc_intern)) {
476 XFREE(MTYPE_ZACC_BD, acc_bd);
477 return NULL;
478 }
479
480 return acc_bd;
481}
482
483/* Free VLAN based broadcast domain -
484 * This just frees appropriate memory, caller should have taken other
485 * needed actions.
486 */
487static void zebra_evpn_acc_vl_free(struct zebra_evpn_access_bd *acc_bd)
488{
489 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
490 zlog_debug("access vlan %d del", acc_bd->vid);
491
492 /* cleanup resources maintained against the ES */
493 list_delete(&acc_bd->mbr_zifs);
494
495 /* remove EVI from various tables */
496 hash_release(zmh_info->evpn_vlan_table, acc_bd);
497
498 XFREE(MTYPE_ZACC_BD, acc_bd);
499}
500
501static void zebra_evpn_acc_vl_cleanup_all(struct hash_bucket *bucket, void *arg)
502{
503 struct zebra_evpn_access_bd *acc_bd = bucket->data;
504
505 zebra_evpn_acc_vl_free(acc_bd);
506}
507
508/* called when a bd mbr is removed or VxLAN_IF is diassociated from the access
509 * VLAN
510 */
511static void zebra_evpn_acc_bd_free_on_deref(struct zebra_evpn_access_bd *acc_bd)
512{
513 if (!list_isempty(acc_bd->mbr_zifs) || acc_bd->vxlan_zif)
514 return;
515
516 /* if there are no references free the EVI */
517 zebra_evpn_acc_vl_free(acc_bd);
518}
519
520/* called when a EVPN-L2VNI is set or cleared against a BD */
87d76d54
PR
521static void zebra_evpn_acc_bd_evpn_set(struct zebra_evpn_access_bd *acc_bd,
522 zebra_evpn_t *zevpn, zebra_evpn_t *old_zevpn)
ce5160c0
AK
523{
524 struct zebra_if *zif;
525 struct listnode *node;
526
527 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
528 zlog_debug("access vlan %d l2-vni %u set",
87d76d54 529 acc_bd->vid, zevpn ? zevpn->vni : 0);
ce5160c0
AK
530
531 for (ALL_LIST_ELEMENTS_RO(acc_bd->mbr_zifs, node, zif)) {
532 if (!zif->es_info.es)
533 continue;
534
87d76d54
PR
535 if (zevpn)
536 zebra_evpn_local_es_evi_add(zif->es_info.es, zevpn);
537 else if (old_zevpn)
538 zebra_evpn_local_es_evi_del(zif->es_info.es, old_zevpn);
ce5160c0
AK
539 }
540}
541
542/* handle VLAN->VxLAN_IF association */
543void zebra_evpn_vl_vxl_ref(uint16_t vid, struct zebra_if *vxlan_zif)
544{
545 struct zebra_evpn_access_bd *acc_bd;
546 struct zebra_if *old_vxlan_zif;
87d76d54 547 zebra_evpn_t *old_zevpn;
ce5160c0
AK
548
549 if (!vid)
550 return;
551
552 acc_bd = zebra_evpn_acc_vl_find(vid);
553 if (!acc_bd)
554 acc_bd = zebra_evpn_acc_vl_new(vid);
555
556 old_vxlan_zif = acc_bd->vxlan_zif;
557 acc_bd->vxlan_zif = vxlan_zif;
558 if (vxlan_zif == old_vxlan_zif)
559 return;
560
87d76d54 561 old_zevpn = acc_bd->zevpn;
8b5fdf2e 562 acc_bd->zevpn = zebra_evpn_lookup(vxlan_zif->l2info.vxl.vni);
87d76d54 563 if (acc_bd->zevpn == old_zevpn)
ce5160c0
AK
564 return;
565
566 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
567 zlog_debug("access vlan %d vni %u ref",
568 acc_bd->vid, vxlan_zif->l2info.vxl.vni);
569
87d76d54
PR
570 if (old_zevpn)
571 zebra_evpn_acc_bd_evpn_set(acc_bd, NULL, old_zevpn);
ce5160c0 572
87d76d54
PR
573 if (acc_bd->zevpn)
574 zebra_evpn_acc_bd_evpn_set(acc_bd, acc_bd->zevpn, NULL);
ce5160c0
AK
575}
576
577/* handle VLAN->VxLAN_IF deref */
578void zebra_evpn_vl_vxl_deref(uint16_t vid, struct zebra_if *vxlan_zif)
579{
580 struct zebra_evpn_access_bd *acc_bd;
581
582 if (!vid)
583 return;
584
585 acc_bd = zebra_evpn_acc_vl_find(vid);
586 if (!acc_bd)
587 return;
588
589 /* clear vxlan_if only if it matches */
590 if (acc_bd->vxlan_zif != vxlan_zif)
591 return;
592
593 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
594 zlog_debug("access vlan %d vni %u deref",
595 acc_bd->vid, vxlan_zif->l2info.vxl.vni);
596
87d76d54
PR
597 if (acc_bd->zevpn)
598 zebra_evpn_acc_bd_evpn_set(acc_bd, NULL, acc_bd->zevpn);
ce5160c0 599
87d76d54 600 acc_bd->zevpn = NULL;
ce5160c0
AK
601 acc_bd->vxlan_zif = NULL;
602
603 /* if there are no other references the access_bd can be freed */
604 zebra_evpn_acc_bd_free_on_deref(acc_bd);
605}
606
87d76d54
PR
607/* handle EVPN add/del */
608void zebra_evpn_vxl_evpn_set(struct zebra_if *zif, zebra_evpn_t *zevpn,
ce5160c0
AK
609 bool set)
610{
611 struct zebra_l2info_vxlan *vxl;
612 struct zebra_evpn_access_bd *acc_bd;
613
614 if (!zif)
615 return;
616
617 /* locate access_bd associated with the vxlan device */
618 vxl = &zif->l2info.vxl;
619 acc_bd = zebra_evpn_acc_vl_find(vxl->access_vlan);
620 if (!acc_bd)
621 return;
622
623 if (set) {
87d76d54
PR
624 zebra_evpn_es_set_base_evpn(zevpn);
625 if (acc_bd->zevpn != zevpn) {
626 acc_bd->zevpn = zevpn;
627 zebra_evpn_acc_bd_evpn_set(acc_bd, zevpn, NULL);
ce5160c0
AK
628 }
629 } else {
87d76d54
PR
630 if (acc_bd->zevpn) {
631 zebra_evpn_t *old_zevpn = acc_bd->zevpn;
632 acc_bd->zevpn = NULL;
633 zebra_evpn_acc_bd_evpn_set(acc_bd, NULL, old_zevpn);
ce5160c0
AK
634 }
635 }
636}
637
638/* handle addition of new VLAN members */
639void zebra_evpn_vl_mbr_ref(uint16_t vid, struct zebra_if *zif)
640{
641 struct zebra_evpn_access_bd *acc_bd;
642
643 if (!vid)
644 return;
645
646 acc_bd = zebra_evpn_acc_vl_find(vid);
647 if (!acc_bd)
648 acc_bd = zebra_evpn_acc_vl_new(vid);
649
650 if (listnode_lookup(acc_bd->mbr_zifs, zif))
651 return;
652
653 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
654 zlog_debug("access vlan %d mbr %s ref",
655 vid, zif->ifp->name);
656
657 listnode_add(acc_bd->mbr_zifs, zif);
87d76d54
PR
658 if (acc_bd->zevpn && zif->es_info.es)
659 zebra_evpn_local_es_evi_add(zif->es_info.es, acc_bd->zevpn);
ce5160c0
AK
660}
661
662/* handle deletion of VLAN members */
663void zebra_evpn_vl_mbr_deref(uint16_t vid, struct zebra_if *zif)
664{
665 struct zebra_evpn_access_bd *acc_bd;
666 struct listnode *node;
667
668 if (!vid)
669 return;
670
671 acc_bd = zebra_evpn_acc_vl_find(vid);
672 if (!acc_bd)
673 return;
674
675 node = listnode_lookup(acc_bd->mbr_zifs, zif);
676 if (!node)
677 return;
678
679 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
680 zlog_debug("access vlan %d mbr %s deref",
681 vid, zif->ifp->name);
682
683 list_delete_node(acc_bd->mbr_zifs, node);
684
87d76d54
PR
685 if (acc_bd->zevpn && zif->es_info.es)
686 zebra_evpn_local_es_evi_del(zif->es_info.es, acc_bd->zevpn);
ce5160c0
AK
687
688 /* if there are no other references the access_bd can be freed */
689 zebra_evpn_acc_bd_free_on_deref(acc_bd);
690}
691
692static void zebra_evpn_acc_vl_show_entry_detail(struct vty *vty,
693 struct zebra_evpn_access_bd *acc_bd, json_object *json)
694{
695 struct zebra_if *zif;
696 struct listnode *node;
697
698 if (json) {
699 /* XXX */
700 } else {
701 vty_out(vty, "VLAN: %u\n", acc_bd->vid);
702 vty_out(vty, " VxLAN Interface: %s\n",
703 acc_bd->vxlan_zif ?
704 acc_bd->vxlan_zif->ifp->name : "-");
705 vty_out(vty, " L2-VNI: %d\n",
87d76d54 706 acc_bd->zevpn ? acc_bd->zevpn->vni : 0);
ce5160c0
AK
707 vty_out(vty, " Member Count: %d\n",
708 listcount(acc_bd->mbr_zifs));
709 vty_out(vty, " Members: \n");
710 for (ALL_LIST_ELEMENTS_RO(acc_bd->mbr_zifs, node, zif))
711 vty_out(vty, " %s\n", zif->ifp->name);
712 vty_out(vty, "\n");
713 }
714}
715
716static void zebra_evpn_acc_vl_show_entry(struct vty *vty,
717 struct zebra_evpn_access_bd *acc_bd, json_object *json)
718{
719 if (!json)
720 vty_out(vty, "%-5u %21s %-8d %u\n",
721 acc_bd->vid,
722 acc_bd->vxlan_zif ?
723 acc_bd->vxlan_zif->ifp->name : "-",
87d76d54 724 acc_bd->zevpn ? acc_bd->zevpn->vni : 0,
ce5160c0
AK
725 listcount(acc_bd->mbr_zifs));
726}
727
728static void zebra_evpn_acc_vl_show_hash(struct hash_bucket *bucket, void *ctxt)
729{
730 struct evpn_mh_show_ctx *wctx = ctxt;
731 struct zebra_evpn_access_bd *acc_bd = bucket->data;
732
733 if (wctx->detail)
734 zebra_evpn_acc_vl_show_entry_detail(wctx->vty,
735 acc_bd, wctx->json);
736 else
737 zebra_evpn_acc_vl_show_entry(wctx->vty,
738 acc_bd, wctx->json);
739}
740
741void zebra_evpn_acc_vl_show(struct vty *vty, bool uj)
742{
743 json_object *json = NULL;
744 struct evpn_mh_show_ctx wctx;
745
746 memset(&wctx, 0, sizeof(wctx));
747 wctx.vty = vty;
748 wctx.json = json;
749 wctx.detail = false;
750
751 if (!json)
752 vty_out(vty, "%-5s %21s %-8s %s\n",
753 "VLAN", "VxLAN-IF", "L2-VNI", "# Members");
754
755 hash_iterate(zmh_info->evpn_vlan_table, zebra_evpn_acc_vl_show_hash,
756 &wctx);
757}
758
759void zebra_evpn_acc_vl_show_detail(struct vty *vty, bool uj)
760{
761 json_object *json = NULL;
762 struct evpn_mh_show_ctx wctx;
763
764 memset(&wctx, 0, sizeof(wctx));
765 wctx.vty = vty;
766 wctx.json = json;
767 wctx.detail = true;
768
769 hash_iterate(zmh_info->evpn_vlan_table, zebra_evpn_acc_vl_show_hash,
770 &wctx);
771}
772
773void zebra_evpn_acc_vl_show_vid(struct vty *vty, bool uj, vlanid_t vid)
774{
775 json_object *json = NULL;
776 struct zebra_evpn_access_bd *acc_bd;
777
778 acc_bd = zebra_evpn_acc_vl_find(vid);
779 if (!acc_bd) {
780 if (!json) {
781 vty_out(vty, "VLAN %u not present\n", vid);
782 return;
783 }
784 }
785 zebra_evpn_acc_vl_show_entry_detail(vty, acc_bd, json);
786}
787
788/* Initialize VLAN member bitmap on an interface. Although VLAN membership
789 * is independent of EVPN we only process it if its of interest to EVPN-MH
790 * i.e. on access ports that can be setup as Ethernet Segments. And that is
791 * intended as an optimization.
792 */
793void zebra_evpn_if_init(struct zebra_if *zif)
794{
795 if (!zebra_evpn_is_if_es_capable(zif))
796 return;
797
798 if (!bf_is_inited(zif->vlan_bitmap))
799 bf_init(zif->vlan_bitmap, IF_VLAN_BITMAP_MAX);
800
801 /* if an es_id and sysmac are already present against the interface
802 * activate it
803 */
804 zebra_evpn_local_es_update(zif, zif->es_info.lid, &zif->es_info.sysmac);
805}
806
807/* handle deletion of an access port by removing it from all associated
808 * broadcast domains.
809 */
810void zebra_evpn_if_cleanup(struct zebra_if *zif)
811{
812 vlanid_t vid;
ab06b033 813 struct zebra_evpn_es *es;
ce5160c0
AK
814
815 if (!bf_is_inited(zif->vlan_bitmap))
816 return;
817
818 bf_for_each_set_bit(zif->vlan_bitmap, vid, IF_VLAN_BITMAP_MAX) {
819 zebra_evpn_vl_mbr_deref(vid, zif);
820 }
821
822 bf_free(zif->vlan_bitmap);
823
824 /* Delete associated Ethernet Segment */
ab06b033
AK
825 es = zif->es_info.es;
826 if (es)
827 zebra_evpn_local_es_del(&es);
ce5160c0
AK
828}
829
830/*****************************************************************************
831 * L2 NH/NHG Management
832 * A L2 NH entry is programmed in the kernel for every ES-VTEP entry. This
833 * NH is then added to the L2-ECMP-NHG associated with the ES.
834 */
835static uint32_t zebra_evpn_nhid_alloc(bool is_nhg)
836{
837 uint32_t id;
838 int type;
839
840 bf_assign_index(zmh_info->nh_id_bitmap, id);
841
842 if (!id)
843 return 0;
844
845 type = is_nhg ? EVPN_NHG_ID_TYPE_BIT : EVPN_NH_ID_TYPE_BIT;
846 return (id | type);
847}
848
849static void zebra_evpn_nhid_free(uint32_t nh_id)
850{
851 uint32_t id = (nh_id & EVPN_NH_ID_VAL_MASK);
852
853 if (!id)
854 return;
855
856 bf_release_index(zmh_info->nh_id_bitmap, id);
857}
858
859/* The MAC ECMP group is activated on the first VTEP */
860static void zebra_evpn_nhg_update(struct zebra_evpn_es *es)
861{
862 uint32_t nh_cnt = 0;
863 struct nh_grp nh_ids[ES_VTEP_MAX_CNT];
864 struct zebra_evpn_es_vtep *es_vtep;
865 struct listnode *node;
866
867 if (!es->nhg_id)
868 return;
869
870 for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
871 if (!es_vtep->nh_id)
872 continue;
873
874 if (nh_cnt >= ES_VTEP_MAX_CNT)
875 break;
876
877 memset(&nh_ids[nh_cnt], 0, sizeof(struct nh_grp));
878 nh_ids[nh_cnt].id = es_vtep->nh_id;
879 ++nh_cnt;
880 }
881
882 if (nh_cnt) {
883 if (IS_ZEBRA_DEBUG_EVPN_MH_NH) {
884 char nh_str[ES_VTEP_LIST_STR_SZ];
885 uint32_t i;
9e0c2fd1 886 char nh_buf[16];
ce5160c0
AK
887
888 nh_str[0] = '\0';
9e0c2fd1
AK
889 for (i = 0; i < nh_cnt; ++i) {
890 snprintf(nh_buf, sizeof(nh_buf), "%u ",
891 nh_ids[i].id);
892 strlcat(nh_str, nh_buf, sizeof(nh_str));
893 }
ce5160c0
AK
894 zlog_debug("es %s nhg 0x%x add %s",
895 es->esi_str, es->nhg_id, nh_str);
896 }
897
898 es->flags |= ZEBRA_EVPNES_NHG_ACTIVE;
899 kernel_upd_mac_nhg(es->nhg_id, nh_cnt, nh_ids);
900 } else {
901 if (es->flags & ZEBRA_EVPNES_NHG_ACTIVE) {
902 if (IS_ZEBRA_DEBUG_EVPN_MH_NH)
903 zlog_debug("es %s nhg 0x%x del",
904 es->esi_str, es->nhg_id);
905 es->flags &= ~ZEBRA_EVPNES_NHG_ACTIVE;
906 kernel_del_mac_nhg(es->nhg_id);
907 }
908 }
909
910 /* XXX - update remote macs associated with the ES */
911}
912
913static void zebra_evpn_nh_add(struct zebra_evpn_es_vtep *es_vtep)
914{
915 if (es_vtep->nh_id)
916 return;
917
918 es_vtep->nh_id = zebra_evpn_nhid_alloc(false);
919
920 if (!es_vtep->nh_id)
921 return;
922
923 if (IS_ZEBRA_DEBUG_EVPN_MH_NH)
9bcef951 924 zlog_debug("es %s vtep %pI4 nh 0x%x add",
ce5160c0 925 es_vtep->es->esi_str,
9bcef951 926 &es_vtep->vtep_ip, es_vtep->nh_id);
ce5160c0
AK
927 /* install the NH */
928 kernel_upd_mac_nh(es_vtep->nh_id, es_vtep->vtep_ip);
929 /* add the NH to the parent NHG */
930 zebra_evpn_nhg_update(es_vtep->es);
931}
932
933static void zebra_evpn_nh_del(struct zebra_evpn_es_vtep *es_vtep)
934{
935 uint32_t nh_id;
936
937 if (!es_vtep->nh_id)
938 return;
939
940 if (IS_ZEBRA_DEBUG_EVPN_MH_NH)
9bcef951 941 zlog_debug("es %s vtep %pI4 nh 0x%x del",
ce5160c0 942 es_vtep->es->esi_str,
9bcef951 943 &es_vtep->vtep_ip, es_vtep->nh_id);
ce5160c0
AK
944
945 nh_id = es_vtep->nh_id;
946 es_vtep->nh_id = 0;
947
948 /* remove the NH from the parent NHG */
949 zebra_evpn_nhg_update(es_vtep->es);
950 /* uninstall the NH */
951 kernel_del_mac_nh(nh_id);
952 zebra_evpn_nhid_free(nh_id);
953
954}
955
956/*****************************************************************************/
957/* Ethernet Segment Management
958 * 1. Ethernet Segment is a collection of links attached to the same
959 * server (MHD) or switch (MHN)
960 * 2. An Ethernet Segment can span multiple PEs and is identified by the
961 * 10-byte ES-ID.
962 * 3. Zebra manages the local ESI configuration.
963 * 4. It also maintains the aliasing that maps an ESI (local or remote)
964 * to one or more PEs/VTEPs.
965 * 5. remote ESs are added by BGP (on rxing EAD Type-1 routes)
966 */
967/* A list of remote VTEPs is maintained for each ES. This list includes -
968 * 1. VTEPs for which we have imported the ESR i.e. ES-peers
969 * 2. VTEPs that have an "active" ES-EVI VTEP i.e. EAD-per-ES and EAD-per-EVI
87d76d54 970 * have been imported into one or more EVPNs
ce5160c0
AK
971 */
972static int zebra_evpn_es_vtep_cmp(void *p1, void *p2)
973{
974 const struct zebra_evpn_es_vtep *es_vtep1 = p1;
975 const struct zebra_evpn_es_vtep *es_vtep2 = p2;
976
977 return es_vtep1->vtep_ip.s_addr - es_vtep2->vtep_ip.s_addr;
978}
979
980static struct zebra_evpn_es_vtep *zebra_evpn_es_vtep_new(
981 struct zebra_evpn_es *es, struct in_addr vtep_ip)
982{
983 struct zebra_evpn_es_vtep *es_vtep;
984
985 es_vtep = XCALLOC(MTYPE_ZES_VTEP, sizeof(*es_vtep));
986
987 es_vtep->es = es;
988 es_vtep->vtep_ip.s_addr = vtep_ip.s_addr;
989 listnode_init(&es_vtep->es_listnode, es_vtep);
990 listnode_add_sort(es->es_vtep_list, &es_vtep->es_listnode);
991
992 return es_vtep;
993}
994
995static void zebra_evpn_es_vtep_free(struct zebra_evpn_es_vtep *es_vtep)
996{
997 struct zebra_evpn_es *es = es_vtep->es;
998
999 list_delete_node(es->es_vtep_list, &es_vtep->es_listnode);
1000 /* update the L2-NHG associated with the ES */
1001 zebra_evpn_nh_del(es_vtep);
1002 XFREE(MTYPE_ZES_VTEP, es_vtep);
1003}
1004
1005
1006/* check if VTEP is already part of the list */
1007static struct zebra_evpn_es_vtep *zebra_evpn_es_vtep_find(
1008 struct zebra_evpn_es *es, struct in_addr vtep_ip)
1009{
1010 struct listnode *node = NULL;
1011 struct zebra_evpn_es_vtep *es_vtep;
1012
1013 for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
1014 if (es_vtep->vtep_ip.s_addr == vtep_ip.s_addr)
1015 return es_vtep;
1016 }
1017 return NULL;
1018}
1019
1103c5c6
AK
1020static void zebra_evpn_es_df_change(struct zebra_evpn_es *es, bool new_non_df,
1021 const char *caller)
1022{
1023 bool old_non_df;
1024
1025 old_non_df = !!(es->flags & ZEBRA_EVPNES_NON_DF);
1026
1027 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1028 zlog_debug("df-change(%s) es %s old %s new %s", caller,
1029 es->esi_str, old_non_df ? "non-df" : "df",
1030 new_non_df ? "non-df" : "df");
1031
1032 if (old_non_df == new_non_df)
1033 return;
1034
1035 if (new_non_df) {
1036 es->flags |= ZEBRA_EVPNES_NON_DF;
1037 /* XXX - Setup a dataplane DF filter to block BUM traffic */
1038 } else {
1039 es->flags &= ~ZEBRA_EVPNES_NON_DF;
1040 /* XXX - clear the non-DF block filter */
1041 }
1042}
1043
1044static void zebra_evpn_es_run_df_election(struct zebra_evpn_es *es,
1045 const char *caller)
1046{
1047 struct listnode *node = NULL;
1048 struct zebra_evpn_es_vtep *es_vtep;
1049 bool new_non_df = false;
1050
1051 /* If the ES is not ready (i.e. not completely configured) there
1052 * is no need to setup the BUM block filter
1053 */
1054 if (!(es->flags & ZEBRA_EVPNES_LOCAL)
1055 || !zmh_info->es_originator_ip.s_addr) {
1056 zebra_evpn_es_df_change(es, new_non_df, caller);
1057 return;
1058 }
1059
1060 /* if oper-state is down DF filtering must be on. when the link comes
1061 * up again dataplane should block BUM till FRR has had the chance
1062 * to run DF election again
1063 */
1064 if (!(es->flags & ZEBRA_EVPNES_OPER_UP)) {
1065 new_non_df = true;
1066 zebra_evpn_es_df_change(es, new_non_df, caller);
1067 return;
1068 }
1069
1070 for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
1071 /* Only VTEPs that have advertised the ESR can participate
1072 * in DF election
1073 */
1074 if (!(es_vtep->flags & ZEBRA_EVPNES_VTEP_RXED_ESR))
1075 continue;
1076
1077 /* If the DF alg is not the same we should fall back to
1078 * service-carving. But as service-carving is not supported
1079 * we will stop forwarding BUM
1080 */
1081 if (es_vtep->df_alg != EVPN_MH_DF_ALG_PREF) {
1082 new_non_df = true;
1083 break;
1084 }
1085
1086 /* Peer VTEP wins DF election if -
1087 * the peer-VTEP has higher preference (or)
1088 * the pref is the same but peer's IP address is lower
1089 */
1090 if ((es_vtep->df_pref > es->df_pref)
1091 || ((es_vtep->df_pref == es->df_pref)
1092 && (es_vtep->vtep_ip.s_addr
1093 < zmh_info->es_originator_ip.s_addr))) {
1094 new_non_df = true;
1095 break;
1096 }
1097 }
1098
1099 zebra_evpn_es_df_change(es, new_non_df, caller);
1100}
1101
ce5160c0 1102static void zebra_evpn_es_vtep_add(struct zebra_evpn_es *es,
1103c5c6
AK
1103 struct in_addr vtep_ip, bool esr_rxed,
1104 uint8_t df_alg, uint16_t df_pref)
ce5160c0
AK
1105{
1106 struct zebra_evpn_es_vtep *es_vtep;
1103c5c6 1107 bool old_esr_rxed;
ce5160c0
AK
1108
1109 es_vtep = zebra_evpn_es_vtep_find(es, vtep_ip);
1110
1111 if (!es_vtep) {
1112 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
9bcef951
MS
1113 zlog_debug("es %s vtep %pI4 add",
1114 es->esi_str, &vtep_ip);
ce5160c0
AK
1115 es_vtep = zebra_evpn_es_vtep_new(es, vtep_ip);
1116 /* update the L2-NHG associated with the ES */
1117 zebra_evpn_nh_add(es_vtep);
1118 }
1103c5c6
AK
1119
1120 old_esr_rxed = !!(es_vtep->flags & ZEBRA_EVPNES_VTEP_RXED_ESR);
1121 if ((old_esr_rxed != esr_rxed) || (es_vtep->df_alg != df_alg)
1122 || (es_vtep->df_pref != df_pref)) {
1123 /* If any of the DF election params changed we need to re-run
1124 * DF election
1125 */
1126 if (esr_rxed)
1127 es_vtep->flags |= ZEBRA_EVPNES_VTEP_RXED_ESR;
1128 else
1129 es_vtep->flags &= ~ZEBRA_EVPNES_VTEP_RXED_ESR;
1130 es_vtep->df_alg = df_alg;
1131 es_vtep->df_pref = df_pref;
1132 zebra_evpn_es_run_df_election(es, __func__);
1133 }
ce5160c0
AK
1134}
1135
1136static void zebra_evpn_es_vtep_del(struct zebra_evpn_es *es,
1137 struct in_addr vtep_ip)
1138{
1139 struct zebra_evpn_es_vtep *es_vtep;
1140
1141 es_vtep = zebra_evpn_es_vtep_find(es, vtep_ip);
1142
1143 if (es_vtep) {
1144 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
9bcef951
MS
1145 zlog_debug("es %s vtep %pI4 del",
1146 es->esi_str, &vtep_ip);
1103c5c6
AK
1147 if (es_vtep->flags & ZEBRA_EVPNES_VTEP_RXED_ESR) {
1148 es_vtep->flags &= ~ZEBRA_EVPNES_VTEP_RXED_ESR;
1149 zebra_evpn_es_run_df_election(es, __func__);
1150 }
ce5160c0
AK
1151 zebra_evpn_es_vtep_free(es_vtep);
1152 }
1153}
1154
1155/* compare ES-IDs for the global ES RB tree */
1156static int zebra_es_rb_cmp(const struct zebra_evpn_es *es1,
1157 const struct zebra_evpn_es *es2)
1158{
1159 return memcmp(&es1->esi, &es2->esi, ESI_BYTES);
1160}
1161RB_GENERATE(zebra_es_rb_head, zebra_evpn_es, rb_node, zebra_es_rb_cmp);
1162
1163/* Lookup ES */
1164struct zebra_evpn_es *zebra_evpn_es_find(esi_t *esi)
1165{
1166 struct zebra_evpn_es tmp;
1167
1168 memcpy(&tmp.esi, esi, sizeof(esi_t));
1169 return RB_FIND(zebra_es_rb_head, &zmh_info->es_rb_tree, &tmp);
1170}
1171
1172/* A new local es is created when a local-es-id and sysmac is configured
1173 * against an interface.
1174 */
1175static struct zebra_evpn_es *zebra_evpn_es_new(esi_t *esi)
1176{
1177 struct zebra_evpn_es *es;
1178
1179 es = XCALLOC(MTYPE_ZES, sizeof(struct zebra_evpn_es));
1180
1181 /* fill in ESI */
1182 memcpy(&es->esi, esi, sizeof(esi_t));
1183 esi_to_str(&es->esi, es->esi_str, sizeof(es->esi_str));
1184
1185 /* Add to rb_tree */
1186 if (RB_INSERT(zebra_es_rb_head, &zmh_info->es_rb_tree, es)) {
1187 XFREE(MTYPE_ZES, es);
1188 return NULL;
1189 }
1190
1191 /* Initialise the ES-EVI list */
1192 es->es_evi_list = list_new();
1193 listset_app_node_mem(es->es_evi_list);
1194
1195 /* Initialise the VTEP list */
1196 es->es_vtep_list = list_new();
1197 listset_app_node_mem(es->es_vtep_list);
1198 es->es_vtep_list->cmp = zebra_evpn_es_vtep_cmp;
1199
b169fd6f
AK
1200 /* mac entries associated with the ES */
1201 es->mac_list = list_new();
1202 listset_app_node_mem(es->mac_list);
1203
ce5160c0
AK
1204 /* reserve a NHG */
1205 es->nhg_id = zebra_evpn_nhid_alloc(true);
1206
1207 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1208 zlog_debug("es %s nhg 0x%x new", es->esi_str, es->nhg_id);
1209
1210 return es;
1211}
1212
1213/* Free a given ES -
1214 * This just frees appropriate memory, caller should have taken other
1215 * needed actions.
1216 */
e378f502 1217static void zebra_evpn_es_free(struct zebra_evpn_es **esp)
ce5160c0 1218{
e378f502
AK
1219 struct zebra_evpn_es *es = *esp;
1220
ce5160c0
AK
1221 /* If the ES has a local or remote reference it cannot be freed.
1222 * Free is also prevented if there are MAC entries referencing
1223 * it.
1224 */
1225 if ((es->flags & (ZEBRA_EVPNES_LOCAL | ZEBRA_EVPNES_REMOTE)) ||
b169fd6f 1226 listcount(es->mac_list))
e378f502 1227 return;
ce5160c0
AK
1228
1229 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1230 zlog_debug("es %s free", es->esi_str);
1231
1232 /* If the NHG is still installed uninstall it and free the id */
1233 if (es->flags & ZEBRA_EVPNES_NHG_ACTIVE) {
1234 es->flags &= ~ZEBRA_EVPNES_NHG_ACTIVE;
1235 kernel_del_mac_nhg(es->nhg_id);
1236 }
1237 zebra_evpn_nhid_free(es->nhg_id);
1238
1239 /* cleanup resources maintained against the ES */
1240 list_delete(&es->es_evi_list);
1241 list_delete(&es->es_vtep_list);
b169fd6f 1242 list_delete(&es->mac_list);
ce5160c0
AK
1243
1244 /* remove from the VNI-ESI rb tree */
1245 RB_REMOVE(zebra_es_rb_head, &zmh_info->es_rb_tree, es);
1246
1247 XFREE(MTYPE_ZES, es);
b169fd6f 1248
e378f502 1249 *esp = NULL;
ce5160c0
AK
1250}
1251
1252/* Inform BGP about local ES addition */
1253static int zebra_evpn_es_send_add_to_client(struct zebra_evpn_es *es)
1254{
1255 struct zserv *client;
1256 struct stream *s;
1257 uint8_t oper_up;
1258
1259 client = zserv_find_client(ZEBRA_ROUTE_BGP, 0);
1260 /* BGP may not be running. */
1261 if (!client)
1262 return 0;
1263
1264 s = stream_new(ZEBRA_MAX_PACKET_SIZ);
1265
1266 zclient_create_header(s, ZEBRA_LOCAL_ES_ADD, zebra_vrf_get_evpn_id());
1267 stream_put(s, &es->esi, sizeof(esi_t));
1268 stream_put_ipv4(s, zmh_info->es_originator_ip.s_addr);
1269 oper_up = !!(es->flags & ZEBRA_EVPNES_OPER_UP);
1270 stream_putc(s, oper_up);
1103c5c6 1271 stream_putw(s, es->df_pref);
ce5160c0
AK
1272
1273 /* Write packet size. */
1274 stream_putw_at(s, 0, stream_get_endp(s));
1275
1276 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1103c5c6
AK
1277 zlog_debug("send add local es %s %pI4 active %u df_pref %u to %s",
1278 es->esi_str, &zmh_info->es_originator_ip,
1279 oper_up, es->df_pref,
1280 zebra_route_string(client->proto));
ce5160c0
AK
1281
1282 client->local_es_add_cnt++;
1283 return zserv_send_message(client, s);
1284}
1285
1286/* Inform BGP about local ES deletion */
1287static int zebra_evpn_es_send_del_to_client(struct zebra_evpn_es *es)
1288{
1289 struct zserv *client;
1290 struct stream *s;
1291
1292 client = zserv_find_client(ZEBRA_ROUTE_BGP, 0);
1293 /* BGP may not be running. */
1294 if (!client)
1295 return 0;
1296
1297 s = stream_new(ZEBRA_MAX_PACKET_SIZ);
1298 stream_reset(s);
1299
1300 zclient_create_header(s, ZEBRA_LOCAL_ES_DEL, zebra_vrf_get_evpn_id());
1301 stream_put(s, &es->esi, sizeof(esi_t));
1302
1303 /* Write packet size. */
1304 stream_putw_at(s, 0, stream_get_endp(s));
1305
1306 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1307 zlog_debug("send del local es %s to %s", es->esi_str,
1308 zebra_route_string(client->proto));
1309
1310 client->local_es_del_cnt++;
1311 return zserv_send_message(client, s);
1312}
1313
ce5160c0
AK
1314static void zebra_evpn_es_re_eval_send_to_client(struct zebra_evpn_es *es,
1315 bool es_evi_re_reval)
1316{
1317 bool old_ready;
1318 bool new_ready;
1319 struct listnode *node;
1320 struct zebra_evpn_es_evi *es_evi;
1321
1322 old_ready = !!(es->flags & ZEBRA_EVPNES_READY_FOR_BGP);
1323
1324 if ((es->flags & ZEBRA_EVPNES_LOCAL) &&
1325 zmh_info->es_originator_ip.s_addr)
1326 es->flags |= ZEBRA_EVPNES_READY_FOR_BGP;
1327 else
1328 es->flags &= ~ZEBRA_EVPNES_READY_FOR_BGP;
1329
1330 new_ready = !!(es->flags & ZEBRA_EVPNES_READY_FOR_BGP);
1331 if (old_ready == new_ready)
1332 return;
1333
1334 if (new_ready)
1335 zebra_evpn_es_send_add_to_client(es);
1336 else
1337 zebra_evpn_es_send_del_to_client(es);
1338
1339 /* re-eval associated EVIs */
1340 if (es_evi_re_reval) {
1341 for (ALL_LIST_ELEMENTS_RO(es->es_evi_list, node, es_evi)) {
1342 if (!(es_evi->flags & ZEBRA_EVPNES_EVI_LOCAL))
1343 continue;
1344 zebra_evpn_es_evi_re_eval_send_to_client(es_evi);
1345 }
1346 }
1347}
1348
1349void zebra_evpn_es_send_all_to_client(bool add)
1350{
1351 struct listnode *es_node;
1352 struct listnode *evi_node;
1353 struct zebra_evpn_es *es;
1354 struct zebra_evpn_es_evi *es_evi;
1355
1356 if (!zmh_info)
1357 return;
1358
1359 for (ALL_LIST_ELEMENTS_RO(zmh_info->local_es_list, es_node, es)) {
1360 if (es->flags & ZEBRA_EVPNES_READY_FOR_BGP) {
1361 if (add)
1362 zebra_evpn_es_send_add_to_client(es);
1363 for (ALL_LIST_ELEMENTS_RO(es->es_evi_list,
1364 evi_node, es_evi)) {
1365 if (!(es_evi->flags &
1366 ZEBRA_EVPNES_EVI_READY_FOR_BGP))
1367 continue;
1368
1369 if (add)
1370 zebra_evpn_es_evi_send_to_client(
87d76d54 1371 es, es_evi->zevpn,
ce5160c0
AK
1372 true /* add */);
1373 else
1374 zebra_evpn_es_evi_send_to_client(
87d76d54 1375 es, es_evi->zevpn,
ce5160c0
AK
1376 false /* add */);
1377 }
1378 if (!add)
1379 zebra_evpn_es_send_del_to_client(es);
1380 }
1381 }
1382}
1383
1384/* walk the vlan bitmap associated with the zif and create or delete
1385 * es_evis for all vlans associated with a VNI.
1386 * XXX: This API is really expensive. optimize later if possible.
1387 */
1388static void zebra_evpn_es_setup_evis(struct zebra_evpn_es *es)
1389{
1390 struct zebra_if *zif = es->zif;
1391 uint16_t vid;
1392 struct zebra_evpn_access_bd *acc_bd;
1393
1394
1395 bf_for_each_set_bit(zif->vlan_bitmap, vid, IF_VLAN_BITMAP_MAX) {
1396 acc_bd = zebra_evpn_acc_vl_find(vid);
87d76d54
PR
1397 if (acc_bd->zevpn)
1398 zebra_evpn_local_es_evi_add(es, acc_bd->zevpn);
ce5160c0
AK
1399 }
1400}
1401
b169fd6f
AK
1402static void zebra_evpn_es_local_mac_update(struct zebra_evpn_es *es,
1403 bool force_clear_static)
1404{
1405 zebra_mac_t *mac;
1406 struct listnode *node;
1407
1408 for (ALL_LIST_ELEMENTS_RO(es->mac_list, node, mac)) {
1409 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE)) {
b2998086
PR
1410 zebra_evpn_sync_mac_dp_install(
1411 mac, false /* set_inactive */,
1412 force_clear_static, __func__);
b169fd6f
AK
1413 }
1414 }
1415}
1416
ce5160c0
AK
1417static void zebra_evpn_es_local_info_set(struct zebra_evpn_es *es,
1418 struct zebra_if *zif)
1419{
1420 if (es->flags & ZEBRA_EVPNES_LOCAL)
1421 return;
1422
1423 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1424 zlog_debug("local es %s add; nhg 0x%x if %s",
1425 es->esi_str, es->nhg_id, zif->ifp->name);
1426
1427 es->flags |= ZEBRA_EVPNES_LOCAL;
1428 listnode_init(&es->local_es_listnode, es);
1429 listnode_add(zmh_info->local_es_list, &es->local_es_listnode);
1430
1431 /* attach es to interface */
1432 zif->es_info.es = es;
1103c5c6
AK
1433 es->df_pref = zif->es_info.df_pref ? zif->es_info.df_pref
1434 : EVPN_MH_DF_PREF_DEFAULT;
ce5160c0
AK
1435
1436 /* attach interface to es */
1437 es->zif = zif;
1438 if (if_is_operative(zif->ifp))
1439 es->flags |= ZEBRA_EVPNES_OPER_UP;
1440
1441 /* setup base-vni if one doesn't already exist; the ES will get sent
1442 * to BGP as a part of that process
1443 */
87d76d54
PR
1444 if (!zmh_info->es_base_evpn)
1445 zebra_evpn_es_get_one_base_evpn();
ce5160c0
AK
1446 else
1447 /* send notification to bgp */
1448 zebra_evpn_es_re_eval_send_to_client(es,
1449 false /* es_evi_re_reval */);
1450
1103c5c6
AK
1451 /* See if the local VTEP can function as DF on the ES */
1452 zebra_evpn_es_run_df_election(es, __func__);
1453
ce5160c0
AK
1454 /* Setup ES-EVIs for all VxLAN stretched VLANs associated with
1455 * the zif
1456 */
1457 zebra_evpn_es_setup_evis(es);
b169fd6f
AK
1458 /* if there any local macs referring to the ES as dest we
1459 * need to set the static reference on them if the MAC is
1460 * synced from an ES peer
1461 */
1462 zebra_evpn_es_local_mac_update(es,
1463 false /* force_clear_static */);
ce5160c0
AK
1464}
1465
e378f502 1466static void zebra_evpn_es_local_info_clear(struct zebra_evpn_es **esp)
ce5160c0
AK
1467{
1468 struct zebra_if *zif;
e378f502 1469 struct zebra_evpn_es *es = *esp;
ce5160c0
AK
1470
1471 if (!(es->flags & ZEBRA_EVPNES_LOCAL))
1472 return;
1473
4cd94050
AK
1474 es->flags &= ~(ZEBRA_EVPNES_LOCAL | ZEBRA_EVPNES_READY_FOR_BGP);
1475
1103c5c6
AK
1476 /* remove the DF filter */
1477 zebra_evpn_es_run_df_election(es, __func__);
1478
b169fd6f
AK
1479 /* if there any local macs referring to the ES as dest we
1480 * need to clear the static reference on them
1481 */
1482 zebra_evpn_es_local_mac_update(es,
1483 true /* force_clear_static */);
1484
ce5160c0
AK
1485 /* clear the es from the parent interface */
1486 zif = es->zif;
1487 zif->es_info.es = NULL;
1488 es->zif = NULL;
1489
1490 /* remove from the ES list */
1491 list_delete_node(zmh_info->local_es_list, &es->local_es_listnode);
1492
1493 /* free up the ES if there is no remote reference */
e378f502 1494 zebra_evpn_es_free(esp);
ce5160c0
AK
1495}
1496
1497/* Delete an ethernet segment and inform BGP */
e378f502 1498static void zebra_evpn_local_es_del(struct zebra_evpn_es **esp)
ce5160c0
AK
1499{
1500 struct zebra_evpn_es_evi *es_evi;
1501 struct listnode *node = NULL;
1502 struct listnode *nnode = NULL;
1503 struct zebra_if *zif;
e378f502 1504 struct zebra_evpn_es *es = *esp;
ce5160c0
AK
1505
1506 if (!CHECK_FLAG(es->flags, ZEBRA_EVPNES_LOCAL))
1507 return;
1508
1509 if (IS_ZEBRA_DEBUG_EVPN_MH_ES) {
1510 zif = es->zif;
1511 zlog_debug("local es %s del; nhg 0x%x if %s",
1512 es->esi_str, es->nhg_id,
1513 zif ? zif->ifp->name : "-");
1514 }
1515
1516 /* remove all ES-EVIs associated with the ES */
1517 for (ALL_LIST_ELEMENTS(es->es_evi_list, node, nnode, es_evi))
1518 zebra_evpn_local_es_evi_do_del(es_evi);
1519
1520 /* send a del if the ES had been sent to BGP earlier */
1521 if (es->flags & ZEBRA_EVPNES_READY_FOR_BGP)
1522 zebra_evpn_es_send_del_to_client(es);
1523
e378f502 1524 zebra_evpn_es_local_info_clear(esp);
ce5160c0
AK
1525}
1526
1527/* eval remote info associated with the ES */
e378f502 1528static void zebra_evpn_es_remote_info_re_eval(struct zebra_evpn_es **esp)
ce5160c0 1529{
e378f502
AK
1530 struct zebra_evpn_es *es = *esp;
1531
ce5160c0
AK
1532 /* if there are remote VTEPs the ES-EVI is classified as "remote" */
1533 if (listcount(es->es_vtep_list)) {
1534 if (!(es->flags & ZEBRA_EVPNES_REMOTE)) {
1535 es->flags |= ZEBRA_EVPNES_REMOTE;
1536 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1537 zlog_debug("remote es %s add; nhg 0x%x",
1538 es->esi_str, es->nhg_id);
1539 }
1540 } else {
1541 if (es->flags & ZEBRA_EVPNES_REMOTE) {
1542 es->flags &= ~ZEBRA_EVPNES_REMOTE;
1543 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1544 zlog_debug("remote es %s del; nhg 0x%x",
1545 es->esi_str, es->nhg_id);
e378f502 1546 zebra_evpn_es_free(esp);
ce5160c0
AK
1547 }
1548 }
1549}
1550
1551/* A new local es is created when a local-es-id and sysmac is configured
1552 * against an interface.
1553 */
1554static int zebra_evpn_local_es_update(struct zebra_if *zif, uint32_t lid,
1555 struct ethaddr *sysmac)
1556{
1557 struct zebra_evpn_es *old_es = zif->es_info.es;
1558 struct zebra_evpn_es *es;
1559 esi_t esi;
1560 int offset = 0;
1561 int field_bytes = 0;
1562
1563 /* Complete config of the ES-ID bootstraps the ES */
1564 if (!lid || is_zero_mac(sysmac)) {
1565 /* if in ES is attached to zif delete it */
1566 if (old_es)
ab06b033 1567 zebra_evpn_local_es_del(&old_es);
ce5160c0
AK
1568 return 0;
1569 }
1570
1571 /* build 10-byte type-3-ESI -
1572 * Type(1-byte), MAC(6-bytes), ES-LID (3-bytes)
1573 */
1574 field_bytes = 1;
1575 esi.val[offset] = ESI_TYPE_MAC;
1576 offset += field_bytes;
1577
1578 field_bytes = ETH_ALEN;
1579 memcpy(&esi.val[offset], (uint8_t *)sysmac, field_bytes);
1580 offset += field_bytes;
1581
1582 esi.val[offset++] = (uint8_t)(lid >> 16);
1583 esi.val[offset++] = (uint8_t)(lid >> 8);
1584 esi.val[offset++] = (uint8_t)lid;
1585
1586 if (old_es && !memcmp(&old_es->esi, &esi, sizeof(esi_t)))
1587 /* dup - nothing to be done */
1588 return 0;
1589
1590 /* release the old_es against the zif */
1591 if (old_es)
ab06b033 1592 zebra_evpn_local_es_del(&old_es);
ce5160c0
AK
1593
1594 es = zebra_evpn_es_find(&esi);
1595 if (es) {
1596 /* if it exists against another interface flag an error */
1597 if (es->zif && es->zif != zif)
1598 return -1;
1599 } else {
1600 /* create new es */
1601 es = zebra_evpn_es_new(&esi);
1602 }
1603
1604 zebra_evpn_es_local_info_set(es, zif);
1605
1606 return 0;
1607}
1608
1609static int zebra_evpn_remote_es_del(esi_t *esi, struct in_addr vtep_ip)
1610{
1611 char buf[ESI_STR_LEN];
1612 struct zebra_evpn_es *es;
1613
1614 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
9bcef951
MS
1615 zlog_debug("remote es %s vtep %pI4 del",
1616 esi_to_str(esi, buf, sizeof(buf)), &vtep_ip);
ce5160c0
AK
1617
1618 es = zebra_evpn_es_find(esi);
1619 if (!es) {
4d8b658c 1620 zlog_warn("remote es %s vtep %pI4 del failed, es missing",
e378f502 1621 esi_to_str(esi, buf, sizeof(buf)), &vtep_ip);
ce5160c0
AK
1622 return -1;
1623 }
1624
1625 zebra_evpn_es_vtep_del(es, vtep_ip);
e378f502 1626 zebra_evpn_es_remote_info_re_eval(&es);
ce5160c0
AK
1627
1628 return 0;
1629}
1630
1631/* force delete a remote ES on the way down */
e378f502 1632static void zebra_evpn_remote_es_flush(struct zebra_evpn_es **esp)
ce5160c0
AK
1633{
1634 struct zebra_evpn_es_vtep *es_vtep;
1635 struct listnode *node;
1636 struct listnode *nnode;
e378f502 1637 struct zebra_evpn_es *es = *esp;
ce5160c0
AK
1638
1639 for (ALL_LIST_ELEMENTS(es->es_vtep_list, node, nnode, es_vtep)) {
1640 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
9bcef951 1641 zlog_debug("es %s vtep %pI4 flush",
ce5160c0 1642 es->esi_str,
9bcef951 1643 &es_vtep->vtep_ip);
ce5160c0 1644 zebra_evpn_es_vtep_free(es_vtep);
ce5160c0 1645 }
e378f502 1646 zebra_evpn_es_remote_info_re_eval(esp);
ce5160c0
AK
1647}
1648
1103c5c6
AK
1649static int zebra_evpn_remote_es_add(esi_t *esi, struct in_addr vtep_ip,
1650 bool esr_rxed, uint8_t df_alg,
1651 uint16_t df_pref)
ce5160c0
AK
1652{
1653 char buf[ESI_STR_LEN];
1654 struct zebra_evpn_es *es;
1655
1656 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1103c5c6
AK
1657 zlog_debug("remote es %s vtep %pI4 add %s df_alg %d df_pref %d",
1658 esi_to_str(esi, buf, sizeof(buf)),
1659 &vtep_ip, esr_rxed ? "esr" : "", df_alg,
1660 df_pref);
ce5160c0
AK
1661
1662 es = zebra_evpn_es_find(esi);
1663 if (!es) {
1664 es = zebra_evpn_es_new(esi);
1665 if (!es) {
e378f502
AK
1666 zlog_warn(
1667 "remote es %s vtep %pI4 add failed, es missing",
1668 esi_to_str(esi, buf, sizeof(buf)), &vtep_ip);
ce5160c0
AK
1669 return -1;
1670 }
1671 }
1672
1103c5c6 1673 zebra_evpn_es_vtep_add(es, vtep_ip, esr_rxed, df_alg, df_pref);
e378f502 1674 zebra_evpn_es_remote_info_re_eval(&es);
ce5160c0
AK
1675
1676 return 0;
1677}
1678
1679void zebra_evpn_proc_remote_es(ZAPI_HANDLER_ARGS)
1680{
1681 struct stream *s;
1682 struct in_addr vtep_ip;
1683 esi_t esi;
1684
1685 if (!is_evpn_enabled()) {
1686 zlog_debug(
1687 "%s: EVPN not enabled yet we received a es_add zapi call",
1688 __PRETTY_FUNCTION__);
1689 return;
1690 }
1691
1692 memset(&esi, 0, sizeof(esi_t));
1693 s = msg;
1694
1695 stream_get(&esi, s, sizeof(esi_t));
1696 vtep_ip.s_addr = stream_get_ipv4(s);
1697
1103c5c6
AK
1698 if (hdr->command == ZEBRA_REMOTE_ES_VTEP_ADD) {
1699 uint32_t zapi_flags;
1700 uint8_t df_alg;
1701 uint16_t df_pref;
1702 bool esr_rxed;
1703
1704 zapi_flags = stream_getl(s);
1705 esr_rxed = (zapi_flags & ZAPI_ES_VTEP_FLAG_ESR_RXED) ? true
1706 : false;
1707 df_alg = stream_getc(s);
1708 df_pref = stream_getw(s);
1709 zebra_evpn_remote_es_add(&esi, vtep_ip, esr_rxed, df_alg,
1710 df_pref);
1711 } else {
ce5160c0 1712 zebra_evpn_remote_es_del(&esi, vtep_ip);
1103c5c6 1713 }
ce5160c0
AK
1714}
1715
1716void zebra_evpn_es_mac_deref_entry(zebra_mac_t *mac)
1717{
1718 struct zebra_evpn_es *es = mac->es;
1719
1720 mac->es = NULL;
b169fd6f 1721 if (!es)
ce5160c0
AK
1722 return;
1723
b169fd6f
AK
1724 list_delete_node(es->mac_list, &mac->es_listnode);
1725 if (!listcount(es->mac_list))
e378f502 1726 zebra_evpn_es_free(&es);
ce5160c0
AK
1727}
1728
1729/* Associate a MAC entry with a local or remote ES. Returns false if there
1730 * was no ES change.
1731 */
1732bool zebra_evpn_es_mac_ref_entry(zebra_mac_t *mac, struct zebra_evpn_es *es)
1733{
1734 if (mac->es == es)
1735 return false;
1736
1737 if (mac->es)
1738 zebra_evpn_es_mac_deref_entry(mac);
1739
1740 if (!es)
1741 return true;
1742
1743 mac->es = es;
b169fd6f
AK
1744 listnode_init(&mac->es_listnode, mac);
1745 listnode_add(es->mac_list, &mac->es_listnode);
1746
ce5160c0
AK
1747 return true;
1748}
1749
b169fd6f 1750bool zebra_evpn_es_mac_ref(zebra_mac_t *mac, esi_t *esi)
ce5160c0
AK
1751{
1752 struct zebra_evpn_es *es;
1753
1754 es = zebra_evpn_es_find(esi);
1755 if (!es) {
4cd94050
AK
1756 /* If non-zero esi implicitly create a new ES */
1757 if (memcmp(esi, zero_esi, sizeof(esi_t))) {
1758 es = zebra_evpn_es_new(esi);
1759 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1760 zlog_debug("auto es %s add on mac ref",
1761 es->esi_str);
1762 }
ce5160c0
AK
1763 }
1764
b169fd6f 1765 return zebra_evpn_es_mac_ref_entry(mac, es);
ce5160c0
AK
1766}
1767
1768/* Inform BGP about local ES-EVI add or del */
1769static int zebra_evpn_es_evi_send_to_client(struct zebra_evpn_es *es,
87d76d54 1770 zebra_evpn_t *zevpn, bool add)
ce5160c0
AK
1771{
1772 struct zserv *client;
1773 struct stream *s;
1774
1775 client = zserv_find_client(ZEBRA_ROUTE_BGP, 0);
1776 /* BGP may not be running. */
1777 if (!client)
1778 return 0;
1779
1780 s = stream_new(ZEBRA_MAX_PACKET_SIZ);
1781
1782 zclient_create_header(s,
1783 add ? ZEBRA_LOCAL_ES_EVI_ADD : ZEBRA_LOCAL_ES_EVI_DEL,
1784 zebra_vrf_get_evpn_id());
1785 stream_put(s, &es->esi, sizeof(esi_t));
87d76d54 1786 stream_putl(s, zevpn->vni);
ce5160c0
AK
1787
1788 /* Write packet size. */
1789 stream_putw_at(s, 0, stream_get_endp(s));
1790
1791 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1792 zlog_debug("send %s local es %s evi %u to %s",
1793 add ? "add" : "del",
87d76d54 1794 es->esi_str, zevpn->vni,
ce5160c0
AK
1795 zebra_route_string(client->proto));
1796
1797 client->local_es_add_cnt++;
1798 return zserv_send_message(client, s);
1799}
1800
1801/* sysmac part of a local ESI has changed */
1802static int zebra_evpn_es_sys_mac_update(struct zebra_if *zif,
1803 struct ethaddr *sysmac)
1804{
1805 int rv;
1806
1807 rv = zebra_evpn_local_es_update(zif, zif->es_info.lid, sysmac);
1808 if (!rv)
1809 memcpy(&zif->es_info.sysmac, sysmac, sizeof(struct ethaddr));
1810
1811 return rv;
1812}
1813
1814/* local-ID part of ESI has changed */
1815static int zebra_evpn_es_lid_update(struct zebra_if *zif, uint32_t lid)
1816{
1817 int rv;
1818
1819 rv = zebra_evpn_local_es_update(zif, lid, &zif->es_info.sysmac);
1820 if (!rv)
1821 zif->es_info.lid = lid;
1822
1823 return rv;
1824}
1825
1826void zebra_evpn_es_cleanup(void)
1827{
1828 struct zebra_evpn_es *es;
1829 struct zebra_evpn_es *es_next;
1830
1831 RB_FOREACH_SAFE(es, zebra_es_rb_head,
1832 &zmh_info->es_rb_tree, es_next) {
e378f502
AK
1833 zebra_evpn_local_es_del(&es);
1834 if (es)
1835 zebra_evpn_remote_es_flush(&es);
ce5160c0
AK
1836 }
1837}
1838
1103c5c6
AK
1839static void zebra_evpn_es_df_pref_update(struct zebra_if *zif, uint16_t df_pref)
1840{
1841 struct zebra_evpn_es *es;
1842 uint16_t tmp_pref;
1843
1844 if (zif->es_info.df_pref == df_pref)
1845 return;
1846
1847 zif->es_info.df_pref = df_pref;
1848 es = zif->es_info.es;
1849
1850 if (!es)
1851 return;
1852
1853 tmp_pref = zif->es_info.df_pref ? zif->es_info.df_pref
1854 : EVPN_MH_DF_PREF_DEFAULT;
1855
1856 if (es->df_pref == tmp_pref)
1857 return;
1858
1859 es->df_pref = tmp_pref;
1860 /* run df election */
1861 zebra_evpn_es_run_df_election(es, __func__);
1862 /* notify bgp */
1863 if (es->flags & ZEBRA_EVPNES_READY_FOR_BGP)
1864 zebra_evpn_es_send_add_to_client(es);
1865}
1866
1867
ce5160c0
AK
1868/* Only certain types of access ports can be setup as an Ethernet Segment */
1869bool zebra_evpn_is_if_es_capable(struct zebra_if *zif)
1870{
1871 if (zif->zif_type == ZEBRA_IF_BOND)
1872 return true;
1873
1874 /* XXX: allow swpX i.e. a regular ethernet port to be an ES link too */
1875 return false;
1876}
1877
1878void zebra_evpn_if_es_print(struct vty *vty, struct zebra_if *zif)
1879{
1880 char buf[ETHER_ADDR_STRLEN];
1881
1882 if (zif->es_info.lid || !is_zero_mac(&zif->es_info.sysmac))
1883 vty_out(vty, " EVPN MH: ES id %u ES sysmac %s\n",
1884 zif->es_info.lid,
1885 prefix_mac2str(&zif->es_info.sysmac,
1886 buf, sizeof(buf)));
1887}
1888
1889void zebra_evpn_es_if_oper_state_change(struct zebra_if *zif, bool up)
1890{
1891 struct zebra_evpn_es *es = zif->es_info.es;
1892 bool old_up = !!(es->flags & ZEBRA_EVPNES_OPER_UP);
1893
1894 if (old_up == up)
1895 return;
1896
1897 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1898 zlog_debug("es %s state changed to %s ",
1899 es->esi_str,
1900 up ? "up" : "down");
1901 if (up)
1902 es->flags |= ZEBRA_EVPNES_OPER_UP;
1903 else
1904 es->flags &= ~ZEBRA_EVPNES_OPER_UP;
1905
1103c5c6
AK
1906 zebra_evpn_es_run_df_election(es, __func__);
1907
ce5160c0
AK
1908 /* inform BGP of the ES oper state change */
1909 if (es->flags & ZEBRA_EVPNES_READY_FOR_BGP)
1910 zebra_evpn_es_send_add_to_client(es);
1911}
1912
9e0c2fd1
AK
1913static char *zebra_evpn_es_vtep_str(char *vtep_str, struct zebra_evpn_es *es,
1914 uint8_t vtep_str_size)
ce5160c0
AK
1915{
1916 struct zebra_evpn_es_vtep *zvtep;
1917 struct listnode *node;
9bcef951 1918 char buf[PREFIX_STRLEN];
ce5160c0
AK
1919 bool first = true;
1920
1921 vtep_str[0] = '\0';
1922 for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, zvtep)) {
1923 if (first) {
1924 first = false;
9bcef951
MS
1925 strlcat(vtep_str, inet_ntop(AF_INET, &zvtep->vtep_ip,
1926 buf, sizeof(buf)),
9e0c2fd1 1927 vtep_str_size);
ce5160c0 1928 } else {
9e0c2fd1 1929 strlcat(vtep_str, ",", vtep_str_size);
9bcef951
MS
1930 strlcat(vtep_str, inet_ntop(AF_INET, &zvtep->vtep_ip,
1931 buf, sizeof(buf)),
9e0c2fd1 1932 vtep_str_size);
ce5160c0
AK
1933 }
1934 }
1935 return vtep_str;
1936}
1937
1938static void zebra_evpn_es_show_entry(struct vty *vty,
1939 struct zebra_evpn_es *es, json_object *json)
1940{
1941 char type_str[4];
1942 char vtep_str[ES_VTEP_LIST_STR_SZ];
1943
1944 if (json) {
1945 /* XXX */
1946 } else {
1947 type_str[0] = '\0';
1948 if (es->flags & ZEBRA_EVPNES_LOCAL)
9e0c2fd1 1949 strlcat(type_str, "L", sizeof(type_str));
ce5160c0 1950 if (es->flags & ZEBRA_EVPNES_REMOTE)
9e0c2fd1 1951 strlcat(type_str, "R", sizeof(type_str));
1103c5c6
AK
1952 if (es->flags & ZEBRA_EVPNES_NON_DF)
1953 strlcat(type_str, "N", sizeof(type_str));
ce5160c0 1954
9e0c2fd1 1955 zebra_evpn_es_vtep_str(vtep_str, es, sizeof(vtep_str));
ce5160c0
AK
1956
1957 vty_out(vty, "%-30s %-4s %-21s %s\n",
1958 es->esi_str, type_str,
1959 es->zif ? es->zif->ifp->name : "-",
1960 vtep_str);
1961 }
1962}
1963
1964static void zebra_evpn_es_show_entry_detail(struct vty *vty,
1965 struct zebra_evpn_es *es, json_object *json)
1966{
1967 char type_str[80];
1103c5c6
AK
1968 char alg_buf[EVPN_DF_ALG_STR_LEN];
1969 struct zebra_evpn_es_vtep *es_vtep;
ce5160c0
AK
1970 struct listnode *node;
1971
1972 if (json) {
1973 /* XXX */
1974 } else {
1975 type_str[0] = '\0';
1976 if (es->flags & ZEBRA_EVPNES_LOCAL)
9e0c2fd1 1977 strlcat(type_str, "Local", sizeof(type_str));
ce5160c0 1978 if (es->flags & ZEBRA_EVPNES_REMOTE) {
9e0c2fd1
AK
1979 if (strnlen(type_str, sizeof(type_str)))
1980 strlcat(type_str, ",", sizeof(type_str));
1981 strlcat(type_str, "Remote", sizeof(type_str));
ce5160c0
AK
1982 }
1983
1984 vty_out(vty, "ESI: %s\n", es->esi_str);
1985 vty_out(vty, " Type: %s\n", type_str);
1986 vty_out(vty, " Interface: %s\n",
1987 (es->zif) ?
1988 es->zif->ifp->name : "-");
1989 vty_out(vty, " State: %s\n",
1990 (es->flags & ZEBRA_EVPNES_OPER_UP) ?
1991 "up" : "down");
1992 vty_out(vty, " Ready for BGP: %s\n",
1993 (es->flags & ZEBRA_EVPNES_READY_FOR_BGP) ?
1994 "yes" : "no");
1995 vty_out(vty, " VNI Count: %d\n", listcount(es->es_evi_list));
b169fd6f 1996 vty_out(vty, " MAC Count: %d\n", listcount(es->mac_list));
1103c5c6
AK
1997 vty_out(vty, " DF: status: %s preference: %u\n",
1998 (es->flags & ZEBRA_EVPNES_NON_DF) ? "non-df" : "df",
1999 es->df_pref);
ce5160c0
AK
2000 vty_out(vty, " Nexthop group: 0x%x\n", es->nhg_id);
2001 vty_out(vty, " VTEPs:\n");
1103c5c6
AK
2002 for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
2003 vty_out(vty, " %pI4",
2004 &es_vtep->vtep_ip);
2005 if (es_vtep->flags & ZEBRA_EVPNES_VTEP_RXED_ESR)
2006 vty_out(vty, " df_alg: %s df_pref: %d",
2007 evpn_es_df_alg2str(es_vtep->df_alg,
2008 alg_buf,
2009 sizeof(alg_buf)),
2010 es_vtep->df_pref);
2011 vty_out(vty, " nh: 0x%x\n", es_vtep->nh_id);
2012 }
ce5160c0
AK
2013
2014 vty_out(vty, "\n");
2015 }
2016}
2017
2018void zebra_evpn_es_show(struct vty *vty, bool uj)
2019{
2020 struct zebra_evpn_es *es;
2021 json_object *json = NULL;
2022
2023 if (uj) {
2024 /* XXX */
2025 } else {
1103c5c6 2026 vty_out(vty, "Type: L local, R remote, N non-DF\n");
ce5160c0
AK
2027 vty_out(vty, "%-30s %-4s %-21s %s\n",
2028 "ESI", "Type", "ES-IF", "VTEPs");
2029 }
2030
2031 RB_FOREACH(es, zebra_es_rb_head, &zmh_info->es_rb_tree)
2032 zebra_evpn_es_show_entry(vty, es, json);
2033}
2034
2035void zebra_evpn_es_show_detail(struct vty *vty, bool uj)
2036{
2037 struct zebra_evpn_es *es;
2038 json_object *json = NULL;
2039
2040 RB_FOREACH(es, zebra_es_rb_head, &zmh_info->es_rb_tree)
2041 zebra_evpn_es_show_entry_detail(vty, es, json);
2042}
2043
2044void zebra_evpn_es_show_esi(struct vty *vty, bool uj, esi_t *esi)
2045{
2046 struct zebra_evpn_es *es;
2047 char esi_str[ESI_STR_LEN];
2048 json_object *json = NULL;
2049
2050 es = zebra_evpn_es_find(esi);
2051
2052 if (!es) {
2053 esi_to_str(esi, esi_str, sizeof(esi_str));
2054 vty_out(vty, "ESI %s does not exist\n", esi_str);
2055 return;
2056 }
2057
2058 zebra_evpn_es_show_entry_detail(vty, es, json);
2059}
2060
2061int zebra_evpn_mh_if_write(struct vty *vty, struct interface *ifp)
2062{
2063 struct zebra_if *zif = ifp->info;
2064 char buf[ETHER_ADDR_STRLEN];
2065
2066 if (zif->es_info.lid)
2067 vty_out(vty, " evpn mh es-id %u\n", zif->es_info.lid);
2068
2069 if (!is_zero_mac(&zif->es_info.sysmac))
2070 vty_out(vty, " evpn mh es-sys-mac %s\n",
2071 prefix_mac2str(&zif->es_info.sysmac,
2072 buf, sizeof(buf)));
1103c5c6
AK
2073
2074 if (zif->es_info.df_pref)
2075 vty_out(vty, " evpn mh es-df-pref %u\n", zif->es_info.df_pref);
2076
ce5160c0
AK
2077 return 0;
2078}
2079
2080#ifndef VTYSH_EXTRACT_PL
2081#include "zebra/zebra_evpn_mh_clippy.c"
2082#endif
1103c5c6
AK
2083/* CLI for configuring DF preference part for an ES */
2084DEFPY(zebra_evpn_es_pref, zebra_evpn_es_pref_cmd,
2085 "[no$no] evpn mh es-df-pref [(1-65535)$df_pref]",
2086 NO_STR "EVPN\n" EVPN_MH_VTY_STR
2087 "preference value used for DF election\n"
2088 "ID\n")
2089{
2090 VTY_DECLVAR_CONTEXT(interface, ifp);
2091 struct zebra_if *zif;
2092
2093 zif = ifp->info;
2094
2095 if (no) {
2096 zebra_evpn_es_df_pref_update(zif, 0);
2097 } else {
2098 if (!zebra_evpn_is_if_es_capable(zif)) {
2099 vty_out(vty,
2100 "%%DF preference cannot be associated with this interface type\n");
2101 return CMD_WARNING;
2102 }
2103 zebra_evpn_es_df_pref_update(zif, df_pref);
2104 }
2105 return CMD_SUCCESS;
2106}
2107
ce5160c0
AK
2108/* CLI for setting up sysmac part of ESI on an access port */
2109DEFPY(zebra_evpn_es_sys_mac,
2110 zebra_evpn_es_sys_mac_cmd,
2111 "[no$no] evpn mh es-sys-mac [X:X:X:X:X:X$mac]",
2112 NO_STR
2113 "EVPN\n"
2114 EVPN_MH_VTY_STR
2115 "Ethernet segment system MAC\n"
2116 MAC_STR
2117)
2118{
2119 VTY_DECLVAR_CONTEXT(interface, ifp);
2120 struct zebra_if *zif;
2121 int ret = 0;
2122
2123 zif = ifp->info;
2124
2125 if (no) {
2126 static struct ethaddr zero_mac;
2127
2128 ret = zebra_evpn_es_sys_mac_update(zif, &zero_mac);
2129 if (ret == -1) {
2130 vty_out(vty, "%%Failed to clear ES sysmac\n");
2131 return CMD_WARNING;
2132 }
2133 } else {
2134
2135 if (!zebra_evpn_is_if_es_capable(zif)) {
2136 vty_out(vty,
2137 "%%ESI cannot be associated with this interface type\n");
2138 return CMD_WARNING;
2139 }
2140
2141 if (!mac || is_zero_mac(&mac->eth_addr)) {
2142 vty_out(vty, "%%ES sysmac value is invalid\n");
2143 return CMD_WARNING;
2144 }
2145
2146 ret = zebra_evpn_es_sys_mac_update(zif, &mac->eth_addr);
2147 if (ret == -1) {
2148 vty_out(vty, "%%ESI already exists on a different interface\n");
2149 return CMD_WARNING;
2150 }
2151 }
2152 return CMD_SUCCESS;
2153}
2154
2155/* CLI for setting up local-ID part of ESI on an access port */
2156DEFPY(zebra_evpn_es_id,
2157 zebra_evpn_es_id_cmd,
2158 "[no$no] evpn mh es-id [(1-16777215)$es_lid]",
2159 NO_STR
2160 "EVPN\n"
2161 EVPN_MH_VTY_STR
2162 "Ethernet segment local identifier\n"
2163 "ID\n"
2164)
2165{
2166 VTY_DECLVAR_CONTEXT(interface, ifp);
2167 struct zebra_if *zif;
2168 int ret;
2169
2170 zif = ifp->info;
2171
2172 if (no) {
2173 ret = zebra_evpn_es_lid_update(zif, 0);
2174 if (ret == -1) {
2175 vty_out(vty, "%%Failed to clear ES local id\n");
2176 return CMD_WARNING;
2177 }
2178 } else {
2179 if (!zebra_evpn_is_if_es_capable(zif)) {
2180 vty_out(vty,
2181 "%%ESI cannot be associated with this interface type\n");
2182 return CMD_WARNING;
2183 }
2184
2185 if (!es_lid) {
2186 vty_out(vty, "%%Specify local ES ID\n");
2187 return CMD_WARNING;
2188 }
2189 ret = zebra_evpn_es_lid_update(zif, es_lid);
2190 if (ret == -1) {
2191 vty_out(vty,
2192 "%%ESI already exists on a different interface\n");
2193 return CMD_WARNING;
2194 }
2195 }
2196 return CMD_SUCCESS;
2197}
2198
2199/*****************************************************************************/
2200/* A base L2-VNI is maintained to derive parameters such as ES originator-IP.
2201 * XXX: once single vxlan device model becomes available this will not be
2202 * necessary
2203 */
2204/* called when a new vni is added or becomes oper up or becomes a bridge port */
87d76d54 2205void zebra_evpn_es_set_base_evpn(zebra_evpn_t *zevpn)
ce5160c0
AK
2206{
2207 struct listnode *node;
2208 struct zebra_evpn_es *es;
2209
87d76d54
PR
2210 if (zmh_info->es_base_evpn) {
2211 if (zmh_info->es_base_evpn != zevpn) {
2212 /* unrelated EVPN; ignore it */
ce5160c0
AK
2213 return;
2214 }
2215 /* check if the local vtep-ip has changed */
2216 } else {
87d76d54
PR
2217 /* check if the EVPN can be used as base EVPN */
2218 if (!zebra_evpn_send_to_client_ok(zevpn))
ce5160c0
AK
2219 return;
2220
2221 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
2222 zlog_debug("es base vni set to %d",
87d76d54
PR
2223 zevpn->vni);
2224 zmh_info->es_base_evpn = zevpn;
ce5160c0
AK
2225 }
2226
2227 /* update local VTEP-IP */
2228 if (zmh_info->es_originator_ip.s_addr ==
87d76d54 2229 zmh_info->es_base_evpn->local_vtep_ip.s_addr)
ce5160c0
AK
2230 return;
2231
2232 zmh_info->es_originator_ip.s_addr =
87d76d54 2233 zmh_info->es_base_evpn->local_vtep_ip.s_addr;
ce5160c0
AK
2234
2235 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
9bcef951
MS
2236 zlog_debug("es originator ip set to %pI4",
2237 &zmh_info->es_base_evpn->local_vtep_ip);
ce5160c0
AK
2238
2239 /* if originator ip changes we need to update bgp */
2240 for (ALL_LIST_ELEMENTS_RO(zmh_info->local_es_list, node, es)) {
1103c5c6
AK
2241 zebra_evpn_es_run_df_election(es, __func__);
2242
ce5160c0
AK
2243 if (es->flags & ZEBRA_EVPNES_READY_FOR_BGP)
2244 zebra_evpn_es_send_add_to_client(es);
2245 else
2246 zebra_evpn_es_re_eval_send_to_client(es,
2247 true /* es_evi_re_reval */);
2248 }
2249}
2250
2251/* called when a vni is removed or becomes oper down or is removed from a
2252 * bridge
2253 */
87d76d54 2254void zebra_evpn_es_clear_base_evpn(zebra_evpn_t *zevpn)
ce5160c0
AK
2255{
2256 struct listnode *node;
2257 struct zebra_evpn_es *es;
2258
87d76d54 2259 if (zmh_info->es_base_evpn != zevpn)
ce5160c0
AK
2260 return;
2261
87d76d54
PR
2262 zmh_info->es_base_evpn = NULL;
2263 /* lost current base EVPN; try to find a new one */
2264 zebra_evpn_es_get_one_base_evpn();
ce5160c0 2265
87d76d54
PR
2266 /* couldn't locate an eligible base evpn */
2267 if (!zmh_info->es_base_evpn && zmh_info->es_originator_ip.s_addr) {
ce5160c0
AK
2268 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
2269 zlog_debug("es originator ip cleared");
2270
2271 zmh_info->es_originator_ip.s_addr = 0;
2272 /* lost originator ip */
2273 for (ALL_LIST_ELEMENTS_RO(zmh_info->local_es_list, node, es)) {
2274 zebra_evpn_es_re_eval_send_to_client(es,
2275 true /* es_evi_re_reval */);
2276 }
2277 }
2278}
2279
2280/* Locate an "eligible" L2-VNI to follow */
87d76d54 2281static int zebra_evpn_es_get_one_base_evpn_cb(struct hash_bucket *b, void *data)
ce5160c0 2282{
87d76d54 2283 zebra_evpn_t *zevpn = b->data;
ce5160c0 2284
87d76d54 2285 zebra_evpn_es_set_base_evpn(zevpn);
ce5160c0 2286
87d76d54 2287 if (zmh_info->es_base_evpn)
ce5160c0
AK
2288 return HASHWALK_ABORT;
2289
2290 return HASHWALK_CONTINUE;
2291}
2292
87d76d54 2293/* locate a base_evpn to follow for the purposes of common params like
ce5160c0
AK
2294 * originator IP
2295 */
87d76d54 2296static void zebra_evpn_es_get_one_base_evpn(void)
ce5160c0
AK
2297{
2298 struct zebra_vrf *zvrf;
2299
2300 zvrf = zebra_vrf_get_evpn();
87d76d54 2301 hash_walk(zvrf->evpn_table, zebra_evpn_es_get_one_base_evpn_cb, NULL);
ce5160c0
AK
2302}
2303
2304/*****************************************************************************/
b169fd6f
AK
2305void zebra_evpn_mh_config_write(struct vty *vty)
2306{
2307 if (zmh_info->mac_hold_time != EVPN_MH_MAC_HOLD_TIME_DEF)
2308 vty_out(vty, "evpn mh mac-holdtime %ld\n",
2309 zmh_info->mac_hold_time);
2310
2311 if (zmh_info->neigh_hold_time != EVPN_MH_NEIGH_HOLD_TIME_DEF)
2312 vty_out(vty, "evpn mh neigh-holdtime %ld\n",
2313 zmh_info->neigh_hold_time);
2314}
2315
2316int zebra_evpn_mh_neigh_holdtime_update(struct vty *vty,
2317 uint32_t duration, bool set_default)
2318{
2319 if (set_default)
f9f0463f 2320 duration = EVPN_MH_NEIGH_HOLD_TIME_DEF;
b169fd6f
AK
2321
2322 zmh_info->neigh_hold_time = duration;
2323
2324 return 0;
2325}
2326
2327int zebra_evpn_mh_mac_holdtime_update(struct vty *vty,
2328 uint32_t duration, bool set_default)
2329{
2330 if (set_default)
2331 duration = EVPN_MH_MAC_HOLD_TIME_DEF;
2332
2333 zmh_info->mac_hold_time = duration;
2334
2335 return 0;
2336}
2337
ce5160c0
AK
2338void zebra_evpn_interface_init(void)
2339{
2340 install_element(INTERFACE_NODE, &zebra_evpn_es_id_cmd);
2341 install_element(INTERFACE_NODE, &zebra_evpn_es_sys_mac_cmd);
1103c5c6 2342 install_element(INTERFACE_NODE, &zebra_evpn_es_pref_cmd);
ce5160c0
AK
2343}
2344
2345void zebra_evpn_mh_init(void)
2346{
2347 zrouter.mh_info = XCALLOC(MTYPE_ZMH_INFO, sizeof(*zrouter.mh_info));
2348
b169fd6f
AK
2349 zmh_info->mac_hold_time = EVPN_MH_MAC_HOLD_TIME_DEF;
2350 zmh_info->neigh_hold_time = EVPN_MH_NEIGH_HOLD_TIME_DEF;
ce5160c0
AK
2351 /* setup ES tables */
2352 RB_INIT(zebra_es_rb_head, &zmh_info->es_rb_tree);
2353 zmh_info->local_es_list = list_new();
2354 listset_app_node_mem(zmh_info->local_es_list);
2355
2356 bf_init(zmh_info->nh_id_bitmap, EVPN_NH_ID_MAX);
2357 bf_assign_zero_index(zmh_info->nh_id_bitmap);
2358
2359 /* setup broadcast domain tables */
2360 zmh_info->evpn_vlan_table = hash_create(zebra_evpn_acc_vl_hash_keymake,
2361 zebra_evpn_acc_vl_cmp, "access VLAN hash table");
2362}
2363
2364void zebra_evpn_mh_terminate(void)
2365{
2366 list_delete(&zmh_info->local_es_list);
2367
2368 hash_iterate(zmh_info->evpn_vlan_table,
2369 zebra_evpn_acc_vl_cleanup_all, NULL);
2370 hash_free(zmh_info->evpn_vlan_table);
2371}