tom

Speeding up stuff.

HostDescription now passes up just a single IpAddress.
/**
* REST resources for the sample topology viewer application.
* Sample topology viewer application.
*/
package org.onlab.onos.tvue;
......
......@@ -22,8 +22,10 @@ public class SummaryCommand extends AbstractShellCommand {
protected void execute() {
TopologyService topologyService = get(TopologyService.class);
Topology topology = topologyService.currentTopology();
print("version=%s, nodes=%d, devices=%d, links=%d, hosts=%d, clusters=%s, paths=%d, flows=%d, intents=%d",
get(CoreService.class).version().toString(),
print("node=%s, version=%s",
get(ClusterService.class).getLocalNode().ip(),
get(CoreService.class).version().toString());
print("nodes=%d, devices=%d, links=%d, hosts=%d, clusters=%s, paths=%d, flows=%d, intents=%d",
get(ClusterService.class).getNodes().size(),
get(DeviceService.class).getDeviceCount(),
get(LinkService.class).getLinkCount(),
......
package org.onlab.onos.net.host;
import com.google.common.collect.ImmutableSet;
import org.onlab.onos.net.AbstractDescription;
import org.onlab.onos.net.HostLocation;
import org.onlab.onos.net.SparseAnnotations;
......@@ -8,9 +7,6 @@ import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import java.util.HashSet;
import java.util.Set;
import static com.google.common.base.MoreObjects.toStringHelper;
/**
......@@ -22,7 +18,7 @@ public class DefaultHostDescription extends AbstractDescription
private final MacAddress mac;
private final VlanId vlan;
private final HostLocation location;
private final Set<IpPrefix> ips;
private final IpPrefix ip;
/**
* Creates a host description using the supplied information.
......@@ -35,7 +31,7 @@ public class DefaultHostDescription extends AbstractDescription
public DefaultHostDescription(MacAddress mac, VlanId vlan,
HostLocation location,
SparseAnnotations... annotations) {
this(mac, vlan, location, new HashSet<IpPrefix>(), annotations);
this(mac, vlan, location, null, annotations);
}
/**
......@@ -44,17 +40,17 @@ public class DefaultHostDescription extends AbstractDescription
* @param mac host MAC address
* @param vlan host VLAN identifier
* @param location host location
* @param ips of host IP addresses
* @param ip host IP address
* @param annotations optional key/value annotations map
*/
public DefaultHostDescription(MacAddress mac, VlanId vlan,
HostLocation location, Set<IpPrefix> ips,
HostLocation location, IpPrefix ip,
SparseAnnotations... annotations) {
super(annotations);
this.mac = mac;
this.vlan = vlan;
this.location = location;
this.ips = new HashSet<>(ips);
this.ip = ip;
}
@Override
......@@ -73,8 +69,8 @@ public class DefaultHostDescription extends AbstractDescription
}
@Override
public Set<IpPrefix> ipAddresses() {
return ImmutableSet.copyOf(ips);
public IpPrefix ipAddress() {
return ip;
}
@Override
......@@ -83,7 +79,7 @@ public class DefaultHostDescription extends AbstractDescription
.add("mac", mac)
.add("vlan", vlan)
.add("location", location)
.add("ipAddresses", ips)
.add("ipAddress", ip)
.toString();
}
......
package org.onlab.onos.net.host;
import java.util.Set;
import org.onlab.onos.net.Description;
import org.onlab.onos.net.HostLocation;
import org.onlab.packet.IpPrefix;
......@@ -35,10 +33,10 @@ public interface HostDescription extends Description {
HostLocation location();
/**
* Returns zero or more IP address(es) associated with this host's MAC.
* Returns the IP address associated with this host's MAC.
*
* @return a set of IP addresses.
* @return host IP address
*/
Set<IpPrefix> ipAddresses();
IpPrefix ipAddress();
}
......
......@@ -45,15 +45,18 @@ public class AbstractEventAccumulatorTest {
public void timeTrigger() {
TestAccumulator accumulator = new TestAccumulator();
accumulator.add(new TestEvent(FOO, "a"));
delay(40);
delay(30);
assertTrue("should not have fired yet", accumulator.batch.isEmpty());
accumulator.add(new TestEvent(FOO, "b"));
delay(40);
delay(30);
assertTrue("should not have fired yet", accumulator.batch.isEmpty());
accumulator.add(new TestEvent(FOO, "c"));
delay(40);
delay(30);
assertTrue("should not have fired yet", accumulator.batch.isEmpty());
accumulator.add(new TestEvent(FOO, "d"));
delay(30);
assertFalse("should have fired", accumulator.batch.isEmpty());
assertEquals("incorrect batch", "abc", accumulator.batch);
assertEquals("incorrect batch", "abcd", accumulator.batch);
}
@Test
......
package org.onlab.onos.net.host;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.Set;
import org.junit.Test;
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.HostLocation;
......@@ -13,7 +8,8 @@ import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import com.google.common.collect.Sets;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* Test for the default host description.
......@@ -22,24 +18,22 @@ public class DefualtHostDecriptionTest {
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 IpPrefix IP = IpPrefix.valueOf("10.0.0.1");
private static final HostLocation LOC = new HostLocation(
DeviceId.deviceId("of:foo"),
PortNumber.portNumber(100),
123L
);
private static final Set<IpPrefix> IPS = Sets.newHashSet(
IpPrefix.valueOf("10.0.0.1"),
IpPrefix.valueOf("10.0.0.2")
);
@Test
public void basics() {
HostDescription host =
new DefaultHostDescription(MAC, VLAN, LOC, IPS);
new DefaultHostDescription(MAC, VLAN, LOC, IP);
assertEquals("incorrect mac", MAC, host.hwAddress());
assertEquals("incorrect vlan", VLAN, host.vlan());
assertEquals("incorrect location", LOC, host.location());
assertTrue("incorrect ip's", IPS.equals(host.ipAddresses()));
assertEquals("incorrect ip's", IP, host.ipAddress());
assertTrue("incorrect toString", host.toString().contains("vlan=10"));
}
......
......@@ -168,7 +168,6 @@ public class HostManager
checkNotNull(hostId, HOST_ID_NULL);
HostEvent event = store.removeHost(hostId);
if (event != null) {
log.info("Host {} administratively removed", hostId);
post(event);
}
}
......@@ -214,7 +213,6 @@ public class HostManager
HostEvent event = store.createOrUpdateHost(provider().id(), hostId,
hostDescription);
if (event != null) {
log.debug("Host {} detected", hostId);
post(event);
}
}
......@@ -225,7 +223,6 @@ public class HostManager
checkValidity();
HostEvent event = store.removeHost(hostId);
if (event != null) {
log.debug("Host {} vanished", hostId);
post(event);
}
}
......
......@@ -58,8 +58,6 @@ public class HostManagerTest {
private static final IpPrefix IP1 = IpPrefix.valueOf("10.0.0.1");
private static final IpPrefix IP2 = IpPrefix.valueOf("10.0.0.2");
private static final Set<IpPrefix> IPSET1 = Sets.newHashSet(IP1);
private static final Set<IpPrefix> IPSET2 = Sets.newHashSet(IP2);
private static final DeviceId DID1 = DeviceId.deviceId("of:001");
private static final DeviceId DID2 = DeviceId.deviceId("of:002");
......@@ -109,8 +107,8 @@ public class HostManagerTest {
}
private void detect(HostId hid, MacAddress mac, VlanId vlan,
HostLocation loc, Set<IpPrefix> ips) {
HostDescription descr = new DefaultHostDescription(mac, vlan, loc, ips);
HostLocation loc, IpPrefix ip) {
HostDescription descr = new DefaultHostDescription(mac, vlan, loc, ip);
providerService.hostDetected(hid, descr);
assertNotNull("host should be found", mgr.getHost(hid));
}
......@@ -130,26 +128,26 @@ public class HostManagerTest {
assertNull("host shouldn't be found", mgr.getHost(HID1));
// host addition
detect(HID1, MAC1, VLAN1, LOC1, IPSET1);
detect(HID1, MAC1, VLAN1, LOC1, IP1);
assertEquals("exactly one should be found", 1, mgr.getHostCount());
detect(HID2, MAC2, VLAN2, LOC2, IPSET1);
detect(HID2, MAC2, VLAN2, LOC2, IP1);
assertEquals("two hosts should be found", 2, mgr.getHostCount());
validateEvents(HOST_ADDED, HOST_ADDED);
// host motion
detect(HID1, MAC1, VLAN1, LOC2, IPSET1);
detect(HID1, MAC1, VLAN1, LOC2, IP1);
validateEvents(HOST_MOVED);
assertEquals("only two hosts should be found", 2, mgr.getHostCount());
// host update
detect(HID1, MAC1, VLAN1, LOC2, IPSET2);
detect(HID1, MAC1, VLAN1, LOC2, IP2);
validateEvents(HOST_UPDATED);
assertEquals("only two hosts should be found", 2, mgr.getHostCount());
}
@Test
public void hostVanished() {
detect(HID1, MAC1, VLAN1, LOC1, IPSET1);
detect(HID1, MAC1, VLAN1, LOC1, IP1);
providerService.hostVanished(HID1);
validateEvents(HOST_ADDED, HOST_REMOVED);
......@@ -157,7 +155,7 @@ public class HostManagerTest {
}
private void validateHosts(
String msg, Iterable<Host> hosts, HostId ... ids) {
String msg, Iterable<Host> hosts, HostId... ids) {
Set<HostId> hids = Sets.newHashSet(ids);
for (Host h : hosts) {
assertTrue(msg, hids.remove(h.id()));
......@@ -167,8 +165,8 @@ public class HostManagerTest {
@Test
public void getHosts() {
detect(HID1, MAC1, VLAN1, LOC1, IPSET1);
detect(HID2, MAC2, VLAN1, LOC2, IPSET2);
detect(HID1, MAC1, VLAN1, LOC1, IP1);
detect(HID2, MAC2, VLAN1, LOC2, IP2);
validateHosts("host not properly stored", mgr.getHosts(), HID1, HID2);
validateHosts("can't get hosts by VLAN", mgr.getHostsByVlan(VLAN1), HID1, HID2);
......
package org.onlab.onos.store.host.impl;
import static org.onlab.onos.net.host.HostEvent.Type.HOST_ADDED;
import static org.onlab.onos.net.host.HostEvent.Type.HOST_MOVED;
import static org.onlab.onos.net.host.HostEvent.Type.HOST_REMOVED;
import static org.onlab.onos.net.host.HostEvent.Type.HOST_UPDATED;
import static org.slf4j.LoggerFactory.getLogger;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Service;
import org.onlab.onos.net.Annotations;
import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.DefaultHost;
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.Host;
import org.onlab.onos.net.HostId;
import org.onlab.onos.net.HostLocation;
import org.onlab.onos.net.host.HostDescription;
import org.onlab.onos.net.host.HostEvent;
import org.onlab.onos.net.host.HostStore;
......@@ -33,10 +27,13 @@ import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.slf4j.Logger;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import static org.onlab.onos.net.host.HostEvent.Type.*;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Manages inventory of end-station hosts using trivial in-memory
......@@ -46,13 +43,13 @@ import com.google.common.collect.Sets;
@Component(immediate = true)
@Service
public class DistributedHostStore
extends AbstractStore<HostEvent, HostStoreDelegate>
implements HostStore {
extends AbstractStore<HostEvent, HostStoreDelegate>
implements HostStore {
private final Logger log = getLogger(getClass());
// Host inventory
private final Map<HostId, Host> hosts = new ConcurrentHashMap<>();
private final Map<HostId, StoredHost> hosts = new ConcurrentHashMap<>(2000000, 0.75f, 16);
// Hosts tracked by their location
private final Multimap<ConnectPoint, Host> locations = HashMultimap.create();
......@@ -73,7 +70,7 @@ implements HostStore {
@Override
public HostEvent createOrUpdateHost(ProviderId providerId, HostId hostId,
HostDescription hostDescription) {
Host host = hosts.get(hostId);
StoredHost host = hosts.get(hostId);
if (host == null) {
return createHost(providerId, hostId, hostDescription);
}
......@@ -83,11 +80,11 @@ implements HostStore {
// creates a new host and sends HOST_ADDED
private HostEvent createHost(ProviderId providerId, HostId hostId,
HostDescription descr) {
DefaultHost newhost = new DefaultHost(providerId, hostId,
StoredHost newhost = new StoredHost(providerId, hostId,
descr.hwAddress(),
descr.vlan(),
descr.location(),
descr.ipAddresses());
ImmutableSet.of(descr.ipAddress()));
synchronized (this) {
hosts.put(hostId, newhost);
locations.put(descr.location(), newhost);
......@@ -96,28 +93,24 @@ implements HostStore {
}
// checks for type of update to host, sends appropriate event
private HostEvent updateHost(ProviderId providerId, Host host,
private HostEvent updateHost(ProviderId providerId, StoredHost host,
HostDescription descr) {
DefaultHost updated;
HostEvent event;
if (!host.location().equals(descr.location())) {
updated = new DefaultHost(providerId, host.id(),
host.mac(),
host.vlan(),
descr.location(),
host.ipAddresses());
event = new HostEvent(HOST_MOVED, updated);
host.setLocation(descr.location());
return new HostEvent(HOST_MOVED, host);
}
} else if (!(host.ipAddresses().equals(descr.ipAddresses()))) {
updated = new DefaultHost(providerId, host.id(),
host.mac(),
host.vlan(),
descr.location(),
descr.ipAddresses());
event = new HostEvent(HOST_UPDATED, updated);
} else {
if (host.ipAddresses().contains(descr.ipAddress())) {
return null;
}
Set<IpPrefix> addresses = new HashSet<>(host.ipAddresses());
addresses.add(descr.ipAddress());
StoredHost updated = new StoredHost(providerId, host.id(),
host.mac(), host.vlan(),
descr.location(), addresses);
event = new HostEvent(HOST_UPDATED, updated);
synchronized (this) {
hosts.put(host.id(), updated);
locations.remove(host.location(), host);
......@@ -145,7 +138,7 @@ implements HostStore {
@Override
public Iterable<Host> getHosts() {
return Collections.unmodifiableSet(new HashSet<>(hosts.values()));
return ImmutableSet.<Host>copyOf(hosts.values());
}
@Override
......@@ -275,4 +268,35 @@ implements HostStore {
return addresses;
}
// Auxiliary extension to allow location to mutate.
private class StoredHost extends DefaultHost {
private HostLocation location;
/**
* 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 annotations optional key/value annotations
*/
public StoredHost(ProviderId providerId, HostId id,
MacAddress mac, VlanId vlan, HostLocation location,
Set<IpPrefix> ips, Annotations... annotations) {
super(providerId, id, mac, vlan, location, ips, annotations);
this.location = location;
}
void setLocation(HostLocation location) {
this.location = location;
}
@Override
public HostLocation location() {
return location;
}
}
}
......
package org.onlab.onos.store.host.impl;
import static org.onlab.onos.net.host.HostEvent.Type.HOST_ADDED;
import static org.onlab.onos.net.host.HostEvent.Type.HOST_MOVED;
import static org.onlab.onos.net.host.HostEvent.Type.HOST_REMOVED;
import static org.onlab.onos.net.host.HostEvent.Type.HOST_UPDATED;
import static org.slf4j.LoggerFactory.getLogger;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Service;
import org.onlab.onos.net.Annotations;
import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.DefaultHost;
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.Host;
import org.onlab.onos.net.HostId;
import org.onlab.onos.net.HostLocation;
import org.onlab.onos.net.host.HostDescription;
import org.onlab.onos.net.host.HostEvent;
import org.onlab.onos.net.host.HostStore;
......@@ -33,10 +27,13 @@ import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.slf4j.Logger;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import static org.onlab.onos.net.host.HostEvent.Type.*;
import static org.slf4j.LoggerFactory.getLogger;
/**
* TEMPORARY: Manages inventory of end-station hosts using distributed
......@@ -46,13 +43,13 @@ import com.google.common.collect.Sets;
@Component(immediate = true)
@Service
public class DistributedHostStore
extends AbstractStore<HostEvent, HostStoreDelegate>
implements HostStore {
extends AbstractStore<HostEvent, HostStoreDelegate>
implements HostStore {
private final Logger log = getLogger(getClass());
// Host inventory
private final Map<HostId, Host> hosts = new ConcurrentHashMap<>();
private final Map<HostId, StoredHost> hosts = new ConcurrentHashMap<>(2000000, 0.75f, 16);
// Hosts tracked by their location
private final Multimap<ConnectPoint, Host> locations = HashMultimap.create();
......@@ -73,7 +70,7 @@ implements HostStore {
@Override
public HostEvent createOrUpdateHost(ProviderId providerId, HostId hostId,
HostDescription hostDescription) {
Host host = hosts.get(hostId);
StoredHost host = hosts.get(hostId);
if (host == null) {
return createHost(providerId, hostId, hostDescription);
}
......@@ -83,11 +80,11 @@ implements HostStore {
// creates a new host and sends HOST_ADDED
private HostEvent createHost(ProviderId providerId, HostId hostId,
HostDescription descr) {
DefaultHost newhost = new DefaultHost(providerId, hostId,
StoredHost newhost = new StoredHost(providerId, hostId,
descr.hwAddress(),
descr.vlan(),
descr.location(),
descr.ipAddresses());
ImmutableSet.of(descr.ipAddress()));
synchronized (this) {
hosts.put(hostId, newhost);
locations.put(descr.location(), newhost);
......@@ -96,28 +93,24 @@ implements HostStore {
}
// checks for type of update to host, sends appropriate event
private HostEvent updateHost(ProviderId providerId, Host host,
private HostEvent updateHost(ProviderId providerId, StoredHost host,
HostDescription descr) {
DefaultHost updated;
HostEvent event;
if (!host.location().equals(descr.location())) {
updated = new DefaultHost(providerId, host.id(),
host.mac(),
host.vlan(),
descr.location(),
host.ipAddresses());
event = new HostEvent(HOST_MOVED, updated);
host.setLocation(descr.location());
return new HostEvent(HOST_MOVED, host);
}
} else if (!(host.ipAddresses().equals(descr.ipAddresses()))) {
updated = new DefaultHost(providerId, host.id(),
host.mac(),
host.vlan(),
descr.location(),
descr.ipAddresses());
event = new HostEvent(HOST_UPDATED, updated);
} else {
if (host.ipAddresses().contains(descr.ipAddress())) {
return null;
}
Set<IpPrefix> addresses = new HashSet<>(host.ipAddresses());
addresses.add(descr.ipAddress());
StoredHost updated = new StoredHost(providerId, host.id(),
host.mac(), host.vlan(),
descr.location(), addresses);
event = new HostEvent(HOST_UPDATED, updated);
synchronized (this) {
hosts.put(host.id(), updated);
locations.remove(host.location(), host);
......@@ -145,7 +138,7 @@ implements HostStore {
@Override
public Iterable<Host> getHosts() {
return Collections.unmodifiableSet(new HashSet<>(hosts.values()));
return ImmutableSet.<Host>copyOf(hosts.values());
}
@Override
......@@ -275,4 +268,35 @@ implements HostStore {
return addresses;
}
// Auxiliary extension to allow location to mutate.
private class StoredHost extends DefaultHost {
private HostLocation location;
/**
* 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 annotations optional key/value annotations
*/
public StoredHost(ProviderId providerId, HostId id,
MacAddress mac, VlanId vlan, HostLocation location,
Set<IpPrefix> ips, Annotations... annotations) {
super(providerId, id, mac, vlan, location, ips, annotations);
this.location = location;
}
void setLocation(HostLocation location) {
this.location = location;
}
@Override
public HostLocation location() {
return location;
}
}
}
......
package org.onlab.onos.store.trivial.impl;
import static org.onlab.onos.net.host.HostEvent.Type.HOST_ADDED;
import static org.onlab.onos.net.host.HostEvent.Type.HOST_MOVED;
import static org.onlab.onos.net.host.HostEvent.Type.HOST_REMOVED;
import static org.onlab.onos.net.host.HostEvent.Type.HOST_UPDATED;
import static org.slf4j.LoggerFactory.getLogger;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Service;
import org.onlab.onos.net.Annotations;
import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.DefaultHost;
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.Host;
import org.onlab.onos.net.HostId;
import org.onlab.onos.net.HostLocation;
import org.onlab.onos.net.host.HostDescription;
import org.onlab.onos.net.host.HostEvent;
import org.onlab.onos.net.host.HostStore;
......@@ -33,10 +27,13 @@ import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.slf4j.Logger;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import static org.onlab.onos.net.host.HostEvent.Type.*;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Manages inventory of end-station hosts using trivial in-memory
......@@ -51,7 +48,7 @@ public class SimpleHostStore
private final Logger log = getLogger(getClass());
// Host inventory
private final Map<HostId, Host> hosts = new ConcurrentHashMap<>();
private final Map<HostId, StoredHost> hosts = new ConcurrentHashMap<>(2000000, 0.75f, 16);
// Hosts tracked by their location
private final Multimap<ConnectPoint, Host> locations = HashMultimap.create();
......@@ -72,7 +69,7 @@ public class SimpleHostStore
@Override
public HostEvent createOrUpdateHost(ProviderId providerId, HostId hostId,
HostDescription hostDescription) {
Host host = hosts.get(hostId);
StoredHost host = hosts.get(hostId);
if (host == null) {
return createHost(providerId, hostId, hostDescription);
}
......@@ -82,11 +79,11 @@ public class SimpleHostStore
// creates a new host and sends HOST_ADDED
private HostEvent createHost(ProviderId providerId, HostId hostId,
HostDescription descr) {
DefaultHost newhost = new DefaultHost(providerId, hostId,
StoredHost newhost = new StoredHost(providerId, hostId,
descr.hwAddress(),
descr.vlan(),
descr.location(),
descr.ipAddresses());
ImmutableSet.of(descr.ipAddress()));
synchronized (this) {
hosts.put(hostId, newhost);
locations.put(descr.location(), newhost);
......@@ -95,28 +92,24 @@ public class SimpleHostStore
}
// checks for type of update to host, sends appropriate event
private HostEvent updateHost(ProviderId providerId, Host host,
private HostEvent updateHost(ProviderId providerId, StoredHost host,
HostDescription descr) {
DefaultHost updated;
HostEvent event;
if (!host.location().equals(descr.location())) {
updated = new DefaultHost(providerId, host.id(),
host.mac(),
host.vlan(),
descr.location(),
host.ipAddresses());
event = new HostEvent(HOST_MOVED, updated);
host.setLocation(descr.location());
return new HostEvent(HOST_MOVED, host);
}
} else if (!(host.ipAddresses().equals(descr.ipAddresses()))) {
updated = new DefaultHost(providerId, host.id(),
host.mac(),
host.vlan(),
descr.location(),
descr.ipAddresses());
event = new HostEvent(HOST_UPDATED, updated);
} else {
if (host.ipAddresses().contains(descr.ipAddress())) {
return null;
}
Set<IpPrefix> addresses = new HashSet<>(host.ipAddresses());
addresses.add(descr.ipAddress());
StoredHost updated = new StoredHost(providerId, host.id(),
host.mac(), host.vlan(),
descr.location(), addresses);
event = new HostEvent(HOST_UPDATED, updated);
synchronized (this) {
hosts.put(host.id(), updated);
locations.remove(host.location(), host);
......@@ -144,7 +137,7 @@ public class SimpleHostStore
@Override
public Iterable<Host> getHosts() {
return Collections.unmodifiableSet(new HashSet<>(hosts.values()));
return ImmutableSet.<Host>copyOf(hosts.values());
}
@Override
......@@ -274,4 +267,35 @@ public class SimpleHostStore
return addresses;
}
// Auxiliary extension to allow location to mutate.
private class StoredHost extends DefaultHost {
private HostLocation location;
/**
* 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 annotations optional key/value annotations
*/
public StoredHost(ProviderId providerId, HostId id,
MacAddress mac, VlanId vlan, HostLocation location,
Set<IpPrefix> ips, Annotations... annotations) {
super(providerId, id, mac, vlan, location, ips, annotations);
this.location = location;
}
void setLocation(HostLocation location) {
this.location = location;
}
@Override
public HostLocation location() {
return location;
}
}
}
......
......@@ -493,7 +493,7 @@
<group>
<title>Core Subsystems</title>
<packages>
org.onlab.onos.cluster.impl:org.onlab.onos.net.device.impl:org.onlab.onos.net.link.impl:org.onlab.onos.net.host.impl:org.onlab.onos.net.topology.impl:org.onlab.onos.net.packet.impl:org.onlab.onos.net.flow.impl:org.onlab.onos.store.trivial.*:org.onlab.onos.net.*.impl:org.onlab.onos.event.impl:org.onlab.onos.store.*:org.onlab.onos.net.intent.impl
org.onlab.onos.impl:org.onlab.onos.cluster.impl:org.onlab.onos.net.device.impl:org.onlab.onos.net.link.impl:org.onlab.onos.net.host.impl:org.onlab.onos.net.topology.impl:org.onlab.onos.net.packet.impl:org.onlab.onos.net.flow.impl:org.onlab.onos.store.trivial.*:org.onlab.onos.net.*.impl:org.onlab.onos.event.impl:org.onlab.onos.store.*:org.onlab.onos.net.intent.impl:org.onlab.onos.net.proxyarp.impl
</packages>
</group>
<group>
......@@ -518,7 +518,7 @@
<group>
<title>Sample Applications</title>
<packages>
org.onlab.onos.tvue:org.onlab.onos.fwd:org.onlab.onos.foo
org.onlab.onos.tvue:org.onlab.onos.fwd:org.onlab.onos.ifwd:org.onlab.onos.mobility:org.onlab.onos.proxyarp:org.onlab.onos.foo
</packages>
</group>
</groups>
......
package org.onlab.onos.provider.of.host.impl;
import static com.google.common.collect.Sets.newHashSet;
import static org.onlab.onos.net.DeviceId.deviceId;
import static org.onlab.onos.net.PortNumber.portNumber;
import static org.slf4j.LoggerFactory.getLogger;
import java.util.Set;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
......@@ -36,6 +29,10 @@ import org.onlab.packet.IpPrefix;
import org.onlab.packet.VlanId;
import org.slf4j.Logger;
import static org.onlab.onos.net.DeviceId.deviceId;
import static org.onlab.onos.net.PortNumber.portNumber;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Provider which uses an OpenFlow controller to detect network
* end-station hosts.
......@@ -58,6 +55,8 @@ public class OpenFlowHostProvider extends AbstractProvider implements HostProvid
private final InternalHostProvider listener = new InternalHostProvider();
private boolean ipLearn = true;
/**
* Creates an OpenFlow host provider.
*/
......@@ -69,7 +68,6 @@ public class OpenFlowHostProvider extends AbstractProvider implements HostProvid
public void activate() {
providerService = providerRegistry.register(this);
controller.addPacketListener(10, listener);
log.info("Started");
}
......@@ -78,7 +76,6 @@ public class OpenFlowHostProvider extends AbstractProvider implements HostProvid
providerRegistry.unregister(this);
controller.removePacketListener(listener);
providerService = null;
log.info("Stopped");
}
......@@ -106,22 +103,22 @@ public class OpenFlowHostProvider extends AbstractProvider implements HostProvid
HostLocation hloc = new HostLocation(deviceId(Dpid.uri(pktCtx.dpid())),
portNumber(pktCtx.inPort()),
System.currentTimeMillis());
HostId hid = HostId.hostId(eth.getSourceMAC(), vlan);
// Potentially a new or moved host
if (eth.getEtherType() == Ethernet.TYPE_ARP) {
ARP arp = (ARP) eth.getPayload();
Set<IpPrefix> ips = newHashSet(IpPrefix.valueOf(arp.getSenderProtocolAddress()));
IpPrefix ip = IpPrefix.valueOf(arp.getSenderProtocolAddress());
HostDescription hdescr =
new DefaultHostDescription(eth.getSourceMAC(), vlan, hloc, ips);
new DefaultHostDescription(eth.getSourceMAC(), vlan, hloc, ip);
providerService.hostDetected(hid, hdescr);
} else if (eth.getEtherType() == Ethernet.TYPE_IPV4) {
IPv4 ip = (IPv4) eth.getPayload();
Set<IpPrefix> ips = newHashSet(IpPrefix.valueOf(ip.getSourceAddress()));
} else if (ipLearn && eth.getEtherType() == Ethernet.TYPE_IPV4) {
IPv4 pip = (IPv4) eth.getPayload();
IpPrefix ip = IpPrefix.valueOf(pip.getSourceAddress());
HostDescription hdescr =
new DefaultHostDescription(eth.getSourceMAC(), vlan, hloc, ips);
new DefaultHostDescription(eth.getSourceMAC(), vlan, hloc, ip);
providerService.hostDetected(hid, hdescr);
}
......