Ray Milkey
Committed by Gerrit Code Review

ONOS-1404 - Rerouting delayed due to flows being removed out of order

ONOS-1409 - handle all links to a switch going away and coming back

Change-Id: Ib7216530fa8eef41b1088c5122a40bf9265481ca
...@@ -15,7 +15,15 @@ ...@@ -15,7 +15,15 @@
15 */ 15 */
16 package org.onosproject.net.intent.impl; 16 package org.onosproject.net.intent.impl;
17 17
18 -import com.google.common.collect.ImmutableList; 18 +import java.util.Collection;
19 +import java.util.EnumSet;
20 +import java.util.List;
21 +import java.util.Map;
22 +import java.util.concurrent.ExecutionException;
23 +import java.util.concurrent.ExecutorService;
24 +import java.util.concurrent.Future;
25 +import java.util.stream.Collectors;
26 +
19 import org.apache.felix.scr.annotations.Activate; 27 import org.apache.felix.scr.annotations.Activate;
20 import org.apache.felix.scr.annotations.Component; 28 import org.apache.felix.scr.annotations.Component;
21 import org.apache.felix.scr.annotations.Deactivate; 29 import org.apache.felix.scr.annotations.Deactivate;
...@@ -48,15 +56,7 @@ import org.onosproject.net.intent.impl.phase.IntentProcessPhase; ...@@ -48,15 +56,7 @@ import org.onosproject.net.intent.impl.phase.IntentProcessPhase;
48 import org.onosproject.net.intent.impl.phase.IntentWorker; 56 import org.onosproject.net.intent.impl.phase.IntentWorker;
49 import org.slf4j.Logger; 57 import org.slf4j.Logger;
50 58
51 -import java.util.Collection; 59 +import com.google.common.collect.ImmutableList;
52 -import java.util.Collections;
53 -import java.util.EnumSet;
54 -import java.util.List;
55 -import java.util.Map;
56 -import java.util.concurrent.ExecutionException;
57 -import java.util.concurrent.ExecutorService;
58 -import java.util.concurrent.Future;
59 -import java.util.stream.Collectors;
60 60
61 import static com.google.common.base.Preconditions.checkNotNull; 61 import static com.google.common.base.Preconditions.checkNotNull;
62 import static java.util.concurrent.Executors.newFixedThreadPool; 62 import static java.util.concurrent.Executors.newFixedThreadPool;
...@@ -359,97 +359,92 @@ public class IntentManager ...@@ -359,97 +359,92 @@ public class IntentManager
359 } 359 }
360 360
361 @Override 361 @Override
362 - public void install(IntentData data) { 362 + public void apply(IntentData toUninstall, IntentData toInstall) {
363 - IntentManager.this.install(data); 363 + IntentManager.this.apply(toUninstall, toInstall);
364 } 364 }
365 -
366 - @Override
367 - public void uninstall(IntentData data) {
368 - IntentManager.this.uninstall(data);
369 - }
370 -
371 } 365 }
372 366
373 - private void install(IntentData data) { 367 + private enum Direction {
374 - // need to consider if FlowRuleIntent is only one as installable intent or not 368 + ADD,
375 - List<Intent> installables = data.installables(); 369 + REMOVE
376 - if (!installables.stream().allMatch(x -> x instanceof FlowRuleIntent)) { 370 + }
377 - throw new IllegalStateException("installable intents must be FlowRuleIntent");
378 - }
379 371
380 - trackerService.addTrackedResources(data.key(), data.intent().resources()); 372 + private void applyIntentData(IntentData data,
381 - installables.forEach(installable -> 373 + FlowRuleOperations.Builder builder,
382 - trackerService.addTrackedResources(data.key(), installable.resources())); 374 + Direction direction) {
375 + if (data != null) {
376 + List<Intent> intentsToApply = data.installables();
377 + if (!intentsToApply.stream().allMatch(x -> x instanceof FlowRuleIntent)) {
378 + throw new IllegalStateException("installable intents must be FlowRuleIntent");
379 + }
383 380
384 - List<Collection<FlowRule>> stages = installables.stream() 381 + if (direction == Direction.ADD) {
385 - .map(x -> (FlowRuleIntent) x) 382 + trackerService.addTrackedResources(data.key(), data.intent().resources());
386 - .map(FlowRuleIntent::flowRules) 383 + intentsToApply.forEach(installable ->
387 - .collect(Collectors.toList()); 384 + trackerService.addTrackedResources(data.key(), installable.resources()));
385 + } else {
386 + trackerService.removeTrackedResources(data.key(), data.intent().resources());
387 + intentsToApply.forEach(installable ->
388 + trackerService.removeTrackedResources(data.intent().key(),
389 + installable.resources()));
390 + }
388 391
389 - FlowRuleOperations.Builder builder = FlowRuleOperations.builder(); 392 + // FIXME do FlowRuleIntents have stages??? Can we do uninstall work in parallel? I think so.
390 - for (Collection<FlowRule> rules : stages) {
391 - rules.forEach(builder::add);
392 builder.newStage(); 393 builder.newStage();
393 - }
394 394
395 - FlowRuleOperations operations = builder.build(new FlowRuleOperationsContext() { 395 + List<Collection<FlowRule>> stages = intentsToApply.stream()
396 - @Override 396 + .map(x -> (FlowRuleIntent) x)
397 - public void onSuccess(FlowRuleOperations ops) { 397 + .map(FlowRuleIntent::flowRules)
398 - log.debug("Completed installing: {}", data.key()); 398 + .collect(Collectors.toList());
399 - data.setState(INSTALLED);
400 - store.write(data);
401 - }
402 399
403 - @Override 400 + for (Collection<FlowRule> rules : stages) {
404 - public void onError(FlowRuleOperations ops) { 401 + if (direction == Direction.ADD) {
405 - log.warn("Failed installation: {} {} on {}", data.key(), data.intent(), ops); 402 + rules.forEach(builder::add);
406 - data.setState(FAILED); 403 + } else {
407 - store.write(data); 404 + rules.forEach(builder::remove);
405 + }
408 } 406 }
409 - });
410 -
411 - flowRuleService.apply(operations);
412 - }
413 -
414 - private void uninstall(IntentData data) {
415 - List<Intent> installables = data.installables();
416 - if (!installables.stream().allMatch(x -> x instanceof FlowRuleIntent)) {
417 - throw new IllegalStateException("installable intents must be FlowRuleIntent");
418 } 407 }
419 408
420 - trackerService.removeTrackedResources(data.key(), data.intent().resources()); 409 + }
421 - installables.forEach(installable ->
422 - trackerService.removeTrackedResources(data.intent().key(),
423 - installable.resources()));
424 410
425 - List<Collection<FlowRule>> stages = installables.stream() 411 + private void apply(IntentData toUninstall, IntentData toInstall) {
426 - .map(x -> (FlowRuleIntent) x) 412 + // need to consider if FlowRuleIntent is only one as installable intent or not
427 - .map(FlowRuleIntent::flowRules)
428 - .collect(Collectors.toList());
429 413
430 FlowRuleOperations.Builder builder = FlowRuleOperations.builder(); 414 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
431 - for (Collection<FlowRule> rules : stages) { 415 + applyIntentData(toUninstall, builder, Direction.REMOVE);
432 - rules.forEach(builder::remove); 416 + applyIntentData(toInstall, builder, Direction.ADD);
433 - builder.newStage();
434 - }
435 417
436 FlowRuleOperations operations = builder.build(new FlowRuleOperationsContext() { 418 FlowRuleOperations operations = builder.build(new FlowRuleOperationsContext() {
437 @Override 419 @Override
438 public void onSuccess(FlowRuleOperations ops) { 420 public void onSuccess(FlowRuleOperations ops) {
439 - log.debug("Completed withdrawing: {}", data.key()); 421 + if (toInstall != null) {
440 - data.setState(WITHDRAWN); 422 + log.debug("Completed installing: {}", toInstall.key());
441 - data.setInstallables(Collections.emptyList()); 423 + //FIXME state depends on install.... we might want to pass this in.
442 - store.write(data); 424 + toInstall.setState(INSTALLED);
425 + store.write(toInstall);
426 + } else if (toUninstall != null) {
427 + log.debug("Completed withdrawing: {}", toUninstall.key());
428 + //FIXME state depends on install.... we might want to pass this in.
429 + toUninstall.setState(WITHDRAWN);
430 + store.write(toUninstall);
431 + }
443 } 432 }
444 433
445 @Override 434 @Override
446 public void onError(FlowRuleOperations ops) { 435 public void onError(FlowRuleOperations ops) {
447 - log.warn("Failed withdraw: {}", data.key()); 436 + if (toInstall != null) {
448 - data.setState(FAILED); 437 + log.warn("Failed installation: {} {} on {}", toInstall.key(), toInstall.intent(), ops);
449 - store.write(data); 438 + //FIXME
439 + toInstall.setState(FAILED);
440 + store.write(toInstall);
441 + }
442 + // if toInstall was cause of error, then recompile (manage/increment counter, when exceeded -> CORRUPT)
443 + // if toUninstall was cause of error, then CORRUPT (another job will lean this up)
450 } 444 }
451 }); 445 });
452 446
453 flowRuleService.apply(operations); 447 flowRuleService.apply(operations);
454 } 448 }
449 +
455 } 450 }
......
...@@ -38,16 +38,8 @@ public interface IntentProcessor { ...@@ -38,16 +38,8 @@ public interface IntentProcessor {
38 List<Intent> compile(Intent intent, List<Intent> previousInstallables); 38 List<Intent> compile(Intent intent, List<Intent> previousInstallables);
39 39
40 /** 40 /**
41 - * Installs an intent included in the specified intent data. 41 + * @param toUninstall Intent data describing flows to uninstall. May be null.
42 - * 42 + * @param toInstall Intent data describing flows to install. May be null.
43 - * @param data intent data containing an intent to be installed
44 - */
45 - void install(IntentData data);
46 -
47 - /**
48 - * Uninstalls an intent included in the specified intent data.
49 - *
50 - * @param data intent data containing an intent to be uninstalled
51 */ 43 */
52 - void uninstall(IntentData data); 44 + void apply(IntentData toUninstall, IntentData toInstall);
53 } 45 }
......
...@@ -50,7 +50,7 @@ final class Compiling implements IntentProcessPhase { ...@@ -50,7 +50,7 @@ final class Compiling implements IntentProcessPhase {
50 public Optional<IntentProcessPhase> execute() { 50 public Optional<IntentProcessPhase> execute() {
51 try { 51 try {
52 data.setInstallables(processor.compile(data.intent(), null)); 52 data.setInstallables(processor.compile(data.intent(), null));
53 - return Optional.of(new Installing(processor, data)); 53 + return Optional.of(new Installing(processor, data, null));
54 } catch (IntentException e) { 54 } catch (IntentException e) {
55 log.debug("Unable to compile intent {} due to: {}", data.intent(), e); 55 log.debug("Unable to compile intent {} due to: {}", data.intent(), e);
56 return Optional.of(new CompileFailed(data)); 56 return Optional.of(new CompileFailed(data));
......
...@@ -28,6 +28,7 @@ class Installing extends FinalIntentProcessPhase { ...@@ -28,6 +28,7 @@ class Installing extends FinalIntentProcessPhase {
28 28
29 private final IntentProcessor processor; 29 private final IntentProcessor processor;
30 private final IntentData data; 30 private final IntentData data;
31 + private final IntentData stored;
31 32
32 /** 33 /**
33 * Create an installing phase. 34 * Create an installing phase.
...@@ -35,15 +36,16 @@ class Installing extends FinalIntentProcessPhase { ...@@ -35,15 +36,16 @@ class Installing extends FinalIntentProcessPhase {
35 * @param processor intent processor that does work for installing 36 * @param processor intent processor that does work for installing
36 * @param data intent data containing an intent to be installed 37 * @param data intent data containing an intent to be installed
37 */ 38 */
38 - Installing(IntentProcessor processor, IntentData data) { 39 + Installing(IntentProcessor processor, IntentData data, IntentData stored) {
39 this.processor = checkNotNull(processor); 40 this.processor = checkNotNull(processor);
40 this.data = checkNotNull(data); 41 this.data = checkNotNull(data);
41 this.data.setState(INSTALLING); 42 this.data.setState(INSTALLING);
43 + this.stored = stored;
42 } 44 }
43 45
44 @Override 46 @Override
45 public void preExecute() { 47 public void preExecute() {
46 - processor.install(data); 48 + processor.apply(stored, data);
47 } 49 }
48 50
49 @Override 51 @Override
......
...@@ -17,7 +17,10 @@ package org.onosproject.net.intent.impl.phase; ...@@ -17,7 +17,10 @@ package org.onosproject.net.intent.impl.phase;
17 17
18 import org.onosproject.net.intent.Intent; 18 import org.onosproject.net.intent.Intent;
19 import org.onosproject.net.intent.IntentData; 19 import org.onosproject.net.intent.IntentData;
20 +import org.onosproject.net.intent.IntentException;
20 import org.onosproject.net.intent.impl.IntentProcessor; 21 import org.onosproject.net.intent.impl.IntentProcessor;
22 +import org.slf4j.Logger;
23 +import org.slf4j.LoggerFactory;
21 24
22 import java.util.List; 25 import java.util.List;
23 import java.util.Optional; 26 import java.util.Optional;
...@@ -29,6 +32,8 @@ import static com.google.common.base.Preconditions.checkNotNull; ...@@ -29,6 +32,8 @@ import static com.google.common.base.Preconditions.checkNotNull;
29 */ 32 */
30 class Recompiling implements IntentProcessPhase { 33 class Recompiling implements IntentProcessPhase {
31 34
35 + private static final Logger log = LoggerFactory.getLogger(Recompiling.class);
36 +
32 private final IntentProcessor processor; 37 private final IntentProcessor processor;
33 private final IntentData data; 38 private final IntentData data;
34 private final IntentData stored; 39 private final IntentData stored;
...@@ -48,8 +53,14 @@ class Recompiling implements IntentProcessPhase { ...@@ -48,8 +53,14 @@ class Recompiling implements IntentProcessPhase {
48 53
49 @Override 54 @Override
50 public Optional<IntentProcessPhase> execute() { 55 public Optional<IntentProcessPhase> execute() {
51 - List<Intent> compiled = processor.compile(data.intent(), stored.installables()); 56 + try {
52 - data.setInstallables(compiled); 57 + List<Intent> compiled = processor.compile(data.intent(), stored.installables());
53 - return Optional.of(new Replacing(processor, data, stored)); 58 + data.setInstallables(compiled);
59 + return Optional.of(new Installing(processor, data, stored));
60 + } catch (IntentException e) {
61 + log.debug("Unable to recompile intent {} due to: {}", data.intent(), e);
62 + // FIXME we need to removed orphaned flows and deallocate resources
63 + return Optional.of(new CompileFailed(data));
64 + }
54 } 65 }
55 } 66 }
......
1 -/*
2 - * Copyright 2015 Open Networking Laboratory
3 - *
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 -package org.onosproject.net.intent.impl.phase;
17 -
18 -import org.onosproject.net.intent.IntentData;
19 -import org.onosproject.net.intent.IntentException;
20 -import org.onosproject.net.intent.impl.IntentProcessor;
21 -import org.slf4j.Logger;
22 -import org.slf4j.LoggerFactory;
23 -
24 -import java.util.Optional;
25 -
26 -import static com.google.common.base.Preconditions.checkNotNull;
27 -
28 -/**
29 - * Represents a phase to replace an intent.
30 - */
31 -final class Replacing implements IntentProcessPhase {
32 -
33 - private static final Logger log = LoggerFactory.getLogger(Replacing.class);
34 -
35 - private final IntentProcessor processor;
36 - private final IntentData data;
37 - private final IntentData stored;
38 -
39 - /**
40 - * Creates a replacing phase.
41 - *
42 - * @param processor intent processor that does work for replacing
43 - * @param data intent data containing an intent to be replaced
44 - * @param stored intent data stored in the store
45 - */
46 - Replacing(IntentProcessor processor, IntentData data, IntentData stored) {
47 - this.processor = checkNotNull(processor);
48 - this.data = checkNotNull(data);
49 - this.stored = checkNotNull(stored);
50 - }
51 -
52 - @Override
53 - public Optional<IntentProcessPhase> execute() {
54 - try {
55 - processor.uninstall(stored);
56 - return Optional.of(new Installing(processor, data));
57 - } catch (IntentException e) {
58 - log.warn("Unable to generate a FlowRuleOperations from intent {} due to:", data.intent().id(), e);
59 - return Optional.of(new ReplaceFailed(data));
60 - }
61 - }
62 -}
...@@ -44,7 +44,7 @@ class Withdrawing extends FinalIntentProcessPhase { ...@@ -44,7 +44,7 @@ class Withdrawing extends FinalIntentProcessPhase {
44 44
45 @Override 45 @Override
46 protected void preExecute() { 46 protected void preExecute() {
47 - processor.uninstall(data); 47 + processor.apply(data, null);
48 } 48 }
49 49
50 @Override 50 @Override
......
1 -/*
2 - * Copyright 2015 Open Networking Laboratory
3 - *
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 -package org.onosproject.net.intent.impl.phase;
17 -
18 -import org.junit.After;
19 -import org.junit.Before;
20 -import org.junit.Test;
21 -import org.onosproject.TestApplicationId;
22 -import org.onosproject.core.ApplicationId;
23 -import org.onosproject.core.IdGenerator;
24 -import org.onosproject.net.ConnectPoint;
25 -import org.onosproject.net.DefaultLink;
26 -import org.onosproject.net.DefaultPath;
27 -import org.onosproject.net.Link;
28 -import org.onosproject.net.Path;
29 -import org.onosproject.net.flow.DefaultTrafficSelector;
30 -import org.onosproject.net.flow.DefaultTrafficTreatment;
31 -import org.onosproject.net.flow.TrafficSelector;
32 -import org.onosproject.net.flow.TrafficTreatment;
33 -import org.onosproject.net.intent.Intent;
34 -import org.onosproject.net.intent.IntentData;
35 -import org.onosproject.net.intent.MockIdGenerator;
36 -import org.onosproject.net.intent.PathIntent;
37 -import org.onosproject.net.intent.PointToPointIntent;
38 -import org.onosproject.net.intent.impl.IntentInstallationException;
39 -import org.onosproject.net.intent.impl.IntentProcessor;
40 -import org.onosproject.net.provider.ProviderId;
41 -import org.onosproject.store.Timestamp;
42 -
43 -import java.util.Arrays;
44 -import java.util.List;
45 -import java.util.Optional;
46 -
47 -import static org.easymock.EasyMock.createMock;
48 -import static org.easymock.EasyMock.expectLastCall;
49 -import static org.easymock.EasyMock.replay;
50 -import static org.easymock.EasyMock.verify;
51 -import static org.hamcrest.Matchers.instanceOf;
52 -import static org.hamcrest.Matchers.is;
53 -import static org.junit.Assert.assertThat;
54 -import static org.onosproject.net.DeviceId.deviceId;
55 -import static org.onosproject.net.Link.Type.DIRECT;
56 -import static org.onosproject.net.PortNumber.portNumber;
57 -import static org.onosproject.net.intent.IntentState.INSTALLED;
58 -import static org.onosproject.net.intent.IntentState.INSTALL_REQ;
59 -
60 -/**
61 - * Unit tests for InstallingCoordinating phase.
62 - */
63 -public class ReplacingTest {
64 -
65 - private final ApplicationId appId = new TestApplicationId("test");
66 - private final ProviderId pid = new ProviderId("of", "test");
67 - private final TrafficSelector selector = DefaultTrafficSelector.emptySelector();
68 - private final TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment();
69 - private final ConnectPoint cp1 = new ConnectPoint(deviceId("1"), portNumber(1));
70 - private final ConnectPoint cp2 = new ConnectPoint(deviceId("1"), portNumber(2));
71 - private final ConnectPoint cp3 = new ConnectPoint(deviceId("2"), portNumber(1));
72 - private final ConnectPoint cp4 = new ConnectPoint(deviceId("2"), portNumber(2));
73 -
74 - private final List<Link> links = Arrays.asList(new DefaultLink(pid, cp2, cp4, DIRECT));
75 - private final Path path = new DefaultPath(pid, links, 10);
76 -
77 - private PointToPointIntent input;
78 - private PathIntent compiled;
79 -
80 - private IdGenerator idGenerator;
81 - private IntentProcessor processor;
82 - private Timestamp version;
83 -
84 - @Before
85 - public void setUp() {
86 - processor = createMock(IntentProcessor.class);
87 - version = createMock(Timestamp.class);
88 -
89 - idGenerator = new MockIdGenerator();
90 -
91 - Intent.bindIdGenerator(idGenerator);
92 -
93 - // Intent creation should be placed after binding an ID generator
94 - input = PointToPointIntent.builder()
95 - .appId(appId)
96 - .selector(selector)
97 - .treatment(treatment)
98 - .ingressPoint(cp1)
99 - .egressPoint(cp3)
100 - .build();
101 - compiled = PathIntent.builder()
102 - .appId(appId)
103 - .selector(selector)
104 - .treatment(treatment)
105 - .path(path)
106 - .build();
107 - }
108 -
109 -
110 - @After
111 - public void tearDown() {
112 - Intent.unbindIdGenerator(idGenerator);
113 - }
114 -
115 - /**
116 - * Tests a next phase when no exception occurs.
117 - */
118 - @Test
119 - public void testMoveToNextPhaseWithoutError() {
120 - IntentData pending = new IntentData(input, INSTALL_REQ, version);
121 - pending.setInstallables(Arrays.asList(compiled));
122 -
123 - IntentData current = new IntentData(input, INSTALLED, version);
124 - current.setInstallables(Arrays.asList(compiled));
125 -
126 - processor.uninstall(current);
127 - replay(processor);
128 -
129 - Replacing sut = new Replacing(processor, pending, current);
130 -
131 - Optional<IntentProcessPhase> executed = sut.execute();
132 -
133 - verify(processor);
134 - assertThat(executed.get(), is(instanceOf(Installing.class)));
135 - }
136 -
137 - /**
138 - * Tests a next phase when IntentInstallationException occurs.
139 - */
140 - @Test
141 - public void testWhenIntentInstallExceptionOccurs() {
142 - IntentData pending = new IntentData(input, INSTALL_REQ, version);
143 - pending.setInstallables(Arrays.asList(compiled));
144 -
145 - IntentData current = new IntentData(input, INSTALLED, version);
146 -
147 - processor.uninstall(current);
148 - expectLastCall().andThrow(new IntentInstallationException());
149 - replay(processor);
150 -
151 - Replacing sut = new Replacing(processor, pending, current);
152 -
153 - Optional<IntentProcessPhase> executed = sut.execute();
154 -
155 - verify(processor);
156 - assertThat(executed.get(), is(instanceOf(ReplaceFailed.class)));
157 - }
158 -}