This will be used by a future commit. Signed-off-by: Daniele Di Proietto <diproiet...@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; + } + } + } + } +} + +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) { -- 2.1.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev