]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_evpn_mac.c
Merge pull request #11564 from kuldeepkash/multicast_pim_bsm
[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 " : "",
377 CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE) ? "LOC Active "
378 : "",
379 CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY) ? "PROXY " : "",
380 CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE)
381 ? "LOC Inactive "
382 : "");
383 return buf;
384}
385
cc9f21da 386static void zebra_evpn_dad_mac_auto_recovery_exp(struct thread *t)
b2998086
PR
387{
388 struct zebra_vrf *zvrf = NULL;
3198b2b3 389 struct zebra_mac *mac = NULL;
f6371c34 390 struct zebra_evpn *zevpn = NULL;
b2998086 391 struct listnode *node = NULL;
72de4110 392 struct zebra_neigh *nbr = NULL;
b2998086
PR
393
394 mac = THREAD_ARG(t);
395
396 /* since this is asynchronous we need sanity checks*/
397 zvrf = vrf_info_lookup(mac->zevpn->vrf_id);
398 if (!zvrf)
cc9f21da 399 return;
b2998086 400
8b5fdf2e 401 zevpn = zebra_evpn_lookup(mac->zevpn->vni);
b2998086 402 if (!zevpn)
cc9f21da 403 return;
b2998086
PR
404
405 mac = zebra_evpn_mac_lookup(zevpn, &mac->macaddr);
406 if (!mac)
cc9f21da 407 return;
b2998086 408
b16e8004
DS
409 if (IS_ZEBRA_DEBUG_VXLAN) {
410 char mac_buf[MAC_BUF_SIZE];
411
b2998086 412 zlog_debug(
ef7b8be4
DL
413 "%s: duplicate addr mac %pEA flags %slearn count %u host count %u auto recovery expired",
414 __func__, &mac->macaddr,
b16e8004
DS
415 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
416 sizeof(mac_buf)),
417 mac->dad_count, listcount(mac->neigh_list));
418 }
b2998086
PR
419
420 /* Remove all IPs as duplicate associcated with this MAC */
421 for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, nbr)) {
422 if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE)) {
423 if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL))
424 ZEBRA_NEIGH_SET_INACTIVE(nbr);
425 else if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_REMOTE))
426 zebra_evpn_rem_neigh_install(
427 zevpn, nbr, false /*was_static*/);
428 }
24268cd0 429
24268cd0
PR
430 UNSET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE);
431 nbr->dad_count = 0;
432 nbr->detect_start_time.tv_sec = 0;
b2998086
PR
433 nbr->dad_dup_detect_time = 0;
434 }
435
436 UNSET_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE);
437 mac->dad_count = 0;
438 mac->detect_start_time.tv_sec = 0;
439 mac->detect_start_time.tv_usec = 0;
440 mac->dad_dup_detect_time = 0;
441 mac->dad_mac_auto_recovery_timer = NULL;
442
443 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
444 /* Inform to BGP */
445 if (zebra_evpn_mac_send_add_to_client(zevpn->vni, &mac->macaddr,
446 mac->flags, mac->loc_seq,
447 mac->es))
cc9f21da 448 return;
b2998086
PR
449
450 /* Process all neighbors associated with this MAC. */
451 zebra_evpn_process_neigh_on_local_mac_change(zevpn, mac, 0,
452 0 /*es_change*/);
453
454 } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
455 zebra_evpn_process_neigh_on_remote_mac_add(zevpn, mac);
456
457 /* Install the entry. */
458 zebra_evpn_rem_mac_install(zevpn, mac, false /* was_static */);
24268cd0 459 }
24268cd0
PR
460}
461
d9d3455e 462static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf,
3198b2b3 463 struct zebra_mac *mac,
d9d3455e
PR
464 struct in_addr vtep_ip,
465 bool do_dad, bool *is_dup_detect,
466 bool is_local)
24268cd0 467{
72de4110 468 struct zebra_neigh *nbr;
24268cd0
PR
469 struct listnode *node = NULL;
470 struct timeval elapsed = {0, 0};
24268cd0
PR
471 bool reset_params = false;
472
b2ee2b71 473 if (!(zebra_evpn_do_dup_addr_detect(zvrf) && do_dad))
24268cd0
PR
474 return;
475
476 /* MAC is detected as duplicate,
477 * Local MAC event -> hold on advertising to BGP.
478 * Remote MAC event -> hold on installing it.
479 */
480 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) {
b16e8004
DS
481 if (IS_ZEBRA_DEBUG_VXLAN) {
482 char mac_buf[MAC_BUF_SIZE];
483
24268cd0 484 zlog_debug(
ef7b8be4
DL
485 "%s: duplicate addr MAC %pEA flags %sskip update to client, learn count %u recover time %u",
486 __func__, &mac->macaddr,
b16e8004
DS
487 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
488 sizeof(mac_buf)),
489 mac->dad_count, zvrf->dad_freeze_time);
490 }
24268cd0
PR
491 /* For duplicate MAC do not update
492 * client but update neigh due to
493 * this MAC update.
494 */
495 if (zvrf->dad_freeze)
496 *is_dup_detect = true;
497
498 return;
499 }
500
501 /* Check if detection time (M-secs) expired.
502 * Reset learn count and detection start time.
503 */
504 monotime_since(&mac->detect_start_time, &elapsed);
505 reset_params = (elapsed.tv_sec > zvrf->dad_time);
506 if (is_local && !reset_params) {
507 /* RFC-7432: A PE/VTEP that detects a MAC mobility
508 * event via LOCAL learning starts an M-second timer.
509 *
510 * NOTE: This is the START of the probe with count is
511 * 0 during LOCAL learn event.
512 * (mac->dad_count == 0 || elapsed.tv_sec >= zvrf->dad_time)
513 */
514 reset_params = !mac->dad_count;
515 }
516
517 if (reset_params) {
b16e8004
DS
518 if (IS_ZEBRA_DEBUG_VXLAN) {
519 char mac_buf[MAC_BUF_SIZE];
520
24268cd0 521 zlog_debug(
ef7b8be4
DL
522 "%s: duplicate addr MAC %pEA flags %sdetection time passed, reset learn count %u",
523 __func__, &mac->macaddr,
b16e8004
DS
524 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
525 sizeof(mac_buf)),
526 mac->dad_count);
527 }
24268cd0
PR
528
529 mac->dad_count = 0;
530 /* Start dup. addr detection (DAD) start time,
531 * ONLY during LOCAL learn.
532 */
533 if (is_local)
534 monotime(&mac->detect_start_time);
535
536 } else if (!is_local) {
537 /* For REMOTE MAC, increment detection count
538 * ONLY while in probe window, once window passed,
539 * next local learn event should trigger DAD.
540 */
541 mac->dad_count++;
542 }
543
544 /* For LOCAL MAC learn event, once count is reset above via either
545 * initial/start detection time or passed the probe time, the count
546 * needs to be incremented.
547 */
548 if (is_local)
549 mac->dad_count++;
550
551 if (mac->dad_count >= zvrf->dad_max_moves) {
552 flog_warn(EC_ZEBRA_DUP_MAC_DETECTED,
ef7b8be4
DL
553 "VNI %u: MAC %pEA detected as duplicate during %s VTEP %pI4",
554 mac->zevpn->vni, &mac->macaddr,
24268cd0 555 is_local ? "local update, last" :
9bcef951 556 "remote update, from", &vtep_ip);
24268cd0
PR
557
558 SET_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE);
559
560 /* Capture Duplicate detection time */
561 mac->dad_dup_detect_time = monotime(NULL);
562
563 /* Mark all IPs/Neighs as duplicate
564 * associcated with this MAC
565 */
566 for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, nbr)) {
567
568 /* Ony Mark IPs which are Local */
569 if (!CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL))
570 continue;
571
572 SET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE);
573
574 nbr->dad_dup_detect_time = monotime(NULL);
575
576 flog_warn(EC_ZEBRA_DUP_IP_INHERIT_DETECTED,
ef7b8be4
DL
577 "VNI %u: MAC %pEA IP %pIA detected as duplicate during %s update, inherit duplicate from MAC",
578 mac->zevpn->vni, &mac->macaddr, &nbr->ip,
24268cd0
PR
579 is_local ? "local" : "remote");
580 }
581
582 /* Start auto recovery timer for this MAC */
583 THREAD_OFF(mac->dad_mac_auto_recovery_timer);
584 if (zvrf->dad_freeze && zvrf->dad_freeze_time) {
b16e8004
DS
585 if (IS_ZEBRA_DEBUG_VXLAN) {
586 char mac_buf[MAC_BUF_SIZE];
587
24268cd0 588 zlog_debug(
ef7b8be4
DL
589 "%s: duplicate addr MAC %pEA flags %sauto recovery time %u start",
590 __func__, &mac->macaddr,
b16e8004
DS
591 zebra_evpn_zebra_mac_flag_dump(
592 mac, mac_buf, sizeof(mac_buf)),
593 zvrf->dad_freeze_time);
594 }
24268cd0
PR
595
596 thread_add_timer(zrouter.master,
b2998086 597 zebra_evpn_dad_mac_auto_recovery_exp,
24268cd0
PR
598 mac, zvrf->dad_freeze_time,
599 &mac->dad_mac_auto_recovery_timer);
600 }
601
602 /* In case of local update, do not inform to client (BGPd),
603 * upd_neigh for neigh sequence change.
604 */
605 if (zvrf->dad_freeze)
606 *is_dup_detect = true;
607 }
608}
609
b2998086
PR
610/*
611 * Print a specific MAC entry.
612 */
3198b2b3 613void zebra_evpn_print_mac(struct zebra_mac *mac, void *ctxt, json_object *json)
24268cd0 614{
b2998086 615 struct vty *vty;
72de4110 616 struct zebra_neigh *n = NULL;
b2998086
PR
617 struct listnode *node = NULL;
618 char buf1[ETHER_ADDR_STRLEN];
619 char buf2[INET6_ADDRSTRLEN];
620 struct zebra_vrf *zvrf;
621 struct timeval detect_start_time = {0, 0};
622 char timebuf[MONOTIME_STRLEN];
623 char thread_buf[THREAD_TIMER_STRLEN];
f1dbb1c7
DS
624 time_t uptime;
625 char up_str[MONOTIME_STRLEN];
24268cd0 626
b2998086 627 zvrf = zebra_vrf_get_evpn();
b2998086
PR
628 vty = (struct vty *)ctxt;
629 prefix_mac2str(&mac->macaddr, buf1, sizeof(buf1));
24268cd0 630
f1dbb1c7
DS
631 uptime = monotime(NULL);
632 uptime -= mac->uptime;
633
634 frrtime_to_interval(uptime, up_str, sizeof(up_str));
635
b2998086
PR
636 if (json) {
637 json_object *json_mac = json_object_new_object();
24268cd0 638
b2998086
PR
639 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
640 struct interface *ifp;
641 vlanid_t vid;
24268cd0 642
b2998086
PR
643 zebra_evpn_mac_get_access_info(mac, &ifp, &vid);
644 json_object_string_add(json_mac, "type", "local");
645 if (ifp) {
646 json_object_string_add(json_mac, "intf",
647 ifp->name);
648 json_object_int_add(json_mac, "ifindex",
649 ifp->ifindex);
650 }
651 if (vid)
652 json_object_int_add(json_mac, "vlan", vid);
653 } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
654 json_object_string_add(json_mac, "type", "remote");
08edf9c6
DA
655 json_object_string_addf(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");
08edf9c6
DA
939 json_object_string_addf(json_mac, "remoteVtep", "%pI4",
940 &mac->fwd_info.r_vtep_ip);
b2998086
PR
941 json_object_object_add(json_mac_hdr, buf1, json_mac);
942 json_object_int_add(json_mac, "localSequence",
943 mac->loc_seq);
944 json_object_int_add(json_mac, "remoteSequence",
945 mac->rem_seq);
946 json_object_int_add(json_mac, "detectionCount",
947 mac->dad_count);
948 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
949 json_object_boolean_true_add(json_mac,
950 "isDuplicate");
951 else
952 json_object_boolean_false_add(json_mac,
953 "isDuplicate");
954 }
24268cd0 955
b2998086
PR
956 wctx->count++;
957 }
24268cd0
PR
958}
959
960/*
b2998086 961 * Print MAC hash entry in detail - called for display of all MACs.
24268cd0 962 */
b2998086 963void zebra_evpn_print_mac_hash_detail(struct hash_bucket *bucket, void *ctxt)
24268cd0 964{
b2998086
PR
965 struct vty *vty;
966 json_object *json_mac_hdr = NULL;
3198b2b3 967 struct zebra_mac *mac;
b2998086
PR
968 struct mac_walk_ctx *wctx = ctxt;
969 char buf1[ETHER_ADDR_STRLEN];
24268cd0 970
b2998086
PR
971 vty = wctx->vty;
972 json_mac_hdr = wctx->json;
3198b2b3 973 mac = (struct zebra_mac *)bucket->data;
b2998086 974 if (!mac)
24268cd0
PR
975 return;
976
b2998086
PR
977 wctx->count++;
978 prefix_mac2str(&mac->macaddr, buf1, sizeof(buf1));
24268cd0 979
b2998086 980 zebra_evpn_print_mac(mac, vty, json_mac_hdr);
24268cd0
PR
981}
982
983/*
b2998086 984 * Inform BGP about local MACIP.
24268cd0 985 */
7f7e49d1
MS
986int zebra_evpn_macip_send_msg_to_client(vni_t vni,
987 const struct ethaddr *macaddr,
1a3bd37f 988 const struct ipaddr *ip, uint8_t flags,
b2998086
PR
989 uint32_t seq, int state,
990 struct zebra_evpn_es *es, uint16_t cmd)
24268cd0 991{
b2998086
PR
992 int ipa_len;
993 struct zserv *client = NULL;
994 struct stream *s = NULL;
995 esi_t *esi = es ? &es->esi : zero_esi;
24268cd0 996
b2998086
PR
997 client = zserv_find_client(ZEBRA_ROUTE_BGP, 0);
998 /* BGP may not be running. */
999 if (!client)
1000 return 0;
24268cd0 1001
b2998086 1002 s = stream_new(ZEBRA_MAX_PACKET_SIZ);
24268cd0 1003
b2998086
PR
1004 zclient_create_header(s, cmd, zebra_vrf_get_evpn_id());
1005 stream_putl(s, vni);
1006 stream_put(s, macaddr->octet, ETH_ALEN);
1007 if (ip) {
1008 ipa_len = 0;
1009 if (IS_IPADDR_V4(ip))
1010 ipa_len = IPV4_MAX_BYTELEN;
1011 else if (IS_IPADDR_V6(ip))
1012 ipa_len = IPV6_MAX_BYTELEN;
24268cd0 1013
b2998086
PR
1014 stream_putl(s, ipa_len); /* IP address length */
1015 if (ipa_len)
1016 stream_put(s, &ip->ip.addr, ipa_len); /* IP address */
1017 } else
1018 stream_putl(s, 0); /* Just MAC. */
24268cd0 1019
b2998086
PR
1020 if (cmd == ZEBRA_MACIP_ADD) {
1021 stream_putc(s, flags); /* sticky mac/gateway mac */
1022 stream_putl(s, seq); /* sequence number */
1023 stream_put(s, esi, sizeof(esi_t));
24268cd0 1024 } else {
b2998086
PR
1025 stream_putl(s, state); /* state - active/inactive */
1026 }
24268cd0 1027
24268cd0 1028
b2998086
PR
1029 /* Write packet size. */
1030 stream_putw_at(s, 0, stream_get_endp(s));
24268cd0 1031
bf902d4c
DS
1032 if (IS_ZEBRA_DEBUG_VXLAN) {
1033 char flag_buf[MACIP_BUF_SIZE];
1034
b2998086 1035 zlog_debug(
ef7b8be4 1036 "Send MACIP %s f %s MAC %pEA IP %pIA seq %u L2-VNI %u ESI %s to %s",
bf902d4c
DS
1037 (cmd == ZEBRA_MACIP_ADD) ? "Add" : "Del",
1038 zclient_evpn_dump_macip_flags(flags, flag_buf,
1039 sizeof(flag_buf)),
ef7b8be4 1040 macaddr, ip, seq, vni,
b2998086
PR
1041 es ? es->esi_str : "-",
1042 zebra_route_string(client->proto));
bf902d4c 1043 }
24268cd0 1044
b2998086
PR
1045 if (cmd == ZEBRA_MACIP_ADD)
1046 client->macipadd_cnt++;
1047 else
1048 client->macipdel_cnt++;
24268cd0 1049
b2998086
PR
1050 return zserv_send_message(client, s);
1051}
24268cd0 1052
b2998086
PR
1053static unsigned int mac_hash_keymake(const void *p)
1054{
3198b2b3 1055 const struct zebra_mac *pmac = p;
b2998086 1056 const void *pnt = (void *)pmac->macaddr.octet;
24268cd0 1057
b2998086 1058 return jhash(pnt, ETH_ALEN, 0xa5a5a55a);
24268cd0
PR
1059}
1060
1061/*
b2998086 1062 * Compare two MAC addresses.
24268cd0 1063 */
b2998086 1064static bool mac_cmp(const void *p1, const void *p2)
24268cd0 1065{
3198b2b3
DS
1066 const struct zebra_mac *pmac1 = p1;
1067 const struct zebra_mac *pmac2 = p2;
24268cd0 1068
b2998086
PR
1069 if (pmac1 == NULL && pmac2 == NULL)
1070 return true;
24268cd0 1071
b2998086
PR
1072 if (pmac1 == NULL || pmac2 == NULL)
1073 return false;
24268cd0 1074
b2998086
PR
1075 return (memcmp(pmac1->macaddr.octet, pmac2->macaddr.octet, ETH_ALEN)
1076 == 0);
1077}
24268cd0 1078
b2998086
PR
1079/*
1080 * Callback to allocate MAC hash entry.
1081 */
1082static void *zebra_evpn_mac_alloc(void *p)
1083{
3198b2b3
DS
1084 const struct zebra_mac *tmp_mac = p;
1085 struct zebra_mac *mac;
24268cd0 1086
3198b2b3 1087 mac = XCALLOC(MTYPE_MAC, sizeof(struct zebra_mac));
b2998086 1088 *mac = *tmp_mac;
24268cd0 1089
b2998086
PR
1090 return ((void *)mac);
1091}
24268cd0 1092
b2998086
PR
1093/*
1094 * Add MAC entry.
1095 */
3198b2b3
DS
1096struct zebra_mac *zebra_evpn_mac_add(struct zebra_evpn *zevpn,
1097 const struct ethaddr *macaddr)
b2998086 1098{
3198b2b3
DS
1099 struct zebra_mac tmp_mac;
1100 struct zebra_mac *mac = NULL;
24268cd0 1101
6006b807 1102 memset(&tmp_mac, 0, sizeof(tmp_mac));
b2998086
PR
1103 memcpy(&tmp_mac.macaddr, macaddr, ETH_ALEN);
1104 mac = hash_get(zevpn->mac_table, &tmp_mac, zebra_evpn_mac_alloc);
24268cd0 1105
b2998086
PR
1106 mac->zevpn = zevpn;
1107 mac->dad_mac_auto_recovery_timer = NULL;
24268cd0 1108
b2998086
PR
1109 mac->neigh_list = list_new();
1110 mac->neigh_list->cmp = neigh_list_cmp;
24268cd0 1111
f1dbb1c7 1112 mac->uptime = monotime(NULL);
b2998086 1113 if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
b16e8004 1114 char mac_buf[MAC_BUF_SIZE];
24268cd0 1115
ef7b8be4
DL
1116 zlog_debug("%s: MAC %pEA flags %s", __func__,
1117 &mac->macaddr,
b16e8004
DS
1118 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
1119 sizeof(mac_buf)));
b2998086
PR
1120 }
1121 return mac;
24268cd0
PR
1122}
1123
1124/*
b2998086 1125 * Delete MAC entry.
24268cd0 1126 */
3198b2b3 1127int zebra_evpn_mac_del(struct zebra_evpn *zevpn, struct zebra_mac *mac)
24268cd0 1128{
3198b2b3 1129 struct zebra_mac *tmp_mac;
24268cd0 1130
b2998086 1131 if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
b16e8004 1132 char mac_buf[MAC_BUF_SIZE];
b2998086 1133
ef7b8be4
DL
1134 zlog_debug("%s: MAC %pEA flags %s", __func__,
1135 &mac->macaddr,
b16e8004
DS
1136 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
1137 sizeof(mac_buf)));
24268cd0
PR
1138 }
1139
b2998086
PR
1140 /* force de-ref any ES entry linked to the MAC */
1141 zebra_evpn_es_mac_deref_entry(mac);
24268cd0 1142
8b07f173
AK
1143 /* remove links to the destination access port */
1144 zebra_evpn_mac_clear_fwd_info(mac);
1145
b2998086
PR
1146 /* Cancel proxy hold timer */
1147 zebra_evpn_mac_stop_hold_timer(mac);
24268cd0 1148
b2998086
PR
1149 /* Cancel auto recovery */
1150 THREAD_OFF(mac->dad_mac_auto_recovery_timer);
24268cd0 1151
d5fdae8f
CS
1152 /* If the MAC is freed before the neigh we will end up
1153 * with a stale pointer against the neigh.
1154 * The situation can arise when a MAC is in remote state
1155 * and its associated neigh is local state.
1156 * zebra_evpn_cfg_cleanup() cleans up remote neighs and MACs.
1157 * Instead of deleting remote MAC, if its neigh list is non-empty
1158 * (associated to local neighs), mark the MAC as AUTO.
1159 */
1160 if (!list_isempty(mac->neigh_list)) {
1161 if (IS_ZEBRA_DEBUG_VXLAN)
1162 zlog_debug(
1163 "MAC %pEA (flags 0x%x vni %u) has non-empty neigh list "
1164 "count %u, mark MAC as AUTO",
1165 &mac->macaddr, mac->flags, zevpn->vni,
1166 listcount(mac->neigh_list));
1167
1168 SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
1169 return 0;
1170 }
1171
b2998086 1172 list_delete(&mac->neigh_list);
24268cd0 1173
b2998086
PR
1174 /* Free the VNI hash entry and allocated memory. */
1175 tmp_mac = hash_release(zevpn->mac_table, mac);
1176 XFREE(MTYPE_MAC, tmp_mac);
24268cd0 1177
b2998086
PR
1178 return 0;
1179}
24268cd0 1180
b2998086 1181static bool zebra_evpn_check_mac_del_from_db(struct mac_walk_ctx *wctx,
3198b2b3 1182 struct zebra_mac *mac)
b2998086
PR
1183{
1184 if ((wctx->flags & DEL_LOCAL_MAC) && (mac->flags & ZEBRA_MAC_LOCAL))
1185 return true;
1186 else if ((wctx->flags & DEL_REMOTE_MAC)
1187 && (mac->flags & ZEBRA_MAC_REMOTE))
1188 return true;
1189 else if ((wctx->flags & DEL_REMOTE_MAC_FROM_VTEP)
1190 && (mac->flags & ZEBRA_MAC_REMOTE)
1191 && IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &wctx->r_vtep_ip))
1192 return true;
1193 else if ((wctx->flags & DEL_LOCAL_MAC) && (mac->flags & ZEBRA_MAC_AUTO)
1194 && !listcount(mac->neigh_list)) {
1195 if (IS_ZEBRA_DEBUG_VXLAN) {
b16e8004 1196 char mac_buf[MAC_BUF_SIZE];
24268cd0 1197
24268cd0 1198 zlog_debug(
ef7b8be4
DL
1199 "%s: Del MAC %pEA flags %s", __func__,
1200 &mac->macaddr,
b16e8004
DS
1201 zebra_evpn_zebra_mac_flag_dump(
1202 mac, mac_buf, sizeof(mac_buf)));
b2998086
PR
1203 }
1204 wctx->uninstall = 0;
24268cd0 1205
b2998086
PR
1206 return true;
1207 }
24268cd0 1208
b2998086
PR
1209 return false;
1210}
24268cd0 1211
b2998086
PR
1212/*
1213 * Free MAC hash entry (callback)
1214 */
1215static void zebra_evpn_mac_del_hash_entry(struct hash_bucket *bucket, void *arg)
1216{
1217 struct mac_walk_ctx *wctx = arg;
3198b2b3 1218 struct zebra_mac *mac = bucket->data;
24268cd0 1219
b2998086
PR
1220 if (zebra_evpn_check_mac_del_from_db(wctx, mac)) {
1221 if (wctx->upd_client && (mac->flags & ZEBRA_MAC_LOCAL)) {
1222 zebra_evpn_mac_send_del_to_client(wctx->zevpn->vni,
1223 &mac->macaddr,
1224 mac->flags, false);
1225 }
1226 if (wctx->uninstall) {
1227 if (zebra_evpn_mac_is_static(mac))
1228 zebra_evpn_sync_mac_dp_install(
1229 mac, false /* set_inactive */,
1230 true /* force_clear_static */,
1231 __func__);
24268cd0 1232
b2998086 1233 if (mac->flags & ZEBRA_MAC_REMOTE)
f3722826
AK
1234 zebra_evpn_rem_mac_uninstall(wctx->zevpn, mac,
1235 false /*force*/);
24268cd0 1236 }
b2998086
PR
1237
1238 zebra_evpn_mac_del(wctx->zevpn, mac);
24268cd0
PR
1239 }
1240
24268cd0
PR
1241 return;
1242}
1243
24268cd0 1244/*
b2998086 1245 * Delete all MAC entries for this EVPN.
24268cd0 1246 */
f6371c34
DS
1247void zebra_evpn_mac_del_all(struct zebra_evpn *zevpn, int uninstall,
1248 int upd_client, uint32_t flags)
24268cd0 1249{
b2998086 1250 struct mac_walk_ctx wctx;
24268cd0 1251
b2998086 1252 if (!zevpn->mac_table)
24268cd0
PR
1253 return;
1254
6006b807 1255 memset(&wctx, 0, sizeof(wctx));
b2998086
PR
1256 wctx.zevpn = zevpn;
1257 wctx.uninstall = uninstall;
1258 wctx.upd_client = upd_client;
1259 wctx.flags = flags;
24268cd0 1260
b2998086
PR
1261 hash_iterate(zevpn->mac_table, zebra_evpn_mac_del_hash_entry, &wctx);
1262}
24268cd0 1263
b2998086
PR
1264/*
1265 * Look up MAC hash entry.
1266 */
3198b2b3
DS
1267struct zebra_mac *zebra_evpn_mac_lookup(struct zebra_evpn *zevpn,
1268 const struct ethaddr *mac)
b2998086 1269{
3198b2b3
DS
1270 struct zebra_mac tmp;
1271 struct zebra_mac *pmac;
24268cd0 1272
b2998086
PR
1273 memset(&tmp, 0, sizeof(tmp));
1274 memcpy(&tmp.macaddr, mac, ETH_ALEN);
1275 pmac = hash_lookup(zevpn->mac_table, &tmp);
24268cd0 1276
b2998086
PR
1277 return pmac;
1278}
24268cd0 1279
b2998086
PR
1280/*
1281 * Inform BGP about local MAC addition.
1282 */
1a3bd37f 1283int zebra_evpn_mac_send_add_to_client(vni_t vni, const struct ethaddr *macaddr,
b2998086
PR
1284 uint32_t mac_flags, uint32_t seq,
1285 struct zebra_evpn_es *es)
1286{
1287 uint8_t flags = 0;
24268cd0 1288
b2998086
PR
1289 if (CHECK_FLAG(mac_flags, ZEBRA_MAC_LOCAL_INACTIVE)) {
1290 /* host reachability has not been verified locally */
24268cd0 1291
b2998086
PR
1292 /* if no ES peer is claiming reachability we can't advertise the
1293 * entry
1294 */
1295 if (!CHECK_FLAG(mac_flags, ZEBRA_MAC_ES_PEER_ACTIVE))
1296 return 0;
24268cd0 1297
b2998086
PR
1298 /* ES peers are claiming reachability; we will
1299 * advertise the entry but with a proxy flag
24268cd0 1300 */
b2998086
PR
1301 SET_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT);
1302 }
24268cd0 1303
b2998086
PR
1304 if (CHECK_FLAG(mac_flags, ZEBRA_MAC_STICKY))
1305 SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
1306 if (CHECK_FLAG(mac_flags, ZEBRA_MAC_DEF_GW))
1307 SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
24268cd0 1308
b2998086
PR
1309 return zebra_evpn_macip_send_msg_to_client(vni, macaddr, NULL, flags,
1310 seq, ZEBRA_NEIGH_ACTIVE, es,
1311 ZEBRA_MACIP_ADD);
1312}
24268cd0 1313
b2998086
PR
1314/*
1315 * Inform BGP about local MAC deletion.
1316 */
1a3bd37f 1317int zebra_evpn_mac_send_del_to_client(vni_t vni, const struct ethaddr *macaddr,
b2998086
PR
1318 uint32_t flags, bool force)
1319{
1320 if (!force) {
1321 if (CHECK_FLAG(flags, ZEBRA_MAC_LOCAL_INACTIVE)
1322 && !CHECK_FLAG(flags, ZEBRA_MAC_ES_PEER_ACTIVE))
1323 /* the host was not advertised - nothing to delete */
1324 return 0;
24268cd0
PR
1325 }
1326
b2998086
PR
1327 return zebra_evpn_macip_send_msg_to_client(
1328 vni, macaddr, NULL, 0 /* flags */, 0 /* seq */,
1329 ZEBRA_NEIGH_ACTIVE, NULL, ZEBRA_MACIP_DEL);
24268cd0
PR
1330}
1331
1332/*
b2998086 1333 * wrapper to create a MAC hash table
24268cd0 1334 */
b2998086 1335struct hash *zebra_mac_db_create(const char *desc)
24268cd0 1336{
da55bcbc 1337 return hash_create_size(8, mac_hash_keymake, mac_cmp, desc);
24268cd0
PR
1338}
1339
b2998086 1340/* program sync mac flags in the dataplane */
3198b2b3 1341int zebra_evpn_sync_mac_dp_install(struct zebra_mac *mac, bool set_inactive,
15400f95 1342 bool force_clear_static, const char *caller)
24268cd0 1343{
b2998086
PR
1344 struct interface *ifp;
1345 bool sticky;
1346 bool set_static;
f6371c34 1347 struct zebra_evpn *zevpn = mac->zevpn;
b2998086
PR
1348 vlanid_t vid;
1349 struct zebra_if *zif;
1350 struct interface *br_ifp;
24268cd0 1351
09de6e45
AK
1352 /* If the ES-EVI doesn't exist defer install. When the ES-EVI is
1353 * created we will attempt to install the mac entry again
1354 */
1355 if (mac->es) {
1356 struct zebra_evpn_es_evi *es_evi;
1357
1358 es_evi = zebra_evpn_es_evi_find(mac->es, mac->zevpn);
1359 if (!es_evi) {
1360 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
1361 zlog_debug(
1362 "%s: dp-install sync-mac vni %u mac %pEA es %s 0x%x %sskipped, no es-evi",
1363 caller, zevpn->vni, &mac->macaddr,
1364 mac->es ? mac->es->esi_str : "-",
1365 mac->flags,
1366 set_inactive ? "inactive " : "");
1367 return -1;
1368 }
1369 }
1370
b2998086
PR
1371 /* get the access vlan from the vxlan_device */
1372 zebra_evpn_mac_get_access_info(mac, &ifp, &vid);
24268cd0 1373
b2998086 1374 if (!ifp) {
b16e8004
DS
1375 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
1376 char mac_buf[MAC_BUF_SIZE];
1377
b2998086 1378 zlog_debug(
b16e8004 1379 "%s: dp-install sync-mac vni %u mac %pEA es %s %s%sskipped, no access-port",
15400f95 1380 caller, zevpn->vni, &mac->macaddr,
b16e8004
DS
1381 mac->es ? mac->es->esi_str : "-",
1382 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
1383 sizeof(mac_buf)),
b2998086 1384 set_inactive ? "inactive " : "");
b16e8004 1385 }
15400f95 1386 return -1;
b2998086 1387 }
24268cd0 1388
b2998086
PR
1389 zif = ifp->info;
1390 br_ifp = zif->brslave_info.br_if;
1391 if (!br_ifp) {
b16e8004
DS
1392 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
1393 char mac_buf[MAC_BUF_SIZE];
1394
b2998086 1395 zlog_debug(
b16e8004 1396 "%s: dp-install sync-mac vni %u mac %pEA es %s %s%sskipped, no br",
15400f95 1397 caller, zevpn->vni, &mac->macaddr,
b16e8004
DS
1398 mac->es ? mac->es->esi_str : "-",
1399 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
1400 sizeof(mac_buf)),
b2998086 1401 set_inactive ? "inactive " : "");
b16e8004 1402 }
15400f95 1403 return -1;
b2998086 1404 }
24268cd0 1405
b2998086
PR
1406 sticky = !!CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY);
1407 if (force_clear_static)
1408 set_static = false;
1409 else
1410 set_static = zebra_evpn_mac_is_static(mac);
24268cd0 1411
15400f95
AK
1412 /* We can install a local mac that has been synced from the peer
1413 * over the VxLAN-overlay/network-port if fast failover is not
1414 * supported and if the local ES is oper-down.
1415 */
1416 if (mac->es && zebra_evpn_es_local_mac_via_network_port(mac->es)) {
b16e8004
DS
1417 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
1418 char mac_buf[MAC_BUF_SIZE];
1419
15400f95 1420 zlog_debug(
b16e8004 1421 "dp-%s sync-nw-mac vni %u mac %pEA es %s %s%s",
15400f95
AK
1422 set_static ? "install" : "uninstall",
1423 zevpn->vni, &mac->macaddr,
b16e8004
DS
1424 mac->es ? mac->es->esi_str : "-",
1425 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
1426 sizeof(mac_buf)),
15400f95 1427 set_inactive ? "inactive " : "");
b16e8004 1428 }
15400f95
AK
1429 if (set_static)
1430 /* XXX - old_static needs to be computed more
1431 * accurately
1432 */
1433 zebra_evpn_rem_mac_install(zevpn, mac,
1434 true /* old_static */);
1435 else
1436 zebra_evpn_rem_mac_uninstall(zevpn, mac,
1437 false /* force */);
1438
1439 return 0;
1440 }
1441
b16e8004
DS
1442 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
1443 char mac_buf[MAC_BUF_SIZE];
1444
1445 zlog_debug("dp-install sync-mac vni %u mac %pEA es %s %s%s%s",
1446 zevpn->vni, &mac->macaddr,
1447 mac->es ? mac->es->esi_str : "-",
1448 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
1449 sizeof(mac_buf)),
1450 set_static ? "static " : "",
1451 set_inactive ? "inactive " : "");
1452 }
24268cd0 1453
b2998086
PR
1454 dplane_local_mac_add(ifp, br_ifp, vid, &mac->macaddr, sticky,
1455 set_static, set_inactive);
15400f95 1456 return 0;
24268cd0
PR
1457}
1458
3198b2b3
DS
1459void zebra_evpn_mac_send_add_del_to_client(struct zebra_mac *mac,
1460 bool old_bgp_ready,
b2998086 1461 bool new_bgp_ready)
24268cd0 1462{
b2998086
PR
1463 if (new_bgp_ready)
1464 zebra_evpn_mac_send_add_to_client(mac->zevpn->vni,
1465 &mac->macaddr, mac->flags,
1466 mac->loc_seq, mac->es);
1467 else if (old_bgp_ready)
1468 zebra_evpn_mac_send_del_to_client(mac->zevpn->vni,
1469 &mac->macaddr, mac->flags,
1470 true /* force */);
24268cd0
PR
1471}
1472
b2998086
PR
1473/* MAC hold timer is used to age out peer-active flag.
1474 *
1475 * During this wait time we expect the dataplane component or an
1476 * external neighmgr daemon to probe existing hosts to independently
1477 * establish their presence on the ES.
1478 */
cc9f21da 1479static void zebra_evpn_mac_hold_exp_cb(struct thread *t)
24268cd0 1480{
3198b2b3 1481 struct zebra_mac *mac;
b2998086
PR
1482 bool old_bgp_ready;
1483 bool new_bgp_ready;
1484 bool old_static;
1485 bool new_static;
24268cd0
PR
1486
1487 mac = THREAD_ARG(t);
b2998086
PR
1488 /* the purpose of the hold timer is to age out the peer-active
1489 * flag
1490 */
1491 if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE))
cc9f21da 1492 return;
24268cd0 1493
b2998086
PR
1494 old_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
1495 old_static = zebra_evpn_mac_is_static(mac);
1496 UNSET_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE);
1497 new_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
1498 new_static = zebra_evpn_mac_is_static(mac);
24268cd0 1499
b16e8004
DS
1500 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
1501 char mac_buf[MAC_BUF_SIZE];
1502
24268cd0 1503 zlog_debug(
ef7b8be4
DL
1504 "sync-mac vni %u mac %pEA es %s %shold expired",
1505 mac->zevpn->vni, &mac->macaddr,
b16e8004
DS
1506 mac->es ? mac->es->esi_str : "-",
1507 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
1508 sizeof(mac_buf)));
1509 }
24268cd0 1510
b2998086
PR
1511 /* re-program the local mac in the dataplane if the mac is no
1512 * longer static
1513 */
1514 if (old_static != new_static)
1515 zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */,
1516 false /* force_clear_static */,
1517 __func__);
24268cd0 1518
b2998086
PR
1519 /* inform bgp if needed */
1520 if (old_bgp_ready != new_bgp_ready)
1521 zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready,
1522 new_bgp_ready);
24268cd0
PR
1523}
1524
3198b2b3 1525static inline void zebra_evpn_mac_start_hold_timer(struct zebra_mac *mac)
24268cd0 1526{
b2998086
PR
1527 if (mac->hold_timer)
1528 return;
24268cd0 1529
b16e8004
DS
1530 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
1531 char mac_buf[MAC_BUF_SIZE];
1532
24268cd0 1533 zlog_debug(
ef7b8be4
DL
1534 "sync-mac vni %u mac %pEA es %s %shold started",
1535 mac->zevpn->vni, &mac->macaddr,
b16e8004
DS
1536 mac->es ? mac->es->esi_str : "-",
1537 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
1538 sizeof(mac_buf)));
1539 }
b2998086
PR
1540 thread_add_timer(zrouter.master, zebra_evpn_mac_hold_exp_cb, mac,
1541 zmh_info->mac_hold_time, &mac->hold_timer);
24268cd0
PR
1542}
1543
3198b2b3 1544void zebra_evpn_mac_stop_hold_timer(struct zebra_mac *mac)
24268cd0 1545{
b2998086
PR
1546 if (!mac->hold_timer)
1547 return;
24268cd0 1548
b16e8004
DS
1549 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
1550 char mac_buf[MAC_BUF_SIZE];
1551
b2998086 1552 zlog_debug(
ef7b8be4
DL
1553 "sync-mac vni %u mac %pEA es %s %shold stopped",
1554 mac->zevpn->vni, &mac->macaddr,
b16e8004
DS
1555 mac->es ? mac->es->esi_str : "-",
1556 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
1557 sizeof(mac_buf)));
1558 }
1559
b2998086 1560 THREAD_OFF(mac->hold_timer);
24268cd0
PR
1561}
1562
3198b2b3 1563void zebra_evpn_sync_mac_del(struct zebra_mac *mac)
24268cd0 1564{
b2998086
PR
1565 bool old_static;
1566 bool new_static;
24268cd0 1567
b16e8004
DS
1568 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
1569 char mac_buf[MAC_BUF_SIZE];
1570
b2998086 1571 zlog_debug(
ef7b8be4
DL
1572 "sync-mac del vni %u mac %pEA es %s seq %d f %s",
1573 mac->zevpn->vni, &mac->macaddr,
b2998086 1574 mac->es ? mac->es->esi_str : "-", mac->loc_seq,
b16e8004
DS
1575 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
1576 sizeof(mac_buf)));
1577 }
1578
b2998086
PR
1579 old_static = zebra_evpn_mac_is_static(mac);
1580 UNSET_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY);
1581 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE))
1582 zebra_evpn_mac_start_hold_timer(mac);
1583 new_static = zebra_evpn_mac_is_static(mac);
24268cd0 1584
b2998086
PR
1585 if (old_static != new_static)
1586 /* program the local mac in the kernel */
1587 zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */,
1588 false /* force_clear_static */,
1589 __func__);
24268cd0
PR
1590}
1591
f6371c34 1592static inline bool zebra_evpn_mac_is_bgp_seq_ok(struct zebra_evpn *zevpn,
3198b2b3
DS
1593 struct zebra_mac *mac,
1594 uint32_t seq, uint16_t ipa_len,
1a3bd37f 1595 const struct ipaddr *ipaddr,
16de1338 1596 bool sync)
24268cd0 1597{
b2998086
PR
1598 char ipbuf[INET6_ADDRSTRLEN];
1599 uint32_t tmp_seq;
16de1338 1600 const char *n_type;
24268cd0 1601
16de1338 1602 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
b2998086 1603 tmp_seq = mac->loc_seq;
16de1338
AK
1604 n_type = "local";
1605 } else {
b2998086 1606 tmp_seq = mac->rem_seq;
16de1338
AK
1607 n_type = "remote";
1608 }
24268cd0 1609
b2998086
PR
1610 if (seq < tmp_seq) {
1611 /* if the mac was never advertised to bgp we must accept
1612 * whatever sequence number bgp sends
1613 * XXX - check with Vivek
1614 */
1615 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)
1616 && !zebra_evpn_mac_is_ready_for_bgp(mac->flags)) {
b16e8004
DS
1617 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
1618 || IS_ZEBRA_DEBUG_VXLAN) {
1619 char mac_buf[MAC_BUF_SIZE];
1620
b2998086 1621 zlog_debug(
ef7b8be4 1622 "%s-macip accept vni %u %s-mac %pEA%s%s lower seq %u f %s",
16de1338
AK
1623 sync ? "sync" : "rem", zevpn->vni,
1624 n_type,
ef7b8be4 1625 &mac->macaddr,
b2998086
PR
1626 ipa_len ? " IP " : "",
1627 ipa_len ? ipaddr2str(ipaddr, ipbuf,
1628 sizeof(ipbuf))
1629 : "",
b16e8004
DS
1630 tmp_seq,
1631 zebra_evpn_zebra_mac_flag_dump(
1632 mac, mac_buf, sizeof(mac_buf)));
1633 }
1634
b2998086
PR
1635 return true;
1636 }
24268cd0 1637
b16e8004
DS
1638 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC || IS_ZEBRA_DEBUG_VXLAN) {
1639 char mac_buf[MAC_BUF_SIZE];
1640
b2998086 1641 zlog_debug(
ef7b8be4 1642 "%s-macip ignore vni %u %s-mac %pEA%s%s as existing has higher seq %u f %s",
16de1338 1643 sync ? "sync" : "rem", zevpn->vni, n_type,
ef7b8be4 1644 &mac->macaddr,
b2998086
PR
1645 ipa_len ? " IP " : "",
1646 ipa_len ? ipaddr2str(ipaddr, ipbuf,
1647 sizeof(ipbuf))
1648 : "",
b16e8004
DS
1649 tmp_seq,
1650 zebra_evpn_zebra_mac_flag_dump(
1651 mac, mac_buf, sizeof(mac_buf)));
1652 }
b2998086 1653 return false;
24268cd0
PR
1654 }
1655
b2998086 1656 return true;
24268cd0
PR
1657}
1658
3198b2b3 1659struct zebra_mac *zebra_evpn_proc_sync_mac_update(
f6371c34
DS
1660 struct zebra_evpn *zevpn, const struct ethaddr *macaddr,
1661 uint16_t ipa_len, const struct ipaddr *ipaddr, uint8_t flags,
1662 uint32_t seq, const esi_t *esi, struct sync_mac_ip_ctx *ctx)
24268cd0 1663{
3198b2b3 1664 struct zebra_mac *mac;
b2998086
PR
1665 bool inform_bgp = false;
1666 bool inform_dataplane = false;
1667 bool seq_change = false;
1668 bool es_change = false;
1669 uint32_t tmp_seq;
b2998086
PR
1670 char ipbuf[INET6_ADDRSTRLEN];
1671 bool old_local = false;
1672 bool old_bgp_ready;
1673 bool new_bgp_ready;
24268cd0 1674
b2998086
PR
1675 mac = zebra_evpn_mac_lookup(zevpn, macaddr);
1676 if (!mac) {
1677 /* if it is a new local path we need to inform both
1678 * the control protocol and the data-plane
1679 */
1680 inform_bgp = true;
1681 inform_dataplane = true;
1682 ctx->mac_created = true;
1683 ctx->mac_inactive = true;
24268cd0 1684
b2998086
PR
1685 /* create the MAC and associate it with the dest ES */
1686 mac = zebra_evpn_mac_add(zevpn, macaddr);
1687 zebra_evpn_es_mac_ref(mac, esi);
24268cd0 1688
b2998086
PR
1689 /* local mac activated by an ES peer */
1690 SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
1691 /* if mac-only route setup peer flags */
1692 if (!ipa_len) {
1693 if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT))
1694 SET_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY);
1695 else
1696 SET_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE);
1697 }
1698 SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE);
1699 old_bgp_ready = false;
1700 new_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
1701 } else {
1702 uint32_t old_flags;
1703 uint32_t new_flags;
1704 bool old_static;
1705 bool new_static;
1706 bool sticky;
1707 bool remote_gw;
24268cd0 1708
f1dbb1c7
DS
1709 mac->uptime = monotime(NULL);
1710
b2998086
PR
1711 old_flags = mac->flags;
1712 sticky = !!CHECK_FLAG(old_flags, ZEBRA_MAC_STICKY);
1713 remote_gw = !!CHECK_FLAG(old_flags, ZEBRA_MAC_REMOTE_DEF_GW);
1714 if (sticky || remote_gw) {
1715 if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
1716 zlog_debug(
ef7b8be4
DL
1717 "Ignore sync-macip vni %u mac %pEA%s%s%s%s",
1718 zevpn->vni, macaddr,
b2998086
PR
1719 ipa_len ? " IP " : "",
1720 ipa_len ? ipaddr2str(ipaddr, ipbuf,
1721 sizeof(ipbuf))
1722 : "",
1723 sticky ? " sticky" : "",
1724 remote_gw ? " remote_gw" : "");
1725 ctx->ignore_macip = true;
1726 return NULL;
1727 }
1728 if (!zebra_evpn_mac_is_bgp_seq_ok(zevpn, mac, seq, ipa_len,
16de1338 1729 ipaddr, true)) {
b2998086
PR
1730 ctx->ignore_macip = true;
1731 return NULL;
1732 }
24268cd0 1733
b2998086
PR
1734 old_local = !!CHECK_FLAG(old_flags, ZEBRA_MAC_LOCAL);
1735 old_static = zebra_evpn_mac_is_static(mac);
24268cd0 1736
b2998086
PR
1737 /* re-build the mac flags */
1738 new_flags = 0;
1739 SET_FLAG(new_flags, ZEBRA_MAC_LOCAL);
1740 /* retain old local activity flag */
1741 if (old_flags & ZEBRA_MAC_LOCAL) {
1742 new_flags |= (old_flags & ZEBRA_MAC_LOCAL_INACTIVE);
1743 } else {
1744 new_flags |= ZEBRA_MAC_LOCAL_INACTIVE;
1745 ctx->mac_inactive = true;
1746 }
1747 if (ipa_len) {
1748 /* if mac-ip route do NOT update the peer flags
1749 * i.e. retain only flags as is
1750 */
1751 new_flags |= (old_flags & ZEBRA_MAC_ALL_PEER_FLAGS);
1752 } else {
1753 /* if mac-only route update peer flags */
1754 if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT)) {
1755 SET_FLAG(new_flags, ZEBRA_MAC_ES_PEER_PROXY);
1756 /* if the mac was peer-active previously we
1757 * need to keep the flag and start the
1758 * holdtimer on it. the peer-active flag is
1759 * cleared on holdtimer expiry.
1760 */
1761 if (CHECK_FLAG(old_flags,
1762 ZEBRA_MAC_ES_PEER_ACTIVE)) {
1763 SET_FLAG(new_flags,
1764 ZEBRA_MAC_ES_PEER_ACTIVE);
1765 zebra_evpn_mac_start_hold_timer(mac);
1766 }
1767 } else {
1768 SET_FLAG(new_flags, ZEBRA_MAC_ES_PEER_ACTIVE);
1769 /* stop hold timer if a peer has verified
1770 * reachability
1771 */
1772 zebra_evpn_mac_stop_hold_timer(mac);
1773 }
1774 }
1775 mac->rem_seq = 0;
8b07f173 1776 zebra_evpn_mac_clear_fwd_info(mac);
b2998086 1777 mac->flags = new_flags;
24268cd0 1778
b16e8004
DS
1779 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC && (old_flags != new_flags)) {
1780 char mac_buf[MAC_BUF_SIZE], omac_buf[MAC_BUF_SIZE];
3198b2b3 1781 struct zebra_mac omac;
b16e8004
DS
1782
1783 omac.flags = old_flags;
b2998086 1784 zlog_debug(
ef7b8be4
DL
1785 "sync-mac vni %u mac %pEA old_f %snew_f %s",
1786 zevpn->vni, macaddr,
b16e8004
DS
1787 zebra_evpn_zebra_mac_flag_dump(
1788 &omac, omac_buf, sizeof(omac_buf)),
1789 zebra_evpn_zebra_mac_flag_dump(
1790 mac, mac_buf, sizeof(mac_buf)));
1791 }
24268cd0 1792
b2998086
PR
1793 /* update es */
1794 es_change = zebra_evpn_es_mac_ref(mac, esi);
1795 /* if mac dest change - inform both sides */
1796 if (es_change) {
1797 inform_bgp = true;
1798 inform_dataplane = true;
1799 ctx->mac_inactive = true;
1800 }
8b07f173 1801
b2998086
PR
1802 /* if peer-flag is being set notify dataplane that the
1803 * entry must not be expired because of local inactivity
1804 */
1805 new_static = zebra_evpn_mac_is_static(mac);
1806 if (old_static != new_static)
1807 inform_dataplane = true;
24268cd0 1808
b2998086
PR
1809 old_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(old_flags);
1810 new_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
1811 if (old_bgp_ready != new_bgp_ready)
1812 inform_bgp = true;
1813 }
24268cd0 1814
24268cd0 1815
b2998086
PR
1816 /* update sequence number; if that results in a new local sequence
1817 * inform bgp
1818 */
1819 tmp_seq = MAX(mac->loc_seq, seq);
1820 if (tmp_seq != mac->loc_seq) {
1821 mac->loc_seq = tmp_seq;
1822 seq_change = true;
1823 inform_bgp = true;
1824 }
24268cd0 1825
b16e8004
DS
1826 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
1827 char mac_buf[MAC_BUF_SIZE];
1828
ef7b8be4
DL
1829 zlog_debug("sync-mac %s vni %u mac %pEA es %s seq %d f %s%s%s",
1830 ctx->mac_created ? "created" : "updated",
1831 zevpn->vni, macaddr,
b2998086 1832 mac->es ? mac->es->esi_str : "-", mac->loc_seq,
b16e8004
DS
1833 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
1834 sizeof(mac_buf)),
1835 inform_bgp ? "inform_bgp" : "",
b2998086 1836 inform_dataplane ? " inform_dp" : "");
b16e8004 1837 }
24268cd0 1838
b2998086
PR
1839 if (inform_bgp)
1840 zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready,
1841 new_bgp_ready);
24268cd0 1842
b2998086
PR
1843 /* neighs using the mac may need to be re-sent to
1844 * bgp with updated info
1845 */
1846 if (seq_change || es_change || !old_local)
1847 zebra_evpn_process_neigh_on_local_mac_change(
1848 zevpn, mac, seq_change, es_change);
24268cd0 1849
b2998086
PR
1850 if (inform_dataplane) {
1851 if (ipa_len)
1852 /* if the mac is being created as a part of MAC-IP
1853 * route wait for the neigh to be updated or
1854 * created before programming the mac
1855 */
1856 ctx->mac_dp_update_deferred = true;
1857 else
1858 /* program the local mac in the kernel. when the ES
1859 * change we need to force the dataplane to reset
1860 * the activity as we are yet to establish activity
1861 * locally
1862 */
1863 zebra_evpn_sync_mac_dp_install(
1864 mac, ctx->mac_inactive,
1865 false /* force_clear_static */, __func__);
1866 }
24268cd0 1867
b2998086 1868 return mac;
24268cd0
PR
1869}
1870
07b12758 1871/* update local forwarding info. return true if a dest-ES change
b2998086
PR
1872 * is detected
1873 */
3198b2b3 1874static bool zebra_evpn_local_mac_update_fwd_info(struct zebra_mac *mac,
d9d3455e
PR
1875 struct interface *ifp,
1876 vlanid_t vid)
24268cd0 1877{
b2998086
PR
1878 struct zebra_if *zif = ifp->info;
1879 bool es_change;
47c58929
PG
1880 ns_id_t local_ns_id = NS_DEFAULT;
1881 struct zebra_vrf *zvrf;
00a7710c 1882 struct zebra_evpn_es *es;
47c58929 1883
096f7609 1884 zvrf = ifp->vrf->info;
47c58929
PG
1885 if (zvrf && zvrf->zns)
1886 local_ns_id = zvrf->zns->ns_id;
24268cd0 1887
8b07f173 1888 zebra_evpn_mac_clear_fwd_info(mac);
24268cd0 1889
00a7710c
AK
1890 es = zif->es_info.es;
1891 if (es && (es->flags & ZEBRA_EVPNES_BYPASS))
1892 es = NULL;
1893 es_change = zebra_evpn_es_mac_ref_entry(mac, es);
24268cd0 1894
b2998086
PR
1895 if (!mac->es) {
1896 /* if es is set fwd_info is not-relevant/taped-out */
1897 mac->fwd_info.local.ifindex = ifp->ifindex;
47c58929 1898 mac->fwd_info.local.ns_id = local_ns_id;
b2998086 1899 mac->fwd_info.local.vid = vid;
8b07f173 1900 zebra_evpn_mac_ifp_link(mac, ifp);
24268cd0
PR
1901 }
1902
b2998086 1903 return es_change;
24268cd0
PR
1904}
1905
24268cd0 1906/* Notify Local MACs to the clienti, skips GW MAC */
b2998086
PR
1907static void zebra_evpn_send_mac_hash_entry_to_client(struct hash_bucket *bucket,
1908 void *arg)
24268cd0
PR
1909{
1910 struct mac_walk_ctx *wctx = arg;
3198b2b3 1911 struct zebra_mac *zmac = bucket->data;
24268cd0
PR
1912
1913 if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_DEF_GW))
1914 return;
1915
1916 if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_LOCAL))
b2998086
PR
1917 zebra_evpn_mac_send_add_to_client(wctx->zevpn->vni,
1918 &zmac->macaddr, zmac->flags,
1919 zmac->loc_seq, zmac->es);
24268cd0
PR
1920}
1921
1922/* Iterator to Notify Local MACs of a EVPN */
f6371c34 1923void zebra_evpn_send_mac_list_to_client(struct zebra_evpn *zevpn)
24268cd0
PR
1924{
1925 struct mac_walk_ctx wctx;
1926
1927 if (!zevpn->mac_table)
1928 return;
1929
6006b807 1930 memset(&wctx, 0, sizeof(wctx));
24268cd0
PR
1931 wctx.zevpn = zevpn;
1932
b2998086
PR
1933 hash_iterate(zevpn->mac_table, zebra_evpn_send_mac_hash_entry_to_client,
1934 &wctx);
24268cd0
PR
1935}
1936
3198b2b3 1937void zebra_evpn_rem_mac_del(struct zebra_evpn *zevpn, struct zebra_mac *mac)
24268cd0 1938{
b2998086
PR
1939 zebra_evpn_process_neigh_on_remote_mac_del(zevpn, mac);
1940 /* the remote sequence number in the auto mac entry
1941 * needs to be reset to 0 as the mac entry may have
1942 * been removed on all VTEPs (including
1943 * the originating one)
1944 */
1945 mac->rem_seq = 0;
24268cd0 1946
b2998086
PR
1947 /* If all remote neighbors referencing a remote MAC
1948 * go away, we need to uninstall the MAC.
1949 */
1950 if (remote_neigh_count(mac) == 0) {
f3722826 1951 zebra_evpn_rem_mac_uninstall(zevpn, mac, false /*force*/);
b2998086
PR
1952 zebra_evpn_es_mac_deref_entry(mac);
1953 UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
24268cd0
PR
1954 }
1955
b2998086
PR
1956 if (list_isempty(mac->neigh_list))
1957 zebra_evpn_mac_del(zevpn, mac);
1958 else
1959 SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
24268cd0
PR
1960}
1961
b2998086
PR
1962/* Print Duplicate MAC */
1963void zebra_evpn_print_dad_mac_hash(struct hash_bucket *bucket, void *ctxt)
24268cd0 1964{
3198b2b3 1965 struct zebra_mac *mac;
24268cd0 1966
3198b2b3 1967 mac = (struct zebra_mac *)bucket->data;
b2998086
PR
1968 if (!mac)
1969 return;
24268cd0 1970
b2998086
PR
1971 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
1972 zebra_evpn_print_mac_hash(bucket, ctxt);
24268cd0
PR
1973}
1974
b2998086
PR
1975/* Print Duplicate MAC in detail */
1976void zebra_evpn_print_dad_mac_hash_detail(struct hash_bucket *bucket,
1977 void *ctxt)
24268cd0 1978{
3198b2b3 1979 struct zebra_mac *mac;
24268cd0 1980
3198b2b3 1981 mac = (struct zebra_mac *)bucket->data;
b2998086
PR
1982 if (!mac)
1983 return;
24268cd0 1984
b2998086
PR
1985 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
1986 zebra_evpn_print_mac_hash_detail(bucket, ctxt);
24268cd0 1987}
19fdd1be 1988
f6371c34
DS
1989int zebra_evpn_mac_remote_macip_add(
1990 struct zebra_evpn *zevpn, struct zebra_vrf *zvrf,
1991 const struct ethaddr *macaddr, uint16_t ipa_len,
3198b2b3
DS
1992 const struct ipaddr *ipaddr, struct zebra_mac **macp,
1993 struct in_addr vtep_ip, uint8_t flags, uint32_t seq, const esi_t *esi)
19fdd1be 1994{
19fdd1be 1995 char buf1[INET6_ADDRSTRLEN];
19fdd1be
PR
1996 bool sticky;
1997 bool remote_gw;
1998 int update_mac = 0;
1999 bool do_dad = false;
2000 bool is_dup_detect = false;
2001 esi_t *old_esi;
2002 bool old_static = false;
3198b2b3 2003 struct zebra_mac *mac;
8e1337c5
AK
2004 bool old_es_present;
2005 bool new_es_present;
19fdd1be
PR
2006
2007 sticky = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
2008 remote_gw = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
2009
2010 mac = zebra_evpn_mac_lookup(zevpn, macaddr);
2011
2012 /* Ignore if the mac is already present as a gateway mac */
2013 if (mac && CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW)
2014 && CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW)) {
2015 if (IS_ZEBRA_DEBUG_VXLAN)
2016 zlog_debug(
ef7b8be4
DL
2017 "Ignore remote MACIP ADD VNI %u MAC %pEA%s%s as MAC is already configured as gateway MAC",
2018 zevpn->vni, macaddr,
19fdd1be
PR
2019 ipa_len ? " IP " : "",
2020 ipa_len ? ipaddr2str(ipaddr, buf1, sizeof(buf1))
2021 : "");
2022 return -1;
2023 }
2024
2025 old_esi = (mac && mac->es) ? &mac->es->esi : zero_esi;
2026
2027 /* check if the remote MAC is unknown or has a change.
2028 * If so, that needs to be updated first. Note that client could
2029 * install MAC and MACIP separately or just install the latter.
2030 */
2031 if (!mac || !CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
2032 || sticky != !!CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)
2033 || remote_gw != !!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW)
2034 || !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &vtep_ip)
2035 || memcmp(old_esi, esi, sizeof(esi_t)) || seq != mac->rem_seq)
2036 update_mac = 1;
2037
2038 if (update_mac) {
2039 if (!mac) {
2040 mac = zebra_evpn_mac_add(zevpn, macaddr);
19fdd1be
PR
2041 zebra_evpn_es_mac_ref(mac, esi);
2042
2043 /* Is this MAC created for a MACIP? */
2044 if (ipa_len)
2045 SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
2046 } else {
19fdd1be
PR
2047 /* When host moves but changes its (MAC,IP)
2048 * binding, BGP may install a MACIP entry that
2049 * corresponds to "older" location of the host
2050 * in transient situations (because {IP1,M1}
2051 * is a different route from {IP1,M2}). Check
2052 * the sequence number and ignore this update
2053 * if appropriate.
2054 */
16de1338
AK
2055 if (!zebra_evpn_mac_is_bgp_seq_ok(
2056 zevpn, mac, seq, ipa_len, ipaddr, false))
19fdd1be 2057 return -1;
c1735c08 2058
8e1337c5 2059 old_es_present = !!mac->es;
c1735c08 2060 zebra_evpn_es_mac_ref(mac, esi);
8e1337c5
AK
2061 new_es_present = !!mac->es;
2062 /* XXX - dataplane is curently not able to handle a MAC
2063 * replace if the destination changes from L2-NHG to
2064 * single VTEP and vice-versa. So delete the old entry
2065 * and re-install
2066 */
2067 if (old_es_present != new_es_present)
2068 zebra_evpn_rem_mac_uninstall(zevpn, mac, false);
19fdd1be
PR
2069 }
2070
2071 /* Check MAC's curent state is local (this is the case
2072 * where MAC has moved from L->R) and check previous
2073 * detection started via local learning.
2074 * RFC-7432: A PE/VTEP that detects a MAC mobility
2075 * event via local learning starts an M-second timer.
2076 *
2077 * VTEP-IP or seq. change alone is not considered
2078 * for dup. detection.
2079 *
2080 * MAC is already marked duplicate set dad, then
2081 * is_dup_detect will be set to not install the entry.
2082 */
2083 if ((!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
2084 && mac->dad_count)
2085 || CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
2086 do_dad = true;
2087
2088 /* Remove local MAC from BGP. */
2089 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
2090 /* force drop the sync flags */
2091 old_static = zebra_evpn_mac_is_static(mac);
b16e8004
DS
2092 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
2093 char mac_buf[MAC_BUF_SIZE];
2094
19fdd1be 2095 zlog_debug(
ef7b8be4
DL
2096 "sync-mac->remote vni %u mac %pEA es %s seq %d f %s",
2097 zevpn->vni, macaddr,
19fdd1be 2098 mac->es ? mac->es->esi_str : "-",
b16e8004
DS
2099 mac->loc_seq,
2100 zebra_evpn_zebra_mac_flag_dump(
2101 mac, mac_buf, sizeof(mac_buf)));
2102 }
2103
19fdd1be
PR
2104 zebra_evpn_mac_clear_sync_info(mac);
2105 zebra_evpn_mac_send_del_to_client(zevpn->vni, macaddr,
2106 mac->flags,
2107 false /* force */);
2108 }
2109
2110 /* Set "auto" and "remote" forwarding info. */
8b07f173 2111 zebra_evpn_mac_clear_fwd_info(mac);
19fdd1be 2112 UNSET_FLAG(mac->flags, ZEBRA_MAC_ALL_LOCAL_FLAGS);
19fdd1be
PR
2113 SET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
2114 mac->fwd_info.r_vtep_ip = vtep_ip;
2115
2116 if (sticky)
2117 SET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
2118 else
2119 UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
2120
2121 if (remote_gw)
2122 SET_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW);
2123 else
2124 UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW);
2125
2126 zebra_evpn_dup_addr_detect_for_mac(
2127 zvrf, mac, mac->fwd_info.r_vtep_ip, do_dad,
2128 &is_dup_detect, false);
2129
2130 if (!is_dup_detect) {
2131 zebra_evpn_process_neigh_on_remote_mac_add(zevpn, mac);
2132 /* Install the entry. */
2133 zebra_evpn_rem_mac_install(zevpn, mac, old_static);
2134 }
2135 }
2136
2137 /* Update seq number. */
2138 mac->rem_seq = seq;
2139
2140 /* If there is no IP, return after clearing AUTO flag of MAC. */
2141 if (!ipa_len) {
2142 UNSET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
2143 return -1;
2144 }
2145 *macp = mac;
2146 return 0;
2147}
d9d3455e 2148
f6371c34
DS
2149int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf,
2150 struct zebra_evpn *zevpn,
d9d3455e 2151 struct interface *ifp,
1a3bd37f 2152 const struct ethaddr *macaddr, vlanid_t vid,
d9d3455e 2153 bool sticky, bool local_inactive,
3198b2b3 2154 bool dp_static, struct zebra_mac *mac)
d9d3455e 2155{
d9d3455e
PR
2156 bool mac_sticky = false;
2157 bool inform_client = false;
2158 bool upd_neigh = false;
2159 bool is_dup_detect = false;
2160 struct in_addr vtep_ip = {.s_addr = 0};
2161 bool es_change = false;
2162 bool new_bgp_ready;
2163 /* assume inactive if not present or if not local */
2164 bool old_local_inactive = true;
2165 bool old_bgp_ready = false;
2166 bool inform_dataplane = false;
2167 bool new_static = false;
2168
2bdd4461 2169 assert(ifp);
d9d3455e 2170 /* Check if we need to create or update or it is a NO-OP. */
00a7710c
AK
2171 if (!mac)
2172 mac = zebra_evpn_mac_lookup(zevpn, macaddr);
d9d3455e
PR
2173 if (!mac) {
2174 if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC)
2175 zlog_debug(
ef7b8be4
DL
2176 "ADD %sMAC %pEA intf %s(%u) VID %u -> VNI %u%s",
2177 sticky ? "sticky " : "", macaddr,
d9d3455e
PR
2178 ifp->name, ifp->ifindex, vid, zevpn->vni,
2179 local_inactive ? " local-inactive" : "");
2180
2181 mac = zebra_evpn_mac_add(zevpn, macaddr);
d9d3455e
PR
2182 SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
2183 es_change = zebra_evpn_local_mac_update_fwd_info(mac, ifp, vid);
2184 if (sticky)
2185 SET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
2186 inform_client = true;
2187 } else {
b16e8004
DS
2188 if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
2189 char mac_buf[MAC_BUF_SIZE];
2190
d9d3455e 2191 zlog_debug(
ef7b8be4
DL
2192 "UPD %sMAC %pEA intf %s(%u) VID %u -> VNI %u %scurFlags %s",
2193 sticky ? "sticky " : "", macaddr,
d9d3455e
PR
2194 ifp->name, ifp->ifindex, vid, zevpn->vni,
2195 local_inactive ? "local-inactive " : "",
b16e8004
DS
2196 zebra_evpn_zebra_mac_flag_dump(
2197 mac, mac_buf, sizeof(mac_buf)));
2198 }
d9d3455e
PR
2199
2200 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
2201 struct interface *old_ifp;
2202 vlanid_t old_vid;
2203 bool old_static;
2204
2205 zebra_evpn_mac_get_access_info(mac, &old_ifp, &old_vid);
2206 old_bgp_ready =
2207 zebra_evpn_mac_is_ready_for_bgp(mac->flags);
2208 old_local_inactive =
2209 !!(mac->flags & ZEBRA_MAC_LOCAL_INACTIVE);
2210 old_static = zebra_evpn_mac_is_static(mac);
2211 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY))
2212 mac_sticky = true;
00a7710c
AK
2213 es_change = zebra_evpn_local_mac_update_fwd_info(
2214 mac, ifp, vid);
d9d3455e
PR
2215
2216 /*
2217 * Update any changes and if changes are relevant to
2218 * BGP, note it.
2219 */
2220 if (mac_sticky == sticky && old_ifp == ifp
2221 && old_vid == vid
2222 && old_local_inactive == local_inactive
00a7710c 2223 && dp_static == old_static && !es_change) {
d9d3455e
PR
2224 if (IS_ZEBRA_DEBUG_VXLAN)
2225 zlog_debug(
ef7b8be4 2226 " Add/Update %sMAC %pEA intf %s(%u) VID %u -> VNI %u%s, "
d9d3455e 2227 "entry exists and has not changed ",
4e9a9863 2228 sticky ? "sticky " : "",
ef7b8be4
DL
2229 macaddr, ifp->name,
2230 ifp->ifindex, vid, zevpn->vni,
d9d3455e
PR
2231 local_inactive
2232 ? " local_inactive"
2233 : "");
2234 return 0;
2235 }
2236 if (mac_sticky != sticky) {
2237 if (sticky)
2238 SET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
2239 else
2240 UNSET_FLAG(mac->flags,
2241 ZEBRA_MAC_STICKY);
2242 inform_client = true;
2243 }
2244
d9d3455e
PR
2245 /* If an es_change is detected we need to advertise
2246 * the route with a sequence that is one
2247 * greater. This is need to indicate a mac-move
2248 * to the ES peers
2249 */
2250 if (es_change) {
00a7710c
AK
2251 /* update the sequence number only if the entry
2252 * is locally active
2253 */
2254 if (!local_inactive)
2255 mac->loc_seq = mac->loc_seq + 1;
d9d3455e
PR
2256 /* force drop the peer/sync info as it is
2257 * simply no longer relevant
2258 */
2259 if (CHECK_FLAG(mac->flags,
2260 ZEBRA_MAC_ALL_PEER_FLAGS)) {
2261 zebra_evpn_mac_clear_sync_info(mac);
2262 new_static =
2263 zebra_evpn_mac_is_static(mac);
2264 /* if we clear peer-flags we
2265 * also need to notify the dataplane
2266 * to drop the static flag
2267 */
2268 if (old_static != new_static)
2269 inform_dataplane = true;
2270 }
2271 }
2272 } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
2273 || CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) {
2274 bool do_dad = false;
2275
2276 /*
2277 * MAC has either moved or was "internally" created due
2278 * to a neighbor learn and is now actually learnt. If
2279 * it was learnt as a remote sticky MAC, this is an
2280 * operator error.
2281 */
2282 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)) {
2283 flog_warn(
2284 EC_ZEBRA_STICKY_MAC_ALREADY_LEARNT,
ef7b8be4
DL
2285 "MAC %pEA already learnt as remote sticky MAC behind VTEP %pI4 VNI %u",
2286 macaddr,
9bcef951 2287 &mac->fwd_info.r_vtep_ip,
d9d3455e
PR
2288 zevpn->vni);
2289 return 0;
2290 }
2291
2292 /* If an actual move, compute MAC's seq number */
2293 if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
2294 mac->loc_seq =
2295 MAX(mac->rem_seq + 1, mac->loc_seq);
2296 vtep_ip = mac->fwd_info.r_vtep_ip;
2297 /* Trigger DAD for remote MAC */
2298 do_dad = true;
2299 }
2300
2301 UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
2302 UNSET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
2303 SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
2304 es_change = zebra_evpn_local_mac_update_fwd_info(
2305 mac, ifp, vid);
2306 if (sticky)
2307 SET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
2308 else
2309 UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
2310 /*
2311 * We have to inform BGP of this MAC as well as process
2312 * all neighbors.
2313 */
2314 inform_client = true;
2315 upd_neigh = true;
2316
2317 zebra_evpn_dup_addr_detect_for_mac(
2318 zvrf, mac, vtep_ip, do_dad, &is_dup_detect,
2319 true);
2320 if (is_dup_detect) {
2321 inform_client = false;
2322 upd_neigh = false;
839dfe29 2323 es_change = false;
d9d3455e
PR
2324 }
2325 }
2326 }
2327
2328 /* if the dataplane thinks the entry is sync but it is
69711b3f
AK
2329 * not sync in zebra (or vice-versa) we need to re-install
2330 * to fixup
d9d3455e 2331 */
69711b3f
AK
2332 new_static = zebra_evpn_mac_is_static(mac);
2333 if (dp_static != new_static)
2334 inform_dataplane = true;
d9d3455e
PR
2335
2336 if (local_inactive)
2337 SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE);
2338 else
2339 UNSET_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE);
2340
2341 new_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
2342 /* if local-activity has changed we need update bgp
2343 * even if bgp already knows about the mac
2344 */
2345 if ((old_local_inactive != local_inactive)
2346 || (new_bgp_ready != old_bgp_ready)) {
b16e8004
DS
2347 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
2348 char mac_buf[MAC_BUF_SIZE];
2349
d9d3455e 2350 zlog_debug(
ef7b8be4
DL
2351 "local mac vni %u mac %pEA es %s seq %d f %s%s",
2352 zevpn->vni, macaddr,
d9d3455e 2353 mac->es ? mac->es->esi_str : "", mac->loc_seq,
b16e8004
DS
2354 zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
2355 sizeof(mac_buf)),
2356 local_inactive ? "local-inactive" : "");
2357 }
2358
839dfe29
CS
2359 if (!is_dup_detect)
2360 inform_client = true;
d9d3455e
PR
2361 }
2362
2363 if (es_change) {
2364 inform_client = true;
2365 upd_neigh = true;
2366 }
2367
2368 /* Inform dataplane if required. */
2369 if (inform_dataplane)
2370 zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */,
2371 false /* force_clear_static */,
2372 __func__);
2373
2374 /* Inform BGP if required. */
2375 if (inform_client)
2376 zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready,
2377 new_bgp_ready);
2378
2379 /* Process all neighbors associated with this MAC, if required. */
2380 if (upd_neigh)
2381 zebra_evpn_process_neigh_on_local_mac_change(zevpn, mac, 0,
2382 es_change);
2383
2384 return 0;
2385}
ad6ca5f4 2386
3198b2b3 2387int zebra_evpn_del_local_mac(struct zebra_evpn *zevpn, struct zebra_mac *mac,
00a7710c 2388 bool clear_static)
ad6ca5f4 2389{
ad6ca5f4
PR
2390 bool old_bgp_ready;
2391 bool new_bgp_ready;
b16e8004 2392
46d6f5a2 2393 if (IS_ZEBRA_DEBUG_VXLAN)
ef7b8be4
DL
2394 zlog_debug("DEL MAC %pEA VNI %u seq %u flags 0x%x nbr count %u",
2395 &mac->macaddr, zevpn->vni, mac->loc_seq, mac->flags,
46d6f5a2 2396 listcount(mac->neigh_list));
ad6ca5f4
PR
2397
2398 old_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
00a7710c 2399 if (!clear_static && zebra_evpn_mac_is_static(mac)) {
ad6ca5f4
PR
2400 /* this is a synced entry and can only be removed when the
2401 * es-peers stop advertising it.
2402 */
8b07f173 2403 zebra_evpn_mac_clear_fwd_info(mac);
ad6ca5f4 2404
b16e8004
DS
2405 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
2406 char mac_buf[MAC_BUF_SIZE];
2407
ad6ca5f4 2408 zlog_debug(
ef7b8be4
DL
2409 "re-add sync-mac vni %u mac %pEA es %s seq %d f %s",
2410 zevpn->vni, &mac->macaddr,
ad6ca5f4 2411 mac->es ? mac->es->esi_str : "-", mac->loc_seq,
b16e8004
DS
2412 zebra_evpn_zebra_mac_flag_dump(
2413 mac, mac_buf, sizeof(mac_buf)));
2414 }
ad6ca5f4
PR
2415
2416 /* inform-bgp about change in local-activity if any */
2417 if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE)) {
2418 SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE);
2419 new_bgp_ready =
2420 zebra_evpn_mac_is_ready_for_bgp(mac->flags);
2421 zebra_evpn_mac_send_add_del_to_client(
2422 mac, old_bgp_ready, new_bgp_ready);
2423 }
2424
1a4f9efd
AK
2425 /* re-install the inactive entry in the kernel */
2426 zebra_evpn_sync_mac_dp_install(mac, true /* set_inactive */,
ad6ca5f4
PR
2427 false /* force_clear_static */,
2428 __func__);
2429
2430 return 0;
2431 }
2432
00a7710c
AK
2433 /* flush the peer info */
2434 zebra_evpn_mac_clear_sync_info(mac);
2435
ad6ca5f4
PR
2436 /* Update all the neigh entries associated with this mac */
2437 zebra_evpn_process_neigh_on_local_mac_del(zevpn, mac);
2438
2439 /* Remove MAC from BGP. */
46d6f5a2 2440 zebra_evpn_mac_send_del_to_client(zevpn->vni, &mac->macaddr, mac->flags,
ad6ca5f4
PR
2441 false /* force */);
2442
2443 zebra_evpn_es_mac_deref_entry(mac);
2444
8b07f173
AK
2445 /* remove links to the destination access port */
2446 zebra_evpn_mac_clear_fwd_info(mac);
2447
ad6ca5f4
PR
2448 /*
2449 * If there are no neigh associated with the mac delete the mac
2450 * else mark it as AUTO for forward reference
2451 */
2452 if (!listcount(mac->neigh_list)) {
2453 zebra_evpn_mac_del(zevpn, mac);
2454 } else {
2455 UNSET_FLAG(mac->flags, ZEBRA_MAC_ALL_LOCAL_FLAGS);
2456 UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
2457 SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
2458 }
2459
2460 return 0;
2461}
7bce3535 2462
5ff58d0a 2463void zebra_evpn_mac_gw_macip_add(struct interface *ifp,
2464 struct zebra_evpn *zevpn,
2465 const struct ipaddr *ip,
2466 struct zebra_mac **macp,
2467 const struct ethaddr *macaddr,
2468 vlanid_t vlan_id, bool def_gw)
7bce3535 2469{
3198b2b3 2470 struct zebra_mac *mac;
47c58929
PG
2471 ns_id_t local_ns_id = NS_DEFAULT;
2472 struct zebra_vrf *zvrf;
2473
096f7609 2474 zvrf = ifp->vrf->info;
47c58929
PG
2475 if (zvrf && zvrf->zns)
2476 local_ns_id = zvrf->zns->ns_id;
7bce3535 2477
b83d220a 2478 if (!*macp) {
2479 mac = zebra_evpn_mac_lookup(zevpn, macaddr);
2480 if (!mac)
2481 mac = zebra_evpn_mac_add(zevpn, macaddr);
2482 *macp = mac;
2483 } else
2484 mac = *macp;
7bce3535
PR
2485
2486 /* Set "local" forwarding info. */
8b07f173 2487 zebra_evpn_mac_clear_fwd_info(mac);
7bce3535
PR
2488 SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
2489 SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
e4c3ece6
AK
2490 if (def_gw)
2491 SET_FLAG(mac->flags, ZEBRA_MAC_DEF_GW);
5ff58d0a 2492 else
2493 SET_FLAG(mac->flags, ZEBRA_MAC_SVI);
7bce3535 2494 mac->fwd_info.local.ifindex = ifp->ifindex;
47c58929 2495 mac->fwd_info.local.ns_id = local_ns_id;
7bce3535 2496 mac->fwd_info.local.vid = vlan_id;
7bce3535 2497}
243b74ed 2498
f6371c34 2499void zebra_evpn_mac_svi_del(struct interface *ifp, struct zebra_evpn *zevpn)
243b74ed 2500{
3198b2b3 2501 struct zebra_mac *mac;
243b74ed 2502 struct ethaddr macaddr;
e4c3ece6 2503 bool old_bgp_ready;
243b74ed
AK
2504
2505 if (!zebra_evpn_mh_do_adv_svi_mac())
2506 return;
2507
2508 memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN);
2509 mac = zebra_evpn_mac_lookup(zevpn, &macaddr);
2510 if (mac && CHECK_FLAG(mac->flags, ZEBRA_MAC_SVI)) {
2511 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
2512 zlog_debug("SVI %s mac free", ifp->name);
2513
e4c3ece6 2514 old_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
243b74ed 2515 UNSET_FLAG(mac->flags, ZEBRA_MAC_SVI);
e4c3ece6
AK
2516 zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready,
2517 false);
243b74ed
AK
2518 zebra_evpn_deref_ip2mac(mac->zevpn, mac);
2519 }
2520}
2521
f6371c34 2522void zebra_evpn_mac_svi_add(struct interface *ifp, struct zebra_evpn *zevpn)
243b74ed 2523{
3198b2b3 2524 struct zebra_mac *mac = NULL;
243b74ed
AK
2525 struct ethaddr macaddr;
2526 struct zebra_if *zif = ifp->info;
e4c3ece6
AK
2527 bool old_bgp_ready;
2528 bool new_bgp_ready;
243b74ed 2529
e4c3ece6
AK
2530 if (!zebra_evpn_mh_do_adv_svi_mac()
2531 || !zebra_evpn_send_to_client_ok(zevpn))
243b74ed
AK
2532 return;
2533
2534 memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN);
2535
2536 /* dup check */
2537 mac = zebra_evpn_mac_lookup(zevpn, &macaddr);
2538 if (mac && CHECK_FLAG(mac->flags, ZEBRA_MAC_SVI))
2539 return;
2540
2541 /* add/update mac */
2542 if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
2543 zlog_debug("SVI %s mac add", zif->ifp->name);
2544
e4c3ece6
AK
2545 old_bgp_ready = (mac && zebra_evpn_mac_is_ready_for_bgp(mac->flags))
2546 ? true
2547 : false;
2548
e4c3ece6 2549 zebra_evpn_mac_gw_macip_add(ifp, zevpn, NULL, &mac, &macaddr, 0, false);
e4c3ece6
AK
2550
2551 new_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
2552 zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready,
2553 new_bgp_ready);
243b74ed 2554}