mirror of https://github.com/apache/cloudstack.git
fix bug 7722, code complete basic architecture
This commit is contained in:
parent
d84acb204e
commit
5c01c42ba7
|
|
@ -0,0 +1,26 @@
|
|||
package com.cloud.network.ovs;
|
||||
|
||||
import com.cloud.agent.api.Command;
|
||||
|
||||
public class OvsCreateGreTunnelCommand extends Command {
|
||||
String remoteIp;
|
||||
String key;
|
||||
|
||||
@Override
|
||||
public boolean executeInSequence() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public OvsCreateGreTunnelCommand(String remoteIp, String key) {
|
||||
this.remoteIp = remoteIp;
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public String getRemoteIp() {
|
||||
return remoteIp;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package com.cloud.network.ovs;
|
||||
|
||||
import com.cloud.agent.api.Command;
|
||||
|
||||
public class OvsSetTagAndFlowCommand extends Command {
|
||||
String vlans;
|
||||
String vmName;
|
||||
|
||||
@Override
|
||||
public boolean executeInSequence() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getVlans() {
|
||||
return vlans;
|
||||
}
|
||||
|
||||
public String getVmName() {
|
||||
return vmName;
|
||||
}
|
||||
|
||||
public OvsSetTagAndFlowCommand(String vmName, String vlans) {
|
||||
this.vmName = vmName;
|
||||
this.vlans = vlans;
|
||||
}
|
||||
}
|
||||
|
|
@ -155,9 +155,12 @@ import com.cloud.host.Host.Type;
|
|||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||
import com.cloud.network.HAProxyConfigurator;
|
||||
import com.cloud.network.LoadBalancerConfigurator;
|
||||
import com.cloud.network.Networks;
|
||||
import com.cloud.network.Networks.BroadcastDomainType;
|
||||
import com.cloud.network.Networks.IsolationType;
|
||||
import com.cloud.network.Networks.TrafficType;
|
||||
import com.cloud.network.ovs.OvsCreateGreTunnelCommand;
|
||||
import com.cloud.network.ovs.OvsSetTagAndFlowCommand;
|
||||
import com.cloud.resource.ServerResource;
|
||||
import com.cloud.storage.Storage;
|
||||
import com.cloud.storage.Storage.ImageFormat;
|
||||
|
|
@ -442,6 +445,10 @@ public abstract class CitrixResourceBase implements ServerResource {
|
|||
return execute((CheckSshCommand)cmd);
|
||||
} else if (cmd instanceof SecurityIngressRulesCmd) {
|
||||
return execute((SecurityIngressRulesCmd) cmd);
|
||||
} else if (cmd instanceof OvsCreateGreTunnelCommand) {
|
||||
return execute((OvsCreateGreTunnelCommand)cmd);
|
||||
} else if (cmd instanceof OvsSetTagAndFlowCommand) {
|
||||
return execute((OvsSetTagAndFlowCommand)cmd);
|
||||
} else {
|
||||
return Answer.createUnsupportedCommandAnswer(cmd);
|
||||
}
|
||||
|
|
@ -466,6 +473,92 @@ public abstract class CitrixResourceBase implements ServerResource {
|
|||
throw new CloudRuntimeException("Unsupported network type: " + type);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a tricky to create network in xenserver.
|
||||
* if you create a network then create bridge by brctl or openvswitch yourself,
|
||||
* then you will get an expection that is "REQUIRED_NETWROK" when you start a
|
||||
* vm with this network. The soultion is, create a vif of dom0 and plug it in
|
||||
* network, xenserver will create the bridge on behalf of you
|
||||
* @throws XmlRpcException
|
||||
* @throws XenAPIException
|
||||
*/
|
||||
private void enableXenServerNetwork(Connection conn, Network nw,
|
||||
String vifNameLabel, String networkDesc) throws XenAPIException, XmlRpcException {
|
||||
/* Make sure there is a physical bridge on this network */
|
||||
VIF dom0vif = null;
|
||||
Pair<VM, VM.Record> vm = getControlDomain(conn);
|
||||
VM dom0 = vm.first();
|
||||
Set<VIF> vifs = dom0.getVIFs(conn);
|
||||
if (vifs.size() != 0) {
|
||||
for (VIF vif : vifs) {
|
||||
Map<String, String> otherConfig = vif.getOtherConfig(conn);
|
||||
if (otherConfig != null) {
|
||||
String nameLabel = otherConfig.get("nameLabel");
|
||||
if ((nameLabel != null) && nameLabel.equalsIgnoreCase(vifNameLabel)) {
|
||||
dom0vif = vif;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* create temp VIF0 */
|
||||
if (dom0vif == null) {
|
||||
s_logger.debug("Can't find a vif on dom0 for " + networkDesc + ", creating a new one");
|
||||
VIF.Record vifr = new VIF.Record();
|
||||
vifr.VM = dom0;
|
||||
vifr.device = getLowestAvailableVIFDeviceNum(conn, dom0);
|
||||
if (vifr.device == null) {
|
||||
s_logger.debug("Failed to create " + networkDesc + ", no vif available");
|
||||
return;
|
||||
}
|
||||
Map<String, String> config = new HashMap<String, String>();
|
||||
config.put("nameLabel", vifNameLabel);
|
||||
vifr.otherConfig = config;
|
||||
vifr.MAC = "FE:FF:FF:FF:FF:FF";
|
||||
vifr.network = nw;
|
||||
dom0vif = VIF.create(conn, vifr);
|
||||
dom0vif.plug(conn);
|
||||
} else {
|
||||
s_logger.debug("already have a vif on dom0 for " + networkDesc);
|
||||
if (!dom0vif.getCurrentlyAttached(conn)) {
|
||||
dom0vif.plug(conn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Network setupvSwitchNetwork(Connection conn) {
|
||||
try {
|
||||
Network vswitchNw = null;
|
||||
|
||||
if (_host.vswitchNetwork == null) {
|
||||
Network.Record rec = new Network.Record();
|
||||
String nwName = Networks.BroadcastScheme.VSwitch.toString();
|
||||
Set<Network> networks = Network.getByNameLabel(conn, nwName);
|
||||
|
||||
if (networks.size() == 0) {
|
||||
rec.nameDescription = "vswitch network for " + nwName;
|
||||
rec.nameLabel = nwName;
|
||||
vswitchNw = Network.create(conn, rec);
|
||||
} else {
|
||||
vswitchNw = networks.iterator().next();
|
||||
}
|
||||
|
||||
enableXenServerNetwork(conn, vswitchNw, "vswitch",
|
||||
"vswicth network");
|
||||
_host.vswitchNetwork = vswitchNw.getUuid(conn);
|
||||
} else {
|
||||
vswitchNw = Network.getByUuid(conn, _host.vswitchNetwork);
|
||||
enableXenServerNetwork(conn, vswitchNw, "vswitch",
|
||||
"vswicth network");
|
||||
}
|
||||
|
||||
return vswitchNw;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected Network getNetwork(Connection conn, NicTO nic) throws XenAPIException, XmlRpcException {
|
||||
Pair<Network, String> network = getNativeNetworkForTraffic(conn, nic.getType());
|
||||
if (nic.getBroadcastUri() != null && nic.getBroadcastUri().toString().contains("untagged")) {
|
||||
|
|
@ -477,7 +570,9 @@ public abstract class CitrixResourceBase implements ServerResource {
|
|||
return enableVlanNetwork(conn, vlan, network.first(), network.second());
|
||||
} else if (nic.getBroadcastType() == BroadcastDomainType.Native || nic.getBroadcastType() == BroadcastDomainType.LinkLocal) {
|
||||
return network.first();
|
||||
}
|
||||
} else if (nic.getBroadcastType() == BroadcastDomainType.Vswitch) {
|
||||
return setupvSwitchNetwork(conn);
|
||||
}
|
||||
|
||||
throw new CloudRuntimeException("Unable to support this type of network broadcast domain: " + nic.getBroadcastUri());
|
||||
}
|
||||
|
|
@ -3725,6 +3820,78 @@ public abstract class CitrixResourceBase implements ServerResource {
|
|||
return Boolean.valueOf(callHostPlugin(conn, "vmops", "can_bridge_firewall", "host_uuid", _host.uuid));
|
||||
}
|
||||
|
||||
//TODO: it's better to move more stuff at host plugin side
|
||||
private Answer execute(OvsSetTagAndFlowCommand cmd) {
|
||||
Connection conn = getConnection();
|
||||
try {
|
||||
Set<VM> vms = VM.getByNameLabel(conn, cmd.getVmName());
|
||||
VM vm = vms.iterator().next();
|
||||
Set<VIF> vifs = vm.getVIFs(conn);
|
||||
String domId = vm.getDomid(conn).toString();
|
||||
String nwName = Networks.BroadcastScheme.VSwitch.toString();
|
||||
Network nw = getNetworkByName(conn, nwName);
|
||||
assert nw!= null : "Why there is no vswith network ???";
|
||||
String bridge = nw.getBridge(conn);
|
||||
|
||||
/*If VM is domainRouter, this will try to set flow and tag on its
|
||||
* none guest network nic. don't worry, it will fail sciently at host
|
||||
* plugin side
|
||||
*/
|
||||
for (VIF vif : vifs) {
|
||||
String vifName = "vif" + domId + vif.getDevice(conn);
|
||||
String result = callHostPlugin(conn, "vmops", "vlanRemapUtils", "op", "createFlow", "bridge",
|
||||
bridge, "vifName", vifName, "mac",
|
||||
vif.getMAC(conn), "remap", cmd.getVlans(),
|
||||
"ip", "placeholder now");
|
||||
s_logger.debug("set flow for " + vifName + " on " + cmd.getVmName() + " " + result);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
if (result.equalsIgnoreCase("SUCCESS")) {
|
||||
return new Answer(cmd, true, "Set flow for " + cmd.getVmName()
|
||||
+ " success, vlans:" + cmd.getVlans());
|
||||
} else {
|
||||
return new Answer(cmd, false, "Set flow for " + cmd.getVmName()
|
||||
+ " failed, vlans:" + cmd.getVlans());
|
||||
}
|
||||
*/
|
||||
return new Answer(cmd, true, "Set flow for " + cmd.getVmName()
|
||||
+ " success, vlans:" + cmd.getVlans());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return new Answer(cmd, false, "Set flow for " + cmd.getVmName()
|
||||
+ " failed, vlans:" + cmd.getVlans());
|
||||
}
|
||||
|
||||
private Answer execute(OvsCreateGreTunnelCommand cmd) {
|
||||
Connection conn = getConnection();
|
||||
try {
|
||||
String nwName = Networks.BroadcastScheme.VSwitch.toString();
|
||||
Network nw = getNetworkByName(conn, nwName);
|
||||
if (nw == null) {
|
||||
nw = setupvSwitchNetwork(conn);
|
||||
}
|
||||
|
||||
String result = callHostPlugin(conn, "vmops", "vlanRemapUtils",
|
||||
"op", "createGRE", "bridge", nw.getBridge(conn),
|
||||
"remoteIP", cmd.getRemoteIp(), "greKey", cmd.getKey());
|
||||
if (result.equalsIgnoreCase("SUCCESS")) {
|
||||
return new Answer(cmd, true, "create gre tunnel to "
|
||||
+ cmd.getRemoteIp() + " success");
|
||||
} else {
|
||||
return new Answer(cmd, false, "create gre tunnel to "
|
||||
+ cmd.getRemoteIp() + " failed");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return new Answer(cmd, false, "create gre tunnel to " + cmd.getRemoteIp() + " failed");
|
||||
}
|
||||
|
||||
private Answer execute(SecurityIngressRulesCmd cmd) {
|
||||
Connection conn = getConnection();
|
||||
if (s_logger.isTraceEnabled()) {
|
||||
|
|
@ -5501,6 +5668,7 @@ public abstract class CitrixResourceBase implements ServerResource {
|
|||
public String publicNetwork;
|
||||
public String privateNetwork;
|
||||
public String linkLocalNetwork;
|
||||
public String vswitchNetwork;
|
||||
public String storageNetwork1;
|
||||
public String storageNetwork2;
|
||||
public String guestNetwork;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,483 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
# Create flows on Open vSwitch
|
||||
#
|
||||
# @param: bridge name, refer to a network created by xenserver
|
||||
# @param: our MAC
|
||||
# @param: vlan ID
|
||||
|
||||
import os
|
||||
import sys
|
||||
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/cloud/management/vlanRemapUtils.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", \
|
||||
|
||||
"ERR_ARGS_NUM" : "ERR_ARGS_NUM", \
|
||||
"ERROR_OP" : "ERROR_OP", \
|
||||
"SUCCESS" : "SUCCESS", \
|
||||
}
|
||||
|
||||
def openLog ():
|
||||
global fLog
|
||||
|
||||
try:
|
||||
if fLog == None:
|
||||
fLog = open (logFile, "a")
|
||||
except IOError, e:
|
||||
#print e
|
||||
pass
|
||||
|
||||
def log (str):
|
||||
global fLog
|
||||
|
||||
if fLog != None:
|
||||
str = "[%s]:" % _asctime (_localtime()) + str + "\n"
|
||||
fLog.write (str)
|
||||
|
||||
def closeLog ():
|
||||
global fLog
|
||||
|
||||
if fLog != None:
|
||||
fLog.close ()
|
||||
|
||||
def isProcessRun (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 isToolExist (name):
|
||||
if _exists (name):
|
||||
return 0
|
||||
return -1
|
||||
|
||||
|
||||
def checkvSwitch ():
|
||||
global result
|
||||
|
||||
ret = isProcessRun (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 = isProcessRun (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 isToolExist (vsctlPath) < 0:
|
||||
result = errors["NO_VSCTL"]
|
||||
return -1
|
||||
|
||||
return 0
|
||||
|
||||
def doCmd (cmds, lines=False):
|
||||
cmd = ""
|
||||
for i in cmds:
|
||||
cmd += " "
|
||||
cmd += i
|
||||
|
||||
log ("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:
|
||||
log ("command output '%s'" % res)
|
||||
return res
|
||||
|
||||
######################## GRE creation utils ##########################
|
||||
# UUID's format is 8-4-4-4-12
|
||||
def isUUID (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
|
||||
|
||||
#FIXME: better check method
|
||||
def checkGREInterface (bridge, remoteIP, greKey):
|
||||
listIfaces = [vsctlPath, "list interface"]
|
||||
res = doCmd (listIfaces, True)
|
||||
|
||||
start = False
|
||||
num = 0
|
||||
keyStr = "key=%s" % greKey
|
||||
uuid = ''
|
||||
for i in res:
|
||||
if "_uuid" in i:
|
||||
(x, uuid) = i.split(":")
|
||||
uuid = strip(uuid)
|
||||
|
||||
if "options" in i and remoteIP in i and keyStr in i:
|
||||
log("WARNING: GRE tunnel for remote_ip=%s key=%s already here" % \
|
||||
(remoteIP, greKey))
|
||||
return -1
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
def createGRE (bridge, remoteIP, greKey):
|
||||
global result
|
||||
|
||||
name = "%sgre" % bridge
|
||||
if checkGREInterface(bridge, remoteIP, greKey) < 0:
|
||||
return 0
|
||||
|
||||
createInterface = [vsctlPath, "create interface", "name=%s" % name, \
|
||||
'type=gre options:"remote_ip=%s key=%s"' % (remoteIP, greKey)]
|
||||
ifaceUUID = doCmd (createInterface)
|
||||
if isUUID (ifaceUUID) < 0:
|
||||
result = errors["COMMAND_FAILED"];
|
||||
return -1
|
||||
|
||||
createPort = [vsctlPath, "create port", "name=%s" % name, \
|
||||
"interfaces=[%s]" % ifaceUUID]
|
||||
portUUID = doCmd (createPort)
|
||||
if isUUID (portUUID) < 0:
|
||||
result = errors["COMMAND_FAILED"];
|
||||
return -1
|
||||
|
||||
addBridge = [vsctlPath, "add bridge %s" % bridge, "port %s" % portUUID]
|
||||
doCmd (addBridge)
|
||||
return 0
|
||||
######################## End GRE creation utils ##########################
|
||||
|
||||
######################## Flow creation utils ##########################
|
||||
def getPortsOnBridge(bridge):
|
||||
listBr = [vsctlPath, "list br", bridge]
|
||||
res = doCmd(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 getFieldOfPort(nameOruuid, field):
|
||||
listport = [vsctlPath, "list port", nameOruuid]
|
||||
res = doCmd(listport, True)
|
||||
|
||||
for i in res:
|
||||
if field in i:
|
||||
(x, r) = i.split(":")
|
||||
return r.lstrip().rstrip()
|
||||
return None
|
||||
|
||||
def getFieldOfInterface(nameOruuid, field):
|
||||
listIface = [vsctlPath, "list interface", nameOruuid]
|
||||
res = doCmd(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 getVifPort(bridge, vifName):
|
||||
portUuids = getPortsOnBridge(bridge)
|
||||
if portUuids == None:
|
||||
log("No ports on bridge %s" % bridge)
|
||||
return -1
|
||||
|
||||
for i in portUuids:
|
||||
name = getFieldOfPort(i, "name")
|
||||
if name == None:
|
||||
log("WARNING: no name found for %s" % name)
|
||||
continue
|
||||
|
||||
name = strip(name, "both")
|
||||
if name == vifName:
|
||||
return getFieldOfInterface(vifName, "ofport")
|
||||
return None
|
||||
|
||||
def getInterfacesOnPort(nameOruuid):
|
||||
listPort = [vsctlPath, "list port", nameOruuid]
|
||||
res = doCmd(listPort, True)
|
||||
|
||||
for i in res:
|
||||
if "interfaces" in i:
|
||||
(x, str) = i.split(":")
|
||||
str = strip(str, "both")
|
||||
return str.split(",")
|
||||
return None
|
||||
|
||||
def getOfPortsByType(bridge, askGre):
|
||||
portUuids = getPortsOnBridge(bridge)
|
||||
if portUuids == None:
|
||||
log("WARNING:No ports on bridge %s" % bridge)
|
||||
return -1
|
||||
|
||||
OfPorts = []
|
||||
for i in portUuids:
|
||||
ifaces = getInterfacesOnPort(i)
|
||||
if ifaces == None:
|
||||
log("WARNING:No interfaces on port %s" % i)
|
||||
continue
|
||||
|
||||
for j in ifaces:
|
||||
if j == '[]':
|
||||
log("WARNING:invalid interface [] on port %s" % i)
|
||||
continue
|
||||
|
||||
type = getFieldOfInterface(j, "type")
|
||||
type = strip(type)
|
||||
if askGre == True and type == "gre":
|
||||
ofport = getFieldOfInterface(j, "ofport")
|
||||
if ofport != '[]':OfPorts.append(strip(ofport))
|
||||
elif askGre == False and type != "gre":
|
||||
ofport = getFieldOfInterface(j, "ofport")
|
||||
if ofport != '[]' and ofport != "65534":OfPorts.append(strip(ofport))
|
||||
return OfPorts
|
||||
|
||||
def getNoneGreOfPort(bridge):
|
||||
return getOfPortsByType(bridge, False)
|
||||
|
||||
def getGreOfPorts(bridge):
|
||||
return getOfPortsByType(bridge, True)
|
||||
|
||||
def findInPort():
|
||||
listIface = [vsctlPath, "list interface"]
|
||||
res = doCmd (listIface, True)
|
||||
|
||||
inport = []
|
||||
port = ""
|
||||
for i in res:
|
||||
if "ofport" in i:
|
||||
(x, port) = i.split(":")
|
||||
port = port.lstrip().rstrip()
|
||||
|
||||
if "type" in i:
|
||||
(x, type) = i.split(":")
|
||||
type = type.lstrip().rstrip()
|
||||
if type == "gre":
|
||||
inport.append (port)
|
||||
return inport
|
||||
|
||||
|
||||
def formatFlow(inPort, vlan, mac, outPut):
|
||||
flow = "in_port=%s dl_vlan=%s dl_dst=%s idle_timeout=0 hard_timeout=0 \
|
||||
actions=strip_vlan,output:%s" % (inPort, vlan, mac, outPut)
|
||||
return flow
|
||||
|
||||
def delFlow(mac):
|
||||
param = "dl_dst=%s" % mac
|
||||
delFlow = ["ovs-ofctl del-flows %s" % bridge, '"%s"' % param]
|
||||
doCmd(delFlow)
|
||||
|
||||
def delARPFlow(vlan):
|
||||
param = "dl_type=0x0806 dl_vlan=%s" % vlan
|
||||
delFlow = ["ovs-ofctl del-flows %s" % bridge, '"%s"' % param]
|
||||
doCmd(delFlow)
|
||||
|
||||
def formatARPFlow(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 \
|
||||
actions=strip_vlan,%s" % (inPort, vlan, outputs)
|
||||
return flow
|
||||
|
||||
def createFlow (bridge, vifName, mac, ip, vlan, remap):
|
||||
inport = getGreOfPorts(bridge)
|
||||
if len(inport) == 0:
|
||||
log("WARNING: no inport found")
|
||||
return -1
|
||||
|
||||
output = getVifPort(bridge, vifName)
|
||||
if output == None:
|
||||
log("WARNING: cannot find ofport for %s" % vifName)
|
||||
return -1
|
||||
if output == '[]':
|
||||
log("WARNING: ofport is [] for %s" % vifName)
|
||||
return -1
|
||||
|
||||
#del old flow here, if any, but in normal there should be no old flow
|
||||
#maybe we need add check here
|
||||
delFlow(mac)
|
||||
|
||||
#set remap here, remap has format e.g. [1,22,200,13,16]
|
||||
remap = strip(remap, "both")
|
||||
log("")
|
||||
log("Create flow for remap")
|
||||
noneGreOfPorts = getNoneGreOfPort(bridge)
|
||||
isARP = True
|
||||
if len(noneGreOfPorts) == 0:
|
||||
log("WARNING: no none GRE ofports found, no ARP flow will be created")
|
||||
isARP = False
|
||||
|
||||
for j in remap.split(","):
|
||||
delARPFlow(j)
|
||||
for i in inport:
|
||||
flow = formatFlow(i, j, mac, output)
|
||||
param = bridge + ' "%s"' % flow
|
||||
addflow = ["ovs-ofctl add-flow", param]
|
||||
doCmd (addflow)
|
||||
|
||||
if isARP == True:
|
||||
flow = formatARPFlow(bridge, i, j, noneGreOfPorts)
|
||||
param = bridge + ' "%s"' % flow
|
||||
addflow = ["ovs-ofctl add-flow", param]
|
||||
doCmd (addflow)
|
||||
|
||||
return 0
|
||||
######################## End Flow creation utils ##########################
|
||||
|
||||
def setTag(vifName, vlan):
|
||||
log("")
|
||||
log("Set tag")
|
||||
setTagCmd = [vsctlPath, "set port", vifName, "tag=%s"%vlan]
|
||||
doCmd (setTagCmd)
|
||||
return 0
|
||||
|
||||
def doCreateGRE(bridge, remoteIP, key):
|
||||
if createGRE(bridge, remoteIP, key) < 0:
|
||||
log("WARNING: create GRE tunnel on %s for %s failed" % (bridge, \
|
||||
remoteIP))
|
||||
else:
|
||||
log("WARNING: create GRE tunnel on %s for %s success" % (bridge, \
|
||||
remoteIP))
|
||||
|
||||
def doCreateFlow (bridge, vifName, mac, ip, vlan, remap):
|
||||
setTag (vifName, vlan)
|
||||
if createFlow(bridge, vifName, mac, ip, vlan, remap) < 0:
|
||||
log ("Create flow failed(bridge=%s, vifName=%s, mac=%s, ip=%s, vlan=%s,\
|
||||
remap=%s" % (bridge, vifName, mac, ip, vlan, remap))
|
||||
else:
|
||||
log ("Create flow success(bridge=%s, vifName=%s, mac=%s, ip=%s, vlan=%s,\
|
||||
remap=%s" % (bridge, vifName, mac, ip, vlan, remap))
|
||||
|
||||
def doDeleteFlow(bridge, vifName, mac, remap):
|
||||
delFlow(mac)
|
||||
log("Delete flows for %s" % mac)
|
||||
|
||||
remap = strip(remap, "both")
|
||||
|
||||
# remove our port from arp flow
|
||||
inport = getGreOfPorts(bridge)
|
||||
if len(inport) == 0:
|
||||
return
|
||||
|
||||
mine = getVifPort(bridge, vifName)
|
||||
noneGreOfPorts = getNoneGreOfPort(bridge)
|
||||
noneGreOfPorts.remove(mine)
|
||||
log("Delete ARP flows for(vifname=%s, ofport=%s)" % (vifName, mine))
|
||||
|
||||
for j in remap.split(","):
|
||||
delARPFlow(j)
|
||||
for i in inport:
|
||||
flow = formatARPFlow(bridge, i, j, noneGreOfPorts)
|
||||
param = bridge + ' "%s"' % flow
|
||||
addflow = ["ovs-ofctl add-flow", param]
|
||||
doCmd (addflow)
|
||||
|
||||
def checkArgNum(num):
|
||||
if len (sys.argv) < num:
|
||||
result = errors["ERR_ARGS_NUM"]
|
||||
print result
|
||||
log ("Error number of arguments")
|
||||
sys.exit (-1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
global result
|
||||
|
||||
openLog ()
|
||||
|
||||
|
||||
if checkvSwitch () < 0:
|
||||
print result
|
||||
log ("Check switch failed, reason = '%s'" % result)
|
||||
sys.exit (-1)
|
||||
|
||||
op = sys.argv[1]
|
||||
if op == "createGRE":
|
||||
checkArgNum(5)
|
||||
bridge = sys.argv[2]
|
||||
remoteIP = sys.argv[3]
|
||||
key = sys.argv[4]
|
||||
doCreateGRE(bridge, remoteIP, key)
|
||||
elif op == "createFlow":
|
||||
checkArgNum(8)
|
||||
bridge = sys.argv[2]
|
||||
vifName = sys.argv[3]
|
||||
mac = sys.argv[4]
|
||||
vlan = sys.argv[5]
|
||||
remap = sys.argv[6]
|
||||
ip = sys.argv[7]
|
||||
doCreateFlow(bridge, vifName, mac, ip, vlan, remap)
|
||||
elif op == "deleteFlow":
|
||||
checkArgNum(6)
|
||||
bridge = sys.argv[2]
|
||||
vifName = sys.argv[3]
|
||||
mac = sys.argv[4]
|
||||
remap = sys.argv[5]
|
||||
doDeleteFlow(bridge, vifName, mac, remap)
|
||||
else:
|
||||
log("WARNING: get an unkown op %s" % op)
|
||||
result=errors["ERROR_OP"]
|
||||
print result
|
||||
sys.exit(-1)
|
||||
|
||||
result = errors["SUCCESS"]
|
||||
closeLog ()
|
||||
print result
|
||||
|
|
@ -128,6 +128,39 @@ def ipassoc(session, args):
|
|||
|
||||
return txt
|
||||
|
||||
@echo
|
||||
def vlanRemapUtils(session, args):
|
||||
cmd = []
|
||||
cmd.insert(0, "python")
|
||||
cmd.insert(1, "/opt/xensource/bin/vlanRemapUtils.py")
|
||||
|
||||
op = args.pop("op")
|
||||
cmd.insert(2, op)
|
||||
if op == "createGRE":
|
||||
cmd.insert(3, args.pop("bridge"))
|
||||
cmd.insert(4, args.pop("remoteIP"))
|
||||
cmd.insert(5, args.pop("greKey"))
|
||||
elif op == "createFlow":
|
||||
cmd.insert(3, args.pop("bridge"))
|
||||
cmd.insert(4, args.pop("vifName"))
|
||||
cmd.insert(5, args.pop("mac"))
|
||||
cmd.insert(6, args.pop("vlan"))
|
||||
cmd.insert(7, args.pop("remap"))
|
||||
cmd.insert(8, args.pop("ip"))
|
||||
elif op == "deleteFlow":
|
||||
cmd.insert(3, args.pop("bridge"))
|
||||
cmd.insert(4, args.pop("vifName"))
|
||||
cmd.insert(5, args.pop("mac"))
|
||||
cmd.insert(6, args.pop("remap"))
|
||||
|
||||
try:
|
||||
txt = util.pread2(cmd)
|
||||
except:
|
||||
util.SMlog("vlanRemapUtils failed")
|
||||
txt = 'failed'
|
||||
|
||||
return txt
|
||||
|
||||
@echo
|
||||
def vm_data(session, args):
|
||||
router_ip = args.pop('routerIP')
|
||||
|
|
@ -519,7 +552,6 @@ def default_ebtables_rules(vm_name, vif, vm_ip, vm_mac):
|
|||
util.SMlog("Failed to program default ebtables OUT rules")
|
||||
return 'false'
|
||||
|
||||
|
||||
@echo
|
||||
def default_network_rules_systemvm(session, args):
|
||||
vm_name = args.pop('vmName')
|
||||
|
|
@ -1032,5 +1064,5 @@ def network_rules(session, args):
|
|||
|
||||
|
||||
if __name__ == "__main__":
|
||||
XenAPIPlugin.dispatch({"pingtest": pingtest, "setup_iscsi":setup_iscsi, "gethostvmstats": gethostvmstats, "getvncport": getvncport, "getgateway": getgateway, "preparemigration": preparemigration, "setIptables": setIptables, "pingdomr": pingdomr, "pingxenserver": pingxenserver, "ipassoc": ipassoc, "vm_data": vm_data, "savePassword": savePassword, "saveDhcpEntry": saveDhcpEntry, "setFirewallRule": setFirewallRule, "setLoadBalancerRule": setLoadBalancerRule, "createFile": createFile, "deleteFile": deleteFile, "networkUsage": networkUsage, "network_rules":network_rules, "can_bridge_firewall":can_bridge_firewall, "default_network_rules":default_network_rules, "destroy_network_rules_for_vm":destroy_network_rules_for_vm, "default_network_rules_systemvm":default_network_rules_systemvm, "get_rule_logs_for_vms":get_rule_logs_for_vms, "setLinkLocalIP":setLinkLocalIP, "lt2p_vpn":lt2p_vpn, "cleanup_rules":cleanup_rules})
|
||||
XenAPIPlugin.dispatch({"pingtest": pingtest, "setup_iscsi":setup_iscsi, "gethostvmstats": gethostvmstats, "getvncport": getvncport, "getgateway": getgateway, "preparemigration": preparemigration, "setIptables": setIptables, "pingdomr": pingdomr, "pingxenserver": pingxenserver, "ipassoc": ipassoc, "vm_data": vm_data, "savePassword": savePassword, "saveDhcpEntry": saveDhcpEntry, "setFirewallRule": setFirewallRule, "setLoadBalancerRule": setLoadBalancerRule, "createFile": createFile, "deleteFile": deleteFile, "networkUsage": networkUsage, "network_rules":network_rules, "can_bridge_firewall":can_bridge_firewall, "default_network_rules":default_network_rules, "destroy_network_rules_for_vm":destroy_network_rules_for_vm, "default_network_rules_systemvm":default_network_rules_systemvm, "get_rule_logs_for_vms":get_rule_logs_for_vms, "setLinkLocalIP":setLinkLocalIP, "lt2p_vpn":lt2p_vpn, "vlanRemapUtils":vlanRemapUtils,"cleanup_rules":cleanup_rules})
|
||||
|
||||
|
|
|
|||
|
|
@ -60,6 +60,10 @@ public class Commands {
|
|||
addCommand(null, cmd);
|
||||
}
|
||||
|
||||
public void addCommand(int index, Command cmd) {
|
||||
_cmds.add(index, cmd);
|
||||
}
|
||||
|
||||
public Answer getAnswer(String id) {
|
||||
int i = _ids.indexOf(id);
|
||||
return i == -1 ? null : _answers[i];
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ public enum Config {
|
|||
NetworkThrottlingRate("Network", ManagementServer.class, Integer.class, "network.throttling.rate", "200", "Default data transfer rate in megabits per second allowed.", null),
|
||||
GuestDomainSuffix("Network", AgentManager.class, String.class, "guest.domain.suffix", "cloud-test.cloud.internal", "Default domain name for vms inside virtualized networks fronted by router", null),
|
||||
DirectNetworkNoDefaultRoute("Network", ManagementServer.class, Boolean.class, "direct.network.no.default.route", "false", "Direct Network Dhcp Server should not send a default route", "true/false"),
|
||||
OvsNetwork("Network", ManagementServer.class, Boolean.class, "open.vswitch.network", "true", "enable/disable open vswitch network", null),
|
||||
|
||||
//VPN
|
||||
RemoteAccessVpnPskLength("Network", AgentManager.class, Integer.class, "remote.access.vpn.psk.length", "24", "The length of the ipsec preshared key (minimum 8, maximum 256)", null),
|
||||
|
|
|
|||
|
|
@ -72,6 +72,9 @@ import com.cloud.network.dao.NetworkRuleConfigDaoImpl;
|
|||
import com.cloud.network.dao.RemoteAccessVpnDaoImpl;
|
||||
import com.cloud.network.dao.VpnUserDaoImpl;
|
||||
import com.cloud.network.lb.LoadBalancingRulesManagerImpl;
|
||||
import com.cloud.network.ovs.OvsNetworkManagerImpl;
|
||||
import com.cloud.network.ovs.dao.VlanMappingDaoImpl;
|
||||
import com.cloud.network.ovs.dao.VlanMappingDirtyDaoImpl;
|
||||
import com.cloud.network.router.VirtualNetworkApplianceManagerImpl;
|
||||
import com.cloud.network.rules.RulesManagerImpl;
|
||||
import com.cloud.network.rules.dao.PortForwardingRulesDaoImpl;
|
||||
|
|
@ -236,6 +239,8 @@ public class DefaultComponentLibrary implements ComponentLibrary {
|
|||
addDao("PortForwardingRulesDao", PortForwardingRulesDaoImpl.class);
|
||||
addDao("UsageEventDao", UsageEventDaoImpl.class);
|
||||
addDao("ClusterDetailsDao", ClusterDetailsDaoImpl.class);
|
||||
addDao("VlanMappingDao", VlanMappingDaoImpl.class);
|
||||
addDao("VlanMappingDirtyDao", VlanMappingDirtyDaoImpl.class);
|
||||
}
|
||||
|
||||
Map<String, ComponentInfo<Manager>> _managers = new HashMap<String, ComponentInfo<Manager>>();
|
||||
|
|
@ -290,6 +295,7 @@ public class DefaultComponentLibrary implements ComponentLibrary {
|
|||
addManager("LoadBalancingRulesManager", LoadBalancingRulesManagerImpl.class);
|
||||
addManager("RulesManager", RulesManagerImpl.class);
|
||||
addManager("RemoteAccessVpnManager", RemoteAccessVpnManagerImpl.class);
|
||||
addManager("OvsNetworkManager", OvsNetworkManagerImpl.class);
|
||||
}
|
||||
|
||||
protected <T> List<ComponentInfo<Adapter>> addAdapterChain(Class<T> interphace, List<Pair<String, Class<? extends T>>> adapters) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,94 @@
|
|||
package com.cloud.network.element;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.ejb.Local;
|
||||
|
||||
import com.cloud.deploy.DeployDestination;
|
||||
import com.cloud.exception.ConcurrentOperationException;
|
||||
import com.cloud.exception.InsufficientCapacityException;
|
||||
import com.cloud.exception.ResourceUnavailableException;
|
||||
import com.cloud.network.Network;
|
||||
import com.cloud.network.PublicIpAddress;
|
||||
import com.cloud.network.Network.Capability;
|
||||
import com.cloud.network.Network.Provider;
|
||||
import com.cloud.network.Network.Service;
|
||||
import com.cloud.network.ovs.OvsNetworkManager;
|
||||
import com.cloud.network.rules.FirewallRule;
|
||||
import com.cloud.offering.NetworkOffering;
|
||||
import com.cloud.utils.component.AdapterBase;
|
||||
import com.cloud.utils.component.Inject;
|
||||
import com.cloud.vm.NicProfile;
|
||||
import com.cloud.vm.ReservationContext;
|
||||
import com.cloud.vm.VirtualMachine;
|
||||
import com.cloud.vm.VirtualMachineProfile;
|
||||
|
||||
@Local(value=NetworkElement.class)
|
||||
public class OvsElement extends AdapterBase implements NetworkElement {
|
||||
@Inject OvsNetworkManager _ovsNetworkMgr;
|
||||
|
||||
@Override
|
||||
public Map<Service, Map<Capability, String>> getCapabilities() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Provider getProvider() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean implement(Network network, NetworkOffering offering,
|
||||
DeployDestination dest, ReservationContext context)
|
||||
throws ConcurrentOperationException, ResourceUnavailableException,
|
||||
InsufficientCapacityException {
|
||||
// TODO Auto-generated method stub
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean prepare(Network network, NicProfile nic,
|
||||
VirtualMachineProfile<? extends VirtualMachine> vm,
|
||||
DeployDestination dest, ReservationContext context)
|
||||
throws ConcurrentOperationException, ResourceUnavailableException,
|
||||
InsufficientCapacityException {
|
||||
_ovsNetworkMgr.CheckAndUpdateDhcpFlow(network);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean release(Network network, NicProfile nic,
|
||||
VirtualMachineProfile<? extends VirtualMachine> vm,
|
||||
ReservationContext context) throws ConcurrentOperationException,
|
||||
ResourceUnavailableException {
|
||||
// TODO Auto-generated method stub
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shutdown(Network network, ReservationContext context)
|
||||
throws ConcurrentOperationException, ResourceUnavailableException {
|
||||
// TODO Auto-generated method stub
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applyIps(Network network,
|
||||
List<? extends PublicIpAddress> ipAddress)
|
||||
throws ResourceUnavailableException {
|
||||
// TODO Auto-generated method stub
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applyRules(Network network,
|
||||
List<? extends FirewallRule> rules)
|
||||
throws ResourceUnavailableException {
|
||||
// TODO Auto-generated method stub
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package com.cloud.network.ovs;
|
||||
|
||||
import com.cloud.agent.manager.Commands;
|
||||
import com.cloud.deploy.DeployDestination;
|
||||
import com.cloud.network.Network;
|
||||
import com.cloud.uservm.UserVm;
|
||||
import com.cloud.utils.component.Manager;
|
||||
import com.cloud.vm.State;
|
||||
import com.cloud.vm.UserVmVO;
|
||||
import com.cloud.vm.VirtualMachineProfile;
|
||||
|
||||
public interface OvsNetworkManager extends Manager {
|
||||
public boolean isOvsNetworkEnabled();
|
||||
|
||||
public long askVlanId(long accountId, long hostId);
|
||||
|
||||
public String getVlanMapping(long accountId);
|
||||
|
||||
public void CheckAndCreateTunnel(Commands cmds,
|
||||
VirtualMachineProfile<UserVmVO> profile, DeployDestination dest);
|
||||
|
||||
public void applyDefaultFlow(Commands cmds,
|
||||
VirtualMachineProfile<UserVmVO> profile, DeployDestination dest);
|
||||
|
||||
public void CheckAndUpdateDhcpFlow(Network nw);
|
||||
public void handleVmStateTransition(UserVm userVm, State vmState);
|
||||
}
|
||||
|
|
@ -0,0 +1,304 @@
|
|||
package com.cloud.network.ovs;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.ejb.Local;
|
||||
import javax.naming.ConfigurationException;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.cloud.agent.AgentManager;
|
||||
import com.cloud.agent.manager.Commands;
|
||||
import com.cloud.configuration.Config;
|
||||
import com.cloud.configuration.dao.ConfigurationDao;
|
||||
import com.cloud.deploy.DeployDestination;
|
||||
import com.cloud.host.HostVO;
|
||||
import com.cloud.host.dao.HostDao;
|
||||
import com.cloud.network.Network;
|
||||
import com.cloud.network.NetworkVO;
|
||||
import com.cloud.network.Networks.BroadcastDomainType;
|
||||
import com.cloud.network.Networks.TrafficType;
|
||||
import com.cloud.network.dao.NetworkDao;
|
||||
import com.cloud.network.ovs.dao.VlanMappingDao;
|
||||
import com.cloud.network.ovs.dao.VlanMappingDirtyDao;
|
||||
import com.cloud.network.ovs.dao.VlanMappingVO;
|
||||
import com.cloud.uservm.UserVm;
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.utils.component.Inject;
|
||||
import com.cloud.utils.db.Transaction;
|
||||
import com.cloud.vm.DomainRouterVO;
|
||||
import com.cloud.vm.NicVO;
|
||||
import com.cloud.vm.State;
|
||||
import com.cloud.vm.UserVmVO;
|
||||
import com.cloud.vm.VirtualMachine;
|
||||
import com.cloud.vm.VirtualMachineProfile;
|
||||
import com.cloud.vm.dao.DomainRouterDao;
|
||||
import com.cloud.vm.dao.NicDao;
|
||||
import com.cloud.vm.dao.UserVmDao;
|
||||
|
||||
@Local(value={OvsNetworkManager.class})
|
||||
public class OvsNetworkManagerImpl implements OvsNetworkManager {
|
||||
private static final Logger s_logger = Logger.getLogger(OvsNetworkManagerImpl.class);
|
||||
@Inject ConfigurationDao _configDao;
|
||||
@Inject VlanMappingDao _vlanMappingDao;
|
||||
@Inject UserVmDao _userVmDao;
|
||||
@Inject HostDao _hostDao;
|
||||
@Inject AgentManager _agentMgr;
|
||||
@Inject NicDao _nicDao;
|
||||
@Inject NetworkDao _networkDao;
|
||||
@Inject VlanMappingDirtyDao _vlanMappingDirtyDao;
|
||||
@Inject DomainRouterDao _routerDao;
|
||||
String _name;
|
||||
boolean _isEnabled;
|
||||
|
||||
@Override
|
||||
public boolean configure(String name, Map<String, Object> params)
|
||||
throws ConfigurationException {
|
||||
_name = name;
|
||||
_isEnabled = _configDao.getValue(Config.OvsNetwork.key()).equalsIgnoreCase("true") ? true : false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean start() {
|
||||
// TODO Auto-generated method stub
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean stop() {
|
||||
// TODO Auto-generated method stub
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
// TODO Auto-generated method stub
|
||||
return _name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOvsNetworkEnabled() {
|
||||
// TODO Auto-generated method stub
|
||||
return _isEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long askVlanId(long accountId, long hostId) {
|
||||
assert _isEnabled : "Who call me ??? while OvsNetwokr is not enabled!!!";
|
||||
final Transaction txn = Transaction.currentTxn();
|
||||
txn.start();
|
||||
|
||||
List<VlanMappingVO> mappings = _vlanMappingDao.listByAccountIdAndHostId(accountId, hostId);
|
||||
long vlan = 0;
|
||||
|
||||
if (mappings.size() !=0) {
|
||||
assert mappings.size() == 1 : "We should only have one vlan for an account on a host";
|
||||
txn.commit();
|
||||
vlan = mappings.get(0).getVlan();
|
||||
s_logger.debug("Already has an Vlan " + vlan + " on host " + hostId
|
||||
+ " for account " + accountId + ", use it!");
|
||||
return vlan;
|
||||
}
|
||||
|
||||
mappings = _vlanMappingDao.listByHostId(hostId);
|
||||
if (mappings.size() > 0) {
|
||||
ArrayList<Long> vlans = new ArrayList<Long>();
|
||||
for (VlanMappingVO vo : mappings) {
|
||||
vlans.add(new Long(vo.getVlan()));
|
||||
}
|
||||
|
||||
// Find first available vlan
|
||||
int i;
|
||||
for (i=0; i<4096; i++) {
|
||||
if (!vlans.contains(new Long(i))) {
|
||||
vlan = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert i!=4096 : "Terrible, vlan exhausted on this server!!!";
|
||||
}
|
||||
|
||||
VlanMappingVO newVlan = new VlanMappingVO(accountId, hostId, vlan);
|
||||
_vlanMappingDao.persist(newVlan);
|
||||
_vlanMappingDirtyDao.markDirty(accountId);
|
||||
txn.commit();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVlanMapping(long accountId) {
|
||||
assert _isEnabled : "Who call me ??? while OvsNetwokr is not enabled!!!";
|
||||
final Transaction txn = Transaction.currentTxn();
|
||||
txn.start();
|
||||
|
||||
List<VlanMappingVO> ours = _vlanMappingDao.listByAccountId(accountId);
|
||||
txn.commit();
|
||||
|
||||
ArrayList<Long>vlans = new ArrayList<Long>();
|
||||
for (VlanMappingVO vo : ours) {
|
||||
vlans.add(new Long(vo.getVlan()));
|
||||
}
|
||||
|
||||
StringBuffer buf = new StringBuffer();
|
||||
for (Long i : vlans) {
|
||||
buf.append("/");
|
||||
buf.append(i.toString());
|
||||
buf.append("/");
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void CheckAndCreateTunnel(Commands cmds, VirtualMachineProfile<UserVmVO> profile,
|
||||
DeployDestination dest) {
|
||||
if (!_isEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
UserVmVO userVm = profile.getVirtualMachine();
|
||||
if (userVm.getType() != VirtualMachine.Type.User) {
|
||||
return;
|
||||
}
|
||||
|
||||
long hostId = dest.getHost().getId();
|
||||
long accountId = userVm.getAccountId();
|
||||
List<UserVmVO> vms = _userVmDao.listByAccountIdAndHostId(accountId, hostId);
|
||||
if (vms.size() != 0) {
|
||||
s_logger.debug("Already has GRE tunnel for account " + accountId
|
||||
+ " for host " + hostId);
|
||||
return;
|
||||
}
|
||||
|
||||
vms = _userVmDao.listByAccountId(accountId);
|
||||
List<Long>remoteHostIds = new ArrayList<Long>();
|
||||
for (UserVmVO v : vms) {
|
||||
Long rh = v.getHostId();
|
||||
if (rh == null || rh.longValue() == hostId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!remoteHostIds.contains(rh)) {
|
||||
remoteHostIds.add(rh);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
String myIp = dest.getHost().getPrivateIpAddress();
|
||||
for (Long i : remoteHostIds) {
|
||||
HostVO rHost = _hostDao.findById(i.longValue());
|
||||
cmds.addCommand(
|
||||
0, new OvsCreateGreTunnelCommand(rHost.getPrivateIpAddress(), "1"));
|
||||
_agentMgr.send(i.longValue(), new OvsCreateGreTunnelCommand(myIp, "1"));
|
||||
s_logger.debug("Ask host " + i.longValue() + " to create gre tunnel to " + hostId);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private String parseVlanAndMapping(String uri) {
|
||||
String sub = uri.substring(BroadcastDomainType.Vswitch.scheme().length() + "://".length() - 1);
|
||||
return sub;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyDefaultFlow(Commands cmds,
|
||||
VirtualMachineProfile<UserVmVO> profile, DeployDestination dest) {
|
||||
if (!_isEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
UserVmVO userVm = profile.getVirtualMachine();
|
||||
VirtualMachine.Type vmType = userVm.getType();
|
||||
if (vmType != VirtualMachine.Type.User
|
||||
&& vmType != VirtualMachine.Type.DomainRouter) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<NicVO> nics = _nicDao.listBy(userVm.getId());
|
||||
if (nics.size() == 0)
|
||||
return;
|
||||
|
||||
NicVO nic = null;
|
||||
if (vmType == VirtualMachine.Type.DomainRouter) {
|
||||
for (NicVO n : nics) {
|
||||
NetworkVO network = _networkDao.findById(n.getNetworkId());
|
||||
if (network.getTrafficType() == TrafficType.Guest) {
|
||||
nic = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
nic = nics.get(0);
|
||||
}
|
||||
|
||||
assert nic!=null : "Why there is no guest network nic???";
|
||||
String vlans = parseVlanAndMapping(nic.getBroadcastUri().toASCIIString());
|
||||
cmds.addCommand(new OvsSetTagAndFlowCommand(userVm.getName(), vlans));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void CheckAndUpdateDhcpFlow(Network nw) {
|
||||
if (!_isEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
DomainRouterVO router = _routerDao.findByNetworkConfiguration(nw.getId());
|
||||
if (router == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
long accountId = nw.getAccountId();
|
||||
if (!_vlanMappingDirtyDao.isDirty(accountId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
String vlans = getVlanMapping(accountId);
|
||||
_agentMgr.send(router.getHostId(), new OvsSetTagAndFlowCommand(
|
||||
router.getName(), vlans));
|
||||
s_logger.debug("ask router " + router.getName() + " on host "
|
||||
+ router.getHostId() + " update vlan map to " + vlans);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
protected void handleVmStarted(UserVm userVm) {
|
||||
scheduleFlowUpdateToHosts(affectedVms, true, null);
|
||||
}
|
||||
|
||||
protected void handleVmStopped(UserVm userVm) {
|
||||
scheduleFlowUpdateToHosts(affectedVms, true, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleVmStateTransition(UserVm userVm, State vmState) {
|
||||
if (!_isEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (vmState) {
|
||||
case Creating:
|
||||
case Destroyed:
|
||||
case Error:
|
||||
case Migrating:
|
||||
case Expunging:
|
||||
case Starting:
|
||||
case Unknown:
|
||||
return;
|
||||
case Running:
|
||||
handleVmStarted(userVm);
|
||||
break;
|
||||
case Stopping:
|
||||
case Stopped:
|
||||
handleVmStopped(userVm);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.cloud.network.ovs.dao;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.cloud.utils.db.GenericDao;
|
||||
|
||||
public interface VlanMappingDao extends GenericDao<VlanMappingVO, Long> {
|
||||
List<VlanMappingVO> listByAccountIdAndHostId(long accountId, long hostId);
|
||||
List<VlanMappingVO> listByHostId(long hostId);
|
||||
List<VlanMappingVO> listByAccountId(long accountId);
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
package com.cloud.network.ovs.dao;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.cloud.utils.db.GenericDaoBase;
|
||||
import com.cloud.utils.db.SearchBuilder;
|
||||
import com.cloud.utils.db.SearchCriteria;
|
||||
import com.cloud.utils.db.SearchCriteria.Op;
|
||||
|
||||
import javax.ejb.Local;
|
||||
|
||||
@Local(value = { VlanMappingDao.class })
|
||||
public class VlanMappingDaoImpl extends GenericDaoBase<VlanMappingVO, Long>
|
||||
implements VlanMappingDao {
|
||||
protected final SearchBuilder<VlanMappingVO> AllFieldsSearch;
|
||||
|
||||
public VlanMappingDaoImpl() {
|
||||
super();
|
||||
AllFieldsSearch = createSearchBuilder();
|
||||
AllFieldsSearch.and("host_id", AllFieldsSearch.entity().getHostId(), Op.EQ);
|
||||
AllFieldsSearch.and("account_id", AllFieldsSearch.entity().getAccountId(), Op.EQ);
|
||||
AllFieldsSearch.and("vlan", AllFieldsSearch.entity().getAccountId(), Op.EQ);
|
||||
AllFieldsSearch.done();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<VlanMappingVO> listByAccountIdAndHostId(long accountId,
|
||||
long hostId) {
|
||||
SearchCriteria<VlanMappingVO> sc = AllFieldsSearch.create();
|
||||
sc.setParameters("account_id", accountId);
|
||||
sc.setParameters("host_id", hostId);
|
||||
return listBy(sc, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<VlanMappingVO> listByHostId(long hostId) {
|
||||
SearchCriteria<VlanMappingVO> sc = AllFieldsSearch.create();
|
||||
sc.setParameters("host_id", hostId);
|
||||
|
||||
return listBy(sc, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<VlanMappingVO> listByAccountId(long accountId) {
|
||||
SearchCriteria<VlanMappingVO> sc = AllFieldsSearch.create();
|
||||
sc.setParameters("account_id", accountId);
|
||||
|
||||
return listBy(sc, null);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.cloud.network.ovs.dao;
|
||||
|
||||
import com.cloud.utils.db.GenericDao;
|
||||
|
||||
public interface VlanMappingDirtyDao extends GenericDao<VlanMappingDirtyVO, Long> {
|
||||
public boolean isDirty(long accountId);
|
||||
public void markDirty(long accountId);
|
||||
public void clean(long accountId);
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
package com.cloud.network.ovs.dao;
|
||||
|
||||
import javax.ejb.Local;
|
||||
|
||||
import com.cloud.utils.db.GenericDaoBase;
|
||||
import com.cloud.utils.db.SearchBuilder;
|
||||
import com.cloud.utils.db.SearchCriteria;
|
||||
import com.cloud.utils.db.SearchCriteria.Op;
|
||||
|
||||
@Local(value = { VlanMappingDirtyDao.class })
|
||||
public class VlanMappingDirtyDaoImpl extends
|
||||
GenericDaoBase<VlanMappingDirtyVO, Long> implements VlanMappingDirtyDao {
|
||||
protected final SearchBuilder<VlanMappingDirtyVO> AllFieldsSearch;
|
||||
|
||||
public VlanMappingDirtyDaoImpl() {
|
||||
super();
|
||||
AllFieldsSearch = createSearchBuilder();
|
||||
AllFieldsSearch.and("account_id", AllFieldsSearch.entity().getAccountId(), Op.EQ);
|
||||
AllFieldsSearch.and("dirty", AllFieldsSearch.entity().isDirty(), Op.EQ);
|
||||
AllFieldsSearch.done();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirty(long accountId) {
|
||||
SearchCriteria<VlanMappingDirtyVO> sc = AllFieldsSearch.create();
|
||||
sc.setParameters("account_id", accountId);
|
||||
VlanMappingDirtyVO vo = findOneBy(sc);
|
||||
if (vo == null) {
|
||||
return false;
|
||||
}
|
||||
return vo.isDirty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markDirty(long accountId) {
|
||||
SearchCriteria<VlanMappingDirtyVO> sc = AllFieldsSearch.create();
|
||||
sc.setParameters("account_id", accountId);
|
||||
VlanMappingDirtyVO vo = findOneBy(sc);
|
||||
if (vo == null) {
|
||||
vo = new VlanMappingDirtyVO(accountId, true);
|
||||
persist(vo);
|
||||
} else {
|
||||
vo.markDirty();
|
||||
update(vo, sc);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clean(long accountId) {
|
||||
SearchCriteria<VlanMappingDirtyVO> sc = AllFieldsSearch.create();
|
||||
sc.setParameters("account_id", accountId);
|
||||
VlanMappingDirtyVO vo = findOneBy(sc);
|
||||
if (vo == null) {
|
||||
vo = new VlanMappingDirtyVO(accountId, false);
|
||||
persist(vo);
|
||||
} else {
|
||||
vo.clean();
|
||||
update(vo, sc);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
package com.cloud.network.ovs.dao;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name=("ovs_vlan_mapping_dirty"))
|
||||
public class VlanMappingDirtyVO {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "id")
|
||||
private long id;
|
||||
|
||||
@Column(name = "dirty")
|
||||
private boolean dirty;
|
||||
|
||||
@Column(name = "account_id")
|
||||
private long accountId;
|
||||
|
||||
public VlanMappingDirtyVO() {
|
||||
|
||||
}
|
||||
|
||||
public VlanMappingDirtyVO(long accountId, boolean dirty) {
|
||||
this.accountId = accountId;
|
||||
this.dirty = dirty;
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public long getAccountId() {
|
||||
return accountId;
|
||||
}
|
||||
|
||||
public boolean isDirty() {
|
||||
return dirty;
|
||||
}
|
||||
|
||||
public void markDirty() {
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
public void clean() {
|
||||
dirty = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
package com.cloud.network.ovs.dao;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Column;
|
||||
|
||||
@Entity
|
||||
@Table(name=("ovs_host_vlan_alloc"))
|
||||
public class VlanMappingVO {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "id")
|
||||
private long id;
|
||||
|
||||
@Column(name = "host_id")
|
||||
private long hostId;
|
||||
|
||||
@Column(name = "account_id")
|
||||
private long accountId;
|
||||
|
||||
@Column(name = "vlan")
|
||||
private long vlan;
|
||||
|
||||
public VlanMappingVO(long accountId, long hostId, long vlan) {
|
||||
this.hostId = hostId;
|
||||
this.accountId = accountId;
|
||||
this.vlan = vlan;
|
||||
}
|
||||
|
||||
public VlanMappingVO() {
|
||||
|
||||
}
|
||||
|
||||
public long getHostId() {
|
||||
return hostId;
|
||||
}
|
||||
|
||||
public long getAccountId() {
|
||||
return accountId;
|
||||
}
|
||||
|
||||
public long getVlan() {
|
||||
return vlan;
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
|
@ -129,6 +129,7 @@ import com.cloud.network.dao.LoadBalancerDao;
|
|||
import com.cloud.network.dao.LoadBalancerVMMapDao;
|
||||
import com.cloud.network.dao.NetworkDao;
|
||||
import com.cloud.network.lb.LoadBalancingRulesManager;
|
||||
import com.cloud.network.ovs.OvsNetworkManager;
|
||||
import com.cloud.network.router.VirtualNetworkApplianceManager;
|
||||
import com.cloud.network.rules.RulesManager;
|
||||
import com.cloud.network.security.SecurityGroupManager;
|
||||
|
|
@ -258,6 +259,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
|
|||
@Inject RulesManager _rulesMgr;
|
||||
@Inject LoadBalancingRulesManager _lbMgr;
|
||||
@Inject UsageEventDao _usageEventDao;
|
||||
@Inject OvsNetworkManager _ovsNetworkMgr;
|
||||
|
||||
private IpAddrAllocator _IpAllocator;
|
||||
ScheduledExecutorService _executor = null;
|
||||
|
|
@ -2395,6 +2397,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
|
|||
}
|
||||
_vmDao.update(userVm.getId(), userVm);
|
||||
|
||||
_ovsNetworkMgr.CheckAndCreateTunnel(cmds, profile, dest);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -100,4 +100,5 @@ public interface UserVmDao extends GenericDao<UserVmVO, Long>, StateDao<State, V
|
|||
UserVm findByZoneAndAcctAndGuestIpAddress(long zoneId, long accountId, String ipAddress);
|
||||
|
||||
UserVm findVmByZoneIdAndName(long zoneId, String name);
|
||||
List<UserVmVO> listByAccountIdAndHostId(long accountId, long hostId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ public class UserVmDaoImpl extends GenericDaoBase<UserVmVO, Long> implements Use
|
|||
protected final SearchBuilder<UserVmVO> GuestIpSearch;
|
||||
protected final SearchBuilder<UserVmVO> ZoneAccountGuestIpSearch;
|
||||
protected final SearchBuilder<UserVmVO> ZoneNameSearch;
|
||||
protected final SearchBuilder<UserVmVO> AccountHostSearch;
|
||||
|
||||
protected final SearchBuilder<UserVmVO> DestroySearch;
|
||||
protected SearchBuilder<UserVmVO> AccountDataCenterVirtualSearch;
|
||||
|
|
@ -136,6 +137,11 @@ public class UserVmDaoImpl extends GenericDaoBase<UserVmVO, Long> implements Use
|
|||
ZoneNameSearch.and("dataCenterId", ZoneNameSearch.entity().getDataCenterId(), SearchCriteria.Op.EQ);
|
||||
ZoneNameSearch.and("name", ZoneNameSearch.entity().getName(), SearchCriteria.Op.EQ);
|
||||
ZoneNameSearch.done();
|
||||
|
||||
AccountHostSearch = createSearchBuilder();
|
||||
AccountHostSearch.and("accountId", AccountHostSearch.entity().getAccountId(), SearchCriteria.Op.EQ);
|
||||
AccountHostSearch.and("hostId", AccountHostSearch.entity().getHostId(), SearchCriteria.Op.EQ);
|
||||
AccountHostSearch.done();
|
||||
|
||||
_updateTimeAttr = _allAttributes.get("updateTime");
|
||||
assert _updateTimeAttr != null : "Couldn't get this updateTime attribute";
|
||||
|
|
@ -401,4 +407,12 @@ public class UserVmDaoImpl extends GenericDaoBase<UserVmVO, Long> implements Use
|
|||
sc.setParameters("name", name);
|
||||
return findOneBy(sc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserVmVO> listByAccountIdAndHostId(long accountId, long hostId) {
|
||||
SearchCriteria<UserVmVO> sc = AccountHostSearch.create();
|
||||
sc.setParameters("hostId", hostId);
|
||||
sc.setParameters("accountId", accountId);
|
||||
return listBy(sc);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1323,4 +1323,19 @@ CREATE TABLE `cloud`.`usage_event` (
|
|||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
CREATE TABLE `cloud`.`ovs_host_vlan_alloc`(
|
||||
`id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT,
|
||||
`host_id` bigint unsigned COMMENT 'host id',
|
||||
`account_id` bigint unsigned COMMENT 'account id',
|
||||
`vlan` bigint unsigned COMMENT 'vlan id under account #account_id on host #host_id',
|
||||
PRIMARY KEY(`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
CREATE TABLE `cloud`.`ovs_vlan_mapping_dirty`(
|
||||
`id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT,
|
||||
`account_id` bigint unsigned COMMENT 'account id',
|
||||
`dirty` int(1) unsigned NOT NULL DEFAULT 0 COMMENT '1 means vlan mapping of this account was changed',
|
||||
PRIMARY KEY(`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
SET foreign_key_checks = 1;
|
||||
|
|
|
|||
Loading…
Reference in New Issue