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