[ONOS-6179] Virtual Network Packet Propagation Issue

There is a problem that the packet request from virtual network
is not relay to real packet service because
VirtualNetworkPacketService cannot process requestPacket()
properly.
Moreover, the installed flow rules from vNet are not syncronized
with the physical rules.

Change-Id: I20c3e1fbb7668f563fafcb3a9d6a7d80ffba55fd
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualPacketProvider.java b/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualPacketProvider.java
index 11c2b00..abd1d7d 100644
--- a/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualPacketProvider.java
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/virtual/provider/VirtualPacketProvider.java
@@ -21,10 +21,9 @@
 /**
  * Abstraction of a virtual packet provider capable of emitting packets
  * from virtual network core services to the underlay network.
- * This provider de-virtualzes OutboundPacket, and virtualizes PacketContext.
+ * 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.
@@ -36,7 +35,15 @@
 
     /**
      * Starts to deliver packets to virtual packet managers.
+     *
+     * @param networkId the network identifier
      */
-    void startPacketHandling();
+    void startPacketHandling(NetworkId networkId);
 
+    /**
+     * Stops to deliver packets to virtual packet managers.
+     *
+     * @param networkId the network identifier
+     */
+    void stopPacketHandling(NetworkId networkId);
 }
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkFlowRuleManager.java b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkFlowRuleManager.java
index 0cbe131..4c93842 100644
--- a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkFlowRuleManager.java
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkFlowRuleManager.java
@@ -470,7 +470,7 @@
                 try {
                     FlowEntry storedRule = storedRules.remove(rule);
                     if (storedRule != null) {
-                        if (storedRule.exactMatch(rule)) {
+                        if (storedRule.id().equals(rule.id())) {
                             // we both have the rule, let's update some info then.
                             flowAdded(rule);
                         } else {
@@ -553,7 +553,17 @@
                     break;
 
                 case BATCH_OPERATION_COMPLETED:
-                    //TODO: do post-processing for batch operations.
+                    FlowOperationsProcessor fops = pendingFlowOperations.remove(
+                            event.subject().batchId());
+                    if (fops == null) {
+                       return;
+                    }
+
+                    if (event.result().isSuccess()) {
+                            fops.satisfy(event.deviceId());
+                    } else {
+                        fops.fail(event.deviceId(), event.result().failedItems());
+                    }
                     break;
 
                 default:
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkPacketManager.java b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkPacketManager.java
index 3f5a8a6..abe089b 100644
--- a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkPacketManager.java
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkPacketManager.java
@@ -255,8 +255,7 @@
         if (device == null) {
             return;
         }
-        VirtualPacketProvider packetProvider =
-                (VirtualPacketProvider) providerService.provider();
+        VirtualPacketProvider packetProvider = providerService.provider();
 
         if (packetProvider != null) {
             packetProvider.emit(networkId, packet);
@@ -281,6 +280,8 @@
             } else {
                 pushToAllDevices(request);
             }
+
+            providerService.provider().startPacketHandling(networkId);
         }
 
         @Override
@@ -292,6 +293,8 @@
             } else {
                 removeFromAllDevices(request);
             }
+
+            providerService.provider().stopPacketHandling(networkId);
         }
     }
 
@@ -364,7 +367,7 @@
         return DefaultForwardingObjective.builder()
                 .withPriority(request.priority().priorityValue())
                 .withSelector(request.selector())
-                .fromApp(manager.getVirtualNetworkApplicationId(networkId()))
+                .fromApp(request.appId())
                 .withFlag(ForwardingObjective.Flag.VERSATILE)
                 .withTreatment(DefaultTrafficTreatment.builder().punt().build())
                 .makePermanent();
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/provider/DefaultVirtualFlowRuleProvider.java b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/provider/DefaultVirtualFlowRuleProvider.java
index 73a207e..a9bff1d 100644
--- a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/provider/DefaultVirtualFlowRuleProvider.java
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/provider/DefaultVirtualFlowRuleProvider.java
@@ -18,11 +18,9 @@
 
 import com.google.common.collect.HashBasedTable;
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 import com.google.common.collect.Table;
-import javafx.util.Pair;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -34,7 +32,7 @@
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
 import org.onosproject.incubator.net.virtual.NetworkId;
-import org.onosproject.incubator.net.virtual.VirtualNetworkAdminService;
+import org.onosproject.incubator.net.virtual.VirtualNetworkService;
 import org.onosproject.incubator.net.virtual.VirtualPort;
 import org.onosproject.incubator.net.virtual.provider.AbstractVirtualProvider;
 import org.onosproject.incubator.net.virtual.provider.InternalRoutingAlgorithm;
@@ -47,12 +45,14 @@
 import org.onosproject.net.Path;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.flow.CompletedBatchOperation;
 import org.onosproject.net.flow.DefaultFlowEntry;
 import org.onosproject.net.flow.DefaultFlowRule;
 import org.onosproject.net.flow.DefaultTrafficSelector;
 import org.onosproject.net.flow.DefaultTrafficTreatment;
 import org.onosproject.net.flow.FlowEntry;
 import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.FlowRuleBatchEntry;
 import org.onosproject.net.flow.FlowRuleBatchOperation;
 import org.onosproject.net.flow.FlowRuleEvent;
 import org.onosproject.net.flow.FlowRuleListener;
@@ -73,8 +73,10 @@
 import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.ImmutableSet.copyOf;
 import static org.slf4j.LoggerFactory.getLogger;
 
 /**
@@ -88,7 +90,7 @@
 public class DefaultVirtualFlowRuleProvider extends AbstractVirtualProvider
         implements VirtualFlowRuleProvider {
 
-    private static final int FLOW_RULE_PRIORITY = 10;
+    private static final String APP_ID_STR = "org.onosproject.virtual.vnet-flow_";
 
     private final Logger log = getLogger(getClass());
 
@@ -96,7 +98,7 @@
     protected TopologyService topologyService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected VirtualNetworkAdminService virtualNetworkAdminService;
+    protected VirtualNetworkService vnService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected CoreService coreService;
@@ -110,10 +112,10 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected VirtualProviderRegistryService providerRegistryService;
 
-    InternalRoutingAlgorithm internalRoutingAlgorithm;
-    InternalVirtualFlowRuleManager frm;
-    ApplicationId appId;
-    FlowRuleListener flowRuleListener;
+    private InternalRoutingAlgorithm internalRoutingAlgorithm;
+    private InternalVirtualFlowRuleManager frm;
+    private ApplicationId appId;
+    private FlowRuleListener flowRuleListener;
 
     /**
      * Creates a provider with the supplied identifier.
@@ -125,8 +127,7 @@
 
     @Activate
     public void activate() {
-        appId = coreService.registerApplication(
-                "org.onosproject.virtual.vnet-flow");
+        appId = coreService.registerApplication(APP_ID_STR);
 
         providerRegistryService.registerProvider(this);
 
@@ -176,7 +177,21 @@
     public void executeBatch(NetworkId networkId, FlowRuleBatchOperation batch) {
         checkNotNull(batch);
 
-        //TODO: execute batch mechanism
+        for (FlowRuleBatchEntry fop : batch.getOperations()) {
+            devirtualize(networkId, fop.target())
+                    .forEach(f -> flowRuleService.applyFlowRules(f));
+        }
+
+        //FIXME: check the success of the all batch operations
+        CompletedBatchOperation status =
+                new CompletedBatchOperation(true, Sets.newConcurrentHashSet(),
+                                            batch.deviceId());
+
+        VirtualFlowRuleProviderService providerService =
+                (VirtualFlowRuleProviderService) providerRegistryService
+                        .getProviderService(networkId,
+                                            VirtualFlowRuleProvider.class);
+        providerService.batchOperationCompleted(batch.id(), status);
     }
 
     public void setEmbeddingAlgorithm(InternalRoutingAlgorithm
@@ -215,53 +230,17 @@
 
         Set<FlowRule> outRules = new HashSet<>();
 
-        Set<VirtualPort> vPorts = virtualNetworkAdminService
-                .getVirtualPorts(networkId, flowRule.deviceId());
+        Set<ConnectPoint> ingressPoints = extractIngressPoints(networkId,
+                                                               flowRule.deviceId(),
+                                                               flowRule.selector());
 
-        PortCriterion portCriterion = ((PortCriterion) flowRule.selector()
-                .getCriterion(Criterion.Type.IN_PORT));
+        ConnectPoint egressPoint = extractEgressPoints(networkId,
+                                                         flowRule.deviceId(),
+                                                         flowRule.treatment());
 
-        Set<ConnectPoint> ingressPoints = new HashSet<>();
-        if (portCriterion != null) {
-            PortNumber vInPortNum = portCriterion.port();
-
-            Optional<ConnectPoint> optionalCp =  vPorts.stream()
-                    .filter(v -> v.number().equals(vInPortNum))
-                    .map(v -> v.realizedBy()).findFirst();
-            if (!optionalCp.isPresent()) {
-                log.info("Port {} is not realized yet, in Network {}, Device {}",
-                         vInPortNum, networkId, flowRule.deviceId());
-                return outRules;
-            }
-            ingressPoints.add(optionalCp.get());
-        } else {
-            for (VirtualPort vPort : vPorts) {
-                if (vPort.realizedBy() != null) {
-                    ingressPoints.add(vPort.realizedBy());
-                } else {
-                    log.info("Port {} is not realized yet, in Network {}, " +
-                                     "Device {}",
-                             vPort, networkId, flowRule.deviceId());
-                    return outRules;
-                }
-            }
-        }
-
-        PortNumber vOutPortNum = flowRule.treatment().allInstructions().stream()
-                .filter(i -> i.type() == Instruction.Type.OUTPUT)
-                .map(i -> ((Instructions.OutputInstruction) i).port())
-                .findFirst().get();
-
-        Optional<ConnectPoint> optionalCpOut = vPorts.stream()
-                .filter(v -> v.number().equals(vOutPortNum))
-                .map(v -> v.realizedBy())
-                .findFirst();
-        if (!optionalCpOut.isPresent()) {
-            log.info("Port {} is not realized yet, in Network {}, Device {}",
-                     vOutPortNum, networkId, flowRule.deviceId());
+        if (egressPoint == null) {
             return outRules;
         }
-        ConnectPoint egressPoint = optionalCpOut.get();
 
         TrafficSelector.Builder commonSelectorBuilder
                 = DefaultTrafficSelector.builder();
@@ -278,40 +257,158 @@
         TrafficTreatment commonTreatment = commonTreatmentBuilder.build();
 
         for (ConnectPoint ingressPoint : ingressPoints) {
-            outRules.addAll(generateRules(networkId, ingressPoint, egressPoint,
-                          commonSelector, commonTreatment, flowRule));
+            if (egressPoint.port() == PortNumber.FLOOD) {
+                Set<ConnectPoint> outPoints = vnService
+                        .getVirtualPorts(networkId, flowRule.deviceId())
+                        .stream()
+                        .map(VirtualPort::realizedBy)
+                        .filter(p -> !p.equals(ingressPoint))
+                        .collect(Collectors.toSet());
+
+                for (ConnectPoint outPoint : outPoints) {
+                    outRules.addAll(generateRules(networkId, ingressPoint, outPoint,
+                                                  commonSelector, commonTreatment, flowRule));
+                }
+            } else {
+                outRules.addAll(generateRules(networkId, ingressPoint, egressPoint,
+                                              commonSelector, commonTreatment, flowRule));
+            }
         }
 
         return outRules;
     }
 
+    /**
+     * Extract ingress connect points of the physical network
+     * from the requested traffic selector.
+     *
+     * @param networkId the virtual network identifier
+     * @param deviceId the virtual device identifier
+     * @param selector the traffic selector to extract ingress point
+     * @return the set of ingress connect points of the physical network
+     */
+    private Set<ConnectPoint> extractIngressPoints(NetworkId networkId,
+                                                   DeviceId deviceId,
+                                                   TrafficSelector selector) {
+
+        Set<ConnectPoint> ingressPoints = new HashSet<>();
+
+        Set<VirtualPort> vPorts = vnService
+                .getVirtualPorts(networkId, deviceId);
+
+        PortCriterion portCriterion = ((PortCriterion) selector
+                .getCriterion(Criterion.Type.IN_PORT));
+
+        if (portCriterion != null) {
+            PortNumber vInPortNum = portCriterion.port();
+
+            Optional<ConnectPoint> optionalCp =  vPorts.stream()
+                    .filter(v -> v.number().equals(vInPortNum))
+                    .map(VirtualPort::realizedBy).findFirst();
+            if (!optionalCp.isPresent()) {
+                log.warn("Port {} is not realized yet, in Network {}, Device {}",
+                         vInPortNum, networkId, deviceId);
+                return ingressPoints;
+            }
+
+            ingressPoints.add(optionalCp.get());
+        } else {
+            for (VirtualPort vPort : vPorts) {
+                if (vPort.realizedBy() != null) {
+                    ingressPoints.add(vPort.realizedBy());
+                } else {
+                    log.warn("Port {} is not realized yet, in Network {}, " +
+                                     "Device {}",
+                             vPort, networkId, deviceId);
+                }
+            }
+        }
+
+        return ingressPoints;
+    }
+
+    /**
+     * Extract egress connect point of the physical network
+     * from the requested traffic treatment.
+     *
+     * @param networkId the virtual network identifier
+     * @param deviceId the virtual device identifier
+     * @param treatment the traffic treatment to extract ingress point
+     * @return the egress connect point of the physical network
+     */
+    private ConnectPoint extractEgressPoints(NetworkId networkId,
+                                                  DeviceId deviceId,
+                                                  TrafficTreatment treatment) {
+
+        Set<VirtualPort> vPorts = vnService
+                .getVirtualPorts(networkId, deviceId);
+
+        PortNumber vOutPortNum = treatment.allInstructions().stream()
+                .filter(i -> i.type() == Instruction.Type.OUTPUT)
+                .map(i -> ((Instructions.OutputInstruction) i).port())
+                .findFirst().get();
+
+        Optional<ConnectPoint> optionalCpOut = vPorts.stream()
+                .filter(v -> v.number().equals(vOutPortNum))
+                .map(VirtualPort::realizedBy)
+                .findFirst();
+
+        if (!optionalCpOut.isPresent()) {
+            if (vOutPortNum.isLogical()) {
+                return new ConnectPoint(DeviceId.deviceId("vNet"), vOutPortNum);
+            }
+
+            log.warn("Port {} is not realized yet, in Network {}, Device {}",
+                     vOutPortNum, networkId, deviceId);
+            return null;
+        }
+
+        return optionalCpOut.get();
+    }
+
+
+    /**
+     * Generates the corresponding flow rules for the physical network.
+     *
+     * @param networkId The virtual network identifier
+     * @param ingressPoint The ingress point of the physical network
+     * @param egressPoint The egress point of the physical network
+     * @param commonSelector A common traffic selector between the virtual
+     *                       and physical flow rules
+     * @param commonTreatment A common traffic treatment between the virtual
+     *                        and physical flow rules
+     * @param flowRule The virtual flow rule to be translated
+     * @return A set of flow rules for the physical network
+     */
     private Set<FlowRule> generateRules(NetworkId networkId,
                                         ConnectPoint ingressPoint,
                                         ConnectPoint egressPoint,
-                                    TrafficSelector commonSelector,
-                                    TrafficTreatment commonTreatment,
+                                        TrafficSelector commonSelector,
+                                        TrafficTreatment commonTreatment,
                                         FlowRule flowRule) {
 
         Set<FlowRule> outRules = new HashSet<>();
 
-        if (ingressPoint.deviceId().equals(egressPoint.deviceId())) {
+        if (ingressPoint.deviceId().equals(egressPoint.deviceId()) ||
+                egressPoint.port().isLogical()) {
             //Traffic is handled inside a single physical switch
             //No tunnel is needed.
 
-            TrafficSelector.Builder selectorBuilder =
-                    DefaultTrafficSelector.builder(commonSelector);
-            selectorBuilder.matchInPort(ingressPoint.port());
+            TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector
+                    .builder(commonSelector)
+                    .matchInPort(ingressPoint.port());
 
-            TrafficTreatment.Builder treatmentBuilder =
-                    DefaultTrafficTreatment.builder(commonTreatment);
-            treatmentBuilder.setOutput(egressPoint.port());
+            TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment
+                    .builder(commonTreatment)
+                    .setOutput(egressPoint.port());
 
-            FlowRule.Builder ruleBuilder = DefaultFlowRule.builder();
-            ruleBuilder.fromApp(appId);
-            ruleBuilder.forDevice(ingressPoint.deviceId());
-            ruleBuilder.withSelector(selectorBuilder.build());
-            ruleBuilder.withTreatment(treatmentBuilder.build());
-            ruleBuilder.withPriority(FLOW_RULE_PRIORITY);
+            FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
+                    .fromApp(vnService.getVirtualNetworkApplicationId(networkId))
+                    .forDevice(ingressPoint.deviceId())
+                    .withSelector(selectorBuilder.build())
+                    .withTreatment(treatmentBuilder.build())
+                    .withPriority(flowRule.priority());
+
             if (flowRule.isPermanent()) {
                 ruleBuilder.makePermanent();
             } else {
@@ -320,7 +417,7 @@
 
             FlowRule rule = ruleBuilder.build();
             frm.addIngressRule(flowRule, rule, networkId);
-            outRules.add(ruleBuilder.build());
+            outRules.add(rule);
         } else {
             //Traffic is handled by multiple physical switches
             //A tunnel is needed.
@@ -329,7 +426,7 @@
                     .findPath(ingressPoint, egressPoint);
             checkNotNull(internalPath, "No path between " +
                     ingressPoint.toString() + " " + egressPoint.toString());
-            ConnectPoint inCp = ingressPoint;
+
             ConnectPoint outCp = internalPath.links().get(0).src();
 
             //ingress point of tunnel
@@ -339,16 +436,18 @@
 
             TrafficTreatment.Builder treatmentBuilder =
                     DefaultTrafficTreatment.builder(commonTreatment);
+            //TODO: add the logic to check host location
             treatmentBuilder.pushVlan()
                     .setVlanId(VlanId.vlanId(networkId.id().shortValue()));
             treatmentBuilder.setOutput(outCp.port());
 
-            FlowRule.Builder ruleBuilder = DefaultFlowRule.builder();
-            ruleBuilder.fromApp(appId);
-            ruleBuilder.forDevice(ingressPoint.deviceId());
-            ruleBuilder.withSelector(selectorBuilder.build());
-            ruleBuilder.withTreatment(treatmentBuilder.build());
-            ruleBuilder.withPriority(FLOW_RULE_PRIORITY);
+            FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
+                    .fromApp(vnService.getVirtualNetworkApplicationId(networkId))
+                    .forDevice(ingressPoint.deviceId())
+                    .withSelector(selectorBuilder.build())
+                    .withTreatment(treatmentBuilder.build())
+                    .withPriority(flowRule.priority());
+
             if (flowRule.isPermanent()) {
                 ruleBuilder.makePermanent();
             } else {
@@ -357,32 +456,33 @@
 
             FlowRule rule = ruleBuilder.build();
             frm.addIngressRule(flowRule, rule, networkId);
-            outRules.add(ruleBuilder.build());
+            outRules.add(rule);
 
             //routing inside tunnel
-            inCp = internalPath.links().get(0).dst();
+            ConnectPoint inCp = internalPath.links().get(0).dst();
 
             if (internalPath.links().size() > 1) {
                 for (Link l : internalPath.links()
-                        .subList(1, internalPath.links().size() - 1)) {
+                        .subList(1, internalPath.links().size())) {
 
                     outCp = l.src();
 
                     selectorBuilder = DefaultTrafficSelector
-                            .builder(commonSelector);
-                    selectorBuilder.matchVlanId(
-                            VlanId.vlanId(networkId.id().shortValue()));
-                    selectorBuilder.matchInPort(inCp.port());
+                            .builder(commonSelector)
+                            .matchVlanId(VlanId.vlanId(networkId.id().shortValue()))
+                            .matchInPort(inCp.port());
 
                     treatmentBuilder = DefaultTrafficTreatment
-                            .builder(commonTreatment);
-                    treatmentBuilder.setOutput(outCp.port());
+                            .builder(commonTreatment)
+                            .setOutput(outCp.port());
 
-                    ruleBuilder = DefaultFlowRule.builder();
-                    ruleBuilder.fromApp(appId);
-                    ruleBuilder.forDevice(inCp.deviceId());
-                    ruleBuilder.withSelector(selectorBuilder.build());
-                    ruleBuilder.withTreatment(treatmentBuilder.build());
+                    ruleBuilder = DefaultFlowRule.builder()
+                            .fromApp(vnService.getVirtualNetworkApplicationId(networkId))
+                            .forDevice(inCp.deviceId())
+                            .withSelector(selectorBuilder.build())
+                            .withTreatment(treatmentBuilder.build())
+                            .withPriority(flowRule.priority());
+
                     if (flowRule.isPermanent()) {
                         ruleBuilder.makePermanent();
                     } else {
@@ -395,21 +495,21 @@
             }
 
             //egress point of tunnel
-            selectorBuilder = DefaultTrafficSelector.builder(commonSelector);
-            selectorBuilder.matchVlanId(
-                    VlanId.vlanId(networkId.id().shortValue()));
-            selectorBuilder.matchInPort(ingressPoint.port());
+            selectorBuilder = DefaultTrafficSelector.builder(commonSelector)
+                    .matchVlanId(VlanId.vlanId(networkId.id().shortValue()))
+                    .matchInPort(inCp.port());
 
-            treatmentBuilder = DefaultTrafficTreatment.builder(commonTreatment);
-            treatmentBuilder.popVlan();
-            treatmentBuilder.setOutput(egressPoint.port());
+            treatmentBuilder = DefaultTrafficTreatment.builder(commonTreatment)
+                    .popVlan()
+                    .setOutput(egressPoint.port());
 
-            ruleBuilder = DefaultFlowRule.builder();
-            ruleBuilder.fromApp(appId);
-            ruleBuilder.forDevice(egressPoint.deviceId());
-            ruleBuilder.withSelector(selectorBuilder.build());
-            ruleBuilder.withTreatment(treatmentBuilder.build());
-            ruleBuilder.withPriority(FLOW_RULE_PRIORITY);
+            ruleBuilder = DefaultFlowRule.builder()
+                    .fromApp(appId)
+                    .forDevice(egressPoint.deviceId())
+                    .withSelector(selectorBuilder.build())
+                    .withTreatment(treatmentBuilder.build())
+                    .withPriority(flowRule.priority());
+
             if (flowRule.isPermanent()) {
                 ruleBuilder.makePermanent();
             } else {
@@ -425,20 +525,21 @@
     private class InternalFlowRuleListener implements FlowRuleListener {
         @Override
         public void event(FlowRuleEvent event) {
-
             if ((event.type() == FlowRuleEvent.Type.RULE_ADDED) ||
                     (event.type() == FlowRuleEvent.Type.RULE_UPDATED)) {
                 if (frm.isVirtualIngressRule(event.subject())) {
                     NetworkId networkId = frm.getVirtualNetworkId(event.subject());
                     FlowEntry vEntry = getVirtualFlowEntry(event.subject());
-                    ImmutableList.Builder<FlowEntry> builder = ImmutableList.builder();
-                    builder.add(vEntry);
+                    frm.addOrUpdateFlowEntry(networkId, vEntry.deviceId(), vEntry);
 
                     VirtualFlowRuleProviderService providerService =
                             (VirtualFlowRuleProviderService) providerRegistryService
                                     .getProviderService(networkId,
                                                         VirtualFlowRuleProvider.class);
 
+                    ImmutableList.Builder<FlowEntry> builder = ImmutableList.builder();
+                    builder.addAll(frm.getFlowEntries(networkId, vEntry.deviceId()));
+
                     providerService.pushFlowMetrics(vEntry.deviceId(), builder.build());
                 }
             } else if (event.type() == FlowRuleEvent.Type.RULE_REMOVED) {
@@ -452,7 +553,6 @@
                                     .getProviderService(networkId,
                                                         VirtualFlowRuleProvider.class);
                     providerService.flowRemoved(vEntry);
-
                 }
             }
         }
@@ -480,31 +580,15 @@
         final Table<NetworkId, DeviceId, Set<FlowRule>> flowRuleTable
                 = HashBasedTable.create();
 
-        /** <Virtual Network ID, Virtual Device ID, Virtual Flow Rules>.*/
-        final Table<NetworkId, DeviceId, Set<FlowRule>> missingFlowRuleTable
-                = HashBasedTable.create();
-
         /** <Virtual Network ID, Virtual Device ID, Virtual Flow Entries>.*/
         final Table<NetworkId, DeviceId, Set<FlowEntry>> flowEntryTable
                 = HashBasedTable.create();
 
         /** <Physical Flow Rule, Virtual Network ID>.*/
-        final Map<FlowRule, NetworkId> ingressRuleMap = Maps.newConcurrentMap();
+        final Map<FlowRule, NetworkId> ingressRuleMap = Maps.newHashMap();
 
         /** <Physical Flow Rule, Virtual Virtual Flow Rule>.*/
-        final Map<FlowRule, FlowRule> virtualizationMap = Maps.newConcurrentMap();
-
-        private int getFlowRuleCount(NetworkId networkId, DeviceId deviceId) {
-            return flowRuleTable.get(networkId, deviceId).size();
-        }
-
-        private int getMissingFlowCount(NetworkId networkId, DeviceId deviceId) {
-            return missingFlowRuleTable.get(networkId, deviceId).size();
-        }
-
-        private int getFlowEntryCount(NetworkId networkId, DeviceId deviceId) {
-            return flowEntryTable.get(networkId, deviceId).size();
-        }
+        final Map<FlowRule, FlowRule> virtualizationMap = Maps.newHashMap();
 
         private Iterable<FlowRule> getFlowRules(NetworkId networkId,
                                                 DeviceId deviceId) {
@@ -535,35 +619,11 @@
             set.remove(flowRule);
         }
 
-        private Set<FlowRule> getMissingRules(NetworkId networkId,
-                                                   DeviceId deviceId) {
-            return missingFlowRuleTable.get(networkId, deviceId);
-        }
-
-        private void addMissingFlowRule(NetworkId networkId, DeviceId deviceId,
-                                 FlowRule flowRule) {
-            Set<FlowRule> set = missingFlowRuleTable.get(networkId, deviceId);
-            if (set == null) {
-                set = Sets.newHashSet();
-                missingFlowRuleTable.put(networkId, deviceId, set);
-            }
-            set.add(flowRule);
-        }
-
-        private void removeMissingFlowRule(NetworkId networkId, DeviceId deviceId,
-                                    FlowRule flowRule) {
-            Set<FlowRule> set = missingFlowRuleTable.get(networkId, deviceId);
-            if (set == null) {
-                return;
-            }
-            set.remove(flowRule);
-        }
-
-        private void addFlowEntry(NetworkId networkId, DeviceId deviceId,
+        private void addOrUpdateFlowEntry(NetworkId networkId, DeviceId deviceId,
                                   FlowEntry flowEntry) {
             Set<FlowEntry> set = flowEntryTable.get(networkId, deviceId);
             if (set == null) {
-                set = Sets.newHashSet();
+                set = Sets.newConcurrentHashSet();
                 flowEntryTable.put(networkId, deviceId, set);
             }
 
@@ -571,11 +631,6 @@
             set.stream().filter(fe -> fe.exactMatch(flowEntry))
                     .forEach(set::remove);
             set.add(flowEntry);
-
-            //Remove old entry from missing flow
-            getMissingRules(networkId, deviceId).stream()
-                    .filter(fr -> fr.exactMatch(flowEntry))
-                    .forEach(fr -> removeMissingFlowRule(networkId, deviceId, fr));
         }
 
         private void removeFlowEntry(NetworkId networkId, DeviceId deviceId,
@@ -594,11 +649,16 @@
         }
 
         private FlowRule getVirtualRule(FlowRule physicalRule) {
-            return virtualizationMap.get(physicalRule);
+                return virtualizationMap.get(physicalRule);
+        }
+
+        private void removeIngressRule(FlowRule physicalRule) {
+            ingressRuleMap.remove(physicalRule);
+            virtualizationMap.remove(physicalRule);
         }
 
         private Set<FlowRule> getAllPhysicalRule() {
-            return ImmutableSet.copyOf(virtualizationMap.keySet());
+            return copyOf(virtualizationMap.keySet());
         }
 
         private NetworkId getVirtualNetworkId(FlowRule physicalRule) {
@@ -614,34 +674,6 @@
         private boolean isVirtualIngressRule(FlowRule flowRule) {
             return ingressRuleMap.containsKey(flowRule);
         }
-
-        private Set<Pair<NetworkId, DeviceId>> getCompletedDevice(boolean
-                                                                  withMissing) {
-
-            Set<Pair<NetworkId, DeviceId>> completed = new HashSet<>();
-
-            for (Table.Cell<NetworkId, DeviceId, Set<FlowRule>> cell
-                    : flowRuleTable.cellSet()) {
-
-                int ruleCount = getFlowRuleCount(cell.getRowKey(),
-                                                 cell.getColumnKey());
-                int missingFlowCount = getMissingFlowCount(cell.getRowKey(),
-                                                           cell.getColumnKey());
-                int entryCount = getFlowEntryCount(cell.getRowKey(),
-                                                   cell.getColumnKey());
-
-                if (withMissing && (ruleCount == missingFlowCount + entryCount)) {
-                    if (ruleCount < entryCount) {
-                        completed.add(new Pair<>(cell.getRowKey(),
-                                                 cell.getColumnKey()));
-                    }
-                } else if (ruleCount == entryCount) {
-                    completed.add(new Pair<>(cell.getRowKey(),
-                                             cell.getColumnKey()));
-                }
-            }
-            return completed;
-        }
     }
 
     private class DefaultInternalRoutingAlgorithm
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/provider/DefaultVirtualPacketProvider.java b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/provider/DefaultVirtualPacketProvider.java
index 36b4397..b53df03 100644
--- a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/provider/DefaultVirtualPacketProvider.java
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/provider/DefaultVirtualPacketProvider.java
@@ -17,6 +17,7 @@
 package org.onosproject.incubator.net.virtual.impl.provider;
 
 import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -37,6 +38,7 @@
 import org.onosproject.incubator.net.virtual.provider.VirtualPacketProviderService;
 import org.onosproject.incubator.net.virtual.provider.VirtualProviderRegistryService;
 import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DeviceId;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.flow.DefaultTrafficTreatment;
 import org.onosproject.net.flow.TrafficTreatment;
@@ -47,6 +49,7 @@
 import org.onosproject.net.packet.InboundPacket;
 import org.onosproject.net.packet.OutboundPacket;
 import org.onosproject.net.packet.PacketContext;
+import org.onosproject.net.packet.PacketPriority;
 import org.onosproject.net.packet.PacketProcessor;
 import org.onosproject.net.packet.PacketService;
 import org.onosproject.net.provider.ProviderId;
@@ -68,6 +71,7 @@
         implements VirtualPacketProvider {
 
     private static final int PACKET_PROCESSOR_PRIORITY = 1;
+    private static final PacketPriority VIRTUAL_PACKET_PRIORITY = PacketPriority.REACTIVE;
 
     private final Logger log = getLogger(getClass());
 
@@ -78,7 +82,7 @@
     protected CoreService coreService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected VirtualNetworkAdminService virtualNetworkAdminService;
+    protected VirtualNetworkAdminService vnaService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected VirtualProviderRegistryService providerRegistryService;
@@ -86,7 +90,9 @@
     ApplicationId appId;
     InternalPacketProcessor processor;
 
-    Map<VirtualPacketContext, PacketContext> contextMap;
+    private Map<VirtualPacketContext, PacketContext> contextMap;
+
+    private Set<NetworkId> requestsSet = Sets.newHashSet();
 
     /**
      * Creates a provider with the supplied identifier.
@@ -113,6 +119,7 @@
         if (processor != null) {
             packetService.removeProcessor(processor);
         }
+        log.info("Stopped");
     }
 
     @Modified
@@ -127,9 +134,23 @@
     }
 
     @Override
-    public void startPacketHandling() {
-        processor = new InternalPacketProcessor();
-        packetService.addProcessor(processor, PACKET_PROCESSOR_PRIORITY);
+    public void startPacketHandling(NetworkId networkId) {
+        requestsSet.add(networkId);
+
+        if (processor == null) {
+            processor = new InternalPacketProcessor();
+            packetService.addProcessor(processor, PACKET_PROCESSOR_PRIORITY);
+        }
+    }
+
+    @Override
+    public void stopPacketHandling(NetworkId networkId) {
+        requestsSet.remove(networkId);
+
+        if (requestsSet.isEmpty()) {
+            packetService.removeProcessor(processor);
+            processor = null;
+        }
     }
 
     /**
@@ -139,36 +160,11 @@
      * @param context A physical PacketContext be translated
      * @return A translated virtual PacketContext
      */
-    private Set<VirtualPacketContext> virtualize(PacketContext context) {
-        Set<VirtualPacketContext> outContext = new HashSet<>();
+    private VirtualPacketContext virtualize(PacketContext context) {
 
-        Set<TenantId> tIds = virtualNetworkAdminService.getTenantIds();
+        VirtualPort vPort = getMappedVirtualPort(context.inPacket().receivedFrom());
 
-        Set<VirtualNetwork> vNetworks = new HashSet<>();
-        tIds.stream()
-                .map(tid -> virtualNetworkAdminService
-                        .getVirtualNetworks(tid))
-                .forEach(vNetworks::addAll);
-
-        Set<VirtualDevice> vDevices = new HashSet<>();
-        vNetworks.stream()
-                .map(network -> virtualNetworkAdminService
-                        .getVirtualDevices(network.id()))
-                .forEach(vDevices::addAll);
-
-        Set<VirtualPort> vPorts = new HashSet<>();
-        vDevices.stream()
-                .map(dev -> virtualNetworkAdminService
-                        .getVirtualPorts(dev.networkId(), dev.id()))
-                .forEach(vPorts::addAll);
-
-        ConnectPoint inCp = context.inPacket().receivedFrom();
-
-        Set<VirtualPort> inVports = vPorts.stream()
-                .filter(vp -> vp.realizedBy().equals(inCp))
-                .collect(Collectors.toSet());
-
-        for (VirtualPort vPort : inVports) {
+        if (vPort != null) {
             ConnectPoint cp = new ConnectPoint(vPort.element().id(),
                                                vPort.number());
 
@@ -179,16 +175,54 @@
                     new DefaultInboundPacket(cp, eth,
                                              ByteBuffer.wrap(eth.serialize()));
 
+            DefaultOutboundPacket outPkt =
+                    new DefaultOutboundPacket(cp.deviceId(),
+                                              DefaultTrafficTreatment.builder().build(),
+                                              ByteBuffer.wrap(eth.serialize()));
+
             VirtualPacketContext vContext =
-                    new VirtualPacketContext(context.time(), inPacket, null,
+                    new VirtualPacketContext(context.time(), inPacket, outPkt,
                                              false, vPort.networkId(),
                                              this);
 
             contextMap.put(vContext, context);
-            outContext.add(vContext);
+
+            return vContext;
+        } else {
+            return null;
         }
 
-        return outContext;
+    }
+
+    /**
+     * Find the corresponding virtual port with the physical port.
+     *
+     * @param cp the connect point for the physical network
+     * @return a virtual port
+     */
+    private VirtualPort getMappedVirtualPort(ConnectPoint cp) {
+        Set<TenantId> tIds = vnaService.getTenantIds();
+
+        Set<VirtualNetwork> vNetworks = new HashSet<>();
+        tIds.forEach(tid -> vNetworks.addAll(vnaService.getVirtualNetworks(tid)));
+
+        for (VirtualNetwork vNet : vNetworks) {
+            Set<VirtualDevice> vDevices = vnaService.getVirtualDevices(vNet.id());
+
+            Set<VirtualPort> vPorts = new HashSet<>();
+            vDevices.forEach(dev -> vPorts
+                    .addAll(vnaService.getVirtualPorts(dev.networkId(), dev.id())));
+
+            VirtualPort vPort = vPorts.stream()
+                    .filter(vp -> vp.realizedBy().equals(cp))
+                    .findFirst().orElse(null);
+
+            if (vPort != null) {
+                return vPort;
+            }
+        }
+
+        return null;
     }
 
     /**
@@ -200,7 +234,7 @@
      * @return de-virtualized (physical) OutboundPacket
      */
     private OutboundPacket devirtualize(NetworkId networkId, OutboundPacket packet) {
-        Set<VirtualPort> vPorts = virtualNetworkAdminService
+        Set<VirtualPort> vPorts = vnaService
                 .getVirtualPorts(networkId, packet.sendThrough());
 
         PortNumber vOutPortNum = packet.treatment().allInstructions().stream()
@@ -213,7 +247,7 @@
                 .map(v -> v.realizedBy())
                 .findFirst();
         if (!optionalCpOut.isPresent()) {
-            log.info("Port {} is not realized yet, in Network {}, Device {}",
+            log.warn("Port {} is not realized yet, in Network {}, Device {}",
                      vOutPortNum, networkId, packet.sendThrough());
             return null;
         }
@@ -243,37 +277,78 @@
      * See {@link org.onosproject.net.packet.PacketContext}
      *
      * @param context A handled packet context
-     * @return de-virtualized (physical) PacketContext
      */
-    public PacketContext devirtualizeContext(VirtualPacketContext context) {
+    public void devirtualizeContext(VirtualPacketContext context) {
         NetworkId networkId = context.getNetworkId();
 
-        OutboundPacket op = devirtualize(networkId, context.outPacket());
+        TrafficTreatment vTreatment = context.treatmentBuilder().build();
 
-        PacketContext packetContext = contextMap.get(context);
+        DeviceId sendThrough = context.outPacket().sendThrough();
 
-        TrafficTreatment.Builder treatmentBuilder
-                = packetContext.treatmentBuilder();
-        if (op.treatment() != null) {
-            op.treatment().allInstructions().forEach(treatmentBuilder::add);
+        PortNumber vOutPortNum = vTreatment.allInstructions().stream()
+                .filter(i -> i.type() == Instruction.Type.OUTPUT)
+                .map(i -> ((Instructions.OutputInstruction) i).port())
+                .findFirst().get();
+
+        TrafficTreatment.Builder commonTreatmentBuilder
+                = DefaultTrafficTreatment.builder();
+        vTreatment.allInstructions().stream()
+                .filter(i -> i.type() != Instruction.Type.OUTPUT)
+                .forEach(i -> commonTreatmentBuilder.add(i));
+        TrafficTreatment commonTreatment = commonTreatmentBuilder.build();
+
+        if (!vOutPortNum.isLogical()) {
+            TrafficTreatment treatment = DefaultTrafficTreatment
+                    .builder()
+                    .addTreatment(commonTreatment)
+                    .setOutput(vOutPortNum)
+                    .build();
+
+            emit(networkId, new DefaultOutboundPacket(sendThrough,
+                                                      treatment,
+                                                      context.outPacket().data()));
+        } else {
+            if (vOutPortNum == PortNumber.FLOOD) {
+                Set<VirtualPort> vPorts = vnaService
+                        .getVirtualPorts(networkId, sendThrough);
+
+                Set<VirtualPort> outPorts = vPorts.stream()
+                        .filter(vp -> vp.number() !=
+                                context.inPacket().receivedFrom().port())
+                        .collect(Collectors.toSet());
+
+                for (VirtualPort outPort : outPorts) {
+                    TrafficTreatment treatment = DefaultTrafficTreatment
+                            .builder()
+                            .addTreatment(commonTreatment)
+                            .setOutput(outPort.number())
+                            .build();
+
+                    emit(networkId, new DefaultOutboundPacket(sendThrough,
+                                                   treatment,
+                                                   context.outPacket().data()));
+                }
+            }
         }
-
-        return packetContext;
     }
 
     private final class InternalPacketProcessor implements PacketProcessor {
 
         @Override
         public void process(PacketContext context) {
-            Set<VirtualPacketContext> vContexts = virtualize(context);
+            VirtualPacketContext vContexts = virtualize(context);
 
-            vContexts.forEach(vpc -> {
-                                  VirtualPacketProviderService service =
-                                          (VirtualPacketProviderService) providerRegistryService
-                                                  .getProviderService(vpc.getNetworkId(),
-                                                                      VirtualPacketProvider.class);
-                                  service.processPacket(vpc);
-                              });
+            if (vContexts == null) {
+                return;
+            }
+
+            VirtualPacketProviderService service =
+                    (VirtualPacketProviderService) providerRegistryService
+                            .getProviderService(vContexts.getNetworkId(),
+                                                VirtualPacketProvider.class);
+            if (service != null) {
+                service.processPacket(vContexts);
+            }
         }
     }
 }
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/provider/VirtualPacketContext.java b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/provider/VirtualPacketContext.java
index 931fb22..9d03b0dc 100644
--- a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/provider/VirtualPacketContext.java
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/provider/VirtualPacketContext.java
@@ -20,7 +20,6 @@
 import org.onosproject.net.packet.DefaultPacketContext;
 import org.onosproject.net.packet.InboundPacket;
 import org.onosproject.net.packet.OutboundPacket;
-import org.onosproject.net.packet.PacketContext;
 
 /**
  * Represents context for processing an inbound packet for a virtual network
@@ -55,8 +54,7 @@
     @Override
     public void send() {
         if (!this.block()) {
-            PacketContext context = dvpp.devirtualizeContext(this);
-            context.send();
+            dvpp.devirtualizeContext(this);
         }
     }
 
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/provider/VirtualProviderManager.java b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/provider/VirtualProviderManager.java
index c822066..9bf5c33 100644
--- a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/provider/VirtualProviderManager.java
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/provider/VirtualProviderManager.java
@@ -84,12 +84,9 @@
     public synchronized void
     registerProviderService(NetworkId networkId,
                             VirtualProviderService virtualProviderService) {
-        Set<VirtualProviderService> services = servicesByNetwork.get(networkId);
+        Set<VirtualProviderService> services =
+                servicesByNetwork.computeIfAbsent(networkId, k -> new HashSet<>());
 
-        if (services == null) {
-            services = new HashSet<>();
-            servicesByNetwork.put(networkId, services);
-        }
         services.add(virtualProviderService);
     }
 
@@ -146,7 +143,7 @@
 
         return services.stream()
                 .filter(s -> getProviderClass(s).equals(providerClass))
-                .findFirst().get();
+                .findFirst().orElse(null);
     }
 
     /**
diff --git a/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkPacketManagerTest.java b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkPacketManagerTest.java
index 184a30e..be91963 100644
--- a/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkPacketManagerTest.java
+++ b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkPacketManagerTest.java
@@ -338,7 +338,12 @@
         }
 
         @Override
-        public void startPacketHandling() {
+        public void startPacketHandling(NetworkId networkId) {
+
+        }
+
+        @Override
+        public void stopPacketHandling(NetworkId networkId) {
 
         }
     }
diff --git a/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/provider/DefaultVirtualFlowRuleProviderTest.java b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/provider/DefaultVirtualFlowRuleProviderTest.java
index 0d3c8cc..2b010bb 100644
--- a/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/provider/DefaultVirtualFlowRuleProviderTest.java
+++ b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/provider/DefaultVirtualFlowRuleProviderTest.java
@@ -73,6 +73,7 @@
 import org.onosproject.net.topology.Topology;
 import org.onosproject.net.topology.TopologyServiceAdapter;
 
+import java.util.Arrays;
 import java.util.HashSet;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicLong;
@@ -125,7 +126,6 @@
 
     private static final int TIMEOUT = 10;
 
-
     protected DefaultVirtualFlowRuleProvider virtualProvider;
 
     private ApplicationId vAppId;
@@ -136,7 +136,7 @@
 
         virtualProvider.deviceService = new TestDeviceService();
         virtualProvider.coreService = new TestCoreService();
-        virtualProvider.virtualNetworkAdminService =
+        virtualProvider.vnService =
                 new TestVirtualNetworkAdminService();
         virtualProvider.topologyService = new TestTopologyService();
         virtualProvider.flowRuleService = new TestFlowRuleService();
@@ -154,7 +154,7 @@
     }
 
     @Test
-    public void virtualizeFlowRuleWithInPort() {
+    public void devirtualizeFlowRuleWithInPort() {
         TrafficSelector ts = DefaultTrafficSelector.builder()
                 .matchInPort(PORT_NUM1).build();
         TrafficTreatment tr = DefaultTrafficTreatment.builder()
@@ -203,7 +203,7 @@
     }
 
     @Test
-    public void virtualizeFlowRuleWithoutInPort() {
+    public void devirtualizeFlowRuleWithoutInPort() {
         TrafficSelector ts = DefaultTrafficSelector.builder().build();
         TrafficTreatment tr = DefaultTrafficTreatment.builder()
                 .setOutput(PORT_NUM2).build();
@@ -327,7 +327,7 @@
         }
     }
 
-    private static class TestVirtualNetworkAdminService
+    private class TestVirtualNetworkAdminService
             implements VirtualNetworkAdminService {
 
         @Override
@@ -368,7 +368,7 @@
 
         @Override
         public ApplicationId getVirtualNetworkApplicationId(NetworkId networkId) {
-            return null;
+            return vAppId;
         }
 
         @Override
@@ -504,15 +504,13 @@
         public Iterable<FlowEntry> getFlowEntries(DeviceId deviceId) {
             return ruleCollection.stream()
                     .filter(r -> r.deviceId().equals(deviceId))
-                    .map(r -> new DefaultFlowEntry(r))
+                    .map(DefaultFlowEntry::new)
                     .collect(Collectors.toSet());
         }
 
         @Override
         public void applyFlowRules(FlowRule... flowRules) {
-            for (FlowRule rule : flowRules) {
-                ruleCollection.add(rule);
-            }
+            ruleCollection.addAll(Arrays.asList(flowRules));
         }
 
         @Override
diff --git a/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/provider/DefaultVirtualPacketProviderTest.java b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/provider/DefaultVirtualPacketProviderTest.java
index dc99153..32c6a30 100644
--- a/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/provider/DefaultVirtualPacketProviderTest.java
+++ b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/provider/DefaultVirtualPacketProviderTest.java
@@ -55,7 +55,9 @@
 import org.onosproject.net.Link;
 import org.onosproject.net.Port;
 import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.DefaultTrafficSelector;
 import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.net.flow.TrafficTreatment;
 import org.onosproject.net.flow.instructions.Instruction;
 import org.onosproject.net.flow.instructions.Instructions;
@@ -142,7 +144,7 @@
         virtualProvider = new DefaultVirtualPacketProvider();
 
         virtualProvider.coreService = new CoreServiceAdapter();
-        virtualProvider.virtualNetworkAdminService =
+        virtualProvider.vnaService =
                 new TestVirtualNetworkAdminService();
 
         providerService = new TestVirtualPacketProviderService();
@@ -155,15 +157,19 @@
         providerManager.registerProviderService(VNET_ID, providerService);
 
         virtualProvider.activate();
-        virtualProvider.startPacketHandling();
         vAppId = new TestApplicationId(0, "Virtual App");
+
+        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+        selector.matchEthType(Ethernet.TYPE_IPV4);
+
+        virtualProvider.startPacketHandling(VNET_ID);
     }
 
     @After
     public void tearDown() {
         virtualProvider.deactivate();
         virtualProvider.coreService = null;
-        virtualProvider.virtualNetworkAdminService = null;
+        virtualProvider.vnaService = null;
     }