| From 61da319dee13f93077be3c40d226805a7c7b57b5 Mon Sep 17 00:00:00 2001 |
| From: Eric Dumazet <eric.dumazet@gmail.com> |
| Date: Wed, 8 Feb 2012 08:51:50 +0000 |
| Subject: gro: more generic L2 header check |
| |
| |
| From: Eric Dumazet <eric.dumazet@gmail.com> |
| |
| [ Upstream commit 5ca3b72c5da47d95b83857b768def6172fbc080a ] |
| |
| Shlomo Pongratz reported GRO L2 header check was suited for Ethernet |
| only, and failed on IB/ipoib traffic. |
| |
| He provided a patch faking a zeroed header to let GRO aggregates frames. |
| |
| Roland Dreier, Herbert Xu, and others suggested we change GRO L2 header |
| check to be more generic, ie not assuming L2 header is 14 bytes, but |
| taking into account hard_header_len. |
| |
| __napi_gro_receive() has special handling for the common case (Ethernet) |
| to avoid a memcmp() call and use an inline optimized function instead. |
| |
| Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> |
| Reported-by: Shlomo Pongratz <shlomop@mellanox.com> |
| Cc: Roland Dreier <roland@kernel.org> |
| Cc: Or Gerlitz <ogerlitz@mellanox.com> |
| Cc: Herbert Xu <herbert@gondor.apana.org.au> |
| Tested-by: Sean Hefty <sean.hefty@intel.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| net/core/dev.c | 10 ++++++++-- |
| 1 file changed, 8 insertions(+), 2 deletions(-) |
| |
| --- a/net/core/dev.c |
| +++ b/net/core/dev.c |
| @@ -3565,14 +3565,20 @@ static inline gro_result_t |
| __napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb) |
| { |
| struct sk_buff *p; |
| + unsigned int maclen = skb->dev->hard_header_len; |
| |
| for (p = napi->gro_list; p; p = p->next) { |
| unsigned long diffs; |
| |
| diffs = (unsigned long)p->dev ^ (unsigned long)skb->dev; |
| diffs |= p->vlan_tci ^ skb->vlan_tci; |
| - diffs |= compare_ether_header(skb_mac_header(p), |
| - skb_gro_mac_header(skb)); |
| + if (maclen == ETH_HLEN) |
| + diffs |= compare_ether_header(skb_mac_header(p), |
| + skb_gro_mac_header(skb)); |
| + else if (!diffs) |
| + diffs = memcmp(skb_mac_header(p), |
| + skb_gro_mac_header(skb), |
| + maclen); |
| NAPI_GRO_CB(p)->same_flow = !diffs; |
| NAPI_GRO_CB(p)->flush = 0; |
| } |