net/mlx5e: Add PTP Flow Steering support
authorAya Levin <ayal@nvidia.com>
Tue, 16 Feb 2021 10:32:48 +0000 (12:32 +0200)
committerSaeed Mahameed <saeedm@nvidia.com>
Tue, 30 Mar 2021 04:21:53 +0000 (21:21 -0700)
When opening PTP channel with MLX5E_PTP_STATE_RX set, add the
corresponding flow steering rules. Capture UDP packets with destination
port 319 and L2 packets with ethertype 0x88F7 and steer them into the RQ
of the PTP channel.
Add API that manages the flow steering rules to be used in the following
patches via safe_reopen_channels mechanism.

Signed-off-by: Aya Levin <ayal@nvidia.com>
Reviewed-by: Tariq Toukan <tariqt@nvidia.com>
Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
drivers/net/ethernet/mellanox/mlx5/core/en/fs.h
drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c
drivers/net/ethernet/mellanox/mlx5/core/en/ptp.h
drivers/net/ethernet/mellanox/mlx5/core/en_fs.c

index c61fbb9c6fa8e710a823433816f0cb39fd1038cc..d53fb1e31b05b5d21384ca42b8f9d59c19954c2a 100644 (file)
@@ -245,6 +245,7 @@ struct mlx5e_accel_fs_tcp;
 
 struct mlx5e_fs_udp;
 struct mlx5e_fs_any;
+struct mlx5e_ptp_fs;
 
 struct mlx5e_flow_steering {
        struct mlx5_flow_namespace      *ns;
@@ -266,6 +267,7 @@ struct mlx5e_flow_steering {
 #endif
        struct mlx5e_fs_udp            *udp;
        struct mlx5e_fs_any            *any;
+       struct mlx5e_ptp_fs            *ptp_fs;
 };
 
 struct ttc_params {
index c1c41c8656dcb7ce9a1e3a70712dcf0d477e3112..995a0947b2d5a2e8fedd14069acab9cb55dc6e76 100644 (file)
@@ -1,9 +1,18 @@
 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
 // Copyright (c) 2020 Mellanox Technologies
 
+#include <linux/ptp_classify.h>
 #include "en/ptp.h"
 #include "en/txrx.h"
 #include "en/params.h"
+#include "en/fs_tt_redirect.h"
+
+struct mlx5e_ptp_fs {
+       struct mlx5_flow_handle *l2_rule;
+       struct mlx5_flow_handle *udp_v4_rule;
+       struct mlx5_flow_handle *udp_v6_rule;
+       bool valid;
+};
 
 #define MLX5E_PTP_CHANNEL_IX 0
 
@@ -573,6 +582,78 @@ static int mlx5e_ptp_set_state(struct mlx5e_ptp *c, struct mlx5e_params *params)
        return bitmap_empty(c->state, MLX5E_PTP_STATE_NUM_STATES) ? -EINVAL : 0;
 }
 
+static void mlx5e_ptp_rx_unset_fs(struct mlx5e_priv *priv)
+{
+       struct mlx5e_ptp_fs *ptp_fs = priv->fs.ptp_fs;
+
+       if (!ptp_fs->valid)
+               return;
+
+       mlx5e_fs_tt_redirect_del_rule(ptp_fs->l2_rule);
+       mlx5e_fs_tt_redirect_any_destroy(priv);
+
+       mlx5e_fs_tt_redirect_del_rule(ptp_fs->udp_v6_rule);
+       mlx5e_fs_tt_redirect_del_rule(ptp_fs->udp_v4_rule);
+       mlx5e_fs_tt_redirect_udp_destroy(priv);
+       ptp_fs->valid = false;
+}
+
+static int mlx5e_ptp_rx_set_fs(struct mlx5e_priv *priv)
+{
+       struct mlx5e_ptp_fs *ptp_fs = priv->fs.ptp_fs;
+       struct mlx5_flow_handle *rule;
+       u32 tirn = priv->ptp_tir.tirn;
+       int err;
+
+       if (ptp_fs->valid)
+               return 0;
+
+       err = mlx5e_fs_tt_redirect_udp_create(priv);
+       if (err)
+               goto out_free;
+
+       rule = mlx5e_fs_tt_redirect_udp_add_rule(priv, MLX5E_TT_IPV4_UDP,
+                                                tirn, PTP_EV_PORT);
+       if (IS_ERR(rule)) {
+               err = PTR_ERR(rule);
+               goto out_destroy_fs_udp;
+       }
+       ptp_fs->udp_v4_rule = rule;
+
+       rule = mlx5e_fs_tt_redirect_udp_add_rule(priv, MLX5E_TT_IPV6_UDP,
+                                                tirn, PTP_EV_PORT);
+       if (IS_ERR(rule)) {
+               err = PTR_ERR(rule);
+               goto out_destroy_udp_v4_rule;
+       }
+       ptp_fs->udp_v6_rule = rule;
+
+       err = mlx5e_fs_tt_redirect_any_create(priv);
+       if (err)
+               goto out_destroy_udp_v6_rule;
+
+       rule = mlx5e_fs_tt_redirect_any_add_rule(priv, tirn, ETH_P_1588);
+       if (IS_ERR(rule)) {
+               err = PTR_ERR(rule);
+               goto out_destroy_fs_any;
+       }
+       ptp_fs->l2_rule = rule;
+       ptp_fs->valid = true;
+
+       return 0;
+
+out_destroy_fs_any:
+       mlx5e_fs_tt_redirect_any_destroy(priv);
+out_destroy_udp_v6_rule:
+       mlx5e_fs_tt_redirect_del_rule(ptp_fs->udp_v6_rule);
+out_destroy_udp_v4_rule:
+       mlx5e_fs_tt_redirect_del_rule(ptp_fs->udp_v4_rule);
+out_destroy_fs_udp:
+       mlx5e_fs_tt_redirect_udp_destroy(priv);
+out_free:
+       return err;
+}
+
 int mlx5e_ptp_open(struct mlx5e_priv *priv, struct mlx5e_params *params,
                   u8 lag_port, struct mlx5e_ptp **cp)
 {
@@ -645,8 +726,10 @@ void mlx5e_ptp_activate_channel(struct mlx5e_ptp *c)
                for (tc = 0; tc < c->num_tc; tc++)
                        mlx5e_activate_txqsq(&c->ptpsq[tc].txqsq);
        }
-       if (test_bit(MLX5E_PTP_STATE_RX, c->state))
+       if (test_bit(MLX5E_PTP_STATE_RX, c->state)) {
+               mlx5e_ptp_rx_set_fs(c->priv);
                mlx5e_activate_rq(&c->rq);
+       }
 }
 
 void mlx5e_ptp_deactivate_channel(struct mlx5e_ptp *c)
@@ -672,3 +755,52 @@ int mlx5e_ptp_get_rqn(struct mlx5e_ptp *c, u32 *rqn)
        *rqn = c->rq.rqn;
        return 0;
 }
+
+int mlx5e_ptp_alloc_rx_fs(struct mlx5e_priv *priv)
+{
+       struct mlx5e_ptp_fs *ptp_fs;
+
+       if (!priv->profile->rx_ptp_support)
+               return 0;
+
+       ptp_fs = kzalloc(sizeof(*ptp_fs), GFP_KERNEL);
+       if (!ptp_fs)
+               return -ENOMEM;
+
+       priv->fs.ptp_fs = ptp_fs;
+       return 0;
+}
+
+void mlx5e_ptp_free_rx_fs(struct mlx5e_priv *priv)
+{
+       struct mlx5e_ptp_fs *ptp_fs = priv->fs.ptp_fs;
+
+       if (!priv->profile->rx_ptp_support)
+               return;
+
+       mlx5e_ptp_rx_unset_fs(priv);
+       kfree(ptp_fs);
+}
+
+int mlx5e_ptp_rx_manage_fs(struct mlx5e_priv *priv, bool set)
+{
+       struct mlx5e_ptp *c = priv->channels.ptp;
+
+       if (!priv->profile->rx_ptp_support)
+               return 0;
+
+       if (set) {
+               if (!c || !test_bit(MLX5E_PTP_STATE_RX, c->state)) {
+                       netdev_WARN_ONCE(priv->netdev, "Don't try to add PTP RX-FS rules");
+                       return -EINVAL;
+               }
+               return mlx5e_ptp_rx_set_fs(priv);
+       }
+       /* set == false */
+       if (c && test_bit(MLX5E_PTP_STATE_RX, c->state)) {
+               netdev_WARN_ONCE(priv->netdev, "Don't try to remove PTP RX-FS rules");
+               return -EINVAL;
+       }
+       mlx5e_ptp_rx_unset_fs(priv);
+       return 0;
+}
index 460b167887bc18f0221546a0e5e5ca67810d3b87..ab935cce952b4ef5c78224f0296c58b9897f8e1f 100644 (file)
@@ -49,6 +49,9 @@ void mlx5e_ptp_close(struct mlx5e_ptp *c);
 void mlx5e_ptp_activate_channel(struct mlx5e_ptp *c);
 void mlx5e_ptp_deactivate_channel(struct mlx5e_ptp *c);
 int mlx5e_ptp_get_rqn(struct mlx5e_ptp *c, u32 *rqn);
+int mlx5e_ptp_alloc_rx_fs(struct mlx5e_priv *priv);
+void mlx5e_ptp_free_rx_fs(struct mlx5e_priv *priv);
+int mlx5e_ptp_rx_manage_fs(struct mlx5e_priv *priv, bool set);
 
 enum {
        MLX5E_SKB_CB_CQE_HWTSTAMP  = BIT(0),
index cf1d3c9c88af3f21b9f80c19913ccf2d0ba96ad7..98f0b857947e9398dec1bf157b9cc8cb98e3c1f5 100644 (file)
@@ -38,6 +38,7 @@
 #include "en.h"
 #include "en_rep.h"
 #include "lib/mpfs.h"
+#include "en/ptp.h"
 
 static int mlx5e_add_l2_flow_rule(struct mlx5e_priv *priv,
                                  struct mlx5e_l2_rule *ai, int type);
@@ -1792,10 +1793,16 @@ int mlx5e_create_flow_steering(struct mlx5e_priv *priv)
                goto err_destroy_l2_table;
        }
 
+       err = mlx5e_ptp_alloc_rx_fs(priv);
+       if (err)
+               goto err_destory_vlan_table;
+
        mlx5e_ethtool_init_steering(priv);
 
        return 0;
 
+err_destory_vlan_table:
+       mlx5e_destroy_vlan_table(priv);
 err_destroy_l2_table:
        mlx5e_destroy_l2_table(priv);
 err_destroy_ttc_table:
@@ -1810,6 +1817,7 @@ err_destroy_arfs_tables:
 
 void mlx5e_destroy_flow_steering(struct mlx5e_priv *priv)
 {
+       mlx5e_ptp_free_rx_fs(priv);
        mlx5e_destroy_vlan_table(priv);
        mlx5e_destroy_l2_table(priv);
        mlx5e_destroy_ttc_table(priv, &priv->fs.ttc);