Merge citrix into master.
authorBen Pfaff <blp@nicira.com>
Wed, 19 Aug 2009 23:08:18 +0000 (16:08 -0700)
committerBen Pfaff <blp@nicira.com>
Wed, 19 Aug 2009 23:08:18 +0000 (16:08 -0700)
12 files changed:
datapath/datapath.c
datapath/dp_dev.c
datapath/dp_notify.c
datapath/dp_sysfs_dp.c
vswitchd/ovs-brcompatd.c
xenserver/README
xenserver/automake.mk
xenserver/etc_init.d_vswitch
xenserver/etc_sysconfig_vswitch.example
xenserver/opt_xensource_libexec_interface-reconfigure
xenserver/usr_sbin_brctl [new file with mode: 0755]
xenserver/vswitch-xen.spec

index de607e8..ab993f6 100644 (file)
@@ -224,7 +224,7 @@ static int create_dp(int dp_idx, const char __user *devnamep)
        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);
 
index 069127e..008f3f6 100644 (file)
@@ -211,16 +211,17 @@ struct net_device *dp_dev_create(struct datapath *dp, const char *dp_name, int p
        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;
 }
 
index f22d8b3..d5a2749 100644 (file)
@@ -11,7 +11,7 @@
 #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) 
@@ -20,7 +20,12 @@ static int dp_device_event(struct notifier_block *unused, unsigned long event,
        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;
index fafd9a9..3cd6d1a 100644 (file)
@@ -448,7 +448,7 @@ static struct attribute *bridge_attrs[] = {
 };
 
 static struct attribute_group bridge_group = {
-       .name = SYSFS_BRIDGE_ATTR,
+       .name = SYSFS_BRIDGE_ATTR, /* "bridge" */
        .attrs = bridge_attrs,
 };
 
@@ -467,6 +467,7 @@ int dp_sysfs_add_dp(struct datapath *dp)
        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",
index 39844f6..d351c05 100644 (file)
@@ -790,6 +790,7 @@ handle_get_bridges_cmd(struct ofpbuf *buffer)
 
     /* 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;
@@ -840,6 +841,8 @@ handle_get_ports_cmd(struct ofpbuf *buffer)
 
     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);
 
@@ -967,7 +970,6 @@ rtnl_recv_update(void)
             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);
@@ -983,8 +985,11 @@ rtnl_recv_update(void)
 
             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);
@@ -992,6 +997,7 @@ rtnl_recv_update(void)
                     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
index 6c91e94..b940e3f 100644 (file)
@@ -60,6 +60,11 @@ files are:
         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.
index 2fe1289..ceebb9d 100644 (file)
@@ -17,5 +17,6 @@ EXTRA_DIST += \
        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
index 462c2a6..abd594e 100755 (executable)
@@ -34,6 +34,7 @@ VSWITCHD_CONF="${VSWITCHD_CONF:-/etc/ovs-vswitchd.conf}"
 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}"
@@ -67,7 +68,7 @@ appctl="$VSWITCH_BASE/bin/ovs-appctl"
 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"
@@ -115,6 +116,28 @@ function reload_vswitchd {
     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=""
@@ -149,9 +172,14 @@ function start_vswitchd {
         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
index 789d61a..ea8efe1 100644 (file)
 #     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
 
index 98bcf4c..b2d5511 100755 (executable)
@@ -266,16 +266,12 @@ def get_netdev_tx_queue_len(device):
         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.
diff --git a/xenserver/usr_sbin_brctl b/xenserver/usr_sbin_brctl
new file mode 100755 (executable)
index 0000000..b97b078
--- /dev/null
@@ -0,0 +1,181 @@
+#! /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()
index 94bd916..576c6e6 100644 (file)
@@ -71,6 +71,8 @@ install -m 755 xenserver/root_vswitch_scripts_dump-vif-details \
                $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
@@ -116,11 +118,28 @@ EOF
         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
@@ -189,13 +208,14 @@ fi
 # 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")
@@ -253,7 +273,8 @@ if [ "$1" = "0" ]; then     # $1 = 1 for upgrade
     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
@@ -297,6 +318,7 @@ fi
 /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