On Thu, Nov 01, 2018 at 05:19:27AM -0700, Slava Ovsiienko wrote:
> This patch adds VXLAN support for flow item/action lists validation.
> The following entities are now supported:
> 
> - RTE_FLOW_ITEM_TYPE_VXLAN, contains the tunnel VNI
> 
> - RTE_FLOW_ACTION_TYPE_VXLAN_DECAP, if this action is specified
>   the items in the flow items list treated as outer  network
>   parameters for tunnel outer header match. The ethernet layer
>   addresses always are treated as inner ones.
> 
> - RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP, contains the item list to
>   build the encapsulation header. In current implementation the
>   values is the subject for some constraints:
>     - outer source MAC address will be always unconditionally
>       set to the one of MAC addresses of outer egress interface
>     - no way to specify source UDP port
>     - all abovementioned parameters are ignored if specified
>       in the rule, warning messages are sent to the log
> 
> Minimal tunneling support is also added. If VXLAN decapsulation
> action is specified the ETH item can follow the VXLAN VNI item,
> the content of this ETH item is treated as inner MAC addresses
> and type. The outer ETH item for VXLAN decapsulation action
> is always ignored.
> 
> Suggested-by: Adrien Mazarguil <adrien.mazarg...@6wind.com>
> Signed-off-by: Viacheslav Ovsiienko <viachesl...@mellanox.com>
> ---

Overall, it is so good. But please make some cosmetic changes. Refer to my
comments below. When you send out v4 with the changes, please put my acked-by
tag.

>  drivers/net/mlx5/mlx5_flow_tcf.c | 741 
> ++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 739 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/net/mlx5/mlx5_flow_tcf.c 
> b/drivers/net/mlx5/mlx5_flow_tcf.c
> index 50f3bd1..7e00232 100644
> --- a/drivers/net/mlx5/mlx5_flow_tcf.c
> +++ b/drivers/net/mlx5/mlx5_flow_tcf.c
> @@ -1116,6 +1116,633 @@ struct pedit_parser {
>  }
>  
>  /**
> + * Validate VXLAN_ENCAP action RTE_FLOW_ITEM_TYPE_ETH item for E-Switch.
> + * The routine checks the L2 fields to be used in encapsulation header.
> + *
> + * @param[in] item
> + *   Pointer to the item structure.
> + * @param[out] error
> + *   Pointer to the error structure.
> + *
> + * @return
> + *   0 on success, a negative errno value otherwise and rte_errno is set.
> + **/
> +static int
> +flow_tcf_validate_vxlan_encap_eth(const struct rte_flow_item *item,
> +                               struct rte_flow_error *error)
> +{
> +     const struct rte_flow_item_eth *spec = item->spec;
> +     const struct rte_flow_item_eth *mask = item->mask;
> +
> +     if (!spec)
> +             /*
> +              * Specification for L2 addresses can be empty
> +              * because these ones are optional and not
> +              * required directly by tc rule. Kernel tries
> +              * to resolve these ones on its own
> +              */
> +             return 0;

Even if it is one line of code, let's use bracket {} because it is multiple
lines with a comment. Without bracket, it could cause a bug if more lines are
added later because people would have wrong impression that there're already
brackets. Please also fix a few more occurrences below.

> +     if (!mask)
> +             /* If mask is not specified use the default one. */
> +             mask = &rte_flow_item_eth_mask;
> +     if (memcmp(&mask->dst,
> +                &flow_tcf_mask_empty.eth.dst,
> +                sizeof(flow_tcf_mask_empty.eth.dst))) {
> +             if (memcmp(&mask->dst,
> +                        &rte_flow_item_eth_mask.dst,
> +                        sizeof(rte_flow_item_eth_mask.dst)))
> +                     return rte_flow_error_set(error, ENOTSUP,
> +                              RTE_FLOW_ERROR_TYPE_ITEM_MASK, mask,
> +                              "no support for partial mask on"
> +                              " \"eth.dst\" field");

The following would be better,
                        return rte_flow_error_set(error, ENOTSUP,
                                                  RTE_FLOW_ERROR_TYPE_ITEM_MASK,
                                                  mask,
                                                  "no support for partial mask"
                                                  " on \"eth.dst\" field");

But, this one is also acceptable (to minimize your effort of correction :-)
                        return rte_flow_error_set
                                (error, ENOTSUP,
                                 RTE_FLOW_ERROR_TYPE_ITEM_MASK, mask,
                                 "no support for partial mask on"
                                 " \"eth.dst\" field");

Please make the same changes for the entire patch set.

Thanks,
Yongseok

> +     }
> +     if (memcmp(&mask->src,
> +                &flow_tcf_mask_empty.eth.src,
> +                sizeof(flow_tcf_mask_empty.eth.src))) {
> +             if (memcmp(&mask->src,
> +                        &rte_flow_item_eth_mask.src,
> +                        sizeof(rte_flow_item_eth_mask.src)))
> +                     return rte_flow_error_set(error, ENOTSUP,
> +                              RTE_FLOW_ERROR_TYPE_ITEM_MASK, mask,
> +                              "no support for partial mask on"
> +                              " \"eth.src\" field");
> +     }
> +     if (mask->type != RTE_BE16(0x0000)) {
> +             if (mask->type != RTE_BE16(0xffff))
> +                     return rte_flow_error_set(error, ENOTSUP,
> +                              RTE_FLOW_ERROR_TYPE_ITEM_MASK, mask,
> +                              "no support for partial mask on"
> +                              " \"eth.type\" field");
> +             DRV_LOG(WARNING,
> +                     "outer ethernet type field"
> +                     " cannot be forced for vxlan"
> +                     " encapsulation, parameter ignored");
> +     }
> +     return 0;
> +}
> +
> +/**
> + * Validate VXLAN_ENCAP action RTE_FLOW_ITEM_TYPE_IPV4 item for E-Switch.
> + * The routine checks the IPv4 fields to be used in encapsulation header.
> + *
> + * @param[in] item
> + *   Pointer to the item structure.
> + * @param[out] error
> + *   Pointer to the error structure.
> + *
> + * @return
> + *   0 on success, a negative errno value otherwise and rte_errno is set.
> + **/
> +static int
> +flow_tcf_validate_vxlan_encap_ipv4(const struct rte_flow_item *item,
> +                                struct rte_flow_error *error)
> +{
> +     const struct rte_flow_item_ipv4 *spec = item->spec;
> +     const struct rte_flow_item_ipv4 *mask = item->mask;
> +
> +     if (!spec)
> +             /*
> +              * Specification for IP addresses cannot be empty
> +              * because it is required by tunnel_key parameter.
> +              */
> +             return rte_flow_error_set(error, EINVAL,
> +                              RTE_FLOW_ERROR_TYPE_ITEM, item,
> +                              "NULL outer ipv4 address specification"
> +                              " for vxlan encapsulation");
> +     if (!mask)
> +             mask = &rte_flow_item_ipv4_mask;
> +     if (mask->hdr.dst_addr != RTE_BE32(0x00000000)) {
> +             if (mask->hdr.dst_addr != RTE_BE32(0xffffffff))
> +                     return rte_flow_error_set(error, ENOTSUP,
> +                              RTE_FLOW_ERROR_TYPE_ITEM_MASK, mask,
> +                              "no support for partial mask on"
> +                              " \"ipv4.hdr.dst_addr\" field"
> +                              " for vxlan encapsulation");
> +             /* More IPv4 address validations can be put here. */
> +     } else {
> +             /*
> +              * Kernel uses the destination IP address to determine
> +              * the routing path and obtain the MAC destination
> +              * address, so IP destination address must be
> +              * specified in the tc rule.
> +              */
> +             return rte_flow_error_set(error, EINVAL,
> +                              RTE_FLOW_ERROR_TYPE_ITEM, item,
> +                              "outer ipv4 destination address must be"
> +                              " specified for vxlan encapsulation");
> +     }
> +     if (mask->hdr.src_addr != RTE_BE32(0x00000000)) {
> +             if (mask->hdr.src_addr != RTE_BE32(0xffffffff))
> +                     return rte_flow_error_set(error, ENOTSUP,
> +                              RTE_FLOW_ERROR_TYPE_ITEM_MASK, mask,
> +                              "no support for partial mask on"
> +                              " \"ipv4.hdr.src_addr\" field"
> +                              " for vxlan encapsulation");
> +             /* More IPv4 address validations can be put here. */
> +     } else {
> +             /*
> +              * Kernel uses the source IP address to select the
> +              * interface for egress encapsulated traffic, so
> +              * it must be specified in the tc rule.
> +              */
> +             return rte_flow_error_set(error, EINVAL,
> +                              RTE_FLOW_ERROR_TYPE_ITEM, item,
> +                              "outer ipv4 source address must be"
> +                              " specified for vxlan encapsulation");
> +     }
> +     return 0;
> +}
> +
> +/**
> + * Validate VXLAN_ENCAP action RTE_FLOW_ITEM_TYPE_IPV6 item for E-Switch.
> + * The routine checks the IPv6 fields to be used in encapsulation header.
> + *
> + * @param[in] item
> + *   Pointer to the item structure.
> + * @param[out] error
> + *   Pointer to the error structure.
> + *
> + * @return
> + *   0 on success, a negative errno value otherwise and rte_ernno is set.
> + **/
> +static int
> +flow_tcf_validate_vxlan_encap_ipv6(const struct rte_flow_item *item,
> +                                struct rte_flow_error *error)
> +{
> +     const struct rte_flow_item_ipv6 *spec = item->spec;
> +     const struct rte_flow_item_ipv6 *mask = item->mask;
> +
> +     if (!spec)
> +             /*
> +              * Specification for IP addresses cannot be empty
> +              * because it is required by tunnel_key parameter.
> +              */
> +             return rte_flow_error_set(error, EINVAL,
> +                              RTE_FLOW_ERROR_TYPE_ITEM, item,
> +                              "NULL outer ipv6 address specification"
> +                              " for vxlan encapsulation");
> +     if (!mask)
> +             mask = &rte_flow_item_ipv6_mask;
> +     if (memcmp(&mask->hdr.dst_addr,
> +                &flow_tcf_mask_empty.ipv6.hdr.dst_addr,
> +                IPV6_ADDR_LEN)) {
> +             if (memcmp(&mask->hdr.dst_addr,
> +                        &rte_flow_item_ipv6_mask.hdr.dst_addr,
> +                        IPV6_ADDR_LEN))
> +                     return rte_flow_error_set(error, ENOTSUP,
> +                              RTE_FLOW_ERROR_TYPE_ITEM_MASK, mask,
> +                              "no support for partial mask on"
> +                              " \"ipv6.hdr.dst_addr\" field"
> +                              " for vxlan encapsulation");
> +             /* More IPv6 address validations can be put here. */
> +     } else {
> +             /*
> +              * Kernel uses the destination IP address to determine
> +              * the routing path and obtain the MAC destination
> +              * address (heigh or gate), so IP destination address
> +              * must be specified within the tc rule.
> +              */
> +             return rte_flow_error_set(error, EINVAL,
> +                              RTE_FLOW_ERROR_TYPE_ITEM, item,
> +                              "outer ipv6 destination address must be"
> +                              " specified for vxlan encapsulation");
> +     }
> +     if (memcmp(&mask->hdr.src_addr,
> +                &flow_tcf_mask_empty.ipv6.hdr.src_addr,
> +                IPV6_ADDR_LEN)) {
> +             if (memcmp(&mask->hdr.src_addr,
> +                        &rte_flow_item_ipv6_mask.hdr.src_addr,
> +                        IPV6_ADDR_LEN))
> +                     return rte_flow_error_set(error, ENOTSUP,
> +                              RTE_FLOW_ERROR_TYPE_ITEM_MASK, mask,
> +                              "no support for partial mask on"
> +                              " \"ipv6.hdr.src_addr\" field"
> +                              " for vxlan encapsulation");
> +             /* More L3 address validation can be put here. */
> +     } else {
> +             /*
> +              * Kernel uses the source IP address to select the
> +              * interface for egress encapsulated traffic, so
> +              * it must be specified in the tc rule.
> +              */
> +             return rte_flow_error_set(error, EINVAL,
> +                              RTE_FLOW_ERROR_TYPE_ITEM, item,
> +                              "outer L3 source address must be"
> +                              " specified for vxlan encapsulation");
> +     }
> +     return 0;
> +}
> +
> +/**
> + * Validate VXLAN_ENCAP action RTE_FLOW_ITEM_TYPE_UDP item for E-Switch.
> + * The routine checks the UDP fields to be used in encapsulation header.
> + *
> + * @param[in] item
> + *   Pointer to the item structure.
> + * @param[out] error
> + *   Pointer to the error structure.
> + *
> + * @return
> + *   0 on success, a negative errno value otherwise and rte_ernno is set.
> + **/
> +static int
> +flow_tcf_validate_vxlan_encap_udp(const struct rte_flow_item *item,
> +                               struct rte_flow_error *error)
> +{
> +     const struct rte_flow_item_udp *spec = item->spec;
> +     const struct rte_flow_item_udp *mask = item->mask;
> +
> +     if (!spec)
> +             /*
> +              * Specification for UDP ports cannot be empty
> +              * because it is required by tunnel_key parameter.
> +              */
> +             return rte_flow_error_set(error, EINVAL,
> +                              RTE_FLOW_ERROR_TYPE_ITEM, item,
> +                              "NULL UDP port specification "
> +                              " for vxlan encapsulation");
> +     if (!mask)
> +             mask = &rte_flow_item_udp_mask;
> +     if (mask->hdr.dst_port != RTE_BE16(0x0000)) {
> +             if (mask->hdr.dst_port != RTE_BE16(0xffff))
> +                     return rte_flow_error_set(error, ENOTSUP,
> +                              RTE_FLOW_ERROR_TYPE_ITEM_MASK, mask,
> +                              "no support for partial mask on"
> +                              " \"udp.hdr.dst_port\" field"
> +                              " for vxlan encapsulation");
> +             if (!spec->hdr.dst_port)
> +                     return rte_flow_error_set(error, EINVAL,
> +                              RTE_FLOW_ERROR_TYPE_ITEM, item,
> +                              "outer UDP remote port cannot be"
> +                              " 0 for vxlan encapsulation");
> +     } else {
> +             return rte_flow_error_set(error, EINVAL,
> +                              RTE_FLOW_ERROR_TYPE_ITEM, item,
> +                              "outer UDP remote port must be"
> +                              " specified for vxlan encapsulation");
> +     }
> +     if (mask->hdr.src_port != RTE_BE16(0x0000)) {
> +             if (mask->hdr.src_port != RTE_BE16(0xffff))
> +                     return rte_flow_error_set(error, ENOTSUP,
> +                              RTE_FLOW_ERROR_TYPE_ITEM_MASK, mask,
> +                              "no support for partial mask on"
> +                              " \"udp.hdr.src_port\" field"
> +                              " for vxlan encapsulation");
> +             DRV_LOG(WARNING,
> +                     "outer UDP source port cannot be"
> +                     " forced for vxlan encapsulation,"
> +                     " parameter ignored");
> +     }
> +     return 0;
> +}
> +
> +/**
> + * Validate VXLAN_ENCAP action RTE_FLOW_ITEM_TYPE_VXLAN item for E-Switch.
> + * The routine checks the VNIP fields to be used in encapsulation header.
> + *
> + * @param[in] item
> + *   Pointer to the item structure.
> + * @param[out] error
> + *   Pointer to the error structure.
> + *
> + * @return
> + *   0 on success, a negative errno value otherwise and rte_ernno is set.
> + **/
> +static int
> +flow_tcf_validate_vxlan_encap_vni(const struct rte_flow_item *item,
> +                               struct rte_flow_error *error)
> +{
> +     const struct rte_flow_item_vxlan *spec = item->spec;
> +     const struct rte_flow_item_vxlan *mask = item->mask;
> +
> +     if (!spec)
> +             /* Outer VNI is required by tunnel_key parameter. */
> +             return rte_flow_error_set(error, EINVAL,
> +                              RTE_FLOW_ERROR_TYPE_ITEM, item,
> +                              "NULL VNI specification"
> +                              " for vxlan encapsulation");
> +     if (!mask)
> +             mask = &rte_flow_item_vxlan_mask;
> +     if (!mask->vni[0] && !mask->vni[1] && !mask->vni[2])
> +             return rte_flow_error_set(error, EINVAL,
> +                                       RTE_FLOW_ERROR_TYPE_ITEM, item,
> +                                       "outer VNI must be specified "
> +                                       "for vxlan encapsulation");
> +     if (mask->vni[0] != 0xff ||
> +         mask->vni[1] != 0xff ||
> +         mask->vni[2] != 0xff)
> +             return rte_flow_error_set(error, ENOTSUP,
> +                                       RTE_FLOW_ERROR_TYPE_ITEM_MASK, mask,
> +                                       "no support for partial mask on"
> +                                       " \"vxlan.vni\" field");
> +
> +     if (!spec->vni[0] && !spec->vni[1] && !spec->vni[2])
> +             return rte_flow_error_set(error, EINVAL,
> +                                       RTE_FLOW_ERROR_TYPE_ITEM, item,
> +                                       "vxlan vni cannot be 0");
> +     return 0;
> +}
> +
> +/**
> + * Validate VXLAN_ENCAP action item list for E-Switch.
> + * The routine checks items to be used in encapsulation header.
> + *
> + * @param[in] action
> + *   Pointer to the VXLAN_ENCAP action structure.
> + * @param[out] error
> + *   Pointer to the error structure.
> + *
> + * @return
> + *   0 on success, a negative errno value otherwise and rte_ernno is set.
> + **/
> +static int
> +flow_tcf_validate_vxlan_encap(const struct rte_flow_action *action,
> +                           struct rte_flow_error *error)
> +{
> +     const struct rte_flow_item *items;
> +     int ret;
> +     uint32_t item_flags = 0;
> +
> +     if (!action->conf)
> +             return rte_flow_error_set
> +                     (error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
> +                      action, "Missing vxlan tunnel"
> +                              " action configuration");
> +     items = ((const struct rte_flow_action_vxlan_encap *)
> +                                     action->conf)->definition;
> +     if (!items)
> +             return rte_flow_error_set
> +                     (error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
> +                      action, "Missing vxlan tunnel"
> +                              " encapsulation parameters");
> +     for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
> +             switch (items->type) {
> +             case RTE_FLOW_ITEM_TYPE_VOID:
> +                     break;
> +             case RTE_FLOW_ITEM_TYPE_ETH:
> +                     ret = mlx5_flow_validate_item_eth(items, item_flags,
> +                                                       error);
> +                     if (ret < 0)
> +                             return ret;
> +                     ret = flow_tcf_validate_vxlan_encap_eth(items, error);
> +                     if (ret < 0)
> +                             return ret;
> +                     item_flags |= MLX5_FLOW_LAYER_OUTER_L2;
> +                     break;
> +             break;
> +             case RTE_FLOW_ITEM_TYPE_IPV4:
> +                     ret = mlx5_flow_validate_item_ipv4(items, item_flags,
> +                                                        error);
> +                     if (ret < 0)
> +                             return ret;
> +                     ret = flow_tcf_validate_vxlan_encap_ipv4(items, error);
> +                     if (ret < 0)
> +                             return ret;
> +                     item_flags |= MLX5_FLOW_LAYER_OUTER_L3_IPV4;
> +                     break;
> +             case RTE_FLOW_ITEM_TYPE_IPV6:
> +                     ret = mlx5_flow_validate_item_ipv6(items, item_flags,
> +                                                        error);
> +                     if (ret < 0)
> +                             return ret;
> +                     ret = flow_tcf_validate_vxlan_encap_ipv6(items, error);
> +                     if (ret < 0)
> +                             return ret;
> +                     item_flags |= MLX5_FLOW_LAYER_OUTER_L3_IPV6;
> +                     break;
> +             case RTE_FLOW_ITEM_TYPE_UDP:
> +                     ret = mlx5_flow_validate_item_udp(items, item_flags,
> +                                                        0xFF, error);
> +                     if (ret < 0)
> +                             return ret;
> +                     ret = flow_tcf_validate_vxlan_encap_udp(items, error);
> +                     if (ret < 0)
> +                             return ret;
> +                     item_flags |= MLX5_FLOW_LAYER_OUTER_L4_UDP;
> +                     break;
> +             case RTE_FLOW_ITEM_TYPE_VXLAN:
> +                     ret = mlx5_flow_validate_item_vxlan(items,
> +                                                         item_flags, error);
> +                     if (ret < 0)
> +                             return ret;
> +                     ret = flow_tcf_validate_vxlan_encap_vni(items, error);
> +                     if (ret < 0)
> +                             return ret;
> +                     item_flags |= MLX5_FLOW_LAYER_VXLAN;
> +                     break;
> +             default:
> +                     return rte_flow_error_set(error, ENOTSUP,
> +                                       RTE_FLOW_ERROR_TYPE_ITEM, items,
> +                                       "vxlan encap item not supported");
> +             }
> +     }
> +     if (!(item_flags & MLX5_FLOW_LAYER_OUTER_L3))
> +             return rte_flow_error_set(error, EINVAL,
> +                                       RTE_FLOW_ERROR_TYPE_ACTION, action,
> +                                       "no outer IP layer found"
> +                                       " for vxlan encapsulation");
> +     if (!(item_flags & MLX5_FLOW_LAYER_OUTER_L4_UDP))
> +             return rte_flow_error_set(error, EINVAL,
> +                                       RTE_FLOW_ERROR_TYPE_ACTION, action,
> +                                       "no outer UDP layer found"
> +                                       " for vxlan encapsulation");
> +     if (!(item_flags & MLX5_FLOW_LAYER_VXLAN))
> +             return rte_flow_error_set(error, EINVAL,
> +                                       RTE_FLOW_ERROR_TYPE_ACTION, action,
> +                                       "no VXLAN VNI found"
> +                                       " for vxlan encapsulation");
> +     return 0;
> +}
> +
> +/**
> + * Validate RTE_FLOW_ITEM_TYPE_IPV4 item if VXLAN_DECAP action
> + * is present in actions list.
> + *
> + * @param[in] ipv4
> + *   Outer IPv4 address item (if any, NULL otherwise).
> + * @param[out] error
> + *   Pointer to the error structure.
> + *
> + * @return
> + *   0 on success, a negative errno value otherwise and rte_ernno is set.
> + **/
> +static int
> +flow_tcf_validate_vxlan_decap_ipv4(const struct rte_flow_item *ipv4,
> +                                struct rte_flow_error *error)
> +{
> +     const struct rte_flow_item_ipv4 *spec = ipv4->spec;
> +     const struct rte_flow_item_ipv4 *mask = ipv4->mask;
> +
> +     if (!spec)
> +             /*
> +              * Specification for IP addresses cannot be empty
> +              * because it is required as decap parameter.
> +              */
> +             return rte_flow_error_set(error, EINVAL,
> +                                       RTE_FLOW_ERROR_TYPE_ITEM, ipv4,
> +                                       "NULL outer ipv4 address"
> +                                       " specification for vxlan"
> +                                       " for vxlan decapsulation");
> +     if (!mask)
> +             mask = &rte_flow_item_ipv4_mask;
> +     if (mask->hdr.dst_addr != RTE_BE32(0x00000000)) {
> +             if (mask->hdr.dst_addr != RTE_BE32(0xffffffff))
> +                     return rte_flow_error_set(error, ENOTSUP,
> +                                      RTE_FLOW_ERROR_TYPE_ITEM_MASK, mask,
> +                                      "no support for partial mask on"
> +                                      " \"ipv4.hdr.dst_addr\" field");
> +             /* More IP address validations can be put here. */
> +     } else {
> +             /*
> +              * Kernel uses the destination IP address
> +              * to determine the ingress network interface
> +              * for traffic being decapsulated.
> +              */
> +             return rte_flow_error_set(error, EINVAL,
> +                                       RTE_FLOW_ERROR_TYPE_ITEM, ipv4,
> +                                       "outer ipv4 destination address"
> +                                       " must be specified for"
> +                                       " vxlan decapsulation");
> +     }
> +     /* Source IP address is optional for decap. */
> +     if (mask->hdr.src_addr != RTE_BE32(0x00000000) &&
> +         mask->hdr.src_addr != RTE_BE32(0xffffffff))
> +             return rte_flow_error_set(error, ENOTSUP,
> +                                       RTE_FLOW_ERROR_TYPE_ITEM_MASK, mask,
> +                                       "no support for partial mask on"
> +                                       " \"ipv4.hdr.src_addr\" field");
> +     return 0;
> +}
> +
> +/**
> + * Validate RTE_FLOW_ITEM_TYPE_IPV6 item if VXLAN_DECAP action
> + * is present in actions list.
> + *
> + * @param[in] ipv6
> + *   Outer IPv6 address item (if any, NULL otherwise).
> + * @param[out] error
> + *   Pointer to the error structure.
> + *
> + * @return
> + *   0 on success, a negative errno value otherwise and rte_ernno is set.
> + **/
> +static int
> +flow_tcf_validate_vxlan_decap_ipv6(const struct rte_flow_item *ipv6,
> +                                struct rte_flow_error *error)
> +{
> +     const struct rte_flow_item_ipv6 *spec = ipv6->spec;
> +     const struct rte_flow_item_ipv6 *mask = ipv6->mask;
> +
> +     if (!spec)
> +             /*
> +              * Specification for IP addresses cannot be empty
> +              * because it is required as decap parameter.
> +              */
> +             return rte_flow_error_set(error, EINVAL,
> +                                       RTE_FLOW_ERROR_TYPE_ITEM, ipv6,
> +                                       "NULL outer ipv6 address"
> +                                       " specification for vxlan"
> +                                       " decapsulation");
> +     if (!mask)
> +             mask = &rte_flow_item_ipv6_mask;
> +     if (memcmp(&mask->hdr.dst_addr,
> +                &flow_tcf_mask_empty.ipv6.hdr.dst_addr,
> +                IPV6_ADDR_LEN)) {
> +             if (memcmp(&mask->hdr.dst_addr,
> +                     &rte_flow_item_ipv6_mask.hdr.dst_addr,
> +                     IPV6_ADDR_LEN))
> +                     return rte_flow_error_set(error, ENOTSUP,
> +                                       RTE_FLOW_ERROR_TYPE_ITEM_MASK, mask,
> +                                       "no support for partial mask on"
> +                                       " \"ipv6.hdr.dst_addr\" field");
> +             /* More IP address validations can be put here. */
> +     } else {
> +             /*
> +              * Kernel uses the destination IP address
> +              * to determine the ingress network interface
> +              * for traffic being decapsulated.
> +              */
> +             return rte_flow_error_set(error, EINVAL,
> +                                       RTE_FLOW_ERROR_TYPE_ITEM, ipv6,
> +                                       "outer ipv6 destination address must 
> be "
> +                                       "specified for vxlan decapsulation");
> +     }
> +     /* Source IP address is optional for decap. */
> +     if (memcmp(&mask->hdr.src_addr,
> +                &flow_tcf_mask_empty.ipv6.hdr.src_addr,
> +                IPV6_ADDR_LEN)) {
> +             if (memcmp(&mask->hdr.src_addr,
> +                        &rte_flow_item_ipv6_mask.hdr.src_addr,
> +                        IPV6_ADDR_LEN))
> +                     return rte_flow_error_set(error, ENOTSUP,
> +                             RTE_FLOW_ERROR_TYPE_ITEM_MASK, mask,
> +                             "no support for partial mask on"
> +                             " \"ipv6.hdr.src_addr\" field");
> +     }
> +     return 0;
> +}
> +
> +/**
> + * Validate RTE_FLOW_ITEM_TYPE_UDP item if VXLAN_DECAP action
> + * is present in actions list.
> + *
> + * @param[in] udp
> + *   Outer UDP layer item (if any, NULL otherwise).
> + * @param[out] error
> + *   Pointer to the error structure.
> + *
> + * @return
> + *   0 on success, a negative errno value otherwise and rte_ernno is set.
> + **/
> +static int
> +flow_tcf_validate_vxlan_decap_udp(const struct rte_flow_item *udp,
> +                               struct rte_flow_error *error)
> +{
> +     const struct rte_flow_item_udp *spec = udp->spec;
> +     const struct rte_flow_item_udp *mask = udp->mask;
> +
> +     if (!spec)
> +             /*
> +              * Specification for UDP ports cannot be empty
> +              * because it is required as decap parameter.
> +              */
> +             return rte_flow_error_set(error, EINVAL,
> +                                       RTE_FLOW_ERROR_TYPE_ITEM, udp,
> +                                       "NULL UDP port specification"
> +                                       " for VXLAN decapsulation");
> +     if (!mask)
> +             mask = &rte_flow_item_udp_mask;
> +     if (mask->hdr.dst_port != RTE_BE16(0x0000)) {
> +             if (mask->hdr.dst_port != RTE_BE16(0xffff))
> +                     return rte_flow_error_set(error, ENOTSUP,
> +                                      RTE_FLOW_ERROR_TYPE_ITEM_MASK, mask,
> +                                      "no support for partial mask on"
> +                                      " \"udp.hdr.dst_port\" field");
> +             if (!spec->hdr.dst_port)
> +                     return rte_flow_error_set(error, EINVAL,
> +                                      RTE_FLOW_ERROR_TYPE_ITEM, udp,
> +                                      "zero decap local UDP port");
> +     } else {
> +             return rte_flow_error_set(error, EINVAL,
> +                                       RTE_FLOW_ERROR_TYPE_ITEM, udp,
> +                                       "outer UDP destination port must be "
> +                                       "specified for vxlan decapsulation");
> +     }
> +     if (mask->hdr.src_port != RTE_BE16(0x0000)) {
> +             if (mask->hdr.src_port != RTE_BE16(0xffff))
> +                     return rte_flow_error_set(error, ENOTSUP,
> +                                      RTE_FLOW_ERROR_TYPE_ITEM_MASK, mask,
> +                                      "no support for partial mask on"
> +                                      " \"udp.hdr.src_port\" field");
> +             DRV_LOG(WARNING,
> +                     "outer UDP local port cannot be "
> +                     "forced for VXLAN encapsulation, "
> +                     "parameter ignored");
> +     }
> +     return 0;
> +}
> +
> +/**
>   * Validate flow for E-Switch.
>   *
>   * @param[in] priv
> @@ -1147,6 +1774,7 @@ struct pedit_parser {
>               const struct rte_flow_item_ipv6 *ipv6;
>               const struct rte_flow_item_tcp *tcp;
>               const struct rte_flow_item_udp *udp;
> +             const struct rte_flow_item_vxlan *vxlan;
>       } spec, mask;
>       union {
>               const struct rte_flow_action_port_id *port_id;
> @@ -1156,6 +1784,7 @@ struct pedit_parser {
>                       of_set_vlan_vid;
>               const struct rte_flow_action_of_set_vlan_pcp *
>                       of_set_vlan_pcp;
> +             const struct rte_flow_action_vxlan_encap *vxlan_encap;
>               const struct rte_flow_action_set_ipv4 *set_ipv4;
>               const struct rte_flow_action_set_ipv6 *set_ipv6;
>       } conf;
> @@ -1242,6 +1871,15 @@ struct pedit_parser {
>                                        " set action must follow push action");
>                       current_action_flag = MLX5_FLOW_ACTION_OF_SET_VLAN_PCP;
>                       break;
> +             case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
> +                     current_action_flag = MLX5_FLOW_ACTION_VXLAN_DECAP;
> +                     break;
> +             case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
> +                     ret = flow_tcf_validate_vxlan_encap(actions, error);
> +                     if (ret < 0)
> +                             return ret;
> +                     current_action_flag = MLX5_FLOW_ACTION_VXLAN_ENCAP;
> +                     break;
>               case RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC:
>                       current_action_flag = MLX5_FLOW_ACTION_SET_IPV4_SRC;
>                       break;
> @@ -1302,11 +1940,32 @@ struct pedit_parser {
>                                                 actions,
>                                                 "can't have multiple fate"
>                                                 " actions");
> +             if ((current_action_flag & MLX5_TCF_VXLAN_ACTIONS) &&
> +                 (action_flags & MLX5_TCF_VXLAN_ACTIONS))
> +                     return rte_flow_error_set(error, EINVAL,
> +                                               RTE_FLOW_ERROR_TYPE_ACTION,
> +                                               actions,
> +                                               "can't have multiple vxlan"
> +                                               " actions");
> +             if ((current_action_flag & MLX5_TCF_VXLAN_ACTIONS) &&
> +                 (action_flags & MLX5_TCF_VLAN_ACTIONS))
> +                     return rte_flow_error_set(error, ENOTSUP,
> +                                               RTE_FLOW_ERROR_TYPE_ACTION,
> +                                               actions,
> +                                               "can't have vxlan and vlan"
> +                                               " actions in the same rule");
>               action_flags |= current_action_flag;
>       }
>       for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
>               unsigned int i;
>  
> +             if ((item_flags & MLX5_FLOW_LAYER_TUNNEL) &&
> +                 items->type != RTE_FLOW_ITEM_TYPE_ETH)
> +                     return rte_flow_error_set(error, ENOTSUP,
> +                                               RTE_FLOW_ERROR_TYPE_ITEM,
> +                                               items,
> +                                               "only L2 inner item"
> +                                               " is supported");
>               switch (items->type) {
>               case RTE_FLOW_ITEM_TYPE_VOID:
>                       break;
> @@ -1360,7 +2019,9 @@ struct pedit_parser {
>                                                         error);
>                       if (ret < 0)
>                               return ret;
> -                     item_flags |= MLX5_FLOW_LAYER_OUTER_L2;
> +                     item_flags |= (item_flags & MLX5_FLOW_LAYER_TUNNEL) ?
> +                                     MLX5_FLOW_LAYER_INNER_L2 :
> +                                     MLX5_FLOW_LAYER_OUTER_L2;
>                       /* TODO:
>                        * Redundant check due to different supported mask.
>                        * Same for the rest of items.
> @@ -1438,6 +2099,12 @@ struct pedit_parser {
>                               next_protocol =
>                                       ((const struct rte_flow_item_ipv4 *)
>                                        (items->spec))->hdr.next_proto_id;
> +                     if (action_flags & MLX5_FLOW_ACTION_VXLAN_DECAP) {
> +                             ret = flow_tcf_validate_vxlan_decap_ipv4
> +                                                             (items, error);
> +                             if (ret < 0)
> +                                     return ret;
> +                     }
>                       break;
>               case RTE_FLOW_ITEM_TYPE_IPV6:
>                       ret = mlx5_flow_validate_item_ipv6(items, item_flags,
> @@ -1465,6 +2132,12 @@ struct pedit_parser {
>                               next_protocol =
>                                       ((const struct rte_flow_item_ipv6 *)
>                                        (items->spec))->hdr.proto;
> +                     if (action_flags & MLX5_FLOW_ACTION_VXLAN_DECAP) {
> +                             ret = flow_tcf_validate_vxlan_decap_ipv6
> +                                                             (items, error);
> +                             if (ret < 0)
> +                                     return ret;
> +                     }
>                       break;
>               case RTE_FLOW_ITEM_TYPE_UDP:
>                       ret = mlx5_flow_validate_item_udp(items, item_flags,
> @@ -1480,6 +2153,12 @@ struct pedit_parser {
>                                error);
>                       if (!mask.udp)
>                               return -rte_errno;
> +                     if (action_flags & MLX5_FLOW_ACTION_VXLAN_DECAP) {
> +                             ret = flow_tcf_validate_vxlan_decap_udp
> +                                                             (items, error);
> +                             if (ret < 0)
> +                                     return ret;
> +                     }
>                       break;
>               case RTE_FLOW_ITEM_TYPE_TCP:
>                       ret = mlx5_flow_validate_item_tcp
> @@ -1499,10 +2178,40 @@ struct pedit_parser {
>                       if (!mask.tcp)
>                               return -rte_errno;
>                       break;
> +             case RTE_FLOW_ITEM_TYPE_VXLAN:
> +                     if (!(action_flags & RTE_FLOW_ACTION_TYPE_VXLAN_DECAP))
> +                             return rte_flow_error_set
> +                                     (error, ENOTSUP,
> +                                      RTE_FLOW_ERROR_TYPE_ITEM,
> +                                      items,
> +                                      "vni pattern should be followed by"
> +                                      " vxlan decapsulation action");
> +                     ret = mlx5_flow_validate_item_vxlan(items,
> +                                                         item_flags, error);
> +                     if (ret < 0)
> +                             return ret;
> +                     item_flags |= MLX5_FLOW_LAYER_VXLAN;
> +                     mask.vxlan = flow_tcf_item_mask
> +                             (items, &rte_flow_item_vxlan_mask,
> +                              &flow_tcf_mask_supported.vxlan,
> +                              &flow_tcf_mask_empty.vxlan,
> +                              sizeof(flow_tcf_mask_supported.vxlan), error);
> +                     if (!mask.vxlan)
> +                             return -rte_errno;
> +                     if (mask.vxlan->vni[0] != 0xff ||
> +                         mask.vxlan->vni[1] != 0xff ||
> +                         mask.vxlan->vni[2] != 0xff)
> +                             return rte_flow_error_set
> +                                     (error, ENOTSUP,
> +                                      RTE_FLOW_ERROR_TYPE_ITEM_MASK,
> +                                      mask.vxlan,
> +                                      "no support for partial or "
> +                                      "empty mask on \"vxlan.vni\" field");
> +                     break;
>               default:
>                       return rte_flow_error_set(error, ENOTSUP,
>                                                 RTE_FLOW_ERROR_TYPE_ITEM,
> -                                               NULL, "item not supported");
> +                                               items, "item not supported");
>               }
>       }
>       if ((action_flags & MLX5_TCF_PEDIT_ACTIONS) &&
> @@ -1571,6 +2280,12 @@ struct pedit_parser {
>                                         RTE_FLOW_ERROR_TYPE_ACTION, actions,
>                                         "vlan actions are supported"
>                                         " only with port_id action");
> +     if ((action_flags & MLX5_TCF_VXLAN_ACTIONS) &&
> +         !(action_flags & MLX5_FLOW_ACTION_PORT_ID))
> +             return rte_flow_error_set(error, ENOTSUP,
> +                                       RTE_FLOW_ERROR_TYPE_ACTION, NULL,
> +                                       "vxlan actions are supported"
> +                                       " only with port_id action");
>       if (!(action_flags & MLX5_TCF_FATE_ACTIONS))
>               return rte_flow_error_set(error, EINVAL,
>                                         RTE_FLOW_ERROR_TYPE_ACTION, actions,
> @@ -1594,6 +2309,28 @@ struct pedit_parser {
>                                                 "no ethernet found in"
>                                                 " pattern");
>       }
> +     if (action_flags & MLX5_FLOW_ACTION_VXLAN_DECAP) {
> +             if (!(item_flags &
> +                  (MLX5_FLOW_LAYER_OUTER_L3_IPV4 |
> +                   MLX5_FLOW_LAYER_OUTER_L3_IPV6)))
> +                     return rte_flow_error_set(error, EINVAL,
> +                                               RTE_FLOW_ERROR_TYPE_ACTION,
> +                                               NULL,
> +                                               "no outer IP pattern found"
> +                                               " for vxlan decap action");
> +             if (!(item_flags & MLX5_FLOW_LAYER_OUTER_L4_UDP))
> +                     return rte_flow_error_set(error, EINVAL,
> +                                               RTE_FLOW_ERROR_TYPE_ACTION,
> +                                               NULL,
> +                                               "no outer UDP pattern found"
> +                                               " for vxlan decap action");
> +             if (!(item_flags & MLX5_FLOW_LAYER_VXLAN))
> +                     return rte_flow_error_set(error, EINVAL,
> +                                               RTE_FLOW_ERROR_TYPE_ACTION,
> +                                               NULL,
> +                                               "no VNI pattern found"
> +                                               " for vxlan decap action");
> +     }
>       return 0;
>  }
>  
> -- 
> 1.8.3.1
> 

Reply via email to