Paul Durrant
2013-Nov-28 13:23 UTC
[PATCH net v2] xen-netback: fix fragment detection in checksum setup
The code to detect fragments in checksum_setup() was missing for IPv4 and
too eager for IPv6. (It transpires that Windows seems to send IPv6 packets
with a fragment header even if they are not a fragment - i.e. offset is zero,
and M bit is not set).
Signed-off-by: Paul Durrant <paul.durrant@citrix.com>
Cc: Wei Liu <wei.liu2@citrix.com>
Cc: Ian Campbell <ian.campbell@citrix.com>
Cc: David Vrabel <david.vrabel@citrix.com>
---
v2
- Added comments noting what fragment/offset masks mean
drivers/net/xen-netback/netback.c | 33 ++++++++++++++++++++++++++++++---
1 file changed, 30 insertions(+), 3 deletions(-)
diff --git a/drivers/net/xen-netback/netback.c
b/drivers/net/xen-netback/netback.c
index 919b650..c7464d8 100644
--- a/drivers/net/xen-netback/netback.c
+++ b/drivers/net/xen-netback/netback.c
@@ -1165,15 +1165,28 @@ static int checksum_setup_ip(struct xenvif *vif, struct
sk_buff *skb,
struct iphdr *iph = (void *)skb->data;
unsigned int header_size;
unsigned int off;
+ bool fragment;
int err = -EPROTO;
+ fragment = false;
+
off = sizeof(struct iphdr);
header_size = skb->network_header + off + MAX_IPOPTLEN;
maybe_pull_tail(skb, header_size);
+ /* 3fff -> fragment offset != 0 OR more fragments */
+ if (ntohs(iph->frag_off) & 0x3fff)
+ fragment = true;
+
off = iph->ihl * 4;
+ if (fragment) {
+ if (net_ratelimit())
+ netdev_err(vif->dev, "Packet is a fragment!\n");
+ goto out;
+ }
+
switch (iph->protocol) {
case IPPROTO_TCP:
if (!skb_partial_csum_set(skb, off,
@@ -1237,6 +1250,7 @@ static int checksum_setup_ipv6(struct xenvif *vif, struct
sk_buff *skb,
bool fragment;
bool done;
+ fragment = false;
done = false;
off = sizeof(struct ipv6hdr);
@@ -1275,9 +1289,22 @@ static int checksum_setup_ipv6(struct xenvif *vif, struct
sk_buff *skb,
off += (hp->hdrlen+2)<<2;
break;
}
- case IPPROTO_FRAGMENT:
- fragment = true;
- /* fall through */
+ case IPPROTO_FRAGMENT: {
+ struct frag_hdr *hp = (void *)(skb->data + off);
+
+ header_size = skb->network_header +
+ off +
+ sizeof(struct frag_hdr);
+ maybe_pull_tail(skb, header_size);
+
+ /* fff9 -> fragment offset != 0 OR more fragments */
+ if (ntohs(hp->frag_off) & 0xfff9)
+ fragment = true;
+
+ nexthdr = hp->nexthdr;
+ off += sizeof(struct frag_hdr);
+ break;
+ }
default:
done = true;
break;
--
1.7.10.4
Eric Dumazet
2013-Nov-28 17:29 UTC
Re: [PATCH net v2] xen-netback: fix fragment detection in checksum setup
On Thu, 2013-11-28 at 13:23 +0000, Paul Durrant wrote:> The code to detect fragments in checksum_setup() was missing for IPv4 and > too eager for IPv6. (It transpires that Windows seems to send IPv6 packets > with a fragment header even if they are not a fragment - i.e. offset is zero, > and M bit is not set).> + /* 3fff -> fragment offset != 0 OR more fragments */ > + if (ntohs(iph->frag_off) & 0x3fff) > + fragment = true; > +What about the more self documented and faster : if (iph->frag_off & htons(IP_OFFSET | IP_MF)) fragment = true;
annie li
2013-Nov-29 05:35 UTC
Re: [PATCH net v2] xen-netback: fix fragment detection in checksum setup
On 2013/11/28 21:23, Paul Durrant wrote:> The code to detect fragments in checksum_setup() was missing for IPv4 and > too eager for IPv6. (It transpires that Windows seems to send IPv6 packets > with a fragment header even if they are not a fragment - i.e. offset is zero, > and M bit is not set). > > Signed-off-by: Paul Durrant <paul.durrant@citrix.com> > Cc: Wei Liu <wei.liu2@citrix.com> > Cc: Ian Campbell <ian.campbell@citrix.com> > Cc: David Vrabel <david.vrabel@citrix.com> > --- > v2 > > - Added comments noting what fragment/offset masks mean > > drivers/net/xen-netback/netback.c | 33 ++++++++++++++++++++++++++++++--- > 1 file changed, 30 insertions(+), 3 deletions(-) > > diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c > index 919b650..c7464d8 100644 > --- a/drivers/net/xen-netback/netback.c > +++ b/drivers/net/xen-netback/netback.c > @@ -1165,15 +1165,28 @@ static int checksum_setup_ip(struct xenvif *vif, struct sk_buff *skb, > struct iphdr *iph = (void *)skb->data; > unsigned int header_size; > unsigned int off; > + bool fragment; > int err = -EPROTO; > > + fragment = false;Is it better to initialize fragment directly as following? bool fragment = false;> + > off = sizeof(struct iphdr); > > header_size = skb->network_header + off + MAX_IPOPTLEN; > maybe_pull_tail(skb, header_size); > > + /* 3fff -> fragment offset != 0 OR more fragments */ > + if (ntohs(iph->frag_off) & 0x3fff) > + fragment = true; > + > off = iph->ihl * 4; > > + if (fragment) { > + if (net_ratelimit()) > + netdev_err(vif->dev, "Packet is a fragment!\n"); > + goto out; > + } > + > switch (iph->protocol) { > case IPPROTO_TCP: > if (!skb_partial_csum_set(skb, off, > @@ -1237,6 +1250,7 @@ static int checksum_setup_ipv6(struct xenvif *vif, struct sk_buff *skb, > bool fragment; > bool done; > > + fragment = false; > done = false;Same as above for "done" and "fragment"... Thanks Annie
Paul Durrant
2013-Nov-29 09:10 UTC
Re: [PATCH net v2] xen-netback: fix fragment detection in checksum setup
> -----Original Message----- > From: annie li [mailto:annie.li@oracle.com] > Sent: 29 November 2013 05:36 > To: Paul Durrant > Cc: xen-devel@lists.xen.org; netdev@vger.kernel.org; Wei Liu; Ian Campbell; > David Vrabel > Subject: Re: [PATCH net v2] xen-netback: fix fragment detection in checksum > setup > > > On 2013/11/28 21:23, Paul Durrant wrote: > > The code to detect fragments in checksum_setup() was missing for IPv4 > and > > too eager for IPv6. (It transpires that Windows seems to send IPv6 packets > > with a fragment header even if they are not a fragment - i.e. offset is zero, > > and M bit is not set). > > > > Signed-off-by: Paul Durrant <paul.durrant@citrix.com> > > Cc: Wei Liu <wei.liu2@citrix.com> > > Cc: Ian Campbell <ian.campbell@citrix.com> > > Cc: David Vrabel <david.vrabel@citrix.com> > > --- > > v2 > > > > - Added comments noting what fragment/offset masks mean > > > > drivers/net/xen-netback/netback.c | 33 > ++++++++++++++++++++++++++++++--- > > 1 file changed, 30 insertions(+), 3 deletions(-) > > > > diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen- > netback/netback.c > > index 919b650..c7464d8 100644 > > --- a/drivers/net/xen-netback/netback.c > > +++ b/drivers/net/xen-netback/netback.c > > @@ -1165,15 +1165,28 @@ static int checksum_setup_ip(struct xenvif *vif, > struct sk_buff *skb, > > struct iphdr *iph = (void *)skb->data; > > unsigned int header_size; > > unsigned int off; > > + bool fragment; > > int err = -EPROTO; > > > > + fragment = false; > > Is it better to initialize fragment directly as following? > bool fragment = false; >I think that''s a matter of personal taste. I tend to favour this style. Paul> > + > > off = sizeof(struct iphdr); > > > > header_size = skb->network_header + off + MAX_IPOPTLEN; > > maybe_pull_tail(skb, header_size); > > > > + /* 3fff -> fragment offset != 0 OR more fragments */ > > + if (ntohs(iph->frag_off) & 0x3fff) > > + fragment = true; > > + > > off = iph->ihl * 4; > > > > + if (fragment) { > > + if (net_ratelimit()) > > + netdev_err(vif->dev, "Packet is a fragment!\n"); > > + goto out; > > + } > > + > > switch (iph->protocol) { > > case IPPROTO_TCP: > > if (!skb_partial_csum_set(skb, off, > > @@ -1237,6 +1250,7 @@ static int checksum_setup_ipv6(struct xenvif *vif, > struct sk_buff *skb, > > bool fragment; > > bool done; > > > > + fragment = false; > > done = false; > > Same as above for "done" and "fragment"... > > Thanks > Annie
annie li
2013-Nov-29 09:57 UTC
Re: [PATCH net v2] xen-netback: fix fragment detection in checksum setup
On 2013/11/29 17:10, Paul Durrant wrote:>> -----Original Message----- >> From: annie li [mailto:annie.li@oracle.com] >> Sent: 29 November 2013 05:36 >> To: Paul Durrant >> Cc: xen-devel@lists.xen.org; netdev@vger.kernel.org; Wei Liu; Ian Campbell; >> David Vrabel >> Subject: Re: [PATCH net v2] xen-netback: fix fragment detection in checksum >> setup >> >> >> On 2013/11/28 21:23, Paul Durrant wrote: >>> The code to detect fragments in checksum_setup() was missing for IPv4 >> and >>> too eager for IPv6. (It transpires that Windows seems to send IPv6 packets >>> with a fragment header even if they are not a fragment - i.e. offset is zero, >>> and M bit is not set). >>> >>> Signed-off-by: Paul Durrant <paul.durrant@citrix.com> >>> Cc: Wei Liu <wei.liu2@citrix.com> >>> Cc: Ian Campbell <ian.campbell@citrix.com> >>> Cc: David Vrabel <david.vrabel@citrix.com> >>> --- >>> v2 >>> >>> - Added comments noting what fragment/offset masks mean >>> >>> drivers/net/xen-netback/netback.c | 33 >> ++++++++++++++++++++++++++++++--- >>> 1 file changed, 30 insertions(+), 3 deletions(-) >>> >>> diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen- >> netback/netback.c >>> index 919b650..c7464d8 100644 >>> --- a/drivers/net/xen-netback/netback.c >>> +++ b/drivers/net/xen-netback/netback.c >>> @@ -1165,15 +1165,28 @@ static int checksum_setup_ip(struct xenvif *vif, >> struct sk_buff *skb, >>> struct iphdr *iph = (void *)skb->data; >>> unsigned int header_size; >>> unsigned int off; >>> + bool fragment; >>> int err = -EPROTO; >>> >>> + fragment = false; >> Is it better to initialize fragment directly as following? >> bool fragment = false; >> > I think that''s a matter of personal taste. I tend to favour this style. >That is OK, I point this out because it is inconsistent with other variable initialization in netback.c. Thanks Annie> >>> + >>> off = sizeof(struct iphdr); >>> >>> header_size = skb->network_header + off + MAX_IPOPTLEN; >>> maybe_pull_tail(skb, header_size); >>> >>> + /* 3fff -> fragment offset != 0 OR more fragments */ >>> + if (ntohs(iph->frag_off) & 0x3fff) >>> + fragment = true; >>> + >>> off = iph->ihl * 4; >>> >>> + if (fragment) { >>> + if (net_ratelimit()) >>> + netdev_err(vif->dev, "Packet is a fragment!\n"); >>> + goto out; >>> + } >>> + >>> switch (iph->protocol) { >>> case IPPROTO_TCP: >>> if (!skb_partial_csum_set(skb, off, >>> @@ -1237,6 +1250,7 @@ static int checksum_setup_ipv6(struct xenvif *vif, >> struct sk_buff *skb, >>> bool fragment; >>> bool done; >>> >>> + fragment = false; >>> done = false; >> Same as above for "done" and "fragment"... >> >> Thanks >> Annie > _______________________________________________ > Xen-devel mailing list > Xen-devel@lists.xen.org > http://lists.xen.org/xen-devel
Paul Durrant
2013-Nov-29 10:32 UTC
Re: [PATCH net v2] xen-netback: fix fragment detection in checksum setup
> -----Original Message----- > From: Eric Dumazet [mailto:eric.dumazet@gmail.com] > Sent: 28 November 2013 17:29 > To: Paul Durrant > Cc: xen-devel@lists.xen.org; netdev@vger.kernel.org; Wei Liu; Ian Campbell; > David Vrabel > Subject: Re: [PATCH net v2] xen-netback: fix fragment detection in checksum > setup > > On Thu, 2013-11-28 at 13:23 +0000, Paul Durrant wrote: > > The code to detect fragments in checksum_setup() was missing for IPv4 > and > > too eager for IPv6. (It transpires that Windows seems to send IPv6 packets > > with a fragment header even if they are not a fragment - i.e. offset is zero, > > and M bit is not set). > > > + /* 3fff -> fragment offset != 0 OR more fragments */ > > + if (ntohs(iph->frag_off) & 0x3fff) > > + fragment = true; > > + > > What about the more self documented and faster : > > if (iph->frag_off & htons(IP_OFFSET | IP_MF)) > fragment = true; >Nicer definitely. I''ll need to add the equivalent def for IP6_OFFSET to use the same style of test there. Thanks, Paul