From c7620108890f58796b0155bb9ef3d65f0b39909f Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Tue, 17 Aug 2021 10:42:51 +0200 Subject: [PATCH] zebra: handle bridge mac address update in evpn contexts when running bgp evpn rt5 setup, the Rmac sent in BGP updates stands for the MAC address of the bridge interface. After having loaded frr configuration, the Rmac address is not refreshed. This issue can be easily reproduced by executing some commands: ip netns exec cust1 ip link set dev br1000 address 2e:ab:45:aa:bb:cc Actually, the BGP EVPN contexts are kept unchanged. That commit proposes to fix this by intercepting the mac address change, and refreshing the vxlan interfaces attached to te bridge interface that changed its MAC address. Signed-off-by: Philippe Guibert --- zebra/if_netlink.c | 34 ++++++++++++++++++++++++---------- zebra/zebra_l2.c | 36 +++++++++++++++++++++++++++++------- zebra/zebra_l2.h | 6 +++++- zebra/zebra_vxlan.c | 7 +++++++ zebra/zebra_vxlan.h | 1 + 5 files changed, 66 insertions(+), 18 deletions(-) diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 8b3b788b727b..658b862e6288 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -1021,7 +1021,8 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup) if (IS_ZEBRA_IF_BOND(ifp)) zebra_l2if_update_bond(ifp, true); if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp)) - zebra_l2if_update_bridge_slave(ifp, bridge_ifindex, ns_id); + zebra_l2if_update_bridge_slave(ifp, bridge_ifindex, ns_id, + ZEBRA_BRIDGE_NO_ACTION); else if (IS_ZEBRA_IF_BOND_SLAVE(ifp)) zebra_l2if_update_bond_slave(ifp, bond_ifindex, !!bypass); @@ -1644,9 +1645,9 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) ifp, linkinfo[IFLA_INFO_DATA], 1, link_nsid); if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp)) - zebra_l2if_update_bridge_slave(ifp, - bridge_ifindex, - ns_id); + zebra_l2if_update_bridge_slave( + ifp, bridge_ifindex, ns_id, + ZEBRA_BRIDGE_NO_ACTION); else if (IS_ZEBRA_IF_BOND_SLAVE(ifp)) zebra_l2if_update_bond_slave(ifp, bond_ifindex, !!bypass); @@ -1670,6 +1671,7 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) if_handle_vrf_change(ifp, vrf_id); } else { bool was_bridge_slave, was_bond_slave; + uint8_t chgflags = ZEBRA_BRIDGE_NO_ACTION; /* Interface update. */ if (IS_ZEBRA_DEBUG_KERNEL) @@ -1711,6 +1713,8 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) if_down(ifp); rib_update(RIB_UPDATE_KERNEL); } else if (if_is_operative(ifp)) { + bool mac_updated = false; + /* Must notify client daemons of new * interface status. */ if (IS_ZEBRA_DEBUG_KERNEL) @@ -1721,9 +1725,11 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) /* Update EVPN VNI when SVI MAC change */ - if (IS_ZEBRA_IF_VLAN(ifp) && - memcmp(old_hw_addr, ifp->hw_addr, - INTERFACE_HWADDR_MAX)) { + if (memcmp(old_hw_addr, ifp->hw_addr, + INTERFACE_HWADDR_MAX)) + mac_updated = true; + if (IS_ZEBRA_IF_VLAN(ifp) + && mac_updated) { struct interface *link_if; link_if = @@ -1733,6 +1739,13 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) if (link_if) zebra_vxlan_svi_up(ifp, link_if); + } else if (mac_updated + && IS_ZEBRA_IF_BRIDGE(ifp)) { + zlog_debug( + "Intf %s(%u) bridge changed MAC address", + name, ifp->ifindex); + chgflags = + ZEBRA_BRIDGE_MASTER_MAC_CHANGE; } } } else { @@ -1758,12 +1771,13 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) netlink_interface_update_l2info( ifp, linkinfo[IFLA_INFO_DATA], 0, link_nsid); + if (IS_ZEBRA_IF_BRIDGE(ifp)) + zebra_l2if_update_bridge(ifp, chgflags); if (IS_ZEBRA_IF_BOND(ifp)) zebra_l2if_update_bond(ifp, true); if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp) || was_bridge_slave) - zebra_l2if_update_bridge_slave(ifp, - bridge_ifindex, - ns_id); + zebra_l2if_update_bridge_slave( + ifp, bridge_ifindex, ns_id, chgflags); else if (IS_ZEBRA_IF_BOND_SLAVE(ifp) || was_bond_slave) zebra_l2if_update_bond_slave(ifp, bond_ifindex, !!bypass); diff --git a/zebra/zebra_l2.c b/zebra/zebra_l2.c index 71fac556e190..ae630314be1e 100644 --- a/zebra/zebra_l2.c +++ b/zebra/zebra_l2.c @@ -50,7 +50,8 @@ /* static function declarations */ /* Private functions */ -static void map_slaves_to_bridge(struct interface *br_if, int link) +static void map_slaves_to_bridge(struct interface *br_if, int link, + bool update_slave, uint8_t chgflags) { struct vrf *vrf; struct interface *ifp; @@ -79,9 +80,17 @@ static void map_slaves_to_bridge(struct interface *br_if, int link) br_slave = &zif->brslave_info; if (link) { - if (br_slave->bridge_ifindex == br_if->ifindex && - br_slave->ns_id == zns->ns_id) + if (br_slave->bridge_ifindex == br_if->ifindex + && br_slave->ns_id == zns->ns_id) { br_slave->br_if = br_if; + if (update_slave) { + zebra_l2if_update_bridge_slave( + ifp, + br_slave->bridge_ifindex, + br_slave->ns_id, + chgflags); + } + } } else { if (br_slave->br_if == br_if) br_slave->br_if = NULL; @@ -261,7 +270,7 @@ void zebra_l2_bridge_add_update(struct interface *ifp, memcpy(&zif->l2info.br, bridge_info, sizeof(*bridge_info)); /* Link all slaves to this bridge */ - map_slaves_to_bridge(ifp, 1); + map_slaves_to_bridge(ifp, 1, false, ZEBRA_BRIDGE_NO_ACTION); } /* @@ -270,7 +279,14 @@ void zebra_l2_bridge_add_update(struct interface *ifp, void zebra_l2_bridge_del(struct interface *ifp) { /* Unlink all slaves to this bridge */ - map_slaves_to_bridge(ifp, 0); + map_slaves_to_bridge(ifp, 0, false, ZEBRA_BRIDGE_NO_ACTION); +} + +void zebra_l2if_update_bridge(struct interface *ifp, uint8_t chgflags) +{ + if (!chgflags) + return; + map_slaves_to_bridge(ifp, 1, true, chgflags); } /* @@ -398,8 +414,8 @@ void zebra_l2_vxlanif_del(struct interface *ifp) * from a bridge before it can be mapped to another bridge. */ void zebra_l2if_update_bridge_slave(struct interface *ifp, - ifindex_t bridge_ifindex, - ns_id_t ns_id) + ifindex_t bridge_ifindex, ns_id_t ns_id, + uint8_t chgflags) { struct zebra_if *zif; ifindex_t old_bridge_ifindex; @@ -413,6 +429,12 @@ void zebra_l2if_update_bridge_slave(struct interface *ifp, if (!zvrf) return; + if (zif->zif_type == ZEBRA_IF_VXLAN + && chgflags != ZEBRA_BRIDGE_NO_ACTION) { + if (ZEBRA_BRIDGE_MASTER_MAC_CHANGE) + zebra_vxlan_if_update(ifp, + ZEBRA_VXLIF_MASTER_MAC_CHANGE); + } old_bridge_ifindex = zif->brslave_info.bridge_ifindex; old_ns_id = zif->brslave_info.ns_id; if (old_bridge_ifindex == bridge_ifindex && diff --git a/zebra/zebra_l2.h b/zebra/zebra_l2.h index 6572f344c4d0..de833ebdbc68 100644 --- a/zebra/zebra_l2.h +++ b/zebra/zebra_l2.h @@ -33,6 +33,9 @@ extern "C" { #endif +#define ZEBRA_BRIDGE_NO_ACTION (0) +#define ZEBRA_BRIDGE_MASTER_MAC_CHANGE (1 << 1) + /* zebra L2 interface information - bridge slave (linkage to bridge) */ struct zebra_l2info_brslave { ifindex_t bridge_ifindex; /* Bridge Master */ @@ -121,7 +124,7 @@ extern void zebra_l2_greif_del(struct interface *ifp); extern void zebra_l2_vxlanif_del(struct interface *ifp); extern void zebra_l2if_update_bridge_slave(struct interface *ifp, ifindex_t bridge_ifindex, - ns_id_t ns_id); + ns_id_t ns_id, uint8_t chgflags); extern void zebra_l2if_update_bond_slave(struct interface *ifp, ifindex_t bond_ifindex, bool bypass); @@ -130,6 +133,7 @@ extern void zebra_vlan_bitmap_compute(struct interface *ifp, extern void zebra_vlan_mbr_re_eval(struct interface *ifp, bitfield_t vlan_bitmap); extern void zebra_l2if_update_bond(struct interface *ifp, bool add); +extern void zebra_l2if_update_bridge(struct interface *ifp, uint8_t chgflags); #ifdef __cplusplus } diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 7ad129cecc95..c13c867d2a4a 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -5043,6 +5043,13 @@ int zebra_vxlan_if_update(struct interface *ifp, uint16_t chgflags) return 0; } + if ((chgflags & ZEBRA_VXLIF_MASTER_MAC_CHANGE) + && if_is_operative(ifp) && is_l3vni_oper_up(zl3vni)) { + zebra_vxlan_process_l3vni_oper_down(zl3vni); + zebra_vxlan_process_l3vni_oper_up(zl3vni); + return 0; + } + /* access-vlan change - process oper down, associate with new * svi_if and then process oper up again */ diff --git a/zebra/zebra_vxlan.h b/zebra/zebra_vxlan.h index 915e987b6bbd..464a8e5fc46c 100644 --- a/zebra/zebra_vxlan.h +++ b/zebra/zebra_vxlan.h @@ -65,6 +65,7 @@ is_vxlan_flooding_head_end(void) #define ZEBRA_VXLIF_MASTER_CHANGE (1 << 1) #define ZEBRA_VXLIF_VLAN_CHANGE (1 << 2) #define ZEBRA_VXLIF_MCAST_GRP_CHANGE (1 << 3) +#define ZEBRA_VXLIF_MASTER_MAC_CHANGE (1 << 4) #define VNI_STR_LEN 32