blob: 7b12a079c0749f46017ec71df8e716fddac954c3 [file] [log] [blame]
Yi Tsengc927a062017-05-02 15:02:37 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Yi Tsengc927a062017-05-02 15:02:37 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.onosproject.net.intent.impl.installer;
18
Antonio Marsico4f68ec92017-03-09 11:16:32 +010019import com.google.common.collect.Lists;
Antonio Marsico4f68ec92017-03-09 11:16:32 +010020import org.onlab.util.Tools;
21import org.onosproject.cfg.ComponentConfigService;
22import org.onosproject.core.DefaultApplicationId;
23import org.onosproject.net.DeviceId;
24import org.onosproject.net.Link;
25import org.onosproject.net.NetworkResource;
26import org.onosproject.net.flow.DefaultFlowRule;
Yi Tsengc927a062017-05-02 15:02:37 -070027import org.onosproject.net.flow.FlowRule;
28import org.onosproject.net.flow.FlowRuleOperations;
29import org.onosproject.net.flow.FlowRuleOperationsContext;
30import org.onosproject.net.flow.FlowRuleService;
31import org.onosproject.net.intent.FlowRuleIntent;
Antonio Marsico4f68ec92017-03-09 11:16:32 +010032import org.onosproject.net.intent.Intent;
Yi Tsengc927a062017-05-02 15:02:37 -070033import org.onosproject.net.intent.IntentData;
34import org.onosproject.net.intent.IntentExtensionService;
Antonio Marsico4f68ec92017-03-09 11:16:32 +010035import org.onosproject.net.intent.IntentInstallCoordinator;
Yi Tsengc927a062017-05-02 15:02:37 -070036import org.onosproject.net.intent.IntentInstaller;
Antonio Marsico4f68ec92017-03-09 11:16:32 +010037import org.onosproject.net.intent.IntentOperationContext;
38import org.onosproject.net.intent.IntentStore;
Yi Tseng24d9be72017-05-12 11:28:13 -070039import org.onosproject.net.intent.ObjectiveTrackerService;
Antonio Marsico4f68ec92017-03-09 11:16:32 +010040import org.onosproject.net.intent.impl.IntentManager;
41import org.osgi.service.component.ComponentContext;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070042import org.osgi.service.component.annotations.Activate;
43import org.osgi.service.component.annotations.Component;
44import org.osgi.service.component.annotations.Deactivate;
45import org.osgi.service.component.annotations.Modified;
46import org.osgi.service.component.annotations.Reference;
47import org.osgi.service.component.annotations.ReferenceCardinality;
Yi Tsengc927a062017-05-02 15:02:37 -070048import org.slf4j.Logger;
49
50import java.util.Collection;
Yi Tseng4a7d1e12017-07-10 16:19:17 -070051import java.util.Collections;
Antonio Marsico4f68ec92017-03-09 11:16:32 +010052import java.util.Comparator;
Yi Tsengc927a062017-05-02 15:02:37 -070053import java.util.List;
54import java.util.Optional;
55import java.util.Set;
Antonio Marsico4f68ec92017-03-09 11:16:32 +010056import java.util.concurrent.CountDownLatch;
57import java.util.concurrent.ScheduledExecutorService;
58import java.util.concurrent.TimeUnit;
Yi Tseng4a7d1e12017-07-10 16:19:17 -070059import java.util.stream.Collectors;
Yi Tseng49a2b2e2017-05-11 14:32:16 -070060
Antonio Marsico4f68ec92017-03-09 11:16:32 +010061import static com.google.common.base.Strings.isNullOrEmpty;
62import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
63import static org.onlab.util.Tools.groupedThreads;
Yi Tsengc927a062017-05-02 15:02:37 -070064import static org.onosproject.net.intent.IntentInstaller.Direction.ADD;
65import static org.onosproject.net.intent.IntentInstaller.Direction.REMOVE;
Antonio Marsico4f68ec92017-03-09 11:16:32 +010066import static org.onosproject.net.intent.IntentState.INSTALLED;
67import static org.onosproject.net.intent.IntentState.REALLOCATING;
68import static org.onosproject.net.intent.constraint.NonDisruptiveConstraint.requireNonDisruptive;
Yi Tsengc927a062017-05-02 15:02:37 -070069import static org.slf4j.LoggerFactory.getLogger;
70
71/**
72 * Installer for FlowRuleIntent.
73 */
74@Component(immediate = true)
75public class FlowRuleIntentInstaller implements IntentInstaller<FlowRuleIntent> {
Ray Milkeyd84f89b2018-08-17 14:54:17 -070076 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tsengc927a062017-05-02 15:02:37 -070077 protected IntentExtensionService intentExtensionService;
78
Ray Milkeyd84f89b2018-08-17 14:54:17 -070079 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tsengc927a062017-05-02 15:02:37 -070080 protected ObjectiveTrackerService trackerService;
81
Ray Milkeyd84f89b2018-08-17 14:54:17 -070082 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tsengc927a062017-05-02 15:02:37 -070083 protected IntentInstallCoordinator intentInstallCoordinator;
84
Ray Milkeyd84f89b2018-08-17 14:54:17 -070085 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tsengc927a062017-05-02 15:02:37 -070086 protected FlowRuleService flowRuleService;
87
Ray Milkeyd84f89b2018-08-17 14:54:17 -070088 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Antonio Marsico4f68ec92017-03-09 11:16:32 +010089 protected ComponentConfigService configService;
90
Ray Milkeyd84f89b2018-08-17 14:54:17 -070091 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Antonio Marsico4f68ec92017-03-09 11:16:32 +010092 protected IntentStore store;
93
94 private ScheduledExecutorService nonDisruptiveIntentInstaller;
95
96 private static final int DEFAULT_NON_DISRUPTIVE_INSTALLATION_WAITING_TIME = 1;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070097 //@Property(name = "nonDisruptiveInstallationWaitingTime",
98 // intValue = DEFAULT_NON_DISRUPTIVE_INSTALLATION_WAITING_TIME,
99 // label = "Number of seconds to wait during the non-disruptive installation phases")
Antonio Marsico4f68ec92017-03-09 11:16:32 +0100100 private int nonDisruptiveInstallationWaitingTime = DEFAULT_NON_DISRUPTIVE_INSTALLATION_WAITING_TIME;
101
102 protected final Logger log = getLogger(IntentManager.class);
103
104 private boolean isReallocationStageFailed = false;
105
106 private static final LinkComparator LINK_COMPARATOR = new LinkComparator();
107
Yi Tsengc927a062017-05-02 15:02:37 -0700108 @Activate
109 public void activate() {
110 intentExtensionService.registerInstaller(FlowRuleIntent.class, this);
Antonio Marsico4f68ec92017-03-09 11:16:32 +0100111 nonDisruptiveIntentInstaller =
112 newSingleThreadScheduledExecutor(groupedThreads("onos/intent", "non-disruptive-installer", log));
113 configService.registerProperties(getClass());
Yi Tsengc927a062017-05-02 15:02:37 -0700114 }
115
116 @Deactivate
117 public void deactivated() {
118 intentExtensionService.unregisterInstaller(FlowRuleIntent.class);
Antonio Marsico4f68ec92017-03-09 11:16:32 +0100119 configService.unregisterProperties(getClass(), false);
Yi Tsengc927a062017-05-02 15:02:37 -0700120 }
121
Antonio Marsico4f68ec92017-03-09 11:16:32 +0100122 @Modified
123 public void modified(ComponentContext context) {
124
125 if (context == null) {
126 nonDisruptiveInstallationWaitingTime = DEFAULT_NON_DISRUPTIVE_INSTALLATION_WAITING_TIME;
127 log.info("Restored default installation time for non-disruptive reallocation (1 sec.)");
128 return;
129 }
130
131 String s = Tools.get(context.getProperties(), "nonDisruptiveInstallationWaitingTime");
132 int nonDisruptiveTime = isNullOrEmpty(s) ? nonDisruptiveInstallationWaitingTime : Integer.parseInt(s);
133 if (nonDisruptiveTime != nonDisruptiveInstallationWaitingTime) {
134 nonDisruptiveInstallationWaitingTime = nonDisruptiveTime;
135 log.info("Reconfigured non-disruptive reallocation with installation delay {} sec.",
136 nonDisruptiveInstallationWaitingTime);
137 }
138 }
Yi Tsengc927a062017-05-02 15:02:37 -0700139
140 @Override
141 public void apply(IntentOperationContext<FlowRuleIntent> context) {
142 Optional<IntentData> toUninstall = context.toUninstall();
143 Optional<IntentData> toInstall = context.toInstall();
144
Antonio Marsico4f68ec92017-03-09 11:16:32 +0100145 if (toInstall.isPresent() && toUninstall.isPresent()) {
146 Intent intentToInstall = toInstall.get().intent();
147 if (requireNonDisruptive(intentToInstall) && INSTALLED.equals(toUninstall.get().state())) {
148 reallocate(context);
149 return;
150 }
151 }
152
Yi Tsengc927a062017-05-02 15:02:37 -0700153 if (!toInstall.isPresent() && !toUninstall.isPresent()) {
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700154 // Nothing to do.
Yi Tsengc927a062017-05-02 15:02:37 -0700155 intentInstallCoordinator.intentInstallSuccess(context);
156 return;
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700157 }
158
159 List<FlowRuleIntent> uninstallIntents = context.intentsToUninstall();
160 List<FlowRuleIntent> installIntents = context.intentsToInstall();
161
162 List<FlowRule> flowRulesToUninstall;
163 List<FlowRule> flowRulesToInstall;
164
165 if (toUninstall.isPresent()) {
166 // Remove tracked resource from both Intent and installable Intents.
Yi Tsengc927a062017-05-02 15:02:37 -0700167 trackIntentResources(toUninstall.get(), uninstallIntents, REMOVE);
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700168
169 // Retrieves all flow rules from all flow rule Intents.
170 flowRulesToUninstall = uninstallIntents.stream()
171 .map(FlowRuleIntent::flowRules)
172 .flatMap(Collection::stream)
173 .collect(Collectors.toList());
Yi Tsengc927a062017-05-02 15:02:37 -0700174 } else {
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700175 // No flow rules to be uninstalled.
176 flowRulesToUninstall = Collections.emptyList();
177 }
178
179 if (toInstall.isPresent()) {
180 // Track resource from both Intent and installable Intents.
181 trackIntentResources(toInstall.get(), installIntents, ADD);
182
183 // Retrieves all flow rules from all flow rule Intents.
184 flowRulesToInstall = installIntents.stream()
185 .map(FlowRuleIntent::flowRules)
186 .flatMap(Collection::stream)
187 .collect(Collectors.toList());
188 } else {
189 // No flow rules to be installed.
190 flowRulesToInstall = Collections.emptyList();
191 }
192
Yi Tsengc29d8822017-10-25 16:19:25 -0700193 List<FlowRule> flowRuleToModify;
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700194 List<FlowRule> dontTouch;
195
196 // If both uninstall/install list contained equal (=match conditions are equal) FlowRules,
197 // omit it from remove list, since it will/should be overwritten by install
Yi Tsengc29d8822017-10-25 16:19:25 -0700198 flowRuleToModify = flowRulesToInstall.stream()
199 .filter(flowRule -> flowRulesToUninstall.stream().anyMatch(flowRule::equals))
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700200 .collect(Collectors.toList());
201
202 // If both contained exactMatch-ing FlowRules, remove from both list,
203 // since it will result in no-op.
204 dontTouch = flowRulesToInstall.stream()
205 .filter(flowRule -> flowRulesToUninstall.stream().anyMatch(flowRule::exactMatch))
206 .collect(Collectors.toList());
207
Yi Tsengc29d8822017-10-25 16:19:25 -0700208 flowRulesToUninstall.removeAll(flowRuleToModify);
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700209 flowRulesToUninstall.removeAll(dontTouch);
Yi Tsengc29d8822017-10-25 16:19:25 -0700210 flowRulesToInstall.removeAll(flowRuleToModify);
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700211 flowRulesToInstall.removeAll(dontTouch);
Yi Tsengc29d8822017-10-25 16:19:25 -0700212 flowRuleToModify.removeAll(dontTouch);
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700213
Yi Tsengc29d8822017-10-25 16:19:25 -0700214 if (flowRulesToInstall.isEmpty() && flowRulesToUninstall.isEmpty() && flowRuleToModify.isEmpty()) {
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700215 // There is no flow rules to install/uninstall
216 intentInstallCoordinator.intentInstallSuccess(context);
217 return;
Yi Tsengc927a062017-05-02 15:02:37 -0700218 }
219
220 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700221 // Add flows
222 flowRulesToInstall.forEach(builder::add);
Yi Tsengc29d8822017-10-25 16:19:25 -0700223 // Modify flows
224 flowRuleToModify.forEach(builder::modify);
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700225 // Remove flows
226 flowRulesToUninstall.forEach(builder::remove);
Yi Tsengc927a062017-05-02 15:02:37 -0700227
228 FlowRuleOperationsContext flowRuleOperationsContext = new FlowRuleOperationsContext() {
229 @Override
230 public void onSuccess(FlowRuleOperations ops) {
231 intentInstallCoordinator.intentInstallSuccess(context);
232 }
233
234 @Override
235 public void onError(FlowRuleOperations ops) {
236 intentInstallCoordinator.intentInstallFailed(context);
237 }
238 };
239
240 FlowRuleOperations operations = builder.build(flowRuleOperationsContext);
Yi Tsengc927a062017-05-02 15:02:37 -0700241 log.debug("applying intent {} -> {} with {} rules: {}",
242 toUninstall.map(x -> x.key().toString()).orElse("<empty>"),
243 toInstall.map(x -> x.key().toString()).orElse("<empty>"),
244 operations.stages().stream().mapToLong(Set::size).sum(),
245 operations.stages());
246 flowRuleService.apply(operations);
247 }
248
Antonio Marsico4f68ec92017-03-09 11:16:32 +0100249 private void reallocate(IntentOperationContext<FlowRuleIntent> context) {
250
251 Optional<IntentData> toUninstall = context.toUninstall();
252 Optional<IntentData> toInstall = context.toInstall();
253
254 //TODO: Update the Intent store with this information
255 toInstall.get().setState(REALLOCATING);
256
257 store.write(toInstall.get());
258
259 List<FlowRuleIntent> uninstallIntents = Lists.newArrayList(context.intentsToUninstall());
260 List<FlowRuleIntent> installIntents = Lists.newArrayList(context.intentsToInstall());
261 FlowRuleOperations.Builder firstStageOperationsBuilder = FlowRuleOperations.builder();
262 List<FlowRule> secondStageFlowRules = Lists.newArrayList();
263 FlowRuleOperations.Builder thirdStageOperationsBuilder = FlowRuleOperations.builder();
264 FlowRuleOperations.Builder finalStageOperationsBuilder = FlowRuleOperations.builder();
265
266 prepareReallocation(uninstallIntents, installIntents,
267 firstStageOperationsBuilder, secondStageFlowRules,
268 thirdStageOperationsBuilder, finalStageOperationsBuilder);
269
270 trackIntentResources(toUninstall.get(), uninstallIntents, REMOVE);
271 trackIntentResources(toInstall.get(), installIntents, ADD);
272
273 CountDownLatch stageCompleteLatch = new CountDownLatch(1);
274
275 FlowRuleOperations firstStageOperations = firstStageOperationsBuilder
276 .build(new StageOperation(context, stageCompleteLatch));
277
278 flowRuleService.apply(firstStageOperations);
279
280 try {
281 stageCompleteLatch.await(nonDisruptiveInstallationWaitingTime, TimeUnit.SECONDS);
282 if (isReallocationStageFailed) {
283 log.error("Reallocation FAILED in stage one: the following FlowRuleOperations are not executed {}",
284 firstStageOperations);
285 return;
286 } else {
287 log.debug("Reallocation stage one completed");
288 }
289 } catch (Exception e) {
290 log.warn("Latch exception in the reallocation stage one");
291 }
292
293 for (FlowRule flowRule : secondStageFlowRules) {
294 stageCompleteLatch = new CountDownLatch(1);
295 FlowRuleOperations operations = FlowRuleOperations.builder()
296 .newStage()
297 .remove(flowRule)
298 .build(new StageOperation(context, stageCompleteLatch));
299 nonDisruptiveIntentInstaller.schedule(new NonDisruptiveInstallation(operations),
300 nonDisruptiveInstallationWaitingTime,
301 TimeUnit.SECONDS);
302 try {
303 stageCompleteLatch.await(nonDisruptiveInstallationWaitingTime, TimeUnit.SECONDS);
304 if (isReallocationStageFailed) {
305 log.error("Reallocation FAILED in stage two: " +
306 "the following FlowRuleOperations are not executed {}",
307 operations);
308 return;
309 } else {
310 log.debug("Reallocation stage two completed");
311 }
312 } catch (Exception e) {
313 log.warn("Latch exception in the reallocation stage two");
314 }
315 }
316
317 stageCompleteLatch = new CountDownLatch(1);
318 FlowRuleOperations thirdStageOperations = thirdStageOperationsBuilder
319 .build(new StageOperation(context, stageCompleteLatch));
320
321 nonDisruptiveIntentInstaller.schedule(new NonDisruptiveInstallation(thirdStageOperations),
322 nonDisruptiveInstallationWaitingTime,
323 TimeUnit.SECONDS);
324 try {
325 stageCompleteLatch.await(nonDisruptiveInstallationWaitingTime, TimeUnit.SECONDS);
326 if (isReallocationStageFailed) {
327 log.error("Reallocation FAILED in stage three: " +
328 "the following FlowRuleOperations are not executed {}",
329 thirdStageOperations);
330 return;
331 } else {
332 log.debug("Reallocation stage three completed");
333 }
334 } catch (Exception e) {
335 log.warn("Latch exception in the reallocation stage three");
336 }
337
338 FlowRuleOperationsContext flowRuleOperationsContext = new FlowRuleOperationsContext() {
339 @Override
340 public void onSuccess(FlowRuleOperations ops) {
341 intentInstallCoordinator.intentInstallSuccess(context);
342 log.info("Non-disruptive reallocation completed for intent {}", toInstall.get().key());
343 }
344
345 @Override
346 public void onError(FlowRuleOperations ops) {
347 intentInstallCoordinator.intentInstallFailed(context);
348 }
349 };
350
351 FlowRuleOperations finalStageOperations = finalStageOperationsBuilder.build(flowRuleOperationsContext);
352 flowRuleService.apply(finalStageOperations);
353 }
354
355 /**
356 * This method prepares the {@link FlowRule} required for every reallocation stage.
357 * <p>Stage 1: the FlowRules of the new path are installed,
358 * with a lower priority only on the devices shared with the old path;</p>
359 * <p>Stage 2: the FlowRules of the old path are removed from the ingress to the egress points,
360 * only in the shared devices;</p>
361 * <p>Stage 3: the FlowRules with a lower priority are restored to the original one;</p>
362 * <p>Stage 4: the remaining FlowRules of the old path are deleted.</p>
363 *
364 * @param uninstallIntents the previous FlowRuleIntent
365 * @param installIntents the new FlowRuleIntent to be installed
366 * @param firstStageBuilder the first stage operation builder
367 * @param secondStageFlowRules the second stage FlowRules
368 * @param thirdStageBuilder the third stage operation builder
369 * @param finalStageBuilder the last stage operation builder
370 */
371 private void prepareReallocation(List<FlowRuleIntent> uninstallIntents, List<FlowRuleIntent> installIntents,
372 FlowRuleOperations.Builder firstStageBuilder,
373 List<FlowRule> secondStageFlowRules,
374 FlowRuleOperations.Builder thirdStageBuilder,
375 FlowRuleOperations.Builder finalStageBuilder) {
376
377
378 // Filter out same intents and intents with same flow rules
379 installIntents.forEach(installIntent -> {
380 uninstallIntents.forEach(uninstallIntent -> {
381
382 List<FlowRule> uninstallFlowRules = Lists.newArrayList(uninstallIntent.flowRules());
383 List<FlowRule> installFlowRules = Lists.newArrayList(installIntent.flowRules());
384
385 List<FlowRule> secondStageRules = Lists.newArrayList();
386 List<FlowRule> thirdStageRules = Lists.newArrayList();
387
388 List<DeviceId> orderedDeviceList = createIngressToEgressDeviceList(installIntent.resources());
389
390 uninstallIntent.flowRules().forEach(flowRuleToUnistall -> {
391 installIntent.flowRules().forEach(flowRuleToInstall -> {
392
393 if (flowRuleToInstall.exactMatch(flowRuleToUnistall)) {
394 //The FlowRules are in common (i.e., we are sharing the path)
395 uninstallFlowRules.remove(flowRuleToInstall);
396 installFlowRules.remove(flowRuleToInstall);
397 } else if (flowRuleToInstall.deviceId().equals(flowRuleToUnistall.deviceId())) {
398 //FlowRules that have a device in common but
399 // different treatment/selector (i.e., overlapping path)
400 FlowRule flowRuleWithLowerPriority = DefaultFlowRule.builder()
401 .withPriority(flowRuleToInstall.priority() - 1)
402 .withSelector(flowRuleToInstall.selector())
403 .forDevice(flowRuleToInstall.deviceId())
404 .makePermanent()
405 .withTreatment(flowRuleToInstall.treatment())
406 .fromApp(new DefaultApplicationId(flowRuleToInstall.appId(),
407 "org.onosproject.net.intent"))
408 .build();
409
410 //Update the FlowRule to be installed with one with a lower priority
411 installFlowRules.remove(flowRuleToInstall);
412 installFlowRules.add(flowRuleWithLowerPriority);
413
414 //Add the FlowRule to be uninstalled to the second stage of non-disruptive update
415 secondStageRules.add(flowRuleToUnistall);
416 uninstallFlowRules.remove(flowRuleToUnistall);
417
418 thirdStageRules.add(flowRuleToInstall);
419 uninstallFlowRules.add(flowRuleWithLowerPriority);
420 }
421 });
422 });
423
424 firstStageBuilder.newStage();
425 installFlowRules.forEach(firstStageBuilder::add);
426
427 Collections.sort(secondStageRules, new SecondStageComparator(orderedDeviceList));
428 secondStageFlowRules.addAll(secondStageRules);
429
430 thirdStageBuilder.newStage();
431 thirdStageRules.forEach(thirdStageBuilder::add);
432
433 finalStageBuilder.newStage();
434 uninstallFlowRules.forEach(finalStageBuilder::remove);
435 });
436 });
437
438 }
439
440 private class StageOperation implements FlowRuleOperationsContext {
441
442 private IntentOperationContext<FlowRuleIntent> context;
443 private CountDownLatch stageCompleteLatch;
444
445 public StageOperation(IntentOperationContext<FlowRuleIntent> context, CountDownLatch stageCompleteLatch) {
446 this.context = context;
447 this.stageCompleteLatch = stageCompleteLatch;
448 isReallocationStageFailed = false;
449 }
450
451 @Override
452 public void onSuccess(FlowRuleOperations ops) {
453 stageCompleteLatch.countDown();
454 log.debug("FlowRuleOperations correctly completed");
455 }
456
457 @Override
458 public void onError(FlowRuleOperations ops) {
459 intentInstallCoordinator.intentInstallFailed(context);
460 isReallocationStageFailed = true;
461 stageCompleteLatch.countDown();
462 log.debug("Installation error for {}", ops);
463 }
464 }
465
466 private final class SecondStageComparator implements Comparator<FlowRule> {
467
468 private List<DeviceId> deviceIds;
469
470 private SecondStageComparator(List<DeviceId> deviceIds) {
471 this.deviceIds = deviceIds;
472 }
473
474 @Override
475 public int compare(FlowRule o1, FlowRule o2) {
476 Integer index1 = deviceIds.indexOf(o1.deviceId());
477 Integer index2 = deviceIds.indexOf(o2.deviceId());
478 return index1.compareTo(index2);
479 }
480 }
481
482 /**
483 * Create a list of devices ordered from the ingress to the egress of a path.
484 * @param resources the resources of the intent
485 * @return a list of devices
486 */
487 private List<DeviceId> createIngressToEgressDeviceList(Collection<NetworkResource> resources) {
488 List<DeviceId> deviceIds = Lists.newArrayList();
489 List<Link> links = Lists.newArrayList();
490
491 for (NetworkResource resource : resources) {
492 if (resource instanceof Link) {
493 Link linkToAdd = (Link) resource;
494 if (linkToAdd.type() != Link.Type.EDGE) {
495 links.add(linkToAdd);
496 }
497 }
498 }
499
500 Collections.sort(links, LINK_COMPARATOR);
501
502 int i = 0;
503 for (Link orderedLink : links) {
504 deviceIds.add(orderedLink.src().deviceId());
505 if (i == resources.size() - 1) {
506 deviceIds.add(orderedLink.dst().deviceId());
507 }
508 i++;
509 }
510
511 return deviceIds;
512 }
513
514 /**
515 * Compares two links in order to find which one is before or after the other.
516 */
517 private static class LinkComparator implements Comparator<Link> {
518
519 @Override
520 public int compare(Link l1, Link l2) {
521
522 //l1 is before l2
523 if (l1.dst().deviceId() == l2.src().deviceId()) {
524 return -1;
525 }
526
527 //l1 is after l2
528 if (l1.src().deviceId() == l2.dst().deviceId()) {
529 return 1;
530 }
531
532 //l2 and l1 are not connected to a common device
533 return 0;
534 }
535 }
536
537 private final class NonDisruptiveInstallation implements Runnable {
538
539 private FlowRuleOperations op;
540
541 private NonDisruptiveInstallation(FlowRuleOperations op) {
542 this.op = op;
543 }
544 @Override
545 public void run() {
546 flowRuleService.apply(this.op);
547 }
548 }
549
Yi Tsengc927a062017-05-02 15:02:37 -0700550 /**
551 * Track or un-track network resource of a Intent and it's installable
552 * Intents.
553 *
554 * @param intentData the Intent data
555 * @param intentsToApply the list of flow rule Intents from the Intent
556 * @param direction the direction to determine track or un-track
557 */
558 private void trackIntentResources(IntentData intentData, List<FlowRuleIntent> intentsToApply, Direction direction) {
559 switch (direction) {
560 case ADD:
561 trackerService.addTrackedResources(intentData.key(), intentData.intent().resources());
562 intentsToApply.forEach(installable ->
563 trackerService.addTrackedResources(intentData.key(),
564 installable.resources()));
565 break;
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700566 case REMOVE:
Yi Tsengc927a062017-05-02 15:02:37 -0700567 trackerService.removeTrackedResources(intentData.key(), intentData.intent().resources());
568 intentsToApply.forEach(installable ->
569 trackerService.removeTrackedResources(intentData.intent().key(),
570 installable.resources()));
571 break;
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700572 default:
573 log.warn("Unknown resource tracking direction.");
574 break;
Yi Tsengc927a062017-05-02 15:02:37 -0700575 }
576 }
Yi Tsengc927a062017-05-02 15:02:37 -0700577}