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