diff --git a/api/src/com/cloud/agent/api/to/NicTO.java b/api/src/com/cloud/agent/api/to/NicTO.java index bd8f24ec563..67660c85307 100644 --- a/api/src/com/cloud/agent/api/to/NicTO.java +++ b/api/src/com/cloud/agent/api/to/NicTO.java @@ -80,4 +80,12 @@ public class NicTO extends NetworkTO { public List getNicSecIps() { return nicSecIps; } + + public String getNetworkUuid() { + return super.getUuid(); + } + + public void setNetworkUuid(String uuid) { + super.setUuid(uuid); + } } diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java index cdeedfea684..c1a77214bec 100755 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java @@ -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) { diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java index 9103b594081..3e7dfafd903 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java @@ -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 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 otherConfig = new HashMap(); @@ -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 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); diff --git a/plugins/network-elements/ovs/resources/META-INF/cloudstack/ovs/spring-ovs-context.xml b/plugins/network-elements/ovs/resources/META-INF/cloudstack/ovs/spring-ovs-context.xml index e60d93e08a1..fa56d5d1e63 100644 --- a/plugins/network-elements/ovs/resources/META-INF/cloudstack/ovs/spring-ovs-context.xml +++ b/plugins/network-elements/ovs/resources/META-INF/cloudstack/ovs/spring-ovs-context.xml @@ -38,5 +38,5 @@ - + diff --git a/plugins/network-elements/ovs/src/com/cloud/agent/api/OvsCreateTunnelCommand.java b/plugins/network-elements/ovs/src/com/cloud/agent/api/OvsCreateTunnelCommand.java index 7f151fbb680..3e08531f06a 100644 --- a/plugins/network-elements/ovs/src/com/cloud/agent/api/OvsCreateTunnelCommand.java +++ b/plugins/network-elements/ovs/src/com/cloud/agent/api/OvsCreateTunnelCommand.java @@ -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; + } } diff --git a/plugins/network-elements/ovs/src/com/cloud/agent/api/OvsDestroyBridgeCommand.java b/plugins/network-elements/ovs/src/com/cloud/agent/api/OvsDestroyBridgeCommand.java index 59b50beb9a7..f9205c5e9c9 100644 --- a/plugins/network-elements/ovs/src/com/cloud/agent/api/OvsDestroyBridgeCommand.java +++ b/plugins/network-elements/ovs/src/com/cloud/agent/api/OvsDestroyBridgeCommand.java @@ -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 diff --git a/plugins/network-elements/ovs/src/com/cloud/agent/api/OvsDestroyTunnelCommand.java b/plugins/network-elements/ovs/src/com/cloud/agent/api/OvsDestroyTunnelCommand.java index 4776a07eddd..9fc6c376034 100644 --- a/plugins/network-elements/ovs/src/com/cloud/agent/api/OvsDestroyTunnelCommand.java +++ b/plugins/network-elements/ovs/src/com/cloud/agent/api/OvsDestroyTunnelCommand.java @@ -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 diff --git a/plugins/network-elements/ovs/src/com/cloud/agent/api/OvsSetupBridgeCommand.java b/plugins/network-elements/ovs/src/com/cloud/agent/api/OvsSetupBridgeCommand.java index e3390f3c6f7..a1045980fc0 100644 --- a/plugins/network-elements/ovs/src/com/cloud/agent/api/OvsSetupBridgeCommand.java +++ b/plugins/network-elements/ovs/src/com/cloud/agent/api/OvsSetupBridgeCommand.java @@ -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() { diff --git a/plugins/network-elements/ovs/src/com/cloud/agent/api/OvsVpcPhysicalTopologyConfigCommand.java b/plugins/network-elements/ovs/src/com/cloud/agent/api/OvsVpcPhysicalTopologyConfigCommand.java new file mode 100644 index 00000000000..35d4c6e7050 --- /dev/null +++ b/plugins/network-elements/ovs/src/com/cloud/agent/api/OvsVpcPhysicalTopologyConfigCommand.java @@ -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; + } +} \ No newline at end of file diff --git a/plugins/network-elements/ovs/src/com/cloud/network/element/OvsElement.java b/plugins/network-elements/ovs/src/com/cloud/network/element/OvsElement.java index 05e81a12a93..c28d90808ed 100644 --- a/plugins/network-elements/ovs/src/com/cloud/network/element/OvsElement.java +++ b/plugins/network-elements/ovs/src/com/cloud/network/element/OvsElement.java @@ -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> 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 userVms = _userVmDao.listByAccountIdAndHostId(vm.getVirtualMachine().getAccountId(), + vm.getVirtualMachine().getHostId()); + if (vm.getType() == VirtualMachine.Type.User) { + if (userVms.size() > 1) { + return true; + } + + List 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; } diff --git a/plugins/network-elements/ovs/src/com/cloud/network/guru/OvsGuestNetworkGuru.java b/plugins/network-elements/ovs/src/com/cloud/network/guru/OvsGuestNetworkGuru.java index 8fa636da593..2814c2a0837 100644 --- a/plugins/network-elements/ovs/src/com/cloud/network/guru/OvsGuestNetworkGuru.java +++ b/plugins/network-elements/ovs/src/com/cloud/network/guru/OvsGuestNetworkGuru.java @@ -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(); + } } diff --git a/plugins/network-elements/ovs/src/com/cloud/network/ovs/OvsNetworkTopologyGuru.java b/plugins/network-elements/ovs/src/com/cloud/network/ovs/OvsNetworkTopologyGuru.java new file mode 100644 index 00000000000..c410d10c22d --- /dev/null +++ b/plugins/network-elements/ovs/src/com/cloud/network/ovs/OvsNetworkTopologyGuru.java @@ -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 getNetworkSpanedHosts(long networkId); + + /** + * get the list of hypervisor hosts id's on which VM's belonging to a VPC spans + */ + public List 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 getVpcOnHost(long hostId); + + /** + * get the list of all active Vm id's in the VPC for all ther tiers + */ + public List 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 getActiveVmsInVpcOnHost(long vpcId, long hostId); +} diff --git a/plugins/network-elements/ovs/src/com/cloud/network/ovs/OvsNetworkTopologyGuruImpl.java b/plugins/network-elements/ovs/src/com/cloud/network/ovs/OvsNetworkTopologyGuruImpl.java new file mode 100644 index 00000000000..7560e35c207 --- /dev/null +++ b/plugins/network-elements/ovs/src/com/cloud/network/ovs/OvsNetworkTopologyGuruImpl.java @@ -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 getNetworkSpanedHosts(long networkId) { + List hostIds = new ArrayList(); + // Find active VMs with a NIC on the target network + List 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 routers = _routerDao.findByNetwork(networkId); + List ins = new ArrayList(); + 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 getVpcSpannedHosts(long vpId) { + return null; + } + + @Override + public List getVpcOnHost(long hostId) { + return null; + } + + @Override + public List getAllActiveVmsInVpc(long vpcId) { + return null; + } + + @Override + public List getActiveVmsInVpcOnHost(long vpcId, long hostId) { + return null; + } +} diff --git a/plugins/network-elements/ovs/src/com/cloud/network/ovs/OvsTunnelManager.java b/plugins/network-elements/ovs/src/com/cloud/network/ovs/OvsTunnelManager.java index 118beeb58cb..cd881363ec3 100644 --- a/plugins/network-elements/ovs/src/com/cloud/network/ovs/OvsTunnelManager.java +++ b/plugins/network-elements/ovs/src/com/cloud/network/ovs/OvsTunnelManager.java @@ -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); } diff --git a/plugins/network-elements/ovs/src/com/cloud/network/ovs/OvsTunnelManagerImpl.java b/plugins/network-elements/ovs/src/com/cloud/network/ovs/OvsTunnelManagerImpl.java index 320568ba084..ae37095360f 100644 --- a/plugins/network-elements/ovs/src/com/cloud/network/ovs/OvsTunnelManagerImpl.java +++ b/plugins/network-elements/ovs/src/com/cloud/network/ovs/OvsTunnelManagerImpl.java @@ -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 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 vms = _userVmDao.listByNetworkIdAndStates(nw.getId(), - State.Running, State.Starting, State.Stopping, State.Unknown, - State.Migrating); - // Find routers for the network - List routers = _routerDao.findByNetwork(nw.getId()); - List ins = new ArrayList(); - if (vms != null) { - ins.addAll(vms); - } - if (routers.size() != 0) { - ins.addAll(routers); - } + String bridgeName = generateBridgeName(nw, key); List toHostIds = new ArrayList(); List fromHostIds = new ArrayList(); - for (VMInstanceVO v : ins) { - Long rh = v.getHostId(); - if (rh == null || rh.longValue() == hostId) { + List 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 userVms = _userVmDao.listByAccountIdAndHostId(vm.getAccountId(), vm.getHostId()); - if (vm.getType() == VirtualMachine.Type.User) { - if (userVms.size() > 1) { - return; - } - - List 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 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 vpcNetworks = _vpcMgr.getVpcNetworks(vpcId); + List hostIds = _ovsNetworkToplogyGuru.getVpcSpannedHosts(vpcId); + List vmIds = _ovsNetworkToplogyGuru.getAllActiveVmsInVpc(vpcId); + + List hosts = new ArrayList(); + List tiers = new ArrayList(); + List vms = new ArrayList(); + + 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 vmNics = new ArrayList(); + 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 vpcNetworks = _vpcMgr.getVpcNetworks(vpcId); + List vpcSpannedHostIds = _ovsNetworkToplogyGuru.getVpcSpannedHosts(vpcId); + String bridgeName=generateBridgeNameForVpc(vpcId); + + for (Network vpcNetwork: vpcNetworks) { + int key = getGreKey(vpcNetwork); + List toHostIds = new ArrayList(); + List fromHostIds = new ArrayList(); + + 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."); + } + } + } } diff --git a/plugins/network-elements/ovs/src/com/cloud/network/ovs/dao/OvsTunnel.java b/plugins/network-elements/ovs/src/com/cloud/network/ovs/dao/OvsTunnel.java new file mode 100644 index 00000000000..3216ac74214 --- /dev/null +++ b/plugins/network-elements/ovs/src/com/cloud/network/ovs/dao/OvsTunnel.java @@ -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 + } +} diff --git a/plugins/network-elements/ovs/src/com/cloud/network/ovs/dao/OvsTunnelNetworkVO.java b/plugins/network-elements/ovs/src/com/cloud/network/ovs/dao/OvsTunnelNetworkVO.java index 2826912d229..88a75913086 100644 --- a/plugins/network-elements/ovs/src/com/cloud/network/ovs/dao/OvsTunnelNetworkVO.java +++ b/plugins/network-elements/ovs/src/com/cloud/network/ovs/dao/OvsTunnelNetworkVO.java @@ -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) { diff --git a/scripts/vm/hypervisor/xenserver/ovstunnel b/scripts/vm/hypervisor/xenserver/ovstunnel index d558e972cda..64a2d362ccf 100755 --- a/scripts/vm/hypervisor/xenserver/ovstunnel +++ b/scripts/vm/hypervisor/xenserver/ovstunnel @@ -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: diff --git a/server/src/com/cloud/hypervisor/HypervisorGuruBase.java b/server/src/com/cloud/hypervisor/HypervisorGuruBase.java index 4af20c6f00d..b643ec41faf 100644 --- a/server/src/com/cloud/hypervisor/HypervisorGuruBase.java +++ b/server/src/com/cloud/hypervisor/HypervisorGuruBase.java @@ -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());