#! /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()