datapath: Add sysfs support for all (otherwise supported) Linux versions.
[sliver-openvswitch.git] / datapath / brc_sysfs_dp.c
1 #include <linux/version.h>
2
3 /*
4  *      Sysfs attributes of bridge for Open vSwitch
5  *
6  *  This has been shamelessly copied from the kernel sources.
7  */
8
9 #include <linux/capability.h>
10 #include <linux/device.h>
11 #include <linux/kernel.h>
12 #include <linux/netdevice.h>
13 #include <linux/if_bridge.h>
14 #include <linux/rtnetlink.h>
15 #include <linux/spinlock.h>
16 #include <linux/times.h>
17 #include <linux/version.h>
18
19 #include "brc_sysfs.h"
20 #include "datapath.h"
21 #include "dp_dev.h"
22
23 #ifdef CONFIG_SYSFS
24 #define to_dev(obj)     container_of(obj, struct device, kobj)
25
26 /* Hack to attempt to build on more platforms. */
27 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)
28 #define BRC_DEVICE_ATTR CLASS_DEVICE_ATTR
29 #define DEVICE_PARAMS struct class_device *d
30 #define DEVICE_ARGS d
31 #define DEV_ATTR(NAME) class_device_attr_##NAME
32 #else
33 #define BRC_DEVICE_ATTR DEVICE_ATTR
34 #define DEVICE_PARAMS struct device *d, struct device_attribute *attr
35 #define DEVICE_ARGS d, attr
36 #define DEV_ATTR(NAME) dev_attr_##NAME
37 #endif
38
39 /*
40  * Common code for storing bridge parameters.
41  */
42 static ssize_t store_bridge_parm(DEVICE_PARAMS,
43                                  const char *buf, size_t len,
44                                  void (*set)(struct datapath *, unsigned long))
45 {
46         struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
47         char *endp;
48         unsigned long val;
49
50         if (!capable(CAP_NET_ADMIN))
51                 return -EPERM;
52
53         val = simple_strtoul(buf, &endp, 0);
54         if (endp == buf)
55                 return -EINVAL;
56
57 #if 0
58         spin_lock_bh(&br->lock);
59         (*set)(br, val);
60         spin_unlock_bh(&br->lock);
61 #else
62         /* xxx We use a default value of 0 for all fields.  If the caller is
63          * xxx attempting to set the value to our default, just silently
64          * xxx ignore the request. 
65          */
66         if (val != 0) {
67                 printk("%s: xxx writing dp parms not supported yet!\n", 
68                        dp_name(dp));
69         }
70 #endif
71         return len;
72 }
73
74
75 static ssize_t show_forward_delay(DEVICE_PARAMS, char *buf)
76 {
77 #if 0
78         struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
79         return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->forward_delay));
80 #else
81         return sprintf(buf, "%d\n", 0);
82 #endif
83 }
84
85 static void set_forward_delay(struct datapath *dp, unsigned long val)
86 {
87 #if 0
88         unsigned long delay = clock_t_to_jiffies(val);
89         br->forward_delay = delay;
90         if (br_is_root_bridge(br))
91                 br->bridge_forward_delay = delay;
92 #else
93         printk("%s: xxx attempt to set_forward_delay()\n", dp_name(dp));
94 #endif
95 }
96
97 static ssize_t store_forward_delay(DEVICE_PARAMS,
98                                    const char *buf, size_t len)
99 {
100         return store_bridge_parm(DEVICE_ARGS, buf, len, set_forward_delay);
101 }
102 static BRC_DEVICE_ATTR(forward_delay, S_IRUGO | S_IWUSR,
103                    show_forward_delay, store_forward_delay);
104
105 static ssize_t show_hello_time(DEVICE_PARAMS, char *buf)
106 {
107 #if 0
108         return sprintf(buf, "%lu\n",
109                        jiffies_to_clock_t(to_bridge(d)->hello_time));
110 #else
111         return sprintf(buf, "%d\n", 0);
112 #endif
113 }
114
115 static void set_hello_time(struct datapath *dp, unsigned long val)
116 {
117 #if 0
118         unsigned long t = clock_t_to_jiffies(val);
119         br->hello_time = t;
120         if (br_is_root_bridge(br))
121                 br->bridge_hello_time = t;
122 #else
123         printk("%s: xxx attempt to set_hello_time()\n", dp_name(dp));
124 #endif
125 }
126
127 static ssize_t store_hello_time(DEVICE_PARAMS,
128                                 const char *buf,
129                                 size_t len)
130 {
131         return store_bridge_parm(DEVICE_ARGS, buf, len, set_hello_time);
132 }
133 static BRC_DEVICE_ATTR(hello_time, S_IRUGO | S_IWUSR, show_hello_time,
134                    store_hello_time);
135
136 static ssize_t show_max_age(DEVICE_PARAMS, char *buf)
137 {
138 #if 0
139         return sprintf(buf, "%lu\n",
140                        jiffies_to_clock_t(to_bridge(d)->max_age));
141 #else
142         return sprintf(buf, "%d\n", 0);
143 #endif
144 }
145
146 static void set_max_age(struct datapath *dp, unsigned long val)
147 {
148 #if 0
149         unsigned long t = clock_t_to_jiffies(val);
150         br->max_age = t;
151         if (br_is_root_bridge(br))
152                 br->bridge_max_age = t;
153 #else
154         printk("%s: xxx attempt to set_max_age()\n", dp_name(dp));
155 #endif
156 }
157
158 static ssize_t store_max_age(DEVICE_PARAMS,
159                              const char *buf, size_t len)
160 {
161         return store_bridge_parm(DEVICE_ARGS, buf, len, set_max_age);
162 }
163 static BRC_DEVICE_ATTR(max_age, S_IRUGO | S_IWUSR, show_max_age, store_max_age);
164
165 static ssize_t show_ageing_time(DEVICE_PARAMS, char *buf)
166 {
167 #if 0
168         struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
169         return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->ageing_time));
170 #else
171         return sprintf(buf, "%d\n", 0);
172 #endif
173 }
174
175 static void set_ageing_time(struct datapath *dp, unsigned long val)
176 {
177 #if 0
178         br->ageing_time = clock_t_to_jiffies(val);
179 #else
180         printk("%s: xxx attempt to set_ageing_time()\n", dp_name(dp));
181 #endif
182 }
183
184 static ssize_t store_ageing_time(DEVICE_PARAMS,
185                                  const char *buf, size_t len)
186 {
187         return store_bridge_parm(DEVICE_ARGS, buf, len, set_ageing_time);
188 }
189 static BRC_DEVICE_ATTR(ageing_time, S_IRUGO | S_IWUSR, show_ageing_time,
190                    store_ageing_time);
191
192 static ssize_t show_stp_state(DEVICE_PARAMS, char *buf)
193 {
194 #if 0
195         struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
196         return sprintf(buf, "%d\n", br->stp_enabled);
197 #else
198         return sprintf(buf, "%d\n", 0);
199 #endif
200 }
201
202
203 static ssize_t store_stp_state(DEVICE_PARAMS,
204                                const char *buf,
205                                size_t len)
206 {
207         struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
208 #if 0
209         char *endp;
210         unsigned long val;
211
212         if (!capable(CAP_NET_ADMIN))
213                 return -EPERM;
214
215         val = simple_strtoul(buf, &endp, 0);
216         if (endp == buf)
217                 return -EINVAL;
218
219         rtnl_lock();
220         br_stp_set_enabled(br, val);
221         rtnl_unlock();
222 #else
223         printk("%s: xxx attempt to set_stp_state()\n", dp_name(dp));
224 #endif
225
226         return len;
227 }
228 static BRC_DEVICE_ATTR(stp_state, S_IRUGO | S_IWUSR, show_stp_state,
229                    store_stp_state);
230
231 static ssize_t show_priority(DEVICE_PARAMS, char *buf)
232 {
233 #if 0
234         struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
235         return sprintf(buf, "%d\n",
236                        (br->bridge_id.prio[0] << 8) | br->bridge_id.prio[1]);
237 #else
238         return sprintf(buf, "%d\n", 0);
239 #endif
240 }
241
242 static void set_priority(struct datapath *dp, unsigned long val)
243 {
244 #if 0
245         br_stp_set_bridge_priority(br, (u16) val);
246 #else
247         printk("%s: xxx attempt to set_priority()\n", dp_name(dp));
248 #endif
249 }
250
251 static ssize_t store_priority(DEVICE_PARAMS,
252                                const char *buf, size_t len)
253 {
254         return store_bridge_parm(DEVICE_ARGS, buf, len, set_priority);
255 }
256 static BRC_DEVICE_ATTR(priority, S_IRUGO | S_IWUSR, show_priority, store_priority);
257
258 static ssize_t show_root_id(DEVICE_PARAMS, char *buf)
259 {
260 #if 0
261         return br_show_bridge_id(buf, &to_bridge(d)->designated_root);
262 #else
263         return sprintf(buf, "0000.010203040506\n");
264 #endif
265 }
266 static BRC_DEVICE_ATTR(root_id, S_IRUGO, show_root_id, NULL);
267
268 static ssize_t show_bridge_id(DEVICE_PARAMS, char *buf)
269 {
270         struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
271         const unsigned char *addr = dp->ports[ODPP_LOCAL]->dev->dev_addr;
272
273         /* xxx Do we need a lock of some sort? */
274         return sprintf(buf, "%.2x%.2x.%.2x%.2x%.2x%.2x%.2x%.2x\n",
275                         0, 0, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
276 }
277 static BRC_DEVICE_ATTR(bridge_id, S_IRUGO, show_bridge_id, NULL);
278
279 static ssize_t show_root_port(DEVICE_PARAMS, char *buf)
280 {
281 #if 0
282         return sprintf(buf, "%d\n", to_bridge(d)->root_port);
283 #else
284         return sprintf(buf, "%d\n", 0);
285 #endif
286 }
287 static BRC_DEVICE_ATTR(root_port, S_IRUGO, show_root_port, NULL);
288
289 static ssize_t show_root_path_cost(DEVICE_PARAMS, char *buf)
290 {
291 #if 0
292         return sprintf(buf, "%d\n", to_bridge(d)->root_path_cost);
293 #else
294         return sprintf(buf, "%d\n", 0);
295 #endif
296 }
297 static BRC_DEVICE_ATTR(root_path_cost, S_IRUGO, show_root_path_cost, NULL);
298
299 static ssize_t show_topology_change(DEVICE_PARAMS, char *buf)
300 {
301 #if 0
302         return sprintf(buf, "%d\n", to_bridge(d)->topology_change);
303 #else
304         return sprintf(buf, "%d\n", 0);
305 #endif
306 }
307 static BRC_DEVICE_ATTR(topology_change, S_IRUGO, show_topology_change, NULL);
308
309 static ssize_t show_topology_change_detected(DEVICE_PARAMS, char *buf)
310 {
311 #if 0
312         struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
313         return sprintf(buf, "%d\n", br->topology_change_detected);
314 #else
315         return sprintf(buf, "%d\n", 0);
316 #endif
317 }
318 static BRC_DEVICE_ATTR(topology_change_detected, S_IRUGO,
319                    show_topology_change_detected, NULL);
320
321 static ssize_t show_hello_timer(DEVICE_PARAMS, char *buf)
322 {
323 #if 0
324         struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
325         return sprintf(buf, "%ld\n", br_timer_value(&br->hello_timer));
326 #else
327         return sprintf(buf, "%d\n", 0);
328 #endif
329 }
330 static BRC_DEVICE_ATTR(hello_timer, S_IRUGO, show_hello_timer, NULL);
331
332 static ssize_t show_tcn_timer(DEVICE_PARAMS, char *buf)
333 {
334 #if 0
335         struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
336         return sprintf(buf, "%ld\n", br_timer_value(&br->tcn_timer));
337 #else
338         return sprintf(buf, "%d\n", 0);
339 #endif
340 }
341 static BRC_DEVICE_ATTR(tcn_timer, S_IRUGO, show_tcn_timer, NULL);
342
343 static ssize_t show_topology_change_timer(DEVICE_PARAMS, char *buf)
344 {
345 #if 0
346         struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
347         return sprintf(buf, "%ld\n", br_timer_value(&br->topology_change_timer));
348 #else
349         return sprintf(buf, "%d\n", 0);
350 #endif
351 }
352 static BRC_DEVICE_ATTR(topology_change_timer, S_IRUGO, show_topology_change_timer,
353                    NULL);
354
355 static ssize_t show_gc_timer(DEVICE_PARAMS, char *buf)
356 {
357 #if 0
358         struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
359         return sprintf(buf, "%ld\n", br_timer_value(&br->gc_timer));
360 #else
361         return sprintf(buf, "%d\n", 0);
362 #endif
363 }
364 static BRC_DEVICE_ATTR(gc_timer, S_IRUGO, show_gc_timer, NULL);
365
366 static ssize_t show_group_addr(DEVICE_PARAMS, char *buf)
367 {
368 #if 0
369         struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
370         return sprintf(buf, "%x:%x:%x:%x:%x:%x\n",
371                        br->group_addr[0], br->group_addr[1],
372                        br->group_addr[2], br->group_addr[3],
373                        br->group_addr[4], br->group_addr[5]);
374 #else
375         return sprintf(buf, "00:01:02:03:04:05\n");
376 #endif
377 }
378
379 static ssize_t store_group_addr(DEVICE_PARAMS,
380                                 const char *buf, size_t len)
381 {
382         struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
383 #if 0
384         unsigned new_addr[6];
385         int i;
386
387         if (!capable(CAP_NET_ADMIN))
388                 return -EPERM;
389
390         if (sscanf(buf, "%x:%x:%x:%x:%x:%x",
391                    &new_addr[0], &new_addr[1], &new_addr[2],
392                    &new_addr[3], &new_addr[4], &new_addr[5]) != 6)
393                 return -EINVAL;
394
395         /* Must be 01:80:c2:00:00:0X */
396         for (i = 0; i < 5; i++)
397                 if (new_addr[i] != br_group_address[i])
398                         return -EINVAL;
399
400         if (new_addr[5] & ~0xf)
401                 return -EINVAL;
402
403         if (new_addr[5] == 1    /* 802.3x Pause address */
404             || new_addr[5] == 2 /* 802.3ad Slow protocols */
405             || new_addr[5] == 3) /* 802.1X PAE address */
406                 return -EINVAL;
407
408         spin_lock_bh(&br->lock);
409         for (i = 0; i < 6; i++)
410                 br->group_addr[i] = new_addr[i];
411         spin_unlock_bh(&br->lock);
412 #else
413         printk("%s: xxx attempt to store_group_addr()\n", dp_name(dp));
414 #endif
415         return len;
416 }
417
418 static BRC_DEVICE_ATTR(group_addr, S_IRUGO | S_IWUSR,
419                    show_group_addr, store_group_addr);
420
421 static struct attribute *bridge_attrs[] = {
422         &DEV_ATTR(forward_delay).attr,
423         &DEV_ATTR(hello_time).attr,
424         &DEV_ATTR(max_age).attr,
425         &DEV_ATTR(ageing_time).attr,
426         &DEV_ATTR(stp_state).attr,
427         &DEV_ATTR(priority).attr,
428         &DEV_ATTR(bridge_id).attr,
429         &DEV_ATTR(root_id).attr,
430         &DEV_ATTR(root_path_cost).attr,
431         &DEV_ATTR(root_port).attr,
432         &DEV_ATTR(topology_change).attr,
433         &DEV_ATTR(topology_change_detected).attr,
434         &DEV_ATTR(hello_timer).attr,
435         &DEV_ATTR(tcn_timer).attr,
436         &DEV_ATTR(topology_change_timer).attr,
437         &DEV_ATTR(gc_timer).attr,
438         &DEV_ATTR(group_addr).attr,
439         NULL
440 };
441
442 static struct attribute_group bridge_group = {
443         .name = SYSFS_BRIDGE_ATTR,
444         .attrs = bridge_attrs,
445 };
446
447 /*
448  * Add entries in sysfs onto the existing network class device
449  * for the bridge.
450  *   Adds a attribute group "bridge" containing tuning parameters.
451  *   Sub directory to hold links to interfaces.
452  *
453  * Note: the ifobj exists only to be a subdirectory
454  *   to hold links.  The ifobj exists in the same data structure
455  *   as its parent the bridge so reference counting works.
456  */
457 int brc_sysfs_add_dp(struct datapath *dp)
458 {
459         struct kobject *kobj = &dp->ports[ODPP_LOCAL]->dev->NETDEV_DEV_MEMBER.kobj;
460         int err;
461
462         err = sysfs_create_group(kobj, &bridge_group);
463         if (err) {
464                 pr_info("%s: can't create group %s/%s\n",
465                         __func__, dp_name(dp), bridge_group.name);
466                 goto out1;
467         }
468
469 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
470         kobject_set_name(&dp->ifobj, SYSFS_BRIDGE_PORT_SUBDIR);
471         dp->ifobj.ktype = NULL;
472         dp->ifobj.kset = NULL;
473         dp->ifobj.parent = kobj;
474
475         err = kobject_register(&dp->ifobj);
476         if (err) {
477                 pr_info("%s: can't add kobject (directory) %s/%s\n",
478                         __FUNCTION__, dp_name(dp), kobject_name(&dp->ifobj));
479                 goto out2;
480         }
481 #else
482         dp->ifobj = kobject_create_and_add(SYSFS_BRIDGE_PORT_SUBDIR, kobj);
483         if (!dp->ifobj) {
484                 pr_info("%s: can't add kobject (directory) %s/%s\n",
485                         __func__, dp_name(dp), SYSFS_BRIDGE_PORT_SUBDIR);
486                 goto out2;
487         }
488 #endif
489         return 0;
490
491  out2:
492         sysfs_remove_group(kobj, &bridge_group);
493  out1:
494         return err;
495 }
496
497 int brc_sysfs_del_dp(struct datapath *dp)
498 {
499         struct kobject *kobj = &dp->ports[ODPP_LOCAL]->dev->NETDEV_DEV_MEMBER.kobj;
500
501 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
502         kobject_unregister(&dp->ifobj);
503 #else 
504         kobject_put(dp->ifobj);
505 #endif
506         sysfs_remove_group(kobj, &bridge_group);
507
508         return 0;
509 }
510 #else /* !CONFIG_SYSFS */
511 int brc_sysfs_add_dp(struct datapath *dp) { return 0; }
512 int brc_sysfs_del_dp(struct datapath *dp) { return 0; }
513 int brc_sysfs_add_if(struct net_bridge_port *p) { return 0; }
514 int brc_sysfs_del_if(struct net_bridge_port *p)
515 {
516         dev_put(p->dev);
517         kfree(p);
518         return 0;
519 }
520 #endif /* !CONFIG_SYSFS */