Avoid high-lighting wrong link
Change-Id: I4b8f8c73a048d030e4517beb474b11ce848a5574
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/ProtectedIntentMonitor.java b/web/gui/src/main/java/org/onosproject/ui/impl/ProtectedIntentMonitor.java
index 3a92428..81561c6 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/ProtectedIntentMonitor.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/ProtectedIntentMonitor.java
@@ -18,14 +18,18 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
+
+
+import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
import org.onosproject.net.ElementId;
import org.onosproject.net.HostId;
import org.onosproject.net.Link;
-import org.onosproject.net.MarkerResource;
-import org.onosproject.net.NetworkResource;
-import org.onosproject.net.behaviour.protection.TransportEndpointDescription;
+import org.onosproject.net.flow.criteria.Criterion;
+import org.onosproject.net.flow.criteria.PortCriterion;
+import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
import org.onosproject.net.intent.FlowRuleIntent;
import org.onosproject.net.intent.Intent;
import org.onosproject.net.intent.OpticalConnectivityIntent;
@@ -45,12 +49,17 @@
import org.slf4j.LoggerFactory;
import java.util.Collection;
-import java.util.HashSet;
+import java.util.LinkedHashSet;
import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
+import java.util.stream.Collectors;
+import static org.onosproject.net.MarkerResource.marker;
import static org.onosproject.ui.impl.ProtectedIntentMonitor.ProtectedMode.IDLE;
import static org.onosproject.ui.impl.ProtectedIntentMonitor.ProtectedMode.SELECTED_INTENT;
@@ -192,24 +201,46 @@
if (selectedIntent != null) {
List<Intent> installables = servicesBundle.intentService()
.getInstallableIntents(selectedIntent.key());
- Set<Link> primary = new HashSet<>();
- Set<Link> backup = new HashSet<>();
+
if (installables != null) {
- //There should be exactly two FlowRuleIntent and four
- //ProtectionEndpointIntent for each ProtectedTransportIntent.
- for (Intent installable : installables) {
- if (installable instanceof FlowRuleIntent) {
- handleFlowRuleIntent(primary, backup, (FlowRuleIntent) installable);
- } else if (installable instanceof ProtectionEndpointIntent) {
- handleProtectionEndpointIntent(primary, backup,
- (ProtectionEndpointIntent) installable);
- } else {
- log.warn("Intent {} is not an expected installable type {} " +
- "related to ProtectedTransportIntent",
- installable.id(), installable.getClass().getSimpleName());
- stopMonitoring();
- }
+ ProtectionEndpointIntent ep1 = installables.stream()
+ .filter(ProtectionEndpointIntent.class::isInstance)
+ .map(ProtectionEndpointIntent.class::cast)
+ .findFirst().orElse(null);
+ ProtectionEndpointIntent ep2 = installables.stream()
+ .filter(ii -> !ii.equals(ep1))
+ .filter(ProtectionEndpointIntent.class::isInstance)
+ .map(ProtectionEndpointIntent.class::cast)
+ .findFirst().orElse(null);
+ if (ep1 == null || ep2 == null) {
+ log.warn("Selected Intent {} didn't have 2 protection endpoints",
+ selectedIntent.key());
+ stopMonitoring();
+ return highlights;
}
+ Set<Link> primary = new LinkedHashSet<>();
+ Set<Link> backup = new LinkedHashSet<>();
+
+ Map<Boolean, List<FlowRuleIntent>> transits = installables.stream()
+ .filter(FlowRuleIntent.class::isInstance)
+ .map(FlowRuleIntent.class::cast)
+ // only consider fwd links so that ants march in one direction
+ // TODO: ⇅didn't help need further investigation.
+ //.filter(i -> !i.resources().contains(marker("rev")))
+ .collect(Collectors.groupingBy(this::isPrimary));
+
+ // walk primary
+ ConnectPoint primHead = ep1.description().paths().get(0).output().connectPoint();
+ ConnectPoint primTail = ep2.description().paths().get(0).output().connectPoint();
+ List<FlowRuleIntent> primTransit = transits.getOrDefault(true, ImmutableList.of());
+ populateLinks(primary, primHead, primTail, primTransit);
+
+ // walk backup
+ ConnectPoint backHead = ep1.description().paths().get(1).output().connectPoint();
+ ConnectPoint backTail = ep2.description().paths().get(1).output().connectPoint();
+ List<FlowRuleIntent> backTransit = transits.getOrDefault(false, ImmutableList.of());
+ populateLinks(backup, backHead, backTail, backTransit);
+
boolean isOptical = selectedIntent instanceof OpticalConnectivityIntent;
//last parameter (traffic) signals if the link is highlited with ants or solid line
//Flavor is swapped so green is primary path.
@@ -223,6 +254,7 @@
processLinks(linkMap, backup, Flavor.SECONDARY_HIGHLIGHT,
isOptical, false, PROTECTED_MOD_BACKUP_SET);
}
+
updateHighlights(highlights, primary);
updateHighlights(highlights, backup);
colorLinks(highlights, linkMap);
@@ -238,31 +270,75 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- private void handleProtectionEndpointIntent(Set<Link> primary, Set<Link> backup,
- ProtectionEndpointIntent peIntent) {
- TransportEndpointDescription primaryDesc = peIntent
- .description().paths().get(0);
- TransportEndpointDescription secondaryDesc = peIntent
- .description().paths().get(1);
- primary.addAll(servicesBundle.linkService()
- .getLinks(primaryDesc.output()
- .connectPoint()));
- backup.addAll(servicesBundle.linkService()
- .getLinks(secondaryDesc.output()
- .connectPoint()));
+ /**
+ * Populate Links along the primary/backup path.
+ *
+ * @param links link collection to populate [output]
+ * @param head head-end of primary/backup path
+ * @param tail tail-end of primary/backup path
+ * @param transit Intents if any
+ */
+ private void populateLinks(Set<Link> links,
+ ConnectPoint head,
+ ConnectPoint tail,
+ List<FlowRuleIntent> transit) {
+ // find first hop link
+ Link first = transit.stream()
+ // search for Link head -> transit Intent head
+ // as first candidate of 1st hop Link
+ .flatMap(fri -> fri.flowRules().stream())
+ .map(fr ->
+ // find first input port from FlowRule
+ Optional.ofNullable(fr.selector().getCriterion(Criterion.Type.IN_PORT))
+ .filter(PortCriterion.class::isInstance)
+ .map(PortCriterion.class::cast)
+ .map(PortCriterion::port)
+ .map(pn -> new ConnectPoint(fr.deviceId(), pn))
+ .orElse(null)
+ ).filter(Objects::nonNull)
+ .map(dst -> servicesBundle.linkService().getLink(head, dst))
+ .filter(Objects::nonNull)
+ .findFirst()
+ // if there isn't one probably 1 hop to the tail
+ .orElse(servicesBundle.linkService().getLink(head, tail));
+
+ // add first link
+ if (first != null) {
+ links.add(first);
+ }
+
+ // add links in the middle if any
+ transit.forEach(fri -> links.addAll(linkResources(fri)));
+
+ // add last hop if any
+ Lists.reverse(transit).stream()
+ // search for Link transit Intent tail -> tail
+ // as candidate of last hop Link
+ .flatMap(fri -> ImmutableList.copyOf(fri.flowRules()).reverse().stream())
+ .map(fr ->
+ // find first output port from FlowRule
+ fr.treatment().allInstructions().stream()
+ .filter(OutputInstruction.class::isInstance).findFirst()
+ .map(OutputInstruction.class::cast)
+ .map(OutputInstruction::port)
+ .map(pn -> new ConnectPoint(fr.deviceId(), pn))
+ .orElse(null)
+ ).filter(Objects::nonNull)
+ .map(src -> servicesBundle.linkService().getLink(src, tail))
+ .filter(Objects::nonNull)
+ .findFirst()
+ .ifPresent(links::add);
}
- private void handleFlowRuleIntent(Set<Link> primary, Set<Link> backup,
- FlowRuleIntent frIntent) {
- boolean protection1 = frIntent.resources().stream()
- .filter(r -> r instanceof MarkerResource)
- .map(NetworkResource::toString)
- .anyMatch(rstring -> rstring.equals(PRIMARY_PATH_TAG));
- if (protection1) {
- primary.addAll(linkResources(frIntent));
- } else {
- backup.addAll(linkResources(frIntent));
- }
+ /**
+ * Returns true if specified intent is marked with primary marker resource.
+ *
+ * @param intent to test
+ * @return true if it is an Intent taking part of primary transit path
+ */
+ private boolean isPrimary(Intent intent) {
+ return intent.resources()
+ .contains(marker(PRIMARY_PATH_TAG));
}
// returns true if the backup path is the one where the traffic is currently flowing