aboutsummaryrefslogtreecommitdiffstats
path: root/net/core
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2012-02-08 03:51:50 -0500
committerDavid S. Miller <davem@davemloft.net>2012-02-08 15:50:01 -0500
commit43480aecb1f538d4f6dd8b2c5d2b71fb98659072 (patch)
tree11e3720c45cccc5696744c8e0743edd3d53d84c4 /net/core
parent377cb4f9e763465984b9bb5187747fd9b02a14c0 (diff)
gro: more generic L2 header check
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>
Diffstat (limited to 'net/core')
-rw-r--r--net/core/dev.c10
1 files changed, 8 insertions, 2 deletions
diff --git a/net/core/dev.c b/net/core/dev.c
index f1249472e90e..763a0eda7158 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -3491,14 +3491,20 @@ static inline gro_result_t
3491__napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb) 3491__napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
3492{ 3492{
3493 struct sk_buff *p; 3493 struct sk_buff *p;
3494 unsigned int maclen = skb->dev->hard_header_len;
3494 3495
3495 for (p = napi->gro_list; p; p = p->next) { 3496 for (p = napi->gro_list; p; p = p->next) {
3496 unsigned long diffs; 3497 unsigned long diffs;
3497 3498
3498 diffs = (unsigned long)p->dev ^ (unsigned long)skb->dev; 3499 diffs = (unsigned long)p->dev ^ (unsigned long)skb->dev;
3499 diffs |= p->vlan_tci ^ skb->vlan_tci; 3500 diffs |= p->vlan_tci ^ skb->vlan_tci;
3500 diffs |= compare_ether_header(skb_mac_header(p), 3501 if (maclen == ETH_HLEN)
3501 skb_gro_mac_header(skb)); 3502 diffs |= compare_ether_header(skb_mac_header(p),
3503 skb_gro_mac_header(skb));
3504 else if (!diffs)
3505 diffs = memcmp(skb_mac_header(p),
3506 skb_gro_mac_header(skb),
3507 maclen);
3502 NAPI_GRO_CB(p)->same_flow = !diffs; 3508 NAPI_GRO_CB(p)->same_flow = !diffs;
3503 NAPI_GRO_CB(p)->flush = 0; 3509 NAPI_GRO_CB(p)->flush = 0;
3504 } 3510 }