diff options
author | Daniele Di Proietto <diproiettod@vmware.com> | 2015-11-15 22:07:25 -0800 |
---|---|---|
committer | Daniele Di Proietto <diproiettod@vmware.com> | 2016-07-27 17:58:44 -0700 |
commit | 94a81e4021ea5b14c635f4a6f6c4513d496ea1b6 (patch) | |
tree | 99c0eb13e8a0b6b9be301d575a83f05603b394c3 /lib | |
parent | caf64dc902dcffeb757f25cd8aff913a83d13a9a (diff) | |
download | openvswitch-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.c | 140 | ||||
-rw-r--r-- | lib/flow.h | 3 |
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) { |