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