cloudstack-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From h...@apache.org
Subject [2/2] git commit: updated refs/heads/sdnextensions to 3056b1a
Date Mon, 07 Oct 2013 11:58:47 GMT
adding KVM support for GRE controller

Signed-off-by: Hugo Trippaers <htrippaers@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.tuna@gmail.com>
Authored: Tue Sep 17 10:27:49 2013 +0700
Committer: Hugo Trippaers <htrippaers@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


Mime
View raw message