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