- Use a NIC whose driver does not have VLAN problems.
- - Use "VLAN splinters", a feature in Open vSwitch 1.4 and later
+ - Use "VLAN splinters", a feature in Open vSwitch 1.4 upto 2.5
that works around bugs in kernel drivers. To enable VLAN
splinters on interface eth0, use the command:
* Introduced SELinux policy package.
- Datapath Linux kernel compatibility.
* Dropped support for kernel older than 3.10.
+ * Removed VLAN splinters feature.
- Tunnels:
* Flow based tunnel match and action can be used for IPv6 address using
tun_ipv6_src, tun_ipv6_dst fields.
lib/vconn.c \
lib/vlan-bitmap.c \
lib/vlan-bitmap.h \
- lib/vlandev.c \
- lib/vlandev.h \
lib/vlog.c \
lib/lldp/aa-structs.h \
lib/lldp/lldp.c \
netdev_dummy_register(level);
dpif_dummy_register(level);
timeval_dummy_register();
- vlandev_dummy_enable();
ofpact_dummy_enable();
}
void dpif_dummy_register(enum dummy_level);
void netdev_dummy_register(enum dummy_level);
void timeval_dummy_register(void);
-void vlandev_dummy_enable(void);
void ofpact_dummy_enable(void);
#endif /* dummy.h */
+++ /dev/null
-/*
- * Copyright (c) 2011, 2013, 2014 Nicira, Inc.
- *
- * 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 <net/if.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-
-#include "dummy.h"
-#include "hash.h"
-#include "shash.h"
-#include "socket-util.h"
-#include "openvswitch/vlog.h"
-
-VLOG_DEFINE_THIS_MODULE(vlandev);
-
-/* A vlandev implementation. */
-struct vlandev_class {
- int (*vd_refresh)(void);
- int (*vd_add)(const char *real_dev, int vid);
- int (*vd_del)(const char *vlan_dev);
-};
-
-#ifdef __linux__
-static const struct vlandev_class vlandev_linux_class;
-#endif
-static const struct vlandev_class vlandev_stub_class;
-static const struct vlandev_class vlandev_dummy_class;
-
-/* The in-use vlandev implementation. */
-static const struct vlandev_class *vd_class;
-
-/* Maps from a VLAN device name (e.g. "eth0.10") to struct vlan_dev. */
-static struct shash vlan_devs = SHASH_INITIALIZER(&vlan_devs);
-
-/* Maps from a VLAN real device name (e.g. "eth0") to struct vlan_real_dev. */
-static struct shash vlan_real_devs = SHASH_INITIALIZER(&vlan_real_devs);
-
-static int vlandev_add__(const char *vlan_dev, const char *real_dev, int vid);
-static int vlandev_del__(const char *vlan_dev);
-static void vlandev_clear__(void);
-
-static const struct vlandev_class *
-vlandev_get_class(void)
-{
- if (!vd_class) {
-#if __linux__
- vd_class = &vlandev_linux_class;
-#else
- vd_class = &vlandev_stub_class;
-#endif
- }
- return vd_class;
-}
-
-/* On Linux, the default implementation of VLAN devices creates and destroys
- * Linux VLAN devices. On other OSess, the default implementation is a
- * nonfunctional stub. In either case, this function replaces this default
- * implementation by a "dummy" implementation that simply reports back whatever
- * the client sets up with vlandev_add() and vlandev_del().
- *
- * Don't call this function directly; use dummy_enable() from dummy.h. */
-void
-vlandev_dummy_enable(void)
-{
- if (vd_class != &vlandev_dummy_class) {
- vd_class = &vlandev_dummy_class;
- vlandev_clear__();
- }
-}
-
-/* Creates a new VLAN device for VLAN 'vid' on top of real Ethernet device
- * 'real_dev'. Returns 0 if successful, otherwise a positive errno value. On
- * OSes other than Linux, in the absence of dummies (see
- * vlandev_dummy_enable()), this always fails.
- *
- * The name of the new VLAN device is not easily predictable, because Linux
- * provides multiple naming schemes, does not allow the client to specify a
- * name, and does not directly report the new VLAN device's name. Use
- * vlandev_refresh() then vlandev_get_name() to find out the new VLAN device's
- * name,. */
-int
-vlandev_add(const char *real_dev, int vid)
-{
- return vlandev_get_class()->vd_add(real_dev, vid);
-}
-
-/* Deletes the VLAN device named 'vlan_dev'. Returns 0 if successful,
- * otherwise a positive errno value. On OSes other than Linux, in the absence
- * of dummies (see vlandev_dummy_enable()), this always fails. */
-int
-vlandev_del(const char *vlan_dev)
-{
- return vlandev_get_class()->vd_del(vlan_dev);
-}
-
-/* Refreshes the cache of real device to VLAN device mappings reported by
- * vlandev_get_real_devs() and vlandev_get_name(). Without calling this
- * function, changes made by vlandev_add() and vlandev_del() may not be
- * reflected by vlandev_get_real_devs() and vlandev_get_name() output. */
-int
-vlandev_refresh(void)
-{
- const struct vlandev_class *class = vlandev_get_class();
- return class->vd_refresh ? class->vd_refresh() : 0;
-}
-
-/* Returns a shash mapping from the name of real Ethernet devices used as the
- * basis of VLAN devices to struct vlan_real_devs. The caller must not modify
- * or free anything in the returned shash.
- *
- * Changes made by vlandev_add() and vlandev_del() may not be reflected in this
- * function's output without an intervening call to vlandev_refresh(). */
-struct shash *
-vlandev_get_real_devs(void)
-{
- return &vlan_real_devs;
-}
-
-/* Returns the name of the VLAN device for VLAN 'vid' on top of
- * 'real_dev_name', or NULL if there is no such VLAN device.
- *
- * Changes made by vlandev_add() and vlandev_del() may not be reflected in this
- * function's output without an intervening call to vlandev_refresh(). */
-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;
-}
-\f
-/* The Linux vlandev implementation. */
-
-#ifdef __linux__
-#include "rtnetlink.h"
-#include <linux/if_vlan.h>
-#include <linux/sockios.h>
-#include "netdev-linux.h"
-
-static struct nln_notifier *vlan_cache_notifier;
-static bool cache_valid;
-
-static void
-vlan_cache_cb(const struct rtnetlink_change *change OVS_UNUSED,
- void *aux OVS_UNUSED)
-{
- cache_valid = false;
-}
-
-static int
-vlandev_linux_refresh(void)
-{
- const char *fn = "/proc/net/vlan/config";
- char line[128];
- FILE *stream;
-
- if (!vlan_cache_notifier) {
- vlan_cache_notifier = rtnetlink_notifier_create(vlan_cache_cb,
- NULL);
- if (!vlan_cache_notifier) {
- return EINVAL;
- }
- }
-
- if (cache_valid) {
- return 0;
- }
-
- vlandev_clear__();
-
- /* 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, ovs_strerror(error));
- return error;
- }
-
- while (fgets(line, sizeof line, stream)) {
- char vlan_dev[16], real_dev[16];
- int vid;
-
- if (ovs_scan(line, "%15[^ |] | %d | %15s", vlan_dev, &vid, real_dev)) {
- vlandev_add__(vlan_dev, real_dev, vid);
- }
- }
- fclose(stream);
-
- cache_valid = true;
- return 0;
-}
-
-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;
-
- via->cmd = cmd;
- ovs_strlcpy(via->device1, netdev_name, sizeof via->device1);
-
- error = af_inet_ioctl(SIOCSIFVLAN, via);
- if (error) {
- VLOG_WARN_RL(&rl, "%s: VLAN ioctl %s failed (%s)",
- netdev_name, cmd_name, ovs_strerror(error));
- }
- return error;
-}
-
-static int
-vlandev_linux_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;
-}
-
-static int
-vlandev_linux_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;
-}
-
-static const struct vlandev_class vlandev_linux_class = {
- vlandev_linux_refresh,
- vlandev_linux_add,
- vlandev_linux_del
-};
-#endif
-\f
-/* Stub implementation. */
-
-static int
-vlandev_stub_add(const char *real_dev OVS_UNUSED, int vid OVS_UNUSED)
-{
- VLOG_ERR("not supported on non-Linux platform");
- return EOPNOTSUPP;
-}
-
-static int
-vlandev_stub_del(const char *vlan_dev OVS_UNUSED)
-{
- VLOG_ERR("not supported on non-Linux platform");
- return EOPNOTSUPP;
-}
-
-static const struct vlandev_class OVS_UNUSED vlandev_stub_class = {
- NULL, /* vd_refresh */
- vlandev_stub_add,
- vlandev_stub_del
-};
-\f
-/* Dummy implementation. */
-
-static int
-vlandev_dummy_add(const char *real_dev, int vid)
-{
- char name[IFNAMSIZ];
-
- if (snprintf(name, sizeof name, "%s.%d", real_dev, vid) >= sizeof name) {
- return ENAMETOOLONG;
- }
- return vlandev_add__(name, real_dev, vid);
-}
-
-static int
-vlandev_dummy_del(const char *vlan_dev)
-{
- return vlandev_del__(vlan_dev);
-}
-
-static const struct vlandev_class vlandev_dummy_class = {
- NULL, /* vd_refresh */
- vlandev_dummy_add,
- vlandev_dummy_del
-};
-\f
-static int
-vlandev_add__(const char *vlan_dev, const char *real_dev, int vid)
-{
- uint32_t vid_hash = hash_int(vid, 0);
- struct vlan_real_dev *vrd;
- struct vlan_dev *vd;
-
- if (vid < 0 || vid > 4095) {
- return EINVAL;
- } else if (shash_find(&vlan_devs, vlan_dev)) {
- return EEXIST;
- }
-
- 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);
- } else {
- HMAP_FOR_EACH_WITH_HASH (vd, hmap_node, vid_hash, &vrd->vlan_devs) {
- if (vd->vid == vid) {
- return EEXIST;
- }
- }
- }
-
- vd = xmalloc(sizeof *vd);
- hmap_insert(&vrd->vlan_devs, &vd->hmap_node, vid_hash);
- vd->name = xstrdup(vlan_dev);
- vd->vid = vid;
- vd->real_dev = vrd;
- shash_add_nocopy(&vlan_devs, vd->name, vd);
-
- return 0;
-}
-
-static int
-vlandev_del__(const char *vlan_dev)
-{
- struct shash_node *vd_node = shash_find(&vlan_devs, vlan_dev);
- if (vd_node) {
- struct vlan_dev *vd = vd_node->data;
- struct vlan_real_dev *vrd = vd->real_dev;
-
- hmap_remove(&vrd->vlan_devs, &vd->hmap_node);
- if (hmap_is_empty(&vrd->vlan_devs)) {
- shash_find_and_delete_assert(&vlan_real_devs, vrd->name);
- free(vrd);
- }
-
- shash_delete(&vlan_devs, vd_node);
- free(vd);
-
- return 0;
- } else {
- return ENOENT;
- }
-}
-
-/* Clear 'vlan_devs' and 'vlan_real_devs' in preparation for repopulating. */
-static void
-vlandev_clear__(void)
-{
- /* We do not free the 'name' members of struct vlan_dev and struct
- * vlan_real_dev, because the "shash"es own them.. */
- struct shash_node *node;
-
- 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);
-}
+++ /dev/null
-/*
- * Copyright (c) 2011 Nicira, Inc.
- *
- * 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_add(const char *real_dev, int vid);
-int vlandev_del(const char *vlan_dev);
-
-int vlandev_refresh(void);
-struct shash *vlandev_get_real_devs(void);
-const char *vlandev_get_name(const char *real_dev_name, int vid);
-
-#endif /* vlandev.h */
struct dpif_ipfix *ipfix; /* IPFIX pointer or NULL. */
struct dpif_sflow *sflow; /* SFlow pointer or NULL. */
- bool vsp_adjusted; /* 'packet' and 'flow' were adjusted for
- VLAN splinters if true. */
-
struct udpif_key *ukey; /* Revalidator flow cache. */
bool ukey_persists; /* Set true to keep 'ukey' beyond the
lifetime of this upcall. */
upcall->out_tun_key = dupcall->out_tun_key;
upcall->actions = dupcall->actions;
- if (vsp_adjust_flow(upcall->ofproto, flow, &dupcall->packet)) {
- upcall->vsp_adjusted = true;
- }
-
pkt_metadata_from_flow(&dupcall->packet.md, flow);
flow_extract(&dupcall->packet, flow);
ofpbuf_init(&upcall->put_actions, 0);
upcall->xout_initialized = false;
- upcall->vsp_adjusted = false;
upcall->ukey_persists = false;
upcall->ukey = NULL;
const struct dp_packet *packet = upcall->packet;
struct ukey_op *op;
- if (upcall->vsp_adjusted) {
- /* This packet was received on a VLAN splinter port. We added a
- * VLAN to the packet to make the packet resemble the flow, but the
- * actions were composed assuming that the packet contained no
- * VLAN. So, we must remove the VLAN header from the packet before
- * trying to execute the actions. */
- if (upcall->odp_actions.size) {
- eth_pop_vlan(CONST_CAST(struct dp_packet *, upcall->packet));
- }
-
- /* Remove the flow vlan tags inserted by vlan splinter logic
- * to ensure megaflow masks generated match the data path flow. */
- CONST_CAST(struct flow *, upcall->flow)->vlan_tci = 0;
- }
-
/* Do not install a flow into the datapath if:
*
* - The datapath already has too many flows.
} else {
odp_port = xport->odp_port;
out_port = odp_port;
- if (ofproto_has_vlan_splinters(ctx->xbridge->ofproto)) {
- ofp_port_t vlandev_port;
-
- wc->masks.vlan_tci |= htons(VLAN_VID_MASK | VLAN_CFI);
- vlandev_port = vsp_realdev_to_vlandev(ctx->xbridge->ofproto,
- ofp_port, flow->vlan_tci);
- if (vlandev_port != ofp_port) {
- out_port = ofp_port_to_odp_port(ctx->xbridge, vlandev_port);
- flow->vlan_tci = htons(0);
- }
- }
}
if (out_port != ODPP_NONE) {
};
/* 'base_flow' reflects the packet as it came in, but we need it to reflect
- * the packet as the datapath will treat it for output actions:
- *
- * - Our datapath doesn't retain tunneling information without us
- * re-setting it, so clear the tunnel data.
- *
- * - For VLAN splinters, a higher layer may pretend that the packet
- * came in on 'flow->in_port.ofp_port' with 'flow->vlan_tci'
- * attached, because that's how we want to treat it from an OpenFlow
- * perspective. But from the datapath's perspective it actually came
- * in on a VLAN device without any VLAN attached. So here we put the
- * datapath's view of the VLAN information in 'base_flow' to ensure
- * correct treatment.
+ * the packet as the datapath will treat it for output actions. Our
+ * datapath doesn't retain tunneling information without us re-setting
+ * it, so clear the tunnel data.
*/
+
memset(&ctx.base_flow.tunnel, 0, sizeof ctx.base_flow.tunnel);
- if (flow->in_port.ofp_port
- != vsp_realdev_to_vlandev(xbridge->ofproto,
- flow->in_port.ofp_port,
- flow->vlan_tci)) {
- ctx.base_flow.vlan_tci = 0;
- }
ofpbuf_reserve(ctx.odp_actions, NL_A_U32_SIZE);
if (xin->wc) {
/* Queue to DSCP mapping. */
struct ofproto_port_queue *qdscp;
size_t n_qdscp;
-
- /* 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. */
- ofp_port_t realdev_ofp_port;
- int vlandev_vid;
};
-/* 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. */
-struct vlan_splinter {
- struct hmap_node realdev_vid_node;
- struct hmap_node vlandev_node;
- ofp_port_t realdev_ofp_port;
- ofp_port_t vlandev_ofp_port;
- int vid;
-};
-
-static void vsp_remove(struct ofport_dpif *);
-static void vsp_add(struct ofport_dpif *, ofp_port_t realdev_ofp_port, int vid);
-
static odp_port_t ofp_port_to_odp_port(const struct ofproto_dpif *,
ofp_port_t);
struct rstp *rstp;
long long int rstp_last_tick;
- /* VLAN splinters. */
- struct ovs_mutex vsp_mutex;
- struct hmap realdev_vid_map OVS_GUARDED; /* (realdev,vid) -> vlandev. */
- struct hmap vlandev_map OVS_GUARDED; /* vlandev -> (realdev,vid). */
-
/* Ports. */
struct sset ports; /* Set of standard port names. */
struct sset ghost_ports; /* Ports with no datapath port. */
ofproto->has_bonded_bundles = false;
ofproto->lacp_enabled = false;
ovs_mutex_init_adaptive(&ofproto->stats_mutex);
- ovs_mutex_init(&ofproto->vsp_mutex);
guarded_list_init(&ofproto->ams);
- hmap_init(&ofproto->vlandev_map);
- hmap_init(&ofproto->realdev_vid_map);
-
sset_init(&ofproto->ports);
sset_init(&ofproto->ghost_ports);
sset_init(&ofproto->port_poll_set);
mac_learning_unref(ofproto->ml);
mcast_snooping_unref(ofproto->ms);
- hmap_destroy(&ofproto->vlandev_map);
- hmap_destroy(&ofproto->realdev_vid_map);
-
sset_destroy(&ofproto->ports);
sset_destroy(&ofproto->ghost_ports);
sset_destroy(&ofproto->port_poll_set);
ovs_mutex_destroy(&ofproto->stats_mutex);
- ovs_mutex_destroy(&ofproto->vsp_mutex);
seq_destroy(ofproto->ams_seq);
port->peer = NULL;
port->qdscp = NULL;
port->n_qdscp = 0;
- port->realdev_ofp_port = 0;
- port->vlandev_vid = 0;
port->carrier_seq = netdev_get_carrier_resets(netdev);
port->is_layer3 = netdev_vport_is_layer3(netdev);
error = "Invalid datapath flow";
goto exit;
}
-
- vsp_adjust_flow(*ofprotop, flow, NULL);
-
} else {
char *err = parse_ofp_exact_flow(flow, NULL, argv[argc - 1], NULL);
return table_id == TBL_INTERNAL;
}
\f
-/* 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. */
-
-static int
-set_realdev(struct ofport *ofport_, ofp_port_t realdev_ofp_port, int vid)
-{
- struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofport_->ofproto);
- struct ofport_dpif *ofport = ofport_dpif_cast(ofport_);
-
- if (realdev_ofp_port == ofport->realdev_ofp_port
- && vid == ofport->vlandev_vid) {
- return 0;
- }
-
- ofproto->backer->need_revalidate = REV_RECONFIGURE;
-
- if (ofport->realdev_ofp_port) {
- vsp_remove(ofport);
- }
- if (realdev_ofp_port && ofport->bundle) {
- /* vlandevs are enslaved to their realdevs, so they are not allowed to
- * themselves be part of a bundle. */
- bundle_set(ofport_->ofproto, ofport->bundle, NULL);
- }
-
- ofport->realdev_ofp_port = realdev_ofp_port;
- ofport->vlandev_vid = vid;
-
- if (realdev_ofp_port) {
- vsp_add(ofport, realdev_ofp_port, vid);
- }
-
- return 0;
-}
-
-static uint32_t
-hash_realdev_vid(ofp_port_t realdev_ofp_port, int vid)
-{
- return hash_2words(ofp_to_u16(realdev_ofp_port), vid);
-}
-
-bool
-ofproto_has_vlan_splinters(const struct ofproto_dpif *ofproto)
- OVS_EXCLUDED(ofproto->vsp_mutex)
-{
- /* hmap_is_empty is thread safe. */
- return !hmap_is_empty(&ofproto->realdev_vid_map);
-}
-
-
-static ofp_port_t
-vsp_realdev_to_vlandev__(const struct ofproto_dpif *ofproto,
- ofp_port_t realdev_ofp_port, ovs_be16 vlan_tci)
- OVS_REQUIRES(ofproto->vsp_mutex)
-{
- if (!hmap_is_empty(&ofproto->realdev_vid_map)) {
- int vid = vlan_tci_to_vid(vlan_tci);
- const struct vlan_splinter *vsp;
-
- HMAP_FOR_EACH_WITH_HASH (vsp, realdev_vid_node,
- hash_realdev_vid(realdev_ofp_port, vid),
- &ofproto->realdev_vid_map) {
- if (vsp->realdev_ofp_port == realdev_ofp_port
- && vsp->vid == vid) {
- return vsp->vlandev_ofp_port;
- }
- }
- }
- return realdev_ofp_port;
-}
-
-/* Returns the OFP port number of the Linux VLAN device that corresponds to
- * 'vlan_tci' on the network device with port number 'realdev_ofp_port' in
- * 'struct ofport_dpif'. For example, given 'realdev_ofp_port' of eth0 and
- * 'vlan_tci' 9, it would return the port number of eth0.9.
- *
- * Unless VLAN splinters are enabled for port 'realdev_ofp_port', this
- * function just returns its 'realdev_ofp_port' argument. */
-ofp_port_t
-vsp_realdev_to_vlandev(const struct ofproto_dpif *ofproto,
- ofp_port_t realdev_ofp_port, ovs_be16 vlan_tci)
- OVS_EXCLUDED(ofproto->vsp_mutex)
-{
- ofp_port_t ret;
-
- /* hmap_is_empty is thread safe, see if we can return immediately. */
- if (hmap_is_empty(&ofproto->realdev_vid_map)) {
- return realdev_ofp_port;
- }
- ovs_mutex_lock(&ofproto->vsp_mutex);
- ret = vsp_realdev_to_vlandev__(ofproto, realdev_ofp_port, vlan_tci);
- ovs_mutex_unlock(&ofproto->vsp_mutex);
- return ret;
-}
-
-static struct vlan_splinter *
-vlandev_find(const struct ofproto_dpif *ofproto, ofp_port_t vlandev_ofp_port)
-{
- struct vlan_splinter *vsp;
-
- HMAP_FOR_EACH_WITH_HASH (vsp, vlandev_node,
- hash_ofp_port(vlandev_ofp_port),
- &ofproto->vlandev_map) {
- if (vsp->vlandev_ofp_port == vlandev_ofp_port) {
- return vsp;
- }
- }
-
- return NULL;
-}
-
-/* Returns the OpenFlow port number of the "real" device underlying the Linux
- * VLAN device with OpenFlow port number 'vlandev_ofp_port' and stores the
- * VLAN VID of the Linux VLAN device in '*vid'. For example, given
- * 'vlandev_ofp_port' of eth0.9, it would return the OpenFlow port number of
- * eth0 and store 9 in '*vid'.
- *
- * Returns 0 and does not modify '*vid' if 'vlandev_ofp_port' is not a Linux
- * VLAN device. Unless VLAN splinters are enabled, this is what this function
- * always does.*/
-static ofp_port_t
-vsp_vlandev_to_realdev(const struct ofproto_dpif *ofproto,
- ofp_port_t vlandev_ofp_port, int *vid)
- OVS_REQUIRES(ofproto->vsp_mutex)
-{
- if (!hmap_is_empty(&ofproto->vlandev_map)) {
- const struct vlan_splinter *vsp;
-
- vsp = vlandev_find(ofproto, vlandev_ofp_port);
- if (vsp) {
- if (vid) {
- *vid = vsp->vid;
- }
- return vsp->realdev_ofp_port;
- }
- }
- return 0;
-}
-
-/* Given 'flow', a flow representing a packet received on 'ofproto', checks
- * whether 'flow->in_port' represents a Linux VLAN device. If so, changes
- * 'flow->in_port' to the "real" device backing the VLAN device, sets
- * 'flow->vlan_tci' to the VLAN VID, and returns true. Optionally pushes the
- * appropriate VLAN on 'packet' if provided. Otherwise (which is always the
- * case unless VLAN splinters are enabled), returns false without making any
- * changes. */
-bool
-vsp_adjust_flow(const struct ofproto_dpif *ofproto, struct flow *flow,
- struct dp_packet *packet)
- OVS_EXCLUDED(ofproto->vsp_mutex)
-{
- ofp_port_t realdev;
- int vid;
-
- /* hmap_is_empty is thread safe. */
- if (hmap_is_empty(&ofproto->vlandev_map)) {
- return false;
- }
-
- ovs_mutex_lock(&ofproto->vsp_mutex);
- realdev = vsp_vlandev_to_realdev(ofproto, flow->in_port.ofp_port, &vid);
- ovs_mutex_unlock(&ofproto->vsp_mutex);
- if (!realdev) {
- return false;
- }
-
- /* Cause the flow to be processed as if it came in on the real device with
- * the VLAN device's VLAN ID. */
- flow->in_port.ofp_port = realdev;
- flow->vlan_tci = htons((vid & VLAN_VID_MASK) | VLAN_CFI);
-
- if (packet) {
- /* Make the packet resemble the flow, so that it gets sent to an
- * OpenFlow controller properly, so that it looks correct for sFlow,
- * and so that flow_extract() will get the correct vlan_tci if it is
- * called on 'packet'. */
- eth_push_vlan(packet, htons(ETH_TYPE_VLAN), flow->vlan_tci);
- }
-
- return true;
-}
-
-static void
-vsp_remove(struct ofport_dpif *port)
-{
- struct ofproto_dpif *ofproto = ofproto_dpif_cast(port->up.ofproto);
- struct vlan_splinter *vsp;
-
- ovs_mutex_lock(&ofproto->vsp_mutex);
- vsp = vlandev_find(ofproto, port->up.ofp_port);
- if (vsp) {
- hmap_remove(&ofproto->vlandev_map, &vsp->vlandev_node);
- hmap_remove(&ofproto->realdev_vid_map, &vsp->realdev_vid_node);
- free(vsp);
-
- port->realdev_ofp_port = 0;
- } else {
- VLOG_ERR("missing vlan device record");
- }
- ovs_mutex_unlock(&ofproto->vsp_mutex);
-}
-
-static void
-vsp_add(struct ofport_dpif *port, ofp_port_t realdev_ofp_port, int vid)
-{
- struct ofproto_dpif *ofproto = ofproto_dpif_cast(port->up.ofproto);
-
- ovs_mutex_lock(&ofproto->vsp_mutex);
- if (!vsp_vlandev_to_realdev(ofproto, port->up.ofp_port, NULL)
- && (vsp_realdev_to_vlandev__(ofproto, realdev_ofp_port, htons(vid))
- == realdev_ofp_port)) {
- struct vlan_splinter *vsp;
-
- vsp = xmalloc(sizeof *vsp);
- vsp->realdev_ofp_port = realdev_ofp_port;
- vsp->vlandev_ofp_port = port->up.ofp_port;
- vsp->vid = vid;
-
- port->realdev_ofp_port = realdev_ofp_port;
-
- hmap_insert(&ofproto->vlandev_map, &vsp->vlandev_node,
- hash_ofp_port(port->up.ofp_port));
- hmap_insert(&ofproto->realdev_vid_map, &vsp->realdev_vid_node,
- hash_realdev_vid(realdev_ofp_port, vid));
- } else {
- VLOG_ERR("duplicate vlan device record");
- }
- ovs_mutex_unlock(&ofproto->vsp_mutex);
-}
static odp_port_t
ofp_port_to_odp_port(const struct ofproto_dpif *ofproto, ofp_port_t ofp_port)
set_mac_table_config,
set_mcast_snooping,
set_mcast_snooping_port,
- set_realdev,
NULL, /* meter_get_features */
NULL, /* meter_set */
NULL, /* meter_get */
uint64_t group_dpif_get_selection_method_param(const struct group_dpif *group);
const struct field_array *group_dpif_get_fields(const struct group_dpif *group);
-bool ofproto_has_vlan_splinters(const struct ofproto_dpif *);
-ofp_port_t vsp_realdev_to_vlandev(const struct ofproto_dpif *,
- ofp_port_t realdev_ofp_port,
- ovs_be16 vlan_tci);
-bool vsp_adjust_flow(const struct ofproto_dpif *, struct flow *,
- struct dp_packet *packet);
-
int ofproto_dpif_execute_actions(struct ofproto_dpif *, const struct flow *,
struct rule_dpif *, const struct ofpact *,
size_t ofpacts_len, struct dp_packet *);
* the flow table and reacquire the global lock. */
struct guarded_list rule_executes; /* Contains "struct rule_execute"s. */
- /* 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. */
- unsigned long int *vlan_bitmap; /* 4096-bit bitmap of in-use VLANs. */
- bool vlans_changed; /* True if new VLANs are in use. */
int min_mtu; /* Current MTU of non-internal ports. */
/* Groups. */
int (*set_mcast_snooping_port)(struct ofproto *ofproto_, void *aux,
const struct ofproto_mcast_snooping_port_settings *s);
-/* 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. */
-
- /* If 'realdev_ofp_port' is nonzero, then this function configures 'ofport'
- * as a VLAN splinter port for VLAN 'vid', associated with the real device
- * that has OpenFlow port number 'realdev_ofp_port'.
- *
- * If 'realdev_ofp_port' is zero, then this function deconfigures 'ofport'
- * as a VLAN splinter port.
- *
- * This function should be NULL if an implementation does not support it.
- */
- int (*set_realdev)(struct ofport *ofport,
- ofp_port_t realdev_ofp_port, int vid);
-
/* ## ------------------------ ## */
/* ## OpenFlow meter functions ## */
/* ## ------------------------ ## */
ovs_list_init(&ofproto->expirable);
ofproto->connmgr = connmgr_create(ofproto, datapath_name, datapath_name);
guarded_list_init(&ofproto->rule_executes);
- ofproto->vlan_bitmap = NULL;
- ofproto->vlans_changed = false;
ofproto->min_mtu = INT_MAX;
ovs_rwlock_init(&ofproto->groups_rwlock);
hmap_init(&ofproto->groups);
ovs_assert(hmap_is_empty(&ofproto->learned_cookies));
hmap_destroy(&ofproto->learned_cookies);
- free(ofproto->vlan_bitmap);
-
ofproto->ofproto_class->dealloc(ofproto);
}
{
struct ofport *port = ofproto_get_port(ofproto, ofp_port);
if (port) {
- if (port->ofproto->ofproto_class->set_realdev) {
- port->ofproto->ofproto_class->set_realdev(port, 0, 0);
- }
if (port->ofproto->ofproto_class->set_stp_port) {
port->ofproto->ofproto_class->set_stp_port(port, NULL);
}
if (old_rule) {
ovsrcu_postpone(remove_rule_rcu, old_rule);
} else {
- if (minimask_get_vid_mask(new_rule->cr.match.mask) == VLAN_VID_MASK) {
- if (ofproto->vlan_bitmap) {
- uint16_t vid = miniflow_get_vid(new_rule->cr.match.flow);
-
- if (!bitmap_is_set(ofproto->vlan_bitmap, vid)) {
- bitmap_set1(ofproto->vlan_bitmap, vid);
- ofproto->vlans_changed = true;
- }
- } else {
- ofproto->vlans_changed = true;
- }
- }
-
ofmonitor_report(ofproto->connmgr, new_rule, NXFME_ADDED, 0,
req ? req->ofconn : NULL,
req ? req->request->xid : 0, NULL);
unixctl_command_register("ofproto/list", "", 0, 0,
ofproto_unixctl_list, NULL);
}
-\f
-/* 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. */
-
-/* Sets a 1-bit in the 4096-bit 'vlan_bitmap' for each VLAN ID that is matched
- * (exactly) by an OpenFlow rule in 'ofproto'. */
-void
-ofproto_get_vlan_usage(struct ofproto *ofproto, unsigned long int *vlan_bitmap)
-{
- struct match match;
- struct cls_rule target;
- const struct oftable *oftable;
-
- match_init_catchall(&match);
- match_set_vlan_vid_masked(&match, htons(VLAN_CFI), htons(VLAN_CFI));
- cls_rule_init(&target, &match, 0);
-
- free(ofproto->vlan_bitmap);
- ofproto->vlan_bitmap = bitmap_allocate(4096);
- ofproto->vlans_changed = false;
-
- OFPROTO_FOR_EACH_TABLE (oftable, ofproto) {
- struct rule *rule;
-
- CLS_FOR_EACH_TARGET (rule, cr, &oftable->cls, &target,
- CLS_MAX_VERSION) {
- if (minimask_get_vid_mask(rule->cr.match.mask) == VLAN_VID_MASK) {
- uint16_t vid = miniflow_get_vid(rule->cr.match.flow);
-
- bitmap_set1(vlan_bitmap, vid);
- bitmap_set1(ofproto->vlan_bitmap, vid);
- }
- }
- }
-
- cls_rule_destroy(&target);
-}
-
-/* Returns true if new VLANs have come into use by the flow table since the
- * last call to ofproto_get_vlan_usage().
- *
- * We don't track when old VLANs stop being used. */
-bool
-ofproto_has_vlan_usage_changed(const struct ofproto *ofproto)
-{
- return ofproto->vlans_changed;
-}
-
-/* Configures a VLAN splinter binding between the ports identified by OpenFlow
- * port numbers 'vlandev_ofp_port' and 'realdev_ofp_port'. If
- * 'realdev_ofp_port' is nonzero, then the VLAN device is enslaved to the real
- * device as a VLAN splinter for VLAN ID 'vid'. If 'realdev_ofp_port' is zero,
- * then the VLAN device is un-enslaved. */
-int
-ofproto_port_set_realdev(struct ofproto *ofproto, ofp_port_t vlandev_ofp_port,
- ofp_port_t realdev_ofp_port, int vid)
-{
- struct ofport *ofport;
- int error;
-
- ovs_assert(vlandev_ofp_port != realdev_ofp_port);
-
- ofport = ofproto_get_port(ofproto, vlandev_ofp_port);
- if (!ofport) {
- VLOG_WARN("%s: cannot set realdev on nonexistent port %"PRIu16,
- ofproto->name, vlandev_ofp_port);
- return EINVAL;
- }
-
- if (!ofproto->ofproto_class->set_realdev) {
- if (!vlandev_ofp_port) {
- return 0;
- }
- VLOG_WARN("%s: vlan splinters not supported", ofproto->name);
- return EOPNOTSUPP;
- }
-
- error = ofproto->ofproto_class->set_realdev(ofport, realdev_ofp_port, vid);
- if (error) {
- VLOG_WARN("%s: setting realdev on port %"PRIu16" (%s) failed (%s)",
- ofproto->name, vlandev_ofp_port,
- netdev_get_name(ofport->netdev), ovs_strerror(error));
- }
- return error;
-}
struct lacp_settings *lacp; /* Nonnull to enable LACP. */
struct lacp_slave_settings *lacp_slaves; /* Array of n_slaves elements. */
-
- /* 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. */
- ofp_port_t realdev_ofp_port;/* OpenFlow port number of real device. */
};
int ofproto_bundle_register(struct ofproto *, void *aux,
ofp_port_t ofp_port,
struct cfm_status *);
\f
-/* 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. */
-
-void ofproto_get_vlan_usage(struct ofproto *, unsigned long int *vlan_bitmap);
-bool ofproto_has_vlan_usage_changed(const struct ofproto *);
-int ofproto_port_set_realdev(struct ofproto *, ofp_port_t vlandev_ofp_port,
- ofp_port_t realdev_ofp_port, int vid);
-\f
/* Table configuration */
enum ofputil_table_miss ofproto_table_get_miss_config(const struct ofproto *,
tests/dpctl.at \
tests/ofproto-dpif.at \
tests/bridge.at \
- tests/vlan-splinters.at \
tests/ofproto.at \
tests/ovsdb.at \
tests/ovsdb-log.at \
m4_include([tests/dpctl.at])
m4_include([tests/ofproto-dpif.at])
m4_include([tests/bridge.at])
-m4_include([tests/vlan-splinters.at])
m4_include([tests/ovsdb.at])
m4_include([tests/ovs-vsctl.at])
m4_include([tests/ovs-monitor-ipsec.at])
+++ /dev/null
-AT_BANNER([VLAN splinters])
-
-AT_SETUP([VLAN splinters])
-AT_SKIP_IF([test "$IS_WIN32" = "yes"])
-OVS_VSWITCHD_START([], [], [=override])
-add_of_ports br0 1 2 3 4
-AT_CHECK([ovs-vsctl \
- -- set Bridge br0 fail-mode=standalone flood_vlans=0,9,11,15 \
- -- set port br0 tag=0 \
- -- set port p1 trunks=0,9,11,15 \
- -- set interface p1 other-config:enable-vlan-splinters=true \
- -- set port p2 tag=9 \
- -- set port p3 tag=11 \
- -- set port p4 tag=15])
-
-ovs-appctl dpif/show | sed -n '
-s/\./_/g
-s/^[[ ]]*\([[^ ]][[^ ]]*\) [[0-9]]*\/\([[0-9]]*\).*/\1=\2/p
-' > port-numbers
-cat port-numbers
-. ./port-numbers
-
-for args in '9 p2' '11 p3' '15 p4'; do
- set $args
- vlan=$1
- eval access_port=\$$2
- eval splinter_port=\$p1_$vlan
-
- # Check that when a packet is received on $splinter_port, it is
- # treated as if it had been received on p1 in the correct VLAN.
- AT_CHECK([ovs-appctl ofproto/trace ovs-dummy "in_port($splinter_port)"],
- [0], [stdout])
- AT_CHECK_UNQUOTED([sed -n '/^Flow/p; /^Datapath/p' stdout], [0], [dnl
-Flow: in_port=$p1,dl_vlan=$vlan,dl_vlan_pcp=0,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x05ff
-Datapath actions: $access_port
-])
-
- # Check that when an OpenFlow action sends a packet to p1 on
- # splintered VLAN $vlan, it is actually output to $splinter_port.
- AT_CHECK([ovs-appctl ofproto/trace ovs-dummy "in_port($access_port)"],
- [0], [stdout])
- AT_CHECK_UNQUOTED([tail -1 stdout], [0], [Datapath actions: $splinter_port
-])
-done
-
-OVS_VSWITCHD_STOP
-AT_CLEANUP
#include "timeval.h"
#include "util.h"
#include "unixctl.h"
-#include "vlandev.h"
#include "lib/vswitch-idl.h"
#include "xenserver.h"
#include "vlan-bitmap.h"
static size_t bridge_get_controllers(const struct bridge *br,
struct ovsrec_controller ***controllersp);
static void bridge_collect_wanted_ports(struct bridge *,
- const unsigned long *splinter_vlans,
struct shash *wanted_ports);
static void bridge_delete_ofprotos(void);
static void bridge_delete_or_reconfigure_ports(struct bridge *);
static ofp_port_t iface_pick_ofport(const struct ovsrec_interface *);
-/* 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. */
-
-/* True if VLAN splinters are enabled on any interface, false otherwise.*/
-static bool vlan_splinters_enabled_anywhere;
-
-static bool vlan_splinters_is_enabled(const struct ovsrec_interface *);
-static unsigned long int *collect_splinter_vlans(
- const struct ovsrec_open_vswitch *);
-static void configure_splinter_port(struct port *);
-static void add_vlan_splinter_ports(struct bridge *,
- const unsigned long int *splinter_vlans,
- struct shash *ports);
-
static void discover_types(const struct ovsrec_open_vswitch *cfg);
static void
static void
bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
{
- unsigned long int *splinter_vlans;
struct sockaddr_in *managers;
struct bridge *br, *next;
int sflow_bridge_number;
* This is mostly an update to bridge data structures. Nothing is pushed
* down to ofproto or lower layers. */
add_del_bridges(ovs_cfg);
- splinter_vlans = collect_splinter_vlans(ovs_cfg);
HMAP_FOR_EACH (br, node, &all_bridges) {
- bridge_collect_wanted_ports(br, splinter_vlans, &br->wanted_ports);
+ bridge_collect_wanted_ports(br, &br->wanted_ports);
bridge_del_ports(br, &br->wanted_ports);
}
- free(splinter_vlans);
/* Start pushing configuration changes down to the ofproto layer:
*
struct ofproto_bundle_settings s;
struct iface *iface;
- if (cfg->vlan_mode && !strcmp(cfg->vlan_mode, "splinter")) {
- configure_splinter_port(port);
- return;
- }
-
/* Get name. */
s.name = port->name;
static int
iface_do_create(const struct bridge *br,
const struct ovsrec_interface *iface_cfg,
- const struct ovsrec_port *port_cfg,
ofp_port_t *ofp_portp, struct netdev **netdevp,
char **errp)
{
VLOG_INFO("bridge %s: added interface %s on port %d",
br->name, iface_cfg->name, *ofp_portp);
- if (port_cfg->vlan_mode && !strcmp(port_cfg->vlan_mode, "splinter")) {
- netdev_turn_flags_on(netdev, NETDEV_UP, NULL);
- }
-
*netdevp = netdev;
return 0;
/* Do the bits that can fail up front. */
ovs_assert(!iface_lookup(br, iface_cfg->name));
- error = iface_do_create(br, iface_cfg, port_cfg, &ofp_port, &netdev, &errp);
+ error = iface_do_create(br, iface_cfg, &ofp_port, &netdev, &errp);
if (error) {
iface_clear_db_record(iface_cfg, errp);
free(errp);
static struct ovsrec_open_vswitch null_cfg;
const struct ovsrec_open_vswitch *cfg;
- bool vlan_splinters_changed;
-
ovsrec_open_vswitch_init(&null_cfg);
ovsdb_idl_run(idl);
stream_ssl_set_ca_cert_file(ssl->ca_cert, ssl->bootstrap_ca_cert);
}
- /* If VLAN splinters are in use, then we need to reconfigure if VLAN
- * usage has changed. */
- vlan_splinters_changed = false;
- if (vlan_splinters_enabled_anywhere) {
- struct bridge *br;
-
- HMAP_FOR_EACH (br, node, &all_bridges) {
- if (ofproto_has_vlan_usage_changed(br->ofproto)) {
- vlan_splinters_changed = true;
- break;
- }
- }
- }
-
- if (ovsdb_idl_get_seqno(idl) != idl_seqno || vlan_splinters_changed
- || ifaces_changed) {
+ if (ovsdb_idl_get_seqno(idl) != idl_seqno || ifaces_changed) {
struct ovsdb_idl_txn *txn;
ifaces_changed = false;
static void
bridge_collect_wanted_ports(struct bridge *br,
- const unsigned long int *splinter_vlans,
struct shash *wanted_ports)
{
size_t i;
shash_add(wanted_ports, br->name, &br->synth_local_port);
}
-
- if (splinter_vlans) {
- add_vlan_splinter_ports(br, splinter_vlans, wanted_ports);
- }
}
/* Deletes "struct port"s and "struct iface"s under 'br' which aren't
return true;
}
-\f
-/* 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. */
-
-static struct ovsrec_port **recs;
-static size_t n_recs, allocated_recs;
-
-/* Adds 'rec' to a list of recs that have to be destroyed when the VLAN
- * splinters are reconfigured. */
-static void
-register_rec(struct ovsrec_port *rec)
-{
- if (n_recs >= allocated_recs) {
- recs = x2nrealloc(recs, &allocated_recs, sizeof *recs);
- }
- recs[n_recs++] = rec;
-}
-
-/* Frees all of the ports registered with register_reg(). */
-static void
-free_registered_recs(void)
-{
- size_t i;
-
- for (i = 0; i < n_recs; i++) {
- struct ovsrec_port *port = recs[i];
- size_t j;
-
- for (j = 0; j < port->n_interfaces; j++) {
- struct ovsrec_interface *iface = port->interfaces[j];
- free(iface->name);
- free(iface);
- }
-
- smap_destroy(&port->other_config);
- free(port->interfaces);
- free(port->name);
- free(port->tag);
- free(port);
- }
- n_recs = 0;
-}
-
-/* Returns true if VLAN splinters are enabled on 'iface_cfg', false
- * otherwise. */
-static bool
-vlan_splinters_is_enabled(const struct ovsrec_interface *iface_cfg)
-{
- return smap_get_bool(&iface_cfg->other_config, "enable-vlan-splinters",
- false);
-}
-
-/* Figures out the set of VLANs that are in use for the purpose of VLAN
- * splinters.
- *
- * If VLAN splinters are enabled on at least one interface and any VLANs are in
- * use, returns a 4096-bit bitmap with a 1-bit for each in-use VLAN (bits 0 and
- * 4095 will not be set). The caller is responsible for freeing the bitmap,
- * with free().
- *
- * If VLANs splinters are not enabled on any interface or if no VLANs are in
- * use, returns NULL.
- *
- * Updates 'vlan_splinters_enabled_anywhere'. */
-static unsigned long int *
-collect_splinter_vlans(const struct ovsrec_open_vswitch *ovs_cfg)
-{
- unsigned long int *splinter_vlans;
- struct sset splinter_ifaces;
- const char *real_dev_name;
- struct shash *real_devs;
- struct shash_node *node;
- struct bridge *br;
- size_t i;
-
- /* Free space allocated for synthesized ports and interfaces, since we're
- * in the process of reconstructing all of them. */
- free_registered_recs();
-
- splinter_vlans = bitmap_allocate(4096);
- sset_init(&splinter_ifaces);
- vlan_splinters_enabled_anywhere = false;
- for (i = 0; i < ovs_cfg->n_bridges; i++) {
- struct ovsrec_bridge *br_cfg = ovs_cfg->bridges[i];
- size_t j;
-
- for (j = 0; j < br_cfg->n_ports; j++) {
- struct ovsrec_port *port_cfg = br_cfg->ports[j];
- int k;
-
- for (k = 0; k < port_cfg->n_interfaces; k++) {
- struct ovsrec_interface *iface_cfg = port_cfg->interfaces[k];
-
- if (vlan_splinters_is_enabled(iface_cfg)) {
- vlan_splinters_enabled_anywhere = true;
- sset_add(&splinter_ifaces, iface_cfg->name);
- vlan_bitmap_from_array__(port_cfg->trunks,
- port_cfg->n_trunks,
- splinter_vlans);
- }
- }
-
- if (port_cfg->tag && *port_cfg->tag > 0 && *port_cfg->tag < 4095) {
- bitmap_set1(splinter_vlans, *port_cfg->tag);
- }
- }
- }
-
- if (!vlan_splinters_enabled_anywhere) {
- free(splinter_vlans);
- sset_destroy(&splinter_ifaces);
- return NULL;
- }
-
- HMAP_FOR_EACH (br, node, &all_bridges) {
- if (br->ofproto) {
- ofproto_get_vlan_usage(br->ofproto, splinter_vlans);
- }
- }
-
- /* Don't allow VLANs 0 or 4095 to be splintered. VLAN 0 should appear on
- * the real device. VLAN 4095 is reserved and Linux doesn't allow a VLAN
- * device to be created for it. */
- bitmap_set0(splinter_vlans, 0);
- bitmap_set0(splinter_vlans, 4095);
-
- /* Delete all VLAN devices that we don't need. */
- vlandev_refresh();
- real_devs = vlandev_get_real_devs();
- SHASH_FOR_EACH (node, real_devs) {
- const struct vlan_real_dev *real_dev = node->data;
- const struct vlan_dev *vlan_dev;
- bool real_dev_has_splinters;
-
- real_dev_has_splinters = sset_contains(&splinter_ifaces,
- real_dev->name);
- HMAP_FOR_EACH (vlan_dev, hmap_node, &real_dev->vlan_devs) {
- if (!real_dev_has_splinters
- || !bitmap_is_set(splinter_vlans, vlan_dev->vid)) {
- struct netdev *netdev;
-
- if (!netdev_open(vlan_dev->name, "system", &netdev)) {
- if (!netdev_get_addr_list(netdev, NULL, NULL, NULL)) {
- /* It has an IP address configured, so we don't own
- * it. Don't delete it. */
- } else {
- vlandev_del(vlan_dev->name);
- }
- netdev_close(netdev);
- }
- }
-
- }
- }
-
- /* Add all VLAN devices that we need. */
- SSET_FOR_EACH (real_dev_name, &splinter_ifaces) {
- int vid;
-
- BITMAP_FOR_EACH_1 (vid, 4096, splinter_vlans) {
- if (!vlandev_get_name(real_dev_name, vid)) {
- vlandev_add(real_dev_name, vid);
- }
- }
- }
-
- vlandev_refresh();
-
- sset_destroy(&splinter_ifaces);
-
- if (bitmap_scan(splinter_vlans, 1, 0, 4096) >= 4096) {
- free(splinter_vlans);
- return NULL;
- }
- return splinter_vlans;
-}
-
-/* Pushes the configure of VLAN splinter port 'port' (e.g. eth0.9) down to
- * ofproto. */
-static void
-configure_splinter_port(struct port *port)
-{
- struct ofproto *ofproto = port->bridge->ofproto;
- ofp_port_t realdev_ofp_port;
- const char *realdev_name;
- struct iface *vlandev, *realdev;
-
- ofproto_bundle_unregister(port->bridge->ofproto, port);
-
- vlandev = CONTAINER_OF(ovs_list_front(&port->ifaces), struct iface,
- port_elem);
-
- realdev_name = smap_get(&port->cfg->other_config, "realdev");
- realdev = iface_lookup(port->bridge, realdev_name);
- realdev_ofp_port = realdev ? realdev->ofp_port : 0;
-
- ofproto_port_set_realdev(ofproto, vlandev->ofp_port, realdev_ofp_port,
- *port->cfg->tag);
-}
-
-static struct ovsrec_port *
-synthesize_splinter_port(const char *real_dev_name,
- const char *vlan_dev_name, int vid)
-{
- struct ovsrec_interface *iface;
- struct ovsrec_port *port;
-
- iface = xmalloc(sizeof *iface);
- ovsrec_interface_init(iface);
- iface->name = xstrdup(vlan_dev_name);
- iface->type = "system";
-
- port = xmalloc(sizeof *port);
- ovsrec_port_init(port);
- port->interfaces = xmemdup(&iface, sizeof iface);
- port->n_interfaces = 1;
- port->name = xstrdup(vlan_dev_name);
- port->vlan_mode = "splinter";
- port->tag = xmalloc(sizeof *port->tag);
- *port->tag = vid;
-
- smap_add(&port->other_config, "realdev", real_dev_name);
-
- register_rec(port);
- return port;
-}
-
-/* For each interface with 'br' that has VLAN splinters enabled, adds a
- * corresponding ovsrec_port to 'ports' for each splinter VLAN marked with a
- * 1-bit in the 'splinter_vlans' bitmap. */
-static void
-add_vlan_splinter_ports(struct bridge *br,
- const unsigned long int *splinter_vlans,
- struct shash *ports)
-{
- size_t i;
-
- /* We iterate through 'br->cfg->ports' instead of 'ports' here because
- * we're modifying 'ports'. */
- for (i = 0; i < br->cfg->n_ports; i++) {
- const char *name = br->cfg->ports[i]->name;
- struct ovsrec_port *port_cfg = shash_find_data(ports, name);
- size_t j;
-
- for (j = 0; j < port_cfg->n_interfaces; j++) {
- struct ovsrec_interface *iface_cfg = port_cfg->interfaces[j];
-
- if (vlan_splinters_is_enabled(iface_cfg)) {
- const char *real_dev_name;
- uint16_t vid;
-
- real_dev_name = iface_cfg->name;
- BITMAP_FOR_EACH_1 (vid, 4096, splinter_vlans) {
- const char *vlan_dev_name;
-
- vlan_dev_name = vlandev_get_name(real_dev_name, vid);
- if (vlan_dev_name
- && !shash_find(ports, vlan_dev_name)) {
- shash_add(ports, vlan_dev_name,
- synthesize_splinter_port(
- real_dev_name, vlan_dev_name, vid));
- }
- }
- }
- }
- }
-}
+\f
static void
mirror_refresh_stats(struct mirror *m)
{
</column>
</group>
- <group title="VLAN Splinters">
- <p>
- The ``VLAN splinters'' feature increases Open vSwitch compatibility
- with buggy network drivers in old versions of Linux that do not
- properly support VLANs when VLAN devices are not used, at some cost
- in memory and performance.
- </p>
-
- <p>
- When VLAN splinters are enabled on a particular interface, Open vSwitch
- creates a VLAN device for each in-use VLAN. For sending traffic tagged
- with a VLAN on the interface, it substitutes the VLAN device. Traffic
- received on the VLAN device is treated as if it had been received on
- the interface on the particular VLAN.
- </p>
-
- <p>
- VLAN splinters consider a VLAN to be in use if:
- </p>
-
- <ul>
- <li>
- The VLAN is the <ref table="Port" column="tag"/> value in any <ref
- table="Port"/> record.
- </li>
-
- <li>
- The VLAN is listed within the <ref table="Port" column="trunks"/>
- column of the <ref table="Port"/> record of an interface on which
- VLAN splinters are enabled.
-
- An empty <ref table="Port" column="trunks"/> does not influence the
- in-use VLANs: creating 4,096 VLAN devices is impractical because it
- will exceed the current 1,024 port per datapath limit.
- </li>
-
- <li>
- An OpenFlow flow within any bridge matches the VLAN.
- </li>
- </ul>
-
- <p>
- The same set of in-use VLANs applies to every interface on which VLAN
- splinters are enabled. That is, the set is not chosen separately for
- each interface but selected once as the union of all in-use VLANs based
- on the rules above.
- </p>
-
- <p>
- It does not make sense to enable VLAN splinters on an interface for an
- access port, or on an interface that is not a physical port.
- </p>
-
- <p>
- VLAN splinters are deprecated. When broken device drivers are no
- longer in widespread use, we will delete this feature.
- </p>
-
- <column name="other_config" key="enable-vlan-splinters"
- type='{"type": "boolean"}'>
- <p>
- Set to <code>true</code> to enable VLAN splinters on this interface.
- Defaults to <code>false</code>.
- </p>
-
- <p>
- VLAN splinters increase kernel and userspace memory overhead, so do
- not use them unless they are needed.
- </p>
-
- <p>
- VLAN splinters do not support 802.1p priority tags. Received
- priorities will appear to be 0, regardless of their actual values,
- and priorities on transmitted packets will also be cleared to 0.
- </p>
- </column>
- </group>
-
<group title="Auto Attach Configuration">
<p>
Auto Attach configuration for a particular interface.