Recover missing pipeconf-merged driver at component activation
needed to support rebooting ONOS nodes
Change-Id: I44d34c649750ffc3d6b0205ee02c8c88391f1f8a
(cherry picked from commit ccee77a024c14c3cef68457028ea71edc0555f54)
diff --git a/core/api/src/main/java/org/onosproject/net/pi/service/PiPipeconfMappingStore.java b/core/api/src/main/java/org/onosproject/net/pi/service/PiPipeconfMappingStore.java
index 2f275ee..4a9bc90 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/service/PiPipeconfMappingStore.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/service/PiPipeconfMappingStore.java
@@ -31,7 +31,7 @@
public interface PiPipeconfMappingStore extends Store<PiPipeconfDeviceMappingEvent, PiPipeconfMappingStoreDelegate> {
/**
- * Retrieves the id of the pipeconf deployed on a given device.
+ * Retrieves the id of the pipeconf associated to a given device.
*
* @param deviceId device identifier
* @return PiPipeconfId
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 f2ece6b..f098c75 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
@@ -120,21 +120,14 @@
Driver driver;
- // Primary source of driver configuration is the network config.
+ // Special processing for devices with pipeconf.
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);
- }
+ // No fallback for pipeconf merged drivers. Returns null if driver
+ // does not exist.
+ return getPipeconfMergedDriver(deviceId);
}
+
+ // Primary source of driver configuration is the network config.
BasicDeviceConfig cfg = networkConfigService.getConfig(deviceId, BasicDeviceConfig.class);
driver = lookupDriver(cfg != null ? cfg.driver() : null);
if (driver != null) {
@@ -155,6 +148,28 @@
NO_DRIVER);
}
+ private Driver getPipeconfMergedDriver(DeviceId deviceId) {
+ PiPipeconfId pipeconfId = pipeconfService.ofDevice(deviceId).orElse(null);
+ if (pipeconfId == null) {
+ log.warn("Missing pipeconf for {}, cannot produce a pipeconf merged driver",
+ deviceId);
+ return null;
+ }
+ String mergedDriverName = pipeconfService.getMergedDriver(deviceId, pipeconfId);
+ if (mergedDriverName == null) {
+ log.warn("Unable to get pipeconf merged driver for {} and {}",
+ deviceId, pipeconfId);
+ return null;
+ }
+ try {
+ return getDriver(mergedDriverName);
+ } catch (ItemNotFoundException e) {
+ log.warn("Specified pipeconf merged driver {} for {} not found",
+ mergedDriverName, deviceId);
+ return null;
+ }
+ }
+
private Driver lookupDriver(String driverName) {
if (driverName != null) {
try {
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 a90149f..5044df0 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,6 +27,7 @@
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.Service;
import org.onlab.util.ItemNotFoundException;
+import org.onlab.util.SharedExecutors;
import org.onosproject.net.DeviceId;
import org.onosproject.net.config.ConfigFactory;
import org.onosproject.net.config.NetworkConfigRegistry;
@@ -55,6 +56,7 @@
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import static java.lang.String.format;
@@ -75,6 +77,8 @@
private static final String MERGED_DRIVER_SEPARATOR = ":";
private static final String CFG_SCHEME = "piPipeconf";
+ private static final int MISSING_DRIVER_WATCHDOG_INTERVAL = 5; // Seconds.
+
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected NetworkConfigRegistry cfgService;
@@ -111,6 +115,13 @@
cfgService.registerConfigFactory(configFactory);
driverAdminService.addListener(driverListener);
checkMissingMergedDrivers();
+ if (!missingMergedDrivers.isEmpty()) {
+ // Missing drivers should be created upon detecting registration
+ // events of a new pipeconf or a base driver. If, for any reason, we
+ // miss such event, here's a watchdog task.
+ SharedExecutors.getPoolThreadExecutor()
+ .execute(this::missingDriversWatchdogTask);
+ }
log.info("Started");
}
@@ -134,7 +145,7 @@
}
pipeconfs.put(pipeconf.id(), pipeconf);
log.info("New pipeconf registered: {}", pipeconf.id());
- executor.execute(() -> mergeAll(pipeconf.id()));
+ executor.execute(() -> attemptMergeAll(pipeconf.id()));
}
@Override
@@ -306,64 +317,102 @@
}
}
- private void checkMissingMergedDrivers() {
- cfgService.getSubjects(DeviceId.class, BasicDeviceConfig.class).stream()
- .map(d -> cfgService.getConfig(d, BasicDeviceConfig.class))
- .map(BasicDeviceConfig::driver)
- .filter(Objects::nonNull)
- .filter(d -> getDriver(d) == null)
- .forEach(driverName -> {
- final String baseDriverName = getBaseDriverNameFromMerged(driverName);
- final PiPipeconfId pipeconfId = getPipeconfIdFromMerged(driverName);
- if (baseDriverName == null || pipeconfId == null) {
- // Not a merged driver.
- return;
- }
- log.info("Detected missing merged driver: {}", driverName);
- missingMergedDrivers.add(driverName);
- // Attempt building the driver now if all pieces are present.
- // If not, either a driver or pipeconf event will re-trigger
- // the merge process.
- if (getDriver(baseDriverName) != null
- && pipeconfs.containsKey(pipeconfId)) {
- mergedDriverName(baseDriverName, pipeconfId);
- }
- });
+ private boolean driverExists(String name) {
+ return getDriver(name) != null;
}
- private void mergeAll(String baseDriverName) {
+ private void checkMissingMergedDriver(DeviceId deviceId) {
+ final PiPipeconfId pipeconfId = pipeconfMappingStore.getPipeconfId(deviceId);
+ final BasicDeviceConfig cfg = cfgService.getConfig(deviceId, BasicDeviceConfig.class);
+
+ if (pipeconfId == null) {
+ // No pipeconf associated.
+ return;
+ }
+
+ if (cfg == null || cfg.driver() == null) {
+ log.warn("Missing basic device config or driver key in netcfg for " +
+ "{}, which is odd since it has a " +
+ "pipeconf associated ({})",
+ deviceId, pipeconfId);
+ return;
+ }
+
+ final String baseDriverName = cfg.driver();
+ final String mergedDriverName = mergedDriverName(baseDriverName, pipeconfId);
+
+ if (driverExists(mergedDriverName) ||
+ missingMergedDrivers.contains(mergedDriverName)) {
+ // Not missing, or already aware of it missing.
+ return;
+ }
+
+ log.info("Detected missing merged driver: {}", mergedDriverName);
+ missingMergedDrivers.add(mergedDriverName);
+ // Attempt building the driver now if all pieces are present.
+ // If not, either a driver or pipeconf event will re-trigger
+ // the process.
+ attemptDriverMerge(mergedDriverName);
+ }
+
+ private void attemptDriverMerge(String mergedDriverName) {
+ final String baseDriverName = getBaseDriverNameFromMerged(mergedDriverName);
+ final PiPipeconfId pipeconfId = getPipeconfIdFromMerged(mergedDriverName);
+ if (driverExists(baseDriverName) && pipeconfs.containsKey(pipeconfId)) {
+ doMergeDriver(baseDriverName, pipeconfId);
+ }
+ }
+
+ private void missingDriversWatchdogTask() {
+ while (true) {
+ // Most probably all missing drivers will be created before the
+ // watchdog interval, so wait before starting...
+ try {
+ TimeUnit.SECONDS.sleep(MISSING_DRIVER_WATCHDOG_INTERVAL);
+ } catch (InterruptedException e) {
+ log.warn("Interrupted! There are still {} missing merged drivers",
+ missingMergedDrivers.size());
+ }
+ if (missingMergedDrivers.isEmpty()) {
+ log.info("There are no more missing merged drivers!");
+ return;
+ }
+ log.info("Detected {} missing merged drivers, attempt merge...",
+ missingMergedDrivers.size());
+ missingMergedDrivers.forEach(this::attemptDriverMerge);
+ }
+ }
+
+ private void checkMissingMergedDrivers() {
+ cfgService.getSubjects(DeviceId.class, BasicDeviceConfig.class)
+ .forEach(this::checkMissingMergedDriver);
+ }
+
+ private void attemptMergeAll(String baseDriverName) {
missingMergedDrivers.stream()
- .filter(driverName -> {
- final String xx = getBaseDriverNameFromMerged(driverName);
+ .filter(missingDriver -> {
+ // Filter missing merged drivers using this base driver.
+ final String xx = getBaseDriverNameFromMerged(missingDriver);
return xx != null && xx.equals(baseDriverName);
})
- .forEach(driverName -> {
- final PiPipeconfId pipeconfId = getPipeconfIdFromMerged(driverName);
- if (pipeconfs.containsKey(pipeconfId)) {
- doMergeDriver(baseDriverName, pipeconfId);
- }
- });
+ .forEach(this::attemptDriverMerge);
}
- private void mergeAll(PiPipeconfId pipeconfId) {
+ private void attemptMergeAll(PiPipeconfId pipeconfId) {
missingMergedDrivers.stream()
- .filter(driverName -> {
- final PiPipeconfId xx = getPipeconfIdFromMerged(driverName);
+ .filter(missingDriver -> {
+ // Filter missing merged drivers using this pipeconf.
+ final PiPipeconfId xx = getPipeconfIdFromMerged(missingDriver);
return xx != null && xx.equals(pipeconfId);
})
- .forEach(driverName -> {
- final String baseDriverName = getBaseDriverNameFromMerged(driverName);
- if (getDriver(baseDriverName) != null) {
- doMergeDriver(baseDriverName, pipeconfId);
- }
- });
+ .forEach(this::attemptDriverMerge);
}
private class InternalDriverListener implements DriverListener {
@Override
public void event(DriverEvent event) {
- executor.execute(() -> mergeAll(event.subject().name()));
+ executor.execute(() -> attemptMergeAll(event.subject().name()));
}
@Override