diff options
-rw-r--r-- | drivers/net/bonding/Makefile | 2 | ||||
-rw-r--r-- | drivers/net/bonding/bond_main.c | 23 | ||||
-rw-r--r-- | drivers/net/bonding/bond_sysfs.c | 1399 | ||||
-rw-r--r-- | drivers/net/bonding/bonding.h | 7 |
4 files changed, 1429 insertions, 2 deletions
diff --git a/drivers/net/bonding/Makefile b/drivers/net/bonding/Makefile index cf50384b469e..5cdae2bc055a 100644 --- a/drivers/net/bonding/Makefile +++ b/drivers/net/bonding/Makefile | |||
@@ -4,5 +4,5 @@ | |||
4 | 4 | ||
5 | obj-$(CONFIG_BONDING) += bonding.o | 5 | obj-$(CONFIG_BONDING) += bonding.o |
6 | 6 | ||
7 | bonding-objs := bond_main.o bond_3ad.o bond_alb.o | 7 | bonding-objs := bond_main.o bond_3ad.o bond_alb.o bond_sysfs.o |
8 | 8 | ||
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index d5415ba9bdb0..5ac9718c5988 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c | |||
@@ -600,6 +600,7 @@ LIST_HEAD(bond_dev_list); | |||
600 | static struct proc_dir_entry *bond_proc_dir = NULL; | 600 | static struct proc_dir_entry *bond_proc_dir = NULL; |
601 | #endif | 601 | #endif |
602 | 602 | ||
603 | extern struct rw_semaphore bonding_rwsem; | ||
603 | static u32 arp_target[BOND_MAX_ARP_TARGETS] = { 0, } ; | 604 | static u32 arp_target[BOND_MAX_ARP_TARGETS] = { 0, } ; |
604 | static int arp_ip_count = 0; | 605 | static int arp_ip_count = 0; |
605 | static int bond_mode = BOND_MODE_ROUNDROBIN; | 606 | static int bond_mode = BOND_MODE_ROUNDROBIN; |
@@ -1960,6 +1961,10 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) | |||
1960 | 1961 | ||
1961 | write_unlock_bh(&bond->lock); | 1962 | write_unlock_bh(&bond->lock); |
1962 | 1963 | ||
1964 | res = bond_create_slave_symlinks(bond_dev, slave_dev); | ||
1965 | if (res) | ||
1966 | goto err_unset_master; | ||
1967 | |||
1963 | printk(KERN_INFO DRV_NAME | 1968 | printk(KERN_INFO DRV_NAME |
1964 | ": %s: enslaving %s as a%s interface with a%s link.\n", | 1969 | ": %s: enslaving %s as a%s interface with a%s link.\n", |
1965 | bond_dev->name, slave_dev->name, | 1970 | bond_dev->name, slave_dev->name, |
@@ -2133,6 +2138,9 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) | |||
2133 | 2138 | ||
2134 | write_unlock_bh(&bond->lock); | 2139 | write_unlock_bh(&bond->lock); |
2135 | 2140 | ||
2141 | /* must do this from outside any spinlocks */ | ||
2142 | bond_destroy_slave_symlinks(bond_dev, slave_dev); | ||
2143 | |||
2136 | bond_del_vlans_from_slave(bond, slave_dev); | 2144 | bond_del_vlans_from_slave(bond, slave_dev); |
2137 | 2145 | ||
2138 | /* If the mode USES_PRIMARY, then we should only remove its | 2146 | /* If the mode USES_PRIMARY, then we should only remove its |
@@ -2224,6 +2232,7 @@ static int bond_release_all(struct net_device *bond_dev) | |||
2224 | */ | 2232 | */ |
2225 | write_unlock_bh(&bond->lock); | 2233 | write_unlock_bh(&bond->lock); |
2226 | 2234 | ||
2235 | bond_destroy_slave_symlinks(bond_dev, slave_dev); | ||
2227 | bond_del_vlans_from_slave(bond, slave_dev); | 2236 | bond_del_vlans_from_slave(bond, slave_dev); |
2228 | 2237 | ||
2229 | /* If the mode USES_PRIMARY, then we should only remove its | 2238 | /* If the mode USES_PRIMARY, then we should only remove its |
@@ -3518,7 +3527,10 @@ static int bond_event_changename(struct bonding *bond) | |||
3518 | bond_remove_proc_entry(bond); | 3527 | bond_remove_proc_entry(bond); |
3519 | bond_create_proc_entry(bond); | 3528 | bond_create_proc_entry(bond); |
3520 | #endif | 3529 | #endif |
3521 | 3530 | down_write(&(bonding_rwsem)); | |
3531 | bond_destroy_sysfs_entry(bond); | ||
3532 | bond_create_sysfs_entry(bond); | ||
3533 | up_write(&(bonding_rwsem)); | ||
3522 | return NOTIFY_DONE; | 3534 | return NOTIFY_DONE; |
3523 | } | 3535 | } |
3524 | 3536 | ||
@@ -3995,6 +4007,7 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd | |||
3995 | return -EPERM; | 4007 | return -EPERM; |
3996 | } | 4008 | } |
3997 | 4009 | ||
4010 | down_write(&(bonding_rwsem)); | ||
3998 | slave_dev = dev_get_by_name(ifr->ifr_slave); | 4011 | slave_dev = dev_get_by_name(ifr->ifr_slave); |
3999 | 4012 | ||
4000 | dprintk("slave_dev=%p: \n", slave_dev); | 4013 | dprintk("slave_dev=%p: \n", slave_dev); |
@@ -4027,6 +4040,7 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd | |||
4027 | dev_put(slave_dev); | 4040 | dev_put(slave_dev); |
4028 | } | 4041 | } |
4029 | 4042 | ||
4043 | up_write(&(bonding_rwsem)); | ||
4030 | return res; | 4044 | return res; |
4031 | } | 4045 | } |
4032 | 4046 | ||
@@ -4962,6 +4976,7 @@ int bond_create(char *name, struct bond_params *params, struct bonding **newbond | |||
4962 | *newbond = bond_dev->priv; | 4976 | *newbond = bond_dev->priv; |
4963 | 4977 | ||
4964 | rtnl_unlock(); /* allows sysfs registration of net device */ | 4978 | rtnl_unlock(); /* allows sysfs registration of net device */ |
4979 | res = bond_create_sysfs_entry(bond_dev->priv); | ||
4965 | goto done; | 4980 | goto done; |
4966 | out_bond: | 4981 | out_bond: |
4967 | bond_deinit(bond_dev); | 4982 | bond_deinit(bond_dev); |
@@ -4996,6 +5011,10 @@ static int __init bonding_init(void) | |||
4996 | goto err; | 5011 | goto err; |
4997 | } | 5012 | } |
4998 | 5013 | ||
5014 | res = bond_create_sysfs(); | ||
5015 | if (res) | ||
5016 | goto err; | ||
5017 | |||
4999 | register_netdevice_notifier(&bond_netdev_notifier); | 5018 | register_netdevice_notifier(&bond_netdev_notifier); |
5000 | register_inetaddr_notifier(&bond_inetaddr_notifier); | 5019 | register_inetaddr_notifier(&bond_inetaddr_notifier); |
5001 | 5020 | ||
@@ -5003,6 +5022,7 @@ static int __init bonding_init(void) | |||
5003 | err: | 5022 | err: |
5004 | rtnl_lock(); | 5023 | rtnl_lock(); |
5005 | bond_free_all(); | 5024 | bond_free_all(); |
5025 | bond_destroy_sysfs(); | ||
5006 | rtnl_unlock(); | 5026 | rtnl_unlock(); |
5007 | out: | 5027 | out: |
5008 | return res; | 5028 | return res; |
@@ -5016,6 +5036,7 @@ static void __exit bonding_exit(void) | |||
5016 | 5036 | ||
5017 | rtnl_lock(); | 5037 | rtnl_lock(); |
5018 | bond_free_all(); | 5038 | bond_free_all(); |
5039 | bond_destroy_sysfs(); | ||
5019 | rtnl_unlock(); | 5040 | rtnl_unlock(); |
5020 | } | 5041 | } |
5021 | 5042 | ||
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c new file mode 100644 index 000000000000..c5f1c52863cb --- /dev/null +++ b/drivers/net/bonding/bond_sysfs.c | |||
@@ -0,0 +1,1399 @@ | |||
1 | |||
2 | /* | ||
3 | * Copyright(c) 2004-2005 Intel Corporation. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License as published by the | ||
7 | * Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
12 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
13 | * for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License along | ||
16 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
17 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
18 | * | ||
19 | * The full GNU General Public License is included in this distribution in the | ||
20 | * file called LICENSE. | ||
21 | * | ||
22 | * | ||
23 | * Changes: | ||
24 | * | ||
25 | * 2004/12/12 - Mitch Williams <mitch.a.williams at intel dot com> | ||
26 | * - Initial creation of sysfs interface. | ||
27 | * | ||
28 | * 2005/06/22 - Radheka Godse <radheka.godse at intel dot com> | ||
29 | * - Added ifenslave -c type functionality to sysfs | ||
30 | * - Added sysfs files for attributes such as MII Status and | ||
31 | * 802.3ad aggregator that are displayed in /proc | ||
32 | * - Added "name value" format to sysfs "mode" and | ||
33 | * "lacp_rate", for e.g., "active-backup 1" or "slow 0" for | ||
34 | * consistency and ease of script parsing | ||
35 | * - Fixed reversal of octets in arp_ip_targets via sysfs | ||
36 | * - sysfs support to handle bond interface re-naming | ||
37 | * - Moved all sysfs entries into /sys/class/net instead of | ||
38 | * of using a standalone subsystem. | ||
39 | * - Added sysfs symlinks between masters and slaves | ||
40 | * - Corrected bugs in sysfs unload path when creating bonds | ||
41 | * with existing interface names. | ||
42 | * - Removed redundant sysfs stat file since it duplicates slave info | ||
43 | * from the proc file | ||
44 | * - Fixed errors in sysfs show/store arp targets. | ||
45 | * - For consistency with ifenslave, instead of exiting | ||
46 | * with an error, updated bonding sysfs to | ||
47 | * close and attempt to enslave an up adapter. | ||
48 | * - Fixed NULL dereference when adding a slave interface | ||
49 | * that does not exist. | ||
50 | * - Added checks in sysfs bonding to reject invalid ip addresses | ||
51 | * - Synch up with post linux-2.6.12 bonding changes | ||
52 | * - Created sysfs bond attrib for xmit_hash_policy | ||
53 | * | ||
54 | * 2005/09/19 - Mitch Williams <mitch.a.williams at intel dot com> | ||
55 | * - Changed semantics of multi-item files to be command-based | ||
56 | * instead of list-based. | ||
57 | * - Changed ARP target handler to use in_aton instead of sscanf | ||
58 | * - Style changes. | ||
59 | * 2005/09/27 - Mitch Williams <mitch.a.williams at intel dot com> | ||
60 | * - Made line endings consistent. | ||
61 | * - Removed "none" from primary output - just put blank instead | ||
62 | * - Fixed bug with long interface names | ||
63 | */ | ||
64 | #include <linux/config.h> | ||
65 | #include <linux/kernel.h> | ||
66 | #include <linux/module.h> | ||
67 | #include <linux/sched.h> | ||
68 | #include <linux/device.h> | ||
69 | #include <linux/sysdev.h> | ||
70 | #include <linux/fs.h> | ||
71 | #include <linux/types.h> | ||
72 | #include <linux/string.h> | ||
73 | #include <linux/netdevice.h> | ||
74 | #include <linux/inetdevice.h> | ||
75 | #include <linux/in.h> | ||
76 | #include <linux/sysfs.h> | ||
77 | #include <linux/string.h> | ||
78 | #include <linux/ctype.h> | ||
79 | #include <linux/inet.h> | ||
80 | #include <linux/rtnetlink.h> | ||
81 | |||
82 | /* #define BONDING_DEBUG 1 */ | ||
83 | #include "bonding.h" | ||
84 | #define to_class_dev(obj) container_of(obj,struct class_device,kobj) | ||
85 | #define to_net_dev(class) container_of(class, struct net_device, class_dev) | ||
86 | #define to_bond(cd) ((struct bonding *)(to_net_dev(cd)->priv)) | ||
87 | |||
88 | /*---------------------------- Declarations -------------------------------*/ | ||
89 | |||
90 | |||
91 | extern struct list_head bond_dev_list; | ||
92 | extern struct bond_params bonding_defaults; | ||
93 | extern struct bond_parm_tbl bond_mode_tbl[]; | ||
94 | extern struct bond_parm_tbl bond_lacp_tbl[]; | ||
95 | extern struct bond_parm_tbl xmit_hashtype_tbl[]; | ||
96 | |||
97 | static int expected_refcount = -1; | ||
98 | static struct class *netdev_class; | ||
99 | /*--------------------------- Data Structures -----------------------------*/ | ||
100 | |||
101 | /* Bonding sysfs lock. Why can't we just use the subsytem lock? | ||
102 | * Because kobject_register tries to acquire the subsystem lock. If | ||
103 | * we already hold the lock (which we would if the user was creating | ||
104 | * a new bond through the sysfs interface), we deadlock. | ||
105 | * This lock is only needed when deleting a bond - we need to make sure | ||
106 | * that we don't collide with an ongoing ioctl. | ||
107 | */ | ||
108 | |||
109 | struct rw_semaphore bonding_rwsem; | ||
110 | |||
111 | |||
112 | |||
113 | |||
114 | /*------------------------------ Functions --------------------------------*/ | ||
115 | |||
116 | /* | ||
117 | * "show" function for the bond_masters attribute. | ||
118 | * The class parameter is ignored. | ||
119 | */ | ||
120 | static ssize_t bonding_show_bonds(struct class *cls, char *buffer) | ||
121 | { | ||
122 | int res = 0; | ||
123 | struct bonding *bond; | ||
124 | |||
125 | down_read(&(bonding_rwsem)); | ||
126 | |||
127 | list_for_each_entry(bond, &bond_dev_list, bond_list) { | ||
128 | if (res > (PAGE_SIZE - IFNAMSIZ)) { | ||
129 | /* not enough space for another interface name */ | ||
130 | if ((PAGE_SIZE - res) > 10) | ||
131 | res = PAGE_SIZE - 10; | ||
132 | res += sprintf(buffer + res, "++more++"); | ||
133 | break; | ||
134 | } | ||
135 | res += sprintf(buffer + res, "%s ", | ||
136 | bond->dev->name); | ||
137 | } | ||
138 | res += sprintf(buffer + res, "\n"); | ||
139 | res++; | ||
140 | up_read(&(bonding_rwsem)); | ||
141 | return res; | ||
142 | } | ||
143 | |||
144 | /* | ||
145 | * "store" function for the bond_masters attribute. This is what | ||
146 | * creates and deletes entire bonds. | ||
147 | * | ||
148 | * The class parameter is ignored. | ||
149 | * | ||
150 | */ | ||
151 | |||
152 | static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t count) | ||
153 | { | ||
154 | char command[IFNAMSIZ + 1] = {0, }; | ||
155 | char *ifname; | ||
156 | int res = count; | ||
157 | struct bonding *bond; | ||
158 | struct bonding *nxt; | ||
159 | |||
160 | down_write(&(bonding_rwsem)); | ||
161 | sscanf(buffer, "%16s", command); /* IFNAMSIZ*/ | ||
162 | ifname = command + 1; | ||
163 | if ((strlen(command) <= 1) || | ||
164 | !dev_valid_name(ifname)) | ||
165 | goto err_no_cmd; | ||
166 | |||
167 | if (command[0] == '+') { | ||
168 | |||
169 | /* Check to see if the bond already exists. */ | ||
170 | list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) | ||
171 | if (strnicmp(bond->dev->name, ifname, IFNAMSIZ) == 0) { | ||
172 | printk(KERN_ERR DRV_NAME | ||
173 | ": cannot add bond %s; it already exists\n", | ||
174 | ifname); | ||
175 | res = -EPERM; | ||
176 | goto out; | ||
177 | } | ||
178 | |||
179 | printk(KERN_INFO DRV_NAME | ||
180 | ": %s is being created...\n", ifname); | ||
181 | if (bond_create(ifname, &bonding_defaults, &bond)) { | ||
182 | printk(KERN_INFO DRV_NAME | ||
183 | ": %s interface already exists. Bond creation failed.\n", | ||
184 | ifname); | ||
185 | res = -EPERM; | ||
186 | } | ||
187 | goto out; | ||
188 | } | ||
189 | |||
190 | if (command[0] == '-') { | ||
191 | list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) | ||
192 | if (strnicmp(bond->dev->name, ifname, IFNAMSIZ) == 0) { | ||
193 | rtnl_lock(); | ||
194 | /* check the ref count on the bond's kobject. | ||
195 | * If it's > expected, then there's a file open, | ||
196 | * and we have to fail. | ||
197 | */ | ||
198 | if (atomic_read(&bond->dev->class_dev.kobj.kref.refcount) | ||
199 | > expected_refcount){ | ||
200 | rtnl_unlock(); | ||
201 | printk(KERN_INFO DRV_NAME | ||
202 | ": Unable remove bond %s due to open references.\n", | ||
203 | ifname); | ||
204 | res = -EPERM; | ||
205 | goto out; | ||
206 | } | ||
207 | printk(KERN_INFO DRV_NAME | ||
208 | ": %s is being deleted...\n", | ||
209 | bond->dev->name); | ||
210 | unregister_netdevice(bond->dev); | ||
211 | bond_deinit(bond->dev); | ||
212 | bond_destroy_sysfs_entry(bond); | ||
213 | rtnl_unlock(); | ||
214 | goto out; | ||
215 | } | ||
216 | |||
217 | printk(KERN_ERR DRV_NAME | ||
218 | ": unable to delete non-existent bond %s\n", ifname); | ||
219 | res = -ENODEV; | ||
220 | goto out; | ||
221 | } | ||
222 | |||
223 | err_no_cmd: | ||
224 | printk(KERN_ERR DRV_NAME | ||
225 | ": no command found in bonding_masters. Use +ifname or -ifname.\n"); | ||
226 | res = -EPERM; | ||
227 | |||
228 | /* Always return either count or an error. If you return 0, you'll | ||
229 | * get called forever, which is bad. | ||
230 | */ | ||
231 | out: | ||
232 | up_write(&(bonding_rwsem)); | ||
233 | return res; | ||
234 | } | ||
235 | /* class attribute for bond_masters file. This ends up in /sys/class/net */ | ||
236 | static CLASS_ATTR(bonding_masters, S_IWUSR | S_IRUGO, | ||
237 | bonding_show_bonds, bonding_store_bonds); | ||
238 | |||
239 | int bond_create_slave_symlinks(struct net_device *master, struct net_device *slave) | ||
240 | { | ||
241 | char linkname[IFNAMSIZ+7]; | ||
242 | int ret = 0; | ||
243 | |||
244 | /* first, create a link from the slave back to the master */ | ||
245 | ret = sysfs_create_link(&(slave->class_dev.kobj), &(master->class_dev.kobj), | ||
246 | "master"); | ||
247 | if (ret) | ||
248 | return ret; | ||
249 | /* next, create a link from the master to the slave */ | ||
250 | sprintf(linkname,"slave_%s",slave->name); | ||
251 | ret = sysfs_create_link(&(master->class_dev.kobj), &(slave->class_dev.kobj), | ||
252 | linkname); | ||
253 | return ret; | ||
254 | |||
255 | } | ||
256 | |||
257 | void bond_destroy_slave_symlinks(struct net_device *master, struct net_device *slave) | ||
258 | { | ||
259 | char linkname[IFNAMSIZ+7]; | ||
260 | |||
261 | sysfs_remove_link(&(slave->class_dev.kobj), "master"); | ||
262 | sprintf(linkname,"slave_%s",slave->name); | ||
263 | sysfs_remove_link(&(master->class_dev.kobj), linkname); | ||
264 | } | ||
265 | |||
266 | |||
267 | /* | ||
268 | * Show the slaves in the current bond. | ||
269 | */ | ||
270 | static ssize_t bonding_show_slaves(struct class_device *cd, char *buf) | ||
271 | { | ||
272 | struct slave *slave; | ||
273 | int i, res = 0; | ||
274 | struct bonding *bond = to_bond(cd); | ||
275 | |||
276 | read_lock_bh(&bond->lock); | ||
277 | bond_for_each_slave(bond, slave, i) { | ||
278 | if (res > (PAGE_SIZE - IFNAMSIZ)) { | ||
279 | /* not enough space for another interface name */ | ||
280 | if ((PAGE_SIZE - res) > 10) | ||
281 | res = PAGE_SIZE - 10; | ||
282 | res += sprintf(buf + res, "++more++"); | ||
283 | break; | ||
284 | } | ||
285 | res += sprintf(buf + res, "%s ", slave->dev->name); | ||
286 | } | ||
287 | read_unlock_bh(&bond->lock); | ||
288 | res += sprintf(buf + res, "\n"); | ||
289 | res++; | ||
290 | return res; | ||
291 | } | ||
292 | |||
293 | /* | ||
294 | * Set the slaves in the current bond. The bond interface must be | ||
295 | * up for this to succeed. | ||
296 | * This function is largely the same flow as bonding_update_bonds(). | ||
297 | */ | ||
298 | static ssize_t bonding_store_slaves(struct class_device *cd, const char *buffer, size_t count) | ||
299 | { | ||
300 | char command[IFNAMSIZ + 1] = { 0, }; | ||
301 | char *ifname; | ||
302 | int i, res, found, ret = count; | ||
303 | struct slave *slave; | ||
304 | struct net_device *dev = 0; | ||
305 | struct bonding *bond = to_bond(cd); | ||
306 | |||
307 | /* Quick sanity check -- is the bond interface up? */ | ||
308 | if (!(bond->dev->flags & IFF_UP)) { | ||
309 | printk(KERN_ERR DRV_NAME | ||
310 | ": %s: Unable to update slaves because interface is down.\n", | ||
311 | bond->dev->name); | ||
312 | ret = -EPERM; | ||
313 | goto out; | ||
314 | } | ||
315 | |||
316 | /* Note: We can't hold bond->lock here, as bond_create grabs it. */ | ||
317 | |||
318 | sscanf(buffer, "%16s", command); /* IFNAMSIZ*/ | ||
319 | ifname = command + 1; | ||
320 | if ((strlen(command) <= 1) || | ||
321 | !dev_valid_name(ifname)) | ||
322 | goto err_no_cmd; | ||
323 | |||
324 | if (command[0] == '+') { | ||
325 | |||
326 | /* Got a slave name in ifname. Is it already in the list? */ | ||
327 | found = 0; | ||
328 | read_lock_bh(&bond->lock); | ||
329 | bond_for_each_slave(bond, slave, i) | ||
330 | if (strnicmp(slave->dev->name, ifname, IFNAMSIZ) == 0) { | ||
331 | printk(KERN_ERR DRV_NAME | ||
332 | ": %s: Interface %s is already enslaved!\n", | ||
333 | bond->dev->name, ifname); | ||
334 | ret = -EPERM; | ||
335 | read_unlock_bh(&bond->lock); | ||
336 | goto out; | ||
337 | } | ||
338 | |||
339 | read_unlock_bh(&bond->lock); | ||
340 | printk(KERN_INFO DRV_NAME ": %s: Adding slave %s.\n", | ||
341 | bond->dev->name, ifname); | ||
342 | dev = dev_get_by_name(ifname); | ||
343 | if (!dev) { | ||
344 | printk(KERN_INFO DRV_NAME | ||
345 | ": %s: Interface %s does not exist!\n", | ||
346 | bond->dev->name, ifname); | ||
347 | ret = -EPERM; | ||
348 | goto out; | ||
349 | } | ||
350 | else | ||
351 | dev_put(dev); | ||
352 | |||
353 | if (dev->flags & IFF_UP) { | ||
354 | printk(KERN_ERR DRV_NAME | ||
355 | ": %s: Error: Unable to enslave %s " | ||
356 | "because it is already up.\n", | ||
357 | bond->dev->name, dev->name); | ||
358 | ret = -EPERM; | ||
359 | goto out; | ||
360 | } | ||
361 | /* If this is the first slave, then we need to set | ||
362 | the master's hardware address to be the same as the | ||
363 | slave's. */ | ||
364 | if (!(*((u32 *) & (bond->dev->dev_addr[0])))) { | ||
365 | memcpy(bond->dev->dev_addr, dev->dev_addr, | ||
366 | dev->addr_len); | ||
367 | } | ||
368 | |||
369 | /* Set the slave's MTU to match the bond */ | ||
370 | if (dev->mtu != bond->dev->mtu) { | ||
371 | if (dev->change_mtu) { | ||
372 | res = dev->change_mtu(dev, | ||
373 | bond->dev->mtu); | ||
374 | if (res) { | ||
375 | ret = res; | ||
376 | goto out; | ||
377 | } | ||
378 | } else { | ||
379 | dev->mtu = bond->dev->mtu; | ||
380 | } | ||
381 | } | ||
382 | rtnl_lock(); | ||
383 | res = bond_enslave(bond->dev, dev); | ||
384 | rtnl_unlock(); | ||
385 | if (res) { | ||
386 | ret = res; | ||
387 | } | ||
388 | goto out; | ||
389 | } | ||
390 | |||
391 | if (command[0] == '-') { | ||
392 | dev = NULL; | ||
393 | bond_for_each_slave(bond, slave, i) | ||
394 | if (strnicmp(slave->dev->name, ifname, IFNAMSIZ) == 0) { | ||
395 | dev = slave->dev; | ||
396 | break; | ||
397 | } | ||
398 | if (dev) { | ||
399 | printk(KERN_INFO DRV_NAME ": %s: Removing slave %s\n", | ||
400 | bond->dev->name, dev->name); | ||
401 | rtnl_lock(); | ||
402 | res = bond_release(bond->dev, dev); | ||
403 | rtnl_unlock(); | ||
404 | if (res) { | ||
405 | ret = res; | ||
406 | goto out; | ||
407 | } | ||
408 | /* set the slave MTU to the default */ | ||
409 | if (dev->change_mtu) { | ||
410 | dev->change_mtu(dev, 1500); | ||
411 | } else { | ||
412 | dev->mtu = 1500; | ||
413 | } | ||
414 | } | ||
415 | else { | ||
416 | printk(KERN_ERR DRV_NAME ": unable to remove non-existent slave %s for bond %s.\n", | ||
417 | ifname, bond->dev->name); | ||
418 | ret = -ENODEV; | ||
419 | } | ||
420 | goto out; | ||
421 | } | ||
422 | |||
423 | err_no_cmd: | ||
424 | printk(KERN_ERR DRV_NAME ": no command found in slaves file for bond %s. Use +ifname or -ifname.\n", bond->dev->name); | ||
425 | ret = -EPERM; | ||
426 | |||
427 | out: | ||
428 | return ret; | ||
429 | } | ||
430 | |||
431 | static CLASS_DEVICE_ATTR(slaves, S_IRUGO | S_IWUSR, bonding_show_slaves, bonding_store_slaves); | ||
432 | |||
433 | /* | ||
434 | * Show and set the bonding mode. The bond interface must be down to | ||
435 | * change the mode. | ||
436 | */ | ||
437 | static ssize_t bonding_show_mode(struct class_device *cd, char *buf) | ||
438 | { | ||
439 | struct bonding *bond = to_bond(cd); | ||
440 | |||
441 | return sprintf(buf, "%s %d\n", | ||
442 | bond_mode_tbl[bond->params.mode].modename, | ||
443 | bond->params.mode) + 1; | ||
444 | } | ||
445 | |||
446 | static ssize_t bonding_store_mode(struct class_device *cd, const char *buf, size_t count) | ||
447 | { | ||
448 | int new_value, ret = count; | ||
449 | struct bonding *bond = to_bond(cd); | ||
450 | |||
451 | if (bond->dev->flags & IFF_UP) { | ||
452 | printk(KERN_ERR DRV_NAME | ||
453 | ": unable to update mode of %s because interface is up.\n", | ||
454 | bond->dev->name); | ||
455 | ret = -EPERM; | ||
456 | goto out; | ||
457 | } | ||
458 | |||
459 | new_value = bond_parse_parm((char *)buf, bond_mode_tbl); | ||
460 | if (new_value < 0) { | ||
461 | printk(KERN_ERR DRV_NAME | ||
462 | ": %s: Ignoring invalid mode value %.*s.\n", | ||
463 | bond->dev->name, | ||
464 | (int)strlen(buf) - 1, buf); | ||
465 | ret = -EINVAL; | ||
466 | goto out; | ||
467 | } else { | ||
468 | bond->params.mode = new_value; | ||
469 | bond_set_mode_ops(bond, bond->params.mode); | ||
470 | printk(KERN_INFO DRV_NAME ": %s: setting mode to %s (%d).\n", | ||
471 | bond->dev->name, bond_mode_tbl[new_value].modename, new_value); | ||
472 | } | ||
473 | out: | ||
474 | return ret; | ||
475 | } | ||
476 | static CLASS_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, bonding_show_mode, bonding_store_mode); | ||
477 | |||
478 | /* | ||
479 | * Show and set the bonding transmit hash method. The bond interface must be down to | ||
480 | * change the xmit hash policy. | ||
481 | */ | ||
482 | static ssize_t bonding_show_xmit_hash(struct class_device *cd, char *buf) | ||
483 | { | ||
484 | int count; | ||
485 | struct bonding *bond = to_bond(cd); | ||
486 | |||
487 | if ((bond->params.mode != BOND_MODE_XOR) && | ||
488 | (bond->params.mode != BOND_MODE_8023AD)) { | ||
489 | // Not Applicable | ||
490 | count = sprintf(buf, "NA\n") + 1; | ||
491 | } else { | ||
492 | count = sprintf(buf, "%s %d\n", | ||
493 | xmit_hashtype_tbl[bond->params.xmit_policy].modename, | ||
494 | bond->params.xmit_policy) + 1; | ||
495 | } | ||
496 | |||
497 | return count; | ||
498 | } | ||
499 | |||
500 | static ssize_t bonding_store_xmit_hash(struct class_device *cd, const char *buf, size_t count) | ||
501 | { | ||
502 | int new_value, ret = count; | ||
503 | struct bonding *bond = to_bond(cd); | ||
504 | |||
505 | if (bond->dev->flags & IFF_UP) { | ||
506 | printk(KERN_ERR DRV_NAME | ||
507 | "%s: Interface is up. Unable to update xmit policy.\n", | ||
508 | bond->dev->name); | ||
509 | ret = -EPERM; | ||
510 | goto out; | ||
511 | } | ||
512 | |||
513 | if ((bond->params.mode != BOND_MODE_XOR) && | ||
514 | (bond->params.mode != BOND_MODE_8023AD)) { | ||
515 | printk(KERN_ERR DRV_NAME | ||
516 | "%s: Transmit hash policy is irrelevant in this mode.\n", | ||
517 | bond->dev->name); | ||
518 | ret = -EPERM; | ||
519 | goto out; | ||
520 | } | ||
521 | |||
522 | new_value = bond_parse_parm((char *)buf, xmit_hashtype_tbl); | ||
523 | if (new_value < 0) { | ||
524 | printk(KERN_ERR DRV_NAME | ||
525 | ": %s: Ignoring invalid xmit hash policy value %.*s.\n", | ||
526 | bond->dev->name, | ||
527 | (int)strlen(buf) - 1, buf); | ||
528 | ret = -EINVAL; | ||
529 | goto out; | ||
530 | } else { | ||
531 | bond->params.xmit_policy = new_value; | ||
532 | bond_set_mode_ops(bond, bond->params.mode); | ||
533 | printk(KERN_INFO DRV_NAME ": %s: setting xmit hash policy to %s (%d).\n", | ||
534 | bond->dev->name, xmit_hashtype_tbl[new_value].modename, new_value); | ||
535 | } | ||
536 | out: | ||
537 | return ret; | ||
538 | } | ||
539 | static CLASS_DEVICE_ATTR(xmit_hash_policy, S_IRUGO | S_IWUSR, bonding_show_xmit_hash, bonding_store_xmit_hash); | ||
540 | |||
541 | /* | ||
542 | * Show and set the arp timer interval. There are two tricky bits | ||
543 | * here. First, if ARP monitoring is activated, then we must disable | ||
544 | * MII monitoring. Second, if the ARP timer isn't running, we must | ||
545 | * start it. | ||
546 | */ | ||
547 | static ssize_t bonding_show_arp_interval(struct class_device *cd, char *buf) | ||
548 | { | ||
549 | struct bonding *bond = to_bond(cd); | ||
550 | |||
551 | return sprintf(buf, "%d\n", bond->params.arp_interval) + 1; | ||
552 | } | ||
553 | |||
554 | static ssize_t bonding_store_arp_interval(struct class_device *cd, const char *buf, size_t count) | ||
555 | { | ||
556 | int new_value, ret = count; | ||
557 | struct bonding *bond = to_bond(cd); | ||
558 | |||
559 | if (sscanf(buf, "%d", &new_value) != 1) { | ||
560 | printk(KERN_ERR DRV_NAME | ||
561 | ": %s: no arp_interval value specified.\n", | ||
562 | bond->dev->name); | ||
563 | ret = -EINVAL; | ||
564 | goto out; | ||
565 | } | ||
566 | if (new_value < 0) { | ||
567 | printk(KERN_ERR DRV_NAME | ||
568 | ": %s: Invalid arp_interval value %d not in range 1-%d; rejected.\n", | ||
569 | bond->dev->name, new_value, INT_MAX); | ||
570 | ret = -EINVAL; | ||
571 | goto out; | ||
572 | } | ||
573 | |||
574 | printk(KERN_INFO DRV_NAME | ||
575 | ": %s: Setting ARP monitoring interval to %d.\n", | ||
576 | bond->dev->name, new_value); | ||
577 | bond->params.arp_interval = new_value; | ||
578 | if (bond->params.miimon) { | ||
579 | printk(KERN_INFO DRV_NAME | ||
580 | ": %s: ARP monitoring cannot be used with MII monitoring. " | ||
581 | "%s Disabling MII monitoring.\n", | ||
582 | bond->dev->name, bond->dev->name); | ||
583 | bond->params.miimon = 0; | ||
584 | /* Kill MII timer, else it brings bond's link down */ | ||
585 | if (bond->arp_timer.function) { | ||
586 | printk(KERN_INFO DRV_NAME | ||
587 | ": %s: Kill MII timer, else it brings bond's link down...\n", | ||
588 | bond->dev->name); | ||
589 | del_timer_sync(&bond->mii_timer); | ||
590 | } | ||
591 | } | ||
592 | if (!bond->params.arp_targets[0]) { | ||
593 | printk(KERN_INFO DRV_NAME | ||
594 | ": %s: ARP monitoring has been set up, " | ||
595 | "but no ARP targets have been specified.\n", | ||
596 | bond->dev->name); | ||
597 | } | ||
598 | if (bond->dev->flags & IFF_UP) { | ||
599 | /* If the interface is up, we may need to fire off | ||
600 | * the ARP timer. If the interface is down, the | ||
601 | * timer will get fired off when the open function | ||
602 | * is called. | ||
603 | */ | ||
604 | if (bond->arp_timer.function) { | ||
605 | /* The timer's already set up, so fire it off */ | ||
606 | mod_timer(&bond->arp_timer, jiffies + 1); | ||
607 | } else { | ||
608 | /* Set up the timer. */ | ||
609 | init_timer(&bond->arp_timer); | ||
610 | bond->arp_timer.expires = jiffies + 1; | ||
611 | bond->arp_timer.data = | ||
612 | (unsigned long) bond->dev; | ||
613 | if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) { | ||
614 | bond->arp_timer.function = | ||
615 | (void *) | ||
616 | &bond_activebackup_arp_mon; | ||
617 | } else { | ||
618 | bond->arp_timer.function = | ||
619 | (void *) | ||
620 | &bond_loadbalance_arp_mon; | ||
621 | } | ||
622 | add_timer(&bond->arp_timer); | ||
623 | } | ||
624 | } | ||
625 | |||
626 | out: | ||
627 | return ret; | ||
628 | } | ||
629 | static CLASS_DEVICE_ATTR(arp_interval, S_IRUGO | S_IWUSR , bonding_show_arp_interval, bonding_store_arp_interval); | ||
630 | |||
631 | /* | ||
632 | * Show and set the arp targets. | ||
633 | */ | ||
634 | static ssize_t bonding_show_arp_targets(struct class_device *cd, char *buf) | ||
635 | { | ||
636 | int i, res = 0; | ||
637 | struct bonding *bond = to_bond(cd); | ||
638 | |||
639 | for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) { | ||
640 | if (bond->params.arp_targets[i]) | ||
641 | res += sprintf(buf + res, "%u.%u.%u.%u ", | ||
642 | NIPQUAD(bond->params.arp_targets[i])); | ||
643 | } | ||
644 | if (res) | ||
645 | res--; /* eat the leftover space */ | ||
646 | res += sprintf(buf + res, "\n"); | ||
647 | res++; | ||
648 | return res; | ||
649 | } | ||
650 | |||
651 | static ssize_t bonding_store_arp_targets(struct class_device *cd, const char *buf, size_t count) | ||
652 | { | ||
653 | u32 newtarget; | ||
654 | int i = 0, done = 0, ret = count; | ||
655 | struct bonding *bond = to_bond(cd); | ||
656 | u32 *targets; | ||
657 | |||
658 | targets = bond->params.arp_targets; | ||
659 | newtarget = in_aton(buf + 1); | ||
660 | /* look for adds */ | ||
661 | if (buf[0] == '+') { | ||
662 | if ((newtarget == 0) || (newtarget == INADDR_BROADCAST)) { | ||
663 | printk(KERN_ERR DRV_NAME | ||
664 | ": %s: invalid ARP target %u.%u.%u.%u specified for addition\n", | ||
665 | bond->dev->name, NIPQUAD(newtarget)); | ||
666 | ret = -EINVAL; | ||
667 | goto out; | ||
668 | } | ||
669 | /* look for an empty slot to put the target in, and check for dupes */ | ||
670 | for (i = 0; (i < BOND_MAX_ARP_TARGETS); i++) { | ||
671 | if (targets[i] == newtarget) { /* duplicate */ | ||
672 | printk(KERN_ERR DRV_NAME | ||
673 | ": %s: ARP target %u.%u.%u.%u is already present\n", | ||
674 | bond->dev->name, NIPQUAD(newtarget)); | ||
675 | if (done) | ||
676 | targets[i] = 0; | ||
677 | ret = -EINVAL; | ||
678 | goto out; | ||
679 | } | ||
680 | if (targets[i] == 0 && !done) { | ||
681 | printk(KERN_INFO DRV_NAME | ||
682 | ": %s: adding ARP target %d.%d.%d.%d.\n", | ||
683 | bond->dev->name, NIPQUAD(newtarget)); | ||
684 | done = 1; | ||
685 | targets[i] = newtarget; | ||
686 | } | ||
687 | } | ||
688 | if (!done) { | ||
689 | printk(KERN_ERR DRV_NAME | ||
690 | ": %s: ARP target table is full!\n", | ||
691 | bond->dev->name); | ||
692 | ret = -EINVAL; | ||
693 | goto out; | ||
694 | } | ||
695 | |||
696 | } | ||
697 | else if (buf[0] == '-') { | ||
698 | if ((newtarget == 0) || (newtarget == INADDR_BROADCAST)) { | ||
699 | printk(KERN_ERR DRV_NAME | ||
700 | ": %s: invalid ARP target %d.%d.%d.%d specified for removal\n", | ||
701 | bond->dev->name, NIPQUAD(newtarget)); | ||
702 | ret = -EINVAL; | ||
703 | goto out; | ||
704 | } | ||
705 | |||
706 | for (i = 0; (i < BOND_MAX_ARP_TARGETS); i++) { | ||
707 | if (targets[i] == newtarget) { | ||
708 | printk(KERN_INFO DRV_NAME | ||
709 | ": %s: removing ARP target %d.%d.%d.%d.\n", | ||
710 | bond->dev->name, NIPQUAD(newtarget)); | ||
711 | targets[i] = 0; | ||
712 | done = 1; | ||
713 | } | ||
714 | } | ||
715 | if (!done) { | ||
716 | printk(KERN_INFO DRV_NAME | ||
717 | ": %s: unable to remove nonexistent ARP target %d.%d.%d.%d.\n", | ||
718 | bond->dev->name, NIPQUAD(newtarget)); | ||
719 | ret = -EINVAL; | ||
720 | goto out; | ||
721 | } | ||
722 | } | ||
723 | else { | ||
724 | printk(KERN_ERR DRV_NAME ": no command found in arp_ip_targets file for bond %s. Use +<addr> or -<addr>.\n", | ||
725 | bond->dev->name); | ||
726 | ret = -EPERM; | ||
727 | goto out; | ||
728 | } | ||
729 | |||
730 | out: | ||
731 | return ret; | ||
732 | } | ||
733 | static CLASS_DEVICE_ATTR(arp_ip_target, S_IRUGO | S_IWUSR , bonding_show_arp_targets, bonding_store_arp_targets); | ||
734 | |||
735 | /* | ||
736 | * Show and set the up and down delays. These must be multiples of the | ||
737 | * MII monitoring value, and are stored internally as the multiplier. | ||
738 | * Thus, we must translate to MS for the real world. | ||
739 | */ | ||
740 | static ssize_t bonding_show_downdelay(struct class_device *cd, char *buf) | ||
741 | { | ||
742 | struct bonding *bond = to_bond(cd); | ||
743 | |||
744 | return sprintf(buf, "%d\n", bond->params.downdelay * bond->params.miimon) + 1; | ||
745 | } | ||
746 | |||
747 | static ssize_t bonding_store_downdelay(struct class_device *cd, const char *buf, size_t count) | ||
748 | { | ||
749 | int new_value, ret = count; | ||
750 | struct bonding *bond = to_bond(cd); | ||
751 | |||
752 | if (!(bond->params.miimon)) { | ||
753 | printk(KERN_ERR DRV_NAME | ||
754 | ": %s: Unable to set down delay as MII monitoring is disabled\n", | ||
755 | bond->dev->name); | ||
756 | ret = -EPERM; | ||
757 | goto out; | ||
758 | } | ||
759 | |||
760 | if (sscanf(buf, "%d", &new_value) != 1) { | ||
761 | printk(KERN_ERR DRV_NAME | ||
762 | ": %s: no down delay value specified.\n", | ||
763 | bond->dev->name); | ||
764 | ret = -EINVAL; | ||
765 | goto out; | ||
766 | } | ||
767 | if (new_value < 0) { | ||
768 | printk(KERN_ERR DRV_NAME | ||
769 | ": %s: Invalid down delay value %d not in range %d-%d; rejected.\n", | ||
770 | bond->dev->name, new_value, 1, INT_MAX); | ||
771 | ret = -EINVAL; | ||
772 | goto out; | ||
773 | } else { | ||
774 | if ((new_value % bond->params.miimon) != 0) { | ||
775 | printk(KERN_WARNING DRV_NAME | ||
776 | ": %s: Warning: down delay (%d) is not a multiple " | ||
777 | "of miimon (%d), delay rounded to %d ms\n", | ||
778 | bond->dev->name, new_value, bond->params.miimon, | ||
779 | (new_value / bond->params.miimon) * | ||
780 | bond->params.miimon); | ||
781 | } | ||
782 | bond->params.downdelay = new_value / bond->params.miimon; | ||
783 | printk(KERN_INFO DRV_NAME ": %s: Setting down delay to %d.\n", | ||
784 | bond->dev->name, bond->params.downdelay * bond->params.miimon); | ||
785 | |||
786 | } | ||
787 | |||
788 | out: | ||
789 | return ret; | ||
790 | } | ||
791 | static CLASS_DEVICE_ATTR(downdelay, S_IRUGO | S_IWUSR , bonding_show_downdelay, bonding_store_downdelay); | ||
792 | |||
793 | static ssize_t bonding_show_updelay(struct class_device *cd, char *buf) | ||
794 | { | ||
795 | struct bonding *bond = to_bond(cd); | ||
796 | |||
797 | return sprintf(buf, "%d\n", bond->params.updelay * bond->params.miimon) + 1; | ||
798 | |||
799 | } | ||
800 | |||
801 | static ssize_t bonding_store_updelay(struct class_device *cd, const char *buf, size_t count) | ||
802 | { | ||
803 | int new_value, ret = count; | ||
804 | struct bonding *bond = to_bond(cd); | ||
805 | |||
806 | if (!(bond->params.miimon)) { | ||
807 | printk(KERN_ERR DRV_NAME | ||
808 | ": %s: Unable to set up delay as MII monitoring is disabled\n", | ||
809 | bond->dev->name); | ||
810 | ret = -EPERM; | ||
811 | goto out; | ||
812 | } | ||
813 | |||
814 | if (sscanf(buf, "%d", &new_value) != 1) { | ||
815 | printk(KERN_ERR DRV_NAME | ||
816 | ": %s: no up delay value specified.\n", | ||
817 | bond->dev->name); | ||
818 | ret = -EINVAL; | ||
819 | goto out; | ||
820 | } | ||
821 | if (new_value < 0) { | ||
822 | printk(KERN_ERR DRV_NAME | ||
823 | ": %s: Invalid down delay value %d not in range %d-%d; rejected.\n", | ||
824 | bond->dev->name, new_value, 1, INT_MAX); | ||
825 | ret = -EINVAL; | ||
826 | goto out; | ||
827 | } else { | ||
828 | if ((new_value % bond->params.miimon) != 0) { | ||
829 | printk(KERN_WARNING DRV_NAME | ||
830 | ": %s: Warning: up delay (%d) is not a multiple " | ||
831 | "of miimon (%d), updelay rounded to %d ms\n", | ||
832 | bond->dev->name, new_value, bond->params.miimon, | ||
833 | (new_value / bond->params.miimon) * | ||
834 | bond->params.miimon); | ||
835 | } | ||
836 | bond->params.updelay = new_value / bond->params.miimon; | ||
837 | printk(KERN_INFO DRV_NAME ": %s: Setting up delay to %d.\n", | ||
838 | bond->dev->name, bond->params.updelay * bond->params.miimon); | ||
839 | |||
840 | } | ||
841 | |||
842 | out: | ||
843 | return ret; | ||
844 | } | ||
845 | static CLASS_DEVICE_ATTR(updelay, S_IRUGO | S_IWUSR , bonding_show_updelay, bonding_store_updelay); | ||
846 | |||
847 | /* | ||
848 | * Show and set the LACP interval. Interface must be down, and the mode | ||
849 | * must be set to 802.3ad mode. | ||
850 | */ | ||
851 | static ssize_t bonding_show_lacp(struct class_device *cd, char *buf) | ||
852 | { | ||
853 | struct bonding *bond = to_bond(cd); | ||
854 | |||
855 | return sprintf(buf, "%s %d\n", | ||
856 | bond_lacp_tbl[bond->params.lacp_fast].modename, | ||
857 | bond->params.lacp_fast) + 1; | ||
858 | } | ||
859 | |||
860 | static ssize_t bonding_store_lacp(struct class_device *cd, const char *buf, size_t count) | ||
861 | { | ||
862 | int new_value, ret = count; | ||
863 | struct bonding *bond = to_bond(cd); | ||
864 | |||
865 | if (bond->dev->flags & IFF_UP) { | ||
866 | printk(KERN_ERR DRV_NAME | ||
867 | ": %s: Unable to update LACP rate because interface is up.\n", | ||
868 | bond->dev->name); | ||
869 | ret = -EPERM; | ||
870 | goto out; | ||
871 | } | ||
872 | |||
873 | if (bond->params.mode != BOND_MODE_8023AD) { | ||
874 | printk(KERN_ERR DRV_NAME | ||
875 | ": %s: Unable to update LACP rate because bond is not in 802.3ad mode.\n", | ||
876 | bond->dev->name); | ||
877 | ret = -EPERM; | ||
878 | goto out; | ||
879 | } | ||
880 | |||
881 | new_value = bond_parse_parm((char *)buf, bond_lacp_tbl); | ||
882 | |||
883 | if ((new_value == 1) || (new_value == 0)) { | ||
884 | bond->params.lacp_fast = new_value; | ||
885 | printk(KERN_INFO DRV_NAME | ||
886 | ": %s: Setting LACP rate to %s (%d).\n", | ||
887 | bond->dev->name, bond_lacp_tbl[new_value].modename, new_value); | ||
888 | } else { | ||
889 | printk(KERN_ERR DRV_NAME | ||
890 | ": %s: Ignoring invalid LACP rate value %.*s.\n", | ||
891 | bond->dev->name, (int)strlen(buf) - 1, buf); | ||
892 | ret = -EINVAL; | ||
893 | } | ||
894 | out: | ||
895 | return ret; | ||
896 | } | ||
897 | static CLASS_DEVICE_ATTR(lacp_rate, S_IRUGO | S_IWUSR, bonding_show_lacp, bonding_store_lacp); | ||
898 | |||
899 | /* | ||
900 | * Show and set the MII monitor interval. There are two tricky bits | ||
901 | * here. First, if MII monitoring is activated, then we must disable | ||
902 | * ARP monitoring. Second, if the timer isn't running, we must | ||
903 | * start it. | ||
904 | */ | ||
905 | static ssize_t bonding_show_miimon(struct class_device *cd, char *buf) | ||
906 | { | ||
907 | struct bonding *bond = to_bond(cd); | ||
908 | |||
909 | return sprintf(buf, "%d\n", bond->params.miimon) + 1; | ||
910 | } | ||
911 | |||
912 | static ssize_t bonding_store_miimon(struct class_device *cd, const char *buf, size_t count) | ||
913 | { | ||
914 | int new_value, ret = count; | ||
915 | struct bonding *bond = to_bond(cd); | ||
916 | |||
917 | if (sscanf(buf, "%d", &new_value) != 1) { | ||
918 | printk(KERN_ERR DRV_NAME | ||
919 | ": %s: no miimon value specified.\n", | ||
920 | bond->dev->name); | ||
921 | ret = -EINVAL; | ||
922 | goto out; | ||
923 | } | ||
924 | if (new_value < 0) { | ||
925 | printk(KERN_ERR DRV_NAME | ||
926 | ": %s: Invalid miimon value %d not in range %d-%d; rejected.\n", | ||
927 | bond->dev->name, new_value, 1, INT_MAX); | ||
928 | ret = -EINVAL; | ||
929 | goto out; | ||
930 | } else { | ||
931 | printk(KERN_INFO DRV_NAME | ||
932 | ": %s: Setting MII monitoring interval to %d.\n", | ||
933 | bond->dev->name, new_value); | ||
934 | bond->params.miimon = new_value; | ||
935 | if(bond->params.updelay) | ||
936 | printk(KERN_INFO DRV_NAME | ||
937 | ": %s: Note: Updating updelay (to %d) " | ||
938 | "since it is a multiple of the miimon value.\n", | ||
939 | bond->dev->name, | ||
940 | bond->params.updelay * bond->params.miimon); | ||
941 | if(bond->params.downdelay) | ||
942 | printk(KERN_INFO DRV_NAME | ||
943 | ": %s: Note: Updating downdelay (to %d) " | ||
944 | "since it is a multiple of the miimon value.\n", | ||
945 | bond->dev->name, | ||
946 | bond->params.downdelay * bond->params.miimon); | ||
947 | if (bond->params.arp_interval) { | ||
948 | printk(KERN_INFO DRV_NAME | ||
949 | ": %s: MII monitoring cannot be used with " | ||
950 | "ARP monitoring. Disabling ARP monitoring...\n", | ||
951 | bond->dev->name); | ||
952 | bond->params.arp_interval = 0; | ||
953 | /* Kill ARP timer, else it brings bond's link down */ | ||
954 | if (bond->mii_timer.function) { | ||
955 | printk(KERN_INFO DRV_NAME | ||
956 | ": %s: Kill ARP timer, else it brings bond's link down...\n", | ||
957 | bond->dev->name); | ||
958 | del_timer_sync(&bond->arp_timer); | ||
959 | } | ||
960 | } | ||
961 | |||
962 | if (bond->dev->flags & IFF_UP) { | ||
963 | /* If the interface is up, we may need to fire off | ||
964 | * the MII timer. If the interface is down, the | ||
965 | * timer will get fired off when the open function | ||
966 | * is called. | ||
967 | */ | ||
968 | if (bond->mii_timer.function) { | ||
969 | /* The timer's already set up, so fire it off */ | ||
970 | mod_timer(&bond->mii_timer, jiffies + 1); | ||
971 | } else { | ||
972 | /* Set up the timer. */ | ||
973 | init_timer(&bond->mii_timer); | ||
974 | bond->mii_timer.expires = jiffies + 1; | ||
975 | bond->mii_timer.data = | ||
976 | (unsigned long) bond->dev; | ||
977 | bond->mii_timer.function = | ||
978 | (void *) &bond_mii_monitor; | ||
979 | add_timer(&bond->mii_timer); | ||
980 | } | ||
981 | } | ||
982 | } | ||
983 | out: | ||
984 | return ret; | ||
985 | } | ||
986 | static CLASS_DEVICE_ATTR(miimon, S_IRUGO | S_IWUSR, bonding_show_miimon, bonding_store_miimon); | ||
987 | |||
988 | /* | ||
989 | * Show and set the primary slave. The store function is much | ||
990 | * simpler than bonding_store_slaves function because it only needs to | ||
991 | * handle one interface name. | ||
992 | * The bond must be a mode that supports a primary for this be | ||
993 | * set. | ||
994 | */ | ||
995 | static ssize_t bonding_show_primary(struct class_device *cd, char *buf) | ||
996 | { | ||
997 | int count = 0; | ||
998 | struct bonding *bond = to_bond(cd); | ||
999 | |||
1000 | if (bond->primary_slave) | ||
1001 | count = sprintf(buf, "%s\n", bond->primary_slave->dev->name) + 1; | ||
1002 | else | ||
1003 | count = sprintf(buf, "\n") + 1; | ||
1004 | |||
1005 | return count; | ||
1006 | } | ||
1007 | |||
1008 | static ssize_t bonding_store_primary(struct class_device *cd, const char *buf, size_t count) | ||
1009 | { | ||
1010 | int i; | ||
1011 | struct slave *slave; | ||
1012 | struct bonding *bond = to_bond(cd); | ||
1013 | |||
1014 | write_lock_bh(&bond->lock); | ||
1015 | if (!USES_PRIMARY(bond->params.mode)) { | ||
1016 | printk(KERN_INFO DRV_NAME | ||
1017 | ": %s: Unable to set primary slave; %s is in mode %d\n", | ||
1018 | bond->dev->name, bond->dev->name, bond->params.mode); | ||
1019 | } else { | ||
1020 | bond_for_each_slave(bond, slave, i) { | ||
1021 | if (strnicmp | ||
1022 | (slave->dev->name, buf, | ||
1023 | strlen(slave->dev->name)) == 0) { | ||
1024 | printk(KERN_INFO DRV_NAME | ||
1025 | ": %s: Setting %s as primary slave.\n", | ||
1026 | bond->dev->name, slave->dev->name); | ||
1027 | bond->primary_slave = slave; | ||
1028 | bond_select_active_slave(bond); | ||
1029 | goto out; | ||
1030 | } | ||
1031 | } | ||
1032 | |||
1033 | /* if we got here, then we didn't match the name of any slave */ | ||
1034 | |||
1035 | if (strlen(buf) == 0 || buf[0] == '\n') { | ||
1036 | printk(KERN_INFO DRV_NAME | ||
1037 | ": %s: Setting primary slave to None.\n", | ||
1038 | bond->dev->name); | ||
1039 | bond->primary_slave = 0; | ||
1040 | bond_select_active_slave(bond); | ||
1041 | } else { | ||
1042 | printk(KERN_INFO DRV_NAME | ||
1043 | ": %s: Unable to set %.*s as primary slave as it is not a slave.\n", | ||
1044 | bond->dev->name, (int)strlen(buf) - 1, buf); | ||
1045 | } | ||
1046 | } | ||
1047 | out: | ||
1048 | write_unlock_bh(&bond->lock); | ||
1049 | return count; | ||
1050 | } | ||
1051 | static CLASS_DEVICE_ATTR(primary, S_IRUGO | S_IWUSR, bonding_show_primary, bonding_store_primary); | ||
1052 | |||
1053 | /* | ||
1054 | * Show and set the use_carrier flag. | ||
1055 | */ | ||
1056 | static ssize_t bonding_show_carrier(struct class_device *cd, char *buf) | ||
1057 | { | ||
1058 | struct bonding *bond = to_bond(cd); | ||
1059 | |||
1060 | return sprintf(buf, "%d\n", bond->params.use_carrier) + 1; | ||
1061 | } | ||
1062 | |||
1063 | static ssize_t bonding_store_carrier(struct class_device *cd, const char *buf, size_t count) | ||
1064 | { | ||
1065 | int new_value, ret = count; | ||
1066 | struct bonding *bond = to_bond(cd); | ||
1067 | |||
1068 | |||
1069 | if (sscanf(buf, "%d", &new_value) != 1) { | ||
1070 | printk(KERN_ERR DRV_NAME | ||
1071 | ": %s: no use_carrier value specified.\n", | ||
1072 | bond->dev->name); | ||
1073 | ret = -EINVAL; | ||
1074 | goto out; | ||
1075 | } | ||
1076 | if ((new_value == 0) || (new_value == 1)) { | ||
1077 | bond->params.use_carrier = new_value; | ||
1078 | printk(KERN_INFO DRV_NAME ": %s: Setting use_carrier to %d.\n", | ||
1079 | bond->dev->name, new_value); | ||
1080 | } else { | ||
1081 | printk(KERN_INFO DRV_NAME | ||
1082 | ": %s: Ignoring invalid use_carrier value %d.\n", | ||
1083 | bond->dev->name, new_value); | ||
1084 | } | ||
1085 | out: | ||
1086 | return count; | ||
1087 | } | ||
1088 | static CLASS_DEVICE_ATTR(use_carrier, S_IRUGO | S_IWUSR, bonding_show_carrier, bonding_store_carrier); | ||
1089 | |||
1090 | |||
1091 | /* | ||
1092 | * Show and set currently active_slave. | ||
1093 | */ | ||
1094 | static ssize_t bonding_show_active_slave(struct class_device *cd, char *buf) | ||
1095 | { | ||
1096 | struct slave *curr; | ||
1097 | struct bonding *bond = to_bond(cd); | ||
1098 | int count; | ||
1099 | |||
1100 | |||
1101 | read_lock(&bond->curr_slave_lock); | ||
1102 | curr = bond->curr_active_slave; | ||
1103 | read_unlock(&bond->curr_slave_lock); | ||
1104 | |||
1105 | if (USES_PRIMARY(bond->params.mode) && curr) | ||
1106 | count = sprintf(buf, "%s\n", curr->dev->name) + 1; | ||
1107 | else | ||
1108 | count = sprintf(buf, "\n") + 1; | ||
1109 | return count; | ||
1110 | } | ||
1111 | |||
1112 | static ssize_t bonding_store_active_slave(struct class_device *cd, const char *buf, size_t count) | ||
1113 | { | ||
1114 | int i; | ||
1115 | struct slave *slave; | ||
1116 | struct slave *old_active = NULL; | ||
1117 | struct slave *new_active = NULL; | ||
1118 | struct bonding *bond = to_bond(cd); | ||
1119 | |||
1120 | write_lock_bh(&bond->lock); | ||
1121 | if (!USES_PRIMARY(bond->params.mode)) { | ||
1122 | printk(KERN_INFO DRV_NAME | ||
1123 | ": %s: Unable to change active slave; %s is in mode %d\n", | ||
1124 | bond->dev->name, bond->dev->name, bond->params.mode); | ||
1125 | } else { | ||
1126 | bond_for_each_slave(bond, slave, i) { | ||
1127 | if (strnicmp | ||
1128 | (slave->dev->name, buf, | ||
1129 | strlen(slave->dev->name)) == 0) { | ||
1130 | old_active = bond->curr_active_slave; | ||
1131 | new_active = slave; | ||
1132 | if (new_active && (new_active == old_active)) { | ||
1133 | /* do nothing */ | ||
1134 | printk(KERN_INFO DRV_NAME | ||
1135 | ": %s: %s is already the current active slave.\n", | ||
1136 | bond->dev->name, slave->dev->name); | ||
1137 | goto out; | ||
1138 | } | ||
1139 | else { | ||
1140 | if ((new_active) && | ||
1141 | (old_active) && | ||
1142 | (new_active->link == BOND_LINK_UP) && | ||
1143 | IS_UP(new_active->dev)) { | ||
1144 | printk(KERN_INFO DRV_NAME | ||
1145 | ": %s: Setting %s as active slave.\n", | ||
1146 | bond->dev->name, slave->dev->name); | ||
1147 | bond_change_active_slave(bond, new_active); | ||
1148 | } | ||
1149 | else { | ||
1150 | printk(KERN_INFO DRV_NAME | ||
1151 | ": %s: Could not set %s as active slave; " | ||
1152 | "either %s is down or the link is down.\n", | ||
1153 | bond->dev->name, slave->dev->name, | ||
1154 | slave->dev->name); | ||
1155 | } | ||
1156 | goto out; | ||
1157 | } | ||
1158 | } | ||
1159 | } | ||
1160 | |||
1161 | /* if we got here, then we didn't match the name of any slave */ | ||
1162 | |||
1163 | if (strlen(buf) == 0 || buf[0] == '\n') { | ||
1164 | printk(KERN_INFO DRV_NAME | ||
1165 | ": %s: Setting active slave to None.\n", | ||
1166 | bond->dev->name); | ||
1167 | bond->primary_slave = 0; | ||
1168 | bond_select_active_slave(bond); | ||
1169 | } else { | ||
1170 | printk(KERN_INFO DRV_NAME | ||
1171 | ": %s: Unable to set %.*s as active slave as it is not a slave.\n", | ||
1172 | bond->dev->name, (int)strlen(buf) - 1, buf); | ||
1173 | } | ||
1174 | } | ||
1175 | out: | ||
1176 | write_unlock_bh(&bond->lock); | ||
1177 | return count; | ||
1178 | |||
1179 | } | ||
1180 | static CLASS_DEVICE_ATTR(active_slave, S_IRUGO | S_IWUSR, bonding_show_active_slave, bonding_store_active_slave); | ||
1181 | |||
1182 | |||
1183 | /* | ||
1184 | * Show link status of the bond interface. | ||
1185 | */ | ||
1186 | static ssize_t bonding_show_mii_status(struct class_device *cd, char *buf) | ||
1187 | { | ||
1188 | struct slave *curr; | ||
1189 | struct bonding *bond = to_bond(cd); | ||
1190 | |||
1191 | read_lock(&bond->curr_slave_lock); | ||
1192 | curr = bond->curr_active_slave; | ||
1193 | read_unlock(&bond->curr_slave_lock); | ||
1194 | |||
1195 | return sprintf(buf, "%s\n", (curr) ? "up" : "down") + 1; | ||
1196 | } | ||
1197 | static CLASS_DEVICE_ATTR(mii_status, S_IRUGO, bonding_show_mii_status, NULL); | ||
1198 | |||
1199 | |||
1200 | /* | ||
1201 | * Show current 802.3ad aggregator ID. | ||
1202 | */ | ||
1203 | static ssize_t bonding_show_ad_aggregator(struct class_device *cd, char *buf) | ||
1204 | { | ||
1205 | int count = 0; | ||
1206 | struct bonding *bond = to_bond(cd); | ||
1207 | |||
1208 | if (bond->params.mode == BOND_MODE_8023AD) { | ||
1209 | struct ad_info ad_info; | ||
1210 | count = sprintf(buf, "%d\n", (bond_3ad_get_active_agg_info(bond, &ad_info)) ? 0 : ad_info.aggregator_id) + 1; | ||
1211 | } | ||
1212 | else | ||
1213 | count = sprintf(buf, "\n") + 1; | ||
1214 | |||
1215 | return count; | ||
1216 | } | ||
1217 | static CLASS_DEVICE_ATTR(ad_aggregator, S_IRUGO, bonding_show_ad_aggregator, NULL); | ||
1218 | |||
1219 | |||
1220 | /* | ||
1221 | * Show number of active 802.3ad ports. | ||
1222 | */ | ||
1223 | static ssize_t bonding_show_ad_num_ports(struct class_device *cd, char *buf) | ||
1224 | { | ||
1225 | int count = 0; | ||
1226 | struct bonding *bond = to_bond(cd); | ||
1227 | |||
1228 | if (bond->params.mode == BOND_MODE_8023AD) { | ||
1229 | struct ad_info ad_info; | ||
1230 | count = sprintf(buf, "%d\n", (bond_3ad_get_active_agg_info(bond, &ad_info)) ? 0: ad_info.ports) + 1; | ||
1231 | } | ||
1232 | else | ||
1233 | count = sprintf(buf, "\n") + 1; | ||
1234 | |||
1235 | return count; | ||
1236 | } | ||
1237 | static CLASS_DEVICE_ATTR(ad_num_ports, S_IRUGO, bonding_show_ad_num_ports, NULL); | ||
1238 | |||
1239 | |||
1240 | /* | ||
1241 | * Show current 802.3ad actor key. | ||
1242 | */ | ||
1243 | static ssize_t bonding_show_ad_actor_key(struct class_device *cd, char *buf) | ||
1244 | { | ||
1245 | int count = 0; | ||
1246 | struct bonding *bond = to_bond(cd); | ||
1247 | |||
1248 | if (bond->params.mode == BOND_MODE_8023AD) { | ||
1249 | struct ad_info ad_info; | ||
1250 | count = sprintf(buf, "%d\n", (bond_3ad_get_active_agg_info(bond, &ad_info)) ? 0 : ad_info.actor_key) + 1; | ||
1251 | } | ||
1252 | else | ||
1253 | count = sprintf(buf, "\n") + 1; | ||
1254 | |||
1255 | return count; | ||
1256 | } | ||
1257 | static CLASS_DEVICE_ATTR(ad_actor_key, S_IRUGO, bonding_show_ad_actor_key, NULL); | ||
1258 | |||
1259 | |||
1260 | /* | ||
1261 | * Show current 802.3ad partner key. | ||
1262 | */ | ||
1263 | static ssize_t bonding_show_ad_partner_key(struct class_device *cd, char *buf) | ||
1264 | { | ||
1265 | int count = 0; | ||
1266 | struct bonding *bond = to_bond(cd); | ||
1267 | |||
1268 | if (bond->params.mode == BOND_MODE_8023AD) { | ||
1269 | struct ad_info ad_info; | ||
1270 | count = sprintf(buf, "%d\n", (bond_3ad_get_active_agg_info(bond, &ad_info)) ? 0 : ad_info.partner_key) + 1; | ||
1271 | } | ||
1272 | else | ||
1273 | count = sprintf(buf, "\n") + 1; | ||
1274 | |||
1275 | return count; | ||
1276 | } | ||
1277 | static CLASS_DEVICE_ATTR(ad_partner_key, S_IRUGO, bonding_show_ad_partner_key, NULL); | ||
1278 | |||
1279 | |||
1280 | /* | ||
1281 | * Show current 802.3ad partner mac. | ||
1282 | */ | ||
1283 | static ssize_t bonding_show_ad_partner_mac(struct class_device *cd, char *buf) | ||
1284 | { | ||
1285 | int count = 0; | ||
1286 | struct bonding *bond = to_bond(cd); | ||
1287 | |||
1288 | if (bond->params.mode == BOND_MODE_8023AD) { | ||
1289 | struct ad_info ad_info; | ||
1290 | if (!bond_3ad_get_active_agg_info(bond, &ad_info)) { | ||
1291 | count = sprintf(buf,"%02x:%02x:%02x:%02x:%02x:%02x\n", | ||
1292 | ad_info.partner_system[0], | ||
1293 | ad_info.partner_system[1], | ||
1294 | ad_info.partner_system[2], | ||
1295 | ad_info.partner_system[3], | ||
1296 | ad_info.partner_system[4], | ||
1297 | ad_info.partner_system[5]) + 1; | ||
1298 | } | ||
1299 | } | ||
1300 | else | ||
1301 | count = sprintf(buf, "\n") + 1; | ||
1302 | |||
1303 | return count; | ||
1304 | } | ||
1305 | static CLASS_DEVICE_ATTR(ad_partner_mac, S_IRUGO, bonding_show_ad_partner_mac, NULL); | ||
1306 | |||
1307 | |||
1308 | |||
1309 | static struct attribute *per_bond_attrs[] = { | ||
1310 | &class_device_attr_slaves.attr, | ||
1311 | &class_device_attr_mode.attr, | ||
1312 | &class_device_attr_arp_interval.attr, | ||
1313 | &class_device_attr_arp_ip_target.attr, | ||
1314 | &class_device_attr_downdelay.attr, | ||
1315 | &class_device_attr_updelay.attr, | ||
1316 | &class_device_attr_lacp_rate.attr, | ||
1317 | &class_device_attr_xmit_hash_policy.attr, | ||
1318 | &class_device_attr_miimon.attr, | ||
1319 | &class_device_attr_primary.attr, | ||
1320 | &class_device_attr_use_carrier.attr, | ||
1321 | &class_device_attr_active_slave.attr, | ||
1322 | &class_device_attr_mii_status.attr, | ||
1323 | &class_device_attr_ad_aggregator.attr, | ||
1324 | &class_device_attr_ad_num_ports.attr, | ||
1325 | &class_device_attr_ad_actor_key.attr, | ||
1326 | &class_device_attr_ad_partner_key.attr, | ||
1327 | &class_device_attr_ad_partner_mac.attr, | ||
1328 | NULL, | ||
1329 | }; | ||
1330 | |||
1331 | static struct attribute_group bonding_group = { | ||
1332 | .name = "bonding", | ||
1333 | .attrs = per_bond_attrs, | ||
1334 | }; | ||
1335 | |||
1336 | /* | ||
1337 | * Initialize sysfs. This sets up the bonding_masters file in | ||
1338 | * /sys/class/net. | ||
1339 | */ | ||
1340 | int bond_create_sysfs(void) | ||
1341 | { | ||
1342 | int ret = 0; | ||
1343 | struct bonding *firstbond; | ||
1344 | |||
1345 | init_rwsem(&bonding_rwsem); | ||
1346 | |||
1347 | /* get the netdev class pointer */ | ||
1348 | firstbond = container_of(bond_dev_list.next, struct bonding, bond_list); | ||
1349 | if (!firstbond) | ||
1350 | return -ENODEV; | ||
1351 | |||
1352 | netdev_class = firstbond->dev->class_dev.class; | ||
1353 | if (!netdev_class) | ||
1354 | return -ENODEV; | ||
1355 | |||
1356 | ret = class_create_file(netdev_class, &class_attr_bonding_masters); | ||
1357 | |||
1358 | return ret; | ||
1359 | |||
1360 | } | ||
1361 | |||
1362 | /* | ||
1363 | * Remove /sys/class/net/bonding_masters. | ||
1364 | */ | ||
1365 | void bond_destroy_sysfs(void) | ||
1366 | { | ||
1367 | if (netdev_class) | ||
1368 | class_remove_file(netdev_class, &class_attr_bonding_masters); | ||
1369 | } | ||
1370 | |||
1371 | /* | ||
1372 | * Initialize sysfs for each bond. This sets up and registers | ||
1373 | * the 'bondctl' directory for each individual bond under /sys/class/net. | ||
1374 | */ | ||
1375 | int bond_create_sysfs_entry(struct bonding *bond) | ||
1376 | { | ||
1377 | struct net_device *dev = bond->dev; | ||
1378 | int err; | ||
1379 | |||
1380 | err = sysfs_create_group(&(dev->class_dev.kobj), &bonding_group); | ||
1381 | if (err) { | ||
1382 | printk(KERN_EMERG "eek! didn't create group!\n"); | ||
1383 | } | ||
1384 | |||
1385 | if (expected_refcount < 1) | ||
1386 | expected_refcount = atomic_read(&bond->dev->class_dev.kobj.kref.refcount); | ||
1387 | |||
1388 | return err; | ||
1389 | } | ||
1390 | /* | ||
1391 | * Remove sysfs entries for each bond. | ||
1392 | */ | ||
1393 | void bond_destroy_sysfs_entry(struct bonding *bond) | ||
1394 | { | ||
1395 | struct net_device *dev = bond->dev; | ||
1396 | |||
1397 | sysfs_remove_group(&(dev->class_dev.kobj), &bonding_group); | ||
1398 | } | ||
1399 | |||
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 863605aab204..903e60aa611e 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <linux/timer.h> | 37 | #include <linux/timer.h> |
38 | #include <linux/proc_fs.h> | 38 | #include <linux/proc_fs.h> |
39 | #include <linux/if_bonding.h> | 39 | #include <linux/if_bonding.h> |
40 | #include <linux/kobject.h> | ||
40 | #include "bond_3ad.h" | 41 | #include "bond_3ad.h" |
41 | #include "bond_alb.h" | 42 | #include "bond_alb.h" |
42 | 43 | ||
@@ -262,6 +263,12 @@ struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr) | |||
262 | int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev); | 263 | int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev); |
263 | int bond_create(char *name, struct bond_params *params, struct bonding **newbond); | 264 | int bond_create(char *name, struct bond_params *params, struct bonding **newbond); |
264 | void bond_deinit(struct net_device *bond_dev); | 265 | void bond_deinit(struct net_device *bond_dev); |
266 | int bond_create_sysfs(void); | ||
267 | void bond_destroy_sysfs(void); | ||
268 | void bond_destroy_sysfs_entry(struct bonding *bond); | ||
269 | int bond_create_sysfs_entry(struct bonding *bond); | ||
270 | int bond_create_slave_symlinks(struct net_device *master, struct net_device *slave); | ||
271 | void bond_destroy_slave_symlinks(struct net_device *master, struct net_device *slave); | ||
265 | int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev); | 272 | int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev); |
266 | int bond_release(struct net_device *bond_dev, struct net_device *slave_dev); | 273 | int bond_release(struct net_device *bond_dev, struct net_device *slave_dev); |
267 | int bond_sethwaddr(struct net_device *bond_dev, struct net_device *slave_dev); | 274 | int bond_sethwaddr(struct net_device *bond_dev, struct net_device *slave_dev); |