ONOS-3633 - Implementation of virtual network point to point intent provider.

Change-Id: Ie2c1e5ac278bc0dd6259479c44dd92b9b625e90b
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/tunnel/TunnelId.java b/incubator/api/src/main/java/org/onosproject/incubator/net/tunnel/TunnelId.java
index a06ab3a..74a3029 100644
--- a/incubator/api/src/main/java/org/onosproject/incubator/net/tunnel/TunnelId.java
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/tunnel/TunnelId.java
@@ -23,39 +23,35 @@
  * Representation of a Tunnel Id.
  */
 @Beta
-public final class TunnelId extends Identifier<Long> {
+public final class TunnelId extends Identifier<String> {
     /**
      * Creates an tunnel identifier from the specified tunnel.
      *
-     * @param value long value
+     * @param value string value
      * @return tunnel identifier
      */
-    public static TunnelId valueOf(long value) {
-        return new TunnelId(value);
-    }
-
     public static TunnelId valueOf(String value) {
-         return new TunnelId(Long.parseLong(value));
+        return new TunnelId(value);
     }
 
     /**
      * Constructor for serializer.
      */
     TunnelId() {
-        super(0L);
+        super("0");
     }
 
     /**
-     * Constructs the ID corresponding to a given long value.
+     * Constructs the ID corresponding to a given string value.
      *
      * @param value the underlying value of this ID
      */
-    TunnelId(long value) {
+    TunnelId(String value) {
         super(value);
     }
 
     @Override
     public String toString() {
-        return "0x" + Long.toHexString(identifier);
+        return id();
     }
 }
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/DefaultVirtualLink.java b/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/DefaultVirtualLink.java
index 2b86e98..ff42dcd 100644
--- a/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/DefaultVirtualLink.java
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/DefaultVirtualLink.java
@@ -25,27 +25,28 @@
 import java.util.Objects;
 
 import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
 
 /**
  * Default representation of a virtual link.
  */
 public final class DefaultVirtualLink extends DefaultLink implements VirtualLink {
 
-    private static final String VIRTUAL = "virtual";
-    private static final ProviderId PID = new ProviderId(VIRTUAL, VIRTUAL);
+    private static final String VIRTUAL = "virtualLink";
+    public static final ProviderId PID = new ProviderId(VIRTUAL, VIRTUAL);
 
     private final NetworkId networkId;
     private final TunnelId tunnelId;
 
     /**
-     * Constructor for a default virtual link.
+     * Private constructor for a default virtual link.
      *
      * @param networkId network identifier
      * @param src       source connection point
      * @param dst       destination connection point
      * @param tunnelId  tunnel identifier
      */
-    public DefaultVirtualLink(NetworkId networkId, ConnectPoint src, ConnectPoint dst, TunnelId tunnelId) {
+    private DefaultVirtualLink(NetworkId networkId, ConnectPoint src, ConnectPoint dst, TunnelId tunnelId) {
         super(PID, src, dst, Type.VIRTUAL, DefaultAnnotations.builder().build());
         this.networkId = networkId;
         this.tunnelId = tunnelId;
@@ -88,4 +89,84 @@
     public String toString() {
         return toStringHelper(this).add("networkId", networkId).add("tunnelId", tunnelId).toString();
     }
+
+    /**
+     * Creates a new default virtual link builder.
+     *
+     * @return default virtual link builder
+     */
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * Builder for DefaultVirtualLink objects.
+     */
+    public static final class Builder extends DefaultLink.Builder {
+        private NetworkId networkId;
+        private ConnectPoint src;
+        private ConnectPoint dst;
+        private TunnelId tunnelId;
+
+        private Builder() {
+            // Hide constructor
+        }
+
+        /**
+         * Sets the network identifier to be used by the builder.
+         *
+         * @param networkId network identifier
+         * @return self
+         */
+        public Builder networkId(NetworkId networkId) {
+            this.networkId = networkId;
+            return this;
+        }
+
+        /**
+         * Sets the source connect point to be used by the builder.
+         *
+         * @param src source connect point
+         * @return self
+         */
+        public Builder src(ConnectPoint src) {
+            this.src = src;
+            return this;
+        }
+
+        /**
+         * Sets the destination connect point to be used by the builder.
+         *
+         * @param dst new destination connect point
+         * @return self
+         */
+        public Builder dst(ConnectPoint dst) {
+            this.dst = dst;
+            return this;
+        }
+
+        /**
+         * Sets the tunnel identifier to be used by the builder.
+         *
+         * @param tunnelId tunnel identifier
+         * @return self
+         */
+        public Builder tunnelId(TunnelId tunnelId) {
+            this.tunnelId = tunnelId;
+            return this;
+        }
+
+        /**
+         * Builds a default virtual link object from the accumulated parameters.
+         *
+         * @return default virtual link object
+         */
+        public DefaultVirtualLink build() {
+            checkNotNull(src, "Source connect point cannot be null");
+            checkNotNull(dst, "Destination connect point cannot be null");
+            checkNotNull(networkId, "Network Id cannot be null");
+
+            return new DefaultVirtualLink(networkId, src, dst, tunnelId);
+        }
+    }
 }
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualLink.java b/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualLink.java
index ddccb1b..10177a7 100644
--- a/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualLink.java
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualLink.java
@@ -16,6 +16,7 @@
 package org.onosproject.incubator.net.virtual;
 
 import com.google.common.annotations.Beta;
+import org.onosproject.incubator.net.tunnel.TunnelId;
 import org.onosproject.net.Link;
 
 /**
@@ -23,4 +24,10 @@
  */
 @Beta
 public interface VirtualLink extends VirtualElement, Link {
+    /**
+     * Returns the tunnel identifier to which this virtual link belongs.
+     *
+     * @return tunnel identifier
+     */
+    TunnelId tunnelId();
 }
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkAdminService.java b/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkAdminService.java
index ef22644..c903e61 100644
--- a/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkAdminService.java
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkAdminService.java
@@ -16,7 +16,6 @@
 package org.onosproject.incubator.net.virtual;
 
 import com.google.common.annotations.Beta;
-import org.onosproject.incubator.net.tunnel.TunnelId;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.Port;
@@ -96,13 +95,11 @@
      * @param networkId  network identifier
      * @param src        source connection point
      * @param dst        destination connection point
-     * @param realizedBy identifier of the tunnel using which this link is realized
      * @return newly created virtual link
      * @throws org.onlab.util.ItemNotFoundException if no such network found
      */
     VirtualLink createVirtualLink(NetworkId networkId,
-                                  ConnectPoint src, ConnectPoint dst,
-                                  TunnelId realizedBy);
+                                  ConnectPoint src, ConnectPoint dst);
 
     // TODO: Discuss whether we should provide an alternate createVirtualLink
     // which is backed by a Path instead; I'm leaning towards not doing that.
@@ -121,11 +118,11 @@
      * Creates a new virtual port on the specified device.
      *
      * @param networkId  network identifier
-     * @param deviceId   device identifier
-     * @param portNumber port number
-     * @param realizedBy underlying port using which this virtual port is realized
+     * @param deviceId   virtual device identifier
+     * @param portNumber virtual port number
+     * @param realizedBy underlying physical port using which this virtual port is realized
      * @return newly created port
-     * @throws org.onlab.util.ItemNotFoundException if no such network or device found
+     * @throws org.onlab.util.ItemNotFoundException if no such network or device is found
      */
     VirtualPort createVirtualPort(NetworkId networkId, DeviceId deviceId,
                                   PortNumber portNumber, Port realizedBy);
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 218c77d..35fb0c3 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
@@ -89,11 +89,18 @@
      * @param networkId  network identifier
      * @param src        source end-point of the link
      * @param dst        destination end-point of the link
-     * @param realizedBy underlying tunnel using which this link is realized
+     * @param realizedBy underlying tunnel identifier using which this link is realized
      * @return the virtual link
      */
-    VirtualLink addLink(NetworkId networkId, ConnectPoint src, ConnectPoint dst,
-                        TunnelId realizedBy);
+    VirtualLink addLink(NetworkId networkId, ConnectPoint src, ConnectPoint dst, TunnelId realizedBy);
+
+    /**
+     * Updates the tunnelId in the virtual link.
+     *
+     * @param virtualLink  virtual link
+     * @param tunnelId tunnel identifier
+     */
+    void updateLink(VirtualLink virtualLink, TunnelId tunnelId);
 
     /**
      * Removes the specified link from the store.
@@ -101,8 +108,9 @@
      * @param networkId network identifier
      * @param src       source connection point
      * @param dst       destination connection point
+     * @return the virtual link
      */
-    void removeLink(NetworkId networkId, ConnectPoint src, ConnectPoint dst);
+    VirtualLink removeLink(NetworkId networkId, ConnectPoint src, ConnectPoint dst);
 
     /**
      * Adds a new virtual port to the network.
diff --git a/incubator/api/src/test/java/org/onosproject/incubator/net/tunnel/DefaultTunnelTest.java b/incubator/api/src/test/java/org/onosproject/incubator/net/tunnel/DefaultTunnelTest.java
index 2f5a570..e9aa30c 100644
--- a/incubator/api/src/test/java/org/onosproject/incubator/net/tunnel/DefaultTunnelTest.java
+++ b/incubator/api/src/test/java/org/onosproject/incubator/net/tunnel/DefaultTunnelTest.java
@@ -44,7 +44,7 @@
                 .valueOf(32421));
         DefaultGroupId groupId = new DefaultGroupId(92034);
         TunnelName tunnelName = TunnelName.tunnelName("TunnelName");
-        TunnelId tunnelId = TunnelId.valueOf(41654654);
+        TunnelId tunnelId = TunnelId.valueOf("41654654");
         ProviderId producerName1 = new ProviderId("producer1", "13");
         ProviderId producerName2 = new ProviderId("producer2", "13");
         Tunnel p1 = new DefaultTunnel(producerName1, src, dst, Tunnel.Type.VXLAN,
diff --git a/incubator/api/src/test/java/org/onosproject/incubator/net/tunnel/TunnelEventTest.java b/incubator/api/src/test/java/org/onosproject/incubator/net/tunnel/TunnelEventTest.java
index 307dc50..c38f755 100644
--- a/incubator/api/src/test/java/org/onosproject/incubator/net/tunnel/TunnelEventTest.java
+++ b/incubator/api/src/test/java/org/onosproject/incubator/net/tunnel/TunnelEventTest.java
@@ -48,7 +48,7 @@
                 .valueOf(32421));
         DefaultGroupId groupId = new DefaultGroupId(92034);
         TunnelName tunnelName = TunnelName.tunnelName("TunnelName");
-        TunnelId tunnelId = TunnelId.valueOf(41654654);
+        TunnelId tunnelId = TunnelId.valueOf("41654654");
         ProviderId producerName1 = new ProviderId("producer1", "13");
         Tunnel p1 = new DefaultTunnel(producerName1, src, dst, Tunnel.Type.VXLAN,
                                       Tunnel.State.ACTIVE, groupId, tunnelId,
diff --git a/incubator/api/src/test/java/org/onosproject/incubator/net/tunnel/TunnelIdTest.java b/incubator/api/src/test/java/org/onosproject/incubator/net/tunnel/TunnelIdTest.java
index d5159fc..22fac69 100644
--- a/incubator/api/src/test/java/org/onosproject/incubator/net/tunnel/TunnelIdTest.java
+++ b/incubator/api/src/test/java/org/onosproject/incubator/net/tunnel/TunnelIdTest.java
@@ -30,9 +30,9 @@
  */
 public class TunnelIdTest {
 
-    final TunnelId tunnelId1 = TunnelId.valueOf(1);
-    final TunnelId sameAstunnelId1 = TunnelId.valueOf(1);
-    final TunnelId tunnelId2 = TunnelId.valueOf(2);
+    final TunnelId tunnelId1 = TunnelId.valueOf("1");
+    final TunnelId sameAstunnelId1 = TunnelId.valueOf("1");
+    final TunnelId tunnelId2 = TunnelId.valueOf("2");
 
     /**
      * Checks that the TunnelId class is immutable.
@@ -58,7 +58,7 @@
      */
     @Test
     public void testConstruction() {
-        final long tunnelIdValue = 7777L;
+        final String tunnelIdValue = "7777";
         final TunnelId tunnelId = TunnelId.valueOf(tunnelIdValue);
         assertThat(tunnelId, is(notNullValue()));
         assertThat(tunnelId.id(), is(tunnelIdValue));
diff --git a/incubator/api/src/test/java/org/onosproject/incubator/net/tunnel/TunnelSubscriptionTest.java b/incubator/api/src/test/java/org/onosproject/incubator/net/tunnel/TunnelSubscriptionTest.java
index 6d69ea745..fc4d04c 100644
--- a/incubator/api/src/test/java/org/onosproject/incubator/net/tunnel/TunnelSubscriptionTest.java
+++ b/incubator/api/src/test/java/org/onosproject/incubator/net/tunnel/TunnelSubscriptionTest.java
@@ -45,7 +45,7 @@
         TunnelEndPoint dst = IpTunnelEndPoint.ipTunnelPoint(IpAddress.valueOf(32421));
         ApplicationId appId = new DefaultApplicationId(243, "test");
         ApplicationId appId2 = new DefaultApplicationId(2431, "test1");
-        TunnelId tunnelId = TunnelId.valueOf(41654654);
+        TunnelId tunnelId = TunnelId.valueOf("41654654");
         TunnelSubscription p1 = new TunnelSubscription(appId, src, dst, tunnelId, Tunnel.Type.VXLAN,
                              null);
         TunnelSubscription p2 = new TunnelSubscription(appId, src, dst, tunnelId, Tunnel.Type.VXLAN,
diff --git a/incubator/api/src/test/java/org/onosproject/incubator/net/virtual/DefaultVirtualLinkTest.java b/incubator/api/src/test/java/org/onosproject/incubator/net/virtual/DefaultVirtualLinkTest.java
index f522293..71e214a 100644
--- a/incubator/api/src/test/java/org/onosproject/incubator/net/virtual/DefaultVirtualLinkTest.java
+++ b/incubator/api/src/test/java/org/onosproject/incubator/net/virtual/DefaultVirtualLinkTest.java
@@ -40,6 +40,60 @@
         assertThatClassIsImmutable(DefaultVirtualLink.class);
     }
 
+    /**
+     * Tests the DefaultVirtualLink Builder to ensure that the src cannot be null.
+     */
+    @Test(expected = NullPointerException.class)
+    public void testBuilderNullSrc() {
+        DefaultVirtualDevice device1 =
+                new DefaultVirtualDevice(NetworkId.networkId(0), DeviceId.deviceId(deviceIdValue1));
+        DefaultVirtualDevice device2 =
+                new DefaultVirtualDevice(NetworkId.networkId(0), DeviceId.deviceId(deviceIdValue2));
+        ConnectPoint src = new ConnectPoint(device1.id(), PortNumber.portNumber(1));
+        ConnectPoint dst = new ConnectPoint(device2.id(), PortNumber.portNumber(2));
+
+        DefaultVirtualLink.builder()
+                .src(null)
+                .build();
+    }
+
+    /**
+     * Tests the DefaultVirtualLink Builder to ensure that the dst cannot be null.
+     */
+    @Test(expected = NullPointerException.class)
+    public void testBuilderNullDst() {
+        DefaultVirtualDevice device1 =
+                new DefaultVirtualDevice(NetworkId.networkId(0), DeviceId.deviceId(deviceIdValue1));
+        DefaultVirtualDevice device2 =
+                new DefaultVirtualDevice(NetworkId.networkId(0), DeviceId.deviceId(deviceIdValue2));
+        ConnectPoint src = new ConnectPoint(device1.id(), PortNumber.portNumber(1));
+        ConnectPoint dst = new ConnectPoint(device2.id(), PortNumber.portNumber(2));
+
+        DefaultVirtualLink.builder()
+                .dst(null)
+                .build();
+    }
+
+    /**
+     * Tests the DefaultVirtualLink Builder to ensure that the networkId cannot be null.
+     */
+    @Test(expected = NullPointerException.class)
+    public void testBuilderNullNetworkId() {
+        DefaultVirtualDevice device1 =
+                new DefaultVirtualDevice(NetworkId.networkId(0), DeviceId.deviceId(deviceIdValue1));
+        DefaultVirtualDevice device2 =
+                new DefaultVirtualDevice(NetworkId.networkId(0), DeviceId.deviceId(deviceIdValue2));
+        ConnectPoint src = new ConnectPoint(device1.id(), PortNumber.portNumber(1));
+        ConnectPoint dst = new ConnectPoint(device2.id(), PortNumber.portNumber(2));
+
+        DefaultVirtualLink.builder()
+                .networkId(null)
+                .build();
+    }
+
+    /**
+     * Tests the DefaultVirtualLink equality method.
+     */
     @Test
     public void testEquality() {
         DefaultVirtualDevice device1 =
@@ -49,10 +103,30 @@
         ConnectPoint src = new ConnectPoint(device1.id(), PortNumber.portNumber(1));
         ConnectPoint dst = new ConnectPoint(device2.id(), PortNumber.portNumber(2));
 
-        DefaultVirtualLink link1 = new DefaultVirtualLink(NetworkId.networkId(0), src, dst, TunnelId.valueOf(0));
-        DefaultVirtualLink link2 = new DefaultVirtualLink(NetworkId.networkId(0), src, dst, TunnelId.valueOf(0));
-        DefaultVirtualLink link3 = new DefaultVirtualLink(NetworkId.networkId(0), src, dst, TunnelId.valueOf(1));
-        DefaultVirtualLink link4 = new DefaultVirtualLink(NetworkId.networkId(1), src, dst, TunnelId.valueOf(0));
+        VirtualLink link1 = DefaultVirtualLink.builder()
+                .networkId(NetworkId.networkId(0))
+                .src(src)
+                .dst(dst)
+                .tunnelId(TunnelId.valueOf("1"))
+                .build();
+        VirtualLink link2 = DefaultVirtualLink.builder()
+                .networkId(NetworkId.networkId(0))
+                .src(src)
+                .dst(dst)
+                .tunnelId(TunnelId.valueOf("1"))
+                .build();
+        VirtualLink link3 = DefaultVirtualLink.builder()
+                .networkId(NetworkId.networkId(0))
+                .src(src)
+                .dst(dst)
+                .tunnelId(TunnelId.valueOf("2"))
+                .build();
+        VirtualLink link4 = DefaultVirtualLink.builder()
+                .networkId(NetworkId.networkId(1))
+                .src(src)
+                .dst(dst)
+                .tunnelId(TunnelId.valueOf("3"))
+                .build();
 
         new EqualsTester().addEqualityGroup(link1, link2).addEqualityGroup(link3)
                 .addEqualityGroup(link4).testEquals();
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/PtToPtIntentVirtualNetworkProvider.java b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/PtToPtIntentVirtualNetworkProvider.java
new file mode 100644
index 0000000..d879f59
--- /dev/null
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/PtToPtIntentVirtualNetworkProvider.java
@@ -0,0 +1,153 @@
+/*
+ * 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 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.apache.felix.scr.annotations.Service;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.incubator.net.tunnel.TunnelId;
+import org.onosproject.incubator.net.virtual.DefaultVirtualLink;
+import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.incubator.net.virtual.VirtualNetworkProvider;
+import org.onosproject.incubator.net.virtual.VirtualNetworkProviderRegistry;
+import org.onosproject.incubator.net.virtual.VirtualNetworkProviderService;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.EncapsulationType;
+import org.onosproject.net.intent.Constraint;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentService;
+import org.onosproject.net.intent.IntentState;
+import org.onosproject.net.intent.Key;
+import org.onosproject.net.intent.PointToPointIntent;
+import org.onosproject.net.intent.constraint.EncapsulationConstraint;
+import org.onosproject.net.provider.AbstractProvider;
+import org.slf4j.Logger;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static java.lang.Thread.sleep;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Point to point intent VirtualNetworkProvider implementation.
+ */
+@Component(immediate = true)
+@Service
+public class PtToPtIntentVirtualNetworkProvider extends AbstractProvider implements VirtualNetworkProvider {
+
+    private final Logger log = getLogger(PtToPtIntentVirtualNetworkProvider.class);
+    private static final String NETWORK_ID_NULL = "Network ID cannot be null";
+    private static final String CONNECT_POINT_NULL = "Connect Point cannot be null";
+    private static final String INTENT_NULL = "Intent cannot be null";
+    protected static final String KEY_FORMAT = "networkId=%s src=%s dst=%s";
+    private static final int MAX_WAIT_COUNT = 30;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected VirtualNetworkProviderRegistry providerRegistry;
+
+    private VirtualNetworkProviderService providerService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected IntentService intentService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected CoreService coreService;
+
+    protected static final String PTPT_INTENT_APPID = "org.onosproject.vnet.intent";
+    private ApplicationId appId;
+
+    /**
+     * Default constructor.
+     */
+    public PtToPtIntentVirtualNetworkProvider() {
+        super(DefaultVirtualLink.PID);
+    }
+
+    @Activate
+    public void activate() {
+        providerService = providerRegistry.register(this);
+        appId = coreService.registerApplication(PTPT_INTENT_APPID);
+
+        log.info("Started");
+    }
+
+    @Deactivate
+    public void deactivate() {
+        providerRegistry.unregister(this);
+        providerService = null;
+        log.info("Stopped");
+    }
+
+    @Override
+    public TunnelId createTunnel(NetworkId networkId, ConnectPoint src, ConnectPoint dst) {
+        checkNotNull(NETWORK_ID_NULL, networkId);
+        checkNotNull(CONNECT_POINT_NULL, src);
+        checkNotNull(CONNECT_POINT_NULL, dst);
+        String key = String.format(KEY_FORMAT, networkId.toString(), src.toString(), dst.toString());
+        Key intentKey = Key.of(key, appId);
+
+        List<Constraint> constraints = new ArrayList<>();
+        constraints.add(new EncapsulationConstraint(EncapsulationType.VLAN));
+
+        // TODO Currently there can only be one tunnel/intent between the src and dst across
+        // all virtual networks. We may want to support multiple intents between the same src/dst pairs.
+        PointToPointIntent intent = PointToPointIntent.builder()
+                .key(intentKey)
+                .appId(appId)
+                .ingressPoint(src)
+                .egressPoint(dst)
+                .constraints(constraints)
+                .build();
+        intentService.submit(intent);
+
+        // construct tunnelId from the key
+        return TunnelId.valueOf(key);
+    }
+
+    @Override
+    public void destroyTunnel(NetworkId networkId, TunnelId tunnelId) {
+        String key = tunnelId.id();
+        Key intentKey = Key.of(key, appId);
+        Intent intent = intentService.getIntent(intentKey);
+        checkNotNull(intent, INTENT_NULL);
+        intentService.withdraw(intent);
+        try {
+            int count = 0;
+            // Loop waiting for the intent to go into a withdrawn or failed state
+            // before attempting to purge it.
+            while (++count <= MAX_WAIT_COUNT) {
+                IntentState state = intentService.getIntentState(intentKey);
+                if ((state == IntentState.FAILED) || (state == IntentState.WITHDRAWN)) {
+                    intentService.purge(intent);
+                    break;
+                }
+                sleep(1000);
+            }
+        } catch (Exception e) {
+            log.error("Exception: " + e);
+        }
+    }
+}
+
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 fdeed25..b1b68a1 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
@@ -66,6 +66,7 @@
     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;
@@ -135,13 +136,41 @@
 
     @Override
     public VirtualLink createVirtualLink(NetworkId networkId,
-                                         ConnectPoint src, ConnectPoint dst,
-                                         TunnelId realizedBy) {
+                                         ConnectPoint src, ConnectPoint dst) {
         checkNotNull(networkId, NETWORK_NULL);
         checkNotNull(src, LINK_POINT_NULL);
         checkNotNull(dst, LINK_POINT_NULL);
-        checkNotNull(realizedBy, "Tunnel ID cannot be null");
-        return store.addLink(networkId, src, dst, realizedBy);
+        VirtualLink virtualLink = store.addLink(networkId, src, dst, 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);
+            }
+        }
+        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;
     }
 
     @Override
@@ -149,7 +178,14 @@
         checkNotNull(networkId, NETWORK_NULL);
         checkNotNull(src, LINK_POINT_NULL);
         checkNotNull(dst, LINK_POINT_NULL);
-        store.removeLink(networkId, src, dst);
+        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());
+            }
+        }
     }
 
     @Override
diff --git a/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/PtToPtIntentVirtualNetworkProviderTest.java b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/PtToPtIntentVirtualNetworkProviderTest.java
new file mode 100644
index 0000000..2f2926b
--- /dev/null
+++ b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/PtToPtIntentVirtualNetworkProviderTest.java
@@ -0,0 +1,249 @@
+/*
+ * 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.Sets;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.TestApplicationId;
+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.tunnel.TunnelId;
+import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.incubator.net.virtual.VirtualNetworkProvider;
+import org.onosproject.incubator.net.virtual.VirtualNetworkProviderRegistry;
+import org.onosproject.incubator.net.virtual.VirtualNetworkProviderService;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentService;
+import org.onosproject.net.intent.IntentServiceAdapter;
+import org.onosproject.net.intent.IntentState;
+import org.onosproject.net.intent.Key;
+import org.onosproject.net.intent.MockIdGenerator;
+import org.onosproject.net.provider.AbstractProviderService;
+import org.onosproject.net.provider.ProviderId;
+
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicLong;
+
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+/**
+ * Junit tests for PtToPtIntentVirtualNetworkProvider.
+ */
+public class PtToPtIntentVirtualNetworkProviderTest {
+
+    private PtToPtIntentVirtualNetworkProvider provider;
+    private VirtualNetworkProviderRegistry providerRegistry;
+
+    private final VirtualNetworkRegistryAdapter virtualNetworkRegistry = new VirtualNetworkRegistryAdapter();
+    private IntentService intentService;
+
+    private static final ApplicationId APP_ID =
+            TestApplicationId.create(PtToPtIntentVirtualNetworkProvider.PTPT_INTENT_APPID);
+
+    private IdGenerator idGenerator = new MockIdGenerator();
+
+    @Before
+    public void setUp() {
+        provider = new PtToPtIntentVirtualNetworkProvider();
+        provider.providerRegistry = virtualNetworkRegistry;
+        final CoreService mockCoreService = createMock(CoreService.class);
+        provider.coreService = mockCoreService;
+        expect(mockCoreService.registerApplication(PtToPtIntentVirtualNetworkProvider.PTPT_INTENT_APPID))
+                .andReturn(APP_ID).anyTimes();
+        replay(mockCoreService);
+        Intent.unbindIdGenerator(idGenerator);
+        Intent.bindIdGenerator(idGenerator);
+
+        intentService = new TestIntentService();
+        provider.intentService = intentService;
+        provider.activate();
+    }
+
+    @After
+    public void tearDown() {
+        provider.deactivate();
+        provider.providerRegistry = null;
+        provider.coreService = null;
+        provider.intentService = null;
+        Intent.unbindIdGenerator(idGenerator);
+    }
+
+    @Test
+    public void basics() {
+        assertNotNull("registration expected", provider);
+    }
+
+    /**
+     * Test a null network identifier.
+     */
+    @Test(expected = NullPointerException.class)
+    public void testCreateTunnelNullNetworkId() {
+        provider.createTunnel(null, null, null);
+    }
+
+    /**
+     * Test a null source connect point.
+     */
+    @Test(expected = NullPointerException.class)
+    public void testCreateTunnelNullSrc() {
+        ConnectPoint dst = new ConnectPoint(DeviceId.deviceId("device2"), PortNumber.portNumber(2));
+
+        provider.createTunnel(NetworkId.networkId(0), null, dst);
+    }
+
+    /**
+     * Test a null destination connect point.
+     */
+    @Test(expected = NullPointerException.class)
+    public void testCreateTunnelNullDst() {
+        ConnectPoint src = new ConnectPoint(DeviceId.deviceId("device1"), PortNumber.portNumber(1));
+
+        provider.createTunnel(NetworkId.networkId(0), src, null);
+    }
+
+    /**
+     * Test creating/destroying a valid tunnel.
+     */
+    @Test
+    public void testCreateRemoveTunnel() {
+        NetworkId networkId = NetworkId.networkId(0);
+        ConnectPoint src = new ConnectPoint(DeviceId.deviceId("device1"), PortNumber.portNumber(1));
+        ConnectPoint dst = new ConnectPoint(DeviceId.deviceId("device2"), PortNumber.portNumber(2));
+
+        TunnelId tunnelId = provider.createTunnel(networkId, src, dst);
+        String key = String.format(PtToPtIntentVirtualNetworkProvider.KEY_FORMAT,
+                                   networkId.toString(), src.toString(), dst.toString());
+
+        assertEquals("TunnelId does not match as expected.", key, tunnelId.toString());
+        provider.destroyTunnel(networkId, tunnelId);
+    }
+
+    /**
+     * Virtual network registry implementation for this test class.
+     */
+    private class VirtualNetworkRegistryAdapter implements VirtualNetworkProviderRegistry {
+        private VirtualNetworkProvider provider;
+
+        @Override
+        public VirtualNetworkProviderService register(VirtualNetworkProvider theProvider) {
+            this.provider = theProvider;
+            return new TestVirtualNetworkProviderService(theProvider);
+        }
+
+        @Override
+        public void unregister(VirtualNetworkProvider theProvider) {
+            this.provider = null;
+        }
+
+        @Override
+        public Set<ProviderId> getProviders() {
+            return null;
+        }
+    }
+
+    /**
+     * Virtual network provider service implementation for this test class.
+     */
+    private class TestVirtualNetworkProviderService
+            extends AbstractProviderService<VirtualNetworkProvider>
+            implements VirtualNetworkProviderService {
+
+        protected TestVirtualNetworkProviderService(VirtualNetworkProvider provider) {
+            super(provider);
+        }
+    }
+
+
+    /**
+     * 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();
+                }
+            };
+        }
+    }
+
+    /**
+     * Represents a fake IntentService class that easily allows to store and
+     * retrieve intents without implementing the IntentService logic.
+     */
+    private class TestIntentService extends IntentServiceAdapter {
+
+        private Set<Intent> intents;
+
+        public TestIntentService() {
+            intents = Sets.newHashSet();
+        }
+
+        @Override
+        public void submit(Intent intent) {
+            intents.add(intent);
+        }
+
+        @Override
+        public void withdraw(Intent intent) {
+        }
+
+        @Override
+        public IntentState getIntentState(Key intentKey) {
+            return IntentState.WITHDRAWN;
+        }
+
+        @Override
+        public void purge(Intent intent) {
+            intents.remove(intent);
+        }
+
+        @Override
+        public long getIntentCount() {
+            return intents.size();
+        }
+
+        @Override
+        public Iterable<Intent> getIntents() {
+            return intents;
+        }
+
+        @Override
+        public Intent getIntent(Key intentKey) {
+            for (Intent intent : intents) {
+                if (intent.key().equals(intentKey)) {
+                    return intent;
+                }
+            }
+            return null;
+        }
+    }
+}
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 214e252..837b501 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,7 +27,6 @@
 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;
@@ -247,8 +246,8 @@
                 manager.createVirtualDevice(virtualNetwork1.id(), DeviceId.deviceId(deviceIdValue2));
         ConnectPoint src = new ConnectPoint(srcVirtualDevice.id(), PortNumber.portNumber(1));
         ConnectPoint dst = new ConnectPoint(dstVirtualDevice.id(), PortNumber.portNumber(2));
-        manager.createVirtualLink(virtualNetwork1.id(), src, dst, TunnelId.valueOf(0));
-        manager.createVirtualLink(virtualNetwork1.id(), dst, src, TunnelId.valueOf(1));
+        manager.createVirtualLink(virtualNetwork1.id(), src, dst);
+        manager.createVirtualLink(virtualNetwork1.id(), dst, src);
 
         Set<VirtualLink> virtualLinks = manager.getVirtualLinks(virtualNetwork1.id());
         assertNotNull("The virtual link set should not be null", virtualLinks);
@@ -263,13 +262,30 @@
         assertTrue("The virtual link set should be empty.", virtualLinks.isEmpty());
 
         // Add/remove the virtual link again.
-        VirtualLink virtualLink = manager.createVirtualLink(virtualNetwork1.id(), src, dst, TunnelId.valueOf(0));
+        VirtualLink virtualLink = manager.createVirtualLink(virtualNetwork1.id(), src, dst);
         manager.removeVirtualLink(virtualLink.networkId(), virtualLink.src(), virtualLink.dst());
         virtualLinks = manager.getVirtualLinks(virtualNetwork1.id());
         assertTrue("The virtual link set should be empty.", virtualLinks.isEmpty());
     }
 
     /**
+     * Tests adding the same virtual link twice.
+     */
+    @Test(expected = IllegalStateException.class)
+    public void testAddSameVirtualLink() {
+        manager.registerTenantId(TenantId.tenantId(tenantIdValue1));
+        VirtualNetwork virtualNetwork1 = manager.createVirtualNetwork(TenantId.tenantId(tenantIdValue1));
+        VirtualDevice srcVirtualDevice =
+                manager.createVirtualDevice(virtualNetwork1.id(), DeviceId.deviceId(deviceIdValue1));
+        VirtualDevice dstVirtualDevice =
+                manager.createVirtualDevice(virtualNetwork1.id(), DeviceId.deviceId(deviceIdValue2));
+        ConnectPoint src = new ConnectPoint(srcVirtualDevice.id(), PortNumber.portNumber(1));
+        ConnectPoint dst = new ConnectPoint(dstVirtualDevice.id(), PortNumber.portNumber(2));
+        manager.createVirtualLink(virtualNetwork1.id(), src, dst);
+        manager.createVirtualLink(virtualNetwork1.id(), src, dst);
+    }
+
+    /**
      * Tests add and remove of virtual ports.
      */
     @Test
diff --git a/incubator/store/src/main/java/org/onosproject/incubator/store/tunnel/impl/DistributedTunnelStore.java b/incubator/store/src/main/java/org/onosproject/incubator/store/tunnel/impl/DistributedTunnelStore.java
index 7f5074a..d796068 100644
--- a/incubator/store/src/main/java/org/onosproject/incubator/store/tunnel/impl/DistributedTunnelStore.java
+++ b/incubator/store/src/main/java/org/onosproject/incubator/store/tunnel/impl/DistributedTunnelStore.java
@@ -180,7 +180,7 @@
             notifyDelegate(event);
             return tunnel.tunnelId();
         } else {
-            TunnelId tunnelId = TunnelId.valueOf(idGenerator.getNewId());
+            TunnelId tunnelId = TunnelId.valueOf(String.valueOf(idGenerator.getNewId()));
             State tunnelState = (state != null) ? state : tunnel.state();
             Tunnel newT = new DefaultTunnel(tunnel.providerId(), tunnel.src(),
                                             tunnel.dst(), tunnel.type(),
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 ca0c311..f4eedc4 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
@@ -134,9 +134,9 @@
                            .register(DefaultVirtualPort.class)
                            .register(DeviceId.class)
                            .register(Device.class)
-                           .register(TunnelId.class)
                            .register(DefaultDevice.class)
                            .register(DefaultPort.class)
+                           .register(TunnelId.class)
                            .nextId(KryoNamespaces.BEGIN_USER_CUSTOM_ID).build());
 
     /**
@@ -349,22 +349,51 @@
         if (virtualLinkSet == null) {
             virtualLinkSet = new HashSet<>();
         }
-        VirtualLink virtualLink = new DefaultVirtualLink(networkId, src, dst, realizedBy);
+        // validate that the link does not already exist in this network
+        checkState(getLink(networkId, src, dst) == null, "The virtual link already exists");
+
+        VirtualLink virtualLink = DefaultVirtualLink.builder()
+                .networkId(networkId)
+                .src(src)
+                .dst(dst)
+                .tunnelId(realizedBy)
+                .build();
+
         virtualLinkSet.add(virtualLink);
         networkIdVirtualLinkSetMap.put(networkId, virtualLinkSet);
         return virtualLink;
     }
 
     @Override
-    public void removeLink(NetworkId networkId, ConnectPoint src, ConnectPoint dst) {
+    public void updateLink(VirtualLink virtualLink, TunnelId tunnelId) {
+        checkState(networkExists(virtualLink.networkId()), "The network has not been added.");
+        Set<VirtualLink> virtualLinkSet = networkIdVirtualLinkSetMap.get(virtualLink.networkId());
+        if (virtualLinkSet == null) {
+            virtualLinkSet = new HashSet<>();
+        }
+        virtualLinkSet.remove(virtualLink);
+
+        VirtualLink newVirtualLink = DefaultVirtualLink.builder()
+                .networkId(virtualLink.networkId())
+                .src(virtualLink.src())
+                .dst(virtualLink.dst())
+                .tunnelId(tunnelId)
+                .build();
+
+        virtualLinkSet.add(newVirtualLink);
+        networkIdVirtualLinkSetMap.put(newVirtualLink.networkId(), virtualLinkSet);
+    }
+
+    @Override
+    public VirtualLink removeLink(NetworkId networkId, ConnectPoint src, ConnectPoint dst) {
         checkState(networkExists(networkId), "The network has not been added.");
 
+        final VirtualLink virtualLink = getLink(networkId, src, dst);
+        if (virtualLink == null) {
+            return null;
+        }
         Set<VirtualLink> virtualLinkSet = new HashSet<>();
-        networkIdVirtualLinkSetMap.get(networkId).forEach(link -> {
-            if (link.src().equals(src) && link.dst().equals(dst)) {
-                virtualLinkSet.add(link);
-            }
-        });
+        virtualLinkSet.add(virtualLink);
 
         if (virtualLinkSet != null) {
             networkIdVirtualLinkSetMap.compute(networkId, (id, existingVirtualLinks) -> {
@@ -375,6 +404,7 @@
                 }
             });
         }
+        return virtualLink;
     }
 
     @Override
@@ -445,6 +475,31 @@
         return ImmutableSet.copyOf(virtualLinkSet);
     }
 
+    /**
+     * Returns the virtual link matching the network identifier, source connect point,
+     * and destination connect point.
+     *
+     * @param networkId network identifier
+     * @param src       source connect point
+     * @param dst       destination connect point
+     * @return virtual link
+     */
+    private VirtualLink getLink(NetworkId networkId, ConnectPoint src, ConnectPoint dst) {
+        Set<VirtualLink> virtualLinkSet = networkIdVirtualLinkSetMap.get(networkId);
+        if (virtualLinkSet == null) {
+            return null;
+        }
+
+        VirtualLink virtualLink = null;
+        for (VirtualLink link : virtualLinkSet) {
+            if (link.src().equals(src) && link.dst().equals(dst)) {
+                virtualLink = link;
+                break;
+            }
+        }
+        return virtualLink;
+    }
+
     @Override
     public Set<VirtualPort> getPorts(NetworkId networkId, DeviceId deviceId) {
         checkState(networkExists(networkId), "The network has not been added.");