Jonathan Hart

ONOS-2513 Fix entire MP2SP intent failing on partial connectivity loss

 * Added PartialFailureContraint to MP2SP intent to allow partial connectivity.
   This means the intent remains installed as long as at least one ingress point
   can reach the egress point.
 * Intents with this constraint are recompiled on ObjectiveTracker triggers
   even if not in FAILED state
 * MP2SP intent compiler can compute a partial tree if constraint is set
 * ObjectiveTracker recompiles intents on any link event
 * SDN-IP MP2SP intents now use PartialFailureConstraint

Change-Id: I32eaa198fae1dfba021d9251c8f855573f0e1d7d
...@@ -15,19 +15,8 @@ ...@@ -15,19 +15,8 @@
15 */ 15 */
16 package org.onosproject.sdnip; 16 package org.onosproject.sdnip;
17 17
18 -import java.util.Collection; 18 +import com.google.common.collect.ImmutableList;
19 -import java.util.HashMap; 19 +import com.google.common.util.concurrent.ThreadFactoryBuilder;
20 -import java.util.HashSet;
21 -import java.util.LinkedList;
22 -import java.util.List;
23 -import java.util.Map;
24 -import java.util.Objects;
25 -import java.util.Set;
26 -import java.util.concurrent.ConcurrentHashMap;
27 -import java.util.concurrent.ExecutorService;
28 -import java.util.concurrent.Executors;
29 -import java.util.concurrent.Semaphore;
30 -
31 import org.onlab.packet.Ethernet; 20 import org.onlab.packet.Ethernet;
32 import org.onlab.packet.IpAddress; 21 import org.onlab.packet.IpAddress;
33 import org.onlab.packet.IpPrefix; 22 import org.onlab.packet.IpPrefix;
...@@ -40,15 +29,17 @@ import org.onosproject.net.flow.DefaultTrafficSelector; ...@@ -40,15 +29,17 @@ import org.onosproject.net.flow.DefaultTrafficSelector;
40 import org.onosproject.net.flow.DefaultTrafficTreatment; 29 import org.onosproject.net.flow.DefaultTrafficTreatment;
41 import org.onosproject.net.flow.TrafficSelector; 30 import org.onosproject.net.flow.TrafficSelector;
42 import org.onosproject.net.flow.TrafficTreatment; 31 import org.onosproject.net.flow.TrafficTreatment;
43 -import org.onosproject.net.flow.criteria.IPCriterion;
44 import org.onosproject.net.flow.criteria.Criterion; 32 import org.onosproject.net.flow.criteria.Criterion;
33 +import org.onosproject.net.flow.criteria.IPCriterion;
45 import org.onosproject.net.host.HostService; 34 import org.onosproject.net.host.HostService;
35 +import org.onosproject.net.intent.Constraint;
46 import org.onosproject.net.intent.Intent; 36 import org.onosproject.net.intent.Intent;
47 import org.onosproject.net.intent.IntentService; 37 import org.onosproject.net.intent.IntentService;
48 import org.onosproject.net.intent.IntentState; 38 import org.onosproject.net.intent.IntentState;
49 import org.onosproject.net.intent.Key; 39 import org.onosproject.net.intent.Key;
50 import org.onosproject.net.intent.MultiPointToSinglePointIntent; 40 import org.onosproject.net.intent.MultiPointToSinglePointIntent;
51 import org.onosproject.net.intent.PointToPointIntent; 41 import org.onosproject.net.intent.PointToPointIntent;
42 +import org.onosproject.net.intent.constraint.PartialFailureConstraint;
52 import org.onosproject.routing.FibListener; 43 import org.onosproject.routing.FibListener;
53 import org.onosproject.routing.FibUpdate; 44 import org.onosproject.routing.FibUpdate;
54 import org.onosproject.routing.IntentRequestListener; 45 import org.onosproject.routing.IntentRequestListener;
...@@ -58,7 +49,18 @@ import org.onosproject.routing.config.RoutingConfigurationService; ...@@ -58,7 +49,18 @@ import org.onosproject.routing.config.RoutingConfigurationService;
58 import org.slf4j.Logger; 49 import org.slf4j.Logger;
59 import org.slf4j.LoggerFactory; 50 import org.slf4j.LoggerFactory;
60 51
61 -import com.google.common.util.concurrent.ThreadFactoryBuilder; 52 +import java.util.Collection;
53 +import java.util.HashMap;
54 +import java.util.HashSet;
55 +import java.util.LinkedList;
56 +import java.util.List;
57 +import java.util.Map;
58 +import java.util.Objects;
59 +import java.util.Set;
60 +import java.util.concurrent.ConcurrentHashMap;
61 +import java.util.concurrent.ExecutorService;
62 +import java.util.concurrent.Executors;
63 +import java.util.concurrent.Semaphore;
62 64
63 import static com.google.common.base.Preconditions.checkArgument; 65 import static com.google.common.base.Preconditions.checkArgument;
64 import static com.google.common.base.Preconditions.checkNotNull; 66 import static com.google.common.base.Preconditions.checkNotNull;
...@@ -70,6 +72,8 @@ import static com.google.common.base.Preconditions.checkNotNull; ...@@ -70,6 +72,8 @@ import static com.google.common.base.Preconditions.checkNotNull;
70 public class IntentSynchronizer implements FibListener, IntentRequestListener { 72 public class IntentSynchronizer implements FibListener, IntentRequestListener {
71 private static final int PRIORITY_OFFSET = 100; 73 private static final int PRIORITY_OFFSET = 100;
72 private static final int PRIORITY_MULTIPLIER = 5; 74 private static final int PRIORITY_MULTIPLIER = 5;
75 + protected static final ImmutableList<Constraint> CONSTRAINTS
76 + = ImmutableList.of(new PartialFailureConstraint());
73 77
74 private static final Logger log = 78 private static final Logger log =
75 LoggerFactory.getLogger(IntentSynchronizer.class); 79 LoggerFactory.getLogger(IntentSynchronizer.class);
...@@ -375,6 +379,7 @@ public class IntentSynchronizer implements FibListener, IntentRequestListener { ...@@ -375,6 +379,7 @@ public class IntentSynchronizer implements FibListener, IntentRequestListener {
375 .ingressPoints(ingressPorts) 379 .ingressPoints(ingressPorts)
376 .egressPoint(egressPort) 380 .egressPoint(egressPort)
377 .priority(priority) 381 .priority(priority)
382 + .constraints(CONSTRAINTS)
378 .build(); 383 .build();
379 } 384 }
380 385
...@@ -427,6 +432,7 @@ public class IntentSynchronizer implements FibListener, IntentRequestListener { ...@@ -427,6 +432,7 @@ public class IntentSynchronizer implements FibListener, IntentRequestListener {
427 .ingressPoints(ingressPoints) 432 .ingressPoints(ingressPoints)
428 .egressPoint(egressPoint) 433 .egressPoint(egressPoint)
429 .priority(priority) 434 .priority(priority)
435 + .constraints(CONSTRAINTS)
430 .build(); 436 .build();
431 437
432 log.trace("Generates ConnectivityInternetToHost intent {}", intent); 438 log.trace("Generates ConnectivityInternetToHost intent {}", intent);
...@@ -925,6 +931,7 @@ public class IntentSynchronizer implements FibListener, IntentRequestListener { ...@@ -925,6 +931,7 @@ public class IntentSynchronizer implements FibListener, IntentRequestListener {
925 .ingressPoints(ingressPoints) 931 .ingressPoints(ingressPoints)
926 .egressPoint(dstConnectPoint) 932 .egressPoint(dstConnectPoint)
927 .priority(priority) 933 .priority(priority)
934 + .constraints(CONSTRAINTS)
928 .build(); 935 .build();
929 936
930 log.trace("Generates ConnectivityHostToHost = {} ", intent); 937 log.trace("Generates ConnectivityHostToHost = {} ", intent);
...@@ -952,6 +959,7 @@ public class IntentSynchronizer implements FibListener, IntentRequestListener { ...@@ -952,6 +959,7 @@ public class IntentSynchronizer implements FibListener, IntentRequestListener {
952 .ingressPoints(ingressPoints) 959 .ingressPoints(ingressPoints)
953 .egressPoint(existingIntent.egressPoint()) 960 .egressPoint(existingIntent.egressPoint())
954 .priority(existingIntent.priority()) 961 .priority(existingIntent.priority())
962 + .constraints(CONSTRAINTS)
955 .build(); 963 .build();
956 964
957 log.trace("Update an existing MultiPointToSinglePointIntent " 965 log.trace("Update an existing MultiPointToSinglePointIntent "
......
...@@ -239,6 +239,7 @@ public class IntentSyncTest extends AbstractIntentTest { ...@@ -239,6 +239,7 @@ public class IntentSyncTest extends AbstractIntentTest {
239 .treatment(treatmentBuilder.build()) 239 .treatment(treatmentBuilder.build())
240 .ingressPoints(ingressPoints) 240 .ingressPoints(ingressPoints)
241 .egressPoint(SW1_ETH1) 241 .egressPoint(SW1_ETH1)
242 + .constraints(IntentSynchronizer.CONSTRAINTS)
242 .build(); 243 .build();
243 244
244 // Setup the expected intents 245 // Setup the expected intents
...@@ -301,6 +302,7 @@ public class IntentSyncTest extends AbstractIntentTest { ...@@ -301,6 +302,7 @@ public class IntentSyncTest extends AbstractIntentTest {
301 .treatment(treatmentBuilder.build()) 302 .treatment(treatmentBuilder.build())
302 .ingressPoints(ingressPoints) 303 .ingressPoints(ingressPoints)
303 .egressPoint(SW4_ETH1) 304 .egressPoint(SW4_ETH1)
305 + .constraints(IntentSynchronizer.CONSTRAINTS)
304 .build(); 306 .build();
305 307
306 // Setup the expected intents 308 // Setup the expected intents
...@@ -371,6 +373,7 @@ public class IntentSyncTest extends AbstractIntentTest { ...@@ -371,6 +373,7 @@ public class IntentSyncTest extends AbstractIntentTest {
371 .treatment(treatmentBuilderNew.build()) 373 .treatment(treatmentBuilderNew.build())
372 .ingressPoints(ingressPointsNew) 374 .ingressPoints(ingressPointsNew)
373 .egressPoint(SW2_ETH1) 375 .egressPoint(SW2_ETH1)
376 + .constraints(IntentSynchronizer.CONSTRAINTS)
374 .build(); 377 .build();
375 378
376 // Set up test expectation 379 // Set up test expectation
...@@ -609,6 +612,7 @@ public class IntentSyncTest extends AbstractIntentTest { ...@@ -609,6 +612,7 @@ public class IntentSyncTest extends AbstractIntentTest {
609 .treatment(treatmentBuilder.build()) 612 .treatment(treatmentBuilder.build())
610 .ingressPoints(ingressPoints) 613 .ingressPoints(ingressPoints)
611 .egressPoint(egressPoint) 614 .egressPoint(egressPoint)
615 + .constraints(IntentSynchronizer.CONSTRAINTS)
612 .build(); 616 .build();
613 return intent; 617 return intent;
614 } 618 }
......
...@@ -39,6 +39,7 @@ import org.onosproject.net.intent.Key; ...@@ -39,6 +39,7 @@ import org.onosproject.net.intent.Key;
39 import org.onosproject.net.intent.constraint.BandwidthConstraint; 39 import org.onosproject.net.intent.constraint.BandwidthConstraint;
40 import org.onosproject.net.intent.constraint.LambdaConstraint; 40 import org.onosproject.net.intent.constraint.LambdaConstraint;
41 import org.onosproject.net.intent.constraint.LinkTypeConstraint; 41 import org.onosproject.net.intent.constraint.LinkTypeConstraint;
42 +import org.onosproject.net.intent.constraint.PartialFailureConstraint;
42 import org.onosproject.net.resource.link.BandwidthResource; 43 import org.onosproject.net.resource.link.BandwidthResource;
43 import org.onlab.packet.IpPrefix; 44 import org.onlab.packet.IpPrefix;
44 import org.onlab.packet.MacAddress; 45 import org.onlab.packet.MacAddress;
...@@ -125,6 +126,10 @@ public abstract class ConnectivityIntentCommand extends AbstractShellCommand { ...@@ -125,6 +126,10 @@ public abstract class ConnectivityIntentCommand extends AbstractShellCommand {
125 required = false, multiValued = false) 126 required = false, multiValued = false)
126 private String intentKey = null; 127 private String intentKey = null;
127 128
129 + @Option(name = "--partial", description = "Allow partial installation",
130 + required = false, multiValued = false)
131 + private boolean partial = false;
132 +
128 133
129 // Treatments 134 // Treatments
130 @Option(name = "--setEthSrc", description = "Rewrite Source MAC Address", 135 @Option(name = "--setEthSrc", description = "Rewrite Source MAC Address",
...@@ -318,6 +323,10 @@ public abstract class ConnectivityIntentCommand extends AbstractShellCommand { ...@@ -318,6 +323,10 @@ public abstract class ConnectivityIntentCommand extends AbstractShellCommand {
318 } 323 }
319 constraints.add(new LinkTypeConstraint(lambda, Link.Type.OPTICAL)); 324 constraints.add(new LinkTypeConstraint(lambda, Link.Type.OPTICAL));
320 325
326 + if (partial) {
327 + constraints.add(new PartialFailureConstraint());
328 + }
329 +
321 return constraints; 330 return constraints;
322 } 331 }
323 332
......
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.constraint;
17 +
18 +import org.onosproject.net.Link;
19 +import org.onosproject.net.Path;
20 +import org.onosproject.net.intent.ConnectivityIntent;
21 +import org.onosproject.net.intent.Constraint;
22 +import org.onosproject.net.intent.Intent;
23 +import org.onosproject.net.resource.link.LinkResourceService;
24 +
25 +/**
26 + * A constraint that allows intents that can only be partially compiled
27 + * (i.e. MultiPointToSinglePointIntent or SinglePointToMultiPointIntent)
28 + * to be installed when some endpoints or paths are not found.
29 + */
30 +public class PartialFailureConstraint implements Constraint {
31 + @Override
32 + public double cost(Link link, LinkResourceService resourceService) {
33 + return 1;
34 + }
35 +
36 + @Override
37 + public boolean validate(Path path, LinkResourceService resourceService) {
38 + return true;
39 + }
40 +
41 + public static boolean intentAllowsPartialFailure(Intent intent) {
42 + if (intent instanceof ConnectivityIntent) {
43 + ConnectivityIntent connectivityIntent = (ConnectivityIntent) intent;
44 + return connectivityIntent.constraints().stream()
45 + .anyMatch(c -> c instanceof PartialFailureConstraint);
46 + }
47 + return false;
48 + }
49 +}
...@@ -25,8 +25,8 @@ import org.apache.felix.scr.annotations.Service; ...@@ -25,8 +25,8 @@ import org.apache.felix.scr.annotations.Service;
25 import org.onosproject.core.CoreService; 25 import org.onosproject.core.CoreService;
26 import org.onosproject.core.IdGenerator; 26 import org.onosproject.core.IdGenerator;
27 import org.onosproject.core.Permission; 27 import org.onosproject.core.Permission;
28 -import org.onosproject.event.ListenerRegistry;
29 import org.onosproject.event.EventDeliveryService; 28 import org.onosproject.event.EventDeliveryService;
29 +import org.onosproject.event.ListenerRegistry;
30 import org.onosproject.net.flow.FlowRule; 30 import org.onosproject.net.flow.FlowRule;
31 import org.onosproject.net.flow.FlowRuleOperations; 31 import org.onosproject.net.flow.FlowRuleOperations;
32 import org.onosproject.net.flow.FlowRuleOperationsContext; 32 import org.onosproject.net.flow.FlowRuleOperationsContext;
...@@ -64,9 +64,10 @@ import static java.util.concurrent.Executors.newFixedThreadPool; ...@@ -64,9 +64,10 @@ import static java.util.concurrent.Executors.newFixedThreadPool;
64 import static java.util.concurrent.Executors.newSingleThreadExecutor; 64 import static java.util.concurrent.Executors.newSingleThreadExecutor;
65 import static org.onlab.util.Tools.groupedThreads; 65 import static org.onlab.util.Tools.groupedThreads;
66 import static org.onosproject.net.intent.IntentState.*; 66 import static org.onosproject.net.intent.IntentState.*;
67 +import static org.onosproject.net.intent.constraint.PartialFailureConstraint.intentAllowsPartialFailure;
67 import static org.onosproject.net.intent.impl.phase.IntentProcessPhase.newInitialPhase; 68 import static org.onosproject.net.intent.impl.phase.IntentProcessPhase.newInitialPhase;
68 -import static org.slf4j.LoggerFactory.getLogger;
69 import static org.onosproject.security.AppGuard.checkPermission; 69 import static org.onosproject.security.AppGuard.checkPermission;
70 +import static org.slf4j.LoggerFactory.getLogger;
70 71
71 72
72 /** 73 /**
...@@ -85,6 +86,8 @@ public class IntentManager ...@@ -85,6 +86,8 @@ public class IntentManager
85 86
86 private static final EnumSet<IntentState> RECOMPILE 87 private static final EnumSet<IntentState> RECOMPILE
87 = EnumSet.of(INSTALL_REQ, FAILED, WITHDRAW_REQ); 88 = EnumSet.of(INSTALL_REQ, FAILED, WITHDRAW_REQ);
89 + private static final EnumSet<IntentState> WITHDRAW
90 + = EnumSet.of(WITHDRAW_REQ, WITHDRAWING, WITHDRAWN);
88 91
89 private final ListenerRegistry<IntentEvent, IntentListener> 92 private final ListenerRegistry<IntentEvent, IntentListener>
90 listenerRegistry = new ListenerRegistry<>(); 93 listenerRegistry = new ListenerRegistry<>();
...@@ -282,19 +285,18 @@ public class IntentManager ...@@ -282,19 +285,18 @@ public class IntentManager
282 submit(intent); 285 submit(intent);
283 } 286 }
284 287
285 - if (compileAllFailed) {
286 // If required, compile all currently failed intents. 288 // If required, compile all currently failed intents.
287 for (Intent intent : getIntents()) { 289 for (Intent intent : getIntents()) {
288 IntentState state = getIntentState(intent.key()); 290 IntentState state = getIntentState(intent.key());
289 - if (RECOMPILE.contains(state)) { 291 + if ((compileAllFailed && RECOMPILE.contains(state))
290 - if (state == WITHDRAW_REQ) { 292 + || intentAllowsPartialFailure(intent)) {
293 + if (WITHDRAW.contains(state)) {
291 withdraw(intent); 294 withdraw(intent);
292 } else { 295 } else {
293 submit(intent); 296 submit(intent);
294 } 297 }
295 } 298 }
296 } 299 }
297 - }
298 300
299 //FIXME 301 //FIXME
300 // for (ApplicationId appId : batches.keySet()) { 302 // for (ApplicationId appId : batches.keySet()) {
......
...@@ -276,31 +276,28 @@ public class ObjectiveTracker implements ObjectiveTrackerService { ...@@ -276,31 +276,28 @@ public class ObjectiveTracker implements ObjectiveTrackerService {
276 delegate.triggerCompile(Collections.emptySet(), true); 276 delegate.triggerCompile(Collections.emptySet(), true);
277 277
278 } else { 278 } else {
279 - Set<Key> toBeRecompiled = new HashSet<>(); 279 + Set<Key> intentsToRecompile = new HashSet<>();
280 - boolean recompileOnly = true; 280 + boolean dontRecompileAllFailedIntents = true;
281 281
282 // Scan through the list of reasons and keep accruing all 282 // Scan through the list of reasons and keep accruing all
283 // intents that need to be recompiled. 283 // intents that need to be recompiled.
284 for (Event reason : event.reasons()) { 284 for (Event reason : event.reasons()) {
285 if (reason instanceof LinkEvent) { 285 if (reason instanceof LinkEvent) {
286 LinkEvent linkEvent = (LinkEvent) reason; 286 LinkEvent linkEvent = (LinkEvent) reason;
287 - if (linkEvent.type() == LINK_REMOVED
288 - || (linkEvent.type() == LINK_UPDATED &&
289 - linkEvent.subject().isDurable())) {
290 final LinkKey linkKey = linkKey(linkEvent.subject()); 287 final LinkKey linkKey = linkKey(linkEvent.subject());
291 synchronized (intentsByLink) { 288 synchronized (intentsByLink) {
292 Set<Key> intentKeys = intentsByLink.get(linkKey); 289 Set<Key> intentKeys = intentsByLink.get(linkKey);
293 - log.debug("recompile triggered by LinkDown {} {}", linkKey, intentKeys); 290 + log.debug("recompile triggered by LinkEvent {} ({}) for {}",
294 - toBeRecompiled.addAll(intentKeys); 291 + linkKey, linkEvent.type(), intentKeys);
292 + intentsToRecompile.addAll(intentKeys);
295 } 293 }
296 - } 294 + dontRecompileAllFailedIntents = dontRecompileAllFailedIntents &&
297 - recompileOnly = recompileOnly &&
298 (linkEvent.type() == LINK_REMOVED || 295 (linkEvent.type() == LINK_REMOVED ||
299 (linkEvent.type() == LINK_UPDATED && 296 (linkEvent.type() == LINK_UPDATED &&
300 linkEvent.subject().isDurable())); 297 linkEvent.subject().isDurable()));
301 } 298 }
302 } 299 }
303 - delegate.triggerCompile(toBeRecompiled, !recompileOnly); 300 + delegate.triggerCompile(intentsToRecompile, !dontRecompileAllFailedIntents);
304 } 301 }
305 } 302 }
306 } 303 }
......
...@@ -15,12 +15,8 @@ ...@@ -15,12 +15,8 @@
15 */ 15 */
16 package org.onosproject.net.intent.impl.compiler; 16 package org.onosproject.net.intent.impl.compiler;
17 17
18 -import java.util.Collections; 18 +import com.google.common.collect.ImmutableSet;
19 -import java.util.HashMap; 19 +import com.google.common.collect.Sets;
20 -import java.util.List;
21 -import java.util.Map;
22 -import java.util.Set;
23 -
24 import org.apache.felix.scr.annotations.Activate; 20 import org.apache.felix.scr.annotations.Activate;
25 import org.apache.felix.scr.annotations.Component; 21 import org.apache.felix.scr.annotations.Component;
26 import org.apache.felix.scr.annotations.Deactivate; 22 import org.apache.felix.scr.annotations.Deactivate;
...@@ -30,20 +26,25 @@ import org.onosproject.net.ConnectPoint; ...@@ -30,20 +26,25 @@ import org.onosproject.net.ConnectPoint;
30 import org.onosproject.net.DeviceId; 26 import org.onosproject.net.DeviceId;
31 import org.onosproject.net.Link; 27 import org.onosproject.net.Link;
32 import org.onosproject.net.Path; 28 import org.onosproject.net.Path;
29 +import org.onosproject.net.device.DeviceService;
33 import org.onosproject.net.intent.Intent; 30 import org.onosproject.net.intent.Intent;
34 import org.onosproject.net.intent.IntentCompiler; 31 import org.onosproject.net.intent.IntentCompiler;
32 +import org.onosproject.net.intent.IntentException;
35 import org.onosproject.net.intent.IntentExtensionService; 33 import org.onosproject.net.intent.IntentExtensionService;
36 import org.onosproject.net.intent.LinkCollectionIntent; 34 import org.onosproject.net.intent.LinkCollectionIntent;
37 import org.onosproject.net.intent.MultiPointToSinglePointIntent; 35 import org.onosproject.net.intent.MultiPointToSinglePointIntent;
38 import org.onosproject.net.intent.PointToPointIntent; 36 import org.onosproject.net.intent.PointToPointIntent;
39 -import org.onosproject.net.intent.impl.PathNotFoundException;
40 import org.onosproject.net.resource.link.LinkResourceAllocations; 37 import org.onosproject.net.resource.link.LinkResourceAllocations;
41 import org.onosproject.net.topology.PathService; 38 import org.onosproject.net.topology.PathService;
42 39
43 -import com.google.common.collect.ImmutableSet; 40 +import java.util.Collections;
44 -import com.google.common.collect.Sets; 41 +import java.util.HashMap;
42 +import java.util.List;
43 +import java.util.Map;
44 +import java.util.Set;
45 45
46 import static org.onosproject.net.DefaultEdgeLink.createEdgeLink; 46 import static org.onosproject.net.DefaultEdgeLink.createEdgeLink;
47 +import static org.onosproject.net.intent.constraint.PartialFailureConstraint.intentAllowsPartialFailure;
47 48
48 /** 49 /**
49 * An intent compiler for 50 * An intent compiler for
...@@ -59,6 +60,9 @@ public class MultiPointToSinglePointIntentCompiler ...@@ -59,6 +60,9 @@ public class MultiPointToSinglePointIntentCompiler
59 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 60 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
60 protected PathService pathService; 61 protected PathService pathService;
61 62
63 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
64 + protected DeviceService deviceService;
65 +
62 @Activate 66 @Activate
63 public void activate() { 67 public void activate() {
64 intentManager.registerCompiler(MultiPointToSinglePointIntent.class, this); 68 intentManager.registerCompiler(MultiPointToSinglePointIntent.class, this);
...@@ -76,12 +80,22 @@ public class MultiPointToSinglePointIntentCompiler ...@@ -76,12 +80,22 @@ public class MultiPointToSinglePointIntentCompiler
76 Map<DeviceId, Link> edgeLinks = new HashMap<>(); 80 Map<DeviceId, Link> edgeLinks = new HashMap<>();
77 ConnectPoint egressPoint = intent.egressPoint(); 81 ConnectPoint egressPoint = intent.egressPoint();
78 82
83 + final boolean allowMissingPaths = intentAllowsPartialFailure(intent);
84 + boolean partialTree = false;
85 + boolean anyMissingPaths = false;
79 for (ConnectPoint ingressPoint : intent.ingressPoints()) { 86 for (ConnectPoint ingressPoint : intent.ingressPoints()) {
80 if (ingressPoint.deviceId().equals(egressPoint.deviceId())) { 87 if (ingressPoint.deviceId().equals(egressPoint.deviceId())) {
88 + if (deviceService.isAvailable(ingressPoint.deviceId())) {
89 + partialTree = true;
81 edgeLinks.put(ingressPoint.deviceId(), createEdgeLink(ingressPoint, true)); 90 edgeLinks.put(ingressPoint.deviceId(), createEdgeLink(ingressPoint, true));
82 edgeLinks.put(egressPoint.deviceId(), createEdgeLink(egressPoint, false)); 91 edgeLinks.put(egressPoint.deviceId(), createEdgeLink(egressPoint, false));
83 } else { 92 } else {
93 + anyMissingPaths = true;
94 + }
95 + } else {
84 Path path = getPath(ingressPoint, intent.egressPoint()); 96 Path path = getPath(ingressPoint, intent.egressPoint());
97 + if (path != null) {
98 + partialTree = true;
85 for (Link link : path.links()) { 99 for (Link link : path.links()) {
86 if (links.containsKey(link.src().deviceId())) { 100 if (links.containsKey(link.src().deviceId())) {
87 // We've already reached the existing tree with the first 101 // We've already reached the existing tree with the first
...@@ -94,9 +108,18 @@ public class MultiPointToSinglePointIntentCompiler ...@@ -94,9 +108,18 @@ public class MultiPointToSinglePointIntentCompiler
94 108
95 links.put(link.src().deviceId(), link); 109 links.put(link.src().deviceId(), link);
96 } 110 }
111 + } else {
112 + anyMissingPaths = true;
113 + }
97 } 114 }
98 } 115 }
99 116
117 + if (!partialTree) {
118 + throw new IntentException("Could not find any paths between ingress and egress points.");
119 + } else if (!allowMissingPaths && anyMissingPaths) {
120 + throw new IntentException("Missing some paths between ingress and egress ports.");
121 + }
122 +
100 Set<Link> allLinks = Sets.newHashSet(links.values()); 123 Set<Link> allLinks = Sets.newHashSet(links.values());
101 allLinks.addAll(edgeLinks.values()); 124 allLinks.addAll(edgeLinks.values());
102 Intent result = LinkCollectionIntent.builder() 125 Intent result = LinkCollectionIntent.builder()
...@@ -119,12 +142,11 @@ public class MultiPointToSinglePointIntentCompiler ...@@ -119,12 +142,11 @@ public class MultiPointToSinglePointIntentCompiler
119 * @param one start of the path 142 * @param one start of the path
120 * @param two end of the path 143 * @param two end of the path
121 * @return Path between the two 144 * @return Path between the two
122 - * @throws org.onosproject.net.intent.impl.PathNotFoundException if a path cannot be found
123 */ 145 */
124 private Path getPath(ConnectPoint one, ConnectPoint two) { 146 private Path getPath(ConnectPoint one, ConnectPoint two) {
125 Set<Path> paths = pathService.getPaths(one.deviceId(), two.deviceId()); 147 Set<Path> paths = pathService.getPaths(one.deviceId(), two.deviceId());
126 if (paths.isEmpty()) { 148 if (paths.isEmpty()) {
127 - throw new PathNotFoundException(one.elementId(), two.elementId()); 149 + return null;
128 } 150 }
129 // TODO: let's be more intelligent about this eventually 151 // TODO: let's be more intelligent about this eventually
130 return paths.iterator().next(); 152 return paths.iterator().next();
......
...@@ -15,17 +15,15 @@ ...@@ -15,17 +15,15 @@
15 */ 15 */
16 package org.onosproject.net.intent.impl.compiler; 16 package org.onosproject.net.intent.impl.compiler;
17 17
18 -import java.util.HashSet;
19 -import java.util.List;
20 -import java.util.Set;
21 -
22 import org.hamcrest.Matchers; 18 import org.hamcrest.Matchers;
23 import org.junit.Test; 19 import org.junit.Test;
24 import org.onosproject.TestApplicationId; 20 import org.onosproject.TestApplicationId;
25 import org.onosproject.core.ApplicationId; 21 import org.onosproject.core.ApplicationId;
26 import org.onosproject.net.ConnectPoint; 22 import org.onosproject.net.ConnectPoint;
23 +import org.onosproject.net.DeviceId;
27 import org.onosproject.net.ElementId; 24 import org.onosproject.net.ElementId;
28 import org.onosproject.net.Path; 25 import org.onosproject.net.Path;
26 +import org.onosproject.net.device.DeviceServiceAdapter;
29 import org.onosproject.net.flow.TrafficSelector; 27 import org.onosproject.net.flow.TrafficSelector;
30 import org.onosproject.net.flow.TrafficTreatment; 28 import org.onosproject.net.flow.TrafficTreatment;
31 import org.onosproject.net.intent.AbstractIntentTest; 29 import org.onosproject.net.intent.AbstractIntentTest;
...@@ -36,6 +34,10 @@ import org.onosproject.net.intent.MultiPointToSinglePointIntent; ...@@ -36,6 +34,10 @@ import org.onosproject.net.intent.MultiPointToSinglePointIntent;
36 import org.onosproject.net.topology.LinkWeight; 34 import org.onosproject.net.topology.LinkWeight;
37 import org.onosproject.net.topology.PathService; 35 import org.onosproject.net.topology.PathService;
38 36
37 +import java.util.HashSet;
38 +import java.util.List;
39 +import java.util.Set;
40 +
39 import static org.hamcrest.CoreMatchers.instanceOf; 41 import static org.hamcrest.CoreMatchers.instanceOf;
40 import static org.hamcrest.CoreMatchers.notNullValue; 42 import static org.hamcrest.CoreMatchers.notNullValue;
41 import static org.hamcrest.MatcherAssert.assertThat; 43 import static org.hamcrest.MatcherAssert.assertThat;
...@@ -92,6 +94,16 @@ public class MultiPointToSinglePointIntentCompilerTest extends AbstractIntentTes ...@@ -92,6 +94,16 @@ public class MultiPointToSinglePointIntentCompilerTest extends AbstractIntentTes
92 } 94 }
93 95
94 /** 96 /**
97 + * Mocks the device service so that a device appears available in the test.
98 + */
99 + private static class MockDeviceService extends DeviceServiceAdapter {
100 + @Override
101 + public boolean isAvailable(DeviceId deviceId) {
102 + return true;
103 + }
104 + }
105 +
106 + /**
95 * Creates a MultiPointToSinglePoint intent for a group of ingress points 107 * Creates a MultiPointToSinglePoint intent for a group of ingress points
96 * and an egress point. 108 * and an egress point.
97 * 109 *
...@@ -126,6 +138,7 @@ public class MultiPointToSinglePointIntentCompilerTest extends AbstractIntentTes ...@@ -126,6 +138,7 @@ public class MultiPointToSinglePointIntentCompilerTest extends AbstractIntentTes
126 MultiPointToSinglePointIntentCompiler compiler = 138 MultiPointToSinglePointIntentCompiler compiler =
127 new MultiPointToSinglePointIntentCompiler(); 139 new MultiPointToSinglePointIntentCompiler();
128 compiler.pathService = new MockPathService(hops); 140 compiler.pathService = new MockPathService(hops);
141 + compiler.deviceService = new MockDeviceService();
129 return compiler; 142 return compiler;
130 } 143 }
131 144
......
...@@ -151,6 +151,7 @@ import org.onosproject.net.intent.constraint.LambdaConstraint; ...@@ -151,6 +151,7 @@ import org.onosproject.net.intent.constraint.LambdaConstraint;
151 import org.onosproject.net.intent.constraint.LatencyConstraint; 151 import org.onosproject.net.intent.constraint.LatencyConstraint;
152 import org.onosproject.net.intent.constraint.LinkTypeConstraint; 152 import org.onosproject.net.intent.constraint.LinkTypeConstraint;
153 import org.onosproject.net.intent.constraint.ObstacleConstraint; 153 import org.onosproject.net.intent.constraint.ObstacleConstraint;
154 +import org.onosproject.net.intent.constraint.PartialFailureConstraint;
154 import org.onosproject.net.intent.constraint.WaypointConstraint; 155 import org.onosproject.net.intent.constraint.WaypointConstraint;
155 import org.onosproject.net.link.DefaultLinkDescription; 156 import org.onosproject.net.link.DefaultLinkDescription;
156 import org.onosproject.net.packet.DefaultOutboundPacket; 157 import org.onosproject.net.packet.DefaultOutboundPacket;
...@@ -389,6 +390,7 @@ public final class KryoNamespaces { ...@@ -389,6 +390,7 @@ public final class KryoNamespaces {
389 ObstacleConstraint.class, 390 ObstacleConstraint.class,
390 AnnotationConstraint.class, 391 AnnotationConstraint.class,
391 BooleanConstraint.class, 392 BooleanConstraint.class,
393 + PartialFailureConstraint.class,
392 IntentOperation.class, 394 IntentOperation.class,
393 FlowRuleExtPayLoad.class, 395 FlowRuleExtPayLoad.class,
394 Frequency.class, 396 Frequency.class,
......