datapath: Slim down the vport interface.
[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                         pr_warning("%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         pr_info("%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         pr_info("%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         pr_info("%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         pr_info("%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                 pr_info("%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         pr_info("%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->ops->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],
229                                  addr[4], addr[5]);
230         } else
231                 result = -ENODEV;
232
233         rcu_read_unlock();
234
235         return result;
236 }
237 static INTERNAL_DEVICE_ATTR(bridge_id, S_IRUGO, show_bridge_id, NULL);
238
239 static ssize_t show_root_port(DEVICE_PARAMS, char *buf)
240 {
241         return sprintf(buf, "%d\n", 0);
242 }
243 static INTERNAL_DEVICE_ATTR(root_port, S_IRUGO, show_root_port, NULL);
244
245 static ssize_t show_root_path_cost(DEVICE_PARAMS, char *buf)
246 {
247         return sprintf(buf, "%d\n", 0);
248 }
249 static INTERNAL_DEVICE_ATTR(root_path_cost, S_IRUGO, show_root_path_cost, NULL);
250
251 static ssize_t show_topology_change(DEVICE_PARAMS, char *buf)
252 {
253         return sprintf(buf, "%d\n", 0);
254 }
255 static INTERNAL_DEVICE_ATTR(topology_change, S_IRUGO, show_topology_change, NULL);
256
257 static ssize_t show_topology_change_detected(DEVICE_PARAMS, char *buf)
258 {
259         return sprintf(buf, "%d\n", 0);
260 }
261 static INTERNAL_DEVICE_ATTR(topology_change_detected, S_IRUGO,
262                    show_topology_change_detected, NULL);
263
264 static ssize_t show_hello_timer(DEVICE_PARAMS, char *buf)
265 {
266         return sprintf(buf, "%d\n", 0);
267 }
268 static INTERNAL_DEVICE_ATTR(hello_timer, S_IRUGO, show_hello_timer, NULL);
269
270 static ssize_t show_tcn_timer(DEVICE_PARAMS, char *buf)
271 {
272         return sprintf(buf, "%d\n", 0);
273 }
274 static INTERNAL_DEVICE_ATTR(tcn_timer, S_IRUGO, show_tcn_timer, NULL);
275
276 static ssize_t show_topology_change_timer(DEVICE_PARAMS, char *buf)
277 {
278         return sprintf(buf, "%d\n", 0);
279 }
280 static INTERNAL_DEVICE_ATTR(topology_change_timer, S_IRUGO, show_topology_change_timer,
281                    NULL);
282
283 static ssize_t show_gc_timer(DEVICE_PARAMS, char *buf)
284 {
285         return sprintf(buf, "%d\n", 0);
286 }
287 static INTERNAL_DEVICE_ATTR(gc_timer, S_IRUGO, show_gc_timer, NULL);
288
289 static ssize_t show_group_addr(DEVICE_PARAMS, char *buf)
290 {
291         return sprintf(buf, "00:01:02:03:04:05\n");
292 }
293
294 static ssize_t store_group_addr(DEVICE_PARAMS,
295                                 const char *buf, size_t len)
296 {
297         struct datapath *dp;
298         ssize_t result = len;
299
300         rcu_read_lock();
301
302         dp = sysfs_get_dp(to_net_dev(d));
303         if (dp)
304                 pr_info("%s: xxx attempt to store_group_addr()\n",
305                        dp_name(dp));
306         else
307                 result = -ENODEV;
308
309         rcu_read_unlock();
310
311         return result;
312 }
313
314 static INTERNAL_DEVICE_ATTR(group_addr, S_IRUGO | S_IWUSR,
315                    show_group_addr, store_group_addr);
316
317 static struct attribute *bridge_attrs[] = {
318         &DEV_ATTR(forward_delay).attr,
319         &DEV_ATTR(hello_time).attr,
320         &DEV_ATTR(max_age).attr,
321         &DEV_ATTR(ageing_time).attr,
322         &DEV_ATTR(stp_state).attr,
323         &DEV_ATTR(priority).attr,
324         &DEV_ATTR(bridge_id).attr,
325         &DEV_ATTR(root_id).attr,
326         &DEV_ATTR(root_path_cost).attr,
327         &DEV_ATTR(root_port).attr,
328         &DEV_ATTR(topology_change).attr,
329         &DEV_ATTR(topology_change_detected).attr,
330         &DEV_ATTR(hello_timer).attr,
331         &DEV_ATTR(tcn_timer).attr,
332         &DEV_ATTR(topology_change_timer).attr,
333         &DEV_ATTR(gc_timer).attr,
334         &DEV_ATTR(group_addr).attr,
335         NULL
336 };
337
338 static struct attribute_group bridge_group = {
339         .name = SYSFS_BRIDGE_ATTR, /* "bridge" */
340         .attrs = bridge_attrs,
341 };
342
343 /*
344  * Add entries in sysfs onto the existing network class device
345  * for the bridge.
346  *   Adds a attribute group "bridge" containing tuning parameters.
347  *   Sub directory to hold links to interfaces.
348  *
349  * Note: the ifobj exists only to be a subdirectory
350  *   to hold links.  The ifobj exists in the same data structure
351  *   as its parent the bridge so reference counting works.
352  */
353 int dp_sysfs_add_dp(struct datapath *dp)
354 {
355         struct vport *vport = rtnl_dereference(dp->ports[OVSP_LOCAL]);
356         struct kobject *kobj = vport->ops->get_kobj(vport);
357         int err;
358
359         /* Create /sys/class/net/<devname>/bridge directory. */
360         err = sysfs_create_group(kobj, &bridge_group);
361         if (err) {
362                 pr_info("%s: can't create group %s/%s\n",
363                         __func__, dp_name(dp), bridge_group.name);
364                 goto out1;
365         }
366
367         /* Create /sys/class/net/<devname>/brif directory. */
368         err = kobject_add(&dp->ifobj, kobj, SYSFS_BRIDGE_PORT_SUBDIR);
369         if (err) {
370                 pr_info("%s: can't add kobject (directory) %s/%s\n",
371                         __func__, dp_name(dp), kobject_name(&dp->ifobj));
372                 goto out2;
373         }
374         kobject_uevent(&dp->ifobj, KOBJ_ADD);
375         return 0;
376
377  out2:
378         sysfs_remove_group(kobj, &bridge_group);
379  out1:
380         return err;
381 }
382
383 int dp_sysfs_del_dp(struct datapath *dp)
384 {
385         struct vport *vport = rtnl_dereference(dp->ports[OVSP_LOCAL]);
386         struct kobject *kobj = vport->ops->get_kobj(vport);
387
388         kobject_del(&dp->ifobj);
389         sysfs_remove_group(kobj, &bridge_group);
390
391         return 0;
392 }
393 #else /* !CONFIG_SYSFS */
394 int dp_sysfs_add_dp(struct datapath *dp) { return 0; }
395 int dp_sysfs_del_dp(struct datapath *dp) { return 0; }
396 int dp_sysfs_add_if(struct vport *p) { return 0; }
397 int dp_sysfs_del_if(struct vport *p) { return 0; }
398 #endif /* !CONFIG_SYSFS */