mlxsw: spectrum_router: Veto unsupported RIF MAC addresses
authorPetr Machata <petrm@mellanox.com>
Thu, 13 Dec 2018 11:54:52 +0000 (11:54 +0000)
committerDavid S. Miller <davem@davemloft.net>
Fri, 14 Dec 2018 02:41:39 +0000 (18:41 -0800)
On NETDEV_PRE_CHANGEADDR, if the change is related to a RIF interface,
verify that it satisfies the criterion that all RIF interfaces have the
same MAC address prefix, as indicated by mlxsw_sp.mac_mask.

Additionally, besides explicit address changes, check that the address
of an interface for which a RIF is about to be added matches the
required pattern as well.

Signed-off-by: Petr Machata <petrm@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Reviewed-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/mellanox/mlxsw/spectrum.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c

index 955f7bb..5fbb4b7 100644 (file)
@@ -5334,7 +5334,9 @@ static int mlxsw_sp_netdevice_event(struct notifier_block *nb,
        else if (mlxsw_sp_netdev_is_ipip_ul(mlxsw_sp, dev))
                err = mlxsw_sp_netdevice_ipip_ul_event(mlxsw_sp, dev,
                                                       event, ptr);
-       else if (event == NETDEV_CHANGEADDR || event == NETDEV_CHANGEMTU)
+       else if (event == NETDEV_PRE_CHANGEADDR ||
+                event == NETDEV_CHANGEADDR ||
+                event == NETDEV_CHANGEMTU)
                err = mlxsw_sp_netdevice_router_port_event(dev, event, ptr);
        else if (mlxsw_sp_is_vrf_event(event, ptr))
                err = mlxsw_sp_netdevice_vrf_event(dev, event, ptr);
index 0cf641a..b33ba8b 100644 (file)
@@ -6699,6 +6699,33 @@ static int mlxsw_sp_inetaddr_macvlan_event(struct net_device *macvlan_dev,
        return 0;
 }
 
+static int mlxsw_sp_router_port_check_rif_addr(struct mlxsw_sp *mlxsw_sp,
+                                              struct net_device *dev,
+                                              const unsigned char *dev_addr,
+                                              struct netlink_ext_ack *extack)
+{
+       struct mlxsw_sp_rif *rif;
+       int i;
+
+       /* A RIF is not created for macvlan netdevs. Their MAC is used to
+        * populate the FDB
+        */
+       if (netif_is_macvlan(dev))
+               return 0;
+
+       for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
+               rif = mlxsw_sp->router->rifs[i];
+               if (rif && rif->dev != dev &&
+                   !ether_addr_equal_masked(rif->dev->dev_addr, dev_addr,
+                                            mlxsw_sp->mac_mask)) {
+                       NL_SET_ERR_MSG_MOD(extack, "All router interface MAC addresses must have the same prefix");
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
 static int __mlxsw_sp_inetaddr_event(struct net_device *dev,
                                     unsigned long event,
                                     struct netlink_ext_ack *extack)
@@ -6760,6 +6787,11 @@ int mlxsw_sp_inetaddr_valid_event(struct notifier_block *unused,
        if (!mlxsw_sp_rif_should_config(rif, dev, event))
                goto out;
 
+       err = mlxsw_sp_router_port_check_rif_addr(mlxsw_sp, dev, dev->dev_addr,
+                                                 ivi->extack);
+       if (err)
+               goto out;
+
        err = __mlxsw_sp_inetaddr_event(dev, event, ivi->extack);
 out:
        return notifier_from_errno(err);
@@ -6841,6 +6873,11 @@ int mlxsw_sp_inet6addr_valid_event(struct notifier_block *unused,
        if (!mlxsw_sp_rif_should_config(rif, dev, event))
                goto out;
 
+       err = mlxsw_sp_router_port_check_rif_addr(mlxsw_sp, dev, dev->dev_addr,
+                                                 i6vi->extack);
+       if (err)
+               goto out;
+
        err = __mlxsw_sp_inetaddr_event(dev, event, i6vi->extack);
 out:
        return notifier_from_errno(err);
@@ -6914,6 +6951,16 @@ err_rif_edit:
        return err;
 }
 
+static int mlxsw_sp_router_port_pre_changeaddr_event(struct mlxsw_sp_rif *rif,
+                           struct netdev_notifier_pre_changeaddr_info *info)
+{
+       struct netlink_ext_ack *extack;
+
+       extack = netdev_notifier_info_to_extack(&info->info);
+       return mlxsw_sp_router_port_check_rif_addr(rif->mlxsw_sp, rif->dev,
+                                                  info->dev_addr, extack);
+}
+
 int mlxsw_sp_netdevice_router_port_event(struct net_device *dev,
                                         unsigned long event, void *ptr)
 {
@@ -6932,6 +6979,8 @@ int mlxsw_sp_netdevice_router_port_event(struct net_device *dev,
        case NETDEV_CHANGEMTU: /* fall through */
        case NETDEV_CHANGEADDR:
                return mlxsw_sp_router_port_change_event(mlxsw_sp, rif);
+       case NETDEV_PRE_CHANGEADDR:
+               return mlxsw_sp_router_port_pre_changeaddr_event(rif, ptr);
        }
 
        return 0;