aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/bonding/bond_main.c
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2013-04-15 13:03:24 -0400
committerDavid S. Miller <davem@davemloft.net>2013-04-18 15:07:29 -0400
commit4394542ca4ec9f28c3c8405063d200b1e7c347d7 (patch)
treec9a7a3b404ca74bafb3cf45bbfd3de4ceb7bb7e8 /drivers/net/bonding/bond_main.c
parent0c14e5ced264620284bd96f888614768c9bd0976 (diff)
bonding: fix l23 and l34 load balancing in forwarding path
Since commit 6b923cb7188d46 (bonding: support for IPv6 transmit hashing) bonding doesn't properly hash traffic in forwarding setups. Vitaly V. Bursov diagnosed that skb_network_header_len() returned 0 in this case. More generally, the transport header might not be in the skb head. Use pskb_may_pull() & skb_header_pointer() to get it right, and use proto_ports_offset() in bond_xmit_hash_policy_l34() to get support for more protocols than TCP and UDP. Reported-by: Vitaly V. Bursov <vitalyb@telenet.dn.ua> Signed-off-by: Eric Dumazet <edumazet@google.com> Cc: Jay Vosburgh <fubar@us.ibm.com> Cc: Andy Gospodarek <andy@greyhouse.net> Cc: John Eaglesham <linux@8192.net> Tested-by: Vitaly V. Bursov <vitalyb@telenet.dn.ua> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/bonding/bond_main.c')
-rw-r--r--drivers/net/bonding/bond_main.c55
1 files changed, 30 insertions, 25 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index a61a760484f7..dea8ce20fea4 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -3296,20 +3296,22 @@ static int bond_xmit_hash_policy_l2(struct sk_buff *skb, int count)
3296 */ 3296 */
3297static int bond_xmit_hash_policy_l23(struct sk_buff *skb, int count) 3297static int bond_xmit_hash_policy_l23(struct sk_buff *skb, int count)
3298{ 3298{
3299 struct ethhdr *data = (struct ethhdr *)skb->data; 3299 const struct ethhdr *data;
3300 struct iphdr *iph; 3300 const struct iphdr *iph;
3301 struct ipv6hdr *ipv6h; 3301 const struct ipv6hdr *ipv6h;
3302 u32 v6hash; 3302 u32 v6hash;
3303 __be32 *s, *d; 3303 const __be32 *s, *d;
3304 3304
3305 if (skb->protocol == htons(ETH_P_IP) && 3305 if (skb->protocol == htons(ETH_P_IP) &&
3306 skb_network_header_len(skb) >= sizeof(*iph)) { 3306 pskb_network_may_pull(skb, sizeof(*iph))) {
3307 iph = ip_hdr(skb); 3307 iph = ip_hdr(skb);
3308 data = (struct ethhdr *)skb->data;
3308 return ((ntohl(iph->saddr ^ iph->daddr) & 0xffff) ^ 3309 return ((ntohl(iph->saddr ^ iph->daddr) & 0xffff) ^
3309 (data->h_dest[5] ^ data->h_source[5])) % count; 3310 (data->h_dest[5] ^ data->h_source[5])) % count;
3310 } else if (skb->protocol == htons(ETH_P_IPV6) && 3311 } else if (skb->protocol == htons(ETH_P_IPV6) &&
3311 skb_network_header_len(skb) >= sizeof(*ipv6h)) { 3312 pskb_network_may_pull(skb, sizeof(*ipv6h))) {
3312 ipv6h = ipv6_hdr(skb); 3313 ipv6h = ipv6_hdr(skb);
3314 data = (struct ethhdr *)skb->data;
3313 s = &ipv6h->saddr.s6_addr32[0]; 3315 s = &ipv6h->saddr.s6_addr32[0];
3314 d = &ipv6h->daddr.s6_addr32[0]; 3316 d = &ipv6h->daddr.s6_addr32[0];
3315 v6hash = (s[1] ^ d[1]) ^ (s[2] ^ d[2]) ^ (s[3] ^ d[3]); 3317 v6hash = (s[1] ^ d[1]) ^ (s[2] ^ d[2]) ^ (s[3] ^ d[3]);
@@ -3328,33 +3330,36 @@ static int bond_xmit_hash_policy_l23(struct sk_buff *skb, int count)
3328static int bond_xmit_hash_policy_l34(struct sk_buff *skb, int count) 3330static int bond_xmit_hash_policy_l34(struct sk_buff *skb, int count)
3329{ 3331{
3330 u32 layer4_xor = 0; 3332 u32 layer4_xor = 0;
3331 struct iphdr *iph; 3333 const struct iphdr *iph;
3332 struct ipv6hdr *ipv6h; 3334 const struct ipv6hdr *ipv6h;
3333 __be32 *s, *d; 3335 const __be32 *s, *d;
3334 __be16 *layer4hdr; 3336 const __be16 *l4 = NULL;
3337 __be16 _l4[2];
3338 int noff = skb_network_offset(skb);
3339 int poff;
3335 3340
3336 if (skb->protocol == htons(ETH_P_IP) && 3341 if (skb->protocol == htons(ETH_P_IP) &&
3337 skb_network_header_len(skb) >= sizeof(*iph)) { 3342 pskb_may_pull(skb, noff + sizeof(*iph))) {
3338 iph = ip_hdr(skb); 3343 iph = ip_hdr(skb);
3339 if (!ip_is_fragment(iph) && 3344 poff = proto_ports_offset(iph->protocol);
3340 (iph->protocol == IPPROTO_TCP || 3345
3341 iph->protocol == IPPROTO_UDP) && 3346 if (!ip_is_fragment(iph) && poff >= 0) {
3342 (skb_headlen(skb) - skb_network_offset(skb) >= 3347 l4 = skb_header_pointer(skb, noff + (iph->ihl << 2) + poff,
3343 iph->ihl * sizeof(u32) + sizeof(*layer4hdr) * 2)) { 3348 sizeof(_l4), &_l4);
3344 layer4hdr = (__be16 *)((u32 *)iph + iph->ihl); 3349 if (l4)
3345 layer4_xor = ntohs(*layer4hdr ^ *(layer4hdr + 1)); 3350 layer4_xor = ntohs(l4[0] ^ l4[1]);
3346 } 3351 }
3347 return (layer4_xor ^ 3352 return (layer4_xor ^
3348 ((ntohl(iph->saddr ^ iph->daddr)) & 0xffff)) % count; 3353 ((ntohl(iph->saddr ^ iph->daddr)) & 0xffff)) % count;
3349 } else if (skb->protocol == htons(ETH_P_IPV6) && 3354 } else if (skb->protocol == htons(ETH_P_IPV6) &&
3350 skb_network_header_len(skb) >= sizeof(*ipv6h)) { 3355 pskb_may_pull(skb, noff + sizeof(*ipv6h))) {
3351 ipv6h = ipv6_hdr(skb); 3356 ipv6h = ipv6_hdr(skb);
3352 if ((ipv6h->nexthdr == IPPROTO_TCP || 3357 poff = proto_ports_offset(ipv6h->nexthdr);
3353 ipv6h->nexthdr == IPPROTO_UDP) && 3358 if (poff >= 0) {
3354 (skb_headlen(skb) - skb_network_offset(skb) >= 3359 l4 = skb_header_pointer(skb, noff + sizeof(*ipv6h) + poff,
3355 sizeof(*ipv6h) + sizeof(*layer4hdr) * 2)) { 3360 sizeof(_l4), &_l4);
3356 layer4hdr = (__be16 *)(ipv6h + 1); 3361 if (l4)
3357 layer4_xor = ntohs(*layer4hdr ^ *(layer4hdr + 1)); 3362 layer4_xor = ntohs(l4[0] ^ l4[1]);
3358 } 3363 }
3359 s = &ipv6h->saddr.s6_addr32[0]; 3364 s = &ipv6h->saddr.s6_addr32[0];
3360 d = &ipv6h->daddr.s6_addr32[0]; 3365 d = &ipv6h->daddr.s6_addr32[0];