2 * Zebra EVPN for VxLAN code
3 * Copyright (C) 2016, 2017 Cumulus Networks, Inc.
5 * This file is part of FRR.
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
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.
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
26 #include "interface.h"
34 #include "zebra/zserv.h"
35 #include "zebra/debug.h"
36 #include "zebra/zebra_router.h"
37 #include "zebra/zebra_errors.h"
38 #include "zebra/zebra_vrf.h"
39 #include "zebra/zebra_evpn.h"
40 #include "zebra/zebra_evpn_mh.h"
41 #include "zebra/zebra_evpn_mac.h"
42 #include "zebra/zebra_evpn_neigh.h"
44 DEFINE_MTYPE_STATIC(ZEBRA
, MAC
, "EVPN MAC");
47 * Return number of valid MACs in an EVPN's MAC hash table - all
48 * remote MACs and non-internal (auto) local MACs count.
50 uint32_t num_valid_macs(struct zebra_evpn
*zevpn
)
53 uint32_t num_macs
= 0;
55 struct hash_bucket
*hb
;
56 struct zebra_mac
*mac
;
58 hash
= zevpn
->mac_table
;
61 for (i
= 0; i
< hash
->size
; i
++) {
62 for (hb
= hash
->index
[i
]; hb
; hb
= hb
->next
) {
63 mac
= (struct zebra_mac
*)hb
->data
;
64 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE
)
65 || CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
)
66 || !CHECK_FLAG(mac
->flags
, ZEBRA_MAC_AUTO
))
74 uint32_t num_dup_detected_macs(struct zebra_evpn
*zevpn
)
77 uint32_t num_macs
= 0;
79 struct hash_bucket
*hb
;
80 struct zebra_mac
*mac
;
82 hash
= zevpn
->mac_table
;
85 for (i
= 0; i
< hash
->size
; i
++) {
86 for (hb
= hash
->index
[i
]; hb
; hb
= hb
->next
) {
87 mac
= (struct zebra_mac
*)hb
->data
;
88 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_DUPLICATE
))
96 /* Setup mac_list against the access port. This is done when a mac uses
97 * the ifp as destination for the first time
99 static void zebra_evpn_mac_ifp_new(struct zebra_if
*zif
)
101 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
102 zlog_debug("MAC list created for ifp %s (%u)", zif
->ifp
->name
,
105 zif
->mac_list
= list_new();
106 listset_app_node_mem(zif
->mac_list
);
109 /* Unlink local mac from a destination access port */
110 static void zebra_evpn_mac_ifp_unlink(struct zebra_mac
*zmac
)
112 struct zebra_if
*zif
;
113 struct interface
*ifp
= zmac
->ifp
;
118 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
119 zlog_debug("VNI %d MAC %pEA unlinked from ifp %s (%u)",
122 ifp
->name
, ifp
->ifindex
);
125 list_delete_node(zif
->mac_list
, &zmac
->ifp_listnode
);
129 /* Free up the mac_list if any as a part of the interface del/cleanup */
130 void zebra_evpn_mac_ifp_del(struct interface
*ifp
)
132 struct zebra_if
*zif
= ifp
->info
;
133 struct listnode
*node
;
134 struct zebra_mac
*zmac
;
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
);
141 for (ALL_LIST_ELEMENTS_RO(zif
->mac_list
, node
, zmac
)) {
142 zebra_evpn_mac_ifp_unlink(zmac
);
144 list_delete(&zif
->mac_list
);
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
152 static void zebra_evpn_mac_ifp_link(struct zebra_mac
*zmac
,
153 struct interface
*ifp
)
155 struct zebra_if
*zif
;
157 if (!CHECK_FLAG(zmac
->flags
, ZEBRA_MAC_LOCAL
))
160 /* already linked to the destination */
161 if (zmac
->ifp
== ifp
)
164 /* unlink the mac from any old destination */
166 zebra_evpn_mac_ifp_unlink(zmac
);
172 /* the interface mac_list is created on first mac link attempt */
174 zebra_evpn_mac_ifp_new(zif
);
176 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
177 zlog_debug("VNI %d MAC %pEA linked to ifp %s (%u)",
180 ifp
->name
, ifp
->ifindex
);
183 listnode_init(&zmac
->ifp_listnode
, zmac
);
184 listnode_add(zif
->mac_list
, &zmac
->ifp_listnode
);
187 /* If the mac is a local mac clear links to destination access port */
188 void zebra_evpn_mac_clear_fwd_info(struct zebra_mac
*zmac
)
190 zebra_evpn_mac_ifp_unlink(zmac
);
191 memset(&zmac
->fwd_info
, 0, sizeof(zmac
->fwd_info
));
195 * Install remote MAC into the forwarding plane.
197 int zebra_evpn_rem_mac_install(struct zebra_evpn
*zevpn
, struct zebra_mac
*mac
,
200 const struct zebra_if
*zif
, *br_zif
;
201 const struct zebra_l2info_vxlan
*vxl
;
203 enum zebra_dplane_result res
;
204 const struct interface
*br_ifp
;
207 struct in_addr vtep_ip
;
209 zif
= zevpn
->vxlan_if
->info
;
213 br_ifp
= zif
->brslave_info
.br_if
;
217 vxl
= &zif
->l2info
.vxl
;
219 sticky
= !!CHECK_FLAG(mac
->flags
,
220 (ZEBRA_MAC_STICKY
| ZEBRA_MAC_REMOTE_DEF_GW
));
222 /* If nexthop group for the FDB entry is inactive (not programmed in
223 * the dataplane) the MAC entry cannot be installed
226 if (!(mac
->es
->flags
& ZEBRA_EVPNES_NHG_ACTIVE
))
228 nhg_id
= mac
->es
->nhg_id
;
232 vtep_ip
= mac
->fwd_info
.r_vtep_ip
;
235 br_zif
= (const struct zebra_if
*)(br_ifp
->info
);
237 if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif
))
238 vid
= vxl
->access_vlan
;
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
)
251 * Uninstall remote MAC from the forwarding plane.
253 int zebra_evpn_rem_mac_uninstall(struct zebra_evpn
*zevpn
,
254 struct zebra_mac
*mac
, bool force
)
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
;
261 enum zebra_dplane_result res
;
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
))
267 if (!zevpn
->vxlan_if
) {
268 if (IS_ZEBRA_DEBUG_VXLAN
)
270 "VNI %u hash %p couldn't be uninstalled - no intf",
275 zif
= zevpn
->vxlan_if
->info
;
279 br_ifp
= zif
->brslave_info
.br_if
;
283 vxl
= &zif
->l2info
.vxl
;
285 br_zif
= (const struct zebra_if
*)br_ifp
->info
;
287 if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif
))
288 vid
= vxl
->access_vlan
;
292 ifp
= zevpn
->vxlan_if
;
293 vtep_ip
= mac
->fwd_info
.r_vtep_ip
;
295 res
= dplane_rem_mac_del(ifp
, br_ifp
, vid
, &mac
->macaddr
, vtep_ip
);
296 if (res
!= ZEBRA_DPLANE_REQUEST_FAILURE
)
303 * Decrement neighbor refcount of MAC; uninstall and free it if
306 void zebra_evpn_deref_ip2mac(struct zebra_evpn
*zevpn
, struct zebra_mac
*mac
)
308 if (!CHECK_FLAG(mac
->flags
, ZEBRA_MAC_AUTO
))
311 /* If all remote neighbors referencing a remote MAC go away,
312 * we need to uninstall the MAC.
314 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE
)
315 && remote_neigh_count(mac
) == 0) {
316 zebra_evpn_rem_mac_uninstall(zevpn
, mac
, false /*force*/);
317 zebra_evpn_es_mac_deref_entry(mac
);
318 UNSET_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE
);
321 /* If no references, delete the MAC. */
322 if (!zebra_evpn_mac_in_use(mac
))
323 zebra_evpn_mac_del(zevpn
, mac
);
326 static void zebra_evpn_mac_get_access_info(struct zebra_mac
*mac
,
327 struct interface
**ifpP
,
330 /* if the mac is associated with an ES we must get the access
334 struct zebra_if
*zif
;
336 /* get the access port from the es */
337 *ifpP
= mac
->es
->zif
? mac
->es
->zif
->ifp
: NULL
;
338 /* get the vlan from the EVPN */
339 if (mac
->zevpn
->vxlan_if
) {
340 zif
= mac
->zevpn
->vxlan_if
->info
;
341 *vid
= zif
->l2info
.vxl
.access_vlan
;
346 struct zebra_ns
*zns
;
348 *vid
= mac
->fwd_info
.local
.vid
;
349 zns
= zebra_ns_lookup(mac
->fwd_info
.local
.ns_id
);
350 *ifpP
= if_lookup_by_index_per_ns(zns
,
351 mac
->fwd_info
.local
.ifindex
);
355 #define MAC_BUF_SIZE 256
356 static char *zebra_evpn_zebra_mac_flag_dump(struct zebra_mac
*mac
, char *buf
,
359 if (mac
->flags
== 0) {
360 snprintfrr(buf
, len
, "None ");
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 "
372 CHECK_FLAG(mac
->flags
, ZEBRA_MAC_DEF_GW
) ? "Default GW " : "",
373 CHECK_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE_DEF_GW
) ? "REM DEF GW "
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 "
379 CHECK_FLAG(mac
->flags
, ZEBRA_MAC_ES_PEER_PROXY
) ? "PROXY " : "",
380 CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL_INACTIVE
)
386 static void zebra_evpn_dad_mac_auto_recovery_exp(struct thread
*t
)
388 struct zebra_vrf
*zvrf
= NULL
;
389 struct zebra_mac
*mac
= NULL
;
390 struct zebra_evpn
*zevpn
= NULL
;
391 struct listnode
*node
= NULL
;
392 struct zebra_neigh
*nbr
= NULL
;
396 /* since this is asynchronous we need sanity checks*/
397 zvrf
= vrf_info_lookup(mac
->zevpn
->vrf_id
);
401 zevpn
= zebra_evpn_lookup(mac
->zevpn
->vni
);
405 mac
= zebra_evpn_mac_lookup(zevpn
, &mac
->macaddr
);
409 if (IS_ZEBRA_DEBUG_VXLAN
) {
410 char mac_buf
[MAC_BUF_SIZE
];
413 "%s: duplicate addr mac %pEA flags %slearn count %u host count %u auto recovery expired",
414 __func__
, &mac
->macaddr
,
415 zebra_evpn_zebra_mac_flag_dump(mac
, mac_buf
,
417 mac
->dad_count
, listcount(mac
->neigh_list
));
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*/);
430 UNSET_FLAG(nbr
->flags
, ZEBRA_NEIGH_DUPLICATE
);
432 nbr
->detect_start_time
.tv_sec
= 0;
433 nbr
->dad_dup_detect_time
= 0;
436 UNSET_FLAG(mac
->flags
, ZEBRA_MAC_DUPLICATE
);
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
;
443 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
)) {
445 if (zebra_evpn_mac_send_add_to_client(zevpn
->vni
, &mac
->macaddr
,
446 mac
->flags
, mac
->loc_seq
,
450 /* Process all neighbors associated with this MAC. */
451 zebra_evpn_process_neigh_on_local_mac_change(zevpn
, mac
, 0,
454 } else if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE
)) {
455 zebra_evpn_process_neigh_on_remote_mac_add(zevpn
, mac
);
457 /* Install the entry. */
458 zebra_evpn_rem_mac_install(zevpn
, mac
, false /* was_static */);
462 static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf
*zvrf
,
463 struct zebra_mac
*mac
,
464 struct in_addr vtep_ip
,
465 bool do_dad
, bool *is_dup_detect
,
468 struct zebra_neigh
*nbr
;
469 struct listnode
*node
= NULL
;
470 struct timeval elapsed
= {0, 0};
471 bool reset_params
= false;
473 if (!(zebra_evpn_do_dup_addr_detect(zvrf
) && do_dad
))
476 /* MAC is detected as duplicate,
477 * Local MAC event -> hold on advertising to BGP.
478 * Remote MAC event -> hold on installing it.
480 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_DUPLICATE
)) {
481 if (IS_ZEBRA_DEBUG_VXLAN
) {
482 char mac_buf
[MAC_BUF_SIZE
];
485 "%s: duplicate addr MAC %pEA flags %sskip update to client, learn count %u recover time %u",
486 __func__
, &mac
->macaddr
,
487 zebra_evpn_zebra_mac_flag_dump(mac
, mac_buf
,
489 mac
->dad_count
, zvrf
->dad_freeze_time
);
491 /* For duplicate MAC do not update
492 * client but update neigh due to
495 if (zvrf
->dad_freeze
)
496 *is_dup_detect
= true;
501 /* Check if detection time (M-secs) expired.
502 * Reset learn count and detection start time.
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.
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)
514 reset_params
= !mac
->dad_count
;
518 if (IS_ZEBRA_DEBUG_VXLAN
) {
519 char mac_buf
[MAC_BUF_SIZE
];
522 "%s: duplicate addr MAC %pEA flags %sdetection time passed, reset learn count %u",
523 __func__
, &mac
->macaddr
,
524 zebra_evpn_zebra_mac_flag_dump(mac
, mac_buf
,
530 /* Start dup. addr detection (DAD) start time,
531 * ONLY during LOCAL learn.
534 monotime(&mac
->detect_start_time
);
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.
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.
551 if (mac
->dad_count
>= zvrf
->dad_max_moves
) {
552 flog_warn(EC_ZEBRA_DUP_MAC_DETECTED
,
553 "VNI %u: MAC %pEA detected as duplicate during %s VTEP %pI4",
554 mac
->zevpn
->vni
, &mac
->macaddr
,
555 is_local
? "local update, last" :
556 "remote update, from", &vtep_ip
);
558 SET_FLAG(mac
->flags
, ZEBRA_MAC_DUPLICATE
);
560 /* Capture Duplicate detection time */
561 mac
->dad_dup_detect_time
= monotime(NULL
);
563 /* Mark all IPs/Neighs as duplicate
564 * associcated with this MAC
566 for (ALL_LIST_ELEMENTS_RO(mac
->neigh_list
, node
, nbr
)) {
568 /* Ony Mark IPs which are Local */
569 if (!CHECK_FLAG(nbr
->flags
, ZEBRA_NEIGH_LOCAL
))
572 SET_FLAG(nbr
->flags
, ZEBRA_NEIGH_DUPLICATE
);
574 nbr
->dad_dup_detect_time
= monotime(NULL
);
576 flog_warn(EC_ZEBRA_DUP_IP_INHERIT_DETECTED
,
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
,
579 is_local
? "local" : "remote");
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
) {
585 if (IS_ZEBRA_DEBUG_VXLAN
) {
586 char mac_buf
[MAC_BUF_SIZE
];
589 "%s: duplicate addr MAC %pEA flags %sauto recovery time %u start",
590 __func__
, &mac
->macaddr
,
591 zebra_evpn_zebra_mac_flag_dump(
592 mac
, mac_buf
, sizeof(mac_buf
)),
593 zvrf
->dad_freeze_time
);
596 thread_add_timer(zrouter
.master
,
597 zebra_evpn_dad_mac_auto_recovery_exp
,
598 mac
, zvrf
->dad_freeze_time
,
599 &mac
->dad_mac_auto_recovery_timer
);
602 /* In case of local update, do not inform to client (BGPd),
603 * upd_neigh for neigh sequence change.
605 if (zvrf
->dad_freeze
)
606 *is_dup_detect
= true;
611 * Print a specific MAC entry.
613 void zebra_evpn_print_mac(struct zebra_mac
*mac
, void *ctxt
, json_object
*json
)
616 struct zebra_neigh
*n
= NULL
;
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
];
625 char up_str
[MONOTIME_STRLEN
];
627 zvrf
= zebra_vrf_get_evpn();
631 vty
= (struct vty
*)ctxt
;
632 prefix_mac2str(&mac
->macaddr
, buf1
, sizeof(buf1
));
634 uptime
= monotime(NULL
);
635 uptime
-= mac
->uptime
;
637 frrtime_to_interval(uptime
, up_str
, sizeof(up_str
));
640 json_object
*json_mac
= json_object_new_object();
642 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
)) {
643 struct interface
*ifp
;
646 zebra_evpn_mac_get_access_info(mac
, &ifp
, &vid
);
647 json_object_string_add(json_mac
, "type", "local");
649 json_object_string_add(json_mac
, "intf",
651 json_object_int_add(json_mac
, "ifindex",
655 json_object_int_add(json_mac
, "vlan", vid
);
656 } else if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE
)) {
657 json_object_string_add(json_mac
, "type", "remote");
658 json_object_string_addf(json_mac
, "remoteVtep", "%pI4",
659 &mac
->fwd_info
.r_vtep_ip
);
660 } else if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_AUTO
))
661 json_object_string_add(json_mac
, "type", "auto");
663 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_STICKY
))
664 json_object_boolean_true_add(json_mac
, "stickyMac");
666 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_SVI
))
667 json_object_boolean_true_add(json_mac
, "sviMac");
669 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_DEF_GW
))
670 json_object_boolean_true_add(json_mac
,
673 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE_DEF_GW
))
674 json_object_boolean_true_add(json_mac
,
677 json_object_string_add(json_mac
, "uptime", up_str
);
678 json_object_int_add(json_mac
, "localSequence", mac
->loc_seq
);
679 json_object_int_add(json_mac
, "remoteSequence", mac
->rem_seq
);
681 json_object_int_add(json_mac
, "detectionCount", mac
->dad_count
);
682 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_DUPLICATE
))
683 json_object_boolean_true_add(json_mac
, "isDuplicate");
685 json_object_boolean_false_add(json_mac
, "isDuplicate");
687 json_object_int_add(json_mac
, "syncNeighCount",
688 mac
->sync_neigh_cnt
);
689 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL_INACTIVE
))
690 json_object_boolean_true_add(json_mac
, "localInactive");
691 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_ES_PEER_PROXY
))
692 json_object_boolean_true_add(json_mac
, "peerProxy");
693 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_ES_PEER_ACTIVE
))
694 json_object_boolean_true_add(json_mac
, "peerActive");
696 json_object_string_add(
697 json_mac
, "peerActiveHold",
698 thread_timer_to_hhmmss(thread_buf
,
702 json_object_string_add(json_mac
, "esi",
704 /* print all the associated neigh */
705 if (!listcount(mac
->neigh_list
))
706 json_object_string_add(json_mac
, "neighbors", "none");
708 json_object
*json_active_nbrs
= json_object_new_array();
709 json_object
*json_inactive_nbrs
=
710 json_object_new_array();
711 json_object
*json_nbrs
= json_object_new_object();
713 for (ALL_LIST_ELEMENTS_RO(mac
->neigh_list
, node
, n
)) {
714 if (IS_ZEBRA_NEIGH_ACTIVE(n
))
715 json_object_array_add(
717 json_object_new_string(
722 json_object_array_add(
724 json_object_new_string(
730 json_object_object_add(json_nbrs
, "active",
732 json_object_object_add(json_nbrs
, "inactive",
734 json_object_object_add(json_mac
, "neighbors",
738 json_object_object_add(json
, buf1
, json_mac
);
740 vty_out(vty
, "MAC: %s\n", buf1
);
742 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
)) {
743 struct interface
*ifp
;
746 zebra_evpn_mac_get_access_info(mac
, &ifp
, &vid
);
749 vty_out(vty
, " ESI: %s\n", mac
->es
->esi_str
);
752 vty_out(vty
, " Intf: %s(%u)", ifp
->name
,
755 vty_out(vty
, " Intf: -");
756 vty_out(vty
, " VLAN: %u", vid
);
757 } else if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE
)) {
759 vty_out(vty
, " Remote ES: %s",
762 vty_out(vty
, " Remote VTEP: %pI4",
763 &mac
->fwd_info
.r_vtep_ip
);
764 } else if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_AUTO
)) {
765 vty_out(vty
, " Auto Mac ");
768 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_STICKY
))
769 vty_out(vty
, " Sticky Mac ");
771 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_SVI
))
772 vty_out(vty
, " SVI-Mac ");
774 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_DEF_GW
))
775 vty_out(vty
, " Default-gateway Mac ");
777 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE_DEF_GW
))
778 vty_out(vty
, " Remote-gateway Mac ");
781 vty_out(vty
, " Sync-info: neigh#: %u", mac
->sync_neigh_cnt
);
782 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL_INACTIVE
))
783 vty_out(vty
, " local-inactive");
784 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_ES_PEER_PROXY
))
785 vty_out(vty
, " peer-proxy");
786 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_ES_PEER_ACTIVE
))
787 vty_out(vty
, " peer-active");
789 vty_out(vty
, " (ht: %s)",
790 thread_timer_to_hhmmss(thread_buf
,
794 vty_out(vty
, " Local Seq: %u Remote Seq: %u\n", mac
->loc_seq
,
796 vty_out(vty
, " Uptime: %s\n", up_str
);
798 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_DUPLICATE
)) {
799 vty_out(vty
, " Duplicate, detected at %s",
800 time_to_string(mac
->dad_dup_detect_time
,
802 } else if (mac
->dad_count
) {
803 monotime_since(&mac
->detect_start_time
,
805 if (detect_start_time
.tv_sec
<= zvrf
->dad_time
) {
806 time_to_string(mac
->detect_start_time
.tv_sec
,
809 " Duplicate detection started at %s, detection count %u\n",
810 timebuf
, mac
->dad_count
);
814 /* print all the associated neigh */
815 vty_out(vty
, " Neighbors:\n");
816 if (!listcount(mac
->neigh_list
))
817 vty_out(vty
, " No Neighbors\n");
819 for (ALL_LIST_ELEMENTS_RO(mac
->neigh_list
, node
, n
)) {
820 vty_out(vty
, " %s %s\n",
821 ipaddr2str(&n
->ip
, buf2
, sizeof(buf2
)),
822 (IS_ZEBRA_NEIGH_ACTIVE(n
)
832 static char *zebra_evpn_print_mac_flags(struct zebra_mac
*mac
, char *flags_buf
,
835 snprintf(flags_buf
, flags_buf_sz
, "%s%s%s%s",
836 mac
->sync_neigh_cnt
? "N" : "",
837 (mac
->flags
& ZEBRA_MAC_ES_PEER_ACTIVE
) ? "P" : "",
838 (mac
->flags
& ZEBRA_MAC_ES_PEER_PROXY
) ? "X" : "",
839 (mac
->flags
& ZEBRA_MAC_LOCAL_INACTIVE
) ? "I" : "");
845 * Print MAC hash entry - called for display of all MACs.
847 void zebra_evpn_print_mac_hash(struct hash_bucket
*bucket
, void *ctxt
)
850 json_object
*json_mac_hdr
= NULL
, *json_mac
= NULL
;
851 struct zebra_mac
*mac
;
852 char buf1
[ETHER_ADDR_STRLEN
];
853 char addr_buf
[PREFIX_STRLEN
];
854 struct mac_walk_ctx
*wctx
= ctxt
;
858 json_mac_hdr
= wctx
->json
;
859 mac
= (struct zebra_mac
*)bucket
->data
;
861 prefix_mac2str(&mac
->macaddr
, buf1
, sizeof(buf1
));
864 json_mac
= json_object_new_object();
866 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
)) {
867 struct interface
*ifp
;
870 if (wctx
->flags
& SHOW_REMOTE_MAC_FROM_VTEP
)
873 zebra_evpn_mac_get_access_info(mac
, &ifp
, &vid
);
874 if (json_mac_hdr
== NULL
) {
875 vty_out(vty
, "%-17s %-6s %-5s %-30s", buf1
, "local",
876 zebra_evpn_print_mac_flags(mac
, flags_buf
,
878 ifp
? ifp
->name
: "-");
880 json_object_string_add(json_mac
, "type", "local");
882 json_object_string_add(json_mac
, "intf",
886 if (json_mac_hdr
== NULL
)
887 vty_out(vty
, " %-5u", vid
);
889 json_object_int_add(json_mac
, "vlan", vid
);
890 } else /* No vid? fill out the space */
891 if (json_mac_hdr
== NULL
)
892 vty_out(vty
, " %-5s", "");
893 if (json_mac_hdr
== NULL
) {
894 vty_out(vty
, " %u/%u", mac
->loc_seq
, mac
->rem_seq
);
897 json_object_int_add(json_mac
, "localSequence",
899 json_object_int_add(json_mac
, "remoteSequence",
901 json_object_int_add(json_mac
, "detectionCount",
903 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_DUPLICATE
))
904 json_object_boolean_true_add(json_mac
,
907 json_object_boolean_false_add(json_mac
,
909 json_object_object_add(json_mac_hdr
, buf1
, json_mac
);
914 } else if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE
)) {
916 if ((wctx
->flags
& SHOW_REMOTE_MAC_FROM_VTEP
)
917 && !IPV4_ADDR_SAME(&mac
->fwd_info
.r_vtep_ip
,
921 if (json_mac_hdr
== NULL
) {
922 if ((wctx
->flags
& SHOW_REMOTE_MAC_FROM_VTEP
)
923 && (wctx
->count
== 0)) {
924 vty_out(vty
, "\nVNI %u\n\n", wctx
->zevpn
->vni
);
925 vty_out(vty
, "%-17s %-6s %-5s%-30s %-5s %s\n",
926 "MAC", "Type", "Flags",
927 "Intf/Remote ES/VTEP", "VLAN",
931 inet_ntop(AF_INET
, &mac
->fwd_info
.r_vtep_ip
,
932 addr_buf
, sizeof(addr_buf
));
934 vty_out(vty
, "%-17s %-6s %-5s %-30s %-5s %u/%u\n", buf1
,
936 zebra_evpn_print_mac_flags(mac
, flags_buf
,
938 mac
->es
? mac
->es
->esi_str
: addr_buf
,
939 "", mac
->loc_seq
, mac
->rem_seq
);
941 json_object_string_add(json_mac
, "type", "remote");
942 json_object_string_addf(json_mac
, "remoteVtep", "%pI4",
943 &mac
->fwd_info
.r_vtep_ip
);
944 json_object_object_add(json_mac_hdr
, buf1
, json_mac
);
945 json_object_int_add(json_mac
, "localSequence",
947 json_object_int_add(json_mac
, "remoteSequence",
949 json_object_int_add(json_mac
, "detectionCount",
951 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_DUPLICATE
))
952 json_object_boolean_true_add(json_mac
,
955 json_object_boolean_false_add(json_mac
,
964 * Print MAC hash entry in detail - called for display of all MACs.
966 void zebra_evpn_print_mac_hash_detail(struct hash_bucket
*bucket
, void *ctxt
)
969 json_object
*json_mac_hdr
= NULL
;
970 struct zebra_mac
*mac
;
971 struct mac_walk_ctx
*wctx
= ctxt
;
972 char buf1
[ETHER_ADDR_STRLEN
];
975 json_mac_hdr
= wctx
->json
;
976 mac
= (struct zebra_mac
*)bucket
->data
;
981 prefix_mac2str(&mac
->macaddr
, buf1
, sizeof(buf1
));
983 zebra_evpn_print_mac(mac
, vty
, json_mac_hdr
);
987 * Inform BGP about local MACIP.
989 int zebra_evpn_macip_send_msg_to_client(vni_t vni
,
990 const struct ethaddr
*macaddr
,
991 const struct ipaddr
*ip
, uint8_t flags
,
992 uint32_t seq
, int state
,
993 struct zebra_evpn_es
*es
, uint16_t cmd
)
996 struct zserv
*client
= NULL
;
997 struct stream
*s
= NULL
;
998 esi_t
*esi
= es
? &es
->esi
: zero_esi
;
1000 client
= zserv_find_client(ZEBRA_ROUTE_BGP
, 0);
1001 /* BGP may not be running. */
1005 s
= stream_new(ZEBRA_MAX_PACKET_SIZ
);
1007 zclient_create_header(s
, cmd
, zebra_vrf_get_evpn_id());
1008 stream_putl(s
, vni
);
1009 stream_put(s
, macaddr
->octet
, ETH_ALEN
);
1012 if (IS_IPADDR_V4(ip
))
1013 ipa_len
= IPV4_MAX_BYTELEN
;
1014 else if (IS_IPADDR_V6(ip
))
1015 ipa_len
= IPV6_MAX_BYTELEN
;
1017 stream_putl(s
, ipa_len
); /* IP address length */
1019 stream_put(s
, &ip
->ip
.addr
, ipa_len
); /* IP address */
1021 stream_putl(s
, 0); /* Just MAC. */
1023 if (cmd
== ZEBRA_MACIP_ADD
) {
1024 stream_putc(s
, flags
); /* sticky mac/gateway mac */
1025 stream_putl(s
, seq
); /* sequence number */
1026 stream_put(s
, esi
, sizeof(esi_t
));
1028 stream_putl(s
, state
); /* state - active/inactive */
1032 /* Write packet size. */
1033 stream_putw_at(s
, 0, stream_get_endp(s
));
1035 if (IS_ZEBRA_DEBUG_VXLAN
) {
1036 char flag_buf
[MACIP_BUF_SIZE
];
1039 "Send MACIP %s f %s MAC %pEA IP %pIA seq %u L2-VNI %u ESI %s to %s",
1040 (cmd
== ZEBRA_MACIP_ADD
) ? "Add" : "Del",
1041 zclient_evpn_dump_macip_flags(flags
, flag_buf
,
1043 macaddr
, ip
, seq
, vni
,
1044 es
? es
->esi_str
: "-",
1045 zebra_route_string(client
->proto
));
1048 if (cmd
== ZEBRA_MACIP_ADD
)
1049 client
->macipadd_cnt
++;
1051 client
->macipdel_cnt
++;
1053 return zserv_send_message(client
, s
);
1056 static unsigned int mac_hash_keymake(const void *p
)
1058 const struct zebra_mac
*pmac
= p
;
1059 const void *pnt
= (void *)pmac
->macaddr
.octet
;
1061 return jhash(pnt
, ETH_ALEN
, 0xa5a5a55a);
1065 * Compare two MAC addresses.
1067 static bool mac_cmp(const void *p1
, const void *p2
)
1069 const struct zebra_mac
*pmac1
= p1
;
1070 const struct zebra_mac
*pmac2
= p2
;
1072 if (pmac1
== NULL
&& pmac2
== NULL
)
1075 if (pmac1
== NULL
|| pmac2
== NULL
)
1078 return (memcmp(pmac1
->macaddr
.octet
, pmac2
->macaddr
.octet
, ETH_ALEN
)
1083 * Callback to allocate MAC hash entry.
1085 static void *zebra_evpn_mac_alloc(void *p
)
1087 const struct zebra_mac
*tmp_mac
= p
;
1088 struct zebra_mac
*mac
;
1090 mac
= XCALLOC(MTYPE_MAC
, sizeof(struct zebra_mac
));
1093 return ((void *)mac
);
1099 struct zebra_mac
*zebra_evpn_mac_add(struct zebra_evpn
*zevpn
,
1100 const struct ethaddr
*macaddr
)
1102 struct zebra_mac tmp_mac
;
1103 struct zebra_mac
*mac
= NULL
;
1105 memset(&tmp_mac
, 0, sizeof(struct zebra_mac
));
1106 memcpy(&tmp_mac
.macaddr
, macaddr
, ETH_ALEN
);
1107 mac
= hash_get(zevpn
->mac_table
, &tmp_mac
, zebra_evpn_mac_alloc
);
1111 mac
->dad_mac_auto_recovery_timer
= NULL
;
1113 mac
->neigh_list
= list_new();
1114 mac
->neigh_list
->cmp
= neigh_list_cmp
;
1116 mac
->uptime
= monotime(NULL
);
1117 if (IS_ZEBRA_DEBUG_VXLAN
|| IS_ZEBRA_DEBUG_EVPN_MH_MAC
) {
1118 char mac_buf
[MAC_BUF_SIZE
];
1120 zlog_debug("%s: MAC %pEA flags %s", __func__
,
1122 zebra_evpn_zebra_mac_flag_dump(mac
, mac_buf
,
1131 int zebra_evpn_mac_del(struct zebra_evpn
*zevpn
, struct zebra_mac
*mac
)
1133 struct zebra_mac
*tmp_mac
;
1135 if (IS_ZEBRA_DEBUG_VXLAN
|| IS_ZEBRA_DEBUG_EVPN_MH_MAC
) {
1136 char mac_buf
[MAC_BUF_SIZE
];
1138 zlog_debug("%s: MAC %pEA flags %s", __func__
,
1140 zebra_evpn_zebra_mac_flag_dump(mac
, mac_buf
,
1144 /* force de-ref any ES entry linked to the MAC */
1145 zebra_evpn_es_mac_deref_entry(mac
);
1147 /* remove links to the destination access port */
1148 zebra_evpn_mac_clear_fwd_info(mac
);
1150 /* Cancel proxy hold timer */
1151 zebra_evpn_mac_stop_hold_timer(mac
);
1153 /* Cancel auto recovery */
1154 THREAD_OFF(mac
->dad_mac_auto_recovery_timer
);
1156 /* If the MAC is freed before the neigh we will end up
1157 * with a stale pointer against the neigh.
1158 * The situation can arise when a MAC is in remote state
1159 * and its associated neigh is local state.
1160 * zebra_evpn_cfg_cleanup() cleans up remote neighs and MACs.
1161 * Instead of deleting remote MAC, if its neigh list is non-empty
1162 * (associated to local neighs), mark the MAC as AUTO.
1164 if (!list_isempty(mac
->neigh_list
)) {
1165 if (IS_ZEBRA_DEBUG_VXLAN
)
1167 "MAC %pEA (flags 0x%x vni %u) has non-empty neigh list "
1168 "count %u, mark MAC as AUTO",
1169 &mac
->macaddr
, mac
->flags
, zevpn
->vni
,
1170 listcount(mac
->neigh_list
));
1172 SET_FLAG(mac
->flags
, ZEBRA_MAC_AUTO
);
1176 list_delete(&mac
->neigh_list
);
1178 /* Free the VNI hash entry and allocated memory. */
1179 tmp_mac
= hash_release(zevpn
->mac_table
, mac
);
1180 XFREE(MTYPE_MAC
, tmp_mac
);
1185 static bool zebra_evpn_check_mac_del_from_db(struct mac_walk_ctx
*wctx
,
1186 struct zebra_mac
*mac
)
1188 if ((wctx
->flags
& DEL_LOCAL_MAC
) && (mac
->flags
& ZEBRA_MAC_LOCAL
))
1190 else if ((wctx
->flags
& DEL_REMOTE_MAC
)
1191 && (mac
->flags
& ZEBRA_MAC_REMOTE
))
1193 else if ((wctx
->flags
& DEL_REMOTE_MAC_FROM_VTEP
)
1194 && (mac
->flags
& ZEBRA_MAC_REMOTE
)
1195 && IPV4_ADDR_SAME(&mac
->fwd_info
.r_vtep_ip
, &wctx
->r_vtep_ip
))
1197 else if ((wctx
->flags
& DEL_LOCAL_MAC
) && (mac
->flags
& ZEBRA_MAC_AUTO
)
1198 && !listcount(mac
->neigh_list
)) {
1199 if (IS_ZEBRA_DEBUG_VXLAN
) {
1200 char mac_buf
[MAC_BUF_SIZE
];
1203 "%s: Del MAC %pEA flags %s", __func__
,
1205 zebra_evpn_zebra_mac_flag_dump(
1206 mac
, mac_buf
, sizeof(mac_buf
)));
1208 wctx
->uninstall
= 0;
1217 * Free MAC hash entry (callback)
1219 static void zebra_evpn_mac_del_hash_entry(struct hash_bucket
*bucket
, void *arg
)
1221 struct mac_walk_ctx
*wctx
= arg
;
1222 struct zebra_mac
*mac
= bucket
->data
;
1224 if (zebra_evpn_check_mac_del_from_db(wctx
, mac
)) {
1225 if (wctx
->upd_client
&& (mac
->flags
& ZEBRA_MAC_LOCAL
)) {
1226 zebra_evpn_mac_send_del_to_client(wctx
->zevpn
->vni
,
1230 if (wctx
->uninstall
) {
1231 if (zebra_evpn_mac_is_static(mac
))
1232 zebra_evpn_sync_mac_dp_install(
1233 mac
, false /* set_inactive */,
1234 true /* force_clear_static */,
1237 if (mac
->flags
& ZEBRA_MAC_REMOTE
)
1238 zebra_evpn_rem_mac_uninstall(wctx
->zevpn
, mac
,
1242 zebra_evpn_mac_del(wctx
->zevpn
, mac
);
1249 * Delete all MAC entries for this EVPN.
1251 void zebra_evpn_mac_del_all(struct zebra_evpn
*zevpn
, int uninstall
,
1252 int upd_client
, uint32_t flags
)
1254 struct mac_walk_ctx wctx
;
1256 if (!zevpn
->mac_table
)
1259 memset(&wctx
, 0, sizeof(struct mac_walk_ctx
));
1261 wctx
.uninstall
= uninstall
;
1262 wctx
.upd_client
= upd_client
;
1265 hash_iterate(zevpn
->mac_table
, zebra_evpn_mac_del_hash_entry
, &wctx
);
1269 * Look up MAC hash entry.
1271 struct zebra_mac
*zebra_evpn_mac_lookup(struct zebra_evpn
*zevpn
,
1272 const struct ethaddr
*mac
)
1274 struct zebra_mac tmp
;
1275 struct zebra_mac
*pmac
;
1277 memset(&tmp
, 0, sizeof(tmp
));
1278 memcpy(&tmp
.macaddr
, mac
, ETH_ALEN
);
1279 pmac
= hash_lookup(zevpn
->mac_table
, &tmp
);
1285 * Inform BGP about local MAC addition.
1287 int zebra_evpn_mac_send_add_to_client(vni_t vni
, const struct ethaddr
*macaddr
,
1288 uint32_t mac_flags
, uint32_t seq
,
1289 struct zebra_evpn_es
*es
)
1293 if (CHECK_FLAG(mac_flags
, ZEBRA_MAC_LOCAL_INACTIVE
)) {
1294 /* host reachability has not been verified locally */
1296 /* if no ES peer is claiming reachability we can't advertise the
1299 if (!CHECK_FLAG(mac_flags
, ZEBRA_MAC_ES_PEER_ACTIVE
))
1302 /* ES peers are claiming reachability; we will
1303 * advertise the entry but with a proxy flag
1305 SET_FLAG(flags
, ZEBRA_MACIP_TYPE_PROXY_ADVERT
);
1308 if (CHECK_FLAG(mac_flags
, ZEBRA_MAC_STICKY
))
1309 SET_FLAG(flags
, ZEBRA_MACIP_TYPE_STICKY
);
1310 if (CHECK_FLAG(mac_flags
, ZEBRA_MAC_DEF_GW
))
1311 SET_FLAG(flags
, ZEBRA_MACIP_TYPE_GW
);
1313 return zebra_evpn_macip_send_msg_to_client(vni
, macaddr
, NULL
, flags
,
1314 seq
, ZEBRA_NEIGH_ACTIVE
, es
,
1319 * Inform BGP about local MAC deletion.
1321 int zebra_evpn_mac_send_del_to_client(vni_t vni
, const struct ethaddr
*macaddr
,
1322 uint32_t flags
, bool force
)
1325 if (CHECK_FLAG(flags
, ZEBRA_MAC_LOCAL_INACTIVE
)
1326 && !CHECK_FLAG(flags
, ZEBRA_MAC_ES_PEER_ACTIVE
))
1327 /* the host was not advertised - nothing to delete */
1331 return zebra_evpn_macip_send_msg_to_client(
1332 vni
, macaddr
, NULL
, 0 /* flags */, 0 /* seq */,
1333 ZEBRA_NEIGH_ACTIVE
, NULL
, ZEBRA_MACIP_DEL
);
1337 * wrapper to create a MAC hash table
1339 struct hash
*zebra_mac_db_create(const char *desc
)
1341 return hash_create_size(8, mac_hash_keymake
, mac_cmp
, desc
);
1344 /* program sync mac flags in the dataplane */
1345 int zebra_evpn_sync_mac_dp_install(struct zebra_mac
*mac
, bool set_inactive
,
1346 bool force_clear_static
, const char *caller
)
1348 struct interface
*ifp
;
1351 struct zebra_evpn
*zevpn
= mac
->zevpn
;
1353 struct zebra_if
*zif
;
1354 struct interface
*br_ifp
;
1356 /* If the ES-EVI doesn't exist defer install. When the ES-EVI is
1357 * created we will attempt to install the mac entry again
1360 struct zebra_evpn_es_evi
*es_evi
;
1362 es_evi
= zebra_evpn_es_evi_find(mac
->es
, mac
->zevpn
);
1364 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
1366 "%s: dp-install sync-mac vni %u mac %pEA es %s 0x%x %sskipped, no es-evi",
1367 caller
, zevpn
->vni
, &mac
->macaddr
,
1368 mac
->es
? mac
->es
->esi_str
: "-",
1370 set_inactive
? "inactive " : "");
1375 /* get the access vlan from the vxlan_device */
1376 zebra_evpn_mac_get_access_info(mac
, &ifp
, &vid
);
1379 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
) {
1380 char mac_buf
[MAC_BUF_SIZE
];
1383 "%s: dp-install sync-mac vni %u mac %pEA es %s %s%sskipped, no access-port",
1384 caller
, zevpn
->vni
, &mac
->macaddr
,
1385 mac
->es
? mac
->es
->esi_str
: "-",
1386 zebra_evpn_zebra_mac_flag_dump(mac
, mac_buf
,
1388 set_inactive
? "inactive " : "");
1394 br_ifp
= zif
->brslave_info
.br_if
;
1396 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
) {
1397 char mac_buf
[MAC_BUF_SIZE
];
1400 "%s: dp-install sync-mac vni %u mac %pEA es %s %s%sskipped, no br",
1401 caller
, zevpn
->vni
, &mac
->macaddr
,
1402 mac
->es
? mac
->es
->esi_str
: "-",
1403 zebra_evpn_zebra_mac_flag_dump(mac
, mac_buf
,
1405 set_inactive
? "inactive " : "");
1410 sticky
= !!CHECK_FLAG(mac
->flags
, ZEBRA_MAC_STICKY
);
1411 if (force_clear_static
)
1414 set_static
= zebra_evpn_mac_is_static(mac
);
1416 /* We can install a local mac that has been synced from the peer
1417 * over the VxLAN-overlay/network-port if fast failover is not
1418 * supported and if the local ES is oper-down.
1420 if (mac
->es
&& zebra_evpn_es_local_mac_via_network_port(mac
->es
)) {
1421 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
) {
1422 char mac_buf
[MAC_BUF_SIZE
];
1425 "dp-%s sync-nw-mac vni %u mac %pEA es %s %s%s",
1426 set_static
? "install" : "uninstall",
1427 zevpn
->vni
, &mac
->macaddr
,
1428 mac
->es
? mac
->es
->esi_str
: "-",
1429 zebra_evpn_zebra_mac_flag_dump(mac
, mac_buf
,
1431 set_inactive
? "inactive " : "");
1434 /* XXX - old_static needs to be computed more
1437 zebra_evpn_rem_mac_install(zevpn
, mac
,
1438 true /* old_static */);
1440 zebra_evpn_rem_mac_uninstall(zevpn
, mac
,
1446 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
) {
1447 char mac_buf
[MAC_BUF_SIZE
];
1449 zlog_debug("dp-install sync-mac vni %u mac %pEA es %s %s%s%s",
1450 zevpn
->vni
, &mac
->macaddr
,
1451 mac
->es
? mac
->es
->esi_str
: "-",
1452 zebra_evpn_zebra_mac_flag_dump(mac
, mac_buf
,
1454 set_static
? "static " : "",
1455 set_inactive
? "inactive " : "");
1458 dplane_local_mac_add(ifp
, br_ifp
, vid
, &mac
->macaddr
, sticky
,
1459 set_static
, set_inactive
);
1463 void zebra_evpn_mac_send_add_del_to_client(struct zebra_mac
*mac
,
1468 zebra_evpn_mac_send_add_to_client(mac
->zevpn
->vni
,
1469 &mac
->macaddr
, mac
->flags
,
1470 mac
->loc_seq
, mac
->es
);
1471 else if (old_bgp_ready
)
1472 zebra_evpn_mac_send_del_to_client(mac
->zevpn
->vni
,
1473 &mac
->macaddr
, mac
->flags
,
1477 /* MAC hold timer is used to age out peer-active flag.
1479 * During this wait time we expect the dataplane component or an
1480 * external neighmgr daemon to probe existing hosts to independently
1481 * establish their presence on the ES.
1483 static void zebra_evpn_mac_hold_exp_cb(struct thread
*t
)
1485 struct zebra_mac
*mac
;
1491 mac
= THREAD_ARG(t
);
1492 /* the purpose of the hold timer is to age out the peer-active
1495 if (!CHECK_FLAG(mac
->flags
, ZEBRA_MAC_ES_PEER_ACTIVE
))
1498 old_bgp_ready
= zebra_evpn_mac_is_ready_for_bgp(mac
->flags
);
1499 old_static
= zebra_evpn_mac_is_static(mac
);
1500 UNSET_FLAG(mac
->flags
, ZEBRA_MAC_ES_PEER_ACTIVE
);
1501 new_bgp_ready
= zebra_evpn_mac_is_ready_for_bgp(mac
->flags
);
1502 new_static
= zebra_evpn_mac_is_static(mac
);
1504 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
) {
1505 char mac_buf
[MAC_BUF_SIZE
];
1508 "sync-mac vni %u mac %pEA es %s %shold expired",
1509 mac
->zevpn
->vni
, &mac
->macaddr
,
1510 mac
->es
? mac
->es
->esi_str
: "-",
1511 zebra_evpn_zebra_mac_flag_dump(mac
, mac_buf
,
1515 /* re-program the local mac in the dataplane if the mac is no
1518 if (old_static
!= new_static
)
1519 zebra_evpn_sync_mac_dp_install(mac
, false /* set_inactive */,
1520 false /* force_clear_static */,
1523 /* inform bgp if needed */
1524 if (old_bgp_ready
!= new_bgp_ready
)
1525 zebra_evpn_mac_send_add_del_to_client(mac
, old_bgp_ready
,
1529 static inline void zebra_evpn_mac_start_hold_timer(struct zebra_mac
*mac
)
1531 if (mac
->hold_timer
)
1534 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
) {
1535 char mac_buf
[MAC_BUF_SIZE
];
1538 "sync-mac vni %u mac %pEA es %s %shold started",
1539 mac
->zevpn
->vni
, &mac
->macaddr
,
1540 mac
->es
? mac
->es
->esi_str
: "-",
1541 zebra_evpn_zebra_mac_flag_dump(mac
, mac_buf
,
1544 thread_add_timer(zrouter
.master
, zebra_evpn_mac_hold_exp_cb
, mac
,
1545 zmh_info
->mac_hold_time
, &mac
->hold_timer
);
1548 void zebra_evpn_mac_stop_hold_timer(struct zebra_mac
*mac
)
1550 if (!mac
->hold_timer
)
1553 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
) {
1554 char mac_buf
[MAC_BUF_SIZE
];
1557 "sync-mac vni %u mac %pEA es %s %shold stopped",
1558 mac
->zevpn
->vni
, &mac
->macaddr
,
1559 mac
->es
? mac
->es
->esi_str
: "-",
1560 zebra_evpn_zebra_mac_flag_dump(mac
, mac_buf
,
1564 THREAD_OFF(mac
->hold_timer
);
1567 void zebra_evpn_sync_mac_del(struct zebra_mac
*mac
)
1572 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
) {
1573 char mac_buf
[MAC_BUF_SIZE
];
1576 "sync-mac del vni %u mac %pEA es %s seq %d f %s",
1577 mac
->zevpn
->vni
, &mac
->macaddr
,
1578 mac
->es
? mac
->es
->esi_str
: "-", mac
->loc_seq
,
1579 zebra_evpn_zebra_mac_flag_dump(mac
, mac_buf
,
1583 old_static
= zebra_evpn_mac_is_static(mac
);
1584 UNSET_FLAG(mac
->flags
, ZEBRA_MAC_ES_PEER_PROXY
);
1585 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_ES_PEER_ACTIVE
))
1586 zebra_evpn_mac_start_hold_timer(mac
);
1587 new_static
= zebra_evpn_mac_is_static(mac
);
1589 if (old_static
!= new_static
)
1590 /* program the local mac in the kernel */
1591 zebra_evpn_sync_mac_dp_install(mac
, false /* set_inactive */,
1592 false /* force_clear_static */,
1596 static inline bool zebra_evpn_mac_is_bgp_seq_ok(struct zebra_evpn
*zevpn
,
1597 struct zebra_mac
*mac
,
1598 uint32_t seq
, uint16_t ipa_len
,
1599 const struct ipaddr
*ipaddr
,
1602 char ipbuf
[INET6_ADDRSTRLEN
];
1606 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
)) {
1607 tmp_seq
= mac
->loc_seq
;
1610 tmp_seq
= mac
->rem_seq
;
1614 if (seq
< tmp_seq
) {
1615 /* if the mac was never advertised to bgp we must accept
1616 * whatever sequence number bgp sends
1617 * XXX - check with Vivek
1619 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
)
1620 && !zebra_evpn_mac_is_ready_for_bgp(mac
->flags
)) {
1621 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
1622 || IS_ZEBRA_DEBUG_VXLAN
) {
1623 char mac_buf
[MAC_BUF_SIZE
];
1626 "%s-macip accept vni %u %s-mac %pEA%s%s lower seq %u f %s",
1627 sync
? "sync" : "rem", zevpn
->vni
,
1630 ipa_len
? " IP " : "",
1631 ipa_len
? ipaddr2str(ipaddr
, ipbuf
,
1635 zebra_evpn_zebra_mac_flag_dump(
1636 mac
, mac_buf
, sizeof(mac_buf
)));
1642 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
|| IS_ZEBRA_DEBUG_VXLAN
) {
1643 char mac_buf
[MAC_BUF_SIZE
];
1646 "%s-macip ignore vni %u %s-mac %pEA%s%s as existing has higher seq %u f %s",
1647 sync
? "sync" : "rem", zevpn
->vni
, n_type
,
1649 ipa_len
? " IP " : "",
1650 ipa_len
? ipaddr2str(ipaddr
, ipbuf
,
1654 zebra_evpn_zebra_mac_flag_dump(
1655 mac
, mac_buf
, sizeof(mac_buf
)));
1663 struct zebra_mac
*zebra_evpn_proc_sync_mac_update(
1664 struct zebra_evpn
*zevpn
, const struct ethaddr
*macaddr
,
1665 uint16_t ipa_len
, const struct ipaddr
*ipaddr
, uint8_t flags
,
1666 uint32_t seq
, const esi_t
*esi
, struct sync_mac_ip_ctx
*ctx
)
1668 struct zebra_mac
*mac
;
1669 bool inform_bgp
= false;
1670 bool inform_dataplane
= false;
1671 bool seq_change
= false;
1672 bool es_change
= false;
1674 char ipbuf
[INET6_ADDRSTRLEN
];
1675 bool old_local
= false;
1679 mac
= zebra_evpn_mac_lookup(zevpn
, macaddr
);
1681 /* if it is a new local path we need to inform both
1682 * the control protocol and the data-plane
1685 inform_dataplane
= true;
1686 ctx
->mac_created
= true;
1687 ctx
->mac_inactive
= true;
1689 /* create the MAC and associate it with the dest ES */
1690 mac
= zebra_evpn_mac_add(zevpn
, macaddr
);
1691 zebra_evpn_es_mac_ref(mac
, esi
);
1693 /* local mac activated by an ES peer */
1694 SET_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
);
1695 /* if mac-only route setup peer flags */
1697 if (CHECK_FLAG(flags
, ZEBRA_MACIP_TYPE_PROXY_ADVERT
))
1698 SET_FLAG(mac
->flags
, ZEBRA_MAC_ES_PEER_PROXY
);
1700 SET_FLAG(mac
->flags
, ZEBRA_MAC_ES_PEER_ACTIVE
);
1702 SET_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL_INACTIVE
);
1703 old_bgp_ready
= false;
1704 new_bgp_ready
= zebra_evpn_mac_is_ready_for_bgp(mac
->flags
);
1713 mac
->uptime
= monotime(NULL
);
1715 old_flags
= mac
->flags
;
1716 sticky
= !!CHECK_FLAG(old_flags
, ZEBRA_MAC_STICKY
);
1717 remote_gw
= !!CHECK_FLAG(old_flags
, ZEBRA_MAC_REMOTE_DEF_GW
);
1718 if (sticky
|| remote_gw
) {
1719 if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH
)
1721 "Ignore sync-macip vni %u mac %pEA%s%s%s%s",
1722 zevpn
->vni
, macaddr
,
1723 ipa_len
? " IP " : "",
1724 ipa_len
? ipaddr2str(ipaddr
, ipbuf
,
1727 sticky
? " sticky" : "",
1728 remote_gw
? " remote_gw" : "");
1729 ctx
->ignore_macip
= true;
1732 if (!zebra_evpn_mac_is_bgp_seq_ok(zevpn
, mac
, seq
, ipa_len
,
1734 ctx
->ignore_macip
= true;
1738 old_local
= !!CHECK_FLAG(old_flags
, ZEBRA_MAC_LOCAL
);
1739 old_static
= zebra_evpn_mac_is_static(mac
);
1741 /* re-build the mac flags */
1743 SET_FLAG(new_flags
, ZEBRA_MAC_LOCAL
);
1744 /* retain old local activity flag */
1745 if (old_flags
& ZEBRA_MAC_LOCAL
) {
1746 new_flags
|= (old_flags
& ZEBRA_MAC_LOCAL_INACTIVE
);
1748 new_flags
|= ZEBRA_MAC_LOCAL_INACTIVE
;
1749 ctx
->mac_inactive
= true;
1752 /* if mac-ip route do NOT update the peer flags
1753 * i.e. retain only flags as is
1755 new_flags
|= (old_flags
& ZEBRA_MAC_ALL_PEER_FLAGS
);
1757 /* if mac-only route update peer flags */
1758 if (CHECK_FLAG(flags
, ZEBRA_MACIP_TYPE_PROXY_ADVERT
)) {
1759 SET_FLAG(new_flags
, ZEBRA_MAC_ES_PEER_PROXY
);
1760 /* if the mac was peer-active previously we
1761 * need to keep the flag and start the
1762 * holdtimer on it. the peer-active flag is
1763 * cleared on holdtimer expiry.
1765 if (CHECK_FLAG(old_flags
,
1766 ZEBRA_MAC_ES_PEER_ACTIVE
)) {
1768 ZEBRA_MAC_ES_PEER_ACTIVE
);
1769 zebra_evpn_mac_start_hold_timer(mac
);
1772 SET_FLAG(new_flags
, ZEBRA_MAC_ES_PEER_ACTIVE
);
1773 /* stop hold timer if a peer has verified
1776 zebra_evpn_mac_stop_hold_timer(mac
);
1780 zebra_evpn_mac_clear_fwd_info(mac
);
1781 mac
->flags
= new_flags
;
1783 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
&& (old_flags
!= new_flags
)) {
1784 char mac_buf
[MAC_BUF_SIZE
], omac_buf
[MAC_BUF_SIZE
];
1785 struct zebra_mac omac
;
1787 omac
.flags
= old_flags
;
1789 "sync-mac vni %u mac %pEA old_f %snew_f %s",
1790 zevpn
->vni
, macaddr
,
1791 zebra_evpn_zebra_mac_flag_dump(
1792 &omac
, omac_buf
, sizeof(omac_buf
)),
1793 zebra_evpn_zebra_mac_flag_dump(
1794 mac
, mac_buf
, sizeof(mac_buf
)));
1798 es_change
= zebra_evpn_es_mac_ref(mac
, esi
);
1799 /* if mac dest change - inform both sides */
1802 inform_dataplane
= true;
1803 ctx
->mac_inactive
= true;
1806 /* if peer-flag is being set notify dataplane that the
1807 * entry must not be expired because of local inactivity
1809 new_static
= zebra_evpn_mac_is_static(mac
);
1810 if (old_static
!= new_static
)
1811 inform_dataplane
= true;
1813 old_bgp_ready
= zebra_evpn_mac_is_ready_for_bgp(old_flags
);
1814 new_bgp_ready
= zebra_evpn_mac_is_ready_for_bgp(mac
->flags
);
1815 if (old_bgp_ready
!= new_bgp_ready
)
1820 /* update sequence number; if that results in a new local sequence
1823 tmp_seq
= MAX(mac
->loc_seq
, seq
);
1824 if (tmp_seq
!= mac
->loc_seq
) {
1825 mac
->loc_seq
= tmp_seq
;
1830 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
) {
1831 char mac_buf
[MAC_BUF_SIZE
];
1833 zlog_debug("sync-mac %s vni %u mac %pEA es %s seq %d f %s%s%s",
1834 ctx
->mac_created
? "created" : "updated",
1835 zevpn
->vni
, macaddr
,
1836 mac
->es
? mac
->es
->esi_str
: "-", mac
->loc_seq
,
1837 zebra_evpn_zebra_mac_flag_dump(mac
, mac_buf
,
1839 inform_bgp
? "inform_bgp" : "",
1840 inform_dataplane
? " inform_dp" : "");
1844 zebra_evpn_mac_send_add_del_to_client(mac
, old_bgp_ready
,
1847 /* neighs using the mac may need to be re-sent to
1848 * bgp with updated info
1850 if (seq_change
|| es_change
|| !old_local
)
1851 zebra_evpn_process_neigh_on_local_mac_change(
1852 zevpn
, mac
, seq_change
, es_change
);
1854 if (inform_dataplane
) {
1856 /* if the mac is being created as a part of MAC-IP
1857 * route wait for the neigh to be updated or
1858 * created before programming the mac
1860 ctx
->mac_dp_update_deferred
= true;
1862 /* program the local mac in the kernel. when the ES
1863 * change we need to force the dataplane to reset
1864 * the activity as we are yet to establish activity
1867 zebra_evpn_sync_mac_dp_install(
1868 mac
, ctx
->mac_inactive
,
1869 false /* force_clear_static */, __func__
);
1875 /* update local forwarding info. return true if a dest-ES change
1878 static bool zebra_evpn_local_mac_update_fwd_info(struct zebra_mac
*mac
,
1879 struct interface
*ifp
,
1882 struct zebra_if
*zif
= ifp
->info
;
1884 ns_id_t local_ns_id
= NS_DEFAULT
;
1885 struct zebra_vrf
*zvrf
;
1886 struct zebra_evpn_es
*es
;
1888 zvrf
= ifp
->vrf
->info
;
1889 if (zvrf
&& zvrf
->zns
)
1890 local_ns_id
= zvrf
->zns
->ns_id
;
1892 zebra_evpn_mac_clear_fwd_info(mac
);
1894 es
= zif
->es_info
.es
;
1895 if (es
&& (es
->flags
& ZEBRA_EVPNES_BYPASS
))
1897 es_change
= zebra_evpn_es_mac_ref_entry(mac
, es
);
1900 /* if es is set fwd_info is not-relevant/taped-out */
1901 mac
->fwd_info
.local
.ifindex
= ifp
->ifindex
;
1902 mac
->fwd_info
.local
.ns_id
= local_ns_id
;
1903 mac
->fwd_info
.local
.vid
= vid
;
1904 zebra_evpn_mac_ifp_link(mac
, ifp
);
1910 /* Notify Local MACs to the clienti, skips GW MAC */
1911 static void zebra_evpn_send_mac_hash_entry_to_client(struct hash_bucket
*bucket
,
1914 struct mac_walk_ctx
*wctx
= arg
;
1915 struct zebra_mac
*zmac
= bucket
->data
;
1917 if (CHECK_FLAG(zmac
->flags
, ZEBRA_MAC_DEF_GW
))
1920 if (CHECK_FLAG(zmac
->flags
, ZEBRA_MAC_LOCAL
))
1921 zebra_evpn_mac_send_add_to_client(wctx
->zevpn
->vni
,
1922 &zmac
->macaddr
, zmac
->flags
,
1923 zmac
->loc_seq
, zmac
->es
);
1926 /* Iterator to Notify Local MACs of a EVPN */
1927 void zebra_evpn_send_mac_list_to_client(struct zebra_evpn
*zevpn
)
1929 struct mac_walk_ctx wctx
;
1931 if (!zevpn
->mac_table
)
1934 memset(&wctx
, 0, sizeof(struct mac_walk_ctx
));
1937 hash_iterate(zevpn
->mac_table
, zebra_evpn_send_mac_hash_entry_to_client
,
1941 void zebra_evpn_rem_mac_del(struct zebra_evpn
*zevpn
, struct zebra_mac
*mac
)
1943 zebra_evpn_process_neigh_on_remote_mac_del(zevpn
, mac
);
1944 /* the remote sequence number in the auto mac entry
1945 * needs to be reset to 0 as the mac entry may have
1946 * been removed on all VTEPs (including
1947 * the originating one)
1951 /* If all remote neighbors referencing a remote MAC
1952 * go away, we need to uninstall the MAC.
1954 if (remote_neigh_count(mac
) == 0) {
1955 zebra_evpn_rem_mac_uninstall(zevpn
, mac
, false /*force*/);
1956 zebra_evpn_es_mac_deref_entry(mac
);
1957 UNSET_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE
);
1960 if (list_isempty(mac
->neigh_list
))
1961 zebra_evpn_mac_del(zevpn
, mac
);
1963 SET_FLAG(mac
->flags
, ZEBRA_MAC_AUTO
);
1966 /* Print Duplicate MAC */
1967 void zebra_evpn_print_dad_mac_hash(struct hash_bucket
*bucket
, void *ctxt
)
1969 struct zebra_mac
*mac
;
1971 mac
= (struct zebra_mac
*)bucket
->data
;
1975 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_DUPLICATE
))
1976 zebra_evpn_print_mac_hash(bucket
, ctxt
);
1979 /* Print Duplicate MAC in detail */
1980 void zebra_evpn_print_dad_mac_hash_detail(struct hash_bucket
*bucket
,
1983 struct zebra_mac
*mac
;
1985 mac
= (struct zebra_mac
*)bucket
->data
;
1989 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_DUPLICATE
))
1990 zebra_evpn_print_mac_hash_detail(bucket
, ctxt
);
1993 int zebra_evpn_mac_remote_macip_add(
1994 struct zebra_evpn
*zevpn
, struct zebra_vrf
*zvrf
,
1995 const struct ethaddr
*macaddr
, uint16_t ipa_len
,
1996 const struct ipaddr
*ipaddr
, struct zebra_mac
**macp
,
1997 struct in_addr vtep_ip
, uint8_t flags
, uint32_t seq
, const esi_t
*esi
)
1999 char buf1
[INET6_ADDRSTRLEN
];
2003 bool do_dad
= false;
2004 bool is_dup_detect
= false;
2006 bool old_static
= false;
2007 struct zebra_mac
*mac
;
2008 bool old_es_present
;
2009 bool new_es_present
;
2011 sticky
= !!CHECK_FLAG(flags
, ZEBRA_MACIP_TYPE_STICKY
);
2012 remote_gw
= !!CHECK_FLAG(flags
, ZEBRA_MACIP_TYPE_GW
);
2014 mac
= zebra_evpn_mac_lookup(zevpn
, macaddr
);
2016 /* Ignore if the mac is already present as a gateway mac */
2017 if (mac
&& CHECK_FLAG(mac
->flags
, ZEBRA_MAC_DEF_GW
)
2018 && CHECK_FLAG(flags
, ZEBRA_MACIP_TYPE_GW
)) {
2019 if (IS_ZEBRA_DEBUG_VXLAN
)
2021 "Ignore remote MACIP ADD VNI %u MAC %pEA%s%s as MAC is already configured as gateway MAC",
2022 zevpn
->vni
, macaddr
,
2023 ipa_len
? " IP " : "",
2024 ipa_len
? ipaddr2str(ipaddr
, buf1
, sizeof(buf1
))
2029 old_esi
= (mac
&& mac
->es
) ? &mac
->es
->esi
: zero_esi
;
2031 /* check if the remote MAC is unknown or has a change.
2032 * If so, that needs to be updated first. Note that client could
2033 * install MAC and MACIP separately or just install the latter.
2035 if (!mac
|| !CHECK_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE
)
2036 || sticky
!= !!CHECK_FLAG(mac
->flags
, ZEBRA_MAC_STICKY
)
2037 || remote_gw
!= !!CHECK_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE_DEF_GW
)
2038 || !IPV4_ADDR_SAME(&mac
->fwd_info
.r_vtep_ip
, &vtep_ip
)
2039 || memcmp(old_esi
, esi
, sizeof(esi_t
)) || seq
!= mac
->rem_seq
)
2044 mac
= zebra_evpn_mac_add(zevpn
, macaddr
);
2045 zebra_evpn_es_mac_ref(mac
, esi
);
2047 /* Is this MAC created for a MACIP? */
2049 SET_FLAG(mac
->flags
, ZEBRA_MAC_AUTO
);
2051 /* When host moves but changes its (MAC,IP)
2052 * binding, BGP may install a MACIP entry that
2053 * corresponds to "older" location of the host
2054 * in transient situations (because {IP1,M1}
2055 * is a different route from {IP1,M2}). Check
2056 * the sequence number and ignore this update
2059 if (!zebra_evpn_mac_is_bgp_seq_ok(
2060 zevpn
, mac
, seq
, ipa_len
, ipaddr
, false))
2063 old_es_present
= !!mac
->es
;
2064 zebra_evpn_es_mac_ref(mac
, esi
);
2065 new_es_present
= !!mac
->es
;
2066 /* XXX - dataplane is curently not able to handle a MAC
2067 * replace if the destination changes from L2-NHG to
2068 * single VTEP and vice-versa. So delete the old entry
2071 if (old_es_present
!= new_es_present
)
2072 zebra_evpn_rem_mac_uninstall(zevpn
, mac
, false);
2075 /* Check MAC's curent state is local (this is the case
2076 * where MAC has moved from L->R) and check previous
2077 * detection started via local learning.
2078 * RFC-7432: A PE/VTEP that detects a MAC mobility
2079 * event via local learning starts an M-second timer.
2081 * VTEP-IP or seq. change alone is not considered
2082 * for dup. detection.
2084 * MAC is already marked duplicate set dad, then
2085 * is_dup_detect will be set to not install the entry.
2087 if ((!CHECK_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE
)
2089 || CHECK_FLAG(mac
->flags
, ZEBRA_MAC_DUPLICATE
))
2092 /* Remove local MAC from BGP. */
2093 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
)) {
2094 /* force drop the sync flags */
2095 old_static
= zebra_evpn_mac_is_static(mac
);
2096 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
) {
2097 char mac_buf
[MAC_BUF_SIZE
];
2100 "sync-mac->remote vni %u mac %pEA es %s seq %d f %s",
2101 zevpn
->vni
, macaddr
,
2102 mac
->es
? mac
->es
->esi_str
: "-",
2104 zebra_evpn_zebra_mac_flag_dump(
2105 mac
, mac_buf
, sizeof(mac_buf
)));
2108 zebra_evpn_mac_clear_sync_info(mac
);
2109 zebra_evpn_mac_send_del_to_client(zevpn
->vni
, macaddr
,
2114 /* Set "auto" and "remote" forwarding info. */
2115 zebra_evpn_mac_clear_fwd_info(mac
);
2116 UNSET_FLAG(mac
->flags
, ZEBRA_MAC_ALL_LOCAL_FLAGS
);
2117 SET_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE
);
2118 mac
->fwd_info
.r_vtep_ip
= vtep_ip
;
2121 SET_FLAG(mac
->flags
, ZEBRA_MAC_STICKY
);
2123 UNSET_FLAG(mac
->flags
, ZEBRA_MAC_STICKY
);
2126 SET_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE_DEF_GW
);
2128 UNSET_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE_DEF_GW
);
2130 zebra_evpn_dup_addr_detect_for_mac(
2131 zvrf
, mac
, mac
->fwd_info
.r_vtep_ip
, do_dad
,
2132 &is_dup_detect
, false);
2134 if (!is_dup_detect
) {
2135 zebra_evpn_process_neigh_on_remote_mac_add(zevpn
, mac
);
2136 /* Install the entry. */
2137 zebra_evpn_rem_mac_install(zevpn
, mac
, old_static
);
2141 /* Update seq number. */
2144 /* If there is no IP, return after clearing AUTO flag of MAC. */
2146 UNSET_FLAG(mac
->flags
, ZEBRA_MAC_AUTO
);
2153 int zebra_evpn_add_update_local_mac(struct zebra_vrf
*zvrf
,
2154 struct zebra_evpn
*zevpn
,
2155 struct interface
*ifp
,
2156 const struct ethaddr
*macaddr
, vlanid_t vid
,
2157 bool sticky
, bool local_inactive
,
2158 bool dp_static
, struct zebra_mac
*mac
)
2160 bool mac_sticky
= false;
2161 bool inform_client
= false;
2162 bool upd_neigh
= false;
2163 bool is_dup_detect
= false;
2164 struct in_addr vtep_ip
= {.s_addr
= 0};
2165 bool es_change
= false;
2167 /* assume inactive if not present or if not local */
2168 bool old_local_inactive
= true;
2169 bool old_bgp_ready
= false;
2170 bool inform_dataplane
= false;
2171 bool new_static
= false;
2174 /* Check if we need to create or update or it is a NO-OP. */
2176 mac
= zebra_evpn_mac_lookup(zevpn
, macaddr
);
2178 if (IS_ZEBRA_DEBUG_VXLAN
|| IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
2180 "ADD %sMAC %pEA intf %s(%u) VID %u -> VNI %u%s",
2181 sticky
? "sticky " : "", macaddr
,
2182 ifp
->name
, ifp
->ifindex
, vid
, zevpn
->vni
,
2183 local_inactive
? " local-inactive" : "");
2185 mac
= zebra_evpn_mac_add(zevpn
, macaddr
);
2186 SET_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
);
2187 es_change
= zebra_evpn_local_mac_update_fwd_info(mac
, ifp
, vid
);
2189 SET_FLAG(mac
->flags
, ZEBRA_MAC_STICKY
);
2190 inform_client
= true;
2192 if (IS_ZEBRA_DEBUG_VXLAN
|| IS_ZEBRA_DEBUG_EVPN_MH_MAC
) {
2193 char mac_buf
[MAC_BUF_SIZE
];
2196 "UPD %sMAC %pEA intf %s(%u) VID %u -> VNI %u %scurFlags %s",
2197 sticky
? "sticky " : "", macaddr
,
2198 ifp
->name
, ifp
->ifindex
, vid
, zevpn
->vni
,
2199 local_inactive
? "local-inactive " : "",
2200 zebra_evpn_zebra_mac_flag_dump(
2201 mac
, mac_buf
, sizeof(mac_buf
)));
2204 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
)) {
2205 struct interface
*old_ifp
;
2209 zebra_evpn_mac_get_access_info(mac
, &old_ifp
, &old_vid
);
2211 zebra_evpn_mac_is_ready_for_bgp(mac
->flags
);
2212 old_local_inactive
=
2213 !!(mac
->flags
& ZEBRA_MAC_LOCAL_INACTIVE
);
2214 old_static
= zebra_evpn_mac_is_static(mac
);
2215 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_STICKY
))
2217 es_change
= zebra_evpn_local_mac_update_fwd_info(
2221 * Update any changes and if changes are relevant to
2224 if (mac_sticky
== sticky
&& old_ifp
== ifp
2226 && old_local_inactive
== local_inactive
2227 && dp_static
== old_static
&& !es_change
) {
2228 if (IS_ZEBRA_DEBUG_VXLAN
)
2230 " Add/Update %sMAC %pEA intf %s(%u) VID %u -> VNI %u%s, "
2231 "entry exists and has not changed ",
2232 sticky
? "sticky " : "",
2234 ifp
->ifindex
, vid
, zevpn
->vni
,
2240 if (mac_sticky
!= sticky
) {
2242 SET_FLAG(mac
->flags
, ZEBRA_MAC_STICKY
);
2244 UNSET_FLAG(mac
->flags
,
2246 inform_client
= true;
2249 /* If an es_change is detected we need to advertise
2250 * the route with a sequence that is one
2251 * greater. This is need to indicate a mac-move
2255 /* update the sequence number only if the entry
2258 if (!local_inactive
)
2259 mac
->loc_seq
= mac
->loc_seq
+ 1;
2260 /* force drop the peer/sync info as it is
2261 * simply no longer relevant
2263 if (CHECK_FLAG(mac
->flags
,
2264 ZEBRA_MAC_ALL_PEER_FLAGS
)) {
2265 zebra_evpn_mac_clear_sync_info(mac
);
2267 zebra_evpn_mac_is_static(mac
);
2268 /* if we clear peer-flags we
2269 * also need to notify the dataplane
2270 * to drop the static flag
2272 if (old_static
!= new_static
)
2273 inform_dataplane
= true;
2276 } else if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE
)
2277 || CHECK_FLAG(mac
->flags
, ZEBRA_MAC_AUTO
)) {
2278 bool do_dad
= false;
2281 * MAC has either moved or was "internally" created due
2282 * to a neighbor learn and is now actually learnt. If
2283 * it was learnt as a remote sticky MAC, this is an
2286 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_STICKY
)) {
2288 EC_ZEBRA_STICKY_MAC_ALREADY_LEARNT
,
2289 "MAC %pEA already learnt as remote sticky MAC behind VTEP %pI4 VNI %u",
2291 &mac
->fwd_info
.r_vtep_ip
,
2296 /* If an actual move, compute MAC's seq number */
2297 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE
)) {
2299 MAX(mac
->rem_seq
+ 1, mac
->loc_seq
);
2300 vtep_ip
= mac
->fwd_info
.r_vtep_ip
;
2301 /* Trigger DAD for remote MAC */
2305 UNSET_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE
);
2306 UNSET_FLAG(mac
->flags
, ZEBRA_MAC_AUTO
);
2307 SET_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
);
2308 es_change
= zebra_evpn_local_mac_update_fwd_info(
2311 SET_FLAG(mac
->flags
, ZEBRA_MAC_STICKY
);
2313 UNSET_FLAG(mac
->flags
, ZEBRA_MAC_STICKY
);
2315 * We have to inform BGP of this MAC as well as process
2318 inform_client
= true;
2321 zebra_evpn_dup_addr_detect_for_mac(
2322 zvrf
, mac
, vtep_ip
, do_dad
, &is_dup_detect
,
2324 if (is_dup_detect
) {
2325 inform_client
= false;
2332 /* if the dataplane thinks the entry is sync but it is
2333 * not sync in zebra (or vice-versa) we need to re-install
2336 new_static
= zebra_evpn_mac_is_static(mac
);
2337 if (dp_static
!= new_static
)
2338 inform_dataplane
= true;
2341 SET_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL_INACTIVE
);
2343 UNSET_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL_INACTIVE
);
2345 new_bgp_ready
= zebra_evpn_mac_is_ready_for_bgp(mac
->flags
);
2346 /* if local-activity has changed we need update bgp
2347 * even if bgp already knows about the mac
2349 if ((old_local_inactive
!= local_inactive
)
2350 || (new_bgp_ready
!= old_bgp_ready
)) {
2351 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
) {
2352 char mac_buf
[MAC_BUF_SIZE
];
2355 "local mac vni %u mac %pEA es %s seq %d f %s%s",
2356 zevpn
->vni
, macaddr
,
2357 mac
->es
? mac
->es
->esi_str
: "", mac
->loc_seq
,
2358 zebra_evpn_zebra_mac_flag_dump(mac
, mac_buf
,
2360 local_inactive
? "local-inactive" : "");
2364 inform_client
= true;
2368 inform_client
= true;
2372 /* Inform dataplane if required. */
2373 if (inform_dataplane
)
2374 zebra_evpn_sync_mac_dp_install(mac
, false /* set_inactive */,
2375 false /* force_clear_static */,
2378 /* Inform BGP if required. */
2380 zebra_evpn_mac_send_add_del_to_client(mac
, old_bgp_ready
,
2383 /* Process all neighbors associated with this MAC, if required. */
2385 zebra_evpn_process_neigh_on_local_mac_change(zevpn
, mac
, 0,
2391 int zebra_evpn_del_local_mac(struct zebra_evpn
*zevpn
, struct zebra_mac
*mac
,
2397 if (IS_ZEBRA_DEBUG_VXLAN
)
2398 zlog_debug("DEL MAC %pEA VNI %u seq %u flags 0x%x nbr count %u",
2399 &mac
->macaddr
, zevpn
->vni
, mac
->loc_seq
, mac
->flags
,
2400 listcount(mac
->neigh_list
));
2402 old_bgp_ready
= zebra_evpn_mac_is_ready_for_bgp(mac
->flags
);
2403 if (!clear_static
&& zebra_evpn_mac_is_static(mac
)) {
2404 /* this is a synced entry and can only be removed when the
2405 * es-peers stop advertising it.
2407 zebra_evpn_mac_clear_fwd_info(mac
);
2409 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
) {
2410 char mac_buf
[MAC_BUF_SIZE
];
2413 "re-add sync-mac vni %u mac %pEA es %s seq %d f %s",
2414 zevpn
->vni
, &mac
->macaddr
,
2415 mac
->es
? mac
->es
->esi_str
: "-", mac
->loc_seq
,
2416 zebra_evpn_zebra_mac_flag_dump(
2417 mac
, mac_buf
, sizeof(mac_buf
)));
2420 /* inform-bgp about change in local-activity if any */
2421 if (!CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL_INACTIVE
)) {
2422 SET_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL_INACTIVE
);
2424 zebra_evpn_mac_is_ready_for_bgp(mac
->flags
);
2425 zebra_evpn_mac_send_add_del_to_client(
2426 mac
, old_bgp_ready
, new_bgp_ready
);
2429 /* re-install the inactive entry in the kernel */
2430 zebra_evpn_sync_mac_dp_install(mac
, true /* set_inactive */,
2431 false /* force_clear_static */,
2437 /* flush the peer info */
2438 zebra_evpn_mac_clear_sync_info(mac
);
2440 /* Update all the neigh entries associated with this mac */
2441 zebra_evpn_process_neigh_on_local_mac_del(zevpn
, mac
);
2443 /* Remove MAC from BGP. */
2444 zebra_evpn_mac_send_del_to_client(zevpn
->vni
, &mac
->macaddr
, mac
->flags
,
2447 zebra_evpn_es_mac_deref_entry(mac
);
2449 /* remove links to the destination access port */
2450 zebra_evpn_mac_clear_fwd_info(mac
);
2453 * If there are no neigh associated with the mac delete the mac
2454 * else mark it as AUTO for forward reference
2456 if (!listcount(mac
->neigh_list
)) {
2457 zebra_evpn_mac_del(zevpn
, mac
);
2459 UNSET_FLAG(mac
->flags
, ZEBRA_MAC_ALL_LOCAL_FLAGS
);
2460 UNSET_FLAG(mac
->flags
, ZEBRA_MAC_STICKY
);
2461 SET_FLAG(mac
->flags
, ZEBRA_MAC_AUTO
);
2467 void zebra_evpn_mac_gw_macip_add(struct interface
*ifp
,
2468 struct zebra_evpn
*zevpn
,
2469 const struct ipaddr
*ip
,
2470 struct zebra_mac
**macp
,
2471 const struct ethaddr
*macaddr
,
2472 vlanid_t vlan_id
, bool def_gw
)
2474 struct zebra_mac
*mac
;
2475 ns_id_t local_ns_id
= NS_DEFAULT
;
2476 struct zebra_vrf
*zvrf
;
2478 zvrf
= ifp
->vrf
->info
;
2479 if (zvrf
&& zvrf
->zns
)
2480 local_ns_id
= zvrf
->zns
->ns_id
;
2483 mac
= zebra_evpn_mac_lookup(zevpn
, macaddr
);
2485 mac
= zebra_evpn_mac_add(zevpn
, macaddr
);
2490 /* Set "local" forwarding info. */
2491 zebra_evpn_mac_clear_fwd_info(mac
);
2492 SET_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
);
2493 SET_FLAG(mac
->flags
, ZEBRA_MAC_AUTO
);
2495 SET_FLAG(mac
->flags
, ZEBRA_MAC_DEF_GW
);
2497 SET_FLAG(mac
->flags
, ZEBRA_MAC_SVI
);
2498 mac
->fwd_info
.local
.ifindex
= ifp
->ifindex
;
2499 mac
->fwd_info
.local
.ns_id
= local_ns_id
;
2500 mac
->fwd_info
.local
.vid
= vlan_id
;
2503 void zebra_evpn_mac_svi_del(struct interface
*ifp
, struct zebra_evpn
*zevpn
)
2505 struct zebra_mac
*mac
;
2506 struct ethaddr macaddr
;
2509 if (!zebra_evpn_mh_do_adv_svi_mac())
2512 memcpy(&macaddr
.octet
, ifp
->hw_addr
, ETH_ALEN
);
2513 mac
= zebra_evpn_mac_lookup(zevpn
, &macaddr
);
2514 if (mac
&& CHECK_FLAG(mac
->flags
, ZEBRA_MAC_SVI
)) {
2515 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2516 zlog_debug("SVI %s mac free", ifp
->name
);
2518 old_bgp_ready
= zebra_evpn_mac_is_ready_for_bgp(mac
->flags
);
2519 UNSET_FLAG(mac
->flags
, ZEBRA_MAC_SVI
);
2520 zebra_evpn_mac_send_add_del_to_client(mac
, old_bgp_ready
,
2522 zebra_evpn_deref_ip2mac(mac
->zevpn
, mac
);
2526 void zebra_evpn_mac_svi_add(struct interface
*ifp
, struct zebra_evpn
*zevpn
)
2528 struct zebra_mac
*mac
= NULL
;
2529 struct ethaddr macaddr
;
2530 struct zebra_if
*zif
= ifp
->info
;
2534 if (!zebra_evpn_mh_do_adv_svi_mac()
2535 || !zebra_evpn_send_to_client_ok(zevpn
))
2538 memcpy(&macaddr
.octet
, ifp
->hw_addr
, ETH_ALEN
);
2541 mac
= zebra_evpn_mac_lookup(zevpn
, &macaddr
);
2542 if (mac
&& CHECK_FLAG(mac
->flags
, ZEBRA_MAC_SVI
))
2545 /* add/update mac */
2546 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2547 zlog_debug("SVI %s mac add", zif
->ifp
->name
);
2549 old_bgp_ready
= (mac
&& zebra_evpn_mac_is_ready_for_bgp(mac
->flags
))
2553 zebra_evpn_mac_gw_macip_add(ifp
, zevpn
, NULL
, &mac
, &macaddr
, 0, false);
2555 new_bgp_ready
= zebra_evpn_mac_is_ready_for_bgp(mac
->flags
);
2556 zebra_evpn_mac_send_add_del_to_client(mac
, old_bgp_ready
,