diff --git a/scripts/vm/hypervisor/xenserver/cloudstack_pluginlib.py b/scripts/vm/hypervisor/xenserver/cloudstack_pluginlib.py index 552e522c98a..ead3105dc99 100644 --- a/scripts/vm/hypervisor/xenserver/cloudstack_pluginlib.py +++ b/scripts/vm/hypervisor/xenserver/cloudstack_pluginlib.py @@ -1,5 +1,5 @@ # Common function for Cloudstack's XenAPI plugins -# +# # Copyright (C) 2012 Citrix Systems import ConfigParser @@ -13,20 +13,22 @@ DEFAULT_LOG_FORMAT = "%(asctime)s %(levelname)8s [%(name)s] %(message)s" DEFAULT_LOG_DATE_FORMAT = "%Y-%m-%d %H:%M:%S" DEFAULT_LOG_FILE = "/var/log/cloudstack_plugins.log" -PLUGIN_CONFIG_PATH='/etc/xensource/cloudstack_plugins.conf' +PLUGIN_CONFIG_PATH = "/etc/xensource/cloudstack_plugins.conf" OVSDB_PID_PATH = "/var/run/openvswitch/ovsdb-server.pid" OVSDB_DAEMON_PATH = "ovsdb-server" OVS_PID_PATH = "/var/run/openvswitch/ovs-vswitchd.pid" OVS_DAEMON_PATH = "ovs-vswitchd" -VSCTL_PATH='/usr/bin/ovs-vsctl' -OFCTL_PATH='/usr/bin/ovs-ofctl' -XE_PATH= "/opt/xensource/bin/xe" +VSCTL_PATH = "/usr/bin/ovs-vsctl" +OFCTL_PATH = "/usr/bin/ovs-ofctl" +XE_PATH = "/opt/xensource/bin/xe" + class PluginError(Exception): """Base Exception class for all plugin errors.""" def __init__(self, *args): Exception.__init__(self, *args) + def setup_logging(log_file=None): debug = False verbose = False @@ -39,15 +41,15 @@ def setup_logging(log_file=None): try: options = config.options('LOGGING') if 'debug' in options: - debug = config.getboolean('LOGGING','debug') + debug = config.getboolean('LOGGING', 'debug') if 'verbose' in options: - verbose = config.getboolean('LOGGING','verbose') + verbose = config.getboolean('LOGGING', 'verbose') if 'format' in options: - log_format = config.get('LOGGING','format') + log_format = config.get('LOGGING', 'format') if 'date_format' in options: - log_date_format = config.get('LOGGING','date_format') + log_date_format = config.get('LOGGING', 'date_format') if 'file' in options: - log_file_2 = config.get('LOGGING','file') + log_file_2 = config.get('LOGGING', 'file') except ValueError: # configuration file contained invalid attributes # ignore them @@ -55,7 +57,7 @@ def setup_logging(log_file=None): except ConfigParser.NoSectionError: # Missing 'Logging' section in configuration file pass - + root_logger = logging.root if debug: root_logger.setLevel(logging.DEBUG) @@ -66,7 +68,7 @@ def setup_logging(log_file=None): formatter = logging.Formatter(log_format, log_date_format) log_filename = log_file or log_file_2 or DEFAULT_LOG_FILE - + logfile_handler = logging.FileHandler(log_filename) logfile_handler.setFormatter(formatter) root_logger.addHandler(logfile_handler) @@ -94,60 +96,65 @@ def do_cmd(cmd): return output -def _is_process_run (pidFile, name): +def _is_process_run(pidFile, name): try: - fpid = open (pidFile, "r") - pid = fpid.readline () - fpid.close () + fpid = open(pidFile, "r") + pid = fpid.readline() + fpid.close() except IOError, e: return -1 pid = pid[:-1] - ps = os.popen ("ps -ae") + ps = os.popen("ps -ae") for l in ps: if pid in l and name in l: - ps.close () + ps.close() return 0 - ps.close () + ps.close() return -2 -def _is_tool_exist (name): + +def _is_tool_exist(name): if os.path.exists(name): return 0 return -1 -def check_switch (): +def check_switch(): global result - ret = _is_process_run (OVSDB_PID_PATH, OVSDB_DAEMON_PATH) + ret = _is_process_run(OVSDB_PID_PATH, OVSDB_DAEMON_PATH) if ret < 0: - if ret == -1: return "NO_DB_PID_FILE" - if ret == -2: return "DB_NOT_RUN" + if ret == -1: + return "NO_DB_PID_FILE" + if ret == -2: + return "DB_NOT_RUN" - ret = _is_process_run (OVS_PID_PATH, OVS_DAEMON_PATH) + ret = _is_process_run(OVS_PID_PATH, OVS_DAEMON_PATH) if ret < 0: - if ret == -1: return "NO_SWITCH_PID_FILE" - if ret == -2: return "SWITCH_NOT_RUN" + if ret == -1: + return "NO_SWITCH_PID_FILE" + if ret == -2: + return "SWITCH_NOT_RUN" - if _is_tool_exist (VSCTL_PATH) < 0: + if _is_tool_exist(VSCTL_PATH) < 0: return "NO_VSCTL" - if _is_tool_exist (OFCTL_PATH) < 0: + if _is_tool_exist(OFCTL_PATH) < 0: return "NO_OFCTL" return "SUCCESS" def _build_flow_expr(**kwargs): - is_delete_expr = kwargs.get('delete', False) + is_delete_expr = kwargs.get('delete', False) flow = "" if not is_delete_expr: flow = "hard_timeout=%s,idle_timeout=%s,priority=%s"\ - % (kwargs.get('hard_timeout','0'), - kwargs.get('idle_timeout','0'), - kwargs.get('priority','1')) + % (kwargs.get('hard_timeout', '0'), + kwargs.get('idle_timeout', '0'), + kwargs.get('priority', '1')) in_port = 'in_port' in kwargs and ",in_port=%s" % kwargs['in_port'] or '' dl_type = 'dl_type' in kwargs and ",dl_type=%s" % kwargs['dl_type'] or '' dl_src = 'dl_src' in kwargs and ",dl_src=%s" % kwargs['dl_src'] or '' @@ -156,7 +163,7 @@ def _build_flow_expr(**kwargs): nw_dst = 'nw_dst' in kwargs and ",nw_dst=%s" % kwargs['nw_dst'] or '' proto = 'proto' in kwargs and ",%s" % kwargs['proto'] or '' ip = ('nw_src' in kwargs or 'nw_dst' in kwargs) and ',ip' or '' - flow = (flow + in_port + dl_type + dl_src + dl_dst + + flow = (flow + in_port + dl_type + dl_src + dl_dst + (ip or proto) + nw_src + nw_dst) return flow @@ -174,17 +181,18 @@ def add_flow(bridge, **kwargs): def del_flows(bridge, **kwargs): - """ + """ Removes flows according to criteria passed as keyword. """ flow = _build_flow_expr(delete=True, **kwargs) # out_port condition does not exist for all flow commands - out_port = 'out_port' in kwargs and ",out_port=%s" % kwargs['out_port'] or '' + out_port = ("out_port" in kwargs and + ",out_port=%s" % kwargs['out_port'] or '') flow = flow + out_port delFlow = [OFCTL_PATH, 'del-flows', bridge, flow] do_cmd(delFlow) - - + + def del_all_flows(bridge): delFlow = [OFCTL_PATH, "del-flows", bridge] do_cmd(delFlow) diff --git a/scripts/vm/hypervisor/xenserver/ovsgre b/scripts/vm/hypervisor/xenserver/ovsgre deleted file mode 100755 index c3839873a38..00000000000 --- a/scripts/vm/hypervisor/xenserver/ovsgre +++ /dev/null @@ -1,794 +0,0 @@ -#!/usr/bin/python -# Version @VERSION@ -# -# A plugin for executing script needed by vmops cloud - -import os, sys, time -import XenAPIPlugin -sys.path.append("/opt/xensource/sm/") -import util -from util import CommandException -import hostvmstats -import socket -import stat -import base64 -import tempfile -from os.path import exists as _exists -from time import localtime as _localtime, asctime as _asctime - -vSwitchDBPidFile = "/var/run/openvswitch/ovsdb-server.pid" -vSwitchDBDaemonName = "ovsdb-server" -vSwitchPidFile = "/var/run/openvswitch/ovs-vswitchd.pid" -vsctlPath = "/usr/bin/ovs-vsctl" -vSwitchDaemonName = "ovs-vswitchd" - -logFile = "/var/log/ovsgre.log" -fLog = None - -global result - -errors = \ - {"NO_DB_PID_FILE" : "NO_DB_PID_FILE", \ - "DB_NOT_RUN" : "DB_NOT_RUN", \ - "NO_SWITCH_PID_FILE" : "NO_SWITCH_PID_FILE", \ - "SWITCH_NOT_RUN" : "SWITCH_NOT_RUN", \ - "NO_VSCTL" : "NO_VSCTL", \ - "COMMAND_FAILED" : "COMMAND_FAILED", \ - "TUNNEL_EXISTED" : "TUNNEL_EXISTED", \ - "NO_INPORT" : "NO_INPORT", \ - "NO_OFPORT" : "NO_OFPORT", \ - - "ERR_ARGS_NUM" : "ERR_ARGS_NUM", \ - "ERROR_OP" : "ERROR_OP", \ - "SUCCESS" : "SUCCESS", \ - } - -class ovs_log(object): - def __init__(self, name): - n = "ovs-%s" % name; - logfilename = "/var/run/cloud/" + n +".log" - - self.name = logfilename - self.vmName = name - self.bridge = "" - self.domId = "" - self.seqno = "" - self.tag = "" - self.vifs = "" - self.macs = "" - self.vlans = "" - self.ofports = "" - - def write(self): - log = open(self.name, "w") - log.write("vmName=%s" % self.vmName) - log.write("\n") - log.write("bridge=%s" % self.bridge) - log.write("\n") - log.write("domId=%s" % self.domId) - log.write("\n") - log.write("seqno=%s" % self.seqno) - log.write("\n") - log.write("tag=%s" % self.tag) - log.write("\n") - log.write("vifs=%s" % self.vifs) - log.write("\n") - log.write("macs=%s" % self.macs) - log.write("\n") - log.write("vlans=%s" % self.vlans) - log.write("\n") - log.write("ofports=%s" % self.ofports) - log.close() - - def read(self): - try: - lines = [line.rstrip() for line in open(self.name)] - for i in lines: - if "=" not in i: - util.SMlog("invalid line(%s) in %s" % (i, self.name)) - continue - - (key,value) = i.split("=") - if key == "vmName": - self.vmName = value - elif key == "bridge": - self.bridge = value - elif key == "domId": - self.domId = value - elif key == "seqno": - self.seqno = value - elif key == "tag": - self.tag = value - elif key == "vifs": - self.vifs = value - elif key == "macs": - self.macs = value - elif key == "vlans": - self.vlans = value - elif key == "ofports": - self.ofports = value - except Exception, e: - util.SMlog(e.__str__()) - util.SMlog("Failed to open ovs log %s" % self.name); - - def get_common_info(self): - self.read() - return "%s,%s,%s,%s,%s" % (self.vmName, self.bridge, self.domId, - self.seqno, self.tag) - - def remove(self): - try: - os.remove(self.name) - except: - util.SMlog("Failed to delete ovs log file " + self.name) - -def open_log (): - global fLog - - try: - if fLog == None: - fLog = open (logFile, "a") - except IOError, e: - #print e - pass - -def pr (str): - global fLog - - if fLog != None: - str = "[%s]:" % _asctime (_localtime()) + str + "\n" - fLog.write (str) - -def close_log (): - global fLog - - if fLog != None: - fLog.close () - -def is_process_run (pidFile, name): - try: - fpid = open (pidFile, "r") - pid = fpid.readline () - fpid.close () - except IOError, e: - return -1 - - pid = pid[:-1] - ps = os.popen ("ps -ae") - for l in ps: - if pid in l and name in l: - ps.close () - return 0 - - ps.close () - return -2 - -def is_tool_exist (name): - if _exists (name): - return 0 - return -1 - - -def check_switch (): - global result - - ret = is_process_run (vSwitchDBPidFile, vSwitchDBDaemonName); - if ret < 0: - if ret == -1: result = errors["NO_DB_PID_FILE"] - if ret == -2: result = errors["DB_NOT_RUN"] - return -1 - - ret = is_process_run (vSwitchPidFile, vSwitchDaemonName) - if ret < 0: - if ret == -1: result = errors["NO_SWITCH_PID_FILE"] - if ret == -2: result = errors["SWITCH_NOT_RUN"] - return -1 - - if is_tool_exist (vsctlPath) < 0: - result = errors["NO_VSCTL"] - return -1 - - return 0 - -def do_cmd (cmds, lines=False): - cmd = "" - for i in cmds: - cmd += " " - cmd += i - - pr("do command '%s'" % cmd) - f = os.popen (cmd) - if lines == True: - res = f.readlines () - else: - res = f.readline () - res = res[:-1] - f.close () - - if lines == False: - pr("command output '%s'" % res) - return res - -######################## GRE creation utils ########################## -# UUID's format is 8-4-4-4-12 -def is_uuid (uuid): - list = uuid.split ("-") - - if len (list) != 5: - return -1 - - if len (list[0]) != 8 or len (list[1]) != 4 \ - or len (list[2]) != 4 or len (list[3]) != 4 \ - or len (list[4]) != 12: - return -1 - - return 0 - -def check_gre (bridge, remoteIP, greKey): - ports = get_ports_on_bridge(bridge) - if ports == None: - return "[]" - - for i in ports: - ifaces = get_interface_on_port(i) - if ifaces == None: - continue - - for j in ifaces: - if j == '[]': - continue - options = get_field_of_interface(j, "options") - if remoteIP in options and greKey in options: - pr("WARNING: GRE tunnel for remote_ip=%s key=%s already here, \ -interface(%s)" % (remoteIP, greKey, j)) - return get_field_of_interface(j, "ofport") - - return "[]" - -def ovs_create_gre (session, args): - global result - bridge = args.pop("bridge") - remoteIP = args.pop("remoteIP") - greKey = args.pop("greKey") - srcHost = args.pop("from") - dstHost = args.pop("to") - - name = "%s-%s" % (srcHost, dstHost) - res = check_gre(bridge, remoteIP, greKey) - if res != "[]": - result = "SUCCESS:%s" % res - return result - - wait = [vsctlPath, "--timeout=30 wait-until bridge %s -- get bridge %s name" % \ - (bridge, bridge)] - res = do_cmd(wait) - if bridge not in res: - pr("WARNIING:Can't find bridge %s for creating tunnel!" % bridge) - result = "COMMAND_FAILED_NO_BRIDGE" - return result - - createInterface = [vsctlPath, "create interface", "name=%s" % name, \ - 'type=gre options:"remote_ip=%s key=%s"' % (remoteIP, greKey)] - ifaceUUID = do_cmd (createInterface) - if is_uuid (ifaceUUID) < 0: - pr("create interface failed, %s is not UUID" % ifaceUUID) - result = "COMMAND_FAILED_CREATE_INTERFACE_FAILED" - return result - - createPort = [vsctlPath, "create port", "name=%s" % name, \ - "interfaces=[%s]" % ifaceUUID] - portUUID = do_cmd (createPort) - if is_uuid (portUUID) < 0: - pr("create port failed, %s is not UUID" % portUUID) - result = "COMMAND_FAILED_CREATE_PORT_FAILED" - return result - - addBridge = [vsctlPath, "add bridge %s" % bridge, "ports %s" % portUUID] - do_cmd (addBridge) - - wait = [vsctlPath, "--timeout=30 wait-until port %s -- get port %s name" % \ - (name, name)] - res = do_cmd(wait) - if name in res: - port = get_field_of_interface(name, "ofport"); - noFlood = [vsctlPath, "ovs-ofctl mod-port %s %s noflood" % (bridge, \ - name)] - do_cmd(noFlood) - result = "SUCCESS:%s" % port - else: - pr("create gre tunnel failed") - result = "COMMAND_FAILED_CREATE_TUNNEL_FAILED" - - return result -######################## End GRE creation utils ########################## - -######################## Flow creation utils ########################## -def get_ports_on_bridge(bridge): - listBr = [vsctlPath, "list br", bridge] - res = do_cmd(listBr, True) - - for i in res: - if "ports" in i: - (x, str) = i.split(":") - str = str.lstrip().rstrip() - str = str[1:] - str = str[:-1] - return str.split(",") - return None - -def get_filed_of_port(nameOruuid, field): - listport = [vsctlPath, "list port", nameOruuid] - res = do_cmd(listport, True) - - for i in res: - if field in i: - (x, r) = i.split(":") - return r.lstrip().rstrip() - return None - -def get_field_of_interface(nameOruuid, field): - listIface = [vsctlPath, "list interface", nameOruuid] - res = do_cmd(listIface, True) - - for i in res: - if field in i: - (x, r) = i.split(":") - return r.lstrip().rstrip() - return None - -def strip(str, direction="default"): - str = str.lstrip().rstrip() - if direction == "left": - return str[1:] - if direction == "right": - return str[:-1] - if direction == "both": - str = str[1:] - str = str[:-1] - return str - return str - -def get_vif_port(bridge, vifName): - portUuids = get_ports_on_bridge(bridge) - if portUuids == None: - pr("No ports on bridge %s" % bridge) - return None - - for i in portUuids: - name = get_filed_of_port(i, "name") - if name == None: - pr("WARNING: no name found for %s" % name) - continue - - name = strip(name, "both") - if name == vifName: - return get_field_of_interface(vifName, "ofport") - return None - -def get_interface_on_port(nameOruuid): - listPort = [vsctlPath, "list port", nameOruuid] - res = do_cmd(listPort, True) - - for i in res: - if "interfaces" in i: - (x, str) = i.split(":") - str = strip(str, "both") - return str.split(",") - return None - -def get_gre_ports(bridge): - portUuids = get_ports_on_bridge(bridge) - if portUuids == None: - pr("WARNING:No ports on bridge %s" % bridge) - return [] - - OfPorts = [] - for i in portUuids: - iface = get_filed_of_port(i, "interfaces") - iface = strip(iface, "both") - type = get_field_of_interface(iface, "type") - if type == 'gre': - port = get_field_of_interface(iface, "ofport") - if port != '[]': - OfPorts.append(port) - - return OfPorts - -def get_ofports_by_tag(bridge, tag): - portUuids = get_ports_on_bridge(bridge) - if portUuids == None: - pr("WARNING:No ports on bridge %s" % bridge) - return [] - - OfPorts = [] - for i in portUuids: - t = get_filed_of_port(i, "tag") - if t != tag: - pr("Skip port %s with tag=%s" % (i, t)) - continue - - iface = get_filed_of_port(i, "interfaces") - iface = strip(iface, "both") - port = get_field_of_interface(iface, "ofport") - if port != '[]': - OfPorts.append(port) - - return OfPorts - -def format_flow(inPort, vlan, mac, outPut): - flow = "in_port=%s dl_vlan=%s dl_dst=%s idle_timeout=0 hard_timeout=0 \ - priority=10000 actions=strip_vlan,output:%s" % (inPort, vlan, mac, outPut) - return flow - -def format_drop_flow(inPort): - flow = "in_port=%s priority=1000 idle_timeout=0 hard_timeout=0 \ - actions=drop" % inPort - return flow - -def add_drop_flow(bridge, port): - flow = format_drop_flow(port) - add_flow(bridge, flow) - -def del_flow(bridge, mac): - param = "dl_dst=%s" % mac - flow = ["ovs-ofctl del-flows %s" % bridge, '"%s"' % param] - do_cmd(flow) - -def del_arp_and_dhcp_flow(bridge, vlan, inPort): - param = "dl_type=0x0806 dl_vlan=%s in_port=%s" % (vlan, inPort) - flow = ["ovs-ofctl del-flows %s" % bridge, '"%s"' % param] - do_cmd(flow) - - param = "dl_type=0x0800 nw_proto=17 tp_dst=68 dl_vlan=%s, in_port=%s" % (vlan, inPort) - flow = ["ovs-ofctl del-flows %s" % bridge, '"%s"' % param] - do_cmd(flow) - - param = "dl_type=0x0800 nw_proto=17 tp_dst=67 dl_vlan=%s, in_port=%s" % (vlan, inPort) - flow = ["ovs-ofctl del-flows %s" % bridge, '"%s"' % param] - do_cmd(flow) - -def format_normal_flow(): - flow = "priority=0 idle_timeout=0 hard_timeout=0 actions=normal" - return flow - -def format_dhcp_flow(bridge, inPort, vlan, ports): - outputs = '' - for i in ports: - str = "output:%s," % i - outputs += str - outputs = outputs[:-1] - flow = "in_port=%s dl_vlan=%s dl_type=0x0800 nw_proto=17 tp_dst=67 idle_timeout=0 hard_timeout=0 \ - priority=10000 actions=strip_vlan,%s" % (inPort, vlan, outputs) - return flow - -def format_dhcp_client_flow(bridge, inPort, vlan, ports): - outputs = '' - for i in ports: - str = "output:%s," % i - outputs += str - outputs = outputs[:-1] - flow = "in_port=%s dl_vlan=%s dl_type=0x0800 nw_proto=17 tp_dst=68 idle_timeout=0 hard_timeout=0 \ - priority=10000 actions=strip_vlan,%s" % (inPort, vlan, outputs) - return flow - -def format_arp_flow(bridge, inPort, vlan, ports): - outputs = '' - for i in ports: - str = "output:%s," % i - outputs += str - - outputs = outputs[:-1] - flow = "in_port=%s dl_vlan=%s dl_type=0x0806 idle_timeout=0 hard_timeout=0 \ - priority=10000 actions=strip_vlan,%s" % (inPort, vlan, outputs) - return flow - -def create_flow (bridge, vifName, mac, vlans): - global result - - output = get_vif_port(bridge, vifName) - if output == None: - pr("WARNING: cannot find ofport for %s" % vifName) - return errors["NO_OFPORT"] - return -1 - if output == '[]': - pr("WARNING: ofport is [] for %s" % vifName) - return errors["NO_OFPORT"] - return -1 - - #set remap here, remap has format e.g. 1/22/200/13/16 - pr("") - pr("Create flow for vlans=%s" % vlans) - for v in vlans.split(","): - try: - (vlan, inPort) = v.split(":") - flow = format_flow(inPort, vlan, mac, output) - add_flow(bridge, flow) - except Exception, e: - pr(e.__str__()) - pr("invalid map") - - # add normal flow make switch work as L2/L3 switch - flow = format_normal_flow() - add_flow(bridge, flow) - - inports = get_gre_ports(bridge) - for i in inports: - add_drop_flow(bridge, i) - - return errors["SUCCESS"] -######################## End Flow creation utils ########################## - -def set_tag(bridge, vifName, vlan): - # The startVM command is slow, we may wait for a while for it creates vif on - # open vswitch - pr("Waiting for %s ..." % vifName) - waitPortCmd = [vsctlPath, "--timeout=10 wait-until port %s -- get port %s name" % \ - (vifName, vifName)] - do_cmd (waitPortCmd) - pr("%s is here" % vifName) - - if get_vif_port(bridge, vifName) == None: - pr("WARNING: %s is not on bridge %s" % (vifName, bridge)) - return 0 - - pr("Set tag") - set_tagCmd = [vsctlPath, "set port", vifName, "tag=%s"%vlan] - do_cmd (set_tagCmd) - return 0 - -def ask_ports(bridge, vifNames): - vifs = vifNames.split(",") - if len(vifs) == 0: - return ' ' - - ofports = [] - for vif in vifs: - op = get_vif_port(bridge, vif) - if op == None: - pr("ask_ports: no port(bridge:%s, vif:%s)" % (bridge, vif)) - continue - ofports.append(op) - - return ",".join(ofports) - -def delete_vm_flows(bridge, vmName, reCreate=True): - log = ovs_log(vmName) - log.read() - - macs = log.macs; - for i in macs.split(","): - del_flow(bridge, i) - pr("Delete flows for %s" % i) - - vlans = log.vlans - for v in vlans.split(","): - try: - (vlan, inPort) = v.split(":") - del_arp_and_dhcp_flow(bridge, vlan, inPort) - except Exception, e: - pr(e.__str__()) - pr("invalid map") - - if reCreate == False: - return - - bridge = log.bridge - tag = log.tag - noneGreOfPorts = get_ofports_by_tag(bridge, tag) - - try: - noneGreOfPorts.remove(log.ofports) - except Exception, e: - pr(e.__str__()) - pr("ofport %s of %s is not on bridge %s" % (log.ofports, log.vmName, - bridge)) - - if len(noneGreOfPorts) != 0: - set_arp_and_dhcp_flow(bridge, vlans, tag, noneGreOfPorts) - - # add normal flow make switch work as L2/L3 switch - flow = format_normal_flow() - add_flow(bridge, flow) - - log.remove() - -def echo(fn): - def wrapped(*v, **k): - name = fn.__name__ - util.SMlog("#### VMOPS enter %s ####" % name ) - res = fn(*v, **k) - util.SMlog("#### VMOPS exit %s ####" % name ) - return res - return wrapped - - -def ovs_handle_rebooted_vm(session, vmName): - curr_domid = '-1' - log = ovs_log(vmName) - log.read() - - (curr_domid, vifrs, hostuuid) = ovs_get_domid_vifrs_hostuuid(session, vmName) - - old_id = log.domId; - if curr_domid == old_id: - util.SMlog("OvsInfo:%s is normal" % vmName) - return True - - util.SMlog("%s rebooted, reset flow for it" % vmName) - vlans = log.vlans; - bridge = log.bridge - tag = log.tag - for vifr in vifrs: - vifName = "vif" + curr_domid + "." + vifr[0] - set_tag(bridge, vifName, tag) - create_flow(bridge, vifName, vifr[1], vlans) - - log.domId = curr_domid - log.write() - - return True - -@echo -def ovs_get_vm_log(session, args): - host_uuid = args.pop('host_uuid') - try: - thishost = session.xenapi.host.get_by_uuid(host_uuid) - hostrec = session.xenapi.host.get_record(thishost) - vms = hostrec.get('resident_VMs') - except Exception, e: - util.SMlog("Failed to get host from uuid %s, exception: %s" % (host_uuid, e.__str__())) - return ' ' - - result = [] - try: - for name in [session.xenapi.VM.get_name_label(x) for x in vms]: - if 1 not in [ name.startswith(c) for c in ['r-', 'i-'] ]: - continue - ovs_handle_rebooted_vm(session, name) - if name.startswith('i-'): - log = ovs_log(name) - info = log.get_common_info() - result.append(info) - except Exception, e: - util.SMlog(e.__str__()) - util.SMlog("OVs failed to get logs, better luck next time!") - - return ";".join(result) - -def ovs_write_vm_log(bridge, vmName, vmId, seqno, vifNames, macs, tag, vlans, ofports): - log = ovs_log(vmName) - log.read() - log.bridge = bridge - log.vmName = vmName - log.domId = vmId - log.seqno = seqno - log.vifs = vifNames - log.macs = macs - log.tag = tag - log.vlans = vlans - log.ofports = ofports - log.write() - - util.SMlog("Writing ovs log to " + log.name) - -@echo -def ovs_delete_flow(session, args): - bridge = args.pop('bridge') - vmName = args.pop('vmName') - - delete_vm_flows(bridge, vmName) - return 'SUCCESS' - -def ovs_get_domid_vifrs_hostuuid(session, vmName): - def get_vif_field(name, field): - return session.xenapi.VIF.get_record(name).get(field) - - try: - vm = session.xenapi.VM.get_by_name_label(vmName) - if len(vm) != 1: - return (-1, [], "-1") - vm_rec = session.xenapi.VM.get_record(vm[0]) - vm_vifs = vm_rec.get('VIFs') - vifrs = [] - for vif in vm_vifs: - rec = (get_vif_field(vif, 'device'), get_vif_field(vif, 'MAC')) - vifrs.append(rec) - domid = vm_rec.get('domid') - host = vm_rec.get('resident_on') - host_rec = session.xenapi.host.get_record(host) - uuid = host_rec.get('uuid') - util.SMlog("OVSINFO: (domid:%s, uuid:%s)" % (domid, uuid)) - return (domid, vifrs, uuid) - - except: - util.SMlog("### Failed to get domid or vif list for vm ##" + vmName) - return (-1, [], "-1") - -def add_flow(bridge, flow): - param = bridge + ' "%s"' % flow - addflow = ["ovs-ofctl add-flow", param] - do_cmd (addflow) - -def set_arp_and_dhcp_flow(bridge, vlans, tag, ofports): - for v in vlans.split(","): - try: - (vlan, inPort) = v.split(":") - arpFlow = format_arp_flow(bridge, inPort, vlan, ofports) - add_flow(bridge, arpFlow) - - dhcpFlow = format_dhcp_flow(bridge, inPort, vlan, ofports) - add_flow(bridge, dhcpFlow) - - dhcpClientFlow = format_dhcp_client_flow(bridge, inPort, vlan, ofports) - add_flow(bridge, dhcpClientFlow) - except Exception, e: - pr(e.__str__()) - pr("invalid map") - -@echo -def ovs_set_arp_and_dhcp_flow(session, args): - vlans = args.pop('vlans') - bridge = args.pop('bridge') - tag = args.pop('tag') - - pr("ovs_set_arp_and_dhcp_flow: bridge=%s, vlans=%s, tag=%s" % (bridge, - vlans, tag)) - if vlans == '[]': - pr("No need to create arp and dhcp flow") - return 'SUCCESS' - - ofports = get_ofports_by_tag(bridge, tag) - if len(ofports) == 0: - pr("No VMs, skip set arp and dhcp flow for tag=%s" % tag) - return 'SUCCESS' - - set_arp_and_dhcp_flow(bridge, vlans, tag, ofports) - return 'SUCCESS' - -@echo -def ovs_set_tag_and_flow(session, args): - bridge = args.pop('bridge') - vmName = args.pop('vmName') - vlans = args.pop('vlans') - tag = args.pop('tag') - seqno = args.pop('seqno') - - (domid, vifrs, hostuuid) = ovs_get_domid_vifrs_hostuuid(session, vmName) - - if domid == '-1': - util.SMlog("### Failed to get domid for vm (-1): " + vmName) - return 'NO_DOMID' - - if len(vifrs) == 0: - return 'SUCCESS' - - pr("ovs_set_tag_and_flow: bridge=%s, vmName=%s, vlans=%s, tag=%s, seqno=%s" % - (bridge, vmName, vlans, tag, seqno)) - #delete old flows first - delete_vm_flows(bridge, vmName, False) - - vifNames = [] - vlans = strip(vlans, "both") - macs = [] - for vifr in vifrs: - vifName = "vif" + domid + "." + vifr[0] - vifNames.append(vifName) - mac = vifr[1] - macs.append(mac) - set_tag(bridge, vifName, tag) - create_flow(bridge, vifName, mac, vlans) - - vifs = ",".join(vifNames) - ofports = ask_ports(bridge, vifs) - ovs_write_vm_log(bridge, vmName, domid, seqno, vifs, ",".join(macs), tag, vlans, ofports) - - #see if there is rebooted vm to handle - ovs_get_vm_log(session, {"host_uuid":hostuuid}) - ovs_set_arp_and_dhcp_flow(session, {"bridge":bridge, "tag":tag, "vlans":vlans}) - return 'SUCCESS' - -if __name__ == "__main__": - open_log() - XenAPIPlugin.dispatch({"ovs_create_gre":ovs_create_gre, "ovs_set_tag_and_flow":ovs_set_tag_and_flow, "ovs_get_vm_log":ovs_get_vm_log,"ovs_delete_flow":ovs_delete_flow}) - close_log() - diff --git a/scripts/vm/hypervisor/xenserver/ovstunnel b/scripts/vm/hypervisor/xenserver/ovstunnel index 0790e1f68c3..0814ab95fec 100755 --- a/scripts/vm/hypervisor/xenserver/ovstunnel +++ b/scripts/vm/hypervisor/xenserver/ovstunnel @@ -1,300 +1,243 @@ #!/usr/bin/python -# Version @VERSION@ -# -# A plugin for executing script needed by vmops cloud +# Creates a tunnel mesh across xenserver hosts +# Enforces broadcast drop rules on ingress GRE tunnels import cloudstack_pluginlib as lib import logging -import os, sys, time +import os +import sys import subprocess +import time import XenAPIPlugin + sys.path.append("/opt/xensource/sm/") import util + from time import localtime as _localtime, asctime as _asctime -xePath= "/opt/xensource/bin/xe" +xePath = "/opt/xensource/bin/xe" lib.setup_logging("/var/log/ovstunnel.log") -def find_vifs_v5(xs_nw_uuid): - logging.debug("Fetching vifs on networks - for XS version 5.x") - vif_uuids_cmd = [xePath, 'network-list', 'uuid=%s' %xs_nw_uuid, - 'params=VIF-uuids', '--minimal'] - vif_uuids_str = lib.do_cmd(vif_uuids_cmd) - vif_uuids = vif_uuids_str.split(';') - vifs = [] - for vif_uuid in vif_uuids: - vif_uuid = vif_uuid.strip() - is_attached_cmd = [xePath, 'vif-list', 'uuid=%s' %vif_uuid, - 'params=currently-attached', '--minimal'] - is_attached = lib.do_cmd(is_attached_cmd) - # Consider only attached VIFs - if is_attached == 'false': - continue - vm_uuid_cmd = [xePath, 'vif-list', 'uuid=%s' %vif_uuid, - 'params=vm-uuid', '--minimal'] - vm_uuid = lib.do_cmd(vm_uuid_cmd) - dom_id_cmd = [xePath, 'vm-list', 'uuid=%s' %vm_uuid, - 'params=dom-id', '--minimal'] - dom_id = lib.do_cmd(dom_id_cmd) - device_cmd = [xePath, 'vif-list', 'uuid=%s' %vif_uuid, - 'params=device', '--minimal'] - device = lib.do_cmd(device_cmd) - vifs.append("vif%s.%s" % (dom_id, device)) - logging.debug("Vifs on network:%s" %vifs) - vif_ofports = [] - for vif in vifs: - vif_ofport_cmd=[lib.VSCTL_PATH, 'get', 'interface', vif, 'ofport'] - vif_ofport = lib.do_cmd(vif_ofport_cmd).strip() - if vif_ofport.endswith('\n'): - vif_ofport = vif_ofport[:-1] - vif_ofports.append(vif_ofport.strip()) - return vif_ofports - - -def find_vifs_v6(xs_nw_uuid): - logging.debug("Fetching vifs on networks - for XS version 6.x") - cmd_vif_ofports = [lib.VSCTL_PATH, "--", "--columns=ofport", - "find", "interface", - "external_ids:xs-network-uuid=%s" % xs_nw_uuid, - "type!=gre"] - vif_ofports_str = lib.do_cmd(cmd_vif_ofports) - vif_ofports = [] - for line in vif_ofports_str.split('\n'): - elements = line.split(':') - if len(elements)==2: - # ensure no trailing \n is returned - if elements[1].endswith('\n'): - elements[1] = elements[1][:-1] - vif_ofports.append(elements[1].strip()) - return vif_ofports - -vif_ofport_list_handlers = { - '5': find_vifs_v5, - '6': find_vifs_v6} - def block_ipv6_v5(bridge): - lib.add_flow(bridge, priority=65000, dl_type='0x86dd', actions='drop') + lib.add_flow(bridge, priority=65000, dl_type='0x86dd', actions='drop') def block_ipv6_v6(bridge): - lib.add_flow(bridge, priority=65000, proto='ipv6', actions='drop') + lib.add_flow(bridge, priority=65000, proto='ipv6', actions='drop') block_ipv6_handlers = { - '5': block_ipv6_v5, - '6': block_ipv6_v6} - - -class PluginError(Exception): - """Base Exception class for all plugin errors.""" - def __init__(self, *args): - Exception.__init__(self, *args) + '5': block_ipv6_v5, + '6': block_ipv6_v6} def echo(fn): - def wrapped(*v, **k): - name = fn.__name__ - util.SMlog("#### VMOPS enter %s ####" % name ) - res = fn(*v, **k) - util.SMlog("#### VMOPS exit %s ####" % name ) - return res - return wrapped + def wrapped(*v, **k): + name = fn.__name__ + util.SMlog("#### VMOPS enter %s ####" % name) + res = fn(*v, **k) + util.SMlog("#### VMOPS exit %s ####" % name) + return res + return wrapped @echo def setup_ovs_bridge(session, args): - bridge = args.pop("bridge") - key = args.pop("key") - xs_nw_uuid = args.pop("xs_nw_uuid") - cs_host_id = args.pop("cs_host_id") - - res = lib.check_switch() - if res != "SUCCESS": - return "FAILURE:%s" %res + bridge = args.pop("bridge") + key = args.pop("key") + xs_nw_uuid = args.pop("xs_nw_uuid") + cs_host_id = args.pop("cs_host_id") - logging.debug("About to manually create the bridge:%s" %bridge) - # create a bridge with the same name as the xapi network - # also associate gre key in other config attribute - res = lib.do_cmd([lib.VSCTL_PATH, "--", "--may-exist", "add-br", bridge, - "--", "set", "bridge", bridge, - "other_config:gre_key=%s" % key]) - logging.debug("Bridge has been manually created:%s" %res) - # TODO: Make sure xs-network-uuid is set into external_ids - lib.do_cmd([lib.VSCTL_PATH, "set", "Bridge", bridge, - "external_ids:xs-network-uuid=%s" % xs_nw_uuid]) - # Non empty result means something went wrong - if res: - result = "FAILURE:%s" %res - else: - # Verify the bridge actually exists, with the gre_key properly set - res = lib.do_cmd([lib.VSCTL_PATH, "get", "bridge", - bridge, "other_config:gre_key"]) - if key in res: - result = "SUCCESS:%s" %bridge - else: - result = "FAILURE:%s" %res - # Finally note in the xenapi network object that the network has - # been configured - xs_nw_uuid = lib.do_cmd([lib.XE_PATH, "network-list", - "bridge=%s" % bridge, "--minimal"]) - lib.do_cmd([lib.XE_PATH,"network-param-set", "uuid=%s" % xs_nw_uuid, - "other-config:is-ovs-tun-network=True"]) - conf_hosts = lib.do_cmd([lib.XE_PATH,"network-param-get", - "uuid=%s" % xs_nw_uuid, - "param-name=other-config", - "param-key=ovs-host-setup", "--minimal"]) - conf_hosts = cs_host_id + (conf_hosts and ',%s' % conf_hosts or '') - lib.do_cmd([lib.XE_PATH,"network-param-set", "uuid=%s" % xs_nw_uuid, - "other-config:ovs-host-setup=%s" %conf_hosts]) - - # BLOCK IPv6 - Flow spec changes with ovs version - host_list_cmd = [lib.XE_PATH, 'host-list', '--minimal'] - host_list_str = lib.do_cmd(host_list_cmd) - host_uuid = host_list_str.split(',')[0].strip() - version_cmd = [lib.XE_PATH, 'host-param-get', 'uuid=%s' % host_uuid, - 'param-name=software-version', - 'param-key=product_version'] - version = lib.do_cmd(version_cmd).split('.')[0] - block_ipv6_handlers[version](bridge) - logging.debug("Setup_ovs_bridge completed with result:%s" %result) - return result + res = lib.check_switch() + if res != "SUCCESS": + return "FAILURE:%s" % res + + logging.debug("About to manually create the bridge:%s" % bridge) + # create a bridge with the same name as the xapi network + # also associate gre key in other config attribute + res = lib.do_cmd([lib.VSCTL_PATH, "--", "--may-exist", "add-br", bridge, + "--", "set", "bridge", bridge, + "other_config:gre_key=%s" % key]) + logging.debug("Bridge has been manually created:%s" % res) + # TODO: Make sure xs-network-uuid is set into external_ids + lib.do_cmd([lib.VSCTL_PATH, "set", "Bridge", bridge, + "external_ids:xs-network-uuid=%s" % xs_nw_uuid]) + # Non empty result means something went wrong + if res: + result = "FAILURE:%s" % res + else: + # Verify the bridge actually exists, with the gre_key properly set + res = lib.do_cmd([lib.VSCTL_PATH, "get", "bridge", + bridge, "other_config:gre_key"]) + if key in res: + result = "SUCCESS:%s" % bridge + else: + result = "FAILURE:%s" % res + # Finally note in the xenapi network object that the network has + # been configured + xs_nw_uuid = lib.do_cmd([lib.XE_PATH, "network-list", + "bridge=%s" % bridge, "--minimal"]) + lib.do_cmd([lib.XE_PATH, "network-param-set", "uuid=%s" % xs_nw_uuid, + "other-config:is-ovs-tun-network=True"]) + conf_hosts = lib.do_cmd([lib.XE_PATH, "network-param-get", + "uuid=%s" % xs_nw_uuid, + "param-name=other-config", + "param-key=ovs-host-setup", "--minimal"]) + conf_hosts = cs_host_id + (conf_hosts and ',%s' % conf_hosts or '') + lib.do_cmd([lib.XE_PATH, "network-param-set", "uuid=%s" % xs_nw_uuid, + "other-config:ovs-host-setup=%s" % conf_hosts]) + + # BLOCK IPv6 - Flow spec changes with ovs version + host_list_cmd = [lib.XE_PATH, 'host-list', '--minimal'] + host_list_str = lib.do_cmd(host_list_cmd) + host_uuid = host_list_str.split(',')[0].strip() + version_cmd = [lib.XE_PATH, 'host-param-get', 'uuid=%s' % host_uuid, + 'param-name=software-version', + 'param-key=product_version'] + version = lib.do_cmd(version_cmd).split('.')[0] + block_ipv6_handlers[version](bridge) + logging.debug("Setup_ovs_bridge completed with result:%s" % result) + return result @echo def destroy_ovs_bridge(session, args): - bridge = args.pop("bridge") - res = lib.check_switch() - # TODO: Must complete this routine - if res != "SUCCESS": - return res - res = lib.do_cmd([lib.VSCTL_PATH, "del-br", bridge]) - logging.debug("Bridge has been manually removed:%s" %res) - if res: - result = "FAILURE:%s" %res - else: - # Note that the bridge has been removed on xapi network object - xs_nw_uuid = lib.do_cmd([xePath, "network-list", - "bridge=%s" % bridge, "--minimal"]) - #lib.do_cmd([xePath,"network-param-set", "uuid=%s" % xs_nw_uuid, - # "other-config:ovs-setup=False"]) - result = "SUCCESS:%s" %bridge + bridge = args.pop("bridge") + res = lib.check_switch() + if res != "SUCCESS": + return res + res = lib.do_cmd([lib.VSCTL_PATH, "del-br", bridge]) + logging.debug("Bridge has been manually removed:%s" % res) + if res: + result = "FAILURE:%s" % res + else: + # Note that the bridge has been removed on xapi network object + xs_nw_uuid = lib.do_cmd([xePath, "network-list", + "bridge=%s" % bridge, "--minimal"]) + #FIXME: WOW, this an error + #lib.do_cmd([xePath,"network-param-set", "uuid=%s" % xs_nw_uuid, + # "other-config:ovs-setup=False"]) + result = "SUCCESS:%s" % bridge + + logging.debug("Destroy_ovs_bridge completed with result:%s" % result) + return result + - logging.debug("Destroy_ovs_bridge completed with result:%s" %result) - return result - - @echo def create_tunnel(session, args): - bridge = args.pop("bridge") - remote_ip = args.pop("remote_ip") - gre_key = args.pop("key") - src_host = args.pop("from") - dst_host = args.pop("to") - - logging.debug("Entering create_tunnel") - - res = lib.check_switch() - if res != "SUCCESS": - logging.debug("Openvswitch running: NO") - return "FAILURE:%s" %res - - # We need to keep the name below 14 characters - # src and target are enough - consider a fixed length hash - name = "t%s-%s-%s" % (gre_key, src_host, dst_host) - - # Verify the xapi bridge to be created - # NOTE: Timeout should not be necessary anymore - wait = [lib.VSCTL_PATH, "--timeout=30", "wait-until", "bridge", bridge, "--", - "get", "bridge", bridge, "name"] - res = lib.do_cmd(wait) - if bridge not in res: - logging.debug("WARNING:Can't find bridge %s for creating " + - "tunnel!" % bridge) - return "FAILURE:NO_BRIDGE" - logging.debug("bridge %s for creating tunnel - VERIFIED" % bridge) - tunnel_setup = False - drop_flow_setup = False - try: - # Create a port and configure the tunnel interface for it - add_tunnel = [lib.VSCTL_PATH, "add-port", bridge, name, "--", "set", "interface", - name, "type=gre", "options:key=%s" % gre_key, - "options:remote_ip=%s" % remote_ip] - lib.do_cmd(add_tunnel) - tunnel_setup = True - # verify port - verify_port = [lib.VSCTL_PATH, "get", "port", name, "interfaces"] - res = lib.do_cmd(verify_port) - # Expecting python-style list as output - iface_list = [] - if len(res) > 2: - iface_list = res.strip()[1:-1].split(',') - if len(iface_list) != 1: - logging.debug("WARNING: Unexpected output while verifying " + - "port %s on bridge %s" %(name, bridge)) - return "FAILURE:VERIFY_PORT_FAILED" - - # verify interface - iface_uuid = iface_list[0] - verify_interface_key = [lib.VSCTL_PATH, "get", "interface", - iface_uuid, "options:key"] - verify_interface_ip = [lib.VSCTL_PATH, "get", "interface", - iface_uuid, "options:remote_ip"] - - key_validation = lib.do_cmd(verify_interface_key) - ip_validation = lib.do_cmd(verify_interface_ip) - - if not gre_key in key_validation or not remote_ip in ip_validation: - logging.debug("WARNING: Unexpected output while verifying " + - "interface %s on bridge %s" %(name, bridge)) - return "FAILURE:VERIFY_INTERFACE_FAILED" - logging.debug("Tunnel interface validated:%s" %verify_interface_ip) - cmd_tun_ofport = [lib.VSCTL_PATH, "get", "interface", - iface_uuid, "ofport"] - tun_ofport = lib.do_cmd(cmd_tun_ofport) - # Ensure no trailing LF - if tun_ofport.endswith('\n'): - tun_ofport = tun_ofport[:-1] - # add flow entryies for dropping broadcast coming in from gre tunnel - lib.add_flow(bridge, priority=1000, in_port=tun_ofport, - dl_dst='ff:ff:ff:ff:ff:ff', actions='drop') - lib.add_flow(bridge, priority=1000, in_port=tun_ofport, - nw_dst='224.0.0.0/24', actions='drop') - drop_flow_setup = True - logging.debug("Broadcast drop rules added") - return "SUCCESS:%s" % name - except: - logging.debug("An unexpected error occured. Rolling back") - if tunnel_setup: - logging.debug("Deleting GRE interface") - # Destroy GRE port and interface - lib.del_port(bridge, name) - if drop_flow_setup: - # Delete flows - logging.debug("Deleting flow entries from GRE interface") - lib.del_flows(bridge, in_port=tun_ofport) - raise + bridge = args.pop("bridge") + remote_ip = args.pop("remote_ip") + gre_key = args.pop("key") + src_host = args.pop("from") + dst_host = args.pop("to") + + logging.debug("Entering create_tunnel") + + res = lib.check_switch() + if res != "SUCCESS": + logging.debug("Openvswitch running: NO") + return "FAILURE:%s" % res + + # We need to keep the name below 14 characters + # src and target are enough - consider a fixed length hash + name = "t%s-%s-%s" % (gre_key, src_host, dst_host) + + # Verify the xapi bridge to be created + # NOTE: Timeout should not be necessary anymore + wait = [lib.VSCTL_PATH, "--timeout=30", "wait-until", "bridge", + bridge, "--", "get", "bridge", bridge, "name"] + res = lib.do_cmd(wait) + if bridge not in res: + logging.debug("WARNING:Can't find bridge %s for creating " + + "tunnel!" % bridge) + return "FAILURE:NO_BRIDGE" + logging.debug("bridge %s for creating tunnel - VERIFIED" % bridge) + tunnel_setup = False + drop_flow_setup = False + try: + # Create a port and configure the tunnel interface for it + add_tunnel = [lib.VSCTL_PATH, "add-port", bridge, + name, "--", "set", "interface", + name, "type=gre", "options:key=%s" % gre_key, + "options:remote_ip=%s" % remote_ip] + lib.do_cmd(add_tunnel) + tunnel_setup = True + # verify port + verify_port = [lib.VSCTL_PATH, "get", "port", name, "interfaces"] + res = lib.do_cmd(verify_port) + # Expecting python-style list as output + iface_list = [] + if len(res) > 2: + iface_list = res.strip()[1:-1].split(',') + if len(iface_list) != 1: + logging.debug("WARNING: Unexpected output while verifying " + + "port %s on bridge %s" % (name, bridge)) + return "FAILURE:VERIFY_PORT_FAILED" + + # verify interface + iface_uuid = iface_list[0] + verify_interface_key = [lib.VSCTL_PATH, "get", "interface", + iface_uuid, "options:key"] + verify_interface_ip = [lib.VSCTL_PATH, "get", "interface", + iface_uuid, "options:remote_ip"] + + key_validation = lib.do_cmd(verify_interface_key) + ip_validation = lib.do_cmd(verify_interface_ip) + + if not gre_key in key_validation or not remote_ip in ip_validation: + logging.debug("WARNING: Unexpected output while verifying " + + "interface %s on bridge %s" % (name, bridge)) + return "FAILURE:VERIFY_INTERFACE_FAILED" + logging.debug("Tunnel interface validated:%s" % verify_interface_ip) + cmd_tun_ofport = [lib.VSCTL_PATH, "get", "interface", + iface_uuid, "ofport"] + tun_ofport = lib.do_cmd(cmd_tun_ofport) + # Ensure no trailing LF + if tun_ofport.endswith('\n'): + tun_ofport = tun_ofport[:-1] + # add flow entryies for dropping broadcast coming in from gre tunnel + lib.add_flow(bridge, priority=1000, in_port=tun_ofport, + dl_dst='ff:ff:ff:ff:ff:ff', actions='drop') + lib.add_flow(bridge, priority=1000, in_port=tun_ofport, + nw_dst='224.0.0.0/24', actions='drop') + drop_flow_setup = True + logging.debug("Broadcast drop rules added") + return "SUCCESS:%s" % name + except: + logging.debug("An unexpected error occured. Rolling back") + if tunnel_setup: + logging.debug("Deleting GRE interface") + # Destroy GRE port and interface + lib.del_port(bridge, name) + if drop_flow_setup: + # Delete flows + logging.debug("Deleting flow entries from GRE interface") + lib.del_flows(bridge, in_port=tun_ofport) + # This will not cancel the original exception + raise @echo def destroy_tunnel(session, args): - bridge = args.pop("bridge") - iface_name = args.pop("in_port") - logging.debug("Destroying tunnel at port %s for bridge %s" - % (iface_name, bridge)) - ofport = get_field_of_interface(iface_name, "ofport") - lib.del_flows(bridge, in_port=ofport) - lib.del_port(bridge, iface_name) - return "SUCCESS" + bridge = args.pop("bridge") + iface_name = args.pop("in_port") + logging.debug("Destroying tunnel at port %s for bridge %s" + % (iface_name, bridge)) + ofport = get_field_of_interface(iface_name, "ofport") + lib.del_flows(bridge, in_port=ofport) + lib.del_port(bridge, iface_name) + return "SUCCESS" def get_field_of_interface(iface_name, field): - get_iface_cmd = [lib.VSCTL_PATH, "get","interface", iface_name, field] - res = lib.do_cmd(get_iface_cmd) - return res + get_iface_cmd = [lib.VSCTL_PATH, "get", "interface", iface_name, field] + res = lib.do_cmd(get_iface_cmd) + return res + if __name__ == "__main__": - XenAPIPlugin.dispatch({"create_tunnel":create_tunnel, - "destroy_tunnel":destroy_tunnel, - "setup_ovs_bridge": setup_ovs_bridge, - "destroy_ovs_bridge": destroy_ovs_bridge}) + XenAPIPlugin.dispatch({"create_tunnel": create_tunnel, + "destroy_tunnel": destroy_tunnel, + "setup_ovs_bridge": setup_ovs_bridge, + "destroy_ovs_bridge": destroy_ovs_bridge})