From: Shahaf Shuler <shah...@mellanox.com>

Signed-off-by: Shahaf Shuler <shah...@mellanox.com>
Signed-off-by: Aviad Yehezkel <avia...@mellanox.com>
Signed-off-by: Matan Barak <mat...@mellanox.com>
Signed-off-by: Nelio Laranjeiro <nelio.laranje...@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

Reply via email to