Committed by
Gerrit Code Review
Simplified Bmv2 device context service and context handling in demo apps
Change-Id: I2a13ed673902d0616732d43c841f50b1ad38cd4c
Showing
6 changed files
with
56 additions
and
80 deletions
... | @@ -56,9 +56,11 @@ import org.onosproject.net.topology.TopologyVertex; | ... | @@ -56,9 +56,11 @@ import org.onosproject.net.topology.TopologyVertex; |
56 | import org.slf4j.Logger; | 56 | import org.slf4j.Logger; |
57 | 57 | ||
58 | import java.util.Collection; | 58 | import java.util.Collection; |
59 | +import java.util.Collections; | ||
59 | import java.util.List; | 60 | import java.util.List; |
60 | import java.util.Map; | 61 | import java.util.Map; |
61 | import java.util.Set; | 62 | import java.util.Set; |
63 | +import java.util.concurrent.ConcurrentMap; | ||
62 | import java.util.concurrent.ExecutorService; | 64 | import java.util.concurrent.ExecutorService; |
63 | import java.util.concurrent.Executors; | 65 | import java.util.concurrent.Executors; |
64 | import java.util.concurrent.TimeUnit; | 66 | import java.util.concurrent.TimeUnit; |
... | @@ -135,10 +137,13 @@ public abstract class AbstractUpgradableFabricApp { | ... | @@ -135,10 +137,13 @@ public abstract class AbstractUpgradableFabricApp { |
135 | private Set<DeviceId> spineSwitches; | 137 | private Set<DeviceId> spineSwitches; |
136 | 138 | ||
137 | private Map<DeviceId, List<FlowRule>> deviceFlowRules; | 139 | private Map<DeviceId, List<FlowRule>> deviceFlowRules; |
138 | - private Map<DeviceId, Boolean> rulesInstalled; | 140 | + private Map<DeviceId, Boolean> contextFlags; |
141 | + private Map<DeviceId, Boolean> ruleFlags; | ||
142 | + | ||
143 | + private ConcurrentMap<DeviceId, Boolean> deployLocks = Maps.newConcurrentMap(); | ||
139 | 144 | ||
140 | /** | 145 | /** |
141 | - * Creates a new Bmv2 Fabric Component. | 146 | + * Creates a new BMv2 fabric app. |
142 | * | 147 | * |
143 | * @param appName app name | 148 | * @param appName app name |
144 | * @param configurationName a common name for the P4 program / BMv2 configuration used by this app | 149 | * @param configurationName a common name for the P4 program / BMv2 configuration used by this app |
... | @@ -212,7 +217,8 @@ public abstract class AbstractUpgradableFabricApp { | ... | @@ -212,7 +217,8 @@ public abstract class AbstractUpgradableFabricApp { |
212 | leafSwitches = Sets.newHashSet(); | 217 | leafSwitches = Sets.newHashSet(); |
213 | spineSwitches = Sets.newHashSet(); | 218 | spineSwitches = Sets.newHashSet(); |
214 | deviceFlowRules = Maps.newConcurrentMap(); | 219 | deviceFlowRules = Maps.newConcurrentMap(); |
215 | - rulesInstalled = Maps.newConcurrentMap(); | 220 | + ruleFlags = Maps.newConcurrentMap(); |
221 | + contextFlags = Maps.newConcurrentMap(); | ||
216 | } | 222 | } |
217 | 223 | ||
218 | // Start flow rules generator... | 224 | // Start flow rules generator... |
... | @@ -266,41 +272,19 @@ public abstract class AbstractUpgradableFabricApp { | ... | @@ -266,41 +272,19 @@ public abstract class AbstractUpgradableFabricApp { |
266 | 272 | ||
267 | private void deployRoutine() { | 273 | private void deployRoutine() { |
268 | if (otherAppFound && otherApp.appActive) { | 274 | if (otherAppFound && otherApp.appActive) { |
269 | - log.info("Starting update routine..."); | 275 | + log.info("Deactivating other app..."); |
270 | - updateRoutine(); | ||
271 | appService.deactivate(otherApp.appId); | 276 | appService.deactivate(otherApp.appId); |
272 | - } else { | 277 | + try { |
273 | - Stream.concat(leafSwitches.stream(), spineSwitches.stream()) | 278 | + Thread.sleep(CLEANUP_SLEEP); |
274 | - .map(deviceService::getDevice) | 279 | + } catch (InterruptedException e) { |
275 | - .forEach(device -> spawnTask(() -> deployDevice(device))); | 280 | + log.warn("Cleanup sleep interrupted!"); |
281 | + Thread.interrupted(); | ||
282 | + } | ||
276 | } | 283 | } |
277 | - } | ||
278 | 284 | ||
279 | - private void updateRoutine() { | ||
280 | Stream.concat(leafSwitches.stream(), spineSwitches.stream()) | 285 | Stream.concat(leafSwitches.stream(), spineSwitches.stream()) |
281 | - .forEach(did -> spawnTask(() -> { | 286 | + .map(deviceService::getDevice) |
282 | - cleanUpDevice(did); | 287 | + .forEach(device -> spawnTask(() -> deployDevice(device))); |
283 | - try { | ||
284 | - Thread.sleep(CLEANUP_SLEEP); | ||
285 | - } catch (InterruptedException e) { | ||
286 | - log.warn("Cleanup sleep interrupted!"); | ||
287 | - Thread.interrupted(); | ||
288 | - } | ||
289 | - deployDevice(deviceService.getDevice(did)); | ||
290 | - })); | ||
291 | - } | ||
292 | - | ||
293 | - private void cleanUpDevice(DeviceId deviceId) { | ||
294 | - List<FlowRule> flowRulesToRemove = Lists.newArrayList(); | ||
295 | - flowRuleService.getFlowEntries(deviceId).forEach(fe -> { | ||
296 | - if (fe.appId() == otherApp.appId.id()) { | ||
297 | - flowRulesToRemove.add(fe); | ||
298 | - } | ||
299 | - }); | ||
300 | - if (flowRulesToRemove.size() > 0) { | ||
301 | - log.info("Cleaning {} old flow rules from {}...", flowRulesToRemove.size(), deviceId); | ||
302 | - removeFlowRules(flowRulesToRemove); | ||
303 | - } | ||
304 | } | 288 | } |
305 | 289 | ||
306 | /** | 290 | /** |
... | @@ -309,36 +293,35 @@ public abstract class AbstractUpgradableFabricApp { | ... | @@ -309,36 +293,35 @@ public abstract class AbstractUpgradableFabricApp { |
309 | * @param device a device | 293 | * @param device a device |
310 | */ | 294 | */ |
311 | public void deployDevice(Device device) { | 295 | public void deployDevice(Device device) { |
312 | - // Serialize executions per device ID using a concurrent map. | 296 | + |
313 | - rulesInstalled.compute(device.id(), (did, deployed) -> { | 297 | + DeviceId deviceId = device.id(); |
314 | - Bmv2DeviceContext deviceContext = bmv2ContextService.getContext(device.id()); | 298 | + |
315 | - if (deviceContext == null) { | 299 | + // Synchronize executions over the same device. |
316 | - log.error("Unable to get context for device {}", device.id()); | 300 | + deployLocks.putIfAbsent(deviceId, new Boolean(true)); |
317 | - return deployed; | 301 | + synchronized (deployLocks.get(deviceId)) { |
318 | - } else if (!deviceContext.equals(bmv2Context)) { | 302 | + |
319 | - log.info("Swapping configuration to {} on device {}...", configurationName, device.id()); | 303 | + // Set context if not already done. |
320 | - bmv2ContextService.triggerConfigurationSwap(device.id(), bmv2Context); | 304 | + if (!contextFlags.getOrDefault(deviceId, false)) { |
321 | - return deployed; | 305 | + log.info("Setting context to {} for {}...", configurationName, deviceId); |
306 | + bmv2ContextService.setContext(deviceId, bmv2Context); | ||
307 | + contextFlags.put(device.id(), true); | ||
308 | + } | ||
309 | + | ||
310 | + // Initialize device. | ||
311 | + if (!initDevice(deviceId)) { | ||
312 | + log.warn("Failed to initialize device {}", deviceId); | ||
322 | } | 313 | } |
323 | 314 | ||
324 | - List<FlowRule> rules = deviceFlowRules.get(device.id()); | 315 | + // Install rules. |
325 | - if (initDevice(device.id())) { | 316 | + if (!ruleFlags.getOrDefault(deviceId, false)) { |
326 | - if (deployed == null && rules != null && rules.size() > 0) { | 317 | + List<FlowRule> rules = deviceFlowRules.getOrDefault(deviceId, Collections.emptyList()); |
327 | - log.info("Installing rules for {}...", did); | 318 | + if (rules.size() > 0) { |
319 | + log.info("Installing rules for {}...", deviceId); | ||
328 | installFlowRules(rules); | 320 | installFlowRules(rules); |
329 | - return true; | 321 | + ruleFlags.put(deviceId, true); |
330 | - } | ||
331 | - } else { | ||
332 | - log.warn("Filed to initialize device {}", device.id()); | ||
333 | - if (deployed != null && rules != null && rules.size() > 0) { | ||
334 | - log.info("Removing rules for {}...", did); | ||
335 | - removeFlowRules(rules); | ||
336 | - return null; | ||
337 | } | 322 | } |
338 | } | 323 | } |
339 | - | 324 | + } |
340 | - return deployed; | ||
341 | - }); | ||
342 | } | 325 | } |
343 | 326 | ||
344 | private void spawnTask(Runnable task) { | 327 | private void spawnTask(Runnable task) { | ... | ... |
... | @@ -164,7 +164,7 @@ public interface Bmv2DeviceAgent { | ... | @@ -164,7 +164,7 @@ public interface Bmv2DeviceAgent { |
164 | * @param jsonString a string value | 164 | * @param jsonString a string value |
165 | * @throws Bmv2RuntimeException if any error occurs | 165 | * @throws Bmv2RuntimeException if any error occurs |
166 | */ | 166 | */ |
167 | - void loadNewJsonConfig(String jsonString) throws Bmv2RuntimeException; | 167 | + void uploadNewJsonConfig(String jsonString) throws Bmv2RuntimeException; |
168 | 168 | ||
169 | /** | 169 | /** |
170 | * Triggers a configuration swap on the device. | 170 | * Triggers a configuration swap on the device. | ... | ... |
... | @@ -25,12 +25,8 @@ import org.onosproject.net.DeviceId; | ... | @@ -25,12 +25,8 @@ import org.onosproject.net.DeviceId; |
25 | */ | 25 | */ |
26 | public interface Bmv2DeviceContextService { | 26 | public interface Bmv2DeviceContextService { |
27 | 27 | ||
28 | - // TODO: handle the potential configuration states (e.g. RUNNING, SWAP_REQUESTED, etc.) | ||
29 | - | ||
30 | /** | 28 | /** |
31 | - * Returns the context of a given device. The context returned is the last one for which a configuration swap was | 29 | + * Returns the context of the given device, null if no context has been previously set. |
32 | - * triggered, hence there's no guarantees that the device is enforcing the returned context's configuration at the | ||
33 | - * time of the call. | ||
34 | * | 30 | * |
35 | * @param deviceId a device ID | 31 | * @param deviceId a device ID |
36 | * @return a BMv2 device context | 32 | * @return a BMv2 device context |
... | @@ -38,12 +34,12 @@ public interface Bmv2DeviceContextService { | ... | @@ -38,12 +34,12 @@ public interface Bmv2DeviceContextService { |
38 | Bmv2DeviceContext getContext(DeviceId deviceId); | 34 | Bmv2DeviceContext getContext(DeviceId deviceId); |
39 | 35 | ||
40 | /** | 36 | /** |
41 | - * Triggers a configuration swap on a given device. | 37 | + * Sets the context for the given device. |
42 | * | 38 | * |
43 | * @param deviceId a device ID | 39 | * @param deviceId a device ID |
44 | * @param context a BMv2 device context | 40 | * @param context a BMv2 device context |
45 | */ | 41 | */ |
46 | - void triggerConfigurationSwap(DeviceId deviceId, Bmv2DeviceContext context); | 42 | + void setContext(DeviceId deviceId, Bmv2DeviceContext context); |
47 | 43 | ||
48 | /** | 44 | /** |
49 | * Binds the given interpreter with the given class loader so that other ONOS instances in the cluster can properly | 45 | * Binds the given interpreter with the given class loader so that other ONOS instances in the cluster can properly |
... | @@ -55,14 +51,9 @@ public interface Bmv2DeviceContextService { | ... | @@ -55,14 +51,9 @@ public interface Bmv2DeviceContextService { |
55 | void registerInterpreterClassLoader(Class<? extends Bmv2Interpreter> interpreterClass, ClassLoader loader); | 51 | void registerInterpreterClassLoader(Class<? extends Bmv2Interpreter> interpreterClass, ClassLoader loader); |
56 | 52 | ||
57 | /** | 53 | /** |
58 | - * Notifies this service that a given device has been updated, meaning a potential context change. | 54 | + * Returns a default context. |
59 | - * It returns true if the device configuration is the same as the last for which a swap was triggered, false | ||
60 | - * otherwise. In the last case, the service will asynchronously trigger a swap to the last | ||
61 | - * configuration stored by this service. If no swap has already been triggered then a default configuration will be | ||
62 | - * applied. | ||
63 | * | 55 | * |
64 | - * @param deviceId a device ID | 56 | + * @return a BMv2 device context |
65 | - * @return a boolean value | ||
66 | */ | 57 | */ |
67 | - boolean notifyDeviceChange(DeviceId deviceId); | 58 | + Bmv2DeviceContext defaultContext(); |
68 | } | 59 | } | ... | ... |
This diff is collapsed. Click to expand it.
... | @@ -397,7 +397,7 @@ public final class Bmv2DeviceThriftClient implements Bmv2DeviceAgent { | ... | @@ -397,7 +397,7 @@ public final class Bmv2DeviceThriftClient implements Bmv2DeviceAgent { |
397 | } | 397 | } |
398 | 398 | ||
399 | @Override | 399 | @Override |
400 | - public void loadNewJsonConfig(String jsonString) throws Bmv2RuntimeException { | 400 | + public void uploadNewJsonConfig(String jsonString) throws Bmv2RuntimeException { |
401 | 401 | ||
402 | log.debug("Loading new JSON config on device... > deviceId={}, jsonStringLength={}", | 402 | log.debug("Loading new JSON config on device... > deviceId={}, jsonStringLength={}", |
403 | deviceId, jsonString.length()); | 403 | deviceId, jsonString.length()); | ... | ... |
... | @@ -185,9 +185,11 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { | ... | @@ -185,9 +185,11 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { |
185 | (!Objects.equals(thisDescription, lastDescription) || | 185 | (!Objects.equals(thisDescription, lastDescription) || |
186 | !Objects.equals(thisDescription.annotations(), lastDescription.annotations())); | 186 | !Objects.equals(thisDescription.annotations(), lastDescription.annotations())); |
187 | if (descriptionChanged || !deviceService.isAvailable(did)) { | 187 | if (descriptionChanged || !deviceService.isAvailable(did)) { |
188 | - // Device description changed or device not available in the core. | 188 | + if (contextService.getContext(did) == null) { |
189 | - if (contextService.notifyDeviceChange(did)) { | 189 | + // Device is a first timer. |
190 | - // Configuration is the expected one, we can proceed notifying the core. | 190 | + log.info("Setting DEFAULT context for {}", did); |
191 | + contextService.setContext(did, contextService.defaultContext()); | ||
192 | + } else { | ||
191 | resetDeviceState(did); | 193 | resetDeviceState(did); |
192 | initPortCounters(did); | 194 | initPortCounters(did); |
193 | providerService.deviceConnected(did, thisDescription); | 195 | providerService.deviceConnected(did, thisDescription); |
... | @@ -295,7 +297,7 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { | ... | @@ -295,7 +297,7 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { |
295 | if (cfg != null) { | 297 | if (cfg != null) { |
296 | try { | 298 | try { |
297 | cfg.getDevicesInfo().stream().forEach(info -> { | 299 | cfg.getDevicesInfo().stream().forEach(info -> { |
298 | - // TODO: require also bmv2 internal device id from net-cfg (now is default 0) | 300 | + // FIXME: require also bmv2 internal device id from net-cfg (now is default 0) |
299 | Bmv2Device bmv2Device = new Bmv2Device(info.ip().toString(), info.port(), 0); | 301 | Bmv2Device bmv2Device = new Bmv2Device(info.ip().toString(), info.port(), 0); |
300 | triggerProbe(bmv2Device.asDeviceId()); | 302 | triggerProbe(bmv2Device.asDeviceId()); |
301 | }); | 303 | }); | ... | ... |
-
Please register or login to post a comment