--- /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