Commit ab3f3d5e authored by Roi Dayan's avatar Roi Dayan Committed by Saeed Mahameed

net/mlx5e: Add mirred/redirect to tc action infra

Add parsing support by implementing struct mlx5e_tc_act
for this action.
Signed-off-by: default avatarRoi Dayan <roid@nvidia.com>
Reviewed-by: default avatarOz Shlomo <ozsh@nvidia.com>
Signed-off-by: default avatarSaeed Mahameed <saeedm@nvidia.com>
parent 163b766f
......@@ -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
......
......@@ -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, */
......
......@@ -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,
......
// 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,
};
// 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,
};
......@@ -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)
{
......
......@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment