blob: 8f31d9a96b964c5ef3da3b3e741d16938960afc5 [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;
Ray Milkeyd04e2272018-10-16 18:20:18 -070064import static org.onosproject.net.OsgiPropertyConstants.NON_DISRUPTIVE_INSTALLATION_WAITING_TIME;
65import static org.onosproject.net.OsgiPropertyConstants.NON_DISRUPTIVE_INSTALLATION_WAITING_TIME_DEFAULT;
Yi Tsengc927a062017-05-02 15:02:37 -070066import static org.onosproject.net.intent.IntentInstaller.Direction.ADD;
67import static org.onosproject.net.intent.IntentInstaller.Direction.REMOVE;
Antonio Marsico4f68ec92017-03-09 11:16:32 +010068import static org.onosproject.net.intent.IntentState.INSTALLED;
69import static org.onosproject.net.intent.IntentState.REALLOCATING;
70import static org.onosproject.net.intent.constraint.NonDisruptiveConstraint.requireNonDisruptive;
Yi Tsengc927a062017-05-02 15:02:37 -070071import static org.slf4j.LoggerFactory.getLogger;
72
73/**
74 * Installer for FlowRuleIntent.
75 */
Ray Milkeyd04e2272018-10-16 18:20:18 -070076@Component(
77 immediate = true,
78 property = {
Ray Milkey2d7bca12018-10-17 14:51:52 -070079 NON_DISRUPTIVE_INSTALLATION_WAITING_TIME + ":Integer=" + NON_DISRUPTIVE_INSTALLATION_WAITING_TIME_DEFAULT
Ray Milkeyd04e2272018-10-16 18:20:18 -070080 }
81)
Yi Tsengc927a062017-05-02 15:02:37 -070082public class FlowRuleIntentInstaller implements IntentInstaller<FlowRuleIntent> {
Ray Milkeyd84f89b2018-08-17 14:54:17 -070083 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tsengc927a062017-05-02 15:02:37 -070084 protected IntentExtensionService intentExtensionService;
85
Ray Milkeyd84f89b2018-08-17 14:54:17 -070086 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tsengc927a062017-05-02 15:02:37 -070087 protected ObjectiveTrackerService trackerService;
88
Ray Milkeyd84f89b2018-08-17 14:54:17 -070089 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tsengc927a062017-05-02 15:02:37 -070090 protected IntentInstallCoordinator intentInstallCoordinator;
91
Ray Milkeyd84f89b2018-08-17 14:54:17 -070092 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tsengc927a062017-05-02 15:02:37 -070093 protected FlowRuleService flowRuleService;
94
Ray Milkeyd84f89b2018-08-17 14:54:17 -070095 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Antonio Marsico4f68ec92017-03-09 11:16:32 +010096 protected ComponentConfigService configService;
97
Ray Milkeyd84f89b2018-08-17 14:54:17 -070098 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Antonio Marsico4f68ec92017-03-09 11:16:32 +010099 protected IntentStore store;
100
101 private ScheduledExecutorService nonDisruptiveIntentInstaller;
102
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700103 //@Property(name = "nonDisruptiveInstallationWaitingTime",
104 // intValue = DEFAULT_NON_DISRUPTIVE_INSTALLATION_WAITING_TIME,
105 // label = "Number of seconds to wait during the non-disruptive installation phases")
Ray Milkeyd04e2272018-10-16 18:20:18 -0700106 private int nonDisruptiveInstallationWaitingTime = NON_DISRUPTIVE_INSTALLATION_WAITING_TIME_DEFAULT;
Antonio Marsico4f68ec92017-03-09 11:16:32 +0100107
108 protected final Logger log = getLogger(IntentManager.class);
109
110 private boolean isReallocationStageFailed = false;
111
112 private static final LinkComparator LINK_COMPARATOR = new LinkComparator();
113
Yi Tsengc927a062017-05-02 15:02:37 -0700114 @Activate
115 public void activate() {
116 intentExtensionService.registerInstaller(FlowRuleIntent.class, this);
Antonio Marsico4f68ec92017-03-09 11:16:32 +0100117 nonDisruptiveIntentInstaller =
118 newSingleThreadScheduledExecutor(groupedThreads("onos/intent", "non-disruptive-installer", log));
119 configService.registerProperties(getClass());
Yi Tsengc927a062017-05-02 15:02:37 -0700120 }
121
122 @Deactivate
123 public void deactivated() {
124 intentExtensionService.unregisterInstaller(FlowRuleIntent.class);
Antonio Marsico4f68ec92017-03-09 11:16:32 +0100125 configService.unregisterProperties(getClass(), false);
Yi Tsengc927a062017-05-02 15:02:37 -0700126 }
127
Antonio Marsico4f68ec92017-03-09 11:16:32 +0100128 @Modified
129 public void modified(ComponentContext context) {
130
131 if (context == null) {
Ray Milkeyd04e2272018-10-16 18:20:18 -0700132 nonDisruptiveInstallationWaitingTime = NON_DISRUPTIVE_INSTALLATION_WAITING_TIME_DEFAULT;
Antonio Marsico4f68ec92017-03-09 11:16:32 +0100133 log.info("Restored default installation time for non-disruptive reallocation (1 sec.)");
134 return;
135 }
136
137 String s = Tools.get(context.getProperties(), "nonDisruptiveInstallationWaitingTime");
138 int nonDisruptiveTime = isNullOrEmpty(s) ? nonDisruptiveInstallationWaitingTime : Integer.parseInt(s);
139 if (nonDisruptiveTime != nonDisruptiveInstallationWaitingTime) {
140 nonDisruptiveInstallationWaitingTime = nonDisruptiveTime;
141 log.info("Reconfigured non-disruptive reallocation with installation delay {} sec.",
142 nonDisruptiveInstallationWaitingTime);
143 }
144 }
Yi Tsengc927a062017-05-02 15:02:37 -0700145
146 @Override
147 public void apply(IntentOperationContext<FlowRuleIntent> context) {
148 Optional<IntentData> toUninstall = context.toUninstall();
149 Optional<IntentData> toInstall = context.toInstall();
150
Antonio Marsico4f68ec92017-03-09 11:16:32 +0100151 if (toInstall.isPresent() && toUninstall.isPresent()) {
152 Intent intentToInstall = toInstall.get().intent();
153 if (requireNonDisruptive(intentToInstall) && INSTALLED.equals(toUninstall.get().state())) {
154 reallocate(context);
155 return;
156 }
157 }
158
Yi Tsengc927a062017-05-02 15:02:37 -0700159 if (!toInstall.isPresent() && !toUninstall.isPresent()) {
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700160 // Nothing to do.
Yi Tsengc927a062017-05-02 15:02:37 -0700161 intentInstallCoordinator.intentInstallSuccess(context);
162 return;
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700163 }
164
165 List<FlowRuleIntent> uninstallIntents = context.intentsToUninstall();
166 List<FlowRuleIntent> installIntents = context.intentsToInstall();
167
168 List<FlowRule> flowRulesToUninstall;
169 List<FlowRule> flowRulesToInstall;
170
171 if (toUninstall.isPresent()) {
172 // Remove tracked resource from both Intent and installable Intents.
Yi Tsengc927a062017-05-02 15:02:37 -0700173 trackIntentResources(toUninstall.get(), uninstallIntents, REMOVE);
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700174
175 // Retrieves all flow rules from all flow rule Intents.
176 flowRulesToUninstall = uninstallIntents.stream()
177 .map(FlowRuleIntent::flowRules)
178 .flatMap(Collection::stream)
179 .collect(Collectors.toList());
Yi Tsengc927a062017-05-02 15:02:37 -0700180 } else {
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700181 // No flow rules to be uninstalled.
182 flowRulesToUninstall = Collections.emptyList();
183 }
184
185 if (toInstall.isPresent()) {
186 // Track resource from both Intent and installable Intents.
187 trackIntentResources(toInstall.get(), installIntents, ADD);
188
189 // Retrieves all flow rules from all flow rule Intents.
190 flowRulesToInstall = installIntents.stream()
191 .map(FlowRuleIntent::flowRules)
192 .flatMap(Collection::stream)
193 .collect(Collectors.toList());
194 } else {
195 // No flow rules to be installed.
196 flowRulesToInstall = Collections.emptyList();
197 }
198
Yi Tsengc29d8822017-10-25 16:19:25 -0700199 List<FlowRule> flowRuleToModify;
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700200 List<FlowRule> dontTouch;
201
202 // If both uninstall/install list contained equal (=match conditions are equal) FlowRules,
203 // omit it from remove list, since it will/should be overwritten by install
Yi Tsengc29d8822017-10-25 16:19:25 -0700204 flowRuleToModify = flowRulesToInstall.stream()
205 .filter(flowRule -> flowRulesToUninstall.stream().anyMatch(flowRule::equals))
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700206 .collect(Collectors.toList());
207
208 // If both contained exactMatch-ing FlowRules, remove from both list,
209 // since it will result in no-op.
210 dontTouch = flowRulesToInstall.stream()
211 .filter(flowRule -> flowRulesToUninstall.stream().anyMatch(flowRule::exactMatch))
212 .collect(Collectors.toList());
213
Yi Tsengc29d8822017-10-25 16:19:25 -0700214 flowRulesToUninstall.removeAll(flowRuleToModify);
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700215 flowRulesToUninstall.removeAll(dontTouch);
Yi Tsengc29d8822017-10-25 16:19:25 -0700216 flowRulesToInstall.removeAll(flowRuleToModify);
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700217 flowRulesToInstall.removeAll(dontTouch);
Yi Tsengc29d8822017-10-25 16:19:25 -0700218 flowRuleToModify.removeAll(dontTouch);
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700219
Yi Tsengc29d8822017-10-25 16:19:25 -0700220 if (flowRulesToInstall.isEmpty() && flowRulesToUninstall.isEmpty() && flowRuleToModify.isEmpty()) {
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700221 // There is no flow rules to install/uninstall
222 intentInstallCoordinator.intentInstallSuccess(context);
223 return;
Yi Tsengc927a062017-05-02 15:02:37 -0700224 }
225
226 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700227 // Add flows
228 flowRulesToInstall.forEach(builder::add);
Yi Tsengc29d8822017-10-25 16:19:25 -0700229 // Modify flows
230 flowRuleToModify.forEach(builder::modify);
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700231 // Remove flows
232 flowRulesToUninstall.forEach(builder::remove);
Yi Tsengc927a062017-05-02 15:02:37 -0700233
234 FlowRuleOperationsContext flowRuleOperationsContext = new FlowRuleOperationsContext() {
235 @Override
236 public void onSuccess(FlowRuleOperations ops) {
237 intentInstallCoordinator.intentInstallSuccess(context);
238 }
239
240 @Override
241 public void onError(FlowRuleOperations ops) {
242 intentInstallCoordinator.intentInstallFailed(context);
243 }
244 };
245
246 FlowRuleOperations operations = builder.build(flowRuleOperationsContext);
Yi Tsengc927a062017-05-02 15:02:37 -0700247 log.debug("applying intent {} -> {} with {} rules: {}",
248 toUninstall.map(x -> x.key().toString()).orElse("<empty>"),
249 toInstall.map(x -> x.key().toString()).orElse("<empty>"),
250 operations.stages().stream().mapToLong(Set::size).sum(),
251 operations.stages());
252 flowRuleService.apply(operations);
253 }
254
Antonio Marsico4f68ec92017-03-09 11:16:32 +0100255 private void reallocate(IntentOperationContext<FlowRuleIntent> context) {
256
257 Optional<IntentData> toUninstall = context.toUninstall();
258 Optional<IntentData> toInstall = context.toInstall();
259
260 //TODO: Update the Intent store with this information
261 toInstall.get().setState(REALLOCATING);
262
263 store.write(toInstall.get());
264
265 List<FlowRuleIntent> uninstallIntents = Lists.newArrayList(context.intentsToUninstall());
266 List<FlowRuleIntent> installIntents = Lists.newArrayList(context.intentsToInstall());
267 FlowRuleOperations.Builder firstStageOperationsBuilder = FlowRuleOperations.builder();
268 List<FlowRule> secondStageFlowRules = Lists.newArrayList();
269 FlowRuleOperations.Builder thirdStageOperationsBuilder = FlowRuleOperations.builder();
270 FlowRuleOperations.Builder finalStageOperationsBuilder = FlowRuleOperations.builder();
271
272 prepareReallocation(uninstallIntents, installIntents,
273 firstStageOperationsBuilder, secondStageFlowRules,
274 thirdStageOperationsBuilder, finalStageOperationsBuilder);
275
276 trackIntentResources(toUninstall.get(), uninstallIntents, REMOVE);
277 trackIntentResources(toInstall.get(), installIntents, ADD);
278
279 CountDownLatch stageCompleteLatch = new CountDownLatch(1);
280
281 FlowRuleOperations firstStageOperations = firstStageOperationsBuilder
282 .build(new StageOperation(context, stageCompleteLatch));
283
284 flowRuleService.apply(firstStageOperations);
285
286 try {
287 stageCompleteLatch.await(nonDisruptiveInstallationWaitingTime, TimeUnit.SECONDS);
288 if (isReallocationStageFailed) {
289 log.error("Reallocation FAILED in stage one: the following FlowRuleOperations are not executed {}",
290 firstStageOperations);
291 return;
292 } else {
293 log.debug("Reallocation stage one completed");
294 }
295 } catch (Exception e) {
296 log.warn("Latch exception in the reallocation stage one");
297 }
298
299 for (FlowRule flowRule : secondStageFlowRules) {
300 stageCompleteLatch = new CountDownLatch(1);
301 FlowRuleOperations operations = FlowRuleOperations.builder()
302 .newStage()
303 .remove(flowRule)
304 .build(new StageOperation(context, stageCompleteLatch));
305 nonDisruptiveIntentInstaller.schedule(new NonDisruptiveInstallation(operations),
306 nonDisruptiveInstallationWaitingTime,
307 TimeUnit.SECONDS);
308 try {
309 stageCompleteLatch.await(nonDisruptiveInstallationWaitingTime, TimeUnit.SECONDS);
310 if (isReallocationStageFailed) {
311 log.error("Reallocation FAILED in stage two: " +
312 "the following FlowRuleOperations are not executed {}",
313 operations);
314 return;
315 } else {
316 log.debug("Reallocation stage two completed");
317 }
318 } catch (Exception e) {
319 log.warn("Latch exception in the reallocation stage two");
320 }
321 }
322
323 stageCompleteLatch = new CountDownLatch(1);
324 FlowRuleOperations thirdStageOperations = thirdStageOperationsBuilder
325 .build(new StageOperation(context, stageCompleteLatch));
326
327 nonDisruptiveIntentInstaller.schedule(new NonDisruptiveInstallation(thirdStageOperations),
328 nonDisruptiveInstallationWaitingTime,
329 TimeUnit.SECONDS);
330 try {
331 stageCompleteLatch.await(nonDisruptiveInstallationWaitingTime, TimeUnit.SECONDS);
332 if (isReallocationStageFailed) {
333 log.error("Reallocation FAILED in stage three: " +
334 "the following FlowRuleOperations are not executed {}",
335 thirdStageOperations);
336 return;
337 } else {
338 log.debug("Reallocation stage three completed");
339 }
340 } catch (Exception e) {
341 log.warn("Latch exception in the reallocation stage three");
342 }
343
344 FlowRuleOperationsContext flowRuleOperationsContext = new FlowRuleOperationsContext() {
345 @Override
346 public void onSuccess(FlowRuleOperations ops) {
347 intentInstallCoordinator.intentInstallSuccess(context);
348 log.info("Non-disruptive reallocation completed for intent {}", toInstall.get().key());
349 }
350
351 @Override
352 public void onError(FlowRuleOperations ops) {
353 intentInstallCoordinator.intentInstallFailed(context);
354 }
355 };
356
357 FlowRuleOperations finalStageOperations = finalStageOperationsBuilder.build(flowRuleOperationsContext);
358 flowRuleService.apply(finalStageOperations);
359 }
360
361 /**
362 * This method prepares the {@link FlowRule} required for every reallocation stage.
363 * <p>Stage 1: the FlowRules of the new path are installed,
364 * with a lower priority only on the devices shared with the old path;</p>
365 * <p>Stage 2: the FlowRules of the old path are removed from the ingress to the egress points,
366 * only in the shared devices;</p>
367 * <p>Stage 3: the FlowRules with a lower priority are restored to the original one;</p>
368 * <p>Stage 4: the remaining FlowRules of the old path are deleted.</p>
369 *
370 * @param uninstallIntents the previous FlowRuleIntent
371 * @param installIntents the new FlowRuleIntent to be installed
372 * @param firstStageBuilder the first stage operation builder
373 * @param secondStageFlowRules the second stage FlowRules
374 * @param thirdStageBuilder the third stage operation builder
375 * @param finalStageBuilder the last stage operation builder
376 */
377 private void prepareReallocation(List<FlowRuleIntent> uninstallIntents, List<FlowRuleIntent> installIntents,
378 FlowRuleOperations.Builder firstStageBuilder,
379 List<FlowRule> secondStageFlowRules,
380 FlowRuleOperations.Builder thirdStageBuilder,
381 FlowRuleOperations.Builder finalStageBuilder) {
382
383
384 // Filter out same intents and intents with same flow rules
385 installIntents.forEach(installIntent -> {
386 uninstallIntents.forEach(uninstallIntent -> {
387
388 List<FlowRule> uninstallFlowRules = Lists.newArrayList(uninstallIntent.flowRules());
389 List<FlowRule> installFlowRules = Lists.newArrayList(installIntent.flowRules());
390
391 List<FlowRule> secondStageRules = Lists.newArrayList();
392 List<FlowRule> thirdStageRules = Lists.newArrayList();
393
394 List<DeviceId> orderedDeviceList = createIngressToEgressDeviceList(installIntent.resources());
395
396 uninstallIntent.flowRules().forEach(flowRuleToUnistall -> {
397 installIntent.flowRules().forEach(flowRuleToInstall -> {
398
399 if (flowRuleToInstall.exactMatch(flowRuleToUnistall)) {
400 //The FlowRules are in common (i.e., we are sharing the path)
401 uninstallFlowRules.remove(flowRuleToInstall);
402 installFlowRules.remove(flowRuleToInstall);
403 } else if (flowRuleToInstall.deviceId().equals(flowRuleToUnistall.deviceId())) {
404 //FlowRules that have a device in common but
405 // different treatment/selector (i.e., overlapping path)
406 FlowRule flowRuleWithLowerPriority = DefaultFlowRule.builder()
407 .withPriority(flowRuleToInstall.priority() - 1)
408 .withSelector(flowRuleToInstall.selector())
409 .forDevice(flowRuleToInstall.deviceId())
410 .makePermanent()
411 .withTreatment(flowRuleToInstall.treatment())
412 .fromApp(new DefaultApplicationId(flowRuleToInstall.appId(),
413 "org.onosproject.net.intent"))
414 .build();
415
416 //Update the FlowRule to be installed with one with a lower priority
417 installFlowRules.remove(flowRuleToInstall);
418 installFlowRules.add(flowRuleWithLowerPriority);
419
420 //Add the FlowRule to be uninstalled to the second stage of non-disruptive update
421 secondStageRules.add(flowRuleToUnistall);
422 uninstallFlowRules.remove(flowRuleToUnistall);
423
424 thirdStageRules.add(flowRuleToInstall);
425 uninstallFlowRules.add(flowRuleWithLowerPriority);
426 }
427 });
428 });
429
430 firstStageBuilder.newStage();
431 installFlowRules.forEach(firstStageBuilder::add);
432
433 Collections.sort(secondStageRules, new SecondStageComparator(orderedDeviceList));
434 secondStageFlowRules.addAll(secondStageRules);
435
436 thirdStageBuilder.newStage();
437 thirdStageRules.forEach(thirdStageBuilder::add);
438
439 finalStageBuilder.newStage();
440 uninstallFlowRules.forEach(finalStageBuilder::remove);
441 });
442 });
443
444 }
445
446 private class StageOperation implements FlowRuleOperationsContext {
447
448 private IntentOperationContext<FlowRuleIntent> context;
449 private CountDownLatch stageCompleteLatch;
450
451 public StageOperation(IntentOperationContext<FlowRuleIntent> context, CountDownLatch stageCompleteLatch) {
452 this.context = context;
453 this.stageCompleteLatch = stageCompleteLatch;
454 isReallocationStageFailed = false;
455 }
456
457 @Override
458 public void onSuccess(FlowRuleOperations ops) {
459 stageCompleteLatch.countDown();
460 log.debug("FlowRuleOperations correctly completed");
461 }
462
463 @Override
464 public void onError(FlowRuleOperations ops) {
465 intentInstallCoordinator.intentInstallFailed(context);
466 isReallocationStageFailed = true;
467 stageCompleteLatch.countDown();
468 log.debug("Installation error for {}", ops);
469 }
470 }
471
472 private final class SecondStageComparator implements Comparator<FlowRule> {
473
474 private List<DeviceId> deviceIds;
475
476 private SecondStageComparator(List<DeviceId> deviceIds) {
477 this.deviceIds = deviceIds;
478 }
479
480 @Override
481 public int compare(FlowRule o1, FlowRule o2) {
482 Integer index1 = deviceIds.indexOf(o1.deviceId());
483 Integer index2 = deviceIds.indexOf(o2.deviceId());
484 return index1.compareTo(index2);
485 }
486 }
487
488 /**
489 * Create a list of devices ordered from the ingress to the egress of a path.
490 * @param resources the resources of the intent
491 * @return a list of devices
492 */
493 private List<DeviceId> createIngressToEgressDeviceList(Collection<NetworkResource> resources) {
494 List<DeviceId> deviceIds = Lists.newArrayList();
495 List<Link> links = Lists.newArrayList();
496
497 for (NetworkResource resource : resources) {
498 if (resource instanceof Link) {
499 Link linkToAdd = (Link) resource;
500 if (linkToAdd.type() != Link.Type.EDGE) {
501 links.add(linkToAdd);
502 }
503 }
504 }
505
506 Collections.sort(links, LINK_COMPARATOR);
507
508 int i = 0;
509 for (Link orderedLink : links) {
510 deviceIds.add(orderedLink.src().deviceId());
511 if (i == resources.size() - 1) {
512 deviceIds.add(orderedLink.dst().deviceId());
513 }
514 i++;
515 }
516
517 return deviceIds;
518 }
519
520 /**
521 * Compares two links in order to find which one is before or after the other.
522 */
523 private static class LinkComparator implements Comparator<Link> {
524
525 @Override
526 public int compare(Link l1, Link l2) {
527
528 //l1 is before l2
529 if (l1.dst().deviceId() == l2.src().deviceId()) {
530 return -1;
531 }
532
533 //l1 is after l2
534 if (l1.src().deviceId() == l2.dst().deviceId()) {
535 return 1;
536 }
537
538 //l2 and l1 are not connected to a common device
539 return 0;
540 }
541 }
542
543 private final class NonDisruptiveInstallation implements Runnable {
544
545 private FlowRuleOperations op;
546
547 private NonDisruptiveInstallation(FlowRuleOperations op) {
548 this.op = op;
549 }
550 @Override
551 public void run() {
552 flowRuleService.apply(this.op);
553 }
554 }
555
Yi Tsengc927a062017-05-02 15:02:37 -0700556 /**
557 * Track or un-track network resource of a Intent and it's installable
558 * Intents.
559 *
560 * @param intentData the Intent data
561 * @param intentsToApply the list of flow rule Intents from the Intent
562 * @param direction the direction to determine track or un-track
563 */
564 private void trackIntentResources(IntentData intentData, List<FlowRuleIntent> intentsToApply, Direction direction) {
565 switch (direction) {
566 case ADD:
567 trackerService.addTrackedResources(intentData.key(), intentData.intent().resources());
568 intentsToApply.forEach(installable ->
569 trackerService.addTrackedResources(intentData.key(),
570 installable.resources()));
571 break;
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700572 case REMOVE:
Yi Tsengc927a062017-05-02 15:02:37 -0700573 trackerService.removeTrackedResources(intentData.key(), intentData.intent().resources());
574 intentsToApply.forEach(installable ->
575 trackerService.removeTrackedResources(intentData.intent().key(),
576 installable.resources()));
577 break;
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700578 default:
579 log.warn("Unknown resource tracking direction.");
580 break;
Yi Tsengc927a062017-05-02 15:02:37 -0700581 }
582 }
Yi Tsengc927a062017-05-02 15:02:37 -0700583}