Adding means to invalidate the pipeliner cache of FlowObjectiveManager.
This will be triggered by:
- changes in the driver configuration
- changes in the driver name configured for the device
Change-Id: I9896960cdb4ed988db2cced8ae0e24e53ffb01fb
diff --git a/core/net/src/main/java/org/onosproject/net/flowobjective/impl/FlowObjectiveManager.java b/core/net/src/main/java/org/onosproject/net/flowobjective/impl/FlowObjectiveManager.java
index 3e242d1..4bd4feb 100644
--- a/core/net/src/main/java/org/onosproject/net/flowobjective/impl/FlowObjectiveManager.java
+++ b/core/net/src/main/java/org/onosproject/net/flowobjective/impl/FlowObjectiveManager.java
@@ -31,6 +31,7 @@
import org.onlab.util.Tools;
import org.onosproject.cfg.ComponentConfigService;
import org.onosproject.cluster.ClusterService;
+import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.behaviour.NextGroup;
import org.onosproject.net.behaviour.Pipeliner;
@@ -38,7 +39,9 @@
import org.onosproject.net.device.DeviceEvent;
import org.onosproject.net.device.DeviceListener;
import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.driver.DriverEvent;
import org.onosproject.net.driver.DriverHandler;
+import org.onosproject.net.driver.DriverListener;
import org.onosproject.net.driver.DriverService;
import org.onosproject.net.flow.FlowRuleService;
import org.onosproject.net.flowobjective.FilteringObjective;
@@ -68,6 +71,7 @@
import static com.google.common.base.Strings.isNullOrEmpty;
import static java.util.concurrent.Executors.newFixedThreadPool;
import static org.onlab.util.Tools.groupedThreads;
+import static org.onosproject.net.AnnotationKeys.DRIVER;
import static org.onosproject.security.AppGuard.checkPermission;
import static org.onosproject.security.AppPermission.Type.FLOWRULE_WRITE;
@@ -124,6 +128,7 @@
private final PipelinerContext context = new InnerPipelineContext();
private final DeviceListener deviceListener = new InnerDeviceListener();
+ private final DriverListener driverListener = new InnerDriverListener();
protected ServiceDirectory serviceDirectory = new DefaultServiceDirectory();
@@ -149,6 +154,7 @@
groupedThreads(GROUP_THREAD_NAME, WORKER_PATTERN, log));
flowObjectiveStore.setDelegate(delegate);
deviceService.addListener(deviceListener);
+ driverService.addListener(driverListener);
log.info("Started");
}
@@ -157,6 +163,7 @@
cfgService.unregisterProperties(getClass(), false);
flowObjectiveStore.unsetDelegate(delegate);
deviceService.removeListener(deviceListener);
+ driverService.removeListener(driverListener);
executorService.shutdown();
pipeliners.clear();
driverHandlers.clear();
@@ -270,7 +277,8 @@
}
@Override
- public void initPolicy(String policy) {}
+ public void initPolicy(String policy) {
+ }
private boolean queueFwdObjective(DeviceId deviceId, ForwardingObjective fwd) {
boolean queued = false;
@@ -402,6 +410,24 @@
return pipeliner;
}
+ private void invalidatePipelinerIfNecessary(Device device) {
+ DriverHandler handler = driverHandlers.get(device.id());
+ if (handler != null &&
+ !Objects.equals(handler.driver().name(),
+ device.annotations().value(DRIVER))) {
+ invalidatePipeliner(device.id());
+ }
+ }
+
+ private void invalidatePipeliner(DeviceId id) {
+ log.info("Invalidating cached pipeline behaviour for {}", id);
+ driverHandlers.remove(id);
+ pipeliners.remove(id);
+ if (deviceService.isAvailable(id)) {
+ getAndInitDevicePipeliner(id);
+ }
+ }
+
// Triggers driver setup when a device is (re)detected.
private class InnerDeviceListener implements DeviceListener {
@Override
@@ -419,6 +445,9 @@
}
break;
case DEVICE_UPDATED:
+ // Invalidate pipeliner and handler caches if the driver name
+ // device annotation changed.
+ invalidatePipelinerIfNecessary(event.subject());
break;
case DEVICE_REMOVED:
// evict Pipeliner and Handler cache, when
@@ -444,6 +473,22 @@
}
}
+ // Monitors driver configuration changes and invalidates the pipeliner cache entries.
+ // Note that this may leave stale entries on the device if the driver changes
+ // in manner where the new driver does not produce backward compatible flow objectives.
+ // In such cases, it is the operator's responsibility to force device re-connect.
+ private class InnerDriverListener implements DriverListener {
+ @Override
+ public void event(DriverEvent event) {
+ String driverName = event.subject().name();
+ driverHandlers.entrySet().stream()
+ .filter(e -> driverName.equals(e.getValue().driver().name()))
+ .map(Map.Entry::getKey)
+ .distinct()
+ .forEach(FlowObjectiveManager.this::invalidatePipeliner);
+ }
+ }
+
// Temporary mechanism to monitor pipeliner setup time-cost; there are
// intermittent time where this takes in excess of 2 seconds. Why?
private long start = 0, totals = 0, count = 0;