bug 7722: open vswitch - works at VM start time, need fullsync() and flow clean in next

This commit is contained in:
Frank 2011-01-05 18:05:44 -08:00
parent 5c01c42ba7
commit c94b6acadf
21 changed files with 890 additions and 83 deletions

View File

@ -3820,34 +3820,22 @@ public abstract class CitrixResourceBase implements ServerResource {
return Boolean.valueOf(callHostPlugin(conn, "vmops", "can_bridge_firewall", "host_uuid", _host.uuid)); 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) { private Answer execute(OvsSetTagAndFlowCommand cmd) {
Connection conn = getConnection(); Connection conn = getConnection();
try { 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(); String nwName = Networks.BroadcastScheme.VSwitch.toString();
Network nw = getNetworkByName(conn, nwName); Network nw = getNetworkByName(conn, nwName);
assert nw!= null : "Why there is no vswith network ???"; assert nw!= null : "Why there is no vswith network ???";
String bridge = nw.getBridge(conn); String bridge = nw.getBridge(conn);
/*If VM is domainRouter, this will try to set flow and tag on its /*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 * plugin side
*/ */
for (VIF vif : vifs) { String result = callHostPlugin(conn, "vmops", "ovs_set_tag_and_flow", "bridge", bridge,
String vifName = "vif" + domId + vif.getDevice(conn); "vmName", cmd.getVmName(), "vlans", cmd.getVlans());
String result = callHostPlugin(conn, "vmops", "vlanRemapUtils", "op", "createFlow", "bridge", s_logger.debug("set flow for " + cmd.getVmName() + " " + result);
bridge, "vifName", vifName, "mac",
vif.getMAC(conn), "remap", cmd.getVlans(),
"ip", "placeholder now");
s_logger.debug("set flow for " + vifName + " on " + cmd.getVmName() + " " + result);
}
/*
if (result.equalsIgnoreCase("SUCCESS")) { if (result.equalsIgnoreCase("SUCCESS")) {
return new Answer(cmd, true, "Set flow for " + cmd.getVmName() return new Answer(cmd, true, "Set flow for " + cmd.getVmName()
+ " success, vlans:" + cmd.getVlans()); + " success, vlans:" + cmd.getVlans());
@ -3855,9 +3843,6 @@ public abstract class CitrixResourceBase implements ServerResource {
return new Answer(cmd, false, "Set flow for " + cmd.getVmName() return new Answer(cmd, false, "Set flow for " + cmd.getVmName()
+ " failed, vlans:" + cmd.getVlans()); + " failed, vlans:" + cmd.getVlans());
} }
*/
return new Answer(cmd, true, "Set flow for " + cmd.getVmName()
+ " success, vlans:" + cmd.getVlans());
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }

View File

@ -338,7 +338,7 @@ def formatARPFlow(bridge, inPort, vlan, ports):
actions=strip_vlan,%s" % (inPort, vlan, outputs) actions=strip_vlan,%s" % (inPort, vlan, outputs)
return flow return flow
def createFlow (bridge, vifName, mac, ip, vlan, remap): def createFlow (bridge, vifName, mac, remap):
inport = getGreOfPorts(bridge) inport = getGreOfPorts(bridge)
if len(inport) == 0: if len(inport) == 0:
log("WARNING: no inport found") log("WARNING: no inport found")
@ -357,7 +357,7 @@ def createFlow (bridge, vifName, mac, ip, vlan, remap):
delFlow(mac) delFlow(mac)
#set remap here, remap has format e.g. [1,22,200,13,16] #set remap here, remap has format e.g. [1,22,200,13,16]
remap = strip(remap, "both") remap = strip(remap)
log("") log("")
log("Create flow for remap") log("Create flow for remap")
noneGreOfPorts = getNoneGreOfPort(bridge) 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") log("WARNING: no none GRE ofports found, no ARP flow will be created")
isARP = False isARP = False
for j in remap.split(","): for j in remap.split("/"):
delARPFlow(j) delARPFlow(j)
for i in inport: for i in inport:
flow = formatFlow(i, j, mac, output) flow = formatFlow(i, j, mac, output)
@ -383,8 +383,19 @@ def createFlow (bridge, vifName, mac, ip, vlan, remap):
return 0 return 0
######################## End Flow creation utils ########################## ######################## End Flow creation utils ##########################
def setTag(vifName, vlan): def setTag(bridge, vifName, vlan):
log("") # 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") log("Set tag")
setTagCmd = [vsctlPath, "set port", vifName, "tag=%s"%vlan] setTagCmd = [vsctlPath, "set port", vifName, "tag=%s"%vlan]
doCmd (setTagCmd) doCmd (setTagCmd)
@ -398,20 +409,22 @@ def doCreateGRE(bridge, remoteIP, key):
log("WARNING: create GRE tunnel on %s for %s success" % (bridge, \ log("WARNING: create GRE tunnel on %s for %s success" % (bridge, \
remoteIP)) remoteIP))
def doCreateFlow (bridge, vifName, mac, ip, vlan, remap): def doCreateFlow (bridge, vifName, mac, remap):
setTag (vifName, vlan) if createFlow(bridge, vifName, mac, remap) < 0:
if createFlow(bridge, vifName, mac, ip, vlan, remap) < 0: log ("Create flow failed(bridge=%s, vifName=%s, mac=%s,\
log ("Create flow failed(bridge=%s, vifName=%s, mac=%s, ip=%s, vlan=%s,\ remap=%s" % (bridge, vifName, mac, remap))
remap=%s" % (bridge, vifName, mac, ip, vlan, remap))
else: else:
log ("Create flow success(bridge=%s, vifName=%s, mac=%s, ip=%s, vlan=%s,\ log ("Create flow success(bridge=%s, vifName=%s, mac=%s,\
remap=%s" % (bridge, vifName, mac, ip, vlan, remap)) remap=%s" % (bridge, vifName, mac, remap))
def doSetTag (bridge, vifName, tag):
setTag(bridge, vifName, tag)
def doDeleteFlow(bridge, vifName, mac, remap): def doDeleteFlow(bridge, vifName, mac, remap):
delFlow(mac) delFlow(mac)
log("Delete flows for %s" % mac) log("Delete flows for %s" % mac)
remap = strip(remap, "both") remap = strip(remap)
# remove our port from arp flow # remove our port from arp flow
inport = getGreOfPorts(bridge) inport = getGreOfPorts(bridge)
@ -423,7 +436,7 @@ def doDeleteFlow(bridge, vifName, mac, remap):
noneGreOfPorts.remove(mine) noneGreOfPorts.remove(mine)
log("Delete ARP flows for(vifname=%s, ofport=%s)" % (vifName, mine)) log("Delete ARP flows for(vifname=%s, ofport=%s)" % (vifName, mine))
for j in remap.split(","): for j in remap.split("/"):
delARPFlow(j) delARPFlow(j)
for i in inport: for i in inport:
flow = formatARPFlow(bridge, i, j, noneGreOfPorts) flow = formatARPFlow(bridge, i, j, noneGreOfPorts)
@ -457,14 +470,12 @@ if __name__ == "__main__":
key = sys.argv[4] key = sys.argv[4]
doCreateGRE(bridge, remoteIP, key) doCreateGRE(bridge, remoteIP, key)
elif op == "createFlow": elif op == "createFlow":
checkArgNum(8) checkArgNum(6)
bridge = sys.argv[2] bridge = sys.argv[2]
vifName = sys.argv[3] vifName = sys.argv[3]
mac = sys.argv[4] mac = sys.argv[4]
vlan = sys.argv[5] remap = sys.argv[5]
remap = sys.argv[6] doCreateFlow(bridge, vifName, mac, remap)
ip = sys.argv[7]
doCreateFlow(bridge, vifName, mac, ip, vlan, remap)
elif op == "deleteFlow": elif op == "deleteFlow":
checkArgNum(6) checkArgNum(6)
bridge = sys.argv[2] bridge = sys.argv[2]
@ -472,6 +483,12 @@ if __name__ == "__main__":
mac = sys.argv[4] mac = sys.argv[4]
remap = sys.argv[5] remap = sys.argv[5]
doDeleteFlow(bridge, vifName, mac, remap) 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: else:
log("WARNING: get an unkown op %s" % op) log("WARNING: get an unkown op %s" % op)
result=errors["ERROR_OP"] result=errors["ERROR_OP"]

View File

@ -144,14 +144,16 @@ def vlanRemapUtils(session, args):
cmd.insert(3, args.pop("bridge")) cmd.insert(3, args.pop("bridge"))
cmd.insert(4, args.pop("vifName")) cmd.insert(4, args.pop("vifName"))
cmd.insert(5, args.pop("mac")) cmd.insert(5, args.pop("mac"))
cmd.insert(6, args.pop("vlan"))
cmd.insert(7, args.pop("remap")) cmd.insert(7, args.pop("remap"))
cmd.insert(8, args.pop("ip"))
elif op == "deleteFlow": elif op == "deleteFlow":
cmd.insert(3, args.pop("bridge")) cmd.insert(3, args.pop("bridge"))
cmd.insert(4, args.pop("vifName")) cmd.insert(4, args.pop("vifName"))
cmd.insert(5, args.pop("mac")) cmd.insert(5, args.pop("mac"))
cmd.insert(6, args.pop("remap")) 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: try:
txt = util.pread2(cmd) 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") util.SMlog("Failed to program default ebtables OUT rules")
return 'false' 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 @echo
def default_network_rules_systemvm(session, args): def default_network_rules_systemvm(session, args):
vm_name = args.pop('vmName') vm_name = args.pop('vmName')
@ -627,9 +670,9 @@ def default_network_rules(session, args):
vifs = [vif] vifs = [vif]
try: try:
util.pread2(['ifconfig', tap]) util.pread2(['ifconfig', tap])
vifs.append(tap) vifs.append(tap)
except: except:
pass pass
delete_rules_for_vm_in_bridge_firewall_chain(vm_name) delete_rules_for_vm_in_bridge_firewall_chain(vm_name)
@ -669,7 +712,7 @@ def default_network_rules(session, args):
return 'false' return 'false'
for v in vifs: 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: if write_rule_log_for_vm(vmName, vm_id, vm_ip, domid, '_initial_', '-1') == False:
util.SMlog("Failed to log default network rules, ignoring") util.SMlog("Failed to log default network rules, ignoring")
@ -983,9 +1026,9 @@ def network_rules(session, args):
vifs = [vif] vifs = [vif]
try: try:
util.pread2(['ifconfig', tap]) util.pread2(['ifconfig', tap])
vifs.append(tap) vifs.append(tap)
except: except:
pass pass
vm_name = '-'.join(vm_name.split('-')[:-1]) vm_name = '-'.join(vm_name.split('-')[:-1])
vmchain = vm_name vmchain = vm_name
@ -1064,5 +1107,5 @@ def network_rules(session, args):
if __name__ == "__main__": 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})

View File

@ -31,3 +31,4 @@ call_firewall.sh=../../../../network/domr/,0755,/opt/xensource/bin
call_loadbalancer.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 l2tp_vpn.sh=../../../../network/domr/,0755,/opt/xensource/bin
cloud-setup-bonding.sh=..,0755,/opt/xensource/bin cloud-setup-bonding.sh=..,0755,/opt/xensource/bin
vlanRemapUtils.py=..,0755,/opt/xensource/bin

View File

@ -73,8 +73,10 @@ import com.cloud.network.dao.RemoteAccessVpnDaoImpl;
import com.cloud.network.dao.VpnUserDaoImpl; import com.cloud.network.dao.VpnUserDaoImpl;
import com.cloud.network.lb.LoadBalancingRulesManagerImpl; import com.cloud.network.lb.LoadBalancingRulesManagerImpl;
import com.cloud.network.ovs.OvsNetworkManagerImpl; 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.VlanMappingDaoImpl;
import com.cloud.network.ovs.dao.VlanMappingDirtyDaoImpl; import com.cloud.network.ovs.dao.VlanMappingDirtyDaoImpl;
import com.cloud.network.ovs.dao.VmFlowLogDaoImpl;
import com.cloud.network.router.VirtualNetworkApplianceManagerImpl; import com.cloud.network.router.VirtualNetworkApplianceManagerImpl;
import com.cloud.network.rules.RulesManagerImpl; import com.cloud.network.rules.RulesManagerImpl;
import com.cloud.network.rules.dao.PortForwardingRulesDaoImpl; import com.cloud.network.rules.dao.PortForwardingRulesDaoImpl;
@ -241,6 +243,8 @@ public class DefaultComponentLibrary implements ComponentLibrary {
addDao("ClusterDetailsDao", ClusterDetailsDaoImpl.class); addDao("ClusterDetailsDao", ClusterDetailsDaoImpl.class);
addDao("VlanMappingDao", VlanMappingDaoImpl.class); addDao("VlanMappingDao", VlanMappingDaoImpl.class);
addDao("VlanMappingDirtyDao", VlanMappingDirtyDaoImpl.class); addDao("VlanMappingDirtyDao", VlanMappingDirtyDaoImpl.class);
addDao("OvsWorkDao", OvsWorkDaoImpl.class);
addDao("VmFlowLogDao", VmFlowLogDaoImpl.class);
} }
Map<String, ComponentInfo<Manager>> _managers = new HashMap<String, ComponentInfo<Manager>>(); Map<String, ComponentInfo<Manager>> _managers = new HashMap<String, ComponentInfo<Manager>>();

View File

@ -252,6 +252,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag
} }
@Override @Override
@DB
public PublicIp assignSourceNatIpAddress(Account owner, Network network, long callerId) throws ConcurrentOperationException, InsufficientAddressCapacityException { 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?"; 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?";

View File

@ -10,6 +10,7 @@ import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.ResourceUnavailableException; import com.cloud.exception.ResourceUnavailableException;
import com.cloud.network.Network; import com.cloud.network.Network;
import com.cloud.network.Networks;
import com.cloud.network.PublicIpAddress; import com.cloud.network.PublicIpAddress;
import com.cloud.network.Network.Capability; import com.cloud.network.Network.Capability;
import com.cloud.network.Network.Provider; import com.cloud.network.Network.Provider;
@ -55,7 +56,15 @@ public class OvsElement extends AdapterBase implements NetworkElement {
DeployDestination dest, ReservationContext context) DeployDestination dest, ReservationContext context)
throws ConcurrentOperationException, ResourceUnavailableException, throws ConcurrentOperationException, ResourceUnavailableException,
InsufficientCapacityException { 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; return true;
} }

View File

@ -5,6 +5,7 @@ import com.cloud.deploy.DeployDestination;
import com.cloud.network.Network; import com.cloud.network.Network;
import com.cloud.uservm.UserVm; import com.cloud.uservm.UserVm;
import com.cloud.utils.component.Manager; import com.cloud.utils.component.Manager;
import com.cloud.vm.DomainRouterVO;
import com.cloud.vm.State; import com.cloud.vm.State;
import com.cloud.vm.UserVmVO; import com.cloud.vm.UserVmVO;
import com.cloud.vm.VirtualMachineProfile; import com.cloud.vm.VirtualMachineProfile;
@ -16,12 +17,21 @@ public interface OvsNetworkManager extends Manager {
public String getVlanMapping(long accountId); public String getVlanMapping(long accountId);
public void CheckAndCreateTunnel(Commands cmds, public void UserVmCheckAndCreateTunnel(Commands cmds,
VirtualMachineProfile<UserVmVO> profile, DeployDestination dest); VirtualMachineProfile<UserVmVO> profile, DeployDestination dest);
public void applyDefaultFlow(Commands cmds, public void applyDefaultFlowToUserVm(Commands cmds,
VirtualMachineProfile<UserVmVO> profile, DeployDestination dest); VirtualMachineProfile<UserVmVO> profile, DeployDestination dest);
public void applyDefaultFlowToRouter(Commands cmds,
VirtualMachineProfile<DomainRouterVO> profile,
DeployDestination dest);
public void CheckAndUpdateDhcpFlow(Network nw); public void CheckAndUpdateDhcpFlow(Network nw);
public void handleVmStateTransition(UserVm userVm, State vmState); public void handleVmStateTransition(UserVm userVm, State vmState);
public void RouterCheckAndCreateTunnel(Commands cmds,
VirtualMachineProfile<DomainRouterVO> profile,
DeployDestination dest);
} }

View File

@ -1,8 +1,15 @@
package com.cloud.network.ovs; package com.cloud.network.ovs;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; 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.ejb.Local;
import javax.naming.ConfigurationException; import javax.naming.ConfigurationException;
@ -13,6 +20,7 @@ import com.cloud.agent.manager.Commands;
import com.cloud.configuration.Config; import com.cloud.configuration.Config;
import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.configuration.dao.ConfigurationDao;
import com.cloud.deploy.DeployDestination; import com.cloud.deploy.DeployDestination;
import com.cloud.exception.AgentUnavailableException;
import com.cloud.host.HostVO; import com.cloud.host.HostVO;
import com.cloud.host.dao.HostDao; import com.cloud.host.dao.HostDao;
import com.cloud.network.Network; 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.BroadcastDomainType;
import com.cloud.network.Networks.TrafficType; import com.cloud.network.Networks.TrafficType;
import com.cloud.network.dao.NetworkDao; 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.VlanMappingDao;
import com.cloud.network.ovs.dao.VlanMappingDirtyDao; import com.cloud.network.ovs.dao.VlanMappingDirtyDao;
import com.cloud.network.ovs.dao.VlanMappingVO; 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.uservm.UserVm;
import com.cloud.utils.Pair; import com.cloud.utils.Pair;
import com.cloud.utils.component.ComponentLocator;
import com.cloud.utils.component.Inject; 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.utils.db.Transaction;
import com.cloud.vm.DomainRouterVO; import com.cloud.vm.DomainRouterVO;
import com.cloud.vm.NicVO; import com.cloud.vm.NicVO;
import com.cloud.vm.State; import com.cloud.vm.State;
import com.cloud.vm.UserVmVO; import com.cloud.vm.UserVmVO;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachineProfile; import com.cloud.vm.VirtualMachineProfile;
import com.cloud.vm.dao.DomainRouterDao; import com.cloud.vm.dao.DomainRouterDao;
@ -49,61 +67,183 @@ public class OvsNetworkManagerImpl implements OvsNetworkManager {
@Inject NetworkDao _networkDao; @Inject NetworkDao _networkDao;
@Inject VlanMappingDirtyDao _vlanMappingDirtyDao; @Inject VlanMappingDirtyDao _vlanMappingDirtyDao;
@Inject DomainRouterDao _routerDao; @Inject DomainRouterDao _routerDao;
@Inject OvsWorkDao _workDao;
@Inject VmFlowLogDao _flowLogDao;
@Inject UserVmDao _userVMDao;
String _name; String _name;
boolean _isEnabled; 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 @Override
public boolean configure(String name, Map<String, Object> params) public boolean configure(String name, Map<String, Object> params)
throws ConfigurationException { throws ConfigurationException {
_name = name; _name = name;
_isEnabled = _configDao.getValue(Config.OvsNetwork.key()).equalsIgnoreCase("true") ? true : false; _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; return true;
} }
@Override @Override
public boolean start() { public boolean start() {
// TODO Auto-generated method stub if (_isEnabled) {
_cleanupExecutor.scheduleAtFixedRate(new CleanupThread(), _timeBetweenCleanups, _timeBetweenCleanups, TimeUnit.SECONDS);
}
return true; return true;
} }
@Override @Override
public boolean stop() { public boolean stop() {
// TODO Auto-generated method stub
return true; return true;
} }
@Override @Override
public String getName() { public String getName() {
// TODO Auto-generated method stub
return _name; return _name;
} }
@Override @Override
public boolean isOvsNetworkEnabled() { public boolean isOvsNetworkEnabled() {
// TODO Auto-generated method stub
return _isEnabled; 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 @Override
@DB
public long askVlanId(long accountId, long hostId) { public long askVlanId(long accountId, long hostId) {
assert _isEnabled : "Who call me ??? while OvsNetwokr is not enabled!!!"; assert _isEnabled : "Who call me ??? while OvsNetwokr is not enabled!!!";
final Transaction txn = Transaction.currentTxn(); final Transaction txn = Transaction.currentTxn();
txn.start(); txn.start();
List<VlanMappingVO> mappings = _vlanMappingDao.listByAccountIdAndHostId(accountId, hostId); VlanMappingVO currVlan = _vlanMappingDao.findByAccountIdAndHostId(accountId, hostId);
long vlan = 0; long vlan = 0;
if (mappings.size() !=0) { if (currVlan != null) {
assert mappings.size() == 1 : "We should only have one vlan for an account on a host"; vlan = currVlan.getVlan();
txn.commit(); currVlan.ref();
vlan = mappings.get(0).getVlan(); _vlanMappingDao.update(currVlan.getId(), currVlan);
s_logger.debug("Already has an Vlan " + vlan + " on host " + hostId 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; return vlan;
} }
mappings = _vlanMappingDao.listByHostId(hostId); List<VlanMappingVO>mappings = _vlanMappingDao.listByHostId(hostId);
if (mappings.size() > 0) { if (mappings.size() > 0) {
ArrayList<Long> vlans = new ArrayList<Long>(); ArrayList<Long> vlans = new ArrayList<Long>();
for (VlanMappingVO vo : mappings) { for (VlanMappingVO vo : mappings) {
@ -129,8 +269,9 @@ public class OvsNetworkManagerImpl implements OvsNetworkManager {
} }
@Override @Override
@DB
public String getVlanMapping(long accountId) { 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(); final Transaction txn = Transaction.currentTxn();
txn.start(); txn.start();
@ -151,22 +292,21 @@ public class OvsNetworkManagerImpl implements OvsNetworkManager {
return buf.toString(); return buf.toString();
} }
@Override protected void CheckAndCreateTunnel(Commands cmds, VMInstanceVO instance,
public void CheckAndCreateTunnel(Commands cmds, VirtualMachineProfile<UserVmVO> profile,
DeployDestination dest) { DeployDestination dest) {
if (!_isEnabled) { if (!_isEnabled) {
return; return;
} }
UserVmVO userVm = profile.getVirtualMachine(); if (instance.getType() != VirtualMachine.Type.User
if (userVm.getType() != VirtualMachine.Type.User) { && instance.getType() != VirtualMachine.Type.DomainRouter) {
return; return;
} }
long hostId = dest.getHost().getId(); long hostId = dest.getHost().getId();
long accountId = userVm.getAccountId(); long accountId = instance.getAccountId();
List<UserVmVO> vms = _userVmDao.listByAccountIdAndHostId(accountId, hostId); 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 s_logger.debug("Already has GRE tunnel for account " + accountId
+ " for host " + hostId); + " for host " + hostId);
return; return;
@ -204,21 +344,19 @@ public class OvsNetworkManagerImpl implements OvsNetworkManager {
return sub; return sub;
} }
@Override protected void applyDefaultFlow(Commands cmds,
public void applyDefaultFlow(Commands cmds, VMInstanceVO instance, DeployDestination dest) {
VirtualMachineProfile<UserVmVO> profile, DeployDestination dest) {
if (!_isEnabled) { if (!_isEnabled) {
return; return;
} }
UserVmVO userVm = profile.getVirtualMachine(); VirtualMachine.Type vmType = instance.getType();
VirtualMachine.Type vmType = userVm.getType();
if (vmType != VirtualMachine.Type.User if (vmType != VirtualMachine.Type.User
&& vmType != VirtualMachine.Type.DomainRouter) { && vmType != VirtualMachine.Type.DomainRouter) {
return; return;
} }
List<NicVO> nics = _nicDao.listBy(userVm.getId()); List<NicVO> nics = _nicDao.listBy(instance.getId());
if (nics.size() == 0) if (nics.size() == 0)
return; return;
@ -237,7 +375,7 @@ public class OvsNetworkManagerImpl implements OvsNetworkManager {
assert nic!=null : "Why there is no guest network nic???"; assert nic!=null : "Why there is no guest network nic???";
String vlans = parseVlanAndMapping(nic.getBroadcastUri().toASCIIString()); String vlans = parseVlanAndMapping(nic.getBroadcastUri().toASCIIString());
cmds.addCommand(new OvsSetTagAndFlowCommand(userVm.getName(), vlans)); cmds.addCommand(new OvsSetTagAndFlowCommand(instance.getName(), vlans));
} }
@Override @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); scheduleFlowUpdateToHosts(affectedVms, true, null);
} }
protected void handleVmStopped(UserVm userVm) { //TODO: think about lock
scheduleFlowUpdateToHosts(affectedVms, true, null); 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 @Override
@ -291,14 +519,42 @@ public class OvsNetworkManagerImpl implements OvsNetworkManager {
case Unknown: case Unknown:
return; return;
case Running: case Running:
handleVmStarted(userVm); handleVmStateChange(userVm);
break; break;
case Stopping: case Stopping:
case Stopped: case Stopped:
handleVmStopped(userVm); checkAndRemove(userVm);
handleVmStateChange(userVm);
break; 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);
}
} }

View 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);
}

View 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;
}
}

View 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;
}
}

View File

@ -8,4 +8,5 @@ public interface VlanMappingDao extends GenericDao<VlanMappingVO, Long> {
List<VlanMappingVO> listByAccountIdAndHostId(long accountId, long hostId); List<VlanMappingVO> listByAccountIdAndHostId(long accountId, long hostId);
List<VlanMappingVO> listByHostId(long hostId); List<VlanMappingVO> listByHostId(long hostId);
List<VlanMappingVO> listByAccountId(long accountId); List<VlanMappingVO> listByAccountId(long accountId);
VlanMappingVO findByAccountIdAndHostId(long accountId, long hostId);
} }

View File

@ -47,4 +47,11 @@ public class VlanMappingDaoImpl extends GenericDaoBase<VlanMappingVO, Long>
return listBy(sc, null); 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);
}
} }

View File

@ -23,11 +23,15 @@ public class VlanMappingVO {
@Column(name = "vlan") @Column(name = "vlan")
private long vlan; private long vlan;
@Column(name = "ref")
private int ref;
public VlanMappingVO(long accountId, long hostId, long vlan) { public VlanMappingVO(long accountId, long hostId, long vlan) {
this.hostId = hostId; this.hostId = hostId;
this.accountId = accountId; this.accountId = accountId;
this.vlan = vlan; this.vlan = vlan;
this.ref = 1;
} }
public VlanMappingVO() { public VlanMappingVO() {
@ -49,4 +53,17 @@ public class VlanMappingVO {
public long getId() { public long getId() {
return id; return id;
} }
public int getRef() {
return ref;
}
public void ref() {
ref++;
}
public int unref() {
ref--;
return ref;
}
} }

View 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);
}

View 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();
}
}

View 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++;
}
}

View File

@ -129,6 +129,7 @@ import com.cloud.network.dao.VpnUserDao;
import com.cloud.network.lb.LoadBalancingRule; import com.cloud.network.lb.LoadBalancingRule;
import com.cloud.network.lb.LoadBalancingRule.LbDestination; import com.cloud.network.lb.LoadBalancingRule.LbDestination;
import com.cloud.network.lb.LoadBalancingRulesManager; import com.cloud.network.lb.LoadBalancingRulesManager;
import com.cloud.network.ovs.OvsNetworkManager;
import com.cloud.network.router.VirtualRouter.Role; import com.cloud.network.router.VirtualRouter.Role;
import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.FirewallRule;
import com.cloud.network.rules.PortForwardingRule; import com.cloud.network.rules.PortForwardingRule;
@ -294,6 +295,7 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian
RemoteAccessVpnDao _vpnDao; RemoteAccessVpnDao _vpnDao;
@Inject @Inject
VMInstanceDao _instanceDao; VMInstanceDao _instanceDao;
OvsNetworkManager _ovsNetworkMgr;
long _routerTemplateId = -1; long _routerTemplateId = -1;
int _routerRamSize; int _routerRamSize;
@ -1250,6 +1252,9 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian
@Override @Override
public boolean finalizeDeployment(Commands cmds, VirtualMachineProfile<DomainRouterVO> profile, DeployDestination dest, ReservationContext context) throws ResourceUnavailableException{ public boolean finalizeDeployment(Commands cmds, VirtualMachineProfile<DomainRouterVO> profile, DeployDestination dest, ReservationContext context) throws ResourceUnavailableException{
NicProfile controlNic = (NicProfile) profile.getParameter("control.nic"); 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)); cmds.addCommand("checkSsh", new CheckSshCommand(profile.getInstanceName(), controlNic.getIp4Address(), 3922, 5, 20));
DomainRouterVO router = profile.getVirtualMachine(); DomainRouterVO router = profile.getVirtualMachine();

View File

@ -1133,7 +1133,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
public void completeStartCommand(UserVmVO vm) { public void completeStartCommand(UserVmVO vm) {
_itMgr.stateTransitTo(vm, VirtualMachine.Event.AgentReportRunning, vm.getHostId()); _itMgr.stateTransitTo(vm, VirtualMachine.Event.AgentReportRunning, vm.getHostId());
_networkGroupMgr.handleVmStateTransition(vm, State.Running); _networkGroupMgr.handleVmStateTransition(vm, State.Running);
_ovsNetworkMgr.handleVmStateTransition(vm, State.Running);
} }
@Override @Override
@ -1167,6 +1167,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
txn.commit(); txn.commit();
_networkGroupMgr.handleVmStateTransition(vm, State.Stopped); _networkGroupMgr.handleVmStateTransition(vm, State.Stopped);
_ovsNetworkMgr.handleVmStateTransition(vm, State.Stopped);
} catch (Throwable th) { } catch (Throwable th) {
s_logger.error("Error during stop: ", th); s_logger.error("Error during stop: ", th);
throw new CloudRuntimeException("Error during stop: ", th); throw new CloudRuntimeException("Error during stop: ", th);
@ -2343,7 +2344,10 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
try { try {
vm = _itMgr.start(vm, null, caller, owner, cmd.getHypervisor()); vm = _itMgr.start(vm, null, caller, owner, cmd.getHypervisor());
} finally { } catch (Exception e) {
e.printStackTrace();
}
finally {
updateVmStateForFailedVmCreation(vm.getId()); updateVmStateForFailedVmCreation(vm.getId());
} }
vm.setPassword(password); vm.setPassword(password);
@ -2397,7 +2401,8 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
} }
_vmDao.update(userVm.getId(), userVm); _vmDao.update(userVm.getId(), userVm);
_ovsNetworkMgr.CheckAndCreateTunnel(cmds, profile, dest); _ovsNetworkMgr.UserVmCheckAndCreateTunnel(cmds, profile, dest);
_ovsNetworkMgr.applyDefaultFlowToUserVm(cmds, profile, dest);
return true; return true;
} }

View File

@ -1328,6 +1328,7 @@ CREATE TABLE `cloud`.`ovs_host_vlan_alloc`(
`host_id` bigint unsigned COMMENT 'host id', `host_id` bigint unsigned COMMENT 'host id',
`account_id` bigint unsigned COMMENT 'account id', `account_id` bigint unsigned COMMENT 'account id',
`vlan` bigint unsigned COMMENT 'vlan id under account #account_id on host #host_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`) PRIMARY KEY(`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
@ -1338,4 +1339,23 @@ CREATE TABLE `cloud`.`ovs_vlan_mapping_dirty`(
PRIMARY KEY(`id`) PRIMARY KEY(`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) 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; SET foreign_key_checks = 1;