summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDaniele Di Proietto <diproiettod@vmware.com>2015-11-15 22:07:25 -0800
committerDaniele Di Proietto <diproiettod@vmware.com>2016-07-27 17:58:44 -0700
commit94a81e4021ea5b14c635f4a6f6c4513d496ea1b6 (patch)
tree99c0eb13e8a0b6b9be301d575a83f05603b394c3 /lib
parentcaf64dc902dcffeb757f25cd8aff913a83d13a9a (diff)
downloadopenvswitch-94a81e4021ea5b14c635f4a6f6c4513d496ea1b6.tar.gz
flow: Export parse_ipv6_ext_hdrs().
This will be used by a future commit. Signed-off-by: Daniele Di Proietto <diproiettod@vmware.com> Acked-by: Joe Stringer <joe@ovn.org> Acked-by: Flavio Leitner <fbl@sysclose.org>
Diffstat (limited to 'lib')
-rw-r--r--lib/flow.c140
-rw-r--r--lib/flow.h3
2 files changed, 81 insertions, 62 deletions
diff --git a/lib/flow.c b/lib/flow.c
index 57751275a..f94b1f288 100644
--- a/lib/flow.c
+++ b/lib/flow.c
@@ -440,6 +440,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 true;
+ }
+ }
+ }
+ }
+}
+
+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
@@ -642,68 +718,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 4cff48cf6..c041e8a1f 100644
--- a/lib/flow.h
+++ b/lib/flow.h
@@ -106,6 +106,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)
{