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🆎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 <philippe.guibert@6wind.com>
This commit is contained in:
Philippe Guibert 2021-08-17 10:42:51 +02:00
parent 2490726201
commit c762010889
5 changed files with 66 additions and 18 deletions

View File

@ -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);

View File

@ -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 &&

View File

@ -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
}

View File

@ -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
*/

View File

@ -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