[ONOS-7684] Support VM Live Migration (VxLAN + VLAN)
Change-Id: I4717f0af6731b41eaf3114994f2087af74c3e3f5
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHostProvider.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHostProvider.java
index 62fd2b4..6094e72 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHostProvider.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHostProvider.java
@@ -16,6 +16,8 @@
package org.onosproject.openstacknetworking.impl;
import com.google.common.base.Strings;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
@@ -30,7 +32,9 @@
import org.onosproject.mastership.MastershipService;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DefaultAnnotations;
+import org.onosproject.net.DefaultHost;
import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
import org.onosproject.net.Host;
import org.onosproject.net.HostId;
import org.onosproject.net.HostLocation;
@@ -46,6 +50,8 @@
import org.onosproject.net.host.HostService;
import org.onosproject.net.provider.AbstractProvider;
import org.onosproject.net.provider.ProviderId;
+import org.onosproject.openstacknetworking.api.InstancePort;
+import org.onosproject.openstacknetworking.api.InstancePortService;
import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
import org.onosproject.openstacknode.api.OpenstackNode;
import org.onosproject.openstacknode.api.OpenstackNodeEvent;
@@ -56,6 +62,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -77,7 +84,6 @@
private final Logger log = LoggerFactory.getLogger(getClass());
private static final String PORT_NAME_PREFIX_VM = "tap";
- private static final String PORT_NAME_PREFIX_CAVIUM = "enp";
private static final String ERR_ADD_HOST = "Failed to add host: ";
private static final String ANNOTATION_SEGMENT_ID = "segId";
private static final String SONA_HOST_SCHEME = "sona";
@@ -103,6 +109,9 @@
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected OpenstackNodeService osNodeService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected InstancePortService instancePortService;
+
private final ExecutorService deviceEventExecutor =
Executors.newSingleThreadExecutor(groupedThreads("openstacknetworking", "device-event"));
private final InternalDeviceListener internalDeviceListener = new InternalDeviceListener();
@@ -110,6 +119,9 @@
private HostProviderService hostProvider;
+ private Map<HostId, Device> hostDeviceMap = Maps.newConcurrentMap();
+ private Set<Host> migratingHosts = Sets.newConcurrentHashSet();
+
/**
* Creates OpenStack switching host provider.
*/
@@ -151,7 +163,7 @@
*
* @param port port object used in ONOS
*/
- private void processPortAdded(Port port) {
+ private void processPortAdded(Port port, Device device) {
// TODO check the node state is COMPLETE
org.openstack4j.model.network.Port osPort = osNetworkService.port(port);
if (osPort == null) {
@@ -176,6 +188,24 @@
.map(ip -> IpAddress.valueOf(ip.getIpAddress()))
.collect(Collectors.toSet());
ConnectPoint connectPoint = new ConnectPoint(port.element().id(), port.number());
+ HostId oldHostId = HostId.hostId(macAddr);
+
+ // In VM migration case, a duplicated host port (port created in at new
+ // compute node) will be detected at OVS; in this case, we will store
+ // the old host instance into migration list, and overwrite old host
+ // with new host instance issue host creation event to ONOS core
+ Device oldDevice = hostDeviceMap.get(oldHostId);
+
+ if (device != null && oldDevice != null && !oldDevice.equals(device)) {
+ Host host = hostService.getHost(oldHostId);
+ if (host != null) {
+ migratingHosts.add(host);
+ }
+ }
+
+ if (device != null) {
+ hostDeviceMap.put(oldHostId, device);
+ }
DefaultAnnotations.Builder annotations = DefaultAnnotations.builder()
.set(ANNOTATION_NETWORK_ID, osPort.getNetworkId())
@@ -187,15 +217,25 @@
}
+ long currentTime = System.currentTimeMillis();
+
HostDescription hostDesc = new DefaultHostDescription(
macAddr,
VlanId.NONE,
- new HostLocation(connectPoint, System.currentTimeMillis()),
+ new HostLocation(connectPoint, currentTime),
fixedIps,
annotations.build());
HostId hostId = HostId.hostId(macAddr);
hostProvider.hostDetected(hostId, hostDesc, false);
+
+ if (device != null && oldDevice != null && !oldDevice.equals(device)) {
+ Host oldHost = hostService.getHost(oldHostId);
+ Host newHost = new DefaultHost(oldHost.providerId(), hostId, macAddr,
+ VlanId.NONE, new HostLocation(connectPoint, currentTime),
+ fixedIps, annotations.build());
+ instancePortService.migrationPortAdded(HostBasedInstancePort.of(newHost));
+ }
}
/**
@@ -204,12 +244,37 @@
* instance through host provider by giving connect point information,
* and vanishes it.
*
- * @param port port object used in ONOS
+ * @param event device event
*/
- private void processPortRemoved(Port port) {
+ private void processPortRemoved(DeviceEvent event) {
+ Port port = event.port();
+ DeviceId deviceId = event.subject().id();
ConnectPoint connectPoint = new ConnectPoint(port.element().id(), port.number());
- hostService.getConnectedHosts(connectPoint)
- .forEach(host -> hostProvider.hostVanished(host.id()));
+
+ Set<Host> hostsToBeRemoved = hostService.getConnectedHosts(connectPoint);
+
+ if (hostsToBeRemoved.size() == 0) {
+
+ for (Host host : migratingHosts) {
+ if (host.location() == null) {
+ continue;
+ }
+ String hostLocation = host.location().toString();
+ StringBuilder deviceIdWithPort = new StringBuilder();
+ deviceIdWithPort.append(deviceId.toString());
+ deviceIdWithPort.append("/");
+ deviceIdWithPort.append(port.number().toString());
+
+ if (hostLocation.equals(deviceIdWithPort.toString())) {
+ InstancePort instPort = HostBasedInstancePort.of(host);
+ instancePortService.migrationPortRemoved(instPort);
+ migratingHosts.remove(host);
+ }
+ }
+
+ } else {
+ hostsToBeRemoved.forEach(host -> hostProvider.hostVanished(host.id()));
+ }
}
/**
@@ -274,7 +339,7 @@
log.debug("Instance port {} is detected from {}",
event.port().annotations().value(PORT_NAME),
event.subject().id());
- processPortAdded(event.port());
+ processPortAdded(event.port(), event.subject());
});
}
@@ -290,7 +355,7 @@
log.debug("Instance port {} is removed from {}",
event.port().annotations().value(PORT_NAME),
event.subject().id());
- processPortRemoved(event.port());
+ processPortRemoved(event);
});
}
@@ -343,7 +408,8 @@
log.debug("Instance port {} is detected from {}",
port.annotations().value(PORT_NAME),
osNode.hostname());
- processPortAdded(port);
+ processPortAdded(port,
+ deviceService.getDevice(osNode.intgBridge()));
});
portNamePrefixMap().values().forEach(portNamePrefix -> {
@@ -355,7 +421,8 @@
log.debug("Instance port {} is detected from {}",
port.annotations().value(portNamePrefix),
osNode.hostname());
- processPortAdded(port);
+ processPortAdded(port,
+ deviceService.getDevice(osNode.intgBridge()));
});
});