net/mlx5: extend IPv6 flow item
[dpdk.git] / drivers / net / mlx5 / mlx5_flow.c
index 0e7ea99..a885f6e 100644 (file)
@@ -111,6 +111,12 @@ struct mlx5_flow_items {
        const enum rte_flow_action_type *const actions;
        /** Bit-masks corresponding to the possibilities for the item. */
        const void *mask;
+       /**
+        * Default bit-masks to use when item->mask is not provided. When
+        * \default_mask is also NULL, the full supported bit-mask (\mask) is
+        * used instead.
+        */
+       const void *default_mask;
        /** Bit-masks size in bytes. */
        const unsigned int mask_sz;
        /**
@@ -157,7 +163,9 @@ static const struct mlx5_flow_items mlx5_flow_items[] = {
                .mask = &(const struct rte_flow_item_eth){
                        .dst.addr_bytes = "\xff\xff\xff\xff\xff\xff",
                        .src.addr_bytes = "\xff\xff\xff\xff\xff\xff",
+                       .type = -1,
                },
+               .default_mask = &rte_flow_item_eth_mask,
                .mask_sz = sizeof(struct rte_flow_item_eth),
                .convert = mlx5_flow_create_eth,
                .dst_sz = sizeof(struct ibv_exp_flow_spec_eth),
@@ -169,6 +177,7 @@ static const struct mlx5_flow_items mlx5_flow_items[] = {
                .mask = &(const struct rte_flow_item_vlan){
                        .tci = -1,
                },
+               .default_mask = &rte_flow_item_vlan_mask,
                .mask_sz = sizeof(struct rte_flow_item_vlan),
                .convert = mlx5_flow_create_vlan,
                .dst_sz = 0,
@@ -181,11 +190,14 @@ static const struct mlx5_flow_items mlx5_flow_items[] = {
                        .hdr = {
                                .src_addr = -1,
                                .dst_addr = -1,
+                               .type_of_service = -1,
+                               .next_proto_id = -1,
                        },
                },
+               .default_mask = &rte_flow_item_ipv4_mask,
                .mask_sz = sizeof(struct rte_flow_item_ipv4),
                .convert = mlx5_flow_create_ipv4,
-               .dst_sz = sizeof(struct ibv_exp_flow_spec_ipv4),
+               .dst_sz = sizeof(struct ibv_exp_flow_spec_ipv4_ext),
        },
        [RTE_FLOW_ITEM_TYPE_IPV6] = {
                .items = ITEMS(RTE_FLOW_ITEM_TYPE_UDP,
@@ -205,11 +217,15 @@ static const struct mlx5_flow_items mlx5_flow_items[] = {
                                        0xff, 0xff, 0xff, 0xff,
                                        0xff, 0xff, 0xff, 0xff,
                                },
+                               .vtc_flow = -1,
+                               .proto = -1,
+                               .hop_limits = -1,
                        },
                },
+               .default_mask = &rte_flow_item_ipv6_mask,
                .mask_sz = sizeof(struct rte_flow_item_ipv6),
                .convert = mlx5_flow_create_ipv6,
-               .dst_sz = sizeof(struct ibv_exp_flow_spec_ipv6),
+               .dst_sz = sizeof(struct ibv_exp_flow_spec_ipv6_ext),
        },
        [RTE_FLOW_ITEM_TYPE_UDP] = {
                .items = ITEMS(RTE_FLOW_ITEM_TYPE_VXLAN),
@@ -220,6 +236,7 @@ static const struct mlx5_flow_items mlx5_flow_items[] = {
                                .dst_port = -1,
                        },
                },
+               .default_mask = &rte_flow_item_udp_mask,
                .mask_sz = sizeof(struct rte_flow_item_udp),
                .convert = mlx5_flow_create_udp,
                .dst_sz = sizeof(struct ibv_exp_flow_spec_tcp_udp),
@@ -232,6 +249,7 @@ static const struct mlx5_flow_items mlx5_flow_items[] = {
                                .dst_port = -1,
                        },
                },
+               .default_mask = &rte_flow_item_tcp_mask,
                .mask_sz = sizeof(struct rte_flow_item_tcp),
                .convert = mlx5_flow_create_tcp,
                .dst_sz = sizeof(struct ibv_exp_flow_spec_tcp_udp),
@@ -242,6 +260,7 @@ static const struct mlx5_flow_items mlx5_flow_items[] = {
                .mask = &(const struct rte_flow_item_vxlan){
                        .vni = "\xff\xff\xff",
                },
+               .default_mask = &rte_flow_item_vxlan_mask,
                .mask_sz = sizeof(struct rte_flow_item_vxlan),
                .convert = mlx5_flow_create_vxlan,
                .dst_sz = sizeof(struct ibv_exp_flow_spec_tunnel),
@@ -396,17 +415,6 @@ priv_flow_validate(struct priv *priv,
 
                if (items->type == RTE_FLOW_ITEM_TYPE_VOID)
                        continue;
-               /* Handle special situation for VLAN. */
-               if (items->type == RTE_FLOW_ITEM_TYPE_VLAN) {
-                       if (((const struct rte_flow_item_vlan *)items)->tci >
-                           ETHER_MAX_VLAN_ID) {
-                               rte_flow_error_set(error, ENOTSUP,
-                                                  RTE_FLOW_ERROR_TYPE_ITEM,
-                                                  items,
-                                                  "wrong VLAN id value");
-                               return -rte_errno;
-                       }
-               }
                for (i = 0;
                     cur_item->items &&
                     cur_item->items[i] != RTE_FLOW_ITEM_TYPE_END;
@@ -421,11 +429,15 @@ priv_flow_validate(struct priv *priv,
                cur_item = token;
                err = mlx5_flow_item_validate(items,
                                              (const uint8_t *)cur_item->mask,
-                                             sizeof(cur_item->mask_sz));
+                                             cur_item->mask_sz);
                if (err)
                        goto exit_item_not_supported;
                if (flow->ibv_attr && cur_item->convert) {
-                       err = cur_item->convert(items, cur_item->mask, flow);
+                       err = cur_item->convert(items,
+                                               (cur_item->default_mask ?
+                                                cur_item->default_mask :
+                                                cur_item->mask),
+                                               flow);
                        if (err)
                                goto exit_item_not_supported;
                }
@@ -449,7 +461,13 @@ priv_flow_validate(struct priv *priv,
                                (const struct rte_flow_action_mark *)
                                actions->conf;
 
-                       if (mark && (mark->id >= MLX5_FLOW_MARK_MAX)) {
+                       if (!mark) {
+                               rte_flow_error_set(error, EINVAL,
+                                                  RTE_FLOW_ERROR_TYPE_ACTION,
+                                                  actions,
+                                                  "mark must be defined");
+                               return -rte_errno;
+                       } else if (mark->id >= MLX5_FLOW_MARK_MAX) {
                                rte_flow_error_set(error, ENOTSUP,
                                                   RTE_FLOW_ERROR_TYPE_ACTION,
                                                   actions,
@@ -462,7 +480,7 @@ priv_flow_validate(struct priv *priv,
                        goto exit_action_not_supported;
                }
        }
-       if (action.mark && !flow->ibv_attr)
+       if (action.mark && !flow->ibv_attr && !action.drop)
                flow->offset += sizeof(struct ibv_exp_flow_spec_action_tag);
        if (!action.queue && !action.drop) {
                rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE,
@@ -538,13 +556,16 @@ mlx5_flow_create_eth(const struct rte_flow_item *item,
                mask = default_mask;
        memcpy(eth->val.dst_mac, spec->dst.addr_bytes, ETHER_ADDR_LEN);
        memcpy(eth->val.src_mac, spec->src.addr_bytes, ETHER_ADDR_LEN);
+       eth->val.ether_type = spec->type;
        memcpy(eth->mask.dst_mac, mask->dst.addr_bytes, ETHER_ADDR_LEN);
        memcpy(eth->mask.src_mac, mask->src.addr_bytes, ETHER_ADDR_LEN);
+       eth->mask.ether_type = mask->type;
        /* Remove unwanted bits from values. */
        for (i = 0; i < 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;
        return 0;
 }
 
@@ -598,31 +619,37 @@ mlx5_flow_create_ipv4(const struct rte_flow_item *item,
        const struct rte_flow_item_ipv4 *spec = item->spec;
        const struct rte_flow_item_ipv4 *mask = item->mask;
        struct mlx5_flow *flow = (struct mlx5_flow *)data;
-       struct ibv_exp_flow_spec_ipv4 *ipv4;
-       unsigned int ipv4_size = sizeof(struct ibv_exp_flow_spec_ipv4);
+       struct ibv_exp_flow_spec_ipv4_ext *ipv4;
+       unsigned int ipv4_size = sizeof(struct ibv_exp_flow_spec_ipv4_ext);
 
        ++flow->ibv_attr->num_of_specs;
        flow->ibv_attr->priority = 1;
        ipv4 = (void *)((uintptr_t)flow->ibv_attr + flow->offset);
-       *ipv4 = (struct ibv_exp_flow_spec_ipv4) {
-               .type = flow->inner | IBV_EXP_FLOW_SPEC_IPV4,
+       *ipv4 = (struct ibv_exp_flow_spec_ipv4_ext) {
+               .type = flow->inner | IBV_EXP_FLOW_SPEC_IPV4_EXT,
                .size = ipv4_size,
        };
        if (!spec)
                return 0;
        if (!mask)
                mask = default_mask;
-       ipv4->val = (struct ibv_exp_flow_ipv4_filter){
+       ipv4->val = (struct ibv_exp_flow_ipv4_ext_filter){
                .src_ip = spec->hdr.src_addr,
                .dst_ip = spec->hdr.dst_addr,
+               .proto = spec->hdr.next_proto_id,
+               .tos = spec->hdr.type_of_service,
        };
-       ipv4->mask = (struct ibv_exp_flow_ipv4_filter){
+       ipv4->mask = (struct ibv_exp_flow_ipv4_ext_filter){
                .src_ip = mask->hdr.src_addr,
                .dst_ip = mask->hdr.dst_addr,
+               .proto = mask->hdr.next_proto_id,
+               .tos = mask->hdr.type_of_service,
        };
        /* Remove unwanted bits from values. */
        ipv4->val.src_ip &= ipv4->mask.src_ip;
        ipv4->val.dst_ip &= ipv4->mask.dst_ip;
+       ipv4->val.proto &= ipv4->mask.proto;
+       ipv4->val.tos &= ipv4->mask.tos;
        return 0;
 }
 
@@ -644,15 +671,14 @@ mlx5_flow_create_ipv6(const struct rte_flow_item *item,
        const struct rte_flow_item_ipv6 *spec = item->spec;
        const struct rte_flow_item_ipv6 *mask = item->mask;
        struct mlx5_flow *flow = (struct mlx5_flow *)data;
-       struct ibv_exp_flow_spec_ipv6 *ipv6;
-       unsigned int ipv6_size = sizeof(struct ibv_exp_flow_spec_ipv6);
-       unsigned int i;
+       struct ibv_exp_flow_spec_ipv6_ext *ipv6;
+       unsigned int ipv6_size = sizeof(struct ibv_exp_flow_spec_ipv6_ext);
 
        ++flow->ibv_attr->num_of_specs;
        flow->ibv_attr->priority = 1;
        ipv6 = (void *)((uintptr_t)flow->ibv_attr + flow->offset);
-       *ipv6 = (struct ibv_exp_flow_spec_ipv6) {
-               .type = flow->inner | IBV_EXP_FLOW_SPEC_IPV6,
+       *ipv6 = (struct ibv_exp_flow_spec_ipv6_ext) {
+               .type = flow->inner | IBV_EXP_FLOW_SPEC_IPV6_EXT,
                .size = ipv6_size,
        };
        if (!spec)
@@ -667,11 +693,12 @@ mlx5_flow_create_ipv6(const struct rte_flow_item *item,
               RTE_DIM(ipv6->mask.src_ip));
        memcpy(ipv6->mask.dst_ip, mask->hdr.dst_addr,
               RTE_DIM(ipv6->mask.dst_ip));
-       /* 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];
-               ipv6->val.dst_ip[i] &= ipv6->mask.dst_ip[i];
-       }
+       ipv6->mask.flow_label = mask->hdr.vtc_flow;
+       ipv6->mask.next_hdr = mask->hdr.proto;
+       ipv6->mask.hop_limit = mask->hdr.hop_limits;
+       ipv6->val.flow_label &= ipv6->mask.flow_label;
+       ipv6->val.next_hdr &= ipv6->mask.next_hdr;
+       ipv6->val.hop_limit &= ipv6->mask.hop_limit;
        return 0;
 }
 
@@ -882,6 +909,12 @@ priv_flow_create_action_queue(struct priv *priv,
                                                 .pd = priv->pd,
                                                 .cq = rte_flow->cq,
                                                 });
+               if (!rte_flow->wq) {
+                       rte_flow_error_set(error, ENOMEM,
+                                          RTE_FLOW_ERROR_TYPE_HANDLE,
+                                          NULL, "cannot allocate WQ");
+                       goto error;
+               }
        } else {
                rxq = container_of((*priv->rxqs)[action->queue_id],
                                   struct rxq_ctrl, rxq);
@@ -928,6 +961,8 @@ priv_flow_create_action_queue(struct priv *priv,
                                   NULL, "cannot allocate QP");
                goto error;
        }
+       if (!priv->started)
+               return rte_flow;
        rte_flow->ibv_flow = ibv_exp_create_flow(rte_flow->qp,
                                                 rte_flow->ibv_attr);
        if (!rte_flow->ibv_flow) {
@@ -946,7 +981,6 @@ error:
                ibv_exp_destroy_wq(rte_flow->wq);
        if (!rte_flow->rxq && rte_flow->cq)
                ibv_destroy_cq(rte_flow->cq);
-       rte_free(rte_flow->ibv_attr);
        rte_free(rte_flow);
        return NULL;
 }
@@ -1018,6 +1052,7 @@ priv_flow_create(struct priv *priv,
                                 actions->conf)->index;
                } else if (actions->type == RTE_FLOW_ACTION_TYPE_DROP) {
                        action.drop = 1;
+                       action.mark = 0;
                } else if (actions->type == RTE_FLOW_ACTION_TYPE_MARK) {
                        const struct rte_flow_action_mark *mark =
                                (const struct rte_flow_action_mark *)
@@ -1025,7 +1060,7 @@ priv_flow_create(struct priv *priv,
 
                        if (mark)
                                action.mark_id = mark->id;
-                       action.mark = 1;
+                       action.mark = !action.drop;
                } else {
                        rte_flow_error_set(error, ENOTSUP,
                                           RTE_FLOW_ERROR_TYPE_ACTION,
@@ -1039,6 +1074,8 @@ priv_flow_create(struct priv *priv,
        }
        rte_flow = priv_flow_create_action_queue(priv, flow.ibv_attr,
                                                 &action, error);
+       if (!rte_flow)
+               goto exit;
        return rte_flow;
 exit:
        rte_free(flow.ibv_attr);