OSDN Git Service

net/mlx5e: Add mirred/redirect to tc action infra
authorRoi Dayan <roid@nvidia.com>
Wed, 21 Jul 2021 07:27:50 +0000 (10:27 +0300)
committerSaeed Mahameed <saeedm@nvidia.com>
Wed, 15 Dec 2021 05:29:43 +0000 (21:29 -0800)
Add parsing support by implementing struct mlx5e_tc_act
for this action.

Signed-off-by: Roi Dayan <roid@nvidia.com>
Reviewed-by: Oz Shlomo <ozsh@nvidia.com>
Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
drivers/net/ethernet/mellanox/mlx5/core/Makefile
drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/act.c
drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/act.h
drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/mirred.c [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/mirred_nic.c [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c

index 530acd0..8712a5c 100644 (file)
@@ -50,7 +50,8 @@ mlx5_core-$(CONFIG_MLX5_CLS_ACT)     += en_tc.o en/rep/tc.o en/rep/neigh.o \
 mlx5_core-$(CONFIG_MLX5_CLS_ACT)     += en/tc/act/act.o en/tc/act/drop.o en/tc/act/trap.o \
                                        en/tc/act/accept.o en/tc/act/mark.o en/tc/act/goto.o \
                                        en/tc/act/tun.o en/tc/act/csum.o en/tc/act/pedit.o \
-                                       en/tc/act/vlan.o en/tc/act/vlan_mangle.o en/tc/act/mpls.o
+                                       en/tc/act/vlan.o en/tc/act/vlan_mangle.o en/tc/act/mpls.o \
+                                       en/tc/act/mirred.o en/tc/act/mirred_nic.o
 
 mlx5_core-$(CONFIG_MLX5_TC_CT)      += en/tc_ct.o
 mlx5_core-$(CONFIG_MLX5_TC_SAMPLE)   += en/tc/sample.o
index e4a96f2..70a3622 100644 (file)
@@ -11,8 +11,8 @@ static struct mlx5e_tc_act *tc_acts_fdb[NUM_FLOW_ACTIONS] = {
        &mlx5e_tc_act_drop,
        &mlx5e_tc_act_trap,
        &mlx5e_tc_act_goto,
-       NULL, /* FLOW_ACTION_REDIRECT, */
-       NULL, /* FLOW_ACTION_MIRRED, */
+       &mlx5e_tc_act_mirred,
+       &mlx5e_tc_act_mirred,
        NULL, /* FLOW_ACTION_REDIRECT_INGRESS, */
        NULL, /* FLOW_ACTION_MIRRED_INGRESS, */
        &mlx5e_tc_act_vlan,
@@ -42,7 +42,7 @@ static struct mlx5e_tc_act *tc_acts_nic[NUM_FLOW_ACTIONS] = {
        &mlx5e_tc_act_drop,
        NULL, /* FLOW_ACTION_TRAP, */
        &mlx5e_tc_act_goto,
-       NULL, /* FLOW_ACTION_REDIRECT, */
+       &mlx5e_tc_act_mirred_nic,
        NULL, /* FLOW_ACTION_MIRRED, */
        NULL, /* FLOW_ACTION_REDIRECT_INGRESS, */
        NULL, /* FLOW_ACTION_MIRRED_INGRESS, */
index a442a28..b57f22c 100644 (file)
@@ -21,6 +21,8 @@ struct mlx5e_tc_act_parse_state {
        bool mpls_push;
        const struct ip_tunnel_info *tun_info;
        struct pedit_headers_action hdrs[__PEDIT_CMD_MAX];
+       int ifindexes[MLX5_MAX_FLOW_FWD_VPORTS];
+       int if_count;
 };
 
 struct mlx5e_tc_act {
@@ -47,6 +49,8 @@ extern struct mlx5e_tc_act mlx5e_tc_act_vlan;
 extern struct mlx5e_tc_act mlx5e_tc_act_vlan_mangle;
 extern struct mlx5e_tc_act mlx5e_tc_act_mpls_push;
 extern struct mlx5e_tc_act mlx5e_tc_act_mpls_pop;
+extern struct mlx5e_tc_act mlx5e_tc_act_mirred;
+extern struct mlx5e_tc_act mlx5e_tc_act_mirred_nic;
 
 struct mlx5e_tc_act *
 mlx5e_tc_act_get(enum flow_action_id act_id,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/mirred.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/mirred.c
new file mode 100644 (file)
index 0000000..a0832b8
--- /dev/null
@@ -0,0 +1,315 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+// Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+#include <linux/if_macvlan.h>
+#include <linux/if_vlan.h>
+#include <net/bareudp.h>
+#include <net/bonding.h>
+#include "act.h"
+#include "vlan.h"
+#include "en/tc_tun_encap.h"
+#include "en/tc_priv.h"
+#include "en_rep.h"
+
+static bool
+same_vf_reps(struct mlx5e_priv *priv, struct net_device *out_dev)
+{
+       return mlx5e_eswitch_vf_rep(priv->netdev) &&
+              priv->netdev == out_dev;
+}
+
+static int
+verify_uplink_forwarding(struct mlx5e_priv *priv,
+                        struct mlx5_flow_attr *attr,
+                        struct net_device *out_dev,
+                        struct netlink_ext_ack *extack)
+{
+       struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
+       struct mlx5e_rep_priv *rep_priv;
+
+       /* Forwarding non encapsulated traffic between
+        * uplink ports is allowed only if
+        * termination_table_raw_traffic cap is set.
+        *
+        * Input vport was stored attr->in_rep.
+        * In LAG case, *priv* is the private data of
+        * uplink which may be not the input vport.
+        */
+       rep_priv = mlx5e_rep_to_rep_priv(attr->esw_attr->in_rep);
+
+       if (!(mlx5e_eswitch_uplink_rep(rep_priv->netdev) &&
+             mlx5e_eswitch_uplink_rep(out_dev)))
+               return 0;
+
+       if (!MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev,
+                                       termination_table_raw_traffic)) {
+               NL_SET_ERR_MSG_MOD(extack,
+                                  "devices are both uplink, can't offload forwarding");
+                       pr_err("devices %s %s are both uplink, can't offload forwarding\n",
+                              priv->netdev->name, out_dev->name);
+                       return -EOPNOTSUPP;
+       } else if (out_dev != rep_priv->netdev) {
+               NL_SET_ERR_MSG_MOD(extack,
+                                  "devices are not the same uplink, can't offload forwarding");
+               pr_err("devices %s %s are both uplink but not the same, can't offload forwarding\n",
+                      priv->netdev->name, out_dev->name);
+               return -EOPNOTSUPP;
+       }
+       return 0;
+}
+
+static bool
+is_duplicated_output_device(struct net_device *dev,
+                           struct net_device *out_dev,
+                           int *ifindexes, int if_count,
+                           struct netlink_ext_ack *extack)
+{
+       int i;
+
+       for (i = 0; i < if_count; i++) {
+               if (ifindexes[i] == out_dev->ifindex) {
+                       NL_SET_ERR_MSG_MOD(extack, "can't duplicate output to same device");
+                       netdev_err(dev, "can't duplicate output to same device: %s\n",
+                                  out_dev->name);
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+static struct net_device *
+get_fdb_out_dev(struct net_device *uplink_dev, struct net_device *out_dev)
+{
+       struct net_device *fdb_out_dev = out_dev;
+       struct net_device *uplink_upper;
+
+       rcu_read_lock();
+       uplink_upper = netdev_master_upper_dev_get_rcu(uplink_dev);
+       if (uplink_upper && netif_is_lag_master(uplink_upper) &&
+           uplink_upper == out_dev) {
+               fdb_out_dev = uplink_dev;
+       } else if (netif_is_lag_master(out_dev)) {
+               fdb_out_dev = bond_option_active_slave_get_rcu(netdev_priv(out_dev));
+               if (fdb_out_dev &&
+                   (!mlx5e_eswitch_rep(fdb_out_dev) ||
+                    !netdev_port_same_parent_id(fdb_out_dev, uplink_dev)))
+                       fdb_out_dev = NULL;
+       }
+       rcu_read_unlock();
+       return fdb_out_dev;
+}
+
+static bool
+tc_act_can_offload_mirred(struct mlx5e_tc_act_parse_state *parse_state,
+                         const struct flow_action_entry *act,
+                         int act_index)
+{
+       struct netlink_ext_ack *extack = parse_state->extack;
+       struct mlx5e_tc_flow *flow = parse_state->flow;
+       struct mlx5e_tc_flow_parse_attr *parse_attr;
+       struct net_device *out_dev = act->dev;
+       struct mlx5e_priv *priv = flow->priv;
+       struct mlx5_esw_flow_attr *esw_attr;
+
+       parse_attr = flow->attr->parse_attr;
+       esw_attr = flow->attr->esw_attr;
+
+       if (!out_dev) {
+               /* out_dev is NULL when filters with
+                * non-existing mirred device are replayed to
+                * the driver.
+                */
+               return false;
+       }
+
+       if (parse_state->mpls_push && !netif_is_bareudp(out_dev)) {
+               NL_SET_ERR_MSG_MOD(extack, "mpls is supported only through a bareudp device");
+               return false;
+       }
+
+       if (mlx5e_is_ft_flow(flow) && out_dev == priv->netdev) {
+               /* Ignore forward to self rules generated
+                * by adding both mlx5 devs to the flow table
+                * block on a normal nft offload setup.
+                */
+               return false;
+       }
+
+       if (esw_attr->out_count >= MLX5_MAX_FLOW_FWD_VPORTS) {
+               NL_SET_ERR_MSG_MOD(extack,
+                                  "can't support more output ports, can't offload forwarding");
+               netdev_warn(priv->netdev,
+                           "can't support more than %d output ports, can't offload forwarding\n",
+                           esw_attr->out_count);
+               return false;
+       }
+
+       if (parse_state->encap ||
+           netdev_port_same_parent_id(priv->netdev, out_dev) ||
+           netif_is_ovs_master(out_dev))
+               return true;
+
+       if (parse_attr->filter_dev != priv->netdev) {
+               /* All mlx5 devices are called to configure
+                * high level device filters. Therefore, the
+                * *attempt* to  install a filter on invalid
+                * eswitch should not trigger an explicit error
+                */
+               return false;
+       }
+
+       NL_SET_ERR_MSG_MOD(extack, "devices are not on same switch HW, can't offload forwarding");
+       netdev_warn(priv->netdev,
+                   "devices %s %s not on same switch HW, can't offload forwarding\n",
+                   netdev_name(priv->netdev),
+                   out_dev->name);
+
+       return false;
+}
+
+static int
+parse_mirred_encap(struct mlx5e_tc_act_parse_state *parse_state,
+                  const struct flow_action_entry *act,
+                  struct mlx5_flow_attr *attr)
+{
+       struct mlx5e_tc_flow_parse_attr *parse_attr = attr->parse_attr;
+       struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr;
+       struct net_device *out_dev = act->dev;
+
+       parse_attr->mirred_ifindex[esw_attr->out_count] = out_dev->ifindex;
+       parse_attr->tun_info[esw_attr->out_count] =
+               mlx5e_dup_tun_info(parse_state->tun_info);
+
+       if (!parse_attr->tun_info[esw_attr->out_count])
+               return -ENOMEM;
+
+       parse_state->encap = false;
+       esw_attr->dests[esw_attr->out_count].flags |= MLX5_ESW_DEST_ENCAP;
+       esw_attr->out_count++;
+       /* attr->dests[].rep is resolved when we handle encap */
+
+       return 0;
+}
+
+static int
+parse_mirred(struct mlx5e_tc_act_parse_state *parse_state,
+            const struct flow_action_entry *act,
+            struct mlx5e_priv *priv,
+            struct mlx5_flow_attr *attr)
+{
+       struct mlx5e_tc_flow_parse_attr *parse_attr = attr->parse_attr;
+       struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr;
+       struct netlink_ext_ack *extack = parse_state->extack;
+       struct mlx5e_rep_priv *rpriv = priv->ppriv;
+       struct net_device *out_dev = act->dev;
+       struct net_device *uplink_dev;
+       struct mlx5e_priv *out_priv;
+       struct mlx5_eswitch *esw;
+       int *ifindexes;
+       int if_count;
+       int err;
+
+       esw = priv->mdev->priv.eswitch;
+       uplink_dev = mlx5_eswitch_uplink_get_proto_dev(esw, REP_ETH);
+       ifindexes = parse_state->ifindexes;
+       if_count = parse_state->if_count;
+
+       if (is_duplicated_output_device(priv->netdev, out_dev, ifindexes, if_count, extack))
+               return -EOPNOTSUPP;
+
+       parse_state->ifindexes[if_count] = out_dev->ifindex;
+       parse_state->if_count++;
+
+       out_dev = get_fdb_out_dev(uplink_dev, out_dev);
+       if (!out_dev)
+               return -ENODEV;
+
+       if (is_vlan_dev(out_dev)) {
+               err = mlx5e_tc_act_vlan_add_push_action(priv, attr, &out_dev, extack);
+               if (err)
+                       return err;
+       }
+
+       if (is_vlan_dev(parse_attr->filter_dev)) {
+               err = mlx5e_tc_act_vlan_add_pop_action(priv, attr, extack);
+               if (err)
+                       return err;
+       }
+
+       if (netif_is_macvlan(out_dev))
+               out_dev = macvlan_dev_real_dev(out_dev);
+
+       err = verify_uplink_forwarding(priv, attr, out_dev, extack);
+       if (err)
+               return err;
+
+       if (!mlx5e_is_valid_eswitch_fwd_dev(priv, out_dev)) {
+               NL_SET_ERR_MSG_MOD(extack,
+                                  "devices are not on same switch HW, can't offload forwarding");
+               return -EOPNOTSUPP;
+       }
+
+       if (same_vf_reps(priv, out_dev)) {
+               NL_SET_ERR_MSG_MOD(extack, "can't forward from a VF to itself");
+               return -EOPNOTSUPP;
+       }
+
+       out_priv = netdev_priv(out_dev);
+       rpriv = out_priv->ppriv;
+       esw_attr->dests[esw_attr->out_count].rep = rpriv->rep;
+       esw_attr->dests[esw_attr->out_count].mdev = out_priv->mdev;
+       esw_attr->out_count++;
+
+       return 0;
+}
+
+static int
+parse_mirred_ovs_master(struct mlx5e_tc_act_parse_state *parse_state,
+                       const struct flow_action_entry *act,
+                       struct mlx5e_priv *priv,
+                       struct mlx5_flow_attr *attr)
+{
+       struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr;
+       struct net_device *out_dev = act->dev;
+       int err;
+
+       err = mlx5e_set_fwd_to_int_port_actions(priv, attr, out_dev->ifindex,
+                                               MLX5E_TC_INT_PORT_EGRESS,
+                                               &attr->action, esw_attr->out_count);
+       if (err)
+               return err;
+
+       esw_attr->out_count++;
+       return 0;
+}
+
+static int
+tc_act_parse_mirred(struct mlx5e_tc_act_parse_state *parse_state,
+                   const struct flow_action_entry *act,
+                   struct mlx5e_priv *priv,
+                   struct mlx5_flow_attr *attr)
+{
+       struct net_device *out_dev = act->dev;
+       int err = -EOPNOTSUPP;
+
+       if (parse_state->encap)
+               err = parse_mirred_encap(parse_state, act, attr);
+       else if (netdev_port_same_parent_id(priv->netdev, out_dev))
+               err = parse_mirred(parse_state, act, priv, attr);
+       else if (netif_is_ovs_master(out_dev))
+               err = parse_mirred_ovs_master(parse_state, act, priv, attr);
+
+       if (err)
+               return err;
+
+       attr->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
+                       MLX5_FLOW_CONTEXT_ACTION_COUNT;
+
+       return 0;
+}
+
+struct mlx5e_tc_act mlx5e_tc_act_mirred = {
+       .can_offload = tc_act_can_offload_mirred,
+       .parse_action = tc_act_parse_mirred,
+};
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/mirred_nic.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/mirred_nic.c
new file mode 100644 (file)
index 0000000..2c74567
--- /dev/null
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+// Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+#include "act.h"
+#include "en/tc_priv.h"
+
+static bool
+tc_act_can_offload_mirred_nic(struct mlx5e_tc_act_parse_state *parse_state,
+                             const struct flow_action_entry *act,
+                             int act_index)
+{
+       struct netlink_ext_ack *extack = parse_state->extack;
+       struct mlx5e_tc_flow *flow = parse_state->flow;
+       struct net_device *out_dev = act->dev;
+       struct mlx5e_priv *priv = flow->priv;
+
+       if (act->id != FLOW_ACTION_REDIRECT)
+               return false;
+
+       if (priv->netdev->netdev_ops != out_dev->netdev_ops ||
+           !mlx5e_same_hw_devs(priv, netdev_priv(out_dev))) {
+               NL_SET_ERR_MSG_MOD(extack,
+                                  "devices are not on same switch HW, can't offload forwarding");
+               netdev_warn(priv->netdev,
+                           "devices %s %s not on same switch HW, can't offload forwarding\n",
+                           netdev_name(priv->netdev),
+                           out_dev->name);
+               return false;
+       }
+
+       return true;
+}
+
+static int
+tc_act_parse_mirred_nic(struct mlx5e_tc_act_parse_state *parse_state,
+                       const struct flow_action_entry *act,
+                       struct mlx5e_priv *priv,
+                       struct mlx5_flow_attr *attr)
+{
+       attr->parse_attr->mirred_ifindex[0] = act->dev->ifindex;
+       flow_flag_set(parse_state->flow, HAIRPIN);
+       attr->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
+                       MLX5_FLOW_CONTEXT_ACTION_COUNT;
+
+       return 0;
+}
+
+struct mlx5e_tc_act mlx5e_tc_act_mirred_nic = {
+       .can_offload = tc_act_can_offload_mirred_nic,
+       .parse_action = tc_act_parse_mirred_nic,
+};
index 21adbdf..f832c26 100644 (file)
@@ -123,6 +123,7 @@ bool mlx5e_is_eswitch_flow(struct mlx5e_tc_flow *flow);
 bool mlx5e_is_ft_flow(struct mlx5e_tc_flow *flow);
 bool mlx5e_is_offloaded_flow(struct mlx5e_tc_flow *flow);
 int mlx5e_get_flow_namespace(struct mlx5e_tc_flow *flow);
+bool mlx5e_same_hw_devs(struct mlx5e_priv *priv, struct mlx5e_priv *peer_priv);
 
 static inline void __flow_flag_set(struct mlx5e_tc_flow *flow, unsigned long flag)
 {
index 9602d2f..d1e8030 100644 (file)
@@ -39,7 +39,6 @@
 #include <linux/rhashtable.h>
 #include <linux/refcount.h>
 #include <linux/completion.h>
-#include <linux/if_macvlan.h>
 #include <net/psample.h>
 #include <net/arp.h>
 #include <net/ipv6_stubs.h>
@@ -1302,8 +1301,6 @@ static void remove_unready_flow(struct mlx5e_tc_flow *flow)
        mutex_unlock(&uplink_priv->unready_flows_lock);
 }
 
-static bool same_hw_devs(struct mlx5e_priv *priv, struct mlx5e_priv *peer_priv);
-
 bool mlx5e_tc_is_vf_tunnel(struct net_device *out_dev, struct net_device *route_dev)
 {
        struct mlx5_core_dev *out_mdev, *route_mdev;
@@ -1318,7 +1315,7 @@ bool mlx5e_tc_is_vf_tunnel(struct net_device *out_dev, struct net_device *route_
            route_mdev->coredev_type != MLX5_COREDEV_VF)
                return false;
 
-       return same_hw_devs(out_priv, route_priv);
+       return mlx5e_same_hw_devs(out_priv, route_priv);
 }
 
 int mlx5e_tc_query_route_vport(struct net_device *out_dev, struct net_device *route_dev, u16 *vport)
@@ -3104,7 +3101,7 @@ static bool same_port_devs(struct mlx5e_priv *priv, struct mlx5e_priv *peer_priv
        return priv->mdev == peer_priv->mdev;
 }
 
-static bool same_hw_devs(struct mlx5e_priv *priv, struct mlx5e_priv *peer_priv)
+bool mlx5e_same_hw_devs(struct mlx5e_priv *priv, struct mlx5e_priv *peer_priv)
 {
        struct mlx5_core_dev *fmdev, *pmdev;
        u64 fsystem_guid, psystem_guid;
@@ -3118,13 +3115,6 @@ static bool same_hw_devs(struct mlx5e_priv *priv, struct mlx5e_priv *peer_priv)
        return (fsystem_guid == psystem_guid);
 }
 
-static bool same_vf_reps(struct mlx5e_priv *priv,
-                        struct net_device *out_dev)
-{
-       return mlx5e_eswitch_vf_rep(priv->netdev) &&
-              priv->netdev == out_dev;
-}
-
 static int
 add_vlan_prio_tag_rewrite_action(struct mlx5e_priv *priv,
                                 struct mlx5e_tc_flow_parse_attr *parse_attr,
@@ -3234,24 +3224,6 @@ parse_tc_nic_actions(struct mlx5e_priv *priv,
 
        flow_action_for_each(i, act, flow_action) {
                switch (act->id) {
-               case FLOW_ACTION_REDIRECT: {
-                       struct net_device *peer_dev = act->dev;
-
-                       if (priv->netdev->netdev_ops == peer_dev->netdev_ops &&
-                           same_hw_devs(priv, netdev_priv(peer_dev))) {
-                               parse_attr->mirred_ifindex[0] = peer_dev->ifindex;
-                               flow_flag_set(flow, HAIRPIN);
-                               attr->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
-                                               MLX5_FLOW_CONTEXT_ACTION_COUNT;
-                       } else {
-                               NL_SET_ERR_MSG_MOD(extack,
-                                                  "device is not on same HW, can't offload");
-                               netdev_warn(priv->netdev, "device %s not on same HW, can't offload\n",
-                                           peer_dev->name);
-                               return -EOPNOTSUPP;
-                       }
-                       }
-                       break;
                case FLOW_ACTION_CT:
                        err = mlx5_tc_ct_parse_action(get_ct_priv(priv), attr,
                                                      &parse_attr->mod_hdr_acts,
@@ -3304,29 +3276,7 @@ static bool is_merged_eswitch_vfs(struct mlx5e_priv *priv,
        return (MLX5_CAP_ESW(priv->mdev, merged_eswitch) &&
                mlx5e_eswitch_vf_rep(priv->netdev) &&
                mlx5e_eswitch_vf_rep(peer_netdev) &&
-               same_hw_devs(priv, peer_priv));
-}
-
-static struct net_device *get_fdb_out_dev(struct net_device *uplink_dev,
-                                         struct net_device *out_dev)
-{
-       struct net_device *fdb_out_dev = out_dev;
-       struct net_device *uplink_upper;
-
-       rcu_read_lock();
-       uplink_upper = netdev_master_upper_dev_get_rcu(uplink_dev);
-       if (uplink_upper && netif_is_lag_master(uplink_upper) &&
-           uplink_upper == out_dev) {
-               fdb_out_dev = uplink_dev;
-       } else if (netif_is_lag_master(out_dev)) {
-               fdb_out_dev = bond_option_active_slave_get_rcu(netdev_priv(out_dev));
-               if (fdb_out_dev &&
-                   (!mlx5e_eswitch_rep(fdb_out_dev) ||
-                    !netdev_port_same_parent_id(fdb_out_dev, uplink_dev)))
-                       fdb_out_dev = NULL;
-       }
-       rcu_read_unlock();
-       return fdb_out_dev;
+               mlx5e_same_hw_devs(priv, peer_priv));
 }
 
 static bool same_hw_reps(struct mlx5e_priv *priv,
@@ -3338,7 +3288,7 @@ static bool same_hw_reps(struct mlx5e_priv *priv,
 
        return mlx5e_eswitch_rep(priv->netdev) &&
               mlx5e_eswitch_rep(peer_netdev) &&
-              same_hw_devs(priv, peer_priv);
+              mlx5e_same_hw_devs(priv, peer_priv);
 }
 
 static bool is_lag_dev(struct mlx5e_priv *priv,
@@ -3362,66 +3312,6 @@ bool mlx5e_is_valid_eswitch_fwd_dev(struct mlx5e_priv *priv,
               same_port_devs(priv, netdev_priv(out_dev));
 }
 
-static bool is_duplicated_output_device(struct net_device *dev,
-                                       struct net_device *out_dev,
-                                       int *ifindexes, int if_count,
-                                       struct netlink_ext_ack *extack)
-{
-       int i;
-
-       for (i = 0; i < if_count; i++) {
-               if (ifindexes[i] == out_dev->ifindex) {
-                       NL_SET_ERR_MSG_MOD(extack,
-                                          "can't duplicate output to same device");
-                       netdev_err(dev, "can't duplicate output to same device: %s\n",
-                                  out_dev->name);
-                       return true;
-               }
-       }
-
-       return false;
-}
-
-static int verify_uplink_forwarding(struct mlx5e_priv *priv,
-                                   struct mlx5e_tc_flow *flow,
-                                   struct net_device *out_dev,
-                                   struct netlink_ext_ack *extack)
-{
-       struct mlx5_esw_flow_attr *attr = flow->attr->esw_attr;
-       struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
-       struct mlx5e_rep_priv *rep_priv;
-
-       /* Forwarding non encapsulated traffic between
-        * uplink ports is allowed only if
-        * termination_table_raw_traffic cap is set.
-        *
-        * Input vport was stored attr->in_rep.
-        * In LAG case, *priv* is the private data of
-        * uplink which may be not the input vport.
-        */
-       rep_priv = mlx5e_rep_to_rep_priv(attr->in_rep);
-
-       if (!(mlx5e_eswitch_uplink_rep(rep_priv->netdev) &&
-             mlx5e_eswitch_uplink_rep(out_dev)))
-               return 0;
-
-       if (!MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev,
-                                       termination_table_raw_traffic)) {
-               NL_SET_ERR_MSG_MOD(extack,
-                                  "devices are both uplink, can't offload forwarding");
-                       pr_err("devices %s %s are both uplink, can't offload forwarding\n",
-                              priv->netdev->name, out_dev->name);
-                       return -EOPNOTSUPP;
-       } else if (out_dev != rep_priv->netdev) {
-               NL_SET_ERR_MSG_MOD(extack,
-                                  "devices are not the same uplink, can't offload forwarding");
-               pr_err("devices %s %s are both uplink but not the same, can't offload forwarding\n",
-                      priv->netdev->name, out_dev->name);
-               return -EOPNOTSUPP;
-       }
-       return 0;
-}
-
 int mlx5e_set_fwd_to_int_port_actions(struct mlx5e_priv *priv,
                                      struct mlx5_flow_attr *attr,
                                      int ifindex,
@@ -3469,18 +3359,15 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv,
        struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
        struct mlx5e_tc_act_parse_state *parse_state;
        struct mlx5e_tc_flow_parse_attr *parse_attr;
-       struct mlx5e_rep_priv *rpriv = priv->ppriv;
        struct mlx5e_sample_attr sample_attr = {};
        struct mlx5_flow_attr *attr = flow->attr;
-       int ifindexes[MLX5_MAX_FLOW_FWD_VPORTS];
-       bool ft_flow = mlx5e_is_ft_flow(flow);
        enum mlx5_flow_namespace_type ns_type;
        const struct flow_action_entry *act;
        struct mlx5_esw_flow_attr *esw_attr;
        struct pedit_headers_action *hdrs;
        struct mlx5e_tc_act *tc_act;
-       int err, i, if_count = 0;
        bool ptype_host = false;
+       int err, i;
 
        err = flow_action_supported(flow_action, extack);
        if (err)
@@ -3548,144 +3435,6 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv,
 
                        break;
                }
-               case FLOW_ACTION_REDIRECT:
-               case FLOW_ACTION_MIRRED: {
-                       struct mlx5e_priv *out_priv;
-                       struct net_device *out_dev;
-
-                       out_dev = act->dev;
-                       if (!out_dev) {
-                               /* out_dev is NULL when filters with
-                                * non-existing mirred device are replayed to
-                                * the driver.
-                                */
-                               return -EINVAL;
-                       }
-
-                       if (parse_state->mpls_push && !netif_is_bareudp(out_dev)) {
-                               NL_SET_ERR_MSG_MOD(extack,
-                                                  "mpls is supported only through a bareudp device");
-                               return -EOPNOTSUPP;
-                       }
-
-                       if (ft_flow && out_dev == priv->netdev) {
-                               /* Ignore forward to self rules generated
-                                * by adding both mlx5 devs to the flow table
-                                * block on a normal nft offload setup.
-                                */
-                               return -EOPNOTSUPP;
-                       }
-
-                       if (esw_attr->out_count >= MLX5_MAX_FLOW_FWD_VPORTS) {
-                               NL_SET_ERR_MSG_MOD(extack,
-                                                  "can't support more output ports, can't offload forwarding");
-                               netdev_warn(priv->netdev,
-                                           "can't support more than %d output ports, can't offload forwarding\n",
-                                           esw_attr->out_count);
-                               return -EOPNOTSUPP;
-                       }
-
-                       attr->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
-                                       MLX5_FLOW_CONTEXT_ACTION_COUNT;
-                       if (parse_state->encap) {
-                               parse_attr->mirred_ifindex[esw_attr->out_count] =
-                                       out_dev->ifindex;
-                               parse_attr->tun_info[esw_attr->out_count] =
-                                       mlx5e_dup_tun_info(parse_state->tun_info);
-                               if (!parse_attr->tun_info[esw_attr->out_count])
-                                       return -ENOMEM;
-                               parse_state->encap = false;
-                               esw_attr->dests[esw_attr->out_count].flags |=
-                                       MLX5_ESW_DEST_ENCAP;
-                               esw_attr->out_count++;
-                               /* attr->dests[].rep is resolved when we
-                                * handle encap
-                                */
-                       } else if (netdev_port_same_parent_id(priv->netdev, out_dev)) {
-                               struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
-                               struct net_device *uplink_dev = mlx5_eswitch_uplink_get_proto_dev(esw, REP_ETH);
-
-                               if (is_duplicated_output_device(priv->netdev,
-                                                               out_dev,
-                                                               ifindexes,
-                                                               if_count,
-                                                               extack))
-                                       return -EOPNOTSUPP;
-
-                               ifindexes[if_count] = out_dev->ifindex;
-                               if_count++;
-
-                               out_dev = get_fdb_out_dev(uplink_dev, out_dev);
-                               if (!out_dev)
-                                       return -ENODEV;
-
-                               if (is_vlan_dev(out_dev)) {
-                                       err = mlx5e_tc_act_vlan_add_push_action(priv, attr,
-                                                                               &out_dev,
-                                                                               extack);
-                                       if (err)
-                                               return err;
-                               }
-
-                               if (is_vlan_dev(parse_attr->filter_dev)) {
-                                       err = mlx5e_tc_act_vlan_add_pop_action(priv, attr,
-                                                                              extack);
-                                       if (err)
-                                               return err;
-                               }
-
-                               if (netif_is_macvlan(out_dev))
-                                       out_dev = macvlan_dev_real_dev(out_dev);
-
-                               err = verify_uplink_forwarding(priv, flow, out_dev, extack);
-                               if (err)
-                                       return err;
-
-                               if (!mlx5e_is_valid_eswitch_fwd_dev(priv, out_dev)) {
-                                       NL_SET_ERR_MSG_MOD(extack,
-                                                          "devices are not on same switch HW, can't offload forwarding");
-                                       return -EOPNOTSUPP;
-                               }
-
-                               if (same_vf_reps(priv, out_dev)) {
-                                       NL_SET_ERR_MSG_MOD(extack,
-                                                          "can't forward from a VF to itself");
-                                       return -EOPNOTSUPP;
-                               }
-
-                               out_priv = netdev_priv(out_dev);
-                               rpriv = out_priv->ppriv;
-                               esw_attr->dests[esw_attr->out_count].rep = rpriv->rep;
-                               esw_attr->dests[esw_attr->out_count].mdev = out_priv->mdev;
-                               esw_attr->out_count++;
-                       } else if (netif_is_ovs_master(out_dev)) {
-                               err = mlx5e_set_fwd_to_int_port_actions(priv, attr,
-                                                                       out_dev->ifindex,
-                                                                       MLX5E_TC_INT_PORT_EGRESS,
-                                                                       &attr->action,
-                                                                       esw_attr->out_count);
-                               if (err)
-                                       return err;
-
-                               esw_attr->out_count++;
-                       } else if (parse_attr->filter_dev != priv->netdev) {
-                               /* All mlx5 devices are called to configure
-                                * high level device filters. Therefore, the
-                                * *attempt* to  install a filter on invalid
-                                * eswitch should not trigger an explicit error
-                                */
-                               return -EINVAL;
-                       } else {
-                               NL_SET_ERR_MSG_MOD(extack,
-                                                  "devices are not on same switch HW, can't offload forwarding");
-                               netdev_warn(priv->netdev,
-                                           "devices %s %s not on same switch HW, can't offload forwarding\n",
-                                           priv->netdev->name,
-                                           out_dev->name);
-                               return -EOPNOTSUPP;
-                       }
-                       }
-                       break;
                case FLOW_ACTION_CT:
                        if (flow_flag_test(flow, SAMPLE)) {
                                NL_SET_ERR_MSG_MOD(extack, "Sample action with connection tracking is not supported");
@@ -4478,7 +4227,7 @@ static void mlx5e_tc_hairpin_update_dead_peer(struct mlx5e_priv *priv,
        u16 peer_vhca_id;
        int bkt;
 
-       if (!same_hw_devs(priv, peer_priv))
+       if (!mlx5e_same_hw_devs(priv, peer_priv))
                return;
 
        peer_vhca_id = MLX5_CAP_GEN(peer_mdev, vhca_id);