]>
Commit | Line | Data |
---|---|---|
a14bc59f | 1 | /* |
f2459fe7 | 2 | * Copyright (c) 2009, 2010 Nicira Networks. |
a14bc59f BP |
3 | * Distributed under the terms of the GNU GPL version 2. |
4 | * | |
5 | * Significant portions of this file may be copied from parts of the Linux | |
6 | * kernel, by Linus Torvalds and others. | |
7 | */ | |
8 | ||
064af421 BP |
9 | /* |
10 | * Sysfs attributes of bridge ports for Open vSwitch | |
11 | * | |
12 | * This has been shamelessly copied from the kernel sources. | |
13 | */ | |
14 | ||
15 | #include <linux/capability.h> | |
16 | #include <linux/kernel.h> | |
17 | #include <linux/netdevice.h> | |
18 | #include <linux/if_bridge.h> | |
19 | #include <linux/rtnetlink.h> | |
20 | #include <linux/spinlock.h> | |
f2459fe7 | 21 | |
064af421 | 22 | #include "datapath.h" |
f2459fe7 JG |
23 | #include "dp_sysfs.h" |
24 | #include "vport.h" | |
064af421 | 25 | |
806e39cf | 26 | #ifdef CONFIG_SYSFS |
064af421 BP |
27 | |
28 | struct brport_attribute { | |
29 | struct attribute attr; | |
f2459fe7 JG |
30 | ssize_t (*show)(struct dp_port *, char *); |
31 | ssize_t (*store)(struct dp_port *, unsigned long); | |
064af421 BP |
32 | }; |
33 | ||
34 | #define BRPORT_ATTR(_name,_mode,_show,_store) \ | |
35 | struct brport_attribute brport_attr_##_name = { \ | |
36 | .attr = {.name = __stringify(_name), \ | |
37 | .mode = _mode, \ | |
38 | .owner = THIS_MODULE, }, \ | |
39 | .show = _show, \ | |
40 | .store = _store, \ | |
41 | }; | |
42 | ||
f2459fe7 | 43 | static ssize_t show_path_cost(struct dp_port *p, char *buf) |
064af421 BP |
44 | { |
45 | #if 0 | |
46 | return sprintf(buf, "%d\n", p->path_cost); | |
47 | #else | |
48 | return sprintf(buf, "%d\n", 0); | |
49 | #endif | |
50 | } | |
f2459fe7 | 51 | static ssize_t store_path_cost(struct dp_port *p, unsigned long v) |
064af421 BP |
52 | { |
53 | #if 0 | |
54 | br_stp_set_path_cost(p, v); | |
55 | #endif | |
56 | return 0; | |
57 | } | |
58 | static BRPORT_ATTR(path_cost, S_IRUGO | S_IWUSR, | |
59 | show_path_cost, store_path_cost); | |
60 | ||
f2459fe7 | 61 | static ssize_t show_priority(struct dp_port *p, char *buf) |
064af421 BP |
62 | { |
63 | #if 0 | |
64 | return sprintf(buf, "%d\n", p->priority); | |
65 | #else | |
66 | return sprintf(buf, "%d\n", 0); | |
67 | #endif | |
68 | } | |
f2459fe7 | 69 | static ssize_t store_priority(struct dp_port *p, unsigned long v) |
064af421 BP |
70 | { |
71 | #if 0 | |
72 | if (v >= (1<<(16-BR_PORT_BITS))) | |
73 | return -ERANGE; | |
74 | br_stp_set_port_priority(p, v); | |
75 | #endif | |
76 | return 0; | |
77 | } | |
78 | static BRPORT_ATTR(priority, S_IRUGO | S_IWUSR, | |
79 | show_priority, store_priority); | |
80 | ||
f2459fe7 | 81 | static ssize_t show_designated_root(struct dp_port *p, char *buf) |
064af421 BP |
82 | { |
83 | #if 0 | |
84 | return br_show_bridge_id(buf, &p->designated_root); | |
85 | #else | |
86 | return sprintf(buf, "0000.010203040506\n"); | |
87 | #endif | |
88 | } | |
89 | static BRPORT_ATTR(designated_root, S_IRUGO, show_designated_root, NULL); | |
90 | ||
f2459fe7 | 91 | static ssize_t show_designated_bridge(struct dp_port *p, char *buf) |
064af421 BP |
92 | { |
93 | #if 0 | |
94 | return br_show_bridge_id(buf, &p->designated_bridge); | |
95 | #else | |
96 | return sprintf(buf, "0000.060504030201\n"); | |
97 | #endif | |
98 | } | |
99 | static BRPORT_ATTR(designated_bridge, S_IRUGO, show_designated_bridge, NULL); | |
100 | ||
f2459fe7 | 101 | static ssize_t show_designated_port(struct dp_port *p, char *buf) |
064af421 BP |
102 | { |
103 | #if 0 | |
104 | return sprintf(buf, "%d\n", p->designated_port); | |
105 | #else | |
106 | return sprintf(buf, "%d\n", 0); | |
107 | #endif | |
108 | } | |
109 | static BRPORT_ATTR(designated_port, S_IRUGO, show_designated_port, NULL); | |
110 | ||
f2459fe7 | 111 | static ssize_t show_designated_cost(struct dp_port *p, char *buf) |
064af421 BP |
112 | { |
113 | #if 0 | |
114 | return sprintf(buf, "%d\n", p->designated_cost); | |
115 | #else | |
116 | return sprintf(buf, "%d\n", 0); | |
117 | #endif | |
118 | } | |
119 | static BRPORT_ATTR(designated_cost, S_IRUGO, show_designated_cost, NULL); | |
120 | ||
f2459fe7 | 121 | static ssize_t show_port_id(struct dp_port *p, char *buf) |
064af421 BP |
122 | { |
123 | #if 0 | |
124 | return sprintf(buf, "0x%x\n", p->port_id); | |
125 | #else | |
126 | return sprintf(buf, "0x%x\n", 0); | |
127 | #endif | |
128 | } | |
129 | static BRPORT_ATTR(port_id, S_IRUGO, show_port_id, NULL); | |
130 | ||
f2459fe7 | 131 | static ssize_t show_port_no(struct dp_port *p, char *buf) |
064af421 BP |
132 | { |
133 | return sprintf(buf, "0x%x\n", p->port_no); | |
134 | } | |
135 | ||
136 | static BRPORT_ATTR(port_no, S_IRUGO, show_port_no, NULL); | |
137 | ||
f2459fe7 | 138 | static ssize_t show_change_ack(struct dp_port *p, char *buf) |
064af421 BP |
139 | { |
140 | #if 0 | |
141 | return sprintf(buf, "%d\n", p->topology_change_ack); | |
142 | #else | |
143 | return sprintf(buf, "%d\n", 0); | |
144 | #endif | |
145 | } | |
146 | static BRPORT_ATTR(change_ack, S_IRUGO, show_change_ack, NULL); | |
147 | ||
f2459fe7 | 148 | static ssize_t show_config_pending(struct dp_port *p, char *buf) |
064af421 BP |
149 | { |
150 | #if 0 | |
151 | return sprintf(buf, "%d\n", p->config_pending); | |
152 | #else | |
153 | return sprintf(buf, "%d\n", 0); | |
154 | #endif | |
155 | } | |
156 | static BRPORT_ATTR(config_pending, S_IRUGO, show_config_pending, NULL); | |
157 | ||
f2459fe7 | 158 | static ssize_t show_port_state(struct dp_port *p, char *buf) |
064af421 BP |
159 | { |
160 | #if 0 | |
161 | return sprintf(buf, "%d\n", p->state); | |
162 | #else | |
163 | return sprintf(buf, "%d\n", 0); | |
164 | #endif | |
165 | } | |
166 | static BRPORT_ATTR(state, S_IRUGO, show_port_state, NULL); | |
167 | ||
f2459fe7 | 168 | static ssize_t show_message_age_timer(struct dp_port *p, |
064af421 BP |
169 | char *buf) |
170 | { | |
171 | #if 0 | |
172 | return sprintf(buf, "%ld\n", br_timer_value(&p->message_age_timer)); | |
173 | #else | |
174 | return sprintf(buf, "%d\n", 0); | |
175 | #endif | |
176 | } | |
177 | static BRPORT_ATTR(message_age_timer, S_IRUGO, show_message_age_timer, NULL); | |
178 | ||
f2459fe7 | 179 | static ssize_t show_forward_delay_timer(struct dp_port *p, |
064af421 BP |
180 | char *buf) |
181 | { | |
182 | #if 0 | |
183 | return sprintf(buf, "%ld\n", br_timer_value(&p->forward_delay_timer)); | |
184 | #else | |
185 | return sprintf(buf, "%d\n", 0); | |
186 | #endif | |
187 | } | |
188 | static BRPORT_ATTR(forward_delay_timer, S_IRUGO, show_forward_delay_timer, NULL); | |
189 | ||
f2459fe7 | 190 | static ssize_t show_hold_timer(struct dp_port *p, |
064af421 BP |
191 | char *buf) |
192 | { | |
193 | #if 0 | |
194 | return sprintf(buf, "%ld\n", br_timer_value(&p->hold_timer)); | |
195 | #else | |
196 | return sprintf(buf, "%d\n", 0); | |
197 | #endif | |
198 | } | |
199 | static BRPORT_ATTR(hold_timer, S_IRUGO, show_hold_timer, NULL); | |
200 | ||
201 | static struct brport_attribute *brport_attrs[] = { | |
202 | &brport_attr_path_cost, | |
203 | &brport_attr_priority, | |
204 | &brport_attr_port_id, | |
205 | &brport_attr_port_no, | |
206 | &brport_attr_designated_root, | |
207 | &brport_attr_designated_bridge, | |
208 | &brport_attr_designated_port, | |
209 | &brport_attr_designated_cost, | |
210 | &brport_attr_state, | |
211 | &brport_attr_change_ack, | |
212 | &brport_attr_config_pending, | |
213 | &brport_attr_message_age_timer, | |
214 | &brport_attr_forward_delay_timer, | |
215 | &brport_attr_hold_timer, | |
216 | NULL | |
217 | }; | |
218 | ||
219 | #define to_brport_attr(_at) container_of(_at, struct brport_attribute, attr) | |
f2459fe7 | 220 | #define to_brport(obj) container_of(obj, struct dp_port, kobj) |
064af421 BP |
221 | |
222 | static ssize_t brport_show(struct kobject * kobj, | |
223 | struct attribute * attr, char * buf) | |
224 | { | |
225 | struct brport_attribute * brport_attr = to_brport_attr(attr); | |
f2459fe7 | 226 | struct dp_port * p = to_brport(kobj); |
064af421 BP |
227 | |
228 | return brport_attr->show(p, buf); | |
229 | } | |
230 | ||
231 | static ssize_t brport_store(struct kobject * kobj, | |
232 | struct attribute * attr, | |
233 | const char * buf, size_t count) | |
234 | { | |
f2459fe7 | 235 | struct dp_port * p = to_brport(kobj); |
064af421 BP |
236 | #if 0 |
237 | struct brport_attribute * brport_attr = to_brport_attr(attr); | |
238 | char *endp; | |
239 | unsigned long val; | |
240 | #endif | |
241 | ssize_t ret = -EINVAL; | |
242 | ||
243 | if (!capable(CAP_NET_ADMIN)) | |
244 | return -EPERM; | |
245 | ||
246 | #if 0 | |
247 | val = simple_strtoul(buf, &endp, 0); | |
248 | if (endp != buf) { | |
249 | rtnl_lock(); | |
250 | if (p->dev && p->br && brport_attr->store) { | |
251 | spin_lock_bh(&p->br->lock); | |
252 | ret = brport_attr->store(p, val); | |
253 | spin_unlock_bh(&p->br->lock); | |
254 | if (ret == 0) | |
255 | ret = count; | |
256 | } | |
257 | rtnl_unlock(); | |
258 | } | |
259 | #else | |
260 | printk("%s: xxx writing port parms not supported yet!\n", | |
261 | dp_name(p->dp)); | |
262 | #endif | |
263 | return ret; | |
264 | } | |
265 | ||
266 | struct sysfs_ops brport_sysfs_ops = { | |
267 | .show = brport_show, | |
268 | .store = brport_store, | |
269 | }; | |
270 | ||
064af421 BP |
271 | /* |
272 | * Add sysfs entries to ethernet device added to a bridge. | |
273 | * Creates a brport subdirectory with bridge attributes. | |
274 | * Puts symlink in bridge's brport subdirectory | |
275 | */ | |
f2459fe7 | 276 | int dp_sysfs_add_if(struct dp_port *p) |
064af421 | 277 | { |
f2459fe7 | 278 | struct kobject *kobj = vport_get_kobj(p->vport); |
064af421 BP |
279 | struct datapath *dp = p->dp; |
280 | struct brport_attribute **a; | |
281 | int err; | |
282 | ||
5e93df1c | 283 | /* Create /sys/class/net/<devname>/brport directory. */ |
f2459fe7 JG |
284 | if (!kobj) |
285 | return -ENOENT; | |
286 | ||
287 | err = kobject_add(&p->kobj, kobj, SYSFS_BRIDGE_PORT_ATTR); | |
064af421 | 288 | if (err) |
806e39cf | 289 | goto err; |
064af421 | 290 | |
5e93df1c BP |
291 | /* Create symlink from /sys/class/net/<devname>/brport/bridge to |
292 | * /sys/class/net/<bridgename>. */ | |
f2459fe7 | 293 | err = sysfs_create_link(&p->kobj, vport_get_kobj(dp->ports[ODPP_LOCAL]->vport), |
5e93df1c | 294 | SYSFS_BRIDGE_PORT_LINK); /* "bridge" */ |
064af421 BP |
295 | if (err) |
296 | goto err_del; | |
297 | ||
5e93df1c | 298 | /* Populate /sys/class/net/<devname>/brport directory with files. */ |
064af421 BP |
299 | for (a = brport_attrs; *a; ++a) { |
300 | err = sysfs_create_file(&p->kobj, &((*a)->attr)); | |
301 | if (err) | |
302 | goto err_del; | |
303 | } | |
304 | ||
5e93df1c BP |
305 | /* Create symlink from /sys/class/net/<bridgename>/brif/<devname> to |
306 | * /sys/class/net/<devname>/brport. */ | |
f2459fe7 | 307 | err = sysfs_create_link(&dp->ifobj, &p->kobj, vport_get_name(p->vport)); |
064af421 BP |
308 | if (err) |
309 | goto err_del; | |
f2459fe7 | 310 | strcpy(p->linkname, vport_get_name(p->vport)); |
064af421 BP |
311 | |
312 | kobject_uevent(&p->kobj, KOBJ_ADD); | |
313 | ||
8fef8c71 | 314 | return 0; |
064af421 BP |
315 | |
316 | err_del: | |
317 | kobject_del(&p->kobj); | |
806e39cf | 318 | err: |
8fef8c71 | 319 | p->linkname[0] = 0; |
064af421 BP |
320 | return err; |
321 | } | |
322 | ||
f2459fe7 | 323 | int dp_sysfs_del_if(struct dp_port *p) |
064af421 | 324 | { |
0515ceb3 BP |
325 | if (p->linkname[0]) { |
326 | sysfs_remove_link(&p->dp->ifobj, p->linkname); | |
58c342f6 BP |
327 | kobject_uevent(&p->kobj, KOBJ_REMOVE); |
328 | kobject_del(&p->kobj); | |
8fef8c71 | 329 | p->linkname[0] = '\0'; |
58c342f6 | 330 | } |
064af421 BP |
331 | return 0; |
332 | } | |
806e39cf | 333 | #endif /* CONFIG_SYSFS */ |