mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
open vswitch - Implement gre tunnel based network that doesn't use vlan
it allows cross zone communication and no 4096 limitation introduced by vlan
This commit is contained in:
parent
0dc959c23f
commit
276e37115b
42
api/src/com/cloud/network/ovs/OvsCreateTunnelAnswer.java
Normal file
42
api/src/com/cloud/network/ovs/OvsCreateTunnelAnswer.java
Normal file
@ -0,0 +1,42 @@
|
||||
package com.cloud.network.ovs;
|
||||
|
||||
import com.cloud.agent.api.Answer;
|
||||
import com.cloud.agent.api.Command;
|
||||
|
||||
public class OvsCreateTunnelAnswer extends Answer {
|
||||
Long from;
|
||||
Long to;
|
||||
long account;
|
||||
String inPortName;
|
||||
|
||||
public OvsCreateTunnelAnswer(Command cmd, boolean success, String details) {
|
||||
super(cmd, success, details);
|
||||
OvsCreateTunnelCommand c = (OvsCreateTunnelCommand)cmd;
|
||||
from = c.getFrom();
|
||||
to = c.getTo();
|
||||
account = c.getAccount();
|
||||
inPortName = "[]";
|
||||
}
|
||||
|
||||
public OvsCreateTunnelAnswer(Command cmd, boolean success, String details, String inPortName) {
|
||||
this(cmd, success, details);
|
||||
this.inPortName = inPortName;
|
||||
}
|
||||
|
||||
|
||||
public Long getFrom() {
|
||||
return from;
|
||||
}
|
||||
|
||||
public Long getTo() {
|
||||
return to;
|
||||
}
|
||||
|
||||
public long getAccount() {
|
||||
return account;
|
||||
}
|
||||
|
||||
public String getInPortName() {
|
||||
return inPortName;
|
||||
}
|
||||
}
|
||||
45
api/src/com/cloud/network/ovs/OvsCreateTunnelCommand.java
Normal file
45
api/src/com/cloud/network/ovs/OvsCreateTunnelCommand.java
Normal file
@ -0,0 +1,45 @@
|
||||
package com.cloud.network.ovs;
|
||||
|
||||
import com.cloud.agent.api.Command;
|
||||
|
||||
public class OvsCreateTunnelCommand extends Command {
|
||||
String key;
|
||||
String remoteIp;
|
||||
Long from;
|
||||
Long to;
|
||||
long account;
|
||||
|
||||
@Override
|
||||
public boolean executeInSequence() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public OvsCreateTunnelCommand(String remoteIp, String key, Long from, Long to, long account) {
|
||||
this.remoteIp = remoteIp;
|
||||
this.key = key;
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
this.account = account;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public String getRemoteIp() {
|
||||
return remoteIp;
|
||||
}
|
||||
|
||||
public Long getFrom() {
|
||||
return from;
|
||||
}
|
||||
|
||||
public Long getTo() {
|
||||
return to;
|
||||
}
|
||||
|
||||
public long getAccount() {
|
||||
return account;
|
||||
}
|
||||
|
||||
}
|
||||
27
api/src/com/cloud/network/ovs/OvsDestroyTunnelCommand.java
Normal file
27
api/src/com/cloud/network/ovs/OvsDestroyTunnelCommand.java
Normal file
@ -0,0 +1,27 @@
|
||||
package com.cloud.network.ovs;
|
||||
|
||||
import com.cloud.agent.api.Command;
|
||||
|
||||
public class OvsDestroyTunnelCommand extends Command {
|
||||
long account;
|
||||
String inPortName;
|
||||
|
||||
public OvsDestroyTunnelCommand(long account, String inPortName) {
|
||||
this.account = account;
|
||||
this.inPortName = inPortName;
|
||||
}
|
||||
|
||||
public long getAccount() {
|
||||
return account;
|
||||
}
|
||||
|
||||
public String getInPortName() {
|
||||
return inPortName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean executeInSequence() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@ -162,7 +162,10 @@ import com.cloud.network.Networks.IsolationType;
|
||||
import com.cloud.network.Networks.TrafficType;
|
||||
import com.cloud.network.ovs.OvsCreateGreTunnelAnswer;
|
||||
import com.cloud.network.ovs.OvsCreateGreTunnelCommand;
|
||||
import com.cloud.network.ovs.OvsCreateTunnelAnswer;
|
||||
import com.cloud.network.ovs.OvsCreateTunnelCommand;
|
||||
import com.cloud.network.ovs.OvsDeleteFlowCommand;
|
||||
import com.cloud.network.ovs.OvsDestroyTunnelCommand;
|
||||
import com.cloud.network.ovs.OvsSetTagAndFlowAnswer;
|
||||
import com.cloud.network.ovs.OvsSetTagAndFlowCommand;
|
||||
import com.cloud.resource.ServerResource;
|
||||
@ -440,6 +443,10 @@ public abstract class CitrixResourceBase implements ServerResource {
|
||||
return execute((CleanupNetworkRulesCmd)cmd);
|
||||
} else if (cmd instanceof NetworkRulesSystemVmCommand) {
|
||||
return execute((NetworkRulesSystemVmCommand)cmd);
|
||||
} else if (cmd instanceof OvsCreateTunnelCommand) {
|
||||
return execute((OvsCreateTunnelCommand)cmd);
|
||||
} else if (cmd instanceof OvsDestroyTunnelCommand) {
|
||||
return execute((OvsDestroyTunnelCommand)cmd);
|
||||
} else {
|
||||
return Answer.createUnsupportedCommandAnswer(cmd);
|
||||
}
|
||||
@ -544,6 +551,29 @@ public abstract class CitrixResourceBase implements ServerResource {
|
||||
return null;
|
||||
}
|
||||
|
||||
private synchronized Network createTunnelNetwork(Connection conn, long account) {
|
||||
try {
|
||||
String nwName = "OVSTunnel" + account;
|
||||
Network nw = null;
|
||||
Network.Record rec = new Network.Record();
|
||||
Set<Network> networks = Network.getByNameLabel(conn, nwName);
|
||||
|
||||
if (networks.size() == 0) {
|
||||
rec.nameDescription = "tunnel network for account " + account;
|
||||
rec.nameLabel = nwName;
|
||||
nw = Network.create(conn, rec);
|
||||
} else {
|
||||
nw = networks.iterator().next();
|
||||
}
|
||||
|
||||
enableXenServerNetwork(conn, nw, nwName, "tunnel network for account " + account);
|
||||
return nw;
|
||||
} catch (Exception e) {
|
||||
s_logger.warn("create tunnel network failed", e);
|
||||
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")) {
|
||||
@ -556,7 +586,13 @@ public abstract class CitrixResourceBase implements ServerResource {
|
||||
} else if (nic.getBroadcastType() == BroadcastDomainType.Native || nic.getBroadcastType() == BroadcastDomainType.LinkLocal) {
|
||||
return network.first();
|
||||
} else if (nic.getBroadcastType() == BroadcastDomainType.Vswitch) {
|
||||
URI broadcastUri = nic.getBroadcastUri();
|
||||
if (broadcastUri.getHost().equalsIgnoreCase("vlan")) {
|
||||
return setupvSwitchNetwork(conn);
|
||||
} else {
|
||||
long account = Long.parseLong(broadcastUri.getHost());
|
||||
return createTunnelNetwork(conn, account);
|
||||
}
|
||||
}
|
||||
|
||||
throw new CloudRuntimeException("Unable to support this type of network broadcast domain: " + nic.getBroadcastUri());
|
||||
@ -3971,6 +4007,51 @@ public abstract class CitrixResourceBase implements ServerResource {
|
||||
return Boolean.valueOf(callHostPlugin(conn, "vmops", "can_bridge_firewall", "host_uuid", _host.uuid));
|
||||
}
|
||||
|
||||
private Answer execute(OvsDestroyTunnelCommand cmd) {
|
||||
Connection conn = getConnection();
|
||||
try {
|
||||
Network nw = createTunnelNetwork(conn, cmd.getAccount());
|
||||
if (nw == null) {
|
||||
return new Answer(cmd, false, "No network found");
|
||||
}
|
||||
|
||||
String bridge = nw.getBridge(conn);
|
||||
String result = callHostPlugin(conn, "ovstunnel", "destroy_tunnel", "bridge", bridge, "in_port", cmd.getInPortName());
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
private OvsCreateTunnelAnswer execute(OvsCreateTunnelCommand cmd) {
|
||||
Connection conn = getConnection();
|
||||
try {
|
||||
Network nw = createTunnelNetwork(conn, cmd.getAccount());
|
||||
if (nw == null) {
|
||||
return new OvsCreateTunnelAnswer(cmd, false, "Cannot create network");
|
||||
}
|
||||
|
||||
String bridge = nw.getBridge(conn);
|
||||
String result = callHostPlugin(conn, "ovstunnel", "create_tunnel", "bridge", bridge, "remote_ip", cmd.getRemoteIp(), "key", cmd.getKey(), "from", cmd.getFrom().toString(), "to", cmd
|
||||
.getTo().toString());
|
||||
|
||||
String[] res = result.split(":");
|
||||
if (res.length == 2 && res[0].equalsIgnoreCase("SUCCESS")) {
|
||||
return new OvsCreateTunnelAnswer(cmd, true, result, res[1]);
|
||||
} else {
|
||||
return new OvsCreateTunnelAnswer(cmd, false, result);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
s_logger.warn("caught execption when creating ovs tunnel", e);
|
||||
return new OvsCreateTunnelAnswer(cmd, false, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private Answer execute(OvsDeleteFlowCommand cmd) {
|
||||
_isOvs = true;
|
||||
|
||||
|
||||
262
scripts/vm/hypervisor/xenserver/ovstunnel
Executable file
262
scripts/vm/hypervisor/xenserver/ovstunnel
Executable file
@ -0,0 +1,262 @@
|
||||
#!/usr/bin/python
|
||||
#
|
||||
# A plugin for executing script needed by vmops cloud
|
||||
|
||||
import os, sys, time
|
||||
import XenAPIPlugin
|
||||
sys.path.append("/opt/xensource/sm/")
|
||||
import util
|
||||
from util import CommandException
|
||||
import hostvmstats
|
||||
import socket
|
||||
import stat
|
||||
import base64
|
||||
import tempfile
|
||||
from os.path import exists as _exists
|
||||
from time import localtime as _localtime, asctime as _asctime
|
||||
|
||||
vSwitchDBPidFile = "/var/run/openvswitch/ovsdb-server.pid"
|
||||
vSwitchDBDaemonName = "ovsdb-server"
|
||||
vSwitchPidFile = "/var/run/openvswitch/ovs-vswitchd.pid"
|
||||
vsctlPath = "/usr/bin/ovs-vsctl"
|
||||
ofctlPath = "/usr/bin/ovs-ofctl"
|
||||
vSwitchDaemonName = "ovs-vswitchd"
|
||||
|
||||
logFile = "/var/log/ovstunnel.log"
|
||||
fLog = None
|
||||
|
||||
def echo(fn):
|
||||
def wrapped(*v, **k):
|
||||
name = fn.__name__
|
||||
util.SMlog("#### VMOPS enter %s ####" % name )
|
||||
res = fn(*v, **k)
|
||||
util.SMlog("#### VMOPS exit %s ####" % name )
|
||||
return res
|
||||
return wrapped
|
||||
|
||||
def open_log ():
|
||||
global fLog
|
||||
|
||||
try:
|
||||
if fLog == None:
|
||||
fLog = open (logFile, "a")
|
||||
except IOError, e:
|
||||
#print e
|
||||
pass
|
||||
|
||||
def pr (str):
|
||||
global fLog
|
||||
|
||||
if fLog != None:
|
||||
str = "[%s]:" % _asctime (_localtime()) + str + "\n"
|
||||
fLog.write (str)
|
||||
|
||||
def close_log ():
|
||||
global fLog
|
||||
|
||||
if fLog != None:
|
||||
fLog.close ()
|
||||
|
||||
def is_process_run (pidFile, name):
|
||||
try:
|
||||
fpid = open (pidFile, "r")
|
||||
pid = fpid.readline ()
|
||||
fpid.close ()
|
||||
except IOError, e:
|
||||
return -1
|
||||
|
||||
pid = pid[:-1]
|
||||
ps = os.popen ("ps -ae")
|
||||
for l in ps:
|
||||
if pid in l and name in l:
|
||||
ps.close ()
|
||||
return 0
|
||||
|
||||
ps.close ()
|
||||
return -2
|
||||
|
||||
def is_tool_exist (name):
|
||||
if _exists (name):
|
||||
return 0
|
||||
return -1
|
||||
|
||||
|
||||
def check_switch ():
|
||||
global result
|
||||
|
||||
ret = is_process_run (vSwitchDBPidFile, vSwitchDBDaemonName);
|
||||
if ret < 0:
|
||||
if ret == -1: return "NO_DB_PID_FILE"
|
||||
if ret == -2: return "DB_NOT_RUN"
|
||||
|
||||
ret = is_process_run (vSwitchPidFile, vSwitchDaemonName)
|
||||
if ret < 0:
|
||||
if ret == -1: return "NO_SWITCH_PID_FILE"
|
||||
if ret == -2: return "SWITCH_NOT_RUN"
|
||||
|
||||
if is_tool_exist (vsctlPath) < 0:
|
||||
return "NO_VSCTL"
|
||||
|
||||
if is_tool_exist (ofctlPath) < 0:
|
||||
return "NO_OFCTL"
|
||||
|
||||
return "SUCCESS"
|
||||
|
||||
def do_cmd (cmds, lines=False):
|
||||
cmd = ""
|
||||
for i in cmds:
|
||||
cmd += " "
|
||||
cmd += i
|
||||
|
||||
pr("do command '%s'" % cmd)
|
||||
f = os.popen (cmd)
|
||||
if lines == True:
|
||||
res = f.readlines ()
|
||||
else:
|
||||
res = f.readline ()
|
||||
res = res[:-1]
|
||||
f.close ()
|
||||
|
||||
if lines == False:
|
||||
pr("command output '%s'" % res)
|
||||
return res
|
||||
|
||||
######################## GRE creation utils ##########################
|
||||
# UUID's format is 8-4-4-4-12
|
||||
def is_uuid (uuid):
|
||||
list = uuid.split ("-")
|
||||
|
||||
if len (list) != 5:
|
||||
return -1
|
||||
|
||||
if len (list[0]) != 8 or len (list[1]) != 4 \
|
||||
or len (list[2]) != 4 or len (list[3]) != 4 \
|
||||
or len (list[4]) != 12:
|
||||
return -1
|
||||
|
||||
return 0
|
||||
|
||||
def set_flood_flow(bridge, inport):
|
||||
flow = "in_port=%s idle_timeout=0 hard_timeout=0 priority=10000 actions=flood" % inport
|
||||
add_flow(bridge, flow)
|
||||
|
||||
@echo
|
||||
def create_tunnel (session, args):
|
||||
bridge = args.pop("bridge")
|
||||
remoteIP = args.pop("remote_ip")
|
||||
greKey = args.pop("key")
|
||||
srcHost = args.pop("from")
|
||||
dstHost = args.pop("to")
|
||||
|
||||
res = check_switch()
|
||||
if res != "SUCCESS":
|
||||
return res
|
||||
|
||||
name = "%s-%s-%s-%s" % (bridge, srcHost, dstHost, greKey)
|
||||
|
||||
wait = [vsctlPath, "--timeout=30 wait-until bridge %s -- get bridge %s name" % \
|
||||
(bridge, bridge)]
|
||||
res = do_cmd(wait)
|
||||
if bridge not in res:
|
||||
pr("WARNIING:Can't find bridge %s for creating tunnel!" % bridge)
|
||||
result = "COMMAND_FAILED_NO_BRIDGE"
|
||||
return result
|
||||
|
||||
createInterface = [vsctlPath, "create interface", "name=%s" % name, \
|
||||
'type=gre options:remote_ip=%s options:key=%s' % (remoteIP, greKey)]
|
||||
ifaceUUID = do_cmd (createInterface)
|
||||
if is_uuid (ifaceUUID) < 0:
|
||||
pr("create interface failed, %s is not UUID" % ifaceUUID)
|
||||
result = "COMMAND_FAILED_CREATE_INTERFACE_FAILED"
|
||||
return result
|
||||
|
||||
createPort = [vsctlPath, "create port", "name=%s" % name, \
|
||||
"interfaces=[%s]" % ifaceUUID]
|
||||
portUUID = do_cmd (createPort)
|
||||
if is_uuid (portUUID) < 0:
|
||||
pr("create port failed, %s is not UUID" % portUUID)
|
||||
result = "COMMAND_FAILED_CREATE_PORT_FAILED"
|
||||
return result
|
||||
|
||||
addBridge = [vsctlPath, "add bridge %s" % bridge, "ports %s" % portUUID]
|
||||
do_cmd (addBridge)
|
||||
|
||||
wait = [vsctlPath, "--timeout=30 wait-until port %s -- get port %s name" % \
|
||||
(name, name)]
|
||||
res = do_cmd(wait)
|
||||
if name in res:
|
||||
port = get_field_of_interface(name, "ofport");
|
||||
if port == "[]":
|
||||
return "COMMAND_FAILED_PORT_IS_[]"
|
||||
|
||||
noFlood = [ofctlPath, "mod-port %s %s noflood" % (bridge, \
|
||||
port)]
|
||||
do_cmd(noFlood)
|
||||
|
||||
set_flood_flow(bridge, port)
|
||||
pr("create tunnel successful(bridge=%s, remote_ip=%s, key=%s, from=%s, to=%s" % \
|
||||
(bridge, remoteIP, greKey, srcHost, dstHost))
|
||||
result = "SUCCESS:%s" % name
|
||||
else:
|
||||
pr("create gre tunnel failed")
|
||||
result = "COMMAND_FAILED_CREATE_TUNNEL_FAILED"
|
||||
|
||||
return result
|
||||
######################## End GRE creation utils ##########################
|
||||
|
||||
def del_all_flows(bridge):
|
||||
delFlow = [ofctlPath, "del-flows %s" % bridge]
|
||||
do_cmd(delFlow)
|
||||
|
||||
normalFlow = "priority=0 idle_timeout=0 hard_timeout=0 actions=normal"
|
||||
add_flow(bridge, normalFlow)
|
||||
|
||||
def del_flows(bridge, ofport):
|
||||
delFlow = [ofctlPath, 'del-flows %s "in_port=%s"' % (bridge, ofport)]
|
||||
do_cmd(delFlow)
|
||||
|
||||
def del_port(bridge, port):
|
||||
delPort = [vsctlPath, "del-port %s %s" % (bridge, port)]
|
||||
do_cmd(delPort)
|
||||
|
||||
@echo
|
||||
def destroy_tunnel(session, args):
|
||||
bridge = args.pop("bridge")
|
||||
inPort = args.pop("in_port")
|
||||
|
||||
# delete all gre ports on bridge
|
||||
if inPort == "[]":
|
||||
listPorts = [vsctlPath, "list-ports %s" % bridge]
|
||||
res = do_cmd(listPorts, True)
|
||||
for p in res:
|
||||
if bridge in p:
|
||||
del_port(bridge, p)
|
||||
del_all_flows(bridge)
|
||||
else:
|
||||
ofport = get_field_of_interface(inPort, "ofport")
|
||||
del_flows(bridge, ofport)
|
||||
del_port(bridge, inPort)
|
||||
|
||||
return "SUCCESS"
|
||||
|
||||
def get_field_of_interface(nameOruuid, field):
|
||||
listIface = [vsctlPath, "list interface", nameOruuid]
|
||||
res = do_cmd(listIface, True)
|
||||
|
||||
for i in res:
|
||||
if field in i:
|
||||
(x, r) = i.split(":")
|
||||
return r.lstrip().rstrip()
|
||||
return None
|
||||
|
||||
|
||||
def add_flow(bridge, flow):
|
||||
param = bridge + ' "%s"' % flow
|
||||
addflow = ["ovs-ofctl add-flow", param]
|
||||
do_cmd (addflow)
|
||||
|
||||
if __name__ == "__main__":
|
||||
open_log()
|
||||
XenAPIPlugin.dispatch({"create_tunnel":create_tunnel, "destroy_tunnel":destroy_tunnel})
|
||||
close_log()
|
||||
|
||||
@ -13,6 +13,7 @@ NFSSR.py=/opt/xensource/sm
|
||||
nfs.py=/opt/xensource/sm
|
||||
vmops=..,0755,/etc/xapi.d/plugins
|
||||
ovsgre=..,0755,/etc/xapi.d/plugins
|
||||
ovstunnel=..,0755,/etc/xapi.d/plugins
|
||||
vmopsSnapshot=..,0755,/etc/xapi.d/plugins
|
||||
hostvmstats.py=..,0755,/opt/xensource/sm
|
||||
systemvm.iso=../../../../../vms,0644,/opt/xensource/packages/iso
|
||||
|
||||
@ -59,7 +59,9 @@ public enum Config {
|
||||
//MulticastThrottlingRate("Network", ManagementServer.class, Integer.class, "multicast.throttling.rate", "10", "Default multicast rate in megabits per second allowed.", null),
|
||||
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.internal", "Default domain name for vms inside virtualized networks fronted by router", null),
|
||||
OvsNetwork("Network", ManagementServer.class, Boolean.class, "open.vswitch.network", "false", "enable/disable open vswitch network", 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.vlan.network", "false", "enable/disable vlan remapping of open vswitch network", null),
|
||||
OvsTunnelNetwork("Network", ManagementServer.class, Boolean.class, "open.vswitch.tunnel.network", "false", "enable/disable open vswitch tunnel network(no vlan)", 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),
|
||||
|
||||
@ -73,7 +73,11 @@ 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.OvsTunnelManagerImpl;
|
||||
import com.cloud.network.ovs.dao.GreTunnelDaoImpl;
|
||||
import com.cloud.network.ovs.dao.OvsTunnelAccountDao;
|
||||
import com.cloud.network.ovs.dao.OvsTunnelAccountDaoImpl;
|
||||
import com.cloud.network.ovs.dao.OvsTunnelDaoImpl;
|
||||
import com.cloud.network.ovs.dao.OvsWorkDaoImpl;
|
||||
import com.cloud.network.ovs.dao.VlanMappingDaoImpl;
|
||||
import com.cloud.network.ovs.dao.VlanMappingDirtyDaoImpl;
|
||||
@ -251,6 +255,8 @@ public class DefaultComponentLibrary implements ComponentLibrary {
|
||||
addDao("OvsWorkDao", OvsWorkDaoImpl.class);
|
||||
addDao("VmFlowLogDao", VmFlowLogDaoImpl.class);
|
||||
addDao("GreTunnelDao", GreTunnelDaoImpl.class);
|
||||
addDao("OvsTunnelDao", OvsTunnelDaoImpl.class);
|
||||
addDao("OvsTunnelAccountDao", OvsTunnelAccountDaoImpl.class);
|
||||
}
|
||||
|
||||
Map<String, ComponentInfo<Manager>> _managers = new HashMap<String, ComponentInfo<Manager>>();
|
||||
@ -306,6 +312,7 @@ public class DefaultComponentLibrary implements ComponentLibrary {
|
||||
addManager("RulesManager", RulesManagerImpl.class);
|
||||
addManager("RemoteAccessVpnManager", RemoteAccessVpnManagerImpl.class);
|
||||
addManager("OvsNetworkManager", OvsNetworkManagerImpl.class);
|
||||
addManager("OvsTunnelManager", OvsTunnelManagerImpl.class);
|
||||
}
|
||||
|
||||
protected <T> List<ComponentInfo<Adapter>> addAdapterChain(Class<T> interphace, List<Pair<String, Class<? extends T>>> adapters) {
|
||||
|
||||
116
server/src/com/cloud/network/ovs/OvsTunnelListener.java
Normal file
116
server/src/com/cloud/network/ovs/OvsTunnelListener.java
Normal file
@ -0,0 +1,116 @@
|
||||
package com.cloud.network.ovs;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.EntityExistsException;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.cloud.agent.Listener;
|
||||
import com.cloud.agent.api.AgentControlAnswer;
|
||||
import com.cloud.agent.api.AgentControlCommand;
|
||||
import com.cloud.agent.api.Answer;
|
||||
import com.cloud.agent.api.Command;
|
||||
import com.cloud.agent.api.StartupCommand;
|
||||
import com.cloud.exception.ConnectionException;
|
||||
import com.cloud.host.Host;
|
||||
import com.cloud.host.HostVO;
|
||||
import com.cloud.host.Status;
|
||||
import com.cloud.host.dao.HostDao;
|
||||
import com.cloud.network.ovs.dao.GreTunnelVO;
|
||||
import com.cloud.network.ovs.dao.OvsTunnelDao;
|
||||
import com.cloud.network.ovs.dao.OvsTunnelVO;
|
||||
|
||||
public class OvsTunnelListener implements Listener {
|
||||
public static final Logger s_logger = Logger.getLogger(OvsListener.class.getName());
|
||||
HostDao _hostDao;
|
||||
OvsTunnelDao _tunnelDao;
|
||||
|
||||
public OvsTunnelListener(OvsTunnelDao tunnelDao, HostDao hostDao) {
|
||||
this._hostDao = hostDao;
|
||||
this._tunnelDao = tunnelDao;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processAnswers(long agentId, long seq, Answer[] answers) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processCommands(long agentId, long seq, Command[] commands) {
|
||||
// TODO Auto-generated method stub
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AgentControlAnswer processControlCommand(long agentId,
|
||||
AgentControlCommand cmd) {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processConnect(HostVO host, StartupCommand cmd)
|
||||
throws ConnectionException {
|
||||
if (host.getType() != Host.Type.Routing) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
List<HostVO> hosts = _hostDao.listByType(Host.Type.Routing);
|
||||
for (HostVO h : hosts) {
|
||||
if (h.getId() == host.getId()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
OvsTunnelVO t = _tunnelDao.getByFromAndTo(host.getId(), h.getId());
|
||||
if (t == null) {
|
||||
t = new OvsTunnelVO(host.getId(), h.getId());
|
||||
try {
|
||||
_tunnelDao.persist(t);
|
||||
} catch (EntityExistsException e) {
|
||||
s_logger.debug(String.format("Already has (from=%1$s, to=%2$s)", host.getId(), h.getId()));
|
||||
}
|
||||
}
|
||||
|
||||
t = _tunnelDao.getByFromAndTo(h.getId(), host.getId());
|
||||
if (t == null) {
|
||||
t = new OvsTunnelVO(h.getId(), host.getId());
|
||||
try {
|
||||
_tunnelDao.persist(t);
|
||||
} catch (EntityExistsException e) {
|
||||
s_logger.debug(String.format("Already has (from=%1$s, to=%2$s)", h.getId(), host.getId()));
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processDisconnect(long agentId, Status state) {
|
||||
// TODO Auto-generated method stub
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRecurring() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTimeout() {
|
||||
// TODO Auto-generated method stub
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processTimeout(long agentId, long seq) {
|
||||
// TODO Auto-generated method stub
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
19
server/src/com/cloud/network/ovs/OvsTunnelManager.java
Normal file
19
server/src/com/cloud/network/ovs/OvsTunnelManager.java
Normal file
@ -0,0 +1,19 @@
|
||||
package com.cloud.network.ovs;
|
||||
|
||||
import com.cloud.agent.manager.Commands;
|
||||
import com.cloud.deploy.DeployDestination;
|
||||
import com.cloud.utils.component.Manager;
|
||||
import com.cloud.vm.DomainRouterVO;
|
||||
import com.cloud.vm.UserVmVO;
|
||||
import com.cloud.vm.VMInstanceVO;
|
||||
import com.cloud.vm.VirtualMachineProfile;
|
||||
|
||||
public interface OvsTunnelManager extends Manager {
|
||||
boolean isOvsTunnelEnabled();
|
||||
|
||||
public void UserVmCheckAndCreateTunnel(Commands cmds, VirtualMachineProfile<UserVmVO> profile, DeployDestination dest);
|
||||
|
||||
public void RouterCheckAndCreateTunnel(Commands cmds, VirtualMachineProfile<DomainRouterVO> profile, DeployDestination dest);
|
||||
|
||||
public void CheckAndDestroyTunnel(VMInstanceVO vm);
|
||||
}
|
||||
288
server/src/com/cloud/network/ovs/OvsTunnelManagerImpl.java
Normal file
288
server/src/com/cloud/network/ovs/OvsTunnelManagerImpl.java
Normal file
@ -0,0 +1,288 @@
|
||||
package com.cloud.network.ovs;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
import javax.ejb.Local;
|
||||
import javax.naming.ConfigurationException;
|
||||
import javax.persistence.EntityExistsException;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.cloud.agent.AgentManager;
|
||||
import com.cloud.agent.api.Answer;
|
||||
import com.cloud.agent.api.Command;
|
||||
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.ovs.dao.OvsTunnelAccountDao;
|
||||
import com.cloud.network.ovs.dao.OvsTunnelAccountVO;
|
||||
import com.cloud.network.ovs.dao.OvsTunnelDao;
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.utils.component.Inject;
|
||||
import com.cloud.utils.concurrency.NamedThreadFactory;
|
||||
import com.cloud.utils.db.DB;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import com.cloud.vm.DomainRouterVO;
|
||||
import com.cloud.vm.UserVmVO;
|
||||
import com.cloud.vm.VMInstanceVO;
|
||||
import com.cloud.vm.VirtualMachine;
|
||||
import com.cloud.vm.VirtualMachineProfile;
|
||||
import com.cloud.vm.dao.DomainRouterDao;
|
||||
import com.cloud.vm.dao.UserVmDao;
|
||||
|
||||
@Local(value={OvsTunnelManager.class})
|
||||
public class OvsTunnelManagerImpl implements OvsTunnelManager {
|
||||
public static final Logger s_logger = Logger.getLogger(OvsTunnelManagerImpl.class.getName());
|
||||
|
||||
String _name;
|
||||
boolean _isEnabled;
|
||||
ScheduledExecutorService _executorPool;
|
||||
ScheduledExecutorService _cleanupExecutor;
|
||||
OvsTunnelListener _listener;
|
||||
|
||||
@Inject ConfigurationDao _configDao;
|
||||
@Inject OvsTunnelDao _tunnelDao;
|
||||
@Inject HostDao _hostDao;
|
||||
@Inject UserVmDao _userVmDao;
|
||||
@Inject DomainRouterDao _routerDao;
|
||||
@Inject OvsTunnelAccountDao _tunnelAccountDao;
|
||||
@Inject AgentManager _agentMgr;
|
||||
|
||||
@Override
|
||||
public boolean configure(String name, Map<String, Object> params)
|
||||
throws ConfigurationException {
|
||||
_name = name;
|
||||
_isEnabled = Boolean.parseBoolean(_configDao.getValue(Config.OvsTunnelNetwork.key()));
|
||||
|
||||
if (_isEnabled) {
|
||||
_executorPool = Executors.newScheduledThreadPool(10, new NamedThreadFactory("OVS"));
|
||||
_cleanupExecutor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("OVS-Cleanup"));
|
||||
_listener = new OvsTunnelListener(_tunnelDao, _hostDao);
|
||||
_agentMgr.registerForHostEvents(_listener, true, true, true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected int getGreKey(long from, long to, long account) {
|
||||
OvsTunnelAccountVO ta = null;
|
||||
int key;
|
||||
|
||||
try {
|
||||
key = _tunnelDao.askKey(from, to);
|
||||
ta = new OvsTunnelAccountVO(from, to, key, account);
|
||||
_tunnelAccountDao.persist(ta);
|
||||
} catch (EntityExistsException e) {
|
||||
ta = _tunnelAccountDao.getByFromToAccount(from, to, account);
|
||||
if (ta == null) {
|
||||
key = -1;
|
||||
} else {
|
||||
key = ta.getKey();
|
||||
}
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
private void handleCreateTunnelAnswer(Answer[] answers){
|
||||
OvsCreateTunnelAnswer r = (OvsCreateTunnelAnswer) answers[0];
|
||||
/*
|
||||
String s = String.format(
|
||||
"(hostIP:%1$s, remoteIP:%2$s, bridge:%3$s, greKey:%4$s)",
|
||||
r.getHostIp(), r.getRemoteIp(), r.getBridge(), r.getKey());
|
||||
*/
|
||||
String s = "hi";
|
||||
Long from = r.getFrom();
|
||||
Long to = r.getTo();
|
||||
long account = r.getAccount();
|
||||
OvsTunnelAccountVO ta = _tunnelAccountDao.getByFromToAccount(from, to, account);
|
||||
if (ta == null) {
|
||||
throw new CloudRuntimeException(String.format("Unable find tunnelAccount record(from=%1$s, to=%2$s, account=%3$s", from, to, account));
|
||||
}
|
||||
|
||||
if (!r.getResult()) {
|
||||
ta.setState("FAILED");
|
||||
s_logger.warn("Create GRE tunnel failed due to " + r.getDetails()
|
||||
+ s);
|
||||
} else {
|
||||
ta.setState("SUCCESS");
|
||||
ta.setPortName(r.getInPortName());
|
||||
s_logger.warn("Create GRE tunnel Success " + r.getDetails()
|
||||
+ s);
|
||||
}
|
||||
_tunnelAccountDao.update(ta.getId(), ta);
|
||||
}
|
||||
|
||||
@DB
|
||||
protected void CheckAndCreateTunnel(VMInstanceVO instance, DeployDestination dest) {
|
||||
if (!_isEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (instance.getType() != VirtualMachine.Type.User
|
||||
&& instance.getType() != VirtualMachine.Type.DomainRouter) {
|
||||
return;
|
||||
}
|
||||
|
||||
long hostId = dest.getHost().getId();
|
||||
long accountId = instance.getAccountId();
|
||||
List<UserVmVO>vms = _userVmDao.listByAccountId(accountId);
|
||||
DomainRouterVO router = _routerDao.findBy(accountId, instance.getDataCenterId());
|
||||
List<VMInstanceVO>ins = new ArrayList<VMInstanceVO>();
|
||||
ins.addAll(vms);
|
||||
ins.add(router);
|
||||
List<Pair<Long, Integer>>toHosts = new ArrayList<Pair<Long, Integer>>();
|
||||
List<Pair<Long, Integer>>fromHosts = new ArrayList<Pair<Long, Integer>>();
|
||||
int key;
|
||||
|
||||
for (VMInstanceVO v : ins) {
|
||||
Long rh = v.getHostId();
|
||||
if (rh == null || rh.longValue() == hostId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
OvsTunnelAccountVO ta = _tunnelAccountDao.getByFromToAccount(hostId, rh.longValue(), accountId);
|
||||
if (ta == null) {
|
||||
key = getGreKey(hostId, rh.longValue(), accountId);
|
||||
if (key == -1) {
|
||||
s_logger.warn(String.format("Cannot get GRE key for from=%1$s to=%2$s accountId=%3$s, tunnel create failed", hostId, rh.longValue(), accountId));
|
||||
continue;
|
||||
}
|
||||
|
||||
Pair<Long, Integer> p = new Pair<Long, Integer>(rh, Integer.valueOf(key));
|
||||
if (!toHosts.contains(p)) {
|
||||
toHosts.add(p);
|
||||
}
|
||||
}
|
||||
|
||||
ta = _tunnelAccountDao.getByFromToAccount(rh.longValue(), hostId, accountId);
|
||||
if (ta == null) {
|
||||
key = getGreKey(rh.longValue(), hostId, accountId);
|
||||
if (key == -1) {
|
||||
s_logger.warn(String.format("Cannot get GRE key for from=%1$s to=%2$s accountId=%3$s, tunnel create failed", rh.longValue(), hostId, accountId));
|
||||
continue;
|
||||
}
|
||||
|
||||
Pair<Long, Integer> p = new Pair<Long, Integer>(rh, Integer.valueOf(key));
|
||||
if (!fromHosts.contains(p)) {
|
||||
fromHosts.add(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
String myIp = dest.getHost().getPrivateIpAddress();
|
||||
for (Pair<Long, Integer> i : toHosts) {
|
||||
HostVO rHost = _hostDao.findById(i.first());
|
||||
Commands cmds = new Commands(
|
||||
new OvsCreateTunnelCommand(rHost.getPrivateIpAddress(), i.second().toString(), Long.valueOf(hostId), i.first(), accountId));
|
||||
s_logger.debug("Ask host " + hostId + " to create gre tunnel to " + i.first());
|
||||
Answer[] answers = _agentMgr.send(hostId, cmds);
|
||||
handleCreateTunnelAnswer(answers);
|
||||
}
|
||||
|
||||
for (Pair<Long, Integer> i : fromHosts) {
|
||||
Commands cmd2s = new Commands(
|
||||
new OvsCreateTunnelCommand(myIp, i.second().toString(), i.first(), Long.valueOf(hostId), accountId));
|
||||
s_logger.debug("Ask host " + i.first() + " to create gre tunnel to " + hostId);
|
||||
Answer[] answers = _agentMgr.send(i.first(), cmd2s);
|
||||
handleCreateTunnelAnswer(answers);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean start() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean stop() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return _name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOvsTunnelEnabled() {
|
||||
return _isEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void UserVmCheckAndCreateTunnel(Commands cmds, VirtualMachineProfile<UserVmVO> profile, DeployDestination dest) {
|
||||
CheckAndCreateTunnel(profile.getVirtualMachine(), dest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void RouterCheckAndCreateTunnel(Commands cmds, VirtualMachineProfile<DomainRouterVO> profile, DeployDestination dest) {
|
||||
CheckAndCreateTunnel(profile.getVirtualMachine(), dest);
|
||||
}
|
||||
|
||||
private void handleDestroyTunnelAnswer(Answer ans, long from, long to, long account) {
|
||||
String toStr = (to == 0 ? "all peers" : Long.toString(to));
|
||||
|
||||
if (ans.getResult()) {
|
||||
if (to == 0) {
|
||||
_tunnelAccountDao.removeByFromAccount(from, account);
|
||||
} else {
|
||||
_tunnelAccountDao.removeByFromToAccount(from, to, account);
|
||||
}
|
||||
|
||||
s_logger.debug(String.format("Destroy tunnel(account:%1$s, from:%2$s, to:%3$s) successful", account, from, toStr));
|
||||
} else {
|
||||
s_logger.debug(String.format("Destroy tunnel(account:%1$s, from:%2$s, to:%3$s) failed", account, from, toStr));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void CheckAndDestroyTunnel(VMInstanceVO vm) {
|
||||
if (!_isEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<UserVmVO> userVms = _userVmDao.listByAccountIdAndHostId(vm.getAccountId(), vm.getHostId());
|
||||
if (vm.getType() == VirtualMachine.Type.User) {
|
||||
if (userVms.size() > 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
DomainRouterVO router = _routerDao.findBy(vm.getAccountId(), vm.getDataCenterId());
|
||||
if (router.getHostId() == vm.getHostId()) {
|
||||
return;
|
||||
}
|
||||
} else if (vm.getType() == VirtualMachine.Type.DomainRouter && userVms.size() != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
/* Now we are last one on host, destroy all tunnels of my account */
|
||||
Command cmd = new OvsDestroyTunnelCommand(vm.getAccountId(), "[]");
|
||||
Answer ans = _agentMgr.send(vm.getHostId(), cmd);
|
||||
handleDestroyTunnelAnswer(ans, vm.getHostId(), 0, vm.getAccountId());
|
||||
|
||||
/* Then ask hosts have peer tunnel with me to destroy them */
|
||||
List<OvsTunnelAccountVO> peers = _tunnelAccountDao.listByToAccount(vm.getHostId(), vm.getAccountId());
|
||||
for (OvsTunnelAccountVO p : peers) {
|
||||
cmd = new OvsDestroyTunnelCommand(p.getAccount(), p.getPortName());
|
||||
ans = _agentMgr.send(p.getFrom(), cmd);
|
||||
handleDestroyTunnelAnswer(ans, p.getFrom(), p.getTo(), p.getAccount());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
s_logger.warn(String.format("Destroy tunnel(account:%1$s, hostId:%2$s) failed", vm.getAccountId(), vm.getHostId()), e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
package com.cloud.network.ovs.dao;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.cloud.utils.db.GenericDao;
|
||||
|
||||
public interface OvsTunnelAccountDao extends
|
||||
GenericDao<OvsTunnelAccountVO, Long> {
|
||||
OvsTunnelAccountVO getByFromToAccount(long from, long to, long account);
|
||||
void removeByFromAccount(long from, long account);
|
||||
void removeByFromToAccount(long from, long to, long account);
|
||||
List<OvsTunnelAccountVO> listByToAccount(long to, long account);
|
||||
}
|
||||
@ -0,0 +1,73 @@
|
||||
package com.cloud.network.ovs.dao;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
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 = { OvsTunnelAccountDao.class })
|
||||
public class OvsTunnelAccountDaoImpl extends
|
||||
GenericDaoBase<OvsTunnelAccountVO, Long> implements OvsTunnelAccountDao {
|
||||
|
||||
protected final SearchBuilder<OvsTunnelAccountVO> fromToAccountSearch;
|
||||
protected final SearchBuilder<OvsTunnelAccountVO> fromAccountSearch;
|
||||
protected final SearchBuilder<OvsTunnelAccountVO> toAccountSearch;
|
||||
|
||||
public OvsTunnelAccountDaoImpl() {
|
||||
fromToAccountSearch = createSearchBuilder();
|
||||
fromToAccountSearch.and("from", fromToAccountSearch.entity().getFrom(), Op.EQ);
|
||||
fromToAccountSearch.and("to", fromToAccountSearch.entity().getTo(), Op.EQ);
|
||||
fromToAccountSearch.and("account", fromToAccountSearch.entity().getAccount(), Op.EQ);
|
||||
fromToAccountSearch.done();
|
||||
|
||||
fromAccountSearch = createSearchBuilder();
|
||||
fromAccountSearch.and("from", fromAccountSearch.entity().getFrom(), Op.EQ);
|
||||
fromAccountSearch.and("account", fromAccountSearch.entity().getAccount(), Op.EQ);
|
||||
fromAccountSearch.done();
|
||||
|
||||
toAccountSearch = createSearchBuilder();
|
||||
toAccountSearch.and("to", toAccountSearch.entity().getTo(), Op.EQ);
|
||||
toAccountSearch.and("account", toAccountSearch.entity().getAccount(), Op.EQ);
|
||||
toAccountSearch.done();
|
||||
}
|
||||
|
||||
@Override
|
||||
public OvsTunnelAccountVO getByFromToAccount(long from, long to,
|
||||
long account) {
|
||||
SearchCriteria<OvsTunnelAccountVO> sc = fromToAccountSearch.create();
|
||||
sc.setParameters("from", from);
|
||||
sc.setParameters("to", to);
|
||||
sc.setParameters("account", account);
|
||||
return findOneBy(sc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeByFromAccount(long from, long account) {
|
||||
SearchCriteria<OvsTunnelAccountVO> sc = fromAccountSearch.create();
|
||||
sc.setParameters("from", from);
|
||||
sc.setParameters("account", account);
|
||||
remove(sc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<OvsTunnelAccountVO> listByToAccount(long to, long account) {
|
||||
SearchCriteria<OvsTunnelAccountVO> sc = toAccountSearch.create();
|
||||
sc.setParameters("to", to);
|
||||
sc.setParameters("account", account);
|
||||
return listBy(sc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeByFromToAccount(long from, long to, long account) {
|
||||
SearchCriteria<OvsTunnelAccountVO> sc = fromToAccountSearch.create();
|
||||
sc.setParameters("from", from);
|
||||
sc.setParameters("to", to);
|
||||
sc.setParameters("account", account);
|
||||
remove(sc);
|
||||
}
|
||||
|
||||
}
|
||||
88
server/src/com/cloud/network/ovs/dao/OvsTunnelAccountVO.java
Normal file
88
server/src/com/cloud/network/ovs/dao/OvsTunnelAccountVO.java
Normal file
@ -0,0 +1,88 @@
|
||||
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_tunnel_account"))
|
||||
public class OvsTunnelAccountVO {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "id")
|
||||
private long id;
|
||||
|
||||
@Column(name = "from")
|
||||
private long from;
|
||||
|
||||
@Column(name = "to")
|
||||
private long to;
|
||||
|
||||
@Column(name = "key")
|
||||
private int key;
|
||||
|
||||
@Column(name = "account")
|
||||
private long account;
|
||||
|
||||
@Column(name = "port_name")
|
||||
private String portName;
|
||||
|
||||
@Column(name = "state")
|
||||
private String state;
|
||||
|
||||
public OvsTunnelAccountVO() {
|
||||
|
||||
}
|
||||
|
||||
public OvsTunnelAccountVO(long from, long to, int key, long account) {
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
this.key = key;
|
||||
this.account = account;
|
||||
this.portName = "[]";
|
||||
this.state = "FAILED";
|
||||
}
|
||||
|
||||
public void setKey(int key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public long getFrom() {
|
||||
return from;
|
||||
}
|
||||
|
||||
public long getTo() {
|
||||
return to;
|
||||
}
|
||||
|
||||
public int getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public long getAccount() {
|
||||
return account;
|
||||
}
|
||||
|
||||
public String getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(String state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public void setPortName(String name) {
|
||||
this.portName = name;
|
||||
}
|
||||
|
||||
public String getPortName() {
|
||||
return portName;
|
||||
}
|
||||
}
|
||||
9
server/src/com/cloud/network/ovs/dao/OvsTunnelDao.java
Normal file
9
server/src/com/cloud/network/ovs/dao/OvsTunnelDao.java
Normal file
@ -0,0 +1,9 @@
|
||||
package com.cloud.network.ovs.dao;
|
||||
|
||||
import com.cloud.utils.db.GenericDao;
|
||||
|
||||
public interface OvsTunnelDao extends GenericDao<OvsTunnelVO, Long> {
|
||||
OvsTunnelVO lockByFromAndTo(long from, long to);
|
||||
OvsTunnelVO getByFromAndTo(long from, long to);
|
||||
int askKey(long from, long to);
|
||||
}
|
||||
59
server/src/com/cloud/network/ovs/dao/OvsTunnelDaoImpl.java
Normal file
59
server/src/com/cloud/network/ovs/dao/OvsTunnelDaoImpl.java
Normal file
@ -0,0 +1,59 @@
|
||||
package com.cloud.network.ovs.dao;
|
||||
|
||||
import javax.ejb.Local;
|
||||
|
||||
import com.cloud.utils.db.DB;
|
||||
import com.cloud.utils.db.GenericDaoBase;
|
||||
import com.cloud.utils.db.SearchBuilder;
|
||||
import com.cloud.utils.db.SearchCriteria;
|
||||
import com.cloud.utils.db.Transaction;
|
||||
import com.cloud.utils.db.SearchCriteria.Op;
|
||||
|
||||
@Local(value = { OvsTunnelDao.class })
|
||||
public class OvsTunnelDaoImpl extends GenericDaoBase<OvsTunnelVO, Long>
|
||||
implements OvsTunnelDao {
|
||||
|
||||
protected final SearchBuilder<OvsTunnelVO> fromToSearch;
|
||||
|
||||
public OvsTunnelDaoImpl() {
|
||||
fromToSearch = createSearchBuilder();
|
||||
fromToSearch.and("from", fromToSearch.entity().getFrom(), Op.EQ);
|
||||
fromToSearch.and("to", fromToSearch.entity().getTo(), Op.EQ);
|
||||
fromToSearch.done();
|
||||
}
|
||||
|
||||
@Override
|
||||
public OvsTunnelVO lockByFromAndTo(long from, long to) {
|
||||
SearchCriteria<OvsTunnelVO> sc = fromToSearch.create();
|
||||
sc.setParameters("from", from);
|
||||
sc.setParameters("to", to);
|
||||
return lockOneRandomRow(sc, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@DB
|
||||
public int askKey(long from, long to) {
|
||||
int key = -1;
|
||||
|
||||
final Transaction txn = Transaction.currentTxn();
|
||||
txn.start();
|
||||
OvsTunnelVO t = lockByFromAndTo(from, to);
|
||||
if (t != null) {
|
||||
key = t.getKey();
|
||||
t.setKey(key+1);
|
||||
update(t.getId(), t);
|
||||
}
|
||||
|
||||
txn.commit();
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OvsTunnelVO getByFromAndTo(long from, long to) {
|
||||
SearchCriteria<OvsTunnelVO> sc = fromToSearch.create();
|
||||
sc.setParameters("from", from);
|
||||
sc.setParameters("to", to);
|
||||
return findOneBy(sc);
|
||||
}
|
||||
|
||||
}
|
||||
64
server/src/com/cloud/network/ovs/dao/OvsTunnelVO.java
Normal file
64
server/src/com/cloud/network/ovs/dao/OvsTunnelVO.java
Normal file
@ -0,0 +1,64 @@
|
||||
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_tunnel"))
|
||||
public class OvsTunnelVO {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "id")
|
||||
private long id;
|
||||
|
||||
@Column(name = "from")
|
||||
private long from;
|
||||
|
||||
@Column(name = "to")
|
||||
private long to;
|
||||
|
||||
@Column(name = "key")
|
||||
private int key;
|
||||
|
||||
|
||||
public OvsTunnelVO() {
|
||||
|
||||
}
|
||||
|
||||
public OvsTunnelVO(long from, long to) {
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
this.key = 0;
|
||||
}
|
||||
|
||||
public OvsTunnelVO(long id, long from, long to) {
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
this.key = 0;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public void setKey(int key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public long getFrom() {
|
||||
return from;
|
||||
}
|
||||
|
||||
public long getTo() {
|
||||
return to;
|
||||
}
|
||||
|
||||
public int getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
@ -118,6 +118,7 @@ import com.cloud.network.lb.LoadBalancingRule.LbDestination;
|
||||
import com.cloud.network.lb.LoadBalancingRulesManager;
|
||||
import com.cloud.network.ovs.GreTunnelException;
|
||||
import com.cloud.network.ovs.OvsNetworkManager;
|
||||
import com.cloud.network.ovs.OvsTunnelManager;
|
||||
import com.cloud.network.router.VirtualRouter.Role;
|
||||
import com.cloud.network.rules.FirewallRule;
|
||||
import com.cloud.network.rules.PortForwardingRule;
|
||||
@ -285,6 +286,8 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian
|
||||
VMInstanceDao _instanceDao;
|
||||
@Inject
|
||||
OvsNetworkManager _ovsNetworkMgr;
|
||||
@Inject
|
||||
OvsTunnelManager _ovsTunnelMgr;
|
||||
|
||||
long _routerTemplateId = -1;
|
||||
int _routerRamSize;
|
||||
@ -1103,6 +1106,7 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian
|
||||
try {
|
||||
_ovsNetworkMgr.RouterCheckAndCreateTunnel(cmds, profile, dest);
|
||||
_ovsNetworkMgr.applyDefaultFlowToRouter(cmds, profile, dest);
|
||||
_ovsTunnelMgr.RouterCheckAndCreateTunnel(cmds, profile, dest);
|
||||
} catch (GreTunnelException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@ -1227,6 +1231,7 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian
|
||||
|
||||
DomainRouterVO router = profile.getVirtualMachine();
|
||||
_ovsNetworkMgr.handleVmStateTransition(router, State.Stopped);
|
||||
_ovsTunnelMgr.CheckAndDestroyTunnel(router);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -125,6 +125,7 @@ import com.cloud.network.dao.NetworkDao;
|
||||
import com.cloud.network.lb.LoadBalancingRulesManager;
|
||||
import com.cloud.network.ovs.GreTunnelException;
|
||||
import com.cloud.network.ovs.OvsNetworkManager;
|
||||
import com.cloud.network.ovs.OvsTunnelManager;
|
||||
import com.cloud.network.router.VirtualNetworkApplianceManager;
|
||||
import com.cloud.network.rules.RulesManager;
|
||||
import com.cloud.network.security.SecurityGroupManager;
|
||||
@ -259,6 +260,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
|
||||
@Inject SSHKeyPairDao _sshKeyPairDao;
|
||||
@Inject UserVmDetailsDao _vmDetailsDao;
|
||||
@Inject OvsNetworkManager _ovsNetworkMgr;
|
||||
@Inject OvsTunnelManager _ovsTunnelMgr;
|
||||
|
||||
private IpAddrAllocator _IpAllocator;
|
||||
ScheduledExecutorService _executor = null;
|
||||
@ -2212,6 +2214,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
|
||||
try {
|
||||
_ovsNetworkMgr.UserVmCheckAndCreateTunnel(cmds, profile, dest);
|
||||
_ovsNetworkMgr.applyDefaultFlowToUserVm(cmds, profile, dest);
|
||||
_ovsTunnelMgr.UserVmCheckAndCreateTunnel(cmds, profile, dest);
|
||||
} catch (GreTunnelException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@ -2282,6 +2285,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
|
||||
UserVmVO vm = profile.getVirtualMachine();
|
||||
_networkGroupMgr.handleVmStateTransition(vm, State.Stopped);
|
||||
_ovsNetworkMgr.handleVmStateTransition(vm, State.Stopped);
|
||||
_ovsTunnelMgr.CheckAndDestroyTunnel(vm);
|
||||
}
|
||||
|
||||
public String generateRandomPassword() {
|
||||
|
||||
@ -1376,6 +1376,25 @@ CREATE TABLE `cloud`.`ovs_tunnel_alloc`(
|
||||
PRIMARY KEY(`from`, `to`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
CREATE TABLE `cloud`.`ovs_tunnel`(
|
||||
`id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT,
|
||||
`from` bigint unsigned COMMENT 'from host id',
|
||||
`to` bigint unsigned COMMENT 'to host id',
|
||||
`key` int unsigned default '0' COMMENT 'current gre key can be used',
|
||||
PRIMARY KEY(`from`, `to`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
CREATE TABLE `cloud`.`ovs_tunnel_account`(
|
||||
`id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT,
|
||||
`from` bigint unsigned COMMENT 'from host id',
|
||||
`to` bigint unsigned COMMENT 'to host id',
|
||||
`account` bigint unsigned COMMENT 'account',
|
||||
`key` int unsigned COMMENT 'gre key',
|
||||
`port_name` varchar(32) COMMENT 'in port on open vswitch',
|
||||
`state` varchar(16) default 'FAILED' COMMENT 'result of tunnel creatation',
|
||||
PRIMARY KEY(`from`, `to`, `account`)
|
||||
) 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',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user