Yuta HIGUCHI
Committed by Gerrit Code Review

Fixing Protected P2PIntent Compiler issues

- Register ProtectionConstraint
- Workaround for NPE in P2PIntent Compiler
  buildFailoverTreatment sometimes throw NPE,
  when the Group was not available by the time building the head-end treatment.
- debug log and cosmetic fixes

This might be related to ONOS-5183

Change-Id: I5ffc78619951fd8c4a35e985b3b849a1702080e8
...@@ -203,6 +203,7 @@ public class DefaultGroupDescription implements GroupDescription { ...@@ -203,6 +203,7 @@ public class DefaultGroupDescription implements GroupDescription {
203 .add("type", type) 203 .add("type", type)
204 .add("buckets", buckets) 204 .add("buckets", buckets)
205 .add("appId", appId) 205 .add("appId", appId)
206 + .add("appCookie", appCookie)
206 .add("givenGroupId", givenGroupId) 207 .add("givenGroupId", givenGroupId)
207 .toString(); 208 .toString();
208 } 209 }
......
...@@ -46,9 +46,11 @@ import org.onosproject.net.group.GroupBucket; ...@@ -46,9 +46,11 @@ import org.onosproject.net.group.GroupBucket;
46 import org.onosproject.net.group.GroupBuckets; 46 import org.onosproject.net.group.GroupBuckets;
47 import org.onosproject.net.group.GroupDescription; 47 import org.onosproject.net.group.GroupDescription;
48 import org.onosproject.net.group.GroupKey; 48 import org.onosproject.net.group.GroupKey;
49 +import org.onosproject.net.group.GroupListener;
49 import org.onosproject.net.group.GroupService; 50 import org.onosproject.net.group.GroupService;
50 import org.onosproject.net.intent.FlowRuleIntent; 51 import org.onosproject.net.intent.FlowRuleIntent;
51 import org.onosproject.net.intent.Intent; 52 import org.onosproject.net.intent.Intent;
53 +import org.onosproject.net.intent.IntentCompilationException;
52 import org.onosproject.net.intent.IntentId; 54 import org.onosproject.net.intent.IntentId;
53 import org.onosproject.net.intent.PathIntent; 55 import org.onosproject.net.intent.PathIntent;
54 import org.onosproject.net.intent.PointToPointIntent; 56 import org.onosproject.net.intent.PointToPointIntent;
...@@ -56,6 +58,7 @@ import org.onosproject.net.intent.constraint.ProtectionConstraint; ...@@ -56,6 +58,7 @@ import org.onosproject.net.intent.constraint.ProtectionConstraint;
56 import org.onosproject.net.intent.impl.PathNotFoundException; 58 import org.onosproject.net.intent.impl.PathNotFoundException;
57 import org.onosproject.net.link.LinkService; 59 import org.onosproject.net.link.LinkService;
58 import org.onosproject.net.provider.ProviderId; 60 import org.onosproject.net.provider.ProviderId;
61 +import org.slf4j.Logger;
59 62
60 import java.nio.ByteBuffer; 63 import java.nio.ByteBuffer;
61 import java.util.ArrayList; 64 import java.util.ArrayList;
...@@ -63,9 +66,14 @@ import java.util.Collections; ...@@ -63,9 +66,14 @@ import java.util.Collections;
63 import java.util.Iterator; 66 import java.util.Iterator;
64 import java.util.List; 67 import java.util.List;
65 import java.util.ListIterator; 68 import java.util.ListIterator;
69 +import java.util.concurrent.CompletableFuture;
70 +import java.util.concurrent.ExecutionException;
71 +import java.util.concurrent.TimeUnit;
72 +import java.util.concurrent.TimeoutException;
66 73
67 import static java.util.Arrays.asList; 74 import static java.util.Arrays.asList;
68 import static org.onosproject.net.DefaultEdgeLink.createEdgeLink; 75 import static org.onosproject.net.DefaultEdgeLink.createEdgeLink;
76 +import static org.slf4j.LoggerFactory.getLogger;
69 77
70 /** 78 /**
71 * An intent compiler for {@link org.onosproject.net.intent.PointToPointIntent}. 79 * An intent compiler for {@link org.onosproject.net.intent.PointToPointIntent}.
...@@ -79,7 +87,13 @@ public class PointToPointIntentCompiler ...@@ -79,7 +87,13 @@ public class PointToPointIntentCompiler
79 new ProviderId("core", "org.onosproject.core", true); 87 new ProviderId("core", "org.onosproject.core", true);
80 // TODO: consider whether the default cost is appropriate or not 88 // TODO: consider whether the default cost is appropriate or not
81 public static final int DEFAULT_COST = 1; 89 public static final int DEFAULT_COST = 1;
90 +
82 protected static final int PRIORITY = Intent.DEFAULT_INTENT_PRIORITY; 91 protected static final int PRIORITY = Intent.DEFAULT_INTENT_PRIORITY;
92 +
93 + private static final int GROUP_TIMEOUT = 5;
94 +
95 + private final Logger log = getLogger(getClass());
96 +
83 protected boolean erasePrimary = false; 97 protected boolean erasePrimary = false;
84 protected boolean eraseBackup = false; 98 protected boolean eraseBackup = false;
85 99
...@@ -104,7 +118,7 @@ public class PointToPointIntentCompiler ...@@ -104,7 +118,7 @@ public class PointToPointIntentCompiler
104 118
105 @Override 119 @Override
106 public List<Intent> compile(PointToPointIntent intent, List<Intent> installable) { 120 public List<Intent> compile(PointToPointIntent intent, List<Intent> installable) {
107 - 121 + log.trace("compiling {} {}", intent, installable);
108 ConnectPoint ingressPoint = intent.ingressPoint(); 122 ConnectPoint ingressPoint = intent.ingressPoint();
109 ConnectPoint egressPoint = intent.egressPoint(); 123 ConnectPoint egressPoint = intent.egressPoint();
110 124
...@@ -121,6 +135,7 @@ public class PointToPointIntentCompiler ...@@ -121,6 +135,7 @@ public class PointToPointIntentCompiler
121 // attempt to compute and implement backup path 135 // attempt to compute and implement backup path
122 return createProtectedIntent(ingressPoint, egressPoint, intent, installable); 136 return createProtectedIntent(ingressPoint, egressPoint, intent, installable);
123 } catch (PathNotFoundException e) { 137 } catch (PathNotFoundException e) {
138 + log.warn("Could not find disjoint Path for {}", intent);
124 // no disjoint path extant -- maximum one path exists between devices 139 // no disjoint path extant -- maximum one path exists between devices
125 return createSinglePathIntent(ingressPoint, egressPoint, intent, installable); 140 return createSinglePathIntent(ingressPoint, egressPoint, intent, installable);
126 } 141 }
...@@ -155,6 +170,7 @@ public class PointToPointIntentCompiler ...@@ -155,6 +170,7 @@ public class PointToPointIntentCompiler
155 ConnectPoint egressPoint, 170 ConnectPoint egressPoint,
156 PointToPointIntent intent, 171 PointToPointIntent intent,
157 List<Intent> installable) { 172 List<Intent> installable) {
173 + log.trace("createProtectedIntent");
158 DisjointPath path = getDisjointPath(intent, ingressPoint.deviceId(), 174 DisjointPath path = getDisjointPath(intent, ingressPoint.deviceId(),
159 egressPoint.deviceId()); 175 egressPoint.deviceId());
160 176
...@@ -208,10 +224,12 @@ public class PointToPointIntentCompiler ...@@ -208,10 +224,12 @@ public class PointToPointIntentCompiler
208 } 224 }
209 } 225 }
210 226
211 - intentList.add(createPathIntent(new DefaultPath(PID, links, path.cost(), path.annotations()), 227 + intentList.add(createPathIntent(new DefaultPath(PID, links, path.cost(),
228 + path.annotations()),
212 intent, PathIntent.ProtectionType.PRIMARY)); 229 intent, PathIntent.ProtectionType.PRIMARY));
213 intentList.add(createPathIntent(new DefaultPath(PID, backupLinks, path.backup().cost(), 230 intentList.add(createPathIntent(new DefaultPath(PID, backupLinks, path.backup().cost(),
214 - path.backup().annotations()), intent, PathIntent.ProtectionType.BACKUP)); 231 + path.backup().annotations()),
232 + intent, PathIntent.ProtectionType.BACKUP));
215 233
216 // Create fast failover flow rule intent or, if it already exists, 234 // Create fast failover flow rule intent or, if it already exists,
217 // add contents appropriately. 235 // add contents appropriately.
...@@ -354,6 +372,7 @@ public class PointToPointIntentCompiler ...@@ -354,6 +372,7 @@ public class PointToPointIntentCompiler
354 372
355 GroupDescription groupDesc = new DefaultGroupDescription(src.deviceId(), Group.Type.FAILOVER, 373 GroupDescription groupDesc = new DefaultGroupDescription(src.deviceId(), Group.Type.FAILOVER,
356 groupBuckets, makeGroupKey(intent.id()), null, intent.appId()); 374 groupBuckets, makeGroupKey(intent.id()), null, intent.appId());
375 + log.trace("adding failover group {}", groupDesc);
357 groupService.addGroup(groupDesc); 376 groupService.addGroup(groupDesc);
358 } 377 }
359 378
...@@ -387,9 +406,75 @@ public class PointToPointIntentCompiler ...@@ -387,9 +406,75 @@ public class PointToPointIntentCompiler
387 return flowRules; 406 return flowRules;
388 } 407 }
389 408
409 +
410 + /**
411 + * Waits for specified group to appear maximum of {@value #GROUP_TIMEOUT} seconds.
412 + *
413 + * @param deviceId {@link DeviceId}
414 + * @param groupKey {@link GroupKey} to wait for.
415 + * @return {@link Group}
416 + * @throws IntentCompilationException on any error.
417 + */
418 + private Group waitForGroup(DeviceId deviceId, GroupKey groupKey) {
419 + return waitForGroup(deviceId, groupKey, GROUP_TIMEOUT, TimeUnit.SECONDS);
420 + }
421 +
422 + /**
423 + * Waits for specified group to appear until timeout.
424 + *
425 + * @param deviceId {@link DeviceId}
426 + * @param groupKey {@link GroupKey} to wait for.
427 + * @param timeout timeout
428 + * @param unit unit of timeout
429 + * @return {@link Group}
430 + * @throws IntentCompilationException on any error.
431 + */
432 + private Group waitForGroup(DeviceId deviceId, GroupKey groupKey, long timeout, TimeUnit unit) {
433 + Group group = groupService.getGroup(deviceId, groupKey);
434 + if (group != null) {
435 + return group;
436 + }
437 +
438 + final CompletableFuture<Group> future = new CompletableFuture<>();
439 + final GroupListener listener = event -> {
440 + if (event.subject().deviceId() == deviceId &&
441 + event.subject().appCookie().equals(groupKey)) {
442 + future.complete(event.subject());
443 + return;
444 + }
445 + };
446 +
447 + groupService.addListener(listener);
448 + try {
449 + group = groupService.getGroup(deviceId, groupKey);
450 + if (group != null) {
451 + return group;
452 + }
453 + return future.get(timeout, unit);
454 + } catch (InterruptedException e) {
455 + log.debug("Interrupted", e);
456 + Thread.currentThread().interrupt();
457 + throw new IntentCompilationException("Interrupted", e);
458 + } catch (ExecutionException e) {
459 + log.debug("ExecutionException", e);
460 + throw new IntentCompilationException("ExecutionException caught", e);
461 + } catch (TimeoutException e) {
462 + // one last try
463 + group = groupService.getGroup(deviceId, groupKey);
464 + if (group != null) {
465 + return group;
466 + } else {
467 + log.debug("Timeout", e);
468 + throw new IntentCompilationException("Timeout", e);
469 + }
470 + } finally {
471 + groupService.removeListener(listener);
472 + }
473 + }
474 +
390 private TrafficTreatment buildFailoverTreatment(DeviceId srcDevice, 475 private TrafficTreatment buildFailoverTreatment(DeviceId srcDevice,
391 GroupKey groupKey) { 476 GroupKey groupKey) {
392 - Group group = groupService.getGroup(srcDevice, groupKey); 477 + Group group = waitForGroup(srcDevice, groupKey);
393 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); 478 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
394 TrafficTreatment trafficTreatment = tBuilder.group(group.id()).build(); 479 TrafficTreatment trafficTreatment = tBuilder.group(group.id()).build();
395 return trafficTreatment; 480 return trafficTreatment;
...@@ -509,7 +594,7 @@ public class PointToPointIntentCompiler ...@@ -509,7 +594,7 @@ public class PointToPointIntentCompiler
509 private void updateFailoverGroup(PointToPointIntent pointIntent) { 594 private void updateFailoverGroup(PointToPointIntent pointIntent) {
510 DeviceId deviceId = pointIntent.ingressPoint().deviceId(); 595 DeviceId deviceId = pointIntent.ingressPoint().deviceId();
511 GroupKey groupKey = makeGroupKey(pointIntent.id()); 596 GroupKey groupKey = makeGroupKey(pointIntent.id());
512 - Group group = groupService.getGroup(deviceId, groupKey); 597 + Group group = waitForGroup(deviceId, groupKey);
513 Iterator<GroupBucket> groupIterator = group.buckets().buckets().iterator(); 598 Iterator<GroupBucket> groupIterator = group.buckets().buckets().iterator();
514 while (groupIterator.hasNext()) { 599 while (groupIterator.hasNext()) {
515 GroupBucket bucket = groupIterator.next(); 600 GroupBucket bucket = groupIterator.next();
......
...@@ -189,6 +189,7 @@ import org.onosproject.net.intent.constraint.LatencyConstraint; ...@@ -189,6 +189,7 @@ import org.onosproject.net.intent.constraint.LatencyConstraint;
189 import org.onosproject.net.intent.constraint.LinkTypeConstraint; 189 import org.onosproject.net.intent.constraint.LinkTypeConstraint;
190 import org.onosproject.net.intent.constraint.ObstacleConstraint; 190 import org.onosproject.net.intent.constraint.ObstacleConstraint;
191 import org.onosproject.net.intent.constraint.PartialFailureConstraint; 191 import org.onosproject.net.intent.constraint.PartialFailureConstraint;
192 +import org.onosproject.net.intent.constraint.ProtectionConstraint;
192 import org.onosproject.net.intent.constraint.WaypointConstraint; 193 import org.onosproject.net.intent.constraint.WaypointConstraint;
193 import org.onosproject.net.link.DefaultLinkDescription; 194 import org.onosproject.net.link.DefaultLinkDescription;
194 import org.onosproject.net.meter.MeterId; 195 import org.onosproject.net.meter.MeterId;
...@@ -550,6 +551,7 @@ public final class KryoNamespaces { ...@@ -550,6 +551,7 @@ public final class KryoNamespaces {
550 .register(DiscreteResourceCodec.class) 551 .register(DiscreteResourceCodec.class)
551 .register(new ImmutableByteSequenceSerializer(), ImmutableByteSequence.class) 552 .register(new ImmutableByteSequenceSerializer(), ImmutableByteSequence.class)
552 .register(PathIntent.ProtectionType.class) 553 .register(PathIntent.ProtectionType.class)
554 + .register(ProtectionConstraint.class)
553 .build("API"); 555 .build("API");
554 556
555 /** 557 /**
......