Fix for routingHandler NPE.
Adding initial delay in handing network config to buffer event and handle async behaviours.
Change-Id: Id6f296f79b74d0386ea4dcb50e7701a672ef51d6
(cherry picked from commit 15fcbba61dbf79836c7f3088bfd257347d0dd2de)
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
index 00bfe93..14989d1 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
@@ -137,7 +137,9 @@
import java.util.Map;
import java.util.Optional;
import java.util.Set;
+import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@@ -249,6 +251,9 @@
private final InternalRouteEventListener routeListener = new InternalRouteEventListener();
private final InternalTopologyListener topologyListener = new InternalTopologyListener();
private final InternalMastershipListener mastershipListener = new InternalMastershipListener();
+ //Completable future for network configuration process to buffer config events handling during activation
+ private CompletableFuture<Boolean> networkConfigCompletion = null;
+ private List<Event> quequedEvents = new CopyOnWriteArrayList<>();
// Handles device, link, topology and network config events
private ScheduledExecutorService mainEventExecutor;
@@ -430,6 +435,7 @@
cfgService.registerConfigFactory(xConnectConfigFactory);
cfgService.registerConfigFactory(mcastConfigFactory);
log.info("Configuring network before adding listeners");
+
cfgListener.configureNetwork();
hostService.addListener(hostListener);
@@ -444,6 +450,15 @@
linkHandler.init();
l2TunnelHandler.init();
+ networkConfigCompletion.whenComplete((value, ex) -> {
+ //setting to null for easier fall through
+ networkConfigCompletion = null;
+ //process all queued events
+ quequedEvents.forEach(event -> {
+ mainEventExecutor.execute(new InternalEventHandler(event));
+ });
+ });
+
log.info("Started");
}
@@ -1377,6 +1392,20 @@
*/
void configureNetwork() {
log.info("Configuring network ...");
+
+ // Setting handling of network configuration events completable future
+ // The completable future is needed because of the async behaviour of the configureNetwork,
+ // listener registration and event arrival
+ // Enables us to buffer the events and execute them when the configure network is done.
+ networkConfigCompletion = new CompletableFuture<>();
+
+ // add a small delay to absorb multiple network config added notifications
+ if (!programmingScheduled.get()) {
+ log.info("Buffering config calls for {} secs", PROGRAM_DELAY);
+ programmingScheduled.set(true);
+ mainEventExecutor.schedule(new ConfigChange(), PROGRAM_DELAY, TimeUnit.SECONDS);
+ }
+
createOrUpdateDeviceConfiguration();
arpHandler = new ArpHandler(srManager);
@@ -1390,13 +1419,10 @@
policyHandler = new PolicyHandler(appId, deviceConfiguration,
flowObjectiveService,
tunnelHandler, policyStore);
- // add a small delay to absorb multiple network config added notifications
- if (!programmingScheduled.get()) {
- log.info("Buffering config calls for {} secs", PROGRAM_DELAY);
- programmingScheduled.set(true);
- mainEventExecutor.schedule(new ConfigChange(), PROGRAM_DELAY, TimeUnit.SECONDS);
- }
+ networkConfigCompletion.complete(true);
+
mcastHandler.init();
+
}
@Override
@@ -1408,7 +1434,11 @@
case CONFIG_UPDATED:
case CONFIG_REMOVED:
log.trace("Schedule Network Config event {}", event);
- mainEventExecutor.execute(new InternalEventHandler(event));
+ if (networkConfigCompletion == null || networkConfigCompletion.isDone()) {
+ mainEventExecutor.execute(new InternalEventHandler(event));
+ } else {
+ quequedEvents.add(event);
+ }
break;
default:
break;
@@ -1454,7 +1484,11 @@
event.type() == LinkEvent.Type.LINK_UPDATED ||
event.type() == LinkEvent.Type.LINK_REMOVED) {
log.trace("Schedule Link event {}", event);
- mainEventExecutor.execute(new InternalEventHandler(event));
+ if (networkConfigCompletion == null || networkConfigCompletion.isDone()) {
+ mainEventExecutor.execute(new InternalEventHandler(event));
+ } else {
+ quequedEvents.add(event);
+ }
}
}
}
@@ -1469,7 +1503,11 @@
case DEVICE_UPDATED:
case DEVICE_AVAILABILITY_CHANGED:
log.trace("Schedule Device event {}", event);
- mainEventExecutor.execute(new InternalEventHandler(event));
+ if (networkConfigCompletion == null || networkConfigCompletion.isDone()) {
+ mainEventExecutor.execute(new InternalEventHandler(event));
+ } else {
+ quequedEvents.add(event);
+ }
break;
default:
}
@@ -1482,7 +1520,11 @@
switch (event.type()) {
case TOPOLOGY_CHANGED:
log.trace("Schedule Topology event {}", event);
- mainEventExecutor.execute(new InternalEventHandler(event));
+ if (networkConfigCompletion == null || networkConfigCompletion.isDone()) {
+ mainEventExecutor.execute(new InternalEventHandler(event));
+ } else {
+ quequedEvents.add(event);
+ }
break;
default:
}
@@ -1578,6 +1620,12 @@
return;
}
+ //The system is in an incoherent state, abort
+ if (defaultRoutingHandler == null) {
+ log.warn("Interface update aborted, defaultRoutingHandler is null");
+ return;
+ }
+
Interface intf = intfs.stream().findFirst().get();
Interface prevIntf = prevIntfs.stream().findFirst().get();