X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fmlx5%2Fmlx5_flow_verbs.c;h=459e7b64835dacfd89c2c59364775e9d49fe6d6a;hb=6bd5efb23db9e419dec51fbea7f71c2fd3703d75;hp=f720c355d1826119f6ac48d79e1cae269794ca99;hpb=06629d860d54ec3015ad2bcd66759d3b5dbc7e3d;p=dpdk.git diff --git a/drivers/net/mlx5/mlx5_flow_verbs.c b/drivers/net/mlx5/mlx5_flow_verbs.c index f720c355d1..459e7b6483 100644 --- a/drivers/net/mlx5/mlx5_flow_verbs.c +++ b/drivers/net/mlx5/mlx5_flow_verbs.c @@ -20,18 +20,89 @@ #include #include -#include #include #include #include #include #include -#include "mlx5.h" +#include +#include + #include "mlx5_defs.h" -#include "mlx5_prm.h" -#include "mlx5_glue.h" +#include "mlx5.h" #include "mlx5_flow.h" +#include "mlx5_rxtx.h" + +#define VERBS_SPEC_INNER(item_flags) \ + (!!((item_flags) & MLX5_FLOW_LAYER_TUNNEL) ? IBV_FLOW_SPEC_INNER : 0) + +/** + * Create Verbs flow counter with Verbs library. + * + * @param[in] dev + * Pointer to the Ethernet device structure. + * @param[in, out] counter + * mlx5 flow counter object, contains the counter id, + * handle of created Verbs flow counter is returned + * in cs field (if counters are supported). + * + * @return + * 0 On success else a negative errno value is returned + * and rte_errno is set. + */ +static int +flow_verbs_counter_create(struct rte_eth_dev *dev, + struct mlx5_flow_counter *counter) +{ +#if defined(HAVE_IBV_DEVICE_COUNTERS_SET_V42) + struct mlx5_priv *priv = dev->data->dev_private; + struct ibv_context *ctx = priv->sh->ctx; + struct ibv_counter_set_init_attr init = { + .counter_set_id = counter->id}; + + counter->cs = mlx5_glue->create_counter_set(ctx, &init); + if (!counter->cs) { + rte_errno = ENOTSUP; + return -ENOTSUP; + } + return 0; +#elif defined(HAVE_IBV_DEVICE_COUNTERS_SET_V45) + struct mlx5_priv *priv = dev->data->dev_private; + struct ibv_context *ctx = priv->sh->ctx; + struct ibv_counters_init_attr init = {0}; + struct ibv_counter_attach_attr attach; + int ret; + + memset(&attach, 0, sizeof(attach)); + counter->cs = mlx5_glue->create_counters(ctx, &init); + if (!counter->cs) { + rte_errno = ENOTSUP; + return -ENOTSUP; + } + attach.counter_desc = IBV_COUNTER_PACKETS; + attach.index = 0; + ret = mlx5_glue->attach_counters(counter->cs, &attach, NULL); + if (!ret) { + attach.counter_desc = IBV_COUNTER_BYTES; + attach.index = 1; + ret = mlx5_glue->attach_counters + (counter->cs, &attach, NULL); + } + if (ret) { + claim_zero(mlx5_glue->destroy_counters(counter->cs)); + counter->cs = NULL; + rte_errno = ret; + return -ret; + } + return 0; +#else + (void)dev; + (void)counter; + rte_errno = ENOTSUP; + return -ENOTSUP; +#endif +} /** * Get a flow counter. @@ -49,62 +120,61 @@ static struct mlx5_flow_counter * flow_verbs_counter_new(struct rte_eth_dev *dev, uint32_t shared, uint32_t id) { - struct priv *priv = dev->data->dev_private; + struct mlx5_priv *priv = dev->data->dev_private; struct mlx5_flow_counter *cnt; + int ret; - LIST_FOREACH(cnt, &priv->flow_counters, next) { - if (!cnt->shared || cnt->shared != shared) - continue; - if (cnt->id != id) - continue; - cnt->ref_cnt++; - return cnt; - } -#ifdef HAVE_IBV_DEVICE_COUNTERS_SET_V42 - - struct mlx5_flow_counter tmpl = { - .shared = shared, - .id = id, - .cs = mlx5_glue->create_counter_set - (priv->ctx, - &(struct ibv_counter_set_init_attr){ - .counter_set_id = id, - }), - .hits = 0, - .bytes = 0, - .ref_cnt = 1, - }; - - if (!tmpl.cs) { - rte_errno = errno; - return NULL; + if (shared) { + TAILQ_FOREACH(cnt, &priv->sh->cmng.flow_counters, next) { + if (cnt->shared && cnt->id == id) { + cnt->ref_cnt++; + return cnt; + } + } } cnt = rte_calloc(__func__, 1, sizeof(*cnt), 0); if (!cnt) { - claim_zero(mlx5_glue->destroy_counter_set(tmpl.cs)); rte_errno = ENOMEM; return NULL; } - *cnt = tmpl; - LIST_INSERT_HEAD(&priv->flow_counters, cnt, next); - return cnt; -#endif - rte_errno = ENOTSUP; + cnt->id = id; + cnt->shared = shared; + cnt->ref_cnt = 1; + cnt->hits = 0; + cnt->bytes = 0; + /* Create counter with Verbs. */ + ret = flow_verbs_counter_create(dev, cnt); + if (!ret) { + TAILQ_INSERT_HEAD(&priv->sh->cmng.flow_counters, cnt, next); + return cnt; + } + /* Some error occurred in Verbs library. */ + rte_free(cnt); + rte_errno = -ret; return NULL; } /** * Release a flow counter. * + * @param[in] dev + * Pointer to the Ethernet device structure. * @param[in] counter * Pointer to the counter handler. */ static void -flow_verbs_counter_release(struct mlx5_flow_counter *counter) +flow_verbs_counter_release(struct rte_eth_dev *dev, + struct mlx5_flow_counter *counter) { + struct mlx5_priv *priv = dev->data->dev_private; + if (--counter->ref_cnt == 0) { +#if defined(HAVE_IBV_DEVICE_COUNTERS_SET_V42) claim_zero(mlx5_glue->destroy_counter_set(counter->cs)); - LIST_REMOVE(counter, next); +#elif defined(HAVE_IBV_DEVICE_COUNTERS_SET_V45) + claim_zero(mlx5_glue->destroy_counters(counter->cs)); +#endif + TAILQ_REMOVE(&priv->sh->cmng.flow_counters, counter, next); rte_free(counter); } } @@ -117,14 +187,15 @@ flow_verbs_counter_release(struct mlx5_flow_counter *counter) */ static int flow_verbs_counter_query(struct rte_eth_dev *dev __rte_unused, - struct rte_flow *flow __rte_unused, - void *data __rte_unused, + struct rte_flow *flow, void *data, struct rte_flow_error *error) { -#ifdef HAVE_IBV_DEVICE_COUNTERS_SET_V42 - if (flow->actions & MLX5_FLOW_ACTION_COUNT) { +#if defined(HAVE_IBV_DEVICE_COUNTERS_SET_V42) || \ + defined(HAVE_IBV_DEVICE_COUNTERS_SET_V45) + if (flow->counter && flow->counter->cs) { struct rte_flow_query_count *qc = data; uint64_t counters[2] = {0, 0}; +#if defined(HAVE_IBV_DEVICE_COUNTERS_SET_V42) struct ibv_query_counter_set_attr query_cs_attr = { .cs = flow->counter->cs, .query_flags = IBV_COUNTER_SET_FORCE_UPDATE, @@ -135,7 +206,12 @@ flow_verbs_counter_query(struct rte_eth_dev *dev __rte_unused, }; int err = mlx5_glue->query_counter_set(&query_cs_attr, &query_out); - +#elif defined(HAVE_IBV_DEVICE_COUNTERS_SET_V45) + int err = mlx5_glue->query_counters + (flow->counter->cs, counters, + RTE_DIM(counters), + IBV_READ_COUNTERS_ATTR_PREFER_CACHED); +#endif if (err) return rte_flow_error_set (error, err, @@ -157,6 +233,8 @@ flow_verbs_counter_query(struct rte_eth_dev *dev __rte_unused, NULL, "flow does not have counter"); #else + (void)flow; + (void)data; return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, @@ -165,27 +243,26 @@ flow_verbs_counter_query(struct rte_eth_dev *dev __rte_unused, } /** - * Add a verbs item specification into @p flow. + * Add a verbs item specification into @p verbs. * - * @param[in, out] flow - * Pointer to flow structure. + * @param[out] verbs + * Pointer to verbs structure. * @param[in] src * Create specification. * @param[in] size * Size in bytes of the specification to copy. */ static void -flow_verbs_spec_add(struct mlx5_flow *flow, void *src, unsigned int size) +flow_verbs_spec_add(struct mlx5_flow_verbs *verbs, void *src, unsigned int size) { - struct mlx5_flow_verbs *verbs = &flow->verbs; + void *dst; - if (verbs->specs) { - void *dst; - - dst = (void *)(verbs->specs + verbs->size); - memcpy(dst, src, size); - ++verbs->attr->num_of_specs; - } + if (!verbs) + return; + MLX5_ASSERT(verbs->specs); + dst = (void *)(verbs->specs + verbs->size); + memcpy(dst, src, size); + ++verbs->attr->num_of_specs; verbs->size += size; } @@ -194,24 +271,23 @@ flow_verbs_spec_add(struct mlx5_flow *flow, void *src, unsigned int size) * the input is valid and that there is space to insert the requested item * into the flow. * + * @param[in, out] dev_flow + * Pointer to dev_flow structure. * @param[in] item * Item specification. * @param[in] item_flags - * Bit field with all detected items. - * @param[in, out] dev_flow - * Pointer to dev_flow structure. + * Parsed item flags. */ static void -flow_verbs_translate_item_eth(const struct rte_flow_item *item, - uint64_t *item_flags, - struct mlx5_flow *dev_flow) +flow_verbs_translate_item_eth(struct mlx5_flow *dev_flow, + const struct rte_flow_item *item, + uint64_t item_flags) { const struct rte_flow_item_eth *spec = item->spec; const struct rte_flow_item_eth *mask = item->mask; - const int tunnel = !!(*item_flags & MLX5_FLOW_LAYER_TUNNEL); const unsigned int size = sizeof(struct ibv_flow_spec_eth); struct ibv_flow_spec_eth eth = { - .type = IBV_FLOW_SPEC_ETH | (tunnel ? IBV_FLOW_SPEC_INNER : 0), + .type = IBV_FLOW_SPEC_ETH | VERBS_SPEC_INNER(item_flags), .size = size, }; @@ -220,23 +296,24 @@ flow_verbs_translate_item_eth(const struct rte_flow_item *item, if (spec) { unsigned int i; - memcpy(ð.val.dst_mac, spec->dst.addr_bytes, ETHER_ADDR_LEN); - memcpy(ð.val.src_mac, spec->src.addr_bytes, ETHER_ADDR_LEN); + memcpy(ð.val.dst_mac, spec->dst.addr_bytes, + RTE_ETHER_ADDR_LEN); + memcpy(ð.val.src_mac, spec->src.addr_bytes, + RTE_ETHER_ADDR_LEN); eth.val.ether_type = spec->type; - memcpy(ð.mask.dst_mac, mask->dst.addr_bytes, ETHER_ADDR_LEN); - memcpy(ð.mask.src_mac, mask->src.addr_bytes, ETHER_ADDR_LEN); + memcpy(ð.mask.dst_mac, mask->dst.addr_bytes, + RTE_ETHER_ADDR_LEN); + memcpy(ð.mask.src_mac, mask->src.addr_bytes, + RTE_ETHER_ADDR_LEN); eth.mask.ether_type = mask->type; /* Remove unwanted bits from values. */ - for (i = 0; i < ETHER_ADDR_LEN; ++i) { + for (i = 0; i < RTE_ETHER_ADDR_LEN; ++i) { eth.val.dst_mac[i] &= eth.mask.dst_mac[i]; eth.val.src_mac[i] &= eth.mask.src_mac[i]; } eth.val.ether_type &= eth.mask.ether_type; - dev_flow->verbs.attr->priority = MLX5_PRIORITY_MAP_L2; } - flow_verbs_spec_add(dev_flow, ð, size); - *item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L2 : - MLX5_FLOW_LAYER_OUTER_L2; + flow_verbs_spec_add(&dev_flow->verbs, ð, size); } /** @@ -278,24 +355,24 @@ flow_verbs_item_vlan_update(struct ibv_flow_attr *attr, * the input is valid and that there is space to insert the requested item * into the flow. * - * @param[in] item - * Item specification. - * @param[in, out] item_flags - * Bit mask that holds all detected items. * @param[in, out] dev_flow * Pointer to dev_flow structure. + * @param[in] item + * Item specification. + * @param[in] item_flags + * Parsed item flags. */ static void -flow_verbs_translate_item_vlan(const struct rte_flow_item *item, - uint64_t *item_flags, - struct mlx5_flow *dev_flow) +flow_verbs_translate_item_vlan(struct mlx5_flow *dev_flow, + const struct rte_flow_item *item, + uint64_t item_flags) { const struct rte_flow_item_vlan *spec = item->spec; const struct rte_flow_item_vlan *mask = item->mask; unsigned int size = sizeof(struct ibv_flow_spec_eth); - const int tunnel = !!(*item_flags & MLX5_FLOW_LAYER_TUNNEL); + const int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL); struct ibv_flow_spec_eth eth = { - .type = IBV_FLOW_SPEC_ETH | (tunnel ? IBV_FLOW_SPEC_INNER : 0), + .type = IBV_FLOW_SPEC_ETH | VERBS_SPEC_INNER(item_flags), .size = size, }; const uint32_t l2m = tunnel ? MLX5_FLOW_LAYER_INNER_L2 : @@ -311,16 +388,13 @@ flow_verbs_translate_item_vlan(const struct rte_flow_item *item, eth.mask.ether_type = mask->inner_type; eth.val.ether_type &= eth.mask.ether_type; } - if (!(*item_flags & l2m)) { - dev_flow->verbs.attr->priority = MLX5_PRIORITY_MAP_L2; - flow_verbs_spec_add(dev_flow, ð, size); - } else { + if (!(item_flags & l2m)) + flow_verbs_spec_add(&dev_flow->verbs, ð, size); + else flow_verbs_item_vlan_update(dev_flow->verbs.attr, ð); - size = 0; /* Only an update is done in eth specification. */ - } - *item_flags |= tunnel ? - (MLX5_FLOW_LAYER_INNER_L2 | MLX5_FLOW_LAYER_INNER_VLAN) : - (MLX5_FLOW_LAYER_OUTER_L2 | MLX5_FLOW_LAYER_OUTER_VLAN); + if (!tunnel) + dev_flow->verbs.vf_vlan.tag = + rte_be_to_cpu_16(spec->tci) & 0x0fff; } /** @@ -328,32 +402,28 @@ flow_verbs_translate_item_vlan(const struct rte_flow_item *item, * the input is valid and that there is space to insert the requested item * into the flow. * + * @param[in, out] dev_flow + * Pointer to dev_flow structure. * @param[in] item * Item specification. - * @param[in, out] item_flags - * Bit mask that marks all detected items. - * @param[in, out] dev_flow - * Pointer to sepacific flow structure. + * @param[in] item_flags + * Parsed item flags. */ static void -flow_verbs_translate_item_ipv4(const struct rte_flow_item *item, - uint64_t *item_flags, - struct mlx5_flow *dev_flow) +flow_verbs_translate_item_ipv4(struct mlx5_flow *dev_flow, + const struct rte_flow_item *item, + uint64_t item_flags) { const struct rte_flow_item_ipv4 *spec = item->spec; const struct rte_flow_item_ipv4 *mask = item->mask; - const int tunnel = !!(*item_flags & MLX5_FLOW_LAYER_TUNNEL); unsigned int size = sizeof(struct ibv_flow_spec_ipv4_ext); struct ibv_flow_spec_ipv4_ext ipv4 = { - .type = IBV_FLOW_SPEC_IPV4_EXT | - (tunnel ? IBV_FLOW_SPEC_INNER : 0), + .type = IBV_FLOW_SPEC_IPV4_EXT | VERBS_SPEC_INNER(item_flags), .size = size, }; if (!mask) mask = &rte_flow_item_ipv4_mask; - *item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 : - MLX5_FLOW_LAYER_OUTER_L3_IPV4; if (spec) { ipv4.val = (struct ibv_flow_ipv4_ext_filter){ .src_ip = spec->hdr.src_addr, @@ -373,12 +443,7 @@ flow_verbs_translate_item_ipv4(const struct rte_flow_item *item, ipv4.val.proto &= ipv4.mask.proto; ipv4.val.tos &= ipv4.mask.tos; } - dev_flow->verbs.hash_fields |= - mlx5_flow_hashfields_adjust(dev_flow, tunnel, - MLX5_IPV4_LAYER_TYPES, - MLX5_IPV4_IBV_RX_HASH); - dev_flow->verbs.attr->priority = MLX5_PRIORITY_MAP_L3; - flow_verbs_spec_add(dev_flow, &ipv4, size); + flow_verbs_spec_add(&dev_flow->verbs, &ipv4, size); } /** @@ -386,31 +451,28 @@ flow_verbs_translate_item_ipv4(const struct rte_flow_item *item, * the input is valid and that there is space to insert the requested item * into the flow. * + * @param[in, out] dev_flow + * Pointer to dev_flow structure. * @param[in] item * Item specification. - * @param[in, out] item_flags - * Bit mask that marks all detected items. - * @param[in, out] dev_flow - * Pointer to sepacific flow structure. + * @param[in] item_flags + * Parsed item flags. */ static void -flow_verbs_translate_item_ipv6(const struct rte_flow_item *item, - uint64_t *item_flags, - struct mlx5_flow *dev_flow) +flow_verbs_translate_item_ipv6(struct mlx5_flow *dev_flow, + const struct rte_flow_item *item, + uint64_t item_flags) { const struct rte_flow_item_ipv6 *spec = item->spec; const struct rte_flow_item_ipv6 *mask = item->mask; - const int tunnel = !!(dev_flow->flow->layers & MLX5_FLOW_LAYER_TUNNEL); unsigned int size = sizeof(struct ibv_flow_spec_ipv6); struct ibv_flow_spec_ipv6 ipv6 = { - .type = IBV_FLOW_SPEC_IPV6 | (tunnel ? IBV_FLOW_SPEC_INNER : 0), + .type = IBV_FLOW_SPEC_IPV6 | VERBS_SPEC_INNER(item_flags), .size = size, }; if (!mask) mask = &rte_flow_item_ipv6_mask; - *item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 : - MLX5_FLOW_LAYER_OUTER_L3_IPV6; if (spec) { unsigned int i; uint32_t vtc_flow_val; @@ -427,19 +489,17 @@ flow_verbs_translate_item_ipv6(const struct rte_flow_item *item, vtc_flow_val = rte_be_to_cpu_32(spec->hdr.vtc_flow); vtc_flow_mask = rte_be_to_cpu_32(mask->hdr.vtc_flow); ipv6.val.flow_label = - rte_cpu_to_be_32((vtc_flow_val & IPV6_HDR_FL_MASK) >> - IPV6_HDR_FL_SHIFT); - ipv6.val.traffic_class = (vtc_flow_val & IPV6_HDR_TC_MASK) >> - IPV6_HDR_TC_SHIFT; + rte_cpu_to_be_32((vtc_flow_val & RTE_IPV6_HDR_FL_MASK) >> + RTE_IPV6_HDR_FL_SHIFT); + ipv6.val.traffic_class = (vtc_flow_val & RTE_IPV6_HDR_TC_MASK) >> + RTE_IPV6_HDR_TC_SHIFT; ipv6.val.next_hdr = spec->hdr.proto; - ipv6.val.hop_limit = spec->hdr.hop_limits; ipv6.mask.flow_label = - rte_cpu_to_be_32((vtc_flow_mask & IPV6_HDR_FL_MASK) >> - IPV6_HDR_FL_SHIFT); - ipv6.mask.traffic_class = (vtc_flow_mask & IPV6_HDR_TC_MASK) >> - IPV6_HDR_TC_SHIFT; + rte_cpu_to_be_32((vtc_flow_mask & RTE_IPV6_HDR_FL_MASK) >> + RTE_IPV6_HDR_FL_SHIFT); + ipv6.mask.traffic_class = (vtc_flow_mask & RTE_IPV6_HDR_TC_MASK) >> + RTE_IPV6_HDR_TC_SHIFT; ipv6.mask.next_hdr = mask->hdr.proto; - ipv6.mask.hop_limit = mask->hdr.hop_limits; /* Remove unwanted bits from values. */ for (i = 0; i < RTE_DIM(ipv6.val.src_ip); ++i) { ipv6.val.src_ip[i] &= ipv6.mask.src_ip[i]; @@ -448,14 +508,8 @@ flow_verbs_translate_item_ipv6(const struct rte_flow_item *item, ipv6.val.flow_label &= ipv6.mask.flow_label; ipv6.val.traffic_class &= ipv6.mask.traffic_class; ipv6.val.next_hdr &= ipv6.mask.next_hdr; - ipv6.val.hop_limit &= ipv6.mask.hop_limit; } - dev_flow->verbs.hash_fields |= - mlx5_flow_hashfields_adjust(dev_flow, tunnel, - MLX5_IPV6_LAYER_TYPES, - MLX5_IPV6_IBV_RX_HASH); - dev_flow->verbs.attr->priority = MLX5_PRIORITY_MAP_L3; - flow_verbs_spec_add(dev_flow, &ipv6, size); + flow_verbs_spec_add(&dev_flow->verbs, &ipv6, size); } /** @@ -463,46 +517,38 @@ flow_verbs_translate_item_ipv6(const struct rte_flow_item *item, * the input is valid and that there is space to insert the requested item * into the flow. * + * @param[in, out] dev_flow + * Pointer to dev_flow structure. * @param[in] item * Item specification. - * @param[in, out] item_flags - * Bit mask that marks all detected items. - * @param[in, out] dev_flow - * Pointer to sepacific flow structure. + * @param[in] item_flags + * Parsed item flags. */ static void -flow_verbs_translate_item_udp(const struct rte_flow_item *item, - uint64_t *item_flags, - struct mlx5_flow *dev_flow) +flow_verbs_translate_item_tcp(struct mlx5_flow *dev_flow, + const struct rte_flow_item *item, + uint64_t item_flags __rte_unused) { - const struct rte_flow_item_udp *spec = item->spec; - const struct rte_flow_item_udp *mask = item->mask; - const int tunnel = !!(*item_flags & MLX5_FLOW_LAYER_TUNNEL); + const struct rte_flow_item_tcp *spec = item->spec; + const struct rte_flow_item_tcp *mask = item->mask; unsigned int size = sizeof(struct ibv_flow_spec_tcp_udp); - struct ibv_flow_spec_tcp_udp udp = { - .type = IBV_FLOW_SPEC_UDP | (tunnel ? IBV_FLOW_SPEC_INNER : 0), + struct ibv_flow_spec_tcp_udp tcp = { + .type = IBV_FLOW_SPEC_TCP | VERBS_SPEC_INNER(item_flags), .size = size, }; if (!mask) - mask = &rte_flow_item_udp_mask; - *item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP : - MLX5_FLOW_LAYER_OUTER_L4_UDP; + mask = &rte_flow_item_tcp_mask; if (spec) { - udp.val.dst_port = spec->hdr.dst_port; - udp.val.src_port = spec->hdr.src_port; - udp.mask.dst_port = mask->hdr.dst_port; - udp.mask.src_port = mask->hdr.src_port; + tcp.val.dst_port = spec->hdr.dst_port; + tcp.val.src_port = spec->hdr.src_port; + tcp.mask.dst_port = mask->hdr.dst_port; + tcp.mask.src_port = mask->hdr.src_port; /* Remove unwanted bits from values. */ - udp.val.src_port &= udp.mask.src_port; - udp.val.dst_port &= udp.mask.dst_port; + tcp.val.src_port &= tcp.mask.src_port; + tcp.val.dst_port &= tcp.mask.dst_port; } - dev_flow->verbs.hash_fields |= - mlx5_flow_hashfields_adjust(dev_flow, tunnel, ETH_RSS_UDP, - (IBV_RX_HASH_SRC_PORT_UDP | - IBV_RX_HASH_DST_PORT_UDP)); - dev_flow->verbs.attr->priority = MLX5_PRIORITY_MAP_L4; - flow_verbs_spec_add(dev_flow, &udp, size); + flow_verbs_spec_add(&dev_flow->verbs, &tcp, size); } /** @@ -510,46 +556,38 @@ flow_verbs_translate_item_udp(const struct rte_flow_item *item, * the input is valid and that there is space to insert the requested item * into the flow. * + * @param[in, out] dev_flow + * Pointer to dev_flow structure. * @param[in] item * Item specification. - * @param[in, out] item_flags - * Bit mask that marks all detected items. - * @param[in, out] dev_flow - * Pointer to sepacific flow structure. + * @param[in] item_flags + * Parsed item flags. */ static void -flow_verbs_translate_item_tcp(const struct rte_flow_item *item, - uint64_t *item_flags, - struct mlx5_flow *dev_flow) +flow_verbs_translate_item_udp(struct mlx5_flow *dev_flow, + const struct rte_flow_item *item, + uint64_t item_flags __rte_unused) { - const struct rte_flow_item_tcp *spec = item->spec; - const struct rte_flow_item_tcp *mask = item->mask; - const int tunnel = !!(dev_flow->flow->layers & MLX5_FLOW_LAYER_TUNNEL); + const struct rte_flow_item_udp *spec = item->spec; + const struct rte_flow_item_udp *mask = item->mask; unsigned int size = sizeof(struct ibv_flow_spec_tcp_udp); - struct ibv_flow_spec_tcp_udp tcp = { - .type = IBV_FLOW_SPEC_TCP | (tunnel ? IBV_FLOW_SPEC_INNER : 0), + struct ibv_flow_spec_tcp_udp udp = { + .type = IBV_FLOW_SPEC_UDP | VERBS_SPEC_INNER(item_flags), .size = size, }; if (!mask) - mask = &rte_flow_item_tcp_mask; - *item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP : - MLX5_FLOW_LAYER_OUTER_L4_TCP; + mask = &rte_flow_item_udp_mask; if (spec) { - tcp.val.dst_port = spec->hdr.dst_port; - tcp.val.src_port = spec->hdr.src_port; - tcp.mask.dst_port = mask->hdr.dst_port; - tcp.mask.src_port = mask->hdr.src_port; + udp.val.dst_port = spec->hdr.dst_port; + udp.val.src_port = spec->hdr.src_port; + udp.mask.dst_port = mask->hdr.dst_port; + udp.mask.src_port = mask->hdr.src_port; /* Remove unwanted bits from values. */ - tcp.val.src_port &= tcp.mask.src_port; - tcp.val.dst_port &= tcp.mask.dst_port; + udp.val.src_port &= udp.mask.src_port; + udp.val.dst_port &= udp.mask.dst_port; } - dev_flow->verbs.hash_fields |= - mlx5_flow_hashfields_adjust(dev_flow, tunnel, ETH_RSS_TCP, - (IBV_RX_HASH_SRC_PORT_TCP | - IBV_RX_HASH_DST_PORT_TCP)); - dev_flow->verbs.attr->priority = MLX5_PRIORITY_MAP_L4; - flow_verbs_spec_add(dev_flow, &tcp, size); + flow_verbs_spec_add(&dev_flow->verbs, &udp, size); } /** @@ -557,17 +595,17 @@ flow_verbs_translate_item_tcp(const struct rte_flow_item *item, * the input is valid and that there is space to insert the requested item * into the flow. * + * @param[in, out] dev_flow + * Pointer to dev_flow structure. * @param[in] item * Item specification. - * @param[in, out] item_flags - * Bit mask that marks all detected items. - * @param[in, out] dev_flow - * Pointer to sepacific flow structure. + * @param[in] item_flags + * Parsed item flags. */ static void -flow_verbs_translate_item_vxlan(const struct rte_flow_item *item, - uint64_t *item_flags, - struct mlx5_flow *dev_flow) +flow_verbs_translate_item_vxlan(struct mlx5_flow *dev_flow, + const struct rte_flow_item *item, + uint64_t item_flags __rte_unused) { const struct rte_flow_item_vxlan *spec = item->spec; const struct rte_flow_item_vxlan *mask = item->mask; @@ -591,9 +629,7 @@ flow_verbs_translate_item_vxlan(const struct rte_flow_item *item, /* Remove unwanted bits from values. */ vxlan.val.tunnel_id &= vxlan.mask.tunnel_id; } - flow_verbs_spec_add(dev_flow, &vxlan, size); - dev_flow->verbs.attr->priority = MLX5_PRIORITY_MAP_L2; - *item_flags |= MLX5_FLOW_LAYER_VXLAN; + flow_verbs_spec_add(&dev_flow->verbs, &vxlan, size); } /** @@ -601,17 +637,17 @@ flow_verbs_translate_item_vxlan(const struct rte_flow_item *item, * the input is valid and that there is space to insert the requested item * into the flow. * + * @param[in, out] dev_flow + * Pointer to dev_flow structure. * @param[in] item * Item specification. - * @param[in, out] item_flags - * Bit mask that marks all detected items. - * @param[in, out] dev_flow - * Pointer to sepacific flow structure. + * @param[in] item_flags + * Parsed item flags. */ static void -flow_verbs_translate_item_vxlan_gpe(const struct rte_flow_item *item, - uint64_t *item_flags, - struct mlx5_flow *dev_flow) +flow_verbs_translate_item_vxlan_gpe(struct mlx5_flow *dev_flow, + const struct rte_flow_item *item, + uint64_t item_flags __rte_unused) { const struct rte_flow_item_vxlan_gpe *spec = item->spec; const struct rte_flow_item_vxlan_gpe *mask = item->mask; @@ -635,9 +671,7 @@ flow_verbs_translate_item_vxlan_gpe(const struct rte_flow_item *item, /* Remove unwanted bits from values. */ vxlan_gpe.val.tunnel_id &= vxlan_gpe.mask.tunnel_id; } - flow_verbs_spec_add(dev_flow, &vxlan_gpe, size); - dev_flow->verbs.attr->priority = MLX5_PRIORITY_MAP_L2; - *item_flags |= MLX5_FLOW_LAYER_VXLAN_GPE; + flow_verbs_spec_add(&dev_flow->verbs, &vxlan_gpe, size); } /** @@ -697,17 +731,17 @@ flow_verbs_item_gre_ip_protocol_update(struct ibv_flow_attr *attr, * the input is valid and that there is space to insert the requested item * into the flow. * + * @param[in, out] dev_flow + * Pointer to dev_flow structure. * @param[in] item * Item specification. - * @param[in, out] item_flags - * Bit mask that marks all detected items. - * @param[in, out] dev_flow - * Pointer to sepacific flow structure. + * @param[in] item_flags + * Parsed item flags. */ static void -flow_verbs_translate_item_gre(const struct rte_flow_item *item __rte_unused, - uint64_t *item_flags, - struct mlx5_flow *dev_flow) +flow_verbs_translate_item_gre(struct mlx5_flow *dev_flow, + const struct rte_flow_item *item __rte_unused, + uint64_t item_flags) { struct mlx5_flow_verbs *verbs = &dev_flow->verbs; #ifndef HAVE_IBV_DEVICE_MPLS_SUPPORT @@ -738,7 +772,7 @@ flow_verbs_translate_item_gre(const struct rte_flow_item *item __rte_unused, tunnel.val.key &= tunnel.mask.key; } #endif - if (*item_flags & MLX5_FLOW_LAYER_OUTER_L3_IPV4) + if (item_flags & MLX5_FLOW_LAYER_OUTER_L3_IPV4) flow_verbs_item_gre_ip_protocol_update(verbs->attr, IBV_FLOW_SPEC_IPV4_EXT, IPPROTO_GRE); @@ -746,9 +780,7 @@ flow_verbs_translate_item_gre(const struct rte_flow_item *item __rte_unused, flow_verbs_item_gre_ip_protocol_update(verbs->attr, IBV_FLOW_SPEC_IPV6, IPPROTO_GRE); - flow_verbs_spec_add(dev_flow, &tunnel, size); - verbs->attr->priority = MLX5_PRIORITY_MAP_L2; - *item_flags |= MLX5_FLOW_LAYER_GRE; + flow_verbs_spec_add(verbs, &tunnel, size); } /** @@ -756,17 +788,17 @@ flow_verbs_translate_item_gre(const struct rte_flow_item *item __rte_unused, * the input is valid and that there is space to insert the requested action * into the flow. This function also return the action that was added. * + * @param[in, out] dev_flow + * Pointer to dev_flow structure. * @param[in] item * Item specification. - * @param[in, out] item_flags - * Bit mask that marks all detected items. - * @param[in, out] dev_flow - * Pointer to sepacific flow structure. + * @param[in] item_flags + * Parsed item flags. */ static void -flow_verbs_translate_item_mpls(const struct rte_flow_item *item __rte_unused, - uint64_t *action_flags __rte_unused, - struct mlx5_flow *dev_flow __rte_unused) +flow_verbs_translate_item_mpls(struct mlx5_flow *dev_flow __rte_unused, + const struct rte_flow_item *item __rte_unused, + uint64_t item_flags __rte_unused) { #ifdef HAVE_IBV_DEVICE_MPLS_SUPPORT const struct rte_flow_item_mpls *spec = item->spec; @@ -785,25 +817,24 @@ flow_verbs_translate_item_mpls(const struct rte_flow_item *item __rte_unused, /* Remove unwanted bits from values. */ mpls.val.label &= mpls.mask.label; } - flow_verbs_spec_add(dev_flow, &mpls, size); - dev_flow->verbs.attr->priority = MLX5_PRIORITY_MAP_L2; - *action_flags |= MLX5_FLOW_LAYER_MPLS; + flow_verbs_spec_add(&dev_flow->verbs, &mpls, size); #endif } /** * Convert the @p action into a Verbs specification. This function assumes that * the input is valid and that there is space to insert the requested action - * into the flow. This function also return the action that was added. + * into the flow. * - * @param[in, out] action_flags - * Pointer to the detected actions. * @param[in] dev_flow * Pointer to mlx5_flow. + * @param[in] action + * Action configuration. */ static void -flow_verbs_translate_action_drop(uint64_t *action_flags, - struct mlx5_flow *dev_flow) +flow_verbs_translate_action_drop + (struct mlx5_flow *dev_flow, + const struct rte_flow_action *action __rte_unused) { unsigned int size = sizeof(struct ibv_flow_spec_action_drop); struct ibv_flow_spec_action_drop drop = { @@ -811,40 +842,35 @@ flow_verbs_translate_action_drop(uint64_t *action_flags, .size = size, }; - flow_verbs_spec_add(dev_flow, &drop, size); - *action_flags |= MLX5_FLOW_ACTION_DROP; + flow_verbs_spec_add(&dev_flow->verbs, &drop, size); } /** * Convert the @p action into a Verbs specification. This function assumes that * the input is valid and that there is space to insert the requested action - * into the flow. This function also return the action that was added. + * into the flow. * - * @param[in] action - * Action configuration. - * @param[in, out] action_flags - * Pointer to the detected actions. * @param[in] dev_flow * Pointer to mlx5_flow. + * @param[in] action + * Action configuration. */ static void -flow_verbs_translate_action_queue(const struct rte_flow_action *action, - uint64_t *action_flags, - struct mlx5_flow *dev_flow) +flow_verbs_translate_action_queue(struct mlx5_flow *dev_flow, + const struct rte_flow_action *action) { const struct rte_flow_action_queue *queue = action->conf; struct rte_flow *flow = dev_flow->flow; - if (flow->queue) - (*flow->queue)[0] = queue->index; + if (flow->rss.queue) + (*flow->rss.queue)[0] = queue->index; flow->rss.queue_num = 1; - *action_flags |= MLX5_FLOW_ACTION_QUEUE; } /** * Convert the @p action into a Verbs specification. This function assumes that * the input is valid and that there is space to insert the requested action - * into the flow. This function also return the action that was added. + * into the flow. * * @param[in] action * Action configuration. @@ -854,40 +880,40 @@ flow_verbs_translate_action_queue(const struct rte_flow_action *action, * Pointer to mlx5_flow. */ static void -flow_verbs_translate_action_rss(const struct rte_flow_action *action, - uint64_t *action_flags, - struct mlx5_flow *dev_flow) +flow_verbs_translate_action_rss(struct mlx5_flow *dev_flow, + const struct rte_flow_action *action) { const struct rte_flow_action_rss *rss = action->conf; + const uint8_t *rss_key; struct rte_flow *flow = dev_flow->flow; - if (flow->queue) - memcpy((*flow->queue), rss->queue, + if (flow->rss.queue) + memcpy((*flow->rss.queue), rss->queue, rss->queue_num * sizeof(uint16_t)); flow->rss.queue_num = rss->queue_num; - memcpy(flow->key, rss->key, MLX5_RSS_HASH_KEY_LEN); - flow->rss.types = rss->types; - flow->rss.level = rss->level; - *action_flags |= MLX5_FLOW_ACTION_RSS; + /* NULL RSS key indicates default RSS key. */ + rss_key = !rss->key ? rss_hash_default_key : rss->key; + memcpy(flow->rss.key, rss_key, MLX5_RSS_HASH_KEY_LEN); + /* + * rss->level and rss.types should be set in advance when expanding + * items for RSS. + */ } /** * Convert the @p action into a Verbs specification. This function assumes that * the input is valid and that there is space to insert the requested action - * into the flow. This function also return the action that was added. + * into the flow. * - * @param[in] action - * Action configuration. - * @param[in, out] action_flags - * Pointer to the detected actions. * @param[in] dev_flow * Pointer to mlx5_flow. + * @param[in] action + * Action configuration. */ static void flow_verbs_translate_action_flag - (const struct rte_flow_action *action __rte_unused, - uint64_t *action_flags, - struct mlx5_flow *dev_flow) + (struct mlx5_flow *dev_flow, + const struct rte_flow_action *action __rte_unused) { unsigned int size = sizeof(struct ibv_flow_spec_action_tag); struct ibv_flow_spec_action_tag tag = { @@ -895,87 +921,44 @@ flow_verbs_translate_action_flag .size = size, .tag_id = mlx5_flow_mark_set(MLX5_FLOW_MARK_DEFAULT), }; - *action_flags |= MLX5_FLOW_ACTION_MARK; - flow_verbs_spec_add(dev_flow, &tag, size); -} -/** - * Update verbs specification to modify the flag to mark. - * - * @param[in, out] verbs - * Pointer to the mlx5_flow_verbs structure. - * @param[in] mark_id - * Mark identifier to replace the flag. - */ -static void -flow_verbs_mark_update(struct mlx5_flow_verbs *verbs, uint32_t mark_id) -{ - struct ibv_spec_header *hdr; - int i; - - if (!verbs) - return; - /* Update Verbs specification. */ - hdr = (struct ibv_spec_header *)verbs->specs; - if (!hdr) - return; - for (i = 0; i != verbs->attr->num_of_specs; ++i) { - if (hdr->type == IBV_FLOW_SPEC_ACTION_TAG) { - struct ibv_flow_spec_action_tag *t = - (struct ibv_flow_spec_action_tag *)hdr; - - t->tag_id = mlx5_flow_mark_set(mark_id); - } - hdr = (struct ibv_spec_header *)((uintptr_t)hdr + hdr->size); - } + flow_verbs_spec_add(&dev_flow->verbs, &tag, size); } /** * Convert the @p action into a Verbs specification. This function assumes that * the input is valid and that there is space to insert the requested action - * into the flow. This function also return the action that was added. + * into the flow. * - * @param[in] action - * Action configuration. - * @param[in, out] action_flags - * Pointer to the detected actions. * @param[in] dev_flow * Pointer to mlx5_flow. + * @param[in] action + * Action configuration. */ static void -flow_verbs_translate_action_mark(const struct rte_flow_action *action, - uint64_t *action_flags, - struct mlx5_flow *dev_flow) +flow_verbs_translate_action_mark(struct mlx5_flow *dev_flow, + const struct rte_flow_action *action) { const struct rte_flow_action_mark *mark = action->conf; unsigned int size = sizeof(struct ibv_flow_spec_action_tag); struct ibv_flow_spec_action_tag tag = { .type = IBV_FLOW_SPEC_ACTION_TAG, .size = size, + .tag_id = mlx5_flow_mark_set(mark->id), }; - struct mlx5_flow_verbs *verbs = &dev_flow->verbs; - if (*action_flags & MLX5_FLOW_ACTION_FLAG) { - flow_verbs_mark_update(verbs, mark->id); - size = 0; - } else { - tag.tag_id = mlx5_flow_mark_set(mark->id); - flow_verbs_spec_add(dev_flow, &tag, size); - } - *action_flags |= MLX5_FLOW_ACTION_MARK; + flow_verbs_spec_add(&dev_flow->verbs, &tag, size); } /** * Convert the @p action into a Verbs specification. This function assumes that * the input is valid and that there is space to insert the requested action - * into the flow. This function also return the action that was added. + * into the flow. * * @param[in] dev * Pointer to the Ethernet device structure. * @param[in] action * Action configuration. - * @param[in, out] action_flags - * Pointer to the detected actions. * @param[in] dev_flow * Pointer to mlx5_flow. * @param[out] error @@ -985,15 +968,15 @@ flow_verbs_translate_action_mark(const struct rte_flow_action *action, * 0 On success else a negative errno value is returned and rte_errno is set. */ static int -flow_verbs_translate_action_count(struct rte_eth_dev *dev, +flow_verbs_translate_action_count(struct mlx5_flow *dev_flow, const struct rte_flow_action *action, - uint64_t *action_flags, - struct mlx5_flow *dev_flow, + struct rte_eth_dev *dev, struct rte_flow_error *error) { const struct rte_flow_action_count *count = action->conf; struct rte_flow *flow = dev_flow->flow; -#ifdef HAVE_IBV_DEVICE_COUNTERS_SET_V42 +#if defined(HAVE_IBV_DEVICE_COUNTERS_SET_V42) || \ + defined(HAVE_IBV_DEVICE_COUNTERS_SET_V45) unsigned int size = sizeof(struct ibv_flow_spec_counter_action); struct ibv_flow_spec_counter_action counter = { .type = IBV_FLOW_SPEC_ACTION_COUNT, @@ -1011,10 +994,12 @@ flow_verbs_translate_action_count(struct rte_eth_dev *dev, "cannot get counter" " context."); } - *action_flags |= MLX5_FLOW_ACTION_COUNT; -#ifdef HAVE_IBV_DEVICE_COUNTERS_SET_V42 +#if defined(HAVE_IBV_DEVICE_COUNTERS_SET_V42) counter.counter_set_handle = flow->counter->cs->handle; - flow_verbs_spec_add(dev_flow, &counter, size); + flow_verbs_spec_add(&dev_flow->verbs, &counter, size); +#elif defined(HAVE_IBV_DEVICE_COUNTERS_SET_V45) + counter.counters = flow->counter->cs; + flow_verbs_spec_add(&dev_flow->verbs, &counter, size); #endif return 0; } @@ -1030,6 +1015,8 @@ flow_verbs_translate_action_count(struct rte_eth_dev *dev, * Pointer to the list of items. * @param[in] actions * Pointer to the list of actions. + * @param[in] external + * This flow rule is created by request external to PMD. * @param[out] error * Pointer to the error structure. * @@ -1041,13 +1028,15 @@ flow_verbs_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr, const struct rte_flow_item items[], const struct rte_flow_action actions[], + bool external __rte_unused, struct rte_flow_error *error) { int ret; - uint32_t action_flags = 0; - uint32_t item_flags = 0; - int tunnel = 0; + uint64_t action_flags = 0; + uint64_t item_flags = 0; + uint64_t last_item = 0; uint8_t next_protocol = 0xff; + uint16_t ether_type = 0; if (items == NULL) return -1; @@ -1055,7 +1044,9 @@ flow_verbs_validate(struct rte_eth_dev *dev, if (ret < 0) return ret; for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) { + int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL); int ret = 0; + switch (items->type) { case RTE_FLOW_ITEM_TYPE_VOID: break; @@ -1064,44 +1055,86 @@ flow_verbs_validate(struct rte_eth_dev *dev, error); if (ret < 0) return ret; - item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L2 : - MLX5_FLOW_LAYER_OUTER_L2; + last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L2 : + MLX5_FLOW_LAYER_OUTER_L2; + if (items->mask != NULL && items->spec != NULL) { + ether_type = + ((const struct rte_flow_item_eth *) + items->spec)->type; + ether_type &= + ((const struct rte_flow_item_eth *) + items->mask)->type; + ether_type = rte_be_to_cpu_16(ether_type); + } else { + ether_type = 0; + } break; case RTE_FLOW_ITEM_TYPE_VLAN: ret = mlx5_flow_validate_item_vlan(items, item_flags, - error); + dev, error); if (ret < 0) return ret; - item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_VLAN : - MLX5_FLOW_LAYER_OUTER_VLAN; + last_item = tunnel ? (MLX5_FLOW_LAYER_INNER_L2 | + MLX5_FLOW_LAYER_INNER_VLAN) : + (MLX5_FLOW_LAYER_OUTER_L2 | + MLX5_FLOW_LAYER_OUTER_VLAN); + if (items->mask != NULL && items->spec != NULL) { + ether_type = + ((const struct rte_flow_item_vlan *) + items->spec)->inner_type; + ether_type &= + ((const struct rte_flow_item_vlan *) + items->mask)->inner_type; + ether_type = rte_be_to_cpu_16(ether_type); + } else { + ether_type = 0; + } break; case RTE_FLOW_ITEM_TYPE_IPV4: ret = mlx5_flow_validate_item_ipv4(items, item_flags, + last_item, + ether_type, NULL, error); if (ret < 0) return ret; - item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 : - MLX5_FLOW_LAYER_OUTER_L3_IPV4; + last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 : + MLX5_FLOW_LAYER_OUTER_L3_IPV4; if (items->mask != NULL && ((const struct rte_flow_item_ipv4 *) - items->mask)->hdr.next_proto_id) + items->mask)->hdr.next_proto_id) { next_protocol = ((const struct rte_flow_item_ipv4 *) (items->spec))->hdr.next_proto_id; + next_protocol &= + ((const struct rte_flow_item_ipv4 *) + (items->mask))->hdr.next_proto_id; + } else { + /* Reset for inner layer. */ + next_protocol = 0xff; + } break; case RTE_FLOW_ITEM_TYPE_IPV6: ret = mlx5_flow_validate_item_ipv6(items, item_flags, + last_item, + ether_type, NULL, error); if (ret < 0) return ret; - item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 : - MLX5_FLOW_LAYER_OUTER_L3_IPV6; + last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 : + MLX5_FLOW_LAYER_OUTER_L3_IPV6; if (items->mask != NULL && ((const struct rte_flow_item_ipv6 *) - items->mask)->hdr.proto) + items->mask)->hdr.proto) { next_protocol = ((const struct rte_flow_item_ipv6 *) items->spec)->hdr.proto; + next_protocol &= + ((const struct rte_flow_item_ipv6 *) + items->mask)->hdr.proto; + } else { + /* Reset for inner layer. */ + next_protocol = 0xff; + } break; case RTE_FLOW_ITEM_TYPE_UDP: ret = mlx5_flow_validate_item_udp(items, item_flags, @@ -1109,8 +1142,8 @@ flow_verbs_validate(struct rte_eth_dev *dev, error); if (ret < 0) return ret; - item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP : - MLX5_FLOW_LAYER_OUTER_L4_UDP; + last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP : + MLX5_FLOW_LAYER_OUTER_L4_UDP; break; case RTE_FLOW_ITEM_TYPE_TCP: ret = mlx5_flow_validate_item_tcp @@ -1120,15 +1153,15 @@ flow_verbs_validate(struct rte_eth_dev *dev, error); if (ret < 0) return ret; - item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP : - MLX5_FLOW_LAYER_OUTER_L4_TCP; + last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP : + MLX5_FLOW_LAYER_OUTER_L4_TCP; break; case RTE_FLOW_ITEM_TYPE_VXLAN: ret = mlx5_flow_validate_item_vxlan(items, item_flags, error); if (ret < 0) return ret; - item_flags |= MLX5_FLOW_LAYER_VXLAN; + last_item = MLX5_FLOW_LAYER_VXLAN; break; case RTE_FLOW_ITEM_TYPE_VXLAN_GPE: ret = mlx5_flow_validate_item_vxlan_gpe(items, @@ -1136,38 +1169,31 @@ flow_verbs_validate(struct rte_eth_dev *dev, dev, error); if (ret < 0) return ret; - item_flags |= MLX5_FLOW_LAYER_VXLAN_GPE; + last_item = MLX5_FLOW_LAYER_VXLAN_GPE; break; case RTE_FLOW_ITEM_TYPE_GRE: ret = mlx5_flow_validate_item_gre(items, item_flags, next_protocol, error); if (ret < 0) return ret; - item_flags |= MLX5_FLOW_LAYER_GRE; + last_item = MLX5_FLOW_LAYER_GRE; break; case RTE_FLOW_ITEM_TYPE_MPLS: - ret = mlx5_flow_validate_item_mpls(items, item_flags, - next_protocol, - error); + ret = mlx5_flow_validate_item_mpls(dev, items, + item_flags, + last_item, error); if (ret < 0) return ret; - if (next_protocol != 0xff && - next_protocol != IPPROTO_MPLS) - return rte_flow_error_set - (error, EINVAL, - RTE_FLOW_ERROR_TYPE_ITEM, items, - "protocol filtering not compatible" - " with MPLS layer"); - item_flags |= MLX5_FLOW_LAYER_MPLS; + last_item = MLX5_FLOW_LAYER_MPLS; break; default: return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM, NULL, "item not supported"); } + item_flags |= last_item; } for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) { - tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL); switch (actions->type) { case RTE_FLOW_ACTION_TYPE_VOID: break; @@ -1208,7 +1234,7 @@ flow_verbs_validate(struct rte_eth_dev *dev, case RTE_FLOW_ACTION_TYPE_RSS: ret = mlx5_flow_validate_action_rss(actions, action_flags, dev, - attr, + attr, item_flags, error); if (ret < 0) return ret; @@ -1227,6 +1253,18 @@ flow_verbs_validate(struct rte_eth_dev *dev, "action not supported"); } } + /* + * Validate the drop action mutual exclusion with other actions. + * Drop action is mutually-exclusive with any other action, except for + * Count action. + */ + if ((action_flags & MLX5_FLOW_ACTION_DROP) && + (action_flags & ~(MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_COUNT))) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, NULL, + "Drop action is mutually-exclusive " + "with any other action, except for " + "Count action"); if (!(action_flags & MLX5_FLOW_FATE_ACTIONS)) return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION, actions, @@ -1236,23 +1274,18 @@ flow_verbs_validate(struct rte_eth_dev *dev, /** * Calculate the required bytes that are needed for the action part of the verbs - * flow, in addtion returns bit-fields with all the detected action, in order to - * avoid another interation over the actions. + * flow. * * @param[in] actions * Pointer to the list of actions. - * @param[out] action_flags - * Pointer to the detected actions. * * @return * The size of the memory needed for all actions. */ static int -flow_verbs_get_actions_and_size(const struct rte_flow_action actions[], - uint64_t *action_flags) +flow_verbs_get_actions_size(const struct rte_flow_action actions[]) { int size = 0; - uint64_t detected_actions = 0; for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) { switch (actions->type) { @@ -1260,56 +1293,44 @@ flow_verbs_get_actions_and_size(const struct rte_flow_action actions[], break; case RTE_FLOW_ACTION_TYPE_FLAG: size += sizeof(struct ibv_flow_spec_action_tag); - detected_actions |= MLX5_FLOW_ACTION_FLAG; break; case RTE_FLOW_ACTION_TYPE_MARK: size += sizeof(struct ibv_flow_spec_action_tag); - detected_actions |= MLX5_FLOW_ACTION_MARK; break; case RTE_FLOW_ACTION_TYPE_DROP: size += sizeof(struct ibv_flow_spec_action_drop); - detected_actions |= MLX5_FLOW_ACTION_DROP; break; case RTE_FLOW_ACTION_TYPE_QUEUE: - detected_actions |= MLX5_FLOW_ACTION_QUEUE; break; case RTE_FLOW_ACTION_TYPE_RSS: - detected_actions |= MLX5_FLOW_ACTION_RSS; break; case RTE_FLOW_ACTION_TYPE_COUNT: -#ifdef HAVE_IBV_DEVICE_COUNTERS_SET_V42 +#if defined(HAVE_IBV_DEVICE_COUNTERS_SET_V42) || \ + defined(HAVE_IBV_DEVICE_COUNTERS_SET_V45) size += sizeof(struct ibv_flow_spec_counter_action); #endif - detected_actions |= MLX5_FLOW_ACTION_COUNT; break; default: break; } } - *action_flags = detected_actions; return size; } /** * Calculate the required bytes that are needed for the item part of the verbs - * flow, in addtion returns bit-fields with all the detected action, in order to - * avoid another interation over the actions. + * flow. * - * @param[in] actions + * @param[in] items * Pointer to the list of items. - * @param[in, out] item_flags - * Pointer to the detected items. * * @return * The size of the memory needed for all items. */ static int -flow_verbs_get_items_and_size(const struct rte_flow_item items[], - uint64_t *item_flags) +flow_verbs_get_items_size(const struct rte_flow_item items[]) { int size = 0; - uint64_t detected_items = 0; - const int tunnel = !!(*item_flags & MLX5_FLOW_LAYER_TUNNEL); for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) { switch (items->type) { @@ -1317,66 +1338,44 @@ flow_verbs_get_items_and_size(const struct rte_flow_item items[], break; case RTE_FLOW_ITEM_TYPE_ETH: size += sizeof(struct ibv_flow_spec_eth); - detected_items |= tunnel ? MLX5_FLOW_LAYER_INNER_L2 : - MLX5_FLOW_LAYER_OUTER_L2; break; case RTE_FLOW_ITEM_TYPE_VLAN: size += sizeof(struct ibv_flow_spec_eth); - detected_items |= tunnel ? MLX5_FLOW_LAYER_INNER_VLAN : - MLX5_FLOW_LAYER_OUTER_VLAN; break; case RTE_FLOW_ITEM_TYPE_IPV4: size += sizeof(struct ibv_flow_spec_ipv4_ext); - detected_items |= tunnel ? - MLX5_FLOW_LAYER_INNER_L3_IPV4 : - MLX5_FLOW_LAYER_OUTER_L3_IPV4; break; case RTE_FLOW_ITEM_TYPE_IPV6: size += sizeof(struct ibv_flow_spec_ipv6); - detected_items |= tunnel ? - MLX5_FLOW_LAYER_INNER_L3_IPV6 : - MLX5_FLOW_LAYER_OUTER_L3_IPV6; break; case RTE_FLOW_ITEM_TYPE_UDP: size += sizeof(struct ibv_flow_spec_tcp_udp); - detected_items |= tunnel ? - MLX5_FLOW_LAYER_INNER_L4_UDP : - MLX5_FLOW_LAYER_OUTER_L4_UDP; break; case RTE_FLOW_ITEM_TYPE_TCP: size += sizeof(struct ibv_flow_spec_tcp_udp); - detected_items |= tunnel ? - MLX5_FLOW_LAYER_INNER_L4_TCP : - MLX5_FLOW_LAYER_OUTER_L4_TCP; break; case RTE_FLOW_ITEM_TYPE_VXLAN: size += sizeof(struct ibv_flow_spec_tunnel); - detected_items |= MLX5_FLOW_LAYER_VXLAN; break; case RTE_FLOW_ITEM_TYPE_VXLAN_GPE: size += sizeof(struct ibv_flow_spec_tunnel); - detected_items |= MLX5_FLOW_LAYER_VXLAN_GPE; break; #ifdef HAVE_IBV_DEVICE_MPLS_SUPPORT case RTE_FLOW_ITEM_TYPE_GRE: size += sizeof(struct ibv_flow_spec_gre); - detected_items |= MLX5_FLOW_LAYER_GRE; break; case RTE_FLOW_ITEM_TYPE_MPLS: size += sizeof(struct ibv_flow_spec_mpls); - detected_items |= MLX5_FLOW_LAYER_MPLS; break; #else case RTE_FLOW_ITEM_TYPE_GRE: size += sizeof(struct ibv_flow_spec_tunnel); - detected_items |= MLX5_FLOW_LAYER_TUNNEL; break; #endif default: break; } } - *item_flags = detected_items; return size; } @@ -1391,10 +1390,6 @@ flow_verbs_get_items_and_size(const struct rte_flow_item items[], * Pointer to the list of items. * @param[in] actions * Pointer to the list of actions. - * @param[out] item_flags - * Pointer to bit mask of all items detected. - * @param[out] action_flags - * Pointer to bit mask of all actions detected. * @param[out] error * Pointer to the error structure. * @@ -1406,26 +1401,25 @@ static struct mlx5_flow * flow_verbs_prepare(const struct rte_flow_attr *attr __rte_unused, const struct rte_flow_item items[], const struct rte_flow_action actions[], - uint64_t *item_flags, - uint64_t *action_flags, struct rte_flow_error *error) { - uint32_t size = sizeof(struct mlx5_flow) + sizeof(struct ibv_flow_attr); - struct mlx5_flow *flow; + size_t size = sizeof(struct mlx5_flow) + sizeof(struct ibv_flow_attr); + struct mlx5_flow *dev_flow; - size += flow_verbs_get_actions_and_size(actions, action_flags); - size += flow_verbs_get_items_and_size(items, item_flags); - flow = rte_calloc(__func__, 1, size, 0); - if (!flow) { + size += flow_verbs_get_actions_size(actions); + size += flow_verbs_get_items_size(items); + dev_flow = rte_calloc(__func__, 1, size, 0); + if (!dev_flow) { rte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, "not enough memory to create flow"); return NULL; } - flow->verbs.attr = (void *)(flow + 1); - flow->verbs.specs = - (uint8_t *)(flow + 1) + sizeof(struct ibv_flow_attr); - return flow; + dev_flow->verbs.attr = (void *)(dev_flow + 1); + dev_flow->verbs.specs = (void *)(dev_flow->verbs.attr + 1); + dev_flow->ingress = attr->ingress; + dev_flow->transfer = attr->transfer; + return dev_flow; } /** @@ -1445,7 +1439,7 @@ flow_verbs_prepare(const struct rte_flow_attr *attr __rte_unused, * Pointer to the error structure. * * @return - * 0 on success, else a negative errno value otherwise and rte_ernno is set. + * 0 on success, else a negative errno value otherwise and rte_errno is set. */ static int flow_verbs_translate(struct rte_eth_dev *dev, @@ -1455,50 +1449,47 @@ flow_verbs_translate(struct rte_eth_dev *dev, const struct rte_flow_action actions[], struct rte_flow_error *error) { - uint64_t action_flags = 0; uint64_t item_flags = 0; + uint64_t action_flags = 0; uint64_t priority = attr->priority; - struct priv *priv = dev->data->dev_private; + uint32_t subpriority = 0; + struct mlx5_priv *priv = dev->data->dev_private; if (priority == MLX5_FLOW_PRIO_RSVD) priority = priv->config.flow_prio - 1; for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) { int ret; + switch (actions->type) { case RTE_FLOW_ACTION_TYPE_VOID: break; case RTE_FLOW_ACTION_TYPE_FLAG: - flow_verbs_translate_action_flag(actions, - &action_flags, - dev_flow); + flow_verbs_translate_action_flag(dev_flow, actions); + action_flags |= MLX5_FLOW_ACTION_FLAG; break; case RTE_FLOW_ACTION_TYPE_MARK: - flow_verbs_translate_action_mark(actions, - &action_flags, - dev_flow); + flow_verbs_translate_action_mark(dev_flow, actions); + action_flags |= MLX5_FLOW_ACTION_MARK; break; case RTE_FLOW_ACTION_TYPE_DROP: - flow_verbs_translate_action_drop(&action_flags, - dev_flow); + flow_verbs_translate_action_drop(dev_flow, actions); + action_flags |= MLX5_FLOW_ACTION_DROP; break; case RTE_FLOW_ACTION_TYPE_QUEUE: - flow_verbs_translate_action_queue(actions, - &action_flags, - dev_flow); + flow_verbs_translate_action_queue(dev_flow, actions); + action_flags |= MLX5_FLOW_ACTION_QUEUE; break; case RTE_FLOW_ACTION_TYPE_RSS: - flow_verbs_translate_action_rss(actions, - &action_flags, - dev_flow); + flow_verbs_translate_action_rss(dev_flow, actions); + action_flags |= MLX5_FLOW_ACTION_RSS; break; case RTE_FLOW_ACTION_TYPE_COUNT: - ret = flow_verbs_translate_action_count(dev, + ret = flow_verbs_translate_action_count(dev_flow, actions, - &action_flags, - dev_flow, - error); + dev, error); if (ret < 0) return ret; + action_flags |= MLX5_FLOW_ACTION_COUNT; break; default: return rte_flow_error_set(error, ENOTSUP, @@ -1507,50 +1498,100 @@ flow_verbs_translate(struct rte_eth_dev *dev, "action not supported"); } } - dev_flow->flow->actions |= action_flags; + dev_flow->actions = action_flags; for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) { + int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL); + switch (items->type) { case RTE_FLOW_ITEM_TYPE_VOID: break; case RTE_FLOW_ITEM_TYPE_ETH: - flow_verbs_translate_item_eth(items, &item_flags, - dev_flow); + flow_verbs_translate_item_eth(dev_flow, items, + item_flags); + subpriority = MLX5_PRIORITY_MAP_L2; + item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L2 : + MLX5_FLOW_LAYER_OUTER_L2; break; case RTE_FLOW_ITEM_TYPE_VLAN: - flow_verbs_translate_item_vlan(items, &item_flags, - dev_flow); + flow_verbs_translate_item_vlan(dev_flow, items, + item_flags); + subpriority = MLX5_PRIORITY_MAP_L2; + item_flags |= tunnel ? (MLX5_FLOW_LAYER_INNER_L2 | + MLX5_FLOW_LAYER_INNER_VLAN) : + (MLX5_FLOW_LAYER_OUTER_L2 | + MLX5_FLOW_LAYER_OUTER_VLAN); break; case RTE_FLOW_ITEM_TYPE_IPV4: - flow_verbs_translate_item_ipv4(items, &item_flags, - dev_flow); + flow_verbs_translate_item_ipv4(dev_flow, items, + item_flags); + subpriority = MLX5_PRIORITY_MAP_L3; + dev_flow->hash_fields |= + mlx5_flow_hashfields_adjust + (dev_flow, tunnel, + MLX5_IPV4_LAYER_TYPES, + MLX5_IPV4_IBV_RX_HASH); + item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 : + MLX5_FLOW_LAYER_OUTER_L3_IPV4; break; case RTE_FLOW_ITEM_TYPE_IPV6: - flow_verbs_translate_item_ipv6(items, &item_flags, - dev_flow); - break; - case RTE_FLOW_ITEM_TYPE_UDP: - flow_verbs_translate_item_udp(items, &item_flags, - dev_flow); + flow_verbs_translate_item_ipv6(dev_flow, items, + item_flags); + subpriority = MLX5_PRIORITY_MAP_L3; + dev_flow->hash_fields |= + mlx5_flow_hashfields_adjust + (dev_flow, tunnel, + MLX5_IPV6_LAYER_TYPES, + MLX5_IPV6_IBV_RX_HASH); + item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 : + MLX5_FLOW_LAYER_OUTER_L3_IPV6; break; case RTE_FLOW_ITEM_TYPE_TCP: - flow_verbs_translate_item_tcp(items, &item_flags, - dev_flow); + flow_verbs_translate_item_tcp(dev_flow, items, + item_flags); + subpriority = MLX5_PRIORITY_MAP_L4; + dev_flow->hash_fields |= + mlx5_flow_hashfields_adjust + (dev_flow, tunnel, ETH_RSS_TCP, + (IBV_RX_HASH_SRC_PORT_TCP | + IBV_RX_HASH_DST_PORT_TCP)); + item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP : + MLX5_FLOW_LAYER_OUTER_L4_TCP; + break; + case RTE_FLOW_ITEM_TYPE_UDP: + flow_verbs_translate_item_udp(dev_flow, items, + item_flags); + subpriority = MLX5_PRIORITY_MAP_L4; + dev_flow->hash_fields |= + mlx5_flow_hashfields_adjust + (dev_flow, tunnel, ETH_RSS_UDP, + (IBV_RX_HASH_SRC_PORT_UDP | + IBV_RX_HASH_DST_PORT_UDP)); + item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP : + MLX5_FLOW_LAYER_OUTER_L4_UDP; break; case RTE_FLOW_ITEM_TYPE_VXLAN: - flow_verbs_translate_item_vxlan(items, &item_flags, - dev_flow); + flow_verbs_translate_item_vxlan(dev_flow, items, + item_flags); + subpriority = MLX5_PRIORITY_MAP_L2; + item_flags |= MLX5_FLOW_LAYER_VXLAN; break; case RTE_FLOW_ITEM_TYPE_VXLAN_GPE: - flow_verbs_translate_item_vxlan_gpe(items, &item_flags, - dev_flow); + flow_verbs_translate_item_vxlan_gpe(dev_flow, items, + item_flags); + subpriority = MLX5_PRIORITY_MAP_L2; + item_flags |= MLX5_FLOW_LAYER_VXLAN_GPE; break; case RTE_FLOW_ITEM_TYPE_GRE: - flow_verbs_translate_item_gre(items, &item_flags, - dev_flow); + flow_verbs_translate_item_gre(dev_flow, items, + item_flags); + subpriority = MLX5_PRIORITY_MAP_L2; + item_flags |= MLX5_FLOW_LAYER_GRE; break; case RTE_FLOW_ITEM_TYPE_MPLS: - flow_verbs_translate_item_mpls(items, &item_flags, - dev_flow); + flow_verbs_translate_item_mpls(dev_flow, items, + item_flags); + subpriority = MLX5_PRIORITY_MAP_L2; + item_flags |= MLX5_FLOW_LAYER_MPLS; break; default: return rte_flow_error_set(error, ENOTSUP, @@ -1559,9 +1600,10 @@ flow_verbs_translate(struct rte_eth_dev *dev, "item not supported"); } } + dev_flow->layers = item_flags; dev_flow->verbs.attr->priority = - mlx5_flow_adjust_priority(dev, priority, - dev_flow->verbs.attr->priority); + mlx5_flow_adjust_priority(dev, priority, subpriority); + dev_flow->verbs.attr->port = (uint8_t)priv->ibv_port; return 0; } @@ -1588,16 +1630,16 @@ flow_verbs_remove(struct rte_eth_dev *dev, struct rte_flow *flow) verbs->flow = NULL; } if (verbs->hrxq) { - if (flow->actions & MLX5_FLOW_ACTION_DROP) + if (dev_flow->actions & MLX5_FLOW_ACTION_DROP) mlx5_hrxq_drop_release(dev); else mlx5_hrxq_release(dev, verbs->hrxq); verbs->hrxq = NULL; } - } - if (flow->counter) { - flow_verbs_counter_release(flow->counter); - flow->counter = NULL; + if (dev_flow->verbs.vf_vlan.tag && + dev_flow->verbs.vf_vlan.created) { + mlx5_vlan_vmwa_release(dev, &dev_flow->verbs.vf_vlan); + } } } @@ -1622,6 +1664,10 @@ flow_verbs_destroy(struct rte_eth_dev *dev, struct rte_flow *flow) LIST_REMOVE(dev_flow, next); rte_free(dev_flow); } + if (flow->counter) { + flow_verbs_counter_release(dev, flow->counter); + flow->counter = NULL; + } } /** @@ -1641,13 +1687,14 @@ static int flow_verbs_apply(struct rte_eth_dev *dev, struct rte_flow *flow, struct rte_flow_error *error) { + struct mlx5_priv *priv = dev->data->dev_private; struct mlx5_flow_verbs *verbs; struct mlx5_flow *dev_flow; int err; LIST_FOREACH(dev_flow, &flow->dev_flows, next) { verbs = &dev_flow->verbs; - if (flow->actions & MLX5_FLOW_ACTION_DROP) { + if (dev_flow->actions & MLX5_FLOW_ACTION_DROP) { verbs->hrxq = mlx5_hrxq_drop_new(dev); if (!verbs->hrxq) { rte_flow_error_set @@ -1659,19 +1706,20 @@ flow_verbs_apply(struct rte_eth_dev *dev, struct rte_flow *flow, } else { struct mlx5_hrxq *hrxq; - hrxq = mlx5_hrxq_get(dev, flow->key, + MLX5_ASSERT(flow->rss.queue); + hrxq = mlx5_hrxq_get(dev, flow->rss.key, MLX5_RSS_HASH_KEY_LEN, - verbs->hash_fields, - (*flow->queue), + dev_flow->hash_fields, + (*flow->rss.queue), flow->rss.queue_num); if (!hrxq) - hrxq = mlx5_hrxq_new(dev, flow->key, + hrxq = mlx5_hrxq_new(dev, flow->rss.key, MLX5_RSS_HASH_KEY_LEN, - verbs->hash_fields, - (*flow->queue), + dev_flow->hash_fields, + (*flow->rss.queue), flow->rss.queue_num, - !!(flow->layers & - MLX5_FLOW_LAYER_TUNNEL)); + !!(dev_flow->layers & + MLX5_FLOW_LAYER_TUNNEL)); if (!hrxq) { rte_flow_error_set (error, rte_errno, @@ -1690,6 +1738,17 @@ flow_verbs_apply(struct rte_eth_dev *dev, struct rte_flow *flow, "hardware refuses to create flow"); goto error; } + if (priv->vmwa_context && + dev_flow->verbs.vf_vlan.tag && + !dev_flow->verbs.vf_vlan.created) { + /* + * The rule contains the VLAN pattern. + * For VF we are going to create VLAN + * interface to make hypervisor set correct + * e-Switch vport context. + */ + mlx5_vlan_vmwa_acquire(dev, &dev_flow->verbs.vf_vlan); + } } return 0; error: @@ -1697,12 +1756,16 @@ error: LIST_FOREACH(dev_flow, &flow->dev_flows, next) { verbs = &dev_flow->verbs; if (verbs->hrxq) { - if (flow->actions & MLX5_FLOW_ACTION_DROP) + if (dev_flow->actions & MLX5_FLOW_ACTION_DROP) mlx5_hrxq_drop_release(dev); else mlx5_hrxq_release(dev, verbs->hrxq); verbs->hrxq = NULL; } + if (dev_flow->verbs.vf_vlan.tag && + dev_flow->verbs.vf_vlan.created) { + mlx5_vlan_vmwa_release(dev, &dev_flow->verbs.vf_vlan); + } } rte_errno = err; /* Restore rte_errno. */ return -rte_errno;