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