Commit 2aec919f authored by David S. Miller's avatar David S. Miller

Merge tag 'mlx5-updates-2021-10-29' of git://git.kernel.org/pub/scm/linux/kernel/git/saeed/linux

Saeed Mahameed says:

====================
mlx5-updates-2021-10-29

1) Minor trivial refactoring and improvements
2) Check for unsupported parameters fields in SW steering
3) Support TC offload for OVS internal port, from Ariel, see below.

Ariel Levkovich says:

=====================

Support HW offload of TC rules involving OVS internal port
device type as the filter device or the destination
device.

The support is for flows which explicitly use the internal
port as source or destination device as well as indirect offload
for flows performing tunnel set or unset via a tunnel device
and the internal port is the tunnel overlay device.

Since flows with internal port as source port are added
as egress rules while redirecting to internal port is done
as an ingress redirect, the series introduces the necessary
changes in mlx5_core driver to support the new types of flows
and actions.

=====================

====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents ae039350 b16eb3c8
......@@ -45,7 +45,7 @@ mlx5_core-$(CONFIG_MLX5_CLS_ACT) += en_tc.o en/rep/tc.o en/rep/neigh.o \
esw/indir_table.o en/tc_tun_encap.o \
en/tc_tun_vxlan.o en/tc_tun_gre.o en/tc_tun_geneve.o \
en/tc_tun_mplsoudp.o diag/en_tc_tracepoint.o \
en/tc/post_act.o
en/tc/post_act.o en/tc/int_port.o
mlx5_core-$(CONFIG_MLX5_TC_CT) += en/tc_ct.o
mlx5_core-$(CONFIG_MLX5_TC_SAMPLE) += en/tc/sample.o
......
......@@ -19,10 +19,13 @@
#include "en/tc_tun.h"
#include "lib/port_tun.h"
#include "en/tc/sample.h"
#include "en_accel/ipsec_rxtx.h"
#include "en/tc/int_port.h"
struct mlx5e_rep_indr_block_priv {
struct net_device *netdev;
struct mlx5e_rep_priv *rpriv;
enum flow_block_binder_type binder_type;
struct list_head list;
};
......@@ -297,14 +300,16 @@ int mlx5e_rep_tc_event_port_affinity(struct mlx5e_priv *priv)
static struct mlx5e_rep_indr_block_priv *
mlx5e_rep_indr_block_priv_lookup(struct mlx5e_rep_priv *rpriv,
struct net_device *netdev)
struct net_device *netdev,
enum flow_block_binder_type binder_type)
{
struct mlx5e_rep_indr_block_priv *cb_priv;
list_for_each_entry(cb_priv,
&rpriv->uplink_priv.tc_indr_block_priv_list,
list)
if (cb_priv->netdev == netdev)
if (cb_priv->netdev == netdev &&
cb_priv->binder_type == binder_type)
return cb_priv;
return NULL;
......@@ -342,9 +347,13 @@ mlx5e_rep_indr_offload(struct net_device *netdev,
static int mlx5e_rep_indr_setup_tc_cb(enum tc_setup_type type,
void *type_data, void *indr_priv)
{
unsigned long flags = MLX5_TC_FLAG(EGRESS) | MLX5_TC_FLAG(ESW_OFFLOAD);
unsigned long flags = MLX5_TC_FLAG(ESW_OFFLOAD);
struct mlx5e_rep_indr_block_priv *priv = indr_priv;
flags |= (priv->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS) ?
MLX5_TC_FLAG(EGRESS) :
MLX5_TC_FLAG(INGRESS);
switch (type) {
case TC_SETUP_CLSFLOWER:
return mlx5e_rep_indr_offload(priv->netdev, type_data, priv,
......@@ -426,11 +435,14 @@ mlx5e_rep_indr_setup_block(struct net_device *netdev, struct Qdisc *sch,
void (*cleanup)(struct flow_block_cb *block_cb))
{
struct mlx5e_priv *priv = netdev_priv(rpriv->netdev);
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
bool is_ovs_int_port = netif_is_ovs_master(netdev);
struct mlx5e_rep_indr_block_priv *indr_priv;
struct flow_block_cb *block_cb;
if (!mlx5e_tc_tun_device_to_offload(priv, netdev) &&
!(is_vlan_dev(netdev) && vlan_dev_real_dev(netdev) == rpriv->netdev)) {
!(is_vlan_dev(netdev) && vlan_dev_real_dev(netdev) == rpriv->netdev) &&
!is_ovs_int_port) {
if (!(netif_is_macvlan(netdev) && macvlan_dev_real_dev(netdev) == rpriv->netdev))
return -EOPNOTSUPP;
if (!mlx5e_rep_macvlan_mode_supported(netdev)) {
......@@ -439,7 +451,14 @@ mlx5e_rep_indr_setup_block(struct net_device *netdev, struct Qdisc *sch,
}
}
if (f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
if (f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS &&
f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS)
return -EOPNOTSUPP;
if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS && !is_ovs_int_port)
return -EOPNOTSUPP;
if (is_ovs_int_port && !mlx5e_tc_int_port_supported(esw))
return -EOPNOTSUPP;
f->unlocked_driver_cb = true;
......@@ -447,7 +466,7 @@ mlx5e_rep_indr_setup_block(struct net_device *netdev, struct Qdisc *sch,
switch (f->command) {
case FLOW_BLOCK_BIND:
indr_priv = mlx5e_rep_indr_block_priv_lookup(rpriv, netdev);
indr_priv = mlx5e_rep_indr_block_priv_lookup(rpriv, netdev, f->binder_type);
if (indr_priv)
return -EEXIST;
......@@ -457,6 +476,7 @@ mlx5e_rep_indr_setup_block(struct net_device *netdev, struct Qdisc *sch,
indr_priv->netdev = netdev;
indr_priv->rpriv = rpriv;
indr_priv->binder_type = f->binder_type;
list_add(&indr_priv->list,
&rpriv->uplink_priv.tc_indr_block_priv_list);
......@@ -474,7 +494,7 @@ mlx5e_rep_indr_setup_block(struct net_device *netdev, struct Qdisc *sch,
return 0;
case FLOW_BLOCK_UNBIND:
indr_priv = mlx5e_rep_indr_block_priv_lookup(rpriv, netdev);
indr_priv = mlx5e_rep_indr_block_priv_lookup(rpriv, netdev, f->binder_type);
if (!indr_priv)
return -ENOENT;
......@@ -611,8 +631,8 @@ static bool mlx5e_restore_tunnel(struct mlx5e_priv *priv, struct sk_buff *skb,
return false;
}
/* Set tun_dev so we do dev_put() after datapath */
tc_priv->tun_dev = dev;
/* Set fwd_dev so we do dev_put() after datapath */
tc_priv->fwd_dev = dev;
skb->dev = dev;
......@@ -652,6 +672,12 @@ static bool mlx5e_restore_skb_chain(struct sk_buff *skb, u32 chain, u32 reg_c1,
return mlx5e_restore_tunnel(priv, skb, tc_priv, tunnel_id);
}
static void mlx5_rep_tc_post_napi_receive(struct mlx5e_tc_update_priv *tc_priv)
{
if (tc_priv->fwd_dev)
dev_put(tc_priv->fwd_dev);
}
static void mlx5e_restore_skb_sample(struct mlx5e_priv *priv, struct sk_buff *skb,
struct mlx5_mapped_obj *mapped_obj,
struct mlx5e_tc_update_priv *tc_priv)
......@@ -665,19 +691,50 @@ static void mlx5e_restore_skb_sample(struct mlx5e_priv *priv, struct sk_buff *sk
mlx5_rep_tc_post_napi_receive(tc_priv);
}
bool mlx5e_rep_tc_update_skb(struct mlx5_cqe64 *cqe,
struct sk_buff *skb,
struct mlx5e_tc_update_priv *tc_priv)
static bool mlx5e_restore_skb_int_port(struct mlx5e_priv *priv, struct sk_buff *skb,
struct mlx5_mapped_obj *mapped_obj,
struct mlx5e_tc_update_priv *tc_priv,
bool *forward_tx,
u32 reg_c1)
{
u32 tunnel_id = (reg_c1 >> ESW_TUN_OFFSET) & TUNNEL_ID_MASK;
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
struct mlx5_rep_uplink_priv *uplink_priv;
struct mlx5e_rep_priv *uplink_rpriv;
/* Tunnel restore takes precedence over int port restore */
if (tunnel_id)
return mlx5e_restore_tunnel(priv, skb, tc_priv, tunnel_id);
uplink_rpriv = mlx5_eswitch_get_uplink_priv(esw, REP_ETH);
uplink_priv = &uplink_rpriv->uplink_priv;
if (mlx5e_tc_int_port_dev_fwd(uplink_priv->int_port_priv, skb,
mapped_obj->int_port_metadata, forward_tx)) {
/* Set fwd_dev for future dev_put */
tc_priv->fwd_dev = skb->dev;
return true;
}
return false;
}
void mlx5e_rep_tc_receive(struct mlx5_cqe64 *cqe, struct mlx5e_rq *rq,
struct sk_buff *skb)
{
u32 reg_c1 = be32_to_cpu(cqe->ft_metadata);
struct mlx5e_tc_update_priv tc_priv = {};
struct mlx5_mapped_obj mapped_obj;
struct mlx5_eswitch *esw;
bool forward_tx = false;
struct mlx5e_priv *priv;
u32 reg_c0;
int err;
reg_c0 = (be32_to_cpu(cqe->sop_drop_qpn) & MLX5E_TC_FLOW_ID_MASK);
if (!reg_c0 || reg_c0 == MLX5_FS_DEFAULT_FLOW_TAG)
return true;
goto forward;
/* If reg_c0 is not equal to the default flow tag then skb->mark
* is not supported and must be reset back to 0.
......@@ -691,26 +748,35 @@ bool mlx5e_rep_tc_update_skb(struct mlx5_cqe64 *cqe,
netdev_dbg(priv->netdev,
"Couldn't find mapped object for reg_c0: %d, err: %d\n",
reg_c0, err);
return false;
goto free_skb;
}
if (mapped_obj.type == MLX5_MAPPED_OBJ_CHAIN) {
u32 reg_c1 = be32_to_cpu(cqe->ft_metadata);
return mlx5e_restore_skb_chain(skb, mapped_obj.chain, reg_c1, tc_priv);
if (!mlx5e_restore_skb_chain(skb, mapped_obj.chain, reg_c1, &tc_priv) &&
!mlx5_ipsec_is_rx_flow(cqe))
goto free_skb;
} else if (mapped_obj.type == MLX5_MAPPED_OBJ_SAMPLE) {
mlx5e_restore_skb_sample(priv, skb, &mapped_obj, tc_priv);
return false;
mlx5e_restore_skb_sample(priv, skb, &mapped_obj, &tc_priv);
goto free_skb;
} else if (mapped_obj.type == MLX5_MAPPED_OBJ_INT_PORT_METADATA) {
if (!mlx5e_restore_skb_int_port(priv, skb, &mapped_obj, &tc_priv,
&forward_tx, reg_c1))
goto free_skb;
} else {
netdev_dbg(priv->netdev, "Invalid mapped object type: %d\n", mapped_obj.type);
return false;
goto free_skb;
}
return true;
}
forward:
if (forward_tx)
dev_queue_xmit(skb);
else
napi_gro_receive(rq->cq.napi, skb);
void mlx5_rep_tc_post_napi_receive(struct mlx5e_tc_update_priv *tc_priv)
{
if (tc_priv->tun_dev)
dev_put(tc_priv->tun_dev);
mlx5_rep_tc_post_napi_receive(&tc_priv);
return;
free_skb:
dev_kfree_skb_any(skb);
}
......@@ -36,10 +36,8 @@ void mlx5e_rep_encap_entry_detach(struct mlx5e_priv *priv,
int mlx5e_rep_setup_tc(struct net_device *dev, enum tc_setup_type type,
void *type_data);
bool mlx5e_rep_tc_update_skb(struct mlx5_cqe64 *cqe,
struct sk_buff *skb,
struct mlx5e_tc_update_priv *tc_priv);
void mlx5_rep_tc_post_napi_receive(struct mlx5e_tc_update_priv *tc_priv);
void mlx5e_rep_tc_receive(struct mlx5_cqe64 *cqe, struct mlx5e_rq *rq,
struct sk_buff *skb);
#else /* CONFIG_MLX5_CLS_ACT */
......@@ -66,13 +64,9 @@ static inline int
mlx5e_rep_setup_tc(struct net_device *dev, enum tc_setup_type type,
void *type_data) { return -EOPNOTSUPP; }
struct mlx5e_tc_update_priv;
static inline bool
mlx5e_rep_tc_update_skb(struct mlx5_cqe64 *cqe,
struct sk_buff *skb,
struct mlx5e_tc_update_priv *tc_priv) { return true; }
static inline void
mlx5_rep_tc_post_napi_receive(struct mlx5e_tc_update_priv *tc_priv) {}
mlx5e_rep_tc_receive(struct mlx5_cqe64 *cqe, struct mlx5e_rq *rq,
struct sk_buff *skb) {}
#endif /* CONFIG_MLX5_CLS_ACT */
......
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
/* Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
#ifndef __MLX5_EN_TC_INT_PORT_H__
#define __MLX5_EN_TC_INT_PORT_H__
#include "en.h"
struct mlx5e_tc_int_port;
struct mlx5e_tc_int_port_priv;
enum mlx5e_tc_int_port_type {
MLX5E_TC_INT_PORT_INGRESS,
MLX5E_TC_INT_PORT_EGRESS,
};
#if IS_ENABLED(CONFIG_MLX5_CLS_ACT)
bool mlx5e_tc_int_port_supported(const struct mlx5_eswitch *esw);
struct mlx5e_tc_int_port_priv *
mlx5e_tc_int_port_init(struct mlx5e_priv *priv);
void
mlx5e_tc_int_port_cleanup(struct mlx5e_tc_int_port_priv *priv);
void mlx5e_tc_int_port_init_rep_rx(struct mlx5e_priv *priv);
void mlx5e_tc_int_port_cleanup_rep_rx(struct mlx5e_priv *priv);
bool
mlx5e_tc_int_port_dev_fwd(struct mlx5e_tc_int_port_priv *priv,
struct sk_buff *skb, u32 int_vport_metadata,
bool *forward_tx);
struct mlx5e_tc_int_port *
mlx5e_tc_int_port_get(struct mlx5e_tc_int_port_priv *priv,
int ifindex,
enum mlx5e_tc_int_port_type type);
void
mlx5e_tc_int_port_put(struct mlx5e_tc_int_port_priv *priv,
struct mlx5e_tc_int_port *int_port);
u32 mlx5e_tc_int_port_get_metadata(struct mlx5e_tc_int_port *int_port);
u32 mlx5e_tc_int_port_get_metadata_for_match(struct mlx5e_tc_int_port *int_port);
int mlx5e_tc_int_port_get_flow_source(struct mlx5e_tc_int_port *int_port);
#else /* CONFIG_MLX5_CLS_ACT */
static inline u32
mlx5e_tc_int_port_get_metadata_for_match(struct mlx5e_tc_int_port *int_port)
{
return 0;
}
static inline int
mlx5e_tc_int_port_get_flow_source(struct mlx5e_tc_int_port *int_port)
{
return 0;
}
static inline bool mlx5e_tc_int_port_supported(const struct mlx5_eswitch *esw)
{
return false;
}
static inline void mlx5e_tc_int_port_init_rep_rx(struct mlx5e_priv *priv) {}
static inline void mlx5e_tc_int_port_cleanup_rep_rx(struct mlx5e_priv *priv) {}
#endif /* CONFIG_MLX5_CLS_ACT */
#endif /* __MLX5_EN_TC_INT_PORT_H__ */
......@@ -4,6 +4,7 @@
#include "en_tc.h"
#include "post_act.h"
#include "mlx5_core.h"
#include "fs_core.h"
struct mlx5e_post_act {
enum mlx5_flow_namespace_type ns_type;
......@@ -28,16 +29,14 @@ struct mlx5e_post_act *
mlx5e_tc_post_act_init(struct mlx5e_priv *priv, struct mlx5_fs_chains *chains,
enum mlx5_flow_namespace_type ns_type)
{
enum fs_flow_table_type table_type = ns_type == MLX5_FLOW_NAMESPACE_FDB ?
FS_FT_FDB : FS_FT_NIC_RX;
struct mlx5e_post_act *post_act;
int err;
if (ns_type == MLX5_FLOW_NAMESPACE_FDB &&
!MLX5_CAP_ESW_FLOWTABLE_FDB(priv->mdev, ignore_flow_level)) {
mlx5_core_warn(priv->mdev, "firmware level support is missing\n");
err = -EOPNOTSUPP;
goto err_check;
} else if (!MLX5_CAP_FLOWTABLE_NIC_RX(priv->mdev, ignore_flow_level)) {
mlx5_core_warn(priv->mdev, "firmware level support is missing\n");
if (!MLX5_CAP_FLOWTABLE_TYPE(priv->mdev, ignore_flow_level, table_type)) {
if (priv->mdev->coredev_type != MLX5_COREDEV_VF)
mlx5_core_warn(priv->mdev, "firmware level support is missing\n");
err = -EOPNOTSUPP;
goto err_check;
}
......
......@@ -631,6 +631,7 @@ mlx5e_tc_sample_unoffload(struct mlx5e_tc_psample *tc_psample,
/* The following delete order can't be changed, otherwise,
* will hit fw syndromes.
*/
esw = tc_psample->esw;
sample_flow = attr->sample_attr->sample_flow;
mlx5_eswitch_del_offloaded_rule(esw, sample_flow->pre_rule, sample_flow->pre_attr);
......
......@@ -889,7 +889,7 @@ mlx5_tc_ct_counter_create(struct mlx5_tc_ct_priv *ct_priv)
return ERR_PTR(-ENOMEM);
counter->is_shared = false;
counter->counter = mlx5_fc_create(ct_priv->dev, true);
counter->counter = mlx5_fc_create_ex(ct_priv->dev, true);
if (IS_ERR(counter->counter)) {
ct_dbg("Failed to create counter for ct entry");
ret = PTR_ERR(counter->counter);
......@@ -2039,25 +2039,36 @@ mlx5_tc_ct_init_check_esw_support(struct mlx5_eswitch *esw,
static int
mlx5_tc_ct_init_check_support(struct mlx5e_priv *priv,
enum mlx5_flow_namespace_type ns_type,
struct mlx5e_post_act *post_act,
const char **err_msg)
struct mlx5e_post_act *post_act)
{
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
const char *err_msg = NULL;
int err = 0;
#if !IS_ENABLED(CONFIG_NET_TC_SKB_EXT)
/* cannot restore chain ID on HW miss */
*err_msg = "tc skb extension missing";
return -EOPNOTSUPP;
err_msg = "tc skb extension missing";
err = -EOPNOTSUPP;
goto out_err;
#endif
if (IS_ERR_OR_NULL(post_act)) {
*err_msg = "tc ct offload not supported, post action is missing";
return -EOPNOTSUPP;
/* Ignore_flow_level support isn't supported by default for VFs and so post_act
* won't be supported. Skip showing error msg.
*/
if (priv->mdev->coredev_type != MLX5_COREDEV_VF)
err_msg = "post action is missing";
err = -EOPNOTSUPP;
goto out_err;
}
if (ns_type == MLX5_FLOW_NAMESPACE_FDB)
return mlx5_tc_ct_init_check_esw_support(esw, err_msg);
return 0;
err = mlx5_tc_ct_init_check_esw_support(esw, &err_msg);
out_err:
if (err && err_msg)
netdev_dbg(priv->netdev, "tc ct offload not supported, %s\n", err_msg);
return err;
}
#define INIT_ERR_PREFIX "tc ct offload init failed"
......@@ -2070,16 +2081,13 @@ mlx5_tc_ct_init(struct mlx5e_priv *priv, struct mlx5_fs_chains *chains,
{
struct mlx5_tc_ct_priv *ct_priv;
struct mlx5_core_dev *dev;
const char *msg;
u64 mapping_id;
int err;
dev = priv->mdev;
err = mlx5_tc_ct_init_check_support(priv, ns_type, post_act, &msg);
if (err) {
mlx5_core_warn(dev, "tc ct offload not supported, %s\n", msg);
err = mlx5_tc_ct_init_check_support(priv, ns_type, post_act);
if (err)
goto err_support;
}
ct_priv = kzalloc(sizeof(*ct_priv), GFP_KERNEL);
if (!ct_priv)
......
......@@ -173,4 +173,6 @@ void mlx5e_flow_put(struct mlx5e_priv *priv, struct mlx5e_tc_flow *flow);
struct mlx5_fc *mlx5e_tc_get_counter(struct mlx5e_tc_flow *flow);
struct mlx5e_tc_int_port_priv *
mlx5e_get_int_port_priv(struct mlx5e_priv *priv);
#endif /* __MLX5_EN_TC_PRIV_H__ */
......@@ -83,7 +83,8 @@ static int get_route_and_out_devs(struct mlx5e_priv *priv,
*/
*route_dev = dev;
if (!netdev_port_same_parent_id(priv->netdev, real_dev) ||
dst_is_lag_dev || is_vlan_dev(*route_dev))
dst_is_lag_dev || is_vlan_dev(*route_dev) ||
netif_is_ovs_master(*route_dev))
*out_dev = uplink_dev;
else if (mlx5e_eswitch_rep(dev) &&
mlx5e_is_valid_eswitch_fwd_dev(priv, dev))
......@@ -710,6 +711,7 @@ int mlx5e_tc_tun_route_lookup(struct mlx5e_priv *priv,
struct mlx5_flow_attr *flow_attr)
{
struct mlx5_esw_flow_attr *esw_attr = flow_attr->esw_attr;
struct mlx5e_tc_int_port *int_port;
TC_TUN_ROUTE_ATTR_INIT(attr);
u16 vport_num;
int err = 0;
......@@ -734,17 +736,25 @@ int mlx5e_tc_tun_route_lookup(struct mlx5e_priv *priv,
if (err)
return err;
if (attr.route_dev->netdev_ops != &mlx5e_netdev_ops ||
!mlx5e_tc_is_vf_tunnel(attr.out_dev, attr.route_dev))
goto out;
err = mlx5e_tc_query_route_vport(attr.out_dev, attr.route_dev, &vport_num);
if (err)
goto out;
if (attr.route_dev->netdev_ops == &mlx5e_netdev_ops &&
mlx5e_tc_is_vf_tunnel(attr.out_dev, attr.route_dev)) {
err = mlx5e_tc_query_route_vport(attr.out_dev, attr.route_dev, &vport_num);
if (err)
goto out;
esw_attr->rx_tun_attr->vni = MLX5_GET(fte_match_param, spec->match_value,
misc_parameters.vxlan_vni);
esw_attr->rx_tun_attr->decap_vport = vport_num;
esw_attr->rx_tun_attr->vni = MLX5_GET(fte_match_param, spec->match_value,
misc_parameters.vxlan_vni);
esw_attr->rx_tun_attr->decap_vport = vport_num;
} else if (netif_is_ovs_master(attr.route_dev)) {
int_port = mlx5e_tc_int_port_get(mlx5e_get_int_port_priv(priv),
attr.route_dev->ifindex,
MLX5E_TC_INT_PORT_INGRESS);
if (IS_ERR(int_port)) {
err = PTR_ERR(int_port);
goto out;
}
esw_attr->int_port = int_port;
}
out:
if (flow_attr->tun_ip_version == 4)
......
......@@ -13,6 +13,30 @@ enum {
MLX5E_ROUTE_ENTRY_VALID = BIT(0),
};
static int mlx5e_set_int_port_tunnel(struct mlx5e_priv *priv,
struct mlx5_flow_attr *attr,
struct mlx5e_encap_entry *e,
int out_index)
{
struct net_device *route_dev;
int err = 0;
route_dev = dev_get_by_index(dev_net(e->out_dev), e->route_dev_ifindex);
if (!route_dev || !netif_is_ovs_master(route_dev))
goto out;
err = mlx5e_set_fwd_to_int_port_actions(priv, attr, e->route_dev_ifindex,
MLX5E_TC_INT_PORT_EGRESS,
&attr->action, out_index);
out:
if (route_dev)
dev_put(route_dev);
return err;
}
struct mlx5e_route_key {
int ip_version;
union {
......@@ -809,6 +833,17 @@ int mlx5e_attach_encap(struct mlx5e_priv *priv,
if (err)
goto out_err;
err = mlx5e_set_int_port_tunnel(priv, attr, e, out_index);
if (err == -EOPNOTSUPP) {
/* If device doesn't support int port offload,
* redirect to uplink vport.
*/
mlx5_core_dbg(priv->mdev, "attaching int port as encap dev not supported, using uplink\n");
err = 0;
} else if (err) {
goto out_err;
}
flow->encaps[out_index].e = e;
list_add(&flow->encaps[out_index].list, &e->flows);
flow->encaps[out_index].index = out_index;
......
......@@ -127,6 +127,25 @@ mlx5e_ipsec_feature_check(struct sk_buff *skb, netdev_features_t features)
return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK);
}
static inline bool
mlx5e_ipsec_txwqe_build_eseg_csum(struct mlx5e_txqsq *sq, struct sk_buff *skb,
struct mlx5_wqe_eth_seg *eseg)
{
struct xfrm_offload *xo = xfrm_offload(skb);
if (!mlx5e_ipsec_eseg_meta(eseg))
return false;
eseg->cs_flags = MLX5_ETH_WQE_L3_CSUM;
if (xo->inner_ipproto) {
eseg->cs_flags |= MLX5_ETH_WQE_L4_INNER_CSUM | MLX5_ETH_WQE_L3_INNER_CSUM;
} else if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) {
eseg->cs_flags |= MLX5_ETH_WQE_L4_CSUM;
sq->stats->csum_partial_inner++;
}
return true;
}
#else
static inline
void mlx5e_ipsec_offload_handle_rx_skb(struct net_device *netdev,
......@@ -143,6 +162,13 @@ static inline bool mlx5_ipsec_is_rx_flow(struct mlx5_cqe64 *cqe) { return false;
static inline netdev_features_t
mlx5e_ipsec_feature_check(struct sk_buff *skb, netdev_features_t features)
{ return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK); }
static inline bool
mlx5e_ipsec_txwqe_build_eseg_csum(struct mlx5e_txqsq *sq, struct sk_buff *skb,
struct mlx5_wqe_eth_seg *eseg)
{
return false;
}
#endif /* CONFIG_MLX5_EN_IPSEC */
#endif /* __MLX5E_IPSEC_RXTX_H__ */
......@@ -53,6 +53,7 @@
#define CREATE_TRACE_POINTS
#include "diag/en_rep_tracepoint.h"
#include "en_accel/ipsec.h"
#include "en/tc/int_port.h"
#define MLX5E_REP_PARAMS_DEF_LOG_SQ_SIZE \
max(0x7, MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE)
......@@ -857,12 +858,22 @@ static void mlx5e_cleanup_rep_rx(struct mlx5e_priv *priv)
static int mlx5e_init_ul_rep_rx(struct mlx5e_priv *priv)
{
int err;
mlx5e_create_q_counters(priv);
return mlx5e_init_rep_rx(priv);
err = mlx5e_init_rep_rx(priv);
if (err)
goto out;
mlx5e_tc_int_port_init_rep_rx(priv);
out:
return err;
}
static void mlx5e_cleanup_ul_rep_rx(struct mlx5e_priv *priv)
{
mlx5e_tc_int_port_cleanup_rep_rx(priv);
mlx5e_cleanup_rep_rx(priv);
mlx5e_destroy_q_counters(priv);
}
......
......@@ -58,6 +58,7 @@ struct mlx5e_neigh_update_table {
};
struct mlx5_tc_ct_priv;
struct mlx5_tc_int_port_priv;
struct mlx5e_rep_bond;
struct mlx5e_tc_tun_encap;
struct mlx5e_post_act;
......@@ -98,6 +99,9 @@ struct mlx5_rep_uplink_priv {
/* tc tunneling encapsulation private data */
struct mlx5e_tc_tun_encap *encap;
/* OVS internal port support */
struct mlx5e_tc_int_port_priv *int_port_priv;
};
struct mlx5e_rep_priv {
......
......@@ -1660,7 +1660,6 @@ static void mlx5e_handle_rx_cqe_rep(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe)
struct mlx5e_priv *priv = netdev_priv(netdev);
struct mlx5e_rep_priv *rpriv = priv->ppriv;
struct mlx5_eswitch_rep *rep = rpriv->rep;
struct mlx5e_tc_update_priv tc_priv = {};
struct mlx5_wq_cyc *wq = &rq->wqe.wq;
struct mlx5e_wqe_frag_info *wi;
struct sk_buff *skb;
......@@ -1696,15 +1695,7 @@ static void mlx5e_handle_rx_cqe_rep(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe)
if (rep->vlan && skb_vlan_tag_present(skb))
skb_vlan_pop(skb);
if (unlikely(!mlx5_ipsec_is_rx_flow(cqe) &&
!mlx5e_rep_tc_update_skb(cqe, skb, &tc_priv))) {
dev_kfree_skb_any(skb);
goto free_wqe;
}
napi_gro_receive(rq->cq.napi, skb);
mlx5_rep_tc_post_napi_receive(&tc_priv);
mlx5e_rep_tc_receive(cqe, rq, skb);
free_wqe:
mlx5e_free_rx_wqe(rq, wi, true);
......@@ -1721,7 +1712,6 @@ static void mlx5e_handle_rx_cqe_mpwrq_rep(struct mlx5e_rq *rq, struct mlx5_cqe64
u32 wqe_offset = stride_ix << rq->mpwqe.log_stride_sz;
u32 head_offset = wqe_offset & (PAGE_SIZE - 1);
u32 page_idx = wqe_offset >> PAGE_SHIFT;
struct mlx5e_tc_update_priv tc_priv = {};
struct mlx5e_rx_wqe_ll *wqe;
struct mlx5_wq_ll *wq;
struct sk_buff *skb;
......@@ -1754,15 +1744,7 @@ static void mlx5e_handle_rx_cqe_mpwrq_rep(struct mlx5e_rq *rq, struct mlx5_cqe64
mlx5e_complete_rx_cqe(rq, cqe, cqe_bcnt, skb);
if (unlikely(!mlx5_ipsec_is_rx_flow(cqe) &&
!mlx5e_rep_tc_update_skb(cqe, skb, &tc_priv))) {
dev_kfree_skb_any(skb);
goto mpwrq_cqe_out;
}
napi_gro_receive(rq->cq.napi, skb);
mlx5_rep_tc_post_napi_receive(&tc_priv);
mlx5e_rep_tc_receive(cqe, rq, skb);
mpwrq_cqe_out:
if (likely(wi->consumed_strides < rq->mpwqe.num_strides))
......
......@@ -60,7 +60,6 @@
#include "en/mapping.h"
#include "en/tc_ct.h"
#include "en/mod_hdr.h"
#include "en/tc_priv.h"
#include "en/tc_tun_encap.h"
#include "en/tc/sample.h"
#include "lib/devcom.h"
......@@ -232,6 +231,23 @@ mlx5e_tc_match_to_reg_set_and_get_id(struct mlx5_core_dev *mdev,
return err;
}
struct mlx5e_tc_int_port_priv *
mlx5e_get_int_port_priv(struct mlx5e_priv *priv)
{
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
struct mlx5_rep_uplink_priv *uplink_priv;
struct mlx5e_rep_priv *uplink_rpriv;
if (is_mdev_switchdev_mode(priv->mdev)) {
uplink_rpriv = mlx5_eswitch_get_uplink_priv(esw, REP_ETH);
uplink_priv = &uplink_rpriv->uplink_priv;
return uplink_priv->int_port_priv;
}
return NULL;
}
static struct mlx5_tc_ct_priv *
get_ct_priv(struct mlx5e_priv *priv)
{
......@@ -1385,6 +1401,9 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
int err = 0;
int out_index;
parse_attr = attr->parse_attr;
esw_attr = attr->esw_attr;
/* We check chain range only for tc flows.
* For ft flows, we checked attr->chain was originally 0 and set it to
* FDB_FT_CHAIN which is outside tc range.
......@@ -1410,6 +1429,24 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
err = mlx5e_attach_decap_route(priv, flow);
if (err)
goto err_out;
if (!attr->chain && esw_attr->int_port) {
/* If decap route device is internal port, change the
* source vport value in reg_c0 back to uplink just in
* case the rule performs goto chain > 0. If we have a miss
* on chain > 0 we want the metadata regs to hold the
* chain id so SW will resume handling of this packet
* from the proper chain.
*/
u32 metadata = mlx5_eswitch_get_vport_metadata_for_set(esw,
esw_attr->in_rep->vport);
err = mlx5e_tc_match_to_reg_set(priv->mdev, &parse_attr->mod_hdr_acts,
MLX5_FLOW_NAMESPACE_FDB, VPORT_TO_REG,
metadata);
if (err)
return err;
}
}
if (flow_flag_test(flow, L3_TO_L2_DECAP)) {
......@@ -1418,8 +1455,31 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
goto err_out;
}
parse_attr = attr->parse_attr;
esw_attr = attr->esw_attr;
if (netif_is_ovs_master(parse_attr->filter_dev)) {
struct mlx5e_tc_int_port *int_port;
if (attr->chain) {
NL_SET_ERR_MSG_MOD(extack,
"Internal port rule is only supported on chain 0");
return -EOPNOTSUPP;
}
if (attr->dest_chain) {
NL_SET_ERR_MSG_MOD(extack,
"Internal port rule offload doesn't support goto action");
return -EOPNOTSUPP;
}
int_port = mlx5e_tc_int_port_get(mlx5e_get_int_port_priv(priv),
parse_attr->filter_dev->ifindex,
flow_flag_test(flow, EGRESS) ?
MLX5E_TC_INT_PORT_EGRESS :
MLX5E_TC_INT_PORT_INGRESS);
if (IS_ERR(int_port))
return PTR_ERR(int_port);
esw_attr->int_port = int_port;
}
for (out_index = 0; out_index < MLX5_MAX_FLOW_FWD_VPORTS; out_index++) {
struct net_device *out_dev;
......@@ -1442,7 +1502,8 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv,
goto err_out;
if (esw_attr->dests[out_index].flags &
MLX5_ESW_DEST_CHAIN_WITH_SRC_PORT_CHANGE)
MLX5_ESW_DEST_CHAIN_WITH_SRC_PORT_CHANGE &&
!esw_attr->dest_int_port)
vf_tun = true;
out_priv = netdev_priv(encap_dev);
rpriv = out_priv->ppriv;
......@@ -1550,7 +1611,8 @@ static void mlx5e_tc_del_fdb_flow(struct mlx5e_priv *priv,
for (out_index = 0; out_index < MLX5_MAX_FLOW_FWD_VPORTS; out_index++) {
if (esw_attr->dests[out_index].flags &
MLX5_ESW_DEST_CHAIN_WITH_SRC_PORT_CHANGE)
MLX5_ESW_DEST_CHAIN_WITH_SRC_PORT_CHANGE &&
!esw_attr->dest_int_port)
vf_tun = true;
if (esw_attr->dests[out_index].flags & MLX5_ESW_DEST_ENCAP) {
mlx5e_detach_encap(priv, flow, out_index);
......@@ -1574,6 +1636,12 @@ static void mlx5e_tc_del_fdb_flow(struct mlx5e_priv *priv,
if (attr->action & MLX5_FLOW_CONTEXT_ACTION_COUNT)
mlx5_fc_destroy(esw_attr->counter_dev, attr->counter);
if (esw_attr->int_port)
mlx5e_tc_int_port_put(mlx5e_get_int_port_priv(priv), esw_attr->int_port);
if (esw_attr->dest_int_port)
mlx5e_tc_int_port_put(mlx5e_get_int_port_priv(priv), esw_attr->dest_int_port);
if (flow_flag_test(flow, L3_TO_L2_DECAP))
mlx5e_detach_decap(priv, flow);
......@@ -3815,6 +3883,45 @@ static int verify_uplink_forwarding(struct mlx5e_priv *priv,
return 0;
}
int mlx5e_set_fwd_to_int_port_actions(struct mlx5e_priv *priv,
struct mlx5_flow_attr *attr,
int ifindex,
enum mlx5e_tc_int_port_type type,
u32 *action,
int out_index)
{
struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr;
struct mlx5e_tc_int_port_priv *int_port_priv;
struct mlx5e_tc_flow_parse_attr *parse_attr;
struct mlx5e_tc_int_port *dest_int_port;
int err;
parse_attr = attr->parse_attr;
int_port_priv = mlx5e_get_int_port_priv(priv);
dest_int_port = mlx5e_tc_int_port_get(int_port_priv, ifindex, type);
if (IS_ERR(dest_int_port))
return PTR_ERR(dest_int_port);
err = mlx5e_tc_match_to_reg_set(priv->mdev, &parse_attr->mod_hdr_acts,
MLX5_FLOW_NAMESPACE_FDB, VPORT_TO_REG,
mlx5e_tc_int_port_get_metadata(dest_int_port));
if (err) {
mlx5e_tc_int_port_put(int_port_priv, dest_int_port);
return err;
}
*action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;
esw_attr->dest_int_port = dest_int_port;
esw_attr->dests[out_index].flags |= MLX5_ESW_DEST_CHAIN_WITH_SRC_PORT_CHANGE;
/* Forward to root fdb for matching against the new source vport */
attr->dest_chain = 0;
return 0;
}
static int parse_tc_fdb_actions(struct mlx5e_priv *priv,
struct flow_action *flow_action,
struct mlx5e_tc_flow *flow,
......@@ -3834,6 +3941,7 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv,
bool encap = false, decap = false;
u32 action = attr->action;
int err, i, if_count = 0;
bool ptype_host = false;
bool mpls_push = false;
if (!flow_action_has_entries(flow_action)) {
......@@ -3857,6 +3965,15 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv,
MLX5_FLOW_CONTEXT_ACTION_COUNT;
attr->flags |= MLX5_ESW_ATTR_FLAG_ACCEPT;
break;
case FLOW_ACTION_PTYPE:
if (act->ptype != PACKET_HOST) {
NL_SET_ERR_MSG_MOD(extack,
"skbedit ptype is only supported with type host");
return -EOPNOTSUPP;
}
ptype_host = true;
break;
case FLOW_ACTION_DROP:
action |= MLX5_FLOW_CONTEXT_ACTION_DROP |
MLX5_FLOW_CONTEXT_ACTION_COUNT;
......@@ -3920,6 +4037,50 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv,
break;
return -EOPNOTSUPP;
case FLOW_ACTION_REDIRECT_INGRESS: {
struct net_device *out_dev;
out_dev = act->dev;
if (!out_dev)
return -EOPNOTSUPP;
if (!netif_is_ovs_master(out_dev)) {
NL_SET_ERR_MSG_MOD(extack,
"redirect to ingress is supported only for OVS internal ports");
return -EOPNOTSUPP;
}
if (netif_is_ovs_master(parse_attr->filter_dev)) {
NL_SET_ERR_MSG_MOD(extack,
"redirect to ingress is not supported from internal port");
return -EOPNOTSUPP;
}
if (!ptype_host) {
NL_SET_ERR_MSG_MOD(extack,
"redirect to int port ingress requires ptype=host action");
return -EOPNOTSUPP;
}
if (esw_attr->out_count) {
NL_SET_ERR_MSG_MOD(extack,
"redirect to int port ingress is supported only as single destination");
return -EOPNOTSUPP;
}
action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
MLX5_FLOW_CONTEXT_ACTION_COUNT;
err = mlx5e_set_fwd_to_int_port_actions(priv, attr, out_dev->ifindex,
MLX5E_TC_INT_PORT_INGRESS,
&action, esw_attr->out_count);
if (err)
return err;
esw_attr->out_count++;
break;
}
case FLOW_ACTION_REDIRECT:
case FLOW_ACTION_MIRRED: {
struct mlx5e_priv *out_priv;
......@@ -4029,6 +4190,16 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv,
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,
&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
......@@ -4130,6 +4301,14 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv,
}
}
/* Forward to/from internal port can only have 1 dest */
if ((netif_is_ovs_master(parse_attr->filter_dev) || esw_attr->dest_int_port) &&
esw_attr->out_count > 1) {
NL_SET_ERR_MSG_MOD(extack,
"Rules with internal port can have only one destination");
return -EOPNOTSUPP;
}
/* always set IP version for indirect table handling */
attr->ip_version = mlx5e_tc_get_ip_version(&parse_attr->spec, true);
......@@ -5074,6 +5253,8 @@ int mlx5e_tc_esw_init(struct rhashtable *tc_ht)
MLX5_FLOW_NAMESPACE_FDB,
uplink_priv->post_act);
uplink_priv->int_port_priv = mlx5e_tc_int_port_init(netdev_priv(priv->netdev));
uplink_priv->tc_psample = mlx5e_tc_sample_init(esw, uplink_priv->post_act);
mapping_id = mlx5_query_nic_system_image_guid(esw->dev);
......@@ -5121,6 +5302,7 @@ int mlx5e_tc_esw_init(struct rhashtable *tc_ht)
mapping_destroy(uplink_priv->tunnel_mapping);
err_tun_mapping:
mlx5e_tc_sample_cleanup(uplink_priv->tc_psample);
mlx5e_tc_int_port_cleanup(uplink_priv->int_port_priv);
mlx5_tc_ct_clean(uplink_priv->ct_priv);
netdev_warn(priv->netdev,
"Failed to initialize tc (eswitch), err: %d", err);
......@@ -5141,6 +5323,7 @@ void mlx5e_tc_esw_cleanup(struct rhashtable *tc_ht)
mapping_destroy(uplink_priv->tunnel_mapping);
mlx5e_tc_sample_cleanup(uplink_priv->tc_psample);
mlx5e_tc_int_port_cleanup(uplink_priv->int_port_priv);
mlx5_tc_ct_clean(uplink_priv->ct_priv);
mlx5e_tc_post_act_destroy(uplink_priv->post_act);
}
......
......@@ -38,6 +38,7 @@
#include "eswitch.h"
#include "en/tc_ct.h"
#include "en/tc_tun.h"
#include "en/tc/int_port.h"
#include "en_rep.h"
#define MLX5E_TC_FLOW_ID_MASK 0x0000ffff
......@@ -56,7 +57,7 @@
int mlx5e_tc_num_filters(struct mlx5e_priv *priv, unsigned long flags);
struct mlx5e_tc_update_priv {
struct net_device *tun_dev;
struct net_device *fwd_dev;
};
struct mlx5_nic_flow_attr {
......@@ -104,6 +105,8 @@ struct mlx5_rx_tun_attr {
#define MLX5E_TC_TABLE_CHAIN_TAG_BITS 16
#define MLX5E_TC_TABLE_CHAIN_TAG_MASK GENMASK(MLX5E_TC_TABLE_CHAIN_TAG_BITS - 1, 0)
#define MLX5E_TC_MAX_INT_PORT_NUM (8)
#if IS_ENABLED(CONFIG_MLX5_CLS_ACT)
struct tunnel_match_key {
......@@ -283,6 +286,12 @@ bool mlx5e_tc_is_vf_tunnel(struct net_device *out_dev, struct net_device *route_
int mlx5e_tc_query_route_vport(struct net_device *out_dev, struct net_device *route_dev,
u16 *vport);
int mlx5e_set_fwd_to_int_port_actions(struct mlx5e_priv *priv,
struct mlx5_flow_attr *attr,
int ifindex,
enum mlx5e_tc_int_port_type type,
u32 *action,
int out_index);
#else /* CONFIG_MLX5_CLS_ACT */
static inline int mlx5e_tc_nic_init(struct mlx5e_priv *priv) { return 0; }
static inline void mlx5e_tc_nic_cleanup(struct mlx5e_priv *priv) {}
......
......@@ -38,6 +38,7 @@
#include "en/txrx.h"
#include "ipoib/ipoib.h"
#include "en_accel/en_accel.h"
#include "en_accel/ipsec_rxtx.h"
#include "en/ptp.h"
static void mlx5e_dma_unmap_wqe_err(struct mlx5e_txqsq *sq, u8 num_dma)
......@@ -213,30 +214,13 @@ static inline void mlx5e_insert_vlan(void *start, struct sk_buff *skb, u16 ihs)
memcpy(&vhdr->h_vlan_encapsulated_proto, skb->data + cpy1_sz, cpy2_sz);
}
static void
ipsec_txwqe_build_eseg_csum(struct mlx5e_txqsq *sq, struct sk_buff *skb,
struct mlx5_wqe_eth_seg *eseg)
{
struct xfrm_offload *xo = xfrm_offload(skb);
eseg->cs_flags = MLX5_ETH_WQE_L3_CSUM;
if (xo->inner_ipproto) {
eseg->cs_flags |= MLX5_ETH_WQE_L4_INNER_CSUM | MLX5_ETH_WQE_L3_INNER_CSUM;
} else if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) {
eseg->cs_flags |= MLX5_ETH_WQE_L4_CSUM;
sq->stats->csum_partial_inner++;
}
}
static inline void
mlx5e_txwqe_build_eseg_csum(struct mlx5e_txqsq *sq, struct sk_buff *skb,
struct mlx5e_accel_tx_state *accel,
struct mlx5_wqe_eth_seg *eseg)
{
if (unlikely(mlx5e_ipsec_eseg_meta(eseg))) {
ipsec_txwqe_build_eseg_csum(sq, skb, eseg);
if (unlikely(mlx5e_ipsec_txwqe_build_eseg_csum(sq, skb, eseg)))
return;
}
if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) {
eseg->cs_flags = MLX5_ETH_WQE_L3_CSUM;
......
......@@ -51,6 +51,7 @@
enum mlx5_mapped_obj_type {
MLX5_MAPPED_OBJ_CHAIN,
MLX5_MAPPED_OBJ_SAMPLE,
MLX5_MAPPED_OBJ_INT_PORT_METADATA,
};
struct mlx5_mapped_obj {
......@@ -63,6 +64,7 @@ struct mlx5_mapped_obj {
u32 trunc_size;
u32 tunnel_id;
} sample;
u32 int_port_metadata;
};
};
......@@ -88,6 +90,7 @@ enum {
MAPPING_TYPE_TUNNEL_ENC_OPTS,
MAPPING_TYPE_LABELS,
MAPPING_TYPE_ZONE,
MAPPING_TYPE_INT_PORT,
};
struct vport_ingress {
......@@ -336,6 +339,9 @@ void mlx5_esw_match_metadata_free(struct mlx5_eswitch *esw, u32 metadata);
int mlx5_esw_qos_modify_vport_rate(struct mlx5_eswitch *esw, u16 vport_num, u32 rate_mbps);
bool mlx5_esw_vport_match_metadata_supported(const struct mlx5_eswitch *esw);
int mlx5_esw_offloads_vport_metadata_set(struct mlx5_eswitch *esw, bool enable);
/* E-Switch API */
int mlx5_eswitch_init(struct mlx5_core_dev *dev);
void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw);
......@@ -461,6 +467,8 @@ struct mlx5_esw_flow_attr {
struct mlx5_eswitch_rep *in_rep;
struct mlx5_core_dev *in_mdev;
struct mlx5_core_dev *counter_dev;
struct mlx5e_tc_int_port *dest_int_port;
struct mlx5e_tc_int_port *int_port;
int split_count;
int out_count;
......
......@@ -86,12 +86,18 @@ mlx5_eswitch_set_rule_flow_source(struct mlx5_eswitch *esw,
struct mlx5_flow_spec *spec,
struct mlx5_esw_flow_attr *attr)
{
if (MLX5_CAP_ESW_FLOWTABLE(esw->dev, flow_source) &&
attr && attr->in_rep)
spec->flow_context.flow_source =
attr->in_rep->vport == MLX5_VPORT_UPLINK ?
MLX5_FLOW_CONTEXT_FLOW_SOURCE_UPLINK :
MLX5_FLOW_CONTEXT_FLOW_SOURCE_LOCAL_VPORT;
if (!MLX5_CAP_ESW_FLOWTABLE(esw->dev, flow_source) || !attr || !attr->in_rep)
return;
if (attr->int_port) {
spec->flow_context.flow_source = mlx5e_tc_int_port_get_flow_source(attr->int_port);
return;
}
spec->flow_context.flow_source = (attr->in_rep->vport == MLX5_VPORT_UPLINK) ?
MLX5_FLOW_CONTEXT_FLOW_SOURCE_UPLINK :
MLX5_FLOW_CONTEXT_FLOW_SOURCE_LOCAL_VPORT;
}
/* Actually only the upper 16 bits of reg c0 need to be cleared, but the lower 16 bits
......@@ -121,6 +127,8 @@ mlx5_eswitch_set_rule_source_port(struct mlx5_eswitch *esw,
struct mlx5_eswitch *src_esw,
u16 vport)
{
struct mlx5_esw_flow_attr *esw_attr = attr->esw_attr;
u32 metadata;
void *misc2;
void *misc;
......@@ -130,10 +138,16 @@ mlx5_eswitch_set_rule_source_port(struct mlx5_eswitch *esw,
if (mlx5_eswitch_vport_match_metadata_enabled(esw)) {
if (mlx5_esw_indir_table_decap_vport(attr))
vport = mlx5_esw_indir_table_decap_vport(attr);
if (esw_attr->int_port)
metadata =
mlx5e_tc_int_port_get_metadata_for_match(esw_attr->int_port);
else
metadata =
mlx5_eswitch_get_vport_metadata_for_match(src_esw, vport);
misc2 = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters_2);
MLX5_SET(fte_match_set_misc2, misc2, metadata_reg_c_0,
mlx5_eswitch_get_vport_metadata_for_match(src_esw,
vport));
MLX5_SET(fte_match_set_misc2, misc2, metadata_reg_c_0, metadata);
misc2 = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters_2);
MLX5_SET(fte_match_set_misc2, misc2, metadata_reg_c_0,
......@@ -290,8 +304,11 @@ esw_setup_chain_src_port_rewrite(struct mlx5_flow_destination *dest,
err = esw_setup_chain_dest(dest, flow_act, chains, attr->dest_chain, 1, 0, *i);
if (err)
goto err_setup_chain;
flow_act->action |= MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT;
flow_act->pkt_reformat = esw_attr->dests[j].pkt_reformat;
if (esw_attr->dests[j].pkt_reformat) {
flow_act->action |= MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT;
flow_act->pkt_reformat = esw_attr->dests[j].pkt_reformat;
}
}
return 0;
......@@ -315,7 +332,8 @@ esw_is_indir_table(struct mlx5_eswitch *esw, struct mlx5_flow_attr *attr)
int i;
for (i = esw_attr->split_count; i < esw_attr->out_count; i++)
if (mlx5_esw_indir_table_needed(esw, attr, esw_attr->dests[i].rep->vport,
if (esw_attr->dests[i].rep &&
mlx5_esw_indir_table_needed(esw, attr, esw_attr->dests[i].rep->vport,
esw_attr->dests[i].mdev))
return true;
return false;
......@@ -1857,6 +1875,17 @@ static void esw_destroy_offloads_fdb_tables(struct mlx5_eswitch *esw)
atomic64_set(&esw->user_count, 0);
}
static int esw_get_offloads_ft_size(struct mlx5_eswitch *esw)
{
int nvports;
nvports = esw->total_vports + MLX5_ESW_MISS_FLOWS;
if (mlx5e_tc_int_port_supported(esw))
nvports += MLX5E_TC_MAX_INT_PORT_NUM;
return nvports;
}
static int esw_create_offloads_table(struct mlx5_eswitch *esw)
{
struct mlx5_flow_table_attr ft_attr = {};
......@@ -1871,7 +1900,7 @@ static int esw_create_offloads_table(struct mlx5_eswitch *esw)
return -EOPNOTSUPP;
}
ft_attr.max_fte = esw->total_vports + MLX5_ESW_MISS_FLOWS;
ft_attr.max_fte = esw_get_offloads_ft_size(esw);
ft_attr.prio = 1;
ft_offloads = mlx5_create_flow_table(ns, &ft_attr);
......@@ -1900,7 +1929,7 @@ static int esw_create_vport_rx_group(struct mlx5_eswitch *esw)
int nvports;
int err = 0;
nvports = esw->total_vports + MLX5_ESW_MISS_FLOWS;
nvports = esw_get_offloads_ft_size(esw);
flow_group_in = kvzalloc(inlen, GFP_KERNEL);
if (!flow_group_in)
return -ENOMEM;
......@@ -2805,7 +2834,8 @@ bool mlx5_esw_vport_match_metadata_supported(const struct mlx5_eswitch *esw)
u32 mlx5_esw_match_metadata_alloc(struct mlx5_eswitch *esw)
{
u32 vport_end_ida = (1 << ESW_VPORT_BITS) - 1;
u32 max_pf_num = (1 << ESW_PFNUM_BITS) - 1;
/* Reserve 0xf for internal port offload */
u32 max_pf_num = (1 << ESW_PFNUM_BITS) - 2;
u32 pf_num;
int id;
......
......@@ -220,7 +220,7 @@ mlx5_eswitch_termtbl_required(struct mlx5_eswitch *esw,
if (!MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, termination_table) ||
!MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, ignore_flow_level) ||
mlx5_esw_attr_flags_skip(attr->flags) ||
!mlx5_eswitch_offload_is_uplink_port(esw, spec))
(!mlx5_eswitch_offload_is_uplink_port(esw, spec) && !esw_attr->int_port))
return false;
/* push vlan on RX */
......@@ -229,7 +229,8 @@ mlx5_eswitch_termtbl_required(struct mlx5_eswitch *esw,
/* hairpin */
for (i = esw_attr->split_count; i < esw_attr->out_count; i++)
if (esw_attr->dests[i].rep->vport == MLX5_VPORT_UPLINK)
if (!esw_attr->dest_int_port && esw_attr->dests[i].rep &&
esw_attr->dests[i].rep->vport == MLX5_VPORT_UPLINK)
return true;
return false;
......
......@@ -301,7 +301,7 @@ static struct mlx5_fc *mlx5_fc_acquire(struct mlx5_core_dev *dev, bool aging)
return mlx5_fc_single_alloc(dev);
}
struct mlx5_fc *mlx5_fc_create(struct mlx5_core_dev *dev, bool aging)
struct mlx5_fc *mlx5_fc_create_ex(struct mlx5_core_dev *dev, bool aging)
{
struct mlx5_fc *counter = mlx5_fc_acquire(dev, aging);
struct mlx5_fc_stats *fc_stats = &dev->priv.fc_stats;
......@@ -332,8 +332,6 @@ struct mlx5_fc *mlx5_fc_create(struct mlx5_core_dev *dev, bool aging)
goto err_out_alloc;
llist_add(&counter->addlist, &fc_stats->addlist);
mod_delayed_work(fc_stats->wq, &fc_stats->work, 0);
}
return counter;
......@@ -342,6 +340,16 @@ struct mlx5_fc *mlx5_fc_create(struct mlx5_core_dev *dev, bool aging)
mlx5_fc_release(dev, counter);
return ERR_PTR(err);
}
struct mlx5_fc *mlx5_fc_create(struct mlx5_core_dev *dev, bool aging)
{
struct mlx5_fc *counter = mlx5_fc_create_ex(dev, aging);
struct mlx5_fc_stats *fc_stats = &dev->priv.fc_stats;
if (aging)
mod_delayed_work(fc_stats->wq, &fc_stats->work, 0);
return counter;
}
EXPORT_SYMBOL(mlx5_fc_create);
u32 mlx5_fc_id(struct mlx5_fc *counter)
......
......@@ -875,9 +875,10 @@ static int dr_matcher_init_fdb(struct mlx5dr_matcher *matcher)
static int dr_matcher_init(struct mlx5dr_matcher *matcher,
struct mlx5dr_match_parameters *mask)
{
struct mlx5dr_match_parameters consumed_mask;
struct mlx5dr_table *tbl = matcher->tbl;
struct mlx5dr_domain *dmn = tbl->dmn;
int ret;
int i, ret;
if (matcher->match_criteria >= DR_MATCHER_CRITERIA_MAX) {
mlx5dr_err(dmn, "Invalid match criteria attribute\n");
......@@ -889,8 +890,16 @@ static int dr_matcher_init(struct mlx5dr_matcher *matcher,
mlx5dr_err(dmn, "Invalid match size attribute\n");
return -EINVAL;
}
consumed_mask.match_buf = kzalloc(mask->match_sz, GFP_KERNEL);
if (!consumed_mask.match_buf)
return -ENOMEM;
consumed_mask.match_sz = mask->match_sz;
memcpy(consumed_mask.match_buf, mask->match_buf, mask->match_sz);
mlx5dr_ste_copy_param(matcher->match_criteria,
&matcher->mask, mask);
&matcher->mask, &consumed_mask,
true);
}
switch (dmn->type) {
......@@ -909,9 +918,22 @@ static int dr_matcher_init(struct mlx5dr_matcher *matcher,
break;
default:
WARN_ON(true);
return -EINVAL;
ret = -EINVAL;
goto free_consumed_mask;
}
/* Check that all mask data was consumed */
for (i = 0; i < consumed_mask.match_sz; i++) {
if (consumed_mask.match_buf[i]) {
mlx5dr_dbg(dmn, "Match param mask contains unsupported parameters\n");
ret = -EOPNOTSUPP;
goto free_consumed_mask;
}
}
ret = 0;
free_consumed_mask:
kfree(consumed_mask.match_buf);
return ret;
}
......
......@@ -917,7 +917,7 @@ static bool dr_rule_verify(struct mlx5dr_matcher *matcher,
return false;
}
mlx5dr_ste_copy_param(matcher->match_criteria, param, value);
mlx5dr_ste_copy_param(matcher->match_criteria, param, value, false);
if (match_criteria & DR_MATCHER_CRITERIA_OUTER) {
s_idx = offsetof(struct mlx5dr_match_param, outer);
......
......@@ -1230,7 +1230,8 @@ void mlx5dr_ste_set_formatted_ste(struct mlx5dr_ste_ctx *ste_ctx,
struct mlx5dr_htbl_connect_info *connect_info);
void mlx5dr_ste_copy_param(u8 match_criteria,
struct mlx5dr_match_param *set_param,
struct mlx5dr_match_parameters *mask);
struct mlx5dr_match_parameters *mask,
bool clear);
struct mlx5dr_qp {
struct mlx5_core_dev *mdev;
......
......@@ -245,6 +245,10 @@ int mlx5_modify_rule_destination(struct mlx5_flow_handle *handler,
struct mlx5_flow_destination *old_dest);
struct mlx5_fc *mlx5_fc_create(struct mlx5_core_dev *dev, bool aging);
/* As mlx5_fc_create() but doesn't queue stats refresh thread. */
struct mlx5_fc *mlx5_fc_create_ex(struct mlx5_core_dev *dev, bool aging);
void mlx5_fc_destroy(struct mlx5_core_dev *dev, struct mlx5_fc *counter);
u64 mlx5_fc_query_lastuse(struct mlx5_fc *counter);
void mlx5_fc_query_cached(struct mlx5_fc *counter,
......
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