datapath: Add generic virtual port layer.
[sliver-openvswitch.git] / datapath / dp_sysfs_if.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 /*
10  *      Sysfs attributes of bridge ports for Open vSwitch
11  *
12  *  This has been shamelessly copied from the kernel sources.
13  */
14
15 #include <linux/capability.h>
16 #include <linux/kernel.h>
17 #include <linux/netdevice.h>
18 #include <linux/if_bridge.h>
19 #include <linux/rtnetlink.h>
20 #include <linux/spinlock.h>
21
22 #include "datapath.h"
23 #include "dp_sysfs.h"
24 #include "vport.h"
25
26 #ifdef CONFIG_SYSFS
27
28 struct brport_attribute {
29         struct attribute        attr;
30         ssize_t (*show)(struct dp_port *, char *);
31         ssize_t (*store)(struct dp_port *, unsigned long);
32 };
33
34 #define BRPORT_ATTR(_name,_mode,_show,_store)                   \
35 struct brport_attribute brport_attr_##_name = {                 \
36         .attr = {.name = __stringify(_name),                    \
37                  .mode = _mode,                                 \
38                  .owner = THIS_MODULE, },                       \
39         .show   = _show,                                        \
40         .store  = _store,                                       \
41 };
42
43 static ssize_t show_path_cost(struct dp_port *p, char *buf)
44 {
45 #if 0
46         return sprintf(buf, "%d\n", p->path_cost);
47 #else
48         return sprintf(buf, "%d\n", 0);
49 #endif
50 }
51 static ssize_t store_path_cost(struct dp_port *p, unsigned long v)
52 {
53 #if 0
54         br_stp_set_path_cost(p, v);
55 #endif
56         return 0;
57 }
58 static BRPORT_ATTR(path_cost, S_IRUGO | S_IWUSR,
59                    show_path_cost, store_path_cost);
60
61 static ssize_t show_priority(struct dp_port *p, char *buf)
62 {
63 #if 0
64         return sprintf(buf, "%d\n", p->priority);
65 #else
66         return sprintf(buf, "%d\n", 0);
67 #endif
68 }
69 static ssize_t store_priority(struct dp_port *p, unsigned long v)
70 {
71 #if 0
72         if (v >= (1<<(16-BR_PORT_BITS)))
73                 return -ERANGE;
74         br_stp_set_port_priority(p, v);
75 #endif
76         return 0;
77 }
78 static BRPORT_ATTR(priority, S_IRUGO | S_IWUSR,
79                          show_priority, store_priority);
80
81 static ssize_t show_designated_root(struct dp_port *p, char *buf)
82 {
83 #if 0
84         return br_show_bridge_id(buf, &p->designated_root);
85 #else
86         return sprintf(buf, "0000.010203040506\n");
87 #endif
88 }
89 static BRPORT_ATTR(designated_root, S_IRUGO, show_designated_root, NULL);
90
91 static ssize_t show_designated_bridge(struct dp_port *p, char *buf)
92 {
93 #if 0
94         return br_show_bridge_id(buf, &p->designated_bridge);
95 #else
96         return sprintf(buf, "0000.060504030201\n");
97 #endif
98 }
99 static BRPORT_ATTR(designated_bridge, S_IRUGO, show_designated_bridge, NULL);
100
101 static ssize_t show_designated_port(struct dp_port *p, char *buf)
102 {
103 #if 0
104         return sprintf(buf, "%d\n", p->designated_port);
105 #else
106         return sprintf(buf, "%d\n", 0);
107 #endif
108 }
109 static BRPORT_ATTR(designated_port, S_IRUGO, show_designated_port, NULL);
110
111 static ssize_t show_designated_cost(struct dp_port *p, char *buf)
112 {
113 #if 0
114         return sprintf(buf, "%d\n", p->designated_cost);
115 #else
116         return sprintf(buf, "%d\n", 0);
117 #endif
118 }
119 static BRPORT_ATTR(designated_cost, S_IRUGO, show_designated_cost, NULL);
120
121 static ssize_t show_port_id(struct dp_port *p, char *buf)
122 {
123 #if 0
124         return sprintf(buf, "0x%x\n", p->port_id);
125 #else
126         return sprintf(buf, "0x%x\n", 0);
127 #endif
128 }
129 static BRPORT_ATTR(port_id, S_IRUGO, show_port_id, NULL);
130
131 static ssize_t show_port_no(struct dp_port *p, char *buf)
132 {
133         return sprintf(buf, "0x%x\n", p->port_no);
134 }
135
136 static BRPORT_ATTR(port_no, S_IRUGO, show_port_no, NULL);
137
138 static ssize_t show_change_ack(struct dp_port *p, char *buf)
139 {
140 #if 0
141         return sprintf(buf, "%d\n", p->topology_change_ack);
142 #else
143         return sprintf(buf, "%d\n", 0);
144 #endif
145 }
146 static BRPORT_ATTR(change_ack, S_IRUGO, show_change_ack, NULL);
147
148 static ssize_t show_config_pending(struct dp_port *p, char *buf)
149 {
150 #if 0
151         return sprintf(buf, "%d\n", p->config_pending);
152 #else
153         return sprintf(buf, "%d\n", 0);
154 #endif
155 }
156 static BRPORT_ATTR(config_pending, S_IRUGO, show_config_pending, NULL);
157
158 static ssize_t show_port_state(struct dp_port *p, char *buf)
159 {
160 #if 0
161         return sprintf(buf, "%d\n", p->state);
162 #else
163         return sprintf(buf, "%d\n", 0);
164 #endif
165 }
166 static BRPORT_ATTR(state, S_IRUGO, show_port_state, NULL);
167
168 static ssize_t show_message_age_timer(struct dp_port *p,
169                                             char *buf)
170 {
171 #if 0
172         return sprintf(buf, "%ld\n", br_timer_value(&p->message_age_timer));
173 #else
174         return sprintf(buf, "%d\n", 0);
175 #endif
176 }
177 static BRPORT_ATTR(message_age_timer, S_IRUGO, show_message_age_timer, NULL);
178
179 static ssize_t show_forward_delay_timer(struct dp_port *p,
180                                             char *buf)
181 {
182 #if 0
183         return sprintf(buf, "%ld\n", br_timer_value(&p->forward_delay_timer));
184 #else
185         return sprintf(buf, "%d\n", 0);
186 #endif
187 }
188 static BRPORT_ATTR(forward_delay_timer, S_IRUGO, show_forward_delay_timer, NULL);
189
190 static ssize_t show_hold_timer(struct dp_port *p,
191                                             char *buf)
192 {
193 #if 0
194         return sprintf(buf, "%ld\n", br_timer_value(&p->hold_timer));
195 #else
196         return sprintf(buf, "%d\n", 0);
197 #endif
198 }
199 static BRPORT_ATTR(hold_timer, S_IRUGO, show_hold_timer, NULL);
200
201 static struct brport_attribute *brport_attrs[] = {
202         &brport_attr_path_cost,
203         &brport_attr_priority,
204         &brport_attr_port_id,
205         &brport_attr_port_no,
206         &brport_attr_designated_root,
207         &brport_attr_designated_bridge,
208         &brport_attr_designated_port,
209         &brport_attr_designated_cost,
210         &brport_attr_state,
211         &brport_attr_change_ack,
212         &brport_attr_config_pending,
213         &brport_attr_message_age_timer,
214         &brport_attr_forward_delay_timer,
215         &brport_attr_hold_timer,
216         NULL
217 };
218
219 #define to_brport_attr(_at) container_of(_at, struct brport_attribute, attr)
220 #define to_brport(obj)  container_of(obj, struct dp_port, kobj)
221
222 static ssize_t brport_show(struct kobject * kobj,
223                            struct attribute * attr, char * buf)
224 {
225         struct brport_attribute * brport_attr = to_brport_attr(attr);
226         struct dp_port * p = to_brport(kobj);
227
228         return brport_attr->show(p, buf);
229 }
230
231 static ssize_t brport_store(struct kobject * kobj,
232                             struct attribute * attr,
233                             const char * buf, size_t count)
234 {
235         struct dp_port * p = to_brport(kobj);
236 #if 0
237         struct brport_attribute * brport_attr = to_brport_attr(attr);
238         char *endp;
239         unsigned long val;
240 #endif
241         ssize_t ret = -EINVAL;
242
243         if (!capable(CAP_NET_ADMIN))
244                 return -EPERM;
245
246 #if 0
247         val = simple_strtoul(buf, &endp, 0);
248         if (endp != buf) {
249                 rtnl_lock();
250                 if (p->dev && p->br && brport_attr->store) {
251                         spin_lock_bh(&p->br->lock);
252                         ret = brport_attr->store(p, val);
253                         spin_unlock_bh(&p->br->lock);
254                         if (ret == 0)
255                                 ret = count;
256                 }
257                 rtnl_unlock();
258         }
259 #else
260         printk("%s: xxx writing port parms not supported yet!\n", 
261                dp_name(p->dp));
262 #endif
263         return ret;
264 }
265
266 struct sysfs_ops brport_sysfs_ops = {
267         .show = brport_show,
268         .store = brport_store,
269 };
270
271 /*
272  * Add sysfs entries to ethernet device added to a bridge.
273  * Creates a brport subdirectory with bridge attributes.
274  * Puts symlink in bridge's brport subdirectory
275  */
276 int dp_sysfs_add_if(struct dp_port *p)
277 {
278         struct kobject *kobj = vport_get_kobj(p->vport);
279         struct datapath *dp = p->dp;
280         struct brport_attribute **a;
281         int err;
282
283         /* Create /sys/class/net/<devname>/brport directory. */
284         if (!kobj)
285                 return -ENOENT;
286
287         err = kobject_add(&p->kobj, kobj, SYSFS_BRIDGE_PORT_ATTR);
288         if (err)
289                 goto err;
290
291         /* Create symlink from /sys/class/net/<devname>/brport/bridge to
292          * /sys/class/net/<bridgename>. */
293         err = sysfs_create_link(&p->kobj, vport_get_kobj(dp->ports[ODPP_LOCAL]->vport),
294                                 SYSFS_BRIDGE_PORT_LINK); /* "bridge" */
295         if (err)
296                 goto err_del;
297
298         /* Populate /sys/class/net/<devname>/brport directory with files. */
299         for (a = brport_attrs; *a; ++a) {
300                 err = sysfs_create_file(&p->kobj, &((*a)->attr));
301                 if (err)
302                         goto err_del;
303         }
304
305         /* Create symlink from /sys/class/net/<bridgename>/brif/<devname> to
306          * /sys/class/net/<devname>/brport.  */
307         err = sysfs_create_link(&dp->ifobj, &p->kobj, vport_get_name(p->vport));
308         if (err)
309                 goto err_del;
310         strcpy(p->linkname, vport_get_name(p->vport));
311
312         kobject_uevent(&p->kobj, KOBJ_ADD);
313
314         return 0;
315
316 err_del:
317         kobject_del(&p->kobj);
318 err:
319         p->linkname[0] = 0;
320         return err;
321 }
322
323 int dp_sysfs_del_if(struct dp_port *p)
324 {
325         if (p->linkname[0]) {
326                 sysfs_remove_link(&p->dp->ifobj, p->linkname);
327                 kobject_uevent(&p->kobj, KOBJ_REMOVE);
328                 kobject_del(&p->kobj);
329                 p->linkname[0] = '\0';
330         }
331         return 0;
332 }
333 #endif /* CONFIG_SYSFS */