1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Zebra EVPN for VxLAN code
4 * Copyright (C) 2016, 2017 Cumulus Networks, Inc.
10 #include "interface.h"
18 #include "zebra/zserv.h"
19 #include "zebra/debug.h"
20 #include "zebra/zebra_router.h"
21 #include "zebra/zebra_errors.h"
22 #include "zebra/zebra_vrf.h"
23 #include "zebra/zebra_vxlan.h"
24 #include "zebra/zebra_vxlan_if.h"
25 #include "zebra/zebra_evpn.h"
26 #include "zebra/zebra_evpn_mh.h"
27 #include "zebra/zebra_evpn_mac.h"
28 #include "zebra/zebra_evpn_neigh.h"
30 DEFINE_MTYPE_STATIC(ZEBRA
, MAC
, "EVPN MAC");
33 * Return number of valid MACs in an EVPN's MAC hash table - all
34 * remote MACs and non-internal (auto) local MACs count.
36 uint32_t num_valid_macs(struct zebra_evpn
*zevpn
)
39 uint32_t num_macs
= 0;
41 struct hash_bucket
*hb
;
42 struct zebra_mac
*mac
;
44 hash
= zevpn
->mac_table
;
47 for (i
= 0; i
< hash
->size
; i
++) {
48 for (hb
= hash
->index
[i
]; hb
; hb
= hb
->next
) {
49 mac
= (struct zebra_mac
*)hb
->data
;
50 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE
)
51 || CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
)
52 || !CHECK_FLAG(mac
->flags
, ZEBRA_MAC_AUTO
))
60 uint32_t num_dup_detected_macs(struct zebra_evpn
*zevpn
)
63 uint32_t num_macs
= 0;
65 struct hash_bucket
*hb
;
66 struct zebra_mac
*mac
;
68 hash
= zevpn
->mac_table
;
71 for (i
= 0; i
< hash
->size
; i
++) {
72 for (hb
= hash
->index
[i
]; hb
; hb
= hb
->next
) {
73 mac
= (struct zebra_mac
*)hb
->data
;
74 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_DUPLICATE
))
82 /* Setup mac_list against the access port. This is done when a mac uses
83 * the ifp as destination for the first time
85 static void zebra_evpn_mac_ifp_new(struct zebra_if
*zif
)
87 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
88 zlog_debug("MAC list created for ifp %s (%u)", zif
->ifp
->name
,
91 zif
->mac_list
= list_new();
92 listset_app_node_mem(zif
->mac_list
);
95 /* Unlink local mac from a destination access port */
96 static void zebra_evpn_mac_ifp_unlink(struct zebra_mac
*zmac
)
99 struct interface
*ifp
= zmac
->ifp
;
104 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
105 zlog_debug("VNI %d MAC %pEA unlinked from ifp %s (%u)",
108 ifp
->name
, ifp
->ifindex
);
111 list_delete_node(zif
->mac_list
, &zmac
->ifp_listnode
);
115 /* Free up the mac_list if any as a part of the interface del/cleanup */
116 void zebra_evpn_mac_ifp_del(struct interface
*ifp
)
118 struct zebra_if
*zif
= ifp
->info
;
119 struct listnode
*node
;
120 struct zebra_mac
*zmac
;
123 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
124 zlog_debug("MAC list deleted for ifp %s (%u)",
125 zif
->ifp
->name
, zif
->ifp
->ifindex
);
127 for (ALL_LIST_ELEMENTS_RO(zif
->mac_list
, node
, zmac
)) {
128 zebra_evpn_mac_ifp_unlink(zmac
);
130 list_delete(&zif
->mac_list
);
134 /* Link local mac to destination access port. This is done only if the
135 * local mac is associated with a zero ESI i.e. single attach or lacp-bypass
138 static void zebra_evpn_mac_ifp_link(struct zebra_mac
*zmac
,
139 struct interface
*ifp
)
141 struct zebra_if
*zif
;
143 if (!CHECK_FLAG(zmac
->flags
, ZEBRA_MAC_LOCAL
))
146 /* already linked to the destination */
147 if (zmac
->ifp
== ifp
)
150 /* unlink the mac from any old destination */
152 zebra_evpn_mac_ifp_unlink(zmac
);
158 /* the interface mac_list is created on first mac link attempt */
160 zebra_evpn_mac_ifp_new(zif
);
162 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
163 zlog_debug("VNI %d MAC %pEA linked to ifp %s (%u)",
166 ifp
->name
, ifp
->ifindex
);
169 listnode_init(&zmac
->ifp_listnode
, zmac
);
170 listnode_add(zif
->mac_list
, &zmac
->ifp_listnode
);
173 /* If the mac is a local mac clear links to destination access port */
174 void zebra_evpn_mac_clear_fwd_info(struct zebra_mac
*zmac
)
176 zebra_evpn_mac_ifp_unlink(zmac
);
177 memset(&zmac
->fwd_info
, 0, sizeof(zmac
->fwd_info
));
181 * Install remote MAC into the forwarding plane.
183 int zebra_evpn_rem_mac_install(struct zebra_evpn
*zevpn
, struct zebra_mac
*mac
,
186 const struct zebra_if
*zif
, *br_zif
;
187 const struct zebra_vxlan_vni
*vni
;
189 enum zebra_dplane_result res
;
190 const struct interface
*br_ifp
;
193 struct in_addr vtep_ip
;
195 zif
= zevpn
->vxlan_if
->info
;
199 br_ifp
= zif
->brslave_info
.br_if
;
203 vni
= zebra_vxlan_if_vni_find(zif
, zevpn
->vni
);
207 sticky
= !!CHECK_FLAG(mac
->flags
,
208 (ZEBRA_MAC_STICKY
| ZEBRA_MAC_REMOTE_DEF_GW
));
210 /* If nexthop group for the FDB entry is inactive (not programmed in
211 * the dataplane) the MAC entry cannot be installed
214 if (!(mac
->es
->flags
& ZEBRA_EVPNES_NHG_ACTIVE
))
216 nhg_id
= mac
->es
->nhg_id
;
220 vtep_ip
= mac
->fwd_info
.r_vtep_ip
;
223 br_zif
= (const struct zebra_if
*)(br_ifp
->info
);
225 if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif
))
226 vid
= vni
->access_vlan
;
230 res
= dplane_rem_mac_add(zevpn
->vxlan_if
, br_ifp
, vid
, &mac
->macaddr
,
231 vni
->vni
, vtep_ip
, sticky
, nhg_id
, was_static
);
232 if (res
!= ZEBRA_DPLANE_REQUEST_FAILURE
)
239 * Uninstall remote MAC from the forwarding plane.
241 int zebra_evpn_rem_mac_uninstall(struct zebra_evpn
*zevpn
,
242 struct zebra_mac
*mac
, bool force
)
244 const struct zebra_if
*zif
, *br_zif
;
245 struct zebra_vxlan_vni
*vni
;
246 struct in_addr vtep_ip
;
247 const struct interface
*ifp
, *br_ifp
;
249 enum zebra_dplane_result res
;
251 /* If the MAC was not installed there is no need to uninstall it */
252 if (!force
&& mac
->es
&& !(mac
->es
->flags
& ZEBRA_EVPNES_NHG_ACTIVE
))
255 if (!zevpn
->vxlan_if
) {
256 if (IS_ZEBRA_DEBUG_VXLAN
)
258 "VNI %u hash %p couldn't be uninstalled - no intf",
263 zif
= zevpn
->vxlan_if
->info
;
267 br_ifp
= zif
->brslave_info
.br_if
;
271 vni
= zebra_vxlan_if_vni_find(zif
, zevpn
->vni
);
275 br_zif
= (const struct zebra_if
*)br_ifp
->info
;
277 if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif
))
278 vid
= vni
->access_vlan
;
282 ifp
= zevpn
->vxlan_if
;
283 vtep_ip
= mac
->fwd_info
.r_vtep_ip
;
285 res
= dplane_rem_mac_del(ifp
, br_ifp
, vid
, &mac
->macaddr
, vni
->vni
,
287 if (res
!= ZEBRA_DPLANE_REQUEST_FAILURE
)
294 * Decrement neighbor refcount of MAC; uninstall and free it if
297 void zebra_evpn_deref_ip2mac(struct zebra_evpn
*zevpn
, struct zebra_mac
*mac
)
299 if (!CHECK_FLAG(mac
->flags
, ZEBRA_MAC_AUTO
))
302 /* If all remote neighbors referencing a remote MAC go away,
303 * we need to uninstall the MAC.
305 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE
)
306 && remote_neigh_count(mac
) == 0) {
307 zebra_evpn_rem_mac_uninstall(zevpn
, mac
, false /*force*/);
308 zebra_evpn_es_mac_deref_entry(mac
);
309 UNSET_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE
);
312 /* If no references, delete the MAC. */
313 if (!zebra_evpn_mac_in_use(mac
))
314 zebra_evpn_mac_del(zevpn
, mac
);
317 static void zebra_evpn_mac_get_access_info(struct zebra_mac
*mac
,
318 struct interface
**p_ifp
,
321 struct zebra_vxlan_vni
*vni
;
323 /* if the mac is associated with an ES we must get the access
327 struct zebra_if
*zif
;
329 /* get the access port from the es */
330 *p_ifp
= mac
->es
->zif
? mac
->es
->zif
->ifp
: NULL
;
331 /* get the vlan from the EVPN */
332 if (mac
->zevpn
->vxlan_if
) {
333 zif
= mac
->zevpn
->vxlan_if
->info
;
334 vni
= zebra_vxlan_if_vni_find(zif
, mac
->zevpn
->vni
);
335 *vid
= vni
->access_vlan
;
340 struct zebra_ns
*zns
;
342 *vid
= mac
->fwd_info
.local
.vid
;
343 zns
= zebra_ns_lookup(mac
->fwd_info
.local
.ns_id
);
344 *p_ifp
= if_lookup_by_index_per_ns(zns
,
345 mac
->fwd_info
.local
.ifindex
);
349 #define MAC_BUF_SIZE 256
350 static char *zebra_evpn_zebra_mac_flag_dump(struct zebra_mac
*mac
, char *buf
,
353 if (mac
->flags
== 0) {
354 snprintfrr(buf
, len
, "None ");
359 buf
, len
, "%s%s%s%s%s%s%s%s%s%s%s%s",
360 CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
) ? "LOC " : "",
361 CHECK_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE
) ? "REM " : "",
362 CHECK_FLAG(mac
->flags
, ZEBRA_MAC_AUTO
) ? "AUTO " : "",
363 CHECK_FLAG(mac
->flags
, ZEBRA_MAC_STICKY
) ? "STICKY " : "",
364 CHECK_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE_RMAC
) ? "REM Router "
366 CHECK_FLAG(mac
->flags
, ZEBRA_MAC_DEF_GW
) ? "Default GW " : "",
367 CHECK_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE_DEF_GW
) ? "REM DEF GW "
369 CHECK_FLAG(mac
->flags
, ZEBRA_MAC_DUPLICATE
) ? "DUP " : "",
370 CHECK_FLAG(mac
->flags
, ZEBRA_MAC_FPM_SENT
) ? "FPM " : "",
371 CHECK_FLAG(mac
->flags
, ZEBRA_MAC_ES_PEER_ACTIVE
)
374 CHECK_FLAG(mac
->flags
, ZEBRA_MAC_ES_PEER_PROXY
) ? "PROXY " : "",
375 CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL_INACTIVE
)
381 static void zebra_evpn_dad_mac_auto_recovery_exp(struct event
*t
)
383 struct zebra_vrf
*zvrf
= NULL
;
384 struct zebra_mac
*mac
= NULL
;
385 struct zebra_evpn
*zevpn
= NULL
;
386 struct listnode
*node
= NULL
;
387 struct zebra_neigh
*nbr
= NULL
;
391 /* since this is asynchronous we need sanity checks*/
392 zvrf
= zebra_vrf_lookup_by_id(mac
->zevpn
->vrf_id
);
396 zevpn
= zebra_evpn_lookup(mac
->zevpn
->vni
);
400 mac
= zebra_evpn_mac_lookup(zevpn
, &mac
->macaddr
);
404 if (IS_ZEBRA_DEBUG_VXLAN
) {
405 char mac_buf
[MAC_BUF_SIZE
];
408 "%s: duplicate addr mac %pEA flags %slearn count %u host count %u auto recovery expired",
409 __func__
, &mac
->macaddr
,
410 zebra_evpn_zebra_mac_flag_dump(mac
, mac_buf
,
412 mac
->dad_count
, listcount(mac
->neigh_list
));
415 /* Remove all IPs as duplicate associcated with this MAC */
416 for (ALL_LIST_ELEMENTS_RO(mac
->neigh_list
, node
, nbr
)) {
417 if (CHECK_FLAG(nbr
->flags
, ZEBRA_NEIGH_DUPLICATE
)) {
418 if (CHECK_FLAG(nbr
->flags
, ZEBRA_NEIGH_LOCAL
))
419 ZEBRA_NEIGH_SET_INACTIVE(nbr
);
420 else if (CHECK_FLAG(nbr
->flags
, ZEBRA_NEIGH_REMOTE
))
421 zebra_evpn_rem_neigh_install(
422 zevpn
, nbr
, false /*was_static*/);
425 UNSET_FLAG(nbr
->flags
, ZEBRA_NEIGH_DUPLICATE
);
427 nbr
->detect_start_time
.tv_sec
= 0;
428 nbr
->dad_dup_detect_time
= 0;
431 UNSET_FLAG(mac
->flags
, ZEBRA_MAC_DUPLICATE
);
433 mac
->detect_start_time
.tv_sec
= 0;
434 mac
->detect_start_time
.tv_usec
= 0;
435 mac
->dad_dup_detect_time
= 0;
436 mac
->dad_mac_auto_recovery_timer
= NULL
;
438 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
)) {
440 if (zebra_evpn_mac_send_add_to_client(zevpn
->vni
, &mac
->macaddr
,
441 mac
->flags
, mac
->loc_seq
,
445 /* Process all neighbors associated with this MAC. */
446 zebra_evpn_process_neigh_on_local_mac_change(zevpn
, mac
, 0,
449 } else if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE
)) {
450 zebra_evpn_process_neigh_on_remote_mac_add(zevpn
, mac
);
452 /* Install the entry. */
453 zebra_evpn_rem_mac_install(zevpn
, mac
, false /* was_static */);
457 static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf
*zvrf
,
458 struct zebra_mac
*mac
,
459 struct in_addr vtep_ip
,
460 bool do_dad
, bool *is_dup_detect
,
463 struct zebra_neigh
*nbr
;
464 struct listnode
*node
= NULL
;
465 struct timeval elapsed
= {0, 0};
466 bool reset_params
= false;
468 if (!(zebra_evpn_do_dup_addr_detect(zvrf
) && do_dad
))
471 /* MAC is detected as duplicate,
472 * Local MAC event -> hold on advertising to BGP.
473 * Remote MAC event -> hold on installing it.
475 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_DUPLICATE
)) {
476 if (IS_ZEBRA_DEBUG_VXLAN
) {
477 char mac_buf
[MAC_BUF_SIZE
];
480 "%s: duplicate addr MAC %pEA flags %sskip update to client, learn count %u recover time %u",
481 __func__
, &mac
->macaddr
,
482 zebra_evpn_zebra_mac_flag_dump(mac
, mac_buf
,
484 mac
->dad_count
, zvrf
->dad_freeze_time
);
486 /* For duplicate MAC do not update
487 * client but update neigh due to
490 if (zvrf
->dad_freeze
)
491 *is_dup_detect
= true;
496 /* Check if detection time (M-secs) expired.
497 * Reset learn count and detection start time.
499 monotime_since(&mac
->detect_start_time
, &elapsed
);
500 reset_params
= (elapsed
.tv_sec
> zvrf
->dad_time
);
501 if (is_local
&& !reset_params
) {
502 /* RFC-7432: A PE/VTEP that detects a MAC mobility
503 * event via LOCAL learning starts an M-second timer.
505 * NOTE: This is the START of the probe with count is
506 * 0 during LOCAL learn event.
507 * (mac->dad_count == 0 || elapsed.tv_sec >= zvrf->dad_time)
509 reset_params
= !mac
->dad_count
;
513 if (IS_ZEBRA_DEBUG_VXLAN
) {
514 char mac_buf
[MAC_BUF_SIZE
];
517 "%s: duplicate addr MAC %pEA flags %sdetection time passed, reset learn count %u",
518 __func__
, &mac
->macaddr
,
519 zebra_evpn_zebra_mac_flag_dump(mac
, mac_buf
,
525 /* Start dup. addr detection (DAD) start time,
526 * ONLY during LOCAL learn.
529 monotime(&mac
->detect_start_time
);
531 } else if (!is_local
) {
532 /* For REMOTE MAC, increment detection count
533 * ONLY while in probe window, once window passed,
534 * next local learn event should trigger DAD.
539 /* For LOCAL MAC learn event, once count is reset above via either
540 * initial/start detection time or passed the probe time, the count
541 * needs to be incremented.
546 if (mac
->dad_count
>= zvrf
->dad_max_moves
) {
547 flog_warn(EC_ZEBRA_DUP_MAC_DETECTED
,
548 "VNI %u: MAC %pEA detected as duplicate during %s VTEP %pI4",
549 mac
->zevpn
->vni
, &mac
->macaddr
,
550 is_local
? "local update, last" :
551 "remote update, from", &vtep_ip
);
553 SET_FLAG(mac
->flags
, ZEBRA_MAC_DUPLICATE
);
555 /* Capture Duplicate detection time */
556 mac
->dad_dup_detect_time
= monotime(NULL
);
558 /* Mark all IPs/Neighs as duplicate
559 * associcated with this MAC
561 for (ALL_LIST_ELEMENTS_RO(mac
->neigh_list
, node
, nbr
)) {
563 /* Ony Mark IPs which are Local */
564 if (!CHECK_FLAG(nbr
->flags
, ZEBRA_NEIGH_LOCAL
))
567 SET_FLAG(nbr
->flags
, ZEBRA_NEIGH_DUPLICATE
);
569 nbr
->dad_dup_detect_time
= monotime(NULL
);
571 flog_warn(EC_ZEBRA_DUP_IP_INHERIT_DETECTED
,
572 "VNI %u: MAC %pEA IP %pIA detected as duplicate during %s update, inherit duplicate from MAC",
573 mac
->zevpn
->vni
, &mac
->macaddr
, &nbr
->ip
,
574 is_local
? "local" : "remote");
577 /* Start auto recovery timer for this MAC */
578 EVENT_OFF(mac
->dad_mac_auto_recovery_timer
);
579 if (zvrf
->dad_freeze
&& zvrf
->dad_freeze_time
) {
580 if (IS_ZEBRA_DEBUG_VXLAN
) {
581 char mac_buf
[MAC_BUF_SIZE
];
584 "%s: duplicate addr MAC %pEA flags %sauto recovery time %u start",
585 __func__
, &mac
->macaddr
,
586 zebra_evpn_zebra_mac_flag_dump(
587 mac
, mac_buf
, sizeof(mac_buf
)),
588 zvrf
->dad_freeze_time
);
591 event_add_timer(zrouter
.master
,
592 zebra_evpn_dad_mac_auto_recovery_exp
,
593 mac
, zvrf
->dad_freeze_time
,
594 &mac
->dad_mac_auto_recovery_timer
);
597 /* In case of local update, do not inform to client (BGPd),
598 * upd_neigh for neigh sequence change.
600 if (zvrf
->dad_freeze
)
601 *is_dup_detect
= true;
606 * Print a specific MAC entry.
608 void zebra_evpn_print_mac(struct zebra_mac
*mac
, void *ctxt
, json_object
*json
)
611 struct zebra_neigh
*n
= NULL
;
612 struct listnode
*node
= NULL
;
613 char buf1
[ETHER_ADDR_STRLEN
];
614 char buf2
[INET6_ADDRSTRLEN
];
615 struct zebra_vrf
*zvrf
;
616 struct timeval detect_start_time
= {0, 0};
617 char timebuf
[MONOTIME_STRLEN
];
618 char thread_buf
[EVENT_TIMER_STRLEN
];
620 char up_str
[MONOTIME_STRLEN
];
622 zvrf
= zebra_vrf_get_evpn();
623 vty
= (struct vty
*)ctxt
;
624 prefix_mac2str(&mac
->macaddr
, buf1
, sizeof(buf1
));
626 uptime
= monotime(NULL
);
627 uptime
-= mac
->uptime
;
629 frrtime_to_interval(uptime
, up_str
, sizeof(up_str
));
632 json_object
*json_mac
= json_object_new_object();
634 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
)) {
635 struct interface
*ifp
;
638 zebra_evpn_mac_get_access_info(mac
, &ifp
, &vid
);
639 json_object_string_add(json_mac
, "type", "local");
641 json_object_string_add(json_mac
, "intf",
643 json_object_int_add(json_mac
, "ifindex",
647 json_object_int_add(json_mac
, "vlan", vid
);
648 } else if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE
)) {
649 json_object_string_add(json_mac
, "type", "remote");
651 json_object_string_add(json_mac
, "remoteEs",
654 json_object_string_addf(
655 json_mac
, "remoteVtep", "%pI4",
656 &mac
->fwd_info
.r_vtep_ip
);
657 } else if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_AUTO
))
658 json_object_string_add(json_mac
, "type", "auto");
660 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_STICKY
))
661 json_object_boolean_true_add(json_mac
, "stickyMac");
663 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_SVI
))
664 json_object_boolean_true_add(json_mac
, "sviMac");
666 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_DEF_GW
))
667 json_object_boolean_true_add(json_mac
,
670 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE_DEF_GW
))
671 json_object_boolean_true_add(json_mac
,
674 json_object_string_add(json_mac
, "uptime", up_str
);
675 json_object_int_add(json_mac
, "localSequence", mac
->loc_seq
);
676 json_object_int_add(json_mac
, "remoteSequence", mac
->rem_seq
);
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");
682 json_object_boolean_false_add(json_mac
, "isDuplicate");
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");
693 json_object_string_add(
694 json_mac
, "peerActiveHold",
695 event_timer_to_hhmmss(thread_buf
,
699 json_object_string_add(json_mac
, "esi",
701 /* print all the associated neigh */
702 if (!listcount(mac
->neigh_list
))
703 json_object_string_add(json_mac
, "neighbors", "none");
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();
710 for (ALL_LIST_ELEMENTS_RO(mac
->neigh_list
, node
, n
)) {
711 if (IS_ZEBRA_NEIGH_ACTIVE(n
))
712 json_object_array_add(
714 json_object_new_string(
719 json_object_array_add(
721 json_object_new_string(
727 json_object_object_add(json_nbrs
, "active",
729 json_object_object_add(json_nbrs
, "inactive",
731 json_object_object_add(json_mac
, "neighbors",
735 json_object_object_add(json
, buf1
, json_mac
);
737 vty_out(vty
, "MAC: %s\n", buf1
);
739 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
)) {
740 struct interface
*ifp
;
743 zebra_evpn_mac_get_access_info(mac
, &ifp
, &vid
);
746 vty_out(vty
, " ESI: %s\n", mac
->es
->esi_str
);
749 vty_out(vty
, " Intf: %s(%u)", ifp
->name
,
752 vty_out(vty
, " Intf: -");
753 vty_out(vty
, " VLAN: %u", vid
);
754 } else if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE
)) {
756 vty_out(vty
, " Remote ES: %s",
759 vty_out(vty
, " Remote VTEP: %pI4",
760 &mac
->fwd_info
.r_vtep_ip
);
761 } else if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_AUTO
)) {
762 vty_out(vty
, " Auto Mac ");
765 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_STICKY
))
766 vty_out(vty
, " Sticky Mac ");
768 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_SVI
))
769 vty_out(vty
, " SVI-Mac ");
771 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_DEF_GW
))
772 vty_out(vty
, " Default-gateway Mac ");
774 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE_DEF_GW
))
775 vty_out(vty
, " Remote-gateway Mac ");
778 vty_out(vty
, " Sync-info: neigh#: %u", mac
->sync_neigh_cnt
);
779 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL_INACTIVE
))
780 vty_out(vty
, " local-inactive");
781 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_ES_PEER_PROXY
))
782 vty_out(vty
, " peer-proxy");
783 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_ES_PEER_ACTIVE
))
784 vty_out(vty
, " peer-active");
786 vty_out(vty
, " (ht: %s)",
787 event_timer_to_hhmmss(thread_buf
,
791 vty_out(vty
, " Local Seq: %u Remote Seq: %u\n", mac
->loc_seq
,
793 vty_out(vty
, " Uptime: %s\n", up_str
);
795 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_DUPLICATE
)) {
796 vty_out(vty
, " Duplicate, detected at %s",
797 time_to_string(mac
->dad_dup_detect_time
,
799 } else if (mac
->dad_count
) {
800 monotime_since(&mac
->detect_start_time
,
802 if (detect_start_time
.tv_sec
<= zvrf
->dad_time
) {
803 time_to_string(mac
->detect_start_time
.tv_sec
,
806 " Duplicate detection started at %s, detection count %u\n",
807 timebuf
, mac
->dad_count
);
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");
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
)
829 static char *zebra_evpn_print_mac_flags(struct zebra_mac
*mac
, char *flags_buf
,
832 snprintf(flags_buf
, flags_buf_sz
, "%s%s%s%s",
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" : "");
842 * Print MAC hash entry - called for display of all MACs.
844 void zebra_evpn_print_mac_hash(struct hash_bucket
*bucket
, void *ctxt
)
847 json_object
*json_mac_hdr
= NULL
, *json_mac
= NULL
;
848 struct zebra_mac
*mac
;
849 char buf1
[ETHER_ADDR_STRLEN
];
850 char addr_buf
[PREFIX_STRLEN
];
851 struct mac_walk_ctx
*wctx
= ctxt
;
855 json_mac_hdr
= wctx
->json
;
856 mac
= (struct zebra_mac
*)bucket
->data
;
858 prefix_mac2str(&mac
->macaddr
, buf1
, sizeof(buf1
));
861 json_mac
= json_object_new_object();
863 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
)) {
864 struct interface
*ifp
;
867 if (wctx
->flags
& SHOW_REMOTE_MAC_FROM_VTEP
)
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
,
875 ifp
? ifp
->name
: "-");
877 json_object_string_add(json_mac
, "type", "local");
879 json_object_string_add(json_mac
, "intf",
883 if (json_mac_hdr
== NULL
)
884 vty_out(vty
, " %-5u", vid
);
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
);
894 json_object_int_add(json_mac
, "localSequence",
896 json_object_int_add(json_mac
, "remoteSequence",
898 json_object_int_add(json_mac
, "detectionCount",
900 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_DUPLICATE
))
901 json_object_boolean_true_add(json_mac
,
904 json_object_boolean_false_add(json_mac
,
906 json_object_object_add(json_mac_hdr
, buf1
, json_mac
);
911 } else if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE
)) {
913 if ((wctx
->flags
& SHOW_REMOTE_MAC_FROM_VTEP
)
914 && !IPV4_ADDR_SAME(&mac
->fwd_info
.r_vtep_ip
,
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",
928 inet_ntop(AF_INET
, &mac
->fwd_info
.r_vtep_ip
,
929 addr_buf
, sizeof(addr_buf
));
931 vty_out(vty
, "%-17s %-6s %-5s %-30s %-5s %u/%u\n", buf1
,
933 zebra_evpn_print_mac_flags(mac
, flags_buf
,
935 mac
->es
? mac
->es
->esi_str
: addr_buf
,
936 "", mac
->loc_seq
, mac
->rem_seq
);
938 json_object_string_add(json_mac
, "type", "remote");
940 json_object_string_add(json_mac
, "remoteEs",
943 json_object_string_addf(
944 json_mac
, "remoteVtep", "%pI4",
945 &mac
->fwd_info
.r_vtep_ip
);
946 json_object_object_add(json_mac_hdr
, buf1
, json_mac
);
947 json_object_int_add(json_mac
, "localSequence",
949 json_object_int_add(json_mac
, "remoteSequence",
951 json_object_int_add(json_mac
, "detectionCount",
953 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_DUPLICATE
))
954 json_object_boolean_true_add(json_mac
,
957 json_object_boolean_false_add(json_mac
,
966 * Print MAC hash entry in detail - called for display of all MACs.
968 void zebra_evpn_print_mac_hash_detail(struct hash_bucket
*bucket
, void *ctxt
)
971 json_object
*json_mac_hdr
= NULL
;
972 struct zebra_mac
*mac
;
973 struct mac_walk_ctx
*wctx
= ctxt
;
974 char buf1
[ETHER_ADDR_STRLEN
];
977 json_mac_hdr
= wctx
->json
;
978 mac
= (struct zebra_mac
*)bucket
->data
;
983 prefix_mac2str(&mac
->macaddr
, buf1
, sizeof(buf1
));
985 zebra_evpn_print_mac(mac
, vty
, json_mac_hdr
);
989 * Inform BGP about local MACIP.
991 int zebra_evpn_macip_send_msg_to_client(vni_t vni
,
992 const struct ethaddr
*macaddr
,
993 const struct ipaddr
*ip
, uint8_t flags
,
994 uint32_t seq
, int state
,
995 struct zebra_evpn_es
*es
, uint16_t cmd
)
998 struct zserv
*client
= NULL
;
999 struct stream
*s
= NULL
;
1000 esi_t
*esi
= es
? &es
->esi
: zero_esi
;
1002 client
= zserv_find_client(ZEBRA_ROUTE_BGP
, 0);
1003 /* BGP may not be running. */
1007 s
= stream_new(ZEBRA_MAX_PACKET_SIZ
);
1009 zclient_create_header(s
, cmd
, zebra_vrf_get_evpn_id());
1010 stream_putl(s
, vni
);
1011 stream_put(s
, macaddr
->octet
, ETH_ALEN
);
1014 if (IS_IPADDR_V4(ip
))
1015 ipa_len
= IPV4_MAX_BYTELEN
;
1016 else if (IS_IPADDR_V6(ip
))
1017 ipa_len
= IPV6_MAX_BYTELEN
;
1019 stream_putl(s
, ipa_len
); /* IP address length */
1021 stream_put(s
, &ip
->ip
.addr
, ipa_len
); /* IP address */
1023 stream_putl(s
, 0); /* Just MAC. */
1025 if (cmd
== ZEBRA_MACIP_ADD
) {
1026 stream_putc(s
, flags
); /* sticky mac/gateway mac */
1027 stream_putl(s
, seq
); /* sequence number */
1028 stream_put(s
, esi
, sizeof(esi_t
));
1030 stream_putl(s
, state
); /* state - active/inactive */
1034 /* Write packet size. */
1035 stream_putw_at(s
, 0, stream_get_endp(s
));
1037 if (IS_ZEBRA_DEBUG_VXLAN
) {
1038 char flag_buf
[MACIP_BUF_SIZE
];
1041 "Send MACIP %s f %s state %u MAC %pEA IP %pIA seq %u L2-VNI %u ESI %s to %s",
1042 (cmd
== ZEBRA_MACIP_ADD
) ? "Add" : "Del",
1043 zclient_evpn_dump_macip_flags(flags
, flag_buf
,
1045 state
, macaddr
, ip
, seq
, vni
, es
? es
->esi_str
: "-",
1046 zebra_route_string(client
->proto
));
1049 if (cmd
== ZEBRA_MACIP_ADD
)
1050 client
->macipadd_cnt
++;
1052 client
->macipdel_cnt
++;
1054 return zserv_send_message(client
, s
);
1057 static unsigned int mac_hash_keymake(const void *p
)
1059 const struct zebra_mac
*pmac
= p
;
1060 const void *pnt
= (void *)pmac
->macaddr
.octet
;
1062 return jhash(pnt
, ETH_ALEN
, 0xa5a5a55a);
1066 * Compare two MAC addresses.
1068 static bool mac_cmp(const void *p1
, const void *p2
)
1070 const struct zebra_mac
*pmac1
= p1
;
1071 const struct zebra_mac
*pmac2
= p2
;
1073 if (pmac1
== NULL
&& pmac2
== NULL
)
1076 if (pmac1
== NULL
|| pmac2
== NULL
)
1079 return (memcmp(pmac1
->macaddr
.octet
, pmac2
->macaddr
.octet
, ETH_ALEN
)
1084 * Callback to allocate MAC hash entry.
1086 static void *zebra_evpn_mac_alloc(void *p
)
1088 const struct zebra_mac
*tmp_mac
= p
;
1089 struct zebra_mac
*mac
;
1091 mac
= XCALLOC(MTYPE_MAC
, sizeof(struct zebra_mac
));
1094 return ((void *)mac
);
1100 struct zebra_mac
*zebra_evpn_mac_add(struct zebra_evpn
*zevpn
,
1101 const struct ethaddr
*macaddr
)
1103 struct zebra_mac tmp_mac
;
1104 struct zebra_mac
*mac
= NULL
;
1106 memset(&tmp_mac
, 0, sizeof(tmp_mac
));
1107 memcpy(&tmp_mac
.macaddr
, macaddr
, ETH_ALEN
);
1108 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 EVENT_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
);
1186 * Add Auto MAC entry.
1188 struct zebra_mac
*zebra_evpn_mac_add_auto(struct zebra_evpn
*zevpn
,
1189 const struct ethaddr
*macaddr
)
1191 struct zebra_mac
*mac
;
1193 mac
= zebra_evpn_mac_add(zevpn
, macaddr
);
1197 zebra_evpn_mac_clear_fwd_info(mac
);
1198 memset(&mac
->flags
, 0, sizeof(uint32_t));
1199 SET_FLAG(mac
->flags
, ZEBRA_MAC_AUTO
);
1204 static bool zebra_evpn_check_mac_del_from_db(struct mac_walk_ctx
*wctx
,
1205 struct zebra_mac
*mac
)
1207 if ((wctx
->flags
& DEL_LOCAL_MAC
) && (mac
->flags
& ZEBRA_MAC_LOCAL
))
1209 else if ((wctx
->flags
& DEL_REMOTE_MAC
)
1210 && (mac
->flags
& ZEBRA_MAC_REMOTE
))
1212 else if ((wctx
->flags
& DEL_REMOTE_MAC_FROM_VTEP
)
1213 && (mac
->flags
& ZEBRA_MAC_REMOTE
)
1214 && IPV4_ADDR_SAME(&mac
->fwd_info
.r_vtep_ip
, &wctx
->r_vtep_ip
))
1216 else if ((wctx
->flags
& DEL_LOCAL_MAC
) && (mac
->flags
& ZEBRA_MAC_AUTO
)
1217 && !listcount(mac
->neigh_list
)) {
1218 if (IS_ZEBRA_DEBUG_VXLAN
) {
1219 char mac_buf
[MAC_BUF_SIZE
];
1222 "%s: Del MAC %pEA flags %s", __func__
,
1224 zebra_evpn_zebra_mac_flag_dump(
1225 mac
, mac_buf
, sizeof(mac_buf
)));
1227 wctx
->uninstall
= 0;
1236 * Free MAC hash entry (callback)
1238 static void zebra_evpn_mac_del_hash_entry(struct hash_bucket
*bucket
, void *arg
)
1240 struct mac_walk_ctx
*wctx
= arg
;
1241 struct zebra_mac
*mac
= bucket
->data
;
1243 if (zebra_evpn_check_mac_del_from_db(wctx
, mac
)) {
1244 if (wctx
->upd_client
&& (mac
->flags
& ZEBRA_MAC_LOCAL
)) {
1245 zebra_evpn_mac_send_del_to_client(wctx
->zevpn
->vni
,
1249 if (wctx
->uninstall
) {
1250 if (zebra_evpn_mac_is_static(mac
))
1251 zebra_evpn_sync_mac_dp_install(
1252 mac
, false /* set_inactive */,
1253 true /* force_clear_static */,
1256 if (mac
->flags
& ZEBRA_MAC_REMOTE
)
1257 zebra_evpn_rem_mac_uninstall(wctx
->zevpn
, mac
,
1261 zebra_evpn_mac_del(wctx
->zevpn
, mac
);
1268 * Delete all MAC entries for this EVPN.
1270 void zebra_evpn_mac_del_all(struct zebra_evpn
*zevpn
, int uninstall
,
1271 int upd_client
, uint32_t flags
)
1273 struct mac_walk_ctx wctx
;
1275 if (!zevpn
->mac_table
)
1278 memset(&wctx
, 0, sizeof(wctx
));
1280 wctx
.uninstall
= uninstall
;
1281 wctx
.upd_client
= upd_client
;
1284 hash_iterate(zevpn
->mac_table
, zebra_evpn_mac_del_hash_entry
, &wctx
);
1288 * Look up MAC hash entry.
1290 struct zebra_mac
*zebra_evpn_mac_lookup(struct zebra_evpn
*zevpn
,
1291 const struct ethaddr
*mac
)
1293 struct zebra_mac tmp
;
1294 struct zebra_mac
*pmac
;
1296 memset(&tmp
, 0, sizeof(tmp
));
1297 memcpy(&tmp
.macaddr
, mac
, ETH_ALEN
);
1298 pmac
= hash_lookup(zevpn
->mac_table
, &tmp
);
1304 * Inform BGP about local MAC addition.
1306 int zebra_evpn_mac_send_add_to_client(vni_t vni
, const struct ethaddr
*macaddr
,
1307 uint32_t mac_flags
, uint32_t seq
,
1308 struct zebra_evpn_es
*es
)
1312 if (CHECK_FLAG(mac_flags
, ZEBRA_MAC_LOCAL_INACTIVE
)) {
1313 /* host reachability has not been verified locally */
1315 /* if no ES peer is claiming reachability we can't advertise the
1318 if (!CHECK_FLAG(mac_flags
, ZEBRA_MAC_ES_PEER_ACTIVE
))
1321 /* ES peers are claiming reachability; we will
1322 * advertise the entry but with a proxy flag
1324 SET_FLAG(flags
, ZEBRA_MACIP_TYPE_PROXY_ADVERT
);
1327 if (CHECK_FLAG(mac_flags
, ZEBRA_MAC_STICKY
))
1328 SET_FLAG(flags
, ZEBRA_MACIP_TYPE_STICKY
);
1329 if (CHECK_FLAG(mac_flags
, ZEBRA_MAC_DEF_GW
))
1330 SET_FLAG(flags
, ZEBRA_MACIP_TYPE_GW
);
1332 return zebra_evpn_macip_send_msg_to_client(vni
, macaddr
, NULL
, flags
,
1333 seq
, ZEBRA_NEIGH_ACTIVE
, es
,
1338 * Inform BGP about local MAC deletion.
1340 int zebra_evpn_mac_send_del_to_client(vni_t vni
, const struct ethaddr
*macaddr
,
1341 uint32_t flags
, bool force
)
1343 int state
= ZEBRA_NEIGH_ACTIVE
;
1346 if (CHECK_FLAG(flags
, ZEBRA_MAC_LOCAL_INACTIVE
)
1347 && !CHECK_FLAG(flags
, ZEBRA_MAC_ES_PEER_ACTIVE
))
1348 /* the host was not advertised - nothing to delete */
1351 /* MAC is LOCAL and DUP_DETECTED, this local mobility event
1352 * is not known to bgpd. Upon receiving local delete
1353 * ask bgp to reinstall the best route (remote entry).
1355 if (CHECK_FLAG(flags
, ZEBRA_MAC_LOCAL
) &&
1356 CHECK_FLAG(flags
, ZEBRA_MAC_DUPLICATE
))
1357 state
= ZEBRA_NEIGH_INACTIVE
;
1360 return zebra_evpn_macip_send_msg_to_client(
1361 vni
, macaddr
, NULL
, 0 /* flags */, 0 /* seq */, state
, NULL
,
1366 * wrapper to create a MAC hash table
1368 struct hash
*zebra_mac_db_create(const char *desc
)
1370 return hash_create_size(8, mac_hash_keymake
, mac_cmp
, desc
);
1373 /* program sync mac flags in the dataplane */
1374 int zebra_evpn_sync_mac_dp_install(struct zebra_mac
*mac
, bool set_inactive
,
1375 bool force_clear_static
, const char *caller
)
1377 struct interface
*ifp
;
1380 struct zebra_evpn
*zevpn
= mac
->zevpn
;
1382 struct zebra_if
*zif
;
1383 struct interface
*br_ifp
;
1385 /* If the ES-EVI doesn't exist defer install. When the ES-EVI is
1386 * created we will attempt to install the mac entry again
1389 struct zebra_evpn_es_evi
*es_evi
;
1391 es_evi
= zebra_evpn_es_evi_find(mac
->es
, mac
->zevpn
);
1393 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
1395 "%s: dp-install sync-mac vni %u mac %pEA es %s 0x%x %sskipped, no es-evi",
1396 caller
, zevpn
->vni
, &mac
->macaddr
,
1397 mac
->es
? mac
->es
->esi_str
: "-",
1399 set_inactive
? "inactive " : "");
1404 /* get the access vlan from the vxlan_device */
1405 zebra_evpn_mac_get_access_info(mac
, &ifp
, &vid
);
1408 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
) {
1409 char mac_buf
[MAC_BUF_SIZE
];
1412 "%s: dp-install sync-mac vni %u mac %pEA es %s %s%sskipped, no access-port",
1413 caller
, zevpn
->vni
, &mac
->macaddr
,
1414 mac
->es
? mac
->es
->esi_str
: "-",
1415 zebra_evpn_zebra_mac_flag_dump(mac
, mac_buf
,
1417 set_inactive
? "inactive " : "");
1423 br_ifp
= zif
->brslave_info
.br_if
;
1425 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
) {
1426 char mac_buf
[MAC_BUF_SIZE
];
1429 "%s: dp-install sync-mac vni %u mac %pEA es %s %s%sskipped, no br",
1430 caller
, zevpn
->vni
, &mac
->macaddr
,
1431 mac
->es
? mac
->es
->esi_str
: "-",
1432 zebra_evpn_zebra_mac_flag_dump(mac
, mac_buf
,
1434 set_inactive
? "inactive " : "");
1439 sticky
= !!CHECK_FLAG(mac
->flags
, ZEBRA_MAC_STICKY
);
1440 if (force_clear_static
)
1443 set_static
= zebra_evpn_mac_is_static(mac
);
1445 /* We can install a local mac that has been synced from the peer
1446 * over the VxLAN-overlay/network-port if fast failover is not
1447 * supported and if the local ES is oper-down.
1449 if (mac
->es
&& zebra_evpn_es_local_mac_via_network_port(mac
->es
)) {
1450 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
) {
1451 char mac_buf
[MAC_BUF_SIZE
];
1454 "dp-%s sync-nw-mac vni %u mac %pEA es %s %s%s",
1455 set_static
? "install" : "uninstall",
1456 zevpn
->vni
, &mac
->macaddr
,
1457 mac
->es
? mac
->es
->esi_str
: "-",
1458 zebra_evpn_zebra_mac_flag_dump(mac
, mac_buf
,
1460 set_inactive
? "inactive " : "");
1463 /* XXX - old_static needs to be computed more
1466 zebra_evpn_rem_mac_install(zevpn
, mac
,
1467 true /* old_static */);
1469 zebra_evpn_rem_mac_uninstall(zevpn
, mac
,
1475 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
) {
1476 char mac_buf
[MAC_BUF_SIZE
];
1478 zlog_debug("dp-install sync-mac vni %u mac %pEA es %s %s%s%s",
1479 zevpn
->vni
, &mac
->macaddr
,
1480 mac
->es
? mac
->es
->esi_str
: "-",
1481 zebra_evpn_zebra_mac_flag_dump(mac
, mac_buf
,
1483 set_static
? "static " : "",
1484 set_inactive
? "inactive " : "");
1487 dplane_local_mac_add(ifp
, br_ifp
, vid
, &mac
->macaddr
, sticky
,
1488 set_static
, set_inactive
);
1492 void zebra_evpn_mac_send_add_del_to_client(struct zebra_mac
*mac
,
1497 zebra_evpn_mac_send_add_to_client(mac
->zevpn
->vni
,
1498 &mac
->macaddr
, mac
->flags
,
1499 mac
->loc_seq
, mac
->es
);
1500 else if (old_bgp_ready
)
1501 zebra_evpn_mac_send_del_to_client(mac
->zevpn
->vni
,
1502 &mac
->macaddr
, mac
->flags
,
1506 /* MAC hold timer is used to age out peer-active flag.
1508 * During this wait time we expect the dataplane component or an
1509 * external neighmgr daemon to probe existing hosts to independently
1510 * establish their presence on the ES.
1512 static void zebra_evpn_mac_hold_exp_cb(struct event
*t
)
1514 struct zebra_mac
*mac
;
1521 /* the purpose of the hold timer is to age out the peer-active
1524 if (!CHECK_FLAG(mac
->flags
, ZEBRA_MAC_ES_PEER_ACTIVE
))
1527 old_bgp_ready
= zebra_evpn_mac_is_ready_for_bgp(mac
->flags
);
1528 old_static
= zebra_evpn_mac_is_static(mac
);
1529 UNSET_FLAG(mac
->flags
, ZEBRA_MAC_ES_PEER_ACTIVE
);
1530 new_bgp_ready
= zebra_evpn_mac_is_ready_for_bgp(mac
->flags
);
1531 new_static
= zebra_evpn_mac_is_static(mac
);
1533 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
) {
1534 char mac_buf
[MAC_BUF_SIZE
];
1537 "sync-mac vni %u mac %pEA es %s %shold expired",
1538 mac
->zevpn
->vni
, &mac
->macaddr
,
1539 mac
->es
? mac
->es
->esi_str
: "-",
1540 zebra_evpn_zebra_mac_flag_dump(mac
, mac_buf
,
1544 /* re-program the local mac in the dataplane if the mac is no
1547 if (old_static
!= new_static
)
1548 zebra_evpn_sync_mac_dp_install(mac
, false /* set_inactive */,
1549 false /* force_clear_static */,
1552 /* inform bgp if needed */
1553 if (old_bgp_ready
!= new_bgp_ready
)
1554 zebra_evpn_mac_send_add_del_to_client(mac
, old_bgp_ready
,
1558 static inline void zebra_evpn_mac_start_hold_timer(struct zebra_mac
*mac
)
1560 if (mac
->hold_timer
)
1563 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
) {
1564 char mac_buf
[MAC_BUF_SIZE
];
1567 "sync-mac vni %u mac %pEA es %s %shold started",
1568 mac
->zevpn
->vni
, &mac
->macaddr
,
1569 mac
->es
? mac
->es
->esi_str
: "-",
1570 zebra_evpn_zebra_mac_flag_dump(mac
, mac_buf
,
1573 event_add_timer(zrouter
.master
, zebra_evpn_mac_hold_exp_cb
, mac
,
1574 zmh_info
->mac_hold_time
, &mac
->hold_timer
);
1577 void zebra_evpn_mac_stop_hold_timer(struct zebra_mac
*mac
)
1579 if (!mac
->hold_timer
)
1582 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
) {
1583 char mac_buf
[MAC_BUF_SIZE
];
1586 "sync-mac vni %u mac %pEA es %s %shold stopped",
1587 mac
->zevpn
->vni
, &mac
->macaddr
,
1588 mac
->es
? mac
->es
->esi_str
: "-",
1589 zebra_evpn_zebra_mac_flag_dump(mac
, mac_buf
,
1593 EVENT_OFF(mac
->hold_timer
);
1596 void zebra_evpn_sync_mac_del(struct zebra_mac
*mac
)
1601 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
) {
1602 char mac_buf
[MAC_BUF_SIZE
];
1605 "sync-mac del vni %u mac %pEA es %s seq %d f %s",
1606 mac
->zevpn
->vni
, &mac
->macaddr
,
1607 mac
->es
? mac
->es
->esi_str
: "-", mac
->loc_seq
,
1608 zebra_evpn_zebra_mac_flag_dump(mac
, mac_buf
,
1612 old_static
= zebra_evpn_mac_is_static(mac
);
1613 UNSET_FLAG(mac
->flags
, ZEBRA_MAC_ES_PEER_PROXY
);
1614 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_ES_PEER_ACTIVE
))
1615 zebra_evpn_mac_start_hold_timer(mac
);
1616 new_static
= zebra_evpn_mac_is_static(mac
);
1618 if (old_static
!= new_static
)
1619 /* program the local mac in the kernel */
1620 zebra_evpn_sync_mac_dp_install(mac
, false /* set_inactive */,
1621 false /* force_clear_static */,
1625 static inline bool zebra_evpn_mac_is_bgp_seq_ok(struct zebra_evpn
*zevpn
,
1626 struct zebra_mac
*mac
,
1627 uint32_t seq
, bool sync
)
1629 char mac_buf
[MAC_BUF_SIZE
];
1632 bool is_local
= false;
1634 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
)) {
1635 tmp_seq
= mac
->loc_seq
;
1639 tmp_seq
= mac
->rem_seq
;
1643 if (seq
< tmp_seq
) {
1645 if (is_local
&& !zebra_evpn_mac_is_ready_for_bgp(mac
->flags
)) {
1646 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
|| IS_ZEBRA_DEBUG_VXLAN
)
1648 "%s-macip not ready vni %u %s-mac %pEA lower seq %u f 0x%x",
1649 sync
? "sync" : "rem", zevpn
->vni
,
1650 n_type
, &mac
->macaddr
, tmp_seq
,
1655 /* if the mac was never advertised to bgp we must accept
1656 * whatever sequence number bgp sends
1658 if (!is_local
&& zebra_vxlan_get_accept_bgp_seq()) {
1659 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
||
1660 IS_ZEBRA_DEBUG_VXLAN
) {
1662 "%s-macip accept vni %u %s-mac %pEA lower seq %u f %s",
1663 sync
? "sync" : "rem", zevpn
->vni
,
1664 n_type
, &mac
->macaddr
, tmp_seq
,
1665 zebra_evpn_zebra_mac_flag_dump(
1666 mac
, mac_buf
, sizeof(mac_buf
)));
1672 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
|| IS_ZEBRA_DEBUG_VXLAN
) {
1674 "%s-macip ignore vni %u %s-mac %pEA as existing has higher seq %u f %s",
1675 sync
? "sync" : "rem", zevpn
->vni
, n_type
,
1676 &mac
->macaddr
, tmp_seq
,
1677 zebra_evpn_zebra_mac_flag_dump(
1678 mac
, mac_buf
, sizeof(mac_buf
)));
1687 struct zebra_mac
*zebra_evpn_proc_sync_mac_update(struct zebra_evpn
*zevpn
,
1688 const struct ethaddr
*macaddr
,
1690 const struct ipaddr
*ipaddr
,
1691 uint8_t flags
, uint32_t seq
,
1694 struct zebra_mac
*mac
;
1695 bool inform_bgp
= false;
1696 bool inform_dataplane
= false;
1697 bool mac_inactive
= false;
1698 bool seq_change
= false;
1699 bool es_change
= false;
1701 char ipbuf
[INET6_ADDRSTRLEN
];
1702 bool old_local
= false;
1705 bool created
= false;
1707 mac
= zebra_evpn_mac_lookup(zevpn
, macaddr
);
1709 /* if it is a new local path we need to inform both
1710 * the control protocol and the data-plane
1713 inform_dataplane
= true;
1714 mac_inactive
= true;
1716 /* create the MAC and associate it with the dest ES */
1717 mac
= zebra_evpn_mac_add(zevpn
, macaddr
);
1718 zebra_evpn_es_mac_ref(mac
, esi
);
1720 /* local mac activated by an ES peer */
1721 SET_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
);
1722 /* if mac-only route setup peer flags */
1724 if (CHECK_FLAG(flags
, ZEBRA_MACIP_TYPE_PROXY_ADVERT
))
1725 SET_FLAG(mac
->flags
, ZEBRA_MAC_ES_PEER_PROXY
);
1727 SET_FLAG(mac
->flags
, ZEBRA_MAC_ES_PEER_ACTIVE
);
1729 SET_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL_INACTIVE
);
1730 old_bgp_ready
= false;
1731 new_bgp_ready
= zebra_evpn_mac_is_ready_for_bgp(mac
->flags
);
1741 mac
->uptime
= monotime(NULL
);
1743 old_flags
= mac
->flags
;
1744 sticky
= !!CHECK_FLAG(old_flags
, ZEBRA_MAC_STICKY
);
1745 remote_gw
= !!CHECK_FLAG(old_flags
, ZEBRA_MAC_REMOTE_DEF_GW
);
1746 if (sticky
|| remote_gw
) {
1747 if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH
)
1749 "Ignore sync-macip vni %u mac %pEA%s%s%s%s",
1750 zevpn
->vni
, macaddr
,
1751 ipa_len
? " IP " : "",
1752 ipa_len
? ipaddr2str(ipaddr
, ipbuf
,
1755 sticky
? " sticky" : "",
1756 remote_gw
? " remote_gw" : "");
1759 if (!zebra_evpn_mac_is_bgp_seq_ok(zevpn
, mac
, seq
, true))
1762 old_local
= !!CHECK_FLAG(old_flags
, ZEBRA_MAC_LOCAL
);
1763 old_static
= zebra_evpn_mac_is_static(mac
);
1765 /* re-build the mac flags */
1767 SET_FLAG(new_flags
, ZEBRA_MAC_LOCAL
);
1768 /* retain old local activity flag */
1769 if (old_flags
& ZEBRA_MAC_LOCAL
)
1770 new_flags
|= (old_flags
& ZEBRA_MAC_LOCAL_INACTIVE
);
1772 new_flags
|= ZEBRA_MAC_LOCAL_INACTIVE
;
1775 /* if mac-ip route do NOT update the peer flags
1776 * i.e. retain only flags as is
1778 new_flags
|= (old_flags
& ZEBRA_MAC_ALL_PEER_FLAGS
);
1780 /* if mac-only route update peer flags */
1781 if (CHECK_FLAG(flags
, ZEBRA_MACIP_TYPE_PROXY_ADVERT
)) {
1782 SET_FLAG(new_flags
, ZEBRA_MAC_ES_PEER_PROXY
);
1783 /* if the mac was peer-active previously we
1784 * need to keep the flag and start the
1785 * holdtimer on it. the peer-active flag is
1786 * cleared on holdtimer expiry.
1788 if (CHECK_FLAG(old_flags
,
1789 ZEBRA_MAC_ES_PEER_ACTIVE
)) {
1791 ZEBRA_MAC_ES_PEER_ACTIVE
);
1792 zebra_evpn_mac_start_hold_timer(mac
);
1795 SET_FLAG(new_flags
, ZEBRA_MAC_ES_PEER_ACTIVE
);
1796 /* stop hold timer if a peer has verified
1799 zebra_evpn_mac_stop_hold_timer(mac
);
1803 zebra_evpn_mac_clear_fwd_info(mac
);
1804 mac
->flags
= new_flags
;
1806 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
&& (old_flags
!= new_flags
)) {
1807 char mac_buf
[MAC_BUF_SIZE
], omac_buf
[MAC_BUF_SIZE
];
1808 struct zebra_mac omac
;
1810 omac
.flags
= old_flags
;
1812 "sync-mac vni %u mac %pEA old_f %snew_f %s",
1813 zevpn
->vni
, macaddr
,
1814 zebra_evpn_zebra_mac_flag_dump(
1815 &omac
, omac_buf
, sizeof(omac_buf
)),
1816 zebra_evpn_zebra_mac_flag_dump(
1817 mac
, mac_buf
, sizeof(mac_buf
)));
1821 es_change
= zebra_evpn_es_mac_ref(mac
, esi
);
1822 /* if mac dest change - inform both sides */
1825 inform_dataplane
= true;
1826 mac_inactive
= true;
1829 /* if peer-flag is being set notify dataplane that the
1830 * entry must not be expired because of local inactivity
1832 new_static
= zebra_evpn_mac_is_static(mac
);
1833 if (old_static
!= new_static
)
1834 inform_dataplane
= true;
1836 old_bgp_ready
= zebra_evpn_mac_is_ready_for_bgp(old_flags
);
1837 new_bgp_ready
= zebra_evpn_mac_is_ready_for_bgp(mac
->flags
);
1838 if (old_bgp_ready
!= new_bgp_ready
)
1843 /* update sequence number; if that results in a new local sequence
1846 tmp_seq
= MAX(mac
->loc_seq
, seq
);
1847 if (tmp_seq
!= mac
->loc_seq
) {
1848 mac
->loc_seq
= tmp_seq
;
1853 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
) {
1854 char mac_buf
[MAC_BUF_SIZE
];
1856 zlog_debug("sync-mac %s vni %u mac %pEA es %s seq %d f %s%s%s",
1857 created
? "created" : "updated", zevpn
->vni
, macaddr
,
1858 mac
->es
? mac
->es
->esi_str
: "-", mac
->loc_seq
,
1859 zebra_evpn_zebra_mac_flag_dump(mac
, mac_buf
,
1861 inform_bgp
? "inform_bgp" : "",
1862 inform_dataplane
? " inform_dp" : "");
1866 zebra_evpn_mac_send_add_del_to_client(mac
, old_bgp_ready
,
1869 /* neighs using the mac may need to be re-sent to
1870 * bgp with updated info
1872 if (seq_change
|| es_change
|| !old_local
)
1873 zebra_evpn_process_neigh_on_local_mac_change(
1874 zevpn
, mac
, seq_change
, es_change
);
1876 if (inform_dataplane
&& !ipa_len
) {
1877 /* program the local mac in the kernel. when the ES
1878 * change we need to force the dataplane to reset
1879 * the activity as we are yet to establish activity
1882 zebra_evpn_sync_mac_dp_install(
1883 mac
, mac_inactive
/* set_inactive */,
1884 false /* force_clear_static */, __func__
);
1890 /* update local forwarding info. return true if a dest-ES change
1893 static bool zebra_evpn_local_mac_update_fwd_info(struct zebra_mac
*mac
,
1894 struct interface
*ifp
,
1897 struct zebra_if
*zif
= ifp
->info
;
1899 ns_id_t local_ns_id
= NS_DEFAULT
;
1900 struct zebra_vrf
*zvrf
;
1901 struct zebra_evpn_es
*es
;
1903 zvrf
= ifp
->vrf
->info
;
1904 if (zvrf
&& zvrf
->zns
)
1905 local_ns_id
= zvrf
->zns
->ns_id
;
1907 zebra_evpn_mac_clear_fwd_info(mac
);
1909 es
= zif
->es_info
.es
;
1910 if (es
&& (es
->flags
& ZEBRA_EVPNES_BYPASS
))
1912 es_change
= zebra_evpn_es_mac_ref_entry(mac
, es
);
1915 /* if es is set fwd_info is not-relevant/taped-out */
1916 mac
->fwd_info
.local
.ifindex
= ifp
->ifindex
;
1917 mac
->fwd_info
.local
.ns_id
= local_ns_id
;
1918 mac
->fwd_info
.local
.vid
= vid
;
1919 zebra_evpn_mac_ifp_link(mac
, ifp
);
1925 /* Notify Local MACs to the clienti, skips GW MAC */
1926 static void zebra_evpn_send_mac_hash_entry_to_client(struct hash_bucket
*bucket
,
1929 struct mac_walk_ctx
*wctx
= arg
;
1930 struct zebra_mac
*zmac
= bucket
->data
;
1932 if (CHECK_FLAG(zmac
->flags
, ZEBRA_MAC_DEF_GW
))
1935 if (CHECK_FLAG(zmac
->flags
, ZEBRA_MAC_LOCAL
))
1936 zebra_evpn_mac_send_add_to_client(wctx
->zevpn
->vni
,
1937 &zmac
->macaddr
, zmac
->flags
,
1938 zmac
->loc_seq
, zmac
->es
);
1941 /* Iterator to Notify Local MACs of a EVPN */
1942 void zebra_evpn_send_mac_list_to_client(struct zebra_evpn
*zevpn
)
1944 struct mac_walk_ctx wctx
;
1946 if (!zevpn
->mac_table
)
1949 memset(&wctx
, 0, sizeof(wctx
));
1952 hash_iterate(zevpn
->mac_table
, zebra_evpn_send_mac_hash_entry_to_client
,
1956 void zebra_evpn_rem_mac_del(struct zebra_evpn
*zevpn
, struct zebra_mac
*mac
)
1958 zebra_evpn_process_neigh_on_remote_mac_del(zevpn
, mac
);
1959 /* the remote sequence number in the auto mac entry
1960 * needs to be reset to 0 as the mac entry may have
1961 * been removed on all VTEPs (including
1962 * the originating one)
1966 /* If all remote neighbors referencing a remote MAC
1967 * go away, we need to uninstall the MAC.
1969 if (remote_neigh_count(mac
) == 0) {
1970 zebra_evpn_rem_mac_uninstall(zevpn
, mac
, false /*force*/);
1971 zebra_evpn_es_mac_deref_entry(mac
);
1972 UNSET_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE
);
1975 if (list_isempty(mac
->neigh_list
))
1976 zebra_evpn_mac_del(zevpn
, mac
);
1978 SET_FLAG(mac
->flags
, ZEBRA_MAC_AUTO
);
1981 /* Print Duplicate MAC */
1982 void zebra_evpn_print_dad_mac_hash(struct hash_bucket
*bucket
, void *ctxt
)
1984 struct zebra_mac
*mac
;
1986 mac
= (struct zebra_mac
*)bucket
->data
;
1990 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_DUPLICATE
))
1991 zebra_evpn_print_mac_hash(bucket
, ctxt
);
1994 /* Print Duplicate MAC in detail */
1995 void zebra_evpn_print_dad_mac_hash_detail(struct hash_bucket
*bucket
,
1998 struct zebra_mac
*mac
;
2000 mac
= (struct zebra_mac
*)bucket
->data
;
2004 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_DUPLICATE
))
2005 zebra_evpn_print_mac_hash_detail(bucket
, ctxt
);
2008 int zebra_evpn_mac_remote_macip_add(struct zebra_evpn
*zevpn
,
2009 struct zebra_vrf
*zvrf
,
2010 const struct ethaddr
*macaddr
,
2011 struct in_addr vtep_ip
, uint8_t flags
,
2012 uint32_t seq
, const esi_t
*esi
)
2017 bool do_dad
= false;
2018 bool is_dup_detect
= false;
2020 bool old_static
= false;
2021 struct zebra_mac
*mac
;
2022 bool old_es_present
;
2023 bool new_es_present
;
2025 sticky
= !!CHECK_FLAG(flags
, ZEBRA_MACIP_TYPE_STICKY
);
2026 remote_gw
= !!CHECK_FLAG(flags
, ZEBRA_MACIP_TYPE_GW
);
2028 mac
= zebra_evpn_mac_lookup(zevpn
, macaddr
);
2030 /* Ignore if the mac is already present as a gateway mac */
2031 if (mac
&& CHECK_FLAG(mac
->flags
, ZEBRA_MAC_DEF_GW
)
2032 && CHECK_FLAG(flags
, ZEBRA_MACIP_TYPE_GW
)) {
2033 if (IS_ZEBRA_DEBUG_VXLAN
)
2035 "Ignore remote MACIP ADD VNI %u MAC %pEA as MAC is already configured as gateway MAC",
2036 zevpn
->vni
, macaddr
);
2040 old_esi
= (mac
&& mac
->es
) ? &mac
->es
->esi
: zero_esi
;
2042 /* check if the remote MAC is unknown or has a change.
2043 * If so, that needs to be updated first. Note that client could
2044 * install MAC and MACIP separately or just install the latter.
2046 if (!mac
|| !CHECK_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE
)
2047 || sticky
!= !!CHECK_FLAG(mac
->flags
, ZEBRA_MAC_STICKY
)
2048 || remote_gw
!= !!CHECK_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE_DEF_GW
)
2049 || !IPV4_ADDR_SAME(&mac
->fwd_info
.r_vtep_ip
, &vtep_ip
)
2050 || memcmp(old_esi
, esi
, sizeof(esi_t
)) || seq
!= mac
->rem_seq
)
2055 mac
= zebra_evpn_mac_add(zevpn
, macaddr
);
2056 zebra_evpn_es_mac_ref(mac
, esi
);
2058 /* When host moves but changes its (MAC,IP)
2059 * binding, BGP may install a MACIP entry that
2060 * corresponds to "older" location of the host
2061 * in transient situations (because {IP1,M1}
2062 * is a different route from {IP1,M2}). Check
2063 * the sequence number and ignore this update
2066 if (!zebra_evpn_mac_is_bgp_seq_ok(zevpn
, mac
, seq
,
2070 old_es_present
= !!mac
->es
;
2071 zebra_evpn_es_mac_ref(mac
, esi
);
2072 new_es_present
= !!mac
->es
;
2073 /* XXX - dataplane is curently not able to handle a MAC
2074 * replace if the destination changes from L2-NHG to
2075 * single VTEP and vice-versa. So delete the old entry
2078 if (old_es_present
!= new_es_present
)
2079 zebra_evpn_rem_mac_uninstall(zevpn
, mac
, false);
2082 /* Check MAC's curent state is local (this is the case
2083 * where MAC has moved from L->R) and check previous
2084 * detection started via local learning.
2085 * RFC-7432: A PE/VTEP that detects a MAC mobility
2086 * event via local learning starts an M-second timer.
2088 * VTEP-IP or seq. change alone is not considered
2089 * for dup. detection.
2091 * MAC is already marked duplicate set dad, then
2092 * is_dup_detect will be set to not install the entry.
2094 if ((!CHECK_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE
)
2096 || CHECK_FLAG(mac
->flags
, ZEBRA_MAC_DUPLICATE
))
2099 /* Remove local MAC from BGP. */
2100 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
)) {
2101 /* force drop the sync flags */
2102 old_static
= zebra_evpn_mac_is_static(mac
);
2103 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
) {
2104 char mac_buf
[MAC_BUF_SIZE
];
2107 "sync-mac->remote vni %u mac %pEA es %s seq %d f %s",
2108 zevpn
->vni
, macaddr
,
2109 mac
->es
? mac
->es
->esi_str
: "-",
2111 zebra_evpn_zebra_mac_flag_dump(
2112 mac
, mac_buf
, sizeof(mac_buf
)));
2115 zebra_evpn_mac_clear_sync_info(mac
);
2116 zebra_evpn_mac_send_del_to_client(zevpn
->vni
, macaddr
,
2121 /* Set "auto" and "remote" forwarding info. */
2122 zebra_evpn_mac_clear_fwd_info(mac
);
2123 UNSET_FLAG(mac
->flags
, ZEBRA_MAC_ALL_LOCAL_FLAGS
);
2124 SET_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE
);
2125 mac
->fwd_info
.r_vtep_ip
= vtep_ip
;
2128 SET_FLAG(mac
->flags
, ZEBRA_MAC_STICKY
);
2130 UNSET_FLAG(mac
->flags
, ZEBRA_MAC_STICKY
);
2133 SET_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE_DEF_GW
);
2135 UNSET_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE_DEF_GW
);
2137 zebra_evpn_dup_addr_detect_for_mac(
2138 zvrf
, mac
, mac
->fwd_info
.r_vtep_ip
, do_dad
,
2139 &is_dup_detect
, false);
2141 if (!is_dup_detect
) {
2142 zebra_evpn_process_neigh_on_remote_mac_add(zevpn
, mac
);
2143 /* Install the entry. */
2144 zebra_evpn_rem_mac_install(zevpn
, mac
, old_static
);
2148 /* Update seq number. */
2151 UNSET_FLAG(mac
->flags
, ZEBRA_MAC_AUTO
);
2155 int zebra_evpn_add_update_local_mac(struct zebra_vrf
*zvrf
,
2156 struct zebra_evpn
*zevpn
,
2157 struct interface
*ifp
,
2158 const struct ethaddr
*macaddr
, vlanid_t vid
,
2159 bool sticky
, bool local_inactive
,
2160 bool dp_static
, struct zebra_mac
*mac
)
2162 bool mac_sticky
= false;
2163 bool inform_client
= false;
2164 bool upd_neigh
= false;
2165 bool is_dup_detect
= false;
2166 struct in_addr vtep_ip
= {.s_addr
= 0};
2167 bool es_change
= false;
2169 /* assume inactive if not present or if not local */
2170 bool old_local_inactive
= true;
2171 bool old_bgp_ready
= false;
2172 bool inform_dataplane
= false;
2173 bool new_static
= false;
2176 /* Check if we need to create or update or it is a NO-OP. */
2178 mac
= zebra_evpn_mac_lookup(zevpn
, macaddr
);
2180 if (IS_ZEBRA_DEBUG_VXLAN
|| IS_ZEBRA_DEBUG_EVPN_MH_MAC
)
2182 "ADD %sMAC %pEA intf %s(%u) VID %u -> VNI %u%s",
2183 sticky
? "sticky " : "", macaddr
,
2184 ifp
->name
, ifp
->ifindex
, vid
, zevpn
->vni
,
2185 local_inactive
? " local-inactive" : "");
2187 mac
= zebra_evpn_mac_add(zevpn
, macaddr
);
2188 SET_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
);
2189 es_change
= zebra_evpn_local_mac_update_fwd_info(mac
, ifp
, vid
);
2191 SET_FLAG(mac
->flags
, ZEBRA_MAC_STICKY
);
2192 inform_client
= true;
2194 if (IS_ZEBRA_DEBUG_VXLAN
|| IS_ZEBRA_DEBUG_EVPN_MH_MAC
) {
2195 char mac_buf
[MAC_BUF_SIZE
];
2198 "UPD %sMAC %pEA intf %s(%u) VID %u -> VNI %u %scurFlags %s",
2199 sticky
? "sticky " : "", macaddr
,
2200 ifp
->name
, ifp
->ifindex
, vid
, zevpn
->vni
,
2201 local_inactive
? "local-inactive " : "",
2202 zebra_evpn_zebra_mac_flag_dump(
2203 mac
, mac_buf
, sizeof(mac_buf
)));
2206 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
)) {
2207 struct interface
*old_ifp
;
2211 zebra_evpn_mac_get_access_info(mac
, &old_ifp
, &old_vid
);
2213 zebra_evpn_mac_is_ready_for_bgp(mac
->flags
);
2214 old_local_inactive
=
2215 !!(mac
->flags
& ZEBRA_MAC_LOCAL_INACTIVE
);
2216 old_static
= zebra_evpn_mac_is_static(mac
);
2217 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_STICKY
))
2219 es_change
= zebra_evpn_local_mac_update_fwd_info(
2223 * Update any changes and if changes are relevant to
2226 if (mac_sticky
== sticky
&& old_ifp
== ifp
2228 && old_local_inactive
== local_inactive
2229 && dp_static
== old_static
&& !es_change
) {
2230 if (IS_ZEBRA_DEBUG_VXLAN
)
2232 " Add/Update %sMAC %pEA intf %s(%u) VID %u -> VNI %u%s, "
2233 "entry exists and has not changed ",
2234 sticky
? "sticky " : "",
2236 ifp
->ifindex
, vid
, zevpn
->vni
,
2242 if (mac_sticky
!= sticky
) {
2244 SET_FLAG(mac
->flags
, ZEBRA_MAC_STICKY
);
2246 UNSET_FLAG(mac
->flags
,
2248 inform_client
= true;
2251 /* If an es_change is detected we need to advertise
2252 * the route with a sequence that is one
2253 * greater. This is need to indicate a mac-move
2257 /* update the sequence number only if the entry
2260 if (!local_inactive
)
2261 mac
->loc_seq
= mac
->loc_seq
+ 1;
2262 /* force drop the peer/sync info as it is
2263 * simply no longer relevant
2265 if (CHECK_FLAG(mac
->flags
,
2266 ZEBRA_MAC_ALL_PEER_FLAGS
)) {
2267 zebra_evpn_mac_clear_sync_info(mac
);
2269 zebra_evpn_mac_is_static(mac
);
2270 /* if we clear peer-flags we
2271 * also need to notify the dataplane
2272 * to drop the static flag
2274 if (old_static
!= new_static
)
2275 inform_dataplane
= true;
2278 } else if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE
)
2279 || CHECK_FLAG(mac
->flags
, ZEBRA_MAC_AUTO
)) {
2280 bool do_dad
= false;
2283 * MAC has either moved or was "internally" created due
2284 * to a neighbor learn and is now actually learnt. If
2285 * it was learnt as a remote sticky MAC, this is an
2288 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_STICKY
)) {
2290 EC_ZEBRA_STICKY_MAC_ALREADY_LEARNT
,
2291 "MAC %pEA already learnt as remote sticky MAC behind VTEP %pI4 VNI %u",
2293 &mac
->fwd_info
.r_vtep_ip
,
2298 /* If an actual move, compute MAC's seq number */
2299 if (CHECK_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE
)) {
2301 MAX(mac
->rem_seq
+ 1, mac
->loc_seq
);
2302 vtep_ip
= mac
->fwd_info
.r_vtep_ip
;
2303 /* Trigger DAD for remote MAC */
2307 UNSET_FLAG(mac
->flags
, ZEBRA_MAC_REMOTE
);
2308 UNSET_FLAG(mac
->flags
, ZEBRA_MAC_AUTO
);
2309 SET_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
);
2310 es_change
= zebra_evpn_local_mac_update_fwd_info(
2313 SET_FLAG(mac
->flags
, ZEBRA_MAC_STICKY
);
2315 UNSET_FLAG(mac
->flags
, ZEBRA_MAC_STICKY
);
2317 * We have to inform BGP of this MAC as well as process
2320 inform_client
= true;
2323 zebra_evpn_dup_addr_detect_for_mac(
2324 zvrf
, mac
, vtep_ip
, do_dad
, &is_dup_detect
,
2326 if (is_dup_detect
) {
2327 inform_client
= false;
2334 /* if the dataplane thinks the entry is sync but it is
2335 * not sync in zebra (or vice-versa) we need to re-install
2338 new_static
= zebra_evpn_mac_is_static(mac
);
2339 if (dp_static
!= new_static
)
2340 inform_dataplane
= true;
2343 SET_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL_INACTIVE
);
2345 UNSET_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL_INACTIVE
);
2347 new_bgp_ready
= zebra_evpn_mac_is_ready_for_bgp(mac
->flags
);
2348 /* if local-activity has changed we need update bgp
2349 * even if bgp already knows about the mac
2351 if ((old_local_inactive
!= local_inactive
)
2352 || (new_bgp_ready
!= old_bgp_ready
)) {
2353 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
) {
2354 char mac_buf
[MAC_BUF_SIZE
];
2357 "local mac vni %u mac %pEA es %s seq %d f %s%s",
2358 zevpn
->vni
, macaddr
,
2359 mac
->es
? mac
->es
->esi_str
: "", mac
->loc_seq
,
2360 zebra_evpn_zebra_mac_flag_dump(mac
, mac_buf
,
2362 local_inactive
? "local-inactive" : "");
2366 inform_client
= true;
2370 inform_client
= true;
2374 /* Inform dataplane if required. */
2375 if (inform_dataplane
)
2376 zebra_evpn_sync_mac_dp_install(mac
, false /* set_inactive */,
2377 false /* force_clear_static */,
2380 /* Inform BGP if required. */
2382 zebra_evpn_mac_send_add_del_to_client(mac
, old_bgp_ready
,
2385 /* Process all neighbors associated with this MAC, if required. */
2387 zebra_evpn_process_neigh_on_local_mac_change(zevpn
, mac
, 0,
2393 int zebra_evpn_del_local_mac(struct zebra_evpn
*zevpn
, struct zebra_mac
*mac
,
2399 if (IS_ZEBRA_DEBUG_VXLAN
)
2400 zlog_debug("DEL MAC %pEA VNI %u seq %u flags 0x%x nbr count %u",
2401 &mac
->macaddr
, zevpn
->vni
, mac
->loc_seq
, mac
->flags
,
2402 listcount(mac
->neigh_list
));
2404 old_bgp_ready
= zebra_evpn_mac_is_ready_for_bgp(mac
->flags
);
2405 if (!clear_static
&& zebra_evpn_mac_is_static(mac
)) {
2406 /* this is a synced entry and can only be removed when the
2407 * es-peers stop advertising it.
2409 zebra_evpn_mac_clear_fwd_info(mac
);
2411 if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
) {
2412 char mac_buf
[MAC_BUF_SIZE
];
2415 "re-add sync-mac vni %u mac %pEA es %s seq %d f %s",
2416 zevpn
->vni
, &mac
->macaddr
,
2417 mac
->es
? mac
->es
->esi_str
: "-", mac
->loc_seq
,
2418 zebra_evpn_zebra_mac_flag_dump(
2419 mac
, mac_buf
, sizeof(mac_buf
)));
2422 /* inform-bgp about change in local-activity if any */
2423 if (!CHECK_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL_INACTIVE
)) {
2424 SET_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL_INACTIVE
);
2426 zebra_evpn_mac_is_ready_for_bgp(mac
->flags
);
2427 zebra_evpn_mac_send_add_del_to_client(
2428 mac
, old_bgp_ready
, new_bgp_ready
);
2431 /* re-install the inactive entry in the kernel */
2432 zebra_evpn_sync_mac_dp_install(mac
, true /* set_inactive */,
2433 false /* force_clear_static */,
2439 /* flush the peer info */
2440 zebra_evpn_mac_clear_sync_info(mac
);
2442 /* Update all the neigh entries associated with this mac */
2443 zebra_evpn_process_neigh_on_local_mac_del(zevpn
, mac
);
2445 /* Remove MAC from BGP. */
2446 zebra_evpn_mac_send_del_to_client(zevpn
->vni
, &mac
->macaddr
, mac
->flags
,
2447 clear_static
/* force */);
2449 zebra_evpn_es_mac_deref_entry(mac
);
2451 /* remove links to the destination access port */
2452 zebra_evpn_mac_clear_fwd_info(mac
);
2455 * If there are no neigh associated with the mac delete the mac
2456 * else mark it as AUTO for forward reference
2458 if (!listcount(mac
->neigh_list
)) {
2459 zebra_evpn_mac_del(zevpn
, mac
);
2461 UNSET_FLAG(mac
->flags
, ZEBRA_MAC_ALL_LOCAL_FLAGS
);
2462 UNSET_FLAG(mac
->flags
, ZEBRA_MAC_STICKY
);
2463 SET_FLAG(mac
->flags
, ZEBRA_MAC_AUTO
);
2469 void zebra_evpn_mac_gw_macip_add(struct interface
*ifp
,
2470 struct zebra_evpn
*zevpn
,
2471 const struct ipaddr
*ip
,
2472 struct zebra_mac
**macp
,
2473 const struct ethaddr
*macaddr
,
2474 vlanid_t vlan_id
, bool def_gw
)
2476 struct zebra_mac
*mac
;
2477 ns_id_t local_ns_id
= NS_DEFAULT
;
2478 struct zebra_vrf
*zvrf
;
2480 zvrf
= ifp
->vrf
->info
;
2481 if (zvrf
&& zvrf
->zns
)
2482 local_ns_id
= zvrf
->zns
->ns_id
;
2485 mac
= zebra_evpn_mac_lookup(zevpn
, macaddr
);
2487 mac
= zebra_evpn_mac_add(zevpn
, macaddr
);
2492 /* Set "local" forwarding info. */
2493 zebra_evpn_mac_clear_fwd_info(mac
);
2494 SET_FLAG(mac
->flags
, ZEBRA_MAC_LOCAL
);
2495 SET_FLAG(mac
->flags
, ZEBRA_MAC_AUTO
);
2497 SET_FLAG(mac
->flags
, ZEBRA_MAC_DEF_GW
);
2499 SET_FLAG(mac
->flags
, ZEBRA_MAC_SVI
);
2500 mac
->fwd_info
.local
.ifindex
= ifp
->ifindex
;
2501 mac
->fwd_info
.local
.ns_id
= local_ns_id
;
2502 mac
->fwd_info
.local
.vid
= vlan_id
;
2505 void zebra_evpn_mac_svi_del(struct interface
*ifp
, struct zebra_evpn
*zevpn
)
2507 struct zebra_mac
*mac
;
2508 struct ethaddr macaddr
;
2511 if (!zebra_evpn_mh_do_adv_svi_mac())
2514 memcpy(&macaddr
.octet
, ifp
->hw_addr
, ETH_ALEN
);
2515 mac
= zebra_evpn_mac_lookup(zevpn
, &macaddr
);
2516 if (mac
&& CHECK_FLAG(mac
->flags
, ZEBRA_MAC_SVI
)) {
2517 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2518 zlog_debug("SVI %s mac free", ifp
->name
);
2520 old_bgp_ready
= zebra_evpn_mac_is_ready_for_bgp(mac
->flags
);
2521 UNSET_FLAG(mac
->flags
, ZEBRA_MAC_SVI
);
2522 zebra_evpn_mac_send_add_del_to_client(mac
, old_bgp_ready
,
2524 zebra_evpn_deref_ip2mac(mac
->zevpn
, mac
);
2528 void zebra_evpn_mac_svi_add(struct interface
*ifp
, struct zebra_evpn
*zevpn
)
2530 struct zebra_mac
*mac
= NULL
;
2531 struct ethaddr macaddr
;
2532 struct zebra_if
*zif
= ifp
->info
;
2536 if (!zebra_evpn_mh_do_adv_svi_mac()
2537 || !zebra_evpn_send_to_client_ok(zevpn
))
2540 memcpy(&macaddr
.octet
, ifp
->hw_addr
, ETH_ALEN
);
2543 mac
= zebra_evpn_mac_lookup(zevpn
, &macaddr
);
2544 if (mac
&& CHECK_FLAG(mac
->flags
, ZEBRA_MAC_SVI
))
2547 /* add/update mac */
2548 if (IS_ZEBRA_DEBUG_EVPN_MH_ES
)
2549 zlog_debug("SVI %s mac add", zif
->ifp
->name
);
2551 old_bgp_ready
= (mac
&& zebra_evpn_mac_is_ready_for_bgp(mac
->flags
))
2555 zebra_evpn_mac_gw_macip_add(ifp
, zevpn
, NULL
, &mac
, &macaddr
, 0, false);
2557 new_bgp_ready
= zebra_evpn_mac_is_ready_for_bgp(mac
->flags
);
2558 zebra_evpn_mac_send_add_del_to_client(mac
, old_bgp_ready
,