net/mlx5e: Enabling aRFS mechanism
authorMaor Gottlieb <maorg@mellanox.com>
Thu, 28 Apr 2016 22:36:42 +0000 (01:36 +0300)
committerDavid S. Miller <davem@davemloft.net>
Fri, 29 Apr 2016 20:29:12 +0000 (16:29 -0400)
Accelerated RFS requires that ntuple filtering is enabled via
ethtool and driver supports ndo_rx_flow_steer.
When the ntuple filtering is enabled, we modify the l3_l4 ttc
rules to point on the aRFS flow tables and when the filtering
is disabled, we modify the l3_l4 ttc rules to point on the RSS
TIRs.

Signed-off-by: Maor Gottlieb <maorg@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/mellanox/mlx5/core/en.h
drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c
drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
drivers/net/ethernet/mellanox/mlx5/core/en_main.c

index 21c38419ad89ffd22cba92b07f289ac6836dce4b..34523c48444e5e26032c767eb5ac8d92feb265c6 100644 (file)
@@ -690,9 +690,21 @@ static inline int mlx5e_arfs_create_tables(struct mlx5e_priv *priv)
 }
 
 static inline void mlx5e_arfs_destroy_tables(struct mlx5e_priv *priv) {}
+
+static inline int mlx5e_arfs_enable(struct mlx5e_priv *priv)
+{
+       return -ENOTSUPP;
+}
+
+static inline int mlx5e_arfs_disable(struct mlx5e_priv *priv)
+{
+       return -ENOTSUPP;
+}
 #else
 int mlx5e_arfs_create_tables(struct mlx5e_priv *priv);
 void mlx5e_arfs_destroy_tables(struct mlx5e_priv *priv);
+int mlx5e_arfs_enable(struct mlx5e_priv *priv);
+int mlx5e_arfs_disable(struct mlx5e_priv *priv);
 int mlx5e_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb,
                        u16 rxq_index, u32 flow_id);
 #endif
index e54fbc16f34dc3768762c4acae32da8d420e2506..b4ae0fe158789913bc0502761df9d4d81a9ec735 100644 (file)
@@ -72,14 +72,87 @@ struct arfs_rule {
        for (j = 0; j < ARFS_HASH_SIZE; j++) \
                hlist_for_each_entry_safe(hn, tmp, &hash[j], hlist)
 
+static enum mlx5e_traffic_types arfs_get_tt(enum arfs_type type)
+{
+       switch (type) {
+       case ARFS_IPV4_TCP:
+               return MLX5E_TT_IPV4_TCP;
+       case ARFS_IPV4_UDP:
+               return MLX5E_TT_IPV4_UDP;
+       case ARFS_IPV6_TCP:
+               return MLX5E_TT_IPV6_TCP;
+       case ARFS_IPV6_UDP:
+               return MLX5E_TT_IPV6_UDP;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int arfs_disable(struct mlx5e_priv *priv)
+{
+       struct mlx5_flow_destination dest;
+       u32 *tirn = priv->indir_tirn;
+       int err = 0;
+       int tt;
+       int i;
+
+       dest.type = MLX5_FLOW_DESTINATION_TYPE_TIR;
+       for (i = 0; i < ARFS_NUM_TYPES; i++) {
+               dest.tir_num = tirn[i];
+               tt = arfs_get_tt(i);
+               /* Modify ttc rules destination to bypass the aRFS tables*/
+               err = mlx5_modify_rule_destination(priv->fs.ttc.rules[tt],
+                                                  &dest);
+               if (err) {
+                       netdev_err(priv->netdev,
+                                  "%s: modify ttc destination failed\n",
+                                  __func__);
+                       return err;
+               }
+       }
+       return 0;
+}
+
+static void arfs_del_rules(struct mlx5e_priv *priv);
+
+int mlx5e_arfs_disable(struct mlx5e_priv *priv)
+{
+       arfs_del_rules(priv);
+
+       return arfs_disable(priv);
+}
+
+int mlx5e_arfs_enable(struct mlx5e_priv *priv)
+{
+       struct mlx5_flow_destination dest;
+       int err = 0;
+       int tt;
+       int i;
+
+       dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
+       for (i = 0; i < ARFS_NUM_TYPES; i++) {
+               dest.ft = priv->fs.arfs.arfs_tables[i].ft.t;
+               tt = arfs_get_tt(i);
+               /* Modify ttc rules destination to point on the aRFS FTs */
+               err = mlx5_modify_rule_destination(priv->fs.ttc.rules[tt],
+                                                  &dest);
+               if (err) {
+                       netdev_err(priv->netdev,
+                                  "%s: modify ttc destination failed err=%d\n",
+                                  __func__, err);
+                       arfs_disable(priv);
+                       return err;
+               }
+       }
+       return 0;
+}
+
 static void arfs_destroy_table(struct arfs_table *arfs_t)
 {
        mlx5_del_flow_rule(arfs_t->default_rule);
        mlx5e_destroy_flow_table(&arfs_t->ft);
 }
 
-static void arfs_del_rules(struct mlx5e_priv *priv);
-
 void mlx5e_arfs_destroy_tables(struct mlx5e_priv *priv)
 {
        int i;
index 498d40784ae95c22a959f5a88275bc82c2006930..534d99e2f9c8ba969d83dc4d3f410cbe733bbe16 100644 (file)
@@ -456,6 +456,7 @@ static int mlx5e_set_channels(struct net_device *dev,
        struct mlx5e_priv *priv = netdev_priv(dev);
        int ncv = mlx5e_get_max_num_channels(priv->mdev);
        unsigned int count = ch->combined_count;
+       bool arfs_enabled;
        bool was_opened;
        int err = 0;
 
@@ -484,13 +485,27 @@ static int mlx5e_set_channels(struct net_device *dev,
        if (was_opened)
                mlx5e_close_locked(dev);
 
+       arfs_enabled = dev->features & NETIF_F_NTUPLE;
+       if (arfs_enabled)
+               mlx5e_arfs_disable(priv);
+
        priv->params.num_channels = count;
        mlx5e_build_default_indir_rqt(priv->mdev, priv->params.indirection_rqt,
                                      MLX5E_INDIR_RQT_SIZE, count);
 
        if (was_opened)
                err = mlx5e_open_locked(dev);
+       if (err)
+               goto out;
 
+       if (arfs_enabled) {
+               err = mlx5e_arfs_enable(priv);
+               if (err)
+                       netdev_err(dev, "%s: mlx5e_arfs_enable failed: %d\n",
+                                  __func__, err);
+       }
+
+out:
        mutex_unlock(&priv->state_lock);
 
        return err;
index 20167b9403b6a545630dd29573774197ac8e83ba..4ccfc1ac62c5146a3d820446b215f7c1c3145ee3 100644 (file)
@@ -2308,6 +2308,21 @@ static int set_feature_rx_vlan(struct net_device *netdev, bool enable)
        return err;
 }
 
+#ifdef CONFIG_RFS_ACCEL
+static int set_feature_arfs(struct net_device *netdev, bool enable)
+{
+       struct mlx5e_priv *priv = netdev_priv(netdev);
+       int err;
+
+       if (enable)
+               err = mlx5e_arfs_enable(priv);
+       else
+               err = mlx5e_arfs_disable(priv);
+
+       return err;
+}
+#endif
+
 static int mlx5e_handle_feature(struct net_device *netdev,
                                netdev_features_t wanted_features,
                                netdev_features_t feature,
@@ -2347,6 +2362,10 @@ static int mlx5e_set_features(struct net_device *netdev,
                                    set_feature_rx_all);
        err |= mlx5e_handle_feature(netdev, features, NETIF_F_HW_VLAN_CTAG_RX,
                                    set_feature_rx_vlan);
+#ifdef CONFIG_RFS_ACCEL
+       err |= mlx5e_handle_feature(netdev, features, NETIF_F_NTUPLE,
+                                   set_feature_arfs);
+#endif
 
        return err ? -EINVAL : 0;
 }
@@ -2562,6 +2581,9 @@ static const struct net_device_ops mlx5e_netdev_ops_basic = {
        .ndo_set_features        = mlx5e_set_features,
        .ndo_change_mtu          = mlx5e_change_mtu,
        .ndo_do_ioctl            = mlx5e_ioctl,
+#ifdef CONFIG_RFS_ACCEL
+       .ndo_rx_flow_steer       = mlx5e_rx_flow_steer,
+#endif
 };
 
 static const struct net_device_ops mlx5e_netdev_ops_sriov = {
@@ -2581,6 +2603,9 @@ static const struct net_device_ops mlx5e_netdev_ops_sriov = {
        .ndo_add_vxlan_port      = mlx5e_add_vxlan_port,
        .ndo_del_vxlan_port      = mlx5e_del_vxlan_port,
        .ndo_features_check      = mlx5e_features_check,
+#ifdef CONFIG_RFS_ACCEL
+       .ndo_rx_flow_steer       = mlx5e_rx_flow_steer,
+#endif
        .ndo_set_vf_mac          = mlx5e_set_vf_mac,
        .ndo_set_vf_vlan         = mlx5e_set_vf_vlan,
        .ndo_get_vf_config       = mlx5e_get_vf_config,