diff mbox series

[ovs-dev,02/11] netdev-offload-dpdk: Add IPv6 pattern matching

Message ID 20200518154026.18059-3-elibr@mellanox.com
State New
Headers show
Series netdev datapath offload: Support IPv6 and VXLAN encap | expand

Commit Message

Eli Britstein May 18, 2020, 3:40 p.m. UTC
Add support for IPv6 pattern matching for offloading flows.

Signed-off-by: Eli Britstein <elibr@mellanox.com>
Reviewed-by: Roni Bar Yanai <roniba@mellanox.com>
---
 Documentation/howto/dpdk.rst |  2 +-
 NEWS                         |  1 +
 lib/netdev-offload-dpdk.c    | 76 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 78 insertions(+), 1 deletion(-)

Comments

Sriharsha Basavapatna May 19, 2020, 2:09 p.m. UTC | #1
On Mon, May 18, 2020 at 9:10 PM Eli Britstein <elibr@mellanox.com> wrote:
>
> Add support for IPv6 pattern matching for offloading flows.
>
> Signed-off-by: Eli Britstein <elibr@mellanox.com>
> Reviewed-by: Roni Bar Yanai <roniba@mellanox.com>
> ---
>  Documentation/howto/dpdk.rst |  2 +-
>  NEWS                         |  1 +
>  lib/netdev-offload-dpdk.c    | 76 ++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 78 insertions(+), 1 deletion(-)
>
> diff --git a/Documentation/howto/dpdk.rst b/Documentation/howto/dpdk.rst
> index be950d7ce..8a0eee80c 100644
> --- a/Documentation/howto/dpdk.rst
> +++ b/Documentation/howto/dpdk.rst
> @@ -385,7 +385,7 @@ The validated NICs are:
>  Supported protocols for hardware offload matches are:
>
>  - L2: Ethernet, VLAN
> -- L3: IPv4
> +- L3: IPv4, IPv6
>  - L4: TCP, UDP, SCTP, ICMP
>
>  Supported actions for hardware offload are:
> diff --git a/NEWS b/NEWS
> index 3dbd8ec0e..91d3d05b7 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -9,6 +9,7 @@ Post-v2.13.0
>     - DPDK:
>       * Deprecated DPDK pdump packet capture support removed.
>       * Deprecated DPDK ring ports (dpdkr) are no longer supported.
> +     * Add hardware offload support for matching IPv6 protocol.
>     - Linux datapath:
>       * Support for kernel versions up to 5.5.x.
>     - AF_XDP:
> diff --git a/lib/netdev-offload-dpdk.c b/lib/netdev-offload-dpdk.c
> index 84bbe29e7..9964ba69e 100644
> --- a/lib/netdev-offload-dpdk.c
> +++ b/lib/netdev-offload-dpdk.c
> @@ -16,6 +16,8 @@
>   */
>  #include <config.h>
>
> +#include <sys/types.h>
> +#include <netinet/ip6.h>
>  #include <rte_flow.h>
>
>  #include "cmap.h"
> @@ -321,6 +323,42 @@ dump_flow_pattern(struct ds *s, const struct rte_flow_item *item)
>          } else {
>              ds_put_cstr(s, "  Mask = null\n");
>          }
> +    } else if (item->type == RTE_FLOW_ITEM_TYPE_IPV6) {
> +        const struct rte_flow_item_ipv6 *ipv6_spec = item->spec;
> +        const struct rte_flow_item_ipv6 *ipv6_mask = item->mask;
> +
> +        char src_addr_str[INET6_ADDRSTRLEN];
> +        char dst_addr_str[INET6_ADDRSTRLEN];
> +
> +        ds_put_cstr(s, "rte flow ipv6 pattern:\n");
> +        if (ipv6_spec) {
> +            ipv6_string_mapped(src_addr_str,
> +                               (struct in6_addr *)&ipv6_spec->hdr.src_addr);
> +            ipv6_string_mapped(dst_addr_str,
> +                               (struct in6_addr *)&ipv6_spec->hdr.dst_addr);
> +
> +            ds_put_format(s, "  Spec:  vtc_flow=%#"PRIx32",  proto=%"PRIu8","
> +                          "  hlim=%"PRIu8",  src=%s,  dst=%s\n",
> +                          ntohl(ipv6_spec->hdr.vtc_flow), ipv6_spec->hdr.proto,
> +                          ipv6_spec->hdr.hop_limits, src_addr_str,
> +                          dst_addr_str);
> +        } else {
> +            ds_put_cstr(s, "  Spec = null\n");
> +        }
> +        if (ipv6_mask) {
> +            ipv6_string_mapped(src_addr_str,
> +                               (struct in6_addr *)&ipv6_mask->hdr.src_addr);
> +            ipv6_string_mapped(dst_addr_str,
> +                               (struct in6_addr *)&ipv6_mask->hdr.dst_addr);
> +
> +            ds_put_format(s, "  Mask:  vtc_flow=%#"PRIx32",  proto=%#"PRIx8","
> +                          "  hlim=%#"PRIx8",  src=%s,  dst=%s\n",
> +                          ntohl(ipv6_mask->hdr.vtc_flow), ipv6_mask->hdr.proto,
> +                          ipv6_mask->hdr.hop_limits, src_addr_str,
> +                          dst_addr_str);
> +        } else {
> +            ds_put_cstr(s, "  Mask = null\n");
> +        }
>      } else {
>          ds_put_format(s, "unknown rte flow pattern (%d)\n", item->type);
>      }
> @@ -660,6 +698,44 @@ parse_flow_match(struct flow_patterns *patterns,
>      /* ignore mask match for now */
>      consumed_masks->nw_frag = 0;
>
> +    /* IP v6 */
> +    if (match->flow.dl_type == htons(ETH_TYPE_IPV6)) {
> +        struct rte_flow_item_ipv6 *spec, *mask;
> +
> +        spec = xzalloc(sizeof *spec);
> +        mask = xzalloc(sizeof *mask);
> +
> +        spec->hdr.proto = match->flow.nw_proto;
> +        spec->hdr.hop_limits = match->flow.nw_ttl;
> +        spec->hdr.vtc_flow = htonl((uint32_t)match->flow.nw_tos <<
> +                                   RTE_IPV6_HDR_TC_SHIFT);
> +        memcpy(spec->hdr.src_addr, &match->flow.ipv6_src,
> +               sizeof spec->hdr.src_addr);
> +        memcpy(spec->hdr.dst_addr, &match->flow.ipv6_dst,
> +               sizeof spec->hdr.dst_addr);
> +
> +        mask->hdr.proto = match->wc.masks.nw_proto;
> +        mask->hdr.hop_limits = match->wc.masks.nw_ttl;
> +        mask->hdr.vtc_flow = htonl((uint32_t)match->wc.masks.nw_tos <<
> +                                   RTE_IPV6_HDR_TC_SHIFT);
> +        memcpy(mask->hdr.src_addr, &match->wc.masks.ipv6_src,
> +               sizeof mask->hdr.src_addr);
> +        memcpy(mask->hdr.dst_addr, &match->wc.masks.ipv6_dst,
> +               sizeof mask->hdr.dst_addr);
> +
> +        consumed_masks->nw_proto = 0;
> +        consumed_masks->nw_ttl = 0;
> +        consumed_masks->nw_tos = 0;
> +        memset(&consumed_masks->ipv6_src, 0, sizeof consumed_masks->ipv6_src);
> +        memset(&consumed_masks->ipv6_dst, 0, sizeof consumed_masks->ipv6_dst);
> +
> +        add_flow_pattern(patterns, RTE_FLOW_ITEM_TYPE_IPV6, spec, mask);
> +
> +        /* Save proto for L4 protocol setup */
> +        proto = spec->hdr.proto & mask->hdr.proto;
> +        next_proto_mask = &mask->hdr.proto;
> +    }
> +
>      if (proto != IPPROTO_ICMP && proto != IPPROTO_UDP  &&
>          proto != IPPROTO_SCTP && proto != IPPROTO_TCP  &&
>          (match->wc.masks.tp_src ||
> --
> 2.14.5
>
LGTM.
Thanks,
-Harsha
diff mbox series

Patch

diff --git a/Documentation/howto/dpdk.rst b/Documentation/howto/dpdk.rst
index be950d7ce..8a0eee80c 100644
--- a/Documentation/howto/dpdk.rst
+++ b/Documentation/howto/dpdk.rst
@@ -385,7 +385,7 @@  The validated NICs are:
 Supported protocols for hardware offload matches are:
 
 - L2: Ethernet, VLAN
-- L3: IPv4
+- L3: IPv4, IPv6
 - L4: TCP, UDP, SCTP, ICMP
 
 Supported actions for hardware offload are:
diff --git a/NEWS b/NEWS
index 3dbd8ec0e..91d3d05b7 100644
--- a/NEWS
+++ b/NEWS
@@ -9,6 +9,7 @@  Post-v2.13.0
    - DPDK:
      * Deprecated DPDK pdump packet capture support removed.
      * Deprecated DPDK ring ports (dpdkr) are no longer supported.
+     * Add hardware offload support for matching IPv6 protocol.
    - Linux datapath:
      * Support for kernel versions up to 5.5.x.
    - AF_XDP:
diff --git a/lib/netdev-offload-dpdk.c b/lib/netdev-offload-dpdk.c
index 84bbe29e7..9964ba69e 100644
--- a/lib/netdev-offload-dpdk.c
+++ b/lib/netdev-offload-dpdk.c
@@ -16,6 +16,8 @@ 
  */
 #include <config.h>
 
+#include <sys/types.h>
+#include <netinet/ip6.h>
 #include <rte_flow.h>
 
 #include "cmap.h"
@@ -321,6 +323,42 @@  dump_flow_pattern(struct ds *s, const struct rte_flow_item *item)
         } else {
             ds_put_cstr(s, "  Mask = null\n");
         }
+    } else if (item->type == RTE_FLOW_ITEM_TYPE_IPV6) {
+        const struct rte_flow_item_ipv6 *ipv6_spec = item->spec;
+        const struct rte_flow_item_ipv6 *ipv6_mask = item->mask;
+
+        char src_addr_str[INET6_ADDRSTRLEN];
+        char dst_addr_str[INET6_ADDRSTRLEN];
+
+        ds_put_cstr(s, "rte flow ipv6 pattern:\n");
+        if (ipv6_spec) {
+            ipv6_string_mapped(src_addr_str,
+                               (struct in6_addr *)&ipv6_spec->hdr.src_addr);
+            ipv6_string_mapped(dst_addr_str,
+                               (struct in6_addr *)&ipv6_spec->hdr.dst_addr);
+
+            ds_put_format(s, "  Spec:  vtc_flow=%#"PRIx32",  proto=%"PRIu8","
+                          "  hlim=%"PRIu8",  src=%s,  dst=%s\n",
+                          ntohl(ipv6_spec->hdr.vtc_flow), ipv6_spec->hdr.proto,
+                          ipv6_spec->hdr.hop_limits, src_addr_str,
+                          dst_addr_str);
+        } else {
+            ds_put_cstr(s, "  Spec = null\n");
+        }
+        if (ipv6_mask) {
+            ipv6_string_mapped(src_addr_str,
+                               (struct in6_addr *)&ipv6_mask->hdr.src_addr);
+            ipv6_string_mapped(dst_addr_str,
+                               (struct in6_addr *)&ipv6_mask->hdr.dst_addr);
+
+            ds_put_format(s, "  Mask:  vtc_flow=%#"PRIx32",  proto=%#"PRIx8","
+                          "  hlim=%#"PRIx8",  src=%s,  dst=%s\n",
+                          ntohl(ipv6_mask->hdr.vtc_flow), ipv6_mask->hdr.proto,
+                          ipv6_mask->hdr.hop_limits, src_addr_str,
+                          dst_addr_str);
+        } else {
+            ds_put_cstr(s, "  Mask = null\n");
+        }
     } else {
         ds_put_format(s, "unknown rte flow pattern (%d)\n", item->type);
     }
@@ -660,6 +698,44 @@  parse_flow_match(struct flow_patterns *patterns,
     /* ignore mask match for now */
     consumed_masks->nw_frag = 0;
 
+    /* IP v6 */
+    if (match->flow.dl_type == htons(ETH_TYPE_IPV6)) {
+        struct rte_flow_item_ipv6 *spec, *mask;
+
+        spec = xzalloc(sizeof *spec);
+        mask = xzalloc(sizeof *mask);
+
+        spec->hdr.proto = match->flow.nw_proto;
+        spec->hdr.hop_limits = match->flow.nw_ttl;
+        spec->hdr.vtc_flow = htonl((uint32_t)match->flow.nw_tos <<
+                                   RTE_IPV6_HDR_TC_SHIFT);
+        memcpy(spec->hdr.src_addr, &match->flow.ipv6_src,
+               sizeof spec->hdr.src_addr);
+        memcpy(spec->hdr.dst_addr, &match->flow.ipv6_dst,
+               sizeof spec->hdr.dst_addr);
+
+        mask->hdr.proto = match->wc.masks.nw_proto;
+        mask->hdr.hop_limits = match->wc.masks.nw_ttl;
+        mask->hdr.vtc_flow = htonl((uint32_t)match->wc.masks.nw_tos <<
+                                   RTE_IPV6_HDR_TC_SHIFT);
+        memcpy(mask->hdr.src_addr, &match->wc.masks.ipv6_src,
+               sizeof mask->hdr.src_addr);
+        memcpy(mask->hdr.dst_addr, &match->wc.masks.ipv6_dst,
+               sizeof mask->hdr.dst_addr);
+
+        consumed_masks->nw_proto = 0;
+        consumed_masks->nw_ttl = 0;
+        consumed_masks->nw_tos = 0;
+        memset(&consumed_masks->ipv6_src, 0, sizeof consumed_masks->ipv6_src);
+        memset(&consumed_masks->ipv6_dst, 0, sizeof consumed_masks->ipv6_dst);
+
+        add_flow_pattern(patterns, RTE_FLOW_ITEM_TYPE_IPV6, spec, mask);
+
+        /* Save proto for L4 protocol setup */
+        proto = spec->hdr.proto & mask->hdr.proto;
+        next_proto_mask = &mask->hdr.proto;
+    }
+
     if (proto != IPPROTO_ICMP && proto != IPPROTO_UDP  &&
         proto != IPPROTO_SCTP && proto != IPPROTO_TCP  &&
         (match->wc.masks.tp_src ||