Detangling incubator: virtual nets, tunnels, resource labels, oh my

- virtual networking moved to /apps/virtual; with CLI & REST API
- tunnels and labels moved to /apps/tunnel; with CLI & REST API; UI disabled for now
- protobuf/models moved to /core/protobuf/models
- defunct grpc/rpc registry stuff left under /graveyard
- compile dependencies on /incubator moved to respective modules for compilation
- run-time dependencies will need to be re-tested for dependent apps

- /graveyard will be removed in not-too-distant future

Change-Id: I0a0b995c635487edcf95a352f50dd162186b0b39
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/AbstractVnetService.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/AbstractVnetService.java
new file mode 100644
index 0000000..b3e1d18
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/AbstractVnetService.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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 org.onlab.osgi.ServiceDirectory;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Basis for virtual network service.
+ */
+public abstract class AbstractVnetService
+        implements VnetService {
+
+    private static final String NETWORK_NULL = "Network ID cannot be null";
+
+    protected NetworkId networkId;
+    protected VirtualNetworkService manager;
+    protected ServiceDirectory serviceDirectory;
+
+    public AbstractVnetService(VirtualNetworkService manager,
+                               NetworkId networkId) {
+        checkNotNull(networkId, NETWORK_NULL);
+        this.manager = manager;
+        this.networkId = networkId;
+        this.serviceDirectory = manager.getServiceDirectory();
+    }
+
+    @Override
+    public NetworkId networkId() {
+        return this.networkId;
+    }
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/Comparators.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/Comparators.java
new file mode 100644
index 0000000..8c67e00
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/Comparators.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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 java.util.Comparator;
+
+/**
+ * Various comparators.
+ */
+public final class Comparators {
+
+    // Ban construction
+    private Comparators() {
+    }
+
+    public static final Comparator<VirtualNetwork> VIRTUAL_NETWORK_COMPARATOR =
+            (v1, v2) -> {
+                int compareId = v1.tenantId().toString().compareTo(v2.tenantId().toString());
+                return (compareId != 0) ? compareId : Long.signum(v1.id().id() - v2.id().id());
+            };
+
+    public static final Comparator<VirtualDevice> VIRTUAL_DEVICE_COMPARATOR =
+            (v1, v2) -> v1.id().toString().compareTo(v2.id().toString());
+
+    public static final Comparator<VirtualPort> VIRTUAL_PORT_COMPARATOR =
+            (v1, v2) -> v1.number().toString().compareTo(v2.number().toString());
+
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/DefaultVirtualDevice.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/DefaultVirtualDevice.java
new file mode 100644
index 0000000..98e3e1e
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/DefaultVirtualDevice.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * 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 org.onlab.packet.ChassisId;
+import org.onosproject.net.DefaultDevice;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.provider.ProviderId;
+
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.*;
+
+/**
+ * Default representation of a virtual device.
+ */
+public final class DefaultVirtualDevice extends DefaultDevice implements VirtualDevice {
+
+    private static final String VIRTUAL = "virtual";
+    private static final ProviderId PID = new ProviderId(VIRTUAL, VIRTUAL);
+
+    private final NetworkId networkId;
+
+    /**
+     * Creates a network element attributed to the specified provider.
+     *
+     * @param networkId network identifier
+     * @param id        device identifier
+     */
+    public DefaultVirtualDevice(NetworkId networkId, DeviceId id) {
+        super(PID, id, Type.VIRTUAL, VIRTUAL, VIRTUAL, VIRTUAL, VIRTUAL,
+              new ChassisId(0));
+        this.networkId = networkId;
+    }
+
+    @Override
+    public NetworkId networkId() {
+        return networkId;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(networkId);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof DefaultVirtualDevice) {
+            DefaultVirtualDevice that = (DefaultVirtualDevice) obj;
+            return super.equals(that) && Objects.equals(this.networkId, that.networkId);
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).add("networkId", networkId).toString();
+    }
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/DefaultVirtualHost.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/DefaultVirtualHost.java
new file mode 100644
index 0000000..61f31b1
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/DefaultVirtualHost.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * 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 org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
+import org.onosproject.net.DefaultAnnotations;
+import org.onosproject.net.DefaultHost;
+import org.onosproject.net.HostId;
+import org.onosproject.net.HostLocation;
+import org.onosproject.net.provider.ProviderId;
+
+import java.util.Collections;
+import java.util.Objects;
+import java.util.Set;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * Default representation of a virtual host.
+ */
+public final class DefaultVirtualHost extends DefaultHost implements VirtualHost {
+
+    private static final String VIRTUAL = "virtual";
+    private static final ProviderId PID = new ProviderId(VIRTUAL, VIRTUAL);
+
+    private final NetworkId networkId;
+
+    /**
+     * Creates a virtual host attributed to the specified provider.
+     *
+     * @param networkId network identifier
+     * @param id        host identifier
+     * @param mac       host MAC address
+     * @param vlan      host VLAN identifier
+     * @param location  host location
+     * @param ips       host IP addresses
+     */
+    public DefaultVirtualHost(NetworkId networkId, HostId id, MacAddress mac,
+                              VlanId vlan, HostLocation location, Set<IpAddress> ips) {
+        this(networkId, id, mac, vlan, Collections.singleton(location), ips);
+    }
+
+    /**
+     * Creates a virtual host attributed to the specified provider.
+     *
+     * @param networkId network identifier
+     * @param id        host identifier
+     * @param mac       host MAC address
+     * @param vlan      host VLAN identifier
+     * @param locations host locations
+     * @param ips       host IP addresses
+     */
+    public DefaultVirtualHost(NetworkId networkId, HostId id, MacAddress mac,
+                              VlanId vlan, Set<HostLocation> locations, Set<IpAddress> ips) {
+        super(PID, id, mac, vlan, locations, ips, false, DefaultAnnotations.builder().build());
+        this.networkId = networkId;
+    }
+
+    @Override
+    public NetworkId networkId() {
+        return networkId;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(networkId);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof DefaultVirtualHost) {
+            DefaultVirtualHost that = (DefaultVirtualHost) obj;
+            return super.equals(that) && Objects.equals(this.networkId, that.networkId);
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).add("networkId", networkId).toString();
+    }
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/DefaultVirtualLink.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/DefaultVirtualLink.java
new file mode 100644
index 0000000..20924bc
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/DefaultVirtualLink.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * 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 org.onosproject.incubator.net.tunnel.TunnelId;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DefaultAnnotations;
+import org.onosproject.net.DefaultLink;
+import org.onosproject.net.provider.ProviderId;
+
+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 = "virtualLink";
+    public static final ProviderId PID = new ProviderId(VIRTUAL, VIRTUAL);
+
+    private final NetworkId networkId;
+    private final TunnelId tunnelId;
+
+    /**
+     * Private constructor for a default virtual link.
+     *
+     * @param networkId network identifier
+     * @param src       source connection point
+     * @param dst       destination connection point
+     * @param state     link state
+     * @param tunnelId  tunnel identifier
+     */
+    private DefaultVirtualLink(NetworkId networkId, ConnectPoint src, ConnectPoint dst,
+                               State state, TunnelId tunnelId) {
+        super(PID, src, dst, Type.VIRTUAL, state, DefaultAnnotations.builder().build());
+        this.networkId = networkId;
+        this.tunnelId = tunnelId;
+    }
+
+    @Override
+    public NetworkId networkId() {
+        return networkId;
+    }
+
+    /**
+     * Returns the tunnel identifier.
+     *
+     * @return tunnel identifier.
+     */
+    public TunnelId tunnelId() {
+        return tunnelId;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(networkId, tunnelId);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof DefaultVirtualLink) {
+            DefaultVirtualLink that = (DefaultVirtualLink) obj;
+            return super.equals(that) &&
+                    Objects.equals(this.networkId, that.networkId) &&
+                    Objects.equals(this.tunnelId, that.tunnelId);
+        }
+        return false;
+    }
+
+    @Override
+    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 State state;
+
+        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;
+        }
+
+        /**
+         * Sets the link state to be used by the builder.
+         *
+         * @param state link state
+         * @return self
+         */
+        public Builder state(State state) {
+            this.state = state;
+            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, state, tunnelId);
+        }
+    }
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/DefaultVirtualNetwork.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/DefaultVirtualNetwork.java
new file mode 100644
index 0000000..bf7de57
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/DefaultVirtualNetwork.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * 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 org.onosproject.net.TenantId;
+
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * Default implementation of the virtual network descriptor.
+ */
+public final class DefaultVirtualNetwork implements VirtualNetwork {
+
+    private final NetworkId id;
+    private final TenantId tenantId;
+
+    /**
+     * Creates a new virtual network descriptor.
+     *
+     * @param id       network identifier
+     * @param tenantId tenant identifier
+     */
+    public DefaultVirtualNetwork(NetworkId id, TenantId tenantId) {
+        this.id = id;
+        this.tenantId = tenantId;
+    }
+
+    @Override
+    public NetworkId id() {
+        return id;
+    }
+
+    @Override
+    public TenantId tenantId() {
+        return tenantId;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(id, tenantId);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof DefaultVirtualNetwork) {
+            DefaultVirtualNetwork that = (DefaultVirtualNetwork) obj;
+            return Objects.equals(this.id, that.id)
+                    && Objects.equals(this.tenantId, that.tenantId);
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("id", id)
+                .add("tenantId", tenantId)
+                .toString();
+    }
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/DefaultVirtualPort.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/DefaultVirtualPort.java
new file mode 100644
index 0000000..d5f3efb
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/DefaultVirtualPort.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * 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 org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DefaultAnnotations;
+import org.onosproject.net.DefaultPort;
+import org.onosproject.net.Device;
+import org.onosproject.net.Element;
+import org.onosproject.net.PortNumber;
+
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * Default representation of a virtual port.
+ */
+public final class DefaultVirtualPort extends DefaultPort implements VirtualPort {
+
+    private final NetworkId networkId;
+    private final ConnectPoint realizedBy;
+
+    /**
+     * Creates a virtual port.
+     *
+     * @param networkId  network identifier
+     * @param device     parent network element
+     * @param portNumber port number
+     * @param realizedBy underling port which realizes this virtual port
+     */
+    public DefaultVirtualPort(NetworkId networkId, Device device, PortNumber portNumber,
+                              ConnectPoint realizedBy) {
+        this(networkId, device, portNumber, false, realizedBy);
+    }
+
+    /**
+     * Creates a virtual port.
+     *
+     * @param networkId  network identifier
+     * @param device     parent network element
+     * @param portNumber port number
+     * @param isEnabled  indicator whether the port is up and active
+     * @param realizedBy underling port which realizes this virtual port
+     */
+    public DefaultVirtualPort(NetworkId networkId, Device device, PortNumber portNumber,
+                              boolean isEnabled, ConnectPoint realizedBy) {
+        super((Element) device, portNumber, isEnabled, DefaultAnnotations.builder().build());
+        this.networkId = networkId;
+        this.realizedBy = realizedBy;
+    }
+
+    /**
+     * Returns network identifier.
+     *
+     * @return network identifier
+     */
+    public NetworkId networkId() {
+        return networkId;
+    }
+
+    @Override
+    public ConnectPoint realizedBy() {
+        return realizedBy;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(networkId, realizedBy);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof DefaultVirtualPort) {
+            DefaultVirtualPort that = (DefaultVirtualPort) obj;
+            return super.equals(that) &&
+                    Objects.equals(this.networkId, that.networkId) &&
+                    Objects.equals(this.number(), that.number()) &&
+                    Objects.equals(this.realizedBy, that.realizedBy);
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).add("networkId", networkId).add("realizedBy", realizedBy).toString();
+    }
+
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/NetworkId.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/NetworkId.java
new file mode 100644
index 0000000..552e941
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/NetworkId.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * 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 org.onlab.util.Identifier;
+
+import java.util.Objects;
+
+/**
+ * Representation of network identity.
+ */
+@Beta
+public final class NetworkId extends Identifier<Long> {
+
+    /**
+     * Represents no network, or an unspecified network.
+     */
+    public static final NetworkId NONE = networkId(-1L);
+
+    /**
+     * Represents the underlying physical network.
+     */
+    public static final NetworkId PHYSICAL = networkId(0L);
+
+    /**
+     * Checks if the id is for virtual network.
+     *
+     * @return true if the id is for virtual network.
+     */
+    public final boolean isVirtualNetworkId() {
+        return (!Objects.equals(this, NONE) && !Objects.equals(this, PHYSICAL));
+    }
+
+    // Public construction is prohibited
+    private NetworkId(long id) {
+        super(id);
+    }
+
+
+    // Default constructor for serialization
+    protected NetworkId() {
+        super(-1L);
+    }
+
+    /**
+     * Creates a network id using the supplied backing id.
+     *
+     * @param id network id
+     * @return network identifier
+     */
+    public static NetworkId networkId(long id) {
+        return new NetworkId(id);
+    }
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualDevice.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualDevice.java
new file mode 100644
index 0000000..d4b098f
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualDevice.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * 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 org.onosproject.net.Device;
+
+/**
+ * Abstraction of a virtual device.
+ */
+@Beta
+public interface VirtualDevice extends VirtualElement, Device {
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualElement.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualElement.java
new file mode 100644
index 0000000..572d02d
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualElement.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * 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;
+
+/**
+ * Abstraction of a virtual element.
+ */
+@Beta
+public interface VirtualElement {
+
+    /**
+     * Returns the network identifier to which this virtual element belongs.
+     *
+     * @return network identifier
+     */
+    NetworkId networkId();
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualHost.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualHost.java
new file mode 100644
index 0000000..569d8e3
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualHost.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * 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 org.onosproject.net.Host;
+
+/**
+ * Abstraction of a virtual end-station host.
+ */
+@Beta
+public interface VirtualHost extends VirtualElement, Host {
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualLink.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualLink.java
new file mode 100644
index 0000000..6f68961
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualLink.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * 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 org.onosproject.incubator.net.tunnel.TunnelId;
+import org.onosproject.net.Link;
+
+/**
+ * Abstraction of a virtual link.
+ */
+@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/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetwork.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetwork.java
new file mode 100644
index 0000000..1cbbddb
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetwork.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * 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 org.onosproject.net.TenantId;
+
+/**
+ * Representation of a virtual network.
+ */
+@Beta
+public interface VirtualNetwork {
+
+    /**
+     * Returns the network identifier.
+     *
+     * @return network id
+     */
+    NetworkId id();
+
+    /**
+     * Returns the identifier of the tenant to which this virtual network belongs.
+     *
+     * @return tenant identifier
+     */
+    TenantId tenantId();
+
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkAdminService.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkAdminService.java
new file mode 100644
index 0000000..bade4078
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkAdminService.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * 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 org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.HostId;
+import org.onosproject.net.HostLocation;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.TenantId;
+
+import java.util.Set;
+
+/**
+ * Service for managing the inventory of virtual networks.
+ */
+@Beta
+public interface VirtualNetworkAdminService extends VirtualNetworkService {
+
+    /**
+     * Registers the specified, externally generated tenant identifier.
+     *
+     * @param tenantId tenant identifier
+     */
+    void registerTenantId(TenantId tenantId);
+
+    /**
+     * Unregisters the specified, externally generated tenant identifier.
+     *
+     * @param tenantId tenant identifier
+     * @throws IllegalStateException if there are networks still owned by this tenant
+     */
+    void unregisterTenantId(TenantId tenantId);
+
+    /**
+     * Returns the set of tenant identifiers known to the system.
+     *
+     * @return set of known tenant identifiers
+     */
+    Set<TenantId> getTenantIds();
+
+    /**
+     * Creates a new virtual network for the specified tenant.
+     *
+     * @param tenantId tenant identifier
+     * @return newly created virtual network
+     */
+    VirtualNetwork createVirtualNetwork(TenantId tenantId);
+
+    /**
+     * Removes the specified virtual network and all its devices and links.
+     *
+     * @param networkId network identifier
+     */
+    void removeVirtualNetwork(NetworkId networkId);
+
+    /**
+     * Creates a new virtual device within the specified network. The device id
+     * must be unique within the bounds of the network.
+     *
+     * @param networkId network identifier
+     * @param deviceId  device identifier
+     * @return newly created virtual device
+     * @throws org.onlab.util.ItemNotFoundException if no such network found
+     */
+    VirtualDevice createVirtualDevice(NetworkId networkId, DeviceId deviceId);
+
+    /**
+     * Removes the specified virtual device and all its ports and affiliated links.
+     *
+     * @param networkId network identifier
+     * @param deviceId  device identifier
+     * @throws org.onlab.util.ItemNotFoundException if no such network or device found
+     */
+    void removeVirtualDevice(NetworkId networkId, DeviceId deviceId);
+
+    /**
+     * Creates a new virtual host within the specified network. The host id
+     * must be unique within the bounds of the network.
+     *
+     * @param networkId network identifier
+     * @param hostId    host identifier
+     * @param mac       mac address
+     * @param vlan      vlan identifier
+     * @param location  host location
+     * @param ips       set of ip addresses
+     * @return newly created virtual host
+     * @throws org.onlab.util.ItemNotFoundException if no such network found
+     */
+    VirtualHost createVirtualHost(NetworkId networkId, HostId hostId, MacAddress mac,
+                                  VlanId vlan, HostLocation location, Set<IpAddress> ips);
+
+    /**
+     * Removes the specified virtual host.
+     *
+     * @param networkId network identifier
+     * @param hostId  host identifier
+     * @throws org.onlab.util.ItemNotFoundException if no such network or host found
+     */
+    void removeVirtualHost(NetworkId networkId, HostId hostId);
+
+    /**
+     * Creates a new virtual link within the specified network.
+     *
+     * @param networkId  network identifier
+     * @param src        source connection point
+     * @param dst        destination connection point
+     * @return newly created virtual link
+     * @throws org.onlab.util.ItemNotFoundException if no such network found
+     */
+    VirtualLink createVirtualLink(NetworkId networkId,
+                                  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.
+
+    /**
+     * Removes the specified virtual link.
+     *
+     * @param networkId network identifier
+     * @param src       source connection point
+     * @param dst       destination connection point
+     * @throws org.onlab.util.ItemNotFoundException if no such network or link found
+     */
+    void removeVirtualLink(NetworkId networkId, ConnectPoint src, ConnectPoint dst);
+
+    /**
+     * Creates a new virtual port on the specified device.
+     *
+     * @param networkId  network identifier
+     * @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 is found
+     */
+    VirtualPort createVirtualPort(NetworkId networkId, DeviceId deviceId,
+                                  PortNumber portNumber, ConnectPoint realizedBy);
+
+    /**
+     * Binds an existing virtual port on the specified device.
+     *
+     * @param networkId  network identifier
+     * @param deviceId   virtual device identifier
+     * @param portNumber virtual port number
+     * @param realizedBy underlying physical port using which this virtual port is realized
+     * @throws org.onlab.util.ItemNotFoundException if no such network or device is found
+     */
+    void bindVirtualPort(NetworkId networkId, DeviceId deviceId,
+                                  PortNumber portNumber, ConnectPoint realizedBy);
+
+    /**
+     * Updates port state of an existing virtual port on the specified device.
+     *
+     * @param networkId  network identifier
+     * @param deviceId   virtual device identifier
+     * @param portNumber virtual port number
+     * @param isEnabled  indicator whether the port is up and active
+     * @throws org.onlab.util.ItemNotFoundException if no such network or device is found
+     */
+    void updatePortState(NetworkId networkId, DeviceId deviceId,
+                                  PortNumber portNumber, boolean isEnabled);
+
+    /**
+     * Removes the specified virtual port.
+     *
+     * @param networkId  network identifier
+     * @param deviceId   device identifier
+     * @param portNumber port number
+     * @throws org.onlab.util.ItemNotFoundException if no such network or port found
+     */
+    void removeVirtualPort(NetworkId networkId, DeviceId deviceId, PortNumber portNumber);
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkEvent.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkEvent.java
new file mode 100644
index 0000000..3f96496
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkEvent.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * 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 org.onosproject.event.AbstractEvent;
+
+/**
+ * Describes virtual network event.
+ */
+public class VirtualNetworkEvent extends AbstractEvent<VirtualNetworkEvent.Type, NetworkId> {
+
+    /**
+     * Type of virtual network events.
+     */
+    public enum Type {
+        /**
+         * Signifies that a new tenant identifier was registered.
+         */
+        TENANT_REGISTERED,
+        /**
+         * Signifies that a tenant identifier was unregistered.
+         */
+        TENANT_UNREGISTERED,
+        /**
+         * Signifies that a new virtual network was added.
+         */
+        NETWORK_ADDED,
+        /**
+         * Signifies that a virtual network was updated.
+         */
+        NETWORK_UPDATED,
+        /**
+         * Signifies that a virtual network was removed.
+         */
+        NETWORK_REMOVED,
+        /**
+         * Signifies that a new virtual network device was added.
+         */
+        VIRTUAL_DEVICE_ADDED,
+        /**
+         * Signifies that a virtual network device was updated.
+         */
+        VIRTUAL_DEVICE_UPDATED,
+        /**
+         * Signifies that a virtual network device was removed.
+         */
+        VIRTUAL_DEVICE_REMOVED,
+        /**
+         * Signifies that a new virtual network port was added.
+         */
+        VIRTUAL_PORT_ADDED,
+        /**
+         * Signifies that a virtual network port was updated.
+         */
+        VIRTUAL_PORT_UPDATED,
+        /**
+         * Signifies that a virtual network port was removed.
+         */
+        VIRTUAL_PORT_REMOVED
+    }
+
+    private final VirtualDevice virtualDevice;
+    private final VirtualPort virtualPort;
+
+    /**
+     * Creates an event of a given type and for the specified subject.
+     *
+     * @param type        event type
+     * @param subject     event subject
+     */
+    public VirtualNetworkEvent(Type type, NetworkId subject) {
+        this(type, subject, null, null);
+    }
+
+    /**
+     * Creates an event of a given type and for the specified subject and the
+     * virtual device.
+     *
+     * @param type          event type
+     * @param subject       event subject
+     * @param virtualDevice virtual device
+     */
+    public VirtualNetworkEvent(Type type, NetworkId subject, VirtualDevice virtualDevice) {
+        this(type, subject, virtualDevice, null);
+    }
+
+    /**
+     * Creates an event of a given type and for the specified subject, virtual device and
+     * virtual port.
+     *
+     * @param type          event type
+     * @param subject       event subject
+     * @param virtualDevice virtual device
+     * @param virtualPort   virtual port
+     */
+    public VirtualNetworkEvent(Type type, NetworkId subject, VirtualDevice virtualDevice,
+                                VirtualPort virtualPort) {
+        super(type, subject);
+        this.virtualDevice = virtualDevice;
+        this.virtualPort = virtualPort;
+    }
+
+    /**
+     * Creates an event of a given type and for the specified subject and time.
+     *
+     * @param type        event type
+     * @param subject     event subject
+     * @param time        occurrence time
+     */
+    public VirtualNetworkEvent(Type type, NetworkId subject, long time) {
+        this(type, subject, null, null, time);
+    }
+
+    /**
+     * Creates an event of a given type and for the specified subject, virtual device and time.
+     *
+     * @param type          event type
+     * @param subject       event subject
+     * @param virtualDevice virtual device
+     * @param time          occurrence time
+     */
+    public VirtualNetworkEvent(Type type, NetworkId subject, VirtualDevice virtualDevice,
+                               long time) {
+        this(type, subject, virtualDevice, null, time);
+    }
+
+    /**
+     * Creates an event of a given type and for the specified subject, virtual port and time.
+     *
+     * @param type          device event type
+     * @param subject       event subject
+     * @param virtualPort   virtual port
+     * @param time          occurrence time
+     */
+    public VirtualNetworkEvent(Type type, NetworkId subject, VirtualPort virtualPort,
+                               long time) {
+        this(type, subject, null, virtualPort, time);
+    }
+
+    /**
+     * Creates an event of a given type and for the specified subject, virtual device,
+     * virtual port and time.
+     *
+     * @param type          device event type
+     * @param subject       event subject
+     * @param virtualDevice virtual device
+     * @param virtualPort   virtual port
+     * @param time          occurrence time
+     */
+    private VirtualNetworkEvent(Type type, NetworkId subject, VirtualDevice virtualDevice,
+                                VirtualPort virtualPort, long time) {
+        super(type, subject, time);
+        this.virtualDevice = virtualDevice;
+        this.virtualPort = virtualPort;
+    }
+
+    /**
+     * Returns virtual device affected by event - may be null (for events relating to
+     * tenants and virtual networks).
+     *
+     * @return virtual device
+     */
+    public VirtualDevice virtualDevice() {
+        return virtualDevice;
+    }
+
+    /**
+     * Returns virtual port affected by event - may be null (for events relating to
+     * tenants, virtual networks and virtual devices).
+     *
+     * @return virtual port
+     */
+    public VirtualPort virtualPort() {
+        return virtualPort;
+    }
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkFlowObjectiveStore.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkFlowObjectiveStore.java
new file mode 100644
index 0000000..c118958
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkFlowObjectiveStore.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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 org.onosproject.net.behaviour.NextGroup;
+import org.onosproject.net.flowobjective.FlowObjectiveStoreDelegate;
+import org.onosproject.net.flowobjective.ObjectiveEvent;
+
+import java.util.Map;
+
+/**
+ * The flow objective store for virtual networks.
+ */
+public interface VirtualNetworkFlowObjectiveStore
+        extends VirtualStore<ObjectiveEvent, FlowObjectiveStoreDelegate> {
+
+    /**
+     * Adds a NextGroup to the store, by mapping it to the nextId as key,
+     * and replacing any previous mapping.
+     *
+     * @param networkId a virtual network identifier
+     * @param nextId an integer
+     * @param group a next group opaque object
+     */
+    void putNextGroup(NetworkId networkId, Integer nextId, NextGroup group);
+
+    /**
+     * Fetch a next group from the store.
+     *
+     * @param networkId a virtual network identifier
+     * @param nextId an integer used as key
+     * @return a next group, or null if group was not found
+     */
+    NextGroup getNextGroup(NetworkId networkId, Integer nextId);
+
+    /**
+     * Remove a next group mapping from the store.
+     *
+     * @param networkId a virtual network identifier
+     * @param nextId  the key to remove from the store.
+     * @return the next group which mapped to the nextId and is now removed, or
+     *          null if no group mapping existed in the store
+     */
+    NextGroup removeNextGroup(NetworkId networkId, Integer nextId);
+
+    /**
+     * Fetch all groups from the store and their mapping to nextIds.
+     *
+     * @param networkId a virtual network identifier
+     * @return a map that represents the current snapshot of Next-ids to NextGroups
+     */
+    Map<Integer, NextGroup> getAllGroups(NetworkId networkId);
+
+    /**
+     * Allocates a next objective id. This id is globally unique.
+     *
+     * @param networkId a virtual network identifier
+     * @return an integer
+     */
+    int allocateNextId(NetworkId networkId);
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkFlowRuleStore.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkFlowRuleStore.java
new file mode 100644
index 0000000..6b532c3
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkFlowRuleStore.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * 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 org.onosproject.net.DeviceId;
+import org.onosproject.net.flow.FlowEntry;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.oldbatch.FlowRuleBatchEvent;
+import org.onosproject.net.flow.oldbatch.FlowRuleBatchOperation;
+import org.onosproject.net.flow.FlowRuleEvent;
+import org.onosproject.net.flow.FlowRuleStoreDelegate;
+import org.onosproject.net.flow.TableStatisticsEntry;
+
+import java.util.List;
+
+/**
+ * Manages inventory of flow rules for virtual networks;
+ * not intended for direct use.
+ */
+public interface VirtualNetworkFlowRuleStore
+        extends VirtualStore<FlowRuleBatchEvent, FlowRuleStoreDelegate> {
+    /**
+     * Returns the number of flow rule in the store.
+     *
+     * @param networkId virtual network identifier
+     * @return number of flow rules
+     */
+    int getFlowRuleCount(NetworkId networkId);
+
+    /**
+     * Returns the stored flow.
+     *
+     * @param networkId virtual network identifier
+     * @param rule the rule to look for
+     * @return a flow rule
+     */
+    FlowEntry getFlowEntry(NetworkId networkId, FlowRule rule);
+
+    /**
+     * Returns the flow entries associated with a device.
+     *
+     * @param networkId virtual network identifier
+     * @param deviceId the device ID
+     * @return the flow entries
+     */
+    Iterable<FlowEntry> getFlowEntries(NetworkId networkId, DeviceId deviceId);
+
+    /**
+     * Stores a batch of flow rules.
+     *
+     * @param networkId virtual network identifier
+     * @param batchOperation batch of flow rules.
+     *           A batch can contain flow rules for a single device only.
+     *
+     */
+    void storeBatch(NetworkId networkId, FlowRuleBatchOperation batchOperation);
+
+    /**
+     * Invoked on the completion of a storeBatch operation.
+     *
+     * @param networkId virtual network identifier
+     * @param event flow rule batch event
+     */
+    void batchOperationComplete(NetworkId networkId, FlowRuleBatchEvent event);
+
+    /**
+     * Marks a flow rule for deletion. Actual deletion will occur
+     * when the provider indicates that the flow has been removed.
+     *
+     * @param networkId virtual network identifier
+     * @param rule the flow rule to delete
+     */
+    void deleteFlowRule(NetworkId networkId, FlowRule rule);
+
+    /**
+     * Stores a new flow rule, or updates an existing entry.
+     *
+     * @param networkId virtual network identifier
+     * @param rule the flow rule to add or update
+     * @return flow_added event, or null if just an update
+     */
+    FlowRuleEvent addOrUpdateFlowRule(NetworkId networkId, FlowEntry rule);
+
+    /**
+     * Removes an existing flow entry.
+     *
+     * @param rule the flow entry to remove
+     * @param networkId virtual network identifier
+     * @return flow_removed event, or null if nothing removed
+     */
+    FlowRuleEvent removeFlowRule(NetworkId networkId, FlowEntry rule);
+
+    /**
+     * Marks a flow rule as PENDING_ADD during retry.
+     *
+     * Emits flow_update event if the state is changed
+     *
+     * @param networkId virtual network identifier
+     * @param rule the flow rule that is retrying
+     * @return flow_updated event, or null if nothing updated
+     */
+    FlowRuleEvent pendingFlowRule(NetworkId networkId, FlowEntry rule);
+
+    /**
+     * Removes all flow entries of given device from store.
+     *
+     * @param networkId virtual network identifier
+     * @param deviceId device id
+     */
+    default void purgeFlowRule(NetworkId networkId, DeviceId deviceId) {}
+
+    /**
+     * Removes all flow entries from store.
+     *
+     * @param networkId virtual network identifier
+     */
+    void purgeFlowRules(NetworkId networkId);
+
+    /**
+     * Updates the flow table statistics of the specified device using
+     * the given statistics.
+     *
+     * @param networkId virtual network identifier
+     * @param deviceId    device identifier
+     * @param tableStats   list of table statistics
+     * @return ready to send event describing what occurred;
+     */
+    FlowRuleEvent updateTableStatistics(NetworkId networkId, DeviceId deviceId,
+                                        List<TableStatisticsEntry> tableStats);
+
+    /**
+     * Returns the flow table statistics associated with a device.
+     *
+     * @param networkId virtual network identifier
+     * @param deviceId the device ID
+     * @return the flow table statistics
+     */
+    Iterable<TableStatisticsEntry> getTableStatistics(NetworkId networkId, DeviceId deviceId);
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkGroupStore.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkGroupStore.java
new file mode 100644
index 0000000..d080524
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkGroupStore.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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 org.onosproject.core.GroupId;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.group.Group;
+import org.onosproject.net.group.GroupBuckets;
+import org.onosproject.net.group.GroupDescription;
+import org.onosproject.net.group.GroupEvent;
+import org.onosproject.net.group.GroupKey;
+import org.onosproject.net.group.GroupOperation;
+import org.onosproject.net.group.GroupStoreDelegate;
+
+import java.util.Collection;
+
+/**
+ * Manages inventory of groups per virtual network and virtual device;
+ * not intended for direct use.
+ */
+public interface VirtualNetworkGroupStore
+        extends VirtualStore<GroupEvent, GroupStoreDelegate> {
+
+    enum UpdateType {
+        /**
+         * Modify existing group entry by adding provided information.
+         */
+        ADD,
+        /**
+         * Modify existing group by removing provided information from it.
+         */
+        REMOVE,
+        /**
+         * Modify existing group entry by setting the provided information,
+         * overwriting the previous group entry entirely.
+         */
+        SET
+    }
+
+    /**
+     * Returns the number of groups for the specified virtual device in the store.
+     *
+     * @param networkId the virtual network ID
+     * @param deviceId the device ID
+     * @return number of groups for the specified device
+     */
+    int getGroupCount(NetworkId networkId, DeviceId deviceId);
+
+    /**
+     * Returns the groups associated with a virtual device.
+     *
+     * @param networkId the virtual network ID
+     * @param deviceId the device ID
+     * @return the group entries
+     */
+    Iterable<Group> getGroups(NetworkId networkId, DeviceId deviceId);
+
+    /**
+     * Returns the stored group entry in a virtual network.
+     *
+     * @param networkId the virtual network ID
+     * @param deviceId the device ID
+     * @param appCookie the group key
+     * @return a group associated with the key
+     */
+    Group getGroup(NetworkId networkId, DeviceId deviceId, GroupKey appCookie);
+
+    /**
+     * Returns the stored group entry for an id.
+     *
+     * @param networkId the virtual network ID
+     * @param deviceId the device ID
+     * @param groupId the group identifier
+     * @return a group associated with the key
+     */
+    Group getGroup(NetworkId networkId, DeviceId deviceId, GroupId groupId);
+
+    /**
+     * Stores a new group entry using the information from group description
+     * for a virtual network.
+     *
+     * @param networkId the virtual network ID
+     * @param groupDesc group description to be used to store group entry
+     */
+    void storeGroupDescription(NetworkId networkId, GroupDescription groupDesc);
+
+    /**
+     * Updates the existing group entry with the information
+     * from group description.
+     *
+     * @param networkId the virtual network ID
+     * @param deviceId the device ID
+     * @param oldAppCookie the current group key
+     * @param type update type
+     * @param newBuckets group buckets for updates
+     * @param newAppCookie optional new group key
+     */
+    void updateGroupDescription(NetworkId networkId,
+                                DeviceId deviceId,
+                                GroupKey oldAppCookie,
+                                UpdateType type,
+                                GroupBuckets newBuckets,
+                                GroupKey newAppCookie);
+
+    /**
+     * Triggers deleting the existing group entry.
+     *
+     * @param networkId the virtual network ID
+     * @param deviceId the device ID
+     * @param appCookie the group key
+     */
+    void deleteGroupDescription(NetworkId networkId,
+                                DeviceId deviceId,
+                                GroupKey appCookie);
+
+    /**
+     * Stores a new group entry, or updates an existing entry.
+     *
+     * @param networkId the virtual network ID
+     * @param group group entry
+     */
+    void addOrUpdateGroupEntry(NetworkId networkId, Group group);
+
+    /**
+     * Removes the group entry from store.
+     *
+     * @param networkId the virtual network ID
+     * @param group group entry
+     */
+    void removeGroupEntry(NetworkId networkId, Group group);
+
+    /**
+     * Removes all group entries of given device from store.
+     *
+     * @param networkId the virtual network ID
+     * @param deviceId device id
+     */
+    void purgeGroupEntry(NetworkId networkId, DeviceId deviceId);
+
+    /**
+     * Removes all group entries from store.
+     *
+     * @param networkId the virtual network ID
+     */
+    default void purgeGroupEntries(NetworkId networkId) {}
+
+    /**
+     * A group entry that is present in switch but not in the store.
+     *
+     * @param networkId the virtual network ID
+     * @param group group entry
+     */
+    void addOrUpdateExtraneousGroupEntry(NetworkId networkId, Group group);
+
+    /**
+     * Remove the group entry from extraneous database.
+     *
+     * @param networkId the virtual network ID
+     * @param group group entry
+     */
+    void removeExtraneousGroupEntry(NetworkId networkId, Group group);
+
+    /**
+     * Returns the extraneous groups associated with a device.
+     *
+     * @param networkId the virtual network ID
+     * @param deviceId the device ID
+     *
+     * @return the extraneous group entries
+     */
+    Iterable<Group> getExtraneousGroups(NetworkId networkId, DeviceId deviceId);
+
+    /**
+     * Indicates the first group audit is completed.
+     *
+     * @param networkId the virtual network ID
+     * @param deviceId the device ID
+     * @param completed initial audit status
+     */
+    void deviceInitialAuditCompleted(NetworkId networkId, DeviceId deviceId, boolean completed);
+
+    /**
+     * Retrieves the initial group audit status for a device.
+     *
+     * @param networkId the virtual network ID
+     * @param deviceId the device ID
+     *
+     * @return initial group audit status
+     */
+    boolean deviceInitialAuditStatus(NetworkId networkId, DeviceId deviceId);
+
+    /**
+     * Indicates the group operations failed.
+     *
+     * @param networkId the virtual network ID
+     * @param deviceId the device ID
+     * @param operation the group operation failed
+     */
+    void groupOperationFailed(NetworkId networkId, DeviceId deviceId, GroupOperation operation);
+
+    /**
+     * Submits the group metrics to store for a given device ID.
+     *
+     * @param networkId the virtual network ID
+     * @param deviceId the device ID
+     * @param groupEntries the group entries as received from southbound
+     */
+    void pushGroupMetrics(NetworkId networkId, DeviceId deviceId, Collection<Group> groupEntries);
+
+    /**
+     * Indicates failover within a failover group.
+     *
+     * @param networkId the virtual network ID
+     * @param failoverGroups groups to notify
+     */
+    void notifyOfFailovers(NetworkId networkId, Collection<Group> failoverGroups);
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkIntent.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkIntent.java
new file mode 100644
index 0000000..817db21
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkIntent.java
@@ -0,0 +1,260 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * 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.ResourceGroup;
+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 Builder appId(ApplicationId appId) {
+            return (Builder) super.appId(appId);
+        }
+
+        @Override
+        public Builder key(Key key) {
+            return (Builder) super.key(key);
+        }
+
+        @Override
+        public Builder selector(TrafficSelector selector) {
+            return (Builder) super.selector(selector);
+        }
+
+        @Override
+        public Builder treatment(TrafficTreatment treatment) {
+            return (Builder) super.treatment(treatment);
+        }
+
+        @Override
+        public Builder constraints(List<Constraint> constraints) {
+            return (Builder) super.constraints(constraints);
+        }
+
+        @Override
+        public Builder priority(int priority) {
+            return (Builder) super.priority(priority);
+        }
+
+        @Override
+        public Builder resourceGroup(ResourceGroup resourceGroup) {
+            return (Builder) super.resourceGroup(resourceGroup);
+        }
+
+        /**
+         * 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,
+                    resourceGroup
+            );
+        }
+    }
+
+
+    /**
+     * 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,
+                                 ResourceGroup resourceGroup) {
+        super(appId, key, Collections.emptyList(), selector, treatment, constraints,
+              priority, resourceGroup);
+
+        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())
+                .add("resourceGroup", resourceGroup())
+                .toString();
+    }
+
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkIntentStore.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkIntentStore.java
new file mode 100644
index 0000000..f8b42c1
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkIntentStore.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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 org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentData;
+import org.onosproject.net.intent.IntentEvent;
+import org.onosproject.net.intent.IntentState;
+import org.onosproject.net.intent.IntentStoreDelegate;
+import org.onosproject.net.intent.Key;
+
+import java.util.List;
+
+public interface VirtualNetworkIntentStore
+        extends VirtualStore<IntentEvent, IntentStoreDelegate> {
+
+    /**
+     * Returns the number of intents in the store.
+     *
+     * @param networkId the virtual network identifier
+     * @return the number of intents in the store
+     */
+    long getIntentCount(NetworkId networkId);
+
+    /**
+     * Returns an iterable of all intents in the store.
+     *
+     * @param networkId the virtual network identifier
+     * @return iterable  of all intents
+     */
+    Iterable<Intent> getIntents(NetworkId networkId);
+
+    /**
+     * Returns an iterable of all intent data objects in the store.
+     *
+     * @param networkId the virtual network identifier
+     * @param localOnly should only intents for which this instance is master
+     *                  be returned
+     * @param olderThan specified duration in milliseconds (0 for "now")
+     * @return iterable of all intent data objects
+     */
+    Iterable<IntentData> getIntentData(NetworkId networkId, boolean localOnly,
+                                       long olderThan);
+
+    /**
+     * Returns the state of the specified intent.
+     *
+     * @param networkId the virtual network identifier
+     * @param intentKey intent identification
+     * @return current intent state
+     */
+    IntentState getIntentState(NetworkId networkId, Key intentKey);
+
+    /**
+     * Returns the list of the installable events associated with the specified
+     * original intent.
+     *
+     * @param networkId the virtual network identifier
+     * @param intentKey original intent identifier
+     * @return compiled installable intents, or null if no installables exist
+     */
+    List<Intent> getInstallableIntents(NetworkId networkId, Key intentKey);
+
+    /**
+     * Writes an IntentData object to the store.
+     *
+     * @param networkId the virtual network identifier
+     * @param newData new intent data to write
+     */
+    void write(NetworkId networkId, IntentData newData);
+
+    /**
+     * Writes a batch of IntentData objects to the store. A batch has no
+     * semantics, this is simply a convenience API.
+     *
+     * @param networkId the virtual network identifier
+     * @param updates collection of intent data objects to write
+     */
+    void batchWrite(NetworkId networkId, Iterable<IntentData> updates);
+
+    /**
+     * Returns the intent with the specified identifier.
+     *
+     * @param networkId the virtual network identifier
+     * @param key key
+     * @return intent or null if not found
+     */
+    Intent getIntent(NetworkId networkId, Key key);
+
+    /**
+     * Returns the intent data object associated with the specified key.
+     *
+     * @param networkId the virtual network identifier
+     * @param key key to look up
+     * @return intent data object
+     */
+    IntentData getIntentData(NetworkId networkId, Key key);
+
+    /**
+     * Adds a new operation, which should be persisted and delegated.
+     *
+     * @param networkId the virtual network identifier
+     * @param intent operation
+     */
+    void addPending(NetworkId networkId, IntentData intent);
+
+    /**
+     * Checks to see whether the calling instance is the master for processing
+     * this intent, or more specifically, the key contained in this intent.
+     *
+     * @param networkId the virtual network identifier
+     * @param intentKey intentKey to check
+     * @return true if master; false, otherwise
+     */
+    //TODO better name
+    boolean isMaster(NetworkId networkId, Key intentKey);
+
+    /**
+     * Returns the intent requests pending processing.
+     *
+     * @param networkId the virtual network identifier
+     * @return pending intents
+     */
+    Iterable<Intent> getPending(NetworkId networkId);
+
+    /**
+     * Returns the intent data objects that are pending processing.
+     *
+     * @param networkId the virtual network identifier
+     * @return pending intent data objects
+     */
+    Iterable<IntentData> getPendingData(NetworkId networkId);
+
+    /**
+     * Returns the intent data object that are pending processing for a specfied
+     * key.
+     *
+     * @param networkId the virtual network identifier
+     * @param intentKey key to look up
+     * @return pending intent data object
+     */
+    IntentData getPendingData(NetworkId networkId, Key intentKey);
+
+    /**
+     * Returns the intent data objects that are pending processing for longer
+     * than the specified duration.
+     *
+     * @param networkId the virtual network identifier
+     * @param localOnly  should only intents for which this instance is master
+     *                   be returned
+     * @param olderThan specified duration in milliseconds (0 for "now")
+     * @return pending intent data objects
+     */
+    Iterable<IntentData> getPendingData(NetworkId networkId, boolean localOnly, long olderThan);
+
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkListener.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkListener.java
new file mode 100644
index 0000000..cc6d663
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkListener.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * 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 org.onosproject.event.EventListener;
+
+/**
+ * Represents entity capable of receiving virtual network events.
+ */
+public interface VirtualNetworkListener extends EventListener<VirtualNetworkEvent> {
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkMastershipStore.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkMastershipStore.java
new file mode 100644
index 0000000..31fdfcd
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkMastershipStore.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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 org.onosproject.cluster.NodeId;
+import org.onosproject.cluster.RoleInfo;
+import org.onosproject.mastership.MastershipEvent;
+import org.onosproject.mastership.MastershipInfo;
+import org.onosproject.mastership.MastershipStoreDelegate;
+import org.onosproject.mastership.MastershipTerm;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.MastershipRole;
+
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * Manages inventory of mastership roles for devices, across controller
+ * instances for virtual networks; not intended for direct use.
+ */
+public interface VirtualNetworkMastershipStore
+        extends VirtualStore<MastershipEvent, MastershipStoreDelegate> {
+
+    // three things to map: NodeId, DeviceId, MastershipRole
+
+    /**
+     * Requests role of the local node for the specified device.
+     *
+     * @param networkId the virtual network identifier
+     * @param deviceId  the device identifier
+     * @return established or newly negotiated mastership role
+     */
+    CompletableFuture<MastershipRole> requestRole(NetworkId networkId, DeviceId deviceId);
+
+    /**
+     * Returns the role of a device for a specific controller instance.
+     *
+     * @param networkId virtual network identifier
+     * @param nodeId    the instance identifier
+     * @param deviceId  the device identifiers
+     * @return the role
+     */
+    MastershipRole getRole(NetworkId networkId, NodeId nodeId, DeviceId deviceId);
+
+    /**
+     * Returns the master for a device.
+     *
+     * @param networkId virtual network identifier
+     * @param deviceId  the device identifier
+     * @return the instance identifier of the master
+     */
+    NodeId getMaster(NetworkId networkId, DeviceId deviceId);
+
+    /**
+     * Returns the master and backup nodes for a device.
+     *
+     * @param networkId virtual network identifier
+     * @param deviceId  the device identifier
+     * @return a RoleInfo containing controller IDs
+     */
+    RoleInfo getNodes(NetworkId networkId, DeviceId deviceId);
+
+    /**
+     * Returns the mastership info for a device.
+     *
+     * @param networkId virtual network identifier
+     * @param deviceId  the device identifier
+     * @return the mastership info
+     */
+    MastershipInfo getMastership(NetworkId networkId, DeviceId deviceId);
+
+    /**
+     * Returns the devices that a controller instance is master of.
+     *
+     * @param networkId virtual network identifier
+     * @param nodeId    the instance identifier
+     * @return a set of device identifiers
+     */
+    Set<DeviceId> getDevices(NetworkId networkId, NodeId nodeId);
+
+
+    /**
+     * Sets a device's role for a specified controller instance.
+     *
+     * @param networkId virtual network identifier
+     * @param nodeId    controller instance identifier
+     * @param deviceId  device identifier
+     * @return a mastership event
+     */
+    CompletableFuture<MastershipEvent> setMaster(NetworkId networkId,
+                                                 NodeId nodeId, DeviceId deviceId);
+
+    /**
+     * Returns the current master and number of past mastership hand-offs
+     * (terms) for a device.
+     *
+     * @param networkId virtual network identifier
+     * @param deviceId  the device identifier
+     * @return the current master's ID and the term value for device, or null
+     */
+    MastershipTerm getTermFor(NetworkId networkId, DeviceId deviceId);
+
+    /**
+     * Sets a controller instance's mastership role to STANDBY for a device.
+     * If the role is MASTER, another controller instance will be selected
+     * as a candidate master.
+     *
+     * @param networkId virtual network identifier
+     * @param nodeId    the controller instance identifier
+     * @param deviceId  device to revoke mastership role for
+     * @return a mastership event
+     */
+    CompletableFuture<MastershipEvent> setStandby(NetworkId networkId,
+                                                  NodeId nodeId, DeviceId deviceId);
+
+    /**
+     * Allows a controller instance to give up its current role for a device.
+     * If the role is MASTER, another controller instance will be selected
+     * as a candidate master.
+     *
+     * @param networkId virtual network identifier
+     * @param nodeId    the controller instance identifier
+     * @param deviceId  device to revoke mastership role for
+     * @return a mastership event
+     */
+    CompletableFuture<MastershipEvent> relinquishRole(NetworkId networkId,
+                                                      NodeId nodeId, DeviceId deviceId);
+
+    /**
+     * Removes all the roles for the specified controller instance.
+     * If the role was MASTER, another controller instance will be selected
+     * as a candidate master.
+     *
+     * @param networkId virtual network identifier
+     * @param nodeId    the controller instance identifier
+     */
+    void relinquishAllRole(NetworkId networkId, NodeId nodeId);
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkMeterStore.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkMeterStore.java
new file mode 100644
index 0000000..954f66b
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkMeterStore.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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 org.onosproject.net.DeviceId;
+import org.onosproject.net.meter.Meter;
+import org.onosproject.net.meter.MeterEvent;
+import org.onosproject.net.meter.MeterFailReason;
+import org.onosproject.net.meter.MeterFeatures;
+import org.onosproject.net.meter.MeterFeaturesKey;
+import org.onosproject.net.meter.MeterKey;
+import org.onosproject.net.meter.MeterOperation;
+import org.onosproject.net.meter.MeterStoreDelegate;
+import org.onosproject.net.meter.MeterStoreResult;
+
+import java.util.Collection;
+import java.util.concurrent.CompletableFuture;
+
+public interface VirtualNetworkMeterStore
+        extends VirtualStore<MeterEvent, MeterStoreDelegate> {
+
+    /**
+     * Adds a meter to the store.
+     *
+     * @param networkId a virtual network identifier
+     * @param meter a meter
+     * @return a future indicating the result of the store operation
+     */
+    CompletableFuture<MeterStoreResult> storeMeter(NetworkId networkId, Meter meter);
+
+    /**
+     * Deletes a meter from the store.
+     *
+     * @param networkId a virtual network identifier
+     * @param meter a meter
+     * @return a future indicating the result of the store operation
+     */
+    CompletableFuture<MeterStoreResult> deleteMeter(NetworkId networkId, Meter meter);
+
+
+    /**
+     * Adds the meter features to the store.
+     *
+     * @param networkId a virtual network identifier
+     * @param meterfeatures the meter features
+     * @return the result of the store operation
+     */
+    MeterStoreResult storeMeterFeatures(NetworkId networkId, MeterFeatures meterfeatures);
+
+    /**
+     * Deletes the meter features from the store.
+     *
+     * @param networkId a virtual network identifier
+     * @param deviceId the device id
+     * @return a future indicating the result of the store operation
+     */
+    MeterStoreResult deleteMeterFeatures(NetworkId networkId, DeviceId deviceId);
+
+
+    /**
+     * Updates a meter whose meter id is the same as the passed meter.
+     *
+     * @param networkId a virtual network identifier
+     * @param meter a new meter
+     * @return a future indicating the result of the store operation
+     */
+    CompletableFuture<MeterStoreResult> updateMeter(NetworkId networkId, Meter meter);
+
+    /**
+     * Updates a given meter's state with the provided state.
+     *
+     * @param networkId a virtual network identifier
+     * @param meter a meter
+     */
+    void updateMeterState(NetworkId networkId, Meter meter);
+
+    /**
+     * Obtains a meter matching the given meter key.
+     *
+     * @param networkId a virtual network identifier
+     * @param key a meter key
+     * @return a meter
+     */
+    Meter getMeter(NetworkId networkId, MeterKey key);
+
+    /**
+     * Returns all meters stored in the store.
+     *
+     * @param networkId a virtual network identifier
+     * @return a collection of meters
+     */
+    Collection<Meter> getAllMeters(NetworkId networkId);
+
+    /**
+     * Update the store by deleting the failed meter.
+     * Notifies the delegate that the meter failed to allow it
+     * to nofity the app.
+     *
+     * @param networkId a virtual network identifier
+     * @param op a failed meter operation
+     * @param reason a failure reason
+     */
+    void failedMeter(NetworkId networkId, MeterOperation op, MeterFailReason reason);
+
+    /**
+     * Delete this meter immediately.
+     *
+     * @param networkId a virtual network identifier
+     * @param m a meter
+     */
+    void deleteMeterNow(NetworkId networkId, Meter m);
+
+    /**
+     * Retrieve maximum meters available for the device.
+     *
+     * @param networkId a virtual network identifier
+     * @param key the meter features key
+     * @return the maximum number of meters supported by the device
+     */
+    long getMaxMeters(NetworkId networkId, MeterFeaturesKey key);
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkPacketStore.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkPacketStore.java
new file mode 100644
index 0000000..4cf5cb9
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkPacketStore.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * 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 org.onosproject.net.packet.OutboundPacket;
+import org.onosproject.net.packet.PacketEvent;
+import org.onosproject.net.packet.PacketRequest;
+import org.onosproject.net.packet.PacketStoreDelegate;
+
+import java.util.List;
+
+public interface VirtualNetworkPacketStore
+        extends VirtualStore<PacketEvent, PacketStoreDelegate> {
+    /**
+     * Decides which instance should emit the packet and forwards the packet to
+     * that instance. The relevant PacketManager is notified via the
+     * PacketStoreDelegate that it should emit the packet.
+     *
+     * @param networkId a virtual network identifier
+     * @param packet the packet to emit
+     */
+    void emit(NetworkId networkId, OutboundPacket packet);
+
+    /**
+     * Requests intercept of packets that match the given selector.
+     *
+     * @param networkId a virtual network identifier
+     * @param request a packet request
+     */
+    void requestPackets(NetworkId networkId, PacketRequest request);
+
+    /**
+     * Cancels intercept of packets that match the given selector.
+     *
+     * @param networkId a virtual network identifier
+     * @param request a packet request
+     */
+    void cancelPackets(NetworkId networkId, PacketRequest request);
+
+    /**
+     * Obtains all existing requests in the system.
+     *
+     * @param networkId a virtual network identifier
+     * @return list of packet requests in order of priority
+     */
+    List<PacketRequest> existingRequests(NetworkId networkId);
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkService.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkService.java
new file mode 100644
index 0000000..d0e4fd1
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkService.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * 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 org.onlab.osgi.ServiceDirectory;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.event.ListenerService;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.TenantId;
+
+import java.util.Set;
+
+/**
+ * Service for querying virtual network inventory.
+ */
+@Beta
+public interface VirtualNetworkService
+        extends ListenerService<VirtualNetworkEvent, VirtualNetworkListener> {
+
+    /**
+     * The topic used for obtaining globally unique ids.
+     */
+    String VIRTUAL_NETWORK_TOPIC = "virtual-network-ids";
+
+    /**
+     * Returns a collection of all virtual networks created on behalf of the
+     * specified tenant.
+     *
+     * @param tenantId tenant identifier
+     * @return collection of networks
+     * @throws org.onlab.util.ItemNotFoundException if no such network found
+     */
+    Set<VirtualNetwork> getVirtualNetworks(TenantId tenantId);
+
+    /**
+     * Returns the virtual network matching the network identifier.
+     *
+     * @param networkId virtual network identifier
+     * @return virtual network instance
+     * @throws org.onlab.util.ItemNotFoundException if no such network found
+     */
+    VirtualNetwork getVirtualNetwork(NetworkId networkId);
+
+    /**
+     * Returns {@code tenantId} for specified virtual network id.
+     *
+     * @param networkId virtual network identifier
+     * @return tenantId tenant identifier
+     * @throws org.onlab.util.ItemNotFoundException if no such network found
+     */
+    TenantId getTenantId(NetworkId networkId);
+
+    /**
+     * Returns a collection of all virtual devices in the specified network.
+     *
+     * @param networkId network identifier
+     * @return collection of devices
+     * @throws org.onlab.util.ItemNotFoundException if no such network found
+     */
+    Set<VirtualDevice> getVirtualDevices(NetworkId networkId);
+
+    /**
+     * Returns a collection of all virtual hosts in the specified network.
+     *
+     * @param networkId network identifier
+     * @return collection of hosts
+     * @throws org.onlab.util.ItemNotFoundException if no such network found
+     */
+    Set<VirtualHost> getVirtualHosts(NetworkId networkId);
+
+    /**
+     * Returns collection of all virtual links in the specified network.
+     *
+     * @param networkId network identifier
+     * @return collection of links
+     * @throws org.onlab.util.ItemNotFoundException if no such network found
+     */
+    Set<VirtualLink> getVirtualLinks(NetworkId networkId);
+
+    /**
+     * Returns list of all virtual ports of the specified device. If the
+     * device identifier is null then all of the virtual ports in the specified
+     * network will be returned.
+     *
+     * @param networkId network identifier
+     * @param deviceId  device identifier
+     * @return list of ports
+     * @throws org.onlab.util.ItemNotFoundException if no such network found
+     */
+    Set<VirtualPort> getVirtualPorts(NetworkId networkId, DeviceId deviceId);
+
+    /**
+     * Returns list of physical device identifier mapping with the virtual
+     * device in the specified network. The physical devices are specified by
+     * port mapping mechanism.
+     *
+     * @param networkId network identifier
+     * @param deviceId the virtual device identifier
+     * @return collection of the specified device's identifier
+     */
+    Set<DeviceId> getPhysicalDevices(NetworkId networkId, DeviceId deviceId);
+
+    /**
+     * Returns implementation of the specified service class for operating
+     * in the context of the given network.
+     * <p>
+     * The following services will be available:
+     * <ul>
+     * <li>{@link org.onosproject.net.device.DeviceService}</li>
+     * <li>{@link org.onosproject.net.link.LinkService}</li>
+     * <li>{@link org.onosproject.net.host.HostService}</li>
+     * <li>{@link org.onosproject.net.topology.TopologyService}</li>
+     * <li>{@link org.onosproject.net.topology.PathService}</li>
+     * <li>{@link org.onosproject.net.packet.PacketService}</li>
+     * <li>{@link org.onosproject.net.flow.FlowRuleService}</li>
+     * <li>{@link org.onosproject.net.flowobjective.FlowObjectiveService}</li>
+     * <li>{@link org.onosproject.net.intent.IntentService}</li>
+     * <li>{@link org.onosproject.mastership.MastershipService}</li>
+     * <li>{@link org.onosproject.mastership.MastershipAdminService}</li>
+     * <li>{@link org.onosproject.mastership.MastershipTermService}</li>
+     * </ul>
+     *
+     * @param networkId    network identifier
+     * @param serviceClass service class
+     * @param <T>          type of service
+     * @return implementation class
+     * @throws org.onlab.util.ItemNotFoundException    if no such network found
+     * @throws org.onlab.osgi.ServiceNotFoundException if no implementation found
+     */
+    <T> T get(NetworkId networkId, Class<T> serviceClass);
+
+    /**
+     * Returns service directory.
+     *
+     * @return a service directory
+     */
+    ServiceDirectory getServiceDirectory();
+
+    /**
+     * Returns the application identifier for a virtual network.
+     *
+     * @param networkId network identifier
+     * @return an representative application identifier for a virtual network
+     */
+    ApplicationId getVirtualNetworkApplicationId(NetworkId networkId);
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkStore.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkStore.java
new file mode 100644
index 0000000..de74333
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkStore.java
@@ -0,0 +1,278 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * 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 org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
+import org.onosproject.incubator.net.tunnel.TunnelId;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.HostId;
+import org.onosproject.net.HostLocation;
+import org.onosproject.net.Link;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.TenantId;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.store.Store;
+
+import java.util.Set;
+
+/**
+ * Mechanism for distributing and storing virtual network model information.
+ */
+public interface VirtualNetworkStore
+        extends Store<VirtualNetworkEvent, VirtualNetworkStoreDelegate> {
+
+    /**
+     * Adds a new tenant ID to the store.
+     *
+     * @param tenantId tenant identifier
+     */
+    void addTenantId(TenantId tenantId);
+
+    /**
+     * Removes the specified tenant ID from the store.
+     *
+     * @param tenantId tenant identifier
+     */
+    void removeTenantId(TenantId tenantId);
+
+    /**
+     * Returns set of registered tenant IDs.
+     *
+     * @return set of tenant identifiers
+     */
+    Set<TenantId> getTenantIds();
+
+    /**
+     * Adds a new virtual network for the specified tenant to the store.
+     *
+     * @param tenantId tenant identifier
+     * @return the virtual network
+     */
+    VirtualNetwork addNetwork(TenantId tenantId);
+
+    /**
+     * Removes the specified virtual network from the store.
+     *
+     * @param networkId network identifier
+     */
+    void removeNetwork(NetworkId networkId);
+
+    /**
+     * Adds a new virtual device to the store. This device will have no ports.
+     *
+     * @param networkId network identifier
+     * @param deviceId  device identifier
+     * @return the virtual device
+     */
+    VirtualDevice addDevice(NetworkId networkId, DeviceId deviceId);
+
+    /**
+     * Removes the specified virtual device from the given network.
+     *
+     * @param networkId network identifier
+     * @param deviceId  device identifier
+     */
+    void removeDevice(NetworkId networkId, DeviceId deviceId);
+
+    /**
+     * Adds a new virtual host to the store.
+     *
+     * @param networkId network identifier
+     * @param hostId    host identifier
+     * @param mac       mac address
+     * @param vlan      vlan identifier
+     * @param location  host location
+     * @param ips       set of ip addresses
+     * @return the virtual host
+     */
+    VirtualHost addHost(NetworkId networkId, HostId hostId, MacAddress mac,
+                        VlanId vlan, HostLocation location, Set<IpAddress> ips);
+
+    /**
+     * Removes the specified virtual host from the store.
+     *
+     * @param networkId network identifier
+     * @param hostId    host identifier
+     */
+    void removeHost(NetworkId networkId, HostId hostId);
+
+    /**
+     * Adds a new virtual link.
+     *
+     * @param networkId  network identifier
+     * @param src        source end-point of the link
+     * @param dst        destination end-point of the link
+     * @param state      link state
+     * @param realizedBy underlying tunnel identifier using which this link is realized
+     * @return the virtual link
+     */
+    VirtualLink addLink(NetworkId networkId, ConnectPoint src, ConnectPoint dst, Link.State state, TunnelId realizedBy);
+
+    /**
+     * Updates the tunnelId in the virtual link.
+     *
+     * @param virtualLink virtual link
+     * @param tunnelId    tunnel identifier
+     * @param state       link state
+     */
+    void updateLink(VirtualLink virtualLink, TunnelId tunnelId, Link.State state);
+
+    /**
+     * Removes the specified link from the store.
+     *
+     * @param networkId network identifier
+     * @param src       source connection point
+     * @param dst       destination connection point
+     * @return the virtual link
+     */
+    VirtualLink removeLink(NetworkId networkId, ConnectPoint src, ConnectPoint dst);
+
+    /**
+     * Adds a new virtual port to the network.
+     *
+     * @param networkId  network identifier
+     * @param deviceId   device identifier
+     * @param portNumber port number
+     * @param realizedBy underlying port which realizes the virtual port
+     * @return the virtual port
+     */
+    VirtualPort addPort(NetworkId networkId, DeviceId deviceId,
+                        PortNumber portNumber, ConnectPoint realizedBy);
+
+    /**
+     * Binds an existing virtual port to the network.
+     *
+     * @param networkId  network identifier
+     * @param deviceId   device identifier
+     * @param portNumber port number
+     * @param realizedBy underlying port which realizes the virtual port
+     */
+     void bindPort(NetworkId networkId, DeviceId deviceId,
+                        PortNumber portNumber, ConnectPoint realizedBy);
+
+    /**
+     * Updates port state of an existing virtual port.
+     *
+     * @param networkId  network identifier
+     * @param deviceId   device identifier
+     * @param portNumber port number
+     * @param isEnabled  indicator whether the port is up and active
+     */
+     void updatePortState(NetworkId networkId, DeviceId deviceId,
+                        PortNumber portNumber, boolean isEnabled);
+
+    /**
+     * Removes the specified port from the given device and network.
+     *
+     * @param networkId  network identifier
+     * @param deviceId   device identifier
+     * @param portNumber port number
+     */
+    void removePort(NetworkId networkId, DeviceId deviceId, PortNumber portNumber);
+
+    /**
+     * Returns the list of networks.
+     *
+     * @param tenantId tenant identifier
+     * @return set of virtual networks
+     */
+    Set<VirtualNetwork> getNetworks(TenantId tenantId);
+
+    /**
+     * Returns the virtual network for the given network identifier.
+     *
+     * @param networkId network identifier
+     * @return the virtual network
+     */
+    VirtualNetwork getNetwork(NetworkId networkId);
+
+    /**
+     * Returns the list of devices in the specified virtual network.
+     *
+     * @param networkId network identifier
+     * @return set of virtual devices
+     */
+    Set<VirtualDevice> getDevices(NetworkId networkId);
+
+    /**
+     * Returns the list of hosts in the specified virtual network.
+     *
+     * @param networkId network identifier
+     * @return set of virtual hosts
+     */
+    Set<VirtualHost> getHosts(NetworkId networkId);
+
+    /**
+     * Returns the list of virtual links in the specified virtual network.
+     *
+     * @param networkId network identifier
+     * @return set of virtual links
+     */
+    Set<VirtualLink> getLinks(NetworkId networkId);
+
+    /**
+     * 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
+     */
+    VirtualLink getLink(NetworkId networkId, ConnectPoint src, ConnectPoint dst);
+
+    /**
+     * Returns the list of ports of the specified virtual device.
+     *
+     * @param networkId network identifier
+     * @param deviceId  device identifier
+     * @return set of virtual networks
+     */
+    Set<VirtualPort> getPorts(NetworkId networkId, DeviceId deviceId);
+
+    /**
+     * Adds the intent to tunnel identifier mapping to the store.
+     *
+     * @param intent   intent
+     * @param tunnelId tunnel identifier
+     * @deprecated in Kingfisher Release (1.10)
+     */
+    @Deprecated
+    void addTunnelId(Intent intent, TunnelId tunnelId);
+
+    /**
+     * Return the set of tunnel identifiers store against the intent.
+     *
+     * @param intent intent
+     * @return set of tunnel identifiers
+     * @deprecated in Kingfisher Release (1.10)
+     */
+    @Deprecated
+    Set<TunnelId> getTunnelIds(Intent intent);
+
+    /**
+     * Removes the intent to tunnel identifier mapping from the store.
+     *
+     * @param intent   intent
+     * @param tunnelId tunnel identifier
+     * @deprecated in Kingfisher Release (1.10)
+     */
+    @Deprecated
+    void removeTunnelId(Intent intent, TunnelId tunnelId);
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkStoreDelegate.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkStoreDelegate.java
new file mode 100644
index 0000000..202a0be
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualNetworkStoreDelegate.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * 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 org.onosproject.store.StoreDelegate;
+
+/**
+ * Network configuration store delegate abstraction.
+ */
+public interface VirtualNetworkStoreDelegate extends StoreDelegate<VirtualNetworkEvent> {
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualPacketContext.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualPacketContext.java
new file mode 100644
index 0000000..42b548a
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualPacketContext.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * 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 org.onosproject.net.packet.PacketContext;
+
+/**
+ * Represents context for processing an inbound packet for a virtual network,
+ * and (optionally) emitting a corresponding outbound packet.
+ */
+public interface VirtualPacketContext extends PacketContext {
+    /**
+     * Returns the network identifier.
+     *
+     * @return network id
+     */
+    NetworkId networkId();
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualPort.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualPort.java
new file mode 100644
index 0000000..a393e8e
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualPort.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * 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 org.onosproject.net.ConnectPoint;
+import org.onosproject.net.Port;
+
+/**
+ * Representation of a virtual port.
+ */
+@Beta
+public interface VirtualPort extends VirtualElement, Port {
+
+    /**
+     * Returns the underlying port using which this port is realized.
+     *
+     * @return underlying port which realizes this virtual port
+     */
+    ConnectPoint realizedBy();
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualPortDescription.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualPortDescription.java
new file mode 100644
index 0000000..0785641
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualPortDescription.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * 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 org.onosproject.net.device.PortDescription;
+
+/**
+ * Information about a virtual port.
+ */
+public interface VirtualPortDescription extends PortDescription {
+
+    // TODO: Add something about a requirement of virtual port.
+
+    /**
+     * Representation of the virtual port.
+     */
+    enum State {
+        /**
+         * Signifies that a virtual port is currently start.
+         */
+        START,
+
+        /**
+         * Signifies that a virtual port is currently stop.
+         */
+        STOP,
+
+        /**
+         * Signifies that a virtual port is pause for a moment.
+         */
+        PAUSE
+    }
+
+    /**
+     * Starts the virtual port.
+     */
+    void start();
+
+    /**
+     * Stops the virtual port.
+     */
+    void stop();
+
+    /**
+     * Pauses the virtual port for stopping a network or device.
+     * e.g. snapshot.
+     */
+    void pause();
+
+    /**
+     * Returns the virtual port state.
+     *
+     * @return state of virtual port
+     */
+    State state();
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualStore.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualStore.java
new file mode 100644
index 0000000..8a25874
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VirtualStore.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * 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 org.onosproject.event.Event;
+import org.onosproject.store.StoreDelegate;
+
+/**
+ * Abstraction of a entity capable of storing and/or distributing information
+ * for virtual network across a cluster.
+ */
+public interface VirtualStore<E extends Event, D extends StoreDelegate<E>> {
+    /**
+     * Sets the delegate on the store.
+     *
+     * @param networkId a virtual network identifier
+     * @param delegate new store delegate
+     * @throws java.lang.IllegalStateException if a delegate is already
+     *                                         currently set on the store and is a different one that
+     */
+    void setDelegate(NetworkId networkId, D delegate);
+
+    /**
+     * Withdraws the delegate from the store.
+     *
+     * @param networkId a virtual network identifier
+     * @param delegate store delegate to withdraw
+     * @throws java.lang.IllegalArgumentException if the delegate is not
+     *                                            currently set on the store
+     */
+    void unsetDelegate(NetworkId networkId, D delegate);
+
+    /**
+     * Indicates whether the store has a delegate.
+     *
+     * @param networkId a virtual network identifier
+     * @return true if delegate is set
+     */
+    boolean hasDelegate(NetworkId networkId);
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VnetService.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VnetService.java
new file mode 100644
index 0000000..1889ad4
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/VnetService.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * 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;
+
+/**
+ * Virtual network service interface.
+ */
+public interface VnetService {
+    NetworkId networkId();
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/codec/VirtualDeviceCodec.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/codec/VirtualDeviceCodec.java
new file mode 100644
index 0000000..c0c8cf8
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/codec/VirtualDeviceCodec.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.codec;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.incubator.net.virtual.DefaultVirtualDevice;
+import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.incubator.net.virtual.VirtualDevice;
+import org.onosproject.net.DeviceId;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onlab.util.Tools.nullIsIllegal;
+
+/**
+ * Codec for the VirtualDevice class.
+ */
+public class VirtualDeviceCodec extends JsonCodec<VirtualDevice> {
+
+    // JSON field names
+    private static final String ID = "deviceId";
+    private static final String NETWORK_ID = "networkId";
+
+    private static final String NULL_OBJECT_MSG = "VirtualDevice cannot be null";
+    private static final String MISSING_MEMBER_MSG = " member is required in VirtualDevice";
+
+    @Override
+    public ObjectNode encode(VirtualDevice vDev, CodecContext context) {
+        checkNotNull(vDev, NULL_OBJECT_MSG);
+
+        ObjectNode result = context.mapper().createObjectNode()
+                .put(NETWORK_ID, vDev.networkId().toString())
+                .put(ID, vDev.id().toString());
+
+        return result;
+    }
+
+    @Override
+    public VirtualDevice decode(ObjectNode json, CodecContext context) {
+        if (json == null || !json.isObject()) {
+            return null;
+        }
+
+        DeviceId dId = DeviceId.deviceId(extractMember(ID, json));
+        NetworkId nId = NetworkId.networkId(Long.parseLong(extractMember(NETWORK_ID, json)));
+        return new DefaultVirtualDevice(nId, dId);
+    }
+
+    /**
+     * Extract member from JSON ObjectNode.
+     *
+     * @param key key for which value is needed
+     * @param json JSON ObjectNode
+     * @return member value
+     */
+    private String extractMember(String key, ObjectNode json) {
+        return nullIsIllegal(json.get(key), key + MISSING_MEMBER_MSG).asText();
+    }
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/codec/VirtualHostCodec.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/codec/VirtualHostCodec.java
new file mode 100644
index 0000000..2ddb589
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/codec/VirtualHostCodec.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.codec;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.incubator.net.virtual.DefaultVirtualHost;
+import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.incubator.net.virtual.VirtualHost;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.HostId;
+import org.onosproject.net.HostLocation;
+import org.onosproject.net.PortNumber;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onlab.util.Tools.nullIsIllegal;
+
+/**
+ * Codec for the VirtualHost class.
+ */
+public class VirtualHostCodec extends JsonCodec<VirtualHost> {
+
+    // JSON field names
+    static final String NETWORK_ID = "networkId";
+    static final String HOST_ID = "id";
+    static final String MAC_ADDRESS = "mac";
+    static final String VLAN = "vlan";
+    static final String IP_ADDRESSES = "ipAddresses";
+    static final String HOST_LOCATION = "locations";
+
+    private static final String NULL_OBJECT_MSG = "VirtualHost cannot be null";
+    private static final String MISSING_MEMBER_MSG = " member is required in VirtualHost";
+
+    @Override
+    public ObjectNode encode(VirtualHost vHost, CodecContext context) {
+        checkNotNull(vHost, NULL_OBJECT_MSG);
+
+        final JsonCodec<HostLocation> locationCodec =
+                context.codec(HostLocation.class);
+        final ObjectNode result = context.mapper().createObjectNode()
+                .put(NETWORK_ID, vHost.networkId().toString())
+                .put(HOST_ID, vHost.id().toString())
+                .put(MAC_ADDRESS, vHost.mac().toString())
+                .put(VLAN, vHost.vlan().toString());
+
+        final ArrayNode jsonIpAddresses = result.putArray(IP_ADDRESSES);
+        for (final IpAddress ipAddress : vHost.ipAddresses()) {
+            jsonIpAddresses.add(ipAddress.toString());
+        }
+        result.set(IP_ADDRESSES, jsonIpAddresses);
+
+        final ArrayNode jsonLocations = result.putArray("locations");
+        for (final HostLocation location : vHost.locations()) {
+            jsonLocations.add(locationCodec.encode(location, context));
+        }
+        result.set("locations", jsonLocations);
+
+        return result;
+    }
+
+    @Override
+    public VirtualHost decode(ObjectNode json, CodecContext context) {
+        if (json == null || !json.isObject()) {
+            return null;
+        }
+
+        NetworkId nId = NetworkId.networkId(Long.parseLong(extractMember(NETWORK_ID, json)));
+        MacAddress mac = MacAddress.valueOf(json.get("mac").asText());
+        VlanId vlanId = VlanId.vlanId((short) json.get("vlan").asInt(VlanId.UNTAGGED));
+
+        Set<HostLocation> locations = new HashSet<>();
+        JsonNode locationNodes = json.get("locations");
+        locationNodes.forEach(locationNode -> {
+            PortNumber portNumber = PortNumber.portNumber(locationNode.get("port").asText());
+            DeviceId deviceId = DeviceId.deviceId(locationNode.get("elementId").asText());
+            locations.add(new HostLocation(deviceId, portNumber, 0));
+        });
+
+        HostId id = HostId.hostId(mac, vlanId);
+
+        Iterator<JsonNode> ipStrings = json.get("ipAddresses").elements();
+        Set<IpAddress> ips = new HashSet<>();
+        while (ipStrings.hasNext()) {
+            ips.add(IpAddress.valueOf(ipStrings.next().asText()));
+        }
+
+        return new DefaultVirtualHost(nId, id, mac, vlanId, locations, ips);
+    }
+
+    /**
+     * Extract member from JSON ObjectNode.
+     *
+     * @param key key for which value is needed
+     * @param json JSON ObjectNode
+     * @return member value
+     */
+    private String extractMember(String key, ObjectNode json) {
+        return nullIsIllegal(json.get(key), key + MISSING_MEMBER_MSG).asText();
+    }
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/codec/VirtualLinkCodec.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/codec/VirtualLinkCodec.java
new file mode 100644
index 0000000..641982f
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/codec/VirtualLinkCodec.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.codec;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.incubator.net.virtual.DefaultVirtualLink;
+import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.incubator.net.virtual.VirtualLink;
+import org.onosproject.net.Link;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onlab.util.Tools.nullIsIllegal;
+
+/**
+ * Codec for the VirtualLink class.
+ */
+public class VirtualLinkCodec extends JsonCodec<VirtualLink> {
+
+    // JSON field names
+    private static final String NETWORK_ID = "networkId";
+
+    private static final String NULL_OBJECT_MSG = "VirtualLink cannot be null";
+    private static final String MISSING_MEMBER_MSG = " member is required in VirtualLink";
+
+    @Override
+    public ObjectNode encode(VirtualLink vLink, CodecContext context) {
+        checkNotNull(vLink, NULL_OBJECT_MSG);
+
+        ObjectNode result = context.mapper().createObjectNode()
+                .put(NETWORK_ID, vLink.networkId().toString());
+        JsonCodec<Link> codec = context.codec(Link.class);
+        ObjectNode linkResult = codec.encode(vLink, context);
+        result.setAll(linkResult);
+        return result;
+    }
+
+    @Override
+    public VirtualLink decode(ObjectNode json, CodecContext context) {
+        if (json == null || !json.isObject()) {
+            return null;
+        }
+        JsonCodec<Link> codec = context.codec(Link.class);
+        Link link = codec.decode(json, context);
+        NetworkId nId = NetworkId.networkId(Long.parseLong(extractMember(NETWORK_ID, json)));
+        return DefaultVirtualLink.builder()
+                .networkId(nId)
+                .src(link.src())
+                .dst(link.dst())
+                .build();
+    }
+
+    /**
+     * Extract member from JSON ObjectNode.
+     *
+     * @param key  key for which value is needed
+     * @param json JSON ObjectNode
+     * @return member value
+     */
+    private String extractMember(String key, ObjectNode json) {
+        return nullIsIllegal(json.get(key), key + MISSING_MEMBER_MSG).asText();
+    }
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/codec/VirtualNetworkCodec.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/codec/VirtualNetworkCodec.java
new file mode 100644
index 0000000..32945e4
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/codec/VirtualNetworkCodec.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.codec;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.incubator.net.virtual.DefaultVirtualNetwork;
+import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.net.TenantId;
+import org.onosproject.incubator.net.virtual.VirtualNetwork;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onlab.util.Tools.nullIsIllegal;
+
+/**
+ * Codec for the VirtualNetwork class.
+ */
+public class VirtualNetworkCodec extends JsonCodec<VirtualNetwork> {
+
+    // JSON field names
+    private static final String NETWORK_ID = "networkId";
+    private static final String TENANT_ID = "tenantId";
+
+    private static final String NULL_OBJECT_MSG = "VirtualNetwork cannot be null";
+    private static final String MISSING_MEMBER_MSG = " member is required in VirtualNetwork";
+
+    @Override
+    public ObjectNode encode(VirtualNetwork vnet, CodecContext context) {
+        checkNotNull(vnet, NULL_OBJECT_MSG);
+
+        ObjectNode result = context.mapper().createObjectNode()
+                .put(NETWORK_ID, vnet.id().toString())
+                .put(TENANT_ID, vnet.tenantId().toString());
+
+        return result;
+    }
+
+    @Override
+    public VirtualNetwork decode(ObjectNode json, CodecContext context) {
+        if (json == null || !json.isObject()) {
+            return null;
+        }
+
+        NetworkId nId = NetworkId.networkId(Long.parseLong(extractMember(NETWORK_ID, json)));
+        TenantId tId = TenantId.tenantId(extractMember(TENANT_ID, json));
+        return new DefaultVirtualNetwork(nId, tId);
+    }
+
+    private String extractMember(String key, ObjectNode json) {
+        return nullIsIllegal(json.get(key), key + MISSING_MEMBER_MSG).asText();
+    }
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/codec/VirtualPortCodec.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/codec/VirtualPortCodec.java
new file mode 100644
index 0000000..474196e
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/codec/VirtualPortCodec.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.codec;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.incubator.net.virtual.DefaultVirtualPort;
+import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.incubator.net.virtual.VirtualDevice;
+import org.onosproject.incubator.net.virtual.VirtualNetworkService;
+import org.onosproject.incubator.net.virtual.VirtualPort;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onlab.util.Tools.nullIsIllegal;
+
+/**
+ * Codec for the VirtualPort class.
+ */
+public class VirtualPortCodec extends JsonCodec<VirtualPort> {
+
+    // JSON field names
+    private static final String NETWORK_ID = "networkId";
+    private static final String DEVICE_ID = "deviceId";
+    private static final String PORT_NUM = "portNum";
+    private static final String PHYS_DEVICE_ID = "physDeviceId";
+    private static final String PHYS_PORT_NUM = "physPortNum";
+
+    private static final String NULL_OBJECT_MSG = "VirtualPort cannot be null";
+    private static final String MISSING_MEMBER_MSG = " member is required in VirtualPort";
+    private static final String INVALID_VIRTUAL_DEVICE = " is not a valid VirtualDevice";
+
+    @Override
+    public ObjectNode encode(VirtualPort vPort, CodecContext context) {
+        checkNotNull(vPort, NULL_OBJECT_MSG);
+
+        ObjectNode result = context.mapper().createObjectNode()
+                .put(NETWORK_ID, vPort.networkId().toString())
+                .put(DEVICE_ID, vPort.element().id().toString())
+                .put(PORT_NUM, vPort.number().toString())
+                .put(PHYS_DEVICE_ID, vPort.realizedBy().deviceId().toString())
+                .put(PHYS_PORT_NUM, vPort.realizedBy().port().toString());
+
+        return result;
+    }
+
+    @Override
+    public VirtualPort decode(ObjectNode json, CodecContext context) {
+        if (json == null || !json.isObject()) {
+            return null;
+        }
+
+        NetworkId nId = NetworkId.networkId(Long.parseLong(extractMember(NETWORK_ID, json)));
+        DeviceId dId = DeviceId.deviceId(extractMember(DEVICE_ID, json));
+
+        VirtualNetworkService vnetService = context.getService(VirtualNetworkService.class);
+        Set<VirtualDevice> vDevs = vnetService.getVirtualDevices(nId);
+        VirtualDevice vDev = vDevs.stream()
+                .filter(virtualDevice -> virtualDevice.id().equals(dId))
+                .findFirst().orElse(null);
+        nullIsIllegal(vDev, dId.toString() + INVALID_VIRTUAL_DEVICE);
+
+        PortNumber portNum = PortNumber.portNumber(extractMember(PORT_NUM, json));
+        DeviceId physDId = DeviceId.deviceId(extractMember(PHYS_DEVICE_ID, json));
+        PortNumber physPortNum = PortNumber.portNumber(extractMember(PHYS_PORT_NUM, json));
+
+        ConnectPoint realizedBy = new ConnectPoint(physDId, physPortNum);
+        return new DefaultVirtualPort(nId, vDev, portNum, realizedBy);
+    }
+
+    private String extractMember(String key, ObjectNode json) {
+        return nullIsIllegal(json.get(key), key + MISSING_MEMBER_MSG).asText();
+    }
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/codec/package-info.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/codec/package-info.java
new file mode 100644
index 0000000..8999592
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/codec/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.
+ */
+
+/**
+ * Network virtualization data model codecs.
+ */
+package org.onosproject.incubator.net.virtual.codec;
\ No newline at end of file
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/event/AbstractVirtualListenerManager.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/event/AbstractVirtualListenerManager.java
new file mode 100644
index 0000000..57dfe0c
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/event/AbstractVirtualListenerManager.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.event;
+
+import org.onlab.osgi.ServiceDirectory;
+import org.onosproject.event.Event;
+import org.onosproject.event.EventDeliveryService;
+import org.onosproject.event.EventListener;
+import org.onosproject.event.ListenerRegistry;
+import org.onosproject.event.ListenerService;
+import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.incubator.net.virtual.VirtualNetworkService;
+import org.onosproject.incubator.net.virtual.VnetService;
+
+/**
+ * Basis for virtual event components which need to export listener mechanism.
+ */
+public abstract class AbstractVirtualListenerManager
+        <E extends Event, L extends EventListener<E>>
+        implements ListenerService<E, L>, VnetService {
+
+    protected final NetworkId networkId;
+    protected final VirtualNetworkService manager;
+    protected final ServiceDirectory serviceDirectory;
+
+    protected EventDeliveryService eventDispatcher;
+
+    private ListenerRegistry<E, L> listenerRegistry;
+
+    private VirtualListenerRegistryManager listenerManager =
+            VirtualListenerRegistryManager.getInstance();
+
+    public AbstractVirtualListenerManager(VirtualNetworkService manager,
+                                          NetworkId networkId,
+                                          Class<? extends Event> eventClass) {
+        this.manager = manager;
+        this.networkId = networkId;
+        this.serviceDirectory = manager.getServiceDirectory();
+
+        //Set default event delivery service by default
+        this.eventDispatcher = serviceDirectory.get(EventDeliveryService.class);
+
+        //Initialize and reference to the listener registry
+        this.listenerRegistry = listenerManager.getRegistry(networkId, eventClass);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public void addListener(L listener) {
+        listenerRegistry.addListener(listener);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public void removeListener(L listener) {
+        listenerRegistry.removeListener(listener);
+    }
+
+    /**
+     * Safely posts the specified event to the local event dispatcher.
+     * If there is no event dispatcher or if the event is null, this method
+     * is a noop.
+     *
+     * @param event event to be posted; may be null
+     */
+    protected void post(E event) {
+        if (event != null && eventDispatcher != null) {
+            VirtualEvent<E> vEvent =
+                    new VirtualEvent<E>(networkId, VirtualEvent.Type.POSTED, event);
+            eventDispatcher.post(vEvent);
+        }
+    }
+
+    @Override
+    public NetworkId networkId() {
+        return this.networkId;
+    }
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/event/VirtualEvent.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/event/VirtualEvent.java
new file mode 100644
index 0000000..bbba983
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/event/VirtualEvent.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.event;
+
+import org.onosproject.event.AbstractEvent;
+import org.onosproject.event.Event;
+import org.onosproject.incubator.net.virtual.NetworkId;
+
+/**
+ * Base class for virtual network event that encapsulates a normal event.
+ */
+public class VirtualEvent<E extends Event>
+        extends AbstractEvent<VirtualEvent.Type, E> {
+
+    private NetworkId networkId;
+
+    /**
+     * Type of virtual network events.
+     */
+    public enum Type {
+        /**
+         * A new virtual event has been posted.
+         */
+        POSTED
+    }
+
+    protected VirtualEvent(NetworkId networkId, Type type, E subject) {
+        super(type, subject);
+        this.networkId = networkId;
+    }
+
+    protected VirtualEvent(NetworkId networkId, Type type, E subject, long time) {
+        super(type, subject, time);
+        this.networkId = networkId;
+    }
+
+    public NetworkId networkId() {
+        return networkId;
+    }
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/event/VirtualListenerRegistryManager.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/event/VirtualListenerRegistryManager.java
new file mode 100644
index 0000000..55210dd
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/event/VirtualListenerRegistryManager.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.event;
+
+import com.google.common.collect.Maps;
+import org.onosproject.event.Event;
+import org.onosproject.event.EventSink;
+import org.onosproject.event.ListenerRegistry;
+import org.onosproject.incubator.net.virtual.NetworkId;
+
+import java.util.Map;
+
+/**
+ * Base implementation of an virtual event sink and a registry capable of tracking
+ * listeners and dispatching events to them as part of event sink processing.
+ */
+public final class VirtualListenerRegistryManager
+        implements EventSink<VirtualEvent> {
+
+    private Map<NetworkId, Map<Class<? extends Event>, ListenerRegistry>>
+            listenerMapByNetwork = Maps.newConcurrentMap();
+
+    ListenerRegistry lastStart;
+
+    // non-instantiable (except for our Singleton)
+    private VirtualListenerRegistryManager() {
+
+    }
+
+    public static VirtualListenerRegistryManager getInstance() {
+        return SingletonHelper.INSTANCE;
+    }
+
+    public ListenerRegistry getRegistry(NetworkId networkId,
+                                        Class<? extends Event> eventClass) {
+        Map<Class<? extends Event>, ListenerRegistry> listenerMapByEvent =
+                listenerMapByNetwork.get(networkId);
+
+        if (listenerMapByEvent == null) {
+            listenerMapByEvent = Maps.newConcurrentMap();
+            listenerMapByNetwork.putIfAbsent(networkId, listenerMapByEvent);
+        }
+
+        ListenerRegistry listenerRegistry = listenerMapByEvent.get(eventClass);
+
+        if (listenerRegistry == null) {
+            listenerRegistry = new ListenerRegistry();
+            listenerMapByEvent.putIfAbsent(eventClass, listenerRegistry);
+        }
+
+        return listenerRegistry;
+    }
+
+    @Override
+    public void process(VirtualEvent event) {
+        NetworkId networkId = event.networkId();
+        Event originalEvent = (Event) event.subject();
+
+        ListenerRegistry listenerRegistry =
+                listenerMapByNetwork.get(networkId).get(originalEvent.getClass());
+        if (listenerRegistry != null) {
+            listenerRegistry.process(originalEvent);
+            lastStart = listenerRegistry;
+        }
+    }
+
+    @Override
+    public void onProcessLimit() {
+        lastStart.onProcessLimit();
+    }
+
+    /**
+     * Prevents object instantiation from external.
+     */
+    private static final class SingletonHelper {
+        private static final String ILLEGAL_ACCESS_MSG =
+                "Should not instantiate this class.";
+        private static final VirtualListenerRegistryManager INSTANCE =
+                new VirtualListenerRegistryManager();
+
+        private SingletonHelper() {
+            throw new IllegalAccessError(ILLEGAL_ACCESS_MSG);
+        }
+    }
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/event/package-info.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/event/package-info.java
new file mode 100644
index 0000000..448df90
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/event/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.
+ */
+
+/**
+ * Virtual network event delivery subsystem interfaces &amp; supporting abstractions.
+ */
+package org.onosproject.incubator.net.virtual.event;
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/intent/VirtualIntentCompiler.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/intent/VirtualIntentCompiler.java
new file mode 100644
index 0000000..e76bf6e
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/intent/VirtualIntentCompiler.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.intent;
+
+import com.google.common.annotations.Beta;
+import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.net.intent.Intent;
+
+import java.util.List;
+
+/**
+ * Abstraction of a compiler which is capable of taking an intent
+ * and translating it to other, potentially installable, intents for virtual networks.
+ *
+ * @param <T> the type of intent
+ */
+@Beta
+public interface VirtualIntentCompiler<T extends Intent> {
+    /**
+     * Compiles the specified intent into other intents.
+     *
+     * @param networkId   network identifier
+     * @param intent      intent to be compiled
+     * @param installable previous compilation result; optional
+     * @return list of resulting intents
+     * @throws VirtualIntentException if issues are encountered while compiling the intent
+     */
+     List<Intent> compile(NetworkId networkId, T intent, List<Intent> installable);
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/intent/VirtualIntentException.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/intent/VirtualIntentException.java
new file mode 100644
index 0000000..49cb908
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/intent/VirtualIntentException.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.intent;
+
+public class VirtualIntentException extends RuntimeException {
+
+    //FIXME: how to obatin UID?
+    private static final long serialVersionUID = 1907263634145241319L;
+
+    /**
+     * Constructs an exception with no message and no underlying cause.
+     */
+    public VirtualIntentException() {
+    }
+
+    /**
+     * Constructs an exception with the specified message.
+     *
+     * @param message the message describing the specific nature of the error
+     */
+    public VirtualIntentException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs an exception with the specified message and the underlying cause.
+     *
+     * @param message the message describing the specific nature of the error
+     * @param cause   the underlying cause of this error
+     */
+    public VirtualIntentException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/intent/package-info.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/intent/package-info.java
new file mode 100644
index 0000000..c5673ac
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/intent/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.
+ */
+
+/**
+ * Set of abstractions for conveying high-level intents for treatment of
+ * selected network traffic by allowing applications to express the
+ * <em>what</em> rather than the <em>how</em> for virtual networks.
+ */
+package org.onosproject.incubator.net.virtual.intent;
\ No newline at end of file
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/package-info.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/package-info.java
new file mode 100644
index 0000000..d9ced32
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * 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.
+ */
+
+/**
+ * Network virtualization data models and services.
+ */
+package org.onosproject.incubator.net.virtual;
\ No newline at end of file
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/AbstractVirtualProvider.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/AbstractVirtualProvider.java
new file mode 100644
index 0000000..bb4ba30
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/AbstractVirtualProvider.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * 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.provider;
+
+import org.onosproject.net.provider.ProviderId;
+
+public abstract class AbstractVirtualProvider implements VirtualProvider {
+    private final ProviderId providerId;
+
+    /**
+     * Creates a virtual provider with the supplied identifier.
+     *
+     * @param id a virtual provider id
+     */
+    protected AbstractVirtualProvider(ProviderId id) {
+        this.providerId = id;
+    }
+
+    @Override
+    public ProviderId id() {
+        return providerId;
+    }
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/AbstractVirtualProviderService.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/AbstractVirtualProviderService.java
new file mode 100644
index 0000000..2411e26
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/AbstractVirtualProviderService.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * 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.provider;
+
+import static com.google.common.base.Preconditions.checkState;
+
+/**
+ * Base implementation of a virtual provider service,
+ * which tracks the provider to which it is issued and can be invalidated.
+ *
+ * @param <P> type of the information provider
+ */
+public abstract class AbstractVirtualProviderService<P extends VirtualProvider>
+        implements VirtualProviderService<P> {
+
+    private boolean isValid = true;
+    private P provider = null;
+
+    /**
+     * Creates a virtual provider service on behalf of the specified provider.
+     *
+     * @param provider provider to which this service is being issued
+     */
+    protected void setProvider(P provider) {
+        this.provider = provider;
+    }
+
+    /**
+     * Invalidates this provider service.
+     */
+    public void invalidate() {
+        isValid = false;
+    }
+
+    /**
+     * Checks the validity of this provider service.
+     *
+     * @throws java.lang.IllegalStateException if the service is no longer valid
+     */
+    public void checkValidity() {
+        checkState(isValid, "Provider service is no longer valid");
+    }
+
+    @Override
+    public P provider() {
+        return provider;
+    }
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/InternalRoutingAlgorithm.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/InternalRoutingAlgorithm.java
new file mode 100644
index 0000000..c17f0d9
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/InternalRoutingAlgorithm.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * 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.provider;
+
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.Path;
+
+/**
+ * Abstraction of an embedding algorithm used for embedding virtual objects
+ * into the underlying physical network.
+ */
+public interface InternalRoutingAlgorithm {
+    /**
+     * Find a route between two connect points (i.e. ports)
+     * according to the own logic.
+     *
+     * @param src A start point
+     * @param dst A sink point
+     * @return The path between src and dst calculated from the algorithm
+     */
+    Path findPath(ConnectPoint src, ConnectPoint dst);
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualDeviceProvider.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualDeviceProvider.java
new file mode 100644
index 0000000..9191eaf
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualDeviceProvider.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * 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.provider;
+
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.MastershipRole;
+import org.onosproject.net.PortNumber;
+
+/**
+ * Abstraction of a virtual device information provider.
+ */
+public interface VirtualDeviceProvider extends VirtualProvider {
+
+    /**
+     * Notifies the provider of a mastership role change for the specified
+     * device as decided by the core.
+     *
+     * @param deviceId  device identifier
+     * @param newRole newly determined mastership role
+     */
+    void roleChanged(DeviceId deviceId, MastershipRole newRole);
+
+    /**
+     * Indicates whether or not the specified connect points on the underlying
+     * network are traversable.
+     *
+     * @param src source connection point
+     * @param dst destination connection point
+     * @return true if the destination is reachable from the source
+     */
+    boolean isTraversable(ConnectPoint src, ConnectPoint dst);
+
+    /**
+     * Indicates whether or not the all physical devices mapped by the given
+     * virtual device are reachable.
+     *
+     * @param deviceId  device identifier
+     * @return true if the all physical devices are reachable, false otherwise
+     */
+    boolean isReachable(DeviceId deviceId);
+
+    /**
+     * Administratively enables or disables a port.
+     *
+     * @param deviceId device identifier
+     * @param portNumber port number
+     * @param enable true if port is to be enabled, false to disable
+     */
+    void changePortState(DeviceId deviceId, PortNumber portNumber,
+                         boolean enable);
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualDeviceProviderService.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualDeviceProviderService.java
new file mode 100644
index 0000000..e2d584c
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualDeviceProviderService.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * 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.provider;
+
+import org.onosproject.incubator.net.virtual.VirtualPortDescription;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.MastershipRole;
+import org.onosproject.net.device.PortStatistics;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Service through which virtual device providers can inject virtual device
+ * information into the core.
+ */
+public interface VirtualDeviceProviderService
+        extends VirtualProviderService<VirtualDeviceProvider> {
+
+    /**
+     * Updates information about all ports of a device. It is up to the core to
+     * determine what has changed.
+     *
+     * @param deviceId         identity of the device
+     * @param portDescs list of virtual device ports
+     */
+    void updatePorts(DeviceId deviceId, List<VirtualPortDescription> portDescs);
+
+    /**
+     * Notifies the core about port status change of a single port.
+     *
+     * @param deviceId        identity of the device
+     * @param portDesc description of the virtual port that changed
+     */
+    void portStatusChanged(DeviceId deviceId, VirtualPortDescription portDesc);
+
+    /**
+     * Notifies the core about the result of a RoleRequest sent to a device.
+     *
+     * @param deviceId identity of the device
+     * @param requested mastership role that was requested by the node
+     * @param response mastership role the switch accepted
+     */
+    void receivedRoleReply(DeviceId deviceId, MastershipRole requested,
+                           MastershipRole response);
+
+    /**
+     * Updates statistics about all ports of a device.
+     *
+     * @param deviceId          identity of the device
+     * @param portStatistics  list of device port statistics
+     */
+    void updatePortStatistics(DeviceId deviceId,
+                              Collection<PortStatistics> portStatistics);
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualFlowRuleProvider.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualFlowRuleProvider.java
new file mode 100644
index 0000000..8a4ec34
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualFlowRuleProvider.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * 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.provider;
+
+import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.oldbatch.FlowRuleBatchOperation;
+
+/**
+ * Abstraction of a virtual flow rule provider.
+ * This provider virtualizes and de-virtualizes FlowRule.
+ * See {@link org.onosproject.net.flow.FlowRule}.
+ */
+public interface VirtualFlowRuleProvider extends VirtualProvider {
+
+    /**
+     * Instructs the provider to apply the specified flow rules to their
+     * respective virtual devices.
+     *
+     * @param networkId the identity of the virtual network where this rule applies
+     * @param flowRules one or more flow rules
+     */
+    void applyFlowRule(NetworkId networkId, FlowRule... flowRules);
+
+    /**
+     * Instructs the provider to remove the specified flow rules to their
+     * respective virtual devices.
+     *
+     * @param networkId the identity of the virtual network where this rule applies
+     * @param flowRules one or more flow rules
+     */
+    void removeFlowRule(NetworkId networkId, FlowRule... flowRules);
+
+    /**
+     * Installs a batch of flow rules. Each flowrule is associated to an
+     * operation which results in either addition, removal or modification.
+     *
+     * @param networkId the identity of the virtual network where this rule applies
+     * @param batch a batch of flow rules
+     */
+    void executeBatch(NetworkId networkId, FlowRuleBatchOperation batch);
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualFlowRuleProviderService.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualFlowRuleProviderService.java
new file mode 100644
index 0000000..065af9c
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualFlowRuleProviderService.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * 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.provider;
+
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.flow.CompletedBatchOperation;
+import org.onosproject.net.flow.FlowEntry;
+import org.onosproject.net.flow.TableStatisticsEntry;
+
+import java.util.List;
+
+/**
+ * Service through which virtual flow rule providers can inject information into
+ * the core.
+ */
+public interface VirtualFlowRuleProviderService
+        extends VirtualProviderService<VirtualFlowRuleProvider> {
+
+    /**
+     * Signals that a flow rule that was previously installed has been removed.
+     *
+     * @param flowEntry removed flow entry
+     */
+    void flowRemoved(FlowEntry flowEntry);
+
+    /**
+     * Pushes the collection of flow entries currently applied on the given
+     * virtual device.
+     *
+     * @param deviceId device identifier
+     * @param flowEntries collection of flow rules
+     */
+    void pushFlowMetrics(DeviceId deviceId, Iterable<FlowEntry> flowEntries);
+
+    /**
+     * Pushes the collection of flow entries currently applied on the given
+     * device without flowMissing process.
+     *
+     * @param deviceId device identifier
+     * @param flowEntries collection of flow rules
+     */
+    void pushFlowMetricsWithoutFlowMissing(DeviceId deviceId, Iterable<FlowEntry> flowEntries);
+
+    /**
+     * Pushes the collection of table statistics entries currently extracted
+     * from the given virtual device.
+     *
+     * @param deviceId device identifier
+     * @param tableStatsEntries collection of flow table statistics entries
+     */
+    void pushTableStatistics(DeviceId deviceId, List<TableStatisticsEntry> tableStatsEntries);
+
+    /**
+     * Indicates to the core that the requested batch operation has
+     * been completed.
+     *
+     * @param batchId the batch which was processed
+     * @param operation the resulting outcome of the operation
+     */
+    void batchOperationCompleted(long batchId, CompletedBatchOperation operation);
+
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualGroupProvider.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualGroupProvider.java
new file mode 100644
index 0000000..72d68c3
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualGroupProvider.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * 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.provider;
+
+import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.group.GroupOperations;
+
+/**
+ * Abstraction of group provider for virtual network.
+ */
+public interface VirtualGroupProvider extends VirtualProvider {
+    /**
+     * Performs a batch of group operation in the specified virtual device
+     * with the specified parameters.
+     *
+     * @param networkId the identity of the virtual network where this rule applies
+     * @param deviceId device identifier on which the batch of group
+     * operations to be executed
+     * @param groupOps immutable list of group operation
+     */
+    void performGroupOperation(NetworkId networkId, DeviceId deviceId,
+                               GroupOperations groupOps);
+
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualGroupProviderService.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualGroupProviderService.java
new file mode 100644
index 0000000..0fdaca8
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualGroupProviderService.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * 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.provider;
+
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.group.Group;
+import org.onosproject.net.group.GroupOperation;
+
+import java.util.Collection;
+
+/**
+ * Service through which Group providers can inject information into
+ * the virtual network core.
+ */
+public interface VirtualGroupProviderService
+        extends VirtualProviderService<VirtualGroupProvider> {
+    /**
+     * Notifies core if any failure from data plane during group operations.
+     *
+     * @param deviceId the device ID
+     * @param operation offended group operation
+     */
+    void groupOperationFailed(DeviceId deviceId, GroupOperation operation);
+
+    /**
+     * Pushes the collection of group detected in the data plane along
+     * with statistics.
+     *
+     * @param deviceId device identifier
+     * @param groupEntries collection of group entries as seen in data plane
+     */
+    void pushGroupMetrics(DeviceId deviceId, Collection<Group> groupEntries);
+
+    /**
+     * Notifies store of group failovers.
+     *
+     * @param failoverGroups failover groups in which a failover has occurred
+     */
+    void notifyOfFailovers(Collection<Group> failoverGroups);
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualMeterProvider.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualMeterProvider.java
new file mode 100644
index 0000000..6ac80e4
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualMeterProvider.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * 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.provider;
+
+import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.meter.MeterOperation;
+import org.onosproject.net.meter.MeterOperations;
+
+/**
+ * Abstraction of a Meter provider for virtual network.
+ */
+public interface VirtualMeterProvider extends VirtualProvider {
+    /**
+     * Performs a batch of meter operation on the specified virtual device
+     * with the specified parameters.
+     *
+     * @param networkId the identity of the virtual network where this rule applies
+     * @param deviceId device identifier on which the batch of group
+     * operations to be executed
+     * @param meterOps immutable list of meter operation
+     */
+    void performMeterOperation(NetworkId networkId, DeviceId deviceId,
+                               MeterOperations meterOps);
+
+
+    /**
+     * Performs a meter operation on the specified vitual device with the
+     * specified parameters.
+     *
+     * @param networkId the identity of the virtual network where this rule applies
+     * @param deviceId device identifier on which the batch of group
+     * operations to be executed
+     * @param meterOp a meter operation
+     */
+    void performMeterOperation(NetworkId networkId, DeviceId deviceId,
+                               MeterOperation meterOp);
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualMeterProviderService.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualMeterProviderService.java
new file mode 100644
index 0000000..46e4a7d
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualMeterProviderService.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * 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.provider;
+
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.meter.Meter;
+import org.onosproject.net.meter.MeterFailReason;
+import org.onosproject.net.meter.MeterFeatures;
+import org.onosproject.net.meter.MeterOperation;
+
+import java.util.Collection;
+
+/**
+ * Service through which meter providers can inject information
+ * into the virtual network subsystem core.
+ */
+public interface VirtualMeterProviderService
+        extends VirtualProviderService<VirtualMeterProvider> {
+    /**
+     * Notifies the core that a meter operation failed for a
+     * specific reason.
+     *
+     * @param operation the failed operation
+     * @param reason the failure reason
+     */
+    void meterOperationFailed(MeterOperation operation, MeterFailReason reason);
+
+    /**
+     * Pushes the collection of meters observed on the data plane as
+     * well as their associated statistics.
+     *
+     * @param deviceId a device id
+     * @param meterEntries a collection of meter entries
+     */
+    void pushMeterMetrics(DeviceId deviceId, Collection<Meter> meterEntries);
+
+    /**
+     * Pushes the meter features collected from the device.
+     *
+     * @param deviceId the device Id
+     * @param meterfeatures the meter features
+     */
+    void pushMeterFeatures(DeviceId deviceId,
+                           MeterFeatures meterfeatures);
+
+    /**
+     * Delete meter features collected from the device.
+     *
+     * @param deviceId the device id
+     */
+    void deleteMeterFeatures(DeviceId deviceId);
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualNetworkProvider.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualNetworkProvider.java
new file mode 100644
index 0000000..038d4b3
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualNetworkProvider.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * 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.provider;
+
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.provider.Provider;
+
+/**
+ * Entity capable of providing traffic isolation constructs for use in
+ * implementation of virtual devices and virtual links.
+ */
+public interface VirtualNetworkProvider extends Provider {
+
+    /**
+     * Indicates whether or not the specified connect points on the underlying
+     * network are traversable/reachable.
+     *
+     * @param src source connection point
+     * @param dst destination connection point
+     * @return true if the destination is reachable from the source
+     */
+    boolean isTraversable(ConnectPoint src, ConnectPoint dst);
+
+    // TODO: Further enhance this interface to support the virtual intent programming across this boundary.
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualNetworkProviderRegistry.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualNetworkProviderRegistry.java
new file mode 100644
index 0000000..6fbb1a7
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualNetworkProviderRegistry.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * 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.provider;
+
+import org.onosproject.net.provider.ProviderRegistry;
+
+/**
+ * Abstraction of a virtual network provider registry.
+ */
+public interface VirtualNetworkProviderRegistry
+        extends ProviderRegistry<VirtualNetworkProvider, VirtualNetworkProviderService> {
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualNetworkProviderService.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualNetworkProviderService.java
new file mode 100644
index 0000000..ee7d9a6
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualNetworkProviderService.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * 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.provider;
+
+import org.onosproject.incubator.net.tunnel.TunnelId;
+import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.provider.ProviderService;
+
+import java.util.Set;
+
+/**
+ * Service through which virtual network providers can inject information into
+ * the core.
+ */
+public interface VirtualNetworkProviderService extends ProviderService<VirtualNetworkProvider> {
+
+    /**
+     * Set of separate topology clusters expressed in terms of connect points which
+     * belong to the same SCC of the underlying topology.
+     *
+     * @param clusters set of sets of mutually reachable connection points;
+     *                 the outer sets are not mutually reachable
+     */
+    void topologyChanged(Set<Set<ConnectPoint>> clusters);
+
+    // TBD: Is the above sufficient to determine health/viability of virtual entities based on
+    // clustering (SCC) of the physical ones?
+
+    /**
+     * This method is used to notify the VirtualNetwork service that a tunnel is now ACTIVE.
+     *
+     * @param networkId network identifier
+     * @param src       source connection point
+     * @param dst       destination connection point
+     * @param tunnelId  tunnel identifier
+     */
+    void tunnelUp(NetworkId networkId, ConnectPoint src, ConnectPoint dst, TunnelId tunnelId);
+
+    /**
+     * This method is used to notify the VirtualNetwork service that a tunnel is now
+     * FAILED or INACTIVE.
+     *
+     * @param networkId network identifier
+     * @param src       source connection point
+     * @param dst       destination connection point
+     * @param tunnelId  tunnel identifier
+     */
+    void tunnelDown(NetworkId networkId, ConnectPoint src, ConnectPoint dst, TunnelId tunnelId);
+
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualPacketProvider.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualPacketProvider.java
new file mode 100644
index 0000000..4cc8d80
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualPacketProvider.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * 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.provider;
+
+import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.net.packet.OutboundPacket;
+
+/**
+ * Abstraction of a virtual packet provider capable of emitting packets
+ * from virtual network core services to the underlay network.
+ * This provider de-virtualizes and virtualize PacketContext.
+ */
+public interface VirtualPacketProvider extends VirtualProvider {
+    /**
+     * Emits the specified outbound packet onto the underlay physical network.
+     * This provider maps the requested packets for physical network.
+     *
+     * @param networkId the virtual network ID
+     * @param packet outbound packet in the context of virtual network
+     */
+    void emit(NetworkId networkId, OutboundPacket packet);
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualPacketProviderService.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualPacketProviderService.java
new file mode 100644
index 0000000..3c2b4c2
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualPacketProviderService.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * 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.provider;
+
+import org.onosproject.net.packet.PacketContext;
+
+/**
+ * Entity capable of processing inbound packets for virtual networks.
+ */
+public interface VirtualPacketProviderService
+        extends VirtualProviderService<VirtualPacketProvider> {
+
+    /**
+     * Submits inbound packet context for processing to virtual network core.
+     * This processing will be done synchronously, i.e. run-to-completion.
+     * This context is translated with virtual concepts.
+     *
+     * @param context inbound packet context
+     */
+    void processPacket(PacketContext context);
+
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualProvider.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualProvider.java
new file mode 100644
index 0000000..ac0dfb6
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualProvider.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * 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.provider;
+
+import org.onosproject.net.provider.ProviderId;
+
+/**
+ * Abstraction of a provider of information about virtual network environment.
+ * The role of virtual providers is to translate virtual objects into physical
+ * objects, vice versa.
+ */
+public interface VirtualProvider {
+
+    /**
+     * Returns the provider identifier.
+     *
+     * @return provider identification
+     */
+    ProviderId id();
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualProviderRegistryService.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualProviderRegistryService.java
new file mode 100644
index 0000000..546463c
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualProviderRegistryService.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.provider;
+
+import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.provider.ProviderId;
+
+import java.util.Set;
+
+/**
+ * Registry for tracking information providers with the core.
+ */
+public interface VirtualProviderRegistryService {
+
+    /**
+     * Registers the supplied virtual provider.
+     *
+     * @param virtualProvider a virtual provider to be registered
+     * @throws java.lang.IllegalArgumentException if the provider is registered already
+     */
+    void registerProvider(VirtualProvider virtualProvider);
+
+    /**
+     * Unregisters the supplied virtual provider.
+     * As a result the previously issued virtual provider service will be invalidated
+     * and any subsequent invocations of its methods may throw
+     * {@link java.lang.IllegalStateException}.
+     * <p>
+     * Unregistering a virtual provider that has not been previously registered results
+     * in a no-op.
+     * </p>
+     *
+     * @param virtualProvider a virtual provider to be unregistered
+     */
+    void unregisterProvider(VirtualProvider virtualProvider);
+
+    /**
+     * Registers the supplied virtual provider.
+     *
+     * @param networkId a virtual network identifier
+     * @param virtualProviderService a virtual provider service to be registered
+     */
+    void registerProviderService(NetworkId networkId,
+                                 VirtualProviderService virtualProviderService);
+
+    /**
+     * Unregisters the supplied virtual provider service.
+     *
+     * @param networkId a virtual network identifier
+     * @param virtualProviderService a virtual provider service to be unregistered
+     */
+    void unregisterProviderService(NetworkId networkId,
+                                   VirtualProviderService virtualProviderService);
+
+    /**
+     * Returns a set of currently registered virtual provider identities.
+     *
+     * @return set of virtual provider identifiers
+     */
+    Set<ProviderId> getProviders();
+
+    /**
+     * Returns a set of currently registered virtual provider identities
+     * corresponding to the requested providerService.
+     *
+     * @param virtualProviderService a virtual provider service
+     * @return set of virtual provider identifiers
+     */
+    Set<ProviderId> getProvidersByService(VirtualProviderService virtualProviderService);
+
+    /**
+     * Returns the virtual provider registered with the specified provider ID or null
+     * if none is found for the given provider family and default fall-back is
+     * not supported.
+     *
+     * @param providerId provider identifier
+     * @return provider
+     */
+    VirtualProvider getProvider(ProviderId providerId);
+
+    /**
+     * Returns the virtual provider for the specified device ID based on URI scheme.
+     *
+     * @param deviceId virtual device identifier
+     * @return provider bound to the URI scheme
+     */
+    VirtualProvider getProvider(DeviceId deviceId);
+
+    /**
+     * Returns the virtual provider registered with the specified scheme.
+     *
+     * @param scheme provider scheme
+     * @return provider
+     */
+    VirtualProvider getProvider(String scheme);
+
+    /**
+     * Returns a virtual provider service corresponding to
+     * the virtual network and provider class type.
+     *
+     * @param networkId a virtual network identifier
+     * @param providerClass a type of virtual provider
+     * @return a virtual provider service
+     */
+    VirtualProviderService getProviderService(NetworkId networkId,
+                                              Class<? extends VirtualProvider> providerClass);
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualProviderService.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualProviderService.java
new file mode 100644
index 0000000..8ad378f
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualProviderService.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * 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.provider;
+
+/**
+ * Abstraction of a service through which virtual providers can inject information
+ * about the network environment into the virtual core.
+ *
+ * @param <P> type of the information virtual provider
+ */
+
+public interface VirtualProviderService<P extends VirtualProvider> {
+    /**
+     * Returns the virtual provider to which this service has been issued.
+     *
+     * @return virtual provider to which this service has been assigned
+     */
+    P provider();
+}
diff --git a/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/package-info.java b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/package-info.java
new file mode 100644
index 0000000..8d360d5
--- /dev/null
+++ b/apps/virtual/api/src/main/java/org/onosproject/incubator/net/virtual/provider/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * 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.
+ */
+
+/**
+ * Network virtualization provider interfaces and implementation.
+ */
+package org.onosproject.incubator.net.virtual.provider;
\ No newline at end of file