Commit | Line | Data |
---|---|---|
b76cdba9 MW |
1 | /* |
2 | * Copyright(c) 2004-2005 Intel Corporation. All rights reserved. | |
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 | |
adf8d3ff | 15 | * with this program; if not, see <http://www.gnu.org/licenses/>. |
b76cdba9 MW |
16 | * |
17 | * The full GNU General Public License is included in this distribution in the | |
18 | * file called LICENSE. | |
19 | * | |
b76cdba9 | 20 | */ |
a4aee5c8 JP |
21 | |
22 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
23 | ||
b76cdba9 MW |
24 | #include <linux/kernel.h> |
25 | #include <linux/module.h> | |
b76cdba9 | 26 | #include <linux/device.h> |
d43c36dc | 27 | #include <linux/sched.h> |
b76cdba9 MW |
28 | #include <linux/fs.h> |
29 | #include <linux/types.h> | |
30 | #include <linux/string.h> | |
31 | #include <linux/netdevice.h> | |
32 | #include <linux/inetdevice.h> | |
33 | #include <linux/in.h> | |
34 | #include <linux/sysfs.h> | |
b76cdba9 MW |
35 | #include <linux/ctype.h> |
36 | #include <linux/inet.h> | |
37 | #include <linux/rtnetlink.h> | |
5c5129b5 | 38 | #include <linux/etherdevice.h> |
881d966b | 39 | #include <net/net_namespace.h> |
ec87fd3b EB |
40 | #include <net/netns/generic.h> |
41 | #include <linux/nsproxy.h> | |
b76cdba9 | 42 | |
b76cdba9 | 43 | #include "bonding.h" |
5a03cdb7 | 44 | |
3d632c3f | 45 | #define to_dev(obj) container_of(obj, struct device, kobj) |
454d7c9b | 46 | #define to_bond(cd) ((struct bonding *)(netdev_priv(to_net_dev(cd)))) |
b76cdba9 | 47 | |
b76cdba9 MW |
48 | /* |
49 | * "show" function for the bond_masters attribute. | |
50 | * The class parameter is ignored. | |
51 | */ | |
28812fe1 AK |
52 | static ssize_t bonding_show_bonds(struct class *cls, |
53 | struct class_attribute *attr, | |
54 | char *buf) | |
b76cdba9 | 55 | { |
4c22400a EB |
56 | struct bond_net *bn = |
57 | container_of(attr, struct bond_net, class_attr_bonding_masters); | |
b76cdba9 MW |
58 | int res = 0; |
59 | struct bonding *bond; | |
60 | ||
7e083840 | 61 | rtnl_lock(); |
b76cdba9 | 62 | |
ec87fd3b | 63 | list_for_each_entry(bond, &bn->dev_list, bond_list) { |
b76cdba9 MW |
64 | if (res > (PAGE_SIZE - IFNAMSIZ)) { |
65 | /* not enough space for another interface name */ | |
66 | if ((PAGE_SIZE - res) > 10) | |
67 | res = PAGE_SIZE - 10; | |
b8843665 | 68 | res += sprintf(buf + res, "++more++ "); |
b76cdba9 MW |
69 | break; |
70 | } | |
b8843665 | 71 | res += sprintf(buf + res, "%s ", bond->dev->name); |
b76cdba9 | 72 | } |
1dcdcd69 WF |
73 | if (res) |
74 | buf[res-1] = '\n'; /* eat the leftover space */ | |
7e083840 SH |
75 | |
76 | rtnl_unlock(); | |
b76cdba9 MW |
77 | return res; |
78 | } | |
79 | ||
4c22400a | 80 | static struct net_device *bond_get_by_name(struct bond_net *bn, const char *ifname) |
373500db SH |
81 | { |
82 | struct bonding *bond; | |
83 | ||
ec87fd3b | 84 | list_for_each_entry(bond, &bn->dev_list, bond_list) { |
373500db SH |
85 | if (strncmp(bond->dev->name, ifname, IFNAMSIZ) == 0) |
86 | return bond->dev; | |
87 | } | |
88 | return NULL; | |
89 | } | |
90 | ||
b76cdba9 MW |
91 | /* |
92 | * "store" function for the bond_masters attribute. This is what | |
93 | * creates and deletes entire bonds. | |
94 | * | |
95 | * The class parameter is ignored. | |
96 | * | |
97 | */ | |
98 | ||
3d632c3f | 99 | static ssize_t bonding_store_bonds(struct class *cls, |
28812fe1 | 100 | struct class_attribute *attr, |
3d632c3f | 101 | const char *buffer, size_t count) |
b76cdba9 | 102 | { |
4c22400a EB |
103 | struct bond_net *bn = |
104 | container_of(attr, struct bond_net, class_attr_bonding_masters); | |
b76cdba9 MW |
105 | char command[IFNAMSIZ + 1] = {0, }; |
106 | char *ifname; | |
027ea041 | 107 | int rv, res = count; |
b76cdba9 | 108 | |
b76cdba9 MW |
109 | sscanf(buffer, "%16s", command); /* IFNAMSIZ*/ |
110 | ifname = command + 1; | |
111 | if ((strlen(command) <= 1) || | |
112 | !dev_valid_name(ifname)) | |
113 | goto err_no_cmd; | |
114 | ||
115 | if (command[0] == '+') { | |
a4aee5c8 | 116 | pr_info("%s is being created...\n", ifname); |
4c22400a | 117 | rv = bond_create(bn->net, ifname); |
027ea041 | 118 | if (rv) { |
5f86cad1 | 119 | if (rv == -EEXIST) |
90194264 | 120 | pr_info("%s already exists\n", ifname); |
5f86cad1 | 121 | else |
90194264 | 122 | pr_info("%s creation failed\n", ifname); |
027ea041 | 123 | res = rv; |
b76cdba9 | 124 | } |
373500db SH |
125 | } else if (command[0] == '-') { |
126 | struct net_device *bond_dev; | |
b76cdba9 | 127 | |
027ea041 | 128 | rtnl_lock(); |
4c22400a | 129 | bond_dev = bond_get_by_name(bn, ifname); |
373500db | 130 | if (bond_dev) { |
a4aee5c8 | 131 | pr_info("%s is being deleted...\n", ifname); |
373500db SH |
132 | unregister_netdevice(bond_dev); |
133 | } else { | |
a4aee5c8 | 134 | pr_err("unable to delete non-existent %s\n", ifname); |
373500db SH |
135 | res = -ENODEV; |
136 | } | |
137 | rtnl_unlock(); | |
138 | } else | |
139 | goto err_no_cmd; | |
027ea041 | 140 | |
373500db SH |
141 | /* Always return either count or an error. If you return 0, you'll |
142 | * get called forever, which is bad. | |
143 | */ | |
144 | return res; | |
b76cdba9 MW |
145 | |
146 | err_no_cmd: | |
90194264 | 147 | pr_err("no command found in bonding_masters - use +ifname or -ifname\n"); |
c4ebc66a | 148 | return -EPERM; |
b76cdba9 | 149 | } |
373500db | 150 | |
b76cdba9 | 151 | /* class attribute for bond_masters file. This ends up in /sys/class/net */ |
4c22400a EB |
152 | static const struct class_attribute class_attr_bonding_masters = { |
153 | .attr = { | |
154 | .name = "bonding_masters", | |
155 | .mode = S_IWUSR | S_IRUGO, | |
156 | }, | |
157 | .show = bonding_show_bonds, | |
158 | .store = bonding_store_bonds, | |
4c22400a | 159 | }; |
b76cdba9 | 160 | |
b76cdba9 MW |
161 | /* |
162 | * Show the slaves in the current bond. | |
163 | */ | |
43cb76d9 GKH |
164 | static ssize_t bonding_show_slaves(struct device *d, |
165 | struct device_attribute *attr, char *buf) | |
b76cdba9 | 166 | { |
43cb76d9 | 167 | struct bonding *bond = to_bond(d); |
9caff1e7 | 168 | struct list_head *iter; |
dec1e90e | 169 | struct slave *slave; |
170 | int res = 0; | |
b76cdba9 | 171 | |
4d1ae5fb | 172 | if (!rtnl_trylock()) |
173 | return restart_syscall(); | |
174 | ||
9caff1e7 | 175 | bond_for_each_slave(bond, slave, iter) { |
b76cdba9 MW |
176 | if (res > (PAGE_SIZE - IFNAMSIZ)) { |
177 | /* not enough space for another interface name */ | |
178 | if ((PAGE_SIZE - res) > 10) | |
179 | res = PAGE_SIZE - 10; | |
7bd46508 | 180 | res += sprintf(buf + res, "++more++ "); |
b76cdba9 MW |
181 | break; |
182 | } | |
183 | res += sprintf(buf + res, "%s ", slave->dev->name); | |
184 | } | |
4d1ae5fb | 185 | |
186 | rtnl_unlock(); | |
187 | ||
1dcdcd69 WF |
188 | if (res) |
189 | buf[res-1] = '\n'; /* eat the leftover space */ | |
dec1e90e | 190 | |
b76cdba9 MW |
191 | return res; |
192 | } | |
193 | ||
194 | /* | |
d6641ccf | 195 | * Set the slaves in the current bond. |
f9f3545e JP |
196 | * This is supposed to be only thin wrapper for bond_enslave and bond_release. |
197 | * All hard work should be done there. | |
b76cdba9 | 198 | */ |
43cb76d9 GKH |
199 | static ssize_t bonding_store_slaves(struct device *d, |
200 | struct device_attribute *attr, | |
201 | const char *buffer, size_t count) | |
b76cdba9 | 202 | { |
43cb76d9 | 203 | struct bonding *bond = to_bond(d); |
0e2e5b66 | 204 | int ret; |
b76cdba9 | 205 | |
0e2e5b66 NA |
206 | ret = bond_opt_tryset_rtnl(bond, BOND_OPT_SLAVES, (char *)buffer); |
207 | if (!ret) | |
208 | ret = count; | |
b76cdba9 | 209 | |
b76cdba9 MW |
210 | return ret; |
211 | } | |
3d632c3f SH |
212 | static DEVICE_ATTR(slaves, S_IRUGO | S_IWUSR, bonding_show_slaves, |
213 | bonding_store_slaves); | |
b76cdba9 MW |
214 | |
215 | /* | |
216 | * Show and set the bonding mode. The bond interface must be down to | |
217 | * change the mode. | |
218 | */ | |
43cb76d9 GKH |
219 | static ssize_t bonding_show_mode(struct device *d, |
220 | struct device_attribute *attr, char *buf) | |
b76cdba9 | 221 | { |
43cb76d9 | 222 | struct bonding *bond = to_bond(d); |
f3253339 | 223 | const struct bond_opt_value *val; |
b76cdba9 | 224 | |
2b3798d5 NA |
225 | val = bond_opt_get_val(BOND_OPT_MODE, bond->params.mode); |
226 | ||
227 | return sprintf(buf, "%s %d\n", val->string, bond->params.mode); | |
b76cdba9 MW |
228 | } |
229 | ||
43cb76d9 GKH |
230 | static ssize_t bonding_store_mode(struct device *d, |
231 | struct device_attribute *attr, | |
232 | const char *buf, size_t count) | |
b76cdba9 | 233 | { |
43cb76d9 | 234 | struct bonding *bond = to_bond(d); |
2b3798d5 | 235 | int ret; |
b76cdba9 | 236 | |
2b3798d5 NA |
237 | ret = bond_opt_tryset_rtnl(bond, BOND_OPT_MODE, (char *)buf); |
238 | if (!ret) | |
72be35fe | 239 | ret = count; |
8f903c70 | 240 | |
b76cdba9 MW |
241 | return ret; |
242 | } | |
3d632c3f SH |
243 | static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, |
244 | bonding_show_mode, bonding_store_mode); | |
b76cdba9 MW |
245 | |
246 | /* | |
3d632c3f | 247 | * Show and set the bonding transmit hash method. |
b76cdba9 | 248 | */ |
43cb76d9 GKH |
249 | static ssize_t bonding_show_xmit_hash(struct device *d, |
250 | struct device_attribute *attr, | |
251 | char *buf) | |
b76cdba9 | 252 | { |
43cb76d9 | 253 | struct bonding *bond = to_bond(d); |
f3253339 | 254 | const struct bond_opt_value *val; |
a4b32ce7 NA |
255 | |
256 | val = bond_opt_get_val(BOND_OPT_XMIT_HASH, bond->params.xmit_policy); | |
b76cdba9 | 257 | |
a4b32ce7 | 258 | return sprintf(buf, "%s %d\n", val->string, bond->params.xmit_policy); |
b76cdba9 MW |
259 | } |
260 | ||
43cb76d9 GKH |
261 | static ssize_t bonding_store_xmit_hash(struct device *d, |
262 | struct device_attribute *attr, | |
263 | const char *buf, size_t count) | |
b76cdba9 | 264 | { |
43cb76d9 | 265 | struct bonding *bond = to_bond(d); |
a4b32ce7 | 266 | int ret; |
b76cdba9 | 267 | |
a4b32ce7 | 268 | ret = bond_opt_tryset_rtnl(bond, BOND_OPT_XMIT_HASH, (char *)buf); |
f70161c6 | 269 | if (!ret) |
270 | ret = count; | |
271 | ||
b76cdba9 MW |
272 | return ret; |
273 | } | |
3d632c3f SH |
274 | static DEVICE_ATTR(xmit_hash_policy, S_IRUGO | S_IWUSR, |
275 | bonding_show_xmit_hash, bonding_store_xmit_hash); | |
b76cdba9 | 276 | |
f5b2b966 JV |
277 | /* |
278 | * Show and set arp_validate. | |
279 | */ | |
43cb76d9 GKH |
280 | static ssize_t bonding_show_arp_validate(struct device *d, |
281 | struct device_attribute *attr, | |
282 | char *buf) | |
f5b2b966 | 283 | { |
43cb76d9 | 284 | struct bonding *bond = to_bond(d); |
f3253339 | 285 | const struct bond_opt_value *val; |
16228881 NA |
286 | |
287 | val = bond_opt_get_val(BOND_OPT_ARP_VALIDATE, | |
288 | bond->params.arp_validate); | |
f5b2b966 | 289 | |
16228881 | 290 | return sprintf(buf, "%s %d\n", val->string, bond->params.arp_validate); |
f5b2b966 JV |
291 | } |
292 | ||
43cb76d9 GKH |
293 | static ssize_t bonding_store_arp_validate(struct device *d, |
294 | struct device_attribute *attr, | |
295 | const char *buf, size_t count) | |
f5b2b966 | 296 | { |
43cb76d9 | 297 | struct bonding *bond = to_bond(d); |
16228881 | 298 | int ret; |
29c49482 | 299 | |
16228881 | 300 | ret = bond_opt_tryset_rtnl(bond, BOND_OPT_ARP_VALIDATE, (char *)buf); |
29c49482 | 301 | if (!ret) |
302 | ret = count; | |
303 | ||
5c5038dc | 304 | return ret; |
f5b2b966 JV |
305 | } |
306 | ||
3d632c3f SH |
307 | static DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_validate, |
308 | bonding_store_arp_validate); | |
8599b52e VF |
309 | /* |
310 | * Show and set arp_all_targets. | |
311 | */ | |
312 | static ssize_t bonding_show_arp_all_targets(struct device *d, | |
313 | struct device_attribute *attr, | |
314 | char *buf) | |
315 | { | |
316 | struct bonding *bond = to_bond(d); | |
f3253339 | 317 | const struct bond_opt_value *val; |
8599b52e | 318 | |
edf36b24 NA |
319 | val = bond_opt_get_val(BOND_OPT_ARP_ALL_TARGETS, |
320 | bond->params.arp_all_targets); | |
321 | return sprintf(buf, "%s %d\n", | |
322 | val->string, bond->params.arp_all_targets); | |
8599b52e VF |
323 | } |
324 | ||
325 | static ssize_t bonding_store_arp_all_targets(struct device *d, | |
326 | struct device_attribute *attr, | |
327 | const char *buf, size_t count) | |
328 | { | |
329 | struct bonding *bond = to_bond(d); | |
edf36b24 | 330 | int ret; |
8599b52e | 331 | |
edf36b24 | 332 | ret = bond_opt_tryset_rtnl(bond, BOND_OPT_ARP_ALL_TARGETS, (char *)buf); |
d5c84254 | 333 | if (!ret) |
334 | ret = count; | |
335 | ||
d5c84254 | 336 | return ret; |
8599b52e VF |
337 | } |
338 | ||
339 | static DEVICE_ATTR(arp_all_targets, S_IRUGO | S_IWUSR, | |
340 | bonding_show_arp_all_targets, bonding_store_arp_all_targets); | |
f5b2b966 | 341 | |
dd957c57 JV |
342 | /* |
343 | * Show and store fail_over_mac. User only allowed to change the | |
344 | * value when there are no slaves. | |
345 | */ | |
3d632c3f SH |
346 | static ssize_t bonding_show_fail_over_mac(struct device *d, |
347 | struct device_attribute *attr, | |
348 | char *buf) | |
dd957c57 JV |
349 | { |
350 | struct bonding *bond = to_bond(d); | |
f3253339 | 351 | const struct bond_opt_value *val; |
dd957c57 | 352 | |
1df6b6aa NA |
353 | val = bond_opt_get_val(BOND_OPT_FAIL_OVER_MAC, |
354 | bond->params.fail_over_mac); | |
355 | ||
356 | return sprintf(buf, "%s %d\n", val->string, bond->params.fail_over_mac); | |
dd957c57 JV |
357 | } |
358 | ||
3d632c3f SH |
359 | static ssize_t bonding_store_fail_over_mac(struct device *d, |
360 | struct device_attribute *attr, | |
361 | const char *buf, size_t count) | |
dd957c57 | 362 | { |
dd957c57 | 363 | struct bonding *bond = to_bond(d); |
1df6b6aa | 364 | int ret; |
dd957c57 | 365 | |
1df6b6aa | 366 | ret = bond_opt_tryset_rtnl(bond, BOND_OPT_FAIL_OVER_MAC, (char *)buf); |
89901972 | 367 | if (!ret) |
368 | ret = count; | |
3915c1e8 | 369 | |
9402b746 | 370 | return ret; |
dd957c57 JV |
371 | } |
372 | ||
3d632c3f SH |
373 | static DEVICE_ATTR(fail_over_mac, S_IRUGO | S_IWUSR, |
374 | bonding_show_fail_over_mac, bonding_store_fail_over_mac); | |
dd957c57 | 375 | |
b76cdba9 MW |
376 | /* |
377 | * Show and set the arp timer interval. There are two tricky bits | |
378 | * here. First, if ARP monitoring is activated, then we must disable | |
379 | * MII monitoring. Second, if the ARP timer isn't running, we must | |
380 | * start it. | |
381 | */ | |
43cb76d9 GKH |
382 | static ssize_t bonding_show_arp_interval(struct device *d, |
383 | struct device_attribute *attr, | |
384 | char *buf) | |
b76cdba9 | 385 | { |
43cb76d9 | 386 | struct bonding *bond = to_bond(d); |
b76cdba9 | 387 | |
7bd46508 | 388 | return sprintf(buf, "%d\n", bond->params.arp_interval); |
b76cdba9 MW |
389 | } |
390 | ||
43cb76d9 GKH |
391 | static ssize_t bonding_store_arp_interval(struct device *d, |
392 | struct device_attribute *attr, | |
393 | const char *buf, size_t count) | |
b76cdba9 | 394 | { |
43cb76d9 | 395 | struct bonding *bond = to_bond(d); |
7bdb04ed | 396 | int ret; |
06151dbc | 397 | |
7bdb04ed | 398 | ret = bond_opt_tryset_rtnl(bond, BOND_OPT_ARP_INTERVAL, (char *)buf); |
06151dbc | 399 | if (!ret) |
400 | ret = count; | |
401 | ||
b76cdba9 MW |
402 | return ret; |
403 | } | |
3d632c3f SH |
404 | static DEVICE_ATTR(arp_interval, S_IRUGO | S_IWUSR, |
405 | bonding_show_arp_interval, bonding_store_arp_interval); | |
b76cdba9 MW |
406 | |
407 | /* | |
408 | * Show and set the arp targets. | |
409 | */ | |
43cb76d9 GKH |
410 | static ssize_t bonding_show_arp_targets(struct device *d, |
411 | struct device_attribute *attr, | |
412 | char *buf) | |
b76cdba9 | 413 | { |
43cb76d9 | 414 | struct bonding *bond = to_bond(d); |
4fb0ef58 | 415 | int i, res = 0; |
b76cdba9 MW |
416 | |
417 | for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) { | |
418 | if (bond->params.arp_targets[i]) | |
63779436 HH |
419 | res += sprintf(buf + res, "%pI4 ", |
420 | &bond->params.arp_targets[i]); | |
b76cdba9 | 421 | } |
1dcdcd69 WF |
422 | if (res) |
423 | buf[res-1] = '\n'; /* eat the leftover space */ | |
4fb0ef58 | 424 | |
b76cdba9 MW |
425 | return res; |
426 | } | |
427 | ||
43cb76d9 GKH |
428 | static ssize_t bonding_store_arp_targets(struct device *d, |
429 | struct device_attribute *attr, | |
430 | const char *buf, size_t count) | |
b76cdba9 | 431 | { |
43cb76d9 | 432 | struct bonding *bond = to_bond(d); |
4fb0ef58 | 433 | int ret; |
b76cdba9 | 434 | |
4fb0ef58 | 435 | ret = bond_opt_tryset_rtnl(bond, BOND_OPT_ARP_TARGETS, (char *)buf); |
7f28fa10 | 436 | if (!ret) |
437 | ret = count; | |
438 | ||
b76cdba9 MW |
439 | return ret; |
440 | } | |
43cb76d9 | 441 | static DEVICE_ATTR(arp_ip_target, S_IRUGO | S_IWUSR , bonding_show_arp_targets, bonding_store_arp_targets); |
b76cdba9 MW |
442 | |
443 | /* | |
444 | * Show and set the up and down delays. These must be multiples of the | |
445 | * MII monitoring value, and are stored internally as the multiplier. | |
446 | * Thus, we must translate to MS for the real world. | |
447 | */ | |
43cb76d9 GKH |
448 | static ssize_t bonding_show_downdelay(struct device *d, |
449 | struct device_attribute *attr, | |
450 | char *buf) | |
b76cdba9 | 451 | { |
43cb76d9 | 452 | struct bonding *bond = to_bond(d); |
b76cdba9 | 453 | |
7bd46508 | 454 | return sprintf(buf, "%d\n", bond->params.downdelay * bond->params.miimon); |
b76cdba9 MW |
455 | } |
456 | ||
43cb76d9 GKH |
457 | static ssize_t bonding_store_downdelay(struct device *d, |
458 | struct device_attribute *attr, | |
459 | const char *buf, size_t count) | |
b76cdba9 | 460 | { |
43cb76d9 | 461 | struct bonding *bond = to_bond(d); |
25a9b54a | 462 | int ret; |
b76cdba9 | 463 | |
25a9b54a | 464 | ret = bond_opt_tryset_rtnl(bond, BOND_OPT_DOWNDELAY, (char *)buf); |
c7461f9b | 465 | if (!ret) |
466 | ret = count; | |
b76cdba9 | 467 | |
b76cdba9 MW |
468 | return ret; |
469 | } | |
3d632c3f SH |
470 | static DEVICE_ATTR(downdelay, S_IRUGO | S_IWUSR, |
471 | bonding_show_downdelay, bonding_store_downdelay); | |
b76cdba9 | 472 | |
43cb76d9 GKH |
473 | static ssize_t bonding_show_updelay(struct device *d, |
474 | struct device_attribute *attr, | |
475 | char *buf) | |
b76cdba9 | 476 | { |
43cb76d9 | 477 | struct bonding *bond = to_bond(d); |
b76cdba9 | 478 | |
7bd46508 | 479 | return sprintf(buf, "%d\n", bond->params.updelay * bond->params.miimon); |
b76cdba9 MW |
480 | |
481 | } | |
482 | ||
43cb76d9 GKH |
483 | static ssize_t bonding_store_updelay(struct device *d, |
484 | struct device_attribute *attr, | |
485 | const char *buf, size_t count) | |
b76cdba9 | 486 | { |
43cb76d9 | 487 | struct bonding *bond = to_bond(d); |
e4994612 | 488 | int ret; |
b76cdba9 | 489 | |
e4994612 | 490 | ret = bond_opt_tryset_rtnl(bond, BOND_OPT_UPDELAY, (char *)buf); |
25852e29 | 491 | if (!ret) |
492 | ret = count; | |
493 | ||
b76cdba9 MW |
494 | return ret; |
495 | } | |
3d632c3f SH |
496 | static DEVICE_ATTR(updelay, S_IRUGO | S_IWUSR, |
497 | bonding_show_updelay, bonding_store_updelay); | |
b76cdba9 MW |
498 | |
499 | /* | |
500 | * Show and set the LACP interval. Interface must be down, and the mode | |
501 | * must be set to 802.3ad mode. | |
502 | */ | |
43cb76d9 GKH |
503 | static ssize_t bonding_show_lacp(struct device *d, |
504 | struct device_attribute *attr, | |
505 | char *buf) | |
b76cdba9 | 506 | { |
43cb76d9 | 507 | struct bonding *bond = to_bond(d); |
f3253339 | 508 | const struct bond_opt_value *val; |
b76cdba9 | 509 | |
d3131de7 NA |
510 | val = bond_opt_get_val(BOND_OPT_LACP_RATE, bond->params.lacp_fast); |
511 | ||
512 | return sprintf(buf, "%s %d\n", val->string, bond->params.lacp_fast); | |
b76cdba9 MW |
513 | } |
514 | ||
43cb76d9 GKH |
515 | static ssize_t bonding_store_lacp(struct device *d, |
516 | struct device_attribute *attr, | |
517 | const char *buf, size_t count) | |
b76cdba9 | 518 | { |
43cb76d9 | 519 | struct bonding *bond = to_bond(d); |
d3131de7 | 520 | int ret; |
998e40bb | 521 | |
d3131de7 | 522 | ret = bond_opt_tryset_rtnl(bond, BOND_OPT_LACP_RATE, (char *)buf); |
998e40bb | 523 | if (!ret) |
524 | ret = count; | |
525 | ||
b76cdba9 MW |
526 | return ret; |
527 | } | |
3d632c3f SH |
528 | static DEVICE_ATTR(lacp_rate, S_IRUGO | S_IWUSR, |
529 | bonding_show_lacp, bonding_store_lacp); | |
b76cdba9 | 530 | |
655f8919 | 531 | static ssize_t bonding_show_min_links(struct device *d, |
532 | struct device_attribute *attr, | |
533 | char *buf) | |
534 | { | |
535 | struct bonding *bond = to_bond(d); | |
536 | ||
537 | return sprintf(buf, "%d\n", bond->params.min_links); | |
538 | } | |
539 | ||
540 | static ssize_t bonding_store_min_links(struct device *d, | |
541 | struct device_attribute *attr, | |
542 | const char *buf, size_t count) | |
543 | { | |
544 | struct bonding *bond = to_bond(d); | |
545 | int ret; | |
655f8919 | 546 | |
633ddc9e | 547 | ret = bond_opt_tryset_rtnl(bond, BOND_OPT_MINLINKS, (char *)buf); |
7d101008 | 548 | if (!ret) |
549 | ret = count; | |
550 | ||
7d101008 | 551 | return ret; |
655f8919 | 552 | } |
553 | static DEVICE_ATTR(min_links, S_IRUGO | S_IWUSR, | |
554 | bonding_show_min_links, bonding_store_min_links); | |
555 | ||
fd989c83 JV |
556 | static ssize_t bonding_show_ad_select(struct device *d, |
557 | struct device_attribute *attr, | |
558 | char *buf) | |
559 | { | |
560 | struct bonding *bond = to_bond(d); | |
f3253339 | 561 | const struct bond_opt_value *val; |
fd989c83 | 562 | |
9e5f5eeb NA |
563 | val = bond_opt_get_val(BOND_OPT_AD_SELECT, bond->params.ad_select); |
564 | ||
565 | return sprintf(buf, "%s %d\n", val->string, bond->params.ad_select); | |
fd989c83 JV |
566 | } |
567 | ||
568 | ||
569 | static ssize_t bonding_store_ad_select(struct device *d, | |
570 | struct device_attribute *attr, | |
571 | const char *buf, size_t count) | |
572 | { | |
fd989c83 | 573 | struct bonding *bond = to_bond(d); |
9e5f5eeb | 574 | int ret; |
fd989c83 | 575 | |
9e5f5eeb | 576 | ret = bond_opt_tryset_rtnl(bond, BOND_OPT_AD_SELECT, (char *)buf); |
ec029fac | 577 | if (!ret) |
578 | ret = count; | |
579 | ||
fd989c83 JV |
580 | return ret; |
581 | } | |
3d632c3f SH |
582 | static DEVICE_ATTR(ad_select, S_IRUGO | S_IWUSR, |
583 | bonding_show_ad_select, bonding_store_ad_select); | |
fd989c83 | 584 | |
ad246c99 BH |
585 | /* |
586 | * Show and set the number of peer notifications to send after a failover event. | |
587 | */ | |
588 | static ssize_t bonding_show_num_peer_notif(struct device *d, | |
589 | struct device_attribute *attr, | |
590 | char *buf) | |
591 | { | |
592 | struct bonding *bond = to_bond(d); | |
593 | return sprintf(buf, "%d\n", bond->params.num_peer_notif); | |
594 | } | |
595 | ||
596 | static ssize_t bonding_store_num_peer_notif(struct device *d, | |
597 | struct device_attribute *attr, | |
598 | const char *buf, size_t count) | |
599 | { | |
600 | struct bonding *bond = to_bond(d); | |
2c9839c1 | 601 | int ret; |
602 | ||
ef56becb | 603 | ret = bond_opt_tryset_rtnl(bond, BOND_OPT_NUM_PEER_NOTIF, (char *)buf); |
2c9839c1 | 604 | if (!ret) |
605 | ret = count; | |
606 | ||
2c9839c1 | 607 | return ret; |
ad246c99 BH |
608 | } |
609 | static DEVICE_ATTR(num_grat_arp, S_IRUGO | S_IWUSR, | |
610 | bonding_show_num_peer_notif, bonding_store_num_peer_notif); | |
611 | static DEVICE_ATTR(num_unsol_na, S_IRUGO | S_IWUSR, | |
612 | bonding_show_num_peer_notif, bonding_store_num_peer_notif); | |
613 | ||
b76cdba9 MW |
614 | /* |
615 | * Show and set the MII monitor interval. There are two tricky bits | |
616 | * here. First, if MII monitoring is activated, then we must disable | |
617 | * ARP monitoring. Second, if the timer isn't running, we must | |
618 | * start it. | |
619 | */ | |
43cb76d9 GKH |
620 | static ssize_t bonding_show_miimon(struct device *d, |
621 | struct device_attribute *attr, | |
622 | char *buf) | |
b76cdba9 | 623 | { |
43cb76d9 | 624 | struct bonding *bond = to_bond(d); |
b76cdba9 | 625 | |
7bd46508 | 626 | return sprintf(buf, "%d\n", bond->params.miimon); |
b76cdba9 MW |
627 | } |
628 | ||
43cb76d9 GKH |
629 | static ssize_t bonding_store_miimon(struct device *d, |
630 | struct device_attribute *attr, | |
631 | const char *buf, size_t count) | |
b76cdba9 | 632 | { |
43cb76d9 | 633 | struct bonding *bond = to_bond(d); |
b98d9c66 | 634 | int ret; |
b76cdba9 | 635 | |
b98d9c66 | 636 | ret = bond_opt_tryset_rtnl(bond, BOND_OPT_MIIMON, (char *)buf); |
eecdaa6e | 637 | if (!ret) |
638 | ret = count; | |
639 | ||
b76cdba9 MW |
640 | return ret; |
641 | } | |
3d632c3f SH |
642 | static DEVICE_ATTR(miimon, S_IRUGO | S_IWUSR, |
643 | bonding_show_miimon, bonding_store_miimon); | |
b76cdba9 MW |
644 | |
645 | /* | |
646 | * Show and set the primary slave. The store function is much | |
647 | * simpler than bonding_store_slaves function because it only needs to | |
648 | * handle one interface name. | |
649 | * The bond must be a mode that supports a primary for this be | |
650 | * set. | |
651 | */ | |
43cb76d9 GKH |
652 | static ssize_t bonding_show_primary(struct device *d, |
653 | struct device_attribute *attr, | |
654 | char *buf) | |
b76cdba9 MW |
655 | { |
656 | int count = 0; | |
43cb76d9 | 657 | struct bonding *bond = to_bond(d); |
b76cdba9 MW |
658 | |
659 | if (bond->primary_slave) | |
7bd46508 | 660 | count = sprintf(buf, "%s\n", bond->primary_slave->dev->name); |
b76cdba9 MW |
661 | |
662 | return count; | |
663 | } | |
664 | ||
43cb76d9 GKH |
665 | static ssize_t bonding_store_primary(struct device *d, |
666 | struct device_attribute *attr, | |
667 | const char *buf, size_t count) | |
b76cdba9 | 668 | { |
43cb76d9 | 669 | struct bonding *bond = to_bond(d); |
0a98a0d1 | 670 | int ret; |
b76cdba9 | 671 | |
180222f0 | 672 | ret = bond_opt_tryset_rtnl(bond, BOND_OPT_PRIMARY, (char *)buf); |
0a98a0d1 | 673 | if (!ret) |
674 | ret = count; | |
8a93664d | 675 | |
0a98a0d1 | 676 | return ret; |
b76cdba9 | 677 | } |
3d632c3f SH |
678 | static DEVICE_ATTR(primary, S_IRUGO | S_IWUSR, |
679 | bonding_show_primary, bonding_store_primary); | |
b76cdba9 | 680 | |
a549952a JP |
681 | /* |
682 | * Show and set the primary_reselect flag. | |
683 | */ | |
684 | static ssize_t bonding_show_primary_reselect(struct device *d, | |
685 | struct device_attribute *attr, | |
686 | char *buf) | |
687 | { | |
688 | struct bonding *bond = to_bond(d); | |
f3253339 | 689 | const struct bond_opt_value *val; |
388d3a6d NA |
690 | |
691 | val = bond_opt_get_val(BOND_OPT_PRIMARY_RESELECT, | |
692 | bond->params.primary_reselect); | |
a549952a JP |
693 | |
694 | return sprintf(buf, "%s %d\n", | |
388d3a6d | 695 | val->string, bond->params.primary_reselect); |
a549952a JP |
696 | } |
697 | ||
698 | static ssize_t bonding_store_primary_reselect(struct device *d, | |
699 | struct device_attribute *attr, | |
700 | const char *buf, size_t count) | |
701 | { | |
a549952a | 702 | struct bonding *bond = to_bond(d); |
388d3a6d | 703 | int ret; |
a549952a | 704 | |
388d3a6d NA |
705 | ret = bond_opt_tryset_rtnl(bond, BOND_OPT_PRIMARY_RESELECT, |
706 | (char *)buf); | |
8a41ae44 | 707 | if (!ret) |
708 | ret = count; | |
a549952a | 709 | |
a549952a JP |
710 | return ret; |
711 | } | |
712 | static DEVICE_ATTR(primary_reselect, S_IRUGO | S_IWUSR, | |
713 | bonding_show_primary_reselect, | |
714 | bonding_store_primary_reselect); | |
715 | ||
b76cdba9 MW |
716 | /* |
717 | * Show and set the use_carrier flag. | |
718 | */ | |
43cb76d9 GKH |
719 | static ssize_t bonding_show_carrier(struct device *d, |
720 | struct device_attribute *attr, | |
721 | char *buf) | |
b76cdba9 | 722 | { |
43cb76d9 | 723 | struct bonding *bond = to_bond(d); |
b76cdba9 | 724 | |
7bd46508 | 725 | return sprintf(buf, "%d\n", bond->params.use_carrier); |
b76cdba9 MW |
726 | } |
727 | ||
43cb76d9 GKH |
728 | static ssize_t bonding_store_carrier(struct device *d, |
729 | struct device_attribute *attr, | |
730 | const char *buf, size_t count) | |
b76cdba9 | 731 | { |
43cb76d9 | 732 | struct bonding *bond = to_bond(d); |
0fff0608 | 733 | int ret; |
b76cdba9 | 734 | |
0fff0608 | 735 | ret = bond_opt_tryset_rtnl(bond, BOND_OPT_USE_CARRIER, (char *)buf); |
9f53e14e | 736 | if (!ret) |
737 | ret = count; | |
738 | ||
672bda33 | 739 | return ret; |
b76cdba9 | 740 | } |
3d632c3f SH |
741 | static DEVICE_ATTR(use_carrier, S_IRUGO | S_IWUSR, |
742 | bonding_show_carrier, bonding_store_carrier); | |
b76cdba9 MW |
743 | |
744 | ||
745 | /* | |
746 | * Show and set currently active_slave. | |
747 | */ | |
43cb76d9 GKH |
748 | static ssize_t bonding_show_active_slave(struct device *d, |
749 | struct device_attribute *attr, | |
750 | char *buf) | |
b76cdba9 | 751 | { |
43cb76d9 | 752 | struct bonding *bond = to_bond(d); |
752d48b5 | 753 | struct net_device *slave_dev; |
16cd0160 | 754 | int count = 0; |
b76cdba9 | 755 | |
278b2083 | 756 | rcu_read_lock(); |
752d48b5 JP |
757 | slave_dev = bond_option_active_slave_get_rcu(bond); |
758 | if (slave_dev) | |
759 | count = sprintf(buf, "%s\n", slave_dev->name); | |
278b2083 | 760 | rcu_read_unlock(); |
761 | ||
b76cdba9 MW |
762 | return count; |
763 | } | |
764 | ||
43cb76d9 GKH |
765 | static ssize_t bonding_store_active_slave(struct device *d, |
766 | struct device_attribute *attr, | |
767 | const char *buf, size_t count) | |
b76cdba9 | 768 | { |
43cb76d9 | 769 | struct bonding *bond = to_bond(d); |
d1fbd3ed | 770 | int ret; |
f4bb2e9c | 771 | |
d1fbd3ed | 772 | ret = bond_opt_tryset_rtnl(bond, BOND_OPT_ACTIVE_SLAVE, (char *)buf); |
d9e32b21 JP |
773 | if (!ret) |
774 | ret = count; | |
e843fa50 | 775 | |
d9e32b21 | 776 | return ret; |
b76cdba9 | 777 | } |
3d632c3f SH |
778 | static DEVICE_ATTR(active_slave, S_IRUGO | S_IWUSR, |
779 | bonding_show_active_slave, bonding_store_active_slave); | |
b76cdba9 MW |
780 | |
781 | ||
782 | /* | |
783 | * Show link status of the bond interface. | |
784 | */ | |
43cb76d9 GKH |
785 | static ssize_t bonding_show_mii_status(struct device *d, |
786 | struct device_attribute *attr, | |
787 | char *buf) | |
b76cdba9 | 788 | { |
43cb76d9 | 789 | struct bonding *bond = to_bond(d); |
b76cdba9 | 790 | |
278b2083 | 791 | return sprintf(buf, "%s\n", bond->curr_active_slave ? "up" : "down"); |
b76cdba9 | 792 | } |
43cb76d9 | 793 | static DEVICE_ATTR(mii_status, S_IRUGO, bonding_show_mii_status, NULL); |
b76cdba9 | 794 | |
b76cdba9 MW |
795 | /* |
796 | * Show current 802.3ad aggregator ID. | |
797 | */ | |
43cb76d9 GKH |
798 | static ssize_t bonding_show_ad_aggregator(struct device *d, |
799 | struct device_attribute *attr, | |
800 | char *buf) | |
b76cdba9 MW |
801 | { |
802 | int count = 0; | |
43cb76d9 | 803 | struct bonding *bond = to_bond(d); |
b76cdba9 MW |
804 | |
805 | if (bond->params.mode == BOND_MODE_8023AD) { | |
806 | struct ad_info ad_info; | |
3d632c3f | 807 | count = sprintf(buf, "%d\n", |
318debd8 | 808 | bond_3ad_get_active_agg_info(bond, &ad_info) |
3d632c3f | 809 | ? 0 : ad_info.aggregator_id); |
b76cdba9 | 810 | } |
b76cdba9 MW |
811 | |
812 | return count; | |
813 | } | |
43cb76d9 | 814 | static DEVICE_ATTR(ad_aggregator, S_IRUGO, bonding_show_ad_aggregator, NULL); |
b76cdba9 MW |
815 | |
816 | ||
817 | /* | |
818 | * Show number of active 802.3ad ports. | |
819 | */ | |
43cb76d9 GKH |
820 | static ssize_t bonding_show_ad_num_ports(struct device *d, |
821 | struct device_attribute *attr, | |
822 | char *buf) | |
b76cdba9 MW |
823 | { |
824 | int count = 0; | |
43cb76d9 | 825 | struct bonding *bond = to_bond(d); |
b76cdba9 MW |
826 | |
827 | if (bond->params.mode == BOND_MODE_8023AD) { | |
828 | struct ad_info ad_info; | |
3d632c3f | 829 | count = sprintf(buf, "%d\n", |
318debd8 | 830 | bond_3ad_get_active_agg_info(bond, &ad_info) |
3d632c3f | 831 | ? 0 : ad_info.ports); |
b76cdba9 | 832 | } |
b76cdba9 MW |
833 | |
834 | return count; | |
835 | } | |
43cb76d9 | 836 | static DEVICE_ATTR(ad_num_ports, S_IRUGO, bonding_show_ad_num_ports, NULL); |
b76cdba9 MW |
837 | |
838 | ||
839 | /* | |
840 | * Show current 802.3ad actor key. | |
841 | */ | |
43cb76d9 GKH |
842 | static ssize_t bonding_show_ad_actor_key(struct device *d, |
843 | struct device_attribute *attr, | |
844 | char *buf) | |
b76cdba9 MW |
845 | { |
846 | int count = 0; | |
43cb76d9 | 847 | struct bonding *bond = to_bond(d); |
b76cdba9 MW |
848 | |
849 | if (bond->params.mode == BOND_MODE_8023AD) { | |
850 | struct ad_info ad_info; | |
3d632c3f | 851 | count = sprintf(buf, "%d\n", |
318debd8 | 852 | bond_3ad_get_active_agg_info(bond, &ad_info) |
3d632c3f | 853 | ? 0 : ad_info.actor_key); |
b76cdba9 | 854 | } |
b76cdba9 MW |
855 | |
856 | return count; | |
857 | } | |
43cb76d9 | 858 | static DEVICE_ATTR(ad_actor_key, S_IRUGO, bonding_show_ad_actor_key, NULL); |
b76cdba9 MW |
859 | |
860 | ||
861 | /* | |
862 | * Show current 802.3ad partner key. | |
863 | */ | |
43cb76d9 GKH |
864 | static ssize_t bonding_show_ad_partner_key(struct device *d, |
865 | struct device_attribute *attr, | |
866 | char *buf) | |
b76cdba9 MW |
867 | { |
868 | int count = 0; | |
43cb76d9 | 869 | struct bonding *bond = to_bond(d); |
b76cdba9 MW |
870 | |
871 | if (bond->params.mode == BOND_MODE_8023AD) { | |
872 | struct ad_info ad_info; | |
3d632c3f | 873 | count = sprintf(buf, "%d\n", |
318debd8 | 874 | bond_3ad_get_active_agg_info(bond, &ad_info) |
3d632c3f | 875 | ? 0 : ad_info.partner_key); |
b76cdba9 | 876 | } |
b76cdba9 MW |
877 | |
878 | return count; | |
879 | } | |
43cb76d9 | 880 | static DEVICE_ATTR(ad_partner_key, S_IRUGO, bonding_show_ad_partner_key, NULL); |
b76cdba9 MW |
881 | |
882 | ||
883 | /* | |
884 | * Show current 802.3ad partner mac. | |
885 | */ | |
43cb76d9 GKH |
886 | static ssize_t bonding_show_ad_partner_mac(struct device *d, |
887 | struct device_attribute *attr, | |
888 | char *buf) | |
b76cdba9 MW |
889 | { |
890 | int count = 0; | |
43cb76d9 | 891 | struct bonding *bond = to_bond(d); |
b76cdba9 MW |
892 | |
893 | if (bond->params.mode == BOND_MODE_8023AD) { | |
894 | struct ad_info ad_info; | |
3d632c3f | 895 | if (!bond_3ad_get_active_agg_info(bond, &ad_info)) |
e174961c | 896 | count = sprintf(buf, "%pM\n", ad_info.partner_system); |
b76cdba9 | 897 | } |
b76cdba9 MW |
898 | |
899 | return count; | |
900 | } | |
43cb76d9 | 901 | static DEVICE_ATTR(ad_partner_mac, S_IRUGO, bonding_show_ad_partner_mac, NULL); |
b76cdba9 | 902 | |
bb1d9123 AG |
903 | /* |
904 | * Show the queue_ids of the slaves in the current bond. | |
905 | */ | |
906 | static ssize_t bonding_show_queue_id(struct device *d, | |
907 | struct device_attribute *attr, | |
908 | char *buf) | |
909 | { | |
bb1d9123 | 910 | struct bonding *bond = to_bond(d); |
9caff1e7 | 911 | struct list_head *iter; |
dec1e90e | 912 | struct slave *slave; |
913 | int res = 0; | |
bb1d9123 AG |
914 | |
915 | if (!rtnl_trylock()) | |
916 | return restart_syscall(); | |
917 | ||
9caff1e7 | 918 | bond_for_each_slave(bond, slave, iter) { |
79236680 NP |
919 | if (res > (PAGE_SIZE - IFNAMSIZ - 6)) { |
920 | /* not enough space for another interface_name:queue_id pair */ | |
bb1d9123 AG |
921 | if ((PAGE_SIZE - res) > 10) |
922 | res = PAGE_SIZE - 10; | |
923 | res += sprintf(buf + res, "++more++ "); | |
924 | break; | |
925 | } | |
926 | res += sprintf(buf + res, "%s:%d ", | |
927 | slave->dev->name, slave->queue_id); | |
928 | } | |
bb1d9123 AG |
929 | if (res) |
930 | buf[res-1] = '\n'; /* eat the leftover space */ | |
4d1ae5fb | 931 | |
bb1d9123 | 932 | rtnl_unlock(); |
dec1e90e | 933 | |
bb1d9123 AG |
934 | return res; |
935 | } | |
936 | ||
937 | /* | |
938 | * Set the queue_ids of the slaves in the current bond. The bond | |
939 | * interface must be enslaved for this to work. | |
940 | */ | |
941 | static ssize_t bonding_store_queue_id(struct device *d, | |
942 | struct device_attribute *attr, | |
943 | const char *buffer, size_t count) | |
944 | { | |
bb1d9123 | 945 | struct bonding *bond = to_bond(d); |
24089ba1 | 946 | int ret; |
bb1d9123 | 947 | |
24089ba1 NA |
948 | ret = bond_opt_tryset_rtnl(bond, BOND_OPT_QUEUE_ID, (char *)buffer); |
949 | if (!ret) | |
950 | ret = count; | |
bb1d9123 | 951 | |
bb1d9123 | 952 | return ret; |
bb1d9123 | 953 | } |
bb1d9123 AG |
954 | static DEVICE_ATTR(queue_id, S_IRUGO | S_IWUSR, bonding_show_queue_id, |
955 | bonding_store_queue_id); | |
956 | ||
957 | ||
ebd8e497 AG |
958 | /* |
959 | * Show and set the all_slaves_active flag. | |
960 | */ | |
961 | static ssize_t bonding_show_slaves_active(struct device *d, | |
962 | struct device_attribute *attr, | |
963 | char *buf) | |
964 | { | |
965 | struct bonding *bond = to_bond(d); | |
966 | ||
967 | return sprintf(buf, "%d\n", bond->params.all_slaves_active); | |
968 | } | |
969 | ||
970 | static ssize_t bonding_store_slaves_active(struct device *d, | |
971 | struct device_attribute *attr, | |
972 | const char *buf, size_t count) | |
973 | { | |
ebd8e497 | 974 | struct bonding *bond = to_bond(d); |
3df01162 | 975 | int ret; |
ebd8e497 | 976 | |
3df01162 NA |
977 | ret = bond_opt_tryset_rtnl(bond, BOND_OPT_ALL_SLAVES_ACTIVE, |
978 | (char *)buf); | |
1cc0b1e3 | 979 | if (!ret) |
980 | ret = count; | |
b76cdba9 | 981 | |
672bda33 | 982 | return ret; |
ebd8e497 AG |
983 | } |
984 | static DEVICE_ATTR(all_slaves_active, S_IRUGO | S_IWUSR, | |
985 | bonding_show_slaves_active, bonding_store_slaves_active); | |
b76cdba9 | 986 | |
c2952c31 FL |
987 | /* |
988 | * Show and set the number of IGMP membership reports to send on link failure | |
989 | */ | |
990 | static ssize_t bonding_show_resend_igmp(struct device *d, | |
94265cf5 FL |
991 | struct device_attribute *attr, |
992 | char *buf) | |
c2952c31 FL |
993 | { |
994 | struct bonding *bond = to_bond(d); | |
995 | ||
996 | return sprintf(buf, "%d\n", bond->params.resend_igmp); | |
997 | } | |
998 | ||
999 | static ssize_t bonding_store_resend_igmp(struct device *d, | |
94265cf5 FL |
1000 | struct device_attribute *attr, |
1001 | const char *buf, size_t count) | |
c2952c31 | 1002 | { |
c2952c31 | 1003 | struct bonding *bond = to_bond(d); |
105c8fb6 | 1004 | int ret; |
c2952c31 | 1005 | |
105c8fb6 | 1006 | ret = bond_opt_tryset_rtnl(bond, BOND_OPT_RESEND_IGMP, (char *)buf); |
d8838de7 | 1007 | if (!ret) |
1008 | ret = count; | |
1009 | ||
c2952c31 FL |
1010 | return ret; |
1011 | } | |
1012 | ||
1013 | static DEVICE_ATTR(resend_igmp, S_IRUGO | S_IWUSR, | |
1014 | bonding_show_resend_igmp, bonding_store_resend_igmp); | |
1015 | ||
7eacd038 NH |
1016 | |
1017 | static ssize_t bonding_show_lp_interval(struct device *d, | |
1018 | struct device_attribute *attr, | |
1019 | char *buf) | |
1020 | { | |
1021 | struct bonding *bond = to_bond(d); | |
1022 | return sprintf(buf, "%d\n", bond->params.lp_interval); | |
1023 | } | |
1024 | ||
1025 | static ssize_t bonding_store_lp_interval(struct device *d, | |
1026 | struct device_attribute *attr, | |
1027 | const char *buf, size_t count) | |
1028 | { | |
1029 | struct bonding *bond = to_bond(d); | |
4325b374 | 1030 | int ret; |
7eacd038 | 1031 | |
4325b374 | 1032 | ret = bond_opt_tryset_rtnl(bond, BOND_OPT_LP_INTERVAL, (char *)buf); |
8d836d09 | 1033 | if (!ret) |
1034 | ret = count; | |
1035 | ||
7eacd038 NH |
1036 | return ret; |
1037 | } | |
1038 | ||
1039 | static DEVICE_ATTR(lp_interval, S_IRUGO | S_IWUSR, | |
1040 | bonding_show_lp_interval, bonding_store_lp_interval); | |
1041 | ||
e9f0fb88 MB |
1042 | static ssize_t bonding_show_tlb_dynamic_lb(struct device *d, |
1043 | struct device_attribute *attr, | |
1044 | char *buf) | |
1045 | { | |
1046 | struct bonding *bond = to_bond(d); | |
1047 | return sprintf(buf, "%d\n", bond->params.tlb_dynamic_lb); | |
1048 | } | |
1049 | ||
1050 | static ssize_t bonding_store_tlb_dynamic_lb(struct device *d, | |
1051 | struct device_attribute *attr, | |
1052 | const char *buf, | |
1053 | size_t count) | |
1054 | { | |
1055 | struct bonding *bond = to_bond(d); | |
1056 | int ret; | |
1057 | ||
1058 | ret = bond_opt_tryset_rtnl(bond, BOND_OPT_TLB_DYNAMIC_LB, | |
1059 | (char *)buf); | |
1060 | if (!ret) | |
1061 | ret = count; | |
1062 | ||
1063 | return ret; | |
1064 | } | |
1065 | ||
1066 | static DEVICE_ATTR(tlb_dynamic_lb, S_IRUGO | S_IWUSR, | |
1067 | bonding_show_tlb_dynamic_lb, | |
1068 | bonding_store_tlb_dynamic_lb); | |
1069 | ||
73958329 NA |
1070 | static ssize_t bonding_show_packets_per_slave(struct device *d, |
1071 | struct device_attribute *attr, | |
1072 | char *buf) | |
1073 | { | |
1074 | struct bonding *bond = to_bond(d); | |
a752a8b9 | 1075 | unsigned int packets_per_slave = bond->params.packets_per_slave; |
a752a8b9 | 1076 | return sprintf(buf, "%u\n", packets_per_slave); |
73958329 NA |
1077 | } |
1078 | ||
1079 | static ssize_t bonding_store_packets_per_slave(struct device *d, | |
1080 | struct device_attribute *attr, | |
1081 | const char *buf, size_t count) | |
1082 | { | |
1083 | struct bonding *bond = to_bond(d); | |
aa59d851 | 1084 | int ret; |
c13ab3ff | 1085 | |
aa59d851 NA |
1086 | ret = bond_opt_tryset_rtnl(bond, BOND_OPT_PACKETS_PER_SLAVE, |
1087 | (char *)buf); | |
c13ab3ff | 1088 | if (!ret) |
1089 | ret = count; | |
1090 | ||
73958329 NA |
1091 | return ret; |
1092 | } | |
1093 | ||
1094 | static DEVICE_ATTR(packets_per_slave, S_IRUGO | S_IWUSR, | |
1095 | bonding_show_packets_per_slave, | |
1096 | bonding_store_packets_per_slave); | |
1097 | ||
b76cdba9 | 1098 | static struct attribute *per_bond_attrs[] = { |
43cb76d9 GKH |
1099 | &dev_attr_slaves.attr, |
1100 | &dev_attr_mode.attr, | |
dd957c57 | 1101 | &dev_attr_fail_over_mac.attr, |
43cb76d9 | 1102 | &dev_attr_arp_validate.attr, |
8599b52e | 1103 | &dev_attr_arp_all_targets.attr, |
43cb76d9 GKH |
1104 | &dev_attr_arp_interval.attr, |
1105 | &dev_attr_arp_ip_target.attr, | |
1106 | &dev_attr_downdelay.attr, | |
1107 | &dev_attr_updelay.attr, | |
1108 | &dev_attr_lacp_rate.attr, | |
fd989c83 | 1109 | &dev_attr_ad_select.attr, |
43cb76d9 | 1110 | &dev_attr_xmit_hash_policy.attr, |
ad246c99 BH |
1111 | &dev_attr_num_grat_arp.attr, |
1112 | &dev_attr_num_unsol_na.attr, | |
43cb76d9 GKH |
1113 | &dev_attr_miimon.attr, |
1114 | &dev_attr_primary.attr, | |
a549952a | 1115 | &dev_attr_primary_reselect.attr, |
43cb76d9 GKH |
1116 | &dev_attr_use_carrier.attr, |
1117 | &dev_attr_active_slave.attr, | |
1118 | &dev_attr_mii_status.attr, | |
1119 | &dev_attr_ad_aggregator.attr, | |
1120 | &dev_attr_ad_num_ports.attr, | |
1121 | &dev_attr_ad_actor_key.attr, | |
1122 | &dev_attr_ad_partner_key.attr, | |
1123 | &dev_attr_ad_partner_mac.attr, | |
bb1d9123 | 1124 | &dev_attr_queue_id.attr, |
ebd8e497 | 1125 | &dev_attr_all_slaves_active.attr, |
c2952c31 | 1126 | &dev_attr_resend_igmp.attr, |
655f8919 | 1127 | &dev_attr_min_links.attr, |
7eacd038 | 1128 | &dev_attr_lp_interval.attr, |
73958329 | 1129 | &dev_attr_packets_per_slave.attr, |
e9f0fb88 | 1130 | &dev_attr_tlb_dynamic_lb.attr, |
b76cdba9 MW |
1131 | NULL, |
1132 | }; | |
1133 | ||
1134 | static struct attribute_group bonding_group = { | |
1135 | .name = "bonding", | |
1136 | .attrs = per_bond_attrs, | |
1137 | }; | |
1138 | ||
1139 | /* | |
1140 | * Initialize sysfs. This sets up the bonding_masters file in | |
1141 | * /sys/class/net. | |
1142 | */ | |
4c22400a | 1143 | int bond_create_sysfs(struct bond_net *bn) |
b76cdba9 | 1144 | { |
b8a9787e | 1145 | int ret; |
b76cdba9 | 1146 | |
4c22400a | 1147 | bn->class_attr_bonding_masters = class_attr_bonding_masters; |
01718e36 | 1148 | sysfs_attr_init(&bn->class_attr_bonding_masters.attr); |
4c22400a | 1149 | |
58292cbe TH |
1150 | ret = netdev_class_create_file_ns(&bn->class_attr_bonding_masters, |
1151 | bn->net); | |
877cbd36 JV |
1152 | /* |
1153 | * Permit multiple loads of the module by ignoring failures to | |
1154 | * create the bonding_masters sysfs file. Bonding devices | |
1155 | * created by second or subsequent loads of the module will | |
1156 | * not be listed in, or controllable by, bonding_masters, but | |
1157 | * will have the usual "bonding" sysfs directory. | |
1158 | * | |
1159 | * This is done to preserve backwards compatibility for | |
1160 | * initscripts/sysconfig, which load bonding multiple times to | |
1161 | * configure multiple bonding devices. | |
1162 | */ | |
1163 | if (ret == -EEXIST) { | |
38d2f38b | 1164 | /* Is someone being kinky and naming a device bonding_master? */ |
4c22400a | 1165 | if (__dev_get_by_name(bn->net, |
38d2f38b | 1166 | class_attr_bonding_masters.attr.name)) |
90194264 | 1167 | pr_err("network device named %s already exists in sysfs\n", |
38d2f38b | 1168 | class_attr_bonding_masters.attr.name); |
130aa61a | 1169 | ret = 0; |
877cbd36 | 1170 | } |
b76cdba9 MW |
1171 | |
1172 | return ret; | |
1173 | ||
1174 | } | |
1175 | ||
1176 | /* | |
1177 | * Remove /sys/class/net/bonding_masters. | |
1178 | */ | |
4c22400a | 1179 | void bond_destroy_sysfs(struct bond_net *bn) |
b76cdba9 | 1180 | { |
58292cbe | 1181 | netdev_class_remove_file_ns(&bn->class_attr_bonding_masters, bn->net); |
b76cdba9 MW |
1182 | } |
1183 | ||
1184 | /* | |
1185 | * Initialize sysfs for each bond. This sets up and registers | |
1186 | * the 'bondctl' directory for each individual bond under /sys/class/net. | |
1187 | */ | |
6151b3d4 | 1188 | void bond_prepare_sysfs_group(struct bonding *bond) |
b76cdba9 | 1189 | { |
6151b3d4 | 1190 | bond->dev->sysfs_groups[0] = &bonding_group; |
b76cdba9 MW |
1191 | } |
1192 |