Fix for ONOS-5032 and ONOS-5034
Change-Id: Ib964252dd05754ce7069a7a82ccb1d1c29bfa978
diff --git a/core/api/src/main/java/org/onosproject/net/DefaultHost.java b/core/api/src/main/java/org/onosproject/net/DefaultHost.java
index 38a8e0d..587fc7f 100644
--- a/core/api/src/main/java/org/onosproject/net/DefaultHost.java
+++ b/core/api/src/main/java/org/onosproject/net/DefaultHost.java
@@ -16,6 +16,7 @@
package org.onosproject.net;
import org.onosproject.net.provider.ProviderId;
+import org.onosproject.store.service.WallClockTimestamp;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
@@ -36,6 +37,7 @@
private final VlanId vlan;
private final HostLocation location;
private final Set<IpAddress> ips;
+ private final WallClockTimestamp timestamp;
/**
* Creates an end-station host using the supplied information.
@@ -51,10 +53,29 @@
public DefaultHost(ProviderId providerId, HostId id, MacAddress mac,
VlanId vlan, HostLocation location, Set<IpAddress> ips,
Annotations... annotations) {
+ this(providerId, id, mac, vlan, location, ips, new WallClockTimestamp(), annotations);
+ }
+
+ /**
+ * Creates an end-station host using the supplied information.
+ *
+ * @param providerId provider identity
+ * @param id host identifier
+ * @param mac host MAC address
+ * @param vlan host VLAN identifier
+ * @param location host location
+ * @param ips host IP addresses
+ * @param timestamp last host updated time
+ * @param annotations optional key/value annotations
+ */
+ public DefaultHost(ProviderId providerId, HostId id, MacAddress mac,
+ VlanId vlan, HostLocation location, Set<IpAddress> ips,
+ WallClockTimestamp timestamp, Annotations... annotations) {
super(providerId, id, annotations);
this.mac = mac;
this.vlan = vlan;
this.location = location;
+ this.timestamp = timestamp;
this.ips = new HashSet<>(ips);
}
@@ -84,6 +105,11 @@
}
@Override
+ public WallClockTimestamp timestamp() {
+ return timestamp;
+ }
+
+ @Override
public int hashCode() {
return Objects.hash(id, mac, vlan, location);
}
@@ -114,6 +140,7 @@
.add("location", location())
.add("ipAddresses", ipAddresses())
.add("annotations", annotations())
+ .add("timestamp", timestamp())
.toString();
}
diff --git a/core/api/src/main/java/org/onosproject/net/Host.java b/core/api/src/main/java/org/onosproject/net/Host.java
index b9621b7..485b76f 100644
--- a/core/api/src/main/java/org/onosproject/net/Host.java
+++ b/core/api/src/main/java/org/onosproject/net/Host.java
@@ -18,6 +18,7 @@
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
+import org.onosproject.store.service.WallClockTimestamp;
import java.util.Set;
@@ -63,6 +64,14 @@
*/
HostLocation location();
+ /**
+ * Returns the host recent time.
+ * @return host last updated time
+ */
+ default WallClockTimestamp timestamp() {
+ return null;
+ }
// TODO: explore capturing list of recent locations to aid in mobility
}
+
diff --git a/core/api/src/main/java/org/onosproject/net/host/DefaultHostDescription.java b/core/api/src/main/java/org/onosproject/net/host/DefaultHostDescription.java
index 3503eca..74fbbe9 100644
--- a/core/api/src/main/java/org/onosproject/net/host/DefaultHostDescription.java
+++ b/core/api/src/main/java/org/onosproject/net/host/DefaultHostDescription.java
@@ -21,6 +21,7 @@
import org.onosproject.net.AbstractDescription;
import org.onosproject.net.HostLocation;
import org.onosproject.net.SparseAnnotations;
+import org.onosproject.store.service.WallClockTimestamp;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
@@ -40,6 +41,7 @@
private final VlanId vlan;
private final HostLocation location;
private final Set<IpAddress> ip;
+ private final WallClockTimestamp timestamp;
/**
* Creates a host description using the supplied information.
@@ -83,11 +85,28 @@
public DefaultHostDescription(MacAddress mac, VlanId vlan,
HostLocation location, Set<IpAddress> ip,
SparseAnnotations... annotations) {
+ this(mac, vlan, location, ip, new WallClockTimestamp(), annotations);
+ }
+
+ /**
+ * Creates a host description using the supplied information.
+ *
+ * @param mac host MAC address
+ * @param vlan host VLAN identifier
+ * @param location host location
+ * @param ip host IP addresses
+ * @param timestamp host recent updated time
+ * @param annotations optional key/value annotations map
+ */
+ public DefaultHostDescription(MacAddress mac, VlanId vlan,
+ HostLocation location, Set<IpAddress> ip,
+ WallClockTimestamp timestamp, SparseAnnotations... annotations) {
super(annotations);
this.mac = mac;
this.vlan = vlan;
this.location = location;
this.ip = ImmutableSet.copyOf(ip);
+ this.timestamp = timestamp;
}
@Override
@@ -111,12 +130,18 @@
}
@Override
+ public WallClockTimestamp timestamp() {
+ return timestamp;
+ }
+
+ @Override
public String toString() {
return toStringHelper(this)
.add("mac", mac)
.add("vlan", vlan)
.add("location", location)
.add("ipAddress", ip)
+ .add("timestamp", timestamp)
.toString();
}
@@ -139,5 +164,4 @@
}
return false;
}
-
}
diff --git a/core/api/src/main/java/org/onosproject/net/host/HostDescription.java b/core/api/src/main/java/org/onosproject/net/host/HostDescription.java
index ad423a3..dd25339 100644
--- a/core/api/src/main/java/org/onosproject/net/host/HostDescription.java
+++ b/core/api/src/main/java/org/onosproject/net/host/HostDescription.java
@@ -22,6 +22,7 @@
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
+import org.onosproject.store.service.WallClockTimestamp;
/**
* Information describing host and its location.
@@ -55,4 +56,12 @@
* @return host IP address
*/
Set<IpAddress> ipAddress();
+
+ /**
+ * Returns the host recent updated Time.
+ * @return host last updated time.
+ */
+ default WallClockTimestamp timestamp() {
+ return null;
+ }
}
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/HostCodec.java b/core/common/src/main/java/org/onosproject/codec/impl/HostCodec.java
index 8bd27c7..ec1b39a 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/HostCodec.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/HostCodec.java
@@ -39,7 +39,8 @@
final ObjectNode result = context.mapper().createObjectNode()
.put("id", host.id().toString())
.put("mac", host.mac().toString())
- .put("vlan", host.vlan().toString());
+ .put("vlan", host.vlan().toString())
+ .put("timestamp", host.timestamp().unixTimestamp());
final ArrayNode jsonIpAddresses = result.putArray("ipAddresses");
for (final IpAddress ipAddress : host.ipAddresses()) {
diff --git a/core/net/BUCK b/core/net/BUCK
index 73bbe7d..773b20a 100644
--- a/core/net/BUCK
+++ b/core/net/BUCK
@@ -12,6 +12,7 @@
'//core/common:onos-core-common',
'//core/store/dist:onos-core-dist',
'//core/store/dist:onos-core-dist-tests',
+ '//utils/osgi:onlab-osgi-tests',
]
osgi_jar_with_tests (
diff --git a/core/net/pom.xml b/core/net/pom.xml
index d30f7a6..57a39e8 100644
--- a/core/net/pom.xml
+++ b/core/net/pom.xml
@@ -125,6 +125,13 @@
<groupId>org.onosproject</groupId>
<artifactId>onos-incubator-net</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onlab-osgi</artifactId>
+ <version>${project.version}</version>
+ <classifier>tests</classifier>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</project>
diff --git a/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java b/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java
index bdb5e43..27b9b7a 100644
--- a/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java
+++ b/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java
@@ -106,6 +106,15 @@
label = "Enable removal of duplicate ip address")
private boolean allowDuplicateIps = true;
+
+ @Property(name = "monitorHosts", boolValue = false,
+ label = "Enable/Disable monitoring of hosts")
+ private boolean monitorHosts = false;
+
+ @Property(name = "probeRate", longValue = 30000,
+ label = "Set the probe Rate in milli seconds")
+ private long probeRate = 30000;
+
private HostMonitor monitor;
@@ -114,17 +123,71 @@
store.setDelegate(delegate);
eventDispatcher.addSink(HostEvent.class, listenerRegistry);
cfgService.registerProperties(getClass());
- modified(context);
networkConfigService.addListener(networkConfigListener);
monitor = new HostMonitor(packetService, this, interfaceService, edgePortService);
+ monitor.setProbeRate(probeRate);
monitor.start();
+ modified(context);
+ cfgService.registerProperties(getClass());
log.info("Started");
}
+ @Deactivate
+ public void deactivate() {
+ store.unsetDelegate(delegate);
+ eventDispatcher.removeSink(HostEvent.class);
+ networkConfigService.removeListener(networkConfigListener);
+ cfgService.unregisterProperties(getClass(), false);
+ monitor.shutdown();
+ log.info("Stopped");
+ }
+
@Modified
public void modified(ComponentContext context) {
+ boolean oldValue = monitorHosts;
+ readComponentConfiguration(context);
+ if (probeRate > 0) {
+ monitor.setProbeRate(probeRate);
+ } else {
+ log.warn("probeRate cannot be lessthan 0");
+ }
+
+ if (oldValue != monitorHosts) {
+ if (monitorHosts) {
+ startMonitoring();
+ } else {
+ stopMonitoring();
+ }
+ }
+ }
+
+ /**
+ * Extracts properties from the component configuration context.
+ *
+ * @param context the component context
+ */
+ private void readComponentConfiguration(ComponentContext context) {
Dictionary<?, ?> properties = context.getProperties();
Boolean flag;
+
+ flag = Tools.isPropertyEnabled(properties, "monitorHosts");
+ if (flag == null) {
+ log.info("monitorHosts is not enabled " +
+ "using current value of {}", monitorHosts);
+ } else {
+ monitorHosts = flag;
+ log.info("Configured. monitorHosts {}",
+ monitorHosts ? "enabled" : "disabled");
+ }
+
+ Long longValue = Tools.getLongProperty(properties, "probeRate");
+ if (longValue == null || longValue == 0) {
+ log.info("probeRate is not set sing default value of {}", probeRate);
+ } else {
+ probeRate = longValue;
+ log.info("Configured. probeRate {}", probeRate);
+ }
+
flag = Tools.isPropertyEnabled(properties, "allowDuplicateIps");
if (flag == null) {
log.info("Removal of duplicate ip address is not configured");
@@ -133,14 +196,32 @@
log.info("Removal of duplicate ip address is {}",
allowDuplicateIps ? "disabled" : "enabled");
}
+
+
}
- @Deactivate
- public void deactivate() {
- store.unsetDelegate(delegate);
- eventDispatcher.removeSink(HostEvent.class);
- networkConfigService.removeListener(networkConfigListener);
- log.info("Stopped");
+ /**
+ * Starts monitoring the hosts by IP Address.
+ *
+ */
+ private void startMonitoring() {
+ store.getHosts().forEach(host -> {
+ host.ipAddresses().forEach(ip -> {
+ monitor.addMonitoringFor(ip);
+ });
+ });
+ }
+
+ /**
+ * Stops monitoring the hosts by IP Address.
+ *
+ */
+ private void stopMonitoring() {
+ store.getHosts().forEach(host -> {
+ host.ipAddresses().forEach(ip -> {
+ monitor.stopMonitoring(ip);
+ });
+ });
}
@Override
@@ -244,8 +325,15 @@
}
store.createOrUpdateHost(provider().id(), hostId,
hostDescription, replaceIps);
+
+ if (monitorHosts) {
+ hostDescription.ipAddress().forEach(ip -> {
+ monitor.addMonitoringFor(ip);
+ });
+ }
}
+
// When a new IP is detected, remove that IP on other hosts if it exists
public void removeDuplicates(HostId hostId, HostDescription desc) {
desc.ipAddress().forEach(ip -> {
@@ -258,9 +346,7 @@
}
});
});
- }
-
-
+ }
// returns a HostDescription made from the union of the BasicHostConfig
@@ -276,6 +362,12 @@
public void hostVanished(HostId hostId) {
checkNotNull(hostId, HOST_ID_NULL);
checkValidity();
+ Host host = store.getHost(hostId);
+ if (monitorHosts) {
+ host.ipAddresses().forEach(ip -> {
+ monitor.stopMonitoring(ip);
+ });
+ }
store.removeHost(hostId);
}
@@ -323,3 +415,4 @@
}
}
}
+
diff --git a/core/net/src/main/java/org/onosproject/net/host/impl/HostMonitor.java b/core/net/src/main/java/org/onosproject/net/host/impl/HostMonitor.java
index c2bac09..747c8eb 100644
--- a/core/net/src/main/java/org/onosproject/net/host/impl/HostMonitor.java
+++ b/core/net/src/main/java/org/onosproject/net/host/impl/HostMonitor.java
@@ -150,6 +150,13 @@
hostProviders.put(provider.id(), provider);
}
+ /*
+ * Sets the probe rate.
+ */
+ void setProbeRate(long probeRate) {
+ this.probeRate = probeRate;
+ }
+
@Override
public void run(Timeout timeout) throws Exception {
monitoredAddresses.forEach(this::probe);
diff --git a/core/net/src/test/java/org/onosproject/net/host/impl/HostManagerTest.java b/core/net/src/test/java/org/onosproject/net/host/impl/HostManagerTest.java
index 1eb014f..dd97d21 100644
--- a/core/net/src/test/java/org/onosproject/net/host/impl/HostManagerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/host/impl/HostManagerTest.java
@@ -98,12 +98,14 @@
protected TestHostProvider provider;
protected HostProviderService providerService;
- private static final ComponentContextAdapter REMOVE_DUPS =
+ private static final ComponentContextAdapter REMOVE_DUPS_MONITOR =
new ComponentContextAdapter() {
@Override
public Dictionary getProperties() {
Hashtable<String, String> props = new Hashtable<>();
props.put("allowDuplicateIps", "true");
+ props.put("monitorHosts", "true");
+ props.put("probeRate", "40000");
return props;
}
};
@@ -116,28 +118,27 @@
registry = mgr;
mgr.networkConfigService = new TestNetworkConfigService();
mgr.cfgService = new ComponentConfigAdapter();
- mgr.activate(REMOVE_DUPS);
+
+ mgr.activate(REMOVE_DUPS_MONITOR);
+
mgr.addListener(listener);
provider = new TestHostProvider();
providerService = registry.register(provider);
- assertTrue("provider should be registered",
- registry.getProviders().contains(provider.id()));
+ assertTrue("provider should be registered", registry.getProviders().contains(provider.id()));
}
@After
public void tearDown() {
registry.unregister(provider);
- assertFalse("provider should not be registered",
- registry.getProviders().contains(provider.id()));
+ assertFalse("provider should not be registered", registry.getProviders().contains(provider.id()));
mgr.removeListener(listener);
mgr.deactivate();
injectEventDispatcher(mgr, null);
}
- private void detect(HostId hid, MacAddress mac, VlanId vlan,
- HostLocation loc, IpAddress ip) {
+ private void detect(HostId hid, MacAddress mac, VlanId vlan, HostLocation loc, IpAddress ip) {
HostDescription descr = new DefaultHostDescription(mac, vlan, loc, ip);
providerService.hostDetected(hid, descr, false);
assertNotNull("host should be found", mgr.getHost(hid));
@@ -217,8 +218,7 @@
assertNull("host should have been removed", mgr.getHost(HID3));
}
- private void validateHosts(
- String msg, Iterable<Host> hosts, HostId... ids) {
+ private void validateHosts(String msg, Iterable<Host> hosts, HostId... ids) {
Set<HostId> hids = Sets.newHashSet(ids);
for (Host h : hosts) {
assertTrue(msg, hids.remove(h.id()));
@@ -252,8 +252,7 @@
assertTrue("incorrect host location", mgr.getConnectedHosts(DID2).isEmpty());
}
- private static class TestHostProvider extends AbstractProvider
- implements HostProvider {
+ private static class TestHostProvider extends AbstractProvider implements HostProvider {
protected TestHostProvider() {
super(PID);
@@ -284,3 +283,4 @@
private class TestNetworkConfigService extends NetworkConfigServiceAdapter {
}
}
+
diff --git a/core/store/dist/src/main/java/org/onosproject/store/host/impl/DistributedHostStore.java b/core/store/dist/src/main/java/org/onosproject/store/host/impl/DistributedHostStore.java
index b4449ae..a359862 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/host/impl/DistributedHostStore.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/host/impl/DistributedHostStore.java
@@ -48,6 +48,7 @@
import org.onosproject.store.service.MapEventListener;
import org.onosproject.store.service.Serializer;
import org.onosproject.store.service.StorageService;
+import org.onosproject.store.service.WallClockTimestamp;
import org.slf4j.Logger;
import java.util.Collection;
@@ -87,7 +88,8 @@
@Activate
public void activate() {
KryoNamespace.Builder hostSerializer = KryoNamespace.newBuilder()
- .register(KryoNamespaces.API);
+ .register(KryoNamespaces.API)
+ .register(WallClockTimestamp.class);
hostsConsistentMap = storageService.<HostId, DefaultHost>consistentMapBuilder()
.withName("onos-hosts")
@@ -122,7 +124,9 @@
if (!Objects.equals(existingHost.providerId(), providerId) ||
!Objects.equals(existingHost.mac(), hostDescription.hwAddress()) ||
!Objects.equals(existingHost.vlan(), hostDescription.vlan()) ||
- !Objects.equals(existingHost.location(), hostDescription.location())) {
+ !Objects.equals(existingHost.location(), hostDescription.location()) ||
+ hostDescription.timestamp() == null ||
+ hostDescription.timestamp().isNewerThan(existingHost.timestamp())) {
return true;
}
@@ -173,13 +177,13 @@
} else {
annotations = hostDescription.annotations();
}
-
return new DefaultHost(providerId,
hostId,
hostDescription.hwAddress(),
hostDescription.vlan(),
location,
addresses,
+ hostDescription.timestamp(),
annotations);
});
return null;
@@ -302,3 +306,4 @@
}
}
}
+