[dpdk-dev] [PATCH v1 6/7] net/mlx5: support security flow action
Nelio Laranjeiro
nelio.laranjeiro at 6wind.com
Thu Nov 23 17:13:08 CET 2017
From: Shahaf Shuler <shahafs at mellanox.com>
Signed-off-by: Shahaf Shuler <shahafs at mellanox.com>
Signed-off-by: Aviad Yehezkel <aviadye at mellanox.com>
Signed-off-by: Matan Barak <matanb at mellanox.com>
Signed-off-by: Nelio Laranjeiro <nelio.laranjeiro at 6wind.com>
---
drivers/net/mlx5/mlx5.h | 7 +
drivers/net/mlx5/mlx5_flow.c | 309 ++++++++++++++++++++++++++++++++++++++----
drivers/net/mlx5/mlx5_ipsec.c | 10 +-
3 files changed, 289 insertions(+), 37 deletions(-)
diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index 2927b851b..cb25beb3c 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -154,6 +154,13 @@ struct priv {
struct rte_security_ctx security; /* Security context. */
};
+/* Security session. */
+struct mlx5_security_session {
+ struct rte_security_ipsec_xform ipsec_xform;
+ struct rte_eth_dev *dev;
+ struct ibv_action_xfrm *ibv_action_xfrm;
+};
+
/**
* Lock private structure to protect it from concurrent access in the
* control path.
diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index ff50470b5..704c47820 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -78,6 +78,20 @@ ibv_destroy_counter_set(struct ibv_counter_set *cs)
}
#endif
+#ifndef HAVE_IBV_IPSEC_SUPPORT
+/* Define dummy structure when IPsec is not available in Verbs. */
+
+/* Dummy spec ESP defined when missing in Verbs. */
+struct ibv_flow_spec_esp {
+ int dummy;
+};
+
+/* Dummy transform action defined when missing in Verbs. */
+struct ibv_flow_spec_action_xfrm {
+ int dummy;
+};
+#endif
+
/* Dev ops structure defined in mlx5.c */
extern const struct eth_dev_ops mlx5_dev_ops;
extern const struct eth_dev_ops mlx5_dev_ops_isolate;
@@ -129,6 +143,14 @@ mlx5_flow_create_flag_mark(struct mlx5_flow_parse *parser, uint32_t mark_id);
static int
mlx5_flow_create_count(struct priv *priv, struct mlx5_flow_parse *parser);
+static int
+mlx5_flow_create_esp(const struct rte_flow_item *item,
+ const void *default_mask,
+ void *data);
+
+static void
+mlx5_flow_create_xfrm(struct mlx5_flow_parse *parser);
+
/* Hash RX queue types. */
enum hash_rxq_type {
HASH_RXQ_TCPV4,
@@ -244,6 +266,8 @@ struct rte_flow {
TAILQ_ENTRY(rte_flow) next; /**< Pointer to the next flow structure. */
uint32_t mark:1; /**< Set if the flow is marked. */
uint32_t drop:1; /**< Drop queue. */
+ uint32_t security:1; /**< Security flow. */
+ uint32_t ingress:1; /**< Ingress flow. */
uint16_t queues_n; /**< Number of entries in queue[]. */
uint16_t (*queues)[]; /**< Queues indexes to use. */
struct rte_eth_rss_conf rss_conf; /**< RSS configuration */
@@ -305,6 +329,7 @@ static const enum rte_flow_action_type valid_actions[] = {
#ifdef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT
RTE_FLOW_ACTION_TYPE_COUNT,
#endif
+ RTE_FLOW_ACTION_TYPE_SECURITY,
RTE_FLOW_ACTION_TYPE_END,
};
@@ -343,7 +368,8 @@ static const struct mlx5_flow_items mlx5_flow_items[] = {
},
[RTE_FLOW_ITEM_TYPE_IPV4] = {
.items = ITEMS(RTE_FLOW_ITEM_TYPE_UDP,
- RTE_FLOW_ITEM_TYPE_TCP),
+ RTE_FLOW_ITEM_TYPE_TCP,
+ RTE_FLOW_ITEM_TYPE_ESP),
.actions = valid_actions,
.mask = &(const struct rte_flow_item_ipv4){
.hdr = {
@@ -360,7 +386,8 @@ static const struct mlx5_flow_items mlx5_flow_items[] = {
},
[RTE_FLOW_ITEM_TYPE_IPV6] = {
.items = ITEMS(RTE_FLOW_ITEM_TYPE_UDP,
- RTE_FLOW_ITEM_TYPE_TCP),
+ RTE_FLOW_ITEM_TYPE_TCP,
+ RTE_FLOW_ITEM_TYPE_ESP),
.actions = valid_actions,
.mask = &(const struct rte_flow_item_ipv6){
.hdr = {
@@ -424,6 +451,17 @@ static const struct mlx5_flow_items mlx5_flow_items[] = {
.convert = mlx5_flow_create_vxlan,
.dst_sz = sizeof(struct ibv_flow_spec_tunnel),
},
+ [RTE_FLOW_ITEM_TYPE_ESP] = {
+ .actions = valid_actions,
+ .mask = &(const struct rte_flow_item_esp){
+ .hdr = {
+ .spi = 0xffffffff,
+ }
+ },
+ .mask_sz = sizeof(struct rte_flow_item_esp),
+ .convert = mlx5_flow_create_esp,
+ .dst_sz = sizeof(struct ibv_flow_spec_esp),
+ },
};
/** Structure to pass to the conversion function. */
@@ -434,6 +472,7 @@ struct mlx5_flow_parse {
uint32_t drop:1; /**< Target is a drop queue. */
uint32_t mark:1; /**< Mark is present in the flow. */
uint32_t count:1; /**< Count is present in the flow. */
+ uint32_t ingress:1; /** Flow is for ingress. */
uint32_t mark_id; /**< Mark identifier. */
uint16_t queues[RTE_MAX_QUEUES_PER_PORT]; /**< Queues indexes to use. */
uint16_t queues_n; /**< Number of entries in queue[]. */
@@ -441,6 +480,7 @@ struct mlx5_flow_parse {
uint8_t rss_key[40]; /**< copy of the RSS key. */
enum hash_rxq_type layer; /**< Last pattern layer detected. */
struct ibv_counter_set *cs; /**< Holds the counter set for the rule */
+ const struct mlx5_security_session *security; /**< Security session */
struct {
struct ibv_flow_attr *ibv_attr;
/**< Pointer to Verbs attributes. */
@@ -601,7 +641,6 @@ priv_flow_convert_attributes(struct priv *priv,
struct mlx5_flow_parse *parser)
{
(void)priv;
- (void)parser;
if (attr->group) {
rte_flow_error_set(error, ENOTSUP,
RTE_FLOW_ERROR_TYPE_ATTR_GROUP,
@@ -616,20 +655,28 @@ priv_flow_convert_attributes(struct priv *priv,
"priorities are not supported");
return -rte_errno;
}
- if (attr->egress) {
+ if (attr->egress && attr->ingress) {
rte_flow_error_set(error, ENOTSUP,
RTE_FLOW_ERROR_TYPE_ATTR_EGRESS,
NULL,
- "egress is not supported");
+ "egress with ingress is not supported");
return -rte_errno;
}
- if (!attr->ingress) {
+ if (attr->ingress && attr->egress) {
rte_flow_error_set(error, ENOTSUP,
RTE_FLOW_ERROR_TYPE_ATTR_INGRESS,
NULL,
- "only ingress is supported");
+ "ingress with egress is supported");
+ return -rte_errno;
+ }
+ if (!(attr->ingress ^ attr->egress)) {
+ rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ATTR,
+ NULL,
+ "Missing Ingress of Egress");
return -rte_errno;
}
+ parser->ingress = attr->ingress;
return 0;
}
@@ -649,10 +696,10 @@ priv_flow_convert_attributes(struct priv *priv,
* 0 on success, a negative errno value otherwise and rte_errno is set.
*/
static int
-priv_flow_convert_actions(struct priv *priv,
- const struct rte_flow_action actions[],
- struct rte_flow_error *error,
- struct mlx5_flow_parse *parser)
+priv_flow_convert_actions_ingress(struct priv *priv,
+ const struct rte_flow_action actions[],
+ struct rte_flow_error *error,
+ struct mlx5_flow_parse *parser)
{
int ret = 0;
const char *msg = NULL;
@@ -760,6 +807,27 @@ priv_flow_convert_actions(struct priv *priv,
}
parser->mark = 1;
parser->mark_id = mark->id;
+ } else if (actions->type == RTE_FLOW_ACTION_TYPE_SECURITY) {
+ if (!actions->conf) {
+ ret = EINVAL;
+ msg = "invalid security configuration";
+ action = actions;
+ goto error;
+ }
+ parser->security =
+ get_sec_session_private_data(actions->conf);
+ if (!parser->security) {
+ ret = EINVAL;
+ msg = "invalid security configuration";
+ action = actions;
+ goto error;
+ }
+ if (!priv->ipsec_en) {
+ ret = ENOTSUP;
+ msg = "action not supported";
+ action = actions;
+ goto error;
+ }
} else if (actions->type == RTE_FLOW_ACTION_TYPE_FLAG) {
parser->mark = 1;
} else if (actions->type == RTE_FLOW_ACTION_TYPE_COUNT &&
@@ -785,6 +853,84 @@ priv_flow_convert_actions(struct priv *priv,
}
/**
+ * Extract actions request to the parser.
+ *
+ * @param priv
+ * Pointer to private structure.
+ * @param[in] actions
+ * Associated actions (list terminated by the END action).
+ * @param[out] error
+ * Perform verbose error reporting if not NULL.
+ * @param[in, out] parser
+ * Internal parser structure.
+ *
+ * @return
+ * 0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+priv_flow_convert_actions_egress(struct priv *priv,
+ const struct rte_flow_action actions[],
+ struct rte_flow_error *error,
+ struct mlx5_flow_parse *parser)
+{
+ int ret;
+ const char *msg;
+ const struct rte_flow_action *action;
+
+ /*
+ * Add default RSS configuration necessary for Verbs to create QP even
+ * if no RSS is necessary.
+ */
+ priv_flow_convert_rss_conf(priv, parser,
+ (const struct rte_eth_rss_conf *)
+ &priv->rss_conf);
+ for (; actions->type != RTE_FLOW_ACTION_TYPE_END; ++actions) {
+ if (actions->type == RTE_FLOW_ACTION_TYPE_VOID) {
+ continue;
+ } else if (actions->type == RTE_FLOW_ACTION_TYPE_SECURITY) {
+ if (!actions->conf) {
+ ret = EINVAL;
+ msg = "invalid security configuration";
+ action = actions;
+ goto error;
+ }
+ parser->security =
+ get_sec_session_private_data(actions->conf);
+ if (!parser->security) {
+ ret = EINVAL;
+ msg = "invalid security configuration";
+ action = actions;
+ goto error;
+ }
+ if (!priv->ipsec_en) {
+ ret = ENOTSUP;
+ msg = "action not supported";
+ action = actions;
+ goto error;
+ }
+ } else {
+ ret = ENOTSUP;
+ msg = "action not supported";
+ action = actions;
+ goto error;
+ }
+ }
+ if (parser->drop) {
+ ret = EINVAL;
+ msg = "dropping in egress is not invalid";
+ action = NULL;
+ goto error;
+ }
+ return 0;
+error:
+ rte_flow_error_set(error, ret,
+ action ? RTE_FLOW_ERROR_TYPE_ACTION :
+ RTE_FLOW_ERROR_TYPE_HANDLE,
+ action, msg);
+ return -rte_errno;
+}
+
+/**
* Validate items.
*
* @param priv
@@ -847,7 +993,7 @@ priv_flow_convert_items_validate(struct priv *priv,
}
parser->inner = IBV_FLOW_SPEC_INNER;
}
- if (parser->drop || parser->queues_n == 1) {
+ if (parser->drop || !parser->ingress || parser->queues_n == 1) {
parser->queue[HASH_RXQ_ETH].offset += cur_item->dst_sz;
} else {
for (n = 0; n != hash_rxq_init_n; ++n)
@@ -865,6 +1011,16 @@ priv_flow_convert_items_validate(struct priv *priv,
for (i = 0; i != hash_rxq_init_n; ++i)
parser->queue[i].offset += size;
}
+ if (parser->security) {
+ unsigned int size = sizeof(struct ibv_flow_spec_action_xfrm);
+
+ if (parser->drop || !parser->ingress) {
+ parser->queue[HASH_RXQ_ETH].offset += size;
+ } else {
+ for (i = 0; i != hash_rxq_init_n; ++i)
+ parser->queue[i].offset += size;
+ }
+ }
return 0;
exit_item_not_supported:
rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM,
@@ -1064,7 +1220,12 @@ priv_flow_convert(struct priv *priv,
ret = priv_flow_convert_attributes(priv, attr, error, parser);
if (ret)
return ret;
- ret = priv_flow_convert_actions(priv, actions, error, parser);
+ if (attr->ingress)
+ ret = priv_flow_convert_actions_ingress(priv, actions, error,
+ parser);
+ else
+ ret = priv_flow_convert_actions_egress(priv, actions, error,
+ parser);
if (ret)
return ret;
ret = priv_flow_convert_items_validate(priv, items, error, parser);
@@ -1075,7 +1236,7 @@ priv_flow_convert(struct priv *priv,
* Second step.
* Allocate the memory space to store verbs specifications.
*/
- if (parser->drop || parser->queues_n == 1) {
+ if (parser->drop || parser->queues_n == 1 || !parser->ingress) {
unsigned int priority =
attr->priority +
hash_rxq_init[HASH_RXQ_ETH].flow_priority;
@@ -1133,6 +1294,8 @@ priv_flow_convert(struct priv *priv,
if (!parser->cs)
goto exit_count_error;
}
+ if (parser->security)
+ mlx5_flow_create_xfrm(parser);
/*
* Last step. Complete missing specification to reach the RSS
* configuration.
@@ -1611,6 +1774,73 @@ mlx5_flow_create_count(struct priv *priv __rte_unused,
}
/**
+ * Convert ESP Item to Verbs specification.
+ *
+ * @param item[in]
+ * Item specification.
+ * @param default_mask[in]
+ * Default bit-masks to use when item->mask is not provided.
+ * @param data[in, out]
+ * User structure.
+ *
+ * @return
+ * 0 on success, errno value on failure.
+ */
+static int
+mlx5_flow_create_esp(const struct rte_flow_item *item __rte_unused,
+ const void *default_mask __rte_unused,
+ void *data __rte_unused)
+{
+ int ret = ENOTSUP;
+#ifdef HAVE_IBV_IPSEC_SUPPORT
+ const struct rte_flow_item_esp *spec = item->spec;
+ const struct rte_flow_item_esp *mask = item->mask;
+ struct mlx5_flow_parse *parser = (struct mlx5_flow_parse *)data;
+ unsigned int size = sizeof(struct ibv_flow_spec_esp);
+ struct ibv_flow_spec_esp esp = {
+ .type = parser->inner | IBV_FLOW_SPEC_ESP,
+ .size = size,
+ };
+
+ ret = 0;
+ if (spec) {
+ if (!mask)
+ mask = default_mask;
+ esp.val.spi = htonl(spec->hdr.spi);
+ esp.val.seq = htonl(spec->hdr.seq);
+ esp.mask.spi = htonl(mask->hdr.spi);
+ esp.mask.seq = htonl(mask->hdr.seq);
+ esp.val.spi &= esp.mask.spi;
+ esp.val.seq &= esp.mask.seq;
+ }
+ mlx5_flow_create_copy(parser, &esp, size);
+#endif
+ return ret;
+}
+
+/**
+ * Convert XFRM action to Verbs specification.
+ *
+ * @param parser
+ * Pointer to MLX5 flow parser structure.
+ */
+static void
+mlx5_flow_create_xfrm(struct mlx5_flow_parse *parser __rte_unused)
+{
+#ifdef HAVE_IBV_IPSEC_SUPPORT
+ unsigned int size = sizeof(struct ibv_flow_spec_action_xfrm);
+ struct ibv_flow_spec_action_xfrm xfrm_spec = {
+ .type = IBV_FLOW_SPEC_ACTION_XFRM,
+ .action = parser->security->ibv_action_xfrm,
+ .size = size,
+ };
+
+ assert(parser->security);
+ mlx5_flow_create_copy(parser, &xfrm_spec, size);
+#endif
+}
+
+/**
* Complete flow rule creation with a drop queue.
*
* @param priv
@@ -1797,6 +2027,7 @@ priv_flow_create_action_queue(struct priv *priv,
(*priv->rxqs)[parser->queues[i]];
q->mark |= parser->mark;
+ q->ipsec_en |= !!(parser->security);
}
return 0;
error:
@@ -1870,18 +2101,23 @@ priv_flow_create(struct priv *priv,
memcpy(flow->queues, parser.queues, parser.queues_n * sizeof(uint16_t));
flow->queues_n = parser.queues_n;
flow->mark = parser.mark;
+ flow->security = !!parser.security;
/* Copy RSS configuration. */
flow->rss_conf = parser.rss_conf;
flow->rss_conf.rss_key = flow->rss_key;
memcpy(flow->rss_key, parser.rss_key, parser.rss_conf.rss_key_len);
/* finalise the flow. */
- if (parser.drop)
- err = priv_flow_create_action_queue_drop(priv, &parser, flow,
- error);
- else
- err = priv_flow_create_action_queue(priv, &parser, flow, error);
- if (err)
- goto exit;
+ flow->ingress = parser.ingress;
+ if (parser.ingress) {
+ if (parser.drop)
+ err = priv_flow_create_action_queue_drop(priv, &parser,
+ flow, error);
+ else
+ err = priv_flow_create_action_queue(priv, &parser, flow,
+ error);
+ if (err)
+ goto exit;
+ }
TAILQ_INSERT_TAIL(list, flow, next);
DEBUG("Flow created %p", (void *)flow);
return flow;
@@ -1962,17 +2198,19 @@ priv_flow_destroy(struct priv *priv,
for (i = 0; i != flow->queues_n; ++i) {
struct rte_flow *tmp;
int mark = 0;
+ int ipsec = 0;
/*
* To remove the mark from the queue, the queue must not be
* present in any other marked flow (RSS or not).
+ * Same thing for the IPsec.
*/
TAILQ_FOREACH(tmp, list, next) {
unsigned int j;
uint16_t *tqs = NULL;
uint16_t tq_n = 0;
- if (!tmp->mark)
+ if (!tmp->mark && !tmp->security)
continue;
for (j = 0; j != hash_rxq_init_n; ++j) {
if (!tmp->frxq[j].hrxq)
@@ -1982,11 +2220,17 @@ priv_flow_destroy(struct priv *priv,
}
if (!tq_n)
continue;
- for (j = 0; (j != tq_n) && !mark; j++)
- if (tqs[j] == (*flow->queues)[i])
- mark = 1;
+ for (j = 0; (j != tq_n) && !mark; j++) {
+ if (tqs[j] == (*flow->queues)[i]) {
+ mark |= (*priv->rxqs)
+ [(*flow->queues)[j]]->mark;
+ ipsec |= !!(*priv->rxqs)
+ [(*flow->queues)[j]]->ipsec_en;
+ }
+ }
}
(*priv->rxqs)[(*flow->queues)[i]]->mark = mark;
+ (*priv->rxqs)[(*flow->queues)[i]]->ipsec_en = ipsec;
}
free:
if (flow->drop) {
@@ -2170,7 +2414,7 @@ priv_flow_stop(struct priv *priv, struct mlx5_flows *list)
/* Next flow. */
continue;
}
- if (flow->mark) {
+ if (flow->mark || flow->security) {
struct mlx5_ind_table_ibv *ind_tbl = NULL;
for (i = 0; i != hash_rxq_init_n; ++i) {
@@ -2179,8 +2423,10 @@ priv_flow_stop(struct priv *priv, struct mlx5_flows *list)
ind_tbl = flow->frxq[i].hrxq->ind_table;
}
assert(ind_tbl);
- for (i = 0; i != ind_tbl->queues_n; ++i)
+ for (i = 0; i != ind_tbl->queues_n; ++i) {
(*priv->rxqs)[ind_tbl->queues[i]]->mark = 0;
+ (*priv->rxqs)[ind_tbl->queues[i]]->ipsec_en = 0;
+ }
}
for (i = 0; i != hash_rxq_init_n; ++i) {
if (!flow->frxq[i].ibv_flow)
@@ -2263,10 +2509,13 @@ priv_flow_start(struct priv *priv, struct mlx5_flows *list)
}
DEBUG("Flow %p applied", (void *)flow);
}
- if (!flow->mark)
+ if (!flow->mark && !flow->security)
continue;
- for (i = 0; i != flow->queues_n; ++i)
- (*priv->rxqs)[(*flow->queues)[i]]->mark = 1;
+ for (i = 0; i != flow->queues_n; ++i) {
+ (*priv->rxqs)[(*flow->queues)[i]]->mark = flow->mark;
+ (*priv->rxqs)[(*flow->queues)[i]]->ipsec_en =
+ flow->security;
+ }
}
return 0;
}
diff --git a/drivers/net/mlx5/mlx5_ipsec.c b/drivers/net/mlx5/mlx5_ipsec.c
index 52a3add7a..e7086adbc 100644
--- a/drivers/net/mlx5/mlx5_ipsec.c
+++ b/drivers/net/mlx5/mlx5_ipsec.c
@@ -57,6 +57,9 @@
" please contact Mellanox")
/* Extra verifications, this API is not unstreamed yet. */
+MLX5_IPSEC_SUPPORT_ERROR(IBV_FLOW_ATTR_FLAGS_EGRESS == 1 << 2);
+MLX5_IPSEC_SUPPORT_ERROR(IBV_FLOW_SPEC_ESP == 0x34);
+MLX5_IPSEC_SUPPORT_ERROR(IBV_FLOW_SPEC_ACTION_XFRM == 0x1002);
MLX5_IPSEC_SUPPORT_ERROR(MLX5DV_CONTEXT_XFRM_FLAGS_ESP_AES_GCM_REQ_METADATA ==
1u << 0);
MLX5_IPSEC_SUPPORT_ERROR(MLX5DV_CONTEXT_XFRM_FLAGS_ESP_AES_GCM_RX == 1u << 1);
@@ -65,13 +68,6 @@ MLX5_IPSEC_SUPPORT_ERROR(MLX5DV_CONTEXT_XFRM_FLAGS_ESP_AES_GCM_SPI_RSS_ONLY ==
1u << 3);
#endif
-/* Security session. */
-struct mlx5_security_session {
- struct rte_security_ipsec_xform ipsec_xform;
- struct rte_eth_dev *dev;
- struct ibv_action_xfrm *ibv_action_xfrm;
-};
-
/** MLX5 Crypto capabilities. */
struct rte_cryptodev_capabilities mlx5_crypto_capabilities[] = {
/* AES GCM (128-bit) */
--
2.11.0
More information about the dev
mailing list