ONOS-2184 - Initial implementation of Virtual network Intent service.
Change-Id: I03103b4eca797cd32480fbd0e3b4cf0385b50ef2
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkIntent.java b/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkIntent.java
new file mode 100644
index 0000000..acdbe44
--- /dev/null
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkIntent.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.incubator.net.virtual;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.MoreObjects;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.intent.ConnectivityIntent;
+import org.onosproject.net.intent.Constraint;
+import org.onosproject.net.intent.Key;
+
+import java.util.Collections;
+import java.util.List;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Abstraction of VirtualNetworkIntent connectivity.
+ */
+@Beta
+public final class VirtualNetworkIntent extends ConnectivityIntent {
+
+ private final NetworkId networkId;
+ private final ConnectPoint ingressPoint;
+ private final ConnectPoint egressPoint;
+
+ private static final String NETWORK_ID_NULL = "Network ID cannot be null";
+
+ /**
+ * Returns a new point to point intent builder. The application id,
+ * ingress point and egress point are required fields. If they are
+ * not set by calls to the appropriate methods, an exception will
+ * be thrown.
+ *
+ * @return point to point builder
+ */
+ public static VirtualNetworkIntent.Builder builder() {
+ return new VirtualNetworkIntent.Builder();
+ }
+
+ /**
+ * Builder of a point to point intent.
+ */
+ public static final class Builder extends ConnectivityIntent.Builder {
+ NetworkId networkId;
+ ConnectPoint ingressPoint;
+ ConnectPoint egressPoint;
+
+ /**
+ * Builder constructor.
+ */
+ private Builder() {
+ // Hide constructor
+ }
+
+ @Override
+ public VirtualNetworkIntent.Builder appId(ApplicationId appId) {
+ return (VirtualNetworkIntent.Builder) super.appId(appId);
+ }
+
+ @Override
+ public VirtualNetworkIntent.Builder key(Key key) {
+ return (VirtualNetworkIntent.Builder) super.key(key);
+ }
+
+ @Override
+ public VirtualNetworkIntent.Builder selector(TrafficSelector selector) {
+ return (VirtualNetworkIntent.Builder) super.selector(selector);
+ }
+
+ @Override
+ public VirtualNetworkIntent.Builder treatment(TrafficTreatment treatment) {
+ return (VirtualNetworkIntent.Builder) super.treatment(treatment);
+ }
+
+ @Override
+ public VirtualNetworkIntent.Builder constraints(List<Constraint> constraints) {
+ return (VirtualNetworkIntent.Builder) super.constraints(constraints);
+ }
+
+ @Override
+ public VirtualNetworkIntent.Builder priority(int priority) {
+ return (VirtualNetworkIntent.Builder) super.priority(priority);
+ }
+
+ /**
+ * Sets the virtual network of the virtual network intent.
+ *
+ * @param networkId virtual network identifier
+ * @return this builder
+ */
+ public VirtualNetworkIntent.Builder networkId(NetworkId networkId) {
+ this.networkId = networkId;
+ return this;
+ }
+
+ /**
+ * Sets the ingress point of the virtual network intent that will be built.
+ *
+ * @param ingressPoint ingress connect point
+ * @return this builder
+ */
+ public VirtualNetworkIntent.Builder ingressPoint(ConnectPoint ingressPoint) {
+ this.ingressPoint = ingressPoint;
+ return this;
+ }
+
+ /**
+ * Sets the egress point of the virtual network intent that will be built.
+ *
+ * @param egressPoint egress connect point
+ * @return this builder
+ */
+ public VirtualNetworkIntent.Builder egressPoint(ConnectPoint egressPoint) {
+ this.egressPoint = egressPoint;
+ return this;
+ }
+
+ /**
+ * Builds a virtual network intent from the accumulated parameters.
+ *
+ * @return virtual network intent
+ */
+ public VirtualNetworkIntent build() {
+
+ return new VirtualNetworkIntent(
+ networkId,
+ appId,
+ key,
+ selector,
+ treatment,
+ ingressPoint,
+ egressPoint,
+ constraints,
+ priority
+ );
+ }
+ }
+
+
+ /**
+ * Creates a new point-to-point intent with the supplied ingress/egress
+ * ports and constraints.
+ *
+ * @param networkId virtual network identifier
+ * @param appId application identifier
+ * @param key key of the intent
+ * @param selector traffic selector
+ * @param treatment treatment
+ * @param ingressPoint ingress port
+ * @param egressPoint egress port
+ * @param constraints optional list of constraints
+ * @param priority priority to use for flows generated by this intent
+ * @throws NullPointerException if {@code ingressPoint} or
+ * {@code egressPoints} or {@code appId} is null.
+ */
+ private VirtualNetworkIntent(NetworkId networkId,
+ ApplicationId appId,
+ Key key,
+ TrafficSelector selector,
+ TrafficTreatment treatment,
+ ConnectPoint ingressPoint,
+ ConnectPoint egressPoint,
+ List<Constraint> constraints,
+ int priority) {
+ super(appId, key, Collections.emptyList(), selector, treatment, constraints,
+ priority);
+
+ checkNotNull(networkId, NETWORK_ID_NULL);
+ checkArgument(!ingressPoint.equals(egressPoint),
+ "ingress and egress should be different (ingress: %s, egress: %s)", ingressPoint, egressPoint);
+
+ this.networkId = networkId;
+ this.ingressPoint = checkNotNull(ingressPoint);
+ this.egressPoint = checkNotNull(egressPoint);
+ }
+
+ /**
+ * Constructor for serializer.
+ */
+ protected VirtualNetworkIntent() {
+ super();
+ this.networkId = null;
+ this.ingressPoint = null;
+ this.egressPoint = null;
+ }
+
+ /**
+ * Returns the virtual network identifier.
+ *
+ * @return network identifier
+ */
+ public NetworkId networkId() {
+ return networkId;
+ }
+
+ /**
+ * Returns the port on which the ingress traffic should be connected to
+ * the egress.
+ *
+ * @return ingress port
+ */
+ public ConnectPoint ingressPoint() {
+ return ingressPoint;
+ }
+
+ /**
+ * Returns the port on which the traffic should egress.
+ *
+ * @return egress port
+ */
+ public ConnectPoint egressPoint() {
+ return egressPoint;
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass())
+ .add("networkId", networkId)
+ .add("id", id())
+ .add("key", key())
+ .add("appId", appId())
+ .add("priority", priority())
+ .add("resources", resources())
+ .add("selector", selector())
+ .add("treatment", treatment())
+ .add("ingress", ingressPoint)
+ .add("egress", egressPoint)
+ .add("constraints", constraints())
+ .toString();
+ }
+
+}
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkStore.java b/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkStore.java
index c2bc250..5deff3c 100644
--- a/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkStore.java
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkStore.java
@@ -26,6 +26,10 @@
import org.onosproject.net.Link;
import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentData;
+import org.onosproject.net.intent.IntentState;
+import org.onosproject.net.intent.Key;
import org.onosproject.store.Store;
import java.util.Set;
@@ -223,4 +227,73 @@
*/
Set<VirtualPort> getPorts(NetworkId networkId, DeviceId deviceId);
+ /**
+ * Add or update the intent to the store.
+ *
+ * @param intent virtual intent
+ * @param state intent state
+ */
+ void addOrUpdateIntent(Intent intent, IntentState state);
+
+ /**
+ * Remove the virtual intent from the store.
+ *
+ * @param intentKey intent key
+ * @return intent data
+ */
+ IntentData removeIntent(Key intentKey);
+
+ /**
+ * Adds the intent to tunnel identifier mapping to the store.
+ *
+ * @param intent intent
+ * @param tunnelId tunnel identifier
+ */
+ void addTunnelId(Intent intent, TunnelId tunnelId);
+
+ /**
+ * Return the set of tunnel identifiers store against the intent.
+ *
+ * @param intent intent
+ * @return set of tunnel identifiers
+ */
+ Set<TunnelId> getTunnelIds(Intent intent);
+
+ /**
+ * Removes the intent to tunnel identifier mapping from the store.
+ *
+ * @param intent intent
+ * @param tunnelId tunnel identifier
+ */
+ void removeTunnelId(Intent intent, TunnelId tunnelId);
+
+ /**
+ * Return all intents.
+ *
+ * @return set of intents
+ */
+ Set<Intent> getIntents();
+
+ /**
+ * Return the intent for the specified intent key.
+ *
+ * @param key intent key
+ * @return intent
+ */
+ Intent getIntent(Key key);
+
+ /**
+ * Return the set of intent data.
+ *
+ * @return set of intent data
+ */
+ Set<IntentData> getIntentData();
+
+ /**
+ * Return the intent data matching the intent key.
+ *
+ * @param key intent key
+ * @return intent data
+ */
+ IntentData getIntentData(Key key);
}
diff --git a/incubator/net/BUCK b/incubator/net/BUCK
index fba929b..17fa793 100644
--- a/incubator/net/BUCK
+++ b/incubator/net/BUCK
@@ -2,13 +2,15 @@
'//lib:CORE_DEPS',
'//core/common:onos-core-common',
'//incubator/api:onos-incubator-api',
+ '//incubator/store:onos-incubator-store',
+ '//utils/rest:onlab-rest',
]
TEST_DEPS = [
+ '//lib:TEST_REST',
'//lib:TEST_ADAPTERS',
'//core/api:onos-api-tests',
'//core/common:onos-core-common-tests',
- '//incubator/store:onos-incubator-store',
'//core/store/serializers:onos-core-serializers',
'//lib:concurrent-trees',
]
diff --git a/incubator/net/pom.xml b/incubator/net/pom.xml
index 0346ac4..e5ea75c 100644
--- a/incubator/net/pom.xml
+++ b/incubator/net/pom.xml
@@ -95,6 +95,14 @@
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.scr.annotations</artifactId>
</dependency>
+
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onlab-osgi</artifactId>
+ <version>${project.version}</version>
+ <classifier>tests</classifier>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkIntentService.java b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkIntentService.java
new file mode 100644
index 0000000..191bec2
--- /dev/null
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkIntentService.java
@@ -0,0 +1,240 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.incubator.net.virtual.impl;
+
+import com.google.common.collect.Iterators;
+import org.onlab.osgi.ServiceDirectory;
+import org.onosproject.event.AbstractListenerManager;
+import org.onosproject.incubator.net.virtual.VirtualNetwork;
+import org.onosproject.incubator.net.virtual.VirtualNetworkIntent;
+import org.onosproject.incubator.net.virtual.VirtualNetworkService;
+import org.onosproject.incubator.net.virtual.VirtualNetworkStore;
+import org.onosproject.incubator.net.virtual.VirtualPort;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentData;
+import org.onosproject.net.intent.IntentEvent;
+import org.onosproject.net.intent.IntentListener;
+import org.onosproject.net.intent.IntentPartitionService;
+import org.onosproject.net.intent.IntentService;
+import org.onosproject.net.intent.IntentState;
+import org.onosproject.net.intent.Key;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+import static com.google.common.base.Preconditions.*;
+
+/**
+ * intent service implementation built on the virtual network service.
+ */
+public class VirtualNetworkIntentService extends AbstractListenerManager<IntentEvent, IntentListener>
+ implements IntentService, VnetService {
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ private static final String NETWORK_NULL = "Network cannot be null";
+ private static final String NETWORK_ID_NULL = "Network ID cannot be null";
+ private static final String DEVICE_NULL = "Device cannot be null";
+ private static final String INTENT_NULL = "Intent cannot be null";
+ private static final String KEY_NULL = "Key cannot be null";
+ private static final String APP_ID_NULL = "Intent app identifier cannot be null";
+ private static final String INTENT_KEY_NULL = "Intent key cannot be null";
+ private static final String CP_NULL = "Connect Point cannot be null";
+
+ protected IntentService intentService;
+ protected VirtualNetworkStore store;
+ protected IntentPartitionService partitionService;
+
+ private final VirtualNetwork network;
+ private final VirtualNetworkService manager;
+
+ /**
+ * Creates a new VirtualNetworkIntentService object.
+ *
+ * @param virtualNetworkManager virtual network manager service
+ * @param network virtual network
+ * @param serviceDirectory service directory
+ */
+ public VirtualNetworkIntentService(VirtualNetworkService virtualNetworkManager, VirtualNetwork network,
+ ServiceDirectory serviceDirectory) {
+ checkNotNull(network, NETWORK_NULL);
+ this.network = network;
+ this.manager = virtualNetworkManager;
+ this.store = serviceDirectory.get(VirtualNetworkStore.class);
+ this.intentService = serviceDirectory.get(IntentService.class);
+ this.partitionService = serviceDirectory.get(IntentPartitionService.class);
+ }
+
+ @Override
+ public void submit(Intent intent) {
+ checkNotNull(intent, INTENT_NULL);
+ checkState(intent instanceof VirtualNetworkIntent, "Only VirtualNetworkIntent is supported.");
+ checkArgument(validateIntent((VirtualNetworkIntent) intent), "Invalid Intent");
+
+ intentService.submit(intent);
+ }
+
+ /**
+ * Returns true if the virtual network intent is valid.
+ *
+ * @param intent virtual network intent
+ * @return true if intent is valid
+ */
+ private boolean validateIntent(VirtualNetworkIntent intent) {
+ checkNotNull(intent, INTENT_NULL);
+ checkNotNull(intent.networkId(), NETWORK_ID_NULL);
+ checkNotNull(intent.appId(), APP_ID_NULL);
+ checkNotNull(intent.key(), INTENT_KEY_NULL);
+ ConnectPoint ingressPoint = intent.ingressPoint();
+ ConnectPoint egressPoint = intent.egressPoint();
+
+ return (validateConnectPoint(ingressPoint) && validateConnectPoint(egressPoint));
+ }
+
+ /**
+ * Returns true if the connect point is valid.
+ *
+ * @param connectPoint connect point
+ * @return true if connect point is valid
+ */
+ private boolean validateConnectPoint(ConnectPoint connectPoint) {
+ checkNotNull(connectPoint, CP_NULL);
+ Port port = getPort(connectPoint.deviceId(), connectPoint.port());
+ return port == null ? false : true;
+ }
+
+ /**
+ * Returns the virtual port for the given device identifier and port number.
+ *
+ * @param deviceId virtual device identifier
+ * @param portNumber virtual port number
+ * @return virtual port
+ */
+ private Port getPort(DeviceId deviceId, PortNumber portNumber) {
+ checkNotNull(deviceId, DEVICE_NULL);
+
+ Optional<VirtualPort> foundPort = manager.getVirtualPorts(this.network.id(), deviceId)
+ .stream()
+ .filter(port -> port.number().equals(portNumber))
+ .findFirst();
+ if (foundPort.isPresent()) {
+ return foundPort.get();
+ }
+ return null;
+ }
+
+ @Override
+ public void withdraw(Intent intent) {
+ checkNotNull(intent, INTENT_NULL);
+ // Withdraws the physical intents created due to the virtual intents.
+ store.getTunnelIds(intent)
+ .forEach(tunnelId -> {
+ Key intentKey = Key.of(tunnelId.id(), intent.appId());
+ Intent physicalIntent = intentService.getIntent(intentKey);
+ checkNotNull(physicalIntent, INTENT_NULL);
+
+ // Withdraw the physical intent(s)
+ log.info("Withdrawing pt-pt intent: " + physicalIntent);
+ intentService.withdraw(physicalIntent);
+ });
+ // Now withdraw the virtual intent
+ log.info("Withdrawing virtual intent: " + intent);
+ intentService.withdraw(intent);
+ }
+
+ @Override
+ public void purge(Intent intent) {
+ checkNotNull(intent, INTENT_NULL);
+ // Purges the physical intents created for each tunnelId.
+ store.getTunnelIds(intent)
+ .forEach(tunnelId -> {
+ Key intentKey = Key.of(tunnelId.id(), intent.appId());
+ Intent physicalIntent = intentService.getIntent(intentKey);
+ checkNotNull(physicalIntent, INTENT_NULL);
+
+ // Purge the physical intent(s)
+ intentService.purge(physicalIntent);
+ store.removeTunnelId(intent, tunnelId);
+ });
+ // Now purge the virtual intent
+ intentService.purge(intent);
+ }
+
+ @Override
+ public Intent getIntent(Key key) {
+ checkNotNull(key, KEY_NULL);
+ return store.getIntent(key);
+ }
+
+ @Override
+ public Iterable<Intent> getIntents() {
+ return store.getIntents();
+ }
+
+ @Override
+ public Iterable<IntentData> getIntentData() {
+ return store.getIntentData();
+ }
+
+ @Override
+ public long getIntentCount() {
+ return Iterators.size(getIntents().iterator());
+ }
+
+ @Override
+ public IntentState getIntentState(Key intentKey) {
+ checkNotNull(intentKey, KEY_NULL);
+ return store.getIntentData(intentKey).state();
+ }
+
+ @Override
+ public List<Intent> getInstallableIntents(Key intentKey) {
+ List<Intent> intents = new ArrayList<>();
+ getIntentData().forEach(intentData -> {
+ if (intentData.intent().key().equals(intentKey)) {
+ intents.addAll(intentData.installables());
+ }
+ });
+ return intents;
+ }
+
+ @Override
+ public boolean isLocal(Key intentKey) {
+ checkNotNull(intentKey, INTENT_KEY_NULL);
+ Intent intent = getIntent(intentKey);
+ checkNotNull(intent, INTENT_NULL);
+ return partitionService.isMine(intentKey);
+ }
+
+ @Override
+ public Iterable<Intent> getPending() {
+ return null;
+ }
+
+
+ @Override
+ public VirtualNetwork network() {
+ return network;
+ }
+}
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkManager.java b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkManager.java
index 6c06968..f264658 100644
--- a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkManager.java
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkManager.java
@@ -22,6 +22,7 @@
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.Service;
+import org.onlab.osgi.DefaultServiceDirectory;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
@@ -34,9 +35,9 @@
import org.onosproject.incubator.net.virtual.VirtualNetwork;
import org.onosproject.incubator.net.virtual.VirtualNetworkAdminService;
import org.onosproject.incubator.net.virtual.VirtualNetworkEvent;
+import org.onosproject.incubator.net.virtual.VirtualNetworkIntent;
import org.onosproject.incubator.net.virtual.VirtualNetworkListener;
import org.onosproject.incubator.net.virtual.VirtualNetworkProvider;
-import org.onosproject.incubator.net.virtual.VirtualNetworkProviderRegistry;
import org.onosproject.incubator.net.virtual.VirtualNetworkProviderService;
import org.onosproject.incubator.net.virtual.VirtualNetworkService;
import org.onosproject.incubator.net.virtual.VirtualNetworkStore;
@@ -50,6 +51,10 @@
import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.intent.IntentEvent;
+import org.onosproject.net.intent.IntentListener;
+import org.onosproject.net.intent.IntentService;
+import org.onosproject.net.intent.IntentState;
import org.onosproject.net.link.LinkService;
import org.onosproject.net.provider.AbstractListenerProviderRegistry;
import org.onosproject.net.provider.AbstractProviderService;
@@ -70,7 +75,7 @@
public class VirtualNetworkManager
extends AbstractListenerProviderRegistry<VirtualNetworkEvent, VirtualNetworkListener,
VirtualNetworkProvider, VirtualNetworkProviderService>
- implements VirtualNetworkService, VirtualNetworkAdminService, VirtualNetworkProviderRegistry {
+ implements VirtualNetworkService, VirtualNetworkAdminService {
private final Logger log = LoggerFactory.getLogger(getClass());
@@ -78,28 +83,51 @@
private static final String NETWORK_NULL = "Network ID cannot be null";
private static final String DEVICE_NULL = "Device ID cannot be null";
private static final String LINK_POINT_NULL = "Link end-point cannot be null";
- private static final String VIRTUAL_LINK_NULL = "Virtual Link cannot be null";
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected VirtualNetworkStore store;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected IntentService intentService;
+
+ private final InternalVirtualIntentListener intentListener = new InternalVirtualIntentListener();
+
private VirtualNetworkStoreDelegate delegate = this::post;
// TODO: figure out how to coordinate "implementation" of a virtual network in a cluster
+ /**
+ * Only used for Junit test methods outside of this package.
+ *
+ * @param store virtual network store
+ */
+ public void setStore(VirtualNetworkStore store) {
+ this.store = store;
+ }
+
+ /**
+ * Only used for Junit test methods outside of this package.
+ *
+ * @param intentService intent service
+ */
+
+ public void setIntentService(IntentService intentService) {
+ this.intentService = intentService;
+ }
+
@Activate
- protected void activate() {
+ public void activate() {
store.setDelegate(delegate);
eventDispatcher.addSink(VirtualNetworkEvent.class, listenerRegistry);
-
+ intentService.addListener(intentListener);
log.info("Started");
}
@Deactivate
- protected void deactivate() {
+ public void deactivate() {
store.unsetDelegate(delegate);
eventDispatcher.removeSink(VirtualNetworkEvent.class);
-
+ intentService.removeListener(intentListener);
log.info("Stopped");
}
@@ -167,48 +195,18 @@
checkNotNull(networkId, NETWORK_NULL);
checkNotNull(src, LINK_POINT_NULL);
checkNotNull(dst, LINK_POINT_NULL);
- VirtualLink virtualLink = store.addLink(networkId, src, dst, Link.State.INACTIVE, null);
- checkNotNull(virtualLink, VIRTUAL_LINK_NULL);
-
- if (virtualLink.providerId() != null) {
- VirtualNetworkProvider provider = getProvider(virtualLink.providerId());
- if (provider != null) {
- TunnelId tunnelId = provider.createTunnel(networkId, mapVirtualToPhysicalPort(networkId, src),
- mapVirtualToPhysicalPort(networkId, dst));
- store.updateLink(virtualLink, tunnelId, Link.State.INACTIVE);
- }
- }
- return virtualLink;
- }
-
- /**
- * Maps the virtual connect point to a physical connect point.
- *
- * @param networkId network identifier
- * @param virtualCp virtual connect point
- * @return physical connect point
- */
- private ConnectPoint mapVirtualToPhysicalPort(NetworkId networkId,
- ConnectPoint virtualCp) {
- Set<VirtualPort> ports = store.getPorts(networkId, virtualCp.deviceId());
- for (VirtualPort port : ports) {
- if (port.element().id().equals(virtualCp.elementId()) &&
- port.number().equals(virtualCp.port())) {
- return new ConnectPoint(port.realizedBy().element().id(), port.realizedBy().number());
- }
- }
- return null;
+ return store.addLink(networkId, src, dst, Link.State.ACTIVE, null);
}
/**
* Maps the physical connect point to a virtual connect point.
*
- * @param networkId network identifier
+ * @param networkId network identifier
* @param physicalCp physical connect point
* @return virtual connect point
*/
private ConnectPoint mapPhysicalToVirtualToPort(NetworkId networkId,
- ConnectPoint physicalCp) {
+ ConnectPoint physicalCp) {
Set<VirtualPort> ports = store.getPorts(networkId, null);
for (VirtualPort port : ports) {
if (port.realizedBy().element().id().equals(physicalCp.elementId()) &&
@@ -224,14 +222,7 @@
checkNotNull(networkId, NETWORK_NULL);
checkNotNull(src, LINK_POINT_NULL);
checkNotNull(dst, LINK_POINT_NULL);
- VirtualLink virtualLink = store.removeLink(networkId, src, dst);
-
- if (virtualLink != null && virtualLink.providerId() != null) {
- VirtualNetworkProvider provider = getProvider(virtualLink.providerId());
- if (provider != null) {
- provider.destroyTunnel(networkId, virtualLink.tunnelId());
- }
- }
+ store.removeLink(networkId, src, dst);
}
@Override
@@ -257,6 +248,12 @@
return store.getNetworks(tenantId);
}
+ /**
+ * Returns the virtual network matching the network identifier.
+ *
+ * @param networkId network identifier
+ * @return virtual network
+ */
private VirtualNetwork getVirtualNetwork(NetworkId networkId) {
checkNotNull(networkId, NETWORK_NULL);
return store.getNetwork(networkId);
@@ -299,17 +296,38 @@
return (T) service;
}
+ /**
+ * Returns the Vnet service matching the service key.
+ *
+ * @param serviceKey service key
+ * @return vnet service
+ */
private VnetService lookup(ServiceKey serviceKey) {
return networkServices.get(serviceKey);
}
+ /**
+ * Creates a new service key using the specified network identifier and service class.
+ *
+ * @param networkId network identifier
+ * @param serviceClass service class
+ * @param <T> type of service
+ * @return service key
+ */
private <T> ServiceKey networkServiceKey(NetworkId networkId, Class<T> serviceClass) {
return new ServiceKey(networkId, serviceClass);
}
+ /**
+ * Create a new vnet service instance.
+ *
+ * @param serviceKey service key
+ * @return vnet service
+ */
private VnetService create(ServiceKey serviceKey) {
VirtualNetwork network = getVirtualNetwork(serviceKey.networkId());
+ checkNotNull(network, NETWORK_NULL);
VnetService service;
if (serviceKey.serviceClass.equals(DeviceService.class)) {
service = new VirtualNetworkDeviceService(this, network);
@@ -317,6 +335,8 @@
service = new VirtualNetworkLinkService(this, network);
} else if (serviceKey.serviceClass.equals(TopologyService.class)) {
service = new VirtualNetworkTopologyService(this, network);
+ } else if (serviceKey.serviceClass.equals(IntentService.class)) {
+ service = new VirtualNetworkIntentService(this, network, new DefaultServiceDirectory());
} else {
return null;
}
@@ -324,25 +344,94 @@
return service;
}
+ /**
+ * Service key class.
+ */
private class ServiceKey {
final NetworkId networkId;
final Class serviceClass;
+ /**
+ * Constructor for service key.
+ *
+ * @param networkId network identifier
+ * @param serviceClass service class
+ */
public ServiceKey(NetworkId networkId, Class serviceClass) {
checkNotNull(networkId, NETWORK_NULL);
this.networkId = networkId;
this.serviceClass = serviceClass;
}
+ /**
+ * Returns the network identifier.
+ *
+ * @return network identifier
+ */
public NetworkId networkId() {
return networkId;
}
+ /**
+ * Returns the service class.
+ *
+ * @return service class
+ */
public Class serviceClass() {
return serviceClass;
}
}
+ /**
+ * Internal intent event listener.
+ */
+ private class InternalVirtualIntentListener implements IntentListener {
+ @Override
+ public void event(IntentEvent event) {
+
+ // Ignore intent events that are not relevant.
+ if (!isRelevant(event)) {
+ return;
+ }
+
+ VirtualNetworkIntent intent = (VirtualNetworkIntent) event.subject();
+
+ switch (event.type()) {
+ case INSTALL_REQ:
+ store.addOrUpdateIntent(intent, IntentState.INSTALL_REQ);
+ break;
+ case INSTALLED:
+ store.addOrUpdateIntent(intent, IntentState.INSTALLED);
+ break;
+ case WITHDRAW_REQ:
+ store.addOrUpdateIntent(intent, IntentState.WITHDRAW_REQ);
+ break;
+ case WITHDRAWN:
+ store.addOrUpdateIntent(intent, IntentState.WITHDRAWN);
+ break;
+ case FAILED:
+ store.addOrUpdateIntent(intent, IntentState.FAILED);
+ break;
+ case CORRUPT:
+ store.addOrUpdateIntent(intent, IntentState.CORRUPT);
+ break;
+ case PURGED:
+ store.removeIntent(intent.key());
+ default:
+ break;
+ }
+ }
+
+ @Override
+ public boolean isRelevant(IntentEvent event) {
+ if (event.subject() instanceof VirtualNetworkIntent) {
+ return true;
+ }
+ return false;
+ }
+ }
+
+
@Override
protected VirtualNetworkProviderService createProviderService(VirtualNetworkProvider provider) {
return new InternalVirtualNetworkProviderService(provider);
diff --git a/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkDeviceServiceTest.java b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkDeviceServiceTest.java
index ecb8b0d..d44d038 100644
--- a/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkDeviceServiceTest.java
+++ b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkDeviceServiceTest.java
@@ -38,6 +38,8 @@
import org.onosproject.net.PortNumber;
import org.onosproject.net.TestDeviceParams;
import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.intent.FakeIntentManager;
+import org.onosproject.net.intent.TestableIntentService;
import org.onosproject.store.service.TestStorageService;
import java.util.Iterator;
@@ -54,6 +56,7 @@
private VirtualNetworkManager manager;
private DistributedVirtualNetworkStore virtualNetworkManagerStore;
private CoreService coreService;
+ private TestableIntentService intentService = new FakeIntentManager();
@Before
public void setUp() throws Exception {
@@ -67,6 +70,7 @@
manager = new VirtualNetworkManager();
manager.store = virtualNetworkManagerStore;
+ manager.intentService = intentService;
NetTestTools.injectEventDispatcher(manager, new TestEventDispatcher());
manager.activate();
}
diff --git a/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkIntentServiceTest.java b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkIntentServiceTest.java
new file mode 100644
index 0000000..ef8de45
--- /dev/null
+++ b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkIntentServiceTest.java
@@ -0,0 +1,398 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.incubator.net.virtual.impl;
+
+import com.google.common.collect.Iterators;
+import com.google.common.collect.Lists;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.junit.TestUtils;
+import org.onlab.osgi.ServiceDirectory;
+import org.onlab.osgi.TestServiceDirectory;
+import org.onlab.rest.BaseResource;
+import org.onosproject.TestApplicationId;
+import org.onosproject.common.event.impl.TestEventDispatcher;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.core.CoreServiceAdapter;
+import org.onosproject.core.IdGenerator;
+import org.onosproject.incubator.net.virtual.TenantId;
+import org.onosproject.incubator.net.virtual.VirtualDevice;
+import org.onosproject.incubator.net.virtual.VirtualLink;
+import org.onosproject.incubator.net.virtual.VirtualNetwork;
+import org.onosproject.incubator.net.virtual.VirtualNetworkIntent;
+import org.onosproject.incubator.net.virtual.VirtualNetworkStore;
+import org.onosproject.incubator.store.virtual.impl.DistributedVirtualNetworkStore;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DefaultPort;
+import org.onosproject.net.EncapsulationType;
+import org.onosproject.net.Link;
+import org.onosproject.net.NetTestTools;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.TestDeviceParams;
+import org.onosproject.net.intent.Constraint;
+import org.onosproject.net.intent.FakeIntentManager;
+import org.onosproject.net.intent.FlowRuleIntent;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentCompiler;
+import org.onosproject.net.intent.IntentEvent;
+import org.onosproject.net.intent.IntentExtensionService;
+import org.onosproject.net.intent.IntentListener;
+import org.onosproject.net.intent.IntentPartitionService;
+import org.onosproject.net.intent.IntentPartitionServiceAdapter;
+import org.onosproject.net.intent.IntentService;
+import org.onosproject.net.intent.IntentState;
+import org.onosproject.net.intent.IntentTestsMocks;
+import org.onosproject.net.intent.Key;
+import org.onosproject.net.intent.MockIdGenerator;
+import org.onosproject.net.intent.TestableIntentService;
+import org.onosproject.net.intent.constraint.EncapsulationConstraint;
+import org.onosproject.store.service.TestStorageService;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+
+import static org.junit.Assert.*;
+
+/**
+ * Junit tests for VirtualNetworkIntentService.
+ */
+public class VirtualNetworkIntentServiceTest extends TestDeviceParams {
+
+ private final String tenantIdValue1 = "TENANT_ID1";
+ private static final ApplicationId APP_ID =
+ new TestApplicationId(PtToPtIntentVirtualNetworkProvider.PTPT_INTENT_APPID);
+
+ private ConnectPoint cp1;
+ private ConnectPoint cp2;
+ private ConnectPoint cp3;
+ private ConnectPoint cp4;
+ private ConnectPoint cp5;
+ private ConnectPoint cp6;
+ private VirtualLink link1;
+ private VirtualLink link2;
+ private VirtualLink link3;
+ private VirtualLink link4;
+ private VirtualLink link5;
+ private VirtualLink link6;
+
+ private VirtualNetworkManager manager;
+ private static DistributedVirtualNetworkStore virtualNetworkManagerStore;
+ private CoreService coreService;
+ private TestableIntentService intentService = new FakeIntentManager();
+ private VirtualNetworkIntentService vnetIntentService;
+ private TestIntentCompiler compiler = new TestIntentCompiler();
+ private IntentExtensionService intentExtensionService;
+ private IntentPartitionService intentPartitionService;
+ private ServiceDirectory testDirectory;
+ private TestListener listener = new TestListener();
+ private IdGenerator idGenerator = new MockIdGenerator();
+ private static final int MAX_WAIT_TIME = 5;
+ private static final int MAX_PERMITS = 1;
+ private static Semaphore created;
+ private static Semaphore withdrawn;
+ private static Semaphore purged;
+
+ @Before
+ public void setUp() throws Exception {
+ virtualNetworkManagerStore = new DistributedVirtualNetworkStore();
+
+ coreService = new VirtualNetworkIntentServiceTest.TestCoreService();
+
+ Intent.unbindIdGenerator(idGenerator);
+ Intent.bindIdGenerator(idGenerator);
+
+ virtualNetworkManagerStore.setCoreService(coreService);
+ TestUtils.setField(coreService, "coreService", new VirtualNetworkIntentServiceTest.TestCoreService());
+ TestUtils.setField(virtualNetworkManagerStore, "storageService", new TestStorageService());
+ virtualNetworkManagerStore.activate();
+
+ manager = new VirtualNetworkManager();
+ manager.store = virtualNetworkManagerStore;
+ NetTestTools.injectEventDispatcher(manager, new TestEventDispatcher());
+ manager.intentService = intentService;
+ manager.activate();
+ intentService.addListener(listener);
+
+ // Register a compiler and an installer both setup for success.
+ intentExtensionService = intentService;
+ intentExtensionService.registerCompiler(VirtualNetworkIntent.class, compiler);
+
+ created = new Semaphore(0, true);
+ withdrawn = new Semaphore(0, true);
+ purged = new Semaphore(0, true);
+
+ intentPartitionService = new IntentPartitionServiceAdapter();
+ testDirectory = new TestServiceDirectory()
+ .add(VirtualNetworkStore.class, virtualNetworkManagerStore)
+ .add(IntentService.class, intentService)
+ .add(IntentPartitionService.class, intentPartitionService);
+ BaseResource.setServiceDirectory(testDirectory);
+ }
+
+ @After
+ public void tearDown() {
+ virtualNetworkManagerStore.deactivate();
+ manager.deactivate();
+ NetTestTools.injectEventDispatcher(manager, null);
+ Intent.unbindIdGenerator(idGenerator);
+ intentService.removeListener(listener);
+ created = null;
+ withdrawn = null;
+ purged = null;
+ }
+
+ /**
+ * Method to create the virtual network for further testing.
+ *
+ * @return virtual network
+ */
+ private VirtualNetwork setupVirtualNetworkTopology() {
+ manager.registerTenantId(TenantId.tenantId(tenantIdValue1));
+ VirtualNetwork virtualNetwork = manager.createVirtualNetwork(TenantId.tenantId(tenantIdValue1));
+ VirtualDevice virtualDevice1 =
+ manager.createVirtualDevice(virtualNetwork.id(), DID1);
+ VirtualDevice virtualDevice2 =
+ manager.createVirtualDevice(virtualNetwork.id(), DID2);
+ VirtualDevice virtualDevice3 =
+ manager.createVirtualDevice(virtualNetwork.id(), DID3);
+ VirtualDevice virtualDevice4 =
+ manager.createVirtualDevice(virtualNetwork.id(), DID4);
+
+ Port port1 = new DefaultPort(virtualDevice1, PortNumber.portNumber(1), true);
+ manager.createVirtualPort(virtualNetwork.id(), virtualDevice1.id(), port1.number(), port1);
+ cp1 = new ConnectPoint(virtualDevice1.id(), port1.number());
+
+ Port port2 = new DefaultPort(virtualDevice1, PortNumber.portNumber(2), true);
+ manager.createVirtualPort(virtualNetwork.id(), virtualDevice1.id(), port2.number(), port2);
+ cp2 = new ConnectPoint(virtualDevice1.id(), port2.number());
+
+ Port port3 = new DefaultPort(virtualDevice2, PortNumber.portNumber(3), true);
+ manager.createVirtualPort(virtualNetwork.id(), virtualDevice2.id(), port3.number(), port3);
+ cp3 = new ConnectPoint(virtualDevice2.id(), port3.number());
+
+ Port port4 = new DefaultPort(virtualDevice2, PortNumber.portNumber(4), true);
+ manager.createVirtualPort(virtualNetwork.id(), virtualDevice2.id(), port4.number(), port4);
+ cp4 = new ConnectPoint(virtualDevice2.id(), port4.number());
+
+ Port port5 = new DefaultPort(virtualDevice3, PortNumber.portNumber(5), true);
+ manager.createVirtualPort(virtualNetwork.id(), virtualDevice3.id(), port5.number(), port5);
+ cp5 = new ConnectPoint(virtualDevice3.id(), port5.number());
+
+ Port port6 = new DefaultPort(virtualDevice3, PortNumber.portNumber(6), true);
+ manager.createVirtualPort(virtualNetwork.id(), virtualDevice3.id(), port6.number(), port6);
+ cp6 = new ConnectPoint(virtualDevice3.id(), port6.number());
+
+ link1 = manager.createVirtualLink(virtualNetwork.id(), cp1, cp3);
+ virtualNetworkManagerStore.updateLink(link1, link1.tunnelId(), Link.State.ACTIVE);
+ link2 = manager.createVirtualLink(virtualNetwork.id(), cp3, cp1);
+ virtualNetworkManagerStore.updateLink(link2, link2.tunnelId(), Link.State.ACTIVE);
+ link3 = manager.createVirtualLink(virtualNetwork.id(), cp4, cp5);
+ virtualNetworkManagerStore.updateLink(link3, link3.tunnelId(), Link.State.ACTIVE);
+ link4 = manager.createVirtualLink(virtualNetwork.id(), cp5, cp4);
+ virtualNetworkManagerStore.updateLink(link4, link4.tunnelId(), Link.State.ACTIVE);
+
+ vnetIntentService = new VirtualNetworkIntentService(manager, virtualNetwork, testDirectory);
+ vnetIntentService.intentService = intentService;
+ vnetIntentService.store = virtualNetworkManagerStore;
+ vnetIntentService.partitionService = intentPartitionService;
+ return virtualNetwork;
+ }
+
+ /**
+ * Tests the submit(), withdraw(), and purge() methods.
+ */
+ @Test
+ public void testCreateAndRemoveIntent() {
+ VirtualNetwork virtualNetwork = setupVirtualNetworkTopology();
+
+ Key intentKey = Key.of("test", APP_ID);
+
+ List<Constraint> constraints = new ArrayList<>();
+ constraints.add(new EncapsulationConstraint(EncapsulationType.VLAN));
+
+ VirtualNetworkIntent virtualIntent = VirtualNetworkIntent.builder()
+ .networkId(virtualNetwork.id())
+ .key(intentKey)
+ .appId(APP_ID)
+ .ingressPoint(cp1)
+ .egressPoint(cp5)
+ .constraints(constraints)
+ .build();
+ // Test the submit() method.
+ vnetIntentService.submit(virtualIntent);
+
+ // Wait for the both intents to go into an INSTALLED state.
+ try {
+ if (!created.tryAcquire(MAX_PERMITS, MAX_WAIT_TIME, TimeUnit.SECONDS)) {
+ fail("Failed to wait for intent to get installed.");
+ }
+ } catch (InterruptedException e) {
+ fail("Semaphore exception during intent installation." + e.getMessage());
+ }
+
+ // Test the getIntentState() method
+ assertEquals("The intent state did not match as expected.", IntentState.INSTALLED,
+ vnetIntentService.getIntentState(virtualIntent.key()));
+
+ // Test the withdraw() method.
+ vnetIntentService.withdraw(virtualIntent);
+ // Wait for the both intents to go into a WITHDRAWN state.
+ try {
+ if (!withdrawn.tryAcquire(MAX_PERMITS, MAX_WAIT_TIME, TimeUnit.SECONDS)) {
+ fail("Failed to wait for intent to get withdrawn.");
+ }
+ } catch (InterruptedException e) {
+ fail("Semaphore exception during intent withdrawal." + e.getMessage());
+ }
+
+ // Test the getIntentState() method
+ assertEquals("The intent state did not match as expected.", IntentState.WITHDRAWN,
+ vnetIntentService.getIntentState(virtualIntent.key()));
+
+ // Test the purge() method.
+ vnetIntentService.purge(virtualIntent);
+ // Wait for the both intents to be removed/purged.
+ try {
+ if (!purged.tryAcquire(MAX_PERMITS, MAX_WAIT_TIME, TimeUnit.SECONDS)) {
+ fail("Failed to wait for intent to get purged.");
+ }
+ } catch (InterruptedException e) {
+ fail("Semaphore exception during intent purging." + e.getMessage());
+ }
+
+ }
+
+ /**
+ * Tests the getIntents, getIntent(), getIntentData(), getIntentCount(),
+ * isLocal() methods.
+ */
+ @Test
+ public void testGetIntents() {
+ VirtualNetwork virtualNetwork = setupVirtualNetworkTopology();
+
+ Key intentKey = Key.of("test", APP_ID);
+
+ List<Constraint> constraints = new ArrayList<>();
+ constraints.add(new EncapsulationConstraint(EncapsulationType.VLAN));
+
+ VirtualNetworkIntent virtualIntent = VirtualNetworkIntent.builder()
+ .networkId(virtualNetwork.id())
+ .key(intentKey)
+ .appId(APP_ID)
+ .ingressPoint(cp1)
+ .egressPoint(cp5)
+ .constraints(constraints)
+ .build();
+ // Test the submit() method.
+ vnetIntentService.submit(virtualIntent);
+
+ // Wait for the both intents to go into an INSTALLED state.
+ try {
+ if (!created.tryAcquire(MAX_PERMITS, MAX_WAIT_TIME, TimeUnit.SECONDS)) {
+ fail("Failed to wait for intent to get installed.");
+ }
+ } catch (InterruptedException e) {
+ fail("Semaphore exception during intent installation." + e.getMessage());
+ }
+
+ // Test the getIntents() method
+ assertEquals("The intents size did not match as expected.", 1,
+ Iterators.size(vnetIntentService.getIntents().iterator()));
+
+ // Test the getIntent() method
+ assertNotNull("The intent should have been found.", vnetIntentService.getIntent(virtualIntent.key()));
+
+ // Test the getIntentData() method
+ assertEquals("The intent data size did not match as expected.", 1,
+ Iterators.size(vnetIntentService.getIntentData().iterator()));
+
+ // Test the getIntentCount() method
+ assertEquals("The intent count did not match as expected.", 1,
+ vnetIntentService.getIntentCount());
+
+ // Test the isLocal() method
+ assertTrue("The intent should be local.", vnetIntentService.isLocal(virtualIntent.key()));
+
+ }
+
+ /**
+ * Test listener to listen for intent events.
+ */
+ private static class TestListener implements IntentListener {
+
+ @Override
+ public void event(IntentEvent event) {
+ switch (event.type()) {
+ case INSTALLED:
+ // Release one permit on the created semaphore since the Intent event was received.
+ virtualNetworkManagerStore.addOrUpdateIntent(event.subject(), IntentState.INSTALLED);
+ created.release();
+ break;
+ case WITHDRAWN:
+ // Release one permit on the removed semaphore since the Intent event was received.
+ virtualNetworkManagerStore.addOrUpdateIntent(event.subject(), IntentState.WITHDRAWN);
+ withdrawn.release();
+ break;
+ case PURGED:
+ // Release one permit on the purged semaphore since the Intent event was received.
+ purged.release();
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ /**
+ * Core service test class.
+ */
+ private class TestCoreService extends CoreServiceAdapter {
+
+ @Override
+ public IdGenerator getIdGenerator(String topic) {
+ return new IdGenerator() {
+ private AtomicLong counter = new AtomicLong(0);
+
+ @Override
+ public long getNewId() {
+ return counter.getAndIncrement();
+ }
+ };
+ }
+ }
+
+ private static class TestIntentCompiler implements IntentCompiler<VirtualNetworkIntent> {
+ @Override
+ public List<Intent> compile(VirtualNetworkIntent intent, List<Intent> installable) {
+ return Lists.newArrayList(new MockInstallableIntent());
+ }
+ }
+
+ private static class MockInstallableIntent extends FlowRuleIntent {
+
+ public MockInstallableIntent() {
+ super(APP_ID, Collections.singletonList(new IntentTestsMocks.MockFlowRule(100)), Collections.emptyList());
+ }
+ }
+}
diff --git a/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkLinkServiceTest.java b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkLinkServiceTest.java
index f056f7c..ee5a5dd 100644
--- a/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkLinkServiceTest.java
+++ b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkLinkServiceTest.java
@@ -35,6 +35,8 @@
import org.onosproject.net.NetTestTools;
import org.onosproject.net.PortNumber;
import org.onosproject.net.TestDeviceParams;
+import org.onosproject.net.intent.FakeIntentManager;
+import org.onosproject.net.intent.TestableIntentService;
import org.onosproject.net.link.LinkService;
import org.onosproject.store.service.TestStorageService;
@@ -54,6 +56,7 @@
private VirtualNetworkManager manager;
private DistributedVirtualNetworkStore virtualNetworkManagerStore;
private CoreService coreService;
+ private TestableIntentService intentService = new FakeIntentManager();
@Before
public void setUp() throws Exception {
@@ -67,6 +70,7 @@
manager = new VirtualNetworkManager();
manager.store = virtualNetworkManagerStore;
+ manager.intentService = intentService;
NetTestTools.injectEventDispatcher(manager, new TestEventDispatcher());
manager.activate();
}
@@ -103,12 +107,12 @@
Iterator<Link> it = linkService.getLinks().iterator();
assertEquals("The link set size did not match.", 2, Iterators.size(it));
- // test the getActiveLinks() method where no links are ACTIVE
+ // test the getActiveLinks() method where all links are ACTIVE
Iterator<Link> it2 = linkService.getActiveLinks().iterator();
- assertEquals("The link set size did not match.", 0, Iterators.size(it2));
+ assertEquals("The link set size did not match.", 2, Iterators.size(it2));
// test the getActiveLinks() method where one link is ACTIVE
- virtualNetworkManagerStore.updateLink(link1, link1.tunnelId(), Link.State.ACTIVE);
+ virtualNetworkManagerStore.updateLink(link1, link1.tunnelId(), Link.State.INACTIVE);
Iterator<Link> it3 = linkService.getActiveLinks().iterator();
assertEquals("The link set size did not match.", 1, Iterators.size(it3));
diff --git a/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkManagerTest.java b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkManagerTest.java
index df5ef28..2834881 100644
--- a/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkManagerTest.java
+++ b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkManagerTest.java
@@ -27,6 +27,7 @@
import org.onosproject.core.CoreServiceAdapter;
import org.onosproject.core.IdGenerator;
import org.onosproject.event.Event;
+import org.onosproject.incubator.net.tunnel.TunnelId;
import org.onosproject.incubator.net.virtual.DefaultVirtualNetwork;
import org.onosproject.incubator.net.virtual.NetworkId;
import org.onosproject.incubator.net.virtual.TenantId;
@@ -35,6 +36,7 @@
import org.onosproject.incubator.net.virtual.VirtualLink;
import org.onosproject.incubator.net.virtual.VirtualNetwork;
import org.onosproject.incubator.net.virtual.VirtualNetworkEvent;
+import org.onosproject.incubator.net.virtual.VirtualNetworkIntent;
import org.onosproject.incubator.net.virtual.VirtualNetworkListener;
import org.onosproject.incubator.net.virtual.VirtualNetworkService;
import org.onosproject.incubator.net.virtual.VirtualPort;
@@ -46,6 +48,12 @@
import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
import org.onosproject.net.TestDeviceParams;
+import org.onosproject.net.intent.FakeIntentManager;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentState;
+import org.onosproject.net.intent.Key;
+import org.onosproject.net.intent.MockIdGenerator;
+import org.onosproject.net.intent.TestableIntentService;
import org.onosproject.store.service.TestStorageService;
import java.util.Collection;
@@ -54,6 +62,7 @@
import java.util.concurrent.atomic.AtomicLong;
import static org.junit.Assert.*;
+import static org.onosproject.net.NetTestTools.APP_ID;
/**
* Junit tests for VirtualNetworkManager.
@@ -67,10 +76,13 @@
private DistributedVirtualNetworkStore virtualNetworkManagerStore;
private CoreService coreService;
private TestListener listener = new TestListener();
+ private TestableIntentService intentService = new FakeIntentManager();
+ private IdGenerator idGenerator = new MockIdGenerator();
@Before
public void setUp() throws Exception {
virtualNetworkManagerStore = new DistributedVirtualNetworkStore();
+ Intent.bindIdGenerator(idGenerator);
coreService = new TestCoreService();
virtualNetworkManagerStore.setCoreService(coreService);
@@ -81,6 +93,7 @@
manager = new VirtualNetworkManager();
manager.store = virtualNetworkManagerStore;
manager.addListener(listener);
+ manager.intentService = intentService;
NetTestTools.injectEventDispatcher(manager, new TestEventDispatcher());
manager.activate();
virtualNetworkManagerService = manager;
@@ -92,6 +105,7 @@
manager.removeListener(listener);
manager.deactivate();
NetTestTools.injectEventDispatcher(manager, null);
+ Intent.unbindIdGenerator(idGenerator);
}
/**
@@ -377,6 +391,95 @@
}
/**
+ * Tests the addOrUpdateIntent() method in the store with a null intent.
+ */
+ @Test(expected = NullPointerException.class)
+ public void testAddOrUpdateNullIntent() {
+ manager.store.addOrUpdateIntent(null, null);
+ }
+
+ /**
+ * Tests the removeIntent() method in the store with a null intent key.
+ */
+ @Test(expected = NullPointerException.class)
+ public void testRemoveNullIntentKey() {
+ manager.store.removeIntent(null);
+ }
+
+ /**
+ * Tests the addOrUpdateIntent(), getIntents(), getIntent(), removeIntent() methods with the store.
+ */
+ @Test
+ public void testAddOrUpdateIntent() {
+ manager.registerTenantId(TenantId.tenantId(tenantIdValue1));
+ VirtualNetwork virtualNetwork = manager.createVirtualNetwork(TenantId.tenantId(tenantIdValue1));
+ ConnectPoint cp1 = new ConnectPoint(DID1, P1);
+ ConnectPoint cp2 = new ConnectPoint(DID2, P1);
+
+ VirtualNetworkIntent virtualIntent = VirtualNetworkIntent.builder()
+ .networkId(virtualNetwork.id())
+ .key(Key.of("Test", APP_ID))
+ .appId(APP_ID)
+ .ingressPoint(cp1)
+ .egressPoint(cp2)
+ .build();
+
+ // Add the intent to the store.
+ manager.store.addOrUpdateIntent(virtualIntent, IntentState.INSTALL_REQ);
+ assertEquals("The intent size should match.", 1, manager.store.getIntents().size());
+ assertNotNull("The intent should not be null.", manager.store.getIntent(virtualIntent.key()));
+
+ // remove the intent from the store.
+ manager.store.removeIntent(virtualIntent.key());
+ assertTrue("The intents should be empty.", manager.store.getIntents().isEmpty());
+ assertNull("The intent should be null.", manager.store.getIntent(virtualIntent.key()));
+ }
+
+ /**
+ * Tests the addTunnelId() method in the store with a null intent.
+ */
+ @Test(expected = NullPointerException.class)
+ public void testAddTunnelIdNullIntent() {
+ manager.store.addTunnelId(null, null);
+ }
+
+ /**
+ * Tests the removeTunnelId() method in the store with a null intent.
+ */
+ @Test(expected = NullPointerException.class)
+ public void testRemoveTunnelIdNullIntent() {
+ manager.store.removeTunnelId(null, null);
+ }
+
+ /**
+ * Tests the addTunnelId, getTunnelIds(), removeTunnelId() methods with the store.
+ */
+ @Test
+ public void testAddTunnelId() {
+ manager.registerTenantId(TenantId.tenantId(tenantIdValue1));
+ VirtualNetwork virtualNetwork = manager.createVirtualNetwork(TenantId.tenantId(tenantIdValue1));
+ ConnectPoint cp1 = new ConnectPoint(DID1, P1);
+ ConnectPoint cp2 = new ConnectPoint(DID2, P1);
+
+ VirtualNetworkIntent virtualIntent = VirtualNetworkIntent.builder()
+ .networkId(virtualNetwork.id())
+ .key(Key.of("Test", APP_ID))
+ .appId(APP_ID)
+ .ingressPoint(cp1)
+ .egressPoint(cp2)
+ .build();
+
+ TunnelId tunnelId = TunnelId.valueOf("virtual tunnel");
+ // Add the intent to tunnelID mapping to the store.
+ manager.store.addTunnelId(virtualIntent, tunnelId);
+ assertEquals("The tunnels size should match.", 1, manager.store.getTunnelIds(virtualIntent).size());
+
+ // Remove the intent to tunnelID mapping from the store.
+ manager.store.removeTunnelId(virtualIntent, tunnelId);
+ assertTrue("The tunnels should be empty.", manager.store.getTunnelIds(virtualIntent).isEmpty());
+ }
+
+ /**
* Method to validate that the actual versus expected virtual network events were
* received correctly.
*
diff --git a/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkTopologyServiceTest.java b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkTopologyServiceTest.java
index d199723..802bc0f 100644
--- a/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkTopologyServiceTest.java
+++ b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkTopologyServiceTest.java
@@ -38,6 +38,8 @@
import org.onosproject.net.Path;
import org.onosproject.net.PortNumber;
import org.onosproject.net.TestDeviceParams;
+import org.onosproject.net.intent.FakeIntentManager;
+import org.onosproject.net.intent.TestableIntentService;
import org.onosproject.net.topology.LinkWeight;
import org.onosproject.net.topology.Topology;
import org.onosproject.net.topology.TopologyCluster;
@@ -62,6 +64,7 @@
private VirtualNetworkManager manager;
private DistributedVirtualNetworkStore virtualNetworkManagerStore;
private CoreService coreService;
+ private TestableIntentService intentService = new FakeIntentManager();
@Before
public void setUp() throws Exception {
@@ -75,6 +78,7 @@
manager = new VirtualNetworkManager();
manager.store = virtualNetworkManagerStore;
+ manager.intentService = intentService;
NetTestTools.injectEventDispatcher(manager, new TestEventDispatcher());
manager.activate();
}
diff --git a/incubator/store/src/main/java/org/onosproject/incubator/store/virtual/impl/DistributedVirtualNetworkStore.java b/incubator/store/src/main/java/org/onosproject/incubator/store/virtual/impl/DistributedVirtualNetworkStore.java
index a9b5ac0..eb4e8b3 100644
--- a/incubator/store/src/main/java/org/onosproject/incubator/store/virtual/impl/DistributedVirtualNetworkStore.java
+++ b/incubator/store/src/main/java/org/onosproject/incubator/store/virtual/impl/DistributedVirtualNetworkStore.java
@@ -42,6 +42,7 @@
import org.onosproject.incubator.net.virtual.VirtualLink;
import org.onosproject.incubator.net.virtual.VirtualNetwork;
import org.onosproject.incubator.net.virtual.VirtualNetworkEvent;
+import org.onosproject.incubator.net.virtual.VirtualNetworkIntent;
import org.onosproject.incubator.net.virtual.VirtualNetworkService;
import org.onosproject.incubator.net.virtual.VirtualNetworkStore;
import org.onosproject.incubator.net.virtual.VirtualNetworkStoreDelegate;
@@ -54,6 +55,10 @@
import org.onosproject.net.Link;
import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentData;
+import org.onosproject.net.intent.IntentState;
+import org.onosproject.net.intent.Key;
import org.onosproject.store.AbstractStore;
import org.onosproject.store.serializers.KryoNamespaces;
import org.onosproject.store.service.ConsistentMap;
@@ -64,6 +69,7 @@
import org.onosproject.store.service.SetEvent;
import org.onosproject.store.service.SetEventListener;
import org.onosproject.store.service.StorageService;
+import org.onosproject.store.service.WallClockTimestamp;
import org.slf4j.Logger;
import java.util.HashSet;
@@ -134,6 +140,14 @@
private ConsistentMap<NetworkId, Set<VirtualPort>> networkIdVirtualPortSetConsistentMap;
private Map<NetworkId, Set<VirtualPort>> networkIdVirtualPortSetMap;
+ // Track intent key to intent data
+ private ConsistentMap<Key, IntentData> intentKeyIntentDataConsistentMap;
+ private Map<Key, IntentData> intentKeyIntentDataMap;
+
+ // Track intent ID to TunnelIds
+ private ConsistentMap<Key, Set<TunnelId>> intentKeyTunnelIdSetConsistentMap;
+ private Map<Key, Set<TunnelId>> intentKeyTunnelIdSetMap;
+
private static final Serializer SERIALIZER = Serializer
.using(new KryoNamespace.Builder().register(KryoNamespaces.API)
.register(TenantId.class)
@@ -150,8 +164,11 @@
.register(DefaultVirtualPort.class)
.register(Device.class)
.register(TunnelId.class)
+ .register(IntentData.class)
+ .register(VirtualNetworkIntent.class)
+ .register(WallClockTimestamp.class)
.nextId(KryoNamespaces.BEGIN_USER_CUSTOM_ID)
- .build("VirtualNetworkStore"));
+ .build());
/**
* Distributed network store service activate method.
@@ -220,11 +237,25 @@
networkIdVirtualPortSetConsistentMap = storageService.<NetworkId, Set<VirtualPort>>consistentMapBuilder()
.withSerializer(SERIALIZER)
- .withName("onos-networkId-virtualportss")
+ .withName("onos-networkId-virtualports")
.withRelaxedReadConsistency()
.build();
networkIdVirtualPortSetMap = networkIdVirtualPortSetConsistentMap.asJavaMap();
+ intentKeyTunnelIdSetConsistentMap = storageService.<Key, Set<TunnelId>>consistentMapBuilder()
+ .withSerializer(SERIALIZER)
+ .withName("onos-intentKey-tunnelIds")
+ .withRelaxedReadConsistency()
+ .build();
+ intentKeyTunnelIdSetMap = intentKeyTunnelIdSetConsistentMap.asJavaMap();
+
+ intentKeyIntentDataConsistentMap = storageService.<Key, IntentData>consistentMapBuilder()
+ .withSerializer(SERIALIZER)
+ .withName("onos-intentKey-intentData")
+ .withRelaxedReadConsistency()
+ .build();
+ intentKeyIntentDataMap = intentKeyIntentDataConsistentMap.asJavaMap();
+
log.info("Started");
}
@@ -607,6 +638,85 @@
return ImmutableSet.copyOf(portSet);
}
+ @Override
+ public synchronized void addOrUpdateIntent(Intent intent, IntentState state) {
+ checkNotNull(intent, "Intent cannot be null");
+ IntentData intentData = removeIntent(intent.key());
+ if (intentData == null) {
+ intentData = new IntentData(intent, state, new WallClockTimestamp(System.currentTimeMillis()));
+ } else {
+ intentData = new IntentData(intent, state, intentData.version());
+ }
+ intentKeyIntentDataMap.put(intent.key(), intentData);
+ }
+
+ @Override
+ public IntentData removeIntent(Key intentKey) {
+ checkNotNull(intentKey, "Intent key cannot be null");
+ return intentKeyIntentDataMap.remove(intentKey);
+ }
+
+ @Override
+ public void addTunnelId(Intent intent, TunnelId tunnelId) {
+ // Add the tunnelId to the intent key set map
+ Set<TunnelId> tunnelIdSet = intentKeyTunnelIdSetMap.remove(intent.key());
+ if (tunnelIdSet == null) {
+ tunnelIdSet = new HashSet<>();
+ }
+ tunnelIdSet.add(tunnelId);
+ intentKeyTunnelIdSetMap.put(intent.key(), tunnelIdSet);
+ }
+
+ @Override
+ public Set<TunnelId> getTunnelIds(Intent intent) {
+ Set<TunnelId> tunnelIdSet = intentKeyTunnelIdSetMap.get(intent.key());
+ return tunnelIdSet == null ? new HashSet<TunnelId>() : ImmutableSet.copyOf(tunnelIdSet);
+ }
+
+ @Override
+ public void removeTunnelId(Intent intent, TunnelId tunnelId) {
+ Set<TunnelId> tunnelIdSet = new HashSet<>();
+ intentKeyTunnelIdSetMap.get(intent.key()).forEach(tunnelId1 -> {
+ if (tunnelId1.equals(tunnelId)) {
+ tunnelIdSet.add(tunnelId);
+ }
+ });
+
+ if (!tunnelIdSet.isEmpty()) {
+ intentKeyTunnelIdSetMap.compute(intent.key(), (key, existingTunnelIds) -> {
+ if (existingTunnelIds == null || existingTunnelIds.isEmpty()) {
+ return new HashSet<>();
+ } else {
+ return new HashSet<>(Sets.difference(existingTunnelIds, tunnelIdSet));
+ }
+ });
+ }
+ }
+
+ @Override
+ public Set<Intent> getIntents() {
+ Set<Intent> intents = new HashSet<>();
+ intentKeyIntentDataMap.values().forEach(intentData -> intents.add(intentData.intent()));
+ return ImmutableSet.copyOf(intents);
+ }
+
+ @Override
+ public Intent getIntent(Key key) {
+ IntentData intentData = intentKeyIntentDataMap.get(key);
+ return intentData == null ? null : intentData.intent();
+ }
+
+ @Override
+ public Set<IntentData> getIntentData() {
+ return ImmutableSet.copyOf(intentKeyIntentDataMap.values());
+ }
+
+ @Override
+ public IntentData getIntentData(Key key) {
+ IntentData intentData = intentKeyIntentDataMap.get(key);
+ return intentData == null ? null : new IntentData(intentData);
+ }
+
/**
* Listener class to map listener set events to the virtual network events.
*/