Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Brian Haley and committed by
Jeff Garzik
305d552a 61c9eaf9

+416 -31
+10
Documentation/networking/bonding.txt
··· 551 551 affects only the active-backup mode. This option was added for 552 552 bonding version 3.3.0. 553 553 554 + num_unsol_na 555 + 556 + Specifies the number of unsolicited IPv6 Neighbor Advertisements 557 + to be issued after a failover event. One unsolicited NA is issued 558 + immediately after the failover. 559 + 560 + The valid range is 0 - 255; the default value is 1. This option 561 + affects only the active-backup mode. This option was added for 562 + bonding version 3.4.0. 563 + 554 564 primary 555 565 556 566 A string (eth0, eth2, etc) specifying which slave is the
+1
drivers/net/Kconfig
··· 61 61 config BONDING 62 62 tristate "Bonding driver support" 63 63 depends on INET 64 + depends on IPV6 || IPV6=n 64 65 ---help--- 65 66 Say 'Y' or 'M' if you wish to be able to 'bond' multiple Ethernet 66 67 Channels together. This is called 'Etherchannel' by Cisco,
+3
drivers/net/bonding/Makefile
··· 6 6 7 7 bonding-objs := bond_main.o bond_3ad.o bond_alb.o bond_sysfs.o 8 8 9 + ipv6-$(subst m,y,$(CONFIG_IPV6)) += bond_ipv6.o 10 + bonding-objs += $(ipv6-y) 11 +
+218
drivers/net/bonding/bond_ipv6.c
··· 1 + /* 2 + * Copyright(c) 2008 Hewlett-Packard Development Company, L.P. 3 + * 4 + * This program is free software; you can redistribute it and/or modify it 5 + * under the terms of the GNU General Public License as published by the 6 + * Free Software Foundation; either version 2 of the License, or 7 + * (at your option) any later version. 8 + * 9 + * This program is distributed in the hope that it will be useful, but 10 + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 11 + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 + * for more details. 13 + * 14 + * You should have received a copy of the GNU General Public License along 15 + * with this program; if not, write to the Free Software Foundation, Inc., 16 + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 + * 18 + * The full GNU General Public License is included in this distribution in the 19 + * file called LICENSE. 20 + * 21 + */ 22 + 23 + //#define BONDING_DEBUG 1 24 + 25 + #include <linux/types.h> 26 + #include <linux/if_vlan.h> 27 + #include <net/ipv6.h> 28 + #include <net/ndisc.h> 29 + #include <net/addrconf.h> 30 + #include "bonding.h" 31 + 32 + /* 33 + * Assign bond->master_ipv6 to the next IPv6 address in the list, or 34 + * zero it out if there are none. 35 + */ 36 + static void bond_glean_dev_ipv6(struct net_device *dev, struct in6_addr *addr) 37 + { 38 + struct inet6_dev *idev; 39 + struct inet6_ifaddr *ifa; 40 + 41 + if (!dev) 42 + return; 43 + 44 + idev = in6_dev_get(dev); 45 + if (!idev) 46 + return; 47 + 48 + read_lock_bh(&idev->lock); 49 + ifa = idev->addr_list; 50 + if (ifa) 51 + ipv6_addr_copy(addr, &ifa->addr); 52 + else 53 + ipv6_addr_set(addr, 0, 0, 0, 0); 54 + 55 + read_unlock_bh(&idev->lock); 56 + 57 + in6_dev_put(idev); 58 + } 59 + 60 + static void bond_na_send(struct net_device *slave_dev, 61 + struct in6_addr *daddr, 62 + int router, 63 + unsigned short vlan_id) 64 + { 65 + struct in6_addr mcaddr; 66 + struct icmp6hdr icmp6h = { 67 + .icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT, 68 + }; 69 + struct sk_buff *skb; 70 + 71 + icmp6h.icmp6_router = router; 72 + icmp6h.icmp6_solicited = 0; 73 + icmp6h.icmp6_override = 1; 74 + 75 + addrconf_addr_solict_mult(daddr, &mcaddr); 76 + 77 + dprintk("ipv6 na on slave %s: dest %pI6, src %pI6\n", 78 + slave->name, &mcaddr, daddr); 79 + 80 + skb = ndisc_build_skb(slave_dev, &mcaddr, daddr, &icmp6h, daddr, 81 + ND_OPT_TARGET_LL_ADDR); 82 + 83 + if (!skb) { 84 + printk(KERN_ERR DRV_NAME ": NA packet allocation failed\n"); 85 + return; 86 + } 87 + 88 + if (vlan_id) { 89 + skb = vlan_put_tag(skb, vlan_id); 90 + if (!skb) { 91 + printk(KERN_ERR DRV_NAME ": failed to insert VLAN tag\n"); 92 + return; 93 + } 94 + } 95 + 96 + ndisc_send_skb(skb, slave_dev, NULL, &mcaddr, daddr, &icmp6h); 97 + } 98 + 99 + /* 100 + * Kick out an unsolicited Neighbor Advertisement for an IPv6 address on 101 + * the bonding master. This will help the switch learn our address 102 + * if in active-backup mode. 103 + * 104 + * Caller must hold curr_slave_lock for read or better 105 + */ 106 + void bond_send_unsolicited_na(struct bonding *bond) 107 + { 108 + struct slave *slave = bond->curr_active_slave; 109 + struct vlan_entry *vlan; 110 + struct inet6_dev *idev; 111 + int is_router; 112 + 113 + dprintk("bond_send_unsol_na: bond %s slave %s\n", bond->dev->name, 114 + slave ? slave->dev->name : "NULL"); 115 + 116 + if (!slave || !bond->send_unsol_na || 117 + test_bit(__LINK_STATE_LINKWATCH_PENDING, &slave->dev->state)) 118 + return; 119 + 120 + bond->send_unsol_na--; 121 + 122 + idev = in6_dev_get(bond->dev); 123 + if (!idev) 124 + return; 125 + 126 + is_router = !!idev->cnf.forwarding; 127 + 128 + in6_dev_put(idev); 129 + 130 + if (!ipv6_addr_any(&bond->master_ipv6)) 131 + bond_na_send(slave->dev, &bond->master_ipv6, is_router, 0); 132 + 133 + list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { 134 + if (!ipv6_addr_any(&vlan->vlan_ipv6)) { 135 + bond_na_send(slave->dev, &vlan->vlan_ipv6, is_router, 136 + vlan->vlan_id); 137 + } 138 + } 139 + } 140 + 141 + /* 142 + * bond_inet6addr_event: handle inet6addr notifier chain events. 143 + * 144 + * We keep track of device IPv6 addresses primarily to use as source 145 + * addresses in NS probes. 146 + * 147 + * We track one IPv6 for the main device (if it has one). 148 + */ 149 + static int bond_inet6addr_event(struct notifier_block *this, 150 + unsigned long event, 151 + void *ptr) 152 + { 153 + struct inet6_ifaddr *ifa = ptr; 154 + struct net_device *vlan_dev, *event_dev = ifa->idev->dev; 155 + struct bonding *bond; 156 + struct vlan_entry *vlan; 157 + 158 + if (dev_net(event_dev) != &init_net) 159 + return NOTIFY_DONE; 160 + 161 + list_for_each_entry(bond, &bond_dev_list, bond_list) { 162 + if (bond->dev == event_dev) { 163 + switch (event) { 164 + case NETDEV_UP: 165 + if (ipv6_addr_any(&bond->master_ipv6)) 166 + ipv6_addr_copy(&bond->master_ipv6, 167 + &ifa->addr); 168 + return NOTIFY_OK; 169 + case NETDEV_DOWN: 170 + if (ipv6_addr_equal(&bond->master_ipv6, 171 + &ifa->addr)) 172 + bond_glean_dev_ipv6(bond->dev, 173 + &bond->master_ipv6); 174 + return NOTIFY_OK; 175 + default: 176 + return NOTIFY_DONE; 177 + } 178 + } 179 + 180 + list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { 181 + vlan_dev = vlan_group_get_device(bond->vlgrp, 182 + vlan->vlan_id); 183 + if (vlan_dev == event_dev) { 184 + switch (event) { 185 + case NETDEV_UP: 186 + if (ipv6_addr_any(&vlan->vlan_ipv6)) 187 + ipv6_addr_copy(&vlan->vlan_ipv6, 188 + &ifa->addr); 189 + return NOTIFY_OK; 190 + case NETDEV_DOWN: 191 + if (ipv6_addr_equal(&vlan->vlan_ipv6, 192 + &ifa->addr)) 193 + bond_glean_dev_ipv6(vlan_dev, 194 + &vlan->vlan_ipv6); 195 + return NOTIFY_OK; 196 + default: 197 + return NOTIFY_DONE; 198 + } 199 + } 200 + } 201 + } 202 + return NOTIFY_DONE; 203 + } 204 + 205 + static struct notifier_block bond_inet6addr_notifier = { 206 + .notifier_call = bond_inet6addr_event, 207 + }; 208 + 209 + void bond_register_ipv6_notifier(void) 210 + { 211 + register_inet6addr_notifier(&bond_inet6addr_notifier); 212 + } 213 + 214 + void bond_unregister_ipv6_notifier(void) 215 + { 216 + unregister_inet6addr_notifier(&bond_inet6addr_notifier); 217 + } 218 +
+31 -2
drivers/net/bonding/bond_main.c
··· 89 89 90 90 static int max_bonds = BOND_DEFAULT_MAX_BONDS; 91 91 static int num_grat_arp = 1; 92 + static int num_unsol_na = 1; 92 93 static int miimon = BOND_LINK_MON_INTERV; 93 94 static int updelay = 0; 94 95 static int downdelay = 0; ··· 108 107 MODULE_PARM_DESC(max_bonds, "Max number of bonded devices"); 109 108 module_param(num_grat_arp, int, 0644); 110 109 MODULE_PARM_DESC(num_grat_arp, "Number of gratuitous ARP packets to send on failover event"); 110 + module_param(num_unsol_na, int, 0644); 111 + MODULE_PARM_DESC(num_unsol_na, "Number of unsolicited IPv6 Neighbor Advertisements packets to send on failover event"); 111 112 module_param(miimon, int, 0); 112 113 MODULE_PARM_DESC(miimon, "Link check interval in milliseconds"); 113 114 module_param(updelay, int, 0); ··· 245 242 dprintk("bond: %s, vlan id %d\n", 246 243 (bond ? bond->dev->name: "None"), vlan_id); 247 244 248 - vlan = kmalloc(sizeof(struct vlan_entry), GFP_KERNEL); 245 + vlan = kzalloc(sizeof(struct vlan_entry), GFP_KERNEL); 249 246 if (!vlan) { 250 247 return -ENOMEM; 251 248 } 252 249 253 250 INIT_LIST_HEAD(&vlan->vlan_list); 254 251 vlan->vlan_id = vlan_id; 255 - vlan->vlan_ip = 0; 256 252 257 253 write_lock_bh(&bond->lock); 258 254 ··· 1209 1207 1210 1208 bond->send_grat_arp = bond->params.num_grat_arp; 1211 1209 bond_send_gratuitous_arp(bond); 1210 + 1211 + bond->send_unsol_na = bond->params.num_unsol_na; 1212 + bond_send_unsolicited_na(bond); 1212 1213 1213 1214 write_unlock_bh(&bond->curr_slave_lock); 1214 1215 read_unlock(&bond->lock); ··· 2468 2463 read_unlock(&bond->curr_slave_lock); 2469 2464 } 2470 2465 2466 + if (bond->send_unsol_na) { 2467 + read_lock(&bond->curr_slave_lock); 2468 + bond_send_unsolicited_na(bond); 2469 + read_unlock(&bond->curr_slave_lock); 2470 + } 2471 + 2471 2472 if (bond_miimon_inspect(bond)) { 2472 2473 read_unlock(&bond->lock); 2473 2474 rtnl_lock(); ··· 3169 3158 read_unlock(&bond->curr_slave_lock); 3170 3159 } 3171 3160 3161 + if (bond->send_unsol_na) { 3162 + read_lock(&bond->curr_slave_lock); 3163 + bond_send_unsolicited_na(bond); 3164 + read_unlock(&bond->curr_slave_lock); 3165 + } 3166 + 3172 3167 if (bond_ab_arp_inspect(bond, delta_in_ticks)) { 3173 3168 read_unlock(&bond->lock); 3174 3169 rtnl_lock(); ··· 3844 3827 write_lock_bh(&bond->lock); 3845 3828 3846 3829 bond->send_grat_arp = 0; 3830 + bond->send_unsol_na = 0; 3847 3831 3848 3832 /* signal timers not to re-arm */ 3849 3833 bond->kill_timers = 1; ··· 4560 4542 bond->primary_slave = NULL; 4561 4543 bond->dev = bond_dev; 4562 4544 bond->send_grat_arp = 0; 4545 + bond->send_unsol_na = 0; 4563 4546 bond->setup_by_slave = 0; 4564 4547 INIT_LIST_HEAD(&bond->vlan_list); 4565 4548 ··· 4810 4791 num_grat_arp = 1; 4811 4792 } 4812 4793 4794 + if (num_unsol_na < 0 || num_unsol_na > 255) { 4795 + printk(KERN_WARNING DRV_NAME 4796 + ": Warning: num_unsol_na (%d) not in range 0-255 so it " 4797 + "was reset to 1 \n", num_unsol_na); 4798 + num_unsol_na = 1; 4799 + } 4800 + 4813 4801 /* reset values for 802.3ad */ 4814 4802 if (bond_mode == BOND_MODE_8023AD) { 4815 4803 if (!miimon) { ··· 5018 4992 params->xmit_policy = xmit_hashtype; 5019 4993 params->miimon = miimon; 5020 4994 params->num_grat_arp = num_grat_arp; 4995 + params->num_unsol_na = num_unsol_na; 5021 4996 params->arp_interval = arp_interval; 5022 4997 params->arp_validate = arp_validate_value; 5023 4998 params->updelay = updelay; ··· 5171 5144 5172 5145 register_netdevice_notifier(&bond_netdev_notifier); 5173 5146 register_inetaddr_notifier(&bond_inetaddr_notifier); 5147 + bond_register_ipv6_notifier(); 5174 5148 5175 5149 goto out; 5176 5150 err: ··· 5194 5166 { 5195 5167 unregister_netdevice_notifier(&bond_netdev_notifier); 5196 5168 unregister_inetaddr_notifier(&bond_inetaddr_notifier); 5169 + bond_unregister_ipv6_notifier(); 5197 5170 5198 5171 bond_destroy_sysfs(); 5199 5172
+42
drivers/net/bonding/bond_sysfs.c
··· 983 983 return ret; 984 984 } 985 985 static DEVICE_ATTR(num_grat_arp, S_IRUGO | S_IWUSR, bonding_show_n_grat_arp, bonding_store_n_grat_arp); 986 + 987 + /* 988 + * Show and set the number of unsolicted NA's to send after a failover event. 989 + */ 990 + static ssize_t bonding_show_n_unsol_na(struct device *d, 991 + struct device_attribute *attr, 992 + char *buf) 993 + { 994 + struct bonding *bond = to_bond(d); 995 + 996 + return sprintf(buf, "%d\n", bond->params.num_unsol_na); 997 + } 998 + 999 + static ssize_t bonding_store_n_unsol_na(struct device *d, 1000 + struct device_attribute *attr, 1001 + const char *buf, size_t count) 1002 + { 1003 + int new_value, ret = count; 1004 + struct bonding *bond = to_bond(d); 1005 + 1006 + if (sscanf(buf, "%d", &new_value) != 1) { 1007 + printk(KERN_ERR DRV_NAME 1008 + ": %s: no num_unsol_na value specified.\n", 1009 + bond->dev->name); 1010 + ret = -EINVAL; 1011 + goto out; 1012 + } 1013 + if (new_value < 0 || new_value > 255) { 1014 + printk(KERN_ERR DRV_NAME 1015 + ": %s: Invalid num_unsol_na value %d not in range 0-255; rejected.\n", 1016 + bond->dev->name, new_value); 1017 + ret = -EINVAL; 1018 + goto out; 1019 + } else { 1020 + bond->params.num_unsol_na = new_value; 1021 + } 1022 + out: 1023 + return ret; 1024 + } 1025 + static DEVICE_ATTR(num_unsol_na, S_IRUGO | S_IWUSR, bonding_show_n_unsol_na, bonding_store_n_unsol_na); 1026 + 986 1027 /* 987 1028 * Show and set the MII monitor interval. There are two tricky bits 988 1029 * here. First, if MII monitoring is activated, then we must disable ··· 1461 1420 &dev_attr_lacp_rate.attr, 1462 1421 &dev_attr_xmit_hash_policy.attr, 1463 1422 &dev_attr_num_grat_arp.attr, 1423 + &dev_attr_num_unsol_na.attr, 1464 1424 &dev_attr_miimon.attr, 1465 1425 &dev_attr_primary.attr, 1466 1426 &dev_attr_use_carrier.attr,
+32 -2
drivers/net/bonding/bonding.h
··· 19 19 #include <linux/proc_fs.h> 20 20 #include <linux/if_bonding.h> 21 21 #include <linux/kobject.h> 22 + #include <linux/in6.h> 22 23 #include "bond_3ad.h" 23 24 #include "bond_alb.h" 24 25 25 - #define DRV_VERSION "3.3.0" 26 - #define DRV_RELDATE "June 10, 2008" 26 + #define DRV_VERSION "3.4.0" 27 + #define DRV_RELDATE "October 7, 2008" 27 28 #define DRV_NAME "bonding" 28 29 #define DRV_DESCRIPTION "Ethernet Channel Bonding Driver" 29 30 30 31 #define BOND_MAX_ARP_TARGETS 16 32 + 33 + extern struct list_head bond_dev_list; 31 34 32 35 #ifdef BONDING_DEBUG 33 36 #define dprintk(fmt, args...) \ ··· 129 126 int xmit_policy; 130 127 int miimon; 131 128 int num_grat_arp; 129 + int num_unsol_na; 132 130 int arp_interval; 133 131 int arp_validate; 134 132 int use_carrier; ··· 152 148 struct list_head vlan_list; 153 149 __be32 vlan_ip; 154 150 unsigned short vlan_id; 151 + #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 152 + struct in6_addr vlan_ipv6; 153 + #endif 155 154 }; 156 155 157 156 struct slave { ··· 202 195 rwlock_t curr_slave_lock; 203 196 s8 kill_timers; 204 197 s8 send_grat_arp; 198 + s8 send_unsol_na; 205 199 s8 setup_by_slave; 206 200 struct net_device_stats stats; 207 201 #ifdef CONFIG_PROC_FS ··· 226 218 struct delayed_work arp_work; 227 219 struct delayed_work alb_work; 228 220 struct delayed_work ad_work; 221 + #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 222 + struct in6_addr master_ipv6; 223 + #endif 229 224 }; 230 225 231 226 /** ··· 351 340 extern struct bond_parm_tbl xmit_hashtype_tbl[]; 352 341 extern struct bond_parm_tbl arp_validate_tbl[]; 353 342 extern struct bond_parm_tbl fail_over_mac_tbl[]; 343 + 344 + #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 345 + void bond_send_unsolicited_na(struct bonding *bond); 346 + void bond_register_ipv6_notifier(void); 347 + void bond_unregister_ipv6_notifier(void); 348 + #else 349 + static inline void bond_send_unsolicited_na(struct bonding *bond) 350 + { 351 + return; 352 + } 353 + static inline void bond_register_ipv6_notifier(void) 354 + { 355 + return; 356 + } 357 + static inline void bond_unregister_ipv6_notifier(void) 358 + { 359 + return; 360 + } 361 + #endif 354 362 355 363 #endif /* _LINUX_BONDING_H */ 356 364
+14
include/net/ndisc.h
··· 108 108 109 109 extern int ndisc_mc_map(struct in6_addr *addr, char *buf, struct net_device *dev, int dir); 110 110 111 + extern struct sk_buff *ndisc_build_skb(struct net_device *dev, 112 + const struct in6_addr *daddr, 113 + const struct in6_addr *saddr, 114 + struct icmp6hdr *icmp6h, 115 + const struct in6_addr *target, 116 + int llinfo); 117 + 118 + extern void ndisc_send_skb(struct sk_buff *skb, 119 + struct net_device *dev, 120 + struct neighbour *neigh, 121 + const struct in6_addr *daddr, 122 + const struct in6_addr *saddr, 123 + struct icmp6hdr *icmp6h); 124 + 111 125 112 126 113 127 /*
+65 -27
net/ipv6/ndisc.c
··· 437 437 ipv6_dev_mc_dec(dev, &maddr); 438 438 } 439 439 440 - /* 441 - * Send a Neighbour Advertisement 442 - */ 443 - static void __ndisc_send(struct net_device *dev, 444 - struct neighbour *neigh, 445 - const struct in6_addr *daddr, 446 - const struct in6_addr *saddr, 447 - struct icmp6hdr *icmp6h, const struct in6_addr *target, 448 - int llinfo) 440 + struct sk_buff *ndisc_build_skb(struct net_device *dev, 441 + const struct in6_addr *daddr, 442 + const struct in6_addr *saddr, 443 + struct icmp6hdr *icmp6h, 444 + const struct in6_addr *target, 445 + int llinfo) 449 446 { 450 - struct flowi fl; 451 - struct dst_entry *dst; 452 447 struct net *net = dev_net(dev); 453 448 struct sock *sk = net->ipv6.ndisc_sk; 454 449 struct sk_buff *skb; 455 450 struct icmp6hdr *hdr; 456 - struct inet6_dev *idev; 457 451 int len; 458 452 int err; 459 - u8 *opt, type; 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; 453 + u8 *opt; 472 454 473 455 if (!dev->addr_len) 474 456 llinfo = 0; ··· 467 485 ND_PRINTK0(KERN_ERR 468 486 "ICMPv6 ND: %s() failed to allocate an skb.\n", 469 487 __func__); 470 - dst_release(dst); 471 - return; 488 + return NULL; 472 489 } 473 490 474 491 skb_reserve(skb, LL_RESERVED_SPACE(dev)); ··· 494 513 csum_partial((__u8 *) hdr, 495 514 len, 0)); 496 515 516 + return skb; 517 + } 518 + 519 + EXPORT_SYMBOL(ndisc_build_skb); 520 + 521 + void ndisc_send_skb(struct sk_buff *skb, 522 + struct net_device *dev, 523 + struct neighbour *neigh, 524 + const struct in6_addr *daddr, 525 + const struct in6_addr *saddr, 526 + struct icmp6hdr *icmp6h) 527 + { 528 + struct flowi fl; 529 + struct dst_entry *dst; 530 + struct net *net = dev_net(dev); 531 + struct sock *sk = net->ipv6.ndisc_sk; 532 + struct inet6_dev *idev; 533 + int err; 534 + u8 type; 535 + 536 + type = icmp6h->icmp6_type; 537 + 538 + icmpv6_flow_init(sk, &fl, type, saddr, daddr, dev->ifindex); 539 + 540 + dst = icmp6_dst_alloc(dev, neigh, daddr); 541 + if (!dst) { 542 + kfree_skb(skb); 543 + return; 544 + } 545 + 546 + err = xfrm_lookup(&dst, &fl, NULL, 0); 547 + if (err < 0) { 548 + kfree_skb(skb); 549 + return; 550 + } 551 + 497 552 skb->dst = dst; 498 553 499 554 idev = in6_dev_get(dst->dev); ··· 544 527 545 528 if (likely(idev != NULL)) 546 529 in6_dev_put(idev); 530 + } 531 + 532 + EXPORT_SYMBOL(ndisc_send_skb); 533 + 534 + /* 535 + * Send a Neighbour Discover packet 536 + */ 537 + static void __ndisc_send(struct net_device *dev, 538 + struct neighbour *neigh, 539 + const struct in6_addr *daddr, 540 + const struct in6_addr *saddr, 541 + struct icmp6hdr *icmp6h, const struct in6_addr *target, 542 + int llinfo) 543 + { 544 + struct sk_buff *skb; 545 + 546 + skb = ndisc_build_skb(dev, daddr, saddr, icmp6h, target, llinfo); 547 + if (!skb) 548 + return; 549 + 550 + ndisc_send_skb(skb, dev, neigh, daddr, saddr, icmp6h); 547 551 } 548 552 549 553 static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,