You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by hu...@apache.org on 2013/10/07 13:58:47 UTC
[2/2] git commit: updated refs/heads/sdnextensions to 3056b1a
adding KVM support for GRE controller
Signed-off-by: Hugo Trippaers <ht...@schubergphilis.com>
Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/3056b1a9
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/3056b1a9
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/3056b1a9
Branch: refs/heads/sdnextensions
Commit: 3056b1a9f8be155d0a66117d8335d6c3a23dcad0
Parents: a0a8183
Author: tuna <ng...@gmail.com>
Authored: Tue Sep 17 10:27:49 2013 +0700
Committer: Hugo Trippaers <ht...@schubergphilis.com>
Committed: Mon Oct 7 13:55:18 2013 +0200
----------------------------------------------------------------------
plugins/hypervisors/kvm/pom.xml | 5 +
.../kvm/resource/LibvirtComputingResource.java | 265 ++++++++++++++++++-
.../vm/hypervisor/kvm/cloudstack_pluginlib.py | 219 +++++++++++++++
scripts/vm/network/vnet/ovstunnel.py | 182 +++++++++++++
4 files changed, 658 insertions(+), 13 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/3056b1a9/plugins/hypervisors/kvm/pom.xml
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/kvm/pom.xml b/plugins/hypervisors/kvm/pom.xml
index 1babe7c..9d055f1 100644
--- a/plugins/hypervisors/kvm/pom.xml
+++ b/plugins/hypervisors/kvm/pom.xml
@@ -41,6 +41,11 @@
<version>${cs.libvirt-java.version}</version>
</dependency>
<dependency>
+ <groupId>org.apache.cloudstack</groupId>
+ <artifactId>cloud-plugin-network-ovs</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
<groupId>com.ceph</groupId>
<artifactId>rados</artifactId>
<version>${cs.rados-java.version}</version>
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/3056b1a9/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
index 914017c..c9e34c5 100755
--- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
@@ -63,8 +63,8 @@ import org.apache.cloudstack.utils.qemu.QemuImg;
import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat;
import org.apache.cloudstack.utils.qemu.QemuImgException;
import org.apache.cloudstack.utils.qemu.QemuImgFile;
-import org.apache.log4j.Logger;
import org.apache.commons.io.FileUtils;
+import org.apache.log4j.Logger;
import org.libvirt.Connect;
import org.libvirt.Domain;
import org.libvirt.DomainBlockStats;
@@ -121,6 +121,13 @@ import com.cloud.agent.api.NetworkRulesSystemVmCommand;
import com.cloud.agent.api.NetworkRulesVmSecondaryIpCommand;
import com.cloud.agent.api.NetworkUsageAnswer;
import com.cloud.agent.api.NetworkUsageCommand;
+import com.cloud.agent.api.OvsCreateTunnelAnswer;
+import com.cloud.agent.api.OvsCreateTunnelCommand;
+import com.cloud.agent.api.OvsDestroyBridgeCommand;
+import com.cloud.agent.api.OvsDestroyTunnelCommand;
+import com.cloud.agent.api.OvsFetchInterfaceAnswer;
+import com.cloud.agent.api.OvsFetchInterfaceCommand;
+import com.cloud.agent.api.OvsSetupBridgeCommand;
import com.cloud.agent.api.PingCommand;
import com.cloud.agent.api.PingRoutingCommand;
import com.cloud.agent.api.PingRoutingWithNwGroupsCommand;
@@ -266,7 +273,7 @@ import com.cloud.vm.VirtualMachineName;
**/
@Local(value = { ServerResource.class })
public class LibvirtComputingResource extends ServerResourceBase implements
-ServerResource {
+ ServerResource {
private static final Logger s_logger = Logger
.getLogger(LibvirtComputingResource.class);
@@ -282,6 +289,7 @@ ServerResource {
private String _ovsPvlanDhcpHostPath;
private String _ovsPvlanVmPath;
private String _routerProxyPath;
+ private String _ovsTunnelPath;
private String _host;
private String _dcId;
private String _pod;
@@ -289,6 +297,7 @@ ServerResource {
private int _migrateSpeed;
private long _hvVersion;
+ private long _kernelVersion;
private KVMHAMonitor _monitor;
private final String _SSHKEYSPATH = "/root/.ssh";
private final String _SSHPRVKEYPATH = _SSHKEYSPATH + File.separator
@@ -597,6 +606,11 @@ ServerResource {
"Unable to find the security_group.py");
}
+ _ovsTunnelPath = Script.findScript(networkScriptsDir, "ovstunnel.py");
+ if (_ovsTunnelPath == null) {
+ throw new ConfigurationException("Unable to find the ovstunnel.py");
+ }
+
_routerProxyPath = Script.findScript("scripts/network/domr/",
"router_proxy.sh");
if (_routerProxyPath == null) {
@@ -846,6 +860,11 @@ ServerResource {
storageProcessor.configure(name, params);
storageHandler = new StorageSubsystemCommandHandlerBase(storageProcessor);
+ String unameKernelVersion = Script.runSimpleBashScript("uname -r");
+ String[] kernelVersions = unameKernelVersion.split("[\\.\\-]");
+ _kernelVersion = Integer.parseInt(kernelVersions[0]) * 1000 * 1000
+ + Integer.parseInt(kernelVersions[1]) * 1000
+ + Integer.parseInt(kernelVersions[2]);
return true;
}
@@ -1069,7 +1088,7 @@ ServerResource {
return vnetId;
}
- private void passCmdLine(String vmName, String cmdLine)
+ private boolean passCmdLine(String vmName, String cmdLine)
throws InternalErrorException {
final Script command = new Script(_patchViaSocketPath, _timeout, s_logger);
String result;
@@ -1077,8 +1096,10 @@ ServerResource {
command.add("-p", cmdLine.replaceAll(" ", "%"));
result = command.execute();
if (result != null) {
- throw new InternalErrorException(result);
+ s_logger.debug("passcmd failed:" + result);
+ return false;
}
+ return true;
}
boolean isDirectAttachedNetwork(String type) {
@@ -1256,7 +1277,17 @@ ServerResource {
return this.storageHandler.handleStorageCommands((StorageSubSystemCommand)cmd);
} else if (cmd instanceof PvlanSetupCommand) {
return execute((PvlanSetupCommand) cmd);
- } else {
+ } else if (cmd instanceof OvsFetchInterfaceCommand) {
+ return execute((OvsFetchInterfaceCommand) cmd);
+ } else if (cmd instanceof OvsSetupBridgeCommand) {
+ return execute((OvsSetupBridgeCommand) cmd);
+ } else if (cmd instanceof OvsDestroyBridgeCommand) {
+ return execute((OvsDestroyBridgeCommand) cmd);
+ } else if (cmd instanceof OvsCreateTunnelCommand) {
+ return execute((OvsCreateTunnelCommand) cmd);
+ } else if (cmd instanceof OvsDestroyTunnelCommand) {
+ return execute((OvsDestroyTunnelCommand) cmd);
+ } else {
s_logger.warn("Unsupported command ");
return Answer.createUnsupportedCommandAnswer(cmd);
}
@@ -1265,6 +1296,188 @@ ServerResource {
}
}
+ // Tuna added
+ private OvsFetchInterfaceAnswer execute(OvsFetchInterfaceCommand cmd) {
+ String label = cmd.getLabel();
+ s_logger.debug("Will look for network with name-label:" + label);
+ try {
+ String ipadd = Script.runSimpleBashScript("ifconfig " + label + " | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}'");
+ String mask = Script.runSimpleBashScript("ifconfig " + label + " | grep 'inet addr:' | cut -d: -f4");
+ String mac = Script.runSimpleBashScript("ifconfig " + label + " | grep HWaddr | awk -F \" \" '{print $5}'");
+ return new OvsFetchInterfaceAnswer(cmd, true, "Interface " + label
+ + " retrieved successfully", ipadd, mask, mac);
+
+ } catch (Exception e) {
+ s_logger.warn("Caught execption when fetching interface", e);
+ return new OvsFetchInterfaceAnswer(cmd, false, "EXCEPTION:"
+ + e.getMessage());
+ }
+
+ }
+
+ private Answer execute(OvsSetupBridgeCommand cmd) {
+ findOrCreateTunnelNetwork(cmd.getKey());
+ configureTunnelNetwork(cmd.getNetworkId(), cmd.getHostId(),
+ cmd.getKey());
+ s_logger.debug("OVS Bridge configured");
+ return new Answer(cmd, true, null);
+ }
+
+ private Answer execute(OvsDestroyBridgeCommand cmd) {
+ destroyTunnelNetwork(cmd.getKey());
+ s_logger.debug("OVS Bridge destroyed");
+ return new Answer(cmd, true, null);
+ }
+
+ private synchronized void destroyTunnelNetwork(int key) {
+ try {
+ findOrCreateTunnelNetwork(key);
+ String bridge = "OVSTunnel" + key;
+ Script cmd = new Script(_ovsTunnelPath, _timeout, s_logger);
+ cmd.add("destroy_ovs_bridge");
+ cmd.add("--bridge", bridge);
+ String result = cmd.execute();
+ String[] res = result.split(":");
+ if (res.length != 2 || !res[0].equalsIgnoreCase("SUCCESS")) {
+ // TODO: Should make this error not fatal?
+ // Can Concurrent VM shutdown/migration/reboot events can cause
+ // this method
+ // to be executed on a bridge which has already been removed?
+ throw new CloudRuntimeException("Unable to remove OVS bridge "
+ + bridge + ":" + res);
+ }
+ return;
+ } catch (Exception e) {
+ s_logger.warn("destroyTunnelNetwork failed:", e);
+ return;
+ }
+ }
+
+ private boolean networkExist(String nwName) {
+ Script.runSimpleBashScript("ifconfig " + nwName);
+ String result = Script.runSimpleBashScript("echo $?");
+ return result.equals("0");
+ }
+
+ private synchronized boolean findOrCreateTunnelNetwork(long key) {
+ try {
+ String nwName = "OVSTunnel" + key;
+ if (networkExist(nwName)) {
+ return true;
+ }
+ // if not found, create a new one
+ Map<String, String> otherConfig = new HashMap<String, String>();
+ otherConfig.put("ovs-host-setup", "");
+ Script.runSimpleBashScript("ovs-vsctl -- --may-exist add-br "
+ + nwName + " -- set bridge " + nwName
+ + " other_config:ovs_host_setup=\" \"");
+ s_logger.debug("### KVM network for tunnels created:" + nwName);
+ } catch (Exception e) {
+ s_logger.warn("createTunnelNetwork failed", e);
+ }
+ return true;
+ }
+
+ private synchronized boolean configureTunnelNetwork(long networkId,
+ long hostId, int key) {
+ try {
+ findOrCreateTunnelNetwork(key);
+ String nwName = "OVSTunnel" + key;
+ String configuredHosts = Script
+ .runSimpleBashScript("ovs-vsctl get bridge " + nwName
+ + " other_config:ovs_host_setup");
+ boolean configured = false;
+ if (configuredHosts != null) {
+ String hostIdsStr[] = configuredHosts.split(",");
+ for (String hostIdStr : hostIdsStr) {
+ if (hostIdStr.equals(((Long) hostId).toString())) {
+ configured = true;
+ break;
+ }
+ }
+ }
+ if (!configured) {
+ Script cmd = new Script(_ovsTunnelPath, _timeout, s_logger);
+ cmd.add("setup_ovs_bridge");
+ cmd.add("--key", String.valueOf(key));
+ cmd.add("--cs_host_id", ((Long) hostId).toString());
+ cmd.add("--bridge", nwName);
+ String result = cmd.execute();
+ String[] res = result.split(":");
+ if (res.length != 2 || !res[0].equalsIgnoreCase("SUCCESS")) {
+ throw new CloudRuntimeException(
+ "Unable to pre-configure OVS bridge " + nwName
+ + " for network ID:" + networkId + " - "
+ + res);
+ }
+ }
+ } catch (Exception e) {
+ s_logger.warn("createandConfigureTunnelNetwork failed", e);
+ return false;
+ }
+ return true;
+ }
+
+ private OvsCreateTunnelAnswer execute(OvsCreateTunnelCommand cmd) {
+ String bridge = "OVSTunnel" + cmd.getKey();
+ try {
+ if (!findOrCreateTunnelNetwork(cmd.getKey())) {
+ s_logger.debug("Error during bridge setup");
+ return new OvsCreateTunnelAnswer(cmd, false,
+ "Cannot create network", bridge);
+ }
+
+ configureTunnelNetwork(cmd.getNetworkId(), cmd.getFrom(),
+ cmd.getKey());
+ Script command = new Script(_ovsTunnelPath, _timeout, s_logger);
+ command.add("create_tunnel");
+ command.add("--bridge", bridge);
+ command.add("--remote_ip", cmd.getRemoteIp());
+ command.add("--key", cmd.getKey().toString());
+ command.add("--src_host", cmd.getFrom().toString());
+ command.add("--dst_host", cmd.getTo().toString());
+
+ String result = command.execute();
+ String[] res = result.split(":");
+ if (res.length == 2 && res[0].equalsIgnoreCase("SUCCESS")) {
+ return new OvsCreateTunnelAnswer(cmd, true, result, res[1],
+ bridge);
+ } else {
+ return new OvsCreateTunnelAnswer(cmd, false, result, bridge);
+ }
+ } catch (Exception e) {
+ s_logger.debug("Error during tunnel setup");
+ s_logger.warn("Caught execption when creating ovs tunnel", e);
+ return new OvsCreateTunnelAnswer(cmd, false, e.getMessage(), bridge);
+ }
+ }
+
+ private Answer execute(OvsDestroyTunnelCommand cmd) {
+ try {
+ if (!findOrCreateTunnelNetwork(cmd.getKey())) {
+ s_logger.warn("Unable to find tunnel network for GRE key:"
+ + cmd.getKey());
+ return new Answer(cmd, false, "No network found");
+ }
+
+ String bridge = "OVSTunnel" + cmd.getKey();
+ Script command = new Script(_ovsTunnelPath, _timeout, s_logger);
+ command.add("destroy_tunnel");
+ command.add("--bridge", bridge);
+ command.add("--iface_name", cmd.getInPortName());
+ String result = command.execute();
+ if (result.equalsIgnoreCase("SUCCESS")) {
+ return new Answer(cmd, true, result);
+ } else {
+ return new Answer(cmd, false, result);
+ }
+ } catch (Exception e) {
+ s_logger.warn("caught execption when destroy ovs tunnel", e);
+ return new Answer(cmd, false, e.getMessage());
+ }
+ }
+ // end Tuna added
+
private CheckNetworkAnswer execute(CheckNetworkCommand cmd) {
List<PhysicalNetworkSetupInfo> phyNics = cmd
.getPhysicalNetworkInfoList();
@@ -2930,7 +3143,8 @@ ServerResource {
}
}
- private Answer execute(RebootCommand cmd) {
+
+ private Answer execute(RebootCommand cmd) {
synchronized (_vms) {
_vms.put(cmd.getVmName(), State.Starting);
@@ -3011,7 +3225,8 @@ ServerResource {
}
}
- protected Answer execute(StopCommand cmd) {
+
+ protected Answer execute(StopCommand cmd) {
final String vmName = cmd.getVmName();
State state = null;
@@ -3178,8 +3393,8 @@ ServerResource {
if (vmTO.getMinRam() != vmTO.getMaxRam()){
grd.setMemBalloning(true);
- grd.setCurrentMem((long)vmTO.getMinRam()/1024);
- grd.setMemorySize((long)vmTO.getMaxRam()/1024);
+ grd.setCurrentMem(vmTO.getMinRam()/1024);
+ grd.setMemorySize(vmTO.getMaxRam()/1024);
}
else{
grd.setMemorySize(vmTO.getMaxRam() / 1024);
@@ -3268,7 +3483,8 @@ ServerResource {
}
}
- protected synchronized StartAnswer execute(StartCommand cmd) {
+
+ protected synchronized StartAnswer execute(StartCommand cmd) {
VirtualMachineTO vmSpec = cmd.getVirtualMachine();
vmSpec.setVncAddr(cmd.getHostIp());
String vmName = vmSpec.getName();
@@ -3317,8 +3533,31 @@ ServerResource {
}
// pass cmdline info to system vms
+ // if (vmSpec.getType() != VirtualMachine.Type.User) {
+ // passCmdLine(vmName, vmSpec.getBootArgs() );
+ // }
+ // merge with master branch
+ // pass cmdline info to system vms
if (vmSpec.getType() != VirtualMachine.Type.User) {
- passCmdLine(vmName, vmSpec.getBootArgs() );
+ if ((_kernelVersion < 2006034) && (conn.getVersion() < 1001000)) {
+ // CLOUDSTACK-2823: try passCmdLine some times if kernel <
+ // 2.6.34 and qemu <1.1.0 on hypervisor
+ // (for instance, CentOS 6.4)
+ // wait for 5 minutes at most
+ for (int count = 0; count < 30; count++) {
+ boolean succeed = passCmdLine(vmName, vmSpec.getBootArgs());
+ if (succeed) {
+ break;
+ }
+ try {
+ Thread.sleep(5000);
+ } catch (InterruptedException e) {
+ s_logger.trace("Ignoring InterruptedException.", e);
+ }
+ }
+ } else {
+ passCmdLine(vmName, vmSpec.getBootArgs());
+ }
}
state = State.Running;
@@ -4589,7 +4828,7 @@ ServerResource {
bytes_rd += blockStats.rd_bytes;
bytes_wr += blockStats.wr_bytes;
}
-
+
if (oldStats != null) {
long deltaiord = io_rd - oldStats._io_rd;
if (deltaiord > 0)
@@ -4604,7 +4843,7 @@ ServerResource {
if (deltabyteswr > 0)
stats.setDiskWriteKBs(deltabyteswr / 1024);
}
-
+
/* save to Hashmap */
vmStats newStat = new vmStats();
newStat._usedTime = info.cpuTime;
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/3056b1a9/scripts/vm/hypervisor/kvm/cloudstack_pluginlib.py
----------------------------------------------------------------------
diff --git a/scripts/vm/hypervisor/kvm/cloudstack_pluginlib.py b/scripts/vm/hypervisor/kvm/cloudstack_pluginlib.py
new file mode 100644
index 0000000..f886aa3
--- /dev/null
+++ b/scripts/vm/hypervisor/kvm/cloudstack_pluginlib.py
@@ -0,0 +1,219 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+
+# cloudstack_pluginlib for openvswitch on KVM hypervisor
+
+import ConfigParser
+import logging
+import os
+import subprocess
+
+from time import localtime, asctime
+
+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 = "/usr/share/cloudstack-common/scripts/vm/hypervisor/xenserver/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"
+
+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
+ log_format = DEFAULT_LOG_FORMAT
+ log_date_format = DEFAULT_LOG_DATE_FORMAT
+ # try to read plugin configuration file
+ if os.path.exists(PLUGIN_CONFIG_PATH):
+ config = ConfigParser.ConfigParser()
+ config.read(PLUGIN_CONFIG_PATH)
+ try:
+ options = config.options('LOGGING')
+ if 'debug' in options:
+ debug = config.getboolean('LOGGING', 'debug')
+ if 'verbose' in options:
+ verbose = config.getboolean('LOGGING', 'verbose')
+ if 'format' in options:
+ log_format = config.get('LOGGING', 'format')
+ if 'date_format' in options:
+ log_date_format = config.get('LOGGING', 'date_format')
+ if 'file' in options:
+ log_file_2 = config.get('LOGGING', 'file')
+ except ValueError:
+ # configuration file contained invalid attributes
+ # ignore them
+ pass
+ except ConfigParser.NoSectionError:
+ # Missing 'Logging' section in configuration file
+ pass
+
+ root_logger = logging.root
+ if debug:
+ root_logger.setLevel(logging.DEBUG)
+ elif verbose:
+ root_logger.setLevel(logging.INFO)
+ else:
+ root_logger.setLevel(logging.WARNING)
+ 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)
+
+
+def do_cmd(cmd):
+ """Abstracts out the basics of issuing system commands. If the command
+ returns anything in stderr, a PluginError is raised with that information.
+ Otherwise, the output from stdout is returned.
+ """
+
+ pipe = subprocess.PIPE
+ logging.debug("Executing:%s", cmd)
+ proc = subprocess.Popen(cmd, shell=False, stdin=pipe, stdout=pipe,
+ stderr=pipe, close_fds=True)
+ ret_code = proc.wait()
+ err = proc.stderr.read()
+ if ret_code:
+ logging.debug("The command exited with the error code: " +
+ "%s (stderr output:%s)" % (ret_code, err))
+ raise PluginError(err)
+ output = proc.stdout.read()
+ if output.endswith('\n'):
+ output = output[:-1]
+ return output
+
+
+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 os.path.exists(name):
+ return 0
+ return -1
+
+
+def check_switch():
+ global result
+
+ 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"
+
+ 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 _is_tool_exist(VSCTL_PATH) < 0:
+ return "NO_VSCTL"
+
+ if _is_tool_exist(OFCTL_PATH) < 0:
+ return "NO_OFCTL"
+
+ return "SUCCESS"
+
+
+def _build_flow_expr(**kwargs):
+ 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'))
+ 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 ''
+ dl_dst = 'dl_dst' in kwargs and ",dl_dst=%s" % kwargs['dl_dst'] or ''
+ nw_src = 'nw_src' in kwargs and ",nw_src=%s" % kwargs['nw_src'] or ''
+ 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 +
+ (ip or proto) + nw_src + nw_dst)
+ return flow
+
+
+def add_flow(bridge, **kwargs):
+ """
+ Builds a flow expression for **kwargs and adds the flow entry
+ to an Open vSwitch instance
+ """
+ flow = _build_flow_expr(**kwargs)
+ actions = 'actions' in kwargs and ",actions=%s" % kwargs['actions'] or ''
+ flow = flow + actions
+ addflow = [OFCTL_PATH, "add-flow", bridge, flow]
+ do_cmd(addflow)
+
+
+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 '')
+ 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)
+
+ normalFlow = "priority=0 idle_timeout=0 hard_timeout=0 actions=normal"
+ add_flow(bridge, normalFlow)
+
+
+def del_port(bridge, port):
+ delPort = [VSCTL_PATH, "del-port", bridge, port]
+ do_cmd(delPort)
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/3056b1a9/scripts/vm/network/vnet/ovstunnel.py
----------------------------------------------------------------------
diff --git a/scripts/vm/network/vnet/ovstunnel.py b/scripts/vm/network/vnet/ovstunnel.py
new file mode 100644
index 0000000..67ef89b
--- /dev/null
+++ b/scripts/vm/network/vnet/ovstunnel.py
@@ -0,0 +1,182 @@
+#!/usr/bin/python
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+
+
+# Creates a tunnel mesh across xenserver hosts
+# Enforces broadcast drop rules on ingress GRE tunnels
+
+import cloudstack_pluginlib as lib
+import logging
+import commands
+import os
+import sys
+import subprocess
+import time
+
+from time import localtime as _localtime, asctime as _asctime
+
+lib.setup_logging("/var/log/ovstunnel.log")
+
+def setup_ovs_bridge(bridge, key, cs_host_id):
+
+ res = lib.check_switch()
+ if res != "SUCCESS":
+ return "FAILURE:%s" % res
+
+ logging.debug("About to manually create the bridge:%s" % bridge)
+ #set gre_key to bridge
+ res = lib.do_cmd([lib.VSCTL_PATH, "set", "bridge", bridge,
+ "other_config:gre_key=%s" % key])
+ logging.debug("Bridge has been manually created:%s" % res)
+ 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
+
+ lib.do_cmd([lib.VSCTL_PATH, "set", "bridge", bridge, "other_config:is-ovs-tun-network=True"])
+ #get list of hosts using this bridge
+ conf_hosts = lib.do_cmd([lib.VSCTL_PATH, "get","bridge", bridge,"other_config:ovs-host-setup"])
+ #add cs_host_id to list of hosts using this bridge
+ conf_hosts = cs_host_id + (conf_hosts and ',%s' % conf_hosts or '')
+ lib.do_cmd([lib.VSCTL_PATH, "set", "bridge", bridge,
+ "other_config:ovs-host-setup=%s" % conf_hosts])
+
+ logging.debug("Setup_ovs_bridge completed with result:%s" % result)
+ return result
+
+def destroy_ovs_bridge(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:
+ result = "SUCCESS:%s" % bridge
+
+ logging.debug("Destroy_ovs_bridge completed with result:%s" % result)
+ return result
+
+def create_tunnel(bridge, remote_ip, gre_key, src_host, dst_host):
+
+ 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 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
+
+def destroy_tunnel(bridge, iface_name):
+
+ 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