Merge branch 'master' of ssh://gerrit.onlab.us:29418/onos-next
better with files
Change-Id: Ifb62a2c9a8e394fe3190582d7236eaea942ee3fc
diff --git a/apps/foo/src/main/java/org/onlab/onos/foo/FooComponent.java b/apps/foo/src/main/java/org/onlab/onos/foo/FooComponent.java
index b9251dd..1fafc32 100644
--- a/apps/foo/src/main/java/org/onlab/onos/foo/FooComponent.java
+++ b/apps/foo/src/main/java/org/onlab/onos/foo/FooComponent.java
@@ -8,6 +8,9 @@
import org.onlab.onos.cluster.ClusterEvent;
import org.onlab.onos.cluster.ClusterEventListener;
import org.onlab.onos.cluster.ClusterService;
+import org.onlab.onos.net.device.DeviceEvent;
+import org.onlab.onos.net.device.DeviceListener;
+import org.onlab.onos.net.device.DeviceService;
import org.slf4j.Logger;
import static org.slf4j.LoggerFactory.getLogger;
@@ -23,17 +26,23 @@
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected ClusterService clusterService;
- private ClusterEventListener clusterListener = new InnerClusterListener();
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected DeviceService deviceService;
+
+ private final ClusterEventListener clusterListener = new InnerClusterListener();
+ private final DeviceListener deviceListener = new InnerDeviceListener();
@Activate
public void activate() {
clusterService.addListener(clusterListener);
+ deviceService.addListener(deviceListener);
log.info("Started");
}
@Deactivate
public void deactivate() {
clusterService.removeListener(clusterListener);
+ deviceService.removeListener(deviceListener);
log.info("Stopped");
}
@@ -43,6 +52,13 @@
log.info("WOOOOT! {}", event);
}
}
+
+ private class InnerDeviceListener implements DeviceListener {
+ @Override
+ public void event(DeviceEvent event) {
+ log.info("YEEEEHAAAAW! {}", event);
+ }
+ }
}
diff --git a/apps/foo/src/main/java/org/onlab/onos/foo/package-info.java b/apps/foo/src/main/java/org/onlab/onos/foo/package-info.java
new file mode 100644
index 0000000..6372772
--- /dev/null
+++ b/apps/foo/src/main/java/org/onlab/onos/foo/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Sample application for use in various experiments.
+ */
+package org.onlab.onos.foo;
\ No newline at end of file
diff --git a/core/api/src/main/java/org/onlab/onos/ApplicationId.java b/core/api/src/main/java/org/onlab/onos/ApplicationId.java
new file mode 100644
index 0000000..f345607
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/ApplicationId.java
@@ -0,0 +1,59 @@
+package org.onlab.onos;
+
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Application id generator class.
+ */
+public final class ApplicationId {
+
+ private static AtomicInteger idDispenser;
+ private final Integer id;
+
+ // Ban public construction
+ private ApplicationId(Integer id) {
+ this.id = id;
+ }
+
+ public Integer id() {
+ return id;
+ }
+
+ public static ApplicationId valueOf(Integer id) {
+ return new ApplicationId(id);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof ApplicationId)) {
+ return false;
+ }
+ ApplicationId other = (ApplicationId) obj;
+ return Objects.equals(this.id, other.id);
+ }
+
+ /**
+ * Returns a new application id.
+ *
+ * @return app id
+ */
+ public static ApplicationId getAppId() {
+ if (ApplicationId.idDispenser == null) {
+ ApplicationId.idDispenser = new AtomicInteger(1);
+ }
+ return new ApplicationId(ApplicationId.idDispenser.getAndIncrement());
+ }
+
+}
diff --git a/core/api/src/main/java/org/onlab/onos/cluster/MastershipStore.java b/core/api/src/main/java/org/onlab/onos/cluster/MastershipStore.java
index 3e2ee03..5c0c207 100644
--- a/core/api/src/main/java/org/onlab/onos/cluster/MastershipStore.java
+++ b/core/api/src/main/java/org/onlab/onos/cluster/MastershipStore.java
@@ -4,12 +4,13 @@
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.MastershipRole;
+import org.onlab.onos.store.Store;
/**
* Manages inventory of mastership roles for devices, across controller
* instances; not intended for direct use.
*/
-public interface MastershipStore {
+public interface MastershipStore extends Store<MastershipEvent, MastershipStoreDelegate> {
// three things to map: NodeId, DeviceId, MastershipRole
@@ -51,9 +52,7 @@
*
* @param nodeId controller instance identifier
* @param deviceId device identifier
- * @param role new role
* @return a mastership event
*/
- MastershipEvent setRole(NodeId nodeId, DeviceId deviceId,
- MastershipRole role);
+ MastershipEvent setMaster(NodeId nodeId, DeviceId deviceId);
}
diff --git a/core/api/src/main/java/org/onlab/onos/net/device/DeviceStore.java b/core/api/src/main/java/org/onlab/onos/net/device/DeviceStore.java
index ef111e9..c84aac8 100644
--- a/core/api/src/main/java/org/onlab/onos/net/device/DeviceStore.java
+++ b/core/api/src/main/java/org/onlab/onos/net/device/DeviceStore.java
@@ -5,13 +5,14 @@
import org.onlab.onos.net.Port;
import org.onlab.onos.net.PortNumber;
import org.onlab.onos.net.provider.ProviderId;
+import org.onlab.onos.store.Store;
import java.util.List;
/**
* Manages inventory of infrastructure devices; not intended for direct use.
*/
-public interface DeviceStore {
+public interface DeviceStore extends Store<DeviceEvent, DeviceStoreDelegate> {
/**
* Returns the number of devices known to the system.
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleStore.java b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleStore.java
index 28793e6..c6093384 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleStore.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleStore.java
@@ -2,11 +2,12 @@
import org.onlab.onos.ApplicationId;
import org.onlab.onos.net.DeviceId;
+import org.onlab.onos.store.Store;
/**
* Manages inventory of flow rules; not intended for direct use.
*/
-public interface FlowRuleStore {
+public interface FlowRuleStore extends Store<FlowRuleEvent, FlowRuleStoreDelegate> {
/**
* Returns the stored flow.
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleStoreDelegate.java b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleStoreDelegate.java
new file mode 100644
index 0000000..119712b
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleStoreDelegate.java
@@ -0,0 +1,9 @@
+package org.onlab.onos.net.flow;
+
+import org.onlab.onos.store.StoreDelegate;
+
+/**
+ * Flow rule store delegate abstraction.
+ */
+public interface FlowRuleStoreDelegate extends StoreDelegate<FlowRuleEvent> {
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/host/HostStore.java b/core/api/src/main/java/org/onlab/onos/net/host/HostStore.java
index e70bbf2..3f1cb23 100644
--- a/core/api/src/main/java/org/onlab/onos/net/host/HostStore.java
+++ b/core/api/src/main/java/org/onlab/onos/net/host/HostStore.java
@@ -1,20 +1,21 @@
package org.onlab.onos.net.host;
-import java.util.Set;
-
import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.Host;
import org.onlab.onos.net.HostId;
import org.onlab.onos.net.provider.ProviderId;
+import org.onlab.onos.store.Store;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
+import java.util.Set;
+
/**
* Manages inventory of end-station hosts; not intended for direct use.
*/
-public interface HostStore {
+public interface HostStore extends Store<HostEvent, HostStoreDelegate> {
/**
* Creates a new host or updates the existing one based on the specified
@@ -133,7 +134,7 @@
* Returns the address bindings for a particular connection point.
*
* @param connectPoint the connection point to return address information
- * for
+ * for
* @return address information for the connection point
*/
PortAddresses getAddressBindingsForPort(ConnectPoint connectPoint);
diff --git a/core/api/src/main/java/org/onlab/onos/net/host/HostStoreDelegate.java b/core/api/src/main/java/org/onlab/onos/net/host/HostStoreDelegate.java
new file mode 100644
index 0000000..999b28f
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/host/HostStoreDelegate.java
@@ -0,0 +1,9 @@
+package org.onlab.onos.net.host;
+
+import org.onlab.onos.store.StoreDelegate;
+
+/**
+ * Infrastructure link store delegate abstraction.
+ */
+public interface HostStoreDelegate extends StoreDelegate<HostEvent> {
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/link/LinkStore.java b/core/api/src/main/java/org/onlab/onos/net/link/LinkStore.java
index dbe4877..0197417 100644
--- a/core/api/src/main/java/org/onlab/onos/net/link/LinkStore.java
+++ b/core/api/src/main/java/org/onlab/onos/net/link/LinkStore.java
@@ -4,13 +4,14 @@
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.provider.ProviderId;
+import org.onlab.onos.store.Store;
import java.util.Set;
/**
* Manages inventory of infrastructure links; not intended for direct use.
*/
-public interface LinkStore {
+public interface LinkStore extends Store<LinkEvent, LinkStoreDelegate> {
/**
* Returns the number of links in the store.
diff --git a/core/api/src/main/java/org/onlab/onos/net/link/LinkStoreDelegate.java b/core/api/src/main/java/org/onlab/onos/net/link/LinkStoreDelegate.java
new file mode 100644
index 0000000..ec747c4
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/link/LinkStoreDelegate.java
@@ -0,0 +1,9 @@
+package org.onlab.onos.net.link;
+
+import org.onlab.onos.store.StoreDelegate;
+
+/**
+ * Infrastructure link store delegate abstraction.
+ */
+public interface LinkStoreDelegate extends StoreDelegate<LinkEvent> {
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/topology/TopologyStore.java b/core/api/src/main/java/org/onlab/onos/net/topology/TopologyStore.java
index adc6145..1945f4c 100644
--- a/core/api/src/main/java/org/onlab/onos/net/topology/TopologyStore.java
+++ b/core/api/src/main/java/org/onlab/onos/net/topology/TopologyStore.java
@@ -6,6 +6,7 @@
import org.onlab.onos.net.Link;
import org.onlab.onos.net.Path;
import org.onlab.onos.net.provider.ProviderId;
+import org.onlab.onos.store.Store;
import java.util.List;
import java.util.Set;
@@ -13,7 +14,7 @@
/**
* Manages inventory of topology snapshots; not intended for direct use.
*/
-public interface TopologyStore {
+public interface TopologyStore extends Store<TopologyEvent, TopologyStoreDelegate> {
/**
* Returns the current topology snapshot.
diff --git a/core/api/src/main/java/org/onlab/onos/net/topology/TopologyStoreDelegate.java b/core/api/src/main/java/org/onlab/onos/net/topology/TopologyStoreDelegate.java
new file mode 100644
index 0000000..2a19a0c
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/topology/TopologyStoreDelegate.java
@@ -0,0 +1,9 @@
+package org.onlab.onos.net.topology;
+
+import org.onlab.onos.store.StoreDelegate;
+
+/**
+ * Topology store delegate abstraction.
+ */
+public interface TopologyStoreDelegate extends StoreDelegate<TopologyEvent> {
+}
diff --git a/core/api/src/main/java/org/onlab/onos/store/AbstractStore.java b/core/api/src/main/java/org/onlab/onos/store/AbstractStore.java
index efd0d03..5d76e0f 100644
--- a/core/api/src/main/java/org/onlab/onos/store/AbstractStore.java
+++ b/core/api/src/main/java/org/onlab/onos/store/AbstractStore.java
@@ -2,6 +2,8 @@
import org.onlab.onos.event.Event;
+import static com.google.common.base.Preconditions.checkState;
+
/**
* Base implementation of a store.
*/
@@ -12,12 +14,21 @@
@Override
public void setDelegate(D delegate) {
+ checkState(this.delegate == null || this.delegate == delegate,
+ "Store delegate already set");
this.delegate = delegate;
}
@Override
- public D getDelegate() {
- return delegate;
+ public void unsetDelegate(D delegate) {
+ if (this.delegate == delegate) {
+ this.delegate = null;
+ }
+ }
+
+ @Override
+ public boolean hasDelegate() {
+ return delegate != null;
}
/**
diff --git a/core/api/src/main/java/org/onlab/onos/store/Store.java b/core/api/src/main/java/org/onlab/onos/store/Store.java
index 9eaef66..28bc08e 100644
--- a/core/api/src/main/java/org/onlab/onos/store/Store.java
+++ b/core/api/src/main/java/org/onlab/onos/store/Store.java
@@ -12,14 +12,25 @@
* Sets the delegate on the store.
*
* @param delegate new store delegate
+ * @throws java.lang.IllegalStateException if a delegate is already
+ * currently set on the store and is a different one that
*/
void setDelegate(D delegate);
/**
- * Get the current store delegate.
+ * Withdraws the delegate from the store.
*
- * @return store delegate
+ * @param delegate store delegate to withdraw
+ * @throws java.lang.IllegalArgumentException if the delegate is not
+ * currently set on the store
*/
- D getDelegate();
+ void unsetDelegate(D delegate);
+
+ /**
+ * Indicates whether the store has a delegate.
+ *
+ * @return true if delegate is set
+ */
+ boolean hasDelegate();
}
diff --git a/core/api/src/main/java/org/onlab/onos/store/StoreDelegate.java b/core/api/src/main/java/org/onlab/onos/store/StoreDelegate.java
index e2c5cd3..c7b0465 100644
--- a/core/api/src/main/java/org/onlab/onos/store/StoreDelegate.java
+++ b/core/api/src/main/java/org/onlab/onos/store/StoreDelegate.java
@@ -8,6 +8,11 @@
*/
public interface StoreDelegate<E extends Event> {
+ /**
+ * Notifies the delegate via the specified event.
+ *
+ * @param event store generated event
+ */
void notify(E event);
}
diff --git a/core/net/pom.xml b/core/net/pom.xml
index b252636..e2703b2 100644
--- a/core/net/pom.xml
+++ b/core/net/pom.xml
@@ -44,6 +44,13 @@
<version>${project.version}</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.onlab.onos</groupId>
+ <artifactId>onos-core-store</artifactId>
+ <version>${project.version}</version>
+ <classifier>tests</classifier>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>org.apache.felix</groupId>
diff --git a/core/net/src/main/java/org/onlab/onos/cluster/impl/ClusterManager.java b/core/net/src/main/java/org/onlab/onos/cluster/impl/ClusterManager.java
index d0cc949..9913ad0 100644
--- a/core/net/src/main/java/org/onlab/onos/cluster/impl/ClusterManager.java
+++ b/core/net/src/main/java/org/onlab/onos/cluster/impl/ClusterManager.java
@@ -53,6 +53,7 @@
@Deactivate
public void deactivate() {
+ store.unsetDelegate(delegate);
eventDispatcher.removeSink(ClusterEvent.class);
log.info("Stopped");
}
diff --git a/core/net/src/main/java/org/onlab/onos/cluster/impl/MastershipManager.java b/core/net/src/main/java/org/onlab/onos/cluster/impl/MastershipManager.java
index 4ac6052..255830c 100644
--- a/core/net/src/main/java/org/onlab/onos/cluster/impl/MastershipManager.java
+++ b/core/net/src/main/java/org/onlab/onos/cluster/impl/MastershipManager.java
@@ -64,9 +64,12 @@
checkNotNull(nodeId, NODE_ID_NULL);
checkNotNull(deviceId, DEVICE_ID_NULL);
checkNotNull(role, ROLE_NULL);
- MastershipEvent event = store.setRole(nodeId, deviceId, role);
- if (event != null) {
- post(event);
+ //TODO figure out appropriate action for non-MASTER roles, if we even set those
+ if (role.equals(MastershipRole.MASTER)) {
+ MastershipEvent event = store.setMaster(nodeId, deviceId);
+ if (event != null) {
+ post(event);
+ }
}
}
diff --git a/core/net/src/main/java/org/onlab/onos/net/device/impl/DeviceManager.java b/core/net/src/main/java/org/onlab/onos/net/device/impl/DeviceManager.java
index 9b6c83a..3dfce00 100644
--- a/core/net/src/main/java/org/onlab/onos/net/device/impl/DeviceManager.java
+++ b/core/net/src/main/java/org/onlab/onos/net/device/impl/DeviceManager.java
@@ -26,6 +26,7 @@
import org.onlab.onos.net.device.DeviceProviderService;
import org.onlab.onos.net.device.DeviceService;
import org.onlab.onos.net.device.DeviceStore;
+import org.onlab.onos.net.device.DeviceStoreDelegate;
import org.onlab.onos.net.device.PortDescription;
import org.onlab.onos.net.provider.AbstractProviderRegistry;
import org.onlab.onos.net.provider.AbstractProviderService;
@@ -33,8 +34,8 @@
import java.util.List;
-import static org.onlab.onos.net.device.DeviceEvent.Type.*;
import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onlab.onos.net.device.DeviceEvent.Type.DEVICE_MASTERSHIP_CHANGED;
import static org.slf4j.LoggerFactory.getLogger;
/**
@@ -57,7 +58,9 @@
protected final AbstractListenerRegistry<DeviceEvent, DeviceListener>
listenerRegistry = new AbstractListenerRegistry<>();
- private final MastershipListener mastershipListener = new InnerMastershipListener();
+ private DeviceStoreDelegate delegate = new InternalStoreDelegate();
+
+ private final MastershipListener mastershipListener = new InternalMastershipListener();
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DeviceStore store;
@@ -73,6 +76,7 @@
@Activate
public void activate() {
+ store.setDelegate(delegate);
eventDispatcher.addSink(DeviceEvent.class, listenerRegistry);
mastershipService.addListener(mastershipListener);
log.info("Started");
@@ -80,6 +84,7 @@
@Deactivate
public void deactivate() {
+ store.unsetDelegate(delegate);
mastershipService.removeListener(mastershipListener);
eventDispatcher.removeSink(DeviceEvent.class);
log.info("Stopped");
@@ -239,7 +244,7 @@
}
// Intercepts mastership events
- private class InnerMastershipListener implements MastershipListener {
+ private class InternalMastershipListener implements MastershipListener {
@Override
public void event(MastershipEvent event) {
// FIXME: for now we're taking action only on becoming master
@@ -248,4 +253,12 @@
}
}
}
+
+ // Store delegate to re-post events emitted from the store.
+ private class InternalStoreDelegate implements DeviceStoreDelegate {
+ @Override
+ public void notify(DeviceEvent event) {
+ post(event);
+ }
+ }
}
diff --git a/core/net/src/main/java/org/onlab/onos/net/flow/impl/FlowRuleManager.java b/core/net/src/main/java/org/onlab/onos/net/flow/impl/FlowRuleManager.java
index 238c4d0..337f437 100644
--- a/core/net/src/main/java/org/onlab/onos/net/flow/impl/FlowRuleManager.java
+++ b/core/net/src/main/java/org/onlab/onos/net/flow/impl/FlowRuleManager.java
@@ -1,11 +1,6 @@
package org.onlab.onos.net.flow.impl;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static org.slf4j.LoggerFactory.getLogger;
-
-import java.util.Iterator;
-import java.util.List;
-
+import com.google.common.collect.Lists;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
@@ -26,11 +21,16 @@
import org.onlab.onos.net.flow.FlowRuleProviderService;
import org.onlab.onos.net.flow.FlowRuleService;
import org.onlab.onos.net.flow.FlowRuleStore;
+import org.onlab.onos.net.flow.FlowRuleStoreDelegate;
import org.onlab.onos.net.provider.AbstractProviderRegistry;
import org.onlab.onos.net.provider.AbstractProviderService;
import org.slf4j.Logger;
-import com.google.common.collect.Lists;
+import java.util.Iterator;
+import java.util.List;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
/**
* Provides implementation of the flow NB & SB APIs.
@@ -47,6 +47,8 @@
private final AbstractListenerRegistry<FlowRuleEvent, FlowRuleListener>
listenerRegistry = new AbstractListenerRegistry<>();
+ private FlowRuleStoreDelegate delegate = new InternalStoreDelegate();
+
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected FlowRuleStore store;
@@ -58,12 +60,14 @@
@Activate
public void activate() {
+ store.setDelegate(delegate);
eventDispatcher.addSink(FlowRuleEvent.class, listenerRegistry);
log.info("Started");
}
@Deactivate
public void deactivate() {
+ store.unsetDelegate(delegate);
eventDispatcher.removeSink(FlowRuleEvent.class);
log.info("Stopped");
}
@@ -249,4 +253,11 @@
}
}
+ // Store delegate to re-post events emitted from the store.
+ private class InternalStoreDelegate implements FlowRuleStoreDelegate {
+ @Override
+ public void notify(FlowRuleEvent event) {
+ eventDispatcher.post(event);
+ }
+ }
}
diff --git a/core/net/src/main/java/org/onlab/onos/net/host/impl/HostManager.java b/core/net/src/main/java/org/onlab/onos/net/host/impl/HostManager.java
index 9b8ecf7..e3f53fe 100644
--- a/core/net/src/main/java/org/onlab/onos/net/host/impl/HostManager.java
+++ b/core/net/src/main/java/org/onlab/onos/net/host/impl/HostManager.java
@@ -1,10 +1,5 @@
package org.onlab.onos.net.host.impl;
-import static com.google.common.base.Preconditions.checkNotNull;
-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;
@@ -26,6 +21,7 @@
import org.onlab.onos.net.host.HostProviderService;
import org.onlab.onos.net.host.HostService;
import org.onlab.onos.net.host.HostStore;
+import org.onlab.onos.net.host.HostStoreDelegate;
import org.onlab.onos.net.host.PortAddresses;
import org.onlab.onos.net.provider.AbstractProviderRegistry;
import org.onlab.onos.net.provider.AbstractProviderService;
@@ -35,6 +31,11 @@
import org.onlab.packet.VlanId;
import org.slf4j.Logger;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
/**
* Provides basic implementation of the host SB & NB APIs.
*/
@@ -50,6 +51,8 @@
private final AbstractListenerRegistry<HostEvent, HostListener>
listenerRegistry = new AbstractListenerRegistry<>();
+ private HostStoreDelegate delegate = new InternalStoreDelegate();
+
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected HostStore store;
@@ -59,12 +62,14 @@
@Activate
public void activate() {
+ store.setDelegate(delegate);
eventDispatcher.addSink(HostEvent.class, listenerRegistry);
log.info("Started");
}
@Deactivate
public void deactivate() {
+ store.unsetDelegate(delegate);
eventDispatcher.removeSink(HostEvent.class);
log.info("Stopped");
}
@@ -219,4 +224,11 @@
}
}
+ // Store delegate to re-post events emitted from the store.
+ private class InternalStoreDelegate implements HostStoreDelegate {
+ @Override
+ public void notify(HostEvent event) {
+ post(event);
+ }
+ }
}
diff --git a/core/net/src/main/java/org/onlab/onos/net/link/impl/LinkManager.java b/core/net/src/main/java/org/onlab/onos/net/link/impl/LinkManager.java
index 9ac5e80..493580d 100644
--- a/core/net/src/main/java/org/onlab/onos/net/link/impl/LinkManager.java
+++ b/core/net/src/main/java/org/onlab/onos/net/link/impl/LinkManager.java
@@ -28,6 +28,7 @@
import org.onlab.onos.net.link.LinkProviderService;
import org.onlab.onos.net.link.LinkService;
import org.onlab.onos.net.link.LinkStore;
+import org.onlab.onos.net.link.LinkStoreDelegate;
import org.onlab.onos.net.provider.AbstractProviderRegistry;
import org.onlab.onos.net.provider.AbstractProviderService;
import org.slf4j.Logger;
@@ -52,7 +53,9 @@
protected final AbstractListenerRegistry<LinkEvent, LinkListener>
listenerRegistry = new AbstractListenerRegistry<>();
- private final DeviceListener deviceListener = new InnerDeviceListener();
+ private LinkStoreDelegate delegate = new InternalStoreDelegate();
+
+ private final DeviceListener deviceListener = new InternalDeviceListener();
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected LinkStore store;
@@ -65,6 +68,7 @@
@Activate
public void activate() {
+ store.setDelegate(delegate);
eventDispatcher.addSink(LinkEvent.class, listenerRegistry);
deviceService.addListener(deviceListener);
log.info("Started");
@@ -72,6 +76,7 @@
@Deactivate
public void deactivate() {
+ store.unsetDelegate(delegate);
eventDispatcher.removeSink(LinkEvent.class);
deviceService.removeListener(deviceListener);
log.info("Stopped");
@@ -154,7 +159,7 @@
// Auxiliary interceptor for device remove events to prune links that
// are associated with the removed device or its port.
- private class InnerDeviceListener implements DeviceListener {
+ private class InternalDeviceListener implements DeviceListener {
@Override
public void event(DeviceEvent event) {
if (event.type() == DeviceEvent.Type.DEVICE_REMOVED) {
@@ -236,4 +241,11 @@
}
}
+ // Store delegate to re-post events emitted from the store.
+ private class InternalStoreDelegate implements LinkStoreDelegate {
+ @Override
+ public void notify(LinkEvent event) {
+ post(event);
+ }
+ }
}
diff --git a/core/net/src/main/java/org/onlab/onos/net/topology/impl/TopologyManager.java b/core/net/src/main/java/org/onlab/onos/net/topology/impl/TopologyManager.java
index 57e9fb7..4846944 100644
--- a/core/net/src/main/java/org/onlab/onos/net/topology/impl/TopologyManager.java
+++ b/core/net/src/main/java/org/onlab/onos/net/topology/impl/TopologyManager.java
@@ -28,6 +28,7 @@
import org.onlab.onos.net.topology.TopologyProviderService;
import org.onlab.onos.net.topology.TopologyService;
import org.onlab.onos.net.topology.TopologyStore;
+import org.onlab.onos.net.topology.TopologyStoreDelegate;
import org.slf4j.Logger;
import java.util.List;
@@ -56,6 +57,8 @@
private final AbstractListenerRegistry<TopologyEvent, TopologyListener>
listenerRegistry = new AbstractListenerRegistry<>();
+ private TopologyStoreDelegate delegate = new InternalStoreDelegate();
+
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected TopologyStore store;
@@ -65,12 +68,14 @@
@Activate
public void activate() {
+ store.setDelegate(delegate);
eventDispatcher.addSink(TopologyEvent.class, listenerRegistry);
log.info("Started");
}
@Deactivate
public void deactivate() {
+ store.unsetDelegate(delegate);
eventDispatcher.removeSink(TopologyEvent.class);
log.info("Stopped");
}
@@ -188,4 +193,11 @@
}
}
+ // Store delegate to re-post events emitted from the store.
+ private class InternalStoreDelegate implements TopologyStoreDelegate {
+ @Override
+ public void notify(TopologyEvent event) {
+ eventDispatcher.post(event);
+ }
+ }
}
diff --git a/core/net/src/test/java/org/onlab/onos/cluster/impl/MastershipManagerTest.java b/core/net/src/test/java/org/onlab/onos/cluster/impl/MastershipManagerTest.java
new file mode 100644
index 0000000..40902f2
--- /dev/null
+++ b/core/net/src/test/java/org/onlab/onos/cluster/impl/MastershipManagerTest.java
@@ -0,0 +1,136 @@
+package org.onlab.onos.cluster.impl;
+
+import java.util.Set;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.onos.cluster.ClusterEventListener;
+import org.onlab.onos.cluster.ClusterService;
+import org.onlab.onos.cluster.ControllerNode;
+import org.onlab.onos.cluster.ControllerNode.State;
+import org.onlab.onos.cluster.DefaultControllerNode;
+import org.onlab.onos.cluster.MastershipService;
+import org.onlab.onos.cluster.NodeId;
+import org.onlab.onos.event.impl.TestEventDispatcher;
+import org.onlab.onos.net.DeviceId;
+import org.onlab.onos.net.trivial.impl.SimpleMastershipStore;
+import org.onlab.packet.IpPrefix;
+
+import static org.junit.Assert.assertEquals;
+import static org.onlab.onos.net.MastershipRole.*;
+
+/**
+ * Test codifying the mastership service contracts.
+ */
+public class MastershipManagerTest {
+
+ private static final NodeId NID_LOCAL = new NodeId("local");
+ private static final NodeId NID_OTHER = new NodeId("foo");
+ private static final IpPrefix LOCALHOST = IpPrefix.valueOf("127.0.0.1");
+ private static final DeviceId DEV_MASTER = DeviceId.deviceId("of:1");
+ private static final DeviceId DEV_OTHER = DeviceId.deviceId("of:2");
+
+ private MastershipManager mgr;
+ protected MastershipService service;
+
+ @Before
+ public void setUp() {
+ mgr = new MastershipManager();
+ service = mgr;
+ mgr.store = new SimpleMastershipStore();
+ mgr.eventDispatcher = new TestEventDispatcher();
+ mgr.clusterService = new TestClusterService();
+ mgr.activate();
+ }
+
+ @After
+ public void tearDown() {
+ mgr.deactivate();
+ mgr.clusterService = null;
+ mgr.eventDispatcher = null;
+ mgr.store = null;
+ }
+
+ @Test
+ public void setRole() {
+ mgr.setRole(NID_OTHER, DEV_MASTER, MASTER);
+ assertEquals("wrong local role:", STANDBY, mgr.getLocalRole(DEV_MASTER));
+
+ //set to master
+ mgr.setRole(NID_LOCAL, DEV_MASTER, MASTER);
+ assertEquals("wrong local role:", MASTER, mgr.getLocalRole(DEV_MASTER));
+ }
+
+ @Test
+ public void relinquishMastership() {
+ //TODO
+ }
+
+ @Test
+ public void requestRoleFor() {
+ mgr.setRole(NID_LOCAL, DEV_MASTER, MASTER);
+ mgr.setRole(NID_OTHER, DEV_OTHER, MASTER);
+
+ //local should be master for one but standby for other
+ assertEquals("wrong role:", MASTER, mgr.requestRoleFor(DEV_MASTER));
+ assertEquals("wrong role:", STANDBY, mgr.requestRoleFor(DEV_OTHER));
+ }
+
+ @Test
+ public void getMasterFor() {
+ mgr.setRole(NID_LOCAL, DEV_MASTER, MASTER);
+ mgr.setRole(NID_OTHER, DEV_OTHER, MASTER);
+ assertEquals("wrong master:", NID_LOCAL, mgr.getMasterFor(DEV_MASTER));
+ assertEquals("wrong master:", NID_OTHER, mgr.getMasterFor(DEV_OTHER));
+
+ //have NID_OTHER hand over DEV_OTHER to NID_LOCAL
+ mgr.setRole(NID_LOCAL, DEV_OTHER, MASTER);
+ assertEquals("wrong master:", NID_LOCAL, mgr.getMasterFor(DEV_OTHER));
+ }
+
+ @Test
+ public void getDevicesOf() {
+ mgr.setRole(NID_LOCAL, DEV_MASTER, MASTER);
+ mgr.setRole(NID_LOCAL, DEV_OTHER, STANDBY);
+ assertEquals("should be one device:", 1, mgr.getDevicesOf(NID_LOCAL).size());
+
+ //hand both devices to NID_LOCAL
+ mgr.setRole(NID_LOCAL, DEV_OTHER, MASTER);
+ assertEquals("should be two devices:", 2, mgr.getDevicesOf(NID_LOCAL).size());
+ }
+
+ private final class TestClusterService implements ClusterService {
+
+ ControllerNode local = new DefaultControllerNode(NID_LOCAL, LOCALHOST);
+
+ @Override
+ public ControllerNode getLocalNode() {
+ return local;
+ }
+
+ @Override
+ public Set<ControllerNode> getNodes() {
+ return null;
+ }
+
+ @Override
+ public ControllerNode getNode(NodeId nodeId) {
+ return null;
+ }
+
+ @Override
+ public State getState(NodeId nodeId) {
+ return null;
+ }
+
+ @Override
+ public void addListener(ClusterEventListener listener) {
+ }
+
+ @Override
+ public void removeListener(ClusterEventListener listener) {
+ }
+
+ }
+}
diff --git a/core/net/src/test/java/org/onlab/onos/net/device/impl/DistributedDeviceManagerTest.java b/core/net/src/test/java/org/onlab/onos/net/device/impl/DistributedDeviceManagerTest.java
index b7362b9..8923da9 100644
--- a/core/net/src/test/java/org/onlab/onos/net/device/impl/DistributedDeviceManagerTest.java
+++ b/core/net/src/test/java/org/onlab/onos/net/device/impl/DistributedDeviceManagerTest.java
@@ -4,13 +4,15 @@
import com.google.common.collect.Sets;
import com.hazelcast.config.Config;
import com.hazelcast.core.Hazelcast;
-import com.hazelcast.core.HazelcastInstance;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+import org.onlab.onos.cluster.DefaultControllerNode;
import org.onlab.onos.cluster.MastershipServiceAdapter;
import org.onlab.onos.cluster.NodeId;
import org.onlab.onos.event.Event;
+import org.onlab.onos.event.EventDeliveryService;
import org.onlab.onos.event.impl.TestEventDispatcher;
import org.onlab.onos.net.Device;
import org.onlab.onos.net.DeviceId;
@@ -30,23 +32,26 @@
import org.onlab.onos.net.device.PortDescription;
import org.onlab.onos.net.provider.AbstractProvider;
import org.onlab.onos.net.provider.ProviderId;
-import org.onlab.onos.store.common.StoreService;
import org.onlab.onos.store.device.impl.DistributedDeviceStore;
import org.onlab.onos.store.impl.StoreManager;
+import org.onlab.onos.store.impl.TestStoreManager;
+import org.onlab.packet.IpPrefix;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
+import java.util.Map.Entry;
import java.util.Set;
-import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import static org.junit.Assert.*;
import static org.onlab.onos.net.Device.Type.SWITCH;
import static org.onlab.onos.net.DeviceId.deviceId;
import static org.onlab.onos.net.device.DeviceEvent.Type.*;
-// FIXME This test is painfully slow starting up Hazelcast on each test cases,
-// turning it off in repository for now.
+// FIXME This test is slow starting up Hazelcast on each test cases.
// FIXME DistributedDeviceStore should have it's own test cases.
/**
@@ -67,6 +72,11 @@
private static final PortNumber P2 = PortNumber.portNumber(2);
private static final PortNumber P3 = PortNumber.portNumber(3);
+ private static final DefaultControllerNode SELF
+ = new DefaultControllerNode(new NodeId("foobar"),
+ IpPrefix.valueOf("127.0.0.1"));
+
+
private DeviceManager mgr;
protected StoreManager storeManager;
@@ -77,6 +87,8 @@
protected TestProvider provider;
protected TestListener listener = new TestListener();
private DistributedDeviceStore dstore;
+ private TestMastershipManager masterManager;
+ private EventDeliveryService eventService;
@Before
public void setUp() {
@@ -84,26 +96,21 @@
service = mgr;
admin = mgr;
registry = mgr;
- // FIXME should be reading the hazelcast.xml
- Config config = new Config();
- // avoid accidentally joining other cluster
- config.getGroupConfig().setName(UUID.randomUUID().toString());
- // quickly form single node cluster
- config.getNetworkConfig().getJoin()
- .getTcpIpConfig()
- .setEnabled(true).setConnectionTimeoutSeconds(0);
- config.getNetworkConfig().getJoin()
- .getMulticastConfig()
- .setEnabled(false);
+ // TODO should find a way to clean Hazelcast instance without shutdown.
+ Config config = TestStoreManager.getTestConfig();
+
+ masterManager = new TestMastershipManager();
storeManager = new TestStoreManager(Hazelcast.newHazelcastInstance(config));
storeManager.activate();
- dstore = new TestDistributedDeviceStore(storeManager);
+ dstore = new TestDistributedDeviceStore();
dstore.activate();
+
mgr.store = dstore;
- mgr.eventDispatcher = new TestEventDispatcher();
- mgr.mastershipService = new TestMastershipService();
+ eventService = new TestEventDispatcher();
+ mgr.eventDispatcher = eventService;
+ mgr.mastershipService = masterManager;
mgr.activate();
service.addListener(listener);
@@ -153,7 +160,7 @@
public void deviceDisconnected() {
connectDevice(DID1, SW1);
connectDevice(DID2, SW1);
- validateEvents(DEVICE_ADDED, DEVICE_ADDED);
+ validateEvents(DEVICE_ADDED, DEVICE_ADDED, DEVICE_ADDED, DEVICE_ADDED);
assertTrue("device should be available", service.isAvailable(DID1));
// Disconnect
@@ -172,7 +179,7 @@
@Test
public void deviceUpdated() {
connectDevice(DID1, SW1);
- validateEvents(DEVICE_ADDED);
+ validateEvents(DEVICE_ADDED, DEVICE_ADDED);
connectDevice(DID1, SW2);
validateEvents(DEVICE_UPDATED);
@@ -192,7 +199,7 @@
pds.add(new DefaultPortDescription(P2, true));
pds.add(new DefaultPortDescription(P3, true));
providerService.updatePorts(DID1, pds);
- validateEvents(DEVICE_ADDED, PORT_ADDED, PORT_ADDED, PORT_ADDED);
+ validateEvents(DEVICE_ADDED, DEVICE_ADDED, PORT_ADDED, PORT_ADDED, PORT_ADDED);
pds.clear();
pds.add(new DefaultPortDescription(P1, false));
@@ -208,7 +215,7 @@
pds.add(new DefaultPortDescription(P1, true));
pds.add(new DefaultPortDescription(P2, true));
providerService.updatePorts(DID1, pds);
- validateEvents(DEVICE_ADDED, PORT_ADDED, PORT_ADDED);
+ validateEvents(DEVICE_ADDED, DEVICE_ADDED, PORT_ADDED, PORT_ADDED);
providerService.portStatusChanged(DID1, new DefaultPortDescription(P1, false));
validateEvents(PORT_UPDATED);
@@ -223,7 +230,7 @@
pds.add(new DefaultPortDescription(P1, true));
pds.add(new DefaultPortDescription(P2, true));
providerService.updatePorts(DID1, pds);
- validateEvents(DEVICE_ADDED, PORT_ADDED, PORT_ADDED);
+ validateEvents(DEVICE_ADDED, DEVICE_ADDED, PORT_ADDED, PORT_ADDED);
assertEquals("wrong port count", 2, service.getPorts(DID1).size());
Port port = service.getPort(DID1, P1);
@@ -237,10 +244,10 @@
connectDevice(DID2, SW2);
assertEquals("incorrect device count", 2, service.getDeviceCount());
admin.removeDevice(DID1);
+ validateEvents(DEVICE_ADDED, DEVICE_ADDED, DEVICE_ADDED, DEVICE_ADDED, DEVICE_REMOVED, DEVICE_REMOVED);
assertNull("device should not be found", service.getDevice(DID1));
assertNotNull("device should be found", service.getDevice(DID2));
assertEquals("incorrect device count", 1, service.getDeviceCount());
-
}
protected void validateEvents(Enum... types) {
@@ -283,23 +290,21 @@
}
private class TestDistributedDeviceStore extends DistributedDeviceStore {
- public TestDistributedDeviceStore(StoreService storeService) {
- this.storeService = storeService;
+
+ public TestDistributedDeviceStore() {
+ this.storeService = storeManager;
}
}
- private class TestStoreManager extends StoreManager {
- TestStoreManager(HazelcastInstance instance) {
- this.instance = instance;
- }
+ private static class TestMastershipManager extends MastershipServiceAdapter {
- @Override
- public void activate() {
- setupKryoPool();
- }
- }
+ private ConcurrentMap<DeviceId, NodeId> masters = new ConcurrentHashMap<>();
- private static class TestMastershipService extends MastershipServiceAdapter {
+ public TestMastershipManager() {
+ // SELF master of all initially
+ masters.put(DID1, SELF.id());
+ masters.put(DID1, SELF.id());
+ }
@Override
public MastershipRole getLocalRole(DeviceId deviceId) {
return MastershipRole.MASTER;
@@ -307,13 +312,27 @@
@Override
public Set<DeviceId> getDevicesOf(NodeId nodeId) {
- return Sets.newHashSet(DID1, DID2);
+ HashSet<DeviceId> set = Sets.newHashSet();
+ for (Entry<DeviceId, NodeId> e : masters.entrySet()) {
+ if (e.getValue().equals(nodeId)) {
+ set.add(e.getKey());
+ }
+ }
+ return set;
}
@Override
public MastershipRole requestRoleFor(DeviceId deviceId) {
- return MastershipRole.MASTER;
+ if (SELF.id().equals(masters.get(deviceId))) {
+ return MastershipRole.MASTER;
+ } else {
+ return MastershipRole.STANDBY;
+ }
+ }
+
+ @Override
+ public void relinquishMastership(DeviceId deviceId) {
+ masters.remove(deviceId, SELF.id());
}
}
-
}
diff --git a/core/store/src/main/java/org/onlab/onos/store/cluster/impl/DistributedMastershipStore.java b/core/store/src/main/java/org/onlab/onos/store/cluster/impl/DistributedMastershipStore.java
index 2a7f67a..d3fcf3e 100644
--- a/core/store/src/main/java/org/onlab/onos/store/cluster/impl/DistributedMastershipStore.java
+++ b/core/store/src/main/java/org/onlab/onos/store/cluster/impl/DistributedMastershipStore.java
@@ -4,6 +4,7 @@
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableSet;
import com.hazelcast.core.IMap;
+
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
@@ -42,6 +43,7 @@
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected ClusterService clusterService;
+ @Override
@Activate
public void activate() {
super.activate();
@@ -52,19 +54,28 @@
masters = new AbsentInvalidatingLoadingCache<>(newBuilder().build(nodeLoader));
rawMasters.addEntryListener(new RemoteEventHandler<>(masters), true);
+ loadMasters();
+
log.info("Started");
}
+ private void loadMasters() {
+ for (byte[] keyBytes : rawMasters.keySet()) {
+ final DeviceId id = deserialize(keyBytes);
+ masters.refresh(id);
+ }
+ }
+
@Deactivate
public void deactivate() {
log.info("Stopped");
}
@Override
- public MastershipEvent setRole(NodeId nodeId, DeviceId deviceId, MastershipRole role) {
+ public MastershipEvent setMaster(NodeId nodeId, DeviceId deviceId) {
synchronized (this) {
NodeId currentMaster = getMaster(deviceId);
- if (role == MastershipRole.MASTER && Objects.equals(currentMaster, nodeId)) {
+ if (Objects.equals(currentMaster, nodeId)) {
return null;
}
@@ -94,7 +105,7 @@
@Override
public MastershipRole requestRole(DeviceId deviceId) {
// FIXME: for now we are 'selecting' as master whoever asks
- setRole(clusterService.getLocalNode().id(), deviceId, MastershipRole.MASTER);
+ setMaster(clusterService.getLocalNode().id(), deviceId);
return MastershipRole.MASTER;
}
diff --git a/core/store/src/main/java/org/onlab/onos/store/device/impl/DistributedDeviceStore.java b/core/store/src/main/java/org/onlab/onos/store/device/impl/DistributedDeviceStore.java
index 52e8ed0..64ae3c8 100644
--- a/core/store/src/main/java/org/onlab/onos/store/device/impl/DistributedDeviceStore.java
+++ b/core/store/src/main/java/org/onlab/onos/store/device/impl/DistributedDeviceStore.java
@@ -15,7 +15,6 @@
import org.onlab.onos.net.DefaultPort;
import org.onlab.onos.net.Device;
import org.onlab.onos.net.DeviceId;
-import org.onlab.onos.net.MastershipRole;
import org.onlab.onos.net.Port;
import org.onlab.onos.net.PortNumber;
import org.onlab.onos.net.device.DeviceDescription;
@@ -61,10 +60,6 @@
private IMap<byte[], byte[]> rawDevices;
private LoadingCache<DeviceId, Optional<DefaultDevice>> devices;
- // private IMap<DeviceId, MastershipRole> roles;
- private IMap<byte[], byte[]> rawRoles;
- private LoadingCache<DeviceId, Optional<MastershipRole>> roles;
-
// private ISet<DeviceId> availableDevices;
private ISet<byte[]> availableDevices;
@@ -73,6 +68,7 @@
private IMap<byte[], byte[]> rawDevicePorts;
private LoadingCache<DeviceId, Optional<Map<PortNumber, Port>>> devicePorts;
+ @Override
@Activate
public void activate() {
super.activate();
@@ -86,14 +82,7 @@
= new OptionalCacheLoader<>(storeService, rawDevices);
devices = new AbsentInvalidatingLoadingCache<>(newBuilder().build(deviceLoader));
// refresh/populate cache based on notification from other instance
- rawDevices.addEntryListener(new RemoteEventHandler<>(devices), includeValue);
-
- rawRoles = theInstance.getMap("roles");
- final OptionalCacheLoader<DeviceId, MastershipRole> rolesLoader
- = new OptionalCacheLoader<>(storeService, rawRoles);
- roles = new AbsentInvalidatingLoadingCache<>(newBuilder().build(rolesLoader));
- // refresh/populate cache based on notification from other instance
- rawRoles.addEntryListener(new RemoteEventHandler<>(roles), includeValue);
+ rawDevices.addEntryListener(new RemoteDeviceEventHandler(devices), includeValue);
// TODO cache availableDevices
availableDevices = theInstance.getSet("availableDevices");
@@ -103,7 +92,9 @@
= new OptionalCacheLoader<>(storeService, rawDevicePorts);
devicePorts = new AbsentInvalidatingLoadingCache<>(newBuilder().build(devicePortLoader));
// refresh/populate cache based on notification from other instance
- rawDevicePorts.addEntryListener(new RemoteEventHandler<>(devicePorts), includeValue);
+ rawDevicePorts.addEntryListener(new RemotePortEventHandler(devicePorts), includeValue);
+
+ loadDeviceCache();
log.info("Started");
}
@@ -115,22 +106,11 @@
@Override
public int getDeviceCount() {
- // TODO IMap size or cache size?
- return rawDevices.size();
+ return devices.asMap().size();
}
@Override
public Iterable<Device> getDevices() {
-// TODO Revisit if we ever need to do this.
-// log.info("{}:{}", rawMap.size(), cache.size());
-// if (rawMap.size() != cache.size()) {
-// for (Entry<byte[], byte[]> e : rawMap.entrySet()) {
-// final DeviceId key = deserialize(e.getKey());
-// final DefaultDevice val = deserialize(e.getValue());
-// cache.put(key, val);
-// }
-// }
-
// TODO builder v.s. copyOf. Guava semms to be using copyOf?
Builder<Device> builder = ImmutableSet.builder();
for (Optional<DefaultDevice> e : devices.asMap().values()) {
@@ -141,6 +121,17 @@
return builder.build();
}
+ private void loadDeviceCache() {
+ log.info("{}:{}", rawDevices.size(), devices.size());
+ if (rawDevices.size() != devices.size()) {
+ for (Map.Entry<byte[], byte[]> e : rawDevices.entrySet()) {
+ final DeviceId key = deserialize(e.getKey());
+ final DefaultDevice val = deserialize(e.getValue());
+ devices.put(key, Optional.of(val));
+ }
+ }
+ }
+
@Override
public Device getDevice(DeviceId deviceId) {
// TODO revisit if ignoring exception is safe.
@@ -171,12 +162,8 @@
devices.put(deviceId, Optional.of(device));
availableDevices.add(deviceIdBytes);
-
- // For now claim the device as a master automatically.
- //rawRoles.put(deviceIdBytes, serialize(MastershipRole.MASTER));
- //roles.put(deviceId, Optional.of(MastershipRole.MASTER));
}
- return new DeviceEvent(DeviceEvent.Type.DEVICE_ADDED, device, null);
+ return new DeviceEvent(DEVICE_ADDED, device, null);
}
// Updates the device and returns the appropriate event if necessary.
@@ -348,8 +335,6 @@
public DeviceEvent removeDevice(DeviceId deviceId) {
synchronized (this) {
byte[] deviceIdBytes = serialize(deviceId);
- rawRoles.remove(deviceIdBytes);
- roles.invalidate(deviceId);
// TODO conditional remove?
Device device = deserialize(rawDevices.remove(deviceIdBytes));
@@ -359,6 +344,48 @@
}
}
- // TODO cache serialized DeviceID if we suffer from serialization cost
+ private class RemoteDeviceEventHandler extends RemoteEventHandler<DeviceId, DefaultDevice> {
+ public RemoteDeviceEventHandler(LoadingCache<DeviceId, Optional<DefaultDevice>> cache) {
+ super(cache);
+ }
+ @Override
+ protected void onAdd(DeviceId deviceId, DefaultDevice device) {
+ delegate.notify(new DeviceEvent(DEVICE_ADDED, device));
+ }
+
+ @Override
+ protected void onRemove(DeviceId deviceId, DefaultDevice device) {
+ delegate.notify(new DeviceEvent(DEVICE_REMOVED, device));
+ }
+
+ @Override
+ protected void onUpdate(DeviceId deviceId, DefaultDevice device) {
+ delegate.notify(new DeviceEvent(DEVICE_UPDATED, device));
+ }
+ }
+
+ private class RemotePortEventHandler extends RemoteEventHandler<DeviceId, Map<PortNumber, Port>> {
+ public RemotePortEventHandler(LoadingCache<DeviceId, Optional<Map<PortNumber, Port>>> cache) {
+ super(cache);
+ }
+
+ @Override
+ protected void onAdd(DeviceId deviceId, Map<PortNumber, Port> ports) {
+// delegate.notify(new DeviceEvent(PORT_ADDED, getDevice(deviceId)));
+ }
+
+ @Override
+ protected void onRemove(DeviceId deviceId, Map<PortNumber, Port> ports) {
+// delegate.notify(new DeviceEvent(PORT_REMOVED, getDevice(deviceId)));
+ }
+
+ @Override
+ protected void onUpdate(DeviceId deviceId, Map<PortNumber, Port> ports) {
+// delegate.notify(new DeviceEvent(PORT_UPDATED, getDevice(deviceId)));
+ }
+ }
+
+
+ // TODO cache serialized DeviceID if we suffer from serialization cost
}
diff --git a/core/store/src/main/java/org/onlab/onos/store/impl/AbstractDistributedStore.java b/core/store/src/main/java/org/onlab/onos/store/impl/AbstractDistributedStore.java
index bca585d..e7c2d58 100644
--- a/core/store/src/main/java/org/onlab/onos/store/impl/AbstractDistributedStore.java
+++ b/core/store/src/main/java/org/onlab/onos/store/impl/AbstractDistributedStore.java
@@ -24,7 +24,7 @@
*/
@Component(componentAbstract = true)
public abstract class AbstractDistributedStore<E extends Event, D extends StoreDelegate<E>>
- extends AbstractStore<E, D> {
+ extends AbstractStore<E, D> {
protected final Logger log = getLogger(getClass());
@@ -66,7 +66,7 @@
* @param <K> IMap key type after deserialization
* @param <V> IMap value type after deserialization
*/
- public final class RemoteEventHandler<K, V> extends EntryAdapter<byte[], byte[]> {
+ public class RemoteEventHandler<K, V> extends EntryAdapter<byte[], byte[]> {
private LoadingCache<K, Optional<V>> cache;
@@ -85,19 +85,58 @@
}
@Override
+ public void entryAdded(EntryEvent<byte[], byte[]> event) {
+ K key = deserialize(event.getKey());
+ V newVal = deserialize(event.getValue());
+ Optional<V> newValue = Optional.of(newVal);
+ cache.asMap().putIfAbsent(key, newValue);
+ onAdd(key, newVal);
+ }
+
+ @Override
public void entryUpdated(EntryEvent<byte[], byte[]> event) {
- cache.put(storeService.<K>deserialize(event.getKey()),
- Optional.of(storeService.<V>deserialize(event.getValue())));
+ K key = deserialize(event.getKey());
+ V oldVal = deserialize(event.getOldValue());
+ Optional<V> oldValue = Optional.fromNullable(oldVal);
+ V newVal = deserialize(event.getValue());
+ Optional<V> newValue = Optional.of(newVal);
+ cache.asMap().replace(key, oldValue, newValue);
+ onUpdate(key, newVal);
}
@Override
public void entryRemoved(EntryEvent<byte[], byte[]> event) {
- cache.invalidate(storeService.<K>deserialize(event.getKey()));
+ K key = deserialize(event.getKey());
+ V val = deserialize(event.getValue());
+ cache.invalidate(key);
+ onRemove(key, val);
}
- @Override
- public void entryAdded(EntryEvent<byte[], byte[]> event) {
- entryUpdated(event);
+ /**
+ * Cache entry addition hook.
+ *
+ * @param key new key
+ * @param newVal new value
+ */
+ protected void onAdd(K key, V newVal) {
+ }
+
+ /**
+ * Cache entry update hook.
+ *
+ * @param key new key
+ * @param newVal new value
+ */
+ protected void onUpdate(K key, V newVal) {
+ }
+
+ /**
+ * Cache entry remove hook.
+ *
+ * @param key new key
+ * @param val old value
+ */
+ protected void onRemove(K key, V val) {
}
}
diff --git a/core/store/src/main/java/org/onlab/onos/store/impl/StoreManager.java b/core/store/src/main/java/org/onlab/onos/store/impl/StoreManager.java
index 77463fd..abd8ade 100644
--- a/core/store/src/main/java/org/onlab/onos/store/impl/StoreManager.java
+++ b/core/store/src/main/java/org/onlab/onos/store/impl/StoreManager.java
@@ -45,7 +45,7 @@
@Service
public class StoreManager implements StoreService {
- private static final String HAZELCAST_XML_FILE = "etc/hazelcast.xml";
+ protected static final String HAZELCAST_XML_FILE = "etc/hazelcast.xml";
private final Logger log = LoggerFactory.getLogger(getClass());
diff --git a/core/store/src/test/java/org/onlab/onos/store/impl/TestStoreManager.java b/core/store/src/test/java/org/onlab/onos/store/impl/TestStoreManager.java
new file mode 100644
index 0000000..c9d8821
--- /dev/null
+++ b/core/store/src/test/java/org/onlab/onos/store/impl/TestStoreManager.java
@@ -0,0 +1,54 @@
+package org.onlab.onos.store.impl;
+
+import java.io.FileNotFoundException;
+import java.util.UUID;
+
+import com.hazelcast.config.Config;
+import com.hazelcast.config.FileSystemXmlConfig;
+import com.hazelcast.core.HazelcastInstance;
+
+/**
+ * Dummy StoreManager to use specified Hazelcast instance.
+ */
+public class TestStoreManager extends StoreManager {
+
+ /**
+ * Gets the Hazelcast Config for testing.
+ *
+ * @return
+ */
+ public static Config getTestConfig() {
+ Config config;
+ try {
+ config = new FileSystemXmlConfig(HAZELCAST_XML_FILE);
+ } catch (FileNotFoundException e) {
+ // falling back to default
+ config = new Config();
+ }
+ // avoid accidentally joining other cluster
+ config.getGroupConfig().setName(UUID.randomUUID().toString());
+ // quickly form single node cluster
+ config.getNetworkConfig().getJoin()
+ .getTcpIpConfig()
+ .setEnabled(true).setConnectionTimeoutSeconds(0);
+ config.getNetworkConfig().getJoin()
+ .getMulticastConfig()
+ .setEnabled(false);
+ return config;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param instance Hazelast instance to return on #getHazelcastInstance()
+ */
+ public TestStoreManager(HazelcastInstance instance) {
+ this.instance = instance;
+ }
+
+ // Hazelcast setup removed from original code.
+ @Override
+ public void activate() {
+ setupKryoPool();
+ }
+}
diff --git a/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleDeviceStore.java b/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleDeviceStore.java
index 78d6a4c..9b78798 100644
--- a/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleDeviceStore.java
+++ b/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleDeviceStore.java
@@ -15,8 +15,10 @@
import org.onlab.onos.net.device.DeviceDescription;
import org.onlab.onos.net.device.DeviceEvent;
import org.onlab.onos.net.device.DeviceStore;
+import org.onlab.onos.net.device.DeviceStoreDelegate;
import org.onlab.onos.net.device.PortDescription;
import org.onlab.onos.net.provider.ProviderId;
+import org.onlab.onos.store.AbstractStore;
import org.slf4j.Logger;
import java.util.ArrayList;
@@ -40,7 +42,9 @@
*/
@Component(immediate = true)
@Service
-public class SimpleDeviceStore implements DeviceStore {
+public class SimpleDeviceStore
+ extends AbstractStore<DeviceEvent, DeviceStoreDelegate>
+ implements DeviceStore {
private final Logger log = getLogger(getClass());
diff --git a/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleFlowRuleStore.java b/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleFlowRuleStore.java
index 816ea63..38e94aa 100644
--- a/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleFlowRuleStore.java
+++ b/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleFlowRuleStore.java
@@ -19,6 +19,8 @@
import org.onlab.onos.net.flow.FlowRuleEvent;
import org.onlab.onos.net.flow.FlowRuleEvent.Type;
import org.onlab.onos.net.flow.FlowRuleStore;
+import org.onlab.onos.net.flow.FlowRuleStoreDelegate;
+import org.onlab.onos.store.AbstractStore;
import org.slf4j.Logger;
import com.google.common.collect.ArrayListMultimap;
@@ -30,7 +32,9 @@
*/
@Component(immediate = true)
@Service
-public class SimpleFlowRuleStore implements FlowRuleStore {
+public class SimpleFlowRuleStore
+ extends AbstractStore<FlowRuleEvent, FlowRuleStoreDelegate>
+ implements FlowRuleStore {
private final Logger log = getLogger(getClass());
diff --git a/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleHostStore.java b/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleHostStore.java
index bcd84df..be609a8 100644
--- a/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleHostStore.java
+++ b/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleHostStore.java
@@ -24,8 +24,10 @@
import org.onlab.onos.net.host.HostDescription;
import org.onlab.onos.net.host.HostEvent;
import org.onlab.onos.net.host.HostStore;
+import org.onlab.onos.net.host.HostStoreDelegate;
import org.onlab.onos.net.host.PortAddresses;
import org.onlab.onos.net.provider.ProviderId;
+import org.onlab.onos.store.AbstractStore;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
@@ -41,7 +43,9 @@
*/
@Component(immediate = true)
@Service
-public class SimpleHostStore implements HostStore {
+public class SimpleHostStore
+ extends AbstractStore<HostEvent, HostStoreDelegate>
+ implements HostStore {
private final Logger log = getLogger(getClass());
diff --git a/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleLinkStore.java b/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleLinkStore.java
index 5c99682..ccb2bfb 100644
--- a/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleLinkStore.java
+++ b/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleLinkStore.java
@@ -14,7 +14,9 @@
import org.onlab.onos.net.link.LinkDescription;
import org.onlab.onos.net.link.LinkEvent;
import org.onlab.onos.net.link.LinkStore;
+import org.onlab.onos.net.link.LinkStoreDelegate;
import org.onlab.onos.net.provider.ProviderId;
+import org.onlab.onos.store.AbstractStore;
import org.slf4j.Logger;
import java.util.Collections;
@@ -35,7 +37,9 @@
*/
@Component(immediate = true)
@Service
-public class SimpleLinkStore implements LinkStore {
+public class SimpleLinkStore
+ extends AbstractStore<LinkEvent, LinkStoreDelegate>
+ implements LinkStore {
private final Logger log = getLogger(getClass());
diff --git a/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleMastershipStore.java b/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleMastershipStore.java
index 24480c6..da691fe 100644
--- a/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleMastershipStore.java
+++ b/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleMastershipStore.java
@@ -3,6 +3,8 @@
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 java.util.concurrent.ConcurrentMap;
@@ -15,9 +17,11 @@
import org.onlab.onos.cluster.DefaultControllerNode;
import org.onlab.onos.cluster.MastershipEvent;
import org.onlab.onos.cluster.MastershipStore;
+import org.onlab.onos.cluster.MastershipStoreDelegate;
import org.onlab.onos.cluster.NodeId;
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.MastershipRole;
+import org.onlab.onos.store.AbstractStore;
import org.onlab.packet.IpPrefix;
import org.slf4j.Logger;
@@ -25,24 +29,27 @@
/**
* Manages inventory of controller mastership over devices using
- * trivial in-memory structures implementation.
+ * trivial, non-distributed in-memory structures implementation.
*/
@Component(immediate = true)
@Service
-public class SimpleMastershipStore implements MastershipStore {
-
- public static final IpPrefix LOCALHOST = IpPrefix.valueOf("127.0.0.1");
+public class SimpleMastershipStore
+ extends AbstractStore<MastershipEvent, MastershipStoreDelegate>
+ implements MastershipStore {
private final Logger log = getLogger(getClass());
- private ControllerNode instance;
+ public static final IpPrefix LOCALHOST = IpPrefix.valueOf("127.0.0.1");
- protected final ConcurrentMap<DeviceId, MastershipRole> roleMap =
+ private ControllerNode instance =
+ new DefaultControllerNode(new NodeId("local"), LOCALHOST);
+
+ //devices mapped to their masters, to emulate multiple nodes
+ protected final ConcurrentMap<DeviceId, NodeId> masterMap =
new ConcurrentHashMap<>();
@Activate
public void activate() {
- instance = new DefaultControllerNode(new NodeId("local"), LOCALHOST);
log.info("Started");
}
@@ -52,23 +59,36 @@
}
@Override
- public MastershipEvent setRole(NodeId nodeId, DeviceId deviceId,
- MastershipRole role) {
- if (roleMap.get(deviceId) == null) {
- return null;
+ public MastershipEvent setMaster(NodeId nodeId, DeviceId deviceId) {
+
+ NodeId node = masterMap.get(deviceId);
+ if (node == null) {
+ masterMap.put(deviceId, nodeId);
+ return new MastershipEvent(MASTER_CHANGED, deviceId, nodeId);
}
- roleMap.put(deviceId, role);
- return new MastershipEvent(MASTER_CHANGED, deviceId, nodeId);
+
+ if (node.equals(nodeId)) {
+ return null;
+ } else {
+ masterMap.put(deviceId, nodeId);
+ return new MastershipEvent(MASTER_CHANGED, deviceId, nodeId);
+ }
}
@Override
public NodeId getMaster(DeviceId deviceId) {
- return instance.id();
+ return masterMap.get(deviceId);
}
@Override
public Set<DeviceId> getDevices(NodeId nodeId) {
- return Collections.unmodifiableSet(roleMap.keySet());
+ Set<DeviceId> ids = new HashSet<>();
+ for (Map.Entry<DeviceId, NodeId> d : masterMap.entrySet()) {
+ if (d.getValue().equals(nodeId)) {
+ ids.add(d.getKey());
+ }
+ }
+ return Collections.unmodifiableSet(ids);
}
@Override
@@ -78,11 +98,18 @@
@Override
public MastershipRole getRole(NodeId nodeId, DeviceId deviceId) {
- MastershipRole role = roleMap.get(deviceId);
- if (role == null) {
- //say MASTER. If clustered, we'd figure out if anyone's got dibs here.
+ NodeId node = masterMap.get(deviceId);
+ MastershipRole role;
+ if (node != null) {
+ if (node.equals(nodeId)) {
+ role = MastershipRole.MASTER;
+ } else {
+ role = MastershipRole.STANDBY;
+ }
+ } else {
+ //masterMap doesn't contain it.
role = MastershipRole.MASTER;
- roleMap.put(deviceId, role);
+ masterMap.put(deviceId, nodeId);
}
return role;
}
diff --git a/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleTopologyStore.java b/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleTopologyStore.java
index 5d9c8de..32cc1f7 100644
--- a/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleTopologyStore.java
+++ b/core/trivial/src/main/java/org/onlab/onos/net/trivial/impl/SimpleTopologyStore.java
@@ -18,6 +18,8 @@
import org.onlab.onos.net.topology.TopologyEvent;
import org.onlab.onos.net.topology.TopologyGraph;
import org.onlab.onos.net.topology.TopologyStore;
+import org.onlab.onos.net.topology.TopologyStoreDelegate;
+import org.onlab.onos.store.AbstractStore;
import org.slf4j.Logger;
import java.util.List;
@@ -31,7 +33,9 @@
*/
@Component(immediate = true)
@Service
-public class SimpleTopologyStore implements TopologyStore {
+public class SimpleTopologyStore
+ extends AbstractStore<TopologyEvent, TopologyStoreDelegate>
+ implements TopologyStore {
private final Logger log = getLogger(getClass());
diff --git a/openflow/api/pom.xml b/openflow/api/pom.xml
index f849e39..2c58e47 100644
--- a/openflow/api/pom.xml
+++ b/openflow/api/pom.xml
@@ -16,6 +16,18 @@
<description>ONOS OpenFlow controller subsystem API</description>
+ <repositories>
+ <!-- FIXME: for Loxigen. Decide how to use Loxigen before release. -->
+ <repository>
+ <id>sonatype-oss-snapshot</id>
+ <name>Sonatype OSS snapshot repository</name>
+ <url>https://oss.sonatype.org/content/repositories/snapshots</url>
+ <releases>
+ <enabled>false</enabled>
+ </releases>
+ </repository>
+ </repositories>
+
<dependencies>
<dependency>
<groupId>org.projectfloodlight</groupId>
diff --git a/pom.xml b/pom.xml
index dcd2a6b..1cc5d3b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -391,13 +391,13 @@
<group>
<title>Network Model & Services</title>
<packages>
- org.onlab.onos:org.onlab.onos.*:
+ org.onlab.onos:org.onlab.onos.*
</packages>
</group>
<group>
<title>Core Subsystems</title>
<packages>
- org.onlab.onos.cluster.impl:org.onlab.onos.store: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.net.trivial.*:org.onlab.onos.net.*.impl:org.onlab.onos.cluster:org.onlab.onos.event.impl:org.onlab.onos.store.*
+ 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.net.trivial.*:org.onlab.onos.net.*.impl:org.onlab.onos.event.impl:org.onlab.onos.store.*
</packages>
</group>
<group>
@@ -422,7 +422,7 @@
<group>
<title>Sample Applications</title>
<packages>
- org.onlab.onos.tvue:org.onlab.onos.fwd
+ org.onlab.onos.tvue:org.onlab.onos.fwd:org.onlab.onos.foo
</packages>
</group>
</groups>
diff --git a/tools/build/onos-package b/tools/build/onos-package
index 8f49516..cf751c7 100755
--- a/tools/build/onos-package
+++ b/tools/build/onos-package
@@ -51,7 +51,7 @@
$ONOS_STAGE/$KARAF_DIST/etc/org.apache.karaf.features.cfg
# Patch the Apache Karaf distribution file to load ONOS features
-perl -pi.old -e 's|^(featuresBoot=.*)|\1,onos-api,onos-core,onos-cli,onos-rest,onos-gui,onos-openflow,onos-app-fwd,onos-app-foo|' \
+perl -pi.old -e 's|^(featuresBoot=.*)|\1,webconsole,onos-api,onos-core,onos-cli,onos-rest,onos-gui,onos-openflow,onos-app-fwd,onos-app-foo|' \
$ONOS_STAGE/$KARAF_DIST/etc/org.apache.karaf.features.cfg
# Patch the Apache Karaf distribution with ONOS branding bundle
diff --git a/tools/test/bin/onos-config b/tools/test/bin/onos-config
index e9f3f0a..9f1e3b0 100755
--- a/tools/test/bin/onos-config
+++ b/tools/test/bin/onos-config
@@ -8,4 +8,7 @@
remote=$ONOS_USER@${1:-$OCI}
-echo "Deprecated!"
\ No newline at end of file
+ssh $remote "
+ sudo perl -pi.bak -e \"s/ <interface>.*</ <interface>${ONOS_NIC:-192.168.56.*}</g\" \
+ $ONOS_INSTALL_DIR/$KARAF_DIST/etc/hazelcast.xml
+"
\ No newline at end of file
diff --git a/tools/test/bin/onos-install b/tools/test/bin/onos-install
index 39fbeaa9..d594105 100755
--- a/tools/test/bin/onos-install
+++ b/tools/test/bin/onos-install
@@ -9,7 +9,8 @@
# If the first option is -f attempt uninstall first.
[ "$1" = "-f" ] && shift && onos-uninstall ${1:-$OCI}
-remote=$ONOS_USER@${1:-$OCI}
+node=${1:-$OCI}
+remote=$ONOS_USER@$node
scp -q $ONOS_TAR $remote:/tmp
@@ -30,7 +31,10 @@
# Remove any previous ON.Lab bits from ~/.m2 repo
rm -fr ~/.m2/repository/org/onlab
-
- # Ignite the ONOS service.
- sudo service onos start
"
+
+# Configure the ONOS installation
+onos-config $node
+
+# Ignite the ONOS service.
+onos-service $node start
diff --git a/tools/test/cells/.reset b/tools/test/cells/.reset
new file mode 100644
index 0000000..c025225
--- /dev/null
+++ b/tools/test/cells/.reset
@@ -0,0 +1 @@
+unset OC1 OC2 OC3 OC4 OC5 OC6 OC7 OC8 OC9 OCN ONOS_NIC
diff --git a/tools/test/cells/local b/tools/test/cells/local
index 3d71a1e..b04a5e3 100644
--- a/tools/test/cells/local
+++ b/tools/test/cells/local
@@ -1,4 +1,5 @@
# Default virtual box ONOS instances 1,2 & ONOS mininet box
+. $ONOS_ROOT/tools/test/cells/.reset
export OC1="192.168.56.101"
export OC2="192.168.56.102"
diff --git a/tools/test/cells/prox b/tools/test/cells/prox
new file mode 100644
index 0000000..3fa1279
--- /dev/null
+++ b/tools/test/cells/prox
@@ -0,0 +1,9 @@
+# ProxMox-based cell of ONOS instances 1,2 & ONOS mininet box
+. $ONOS_ROOT/tools/test/cells/.reset
+
+export ONOS_NIC="10.1.9.*"
+
+export OC1="10.1.9.94"
+export OC2="10.1.9.82"
+
+export OCN="10.1.9.93"