2 * Copyright (c) 2011, 2013 Nicira, Inc.
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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
23 #include <sys/ioctl.h>
31 VLOG_DEFINE_THIS_MODULE(vlandev
);
33 /* A vlandev implementation. */
34 struct vlandev_class
{
35 int (*vd_refresh
)(void);
36 int (*vd_add
)(const char *real_dev
, int vid
);
37 int (*vd_del
)(const char *vlan_dev
);
41 static const struct vlandev_class vlandev_linux_class
;
43 static const struct vlandev_class vlandev_stub_class
;
44 static const struct vlandev_class vlandev_dummy_class
;
46 /* The in-use vlandev implementation. */
47 static const struct vlandev_class
*vd_class
;
49 /* Maps from a VLAN device name (e.g. "eth0.10") to struct vlan_dev. */
50 static struct shash vlan_devs
= SHASH_INITIALIZER(&vlan_devs
);
52 /* Maps from a VLAN real device name (e.g. "eth0") to struct vlan_real_dev. */
53 static struct shash vlan_real_devs
= SHASH_INITIALIZER(&vlan_real_devs
);
55 static int vlandev_add__(const char *vlan_dev
, const char *real_dev
, int vid
);
56 static int vlandev_del__(const char *vlan_dev
);
57 static void vlandev_clear__(void);
59 static const struct vlandev_class
*
60 vlandev_get_class(void)
64 vd_class
= &vlandev_linux_class
;
66 vd_class
= &vlandev_stub_class
;
72 /* On Linux, the default implementation of VLAN devices creates and destroys
73 * Linux VLAN devices. On other OSess, the default implementation is a
74 * nonfunctional stub. In either case, this function replaces this default
75 * implementation by a "dummy" implementation that simply reports back whatever
76 * the client sets up with vlandev_add() and vlandev_del().
78 * Don't call this function directly; use dummy_enable() from dummy.h. */
80 vlandev_dummy_enable(void)
82 if (vd_class
!= &vlandev_dummy_class
) {
83 vd_class
= &vlandev_dummy_class
;
88 /* Creates a new VLAN device for VLAN 'vid' on top of real Ethernet device
89 * 'real_dev'. Returns 0 if successful, otherwise a positive errno value. On
90 * OSes other than Linux, in the absence of dummies (see
91 * vlandev_dummy_enable()), this always fails.
93 * The name of the new VLAN device is not easily predictable, because Linux
94 * provides multiple naming schemes, does not allow the client to specify a
95 * name, and does not directly report the new VLAN device's name. Use
96 * vlandev_refresh() then vlandev_get_name() to find out the new VLAN device's
99 vlandev_add(const char *real_dev
, int vid
)
101 return vlandev_get_class()->vd_add(real_dev
, vid
);
104 /* Deletes the VLAN device named 'vlan_dev'. Returns 0 if successful,
105 * otherwise a positive errno value. On OSes other than Linux, in the absence
106 * of dummies (see vlandev_dummy_enable()), this always fails. */
108 vlandev_del(const char *vlan_dev
)
110 return vlandev_get_class()->vd_del(vlan_dev
);
113 /* Refreshes the cache of real device to VLAN device mappings reported by
114 * vlandev_get_real_devs() and vlandev_get_name(). Without calling this
115 * function, changes made by vlandev_add() and vlandev_del() may not be
116 * reflected by vlandev_get_real_devs() and vlandev_get_name() output. */
118 vlandev_refresh(void)
120 const struct vlandev_class
*class = vlandev_get_class();
121 return class->vd_refresh
? class->vd_refresh() : 0;
124 /* Returns a shash mapping from the name of real Ethernet devices used as the
125 * basis of VLAN devices to struct vlan_real_devs. The caller must not modify
126 * or free anything in the returned shash.
128 * Changes made by vlandev_add() and vlandev_del() may not be reflected in this
129 * function's output without an intervening call to vlandev_refresh(). */
131 vlandev_get_real_devs(void)
133 return &vlan_real_devs
;
136 /* Returns the name of the VLAN device for VLAN 'vid' on top of
137 * 'real_dev_name', or NULL if there is no such VLAN device.
139 * Changes made by vlandev_add() and vlandev_del() may not be reflected in this
140 * function's output without an intervening call to vlandev_refresh(). */
142 vlandev_get_name(const char *real_dev_name
, int vid
)
144 const struct vlan_real_dev
*real_dev
;
146 real_dev
= shash_find_data(&vlan_real_devs
, real_dev_name
);
148 const struct vlan_dev
*vlan_dev
;
150 HMAP_FOR_EACH_WITH_HASH (vlan_dev
, hmap_node
, hash_int(vid
, 0),
151 &real_dev
->vlan_devs
) {
152 if (vlan_dev
->vid
== vid
) {
153 return vlan_dev
->name
;
161 /* The Linux vlandev implementation. */
163 #ifdef LINUX_DATAPATH
164 #include "rtnetlink-link.h"
165 #include <linux/if_vlan.h>
166 #include <linux/sockios.h>
167 #include "netdev-linux.h"
169 static struct nln_notifier
*vlan_cache_notifier
;
170 static bool cache_valid
;
173 vlan_cache_cb(const struct rtnetlink_link_change
*change OVS_UNUSED
,
174 void *aux OVS_UNUSED
)
180 vlandev_linux_refresh(void)
182 const char *fn
= "/proc/net/vlan/config";
186 if (!vlan_cache_notifier
) {
187 vlan_cache_notifier
= rtnetlink_link_notifier_create(vlan_cache_cb
,
189 if (!vlan_cache_notifier
) {
200 /* Repopulate cache. */
201 stream
= fopen(fn
, "r");
203 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(1, 1);
207 if (error
== ENOENT
&& !stat("/proc", &s
)) {
208 /* Probably the vlan module just isn't loaded, and probably that's
209 * because no VLAN devices have been created.
211 * Not really an error. */
215 VLOG_WARN_RL(&rl
, "%s: open failed (%s)", fn
, ovs_strerror(error
));
219 while (fgets(line
, sizeof line
, stream
)) {
220 char vlan_dev
[16], real_dev
[16];
223 if (sscanf(line
, "%15[^ |] | %d | %15s",
224 vlan_dev
, &vid
, real_dev
) == 3) {
225 vlandev_add__(vlan_dev
, real_dev
, vid
);
235 do_vlan_ioctl(const char *netdev_name
, struct vlan_ioctl_args
*via
,
236 int cmd
, const char *cmd_name
)
238 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(1, 1);
243 ovs_strlcpy(via
->device1
, netdev_name
, sizeof via
->device1
);
245 sock
= netdev_linux_get_af_inet_sock();
250 error
= ioctl(sock
, SIOCSIFVLAN
, via
) < 0 ? errno
: 0;
252 VLOG_WARN_RL(&rl
, "%s: VLAN ioctl %s failed (%s)",
253 netdev_name
, cmd_name
, ovs_strerror(error
));
259 vlandev_linux_add(const char *real_dev
, int vid
)
261 struct vlan_ioctl_args via
;
264 memset(&via
, 0, sizeof via
);
267 error
= do_vlan_ioctl(real_dev
, &via
, ADD_VLAN_CMD
, "ADD_VLAN_CMD");
275 vlandev_linux_del(const char *vlan_dev
)
277 struct vlan_ioctl_args via
;
280 memset(&via
, 0, sizeof via
);
281 error
= do_vlan_ioctl(vlan_dev
, &via
, DEL_VLAN_CMD
, "DEL_VLAN_CMD");
288 static const struct vlandev_class vlandev_linux_class
= {
289 vlandev_linux_refresh
,
295 /* Stub implementation. */
298 vlandev_stub_add(const char *real_dev OVS_UNUSED
, int vid OVS_UNUSED
)
300 VLOG_ERR("not supported on non-Linux platform");
305 vlandev_stub_del(const char *vlan_dev OVS_UNUSED
)
307 VLOG_ERR("not supported on non-Linux platform");
311 static const struct vlandev_class vlandev_stub_class
= {
312 NULL
, /* vd_refresh */
317 /* Dummy implementation. */
320 vlandev_dummy_add(const char *real_dev
, int vid
)
324 if (snprintf(name
, sizeof name
, "%s.%d", real_dev
, vid
) >= sizeof name
) {
327 return vlandev_add__(name
, real_dev
, vid
);
331 vlandev_dummy_del(const char *vlan_dev
)
333 return vlandev_del__(vlan_dev
);
336 static const struct vlandev_class vlandev_dummy_class
= {
337 NULL
, /* vd_refresh */
343 vlandev_add__(const char *vlan_dev
, const char *real_dev
, int vid
)
345 uint32_t vid_hash
= hash_int(vid
, 0);
346 struct vlan_real_dev
*vrd
;
349 if (vid
< 0 || vid
> 4095) {
351 } else if (shash_find(&vlan_devs
, vlan_dev
)) {
355 vrd
= shash_find_data(&vlan_real_devs
, real_dev
);
357 vrd
= xmalloc(sizeof *vrd
);
358 vrd
->name
= xstrdup(real_dev
);
359 hmap_init(&vrd
->vlan_devs
);
360 shash_add_nocopy(&vlan_real_devs
, vrd
->name
, vrd
);
362 HMAP_FOR_EACH_WITH_HASH (vd
, hmap_node
, vid_hash
, &vrd
->vlan_devs
) {
363 if (vd
->vid
== vid
) {
369 vd
= xmalloc(sizeof *vd
);
370 hmap_insert(&vrd
->vlan_devs
, &vd
->hmap_node
, vid_hash
);
371 vd
->name
= xstrdup(vlan_dev
);
374 shash_add_nocopy(&vlan_devs
, vd
->name
, vd
);
380 vlandev_del__(const char *vlan_dev
)
382 struct shash_node
*vd_node
= shash_find(&vlan_devs
, vlan_dev
);
384 struct vlan_dev
*vd
= vd_node
->data
;
385 struct vlan_real_dev
*vrd
= vd
->real_dev
;
387 hmap_remove(&vrd
->vlan_devs
, &vd
->hmap_node
);
388 if (hmap_is_empty(&vrd
->vlan_devs
)) {
389 shash_find_and_delete_assert(&vlan_real_devs
, vrd
->name
);
393 shash_delete(&vlan_devs
, vd_node
);
402 /* Clear 'vlan_devs' and 'vlan_real_devs' in preparation for repopulating. */
404 vlandev_clear__(void)
406 /* We do not free the 'name' members of struct vlan_dev and struct
407 * vlan_real_dev, because the "shash"es own them.. */
408 struct shash_node
*node
;
410 shash_clear_free_data(&vlan_devs
);
411 SHASH_FOR_EACH (node
, &vlan_real_devs
) {
412 struct vlan_real_dev
*vrd
= node
->data
;
414 hmap_destroy(&vrd
->vlan_devs
);
416 shash_clear_free_data(&vlan_real_devs
);