]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_evpn_mh.c
ospfd: replace inet_ntoa
[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;
813
814 if (!bf_is_inited(zif->vlan_bitmap))
815 return;
816
817 bf_for_each_set_bit(zif->vlan_bitmap, vid, IF_VLAN_BITMAP_MAX) {
818 zebra_evpn_vl_mbr_deref(vid, zif);
819 }
820
821 bf_free(zif->vlan_bitmap);
822
823 /* Delete associated Ethernet Segment */
824 if (zif->es_info.es)
e378f502 825 zebra_evpn_local_es_del(&zif->es_info.es);
ce5160c0
AK
826}
827
828/*****************************************************************************
829 * L2 NH/NHG Management
830 * A L2 NH entry is programmed in the kernel for every ES-VTEP entry. This
831 * NH is then added to the L2-ECMP-NHG associated with the ES.
832 */
833static uint32_t zebra_evpn_nhid_alloc(bool is_nhg)
834{
835 uint32_t id;
836 int type;
837
838 bf_assign_index(zmh_info->nh_id_bitmap, id);
839
840 if (!id)
841 return 0;
842
843 type = is_nhg ? EVPN_NHG_ID_TYPE_BIT : EVPN_NH_ID_TYPE_BIT;
844 return (id | type);
845}
846
847static void zebra_evpn_nhid_free(uint32_t nh_id)
848{
849 uint32_t id = (nh_id & EVPN_NH_ID_VAL_MASK);
850
851 if (!id)
852 return;
853
854 bf_release_index(zmh_info->nh_id_bitmap, id);
855}
856
857/* The MAC ECMP group is activated on the first VTEP */
858static void zebra_evpn_nhg_update(struct zebra_evpn_es *es)
859{
860 uint32_t nh_cnt = 0;
861 struct nh_grp nh_ids[ES_VTEP_MAX_CNT];
862 struct zebra_evpn_es_vtep *es_vtep;
863 struct listnode *node;
864
865 if (!es->nhg_id)
866 return;
867
868 for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
869 if (!es_vtep->nh_id)
870 continue;
871
872 if (nh_cnt >= ES_VTEP_MAX_CNT)
873 break;
874
875 memset(&nh_ids[nh_cnt], 0, sizeof(struct nh_grp));
876 nh_ids[nh_cnt].id = es_vtep->nh_id;
877 ++nh_cnt;
878 }
879
880 if (nh_cnt) {
881 if (IS_ZEBRA_DEBUG_EVPN_MH_NH) {
882 char nh_str[ES_VTEP_LIST_STR_SZ];
883 uint32_t i;
9e0c2fd1 884 char nh_buf[16];
ce5160c0
AK
885
886 nh_str[0] = '\0';
9e0c2fd1
AK
887 for (i = 0; i < nh_cnt; ++i) {
888 snprintf(nh_buf, sizeof(nh_buf), "%u ",
889 nh_ids[i].id);
890 strlcat(nh_str, nh_buf, sizeof(nh_str));
891 }
ce5160c0
AK
892 zlog_debug("es %s nhg 0x%x add %s",
893 es->esi_str, es->nhg_id, nh_str);
894 }
895
896 es->flags |= ZEBRA_EVPNES_NHG_ACTIVE;
897 kernel_upd_mac_nhg(es->nhg_id, nh_cnt, nh_ids);
898 } else {
899 if (es->flags & ZEBRA_EVPNES_NHG_ACTIVE) {
900 if (IS_ZEBRA_DEBUG_EVPN_MH_NH)
901 zlog_debug("es %s nhg 0x%x del",
902 es->esi_str, es->nhg_id);
903 es->flags &= ~ZEBRA_EVPNES_NHG_ACTIVE;
904 kernel_del_mac_nhg(es->nhg_id);
905 }
906 }
907
908 /* XXX - update remote macs associated with the ES */
909}
910
911static void zebra_evpn_nh_add(struct zebra_evpn_es_vtep *es_vtep)
912{
913 if (es_vtep->nh_id)
914 return;
915
916 es_vtep->nh_id = zebra_evpn_nhid_alloc(false);
917
918 if (!es_vtep->nh_id)
919 return;
920
921 if (IS_ZEBRA_DEBUG_EVPN_MH_NH)
922 zlog_debug("es %s vtep %s nh 0x%x add",
923 es_vtep->es->esi_str,
924 inet_ntoa(es_vtep->vtep_ip), es_vtep->nh_id);
925 /* install the NH */
926 kernel_upd_mac_nh(es_vtep->nh_id, es_vtep->vtep_ip);
927 /* add the NH to the parent NHG */
928 zebra_evpn_nhg_update(es_vtep->es);
929}
930
931static void zebra_evpn_nh_del(struct zebra_evpn_es_vtep *es_vtep)
932{
933 uint32_t nh_id;
934
935 if (!es_vtep->nh_id)
936 return;
937
938 if (IS_ZEBRA_DEBUG_EVPN_MH_NH)
939 zlog_debug("es %s vtep %s nh 0x%x del",
940 es_vtep->es->esi_str,
941 inet_ntoa(es_vtep->vtep_ip), es_vtep->nh_id);
942
943 nh_id = es_vtep->nh_id;
944 es_vtep->nh_id = 0;
945
946 /* remove the NH from the parent NHG */
947 zebra_evpn_nhg_update(es_vtep->es);
948 /* uninstall the NH */
949 kernel_del_mac_nh(nh_id);
950 zebra_evpn_nhid_free(nh_id);
951
952}
953
954/*****************************************************************************/
955/* Ethernet Segment Management
956 * 1. Ethernet Segment is a collection of links attached to the same
957 * server (MHD) or switch (MHN)
958 * 2. An Ethernet Segment can span multiple PEs and is identified by the
959 * 10-byte ES-ID.
960 * 3. Zebra manages the local ESI configuration.
961 * 4. It also maintains the aliasing that maps an ESI (local or remote)
962 * to one or more PEs/VTEPs.
963 * 5. remote ESs are added by BGP (on rxing EAD Type-1 routes)
964 */
965/* A list of remote VTEPs is maintained for each ES. This list includes -
966 * 1. VTEPs for which we have imported the ESR i.e. ES-peers
967 * 2. VTEPs that have an "active" ES-EVI VTEP i.e. EAD-per-ES and EAD-per-EVI
87d76d54 968 * have been imported into one or more EVPNs
ce5160c0
AK
969 */
970static int zebra_evpn_es_vtep_cmp(void *p1, void *p2)
971{
972 const struct zebra_evpn_es_vtep *es_vtep1 = p1;
973 const struct zebra_evpn_es_vtep *es_vtep2 = p2;
974
975 return es_vtep1->vtep_ip.s_addr - es_vtep2->vtep_ip.s_addr;
976}
977
978static struct zebra_evpn_es_vtep *zebra_evpn_es_vtep_new(
979 struct zebra_evpn_es *es, struct in_addr vtep_ip)
980{
981 struct zebra_evpn_es_vtep *es_vtep;
982
983 es_vtep = XCALLOC(MTYPE_ZES_VTEP, sizeof(*es_vtep));
984
985 es_vtep->es = es;
986 es_vtep->vtep_ip.s_addr = vtep_ip.s_addr;
987 listnode_init(&es_vtep->es_listnode, es_vtep);
988 listnode_add_sort(es->es_vtep_list, &es_vtep->es_listnode);
989
990 return es_vtep;
991}
992
993static void zebra_evpn_es_vtep_free(struct zebra_evpn_es_vtep *es_vtep)
994{
995 struct zebra_evpn_es *es = es_vtep->es;
996
997 list_delete_node(es->es_vtep_list, &es_vtep->es_listnode);
998 /* update the L2-NHG associated with the ES */
999 zebra_evpn_nh_del(es_vtep);
1000 XFREE(MTYPE_ZES_VTEP, es_vtep);
1001}
1002
1003
1004/* check if VTEP is already part of the list */
1005static struct zebra_evpn_es_vtep *zebra_evpn_es_vtep_find(
1006 struct zebra_evpn_es *es, struct in_addr vtep_ip)
1007{
1008 struct listnode *node = NULL;
1009 struct zebra_evpn_es_vtep *es_vtep;
1010
1011 for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
1012 if (es_vtep->vtep_ip.s_addr == vtep_ip.s_addr)
1013 return es_vtep;
1014 }
1015 return NULL;
1016}
1017
1018static void zebra_evpn_es_vtep_add(struct zebra_evpn_es *es,
1019 struct in_addr vtep_ip)
1020{
1021 struct zebra_evpn_es_vtep *es_vtep;
1022
1023 es_vtep = zebra_evpn_es_vtep_find(es, vtep_ip);
1024
1025 if (!es_vtep) {
1026 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1027 zlog_debug("es %s vtep %s add",
1028 es->esi_str, inet_ntoa(vtep_ip));
1029 es_vtep = zebra_evpn_es_vtep_new(es, vtep_ip);
1030 /* update the L2-NHG associated with the ES */
1031 zebra_evpn_nh_add(es_vtep);
1032 }
1033}
1034
1035static void zebra_evpn_es_vtep_del(struct zebra_evpn_es *es,
1036 struct in_addr vtep_ip)
1037{
1038 struct zebra_evpn_es_vtep *es_vtep;
1039
1040 es_vtep = zebra_evpn_es_vtep_find(es, vtep_ip);
1041
1042 if (es_vtep) {
1043 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1044 zlog_debug("es %s vtep %s del",
1045 es->esi_str, inet_ntoa(vtep_ip));
1046 zebra_evpn_es_vtep_free(es_vtep);
1047 }
1048}
1049
1050/* compare ES-IDs for the global ES RB tree */
1051static int zebra_es_rb_cmp(const struct zebra_evpn_es *es1,
1052 const struct zebra_evpn_es *es2)
1053{
1054 return memcmp(&es1->esi, &es2->esi, ESI_BYTES);
1055}
1056RB_GENERATE(zebra_es_rb_head, zebra_evpn_es, rb_node, zebra_es_rb_cmp);
1057
1058/* Lookup ES */
1059struct zebra_evpn_es *zebra_evpn_es_find(esi_t *esi)
1060{
1061 struct zebra_evpn_es tmp;
1062
1063 memcpy(&tmp.esi, esi, sizeof(esi_t));
1064 return RB_FIND(zebra_es_rb_head, &zmh_info->es_rb_tree, &tmp);
1065}
1066
1067/* A new local es is created when a local-es-id and sysmac is configured
1068 * against an interface.
1069 */
1070static struct zebra_evpn_es *zebra_evpn_es_new(esi_t *esi)
1071{
1072 struct zebra_evpn_es *es;
1073
1074 es = XCALLOC(MTYPE_ZES, sizeof(struct zebra_evpn_es));
1075
1076 /* fill in ESI */
1077 memcpy(&es->esi, esi, sizeof(esi_t));
1078 esi_to_str(&es->esi, es->esi_str, sizeof(es->esi_str));
1079
1080 /* Add to rb_tree */
1081 if (RB_INSERT(zebra_es_rb_head, &zmh_info->es_rb_tree, es)) {
1082 XFREE(MTYPE_ZES, es);
1083 return NULL;
1084 }
1085
1086 /* Initialise the ES-EVI list */
1087 es->es_evi_list = list_new();
1088 listset_app_node_mem(es->es_evi_list);
1089
1090 /* Initialise the VTEP list */
1091 es->es_vtep_list = list_new();
1092 listset_app_node_mem(es->es_vtep_list);
1093 es->es_vtep_list->cmp = zebra_evpn_es_vtep_cmp;
1094
b169fd6f
AK
1095 /* mac entries associated with the ES */
1096 es->mac_list = list_new();
1097 listset_app_node_mem(es->mac_list);
1098
ce5160c0
AK
1099 /* reserve a NHG */
1100 es->nhg_id = zebra_evpn_nhid_alloc(true);
1101
1102 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1103 zlog_debug("es %s nhg 0x%x new", es->esi_str, es->nhg_id);
1104
1105 return es;
1106}
1107
1108/* Free a given ES -
1109 * This just frees appropriate memory, caller should have taken other
1110 * needed actions.
1111 */
e378f502 1112static void zebra_evpn_es_free(struct zebra_evpn_es **esp)
ce5160c0 1113{
e378f502
AK
1114 struct zebra_evpn_es *es = *esp;
1115
ce5160c0
AK
1116 /* If the ES has a local or remote reference it cannot be freed.
1117 * Free is also prevented if there are MAC entries referencing
1118 * it.
1119 */
1120 if ((es->flags & (ZEBRA_EVPNES_LOCAL | ZEBRA_EVPNES_REMOTE)) ||
b169fd6f 1121 listcount(es->mac_list))
e378f502 1122 return;
ce5160c0
AK
1123
1124 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1125 zlog_debug("es %s free", es->esi_str);
1126
1127 /* If the NHG is still installed uninstall it and free the id */
1128 if (es->flags & ZEBRA_EVPNES_NHG_ACTIVE) {
1129 es->flags &= ~ZEBRA_EVPNES_NHG_ACTIVE;
1130 kernel_del_mac_nhg(es->nhg_id);
1131 }
1132 zebra_evpn_nhid_free(es->nhg_id);
1133
1134 /* cleanup resources maintained against the ES */
1135 list_delete(&es->es_evi_list);
1136 list_delete(&es->es_vtep_list);
b169fd6f 1137 list_delete(&es->mac_list);
ce5160c0
AK
1138
1139 /* remove from the VNI-ESI rb tree */
1140 RB_REMOVE(zebra_es_rb_head, &zmh_info->es_rb_tree, es);
1141
1142 XFREE(MTYPE_ZES, es);
b169fd6f 1143
e378f502 1144 *esp = NULL;
ce5160c0
AK
1145}
1146
1147/* Inform BGP about local ES addition */
1148static int zebra_evpn_es_send_add_to_client(struct zebra_evpn_es *es)
1149{
1150 struct zserv *client;
1151 struct stream *s;
1152 uint8_t oper_up;
1153
1154 client = zserv_find_client(ZEBRA_ROUTE_BGP, 0);
1155 /* BGP may not be running. */
1156 if (!client)
1157 return 0;
1158
1159 s = stream_new(ZEBRA_MAX_PACKET_SIZ);
1160
1161 zclient_create_header(s, ZEBRA_LOCAL_ES_ADD, zebra_vrf_get_evpn_id());
1162 stream_put(s, &es->esi, sizeof(esi_t));
1163 stream_put_ipv4(s, zmh_info->es_originator_ip.s_addr);
1164 oper_up = !!(es->flags & ZEBRA_EVPNES_OPER_UP);
1165 stream_putc(s, oper_up);
1166
1167 /* Write packet size. */
1168 stream_putw_at(s, 0, stream_get_endp(s));
1169
1170 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1171 zlog_debug("send add local es %s %s to %s",
1172 es->esi_str,
1173 inet_ntoa(zmh_info->es_originator_ip),
1174 zebra_route_string(client->proto));
1175
1176 client->local_es_add_cnt++;
1177 return zserv_send_message(client, s);
1178}
1179
1180/* Inform BGP about local ES deletion */
1181static int zebra_evpn_es_send_del_to_client(struct zebra_evpn_es *es)
1182{
1183 struct zserv *client;
1184 struct stream *s;
1185
1186 client = zserv_find_client(ZEBRA_ROUTE_BGP, 0);
1187 /* BGP may not be running. */
1188 if (!client)
1189 return 0;
1190
1191 s = stream_new(ZEBRA_MAX_PACKET_SIZ);
1192 stream_reset(s);
1193
1194 zclient_create_header(s, ZEBRA_LOCAL_ES_DEL, zebra_vrf_get_evpn_id());
1195 stream_put(s, &es->esi, sizeof(esi_t));
1196
1197 /* Write packet size. */
1198 stream_putw_at(s, 0, stream_get_endp(s));
1199
1200 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1201 zlog_debug("send del local es %s to %s", es->esi_str,
1202 zebra_route_string(client->proto));
1203
1204 client->local_es_del_cnt++;
1205 return zserv_send_message(client, s);
1206}
1207
ce5160c0
AK
1208static void zebra_evpn_es_re_eval_send_to_client(struct zebra_evpn_es *es,
1209 bool es_evi_re_reval)
1210{
1211 bool old_ready;
1212 bool new_ready;
1213 struct listnode *node;
1214 struct zebra_evpn_es_evi *es_evi;
1215
1216 old_ready = !!(es->flags & ZEBRA_EVPNES_READY_FOR_BGP);
1217
1218 if ((es->flags & ZEBRA_EVPNES_LOCAL) &&
1219 zmh_info->es_originator_ip.s_addr)
1220 es->flags |= ZEBRA_EVPNES_READY_FOR_BGP;
1221 else
1222 es->flags &= ~ZEBRA_EVPNES_READY_FOR_BGP;
1223
1224 new_ready = !!(es->flags & ZEBRA_EVPNES_READY_FOR_BGP);
1225 if (old_ready == new_ready)
1226 return;
1227
1228 if (new_ready)
1229 zebra_evpn_es_send_add_to_client(es);
1230 else
1231 zebra_evpn_es_send_del_to_client(es);
1232
1233 /* re-eval associated EVIs */
1234 if (es_evi_re_reval) {
1235 for (ALL_LIST_ELEMENTS_RO(es->es_evi_list, node, es_evi)) {
1236 if (!(es_evi->flags & ZEBRA_EVPNES_EVI_LOCAL))
1237 continue;
1238 zebra_evpn_es_evi_re_eval_send_to_client(es_evi);
1239 }
1240 }
1241}
1242
1243void zebra_evpn_es_send_all_to_client(bool add)
1244{
1245 struct listnode *es_node;
1246 struct listnode *evi_node;
1247 struct zebra_evpn_es *es;
1248 struct zebra_evpn_es_evi *es_evi;
1249
1250 if (!zmh_info)
1251 return;
1252
1253 for (ALL_LIST_ELEMENTS_RO(zmh_info->local_es_list, es_node, es)) {
1254 if (es->flags & ZEBRA_EVPNES_READY_FOR_BGP) {
1255 if (add)
1256 zebra_evpn_es_send_add_to_client(es);
1257 for (ALL_LIST_ELEMENTS_RO(es->es_evi_list,
1258 evi_node, es_evi)) {
1259 if (!(es_evi->flags &
1260 ZEBRA_EVPNES_EVI_READY_FOR_BGP))
1261 continue;
1262
1263 if (add)
1264 zebra_evpn_es_evi_send_to_client(
87d76d54 1265 es, es_evi->zevpn,
ce5160c0
AK
1266 true /* add */);
1267 else
1268 zebra_evpn_es_evi_send_to_client(
87d76d54 1269 es, es_evi->zevpn,
ce5160c0
AK
1270 false /* add */);
1271 }
1272 if (!add)
1273 zebra_evpn_es_send_del_to_client(es);
1274 }
1275 }
1276}
1277
1278/* walk the vlan bitmap associated with the zif and create or delete
1279 * es_evis for all vlans associated with a VNI.
1280 * XXX: This API is really expensive. optimize later if possible.
1281 */
1282static void zebra_evpn_es_setup_evis(struct zebra_evpn_es *es)
1283{
1284 struct zebra_if *zif = es->zif;
1285 uint16_t vid;
1286 struct zebra_evpn_access_bd *acc_bd;
1287
1288
1289 bf_for_each_set_bit(zif->vlan_bitmap, vid, IF_VLAN_BITMAP_MAX) {
1290 acc_bd = zebra_evpn_acc_vl_find(vid);
87d76d54
PR
1291 if (acc_bd->zevpn)
1292 zebra_evpn_local_es_evi_add(es, acc_bd->zevpn);
ce5160c0
AK
1293 }
1294}
1295
b169fd6f
AK
1296static void zebra_evpn_es_local_mac_update(struct zebra_evpn_es *es,
1297 bool force_clear_static)
1298{
1299 zebra_mac_t *mac;
1300 struct listnode *node;
1301
1302 for (ALL_LIST_ELEMENTS_RO(es->mac_list, node, mac)) {
1303 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE)) {
b2998086
PR
1304 zebra_evpn_sync_mac_dp_install(
1305 mac, false /* set_inactive */,
1306 force_clear_static, __func__);
b169fd6f
AK
1307 }
1308 }
1309}
1310
ce5160c0
AK
1311static void zebra_evpn_es_local_info_set(struct zebra_evpn_es *es,
1312 struct zebra_if *zif)
1313{
1314 if (es->flags & ZEBRA_EVPNES_LOCAL)
1315 return;
1316
1317 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1318 zlog_debug("local es %s add; nhg 0x%x if %s",
1319 es->esi_str, es->nhg_id, zif->ifp->name);
1320
1321 es->flags |= ZEBRA_EVPNES_LOCAL;
1322 listnode_init(&es->local_es_listnode, es);
1323 listnode_add(zmh_info->local_es_list, &es->local_es_listnode);
1324
1325 /* attach es to interface */
1326 zif->es_info.es = es;
1327
1328 /* attach interface to es */
1329 es->zif = zif;
1330 if (if_is_operative(zif->ifp))
1331 es->flags |= ZEBRA_EVPNES_OPER_UP;
1332
1333 /* setup base-vni if one doesn't already exist; the ES will get sent
1334 * to BGP as a part of that process
1335 */
87d76d54
PR
1336 if (!zmh_info->es_base_evpn)
1337 zebra_evpn_es_get_one_base_evpn();
ce5160c0
AK
1338 else
1339 /* send notification to bgp */
1340 zebra_evpn_es_re_eval_send_to_client(es,
1341 false /* es_evi_re_reval */);
1342
1343 /* Setup ES-EVIs for all VxLAN stretched VLANs associated with
1344 * the zif
1345 */
1346 zebra_evpn_es_setup_evis(es);
b169fd6f
AK
1347 /* if there any local macs referring to the ES as dest we
1348 * need to set the static reference on them if the MAC is
1349 * synced from an ES peer
1350 */
1351 zebra_evpn_es_local_mac_update(es,
1352 false /* force_clear_static */);
ce5160c0
AK
1353}
1354
e378f502 1355static void zebra_evpn_es_local_info_clear(struct zebra_evpn_es **esp)
ce5160c0
AK
1356{
1357 struct zebra_if *zif;
e378f502 1358 struct zebra_evpn_es *es = *esp;
ce5160c0
AK
1359
1360 if (!(es->flags & ZEBRA_EVPNES_LOCAL))
1361 return;
1362
4cd94050
AK
1363 es->flags &= ~(ZEBRA_EVPNES_LOCAL | ZEBRA_EVPNES_READY_FOR_BGP);
1364
b169fd6f
AK
1365 /* if there any local macs referring to the ES as dest we
1366 * need to clear the static reference on them
1367 */
1368 zebra_evpn_es_local_mac_update(es,
1369 true /* force_clear_static */);
1370
ce5160c0
AK
1371 /* clear the es from the parent interface */
1372 zif = es->zif;
1373 zif->es_info.es = NULL;
1374 es->zif = NULL;
1375
1376 /* remove from the ES list */
1377 list_delete_node(zmh_info->local_es_list, &es->local_es_listnode);
1378
1379 /* free up the ES if there is no remote reference */
e378f502 1380 zebra_evpn_es_free(esp);
ce5160c0
AK
1381}
1382
1383/* Delete an ethernet segment and inform BGP */
e378f502 1384static void zebra_evpn_local_es_del(struct zebra_evpn_es **esp)
ce5160c0
AK
1385{
1386 struct zebra_evpn_es_evi *es_evi;
1387 struct listnode *node = NULL;
1388 struct listnode *nnode = NULL;
1389 struct zebra_if *zif;
e378f502 1390 struct zebra_evpn_es *es = *esp;
ce5160c0
AK
1391
1392 if (!CHECK_FLAG(es->flags, ZEBRA_EVPNES_LOCAL))
1393 return;
1394
1395 if (IS_ZEBRA_DEBUG_EVPN_MH_ES) {
1396 zif = es->zif;
1397 zlog_debug("local es %s del; nhg 0x%x if %s",
1398 es->esi_str, es->nhg_id,
1399 zif ? zif->ifp->name : "-");
1400 }
1401
1402 /* remove all ES-EVIs associated with the ES */
1403 for (ALL_LIST_ELEMENTS(es->es_evi_list, node, nnode, es_evi))
1404 zebra_evpn_local_es_evi_do_del(es_evi);
1405
1406 /* send a del if the ES had been sent to BGP earlier */
1407 if (es->flags & ZEBRA_EVPNES_READY_FOR_BGP)
1408 zebra_evpn_es_send_del_to_client(es);
1409
e378f502 1410 zebra_evpn_es_local_info_clear(esp);
ce5160c0
AK
1411}
1412
1413/* eval remote info associated with the ES */
e378f502 1414static void zebra_evpn_es_remote_info_re_eval(struct zebra_evpn_es **esp)
ce5160c0 1415{
e378f502
AK
1416 struct zebra_evpn_es *es = *esp;
1417
ce5160c0
AK
1418 /* if there are remote VTEPs the ES-EVI is classified as "remote" */
1419 if (listcount(es->es_vtep_list)) {
1420 if (!(es->flags & ZEBRA_EVPNES_REMOTE)) {
1421 es->flags |= ZEBRA_EVPNES_REMOTE;
1422 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1423 zlog_debug("remote es %s add; nhg 0x%x",
1424 es->esi_str, es->nhg_id);
1425 }
1426 } else {
1427 if (es->flags & ZEBRA_EVPNES_REMOTE) {
1428 es->flags &= ~ZEBRA_EVPNES_REMOTE;
1429 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1430 zlog_debug("remote es %s del; nhg 0x%x",
1431 es->esi_str, es->nhg_id);
e378f502 1432 zebra_evpn_es_free(esp);
ce5160c0
AK
1433 }
1434 }
1435}
1436
1437/* A new local es is created when a local-es-id and sysmac is configured
1438 * against an interface.
1439 */
1440static int zebra_evpn_local_es_update(struct zebra_if *zif, uint32_t lid,
1441 struct ethaddr *sysmac)
1442{
1443 struct zebra_evpn_es *old_es = zif->es_info.es;
1444 struct zebra_evpn_es *es;
1445 esi_t esi;
1446 int offset = 0;
1447 int field_bytes = 0;
1448
1449 /* Complete config of the ES-ID bootstraps the ES */
1450 if (!lid || is_zero_mac(sysmac)) {
1451 /* if in ES is attached to zif delete it */
1452 if (old_es)
e378f502 1453 zebra_evpn_local_es_del(&zif->es_info.es);
ce5160c0
AK
1454 return 0;
1455 }
1456
1457 /* build 10-byte type-3-ESI -
1458 * Type(1-byte), MAC(6-bytes), ES-LID (3-bytes)
1459 */
1460 field_bytes = 1;
1461 esi.val[offset] = ESI_TYPE_MAC;
1462 offset += field_bytes;
1463
1464 field_bytes = ETH_ALEN;
1465 memcpy(&esi.val[offset], (uint8_t *)sysmac, field_bytes);
1466 offset += field_bytes;
1467
1468 esi.val[offset++] = (uint8_t)(lid >> 16);
1469 esi.val[offset++] = (uint8_t)(lid >> 8);
1470 esi.val[offset++] = (uint8_t)lid;
1471
1472 if (old_es && !memcmp(&old_es->esi, &esi, sizeof(esi_t)))
1473 /* dup - nothing to be done */
1474 return 0;
1475
1476 /* release the old_es against the zif */
1477 if (old_es)
e378f502 1478 zebra_evpn_local_es_del(&zif->es_info.es);
ce5160c0
AK
1479
1480 es = zebra_evpn_es_find(&esi);
1481 if (es) {
1482 /* if it exists against another interface flag an error */
1483 if (es->zif && es->zif != zif)
1484 return -1;
1485 } else {
1486 /* create new es */
1487 es = zebra_evpn_es_new(&esi);
1488 }
1489
1490 zebra_evpn_es_local_info_set(es, zif);
1491
1492 return 0;
1493}
1494
1495static int zebra_evpn_remote_es_del(esi_t *esi, struct in_addr vtep_ip)
1496{
1497 char buf[ESI_STR_LEN];
1498 struct zebra_evpn_es *es;
1499
1500 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1501 zlog_debug("remote es %s vtep %s del",
1502 esi_to_str(esi, buf, sizeof(buf)),
1503 inet_ntoa(vtep_ip));
1504
1505 es = zebra_evpn_es_find(esi);
1506 if (!es) {
4d8b658c 1507 zlog_warn("remote es %s vtep %pI4 del failed, es missing",
e378f502 1508 esi_to_str(esi, buf, sizeof(buf)), &vtep_ip);
ce5160c0
AK
1509 return -1;
1510 }
1511
1512 zebra_evpn_es_vtep_del(es, vtep_ip);
e378f502 1513 zebra_evpn_es_remote_info_re_eval(&es);
ce5160c0
AK
1514
1515 return 0;
1516}
1517
1518/* force delete a remote ES on the way down */
e378f502 1519static void zebra_evpn_remote_es_flush(struct zebra_evpn_es **esp)
ce5160c0
AK
1520{
1521 struct zebra_evpn_es_vtep *es_vtep;
1522 struct listnode *node;
1523 struct listnode *nnode;
e378f502 1524 struct zebra_evpn_es *es = *esp;
ce5160c0
AK
1525
1526 for (ALL_LIST_ELEMENTS(es->es_vtep_list, node, nnode, es_vtep)) {
1527 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1528 zlog_debug("es %s vtep %s flush",
1529 es->esi_str,
1530 inet_ntoa(es_vtep->vtep_ip));
1531 zebra_evpn_es_vtep_free(es_vtep);
ce5160c0 1532 }
e378f502 1533 zebra_evpn_es_remote_info_re_eval(esp);
ce5160c0
AK
1534}
1535
1536static int zebra_evpn_remote_es_add(esi_t *esi, struct in_addr vtep_ip)
1537{
1538 char buf[ESI_STR_LEN];
1539 struct zebra_evpn_es *es;
1540
1541 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1542 zlog_debug("remote es %s vtep %s add",
1543 esi_to_str(esi, buf, sizeof(buf)),
1544 inet_ntoa(vtep_ip));
1545
1546 es = zebra_evpn_es_find(esi);
1547 if (!es) {
1548 es = zebra_evpn_es_new(esi);
1549 if (!es) {
e378f502
AK
1550 zlog_warn(
1551 "remote es %s vtep %pI4 add failed, es missing",
1552 esi_to_str(esi, buf, sizeof(buf)), &vtep_ip);
ce5160c0
AK
1553 return -1;
1554 }
1555 }
1556
1557 zebra_evpn_es_vtep_add(es, vtep_ip);
e378f502 1558 zebra_evpn_es_remote_info_re_eval(&es);
ce5160c0
AK
1559
1560 return 0;
1561}
1562
1563void zebra_evpn_proc_remote_es(ZAPI_HANDLER_ARGS)
1564{
1565 struct stream *s;
1566 struct in_addr vtep_ip;
1567 esi_t esi;
1568
1569 if (!is_evpn_enabled()) {
1570 zlog_debug(
1571 "%s: EVPN not enabled yet we received a es_add zapi call",
1572 __PRETTY_FUNCTION__);
1573 return;
1574 }
1575
1576 memset(&esi, 0, sizeof(esi_t));
1577 s = msg;
1578
1579 stream_get(&esi, s, sizeof(esi_t));
1580 vtep_ip.s_addr = stream_get_ipv4(s);
1581
1582 if (hdr->command == ZEBRA_REMOTE_ES_VTEP_ADD)
1583 zebra_evpn_remote_es_add(&esi, vtep_ip);
1584 else
1585 zebra_evpn_remote_es_del(&esi, vtep_ip);
1586}
1587
1588void zebra_evpn_es_mac_deref_entry(zebra_mac_t *mac)
1589{
1590 struct zebra_evpn_es *es = mac->es;
1591
1592 mac->es = NULL;
b169fd6f 1593 if (!es)
ce5160c0
AK
1594 return;
1595
b169fd6f
AK
1596 list_delete_node(es->mac_list, &mac->es_listnode);
1597 if (!listcount(es->mac_list))
e378f502 1598 zebra_evpn_es_free(&es);
ce5160c0
AK
1599}
1600
1601/* Associate a MAC entry with a local or remote ES. Returns false if there
1602 * was no ES change.
1603 */
1604bool zebra_evpn_es_mac_ref_entry(zebra_mac_t *mac, struct zebra_evpn_es *es)
1605{
1606 if (mac->es == es)
1607 return false;
1608
1609 if (mac->es)
1610 zebra_evpn_es_mac_deref_entry(mac);
1611
1612 if (!es)
1613 return true;
1614
1615 mac->es = es;
b169fd6f
AK
1616 listnode_init(&mac->es_listnode, mac);
1617 listnode_add(es->mac_list, &mac->es_listnode);
1618
ce5160c0
AK
1619 return true;
1620}
1621
b169fd6f 1622bool zebra_evpn_es_mac_ref(zebra_mac_t *mac, esi_t *esi)
ce5160c0
AK
1623{
1624 struct zebra_evpn_es *es;
1625
1626 es = zebra_evpn_es_find(esi);
1627 if (!es) {
4cd94050
AK
1628 /* If non-zero esi implicitly create a new ES */
1629 if (memcmp(esi, zero_esi, sizeof(esi_t))) {
1630 es = zebra_evpn_es_new(esi);
1631 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1632 zlog_debug("auto es %s add on mac ref",
1633 es->esi_str);
1634 }
ce5160c0
AK
1635 }
1636
b169fd6f 1637 return zebra_evpn_es_mac_ref_entry(mac, es);
ce5160c0
AK
1638}
1639
1640/* Inform BGP about local ES-EVI add or del */
1641static int zebra_evpn_es_evi_send_to_client(struct zebra_evpn_es *es,
87d76d54 1642 zebra_evpn_t *zevpn, bool add)
ce5160c0
AK
1643{
1644 struct zserv *client;
1645 struct stream *s;
1646
1647 client = zserv_find_client(ZEBRA_ROUTE_BGP, 0);
1648 /* BGP may not be running. */
1649 if (!client)
1650 return 0;
1651
1652 s = stream_new(ZEBRA_MAX_PACKET_SIZ);
1653
1654 zclient_create_header(s,
1655 add ? ZEBRA_LOCAL_ES_EVI_ADD : ZEBRA_LOCAL_ES_EVI_DEL,
1656 zebra_vrf_get_evpn_id());
1657 stream_put(s, &es->esi, sizeof(esi_t));
87d76d54 1658 stream_putl(s, zevpn->vni);
ce5160c0
AK
1659
1660 /* Write packet size. */
1661 stream_putw_at(s, 0, stream_get_endp(s));
1662
1663 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1664 zlog_debug("send %s local es %s evi %u to %s",
1665 add ? "add" : "del",
87d76d54 1666 es->esi_str, zevpn->vni,
ce5160c0
AK
1667 zebra_route_string(client->proto));
1668
1669 client->local_es_add_cnt++;
1670 return zserv_send_message(client, s);
1671}
1672
1673/* sysmac part of a local ESI has changed */
1674static int zebra_evpn_es_sys_mac_update(struct zebra_if *zif,
1675 struct ethaddr *sysmac)
1676{
1677 int rv;
1678
1679 rv = zebra_evpn_local_es_update(zif, zif->es_info.lid, sysmac);
1680 if (!rv)
1681 memcpy(&zif->es_info.sysmac, sysmac, sizeof(struct ethaddr));
1682
1683 return rv;
1684}
1685
1686/* local-ID part of ESI has changed */
1687static int zebra_evpn_es_lid_update(struct zebra_if *zif, uint32_t lid)
1688{
1689 int rv;
1690
1691 rv = zebra_evpn_local_es_update(zif, lid, &zif->es_info.sysmac);
1692 if (!rv)
1693 zif->es_info.lid = lid;
1694
1695 return rv;
1696}
1697
1698void zebra_evpn_es_cleanup(void)
1699{
1700 struct zebra_evpn_es *es;
1701 struct zebra_evpn_es *es_next;
1702
1703 RB_FOREACH_SAFE(es, zebra_es_rb_head,
1704 &zmh_info->es_rb_tree, es_next) {
e378f502
AK
1705 zebra_evpn_local_es_del(&es);
1706 if (es)
1707 zebra_evpn_remote_es_flush(&es);
ce5160c0
AK
1708 }
1709}
1710
1711/* Only certain types of access ports can be setup as an Ethernet Segment */
1712bool zebra_evpn_is_if_es_capable(struct zebra_if *zif)
1713{
1714 if (zif->zif_type == ZEBRA_IF_BOND)
1715 return true;
1716
1717 /* XXX: allow swpX i.e. a regular ethernet port to be an ES link too */
1718 return false;
1719}
1720
1721void zebra_evpn_if_es_print(struct vty *vty, struct zebra_if *zif)
1722{
1723 char buf[ETHER_ADDR_STRLEN];
1724
1725 if (zif->es_info.lid || !is_zero_mac(&zif->es_info.sysmac))
1726 vty_out(vty, " EVPN MH: ES id %u ES sysmac %s\n",
1727 zif->es_info.lid,
1728 prefix_mac2str(&zif->es_info.sysmac,
1729 buf, sizeof(buf)));
1730}
1731
1732void zebra_evpn_es_if_oper_state_change(struct zebra_if *zif, bool up)
1733{
1734 struct zebra_evpn_es *es = zif->es_info.es;
1735 bool old_up = !!(es->flags & ZEBRA_EVPNES_OPER_UP);
1736
1737 if (old_up == up)
1738 return;
1739
1740 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1741 zlog_debug("es %s state changed to %s ",
1742 es->esi_str,
1743 up ? "up" : "down");
1744 if (up)
1745 es->flags |= ZEBRA_EVPNES_OPER_UP;
1746 else
1747 es->flags &= ~ZEBRA_EVPNES_OPER_UP;
1748
1749 /* inform BGP of the ES oper state change */
1750 if (es->flags & ZEBRA_EVPNES_READY_FOR_BGP)
1751 zebra_evpn_es_send_add_to_client(es);
1752}
1753
9e0c2fd1
AK
1754static char *zebra_evpn_es_vtep_str(char *vtep_str, struct zebra_evpn_es *es,
1755 uint8_t vtep_str_size)
ce5160c0
AK
1756{
1757 struct zebra_evpn_es_vtep *zvtep;
1758 struct listnode *node;
1759 bool first = true;
1760
1761 vtep_str[0] = '\0';
1762 for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, zvtep)) {
1763 if (first) {
1764 first = false;
9e0c2fd1
AK
1765 strlcat(vtep_str, inet_ntoa(zvtep->vtep_ip),
1766 vtep_str_size);
ce5160c0 1767 } else {
9e0c2fd1
AK
1768 strlcat(vtep_str, ",", vtep_str_size);
1769 strlcat(vtep_str, inet_ntoa(zvtep->vtep_ip),
1770 vtep_str_size);
ce5160c0
AK
1771 }
1772 }
1773 return vtep_str;
1774}
1775
1776static void zebra_evpn_es_show_entry(struct vty *vty,
1777 struct zebra_evpn_es *es, json_object *json)
1778{
1779 char type_str[4];
1780 char vtep_str[ES_VTEP_LIST_STR_SZ];
1781
1782 if (json) {
1783 /* XXX */
1784 } else {
1785 type_str[0] = '\0';
1786 if (es->flags & ZEBRA_EVPNES_LOCAL)
9e0c2fd1 1787 strlcat(type_str, "L", sizeof(type_str));
ce5160c0 1788 if (es->flags & ZEBRA_EVPNES_REMOTE)
9e0c2fd1 1789 strlcat(type_str, "R", sizeof(type_str));
ce5160c0 1790
9e0c2fd1 1791 zebra_evpn_es_vtep_str(vtep_str, es, sizeof(vtep_str));
ce5160c0
AK
1792
1793 vty_out(vty, "%-30s %-4s %-21s %s\n",
1794 es->esi_str, type_str,
1795 es->zif ? es->zif->ifp->name : "-",
1796 vtep_str);
1797 }
1798}
1799
1800static void zebra_evpn_es_show_entry_detail(struct vty *vty,
1801 struct zebra_evpn_es *es, json_object *json)
1802{
1803 char type_str[80];
1804 struct zebra_evpn_es_vtep *zvtep;
1805 struct listnode *node;
1806
1807 if (json) {
1808 /* XXX */
1809 } else {
1810 type_str[0] = '\0';
1811 if (es->flags & ZEBRA_EVPNES_LOCAL)
9e0c2fd1 1812 strlcat(type_str, "Local", sizeof(type_str));
ce5160c0 1813 if (es->flags & ZEBRA_EVPNES_REMOTE) {
9e0c2fd1
AK
1814 if (strnlen(type_str, sizeof(type_str)))
1815 strlcat(type_str, ",", sizeof(type_str));
1816 strlcat(type_str, "Remote", sizeof(type_str));
ce5160c0
AK
1817 }
1818
1819 vty_out(vty, "ESI: %s\n", es->esi_str);
1820 vty_out(vty, " Type: %s\n", type_str);
1821 vty_out(vty, " Interface: %s\n",
1822 (es->zif) ?
1823 es->zif->ifp->name : "-");
1824 vty_out(vty, " State: %s\n",
1825 (es->flags & ZEBRA_EVPNES_OPER_UP) ?
1826 "up" : "down");
1827 vty_out(vty, " Ready for BGP: %s\n",
1828 (es->flags & ZEBRA_EVPNES_READY_FOR_BGP) ?
1829 "yes" : "no");
1830 vty_out(vty, " VNI Count: %d\n", listcount(es->es_evi_list));
b169fd6f 1831 vty_out(vty, " MAC Count: %d\n", listcount(es->mac_list));
ce5160c0
AK
1832 vty_out(vty, " Nexthop group: 0x%x\n", es->nhg_id);
1833 vty_out(vty, " VTEPs:\n");
1834 for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, zvtep))
1835 vty_out(vty, " %s nh: 0x%x\n",
1836 inet_ntoa(zvtep->vtep_ip),
1837 zvtep->nh_id);
1838
1839 vty_out(vty, "\n");
1840 }
1841}
1842
1843void zebra_evpn_es_show(struct vty *vty, bool uj)
1844{
1845 struct zebra_evpn_es *es;
1846 json_object *json = NULL;
1847
1848 if (uj) {
1849 /* XXX */
1850 } else {
1851 vty_out(vty, "Type: L local, R remote\n");
1852 vty_out(vty, "%-30s %-4s %-21s %s\n",
1853 "ESI", "Type", "ES-IF", "VTEPs");
1854 }
1855
1856 RB_FOREACH(es, zebra_es_rb_head, &zmh_info->es_rb_tree)
1857 zebra_evpn_es_show_entry(vty, es, json);
1858}
1859
1860void zebra_evpn_es_show_detail(struct vty *vty, bool uj)
1861{
1862 struct zebra_evpn_es *es;
1863 json_object *json = NULL;
1864
1865 RB_FOREACH(es, zebra_es_rb_head, &zmh_info->es_rb_tree)
1866 zebra_evpn_es_show_entry_detail(vty, es, json);
1867}
1868
1869void zebra_evpn_es_show_esi(struct vty *vty, bool uj, esi_t *esi)
1870{
1871 struct zebra_evpn_es *es;
1872 char esi_str[ESI_STR_LEN];
1873 json_object *json = NULL;
1874
1875 es = zebra_evpn_es_find(esi);
1876
1877 if (!es) {
1878 esi_to_str(esi, esi_str, sizeof(esi_str));
1879 vty_out(vty, "ESI %s does not exist\n", esi_str);
1880 return;
1881 }
1882
1883 zebra_evpn_es_show_entry_detail(vty, es, json);
1884}
1885
1886int zebra_evpn_mh_if_write(struct vty *vty, struct interface *ifp)
1887{
1888 struct zebra_if *zif = ifp->info;
1889 char buf[ETHER_ADDR_STRLEN];
1890
1891 if (zif->es_info.lid)
1892 vty_out(vty, " evpn mh es-id %u\n", zif->es_info.lid);
1893
1894 if (!is_zero_mac(&zif->es_info.sysmac))
1895 vty_out(vty, " evpn mh es-sys-mac %s\n",
1896 prefix_mac2str(&zif->es_info.sysmac,
1897 buf, sizeof(buf)));
1898 return 0;
1899}
1900
1901#ifndef VTYSH_EXTRACT_PL
1902#include "zebra/zebra_evpn_mh_clippy.c"
1903#endif
1904/* CLI for setting up sysmac part of ESI on an access port */
1905DEFPY(zebra_evpn_es_sys_mac,
1906 zebra_evpn_es_sys_mac_cmd,
1907 "[no$no] evpn mh es-sys-mac [X:X:X:X:X:X$mac]",
1908 NO_STR
1909 "EVPN\n"
1910 EVPN_MH_VTY_STR
1911 "Ethernet segment system MAC\n"
1912 MAC_STR
1913)
1914{
1915 VTY_DECLVAR_CONTEXT(interface, ifp);
1916 struct zebra_if *zif;
1917 int ret = 0;
1918
1919 zif = ifp->info;
1920
1921 if (no) {
1922 static struct ethaddr zero_mac;
1923
1924 ret = zebra_evpn_es_sys_mac_update(zif, &zero_mac);
1925 if (ret == -1) {
1926 vty_out(vty, "%%Failed to clear ES sysmac\n");
1927 return CMD_WARNING;
1928 }
1929 } else {
1930
1931 if (!zebra_evpn_is_if_es_capable(zif)) {
1932 vty_out(vty,
1933 "%%ESI cannot be associated with this interface type\n");
1934 return CMD_WARNING;
1935 }
1936
1937 if (!mac || is_zero_mac(&mac->eth_addr)) {
1938 vty_out(vty, "%%ES sysmac value is invalid\n");
1939 return CMD_WARNING;
1940 }
1941
1942 ret = zebra_evpn_es_sys_mac_update(zif, &mac->eth_addr);
1943 if (ret == -1) {
1944 vty_out(vty, "%%ESI already exists on a different interface\n");
1945 return CMD_WARNING;
1946 }
1947 }
1948 return CMD_SUCCESS;
1949}
1950
1951/* CLI for setting up local-ID part of ESI on an access port */
1952DEFPY(zebra_evpn_es_id,
1953 zebra_evpn_es_id_cmd,
1954 "[no$no] evpn mh es-id [(1-16777215)$es_lid]",
1955 NO_STR
1956 "EVPN\n"
1957 EVPN_MH_VTY_STR
1958 "Ethernet segment local identifier\n"
1959 "ID\n"
1960)
1961{
1962 VTY_DECLVAR_CONTEXT(interface, ifp);
1963 struct zebra_if *zif;
1964 int ret;
1965
1966 zif = ifp->info;
1967
1968 if (no) {
1969 ret = zebra_evpn_es_lid_update(zif, 0);
1970 if (ret == -1) {
1971 vty_out(vty, "%%Failed to clear ES local id\n");
1972 return CMD_WARNING;
1973 }
1974 } else {
1975 if (!zebra_evpn_is_if_es_capable(zif)) {
1976 vty_out(vty,
1977 "%%ESI cannot be associated with this interface type\n");
1978 return CMD_WARNING;
1979 }
1980
1981 if (!es_lid) {
1982 vty_out(vty, "%%Specify local ES ID\n");
1983 return CMD_WARNING;
1984 }
1985 ret = zebra_evpn_es_lid_update(zif, es_lid);
1986 if (ret == -1) {
1987 vty_out(vty,
1988 "%%ESI already exists on a different interface\n");
1989 return CMD_WARNING;
1990 }
1991 }
1992 return CMD_SUCCESS;
1993}
1994
1995/*****************************************************************************/
1996/* A base L2-VNI is maintained to derive parameters such as ES originator-IP.
1997 * XXX: once single vxlan device model becomes available this will not be
1998 * necessary
1999 */
2000/* called when a new vni is added or becomes oper up or becomes a bridge port */
87d76d54 2001void zebra_evpn_es_set_base_evpn(zebra_evpn_t *zevpn)
ce5160c0
AK
2002{
2003 struct listnode *node;
2004 struct zebra_evpn_es *es;
2005
87d76d54
PR
2006 if (zmh_info->es_base_evpn) {
2007 if (zmh_info->es_base_evpn != zevpn) {
2008 /* unrelated EVPN; ignore it */
ce5160c0
AK
2009 return;
2010 }
2011 /* check if the local vtep-ip has changed */
2012 } else {
87d76d54
PR
2013 /* check if the EVPN can be used as base EVPN */
2014 if (!zebra_evpn_send_to_client_ok(zevpn))
ce5160c0
AK
2015 return;
2016
2017 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
2018 zlog_debug("es base vni set to %d",
87d76d54
PR
2019 zevpn->vni);
2020 zmh_info->es_base_evpn = zevpn;
ce5160c0
AK
2021 }
2022
2023 /* update local VTEP-IP */
2024 if (zmh_info->es_originator_ip.s_addr ==
87d76d54 2025 zmh_info->es_base_evpn->local_vtep_ip.s_addr)
ce5160c0
AK
2026 return;
2027
2028 zmh_info->es_originator_ip.s_addr =
87d76d54 2029 zmh_info->es_base_evpn->local_vtep_ip.s_addr;
ce5160c0
AK
2030
2031 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
2032 zlog_debug("es originator ip set to %s",
87d76d54 2033 inet_ntoa(zmh_info->es_base_evpn->local_vtep_ip));
ce5160c0
AK
2034
2035 /* if originator ip changes we need to update bgp */
2036 for (ALL_LIST_ELEMENTS_RO(zmh_info->local_es_list, node, es)) {
2037 if (es->flags & ZEBRA_EVPNES_READY_FOR_BGP)
2038 zebra_evpn_es_send_add_to_client(es);
2039 else
2040 zebra_evpn_es_re_eval_send_to_client(es,
2041 true /* es_evi_re_reval */);
2042 }
2043}
2044
2045/* called when a vni is removed or becomes oper down or is removed from a
2046 * bridge
2047 */
87d76d54 2048void zebra_evpn_es_clear_base_evpn(zebra_evpn_t *zevpn)
ce5160c0
AK
2049{
2050 struct listnode *node;
2051 struct zebra_evpn_es *es;
2052
87d76d54 2053 if (zmh_info->es_base_evpn != zevpn)
ce5160c0
AK
2054 return;
2055
87d76d54
PR
2056 zmh_info->es_base_evpn = NULL;
2057 /* lost current base EVPN; try to find a new one */
2058 zebra_evpn_es_get_one_base_evpn();
ce5160c0 2059
87d76d54
PR
2060 /* couldn't locate an eligible base evpn */
2061 if (!zmh_info->es_base_evpn && zmh_info->es_originator_ip.s_addr) {
ce5160c0
AK
2062 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
2063 zlog_debug("es originator ip cleared");
2064
2065 zmh_info->es_originator_ip.s_addr = 0;
2066 /* lost originator ip */
2067 for (ALL_LIST_ELEMENTS_RO(zmh_info->local_es_list, node, es)) {
2068 zebra_evpn_es_re_eval_send_to_client(es,
2069 true /* es_evi_re_reval */);
2070 }
2071 }
2072}
2073
2074/* Locate an "eligible" L2-VNI to follow */
87d76d54 2075static int zebra_evpn_es_get_one_base_evpn_cb(struct hash_bucket *b, void *data)
ce5160c0 2076{
87d76d54 2077 zebra_evpn_t *zevpn = b->data;
ce5160c0 2078
87d76d54 2079 zebra_evpn_es_set_base_evpn(zevpn);
ce5160c0 2080
87d76d54 2081 if (zmh_info->es_base_evpn)
ce5160c0
AK
2082 return HASHWALK_ABORT;
2083
2084 return HASHWALK_CONTINUE;
2085}
2086
87d76d54 2087/* locate a base_evpn to follow for the purposes of common params like
ce5160c0
AK
2088 * originator IP
2089 */
87d76d54 2090static void zebra_evpn_es_get_one_base_evpn(void)
ce5160c0
AK
2091{
2092 struct zebra_vrf *zvrf;
2093
2094 zvrf = zebra_vrf_get_evpn();
87d76d54 2095 hash_walk(zvrf->evpn_table, zebra_evpn_es_get_one_base_evpn_cb, NULL);
ce5160c0
AK
2096}
2097
2098/*****************************************************************************/
b169fd6f
AK
2099void zebra_evpn_mh_config_write(struct vty *vty)
2100{
2101 if (zmh_info->mac_hold_time != EVPN_MH_MAC_HOLD_TIME_DEF)
2102 vty_out(vty, "evpn mh mac-holdtime %ld\n",
2103 zmh_info->mac_hold_time);
2104
2105 if (zmh_info->neigh_hold_time != EVPN_MH_NEIGH_HOLD_TIME_DEF)
2106 vty_out(vty, "evpn mh neigh-holdtime %ld\n",
2107 zmh_info->neigh_hold_time);
2108}
2109
2110int zebra_evpn_mh_neigh_holdtime_update(struct vty *vty,
2111 uint32_t duration, bool set_default)
2112{
2113 if (set_default)
f9f0463f 2114 duration = EVPN_MH_NEIGH_HOLD_TIME_DEF;
b169fd6f
AK
2115
2116 zmh_info->neigh_hold_time = duration;
2117
2118 return 0;
2119}
2120
2121int zebra_evpn_mh_mac_holdtime_update(struct vty *vty,
2122 uint32_t duration, bool set_default)
2123{
2124 if (set_default)
2125 duration = EVPN_MH_MAC_HOLD_TIME_DEF;
2126
2127 zmh_info->mac_hold_time = duration;
2128
2129 return 0;
2130}
2131
ce5160c0
AK
2132void zebra_evpn_interface_init(void)
2133{
2134 install_element(INTERFACE_NODE, &zebra_evpn_es_id_cmd);
2135 install_element(INTERFACE_NODE, &zebra_evpn_es_sys_mac_cmd);
2136}
2137
2138void zebra_evpn_mh_init(void)
2139{
2140 zrouter.mh_info = XCALLOC(MTYPE_ZMH_INFO, sizeof(*zrouter.mh_info));
2141
b169fd6f
AK
2142 zmh_info->mac_hold_time = EVPN_MH_MAC_HOLD_TIME_DEF;
2143 zmh_info->neigh_hold_time = EVPN_MH_NEIGH_HOLD_TIME_DEF;
ce5160c0
AK
2144 /* setup ES tables */
2145 RB_INIT(zebra_es_rb_head, &zmh_info->es_rb_tree);
2146 zmh_info->local_es_list = list_new();
2147 listset_app_node_mem(zmh_info->local_es_list);
2148
2149 bf_init(zmh_info->nh_id_bitmap, EVPN_NH_ID_MAX);
2150 bf_assign_zero_index(zmh_info->nh_id_bitmap);
2151
2152 /* setup broadcast domain tables */
2153 zmh_info->evpn_vlan_table = hash_create(zebra_evpn_acc_vl_hash_keymake,
2154 zebra_evpn_acc_vl_cmp, "access VLAN hash table");
2155}
2156
2157void zebra_evpn_mh_terminate(void)
2158{
2159 list_delete(&zmh_info->local_es_list);
2160
2161 hash_iterate(zmh_info->evpn_vlan_table,
2162 zebra_evpn_acc_vl_cleanup_all, NULL);
2163 hash_free(zmh_info->evpn_vlan_table);
2164}