ONOS-2184 - Initial implementation of Virtual network Intent service.

Change-Id: I03103b4eca797cd32480fbd0e3b4cf0385b50ef2
diff --git a/cli/BUCK b/cli/BUCK
index d2333d0..d00ee98 100644
--- a/cli/BUCK
+++ b/cli/BUCK
@@ -2,6 +2,7 @@
     '//lib:CORE_DEPS',
     '//lib:org.apache.karaf.shell.console',
     '//incubator/api:onos-incubator-api',
+    '//incubator/net:onos-incubator-net',
     '//utils/rest:onlab-rest',
     '//core/common:onos-core-common',
 ]
diff --git a/cli/src/main/java/org/onosproject/cli/net/vnet/VirtualNetworkIntentCreateCommand.java b/cli/src/main/java/org/onosproject/cli/net/vnet/VirtualNetworkIntentCreateCommand.java
new file mode 100644
index 0000000..8107cd0
--- /dev/null
+++ b/cli/src/main/java/org/onosproject/cli/net/vnet/VirtualNetworkIntentCreateCommand.java
@@ -0,0 +1,82 @@
+/*
+ * 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.cli.net.vnet;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.net.ConnectivityIntentCommand;
+import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.incubator.net.virtual.VirtualNetworkIntent;
+import org.onosproject.incubator.net.virtual.VirtualNetworkService;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.intent.Constraint;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentService;
+
+import java.util.List;
+
+/**
+ * Installs virtual network intents.
+ */
+@Command(scope = "onos", name = "add-vnet-intent",
+        description = "Installs virtual network connectivity intent")
+public class VirtualNetworkIntentCreateCommand extends ConnectivityIntentCommand {
+
+    @Argument(index = 0, name = "networkId", description = "Network ID",
+            required = true, multiValued = false)
+    Long networkId = null;
+
+    @Argument(index = 1, name = "ingressDevice",
+            description = "Ingress Device/Port Description",
+            required = true, multiValued = false)
+    String ingressDeviceString = null;
+
+    @Argument(index = 2, name = "egressDevice",
+            description = "Egress Device/Port Description",
+            required = true, multiValued = false)
+    String egressDeviceString = null;
+
+    @Override
+    protected void execute() {
+        VirtualNetworkService service = get(VirtualNetworkService.class);
+        IntentService virtualNetworkIntentService = service.get(NetworkId.networkId(networkId), IntentService.class);
+
+        ConnectPoint ingress = ConnectPoint.deviceConnectPoint(ingressDeviceString);
+        ConnectPoint egress = ConnectPoint.deviceConnectPoint(egressDeviceString);
+
+        TrafficSelector selector = buildTrafficSelector();
+        TrafficTreatment treatment = buildTrafficTreatment();
+
+        List<Constraint> constraints = buildConstraints();
+
+        Intent intent = VirtualNetworkIntent.builder()
+                .networkId(NetworkId.networkId(networkId))
+                .appId(appId())
+                .key(key())
+                .selector(selector)
+                .treatment(treatment)
+                .ingressPoint(ingress)
+                .egressPoint(egress)
+                .constraints(constraints)
+                .priority(priority())
+                .build();
+        virtualNetworkIntentService.submit(intent);
+        print("Virtual intent submitted:\n%s", intent.toString());
+    }
+}
diff --git a/cli/src/main/java/org/onosproject/cli/net/vnet/VirtualNetworkIntentRemoveCommand.java b/cli/src/main/java/org/onosproject/cli/net/vnet/VirtualNetworkIntentRemoveCommand.java
new file mode 100644
index 0000000..08effbc
--- /dev/null
+++ b/cli/src/main/java/org/onosproject/cli/net/vnet/VirtualNetworkIntentRemoveCommand.java
@@ -0,0 +1,186 @@
+/*
+ * 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.cli.net.vnet;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.apache.karaf.shell.commands.Option;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.incubator.net.virtual.VirtualNetworkService;
+import org.onosproject.net.intent.Intent;
+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.intent.Key;
+
+import java.math.BigInteger;
+import java.util.EnumSet;
+import java.util.Objects;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import static com.google.common.base.Strings.isNullOrEmpty;
+import static org.onosproject.net.intent.IntentState.FAILED;
+import static org.onosproject.net.intent.IntentState.WITHDRAWN;
+
+/**
+ * Removes a virtual network intent.
+ */
+@Command(scope = "onos", name = "remove-vnet-intent",
+        description = "Removes the virtual network intent")
+public class VirtualNetworkIntentRemoveCommand extends AbstractShellCommand {
+
+    @Argument(index = 0, name = "networkId", description = "Network ID",
+            required = true, multiValued = false)
+    Long networkId = null;
+
+    @Argument(index = 1, name = "app",
+            description = "Application ID",
+            required = false, multiValued = false)
+    String applicationIdString = null;
+
+    @Argument(index = 2, name = "key",
+            description = "Intent Key",
+            required = false, multiValued = false)
+    String keyString = null;
+
+    @Option(name = "-p", aliases = "--purge",
+            description = "Purge the intent from the store after removal",
+            required = false, multiValued = false)
+    private boolean purgeAfterRemove = false;
+
+    @Option(name = "-s", aliases = "--sync",
+            description = "Waits for the removal before returning",
+            required = false, multiValued = false)
+    private boolean sync = false;
+
+    private static final EnumSet<IntentState> CAN_PURGE = EnumSet.of(WITHDRAWN, FAILED);
+
+    @Override
+    protected void execute() {
+        VirtualNetworkService service = get(VirtualNetworkService.class);
+        IntentService intentService = service.get(NetworkId.networkId(networkId), IntentService.class);
+        CoreService coreService = get(CoreService.class);
+
+        if (purgeAfterRemove || sync) {
+            print("Using \"sync\" to remove/purge intents - this may take a while...");
+            print("Check \"summary\" to see remove/purge progress.");
+        }
+
+        ApplicationId appId = appId();
+        if (!isNullOrEmpty(applicationIdString)) {
+            appId = coreService.getAppId(applicationIdString);
+            if (appId == null) {
+                print("Cannot find application Id %s", applicationIdString);
+                return;
+            }
+        }
+
+        if (isNullOrEmpty(keyString)) {
+            for (Intent intent : intentService.getIntents()) {
+                if (intent.appId().equals(appId)) {
+                    removeIntent(intentService, intent);
+                }
+            }
+
+        } else {
+            final Key key;
+            if (keyString.startsWith("0x")) {
+                // The intent uses a LongKey
+                keyString = keyString.replaceFirst("0x", "");
+                key = Key.of(new BigInteger(keyString, 16).longValue(), appId);
+            } else {
+                // The intent uses a StringKey
+                key = Key.of(keyString, appId);
+            }
+
+            Intent intent = intentService.getIntent(key);
+            if (intent != null) {
+                removeIntent(intentService, intent);
+            } else {
+                print("Intent not found!");
+            }
+        }
+    }
+
+    /**
+     * Removes the intent using the specified intentService.
+     *
+     * @param intentService intent service
+     * @param intent        intent
+     */
+    private void removeIntent(IntentService intentService, Intent intent) {
+        IntentListener listener = null;
+        Key key = intent.key();
+        final CountDownLatch withdrawLatch, purgeLatch;
+        if (purgeAfterRemove || sync) {
+            // set up latch and listener to track uninstall progress
+            withdrawLatch = new CountDownLatch(1);
+            purgeLatch = purgeAfterRemove ? new CountDownLatch(1) : null;
+            listener = (IntentEvent event) -> {
+                if (Objects.equals(event.subject().key(), key)) {
+                    if (event.type() == IntentEvent.Type.WITHDRAWN ||
+                            event.type() == IntentEvent.Type.FAILED) {
+                        withdrawLatch.countDown();
+                    } else if (purgeAfterRemove &&
+                            event.type() == IntentEvent.Type.PURGED) {
+                        purgeLatch.countDown();
+                    }
+                }
+            };
+            intentService.addListener(listener);
+        } else {
+            purgeLatch = null;
+            withdrawLatch = null;
+        }
+
+        // request the withdraw
+        intentService.withdraw(intent);
+
+        if (purgeAfterRemove || sync) {
+            try { // wait for withdraw event
+                withdrawLatch.await(5, TimeUnit.SECONDS);
+            } catch (InterruptedException e) {
+                print("Timed out waiting for intent {} withdraw", key);
+            }
+            if (purgeAfterRemove && CAN_PURGE.contains(intentService.getIntentState(key))) {
+                intentService.purge(intent);
+                if (sync) { // wait for purge event
+                    /* TODO
+                       Technically, the event comes before map.remove() is called.
+                       If we depend on sync and purge working together, we will
+                       need to address this.
+                    */
+                    try {
+                        purgeLatch.await(5, TimeUnit.SECONDS);
+                    } catch (InterruptedException e) {
+                        print("Timed out waiting for intent {} purge", key);
+                    }
+                }
+            }
+        }
+
+        if (listener != null) {
+            // clean up the listener
+            intentService.removeListener(listener);
+        }
+    }
+}
diff --git a/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
index 92da929..6ea9077 100644
--- a/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
+++ b/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -683,6 +683,12 @@
         <command>
             <action class="org.onosproject.cli.net.vnet.VirtualHostRemoveCommand"/>
         </command>
+        <command>
+            <action class="org.onosproject.cli.net.vnet.VirtualNetworkIntentCreateCommand"/>
+        </command>
+        <command>
+            <action class="org.onosproject.cli.net.vnet.VirtualNetworkIntentRemoveCommand"/>
+        </command>
     </command-bundle>
 
     <bean id="reviewAppNameCompleter" class="org.onosproject.cli.security.ReviewApplicationNameCompleter"/>
diff --git a/core/api/src/test/java/org/onosproject/net/intent/FakeIntentManager.java b/core/api/src/test/java/org/onosproject/net/intent/FakeIntentManager.java
index d5b88a4..1ceb3b2 100644
--- a/core/api/src/test/java/org/onosproject/net/intent/FakeIntentManager.java
+++ b/core/api/src/test/java/org/onosproject/net/intent/FakeIntentManager.java
@@ -155,7 +155,6 @@
 
     @Override
     public void withdraw(Intent intent) {
-        intents.remove(intent.key());
         executeWithdraw(intent);
     }
 
@@ -167,6 +166,7 @@
             intents.remove(intent.key());
             installables.remove(intent.key());
             intentStates.remove(intent.key());
+            dispatch(new IntentEvent(IntentEvent.Type.PURGED, intent));
         }
     }
 
diff --git a/core/net/BUCK b/core/net/BUCK
index 7070fb7..fa93865 100644
--- a/core/net/BUCK
+++ b/core/net/BUCK
@@ -1,9 +1,13 @@
 COMPILE_DEPS = [
     '//lib:CORE_DEPS',
     '//incubator/api:onos-incubator-api',
+    '//utils/rest:onlab-rest',
+    '//incubator/net:onos-incubator-net',
+    '//incubator/store:onos-incubator-store',
 ]
 
 TEST_DEPS = [
+    '//lib:TEST_REST',
     '//lib:TEST_ADAPTERS',
     '//core/common:onos-core-common',
     '//core/store/dist:onos-core-dist',
diff --git a/core/net/pom.xml b/core/net/pom.xml
index eb6f1b7..1d3650b 100644
--- a/core/net/pom.xml
+++ b/core/net/pom.xml
@@ -93,6 +93,14 @@
 
         <dependency>
             <groupId>org.onosproject</groupId>
+            <artifactId>onlab-osgi</artifactId>
+            <version>${project.version}</version>
+            <classifier>tests</classifier>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
             <artifactId>onos-incubator-api</artifactId>
         </dependency>
 
@@ -110,6 +118,17 @@
             <groupId>org.apache.felix</groupId>
             <artifactId>org.apache.felix.scr</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-incubator-store</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-incubator-net</artifactId>
+            <version>${project.version}</version>
+        </dependency>
     </dependencies>
 
 </project>
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/VirtualNetworkIntentCompiler.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/VirtualNetworkIntentCompiler.java
new file mode 100644
index 0000000..04f42e5
--- /dev/null
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/VirtualNetworkIntentCompiler.java
@@ -0,0 +1,189 @@
+/*
+ * 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.net.intent.impl.compiler;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onlab.osgi.DefaultServiceDirectory;
+import org.onlab.osgi.ServiceDirectory;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.incubator.net.tunnel.TunnelId;
+import org.onosproject.incubator.net.virtual.NetworkId;
+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.EncapsulationType;
+import org.onosproject.net.Link;
+import org.onosproject.net.Path;
+import org.onosproject.net.intent.Constraint;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentService;
+import org.onosproject.net.intent.Key;
+import org.onosproject.net.intent.PointToPointIntent;
+import org.onosproject.net.intent.constraint.EncapsulationConstraint;
+import org.onosproject.net.intent.impl.IntentCompilationException;
+import org.onosproject.net.topology.TopologyService;
+import org.slf4j.Logger;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * An intent compiler for {@link org.onosproject.incubator.net.virtual.VirtualNetworkIntent}.
+ */
+@Component(immediate = true)
+public class VirtualNetworkIntentCompiler
+        extends ConnectivityIntentCompiler<VirtualNetworkIntent> {
+
+    private final Logger log = getLogger(getClass());
+
+    private static final String NETWORK_ID = "networkId=";
+    protected static final String KEY_FORMAT = "{" + NETWORK_ID + "%s, src=%s, dst=%s}";
+
+    protected ServiceDirectory serviceDirectory = new DefaultServiceDirectory();
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected VirtualNetworkService manager;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected IntentService intentService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected VirtualNetworkStore store;
+
+
+    @Activate
+    public void activate() {
+        intentManager.registerCompiler(VirtualNetworkIntent.class, this);
+    }
+
+    @Deactivate
+    public void deactivate() {
+        intentManager.unregisterCompiler(VirtualNetworkIntent.class);
+    }
+
+    @Override
+    public List<Intent> compile(VirtualNetworkIntent intent, List<Intent> installable) {
+
+        log.debug("Compiling intent: " + intent);
+        List<Intent> intents = new ArrayList<>();
+        Optional<Path> path = getPaths(intent).stream()
+                .findFirst();
+        if (path != null && path.isPresent()) {
+            path.get().links().forEach(link -> {
+                Intent physicalIntent = createPtPtIntent(intent, link);
+                intents.add(physicalIntent);
+
+                // store the virtual intent to physical intent tunnelId mapping
+                store.addTunnelId(intent, TunnelId.valueOf(physicalIntent.key().toString()));
+            });
+        } else {
+            throw new IntentCompilationException("Unable to find a path for intent " + intent);
+        }
+
+        return intents;
+    }
+
+    /**
+     * Returns the paths for the virtual network intent.
+     *
+     * @param intent virtual network intent
+     * @return set of paths
+     */
+    private Set<Path> getPaths(VirtualNetworkIntent intent) {
+
+        TopologyService topologyService = manager.get(intent.networkId(), TopologyService.class);
+        if (topologyService == null) {
+            throw new IntentCompilationException("topologyService is null");
+        }
+        return topologyService.getPaths(topologyService.currentTopology(),
+                                        intent.ingressPoint().deviceId(), intent.egressPoint().deviceId());
+    }
+
+    /**
+     * Encodes the key using the network identifier, application identifer, source and destination
+     * connect points.
+     *
+     * @param networkId     virtual network identifier
+     * @param applicationId application identifier
+     * @param src           source connect point
+     * @param dst           destination connect point
+     * @return encoded key
+     */
+    private static Key encodeKey(NetworkId networkId, ApplicationId applicationId, ConnectPoint src, ConnectPoint dst) {
+        String key = String.format(KEY_FORMAT, networkId, src, dst);
+        return Key.of(key, applicationId);
+    }
+
+    /**
+     * Creates a point-to-point intent from the virtual network intent and virtual link.
+     *
+     * @param intent virtual network intent
+     * @param link   virtual link
+     * @return point to point intent
+     */
+    private Intent createPtPtIntent(VirtualNetworkIntent intent, Link link) {
+        ConnectPoint ingressPoint = mapVirtualToPhysicalPort(intent.networkId(), link.src());
+        ConnectPoint egressPoint = mapVirtualToPhysicalPort(intent.networkId(), link.dst());
+        Key intentKey = encodeKey(intent.networkId(), intent.appId(), ingressPoint, egressPoint);
+
+        List<Constraint> constraints = new ArrayList<>();
+        constraints.add(new EncapsulationConstraint(EncapsulationType.VLAN));
+
+        // TODO Currently there can only be one intent between the ingress and egress across
+        // all virtual networks. We may want to support multiple intents between the same src/dst pairs.
+        PointToPointIntent physicalIntent = PointToPointIntent.builder()
+                .key(intentKey)
+                .appId(intent.appId())
+                .ingressPoint(ingressPoint)
+                .egressPoint(egressPoint)
+                .constraints(constraints)
+                .build();
+        log.debug("Submitting physical intent: " + physicalIntent);
+        intentService.submit(physicalIntent);
+
+        return physicalIntent;
+    }
+
+    /**
+     * Maps the virtual connect point to a physical connect point.
+     *
+     * @param networkId virtual network identifier
+     * @param virtualCp virtual connect point
+     * @return physical connect point
+     */
+    private ConnectPoint mapVirtualToPhysicalPort(NetworkId networkId, ConnectPoint virtualCp) {
+        Set<VirtualPort> ports = manager.getVirtualPorts(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;
+    }
+}
+
diff --git a/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/VirtualNetworkIntentCompilerTest.java b/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/VirtualNetworkIntentCompilerTest.java
new file mode 100644
index 0000000..137d2e0
--- /dev/null
+++ b/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/VirtualNetworkIntentCompilerTest.java
@@ -0,0 +1,239 @@
+/*
+ * 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.net.intent.impl.compiler;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+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.VirtualNetworkService;
+import org.onosproject.incubator.net.virtual.VirtualNetworkStore;
+import org.onosproject.incubator.net.virtual.impl.VirtualNetworkManager;
+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.Intent;
+import org.onosproject.net.intent.IntentExtensionService;
+import org.onosproject.net.intent.IntentService;
+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.atomic.AtomicLong;
+
+import static org.junit.Assert.assertEquals;
+import static org.onlab.junit.TestUtils.TestUtilsException;
+import static org.onlab.junit.TestUtils.setField;
+
+/**
+ * Junit tests for virtual network intent compiler.
+ */
+public class VirtualNetworkIntentCompilerTest extends TestDeviceParams {
+
+    private CoreService coreService;
+    private TestableIntentService intentService = new FakeIntentManager();
+    private IntentExtensionService intentExtensionService;
+    private final IdGenerator idGenerator = new MockIdGenerator();
+    private VirtualNetworkIntentCompiler compiler;
+    private VirtualNetworkManager manager;
+    private DistributedVirtualNetworkStore virtualNetworkManagerStore;
+    private ServiceDirectory testDirectory;
+
+    private final String tenantIdValue1 = "TENANT_ID1";
+    private static final ApplicationId APP_ID =
+            new TestApplicationId("test");
+
+    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;
+
+    @Before
+    public void setUp() throws TestUtilsException {
+        virtualNetworkManagerStore = new DistributedVirtualNetworkStore();
+
+        coreService = new TestCoreService();
+
+        Intent.unbindIdGenerator(idGenerator);
+        Intent.bindIdGenerator(idGenerator);
+
+        virtualNetworkManagerStore.setCoreService(coreService);
+        setField(coreService, "coreService", new TestCoreService());
+        setField(virtualNetworkManagerStore, "storageService", new TestStorageService());
+        virtualNetworkManagerStore.activate();
+
+        manager = new VirtualNetworkManager();
+        manager.setStore(virtualNetworkManagerStore);
+        manager.setIntentService(intentService);
+        NetTestTools.injectEventDispatcher(manager, new TestEventDispatcher());
+        manager.activate();
+
+        // Register a compiler and an installer both setup for success.
+        intentExtensionService = intentService;
+
+        testDirectory = new TestServiceDirectory()
+                .add(VirtualNetworkService.class, manager)
+                .add(VirtualNetworkStore.class, virtualNetworkManagerStore)
+                .add(IntentService.class, intentService);
+        BaseResource.setServiceDirectory(testDirectory);
+
+        compiler = new VirtualNetworkIntentCompiler();
+        compiler.manager = manager;
+        compiler.intentService = intentService;
+        compiler.store = virtualNetworkManagerStore;
+        compiler.intentManager = intentExtensionService;
+        compiler.serviceDirectory = testDirectory;
+    }
+
+    @After
+    public void tearDown() {
+        Intent.unbindIdGenerator(idGenerator);
+        manager.deactivate();
+    }
+
+    /**
+     * 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);
+
+        return virtualNetwork;
+    }
+
+    @Test
+    public void testCompiler() {
+        compiler.activate();
+        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();
+
+        List<Intent> compiled = compiler.compile(virtualIntent, Collections.emptyList());
+        assertEquals("The virtual intents size is not as expected.", 2, compiled.size());
+
+        compiler.deactivate();
+    }
+
+
+    /**
+     * 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();
+                }
+            };
+        }
+    }
+
+}
diff --git a/core/store/dist/BUCK b/core/store/dist/BUCK
index 075612f..b5db3b8 100644
--- a/core/store/dist/BUCK
+++ b/core/store/dist/BUCK
@@ -9,6 +9,7 @@
     '//lib:netty-handler',
     '//lib:netty-transport-native-epoll',
     '//lib:commons-math3',
+    '//incubator/api:onos-incubator-api',
 ]
 
 TEST_DEPS = [
diff --git a/core/store/dist/src/main/java/org/onosproject/store/intent/impl/GossipIntentStore.java b/core/store/dist/src/main/java/org/onosproject/store/intent/impl/GossipIntentStore.java
index 57a86e4..2b46dbc 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/intent/impl/GossipIntentStore.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/intent/impl/GossipIntentStore.java
@@ -27,6 +27,8 @@
 import org.onosproject.cluster.ClusterService;
 import org.onosproject.cluster.ControllerNode;
 import org.onosproject.cluster.NodeId;
+import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.incubator.net.virtual.VirtualNetworkIntent;
 import org.onosproject.net.intent.Intent;
 import org.onosproject.net.intent.IntentData;
 import org.onosproject.net.intent.IntentEvent;
@@ -97,6 +99,8 @@
         KryoNamespace.Builder intentSerializer = KryoNamespace.newBuilder()
                 .register(KryoNamespaces.API)
                 .register(IntentData.class)
+                .register(VirtualNetworkIntent.class)
+                .register(NetworkId.class)
                 .register(MultiValuedTimestamp.class);
 
         currentMap = storageService.<Key, IntentData>eventuallyConsistentMapBuilder()
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.
      */
diff --git a/pom.xml b/pom.xml
index 72f8966..60eb440 100644
--- a/pom.xml
+++ b/pom.xml
@@ -142,6 +142,12 @@
 
             <dependency>
                 <groupId>org.onosproject</groupId>
+                <artifactId>onos-incubator-net</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.onosproject</groupId>
                 <artifactId>onos-core-common</artifactId>
                 <version>${project.version}</version>
             </dependency>