Extend host structures to store multiple locations
Also update host location format in CLI and REST API
Change-Id: I0fbd655f642627dd3eb8a2925f83a3ee016fe4aa
diff --git a/cli/src/main/java/org/onosproject/cli/net/HostsListCommand.java b/cli/src/main/java/org/onosproject/cli/net/HostsListCommand.java
index 3ec3ce3..95b72e5 100644
--- a/cli/src/main/java/org/onosproject/cli/net/HostsListCommand.java
+++ b/cli/src/main/java/org/onosproject/cli/net/HostsListCommand.java
@@ -38,10 +38,10 @@
public class HostsListCommand extends AbstractShellCommand {
private static final String FMT =
- "id=%s, mac=%s, location=%s/%s, vlan=%s, ip(s)=%s%s, configured=%s";
+ "id=%s, mac=%s, location=%s, vlan=%s, ip(s)=%s%s, configured=%s";
private static final String FMT_SHORT =
- "id=%s, mac=%s, location=%s/%s, vlan=%s, ip(s)=%s";
+ "id=%s, mac=%s, location=%s, vlan=%s, ip(s)=%s";
@Option(name = "-s", aliases = "--short", description = "Show short output only",
required = false, multiValued = false)
@@ -88,11 +88,11 @@
protected void printHost(Host host) {
if (shortOnly) {
print(FMT_SHORT, host.id(), host.mac(),
- host.location().deviceId(), host.location().port(),
+ host.locations(),
host.vlan(), host.ipAddresses());
} else {
print(FMT, host.id(), host.mac(),
- host.location().deviceId(), host.location().port(),
+ host.locations(),
host.vlan(), host.ipAddresses(), annotations(host.annotations()),
host.configured());
}
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 d9cfa25..defb5a3 100644
--- a/core/api/src/main/java/org/onosproject/net/DefaultHost.java
+++ b/core/api/src/main/java/org/onosproject/net/DefaultHost.java
@@ -21,6 +21,7 @@
import org.onlab.packet.VlanId;
import java.util.Collections;
+import java.util.Comparator;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
@@ -34,7 +35,7 @@
private final MacAddress mac;
private final VlanId vlan;
- private final HostLocation location;
+ private final Set<HostLocation> locations;
private final Set<IpAddress> ips;
private final boolean configured;
@@ -70,10 +71,29 @@
public DefaultHost(ProviderId providerId, HostId id, MacAddress mac,
VlanId vlan, HostLocation location, Set<IpAddress> ips,
boolean configured, Annotations... annotations) {
+ this(providerId, id, mac, vlan, Collections.singleton(location), ips,
+ configured, 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 locations set of host locations
+ * @param ips host IP addresses
+ * @param configured true if configured via NetworkConfiguration
+ * @param annotations optional key/value annotations
+ */
+ public DefaultHost(ProviderId providerId, HostId id, MacAddress mac,
+ VlanId vlan, Set<HostLocation> locations, Set<IpAddress> ips,
+ boolean configured, Annotations... annotations) {
super(providerId, id, annotations);
this.mac = mac;
this.vlan = vlan;
- this.location = location;
+ this.locations = new HashSet<>(locations);
this.ips = new HashSet<>(ips);
this.configured = configured;
}
@@ -99,7 +119,14 @@
@Override
public HostLocation location() {
- return location;
+ return locations.stream()
+ .sorted(Comparator.comparingLong(HostLocation::time).reversed())
+ .findFirst().orElse(null);
+ }
+
+ @Override
+ public Set<HostLocation> locations() {
+ return locations;
}
@Override
@@ -114,7 +141,7 @@
@Override
public int hashCode() {
- return Objects.hash(id, mac, vlan, location);
+ return Objects.hash(id, mac, vlan, locations);
}
@Override
@@ -127,7 +154,7 @@
return Objects.equals(this.id, other.id) &&
Objects.equals(this.mac, other.mac) &&
Objects.equals(this.vlan, other.vlan) &&
- Objects.equals(this.location, other.location) &&
+ Objects.equals(this.locations, other.locations) &&
Objects.equals(this.ipAddresses(), other.ipAddresses()) &&
Objects.equals(this.annotations(), other.annotations());
}
@@ -140,7 +167,7 @@
.add("id", id())
.add("mac", mac())
.add("vlan", vlan())
- .add("location", location())
+ .add("locations", locations())
.add("ipAddresses", ipAddresses())
.add("annotations", annotations())
.add("configured", configured())
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 5094727..86ef79f 100644
--- a/core/api/src/main/java/org/onosproject/net/Host.java
+++ b/core/api/src/main/java/org/onosproject/net/Host.java
@@ -59,11 +59,18 @@
* Returns the most recent host location where the host attaches to the
* network edge.
*
- * @return host location
+ * @return the most recent host location
*/
HostLocation location();
/**
+ * Returns all host locations where the host attaches to the network edge.
+ *
+ * @return all host locations
+ */
+ Set<HostLocation> locations();
+
+ /**
* Returns true if configured by NetworkConfiguration.
* @return configured/learnt dynamically
*/
@@ -73,4 +80,3 @@
// TODO: explore capturing list of recent locations to aid in mobility
}
-
diff --git a/core/api/src/main/java/org/onosproject/net/HostLocation.java b/core/api/src/main/java/org/onosproject/net/HostLocation.java
index f7868c6..94409b6 100644
--- a/core/api/src/main/java/org/onosproject/net/HostLocation.java
+++ b/core/api/src/main/java/org/onosproject/net/HostLocation.java
@@ -64,4 +64,8 @@
return time;
}
+ @Override
+ public String toString() {
+ return deviceId() + "/" + port();
+ }
}
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 5f9cfd8..c2531f6 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
@@ -16,6 +16,8 @@
package org.onosproject.net.host;
import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
import java.util.Set;
import org.onosproject.net.AbstractDescription;
@@ -38,7 +40,7 @@
private final MacAddress mac;
private final VlanId vlan;
- private final HostLocation location;
+ private final Set<HostLocation> locations;
private final Set<IpAddress> ip;
private final boolean configured;
@@ -53,8 +55,7 @@
public DefaultHostDescription(MacAddress mac, VlanId vlan,
HostLocation location,
SparseAnnotations... annotations) {
- this(mac, vlan, location, Collections.emptySet(),
- annotations);
+ this(mac, vlan, location, Collections.emptySet(), annotations);
}
/**
@@ -100,8 +101,7 @@
HostLocation location,
boolean configured,
SparseAnnotations... annotations) {
- this(mac, vlan, location, Collections.<IpAddress>emptySet(),
- configured, annotations);
+ this(mac, vlan, location, Collections.emptySet(), configured, annotations);
}
/**
@@ -118,11 +118,28 @@
HostLocation location, Set<IpAddress> ip,
boolean configured,
SparseAnnotations... annotations) {
+ this(mac, vlan, Collections.singleton(location), ip, configured, annotations);
+ }
+
+ /**
+ * Creates a host description using the supplied information.
+ *
+ * @param mac host MAC address
+ * @param vlan host VLAN identifier
+ * @param locations host locations
+ * @param ip host IP address
+ * @param configured true if configured via NetworkConfiguration
+ * @param annotations optional key/value annotations map
+ */
+ public DefaultHostDescription(MacAddress mac, VlanId vlan,
+ Set<HostLocation> locations,
+ Set<IpAddress> ip, boolean configured,
+ SparseAnnotations... annotations) {
super(annotations);
this.mac = mac;
this.vlan = vlan;
- this.location = location;
- this.ip = ImmutableSet.copyOf(ip);
+ this.locations = new HashSet<>(locations);
+ this.ip = new HashSet<>(ip);
this.configured = configured;
}
@@ -138,7 +155,14 @@
@Override
public HostLocation location() {
- return location;
+ return locations.stream()
+ .sorted(Comparator.comparingLong(HostLocation::time).reversed())
+ .findFirst().orElse(null);
+ }
+
+ @Override
+ public Set<HostLocation> locations() {
+ return locations;
}
@Override
@@ -156,7 +180,7 @@
return toStringHelper(this)
.add("mac", mac)
.add("vlan", vlan)
- .add("location", location)
+ .add("locations", locations)
.add("ipAddress", ip)
.add("configured", configured)
.toString();
@@ -164,7 +188,7 @@
@Override
public int hashCode() {
- return Objects.hashCode(super.hashCode(), mac, vlan, location, ip);
+ return Objects.hashCode(super.hashCode(), mac, vlan, locations, ip);
}
@Override
@@ -176,7 +200,7 @@
DefaultHostDescription that = (DefaultHostDescription) object;
return Objects.equal(this.mac, that.mac)
&& Objects.equal(this.vlan, that.vlan)
- && Objects.equal(this.location, that.location)
+ && Objects.equal(this.locations, that.locations)
&& Objects.equal(this.ip, that.ip);
}
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 d7687ac..bba9dc9 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
@@ -43,13 +43,20 @@
VlanId vlan();
/**
- * Returns the location of the host on the network edge.
+ * Returns the most recent location of the host on the network edge.
*
- * @return the network location
+ * @return the most recent host location
*/
HostLocation location();
/**
+ * Returns all locations of the host on the network edge.
+ *
+ * @return all host locations
+ */
+ Set<HostLocation> locations();
+
+ /**
* Returns the IP address associated with this host's MAC.
*
* @return host IP address
diff --git a/core/api/src/test/java/org/onosproject/net/DefaultHostTest.java b/core/api/src/test/java/org/onosproject/net/DefaultHostTest.java
index 62012ba..e36d0e2 100644
--- a/core/api/src/test/java/org/onosproject/net/DefaultHostTest.java
+++ b/core/api/src/test/java/org/onosproject/net/DefaultHostTest.java
@@ -16,12 +16,19 @@
package org.onosproject.net;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.testing.EqualsTester;
+import java.util.Set;
import org.junit.Test;
-import com.google.common.testing.EqualsTester;
-
-public class DefaultHostTest extends TestDeviceParams {
+public class DefaultHostTest extends TestDeviceParams {
+ private static final Set<HostLocation> LOCATIONS = ImmutableSet.of(LOC1, LOC2, LOC3);
+ private static final Host SINGLE_HOMED_HOST =
+ new DefaultHost(PID, HID1, MAC1, VLAN1, LOC1, IPSET1);
+ private static final Host MULTI_HOMED_HOST =
+ new DefaultHost(PID, HID1, MAC1, VLAN1, LOCATIONS, IPSET1, false);
@Test
public void testEquality() {
@@ -39,13 +46,27 @@
@Test
public void basics() {
- Host host = new DefaultHost(PID, HID1, MAC1, VLAN1, LOC1, IPSET1);
- assertEquals("incorrect provider", PID, host.providerId());
- assertEquals("incorrect id", HID1, host.id());
- assertEquals("incorrect type", MAC1, host.mac());
- assertEquals("incorrect VLAN", VLAN1, host.vlan());
- assertEquals("incorrect location", LOC1, host.location());
- assertEquals("incorrect IP's", IPSET1, host.ipAddresses());
+ assertEquals("incorrect provider", PID, SINGLE_HOMED_HOST.providerId());
+ assertEquals("incorrect id", HID1, SINGLE_HOMED_HOST.id());
+ assertEquals("incorrect type", MAC1, SINGLE_HOMED_HOST.mac());
+ assertEquals("incorrect VLAN", VLAN1, SINGLE_HOMED_HOST.vlan());
+ assertEquals("incorrect location", LOC1, SINGLE_HOMED_HOST.location());
+ assertEquals("incorrect IPs", IPSET1, SINGLE_HOMED_HOST.ipAddresses());
+ }
+
+ @Test
+ public void testLocation() {
+ assertEquals("Latest location should be LOC3", LOC3, MULTI_HOMED_HOST.location());
+ }
+
+ @Test
+ public void testLocations() {
+ Set<HostLocation> locations = MULTI_HOMED_HOST.locations();
+
+ assertEquals("There should be 3 locations", locations.size(), 3);
+ assertTrue("Host location contains 1st location", locations.contains(LOC1));
+ assertTrue("Host location contains 2nd location", locations.contains(LOC2));
+ assertTrue("Host location contains 3rd location", locations.contains(LOC3));
}
}
diff --git a/core/api/src/test/java/org/onosproject/net/TestDeviceParams.java b/core/api/src/test/java/org/onosproject/net/TestDeviceParams.java
index 2de364a..4fa7baf 100644
--- a/core/api/src/test/java/org/onosproject/net/TestDeviceParams.java
+++ b/core/api/src/test/java/org/onosproject/net/TestDeviceParams.java
@@ -51,7 +51,8 @@
protected static final HostId HID1 = HostId.hostId(MAC1, VLAN1);
protected static final HostId HID2 = HostId.hostId(MAC2, VLAN2);
protected static final HostLocation LOC1 = new HostLocation(DID1, P1, 123L);
- protected static final HostLocation LOC2 = new HostLocation(DID2, P2, 123L);
+ protected static final HostLocation LOC2 = new HostLocation(DID2, P2, 456L);
+ protected static final HostLocation LOC3 = new HostLocation(DID3, P1, 789L);
protected static final Set<IpAddress> IPSET1 = Sets.newHashSet(IP1, IP2);
protected static final Set<IpAddress> IPSET2 = Sets.newHashSet(IP1, IP3);
diff --git a/core/api/src/test/java/org/onosproject/net/host/DefaultHostDecriptionTest.java b/core/api/src/test/java/org/onosproject/net/host/DefaultHostDecriptionTest.java
index 26a1cde..0b36035 100644
--- a/core/api/src/test/java/org/onosproject/net/host/DefaultHostDecriptionTest.java
+++ b/core/api/src/test/java/org/onosproject/net/host/DefaultHostDecriptionTest.java
@@ -16,14 +16,12 @@
package org.onosproject.net.host;
import org.junit.Test;
-import org.onosproject.net.DeviceId;
import org.onosproject.net.HostLocation;
-import org.onosproject.net.PortNumber;
-import org.onlab.packet.IpAddress;
-import org.onlab.packet.MacAddress;
-import org.onlab.packet.VlanId;
import com.google.common.collect.ImmutableSet;
+import org.onosproject.net.TestDeviceParams;
+
+import java.util.Set;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -31,27 +29,34 @@
/**
* Test for the default host description.
*/
-public class DefaultHostDecriptionTest {
-
- private static final MacAddress MAC = MacAddress.valueOf("00:00:11:00:00:01");
- private static final VlanId VLAN = VlanId.vlanId((short) 10);
- private static final IpAddress IP = IpAddress.valueOf("10.0.0.1");
-
- private static final HostLocation LOC = new HostLocation(
- DeviceId.deviceId("of:foo"),
- PortNumber.portNumber(100),
- 123L
- );
+public class DefaultHostDecriptionTest extends TestDeviceParams {
+ private static final Set<HostLocation> LOCATIONS = ImmutableSet.of(LOC1, LOC2, LOC3);
+ private static final HostDescription SINGLE_HOMED_HOST_DESCR =
+ new DefaultHostDescription(MAC1, VLAN1, LOC1, IP1);
+ private static final HostDescription MULTI_HOMED_HOST_DESCR =
+ new DefaultHostDescription(MAC1, VLAN1, LOCATIONS, IPSET1, false);
@Test
public void basics() {
- HostDescription host =
- new DefaultHostDescription(MAC, VLAN, LOC, IP);
- assertEquals("incorrect mac", MAC, host.hwAddress());
- assertEquals("incorrect vlan", VLAN, host.vlan());
- assertEquals("incorrect location", LOC, host.location());
- assertEquals("incorrect ip's", ImmutableSet.of(IP), host.ipAddress());
- assertTrue("incorrect toString", host.toString().contains("vlan=10"));
+ assertEquals("incorrect mac", MAC1, SINGLE_HOMED_HOST_DESCR.hwAddress());
+ assertEquals("incorrect vlan", VLAN1, SINGLE_HOMED_HOST_DESCR.vlan());
+ assertEquals("incorrect location", LOC1, SINGLE_HOMED_HOST_DESCR.location());
+ assertEquals("incorrect IPs", ImmutableSet.of(IP1), SINGLE_HOMED_HOST_DESCR.ipAddress());
+ assertTrue("incorrect toString", SINGLE_HOMED_HOST_DESCR.toString().contains("vlan=11"));
}
+ @Test
+ public void testLocation() {
+ assertEquals("Latest location should be LOC3", LOC3, MULTI_HOMED_HOST_DESCR.location());
+ }
+
+ @Test
+ public void testLocations() {
+ Set<HostLocation> locations = MULTI_HOMED_HOST_DESCR.locations();
+
+ assertEquals("There should be 3 locations", locations.size(), 3);
+ assertTrue("Host location contains 1st location", locations.contains(LOC1));
+ assertTrue("Host location contains 2nd location", locations.contains(LOC2));
+ assertTrue("Host location contains 3rd location", locations.contains(LOC3));
+ }
}
diff --git a/core/api/src/test/java/org/onosproject/ui/topo/NodeSelectionTest.java b/core/api/src/test/java/org/onosproject/ui/topo/NodeSelectionTest.java
index 97f9843..63a4444 100644
--- a/core/api/src/test/java/org/onosproject/ui/topo/NodeSelectionTest.java
+++ b/core/api/src/test/java/org/onosproject/ui/topo/NodeSelectionTest.java
@@ -53,7 +53,7 @@
private static class FakeHost extends DefaultHost {
FakeHost(HostId id) {
- super(null, id, null, null, null, ImmutableSet.of());
+ super(null, id, null, null, ImmutableSet.of(), ImmutableSet.of(), false);
}
}
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 b5f9b02..233d61d 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
@@ -47,7 +47,12 @@
jsonIpAddresses.add(ipAddress.toString());
}
result.set("ipAddresses", jsonIpAddresses);
- result.set("location", locationCodec.encode(host.location(), context));
+
+ final ArrayNode jsonLocations = result.putArray("locations");
+ for (final HostLocation location : host.locations()) {
+ jsonLocations.add(locationCodec.encode(location, context));
+ }
+ result.set("locations", jsonLocations);
return annotate(result, host, context);
}
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/VirtualHostCodec.java b/core/common/src/main/java/org/onosproject/codec/impl/VirtualHostCodec.java
index 05ce81e..d6a7c80 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/VirtualHostCodec.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/VirtualHostCodec.java
@@ -49,7 +49,7 @@
static final String MAC_ADDRESS = "mac";
static final String VLAN = "vlan";
static final String IP_ADDRESSES = "ipAddresses";
- static final String HOST_LOCATION = "location";
+ static final String HOST_LOCATION = "locations";
private static final String NULL_OBJECT_MSG = "VirtualHost cannot be null";
private static final String MISSING_MEMBER_MSG = " member is required in VirtualHost";
@@ -71,7 +71,12 @@
jsonIpAddresses.add(ipAddress.toString());
}
result.set(IP_ADDRESSES, jsonIpAddresses);
- result.set(HOST_LOCATION, locationCodec.encode(vHost.location(), context));
+
+ final ArrayNode jsonLocations = result.putArray("locations");
+ for (final HostLocation location : vHost.locations()) {
+ jsonLocations.add(locationCodec.encode(location, context));
+ }
+ result.set("locations", jsonLocations);
return result;
}
@@ -85,10 +90,15 @@
NetworkId nId = NetworkId.networkId(Long.parseLong(extractMember(NETWORK_ID, json)));
MacAddress mac = MacAddress.valueOf(json.get("mac").asText());
VlanId vlanId = VlanId.vlanId((short) json.get("vlan").asInt(VlanId.UNTAGGED));
- JsonNode locationNode = json.get("location");
- PortNumber portNumber = PortNumber.portNumber(locationNode.get("port").asText());
- DeviceId deviceId = DeviceId.deviceId(locationNode.get("elementId").asText());
- HostLocation hostLocation = new HostLocation(deviceId, portNumber, 0);
+
+ Set<HostLocation> locations = new HashSet<>();
+ JsonNode locationNodes = json.get("locations");
+ locationNodes.forEach(locationNode -> {
+ PortNumber portNumber = PortNumber.portNumber(locationNode.get("port").asText());
+ DeviceId deviceId = DeviceId.deviceId(locationNode.get("elementId").asText());
+ locations.add(new HostLocation(deviceId, portNumber, 0));
+ });
+
HostId id = HostId.hostId(mac, vlanId);
Iterator<JsonNode> ipStrings = json.get("ipAddresses").elements();
@@ -97,7 +107,7 @@
ips.add(IpAddress.valueOf(ipStrings.next().asText()));
}
- return new DefaultVirtualHost(nId, id, mac, vlanId, hostLocation, ips);
+ return new DefaultVirtualHost(nId, id, mac, vlanId, locations, ips);
}
/**
diff --git a/core/common/src/test/java/org/onosproject/codec/impl/VirtualHostCodecTest.java b/core/common/src/test/java/org/onosproject/codec/impl/VirtualHostCodecTest.java
index 1774242..661a1f3 100644
--- a/core/common/src/test/java/org/onosproject/codec/impl/VirtualHostCodecTest.java
+++ b/core/common/src/test/java/org/onosproject/codec/impl/VirtualHostCodecTest.java
@@ -81,9 +81,9 @@
is(TEST_MAC_ADDRESS));
assertThat(node.get(VirtualHostCodec.VLAN).asInt(),
is((int) TEST_VLAN_ID));
- assertThat(node.get(VirtualHostCodec.HOST_LOCATION).get("elementId").asText(),
+ assertThat(node.get(VirtualHostCodec.HOST_LOCATION).get(0).get("elementId").asText(),
is(location.deviceId().toString()));
- assertThat(node.get(VirtualHostCodec.HOST_LOCATION).get("port").asLong(),
+ assertThat(node.get(VirtualHostCodec.HOST_LOCATION).get(0).get("port").asLong(),
is(location.port().toLong()));
JsonNode jsonIps = node.get(VirtualHostCodec.IP_ADDRESSES);
diff --git a/core/common/src/test/resources/org/onosproject/codec/impl/VirtualHost.json b/core/common/src/test/resources/org/onosproject/codec/impl/VirtualHost.json
index ab5a81b..818ce0b 100644
--- a/core/common/src/test/resources/org/onosproject/codec/impl/VirtualHost.json
+++ b/core/common/src/test/resources/org/onosproject/codec/impl/VirtualHost.json
@@ -6,8 +6,10 @@
"1.1.1.1",
"2.2.2.2"
],
- "location": {
- "elementId": "of:d1",
- "port": "1"
- }
+ "locations": [
+ {
+ "elementId": "of:d1",
+ "port": "1"
+ }
+ ]
}
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 c65ca4b..64d24a7 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
@@ -160,7 +160,7 @@
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.locations(), hostDescription.locations())) {
return true;
}
@@ -194,7 +194,6 @@
existingHost -> shouldUpdate(existingHost, providerId,
hostDescription, replaceIPs),
(id, existingHost) -> {
- HostLocation location = hostDescription.location();
final Set<IpAddress> addresses;
if (existingHost == null || replaceIPs) {
@@ -219,7 +218,7 @@
hostId,
hostDescription.hwAddress(),
hostDescription.vlan(),
- location,
+ hostDescription.locations(),
addresses,
configured,
annotations);
@@ -253,8 +252,9 @@
hostId,
existingHost.mac(),
existingHost.vlan(),
- existingHost.location(),
+ existingHost.locations(),
ImmutableSet.copyOf(addresses),
+ existingHost.configured(),
existingHost.annotations());
} else {
return existingHost;
@@ -299,7 +299,7 @@
@Override
public Set<Host> getConnectedHosts(ConnectPoint connectPoint) {
Set<Host> filtered = hosts.entrySet().stream()
- .filter(entry -> entry.getValue().location().equals(connectPoint))
+ .filter(entry -> entry.getValue().locations().contains(connectPoint))
.map(Map.Entry::getValue)
.collect(Collectors.toSet());
return ImmutableSet.copyOf(filtered);
@@ -308,7 +308,8 @@
@Override
public Set<Host> getConnectedHosts(DeviceId deviceId) {
Set<Host> filtered = hosts.entrySet().stream()
- .filter(entry -> entry.getValue().location().deviceId().equals(deviceId))
+ .filter(entry -> entry.getValue().locations().stream()
+ .map(HostLocation::deviceId).anyMatch(dpid -> dpid.equals(deviceId)))
.map(Map.Entry::getValue)
.collect(Collectors.toSet());
return ImmutableSet.copyOf(filtered);
@@ -382,7 +383,7 @@
case UPDATE:
updateHostsByIp(host);
DefaultHost prevHost = checkNotNull(event.oldValue().value());
- if (!Objects.equals(prevHost.location(), host.location())) {
+ if (!Objects.equals(prevHost.locations(), host.locations())) {
notifyDelegate(new HostEvent(HOST_MOVED, host, prevHost));
} else if (!Objects.equals(prevHost, host)) {
notifyDelegate(new HostEvent(HOST_UPDATED, host, prevHost));
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/DefaultVirtualHost.java b/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/DefaultVirtualHost.java
index 2256fd3..cea2991 100644
--- a/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/DefaultVirtualHost.java
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/DefaultVirtualHost.java
@@ -25,6 +25,7 @@
import org.onosproject.net.HostLocation;
import org.onosproject.net.provider.ProviderId;
+import java.util.Collections;
import java.util.Objects;
import java.util.Set;
@@ -52,7 +53,22 @@
*/
public DefaultVirtualHost(NetworkId networkId, HostId id, MacAddress mac,
VlanId vlan, HostLocation location, Set<IpAddress> ips) {
- super(PID, id, mac, vlan, location, ips, DefaultAnnotations.builder().build());
+ this(networkId, id, mac, vlan, Collections.singleton(location), ips);
+ }
+
+ /**
+ * Creates a virtual host attributed to the specified provider.
+ *
+ * @param networkId network identifier
+ * @param id host identifier
+ * @param mac host MAC address
+ * @param vlan host VLAN identifier
+ * @param locations host locations
+ * @param ips host IP addresses
+ */
+ public DefaultVirtualHost(NetworkId networkId, HostId id, MacAddress mac,
+ VlanId vlan, Set<HostLocation> locations, Set<IpAddress> ips) {
+ super(PID, id, mac, vlan, locations, ips, false, DefaultAnnotations.builder().build());
this.networkId = networkId;
}
diff --git a/web/api/src/main/java/org/onosproject/rest/resources/HostsWebResource.java b/web/api/src/main/java/org/onosproject/rest/resources/HostsWebResource.java
index 7d5dfad..4d85ba0 100644
--- a/web/api/src/main/java/org/onosproject/rest/resources/HostsWebResource.java
+++ b/web/api/src/main/java/org/onosproject/rest/resources/HostsWebResource.java
@@ -68,7 +68,7 @@
@Context
private UriInfo uriInfo;
private static final String HOST_NOT_FOUND = "Host is not found";
- private static final String[] REMOVAL_KEYS = {"mac", "vlan", "location", "ipAddresses"};
+ private static final String[] REMOVAL_KEYS = {"mac", "vlan", "locations", "ipAddresses"};
/**
* Get all end-station hosts.
@@ -219,15 +219,21 @@
private HostId parseHost(JsonNode node) {
MacAddress mac = MacAddress.valueOf(node.get("mac").asText());
VlanId vlanId = VlanId.vlanId((short) node.get("vlan").asInt(VlanId.UNTAGGED));
- JsonNode locationNode = node.get("location");
- String deviceAndPort = locationNode.get("elementId").asText() + "/" +
- locationNode.get("port").asText();
- HostLocation hostLocation = new HostLocation(ConnectPoint.deviceConnectPoint(deviceAndPort), 0);
- Iterator<JsonNode> ipStrings = node.get("ipAddresses").elements();
+ Iterator<JsonNode> locationNodes = node.get("locations").elements();
+ Set<HostLocation> locations = new HashSet<>();
+ while (locationNodes.hasNext()) {
+ JsonNode locationNode = locationNodes.next();
+ String deviceAndPort = locationNode.get("elementId").asText() + "/" +
+ locationNode.get("port").asText();
+ HostLocation hostLocation = new HostLocation(ConnectPoint.deviceConnectPoint(deviceAndPort), 0);
+ locations.add(hostLocation);
+ }
+
+ Iterator<JsonNode> ipNodes = node.get("ipAddresses").elements();
Set<IpAddress> ips = new HashSet<>();
- while (ipStrings.hasNext()) {
- ips.add(IpAddress.valueOf(ipStrings.next().asText()));
+ while (ipNodes.hasNext()) {
+ ips.add(IpAddress.valueOf(ipNodes.next().asText()));
}
// try to remove elements from json node after reading them
@@ -235,7 +241,7 @@
// Update host inventory
HostId hostId = HostId.hostId(mac, vlanId);
- DefaultHostDescription desc = new DefaultHostDescription(mac, vlanId, hostLocation, ips, true, annotations);
+ DefaultHostDescription desc = new DefaultHostDescription(mac, vlanId, locations, ips, true, annotations);
hostProviderService.hostDetected(hostId, desc, false);
return hostId;
}
diff --git a/web/api/src/main/resources/definitions/Host.json b/web/api/src/main/resources/definitions/Host.json
index 208bf1f..b29e828 100644
--- a/web/api/src/main/resources/definitions/Host.json
+++ b/web/api/src/main/resources/definitions/Host.json
@@ -32,21 +32,24 @@
"example": "127.0.0.1"
}
},
- "location": {
- "type": "object",
- "title": "location",
- "required": [
- "elementId",
- "port"
- ],
- "properties": {
- "elementId": {
- "type": "string",
- "example": "of:0000000000000002"
- },
- "port": {
- "type": "string",
- "example": "3"
+ "locations": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "title": "location",
+ "required": [
+ "elementId",
+ "port"
+ ],
+ "properties": {
+ "elementId": {
+ "type": "string",
+ "example": "of:0000000000000002"
+ },
+ "port": {
+ "type": "string",
+ "example": "3"
+ }
}
}
}
diff --git a/web/api/src/main/resources/definitions/HostPut.json b/web/api/src/main/resources/definitions/HostPut.json
index 66bf654..26e1c41 100644
--- a/web/api/src/main/resources/definitions/HostPut.json
+++ b/web/api/src/main/resources/definitions/HostPut.json
@@ -27,21 +27,24 @@
"example": "127.0.0.1"
}
},
- "location": {
- "type": "object",
- "title": "location",
- "required": [
- "elementId",
- "port"
- ],
- "properties": {
- "elementId": {
- "type": "string",
- "example": "of:0000000000000002"
- },
- "port": {
- "type": "string",
- "example": "3"
+ "locations": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "title": "location",
+ "required": [
+ "elementId",
+ "port"
+ ],
+ "properties": {
+ "elementId": {
+ "type": "string",
+ "example": "of:0000000000000002"
+ },
+ "port": {
+ "type": "string",
+ "example": "3"
+ }
}
}
}
diff --git a/web/api/src/main/resources/definitions/Hosts.json b/web/api/src/main/resources/definitions/Hosts.json
index 235a083..3615ba4 100644
--- a/web/api/src/main/resources/definitions/Hosts.json
+++ b/web/api/src/main/resources/definitions/Hosts.json
@@ -45,21 +45,24 @@
"example": "127.0.0.1"
}
},
- "location": {
- "type": "object",
- "title": "location",
- "required": [
- "elementId",
- "port"
- ],
- "properties": {
- "elementId": {
- "type": "string",
- "example": "of:0000000000000002"
- },
- "port": {
- "type": "string",
- "example": "3"
+ "locations": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "title": "location",
+ "required": [
+ "elementId",
+ "port"
+ ],
+ "properties": {
+ "elementId": {
+ "type": "string",
+ "example": "of:0000000000000002"
+ },
+ "port": {
+ "type": "string",
+ "example": "3"
+ }
}
}
}
diff --git a/web/api/src/main/resources/definitions/VirtualHost.json b/web/api/src/main/resources/definitions/VirtualHost.json
index e27d148..4035694 100644
--- a/web/api/src/main/resources/definitions/VirtualHost.json
+++ b/web/api/src/main/resources/definitions/VirtualHost.json
@@ -38,21 +38,24 @@
"example": "127.0.0.1"
}
},
- "location": {
- "type": "object",
- "title": "location",
- "required": [
- "elementId",
- "port"
- ],
- "properties": {
- "elementId": {
- "type": "string",
- "example": "of:0000000000000002"
- },
- "port": {
- "type": "string",
- "example": "3"
+ "locations": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "title": "location",
+ "required": [
+ "elementId",
+ "port"
+ ],
+ "properties": {
+ "elementId": {
+ "type": "string",
+ "example": "of:0000000000000002"
+ },
+ "port": {
+ "type": "string",
+ "example": "3"
+ }
}
}
}
diff --git a/web/api/src/main/resources/definitions/VirtualHostPut.json b/web/api/src/main/resources/definitions/VirtualHostPut.json
index c0b8eba..3026478 100644
--- a/web/api/src/main/resources/definitions/VirtualHostPut.json
+++ b/web/api/src/main/resources/definitions/VirtualHostPut.json
@@ -33,21 +33,24 @@
"example": "127.0.0.1"
}
},
- "location": {
- "type": "object",
- "title": "location",
- "required": [
- "elementId",
- "port"
- ],
- "properties": {
- "elementId": {
- "type": "string",
- "example": "of:0000000000000002"
- },
- "port": {
- "type": "string",
- "example": "3"
+ "locations": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "title": "location",
+ "required": [
+ "elementId",
+ "port"
+ ],
+ "properties": {
+ "elementId": {
+ "type": "string",
+ "example": "of:0000000000000002"
+ },
+ "port": {
+ "type": "string",
+ "example": "3"
+ }
}
}
}
diff --git a/web/api/src/main/resources/definitions/VirtualHosts.json b/web/api/src/main/resources/definitions/VirtualHosts.json
index 001867e..979a3f7 100644
--- a/web/api/src/main/resources/definitions/VirtualHosts.json
+++ b/web/api/src/main/resources/definitions/VirtualHosts.json
@@ -51,21 +51,24 @@
"example": "127.0.0.1"
}
},
- "location": {
- "type": "object",
- "title": "location",
- "required": [
- "elementId",
- "port"
- ],
- "properties": {
- "elementId": {
- "type": "string",
- "example": "of:0000000000000002"
- },
- "port": {
- "type": "string",
- "example": "3"
+ "locations": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "title": "location",
+ "required": [
+ "elementId",
+ "port"
+ ],
+ "properties": {
+ "elementId": {
+ "type": "string",
+ "example": "of:0000000000000002"
+ },
+ "port": {
+ "type": "string",
+ "example": "3"
+ }
}
}
}
diff --git a/web/api/src/test/java/org/onosproject/rest/resources/HostResourceTest.java b/web/api/src/test/java/org/onosproject/rest/resources/HostResourceTest.java
index 4c0ea91..94c390d 100644
--- a/web/api/src/test/java/org/onosproject/rest/resources/HostResourceTest.java
+++ b/web/api/src/test/java/org/onosproject/rest/resources/HostResourceTest.java
@@ -19,6 +19,7 @@
import com.eclipsesource.json.Json;
import com.eclipsesource.json.JsonArray;
import com.eclipsesource.json.JsonObject;
+import com.eclipsesource.json.JsonValue;
import com.google.common.collect.ImmutableSet;
import org.hamcrest.Description;
import org.hamcrest.Matchers;
@@ -52,6 +53,7 @@
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.Set;
import static org.easymock.EasyMock.anyBoolean;
@@ -143,19 +145,21 @@
return false;
}
- // Check location element id
- final JsonObject jsonLocation = jsonHost.get("location").asObject();
- final String jsonLocationElementId = jsonLocation.get("elementId").asString();
- if (!jsonLocationElementId.equals(host.location().elementId().toString())) {
- reason = "location element id " + host.location().elementId().toString();
+ // Check host locations
+ final JsonArray jsonLocations = jsonHost.get("locations").asArray();
+ final Set<HostLocation> expectedLocations = host.locations();
+ if (jsonLocations.size() != expectedLocations.size()) {
+ reason = "locations arrays differ in size";
return false;
}
- // Check location port number
- final String jsonLocationPortNumber = jsonLocation.get("port").asString();
- if (!jsonLocationPortNumber.equals(host.location().port().toString())) {
- reason = "location portNumber " + host.location().port().toString();
- return false;
+ Iterator<JsonValue> jsonIterator = jsonLocations.iterator();
+ Iterator<HostLocation> locIterator = expectedLocations.iterator();
+ while (jsonIterator.hasNext()) {
+ boolean result = verifyLocation(jsonIterator.next().asObject(), locIterator.next());
+ if (!result) {
+ return false;
+ }
}
// Check Ip Addresses
@@ -173,6 +177,20 @@
public void describeTo(Description description) {
description.appendText(reason);
}
+
+ private boolean verifyLocation(JsonObject jsonLocation, HostLocation expectedLocation) {
+ final String jsonLocationElementId = jsonLocation.get("elementId").asString();
+ if (!jsonLocationElementId.equals(expectedLocation.elementId().toString())) {
+ reason = "location element id " + host.location().elementId().toString();
+ return false;
+ }
+ final String jsonLocationPortNumber = jsonLocation.get("port").asString();
+ if (!jsonLocationPortNumber.equals(expectedLocation.port().toString())) {
+ reason = "location portNumber " + expectedLocation.port().toString();
+ return false;
+ }
+ return true;
+ }
}
/**
diff --git a/web/api/src/test/resources/org/onosproject/rest/resources/post-host.json b/web/api/src/test/resources/org/onosproject/rest/resources/post-host.json
index 26c6292..b5fe3a1 100644
--- a/web/api/src/test/resources/org/onosproject/rest/resources/post-host.json
+++ b/web/api/src/test/resources/org/onosproject/rest/resources/post-host.json
@@ -2,10 +2,16 @@
"id": "11:22:33:44:55:66/-1",
"vlan": "-1",
"mac": "11:22:33:44:55:66",
- "location": {
- "port": 3,
- "elementId": "of:0000000000000001"
- },
+ "locations": [
+ {
+ "port": 3,
+ "elementId": "of:0000000000000001"
+ },
+ {
+ "port": 4,
+ "elementId": "of:0000000000000002"
+ }
+ ],
"ipAddresses": [
"10.10.10.10"
]
diff --git a/web/api/src/test/resources/org/onosproject/rest/resources/post-virtual-host.json b/web/api/src/test/resources/org/onosproject/rest/resources/post-virtual-host.json
index 3621798..557dc32 100644
--- a/web/api/src/test/resources/org/onosproject/rest/resources/post-virtual-host.json
+++ b/web/api/src/test/resources/org/onosproject/rest/resources/post-virtual-host.json
@@ -3,10 +3,12 @@
"id": "00:11:00:00:00:01/11",
"mac": "00:11:00:00:00:01",
"vlan": "11",
- "location": {
- "elementId": "devid1",
- "port": "100"
- },
+ "locations": [
+ {
+ "elementId": "devid1",
+ "port": "100"
+ }
+ ],
"ipAddresses": [
"10.0.0.1",
"10.0.0.2"