]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_evpn_mac.c
Merge pull request #11852 from gpnaveen/bgp_admin_dist
[mirror_frr.git] / zebra / zebra_evpn_mac.c
CommitLineData
24268cd0
PR
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"
b2998086 26#include "interface.h"
24268cd0 27#include "jhash.h"
24268cd0
PR
28#include "memory.h"
29#include "prefix.h"
24268cd0 30#include "vlan.h"
b2998086 31#include "json.h"
bf902d4c 32#include "printfrr.h"
24268cd0 33
b2998086 34#include "zebra/zserv.h"
24268cd0 35#include "zebra/debug.h"
b2998086 36#include "zebra/zebra_router.h"
b2998086 37#include "zebra/zebra_errors.h"
24268cd0 38#include "zebra/zebra_vrf.h"
b2998086 39#include "zebra/zebra_evpn.h"
24268cd0 40#include "zebra/zebra_evpn_mh.h"
b2998086
PR
41#include "zebra/zebra_evpn_mac.h"
42#include "zebra/zebra_evpn_neigh.h"
24268cd0 43
24268cd0 44DEFINE_MTYPE_STATIC(ZEBRA, MAC, "EVPN MAC");
24268cd0
PR
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 */
f6371c34 50uint32_t num_valid_macs(struct zebra_evpn *zevpn)
24268cd0
PR
51{
52 unsigned int i;
53 uint32_t num_macs = 0;
54 struct hash *hash;
55 struct hash_bucket *hb;
3198b2b3 56 struct zebra_mac *mac;
24268cd0
PR
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) {
3198b2b3 63 mac = (struct zebra_mac *)hb->data;
24268cd0
PR
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
f6371c34 74uint32_t num_dup_detected_macs(struct zebra_evpn *zevpn)
24268cd0
PR
75{
76 unsigned int i;
77 uint32_t num_macs = 0;
78 struct hash *hash;
79 struct hash_bucket *hb;
3198b2b3 80 struct zebra_mac *mac;
24268cd0
PR
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) {
3198b2b3 87 mac = (struct zebra_mac *)hb->data;
24268cd0
PR
88 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
89 num_macs++;
90 }
91 }
92
93 return num_macs;
94}
95
8b07f173
AK
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 */
99static 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
8b07f173 109/* Unlink local mac from a destination access port */
3198b2b3 110static void zebra_evpn_mac_ifp_unlink(struct zebra_mac *zmac)
8b07f173
AK
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
51aa2693
AK
129/* Free up the mac_list if any as a part of the interface del/cleanup */
130void 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
8b07f173
AK
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 */
3198b2b3
DS
152static void zebra_evpn_mac_ifp_link(struct zebra_mac *zmac,
153 struct interface *ifp)
8b07f173
AK
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 */
3198b2b3 188void zebra_evpn_mac_clear_fwd_info(struct zebra_mac *zmac)
8b07f173
AK
189{
190 zebra_evpn_mac_ifp_unlink(zmac);
191 memset(&zmac->fwd_info, 0, sizeof(zmac->fwd_info));
192}
193
b2998086
PR
194/*
195 * Install remote MAC into the forwarding plane.
196 */
3198b2b3 197int zebra_evpn_rem_mac_install(struct zebra_evpn *zevpn, struct zebra_mac *mac,
b2998086 198 bool was_static)
24268cd0 199{
b2998086
PR
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;
24268cd0 208
b2998086
PR
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;
24268cd0
PR
233 }
234
b2998086
PR
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;
24268cd0
PR
248}
249
b2998086
PR
250/*
251 * Uninstall remote MAC from the forwarding plane.
252 */
3198b2b3
DS
253int zebra_evpn_rem_mac_uninstall(struct zebra_evpn *zevpn,
254 struct zebra_mac *mac, bool force)
24268cd0 255{
b2998086
PR
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;
24268cd0 262
f3722826
AK
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
b2998086
PR
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 }
24268cd0 274
b2998086
PR
275 zif = zevpn->vxlan_if->info;
276 if (!zif)
277 return -1;
24268cd0 278
b2998086
PR
279 br_ifp = zif->brslave_info.br_if;
280 if (br_ifp == NULL)
281 return -1;
24268cd0 282
b2998086 283 vxl = &zif->l2info.vxl;
24268cd0 284
b2998086 285 br_zif = (const struct zebra_if *)br_ifp->info;
24268cd0 286
b2998086
PR
287 if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif))
288 vid = vxl->access_vlan;
289 else
290 vid = 0;
24268cd0 291
b2998086
PR
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;
24268cd0
PR
300}
301
b2998086
PR
302/*
303 * Decrement neighbor refcount of MAC; uninstall and free it if
304 * appropriate.
24268cd0 305 */
3198b2b3 306void zebra_evpn_deref_ip2mac(struct zebra_evpn *zevpn, struct zebra_mac *mac)
24268cd0 307{
b2998086
PR
308 if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO))
309 return;
24268cd0 310
b2998086
PR
311 /* If all remote neighbors referencing a remote MAC go away,
312 * we need to uninstall the MAC.
24268cd0 313 */
b2998086
PR
314 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
315 && remote_neigh_count(mac) == 0) {
f3722826 316 zebra_evpn_rem_mac_uninstall(zevpn, mac, false /*force*/);
b2998086
PR
317 zebra_evpn_es_mac_deref_entry(mac);
318 UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
319 }
320
243b74ed
AK
321 /* If no references, delete the MAC. */
322 if (!zebra_evpn_mac_in_use(mac))
b2998086
PR
323 zebra_evpn_mac_del(zevpn, mac);
324}
325
3198b2b3 326static void zebra_evpn_mac_get_access_info(struct zebra_mac *mac,
e3f05a8a 327 struct interface **p_ifp,
d9d3455e 328 vlanid_t *vid)
b2998086
PR
329{
330 /* if the mac is associated with an ES we must get the access
331 * info from the ES
24268cd0 332 */
b2998086
PR
333 if (mac->es) {
334 struct zebra_if *zif;
335
336 /* get the access port from the es */
e3f05a8a 337 *p_ifp = mac->es->zif ? mac->es->zif->ifp : NULL;
b2998086
PR
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;
47c58929 349 zns = zebra_ns_lookup(mac->fwd_info.local.ns_id);
e3f05a8a 350 *p_ifp = if_lookup_by_index_per_ns(zns,
351 mac->fwd_info.local.ifindex);
b2998086
PR
352 }
353}
354
b16e8004 355#define MAC_BUF_SIZE 256
3198b2b3 356static char *zebra_evpn_zebra_mac_flag_dump(struct zebra_mac *mac, char *buf,
b16e8004
DS
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 " : "",
0ef63eb5 377 CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE)
378 ? "PEER Active "
379 : "",
b16e8004
DS
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
cc9f21da 387static void zebra_evpn_dad_mac_auto_recovery_exp(struct thread *t)
b2998086
PR
388{
389 struct zebra_vrf *zvrf = NULL;
3198b2b3 390 struct zebra_mac *mac = NULL;
f6371c34 391 struct zebra_evpn *zevpn = NULL;
b2998086 392 struct listnode *node = NULL;
72de4110 393 struct zebra_neigh *nbr = NULL;
b2998086
PR
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)
cc9f21da 400 return;
b2998086 401
8b5fdf2e 402 zevpn = zebra_evpn_lookup(mac->zevpn->vni);
b2998086 403 if (!zevpn)
cc9f21da 404 return;
b2998086
PR
405
406 mac = zebra_evpn_mac_lookup(zevpn, &mac->macaddr);
407 if (!mac)
cc9f21da 408 return;
b2998086 409
b16e8004
DS
410 if (IS_ZEBRA_DEBUG_VXLAN) {
411 char mac_buf[MAC_BUF_SIZE];
412
b2998086 413 zlog_debug(
ef7b8be4
DL
414 "%s: duplicate addr mac %pEA flags %slearn count %u host count %u auto recovery expired",
415 __func__, &mac->macaddr,
b16e8004
DS
416 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
417 sizeof(mac_buf)),
418 mac->dad_count, listcount(mac->neigh_list));
419 }
b2998086
PR
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 }
24268cd0 430
24268cd0
PR
431 UNSET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE);
432 nbr->dad_count = 0;
433 nbr->detect_start_time.tv_sec = 0;
b2998086
PR
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))
cc9f21da 449 return;
b2998086
PR
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 */);
24268cd0 460 }
24268cd0
PR
461}
462
d9d3455e 463static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf,
3198b2b3 464 struct zebra_mac *mac,
d9d3455e
PR
465 struct in_addr vtep_ip,
466 bool do_dad, bool *is_dup_detect,
467 bool is_local)
24268cd0 468{
72de4110 469 struct zebra_neigh *nbr;
24268cd0
PR
470 struct listnode *node = NULL;
471 struct timeval elapsed = {0, 0};
24268cd0
PR
472 bool reset_params = false;
473
b2ee2b71 474 if (!(zebra_evpn_do_dup_addr_detect(zvrf) && do_dad))
24268cd0
PR
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)) {
b16e8004
DS
482 if (IS_ZEBRA_DEBUG_VXLAN) {
483 char mac_buf[MAC_BUF_SIZE];
484
24268cd0 485 zlog_debug(
ef7b8be4
DL
486 "%s: duplicate addr MAC %pEA flags %sskip update to client, learn count %u recover time %u",
487 __func__, &mac->macaddr,
b16e8004
DS
488 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
489 sizeof(mac_buf)),
490 mac->dad_count, zvrf->dad_freeze_time);
491 }
24268cd0
PR
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) {
b16e8004
DS
519 if (IS_ZEBRA_DEBUG_VXLAN) {
520 char mac_buf[MAC_BUF_SIZE];
521
24268cd0 522 zlog_debug(
ef7b8be4
DL
523 "%s: duplicate addr MAC %pEA flags %sdetection time passed, reset learn count %u",
524 __func__, &mac->macaddr,
b16e8004
DS
525 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
526 sizeof(mac_buf)),
527 mac->dad_count);
528 }
24268cd0
PR
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,
ef7b8be4
DL
554 "VNI %u: MAC %pEA detected as duplicate during %s VTEP %pI4",
555 mac->zevpn->vni, &mac->macaddr,
24268cd0 556 is_local ? "local update, last" :
9bcef951 557 "remote update, from", &vtep_ip);
24268cd0
PR
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,
ef7b8be4
DL
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,
24268cd0
PR
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) {
b16e8004
DS
586 if (IS_ZEBRA_DEBUG_VXLAN) {
587 char mac_buf[MAC_BUF_SIZE];
588
24268cd0 589 zlog_debug(
ef7b8be4
DL
590 "%s: duplicate addr MAC %pEA flags %sauto recovery time %u start",
591 __func__, &mac->macaddr,
b16e8004
DS
592 zebra_evpn_zebra_mac_flag_dump(
593 mac, mac_buf, sizeof(mac_buf)),
594 zvrf->dad_freeze_time);
595 }
24268cd0
PR
596
597 thread_add_timer(zrouter.master,
b2998086 598 zebra_evpn_dad_mac_auto_recovery_exp,
24268cd0
PR
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
b2998086
PR
611/*
612 * Print a specific MAC entry.
613 */
3198b2b3 614void zebra_evpn_print_mac(struct zebra_mac *mac, void *ctxt, json_object *json)
24268cd0 615{
b2998086 616 struct vty *vty;
72de4110 617 struct zebra_neigh *n = NULL;
b2998086
PR
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];
f1dbb1c7
DS
625 time_t uptime;
626 char up_str[MONOTIME_STRLEN];
24268cd0 627
b2998086 628 zvrf = zebra_vrf_get_evpn();
b2998086
PR
629 vty = (struct vty *)ctxt;
630 prefix_mac2str(&mac->macaddr, buf1, sizeof(buf1));
24268cd0 631
f1dbb1c7
DS
632 uptime = monotime(NULL);
633 uptime -= mac->uptime;
634
635 frrtime_to_interval(uptime, up_str, sizeof(up_str));
636
b2998086
PR
637 if (json) {
638 json_object *json_mac = json_object_new_object();
24268cd0 639
b2998086
PR
640 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
641 struct interface *ifp;
642 vlanid_t vid;
24268cd0 643
b2998086
PR
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");
08edf9c6
DA
656 json_object_string_addf(json_mac, "remoteVtep", "%pI4",
657 &mac->fwd_info.r_vtep_ip);
b2998086
PR
658 } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO))
659 json_object_string_add(json_mac, "type", "auto");
24268cd0 660
b2998086
PR
661 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY))
662 json_object_boolean_true_add(json_mac, "stickyMac");
24268cd0 663
243b74ed
AK
664 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_SVI))
665 json_object_boolean_true_add(json_mac, "sviMac");
666
b2998086
PR
667 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW))
668 json_object_boolean_true_add(json_mac,
669 "defaultGateway");
24268cd0 670
b2998086
PR
671 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW))
672 json_object_boolean_true_add(json_mac,
673 "remoteGatewayMac");
24268cd0 674
f1dbb1c7 675 json_object_string_add(json_mac, "uptime", up_str);
b2998086
PR
676 json_object_int_add(json_mac, "localSequence", mac->loc_seq);
677 json_object_int_add(json_mac, "remoteSequence", mac->rem_seq);
24268cd0 678
b2998086
PR
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");
24268cd0 684
b2998086
PR
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();
24268cd0 710
b2998086
PR
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 }
24268cd0 727
b2998086
PR
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);
24268cd0 734 }
24268cd0 735
b2998086
PR
736 json_object_object_add(json, buf1, json_mac);
737 } else {
738 vty_out(vty, "MAC: %s\n", buf1);
24268cd0 739
b2998086
PR
740 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
741 struct interface *ifp;
742 vlanid_t vid;
24268cd0 743
b2998086 744 zebra_evpn_mac_get_access_info(mac, &ifp, &vid);
24268cd0 745
b2998086
PR
746 if (mac->es)
747 vty_out(vty, " ESI: %s\n", mac->es->esi_str);
24268cd0 748
b2998086
PR
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
9bcef951
MS
760 vty_out(vty, " Remote VTEP: %pI4",
761 &mac->fwd_info.r_vtep_ip);
b2998086
PR
762 } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) {
763 vty_out(vty, " Auto Mac ");
764 }
24268cd0 765
b2998086
PR
766 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY))
767 vty_out(vty, " Sticky Mac ");
24268cd0 768
243b74ed
AK
769 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_SVI))
770 vty_out(vty, " SVI-Mac ");
771
b2998086
PR
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))
24268cd0 781 vty_out(vty, " local-inactive");
b2998086 782 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY))
24268cd0 783 vty_out(vty, " peer-proxy");
b2998086 784 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE))
24268cd0 785 vty_out(vty, " peer-active");
b2998086 786 if (mac->hold_timer)
24268cd0 787 vty_out(vty, " (ht: %s)",
b2998086
PR
788 thread_timer_to_hhmmss(thread_buf,
789 sizeof(thread_buf),
790 mac->hold_timer));
791 vty_out(vty, "\n");
f1dbb1c7 792 vty_out(vty, " Local Seq: %u Remote Seq: %u\n", mac->loc_seq,
b2998086 793 mac->rem_seq);
f1dbb1c7 794 vty_out(vty, " Uptime: %s\n", up_str);
24268cd0 795
b2998086 796 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) {
24268cd0 797 vty_out(vty, " Duplicate, detected at %s",
b2998086 798 time_to_string(mac->dad_dup_detect_time,
24268cd0 799 timebuf));
b2998086
PR
800 } else if (mac->dad_count) {
801 monotime_since(&mac->detect_start_time,
24268cd0
PR
802 &detect_start_time);
803 if (detect_start_time.tv_sec <= zvrf->dad_time) {
b2998086 804 time_to_string(mac->detect_start_time.tv_sec,
24268cd0
PR
805 timebuf);
806 vty_out(vty,
807 " Duplicate detection started at %s, detection count %u\n",
b2998086 808 timebuf, mac->dad_count);
24268cd0
PR
809 }
810 }
24268cd0 811
b2998086
PR
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 }
24268cd0 825
b2998086 826 vty_out(vty, "\n");
24268cd0
PR
827 }
828}
829
3198b2b3 830static char *zebra_evpn_print_mac_flags(struct zebra_mac *mac, char *flags_buf,
700cae76 831 size_t flags_buf_sz)
24268cd0 832{
b2998086 833 snprintf(flags_buf, flags_buf_sz, "%s%s%s%s",
00a7710c
AK
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" : "");
24268cd0
PR
838
839 return flags_buf;
840}
841
842/*
b2998086 843 * Print MAC hash entry - called for display of all MACs.
24268cd0 844 */
b2998086 845void zebra_evpn_print_mac_hash(struct hash_bucket *bucket, void *ctxt)
24268cd0
PR
846{
847 struct vty *vty;
b2998086 848 json_object *json_mac_hdr = NULL, *json_mac = NULL;
3198b2b3 849 struct zebra_mac *mac;
24268cd0 850 char buf1[ETHER_ADDR_STRLEN];
9bcef951 851 char addr_buf[PREFIX_STRLEN];
b2998086 852 struct mac_walk_ctx *wctx = ctxt;
24268cd0
PR
853 char flags_buf[6];
854
855 vty = wctx->vty;
b2998086 856 json_mac_hdr = wctx->json;
3198b2b3 857 mac = (struct zebra_mac *)bucket->data;
b2998086
PR
858
859 prefix_mac2str(&mac->macaddr, buf1, sizeof(buf1));
860
861 if (json_mac_hdr)
862 json_mac = json_object_new_object();
24268cd0 863
b2998086
PR
864 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
865 struct interface *ifp;
866 vlanid_t vid;
24268cd0 867
b2998086 868 if (wctx->flags & SHOW_REMOTE_MAC_FROM_VTEP)
24268cd0
PR
869 return;
870
b2998086
PR
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");
24268cd0 894 } else {
b2998086
PR
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,
24268cd0
PR
903 "isDuplicate");
904 else
b2998086 905 json_object_boolean_false_add(json_mac,
24268cd0 906 "isDuplicate");
b2998086 907 json_object_object_add(json_mac_hdr, buf1, json_mac);
24268cd0 908 }
b2998086 909
24268cd0 910 wctx->count++;
b2998086
PR
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))
24268cd0
PR
917 return;
918
b2998086
PR
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");
24268cd0 927 }
9bcef951
MS
928 if (mac->es == NULL)
929 inet_ntop(AF_INET, &mac->fwd_info.r_vtep_ip,
930 addr_buf, sizeof(addr_buf));
931
b2998086
PR
932 vty_out(vty, "%-17s %-6s %-5s %-30s %-5s %u/%u\n", buf1,
933 "remote",
934 zebra_evpn_print_mac_flags(mac, flags_buf,
9bcef951
MS
935 sizeof(flags_buf)),
936 mac->es ? mac->es->esi_str : addr_buf,
b2998086
PR
937 "", mac->loc_seq, mac->rem_seq);
938 } else {
939 json_object_string_add(json_mac, "type", "remote");
08edf9c6
DA
940 json_object_string_addf(json_mac, "remoteVtep", "%pI4",
941 &mac->fwd_info.r_vtep_ip);
b2998086
PR
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 }
24268cd0 956
b2998086
PR
957 wctx->count++;
958 }
24268cd0
PR
959}
960
961/*
b2998086 962 * Print MAC hash entry in detail - called for display of all MACs.
24268cd0 963 */
b2998086 964void zebra_evpn_print_mac_hash_detail(struct hash_bucket *bucket, void *ctxt)
24268cd0 965{
b2998086
PR
966 struct vty *vty;
967 json_object *json_mac_hdr = NULL;
3198b2b3 968 struct zebra_mac *mac;
b2998086
PR
969 struct mac_walk_ctx *wctx = ctxt;
970 char buf1[ETHER_ADDR_STRLEN];
24268cd0 971
b2998086
PR
972 vty = wctx->vty;
973 json_mac_hdr = wctx->json;
3198b2b3 974 mac = (struct zebra_mac *)bucket->data;
b2998086 975 if (!mac)
24268cd0
PR
976 return;
977
b2998086
PR
978 wctx->count++;
979 prefix_mac2str(&mac->macaddr, buf1, sizeof(buf1));
24268cd0 980
b2998086 981 zebra_evpn_print_mac(mac, vty, json_mac_hdr);
24268cd0
PR
982}
983
984/*
b2998086 985 * Inform BGP about local MACIP.
24268cd0 986 */
7f7e49d1
MS
987int zebra_evpn_macip_send_msg_to_client(vni_t vni,
988 const struct ethaddr *macaddr,
1a3bd37f 989 const struct ipaddr *ip, uint8_t flags,
b2998086
PR
990 uint32_t seq, int state,
991 struct zebra_evpn_es *es, uint16_t cmd)
24268cd0 992{
b2998086
PR
993 int ipa_len;
994 struct zserv *client = NULL;
995 struct stream *s = NULL;
996 esi_t *esi = es ? &es->esi : zero_esi;
24268cd0 997
b2998086
PR
998 client = zserv_find_client(ZEBRA_ROUTE_BGP, 0);
999 /* BGP may not be running. */
1000 if (!client)
1001 return 0;
24268cd0 1002
b2998086 1003 s = stream_new(ZEBRA_MAX_PACKET_SIZ);
24268cd0 1004
b2998086
PR
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;
24268cd0 1014
b2998086
PR
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. */
24268cd0 1020
b2998086
PR
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));
24268cd0 1025 } else {
b2998086
PR
1026 stream_putl(s, state); /* state - active/inactive */
1027 }
24268cd0 1028
24268cd0 1029
b2998086
PR
1030 /* Write packet size. */
1031 stream_putw_at(s, 0, stream_get_endp(s));
24268cd0 1032
bf902d4c
DS
1033 if (IS_ZEBRA_DEBUG_VXLAN) {
1034 char flag_buf[MACIP_BUF_SIZE];
1035
b2998086 1036 zlog_debug(
ef7b8be4 1037 "Send MACIP %s f %s MAC %pEA IP %pIA seq %u L2-VNI %u ESI %s to %s",
bf902d4c
DS
1038 (cmd == ZEBRA_MACIP_ADD) ? "Add" : "Del",
1039 zclient_evpn_dump_macip_flags(flags, flag_buf,
1040 sizeof(flag_buf)),
ef7b8be4 1041 macaddr, ip, seq, vni,
b2998086
PR
1042 es ? es->esi_str : "-",
1043 zebra_route_string(client->proto));
bf902d4c 1044 }
24268cd0 1045
b2998086
PR
1046 if (cmd == ZEBRA_MACIP_ADD)
1047 client->macipadd_cnt++;
1048 else
1049 client->macipdel_cnt++;
24268cd0 1050
b2998086
PR
1051 return zserv_send_message(client, s);
1052}
24268cd0 1053
b2998086
PR
1054static unsigned int mac_hash_keymake(const void *p)
1055{
3198b2b3 1056 const struct zebra_mac *pmac = p;
b2998086 1057 const void *pnt = (void *)pmac->macaddr.octet;
24268cd0 1058
b2998086 1059 return jhash(pnt, ETH_ALEN, 0xa5a5a55a);
24268cd0
PR
1060}
1061
1062/*
b2998086 1063 * Compare two MAC addresses.
24268cd0 1064 */
b2998086 1065static bool mac_cmp(const void *p1, const void *p2)
24268cd0 1066{
3198b2b3
DS
1067 const struct zebra_mac *pmac1 = p1;
1068 const struct zebra_mac *pmac2 = p2;
24268cd0 1069
b2998086
PR
1070 if (pmac1 == NULL && pmac2 == NULL)
1071 return true;
24268cd0 1072
b2998086
PR
1073 if (pmac1 == NULL || pmac2 == NULL)
1074 return false;
24268cd0 1075
b2998086
PR
1076 return (memcmp(pmac1->macaddr.octet, pmac2->macaddr.octet, ETH_ALEN)
1077 == 0);
1078}
24268cd0 1079
b2998086
PR
1080/*
1081 * Callback to allocate MAC hash entry.
1082 */
1083static void *zebra_evpn_mac_alloc(void *p)
1084{
3198b2b3
DS
1085 const struct zebra_mac *tmp_mac = p;
1086 struct zebra_mac *mac;
24268cd0 1087
3198b2b3 1088 mac = XCALLOC(MTYPE_MAC, sizeof(struct zebra_mac));
b2998086 1089 *mac = *tmp_mac;
24268cd0 1090
b2998086
PR
1091 return ((void *)mac);
1092}
24268cd0 1093
b2998086
PR
1094/*
1095 * Add MAC entry.
1096 */
3198b2b3
DS
1097struct zebra_mac *zebra_evpn_mac_add(struct zebra_evpn *zevpn,
1098 const struct ethaddr *macaddr)
b2998086 1099{
3198b2b3
DS
1100 struct zebra_mac tmp_mac;
1101 struct zebra_mac *mac = NULL;
24268cd0 1102
6006b807 1103 memset(&tmp_mac, 0, sizeof(tmp_mac));
b2998086
PR
1104 memcpy(&tmp_mac.macaddr, macaddr, ETH_ALEN);
1105 mac = hash_get(zevpn->mac_table, &tmp_mac, zebra_evpn_mac_alloc);
24268cd0 1106
b2998086
PR
1107 mac->zevpn = zevpn;
1108 mac->dad_mac_auto_recovery_timer = NULL;
24268cd0 1109
b2998086
PR
1110 mac->neigh_list = list_new();
1111 mac->neigh_list->cmp = neigh_list_cmp;
24268cd0 1112
f1dbb1c7 1113 mac->uptime = monotime(NULL);
b2998086 1114 if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
b16e8004 1115 char mac_buf[MAC_BUF_SIZE];
24268cd0 1116
ef7b8be4
DL
1117 zlog_debug("%s: MAC %pEA flags %s", __func__,
1118 &mac->macaddr,
b16e8004
DS
1119 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
1120 sizeof(mac_buf)));
b2998086
PR
1121 }
1122 return mac;
24268cd0
PR
1123}
1124
1125/*
b2998086 1126 * Delete MAC entry.
24268cd0 1127 */
3198b2b3 1128int zebra_evpn_mac_del(struct zebra_evpn *zevpn, struct zebra_mac *mac)
24268cd0 1129{
3198b2b3 1130 struct zebra_mac *tmp_mac;
24268cd0 1131
b2998086 1132 if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
b16e8004 1133 char mac_buf[MAC_BUF_SIZE];
b2998086 1134
ef7b8be4
DL
1135 zlog_debug("%s: MAC %pEA flags %s", __func__,
1136 &mac->macaddr,
b16e8004
DS
1137 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
1138 sizeof(mac_buf)));
24268cd0
PR
1139 }
1140
b2998086
PR
1141 /* force de-ref any ES entry linked to the MAC */
1142 zebra_evpn_es_mac_deref_entry(mac);
24268cd0 1143
8b07f173
AK
1144 /* remove links to the destination access port */
1145 zebra_evpn_mac_clear_fwd_info(mac);
1146
b2998086
PR
1147 /* Cancel proxy hold timer */
1148 zebra_evpn_mac_stop_hold_timer(mac);
24268cd0 1149
b2998086
PR
1150 /* Cancel auto recovery */
1151 THREAD_OFF(mac->dad_mac_auto_recovery_timer);
24268cd0 1152
d5fdae8f
CS
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
b2998086 1173 list_delete(&mac->neigh_list);
24268cd0 1174
b2998086
PR
1175 /* Free the VNI hash entry and allocated memory. */
1176 tmp_mac = hash_release(zevpn->mac_table, mac);
1177 XFREE(MTYPE_MAC, tmp_mac);
24268cd0 1178
b2998086
PR
1179 return 0;
1180}
24268cd0 1181
b2998086 1182static bool zebra_evpn_check_mac_del_from_db(struct mac_walk_ctx *wctx,
3198b2b3 1183 struct zebra_mac *mac)
b2998086
PR
1184{
1185 if ((wctx->flags & DEL_LOCAL_MAC) && (mac->flags & ZEBRA_MAC_LOCAL))
1186 return true;
1187 else if ((wctx->flags & DEL_REMOTE_MAC)
1188 && (mac->flags & ZEBRA_MAC_REMOTE))
1189 return true;
1190 else if ((wctx->flags & DEL_REMOTE_MAC_FROM_VTEP)
1191 && (mac->flags & ZEBRA_MAC_REMOTE)
1192 && IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &wctx->r_vtep_ip))
1193 return true;
1194 else if ((wctx->flags & DEL_LOCAL_MAC) && (mac->flags & ZEBRA_MAC_AUTO)
1195 && !listcount(mac->neigh_list)) {
1196 if (IS_ZEBRA_DEBUG_VXLAN) {
b16e8004 1197 char mac_buf[MAC_BUF_SIZE];
24268cd0 1198
24268cd0 1199 zlog_debug(
ef7b8be4
DL
1200 "%s: Del MAC %pEA flags %s", __func__,
1201 &mac->macaddr,
b16e8004
DS
1202 zebra_evpn_zebra_mac_flag_dump(
1203 mac, mac_buf, sizeof(mac_buf)));
b2998086
PR
1204 }
1205 wctx->uninstall = 0;
24268cd0 1206
b2998086
PR
1207 return true;
1208 }
24268cd0 1209
b2998086
PR
1210 return false;
1211}
24268cd0 1212
b2998086
PR
1213/*
1214 * Free MAC hash entry (callback)
1215 */
1216static void zebra_evpn_mac_del_hash_entry(struct hash_bucket *bucket, void *arg)
1217{
1218 struct mac_walk_ctx *wctx = arg;
3198b2b3 1219 struct zebra_mac *mac = bucket->data;
24268cd0 1220
b2998086
PR
1221 if (zebra_evpn_check_mac_del_from_db(wctx, mac)) {
1222 if (wctx->upd_client && (mac->flags & ZEBRA_MAC_LOCAL)) {
1223 zebra_evpn_mac_send_del_to_client(wctx->zevpn->vni,
1224 &mac->macaddr,
1225 mac->flags, false);
1226 }
1227 if (wctx->uninstall) {
1228 if (zebra_evpn_mac_is_static(mac))
1229 zebra_evpn_sync_mac_dp_install(
1230 mac, false /* set_inactive */,
1231 true /* force_clear_static */,
1232 __func__);
24268cd0 1233
b2998086 1234 if (mac->flags & ZEBRA_MAC_REMOTE)
f3722826
AK
1235 zebra_evpn_rem_mac_uninstall(wctx->zevpn, mac,
1236 false /*force*/);
24268cd0 1237 }
b2998086
PR
1238
1239 zebra_evpn_mac_del(wctx->zevpn, mac);
24268cd0
PR
1240 }
1241
24268cd0
PR
1242 return;
1243}
1244
24268cd0 1245/*
b2998086 1246 * Delete all MAC entries for this EVPN.
24268cd0 1247 */
f6371c34
DS
1248void zebra_evpn_mac_del_all(struct zebra_evpn *zevpn, int uninstall,
1249 int upd_client, uint32_t flags)
24268cd0 1250{
b2998086 1251 struct mac_walk_ctx wctx;
24268cd0 1252
b2998086 1253 if (!zevpn->mac_table)
24268cd0
PR
1254 return;
1255
6006b807 1256 memset(&wctx, 0, sizeof(wctx));
b2998086
PR
1257 wctx.zevpn = zevpn;
1258 wctx.uninstall = uninstall;
1259 wctx.upd_client = upd_client;
1260 wctx.flags = flags;
24268cd0 1261
b2998086
PR
1262 hash_iterate(zevpn->mac_table, zebra_evpn_mac_del_hash_entry, &wctx);
1263}
24268cd0 1264
b2998086
PR
1265/*
1266 * Look up MAC hash entry.
1267 */
3198b2b3
DS
1268struct zebra_mac *zebra_evpn_mac_lookup(struct zebra_evpn *zevpn,
1269 const struct ethaddr *mac)
b2998086 1270{
3198b2b3
DS
1271 struct zebra_mac tmp;
1272 struct zebra_mac *pmac;
24268cd0 1273
b2998086
PR
1274 memset(&tmp, 0, sizeof(tmp));
1275 memcpy(&tmp.macaddr, mac, ETH_ALEN);
1276 pmac = hash_lookup(zevpn->mac_table, &tmp);
24268cd0 1277
b2998086
PR
1278 return pmac;
1279}
24268cd0 1280
b2998086
PR
1281/*
1282 * Inform BGP about local MAC addition.
1283 */
1a3bd37f 1284int zebra_evpn_mac_send_add_to_client(vni_t vni, const struct ethaddr *macaddr,
b2998086
PR
1285 uint32_t mac_flags, uint32_t seq,
1286 struct zebra_evpn_es *es)
1287{
1288 uint8_t flags = 0;
24268cd0 1289
b2998086
PR
1290 if (CHECK_FLAG(mac_flags, ZEBRA_MAC_LOCAL_INACTIVE)) {
1291 /* host reachability has not been verified locally */
24268cd0 1292
b2998086
PR
1293 /* if no ES peer is claiming reachability we can't advertise the
1294 * entry
1295 */
1296 if (!CHECK_FLAG(mac_flags, ZEBRA_MAC_ES_PEER_ACTIVE))
1297 return 0;
24268cd0 1298
b2998086
PR
1299 /* ES peers are claiming reachability; we will
1300 * advertise the entry but with a proxy flag
24268cd0 1301 */
b2998086
PR
1302 SET_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT);
1303 }
24268cd0 1304
b2998086
PR
1305 if (CHECK_FLAG(mac_flags, ZEBRA_MAC_STICKY))
1306 SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
1307 if (CHECK_FLAG(mac_flags, ZEBRA_MAC_DEF_GW))
1308 SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
24268cd0 1309
b2998086
PR
1310 return zebra_evpn_macip_send_msg_to_client(vni, macaddr, NULL, flags,
1311 seq, ZEBRA_NEIGH_ACTIVE, es,
1312 ZEBRA_MACIP_ADD);
1313}
24268cd0 1314
b2998086
PR
1315/*
1316 * Inform BGP about local MAC deletion.
1317 */
1a3bd37f 1318int zebra_evpn_mac_send_del_to_client(vni_t vni, const struct ethaddr *macaddr,
b2998086
PR
1319 uint32_t flags, bool force)
1320{
1321 if (!force) {
1322 if (CHECK_FLAG(flags, ZEBRA_MAC_LOCAL_INACTIVE)
1323 && !CHECK_FLAG(flags, ZEBRA_MAC_ES_PEER_ACTIVE))
1324 /* the host was not advertised - nothing to delete */
1325 return 0;
24268cd0
PR
1326 }
1327
b2998086
PR
1328 return zebra_evpn_macip_send_msg_to_client(
1329 vni, macaddr, NULL, 0 /* flags */, 0 /* seq */,
1330 ZEBRA_NEIGH_ACTIVE, NULL, ZEBRA_MACIP_DEL);
24268cd0
PR
1331}
1332
1333/*
b2998086 1334 * wrapper to create a MAC hash table
24268cd0 1335 */
b2998086 1336struct hash *zebra_mac_db_create(const char *desc)
24268cd0 1337{
da55bcbc 1338 return hash_create_size(8, mac_hash_keymake, mac_cmp, desc);
24268cd0
PR
1339}
1340
b2998086 1341/* program sync mac flags in the dataplane */
3198b2b3 1342int zebra_evpn_sync_mac_dp_install(struct zebra_mac *mac, bool set_inactive,
15400f95 1343 bool force_clear_static, const char *caller)
24268cd0 1344{
b2998086
PR
1345 struct interface *ifp;
1346 bool sticky;
1347 bool set_static;
f6371c34 1348 struct zebra_evpn *zevpn = mac->zevpn;
b2998086
PR
1349 vlanid_t vid;
1350 struct zebra_if *zif;
1351 struct interface *br_ifp;
24268cd0 1352
09de6e45
AK
1353 /* If the ES-EVI doesn't exist defer install. When the ES-EVI is
1354 * created we will attempt to install the mac entry again
1355 */
1356 if (mac->es) {
1357 struct zebra_evpn_es_evi *es_evi;
1358
1359 es_evi = zebra_evpn_es_evi_find(mac->es, mac->zevpn);
1360 if (!es_evi) {
1361 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
1362 zlog_debug(
1363 "%s: dp-install sync-mac vni %u mac %pEA es %s 0x%x %sskipped, no es-evi",
1364 caller, zevpn->vni, &mac->macaddr,
1365 mac->es ? mac->es->esi_str : "-",
1366 mac->flags,
1367 set_inactive ? "inactive " : "");
1368 return -1;
1369 }
1370 }
1371
b2998086
PR
1372 /* get the access vlan from the vxlan_device */
1373 zebra_evpn_mac_get_access_info(mac, &ifp, &vid);
24268cd0 1374
b2998086 1375 if (!ifp) {
b16e8004
DS
1376 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
1377 char mac_buf[MAC_BUF_SIZE];
1378
b2998086 1379 zlog_debug(
b16e8004 1380 "%s: dp-install sync-mac vni %u mac %pEA es %s %s%sskipped, no access-port",
15400f95 1381 caller, zevpn->vni, &mac->macaddr,
b16e8004
DS
1382 mac->es ? mac->es->esi_str : "-",
1383 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
1384 sizeof(mac_buf)),
b2998086 1385 set_inactive ? "inactive " : "");
b16e8004 1386 }
15400f95 1387 return -1;
b2998086 1388 }
24268cd0 1389
b2998086
PR
1390 zif = ifp->info;
1391 br_ifp = zif->brslave_info.br_if;
1392 if (!br_ifp) {
b16e8004
DS
1393 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
1394 char mac_buf[MAC_BUF_SIZE];
1395
b2998086 1396 zlog_debug(
b16e8004 1397 "%s: dp-install sync-mac vni %u mac %pEA es %s %s%sskipped, no br",
15400f95 1398 caller, zevpn->vni, &mac->macaddr,
b16e8004
DS
1399 mac->es ? mac->es->esi_str : "-",
1400 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
1401 sizeof(mac_buf)),
b2998086 1402 set_inactive ? "inactive " : "");
b16e8004 1403 }
15400f95 1404 return -1;
b2998086 1405 }
24268cd0 1406
b2998086
PR
1407 sticky = !!CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY);
1408 if (force_clear_static)
1409 set_static = false;
1410 else
1411 set_static = zebra_evpn_mac_is_static(mac);
24268cd0 1412
15400f95
AK
1413 /* We can install a local mac that has been synced from the peer
1414 * over the VxLAN-overlay/network-port if fast failover is not
1415 * supported and if the local ES is oper-down.
1416 */
1417 if (mac->es && zebra_evpn_es_local_mac_via_network_port(mac->es)) {
b16e8004
DS
1418 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
1419 char mac_buf[MAC_BUF_SIZE];
1420
15400f95 1421 zlog_debug(
b16e8004 1422 "dp-%s sync-nw-mac vni %u mac %pEA es %s %s%s",
15400f95
AK
1423 set_static ? "install" : "uninstall",
1424 zevpn->vni, &mac->macaddr,
b16e8004
DS
1425 mac->es ? mac->es->esi_str : "-",
1426 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
1427 sizeof(mac_buf)),
15400f95 1428 set_inactive ? "inactive " : "");
b16e8004 1429 }
15400f95
AK
1430 if (set_static)
1431 /* XXX - old_static needs to be computed more
1432 * accurately
1433 */
1434 zebra_evpn_rem_mac_install(zevpn, mac,
1435 true /* old_static */);
1436 else
1437 zebra_evpn_rem_mac_uninstall(zevpn, mac,
1438 false /* force */);
1439
1440 return 0;
1441 }
1442
b16e8004
DS
1443 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
1444 char mac_buf[MAC_BUF_SIZE];
1445
1446 zlog_debug("dp-install sync-mac vni %u mac %pEA es %s %s%s%s",
1447 zevpn->vni, &mac->macaddr,
1448 mac->es ? mac->es->esi_str : "-",
1449 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
1450 sizeof(mac_buf)),
1451 set_static ? "static " : "",
1452 set_inactive ? "inactive " : "");
1453 }
24268cd0 1454
b2998086
PR
1455 dplane_local_mac_add(ifp, br_ifp, vid, &mac->macaddr, sticky,
1456 set_static, set_inactive);
15400f95 1457 return 0;
24268cd0
PR
1458}
1459
3198b2b3
DS
1460void zebra_evpn_mac_send_add_del_to_client(struct zebra_mac *mac,
1461 bool old_bgp_ready,
b2998086 1462 bool new_bgp_ready)
24268cd0 1463{
b2998086
PR
1464 if (new_bgp_ready)
1465 zebra_evpn_mac_send_add_to_client(mac->zevpn->vni,
1466 &mac->macaddr, mac->flags,
1467 mac->loc_seq, mac->es);
1468 else if (old_bgp_ready)
1469 zebra_evpn_mac_send_del_to_client(mac->zevpn->vni,
1470 &mac->macaddr, mac->flags,
1471 true /* force */);
24268cd0
PR
1472}
1473
b2998086
PR
1474/* MAC hold timer is used to age out peer-active flag.
1475 *
1476 * During this wait time we expect the dataplane component or an
1477 * external neighmgr daemon to probe existing hosts to independently
1478 * establish their presence on the ES.
1479 */
cc9f21da 1480static void zebra_evpn_mac_hold_exp_cb(struct thread *t)
24268cd0 1481{
3198b2b3 1482 struct zebra_mac *mac;
b2998086
PR
1483 bool old_bgp_ready;
1484 bool new_bgp_ready;
1485 bool old_static;
1486 bool new_static;
24268cd0
PR
1487
1488 mac = THREAD_ARG(t);
b2998086
PR
1489 /* the purpose of the hold timer is to age out the peer-active
1490 * flag
1491 */
1492 if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE))
cc9f21da 1493 return;
24268cd0 1494
b2998086
PR
1495 old_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
1496 old_static = zebra_evpn_mac_is_static(mac);
1497 UNSET_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE);
1498 new_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
1499 new_static = zebra_evpn_mac_is_static(mac);
24268cd0 1500
b16e8004
DS
1501 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
1502 char mac_buf[MAC_BUF_SIZE];
1503
24268cd0 1504 zlog_debug(
ef7b8be4
DL
1505 "sync-mac vni %u mac %pEA es %s %shold expired",
1506 mac->zevpn->vni, &mac->macaddr,
b16e8004
DS
1507 mac->es ? mac->es->esi_str : "-",
1508 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
1509 sizeof(mac_buf)));
1510 }
24268cd0 1511
b2998086
PR
1512 /* re-program the local mac in the dataplane if the mac is no
1513 * longer static
1514 */
1515 if (old_static != new_static)
1516 zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */,
1517 false /* force_clear_static */,
1518 __func__);
24268cd0 1519
b2998086
PR
1520 /* inform bgp if needed */
1521 if (old_bgp_ready != new_bgp_ready)
1522 zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready,
1523 new_bgp_ready);
24268cd0
PR
1524}
1525
3198b2b3 1526static inline void zebra_evpn_mac_start_hold_timer(struct zebra_mac *mac)
24268cd0 1527{
b2998086
PR
1528 if (mac->hold_timer)
1529 return;
24268cd0 1530
b16e8004
DS
1531 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
1532 char mac_buf[MAC_BUF_SIZE];
1533
24268cd0 1534 zlog_debug(
ef7b8be4
DL
1535 "sync-mac vni %u mac %pEA es %s %shold started",
1536 mac->zevpn->vni, &mac->macaddr,
b16e8004
DS
1537 mac->es ? mac->es->esi_str : "-",
1538 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
1539 sizeof(mac_buf)));
1540 }
b2998086
PR
1541 thread_add_timer(zrouter.master, zebra_evpn_mac_hold_exp_cb, mac,
1542 zmh_info->mac_hold_time, &mac->hold_timer);
24268cd0
PR
1543}
1544
3198b2b3 1545void zebra_evpn_mac_stop_hold_timer(struct zebra_mac *mac)
24268cd0 1546{
b2998086
PR
1547 if (!mac->hold_timer)
1548 return;
24268cd0 1549
b16e8004
DS
1550 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
1551 char mac_buf[MAC_BUF_SIZE];
1552
b2998086 1553 zlog_debug(
ef7b8be4
DL
1554 "sync-mac vni %u mac %pEA es %s %shold stopped",
1555 mac->zevpn->vni, &mac->macaddr,
b16e8004
DS
1556 mac->es ? mac->es->esi_str : "-",
1557 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
1558 sizeof(mac_buf)));
1559 }
1560
b2998086 1561 THREAD_OFF(mac->hold_timer);
24268cd0
PR
1562}
1563
3198b2b3 1564void zebra_evpn_sync_mac_del(struct zebra_mac *mac)
24268cd0 1565{
b2998086
PR
1566 bool old_static;
1567 bool new_static;
24268cd0 1568
b16e8004
DS
1569 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
1570 char mac_buf[MAC_BUF_SIZE];
1571
b2998086 1572 zlog_debug(
ef7b8be4
DL
1573 "sync-mac del vni %u mac %pEA es %s seq %d f %s",
1574 mac->zevpn->vni, &mac->macaddr,
b2998086 1575 mac->es ? mac->es->esi_str : "-", mac->loc_seq,
b16e8004
DS
1576 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
1577 sizeof(mac_buf)));
1578 }
1579
b2998086
PR
1580 old_static = zebra_evpn_mac_is_static(mac);
1581 UNSET_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY);
1582 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE))
1583 zebra_evpn_mac_start_hold_timer(mac);
1584 new_static = zebra_evpn_mac_is_static(mac);
24268cd0 1585
b2998086
PR
1586 if (old_static != new_static)
1587 /* program the local mac in the kernel */
1588 zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */,
1589 false /* force_clear_static */,
1590 __func__);
24268cd0
PR
1591}
1592
f6371c34 1593static inline bool zebra_evpn_mac_is_bgp_seq_ok(struct zebra_evpn *zevpn,
3198b2b3
DS
1594 struct zebra_mac *mac,
1595 uint32_t seq, uint16_t ipa_len,
1a3bd37f 1596 const struct ipaddr *ipaddr,
16de1338 1597 bool sync)
24268cd0 1598{
b2998086
PR
1599 char ipbuf[INET6_ADDRSTRLEN];
1600 uint32_t tmp_seq;
16de1338 1601 const char *n_type;
24268cd0 1602
16de1338 1603 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
b2998086 1604 tmp_seq = mac->loc_seq;
16de1338
AK
1605 n_type = "local";
1606 } else {
b2998086 1607 tmp_seq = mac->rem_seq;
16de1338
AK
1608 n_type = "remote";
1609 }
24268cd0 1610
b2998086
PR
1611 if (seq < tmp_seq) {
1612 /* if the mac was never advertised to bgp we must accept
1613 * whatever sequence number bgp sends
1614 * XXX - check with Vivek
1615 */
1616 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)
1617 && !zebra_evpn_mac_is_ready_for_bgp(mac->flags)) {
b16e8004
DS
1618 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
1619 || IS_ZEBRA_DEBUG_VXLAN) {
1620 char mac_buf[MAC_BUF_SIZE];
1621
b2998086 1622 zlog_debug(
ef7b8be4 1623 "%s-macip accept vni %u %s-mac %pEA%s%s lower seq %u f %s",
16de1338
AK
1624 sync ? "sync" : "rem", zevpn->vni,
1625 n_type,
ef7b8be4 1626 &mac->macaddr,
b2998086
PR
1627 ipa_len ? " IP " : "",
1628 ipa_len ? ipaddr2str(ipaddr, ipbuf,
1629 sizeof(ipbuf))
1630 : "",
b16e8004
DS
1631 tmp_seq,
1632 zebra_evpn_zebra_mac_flag_dump(
1633 mac, mac_buf, sizeof(mac_buf)));
1634 }
1635
b2998086
PR
1636 return true;
1637 }
24268cd0 1638
b16e8004
DS
1639 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC || IS_ZEBRA_DEBUG_VXLAN) {
1640 char mac_buf[MAC_BUF_SIZE];
1641
b2998086 1642 zlog_debug(
ef7b8be4 1643 "%s-macip ignore vni %u %s-mac %pEA%s%s as existing has higher seq %u f %s",
16de1338 1644 sync ? "sync" : "rem", zevpn->vni, n_type,
ef7b8be4 1645 &mac->macaddr,
b2998086
PR
1646 ipa_len ? " IP " : "",
1647 ipa_len ? ipaddr2str(ipaddr, ipbuf,
1648 sizeof(ipbuf))
1649 : "",
b16e8004
DS
1650 tmp_seq,
1651 zebra_evpn_zebra_mac_flag_dump(
1652 mac, mac_buf, sizeof(mac_buf)));
1653 }
b2998086 1654 return false;
24268cd0
PR
1655 }
1656
b2998086 1657 return true;
24268cd0
PR
1658}
1659
3198b2b3 1660struct zebra_mac *zebra_evpn_proc_sync_mac_update(
f6371c34
DS
1661 struct zebra_evpn *zevpn, const struct ethaddr *macaddr,
1662 uint16_t ipa_len, const struct ipaddr *ipaddr, uint8_t flags,
1663 uint32_t seq, const esi_t *esi, struct sync_mac_ip_ctx *ctx)
24268cd0 1664{
3198b2b3 1665 struct zebra_mac *mac;
b2998086
PR
1666 bool inform_bgp = false;
1667 bool inform_dataplane = false;
1668 bool seq_change = false;
1669 bool es_change = false;
1670 uint32_t tmp_seq;
b2998086
PR
1671 char ipbuf[INET6_ADDRSTRLEN];
1672 bool old_local = false;
1673 bool old_bgp_ready;
1674 bool new_bgp_ready;
24268cd0 1675
b2998086
PR
1676 mac = zebra_evpn_mac_lookup(zevpn, macaddr);
1677 if (!mac) {
1678 /* if it is a new local path we need to inform both
1679 * the control protocol and the data-plane
1680 */
1681 inform_bgp = true;
1682 inform_dataplane = true;
1683 ctx->mac_created = true;
1684 ctx->mac_inactive = true;
24268cd0 1685
b2998086
PR
1686 /* create the MAC and associate it with the dest ES */
1687 mac = zebra_evpn_mac_add(zevpn, macaddr);
1688 zebra_evpn_es_mac_ref(mac, esi);
24268cd0 1689
b2998086
PR
1690 /* local mac activated by an ES peer */
1691 SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
1692 /* if mac-only route setup peer flags */
1693 if (!ipa_len) {
1694 if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT))
1695 SET_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY);
1696 else
1697 SET_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE);
1698 }
1699 SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE);
1700 old_bgp_ready = false;
1701 new_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
1702 } else {
1703 uint32_t old_flags;
1704 uint32_t new_flags;
1705 bool old_static;
1706 bool new_static;
1707 bool sticky;
1708 bool remote_gw;
24268cd0 1709
f1dbb1c7
DS
1710 mac->uptime = monotime(NULL);
1711
b2998086
PR
1712 old_flags = mac->flags;
1713 sticky = !!CHECK_FLAG(old_flags, ZEBRA_MAC_STICKY);
1714 remote_gw = !!CHECK_FLAG(old_flags, ZEBRA_MAC_REMOTE_DEF_GW);
1715 if (sticky || remote_gw) {
1716 if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
1717 zlog_debug(
ef7b8be4
DL
1718 "Ignore sync-macip vni %u mac %pEA%s%s%s%s",
1719 zevpn->vni, macaddr,
b2998086
PR
1720 ipa_len ? " IP " : "",
1721 ipa_len ? ipaddr2str(ipaddr, ipbuf,
1722 sizeof(ipbuf))
1723 : "",
1724 sticky ? " sticky" : "",
1725 remote_gw ? " remote_gw" : "");
1726 ctx->ignore_macip = true;
1727 return NULL;
1728 }
1729 if (!zebra_evpn_mac_is_bgp_seq_ok(zevpn, mac, seq, ipa_len,
16de1338 1730 ipaddr, true)) {
b2998086
PR
1731 ctx->ignore_macip = true;
1732 return NULL;
1733 }
24268cd0 1734
b2998086
PR
1735 old_local = !!CHECK_FLAG(old_flags, ZEBRA_MAC_LOCAL);
1736 old_static = zebra_evpn_mac_is_static(mac);
24268cd0 1737
b2998086
PR
1738 /* re-build the mac flags */
1739 new_flags = 0;
1740 SET_FLAG(new_flags, ZEBRA_MAC_LOCAL);
1741 /* retain old local activity flag */
1742 if (old_flags & ZEBRA_MAC_LOCAL) {
1743 new_flags |= (old_flags & ZEBRA_MAC_LOCAL_INACTIVE);
1744 } else {
1745 new_flags |= ZEBRA_MAC_LOCAL_INACTIVE;
1746 ctx->mac_inactive = true;
1747 }
1748 if (ipa_len) {
1749 /* if mac-ip route do NOT update the peer flags
1750 * i.e. retain only flags as is
1751 */
1752 new_flags |= (old_flags & ZEBRA_MAC_ALL_PEER_FLAGS);
1753 } else {
1754 /* if mac-only route update peer flags */
1755 if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT)) {
1756 SET_FLAG(new_flags, ZEBRA_MAC_ES_PEER_PROXY);
1757 /* if the mac was peer-active previously we
1758 * need to keep the flag and start the
1759 * holdtimer on it. the peer-active flag is
1760 * cleared on holdtimer expiry.
1761 */
1762 if (CHECK_FLAG(old_flags,
1763 ZEBRA_MAC_ES_PEER_ACTIVE)) {
1764 SET_FLAG(new_flags,
1765 ZEBRA_MAC_ES_PEER_ACTIVE);
1766 zebra_evpn_mac_start_hold_timer(mac);
1767 }
1768 } else {
1769 SET_FLAG(new_flags, ZEBRA_MAC_ES_PEER_ACTIVE);
1770 /* stop hold timer if a peer has verified
1771 * reachability
1772 */
1773 zebra_evpn_mac_stop_hold_timer(mac);
1774 }
1775 }
1776 mac->rem_seq = 0;
8b07f173 1777 zebra_evpn_mac_clear_fwd_info(mac);
b2998086 1778 mac->flags = new_flags;
24268cd0 1779
b16e8004
DS
1780 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC && (old_flags != new_flags)) {
1781 char mac_buf[MAC_BUF_SIZE], omac_buf[MAC_BUF_SIZE];
3198b2b3 1782 struct zebra_mac omac;
b16e8004
DS
1783
1784 omac.flags = old_flags;
b2998086 1785 zlog_debug(
ef7b8be4
DL
1786 "sync-mac vni %u mac %pEA old_f %snew_f %s",
1787 zevpn->vni, macaddr,
b16e8004
DS
1788 zebra_evpn_zebra_mac_flag_dump(
1789 &omac, omac_buf, sizeof(omac_buf)),
1790 zebra_evpn_zebra_mac_flag_dump(
1791 mac, mac_buf, sizeof(mac_buf)));
1792 }
24268cd0 1793
b2998086
PR
1794 /* update es */
1795 es_change = zebra_evpn_es_mac_ref(mac, esi);
1796 /* if mac dest change - inform both sides */
1797 if (es_change) {
1798 inform_bgp = true;
1799 inform_dataplane = true;
1800 ctx->mac_inactive = true;
1801 }
8b07f173 1802
b2998086
PR
1803 /* if peer-flag is being set notify dataplane that the
1804 * entry must not be expired because of local inactivity
1805 */
1806 new_static = zebra_evpn_mac_is_static(mac);
1807 if (old_static != new_static)
1808 inform_dataplane = true;
24268cd0 1809
b2998086
PR
1810 old_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(old_flags);
1811 new_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
1812 if (old_bgp_ready != new_bgp_ready)
1813 inform_bgp = true;
1814 }
24268cd0 1815
24268cd0 1816
b2998086
PR
1817 /* update sequence number; if that results in a new local sequence
1818 * inform bgp
1819 */
1820 tmp_seq = MAX(mac->loc_seq, seq);
1821 if (tmp_seq != mac->loc_seq) {
1822 mac->loc_seq = tmp_seq;
1823 seq_change = true;
1824 inform_bgp = true;
1825 }
24268cd0 1826
b16e8004
DS
1827 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
1828 char mac_buf[MAC_BUF_SIZE];
1829
ef7b8be4
DL
1830 zlog_debug("sync-mac %s vni %u mac %pEA es %s seq %d f %s%s%s",
1831 ctx->mac_created ? "created" : "updated",
1832 zevpn->vni, macaddr,
b2998086 1833 mac->es ? mac->es->esi_str : "-", mac->loc_seq,
b16e8004
DS
1834 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
1835 sizeof(mac_buf)),
1836 inform_bgp ? "inform_bgp" : "",
b2998086 1837 inform_dataplane ? " inform_dp" : "");
b16e8004 1838 }
24268cd0 1839
b2998086
PR
1840 if (inform_bgp)
1841 zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready,
1842 new_bgp_ready);
24268cd0 1843
b2998086
PR
1844 /* neighs using the mac may need to be re-sent to
1845 * bgp with updated info
1846 */
1847 if (seq_change || es_change || !old_local)
1848 zebra_evpn_process_neigh_on_local_mac_change(
1849 zevpn, mac, seq_change, es_change);
24268cd0 1850
b2998086
PR
1851 if (inform_dataplane) {
1852 if (ipa_len)
1853 /* if the mac is being created as a part of MAC-IP
1854 * route wait for the neigh to be updated or
1855 * created before programming the mac
1856 */
1857 ctx->mac_dp_update_deferred = true;
1858 else
1859 /* program the local mac in the kernel. when the ES
1860 * change we need to force the dataplane to reset
1861 * the activity as we are yet to establish activity
1862 * locally
1863 */
1864 zebra_evpn_sync_mac_dp_install(
1865 mac, ctx->mac_inactive,
1866 false /* force_clear_static */, __func__);
1867 }
24268cd0 1868
b2998086 1869 return mac;
24268cd0
PR
1870}
1871
07b12758 1872/* update local forwarding info. return true if a dest-ES change
b2998086
PR
1873 * is detected
1874 */
3198b2b3 1875static bool zebra_evpn_local_mac_update_fwd_info(struct zebra_mac *mac,
d9d3455e
PR
1876 struct interface *ifp,
1877 vlanid_t vid)
24268cd0 1878{
b2998086
PR
1879 struct zebra_if *zif = ifp->info;
1880 bool es_change;
47c58929
PG
1881 ns_id_t local_ns_id = NS_DEFAULT;
1882 struct zebra_vrf *zvrf;
00a7710c 1883 struct zebra_evpn_es *es;
47c58929 1884
096f7609 1885 zvrf = ifp->vrf->info;
47c58929
PG
1886 if (zvrf && zvrf->zns)
1887 local_ns_id = zvrf->zns->ns_id;
24268cd0 1888
8b07f173 1889 zebra_evpn_mac_clear_fwd_info(mac);
24268cd0 1890
00a7710c
AK
1891 es = zif->es_info.es;
1892 if (es && (es->flags & ZEBRA_EVPNES_BYPASS))
1893 es = NULL;
1894 es_change = zebra_evpn_es_mac_ref_entry(mac, es);
24268cd0 1895
b2998086
PR
1896 if (!mac->es) {
1897 /* if es is set fwd_info is not-relevant/taped-out */
1898 mac->fwd_info.local.ifindex = ifp->ifindex;
47c58929 1899 mac->fwd_info.local.ns_id = local_ns_id;
b2998086 1900 mac->fwd_info.local.vid = vid;
8b07f173 1901 zebra_evpn_mac_ifp_link(mac, ifp);
24268cd0
PR
1902 }
1903
b2998086 1904 return es_change;
24268cd0
PR
1905}
1906
24268cd0 1907/* Notify Local MACs to the clienti, skips GW MAC */
b2998086
PR
1908static void zebra_evpn_send_mac_hash_entry_to_client(struct hash_bucket *bucket,
1909 void *arg)
24268cd0
PR
1910{
1911 struct mac_walk_ctx *wctx = arg;
3198b2b3 1912 struct zebra_mac *zmac = bucket->data;
24268cd0
PR
1913
1914 if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_DEF_GW))
1915 return;
1916
1917 if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_LOCAL))
b2998086
PR
1918 zebra_evpn_mac_send_add_to_client(wctx->zevpn->vni,
1919 &zmac->macaddr, zmac->flags,
1920 zmac->loc_seq, zmac->es);
24268cd0
PR
1921}
1922
1923/* Iterator to Notify Local MACs of a EVPN */
f6371c34 1924void zebra_evpn_send_mac_list_to_client(struct zebra_evpn *zevpn)
24268cd0
PR
1925{
1926 struct mac_walk_ctx wctx;
1927
1928 if (!zevpn->mac_table)
1929 return;
1930
6006b807 1931 memset(&wctx, 0, sizeof(wctx));
24268cd0
PR
1932 wctx.zevpn = zevpn;
1933
b2998086
PR
1934 hash_iterate(zevpn->mac_table, zebra_evpn_send_mac_hash_entry_to_client,
1935 &wctx);
24268cd0
PR
1936}
1937
3198b2b3 1938void zebra_evpn_rem_mac_del(struct zebra_evpn *zevpn, struct zebra_mac *mac)
24268cd0 1939{
b2998086
PR
1940 zebra_evpn_process_neigh_on_remote_mac_del(zevpn, mac);
1941 /* the remote sequence number in the auto mac entry
1942 * needs to be reset to 0 as the mac entry may have
1943 * been removed on all VTEPs (including
1944 * the originating one)
1945 */
1946 mac->rem_seq = 0;
24268cd0 1947
b2998086
PR
1948 /* If all remote neighbors referencing a remote MAC
1949 * go away, we need to uninstall the MAC.
1950 */
1951 if (remote_neigh_count(mac) == 0) {
f3722826 1952 zebra_evpn_rem_mac_uninstall(zevpn, mac, false /*force*/);
b2998086
PR
1953 zebra_evpn_es_mac_deref_entry(mac);
1954 UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
24268cd0
PR
1955 }
1956
b2998086
PR
1957 if (list_isempty(mac->neigh_list))
1958 zebra_evpn_mac_del(zevpn, mac);
1959 else
1960 SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
24268cd0
PR
1961}
1962
b2998086
PR
1963/* Print Duplicate MAC */
1964void zebra_evpn_print_dad_mac_hash(struct hash_bucket *bucket, void *ctxt)
24268cd0 1965{
3198b2b3 1966 struct zebra_mac *mac;
24268cd0 1967
3198b2b3 1968 mac = (struct zebra_mac *)bucket->data;
b2998086
PR
1969 if (!mac)
1970 return;
24268cd0 1971
b2998086
PR
1972 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
1973 zebra_evpn_print_mac_hash(bucket, ctxt);
24268cd0
PR
1974}
1975
b2998086
PR
1976/* Print Duplicate MAC in detail */
1977void zebra_evpn_print_dad_mac_hash_detail(struct hash_bucket *bucket,
1978 void *ctxt)
24268cd0 1979{
3198b2b3 1980 struct zebra_mac *mac;
24268cd0 1981
3198b2b3 1982 mac = (struct zebra_mac *)bucket->data;
b2998086
PR
1983 if (!mac)
1984 return;
24268cd0 1985
b2998086
PR
1986 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
1987 zebra_evpn_print_mac_hash_detail(bucket, ctxt);
24268cd0 1988}
19fdd1be 1989
f6371c34
DS
1990int zebra_evpn_mac_remote_macip_add(
1991 struct zebra_evpn *zevpn, struct zebra_vrf *zvrf,
1992 const struct ethaddr *macaddr, uint16_t ipa_len,
3198b2b3
DS
1993 const struct ipaddr *ipaddr, struct zebra_mac **macp,
1994 struct in_addr vtep_ip, uint8_t flags, uint32_t seq, const esi_t *esi)
19fdd1be 1995{
19fdd1be 1996 char buf1[INET6_ADDRSTRLEN];
19fdd1be
PR
1997 bool sticky;
1998 bool remote_gw;
1999 int update_mac = 0;
2000 bool do_dad = false;
2001 bool is_dup_detect = false;
2002 esi_t *old_esi;
2003 bool old_static = false;
3198b2b3 2004 struct zebra_mac *mac;
8e1337c5
AK
2005 bool old_es_present;
2006 bool new_es_present;
19fdd1be
PR
2007
2008 sticky = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
2009 remote_gw = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
2010
2011 mac = zebra_evpn_mac_lookup(zevpn, macaddr);
2012
2013 /* Ignore if the mac is already present as a gateway mac */
2014 if (mac && CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW)
2015 && CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW)) {
2016 if (IS_ZEBRA_DEBUG_VXLAN)
2017 zlog_debug(
ef7b8be4
DL
2018 "Ignore remote MACIP ADD VNI %u MAC %pEA%s%s as MAC is already configured as gateway MAC",
2019 zevpn->vni, macaddr,
19fdd1be
PR
2020 ipa_len ? " IP " : "",
2021 ipa_len ? ipaddr2str(ipaddr, buf1, sizeof(buf1))
2022 : "");
2023 return -1;
2024 }
2025
2026 old_esi = (mac && mac->es) ? &mac->es->esi : zero_esi;
2027
2028 /* check if the remote MAC is unknown or has a change.
2029 * If so, that needs to be updated first. Note that client could
2030 * install MAC and MACIP separately or just install the latter.
2031 */
2032 if (!mac || !CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
2033 || sticky != !!CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)
2034 || remote_gw != !!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW)
2035 || !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &vtep_ip)
2036 || memcmp(old_esi, esi, sizeof(esi_t)) || seq != mac->rem_seq)
2037 update_mac = 1;
2038
2039 if (update_mac) {
2040 if (!mac) {
2041 mac = zebra_evpn_mac_add(zevpn, macaddr);
19fdd1be
PR
2042 zebra_evpn_es_mac_ref(mac, esi);
2043
2044 /* Is this MAC created for a MACIP? */
2045 if (ipa_len)
2046 SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
2047 } else {
19fdd1be
PR
2048 /* When host moves but changes its (MAC,IP)
2049 * binding, BGP may install a MACIP entry that
2050 * corresponds to "older" location of the host
2051 * in transient situations (because {IP1,M1}
2052 * is a different route from {IP1,M2}). Check
2053 * the sequence number and ignore this update
2054 * if appropriate.
2055 */
16de1338
AK
2056 if (!zebra_evpn_mac_is_bgp_seq_ok(
2057 zevpn, mac, seq, ipa_len, ipaddr, false))
19fdd1be 2058 return -1;
c1735c08 2059
8e1337c5 2060 old_es_present = !!mac->es;
c1735c08 2061 zebra_evpn_es_mac_ref(mac, esi);
8e1337c5
AK
2062 new_es_present = !!mac->es;
2063 /* XXX - dataplane is curently not able to handle a MAC
2064 * replace if the destination changes from L2-NHG to
2065 * single VTEP and vice-versa. So delete the old entry
2066 * and re-install
2067 */
2068 if (old_es_present != new_es_present)
2069 zebra_evpn_rem_mac_uninstall(zevpn, mac, false);
19fdd1be
PR
2070 }
2071
2072 /* Check MAC's curent state is local (this is the case
2073 * where MAC has moved from L->R) and check previous
2074 * detection started via local learning.
2075 * RFC-7432: A PE/VTEP that detects a MAC mobility
2076 * event via local learning starts an M-second timer.
2077 *
2078 * VTEP-IP or seq. change alone is not considered
2079 * for dup. detection.
2080 *
2081 * MAC is already marked duplicate set dad, then
2082 * is_dup_detect will be set to not install the entry.
2083 */
2084 if ((!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
2085 && mac->dad_count)
2086 || CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
2087 do_dad = true;
2088
2089 /* Remove local MAC from BGP. */
2090 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
2091 /* force drop the sync flags */
2092 old_static = zebra_evpn_mac_is_static(mac);
b16e8004
DS
2093 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
2094 char mac_buf[MAC_BUF_SIZE];
2095
19fdd1be 2096 zlog_debug(
ef7b8be4
DL
2097 "sync-mac->remote vni %u mac %pEA es %s seq %d f %s",
2098 zevpn->vni, macaddr,
19fdd1be 2099 mac->es ? mac->es->esi_str : "-",
b16e8004
DS
2100 mac->loc_seq,
2101 zebra_evpn_zebra_mac_flag_dump(
2102 mac, mac_buf, sizeof(mac_buf)));
2103 }
2104
19fdd1be
PR
2105 zebra_evpn_mac_clear_sync_info(mac);
2106 zebra_evpn_mac_send_del_to_client(zevpn->vni, macaddr,
2107 mac->flags,
2108 false /* force */);
2109 }
2110
2111 /* Set "auto" and "remote" forwarding info. */
8b07f173 2112 zebra_evpn_mac_clear_fwd_info(mac);
19fdd1be 2113 UNSET_FLAG(mac->flags, ZEBRA_MAC_ALL_LOCAL_FLAGS);
19fdd1be
PR
2114 SET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
2115 mac->fwd_info.r_vtep_ip = vtep_ip;
2116
2117 if (sticky)
2118 SET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
2119 else
2120 UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
2121
2122 if (remote_gw)
2123 SET_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW);
2124 else
2125 UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW);
2126
2127 zebra_evpn_dup_addr_detect_for_mac(
2128 zvrf, mac, mac->fwd_info.r_vtep_ip, do_dad,
2129 &is_dup_detect, false);
2130
2131 if (!is_dup_detect) {
2132 zebra_evpn_process_neigh_on_remote_mac_add(zevpn, mac);
2133 /* Install the entry. */
2134 zebra_evpn_rem_mac_install(zevpn, mac, old_static);
2135 }
2136 }
2137
2138 /* Update seq number. */
2139 mac->rem_seq = seq;
2140
2141 /* If there is no IP, return after clearing AUTO flag of MAC. */
2142 if (!ipa_len) {
2143 UNSET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
2144 return -1;
2145 }
2146 *macp = mac;
2147 return 0;
2148}
d9d3455e 2149
f6371c34
DS
2150int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf,
2151 struct zebra_evpn *zevpn,
d9d3455e 2152 struct interface *ifp,
1a3bd37f 2153 const struct ethaddr *macaddr, vlanid_t vid,
d9d3455e 2154 bool sticky, bool local_inactive,
3198b2b3 2155 bool dp_static, struct zebra_mac *mac)
d9d3455e 2156{
d9d3455e
PR
2157 bool mac_sticky = false;
2158 bool inform_client = false;
2159 bool upd_neigh = false;
2160 bool is_dup_detect = false;
2161 struct in_addr vtep_ip = {.s_addr = 0};
2162 bool es_change = false;
2163 bool new_bgp_ready;
2164 /* assume inactive if not present or if not local */
2165 bool old_local_inactive = true;
2166 bool old_bgp_ready = false;
2167 bool inform_dataplane = false;
2168 bool new_static = false;
2169
2bdd4461 2170 assert(ifp);
d9d3455e 2171 /* Check if we need to create or update or it is a NO-OP. */
00a7710c
AK
2172 if (!mac)
2173 mac = zebra_evpn_mac_lookup(zevpn, macaddr);
d9d3455e
PR
2174 if (!mac) {
2175 if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC)
2176 zlog_debug(
ef7b8be4
DL
2177 "ADD %sMAC %pEA intf %s(%u) VID %u -> VNI %u%s",
2178 sticky ? "sticky " : "", macaddr,
d9d3455e
PR
2179 ifp->name, ifp->ifindex, vid, zevpn->vni,
2180 local_inactive ? " local-inactive" : "");
2181
2182 mac = zebra_evpn_mac_add(zevpn, macaddr);
d9d3455e
PR
2183 SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
2184 es_change = zebra_evpn_local_mac_update_fwd_info(mac, ifp, vid);
2185 if (sticky)
2186 SET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
2187 inform_client = true;
2188 } else {
b16e8004
DS
2189 if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
2190 char mac_buf[MAC_BUF_SIZE];
2191
d9d3455e 2192 zlog_debug(
ef7b8be4
DL
2193 "UPD %sMAC %pEA intf %s(%u) VID %u -> VNI %u %scurFlags %s",
2194 sticky ? "sticky " : "", macaddr,
d9d3455e
PR
2195 ifp->name, ifp->ifindex, vid, zevpn->vni,
2196 local_inactive ? "local-inactive " : "",
b16e8004
DS
2197 zebra_evpn_zebra_mac_flag_dump(
2198 mac, mac_buf, sizeof(mac_buf)));
2199 }
d9d3455e
PR
2200
2201 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
2202 struct interface *old_ifp;
2203 vlanid_t old_vid;
2204 bool old_static;
2205
2206 zebra_evpn_mac_get_access_info(mac, &old_ifp, &old_vid);
2207 old_bgp_ready =
2208 zebra_evpn_mac_is_ready_for_bgp(mac->flags);
2209 old_local_inactive =
2210 !!(mac->flags & ZEBRA_MAC_LOCAL_INACTIVE);
2211 old_static = zebra_evpn_mac_is_static(mac);
2212 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY))
2213 mac_sticky = true;
00a7710c
AK
2214 es_change = zebra_evpn_local_mac_update_fwd_info(
2215 mac, ifp, vid);
d9d3455e
PR
2216
2217 /*
2218 * Update any changes and if changes are relevant to
2219 * BGP, note it.
2220 */
2221 if (mac_sticky == sticky && old_ifp == ifp
2222 && old_vid == vid
2223 && old_local_inactive == local_inactive
00a7710c 2224 && dp_static == old_static && !es_change) {
d9d3455e
PR
2225 if (IS_ZEBRA_DEBUG_VXLAN)
2226 zlog_debug(
ef7b8be4 2227 " Add/Update %sMAC %pEA intf %s(%u) VID %u -> VNI %u%s, "
d9d3455e 2228 "entry exists and has not changed ",
4e9a9863 2229 sticky ? "sticky " : "",
ef7b8be4
DL
2230 macaddr, ifp->name,
2231 ifp->ifindex, vid, zevpn->vni,
d9d3455e
PR
2232 local_inactive
2233 ? " local_inactive"
2234 : "");
2235 return 0;
2236 }
2237 if (mac_sticky != sticky) {
2238 if (sticky)
2239 SET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
2240 else
2241 UNSET_FLAG(mac->flags,
2242 ZEBRA_MAC_STICKY);
2243 inform_client = true;
2244 }
2245
d9d3455e
PR
2246 /* If an es_change is detected we need to advertise
2247 * the route with a sequence that is one
2248 * greater. This is need to indicate a mac-move
2249 * to the ES peers
2250 */
2251 if (es_change) {
00a7710c
AK
2252 /* update the sequence number only if the entry
2253 * is locally active
2254 */
2255 if (!local_inactive)
2256 mac->loc_seq = mac->loc_seq + 1;
d9d3455e
PR
2257 /* force drop the peer/sync info as it is
2258 * simply no longer relevant
2259 */
2260 if (CHECK_FLAG(mac->flags,
2261 ZEBRA_MAC_ALL_PEER_FLAGS)) {
2262 zebra_evpn_mac_clear_sync_info(mac);
2263 new_static =
2264 zebra_evpn_mac_is_static(mac);
2265 /* if we clear peer-flags we
2266 * also need to notify the dataplane
2267 * to drop the static flag
2268 */
2269 if (old_static != new_static)
2270 inform_dataplane = true;
2271 }
2272 }
2273 } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
2274 || CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) {
2275 bool do_dad = false;
2276
2277 /*
2278 * MAC has either moved or was "internally" created due
2279 * to a neighbor learn and is now actually learnt. If
2280 * it was learnt as a remote sticky MAC, this is an
2281 * operator error.
2282 */
2283 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)) {
2284 flog_warn(
2285 EC_ZEBRA_STICKY_MAC_ALREADY_LEARNT,
ef7b8be4
DL
2286 "MAC %pEA already learnt as remote sticky MAC behind VTEP %pI4 VNI %u",
2287 macaddr,
9bcef951 2288 &mac->fwd_info.r_vtep_ip,
d9d3455e
PR
2289 zevpn->vni);
2290 return 0;
2291 }
2292
2293 /* If an actual move, compute MAC's seq number */
2294 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
2295 mac->loc_seq =
2296 MAX(mac->rem_seq + 1, mac->loc_seq);
2297 vtep_ip = mac->fwd_info.r_vtep_ip;
2298 /* Trigger DAD for remote MAC */
2299 do_dad = true;
2300 }
2301
2302 UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
2303 UNSET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
2304 SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
2305 es_change = zebra_evpn_local_mac_update_fwd_info(
2306 mac, ifp, vid);
2307 if (sticky)
2308 SET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
2309 else
2310 UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
2311 /*
2312 * We have to inform BGP of this MAC as well as process
2313 * all neighbors.
2314 */
2315 inform_client = true;
2316 upd_neigh = true;
2317
2318 zebra_evpn_dup_addr_detect_for_mac(
2319 zvrf, mac, vtep_ip, do_dad, &is_dup_detect,
2320 true);
2321 if (is_dup_detect) {
2322 inform_client = false;
2323 upd_neigh = false;
839dfe29 2324 es_change = false;
d9d3455e
PR
2325 }
2326 }
2327 }
2328
2329 /* if the dataplane thinks the entry is sync but it is
69711b3f
AK
2330 * not sync in zebra (or vice-versa) we need to re-install
2331 * to fixup
d9d3455e 2332 */
69711b3f
AK
2333 new_static = zebra_evpn_mac_is_static(mac);
2334 if (dp_static != new_static)
2335 inform_dataplane = true;
d9d3455e
PR
2336
2337 if (local_inactive)
2338 SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE);
2339 else
2340 UNSET_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE);
2341
2342 new_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
2343 /* if local-activity has changed we need update bgp
2344 * even if bgp already knows about the mac
2345 */
2346 if ((old_local_inactive != local_inactive)
2347 || (new_bgp_ready != old_bgp_ready)) {
b16e8004
DS
2348 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
2349 char mac_buf[MAC_BUF_SIZE];
2350
d9d3455e 2351 zlog_debug(
ef7b8be4
DL
2352 "local mac vni %u mac %pEA es %s seq %d f %s%s",
2353 zevpn->vni, macaddr,
d9d3455e 2354 mac->es ? mac->es->esi_str : "", mac->loc_seq,
b16e8004
DS
2355 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
2356 sizeof(mac_buf)),
2357 local_inactive ? "local-inactive" : "");
2358 }
2359
839dfe29
CS
2360 if (!is_dup_detect)
2361 inform_client = true;
d9d3455e
PR
2362 }
2363
2364 if (es_change) {
2365 inform_client = true;
2366 upd_neigh = true;
2367 }
2368
2369 /* Inform dataplane if required. */
2370 if (inform_dataplane)
2371 zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */,
2372 false /* force_clear_static */,
2373 __func__);
2374
2375 /* Inform BGP if required. */
2376 if (inform_client)
2377 zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready,
2378 new_bgp_ready);
2379
2380 /* Process all neighbors associated with this MAC, if required. */
2381 if (upd_neigh)
2382 zebra_evpn_process_neigh_on_local_mac_change(zevpn, mac, 0,
2383 es_change);
2384
2385 return 0;
2386}
ad6ca5f4 2387
3198b2b3 2388int zebra_evpn_del_local_mac(struct zebra_evpn *zevpn, struct zebra_mac *mac,
00a7710c 2389 bool clear_static)
ad6ca5f4 2390{
ad6ca5f4
PR
2391 bool old_bgp_ready;
2392 bool new_bgp_ready;
b16e8004 2393
46d6f5a2 2394 if (IS_ZEBRA_DEBUG_VXLAN)
ef7b8be4
DL
2395 zlog_debug("DEL MAC %pEA VNI %u seq %u flags 0x%x nbr count %u",
2396 &mac->macaddr, zevpn->vni, mac->loc_seq, mac->flags,
46d6f5a2 2397 listcount(mac->neigh_list));
ad6ca5f4
PR
2398
2399 old_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
00a7710c 2400 if (!clear_static && zebra_evpn_mac_is_static(mac)) {
ad6ca5f4
PR
2401 /* this is a synced entry and can only be removed when the
2402 * es-peers stop advertising it.
2403 */
8b07f173 2404 zebra_evpn_mac_clear_fwd_info(mac);
ad6ca5f4 2405
b16e8004
DS
2406 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
2407 char mac_buf[MAC_BUF_SIZE];
2408
ad6ca5f4 2409 zlog_debug(
ef7b8be4
DL
2410 "re-add sync-mac vni %u mac %pEA es %s seq %d f %s",
2411 zevpn->vni, &mac->macaddr,
ad6ca5f4 2412 mac->es ? mac->es->esi_str : "-", mac->loc_seq,
b16e8004
DS
2413 zebra_evpn_zebra_mac_flag_dump(
2414 mac, mac_buf, sizeof(mac_buf)));
2415 }
ad6ca5f4
PR
2416
2417 /* inform-bgp about change in local-activity if any */
2418 if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE)) {
2419 SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE);
2420 new_bgp_ready =
2421 zebra_evpn_mac_is_ready_for_bgp(mac->flags);
2422 zebra_evpn_mac_send_add_del_to_client(
2423 mac, old_bgp_ready, new_bgp_ready);
2424 }
2425
1a4f9efd
AK
2426 /* re-install the inactive entry in the kernel */
2427 zebra_evpn_sync_mac_dp_install(mac, true /* set_inactive */,
ad6ca5f4
PR
2428 false /* force_clear_static */,
2429 __func__);
2430
2431 return 0;
2432 }
2433
00a7710c
AK
2434 /* flush the peer info */
2435 zebra_evpn_mac_clear_sync_info(mac);
2436
ad6ca5f4
PR
2437 /* Update all the neigh entries associated with this mac */
2438 zebra_evpn_process_neigh_on_local_mac_del(zevpn, mac);
2439
2440 /* Remove MAC from BGP. */
46d6f5a2 2441 zebra_evpn_mac_send_del_to_client(zevpn->vni, &mac->macaddr, mac->flags,
ad6ca5f4
PR
2442 false /* force */);
2443
2444 zebra_evpn_es_mac_deref_entry(mac);
2445
8b07f173
AK
2446 /* remove links to the destination access port */
2447 zebra_evpn_mac_clear_fwd_info(mac);
2448
ad6ca5f4
PR
2449 /*
2450 * If there are no neigh associated with the mac delete the mac
2451 * else mark it as AUTO for forward reference
2452 */
2453 if (!listcount(mac->neigh_list)) {
2454 zebra_evpn_mac_del(zevpn, mac);
2455 } else {
2456 UNSET_FLAG(mac->flags, ZEBRA_MAC_ALL_LOCAL_FLAGS);
2457 UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
2458 SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
2459 }
2460
2461 return 0;
2462}
7bce3535 2463
5ff58d0a 2464void zebra_evpn_mac_gw_macip_add(struct interface *ifp,
2465 struct zebra_evpn *zevpn,
2466 const struct ipaddr *ip,
2467 struct zebra_mac **macp,
2468 const struct ethaddr *macaddr,
2469 vlanid_t vlan_id, bool def_gw)
7bce3535 2470{
3198b2b3 2471 struct zebra_mac *mac;
47c58929
PG
2472 ns_id_t local_ns_id = NS_DEFAULT;
2473 struct zebra_vrf *zvrf;
2474
096f7609 2475 zvrf = ifp->vrf->info;
47c58929
PG
2476 if (zvrf && zvrf->zns)
2477 local_ns_id = zvrf->zns->ns_id;
7bce3535 2478
b83d220a 2479 if (!*macp) {
2480 mac = zebra_evpn_mac_lookup(zevpn, macaddr);
2481 if (!mac)
2482 mac = zebra_evpn_mac_add(zevpn, macaddr);
2483 *macp = mac;
2484 } else
2485 mac = *macp;
7bce3535
PR
2486
2487 /* Set "local" forwarding info. */
8b07f173 2488 zebra_evpn_mac_clear_fwd_info(mac);
7bce3535
PR
2489 SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
2490 SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
e4c3ece6
AK
2491 if (def_gw)
2492 SET_FLAG(mac->flags, ZEBRA_MAC_DEF_GW);
5ff58d0a 2493 else
2494 SET_FLAG(mac->flags, ZEBRA_MAC_SVI);
7bce3535 2495 mac->fwd_info.local.ifindex = ifp->ifindex;
47c58929 2496 mac->fwd_info.local.ns_id = local_ns_id;
7bce3535 2497 mac->fwd_info.local.vid = vlan_id;
7bce3535 2498}
243b74ed 2499
f6371c34 2500void zebra_evpn_mac_svi_del(struct interface *ifp, struct zebra_evpn *zevpn)
243b74ed 2501{
3198b2b3 2502 struct zebra_mac *mac;
243b74ed 2503 struct ethaddr macaddr;
e4c3ece6 2504 bool old_bgp_ready;
243b74ed
AK
2505
2506 if (!zebra_evpn_mh_do_adv_svi_mac())
2507 return;
2508
2509 memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN);
2510 mac = zebra_evpn_mac_lookup(zevpn, &macaddr);
2511 if (mac && CHECK_FLAG(mac->flags, ZEBRA_MAC_SVI)) {
2512 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
2513 zlog_debug("SVI %s mac free", ifp->name);
2514
e4c3ece6 2515 old_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
243b74ed 2516 UNSET_FLAG(mac->flags, ZEBRA_MAC_SVI);
e4c3ece6
AK
2517 zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready,
2518 false);
243b74ed
AK
2519 zebra_evpn_deref_ip2mac(mac->zevpn, mac);
2520 }
2521}
2522
f6371c34 2523void zebra_evpn_mac_svi_add(struct interface *ifp, struct zebra_evpn *zevpn)
243b74ed 2524{
3198b2b3 2525 struct zebra_mac *mac = NULL;
243b74ed
AK
2526 struct ethaddr macaddr;
2527 struct zebra_if *zif = ifp->info;
e4c3ece6
AK
2528 bool old_bgp_ready;
2529 bool new_bgp_ready;
243b74ed 2530
e4c3ece6
AK
2531 if (!zebra_evpn_mh_do_adv_svi_mac()
2532 || !zebra_evpn_send_to_client_ok(zevpn))
243b74ed
AK
2533 return;
2534
2535 memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN);
2536
2537 /* dup check */
2538 mac = zebra_evpn_mac_lookup(zevpn, &macaddr);
2539 if (mac && CHECK_FLAG(mac->flags, ZEBRA_MAC_SVI))
2540 return;
2541
2542 /* add/update mac */
2543 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
2544 zlog_debug("SVI %s mac add", zif->ifp->name);
2545
e4c3ece6
AK
2546 old_bgp_ready = (mac && zebra_evpn_mac_is_ready_for_bgp(mac->flags))
2547 ? true
2548 : false;
2549
e4c3ece6 2550 zebra_evpn_mac_gw_macip_add(ifp, zevpn, NULL, &mac, &macaddr, 0, false);
e4c3ece6
AK
2551
2552 new_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
2553 zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready,
2554 new_bgp_ready);
243b74ed 2555}