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

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.30-rc3 216 lines 5.4 kB view raw
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#include <linux/types.h> 24#include <linux/if_vlan.h> 25#include <net/ipv6.h> 26#include <net/ndisc.h> 27#include <net/addrconf.h> 28#include "bonding.h" 29 30/* 31 * Assign bond->master_ipv6 to the next IPv6 address in the list, or 32 * zero it out if there are none. 33 */ 34static void bond_glean_dev_ipv6(struct net_device *dev, struct in6_addr *addr) 35{ 36 struct inet6_dev *idev; 37 struct inet6_ifaddr *ifa; 38 39 if (!dev) 40 return; 41 42 idev = in6_dev_get(dev); 43 if (!idev) 44 return; 45 46 read_lock_bh(&idev->lock); 47 ifa = idev->addr_list; 48 if (ifa) 49 ipv6_addr_copy(addr, &ifa->addr); 50 else 51 ipv6_addr_set(addr, 0, 0, 0, 0); 52 53 read_unlock_bh(&idev->lock); 54 55 in6_dev_put(idev); 56} 57 58static void bond_na_send(struct net_device *slave_dev, 59 struct in6_addr *daddr, 60 int router, 61 unsigned short vlan_id) 62{ 63 struct in6_addr mcaddr; 64 struct icmp6hdr icmp6h = { 65 .icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT, 66 }; 67 struct sk_buff *skb; 68 69 icmp6h.icmp6_router = router; 70 icmp6h.icmp6_solicited = 0; 71 icmp6h.icmp6_override = 1; 72 73 addrconf_addr_solict_mult(daddr, &mcaddr); 74 75 pr_debug("ipv6 na on slave %s: dest %pI6, src %pI6\n", 76 slave_dev->name, &mcaddr, daddr); 77 78 skb = ndisc_build_skb(slave_dev, &mcaddr, daddr, &icmp6h, daddr, 79 ND_OPT_TARGET_LL_ADDR); 80 81 if (!skb) { 82 printk(KERN_ERR DRV_NAME ": NA packet allocation failed\n"); 83 return; 84 } 85 86 if (vlan_id) { 87 skb = vlan_put_tag(skb, vlan_id); 88 if (!skb) { 89 printk(KERN_ERR DRV_NAME ": failed to insert VLAN tag\n"); 90 return; 91 } 92 } 93 94 ndisc_send_skb(skb, slave_dev, NULL, &mcaddr, daddr, &icmp6h); 95} 96 97/* 98 * Kick out an unsolicited Neighbor Advertisement for an IPv6 address on 99 * the bonding master. This will help the switch learn our address 100 * if in active-backup mode. 101 * 102 * Caller must hold curr_slave_lock for read or better 103 */ 104void bond_send_unsolicited_na(struct bonding *bond) 105{ 106 struct slave *slave = bond->curr_active_slave; 107 struct vlan_entry *vlan; 108 struct inet6_dev *idev; 109 int is_router; 110 111 pr_debug("bond_send_unsol_na: bond %s slave %s\n", bond->dev->name, 112 slave ? slave->dev->name : "NULL"); 113 114 if (!slave || !bond->send_unsol_na || 115 test_bit(__LINK_STATE_LINKWATCH_PENDING, &slave->dev->state)) 116 return; 117 118 bond->send_unsol_na--; 119 120 idev = in6_dev_get(bond->dev); 121 if (!idev) 122 return; 123 124 is_router = !!idev->cnf.forwarding; 125 126 in6_dev_put(idev); 127 128 if (!ipv6_addr_any(&bond->master_ipv6)) 129 bond_na_send(slave->dev, &bond->master_ipv6, is_router, 0); 130 131 list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { 132 if (!ipv6_addr_any(&vlan->vlan_ipv6)) { 133 bond_na_send(slave->dev, &vlan->vlan_ipv6, is_router, 134 vlan->vlan_id); 135 } 136 } 137} 138 139/* 140 * bond_inet6addr_event: handle inet6addr notifier chain events. 141 * 142 * We keep track of device IPv6 addresses primarily to use as source 143 * addresses in NS probes. 144 * 145 * We track one IPv6 for the main device (if it has one). 146 */ 147static int bond_inet6addr_event(struct notifier_block *this, 148 unsigned long event, 149 void *ptr) 150{ 151 struct inet6_ifaddr *ifa = ptr; 152 struct net_device *vlan_dev, *event_dev = ifa->idev->dev; 153 struct bonding *bond; 154 struct vlan_entry *vlan; 155 156 if (dev_net(event_dev) != &init_net) 157 return NOTIFY_DONE; 158 159 list_for_each_entry(bond, &bond_dev_list, bond_list) { 160 if (bond->dev == event_dev) { 161 switch (event) { 162 case NETDEV_UP: 163 if (ipv6_addr_any(&bond->master_ipv6)) 164 ipv6_addr_copy(&bond->master_ipv6, 165 &ifa->addr); 166 return NOTIFY_OK; 167 case NETDEV_DOWN: 168 if (ipv6_addr_equal(&bond->master_ipv6, 169 &ifa->addr)) 170 bond_glean_dev_ipv6(bond->dev, 171 &bond->master_ipv6); 172 return NOTIFY_OK; 173 default: 174 return NOTIFY_DONE; 175 } 176 } 177 178 list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { 179 vlan_dev = vlan_group_get_device(bond->vlgrp, 180 vlan->vlan_id); 181 if (vlan_dev == event_dev) { 182 switch (event) { 183 case NETDEV_UP: 184 if (ipv6_addr_any(&vlan->vlan_ipv6)) 185 ipv6_addr_copy(&vlan->vlan_ipv6, 186 &ifa->addr); 187 return NOTIFY_OK; 188 case NETDEV_DOWN: 189 if (ipv6_addr_equal(&vlan->vlan_ipv6, 190 &ifa->addr)) 191 bond_glean_dev_ipv6(vlan_dev, 192 &vlan->vlan_ipv6); 193 return NOTIFY_OK; 194 default: 195 return NOTIFY_DONE; 196 } 197 } 198 } 199 } 200 return NOTIFY_DONE; 201} 202 203static struct notifier_block bond_inet6addr_notifier = { 204 .notifier_call = bond_inet6addr_event, 205}; 206 207void bond_register_ipv6_notifier(void) 208{ 209 register_inet6addr_notifier(&bond_inet6addr_notifier); 210} 211 212void bond_unregister_ipv6_notifier(void) 213{ 214 unregister_inet6addr_notifier(&bond_inet6addr_notifier); 215} 216