Few core changes in preparation of P4Runtime subsystem refactoring

Refactoring aims at providing a more robust connection procedure of
P4Runtime-based devices.

Refactoring requires devices to be registered to the core with
available=false (i.e. offline), and marked online only when the P4
pipeline has been deployed to the device. Also, it leaves the duty of
handling pipeconf-specific drivers to the driver subsystem, instead of
having the GeneralDeviceProvider take care of it, which resulted to be
brittle.

Changes include:
- Choose not to mark device online when re-asserting mastership role by
declaring special device annotation.
- Lookup drivers in device projectable model unsing driver service
device-based method, which is consistent with the way other subsystems
look for device drivers.
- In DriverManager, when looking for device drivers, consider the case
of pipeconf-programmable devices, in which case a special "merged"
driver needs to instantiated at runtime.
- In PacketManager, push flow objectives only if device is available
(i.e. after pipeline has been deployed).

Change-Id: I80f78a4f40730a06cb82fa55fefab08a91a89268
diff --git a/apps/cfm/app/src/test/java/org/onosproject/incubator/net/l2monitoring/cfm/impl/CfmMepManagerTest.java b/apps/cfm/app/src/test/java/org/onosproject/incubator/net/l2monitoring/cfm/impl/CfmMepManagerTest.java
index 5941f6f..a5a5b66 100644
--- a/apps/cfm/app/src/test/java/org/onosproject/incubator/net/l2monitoring/cfm/impl/CfmMepManagerTest.java
+++ b/apps/cfm/app/src/test/java/org/onosproject/incubator/net/l2monitoring/cfm/impl/CfmMepManagerTest.java
@@ -78,10 +78,10 @@
 import static org.easymock.EasyMock.createMock;
 import static org.easymock.EasyMock.expect;
 import static org.easymock.EasyMock.replay;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.onosproject.net.NetTestTools.injectEventDispatcher;
 
@@ -222,7 +222,8 @@
         expect(deviceService.getDevice(DEVICE_ID2)).andReturn(device2).anyTimes();
         replay(deviceService);
 
-        expect(driverService.getDriver(TEST_DRIVER)).andReturn(testDriver).anyTimes();
+        expect(driverService.getDriver(DEVICE_ID1)).andReturn(testDriver).anyTimes();
+        expect(driverService.getDriver(DEVICE_ID2)).andReturn(testDriver).anyTimes();
         replay(driverService);
 
         Collection<MepEntry> mepEntries = mepManager.getAllMeps(MDNAME1, MANAME1);
@@ -241,7 +242,7 @@
         expect(deviceService.getDevice(DEVICE_ID1)).andReturn(device1).anyTimes();
         replay(deviceService);
 
-        expect(driverService.getDriver(TEST_DRIVER)).andReturn(testDriver).anyTimes();
+        expect(driverService.getDriver(DEVICE_ID1)).andReturn(testDriver).anyTimes();
         replay(driverService);
 
         MepEntry mepEntry = mepManager.getMep(MDNAME1, MANAME1, MEPID1);
@@ -260,7 +261,7 @@
         expect(deviceService.getDevice(DEVICE_ID1)).andReturn(null).anyTimes();
         replay(deviceService);
 
-        expect(driverService.getDriver(TEST_DRIVER)).andReturn(testDriver).anyTimes();
+        expect(driverService.getDriver(DEVICE_ID1)).andReturn(testDriver).anyTimes();
         replay(driverService);
 
         try {
@@ -282,7 +283,8 @@
         expect(deviceService.getDevice(DEVICE_ID2)).andReturn(device2).anyTimes();
         replay(deviceService);
 
-        expect(driverService.getDriver(TEST_DRIVER)).andReturn(testDriver).anyTimes();
+        expect(driverService.getDriver(DEVICE_ID1)).andReturn(testDriver).anyTimes();
+        expect(driverService.getDriver(DEVICE_ID2)).andReturn(testDriver).anyTimes();
         replay(driverService);
 
         assertTrue(mepManager.deleteMep(MDNAME1, MANAME1, MEPID1, Optional.empty()));
@@ -299,7 +301,8 @@
         expect(deviceService.getDevice(DEVICE_ID2)).andReturn(device2).anyTimes();
         replay(deviceService);
 
-        expect(driverService.getDriver(TEST_DRIVER)).andReturn(testDriver).anyTimes();
+        expect(driverService.getDriver(DEVICE_ID1)).andReturn(testDriver).anyTimes();
+        expect(driverService.getDriver(DEVICE_ID2)).andReturn(testDriver).anyTimes();
         replay(driverService);
 
         MepId mepId3 = MepId.valueOf((short) 3);
@@ -336,7 +339,7 @@
         expect(deviceService.getDevice(deviceId3)).andReturn(device3).anyTimes();
         replay(deviceService);
 
-        expect(driverService.getDriver(TEST_DRIVER_3)).andReturn(testDriver3).anyTimes();
+        expect(driverService.getDriver(deviceId3)).andReturn(testDriver3).anyTimes();
         replay(driverService);
 
         MepId mepId3 = MepId.valueOf((short) 3);
@@ -362,7 +365,7 @@
         expect(deviceService.getDevice(DEVICE_ID1)).andReturn(device1).anyTimes();
         replay(deviceService);
 
-        expect(driverService.getDriver(TEST_DRIVER)).andReturn(testDriver).anyTimes();
+        expect(driverService.getDriver(DEVICE_ID1)).andReturn(testDriver).anyTimes();
         replay(driverService);
 
         MepLbCreate lbCreate = DefaultMepLbCreate.builder(MepId.valueOf((short) 11)).build();
@@ -383,7 +386,7 @@
         expect(deviceService.getDevice(DEVICE_ID1)).andReturn(device1).anyTimes();
         replay(deviceService);
 
-        expect(driverService.getDriver(TEST_DRIVER)).andReturn(testDriver).anyTimes();
+        expect(driverService.getDriver(DEVICE_ID1)).andReturn(testDriver).anyTimes();
         replay(driverService);
 
         try {
@@ -403,7 +406,7 @@
         expect(deviceService.getDevice(DEVICE_ID1)).andReturn(device1).anyTimes();
         replay(deviceService);
 
-        expect(driverService.getDriver(TEST_DRIVER)).andReturn(testDriver).anyTimes();
+        expect(driverService.getDriver(DEVICE_ID1)).andReturn(testDriver).anyTimes();
         replay(driverService);
 
         MepLtCreate ltCreate = DefaultMepLtCreate.builder(MepId.valueOf((short) 11)).build();
@@ -428,7 +431,8 @@
         expect(deviceService.getDevice(DEVICE_ID2)).andReturn(device2).anyTimes();
         replay(deviceService);
 
-        expect(driverService.getDriver(TEST_DRIVER)).andReturn(testDriver).anyTimes();
+        expect(driverService.getDriver(DEVICE_ID1)).andReturn(testDriver).anyTimes();
+        expect(driverService.getDriver(DEVICE_ID2)).andReturn(testDriver).anyTimes();
         replay(driverService);
 
 //        This is arranged like
diff --git a/apps/cfm/app/src/test/java/org/onosproject/incubator/net/l2monitoring/soam/impl/SoamManagerTest.java b/apps/cfm/app/src/test/java/org/onosproject/incubator/net/l2monitoring/soam/impl/SoamManagerTest.java
index a3a6d52..bf5af67 100644
--- a/apps/cfm/app/src/test/java/org/onosproject/incubator/net/l2monitoring/soam/impl/SoamManagerTest.java
+++ b/apps/cfm/app/src/test/java/org/onosproject/incubator/net/l2monitoring/soam/impl/SoamManagerTest.java
@@ -172,7 +172,7 @@
         expect(mepService.getMep(MDNAME1, MANAME1, MEPID1)).andReturn(mep1).anyTimes();
         replay(mepService);
 
-        expect(driverService.getDriver(TEST_DRIVER)).andReturn(testDriver).anyTimes();
+        expect(driverService.getDriver(DEVICE_ID1)).andReturn(testDriver).anyTimes();
         replay(driverService);
 
         Collection<DelayMeasurementEntry> dmEntries =
@@ -189,7 +189,7 @@
         expect(mepService.getMep(MDNAME1, MANAME1, MEPID1)).andReturn(mep1).anyTimes();
         replay(mepService);
 
-        expect(driverService.getDriver(TEST_DRIVER)).andReturn(testDriver).anyTimes();
+        expect(driverService.getDriver(DEVICE_ID1)).andReturn(testDriver).anyTimes();
         replay(driverService);
 
         DelayMeasurementEntry dmEntry =
@@ -207,7 +207,7 @@
         expect(mepService.getMep(MDNAME1, MANAME1, MEPID1)).andReturn(mep1).anyTimes();
         replay(mepService);
 
-        expect(driverService.getDriver(TEST_DRIVER)).andReturn(testDriver).anyTimes();
+        expect(driverService.getDriver(DEVICE_ID1)).andReturn(testDriver).anyTimes();
         replay(driverService);
 
         DelayMeasurementStatCurrent dmCurrentStat =
@@ -225,7 +225,7 @@
         expect(mepService.getMep(MDNAME1, MANAME1, MEPID1)).andReturn(mep1).anyTimes();
         replay(mepService);
 
-        expect(driverService.getDriver(TEST_DRIVER)).andReturn(testDriver).anyTimes();
+        expect(driverService.getDriver(DEVICE_ID1)).andReturn(testDriver).anyTimes();
         replay(driverService);
 
         Collection<DelayMeasurementStatHistory> dmHistoricalStats =
@@ -243,7 +243,7 @@
         expect(mepService.getMep(MDNAME1, MANAME1, MEPID1)).andReturn(mep1).anyTimes();
         replay(mepService);
 
-        expect(driverService.getDriver(TEST_DRIVER)).andReturn(testDriver).anyTimes();
+        expect(driverService.getDriver(DEVICE_ID1)).andReturn(testDriver).anyTimes();
         replay(driverService);
 
         DelayMeasurementCreate dmCreate1 = DefaultDelayMeasurementCreate
@@ -288,7 +288,7 @@
         expect(mepService.getMep(MDNAME1, MANAME1, mepId3)).andReturn(mep3).anyTimes();
         replay(mepService);
 
-        expect(driverService.getDriver(TEST_DRIVER_3)).andReturn(testDriver3).anyTimes();
+        expect(driverService.getDriver(deviceId3)).andReturn(testDriver3).anyTimes();
         replay(driverService);
 
         DelayMeasurementCreate dmCreate1 = DefaultDelayMeasurementCreate
diff --git a/core/api/src/main/java/org/onosproject/net/AnnotationKeys.java b/core/api/src/main/java/org/onosproject/net/AnnotationKeys.java
index 31e489e..5af7f7a 100644
--- a/core/api/src/main/java/org/onosproject/net/AnnotationKeys.java
+++ b/core/api/src/main/java/org/onosproject/net/AnnotationKeys.java
@@ -89,6 +89,16 @@
     public static final String DRIVER = "driver";
 
     /**
+     * Annotation key for the device availability behavior. The value of this key
+     * is expected to be a boolean ({@code true} or {@code false}) and it is
+     * used to determine if the device can be marked online by the core when
+     * deemed appropriate (value is {@code false}, default behaviour if key is
+     * not present), or if marking online should be left to providers ({@code
+     * true}).
+     */
+    public static final String PROVIDER_MARK_ONLINE = "providerMarkOnline";
+
+    /**
      * Annotation key for durable links.
      */
     public static final String DURABLE = "durable";
diff --git a/core/api/src/main/java/org/onosproject/net/DefaultDevice.java b/core/api/src/main/java/org/onosproject/net/DefaultDevice.java
index 9d9cc1b..ea25ed5 100644
--- a/core/api/src/main/java/org/onosproject/net/DefaultDevice.java
+++ b/core/api/src/main/java/org/onosproject/net/DefaultDevice.java
@@ -16,6 +16,7 @@
 package org.onosproject.net;
 
 import org.onlab.packet.ChassisId;
+import org.onlab.util.ItemNotFoundException;
 import org.onosproject.net.driver.Behaviour;
 import org.onosproject.net.driver.DefaultDriverHandler;
 import org.onosproject.net.driver.Driver;
@@ -152,9 +153,11 @@
 
     @Override
     protected Driver locateDriver() {
-        Driver driver = super.locateDriver();
-        return driver != null ? driver :
-                driverService().getDriver(manufacturer, hwVersion, swVersion);
+        try {
+            return driverService().getDriver(id());
+        } catch (ItemNotFoundException e) {
+            return null;
+        }
     }
 
     /**
diff --git a/core/api/src/main/java/org/onosproject/net/pi/service/PiPipeconfService.java b/core/api/src/main/java/org/onosproject/net/pi/service/PiPipeconfService.java
index b574b5b..e9539a5 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/service/PiPipeconfService.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/service/PiPipeconfService.java
@@ -98,7 +98,7 @@
      * @param pipeconfId a pipeconf identifier
      * @return driver name or null.
      */
-    String mergeDriver(DeviceId deviceId, PiPipeconfId pipeconfId);
+    String getMergedDriver(DeviceId deviceId, PiPipeconfId pipeconfId);
 
     /**
      * Returns the pipeconf identifier currently associated with the given
diff --git a/core/api/src/test/java/org/onosproject/net/pi/PiPipeconfServiceAdapter.java b/core/api/src/test/java/org/onosproject/net/pi/PiPipeconfServiceAdapter.java
new file mode 100644
index 0000000..8eebf5f
--- /dev/null
+++ b/core/api/src/test/java/org/onosproject/net/pi/PiPipeconfServiceAdapter.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.net.pi;
+
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.pi.model.PiPipeconf;
+import org.onosproject.net.pi.model.PiPipeconfId;
+import org.onosproject.net.pi.service.PiPipeconfService;
+
+import java.util.Collections;
+import java.util.Optional;
+
+/**
+ * Test adapter of PiPipeconfService.
+ */
+public class PiPipeconfServiceAdapter implements PiPipeconfService {
+    @Override
+    public void register(PiPipeconf pipeconf) throws IllegalStateException {
+
+    }
+
+    @Override
+    public void remove(PiPipeconfId pipeconfId) throws IllegalStateException {
+
+    }
+
+    @Override
+    public Iterable<PiPipeconf> getPipeconfs() {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public Optional<PiPipeconf> getPipeconf(PiPipeconfId id) {
+        return Optional.empty();
+    }
+
+    @Override
+    public void bindToDevice(PiPipeconfId pipeconfId, DeviceId deviceId) {
+
+    }
+
+    @Override
+    public String getMergedDriver(DeviceId deviceId, PiPipeconfId pipeconfId) {
+        return null;
+    }
+
+    @Override
+    public Optional<PiPipeconfId> ofDevice(DeviceId deviceId) {
+        return Optional.empty();
+    }
+}
diff --git a/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java b/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java
index 09d95b4..d22e044 100644
--- a/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java
+++ b/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java
@@ -36,6 +36,7 @@
 import org.onosproject.mastership.MastershipService;
 import org.onosproject.mastership.MastershipTerm;
 import org.onosproject.mastership.MastershipTermService;
+import org.onosproject.net.AnnotationKeys;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.Device;
 import org.onosproject.net.Device.Type;
@@ -826,6 +827,12 @@
         return (cfg == null || cfg.isAllowed());
     }
 
+    private boolean canMarkOnline(Device device) {
+        final boolean providerMarkOnline = Boolean.parseBoolean(
+                device.annotations().value(AnnotationKeys.PROVIDER_MARK_ONLINE));
+        return !providerMarkOnline;
+    }
+
     // Applies the specified role to the device; ignores NONE
 
     /**
@@ -887,7 +894,7 @@
         switch (myNextRole) {
             case MASTER:
                 final Device device = getDevice(did);
-                if ((device != null) && !isAvailable(did)) {
+                if (device != null && !isAvailable(did) && canMarkOnline(device)) {
                     post(store.markOnline(did));
                 }
                 // TODO: should apply role only if there is mismatch
diff --git a/core/net/src/main/java/org/onosproject/net/driver/impl/DriverManager.java b/core/net/src/main/java/org/onosproject/net/driver/impl/DriverManager.java
index 1dd8f7b..f2ece6b 100644
--- a/core/net/src/main/java/org/onosproject/net/driver/impl/DriverManager.java
+++ b/core/net/src/main/java/org/onosproject/net/driver/impl/DriverManager.java
@@ -36,6 +36,8 @@
 import org.onosproject.net.driver.DriverListener;
 import org.onosproject.net.driver.DriverRegistry;
 import org.onosproject.net.driver.DriverService;
+import org.onosproject.net.pi.model.PiPipeconfId;
+import org.onosproject.net.pi.service.PiPipeconfService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -71,6 +73,9 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected NetworkConfigService networkConfigService;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected PiPipeconfService pipeconfService;
+
     @Activate
     protected void activate() {
         AbstractProjectableModel.setDriverService(null, this);
@@ -113,9 +118,25 @@
     public Driver getDriver(DeviceId deviceId) {
         checkPermission(DRIVER_READ);
 
+        Driver driver;
+
         // Primary source of driver configuration is the network config.
+        if (pipeconfService.ofDevice(deviceId).isPresent()) {
+            // Device has pipeconf associated, look for merged driver.
+            // Implementation of PiPipeconfService is expected to look for a
+            // base driver in network config.
+            PiPipeconfId pipeconfId = pipeconfService.ofDevice(deviceId).get();
+            String mergedDriver = pipeconfService.getMergedDriver(deviceId, pipeconfId);
+            driver = mergedDriver != null ? lookupDriver(mergedDriver) : null;
+            if (driver != null) {
+                return driver;
+            } else {
+                log.error("Merged driver for {} with pipeconf {} not found, falling back.",
+                          deviceId, pipeconfId);
+            }
+        }
         BasicDeviceConfig cfg = networkConfigService.getConfig(deviceId, BasicDeviceConfig.class);
-        Driver driver = lookupDriver(cfg != null ? cfg.driver() : null);
+        driver = lookupDriver(cfg != null ? cfg.driver() : null);
         if (driver != null) {
             return driver;
         }
diff --git a/core/net/src/main/java/org/onosproject/net/packet/impl/PacketManager.java b/core/net/src/main/java/org/onosproject/net/packet/impl/PacketManager.java
index 6be6c54..ac5c732 100644
--- a/core/net/src/main/java/org/onosproject/net/packet/impl/PacketManager.java
+++ b/core/net/src/main/java/org/onosproject/net/packet/impl/PacketManager.java
@@ -309,6 +309,10 @@
             return;
         }
 
+        if (!deviceService.isAvailable(device.id())) {
+            return;
+        }
+
         ForwardingObjective forwarding = createBuilder(request)
                 .add(new ObjectiveContext() {
                     @Override
diff --git a/core/net/src/main/java/org/onosproject/net/pi/impl/PiPipeconfManager.java b/core/net/src/main/java/org/onosproject/net/pi/impl/PiPipeconfManager.java
index 5be4a26..0e2ea82 100644
--- a/core/net/src/main/java/org/onosproject/net/pi/impl/PiPipeconfManager.java
+++ b/core/net/src/main/java/org/onosproject/net/pi/impl/PiPipeconfManager.java
@@ -27,7 +27,6 @@
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.apache.felix.scr.annotations.Service;
 import org.onlab.util.ItemNotFoundException;
-import org.onosproject.cluster.ClusterService;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.config.ConfigFactory;
 import org.onosproject.net.config.NetworkConfigRegistry;
@@ -40,7 +39,6 @@
 import org.onosproject.net.driver.DriverEvent;
 import org.onosproject.net.driver.DriverListener;
 import org.onosproject.net.driver.DriverProvider;
-import org.onosproject.net.driver.DriverService;
 import org.onosproject.net.pi.model.PiPipeconf;
 import org.onosproject.net.pi.model.PiPipeconfId;
 import org.onosproject.net.pi.service.PiPipeconfConfig;
@@ -81,17 +79,11 @@
     protected NetworkConfigRegistry cfgService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected DriverService driverService;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected DriverAdminService driverAdminService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     private PiPipeconfMappingStore pipeconfMappingStore;
 
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected ClusterService clusterService;
-
     // Registered pipeconf are replicated through the app subsystem and
     // registered on app activated events. Hence, there should be no need of
     // distributing this map.
@@ -117,7 +109,7 @@
     @Activate
     public void activate() {
         cfgService.registerConfigFactory(configFactory);
-        driverService.addListener(driverListener);
+        driverAdminService.addListener(driverListener);
         checkMissingMergedDrivers();
         log.info("Started");
     }
@@ -127,12 +119,11 @@
     public void deactivate() {
         executor.shutdown();
         cfgService.unregisterConfigFactory(configFactory);
-        driverService.removeListener(driverListener);
+        driverAdminService.removeListener(driverListener);
         pipeconfs.clear();
         missingMergedDrivers.clear();
         cfgService = null;
         driverAdminService = null;
-        driverService = null;
         log.info("Stopped");
     }
 
@@ -170,11 +161,17 @@
 
     @Override
     public void bindToDevice(PiPipeconfId pipeconfId, DeviceId deviceId) {
+        PiPipeconfId existingPipeconfId = pipeconfMappingStore.getPipeconfId(deviceId);
+        if (existingPipeconfId != null && !existingPipeconfId.equals(pipeconfId)) {
+            log.error("Cannot set binding for {} to {} as one already exists ({})",
+                      deviceId, pipeconfId, existingPipeconfId);
+            return;
+        }
         pipeconfMappingStore.createOrUpdateBinding(deviceId, pipeconfId);
     }
 
     @Override
-    public String mergeDriver(DeviceId deviceId, PiPipeconfId pipeconfId) {
+    public String getMergedDriver(DeviceId deviceId, PiPipeconfId pipeconfId) {
         log.debug("Starting device driver merge of {} with {}...", deviceId, pipeconfId);
         final BasicDeviceConfig basicDeviceConfig = cfgService.getConfig(
                 deviceId, BasicDeviceConfig.class);
@@ -298,7 +295,7 @@
 
     private Driver getDriver(String name) {
         try {
-            return driverService.getDriver(name);
+            return driverAdminService.getDriver(name);
         } catch (ItemNotFoundException e) {
             return null;
         }
diff --git a/core/net/src/test/java/org/onosproject/net/flow/impl/FlowRuleManagerTest.java b/core/net/src/test/java/org/onosproject/net/flow/impl/FlowRuleManagerTest.java
index 3697641..f4549c5 100644
--- a/core/net/src/test/java/org/onosproject/net/flow/impl/FlowRuleManagerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/flow/impl/FlowRuleManagerTest.java
@@ -39,6 +39,7 @@
 import org.onosproject.net.Device.Type;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.MastershipRole;
+import org.onosproject.net.config.NetworkConfigServiceAdapter;
 import org.onosproject.net.device.DeviceServiceAdapter;
 import org.onosproject.net.driver.AbstractHandlerBehaviour;
 import org.onosproject.net.driver.DefaultDriver;
@@ -51,7 +52,6 @@
 import org.onosproject.net.flow.FlowEntry;
 import org.onosproject.net.flow.FlowEntry.FlowEntryState;
 import org.onosproject.net.flow.FlowRule;
-import org.onosproject.net.flow.oldbatch.FlowRuleBatchOperation;
 import org.onosproject.net.flow.FlowRuleEvent;
 import org.onosproject.net.flow.FlowRuleListener;
 import org.onosproject.net.flow.FlowRuleProgrammable;
@@ -66,6 +66,8 @@
 import org.onosproject.net.flow.instructions.Instruction;
 import org.onosproject.net.flow.instructions.Instructions;
 import org.onosproject.net.flow.instructions.Instructions.MetadataInstruction;
+import org.onosproject.net.flow.oldbatch.FlowRuleBatchOperation;
+import org.onosproject.net.pi.PiPipeconfServiceAdapter;
 import org.onosproject.net.provider.AbstractProvider;
 import org.onosproject.net.provider.ProviderId;
 import org.onosproject.store.trivial.SimpleFlowRuleStore;
@@ -84,9 +86,16 @@
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicLong;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 import static org.onosproject.net.NetTestTools.injectEventDispatcher;
-import static org.onosproject.net.flow.FlowRuleEvent.Type.*;
+import static org.onosproject.net.flow.FlowRuleEvent.Type.RULE_ADDED;
+import static org.onosproject.net.flow.FlowRuleEvent.Type.RULE_ADD_REQUESTED;
+import static org.onosproject.net.flow.FlowRuleEvent.Type.RULE_REMOVED;
+import static org.onosproject.net.flow.FlowRuleEvent.Type.RULE_REMOVE_REQUESTED;
+import static org.onosproject.net.flow.FlowRuleEvent.Type.RULE_UPDATED;
 
 /**
  * Test codifying the flow rule service & flow rule provider service contracts.
@@ -712,6 +721,8 @@
         TestDriverManager(DriverRegistry registry) {
             this.registry = registry;
             this.deviceService = mgr.deviceService;
+            this.pipeconfService = new PiPipeconfServiceAdapter();
+            this.networkConfigService = new NetworkConfigServiceAdapter();
             activate();
         }
     }
diff --git a/core/net/src/test/java/org/onosproject/net/group/impl/GroupManagerTest.java b/core/net/src/test/java/org/onosproject/net/group/impl/GroupManagerTest.java
index 7135c49..d1777ba 100644
--- a/core/net/src/test/java/org/onosproject/net/group/impl/GroupManagerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/group/impl/GroupManagerTest.java
@@ -37,6 +37,7 @@
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.MastershipRole;
 import org.onosproject.net.PortNumber;
+import org.onosproject.net.config.NetworkConfigServiceAdapter;
 import org.onosproject.net.device.DeviceServiceAdapter;
 import org.onosproject.net.driver.AbstractHandlerBehaviour;
 import org.onosproject.net.driver.DefaultDriver;
@@ -64,6 +65,7 @@
 import org.onosproject.net.group.GroupProviderService;
 import org.onosproject.net.group.GroupService;
 import org.onosproject.net.group.StoredGroupEntry;
+import org.onosproject.net.pi.PiPipeconfServiceAdapter;
 import org.onosproject.net.provider.AbstractProvider;
 import org.onosproject.net.provider.ProviderId;
 import org.onosproject.store.trivial.SimpleGroupStore;
@@ -74,7 +76,11 @@
 import java.util.Collections;
 import java.util.List;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 import static org.onosproject.net.NetTestTools.injectEventDispatcher;
 
 /**
@@ -787,6 +793,8 @@
         TestDriverManager(DriverRegistry registry) {
             this.registry = registry;
             this.deviceService = mgr.deviceService;
+            this.pipeconfService = new PiPipeconfServiceAdapter();
+            this.networkConfigService = new NetworkConfigServiceAdapter();
             activate();
         }
     }
diff --git a/core/net/src/test/java/org/onosproject/net/meter/impl/MeterManagerTest.java b/core/net/src/test/java/org/onosproject/net/meter/impl/MeterManagerTest.java
index 3bd5e9b..ea21b9f 100644
--- a/core/net/src/test/java/org/onosproject/net/meter/impl/MeterManagerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/meter/impl/MeterManagerTest.java
@@ -68,21 +68,26 @@
 import org.onosproject.net.meter.MeterRequest;
 import org.onosproject.net.meter.MeterService;
 import org.onosproject.net.meter.MeterState;
+import org.onosproject.net.pi.PiPipeconfServiceAdapter;
 import org.onosproject.net.provider.AbstractProvider;
 import org.onosproject.net.provider.ProviderId;
 import org.onosproject.store.service.Serializer;
 import org.onosproject.store.service.TestStorageService;
 
-import java.util.Collections;
-import java.util.HashSet;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.CompletableFuture;
 
 import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
 import static org.onosproject.net.NetTestTools.APP_ID;
 import static org.onosproject.net.NetTestTools.did;
 import static org.onosproject.net.NetTestTools.injectEventDispatcher;
@@ -526,6 +531,7 @@
             this.registry = registry;
             this.deviceService = deviceService;
             this.networkConfigService = networkConfigService;
+            this.pipeconfService = new PiPipeconfServiceAdapter();
             activate();
         }
     }
diff --git a/core/net/src/test/java/org/onosproject/net/packet/impl/PacketManagerTest.java b/core/net/src/test/java/org/onosproject/net/packet/impl/PacketManagerTest.java
index 6e4a7a5..81c2368 100644
--- a/core/net/src/test/java/org/onosproject/net/packet/impl/PacketManagerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/packet/impl/PacketManagerTest.java
@@ -30,6 +30,7 @@
 import org.onosproject.net.DefaultDevice;
 import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
+import org.onosproject.net.config.NetworkConfigServiceAdapter;
 import org.onosproject.net.device.DeviceServiceAdapter;
 import org.onosproject.net.driver.AbstractHandlerBehaviour;
 import org.onosproject.net.driver.DefaultDriver;
@@ -41,6 +42,7 @@
 import org.onosproject.net.packet.OutboundPacket;
 import org.onosproject.net.packet.PacketProgrammable;
 import org.onosproject.net.packet.PacketProviderRegistry;
+import org.onosproject.net.pi.PiPipeconfServiceAdapter;
 import org.onosproject.net.provider.ProviderId;
 import org.onosproject.net.provider.TestProvider;
 import org.onosproject.store.trivial.SimplePacketStore;
@@ -147,6 +149,8 @@
         TestDriverManager(DriverRegistry registry) {
             this.registry = registry;
             this.deviceService = mgr.deviceService;
+            this.pipeconfService = new PiPipeconfServiceAdapter();
+            this.networkConfigService = new NetworkConfigServiceAdapter();
             activate();
         }
     }
diff --git a/core/net/src/test/java/org/onosproject/net/pi/impl/PiPipeconfManagerTest.java b/core/net/src/test/java/org/onosproject/net/pi/impl/PiPipeconfManagerTest.java
index a418461..20ded6a 100644
--- a/core/net/src/test/java/org/onosproject/net/pi/impl/PiPipeconfManagerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/pi/impl/PiPipeconfManagerTest.java
@@ -42,8 +42,6 @@
 import org.onosproject.net.driver.DriverAdminService;
 import org.onosproject.net.driver.DriverAdminServiceAdapter;
 import org.onosproject.net.driver.DriverProvider;
-import org.onosproject.net.driver.DriverService;
-import org.onosproject.net.driver.DriverServiceAdapter;
 import org.onosproject.net.pi.model.PiPipeconf;
 import org.onosproject.net.pi.model.PiPipeconfId;
 import org.onosproject.net.pi.service.PiPipeconfConfig;
@@ -72,7 +70,6 @@
 
     //Mock util sets and classes
     private final NetworkConfigRegistry cfgService = new MockNetworkConfigRegistry();
-    private final DriverService driverService = new MockDriverService();
     private final DriverAdminService driverAdminService = new MockDriverAdminService();
     private Driver baseDriver = new MockDriver();
 
@@ -97,7 +94,6 @@
         piPipeconfService = new PiPipeconfManager();
         piPipeconf = BASIC_PIPECONF;
         piPipeconfService.cfgService = cfgService;
-        piPipeconfService.driverService = driverService;
         piPipeconfService.driverAdminService = driverAdminService;
         String key = "piPipeconf";
         ObjectMapper mapper = new ObjectMapper();
@@ -112,7 +108,7 @@
 
     @Test
     public void activate() {
-        assertEquals("Incorrect driver service", driverService, piPipeconfService.driverService);
+        assertEquals("Incorrect driver admin service", driverAdminService, piPipeconfService.driverAdminService);
         assertEquals("Incorrect driverAdminService service", driverAdminService, piPipeconfService.driverAdminService);
         assertEquals("Incorrect configuration service", cfgService, piPipeconfService.cfgService);
         assertTrue("Incorrect config factory", cfgFactories.contains(piPipeconfService.configFactory));
@@ -121,7 +117,7 @@
     @Test
     public void deactivate() {
         piPipeconfService.deactivate();
-        assertEquals("Incorrect driver service", null, piPipeconfService.driverService);
+        assertEquals("Incorrect driver admin service", null, piPipeconfService.driverAdminService);
         assertEquals("Incorrect driverAdminService service", null, piPipeconfService.driverAdminService);
         assertEquals("Incorrect configuration service", null, piPipeconfService.cfgService);
         assertFalse("Config factory should be unregistered", cfgFactories.contains(piPipeconfService.configFactory));
@@ -153,7 +149,10 @@
         assertEquals("Returned PiPipeconf is not correct", piPipeconf,
                      piPipeconfService.getPipeconf(piPipeconf.id()).get());
 
-        String mergedDriverName = piPipeconfService.mergeDriver(DEVICE_ID, piPipeconfId);
+        String mergedDriverName = piPipeconfService.getMergedDriver(DEVICE_ID, piPipeconfId);
+
+        String expectedName = BASE_DRIVER + ":" + piPipeconfId.id();
+        assertEquals(expectedName, mergedDriverName);
 
         //we assume that the provider is 1 and that it contains 1 driver
         //we also assume that everything after driverAdminService.registerProvider(provider); has been tested.
@@ -208,7 +207,8 @@
         }
     }
 
-    private class MockDriverService extends DriverServiceAdapter {
+    private class MockDriverAdminService extends DriverAdminServiceAdapter {
+
         @Override
         public Driver getDriver(String driverName) {
             if (driverName.equals(BASE_DRIVER)) {
@@ -216,9 +216,6 @@
             }
             throw new ItemNotFoundException("Driver not found");
         }
-    }
-
-    private class MockDriverAdminService extends DriverAdminServiceAdapter {
 
         @Override
         public void registerProvider(DriverProvider provider) {
diff --git a/providers/general/device/src/main/java/org/onosproject/provider/general/device/impl/GeneralDeviceProvider.java b/providers/general/device/src/main/java/org/onosproject/provider/general/device/impl/GeneralDeviceProvider.java
index f703371..21c6ae7 100644
--- a/providers/general/device/src/main/java/org/onosproject/provider/general/device/impl/GeneralDeviceProvider.java
+++ b/providers/general/device/src/main/java/org/onosproject/provider/general/device/impl/GeneralDeviceProvider.java
@@ -541,22 +541,23 @@
         }
         final PiPipeconfId pipeconfId = pipeconf.id();
 
-        final String mergedDriverName = piPipeconfService.mergeDriver(
-                deviceId, pipeconfId);
-        if (mergedDriverName == null) {
-            log.error("Unable to get merged driver for {} and {}, aborting device discovery",
-                      deviceId, pipeconfId);
-            return false;
-        }
+        // To be removed in change #19606
+        // final String mergedDriverName = piPipeconfService.mergeDriver(
+        //         deviceId, pipeconfId);
+        // if (mergedDriverName == null) {
+        //     log.error("Unable to get merged driver for {} and {}, aborting device discovery",
+        //               deviceId, pipeconfId);
+        //     return false;
+        // }
 
         if (!asMaster) {
             // From now one only the master.
             return true;
         }
 
-        if (!setDriverViaCfg(deviceId, mergedDriverName)) {
-            return false;
-        }
+        // if (!setDriverViaCfg(deviceId, mergedDriverName)) {
+        //     return false;
+        // }
 
         // FIXME: we just introduced a race condition as it might happen that a
         // node does not receive the new cfg (with the merged driver) before the