]> git.proxmox.com Git - mirror_frr.git/blob - zebra/zebra_evpn_mac.c
zebra: Fix tracepoint changes for lttng
[mirror_frr.git] / zebra / zebra_evpn_mac.c
1 /*
2 * Zebra EVPN for VxLAN code
3 * Copyright (C) 2016, 2017 Cumulus Networks, Inc.
4 *
5 * This file is part of FRR.
6 *
7 * FRR is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2, or (at your option) any
10 * later version.
11 *
12 * FRR is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with FRR; see the file COPYING. If not, write to the Free
19 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 * 02111-1307, USA.
21 */
22
23 #include <zebra.h>
24
25 #include "hash.h"
26 #include "interface.h"
27 #include "jhash.h"
28 #include "memory.h"
29 #include "prefix.h"
30 #include "vlan.h"
31 #include "json.h"
32 #include "printfrr.h"
33
34 #include "zebra/zserv.h"
35 #include "zebra/debug.h"
36 #include "zebra/zebra_router.h"
37 #include "zebra/zebra_errors.h"
38 #include "zebra/zebra_vrf.h"
39 #include "zebra/zebra_evpn.h"
40 #include "zebra/zebra_evpn_mh.h"
41 #include "zebra/zebra_evpn_mac.h"
42 #include "zebra/zebra_evpn_neigh.h"
43
44 DEFINE_MTYPE_STATIC(ZEBRA, MAC, "EVPN MAC");
45
46 /*
47 * Return number of valid MACs in an EVPN's MAC hash table - all
48 * remote MACs and non-internal (auto) local MACs count.
49 */
50 uint32_t num_valid_macs(struct zebra_evpn *zevpn)
51 {
52 unsigned int i;
53 uint32_t num_macs = 0;
54 struct hash *hash;
55 struct hash_bucket *hb;
56 struct zebra_mac *mac;
57
58 hash = zevpn->mac_table;
59 if (!hash)
60 return num_macs;
61 for (i = 0; i < hash->size; i++) {
62 for (hb = hash->index[i]; hb; hb = hb->next) {
63 mac = (struct zebra_mac *)hb->data;
64 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
65 || CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)
66 || !CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO))
67 num_macs++;
68 }
69 }
70
71 return num_macs;
72 }
73
74 uint32_t num_dup_detected_macs(struct zebra_evpn *zevpn)
75 {
76 unsigned int i;
77 uint32_t num_macs = 0;
78 struct hash *hash;
79 struct hash_bucket *hb;
80 struct zebra_mac *mac;
81
82 hash = zevpn->mac_table;
83 if (!hash)
84 return num_macs;
85 for (i = 0; i < hash->size; i++) {
86 for (hb = hash->index[i]; hb; hb = hb->next) {
87 mac = (struct zebra_mac *)hb->data;
88 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
89 num_macs++;
90 }
91 }
92
93 return num_macs;
94 }
95
96 /* Setup mac_list against the access port. This is done when a mac uses
97 * the ifp as destination for the first time
98 */
99 static void zebra_evpn_mac_ifp_new(struct zebra_if *zif)
100 {
101 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
102 zlog_debug("MAC list created for ifp %s (%u)", zif->ifp->name,
103 zif->ifp->ifindex);
104
105 zif->mac_list = list_new();
106 listset_app_node_mem(zif->mac_list);
107 }
108
109 /* Unlink local mac from a destination access port */
110 static void zebra_evpn_mac_ifp_unlink(struct zebra_mac *zmac)
111 {
112 struct zebra_if *zif;
113 struct interface *ifp = zmac->ifp;
114
115 if (!ifp)
116 return;
117
118 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
119 zlog_debug("VNI %d MAC %pEA unlinked from ifp %s (%u)",
120 zmac->zevpn->vni,
121 &zmac->macaddr,
122 ifp->name, ifp->ifindex);
123
124 zif = ifp->info;
125 list_delete_node(zif->mac_list, &zmac->ifp_listnode);
126 zmac->ifp = NULL;
127 }
128
129 /* Free up the mac_list if any as a part of the interface del/cleanup */
130 void zebra_evpn_mac_ifp_del(struct interface *ifp)
131 {
132 struct zebra_if *zif = ifp->info;
133 struct listnode *node;
134 struct zebra_mac *zmac;
135
136 if (zif->mac_list) {
137 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
138 zlog_debug("MAC list deleted for ifp %s (%u)",
139 zif->ifp->name, zif->ifp->ifindex);
140
141 for (ALL_LIST_ELEMENTS_RO(zif->mac_list, node, zmac)) {
142 zebra_evpn_mac_ifp_unlink(zmac);
143 }
144 list_delete(&zif->mac_list);
145 }
146 }
147
148 /* Link local mac to destination access port. This is done only if the
149 * local mac is associated with a zero ESI i.e. single attach or lacp-bypass
150 * bridge port member
151 */
152 static void zebra_evpn_mac_ifp_link(struct zebra_mac *zmac,
153 struct interface *ifp)
154 {
155 struct zebra_if *zif;
156
157 if (!CHECK_FLAG(zmac->flags, ZEBRA_MAC_LOCAL))
158 return;
159
160 /* already linked to the destination */
161 if (zmac->ifp == ifp)
162 return;
163
164 /* unlink the mac from any old destination */
165 if (zmac->ifp)
166 zebra_evpn_mac_ifp_unlink(zmac);
167
168 if (!ifp)
169 return;
170
171 zif = ifp->info;
172 /* the interface mac_list is created on first mac link attempt */
173 if (!zif->mac_list)
174 zebra_evpn_mac_ifp_new(zif);
175
176 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
177 zlog_debug("VNI %d MAC %pEA linked to ifp %s (%u)",
178 zmac->zevpn->vni,
179 &zmac->macaddr,
180 ifp->name, ifp->ifindex);
181
182 zmac->ifp = ifp;
183 listnode_init(&zmac->ifp_listnode, zmac);
184 listnode_add(zif->mac_list, &zmac->ifp_listnode);
185 }
186
187 /* If the mac is a local mac clear links to destination access port */
188 void zebra_evpn_mac_clear_fwd_info(struct zebra_mac *zmac)
189 {
190 zebra_evpn_mac_ifp_unlink(zmac);
191 memset(&zmac->fwd_info, 0, sizeof(zmac->fwd_info));
192 }
193
194 /*
195 * Install remote MAC into the forwarding plane.
196 */
197 int zebra_evpn_rem_mac_install(struct zebra_evpn *zevpn, struct zebra_mac *mac,
198 bool was_static)
199 {
200 const struct zebra_if *zif, *br_zif;
201 const struct zebra_l2info_vxlan *vxl;
202 bool sticky;
203 enum zebra_dplane_result res;
204 const struct interface *br_ifp;
205 vlanid_t vid;
206 uint32_t nhg_id;
207 struct in_addr vtep_ip;
208
209 zif = zevpn->vxlan_if->info;
210 if (!zif)
211 return -1;
212
213 br_ifp = zif->brslave_info.br_if;
214 if (br_ifp == NULL)
215 return -1;
216
217 vxl = &zif->l2info.vxl;
218
219 sticky = !!CHECK_FLAG(mac->flags,
220 (ZEBRA_MAC_STICKY | ZEBRA_MAC_REMOTE_DEF_GW));
221
222 /* If nexthop group for the FDB entry is inactive (not programmed in
223 * the dataplane) the MAC entry cannot be installed
224 */
225 if (mac->es) {
226 if (!(mac->es->flags & ZEBRA_EVPNES_NHG_ACTIVE))
227 return -1;
228 nhg_id = mac->es->nhg_id;
229 vtep_ip.s_addr = 0;
230 } else {
231 nhg_id = 0;
232 vtep_ip = mac->fwd_info.r_vtep_ip;
233 }
234
235 br_zif = (const struct zebra_if *)(br_ifp->info);
236
237 if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif))
238 vid = vxl->access_vlan;
239 else
240 vid = 0;
241
242 res = dplane_rem_mac_add(zevpn->vxlan_if, br_ifp, vid, &mac->macaddr,
243 vtep_ip, sticky, nhg_id, was_static);
244 if (res != ZEBRA_DPLANE_REQUEST_FAILURE)
245 return 0;
246 else
247 return -1;
248 }
249
250 /*
251 * Uninstall remote MAC from the forwarding plane.
252 */
253 int zebra_evpn_rem_mac_uninstall(struct zebra_evpn *zevpn,
254 struct zebra_mac *mac, bool force)
255 {
256 const struct zebra_if *zif, *br_zif;
257 const struct zebra_l2info_vxlan *vxl;
258 struct in_addr vtep_ip;
259 const struct interface *ifp, *br_ifp;
260 vlanid_t vid;
261 enum zebra_dplane_result res;
262
263 /* If the MAC was not installed there is no need to uninstall it */
264 if (!force && mac->es && !(mac->es->flags & ZEBRA_EVPNES_NHG_ACTIVE))
265 return -1;
266
267 if (!zevpn->vxlan_if) {
268 if (IS_ZEBRA_DEBUG_VXLAN)
269 zlog_debug(
270 "VNI %u hash %p couldn't be uninstalled - no intf",
271 zevpn->vni, zevpn);
272 return -1;
273 }
274
275 zif = zevpn->vxlan_if->info;
276 if (!zif)
277 return -1;
278
279 br_ifp = zif->brslave_info.br_if;
280 if (br_ifp == NULL)
281 return -1;
282
283 vxl = &zif->l2info.vxl;
284
285 br_zif = (const struct zebra_if *)br_ifp->info;
286
287 if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif))
288 vid = vxl->access_vlan;
289 else
290 vid = 0;
291
292 ifp = zevpn->vxlan_if;
293 vtep_ip = mac->fwd_info.r_vtep_ip;
294
295 res = dplane_rem_mac_del(ifp, br_ifp, vid, &mac->macaddr, vtep_ip);
296 if (res != ZEBRA_DPLANE_REQUEST_FAILURE)
297 return 0;
298 else
299 return -1;
300 }
301
302 /*
303 * Decrement neighbor refcount of MAC; uninstall and free it if
304 * appropriate.
305 */
306 void zebra_evpn_deref_ip2mac(struct zebra_evpn *zevpn, struct zebra_mac *mac)
307 {
308 if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO))
309 return;
310
311 /* If all remote neighbors referencing a remote MAC go away,
312 * we need to uninstall the MAC.
313 */
314 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
315 && remote_neigh_count(mac) == 0) {
316 zebra_evpn_rem_mac_uninstall(zevpn, mac, false /*force*/);
317 zebra_evpn_es_mac_deref_entry(mac);
318 UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
319 }
320
321 /* If no references, delete the MAC. */
322 if (!zebra_evpn_mac_in_use(mac))
323 zebra_evpn_mac_del(zevpn, mac);
324 }
325
326 static void zebra_evpn_mac_get_access_info(struct zebra_mac *mac,
327 struct interface **p_ifp,
328 vlanid_t *vid)
329 {
330 /* if the mac is associated with an ES we must get the access
331 * info from the ES
332 */
333 if (mac->es) {
334 struct zebra_if *zif;
335
336 /* get the access port from the es */
337 *p_ifp = mac->es->zif ? mac->es->zif->ifp : NULL;
338 /* get the vlan from the EVPN */
339 if (mac->zevpn->vxlan_if) {
340 zif = mac->zevpn->vxlan_if->info;
341 *vid = zif->l2info.vxl.access_vlan;
342 } else {
343 *vid = 0;
344 }
345 } else {
346 struct zebra_ns *zns;
347
348 *vid = mac->fwd_info.local.vid;
349 zns = zebra_ns_lookup(mac->fwd_info.local.ns_id);
350 *p_ifp = if_lookup_by_index_per_ns(zns,
351 mac->fwd_info.local.ifindex);
352 }
353 }
354
355 #define MAC_BUF_SIZE 256
356 static char *zebra_evpn_zebra_mac_flag_dump(struct zebra_mac *mac, char *buf,
357 size_t len)
358 {
359 if (mac->flags == 0) {
360 snprintfrr(buf, len, "None ");
361 return buf;
362 }
363
364 snprintfrr(
365 buf, len, "%s%s%s%s%s%s%s%s%s%s%s%s",
366 CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL) ? "LOC " : "",
367 CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) ? "REM " : "",
368 CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO) ? "AUTO " : "",
369 CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? "STICKY " : "",
370 CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_RMAC) ? "REM Router "
371 : "",
372 CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW) ? "Default GW " : "",
373 CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW) ? "REM DEF GW "
374 : "",
375 CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE) ? "DUP " : "",
376 CHECK_FLAG(mac->flags, ZEBRA_MAC_FPM_SENT) ? "FPM " : "",
377 CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE)
378 ? "PEER Active "
379 : "",
380 CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY) ? "PROXY " : "",
381 CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE)
382 ? "LOC Inactive "
383 : "");
384 return buf;
385 }
386
387 static void zebra_evpn_dad_mac_auto_recovery_exp(struct thread *t)
388 {
389 struct zebra_vrf *zvrf = NULL;
390 struct zebra_mac *mac = NULL;
391 struct zebra_evpn *zevpn = NULL;
392 struct listnode *node = NULL;
393 struct zebra_neigh *nbr = NULL;
394
395 mac = THREAD_ARG(t);
396
397 /* since this is asynchronous we need sanity checks*/
398 zvrf = vrf_info_lookup(mac->zevpn->vrf_id);
399 if (!zvrf)
400 return;
401
402 zevpn = zebra_evpn_lookup(mac->zevpn->vni);
403 if (!zevpn)
404 return;
405
406 mac = zebra_evpn_mac_lookup(zevpn, &mac->macaddr);
407 if (!mac)
408 return;
409
410 if (IS_ZEBRA_DEBUG_VXLAN) {
411 char mac_buf[MAC_BUF_SIZE];
412
413 zlog_debug(
414 "%s: duplicate addr mac %pEA flags %slearn count %u host count %u auto recovery expired",
415 __func__, &mac->macaddr,
416 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
417 sizeof(mac_buf)),
418 mac->dad_count, listcount(mac->neigh_list));
419 }
420
421 /* Remove all IPs as duplicate associcated with this MAC */
422 for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, nbr)) {
423 if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE)) {
424 if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL))
425 ZEBRA_NEIGH_SET_INACTIVE(nbr);
426 else if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_REMOTE))
427 zebra_evpn_rem_neigh_install(
428 zevpn, nbr, false /*was_static*/);
429 }
430
431 UNSET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE);
432 nbr->dad_count = 0;
433 nbr->detect_start_time.tv_sec = 0;
434 nbr->dad_dup_detect_time = 0;
435 }
436
437 UNSET_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE);
438 mac->dad_count = 0;
439 mac->detect_start_time.tv_sec = 0;
440 mac->detect_start_time.tv_usec = 0;
441 mac->dad_dup_detect_time = 0;
442 mac->dad_mac_auto_recovery_timer = NULL;
443
444 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
445 /* Inform to BGP */
446 if (zebra_evpn_mac_send_add_to_client(zevpn->vni, &mac->macaddr,
447 mac->flags, mac->loc_seq,
448 mac->es))
449 return;
450
451 /* Process all neighbors associated with this MAC. */
452 zebra_evpn_process_neigh_on_local_mac_change(zevpn, mac, 0,
453 0 /*es_change*/);
454
455 } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
456 zebra_evpn_process_neigh_on_remote_mac_add(zevpn, mac);
457
458 /* Install the entry. */
459 zebra_evpn_rem_mac_install(zevpn, mac, false /* was_static */);
460 }
461 }
462
463 static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf,
464 struct zebra_mac *mac,
465 struct in_addr vtep_ip,
466 bool do_dad, bool *is_dup_detect,
467 bool is_local)
468 {
469 struct zebra_neigh *nbr;
470 struct listnode *node = NULL;
471 struct timeval elapsed = {0, 0};
472 bool reset_params = false;
473
474 if (!(zebra_evpn_do_dup_addr_detect(zvrf) && do_dad))
475 return;
476
477 /* MAC is detected as duplicate,
478 * Local MAC event -> hold on advertising to BGP.
479 * Remote MAC event -> hold on installing it.
480 */
481 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) {
482 if (IS_ZEBRA_DEBUG_VXLAN) {
483 char mac_buf[MAC_BUF_SIZE];
484
485 zlog_debug(
486 "%s: duplicate addr MAC %pEA flags %sskip update to client, learn count %u recover time %u",
487 __func__, &mac->macaddr,
488 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
489 sizeof(mac_buf)),
490 mac->dad_count, zvrf->dad_freeze_time);
491 }
492 /* For duplicate MAC do not update
493 * client but update neigh due to
494 * this MAC update.
495 */
496 if (zvrf->dad_freeze)
497 *is_dup_detect = true;
498
499 return;
500 }
501
502 /* Check if detection time (M-secs) expired.
503 * Reset learn count and detection start time.
504 */
505 monotime_since(&mac->detect_start_time, &elapsed);
506 reset_params = (elapsed.tv_sec > zvrf->dad_time);
507 if (is_local && !reset_params) {
508 /* RFC-7432: A PE/VTEP that detects a MAC mobility
509 * event via LOCAL learning starts an M-second timer.
510 *
511 * NOTE: This is the START of the probe with count is
512 * 0 during LOCAL learn event.
513 * (mac->dad_count == 0 || elapsed.tv_sec >= zvrf->dad_time)
514 */
515 reset_params = !mac->dad_count;
516 }
517
518 if (reset_params) {
519 if (IS_ZEBRA_DEBUG_VXLAN) {
520 char mac_buf[MAC_BUF_SIZE];
521
522 zlog_debug(
523 "%s: duplicate addr MAC %pEA flags %sdetection time passed, reset learn count %u",
524 __func__, &mac->macaddr,
525 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
526 sizeof(mac_buf)),
527 mac->dad_count);
528 }
529
530 mac->dad_count = 0;
531 /* Start dup. addr detection (DAD) start time,
532 * ONLY during LOCAL learn.
533 */
534 if (is_local)
535 monotime(&mac->detect_start_time);
536
537 } else if (!is_local) {
538 /* For REMOTE MAC, increment detection count
539 * ONLY while in probe window, once window passed,
540 * next local learn event should trigger DAD.
541 */
542 mac->dad_count++;
543 }
544
545 /* For LOCAL MAC learn event, once count is reset above via either
546 * initial/start detection time or passed the probe time, the count
547 * needs to be incremented.
548 */
549 if (is_local)
550 mac->dad_count++;
551
552 if (mac->dad_count >= zvrf->dad_max_moves) {
553 flog_warn(EC_ZEBRA_DUP_MAC_DETECTED,
554 "VNI %u: MAC %pEA detected as duplicate during %s VTEP %pI4",
555 mac->zevpn->vni, &mac->macaddr,
556 is_local ? "local update, last" :
557 "remote update, from", &vtep_ip);
558
559 SET_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE);
560
561 /* Capture Duplicate detection time */
562 mac->dad_dup_detect_time = monotime(NULL);
563
564 /* Mark all IPs/Neighs as duplicate
565 * associcated with this MAC
566 */
567 for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, nbr)) {
568
569 /* Ony Mark IPs which are Local */
570 if (!CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL))
571 continue;
572
573 SET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE);
574
575 nbr->dad_dup_detect_time = monotime(NULL);
576
577 flog_warn(EC_ZEBRA_DUP_IP_INHERIT_DETECTED,
578 "VNI %u: MAC %pEA IP %pIA detected as duplicate during %s update, inherit duplicate from MAC",
579 mac->zevpn->vni, &mac->macaddr, &nbr->ip,
580 is_local ? "local" : "remote");
581 }
582
583 /* Start auto recovery timer for this MAC */
584 THREAD_OFF(mac->dad_mac_auto_recovery_timer);
585 if (zvrf->dad_freeze && zvrf->dad_freeze_time) {
586 if (IS_ZEBRA_DEBUG_VXLAN) {
587 char mac_buf[MAC_BUF_SIZE];
588
589 zlog_debug(
590 "%s: duplicate addr MAC %pEA flags %sauto recovery time %u start",
591 __func__, &mac->macaddr,
592 zebra_evpn_zebra_mac_flag_dump(
593 mac, mac_buf, sizeof(mac_buf)),
594 zvrf->dad_freeze_time);
595 }
596
597 thread_add_timer(zrouter.master,
598 zebra_evpn_dad_mac_auto_recovery_exp,
599 mac, zvrf->dad_freeze_time,
600 &mac->dad_mac_auto_recovery_timer);
601 }
602
603 /* In case of local update, do not inform to client (BGPd),
604 * upd_neigh for neigh sequence change.
605 */
606 if (zvrf->dad_freeze)
607 *is_dup_detect = true;
608 }
609 }
610
611 /*
612 * Print a specific MAC entry.
613 */
614 void zebra_evpn_print_mac(struct zebra_mac *mac, void *ctxt, json_object *json)
615 {
616 struct vty *vty;
617 struct zebra_neigh *n = NULL;
618 struct listnode *node = NULL;
619 char buf1[ETHER_ADDR_STRLEN];
620 char buf2[INET6_ADDRSTRLEN];
621 struct zebra_vrf *zvrf;
622 struct timeval detect_start_time = {0, 0};
623 char timebuf[MONOTIME_STRLEN];
624 char thread_buf[THREAD_TIMER_STRLEN];
625 time_t uptime;
626 char up_str[MONOTIME_STRLEN];
627
628 zvrf = zebra_vrf_get_evpn();
629 vty = (struct vty *)ctxt;
630 prefix_mac2str(&mac->macaddr, buf1, sizeof(buf1));
631
632 uptime = monotime(NULL);
633 uptime -= mac->uptime;
634
635 frrtime_to_interval(uptime, up_str, sizeof(up_str));
636
637 if (json) {
638 json_object *json_mac = json_object_new_object();
639
640 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
641 struct interface *ifp;
642 vlanid_t vid;
643
644 zebra_evpn_mac_get_access_info(mac, &ifp, &vid);
645 json_object_string_add(json_mac, "type", "local");
646 if (ifp) {
647 json_object_string_add(json_mac, "intf",
648 ifp->name);
649 json_object_int_add(json_mac, "ifindex",
650 ifp->ifindex);
651 }
652 if (vid)
653 json_object_int_add(json_mac, "vlan", vid);
654 } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
655 json_object_string_add(json_mac, "type", "remote");
656 json_object_string_addf(json_mac, "remoteVtep", "%pI4",
657 &mac->fwd_info.r_vtep_ip);
658 } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO))
659 json_object_string_add(json_mac, "type", "auto");
660
661 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY))
662 json_object_boolean_true_add(json_mac, "stickyMac");
663
664 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_SVI))
665 json_object_boolean_true_add(json_mac, "sviMac");
666
667 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW))
668 json_object_boolean_true_add(json_mac,
669 "defaultGateway");
670
671 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW))
672 json_object_boolean_true_add(json_mac,
673 "remoteGatewayMac");
674
675 json_object_string_add(json_mac, "uptime", up_str);
676 json_object_int_add(json_mac, "localSequence", mac->loc_seq);
677 json_object_int_add(json_mac, "remoteSequence", mac->rem_seq);
678
679 json_object_int_add(json_mac, "detectionCount", mac->dad_count);
680 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
681 json_object_boolean_true_add(json_mac, "isDuplicate");
682 else
683 json_object_boolean_false_add(json_mac, "isDuplicate");
684
685 json_object_int_add(json_mac, "syncNeighCount",
686 mac->sync_neigh_cnt);
687 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE))
688 json_object_boolean_true_add(json_mac, "localInactive");
689 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY))
690 json_object_boolean_true_add(json_mac, "peerProxy");
691 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE))
692 json_object_boolean_true_add(json_mac, "peerActive");
693 if (mac->hold_timer)
694 json_object_string_add(
695 json_mac, "peerActiveHold",
696 thread_timer_to_hhmmss(thread_buf,
697 sizeof(thread_buf),
698 mac->hold_timer));
699 if (mac->es)
700 json_object_string_add(json_mac, "esi",
701 mac->es->esi_str);
702 /* print all the associated neigh */
703 if (!listcount(mac->neigh_list))
704 json_object_string_add(json_mac, "neighbors", "none");
705 else {
706 json_object *json_active_nbrs = json_object_new_array();
707 json_object *json_inactive_nbrs =
708 json_object_new_array();
709 json_object *json_nbrs = json_object_new_object();
710
711 for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, n)) {
712 if (IS_ZEBRA_NEIGH_ACTIVE(n))
713 json_object_array_add(
714 json_active_nbrs,
715 json_object_new_string(
716 ipaddr2str(
717 &n->ip, buf2,
718 sizeof(buf2))));
719 else
720 json_object_array_add(
721 json_inactive_nbrs,
722 json_object_new_string(
723 ipaddr2str(
724 &n->ip, buf2,
725 sizeof(buf2))));
726 }
727
728 json_object_object_add(json_nbrs, "active",
729 json_active_nbrs);
730 json_object_object_add(json_nbrs, "inactive",
731 json_inactive_nbrs);
732 json_object_object_add(json_mac, "neighbors",
733 json_nbrs);
734 }
735
736 json_object_object_add(json, buf1, json_mac);
737 } else {
738 vty_out(vty, "MAC: %s\n", buf1);
739
740 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
741 struct interface *ifp;
742 vlanid_t vid;
743
744 zebra_evpn_mac_get_access_info(mac, &ifp, &vid);
745
746 if (mac->es)
747 vty_out(vty, " ESI: %s\n", mac->es->esi_str);
748
749 if (ifp)
750 vty_out(vty, " Intf: %s(%u)", ifp->name,
751 ifp->ifindex);
752 else
753 vty_out(vty, " Intf: -");
754 vty_out(vty, " VLAN: %u", vid);
755 } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
756 if (mac->es)
757 vty_out(vty, " Remote ES: %s",
758 mac->es->esi_str);
759 else
760 vty_out(vty, " Remote VTEP: %pI4",
761 &mac->fwd_info.r_vtep_ip);
762 } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) {
763 vty_out(vty, " Auto Mac ");
764 }
765
766 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY))
767 vty_out(vty, " Sticky Mac ");
768
769 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_SVI))
770 vty_out(vty, " SVI-Mac ");
771
772 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW))
773 vty_out(vty, " Default-gateway Mac ");
774
775 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW))
776 vty_out(vty, " Remote-gateway Mac ");
777
778 vty_out(vty, "\n");
779 vty_out(vty, " Sync-info: neigh#: %u", mac->sync_neigh_cnt);
780 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE))
781 vty_out(vty, " local-inactive");
782 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY))
783 vty_out(vty, " peer-proxy");
784 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE))
785 vty_out(vty, " peer-active");
786 if (mac->hold_timer)
787 vty_out(vty, " (ht: %s)",
788 thread_timer_to_hhmmss(thread_buf,
789 sizeof(thread_buf),
790 mac->hold_timer));
791 vty_out(vty, "\n");
792 vty_out(vty, " Local Seq: %u Remote Seq: %u\n", mac->loc_seq,
793 mac->rem_seq);
794 vty_out(vty, " Uptime: %s\n", up_str);
795
796 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) {
797 vty_out(vty, " Duplicate, detected at %s",
798 time_to_string(mac->dad_dup_detect_time,
799 timebuf));
800 } else if (mac->dad_count) {
801 monotime_since(&mac->detect_start_time,
802 &detect_start_time);
803 if (detect_start_time.tv_sec <= zvrf->dad_time) {
804 time_to_string(mac->detect_start_time.tv_sec,
805 timebuf);
806 vty_out(vty,
807 " Duplicate detection started at %s, detection count %u\n",
808 timebuf, mac->dad_count);
809 }
810 }
811
812 /* print all the associated neigh */
813 vty_out(vty, " Neighbors:\n");
814 if (!listcount(mac->neigh_list))
815 vty_out(vty, " No Neighbors\n");
816 else {
817 for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, n)) {
818 vty_out(vty, " %s %s\n",
819 ipaddr2str(&n->ip, buf2, sizeof(buf2)),
820 (IS_ZEBRA_NEIGH_ACTIVE(n)
821 ? "Active"
822 : "Inactive"));
823 }
824 }
825
826 vty_out(vty, "\n");
827 }
828 }
829
830 static char *zebra_evpn_print_mac_flags(struct zebra_mac *mac, char *flags_buf,
831 size_t flags_buf_sz)
832 {
833 snprintf(flags_buf, flags_buf_sz, "%s%s%s%s",
834 mac->sync_neigh_cnt ? "N" : "",
835 (mac->flags & ZEBRA_MAC_ES_PEER_ACTIVE) ? "P" : "",
836 (mac->flags & ZEBRA_MAC_ES_PEER_PROXY) ? "X" : "",
837 (mac->flags & ZEBRA_MAC_LOCAL_INACTIVE) ? "I" : "");
838
839 return flags_buf;
840 }
841
842 /*
843 * Print MAC hash entry - called for display of all MACs.
844 */
845 void zebra_evpn_print_mac_hash(struct hash_bucket *bucket, void *ctxt)
846 {
847 struct vty *vty;
848 json_object *json_mac_hdr = NULL, *json_mac = NULL;
849 struct zebra_mac *mac;
850 char buf1[ETHER_ADDR_STRLEN];
851 char addr_buf[PREFIX_STRLEN];
852 struct mac_walk_ctx *wctx = ctxt;
853 char flags_buf[6];
854
855 vty = wctx->vty;
856 json_mac_hdr = wctx->json;
857 mac = (struct zebra_mac *)bucket->data;
858
859 prefix_mac2str(&mac->macaddr, buf1, sizeof(buf1));
860
861 if (json_mac_hdr)
862 json_mac = json_object_new_object();
863
864 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
865 struct interface *ifp;
866 vlanid_t vid;
867
868 if (wctx->flags & SHOW_REMOTE_MAC_FROM_VTEP)
869 return;
870
871 zebra_evpn_mac_get_access_info(mac, &ifp, &vid);
872 if (json_mac_hdr == NULL) {
873 vty_out(vty, "%-17s %-6s %-5s %-30s", buf1, "local",
874 zebra_evpn_print_mac_flags(mac, flags_buf,
875 sizeof(flags_buf)),
876 ifp ? ifp->name : "-");
877 } else {
878 json_object_string_add(json_mac, "type", "local");
879 if (ifp)
880 json_object_string_add(json_mac, "intf",
881 ifp->name);
882 }
883 if (vid) {
884 if (json_mac_hdr == NULL)
885 vty_out(vty, " %-5u", vid);
886 else
887 json_object_int_add(json_mac, "vlan", vid);
888 } else /* No vid? fill out the space */
889 if (json_mac_hdr == NULL)
890 vty_out(vty, " %-5s", "");
891 if (json_mac_hdr == NULL) {
892 vty_out(vty, " %u/%u", mac->loc_seq, mac->rem_seq);
893 vty_out(vty, "\n");
894 } else {
895 json_object_int_add(json_mac, "localSequence",
896 mac->loc_seq);
897 json_object_int_add(json_mac, "remoteSequence",
898 mac->rem_seq);
899 json_object_int_add(json_mac, "detectionCount",
900 mac->dad_count);
901 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
902 json_object_boolean_true_add(json_mac,
903 "isDuplicate");
904 else
905 json_object_boolean_false_add(json_mac,
906 "isDuplicate");
907 json_object_object_add(json_mac_hdr, buf1, json_mac);
908 }
909
910 wctx->count++;
911
912 } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
913
914 if ((wctx->flags & SHOW_REMOTE_MAC_FROM_VTEP)
915 && !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip,
916 &wctx->r_vtep_ip))
917 return;
918
919 if (json_mac_hdr == NULL) {
920 if ((wctx->flags & SHOW_REMOTE_MAC_FROM_VTEP)
921 && (wctx->count == 0)) {
922 vty_out(vty, "\nVNI %u\n\n", wctx->zevpn->vni);
923 vty_out(vty, "%-17s %-6s %-5s%-30s %-5s %s\n",
924 "MAC", "Type", "Flags",
925 "Intf/Remote ES/VTEP", "VLAN",
926 "Seq #'s");
927 }
928 if (mac->es == NULL)
929 inet_ntop(AF_INET, &mac->fwd_info.r_vtep_ip,
930 addr_buf, sizeof(addr_buf));
931
932 vty_out(vty, "%-17s %-6s %-5s %-30s %-5s %u/%u\n", buf1,
933 "remote",
934 zebra_evpn_print_mac_flags(mac, flags_buf,
935 sizeof(flags_buf)),
936 mac->es ? mac->es->esi_str : addr_buf,
937 "", mac->loc_seq, mac->rem_seq);
938 } else {
939 json_object_string_add(json_mac, "type", "remote");
940 json_object_string_addf(json_mac, "remoteVtep", "%pI4",
941 &mac->fwd_info.r_vtep_ip);
942 json_object_object_add(json_mac_hdr, buf1, json_mac);
943 json_object_int_add(json_mac, "localSequence",
944 mac->loc_seq);
945 json_object_int_add(json_mac, "remoteSequence",
946 mac->rem_seq);
947 json_object_int_add(json_mac, "detectionCount",
948 mac->dad_count);
949 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
950 json_object_boolean_true_add(json_mac,
951 "isDuplicate");
952 else
953 json_object_boolean_false_add(json_mac,
954 "isDuplicate");
955 }
956
957 wctx->count++;
958 }
959 }
960
961 /*
962 * Print MAC hash entry in detail - called for display of all MACs.
963 */
964 void zebra_evpn_print_mac_hash_detail(struct hash_bucket *bucket, void *ctxt)
965 {
966 struct vty *vty;
967 json_object *json_mac_hdr = NULL;
968 struct zebra_mac *mac;
969 struct mac_walk_ctx *wctx = ctxt;
970 char buf1[ETHER_ADDR_STRLEN];
971
972 vty = wctx->vty;
973 json_mac_hdr = wctx->json;
974 mac = (struct zebra_mac *)bucket->data;
975 if (!mac)
976 return;
977
978 wctx->count++;
979 prefix_mac2str(&mac->macaddr, buf1, sizeof(buf1));
980
981 zebra_evpn_print_mac(mac, vty, json_mac_hdr);
982 }
983
984 /*
985 * Inform BGP about local MACIP.
986 */
987 int zebra_evpn_macip_send_msg_to_client(vni_t vni,
988 const struct ethaddr *macaddr,
989 const struct ipaddr *ip, uint8_t flags,
990 uint32_t seq, int state,
991 struct zebra_evpn_es *es, uint16_t cmd)
992 {
993 int ipa_len;
994 struct zserv *client = NULL;
995 struct stream *s = NULL;
996 esi_t *esi = es ? &es->esi : zero_esi;
997
998 client = zserv_find_client(ZEBRA_ROUTE_BGP, 0);
999 /* BGP may not be running. */
1000 if (!client)
1001 return 0;
1002
1003 s = stream_new(ZEBRA_MAX_PACKET_SIZ);
1004
1005 zclient_create_header(s, cmd, zebra_vrf_get_evpn_id());
1006 stream_putl(s, vni);
1007 stream_put(s, macaddr->octet, ETH_ALEN);
1008 if (ip) {
1009 ipa_len = 0;
1010 if (IS_IPADDR_V4(ip))
1011 ipa_len = IPV4_MAX_BYTELEN;
1012 else if (IS_IPADDR_V6(ip))
1013 ipa_len = IPV6_MAX_BYTELEN;
1014
1015 stream_putl(s, ipa_len); /* IP address length */
1016 if (ipa_len)
1017 stream_put(s, &ip->ip.addr, ipa_len); /* IP address */
1018 } else
1019 stream_putl(s, 0); /* Just MAC. */
1020
1021 if (cmd == ZEBRA_MACIP_ADD) {
1022 stream_putc(s, flags); /* sticky mac/gateway mac */
1023 stream_putl(s, seq); /* sequence number */
1024 stream_put(s, esi, sizeof(esi_t));
1025 } else {
1026 stream_putl(s, state); /* state - active/inactive */
1027 }
1028
1029
1030 /* Write packet size. */
1031 stream_putw_at(s, 0, stream_get_endp(s));
1032
1033 if (IS_ZEBRA_DEBUG_VXLAN) {
1034 char flag_buf[MACIP_BUF_SIZE];
1035
1036 zlog_debug(
1037 "Send MACIP %s f %s MAC %pEA IP %pIA seq %u L2-VNI %u ESI %s to %s",
1038 (cmd == ZEBRA_MACIP_ADD) ? "Add" : "Del",
1039 zclient_evpn_dump_macip_flags(flags, flag_buf,
1040 sizeof(flag_buf)),
1041 macaddr, ip, seq, vni,
1042 es ? es->esi_str : "-",
1043 zebra_route_string(client->proto));
1044 }
1045
1046 if (cmd == ZEBRA_MACIP_ADD)
1047 client->macipadd_cnt++;
1048 else
1049 client->macipdel_cnt++;
1050
1051 return zserv_send_message(client, s);
1052 }
1053
1054 static unsigned int mac_hash_keymake(const void *p)
1055 {
1056 const struct zebra_mac *pmac = p;
1057 const void *pnt = (void *)pmac->macaddr.octet;
1058
1059 return jhash(pnt, ETH_ALEN, 0xa5a5a55a);
1060 }
1061
1062 /*
1063 * Compare two MAC addresses.
1064 */
1065 static bool mac_cmp(const void *p1, const void *p2)
1066 {
1067 const struct zebra_mac *pmac1 = p1;
1068 const struct zebra_mac *pmac2 = p2;
1069
1070 if (pmac1 == NULL && pmac2 == NULL)
1071 return true;
1072
1073 if (pmac1 == NULL || pmac2 == NULL)
1074 return false;
1075
1076 return (memcmp(pmac1->macaddr.octet, pmac2->macaddr.octet, ETH_ALEN)
1077 == 0);
1078 }
1079
1080 /*
1081 * Callback to allocate MAC hash entry.
1082 */
1083 static void *zebra_evpn_mac_alloc(void *p)
1084 {
1085 const struct zebra_mac *tmp_mac = p;
1086 struct zebra_mac *mac;
1087
1088 mac = XCALLOC(MTYPE_MAC, sizeof(struct zebra_mac));
1089 *mac = *tmp_mac;
1090
1091 return ((void *)mac);
1092 }
1093
1094 /*
1095 * Add MAC entry.
1096 */
1097 struct zebra_mac *zebra_evpn_mac_add(struct zebra_evpn *zevpn,
1098 const struct ethaddr *macaddr)
1099 {
1100 struct zebra_mac tmp_mac;
1101 struct zebra_mac *mac = NULL;
1102
1103 memset(&tmp_mac, 0, sizeof(tmp_mac));
1104 memcpy(&tmp_mac.macaddr, macaddr, ETH_ALEN);
1105 mac = hash_get(zevpn->mac_table, &tmp_mac, zebra_evpn_mac_alloc);
1106
1107 mac->zevpn = zevpn;
1108 mac->dad_mac_auto_recovery_timer = NULL;
1109
1110 mac->neigh_list = list_new();
1111 mac->neigh_list->cmp = neigh_list_cmp;
1112
1113 mac->uptime = monotime(NULL);
1114 if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
1115 char mac_buf[MAC_BUF_SIZE];
1116
1117 zlog_debug("%s: MAC %pEA flags %s", __func__,
1118 &mac->macaddr,
1119 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
1120 sizeof(mac_buf)));
1121 }
1122 return mac;
1123 }
1124
1125 /*
1126 * Delete MAC entry.
1127 */
1128 int zebra_evpn_mac_del(struct zebra_evpn *zevpn, struct zebra_mac *mac)
1129 {
1130 struct zebra_mac *tmp_mac;
1131
1132 if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
1133 char mac_buf[MAC_BUF_SIZE];
1134
1135 zlog_debug("%s: MAC %pEA flags %s", __func__,
1136 &mac->macaddr,
1137 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
1138 sizeof(mac_buf)));
1139 }
1140
1141 /* force de-ref any ES entry linked to the MAC */
1142 zebra_evpn_es_mac_deref_entry(mac);
1143
1144 /* remove links to the destination access port */
1145 zebra_evpn_mac_clear_fwd_info(mac);
1146
1147 /* Cancel proxy hold timer */
1148 zebra_evpn_mac_stop_hold_timer(mac);
1149
1150 /* Cancel auto recovery */
1151 THREAD_OFF(mac->dad_mac_auto_recovery_timer);
1152
1153 /* If the MAC is freed before the neigh we will end up
1154 * with a stale pointer against the neigh.
1155 * The situation can arise when a MAC is in remote state
1156 * and its associated neigh is local state.
1157 * zebra_evpn_cfg_cleanup() cleans up remote neighs and MACs.
1158 * Instead of deleting remote MAC, if its neigh list is non-empty
1159 * (associated to local neighs), mark the MAC as AUTO.
1160 */
1161 if (!list_isempty(mac->neigh_list)) {
1162 if (IS_ZEBRA_DEBUG_VXLAN)
1163 zlog_debug(
1164 "MAC %pEA (flags 0x%x vni %u) has non-empty neigh list "
1165 "count %u, mark MAC as AUTO",
1166 &mac->macaddr, mac->flags, zevpn->vni,
1167 listcount(mac->neigh_list));
1168
1169 SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
1170 return 0;
1171 }
1172
1173 list_delete(&mac->neigh_list);
1174
1175 /* Free the VNI hash entry and allocated memory. */
1176 tmp_mac = hash_release(zevpn->mac_table, mac);
1177 XFREE(MTYPE_MAC, tmp_mac);
1178
1179 return 0;
1180 }
1181
1182 /*
1183 * Add Auto MAC entry.
1184 */
1185 struct zebra_mac *zebra_evpn_mac_add_auto(struct zebra_evpn *zevpn,
1186 const struct ethaddr *macaddr)
1187 {
1188 struct zebra_mac *mac;
1189
1190 mac = zebra_evpn_mac_add(zevpn, macaddr);
1191 if (!mac)
1192 return NULL;
1193
1194 zebra_evpn_mac_clear_fwd_info(mac);
1195 memset(&mac->flags, 0, sizeof(uint32_t));
1196 SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
1197
1198 return mac;
1199 }
1200
1201 static bool zebra_evpn_check_mac_del_from_db(struct mac_walk_ctx *wctx,
1202 struct zebra_mac *mac)
1203 {
1204 if ((wctx->flags & DEL_LOCAL_MAC) && (mac->flags & ZEBRA_MAC_LOCAL))
1205 return true;
1206 else if ((wctx->flags & DEL_REMOTE_MAC)
1207 && (mac->flags & ZEBRA_MAC_REMOTE))
1208 return true;
1209 else if ((wctx->flags & DEL_REMOTE_MAC_FROM_VTEP)
1210 && (mac->flags & ZEBRA_MAC_REMOTE)
1211 && IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &wctx->r_vtep_ip))
1212 return true;
1213 else if ((wctx->flags & DEL_LOCAL_MAC) && (mac->flags & ZEBRA_MAC_AUTO)
1214 && !listcount(mac->neigh_list)) {
1215 if (IS_ZEBRA_DEBUG_VXLAN) {
1216 char mac_buf[MAC_BUF_SIZE];
1217
1218 zlog_debug(
1219 "%s: Del MAC %pEA flags %s", __func__,
1220 &mac->macaddr,
1221 zebra_evpn_zebra_mac_flag_dump(
1222 mac, mac_buf, sizeof(mac_buf)));
1223 }
1224 wctx->uninstall = 0;
1225
1226 return true;
1227 }
1228
1229 return false;
1230 }
1231
1232 /*
1233 * Free MAC hash entry (callback)
1234 */
1235 static void zebra_evpn_mac_del_hash_entry(struct hash_bucket *bucket, void *arg)
1236 {
1237 struct mac_walk_ctx *wctx = arg;
1238 struct zebra_mac *mac = bucket->data;
1239
1240 if (zebra_evpn_check_mac_del_from_db(wctx, mac)) {
1241 if (wctx->upd_client && (mac->flags & ZEBRA_MAC_LOCAL)) {
1242 zebra_evpn_mac_send_del_to_client(wctx->zevpn->vni,
1243 &mac->macaddr,
1244 mac->flags, false);
1245 }
1246 if (wctx->uninstall) {
1247 if (zebra_evpn_mac_is_static(mac))
1248 zebra_evpn_sync_mac_dp_install(
1249 mac, false /* set_inactive */,
1250 true /* force_clear_static */,
1251 __func__);
1252
1253 if (mac->flags & ZEBRA_MAC_REMOTE)
1254 zebra_evpn_rem_mac_uninstall(wctx->zevpn, mac,
1255 false /*force*/);
1256 }
1257
1258 zebra_evpn_mac_del(wctx->zevpn, mac);
1259 }
1260
1261 return;
1262 }
1263
1264 /*
1265 * Delete all MAC entries for this EVPN.
1266 */
1267 void zebra_evpn_mac_del_all(struct zebra_evpn *zevpn, int uninstall,
1268 int upd_client, uint32_t flags)
1269 {
1270 struct mac_walk_ctx wctx;
1271
1272 if (!zevpn->mac_table)
1273 return;
1274
1275 memset(&wctx, 0, sizeof(wctx));
1276 wctx.zevpn = zevpn;
1277 wctx.uninstall = uninstall;
1278 wctx.upd_client = upd_client;
1279 wctx.flags = flags;
1280
1281 hash_iterate(zevpn->mac_table, zebra_evpn_mac_del_hash_entry, &wctx);
1282 }
1283
1284 /*
1285 * Look up MAC hash entry.
1286 */
1287 struct zebra_mac *zebra_evpn_mac_lookup(struct zebra_evpn *zevpn,
1288 const struct ethaddr *mac)
1289 {
1290 struct zebra_mac tmp;
1291 struct zebra_mac *pmac;
1292
1293 memset(&tmp, 0, sizeof(tmp));
1294 memcpy(&tmp.macaddr, mac, ETH_ALEN);
1295 pmac = hash_lookup(zevpn->mac_table, &tmp);
1296
1297 return pmac;
1298 }
1299
1300 /*
1301 * Inform BGP about local MAC addition.
1302 */
1303 int zebra_evpn_mac_send_add_to_client(vni_t vni, const struct ethaddr *macaddr,
1304 uint32_t mac_flags, uint32_t seq,
1305 struct zebra_evpn_es *es)
1306 {
1307 uint8_t flags = 0;
1308
1309 if (CHECK_FLAG(mac_flags, ZEBRA_MAC_LOCAL_INACTIVE)) {
1310 /* host reachability has not been verified locally */
1311
1312 /* if no ES peer is claiming reachability we can't advertise the
1313 * entry
1314 */
1315 if (!CHECK_FLAG(mac_flags, ZEBRA_MAC_ES_PEER_ACTIVE))
1316 return 0;
1317
1318 /* ES peers are claiming reachability; we will
1319 * advertise the entry but with a proxy flag
1320 */
1321 SET_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT);
1322 }
1323
1324 if (CHECK_FLAG(mac_flags, ZEBRA_MAC_STICKY))
1325 SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
1326 if (CHECK_FLAG(mac_flags, ZEBRA_MAC_DEF_GW))
1327 SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
1328
1329 return zebra_evpn_macip_send_msg_to_client(vni, macaddr, NULL, flags,
1330 seq, ZEBRA_NEIGH_ACTIVE, es,
1331 ZEBRA_MACIP_ADD);
1332 }
1333
1334 /*
1335 * Inform BGP about local MAC deletion.
1336 */
1337 int zebra_evpn_mac_send_del_to_client(vni_t vni, const struct ethaddr *macaddr,
1338 uint32_t flags, bool force)
1339 {
1340 if (!force) {
1341 if (CHECK_FLAG(flags, ZEBRA_MAC_LOCAL_INACTIVE)
1342 && !CHECK_FLAG(flags, ZEBRA_MAC_ES_PEER_ACTIVE))
1343 /* the host was not advertised - nothing to delete */
1344 return 0;
1345 }
1346
1347 return zebra_evpn_macip_send_msg_to_client(
1348 vni, macaddr, NULL, 0 /* flags */, 0 /* seq */,
1349 ZEBRA_NEIGH_ACTIVE, NULL, ZEBRA_MACIP_DEL);
1350 }
1351
1352 /*
1353 * wrapper to create a MAC hash table
1354 */
1355 struct hash *zebra_mac_db_create(const char *desc)
1356 {
1357 return hash_create_size(8, mac_hash_keymake, mac_cmp, desc);
1358 }
1359
1360 /* program sync mac flags in the dataplane */
1361 int zebra_evpn_sync_mac_dp_install(struct zebra_mac *mac, bool set_inactive,
1362 bool force_clear_static, const char *caller)
1363 {
1364 struct interface *ifp;
1365 bool sticky;
1366 bool set_static;
1367 struct zebra_evpn *zevpn = mac->zevpn;
1368 vlanid_t vid;
1369 struct zebra_if *zif;
1370 struct interface *br_ifp;
1371
1372 /* If the ES-EVI doesn't exist defer install. When the ES-EVI is
1373 * created we will attempt to install the mac entry again
1374 */
1375 if (mac->es) {
1376 struct zebra_evpn_es_evi *es_evi;
1377
1378 es_evi = zebra_evpn_es_evi_find(mac->es, mac->zevpn);
1379 if (!es_evi) {
1380 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
1381 zlog_debug(
1382 "%s: dp-install sync-mac vni %u mac %pEA es %s 0x%x %sskipped, no es-evi",
1383 caller, zevpn->vni, &mac->macaddr,
1384 mac->es ? mac->es->esi_str : "-",
1385 mac->flags,
1386 set_inactive ? "inactive " : "");
1387 return -1;
1388 }
1389 }
1390
1391 /* get the access vlan from the vxlan_device */
1392 zebra_evpn_mac_get_access_info(mac, &ifp, &vid);
1393
1394 if (!ifp) {
1395 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
1396 char mac_buf[MAC_BUF_SIZE];
1397
1398 zlog_debug(
1399 "%s: dp-install sync-mac vni %u mac %pEA es %s %s%sskipped, no access-port",
1400 caller, zevpn->vni, &mac->macaddr,
1401 mac->es ? mac->es->esi_str : "-",
1402 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
1403 sizeof(mac_buf)),
1404 set_inactive ? "inactive " : "");
1405 }
1406 return -1;
1407 }
1408
1409 zif = ifp->info;
1410 br_ifp = zif->brslave_info.br_if;
1411 if (!br_ifp) {
1412 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
1413 char mac_buf[MAC_BUF_SIZE];
1414
1415 zlog_debug(
1416 "%s: dp-install sync-mac vni %u mac %pEA es %s %s%sskipped, no br",
1417 caller, zevpn->vni, &mac->macaddr,
1418 mac->es ? mac->es->esi_str : "-",
1419 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
1420 sizeof(mac_buf)),
1421 set_inactive ? "inactive " : "");
1422 }
1423 return -1;
1424 }
1425
1426 sticky = !!CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY);
1427 if (force_clear_static)
1428 set_static = false;
1429 else
1430 set_static = zebra_evpn_mac_is_static(mac);
1431
1432 /* We can install a local mac that has been synced from the peer
1433 * over the VxLAN-overlay/network-port if fast failover is not
1434 * supported and if the local ES is oper-down.
1435 */
1436 if (mac->es && zebra_evpn_es_local_mac_via_network_port(mac->es)) {
1437 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
1438 char mac_buf[MAC_BUF_SIZE];
1439
1440 zlog_debug(
1441 "dp-%s sync-nw-mac vni %u mac %pEA es %s %s%s",
1442 set_static ? "install" : "uninstall",
1443 zevpn->vni, &mac->macaddr,
1444 mac->es ? mac->es->esi_str : "-",
1445 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
1446 sizeof(mac_buf)),
1447 set_inactive ? "inactive " : "");
1448 }
1449 if (set_static)
1450 /* XXX - old_static needs to be computed more
1451 * accurately
1452 */
1453 zebra_evpn_rem_mac_install(zevpn, mac,
1454 true /* old_static */);
1455 else
1456 zebra_evpn_rem_mac_uninstall(zevpn, mac,
1457 false /* force */);
1458
1459 return 0;
1460 }
1461
1462 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
1463 char mac_buf[MAC_BUF_SIZE];
1464
1465 zlog_debug("dp-install sync-mac vni %u mac %pEA es %s %s%s%s",
1466 zevpn->vni, &mac->macaddr,
1467 mac->es ? mac->es->esi_str : "-",
1468 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
1469 sizeof(mac_buf)),
1470 set_static ? "static " : "",
1471 set_inactive ? "inactive " : "");
1472 }
1473
1474 dplane_local_mac_add(ifp, br_ifp, vid, &mac->macaddr, sticky,
1475 set_static, set_inactive);
1476 return 0;
1477 }
1478
1479 void zebra_evpn_mac_send_add_del_to_client(struct zebra_mac *mac,
1480 bool old_bgp_ready,
1481 bool new_bgp_ready)
1482 {
1483 if (new_bgp_ready)
1484 zebra_evpn_mac_send_add_to_client(mac->zevpn->vni,
1485 &mac->macaddr, mac->flags,
1486 mac->loc_seq, mac->es);
1487 else if (old_bgp_ready)
1488 zebra_evpn_mac_send_del_to_client(mac->zevpn->vni,
1489 &mac->macaddr, mac->flags,
1490 true /* force */);
1491 }
1492
1493 /* MAC hold timer is used to age out peer-active flag.
1494 *
1495 * During this wait time we expect the dataplane component or an
1496 * external neighmgr daemon to probe existing hosts to independently
1497 * establish their presence on the ES.
1498 */
1499 static void zebra_evpn_mac_hold_exp_cb(struct thread *t)
1500 {
1501 struct zebra_mac *mac;
1502 bool old_bgp_ready;
1503 bool new_bgp_ready;
1504 bool old_static;
1505 bool new_static;
1506
1507 mac = THREAD_ARG(t);
1508 /* the purpose of the hold timer is to age out the peer-active
1509 * flag
1510 */
1511 if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE))
1512 return;
1513
1514 old_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
1515 old_static = zebra_evpn_mac_is_static(mac);
1516 UNSET_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE);
1517 new_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
1518 new_static = zebra_evpn_mac_is_static(mac);
1519
1520 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
1521 char mac_buf[MAC_BUF_SIZE];
1522
1523 zlog_debug(
1524 "sync-mac vni %u mac %pEA es %s %shold expired",
1525 mac->zevpn->vni, &mac->macaddr,
1526 mac->es ? mac->es->esi_str : "-",
1527 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
1528 sizeof(mac_buf)));
1529 }
1530
1531 /* re-program the local mac in the dataplane if the mac is no
1532 * longer static
1533 */
1534 if (old_static != new_static)
1535 zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */,
1536 false /* force_clear_static */,
1537 __func__);
1538
1539 /* inform bgp if needed */
1540 if (old_bgp_ready != new_bgp_ready)
1541 zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready,
1542 new_bgp_ready);
1543 }
1544
1545 static inline void zebra_evpn_mac_start_hold_timer(struct zebra_mac *mac)
1546 {
1547 if (mac->hold_timer)
1548 return;
1549
1550 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
1551 char mac_buf[MAC_BUF_SIZE];
1552
1553 zlog_debug(
1554 "sync-mac vni %u mac %pEA es %s %shold started",
1555 mac->zevpn->vni, &mac->macaddr,
1556 mac->es ? mac->es->esi_str : "-",
1557 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
1558 sizeof(mac_buf)));
1559 }
1560 thread_add_timer(zrouter.master, zebra_evpn_mac_hold_exp_cb, mac,
1561 zmh_info->mac_hold_time, &mac->hold_timer);
1562 }
1563
1564 void zebra_evpn_mac_stop_hold_timer(struct zebra_mac *mac)
1565 {
1566 if (!mac->hold_timer)
1567 return;
1568
1569 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
1570 char mac_buf[MAC_BUF_SIZE];
1571
1572 zlog_debug(
1573 "sync-mac vni %u mac %pEA es %s %shold stopped",
1574 mac->zevpn->vni, &mac->macaddr,
1575 mac->es ? mac->es->esi_str : "-",
1576 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
1577 sizeof(mac_buf)));
1578 }
1579
1580 THREAD_OFF(mac->hold_timer);
1581 }
1582
1583 void zebra_evpn_sync_mac_del(struct zebra_mac *mac)
1584 {
1585 bool old_static;
1586 bool new_static;
1587
1588 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
1589 char mac_buf[MAC_BUF_SIZE];
1590
1591 zlog_debug(
1592 "sync-mac del vni %u mac %pEA es %s seq %d f %s",
1593 mac->zevpn->vni, &mac->macaddr,
1594 mac->es ? mac->es->esi_str : "-", mac->loc_seq,
1595 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
1596 sizeof(mac_buf)));
1597 }
1598
1599 old_static = zebra_evpn_mac_is_static(mac);
1600 UNSET_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY);
1601 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE))
1602 zebra_evpn_mac_start_hold_timer(mac);
1603 new_static = zebra_evpn_mac_is_static(mac);
1604
1605 if (old_static != new_static)
1606 /* program the local mac in the kernel */
1607 zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */,
1608 false /* force_clear_static */,
1609 __func__);
1610 }
1611
1612 static inline bool zebra_evpn_mac_is_bgp_seq_ok(struct zebra_evpn *zevpn,
1613 struct zebra_mac *mac,
1614 uint32_t seq, bool sync)
1615 {
1616 char mac_buf[MAC_BUF_SIZE];
1617 uint32_t tmp_seq;
1618 const char *n_type;
1619 bool is_local = false;
1620
1621 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
1622 tmp_seq = mac->loc_seq;
1623 n_type = "local";
1624 is_local = true;
1625 } else {
1626 tmp_seq = mac->rem_seq;
1627 n_type = "remote";
1628 }
1629
1630 if (seq < tmp_seq) {
1631
1632 if (is_local && !zebra_evpn_mac_is_ready_for_bgp(mac->flags)) {
1633 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC || IS_ZEBRA_DEBUG_VXLAN)
1634 zlog_debug(
1635 "%s-macip not ready vni %u %s-mac %pEA lower seq %u f 0x%x",
1636 sync ? "sync" : "rem", zevpn->vni,
1637 n_type, &mac->macaddr, tmp_seq,
1638 mac->flags);
1639 return true;
1640 }
1641
1642 /* if the mac was never advertised to bgp we must accept
1643 * whatever sequence number bgp sends
1644 */
1645 if (!is_local && zebra_vxlan_get_accept_bgp_seq()) {
1646 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC ||
1647 IS_ZEBRA_DEBUG_VXLAN) {
1648 zlog_debug(
1649 "%s-macip accept vni %u %s-mac %pEA lower seq %u f %s",
1650 sync ? "sync" : "rem", zevpn->vni,
1651 n_type, &mac->macaddr, tmp_seq,
1652 zebra_evpn_zebra_mac_flag_dump(
1653 mac, mac_buf, sizeof(mac_buf)));
1654 }
1655
1656 return true;
1657 }
1658
1659 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC || IS_ZEBRA_DEBUG_VXLAN) {
1660 zlog_debug(
1661 "%s-macip ignore vni %u %s-mac %pEA as existing has higher seq %u f %s",
1662 sync ? "sync" : "rem", zevpn->vni, n_type,
1663 &mac->macaddr, tmp_seq,
1664 zebra_evpn_zebra_mac_flag_dump(
1665 mac, mac_buf, sizeof(mac_buf)));
1666 }
1667
1668 return false;
1669 }
1670
1671 return true;
1672 }
1673
1674 struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevpn,
1675 const struct ethaddr *macaddr,
1676 uint16_t ipa_len,
1677 const struct ipaddr *ipaddr,
1678 uint8_t flags, uint32_t seq,
1679 const esi_t *esi)
1680 {
1681 struct zebra_mac *mac;
1682 bool inform_bgp = false;
1683 bool inform_dataplane = false;
1684 bool seq_change = false;
1685 bool es_change = false;
1686 uint32_t tmp_seq;
1687 char ipbuf[INET6_ADDRSTRLEN];
1688 bool old_local = false;
1689 bool old_bgp_ready;
1690 bool new_bgp_ready;
1691 bool created = false;
1692
1693 mac = zebra_evpn_mac_lookup(zevpn, macaddr);
1694 if (!mac) {
1695 /* if it is a new local path we need to inform both
1696 * the control protocol and the data-plane
1697 */
1698 inform_bgp = true;
1699 inform_dataplane = true;
1700
1701 /* create the MAC and associate it with the dest ES */
1702 mac = zebra_evpn_mac_add(zevpn, macaddr);
1703 zebra_evpn_es_mac_ref(mac, esi);
1704
1705 /* local mac activated by an ES peer */
1706 SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
1707 /* if mac-only route setup peer flags */
1708 if (!ipa_len) {
1709 if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT))
1710 SET_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY);
1711 else
1712 SET_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE);
1713 }
1714 SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE);
1715 old_bgp_ready = false;
1716 new_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
1717 created = true;
1718 } else {
1719 uint32_t old_flags;
1720 uint32_t new_flags;
1721 bool old_static;
1722 bool new_static;
1723 bool sticky;
1724 bool remote_gw;
1725
1726 mac->uptime = monotime(NULL);
1727
1728 old_flags = mac->flags;
1729 sticky = !!CHECK_FLAG(old_flags, ZEBRA_MAC_STICKY);
1730 remote_gw = !!CHECK_FLAG(old_flags, ZEBRA_MAC_REMOTE_DEF_GW);
1731 if (sticky || remote_gw) {
1732 if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
1733 zlog_debug(
1734 "Ignore sync-macip vni %u mac %pEA%s%s%s%s",
1735 zevpn->vni, macaddr,
1736 ipa_len ? " IP " : "",
1737 ipa_len ? ipaddr2str(ipaddr, ipbuf,
1738 sizeof(ipbuf))
1739 : "",
1740 sticky ? " sticky" : "",
1741 remote_gw ? " remote_gw" : "");
1742 return NULL;
1743 }
1744 if (!zebra_evpn_mac_is_bgp_seq_ok(zevpn, mac, seq, true))
1745 return NULL;
1746
1747 old_local = !!CHECK_FLAG(old_flags, ZEBRA_MAC_LOCAL);
1748 old_static = zebra_evpn_mac_is_static(mac);
1749
1750 /* re-build the mac flags */
1751 new_flags = 0;
1752 SET_FLAG(new_flags, ZEBRA_MAC_LOCAL);
1753 /* retain old local activity flag */
1754 if (old_flags & ZEBRA_MAC_LOCAL)
1755 new_flags |= (old_flags & ZEBRA_MAC_LOCAL_INACTIVE);
1756 else
1757 new_flags |= ZEBRA_MAC_LOCAL_INACTIVE;
1758
1759 if (ipa_len) {
1760 /* if mac-ip route do NOT update the peer flags
1761 * i.e. retain only flags as is
1762 */
1763 new_flags |= (old_flags & ZEBRA_MAC_ALL_PEER_FLAGS);
1764 } else {
1765 /* if mac-only route update peer flags */
1766 if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT)) {
1767 SET_FLAG(new_flags, ZEBRA_MAC_ES_PEER_PROXY);
1768 /* if the mac was peer-active previously we
1769 * need to keep the flag and start the
1770 * holdtimer on it. the peer-active flag is
1771 * cleared on holdtimer expiry.
1772 */
1773 if (CHECK_FLAG(old_flags,
1774 ZEBRA_MAC_ES_PEER_ACTIVE)) {
1775 SET_FLAG(new_flags,
1776 ZEBRA_MAC_ES_PEER_ACTIVE);
1777 zebra_evpn_mac_start_hold_timer(mac);
1778 }
1779 } else {
1780 SET_FLAG(new_flags, ZEBRA_MAC_ES_PEER_ACTIVE);
1781 /* stop hold timer if a peer has verified
1782 * reachability
1783 */
1784 zebra_evpn_mac_stop_hold_timer(mac);
1785 }
1786 }
1787 mac->rem_seq = 0;
1788 zebra_evpn_mac_clear_fwd_info(mac);
1789 mac->flags = new_flags;
1790
1791 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC && (old_flags != new_flags)) {
1792 char mac_buf[MAC_BUF_SIZE], omac_buf[MAC_BUF_SIZE];
1793 struct zebra_mac omac;
1794
1795 omac.flags = old_flags;
1796 zlog_debug(
1797 "sync-mac vni %u mac %pEA old_f %snew_f %s",
1798 zevpn->vni, macaddr,
1799 zebra_evpn_zebra_mac_flag_dump(
1800 &omac, omac_buf, sizeof(omac_buf)),
1801 zebra_evpn_zebra_mac_flag_dump(
1802 mac, mac_buf, sizeof(mac_buf)));
1803 }
1804
1805 /* update es */
1806 es_change = zebra_evpn_es_mac_ref(mac, esi);
1807 /* if mac dest change - inform both sides */
1808 if (es_change) {
1809 inform_bgp = true;
1810 inform_dataplane = true;
1811 }
1812
1813 /* if peer-flag is being set notify dataplane that the
1814 * entry must not be expired because of local inactivity
1815 */
1816 new_static = zebra_evpn_mac_is_static(mac);
1817 if (old_static != new_static)
1818 inform_dataplane = true;
1819
1820 old_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(old_flags);
1821 new_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
1822 if (old_bgp_ready != new_bgp_ready)
1823 inform_bgp = true;
1824 }
1825
1826
1827 /* update sequence number; if that results in a new local sequence
1828 * inform bgp
1829 */
1830 tmp_seq = MAX(mac->loc_seq, seq);
1831 if (tmp_seq != mac->loc_seq) {
1832 mac->loc_seq = tmp_seq;
1833 seq_change = true;
1834 inform_bgp = true;
1835 }
1836
1837 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
1838 char mac_buf[MAC_BUF_SIZE];
1839
1840 zlog_debug("sync-mac %s vni %u mac %pEA es %s seq %d f %s%s%s",
1841 created ? "created" : "updated", zevpn->vni, macaddr,
1842 mac->es ? mac->es->esi_str : "-", mac->loc_seq,
1843 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
1844 sizeof(mac_buf)),
1845 inform_bgp ? "inform_bgp" : "",
1846 inform_dataplane ? " inform_dp" : "");
1847 }
1848
1849 if (inform_bgp)
1850 zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready,
1851 new_bgp_ready);
1852
1853 /* neighs using the mac may need to be re-sent to
1854 * bgp with updated info
1855 */
1856 if (seq_change || es_change || !old_local)
1857 zebra_evpn_process_neigh_on_local_mac_change(
1858 zevpn, mac, seq_change, es_change);
1859
1860 if (inform_dataplane && !ipa_len) {
1861 /* program the local mac in the kernel. when the ES
1862 * change we need to force the dataplane to reset
1863 * the activity as we are yet to establish activity
1864 * locally
1865 */
1866 zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */,
1867 false /* force_clear_static */,
1868 __func__);
1869 }
1870
1871 return mac;
1872 }
1873
1874 /* update local forwarding info. return true if a dest-ES change
1875 * is detected
1876 */
1877 static bool zebra_evpn_local_mac_update_fwd_info(struct zebra_mac *mac,
1878 struct interface *ifp,
1879 vlanid_t vid)
1880 {
1881 struct zebra_if *zif = ifp->info;
1882 bool es_change;
1883 ns_id_t local_ns_id = NS_DEFAULT;
1884 struct zebra_vrf *zvrf;
1885 struct zebra_evpn_es *es;
1886
1887 zvrf = ifp->vrf->info;
1888 if (zvrf && zvrf->zns)
1889 local_ns_id = zvrf->zns->ns_id;
1890
1891 zebra_evpn_mac_clear_fwd_info(mac);
1892
1893 es = zif->es_info.es;
1894 if (es && (es->flags & ZEBRA_EVPNES_BYPASS))
1895 es = NULL;
1896 es_change = zebra_evpn_es_mac_ref_entry(mac, es);
1897
1898 if (!mac->es) {
1899 /* if es is set fwd_info is not-relevant/taped-out */
1900 mac->fwd_info.local.ifindex = ifp->ifindex;
1901 mac->fwd_info.local.ns_id = local_ns_id;
1902 mac->fwd_info.local.vid = vid;
1903 zebra_evpn_mac_ifp_link(mac, ifp);
1904 }
1905
1906 return es_change;
1907 }
1908
1909 /* Notify Local MACs to the clienti, skips GW MAC */
1910 static void zebra_evpn_send_mac_hash_entry_to_client(struct hash_bucket *bucket,
1911 void *arg)
1912 {
1913 struct mac_walk_ctx *wctx = arg;
1914 struct zebra_mac *zmac = bucket->data;
1915
1916 if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_DEF_GW))
1917 return;
1918
1919 if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_LOCAL))
1920 zebra_evpn_mac_send_add_to_client(wctx->zevpn->vni,
1921 &zmac->macaddr, zmac->flags,
1922 zmac->loc_seq, zmac->es);
1923 }
1924
1925 /* Iterator to Notify Local MACs of a EVPN */
1926 void zebra_evpn_send_mac_list_to_client(struct zebra_evpn *zevpn)
1927 {
1928 struct mac_walk_ctx wctx;
1929
1930 if (!zevpn->mac_table)
1931 return;
1932
1933 memset(&wctx, 0, sizeof(wctx));
1934 wctx.zevpn = zevpn;
1935
1936 hash_iterate(zevpn->mac_table, zebra_evpn_send_mac_hash_entry_to_client,
1937 &wctx);
1938 }
1939
1940 void zebra_evpn_rem_mac_del(struct zebra_evpn *zevpn, struct zebra_mac *mac)
1941 {
1942 zebra_evpn_process_neigh_on_remote_mac_del(zevpn, mac);
1943 /* the remote sequence number in the auto mac entry
1944 * needs to be reset to 0 as the mac entry may have
1945 * been removed on all VTEPs (including
1946 * the originating one)
1947 */
1948 mac->rem_seq = 0;
1949
1950 /* If all remote neighbors referencing a remote MAC
1951 * go away, we need to uninstall the MAC.
1952 */
1953 if (remote_neigh_count(mac) == 0) {
1954 zebra_evpn_rem_mac_uninstall(zevpn, mac, false /*force*/);
1955 zebra_evpn_es_mac_deref_entry(mac);
1956 UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
1957 }
1958
1959 if (list_isempty(mac->neigh_list))
1960 zebra_evpn_mac_del(zevpn, mac);
1961 else
1962 SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
1963 }
1964
1965 /* Print Duplicate MAC */
1966 void zebra_evpn_print_dad_mac_hash(struct hash_bucket *bucket, void *ctxt)
1967 {
1968 struct zebra_mac *mac;
1969
1970 mac = (struct zebra_mac *)bucket->data;
1971 if (!mac)
1972 return;
1973
1974 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
1975 zebra_evpn_print_mac_hash(bucket, ctxt);
1976 }
1977
1978 /* Print Duplicate MAC in detail */
1979 void zebra_evpn_print_dad_mac_hash_detail(struct hash_bucket *bucket,
1980 void *ctxt)
1981 {
1982 struct zebra_mac *mac;
1983
1984 mac = (struct zebra_mac *)bucket->data;
1985 if (!mac)
1986 return;
1987
1988 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
1989 zebra_evpn_print_mac_hash_detail(bucket, ctxt);
1990 }
1991
1992 int zebra_evpn_mac_remote_macip_add(struct zebra_evpn *zevpn,
1993 struct zebra_vrf *zvrf,
1994 const struct ethaddr *macaddr,
1995 struct in_addr vtep_ip, uint8_t flags,
1996 uint32_t seq, const esi_t *esi)
1997 {
1998 bool sticky;
1999 bool remote_gw;
2000 int update_mac = 0;
2001 bool do_dad = false;
2002 bool is_dup_detect = false;
2003 esi_t *old_esi;
2004 bool old_static = false;
2005 struct zebra_mac *mac;
2006 bool old_es_present;
2007 bool new_es_present;
2008
2009 sticky = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
2010 remote_gw = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
2011
2012 mac = zebra_evpn_mac_lookup(zevpn, macaddr);
2013
2014 /* Ignore if the mac is already present as a gateway mac */
2015 if (mac && CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW)
2016 && CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW)) {
2017 if (IS_ZEBRA_DEBUG_VXLAN)
2018 zlog_debug(
2019 "Ignore remote MACIP ADD VNI %u MAC %pEA as MAC is already configured as gateway MAC",
2020 zevpn->vni, macaddr);
2021 return -1;
2022 }
2023
2024 old_esi = (mac && mac->es) ? &mac->es->esi : zero_esi;
2025
2026 /* check if the remote MAC is unknown or has a change.
2027 * If so, that needs to be updated first. Note that client could
2028 * install MAC and MACIP separately or just install the latter.
2029 */
2030 if (!mac || !CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
2031 || sticky != !!CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)
2032 || remote_gw != !!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW)
2033 || !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &vtep_ip)
2034 || memcmp(old_esi, esi, sizeof(esi_t)) || seq != mac->rem_seq)
2035 update_mac = 1;
2036
2037 if (update_mac) {
2038 if (!mac) {
2039 mac = zebra_evpn_mac_add(zevpn, macaddr);
2040 zebra_evpn_es_mac_ref(mac, esi);
2041 } else {
2042 /* When host moves but changes its (MAC,IP)
2043 * binding, BGP may install a MACIP entry that
2044 * corresponds to "older" location of the host
2045 * in transient situations (because {IP1,M1}
2046 * is a different route from {IP1,M2}). Check
2047 * the sequence number and ignore this update
2048 * if appropriate.
2049 */
2050 if (!zebra_evpn_mac_is_bgp_seq_ok(zevpn, mac, seq,
2051 false))
2052 return -1;
2053
2054 old_es_present = !!mac->es;
2055 zebra_evpn_es_mac_ref(mac, esi);
2056 new_es_present = !!mac->es;
2057 /* XXX - dataplane is curently not able to handle a MAC
2058 * replace if the destination changes from L2-NHG to
2059 * single VTEP and vice-versa. So delete the old entry
2060 * and re-install
2061 */
2062 if (old_es_present != new_es_present)
2063 zebra_evpn_rem_mac_uninstall(zevpn, mac, false);
2064 }
2065
2066 /* Check MAC's curent state is local (this is the case
2067 * where MAC has moved from L->R) and check previous
2068 * detection started via local learning.
2069 * RFC-7432: A PE/VTEP that detects a MAC mobility
2070 * event via local learning starts an M-second timer.
2071 *
2072 * VTEP-IP or seq. change alone is not considered
2073 * for dup. detection.
2074 *
2075 * MAC is already marked duplicate set dad, then
2076 * is_dup_detect will be set to not install the entry.
2077 */
2078 if ((!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
2079 && mac->dad_count)
2080 || CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
2081 do_dad = true;
2082
2083 /* Remove local MAC from BGP. */
2084 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
2085 /* force drop the sync flags */
2086 old_static = zebra_evpn_mac_is_static(mac);
2087 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
2088 char mac_buf[MAC_BUF_SIZE];
2089
2090 zlog_debug(
2091 "sync-mac->remote vni %u mac %pEA es %s seq %d f %s",
2092 zevpn->vni, macaddr,
2093 mac->es ? mac->es->esi_str : "-",
2094 mac->loc_seq,
2095 zebra_evpn_zebra_mac_flag_dump(
2096 mac, mac_buf, sizeof(mac_buf)));
2097 }
2098
2099 zebra_evpn_mac_clear_sync_info(mac);
2100 zebra_evpn_mac_send_del_to_client(zevpn->vni, macaddr,
2101 mac->flags,
2102 false /* force */);
2103 }
2104
2105 /* Set "auto" and "remote" forwarding info. */
2106 zebra_evpn_mac_clear_fwd_info(mac);
2107 UNSET_FLAG(mac->flags, ZEBRA_MAC_ALL_LOCAL_FLAGS);
2108 SET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
2109 mac->fwd_info.r_vtep_ip = vtep_ip;
2110
2111 if (sticky)
2112 SET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
2113 else
2114 UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
2115
2116 if (remote_gw)
2117 SET_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW);
2118 else
2119 UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW);
2120
2121 zebra_evpn_dup_addr_detect_for_mac(
2122 zvrf, mac, mac->fwd_info.r_vtep_ip, do_dad,
2123 &is_dup_detect, false);
2124
2125 if (!is_dup_detect) {
2126 zebra_evpn_process_neigh_on_remote_mac_add(zevpn, mac);
2127 /* Install the entry. */
2128 zebra_evpn_rem_mac_install(zevpn, mac, old_static);
2129 }
2130 }
2131
2132 /* Update seq number. */
2133 mac->rem_seq = seq;
2134
2135 UNSET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
2136 return 0;
2137 }
2138
2139 int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf,
2140 struct zebra_evpn *zevpn,
2141 struct interface *ifp,
2142 const struct ethaddr *macaddr, vlanid_t vid,
2143 bool sticky, bool local_inactive,
2144 bool dp_static, struct zebra_mac *mac)
2145 {
2146 bool mac_sticky = false;
2147 bool inform_client = false;
2148 bool upd_neigh = false;
2149 bool is_dup_detect = false;
2150 struct in_addr vtep_ip = {.s_addr = 0};
2151 bool es_change = false;
2152 bool new_bgp_ready;
2153 /* assume inactive if not present or if not local */
2154 bool old_local_inactive = true;
2155 bool old_bgp_ready = false;
2156 bool inform_dataplane = false;
2157 bool new_static = false;
2158
2159 assert(ifp);
2160 /* Check if we need to create or update or it is a NO-OP. */
2161 if (!mac)
2162 mac = zebra_evpn_mac_lookup(zevpn, macaddr);
2163 if (!mac) {
2164 if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC)
2165 zlog_debug(
2166 "ADD %sMAC %pEA intf %s(%u) VID %u -> VNI %u%s",
2167 sticky ? "sticky " : "", macaddr,
2168 ifp->name, ifp->ifindex, vid, zevpn->vni,
2169 local_inactive ? " local-inactive" : "");
2170
2171 mac = zebra_evpn_mac_add(zevpn, macaddr);
2172 SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
2173 es_change = zebra_evpn_local_mac_update_fwd_info(mac, ifp, vid);
2174 if (sticky)
2175 SET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
2176 inform_client = true;
2177 } else {
2178 if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
2179 char mac_buf[MAC_BUF_SIZE];
2180
2181 zlog_debug(
2182 "UPD %sMAC %pEA intf %s(%u) VID %u -> VNI %u %scurFlags %s",
2183 sticky ? "sticky " : "", macaddr,
2184 ifp->name, ifp->ifindex, vid, zevpn->vni,
2185 local_inactive ? "local-inactive " : "",
2186 zebra_evpn_zebra_mac_flag_dump(
2187 mac, mac_buf, sizeof(mac_buf)));
2188 }
2189
2190 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
2191 struct interface *old_ifp;
2192 vlanid_t old_vid;
2193 bool old_static;
2194
2195 zebra_evpn_mac_get_access_info(mac, &old_ifp, &old_vid);
2196 old_bgp_ready =
2197 zebra_evpn_mac_is_ready_for_bgp(mac->flags);
2198 old_local_inactive =
2199 !!(mac->flags & ZEBRA_MAC_LOCAL_INACTIVE);
2200 old_static = zebra_evpn_mac_is_static(mac);
2201 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY))
2202 mac_sticky = true;
2203 es_change = zebra_evpn_local_mac_update_fwd_info(
2204 mac, ifp, vid);
2205
2206 /*
2207 * Update any changes and if changes are relevant to
2208 * BGP, note it.
2209 */
2210 if (mac_sticky == sticky && old_ifp == ifp
2211 && old_vid == vid
2212 && old_local_inactive == local_inactive
2213 && dp_static == old_static && !es_change) {
2214 if (IS_ZEBRA_DEBUG_VXLAN)
2215 zlog_debug(
2216 " Add/Update %sMAC %pEA intf %s(%u) VID %u -> VNI %u%s, "
2217 "entry exists and has not changed ",
2218 sticky ? "sticky " : "",
2219 macaddr, ifp->name,
2220 ifp->ifindex, vid, zevpn->vni,
2221 local_inactive
2222 ? " local_inactive"
2223 : "");
2224 return 0;
2225 }
2226 if (mac_sticky != sticky) {
2227 if (sticky)
2228 SET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
2229 else
2230 UNSET_FLAG(mac->flags,
2231 ZEBRA_MAC_STICKY);
2232 inform_client = true;
2233 }
2234
2235 /* If an es_change is detected we need to advertise
2236 * the route with a sequence that is one
2237 * greater. This is need to indicate a mac-move
2238 * to the ES peers
2239 */
2240 if (es_change) {
2241 /* update the sequence number only if the entry
2242 * is locally active
2243 */
2244 if (!local_inactive)
2245 mac->loc_seq = mac->loc_seq + 1;
2246 /* force drop the peer/sync info as it is
2247 * simply no longer relevant
2248 */
2249 if (CHECK_FLAG(mac->flags,
2250 ZEBRA_MAC_ALL_PEER_FLAGS)) {
2251 zebra_evpn_mac_clear_sync_info(mac);
2252 new_static =
2253 zebra_evpn_mac_is_static(mac);
2254 /* if we clear peer-flags we
2255 * also need to notify the dataplane
2256 * to drop the static flag
2257 */
2258 if (old_static != new_static)
2259 inform_dataplane = true;
2260 }
2261 }
2262 } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
2263 || CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) {
2264 bool do_dad = false;
2265
2266 /*
2267 * MAC has either moved or was "internally" created due
2268 * to a neighbor learn and is now actually learnt. If
2269 * it was learnt as a remote sticky MAC, this is an
2270 * operator error.
2271 */
2272 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)) {
2273 flog_warn(
2274 EC_ZEBRA_STICKY_MAC_ALREADY_LEARNT,
2275 "MAC %pEA already learnt as remote sticky MAC behind VTEP %pI4 VNI %u",
2276 macaddr,
2277 &mac->fwd_info.r_vtep_ip,
2278 zevpn->vni);
2279 return 0;
2280 }
2281
2282 /* If an actual move, compute MAC's seq number */
2283 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
2284 mac->loc_seq =
2285 MAX(mac->rem_seq + 1, mac->loc_seq);
2286 vtep_ip = mac->fwd_info.r_vtep_ip;
2287 /* Trigger DAD for remote MAC */
2288 do_dad = true;
2289 }
2290
2291 UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
2292 UNSET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
2293 SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
2294 es_change = zebra_evpn_local_mac_update_fwd_info(
2295 mac, ifp, vid);
2296 if (sticky)
2297 SET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
2298 else
2299 UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
2300 /*
2301 * We have to inform BGP of this MAC as well as process
2302 * all neighbors.
2303 */
2304 inform_client = true;
2305 upd_neigh = true;
2306
2307 zebra_evpn_dup_addr_detect_for_mac(
2308 zvrf, mac, vtep_ip, do_dad, &is_dup_detect,
2309 true);
2310 if (is_dup_detect) {
2311 inform_client = false;
2312 upd_neigh = false;
2313 es_change = false;
2314 }
2315 }
2316 }
2317
2318 /* if the dataplane thinks the entry is sync but it is
2319 * not sync in zebra (or vice-versa) we need to re-install
2320 * to fixup
2321 */
2322 new_static = zebra_evpn_mac_is_static(mac);
2323 if (dp_static != new_static)
2324 inform_dataplane = true;
2325
2326 if (local_inactive)
2327 SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE);
2328 else
2329 UNSET_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE);
2330
2331 new_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
2332 /* if local-activity has changed we need update bgp
2333 * even if bgp already knows about the mac
2334 */
2335 if ((old_local_inactive != local_inactive)
2336 || (new_bgp_ready != old_bgp_ready)) {
2337 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
2338 char mac_buf[MAC_BUF_SIZE];
2339
2340 zlog_debug(
2341 "local mac vni %u mac %pEA es %s seq %d f %s%s",
2342 zevpn->vni, macaddr,
2343 mac->es ? mac->es->esi_str : "", mac->loc_seq,
2344 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
2345 sizeof(mac_buf)),
2346 local_inactive ? "local-inactive" : "");
2347 }
2348
2349 if (!is_dup_detect)
2350 inform_client = true;
2351 }
2352
2353 if (es_change) {
2354 inform_client = true;
2355 upd_neigh = true;
2356 }
2357
2358 /* Inform dataplane if required. */
2359 if (inform_dataplane)
2360 zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */,
2361 false /* force_clear_static */,
2362 __func__);
2363
2364 /* Inform BGP if required. */
2365 if (inform_client)
2366 zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready,
2367 new_bgp_ready);
2368
2369 /* Process all neighbors associated with this MAC, if required. */
2370 if (upd_neigh)
2371 zebra_evpn_process_neigh_on_local_mac_change(zevpn, mac, 0,
2372 es_change);
2373
2374 return 0;
2375 }
2376
2377 int zebra_evpn_del_local_mac(struct zebra_evpn *zevpn, struct zebra_mac *mac,
2378 bool clear_static)
2379 {
2380 bool old_bgp_ready;
2381 bool new_bgp_ready;
2382
2383 if (IS_ZEBRA_DEBUG_VXLAN)
2384 zlog_debug("DEL MAC %pEA VNI %u seq %u flags 0x%x nbr count %u",
2385 &mac->macaddr, zevpn->vni, mac->loc_seq, mac->flags,
2386 listcount(mac->neigh_list));
2387
2388 old_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
2389 if (!clear_static && zebra_evpn_mac_is_static(mac)) {
2390 /* this is a synced entry and can only be removed when the
2391 * es-peers stop advertising it.
2392 */
2393 zebra_evpn_mac_clear_fwd_info(mac);
2394
2395 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
2396 char mac_buf[MAC_BUF_SIZE];
2397
2398 zlog_debug(
2399 "re-add sync-mac vni %u mac %pEA es %s seq %d f %s",
2400 zevpn->vni, &mac->macaddr,
2401 mac->es ? mac->es->esi_str : "-", mac->loc_seq,
2402 zebra_evpn_zebra_mac_flag_dump(
2403 mac, mac_buf, sizeof(mac_buf)));
2404 }
2405
2406 /* inform-bgp about change in local-activity if any */
2407 if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE)) {
2408 SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE);
2409 new_bgp_ready =
2410 zebra_evpn_mac_is_ready_for_bgp(mac->flags);
2411 zebra_evpn_mac_send_add_del_to_client(
2412 mac, old_bgp_ready, new_bgp_ready);
2413 }
2414
2415 /* re-install the inactive entry in the kernel */
2416 zebra_evpn_sync_mac_dp_install(mac, true /* set_inactive */,
2417 false /* force_clear_static */,
2418 __func__);
2419
2420 return 0;
2421 }
2422
2423 /* flush the peer info */
2424 zebra_evpn_mac_clear_sync_info(mac);
2425
2426 /* Update all the neigh entries associated with this mac */
2427 zebra_evpn_process_neigh_on_local_mac_del(zevpn, mac);
2428
2429 /* Remove MAC from BGP. */
2430 zebra_evpn_mac_send_del_to_client(zevpn->vni, &mac->macaddr, mac->flags,
2431 false /* force */);
2432
2433 zebra_evpn_es_mac_deref_entry(mac);
2434
2435 /* remove links to the destination access port */
2436 zebra_evpn_mac_clear_fwd_info(mac);
2437
2438 /*
2439 * If there are no neigh associated with the mac delete the mac
2440 * else mark it as AUTO for forward reference
2441 */
2442 if (!listcount(mac->neigh_list)) {
2443 zebra_evpn_mac_del(zevpn, mac);
2444 } else {
2445 UNSET_FLAG(mac->flags, ZEBRA_MAC_ALL_LOCAL_FLAGS);
2446 UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
2447 SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
2448 }
2449
2450 return 0;
2451 }
2452
2453 void zebra_evpn_mac_gw_macip_add(struct interface *ifp,
2454 struct zebra_evpn *zevpn,
2455 const struct ipaddr *ip,
2456 struct zebra_mac **macp,
2457 const struct ethaddr *macaddr,
2458 vlanid_t vlan_id, bool def_gw)
2459 {
2460 struct zebra_mac *mac;
2461 ns_id_t local_ns_id = NS_DEFAULT;
2462 struct zebra_vrf *zvrf;
2463
2464 zvrf = ifp->vrf->info;
2465 if (zvrf && zvrf->zns)
2466 local_ns_id = zvrf->zns->ns_id;
2467
2468 if (!*macp) {
2469 mac = zebra_evpn_mac_lookup(zevpn, macaddr);
2470 if (!mac)
2471 mac = zebra_evpn_mac_add(zevpn, macaddr);
2472 *macp = mac;
2473 } else
2474 mac = *macp;
2475
2476 /* Set "local" forwarding info. */
2477 zebra_evpn_mac_clear_fwd_info(mac);
2478 SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
2479 SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
2480 if (def_gw)
2481 SET_FLAG(mac->flags, ZEBRA_MAC_DEF_GW);
2482 else
2483 SET_FLAG(mac->flags, ZEBRA_MAC_SVI);
2484 mac->fwd_info.local.ifindex = ifp->ifindex;
2485 mac->fwd_info.local.ns_id = local_ns_id;
2486 mac->fwd_info.local.vid = vlan_id;
2487 }
2488
2489 void zebra_evpn_mac_svi_del(struct interface *ifp, struct zebra_evpn *zevpn)
2490 {
2491 struct zebra_mac *mac;
2492 struct ethaddr macaddr;
2493 bool old_bgp_ready;
2494
2495 if (!zebra_evpn_mh_do_adv_svi_mac())
2496 return;
2497
2498 memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN);
2499 mac = zebra_evpn_mac_lookup(zevpn, &macaddr);
2500 if (mac && CHECK_FLAG(mac->flags, ZEBRA_MAC_SVI)) {
2501 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
2502 zlog_debug("SVI %s mac free", ifp->name);
2503
2504 old_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
2505 UNSET_FLAG(mac->flags, ZEBRA_MAC_SVI);
2506 zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready,
2507 false);
2508 zebra_evpn_deref_ip2mac(mac->zevpn, mac);
2509 }
2510 }
2511
2512 void zebra_evpn_mac_svi_add(struct interface *ifp, struct zebra_evpn *zevpn)
2513 {
2514 struct zebra_mac *mac = NULL;
2515 struct ethaddr macaddr;
2516 struct zebra_if *zif = ifp->info;
2517 bool old_bgp_ready;
2518 bool new_bgp_ready;
2519
2520 if (!zebra_evpn_mh_do_adv_svi_mac()
2521 || !zebra_evpn_send_to_client_ok(zevpn))
2522 return;
2523
2524 memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN);
2525
2526 /* dup check */
2527 mac = zebra_evpn_mac_lookup(zevpn, &macaddr);
2528 if (mac && CHECK_FLAG(mac->flags, ZEBRA_MAC_SVI))
2529 return;
2530
2531 /* add/update mac */
2532 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
2533 zlog_debug("SVI %s mac add", zif->ifp->name);
2534
2535 old_bgp_ready = (mac && zebra_evpn_mac_is_ready_for_bgp(mac->flags))
2536 ? true
2537 : false;
2538
2539 zebra_evpn_mac_gw_macip_add(ifp, zevpn, NULL, &mac, &macaddr, 0, false);
2540
2541 new_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
2542 zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready,
2543 new_bgp_ready);
2544 }