net/mlx5e: Restrict the combination of large MTU and XDP
authorTariq Toukan <tariqt@mellanox.com>
Sun, 31 Dec 2017 13:50:13 +0000 (15:50 +0200)
committerSaeed Mahameed <saeedm@mellanox.com>
Thu, 26 Jul 2018 22:23:53 +0000 (15:23 -0700)
Add checks in control path upon an MTU change or an XDP program set,
to prevent reaching cases where large MTU and XDP are set simultaneously.

This is to make sure we allow XDP only with the linear RX memory scheme,
i.e. a received packet is not scattered to different pages.
Change mlx5e_rx_get_linear_frag_sz() accordingly, so that we make sure
the XDP configuration can really be set, instead of assuming that it is.

Signed-off-by: Tariq Toukan <tariqt@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
drivers/net/ethernet/mellanox/mlx5/core/en.h
drivers/net/ethernet/mellanox/mlx5/core/en_main.c

index dc9aa070eafa5439a4ce9b110c7ceec3ca455b04..7840f6f44379251df9340647078e6e5c8752b304 100644 (file)
@@ -72,6 +72,8 @@ struct page_pool;
 #define MLX5_RX_HEADROOM NET_SKB_PAD
 #define MLX5_SKB_FRAG_SZ(len)  (SKB_DATA_ALIGN(len) +  \
                                 SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
+#define MLX5E_XDP_MAX_MTU ((int)(PAGE_SIZE - \
+                                MLX5_SKB_FRAG_SZ(XDP_PACKET_HEADROOM)))
 
 #define MLX5_MPWRQ_MIN_LOG_STRIDE_SZ(mdev) \
        (6 + MLX5_CAP_GEN(mdev, cache_line_128byte)) /* HW restriction */
index a1a54ea3aeb489c7e4020ee60630a6c129100bfe..56ae6e428fdfb897a72b87f0f6c6f585316e1c85 100644 (file)
@@ -96,14 +96,19 @@ bool mlx5e_check_fragmented_striding_rq_cap(struct mlx5_core_dev *mdev)
 
 static u32 mlx5e_rx_get_linear_frag_sz(struct mlx5e_params *params)
 {
-       if (!params->xdp_prog) {
-               u16 hw_mtu = MLX5E_SW2HW_MTU(params, params->sw_mtu);
-               u16 rq_headroom = MLX5_RX_HEADROOM + NET_IP_ALIGN;
+       u16 hw_mtu = MLX5E_SW2HW_MTU(params, params->sw_mtu);
+       u16 linear_rq_headroom = params->xdp_prog ?
+               XDP_PACKET_HEADROOM : MLX5_RX_HEADROOM;
+       u32 frag_sz;
 
-               return MLX5_SKB_FRAG_SZ(rq_headroom + hw_mtu);
-       }
+       linear_rq_headroom += NET_IP_ALIGN;
 
-       return PAGE_SIZE;
+       frag_sz = MLX5_SKB_FRAG_SZ(linear_rq_headroom + hw_mtu);
+
+       if (params->xdp_prog && frag_sz < PAGE_SIZE)
+               frag_sz = PAGE_SIZE;
+
+       return frag_sz;
 }
 
 static u8 mlx5e_mpwqe_log_pkts_per_wqe(struct mlx5e_params *params)
@@ -3707,6 +3712,14 @@ int mlx5e_change_mtu(struct net_device *netdev, int new_mtu,
        new_channels.params = *params;
        new_channels.params.sw_mtu = new_mtu;
 
+       if (params->xdp_prog &&
+           !mlx5e_rx_is_linear_skb(priv->mdev, &new_channels.params)) {
+               netdev_err(netdev, "MTU(%d) > %d is not allowed while XDP enabled\n",
+                          new_mtu, MLX5E_XDP_MAX_MTU);
+               err = -EINVAL;
+               goto out;
+       }
+
        if (params->rq_wq_type == MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ) {
                u8 ppw_old = mlx5e_mpwqe_log_pkts_per_wqe(params);
                u8 ppw_new = mlx5e_mpwqe_log_pkts_per_wqe(&new_channels.params);
@@ -4094,9 +4107,10 @@ static void mlx5e_tx_timeout(struct net_device *dev)
        queue_work(priv->wq, &priv->tx_timeout_work);
 }
 
-static int mlx5e_xdp_allowed(struct mlx5e_priv *priv)
+static int mlx5e_xdp_allowed(struct mlx5e_priv *priv, struct bpf_prog *prog)
 {
        struct net_device *netdev = priv->netdev;
+       struct mlx5e_channels new_channels = {};
 
        if (priv->channels.params.lro_en) {
                netdev_warn(netdev, "can't set XDP while LRO is on, disable LRO first\n");
@@ -4108,6 +4122,15 @@ static int mlx5e_xdp_allowed(struct mlx5e_priv *priv)
                return -EINVAL;
        }
 
+       new_channels.params = priv->channels.params;
+       new_channels.params.xdp_prog = prog;
+
+       if (!mlx5e_rx_is_linear_skb(priv->mdev, &new_channels.params)) {
+               netdev_warn(netdev, "XDP is not allowed with MTU(%d) > %d\n",
+                           new_channels.params.sw_mtu, MLX5E_XDP_MAX_MTU);
+               return -EINVAL;
+       }
+
        return 0;
 }
 
@@ -4122,7 +4145,7 @@ static int mlx5e_xdp_set(struct net_device *netdev, struct bpf_prog *prog)
        mutex_lock(&priv->state_lock);
 
        if (prog) {
-               err = mlx5e_xdp_allowed(priv);
+               err = mlx5e_xdp_allowed(priv, prog);
                if (err)
                        goto unlock;
        }