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
Showing
3 changed files
with
93 additions
and
5 deletions
... | @@ -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 | /** | ... | ... |
-
Please register or login to post a comment