[ONOS-5487] Implementation skeleton for VirtualFlowProvider.

Changes
1. The default code is added as DefaultVirtualFlowProvider
2. EmbeddingAlgorithm interface is added
3. Simple test code is added

Change-Id: I4f86898b6c78e23909b172f75d4bafc8367cc8b7
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
new file mode 100644
index 0000000..320d167
--- /dev/null
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/provider/DefaultVirtualFlowRuleProvider.java
@@ -0,0 +1,665 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.incubator.net.virtual.impl.provider;
+
+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;
+import org.apache.felix.scr.annotations.Modified;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Service;
+import org.onlab.packet.VlanId;
+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.VirtualPort;
+import org.onosproject.incubator.net.virtual.provider.AbstractVirtualProvider;
+import org.onosproject.incubator.net.virtual.provider.InternalRoutingAlgorithm;
+import org.onosproject.incubator.net.virtual.provider.VirtualFlowRuleProvider;
+import org.onosproject.incubator.net.virtual.provider.VirtualFlowRuleProviderService;
+import org.onosproject.incubator.net.virtual.provider.VirtualProviderRegistryService;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Link;
+import org.onosproject.net.Path;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.device.DeviceService;
+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.FlowRuleBatchOperation;
+import org.onosproject.net.flow.FlowRuleEvent;
+import org.onosproject.net.flow.FlowRuleListener;
+import org.onosproject.net.flow.FlowRuleService;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.criteria.Criterion;
+import org.onosproject.net.flow.criteria.PortCriterion;
+import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.flow.instructions.Instructions;
+import org.onosproject.net.provider.ProviderId;
+import org.onosproject.net.topology.TopologyService;
+import org.osgi.service.component.ComponentContext;
+import org.slf4j.Logger;
+
+import java.util.Dictionary;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Provider that translate virtual flow rules into physical rules.
+ * Current implementation is based on FlowRules.
+ * This virtualize and de-virtualize virtual flow rules into physical flow rules.
+ * {@link org.onosproject.net.flow.FlowRule}
+ */
+@Component(immediate = true)
+@Service
+public class DefaultVirtualFlowRuleProvider extends AbstractVirtualProvider
+        implements VirtualFlowRuleProvider {
+
+    private static final int FLOW_RULE_PRIORITY = 10;
+
+    private final Logger log = getLogger(getClass());
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected TopologyService topologyService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected VirtualNetworkAdminService virtualNetworkAdminService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected CoreService coreService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected FlowRuleService flowRuleService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected DeviceService deviceService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected VirtualProviderRegistryService providerRegistryService;
+
+    InternalRoutingAlgorithm internalRoutingAlgorithm;
+    InternalVirtualFlowRuleManager frm;
+    ApplicationId appId;
+    FlowRuleListener flowRuleListener;
+
+    /**
+     * Creates a provider with the supplied identifier.
+     */
+    public DefaultVirtualFlowRuleProvider() {
+        super(new ProviderId("vnet-flow", "org.onosproject.virtual.vnet-flow"));
+    }
+
+
+    @Activate
+    public void activate() {
+        appId = coreService.registerApplication(
+                "org.onosproject.virtual.vnet-flow");
+
+        providerRegistryService.registerProvider(this);
+
+        flowRuleListener = new InternalFlowRuleListener();
+        flowRuleService.addListener(flowRuleListener);
+
+        internalRoutingAlgorithm = new DefaultInternalRoutingAlgorithm();
+        frm = new InternalVirtualFlowRuleManager();
+
+        log.info("Started");
+    }
+
+    @Deactivate
+    public void deactivate() {
+        flowRuleService.removeListener(flowRuleListener);
+        providerRegistryService.unregisterProvider(this);
+    }
+
+    @Modified
+    protected void modified(ComponentContext context) {
+        Dictionary<?, ?> properties = context.getProperties();
+    }
+
+    @Override
+    public void applyFlowRule(NetworkId networkId, FlowRule... flowRules) {
+        for (FlowRule flowRule : flowRules) {
+            devirtualize(networkId, flowRule).forEach(
+                    r -> {
+                        flowRuleService.applyFlowRules(r);
+                    }
+            );
+        }
+    }
+
+    @Override
+    public void removeFlowRule(NetworkId networkId, FlowRule... flowRules) {
+        for (FlowRule flowRule : flowRules) {
+            devirtualize(networkId, flowRule).forEach(
+                    r -> {
+                        flowRuleService.removeFlowRules(r);
+                    }
+            );
+        }
+    }
+
+    @Override
+    public void executeBatch(NetworkId networkId, FlowRuleBatchOperation batch) {
+        checkNotNull(batch);
+
+        //TODO: execute batch mechanism
+    }
+
+    public void setEmbeddingAlgorithm(InternalRoutingAlgorithm
+                                              internalRoutingAlgorithm) {
+        this.internalRoutingAlgorithm = internalRoutingAlgorithm;
+    }
+
+    /**
+     * Translate the requested physical flow rules into virtual flow rules.
+     *
+     * @param flowRule A virtual flow rule to be translated
+     * @return A flow rule for a specific virtual network
+     */
+    private FlowRule virtualize(FlowRule flowRule) {
+        return frm.getVirtualRule(flowRule);
+    }
+
+    private FlowEntry virtualize(FlowEntry flowEntry) {
+        FlowRule vRule = virtualize(flowEntry);
+        FlowEntry vEntry = new DefaultFlowEntry(vRule, flowEntry.state(),
+                                                flowEntry.life(),
+                                                flowEntry.packets(),
+                                                flowEntry.bytes());
+
+        return vEntry;
+    }
+
+    /**
+     * Translate the requested virtual flow rules into physical flow rules.
+     * The translation could be one to many.
+     *
+     * @param flowRule A flow rule from underlying data plane to be translated
+     * @return A set of flow rules for physical network
+     */
+    private Set<FlowRule> devirtualize(NetworkId networkId, FlowRule flowRule) {
+
+        Set<FlowRule> outRules = new HashSet<>();
+
+        Set<VirtualPort> vPorts = virtualNetworkAdminService
+                .getVirtualPorts(networkId, flowRule.deviceId());
+
+        PortCriterion portCriterion = ((PortCriterion) flowRule.selector()
+                .getCriterion(Criterion.Type.IN_PORT));
+
+        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());
+            return outRules;
+        }
+        ConnectPoint egressPoint = optionalCpOut.get();
+
+        TrafficSelector.Builder commonSelectorBuilder
+                = DefaultTrafficSelector.builder();
+        flowRule.selector().criteria().stream()
+                .filter(c -> c.type() != Criterion.Type.IN_PORT)
+                .forEach(c -> commonSelectorBuilder.add(c));
+        TrafficSelector commonSelector = commonSelectorBuilder.build();
+
+        TrafficTreatment.Builder commonTreatmentBuilder
+                = DefaultTrafficTreatment.builder();
+        flowRule.treatment().allInstructions().stream()
+                .filter(i -> i.type() != Instruction.Type.OUTPUT)
+                .forEach(i -> commonTreatmentBuilder.add(i));
+        TrafficTreatment commonTreatment = commonTreatmentBuilder.build();
+
+        for (ConnectPoint ingressPoint : ingressPoints) {
+            outRules.addAll(generateRules(networkId, ingressPoint, egressPoint,
+                          commonSelector, commonTreatment, flowRule));
+        }
+
+        return outRules;
+    }
+
+    private Set<FlowRule> generateRules(NetworkId networkId,
+                                        ConnectPoint ingressPoint,
+                                        ConnectPoint egressPoint,
+                                    TrafficSelector commonSelector,
+                                    TrafficTreatment commonTreatment,
+                                        FlowRule flowRule) {
+
+        Set<FlowRule> outRules = new HashSet<>();
+
+        if (ingressPoint.deviceId().equals(egressPoint.deviceId())) {
+            //Traffic is handled inside a single physical switch
+            //No tunnel is needed.
+
+            TrafficSelector.Builder selectorBuilder =
+                    DefaultTrafficSelector.builder(commonSelector);
+            selectorBuilder.matchInPort(ingressPoint.port());
+
+            TrafficTreatment.Builder treatmentBuilder =
+                    DefaultTrafficTreatment.builder(commonTreatment);
+            treatmentBuilder.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);
+            if (flowRule.isPermanent()) {
+                ruleBuilder.makePermanent();
+            } else {
+                ruleBuilder.makeTemporary(flowRule.timeout());
+            }
+
+            FlowRule rule = ruleBuilder.build();
+            frm.addIngressRule(flowRule, rule, networkId);
+            outRules.add(ruleBuilder.build());
+        } else {
+            //Traffic is handled by multiple physical switches
+            //A tunnel is needed.
+
+            Path internalPath = internalRoutingAlgorithm
+                    .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
+            TrafficSelector.Builder selectorBuilder =
+                    DefaultTrafficSelector.builder(commonSelector);
+            selectorBuilder.matchInPort(ingressPoint.port());
+
+            TrafficTreatment.Builder treatmentBuilder =
+                    DefaultTrafficTreatment.builder(commonTreatment);
+            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);
+            if (flowRule.isPermanent()) {
+                ruleBuilder.makePermanent();
+            } else {
+                ruleBuilder.makeTemporary(flowRule.timeout());
+            }
+
+            FlowRule rule = ruleBuilder.build();
+            frm.addIngressRule(flowRule, rule, networkId);
+            outRules.add(ruleBuilder.build());
+
+            //routing inside tunnel
+            inCp = internalPath.links().get(0).dst();
+
+            if (internalPath.links().size() > 1) {
+                for (Link l : internalPath.links()
+                        .subList(1, internalPath.links().size() - 1)) {
+
+                    outCp = l.src();
+
+                    selectorBuilder = DefaultTrafficSelector
+                            .builder(commonSelector);
+                    selectorBuilder.matchVlanId(
+                            VlanId.vlanId(networkId.id().shortValue()));
+                    selectorBuilder.matchInPort(inCp.port());
+
+                    treatmentBuilder = DefaultTrafficTreatment
+                            .builder(commonTreatment);
+                    treatmentBuilder.setOutput(outCp.port());
+
+                    ruleBuilder = DefaultFlowRule.builder();
+                    ruleBuilder.fromApp(appId);
+                    ruleBuilder.forDevice(inCp.deviceId());
+                    ruleBuilder.withSelector(selectorBuilder.build());
+                    ruleBuilder.withTreatment(treatmentBuilder.build());
+                    if (flowRule.isPermanent()) {
+                        ruleBuilder.makePermanent();
+                    } else {
+                        ruleBuilder.makeTemporary(flowRule.timeout());
+                    }
+
+                    outRules.add(ruleBuilder.build());
+                    inCp = l.dst();
+                }
+            }
+
+            //egress point of tunnel
+            selectorBuilder = DefaultTrafficSelector.builder(commonSelector);
+            selectorBuilder.matchVlanId(
+                    VlanId.vlanId(networkId.id().shortValue()));
+            selectorBuilder.matchInPort(ingressPoint.port());
+
+            treatmentBuilder = DefaultTrafficTreatment.builder(commonTreatment);
+            treatmentBuilder.popVlan();
+            treatmentBuilder.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);
+            if (flowRule.isPermanent()) {
+                ruleBuilder.makePermanent();
+            } else {
+                ruleBuilder.makeTemporary(flowRule.timeout());
+            }
+
+            outRules.add(ruleBuilder.build());
+        }
+
+        return outRules;
+    }
+
+    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);
+
+                    VirtualFlowRuleProviderService providerService =
+                            (VirtualFlowRuleProviderService) providerRegistryService
+                                    .getProviderService(networkId,
+                                                        VirtualFlowRuleProvider.class);
+
+                    providerService.pushFlowMetrics(vEntry.deviceId(), builder.build());
+                }
+            } else if (event.type() == FlowRuleEvent.Type.RULE_REMOVED) {
+                if (frm.isVirtualIngressRule(event.subject())) {
+                    //FIXME confirm all physical rules are removed
+                    NetworkId networkId = frm.getVirtualNetworkId(event.subject());
+                    FlowEntry vEntry = getVirtualFlowEntry(event.subject());
+
+                    VirtualFlowRuleProviderService providerService =
+                            (VirtualFlowRuleProviderService) providerRegistryService
+                                    .getProviderService(networkId,
+                                                        VirtualFlowRuleProvider.class);
+                    providerService.flowRemoved(vEntry);
+
+                }
+            }
+        }
+
+        private FlowEntry getVirtualFlowEntry(FlowRule rule) {
+            FlowEntry entry = null;
+            for (FlowEntry fe :
+                    flowRuleService.getFlowEntries(rule.deviceId())) {
+                if (rule.exactMatch(fe)) {
+                    entry = fe;
+                }
+            }
+
+            FlowRule vRule = virtualize(entry);
+            FlowEntry vEntry = new DefaultFlowEntry(vRule, entry.state(),
+                                                    entry.life(), entry.packets(),
+                                                    entry.bytes());
+
+            return vEntry;
+        }
+    }
+
+    private class InternalVirtualFlowRuleManager {
+        /** <Virtual Network ID, Virtual Device ID, Virtual Flow Rules>.*/
+        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();
+
+        /** <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();
+        }
+
+        private Iterable<FlowRule> getFlowRules(NetworkId networkId,
+                                                DeviceId deviceId) {
+            return flowRuleTable.get(networkId, deviceId);
+        }
+
+        private Iterable<FlowEntry> getFlowEntries(NetworkId networkId,
+                                                   DeviceId deviceId) {
+            return flowEntryTable.get(networkId, deviceId);
+        }
+
+        private void addFlowRule(NetworkId networkId, DeviceId deviceId,
+                                 FlowRule flowRule) {
+            Set<FlowRule> set = flowRuleTable.get(networkId, deviceId);
+            if (set == null) {
+                set = Sets.newHashSet();
+                flowRuleTable.put(networkId, deviceId, set);
+            }
+            set.add(flowRule);
+        }
+
+        private void removeFlowRule(NetworkId networkId, DeviceId deviceId,
+                                    FlowRule flowRule) {
+            Set<FlowRule> set = flowRuleTable.get(networkId, deviceId);
+            if (set == null) {
+                return;
+            }
+            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,
+                                  FlowEntry flowEntry) {
+            Set<FlowEntry> set = flowEntryTable.get(networkId, deviceId);
+            if (set == null) {
+                set = Sets.newHashSet();
+                flowEntryTable.put(networkId, deviceId, set);
+            }
+
+            //Replace old entry with new one
+            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,
+                                     FlowEntry flowEntry) {
+            Set<FlowEntry> set = flowEntryTable.get(networkId, deviceId);
+            if (set == null) {
+                return;
+            }
+            set.remove(flowEntry);
+        }
+
+        private void addIngressRule(FlowRule virtualRule, FlowRule physicalRule,
+                                    NetworkId networkId) {
+            ingressRuleMap.put(physicalRule, networkId);
+            virtualizationMap.put(physicalRule, virtualRule);
+        }
+
+        private FlowRule getVirtualRule(FlowRule physicalRule) {
+            return virtualizationMap.get(physicalRule);
+        }
+
+        private Set<FlowRule> getAllPhysicalRule() {
+            return ImmutableSet.copyOf(virtualizationMap.keySet());
+        }
+
+        private NetworkId getVirtualNetworkId(FlowRule physicalRule) {
+            return ingressRuleMap.get(physicalRule);
+        }
+
+        /**
+         * Test the rule is the ingress rule for virtual rules.
+         *
+         * @param flowRule A flow rule from underlying data plane to be translated
+         * @return True when the rule is for ingress point for a virtual switch
+         */
+        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
+            implements InternalRoutingAlgorithm {
+
+        @Override
+        public Path findPath(ConnectPoint src, ConnectPoint dst) {
+            Set<Path> paths =
+                    topologyService.getPaths(topologyService.currentTopology(),
+                                             src.deviceId(),
+                                             dst.deviceId());
+
+            if (paths.isEmpty()) {
+                return null;
+            }
+
+            //TODO the logic find the best path
+            return (Path) paths.toArray()[0];
+        }
+    }
+}
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 40a791f..c822066 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
@@ -137,7 +137,7 @@
 
     @Override
     public synchronized VirtualProviderService
-    getProviderService(NetworkId networkId, VirtualProvider virtualProvider) {
+    getProviderService(NetworkId networkId, Class<? extends VirtualProvider> providerClass) {
         Set<VirtualProviderService> services = servicesByNetwork.get(networkId);
 
         if (services == null) {
@@ -145,7 +145,7 @@
         }
 
         return services.stream()
-                .filter(s -> getProviderClass(s).isInstance(virtualProvider))
+                .filter(s -> getProviderClass(s).equals(providerClass))
                 .findFirst().get();
     }
 
diff --git a/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkFlowRuleManagerTest.java b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkFlowRuleManagerTest.java
index 40658bd..0afc6ea 100644
--- a/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkFlowRuleManagerTest.java
+++ b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkFlowRuleManagerTest.java
@@ -164,9 +164,9 @@
         vnetFlowRuleService2.deviceInstallers = MoreExecutors.newDirectExecutorService();
 
         providerService1 = (VirtualFlowRuleProviderService)
-                providerRegistryService.getProviderService(vnet1.id(), provider);
+                providerRegistryService.getProviderService(vnet1.id(), VirtualFlowRuleProvider.class);
         providerService2 = (VirtualFlowRuleProviderService)
-                providerRegistryService.getProviderService(vnet2.id(), provider);
+                providerRegistryService.getProviderService(vnet2.id(), VirtualFlowRuleProvider.class);
     }
 
     @After
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
new file mode 100644
index 0000000..f135464
--- /dev/null
+++ b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/provider/DefaultVirtualFlowRuleProviderTest.java
@@ -0,0 +1,663 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.incubator.net.virtual.impl.provider;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.osgi.ServiceDirectory;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.core.DefaultApplicationId;
+import org.onosproject.core.IdGenerator;
+import org.onosproject.core.Version;
+import org.onosproject.incubator.net.virtual.DefaultVirtualDevice;
+import org.onosproject.incubator.net.virtual.DefaultVirtualNetwork;
+import org.onosproject.incubator.net.virtual.DefaultVirtualPort;
+import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.incubator.net.virtual.TenantId;
+import org.onosproject.incubator.net.virtual.VirtualDevice;
+import org.onosproject.incubator.net.virtual.VirtualHost;
+import org.onosproject.incubator.net.virtual.VirtualLink;
+import org.onosproject.incubator.net.virtual.VirtualNetwork;
+import org.onosproject.incubator.net.virtual.VirtualNetworkAdminService;
+import org.onosproject.incubator.net.virtual.VirtualPort;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DefaultAnnotations;
+import org.onosproject.net.DefaultDevice;
+import org.onosproject.net.DefaultLink;
+import org.onosproject.net.DefaultPath;
+import org.onosproject.net.DefaultPort;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.DisjointPath;
+import org.onosproject.net.HostId;
+import org.onosproject.net.HostLocation;
+import org.onosproject.net.Link;
+import org.onosproject.net.Path;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.device.DeviceServiceAdapter;
+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.FlowRuleListener;
+import org.onosproject.net.flow.FlowRuleOperations;
+import org.onosproject.net.flow.FlowRuleService;
+import org.onosproject.net.flow.TableStatisticsEntry;
+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.L2ModificationInstruction;
+import org.onosproject.net.provider.ProviderId;
+import org.onosproject.net.topology.ClusterId;
+import org.onosproject.net.topology.LinkWeight;
+import org.onosproject.net.topology.Topology;
+import org.onosproject.net.topology.TopologyCluster;
+import org.onosproject.net.topology.TopologyGraph;
+import org.onosproject.net.topology.TopologyListener;
+import org.onosproject.net.topology.TopologyService;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static org.junit.Assert.assertEquals;
+
+public class DefaultVirtualFlowRuleProviderTest {
+    private static final ProviderId PID = new ProviderId("of", "foo");
+
+    private static final DeviceId DID1 = DeviceId.deviceId("of:001");
+    private static final DeviceId DID2 = DeviceId.deviceId("of:002");
+    private static final PortNumber PORT_NUM1 = PortNumber.portNumber(1);
+    private static final PortNumber PORT_NUM2 = PortNumber.portNumber(2);
+
+    private static final DefaultAnnotations ANNOTATIONS =
+            DefaultAnnotations.builder().set("foo", "bar").build();
+
+    private static final Device DEV1 =
+            new DefaultDevice(PID, DID1, Device.Type.SWITCH, "", "", "", "", null);
+    private static final Device DEV2 =
+            new DefaultDevice(PID, DID2, Device.Type.SWITCH, "", "", "", "", null);
+    private static final Port PORT11 =
+            new DefaultPort(DEV1, PORT_NUM1, true, ANNOTATIONS);
+    private static final Port PORT12 =
+            new DefaultPort(DEV1, PORT_NUM2, true, ANNOTATIONS);
+    private static final Port PORT21 =
+            new DefaultPort(DEV2, PORT_NUM1, true, ANNOTATIONS);
+    private static final Port PORT22 =
+            new DefaultPort(DEV2, PORT_NUM2, true, ANNOTATIONS);
+
+    private static final ConnectPoint CP11 = new ConnectPoint(DID1, PORT_NUM1);
+    private static final ConnectPoint CP12 = new ConnectPoint(DID1, PORT_NUM2);
+    private static final ConnectPoint CP21 = new ConnectPoint(DID2, PORT_NUM1);
+    private static final ConnectPoint CP22 = new ConnectPoint(DID2, PORT_NUM2);
+    private static final Link LINK1 = DefaultLink.builder()
+            .src(CP12).dst(CP21).providerId(PID).type(Link.Type.DIRECT).build();
+
+    private static final NetworkId VNET_ID = NetworkId.networkId(1);
+    private static final DeviceId VDID = DeviceId.deviceId("of:100");
+
+    private static final VirtualNetwork VNET = new DefaultVirtualNetwork(
+            VNET_ID, TenantId.tenantId("t1"));
+    private static final VirtualDevice VDEV =
+            new DefaultVirtualDevice(VNET_ID, VDID);
+    private static final VirtualPort VPORT1 =
+            new DefaultVirtualPort(VNET_ID, VDEV, PORT_NUM1, CP11);
+    private static final VirtualPort VPORT2 =
+            new DefaultVirtualPort(VNET_ID, VDEV, PORT_NUM2, CP22);
+
+    private static final int TIMEOUT = 10;
+
+
+    protected DefaultVirtualFlowRuleProvider virtualProvider;
+
+    private ApplicationId vAppId;
+
+    @Before
+    public void setUp() {
+        virtualProvider = new DefaultVirtualFlowRuleProvider();
+
+        virtualProvider.deviceService = new TestDeviceService();
+        virtualProvider.coreService = new TestCoreService();
+        virtualProvider.virtualNetworkAdminService =
+                new TestVirtualNetworkAdminService();
+        virtualProvider.topologyService = new TestTopologyService();
+        virtualProvider.flowRuleService = new TestFlowRuleService();
+        virtualProvider.providerRegistryService = new VirtualProviderManager();
+
+        virtualProvider.activate();
+        vAppId = new TestApplicationId(0, "Virtual App");
+    }
+
+    @After
+    public void tearDown() {
+        virtualProvider.deactivate();
+        virtualProvider.deviceService = null;
+        virtualProvider.coreService = null;
+    }
+
+    @Test
+    public void virtualizeFlowRuleWithInPort() {
+        TrafficSelector ts = DefaultTrafficSelector.builder()
+                .matchInPort(PORT_NUM1).build();
+        TrafficTreatment tr = DefaultTrafficTreatment.builder()
+                .setOutput(PORT_NUM2).build();
+
+        FlowRule r1 = DefaultFlowRule.builder()
+                .forDevice(VDID)
+                .withSelector(ts)
+                .withTreatment(tr)
+                .withPriority(10)
+                .fromApp(vAppId)
+                .makeTemporary(TIMEOUT)
+                .build();
+
+        virtualProvider.applyFlowRule(VNET_ID, r1);
+
+        assertEquals("2 rules should exist", 2,
+                     virtualProvider.flowRuleService.getFlowRuleCount());
+
+        Set<FlowEntry> phyRules = new HashSet<>();
+        for (FlowEntry i : virtualProvider.flowRuleService.getFlowEntries(DID1)) {
+            phyRules.add(i);
+        }
+        for (FlowEntry i : virtualProvider.flowRuleService.getFlowEntries(DID2)) {
+            phyRules.add(i);
+        }
+
+        FlowRule in = null;
+        FlowRule out = null;
+
+        for (FlowRule rule : phyRules) {
+
+            L2ModificationInstruction i = (L2ModificationInstruction)
+                    rule.treatment().allInstructions().get(0);
+
+            if (i.subtype() == L2ModificationInstruction.L2SubType.VLAN_PUSH) {
+                in = rule;
+            } else {
+                out = rule;
+            }
+
+        }
+
+        assertEquals(DID1, in.deviceId());
+        assertEquals(DID2, out.deviceId());
+    }
+
+    @Test
+    public void virtualizeFlowRuleWithoutInPort() {
+        TrafficSelector ts = DefaultTrafficSelector.builder().build();
+        TrafficTreatment tr = DefaultTrafficTreatment.builder()
+                .setOutput(PORT_NUM2).build();
+
+        FlowRule r1 = DefaultFlowRule.builder()
+                .forDevice(VDID)
+                .withSelector(ts)
+                .withTreatment(tr)
+                .withPriority(10)
+                .fromApp(vAppId)
+                .makeTemporary(TIMEOUT)
+                .build();
+
+        virtualProvider.applyFlowRule(VNET_ID, r1);
+
+        assertEquals("3 rules should exist", 3,
+                     virtualProvider.flowRuleService.getFlowRuleCount());
+
+        FlowRule inFromDID1 = null;
+        FlowRule inFromDID2 = null;
+        FlowRule out = null;
+
+        Set<FlowEntry> phyRules = new HashSet<>();
+        for (FlowEntry i : virtualProvider.flowRuleService.getFlowEntries(DID1)) {
+            phyRules.add(i);
+        }
+        for (FlowEntry i : virtualProvider.flowRuleService.getFlowEntries(DID2)) {
+            phyRules.add(i);
+        }
+
+        for (FlowRule rule : phyRules) {
+            for (Instruction inst : rule.treatment().allInstructions()) {
+                if (inst.type() == Instruction.Type.L2MODIFICATION) {
+                    L2ModificationInstruction i = (L2ModificationInstruction) inst;
+                    if (i.subtype() == L2ModificationInstruction.L2SubType.VLAN_PUSH) {
+                        inFromDID1 = rule;
+                        break;
+                    } else {
+                        out = rule;
+                        break;
+                    }
+                } else {
+                    inFromDID2 = rule;
+                    break;
+                }
+            }
+        }
+
+        assertEquals(DID1, inFromDID1.deviceId());
+        assertEquals(DID2, inFromDID2.deviceId());
+        assertEquals(DID2, out.deviceId());
+    }
+
+    @Test
+    public void removeVirtualizeFlowRule() {
+        TrafficSelector ts = DefaultTrafficSelector.builder().build();
+        TrafficTreatment tr = DefaultTrafficTreatment.builder()
+                .setOutput(PORT_NUM2).build();
+
+        FlowRule r1 = DefaultFlowRule.builder()
+                .forDevice(VDID)
+                .withSelector(ts)
+                .withTreatment(tr)
+                .withPriority(10)
+                .fromApp(vAppId)
+                .makeTemporary(TIMEOUT)
+                .build();
+
+        virtualProvider.removeFlowRule(VNET_ID, r1);
+
+        assertEquals("0 rules should exist", 0,
+                     virtualProvider.flowRuleService.getFlowRuleCount());
+    }
+
+
+    private static class TestDeviceService extends DeviceServiceAdapter {
+        @Override
+        public int getDeviceCount() {
+            return 2;
+        }
+
+        @Override
+        public Iterable<Device> getDevices() {
+            return ImmutableList.of(DEV1, DEV2);
+        }
+
+        @Override
+        public Iterable<Device> getAvailableDevices() {
+            return getDevices();
+        }
+
+        @Override
+        public Device getDevice(DeviceId deviceId) {
+            return deviceId.equals(DID2) ? DEV2 : DEV1;
+        }
+    }
+
+    private static class TestCoreService implements CoreService {
+
+        @Override
+        public Version version() {
+            return null;
+        }
+
+        @Override
+        public Set<ApplicationId> getAppIds() {
+            return null;
+        }
+
+        @Override
+        public ApplicationId getAppId(Short id) {
+            return null;
+        }
+
+        @Override
+        public ApplicationId getAppId(String name) {
+            return null;
+        }
+
+        @Override
+        public ApplicationId registerApplication(String name) {
+            return new TestApplicationId(1, name);
+        }
+
+        @Override
+        public ApplicationId registerApplication(String name,
+                                                 Runnable preDeactivate) {
+            return null;
+        }
+
+        @Override
+        public IdGenerator getIdGenerator(String topic) {
+            return null;
+        }
+    }
+
+    private static class TestApplicationId extends DefaultApplicationId {
+        public TestApplicationId(int id, String name) {
+            super(id, name);
+        }
+    }
+
+    private static class TestVirtualNetworkAdminService
+            implements VirtualNetworkAdminService {
+
+        @Override
+        public Set<VirtualNetwork> getVirtualNetworks(TenantId tenantId) {
+            return null;
+        }
+
+        @Override
+        public Set<VirtualDevice> getVirtualDevices(NetworkId networkId) {
+            return ImmutableSet.of(VDEV);
+        }
+
+        @Override
+        public Set<VirtualHost> getVirtualHosts(NetworkId networkId) {
+            return null;
+        }
+
+        @Override
+        public Set<VirtualLink> getVirtualLinks(NetworkId networkId) {
+            return null;
+        }
+
+        @Override
+        public Set<VirtualPort> getVirtualPorts(NetworkId networkId,
+                                                DeviceId deviceId) {
+            return ImmutableSet.of(VPORT1, VPORT2);
+        }
+
+        @Override
+        public <T> T get(NetworkId networkId, Class<T> serviceClass) {
+            return null;
+        }
+
+        @Override
+        public ServiceDirectory getServiceDirectory() {
+            return null;
+        }
+
+        @Override
+        public void registerTenantId(TenantId tenantId) {
+
+        }
+
+        @Override
+        public void unregisterTenantId(TenantId tenantId) {
+
+        }
+
+        @Override
+        public Set<TenantId> getTenantIds() {
+            return null;
+        }
+
+        @Override
+        public VirtualNetwork createVirtualNetwork(TenantId tenantId) {
+            return null;
+        }
+
+        @Override
+        public void removeVirtualNetwork(NetworkId networkId) {
+
+        }
+
+        @Override
+        public VirtualDevice createVirtualDevice(NetworkId networkId,
+                                                 DeviceId deviceId) {
+            return null;
+        }
+
+        @Override
+        public void removeVirtualDevice(NetworkId networkId, DeviceId deviceId) {
+
+        }
+
+        @Override
+        public VirtualHost createVirtualHost(NetworkId networkId, HostId hostId,
+                                             MacAddress mac, VlanId vlan,
+                                             HostLocation location,
+                                             Set<IpAddress> ips) {
+            return null;
+        }
+
+        @Override
+        public void removeVirtualHost(NetworkId networkId, HostId hostId) {
+
+        }
+
+        @Override
+        public VirtualLink createVirtualLink(NetworkId networkId,
+                                             ConnectPoint src, ConnectPoint dst) {
+            return null;
+        }
+
+        @Override
+        public void removeVirtualLink(NetworkId networkId,
+                                      ConnectPoint src, ConnectPoint dst) {
+
+        }
+
+        @Override
+        public VirtualPort createVirtualPort(NetworkId networkId,
+                                             DeviceId deviceId,
+                                             PortNumber portNumber,
+                                             ConnectPoint realizedBy) {
+            return null;
+        }
+
+        @Override
+        public void bindVirtualPort(NetworkId networkId,
+                                    DeviceId deviceId,
+                                    PortNumber portNumber,
+                                    ConnectPoint realizedBy) {
+
+        }
+
+        @Override
+        public void removeVirtualPort(NetworkId networkId, DeviceId deviceId,
+                                      PortNumber portNumber) {
+
+        }
+    }
+
+    private static class TestTopologyService implements TopologyService {
+
+        @Override
+        public void addListener(TopologyListener listener) {
+
+        }
+
+        @Override
+        public void removeListener(TopologyListener listener) {
+
+        }
+
+        @Override
+        public Topology currentTopology() {
+            return null;
+        }
+
+        @Override
+        public boolean isLatest(Topology topology) {
+            return false;
+        }
+
+        @Override
+        public TopologyGraph getGraph(Topology topology) {
+            return null;
+        }
+
+        @Override
+        public Set<TopologyCluster> getClusters(Topology topology) {
+            return null;
+        }
+
+        @Override
+        public TopologyCluster getCluster(Topology topology, ClusterId clusterId) {
+            return null;
+        }
+
+        @Override
+        public Set<DeviceId> getClusterDevices(Topology topology,
+                                               TopologyCluster cluster) {
+            return null;
+        }
+
+        @Override
+        public Set<Link> getClusterLinks(Topology topology,
+                                         TopologyCluster cluster) {
+            return null;
+        }
+
+        @Override
+        public Set<Path> getPaths(Topology topology, DeviceId src, DeviceId dst) {
+            DefaultPath path = new DefaultPath(PID, ImmutableList.of(LINK1),
+                                               100, ANNOTATIONS);
+            return ImmutableSet.of(path);
+        }
+
+        @Override
+        public Set<Path> getPaths(Topology topology, DeviceId src,
+                                  DeviceId dst, LinkWeight weight) {
+            DefaultPath path = new DefaultPath(PID, ImmutableList.of(LINK1),
+                                               100, ANNOTATIONS);
+            return ImmutableSet.of(path);
+        }
+
+        @Override
+        public Set<DisjointPath> getDisjointPaths(Topology topology,
+                                                  DeviceId src, DeviceId dst) {
+            return null;
+        }
+
+        @Override
+        public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src,
+                                                  DeviceId dst, LinkWeight weight) {
+            return null;
+        }
+
+        @Override
+        public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src,
+                                                  DeviceId dst,
+                                                  Map<Link, Object> riskProfile) {
+            return null;
+        }
+
+        @Override
+        public Set<DisjointPath> getDisjointPaths(Topology topology, DeviceId src,
+                                                  DeviceId dst, LinkWeight weight,
+                                                  Map<Link, Object> riskProfile) {
+            return null;
+        }
+
+        @Override
+        public boolean isInfrastructure(Topology topology,
+                                        ConnectPoint connectPoint) {
+            return false;
+        }
+
+        @Override
+        public boolean isBroadcastPoint(Topology topology,
+                                        ConnectPoint connectPoint) {
+            return false;
+        }
+    }
+
+    private static class TestFlowRuleService implements FlowRuleService {
+        static Set<FlowRule> ruleCollection = new HashSet<>();
+
+        @Override
+        public void addListener(FlowRuleListener listener) {
+
+        }
+
+        @Override
+        public void removeListener(FlowRuleListener listener) {
+
+        }
+
+        @Override
+        public int getFlowRuleCount() {
+            return ruleCollection.size();
+        }
+
+        @Override
+        public Iterable<FlowEntry> getFlowEntries(DeviceId deviceId) {
+            return ruleCollection.stream()
+                    .filter(r -> r.deviceId().equals(deviceId))
+                    .map(r -> new DefaultFlowEntry(r))
+                    .collect(Collectors.toSet());
+        }
+
+        @Override
+        public void applyFlowRules(FlowRule... flowRules) {
+            for (FlowRule rule : flowRules) {
+                ruleCollection.add(rule);
+            }
+        }
+
+        @Override
+        public void purgeFlowRules(DeviceId deviceId) {
+
+        }
+
+        @Override
+        public void removeFlowRules(FlowRule... flowRules) {
+            Set<FlowRule> candidates = new HashSet<>();
+            for (FlowRule rule : flowRules) {
+                ruleCollection.stream()
+                        .filter(r -> r.exactMatch(rule))
+                        .forEach(candidates::add);
+            }
+            ruleCollection.removeAll(candidates);
+        }
+
+        @Override
+        public void removeFlowRulesById(ApplicationId appId) {
+
+        }
+
+        @Override
+        public Iterable<FlowRule> getFlowRulesById(ApplicationId id) {
+            return null;
+        }
+
+        @Override
+        public Iterable<FlowEntry> getFlowEntriesById(ApplicationId id) {
+            return null;
+        }
+
+        @Override
+        public Iterable<FlowRule> getFlowRulesByGroupId(ApplicationId appId,
+                                                        short groupId) {
+            return null;
+        }
+
+        @Override
+        public void apply(FlowRuleOperations ops) {
+
+        }
+
+        @Override
+        public Iterable<TableStatisticsEntry>
+        getFlowTableStatistics(DeviceId deviceId) {
+            return null;
+        }
+    }
+}
diff --git a/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/provider/VirtualProviderManagerTest.java b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/provider/VirtualProviderManagerTest.java
index f952633..6fb7a8d 100644
--- a/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/provider/VirtualProviderManagerTest.java
+++ b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/provider/VirtualProviderManagerTest.java
@@ -81,7 +81,7 @@
         virtualProviderManager.registerProviderService(NETWORK_ID1, providerService1);
 
         assertEquals(providerService1,
-                     virtualProviderManager.getProviderService(NETWORK_ID1, provider1));
+                     virtualProviderManager.getProviderService(NETWORK_ID1, TestProvider1.class));
     }
 
     private class TestProvider1 extends AbstractVirtualProvider {