]> git.puffer.fish Git - matthieu/frr.git/commitdiff
zebra: handle bridge mac address update in evpn contexts
authorPhilippe Guibert <philippe.guibert@6wind.com>
Tue, 17 Aug 2021 08:42:51 +0000 (10:42 +0200)
committerPhilippe Guibert <philippe.guibert@6wind.com>
Fri, 17 Sep 2021 08:25:35 +0000 (10:25 +0200)
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 <philippe.guibert@6wind.com>
zebra/if_netlink.c
zebra/zebra_l2.c
zebra/zebra_l2.h
zebra/zebra_vxlan.c
zebra/zebra_vxlan.h

index 8b3b788b727bb5a6636970441fe01bb3d40cd3d7..658b862e62883bf1c8b6e1714de174d6a8e1cfe8 100644 (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);
index 71fac556e19006c8638efde60d3dd83834fe5f4d..ae630314be1ebcdb2c60e56f7ba667b5c7e01c25 100644 (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 &&
index 6572f344c4d0de2cd6fa1fa79f7ed276fb3765bd..de833ebdbc684134466f78b01775718e32da1085 100644 (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
 }
index 7ad129cecc95fd57fb5f376dfffdb58a0c15b2c6..c13c867d2a4a18879ef47341fe360e96c5edbf89 100644 (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
                 */
index 915e987b6bbd8b57d1c899b2e2d33e89575030a5..464a8e5fc46ca76d806e8b6dadc76dd1f18cddee 100644 (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