Looks good. Ethan
On Tue, Nov 15, 2011 at 17:17, Ben Pfaff <b...@nicira.com> wrote: > --- > lib/automake.mk | 2 + > lib/netdev-linux.c | 8 ++ > lib/netdev-linux.h | 1 + > lib/vlandev.c | 213 > ++++++++++++++++++++++++++++++++++++++++++++++++++++ > lib/vlandev.h | 52 +++++++++++++ > 5 files changed, 276 insertions(+), 0 deletions(-) > create mode 100644 lib/vlandev.c > create mode 100644 lib/vlandev.h > > diff --git a/lib/automake.mk b/lib/automake.mk > index 6484518..8a82a72 100644 > --- a/lib/automake.mk > +++ b/lib/automake.mk > @@ -182,6 +182,8 @@ lib_libopenvswitch_a_SOURCES = \ > lib/vconn.h \ > lib/vlan-bitmap.c \ > lib/vlan-bitmap.h \ > + lib/vlandev.c \ > + lib/vlandev.h \ > lib/vlog.c \ > lib/vlog.h > nodist_lib_libopenvswitch_a_SOURCES = \ > diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c > index 134d99b..44167da 100644 > --- a/lib/netdev-linux.c > +++ b/lib/netdev-linux.c > @@ -3932,6 +3932,14 @@ tc_calc_buffer(unsigned int Bps, int mtu, uint64_t > burst_bytes) > > /* Linux-only functions declared in netdev-linux.h */ > > +/* Returns a fd for an AF_INET socket or a negative errno value. */ > +int > +netdev_linux_get_af_inet_sock(void) > +{ > + int error = netdev_linux_init(); > + return error ? -error : af_inet_sock; > +} > + > /* Modifies the 'flag' bit in ethtool's flags field for 'netdev'. If > * 'enable' is true, the bit is set. Otherwise, it is cleared. */ > int > diff --git a/lib/netdev-linux.h b/lib/netdev-linux.h > index c8caa4e..21a2db2 100644 > --- a/lib/netdev-linux.h > +++ b/lib/netdev-linux.h > @@ -29,5 +29,6 @@ struct rtnl_link_stats; > > int netdev_linux_ethtool_set_flag(struct netdev *netdev, uint32_t flag, > const char *flag_name, bool enable); > +int netdev_linux_get_af_inet_sock(void); > > #endif /* netdev-linux.h */ > diff --git a/lib/vlandev.c b/lib/vlandev.c > new file mode 100644 > index 0000000..2e5bb79 > --- /dev/null > +++ b/lib/vlandev.c > @@ -0,0 +1,213 @@ > +/* > + * Copyright (c) 2011 Nicira Networks. > + * > + * Licensed under the Apache License, Version 2.0 (the "License"); > + * you may not use this file except in compliance with the License. > + * You may obtain a copy of the License at: > + * > + * http://www.apache.org/licenses/LICENSE-2.0 > + * > + * Unless required by applicable law or agreed to in writing, software > + * distributed under the License is distributed on an "AS IS" BASIS, > + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. > + * See the License for the specific language governing permissions and > + * limitations under the License. > + */ > + > +#include <config.h> > + > +#include "vlandev.h" > + > +#include <errno.h> > +#include <sys/ioctl.h> > +#include <sys/stat.h> > + > +#include "hash.h" > +#include "rtnetlink-link.h" > +#include "shash.h" > +#include "vlog.h" > + > +VLOG_DEFINE_THIS_MODULE(vlandev); > + > +#ifdef __linux__ > +#include <linux/if_vlan.h> > +#include <linux/sockios.h> > +#include "netdev-linux.h" > + > +static struct nln_notifier *vlan_cache_notifier; > +static struct shash vlan_devs = SHASH_INITIALIZER(&vlan_devs); > +static struct shash vlan_real_devs = SHASH_INITIALIZER(&vlan_real_devs); > +static bool cache_valid; > + > +static void > +vlan_cache_cb(const struct rtnetlink_link_change *change OVS_UNUSED, > + void *aux OVS_UNUSED) > +{ > + cache_valid = false; > +} > + > +int > +vlandev_refresh(void) > +{ > + const char *fn = "/proc/net/vlan/config"; > + struct shash_node *node; > + char line[128]; > + FILE *stream; > + > + if (!vlan_cache_notifier) { > + vlan_cache_notifier = rtnetlink_link_notifier_create(vlan_cache_cb, > + NULL); > + if (!vlan_cache_notifier) { > + return EINVAL; > + } > + } > + > + if (cache_valid) { > + return 0; > + } > + > + /* Free old cache. > + * > + * The 'name' members point to strings owned by the "shash"es so we do > not > + * free them ourselves. */ > + shash_clear_free_data(&vlan_devs); > + SHASH_FOR_EACH (node, &vlan_real_devs) { > + struct vlan_real_dev *vrd = node->data; > + > + hmap_destroy(&vrd->vlan_devs); > + } > + shash_clear_free_data(&vlan_real_devs); > + > + /* Repopulate cache. */ > + stream = fopen(fn, "r"); > + if (!stream) { > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); > + int error = errno; > + struct stat s; > + > + if (error == ENOENT && !stat("/proc", &s)) { > + /* Probably the vlan module just isn't loaded, and probably > that's > + * because no VLAN devices have been created. > + * > + * Not really an error. */ > + return 0; > + } > + > + VLOG_WARN_RL(&rl, "%s: open failed (%s)", fn, strerror(error)); > + return error; > + } > + > + while (fgets(line, sizeof line, stream)) { > + char vlan_dev[16], real_dev[16]; > + int vid; > + > + if (sscanf(line, "%15[^ |] | %d | %15s", vlan_dev, &vid, real_dev) > == 3 > + && vid >= 0 && vid <= 4095 > + && !shash_find(&vlan_devs, vlan_dev)) { > + struct vlan_real_dev *vrd; > + struct vlan_dev *vd; > + > + vrd = shash_find_data(&vlan_real_devs, real_dev); > + if (!vrd) { > + vrd = xmalloc(sizeof *vrd); > + vrd->name = xstrdup(real_dev); > + hmap_init(&vrd->vlan_devs); > + shash_add_nocopy(&vlan_real_devs, vrd->name, vrd); > + } > + > + vd = xmalloc(sizeof *vd); > + hmap_insert(&vrd->vlan_devs, &vd->hmap_node, hash_int(vid, 0)); > + vd->name = xstrdup(vlan_dev); > + vd->vid = vid; > + vd->real_dev = vrd; > + shash_add_nocopy(&vlan_devs, vd->name, vd); > + } > + } > + fclose(stream); > + > + cache_valid = true; > + return 0; > +} > + > +struct shash * > +vlandev_get_real_devs(void) > +{ > + return &vlan_real_devs; > +} > + > +const char * > +vlandev_get_name(const char *real_dev_name, int vid) > +{ > + const struct vlan_real_dev *real_dev; > + > + real_dev = shash_find_data(&vlan_real_devs, real_dev_name); > + if (real_dev) { > + const struct vlan_dev *vlan_dev; > + > + HMAP_FOR_EACH_WITH_HASH (vlan_dev, hmap_node, hash_int(vid, 0), > + &real_dev->vlan_devs) { > + if (vlan_dev->vid == vid) { > + return vlan_dev->name; > + } > + } > + } > + > + return NULL; > +} > + > +static int > +do_vlan_ioctl(const char *netdev_name, struct vlan_ioctl_args *via, > + int cmd, const char *cmd_name) > +{ > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); > + int error; > + int sock; > + > + via->cmd = cmd; > + ovs_strlcpy(via->device1, netdev_name, sizeof via->device1); > + > + sock = netdev_linux_get_af_inet_sock(); > + if (sock < 0) { > + return -sock; > + } > + > + error = ioctl(sock, SIOCSIFVLAN, via) < 0 ? errno : 0; > + if (error) { > + VLOG_WARN_RL(&rl, "%s: VLAN ioctl %s failed (%s)", > + netdev_name, cmd_name, strerror(error)); > + } > + return error; > +} > + > +int > +vlandev_add(const char *real_dev, int vid) > +{ > + struct vlan_ioctl_args via; > + int error; > + > + memset(&via, 0, sizeof via); > + via.u.VID = vid; > + > + error = do_vlan_ioctl(real_dev, &via, ADD_VLAN_CMD, "ADD_VLAN_CMD"); > + if (!error) { > + cache_valid = false; > + } > + return error; > +} > + > +int > +vlandev_del(const char *vlan_dev) > +{ > + struct vlan_ioctl_args via; > + int error; > + > + memset(&via, 0, sizeof via); > + error = do_vlan_ioctl(vlan_dev, &via, DEL_VLAN_CMD, "DEL_VLAN_CMD"); > + if (!error) { > + cache_valid = false; > + } > + return error; > +} > +#else /* !__linux__ */ > + > +#endif > diff --git a/lib/vlandev.h b/lib/vlandev.h > new file mode 100644 > index 0000000..cba0fa4 > --- /dev/null > +++ b/lib/vlandev.h > @@ -0,0 +1,52 @@ > +/* > + * Copyright (c) 2011 Nicira Networks. > + * > + * Licensed under the Apache License, Version 2.0 (the "License"); > + * you may not use this file except in compliance with the License. > + * You may obtain a copy of the License at: > + * > + * http://www.apache.org/licenses/LICENSE-2.0 > + * > + * Unless required by applicable law or agreed to in writing, software > + * distributed under the License is distributed on an "AS IS" BASIS, > + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. > + * See the License for the specific language governing permissions and > + * limitations under the License. > + */ > + > +#ifndef VLANDEV_H > +#define VLANDEV_H 1 > + > +#include "hmap.h" > + > +/* Linux VLAN device support (e.g. "eth0.10" for VLAN 10.) > + * > + * This is deprecated. It is only for compatibility with broken device > + * drivers in old versions of Linux that do not properly support VLANs when > + * VLAN devices are not used. When broken device drivers are no longer in > + * widespread use, we will delete these interfaces. */ > + > +/* A VLAN device (e.g. "eth0.10" for VLAN 10 on eth0). */ > +struct vlan_dev { > + struct vlan_real_dev *real_dev; /* Parent, e.g. "eth0". */ > + struct hmap_node hmap_node; /* In vlan_real_dev's "vlan_devs" map. */ > + char *name; /* VLAN device name, e.g. "eth0.10". */ > + int vid; /* VLAN ID, e.g. 10. */ > +}; > + > +/* A device that has VLAN devices broken out of it. */ > +struct vlan_real_dev { > + char *name; /* Name, e.g. "eth0". */ > + struct hmap vlan_devs; /* All child VLAN devices, hashed by VID. */ > +}; > + > +int vlandev_refresh(void); > + > +struct shash *vlandev_get_real_devs(void); > + > +const char *vlandev_get_name(const char *real_dev_name, int vid); > + > +int vlandev_add(const char *real_dev, int vid); > +int vlandev_del(const char *vlan_dev); > + > +#endif /* vlandev.h */ > -- > 1.7.4.4 > > _______________________________________________ > dev mailing list > dev@openvswitch.org > http://openvswitch.org/mailman/listinfo/dev > _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev