Deepa Vaddireddy
Committed by sdn

Fix for ONOS-5032 and ONOS-5034

Change-Id: Ib964252dd05754ce7069a7a82ccb1d1c29bfa978
...@@ -24,6 +24,7 @@ import org.onosproject.cli.AbstractShellCommand; ...@@ -24,6 +24,7 @@ import org.onosproject.cli.AbstractShellCommand;
24 import org.onosproject.net.Host; 24 import org.onosproject.net.Host;
25 import org.onosproject.net.host.HostService; 25 import org.onosproject.net.host.HostService;
26 import org.onosproject.utils.Comparators; 26 import org.onosproject.utils.Comparators;
27 +import org.onlab.util.Tools;
27 28
28 import java.util.Collections; 29 import java.util.Collections;
29 import java.util.List; 30 import java.util.List;
...@@ -38,7 +39,7 @@ import static com.google.common.collect.Lists.newArrayList; ...@@ -38,7 +39,7 @@ import static com.google.common.collect.Lists.newArrayList;
38 public class HostsListCommand extends AbstractShellCommand { 39 public class HostsListCommand extends AbstractShellCommand {
39 40
40 private static final String FMT = 41 private static final String FMT =
41 - "id=%s, mac=%s, location=%s/%s, vlan=%s, ip(s)=%s%s"; 42 + "id=%s, mac=%s, location=%s/%s, vlan=%s, ip(s)=%s%s, last seen time=%s";
42 43
43 private static final String FMT_SHORT = 44 private static final String FMT_SHORT =
44 "id=%s, mac=%s, location=%s/%s, vlan=%s, ip(s)=%s"; 45 "id=%s, mac=%s, location=%s/%s, vlan=%s, ip(s)=%s";
...@@ -93,7 +94,9 @@ public class HostsListCommand extends AbstractShellCommand { ...@@ -93,7 +94,9 @@ public class HostsListCommand extends AbstractShellCommand {
93 } else { 94 } else {
94 print(FMT, host.id(), host.mac(), 95 print(FMT, host.id(), host.mac(),
95 host.location().deviceId(), host.location().port(), 96 host.location().deviceId(), host.location().port(),
96 - host.vlan(), host.ipAddresses(), annotations(host.annotations())); 97 + host.vlan(), host.ipAddresses(), annotations(host.annotations()),
98 + Tools.timeAgo(host.timestamp().unixTimestamp()));
97 } 99 }
98 } 100 }
99 } 101 }
102 +
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
16 package org.onosproject.net; 16 package org.onosproject.net;
17 17
18 import org.onosproject.net.provider.ProviderId; 18 import org.onosproject.net.provider.ProviderId;
19 +import org.onosproject.store.service.WallClockTimestamp;
19 import org.onlab.packet.IpAddress; 20 import org.onlab.packet.IpAddress;
20 import org.onlab.packet.MacAddress; 21 import org.onlab.packet.MacAddress;
21 import org.onlab.packet.VlanId; 22 import org.onlab.packet.VlanId;
...@@ -36,6 +37,7 @@ public class DefaultHost extends AbstractElement implements Host { ...@@ -36,6 +37,7 @@ public class DefaultHost extends AbstractElement implements Host {
36 private final VlanId vlan; 37 private final VlanId vlan;
37 private final HostLocation location; 38 private final HostLocation location;
38 private final Set<IpAddress> ips; 39 private final Set<IpAddress> ips;
40 + private final WallClockTimestamp timestamp;
39 41
40 /** 42 /**
41 * Creates an end-station host using the supplied information. 43 * Creates an end-station host using the supplied information.
...@@ -51,10 +53,29 @@ public class DefaultHost extends AbstractElement implements Host { ...@@ -51,10 +53,29 @@ public class DefaultHost extends AbstractElement implements Host {
51 public DefaultHost(ProviderId providerId, HostId id, MacAddress mac, 53 public DefaultHost(ProviderId providerId, HostId id, MacAddress mac,
52 VlanId vlan, HostLocation location, Set<IpAddress> ips, 54 VlanId vlan, HostLocation location, Set<IpAddress> ips,
53 Annotations... annotations) { 55 Annotations... annotations) {
56 + this(providerId, id, mac, vlan, location, ips, new WallClockTimestamp(), annotations);
57 + }
58 +
59 + /**
60 + * Creates an end-station host using the supplied information.
61 + *
62 + * @param providerId provider identity
63 + * @param id host identifier
64 + * @param mac host MAC address
65 + * @param vlan host VLAN identifier
66 + * @param location host location
67 + * @param ips host IP addresses
68 + * @param timestamp last host updated time
69 + * @param annotations optional key/value annotations
70 + */
71 + public DefaultHost(ProviderId providerId, HostId id, MacAddress mac,
72 + VlanId vlan, HostLocation location, Set<IpAddress> ips,
73 + WallClockTimestamp timestamp, Annotations... annotations) {
54 super(providerId, id, annotations); 74 super(providerId, id, annotations);
55 this.mac = mac; 75 this.mac = mac;
56 this.vlan = vlan; 76 this.vlan = vlan;
57 this.location = location; 77 this.location = location;
78 + this.timestamp = timestamp;
58 this.ips = new HashSet<>(ips); 79 this.ips = new HashSet<>(ips);
59 } 80 }
60 81
...@@ -84,6 +105,11 @@ public class DefaultHost extends AbstractElement implements Host { ...@@ -84,6 +105,11 @@ public class DefaultHost extends AbstractElement implements Host {
84 } 105 }
85 106
86 @Override 107 @Override
108 + public WallClockTimestamp timestamp() {
109 + return timestamp;
110 + }
111 +
112 + @Override
87 public int hashCode() { 113 public int hashCode() {
88 return Objects.hash(id, mac, vlan, location); 114 return Objects.hash(id, mac, vlan, location);
89 } 115 }
...@@ -114,6 +140,7 @@ public class DefaultHost extends AbstractElement implements Host { ...@@ -114,6 +140,7 @@ public class DefaultHost extends AbstractElement implements Host {
114 .add("location", location()) 140 .add("location", location())
115 .add("ipAddresses", ipAddresses()) 141 .add("ipAddresses", ipAddresses())
116 .add("annotations", annotations()) 142 .add("annotations", annotations())
143 + .add("timestamp", timestamp())
117 .toString(); 144 .toString();
118 } 145 }
119 146
......
...@@ -18,6 +18,7 @@ package org.onosproject.net; ...@@ -18,6 +18,7 @@ package org.onosproject.net;
18 import org.onlab.packet.IpAddress; 18 import org.onlab.packet.IpAddress;
19 import org.onlab.packet.MacAddress; 19 import org.onlab.packet.MacAddress;
20 import org.onlab.packet.VlanId; 20 import org.onlab.packet.VlanId;
21 +import org.onosproject.store.service.WallClockTimestamp;
21 22
22 import java.util.Set; 23 import java.util.Set;
23 24
...@@ -63,6 +64,14 @@ public interface Host extends Element { ...@@ -63,6 +64,14 @@ public interface Host extends Element {
63 */ 64 */
64 HostLocation location(); 65 HostLocation location();
65 66
67 + /**
68 + * Returns the host recent time.
69 + * @return host last updated time
70 + */
71 + default WallClockTimestamp timestamp() {
72 + return null;
73 + }
66 // TODO: explore capturing list of recent locations to aid in mobility 74 // TODO: explore capturing list of recent locations to aid in mobility
67 75
68 } 76 }
77 +
......
...@@ -21,6 +21,7 @@ import java.util.Set; ...@@ -21,6 +21,7 @@ import java.util.Set;
21 import org.onosproject.net.AbstractDescription; 21 import org.onosproject.net.AbstractDescription;
22 import org.onosproject.net.HostLocation; 22 import org.onosproject.net.HostLocation;
23 import org.onosproject.net.SparseAnnotations; 23 import org.onosproject.net.SparseAnnotations;
24 +import org.onosproject.store.service.WallClockTimestamp;
24 import org.onlab.packet.IpAddress; 25 import org.onlab.packet.IpAddress;
25 import org.onlab.packet.MacAddress; 26 import org.onlab.packet.MacAddress;
26 import org.onlab.packet.VlanId; 27 import org.onlab.packet.VlanId;
...@@ -40,6 +41,7 @@ public class DefaultHostDescription extends AbstractDescription ...@@ -40,6 +41,7 @@ public class DefaultHostDescription extends AbstractDescription
40 private final VlanId vlan; 41 private final VlanId vlan;
41 private final HostLocation location; 42 private final HostLocation location;
42 private final Set<IpAddress> ip; 43 private final Set<IpAddress> ip;
44 + private final WallClockTimestamp timestamp;
43 45
44 /** 46 /**
45 * Creates a host description using the supplied information. 47 * Creates a host description using the supplied information.
...@@ -83,11 +85,28 @@ public class DefaultHostDescription extends AbstractDescription ...@@ -83,11 +85,28 @@ public class DefaultHostDescription extends AbstractDescription
83 public DefaultHostDescription(MacAddress mac, VlanId vlan, 85 public DefaultHostDescription(MacAddress mac, VlanId vlan,
84 HostLocation location, Set<IpAddress> ip, 86 HostLocation location, Set<IpAddress> ip,
85 SparseAnnotations... annotations) { 87 SparseAnnotations... annotations) {
88 + this(mac, vlan, location, ip, new WallClockTimestamp(), annotations);
89 + }
90 +
91 + /**
92 + * Creates a host description using the supplied information.
93 + *
94 + * @param mac host MAC address
95 + * @param vlan host VLAN identifier
96 + * @param location host location
97 + * @param ip host IP addresses
98 + * @param timestamp host recent updated time
99 + * @param annotations optional key/value annotations map
100 + */
101 + public DefaultHostDescription(MacAddress mac, VlanId vlan,
102 + HostLocation location, Set<IpAddress> ip,
103 + WallClockTimestamp timestamp, SparseAnnotations... annotations) {
86 super(annotations); 104 super(annotations);
87 this.mac = mac; 105 this.mac = mac;
88 this.vlan = vlan; 106 this.vlan = vlan;
89 this.location = location; 107 this.location = location;
90 this.ip = ImmutableSet.copyOf(ip); 108 this.ip = ImmutableSet.copyOf(ip);
109 + this.timestamp = timestamp;
91 } 110 }
92 111
93 @Override 112 @Override
...@@ -111,12 +130,18 @@ public class DefaultHostDescription extends AbstractDescription ...@@ -111,12 +130,18 @@ public class DefaultHostDescription extends AbstractDescription
111 } 130 }
112 131
113 @Override 132 @Override
133 + public WallClockTimestamp timestamp() {
134 + return timestamp;
135 + }
136 +
137 + @Override
114 public String toString() { 138 public String toString() {
115 return toStringHelper(this) 139 return toStringHelper(this)
116 .add("mac", mac) 140 .add("mac", mac)
117 .add("vlan", vlan) 141 .add("vlan", vlan)
118 .add("location", location) 142 .add("location", location)
119 .add("ipAddress", ip) 143 .add("ipAddress", ip)
144 + .add("timestamp", timestamp)
120 .toString(); 145 .toString();
121 } 146 }
122 147
...@@ -139,5 +164,4 @@ public class DefaultHostDescription extends AbstractDescription ...@@ -139,5 +164,4 @@ public class DefaultHostDescription extends AbstractDescription
139 } 164 }
140 return false; 165 return false;
141 } 166 }
142 -
143 } 167 }
......
...@@ -22,6 +22,7 @@ import org.onosproject.net.HostLocation; ...@@ -22,6 +22,7 @@ import org.onosproject.net.HostLocation;
22 import org.onlab.packet.IpAddress; 22 import org.onlab.packet.IpAddress;
23 import org.onlab.packet.MacAddress; 23 import org.onlab.packet.MacAddress;
24 import org.onlab.packet.VlanId; 24 import org.onlab.packet.VlanId;
25 +import org.onosproject.store.service.WallClockTimestamp;
25 26
26 /** 27 /**
27 * Information describing host and its location. 28 * Information describing host and its location.
...@@ -55,4 +56,12 @@ public interface HostDescription extends Description { ...@@ -55,4 +56,12 @@ public interface HostDescription extends Description {
55 * @return host IP address 56 * @return host IP address
56 */ 57 */
57 Set<IpAddress> ipAddress(); 58 Set<IpAddress> ipAddress();
59 +
60 + /**
61 + * Returns the host recent updated Time.
62 + * @return host last updated time.
63 + */
64 + default WallClockTimestamp timestamp() {
65 + return null;
66 + }
58 } 67 }
......
...@@ -39,7 +39,8 @@ public final class HostCodec extends AnnotatedCodec<Host> { ...@@ -39,7 +39,8 @@ public final class HostCodec extends AnnotatedCodec<Host> {
39 final ObjectNode result = context.mapper().createObjectNode() 39 final ObjectNode result = context.mapper().createObjectNode()
40 .put("id", host.id().toString()) 40 .put("id", host.id().toString())
41 .put("mac", host.mac().toString()) 41 .put("mac", host.mac().toString())
42 - .put("vlan", host.vlan().toString()); 42 + .put("vlan", host.vlan().toString())
43 + .put("timestamp", host.timestamp().unixTimestamp());
43 44
44 final ArrayNode jsonIpAddresses = result.putArray("ipAddresses"); 45 final ArrayNode jsonIpAddresses = result.putArray("ipAddresses");
45 for (final IpAddress ipAddress : host.ipAddresses()) { 46 for (final IpAddress ipAddress : host.ipAddresses()) {
......
...@@ -12,6 +12,7 @@ TEST_DEPS = [ ...@@ -12,6 +12,7 @@ TEST_DEPS = [
12 '//core/common:onos-core-common', 12 '//core/common:onos-core-common',
13 '//core/store/dist:onos-core-dist', 13 '//core/store/dist:onos-core-dist',
14 '//core/store/dist:onos-core-dist-tests', 14 '//core/store/dist:onos-core-dist-tests',
15 + '//utils/osgi:onlab-osgi-tests',
15 ] 16 ]
16 17
17 osgi_jar_with_tests ( 18 osgi_jar_with_tests (
......
...@@ -125,6 +125,13 @@ ...@@ -125,6 +125,13 @@
125 <groupId>org.onosproject</groupId> 125 <groupId>org.onosproject</groupId>
126 <artifactId>onos-incubator-net</artifactId> 126 <artifactId>onos-incubator-net</artifactId>
127 </dependency> 127 </dependency>
128 + <dependency>
129 + <groupId>org.onosproject</groupId>
130 + <artifactId>onlab-osgi</artifactId>
131 + <version>${project.version}</version>
132 + <classifier>tests</classifier>
133 + <scope>test</scope>
134 + </dependency>
128 </dependencies> 135 </dependencies>
129 136
130 </project> 137 </project>
......
...@@ -106,6 +106,15 @@ public class HostManager ...@@ -106,6 +106,15 @@ public class HostManager
106 label = "Enable removal of duplicate ip address") 106 label = "Enable removal of duplicate ip address")
107 107
108 private boolean allowDuplicateIps = true; 108 private boolean allowDuplicateIps = true;
109 +
110 + @Property(name = "monitorHosts", boolValue = false,
111 + label = "Enable/Disable monitoring of hosts")
112 + private boolean monitorHosts = false;
113 +
114 + @Property(name = "probeRate", longValue = 30000,
115 + label = "Set the probe Rate in milli seconds")
116 + private long probeRate = 30000;
117 +
109 private HostMonitor monitor; 118 private HostMonitor monitor;
110 119
111 120
...@@ -114,17 +123,71 @@ public class HostManager ...@@ -114,17 +123,71 @@ public class HostManager
114 store.setDelegate(delegate); 123 store.setDelegate(delegate);
115 eventDispatcher.addSink(HostEvent.class, listenerRegistry); 124 eventDispatcher.addSink(HostEvent.class, listenerRegistry);
116 cfgService.registerProperties(getClass()); 125 cfgService.registerProperties(getClass());
117 - modified(context);
118 networkConfigService.addListener(networkConfigListener); 126 networkConfigService.addListener(networkConfigListener);
119 monitor = new HostMonitor(packetService, this, interfaceService, edgePortService); 127 monitor = new HostMonitor(packetService, this, interfaceService, edgePortService);
128 + monitor.setProbeRate(probeRate);
120 monitor.start(); 129 monitor.start();
130 + modified(context);
131 + cfgService.registerProperties(getClass());
121 log.info("Started"); 132 log.info("Started");
122 } 133 }
123 134
135 + @Deactivate
136 + public void deactivate() {
137 + store.unsetDelegate(delegate);
138 + eventDispatcher.removeSink(HostEvent.class);
139 + networkConfigService.removeListener(networkConfigListener);
140 + cfgService.unregisterProperties(getClass(), false);
141 + monitor.shutdown();
142 + log.info("Stopped");
143 + }
144 +
124 @Modified 145 @Modified
125 public void modified(ComponentContext context) { 146 public void modified(ComponentContext context) {
147 + boolean oldValue = monitorHosts;
148 + readComponentConfiguration(context);
149 + if (probeRate > 0) {
150 + monitor.setProbeRate(probeRate);
151 + } else {
152 + log.warn("probeRate cannot be lessthan 0");
153 + }
154 +
155 + if (oldValue != monitorHosts) {
156 + if (monitorHosts) {
157 + startMonitoring();
158 + } else {
159 + stopMonitoring();
160 + }
161 + }
162 + }
163 +
164 + /**
165 + * Extracts properties from the component configuration context.
166 + *
167 + * @param context the component context
168 + */
169 + private void readComponentConfiguration(ComponentContext context) {
126 Dictionary<?, ?> properties = context.getProperties(); 170 Dictionary<?, ?> properties = context.getProperties();
127 Boolean flag; 171 Boolean flag;
172 +
173 + flag = Tools.isPropertyEnabled(properties, "monitorHosts");
174 + if (flag == null) {
175 + log.info("monitorHosts is not enabled " +
176 + "using current value of {}", monitorHosts);
177 + } else {
178 + monitorHosts = flag;
179 + log.info("Configured. monitorHosts {}",
180 + monitorHosts ? "enabled" : "disabled");
181 + }
182 +
183 + Long longValue = Tools.getLongProperty(properties, "probeRate");
184 + if (longValue == null || longValue == 0) {
185 + log.info("probeRate is not set sing default value of {}", probeRate);
186 + } else {
187 + probeRate = longValue;
188 + log.info("Configured. probeRate {}", probeRate);
189 + }
190 +
128 flag = Tools.isPropertyEnabled(properties, "allowDuplicateIps"); 191 flag = Tools.isPropertyEnabled(properties, "allowDuplicateIps");
129 if (flag == null) { 192 if (flag == null) {
130 log.info("Removal of duplicate ip address is not configured"); 193 log.info("Removal of duplicate ip address is not configured");
...@@ -133,14 +196,32 @@ public class HostManager ...@@ -133,14 +196,32 @@ public class HostManager
133 log.info("Removal of duplicate ip address is {}", 196 log.info("Removal of duplicate ip address is {}",
134 allowDuplicateIps ? "disabled" : "enabled"); 197 allowDuplicateIps ? "disabled" : "enabled");
135 } 198 }
199 +
200 +
136 } 201 }
137 202
138 - @Deactivate 203 + /**
139 - public void deactivate() { 204 + * Starts monitoring the hosts by IP Address.
140 - store.unsetDelegate(delegate); 205 + *
141 - eventDispatcher.removeSink(HostEvent.class); 206 + */
142 - networkConfigService.removeListener(networkConfigListener); 207 + private void startMonitoring() {
143 - log.info("Stopped"); 208 + store.getHosts().forEach(host -> {
209 + host.ipAddresses().forEach(ip -> {
210 + monitor.addMonitoringFor(ip);
211 + });
212 + });
213 + }
214 +
215 + /**
216 + * Stops monitoring the hosts by IP Address.
217 + *
218 + */
219 + private void stopMonitoring() {
220 + store.getHosts().forEach(host -> {
221 + host.ipAddresses().forEach(ip -> {
222 + monitor.stopMonitoring(ip);
223 + });
224 + });
144 } 225 }
145 226
146 @Override 227 @Override
...@@ -244,8 +325,15 @@ public class HostManager ...@@ -244,8 +325,15 @@ public class HostManager
244 } 325 }
245 store.createOrUpdateHost(provider().id(), hostId, 326 store.createOrUpdateHost(provider().id(), hostId,
246 hostDescription, replaceIps); 327 hostDescription, replaceIps);
328 +
329 + if (monitorHosts) {
330 + hostDescription.ipAddress().forEach(ip -> {
331 + monitor.addMonitoringFor(ip);
332 + });
333 + }
247 } 334 }
248 335
336 +
249 // When a new IP is detected, remove that IP on other hosts if it exists 337 // When a new IP is detected, remove that IP on other hosts if it exists
250 public void removeDuplicates(HostId hostId, HostDescription desc) { 338 public void removeDuplicates(HostId hostId, HostDescription desc) {
251 desc.ipAddress().forEach(ip -> { 339 desc.ipAddress().forEach(ip -> {
...@@ -258,9 +346,7 @@ public class HostManager ...@@ -258,9 +346,7 @@ public class HostManager
258 } 346 }
259 }); 347 });
260 }); 348 });
261 - } 349 + }
262 -
263 -
264 350
265 351
266 // returns a HostDescription made from the union of the BasicHostConfig 352 // returns a HostDescription made from the union of the BasicHostConfig
...@@ -276,6 +362,12 @@ public class HostManager ...@@ -276,6 +362,12 @@ public class HostManager
276 public void hostVanished(HostId hostId) { 362 public void hostVanished(HostId hostId) {
277 checkNotNull(hostId, HOST_ID_NULL); 363 checkNotNull(hostId, HOST_ID_NULL);
278 checkValidity(); 364 checkValidity();
365 + Host host = store.getHost(hostId);
366 + if (monitorHosts) {
367 + host.ipAddresses().forEach(ip -> {
368 + monitor.stopMonitoring(ip);
369 + });
370 + }
279 store.removeHost(hostId); 371 store.removeHost(hostId);
280 } 372 }
281 373
...@@ -323,3 +415,4 @@ public class HostManager ...@@ -323,3 +415,4 @@ public class HostManager
323 } 415 }
324 } 416 }
325 } 417 }
418 +
......
...@@ -150,6 +150,13 @@ public class HostMonitor implements TimerTask { ...@@ -150,6 +150,13 @@ public class HostMonitor implements TimerTask {
150 hostProviders.put(provider.id(), provider); 150 hostProviders.put(provider.id(), provider);
151 } 151 }
152 152
153 + /*
154 + * Sets the probe rate.
155 + */
156 + void setProbeRate(long probeRate) {
157 + this.probeRate = probeRate;
158 + }
159 +
153 @Override 160 @Override
154 public void run(Timeout timeout) throws Exception { 161 public void run(Timeout timeout) throws Exception {
155 monitoredAddresses.forEach(this::probe); 162 monitoredAddresses.forEach(this::probe);
......
...@@ -98,12 +98,14 @@ public class HostManagerTest { ...@@ -98,12 +98,14 @@ public class HostManagerTest {
98 protected TestHostProvider provider; 98 protected TestHostProvider provider;
99 protected HostProviderService providerService; 99 protected HostProviderService providerService;
100 100
101 - private static final ComponentContextAdapter REMOVE_DUPS = 101 + private static final ComponentContextAdapter REMOVE_DUPS_MONITOR =
102 new ComponentContextAdapter() { 102 new ComponentContextAdapter() {
103 @Override 103 @Override
104 public Dictionary getProperties() { 104 public Dictionary getProperties() {
105 Hashtable<String, String> props = new Hashtable<>(); 105 Hashtable<String, String> props = new Hashtable<>();
106 props.put("allowDuplicateIps", "true"); 106 props.put("allowDuplicateIps", "true");
107 + props.put("monitorHosts", "true");
108 + props.put("probeRate", "40000");
107 return props; 109 return props;
108 } 110 }
109 }; 111 };
...@@ -116,28 +118,27 @@ public class HostManagerTest { ...@@ -116,28 +118,27 @@ public class HostManagerTest {
116 registry = mgr; 118 registry = mgr;
117 mgr.networkConfigService = new TestNetworkConfigService(); 119 mgr.networkConfigService = new TestNetworkConfigService();
118 mgr.cfgService = new ComponentConfigAdapter(); 120 mgr.cfgService = new ComponentConfigAdapter();
119 - mgr.activate(REMOVE_DUPS); 121 +
122 + mgr.activate(REMOVE_DUPS_MONITOR);
123 +
120 mgr.addListener(listener); 124 mgr.addListener(listener);
121 125
122 provider = new TestHostProvider(); 126 provider = new TestHostProvider();
123 providerService = registry.register(provider); 127 providerService = registry.register(provider);
124 - assertTrue("provider should be registered", 128 + assertTrue("provider should be registered", registry.getProviders().contains(provider.id()));
125 - registry.getProviders().contains(provider.id()));
126 } 129 }
127 130
128 @After 131 @After
129 public void tearDown() { 132 public void tearDown() {
130 registry.unregister(provider); 133 registry.unregister(provider);
131 - assertFalse("provider should not be registered", 134 + assertFalse("provider should not be registered", registry.getProviders().contains(provider.id()));
132 - registry.getProviders().contains(provider.id()));
133 135
134 mgr.removeListener(listener); 136 mgr.removeListener(listener);
135 mgr.deactivate(); 137 mgr.deactivate();
136 injectEventDispatcher(mgr, null); 138 injectEventDispatcher(mgr, null);
137 } 139 }
138 140
139 - private void detect(HostId hid, MacAddress mac, VlanId vlan, 141 + private void detect(HostId hid, MacAddress mac, VlanId vlan, HostLocation loc, IpAddress ip) {
140 - HostLocation loc, IpAddress ip) {
141 HostDescription descr = new DefaultHostDescription(mac, vlan, loc, ip); 142 HostDescription descr = new DefaultHostDescription(mac, vlan, loc, ip);
142 providerService.hostDetected(hid, descr, false); 143 providerService.hostDetected(hid, descr, false);
143 assertNotNull("host should be found", mgr.getHost(hid)); 144 assertNotNull("host should be found", mgr.getHost(hid));
...@@ -217,8 +218,7 @@ public class HostManagerTest { ...@@ -217,8 +218,7 @@ public class HostManagerTest {
217 assertNull("host should have been removed", mgr.getHost(HID3)); 218 assertNull("host should have been removed", mgr.getHost(HID3));
218 } 219 }
219 220
220 - private void validateHosts( 221 + private void validateHosts(String msg, Iterable<Host> hosts, HostId... ids) {
221 - String msg, Iterable<Host> hosts, HostId... ids) {
222 Set<HostId> hids = Sets.newHashSet(ids); 222 Set<HostId> hids = Sets.newHashSet(ids);
223 for (Host h : hosts) { 223 for (Host h : hosts) {
224 assertTrue(msg, hids.remove(h.id())); 224 assertTrue(msg, hids.remove(h.id()));
...@@ -252,8 +252,7 @@ public class HostManagerTest { ...@@ -252,8 +252,7 @@ public class HostManagerTest {
252 assertTrue("incorrect host location", mgr.getConnectedHosts(DID2).isEmpty()); 252 assertTrue("incorrect host location", mgr.getConnectedHosts(DID2).isEmpty());
253 } 253 }
254 254
255 - private static class TestHostProvider extends AbstractProvider 255 + private static class TestHostProvider extends AbstractProvider implements HostProvider {
256 - implements HostProvider {
257 256
258 protected TestHostProvider() { 257 protected TestHostProvider() {
259 super(PID); 258 super(PID);
...@@ -284,3 +283,4 @@ public class HostManagerTest { ...@@ -284,3 +283,4 @@ public class HostManagerTest {
284 private class TestNetworkConfigService extends NetworkConfigServiceAdapter { 283 private class TestNetworkConfigService extends NetworkConfigServiceAdapter {
285 } 284 }
286 } 285 }
286 +
......
...@@ -48,6 +48,7 @@ import org.onosproject.store.service.MapEvent; ...@@ -48,6 +48,7 @@ import org.onosproject.store.service.MapEvent;
48 import org.onosproject.store.service.MapEventListener; 48 import org.onosproject.store.service.MapEventListener;
49 import org.onosproject.store.service.Serializer; 49 import org.onosproject.store.service.Serializer;
50 import org.onosproject.store.service.StorageService; 50 import org.onosproject.store.service.StorageService;
51 +import org.onosproject.store.service.WallClockTimestamp;
51 import org.slf4j.Logger; 52 import org.slf4j.Logger;
52 53
53 import java.util.Collection; 54 import java.util.Collection;
...@@ -87,7 +88,8 @@ public class DistributedHostStore ...@@ -87,7 +88,8 @@ public class DistributedHostStore
87 @Activate 88 @Activate
88 public void activate() { 89 public void activate() {
89 KryoNamespace.Builder hostSerializer = KryoNamespace.newBuilder() 90 KryoNamespace.Builder hostSerializer = KryoNamespace.newBuilder()
90 - .register(KryoNamespaces.API); 91 + .register(KryoNamespaces.API)
92 + .register(WallClockTimestamp.class);
91 93
92 hostsConsistentMap = storageService.<HostId, DefaultHost>consistentMapBuilder() 94 hostsConsistentMap = storageService.<HostId, DefaultHost>consistentMapBuilder()
93 .withName("onos-hosts") 95 .withName("onos-hosts")
...@@ -122,7 +124,9 @@ public class DistributedHostStore ...@@ -122,7 +124,9 @@ public class DistributedHostStore
122 if (!Objects.equals(existingHost.providerId(), providerId) || 124 if (!Objects.equals(existingHost.providerId(), providerId) ||
123 !Objects.equals(existingHost.mac(), hostDescription.hwAddress()) || 125 !Objects.equals(existingHost.mac(), hostDescription.hwAddress()) ||
124 !Objects.equals(existingHost.vlan(), hostDescription.vlan()) || 126 !Objects.equals(existingHost.vlan(), hostDescription.vlan()) ||
125 - !Objects.equals(existingHost.location(), hostDescription.location())) { 127 + !Objects.equals(existingHost.location(), hostDescription.location()) ||
128 + hostDescription.timestamp() == null ||
129 + hostDescription.timestamp().isNewerThan(existingHost.timestamp())) {
126 return true; 130 return true;
127 } 131 }
128 132
...@@ -173,13 +177,13 @@ public class DistributedHostStore ...@@ -173,13 +177,13 @@ public class DistributedHostStore
173 } else { 177 } else {
174 annotations = hostDescription.annotations(); 178 annotations = hostDescription.annotations();
175 } 179 }
176 -
177 return new DefaultHost(providerId, 180 return new DefaultHost(providerId,
178 hostId, 181 hostId,
179 hostDescription.hwAddress(), 182 hostDescription.hwAddress(),
180 hostDescription.vlan(), 183 hostDescription.vlan(),
181 location, 184 location,
182 addresses, 185 addresses,
186 + hostDescription.timestamp(),
183 annotations); 187 annotations);
184 }); 188 });
185 return null; 189 return null;
...@@ -302,3 +306,4 @@ public class DistributedHostStore ...@@ -302,3 +306,4 @@ public class DistributedHostStore
302 } 306 }
303 } 307 }
304 } 308 }
309 +
......
...@@ -44,17 +44,22 @@ import org.onosproject.net.Device; ...@@ -44,17 +44,22 @@ import org.onosproject.net.Device;
44 import org.onosproject.net.Host; 44 import org.onosproject.net.Host;
45 import org.onosproject.net.HostId; 45 import org.onosproject.net.HostId;
46 import org.onosproject.net.HostLocation; 46 import org.onosproject.net.HostLocation;
47 +import org.onosproject.net.MastershipRole;
47 import org.onosproject.net.device.DeviceEvent; 48 import org.onosproject.net.device.DeviceEvent;
48 import org.onosproject.net.device.DeviceListener; 49 import org.onosproject.net.device.DeviceListener;
49 import org.onosproject.net.device.DeviceService; 50 import org.onosproject.net.device.DeviceService;
50 import org.onosproject.net.flow.DefaultTrafficSelector; 51 import org.onosproject.net.flow.DefaultTrafficSelector;
52 +import org.onosproject.net.flow.DefaultTrafficTreatment;
51 import org.onosproject.net.flow.TrafficSelector; 53 import org.onosproject.net.flow.TrafficSelector;
54 +import org.onosproject.net.flow.TrafficTreatment;
52 import org.onosproject.net.host.DefaultHostDescription; 55 import org.onosproject.net.host.DefaultHostDescription;
53 import org.onosproject.net.host.HostDescription; 56 import org.onosproject.net.host.HostDescription;
54 import org.onosproject.net.host.HostProvider; 57 import org.onosproject.net.host.HostProvider;
55 import org.onosproject.net.host.HostProviderRegistry; 58 import org.onosproject.net.host.HostProviderRegistry;
56 import org.onosproject.net.host.HostProviderService; 59 import org.onosproject.net.host.HostProviderService;
57 import org.onosproject.net.host.HostService; 60 import org.onosproject.net.host.HostService;
61 +import org.onosproject.net.packet.DefaultOutboundPacket;
62 +import org.onosproject.net.packet.OutboundPacket;
58 import org.onosproject.net.packet.PacketContext; 63 import org.onosproject.net.packet.PacketContext;
59 import org.onosproject.net.packet.PacketPriority; 64 import org.onosproject.net.packet.PacketPriority;
60 import org.onosproject.net.packet.PacketProcessor; 65 import org.onosproject.net.packet.PacketProcessor;
...@@ -66,6 +71,7 @@ import org.onosproject.net.topology.TopologyService; ...@@ -66,6 +71,7 @@ import org.onosproject.net.topology.TopologyService;
66 import org.osgi.service.component.ComponentContext; 71 import org.osgi.service.component.ComponentContext;
67 import org.slf4j.Logger; 72 import org.slf4j.Logger;
68 73
74 +import java.nio.ByteBuffer;
69 import java.util.Dictionary; 75 import java.util.Dictionary;
70 import java.util.Set; 76 import java.util.Set;
71 import java.util.concurrent.ExecutorService; 77 import java.util.concurrent.ExecutorService;
...@@ -126,6 +132,8 @@ public class HostLocationProvider extends AbstractProvider implements HostProvid ...@@ -126,6 +132,8 @@ public class HostLocationProvider extends AbstractProvider implements HostProvid
126 132
127 protected ExecutorService eventHandler; 133 protected ExecutorService eventHandler;
128 134
135 + private static final byte[] SENDER_ADDRESS = IpAddress.valueOf("0.0.0.0").toOctets();
136 +
129 /** 137 /**
130 * Creates an OpenFlow host provider. 138 * Creates an OpenFlow host provider.
131 */ 139 */
...@@ -261,7 +269,60 @@ public class HostLocationProvider extends AbstractProvider implements HostProvid ...@@ -261,7 +269,60 @@ public class HostLocationProvider extends AbstractProvider implements HostProvid
261 269
262 @Override 270 @Override
263 public void triggerProbe(Host host) { 271 public void triggerProbe(Host host) {
264 - log.info("Triggering probe on device {}", host); 272 + log.info("Triggering probe on device {} ", host);
273 + MastershipRole role = deviceService.getRole(host.location().deviceId());
274 + if (role.equals(MastershipRole.MASTER)) {
275 + host.ipAddresses().forEach(ip -> {
276 + sendProbe(host, ip);
277 + });
278 + } else {
279 + log.info("not the master, master will probe {}");
280 + }
281 + }
282 +
283 + private void sendProbe(Host host, IpAddress targetIp) {
284 + Ethernet probePacket = null;
285 + if (targetIp.isIp4()) {
286 + // IPv4: Use ARP
287 + probePacket = buildArpRequest(targetIp, host);
288 + } else {
289 + // IPv6: Use Neighbor Discovery
290 + //FIX ME need to implement ndp probe
291 + log.info("Triggering probe on device {} ", host);
292 + }
293 +
294 + TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(host.location().port()).build();
295 +
296 + OutboundPacket outboundPacket = new DefaultOutboundPacket(host.location().deviceId(), treatment,
297 + ByteBuffer.wrap(probePacket.serialize()));
298 +
299 + packetService.emit(outboundPacket);
300 + }
301 +
302 + /*
303 + * This method is using source ip as 0.0.0.0 , to receive the reply even from the sub net hosts.
304 + */
305 + private Ethernet buildArpRequest(IpAddress targetIp, Host host) {
306 +
307 + ARP arp = new ARP();
308 + arp.setHardwareType(ARP.HW_TYPE_ETHERNET)
309 + .setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH)
310 + .setProtocolType(ARP.PROTO_TYPE_IP)
311 + .setProtocolAddressLength((byte) IpAddress.INET_BYTE_LENGTH)
312 + .setOpCode(ARP.OP_REQUEST);
313 +
314 + arp.setSenderHardwareAddress(MacAddress.BROADCAST.toBytes())
315 + .setSenderProtocolAddress(SENDER_ADDRESS)
316 + .setTargetHardwareAddress(MacAddress.BROADCAST.toBytes())
317 + .setTargetProtocolAddress(targetIp.toOctets());
318 +
319 + Ethernet ethernet = new Ethernet();
320 + ethernet.setEtherType(Ethernet.TYPE_ARP)
321 + .setDestinationMACAddress(MacAddress.BROADCAST)
322 + .setSourceMACAddress(MacAddress.BROADCAST).setPayload(arp);
323 +
324 + ethernet.setPad(true);
325 + return ethernet;
265 } 326 }
266 327
267 private class InternalHostProvider implements PacketProcessor { 328 private class InternalHostProvider implements PacketProcessor {
...@@ -449,3 +510,4 @@ public class HostLocationProvider extends AbstractProvider implements HostProvid ...@@ -449,3 +510,4 @@ public class HostLocationProvider extends AbstractProvider implements HostProvid
449 } 510 }
450 511
451 } 512 }
513 +
......
...@@ -348,6 +348,26 @@ public abstract class Tools { ...@@ -348,6 +348,26 @@ public abstract class Tools {
348 } 348 }
349 349
350 /** 350 /**
351 + * Get Long property from the propertyName
352 + * Return null if propertyName is not found.
353 + *
354 + * @param properties properties to be looked up
355 + * @param propertyName the name of the property to look up
356 + * @return value when the propertyName is defined or return null
357 + */
358 + public static Long getLongProperty(Dictionary<?, ?> properties,
359 + String propertyName) {
360 + Long value;
361 + try {
362 + String s = get(properties, propertyName);
363 + value = Strings.isNullOrEmpty(s) ? null : Long.valueOf(s);
364 + } catch (NumberFormatException | ClassCastException e) {
365 + value = null;
366 + }
367 + return value;
368 + }
369 +
370 + /**
351 * Suspends the current thread for a specified number of millis. 371 * Suspends the current thread for a specified number of millis.
352 * 372 *
353 * @param ms number of millis 373 * @param ms number of millis
......
...@@ -198,7 +198,7 @@ public class HostResourceTest extends ResourceTest { ...@@ -198,7 +198,7 @@ public class HostResourceTest extends ResourceTest {
198 @Override 198 @Override
199 public boolean matchesSafely(JsonArray json) { 199 public boolean matchesSafely(JsonArray json) {
200 boolean hostFound = false; 200 boolean hostFound = false;
201 - final int expectedAttributes = 5; 201 + final int expectedAttributes = 6;
202 for (int jsonHostIndex = 0; jsonHostIndex < json.size(); 202 for (int jsonHostIndex = 0; jsonHostIndex < json.size();
203 jsonHostIndex++) { 203 jsonHostIndex++) {
204 204
......