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