Carmelo Cascone
Committed by Jonathan Hart

Various BMv2 bugfixes

Change-Id: Ia5a2a1c86b8a90ad68ddb92980377f6308e200d2
...@@ -64,6 +64,8 @@ import java.util.concurrent.ConcurrentMap; ...@@ -64,6 +64,8 @@ import java.util.concurrent.ConcurrentMap;
64 import java.util.concurrent.ExecutorService; 64 import java.util.concurrent.ExecutorService;
65 import java.util.concurrent.Executors; 65 import java.util.concurrent.Executors;
66 import java.util.concurrent.TimeUnit; 66 import java.util.concurrent.TimeUnit;
67 +import java.util.concurrent.locks.Lock;
68 +import java.util.concurrent.locks.ReentrantLock;
67 import java.util.stream.Collectors; 69 import java.util.stream.Collectors;
68 import java.util.stream.Stream; 70 import java.util.stream.Stream;
69 71
...@@ -87,7 +89,7 @@ public abstract class AbstractUpgradableFabricApp { ...@@ -87,7 +89,7 @@ public abstract class AbstractUpgradableFabricApp {
87 private static final int NUM_SPINES = 3; 89 private static final int NUM_SPINES = 3;
88 private static final int FLOW_PRIORITY = 100; 90 private static final int FLOW_PRIORITY = 100;
89 91
90 - private static final int CLEANUP_SLEEP = 1000; 92 + private static final int CLEANUP_SLEEP = 2000;
91 93
92 protected final Logger log = getLogger(getClass()); 94 protected final Logger log = getLogger(getClass());
93 95
...@@ -137,10 +139,11 @@ public abstract class AbstractUpgradableFabricApp { ...@@ -137,10 +139,11 @@ public abstract class AbstractUpgradableFabricApp {
137 private Set<DeviceId> spineSwitches; 139 private Set<DeviceId> spineSwitches;
138 140
139 private Map<DeviceId, List<FlowRule>> deviceFlowRules; 141 private Map<DeviceId, List<FlowRule>> deviceFlowRules;
142 + private Map<DeviceId, Bmv2DeviceContext> previousContexts;
140 private Map<DeviceId, Boolean> contextFlags; 143 private Map<DeviceId, Boolean> contextFlags;
141 private Map<DeviceId, Boolean> ruleFlags; 144 private Map<DeviceId, Boolean> ruleFlags;
142 145
143 - private ConcurrentMap<DeviceId, Boolean> deployLocks = Maps.newConcurrentMap(); 146 + private ConcurrentMap<DeviceId, Lock> deviceLocks = Maps.newConcurrentMap();
144 147
145 /** 148 /**
146 * Creates a new BMv2 fabric app. 149 * Creates a new BMv2 fabric app.
...@@ -270,7 +273,7 @@ public abstract class AbstractUpgradableFabricApp { ...@@ -270,7 +273,7 @@ public abstract class AbstractUpgradableFabricApp {
270 public abstract List<FlowRule> generateSpineRules(DeviceId deviceId, Collection<Host> dstHosts, Topology topology) 273 public abstract List<FlowRule> generateSpineRules(DeviceId deviceId, Collection<Host> dstHosts, Topology topology)
271 throws FlowRuleGeneratorException; 274 throws FlowRuleGeneratorException;
272 275
273 - private void deployRoutine() { 276 + private void deployAllDevices() {
274 if (otherAppFound && otherApp.appActive) { 277 if (otherAppFound && otherApp.appActive) {
275 log.info("Deactivating other app..."); 278 log.info("Deactivating other app...");
276 appService.deactivate(otherApp.appId); 279 appService.deactivate(otherApp.appId);
...@@ -297,9 +300,10 @@ public abstract class AbstractUpgradableFabricApp { ...@@ -297,9 +300,10 @@ public abstract class AbstractUpgradableFabricApp {
297 DeviceId deviceId = device.id(); 300 DeviceId deviceId = device.id();
298 301
299 // Synchronize executions over the same device. 302 // Synchronize executions over the same device.
300 - deployLocks.putIfAbsent(deviceId, new Boolean(true)); 303 + Lock lock = deviceLocks.computeIfAbsent(deviceId, k -> new ReentrantLock());
301 - synchronized (deployLocks.get(deviceId)) { 304 + lock.lock();
302 305
306 + try {
303 // Set context if not already done. 307 // Set context if not already done.
304 if (!contextFlags.getOrDefault(deviceId, false)) { 308 if (!contextFlags.getOrDefault(deviceId, false)) {
305 log.info("Setting context to {} for {}...", configurationName, deviceId); 309 log.info("Setting context to {} for {}...", configurationName, deviceId);
...@@ -321,6 +325,8 @@ public abstract class AbstractUpgradableFabricApp { ...@@ -321,6 +325,8 @@ public abstract class AbstractUpgradableFabricApp {
321 ruleFlags.put(deviceId, true); 325 ruleFlags.put(deviceId, true);
322 } 326 }
323 } 327 }
328 + } finally {
329 + lock.unlock();
324 } 330 }
325 } 331 }
326 332
...@@ -421,9 +427,9 @@ public abstract class AbstractUpgradableFabricApp { ...@@ -421,9 +427,9 @@ public abstract class AbstractUpgradableFabricApp {
421 ImmutableMap.Builder<DeviceId, List<FlowRule>> mapBuilder = ImmutableMap.builder(); 427 ImmutableMap.Builder<DeviceId, List<FlowRule>> mapBuilder = ImmutableMap.builder();
422 concat(spines.stream(), leafs.stream()) 428 concat(spines.stream(), leafs.stream())
423 .map(deviceId -> ImmutableList.copyOf(newFlowRules 429 .map(deviceId -> ImmutableList.copyOf(newFlowRules
424 - .stream() 430 + .stream()
425 - .filter(fr -> fr.deviceId().equals(deviceId)) 431 + .filter(fr -> fr.deviceId().equals(deviceId))
426 - .iterator())) 432 + .iterator()))
427 .forEach(frs -> mapBuilder.put(frs.get(0).deviceId(), frs)); 433 .forEach(frs -> mapBuilder.put(frs.get(0).deviceId(), frs));
428 this.deviceFlowRules = mapBuilder.build(); 434 this.deviceFlowRules = mapBuilder.build();
429 435
...@@ -433,10 +439,9 @@ public abstract class AbstractUpgradableFabricApp { ...@@ -433,10 +439,9 @@ public abstract class AbstractUpgradableFabricApp {
433 // Avoid other executions to modify the generated flow rules. 439 // Avoid other executions to modify the generated flow rules.
434 flowRuleGenerated = true; 440 flowRuleGenerated = true;
435 441
436 - log.info("DONE! Generated {} flow rules for {} devices...", newFlowRules.size(), spines.size() + leafs.size()); 442 + log.info("Generated {} flow rules for {} devices", newFlowRules.size(), spines.size() + leafs.size());
437 443
438 - // Deploy configuration. 444 + spawnTask(this::deployAllDevices);
439 - spawnTask(this::deployRoutine);
440 } 445 }
441 446
442 /** 447 /**
......
1 -/Users/carmelo/workspace/onos-p4-dev/p4src/build/ecmp.json
...\ No newline at end of file ...\ No newline at end of file
This diff is collapsed. Click to expand it.
...@@ -105,7 +105,7 @@ public class WcmpFabricApp extends AbstractUpgradableFabricApp { ...@@ -105,7 +105,7 @@ public class WcmpFabricApp extends AbstractUpgradableFabricApp {
105 } 105 }
106 return true; 106 return true;
107 } catch (Bmv2RuntimeException e) { 107 } catch (Bmv2RuntimeException e) {
108 - log.error("Unable to init device {}: {}", deviceId, e.explain()); 108 + log.debug("Exception while initializing device {}: {}", deviceId, e.explain());
109 return false; 109 return false;
110 } 110 }
111 } 111 }
......
1 -/Users/carmelo/workspace/onos-p4-dev/p4src/build/wcmp.json
...\ No newline at end of file ...\ No newline at end of file
This diff is collapsed. Click to expand it.
...@@ -18,6 +18,7 @@ package org.onosproject.drivers.bmv2; ...@@ -18,6 +18,7 @@ package org.onosproject.drivers.bmv2;
18 18
19 import com.google.common.collect.ImmutableList; 19 import com.google.common.collect.ImmutableList;
20 import com.google.common.collect.Lists; 20 import com.google.common.collect.Lists;
21 +import org.onlab.osgi.ServiceNotFoundException;
21 import org.onlab.packet.ChassisId; 22 import org.onlab.packet.ChassisId;
22 import org.onosproject.bmv2.api.runtime.Bmv2DeviceAgent; 23 import org.onosproject.bmv2.api.runtime.Bmv2DeviceAgent;
23 import org.onosproject.bmv2.api.runtime.Bmv2RuntimeException; 24 import org.onosproject.bmv2.api.runtime.Bmv2RuntimeException;
...@@ -54,12 +55,13 @@ public class Bmv2DeviceDescriptionDiscovery extends AbstractHandlerBehaviour imp ...@@ -54,12 +55,13 @@ public class Bmv2DeviceDescriptionDiscovery extends AbstractHandlerBehaviour imp
54 private Bmv2Controller controller; 55 private Bmv2Controller controller;
55 56
56 private boolean init() { 57 private boolean init() {
57 - controller = handler().get(Bmv2Controller.class); 58 + try {
58 - if (controller == null) { 59 + controller = handler().get(Bmv2Controller.class);
59 - log.warn("Failed to get a BMv2 controller"); 60 + return true;
61 + } catch (ServiceNotFoundException e) {
62 + log.warn(e.getMessage());
60 return false; 63 return false;
61 } 64 }
62 - return true;
63 } 65 }
64 66
65 @Override 67 @Override
......
...@@ -19,6 +19,7 @@ package org.onosproject.drivers.bmv2; ...@@ -19,6 +19,7 @@ package org.onosproject.drivers.bmv2;
19 import com.google.common.collect.Lists; 19 import com.google.common.collect.Lists;
20 import com.google.common.collect.Maps; 20 import com.google.common.collect.Maps;
21 import org.apache.commons.lang3.tuple.Pair; 21 import org.apache.commons.lang3.tuple.Pair;
22 +import org.onlab.osgi.ServiceNotFoundException;
22 import org.onosproject.bmv2.api.context.Bmv2Configuration; 23 import org.onosproject.bmv2.api.context.Bmv2Configuration;
23 import org.onosproject.bmv2.api.context.Bmv2DeviceContext; 24 import org.onosproject.bmv2.api.context.Bmv2DeviceContext;
24 import org.onosproject.bmv2.api.context.Bmv2FlowRuleTranslator; 25 import org.onosproject.bmv2.api.context.Bmv2FlowRuleTranslator;
...@@ -70,22 +71,15 @@ public class Bmv2FlowRuleProgrammable extends AbstractHandlerBehaviour implement ...@@ -70,22 +71,15 @@ public class Bmv2FlowRuleProgrammable extends AbstractHandlerBehaviour implement
70 private Bmv2DeviceContextService contextService; 71 private Bmv2DeviceContextService contextService;
71 72
72 private boolean init() { 73 private boolean init() {
73 - controller = handler().get(Bmv2Controller.class); 74 + try {
74 - tableEntryService = handler().get(Bmv2TableEntryService.class); 75 + controller = handler().get(Bmv2Controller.class);
75 - contextService = handler().get(Bmv2DeviceContextService.class); 76 + tableEntryService = handler().get(Bmv2TableEntryService.class);
76 - if (controller == null) { 77 + contextService = handler().get(Bmv2DeviceContextService.class);
77 - log.warn("Failed to get a BMv2 controller"); 78 + return true;
78 - return false; 79 + } catch (ServiceNotFoundException e) {
79 - } 80 + log.warn(e.getMessage());
80 - if (tableEntryService == null) {
81 - log.warn("Failed to get a BMv2 table entry service");
82 - return false;
83 - }
84 - if (contextService == null) {
85 - log.warn("Failed to get a BMv2 device context service");
86 return false; 81 return false;
87 } 82 }
88 - return true;
89 } 83 }
90 84
91 @Override 85 @Override
...@@ -140,9 +134,14 @@ public class Bmv2FlowRuleProgrammable extends AbstractHandlerBehaviour implement ...@@ -140,9 +134,14 @@ public class Bmv2FlowRuleProgrammable extends AbstractHandlerBehaviour implement
140 Bmv2FlowRuleWrapper frWrapper = tableEntryService.lookup(entryRef); 134 Bmv2FlowRuleWrapper frWrapper = tableEntryService.lookup(entryRef);
141 135
142 if (frWrapper == null) { 136 if (frWrapper == null) {
143 - log.warn("missing reference from table entry service, BUG? " + 137 + log.debug("Missing reference from table entry service. Deleting it. BUG? " +
144 "deviceId={}, tableName={}, matchKey={}", 138 "deviceId={}, tableName={}, matchKey={}",
145 deviceId, table.name(), entryRef.matchKey()); 139 deviceId, table.name(), entryRef.matchKey());
140 + try {
141 + doRemove(deviceAgent, table.name(), parsedEntry.entryId(), parsedEntry.matchKey());
142 + } catch (Bmv2RuntimeException e) {
143 + log.warn("Unable to remove inconsistent flow rule: {}", e.explain());
144 + }
146 continue; // next entry 145 continue; // next entry
147 } 146 }
148 147
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
16 16
17 package org.onosproject.drivers.bmv2; 17 package org.onosproject.drivers.bmv2;
18 18
19 +import org.onlab.osgi.ServiceNotFoundException;
19 import org.onlab.util.ImmutableByteSequence; 20 import org.onlab.util.ImmutableByteSequence;
20 import org.onosproject.bmv2.api.runtime.Bmv2DeviceAgent; 21 import org.onosproject.bmv2.api.runtime.Bmv2DeviceAgent;
21 import org.onosproject.bmv2.api.runtime.Bmv2RuntimeException; 22 import org.onosproject.bmv2.api.runtime.Bmv2RuntimeException;
...@@ -78,9 +79,11 @@ public class Bmv2PacketProgrammable extends AbstractHandlerBehaviour implements ...@@ -78,9 +79,11 @@ public class Bmv2PacketProgrammable extends AbstractHandlerBehaviour implements
78 79
79 DeviceId deviceId = handler().data().deviceId(); 80 DeviceId deviceId = handler().data().deviceId();
80 81
81 - Bmv2Controller controller = handler().get(Bmv2Controller.class); 82 + Bmv2Controller controller;
82 - if (controller == null) { 83 + try {
83 - log.error("Failed to get BMv2 controller"); 84 + controller = handler().get(Bmv2Controller.class);
85 + } catch (ServiceNotFoundException e) {
86 + log.warn(e.getMessage());
84 return; 87 return;
85 } 88 }
86 89
......
...@@ -189,16 +189,17 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { ...@@ -189,16 +189,17 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider {
189 (!Objects.equals(thisDescription, lastDescription) || 189 (!Objects.equals(thisDescription, lastDescription) ||
190 !Objects.equals(thisDescription.annotations(), lastDescription.annotations())); 190 !Objects.equals(thisDescription.annotations(), lastDescription.annotations()));
191 if (descriptionChanged || !deviceService.isAvailable(did)) { 191 if (descriptionChanged || !deviceService.isAvailable(did)) {
192 - if (contextService.getContext(did) == null) { 192 + if (deviceService.getDevice(did) == null) {
193 // Device is a first timer. 193 // Device is a first timer.
194 log.info("Setting DEFAULT context for {}", did); 194 log.info("Setting DEFAULT context for {}", did);
195 + // It is important to do this before connecting the device so other
196 + // services won't find a null context.
195 contextService.setContext(did, contextService.defaultContext()); 197 contextService.setContext(did, contextService.defaultContext());
196 - } else {
197 - resetDeviceState(did);
198 - initPortCounters(did);
199 - providerService.deviceConnected(did, thisDescription);
200 - updatePortsAndStats(did);
201 } 198 }
199 + resetDeviceState(did);
200 + initPortCounters(did);
201 + providerService.deviceConnected(did, thisDescription);
202 + updatePortsAndStats(did);
202 } 203 }
203 return thisDescription; 204 return thisDescription;
204 } else { 205 } else {
...@@ -272,7 +273,7 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { ...@@ -272,7 +273,7 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider {
272 if (deviceService.isAvailable(did)) { 273 if (deviceService.isAvailable(did)) {
273 providerService.deviceDisconnected(did); 274 providerService.deviceDisconnected(did);
274 } 275 }
275 - activeDevices.put(did, null); 276 + activeDevices.remove(did);
276 } 277 }
277 278
278 /** 279 /**
...@@ -333,7 +334,7 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { ...@@ -333,7 +334,7 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider {
333 } 334 }
334 335
335 /** 336 /**
336 - * Task that periodically trigger device probes to check for device status and update port informations. 337 + * Task that periodically trigger device probes to check for device status and update port information.
337 */ 338 */
338 private class DevicePoller implements TimerTask { 339 private class DevicePoller implements TimerTask {
339 340
......