diff mbox

[ovs-dev,02/12] flow: Export parse_ipv6_ext_hdrs().

Message ID 1447654883-8097-3-git-send-email-diproiettod@vmware.com
State Changes Requested
Headers show

Commit Message

Daniele Di Proietto Nov. 16, 2015, 6:21 a.m. UTC
This will be used by a future commit.

Signed-off-by: Daniele Di Proietto <diproiettod@vmware.com>
---
 lib/flow.c | 140 ++++++++++++++++++++++++++++++++++---------------------------
 lib/flow.h |   3 ++
 2 files changed, 81 insertions(+), 62 deletions(-)

Comments

Joe Stringer Nov. 16, 2015, 5:48 p.m. UTC | #1
On 15 November 2015 at 22:21, Daniele Di Proietto
<diproiettod@vmware.com> wrote:
> This will be used by a future commit.
>
> Signed-off-by: Daniele Di Proietto <diproiettod@vmware.com>
> ---
>  lib/flow.c | 140 ++++++++++++++++++++++++++++++++++---------------------------
>  lib/flow.h |   3 ++
>  2 files changed, 81 insertions(+), 62 deletions(-)
>
> diff --git a/lib/flow.c b/lib/flow.c
> index d5dcb92..2bdce26 100644
> --- a/lib/flow.c
> +++ b/lib/flow.c
> @@ -402,6 +402,82 @@ invalid:
>      arp_buf[1] = eth_addr_zero;
>  }
>
> +static inline bool
> +parse_ipv6_ext_hdrs__(const void **datap, size_t *sizep, uint8_t *nw_proto,
> +                      uint8_t *nw_frag)
> +{
> +    while (1) {
> +        if (OVS_LIKELY((*nw_proto != IPPROTO_HOPOPTS)
> +                       && (*nw_proto != IPPROTO_ROUTING)
> +                       && (*nw_proto != IPPROTO_DSTOPTS)
> +                       && (*nw_proto != IPPROTO_AH)
> +                       && (*nw_proto != IPPROTO_FRAGMENT))) {
> +            /* It's either a terminal header (e.g., TCP, UDP) or one we
> +             * don't understand.  In either case, we're done with the
> +             * packet, so use it to fill in 'nw_proto'. */
> +            return true;
> +        }
> +
> +        /* We only verify that at least 8 bytes of the next header are
> +         * available, but many of these headers are longer.  Ensure that
> +         * accesses within the extension header are within those first 8
> +         * bytes. All extension headers are required to be at least 8
> +         * bytes. */
> +        if (OVS_UNLIKELY(*sizep < 8)) {
> +            return false;
> +        }
> +
> +        if ((*nw_proto == IPPROTO_HOPOPTS)
> +            || (*nw_proto == IPPROTO_ROUTING)
> +            || (*nw_proto == IPPROTO_DSTOPTS)) {
> +            /* These headers, while different, have the fields we care
> +             * about in the same location and with the same
> +             * interpretation. */
> +            const struct ip6_ext *ext_hdr = *datap;
> +            *nw_proto = ext_hdr->ip6e_nxt;
> +            if (OVS_UNLIKELY(!data_try_pull(datap, sizep,
> +                                            (ext_hdr->ip6e_len + 1) * 8))) {
> +                return false;
> +            }
> +        } else if (*nw_proto == IPPROTO_AH) {
> +            /* A standard AH definition isn't available, but the fields
> +             * we care about are in the same location as the generic
> +             * option header--only the header length is calculated
> +             * differently. */
> +            const struct ip6_ext *ext_hdr = *datap;
> +            *nw_proto = ext_hdr->ip6e_nxt;
> +            if (OVS_UNLIKELY(!data_try_pull(datap, sizep,
> +                                            (ext_hdr->ip6e_len + 2) * 4))) {
> +                return false;
> +            }
> +        } else if (*nw_proto == IPPROTO_FRAGMENT) {
> +            const struct ovs_16aligned_ip6_frag *frag_hdr = *datap;
> +
> +            *nw_proto = frag_hdr->ip6f_nxt;
> +            if (!data_try_pull(datap, sizep, sizeof *frag_hdr)) {
> +                return false;
> +            }
> +
> +            /* We only process the first fragment. */
> +            if (frag_hdr->ip6f_offlg != htons(0)) {
> +                *nw_frag = FLOW_NW_FRAG_ANY;
> +                if ((frag_hdr->ip6f_offlg & IP6F_OFF_MASK) != htons(0)) {
> +                    *nw_frag |= FLOW_NW_FRAG_LATER;
> +                    *nw_proto = IPPROTO_FRAGMENT;
> +                    return false;

I think this is supposed to be true?
diff mbox

Patch

diff --git a/lib/flow.c b/lib/flow.c
index d5dcb92..2bdce26 100644
--- a/lib/flow.c
+++ b/lib/flow.c
@@ -402,6 +402,82 @@  invalid:
     arp_buf[1] = eth_addr_zero;
 }
 
+static inline bool
+parse_ipv6_ext_hdrs__(const void **datap, size_t *sizep, uint8_t *nw_proto,
+                      uint8_t *nw_frag)
+{
+    while (1) {
+        if (OVS_LIKELY((*nw_proto != IPPROTO_HOPOPTS)
+                       && (*nw_proto != IPPROTO_ROUTING)
+                       && (*nw_proto != IPPROTO_DSTOPTS)
+                       && (*nw_proto != IPPROTO_AH)
+                       && (*nw_proto != IPPROTO_FRAGMENT))) {
+            /* It's either a terminal header (e.g., TCP, UDP) or one we
+             * don't understand.  In either case, we're done with the
+             * packet, so use it to fill in 'nw_proto'. */
+            return true;
+        }
+
+        /* We only verify that at least 8 bytes of the next header are
+         * available, but many of these headers are longer.  Ensure that
+         * accesses within the extension header are within those first 8
+         * bytes. All extension headers are required to be at least 8
+         * bytes. */
+        if (OVS_UNLIKELY(*sizep < 8)) {
+            return false;
+        }
+
+        if ((*nw_proto == IPPROTO_HOPOPTS)
+            || (*nw_proto == IPPROTO_ROUTING)
+            || (*nw_proto == IPPROTO_DSTOPTS)) {
+            /* These headers, while different, have the fields we care
+             * about in the same location and with the same
+             * interpretation. */
+            const struct ip6_ext *ext_hdr = *datap;
+            *nw_proto = ext_hdr->ip6e_nxt;
+            if (OVS_UNLIKELY(!data_try_pull(datap, sizep,
+                                            (ext_hdr->ip6e_len + 1) * 8))) {
+                return false;
+            }
+        } else if (*nw_proto == IPPROTO_AH) {
+            /* A standard AH definition isn't available, but the fields
+             * we care about are in the same location as the generic
+             * option header--only the header length is calculated
+             * differently. */
+            const struct ip6_ext *ext_hdr = *datap;
+            *nw_proto = ext_hdr->ip6e_nxt;
+            if (OVS_UNLIKELY(!data_try_pull(datap, sizep,
+                                            (ext_hdr->ip6e_len + 2) * 4))) {
+                return false;
+            }
+        } else if (*nw_proto == IPPROTO_FRAGMENT) {
+            const struct ovs_16aligned_ip6_frag *frag_hdr = *datap;
+
+            *nw_proto = frag_hdr->ip6f_nxt;
+            if (!data_try_pull(datap, sizep, sizeof *frag_hdr)) {
+                return false;
+            }
+
+            /* We only process the first fragment. */
+            if (frag_hdr->ip6f_offlg != htons(0)) {
+                *nw_frag = FLOW_NW_FRAG_ANY;
+                if ((frag_hdr->ip6f_offlg & IP6F_OFF_MASK) != htons(0)) {
+                    *nw_frag |= FLOW_NW_FRAG_LATER;
+                    *nw_proto = IPPROTO_FRAGMENT;
+                    return false;
+                }
+            }
+        }
+    }
+}
+
+bool
+parse_ipv6_ext_hdrs(const void **datap, size_t *sizep, uint8_t *nw_proto,
+                    uint8_t *nw_frag)
+{
+    return parse_ipv6_ext_hdrs__(datap, sizep, nw_proto, nw_frag);
+}
+
 /* Initializes 'flow' members from 'packet' and 'md'
  *
  * Initializes 'packet' header l2 pointer to the start of the Ethernet
@@ -604,68 +680,8 @@  miniflow_extract(struct dp_packet *packet, struct miniflow *dst)
         nw_ttl = nh->ip6_hlim;
         nw_proto = nh->ip6_nxt;
 
-        while (1) {
-            if (OVS_LIKELY((nw_proto != IPPROTO_HOPOPTS)
-                           && (nw_proto != IPPROTO_ROUTING)
-                           && (nw_proto != IPPROTO_DSTOPTS)
-                           && (nw_proto != IPPROTO_AH)
-                           && (nw_proto != IPPROTO_FRAGMENT))) {
-                /* It's either a terminal header (e.g., TCP, UDP) or one we
-                 * don't understand.  In either case, we're done with the
-                 * packet, so use it to fill in 'nw_proto'. */
-                break;
-            }
-
-            /* We only verify that at least 8 bytes of the next header are
-             * available, but many of these headers are longer.  Ensure that
-             * accesses within the extension header are within those first 8
-             * bytes. All extension headers are required to be at least 8
-             * bytes. */
-            if (OVS_UNLIKELY(size < 8)) {
-                goto out;
-            }
-
-            if ((nw_proto == IPPROTO_HOPOPTS)
-                || (nw_proto == IPPROTO_ROUTING)
-                || (nw_proto == IPPROTO_DSTOPTS)) {
-                /* These headers, while different, have the fields we care
-                 * about in the same location and with the same
-                 * interpretation. */
-                const struct ip6_ext *ext_hdr = data;
-                nw_proto = ext_hdr->ip6e_nxt;
-                if (OVS_UNLIKELY(!data_try_pull(&data, &size,
-                                                (ext_hdr->ip6e_len + 1) * 8))) {
-                    goto out;
-                }
-            } else if (nw_proto == IPPROTO_AH) {
-                /* A standard AH definition isn't available, but the fields
-                 * we care about are in the same location as the generic
-                 * option header--only the header length is calculated
-                 * differently. */
-                const struct ip6_ext *ext_hdr = data;
-                nw_proto = ext_hdr->ip6e_nxt;
-                if (OVS_UNLIKELY(!data_try_pull(&data, &size,
-                                                (ext_hdr->ip6e_len + 2) * 4))) {
-                    goto out;
-                }
-            } else if (nw_proto == IPPROTO_FRAGMENT) {
-                const struct ovs_16aligned_ip6_frag *frag_hdr = data;
-
-                nw_proto = frag_hdr->ip6f_nxt;
-                if (!data_try_pull(&data, &size, sizeof *frag_hdr)) {
-                    goto out;
-                }
-
-                /* We only process the first fragment. */
-                if (frag_hdr->ip6f_offlg != htons(0)) {
-                    nw_frag = FLOW_NW_FRAG_ANY;
-                    if ((frag_hdr->ip6f_offlg & IP6F_OFF_MASK) != htons(0)) {
-                        nw_frag |= FLOW_NW_FRAG_LATER;
-                        nw_proto = IPPROTO_FRAGMENT;
-                        break;
-                    }
-                }
-            }
+        if (!parse_ipv6_ext_hdrs__(&data, &size, &nw_proto, &nw_frag)) {
+            goto out;
         }
     } else {
         if (dl_type == htons(ETH_TYPE_ARP) ||
diff --git a/lib/flow.h b/lib/flow.h
index 41397d4..de15a98 100644
--- a/lib/flow.h
+++ b/lib/flow.h
@@ -235,6 +235,9 @@  void flow_set_mpls_lse(struct flow *, int idx, ovs_be32 lse);
 
 void flow_compose(struct dp_packet *, const struct flow *);
 
+bool parse_ipv6_ext_hdrs(const void **datap, size_t *sizep, uint8_t *nw_proto,
+                         uint8_t *nw_frag);
+
 static inline uint64_t
 flow_get_xreg(const struct flow *flow, int idx)
 {