Commit edd8b295 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'mlx5-ipsec-packet-offload-support-in-eswitch-mode'

Leon Romanovsky says:

====================
mlx5 IPsec packet offload support in eswitch mode

This series from Jianbo adds mlx5 IPsec packet offload support in eswitch
offloaded mode.

It works exactly like "regular" IPsec, nothing special, except
now users can switch to switchdev before adding IPsec rules.

 devlink dev eswitch set pci/0000:06:00.0 mode switchdev

Same configurations as here:

https://lore.kernel.org/netdev/cover.1670005543.git.leonro@nvidia.com/

Packet offload mode:
  ip xfrm state offload packet dev <if-name> dir <in|out>
  ip xfrm policy .... offload packet dev <if-name>
Crypto offload mode:
  ip xfrm state offload crypto dev <if-name> dir <in|out>
or (backward compatibility)
  ip xfrm state offload dev <if-name> dir <in|out>

v0: https://lore.kernel.org/all/cover.1689064922.git.leonro@nvidia.com
====================

Link: https://lore.kernel.org/r/cover.1690802064.git.leon@kernel.orgSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 30ff01ee c8e350e6
...@@ -75,6 +75,10 @@ mlx5_core-$(CONFIG_MLX5_ESWITCH) += esw/acl/helper.o \ ...@@ -75,6 +75,10 @@ mlx5_core-$(CONFIG_MLX5_ESWITCH) += esw/acl/helper.o \
esw/acl/egress_lgcy.o esw/acl/egress_ofld.o \ esw/acl/egress_lgcy.o esw/acl/egress_ofld.o \
esw/acl/ingress_lgcy.o esw/acl/ingress_ofld.o esw/acl/ingress_lgcy.o esw/acl/ingress_ofld.o
ifneq ($(CONFIG_MLX5_EN_IPSEC),)
mlx5_core-$(CONFIG_MLX5_ESWITCH) += esw/ipsec_fs.o
endif
mlx5_core-$(CONFIG_MLX5_BRIDGE) += esw/bridge.o esw/bridge_mcast.o esw/bridge_debugfs.o \ mlx5_core-$(CONFIG_MLX5_BRIDGE) += esw/bridge.o esw/bridge_mcast.o esw/bridge_debugfs.o \
en/rep/bridge.o en/rep/bridge.o
......
...@@ -715,9 +715,20 @@ void mlx5e_rep_tc_receive(struct mlx5_cqe64 *cqe, struct mlx5e_rq *rq, ...@@ -715,9 +715,20 @@ void mlx5e_rep_tc_receive(struct mlx5_cqe64 *cqe, struct mlx5e_rq *rq,
uplink_priv = &uplink_rpriv->uplink_priv; uplink_priv = &uplink_rpriv->uplink_priv;
ct_priv = uplink_priv->ct_priv; ct_priv = uplink_priv->ct_priv;
if (!mlx5_ipsec_is_rx_flow(cqe) && #ifdef CONFIG_MLX5_EN_IPSEC
!mlx5e_tc_update_skb(cqe, skb, mapping_ctx, reg_c0, ct_priv, zone_restore_id, tunnel_id, if (!(tunnel_id >> ESW_TUN_OPTS_BITS)) {
&tc_priv)) u32 mapped_id;
u32 metadata;
mapped_id = tunnel_id & ESW_IPSEC_RX_MAPPED_ID_MASK;
if (mapped_id &&
!mlx5_esw_ipsec_rx_make_metadata(priv, mapped_id, &metadata))
mlx5e_ipsec_offload_handle_rx_skb(priv->netdev, skb, metadata);
}
#endif
if (!mlx5e_tc_update_skb(cqe, skb, mapping_ctx, reg_c0, ct_priv,
zone_restore_id, tunnel_id, &tc_priv))
goto free_skb; goto free_skb;
forward: forward:
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#include "en.h" #include "en.h"
#include "ipsec.h" #include "ipsec.h"
#include "ipsec_rxtx.h" #include "ipsec_rxtx.h"
#include "en_rep.h"
#define MLX5_IPSEC_RESCHED msecs_to_jiffies(1000) #define MLX5_IPSEC_RESCHED msecs_to_jiffies(1000)
#define MLX5E_IPSEC_TUNNEL_SA XA_MARK_1 #define MLX5E_IPSEC_TUNNEL_SA XA_MARK_1
...@@ -858,6 +859,7 @@ void mlx5e_ipsec_init(struct mlx5e_priv *priv) ...@@ -858,6 +859,7 @@ void mlx5e_ipsec_init(struct mlx5e_priv *priv)
goto clear_aso; goto clear_aso;
} }
ipsec->is_uplink_rep = mlx5e_is_uplink_rep(priv);
ret = mlx5e_accel_ipsec_fs_init(ipsec); ret = mlx5e_accel_ipsec_fs_init(ipsec);
if (ret) if (ret)
goto err_fs_init; goto err_fs_init;
......
...@@ -143,7 +143,7 @@ struct mlx5e_ipsec_sw_stats { ...@@ -143,7 +143,7 @@ struct mlx5e_ipsec_sw_stats {
atomic64_t ipsec_tx_drop_trailer; atomic64_t ipsec_tx_drop_trailer;
}; };
struct mlx5e_ipsec_rx; struct mlx5e_ipsec_fc;
struct mlx5e_ipsec_tx; struct mlx5e_ipsec_tx;
struct mlx5e_ipsec_work { struct mlx5e_ipsec_work {
...@@ -169,6 +169,58 @@ struct mlx5e_ipsec_aso { ...@@ -169,6 +169,58 @@ struct mlx5e_ipsec_aso {
spinlock_t lock; spinlock_t lock;
}; };
struct mlx5e_ipsec_rx_create_attr {
struct mlx5_flow_namespace *ns;
struct mlx5_ttc_table *ttc;
u32 family;
int prio;
int pol_level;
int sa_level;
int status_level;
enum mlx5_flow_namespace_type chains_ns;
};
struct mlx5e_ipsec_ft {
struct mutex mutex; /* Protect changes to this struct */
struct mlx5_flow_table *pol;
struct mlx5_flow_table *sa;
struct mlx5_flow_table *status;
u32 refcnt;
};
struct mlx5e_ipsec_rule {
struct mlx5_flow_handle *rule;
struct mlx5_modify_hdr *modify_hdr;
struct mlx5_pkt_reformat *pkt_reformat;
struct mlx5_fc *fc;
};
struct mlx5e_ipsec_miss {
struct mlx5_flow_group *group;
struct mlx5_flow_handle *rule;
};
struct mlx5e_ipsec_rx {
struct mlx5e_ipsec_ft ft;
struct mlx5e_ipsec_miss pol;
struct mlx5e_ipsec_miss sa;
struct mlx5e_ipsec_rule status;
struct mlx5e_ipsec_miss status_drop;
struct mlx5_fc *status_drop_cnt;
struct mlx5e_ipsec_fc *fc;
struct mlx5_fs_chains *chains;
u8 allow_tunnel_mode : 1;
struct xarray ipsec_obj_id_map;
};
struct mlx5e_ipsec_tx_create_attr {
int prio;
int pol_level;
int sa_level;
int cnt_level;
enum mlx5_flow_namespace_type chains_ns;
};
struct mlx5e_ipsec { struct mlx5e_ipsec {
struct mlx5_core_dev *mdev; struct mlx5_core_dev *mdev;
struct xarray sadb; struct xarray sadb;
...@@ -178,11 +230,14 @@ struct mlx5e_ipsec { ...@@ -178,11 +230,14 @@ struct mlx5e_ipsec {
struct mlx5e_flow_steering *fs; struct mlx5e_flow_steering *fs;
struct mlx5e_ipsec_rx *rx_ipv4; struct mlx5e_ipsec_rx *rx_ipv4;
struct mlx5e_ipsec_rx *rx_ipv6; struct mlx5e_ipsec_rx *rx_ipv6;
struct mlx5e_ipsec_rx *rx_esw;
struct mlx5e_ipsec_tx *tx; struct mlx5e_ipsec_tx *tx;
struct mlx5e_ipsec_tx *tx_esw;
struct mlx5e_ipsec_aso *aso; struct mlx5e_ipsec_aso *aso;
struct notifier_block nb; struct notifier_block nb;
struct notifier_block netevent_nb; struct notifier_block netevent_nb;
struct mlx5_ipsec_fs *roce; struct mlx5_ipsec_fs *roce;
u8 is_uplink_rep: 1;
}; };
struct mlx5e_ipsec_esn_state { struct mlx5e_ipsec_esn_state {
...@@ -191,13 +246,6 @@ struct mlx5e_ipsec_esn_state { ...@@ -191,13 +246,6 @@ struct mlx5e_ipsec_esn_state {
u8 overlap: 1; u8 overlap: 1;
}; };
struct mlx5e_ipsec_rule {
struct mlx5_flow_handle *rule;
struct mlx5_modify_hdr *modify_hdr;
struct mlx5_pkt_reformat *pkt_reformat;
struct mlx5_fc *fc;
};
struct mlx5e_ipsec_limits { struct mlx5e_ipsec_limits {
u64 round; u64 round;
u8 soft_limit_hit : 1; u8 soft_limit_hit : 1;
...@@ -217,6 +265,7 @@ struct mlx5e_ipsec_sa_entry { ...@@ -217,6 +265,7 @@ struct mlx5e_ipsec_sa_entry {
struct mlx5e_ipsec_work *work; struct mlx5e_ipsec_work *work;
struct mlx5e_ipsec_dwork *dwork; struct mlx5e_ipsec_dwork *dwork;
struct mlx5e_ipsec_limits limits; struct mlx5e_ipsec_limits limits;
u32 rx_mapped_id;
}; };
struct mlx5_accel_pol_xfrm_attrs { struct mlx5_accel_pol_xfrm_attrs {
......
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
#include "fs_core.h" #include "fs_core.h"
#include "lib/ipsec_fs_roce.h" #include "lib/ipsec_fs_roce.h"
#include "lib/fs_chains.h" #include "lib/fs_chains.h"
#include "esw/ipsec_fs.h"
#include "en_rep.h"
#define NUM_IPSEC_FTE BIT(15) #define NUM_IPSEC_FTE BIT(15)
#define MLX5_REFORMAT_TYPE_ADD_ESP_TRANSPORT_SIZE 16 #define MLX5_REFORMAT_TYPE_ADD_ESP_TRANSPORT_SIZE 16
...@@ -19,32 +21,10 @@ struct mlx5e_ipsec_fc { ...@@ -19,32 +21,10 @@ struct mlx5e_ipsec_fc {
struct mlx5_fc *drop; struct mlx5_fc *drop;
}; };
struct mlx5e_ipsec_ft {
struct mutex mutex; /* Protect changes to this struct */
struct mlx5_flow_table *pol;
struct mlx5_flow_table *sa;
struct mlx5_flow_table *status;
u32 refcnt;
};
struct mlx5e_ipsec_miss {
struct mlx5_flow_group *group;
struct mlx5_flow_handle *rule;
};
struct mlx5e_ipsec_rx {
struct mlx5e_ipsec_ft ft;
struct mlx5e_ipsec_miss pol;
struct mlx5e_ipsec_miss sa;
struct mlx5e_ipsec_rule status;
struct mlx5e_ipsec_fc *fc;
struct mlx5_fs_chains *chains;
u8 allow_tunnel_mode : 1;
};
struct mlx5e_ipsec_tx { struct mlx5e_ipsec_tx {
struct mlx5e_ipsec_ft ft; struct mlx5e_ipsec_ft ft;
struct mlx5e_ipsec_miss pol; struct mlx5e_ipsec_miss pol;
struct mlx5e_ipsec_miss sa;
struct mlx5e_ipsec_rule status; struct mlx5e_ipsec_rule status;
struct mlx5_flow_namespace *ns; struct mlx5_flow_namespace *ns;
struct mlx5e_ipsec_fc *fc; struct mlx5e_ipsec_fc *fc;
...@@ -60,14 +40,25 @@ static enum mlx5_traffic_types family2tt(u32 family) ...@@ -60,14 +40,25 @@ static enum mlx5_traffic_types family2tt(u32 family)
return MLX5_TT_IPV6_IPSEC_ESP; return MLX5_TT_IPV6_IPSEC_ESP;
} }
static struct mlx5e_ipsec_rx *ipsec_rx(struct mlx5e_ipsec *ipsec, u32 family) static struct mlx5e_ipsec_rx *ipsec_rx(struct mlx5e_ipsec *ipsec, u32 family, int type)
{ {
if (ipsec->is_uplink_rep && type == XFRM_DEV_OFFLOAD_PACKET)
return ipsec->rx_esw;
if (family == AF_INET) if (family == AF_INET)
return ipsec->rx_ipv4; return ipsec->rx_ipv4;
return ipsec->rx_ipv6; return ipsec->rx_ipv6;
} }
static struct mlx5e_ipsec_tx *ipsec_tx(struct mlx5e_ipsec *ipsec, int type)
{
if (ipsec->is_uplink_rep && type == XFRM_DEV_OFFLOAD_PACKET)
return ipsec->tx_esw;
return ipsec->tx;
}
static struct mlx5_fs_chains * static struct mlx5_fs_chains *
ipsec_chains_create(struct mlx5_core_dev *mdev, struct mlx5_flow_table *miss_ft, ipsec_chains_create(struct mlx5_core_dev *mdev, struct mlx5_flow_table *miss_ft,
enum mlx5_flow_namespace_type ns, int base_prio, enum mlx5_flow_namespace_type ns, int base_prio,
...@@ -238,13 +229,19 @@ static int ipsec_miss_create(struct mlx5_core_dev *mdev, ...@@ -238,13 +229,19 @@ static int ipsec_miss_create(struct mlx5_core_dev *mdev,
return err; return err;
} }
static void rx_destroy(struct mlx5_core_dev *mdev, struct mlx5e_ipsec *ipsec, static void ipsec_rx_ft_disconnect(struct mlx5e_ipsec *ipsec, u32 family)
struct mlx5e_ipsec_rx *rx, u32 family)
{ {
struct mlx5_ttc_table *ttc = mlx5e_fs_get_ttc(ipsec->fs, false); struct mlx5_ttc_table *ttc = mlx5e_fs_get_ttc(ipsec->fs, false);
/* disconnect */
mlx5_ttc_fwd_default_dest(ttc, family2tt(family)); mlx5_ttc_fwd_default_dest(ttc, family2tt(family));
}
static void rx_destroy(struct mlx5_core_dev *mdev, struct mlx5e_ipsec *ipsec,
struct mlx5e_ipsec_rx *rx, u32 family)
{
/* disconnect */
if (rx != ipsec->rx_esw)
ipsec_rx_ft_disconnect(ipsec, family);
if (rx->chains) { if (rx->chains) {
ipsec_chains_destroy(rx->chains); ipsec_chains_destroy(rx->chains);
...@@ -257,63 +254,112 @@ static void rx_destroy(struct mlx5_core_dev *mdev, struct mlx5e_ipsec *ipsec, ...@@ -257,63 +254,112 @@ static void rx_destroy(struct mlx5_core_dev *mdev, struct mlx5e_ipsec *ipsec,
mlx5_del_flow_rules(rx->sa.rule); mlx5_del_flow_rules(rx->sa.rule);
mlx5_destroy_flow_group(rx->sa.group); mlx5_destroy_flow_group(rx->sa.group);
mlx5_destroy_flow_table(rx->ft.sa); mlx5_destroy_flow_table(rx->ft.sa);
if (rx->allow_tunnel_mode) if (rx == ipsec->rx_esw) {
mlx5_eswitch_unblock_encap(mdev); mlx5_esw_ipsec_rx_status_destroy(ipsec, rx);
mlx5_del_flow_rules(rx->status.rule); } else {
mlx5_modify_header_dealloc(mdev, rx->status.modify_hdr); mlx5_del_flow_rules(rx->status.rule);
mlx5_modify_header_dealloc(mdev, rx->status.modify_hdr);
}
mlx5_destroy_flow_table(rx->ft.status); mlx5_destroy_flow_table(rx->ft.status);
mlx5_ipsec_fs_roce_rx_destroy(ipsec->roce, family); mlx5_ipsec_fs_roce_rx_destroy(ipsec->roce, family);
} }
static void ipsec_rx_create_attr_set(struct mlx5e_ipsec *ipsec,
struct mlx5e_ipsec_rx *rx,
u32 family,
struct mlx5e_ipsec_rx_create_attr *attr)
{
if (rx == ipsec->rx_esw) {
/* For packet offload in switchdev mode, RX & TX use FDB namespace */
attr->ns = ipsec->tx_esw->ns;
mlx5_esw_ipsec_rx_create_attr_set(ipsec, attr);
return;
}
attr->ns = mlx5e_fs_get_ns(ipsec->fs, false);
attr->ttc = mlx5e_fs_get_ttc(ipsec->fs, false);
attr->family = family;
attr->prio = MLX5E_NIC_PRIO;
attr->pol_level = MLX5E_ACCEL_FS_POL_FT_LEVEL;
attr->sa_level = MLX5E_ACCEL_FS_ESP_FT_LEVEL;
attr->status_level = MLX5E_ACCEL_FS_ESP_FT_ERR_LEVEL;
attr->chains_ns = MLX5_FLOW_NAMESPACE_KERNEL;
}
static int ipsec_rx_status_pass_dest_get(struct mlx5e_ipsec *ipsec,
struct mlx5e_ipsec_rx *rx,
struct mlx5e_ipsec_rx_create_attr *attr,
struct mlx5_flow_destination *dest)
{
struct mlx5_flow_table *ft;
int err;
if (rx == ipsec->rx_esw)
return mlx5_esw_ipsec_rx_status_pass_dest_get(ipsec, dest);
*dest = mlx5_ttc_get_default_dest(attr->ttc, family2tt(attr->family));
err = mlx5_ipsec_fs_roce_rx_create(ipsec->mdev, ipsec->roce, attr->ns, dest,
attr->family, MLX5E_ACCEL_FS_ESP_FT_ROCE_LEVEL,
attr->prio);
if (err)
return err;
ft = mlx5_ipsec_fs_roce_ft_get(ipsec->roce, attr->family);
if (ft) {
dest->type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
dest->ft = ft;
}
return 0;
}
static void ipsec_rx_ft_connect(struct mlx5e_ipsec *ipsec,
struct mlx5e_ipsec_rx *rx,
struct mlx5e_ipsec_rx_create_attr *attr)
{
struct mlx5_flow_destination dest = {};
dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
dest.ft = rx->ft.pol;
mlx5_ttc_fwd_dest(attr->ttc, family2tt(attr->family), &dest);
}
static int rx_create(struct mlx5_core_dev *mdev, struct mlx5e_ipsec *ipsec, static int rx_create(struct mlx5_core_dev *mdev, struct mlx5e_ipsec *ipsec,
struct mlx5e_ipsec_rx *rx, u32 family) struct mlx5e_ipsec_rx *rx, u32 family)
{ {
struct mlx5_flow_namespace *ns = mlx5e_fs_get_ns(ipsec->fs, false); struct mlx5e_ipsec_rx_create_attr attr;
struct mlx5_ttc_table *ttc = mlx5e_fs_get_ttc(ipsec->fs, false);
struct mlx5_flow_destination default_dest;
struct mlx5_flow_destination dest[2]; struct mlx5_flow_destination dest[2];
struct mlx5_flow_table *ft; struct mlx5_flow_table *ft;
u32 flags = 0; u32 flags = 0;
int err; int err;
default_dest = mlx5_ttc_get_default_dest(ttc, family2tt(family)); ipsec_rx_create_attr_set(ipsec, rx, family, &attr);
err = mlx5_ipsec_fs_roce_rx_create(mdev, ipsec->roce, ns, &default_dest,
family, MLX5E_ACCEL_FS_ESP_FT_ROCE_LEVEL, err = ipsec_rx_status_pass_dest_get(ipsec, rx, &attr, &dest[0]);
MLX5E_NIC_PRIO);
if (err) if (err)
return err; return err;
ft = ipsec_ft_create(ns, MLX5E_ACCEL_FS_ESP_FT_ERR_LEVEL, ft = ipsec_ft_create(attr.ns, attr.status_level, attr.prio, 1, 0);
MLX5E_NIC_PRIO, 1, 0);
if (IS_ERR(ft)) { if (IS_ERR(ft)) {
err = PTR_ERR(ft); err = PTR_ERR(ft);
goto err_fs_ft_status; goto err_fs_ft_status;
} }
rx->ft.status = ft; rx->ft.status = ft;
ft = mlx5_ipsec_fs_roce_ft_get(ipsec->roce, family);
if (ft) {
dest[0].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
dest[0].ft = ft;
} else {
dest[0] = default_dest;
}
dest[1].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER; dest[1].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
dest[1].counter_id = mlx5_fc_id(rx->fc->cnt); dest[1].counter_id = mlx5_fc_id(rx->fc->cnt);
err = ipsec_status_rule(mdev, rx, dest); if (rx == ipsec->rx_esw)
err = mlx5_esw_ipsec_rx_status_create(ipsec, rx, dest);
else
err = ipsec_status_rule(mdev, rx, dest);
if (err) if (err)
goto err_add; goto err_add;
/* Create FT */ /* Create FT */
if (mlx5_ipsec_device_caps(mdev) & MLX5_IPSEC_CAP_TUNNEL)
rx->allow_tunnel_mode = mlx5_eswitch_block_encap(mdev);
if (rx->allow_tunnel_mode) if (rx->allow_tunnel_mode)
flags = MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT; flags = MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT;
ft = ipsec_ft_create(ns, MLX5E_ACCEL_FS_ESP_FT_LEVEL, MLX5E_NIC_PRIO, 2, ft = ipsec_ft_create(attr.ns, attr.sa_level, attr.prio, 2, flags);
flags);
if (IS_ERR(ft)) { if (IS_ERR(ft)) {
err = PTR_ERR(ft); err = PTR_ERR(ft);
goto err_fs_ft; goto err_fs_ft;
...@@ -326,9 +372,9 @@ static int rx_create(struct mlx5_core_dev *mdev, struct mlx5e_ipsec *ipsec, ...@@ -326,9 +372,9 @@ static int rx_create(struct mlx5_core_dev *mdev, struct mlx5e_ipsec *ipsec,
if (mlx5_ipsec_device_caps(mdev) & MLX5_IPSEC_CAP_PRIO) { if (mlx5_ipsec_device_caps(mdev) & MLX5_IPSEC_CAP_PRIO) {
rx->chains = ipsec_chains_create(mdev, rx->ft.sa, rx->chains = ipsec_chains_create(mdev, rx->ft.sa,
MLX5_FLOW_NAMESPACE_KERNEL, attr.chains_ns,
MLX5E_NIC_PRIO, attr.prio,
MLX5E_ACCEL_FS_POL_FT_LEVEL, attr.pol_level,
&rx->ft.pol); &rx->ft.pol);
if (IS_ERR(rx->chains)) { if (IS_ERR(rx->chains)) {
err = PTR_ERR(rx->chains); err = PTR_ERR(rx->chains);
...@@ -338,8 +384,7 @@ static int rx_create(struct mlx5_core_dev *mdev, struct mlx5e_ipsec *ipsec, ...@@ -338,8 +384,7 @@ static int rx_create(struct mlx5_core_dev *mdev, struct mlx5e_ipsec *ipsec,
goto connect; goto connect;
} }
ft = ipsec_ft_create(ns, MLX5E_ACCEL_FS_POL_FT_LEVEL, MLX5E_NIC_PRIO, ft = ipsec_ft_create(attr.ns, attr.pol_level, attr.prio, 2, 0);
2, 0);
if (IS_ERR(ft)) { if (IS_ERR(ft)) {
err = PTR_ERR(ft); err = PTR_ERR(ft);
goto err_pol_ft; goto err_pol_ft;
...@@ -354,10 +399,8 @@ static int rx_create(struct mlx5_core_dev *mdev, struct mlx5e_ipsec *ipsec, ...@@ -354,10 +399,8 @@ static int rx_create(struct mlx5_core_dev *mdev, struct mlx5e_ipsec *ipsec,
connect: connect:
/* connect */ /* connect */
memset(dest, 0x00, sizeof(*dest)); if (rx != ipsec->rx_esw)
dest[0].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE; ipsec_rx_ft_connect(ipsec, rx, &attr);
dest[0].ft = rx->ft.pol;
mlx5_ttc_fwd_dest(ttc, family2tt(family), &dest[0]);
return 0; return 0;
err_pol_miss: err_pol_miss:
...@@ -368,8 +411,6 @@ static int rx_create(struct mlx5_core_dev *mdev, struct mlx5e_ipsec *ipsec, ...@@ -368,8 +411,6 @@ static int rx_create(struct mlx5_core_dev *mdev, struct mlx5e_ipsec *ipsec,
err_fs: err_fs:
mlx5_destroy_flow_table(rx->ft.sa); mlx5_destroy_flow_table(rx->ft.sa);
err_fs_ft: err_fs_ft:
if (rx->allow_tunnel_mode)
mlx5_eswitch_unblock_encap(mdev);
mlx5_del_flow_rules(rx->status.rule); mlx5_del_flow_rules(rx->status.rule);
mlx5_modify_header_dealloc(mdev, rx->status.modify_hdr); mlx5_modify_header_dealloc(mdev, rx->status.modify_hdr);
err_add: err_add:
...@@ -387,13 +428,26 @@ static int rx_get(struct mlx5_core_dev *mdev, struct mlx5e_ipsec *ipsec, ...@@ -387,13 +428,26 @@ static int rx_get(struct mlx5_core_dev *mdev, struct mlx5e_ipsec *ipsec,
if (rx->ft.refcnt) if (rx->ft.refcnt)
goto skip; goto skip;
if (mlx5_ipsec_device_caps(mdev) & MLX5_IPSEC_CAP_TUNNEL)
rx->allow_tunnel_mode = mlx5_eswitch_block_encap(mdev);
err = mlx5_eswitch_block_mode_trylock(mdev);
if (err)
goto err_out;
err = rx_create(mdev, ipsec, rx, family); err = rx_create(mdev, ipsec, rx, family);
mlx5_eswitch_block_mode_unlock(mdev, err);
if (err) if (err)
return err; goto err_out;
skip: skip:
rx->ft.refcnt++; rx->ft.refcnt++;
return 0; return 0;
err_out:
if (rx->allow_tunnel_mode)
mlx5_eswitch_unblock_encap(mdev);
return err;
} }
static void rx_put(struct mlx5e_ipsec *ipsec, struct mlx5e_ipsec_rx *rx, static void rx_put(struct mlx5e_ipsec *ipsec, struct mlx5e_ipsec_rx *rx,
...@@ -402,13 +456,19 @@ static void rx_put(struct mlx5e_ipsec *ipsec, struct mlx5e_ipsec_rx *rx, ...@@ -402,13 +456,19 @@ static void rx_put(struct mlx5e_ipsec *ipsec, struct mlx5e_ipsec_rx *rx,
if (--rx->ft.refcnt) if (--rx->ft.refcnt)
return; return;
mlx5_eswitch_unblock_mode_lock(ipsec->mdev);
rx_destroy(ipsec->mdev, ipsec, rx, family); rx_destroy(ipsec->mdev, ipsec, rx, family);
mlx5_eswitch_unblock_mode_unlock(ipsec->mdev);
if (rx->allow_tunnel_mode)
mlx5_eswitch_unblock_encap(ipsec->mdev);
} }
static struct mlx5e_ipsec_rx *rx_ft_get(struct mlx5_core_dev *mdev, static struct mlx5e_ipsec_rx *rx_ft_get(struct mlx5_core_dev *mdev,
struct mlx5e_ipsec *ipsec, u32 family) struct mlx5e_ipsec *ipsec, u32 family,
int type)
{ {
struct mlx5e_ipsec_rx *rx = ipsec_rx(ipsec, family); struct mlx5e_ipsec_rx *rx = ipsec_rx(ipsec, family, type);
int err; int err;
mutex_lock(&rx->ft.mutex); mutex_lock(&rx->ft.mutex);
...@@ -422,9 +482,9 @@ static struct mlx5e_ipsec_rx *rx_ft_get(struct mlx5_core_dev *mdev, ...@@ -422,9 +482,9 @@ static struct mlx5e_ipsec_rx *rx_ft_get(struct mlx5_core_dev *mdev,
static struct mlx5_flow_table *rx_ft_get_policy(struct mlx5_core_dev *mdev, static struct mlx5_flow_table *rx_ft_get_policy(struct mlx5_core_dev *mdev,
struct mlx5e_ipsec *ipsec, struct mlx5e_ipsec *ipsec,
u32 family, u32 prio) u32 family, u32 prio, int type)
{ {
struct mlx5e_ipsec_rx *rx = ipsec_rx(ipsec, family); struct mlx5e_ipsec_rx *rx = ipsec_rx(ipsec, family, type);
struct mlx5_flow_table *ft; struct mlx5_flow_table *ft;
int err; int err;
...@@ -449,18 +509,18 @@ static struct mlx5_flow_table *rx_ft_get_policy(struct mlx5_core_dev *mdev, ...@@ -449,18 +509,18 @@ static struct mlx5_flow_table *rx_ft_get_policy(struct mlx5_core_dev *mdev,
return ERR_PTR(err); return ERR_PTR(err);
} }
static void rx_ft_put(struct mlx5e_ipsec *ipsec, u32 family) static void rx_ft_put(struct mlx5e_ipsec *ipsec, u32 family, int type)
{ {
struct mlx5e_ipsec_rx *rx = ipsec_rx(ipsec, family); struct mlx5e_ipsec_rx *rx = ipsec_rx(ipsec, family, type);
mutex_lock(&rx->ft.mutex); mutex_lock(&rx->ft.mutex);
rx_put(ipsec, rx, family); rx_put(ipsec, rx, family);
mutex_unlock(&rx->ft.mutex); mutex_unlock(&rx->ft.mutex);
} }
static void rx_ft_put_policy(struct mlx5e_ipsec *ipsec, u32 family, u32 prio) static void rx_ft_put_policy(struct mlx5e_ipsec *ipsec, u32 family, u32 prio, int type)
{ {
struct mlx5e_ipsec_rx *rx = ipsec_rx(ipsec, family); struct mlx5e_ipsec_rx *rx = ipsec_rx(ipsec, family, type);
mutex_lock(&rx->ft.mutex); mutex_lock(&rx->ft.mutex);
if (rx->chains) if (rx->chains)
...@@ -504,7 +564,7 @@ static int ipsec_counter_rule_tx(struct mlx5_core_dev *mdev, struct mlx5e_ipsec_ ...@@ -504,7 +564,7 @@ static int ipsec_counter_rule_tx(struct mlx5_core_dev *mdev, struct mlx5e_ipsec_
} }
/* IPsec TX flow steering */ /* IPsec TX flow steering */
static void tx_destroy(struct mlx5_core_dev *mdev, struct mlx5e_ipsec_tx *tx, static void tx_destroy(struct mlx5e_ipsec *ipsec, struct mlx5e_ipsec_tx *tx,
struct mlx5_ipsec_fs *roce) struct mlx5_ipsec_fs *roce)
{ {
mlx5_ipsec_fs_roce_tx_destroy(roce); mlx5_ipsec_fs_roce_tx_destroy(roce);
...@@ -516,22 +576,43 @@ static void tx_destroy(struct mlx5_core_dev *mdev, struct mlx5e_ipsec_tx *tx, ...@@ -516,22 +576,43 @@ static void tx_destroy(struct mlx5_core_dev *mdev, struct mlx5e_ipsec_tx *tx,
mlx5_destroy_flow_table(tx->ft.pol); mlx5_destroy_flow_table(tx->ft.pol);
} }
if (tx == ipsec->tx_esw) {
mlx5_del_flow_rules(tx->sa.rule);
mlx5_destroy_flow_group(tx->sa.group);
}
mlx5_destroy_flow_table(tx->ft.sa); mlx5_destroy_flow_table(tx->ft.sa);
if (tx->allow_tunnel_mode)
mlx5_eswitch_unblock_encap(mdev);
mlx5_del_flow_rules(tx->status.rule); mlx5_del_flow_rules(tx->status.rule);
mlx5_destroy_flow_table(tx->ft.status); mlx5_destroy_flow_table(tx->ft.status);
} }
static int tx_create(struct mlx5_core_dev *mdev, struct mlx5e_ipsec_tx *tx, static void ipsec_tx_create_attr_set(struct mlx5e_ipsec *ipsec,
struct mlx5e_ipsec_tx *tx,
struct mlx5e_ipsec_tx_create_attr *attr)
{
if (tx == ipsec->tx_esw) {
mlx5_esw_ipsec_tx_create_attr_set(ipsec, attr);
return;
}
attr->prio = 0;
attr->pol_level = 0;
attr->sa_level = 1;
attr->cnt_level = 2;
attr->chains_ns = MLX5_FLOW_NAMESPACE_EGRESS_IPSEC;
}
static int tx_create(struct mlx5e_ipsec *ipsec, struct mlx5e_ipsec_tx *tx,
struct mlx5_ipsec_fs *roce) struct mlx5_ipsec_fs *roce)
{ {
struct mlx5_core_dev *mdev = ipsec->mdev;
struct mlx5e_ipsec_tx_create_attr attr;
struct mlx5_flow_destination dest = {}; struct mlx5_flow_destination dest = {};
struct mlx5_flow_table *ft; struct mlx5_flow_table *ft;
u32 flags = 0; u32 flags = 0;
int err; int err;
ft = ipsec_ft_create(tx->ns, 2, 0, 1, 0); ipsec_tx_create_attr_set(ipsec, tx, &attr);
ft = ipsec_ft_create(tx->ns, attr.cnt_level, attr.prio, 1, 0);
if (IS_ERR(ft)) if (IS_ERR(ft))
return PTR_ERR(ft); return PTR_ERR(ft);
tx->ft.status = ft; tx->ft.status = ft;
...@@ -540,20 +621,27 @@ static int tx_create(struct mlx5_core_dev *mdev, struct mlx5e_ipsec_tx *tx, ...@@ -540,20 +621,27 @@ static int tx_create(struct mlx5_core_dev *mdev, struct mlx5e_ipsec_tx *tx,
if (err) if (err)
goto err_status_rule; goto err_status_rule;
if (mlx5_ipsec_device_caps(mdev) & MLX5_IPSEC_CAP_TUNNEL)
tx->allow_tunnel_mode = mlx5_eswitch_block_encap(mdev);
if (tx->allow_tunnel_mode) if (tx->allow_tunnel_mode)
flags = MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT; flags = MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT;
ft = ipsec_ft_create(tx->ns, 1, 0, 4, flags); ft = ipsec_ft_create(tx->ns, attr.sa_level, attr.prio, 4, flags);
if (IS_ERR(ft)) { if (IS_ERR(ft)) {
err = PTR_ERR(ft); err = PTR_ERR(ft);
goto err_sa_ft; goto err_sa_ft;
} }
tx->ft.sa = ft; tx->ft.sa = ft;
if (tx == ipsec->tx_esw) {
dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
dest.vport.num = MLX5_VPORT_UPLINK;
err = ipsec_miss_create(mdev, tx->ft.sa, &tx->sa, &dest);
if (err)
goto err_sa_miss;
memset(&dest, 0, sizeof(dest));
}
if (mlx5_ipsec_device_caps(mdev) & MLX5_IPSEC_CAP_PRIO) { if (mlx5_ipsec_device_caps(mdev) & MLX5_IPSEC_CAP_PRIO) {
tx->chains = ipsec_chains_create( tx->chains = ipsec_chains_create(
mdev, tx->ft.sa, MLX5_FLOW_NAMESPACE_EGRESS_IPSEC, 0, 0, mdev, tx->ft.sa, attr.chains_ns, attr.prio, attr.pol_level,
&tx->ft.pol); &tx->ft.pol);
if (IS_ERR(tx->chains)) { if (IS_ERR(tx->chains)) {
err = PTR_ERR(tx->chains); err = PTR_ERR(tx->chains);
...@@ -563,7 +651,7 @@ static int tx_create(struct mlx5_core_dev *mdev, struct mlx5e_ipsec_tx *tx, ...@@ -563,7 +651,7 @@ static int tx_create(struct mlx5_core_dev *mdev, struct mlx5e_ipsec_tx *tx,
goto connect_roce; goto connect_roce;
} }
ft = ipsec_ft_create(tx->ns, 0, 0, 2, 0); ft = ipsec_ft_create(tx->ns, attr.pol_level, attr.prio, 2, 0);
if (IS_ERR(ft)) { if (IS_ERR(ft)) {
err = PTR_ERR(ft); err = PTR_ERR(ft);
goto err_pol_ft; goto err_pol_ft;
...@@ -592,16 +680,38 @@ static int tx_create(struct mlx5_core_dev *mdev, struct mlx5e_ipsec_tx *tx, ...@@ -592,16 +680,38 @@ static int tx_create(struct mlx5_core_dev *mdev, struct mlx5e_ipsec_tx *tx,
mlx5_destroy_flow_table(tx->ft.pol); mlx5_destroy_flow_table(tx->ft.pol);
} }
err_pol_ft: err_pol_ft:
if (tx == ipsec->tx_esw) {
mlx5_del_flow_rules(tx->sa.rule);
mlx5_destroy_flow_group(tx->sa.group);
}
err_sa_miss:
mlx5_destroy_flow_table(tx->ft.sa); mlx5_destroy_flow_table(tx->ft.sa);
err_sa_ft: err_sa_ft:
if (tx->allow_tunnel_mode)
mlx5_eswitch_unblock_encap(mdev);
mlx5_del_flow_rules(tx->status.rule); mlx5_del_flow_rules(tx->status.rule);
err_status_rule: err_status_rule:
mlx5_destroy_flow_table(tx->ft.status); mlx5_destroy_flow_table(tx->ft.status);
return err; return err;
} }
static void ipsec_esw_tx_ft_policy_set(struct mlx5_core_dev *mdev,
struct mlx5_flow_table *ft)
{
#ifdef CONFIG_MLX5_ESWITCH
struct mlx5_eswitch *esw = mdev->priv.eswitch;
struct mlx5e_rep_priv *uplink_rpriv;
struct mlx5e_priv *priv;
esw->offloads.ft_ipsec_tx_pol = ft;
uplink_rpriv = mlx5_eswitch_get_uplink_priv(esw, REP_ETH);
priv = netdev_priv(uplink_rpriv->netdev);
if (!priv->channels.num)
return;
mlx5e_rep_deactivate_channels(priv);
mlx5e_rep_activate_channels(priv);
#endif
}
static int tx_get(struct mlx5_core_dev *mdev, struct mlx5e_ipsec *ipsec, static int tx_get(struct mlx5_core_dev *mdev, struct mlx5e_ipsec *ipsec,
struct mlx5e_ipsec_tx *tx) struct mlx5e_ipsec_tx *tx)
{ {
...@@ -610,13 +720,32 @@ static int tx_get(struct mlx5_core_dev *mdev, struct mlx5e_ipsec *ipsec, ...@@ -610,13 +720,32 @@ static int tx_get(struct mlx5_core_dev *mdev, struct mlx5e_ipsec *ipsec,
if (tx->ft.refcnt) if (tx->ft.refcnt)
goto skip; goto skip;
err = tx_create(mdev, tx, ipsec->roce); if (mlx5_ipsec_device_caps(mdev) & MLX5_IPSEC_CAP_TUNNEL)
tx->allow_tunnel_mode = mlx5_eswitch_block_encap(mdev);
err = mlx5_eswitch_block_mode_trylock(mdev);
if (err) if (err)
return err; goto err_out;
err = tx_create(ipsec, tx, ipsec->roce);
if (err) {
mlx5_eswitch_block_mode_unlock(mdev, err);
goto err_out;
}
if (tx == ipsec->tx_esw)
ipsec_esw_tx_ft_policy_set(mdev, tx->ft.pol);
mlx5_eswitch_block_mode_unlock(mdev, err);
skip: skip:
tx->ft.refcnt++; tx->ft.refcnt++;
return 0; return 0;
err_out:
if (tx->allow_tunnel_mode)
mlx5_eswitch_unblock_encap(mdev);
return err;
} }
static void tx_put(struct mlx5e_ipsec *ipsec, struct mlx5e_ipsec_tx *tx) static void tx_put(struct mlx5e_ipsec *ipsec, struct mlx5e_ipsec_tx *tx)
...@@ -624,14 +753,26 @@ static void tx_put(struct mlx5e_ipsec *ipsec, struct mlx5e_ipsec_tx *tx) ...@@ -624,14 +753,26 @@ static void tx_put(struct mlx5e_ipsec *ipsec, struct mlx5e_ipsec_tx *tx)
if (--tx->ft.refcnt) if (--tx->ft.refcnt)
return; return;
tx_destroy(ipsec->mdev, tx, ipsec->roce); mlx5_eswitch_unblock_mode_lock(ipsec->mdev);
if (tx == ipsec->tx_esw) {
mlx5_esw_ipsec_restore_dest_uplink(ipsec->mdev);
ipsec_esw_tx_ft_policy_set(ipsec->mdev, NULL);
}
tx_destroy(ipsec, tx, ipsec->roce);
mlx5_eswitch_unblock_mode_unlock(ipsec->mdev);
if (tx->allow_tunnel_mode)
mlx5_eswitch_unblock_encap(ipsec->mdev);
} }
static struct mlx5_flow_table *tx_ft_get_policy(struct mlx5_core_dev *mdev, static struct mlx5_flow_table *tx_ft_get_policy(struct mlx5_core_dev *mdev,
struct mlx5e_ipsec *ipsec, struct mlx5e_ipsec *ipsec,
u32 prio) u32 prio, int type)
{ {
struct mlx5e_ipsec_tx *tx = ipsec->tx; struct mlx5e_ipsec_tx *tx = ipsec_tx(ipsec, type);
struct mlx5_flow_table *ft; struct mlx5_flow_table *ft;
int err; int err;
...@@ -657,9 +798,9 @@ static struct mlx5_flow_table *tx_ft_get_policy(struct mlx5_core_dev *mdev, ...@@ -657,9 +798,9 @@ static struct mlx5_flow_table *tx_ft_get_policy(struct mlx5_core_dev *mdev,
} }
static struct mlx5e_ipsec_tx *tx_ft_get(struct mlx5_core_dev *mdev, static struct mlx5e_ipsec_tx *tx_ft_get(struct mlx5_core_dev *mdev,
struct mlx5e_ipsec *ipsec) struct mlx5e_ipsec *ipsec, int type)
{ {
struct mlx5e_ipsec_tx *tx = ipsec->tx; struct mlx5e_ipsec_tx *tx = ipsec_tx(ipsec, type);
int err; int err;
mutex_lock(&tx->ft.mutex); mutex_lock(&tx->ft.mutex);
...@@ -671,18 +812,18 @@ static struct mlx5e_ipsec_tx *tx_ft_get(struct mlx5_core_dev *mdev, ...@@ -671,18 +812,18 @@ static struct mlx5e_ipsec_tx *tx_ft_get(struct mlx5_core_dev *mdev,
return tx; return tx;
} }
static void tx_ft_put(struct mlx5e_ipsec *ipsec) static void tx_ft_put(struct mlx5e_ipsec *ipsec, int type)
{ {
struct mlx5e_ipsec_tx *tx = ipsec->tx; struct mlx5e_ipsec_tx *tx = ipsec_tx(ipsec, type);
mutex_lock(&tx->ft.mutex); mutex_lock(&tx->ft.mutex);
tx_put(ipsec, tx); tx_put(ipsec, tx);
mutex_unlock(&tx->ft.mutex); mutex_unlock(&tx->ft.mutex);
} }
static void tx_ft_put_policy(struct mlx5e_ipsec *ipsec, u32 prio) static void tx_ft_put_policy(struct mlx5e_ipsec *ipsec, u32 prio, int type)
{ {
struct mlx5e_ipsec_tx *tx = ipsec->tx; struct mlx5e_ipsec_tx *tx = ipsec_tx(ipsec, type);
mutex_lock(&tx->ft.mutex); mutex_lock(&tx->ft.mutex);
if (tx->chains) if (tx->chains)
...@@ -782,15 +923,15 @@ static void setup_fte_reg_a(struct mlx5_flow_spec *spec) ...@@ -782,15 +923,15 @@ static void setup_fte_reg_a(struct mlx5_flow_spec *spec)
misc_parameters_2.metadata_reg_a, MLX5_ETH_WQE_FT_META_IPSEC); misc_parameters_2.metadata_reg_a, MLX5_ETH_WQE_FT_META_IPSEC);
} }
static void setup_fte_reg_c0(struct mlx5_flow_spec *spec, u32 reqid) static void setup_fte_reg_c4(struct mlx5_flow_spec *spec, u32 reqid)
{ {
/* Pass policy check before choosing this SA */ /* Pass policy check before choosing this SA */
spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_2; spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_2;
MLX5_SET(fte_match_param, spec->match_criteria, MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
misc_parameters_2.metadata_reg_c_0, reqid); misc_parameters_2.metadata_reg_c_4);
MLX5_SET(fte_match_param, spec->match_value, MLX5_SET(fte_match_param, spec->match_value,
misc_parameters_2.metadata_reg_c_0, reqid); misc_parameters_2.metadata_reg_c_4, reqid);
} }
static void setup_fte_upper_proto_match(struct mlx5_flow_spec *spec, struct upspec *upspec) static void setup_fte_upper_proto_match(struct mlx5_flow_spec *spec, struct upspec *upspec)
...@@ -814,11 +955,24 @@ static void setup_fte_upper_proto_match(struct mlx5_flow_spec *spec, struct upsp ...@@ -814,11 +955,24 @@ static void setup_fte_upper_proto_match(struct mlx5_flow_spec *spec, struct upsp
} }
} }
static int setup_modify_header(struct mlx5_core_dev *mdev, u32 val, u8 dir, static enum mlx5_flow_namespace_type ipsec_fs_get_ns(struct mlx5e_ipsec *ipsec,
int type, u8 dir)
{
if (ipsec->is_uplink_rep && type == XFRM_DEV_OFFLOAD_PACKET)
return MLX5_FLOW_NAMESPACE_FDB;
if (dir == XFRM_DEV_OFFLOAD_IN)
return MLX5_FLOW_NAMESPACE_KERNEL;
return MLX5_FLOW_NAMESPACE_EGRESS;
}
static int setup_modify_header(struct mlx5e_ipsec *ipsec, int type, u32 val, u8 dir,
struct mlx5_flow_act *flow_act) struct mlx5_flow_act *flow_act)
{ {
enum mlx5_flow_namespace_type ns_type = ipsec_fs_get_ns(ipsec, type, dir);
u8 action[MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto)] = {}; u8 action[MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto)] = {};
enum mlx5_flow_namespace_type ns_type; struct mlx5_core_dev *mdev = ipsec->mdev;
struct mlx5_modify_hdr *modify_hdr; struct mlx5_modify_hdr *modify_hdr;
MLX5_SET(set_action_in, action, action_type, MLX5_ACTION_TYPE_SET); MLX5_SET(set_action_in, action, action_type, MLX5_ACTION_TYPE_SET);
...@@ -826,12 +980,10 @@ static int setup_modify_header(struct mlx5_core_dev *mdev, u32 val, u8 dir, ...@@ -826,12 +980,10 @@ static int setup_modify_header(struct mlx5_core_dev *mdev, u32 val, u8 dir,
case XFRM_DEV_OFFLOAD_IN: case XFRM_DEV_OFFLOAD_IN:
MLX5_SET(set_action_in, action, field, MLX5_SET(set_action_in, action, field,
MLX5_ACTION_IN_FIELD_METADATA_REG_B); MLX5_ACTION_IN_FIELD_METADATA_REG_B);
ns_type = MLX5_FLOW_NAMESPACE_KERNEL;
break; break;
case XFRM_DEV_OFFLOAD_OUT: case XFRM_DEV_OFFLOAD_OUT:
MLX5_SET(set_action_in, action, field, MLX5_SET(set_action_in, action, field,
MLX5_ACTION_IN_FIELD_METADATA_REG_C_0); MLX5_ACTION_IN_FIELD_METADATA_REG_C_4);
ns_type = MLX5_FLOW_NAMESPACE_EGRESS;
break; break;
default: default:
return -EINVAL; return -EINVAL;
...@@ -1024,26 +1176,17 @@ setup_pkt_transport_reformat(struct mlx5_accel_esp_xfrm_attrs *attrs, ...@@ -1024,26 +1176,17 @@ setup_pkt_transport_reformat(struct mlx5_accel_esp_xfrm_attrs *attrs,
return 0; return 0;
} }
static int setup_pkt_reformat(struct mlx5_core_dev *mdev, static int setup_pkt_reformat(struct mlx5e_ipsec *ipsec,
struct mlx5_accel_esp_xfrm_attrs *attrs, struct mlx5_accel_esp_xfrm_attrs *attrs,
struct mlx5_flow_act *flow_act) struct mlx5_flow_act *flow_act)
{ {
enum mlx5_flow_namespace_type ns_type = ipsec_fs_get_ns(ipsec, attrs->type,
attrs->dir);
struct mlx5_pkt_reformat_params reformat_params = {}; struct mlx5_pkt_reformat_params reformat_params = {};
struct mlx5_core_dev *mdev = ipsec->mdev;
struct mlx5_pkt_reformat *pkt_reformat; struct mlx5_pkt_reformat *pkt_reformat;
enum mlx5_flow_namespace_type ns_type;
int ret; int ret;
switch (attrs->dir) {
case XFRM_DEV_OFFLOAD_IN:
ns_type = MLX5_FLOW_NAMESPACE_KERNEL;
break;
case XFRM_DEV_OFFLOAD_OUT:
ns_type = MLX5_FLOW_NAMESPACE_EGRESS;
break;
default:
return -EINVAL;
}
switch (attrs->mode) { switch (attrs->mode) {
case XFRM_MODE_TRANSPORT: case XFRM_MODE_TRANSPORT:
ret = setup_pkt_transport_reformat(attrs, &reformat_params); ret = setup_pkt_transport_reformat(attrs, &reformat_params);
...@@ -1080,9 +1223,9 @@ static int rx_add_rule(struct mlx5e_ipsec_sa_entry *sa_entry) ...@@ -1080,9 +1223,9 @@ static int rx_add_rule(struct mlx5e_ipsec_sa_entry *sa_entry)
struct mlx5_flow_spec *spec; struct mlx5_flow_spec *spec;
struct mlx5e_ipsec_rx *rx; struct mlx5e_ipsec_rx *rx;
struct mlx5_fc *counter; struct mlx5_fc *counter;
int err; int err = 0;
rx = rx_ft_get(mdev, ipsec, attrs->family); rx = rx_ft_get(mdev, ipsec, attrs->family, attrs->type);
if (IS_ERR(rx)) if (IS_ERR(rx))
return PTR_ERR(rx); return PTR_ERR(rx);
...@@ -1101,14 +1244,19 @@ static int rx_add_rule(struct mlx5e_ipsec_sa_entry *sa_entry) ...@@ -1101,14 +1244,19 @@ static int rx_add_rule(struct mlx5e_ipsec_sa_entry *sa_entry)
setup_fte_esp(spec); setup_fte_esp(spec);
setup_fte_no_frags(spec); setup_fte_no_frags(spec);
err = setup_modify_header(mdev, sa_entry->ipsec_obj_id | BIT(31), if (rx != ipsec->rx_esw)
XFRM_DEV_OFFLOAD_IN, &flow_act); err = setup_modify_header(ipsec, attrs->type,
sa_entry->ipsec_obj_id | BIT(31),
XFRM_DEV_OFFLOAD_IN, &flow_act);
else
err = mlx5_esw_ipsec_rx_setup_modify_header(sa_entry, &flow_act);
if (err) if (err)
goto err_mod_header; goto err_mod_header;
switch (attrs->type) { switch (attrs->type) {
case XFRM_DEV_OFFLOAD_PACKET: case XFRM_DEV_OFFLOAD_PACKET:
err = setup_pkt_reformat(mdev, attrs, &flow_act); err = setup_pkt_reformat(ipsec, attrs, &flow_act);
if (err) if (err)
goto err_pkt_reformat; goto err_pkt_reformat;
break; break;
...@@ -1158,7 +1306,7 @@ static int rx_add_rule(struct mlx5e_ipsec_sa_entry *sa_entry) ...@@ -1158,7 +1306,7 @@ static int rx_add_rule(struct mlx5e_ipsec_sa_entry *sa_entry)
err_mod_header: err_mod_header:
kvfree(spec); kvfree(spec);
err_alloc: err_alloc:
rx_ft_put(ipsec, attrs->family); rx_ft_put(ipsec, attrs->family, attrs->type);
return err; return err;
} }
...@@ -1175,7 +1323,7 @@ static int tx_add_rule(struct mlx5e_ipsec_sa_entry *sa_entry) ...@@ -1175,7 +1323,7 @@ static int tx_add_rule(struct mlx5e_ipsec_sa_entry *sa_entry)
struct mlx5_fc *counter; struct mlx5_fc *counter;
int err; int err;
tx = tx_ft_get(mdev, ipsec); tx = tx_ft_get(mdev, ipsec, attrs->type);
if (IS_ERR(tx)) if (IS_ERR(tx))
return PTR_ERR(tx); return PTR_ERR(tx);
...@@ -1201,8 +1349,8 @@ static int tx_add_rule(struct mlx5e_ipsec_sa_entry *sa_entry) ...@@ -1201,8 +1349,8 @@ static int tx_add_rule(struct mlx5e_ipsec_sa_entry *sa_entry)
break; break;
case XFRM_DEV_OFFLOAD_PACKET: case XFRM_DEV_OFFLOAD_PACKET:
if (attrs->reqid) if (attrs->reqid)
setup_fte_reg_c0(spec, attrs->reqid); setup_fte_reg_c4(spec, attrs->reqid);
err = setup_pkt_reformat(mdev, attrs, &flow_act); err = setup_pkt_reformat(ipsec, attrs, &flow_act);
if (err) if (err)
goto err_pkt_reformat; goto err_pkt_reformat;
break; break;
...@@ -1251,7 +1399,7 @@ static int tx_add_rule(struct mlx5e_ipsec_sa_entry *sa_entry) ...@@ -1251,7 +1399,7 @@ static int tx_add_rule(struct mlx5e_ipsec_sa_entry *sa_entry)
err_pkt_reformat: err_pkt_reformat:
kvfree(spec); kvfree(spec);
err_alloc: err_alloc:
tx_ft_put(ipsec); tx_ft_put(ipsec, attrs->type);
return err; return err;
} }
...@@ -1259,15 +1407,16 @@ static int tx_add_policy(struct mlx5e_ipsec_pol_entry *pol_entry) ...@@ -1259,15 +1407,16 @@ static int tx_add_policy(struct mlx5e_ipsec_pol_entry *pol_entry)
{ {
struct mlx5_accel_pol_xfrm_attrs *attrs = &pol_entry->attrs; struct mlx5_accel_pol_xfrm_attrs *attrs = &pol_entry->attrs;
struct mlx5_core_dev *mdev = mlx5e_ipsec_pol2dev(pol_entry); struct mlx5_core_dev *mdev = mlx5e_ipsec_pol2dev(pol_entry);
struct mlx5e_ipsec_tx *tx = pol_entry->ipsec->tx; struct mlx5e_ipsec *ipsec = pol_entry->ipsec;
struct mlx5_flow_destination dest[2] = {}; struct mlx5_flow_destination dest[2] = {};
struct mlx5_flow_act flow_act = {}; struct mlx5_flow_act flow_act = {};
struct mlx5_flow_handle *rule; struct mlx5_flow_handle *rule;
struct mlx5_flow_spec *spec; struct mlx5_flow_spec *spec;
struct mlx5_flow_table *ft; struct mlx5_flow_table *ft;
struct mlx5e_ipsec_tx *tx;
int err, dstn = 0; int err, dstn = 0;
ft = tx_ft_get_policy(mdev, pol_entry->ipsec, attrs->prio); ft = tx_ft_get_policy(mdev, ipsec, attrs->prio, attrs->type);
if (IS_ERR(ft)) if (IS_ERR(ft))
return PTR_ERR(ft); return PTR_ERR(ft);
...@@ -1277,6 +1426,7 @@ static int tx_add_policy(struct mlx5e_ipsec_pol_entry *pol_entry) ...@@ -1277,6 +1426,7 @@ static int tx_add_policy(struct mlx5e_ipsec_pol_entry *pol_entry)
goto err_alloc; goto err_alloc;
} }
tx = ipsec_tx(ipsec, attrs->type);
if (attrs->family == AF_INET) if (attrs->family == AF_INET)
setup_fte_addr4(spec, &attrs->saddr.a4, &attrs->daddr.a4); setup_fte_addr4(spec, &attrs->saddr.a4, &attrs->daddr.a4);
else else
...@@ -1291,7 +1441,7 @@ static int tx_add_policy(struct mlx5e_ipsec_pol_entry *pol_entry) ...@@ -1291,7 +1441,7 @@ static int tx_add_policy(struct mlx5e_ipsec_pol_entry *pol_entry)
if (!attrs->reqid) if (!attrs->reqid)
break; break;
err = setup_modify_header(mdev, attrs->reqid, err = setup_modify_header(ipsec, attrs->type, attrs->reqid,
XFRM_DEV_OFFLOAD_OUT, &flow_act); XFRM_DEV_OFFLOAD_OUT, &flow_act);
if (err) if (err)
goto err_mod_header; goto err_mod_header;
...@@ -1310,6 +1460,8 @@ static int tx_add_policy(struct mlx5e_ipsec_pol_entry *pol_entry) ...@@ -1310,6 +1460,8 @@ static int tx_add_policy(struct mlx5e_ipsec_pol_entry *pol_entry)
} }
flow_act.flags |= FLOW_ACT_NO_APPEND; flow_act.flags |= FLOW_ACT_NO_APPEND;
if (tx == ipsec->tx_esw && tx->chains)
flow_act.flags |= FLOW_ACT_IGNORE_FLOW_LEVEL;
dest[dstn].ft = tx->ft.sa; dest[dstn].ft = tx->ft.sa;
dest[dstn].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE; dest[dstn].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
dstn++; dstn++;
...@@ -1331,7 +1483,7 @@ static int tx_add_policy(struct mlx5e_ipsec_pol_entry *pol_entry) ...@@ -1331,7 +1483,7 @@ static int tx_add_policy(struct mlx5e_ipsec_pol_entry *pol_entry)
err_mod_header: err_mod_header:
kvfree(spec); kvfree(spec);
err_alloc: err_alloc:
tx_ft_put_policy(pol_entry->ipsec, attrs->prio); tx_ft_put_policy(ipsec, attrs->prio, attrs->type);
return err; return err;
} }
...@@ -1339,6 +1491,7 @@ static int rx_add_policy(struct mlx5e_ipsec_pol_entry *pol_entry) ...@@ -1339,6 +1491,7 @@ static int rx_add_policy(struct mlx5e_ipsec_pol_entry *pol_entry)
{ {
struct mlx5_accel_pol_xfrm_attrs *attrs = &pol_entry->attrs; struct mlx5_accel_pol_xfrm_attrs *attrs = &pol_entry->attrs;
struct mlx5_core_dev *mdev = mlx5e_ipsec_pol2dev(pol_entry); struct mlx5_core_dev *mdev = mlx5e_ipsec_pol2dev(pol_entry);
struct mlx5e_ipsec *ipsec = pol_entry->ipsec;
struct mlx5_flow_destination dest[2]; struct mlx5_flow_destination dest[2];
struct mlx5_flow_act flow_act = {}; struct mlx5_flow_act flow_act = {};
struct mlx5_flow_handle *rule; struct mlx5_flow_handle *rule;
...@@ -1347,11 +1500,12 @@ static int rx_add_policy(struct mlx5e_ipsec_pol_entry *pol_entry) ...@@ -1347,11 +1500,12 @@ static int rx_add_policy(struct mlx5e_ipsec_pol_entry *pol_entry)
struct mlx5e_ipsec_rx *rx; struct mlx5e_ipsec_rx *rx;
int err, dstn = 0; int err, dstn = 0;
ft = rx_ft_get_policy(mdev, pol_entry->ipsec, attrs->family, attrs->prio); ft = rx_ft_get_policy(mdev, pol_entry->ipsec, attrs->family, attrs->prio,
attrs->type);
if (IS_ERR(ft)) if (IS_ERR(ft))
return PTR_ERR(ft); return PTR_ERR(ft);
rx = ipsec_rx(pol_entry->ipsec, attrs->family); rx = ipsec_rx(pol_entry->ipsec, attrs->family, attrs->type);
spec = kvzalloc(sizeof(*spec), GFP_KERNEL); spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
if (!spec) { if (!spec) {
...@@ -1383,6 +1537,8 @@ static int rx_add_policy(struct mlx5e_ipsec_pol_entry *pol_entry) ...@@ -1383,6 +1537,8 @@ static int rx_add_policy(struct mlx5e_ipsec_pol_entry *pol_entry)
} }
flow_act.flags |= FLOW_ACT_NO_APPEND; flow_act.flags |= FLOW_ACT_NO_APPEND;
if (rx == ipsec->rx_esw && rx->chains)
flow_act.flags |= FLOW_ACT_IGNORE_FLOW_LEVEL;
dest[dstn].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE; dest[dstn].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
dest[dstn].ft = rx->ft.sa; dest[dstn].ft = rx->ft.sa;
dstn++; dstn++;
...@@ -1400,88 +1556,110 @@ static int rx_add_policy(struct mlx5e_ipsec_pol_entry *pol_entry) ...@@ -1400,88 +1556,110 @@ static int rx_add_policy(struct mlx5e_ipsec_pol_entry *pol_entry)
err_action: err_action:
kvfree(spec); kvfree(spec);
err_alloc: err_alloc:
rx_ft_put_policy(pol_entry->ipsec, attrs->family, attrs->prio); rx_ft_put_policy(pol_entry->ipsec, attrs->family, attrs->prio, attrs->type);
return err; return err;
} }
static void ipsec_fs_destroy_single_counter(struct mlx5_core_dev *mdev,
struct mlx5e_ipsec_fc *fc)
{
mlx5_fc_destroy(mdev, fc->drop);
mlx5_fc_destroy(mdev, fc->cnt);
kfree(fc);
}
static void ipsec_fs_destroy_counters(struct mlx5e_ipsec *ipsec) static void ipsec_fs_destroy_counters(struct mlx5e_ipsec *ipsec)
{ {
struct mlx5e_ipsec_rx *rx_ipv4 = ipsec->rx_ipv4;
struct mlx5_core_dev *mdev = ipsec->mdev; struct mlx5_core_dev *mdev = ipsec->mdev;
struct mlx5e_ipsec_tx *tx = ipsec->tx;
mlx5_fc_destroy(mdev, tx->fc->drop); ipsec_fs_destroy_single_counter(mdev, ipsec->tx->fc);
mlx5_fc_destroy(mdev, tx->fc->cnt); ipsec_fs_destroy_single_counter(mdev, ipsec->rx_ipv4->fc);
kfree(tx->fc); if (ipsec->is_uplink_rep) {
mlx5_fc_destroy(mdev, rx_ipv4->fc->drop); ipsec_fs_destroy_single_counter(mdev, ipsec->tx_esw->fc);
mlx5_fc_destroy(mdev, rx_ipv4->fc->cnt); ipsec_fs_destroy_single_counter(mdev, ipsec->rx_esw->fc);
kfree(rx_ipv4->fc); }
} }
static int ipsec_fs_init_counters(struct mlx5e_ipsec *ipsec) static struct mlx5e_ipsec_fc *ipsec_fs_init_single_counter(struct mlx5_core_dev *mdev)
{ {
struct mlx5e_ipsec_rx *rx_ipv4 = ipsec->rx_ipv4;
struct mlx5e_ipsec_rx *rx_ipv6 = ipsec->rx_ipv6;
struct mlx5_core_dev *mdev = ipsec->mdev;
struct mlx5e_ipsec_tx *tx = ipsec->tx;
struct mlx5e_ipsec_fc *fc; struct mlx5e_ipsec_fc *fc;
struct mlx5_fc *counter; struct mlx5_fc *counter;
int err; int err;
fc = kzalloc(sizeof(*rx_ipv4->fc), GFP_KERNEL); fc = kzalloc(sizeof(*fc), GFP_KERNEL);
if (!fc) if (!fc)
return -ENOMEM; return ERR_PTR(-ENOMEM);
/* Both IPv4 and IPv6 point to same flow counters struct. */
rx_ipv4->fc = fc;
rx_ipv6->fc = fc;
counter = mlx5_fc_create(mdev, false); counter = mlx5_fc_create(mdev, false);
if (IS_ERR(counter)) { if (IS_ERR(counter)) {
err = PTR_ERR(counter); err = PTR_ERR(counter);
goto err_rx_cnt; goto err_cnt;
} }
fc->cnt = counter; fc->cnt = counter;
counter = mlx5_fc_create(mdev, false); counter = mlx5_fc_create(mdev, false);
if (IS_ERR(counter)) { if (IS_ERR(counter)) {
err = PTR_ERR(counter); err = PTR_ERR(counter);
goto err_rx_drop; goto err_drop;
} }
fc->drop = counter; fc->drop = counter;
fc = kzalloc(sizeof(*tx->fc), GFP_KERNEL);
if (!fc) { return fc;
err = -ENOMEM;
goto err_tx_fc; err_drop:
mlx5_fc_destroy(mdev, fc->cnt);
err_cnt:
kfree(fc);
return ERR_PTR(err);
}
static int ipsec_fs_init_counters(struct mlx5e_ipsec *ipsec)
{
struct mlx5_core_dev *mdev = ipsec->mdev;
struct mlx5e_ipsec_fc *fc;
int err;
fc = ipsec_fs_init_single_counter(mdev);
if (IS_ERR(fc)) {
err = PTR_ERR(fc);
goto err_rx_cnt;
} }
ipsec->rx_ipv4->fc = fc;
tx->fc = fc; fc = ipsec_fs_init_single_counter(mdev);
counter = mlx5_fc_create(mdev, false); if (IS_ERR(fc)) {
if (IS_ERR(counter)) { err = PTR_ERR(fc);
err = PTR_ERR(counter);
goto err_tx_cnt; goto err_tx_cnt;
} }
ipsec->tx->fc = fc;
fc->cnt = counter; if (ipsec->is_uplink_rep) {
counter = mlx5_fc_create(mdev, false); fc = ipsec_fs_init_single_counter(mdev);
if (IS_ERR(counter)) { if (IS_ERR(fc)) {
err = PTR_ERR(counter); err = PTR_ERR(fc);
goto err_tx_drop; goto err_rx_esw_cnt;
}
ipsec->rx_esw->fc = fc;
fc = ipsec_fs_init_single_counter(mdev);
if (IS_ERR(fc)) {
err = PTR_ERR(fc);
goto err_tx_esw_cnt;
}
ipsec->tx_esw->fc = fc;
} }
fc->drop = counter; /* Both IPv4 and IPv6 point to same flow counters struct. */
ipsec->rx_ipv6->fc = ipsec->rx_ipv4->fc;
return 0; return 0;
err_tx_drop: err_tx_esw_cnt:
mlx5_fc_destroy(mdev, tx->fc->cnt); ipsec_fs_destroy_single_counter(mdev, ipsec->rx_esw->fc);
err_rx_esw_cnt:
ipsec_fs_destroy_single_counter(mdev, ipsec->tx->fc);
err_tx_cnt: err_tx_cnt:
kfree(tx->fc); ipsec_fs_destroy_single_counter(mdev, ipsec->rx_ipv4->fc);
err_tx_fc:
mlx5_fc_destroy(mdev, rx_ipv4->fc->drop);
err_rx_drop:
mlx5_fc_destroy(mdev, rx_ipv4->fc->cnt);
err_rx_cnt: err_rx_cnt:
kfree(rx_ipv4->fc);
return err; return err;
} }
...@@ -1491,6 +1669,7 @@ void mlx5e_accel_ipsec_fs_read_stats(struct mlx5e_priv *priv, void *ipsec_stats) ...@@ -1491,6 +1669,7 @@ void mlx5e_accel_ipsec_fs_read_stats(struct mlx5e_priv *priv, void *ipsec_stats)
struct mlx5e_ipsec *ipsec = priv->ipsec; struct mlx5e_ipsec *ipsec = priv->ipsec;
struct mlx5e_ipsec_hw_stats *stats; struct mlx5e_ipsec_hw_stats *stats;
struct mlx5e_ipsec_fc *fc; struct mlx5e_ipsec_fc *fc;
u64 packets, bytes;
stats = (struct mlx5e_ipsec_hw_stats *)ipsec_stats; stats = (struct mlx5e_ipsec_hw_stats *)ipsec_stats;
...@@ -1512,14 +1691,94 @@ void mlx5e_accel_ipsec_fs_read_stats(struct mlx5e_priv *priv, void *ipsec_stats) ...@@ -1512,14 +1691,94 @@ void mlx5e_accel_ipsec_fs_read_stats(struct mlx5e_priv *priv, void *ipsec_stats)
mlx5_fc_query(mdev, fc->cnt, &stats->ipsec_tx_pkts, &stats->ipsec_tx_bytes); mlx5_fc_query(mdev, fc->cnt, &stats->ipsec_tx_pkts, &stats->ipsec_tx_bytes);
mlx5_fc_query(mdev, fc->drop, &stats->ipsec_tx_drop_pkts, mlx5_fc_query(mdev, fc->drop, &stats->ipsec_tx_drop_pkts,
&stats->ipsec_tx_drop_bytes); &stats->ipsec_tx_drop_bytes);
if (ipsec->is_uplink_rep) {
fc = ipsec->rx_esw->fc;
if (!mlx5_fc_query(mdev, fc->cnt, &packets, &bytes)) {
stats->ipsec_rx_pkts += packets;
stats->ipsec_rx_bytes += bytes;
}
if (!mlx5_fc_query(mdev, fc->drop, &packets, &bytes)) {
stats->ipsec_rx_drop_pkts += packets;
stats->ipsec_rx_drop_bytes += bytes;
}
fc = ipsec->tx_esw->fc;
if (!mlx5_fc_query(mdev, fc->cnt, &packets, &bytes)) {
stats->ipsec_tx_pkts += packets;
stats->ipsec_tx_bytes += bytes;
}
if (!mlx5_fc_query(mdev, fc->drop, &packets, &bytes)) {
stats->ipsec_tx_drop_pkts += packets;
stats->ipsec_tx_drop_bytes += bytes;
}
}
}
#ifdef CONFIG_MLX5_ESWITCH
static int mlx5e_ipsec_block_tc_offload(struct mlx5_core_dev *mdev)
{
struct mlx5_eswitch *esw = mdev->priv.eswitch;
int err = 0;
if (esw)
down_write(&esw->mode_lock);
if (mdev->num_block_ipsec) {
err = -EBUSY;
goto unlock;
}
mdev->num_block_tc++;
unlock:
if (esw)
up_write(&esw->mode_lock);
return err;
}
#else
static int mlx5e_ipsec_block_tc_offload(struct mlx5_core_dev *mdev)
{
if (mdev->num_block_ipsec)
return -EBUSY;
mdev->num_block_tc++;
return 0;
}
#endif
static void mlx5e_ipsec_unblock_tc_offload(struct mlx5_core_dev *mdev)
{
mdev->num_block_tc++;
} }
int mlx5e_accel_ipsec_fs_add_rule(struct mlx5e_ipsec_sa_entry *sa_entry) int mlx5e_accel_ipsec_fs_add_rule(struct mlx5e_ipsec_sa_entry *sa_entry)
{ {
int err;
if (sa_entry->attrs.type == XFRM_DEV_OFFLOAD_PACKET) {
err = mlx5e_ipsec_block_tc_offload(sa_entry->ipsec->mdev);
if (err)
return err;
}
if (sa_entry->attrs.dir == XFRM_DEV_OFFLOAD_OUT) if (sa_entry->attrs.dir == XFRM_DEV_OFFLOAD_OUT)
return tx_add_rule(sa_entry); err = tx_add_rule(sa_entry);
else
err = rx_add_rule(sa_entry);
if (err)
goto err_out;
return rx_add_rule(sa_entry); return 0;
err_out:
if (sa_entry->attrs.type == XFRM_DEV_OFFLOAD_PACKET)
mlx5e_ipsec_unblock_tc_offload(sa_entry->ipsec->mdev);
return err;
} }
void mlx5e_accel_ipsec_fs_del_rule(struct mlx5e_ipsec_sa_entry *sa_entry) void mlx5e_accel_ipsec_fs_del_rule(struct mlx5e_ipsec_sa_entry *sa_entry)
...@@ -1532,21 +1791,40 @@ void mlx5e_accel_ipsec_fs_del_rule(struct mlx5e_ipsec_sa_entry *sa_entry) ...@@ -1532,21 +1791,40 @@ void mlx5e_accel_ipsec_fs_del_rule(struct mlx5e_ipsec_sa_entry *sa_entry)
if (ipsec_rule->pkt_reformat) if (ipsec_rule->pkt_reformat)
mlx5_packet_reformat_dealloc(mdev, ipsec_rule->pkt_reformat); mlx5_packet_reformat_dealloc(mdev, ipsec_rule->pkt_reformat);
if (sa_entry->attrs.type == XFRM_DEV_OFFLOAD_PACKET)
mlx5e_ipsec_unblock_tc_offload(mdev);
if (sa_entry->attrs.dir == XFRM_DEV_OFFLOAD_OUT) { if (sa_entry->attrs.dir == XFRM_DEV_OFFLOAD_OUT) {
tx_ft_put(sa_entry->ipsec); tx_ft_put(sa_entry->ipsec, sa_entry->attrs.type);
return; return;
} }
mlx5_modify_header_dealloc(mdev, ipsec_rule->modify_hdr); mlx5_modify_header_dealloc(mdev, ipsec_rule->modify_hdr);
rx_ft_put(sa_entry->ipsec, sa_entry->attrs.family); mlx5_esw_ipsec_rx_id_mapping_remove(sa_entry);
rx_ft_put(sa_entry->ipsec, sa_entry->attrs.family, sa_entry->attrs.type);
} }
int mlx5e_accel_ipsec_fs_add_pol(struct mlx5e_ipsec_pol_entry *pol_entry) int mlx5e_accel_ipsec_fs_add_pol(struct mlx5e_ipsec_pol_entry *pol_entry)
{ {
int err;
err = mlx5e_ipsec_block_tc_offload(pol_entry->ipsec->mdev);
if (err)
return err;
if (pol_entry->attrs.dir == XFRM_DEV_OFFLOAD_OUT) if (pol_entry->attrs.dir == XFRM_DEV_OFFLOAD_OUT)
return tx_add_policy(pol_entry); err = tx_add_policy(pol_entry);
else
err = rx_add_policy(pol_entry);
if (err)
goto err_out;
return rx_add_policy(pol_entry); return 0;
err_out:
mlx5e_ipsec_unblock_tc_offload(pol_entry->ipsec->mdev);
return err;
} }
void mlx5e_accel_ipsec_fs_del_pol(struct mlx5e_ipsec_pol_entry *pol_entry) void mlx5e_accel_ipsec_fs_del_pol(struct mlx5e_ipsec_pol_entry *pol_entry)
...@@ -1556,16 +1834,18 @@ void mlx5e_accel_ipsec_fs_del_pol(struct mlx5e_ipsec_pol_entry *pol_entry) ...@@ -1556,16 +1834,18 @@ void mlx5e_accel_ipsec_fs_del_pol(struct mlx5e_ipsec_pol_entry *pol_entry)
mlx5_del_flow_rules(ipsec_rule->rule); mlx5_del_flow_rules(ipsec_rule->rule);
mlx5e_ipsec_unblock_tc_offload(pol_entry->ipsec->mdev);
if (pol_entry->attrs.dir == XFRM_DEV_OFFLOAD_IN) { if (pol_entry->attrs.dir == XFRM_DEV_OFFLOAD_IN) {
rx_ft_put_policy(pol_entry->ipsec, pol_entry->attrs.family, rx_ft_put_policy(pol_entry->ipsec, pol_entry->attrs.family,
pol_entry->attrs.prio); pol_entry->attrs.prio, pol_entry->attrs.type);
return; return;
} }
if (ipsec_rule->modify_hdr) if (ipsec_rule->modify_hdr)
mlx5_modify_header_dealloc(mdev, ipsec_rule->modify_hdr); mlx5_modify_header_dealloc(mdev, ipsec_rule->modify_hdr);
tx_ft_put_policy(pol_entry->ipsec, pol_entry->attrs.prio); tx_ft_put_policy(pol_entry->ipsec, pol_entry->attrs.prio, pol_entry->attrs.type);
} }
void mlx5e_accel_ipsec_fs_cleanup(struct mlx5e_ipsec *ipsec) void mlx5e_accel_ipsec_fs_cleanup(struct mlx5e_ipsec *ipsec)
...@@ -1573,7 +1853,7 @@ void mlx5e_accel_ipsec_fs_cleanup(struct mlx5e_ipsec *ipsec) ...@@ -1573,7 +1853,7 @@ void mlx5e_accel_ipsec_fs_cleanup(struct mlx5e_ipsec *ipsec)
if (!ipsec->tx) if (!ipsec->tx)
return; return;
if (mlx5_ipsec_device_caps(ipsec->mdev) & MLX5_IPSEC_CAP_ROCE) if (ipsec->roce)
mlx5_ipsec_fs_roce_cleanup(ipsec->roce); mlx5_ipsec_fs_roce_cleanup(ipsec->roce);
ipsec_fs_destroy_counters(ipsec); ipsec_fs_destroy_counters(ipsec);
...@@ -1588,12 +1868,24 @@ void mlx5e_accel_ipsec_fs_cleanup(struct mlx5e_ipsec *ipsec) ...@@ -1588,12 +1868,24 @@ void mlx5e_accel_ipsec_fs_cleanup(struct mlx5e_ipsec *ipsec)
mutex_destroy(&ipsec->rx_ipv6->ft.mutex); mutex_destroy(&ipsec->rx_ipv6->ft.mutex);
WARN_ON(ipsec->rx_ipv6->ft.refcnt); WARN_ON(ipsec->rx_ipv6->ft.refcnt);
kfree(ipsec->rx_ipv6); kfree(ipsec->rx_ipv6);
if (ipsec->is_uplink_rep) {
xa_destroy(&ipsec->rx_esw->ipsec_obj_id_map);
mutex_destroy(&ipsec->tx_esw->ft.mutex);
WARN_ON(ipsec->tx_esw->ft.refcnt);
kfree(ipsec->tx_esw);
mutex_destroy(&ipsec->rx_esw->ft.mutex);
WARN_ON(ipsec->rx_esw->ft.refcnt);
kfree(ipsec->rx_esw);
}
} }
int mlx5e_accel_ipsec_fs_init(struct mlx5e_ipsec *ipsec) int mlx5e_accel_ipsec_fs_init(struct mlx5e_ipsec *ipsec)
{ {
struct mlx5_core_dev *mdev = ipsec->mdev; struct mlx5_core_dev *mdev = ipsec->mdev;
struct mlx5_flow_namespace *ns; struct mlx5_flow_namespace *ns, *ns_esw;
int err = -ENOMEM; int err = -ENOMEM;
ns = mlx5_get_flow_namespace(ipsec->mdev, ns = mlx5_get_flow_namespace(ipsec->mdev,
...@@ -1601,9 +1893,23 @@ int mlx5e_accel_ipsec_fs_init(struct mlx5e_ipsec *ipsec) ...@@ -1601,9 +1893,23 @@ int mlx5e_accel_ipsec_fs_init(struct mlx5e_ipsec *ipsec)
if (!ns) if (!ns)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (ipsec->is_uplink_rep) {
ns_esw = mlx5_get_flow_namespace(mdev, MLX5_FLOW_NAMESPACE_FDB);
if (!ns_esw)
return -EOPNOTSUPP;
ipsec->tx_esw = kzalloc(sizeof(*ipsec->tx_esw), GFP_KERNEL);
if (!ipsec->tx_esw)
return -ENOMEM;
ipsec->rx_esw = kzalloc(sizeof(*ipsec->rx_esw), GFP_KERNEL);
if (!ipsec->rx_esw)
goto err_rx_esw;
}
ipsec->tx = kzalloc(sizeof(*ipsec->tx), GFP_KERNEL); ipsec->tx = kzalloc(sizeof(*ipsec->tx), GFP_KERNEL);
if (!ipsec->tx) if (!ipsec->tx)
return -ENOMEM; goto err_tx;
ipsec->rx_ipv4 = kzalloc(sizeof(*ipsec->rx_ipv4), GFP_KERNEL); ipsec->rx_ipv4 = kzalloc(sizeof(*ipsec->rx_ipv4), GFP_KERNEL);
if (!ipsec->rx_ipv4) if (!ipsec->rx_ipv4)
...@@ -1622,8 +1928,14 @@ int mlx5e_accel_ipsec_fs_init(struct mlx5e_ipsec *ipsec) ...@@ -1622,8 +1928,14 @@ int mlx5e_accel_ipsec_fs_init(struct mlx5e_ipsec *ipsec)
mutex_init(&ipsec->rx_ipv6->ft.mutex); mutex_init(&ipsec->rx_ipv6->ft.mutex);
ipsec->tx->ns = ns; ipsec->tx->ns = ns;
if (mlx5_ipsec_device_caps(mdev) & MLX5_IPSEC_CAP_ROCE) if (ipsec->is_uplink_rep) {
mutex_init(&ipsec->tx_esw->ft.mutex);
mutex_init(&ipsec->rx_esw->ft.mutex);
ipsec->tx_esw->ns = ns_esw;
xa_init_flags(&ipsec->rx_esw->ipsec_obj_id_map, XA_FLAGS_ALLOC1);
} else if (mlx5_ipsec_device_caps(mdev) & MLX5_IPSEC_CAP_ROCE) {
ipsec->roce = mlx5_ipsec_fs_roce_init(mdev); ipsec->roce = mlx5_ipsec_fs_roce_init(mdev);
}
return 0; return 0;
...@@ -1633,6 +1945,10 @@ int mlx5e_accel_ipsec_fs_init(struct mlx5e_ipsec *ipsec) ...@@ -1633,6 +1945,10 @@ int mlx5e_accel_ipsec_fs_init(struct mlx5e_ipsec *ipsec)
kfree(ipsec->rx_ipv4); kfree(ipsec->rx_ipv4);
err_rx_ipv4: err_rx_ipv4:
kfree(ipsec->tx); kfree(ipsec->tx);
err_tx:
kfree(ipsec->rx_esw);
err_rx_esw:
kfree(ipsec->tx_esw);
return err; return err;
} }
...@@ -1654,10 +1970,12 @@ void mlx5e_accel_ipsec_fs_modify(struct mlx5e_ipsec_sa_entry *sa_entry) ...@@ -1654,10 +1970,12 @@ void mlx5e_accel_ipsec_fs_modify(struct mlx5e_ipsec_sa_entry *sa_entry)
bool mlx5e_ipsec_fs_tunnel_enabled(struct mlx5e_ipsec_sa_entry *sa_entry) bool mlx5e_ipsec_fs_tunnel_enabled(struct mlx5e_ipsec_sa_entry *sa_entry)
{ {
struct mlx5e_ipsec_rx *rx = struct mlx5_accel_esp_xfrm_attrs *attrs = &sa_entry->attrs;
ipsec_rx(sa_entry->ipsec, sa_entry->attrs.family); struct mlx5e_ipsec_rx *rx;
struct mlx5e_ipsec_tx *tx = sa_entry->ipsec->tx; struct mlx5e_ipsec_tx *tx;
rx = ipsec_rx(sa_entry->ipsec, attrs->family, attrs->type);
tx = ipsec_tx(sa_entry->ipsec, attrs->type);
if (sa_entry->attrs.dir == XFRM_DEV_OFFLOAD_OUT) if (sa_entry->attrs.dir == XFRM_DEV_OFFLOAD_OUT)
return tx->allow_tunnel_mode; return tx->allow_tunnel_mode;
......
...@@ -45,8 +45,9 @@ u32 mlx5_ipsec_device_caps(struct mlx5_core_dev *mdev) ...@@ -45,8 +45,9 @@ u32 mlx5_ipsec_device_caps(struct mlx5_core_dev *mdev)
MLX5_CAP_FLOWTABLE_NIC_RX(mdev, decap)) MLX5_CAP_FLOWTABLE_NIC_RX(mdev, decap))
caps |= MLX5_IPSEC_CAP_PACKET_OFFLOAD; caps |= MLX5_IPSEC_CAP_PACKET_OFFLOAD;
if (MLX5_CAP_FLOWTABLE_NIC_TX(mdev, ignore_flow_level) && if ((MLX5_CAP_FLOWTABLE_NIC_TX(mdev, ignore_flow_level) &&
MLX5_CAP_FLOWTABLE_NIC_RX(mdev, ignore_flow_level)) MLX5_CAP_FLOWTABLE_NIC_RX(mdev, ignore_flow_level)) ||
MLX5_CAP_ESW_FLOWTABLE_FDB(mdev, ignore_flow_level))
caps |= MLX5_IPSEC_CAP_PRIO; caps |= MLX5_IPSEC_CAP_PRIO;
if (MLX5_CAP_FLOWTABLE_NIC_TX(mdev, if (MLX5_CAP_FLOWTABLE_NIC_TX(mdev,
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include "ipsec.h" #include "ipsec.h"
#include "ipsec_rxtx.h" #include "ipsec_rxtx.h"
#include "en.h" #include "en.h"
#include "esw/ipsec_fs.h"
enum { enum {
MLX5E_IPSEC_TX_SYNDROME_OFFLOAD = 0x8, MLX5E_IPSEC_TX_SYNDROME_OFFLOAD = 0x8,
...@@ -309,9 +310,8 @@ enum { ...@@ -309,9 +310,8 @@ enum {
void mlx5e_ipsec_offload_handle_rx_skb(struct net_device *netdev, void mlx5e_ipsec_offload_handle_rx_skb(struct net_device *netdev,
struct sk_buff *skb, struct sk_buff *skb,
struct mlx5_cqe64 *cqe) u32 ipsec_meta_data)
{ {
u32 ipsec_meta_data = be32_to_cpu(cqe->ft_metadata);
struct mlx5e_priv *priv = netdev_priv(netdev); struct mlx5e_priv *priv = netdev_priv(netdev);
struct mlx5e_ipsec *ipsec = priv->ipsec; struct mlx5e_ipsec *ipsec = priv->ipsec;
struct mlx5e_ipsec_sa_entry *sa_entry; struct mlx5e_ipsec_sa_entry *sa_entry;
...@@ -356,3 +356,24 @@ void mlx5e_ipsec_offload_handle_rx_skb(struct net_device *netdev, ...@@ -356,3 +356,24 @@ void mlx5e_ipsec_offload_handle_rx_skb(struct net_device *netdev,
atomic64_inc(&ipsec->sw_stats.ipsec_rx_drop_syndrome); atomic64_inc(&ipsec->sw_stats.ipsec_rx_drop_syndrome);
} }
} }
int mlx5_esw_ipsec_rx_make_metadata(struct mlx5e_priv *priv, u32 id, u32 *metadata)
{
struct mlx5e_ipsec *ipsec = priv->ipsec;
u32 ipsec_obj_id;
int err;
if (!ipsec || !ipsec->is_uplink_rep)
return -EINVAL;
err = mlx5_esw_ipsec_rx_ipsec_obj_id_search(priv, id, &ipsec_obj_id);
if (err) {
atomic64_inc(&ipsec->sw_stats.ipsec_rx_drop_sadb_miss);
return err;
}
*metadata = MLX5_IPSEC_METADATA_CREATE(ipsec_obj_id,
MLX5E_IPSEC_OFFLOAD_RX_SYNDROME_DECRYPTED);
return 0;
}
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
#define MLX5_IPSEC_METADATA_MARKER(metadata) (((metadata) >> 31) & 0x1) #define MLX5_IPSEC_METADATA_MARKER(metadata) (((metadata) >> 31) & 0x1)
#define MLX5_IPSEC_METADATA_SYNDROM(metadata) (((metadata) >> 24) & GENMASK(5, 0)) #define MLX5_IPSEC_METADATA_SYNDROM(metadata) (((metadata) >> 24) & GENMASK(5, 0))
#define MLX5_IPSEC_METADATA_HANDLE(metadata) ((metadata) & GENMASK(23, 0)) #define MLX5_IPSEC_METADATA_HANDLE(metadata) ((metadata) & GENMASK(23, 0))
#define MLX5_IPSEC_METADATA_CREATE(id, syndrome) ((id) | ((syndrome) << 24))
struct mlx5e_accel_tx_ipsec_state { struct mlx5e_accel_tx_ipsec_state {
struct xfrm_offload *xo; struct xfrm_offload *xo;
...@@ -66,7 +67,8 @@ void mlx5e_ipsec_handle_tx_wqe(struct mlx5e_tx_wqe *wqe, ...@@ -66,7 +67,8 @@ void mlx5e_ipsec_handle_tx_wqe(struct mlx5e_tx_wqe *wqe,
struct mlx5_wqe_inline_seg *inlseg); struct mlx5_wqe_inline_seg *inlseg);
void mlx5e_ipsec_offload_handle_rx_skb(struct net_device *netdev, void mlx5e_ipsec_offload_handle_rx_skb(struct net_device *netdev,
struct sk_buff *skb, struct sk_buff *skb,
struct mlx5_cqe64 *cqe); u32 ipsec_meta_data);
int mlx5_esw_ipsec_rx_make_metadata(struct mlx5e_priv *priv, u32 id, u32 *metadata);
static inline unsigned int mlx5e_ipsec_tx_ids_len(struct mlx5e_accel_tx_ipsec_state *ipsec_st) static inline unsigned int mlx5e_ipsec_tx_ids_len(struct mlx5e_accel_tx_ipsec_state *ipsec_st)
{ {
return ipsec_st->tailen; return ipsec_st->tailen;
...@@ -145,7 +147,7 @@ mlx5e_ipsec_txwqe_build_eseg_csum(struct mlx5e_txqsq *sq, struct sk_buff *skb, ...@@ -145,7 +147,7 @@ mlx5e_ipsec_txwqe_build_eseg_csum(struct mlx5e_txqsq *sq, struct sk_buff *skb,
static inline static inline
void mlx5e_ipsec_offload_handle_rx_skb(struct net_device *netdev, void mlx5e_ipsec_offload_handle_rx_skb(struct net_device *netdev,
struct sk_buff *skb, struct sk_buff *skb,
struct mlx5_cqe64 *cqe) u32 ipsec_meta_data)
{} {}
static inline bool mlx5e_ipsec_eseg_meta(struct mlx5_wqe_eth_seg *eseg) static inline bool mlx5e_ipsec_eseg_meta(struct mlx5_wqe_eth_seg *eseg)
......
...@@ -1338,6 +1338,7 @@ static mlx5e_stats_grp_t mlx5e_ul_rep_stats_grps[] = { ...@@ -1338,6 +1338,7 @@ static mlx5e_stats_grp_t mlx5e_ul_rep_stats_grps[] = {
&MLX5E_STATS_GRP(channels), &MLX5E_STATS_GRP(channels),
&MLX5E_STATS_GRP(per_port_buff_congest), &MLX5E_STATS_GRP(per_port_buff_congest),
#ifdef CONFIG_MLX5_EN_IPSEC #ifdef CONFIG_MLX5_EN_IPSEC
&MLX5E_STATS_GRP(ipsec_hw),
&MLX5E_STATS_GRP(ipsec_sw), &MLX5E_STATS_GRP(ipsec_sw),
#endif #endif
&MLX5E_STATS_GRP(ptp), &MLX5E_STATS_GRP(ptp),
......
...@@ -1543,7 +1543,8 @@ static inline void mlx5e_build_rx_skb(struct mlx5_cqe64 *cqe, ...@@ -1543,7 +1543,8 @@ static inline void mlx5e_build_rx_skb(struct mlx5_cqe64 *cqe,
mlx5e_ktls_handle_rx_skb(rq, skb, cqe, &cqe_bcnt); mlx5e_ktls_handle_rx_skb(rq, skb, cqe, &cqe_bcnt);
if (unlikely(mlx5_ipsec_is_rx_flow(cqe))) if (unlikely(mlx5_ipsec_is_rx_flow(cqe)))
mlx5e_ipsec_offload_handle_rx_skb(netdev, skb, cqe); mlx5e_ipsec_offload_handle_rx_skb(netdev, skb,
be32_to_cpu(cqe->ft_metadata));
if (unlikely(mlx5e_macsec_is_rx_flow(cqe))) if (unlikely(mlx5e_macsec_is_rx_flow(cqe)))
mlx5e_macsec_offload_handle_rx_skb(netdev, skb, cqe); mlx5e_macsec_offload_handle_rx_skb(netdev, skb, cqe);
......
...@@ -4606,6 +4606,46 @@ static bool is_flow_rule_duplicate_allowed(struct net_device *dev, ...@@ -4606,6 +4606,46 @@ static bool is_flow_rule_duplicate_allowed(struct net_device *dev,
return netif_is_lag_port(dev) && rpriv && rpriv->rep->vport != MLX5_VPORT_UPLINK; return netif_is_lag_port(dev) && rpriv && rpriv->rep->vport != MLX5_VPORT_UPLINK;
} }
/* As IPsec and TC order is not aligned between software and hardware-offload,
* either IPsec offload or TC offload, not both, is allowed for a specific interface.
*/
static bool is_tc_ipsec_order_check_needed(struct net_device *filter, struct mlx5e_priv *priv)
{
if (!IS_ENABLED(CONFIG_MLX5_EN_IPSEC))
return false;
if (filter != priv->netdev)
return false;
if (mlx5e_eswitch_vf_rep(priv->netdev))
return false;
return true;
}
static int mlx5e_tc_block_ipsec_offload(struct net_device *filter, struct mlx5e_priv *priv)
{
struct mlx5_core_dev *mdev = priv->mdev;
if (!is_tc_ipsec_order_check_needed(filter, priv))
return 0;
if (mdev->num_block_tc)
return -EBUSY;
mdev->num_block_ipsec++;
return 0;
}
static void mlx5e_tc_unblock_ipsec_offload(struct net_device *filter, struct mlx5e_priv *priv)
{
if (!is_tc_ipsec_order_check_needed(filter, priv))
return;
priv->mdev->num_block_ipsec--;
}
int mlx5e_configure_flower(struct net_device *dev, struct mlx5e_priv *priv, int mlx5e_configure_flower(struct net_device *dev, struct mlx5e_priv *priv,
struct flow_cls_offload *f, unsigned long flags) struct flow_cls_offload *f, unsigned long flags)
{ {
...@@ -4618,6 +4658,10 @@ int mlx5e_configure_flower(struct net_device *dev, struct mlx5e_priv *priv, ...@@ -4618,6 +4658,10 @@ int mlx5e_configure_flower(struct net_device *dev, struct mlx5e_priv *priv,
if (!mlx5_esw_hold(priv->mdev)) if (!mlx5_esw_hold(priv->mdev))
return -EBUSY; return -EBUSY;
err = mlx5e_tc_block_ipsec_offload(dev, priv);
if (err)
goto esw_release;
mlx5_esw_get(priv->mdev); mlx5_esw_get(priv->mdev);
rcu_read_lock(); rcu_read_lock();
...@@ -4663,7 +4707,9 @@ int mlx5e_configure_flower(struct net_device *dev, struct mlx5e_priv *priv, ...@@ -4663,7 +4707,9 @@ int mlx5e_configure_flower(struct net_device *dev, struct mlx5e_priv *priv,
err_free: err_free:
mlx5e_flow_put(priv, flow); mlx5e_flow_put(priv, flow);
out: out:
mlx5e_tc_unblock_ipsec_offload(dev, priv);
mlx5_esw_put(priv->mdev); mlx5_esw_put(priv->mdev);
esw_release:
mlx5_esw_release(priv->mdev); mlx5_esw_release(priv->mdev);
return err; return err;
} }
...@@ -4704,6 +4750,7 @@ int mlx5e_delete_flower(struct net_device *dev, struct mlx5e_priv *priv, ...@@ -4704,6 +4750,7 @@ int mlx5e_delete_flower(struct net_device *dev, struct mlx5e_priv *priv,
trace_mlx5e_delete_flower(f); trace_mlx5e_delete_flower(f);
mlx5e_flow_put(priv, flow); mlx5e_flow_put(priv, flow);
mlx5e_tc_unblock_ipsec_offload(dev, priv);
mlx5_esw_put(priv->mdev); mlx5_esw_put(priv->mdev);
return 0; return 0;
......
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
// Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#include "fs_core.h"
#include "eswitch.h"
#include "en_accel/ipsec.h"
#include "esw/ipsec_fs.h"
#if IS_ENABLED(CONFIG_MLX5_CLS_ACT)
#include "en/tc_priv.h"
#endif
enum {
MLX5_ESW_IPSEC_RX_POL_FT_LEVEL,
MLX5_ESW_IPSEC_RX_ESP_FT_LEVEL,
MLX5_ESW_IPSEC_RX_ESP_FT_CHK_LEVEL,
};
enum {
MLX5_ESW_IPSEC_TX_POL_FT_LEVEL,
MLX5_ESW_IPSEC_TX_ESP_FT_LEVEL,
MLX5_ESW_IPSEC_TX_ESP_FT_CNT_LEVEL,
};
static void esw_ipsec_rx_status_drop_destroy(struct mlx5e_ipsec *ipsec,
struct mlx5e_ipsec_rx *rx)
{
mlx5_del_flow_rules(rx->status_drop.rule);
mlx5_destroy_flow_group(rx->status_drop.group);
mlx5_fc_destroy(ipsec->mdev, rx->status_drop_cnt);
}
static void esw_ipsec_rx_status_pass_destroy(struct mlx5e_ipsec *ipsec,
struct mlx5e_ipsec_rx *rx)
{
mlx5_del_flow_rules(rx->status.rule);
mlx5_chains_put_table(esw_chains(ipsec->mdev->priv.eswitch), 0, 1, 0);
}
static int esw_ipsec_rx_status_drop_create(struct mlx5e_ipsec *ipsec,
struct mlx5e_ipsec_rx *rx)
{
int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
struct mlx5_flow_table *ft = rx->ft.status;
struct mlx5_core_dev *mdev = ipsec->mdev;
struct mlx5_flow_destination dest = {};
struct mlx5_flow_act flow_act = {};
struct mlx5_flow_handle *rule;
struct mlx5_fc *flow_counter;
struct mlx5_flow_spec *spec;
struct mlx5_flow_group *g;
u32 *flow_group_in;
int err = 0;
flow_group_in = kvzalloc(inlen, GFP_KERNEL);
spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
if (!flow_group_in || !spec) {
err = -ENOMEM;
goto err_out;
}
MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, ft->max_fte - 1);
MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, ft->max_fte - 1);
g = mlx5_create_flow_group(ft, flow_group_in);
if (IS_ERR(g)) {
err = PTR_ERR(g);
mlx5_core_err(mdev,
"Failed to add ipsec rx status drop flow group, err=%d\n", err);
goto err_out;
}
flow_counter = mlx5_fc_create(mdev, false);
if (IS_ERR(flow_counter)) {
err = PTR_ERR(flow_counter);
mlx5_core_err(mdev,
"Failed to add ipsec rx status drop rule counter, err=%d\n", err);
goto err_cnt;
}
flow_act.action = MLX5_FLOW_CONTEXT_ACTION_DROP | MLX5_FLOW_CONTEXT_ACTION_COUNT;
dest.type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
dest.counter_id = mlx5_fc_id(flow_counter);
spec->flow_context.flow_source = MLX5_FLOW_CONTEXT_FLOW_SOURCE_UPLINK;
rule = mlx5_add_flow_rules(ft, spec, &flow_act, &dest, 1);
if (IS_ERR(rule)) {
err = PTR_ERR(rule);
mlx5_core_err(mdev,
"Failed to add ipsec rx status drop rule, err=%d\n", err);
goto err_rule;
}
rx->status_drop.group = g;
rx->status_drop.rule = rule;
rx->status_drop_cnt = flow_counter;
kvfree(flow_group_in);
kvfree(spec);
return 0;
err_rule:
mlx5_fc_destroy(mdev, flow_counter);
err_cnt:
mlx5_destroy_flow_group(g);
err_out:
kvfree(flow_group_in);
kvfree(spec);
return err;
}
static int esw_ipsec_rx_status_pass_create(struct mlx5e_ipsec *ipsec,
struct mlx5e_ipsec_rx *rx,
struct mlx5_flow_destination *dest)
{
struct mlx5_flow_act flow_act = {};
struct mlx5_flow_handle *rule;
struct mlx5_flow_spec *spec;
int err;
spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
if (!spec)
return -ENOMEM;
MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria,
misc_parameters_2.ipsec_syndrome);
MLX5_SET(fte_match_param, spec->match_value,
misc_parameters_2.ipsec_syndrome, 0);
spec->flow_context.flow_source = MLX5_FLOW_CONTEXT_FLOW_SOURCE_UPLINK;
spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS_2;
flow_act.flags = FLOW_ACT_NO_APPEND;
flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
MLX5_FLOW_CONTEXT_ACTION_COUNT;
rule = mlx5_add_flow_rules(rx->ft.status, spec, &flow_act, dest, 2);
if (IS_ERR(rule)) {
err = PTR_ERR(rule);
mlx5_core_warn(ipsec->mdev,
"Failed to add ipsec rx status pass rule, err=%d\n", err);
goto err_rule;
}
rx->status.rule = rule;
kvfree(spec);
return 0;
err_rule:
kvfree(spec);
return err;
}
void mlx5_esw_ipsec_rx_status_destroy(struct mlx5e_ipsec *ipsec,
struct mlx5e_ipsec_rx *rx)
{
esw_ipsec_rx_status_pass_destroy(ipsec, rx);
esw_ipsec_rx_status_drop_destroy(ipsec, rx);
}
int mlx5_esw_ipsec_rx_status_create(struct mlx5e_ipsec *ipsec,
struct mlx5e_ipsec_rx *rx,
struct mlx5_flow_destination *dest)
{
int err;
err = esw_ipsec_rx_status_drop_create(ipsec, rx);
if (err)
return err;
err = esw_ipsec_rx_status_pass_create(ipsec, rx, dest);
if (err)
goto err_pass_create;
return 0;
err_pass_create:
esw_ipsec_rx_status_drop_destroy(ipsec, rx);
return err;
}
void mlx5_esw_ipsec_rx_create_attr_set(struct mlx5e_ipsec *ipsec,
struct mlx5e_ipsec_rx_create_attr *attr)
{
attr->prio = FDB_CRYPTO_INGRESS;
attr->pol_level = MLX5_ESW_IPSEC_RX_POL_FT_LEVEL;
attr->sa_level = MLX5_ESW_IPSEC_RX_ESP_FT_LEVEL;
attr->status_level = MLX5_ESW_IPSEC_RX_ESP_FT_CHK_LEVEL;
attr->chains_ns = MLX5_FLOW_NAMESPACE_FDB;
}
int mlx5_esw_ipsec_rx_status_pass_dest_get(struct mlx5e_ipsec *ipsec,
struct mlx5_flow_destination *dest)
{
dest->type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
dest->ft = mlx5_chains_get_table(esw_chains(ipsec->mdev->priv.eswitch), 0, 1, 0);
return 0;
}
int mlx5_esw_ipsec_rx_setup_modify_header(struct mlx5e_ipsec_sa_entry *sa_entry,
struct mlx5_flow_act *flow_act)
{
u8 action[MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto)] = {};
struct mlx5e_ipsec *ipsec = sa_entry->ipsec;
struct mlx5_core_dev *mdev = ipsec->mdev;
struct mlx5_modify_hdr *modify_hdr;
u32 mapped_id;
int err;
err = xa_alloc_bh(&ipsec->rx_esw->ipsec_obj_id_map, &mapped_id,
xa_mk_value(sa_entry->ipsec_obj_id),
XA_LIMIT(1, ESW_IPSEC_RX_MAPPED_ID_MASK), 0);
if (err)
return err;
/* reuse tunnel bits for ipsec,
* tun_id is always 0 and tun_opts is mapped to ipsec_obj_id.
*/
MLX5_SET(set_action_in, action, action_type, MLX5_ACTION_TYPE_SET);
MLX5_SET(set_action_in, action, field,
MLX5_ACTION_IN_FIELD_METADATA_REG_C_1);
MLX5_SET(set_action_in, action, offset, ESW_ZONE_ID_BITS);
MLX5_SET(set_action_in, action, length,
ESW_TUN_ID_BITS + ESW_TUN_OPTS_BITS);
MLX5_SET(set_action_in, action, data, mapped_id);
modify_hdr = mlx5_modify_header_alloc(mdev, MLX5_FLOW_NAMESPACE_FDB,
1, action);
if (IS_ERR(modify_hdr)) {
err = PTR_ERR(modify_hdr);
goto err_header_alloc;
}
sa_entry->rx_mapped_id = mapped_id;
flow_act->modify_hdr = modify_hdr;
flow_act->action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;
return 0;
err_header_alloc:
xa_erase_bh(&ipsec->rx_esw->ipsec_obj_id_map, mapped_id);
return err;
}
void mlx5_esw_ipsec_rx_id_mapping_remove(struct mlx5e_ipsec_sa_entry *sa_entry)
{
struct mlx5e_ipsec *ipsec = sa_entry->ipsec;
if (sa_entry->rx_mapped_id)
xa_erase_bh(&ipsec->rx_esw->ipsec_obj_id_map,
sa_entry->rx_mapped_id);
}
int mlx5_esw_ipsec_rx_ipsec_obj_id_search(struct mlx5e_priv *priv, u32 id,
u32 *ipsec_obj_id)
{
struct mlx5e_ipsec *ipsec = priv->ipsec;
void *val;
val = xa_load(&ipsec->rx_esw->ipsec_obj_id_map, id);
if (!val)
return -ENOENT;
*ipsec_obj_id = xa_to_value(val);
return 0;
}
void mlx5_esw_ipsec_tx_create_attr_set(struct mlx5e_ipsec *ipsec,
struct mlx5e_ipsec_tx_create_attr *attr)
{
attr->prio = FDB_CRYPTO_EGRESS;
attr->pol_level = MLX5_ESW_IPSEC_TX_POL_FT_LEVEL;
attr->sa_level = MLX5_ESW_IPSEC_TX_ESP_FT_LEVEL;
attr->cnt_level = MLX5_ESW_IPSEC_TX_ESP_FT_CNT_LEVEL;
attr->chains_ns = MLX5_FLOW_NAMESPACE_FDB;
}
#if IS_ENABLED(CONFIG_MLX5_CLS_ACT)
static int mlx5_esw_ipsec_modify_flow_dests(struct mlx5_eswitch *esw,
struct mlx5e_tc_flow *flow)
{
struct mlx5_esw_flow_attr *esw_attr;
struct mlx5_flow_attr *attr;
int err;
attr = flow->attr;
esw_attr = attr->esw_attr;
if (esw_attr->out_count - esw_attr->split_count > 1)
return 0;
err = mlx5_eswitch_restore_ipsec_rule(esw, flow->rule[0], esw_attr,
esw_attr->out_count - 1);
return err;
}
#endif
void mlx5_esw_ipsec_restore_dest_uplink(struct mlx5_core_dev *mdev)
{
#if IS_ENABLED(CONFIG_MLX5_CLS_ACT)
struct mlx5_eswitch *esw = mdev->priv.eswitch;
struct mlx5_eswitch_rep *rep;
struct mlx5e_rep_priv *rpriv;
struct rhashtable_iter iter;
struct mlx5e_tc_flow *flow;
unsigned long i;
int err;
xa_for_each(&esw->offloads.vport_reps, i, rep) {
rpriv = rep->rep_data[REP_ETH].priv;
if (!rpriv || !rpriv->netdev)
continue;
rhashtable_walk_enter(&rpriv->tc_ht, &iter);
rhashtable_walk_start(&iter);
while ((flow = rhashtable_walk_next(&iter)) != NULL) {
if (IS_ERR(flow))
continue;
err = mlx5_esw_ipsec_modify_flow_dests(esw, flow);
if (err)
mlx5_core_warn_once(mdev,
"Faided to modify flow dests for IPsec");
}
rhashtable_walk_stop(&iter);
rhashtable_walk_exit(&iter);
}
#endif
}
/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
/* Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
#ifndef __MLX5_ESW_IPSEC_FS_H__
#define __MLX5_ESW_IPSEC_FS_H__
struct mlx5e_ipsec;
struct mlx5e_ipsec_sa_entry;
#ifdef CONFIG_MLX5_ESWITCH
void mlx5_esw_ipsec_rx_status_destroy(struct mlx5e_ipsec *ipsec,
struct mlx5e_ipsec_rx *rx);
int mlx5_esw_ipsec_rx_status_create(struct mlx5e_ipsec *ipsec,
struct mlx5e_ipsec_rx *rx,
struct mlx5_flow_destination *dest);
void mlx5_esw_ipsec_rx_create_attr_set(struct mlx5e_ipsec *ipsec,
struct mlx5e_ipsec_rx_create_attr *attr);
int mlx5_esw_ipsec_rx_status_pass_dest_get(struct mlx5e_ipsec *ipsec,
struct mlx5_flow_destination *dest);
int mlx5_esw_ipsec_rx_setup_modify_header(struct mlx5e_ipsec_sa_entry *sa_entry,
struct mlx5_flow_act *flow_act);
void mlx5_esw_ipsec_rx_id_mapping_remove(struct mlx5e_ipsec_sa_entry *sa_entry);
int mlx5_esw_ipsec_rx_ipsec_obj_id_search(struct mlx5e_priv *priv, u32 id,
u32 *ipsec_obj_id);
void mlx5_esw_ipsec_tx_create_attr_set(struct mlx5e_ipsec *ipsec,
struct mlx5e_ipsec_tx_create_attr *attr);
void mlx5_esw_ipsec_restore_dest_uplink(struct mlx5_core_dev *mdev);
#else
static inline void mlx5_esw_ipsec_rx_status_destroy(struct mlx5e_ipsec *ipsec,
struct mlx5e_ipsec_rx *rx) {}
static inline int mlx5_esw_ipsec_rx_status_create(struct mlx5e_ipsec *ipsec,
struct mlx5e_ipsec_rx *rx,
struct mlx5_flow_destination *dest)
{
return -EINVAL;
}
static inline void mlx5_esw_ipsec_rx_create_attr_set(struct mlx5e_ipsec *ipsec,
struct mlx5e_ipsec_rx_create_attr *attr) {}
static inline int mlx5_esw_ipsec_rx_status_pass_dest_get(struct mlx5e_ipsec *ipsec,
struct mlx5_flow_destination *dest)
{
return -EINVAL;
}
static inline int mlx5_esw_ipsec_rx_setup_modify_header(struct mlx5e_ipsec_sa_entry *sa_entry,
struct mlx5_flow_act *flow_act)
{
return -EINVAL;
}
static inline void mlx5_esw_ipsec_rx_id_mapping_remove(struct mlx5e_ipsec_sa_entry *sa_entry) {}
static inline int mlx5_esw_ipsec_rx_ipsec_obj_id_search(struct mlx5e_priv *priv, u32 id,
u32 *ipsec_obj_id)
{
return -EINVAL;
}
static inline void mlx5_esw_ipsec_tx_create_attr_set(struct mlx5e_ipsec *ipsec,
struct mlx5e_ipsec_tx_create_attr *attr) {}
static inline void mlx5_esw_ipsec_restore_dest_uplink(struct mlx5_core_dev *mdev) {}
#endif /* CONFIG_MLX5_ESWITCH */
#endif /* __MLX5_ESW_IPSEC_FS_H__ */
...@@ -254,6 +254,7 @@ struct mlx5_esw_offload { ...@@ -254,6 +254,7 @@ struct mlx5_esw_offload {
struct mlx5_flow_group *vport_rx_group; struct mlx5_flow_group *vport_rx_group;
struct mlx5_flow_group *vport_rx_drop_group; struct mlx5_flow_group *vport_rx_drop_group;
struct mlx5_flow_handle *vport_rx_drop_rule; struct mlx5_flow_handle *vport_rx_drop_rule;
struct mlx5_flow_table *ft_ipsec_tx_pol;
struct xarray vport_reps; struct xarray vport_reps;
struct list_head peer_flows[MLX5_MAX_PORTS]; struct list_head peer_flows[MLX5_MAX_PORTS];
struct mutex peer_mutex; struct mutex peer_mutex;
...@@ -269,6 +270,7 @@ struct mlx5_esw_offload { ...@@ -269,6 +270,7 @@ struct mlx5_esw_offload {
u8 inline_mode; u8 inline_mode;
atomic64_t num_flows; atomic64_t num_flows;
u64 num_block_encap; u64 num_block_encap;
u64 num_block_mode;
enum devlink_eswitch_encap_mode encap; enum devlink_eswitch_encap_mode encap;
struct ida vport_metadata_ida; struct ida vport_metadata_ida;
unsigned int host_number; /* ECPF supports one external host */ unsigned int host_number; /* ECPF supports one external host */
...@@ -783,6 +785,11 @@ int mlx5_eswitch_reload_reps(struct mlx5_eswitch *esw); ...@@ -783,6 +785,11 @@ int mlx5_eswitch_reload_reps(struct mlx5_eswitch *esw);
bool mlx5_eswitch_block_encap(struct mlx5_core_dev *dev); bool mlx5_eswitch_block_encap(struct mlx5_core_dev *dev);
void mlx5_eswitch_unblock_encap(struct mlx5_core_dev *dev); void mlx5_eswitch_unblock_encap(struct mlx5_core_dev *dev);
int mlx5_eswitch_block_mode_trylock(struct mlx5_core_dev *dev);
void mlx5_eswitch_block_mode_unlock(struct mlx5_core_dev *dev, int err);
void mlx5_eswitch_unblock_mode_lock(struct mlx5_core_dev *dev);
void mlx5_eswitch_unblock_mode_unlock(struct mlx5_core_dev *dev);
static inline int mlx5_eswitch_num_vfs(struct mlx5_eswitch *esw) static inline int mlx5_eswitch_num_vfs(struct mlx5_eswitch *esw)
{ {
if (mlx5_esw_allowed(esw)) if (mlx5_esw_allowed(esw))
...@@ -804,6 +811,8 @@ mlx5_eswitch_get_slow_fdb(struct mlx5_eswitch *esw) ...@@ -804,6 +811,8 @@ mlx5_eswitch_get_slow_fdb(struct mlx5_eswitch *esw)
return esw->fdb_table.offloads.slow_fdb; return esw->fdb_table.offloads.slow_fdb;
} }
int mlx5_eswitch_restore_ipsec_rule(struct mlx5_eswitch *esw, struct mlx5_flow_handle *rule,
struct mlx5_esw_flow_attr *esw_attr, int attr_idx);
#else /* CONFIG_MLX5_ESWITCH */ #else /* CONFIG_MLX5_ESWITCH */
/* eswitch API stubs */ /* eswitch API stubs */
static inline int mlx5_eswitch_init(struct mlx5_core_dev *dev) { return 0; } static inline int mlx5_eswitch_init(struct mlx5_core_dev *dev) { return 0; }
...@@ -862,6 +871,14 @@ static inline bool mlx5_eswitch_block_encap(struct mlx5_core_dev *dev) ...@@ -862,6 +871,14 @@ static inline bool mlx5_eswitch_block_encap(struct mlx5_core_dev *dev)
static inline void mlx5_eswitch_unblock_encap(struct mlx5_core_dev *dev) static inline void mlx5_eswitch_unblock_encap(struct mlx5_core_dev *dev)
{ {
} }
static inline int mlx5_eswitch_block_mode_trylock(struct mlx5_core_dev *dev) { return 0; }
static inline void mlx5_eswitch_block_mode_unlock(struct mlx5_core_dev *dev, int err) {}
static inline void mlx5_eswitch_unblock_mode_lock(struct mlx5_core_dev *dev) {}
static inline void mlx5_eswitch_unblock_mode_unlock(struct mlx5_core_dev *dev) {}
#endif /* CONFIG_MLX5_ESWITCH */ #endif /* CONFIG_MLX5_ESWITCH */
#endif /* __MLX5_ESWITCH_H__ */ #endif /* __MLX5_ESWITCH_H__ */
...@@ -424,10 +424,51 @@ esw_cleanup_chain_dest(struct mlx5_fs_chains *chains, u32 chain, u32 prio, u32 l ...@@ -424,10 +424,51 @@ esw_cleanup_chain_dest(struct mlx5_fs_chains *chains, u32 chain, u32 prio, u32 l
mlx5_chains_put_table(chains, chain, prio, level); mlx5_chains_put_table(chains, chain, prio, level);
} }
static bool esw_same_vhca_id(struct mlx5_core_dev *mdev1, struct mlx5_core_dev *mdev2)
{
return MLX5_CAP_GEN(mdev1, vhca_id) == MLX5_CAP_GEN(mdev2, vhca_id);
}
static bool esw_setup_uplink_fwd_ipsec_needed(struct mlx5_eswitch *esw,
struct mlx5_esw_flow_attr *esw_attr,
int attr_idx)
{
if (esw->offloads.ft_ipsec_tx_pol &&
esw_attr->dests[attr_idx].rep &&
esw_attr->dests[attr_idx].rep->vport == MLX5_VPORT_UPLINK &&
/* To be aligned with software, encryption is needed only for tunnel device */
(esw_attr->dests[attr_idx].flags & MLX5_ESW_DEST_ENCAP_VALID) &&
esw_attr->dests[attr_idx].rep != esw_attr->in_rep &&
esw_same_vhca_id(esw_attr->dests[attr_idx].mdev, esw->dev))
return true;
return false;
}
static bool esw_flow_dests_fwd_ipsec_check(struct mlx5_eswitch *esw,
struct mlx5_esw_flow_attr *esw_attr)
{
int i;
if (!esw->offloads.ft_ipsec_tx_pol)
return true;
for (i = 0; i < esw_attr->split_count; i++)
if (esw_setup_uplink_fwd_ipsec_needed(esw, esw_attr, i))
return false;
for (i = esw_attr->split_count; i < esw_attr->out_count; i++)
if (esw_setup_uplink_fwd_ipsec_needed(esw, esw_attr, i) &&
(esw_attr->out_count - esw_attr->split_count > 1))
return false;
return true;
}
static void static void
esw_setup_vport_dest(struct mlx5_flow_destination *dest, struct mlx5_flow_act *flow_act, esw_setup_dest_fwd_vport(struct mlx5_flow_destination *dest, struct mlx5_flow_act *flow_act,
struct mlx5_eswitch *esw, struct mlx5_esw_flow_attr *esw_attr, struct mlx5_eswitch *esw, struct mlx5_esw_flow_attr *esw_attr,
int attr_idx, int dest_idx, bool pkt_reformat) int attr_idx, int dest_idx, bool pkt_reformat)
{ {
dest[dest_idx].type = MLX5_FLOW_DESTINATION_TYPE_VPORT; dest[dest_idx].type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
dest[dest_idx].vport.num = esw_attr->dests[attr_idx].rep->vport; dest[dest_idx].vport.num = esw_attr->dests[attr_idx].rep->vport;
...@@ -449,6 +490,33 @@ esw_setup_vport_dest(struct mlx5_flow_destination *dest, struct mlx5_flow_act *f ...@@ -449,6 +490,33 @@ esw_setup_vport_dest(struct mlx5_flow_destination *dest, struct mlx5_flow_act *f
} }
} }
static void
esw_setup_dest_fwd_ipsec(struct mlx5_flow_destination *dest, struct mlx5_flow_act *flow_act,
struct mlx5_eswitch *esw, struct mlx5_esw_flow_attr *esw_attr,
int attr_idx, int dest_idx, bool pkt_reformat)
{
dest[dest_idx].ft = esw->offloads.ft_ipsec_tx_pol;
dest[dest_idx].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
if (pkt_reformat &&
esw_attr->dests[attr_idx].flags & MLX5_ESW_DEST_ENCAP_VALID) {
flow_act->action |= MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT;
flow_act->pkt_reformat = esw_attr->dests[attr_idx].pkt_reformat;
}
}
static void
esw_setup_vport_dest(struct mlx5_flow_destination *dest, struct mlx5_flow_act *flow_act,
struct mlx5_eswitch *esw, struct mlx5_esw_flow_attr *esw_attr,
int attr_idx, int dest_idx, bool pkt_reformat)
{
if (esw_setup_uplink_fwd_ipsec_needed(esw, esw_attr, attr_idx))
esw_setup_dest_fwd_ipsec(dest, flow_act, esw, esw_attr,
attr_idx, dest_idx, pkt_reformat);
else
esw_setup_dest_fwd_vport(dest, flow_act, esw, esw_attr,
attr_idx, dest_idx, pkt_reformat);
}
static int static int
esw_setup_vport_dests(struct mlx5_flow_destination *dest, struct mlx5_flow_act *flow_act, esw_setup_vport_dests(struct mlx5_flow_destination *dest, struct mlx5_flow_act *flow_act,
struct mlx5_eswitch *esw, struct mlx5_esw_flow_attr *esw_attr, struct mlx5_eswitch *esw, struct mlx5_esw_flow_attr *esw_attr,
...@@ -575,6 +643,9 @@ mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw, ...@@ -575,6 +643,9 @@ mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw,
if (!mlx5_eswitch_vlan_actions_supported(esw->dev, 1)) if (!mlx5_eswitch_vlan_actions_supported(esw->dev, 1))
return ERR_PTR(-EOPNOTSUPP); return ERR_PTR(-EOPNOTSUPP);
if (!esw_flow_dests_fwd_ipsec_check(esw, esw_attr))
return ERR_PTR(-EOPNOTSUPP);
dest = kcalloc(MLX5_MAX_FLOW_FWD_VPORTS + 1, sizeof(*dest), GFP_KERNEL); dest = kcalloc(MLX5_MAX_FLOW_FWD_VPORTS + 1, sizeof(*dest), GFP_KERNEL);
if (!dest) if (!dest)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
...@@ -884,6 +955,17 @@ mlx5_eswitch_add_send_to_vport_rule(struct mlx5_eswitch *on_esw, ...@@ -884,6 +955,17 @@ mlx5_eswitch_add_send_to_vport_rule(struct mlx5_eswitch *on_esw,
dest.vport.flags |= MLX5_FLOW_DEST_VPORT_VHCA_ID; dest.vport.flags |= MLX5_FLOW_DEST_VPORT_VHCA_ID;
flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
if (rep->vport == MLX5_VPORT_UPLINK && on_esw->offloads.ft_ipsec_tx_pol) {
dest.ft = on_esw->offloads.ft_ipsec_tx_pol;
flow_act.flags = FLOW_ACT_IGNORE_FLOW_LEVEL;
dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
} else {
dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
dest.vport.num = rep->vport;
dest.vport.vhca_id = MLX5_CAP_GEN(rep->esw->dev, vhca_id);
dest.vport.flags |= MLX5_FLOW_DEST_VPORT_VHCA_ID;
}
if (MLX5_CAP_ESW_FLOWTABLE(on_esw->dev, flow_source) && if (MLX5_CAP_ESW_FLOWTABLE(on_esw->dev, flow_source) &&
rep->vport == MLX5_VPORT_UPLINK) rep->vport == MLX5_VPORT_UPLINK)
spec->flow_context.flow_source = MLX5_FLOW_CONTEXT_FLOW_SOURCE_LOCAL_VPORT; spec->flow_context.flow_source = MLX5_FLOW_CONTEXT_FLOW_SOURCE_LOCAL_VPORT;
...@@ -3507,6 +3589,69 @@ static bool esw_offloads_devlink_ns_eq_netdev_ns(struct devlink *devlink) ...@@ -3507,6 +3589,69 @@ static bool esw_offloads_devlink_ns_eq_netdev_ns(struct devlink *devlink)
return net_eq(devl_net, netdev_net); return net_eq(devl_net, netdev_net);
} }
int mlx5_eswitch_block_mode_trylock(struct mlx5_core_dev *dev)
{
struct devlink *devlink = priv_to_devlink(dev);
struct mlx5_eswitch *esw;
int err;
devl_lock(devlink);
esw = mlx5_devlink_eswitch_get(devlink);
if (IS_ERR(esw)) {
/* Failure means no eswitch => not possible to change eswitch mode */
devl_unlock(devlink);
return 0;
}
err = mlx5_esw_try_lock(esw);
if (err < 0) {
devl_unlock(devlink);
return err;
}
return 0;
}
void mlx5_eswitch_block_mode_unlock(struct mlx5_core_dev *dev, int err)
{
struct devlink *devlink = priv_to_devlink(dev);
struct mlx5_eswitch *esw;
esw = mlx5_devlink_eswitch_get(devlink);
if (IS_ERR(esw))
return;
if (!err)
esw->offloads.num_block_mode++;
mlx5_esw_unlock(esw);
devl_unlock(devlink);
}
void mlx5_eswitch_unblock_mode_lock(struct mlx5_core_dev *dev)
{
struct devlink *devlink = priv_to_devlink(dev);
struct mlx5_eswitch *esw;
esw = mlx5_devlink_eswitch_get(devlink);
if (IS_ERR(esw))
return;
down_write(&esw->mode_lock);
}
void mlx5_eswitch_unblock_mode_unlock(struct mlx5_core_dev *dev)
{
struct devlink *devlink = priv_to_devlink(dev);
struct mlx5_eswitch *esw;
esw = mlx5_devlink_eswitch_get(devlink);
if (IS_ERR(esw))
return;
esw->offloads.num_block_mode--;
up_write(&esw->mode_lock);
}
int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode, int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
...@@ -3540,6 +3685,13 @@ int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode, ...@@ -3540,6 +3685,13 @@ int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
if (cur_mlx5_mode == mlx5_mode) if (cur_mlx5_mode == mlx5_mode)
goto unlock; goto unlock;
if (esw->offloads.num_block_mode) {
NL_SET_ERR_MSG_MOD(extack,
"Can't change eswitch mode when IPsec SA and/or policies are configured");
err = -EOPNOTSUPP;
goto unlock;
}
mlx5_eswitch_disable_locked(esw); mlx5_eswitch_disable_locked(esw);
if (mode == DEVLINK_ESWITCH_MODE_SWITCHDEV) { if (mode == DEVLINK_ESWITCH_MODE_SWITCHDEV) {
if (mlx5_devlink_trap_get_num_active(esw->dev)) { if (mlx5_devlink_trap_get_num_active(esw->dev)) {
...@@ -4293,3 +4445,19 @@ int mlx5_devlink_port_fn_roce_set(struct devlink_port *port, bool enable, ...@@ -4293,3 +4445,19 @@ int mlx5_devlink_port_fn_roce_set(struct devlink_port *port, bool enable,
mutex_unlock(&esw->state_lock); mutex_unlock(&esw->state_lock);
return err; return err;
} }
int
mlx5_eswitch_restore_ipsec_rule(struct mlx5_eswitch *esw, struct mlx5_flow_handle *rule,
struct mlx5_esw_flow_attr *esw_attr, int attr_idx)
{
struct mlx5_flow_destination new_dest = {};
struct mlx5_flow_destination old_dest = {};
if (!esw_setup_uplink_fwd_ipsec_needed(esw, esw_attr, attr_idx))
return 0;
esw_setup_dest_fwd_ipsec(&old_dest, NULL, esw, esw_attr, attr_idx, 0, false);
esw_setup_dest_fwd_vport(&new_dest, NULL, esw, esw_attr, attr_idx, 0, false);
return mlx5_modify_rule_destination(rule, &new_dest, &old_dest);
}
...@@ -1066,7 +1066,7 @@ int mlx5_modify_rule_destination(struct mlx5_flow_handle *handle, ...@@ -1066,7 +1066,7 @@ int mlx5_modify_rule_destination(struct mlx5_flow_handle *handle,
} }
for (i = 0; i < handle->num_rules; i++) { for (i = 0; i < handle->num_rules; i++) {
if (mlx5_flow_dests_cmp(new_dest, &handle->rule[i]->dest_attr)) if (mlx5_flow_dests_cmp(old_dest, &handle->rule[i]->dest_attr))
return _mlx5_modify_rule_destination(handle->rule[i], return _mlx5_modify_rule_destination(handle->rule[i],
new_dest); new_dest);
} }
...@@ -2987,6 +2987,12 @@ static int init_fdb_root_ns(struct mlx5_flow_steering *steering) ...@@ -2987,6 +2987,12 @@ static int init_fdb_root_ns(struct mlx5_flow_steering *steering)
if (err) if (err)
goto out_err; goto out_err;
maj_prio = fs_create_prio(&steering->fdb_root_ns->ns, FDB_CRYPTO_INGRESS, 3);
if (IS_ERR(maj_prio)) {
err = PTR_ERR(maj_prio);
goto out_err;
}
err = create_fdb_fast_path(steering); err = create_fdb_fast_path(steering);
if (err) if (err)
goto out_err; goto out_err;
...@@ -3009,6 +3015,12 @@ static int init_fdb_root_ns(struct mlx5_flow_steering *steering) ...@@ -3009,6 +3015,12 @@ static int init_fdb_root_ns(struct mlx5_flow_steering *steering)
goto out_err; goto out_err;
} }
maj_prio = fs_create_prio(&steering->fdb_root_ns->ns, FDB_CRYPTO_EGRESS, 3);
if (IS_ERR(maj_prio)) {
err = PTR_ERR(maj_prio);
goto out_err;
}
/* We put this priority last, knowing that nothing will get here /* We put this priority last, knowing that nothing will get here
* unless explicitly forwarded to. This is possible because the * unless explicitly forwarded to. This is possible because the
* slow path tables have catch all rules and nothing gets passed * slow path tables have catch all rules and nothing gets passed
......
...@@ -806,6 +806,8 @@ struct mlx5_core_dev { ...@@ -806,6 +806,8 @@ struct mlx5_core_dev {
u32 vsc_addr; u32 vsc_addr;
struct mlx5_hv_vhca *hv_vhca; struct mlx5_hv_vhca *hv_vhca;
struct mlx5_thermal *thermal; struct mlx5_thermal *thermal;
u64 num_block_tc;
u64 num_block_ipsec;
}; };
struct mlx5_db { struct mlx5_db {
......
...@@ -144,6 +144,9 @@ u32 mlx5_eswitch_get_vport_metadata_for_set(struct mlx5_eswitch *esw, ...@@ -144,6 +144,9 @@ u32 mlx5_eswitch_get_vport_metadata_for_set(struct mlx5_eswitch *esw,
GENMASK(31 - ESW_TUN_ID_BITS - ESW_RESERVED_BITS, \ GENMASK(31 - ESW_TUN_ID_BITS - ESW_RESERVED_BITS, \
ESW_TUN_OPTS_OFFSET + 1) ESW_TUN_OPTS_OFFSET + 1)
/* reuse tun_opts for the mapped ipsec obj id when tun_id is 0 (invalid) */
#define ESW_IPSEC_RX_MAPPED_ID_MASK GENMASK(ESW_TUN_OPTS_BITS - 1, 0)
u8 mlx5_eswitch_mode(const struct mlx5_core_dev *dev); u8 mlx5_eswitch_mode(const struct mlx5_core_dev *dev);
u16 mlx5_eswitch_get_total_vports(const struct mlx5_core_dev *dev); u16 mlx5_eswitch_get_total_vports(const struct mlx5_core_dev *dev);
struct mlx5_core_dev *mlx5_eswitch_get_core_dev(struct mlx5_eswitch *esw); struct mlx5_core_dev *mlx5_eswitch_get_core_dev(struct mlx5_eswitch *esw);
......
...@@ -109,11 +109,13 @@ enum mlx5_flow_namespace_type { ...@@ -109,11 +109,13 @@ enum mlx5_flow_namespace_type {
enum { enum {
FDB_BYPASS_PATH, FDB_BYPASS_PATH,
FDB_CRYPTO_INGRESS,
FDB_TC_OFFLOAD, FDB_TC_OFFLOAD,
FDB_FT_OFFLOAD, FDB_FT_OFFLOAD,
FDB_TC_MISS, FDB_TC_MISS,
FDB_BR_OFFLOAD, FDB_BR_OFFLOAD,
FDB_SLOW_PATH, FDB_SLOW_PATH,
FDB_CRYPTO_EGRESS,
FDB_PER_VPORT, FDB_PER_VPORT,
}; };
......
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