Cherry pick from Change-Id: I4f544b8ccf4f09db67962e4603be5a366ab0c283
Change-Id: I3dddab925dd3601ecf868e22ab25d462c56fb828
diff --git a/core/api/src/main/java/org/onosproject/net/host/HostService.java b/core/api/src/main/java/org/onosproject/net/host/HostService.java
index 817e3f6..f366334 100644
--- a/core/api/src/main/java/org/onosproject/net/host/HostService.java
+++ b/core/api/src/main/java/org/onosproject/net/host/HostService.java
@@ -23,6 +23,7 @@
import org.onosproject.net.DeviceId;
import org.onosproject.net.Host;
import org.onosproject.net.HostId;
+import org.onosproject.store.Timestamp;
import java.util.Set;
@@ -123,4 +124,13 @@
*/
void requestMac(IpAddress ip);
+ /**
+ * Returns the recent host updated time.
+ *
+ * @param hostId host identifier
+ * @return recent host updated time
+ */
+ default Timestamp getHostLastseenTime(HostId hostId) {
+ return null;
+ }
}
diff --git a/core/api/src/main/java/org/onosproject/net/host/HostStore.java b/core/api/src/main/java/org/onosproject/net/host/HostStore.java
index e73fbb7..63984e0 100644
--- a/core/api/src/main/java/org/onosproject/net/host/HostStore.java
+++ b/core/api/src/main/java/org/onosproject/net/host/HostStore.java
@@ -24,6 +24,7 @@
import org.onosproject.net.HostId;
import org.onosproject.net.provider.ProviderId;
import org.onosproject.store.Store;
+import org.onosproject.store.Timestamp;
import java.util.Set;
@@ -125,4 +126,11 @@
*/
Set<Host> getConnectedHosts(DeviceId deviceId);
+ /**
+ * Returns the last host updated time.
+ *
+ * @param hostId host identifier
+ * @return recent host updated time
+ */
+ Timestamp getHostLastseenTime(HostId hostId);
}
diff --git a/core/api/src/test/java/org/onosproject/net/host/HostServiceAdapter.java b/core/api/src/test/java/org/onosproject/net/host/HostServiceAdapter.java
index 02ee750..5242fc5 100644
--- a/core/api/src/test/java/org/onosproject/net/host/HostServiceAdapter.java
+++ b/core/api/src/test/java/org/onosproject/net/host/HostServiceAdapter.java
@@ -28,6 +28,7 @@
import org.onosproject.net.HostId;
import org.onosproject.net.HostLocation;
import org.onosproject.net.provider.ProviderId;
+import org.onosproject.store.Timestamp;
import com.google.common.collect.Sets;
@@ -101,4 +102,9 @@
public void removeListener(HostListener listener) {
}
+ @Override
+ public Timestamp getHostLastseenTime(HostId hostId) {
+ return null;
+ }
+
}
diff --git a/core/common/src/test/java/org/onosproject/store/trivial/SimpleHostStore.java b/core/common/src/test/java/org/onosproject/store/trivial/SimpleHostStore.java
index 98a9252..310655a 100644
--- a/core/common/src/test/java/org/onosproject/store/trivial/SimpleHostStore.java
+++ b/core/common/src/test/java/org/onosproject/store/trivial/SimpleHostStore.java
@@ -39,6 +39,7 @@
import org.onosproject.net.host.HostStoreDelegate;
import org.onosproject.net.provider.ProviderId;
import org.onosproject.store.AbstractStore;
+import org.onosproject.store.Timestamp;
import org.slf4j.Logger;
import java.util.HashSet;
@@ -265,4 +266,9 @@
return location;
}
}
+
+ @Override
+ public Timestamp getHostLastseenTime(HostId hostId) {
+ return null;
+ }
}
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 a18d4ad..fb992c4 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
@@ -52,6 +52,7 @@
import org.onosproject.net.host.HostStoreDelegate;
import org.onosproject.net.packet.PacketService;
import org.onosproject.net.provider.AbstractProviderService;
+import org.onosproject.store.Timestamp;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
@@ -305,6 +306,12 @@
store.removeHost(hostId);
}
+ @Override
+ public Timestamp getHostLastseenTime(HostId hostId) {
+ checkNotNull(hostId, HOST_ID_NULL);
+ return store.getHostLastseenTime(hostId);
+ }
+
// Personalized host provider service issued to the supplied provider.
private class InternalHostProviderService
extends AbstractProviderService<HostProvider>
@@ -346,9 +353,6 @@
});
}
-
-
-
// returns a HostDescription made from the union of the BasicHostConfig
// annotations if it exists
private HostDescription validateHost(HostDescription hostDescription, HostId hostId) {
diff --git a/core/store/dist/BUCK b/core/store/dist/BUCK
index 0e4731e..ec644c9 100644
--- a/core/store/dist/BUCK
+++ b/core/store/dist/BUCK
@@ -17,6 +17,7 @@
'//lib:TEST',
'//core/api:onos-api-tests',
'//core/common:onos-core-common-tests',
+ '//utils/osgi:onlab-osgi-tests',
]
osgi_jar_with_tests (
diff --git a/core/store/dist/pom.xml b/core/store/dist/pom.xml
index 5ae168f..aa948da 100644
--- a/core/store/dist/pom.xml
+++ b/core/store/dist/pom.xml
@@ -122,6 +122,13 @@
<artifactId>netty-resolver</artifactId>
<version>${netty4.version}</version>
</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/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 356df9c..7f9be04 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
@@ -21,6 +21,8 @@
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Modified;
+import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.Service;
@@ -28,6 +30,7 @@
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onlab.util.KryoNamespace;
+import org.onosproject.cfg.ComponentConfigService;
import org.onosproject.net.Annotations;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DefaultAnnotations;
@@ -42,15 +45,20 @@
import org.onosproject.net.host.HostStoreDelegate;
import org.onosproject.net.provider.ProviderId;
import org.onosproject.store.AbstractStore;
+import org.onosproject.store.Timestamp;
import org.onosproject.store.serializers.KryoNamespaces;
+import org.onosproject.store.service.EventuallyConsistentMap;
import org.onosproject.store.service.ConsistentMap;
import org.onosproject.store.service.MapEvent;
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.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import java.util.Collection;
+import java.util.Dictionary;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
@@ -58,6 +66,8 @@
import java.util.function.Predicate;
import java.util.stream.Collectors;
+import static com.google.common.base.Strings.isNullOrEmpty;
+import static org.onlab.util.Tools.get;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static org.onosproject.net.DefaultAnnotations.merge;
@@ -75,6 +85,15 @@
private final Logger log = getLogger(getClass());
+ private static final boolean DEFAULT_RECORD_TIMESTAMP_ENABLED = false;
+
+ @Property(name = "recordHostTimestamp", boolValue = DEFAULT_RECORD_TIMESTAMP_ENABLED,
+ label = "Indicates whether recoding of host timestamp is enabled or not")
+ private volatile boolean recordHostTimestamp = DEFAULT_RECORD_TIMESTAMP_ENABLED;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected ComponentConfigService configService;
+
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected StorageService storageService;
@@ -84,8 +103,11 @@
private MapEventListener<HostId, DefaultHost> hostLocationTracker =
new HostLocationTracker();
+ private EventuallyConsistentMap<HostId, Timestamp> hostsTimestamp;
+
@Activate
- public void activate() {
+ public void activate(ComponentContext context) {
+ configService.registerProperties(getClass());
KryoNamespace.Builder hostSerializer = KryoNamespace.newBuilder()
.register(KryoNamespaces.API);
@@ -97,19 +119,45 @@
hosts = hostsConsistentMap.asJavaMap();
+ hostsTimestamp = storageService.<HostId, Timestamp>eventuallyConsistentMapBuilder()
+ .withName("onos-hosts-timestamp")
+ .withTimestampProvider((k, v) -> new WallClockTimestamp())
+ .withSerializer(hostSerializer)
+ .build();
hostsConsistentMap.addListener(hostLocationTracker);
-
+ modified(context);
log.info("Started");
}
@Deactivate
public void deactivate() {
+ configService.unregisterProperties(getClass(), false);
hostsConsistentMap.removeListener(hostLocationTracker);
log.info("Stopped");
}
+ @SuppressWarnings("rawtypes")
+ @Modified
+ public void modified(ComponentContext context) {
+ if (context == null) {
+ recordHostTimestamp = DEFAULT_RECORD_TIMESTAMP_ENABLED;
+ log.info("Default config");
+ return;
+ }
+
+ Dictionary properties = context.getProperties();
+ String s = get(properties, "recordHostTimestamp");
+ boolean newRecordTimestamp = isNullOrEmpty(s) ? recordHostTimestamp : Boolean.parseBoolean(s.trim());
+
+ if (newRecordTimestamp != recordHostTimestamp) {
+ recordHostTimestamp = newRecordTimestamp;
+ }
+ }
+
+
+
private boolean shouldUpdate(DefaultHost existingHost,
ProviderId providerId,
HostId hostId,
@@ -152,6 +200,10 @@
HostId hostId,
HostDescription hostDescription,
boolean replaceIPs) {
+ if (recordHostTimestamp && !hostDescription.ipAddress().isEmpty()) {
+ hostsTimestamp.put(hostId, new WallClockTimestamp());
+ }
+
hostsConsistentMap.computeIf(hostId,
existingHost -> shouldUpdate(existingHost, providerId, hostId,
hostDescription, replaceIPs),
@@ -274,6 +326,11 @@
return ImmutableSet.copyOf(filtered);
}
+ @Override
+ public Timestamp getHostLastseenTime(HostId hostId) {
+ return hostsTimestamp.get(hostId);
+ }
+
private Set<Host> filter(Collection<DefaultHost> collection, Predicate<DefaultHost> predicate) {
return collection.stream().filter(predicate).collect(Collectors.toSet());
}
diff --git a/core/store/dist/src/test/java/org/onosproject/store/host/impl/DistributedHostStoreTest.java b/core/store/dist/src/test/java/org/onosproject/store/host/impl/DistributedHostStoreTest.java
index 9f7338d..9ca2c98 100644
--- a/core/store/dist/src/test/java/org/onosproject/store/host/impl/DistributedHostStoreTest.java
+++ b/core/store/dist/src/test/java/org/onosproject/store/host/impl/DistributedHostStoreTest.java
@@ -18,17 +18,22 @@
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+import org.onlab.osgi.ComponentContextAdapter;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
+import org.onosproject.cfg.ComponentConfigAdapter;
import org.onosproject.net.Host;
import org.onosproject.net.HostId;
import org.onosproject.net.HostLocation;
import org.onosproject.net.host.DefaultHostDescription;
import org.onosproject.net.host.HostDescription;
import org.onosproject.net.provider.ProviderId;
+import org.onosproject.store.Timestamp;
import org.onosproject.store.service.TestStorageService;
+import java.util.Dictionary;
import java.util.HashSet;
+import java.util.Hashtable;
import java.util.Set;
import static junit.framework.TestCase.assertTrue;
@@ -48,12 +53,22 @@
private static final ProviderId PID = new ProviderId("of", "foo");
+ public static final ComponentContextAdapter RECORD_HOST_TIMESTAMP = new ComponentContextAdapter() {
+ @Override
+ public Dictionary getProperties() {
+ Hashtable<String, String> props = new Hashtable<String, String>();
+ props.put("recordHostTimestamp", "true");
+ return props;
+ }
+ };
+
@Before
public void setUp() {
ecXHostStore = new DistributedHostStore();
ecXHostStore.storageService = new TestStorageService();
- ecXHostStore.activate();
+ ecXHostStore.configService = new ComponentConfigAdapter();
+ ecXHostStore.activate(RECORD_HOST_TIMESTAMP);
}
@After
@@ -82,4 +97,21 @@
assertTrue(host.ipAddresses().contains(IP2));
}
+ @Test
+ public void testRecordTimestamp() {
+ Set<IpAddress> ips = new HashSet<>();
+ ips.add(IP1);
+ ips.add(IP2);
+
+ HostDescription description = new DefaultHostDescription(HOSTID.mac(),
+ HOSTID.vlanId(),
+ HostLocation.NONE,
+ ips);
+ ecXHostStore.createOrUpdateHost(PID, HOSTID, description, false);
+ Timestamp timestamp = ecXHostStore.getHostLastseenTime(HOSTID);
+
+ assertFalse(timestamp == null);
+ assertTrue(timestamp != null);
+ }
+
}