mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
bug 7722: open vswitch - works at VM start time, need fullsync() and flow clean in next
This commit is contained in:
parent
5c01c42ba7
commit
c94b6acadf
@ -3820,34 +3820,22 @@ 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
|
||||
* none guest network nic. don't worry, it will fail silently 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);
|
||||
|
||||
}
|
||||
String result = callHostPlugin(conn, "vmops", "ovs_set_tag_and_flow", "bridge", bridge,
|
||||
"vmName", cmd.getVmName(), "vlans", cmd.getVlans());
|
||||
s_logger.debug("set flow for " + cmd.getVmName() + " " + result);
|
||||
|
||||
/*
|
||||
if (result.equalsIgnoreCase("SUCCESS")) {
|
||||
return new Answer(cmd, true, "Set flow for " + cmd.getVmName()
|
||||
+ " success, vlans:" + cmd.getVlans());
|
||||
@ -3855,9 +3843,6 @@ public abstract class CitrixResourceBase implements ServerResource {
|
||||
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();
|
||||
}
|
||||
|
||||
@ -338,7 +338,7 @@ def formatARPFlow(bridge, inPort, vlan, ports):
|
||||
actions=strip_vlan,%s" % (inPort, vlan, outputs)
|
||||
return flow
|
||||
|
||||
def createFlow (bridge, vifName, mac, ip, vlan, remap):
|
||||
def createFlow (bridge, vifName, mac, remap):
|
||||
inport = getGreOfPorts(bridge)
|
||||
if len(inport) == 0:
|
||||
log("WARNING: no inport found")
|
||||
@ -357,7 +357,7 @@ def createFlow (bridge, vifName, mac, ip, vlan, remap):
|
||||
delFlow(mac)
|
||||
|
||||
#set remap here, remap has format e.g. [1,22,200,13,16]
|
||||
remap = strip(remap, "both")
|
||||
remap = strip(remap)
|
||||
log("")
|
||||
log("Create flow for remap")
|
||||
noneGreOfPorts = getNoneGreOfPort(bridge)
|
||||
@ -366,7 +366,7 @@ def createFlow (bridge, vifName, mac, ip, vlan, remap):
|
||||
log("WARNING: no none GRE ofports found, no ARP flow will be created")
|
||||
isARP = False
|
||||
|
||||
for j in remap.split(","):
|
||||
for j in remap.split("/"):
|
||||
delARPFlow(j)
|
||||
for i in inport:
|
||||
flow = formatFlow(i, j, mac, output)
|
||||
@ -383,8 +383,19 @@ def createFlow (bridge, vifName, mac, ip, vlan, remap):
|
||||
return 0
|
||||
######################## End Flow creation utils ##########################
|
||||
|
||||
def setTag(vifName, vlan):
|
||||
log("")
|
||||
def setTag(bridge, vifName, vlan):
|
||||
# The startVM command is slow, we may wait for a while for it creates vif on
|
||||
# open vswitch
|
||||
log("Waiting for %s ..." % vifName)
|
||||
waitPortCmd = [vsctlPath, "--timeout=10 wait-until port %s -- get port %s name" % \
|
||||
(vifName, vifName)]
|
||||
doCmd (waitPortCmd)
|
||||
log("%s is here" % vifName)
|
||||
|
||||
if getVifPort(bridge, vifName) == None:
|
||||
log("WARNING: %s is not on bridge %s" % (vifName, bridge))
|
||||
return 0
|
||||
|
||||
log("Set tag")
|
||||
setTagCmd = [vsctlPath, "set port", vifName, "tag=%s"%vlan]
|
||||
doCmd (setTagCmd)
|
||||
@ -398,20 +409,22 @@ def doCreateGRE(bridge, remoteIP, key):
|
||||
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))
|
||||
def doCreateFlow (bridge, vifName, mac, remap):
|
||||
if createFlow(bridge, vifName, mac, remap) < 0:
|
||||
log ("Create flow failed(bridge=%s, vifName=%s, mac=%s,\
|
||||
remap=%s" % (bridge, vifName, mac, remap))
|
||||
else:
|
||||
log ("Create flow success(bridge=%s, vifName=%s, mac=%s, ip=%s, vlan=%s,\
|
||||
remap=%s" % (bridge, vifName, mac, ip, vlan, remap))
|
||||
log ("Create flow success(bridge=%s, vifName=%s, mac=%s,\
|
||||
remap=%s" % (bridge, vifName, mac, remap))
|
||||
|
||||
def doSetTag (bridge, vifName, tag):
|
||||
setTag(bridge, vifName, tag)
|
||||
|
||||
def doDeleteFlow(bridge, vifName, mac, remap):
|
||||
delFlow(mac)
|
||||
log("Delete flows for %s" % mac)
|
||||
|
||||
remap = strip(remap, "both")
|
||||
remap = strip(remap)
|
||||
|
||||
# remove our port from arp flow
|
||||
inport = getGreOfPorts(bridge)
|
||||
@ -423,7 +436,7 @@ def doDeleteFlow(bridge, vifName, mac, remap):
|
||||
noneGreOfPorts.remove(mine)
|
||||
log("Delete ARP flows for(vifname=%s, ofport=%s)" % (vifName, mine))
|
||||
|
||||
for j in remap.split(","):
|
||||
for j in remap.split("/"):
|
||||
delARPFlow(j)
|
||||
for i in inport:
|
||||
flow = formatARPFlow(bridge, i, j, noneGreOfPorts)
|
||||
@ -457,14 +470,12 @@ if __name__ == "__main__":
|
||||
key = sys.argv[4]
|
||||
doCreateGRE(bridge, remoteIP, key)
|
||||
elif op == "createFlow":
|
||||
checkArgNum(8)
|
||||
checkArgNum(6)
|
||||
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)
|
||||
remap = sys.argv[5]
|
||||
doCreateFlow(bridge, vifName, mac, remap)
|
||||
elif op == "deleteFlow":
|
||||
checkArgNum(6)
|
||||
bridge = sys.argv[2]
|
||||
@ -472,6 +483,12 @@ if __name__ == "__main__":
|
||||
mac = sys.argv[4]
|
||||
remap = sys.argv[5]
|
||||
doDeleteFlow(bridge, vifName, mac, remap)
|
||||
elif op == "setTag":
|
||||
checkArgNum(5)
|
||||
bridge = sys.argv[2]
|
||||
vifName = sys.argv[3]
|
||||
tag = sys.argv[4]
|
||||
doSetTag(bridge, vifName, tag)
|
||||
else:
|
||||
log("WARNING: get an unkown op %s" % op)
|
||||
result=errors["ERROR_OP"]
|
||||
|
||||
@ -144,14 +144,16 @@ def vlanRemapUtils(session, args):
|
||||
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"))
|
||||
elif op == "setTag":
|
||||
cmd.insert(3, args.pop("bridge"))
|
||||
cmd.insert(4, args.pop("vifName"))
|
||||
cmd.insert(5, args.pop("tag"))
|
||||
|
||||
try:
|
||||
txt = util.pread2(cmd)
|
||||
@ -552,6 +554,47 @@ def default_ebtables_rules(vm_name, vif, vm_ip, vm_mac):
|
||||
util.SMlog("Failed to program default ebtables OUT rules")
|
||||
return 'false'
|
||||
|
||||
def ovs_set_tag_and_flow(session, args):
|
||||
def get_vif_field(name, field):
|
||||
return session.xenapi.VIF.get_record(name).get(field)
|
||||
|
||||
bridge = args.pop('bridge')
|
||||
vm_name = args.pop('vmName')
|
||||
vlanStr = args.pop('vlans')
|
||||
|
||||
try:
|
||||
vm = session.xenapi.VM.get_by_name_label(vm_name)
|
||||
if len(vm) != 1:
|
||||
return 'false'
|
||||
vm_rec = session.xenapi.VM.get_record(vm[0])
|
||||
vm_vifs = vm_rec.get('VIFs')
|
||||
vifrs = []
|
||||
for vif in vm_vifs:
|
||||
rec = (get_vif_field(vif, 'device'), get_vif_field(vif, 'MAC'))
|
||||
vifrs.append(rec)
|
||||
domid = vm_rec.get('domid')
|
||||
except:
|
||||
util.SMlog("### Failed to get domid or vif list for vm ##" + vm_name)
|
||||
return 'false'
|
||||
|
||||
if domid == '-1':
|
||||
util.SMlog("### Failed to get domid for vm (-1): " + vm_name)
|
||||
return 'false'
|
||||
|
||||
if len(vifrs) == 0:
|
||||
return 'SUCCESS'
|
||||
|
||||
if vlanStr.startswith("/"): vlanStr = vlanStr[1:]
|
||||
if vlanStr.endswith("/"): vlanStr = vlanStr[:-1]
|
||||
vlans = vlanStr.split("/")
|
||||
for vifr in vifrs:
|
||||
vifName = "vif" + domid + "." + vifr[0]
|
||||
mac = vifr[1]
|
||||
vlanRemapUtils(session, {"op":"setTag", "vifName":vifName, "bridge":bridge, "tag":vlans[0]})
|
||||
vlanRemapUtils(session, {"op":"createFlow", "vifName":vifName, "bridge":bridge, "mac":mac, "remap":vlanStr})
|
||||
|
||||
return 'SUCCESS'
|
||||
|
||||
@echo
|
||||
def default_network_rules_systemvm(session, args):
|
||||
vm_name = args.pop('vmName')
|
||||
@ -627,9 +670,9 @@ def default_network_rules(session, args):
|
||||
vifs = [vif]
|
||||
try:
|
||||
util.pread2(['ifconfig', tap])
|
||||
vifs.append(tap)
|
||||
vifs.append(tap)
|
||||
except:
|
||||
pass
|
||||
pass
|
||||
|
||||
delete_rules_for_vm_in_bridge_firewall_chain(vm_name)
|
||||
|
||||
@ -669,7 +712,7 @@ def default_network_rules(session, args):
|
||||
return 'false'
|
||||
|
||||
for v in vifs:
|
||||
default_ebtables_rules(vm_name, v, vm_ip, vm_mac)
|
||||
default_ebtables_rules(vm_name, v, vm_ip, vm_mac)
|
||||
|
||||
if write_rule_log_for_vm(vmName, vm_id, vm_ip, domid, '_initial_', '-1') == False:
|
||||
util.SMlog("Failed to log default network rules, ignoring")
|
||||
@ -983,9 +1026,9 @@ def network_rules(session, args):
|
||||
vifs = [vif]
|
||||
try:
|
||||
util.pread2(['ifconfig', tap])
|
||||
vifs.append(tap)
|
||||
vifs.append(tap)
|
||||
except:
|
||||
pass
|
||||
pass
|
||||
vm_name = '-'.join(vm_name.split('-')[:-1])
|
||||
vmchain = vm_name
|
||||
|
||||
@ -1064,5 +1107,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, "vlanRemapUtils":vlanRemapUtils,"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,"cleanup_rules":cleanup_rules,"vlanRemapUtils":vlanRemapUtils, "ovs_set_tag_and_flow":ovs_set_tag_and_flow})
|
||||
|
||||
|
||||
@ -31,3 +31,4 @@ call_firewall.sh=../../../../network/domr/,0755,/opt/xensource/bin
|
||||
call_loadbalancer.sh=../../../../network/domr/,0755,/opt/xensource/bin
|
||||
l2tp_vpn.sh=../../../../network/domr/,0755,/opt/xensource/bin
|
||||
cloud-setup-bonding.sh=..,0755,/opt/xensource/bin
|
||||
vlanRemapUtils.py=..,0755,/opt/xensource/bin
|
||||
|
||||
@ -73,8 +73,10 @@ 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.OvsWorkDaoImpl;
|
||||
import com.cloud.network.ovs.dao.VlanMappingDaoImpl;
|
||||
import com.cloud.network.ovs.dao.VlanMappingDirtyDaoImpl;
|
||||
import com.cloud.network.ovs.dao.VmFlowLogDaoImpl;
|
||||
import com.cloud.network.router.VirtualNetworkApplianceManagerImpl;
|
||||
import com.cloud.network.rules.RulesManagerImpl;
|
||||
import com.cloud.network.rules.dao.PortForwardingRulesDaoImpl;
|
||||
@ -241,6 +243,8 @@ public class DefaultComponentLibrary implements ComponentLibrary {
|
||||
addDao("ClusterDetailsDao", ClusterDetailsDaoImpl.class);
|
||||
addDao("VlanMappingDao", VlanMappingDaoImpl.class);
|
||||
addDao("VlanMappingDirtyDao", VlanMappingDirtyDaoImpl.class);
|
||||
addDao("OvsWorkDao", OvsWorkDaoImpl.class);
|
||||
addDao("VmFlowLogDao", VmFlowLogDaoImpl.class);
|
||||
}
|
||||
|
||||
Map<String, ComponentInfo<Manager>> _managers = new HashMap<String, ComponentInfo<Manager>>();
|
||||
|
||||
@ -252,6 +252,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag
|
||||
}
|
||||
|
||||
@Override
|
||||
@DB
|
||||
public PublicIp assignSourceNatIpAddress(Account owner, Network network, long callerId) throws ConcurrentOperationException, InsufficientAddressCapacityException {
|
||||
assert (network.getTrafficType() != null) : "You're asking for a source nat but your network can't participate in source nat. What do you have to say for yourself?";
|
||||
|
||||
|
||||
@ -10,6 +10,7 @@ import com.cloud.exception.ConcurrentOperationException;
|
||||
import com.cloud.exception.InsufficientCapacityException;
|
||||
import com.cloud.exception.ResourceUnavailableException;
|
||||
import com.cloud.network.Network;
|
||||
import com.cloud.network.Networks;
|
||||
import com.cloud.network.PublicIpAddress;
|
||||
import com.cloud.network.Network.Capability;
|
||||
import com.cloud.network.Network.Provider;
|
||||
@ -55,7 +56,15 @@ public class OvsElement extends AdapterBase implements NetworkElement {
|
||||
DeployDestination dest, ReservationContext context)
|
||||
throws ConcurrentOperationException, ResourceUnavailableException,
|
||||
InsufficientCapacityException {
|
||||
_ovsNetworkMgr.CheckAndUpdateDhcpFlow(network);
|
||||
VirtualMachine instance = vm.getVirtualMachine();
|
||||
|
||||
if (instance.getType() == VirtualMachine.Type.DomainRouter) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (network.getTrafficType() == Networks.TrafficType.Guest) {
|
||||
_ovsNetworkMgr.CheckAndUpdateDhcpFlow(network);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -5,6 +5,7 @@ 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.DomainRouterVO;
|
||||
import com.cloud.vm.State;
|
||||
import com.cloud.vm.UserVmVO;
|
||||
import com.cloud.vm.VirtualMachineProfile;
|
||||
@ -16,12 +17,21 @@ public interface OvsNetworkManager extends Manager {
|
||||
|
||||
public String getVlanMapping(long accountId);
|
||||
|
||||
public void CheckAndCreateTunnel(Commands cmds,
|
||||
public void UserVmCheckAndCreateTunnel(Commands cmds,
|
||||
VirtualMachineProfile<UserVmVO> profile, DeployDestination dest);
|
||||
|
||||
public void applyDefaultFlow(Commands cmds,
|
||||
public void applyDefaultFlowToUserVm(Commands cmds,
|
||||
VirtualMachineProfile<UserVmVO> profile, DeployDestination dest);
|
||||
|
||||
|
||||
public void applyDefaultFlowToRouter(Commands cmds,
|
||||
VirtualMachineProfile<DomainRouterVO> profile,
|
||||
DeployDestination dest);
|
||||
|
||||
public void CheckAndUpdateDhcpFlow(Network nw);
|
||||
|
||||
public void handleVmStateTransition(UserVm userVm, State vmState);
|
||||
|
||||
public void RouterCheckAndCreateTunnel(Commands cmds,
|
||||
VirtualMachineProfile<DomainRouterVO> profile,
|
||||
DeployDestination dest);
|
||||
}
|
||||
|
||||
@ -1,8 +1,15 @@
|
||||
package com.cloud.network.ovs;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.ejb.Local;
|
||||
import javax.naming.ConfigurationException;
|
||||
|
||||
@ -13,6 +20,7 @@ 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.exception.AgentUnavailableException;
|
||||
import com.cloud.host.HostVO;
|
||||
import com.cloud.host.dao.HostDao;
|
||||
import com.cloud.network.Network;
|
||||
@ -20,17 +28,27 @@ 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.OvsWorkDao;
|
||||
import com.cloud.network.ovs.dao.OvsWorkVO;
|
||||
import com.cloud.network.ovs.dao.OvsWorkVO.Step;
|
||||
import com.cloud.network.ovs.dao.VlanMappingDao;
|
||||
import com.cloud.network.ovs.dao.VlanMappingDirtyDao;
|
||||
import com.cloud.network.ovs.dao.VlanMappingVO;
|
||||
import com.cloud.network.ovs.dao.VmFlowLogDao;
|
||||
import com.cloud.network.ovs.dao.VmFlowLogVO;
|
||||
import com.cloud.server.ManagementServer;
|
||||
import com.cloud.uservm.UserVm;
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.utils.component.ComponentLocator;
|
||||
import com.cloud.utils.component.Inject;
|
||||
import com.cloud.utils.concurrency.NamedThreadFactory;
|
||||
import com.cloud.utils.db.DB;
|
||||
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.VMInstanceVO;
|
||||
import com.cloud.vm.VirtualMachine;
|
||||
import com.cloud.vm.VirtualMachineProfile;
|
||||
import com.cloud.vm.dao.DomainRouterDao;
|
||||
@ -49,61 +67,183 @@ public class OvsNetworkManagerImpl implements OvsNetworkManager {
|
||||
@Inject NetworkDao _networkDao;
|
||||
@Inject VlanMappingDirtyDao _vlanMappingDirtyDao;
|
||||
@Inject DomainRouterDao _routerDao;
|
||||
@Inject OvsWorkDao _workDao;
|
||||
@Inject VmFlowLogDao _flowLogDao;
|
||||
@Inject UserVmDao _userVMDao;
|
||||
String _name;
|
||||
boolean _isEnabled;
|
||||
ScheduledExecutorService _executorPool;
|
||||
ScheduledExecutorService _cleanupExecutor;
|
||||
|
||||
private long _serverId;
|
||||
private final long _timeBetweenCleanups = 30; //seconds
|
||||
|
||||
public class WorkerThread implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
work();
|
||||
}
|
||||
|
||||
WorkerThread() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class CleanupThread implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
cleanupFinishedWork();
|
||||
cleanupUnfinishedWork();
|
||||
}
|
||||
|
||||
CleanupThread() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean configure(String name, Map<String, Object> params)
|
||||
throws ConfigurationException {
|
||||
_name = name;
|
||||
_isEnabled = _configDao.getValue(Config.OvsNetwork.key()).equalsIgnoreCase("true") ? true : false;
|
||||
_serverId = ((ManagementServer)ComponentLocator.getComponent(ManagementServer.Name)).getId();
|
||||
_executorPool = Executors.newScheduledThreadPool(10, new NamedThreadFactory("OVS"));
|
||||
_cleanupExecutor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("OVS-Cleanup"));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean start() {
|
||||
// TODO Auto-generated method stub
|
||||
if (_isEnabled) {
|
||||
_cleanupExecutor.scheduleAtFixedRate(new CleanupThread(), _timeBetweenCleanups, _timeBetweenCleanups, TimeUnit.SECONDS);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
public void cleanupFinishedWork() {
|
||||
Date before = new Date(System.currentTimeMillis() - 24*3600*1000l);
|
||||
int numDeleted = _workDao.deleteFinishedWork(before);
|
||||
if (numDeleted > 0) {
|
||||
s_logger.info("Ovs cleanup deleted " + numDeleted + " finished work items older than " + before.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void cleanupUnfinishedWork() {
|
||||
Date before = new Date(System.currentTimeMillis() - 30*1000l);
|
||||
List<OvsWorkVO> unfinished = _workDao.findUnfinishedWork(before);
|
||||
if (unfinished.size() > 0) {
|
||||
s_logger.info("Ovscleanup found " + unfinished.size() + " unfinished work items older than " + before.toString());
|
||||
Set<Long> affectedVms = new HashSet<Long>();
|
||||
for (OvsWorkVO work: unfinished) {
|
||||
affectedVms.add(work.getInstanceId());
|
||||
}
|
||||
|
||||
s_logger.info("Ovs cleanup re-schedule unfinished work");
|
||||
scheduleFlowUpdateToHosts(affectedVms, false, null);
|
||||
} else {
|
||||
s_logger.debug("Ovs cleanup found no unfinished work items older than " + before.toString());
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: think about lock, how new VM start when we change rows
|
||||
@DB
|
||||
public void work() {
|
||||
if (s_logger.isTraceEnabled()) {
|
||||
s_logger.trace("Checking the database");
|
||||
}
|
||||
final OvsWorkVO work = _workDao.take(_serverId);
|
||||
if (work == null) {
|
||||
return;
|
||||
}
|
||||
Long userVmId = work.getInstanceId();
|
||||
UserVm vm = null;
|
||||
Long seqnum = null;
|
||||
s_logger.info("Ovs working on " + work.toString());
|
||||
final Transaction txn = Transaction.currentTxn();
|
||||
txn.start();
|
||||
try {
|
||||
vm = _userVMDao.acquireInLockTable(work.getInstanceId());
|
||||
if (vm == null) {
|
||||
s_logger.warn("Ovs unable to acquire lock on vm id=" + userVmId);
|
||||
return ;
|
||||
}
|
||||
|
||||
String vlans = getVlanMapping(vm.getAccountId());
|
||||
Long agentId = null;
|
||||
VmFlowLogVO log = _flowLogDao.findByVmId(userVmId);
|
||||
if (log == null) {
|
||||
s_logger.warn("Ovs cannot find log record for vm id=" + userVmId);
|
||||
return;
|
||||
}
|
||||
seqnum = log.getLogsequence();
|
||||
|
||||
if (vm != null && vm.getState() == State.Running) {
|
||||
agentId = vm.getHostId();
|
||||
if (agentId != null ) {
|
||||
//TODO: set flow here
|
||||
OvsSetTagAndFlowCommand cmd = new OvsSetTagAndFlowCommand(vm.getName(),vlans);
|
||||
Commands cmds = new Commands(cmd);
|
||||
try {
|
||||
//_agentMgr.send(agentId, cmds, _answerListener);
|
||||
_agentMgr.send(agentId, cmds, null);
|
||||
//TODO: clean dirty in answerListener
|
||||
} catch (AgentUnavailableException e) {
|
||||
s_logger.debug("Unable to send updates for vm: " + userVmId + "(agentid=" + agentId + ")");
|
||||
_workDao.updateStep(work.getInstanceId(), seqnum, Step.Done);
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (vm != null) {
|
||||
_userVMDao.releaseFromLockTable(userVmId);
|
||||
_workDao.updateStep(work.getId(), Step.Done);
|
||||
}
|
||||
txn.commit();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
//TODO: think about lock
|
||||
@Override
|
||||
@DB
|
||||
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);
|
||||
VlanMappingVO currVlan = _vlanMappingDao.findByAccountIdAndHostId(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();
|
||||
if (currVlan != null) {
|
||||
vlan = currVlan.getVlan();
|
||||
currVlan.ref();
|
||||
_vlanMappingDao.update(currVlan.getId(), currVlan);
|
||||
s_logger.debug("Already has an Vlan " + vlan + " on host " + hostId
|
||||
+ " for account " + accountId + ", use it!");
|
||||
+ " for account " + accountId + ", use it, reference count is " + currVlan.getRef());
|
||||
txn.commit();
|
||||
return vlan;
|
||||
}
|
||||
|
||||
mappings = _vlanMappingDao.listByHostId(hostId);
|
||||
List<VlanMappingVO>mappings = _vlanMappingDao.listByHostId(hostId);
|
||||
if (mappings.size() > 0) {
|
||||
ArrayList<Long> vlans = new ArrayList<Long>();
|
||||
for (VlanMappingVO vo : mappings) {
|
||||
@ -129,8 +269,9 @@ public class OvsNetworkManagerImpl implements OvsNetworkManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
@DB
|
||||
public String getVlanMapping(long accountId) {
|
||||
assert _isEnabled : "Who call me ??? while OvsNetwokr is not enabled!!!";
|
||||
assert _isEnabled : "Who call me ??? while OvsNetwork is not enabled!!!";
|
||||
final Transaction txn = Transaction.currentTxn();
|
||||
txn.start();
|
||||
|
||||
@ -151,22 +292,21 @@ public class OvsNetworkManagerImpl implements OvsNetworkManager {
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void CheckAndCreateTunnel(Commands cmds, VirtualMachineProfile<UserVmVO> profile,
|
||||
protected void CheckAndCreateTunnel(Commands cmds, VMInstanceVO instance,
|
||||
DeployDestination dest) {
|
||||
if (!_isEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
UserVmVO userVm = profile.getVirtualMachine();
|
||||
if (userVm.getType() != VirtualMachine.Type.User) {
|
||||
if (instance.getType() != VirtualMachine.Type.User
|
||||
&& instance.getType() != VirtualMachine.Type.DomainRouter) {
|
||||
return;
|
||||
}
|
||||
|
||||
long hostId = dest.getHost().getId();
|
||||
long accountId = userVm.getAccountId();
|
||||
long accountId = instance.getAccountId();
|
||||
List<UserVmVO> vms = _userVmDao.listByAccountIdAndHostId(accountId, hostId);
|
||||
if (vms.size() != 0) {
|
||||
if (vms.size() > 1 || (vms.size() == 1 && vms.get(0).getId() != instance.getId())) {
|
||||
s_logger.debug("Already has GRE tunnel for account " + accountId
|
||||
+ " for host " + hostId);
|
||||
return;
|
||||
@ -204,21 +344,19 @@ public class OvsNetworkManagerImpl implements OvsNetworkManager {
|
||||
return sub;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyDefaultFlow(Commands cmds,
|
||||
VirtualMachineProfile<UserVmVO> profile, DeployDestination dest) {
|
||||
protected void applyDefaultFlow(Commands cmds,
|
||||
VMInstanceVO instance, DeployDestination dest) {
|
||||
if (!_isEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
UserVmVO userVm = profile.getVirtualMachine();
|
||||
VirtualMachine.Type vmType = userVm.getType();
|
||||
VirtualMachine.Type vmType = instance.getType();
|
||||
if (vmType != VirtualMachine.Type.User
|
||||
&& vmType != VirtualMachine.Type.DomainRouter) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<NicVO> nics = _nicDao.listBy(userVm.getId());
|
||||
List<NicVO> nics = _nicDao.listBy(instance.getId());
|
||||
if (nics.size() == 0)
|
||||
return;
|
||||
|
||||
@ -237,7 +375,7 @@ public class OvsNetworkManagerImpl implements OvsNetworkManager {
|
||||
|
||||
assert nic!=null : "Why there is no guest network nic???";
|
||||
String vlans = parseVlanAndMapping(nic.getBroadcastUri().toASCIIString());
|
||||
cmds.addCommand(new OvsSetTagAndFlowCommand(userVm.getName(), vlans));
|
||||
cmds.addCommand(new OvsSetTagAndFlowCommand(instance.getName(), vlans));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -267,12 +405,102 @@ public class OvsNetworkManagerImpl implements OvsNetworkManager {
|
||||
}
|
||||
}
|
||||
|
||||
protected void handleVmStarted(UserVm userVm) {
|
||||
@DB
|
||||
public void scheduleFlowUpdateToHosts(Set<Long> affectedVms, boolean updateSeqno, Long delayMs) {
|
||||
if (!_isEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (affectedVms == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (delayMs == null)
|
||||
delayMs = new Long(100l);
|
||||
|
||||
for (Long vmId: affectedVms) {
|
||||
Transaction txn = Transaction.currentTxn();
|
||||
txn.start();
|
||||
VmFlowLogVO log = null;
|
||||
OvsWorkVO work = null;
|
||||
UserVm vm = null;
|
||||
try {
|
||||
vm = _userVMDao.acquireInLockTable(vmId);
|
||||
if (vm == null) {
|
||||
s_logger.warn("Ovs failed to acquire lock on vm id " + vmId);
|
||||
continue;
|
||||
}
|
||||
log = _flowLogDao.findByVmId(vmId);
|
||||
if (log == null) {
|
||||
log = new VmFlowLogVO(vmId);
|
||||
log = _flowLogDao.persist(log);
|
||||
}
|
||||
|
||||
if (log != null && updateSeqno){
|
||||
log.incrLogsequence();
|
||||
_flowLogDao.update(log.getId(), log);
|
||||
}
|
||||
|
||||
work = _workDao.findByVmIdStep(vmId, Step.Scheduled);
|
||||
if (work == null) {
|
||||
work = new OvsWorkVO(vmId, null, null, OvsWorkVO.Step.Scheduled, null);
|
||||
work = _workDao.persist(work);
|
||||
}
|
||||
|
||||
work.setLogsequenceNumber(log.getLogsequence());
|
||||
_workDao.update(work.getId(), work);
|
||||
} finally {
|
||||
if (vm != null) {
|
||||
_userVMDao.releaseFromLockTable(vmId);
|
||||
}
|
||||
}
|
||||
txn.commit();
|
||||
|
||||
_executorPool.schedule(new WorkerThread(), delayMs, TimeUnit.MILLISECONDS);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
protected Set<Long> getAffectedVms(UserVm userVm) {
|
||||
long accountId = userVm.getAccountId();
|
||||
if (!_vlanMappingDirtyDao.isDirty(accountId)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Set<Long> affectedVms = new HashSet<Long>();
|
||||
List<UserVmVO> vms = _userVmDao.listByAccountId(accountId);
|
||||
for (UserVmVO vm : vms) {
|
||||
affectedVms.add(new Long(vm.getId()));
|
||||
}
|
||||
return affectedVms;
|
||||
}
|
||||
|
||||
protected void handleVmStateChange(UserVm userVm) {
|
||||
Set<Long> affectedVms = getAffectedVms(userVm);
|
||||
scheduleFlowUpdateToHosts(affectedVms, true, null);
|
||||
}
|
||||
|
||||
protected void handleVmStopped(UserVm userVm) {
|
||||
scheduleFlowUpdateToHosts(affectedVms, true, null);
|
||||
//TODO: think about lock
|
||||
protected void checkAndRemove(UserVm userVm) {
|
||||
long accountId = userVm.getAccountId();
|
||||
long hostId = userVm.getHostId();
|
||||
|
||||
final Transaction txn = Transaction.currentTxn();
|
||||
txn.start();
|
||||
VlanMappingVO vo = _vlanMappingDao.findByAccountIdAndHostId(accountId, hostId);
|
||||
if (vo.unref() == 0) {
|
||||
_vlanMappingDao.remove(vo.getId());
|
||||
s_logger.debug(userVm.getName() + " is the last one on host "
|
||||
+ hostId + " for account " + accountId
|
||||
+ ", remove vlan in ovs_host_vlan_alloc");
|
||||
_vlanMappingDirtyDao.markDirty(accountId);
|
||||
} else {
|
||||
_vlanMappingDao.update(vo.getId(), vo);
|
||||
s_logger.debug(userVm.getName()
|
||||
+ " reduces reference count of (account,host) = ("
|
||||
+ accountId + "," + hostId + ") to " + vo.getRef());
|
||||
}
|
||||
txn.commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -291,14 +519,42 @@ public class OvsNetworkManagerImpl implements OvsNetworkManager {
|
||||
case Unknown:
|
||||
return;
|
||||
case Running:
|
||||
handleVmStarted(userVm);
|
||||
handleVmStateChange(userVm);
|
||||
break;
|
||||
case Stopping:
|
||||
case Stopped:
|
||||
handleVmStopped(userVm);
|
||||
checkAndRemove(userVm);
|
||||
handleVmStateChange(userVm);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void UserVmCheckAndCreateTunnel(Commands cmds,
|
||||
VirtualMachineProfile<UserVmVO> profile, DeployDestination dest) {
|
||||
CheckAndCreateTunnel(cmds, (VMInstanceVO)profile.getVirtualMachine(), dest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void RouterCheckAndCreateTunnel(Commands cmds,
|
||||
VirtualMachineProfile<DomainRouterVO> profile,
|
||||
DeployDestination dest) {
|
||||
CheckAndCreateTunnel(cmds, (VMInstanceVO)profile.getVirtualMachine(), dest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyDefaultFlowToUserVm(Commands cmds,
|
||||
VirtualMachineProfile<UserVmVO> profile, DeployDestination dest) {
|
||||
applyDefaultFlow(cmds, profile.getVirtualMachine(), dest);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyDefaultFlowToRouter(Commands cmds,
|
||||
VirtualMachineProfile<DomainRouterVO> profile,
|
||||
DeployDestination dest) {
|
||||
applyDefaultFlow(cmds, profile.getVirtualMachine(), dest);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
23
server/src/com/cloud/network/ovs/dao/OvsWorkDao.java
Normal file
23
server/src/com/cloud/network/ovs/dao/OvsWorkDao.java
Normal file
@ -0,0 +1,23 @@
|
||||
package com.cloud.network.ovs.dao;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import com.cloud.network.ovs.dao.OvsWorkVO.Step;
|
||||
import com.cloud.utils.db.GenericDao;
|
||||
|
||||
public interface OvsWorkDao extends GenericDao<OvsWorkVO, Long> {
|
||||
OvsWorkVO findByVmId(long vmId, boolean taken);
|
||||
|
||||
OvsWorkVO findByVmIdStep(long vmId, Step step);
|
||||
|
||||
OvsWorkVO take(long serverId);
|
||||
|
||||
void updateStep(Long vmId, Long logSequenceNumber, Step done);
|
||||
|
||||
void updateStep(Long workId, Step done);
|
||||
|
||||
int deleteFinishedWork(Date timeBefore);
|
||||
|
||||
List<OvsWorkVO> findUnfinishedWork(Date timeBefore);
|
||||
}
|
||||
187
server/src/com/cloud/network/ovs/dao/OvsWorkDaoImpl.java
Normal file
187
server/src/com/cloud/network/ovs/dao/OvsWorkDaoImpl.java
Normal file
@ -0,0 +1,187 @@
|
||||
package com.cloud.network.ovs.dao;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import javax.ejb.Local;
|
||||
import com.cloud.ha.HaWorkVO;
|
||||
import com.cloud.network.ovs.dao.OvsWorkVO.Step;
|
||||
import com.cloud.utils.db.Filter;
|
||||
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 com.cloud.utils.db.Transaction;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
|
||||
@Local(value={OvsWorkDao.class})
|
||||
public class OvsWorkDaoImpl extends GenericDaoBase<OvsWorkVO, Long> implements
|
||||
OvsWorkDao {
|
||||
private SearchBuilder<OvsWorkVO> VmIdTakenSearch;
|
||||
private SearchBuilder<OvsWorkVO> VmIdSeqNumSearch;
|
||||
private SearchBuilder<OvsWorkVO> VmIdUnTakenSearch;
|
||||
private SearchBuilder<OvsWorkVO> UntakenWorkSearch;
|
||||
private SearchBuilder<OvsWorkVO> VmIdStepSearch;
|
||||
private SearchBuilder<OvsWorkVO> CleanupSearch;
|
||||
|
||||
|
||||
protected OvsWorkDaoImpl() {
|
||||
VmIdTakenSearch = createSearchBuilder();
|
||||
VmIdTakenSearch.and("vmId", VmIdTakenSearch.entity().getInstanceId(), SearchCriteria.Op.EQ);
|
||||
VmIdTakenSearch.and("taken", VmIdTakenSearch.entity().getDateTaken(), SearchCriteria.Op.NNULL);
|
||||
|
||||
VmIdTakenSearch.done();
|
||||
|
||||
VmIdUnTakenSearch = createSearchBuilder();
|
||||
VmIdUnTakenSearch.and("vmId", VmIdUnTakenSearch.entity().getInstanceId(), SearchCriteria.Op.EQ);
|
||||
VmIdUnTakenSearch.and("taken", VmIdUnTakenSearch.entity().getDateTaken(), SearchCriteria.Op.NULL);
|
||||
|
||||
VmIdUnTakenSearch.done();
|
||||
|
||||
UntakenWorkSearch = createSearchBuilder();
|
||||
UntakenWorkSearch.and("server", UntakenWorkSearch.entity().getServerId(), SearchCriteria.Op.NULL);
|
||||
UntakenWorkSearch.and("taken", UntakenWorkSearch.entity().getDateTaken(), SearchCriteria.Op.NULL);
|
||||
UntakenWorkSearch.and("step", UntakenWorkSearch.entity().getStep(), SearchCriteria.Op.EQ);
|
||||
|
||||
UntakenWorkSearch.done();
|
||||
|
||||
VmIdSeqNumSearch = createSearchBuilder();
|
||||
VmIdSeqNumSearch.and("vmId", VmIdSeqNumSearch.entity().getInstanceId(), SearchCriteria.Op.EQ);
|
||||
VmIdSeqNumSearch.and("seqno", VmIdSeqNumSearch.entity().getLogsequenceNumber(), SearchCriteria.Op.EQ);
|
||||
|
||||
VmIdSeqNumSearch.done();
|
||||
|
||||
VmIdStepSearch = createSearchBuilder();
|
||||
VmIdStepSearch.and("vmId", VmIdStepSearch.entity().getInstanceId(), SearchCriteria.Op.EQ);
|
||||
VmIdStepSearch.and("step", VmIdStepSearch.entity().getStep(), SearchCriteria.Op.EQ);
|
||||
|
||||
VmIdStepSearch.done();
|
||||
|
||||
CleanupSearch = createSearchBuilder();
|
||||
CleanupSearch.and("taken", CleanupSearch.entity().getDateTaken(), Op.LTEQ);
|
||||
CleanupSearch.and("step", CleanupSearch.entity().getStep(), SearchCriteria.Op.IN);
|
||||
|
||||
CleanupSearch.done();
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public OvsWorkVO findByVmId(long vmId, boolean taken) {
|
||||
SearchCriteria<OvsWorkVO> sc = taken?VmIdTakenSearch.create():VmIdUnTakenSearch.create();
|
||||
sc.setParameters("vmId", vmId);
|
||||
return findOneIncludingRemovedBy(sc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OvsWorkVO take(long serverId) {
|
||||
final Transaction txn = Transaction.currentTxn();
|
||||
try {
|
||||
final SearchCriteria<OvsWorkVO> sc = UntakenWorkSearch.create();
|
||||
sc.setParameters("step", Step.Scheduled);
|
||||
|
||||
final Filter filter = new Filter(OvsWorkVO.class, null, true, 0l, 1l);//FIXME: order desc by update time?
|
||||
|
||||
txn.start();
|
||||
final List<OvsWorkVO> vos = lockRows(sc, filter, true);
|
||||
if (vos.size() == 0) {
|
||||
txn.commit();
|
||||
return null;
|
||||
}
|
||||
OvsWorkVO work = null;
|
||||
for (OvsWorkVO w: vos) {
|
||||
//ensure that there is no job in Processing state for the same VM
|
||||
if ( findByVmIdStep(w.getInstanceId(), Step.Processing) == null) {
|
||||
work = w;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (work == null) {
|
||||
txn.commit();
|
||||
return null;
|
||||
}
|
||||
work.setServerId(serverId);
|
||||
work.setDateTaken(new Date());
|
||||
work.setStep(OvsWorkVO.Step.Processing);
|
||||
|
||||
update(work.getId(), work);
|
||||
|
||||
txn.commit();
|
||||
|
||||
return work;
|
||||
|
||||
} catch (final Throwable e) {
|
||||
throw new CloudRuntimeException("Unable to execute take", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateStep(Long vmId, Long logSequenceNumber, Step step) {
|
||||
final Transaction txn = Transaction.currentTxn();
|
||||
txn.start();
|
||||
SearchCriteria<OvsWorkVO> sc = VmIdSeqNumSearch.create();
|
||||
sc.setParameters("vmId", vmId);
|
||||
sc.setParameters("seqno", logSequenceNumber);
|
||||
|
||||
final Filter filter = new Filter(HaWorkVO.class, null, true, 0l, 1l);
|
||||
|
||||
final List<OvsWorkVO> vos = lockRows(sc, filter, true);
|
||||
if (vos.size() == 0) {
|
||||
txn.commit();
|
||||
return;
|
||||
}
|
||||
OvsWorkVO work = vos.get(0);
|
||||
work.setStep(step);
|
||||
update(work.getId(), work);
|
||||
|
||||
txn.commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public OvsWorkVO findByVmIdStep(long vmId, Step step) {
|
||||
SearchCriteria<OvsWorkVO> sc = VmIdStepSearch.create();
|
||||
sc.setParameters("vmId", vmId);
|
||||
sc.setParameters("step", step);
|
||||
return findOneIncludingRemovedBy(sc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateStep(Long workId, Step step) {
|
||||
final Transaction txn = Transaction.currentTxn();
|
||||
txn.start();
|
||||
|
||||
OvsWorkVO work = lockRow(workId, true);
|
||||
if (work == null) {
|
||||
txn.commit();
|
||||
return;
|
||||
}
|
||||
work.setStep(step);
|
||||
update(work.getId(), work);
|
||||
|
||||
txn.commit();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int deleteFinishedWork(Date timeBefore) {
|
||||
final SearchCriteria<OvsWorkVO> sc = CleanupSearch.create();
|
||||
sc.setParameters("taken", timeBefore);
|
||||
sc.setParameters("step", Step.Done);
|
||||
|
||||
return expunge(sc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<OvsWorkVO> findUnfinishedWork(Date timeBefore) {
|
||||
final SearchCriteria<OvsWorkVO> sc = CleanupSearch.create();
|
||||
sc.setParameters("taken", timeBefore);
|
||||
sc.setParameters("step", Step.Processing);
|
||||
|
||||
List<OvsWorkVO> result = listIncludingRemovedBy(sc);
|
||||
|
||||
OvsWorkVO work = createForUpdate();
|
||||
work.setStep(Step.Error);
|
||||
update(work, sc);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
123
server/src/com/cloud/network/ovs/dao/OvsWorkVO.java
Normal file
123
server/src/com/cloud/network/ovs/dao/OvsWorkVO.java
Normal file
@ -0,0 +1,123 @@
|
||||
package com.cloud.network.ovs.dao;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EnumType;
|
||||
import javax.persistence.Enumerated;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
import com.cloud.utils.db.GenericDao;
|
||||
|
||||
|
||||
@Entity
|
||||
@Table(name="ovs_work")
|
||||
public class OvsWorkVO {
|
||||
public enum Step {
|
||||
Scheduled,
|
||||
Processing,
|
||||
Done,
|
||||
Error
|
||||
}
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy=GenerationType.IDENTITY)
|
||||
@Column(name="id")
|
||||
private Long id;
|
||||
|
||||
@Column(name="instance_id", updatable=false, nullable=false)
|
||||
private Long instanceId; // vm_instance id
|
||||
|
||||
|
||||
@Column(name="mgmt_server_id", nullable=true)
|
||||
private Long serverId;
|
||||
|
||||
@Column(name=GenericDao.CREATED_COLUMN)
|
||||
private Date created;
|
||||
|
||||
|
||||
@Column(name="step", nullable = false)
|
||||
@Enumerated(value=EnumType.STRING)
|
||||
private Step step;
|
||||
|
||||
@Column(name="taken", nullable=true)
|
||||
@Temporal(value=TemporalType.TIMESTAMP)
|
||||
private Date dateTaken;
|
||||
|
||||
@Column(name="seq_no", nullable=true)
|
||||
private Long logsequenceNumber = null;
|
||||
|
||||
|
||||
protected OvsWorkVO() {
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public Long getInstanceId() {
|
||||
return instanceId;
|
||||
}
|
||||
|
||||
|
||||
public Long getServerId() {
|
||||
return serverId;
|
||||
}
|
||||
|
||||
|
||||
public void setServerId(final Long serverId) {
|
||||
this.serverId = serverId;
|
||||
}
|
||||
|
||||
public Date getCreated() {
|
||||
return created;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public OvsWorkVO(Long instanceId, Long serverId, Date created,
|
||||
Step step, Date dateTaken) {
|
||||
super();
|
||||
this.instanceId = instanceId;
|
||||
this.serverId = serverId;
|
||||
this.created = created;
|
||||
this.step = step;
|
||||
this.dateTaken = dateTaken;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder("[Ovs-Work:id=").append(id).append(":vm=").append(instanceId).append("]").toString();
|
||||
}
|
||||
|
||||
public Date getDateTaken() {
|
||||
return dateTaken;
|
||||
}
|
||||
|
||||
public void setStep(Step step) {
|
||||
this.step = step;
|
||||
}
|
||||
|
||||
public Step getStep() {
|
||||
return step;
|
||||
}
|
||||
|
||||
public void setDateTaken(Date date) {
|
||||
dateTaken = date;
|
||||
}
|
||||
|
||||
public Long getLogsequenceNumber() {
|
||||
return logsequenceNumber;
|
||||
}
|
||||
|
||||
public void setLogsequenceNumber(Long logsequenceNumber) {
|
||||
this.logsequenceNumber = logsequenceNumber;
|
||||
}
|
||||
|
||||
}
|
||||
@ -8,4 +8,5 @@ public interface VlanMappingDao extends GenericDao<VlanMappingVO, Long> {
|
||||
List<VlanMappingVO> listByAccountIdAndHostId(long accountId, long hostId);
|
||||
List<VlanMappingVO> listByHostId(long hostId);
|
||||
List<VlanMappingVO> listByAccountId(long accountId);
|
||||
VlanMappingVO findByAccountIdAndHostId(long accountId, long hostId);
|
||||
}
|
||||
|
||||
@ -47,4 +47,11 @@ public class VlanMappingDaoImpl extends GenericDaoBase<VlanMappingVO, Long>
|
||||
|
||||
return listBy(sc, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VlanMappingVO findByAccountIdAndHostId(long accountId, long hostId) {
|
||||
SearchCriteria<VlanMappingVO> sc = AllFieldsSearch.create();
|
||||
sc.setParameters("account_id", accountId);
|
||||
return findOneBy(sc);
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,11 +23,15 @@ public class VlanMappingVO {
|
||||
|
||||
@Column(name = "vlan")
|
||||
private long vlan;
|
||||
|
||||
@Column(name = "ref")
|
||||
private int ref;
|
||||
|
||||
public VlanMappingVO(long accountId, long hostId, long vlan) {
|
||||
this.hostId = hostId;
|
||||
this.accountId = accountId;
|
||||
this.vlan = vlan;
|
||||
this.ref = 1;
|
||||
}
|
||||
|
||||
public VlanMappingVO() {
|
||||
@ -49,4 +53,17 @@ public class VlanMappingVO {
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public int getRef() {
|
||||
return ref;
|
||||
}
|
||||
|
||||
public void ref() {
|
||||
ref++;
|
||||
}
|
||||
|
||||
public int unref() {
|
||||
ref--;
|
||||
return ref;
|
||||
}
|
||||
}
|
||||
|
||||
7
server/src/com/cloud/network/ovs/dao/VmFlowLogDao.java
Normal file
7
server/src/com/cloud/network/ovs/dao/VmFlowLogDao.java
Normal file
@ -0,0 +1,7 @@
|
||||
package com.cloud.network.ovs.dao;
|
||||
|
||||
import com.cloud.utils.db.GenericDao;
|
||||
|
||||
public interface VmFlowLogDao extends GenericDao<VmFlowLogVO, Long> {
|
||||
VmFlowLogVO findByVmId(long vmId);
|
||||
}
|
||||
27
server/src/com/cloud/network/ovs/dao/VmFlowLogDaoImpl.java
Normal file
27
server/src/com/cloud/network/ovs/dao/VmFlowLogDaoImpl.java
Normal file
@ -0,0 +1,27 @@
|
||||
package com.cloud.network.ovs.dao;
|
||||
|
||||
import com.cloud.utils.db.GenericDaoBase;
|
||||
import com.cloud.utils.db.SearchBuilder;
|
||||
import com.cloud.utils.db.SearchCriteria;
|
||||
import javax.ejb.Local;
|
||||
|
||||
@Local(value={VmFlowLogDao.class})
|
||||
public class VmFlowLogDaoImpl extends GenericDaoBase<VmFlowLogVO, Long>
|
||||
implements VmFlowLogDao {
|
||||
private SearchBuilder<VmFlowLogVO> VmIdSearch;
|
||||
|
||||
@Override
|
||||
public VmFlowLogVO findByVmId(long vmId) {
|
||||
SearchCriteria<VmFlowLogVO> sc = VmIdSearch.create();
|
||||
sc.setParameters("vmId", vmId);
|
||||
return findOneIncludingRemovedBy(sc);
|
||||
}
|
||||
|
||||
protected VmFlowLogDaoImpl() {
|
||||
VmIdSearch = createSearchBuilder();
|
||||
VmIdSearch.and("vmId", VmIdSearch.entity().getInstanceId(),
|
||||
SearchCriteria.Op.EQ);
|
||||
VmIdSearch.done();
|
||||
|
||||
}
|
||||
}
|
||||
59
server/src/com/cloud/network/ovs/dao/VmFlowLogVO.java
Normal file
59
server/src/com/cloud/network/ovs/dao/VmFlowLogVO.java
Normal file
@ -0,0 +1,59 @@
|
||||
package com.cloud.network.ovs.dao;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import com.cloud.utils.db.GenericDao;
|
||||
|
||||
@Entity
|
||||
@Table(name="ovs_vm_flow_log")
|
||||
public class VmFlowLogVO {
|
||||
@Id
|
||||
@GeneratedValue(strategy=GenerationType.IDENTITY)
|
||||
@Column(name="id")
|
||||
private Long id;
|
||||
|
||||
@Column(name="instance_id", updatable=false, nullable=false)
|
||||
private Long instanceId; // vm_instance id
|
||||
|
||||
@Column(name=GenericDao.CREATED_COLUMN)
|
||||
private Date created;
|
||||
|
||||
@Column(name="logsequence")
|
||||
long logsequence;
|
||||
|
||||
protected VmFlowLogVO() {
|
||||
|
||||
}
|
||||
|
||||
public VmFlowLogVO(Long instanceId) {
|
||||
super();
|
||||
this.instanceId = instanceId;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public Long getInstanceId() {
|
||||
return instanceId;
|
||||
}
|
||||
|
||||
public Date getCreated() {
|
||||
return created;
|
||||
}
|
||||
|
||||
public long getLogsequence() {
|
||||
return logsequence;
|
||||
}
|
||||
|
||||
public void incrLogsequence() {
|
||||
logsequence++;
|
||||
}
|
||||
}
|
||||
@ -129,6 +129,7 @@ import com.cloud.network.dao.VpnUserDao;
|
||||
import com.cloud.network.lb.LoadBalancingRule;
|
||||
import com.cloud.network.lb.LoadBalancingRule.LbDestination;
|
||||
import com.cloud.network.lb.LoadBalancingRulesManager;
|
||||
import com.cloud.network.ovs.OvsNetworkManager;
|
||||
import com.cloud.network.router.VirtualRouter.Role;
|
||||
import com.cloud.network.rules.FirewallRule;
|
||||
import com.cloud.network.rules.PortForwardingRule;
|
||||
@ -294,6 +295,7 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian
|
||||
RemoteAccessVpnDao _vpnDao;
|
||||
@Inject
|
||||
VMInstanceDao _instanceDao;
|
||||
OvsNetworkManager _ovsNetworkMgr;
|
||||
|
||||
long _routerTemplateId = -1;
|
||||
int _routerRamSize;
|
||||
@ -1250,6 +1252,9 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian
|
||||
@Override
|
||||
public boolean finalizeDeployment(Commands cmds, VirtualMachineProfile<DomainRouterVO> profile, DeployDestination dest, ReservationContext context) throws ResourceUnavailableException{
|
||||
NicProfile controlNic = (NicProfile) profile.getParameter("control.nic");
|
||||
_ovsNetworkMgr.RouterCheckAndCreateTunnel(cmds, profile, dest);
|
||||
_ovsNetworkMgr.applyDefaultFlowToRouter(cmds, profile, dest);
|
||||
|
||||
cmds.addCommand("checkSsh", new CheckSshCommand(profile.getInstanceName(), controlNic.getIp4Address(), 3922, 5, 20));
|
||||
|
||||
DomainRouterVO router = profile.getVirtualMachine();
|
||||
|
||||
@ -1133,7 +1133,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
|
||||
public void completeStartCommand(UserVmVO vm) {
|
||||
_itMgr.stateTransitTo(vm, VirtualMachine.Event.AgentReportRunning, vm.getHostId());
|
||||
_networkGroupMgr.handleVmStateTransition(vm, State.Running);
|
||||
|
||||
_ovsNetworkMgr.handleVmStateTransition(vm, State.Running);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -1167,6 +1167,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
|
||||
|
||||
txn.commit();
|
||||
_networkGroupMgr.handleVmStateTransition(vm, State.Stopped);
|
||||
_ovsNetworkMgr.handleVmStateTransition(vm, State.Stopped);
|
||||
} catch (Throwable th) {
|
||||
s_logger.error("Error during stop: ", th);
|
||||
throw new CloudRuntimeException("Error during stop: ", th);
|
||||
@ -2343,7 +2344,10 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
|
||||
|
||||
try {
|
||||
vm = _itMgr.start(vm, null, caller, owner, cmd.getHypervisor());
|
||||
} finally {
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
finally {
|
||||
updateVmStateForFailedVmCreation(vm.getId());
|
||||
}
|
||||
vm.setPassword(password);
|
||||
@ -2397,7 +2401,8 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
|
||||
}
|
||||
_vmDao.update(userVm.getId(), userVm);
|
||||
|
||||
_ovsNetworkMgr.CheckAndCreateTunnel(cmds, profile, dest);
|
||||
_ovsNetworkMgr.UserVmCheckAndCreateTunnel(cmds, profile, dest);
|
||||
_ovsNetworkMgr.applyDefaultFlowToUserVm(cmds, profile, dest);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -1328,6 +1328,7 @@ CREATE TABLE `cloud`.`ovs_host_vlan_alloc`(
|
||||
`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',
|
||||
`ref` int unsigned NOT NULL DEFAULT 0 COMMENT 'reference count',
|
||||
PRIMARY KEY(`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
@ -1338,4 +1339,23 @@ CREATE TABLE `cloud`.`ovs_vlan_mapping_dirty`(
|
||||
PRIMARY KEY(`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
CREATE TABLE `cloud`.`ovs_vm_flow_log` (
|
||||
`id` bigint unsigned UNIQUE NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
`instance_id` bigint unsigned NOT NULL COMMENT 'vm instance that needs flows to be synced.',
|
||||
`created` datetime NOT NULL COMMENT 'time the entry was requested',
|
||||
`logsequence` bigint unsigned COMMENT 'seq number to be sent to agent, uniquely identifies flow update',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
CREATE TABLE `cloud`.`ovs_work` (
|
||||
`id` bigint unsigned UNIQUE NOT NULL AUTO_INCREMENT COMMENT 'id',
|
||||
`instance_id` bigint unsigned NOT NULL COMMENT 'vm instance that needs rules to be synced.',
|
||||
`mgmt_server_id` bigint unsigned COMMENT 'management server that has taken up the work of doing rule sync',
|
||||
`created` datetime NOT NULL COMMENT 'time the entry was requested',
|
||||
`taken` datetime COMMENT 'time it was taken by the management server',
|
||||
`step` varchar(32) NOT NULL COMMENT 'Step in the work',
|
||||
`seq_no` bigint unsigned COMMENT 'seq number to be sent to agent, uniquely identifies ruleset update',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
SET foreign_key_checks = 1;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user