blob: 71cf28c8f7776f6b4d494678992498042a55a024 [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)
David Glantz0a5779c2021-09-22 14:34:14 -0500177 .filter(flowRule -> flowRuleService.getFlowEntry(flowRule) != null)
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700178 .collect(Collectors.toList());
Yi Tsengc927a062017-05-02 15:02:37 -0700179 } else {
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700180 // No flow rules to be uninstalled.
181 flowRulesToUninstall = Collections.emptyList();
182 }
183
184 if (toInstall.isPresent()) {
185 // Track resource from both Intent and installable Intents.
186 trackIntentResources(toInstall.get(), installIntents, ADD);
187
188 // Retrieves all flow rules from all flow rule Intents.
189 flowRulesToInstall = installIntents.stream()
190 .map(FlowRuleIntent::flowRules)
191 .flatMap(Collection::stream)
192 .collect(Collectors.toList());
193 } else {
194 // No flow rules to be installed.
195 flowRulesToInstall = Collections.emptyList();
196 }
197
Yi Tsengc29d8822017-10-25 16:19:25 -0700198 List<FlowRule> flowRuleToModify;
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700199 List<FlowRule> dontTouch;
200
201 // If both uninstall/install list contained equal (=match conditions are equal) FlowRules,
202 // omit it from remove list, since it will/should be overwritten by install
Yi Tsengc29d8822017-10-25 16:19:25 -0700203 flowRuleToModify = flowRulesToInstall.stream()
204 .filter(flowRule -> flowRulesToUninstall.stream().anyMatch(flowRule::equals))
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700205 .collect(Collectors.toList());
206
207 // If both contained exactMatch-ing FlowRules, remove from both list,
208 // since it will result in no-op.
209 dontTouch = flowRulesToInstall.stream()
210 .filter(flowRule -> flowRulesToUninstall.stream().anyMatch(flowRule::exactMatch))
211 .collect(Collectors.toList());
212
Yi Tsengc29d8822017-10-25 16:19:25 -0700213 flowRulesToUninstall.removeAll(flowRuleToModify);
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700214 flowRulesToUninstall.removeAll(dontTouch);
Yi Tsengc29d8822017-10-25 16:19:25 -0700215 flowRulesToInstall.removeAll(flowRuleToModify);
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700216 flowRulesToInstall.removeAll(dontTouch);
Yi Tsengc29d8822017-10-25 16:19:25 -0700217 flowRuleToModify.removeAll(dontTouch);
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700218
Yi Tsengc29d8822017-10-25 16:19:25 -0700219 if (flowRulesToInstall.isEmpty() && flowRulesToUninstall.isEmpty() && flowRuleToModify.isEmpty()) {
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700220 // There is no flow rules to install/uninstall
221 intentInstallCoordinator.intentInstallSuccess(context);
222 return;
Yi Tsengc927a062017-05-02 15:02:37 -0700223 }
224
225 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700226 // Add flows
227 flowRulesToInstall.forEach(builder::add);
Yi Tsengc29d8822017-10-25 16:19:25 -0700228 // Modify flows
229 flowRuleToModify.forEach(builder::modify);
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700230 // Remove flows
231 flowRulesToUninstall.forEach(builder::remove);
Yi Tsengc927a062017-05-02 15:02:37 -0700232
233 FlowRuleOperationsContext flowRuleOperationsContext = new FlowRuleOperationsContext() {
234 @Override
235 public void onSuccess(FlowRuleOperations ops) {
236 intentInstallCoordinator.intentInstallSuccess(context);
237 }
238
239 @Override
240 public void onError(FlowRuleOperations ops) {
241 intentInstallCoordinator.intentInstallFailed(context);
242 }
243 };
244
245 FlowRuleOperations operations = builder.build(flowRuleOperationsContext);
Yi Tsengc927a062017-05-02 15:02:37 -0700246 log.debug("applying intent {} -> {} with {} rules: {}",
247 toUninstall.map(x -> x.key().toString()).orElse("<empty>"),
248 toInstall.map(x -> x.key().toString()).orElse("<empty>"),
249 operations.stages().stream().mapToLong(Set::size).sum(),
250 operations.stages());
251 flowRuleService.apply(operations);
252 }
253
Antonio Marsico4f68ec92017-03-09 11:16:32 +0100254 private void reallocate(IntentOperationContext<FlowRuleIntent> context) {
255
256 Optional<IntentData> toUninstall = context.toUninstall();
257 Optional<IntentData> toInstall = context.toInstall();
258
259 //TODO: Update the Intent store with this information
260 toInstall.get().setState(REALLOCATING);
261
262 store.write(toInstall.get());
263
264 List<FlowRuleIntent> uninstallIntents = Lists.newArrayList(context.intentsToUninstall());
265 List<FlowRuleIntent> installIntents = Lists.newArrayList(context.intentsToInstall());
266 FlowRuleOperations.Builder firstStageOperationsBuilder = FlowRuleOperations.builder();
267 List<FlowRule> secondStageFlowRules = Lists.newArrayList();
268 FlowRuleOperations.Builder thirdStageOperationsBuilder = FlowRuleOperations.builder();
269 FlowRuleOperations.Builder finalStageOperationsBuilder = FlowRuleOperations.builder();
270
271 prepareReallocation(uninstallIntents, installIntents,
272 firstStageOperationsBuilder, secondStageFlowRules,
273 thirdStageOperationsBuilder, finalStageOperationsBuilder);
274
275 trackIntentResources(toUninstall.get(), uninstallIntents, REMOVE);
276 trackIntentResources(toInstall.get(), installIntents, ADD);
277
278 CountDownLatch stageCompleteLatch = new CountDownLatch(1);
279
280 FlowRuleOperations firstStageOperations = firstStageOperationsBuilder
281 .build(new StageOperation(context, stageCompleteLatch));
282
283 flowRuleService.apply(firstStageOperations);
284
285 try {
286 stageCompleteLatch.await(nonDisruptiveInstallationWaitingTime, TimeUnit.SECONDS);
287 if (isReallocationStageFailed) {
288 log.error("Reallocation FAILED in stage one: the following FlowRuleOperations are not executed {}",
289 firstStageOperations);
290 return;
291 } else {
292 log.debug("Reallocation stage one completed");
293 }
294 } catch (Exception e) {
295 log.warn("Latch exception in the reallocation stage one");
296 }
297
298 for (FlowRule flowRule : secondStageFlowRules) {
299 stageCompleteLatch = new CountDownLatch(1);
300 FlowRuleOperations operations = FlowRuleOperations.builder()
301 .newStage()
302 .remove(flowRule)
303 .build(new StageOperation(context, stageCompleteLatch));
304 nonDisruptiveIntentInstaller.schedule(new NonDisruptiveInstallation(operations),
305 nonDisruptiveInstallationWaitingTime,
306 TimeUnit.SECONDS);
307 try {
308 stageCompleteLatch.await(nonDisruptiveInstallationWaitingTime, TimeUnit.SECONDS);
309 if (isReallocationStageFailed) {
310 log.error("Reallocation FAILED in stage two: " +
311 "the following FlowRuleOperations are not executed {}",
312 operations);
313 return;
314 } else {
315 log.debug("Reallocation stage two completed");
316 }
317 } catch (Exception e) {
318 log.warn("Latch exception in the reallocation stage two");
319 }
320 }
321
322 stageCompleteLatch = new CountDownLatch(1);
323 FlowRuleOperations thirdStageOperations = thirdStageOperationsBuilder
324 .build(new StageOperation(context, stageCompleteLatch));
325
326 nonDisruptiveIntentInstaller.schedule(new NonDisruptiveInstallation(thirdStageOperations),
327 nonDisruptiveInstallationWaitingTime,
328 TimeUnit.SECONDS);
329 try {
330 stageCompleteLatch.await(nonDisruptiveInstallationWaitingTime, TimeUnit.SECONDS);
331 if (isReallocationStageFailed) {
332 log.error("Reallocation FAILED in stage three: " +
333 "the following FlowRuleOperations are not executed {}",
334 thirdStageOperations);
335 return;
336 } else {
337 log.debug("Reallocation stage three completed");
338 }
339 } catch (Exception e) {
340 log.warn("Latch exception in the reallocation stage three");
341 }
342
343 FlowRuleOperationsContext flowRuleOperationsContext = new FlowRuleOperationsContext() {
344 @Override
345 public void onSuccess(FlowRuleOperations ops) {
346 intentInstallCoordinator.intentInstallSuccess(context);
347 log.info("Non-disruptive reallocation completed for intent {}", toInstall.get().key());
348 }
349
350 @Override
351 public void onError(FlowRuleOperations ops) {
352 intentInstallCoordinator.intentInstallFailed(context);
353 }
354 };
355
356 FlowRuleOperations finalStageOperations = finalStageOperationsBuilder.build(flowRuleOperationsContext);
357 flowRuleService.apply(finalStageOperations);
358 }
359
360 /**
361 * This method prepares the {@link FlowRule} required for every reallocation stage.
362 * <p>Stage 1: the FlowRules of the new path are installed,
363 * with a lower priority only on the devices shared with the old path;</p>
364 * <p>Stage 2: the FlowRules of the old path are removed from the ingress to the egress points,
365 * only in the shared devices;</p>
366 * <p>Stage 3: the FlowRules with a lower priority are restored to the original one;</p>
367 * <p>Stage 4: the remaining FlowRules of the old path are deleted.</p>
368 *
369 * @param uninstallIntents the previous FlowRuleIntent
370 * @param installIntents the new FlowRuleIntent to be installed
371 * @param firstStageBuilder the first stage operation builder
372 * @param secondStageFlowRules the second stage FlowRules
373 * @param thirdStageBuilder the third stage operation builder
374 * @param finalStageBuilder the last stage operation builder
375 */
376 private void prepareReallocation(List<FlowRuleIntent> uninstallIntents, List<FlowRuleIntent> installIntents,
377 FlowRuleOperations.Builder firstStageBuilder,
378 List<FlowRule> secondStageFlowRules,
379 FlowRuleOperations.Builder thirdStageBuilder,
380 FlowRuleOperations.Builder finalStageBuilder) {
381
382
383 // Filter out same intents and intents with same flow rules
384 installIntents.forEach(installIntent -> {
385 uninstallIntents.forEach(uninstallIntent -> {
386
387 List<FlowRule> uninstallFlowRules = Lists.newArrayList(uninstallIntent.flowRules());
388 List<FlowRule> installFlowRules = Lists.newArrayList(installIntent.flowRules());
389
390 List<FlowRule> secondStageRules = Lists.newArrayList();
391 List<FlowRule> thirdStageRules = Lists.newArrayList();
392
393 List<DeviceId> orderedDeviceList = createIngressToEgressDeviceList(installIntent.resources());
394
395 uninstallIntent.flowRules().forEach(flowRuleToUnistall -> {
396 installIntent.flowRules().forEach(flowRuleToInstall -> {
397
398 if (flowRuleToInstall.exactMatch(flowRuleToUnistall)) {
399 //The FlowRules are in common (i.e., we are sharing the path)
400 uninstallFlowRules.remove(flowRuleToInstall);
401 installFlowRules.remove(flowRuleToInstall);
402 } else if (flowRuleToInstall.deviceId().equals(flowRuleToUnistall.deviceId())) {
403 //FlowRules that have a device in common but
404 // different treatment/selector (i.e., overlapping path)
405 FlowRule flowRuleWithLowerPriority = DefaultFlowRule.builder()
406 .withPriority(flowRuleToInstall.priority() - 1)
407 .withSelector(flowRuleToInstall.selector())
408 .forDevice(flowRuleToInstall.deviceId())
409 .makePermanent()
410 .withTreatment(flowRuleToInstall.treatment())
411 .fromApp(new DefaultApplicationId(flowRuleToInstall.appId(),
412 "org.onosproject.net.intent"))
413 .build();
414
415 //Update the FlowRule to be installed with one with a lower priority
416 installFlowRules.remove(flowRuleToInstall);
417 installFlowRules.add(flowRuleWithLowerPriority);
418
419 //Add the FlowRule to be uninstalled to the second stage of non-disruptive update
420 secondStageRules.add(flowRuleToUnistall);
421 uninstallFlowRules.remove(flowRuleToUnistall);
422
423 thirdStageRules.add(flowRuleToInstall);
424 uninstallFlowRules.add(flowRuleWithLowerPriority);
425 }
426 });
427 });
428
429 firstStageBuilder.newStage();
430 installFlowRules.forEach(firstStageBuilder::add);
431
432 Collections.sort(secondStageRules, new SecondStageComparator(orderedDeviceList));
433 secondStageFlowRules.addAll(secondStageRules);
434
435 thirdStageBuilder.newStage();
436 thirdStageRules.forEach(thirdStageBuilder::add);
437
438 finalStageBuilder.newStage();
439 uninstallFlowRules.forEach(finalStageBuilder::remove);
440 });
441 });
442
443 }
444
445 private class StageOperation implements FlowRuleOperationsContext {
446
447 private IntentOperationContext<FlowRuleIntent> context;
448 private CountDownLatch stageCompleteLatch;
449
450 public StageOperation(IntentOperationContext<FlowRuleIntent> context, CountDownLatch stageCompleteLatch) {
451 this.context = context;
452 this.stageCompleteLatch = stageCompleteLatch;
453 isReallocationStageFailed = false;
454 }
455
456 @Override
457 public void onSuccess(FlowRuleOperations ops) {
458 stageCompleteLatch.countDown();
459 log.debug("FlowRuleOperations correctly completed");
460 }
461
462 @Override
463 public void onError(FlowRuleOperations ops) {
464 intentInstallCoordinator.intentInstallFailed(context);
465 isReallocationStageFailed = true;
466 stageCompleteLatch.countDown();
467 log.debug("Installation error for {}", ops);
468 }
469 }
470
471 private final class SecondStageComparator implements Comparator<FlowRule> {
472
473 private List<DeviceId> deviceIds;
474
475 private SecondStageComparator(List<DeviceId> deviceIds) {
476 this.deviceIds = deviceIds;
477 }
478
479 @Override
480 public int compare(FlowRule o1, FlowRule o2) {
481 Integer index1 = deviceIds.indexOf(o1.deviceId());
482 Integer index2 = deviceIds.indexOf(o2.deviceId());
483 return index1.compareTo(index2);
484 }
485 }
486
487 /**
488 * Create a list of devices ordered from the ingress to the egress of a path.
489 * @param resources the resources of the intent
490 * @return a list of devices
491 */
492 private List<DeviceId> createIngressToEgressDeviceList(Collection<NetworkResource> resources) {
493 List<DeviceId> deviceIds = Lists.newArrayList();
494 List<Link> links = Lists.newArrayList();
495
496 for (NetworkResource resource : resources) {
497 if (resource instanceof Link) {
498 Link linkToAdd = (Link) resource;
499 if (linkToAdd.type() != Link.Type.EDGE) {
500 links.add(linkToAdd);
501 }
502 }
503 }
504
505 Collections.sort(links, LINK_COMPARATOR);
506
507 int i = 0;
508 for (Link orderedLink : links) {
509 deviceIds.add(orderedLink.src().deviceId());
510 if (i == resources.size() - 1) {
511 deviceIds.add(orderedLink.dst().deviceId());
512 }
513 i++;
514 }
515
516 return deviceIds;
517 }
518
519 /**
520 * Compares two links in order to find which one is before or after the other.
521 */
522 private static class LinkComparator implements Comparator<Link> {
523
524 @Override
525 public int compare(Link l1, Link l2) {
526
527 //l1 is before l2
528 if (l1.dst().deviceId() == l2.src().deviceId()) {
529 return -1;
530 }
531
532 //l1 is after l2
533 if (l1.src().deviceId() == l2.dst().deviceId()) {
534 return 1;
535 }
536
537 //l2 and l1 are not connected to a common device
538 return 0;
539 }
540 }
541
542 private final class NonDisruptiveInstallation implements Runnable {
543
544 private FlowRuleOperations op;
545
546 private NonDisruptiveInstallation(FlowRuleOperations op) {
547 this.op = op;
548 }
549 @Override
550 public void run() {
551 flowRuleService.apply(this.op);
552 }
553 }
554
Yi Tsengc927a062017-05-02 15:02:37 -0700555 /**
556 * Track or un-track network resource of a Intent and it's installable
557 * Intents.
558 *
559 * @param intentData the Intent data
560 * @param intentsToApply the list of flow rule Intents from the Intent
561 * @param direction the direction to determine track or un-track
562 */
563 private void trackIntentResources(IntentData intentData, List<FlowRuleIntent> intentsToApply, Direction direction) {
564 switch (direction) {
565 case ADD:
566 trackerService.addTrackedResources(intentData.key(), intentData.intent().resources());
567 intentsToApply.forEach(installable ->
568 trackerService.addTrackedResources(intentData.key(),
569 installable.resources()));
570 break;
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700571 case REMOVE:
Yi Tsengc927a062017-05-02 15:02:37 -0700572 trackerService.removeTrackedResources(intentData.key(), intentData.intent().resources());
573 intentsToApply.forEach(installable ->
574 trackerService.removeTrackedResources(intentData.intent().key(),
575 installable.resources()));
576 break;
Yi Tseng4a7d1e12017-07-10 16:19:17 -0700577 default:
578 log.warn("Unknown resource tracking direction.");
579 break;
Yi Tsengc927a062017-05-02 15:02:37 -0700580 }
581 }
Yi Tsengc927a062017-05-02 15:02:37 -0700582}