blob: d96de2f42062c7c359ea85b57e73c319b716ea59 [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;
Yi Tsengc927a062017-05-02 15:02:37 -070020import org.apache.felix.scr.annotations.Activate;
21import org.apache.felix.scr.annotations.Component;
22import org.apache.felix.scr.annotations.Deactivate;
Antonio Marsico4f68ec92017-03-09 11:16:32 +010023import org.apache.felix.scr.annotations.Modified;
24import org.apache.felix.scr.annotations.Property;
Yi Tsengc927a062017-05-02 15:02:37 -070025import org.apache.felix.scr.annotations.Reference;
26import org.apache.felix.scr.annotations.ReferenceCardinality;
Antonio Marsico4f68ec92017-03-09 11:16:32 +010027import org.onlab.util.Tools;
28import org.onosproject.cfg.ComponentConfigService;
29import org.onosproject.core.DefaultApplicationId;
30import org.onosproject.net.DeviceId;
31import org.onosproject.net.Link;
32import org.onosproject.net.NetworkResource;
33import org.onosproject.net.flow.DefaultFlowRule;
Yi Tsengc927a062017-05-02 15:02:37 -070034import org.onosproject.net.flow.FlowRule;
35import org.onosproject.net.flow.FlowRuleOperations;
36import org.onosproject.net.flow.FlowRuleOperationsContext;
37import org.onosproject.net.flow.FlowRuleService;
38import org.onosproject.net.intent.FlowRuleIntent;
Antonio Marsico4f68ec92017-03-09 11:16:32 +010039import org.onosproject.net.intent.Intent;
Yi Tsengc927a062017-05-02 15:02:37 -070040import org.onosproject.net.intent.IntentData;
41import org.onosproject.net.intent.IntentExtensionService;
Antonio Marsico4f68ec92017-03-09 11:16:32 +010042import org.onosproject.net.intent.IntentInstallCoordinator;
Yi Tsengc927a062017-05-02 15:02:37 -070043import org.onosproject.net.intent.IntentInstaller;
Antonio Marsico4f68ec92017-03-09 11:16:32 +010044import org.onosproject.net.intent.IntentOperationContext;
45import org.onosproject.net.intent.IntentStore;
Yi Tseng24d9be72017-05-12 11:28:13 -070046import org.onosproject.net.intent.ObjectiveTrackerService;
Antonio Marsico4f68ec92017-03-09 11:16:32 +010047import org.onosproject.net.intent.impl.IntentManager;
48import org.osgi.service.component.ComponentContext;
Yi Tsengc927a062017-05-02 15:02:37 -070049import org.slf4j.Logger;
50
51import java.util.Collection;
Yi Tseng4a7d1e12017-07-10 16:19:17 -070052import java.util.Collections;
Antonio Marsico4f68ec92017-03-09 11:16:32 +010053import java.util.Comparator;
Yi Tsengc927a062017-05-02 15:02:37 -070054import java.util.List;
55import java.util.Optional;
56import java.util.Set;
Antonio Marsico4f68ec92017-03-09 11:16:32 +010057import java.util.concurrent.CountDownLatch;
58import java.util.concurrent.ScheduledExecutorService;
59import java.util.concurrent.TimeUnit;
Yi Tseng4a7d1e12017-07-10 16:19:17 -070060import java.util.stream.Collectors;
Yi Tseng49a2b2e2017-05-11 14:32:16 -070061
Antonio Marsico4f68ec92017-03-09 11:16:32 +010062import static com.google.common.base.Strings.isNullOrEmpty;
63import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
64import static org.onlab.util.Tools.groupedThreads;
Yi Tsengc927a062017-05-02 15:02:37 -070065import static org.onosproject.net.intent.IntentInstaller.Direction.ADD;
66import static org.onosproject.net.intent.IntentInstaller.Direction.REMOVE;
Antonio Marsico4f68ec92017-03-09 11:16:32 +010067import static org.onosproject.net.intent.IntentState.INSTALLED;
68import static org.onosproject.net.intent.IntentState.REALLOCATING;
69import static org.onosproject.net.intent.constraint.NonDisruptiveConstraint.requireNonDisruptive;
Yi Tsengc927a062017-05-02 15:02:37 -070070import static org.slf4j.LoggerFactory.getLogger;
71
72/**
73 * Installer for FlowRuleIntent.
74 */
75@Component(immediate = true)
76public class FlowRuleIntentInstaller implements IntentInstaller<FlowRuleIntent> {
77 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
78 protected IntentExtensionService intentExtensionService;
79
80 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
81 protected ObjectiveTrackerService trackerService;
82
83 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
84 protected IntentInstallCoordinator intentInstallCoordinator;
85
86 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
87 protected FlowRuleService flowRuleService;
88
Antonio Marsico4f68ec92017-03-09 11:16:32 +010089 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
90 protected ComponentConfigService configService;
91
92 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
93 protected IntentStore store;
94
95 private ScheduledExecutorService nonDisruptiveIntentInstaller;
96
97 private static final int DEFAULT_NON_DISRUPTIVE_INSTALLATION_WAITING_TIME = 1;
98 @Property(name = "nonDisruptiveInstallationWaitingTime",
99 intValue = DEFAULT_NON_DISRUPTIVE_INSTALLATION_WAITING_TIME,
100 label = "Number of seconds to wait during the non-disruptive installation phases")
101 private int nonDisruptiveInstallationWaitingTime = DEFAULT_NON_DISRUPTIVE_INSTALLATION_WAITING_TIME;
102
103 protected final Logger log = getLogger(IntentManager.class);
104
105 private boolean isReallocationStageFailed = false;
106
107 private static final LinkComparator LINK_COMPARATOR = new LinkComparator();
108
Yi Tsengc927a062017-05-02 15:02:37 -0700109 @Activate
110 public void activate() {
111 intentExtensionService.registerInstaller(FlowRuleIntent.class, this);
Antonio Marsico4f68ec92017-03-09 11:16:32 +0100112 nonDisruptiveIntentInstaller =
113 newSingleThreadScheduledExecutor(groupedThreads("onos/intent", "non-disruptive-installer", log));
114 configService.registerProperties(getClass());
Yi Tsengc927a062017-05-02 15:02:37 -0700115 }
116
117 @Deactivate
118 public void deactivated() {
119 intentExtensionService.unregisterInstaller(FlowRuleIntent.class);
Antonio Marsico4f68ec92017-03-09 11:16:32 +0100120 configService.unregisterProperties(getClass(), false);
Yi Tsengc927a062017-05-02 15:02:37 -0700121 }
122
Antonio Marsico4f68ec92017-03-09 11:16:32 +0100123 @Modified
124 public void modified(ComponentContext context) {
125
126 if (context == null) {
127 nonDisruptiveInstallationWaitingTime = DEFAULT_NON_DISRUPTIVE_INSTALLATION_WAITING_TIME;
128 log.info("Restored default installation time for non-disruptive reallocation (1 sec.)");
129 return;
130 }
131
132 String s = Tools.get(context.getProperties(), "nonDisruptiveInstallationWaitingTime");
133 int nonDisruptiveTime = isNullOrEmpty(s) ? nonDisruptiveInstallationWaitingTime : Integer.parseInt(s);
134 if (nonDisruptiveTime != nonDisruptiveInstallationWaitingTime) {
135 nonDisruptiveInstallationWaitingTime = nonDisruptiveTime;
136 log.info("Reconfigured non-disruptive reallocation with installation delay {} sec.",
137 nonDisruptiveInstallationWaitingTime);
138 }
139 }
Yi Tsengc927a062017-05-02 15:02:37 -0700140
141 @Override
142 public void apply(IntentOperationContext<FlowRuleIntent> context) {
143 Optional<IntentData> toUninstall = context.toUninstall();
144 Optional<IntentData> toInstall = context.toInstall();
145
Antonio Marsico4f68ec92017-03-09 11:16:32 +0100146 if (toInstall.isPresent() && toUninstall.isPresent()) {
147 Intent intentToInstall = toInstall.get().intent();
148 if (requireNonDisruptive(intentToInstall) && INSTALLED.equals(toUninstall.get().state())) {
149 reallocate(context);
150 return;
151 }
152 }
153
Yi Tsengc927a062017-05-02 15:02:37 -0700154 if (!toInstall.isPresent() && !toUninstall.isPresent()) {
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700155 // Nothing to do.
Yi Tsengc927a062017-05-02 15:02:37 -0700156 intentInstallCoordinator.intentInstallSuccess(context);
157 return;
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700158 }
159
160 List<FlowRuleIntent> uninstallIntents = context.intentsToUninstall();
161 List<FlowRuleIntent> installIntents = context.intentsToInstall();
162
163 List<FlowRule> flowRulesToUninstall;
164 List<FlowRule> flowRulesToInstall;
165
166 if (toUninstall.isPresent()) {
167 // Remove tracked resource from both Intent and installable Intents.
Yi Tsengc927a062017-05-02 15:02:37 -0700168 trackIntentResources(toUninstall.get(), uninstallIntents, REMOVE);
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700169
170 // Retrieves all flow rules from all flow rule Intents.
171 flowRulesToUninstall = uninstallIntents.stream()
172 .map(FlowRuleIntent::flowRules)
173 .flatMap(Collection::stream)
174 .collect(Collectors.toList());
Yi Tsengc927a062017-05-02 15:02:37 -0700175 } else {
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700176 // No flow rules to be uninstalled.
177 flowRulesToUninstall = Collections.emptyList();
178 }
179
180 if (toInstall.isPresent()) {
181 // Track resource from both Intent and installable Intents.
182 trackIntentResources(toInstall.get(), installIntents, ADD);
183
184 // Retrieves all flow rules from all flow rule Intents.
185 flowRulesToInstall = installIntents.stream()
186 .map(FlowRuleIntent::flowRules)
187 .flatMap(Collection::stream)
188 .collect(Collectors.toList());
189 } else {
190 // No flow rules to be installed.
191 flowRulesToInstall = Collections.emptyList();
192 }
193
Yi Tsengc29d8822017-10-25 16:19:25 -0700194 List<FlowRule> flowRuleToModify;
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700195 List<FlowRule> dontTouch;
196
197 // If both uninstall/install list contained equal (=match conditions are equal) FlowRules,
198 // omit it from remove list, since it will/should be overwritten by install
Yi Tsengc29d8822017-10-25 16:19:25 -0700199 flowRuleToModify = flowRulesToInstall.stream()
200 .filter(flowRule -> flowRulesToUninstall.stream().anyMatch(flowRule::equals))
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700201 .collect(Collectors.toList());
202
203 // If both contained exactMatch-ing FlowRules, remove from both list,
204 // since it will result in no-op.
205 dontTouch = flowRulesToInstall.stream()
206 .filter(flowRule -> flowRulesToUninstall.stream().anyMatch(flowRule::exactMatch))
207 .collect(Collectors.toList());
208
Yi Tsengc29d8822017-10-25 16:19:25 -0700209 flowRulesToUninstall.removeAll(flowRuleToModify);
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700210 flowRulesToUninstall.removeAll(dontTouch);
Yi Tsengc29d8822017-10-25 16:19:25 -0700211 flowRulesToInstall.removeAll(flowRuleToModify);
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700212 flowRulesToInstall.removeAll(dontTouch);
Yi Tsengc29d8822017-10-25 16:19:25 -0700213 flowRuleToModify.removeAll(dontTouch);
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700214
Yi Tsengc29d8822017-10-25 16:19:25 -0700215 if (flowRulesToInstall.isEmpty() && flowRulesToUninstall.isEmpty() && flowRuleToModify.isEmpty()) {
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700216 // There is no flow rules to install/uninstall
217 intentInstallCoordinator.intentInstallSuccess(context);
218 return;
Yi Tsengc927a062017-05-02 15:02:37 -0700219 }
220
221 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700222 // Add flows
223 flowRulesToInstall.forEach(builder::add);
Yi Tsengc29d8822017-10-25 16:19:25 -0700224 // Modify flows
225 flowRuleToModify.forEach(builder::modify);
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700226 // Remove flows
227 flowRulesToUninstall.forEach(builder::remove);
Yi Tsengc927a062017-05-02 15:02:37 -0700228
229 FlowRuleOperationsContext flowRuleOperationsContext = new FlowRuleOperationsContext() {
230 @Override
231 public void onSuccess(FlowRuleOperations ops) {
232 intentInstallCoordinator.intentInstallSuccess(context);
233 }
234
235 @Override
236 public void onError(FlowRuleOperations ops) {
237 intentInstallCoordinator.intentInstallFailed(context);
238 }
239 };
240
241 FlowRuleOperations operations = builder.build(flowRuleOperationsContext);
Yi Tsengc927a062017-05-02 15:02:37 -0700242 log.debug("applying intent {} -> {} with {} rules: {}",
243 toUninstall.map(x -> x.key().toString()).orElse("<empty>"),
244 toInstall.map(x -> x.key().toString()).orElse("<empty>"),
245 operations.stages().stream().mapToLong(Set::size).sum(),
246 operations.stages());
247 flowRuleService.apply(operations);
248 }
249
Antonio Marsico4f68ec92017-03-09 11:16:32 +0100250 private void reallocate(IntentOperationContext<FlowRuleIntent> context) {
251
252 Optional<IntentData> toUninstall = context.toUninstall();
253 Optional<IntentData> toInstall = context.toInstall();
254
255 //TODO: Update the Intent store with this information
256 toInstall.get().setState(REALLOCATING);
257
258 store.write(toInstall.get());
259
260 List<FlowRuleIntent> uninstallIntents = Lists.newArrayList(context.intentsToUninstall());
261 List<FlowRuleIntent> installIntents = Lists.newArrayList(context.intentsToInstall());
262 FlowRuleOperations.Builder firstStageOperationsBuilder = FlowRuleOperations.builder();
263 List<FlowRule> secondStageFlowRules = Lists.newArrayList();
264 FlowRuleOperations.Builder thirdStageOperationsBuilder = FlowRuleOperations.builder();
265 FlowRuleOperations.Builder finalStageOperationsBuilder = FlowRuleOperations.builder();
266
267 prepareReallocation(uninstallIntents, installIntents,
268 firstStageOperationsBuilder, secondStageFlowRules,
269 thirdStageOperationsBuilder, finalStageOperationsBuilder);
270
271 trackIntentResources(toUninstall.get(), uninstallIntents, REMOVE);
272 trackIntentResources(toInstall.get(), installIntents, ADD);
273
274 CountDownLatch stageCompleteLatch = new CountDownLatch(1);
275
276 FlowRuleOperations firstStageOperations = firstStageOperationsBuilder
277 .build(new StageOperation(context, stageCompleteLatch));
278
279 flowRuleService.apply(firstStageOperations);
280
281 try {
282 stageCompleteLatch.await(nonDisruptiveInstallationWaitingTime, TimeUnit.SECONDS);
283 if (isReallocationStageFailed) {
284 log.error("Reallocation FAILED in stage one: the following FlowRuleOperations are not executed {}",
285 firstStageOperations);
286 return;
287 } else {
288 log.debug("Reallocation stage one completed");
289 }
290 } catch (Exception e) {
291 log.warn("Latch exception in the reallocation stage one");
292 }
293
294 for (FlowRule flowRule : secondStageFlowRules) {
295 stageCompleteLatch = new CountDownLatch(1);
296 FlowRuleOperations operations = FlowRuleOperations.builder()
297 .newStage()
298 .remove(flowRule)
299 .build(new StageOperation(context, stageCompleteLatch));
300 nonDisruptiveIntentInstaller.schedule(new NonDisruptiveInstallation(operations),
301 nonDisruptiveInstallationWaitingTime,
302 TimeUnit.SECONDS);
303 try {
304 stageCompleteLatch.await(nonDisruptiveInstallationWaitingTime, TimeUnit.SECONDS);
305 if (isReallocationStageFailed) {
306 log.error("Reallocation FAILED in stage two: " +
307 "the following FlowRuleOperations are not executed {}",
308 operations);
309 return;
310 } else {
311 log.debug("Reallocation stage two completed");
312 }
313 } catch (Exception e) {
314 log.warn("Latch exception in the reallocation stage two");
315 }
316 }
317
318 stageCompleteLatch = new CountDownLatch(1);
319 FlowRuleOperations thirdStageOperations = thirdStageOperationsBuilder
320 .build(new StageOperation(context, stageCompleteLatch));
321
322 nonDisruptiveIntentInstaller.schedule(new NonDisruptiveInstallation(thirdStageOperations),
323 nonDisruptiveInstallationWaitingTime,
324 TimeUnit.SECONDS);
325 try {
326 stageCompleteLatch.await(nonDisruptiveInstallationWaitingTime, TimeUnit.SECONDS);
327 if (isReallocationStageFailed) {
328 log.error("Reallocation FAILED in stage three: " +
329 "the following FlowRuleOperations are not executed {}",
330 thirdStageOperations);
331 return;
332 } else {
333 log.debug("Reallocation stage three completed");
334 }
335 } catch (Exception e) {
336 log.warn("Latch exception in the reallocation stage three");
337 }
338
339 FlowRuleOperationsContext flowRuleOperationsContext = new FlowRuleOperationsContext() {
340 @Override
341 public void onSuccess(FlowRuleOperations ops) {
342 intentInstallCoordinator.intentInstallSuccess(context);
343 log.info("Non-disruptive reallocation completed for intent {}", toInstall.get().key());
344 }
345
346 @Override
347 public void onError(FlowRuleOperations ops) {
348 intentInstallCoordinator.intentInstallFailed(context);
349 }
350 };
351
352 FlowRuleOperations finalStageOperations = finalStageOperationsBuilder.build(flowRuleOperationsContext);
353 flowRuleService.apply(finalStageOperations);
354 }
355
356 /**
357 * This method prepares the {@link FlowRule} required for every reallocation stage.
358 * <p>Stage 1: the FlowRules of the new path are installed,
359 * with a lower priority only on the devices shared with the old path;</p>
360 * <p>Stage 2: the FlowRules of the old path are removed from the ingress to the egress points,
361 * only in the shared devices;</p>
362 * <p>Stage 3: the FlowRules with a lower priority are restored to the original one;</p>
363 * <p>Stage 4: the remaining FlowRules of the old path are deleted.</p>
364 *
365 * @param uninstallIntents the previous FlowRuleIntent
366 * @param installIntents the new FlowRuleIntent to be installed
367 * @param firstStageBuilder the first stage operation builder
368 * @param secondStageFlowRules the second stage FlowRules
369 * @param thirdStageBuilder the third stage operation builder
370 * @param finalStageBuilder the last stage operation builder
371 */
372 private void prepareReallocation(List<FlowRuleIntent> uninstallIntents, List<FlowRuleIntent> installIntents,
373 FlowRuleOperations.Builder firstStageBuilder,
374 List<FlowRule> secondStageFlowRules,
375 FlowRuleOperations.Builder thirdStageBuilder,
376 FlowRuleOperations.Builder finalStageBuilder) {
377
378
379 // Filter out same intents and intents with same flow rules
380 installIntents.forEach(installIntent -> {
381 uninstallIntents.forEach(uninstallIntent -> {
382
383 List<FlowRule> uninstallFlowRules = Lists.newArrayList(uninstallIntent.flowRules());
384 List<FlowRule> installFlowRules = Lists.newArrayList(installIntent.flowRules());
385
386 List<FlowRule> secondStageRules = Lists.newArrayList();
387 List<FlowRule> thirdStageRules = Lists.newArrayList();
388
389 List<DeviceId> orderedDeviceList = createIngressToEgressDeviceList(installIntent.resources());
390
391 uninstallIntent.flowRules().forEach(flowRuleToUnistall -> {
392 installIntent.flowRules().forEach(flowRuleToInstall -> {
393
394 if (flowRuleToInstall.exactMatch(flowRuleToUnistall)) {
395 //The FlowRules are in common (i.e., we are sharing the path)
396 uninstallFlowRules.remove(flowRuleToInstall);
397 installFlowRules.remove(flowRuleToInstall);
398 } else if (flowRuleToInstall.deviceId().equals(flowRuleToUnistall.deviceId())) {
399 //FlowRules that have a device in common but
400 // different treatment/selector (i.e., overlapping path)
401 FlowRule flowRuleWithLowerPriority = DefaultFlowRule.builder()
402 .withPriority(flowRuleToInstall.priority() - 1)
403 .withSelector(flowRuleToInstall.selector())
404 .forDevice(flowRuleToInstall.deviceId())
405 .makePermanent()
406 .withTreatment(flowRuleToInstall.treatment())
407 .fromApp(new DefaultApplicationId(flowRuleToInstall.appId(),
408 "org.onosproject.net.intent"))
409 .build();
410
411 //Update the FlowRule to be installed with one with a lower priority
412 installFlowRules.remove(flowRuleToInstall);
413 installFlowRules.add(flowRuleWithLowerPriority);
414
415 //Add the FlowRule to be uninstalled to the second stage of non-disruptive update
416 secondStageRules.add(flowRuleToUnistall);
417 uninstallFlowRules.remove(flowRuleToUnistall);
418
419 thirdStageRules.add(flowRuleToInstall);
420 uninstallFlowRules.add(flowRuleWithLowerPriority);
421 }
422 });
423 });
424
425 firstStageBuilder.newStage();
426 installFlowRules.forEach(firstStageBuilder::add);
427
428 Collections.sort(secondStageRules, new SecondStageComparator(orderedDeviceList));
429 secondStageFlowRules.addAll(secondStageRules);
430
431 thirdStageBuilder.newStage();
432 thirdStageRules.forEach(thirdStageBuilder::add);
433
434 finalStageBuilder.newStage();
435 uninstallFlowRules.forEach(finalStageBuilder::remove);
436 });
437 });
438
439 }
440
441 private class StageOperation implements FlowRuleOperationsContext {
442
443 private IntentOperationContext<FlowRuleIntent> context;
444 private CountDownLatch stageCompleteLatch;
445
446 public StageOperation(IntentOperationContext<FlowRuleIntent> context, CountDownLatch stageCompleteLatch) {
447 this.context = context;
448 this.stageCompleteLatch = stageCompleteLatch;
449 isReallocationStageFailed = false;
450 }
451
452 @Override
453 public void onSuccess(FlowRuleOperations ops) {
454 stageCompleteLatch.countDown();
455 log.debug("FlowRuleOperations correctly completed");
456 }
457
458 @Override
459 public void onError(FlowRuleOperations ops) {
460 intentInstallCoordinator.intentInstallFailed(context);
461 isReallocationStageFailed = true;
462 stageCompleteLatch.countDown();
463 log.debug("Installation error for {}", ops);
464 }
465 }
466
467 private final class SecondStageComparator implements Comparator<FlowRule> {
468
469 private List<DeviceId> deviceIds;
470
471 private SecondStageComparator(List<DeviceId> deviceIds) {
472 this.deviceIds = deviceIds;
473 }
474
475 @Override
476 public int compare(FlowRule o1, FlowRule o2) {
477 Integer index1 = deviceIds.indexOf(o1.deviceId());
478 Integer index2 = deviceIds.indexOf(o2.deviceId());
479 return index1.compareTo(index2);
480 }
481 }
482
483 /**
484 * Create a list of devices ordered from the ingress to the egress of a path.
485 * @param resources the resources of the intent
486 * @return a list of devices
487 */
488 private List<DeviceId> createIngressToEgressDeviceList(Collection<NetworkResource> resources) {
489 List<DeviceId> deviceIds = Lists.newArrayList();
490 List<Link> links = Lists.newArrayList();
491
492 for (NetworkResource resource : resources) {
493 if (resource instanceof Link) {
494 Link linkToAdd = (Link) resource;
495 if (linkToAdd.type() != Link.Type.EDGE) {
496 links.add(linkToAdd);
497 }
498 }
499 }
500
501 Collections.sort(links, LINK_COMPARATOR);
502
503 int i = 0;
504 for (Link orderedLink : links) {
505 deviceIds.add(orderedLink.src().deviceId());
506 if (i == resources.size() - 1) {
507 deviceIds.add(orderedLink.dst().deviceId());
508 }
509 i++;
510 }
511
512 return deviceIds;
513 }
514
515 /**
516 * Compares two links in order to find which one is before or after the other.
517 */
518 private static class LinkComparator implements Comparator<Link> {
519
520 @Override
521 public int compare(Link l1, Link l2) {
522
523 //l1 is before l2
524 if (l1.dst().deviceId() == l2.src().deviceId()) {
525 return -1;
526 }
527
528 //l1 is after l2
529 if (l1.src().deviceId() == l2.dst().deviceId()) {
530 return 1;
531 }
532
533 //l2 and l1 are not connected to a common device
534 return 0;
535 }
536 }
537
538 private final class NonDisruptiveInstallation implements Runnable {
539
540 private FlowRuleOperations op;
541
542 private NonDisruptiveInstallation(FlowRuleOperations op) {
543 this.op = op;
544 }
545 @Override
546 public void run() {
547 flowRuleService.apply(this.op);
548 }
549 }
550
Yi Tsengc927a062017-05-02 15:02:37 -0700551 /**
552 * Track or un-track network resource of a Intent and it's installable
553 * Intents.
554 *
555 * @param intentData the Intent data
556 * @param intentsToApply the list of flow rule Intents from the Intent
557 * @param direction the direction to determine track or un-track
558 */
559 private void trackIntentResources(IntentData intentData, List<FlowRuleIntent> intentsToApply, Direction direction) {
560 switch (direction) {
561 case ADD:
562 trackerService.addTrackedResources(intentData.key(), intentData.intent().resources());
563 intentsToApply.forEach(installable ->
564 trackerService.addTrackedResources(intentData.key(),
565 installable.resources()));
566 break;
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700567 case REMOVE:
Yi Tsengc927a062017-05-02 15:02:37 -0700568 trackerService.removeTrackedResources(intentData.key(), intentData.intent().resources());
569 intentsToApply.forEach(installable ->
570 trackerService.removeTrackedResources(intentData.intent().key(),
571 installable.resources()));
572 break;
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700573 default:
574 log.warn("Unknown resource tracking direction.");
575 break;
Yi Tsengc927a062017-05-02 15:02:37 -0700576 }
577 }
Yi Tsengc927a062017-05-02 15:02:37 -0700578}