introduce OvsNetworkTopologyGuru that has convinenace functions to

- get the hosts on which VPC spans given vpc id
   - get the VM's in the VPC
   - get the hosts on which a network spans
   - get the VPC's to which a hosts is part of
   - get VM's of a VPC on a hosts

introduces capability to build a physical toplogy representation of a
VPC. This json file is encapsulated in
OvsVpcPhysicalTopologyConfigCommand, and is used to send full topology
to hypervisor hosts. On hypervisor this json config can be used to setup
tunnels, configure bridge, add flow rules etc

Ovs GURU, to use different broasdcast scheme VS://vpcid.gerkey for the
networks in VPC that use distributed routing

each VIF and tunnel interface to carry the network UUID in other/options
config
This commit is contained in:
Murali Reddy 2014-03-10 12:52:30 +05:30
parent 100df92455
commit e045883c52
19 changed files with 737 additions and 160 deletions

View File

@ -80,4 +80,12 @@ public class NicTO extends NetworkTO {
public List<String> getNicSecIps() {
return nicSecIps;
}
public String getNetworkUuid() {
return super.getUuid();
}
public void setNetworkUuid(String uuid) {
super.setUuid(uuid);
}
}

View File

@ -1388,23 +1388,22 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
}
private Answer execute(OvsSetupBridgeCommand cmd) {
findOrCreateTunnelNetwork(cmd.getKey());
findOrCreateTunnelNetwork(cmd.getBridgeName());
configureTunnelNetwork(cmd.getNetworkId(), cmd.getHostId(),
cmd.getKey());
cmd.getBridgeName());
s_logger.debug("OVS Bridge configured");
return new Answer(cmd, true, null);
}
private Answer execute(OvsDestroyBridgeCommand cmd) {
destroyTunnelNetwork(cmd.getKey());
destroyTunnelNetwork(cmd.getBridgeName());
s_logger.debug("OVS Bridge destroyed");
return new Answer(cmd, true, null);
}
private synchronized void destroyTunnelNetwork(int key) {
private synchronized void destroyTunnelNetwork(String bridge) {
try {
findOrCreateTunnelNetwork(key);
String bridge = "OVSTunnel" + key;
findOrCreateTunnelNetwork(bridge);
Script cmd = new Script(_ovsTunnelPath, _timeout, s_logger);
cmd.add("destroy_ovs_bridge");
cmd.add("--bridge", bridge);
@ -1423,9 +1422,8 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
}
}
private synchronized boolean findOrCreateTunnelNetwork(long key) {
private synchronized boolean findOrCreateTunnelNetwork(String nwName) {
try {
String nwName = "OVSTunnel" + key;
if (checkNetwork(nwName)) {
return true;
}
@ -1443,10 +1441,9 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
}
private synchronized boolean configureTunnelNetwork(long networkId,
long hostId, int key) {
long hostId, String nwName) {
try {
findOrCreateTunnelNetwork(key);
String nwName = "OVSTunnel" + key;
findOrCreateTunnelNetwork(nwName);
String configuredHosts = Script
.runSimpleBashScript("ovs-vsctl get bridge " + nwName
+ " other_config:ovs_host_setup");
@ -1463,7 +1460,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
if (!configured) {
Script cmd = new Script(_ovsTunnelPath, _timeout, s_logger);
cmd.add("setup_ovs_bridge");
cmd.add("--key", String.valueOf(key));
cmd.add("--key", nwName);
cmd.add("--cs_host_id", ((Long)hostId).toString());
cmd.add("--bridge", nwName);
String result = cmd.execute();
@ -1481,16 +1478,16 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
}
private OvsCreateTunnelAnswer execute(OvsCreateTunnelCommand cmd) {
String bridge = "OVSTunnel" + cmd.getKey();
String bridge = cmd.getNetworkName();
try {
if (!findOrCreateTunnelNetwork(cmd.getKey())) {
if (!findOrCreateTunnelNetwork(bridge)) {
s_logger.debug("Error during bridge setup");
return new OvsCreateTunnelAnswer(cmd, false,
"Cannot create network", bridge);
}
configureTunnelNetwork(cmd.getNetworkId(), cmd.getFrom(),
cmd.getKey());
cmd.getNetworkName());
Script command = new Script(_ovsTunnelPath, _timeout, s_logger);
command.add("create_tunnel");
command.add("--bridge", bridge);
@ -1515,16 +1512,15 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
private Answer execute(OvsDestroyTunnelCommand cmd) {
try {
if (!findOrCreateTunnelNetwork(cmd.getKey())) {
if (!findOrCreateTunnelNetwork(cmd.getBridgeName())) {
s_logger.warn("Unable to find tunnel network for GRE key:"
+ cmd.getKey());
+ cmd.getBridgeName());
return new Answer(cmd, false, "No network found");
}
String bridge = "OVSTunnel" + cmd.getKey();
Script command = new Script(_ovsTunnelPath, _timeout, s_logger);
command.add("destroy_tunnel");
command.add("--bridge", bridge);
command.add("--bridge", cmd.getBridgeName());
command.add("--iface_name", cmd.getInPortName());
String result = command.execute();
if (result == null) {

View File

@ -148,6 +148,7 @@ import com.cloud.agent.api.OvsFetchInterfaceCommand;
import com.cloud.agent.api.OvsSetTagAndFlowAnswer;
import com.cloud.agent.api.OvsSetTagAndFlowCommand;
import com.cloud.agent.api.OvsSetupBridgeCommand;
import com.cloud.agent.api.OvsVpcPhysicalTopologyConfigCommand;
import com.cloud.agent.api.PerformanceMonitorAnswer;
import com.cloud.agent.api.PerformanceMonitorCommand;
import com.cloud.agent.api.PingCommand;
@ -507,6 +508,8 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
return execute((OvsSetTagAndFlowCommand)cmd);
} else if (clazz == OvsDeleteFlowCommand.class) {
return execute((OvsDeleteFlowCommand)cmd);
} else if (clazz == OvsVpcPhysicalTopologyConfigCommand.class) {
return execute((OvsVpcPhysicalTopologyConfigCommand) cmd);
} else if (clazz == CleanupNetworkRulesCmd.class) {
return execute((CleanupNetworkRulesCmd)cmd);
} else if (clazz == NetworkRulesSystemVmCommand.class) {
@ -964,15 +967,14 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
/**
* This method just creates a XenServer network following the tunnel network naming convention
*/
private synchronized Network findOrCreateTunnelNetwork(Connection conn, long key) {
private synchronized Network findOrCreateTunnelNetwork(Connection conn, String nwName) {
try {
String nwName = "OVSTunnel" + key;
Network nw = null;
Network.Record rec = new Network.Record();
Set<Network> networks = Network.getByNameLabel(conn, nwName);
if (networks.size() == 0) {
rec.nameDescription = "tunnel network id# " + key;
rec.nameDescription = "tunnel network id# " + nwName;
rec.nameLabel = nwName;
//Initialize the ovs-host-setup to avoid error when doing get-param in plugin
Map<String, String> otherConfig = new HashMap<String, String>();
@ -981,7 +983,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
nw = Network.create(conn, rec);
// Plug dom0 vif only when creating network
if (!is_xcp())
enableXenServerNetwork(conn, nw, nwName, "tunnel network for account " + key);
enableXenServerNetwork(conn, nw, nwName, "tunnel network for account " + nwName);
s_logger.debug("### Xen Server network for tunnels created:" + nwName);
} else {
nw = networks.iterator().next();
@ -997,10 +999,10 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
/**
* This method creates a XenServer network and configures it for being used as a L2-in-L3 tunneled network
*/
private synchronized Network configureTunnelNetwork(Connection conn, long networkId, long hostId, int key) {
private synchronized Network configureTunnelNetwork(Connection conn, long networkId, long hostId, String bridgeName) {
try {
Network nw = findOrCreateTunnelNetwork(conn, key);
String nwName = "OVSTunnel" + key;
Network nw = findOrCreateTunnelNetwork(conn, bridgeName);
String nwName = bridgeName;
//Invoke plugin to setup the bridge which will be used by this network
String bridge = nw.getBridge(conn);
Map<String, String> nwOtherConfig = nw.getOtherConfig(conn);
@ -1018,11 +1020,20 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
if (!configured) {
// Plug dom0 vif only if not done before for network and host
if (!is_xcp())
enableXenServerNetwork(conn, nw, nwName, "tunnel network for account " + key);
String result = callHostPlugin(conn, "ovstunnel", "setup_ovs_bridge", "bridge", bridge,
"key", String.valueOf(key),
"xs_nw_uuid", nw.getUuid(conn),
"cs_host_id", ((Long)hostId).toString());
enableXenServerNetwork(conn, nw, nwName, "tunnel network for account " + bridgeName);
String result;
if (bridgeName.startsWith("OVS-DR-VPC-Bridge")) {
result = callHostPlugin(conn, "ovstunnel", "setup_ovs_bridge_for_distributed_routing", "bridge", bridge,
"key", bridgeName,
"xs_nw_uuid", nw.getUuid(conn),
"cs_host_id", ((Long)hostId).toString());
} else {
result = callHostPlugin(conn, "ovstunnel", "setup_ovs_bridge", "bridge", bridge,
"key", bridgeName,
"xs_nw_uuid", nw.getUuid(conn),
"cs_host_id", ((Long)hostId).toString());
}
//Note down the fact that the ovs bridge has been setup
String[] res = result.split(":");
if (res.length != 2 || !res[0].equalsIgnoreCase("SUCCESS")) {
@ -1037,9 +1048,9 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
}
}
private synchronized void destroyTunnelNetwork(Connection conn, int key) {
private synchronized void destroyTunnelNetwork(Connection conn, String bridgeName) {
try {
Network nw = findOrCreateTunnelNetwork(conn, key);
Network nw = findOrCreateTunnelNetwork(conn, bridgeName);
String bridge = nw.getBridge(conn);
String result = callHostPlugin(conn, "ovstunnel", "destroy_ovs_bridge", "bridge", bridge);
String[] res = result.split(":");
@ -1079,8 +1090,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
_isOvs = true;
return setupvSwitchNetwork(conn);
} else {
long vnetId = Long.parseLong(BroadcastDomainType.getValue(uri));
return findOrCreateTunnelNetwork(conn, vnetId);
return findOrCreateTunnelNetwork(conn, getOvsTunnelNetworkName(BroadcastDomainType.getValue(uri)));
}
} else if (type == BroadcastDomainType.Storage) {
if (uri == null) {
@ -1102,6 +1112,19 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
throw new CloudRuntimeException("Unable to support this type of network broadcast domain: " + nic.getBroadcastUri());
}
private String getOvsTunnelNetworkName(String broadcastUri) {
if (broadcastUri.contains(".")) {
String[] parts = broadcastUri.split(".");
return "OVS-DR-VPC-Bridge"+parts[0];
} else {
try {
return "OVSTunnel" + broadcastUri;
} catch (Exception e) {
return null;
}
}
}
protected VIF createVif(Connection conn, String vmName, VM vm, VirtualMachineTO vmSpec, NicTO nic) throws XmlRpcException, XenAPIException {
assert (nic.getUuid() != null) : "Nic should have a uuid value";
@ -1122,7 +1145,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
if (vmSpec != null) {
vifr.otherConfig.put("cloudstack-vm-id", vmSpec.getUuid());
}
vifr.otherConfig.put("cloudstack-network-id", nic.getNetworkUuid());
vifr.network = getNetwork(conn, nic);
if (nic.getNetworkRateMbps() != null && nic.getNetworkRateMbps().intValue() != -1) {
@ -5220,15 +5243,15 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
private Answer execute(OvsSetupBridgeCommand cmd) {
Connection conn = getConnection();
findOrCreateTunnelNetwork(conn, cmd.getKey());
configureTunnelNetwork(conn, cmd.getNetworkId(), cmd.getHostId(), cmd.getKey());
findOrCreateTunnelNetwork(conn, cmd.getBridgeName());
configureTunnelNetwork(conn, cmd.getNetworkId(), cmd.getHostId(), cmd.getBridgeName());
s_logger.debug("OVS Bridge configured");
return new Answer(cmd, true, null);
}
private Answer execute(OvsDestroyBridgeCommand cmd) {
Connection conn = getConnection();
destroyTunnelNetwork(conn, cmd.getKey());
destroyTunnelNetwork(conn, cmd.getBridgeName());
s_logger.debug("OVS Bridge destroyed");
return new Answer(cmd, true, null);
}
@ -5236,14 +5259,14 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
private Answer execute(OvsDestroyTunnelCommand cmd) {
Connection conn = getConnection();
try {
Network nw = findOrCreateTunnelNetwork(conn, cmd.getNetworkId());
Network nw = findOrCreateTunnelNetwork(conn, cmd.getBridgeName());
if (nw == null) {
s_logger.warn("Unable to find tunnel network for GRE key:" + cmd.getKey());
s_logger.warn("Unable to find tunnel network for GRE key:" + cmd.getBridgeName());
return new Answer(cmd, false, "No network found");
}
String bridge = nw.getBridge(conn);
String result = callHostPlugin(conn, "ovstunnel", "destroy_tunnel", "bridge", bridge, "in_port", cmd.getInPortName());
String result = callHostPlugin(conn, "ovstunnel", "configure_ovs_bridge_for_network_topology", "bridge", bridge, "in_port", cmd.getInPortName());
if (result.equalsIgnoreCase("SUCCESS")) {
return new Answer(cmd, true, result);
} else {
@ -5255,6 +5278,22 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
}
}
public Answer execute(OvsVpcPhysicalTopologyConfigCommand cmd) {
Connection conn = getConnection();
try {
String result = callHostPlugin(conn, "ovstunnel", "configure_ovs_bridge_for_network_topology", "bridge",
cmd.getBridgeName(), "host-id", ((Long)cmd.getHostId()).toString());
if (result.equalsIgnoreCase("SUCCESS")) {
return new Answer(cmd, true, result);
} else {
return new Answer(cmd, false, result);
}
} catch (Exception e) {
s_logger.warn("caught exception while updating host with latest VPC topology", e);
return new Answer(cmd, false, e.getMessage());
}
}
private Answer execute(UpdateHostPasswordCommand cmd) {
_password.add(cmd.getNewPassword());
return new Answer(cmd, true, null);
@ -5264,17 +5303,19 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
Connection conn = getConnection();
String bridge = "unknown";
try {
Network nw = findOrCreateTunnelNetwork(conn, cmd.getKey());
Network nw = findOrCreateTunnelNetwork(conn, cmd.getNetworkName());
if (nw == null) {
s_logger.debug("Error during bridge setup");
return new OvsCreateTunnelAnswer(cmd, false, "Cannot create network", bridge);
}
configureTunnelNetwork(conn, cmd.getNetworkId(), cmd.getFrom(), cmd.getKey());
configureTunnelNetwork(conn, cmd.getNetworkId(), cmd.getFrom(), cmd.getNetworkName());
bridge = nw.getBridge(conn);
String result =
callHostPlugin(conn, "ovstunnel", "create_tunnel", "bridge", bridge, "remote_ip", cmd.getRemoteIp(), "key", cmd.getKey().toString(), "from",
cmd.getFrom().toString(), "to", cmd.getTo().toString());
callHostPlugin(conn, "ovstunnel", "create_tunnel", "bridge", bridge, "remote_ip", cmd.getRemoteIp(),
"key", cmd.getKey().toString(), "from",
cmd.getFrom().toString(), "to", cmd.getTo().toString(), "cloudstack-network-id",
cmd.getNetworkUuid());
String[] res = result.split(":");
if (res.length == 2 && res[0].equalsIgnoreCase("SUCCESS")) {
return new OvsCreateTunnelAnswer(cmd, true, result, res[1], bridge);

View File

@ -38,5 +38,5 @@
<bean id="ovsTunnelManagerImpl" class="com.cloud.network.ovs.OvsTunnelManagerImpl" />
<bean id="ovsTunnelInterfaceDaoImpl" class="com.cloud.network.ovs.dao.OvsTunnelInterfaceDaoImpl" />
<bean id="ovsTunnelNetworkDaoImpl" class="com.cloud.network.ovs.dao.OvsTunnelNetworkDaoImpl" />
<bean id="ovsNetworkTopologyGuruImpl" class="com.cloud.network.ovs.OvsNetworkTopologyGuruImpl"/>
</beans>

View File

@ -20,10 +20,13 @@ package com.cloud.agent.api;
public class OvsCreateTunnelCommand extends Command {
Integer key;
String remoteIp;
String networkName;
Long from;
Long to;
long networkId;
String networkUuid;
// for debug info
String fromIp;
@ -33,13 +36,15 @@ public class OvsCreateTunnelCommand extends Command {
}
public OvsCreateTunnelCommand(String remoteIp, Integer key, Long from,
Long to, long networkId, String fromIp) {
Long to, long networkId, String fromIp, String networkName, String networkUuid) {
this.remoteIp = remoteIp;
this.key = key;
this.from = from;
this.to = to;
this.networkId = networkId;
this.fromIp = fromIp;
this.networkName = networkName;
this.networkUuid = networkUuid;
}
public Integer getKey() {
@ -66,4 +71,16 @@ public class OvsCreateTunnelCommand extends Command {
return fromIp;
}
public String getNetworkName() {
return networkName;
}
public String getNetworkUuid() {
return networkUuid;
}
public void setNetworkUuid(String networkUuid) {
this.networkUuid = networkUuid;
}
}

View File

@ -21,19 +21,19 @@ package com.cloud.agent.api;
public class OvsDestroyBridgeCommand extends Command {
Long networkId;
Integer key;
String name;
public OvsDestroyBridgeCommand(Long networkId, Integer key) {
public OvsDestroyBridgeCommand(Long networkId, String name) {
this.networkId = networkId;
this.key = key;
this.name = name;
}
public Long getNetworkId() {
return networkId;
}
public Integer getKey() {
return key;
public String getBridgeName() {
return name;
}
@Override

View File

@ -20,14 +20,14 @@ package com.cloud.agent.api;
public class OvsDestroyTunnelCommand extends Command {
Long networkId;
Integer key;
String networkName;
String inPortName;
public OvsDestroyTunnelCommand(Long networkId, Integer key,
public OvsDestroyTunnelCommand(Long networkId, String networkName,
String inPortName) {
this.networkId = networkId;
this.inPortName = inPortName;
this.key = key;
this.networkName = networkName;
}
public Long getNetworkId() {
@ -38,8 +38,8 @@ public class OvsDestroyTunnelCommand extends Command {
return inPortName;
}
public Integer getKey() {
return key;
public String getBridgeName() {
return networkName;
}
@Override

View File

@ -19,7 +19,7 @@ package com.cloud.agent.api;
public class OvsSetupBridgeCommand extends Command {
Integer key;
String name;
Long hostId;
Long networkId;
@ -28,14 +28,14 @@ public class OvsSetupBridgeCommand extends Command {
return true;
}
public OvsSetupBridgeCommand(Integer key, Long hostId, Long networkId) {
this.key = key;
public OvsSetupBridgeCommand(String name, Long hostId, Long networkId) {
this.name = name;
this.hostId = hostId;
this.networkId = networkId;
}
public Integer getKey() {
return key;
public String getBridgeName() {
return name;
}
public Long getHostId() {

View File

@ -0,0 +1,127 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package com.cloud.agent.api;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
/**
* This command represents view of how a VPC is laid out (on which hosts, which VM is on which host etc)
* on the physical infrastructure.
*/
public class OvsVpcPhysicalTopologyConfigCommand extends Command {
VpcConfig vpcConfig =null;
long hostId;
String bridgeName;
public static class Host {
long hostId;
String ipAddress;
public Host (long hostId, String ipAddress) {
this.hostId = hostId;
this.ipAddress = ipAddress;
}
}
public static class Nic {
String ipAddress;
String macAddress;
String networkUuid;
public Nic (String ipAddress, String macAddress, String networkUuid) {
this.ipAddress = ipAddress;
this.macAddress = macAddress;
this.networkUuid = networkUuid;
}
}
public static class Tier {
long greKey;
String networkUuid;
String gatewayIp;
String gatewayMac;
String cidr;
public Tier(long greKey, String networkUuid, String gatewayIp, String gatewayMac, String cidr) {
this.greKey = greKey;
this.networkUuid = networkUuid;
this.gatewayIp = gatewayIp;
this.gatewayMac = gatewayMac;
this.cidr = cidr;
}
}
public static class Vm {
long hostId;
Nic[] nics;
public Vm(long hostId, Nic[] nics) {
this.hostId = hostId;
this.nics = nics;
}
}
public static class Vpc {
String cidr;
Host[] hosts;
Tier[] tiers;
Vm[] vms;
public Vpc(Host[] hosts, Tier[] tiers, Vm[] vms, String cidr) {
this.hosts = hosts;
this.tiers = tiers;
this.vms = vms;
this.cidr = cidr;
}
}
public static class VpcConfig {
Vpc vpc;
public VpcConfig(Vpc vpc) {
this.vpc = vpc;
}
}
public OvsVpcPhysicalTopologyConfigCommand(Host[] hosts, Tier[] tiers, Vm[] vms, String cidr) {
Vpc vpc = new Vpc(hosts, tiers, vms, cidr);
vpcConfig = new VpcConfig(vpc);
}
public String getjsonVpcConfig() {
Gson gson = new GsonBuilder().create();
return gson.toJson(vpcConfig).toLowerCase();
}
@Override
public boolean executeInSequence() {
return false;
}
public void setHostId(long hostId) {
this.hostId = hostId;
}
public long getHostId() {
return hostId;
}
public String getBridgeName() {
return bridgeName;
}
public void setBridgeName(String bridgeName) {
this.bridgeName = bridgeName;
}
}

View File

@ -16,6 +16,8 @@
// under the License.
package com.cloud.network.element;
import com.cloud.host.dao.HostDao;
import com.cloud.vm.dao.UserVmDao;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@ -73,6 +75,8 @@ import com.cloud.vm.NicProfile;
import com.cloud.vm.ReservationContext;
import com.cloud.vm.VirtualMachineProfile;
import com.cloud.vm.dao.DomainRouterDao;
import com.cloud.vm.UserVmVO;
import com.cloud.vm.VirtualMachine;
@Local(value = {NetworkElement.class, ConnectivityProvider.class,
SourceNatServiceProvider.class, StaticNatServiceProvider.class,
@ -93,6 +97,10 @@ StaticNatServiceProvider, IpDeployer {
DomainRouterDao _routerDao;
@Inject
VpcVirtualNetworkApplianceManager _routerMgr;
@Inject
UserVmDao _userVmDao;
@Inject
HostDao _hostDao;
private static final Logger s_logger = Logger.getLogger(OvsElement.class);
private static final Map<Service, Map<Capability, String>> capabilities = setCapabilities();
@ -171,7 +179,12 @@ StaticNatServiceProvider, IpDeployer {
return false;
}
_ovsTunnelMgr.vmCheckAndCreateTunnel(vm, network, dest);
if (vm.getType() != VirtualMachine.Type.User && vm.getType() != VirtualMachine.Type.DomainRouter) {
return false;
}
// prepare the tunnel network on the host, in order for VM to get launched
_ovsTunnelMgr.checkAndPrepareHostForTunnelNetwork(network, dest.getHost());
return true;
}
@ -192,7 +205,25 @@ StaticNatServiceProvider, IpDeployer {
return false;
}
_ovsTunnelMgr.checkAndDestroyTunnel(vm.getVirtualMachine(), network);
List<UserVmVO> userVms = _userVmDao.listByAccountIdAndHostId(vm.getVirtualMachine().getAccountId(),
vm.getVirtualMachine().getHostId());
if (vm.getType() == VirtualMachine.Type.User) {
if (userVms.size() > 1) {
return true;
}
List<DomainRouterVO> routers = _routerDao.findByNetwork(network.getId());
for (DomainRouterVO router : routers) {
if (router.getHostId().equals(vm.getVirtualMachine().getHostId())) {
return true;
}
}
} else if (vm.getType() == VirtualMachine.Type.DomainRouter && userVms.size() != 0) {
return true;
}
HostVO host = _hostDao.findById(vm.getVirtualMachine().getHostId());
_ovsTunnelMgr.checkAndRemoveHostFromTunnelNetwork(network, host);
return true;
}

View File

@ -16,6 +16,8 @@
// under the License.
package com.cloud.network.guru;
import com.cloud.network.vpc.VpcVO;
import com.cloud.network.vpc.dao.VpcDao;
import javax.ejb.Local;
import javax.inject.Inject;
@ -61,6 +63,8 @@ public class OvsGuestNetworkGuru extends GuestNetworkGuru {
OvsTunnelManager _ovsTunnelMgr;
@Inject
NetworkOfferingServiceMapDao _ntwkOfferingSrvcDao;
@Inject
VpcDao _vpcDao;
OvsGuestNetworkGuru() {
super();
@ -145,10 +149,14 @@ public class OvsGuestNetworkGuru extends GuestNetworkGuru {
implemented.setCidr(network.getCidr());
}
// do we need to create switch right now?
implemented.setBroadcastDomainType(BroadcastDomainType.Vswitch);
if (network.getVpcId() != null && isVpcEnabledForDistributedRouter(network.getVpcId())) {
String keyStr = BroadcastDomainType.getValue(implemented.getBroadcastUri());
Long vpcid= network.getVpcId();
implemented.setBroadcastUri(BroadcastDomainType.Vswitch.toUri(vpcid.toString()+keyStr));
}
return implemented;
}
@ -215,4 +223,9 @@ public class OvsGuestNetworkGuru extends GuestNetworkGuru {
implemented.setBroadcastUri(network.getBroadcastUri());
}
}
boolean isVpcEnabledForDistributedRouter(long vpcId) {
VpcVO vpc = _vpcDao.findById(vpcId);
return vpc.usesDistributedRouter();
}
}

View File

@ -0,0 +1,49 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package com.cloud.network.ovs;
import com.cloud.utils.component.Manager;
import java.util.List;
public interface OvsNetworkTopologyGuru extends Manager {
/**
* get the list of hypervisor hosts id's on which VM's belonging to the network currently spans
*/
public List<Long> getNetworkSpanedHosts(long networkId);
/**
* get the list of hypervisor hosts id's on which VM's belonging to a VPC spans
*/
public List<Long> getVpcSpannedHosts(long vpId);
/**
* get the list of VPC id's of the vpc's for which one or more VM's from the VPC are running on the host
*/
public List<Long> getVpcOnHost(long hostId);
/**
* get the list of all active Vm id's in the VPC for all ther tiers
*/
public List<Long> getAllActiveVmsInVpc(long vpcId);
/**
* get the list of all Vm id's in the VPC for all the tiers that are running on the host
*/
public List<Long> getActiveVmsInVpcOnHost(long vpcId, long hostId);
}

View File

@ -0,0 +1,74 @@
package com.cloud.network.ovs;
import com.cloud.utils.component.ManagerBase;
import com.cloud.vm.DomainRouterVO;
import com.cloud.vm.UserVmVO;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.dao.DomainRouterDao;
import com.cloud.vm.dao.UserVmDao;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.Local;
import javax.inject.Inject;
import org.springframework.stereotype.Component;
@Component
@Local(value = {OvsNetworkTopologyGuru.class})
public class OvsNetworkTopologyGuruImpl extends ManagerBase implements OvsNetworkTopologyGuru {
@Inject
UserVmDao _userVmDao;
@Inject
DomainRouterDao _routerDao;
/**
* get the list of hypervisor hosts on which VM's belonging to a network currently spans
*/
public List<Long> getNetworkSpanedHosts(long networkId) {
List<Long> hostIds = new ArrayList<Long>();
// Find active VMs with a NIC on the target network
List<UserVmVO> vms = _userVmDao.listByNetworkIdAndStates(networkId,
VirtualMachine.State.Running, VirtualMachine.State.Starting, VirtualMachine.State.Stopping, VirtualMachine.State.Unknown,
VirtualMachine.State.Migrating);
// Find routers for the network
List<DomainRouterVO> routers = _routerDao.findByNetwork(networkId);
List<VMInstanceVO> ins = new ArrayList<VMInstanceVO>();
if (vms != null) {
ins.addAll(vms);
}
if (routers.size() != 0) {
ins.addAll(routers);
}
for (VMInstanceVO v : ins) {
Long rh = v.getHostId();
if (rh == null) {
continue;
}
if (!hostIds.contains(rh)) {
hostIds.add(rh);
}
}
return hostIds;
}
@Override
public List<Long> getVpcSpannedHosts(long vpId) {
return null;
}
@Override
public List<Long> getVpcOnHost(long hostId) {
return null;
}
@Override
public List<Long> getAllActiveVmsInVpc(long vpcId) {
return null;
}
@Override
public List<Long> getActiveVmsInVpcOnHost(long vpcId, long hostId) {
return null;
}
}

View File

@ -16,18 +16,24 @@
// under the License.
package com.cloud.network.ovs;
import com.cloud.deploy.DeployDestination;
import com.cloud.host.Host;
import com.cloud.network.Network;
import com.cloud.utils.component.Manager;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachineProfile;
public interface OvsTunnelManager extends Manager {
boolean isOvsTunnelEnabled();
public void vmCheckAndCreateTunnel(VirtualMachineProfile vm, Network nw, DeployDestination dest);
/**
* create a bridge on the host if not already created for the network and establish full tunnel mesh with
* the rest of the hosts on which network spans
*/
public void checkAndPrepareHostForTunnelNetwork(Network nw, Host host);
public void checkAndDestroyTunnel(VirtualMachine vm, Network nw);
/**
* remove the bridge and tunnels to the hosts on which network spans if there are no other VM's
* belonging to the network are running on the host
*/
public void checkAndRemoveHostFromTunnelNetwork(Network nw, Host host);
}

View File

@ -16,6 +16,12 @@
// under the License.
package com.cloud.network.ovs;
import com.cloud.network.dao.NetworkDao;
import com.cloud.network.vpc.VpcManager;
import com.cloud.vm.Nic;
import com.cloud.vm.NicVO;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.dao.VMInstanceDao;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@ -42,9 +48,9 @@ import com.cloud.agent.api.OvsDestroyTunnelCommand;
import com.cloud.agent.api.OvsFetchInterfaceAnswer;
import com.cloud.agent.api.OvsFetchInterfaceCommand;
import com.cloud.agent.api.OvsSetupBridgeCommand;
import com.cloud.agent.api.OvsVpcPhysicalTopologyConfigCommand;
import com.cloud.agent.manager.Commands;
import com.cloud.configuration.Config;
import com.cloud.deploy.DeployDestination;
import com.cloud.exception.AgentUnavailableException;
import com.cloud.exception.OperationTimedoutException;
import com.cloud.host.Host;
@ -60,19 +66,15 @@ import com.cloud.network.ovs.dao.OvsTunnelInterfaceDao;
import com.cloud.network.ovs.dao.OvsTunnelInterfaceVO;
import com.cloud.network.ovs.dao.OvsTunnelNetworkDao;
import com.cloud.network.ovs.dao.OvsTunnelNetworkVO;
import com.cloud.network.ovs.dao.OvsTunnel;
import com.cloud.network.vpc.dao.VpcDao;
import com.cloud.network.vpc.VpcVO;
import com.cloud.utils.component.ManagerBase;
import com.cloud.utils.concurrency.NamedThreadFactory;
import com.cloud.utils.db.DB;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.vm.DomainRouterVO;
import com.cloud.vm.UserVmVO;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachine.State;
import com.cloud.vm.VirtualMachineProfile;
import com.cloud.vm.dao.DomainRouterDao;
import com.cloud.vm.dao.NicDao;
import com.cloud.vm.dao.UserVmDao;
@Component
@Local(value = {OvsTunnelManager.class})
@ -91,8 +93,7 @@ public class OvsTunnelManagerImpl extends ManagerBase implements OvsTunnelManage
HostDao _hostDao;
@Inject
PhysicalNetworkTrafficTypeDao _physNetTTDao;
@Inject
UserVmDao _userVmDao;
@Inject
DomainRouterDao _routerDao;
@Inject
@ -101,6 +102,16 @@ public class OvsTunnelManagerImpl extends ManagerBase implements OvsTunnelManage
OvsTunnelInterfaceDao _tunnelInterfaceDao;
@Inject
AgentManager _agentMgr;
@Inject
OvsNetworkTopologyGuru _ovsNetworkToplogyGuru;
@Inject
VpcDao _vpcDao;
@Inject
VpcManager _vpcMgr;
@Inject
protected VMInstanceDao _vmInstanceDao;
@Inject
NetworkDao _networkDao;
@Override
public boolean configure(String name, Map<String, Object> params)
@ -182,13 +193,13 @@ public class OvsTunnelManagerImpl extends ManagerBase implements OvsTunnelManage
from, to, networkId));
}
if (!r.getResult()) {
tunnel.setState("FAILED");
s_logger.warn("Create GRE tunnel failed due to " + r.getDetails()
tunnel.setState(OvsTunnel.State.Failed.name());
s_logger.warn("Create GRE tunnel from " + from + " to " + to + " failed due to " + r.getDetails()
+ s);
} else {
tunnel.setState("SUCCESS");
tunnel.setState(OvsTunnel.State.Established.name());
tunnel.setPortName(r.getInPortName());
s_logger.warn("Create GRE tunnel " + r.getDetails() + s);
s_logger.info("Create GRE tunnel from " + from + " to " + to + " succeeded." + r.getDetails() + s);
}
_tunnelNetworkDao.update(tunnel.getId(), tunnel);
}
@ -249,13 +260,14 @@ public class OvsTunnelManagerImpl extends ManagerBase implements OvsTunnelManage
int key = 0;
try {
//The GRE key is actually in the host part of the URI
// this is not true for lswitch/NiciraNvp!
String keyStr = BroadcastDomainType.getValue(network.getBroadcastUri());
// The key is most certainly and int if network is a vlan.
// !! not in the case of lswitch/pvlan/(possibly)vswitch
// So we now feel quite safe in converting it into a string
// by calling the appropriate BroadcastDomainType method
key = Integer.parseInt(keyStr);
if (keyStr.contains(".")) {
String[] parts = keyStr.split(".");
key = Integer.parseInt(parts[1]);
} else {
key = Integer.parseInt(keyStr);
}
return key;
} catch (NumberFormatException e) {
s_logger.debug("Well well, how did '" + key
@ -268,41 +280,23 @@ public class OvsTunnelManagerImpl extends ManagerBase implements OvsTunnelManage
}
@DB
protected void checkAndCreateTunnel(VirtualMachine instance, Network nw, DeployDestination dest) {
protected void checkAndCreateTunnel(Network nw, Host host) {
s_logger.debug("Creating tunnels with OVS tunnel manager");
if (instance.getType() != VirtualMachine.Type.User
&& instance.getType() != VirtualMachine.Type.DomainRouter) {
s_logger.debug("Will not work if you're not"
+ "an instance or a virtual router");
return;
}
long hostId = dest.getHost().getId();
long hostId = host.getId();
int key = getGreKey(nw);
// Find active VMs with a NIC on the target network
List<UserVmVO> vms = _userVmDao.listByNetworkIdAndStates(nw.getId(),
State.Running, State.Starting, State.Stopping, State.Unknown,
State.Migrating);
// Find routers for the network
List<DomainRouterVO> routers = _routerDao.findByNetwork(nw.getId());
List<VMInstanceVO> ins = new ArrayList<VMInstanceVO>();
if (vms != null) {
ins.addAll(vms);
}
if (routers.size() != 0) {
ins.addAll(routers);
}
String bridgeName = generateBridgeName(nw, key);
List<Long> toHostIds = new ArrayList<Long>();
List<Long> fromHostIds = new ArrayList<Long>();
for (VMInstanceVO v : ins) {
Long rh = v.getHostId();
if (rh == null || rh.longValue() == hostId) {
List<Long> networkSpannedHosts = _ovsNetworkToplogyGuru.getNetworkSpanedHosts(nw.getId());
for (Long rh : networkSpannedHosts) {
if (rh == hostId) {
continue;
}
OvsTunnelNetworkVO ta = _tunnelNetworkDao.getByFromToNetwork(hostId, rh.longValue(), nw.getId());
// Try and create the tunnel even if a previous attempt failed
if (ta == null || ta.getState().equals("FAILED")) {
if (ta == null || ta.getState().equals(OvsTunnel.State.Failed.name())) {
s_logger.debug("Attempting to create tunnel from:" + hostId + " to:" + rh.longValue());
if (ta == null) {
createTunnelRecord(hostId, rh.longValue(), nw.getId(), key);
@ -315,7 +309,7 @@ public class OvsTunnelManagerImpl extends ManagerBase implements OvsTunnelManage
ta = _tunnelNetworkDao.getByFromToNetwork(rh.longValue(),
hostId, nw.getId());
// Try and create the tunnel even if a previous attempt failed
if (ta == null || ta.getState().equals("FAILED")) {
if (ta == null || ta.getState().equals(OvsTunnel.State.Failed.name())) {
s_logger.debug("Attempting to create tunnel from:" +
rh.longValue() + " to:" + hostId);
if (ta == null) {
@ -329,9 +323,9 @@ public class OvsTunnelManagerImpl extends ManagerBase implements OvsTunnelManage
}
//TODO: Should we propagate the exception here?
try {
String myIp = getGreEndpointIP(dest.getHost(), nw);
String myIp = getGreEndpointIP(host, nw);
if (myIp == null)
throw new GreTunnelException("Unable to retrieve the source " + "endpoint for the GRE tunnel." + "Failure is on host:" + dest.getHost().getId());
throw new GreTunnelException("Unable to retrieve the source " + "endpoint for the GRE tunnel." + "Failure is on host:" + host.getId());
boolean noHost = true;
for (Long i : toHostIds) {
HostVO rHost = _hostDao.findById(i);
@ -343,7 +337,8 @@ public class OvsTunnelManagerImpl extends ManagerBase implements OvsTunnelManage
+ "Failure is on host:" + rHost.getId());
Commands cmds = new Commands(
new OvsCreateTunnelCommand(otherIp, key,
Long.valueOf(hostId), i, nw.getId(), myIp));
Long.valueOf(hostId), i, nw.getId(), myIp, bridgeName, nw.getUuid()));
s_logger.debug("Attempting to create tunnel from:" + hostId + " to:" + i + " for the network " + nw.getId());
s_logger.debug("Ask host " + hostId
+ " to create gre tunnel to " + i);
Answer[] answers = _agentMgr.send(hostId, cmds);
@ -355,21 +350,19 @@ public class OvsTunnelManagerImpl extends ManagerBase implements OvsTunnelManage
HostVO rHost = _hostDao.findById(i);
String otherIp = getGreEndpointIP(rHost, nw);
Commands cmds = new Commands(new OvsCreateTunnelCommand(myIp,
key, i, Long.valueOf(hostId), nw.getId(), otherIp));
key, i, Long.valueOf(hostId), nw.getId(), otherIp, bridgeName, nw.getUuid()));
s_logger.debug("Ask host " + i + " to create gre tunnel to "
+ hostId);
Answer[] answers = _agentMgr.send(i, cmds);
handleCreateTunnelAnswer(answers);
noHost = false;
}
// If no tunnels have been configured, perform the bridge setup
// anyway
// This will ensure VIF rules will be triggered
// anyway. This will ensure VIF rules will be triggered
if (noHost) {
Commands cmds = new Commands(new OvsSetupBridgeCommand(key,
hostId, nw.getId()));
s_logger.debug("Ask host " + hostId
+ " to configure bridge for network:" + nw.getId());
Commands cmds = new Commands(new OvsSetupBridgeCommand(bridgeName, hostId, nw.getId()));
s_logger.debug("Ask host " + hostId + " to configure bridge for network:" + nw.getId());
Answer[] answers = _agentMgr.send(hostId, cmds);
handleSetupBridgeAnswer(answers);
}
@ -384,10 +377,20 @@ public class OvsTunnelManagerImpl extends ManagerBase implements OvsTunnelManage
return true;
}
boolean isVpcEnabledForDistributedRouter(long vpcId) {
VpcVO vpc = _vpcDao.findById(vpcId);
return vpc.usesDistributedRouter();
}
@Override
public void vmCheckAndCreateTunnel(VirtualMachineProfile vm,
Network nw, DeployDestination dest) {
checkAndCreateTunnel(vm.getVirtualMachine(), nw, dest);
public void checkAndPrepareHostForTunnelNetwork(Network nw, Host host) {
if (nw.getVpcId() != null && isVpcEnabledForDistributedRouter(nw.getVpcId())) {
// check and setup host to be in full tunnel mesh with each of the network in the VPC
checkAndCreateVpcTunnelNetworks(host, nw.getVpcId());
} else {
// check and setup host to be in full tunnel mesh with the network
checkAndCreateTunnel(nw, host);
}
}
@DB
@ -440,45 +443,28 @@ public class OvsTunnelManagerImpl extends ManagerBase implements OvsTunnelManage
}
@Override
public void checkAndDestroyTunnel(VirtualMachine vm, Network nw) {
// if (!_isEnabled) {
// return;
// }
public void checkAndRemoveHostFromTunnelNetwork(Network nw, Host host) {
List<UserVmVO> userVms = _userVmDao.listByAccountIdAndHostId(vm.getAccountId(), vm.getHostId());
if (vm.getType() == VirtualMachine.Type.User) {
if (userVms.size() > 1) {
return;
}
List<DomainRouterVO> routers = _routerDao.findByNetwork(nw.getId());
for (DomainRouterVO router : routers) {
if (router.getHostId().equals(vm.getHostId())) {
return;
}
}
} else if (vm.getType() == VirtualMachine.Type.DomainRouter && userVms.size() != 0) {
return;
}
try {
/* Now we are last one on host, destroy the bridge with all
* the tunnels for this network */
int key = getGreKey(nw);
Command cmd = new OvsDestroyBridgeCommand(nw.getId(), key);
s_logger.debug("Destroying bridge for network " + nw.getId() + " on host:" + vm.getHostId());
Answer ans = _agentMgr.send(vm.getHostId(), cmd);
handleDestroyBridgeAnswer(ans, vm.getHostId(), nw.getId());
String bridgeName = generateBridgeName(nw, key);
Command cmd = new OvsDestroyBridgeCommand(nw.getId(), bridgeName);
s_logger.debug("Destroying bridge for network " + nw.getId() + " on host:" + host.getId());
Answer ans = _agentMgr.send(host.getId(), cmd);
handleDestroyBridgeAnswer(ans, host.getId(), nw.getId());
/* Then ask hosts have peer tunnel with me to destroy them */
List<OvsTunnelNetworkVO> peers =
_tunnelNetworkDao.listByToNetwork(vm.getHostId(),
_tunnelNetworkDao.listByToNetwork(host.getId(),
nw.getId());
for (OvsTunnelNetworkVO p : peers) {
// If the tunnel was not successfully created don't bother to remove it
if (p.getState().equals("SUCCESS")) {
cmd = new OvsDestroyTunnelCommand(p.getNetworkId(), key,
if (p.getState().equals(OvsTunnel.State.Established.name())) {
cmd = new OvsDestroyTunnelCommand(p.getNetworkId(), bridgeName,
p.getPortName());
s_logger.debug("Destroying tunnel to " + vm.getHostId() +
s_logger.debug("Destroying tunnel to " + host.getId() +
" from " + p.getFrom());
ans = _agentMgr.send(p.getFrom(), cmd);
handleDestroyTunnelAnswer(ans, p.getFrom(),
@ -486,8 +472,204 @@ public class OvsTunnelManagerImpl extends ManagerBase implements OvsTunnelManage
}
}
} catch (Exception e) {
s_logger.warn(String.format("Destroy tunnel(account:%1$s," + "hostId:%2$s) failed", vm.getAccountId(), vm.getHostId()), e);
s_logger.warn(String.format("Destroy tunnel failed", e));
}
}
private String generateBridgeName(Network nw, int key) {
if (nw.getVpcId() != null && isVpcEnabledForDistributedRouter(nw.getVpcId())) {
return "OVS-DR-VPC-Bridge" + nw.getVpcId();
} else {
return "OVSTunnel"+key;
}
}
private String generateBridgeNameForVpc(long vpcId) {
return "OVS-DR-VPC-Bridge" + vpcId;
}
public boolean sendVpcTopologyChangeUpdate(OvsVpcPhysicalTopologyConfigCommand updateCmd, long hostId, String bridgeName) {
try {
s_logger.debug("Sending VPC topology update to the host " + hostId);
updateCmd.setHostId(hostId);
updateCmd.setBridgeName(bridgeName);
Answer ans = _agentMgr.send(hostId, updateCmd);
if (ans.getResult()) {
s_logger.debug("Successfully updated the host " + hostId + " with latest VPC topology." );
return true;
} else {
s_logger.debug("Failed to update the host " + hostId + " with latest VPC topology." );
return false;
}
} catch (Exception e) {
s_logger.debug("Failed to updated the host " + hostId + " with latest VPC topology." );
return false;
}
}
OvsVpcPhysicalTopologyConfigCommand prepareVpcTopologyUpdate(long vpcId) {
VpcVO vpc = _vpcDao.findById(vpcId);
assert (vpc != null): "invalid vpc id";
List<? extends Network> vpcNetworks = _vpcMgr.getVpcNetworks(vpcId);
List<Long> hostIds = _ovsNetworkToplogyGuru.getVpcSpannedHosts(vpcId);
List<Long> vmIds = _ovsNetworkToplogyGuru.getAllActiveVmsInVpc(vpcId);
List<OvsVpcPhysicalTopologyConfigCommand.Host> hosts = new ArrayList<OvsVpcPhysicalTopologyConfigCommand.Host>();
List<OvsVpcPhysicalTopologyConfigCommand.Tier> tiers = new ArrayList<OvsVpcPhysicalTopologyConfigCommand.Tier>();
List<OvsVpcPhysicalTopologyConfigCommand.Vm> vms = new ArrayList<OvsVpcPhysicalTopologyConfigCommand.Vm>();
for (Long hostId : hostIds) {
HostVO hostDetails = _hostDao.findById(hostId);
String remoteIp = null;
for (Network network: vpcNetworks) {
try {
remoteIp = getGreEndpointIP(hostDetails, network);
} catch (Exception e) {
}
}
OvsVpcPhysicalTopologyConfigCommand.Host host = new OvsVpcPhysicalTopologyConfigCommand.Host(hostId, remoteIp);
hosts.add(host);
}
for (Network network: vpcNetworks) {
String key = BroadcastDomainType.getValue(network.getBroadcastUri());
long gre_key;
if (key.contains(".")) {
String[] parts = key.split(".");
gre_key = Long.parseLong(parts[1]);
} else {
try {
gre_key = Long.parseLong(BroadcastDomainType.getValue(key));
} catch (Exception e) {
return null;
}
}
NicVO nic = _nicDao.findByIp4AddressAndNetworkId(network.getGateway(), network.getId());
OvsVpcPhysicalTopologyConfigCommand.Tier tier = new OvsVpcPhysicalTopologyConfigCommand.Tier(gre_key,
network.getUuid(), network.getGateway(), nic.getMacAddress(), network.getCidr());
tiers.add(tier);
}
for (long vmId: vmIds) {
VirtualMachine vmInstance = _vmInstanceDao.findById(vmId);
List<OvsVpcPhysicalTopologyConfigCommand.Nic> vmNics = new ArrayList<OvsVpcPhysicalTopologyConfigCommand.Nic>();
for (Nic vmNic :_nicDao.listByVmId(vmId)) {
Network network = _networkDao.findById(vmNic.getNetworkId());
if (network.getTrafficType() == TrafficType.Guest) {
OvsVpcPhysicalTopologyConfigCommand.Nic nic = new OvsVpcPhysicalTopologyConfigCommand.Nic(
vmNic.getIp4Address(), vmNic.getMacAddress(), ((Long)vmNic.getNetworkId()).toString());
vmNics.add(nic);
}
}
OvsVpcPhysicalTopologyConfigCommand.Vm vm = new OvsVpcPhysicalTopologyConfigCommand.Vm(
vmInstance.getHostId(), vmNics.toArray(new OvsVpcPhysicalTopologyConfigCommand.Nic[vmNics.size()]));
vms.add(vm);
}
return new OvsVpcPhysicalTopologyConfigCommand(
hosts.toArray(new OvsVpcPhysicalTopologyConfigCommand.Host[hosts.size()]),
tiers.toArray(new OvsVpcPhysicalTopologyConfigCommand.Tier[tiers.size()]),
vms.toArray(new OvsVpcPhysicalTopologyConfigCommand.Vm[vms.size()]),
vpc.getCidr());
}
@DB
protected void checkAndCreateVpcTunnelNetworks(Host host, long vpcId) {
long hostId = host.getId();
List<? extends Network> vpcNetworks = _vpcMgr.getVpcNetworks(vpcId);
List<Long> vpcSpannedHostIds = _ovsNetworkToplogyGuru.getVpcSpannedHosts(vpcId);
String bridgeName=generateBridgeNameForVpc(vpcId);
for (Network vpcNetwork: vpcNetworks) {
int key = getGreKey(vpcNetwork);
List<Long> toHostIds = new ArrayList<Long>();
List<Long> fromHostIds = new ArrayList<Long>();
for (Long rh : vpcSpannedHostIds) {
if (rh == hostId) {
continue;
}
OvsTunnelNetworkVO ta = _tunnelNetworkDao.getByFromToNetwork(hostId, rh.longValue(), vpcNetwork.getId());
// Try and create the tunnel even if a previous attempt failed
if (ta == null || ta.getState().equals(OvsTunnel.State.Failed.name())) {
s_logger.debug("Attempting to create tunnel from:" + hostId + " to:" + rh.longValue());
if (ta == null) {
createTunnelRecord(hostId, rh.longValue(), vpcNetwork.getId(), key);
}
if (!toHostIds.contains(rh)) {
toHostIds.add(rh);
}
}
ta = _tunnelNetworkDao.getByFromToNetwork(rh.longValue(),
hostId, vpcNetwork.getId());
// Try and create the tunnel even if a previous attempt failed
if (ta == null || ta.getState().equals(OvsTunnel.State.Failed.name())) {
s_logger.debug("Attempting to create tunnel from:" +
rh.longValue() + " to:" + hostId);
if (ta == null) {
createTunnelRecord(rh.longValue(), hostId,
vpcNetwork.getId(), key);
}
if (!fromHostIds.contains(rh)) {
fromHostIds.add(rh);
}
}
}
try {
String myIp = getGreEndpointIP(host, vpcNetwork);
if (myIp == null)
throw new GreTunnelException("Unable to retrieve the source " + "endpoint for the GRE tunnel."
+ "Failure is on host:" + host.getId());
boolean noHost = true;
for (Long i : toHostIds) {
HostVO rHost = _hostDao.findById(i);
String otherIp = getGreEndpointIP(rHost, vpcNetwork);
if (otherIp == null)
throw new GreTunnelException(
"Unable to retrieve the remote "
+ "endpoint for the GRE tunnel."
+ "Failure is on host:" + rHost.getId());
Commands cmds = new Commands(
new OvsCreateTunnelCommand(otherIp, key,
Long.valueOf(hostId), i, vpcNetwork.getId(), myIp, bridgeName,
vpcNetwork.getUuid()));
s_logger.debug("Attempting to create tunnel from:" + hostId + " to:" + i + " for the network "
+ vpcNetwork.getId());
s_logger.debug("Ask host " + hostId
+ " to create gre tunnel to " + i);
Answer[] answers = _agentMgr.send(hostId, cmds);
handleCreateTunnelAnswer(answers);
noHost = false;
}
for (Long i : fromHostIds) {
HostVO rHost = _hostDao.findById(i);
String otherIp = getGreEndpointIP(rHost, vpcNetwork);
Commands cmds = new Commands(new OvsCreateTunnelCommand(myIp,
key, i, Long.valueOf(hostId), vpcNetwork.getId(), otherIp, bridgeName,
vpcNetwork.getUuid()));
s_logger.debug("Ask host " + i + " to create gre tunnel to "
+ hostId);
Answer[] answers = _agentMgr.send(i, cmds);
handleCreateTunnelAnswer(answers);
noHost = false;
}
} catch (GreTunnelException | OperationTimedoutException | AgentUnavailableException e) {
// I really thing we should do a better handling of these exceptions
s_logger.warn("Ovs Tunnel network created tunnel failed", e);
}
}
OvsVpcPhysicalTopologyConfigCommand topologyConfigCommand = prepareVpcTopologyUpdate(vpcId);
for (Long id: vpcSpannedHostIds) {
if (!sendVpcTopologyChangeUpdate(topologyConfigCommand, id, bridgeName)) {
s_logger.debug("Failed to send VPC topology change update to host : " + id + ". Moving on with rest of" +
"the host update.");
}
}
}
}

View File

@ -0,0 +1,24 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package com.cloud.network.ovs.dao;
public interface OvsTunnel {
public enum State {
Created, Established, Failed
}
}

View File

@ -62,7 +62,7 @@ public class OvsTunnelNetworkVO implements InternalIdentity {
this.key = key;
this.networkId = networkId;
this.portName = "[]";
this.state = "FAILED";
this.state = OvsTunnel.State.Created.name();
}
public void setKey(int key) {

View File

@ -224,6 +224,7 @@ def create_tunnel(session, args):
gre_key = args.pop("key")
src_host = args.pop("from")
dst_host = args.pop("to")
network_uuid = args.pop("cloudstack-network-id")
logging.debug("Entering create_tunnel")
@ -318,6 +319,7 @@ def create_tunnel(session, args):
# add flow rule to send the traffic from tunnel ports to L2 switching table only
lib.add_flow(bridge, priority=1000, in_port=tun_ofport, table=0, actions='resubmit(,1)')
lib.do_cmd([lib.VSCTL_PATH, "set", "interface", name, "options:cloudstack-network-id=%s" % network_uuid])
return "SUCCESS:%s" % name
except:

View File

@ -16,6 +16,7 @@
// under the License.
package com.cloud.hypervisor;
import com.cloud.network.dao.NetworkVO;
import java.util.List;
import java.util.Map;
@ -41,6 +42,7 @@ import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachineProfile;
import com.cloud.vm.dao.NicDao;
import com.cloud.network.dao.NetworkDao;
import com.cloud.vm.dao.NicSecondaryIpDao;
import com.cloud.vm.dao.UserVmDetailsDao;
import com.cloud.vm.dao.VMInstanceDao;
@ -52,6 +54,8 @@ public abstract class HypervisorGuruBase extends AdapterBase implements Hypervis
@Inject
NicDao _nicDao;
@Inject
NetworkDao _networkDao;
@Inject
VMInstanceDao _virtualMachineDao;
@Inject
UserVmDetailsDao _userVmDetailsDao;
@ -87,6 +91,9 @@ public abstract class HypervisorGuruBase extends AdapterBase implements Hypervis
to.setName(profile.getName());
to.setSecurityGroupEnabled(profile.isSecurityGroupEnabled());
NetworkVO network = _networkDao.findById(profile.getNetworkId());
to.setNetworkUuid(network.getUuid());
// Workaround to make sure the TO has the UUID we need for Niciri integration
NicVO nicVO = _nicDao.findById(profile.getId());
to.setUuid(nicVO.getUuid());