Setting tag sliver-openvswitch-2.2.90-1
[sliver-openvswitch.git] / lib / vlandev.c
1 /*
2  * Copyright (c) 2011, 2013, 2014 Nicira, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <config.h>
18
19 #include "vlandev.h"
20
21 #include <errno.h>
22 #include <net/if.h>
23 #include <sys/ioctl.h>
24 #include <sys/stat.h>
25
26 #include "dummy.h"
27 #include "hash.h"
28 #include "shash.h"
29 #include "socket-util.h"
30 #include "vlog.h"
31
32 VLOG_DEFINE_THIS_MODULE(vlandev);
33
34 /* A vlandev implementation. */
35 struct vlandev_class {
36     int (*vd_refresh)(void);
37     int (*vd_add)(const char *real_dev, int vid);
38     int (*vd_del)(const char *vlan_dev);
39 };
40
41 #ifdef __linux__
42 static const struct vlandev_class vlandev_linux_class;
43 #endif
44 static const struct vlandev_class vlandev_stub_class;
45 static const struct vlandev_class vlandev_dummy_class;
46
47 /* The in-use vlandev implementation. */
48 static const struct vlandev_class *vd_class;
49
50 /* Maps from a VLAN device name (e.g. "eth0.10") to struct vlan_dev. */
51 static struct shash vlan_devs = SHASH_INITIALIZER(&vlan_devs);
52
53 /* Maps from a VLAN real device name (e.g. "eth0") to struct vlan_real_dev. */
54 static struct shash vlan_real_devs = SHASH_INITIALIZER(&vlan_real_devs);
55
56 static int vlandev_add__(const char *vlan_dev, const char *real_dev, int vid);
57 static int vlandev_del__(const char *vlan_dev);
58 static void vlandev_clear__(void);
59
60 static const struct vlandev_class *
61 vlandev_get_class(void)
62 {
63     if (!vd_class) {
64 #if __linux__
65         vd_class = &vlandev_linux_class;
66 #else
67         vd_class = &vlandev_stub_class;
68 #endif
69     }
70     return vd_class;
71 }
72
73 /* On Linux, the default implementation of VLAN devices creates and destroys
74  * Linux VLAN devices.  On other OSess, the default implementation is a
75  * nonfunctional stub.  In either case, this function replaces this default
76  * implementation by a "dummy" implementation that simply reports back whatever
77  * the client sets up with vlandev_add() and vlandev_del().
78  *
79  * Don't call this function directly; use dummy_enable() from dummy.h. */
80 void
81 vlandev_dummy_enable(void)
82 {
83     if (vd_class != &vlandev_dummy_class) {
84         vd_class = &vlandev_dummy_class;
85         vlandev_clear__();
86     }
87 }
88
89 /* Creates a new VLAN device for VLAN 'vid' on top of real Ethernet device
90  * 'real_dev'.  Returns 0 if successful, otherwise a positive errno value.  On
91  * OSes other than Linux, in the absence of dummies (see
92  * vlandev_dummy_enable()), this always fails.
93  *
94  * The name of the new VLAN device is not easily predictable, because Linux
95  * provides multiple naming schemes, does not allow the client to specify a
96  * name, and does not directly report the new VLAN device's name.  Use
97  * vlandev_refresh() then vlandev_get_name() to find out the new VLAN device's
98  * name,. */
99 int
100 vlandev_add(const char *real_dev, int vid)
101 {
102     return vlandev_get_class()->vd_add(real_dev, vid);
103 }
104
105 /* Deletes the VLAN device named 'vlan_dev'.  Returns 0 if successful,
106  * otherwise a positive errno value.  On OSes other than Linux, in the absence
107  * of dummies (see vlandev_dummy_enable()), this always fails. */
108 int
109 vlandev_del(const char *vlan_dev)
110 {
111     return vlandev_get_class()->vd_del(vlan_dev);
112 }
113
114 /* Refreshes the cache of real device to VLAN device mappings reported by
115  * vlandev_get_real_devs() and vlandev_get_name().  Without calling this
116  * function, changes made by vlandev_add() and vlandev_del() may not be
117  * reflected by vlandev_get_real_devs() and vlandev_get_name() output. */
118 int
119 vlandev_refresh(void)
120 {
121     const struct vlandev_class *class = vlandev_get_class();
122     return class->vd_refresh ? class->vd_refresh() : 0;
123 }
124
125 /* Returns a shash mapping from the name of real Ethernet devices used as the
126  * basis of VLAN devices to struct vlan_real_devs.  The caller must not modify
127  * or free anything in the returned shash.
128  *
129  * Changes made by vlandev_add() and vlandev_del() may not be reflected in this
130  * function's output without an intervening call to vlandev_refresh(). */
131 struct shash *
132 vlandev_get_real_devs(void)
133 {
134     return &vlan_real_devs;
135 }
136
137 /* Returns the name of the VLAN device for VLAN 'vid' on top of
138  * 'real_dev_name', or NULL if there is no such VLAN device.
139  *
140  * Changes made by vlandev_add() and vlandev_del() may not be reflected in this
141  * function's output without an intervening call to vlandev_refresh(). */
142 const char *
143 vlandev_get_name(const char *real_dev_name, int vid)
144 {
145     const struct vlan_real_dev *real_dev;
146
147     real_dev = shash_find_data(&vlan_real_devs, real_dev_name);
148     if (real_dev) {
149         const struct vlan_dev *vlan_dev;
150
151         HMAP_FOR_EACH_WITH_HASH (vlan_dev, hmap_node, hash_int(vid, 0),
152                                  &real_dev->vlan_devs) {
153             if (vlan_dev->vid == vid) {
154                 return vlan_dev->name;
155             }
156         }
157     }
158
159     return NULL;
160 }
161 \f
162 /* The Linux vlandev implementation. */
163
164 #ifdef __linux__
165 #include "rtnetlink-link.h"
166 #include <linux/if_vlan.h>
167 #include <linux/sockios.h>
168 #include "netdev-linux.h"
169
170 static struct nln_notifier *vlan_cache_notifier;
171 static bool cache_valid;
172
173 static void
174 vlan_cache_cb(const struct rtnetlink_link_change *change OVS_UNUSED,
175               void *aux OVS_UNUSED)
176 {
177     cache_valid = false;
178 }
179
180 static int
181 vlandev_linux_refresh(void)
182 {
183     const char *fn = "/proc/net/vlan/config";
184     char line[128];
185     FILE *stream;
186
187     if (!vlan_cache_notifier) {
188         vlan_cache_notifier = rtnetlink_link_notifier_create(vlan_cache_cb,
189                                                              NULL);
190         if (!vlan_cache_notifier) {
191             return EINVAL;
192         }
193     }
194
195     if (cache_valid) {
196         return 0;
197     }
198
199     vlandev_clear__();
200
201     /* Repopulate cache. */
202     stream = fopen(fn, "r");
203     if (!stream) {
204         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
205         int error = errno;
206         struct stat s;
207
208         if (error == ENOENT && !stat("/proc", &s)) {
209             /* Probably the vlan module just isn't loaded, and probably that's
210              * because no VLAN devices have been created.
211              *
212              * Not really an error. */
213             return 0;
214         }
215
216         VLOG_WARN_RL(&rl, "%s: open failed (%s)", fn, ovs_strerror(error));
217         return error;
218     }
219
220     while (fgets(line, sizeof line, stream)) {
221         char vlan_dev[16], real_dev[16];
222         int vid;
223
224         if (ovs_scan(line, "%15[^ |] | %d | %15s", vlan_dev, &vid, real_dev)) {
225             vlandev_add__(vlan_dev, real_dev, vid);
226         }
227     }
228     fclose(stream);
229
230     cache_valid = true;
231     return 0;
232 }
233
234 static int
235 do_vlan_ioctl(const char *netdev_name, struct vlan_ioctl_args *via,
236               int cmd, const char *cmd_name)
237 {
238     static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
239     int error;
240
241     via->cmd = cmd;
242     ovs_strlcpy(via->device1, netdev_name, sizeof via->device1);
243
244     error = af_inet_ioctl(SIOCSIFVLAN, via);
245     if (error) {
246         VLOG_WARN_RL(&rl, "%s: VLAN ioctl %s failed (%s)",
247                      netdev_name, cmd_name, ovs_strerror(error));
248     }
249     return error;
250 }
251
252 static int
253 vlandev_linux_add(const char *real_dev, int vid)
254 {
255     struct vlan_ioctl_args via;
256     int error;
257
258     memset(&via, 0, sizeof via);
259     via.u.VID = vid;
260
261     error = do_vlan_ioctl(real_dev, &via, ADD_VLAN_CMD, "ADD_VLAN_CMD");
262     if (!error) {
263         cache_valid = false;
264     }
265     return error;
266 }
267
268 static int
269 vlandev_linux_del(const char *vlan_dev)
270 {
271     struct vlan_ioctl_args via;
272     int error;
273
274     memset(&via, 0, sizeof via);
275     error = do_vlan_ioctl(vlan_dev, &via, DEL_VLAN_CMD, "DEL_VLAN_CMD");
276     if (!error) {
277         cache_valid = false;
278     }
279     return error;
280 }
281
282 static const struct vlandev_class vlandev_linux_class = {
283     vlandev_linux_refresh,
284     vlandev_linux_add,
285     vlandev_linux_del
286 };
287 #endif
288 \f
289 /* Stub implementation. */
290
291 static int
292 vlandev_stub_add(const char *real_dev OVS_UNUSED, int vid OVS_UNUSED)
293 {
294     VLOG_ERR("not supported on non-Linux platform");
295     return EOPNOTSUPP;
296 }
297
298 static int
299 vlandev_stub_del(const char *vlan_dev OVS_UNUSED)
300 {
301     VLOG_ERR("not supported on non-Linux platform");
302     return EOPNOTSUPP;
303 }
304
305 static const struct vlandev_class OVS_UNUSED vlandev_stub_class = {
306     NULL,                       /* vd_refresh */
307     vlandev_stub_add,
308     vlandev_stub_del
309 };
310 \f
311 /* Dummy implementation. */
312
313 static int
314 vlandev_dummy_add(const char *real_dev, int vid)
315 {
316     char name[IFNAMSIZ];
317
318     if (snprintf(name, sizeof name, "%s.%d", real_dev, vid) >= sizeof name) {
319         return ENAMETOOLONG;
320     }
321     return vlandev_add__(name, real_dev, vid);
322 }
323
324 static int
325 vlandev_dummy_del(const char *vlan_dev)
326 {
327     return vlandev_del__(vlan_dev);
328 }
329
330 static const struct vlandev_class vlandev_dummy_class = {
331     NULL,                       /* vd_refresh */
332     vlandev_dummy_add,
333     vlandev_dummy_del
334 };
335 \f
336 static int
337 vlandev_add__(const char *vlan_dev, const char *real_dev, int vid)
338 {
339     uint32_t vid_hash = hash_int(vid, 0);
340     struct vlan_real_dev *vrd;
341     struct vlan_dev *vd;
342
343     if (vid < 0 || vid > 4095) {
344         return EINVAL;
345     } else if (shash_find(&vlan_devs, vlan_dev)) {
346         return EEXIST;
347     }
348
349     vrd = shash_find_data(&vlan_real_devs, real_dev);
350     if (!vrd) {
351         vrd = xmalloc(sizeof *vrd);
352         vrd->name = xstrdup(real_dev);
353         hmap_init(&vrd->vlan_devs);
354         shash_add_nocopy(&vlan_real_devs, vrd->name, vrd);
355     } else {
356         HMAP_FOR_EACH_WITH_HASH (vd, hmap_node, vid_hash, &vrd->vlan_devs) {
357             if (vd->vid == vid) {
358                 return EEXIST;
359             }
360         }
361     }
362
363     vd = xmalloc(sizeof *vd);
364     hmap_insert(&vrd->vlan_devs, &vd->hmap_node, vid_hash);
365     vd->name = xstrdup(vlan_dev);
366     vd->vid = vid;
367     vd->real_dev = vrd;
368     shash_add_nocopy(&vlan_devs, vd->name, vd);
369
370     return 0;
371 }
372
373 static int
374 vlandev_del__(const char *vlan_dev)
375 {
376     struct shash_node *vd_node = shash_find(&vlan_devs, vlan_dev);
377     if (vd_node) {
378         struct vlan_dev *vd = vd_node->data;
379         struct vlan_real_dev *vrd = vd->real_dev;
380
381         hmap_remove(&vrd->vlan_devs, &vd->hmap_node);
382         if (hmap_is_empty(&vrd->vlan_devs)) {
383             shash_find_and_delete_assert(&vlan_real_devs, vrd->name);
384             free(vrd);
385         }
386
387         shash_delete(&vlan_devs, vd_node);
388         free(vd);
389
390         return 0;
391     } else {
392         return ENOENT;
393     }
394 }
395
396 /* Clear 'vlan_devs' and 'vlan_real_devs' in preparation for repopulating. */
397 static void
398 vlandev_clear__(void)
399 {
400     /* We do not free the 'name' members of struct vlan_dev and struct
401      * vlan_real_dev, because the "shash"es own them.. */
402     struct shash_node *node;
403
404     shash_clear_free_data(&vlan_devs);
405     SHASH_FOR_EACH (node, &vlan_real_devs) {
406         struct vlan_real_dev *vrd = node->data;
407
408         hmap_destroy(&vrd->vlan_devs);
409     }
410     shash_clear_free_data(&vlan_real_devs);
411 }