init_waitqueue_head(&dp->waitqueue);
/* Initialize kobject for bridge. This will be added as
- * /sys/class/net/<devname>/bridge later, if sysfs is enabled. */
+ * /sys/class/net/<devname>/brif later, if sysfs is enabled. */
dp->ifobj.kset = NULL;
kobject_init(&dp->ifobj, &dp_ktype);
if (!netdev)
return ERR_PTR(-ENOMEM);
+ dp_dev = dp_dev_priv(netdev);
+ dp_dev->dp = dp;
+ dp_dev->port_no = port_no;
+ dp_dev->dev = netdev;
+
err = register_netdevice(netdev);
if (err) {
free_netdev(netdev);
return ERR_PTR(err);
}
- dp_dev = dp_dev_priv(netdev);
- dp_dev->dp = dp;
- dp_dev->port_no = port_no;
- dp_dev->dev = netdev;
return netdev;
}
#include <linux/netdevice.h>
#include "datapath.h"
-
+#include "dp_dev.h"
static int dp_device_event(struct notifier_block *unused, unsigned long event,
void *ptr)
struct net_bridge_port *p;
struct datapath *dp;
- p = dev->br_port;
+ if (is_dp_dev(dev)) {
+ struct dp_dev *dp_dev = dp_dev_priv(dev);
+ p = dp_dev->dp->ports[dp_dev->port_no];
+ } else {
+ p = dev->br_port;
+ }
if (!p)
return NOTIFY_DONE;
dp = p->dp;
};
static struct attribute_group bridge_group = {
- .name = SYSFS_BRIDGE_ATTR,
+ .name = SYSFS_BRIDGE_ATTR, /* "bridge" */
.attrs = bridge_attrs,
};
struct kobject *kobj = &dp->ports[ODPP_LOCAL]->dev->NETDEV_DEV_MEMBER.kobj;
int err;
+ /* Create /sys/class/net/<devname>/bridge directory. */
err = sysfs_create_group(kobj, &bridge_group);
if (err) {
pr_info("%s: can't create group %s/%s\n",
/* Get all the real bridges and all the fake ones. */
cfg_read();
+ svec_init(&bridges);
cfg_get_subsections(&bridges, "bridge");
SVEC_FOR_EACH (i, br_name, &bridges) {
const char *iface_name;
svec_init(&ports);
get_bridge_ports(ovs_bridge, &ports, br_vlan);
+ svec_sort(&ports);
+ svec_del(&ports, linux_bridge);
send_ifindex_reply(seq, &ports); /* XXX bonds won't show up */
svec_destroy(&ports);
const char *port_name = nl_attr_get_string(attrs[IFLA_IFNAME]);
char br_name[IFNAMSIZ];
uint32_t br_idx = nl_attr_get_u32(attrs[IFLA_MASTER]);
- struct svec ports;
if (!if_indextoname(br_idx, br_name)) {
ofpbuf_delete(buf);
if (!netdev_exists(port_name)) {
/* Network device is really gone. */
+ struct svec ports;
+
VLOG_INFO("network device %s destroyed, "
"removing from bridge %s", port_name, br_name);
+
svec_init(&ports);
cfg_get_all_keys(&ports, "bridge.%s.port", br_name);
svec_sort(&ports);
del_port(br_name, port_name);
rewrite_and_reload_config();
}
+ svec_destroy(&ports);
} else {
/* A network device by that name exists even though the kernel
* told us it had disappeared. Probably, what happened was
used to control vswitch when integrated with Citrix management
tools.
+ usr_sbin_brctl
+
+ wrapper for /usr/sbin/brctl that provides some additional
+ bridge compatibility
+
usr_sbin_xen-bugtool
vswitch-aware replacement for Citrix script of the same name.
xenserver/opt_xensource_libexec_interface-reconfigure \
xenserver/root_vswitch_scripts_dump-vif-details \
xenserver/usr_lib_xsconsole_plugins-base_XSFeatureVSwitch.py \
+ xenserver/usr_sbin_brctl \
xenserver/usr_sbin_xen-bugtool \
xenserver/vswitch-xen.spec
VSWITCHD_PIDFILE="${VSWITCHD_PIDFILE:-/var/run/ovs-vswitchd.pid}"
VSWITCHD_RUN_DIR="${VSWITCHD_RUN_DIR:-/var/xen/vswitch}"
VSWITCHD_PRIORITY="${VSWITCHD_PRIORITY:--5}"
+VSWITCHD_NETBACK_PRIORITY="${VSWITCHD_NETBACK_PRIORITY:-0}"
VSWITCHD_LOGFILE="${VSWITCHD_LOGFILE:-/var/log/ovs-vswitchd.log}"
VSWITCHD_FILE_LOGLEVEL="${VSWITCHD_FILE_LOGLEVEL:-}"
VSWITCHD_SYSLOG_LOGLEVEL="${VSWITCHD_SYSLOG_LOGLEVEL:-WARN}"
ofctl="$VSWITCH_BASE/bin/ovs-ofctl"
-if [ "$ENABLE_FAKE_PROC_NET" == "y" ]; then
+if [ "$ENABLE_FAKE_PROC_NET" = "y" ]; then
if [ "$ENABLE_BRCOMPAT" != "y" ]; then
warning "FAKE_PROC_NET required BRCOMPAT which was disabled. Force enabling."
ENABLE_BRCOMPAT="y"
fi
}
+function quietly {
+ "$@" > /dev/null
+}
+
+# renice_netback PRIORITY PID [PID...]
+#
+# Renices the netback processes given as each PID to nice level PRIORITY.
+function renice_netback {
+ local pri=$1
+ shift
+
+ if test $# = 0; then
+ warning "Netback not running, nothing to renice"
+ return
+ fi
+
+ for pid
+ do
+ action "Renicing netback (pid $pid) to priority $pri" quietly renice $pri -p $pid
+ done
+}
+
function start_vswitchd {
local syslog_opt="-vANY:SYSLOG:${VSWITCHD_SYSLOG_LOGLEVEL}"
local logfile_file_opt=""
daemonize="n"
fi
local fake_proc_net_opt=""
- if [ "$ENABLE_FAKE_PROC_NET" == "y" ]; then
+ if [ "$ENABLE_FAKE_PROC_NET" = "y" ]; then
fake_proc_net_opt="--fake-proc-net"
fi
+ if [ "$VSWITCHD_NETBACK_PRIORITY" != default ]; then
+ renice_netback $VSWITCHD_NETBACK_PRIORITY $(pidof netback)
+ else
+ warning "Netback renicing disabled (see /etc/sysconfig/vswitch)"
+ fi
if [ "$daemonize" != "y" ]; then
# Start in background and force a "success" message
action "Starting ovs-vswitchd ($strace_opt$valgrind_opt)" true
# processes.
# VSWITCHD_PRIORITY=-5
+# VSWITCHD_NETBACK_PRIORITY: "nice" priority at which to run netback.
+# It is a good idea to run ovs-vswitchd at a higher priority than
+# netback to ensure that it gets enough CPU time to set up flows
+# (bug #1656). Set this to 'default' to avoid changing netback's
+# priority.
+# VSWITCHD_NETBACK_PRIORITY=0
+
# VSWITCHD_LOGFILE: File to send the FILE_LOGLEVEL log messages to.
# VSWITCHD_LOGFILE=/var/log/ovs-vswitchd.log
return None
def get_netdev_by_mac(mac):
- maybe = None
for device in os.listdir("/sys/class/net"):
dev_mac = get_netdev_mac(device)
- if dev_mac and mac.lower() == dev_mac.lower():
- if get_netdev_tx_queue_len(device):
+ if (dev_mac and mac.lower() == dev_mac.lower() and
+ get_netdev_tx_queue_len(device)):
return device
- if not maybe:
- # Probably a datapath internal port.
- maybe = device
- return maybe
+ return None
#
# Helper functions for encoding/decoding database attributes to/from XML.
--- /dev/null
+#! /usr/bin/python
+#
+# Copyright (c) 2009 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.
+
+import getopt
+import os
+import re
+import subprocess
+import sys
+
+argv0 = sys.argv[0]
+
+BRCTL = "/root/vswitch/xs-original/brctl"
+VSWITCHD_CONF = "/etc/ovs-vswitchd.conf"
+
+# Execute the real brctl program, passing the same arguments that were passed
+# to us.
+def delegate():
+ os.execl(BRCTL, BRCTL, *sys.argv[1:])
+ # execl should never return. We only arrive here if brctl failed to exec.
+ sys.exit(1)
+
+# Read the ovs-vswitchd.conf file named 'filename' and return its contents as a
+# dictionary that maps from string keys to lists of string values. (Even
+# singleton values are represented as lists.)
+def cfg_read(filename):
+ try:
+ f = open(filename)
+ except IOError, e:
+ sys.stderr.write("%s: could not open %s (%s)\n"
+ % (argv0, filename, e.strerror))
+ sys.exit(1)
+
+ cfg = {}
+ rx = re.compile('([-._@$:+a-zA-Z0-9]+)(?:[ \t\r\n\v]*)=(?:[ \t\r\n\v]*)(.*)$')
+ for line in f:
+ line = line.strip()
+ if len(line) == 0 or line[0] == '#':
+ continue
+
+ match = rx.match(line)
+ if match == None:
+ continue
+
+ key, value = match.groups()
+ if key not in cfg:
+ cfg[key] = []
+ cfg[key].append(value)
+ return cfg
+
+# Returns a set of the immediate subsections of 'section' within 'cfg'. For
+# example, if 'section' is "bridge" and keys bridge.a, bridge.b, bridge.b.c,
+# and bridge.c.x.y.z exist, returns set(['a', 'b', 'c']).
+def cfg_get_subsections(cfg, section):
+ subsections = set()
+ for key in cfg:
+ if key.startswith(section + "."):
+ dot = key.find(".", len(section) + 1)
+ if dot == -1:
+ dot = len(key)
+ subsections.add(key[len(section) + 1:dot])
+ return subsections
+
+# Returns True if 'cfg' contains a key whose single value is 'true'. Otherwise
+# returns False.
+def cfg_get_bool(cfg, name):
+ return name in cfg and cfg[name] == ['true']
+
+# If 'cfg' has a port named 'port' configured with an implicit VLAN, returns
+# that VLAN number. Otherwise, returns 0.
+def get_port_vlan(cfg, port):
+ try:
+ return int(cfg["vlan.%s.tag" % port][0])
+ except (ValueError, KeyError):
+ return 0
+
+# Returns all the ports within 'bridge' in 'cfg'. If 'vlan' is nonnegative,
+# the ports returned are only those configured with implicit VLAN 'vlan'.
+def get_bridge_ports(cfg, bridge, vlan):
+ ports = []
+ for port in cfg["bridge.%s.port" % bridge]:
+ if vlan < 0 or get_port_vlan(cfg, port) == vlan:
+ ports.append(port)
+ return ports
+
+# Returns all the interfaces within 'bridge' in 'cfg'. If 'vlan' is
+# nonnegative, the interfaces returned are only those whose ports are
+# configured with implicit VLAN 'vlan'.
+def get_bridge_ifaces(cfg, bridge, vlan):
+ ifaces = []
+ for port in get_bridge_ports(cfg, bridge, vlan):
+ ifaces.extend(cfg.get("bonding.%s.slave" % port, [port]))
+ return ifaces
+
+# Returns the first line of the file named 'name', with the trailing new-line
+# (if any) stripped off.
+def read_first_line_of_file(name):
+ file = None
+ try:
+ file = open(name, 'r')
+ return file.readline().rstrip('\n')
+ finally:
+ if file != None:
+ file.close()
+
+# Returns a bridge ID constructed from the MAC address of network device
+# 'netdev', in the format "8000.000102030405".
+def get_bridge_id(netdev):
+ try:
+ hwaddr = read_first_line_of_file("/sys/class/net/%s/address" % netdev)
+ return "8000.%s" % (hwaddr.replace(":", ""))
+ except:
+ return "8000.002320ffffff"
+
+def cmd_show():
+ print "bridge name\tbridge id\t\tSTP enabled\tinterfaces"
+ cfg = cfg_read(VSWITCHD_CONF)
+
+ # Find all the bridges.
+ real_bridges = [(br, br, 0) for br in cfg_get_subsections(cfg, "bridge")]
+ fake_bridges = []
+ for linux_bridge, ovs_bridge, vlan in real_bridges:
+ for iface in get_bridge_ifaces(cfg, ovs_bridge, -1):
+ if cfg_get_bool(cfg, "iface.%s.fake-bridge" % iface):
+ fake_bridges.append((iface, ovs_bridge,
+ get_port_vlan(cfg, iface)))
+ bridges = real_bridges + fake_bridges
+
+ # Find all the interfaces on each bridge.
+ for linux_bridge, ovs_bridge, vlan in bridges:
+ bridge_ports = get_bridge_ports(cfg, ovs_bridge, vlan)
+ if linux_bridge in bridge_ports:
+ bridge_ports.remove(linux_bridge)
+ bridge_ports.sort()
+ bridge_id = get_bridge_id(linux_bridge)
+ first_port = ""
+ if bridge_ports:
+ first_port = bridge_ports[0]
+ print "%s\t\t%s\t%s\t\t%s" % (linux_bridge, bridge_id, "no", first_port)
+ for port in bridge_ports[1:]:
+ print "\t\t\t\t\t\t\t%s" % port
+
+def main():
+ # Parse the command line.
+ try:
+ options, args = getopt.gnu_getopt(sys.argv[1:],
+ "hV", ["help", "version"])
+ except getopt.GetoptError, msg:
+ sys.stderr.write("%s: %s (use --help for help)\n" % (argv0, msg))
+ sys.exit(1)
+
+ # Handle command-line options.
+ for opt, optarg in options:
+ if opt == "-h" or opt == "--help":
+ delegate()
+ elif opt == "-V" or opt == "--version":
+ subprocess.call([BRCTL, "--version"])
+ print "Open vSwitch brctl wrapper"
+ sys.exit(0)
+
+ # Execute commands. Most commands are delegated to the brctl binary that
+ # we are wrapping, but we implement the "show" command ourselves.
+ if args and args[0] == "show":
+ cmd_show()
+ else:
+ delegate()
+
+if __name__ == "__main__":
+ main()
$RPM_BUILD_ROOT%{_prefix}/scripts/dump-vif-details
install -m 755 xenserver/usr_sbin_xen-bugtool \
$RPM_BUILD_ROOT%{_prefix}/scripts/xen-bugtool
+install -m 755 xenserver/usr_sbin_brctl \
+ $RPM_BUILD_ROOT%{_prefix}/scripts/brctl
install -m 644 \
xenserver/usr_lib_xsconsole_plugins-base_XSFeatureVSwitch.py \
$RPM_BUILD_ROOT%{_prefix}/scripts/XSFeatureVSwitch.py
printf "\nThe original XenServer scripts replaced by this package\n"
printf "are different than expected. This could lead to unexpected\n"
printf "behavior of your server. Unless you are sure you know what\n"
- printf "you are doing, it is highly recomended that you remove this\n"
+ printf "you are doing, it is highly recommended that you remove this\n"
printf "package immediately after the install completes, which\n"
printf "will restore the XenServer scripts that you were previously\n"
printf "using.\n\n"
fi
+ if test "`/usr/sbin/brctl --version`" != "bridge-utils, 1.1"; then
+cat <<EOF
+
+/usr/sbin/brctl replaced by this package reports the following version:
+
+`/usr/sbin/brctl --version`
+
+The expected version was:
+
+bridge-utils, 1.1
+
+Unless you are sure you know what you are doing, it is highly recommended that
+you remove this package immediately after the install completes, which will
+restore the original /usr/sbin/brctl.
+
+EOF
+ fi
fi
if test ! -e /etc/ovs-vswitch.dbcache; then
# Ensure ovs-vswitchd.conf exists
touch /etc/ovs-vswitchd.conf
-# Replace original XenServer files
+# Replace XenServer files by our versions.
mkdir -p %{_prefix}/xs-original \
|| printf "Could not create script backup directory.\n"
for f in \
/opt/xensource/libexec/interface-reconfigure \
/etc/xensource/scripts/vif \
- /usr/sbin/xen-bugtool
+ /usr/sbin/xen-bugtool \
+ /usr/sbin/brctl
do
s=$(basename "$f")
t=$(readlink "$f")
for f in \
/opt/xensource/libexec/interface-reconfigure \
/etc/xensource/scripts/vif \
- /usr/sbin/xen-bugtool
+ /usr/sbin/xen-bugtool \
+ /usr/sbin/brctl
do
s=$(basename "$f")
if [ ! -f "%{_prefix}/xs-original/$s" ]; then
/root/vswitch/scripts/vif
/root/vswitch/scripts/xen-bugtool
/root/vswitch/scripts/XSFeatureVSwitch.py
+/root/vswitch/scripts/brctl
# Following two files are generated automatically by rpm. We don't
# really need them and they won't be used on the XenServer, but there
# isn't an obvious place to get rid of them since they are generated