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