Prepare Open vSwitch 1.1.2 release.
[sliver-openvswitch.git] / datapath / dp_sysfs_dp.c
1 /*
2  * Copyright (c) 2009, 2010 Nicira Networks.
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
9 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
10
11 #include <linux/version.h>
12
13 /*
14  *      Sysfs attributes of bridge for Open vSwitch
15  *
16  *  This has been shamelessly copied from the kernel sources.
17  */
18
19 #include <linux/capability.h>
20 #include <linux/device.h>
21 #include <linux/kernel.h>
22 #include <linux/netdevice.h>
23 #include <linux/if_bridge.h>
24 #include <linux/rtnetlink.h>
25 #include <linux/version.h>
26
27 #include "dp_sysfs.h"
28 #include "datapath.h"
29 #include "vport-internal_dev.h"
30
31 #ifdef CONFIG_SYSFS
32
33 /* Hack to attempt to build on more platforms. */
34 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)
35 #define INTERNAL_DEVICE_ATTR CLASS_DEVICE_ATTR
36 #define DEVICE_PARAMS struct class_device *d
37 #define DEVICE_ARGS d
38 #define DEV_ATTR(NAME) class_device_attr_##NAME
39 #else
40 #define INTERNAL_DEVICE_ATTR DEVICE_ATTR
41 #define DEVICE_PARAMS struct device *d, struct device_attribute *attr
42 #define DEVICE_ARGS d, attr
43 #define DEV_ATTR(NAME) dev_attr_##NAME
44 #endif
45
46 static struct datapath *sysfs_get_dp(struct net_device *netdev)
47 {
48         struct vport *vport = internal_dev_get_vport(netdev);
49         return vport ? vport->dp : NULL;
50 }
51 /*
52  * Common code for storing bridge parameters.
53  */
54 static ssize_t store_bridge_parm(DEVICE_PARAMS,
55                                  const char *buf, size_t len,
56                                  void (*set)(struct datapath *, unsigned long))
57 {
58         char *endp;
59         unsigned long val;
60         ssize_t result = len;
61
62         if (!capable(CAP_NET_ADMIN))
63                 return -EPERM;
64
65         val = simple_strtoul(buf, &endp, 0);
66         if (endp == buf)
67                 return -EINVAL;
68
69         /* xxx We use a default value of 0 for all fields.  If the caller is
70          * xxx attempting to set the value to our default, just silently
71          * xxx ignore the request.
72          */
73         if (val != 0) {
74                 struct datapath *dp;
75
76                 rcu_read_lock();
77
78                 dp = sysfs_get_dp(to_net_dev(d));
79                 if (dp)
80                         printk("%s: xxx writing dp parms not supported yet!\n",
81                                dp_name(dp));
82                 else
83                         result = -ENODEV;
84
85                 rcu_read_unlock();
86         }
87
88         return result;
89 }
90
91
92 static ssize_t show_forward_delay(DEVICE_PARAMS, char *buf)
93 {
94         return sprintf(buf, "%d\n", 0);
95 }
96
97 static void set_forward_delay(struct datapath *dp, unsigned long val)
98 {
99         printk("%s: xxx attempt to set_forward_delay()\n", dp_name(dp));
100 }
101
102 static ssize_t store_forward_delay(DEVICE_PARAMS,
103                                    const char *buf, size_t len)
104 {
105         return store_bridge_parm(DEVICE_ARGS, buf, len, set_forward_delay);
106 }
107 static INTERNAL_DEVICE_ATTR(forward_delay, S_IRUGO | S_IWUSR,
108                    show_forward_delay, store_forward_delay);
109
110 static ssize_t show_hello_time(DEVICE_PARAMS, char *buf)
111 {
112         return sprintf(buf, "%d\n", 0);
113 }
114
115 static void set_hello_time(struct datapath *dp, unsigned long val)
116 {
117         printk("%s: xxx attempt to set_hello_time()\n", dp_name(dp));
118 }
119
120 static ssize_t store_hello_time(DEVICE_PARAMS,
121                                 const char *buf,
122                                 size_t len)
123 {
124         return store_bridge_parm(DEVICE_ARGS, buf, len, set_hello_time);
125 }
126 static INTERNAL_DEVICE_ATTR(hello_time, S_IRUGO | S_IWUSR, show_hello_time,
127                    store_hello_time);
128
129 static ssize_t show_max_age(DEVICE_PARAMS, char *buf)
130 {
131         return sprintf(buf, "%d\n", 0);
132 }
133
134 static void set_max_age(struct datapath *dp, unsigned long val)
135 {
136         printk("%s: xxx attempt to set_max_age()\n", dp_name(dp));
137 }
138
139 static ssize_t store_max_age(DEVICE_PARAMS,
140                              const char *buf, size_t len)
141 {
142         return store_bridge_parm(DEVICE_ARGS, buf, len, set_max_age);
143 }
144 static INTERNAL_DEVICE_ATTR(max_age, S_IRUGO | S_IWUSR, show_max_age, store_max_age);
145
146 static ssize_t show_ageing_time(DEVICE_PARAMS, char *buf)
147 {
148         return sprintf(buf, "%d\n", 0);
149 }
150
151 static void set_ageing_time(struct datapath *dp, unsigned long val)
152 {
153         printk("%s: xxx attempt to set_ageing_time()\n", dp_name(dp));
154 }
155
156 static ssize_t store_ageing_time(DEVICE_PARAMS,
157                                  const char *buf, size_t len)
158 {
159         return store_bridge_parm(DEVICE_ARGS, buf, len, set_ageing_time);
160 }
161 static INTERNAL_DEVICE_ATTR(ageing_time, S_IRUGO | S_IWUSR, show_ageing_time,
162                    store_ageing_time);
163
164 static ssize_t show_stp_state(DEVICE_PARAMS, char *buf)
165 {
166         return sprintf(buf, "%d\n", 0);
167 }
168
169
170 static ssize_t store_stp_state(DEVICE_PARAMS,
171                                const char *buf,
172                                size_t len)
173 {
174         struct datapath *dp;
175         ssize_t result = len;
176
177         rcu_read_lock();
178
179         dp = sysfs_get_dp(to_net_dev(d));
180         if (dp)
181                 printk("%s: xxx attempt to set_stp_state()\n", dp_name(dp));
182         else
183                 result = -ENODEV;
184
185         rcu_read_unlock();
186
187         return result;
188 }
189 static INTERNAL_DEVICE_ATTR(stp_state, S_IRUGO | S_IWUSR, show_stp_state,
190                    store_stp_state);
191
192 static ssize_t show_priority(DEVICE_PARAMS, char *buf)
193 {
194         return sprintf(buf, "%d\n", 0);
195 }
196
197 static void set_priority(struct datapath *dp, unsigned long val)
198 {
199         printk("%s: xxx attempt to set_priority()\n", dp_name(dp));
200 }
201
202 static ssize_t store_priority(DEVICE_PARAMS,
203                                const char *buf, size_t len)
204 {
205         return store_bridge_parm(DEVICE_ARGS, buf, len, set_priority);
206 }
207 static INTERNAL_DEVICE_ATTR(priority, S_IRUGO | S_IWUSR, show_priority, store_priority);
208
209 static ssize_t show_root_id(DEVICE_PARAMS, char *buf)
210 {
211         return sprintf(buf, "0000.010203040506\n");
212 }
213 static INTERNAL_DEVICE_ATTR(root_id, S_IRUGO, show_root_id, NULL);
214
215 static ssize_t show_bridge_id(DEVICE_PARAMS, char *buf)
216 {
217         struct vport *vport;
218         ssize_t result;
219
220         rcu_read_lock();
221
222         vport = internal_dev_get_vport(to_net_dev(d));
223         if (vport) {
224                 const unsigned char *addr;
225
226                 addr = vport_get_addr(vport);
227                 result = sprintf(buf, "%.2x%.2x.%.2x%.2x%.2x%.2x%.2x%.2x\n",
228                                  0, 0, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
229         } else
230                 result = -ENODEV;
231
232         rcu_read_unlock();
233
234         return result;
235 }
236 static INTERNAL_DEVICE_ATTR(bridge_id, S_IRUGO, show_bridge_id, NULL);
237
238 static ssize_t show_root_port(DEVICE_PARAMS, char *buf)
239 {
240         return sprintf(buf, "%d\n", 0);
241 }
242 static INTERNAL_DEVICE_ATTR(root_port, S_IRUGO, show_root_port, NULL);
243
244 static ssize_t show_root_path_cost(DEVICE_PARAMS, char *buf)
245 {
246         return sprintf(buf, "%d\n", 0);
247 }
248 static INTERNAL_DEVICE_ATTR(root_path_cost, S_IRUGO, show_root_path_cost, NULL);
249
250 static ssize_t show_topology_change(DEVICE_PARAMS, char *buf)
251 {
252         return sprintf(buf, "%d\n", 0);
253 }
254 static INTERNAL_DEVICE_ATTR(topology_change, S_IRUGO, show_topology_change, NULL);
255
256 static ssize_t show_topology_change_detected(DEVICE_PARAMS, char *buf)
257 {
258         return sprintf(buf, "%d\n", 0);
259 }
260 static INTERNAL_DEVICE_ATTR(topology_change_detected, S_IRUGO,
261                    show_topology_change_detected, NULL);
262
263 static ssize_t show_hello_timer(DEVICE_PARAMS, char *buf)
264 {
265         return sprintf(buf, "%d\n", 0);
266 }
267 static INTERNAL_DEVICE_ATTR(hello_timer, S_IRUGO, show_hello_timer, NULL);
268
269 static ssize_t show_tcn_timer(DEVICE_PARAMS, char *buf)
270 {
271         return sprintf(buf, "%d\n", 0);
272 }
273 static INTERNAL_DEVICE_ATTR(tcn_timer, S_IRUGO, show_tcn_timer, NULL);
274
275 static ssize_t show_topology_change_timer(DEVICE_PARAMS, char *buf)
276 {
277         return sprintf(buf, "%d\n", 0);
278 }
279 static INTERNAL_DEVICE_ATTR(topology_change_timer, S_IRUGO, show_topology_change_timer,
280                    NULL);
281
282 static ssize_t show_gc_timer(DEVICE_PARAMS, char *buf)
283 {
284         return sprintf(buf, "%d\n", 0);
285 }
286 static INTERNAL_DEVICE_ATTR(gc_timer, S_IRUGO, show_gc_timer, NULL);
287
288 static ssize_t show_group_addr(DEVICE_PARAMS, char *buf)
289 {
290         return sprintf(buf, "00:01:02:03:04:05\n");
291 }
292
293 static ssize_t store_group_addr(DEVICE_PARAMS,
294                                 const char *buf, size_t len)
295 {
296         struct datapath *dp;
297         ssize_t result = len;
298
299         rcu_read_lock();
300
301         dp = sysfs_get_dp(to_net_dev(d));
302         if (dp)
303                 printk("%s: xxx attempt to store_group_addr()\n", dp_name(dp));
304         else
305                 result = -ENODEV;
306
307         rcu_read_unlock();
308
309         return result;
310 }
311
312 static INTERNAL_DEVICE_ATTR(group_addr, S_IRUGO | S_IWUSR,
313                    show_group_addr, store_group_addr);
314
315 static struct attribute *bridge_attrs[] = {
316         &DEV_ATTR(forward_delay).attr,
317         &DEV_ATTR(hello_time).attr,
318         &DEV_ATTR(max_age).attr,
319         &DEV_ATTR(ageing_time).attr,
320         &DEV_ATTR(stp_state).attr,
321         &DEV_ATTR(priority).attr,
322         &DEV_ATTR(bridge_id).attr,
323         &DEV_ATTR(root_id).attr,
324         &DEV_ATTR(root_path_cost).attr,
325         &DEV_ATTR(root_port).attr,
326         &DEV_ATTR(topology_change).attr,
327         &DEV_ATTR(topology_change_detected).attr,
328         &DEV_ATTR(hello_timer).attr,
329         &DEV_ATTR(tcn_timer).attr,
330         &DEV_ATTR(topology_change_timer).attr,
331         &DEV_ATTR(gc_timer).attr,
332         &DEV_ATTR(group_addr).attr,
333         NULL
334 };
335
336 static struct attribute_group bridge_group = {
337         .name = SYSFS_BRIDGE_ATTR, /* "bridge" */
338         .attrs = bridge_attrs,
339 };
340
341 /*
342  * Add entries in sysfs onto the existing network class device
343  * for the bridge.
344  *   Adds a attribute group "bridge" containing tuning parameters.
345  *   Sub directory to hold links to interfaces.
346  *
347  * Note: the ifobj exists only to be a subdirectory
348  *   to hold links.  The ifobj exists in the same data structure
349  *   as its parent the bridge so reference counting works.
350  */
351 int dp_sysfs_add_dp(struct datapath *dp)
352 {
353         struct kobject *kobj =
354                 vport_get_kobj(rtnl_dereference(dp->ports[ODPP_LOCAL]));
355         int err;
356
357         /* Create /sys/class/net/<devname>/bridge directory. */
358         err = sysfs_create_group(kobj, &bridge_group);
359         if (err) {
360                 pr_info("%s: can't create group %s/%s\n",
361                         __func__, dp_name(dp), bridge_group.name);
362                 goto out1;
363         }
364
365         /* Create /sys/class/net/<devname>/brif directory. */
366         err = kobject_add(&dp->ifobj, kobj, SYSFS_BRIDGE_PORT_SUBDIR);
367         if (err) {
368                 pr_info("%s: can't add kobject (directory) %s/%s\n",
369                         __FUNCTION__, dp_name(dp), kobject_name(&dp->ifobj));
370                 goto out2;
371         }
372         kobject_uevent(&dp->ifobj, KOBJ_ADD);
373         return 0;
374
375  out2:
376         sysfs_remove_group(kobj, &bridge_group);
377  out1:
378         return err;
379 }
380
381 int dp_sysfs_del_dp(struct datapath *dp)
382 {
383         struct kobject *kobj =
384                 vport_get_kobj(rtnl_dereference(dp->ports[ODPP_LOCAL]));
385
386         kobject_del(&dp->ifobj);
387         sysfs_remove_group(kobj, &bridge_group);
388
389         return 0;
390 }
391 #else /* !CONFIG_SYSFS */
392 int dp_sysfs_add_dp(struct datapath *dp) { return 0; }
393 int dp_sysfs_del_dp(struct datapath *dp) { return 0; }
394 int dp_sysfs_add_if(struct vport *p) { return 0; }
395 int dp_sysfs_del_if(struct vport *p) { return 0; }
396 #endif /* !CONFIG_SYSFS */