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