aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ndisc.c
diff options
context:
space:
mode:
authorBrian Haley <brian.haley@hp.com>2008-11-04 20:51:14 -0500
committerJeff Garzik <jgarzik@redhat.com>2008-11-06 00:49:37 -0500
commit305d552accae6afb859c493ebc7d98ca3371dae2 (patch)
treeaa1230b1a6cf85ceb36d3e8a8a155ef4348523b6 /net/ipv6/ndisc.c
parent61c9eaf90081cbe6dc4f389e0056bff76eca19ec (diff)
bonding: send IPv6 neighbor advertisement on failover
This patch adds better IPv6 failover support for bonding devices, especially when in active-backup mode and there are only IPv6 addresses configured, as reported by Alex Sidorenko. - Creates a new file, net/drivers/bonding/bond_ipv6.c, for the IPv6-specific routines. Both regular bonds and VLANs over bonds are supported. - Adds a new tunable, num_unsol_na, to limit the number of unsolicited IPv6 Neighbor Advertisements that are sent on a failover event. Default is 1. - Creates two new IPv6 neighbor discovery functions: ndisc_build_skb() ndisc_send_skb() These were required to support VLANs since we have to be able to add the VLAN id to the skb since ndisc_send_na() and friends shouldn't be asked to do this. These two routines are basically __ndisc_send() split into two pieces, in a slightly different order. - Updates Documentation/networking/bonding.txt and bumps the rev of bond support to 3.4.0. On failover, this new code will generate one packet: - An unsolicited IPv6 Neighbor Advertisement, which helps the switch learn that the address has moved to the new slave. Testing has shown that sending just the NA results in pretty good behavior when in active-back mode, I saw no lost ping packets for example. Signed-off-by: Brian Haley <brian.haley@hp.com> Signed-off-by: Jay Vosburgh <fubar@us.ibm.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'net/ipv6/ndisc.c')
-rw-r--r--net/ipv6/ndisc.c92
1 files changed, 65 insertions, 27 deletions
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 2a6752dae09d..fbf451c0d77a 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -437,38 +437,20 @@ static void pndisc_destructor(struct pneigh_entry *n)
437 ipv6_dev_mc_dec(dev, &maddr); 437 ipv6_dev_mc_dec(dev, &maddr);
438} 438}
439 439
440/* 440struct sk_buff *ndisc_build_skb(struct net_device *dev,
441 * Send a Neighbour Advertisement 441 const struct in6_addr *daddr,
442 */ 442 const struct in6_addr *saddr,
443static void __ndisc_send(struct net_device *dev, 443 struct icmp6hdr *icmp6h,
444 struct neighbour *neigh, 444 const struct in6_addr *target,
445 const struct in6_addr *daddr, 445 int llinfo)
446 const struct in6_addr *saddr,
447 struct icmp6hdr *icmp6h, const struct in6_addr *target,
448 int llinfo)
449{ 446{
450 struct flowi fl;
451 struct dst_entry *dst;
452 struct net *net = dev_net(dev); 447 struct net *net = dev_net(dev);
453 struct sock *sk = net->ipv6.ndisc_sk; 448 struct sock *sk = net->ipv6.ndisc_sk;
454 struct sk_buff *skb; 449 struct sk_buff *skb;
455 struct icmp6hdr *hdr; 450 struct icmp6hdr *hdr;
456 struct inet6_dev *idev;
457 int len; 451 int len;
458 int err; 452 int err;
459 u8 *opt, type; 453 u8 *opt;
460
461 type = icmp6h->icmp6_type;
462
463 icmpv6_flow_init(sk, &fl, type, saddr, daddr, dev->ifindex);
464
465 dst = icmp6_dst_alloc(dev, neigh, daddr);
466 if (!dst)
467 return;
468
469 err = xfrm_lookup(&dst, &fl, NULL, 0);
470 if (err < 0)
471 return;
472 454
473 if (!dev->addr_len) 455 if (!dev->addr_len)
474 llinfo = 0; 456 llinfo = 0;
@@ -485,8 +467,7 @@ static void __ndisc_send(struct net_device *dev,
485 ND_PRINTK0(KERN_ERR 467 ND_PRINTK0(KERN_ERR
486 "ICMPv6 ND: %s() failed to allocate an skb.\n", 468 "ICMPv6 ND: %s() failed to allocate an skb.\n",
487 __func__); 469 __func__);
488 dst_release(dst); 470 return NULL;
489 return;
490 } 471 }
491 472
492 skb_reserve(skb, LL_RESERVED_SPACE(dev)); 473 skb_reserve(skb, LL_RESERVED_SPACE(dev));
@@ -513,6 +494,42 @@ static void __ndisc_send(struct net_device *dev,
513 csum_partial((__u8 *) hdr, 494 csum_partial((__u8 *) hdr,
514 len, 0)); 495 len, 0));
515 496
497 return skb;
498}
499
500EXPORT_SYMBOL(ndisc_build_skb);
501
502void ndisc_send_skb(struct sk_buff *skb,
503 struct net_device *dev,
504 struct neighbour *neigh,
505 const struct in6_addr *daddr,
506 const struct in6_addr *saddr,
507 struct icmp6hdr *icmp6h)
508{
509 struct flowi fl;
510 struct dst_entry *dst;
511 struct net *net = dev_net(dev);
512 struct sock *sk = net->ipv6.ndisc_sk;
513 struct inet6_dev *idev;
514 int err;
515 u8 type;
516
517 type = icmp6h->icmp6_type;
518
519 icmpv6_flow_init(sk, &fl, type, saddr, daddr, dev->ifindex);
520
521 dst = icmp6_dst_alloc(dev, neigh, daddr);
522 if (!dst) {
523 kfree_skb(skb);
524 return;
525 }
526
527 err = xfrm_lookup(&dst, &fl, NULL, 0);
528 if (err < 0) {
529 kfree_skb(skb);
530 return;
531 }
532
516 skb->dst = dst; 533 skb->dst = dst;
517 534
518 idev = in6_dev_get(dst->dev); 535 idev = in6_dev_get(dst->dev);
@@ -529,6 +546,27 @@ static void __ndisc_send(struct net_device *dev,
529 in6_dev_put(idev); 546 in6_dev_put(idev);
530} 547}
531 548
549EXPORT_SYMBOL(ndisc_send_skb);
550
551/*
552 * Send a Neighbour Discover packet
553 */
554static void __ndisc_send(struct net_device *dev,
555 struct neighbour *neigh,
556 const struct in6_addr *daddr,
557 const struct in6_addr *saddr,
558 struct icmp6hdr *icmp6h, const struct in6_addr *target,
559 int llinfo)
560{
561 struct sk_buff *skb;
562
563 skb = ndisc_build_skb(dev, daddr, saddr, icmp6h, target, llinfo);
564 if (!skb)
565 return;
566
567 ndisc_send_skb(skb, dev, neigh, daddr, saddr, icmp6h);
568}
569
532static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, 570static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
533 const struct in6_addr *daddr, 571 const struct in6_addr *daddr,
534 const struct in6_addr *solicited_addr, 572 const struct in6_addr *solicited_addr,