]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_evpn_mh.c
Merge pull request #7015 from donaldsharp/zebra_nht_no_heros_tonight
[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);
ce5160c0
AK
63static void zebra_evpn_local_es_del(struct zebra_evpn_es *es);
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);
ce5160c0 361 }
87d76d54 362 zebra_evpn_es_evi_show_one_evpn(zevpn, vty, json, detail);
ce5160c0
AK
363}
364
365/* Initialize the ES tables maintained per-L2_VNI */
87d76d54 366void zebra_evpn_evpn_es_init(zebra_evpn_t *zevpn)
ce5160c0
AK
367{
368 /* Initialize the ES-EVI RB tree */
87d76d54 369 RB_INIT(zebra_es_evi_rb_head, &zevpn->es_evi_rb_tree);
ce5160c0
AK
370
371 /* Initialize the local and remote ES lists maintained for quick
372 * walks by type
373 */
87d76d54
PR
374 zevpn->local_es_evi_list = list_new();
375 listset_app_node_mem(zevpn->local_es_evi_list);
ce5160c0
AK
376}
377
87d76d54
PR
378/* Cleanup the ES info maintained per- EVPN */
379void zebra_evpn_evpn_es_cleanup(zebra_evpn_t *zevpn)
ce5160c0
AK
380{
381 struct zebra_evpn_es_evi *es_evi;
382 struct zebra_evpn_es_evi *es_evi_next;
383
384 RB_FOREACH_SAFE(es_evi, zebra_es_evi_rb_head,
87d76d54 385 &zevpn->es_evi_rb_tree, es_evi_next) {
ce5160c0
AK
386 zebra_evpn_local_es_evi_do_del(es_evi);
387 }
388
87d76d54
PR
389 list_delete(&zevpn->local_es_evi_list);
390 zebra_evpn_es_clear_base_evpn(zevpn);
ce5160c0
AK
391}
392
393/* called when the oper state or bridge membership changes for the
394 * vxlan device
395 */
87d76d54 396void zebra_evpn_update_all_es(zebra_evpn_t *zevpn)
ce5160c0
AK
397{
398 struct zebra_evpn_es_evi *es_evi;
399 struct listnode *node;
400
87d76d54
PR
401 /* the EVPN is now elgible as a base for EVPN-MH */
402 if (zebra_evpn_send_to_client_ok(zevpn))
403 zebra_evpn_es_set_base_evpn(zevpn);
ce5160c0 404 else
87d76d54 405 zebra_evpn_es_clear_base_evpn(zevpn);
ce5160c0 406
87d76d54 407 for (ALL_LIST_ELEMENTS_RO(zevpn->local_es_evi_list, node, es_evi))
ce5160c0
AK
408 zebra_evpn_es_evi_re_eval_send_to_client(es_evi);
409}
410
411/*****************************************************************************/
412/* Access broadcast domains (BD)
413 * 1. These broadcast domains can be VLAN aware (in which case
414 * the key is VID) or VLAN unaware (in which case the key is
415 * 2. A VID-BD is created when a VLAN is associated with an access port or
416 * when the VLAN is associated with VXLAN_IF
417 * 3. A BD is translated into ES-EVI entries when a VNI is associated
418 * with the broadcast domain
419 */
420/* Hash key for VLAN based broadcast domains */
421static unsigned int zebra_evpn_acc_vl_hash_keymake(const void *p)
422{
423 const struct zebra_evpn_access_bd *acc_bd = p;
424
425 return jhash_1word(acc_bd->vid, 0);
426}
427
428/* Compare two VLAN based broadcast domains */
429static bool zebra_evpn_acc_vl_cmp(const void *p1, const void *p2)
430{
431 const struct zebra_evpn_access_bd *acc_bd1 = p1;
432 const struct zebra_evpn_access_bd *acc_bd2 = p2;
433
434 if (acc_bd1 == NULL && acc_bd2 == NULL)
435 return true;
436
437 if (acc_bd1 == NULL || acc_bd2 == NULL)
438 return false;
439
440 return (acc_bd1->vid == acc_bd2->vid);
441}
442
443/* Lookup VLAN based broadcast domain */
444static struct zebra_evpn_access_bd *zebra_evpn_acc_vl_find(vlanid_t vid)
445{
446 struct zebra_evpn_access_bd *acc_bd;
447 struct zebra_evpn_access_bd tmp;
448
449 tmp.vid = vid;
450 acc_bd = hash_lookup(zmh_info->evpn_vlan_table, &tmp);
451
452 return acc_bd;
453}
454
455/* A new broadcast domain can be created when a VLAN member or VLAN<=>VxLAN_IF
456 * mapping is added.
457 */
458static struct zebra_evpn_access_bd *zebra_evpn_acc_vl_new(vlanid_t vid)
459{
460 struct zebra_evpn_access_bd *acc_bd;
461
462 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
463 zlog_debug("access vlan %d add", vid);
464
465 acc_bd = XCALLOC(MTYPE_ZACC_BD, sizeof(struct zebra_evpn_access_bd));
466
467 acc_bd->vid = vid;
468
469 /* Initialize the mbr list */
470 acc_bd->mbr_zifs = list_new();
471
472 /* Add to hash */
473 if (!hash_get(zmh_info->evpn_vlan_table, acc_bd, hash_alloc_intern)) {
474 XFREE(MTYPE_ZACC_BD, acc_bd);
475 return NULL;
476 }
477
478 return acc_bd;
479}
480
481/* Free VLAN based broadcast domain -
482 * This just frees appropriate memory, caller should have taken other
483 * needed actions.
484 */
485static void zebra_evpn_acc_vl_free(struct zebra_evpn_access_bd *acc_bd)
486{
487 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
488 zlog_debug("access vlan %d del", acc_bd->vid);
489
490 /* cleanup resources maintained against the ES */
491 list_delete(&acc_bd->mbr_zifs);
492
493 /* remove EVI from various tables */
494 hash_release(zmh_info->evpn_vlan_table, acc_bd);
495
496 XFREE(MTYPE_ZACC_BD, acc_bd);
497}
498
499static void zebra_evpn_acc_vl_cleanup_all(struct hash_bucket *bucket, void *arg)
500{
501 struct zebra_evpn_access_bd *acc_bd = bucket->data;
502
503 zebra_evpn_acc_vl_free(acc_bd);
504}
505
506/* called when a bd mbr is removed or VxLAN_IF is diassociated from the access
507 * VLAN
508 */
509static void zebra_evpn_acc_bd_free_on_deref(struct zebra_evpn_access_bd *acc_bd)
510{
511 if (!list_isempty(acc_bd->mbr_zifs) || acc_bd->vxlan_zif)
512 return;
513
514 /* if there are no references free the EVI */
515 zebra_evpn_acc_vl_free(acc_bd);
516}
517
518/* called when a EVPN-L2VNI is set or cleared against a BD */
87d76d54
PR
519static void zebra_evpn_acc_bd_evpn_set(struct zebra_evpn_access_bd *acc_bd,
520 zebra_evpn_t *zevpn, zebra_evpn_t *old_zevpn)
ce5160c0
AK
521{
522 struct zebra_if *zif;
523 struct listnode *node;
524
525 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
526 zlog_debug("access vlan %d l2-vni %u set",
87d76d54 527 acc_bd->vid, zevpn ? zevpn->vni : 0);
ce5160c0
AK
528
529 for (ALL_LIST_ELEMENTS_RO(acc_bd->mbr_zifs, node, zif)) {
530 if (!zif->es_info.es)
531 continue;
532
87d76d54
PR
533 if (zevpn)
534 zebra_evpn_local_es_evi_add(zif->es_info.es, zevpn);
535 else if (old_zevpn)
536 zebra_evpn_local_es_evi_del(zif->es_info.es, old_zevpn);
ce5160c0
AK
537 }
538}
539
540/* handle VLAN->VxLAN_IF association */
541void zebra_evpn_vl_vxl_ref(uint16_t vid, struct zebra_if *vxlan_zif)
542{
543 struct zebra_evpn_access_bd *acc_bd;
544 struct zebra_if *old_vxlan_zif;
87d76d54 545 zebra_evpn_t *old_zevpn;
ce5160c0
AK
546
547 if (!vid)
548 return;
549
550 acc_bd = zebra_evpn_acc_vl_find(vid);
551 if (!acc_bd)
552 acc_bd = zebra_evpn_acc_vl_new(vid);
553
554 old_vxlan_zif = acc_bd->vxlan_zif;
555 acc_bd->vxlan_zif = vxlan_zif;
556 if (vxlan_zif == old_vxlan_zif)
557 return;
558
87d76d54 559 old_zevpn = acc_bd->zevpn;
8b5fdf2e 560 acc_bd->zevpn = zebra_evpn_lookup(vxlan_zif->l2info.vxl.vni);
87d76d54 561 if (acc_bd->zevpn == old_zevpn)
ce5160c0
AK
562 return;
563
564 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
565 zlog_debug("access vlan %d vni %u ref",
566 acc_bd->vid, vxlan_zif->l2info.vxl.vni);
567
87d76d54
PR
568 if (old_zevpn)
569 zebra_evpn_acc_bd_evpn_set(acc_bd, NULL, old_zevpn);
ce5160c0 570
87d76d54
PR
571 if (acc_bd->zevpn)
572 zebra_evpn_acc_bd_evpn_set(acc_bd, acc_bd->zevpn, NULL);
ce5160c0
AK
573}
574
575/* handle VLAN->VxLAN_IF deref */
576void zebra_evpn_vl_vxl_deref(uint16_t vid, struct zebra_if *vxlan_zif)
577{
578 struct zebra_evpn_access_bd *acc_bd;
579
580 if (!vid)
581 return;
582
583 acc_bd = zebra_evpn_acc_vl_find(vid);
584 if (!acc_bd)
585 return;
586
587 /* clear vxlan_if only if it matches */
588 if (acc_bd->vxlan_zif != vxlan_zif)
589 return;
590
591 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
592 zlog_debug("access vlan %d vni %u deref",
593 acc_bd->vid, vxlan_zif->l2info.vxl.vni);
594
87d76d54
PR
595 if (acc_bd->zevpn)
596 zebra_evpn_acc_bd_evpn_set(acc_bd, NULL, acc_bd->zevpn);
ce5160c0 597
87d76d54 598 acc_bd->zevpn = NULL;
ce5160c0
AK
599 acc_bd->vxlan_zif = NULL;
600
601 /* if there are no other references the access_bd can be freed */
602 zebra_evpn_acc_bd_free_on_deref(acc_bd);
603}
604
87d76d54
PR
605/* handle EVPN add/del */
606void zebra_evpn_vxl_evpn_set(struct zebra_if *zif, zebra_evpn_t *zevpn,
ce5160c0
AK
607 bool set)
608{
609 struct zebra_l2info_vxlan *vxl;
610 struct zebra_evpn_access_bd *acc_bd;
611
612 if (!zif)
613 return;
614
615 /* locate access_bd associated with the vxlan device */
616 vxl = &zif->l2info.vxl;
617 acc_bd = zebra_evpn_acc_vl_find(vxl->access_vlan);
618 if (!acc_bd)
619 return;
620
621 if (set) {
87d76d54
PR
622 zebra_evpn_es_set_base_evpn(zevpn);
623 if (acc_bd->zevpn != zevpn) {
624 acc_bd->zevpn = zevpn;
625 zebra_evpn_acc_bd_evpn_set(acc_bd, zevpn, NULL);
ce5160c0
AK
626 }
627 } else {
87d76d54
PR
628 if (acc_bd->zevpn) {
629 zebra_evpn_t *old_zevpn = acc_bd->zevpn;
630 acc_bd->zevpn = NULL;
631 zebra_evpn_acc_bd_evpn_set(acc_bd, NULL, old_zevpn);
ce5160c0
AK
632 }
633 }
634}
635
636/* handle addition of new VLAN members */
637void zebra_evpn_vl_mbr_ref(uint16_t vid, struct zebra_if *zif)
638{
639 struct zebra_evpn_access_bd *acc_bd;
640
641 if (!vid)
642 return;
643
644 acc_bd = zebra_evpn_acc_vl_find(vid);
645 if (!acc_bd)
646 acc_bd = zebra_evpn_acc_vl_new(vid);
647
648 if (listnode_lookup(acc_bd->mbr_zifs, zif))
649 return;
650
651 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
652 zlog_debug("access vlan %d mbr %s ref",
653 vid, zif->ifp->name);
654
655 listnode_add(acc_bd->mbr_zifs, zif);
87d76d54
PR
656 if (acc_bd->zevpn && zif->es_info.es)
657 zebra_evpn_local_es_evi_add(zif->es_info.es, acc_bd->zevpn);
ce5160c0
AK
658}
659
660/* handle deletion of VLAN members */
661void zebra_evpn_vl_mbr_deref(uint16_t vid, struct zebra_if *zif)
662{
663 struct zebra_evpn_access_bd *acc_bd;
664 struct listnode *node;
665
666 if (!vid)
667 return;
668
669 acc_bd = zebra_evpn_acc_vl_find(vid);
670 if (!acc_bd)
671 return;
672
673 node = listnode_lookup(acc_bd->mbr_zifs, zif);
674 if (!node)
675 return;
676
677 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
678 zlog_debug("access vlan %d mbr %s deref",
679 vid, zif->ifp->name);
680
681 list_delete_node(acc_bd->mbr_zifs, node);
682
87d76d54
PR
683 if (acc_bd->zevpn && zif->es_info.es)
684 zebra_evpn_local_es_evi_del(zif->es_info.es, acc_bd->zevpn);
ce5160c0
AK
685
686 /* if there are no other references the access_bd can be freed */
687 zebra_evpn_acc_bd_free_on_deref(acc_bd);
688}
689
690static void zebra_evpn_acc_vl_show_entry_detail(struct vty *vty,
691 struct zebra_evpn_access_bd *acc_bd, json_object *json)
692{
693 struct zebra_if *zif;
694 struct listnode *node;
695
696 if (json) {
697 /* XXX */
698 } else {
699 vty_out(vty, "VLAN: %u\n", acc_bd->vid);
700 vty_out(vty, " VxLAN Interface: %s\n",
701 acc_bd->vxlan_zif ?
702 acc_bd->vxlan_zif->ifp->name : "-");
703 vty_out(vty, " L2-VNI: %d\n",
87d76d54 704 acc_bd->zevpn ? acc_bd->zevpn->vni : 0);
ce5160c0
AK
705 vty_out(vty, " Member Count: %d\n",
706 listcount(acc_bd->mbr_zifs));
707 vty_out(vty, " Members: \n");
708 for (ALL_LIST_ELEMENTS_RO(acc_bd->mbr_zifs, node, zif))
709 vty_out(vty, " %s\n", zif->ifp->name);
710 vty_out(vty, "\n");
711 }
712}
713
714static void zebra_evpn_acc_vl_show_entry(struct vty *vty,
715 struct zebra_evpn_access_bd *acc_bd, json_object *json)
716{
717 if (!json)
718 vty_out(vty, "%-5u %21s %-8d %u\n",
719 acc_bd->vid,
720 acc_bd->vxlan_zif ?
721 acc_bd->vxlan_zif->ifp->name : "-",
87d76d54 722 acc_bd->zevpn ? acc_bd->zevpn->vni : 0,
ce5160c0
AK
723 listcount(acc_bd->mbr_zifs));
724}
725
726static void zebra_evpn_acc_vl_show_hash(struct hash_bucket *bucket, void *ctxt)
727{
728 struct evpn_mh_show_ctx *wctx = ctxt;
729 struct zebra_evpn_access_bd *acc_bd = bucket->data;
730
731 if (wctx->detail)
732 zebra_evpn_acc_vl_show_entry_detail(wctx->vty,
733 acc_bd, wctx->json);
734 else
735 zebra_evpn_acc_vl_show_entry(wctx->vty,
736 acc_bd, wctx->json);
737}
738
739void zebra_evpn_acc_vl_show(struct vty *vty, bool uj)
740{
741 json_object *json = NULL;
742 struct evpn_mh_show_ctx wctx;
743
744 memset(&wctx, 0, sizeof(wctx));
745 wctx.vty = vty;
746 wctx.json = json;
747 wctx.detail = false;
748
749 if (!json)
750 vty_out(vty, "%-5s %21s %-8s %s\n",
751 "VLAN", "VxLAN-IF", "L2-VNI", "# Members");
752
753 hash_iterate(zmh_info->evpn_vlan_table, zebra_evpn_acc_vl_show_hash,
754 &wctx);
755}
756
757void zebra_evpn_acc_vl_show_detail(struct vty *vty, bool uj)
758{
759 json_object *json = NULL;
760 struct evpn_mh_show_ctx wctx;
761
762 memset(&wctx, 0, sizeof(wctx));
763 wctx.vty = vty;
764 wctx.json = json;
765 wctx.detail = true;
766
767 hash_iterate(zmh_info->evpn_vlan_table, zebra_evpn_acc_vl_show_hash,
768 &wctx);
769}
770
771void zebra_evpn_acc_vl_show_vid(struct vty *vty, bool uj, vlanid_t vid)
772{
773 json_object *json = NULL;
774 struct zebra_evpn_access_bd *acc_bd;
775
776 acc_bd = zebra_evpn_acc_vl_find(vid);
777 if (!acc_bd) {
778 if (!json) {
779 vty_out(vty, "VLAN %u not present\n", vid);
780 return;
781 }
782 }
783 zebra_evpn_acc_vl_show_entry_detail(vty, acc_bd, json);
784}
785
786/* Initialize VLAN member bitmap on an interface. Although VLAN membership
787 * is independent of EVPN we only process it if its of interest to EVPN-MH
788 * i.e. on access ports that can be setup as Ethernet Segments. And that is
789 * intended as an optimization.
790 */
791void zebra_evpn_if_init(struct zebra_if *zif)
792{
793 if (!zebra_evpn_is_if_es_capable(zif))
794 return;
795
796 if (!bf_is_inited(zif->vlan_bitmap))
797 bf_init(zif->vlan_bitmap, IF_VLAN_BITMAP_MAX);
798
799 /* if an es_id and sysmac are already present against the interface
800 * activate it
801 */
802 zebra_evpn_local_es_update(zif, zif->es_info.lid, &zif->es_info.sysmac);
803}
804
805/* handle deletion of an access port by removing it from all associated
806 * broadcast domains.
807 */
808void zebra_evpn_if_cleanup(struct zebra_if *zif)
809{
810 vlanid_t vid;
811
812 if (!bf_is_inited(zif->vlan_bitmap))
813 return;
814
815 bf_for_each_set_bit(zif->vlan_bitmap, vid, IF_VLAN_BITMAP_MAX) {
816 zebra_evpn_vl_mbr_deref(vid, zif);
817 }
818
819 bf_free(zif->vlan_bitmap);
820
821 /* Delete associated Ethernet Segment */
822 if (zif->es_info.es)
823 zebra_evpn_local_es_del(zif->es_info.es);
824}
825
826/*****************************************************************************
827 * L2 NH/NHG Management
828 * A L2 NH entry is programmed in the kernel for every ES-VTEP entry. This
829 * NH is then added to the L2-ECMP-NHG associated with the ES.
830 */
831static uint32_t zebra_evpn_nhid_alloc(bool is_nhg)
832{
833 uint32_t id;
834 int type;
835
836 bf_assign_index(zmh_info->nh_id_bitmap, id);
837
838 if (!id)
839 return 0;
840
841 type = is_nhg ? EVPN_NHG_ID_TYPE_BIT : EVPN_NH_ID_TYPE_BIT;
842 return (id | type);
843}
844
845static void zebra_evpn_nhid_free(uint32_t nh_id)
846{
847 uint32_t id = (nh_id & EVPN_NH_ID_VAL_MASK);
848
849 if (!id)
850 return;
851
852 bf_release_index(zmh_info->nh_id_bitmap, id);
853}
854
855/* The MAC ECMP group is activated on the first VTEP */
856static void zebra_evpn_nhg_update(struct zebra_evpn_es *es)
857{
858 uint32_t nh_cnt = 0;
859 struct nh_grp nh_ids[ES_VTEP_MAX_CNT];
860 struct zebra_evpn_es_vtep *es_vtep;
861 struct listnode *node;
862
863 if (!es->nhg_id)
864 return;
865
866 for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
867 if (!es_vtep->nh_id)
868 continue;
869
870 if (nh_cnt >= ES_VTEP_MAX_CNT)
871 break;
872
873 memset(&nh_ids[nh_cnt], 0, sizeof(struct nh_grp));
874 nh_ids[nh_cnt].id = es_vtep->nh_id;
875 ++nh_cnt;
876 }
877
878 if (nh_cnt) {
879 if (IS_ZEBRA_DEBUG_EVPN_MH_NH) {
880 char nh_str[ES_VTEP_LIST_STR_SZ];
881 uint32_t i;
9e0c2fd1 882 char nh_buf[16];
ce5160c0
AK
883
884 nh_str[0] = '\0';
9e0c2fd1
AK
885 for (i = 0; i < nh_cnt; ++i) {
886 snprintf(nh_buf, sizeof(nh_buf), "%u ",
887 nh_ids[i].id);
888 strlcat(nh_str, nh_buf, sizeof(nh_str));
889 }
ce5160c0
AK
890 zlog_debug("es %s nhg 0x%x add %s",
891 es->esi_str, es->nhg_id, nh_str);
892 }
893
894 es->flags |= ZEBRA_EVPNES_NHG_ACTIVE;
895 kernel_upd_mac_nhg(es->nhg_id, nh_cnt, nh_ids);
896 } else {
897 if (es->flags & ZEBRA_EVPNES_NHG_ACTIVE) {
898 if (IS_ZEBRA_DEBUG_EVPN_MH_NH)
899 zlog_debug("es %s nhg 0x%x del",
900 es->esi_str, es->nhg_id);
901 es->flags &= ~ZEBRA_EVPNES_NHG_ACTIVE;
902 kernel_del_mac_nhg(es->nhg_id);
903 }
904 }
905
906 /* XXX - update remote macs associated with the ES */
907}
908
909static void zebra_evpn_nh_add(struct zebra_evpn_es_vtep *es_vtep)
910{
911 if (es_vtep->nh_id)
912 return;
913
914 es_vtep->nh_id = zebra_evpn_nhid_alloc(false);
915
916 if (!es_vtep->nh_id)
917 return;
918
919 if (IS_ZEBRA_DEBUG_EVPN_MH_NH)
920 zlog_debug("es %s vtep %s nh 0x%x add",
921 es_vtep->es->esi_str,
922 inet_ntoa(es_vtep->vtep_ip), es_vtep->nh_id);
923 /* install the NH */
924 kernel_upd_mac_nh(es_vtep->nh_id, es_vtep->vtep_ip);
925 /* add the NH to the parent NHG */
926 zebra_evpn_nhg_update(es_vtep->es);
927}
928
929static void zebra_evpn_nh_del(struct zebra_evpn_es_vtep *es_vtep)
930{
931 uint32_t nh_id;
932
933 if (!es_vtep->nh_id)
934 return;
935
936 if (IS_ZEBRA_DEBUG_EVPN_MH_NH)
937 zlog_debug("es %s vtep %s nh 0x%x del",
938 es_vtep->es->esi_str,
939 inet_ntoa(es_vtep->vtep_ip), es_vtep->nh_id);
940
941 nh_id = es_vtep->nh_id;
942 es_vtep->nh_id = 0;
943
944 /* remove the NH from the parent NHG */
945 zebra_evpn_nhg_update(es_vtep->es);
946 /* uninstall the NH */
947 kernel_del_mac_nh(nh_id);
948 zebra_evpn_nhid_free(nh_id);
949
950}
951
952/*****************************************************************************/
953/* Ethernet Segment Management
954 * 1. Ethernet Segment is a collection of links attached to the same
955 * server (MHD) or switch (MHN)
956 * 2. An Ethernet Segment can span multiple PEs and is identified by the
957 * 10-byte ES-ID.
958 * 3. Zebra manages the local ESI configuration.
959 * 4. It also maintains the aliasing that maps an ESI (local or remote)
960 * to one or more PEs/VTEPs.
961 * 5. remote ESs are added by BGP (on rxing EAD Type-1 routes)
962 */
963/* A list of remote VTEPs is maintained for each ES. This list includes -
964 * 1. VTEPs for which we have imported the ESR i.e. ES-peers
965 * 2. VTEPs that have an "active" ES-EVI VTEP i.e. EAD-per-ES and EAD-per-EVI
87d76d54 966 * have been imported into one or more EVPNs
ce5160c0
AK
967 */
968static int zebra_evpn_es_vtep_cmp(void *p1, void *p2)
969{
970 const struct zebra_evpn_es_vtep *es_vtep1 = p1;
971 const struct zebra_evpn_es_vtep *es_vtep2 = p2;
972
973 return es_vtep1->vtep_ip.s_addr - es_vtep2->vtep_ip.s_addr;
974}
975
976static struct zebra_evpn_es_vtep *zebra_evpn_es_vtep_new(
977 struct zebra_evpn_es *es, struct in_addr vtep_ip)
978{
979 struct zebra_evpn_es_vtep *es_vtep;
980
981 es_vtep = XCALLOC(MTYPE_ZES_VTEP, sizeof(*es_vtep));
982
983 es_vtep->es = es;
984 es_vtep->vtep_ip.s_addr = vtep_ip.s_addr;
985 listnode_init(&es_vtep->es_listnode, es_vtep);
986 listnode_add_sort(es->es_vtep_list, &es_vtep->es_listnode);
987
988 return es_vtep;
989}
990
991static void zebra_evpn_es_vtep_free(struct zebra_evpn_es_vtep *es_vtep)
992{
993 struct zebra_evpn_es *es = es_vtep->es;
994
995 list_delete_node(es->es_vtep_list, &es_vtep->es_listnode);
996 /* update the L2-NHG associated with the ES */
997 zebra_evpn_nh_del(es_vtep);
998 XFREE(MTYPE_ZES_VTEP, es_vtep);
999}
1000
1001
1002/* check if VTEP is already part of the list */
1003static struct zebra_evpn_es_vtep *zebra_evpn_es_vtep_find(
1004 struct zebra_evpn_es *es, struct in_addr vtep_ip)
1005{
1006 struct listnode *node = NULL;
1007 struct zebra_evpn_es_vtep *es_vtep;
1008
1009 for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
1010 if (es_vtep->vtep_ip.s_addr == vtep_ip.s_addr)
1011 return es_vtep;
1012 }
1013 return NULL;
1014}
1015
1016static void zebra_evpn_es_vtep_add(struct zebra_evpn_es *es,
1017 struct in_addr vtep_ip)
1018{
1019 struct zebra_evpn_es_vtep *es_vtep;
1020
1021 es_vtep = zebra_evpn_es_vtep_find(es, vtep_ip);
1022
1023 if (!es_vtep) {
1024 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1025 zlog_debug("es %s vtep %s add",
1026 es->esi_str, inet_ntoa(vtep_ip));
1027 es_vtep = zebra_evpn_es_vtep_new(es, vtep_ip);
1028 /* update the L2-NHG associated with the ES */
1029 zebra_evpn_nh_add(es_vtep);
1030 }
1031}
1032
1033static void zebra_evpn_es_vtep_del(struct zebra_evpn_es *es,
1034 struct in_addr vtep_ip)
1035{
1036 struct zebra_evpn_es_vtep *es_vtep;
1037
1038 es_vtep = zebra_evpn_es_vtep_find(es, vtep_ip);
1039
1040 if (es_vtep) {
1041 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1042 zlog_debug("es %s vtep %s del",
1043 es->esi_str, inet_ntoa(vtep_ip));
1044 zebra_evpn_es_vtep_free(es_vtep);
1045 }
1046}
1047
1048/* compare ES-IDs for the global ES RB tree */
1049static int zebra_es_rb_cmp(const struct zebra_evpn_es *es1,
1050 const struct zebra_evpn_es *es2)
1051{
1052 return memcmp(&es1->esi, &es2->esi, ESI_BYTES);
1053}
1054RB_GENERATE(zebra_es_rb_head, zebra_evpn_es, rb_node, zebra_es_rb_cmp);
1055
1056/* Lookup ES */
1057struct zebra_evpn_es *zebra_evpn_es_find(esi_t *esi)
1058{
1059 struct zebra_evpn_es tmp;
1060
1061 memcpy(&tmp.esi, esi, sizeof(esi_t));
1062 return RB_FIND(zebra_es_rb_head, &zmh_info->es_rb_tree, &tmp);
1063}
1064
1065/* A new local es is created when a local-es-id and sysmac is configured
1066 * against an interface.
1067 */
1068static struct zebra_evpn_es *zebra_evpn_es_new(esi_t *esi)
1069{
1070 struct zebra_evpn_es *es;
1071
1072 es = XCALLOC(MTYPE_ZES, sizeof(struct zebra_evpn_es));
1073
1074 /* fill in ESI */
1075 memcpy(&es->esi, esi, sizeof(esi_t));
1076 esi_to_str(&es->esi, es->esi_str, sizeof(es->esi_str));
1077
1078 /* Add to rb_tree */
1079 if (RB_INSERT(zebra_es_rb_head, &zmh_info->es_rb_tree, es)) {
1080 XFREE(MTYPE_ZES, es);
1081 return NULL;
1082 }
1083
1084 /* Initialise the ES-EVI list */
1085 es->es_evi_list = list_new();
1086 listset_app_node_mem(es->es_evi_list);
1087
1088 /* Initialise the VTEP list */
1089 es->es_vtep_list = list_new();
1090 listset_app_node_mem(es->es_vtep_list);
1091 es->es_vtep_list->cmp = zebra_evpn_es_vtep_cmp;
1092
b169fd6f
AK
1093 /* mac entries associated with the ES */
1094 es->mac_list = list_new();
1095 listset_app_node_mem(es->mac_list);
1096
ce5160c0
AK
1097 /* reserve a NHG */
1098 es->nhg_id = zebra_evpn_nhid_alloc(true);
1099
1100 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1101 zlog_debug("es %s nhg 0x%x new", es->esi_str, es->nhg_id);
1102
1103 return es;
1104}
1105
1106/* Free a given ES -
1107 * This just frees appropriate memory, caller should have taken other
1108 * needed actions.
1109 */
b169fd6f 1110static struct zebra_evpn_es *zebra_evpn_es_free(struct zebra_evpn_es *es)
ce5160c0
AK
1111{
1112 /* If the ES has a local or remote reference it cannot be freed.
1113 * Free is also prevented if there are MAC entries referencing
1114 * it.
1115 */
1116 if ((es->flags & (ZEBRA_EVPNES_LOCAL | ZEBRA_EVPNES_REMOTE)) ||
b169fd6f
AK
1117 listcount(es->mac_list))
1118 return es;
ce5160c0
AK
1119
1120 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1121 zlog_debug("es %s free", es->esi_str);
1122
1123 /* If the NHG is still installed uninstall it and free the id */
1124 if (es->flags & ZEBRA_EVPNES_NHG_ACTIVE) {
1125 es->flags &= ~ZEBRA_EVPNES_NHG_ACTIVE;
1126 kernel_del_mac_nhg(es->nhg_id);
1127 }
1128 zebra_evpn_nhid_free(es->nhg_id);
1129
1130 /* cleanup resources maintained against the ES */
1131 list_delete(&es->es_evi_list);
1132 list_delete(&es->es_vtep_list);
b169fd6f 1133 list_delete(&es->mac_list);
ce5160c0
AK
1134
1135 /* remove from the VNI-ESI rb tree */
1136 RB_REMOVE(zebra_es_rb_head, &zmh_info->es_rb_tree, es);
1137
1138 XFREE(MTYPE_ZES, es);
b169fd6f
AK
1139
1140 return NULL;
ce5160c0
AK
1141}
1142
1143/* Inform BGP about local ES addition */
1144static int zebra_evpn_es_send_add_to_client(struct zebra_evpn_es *es)
1145{
1146 struct zserv *client;
1147 struct stream *s;
1148 uint8_t oper_up;
1149
1150 client = zserv_find_client(ZEBRA_ROUTE_BGP, 0);
1151 /* BGP may not be running. */
1152 if (!client)
1153 return 0;
1154
1155 s = stream_new(ZEBRA_MAX_PACKET_SIZ);
1156
1157 zclient_create_header(s, ZEBRA_LOCAL_ES_ADD, zebra_vrf_get_evpn_id());
1158 stream_put(s, &es->esi, sizeof(esi_t));
1159 stream_put_ipv4(s, zmh_info->es_originator_ip.s_addr);
1160 oper_up = !!(es->flags & ZEBRA_EVPNES_OPER_UP);
1161 stream_putc(s, oper_up);
1162
1163 /* Write packet size. */
1164 stream_putw_at(s, 0, stream_get_endp(s));
1165
1166 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1167 zlog_debug("send add local es %s %s to %s",
1168 es->esi_str,
1169 inet_ntoa(zmh_info->es_originator_ip),
1170 zebra_route_string(client->proto));
1171
1172 client->local_es_add_cnt++;
1173 return zserv_send_message(client, s);
1174}
1175
1176/* Inform BGP about local ES deletion */
1177static int zebra_evpn_es_send_del_to_client(struct zebra_evpn_es *es)
1178{
1179 struct zserv *client;
1180 struct stream *s;
1181
1182 client = zserv_find_client(ZEBRA_ROUTE_BGP, 0);
1183 /* BGP may not be running. */
1184 if (!client)
1185 return 0;
1186
1187 s = stream_new(ZEBRA_MAX_PACKET_SIZ);
1188 stream_reset(s);
1189
1190 zclient_create_header(s, ZEBRA_LOCAL_ES_DEL, zebra_vrf_get_evpn_id());
1191 stream_put(s, &es->esi, sizeof(esi_t));
1192
1193 /* Write packet size. */
1194 stream_putw_at(s, 0, stream_get_endp(s));
1195
1196 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1197 zlog_debug("send del local es %s to %s", es->esi_str,
1198 zebra_route_string(client->proto));
1199
1200 client->local_es_del_cnt++;
1201 return zserv_send_message(client, s);
1202}
1203
1204/* XXX - call any time ZEBRA_EVPNES_LOCAL gets set or cleared */
1205static void zebra_evpn_es_re_eval_send_to_client(struct zebra_evpn_es *es,
1206 bool es_evi_re_reval)
1207{
1208 bool old_ready;
1209 bool new_ready;
1210 struct listnode *node;
1211 struct zebra_evpn_es_evi *es_evi;
1212
1213 old_ready = !!(es->flags & ZEBRA_EVPNES_READY_FOR_BGP);
1214
1215 if ((es->flags & ZEBRA_EVPNES_LOCAL) &&
1216 zmh_info->es_originator_ip.s_addr)
1217 es->flags |= ZEBRA_EVPNES_READY_FOR_BGP;
1218 else
1219 es->flags &= ~ZEBRA_EVPNES_READY_FOR_BGP;
1220
1221 new_ready = !!(es->flags & ZEBRA_EVPNES_READY_FOR_BGP);
1222 if (old_ready == new_ready)
1223 return;
1224
1225 if (new_ready)
1226 zebra_evpn_es_send_add_to_client(es);
1227 else
1228 zebra_evpn_es_send_del_to_client(es);
1229
1230 /* re-eval associated EVIs */
1231 if (es_evi_re_reval) {
1232 for (ALL_LIST_ELEMENTS_RO(es->es_evi_list, node, es_evi)) {
1233 if (!(es_evi->flags & ZEBRA_EVPNES_EVI_LOCAL))
1234 continue;
1235 zebra_evpn_es_evi_re_eval_send_to_client(es_evi);
1236 }
1237 }
1238}
1239
1240void zebra_evpn_es_send_all_to_client(bool add)
1241{
1242 struct listnode *es_node;
1243 struct listnode *evi_node;
1244 struct zebra_evpn_es *es;
1245 struct zebra_evpn_es_evi *es_evi;
1246
1247 if (!zmh_info)
1248 return;
1249
1250 for (ALL_LIST_ELEMENTS_RO(zmh_info->local_es_list, es_node, es)) {
1251 if (es->flags & ZEBRA_EVPNES_READY_FOR_BGP) {
1252 if (add)
1253 zebra_evpn_es_send_add_to_client(es);
1254 for (ALL_LIST_ELEMENTS_RO(es->es_evi_list,
1255 evi_node, es_evi)) {
1256 if (!(es_evi->flags &
1257 ZEBRA_EVPNES_EVI_READY_FOR_BGP))
1258 continue;
1259
1260 if (add)
1261 zebra_evpn_es_evi_send_to_client(
87d76d54 1262 es, es_evi->zevpn,
ce5160c0
AK
1263 true /* add */);
1264 else
1265 zebra_evpn_es_evi_send_to_client(
87d76d54 1266 es, es_evi->zevpn,
ce5160c0
AK
1267 false /* add */);
1268 }
1269 if (!add)
1270 zebra_evpn_es_send_del_to_client(es);
1271 }
1272 }
1273}
1274
1275/* walk the vlan bitmap associated with the zif and create or delete
1276 * es_evis for all vlans associated with a VNI.
1277 * XXX: This API is really expensive. optimize later if possible.
1278 */
1279static void zebra_evpn_es_setup_evis(struct zebra_evpn_es *es)
1280{
1281 struct zebra_if *zif = es->zif;
1282 uint16_t vid;
1283 struct zebra_evpn_access_bd *acc_bd;
1284
1285
1286 bf_for_each_set_bit(zif->vlan_bitmap, vid, IF_VLAN_BITMAP_MAX) {
1287 acc_bd = zebra_evpn_acc_vl_find(vid);
87d76d54
PR
1288 if (acc_bd->zevpn)
1289 zebra_evpn_local_es_evi_add(es, acc_bd->zevpn);
ce5160c0
AK
1290 }
1291}
1292
b169fd6f
AK
1293static void zebra_evpn_es_local_mac_update(struct zebra_evpn_es *es,
1294 bool force_clear_static)
1295{
1296 zebra_mac_t *mac;
1297 struct listnode *node;
1298
1299 for (ALL_LIST_ELEMENTS_RO(es->mac_list, node, mac)) {
1300 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE)) {
b2998086
PR
1301 zebra_evpn_sync_mac_dp_install(
1302 mac, false /* set_inactive */,
1303 force_clear_static, __func__);
b169fd6f
AK
1304 }
1305 }
1306}
1307
ce5160c0
AK
1308static void zebra_evpn_es_local_info_set(struct zebra_evpn_es *es,
1309 struct zebra_if *zif)
1310{
1311 if (es->flags & ZEBRA_EVPNES_LOCAL)
1312 return;
1313
1314 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1315 zlog_debug("local es %s add; nhg 0x%x if %s",
1316 es->esi_str, es->nhg_id, zif->ifp->name);
1317
1318 es->flags |= ZEBRA_EVPNES_LOCAL;
1319 listnode_init(&es->local_es_listnode, es);
1320 listnode_add(zmh_info->local_es_list, &es->local_es_listnode);
1321
1322 /* attach es to interface */
1323 zif->es_info.es = es;
1324
1325 /* attach interface to es */
1326 es->zif = zif;
1327 if (if_is_operative(zif->ifp))
1328 es->flags |= ZEBRA_EVPNES_OPER_UP;
1329
1330 /* setup base-vni if one doesn't already exist; the ES will get sent
1331 * to BGP as a part of that process
1332 */
87d76d54
PR
1333 if (!zmh_info->es_base_evpn)
1334 zebra_evpn_es_get_one_base_evpn();
ce5160c0
AK
1335 else
1336 /* send notification to bgp */
1337 zebra_evpn_es_re_eval_send_to_client(es,
1338 false /* es_evi_re_reval */);
1339
1340 /* Setup ES-EVIs for all VxLAN stretched VLANs associated with
1341 * the zif
1342 */
1343 zebra_evpn_es_setup_evis(es);
b169fd6f
AK
1344 /* if there any local macs referring to the ES as dest we
1345 * need to set the static reference on them if the MAC is
1346 * synced from an ES peer
1347 */
1348 zebra_evpn_es_local_mac_update(es,
1349 false /* force_clear_static */);
ce5160c0
AK
1350}
1351
1352static void zebra_evpn_es_local_info_clear(struct zebra_evpn_es *es)
1353{
1354 struct zebra_if *zif;
1355
1356 if (!(es->flags & ZEBRA_EVPNES_LOCAL))
1357 return;
1358
1359 es->flags &= ~ZEBRA_EVPNES_LOCAL;
b169fd6f
AK
1360 /* if there any local macs referring to the ES as dest we
1361 * need to clear the static reference on them
1362 */
1363 zebra_evpn_es_local_mac_update(es,
1364 true /* force_clear_static */);
1365
ce5160c0
AK
1366 /* clear the es from the parent interface */
1367 zif = es->zif;
1368 zif->es_info.es = NULL;
1369 es->zif = NULL;
1370
1371 /* remove from the ES list */
1372 list_delete_node(zmh_info->local_es_list, &es->local_es_listnode);
1373
1374 /* free up the ES if there is no remote reference */
1375 zebra_evpn_es_free(es);
1376}
1377
1378/* Delete an ethernet segment and inform BGP */
1379static void zebra_evpn_local_es_del(struct zebra_evpn_es *es)
1380{
1381 struct zebra_evpn_es_evi *es_evi;
1382 struct listnode *node = NULL;
1383 struct listnode *nnode = NULL;
1384 struct zebra_if *zif;
1385
1386 if (!CHECK_FLAG(es->flags, ZEBRA_EVPNES_LOCAL))
1387 return;
1388
1389 if (IS_ZEBRA_DEBUG_EVPN_MH_ES) {
1390 zif = es->zif;
1391 zlog_debug("local es %s del; nhg 0x%x if %s",
1392 es->esi_str, es->nhg_id,
1393 zif ? zif->ifp->name : "-");
1394 }
1395
1396 /* remove all ES-EVIs associated with the ES */
1397 for (ALL_LIST_ELEMENTS(es->es_evi_list, node, nnode, es_evi))
1398 zebra_evpn_local_es_evi_do_del(es_evi);
1399
1400 /* send a del if the ES had been sent to BGP earlier */
1401 if (es->flags & ZEBRA_EVPNES_READY_FOR_BGP)
1402 zebra_evpn_es_send_del_to_client(es);
1403
1404 zebra_evpn_es_local_info_clear(es);
1405}
1406
1407/* eval remote info associated with the ES */
1408static void zebra_evpn_es_remote_info_re_eval(struct zebra_evpn_es *es)
1409{
1410 /* if there are remote VTEPs the ES-EVI is classified as "remote" */
1411 if (listcount(es->es_vtep_list)) {
1412 if (!(es->flags & ZEBRA_EVPNES_REMOTE)) {
1413 es->flags |= ZEBRA_EVPNES_REMOTE;
1414 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1415 zlog_debug("remote es %s add; nhg 0x%x",
1416 es->esi_str, es->nhg_id);
1417 }
1418 } else {
1419 if (es->flags & ZEBRA_EVPNES_REMOTE) {
1420 es->flags &= ~ZEBRA_EVPNES_REMOTE;
1421 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1422 zlog_debug("remote es %s del; nhg 0x%x",
1423 es->esi_str, es->nhg_id);
1424 zebra_evpn_es_free(es);
1425 }
1426 }
1427}
1428
1429/* A new local es is created when a local-es-id and sysmac is configured
1430 * against an interface.
1431 */
1432static int zebra_evpn_local_es_update(struct zebra_if *zif, uint32_t lid,
1433 struct ethaddr *sysmac)
1434{
1435 struct zebra_evpn_es *old_es = zif->es_info.es;
1436 struct zebra_evpn_es *es;
1437 esi_t esi;
1438 int offset = 0;
1439 int field_bytes = 0;
1440
1441 /* Complete config of the ES-ID bootstraps the ES */
1442 if (!lid || is_zero_mac(sysmac)) {
1443 /* if in ES is attached to zif delete it */
1444 if (old_es)
1445 zebra_evpn_local_es_del(old_es);
1446 return 0;
1447 }
1448
1449 /* build 10-byte type-3-ESI -
1450 * Type(1-byte), MAC(6-bytes), ES-LID (3-bytes)
1451 */
1452 field_bytes = 1;
1453 esi.val[offset] = ESI_TYPE_MAC;
1454 offset += field_bytes;
1455
1456 field_bytes = ETH_ALEN;
1457 memcpy(&esi.val[offset], (uint8_t *)sysmac, field_bytes);
1458 offset += field_bytes;
1459
1460 esi.val[offset++] = (uint8_t)(lid >> 16);
1461 esi.val[offset++] = (uint8_t)(lid >> 8);
1462 esi.val[offset++] = (uint8_t)lid;
1463
1464 if (old_es && !memcmp(&old_es->esi, &esi, sizeof(esi_t)))
1465 /* dup - nothing to be done */
1466 return 0;
1467
1468 /* release the old_es against the zif */
1469 if (old_es)
1470 zebra_evpn_local_es_del(old_es);
1471
1472 es = zebra_evpn_es_find(&esi);
1473 if (es) {
1474 /* if it exists against another interface flag an error */
1475 if (es->zif && es->zif != zif)
1476 return -1;
1477 } else {
1478 /* create new es */
1479 es = zebra_evpn_es_new(&esi);
1480 }
1481
1482 zebra_evpn_es_local_info_set(es, zif);
1483
1484 return 0;
1485}
1486
1487static int zebra_evpn_remote_es_del(esi_t *esi, struct in_addr vtep_ip)
1488{
1489 char buf[ESI_STR_LEN];
1490 struct zebra_evpn_es *es;
1491
1492 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1493 zlog_debug("remote es %s vtep %s del",
1494 esi_to_str(esi, buf, sizeof(buf)),
1495 inet_ntoa(vtep_ip));
1496
1497 es = zebra_evpn_es_find(esi);
1498 if (!es) {
1499 /* XXX - error log */
1500 return -1;
1501 }
1502
1503 zebra_evpn_es_vtep_del(es, vtep_ip);
1504 zebra_evpn_es_remote_info_re_eval(es);
1505
1506 return 0;
1507}
1508
1509/* force delete a remote ES on the way down */
1510static void zebra_evpn_remote_es_flush(struct zebra_evpn_es *es)
1511{
1512 struct zebra_evpn_es_vtep *es_vtep;
1513 struct listnode *node;
1514 struct listnode *nnode;
1515
1516 for (ALL_LIST_ELEMENTS(es->es_vtep_list, node, nnode, es_vtep)) {
1517 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1518 zlog_debug("es %s vtep %s flush",
1519 es->esi_str,
1520 inet_ntoa(es_vtep->vtep_ip));
1521 zebra_evpn_es_vtep_free(es_vtep);
1522 zebra_evpn_es_remote_info_re_eval(es);
1523 }
1524}
1525
1526static int zebra_evpn_remote_es_add(esi_t *esi, struct in_addr vtep_ip)
1527{
1528 char buf[ESI_STR_LEN];
1529 struct zebra_evpn_es *es;
1530
1531 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1532 zlog_debug("remote es %s vtep %s add",
1533 esi_to_str(esi, buf, sizeof(buf)),
1534 inet_ntoa(vtep_ip));
1535
1536 es = zebra_evpn_es_find(esi);
1537 if (!es) {
1538 es = zebra_evpn_es_new(esi);
1539 if (!es) {
1540 /* XXX - error log */
1541 return -1;
1542 }
1543 }
1544
1545 zebra_evpn_es_vtep_add(es, vtep_ip);
1546 zebra_evpn_es_remote_info_re_eval(es);
1547
1548 return 0;
1549}
1550
1551void zebra_evpn_proc_remote_es(ZAPI_HANDLER_ARGS)
1552{
1553 struct stream *s;
1554 struct in_addr vtep_ip;
1555 esi_t esi;
1556
1557 if (!is_evpn_enabled()) {
1558 zlog_debug(
1559 "%s: EVPN not enabled yet we received a es_add zapi call",
1560 __PRETTY_FUNCTION__);
1561 return;
1562 }
1563
1564 memset(&esi, 0, sizeof(esi_t));
1565 s = msg;
1566
1567 stream_get(&esi, s, sizeof(esi_t));
1568 vtep_ip.s_addr = stream_get_ipv4(s);
1569
1570 if (hdr->command == ZEBRA_REMOTE_ES_VTEP_ADD)
1571 zebra_evpn_remote_es_add(&esi, vtep_ip);
1572 else
1573 zebra_evpn_remote_es_del(&esi, vtep_ip);
1574}
1575
1576void zebra_evpn_es_mac_deref_entry(zebra_mac_t *mac)
1577{
1578 struct zebra_evpn_es *es = mac->es;
1579
1580 mac->es = NULL;
b169fd6f 1581 if (!es)
ce5160c0
AK
1582 return;
1583
b169fd6f
AK
1584 list_delete_node(es->mac_list, &mac->es_listnode);
1585 if (!listcount(es->mac_list))
ce5160c0
AK
1586 zebra_evpn_es_free(es);
1587}
1588
1589/* Associate a MAC entry with a local or remote ES. Returns false if there
1590 * was no ES change.
1591 */
1592bool zebra_evpn_es_mac_ref_entry(zebra_mac_t *mac, struct zebra_evpn_es *es)
1593{
1594 if (mac->es == es)
1595 return false;
1596
1597 if (mac->es)
1598 zebra_evpn_es_mac_deref_entry(mac);
1599
1600 if (!es)
1601 return true;
1602
1603 mac->es = es;
b169fd6f
AK
1604 listnode_init(&mac->es_listnode, mac);
1605 listnode_add(es->mac_list, &mac->es_listnode);
1606
ce5160c0
AK
1607 return true;
1608}
1609
b169fd6f 1610bool zebra_evpn_es_mac_ref(zebra_mac_t *mac, esi_t *esi)
ce5160c0
AK
1611{
1612 struct zebra_evpn_es *es;
1613
1614 es = zebra_evpn_es_find(esi);
1615 if (!es) {
1616 es = zebra_evpn_es_new(esi);
1617 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1618 zlog_debug("auto es %s add on mac ref", es->esi_str);
1619 }
1620
b169fd6f 1621 return zebra_evpn_es_mac_ref_entry(mac, es);
ce5160c0
AK
1622}
1623
1624/* Inform BGP about local ES-EVI add or del */
1625static int zebra_evpn_es_evi_send_to_client(struct zebra_evpn_es *es,
87d76d54 1626 zebra_evpn_t *zevpn, bool add)
ce5160c0
AK
1627{
1628 struct zserv *client;
1629 struct stream *s;
1630
1631 client = zserv_find_client(ZEBRA_ROUTE_BGP, 0);
1632 /* BGP may not be running. */
1633 if (!client)
1634 return 0;
1635
1636 s = stream_new(ZEBRA_MAX_PACKET_SIZ);
1637
1638 zclient_create_header(s,
1639 add ? ZEBRA_LOCAL_ES_EVI_ADD : ZEBRA_LOCAL_ES_EVI_DEL,
1640 zebra_vrf_get_evpn_id());
1641 stream_put(s, &es->esi, sizeof(esi_t));
87d76d54 1642 stream_putl(s, zevpn->vni);
ce5160c0
AK
1643
1644 /* Write packet size. */
1645 stream_putw_at(s, 0, stream_get_endp(s));
1646
1647 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1648 zlog_debug("send %s local es %s evi %u to %s",
1649 add ? "add" : "del",
87d76d54 1650 es->esi_str, zevpn->vni,
ce5160c0
AK
1651 zebra_route_string(client->proto));
1652
1653 client->local_es_add_cnt++;
1654 return zserv_send_message(client, s);
1655}
1656
1657/* sysmac part of a local ESI has changed */
1658static int zebra_evpn_es_sys_mac_update(struct zebra_if *zif,
1659 struct ethaddr *sysmac)
1660{
1661 int rv;
1662
1663 rv = zebra_evpn_local_es_update(zif, zif->es_info.lid, sysmac);
1664 if (!rv)
1665 memcpy(&zif->es_info.sysmac, sysmac, sizeof(struct ethaddr));
1666
1667 return rv;
1668}
1669
1670/* local-ID part of ESI has changed */
1671static int zebra_evpn_es_lid_update(struct zebra_if *zif, uint32_t lid)
1672{
1673 int rv;
1674
1675 rv = zebra_evpn_local_es_update(zif, lid, &zif->es_info.sysmac);
1676 if (!rv)
1677 zif->es_info.lid = lid;
1678
1679 return rv;
1680}
1681
1682void zebra_evpn_es_cleanup(void)
1683{
1684 struct zebra_evpn_es *es;
1685 struct zebra_evpn_es *es_next;
1686
1687 RB_FOREACH_SAFE(es, zebra_es_rb_head,
1688 &zmh_info->es_rb_tree, es_next) {
1689 zebra_evpn_local_es_del(es);
1690 zebra_evpn_remote_es_flush(es);
1691 }
1692}
1693
1694/* Only certain types of access ports can be setup as an Ethernet Segment */
1695bool zebra_evpn_is_if_es_capable(struct zebra_if *zif)
1696{
1697 if (zif->zif_type == ZEBRA_IF_BOND)
1698 return true;
1699
1700 /* XXX: allow swpX i.e. a regular ethernet port to be an ES link too */
1701 return false;
1702}
1703
1704void zebra_evpn_if_es_print(struct vty *vty, struct zebra_if *zif)
1705{
1706 char buf[ETHER_ADDR_STRLEN];
1707
1708 if (zif->es_info.lid || !is_zero_mac(&zif->es_info.sysmac))
1709 vty_out(vty, " EVPN MH: ES id %u ES sysmac %s\n",
1710 zif->es_info.lid,
1711 prefix_mac2str(&zif->es_info.sysmac,
1712 buf, sizeof(buf)));
1713}
1714
1715void zebra_evpn_es_if_oper_state_change(struct zebra_if *zif, bool up)
1716{
1717 struct zebra_evpn_es *es = zif->es_info.es;
1718 bool old_up = !!(es->flags & ZEBRA_EVPNES_OPER_UP);
1719
1720 if (old_up == up)
1721 return;
1722
1723 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1724 zlog_debug("es %s state changed to %s ",
1725 es->esi_str,
1726 up ? "up" : "down");
1727 if (up)
1728 es->flags |= ZEBRA_EVPNES_OPER_UP;
1729 else
1730 es->flags &= ~ZEBRA_EVPNES_OPER_UP;
1731
1732 /* inform BGP of the ES oper state change */
1733 if (es->flags & ZEBRA_EVPNES_READY_FOR_BGP)
1734 zebra_evpn_es_send_add_to_client(es);
1735}
1736
9e0c2fd1
AK
1737static char *zebra_evpn_es_vtep_str(char *vtep_str, struct zebra_evpn_es *es,
1738 uint8_t vtep_str_size)
ce5160c0
AK
1739{
1740 struct zebra_evpn_es_vtep *zvtep;
1741 struct listnode *node;
1742 bool first = true;
1743
1744 vtep_str[0] = '\0';
1745 for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, zvtep)) {
1746 if (first) {
1747 first = false;
9e0c2fd1
AK
1748 strlcat(vtep_str, inet_ntoa(zvtep->vtep_ip),
1749 vtep_str_size);
ce5160c0 1750 } else {
9e0c2fd1
AK
1751 strlcat(vtep_str, ",", vtep_str_size);
1752 strlcat(vtep_str, inet_ntoa(zvtep->vtep_ip),
1753 vtep_str_size);
ce5160c0
AK
1754 }
1755 }
1756 return vtep_str;
1757}
1758
1759static void zebra_evpn_es_show_entry(struct vty *vty,
1760 struct zebra_evpn_es *es, json_object *json)
1761{
1762 char type_str[4];
1763 char vtep_str[ES_VTEP_LIST_STR_SZ];
1764
1765 if (json) {
1766 /* XXX */
1767 } else {
1768 type_str[0] = '\0';
1769 if (es->flags & ZEBRA_EVPNES_LOCAL)
9e0c2fd1 1770 strlcat(type_str, "L", sizeof(type_str));
ce5160c0 1771 if (es->flags & ZEBRA_EVPNES_REMOTE)
9e0c2fd1 1772 strlcat(type_str, "R", sizeof(type_str));
ce5160c0 1773
9e0c2fd1 1774 zebra_evpn_es_vtep_str(vtep_str, es, sizeof(vtep_str));
ce5160c0
AK
1775
1776 vty_out(vty, "%-30s %-4s %-21s %s\n",
1777 es->esi_str, type_str,
1778 es->zif ? es->zif->ifp->name : "-",
1779 vtep_str);
1780 }
1781}
1782
1783static void zebra_evpn_es_show_entry_detail(struct vty *vty,
1784 struct zebra_evpn_es *es, json_object *json)
1785{
1786 char type_str[80];
1787 struct zebra_evpn_es_vtep *zvtep;
1788 struct listnode *node;
1789
1790 if (json) {
1791 /* XXX */
1792 } else {
1793 type_str[0] = '\0';
1794 if (es->flags & ZEBRA_EVPNES_LOCAL)
9e0c2fd1 1795 strlcat(type_str, "Local", sizeof(type_str));
ce5160c0 1796 if (es->flags & ZEBRA_EVPNES_REMOTE) {
9e0c2fd1
AK
1797 if (strnlen(type_str, sizeof(type_str)))
1798 strlcat(type_str, ",", sizeof(type_str));
1799 strlcat(type_str, "Remote", sizeof(type_str));
ce5160c0
AK
1800 }
1801
1802 vty_out(vty, "ESI: %s\n", es->esi_str);
1803 vty_out(vty, " Type: %s\n", type_str);
1804 vty_out(vty, " Interface: %s\n",
1805 (es->zif) ?
1806 es->zif->ifp->name : "-");
1807 vty_out(vty, " State: %s\n",
1808 (es->flags & ZEBRA_EVPNES_OPER_UP) ?
1809 "up" : "down");
1810 vty_out(vty, " Ready for BGP: %s\n",
1811 (es->flags & ZEBRA_EVPNES_READY_FOR_BGP) ?
1812 "yes" : "no");
1813 vty_out(vty, " VNI Count: %d\n", listcount(es->es_evi_list));
b169fd6f 1814 vty_out(vty, " MAC Count: %d\n", listcount(es->mac_list));
ce5160c0
AK
1815 vty_out(vty, " Nexthop group: 0x%x\n", es->nhg_id);
1816 vty_out(vty, " VTEPs:\n");
1817 for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, zvtep))
1818 vty_out(vty, " %s nh: 0x%x\n",
1819 inet_ntoa(zvtep->vtep_ip),
1820 zvtep->nh_id);
1821
1822 vty_out(vty, "\n");
1823 }
1824}
1825
1826void zebra_evpn_es_show(struct vty *vty, bool uj)
1827{
1828 struct zebra_evpn_es *es;
1829 json_object *json = NULL;
1830
1831 if (uj) {
1832 /* XXX */
1833 } else {
1834 vty_out(vty, "Type: L local, R remote\n");
1835 vty_out(vty, "%-30s %-4s %-21s %s\n",
1836 "ESI", "Type", "ES-IF", "VTEPs");
1837 }
1838
1839 RB_FOREACH(es, zebra_es_rb_head, &zmh_info->es_rb_tree)
1840 zebra_evpn_es_show_entry(vty, es, json);
1841}
1842
1843void zebra_evpn_es_show_detail(struct vty *vty, bool uj)
1844{
1845 struct zebra_evpn_es *es;
1846 json_object *json = NULL;
1847
1848 RB_FOREACH(es, zebra_es_rb_head, &zmh_info->es_rb_tree)
1849 zebra_evpn_es_show_entry_detail(vty, es, json);
1850}
1851
1852void zebra_evpn_es_show_esi(struct vty *vty, bool uj, esi_t *esi)
1853{
1854 struct zebra_evpn_es *es;
1855 char esi_str[ESI_STR_LEN];
1856 json_object *json = NULL;
1857
1858 es = zebra_evpn_es_find(esi);
1859
1860 if (!es) {
1861 esi_to_str(esi, esi_str, sizeof(esi_str));
1862 vty_out(vty, "ESI %s does not exist\n", esi_str);
1863 return;
1864 }
1865
1866 zebra_evpn_es_show_entry_detail(vty, es, json);
1867}
1868
1869int zebra_evpn_mh_if_write(struct vty *vty, struct interface *ifp)
1870{
1871 struct zebra_if *zif = ifp->info;
1872 char buf[ETHER_ADDR_STRLEN];
1873
1874 if (zif->es_info.lid)
1875 vty_out(vty, " evpn mh es-id %u\n", zif->es_info.lid);
1876
1877 if (!is_zero_mac(&zif->es_info.sysmac))
1878 vty_out(vty, " evpn mh es-sys-mac %s\n",
1879 prefix_mac2str(&zif->es_info.sysmac,
1880 buf, sizeof(buf)));
1881 return 0;
1882}
1883
1884#ifndef VTYSH_EXTRACT_PL
1885#include "zebra/zebra_evpn_mh_clippy.c"
1886#endif
1887/* CLI for setting up sysmac part of ESI on an access port */
1888DEFPY(zebra_evpn_es_sys_mac,
1889 zebra_evpn_es_sys_mac_cmd,
1890 "[no$no] evpn mh es-sys-mac [X:X:X:X:X:X$mac]",
1891 NO_STR
1892 "EVPN\n"
1893 EVPN_MH_VTY_STR
1894 "Ethernet segment system MAC\n"
1895 MAC_STR
1896)
1897{
1898 VTY_DECLVAR_CONTEXT(interface, ifp);
1899 struct zebra_if *zif;
1900 int ret = 0;
1901
1902 zif = ifp->info;
1903
1904 if (no) {
1905 static struct ethaddr zero_mac;
1906
1907 ret = zebra_evpn_es_sys_mac_update(zif, &zero_mac);
1908 if (ret == -1) {
1909 vty_out(vty, "%%Failed to clear ES sysmac\n");
1910 return CMD_WARNING;
1911 }
1912 } else {
1913
1914 if (!zebra_evpn_is_if_es_capable(zif)) {
1915 vty_out(vty,
1916 "%%ESI cannot be associated with this interface type\n");
1917 return CMD_WARNING;
1918 }
1919
1920 if (!mac || is_zero_mac(&mac->eth_addr)) {
1921 vty_out(vty, "%%ES sysmac value is invalid\n");
1922 return CMD_WARNING;
1923 }
1924
1925 ret = zebra_evpn_es_sys_mac_update(zif, &mac->eth_addr);
1926 if (ret == -1) {
1927 vty_out(vty, "%%ESI already exists on a different interface\n");
1928 return CMD_WARNING;
1929 }
1930 }
1931 return CMD_SUCCESS;
1932}
1933
1934/* CLI for setting up local-ID part of ESI on an access port */
1935DEFPY(zebra_evpn_es_id,
1936 zebra_evpn_es_id_cmd,
1937 "[no$no] evpn mh es-id [(1-16777215)$es_lid]",
1938 NO_STR
1939 "EVPN\n"
1940 EVPN_MH_VTY_STR
1941 "Ethernet segment local identifier\n"
1942 "ID\n"
1943)
1944{
1945 VTY_DECLVAR_CONTEXT(interface, ifp);
1946 struct zebra_if *zif;
1947 int ret;
1948
1949 zif = ifp->info;
1950
1951 if (no) {
1952 ret = zebra_evpn_es_lid_update(zif, 0);
1953 if (ret == -1) {
1954 vty_out(vty, "%%Failed to clear ES local id\n");
1955 return CMD_WARNING;
1956 }
1957 } else {
1958 if (!zebra_evpn_is_if_es_capable(zif)) {
1959 vty_out(vty,
1960 "%%ESI cannot be associated with this interface type\n");
1961 return CMD_WARNING;
1962 }
1963
1964 if (!es_lid) {
1965 vty_out(vty, "%%Specify local ES ID\n");
1966 return CMD_WARNING;
1967 }
1968 ret = zebra_evpn_es_lid_update(zif, es_lid);
1969 if (ret == -1) {
1970 vty_out(vty,
1971 "%%ESI already exists on a different interface\n");
1972 return CMD_WARNING;
1973 }
1974 }
1975 return CMD_SUCCESS;
1976}
1977
1978/*****************************************************************************/
1979/* A base L2-VNI is maintained to derive parameters such as ES originator-IP.
1980 * XXX: once single vxlan device model becomes available this will not be
1981 * necessary
1982 */
1983/* called when a new vni is added or becomes oper up or becomes a bridge port */
87d76d54 1984void zebra_evpn_es_set_base_evpn(zebra_evpn_t *zevpn)
ce5160c0
AK
1985{
1986 struct listnode *node;
1987 struct zebra_evpn_es *es;
1988
87d76d54
PR
1989 if (zmh_info->es_base_evpn) {
1990 if (zmh_info->es_base_evpn != zevpn) {
1991 /* unrelated EVPN; ignore it */
ce5160c0
AK
1992 return;
1993 }
1994 /* check if the local vtep-ip has changed */
1995 } else {
87d76d54
PR
1996 /* check if the EVPN can be used as base EVPN */
1997 if (!zebra_evpn_send_to_client_ok(zevpn))
ce5160c0
AK
1998 return;
1999
2000 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
2001 zlog_debug("es base vni set to %d",
87d76d54
PR
2002 zevpn->vni);
2003 zmh_info->es_base_evpn = zevpn;
ce5160c0
AK
2004 }
2005
2006 /* update local VTEP-IP */
2007 if (zmh_info->es_originator_ip.s_addr ==
87d76d54 2008 zmh_info->es_base_evpn->local_vtep_ip.s_addr)
ce5160c0
AK
2009 return;
2010
2011 zmh_info->es_originator_ip.s_addr =
87d76d54 2012 zmh_info->es_base_evpn->local_vtep_ip.s_addr;
ce5160c0
AK
2013
2014 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
2015 zlog_debug("es originator ip set to %s",
87d76d54 2016 inet_ntoa(zmh_info->es_base_evpn->local_vtep_ip));
ce5160c0
AK
2017
2018 /* if originator ip changes we need to update bgp */
2019 for (ALL_LIST_ELEMENTS_RO(zmh_info->local_es_list, node, es)) {
2020 if (es->flags & ZEBRA_EVPNES_READY_FOR_BGP)
2021 zebra_evpn_es_send_add_to_client(es);
2022 else
2023 zebra_evpn_es_re_eval_send_to_client(es,
2024 true /* es_evi_re_reval */);
2025 }
2026}
2027
2028/* called when a vni is removed or becomes oper down or is removed from a
2029 * bridge
2030 */
87d76d54 2031void zebra_evpn_es_clear_base_evpn(zebra_evpn_t *zevpn)
ce5160c0
AK
2032{
2033 struct listnode *node;
2034 struct zebra_evpn_es *es;
2035
87d76d54 2036 if (zmh_info->es_base_evpn != zevpn)
ce5160c0
AK
2037 return;
2038
87d76d54
PR
2039 zmh_info->es_base_evpn = NULL;
2040 /* lost current base EVPN; try to find a new one */
2041 zebra_evpn_es_get_one_base_evpn();
ce5160c0 2042
87d76d54
PR
2043 /* couldn't locate an eligible base evpn */
2044 if (!zmh_info->es_base_evpn && zmh_info->es_originator_ip.s_addr) {
ce5160c0
AK
2045 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
2046 zlog_debug("es originator ip cleared");
2047
2048 zmh_info->es_originator_ip.s_addr = 0;
2049 /* lost originator ip */
2050 for (ALL_LIST_ELEMENTS_RO(zmh_info->local_es_list, node, es)) {
2051 zebra_evpn_es_re_eval_send_to_client(es,
2052 true /* es_evi_re_reval */);
2053 }
2054 }
2055}
2056
2057/* Locate an "eligible" L2-VNI to follow */
87d76d54 2058static int zebra_evpn_es_get_one_base_evpn_cb(struct hash_bucket *b, void *data)
ce5160c0 2059{
87d76d54 2060 zebra_evpn_t *zevpn = b->data;
ce5160c0 2061
87d76d54 2062 zebra_evpn_es_set_base_evpn(zevpn);
ce5160c0 2063
87d76d54 2064 if (zmh_info->es_base_evpn)
ce5160c0
AK
2065 return HASHWALK_ABORT;
2066
2067 return HASHWALK_CONTINUE;
2068}
2069
87d76d54 2070/* locate a base_evpn to follow for the purposes of common params like
ce5160c0
AK
2071 * originator IP
2072 */
87d76d54 2073static void zebra_evpn_es_get_one_base_evpn(void)
ce5160c0
AK
2074{
2075 struct zebra_vrf *zvrf;
2076
2077 zvrf = zebra_vrf_get_evpn();
87d76d54 2078 hash_walk(zvrf->evpn_table, zebra_evpn_es_get_one_base_evpn_cb, NULL);
ce5160c0
AK
2079}
2080
2081/*****************************************************************************/
b169fd6f
AK
2082void zebra_evpn_mh_config_write(struct vty *vty)
2083{
2084 if (zmh_info->mac_hold_time != EVPN_MH_MAC_HOLD_TIME_DEF)
2085 vty_out(vty, "evpn mh mac-holdtime %ld\n",
2086 zmh_info->mac_hold_time);
2087
2088 if (zmh_info->neigh_hold_time != EVPN_MH_NEIGH_HOLD_TIME_DEF)
2089 vty_out(vty, "evpn mh neigh-holdtime %ld\n",
2090 zmh_info->neigh_hold_time);
2091}
2092
2093int zebra_evpn_mh_neigh_holdtime_update(struct vty *vty,
2094 uint32_t duration, bool set_default)
2095{
2096 if (set_default)
2097 zmh_info->neigh_hold_time = EVPN_MH_NEIGH_HOLD_TIME_DEF;
2098
2099 zmh_info->neigh_hold_time = duration;
2100
2101 return 0;
2102}
2103
2104int zebra_evpn_mh_mac_holdtime_update(struct vty *vty,
2105 uint32_t duration, bool set_default)
2106{
2107 if (set_default)
2108 duration = EVPN_MH_MAC_HOLD_TIME_DEF;
2109
2110 zmh_info->mac_hold_time = duration;
2111
2112 return 0;
2113}
2114
ce5160c0
AK
2115void zebra_evpn_interface_init(void)
2116{
2117 install_element(INTERFACE_NODE, &zebra_evpn_es_id_cmd);
2118 install_element(INTERFACE_NODE, &zebra_evpn_es_sys_mac_cmd);
2119}
2120
2121void zebra_evpn_mh_init(void)
2122{
2123 zrouter.mh_info = XCALLOC(MTYPE_ZMH_INFO, sizeof(*zrouter.mh_info));
2124
b169fd6f
AK
2125 zmh_info->mac_hold_time = EVPN_MH_MAC_HOLD_TIME_DEF;
2126 zmh_info->neigh_hold_time = EVPN_MH_NEIGH_HOLD_TIME_DEF;
ce5160c0
AK
2127 /* setup ES tables */
2128 RB_INIT(zebra_es_rb_head, &zmh_info->es_rb_tree);
2129 zmh_info->local_es_list = list_new();
2130 listset_app_node_mem(zmh_info->local_es_list);
2131
2132 bf_init(zmh_info->nh_id_bitmap, EVPN_NH_ID_MAX);
2133 bf_assign_zero_index(zmh_info->nh_id_bitmap);
2134
2135 /* setup broadcast domain tables */
2136 zmh_info->evpn_vlan_table = hash_create(zebra_evpn_acc_vl_hash_keymake,
2137 zebra_evpn_acc_vl_cmp, "access VLAN hash table");
2138}
2139
2140void zebra_evpn_mh_terminate(void)
2141{
2142 list_delete(&zmh_info->local_es_list);
2143
2144 hash_iterate(zmh_info->evpn_vlan_table,
2145 zebra_evpn_acc_vl_cleanup_all, NULL);
2146 hash_free(zmh_info->evpn_vlan_table);
2147}