diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /net/bridge/br_sysfs_br.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'net/bridge/br_sysfs_br.c')
-rw-r--r-- | net/bridge/br_sysfs_br.c | 364 |
1 files changed, 364 insertions, 0 deletions
diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c new file mode 100644 index 000000000000..98cf53c81fad --- /dev/null +++ b/net/bridge/br_sysfs_br.c | |||
@@ -0,0 +1,364 @@ | |||
1 | /* | ||
2 | * Sysfs attributes of bridge ports | ||
3 | * Linux ethernet bridge | ||
4 | * | ||
5 | * Authors: | ||
6 | * Stephen Hemminger <shemminger@osdl.org> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; either version | ||
11 | * 2 of the License, or (at your option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/netdevice.h> | ||
16 | #include <linux/if_bridge.h> | ||
17 | #include <linux/rtnetlink.h> | ||
18 | #include <linux/spinlock.h> | ||
19 | #include <linux/times.h> | ||
20 | |||
21 | #include "br_private.h" | ||
22 | |||
23 | #define to_class_dev(obj) container_of(obj,struct class_device,kobj) | ||
24 | #define to_net_dev(class) container_of(class, struct net_device, class_dev) | ||
25 | #define to_bridge(cd) ((struct net_bridge *)(to_net_dev(cd)->priv)) | ||
26 | |||
27 | /* | ||
28 | * Common code for storing bridge parameters. | ||
29 | */ | ||
30 | static ssize_t store_bridge_parm(struct class_device *cd, | ||
31 | const char *buf, size_t len, | ||
32 | void (*set)(struct net_bridge *, unsigned long)) | ||
33 | { | ||
34 | struct net_bridge *br = to_bridge(cd); | ||
35 | char *endp; | ||
36 | unsigned long val; | ||
37 | |||
38 | if (!capable(CAP_NET_ADMIN)) | ||
39 | return -EPERM; | ||
40 | |||
41 | val = simple_strtoul(buf, &endp, 0); | ||
42 | if (endp == buf) | ||
43 | return -EINVAL; | ||
44 | |||
45 | spin_lock_bh(&br->lock); | ||
46 | (*set)(br, val); | ||
47 | spin_unlock_bh(&br->lock); | ||
48 | return len; | ||
49 | } | ||
50 | |||
51 | |||
52 | static ssize_t show_forward_delay(struct class_device *cd, char *buf) | ||
53 | { | ||
54 | struct net_bridge *br = to_bridge(cd); | ||
55 | return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->forward_delay)); | ||
56 | } | ||
57 | |||
58 | static void set_forward_delay(struct net_bridge *br, unsigned long val) | ||
59 | { | ||
60 | unsigned long delay = clock_t_to_jiffies(val); | ||
61 | br->forward_delay = delay; | ||
62 | if (br_is_root_bridge(br)) | ||
63 | br->bridge_forward_delay = delay; | ||
64 | } | ||
65 | |||
66 | static ssize_t store_forward_delay(struct class_device *cd, const char *buf, | ||
67 | size_t len) | ||
68 | { | ||
69 | return store_bridge_parm(cd, buf, len, set_forward_delay); | ||
70 | } | ||
71 | static CLASS_DEVICE_ATTR(forward_delay, S_IRUGO | S_IWUSR, | ||
72 | show_forward_delay, store_forward_delay); | ||
73 | |||
74 | static ssize_t show_hello_time(struct class_device *cd, char *buf) | ||
75 | { | ||
76 | return sprintf(buf, "%lu\n", | ||
77 | jiffies_to_clock_t(to_bridge(cd)->hello_time)); | ||
78 | } | ||
79 | |||
80 | static void set_hello_time(struct net_bridge *br, unsigned long val) | ||
81 | { | ||
82 | unsigned long t = clock_t_to_jiffies(val); | ||
83 | br->hello_time = t; | ||
84 | if (br_is_root_bridge(br)) | ||
85 | br->bridge_hello_time = t; | ||
86 | } | ||
87 | |||
88 | static ssize_t store_hello_time(struct class_device *cd, const char *buf, | ||
89 | size_t len) | ||
90 | { | ||
91 | return store_bridge_parm(cd, buf, len, set_hello_time); | ||
92 | } | ||
93 | |||
94 | static CLASS_DEVICE_ATTR(hello_time, S_IRUGO | S_IWUSR, show_hello_time, | ||
95 | store_hello_time); | ||
96 | |||
97 | static ssize_t show_max_age(struct class_device *cd, char *buf) | ||
98 | { | ||
99 | return sprintf(buf, "%lu\n", | ||
100 | jiffies_to_clock_t(to_bridge(cd)->max_age)); | ||
101 | } | ||
102 | |||
103 | static void set_max_age(struct net_bridge *br, unsigned long val) | ||
104 | { | ||
105 | unsigned long t = clock_t_to_jiffies(val); | ||
106 | br->max_age = t; | ||
107 | if (br_is_root_bridge(br)) | ||
108 | br->bridge_max_age = t; | ||
109 | } | ||
110 | |||
111 | static ssize_t store_max_age(struct class_device *cd, const char *buf, | ||
112 | size_t len) | ||
113 | { | ||
114 | return store_bridge_parm(cd, buf, len, set_max_age); | ||
115 | } | ||
116 | |||
117 | static CLASS_DEVICE_ATTR(max_age, S_IRUGO | S_IWUSR, show_max_age, | ||
118 | store_max_age); | ||
119 | |||
120 | static ssize_t show_ageing_time(struct class_device *cd, char *buf) | ||
121 | { | ||
122 | struct net_bridge *br = to_bridge(cd); | ||
123 | return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->ageing_time)); | ||
124 | } | ||
125 | |||
126 | static void set_ageing_time(struct net_bridge *br, unsigned long val) | ||
127 | { | ||
128 | br->ageing_time = clock_t_to_jiffies(val); | ||
129 | } | ||
130 | |||
131 | static ssize_t store_ageing_time(struct class_device *cd, const char *buf, | ||
132 | size_t len) | ||
133 | { | ||
134 | return store_bridge_parm(cd, buf, len, set_ageing_time); | ||
135 | } | ||
136 | |||
137 | static CLASS_DEVICE_ATTR(ageing_time, S_IRUGO | S_IWUSR, show_ageing_time, | ||
138 | store_ageing_time); | ||
139 | static ssize_t show_stp_state(struct class_device *cd, char *buf) | ||
140 | { | ||
141 | struct net_bridge *br = to_bridge(cd); | ||
142 | return sprintf(buf, "%d\n", br->stp_enabled); | ||
143 | } | ||
144 | |||
145 | static void set_stp_state(struct net_bridge *br, unsigned long val) | ||
146 | { | ||
147 | br->stp_enabled = val; | ||
148 | } | ||
149 | |||
150 | static ssize_t store_stp_state(struct class_device *cd, | ||
151 | const char *buf, size_t len) | ||
152 | { | ||
153 | return store_bridge_parm(cd, buf, len, set_stp_state); | ||
154 | } | ||
155 | |||
156 | static CLASS_DEVICE_ATTR(stp_state, S_IRUGO | S_IWUSR, show_stp_state, | ||
157 | store_stp_state); | ||
158 | |||
159 | static ssize_t show_priority(struct class_device *cd, char *buf) | ||
160 | { | ||
161 | struct net_bridge *br = to_bridge(cd); | ||
162 | return sprintf(buf, "%d\n", | ||
163 | (br->bridge_id.prio[0] << 8) | br->bridge_id.prio[1]); | ||
164 | } | ||
165 | |||
166 | static void set_priority(struct net_bridge *br, unsigned long val) | ||
167 | { | ||
168 | br_stp_set_bridge_priority(br, (u16) val); | ||
169 | } | ||
170 | |||
171 | static ssize_t store_priority(struct class_device *cd, | ||
172 | const char *buf, size_t len) | ||
173 | { | ||
174 | return store_bridge_parm(cd, buf, len, set_priority); | ||
175 | } | ||
176 | static CLASS_DEVICE_ATTR(priority, S_IRUGO | S_IWUSR, show_priority, | ||
177 | store_priority); | ||
178 | |||
179 | static ssize_t show_root_id(struct class_device *cd, char *buf) | ||
180 | { | ||
181 | return br_show_bridge_id(buf, &to_bridge(cd)->designated_root); | ||
182 | } | ||
183 | static CLASS_DEVICE_ATTR(root_id, S_IRUGO, show_root_id, NULL); | ||
184 | |||
185 | static ssize_t show_bridge_id(struct class_device *cd, char *buf) | ||
186 | { | ||
187 | return br_show_bridge_id(buf, &to_bridge(cd)->bridge_id); | ||
188 | } | ||
189 | static CLASS_DEVICE_ATTR(bridge_id, S_IRUGO, show_bridge_id, NULL); | ||
190 | |||
191 | static ssize_t show_root_port(struct class_device *cd, char *buf) | ||
192 | { | ||
193 | return sprintf(buf, "%d\n", to_bridge(cd)->root_port); | ||
194 | } | ||
195 | static CLASS_DEVICE_ATTR(root_port, S_IRUGO, show_root_port, NULL); | ||
196 | |||
197 | static ssize_t show_root_path_cost(struct class_device *cd, char *buf) | ||
198 | { | ||
199 | return sprintf(buf, "%d\n", to_bridge(cd)->root_path_cost); | ||
200 | } | ||
201 | static CLASS_DEVICE_ATTR(root_path_cost, S_IRUGO, show_root_path_cost, NULL); | ||
202 | |||
203 | static ssize_t show_topology_change(struct class_device *cd, char *buf) | ||
204 | { | ||
205 | return sprintf(buf, "%d\n", to_bridge(cd)->topology_change); | ||
206 | } | ||
207 | static CLASS_DEVICE_ATTR(topology_change, S_IRUGO, show_topology_change, NULL); | ||
208 | |||
209 | static ssize_t show_topology_change_detected(struct class_device *cd, char *buf) | ||
210 | { | ||
211 | struct net_bridge *br = to_bridge(cd); | ||
212 | return sprintf(buf, "%d\n", br->topology_change_detected); | ||
213 | } | ||
214 | static CLASS_DEVICE_ATTR(topology_change_detected, S_IRUGO, show_topology_change_detected, NULL); | ||
215 | |||
216 | static ssize_t show_hello_timer(struct class_device *cd, char *buf) | ||
217 | { | ||
218 | struct net_bridge *br = to_bridge(cd); | ||
219 | return sprintf(buf, "%ld\n", br_timer_value(&br->hello_timer)); | ||
220 | } | ||
221 | static CLASS_DEVICE_ATTR(hello_timer, S_IRUGO, show_hello_timer, NULL); | ||
222 | |||
223 | static ssize_t show_tcn_timer(struct class_device *cd, char *buf) | ||
224 | { | ||
225 | struct net_bridge *br = to_bridge(cd); | ||
226 | return sprintf(buf, "%ld\n", br_timer_value(&br->tcn_timer)); | ||
227 | } | ||
228 | static CLASS_DEVICE_ATTR(tcn_timer, S_IRUGO, show_tcn_timer, NULL); | ||
229 | |||
230 | static ssize_t show_topology_change_timer(struct class_device *cd, char *buf) | ||
231 | { | ||
232 | struct net_bridge *br = to_bridge(cd); | ||
233 | return sprintf(buf, "%ld\n", br_timer_value(&br->topology_change_timer)); | ||
234 | } | ||
235 | static CLASS_DEVICE_ATTR(topology_change_timer, S_IRUGO, show_topology_change_timer, NULL); | ||
236 | |||
237 | static ssize_t show_gc_timer(struct class_device *cd, char *buf) | ||
238 | { | ||
239 | struct net_bridge *br = to_bridge(cd); | ||
240 | return sprintf(buf, "%ld\n", br_timer_value(&br->gc_timer)); | ||
241 | } | ||
242 | static CLASS_DEVICE_ATTR(gc_timer, S_IRUGO, show_gc_timer, NULL); | ||
243 | |||
244 | static struct attribute *bridge_attrs[] = { | ||
245 | &class_device_attr_forward_delay.attr, | ||
246 | &class_device_attr_hello_time.attr, | ||
247 | &class_device_attr_max_age.attr, | ||
248 | &class_device_attr_ageing_time.attr, | ||
249 | &class_device_attr_stp_state.attr, | ||
250 | &class_device_attr_priority.attr, | ||
251 | &class_device_attr_bridge_id.attr, | ||
252 | &class_device_attr_root_id.attr, | ||
253 | &class_device_attr_root_path_cost.attr, | ||
254 | &class_device_attr_root_port.attr, | ||
255 | &class_device_attr_topology_change.attr, | ||
256 | &class_device_attr_topology_change_detected.attr, | ||
257 | &class_device_attr_hello_timer.attr, | ||
258 | &class_device_attr_tcn_timer.attr, | ||
259 | &class_device_attr_topology_change_timer.attr, | ||
260 | &class_device_attr_gc_timer.attr, | ||
261 | NULL | ||
262 | }; | ||
263 | |||
264 | static struct attribute_group bridge_group = { | ||
265 | .name = SYSFS_BRIDGE_ATTR, | ||
266 | .attrs = bridge_attrs, | ||
267 | }; | ||
268 | |||
269 | /* | ||
270 | * Export the forwarding information table as a binary file | ||
271 | * The records are struct __fdb_entry. | ||
272 | * | ||
273 | * Returns the number of bytes read. | ||
274 | */ | ||
275 | static ssize_t brforward_read(struct kobject *kobj, char *buf, | ||
276 | loff_t off, size_t count) | ||
277 | { | ||
278 | struct class_device *cdev = to_class_dev(kobj); | ||
279 | struct net_bridge *br = to_bridge(cdev); | ||
280 | int n; | ||
281 | |||
282 | /* must read whole records */ | ||
283 | if (off % sizeof(struct __fdb_entry) != 0) | ||
284 | return -EINVAL; | ||
285 | |||
286 | n = br_fdb_fillbuf(br, buf, | ||
287 | count / sizeof(struct __fdb_entry), | ||
288 | off / sizeof(struct __fdb_entry)); | ||
289 | |||
290 | if (n > 0) | ||
291 | n *= sizeof(struct __fdb_entry); | ||
292 | |||
293 | return n; | ||
294 | } | ||
295 | |||
296 | static struct bin_attribute bridge_forward = { | ||
297 | .attr = { .name = SYSFS_BRIDGE_FDB, | ||
298 | .mode = S_IRUGO, | ||
299 | .owner = THIS_MODULE, }, | ||
300 | .read = brforward_read, | ||
301 | }; | ||
302 | |||
303 | /* | ||
304 | * Add entries in sysfs onto the existing network class device | ||
305 | * for the bridge. | ||
306 | * Adds a attribute group "bridge" containing tuning parameters. | ||
307 | * Binary attribute containing the forward table | ||
308 | * Sub directory to hold links to interfaces. | ||
309 | * | ||
310 | * Note: the ifobj exists only to be a subdirectory | ||
311 | * to hold links. The ifobj exists in same data structure | ||
312 | * as it's parent the bridge so reference counting works. | ||
313 | */ | ||
314 | int br_sysfs_addbr(struct net_device *dev) | ||
315 | { | ||
316 | struct kobject *brobj = &dev->class_dev.kobj; | ||
317 | struct net_bridge *br = netdev_priv(dev); | ||
318 | int err; | ||
319 | |||
320 | err = sysfs_create_group(brobj, &bridge_group); | ||
321 | if (err) { | ||
322 | pr_info("%s: can't create group %s/%s\n", | ||
323 | __FUNCTION__, dev->name, bridge_group.name); | ||
324 | goto out1; | ||
325 | } | ||
326 | |||
327 | err = sysfs_create_bin_file(brobj, &bridge_forward); | ||
328 | if (err) { | ||
329 | pr_info("%s: can't create attribue file %s/%s\n", | ||
330 | __FUNCTION__, dev->name, bridge_forward.attr.name); | ||
331 | goto out2; | ||
332 | } | ||
333 | |||
334 | |||
335 | kobject_set_name(&br->ifobj, SYSFS_BRIDGE_PORT_SUBDIR); | ||
336 | br->ifobj.ktype = NULL; | ||
337 | br->ifobj.kset = NULL; | ||
338 | br->ifobj.parent = brobj; | ||
339 | |||
340 | err = kobject_register(&br->ifobj); | ||
341 | if (err) { | ||
342 | pr_info("%s: can't add kobject (directory) %s/%s\n", | ||
343 | __FUNCTION__, dev->name, br->ifobj.name); | ||
344 | goto out3; | ||
345 | } | ||
346 | return 0; | ||
347 | out3: | ||
348 | sysfs_remove_bin_file(&dev->class_dev.kobj, &bridge_forward); | ||
349 | out2: | ||
350 | sysfs_remove_group(&dev->class_dev.kobj, &bridge_group); | ||
351 | out1: | ||
352 | return err; | ||
353 | |||
354 | } | ||
355 | |||
356 | void br_sysfs_delbr(struct net_device *dev) | ||
357 | { | ||
358 | struct kobject *kobj = &dev->class_dev.kobj; | ||
359 | struct net_bridge *br = netdev_priv(dev); | ||
360 | |||
361 | kobject_unregister(&br->ifobj); | ||
362 | sysfs_remove_bin_file(kobj, &bridge_forward); | ||
363 | sysfs_remove_group(kobj, &bridge_group); | ||
364 | } | ||