aboutsummaryrefslogtreecommitdiff
path: root/datapath
diff options
context:
space:
mode:
authorJesse Gross <jesse@nicira.com>2011-12-01 16:09:05 -0800
committerJesse Gross <jesse@nicira.com>2011-12-02 11:22:13 -0800
commit0fd0d0834f79d6cfe8a0eccc19732bae365aa575 (patch)
tree9f6fd61d52587ba30f3f755412098e20a7e331ba /datapath
parent1f6e0fbd81b8f1786be0232f83792170a9f476d3 (diff)
datapath: Remove custom version of ipv6_skip_exthdr().
We currently have a version of ipv6_skip_exthdr() which is identical to the main one with the addition of fragment reporting. We can propose our version for upstream and then use it directly without duplication. Signed-off-by: Jesse Gross <jesse@nicira.com> Acked-by: Ben Pfaff <blp@nicira.com>
Diffstat (limited to 'datapath')
-rw-r--r--datapath/flow.c70
-rw-r--r--datapath/linux/Modules.mk1
-rw-r--r--datapath/linux/compat/exthdrs_core.c48
-rw-r--r--datapath/linux/compat/include/linux/ipv6.h8
-rw-r--r--datapath/tunnel.c3
5 files changed, 68 insertions, 62 deletions
diff --git a/datapath/flow.c b/datapath/flow.c
index c6f591af..78dea3a6 100644
--- a/datapath/flow.c
+++ b/datapath/flow.c
@@ -128,66 +128,6 @@ u64 ovs_flow_used_time(unsigned long flow_jiffies)
(offsetof(struct sw_flow_key, field) + \
FIELD_SIZEOF(struct sw_flow_key, field))
-/**
- * skip_exthdr - skip any IPv6 extension headers
- * @skb: skbuff to parse
- * @start: offset of first extension header
- * @nexthdrp: Initially, points to the type of the extension header at @start.
- * This function updates it to point to the extension header at the final
- * offset.
- * @frag: Points to the @frag member in a &struct sw_flow_key. This
- * function sets an appropriate %OVS_FRAG_TYPE_* value.
- *
- * This is based on ipv6_skip_exthdr() but adds the updates to *@frag.
- *
- * When there is more than one fragment header, this version reports whether
- * the final fragment header that it examines is a first fragment.
- *
- * Returns the final payload offset, or -1 on error.
- */
-static int skip_exthdr(const struct sk_buff *skb, int start, u8 *nexthdrp,
- u8 *frag)
-{
- u8 nexthdr = *nexthdrp;
-
- while (ipv6_ext_hdr(nexthdr)) {
- struct ipv6_opt_hdr _hdr, *hp;
- int hdrlen;
-
- if (nexthdr == NEXTHDR_NONE)
- return -1;
- hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
- if (hp == NULL)
- return -1;
- if (nexthdr == NEXTHDR_FRAGMENT) {
- __be16 _frag_off, *fp;
- fp = skb_header_pointer(skb,
- start+offsetof(struct frag_hdr,
- frag_off),
- sizeof(_frag_off),
- &_frag_off);
- if (fp == NULL)
- return -1;
-
- if (ntohs(*fp) & ~0x7) {
- *frag = OVS_FRAG_TYPE_LATER;
- break;
- }
- *frag = OVS_FRAG_TYPE_FIRST;
- hdrlen = 8;
- } else if (nexthdr == NEXTHDR_AUTH)
- hdrlen = (hp->hdrlen+2)<<2;
- else
- hdrlen = ipv6_optlen(hp);
-
- nexthdr = hp->nexthdr;
- start += hdrlen;
- }
-
- *nexthdrp = nexthdr;
- return start;
-}
-
static int parse_ipv6hdr(struct sk_buff *skb, struct sw_flow_key *key,
int *key_lenp)
{
@@ -196,6 +136,7 @@ static int parse_ipv6hdr(struct sk_buff *skb, struct sw_flow_key *key,
int payload_ofs;
struct ipv6hdr *nh;
uint8_t nexthdr;
+ __be16 frag_off;
int err;
*key_lenp = SW_FLOW_KEY_OFFSET(ipv6.label);
@@ -215,10 +156,17 @@ static int parse_ipv6hdr(struct sk_buff *skb, struct sw_flow_key *key,
key->ipv6.addr.src = nh->saddr;
key->ipv6.addr.dst = nh->daddr;
- payload_ofs = skip_exthdr(skb, payload_ofs, &nexthdr, &key->ip.frag);
+ payload_ofs = ipv6_skip_exthdr(skb, payload_ofs, &nexthdr, &frag_off);
if (unlikely(payload_ofs < 0))
return -EINVAL;
+ if (frag_off) {
+ if (frag_off & htons(~0x7))
+ key->ip.frag = OVS_FRAG_TYPE_LATER;
+ else
+ key->ip.frag = OVS_FRAG_TYPE_FIRST;
+ }
+
nh_len = payload_ofs - nh_ofs;
skb_set_transport_header(skb, nh_ofs + nh_len);
key->ip.proto = nexthdr;
diff --git a/datapath/linux/Modules.mk b/datapath/linux/Modules.mk
index 1f9973b4..bb8eff6c 100644
--- a/datapath/linux/Modules.mk
+++ b/datapath/linux/Modules.mk
@@ -1,6 +1,7 @@
openvswitch_sources += \
linux/compat/addrconf_core-openvswitch.c \
linux/compat/dev-openvswitch.c \
+ linux/compat/exthdrs_core.c \
linux/compat/flex_array.c \
linux/compat/genetlink-openvswitch.c \
linux/compat/ip_output-openvswitch.c \
diff --git a/datapath/linux/compat/exthdrs_core.c b/datapath/linux/compat/exthdrs_core.c
new file mode 100644
index 00000000..658e16ac
--- /dev/null
+++ b/datapath/linux/compat/exthdrs_core.c
@@ -0,0 +1,48 @@
+#include <linux/ipv6.h>
+#include <net/ipv6.h>
+
+/* This function is upstream but not the version which supplies the
+ * fragment offset. We plan to propose the extended version.
+ */
+int rpl_ipv6_skip_exthdr(const struct sk_buff *skb, int start,
+ u8 *nexthdrp, __be16 *frag_offp)
+{
+ u8 nexthdr = *nexthdrp;
+
+ *frag_offp = 0;
+
+ while (ipv6_ext_hdr(nexthdr)) {
+ struct ipv6_opt_hdr _hdr, *hp;
+ int hdrlen;
+
+ if (nexthdr == NEXTHDR_NONE)
+ return -1;
+ hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
+ if (hp == NULL)
+ return -1;
+ if (nexthdr == NEXTHDR_FRAGMENT) {
+ __be16 _frag_off, *fp;
+ fp = skb_header_pointer(skb,
+ start+offsetof(struct frag_hdr,
+ frag_off),
+ sizeof(_frag_off),
+ &_frag_off);
+ if (fp == NULL)
+ return -1;
+
+ *frag_offp = *fp;
+ if (ntohs(*frag_offp) & ~0x7)
+ break;
+ hdrlen = 8;
+ } else if (nexthdr == NEXTHDR_AUTH)
+ hdrlen = (hp->hdrlen+2)<<2;
+ else
+ hdrlen = ipv6_optlen(hp);
+
+ nexthdr = hp->nexthdr;
+ start += hdrlen;
+ }
+
+ *nexthdrp = nexthdr;
+ return start;
+}
diff --git a/datapath/linux/compat/include/linux/ipv6.h b/datapath/linux/compat/include/linux/ipv6.h
index 25a5431a..fdbbe62a 100644
--- a/datapath/linux/compat/include/linux/ipv6.h
+++ b/datapath/linux/compat/include/linux/ipv6.h
@@ -2,6 +2,7 @@
#define __LINUX_IPV6_WRAPPER_H 1
#include_next <linux/ipv6.h>
+#include <net/ipv6.h>
#ifndef HAVE_SKBUFF_HEADER_HELPERS
static inline struct ipv6hdr *ipv6_hdr(const struct sk_buff *skb)
@@ -10,4 +11,11 @@ static inline struct ipv6hdr *ipv6_hdr(const struct sk_buff *skb)
}
#endif
+/* This function is upstream but not the version which supplies the
+ * fragment offset. We plan to propose the extended version.
+ */
+#define ipv6_skip_exthdr rpl_ipv6_skip_exthdr
+extern int rpl_ipv6_skip_exthdr(const struct sk_buff *skb, int start,
+ u8 *nexthdrp, __be16 *frag_offp);
+
#endif
diff --git a/datapath/tunnel.c b/datapath/tunnel.c
index 4ce830ff..33d2fe93 100644
--- a/datapath/tunnel.c
+++ b/datapath/tunnel.c
@@ -538,6 +538,7 @@ static bool ipv6_should_icmp(struct sk_buff *skb)
int addr_type;
int payload_off = (u8 *)(old_ipv6h + 1) - skb->data;
u8 nexthdr = ipv6_hdr(skb)->nexthdr;
+ __be16 frag_off;
/* Check source address is valid. */
addr_type = ipv6_addr_type(&old_ipv6h->saddr);
@@ -549,7 +550,7 @@ static bool ipv6_should_icmp(struct sk_buff *skb)
return false;
/* Don't respond to ICMP error messages. */
- payload_off = ipv6_skip_exthdr(skb, payload_off, &nexthdr);
+ payload_off = ipv6_skip_exthdr(skb, payload_off, &nexthdr, &frag_off);
if (payload_off < 0)
return false;