Commit 802c2125 authored by Aviad Yehezkel's avatar Aviad Yehezkel Committed by Jason Gunthorpe

IB/mlx5: Add IPsec support for egress and ingress

This commit introduces support for the esp_aes_gcm flow
specification for the Innova device. To that end we add
support for egress steering and some validations that an
IPsec rule is indeed valid.
Signed-off-by: default avatarMatan Barak <matanb@mellanox.com>
Signed-off-by: default avatarAviad Yehezkel <aviadye@mellanox.com>
Signed-off-by: default avatarLeon Romanovsky <leonro@mellanox.com>
Signed-off-by: default avatarJason Gunthorpe <jgg@mellanox.com>
parent 363c5a57
...@@ -51,6 +51,7 @@ ...@@ -51,6 +51,7 @@
#include <linux/mlx5/port.h> #include <linux/mlx5/port.h>
#include <linux/mlx5/vport.h> #include <linux/mlx5/vport.h>
#include <linux/mlx5/fs.h> #include <linux/mlx5/fs.h>
#include <linux/mlx5/fs_helpers.h>
#include <linux/list.h> #include <linux/list.h>
#include <rdma/ib_smi.h> #include <rdma/ib_smi.h>
#include <rdma/ib_umem.h> #include <rdma/ib_umem.h>
...@@ -2321,8 +2322,28 @@ static void set_tos(void *outer_c, void *outer_v, u8 mask, u8 val) ...@@ -2321,8 +2322,28 @@ static void set_tos(void *outer_c, void *outer_v, u8 mask, u8 val)
offsetof(typeof(filter), field) -\ offsetof(typeof(filter), field) -\
sizeof(filter.field)) sizeof(filter.field))
static int parse_flow_flow_action(const union ib_flow_spec *ib_spec,
const struct ib_flow_attr *flow_attr,
struct mlx5_flow_act *action)
{
struct mlx5_ib_flow_action *maction = to_mflow_act(ib_spec->action.act);
switch (maction->ib_action.type) {
case IB_FLOW_ACTION_ESP:
/* Currently only AES_GCM keymat is supported by the driver */
action->esp_id = (uintptr_t)maction->esp_aes_gcm.ctx;
action->action |= flow_attr->flags & IB_FLOW_ATTR_FLAGS_EGRESS ?
MLX5_FLOW_CONTEXT_ACTION_ENCRYPT :
MLX5_FLOW_CONTEXT_ACTION_DECRYPT;
return 0;
default:
return -EOPNOTSUPP;
}
}
static int parse_flow_attr(struct mlx5_core_dev *mdev, u32 *match_c, static int parse_flow_attr(struct mlx5_core_dev *mdev, u32 *match_c,
u32 *match_v, const union ib_flow_spec *ib_spec, u32 *match_v, const union ib_flow_spec *ib_spec,
const struct ib_flow_attr *flow_attr,
struct mlx5_flow_act *action) struct mlx5_flow_act *action)
{ {
void *misc_params_c = MLX5_ADDR_OF(fte_match_param, match_c, void *misc_params_c = MLX5_ADDR_OF(fte_match_param, match_c,
...@@ -2332,6 +2353,7 @@ static int parse_flow_attr(struct mlx5_core_dev *mdev, u32 *match_c, ...@@ -2332,6 +2353,7 @@ static int parse_flow_attr(struct mlx5_core_dev *mdev, u32 *match_c,
void *headers_c; void *headers_c;
void *headers_v; void *headers_v;
int match_ipv; int match_ipv;
int ret;
if (ib_spec->type & IB_FLOW_SPEC_INNER) { if (ib_spec->type & IB_FLOW_SPEC_INNER) {
headers_c = MLX5_ADDR_OF(fte_match_param, match_c, headers_c = MLX5_ADDR_OF(fte_match_param, match_c,
...@@ -2482,7 +2504,15 @@ static int parse_flow_attr(struct mlx5_core_dev *mdev, u32 *match_c, ...@@ -2482,7 +2504,15 @@ static int parse_flow_attr(struct mlx5_core_dev *mdev, u32 *match_c,
ntohl(ib_spec->ipv6.mask.flow_label), ntohl(ib_spec->ipv6.mask.flow_label),
ntohl(ib_spec->ipv6.val.flow_label), ntohl(ib_spec->ipv6.val.flow_label),
ib_spec->type & IB_FLOW_SPEC_INNER); ib_spec->type & IB_FLOW_SPEC_INNER);
break;
case IB_FLOW_SPEC_ESP:
if (ib_spec->esp.mask.seq)
return -EOPNOTSUPP;
MLX5_SET(fte_match_set_misc, misc_params_c, outer_esp_spi,
ntohl(ib_spec->esp.mask.spi));
MLX5_SET(fte_match_set_misc, misc_params_v, outer_esp_spi,
ntohl(ib_spec->esp.val.spi));
break; break;
case IB_FLOW_SPEC_TCP: case IB_FLOW_SPEC_TCP:
if (FIELDS_NOT_SUPPORTED(ib_spec->tcp_udp.mask, if (FIELDS_NOT_SUPPORTED(ib_spec->tcp_udp.mask,
...@@ -2550,6 +2580,11 @@ static int parse_flow_attr(struct mlx5_core_dev *mdev, u32 *match_c, ...@@ -2550,6 +2580,11 @@ static int parse_flow_attr(struct mlx5_core_dev *mdev, u32 *match_c,
return -EOPNOTSUPP; return -EOPNOTSUPP;
action->action |= MLX5_FLOW_CONTEXT_ACTION_DROP; action->action |= MLX5_FLOW_CONTEXT_ACTION_DROP;
break; break;
case IB_FLOW_SPEC_ACTION_HANDLE:
ret = parse_flow_flow_action(ib_spec, flow_attr, action);
if (ret)
return ret;
break;
default: default:
return -EINVAL; return -EINVAL;
} }
...@@ -2591,6 +2626,46 @@ static bool flow_is_multicast_only(const struct ib_flow_attr *ib_attr) ...@@ -2591,6 +2626,46 @@ static bool flow_is_multicast_only(const struct ib_flow_attr *ib_attr)
return false; return false;
} }
enum valid_spec {
VALID_SPEC_INVALID,
VALID_SPEC_VALID,
VALID_SPEC_NA,
};
static enum valid_spec
is_valid_esp_aes_gcm(struct mlx5_core_dev *mdev,
const struct mlx5_flow_spec *spec,
const struct mlx5_flow_act *flow_act,
bool egress)
{
const u32 *match_c = spec->match_criteria;
bool is_crypto =
(flow_act->action & (MLX5_FLOW_CONTEXT_ACTION_ENCRYPT |
MLX5_FLOW_CONTEXT_ACTION_DECRYPT));
bool is_ipsec = mlx5_fs_is_ipsec_flow(match_c);
bool is_drop = flow_act->action & MLX5_FLOW_CONTEXT_ACTION_DROP;
/*
* Currently only crypto is supported in egress, when regular egress
* rules would be supported, always return VALID_SPEC_NA.
*/
if (!is_crypto)
return egress ? VALID_SPEC_INVALID : VALID_SPEC_NA;
return is_crypto && is_ipsec &&
(!egress || (!is_drop && !flow_act->has_flow_tag)) ?
VALID_SPEC_VALID : VALID_SPEC_INVALID;
}
static bool is_valid_spec(struct mlx5_core_dev *mdev,
const struct mlx5_flow_spec *spec,
const struct mlx5_flow_act *flow_act,
bool egress)
{
/* We curretly only support ipsec egress flow */
return is_valid_esp_aes_gcm(mdev, spec, flow_act, egress) != VALID_SPEC_INVALID;
}
static bool is_valid_ethertype(struct mlx5_core_dev *mdev, static bool is_valid_ethertype(struct mlx5_core_dev *mdev,
const struct ib_flow_attr *flow_attr, const struct ib_flow_attr *flow_attr,
bool check_inner) bool check_inner)
...@@ -2715,13 +2790,17 @@ static struct mlx5_ib_flow_prio *get_flow_table(struct mlx5_ib_dev *dev, ...@@ -2715,13 +2790,17 @@ static struct mlx5_ib_flow_prio *get_flow_table(struct mlx5_ib_dev *dev,
max_table_size = BIT(MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev, max_table_size = BIT(MLX5_CAP_FLOWTABLE_NIC_RX(dev->mdev,
log_max_ft_size)); log_max_ft_size));
if (flow_attr->type == IB_FLOW_ATTR_NORMAL) { if (flow_attr->type == IB_FLOW_ATTR_NORMAL) {
if (flow_is_multicast_only(flow_attr) && if (ft_type == MLX5_IB_FT_TX)
!dont_trap) priority = 0;
else if (flow_is_multicast_only(flow_attr) &&
!dont_trap)
priority = MLX5_IB_FLOW_MCAST_PRIO; priority = MLX5_IB_FLOW_MCAST_PRIO;
else else
priority = ib_prio_to_core_prio(flow_attr->priority, priority = ib_prio_to_core_prio(flow_attr->priority,
dont_trap); dont_trap);
ns = mlx5_get_flow_namespace(dev->mdev, ns = mlx5_get_flow_namespace(dev->mdev,
ft_type == MLX5_IB_FT_TX ?
MLX5_FLOW_NAMESPACE_EGRESS :
MLX5_FLOW_NAMESPACE_BYPASS); MLX5_FLOW_NAMESPACE_BYPASS);
num_entries = MLX5_FS_MAX_ENTRIES; num_entries = MLX5_FS_MAX_ENTRIES;
num_groups = MLX5_FS_MAX_TYPES; num_groups = MLX5_FS_MAX_TYPES;
...@@ -2808,6 +2887,7 @@ static struct mlx5_ib_flow_handler *_create_flow_rule(struct mlx5_ib_dev *dev, ...@@ -2808,6 +2887,7 @@ static struct mlx5_ib_flow_handler *_create_flow_rule(struct mlx5_ib_dev *dev,
unsigned int spec_index; unsigned int spec_index;
int err = 0; int err = 0;
int dest_num = 1; int dest_num = 1;
bool is_egress = flow_attr->flags & IB_FLOW_ATTR_FLAGS_EGRESS;
if (!is_valid_attr(dev->mdev, flow_attr)) if (!is_valid_attr(dev->mdev, flow_attr))
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
...@@ -2824,7 +2904,7 @@ static struct mlx5_ib_flow_handler *_create_flow_rule(struct mlx5_ib_dev *dev, ...@@ -2824,7 +2904,7 @@ static struct mlx5_ib_flow_handler *_create_flow_rule(struct mlx5_ib_dev *dev,
for (spec_index = 0; spec_index < flow_attr->num_of_specs; spec_index++) { for (spec_index = 0; spec_index < flow_attr->num_of_specs; spec_index++) {
err = parse_flow_attr(dev->mdev, spec->match_criteria, err = parse_flow_attr(dev->mdev, spec->match_criteria,
spec->match_value, spec->match_value,
ib_flow, &flow_act); ib_flow, flow_attr, &flow_act);
if (err < 0) if (err < 0)
goto free; goto free;
...@@ -2847,12 +2927,23 @@ static struct mlx5_ib_flow_handler *_create_flow_rule(struct mlx5_ib_dev *dev, ...@@ -2847,12 +2927,23 @@ static struct mlx5_ib_flow_handler *_create_flow_rule(struct mlx5_ib_dev *dev,
} }
spec->match_criteria_enable = get_match_criteria_enable(spec->match_criteria); spec->match_criteria_enable = get_match_criteria_enable(spec->match_criteria);
if (is_egress &&
!is_valid_spec(dev->mdev, spec, &flow_act, is_egress)) {
err = -EINVAL;
goto free;
}
if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_DROP) { if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_DROP) {
rule_dst = NULL; rule_dst = NULL;
dest_num = 0; dest_num = 0;
} else { } else {
flow_act.action = dst ? MLX5_FLOW_CONTEXT_ACTION_FWD_DEST : if (is_egress)
MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_PRIO; flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_ALLOW;
else
flow_act.action |=
dst ? MLX5_FLOW_CONTEXT_ACTION_FWD_DEST :
MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_PRIO;
} }
if (flow_act.has_flow_tag && if (flow_act.has_flow_tag &&
...@@ -3026,6 +3117,7 @@ static struct ib_flow *mlx5_ib_create_flow(struct ib_qp *qp, ...@@ -3026,6 +3117,7 @@ static struct ib_flow *mlx5_ib_create_flow(struct ib_qp *qp,
struct mlx5_flow_destination *dst = NULL; struct mlx5_flow_destination *dst = NULL;
struct mlx5_ib_flow_prio *ft_prio_tx = NULL; struct mlx5_ib_flow_prio *ft_prio_tx = NULL;
struct mlx5_ib_flow_prio *ft_prio; struct mlx5_ib_flow_prio *ft_prio;
bool is_egress = flow_attr->flags & IB_FLOW_ATTR_FLAGS_EGRESS;
int err; int err;
int underlay_qpn; int underlay_qpn;
...@@ -3034,7 +3126,13 @@ static struct ib_flow *mlx5_ib_create_flow(struct ib_qp *qp, ...@@ -3034,7 +3126,13 @@ static struct ib_flow *mlx5_ib_create_flow(struct ib_qp *qp,
if (domain != IB_FLOW_DOMAIN_USER || if (domain != IB_FLOW_DOMAIN_USER ||
flow_attr->port > dev->num_ports || flow_attr->port > dev->num_ports ||
(flow_attr->flags & ~IB_FLOW_ATTR_FLAGS_DONT_TRAP)) (flow_attr->flags & ~(IB_FLOW_ATTR_FLAGS_DONT_TRAP |
IB_FLOW_ATTR_FLAGS_EGRESS)))
return ERR_PTR(-EINVAL);
if (is_egress &&
(flow_attr->type == IB_FLOW_ATTR_ALL_DEFAULT ||
flow_attr->type == IB_FLOW_ATTR_MC_DEFAULT))
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
dst = kzalloc(sizeof(*dst), GFP_KERNEL); dst = kzalloc(sizeof(*dst), GFP_KERNEL);
...@@ -3043,7 +3141,8 @@ static struct ib_flow *mlx5_ib_create_flow(struct ib_qp *qp, ...@@ -3043,7 +3141,8 @@ static struct ib_flow *mlx5_ib_create_flow(struct ib_qp *qp,
mutex_lock(&dev->flow_db->lock); mutex_lock(&dev->flow_db->lock);
ft_prio = get_flow_table(dev, flow_attr, MLX5_IB_FT_RX); ft_prio = get_flow_table(dev, flow_attr,
is_egress ? MLX5_IB_FT_TX : MLX5_IB_FT_RX);
if (IS_ERR(ft_prio)) { if (IS_ERR(ft_prio)) {
err = PTR_ERR(ft_prio); err = PTR_ERR(ft_prio);
goto unlock; goto unlock;
...@@ -3057,11 +3156,15 @@ static struct ib_flow *mlx5_ib_create_flow(struct ib_qp *qp, ...@@ -3057,11 +3156,15 @@ static struct ib_flow *mlx5_ib_create_flow(struct ib_qp *qp,
} }
} }
dst->type = MLX5_FLOW_DESTINATION_TYPE_TIR; if (is_egress) {
if (mqp->flags & MLX5_IB_QP_RSS) dst->type = MLX5_FLOW_DESTINATION_TYPE_PORT;
dst->tir_num = mqp->rss_qp.tirn; } else {
else dst->type = MLX5_FLOW_DESTINATION_TYPE_TIR;
dst->tir_num = mqp->raw_packet_qp.rq.tirn; if (mqp->flags & MLX5_IB_QP_RSS)
dst->tir_num = mqp->rss_qp.tirn;
else
dst->tir_num = mqp->raw_packet_qp.rq.tirn;
}
if (flow_attr->type == IB_FLOW_ATTR_NORMAL) { if (flow_attr->type == IB_FLOW_ATTR_NORMAL) {
if (flow_attr->flags & IB_FLOW_ATTR_FLAGS_DONT_TRAP) { if (flow_attr->flags & IB_FLOW_ATTR_FLAGS_DONT_TRAP) {
......
...@@ -152,6 +152,7 @@ struct mlx5_ib_pd { ...@@ -152,6 +152,7 @@ struct mlx5_ib_pd {
#define MLX5_IB_NUM_FLOW_FT (MLX5_IB_FLOW_LEFTOVERS_PRIO + 1) #define MLX5_IB_NUM_FLOW_FT (MLX5_IB_FLOW_LEFTOVERS_PRIO + 1)
#define MLX5_IB_NUM_SNIFFER_FTS 2 #define MLX5_IB_NUM_SNIFFER_FTS 2
#define MLX5_IB_NUM_EGRESS_FTS 1
struct mlx5_ib_flow_prio { struct mlx5_ib_flow_prio {
struct mlx5_flow_table *flow_table; struct mlx5_flow_table *flow_table;
unsigned int refcount; unsigned int refcount;
...@@ -167,6 +168,7 @@ struct mlx5_ib_flow_handler { ...@@ -167,6 +168,7 @@ struct mlx5_ib_flow_handler {
struct mlx5_ib_flow_db { struct mlx5_ib_flow_db {
struct mlx5_ib_flow_prio prios[MLX5_IB_NUM_FLOW_FT]; struct mlx5_ib_flow_prio prios[MLX5_IB_NUM_FLOW_FT];
struct mlx5_ib_flow_prio sniffer[MLX5_IB_NUM_SNIFFER_FTS]; struct mlx5_ib_flow_prio sniffer[MLX5_IB_NUM_SNIFFER_FTS];
struct mlx5_ib_flow_prio egress[MLX5_IB_NUM_EGRESS_FTS];
struct mlx5_flow_table *lag_demux_ft; struct mlx5_flow_table *lag_demux_ft;
/* Protect flow steering bypass flow tables /* Protect flow steering bypass flow tables
* when add/del flow rules. * when add/del flow rules.
......
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