net/mlx5e: XDP, fix redirect resources availability check [Linux 5.0]

net/mlx5e: XDP, fix redirect resources availability check [Linux 5.0]

This Linux kernel change "net/mlx5e: XDP, fix redirect resources availability check" is included in the Linux 5.0 release. This change is authored by Saeed Mahameed <saeedm [at] mellanox.com> on Mon Feb 11 16:27:02 2019 -0800. The commit for this change in Linux stable tree is 407e17b (patch).

net/mlx5e: XDP, fix redirect resources availability check

Currently mlx5 driver creates xdp redirect hw queues unconditionally on
netdevice open, This is great until someone starts redirecting XDP traffic
via ndo_xdp_xmit on mlx5 device and changes the device configuration at
the same time, this might cause crashes, since the other device's napi
is not aware of the mlx5 state change (resources un-availability).

To fix this we must synchronize with other devices napi's on the system.
Added a new flag under mlx5e_priv to determine XDP TX resources are
available, set/clear it up when necessary and use synchronize_rcu()
when the flag is turned off, so other napi's are in-sync with it, before
we actually cleanup the hw resources.

The flag is tested prior to committing to transmit on mlx5e_xdp_xmit, and
it is sufficient to determine if it safe to transmit or not. The other
two internal flags (MLX5E_STATE_OPENED and MLX5E_SQ_STATE_ENABLED) become
unnecessary. Thus, they are removed from data path.

Fixes: 58b99ee3e3eb ("net/mlx5e: Add support for XDP_REDIRECT in device-out side")
Reported-by: Toke Høiland-Jørgensen <[email protected]>
Reviewed-by: Tariq Toukan <[email protected]>
Signed-off-by: Saeed Mahameed <[email protected]>

There are 26 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 drivers/net/ethernet/mellanox/mlx5/core/en.h      |  1 +
 drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c  |  6 ++----
 drivers/net/ethernet/mellanox/mlx5/core/en/xdp.h  | 17 +++++++++++++++++
 drivers/net/ethernet/mellanox/mlx5/core/en_main.c |  2 ++
 4 files changed, 22 insertions(+), 4 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h
index 8fa8fdd..448a925 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h
@@ -657,6 +657,7 @@ struct mlx5e_channel_stats {
 enum {
    MLX5E_STATE_OPENED,
    MLX5E_STATE_DESTROYING,
+   MLX5E_STATE_XDP_TX_ENABLED,
 };

 struct mlx5e_rqt {
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c
index 3740177..03b2a9f 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c
@@ -365,7 +365,8 @@ int mlx5e_xdp_xmit(struct net_device *dev, int n, struct xdp_frame **frames,
    int sq_num;
    int i;

-   if (unlikely(!test_bit(MLX5E_STATE_OPENED, &priv->state)))
+   /* this flag is sufficient, no need to test internal sq state */
+   if (unlikely(!mlx5e_xdp_tx_is_enabled(priv)))
        return -ENETDOWN;

    if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK))
@@ -378,9 +379,6 @@ int mlx5e_xdp_xmit(struct net_device *dev, int n, struct xdp_frame **frames,

    sq = &priv->channels.c[sq_num]->xdpsq;

-   if (unlikely(!test_bit(MLX5E_SQ_STATE_ENABLED, &sq->state)))
-       return -ENETDOWN;
-
    for (i = 0; i < n; i++) {
        struct xdp_frame *xdpf = frames[i];
        struct mlx5e_xdp_info xdpi;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.h b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.h
index 3a67cb3..ee27a7c 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.h
@@ -50,6 +50,23 @@ bool mlx5e_xdp_handle(struct mlx5e_rq *rq, struct mlx5e_dma_info *di,
 int mlx5e_xdp_xmit(struct net_device *dev, int n, struct xdp_frame **frames,
           u32 flags);

+static inline void mlx5e_xdp_tx_enable(struct mlx5e_priv *priv)
+{
+   set_bit(MLX5E_STATE_XDP_TX_ENABLED, &priv->state);
+}
+
+static inline void mlx5e_xdp_tx_disable(struct mlx5e_priv *priv)
+{
+   clear_bit(MLX5E_STATE_XDP_TX_ENABLED, &priv->state);
+   /* let other device's napi(s) see our new state */
+   synchronize_rcu();
+}
+
+static inline bool mlx5e_xdp_tx_is_enabled(struct mlx5e_priv *priv)
+{
+   return test_bit(MLX5E_STATE_XDP_TX_ENABLED, &priv->state);
+}
+
 static inline void mlx5e_xmit_xdp_doorbell(struct mlx5e_xdpsq *sq)
 {
    if (sq->doorbell_cseg) {
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index 01819e5..93e50cc 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -2938,6 +2938,7 @@ void mlx5e_activate_priv_channels(struct mlx5e_priv *priv)

    mlx5e_build_tx2sq_maps(priv);
    mlx5e_activate_channels(&priv->channels);
+   mlx5e_xdp_tx_enable(priv);
    netif_tx_start_all_queues(priv->netdev);

    if (mlx5e_is_vport_rep(priv))
@@ -2959,6 +2960,7 @@ void mlx5e_deactivate_priv_channels(struct mlx5e_priv *priv)
     */
    netif_tx_stop_all_queues(priv->netdev);
    netif_tx_disable(priv->netdev);
+   mlx5e_xdp_tx_disable(priv);
    mlx5e_deactivate_channels(&priv->channels);
 }

Leave a Reply

Your email address will not be published. Required fields are marked *