[AETHER-38] Extract pipeline-dependent code from current T3 implementation
- Executes also a refactoring of several components of the app;
- Uses the new abstractions introduced in the ONOS core and
deprecates the old ones
- Deprecates unused APIs of the TroubleshootService
- Generator and other utils has been moved to the ONOS core
- Updates and fixes unit tests to make the build happy
Change-Id: Iac9ba644e1e199a58e8da53d0db78e36db56647c
diff --git a/app/pom.xml b/app/pom.xml
index 6c355b4..932d834 100644
--- a/app/pom.xml
+++ b/app/pom.xml
@@ -84,6 +84,14 @@
<scope>provided</scope>
</dependency>
+ <!-- ONOS drivers -->
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-drivers-default</artifactId>
+ <version>${onos.version}</version>
+ <scope>provided</scope>
+ </dependency>
+
<!-- Other Trellis apps -->
<dependency>
<groupId>org.onosproject</groupId>
diff --git a/app/src/main/java/org/onosproject/t3/api/FlowNib.java b/app/src/main/java/org/onosproject/t3/api/FlowNib.java
index b9f2226..1b70551 100644
--- a/app/src/main/java/org/onosproject/t3/api/FlowNib.java
+++ b/app/src/main/java/org/onosproject/t3/api/FlowNib.java
@@ -67,7 +67,7 @@
.filter(flow -> flow.state() == flowState
&& flow.deviceId().equals(deviceId))
.collect(Collectors.toSet());
- return flowsFiltered != null ? ImmutableSet.copyOf(flowsFiltered) : ImmutableSet.of();
+ return ImmutableSet.copyOf(flowsFiltered);
}
/**
diff --git a/app/src/main/java/org/onosproject/t3/api/GroupNib.java b/app/src/main/java/org/onosproject/t3/api/GroupNib.java
index b1fb563..14f55a7 100644
--- a/app/src/main/java/org/onosproject/t3/api/GroupNib.java
+++ b/app/src/main/java/org/onosproject/t3/api/GroupNib.java
@@ -56,6 +56,21 @@
}
/**
+ * Returns all groups associated with the given device and filtered by the group state.
+ *
+ * @param deviceId device ID to get groups for
+ * @param groupState the group state
+ * @return iterable of device's groups
+ */
+ public Iterable<Group> getGroupsByState(DeviceId deviceId, Group.GroupState groupState) {
+ Set<Group> groupsFiltered = groups.stream()
+ .filter(group -> group.state() == groupState
+ && group.deviceId().equals(deviceId))
+ .collect(Collectors.toSet());
+ return ImmutableSet.copyOf(groupsFiltered);
+ }
+
+ /**
* Returns all groups associated with the given device.
*
* @param deviceId device ID to get groups for
@@ -63,9 +78,9 @@
*/
public Iterable<Group> getGroups(DeviceId deviceId) {
Set<Group> groupsFiltered = groups.stream()
- .filter(g -> g.deviceId().equals(deviceId))
+ .filter(group -> group.deviceId().equals(deviceId))
.collect(Collectors.toSet());
- return groupsFiltered != null ? ImmutableSet.copyOf(groupsFiltered) : ImmutableSet.of();
+ return ImmutableSet.copyOf(groupsFiltered);
}
/**
diff --git a/app/src/main/java/org/onosproject/t3/api/GroupsInDevice.java b/app/src/main/java/org/onosproject/t3/api/GroupsInDevice.java
index 74203af..b17cfbb 100644
--- a/app/src/main/java/org/onosproject/t3/api/GroupsInDevice.java
+++ b/app/src/main/java/org/onosproject/t3/api/GroupsInDevice.java
@@ -25,8 +25,9 @@
/**
* Class to represent the groups in a device for a given output and packet.
+ * @deprecated in t3-4.0
*/
-//FIXME consider name change.
+@Deprecated
public class GroupsInDevice {
private ConnectPoint output;
diff --git a/app/src/main/java/org/onosproject/t3/api/StaticPacketTrace.java b/app/src/main/java/org/onosproject/t3/api/StaticPacketTrace.java
index 22db007..57e1dce 100644
--- a/app/src/main/java/org/onosproject/t3/api/StaticPacketTrace.java
+++ b/app/src/main/java/org/onosproject/t3/api/StaticPacketTrace.java
@@ -21,6 +21,7 @@
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Host;
+import org.onosproject.net.PipelineTraceableHitChain;
import org.onosproject.net.flow.FlowEntry;
import org.onosproject.net.flow.TrafficSelector;
@@ -36,10 +37,11 @@
*/
public class StaticPacketTrace {
- private final TrafficSelector inPacket;
- private final ConnectPoint in;
+ private final TrafficSelector ingressPacket;
+ private final ConnectPoint ingressPoint;
List<List<ConnectPoint>> completePaths;
private Map<DeviceId, List<GroupsInDevice>> outputsForDevice;
+ private Map<DeviceId, List<PipelineTraceableHitChain>> hitChainsForDevice;
private Map<DeviceId, List<FlowEntry>> flowsForDevice;
private StringBuilder resultMessage;
private Pair<Host, Host> hosts;
@@ -48,15 +50,16 @@
/**
* Builds the trace with a given packet and a connect point.
*
- * @param packet the packet to trace
- * @param in the initial connect point
+ * @param inPacket the packet to trace
+ * @param inPoint the initial connect point
*/
- public StaticPacketTrace(TrafficSelector packet, ConnectPoint in) {
- this.inPacket = packet;
- this.in = in;
+ public StaticPacketTrace(TrafficSelector inPacket, ConnectPoint inPoint) {
+ this.ingressPacket = inPacket;
+ this.ingressPoint = inPoint;
completePaths = new ArrayList<>();
outputsForDevice = new HashMap<>();
flowsForDevice = new HashMap<>();
+ hitChainsForDevice = new HashMap<>();
resultMessage = new StringBuilder();
hosts = null;
}
@@ -64,16 +67,17 @@
/**
* Builds the trace with a given packet and a connect point.
*
- * @param packet the packet to trace
- * @param in the initial connect point
- * @param hosts pair of source and destination hosts
+ * @param inPacket the packet to trace
+ * @param inPoint the initial connect point
+ * @param hosts pair of source and destination hosts
*/
- public StaticPacketTrace(TrafficSelector packet, ConnectPoint in, Pair<Host, Host> hosts) {
- this.inPacket = packet;
- this.in = in;
+ public StaticPacketTrace(TrafficSelector inPacket, ConnectPoint inPoint, Pair<Host, Host> hosts) {
+ this.ingressPacket = inPacket;
+ this.ingressPoint = inPoint;
completePaths = new ArrayList<>();
outputsForDevice = new HashMap<>();
flowsForDevice = new HashMap<>();
+ hitChainsForDevice = new HashMap<>();
resultMessage = new StringBuilder();
this.hosts = hosts;
}
@@ -84,7 +88,7 @@
* @return the initial packet in the form of a selector.
*/
public TrafficSelector getInitialPacket() {
- return inPacket;
+ return ingressPacket;
}
/**
@@ -93,7 +97,7 @@
* @return the connect point
*/
public ConnectPoint getInitialConnectPoint() {
- return in;
+ return ingressPoint;
}
/**
@@ -122,7 +126,9 @@
*
* @param deviceId the device
* @param outputPath the groups in device objects
+ * @deprecated in t3-4.0
*/
+ @Deprecated
public void addGroupOutputPath(DeviceId deviceId, GroupsInDevice outputPath) {
if (!outputsForDevice.containsKey(deviceId)) {
outputsForDevice.put(deviceId, new ArrayList<>());
@@ -131,16 +137,48 @@
}
/**
+ * Adds the pipeline hit chain for a given device.
+ *
+ * @param deviceId the device
+ * @param hitChain the hit chain
+ */
+ public void addHitChain(DeviceId deviceId, PipelineTraceableHitChain hitChain) {
+ hitChainsForDevice.compute(deviceId, (k, v) -> {
+ if (v == null) {
+ v = new ArrayList<>();
+ }
+ if (!v.contains(hitChain)) {
+ v.add(hitChain);
+ }
+ return v;
+ });
+ }
+
+ /**
* Returns all the possible group-based outputs for a given device.
*
* @param deviceId the device
* @return the list of Groups for this device.
+ * @deprecated in t3-4.0
*/
+ @Deprecated
public List<GroupsInDevice> getGroupOuputs(DeviceId deviceId) {
return outputsForDevice.get(deviceId) == null ? null : ImmutableList.copyOf(outputsForDevice.get(deviceId));
}
/**
+ * Returns all the possible pipeline hit chains for a given device.
+ *
+ * @param deviceId the device
+ * @return the list of hit chains
+ */
+ public List<PipelineTraceableHitChain> getHitChains(DeviceId deviceId) {
+ List<PipelineTraceableHitChain> hitChains = hitChainsForDevice.get(deviceId);
+ return hitChains == null ? null : ImmutableList.copyOf(hitChains);
+
+ }
+
+ /**
* Adds a complete possible path.
*
* @param completePath the path
@@ -163,7 +201,9 @@
*
* @param deviceId the device considered
* @param flows the flows
+ * @deprecated in t3-4.0
*/
+ @Deprecated
public void addFlowsForDevice(DeviceId deviceId, List<FlowEntry> flows) {
flowsForDevice.put(deviceId, flows);
}
@@ -173,7 +213,9 @@
*
* @param deviceId the device
* @return the flows matched
+ * @deprecated in t3-4.0
*/
+ @Deprecated
public List<FlowEntry> getFlowsForDevice(DeviceId deviceId) {
return flowsForDevice.getOrDefault(deviceId, ImmutableList.of());
}
@@ -214,15 +256,15 @@
this.success.add(success);
}
-
@Override
public String toString() {
return "StaticPacketTrace{" +
- "inPacket=" + inPacket +
- ", in=" + in +
+ "ingressPacket=" + ingressPacket +
+ ", ingressPoint=" + ingressPoint +
", completePaths=" + completePaths +
", outputsForDevice=" + outputsForDevice +
", flowsForDevice=" + flowsForDevice +
+ ", hitChains=" + hitChainsForDevice +
", resultMessage=" + resultMessage +
'}';
}
diff --git a/app/src/main/java/org/onosproject/t3/api/TroubleshootService.java b/app/src/main/java/org/onosproject/t3/api/TroubleshootService.java
index 3ab6052..d9c2f59 100644
--- a/app/src/main/java/org/onosproject/t3/api/TroubleshootService.java
+++ b/app/src/main/java/org/onosproject/t3/api/TroubleshootService.java
@@ -18,10 +18,10 @@
import org.onlab.packet.EthType;
import org.onlab.packet.VlanId;
+import org.onlab.util.Generator;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.HostId;
import org.onosproject.net.flow.TrafficSelector;
-import org.onosproject.t3.impl.Generator;
import java.util.List;
import java.util.Set;
@@ -37,7 +37,9 @@
*
* @param type the etherType of the traffic we want to trace.
* @return trace result
+ * @deprecated in t3-4.0
*/
+ @Deprecated
List<StaticPacketTrace> pingAll(EthType.EtherType type);
/**
@@ -81,7 +83,9 @@
*
* @param vlanId the vlan id configured for multicast
* @return list of trace result
+ * @deprecated in t3-4.0
*/
+ @Deprecated
List<Set<StaticPacketTrace>> getMulitcastTrace(VlanId vlanId);
/**
diff --git a/app/src/main/java/org/onosproject/t3/cli/T3CliUtils.java b/app/src/main/java/org/onosproject/t3/cli/T3CliUtils.java
index ddbdb38..8568775 100644
--- a/app/src/main/java/org/onosproject/t3/cli/T3CliUtils.java
+++ b/app/src/main/java/org/onosproject/t3/cli/T3CliUtils.java
@@ -18,9 +18,12 @@
import org.apache.commons.lang.StringUtils;
import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DataPlaneEntity;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.flow.FlowEntry;
import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.group.Group;
import org.onosproject.net.group.GroupBucket;
-import org.onosproject.t3.api.GroupsInDevice;
import org.onosproject.t3.api.StaticPacketTrace;
import java.util.List;
@@ -88,8 +91,7 @@
tracePrint.append("\n");
tracePrint.append("Input from " + connectPoint);
tracePrint.append("\n");
- tracePrint = printFlows(trace, verbose, connectPoint, tracePrint);
- tracePrint = printGroups(trace, verbose, connectPoint, tracePrint);
+ tracePrint = printHitChains(trace, verbose, connectPoint.deviceId(), tracePrint);
tracePrint.append("\n");
} else {
for (ConnectPoint connectPoint : path) {
@@ -98,11 +100,7 @@
tracePrint.append("\n");
tracePrint.append(" Input from " + connectPoint);
tracePrint.append("\n");
- tracePrint = printFlows(trace, verbose, connectPoint, tracePrint);
- } else {
- tracePrint = printGroups(trace, verbose, connectPoint, tracePrint);
- tracePrint.append(" Output through " + connectPoint);
- tracePrint.append("\n");
+ tracePrint = printHitChains(trace, verbose, connectPoint.deviceId(), tracePrint);
}
previous = connectPoint;
}
@@ -112,62 +110,71 @@
return tracePrint;
}
-
- //Prints the flows for a given trace and a specified level of verbosity
- private static StringBuilder printFlows(StaticPacketTrace trace, boolean verbose, ConnectPoint connectPoint,
- StringBuilder tracePrint) {
- tracePrint.append(" Flows ");
- tracePrint.append(trace.getFlowsForDevice(connectPoint.deviceId()).size());
+ private static StringBuilder printHitChains(StaticPacketTrace trace, boolean verbose, DeviceId deviceId,
+ StringBuilder tracePrint) {
+ tracePrint.append(" Hit chains ");
+ tracePrint.append(trace.getHitChains(deviceId).size());
tracePrint.append(" \n");
- trace.getFlowsForDevice(connectPoint.deviceId()).forEach(f -> {
- if (verbose) {
- tracePrint.append(" " + String.format(FLOW_SHORT_FORMAT, f.state(), f.bytes(), f.packets(),
- f.table(), f.priority(), f.selector().criteria(),
- printTreatment(f.treatment())));
- tracePrint.append("\n");
- } else {
- tracePrint.append(String.format(" flowId=%s, table=%s, selector=%s", f.id(), f.table(),
- f.selector().criteria()));
- tracePrint.append("\n");
- }
+ tracePrint.append(" \n");
+ int[] index = {1};
+ trace.getHitChains(deviceId).forEach(hitChain -> {
+ tracePrint.append(" Hit chain " + index[0]++);
+ tracePrint.append(" \n");
+ // Print for each chain the matchable entities first
+ hitChain.getHitChain().forEach(dataPlaneEntity -> {
+ if (dataPlaneEntity.getType() == DataPlaneEntity.Type.FLOWRULE) {
+ printFlow(dataPlaneEntity.getFlowEntry(), verbose, tracePrint);
+ } else if (dataPlaneEntity.getType() == DataPlaneEntity.Type.GROUP) {
+ printGroup(dataPlaneEntity.getGroupEntry(), verbose, tracePrint);
+ }
+ });
+ // Then the output packet of the current chain
+ tracePrint.append(" Outgoing Packet " + hitChain.getEgressPacket());
+ tracePrint.append("\n");
+ // The output port of the current chain
+ tracePrint.append(" Output through " + hitChain.getOutputPort());
+ tracePrint.append("\n");
+ // Dropped during the processing ?
+ tracePrint.append(" Dropped " + hitChain.isDropped());
+ tracePrint.append("\n");
+ tracePrint.append("\n");
});
+
return tracePrint;
}
- //Prints the groups for a given trace and a specified level of verbosity
- private static StringBuilder printGroups(StaticPacketTrace trace, boolean verbose, ConnectPoint connectPoint,
- StringBuilder tracePrint) {
- List<GroupsInDevice> groupsInDevice = trace.getGroupOuputs(connectPoint.deviceId());
- if (groupsInDevice != null) {
- tracePrint.append(" Groups");
- tracePrint.append("\n");
- groupsInDevice.forEach(output -> {
- if (output.getOutput().equals(connectPoint)) {
- output.getGroups().forEach(group -> {
- if (verbose) {
- tracePrint.append(" " + String.format(GROUP_FORMAT, Integer.toHexString(group.id().id()),
- group.state(), group.type(), group.bytes(), group.packets(),
- group.appId().name(), group.referenceCount()));
- tracePrint.append("\n");
- int i = 0;
- for (GroupBucket bucket : group.buckets().buckets()) {
- tracePrint.append(" " + String.format(GROUP_BUCKET_FORMAT,
- Integer.toHexString(group.id().id()),
- ++i, bucket.bytes(), bucket.packets(),
- bucket.treatment().allInstructions()));
- tracePrint.append("\n");
- }
- } else {
- tracePrint.append(" groupId=" + group.id());
- tracePrint.append("\n");
- }
- });
- tracePrint.append(" Outgoing Packet " + output.getFinalPacket());
- tracePrint.append("\n");
- }
- });
+ // Prints the flows for a given trace and a specified level of verbosity
+ private static void printFlow(FlowEntry f, boolean verbose, StringBuilder tracePrint) {
+ if (verbose) {
+ tracePrint.append(" " + String.format(FLOW_SHORT_FORMAT, f.state(), f.bytes(), f.packets(),
+ f.table(), f.priority(), f.selector().criteria(),
+ printTreatment(f.treatment())));
+ } else {
+ tracePrint.append(String.format(" flowId=%s, table=%s, selector=%s", f.id(), f.table(),
+ f.selector().criteria()));
}
- return tracePrint;
+ tracePrint.append("\n");
+ }
+
+ // Prints the groups for a given trace and a specified level of verbosity
+ private static void printGroup(Group group, boolean verbose, StringBuilder tracePrint) {
+ if (verbose) {
+ tracePrint.append(" " + String.format(GROUP_FORMAT, Integer.toHexString(group.id().id()),
+ group.state(), group.type(), group.bytes(), group.packets(),
+ group.appId().name(), group.referenceCount()));
+ tracePrint.append("\n");
+ int i = 0;
+ for (GroupBucket bucket : group.buckets().buckets()) {
+ tracePrint.append(" " + String.format(GROUP_BUCKET_FORMAT,
+ Integer.toHexString(group.id().id()),
+ ++i, bucket.bytes(), bucket.packets(),
+ bucket.treatment().allInstructions()));
+ tracePrint.append("\n");
+ }
+ } else {
+ tracePrint.append(" groupId=" + group.id());
+ tracePrint.append("\n");
+ }
}
private static String printTreatment(TrafficTreatment treatment) {
diff --git a/app/src/main/java/org/onosproject/t3/cli/TroubleshootMcastCommand.java b/app/src/main/java/org/onosproject/t3/cli/TroubleshootMcastCommand.java
index d635c23..0e51066 100644
--- a/app/src/main/java/org/onosproject/t3/cli/TroubleshootMcastCommand.java
+++ b/app/src/main/java/org/onosproject/t3/cli/TroubleshootMcastCommand.java
@@ -24,6 +24,7 @@
import org.onlab.packet.EthType;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.VlanId;
+import org.onlab.util.Generator;
import org.onosproject.cli.AbstractShellCommand;
import org.onosproject.cli.PlaceholderCompleter;
import org.onosproject.net.ConnectPoint;
@@ -33,7 +34,6 @@
import org.onosproject.net.flow.criteria.IPCriterion;
import org.onosproject.t3.api.StaticPacketTrace;
import org.onosproject.t3.api.TroubleshootService;
-import org.onosproject.t3.impl.Generator;
import java.util.ArrayList;
import java.util.List;
diff --git a/app/src/main/java/org/onosproject/t3/cli/TroubleshootPingAllCommand.java b/app/src/main/java/org/onosproject/t3/cli/TroubleshootPingAllCommand.java
index e61a533..40f747f 100644
--- a/app/src/main/java/org/onosproject/t3/cli/TroubleshootPingAllCommand.java
+++ b/app/src/main/java/org/onosproject/t3/cli/TroubleshootPingAllCommand.java
@@ -22,6 +22,7 @@
import org.apache.karaf.shell.api.action.Option;
import org.apache.karaf.shell.api.action.lifecycle.Service;
import org.onlab.packet.IpAddress;
+import org.onlab.util.Generator;
import org.onosproject.cli.AbstractShellCommand;
import org.onosproject.cli.PlaceholderCompleter;
import org.onosproject.cli.net.EthTypeCompleter;
@@ -30,7 +31,6 @@
import org.onosproject.net.flow.criteria.IPCriterion;
import org.onosproject.t3.api.StaticPacketTrace;
import org.onosproject.t3.api.TroubleshootService;
-import org.onosproject.t3.impl.Generator;
import java.util.ArrayList;
import java.util.List;
diff --git a/app/src/main/java/org/onosproject/t3/impl/Generator.java b/app/src/main/java/org/onosproject/t3/impl/Generator.java
deleted file mode 100644
index 82ad628..0000000
--- a/app/src/main/java/org/onosproject/t3/impl/Generator.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright 2018-present Open Networking Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.onosproject.t3.impl;
-
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-
-/**
- * Generator class that yields instances of T type objects as soon as they are ready.
- *
- * @param <T> type of the object.
- */
-public abstract class Generator<T> implements Iterable<T> {
-
- private class Condition {
- private boolean isSet;
-
- synchronized void set() {
- isSet = true;
- notifyAll();
- }
-
- synchronized void await() throws InterruptedException {
- try {
-
- if (isSet) {
- return;
- }
-
- while (!isSet) {
- wait();
- }
- } finally {
- isSet = false;
- }
- }
- }
-
- private static ThreadGroup threadGroup;
-
- private Thread producer;
- private boolean hasFinished;
- private final Condition itemAvailableOrHasFinished = new Condition();
- private final Condition itemRequested = new Condition();
- private T nextItem;
- private boolean nextItemAvailable;
- private RuntimeException exceptionRaisedByProducer;
-
- @Override
- public Iterator<T> iterator() {
- return new Iterator<T>() {
- @Override
- public boolean hasNext() {
- return waitForNext();
- }
-
- @Override
- public T next() {
- if (!waitForNext()) {
- throw new NoSuchElementException();
- }
- nextItemAvailable = false;
- return nextItem;
- }
-
- @Override
- public void remove() {
- throw new UnsupportedOperationException();
- }
-
- private boolean waitForNext() {
- if (nextItemAvailable) {
- return true;
- }
- if (hasFinished) {
- return false;
- }
- if (producer == null) {
- startProducer();
- }
- itemRequested.set();
- try {
- itemAvailableOrHasFinished.await();
- } catch (InterruptedException e) {
- hasFinished = true;
- producer.interrupt();
- try {
- producer.join();
- } catch (InterruptedException e1) {
- // Interrupting the broken thread
- Thread.currentThread().interrupt();
- throw new IllegalStateException(e1);
- }
- }
- if (exceptionRaisedByProducer != null) {
- throw exceptionRaisedByProducer;
- }
- return !hasFinished;
- }
- };
- }
-
- protected abstract void run() throws InterruptedException;
-
- void yield(T element) throws InterruptedException {
- nextItem = element;
- nextItemAvailable = true;
- itemAvailableOrHasFinished.set();
- itemRequested.await();
- }
-
- private void startProducer() {
- assert producer == null;
- synchronized (this) {
- if (threadGroup == null) {
- threadGroup = new ThreadGroup("onos-t3-generator");
- }
- }
- producer = new Thread(threadGroup, () -> {
- try {
- itemRequested.await();
- Generator.this.run();
- } catch (InterruptedException e) {
- // Remaining steps in run() will shut down thread.
- } catch (RuntimeException e) {
- exceptionRaisedByProducer = e;
- }
- hasFinished = true;
- itemAvailableOrHasFinished.set();
- });
- producer.setDaemon(true);
- producer.start();
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/onosproject/t3/impl/McastGenerator.java b/app/src/main/java/org/onosproject/t3/impl/McastGenerator.java
index 7520843..780de09 100644
--- a/app/src/main/java/org/onosproject/t3/impl/McastGenerator.java
+++ b/app/src/main/java/org/onosproject/t3/impl/McastGenerator.java
@@ -21,6 +21,7 @@
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
+import org.onlab.util.Generator;
import org.onosproject.mcast.api.McastRouteData;
import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.TrafficSelector;
diff --git a/app/src/main/java/org/onosproject/t3/impl/PingAllGenerator.java b/app/src/main/java/org/onosproject/t3/impl/PingAllGenerator.java
index e935fad..7d656c5 100644
--- a/app/src/main/java/org/onosproject/t3/impl/PingAllGenerator.java
+++ b/app/src/main/java/org/onosproject/t3/impl/PingAllGenerator.java
@@ -19,6 +19,7 @@
import com.google.common.collect.Sets;
import org.onlab.packet.EthType;
import org.onlab.packet.IpAddress;
+import org.onlab.util.Generator;
import org.onosproject.t3.api.HostNib;
import org.onosproject.t3.api.StaticPacketTrace;
import org.slf4j.Logger;
diff --git a/app/src/main/java/org/onosproject/t3/impl/TroubleshootManager.java b/app/src/main/java/org/onosproject/t3/impl/TroubleshootManager.java
index bc04136..b683351 100644
--- a/app/src/main/java/org/onosproject/t3/impl/TroubleshootManager.java
+++ b/app/src/main/java/org/onosproject/t3/impl/TroubleshootManager.java
@@ -21,25 +21,32 @@
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
+import com.google.common.collect.Maps;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.onlab.packet.IpAddress;
import org.onlab.packet.VlanId;
+import org.onlab.util.Generator;
import org.onosproject.cluster.NodeId;
+
import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DataPlaneEntity;
+import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Host;
import org.onosproject.net.HostId;
import org.onosproject.net.Link;
+import org.onosproject.net.PipelineTraceableHitChain;
+import org.onosproject.net.PipelineTraceableInput;
+import org.onosproject.net.PipelineTraceableOutput;
+import org.onosproject.net.PipelineTraceableOutput.PipelineTraceableResult;
import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
+import org.onosproject.net.behaviour.PipelineTraceable;
import org.onosproject.net.config.ConfigException;
import org.onosproject.net.config.basics.InterfaceConfig;
import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.FlowEntry;
-import org.onosproject.net.flow.FlowRule;
-import org.onosproject.net.flow.IndexTableId;
-import org.onosproject.net.flow.TableId;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.criteria.Criteria;
import org.onosproject.net.flow.criteria.Criterion;
@@ -47,12 +54,7 @@
import org.onosproject.net.flow.criteria.EthTypeCriterion;
import org.onosproject.net.flow.criteria.IPCriterion;
import org.onosproject.net.flow.criteria.VlanIdCriterion;
-import org.onosproject.net.flow.instructions.Instruction;
-import org.onosproject.net.flow.instructions.Instructions;
-import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
-import org.onosproject.net.flow.instructions.L2ModificationInstruction;
import org.onosproject.net.group.Group;
-import org.onosproject.net.group.GroupBucket;
import org.onosproject.net.host.InterfaceIpAddress;
import org.onosproject.net.intf.Interface;
import org.onosproject.routeservice.ResolvedRoute;
@@ -62,7 +64,6 @@
import org.onosproject.t3.api.EdgePortNib;
import org.onosproject.t3.api.FlowNib;
import org.onosproject.t3.api.GroupNib;
-import org.onosproject.t3.api.GroupsInDevice;
import org.onosproject.t3.api.HostNib;
import org.onosproject.t3.api.LinkNib;
import org.onosproject.t3.api.MastershipNib;
@@ -75,27 +76,20 @@
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashSet;
+import java.util.Map;
import java.util.List;
-import java.util.Optional;
import java.util.Set;
+import java.util.HashSet;
+import java.util.Optional;
+import java.util.ArrayList;
+import java.util.Collections;
+
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import static org.onlab.packet.EthType.EtherType;
import static org.onosproject.net.flow.TrafficSelector.Builder;
-import static org.onosproject.net.flow.instructions.Instructions.GroupInstruction;
-import static org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
-import static org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsHeaderInstruction;
-import static org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsLabelInstruction;
-import static org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
-import static org.onosproject.t3.impl.TroubleshootUtils.compareMac;
import static org.slf4j.LoggerFactory.getLogger;
/**
@@ -123,6 +117,9 @@
protected NetworkConfigNib networkConfigNib = NetworkConfigNib.getInstance();
protected MulticastRouteNib mcastRouteNib = MulticastRouteNib.getInstance();
+ // FIXME Revisit offline mode after a first implementation
+ private final Map<DeviceId, PipelineTraceable> pipelineTraceables = Maps.newConcurrentMap();
+
@Override
public boolean checkNibValidity() {
return Stream.of(flowNib, groupNib, linkNib, hostNib, deviceNib, driverNib,
@@ -146,32 +143,6 @@
}
@Override
- public List<StaticPacketTrace> pingAll(EtherType type) {
- ImmutableList.Builder<StaticPacketTrace> tracesBuilder = ImmutableList.builder();
- hostNib.getHosts().forEach(host -> {
- List<IpAddress> ipAddresses = getIpAddresses(host, type, false);
- if (ipAddresses.size() > 0) {
- //check if the host has only local IPs of that ETH type
- boolean onlyLocalSrc = ipAddresses.size() == 1 && ipAddresses.get(0).isLinkLocal();
- hostNib.getHosts().forEach(hostToPing -> {
- List<IpAddress> ipAddressesToPing = getIpAddresses(hostToPing, type, false);
- //check if the other host has only local IPs of that ETH type
- boolean onlyLocalDst = ipAddressesToPing.size() == 1 && ipAddressesToPing.get(0).isLinkLocal();
- boolean sameLocation = Sets.intersection(host.locations(), hostToPing.locations()).size() > 0;
- //Trace is done only if they are both local and under the same location
- // or not local and if they are not the same host.
- if (((sameLocation && onlyLocalDst && onlyLocalSrc) ||
- (!onlyLocalSrc && !onlyLocalDst && ipAddressesToPing.size() > 0))
- && !host.equals(hostToPing)) {
- tracesBuilder.addAll(trace(host.id(), hostToPing.id(), type));
- }
- });
- }
- });
- return tracesBuilder.build();
- }
-
- @Override
public Generator<Set<StaticPacketTrace>> pingAllGenerator(EtherType type) {
return new PingAllGenerator(type, hostNib, this);
}
@@ -269,6 +240,32 @@
}
}
+ private PipelineTraceable getPipelineMatchable(DeviceId deviceId) {
+ return pipelineTraceables.compute(deviceId, (k, v) -> {
+ if (v == null) {
+ log.info("PipelineMatchable not found for {}", deviceId);
+ Device d = deviceNib.getDevice(deviceId);
+ if (d.is(PipelineTraceable.class)) {
+ v = d.as(PipelineTraceable.class);
+ v.init();
+ } else {
+ log.warn("PipelineMatchable behaviour not supported for device {}",
+ deviceId);
+ }
+ }
+ return v;
+ });
+ }
+
+ private List<DataPlaneEntity> getDataPlaneEntities(DeviceId deviceId) {
+ List<DataPlaneEntity> dataPlaneEntities = Lists.newArrayList();
+ flowNib.getFlowEntriesByState(deviceId, FlowEntry.FlowEntryState.ADDED).forEach(entity ->
+ dataPlaneEntities.add(new DataPlaneEntity(entity)));
+ groupNib.getGroupsByState(deviceId, Group.GroupState.ADDED).forEach(entity ->
+ dataPlaneEntities.add(new DataPlaneEntity(entity)));
+ return dataPlaneEntities;
+ }
+
/**
* Matches src and dst IPs based on host information.
*
@@ -392,14 +389,6 @@
return trace;
}
- @Override
- public List<Set<StaticPacketTrace>> getMulitcastTrace(VlanId vlanId) {
- Generator<Set<StaticPacketTrace>> gen = new McastGenerator(mcastRouteNib, this, vlanId);
- List<Set<StaticPacketTrace>> multicastTraceList =
- StreamSupport.stream(gen.spliterator(), false).collect(Collectors.toList());
- return multicastTraceList;
- }
-
/**
* Computes a trace for a give packet that start in the network at the given connect point.
*
@@ -427,20 +416,24 @@
completePath.add(in);
//If the trace has no outputs for the given input we stop here
- if (trace.getGroupOuputs(in.deviceId()) == null) {
- computePath(completePath, trace, null);
+ if (trace.getHitChains(in.deviceId()) == null) {
+ TroubleshootUtils.computePath(completePath, trace, null);
trace.addResultMessage("No output out of device " + in.deviceId() + ". Packet is dropped");
trace.setSuccess(false);
return trace;
}
//If the trace has outputs we analyze them all
- for (GroupsInDevice outputPath : trace.getGroupOuputs(in.deviceId())) {
+ for (PipelineTraceableHitChain outputPath : trace.getHitChains(in.deviceId())) {
- ConnectPoint cp = outputPath.getOutput();
+ ConnectPoint cp = outputPath.getOutputPort();
log.debug("Connect point in {}", in);
log.debug("Output path {}", cp);
- log.debug("{}", outputPath.getFinalPacket());
+ log.debug("{}", outputPath.getEgressPacket());
+
+ if (outputPath.isDropped()) {
+ continue;
+ }
//Hosts for the the given output
Set<Host> hostsList = hostNib.getConnectedHosts(cp);
@@ -448,34 +441,31 @@
Set<Host> hosts = getHosts(trace);
if (in.equals(cp) && trace.getInitialPacket().getCriterion(Criterion.Type.VLAN_VID) != null &&
- outputPath.getFinalPacket().getCriterion(Criterion.Type.VLAN_VID) != null
+ outputPath.getEgressPacket().getCriterion(Criterion.Type.VLAN_VID) != null
&& ((VlanIdCriterion) trace.getInitialPacket().getCriterion(Criterion.Type.VLAN_VID)).vlanId()
- .equals(((VlanIdCriterion) outputPath.getFinalPacket().getCriterion(Criterion.Type.VLAN_VID))
+ .equals(((VlanIdCriterion) outputPath.getEgressPacket().getCriterion(Criterion.Type.VLAN_VID))
.vlanId())) {
- if (trace.getGroupOuputs(in.deviceId()).size() == 1 &&
- computePath(completePath, trace, outputPath.getOutput())) {
+ if (trace.getHitChains(in.deviceId()).size() == 1 &&
+ TroubleshootUtils.computePath(completePath, trace, outputPath.getOutputPort())) {
trace.addResultMessage("Connect point out " + cp + " is same as initial input " + in);
trace.setSuccess(false);
}
} else if (!Collections.disjoint(hostsList, hosts)) {
//If the two host collections contain the same item it means we reached the proper output
- log.debug("Stopping here because host is expected destination {}, reached through", completePath);
- if (computePath(completePath, trace, outputPath.getOutput())) {
+ log.debug("Stopping here because host is expected destination, reached through {}", completePath);
+ if (TroubleshootUtils.computePath(completePath, trace, outputPath.getOutputPort())) {
trace.addResultMessage("Reached required destination Host " + cp);
trace.setSuccess(true);
}
break;
- } else if (cp.port().equals(PortNumber.CONTROLLER)) {
+ } else if (cp.port().equals(PortNumber.CONTROLLER)) {
//Getting the master when the packet gets sent as packet in
NodeId master = mastershipNib.getMasterFor(cp.deviceId());
// TODO if we don't need to print master node id, exclude mastership NIB which is used only here
trace.addResultMessage(PACKET_TO_CONTROLLER + " " + master.id());
- computePath(completePath, trace, outputPath.getOutput());
- handleVlanToController(outputPath, trace);
-
+ TroubleshootUtils.computePath(completePath, trace, outputPath.getOutputPort());
} else if (linkNib.getEgressLinks(cp).size() > 0) {
-
//TODO this can be optimized if we use a Tree structure for paths.
//if we already have outputs let's check if the one we are considering starts from one of the devices
// in any of the ones we have.
@@ -513,7 +503,7 @@
ConnectPoint dst = link.dst();
//change in-port to the dst link in port
Builder updatedPacket = DefaultTrafficSelector.builder();
- outputPath.getFinalPacket().criteria().forEach(updatedPacket::add);
+ outputPath.getEgressPacket().criteria().forEach(updatedPacket::add);
updatedPacket.add(Criteria.matchInPort(dst.port()));
log.debug("DST Connect Point {}", dst);
//build the elements for that device
@@ -521,15 +511,15 @@
//continue the trace along the path
getTrace(completePath, dst, trace, isDualHomed);
}
- } else if (edgePortNib.isEdgePoint(outputPath.getOutput()) &&
+ } else if (edgePortNib.isEdgePoint(outputPath.getOutputPort()) &&
trace.getInitialPacket().getCriterion(Criterion.Type.ETH_DST) != null &&
((EthCriterion) trace.getInitialPacket().getCriterion(Criterion.Type.ETH_DST))
.mac().isMulticast()) {
- trace.addResultMessage("Packet is multicast and reached output " + outputPath.getOutput() +
+ trace.addResultMessage("Packet is multicast and reached output " + outputPath.getOutputPort() +
" which is enabled and is edge port");
trace.setSuccess(true);
- computePath(completePath, trace, outputPath.getOutput());
- if (!hasOtherOutput(in.deviceId(), trace, outputPath.getOutput())) {
+ TroubleshootUtils.computePath(completePath, trace, outputPath.getOutputPort());
+ if (!hasOtherOutput(in.deviceId(), trace, outputPath.getOutputPort())) {
return trace;
}
} else if (deviceNib.getPort(cp) != null && deviceNib.getPort(cp).isEnabled()) {
@@ -538,9 +528,9 @@
//We treat as correct output only if it's not LLDP or BDDP
if (!(ethTypeCriterion.ethType().equals(EtherType.LLDP.ethType())
&& !ethTypeCriterion.ethType().equals(EtherType.BDDP.ethType()))) {
- if (computePath(completePath, trace, outputPath.getOutput())) {
+ if (TroubleshootUtils.computePath(completePath, trace, outputPath.getOutputPort())) {
if (hostsList.isEmpty()) {
- trace.addResultMessage("Packet is " + ((EthTypeCriterion) outputPath.getFinalPacket()
+ trace.addResultMessage("Packet is " + ((EthTypeCriterion) outputPath.getEgressPacket()
.getCriterion(Criterion.Type.ETH_TYPE)).ethType() + " and reached " +
cp + " with no hosts connected ");
} else {
@@ -557,7 +547,7 @@
if (hostsList.stream().anyMatch(host -> host.ipAddresses().contains(finalIpAddress)) ||
hostNib.getHostsByIp(finalIpAddress).isEmpty()) {
trace.addResultMessage("Packet is " +
- ((EthTypeCriterion) outputPath.getFinalPacket()
+ ((EthTypeCriterion) outputPath.getEgressPacket()
.getCriterion(Criterion.Type.ETH_TYPE)).ethType() +
" and reached " + cp + " with hosts " + hostsList);
} else {
@@ -566,7 +556,7 @@
trace.setSuccess(false);
}
} else {
- trace.addResultMessage("Packet is " + ((EthTypeCriterion) outputPath.getFinalPacket()
+ trace.addResultMessage("Packet is " + ((EthTypeCriterion) outputPath.getEgressPacket()
.getCriterion(Criterion.Type.ETH_TYPE)).ethType() + " and reached " +
cp + " with hosts " + hostsList);
}
@@ -576,7 +566,7 @@
}
} else {
- computePath(completePath, trace, cp);
+ TroubleshootUtils.computePath(completePath, trace, cp);
trace.setSuccess(false);
if (deviceNib.getPort(cp) == null) {
//Port is not existent on device.
@@ -592,34 +582,6 @@
return trace;
}
-
- /**
- * If the initial packet comes tagged with a Vlan we output it with that to ONOS.
- * If ONOS applied a vlan we remove it.
- *
- * @param outputPath the output
- * @param trace the trace we are building
- */
-
- private void handleVlanToController(GroupsInDevice outputPath, StaticPacketTrace trace) {
-
- VlanIdCriterion initialVid = (VlanIdCriterion) trace.getInitialPacket().getCriterion(Criterion.Type.VLAN_VID);
- VlanIdCriterion finalVid = (VlanIdCriterion) outputPath.getFinalPacket().getCriterion(Criterion.Type.VLAN_VID);
-
- if (initialVid != null && !initialVid.equals(finalVid) && initialVid.vlanId().equals(VlanId.NONE)) {
-
- Set<Criterion> finalCriteria = new HashSet<>(outputPath.getFinalPacket().criteria());
- //removing the final vlanId
- finalCriteria.remove(finalVid);
- Builder packetUpdated = DefaultTrafficSelector.builder();
- finalCriteria.forEach(packetUpdated::add);
- //Initial was none so we set it to that
- packetUpdated.add(Criteria.matchVlanId(VlanId.NONE));
- //Update final packet
- outputPath.setFinalPacket(packetUpdated.build());
- }
- }
-
/**
* Checks if the device has other outputs than the given connect point.
*
@@ -629,9 +591,8 @@
* @return true if the device has other outputs.
*/
private boolean hasOtherOutput(DeviceId inDeviceId, StaticPacketTrace trace, ConnectPoint cp) {
- return trace.getGroupOuputs(inDeviceId).stream().filter(groupsInDevice -> {
- return !groupsInDevice.getOutput().equals(cp);
- }).count() > 0;
+ return trace.getHitChains(inDeviceId).stream().filter(groupsInDevice ->
+ !groupsInDevice.getOutputPort().equals(cp)).count() > 0;
}
/**
@@ -678,35 +639,6 @@
}
/**
- * Computes the list of traversed connect points.
- *
- * @param completePath the list of devices
- * @param trace the trace we are building
- * @param output the final output connect point
- */
- private boolean computePath(List<ConnectPoint> completePath, StaticPacketTrace trace, ConnectPoint output) {
- List<ConnectPoint> traverseList = new ArrayList<>();
- if (!completePath.contains(trace.getInitialConnectPoint())) {
- traverseList.add(trace.getInitialConnectPoint());
- }
-
- if (output != null && trace.getInitialConnectPoint().deviceId().equals(output.deviceId())) {
- trace.addCompletePath(ImmutableList.of(trace.getInitialConnectPoint(), output));
- return true;
- }
-
- traverseList.addAll(completePath);
- if (output != null && !completePath.contains(output)) {
- traverseList.add(output);
- }
- if (!trace.getCompletePaths().contains(traverseList)) {
- trace.addCompletePath(ImmutableList.copyOf(traverseList));
- return true;
- }
- return false;
- }
-
- /**
* Traces the packet inside a device starting from an input connect point.
*
* @param trace the trace we are building
@@ -718,12 +650,21 @@
*/
private StaticPacketTrace traceInDevice(StaticPacketTrace trace, TrafficSelector packet, ConnectPoint in,
boolean isDualHomed, List<ConnectPoint> completePath) {
+ // Get the behavior - do not proceed if there is no PipelineMatchable for the given device
+ PipelineTraceable pipelineMatchable = getPipelineMatchable(in.deviceId());
+ if (pipelineMatchable == null) {
+ trace.addResultMessage("No PipelineMatchable behavior for " + in.deviceId() + ". Aborting");
+ TroubleshootUtils.computePath(completePath, trace, null);
+ trace.setSuccess(false);
+ return trace;
+ }
+ // Verify the presence of multiple routes - if the device has been visited in the past
boolean multipleRoutes = false;
- if (trace.getGroupOuputs(in.deviceId()) != null) {
+ if (trace.getHitChains(in.deviceId()) != null) {
multipleRoutes = multipleRoutes(trace);
}
- if (trace.getGroupOuputs(in.deviceId()) != null && !isDualHomed && !multipleRoutes) {
+ if (trace.getHitChains(in.deviceId()) != null && !isDualHomed && !multipleRoutes) {
log.debug("Trace already contains device and given outputs");
return trace;
}
@@ -733,12 +674,12 @@
//if device is not available exit here.
if (!deviceNib.isAvailable(in.deviceId())) {
trace.addResultMessage("Device is offline " + in.deviceId());
- computePath(completePath, trace, null);
+ TroubleshootUtils.computePath(completePath, trace, null);
return trace;
}
- //handle when the input is the controller
- //NOTE, we are using the input port as a convenience to carry the CONTROLLER port number even if
+ // Handle when the input is the controller.
+ // NOTE, we are using the input port as a convenience to carry the CONTROLLER port number even if
// a packet in from the controller will not actually traverse the pipeline and have no such notion
// as the input port.
if (in.port().equals(PortNumber.CONTROLLER)) {
@@ -748,197 +689,38 @@
}
}
- List<FlowEntry> flows = new ArrayList<>();
- List<FlowEntry> outputFlows = new ArrayList<>();
- List<Instruction> deferredInstructions = new ArrayList<>();
-
- FlowEntry nextTableIdEntry = findNextTableIdEntry(in.deviceId(), -1);
- if (nextTableIdEntry == null) {
- trace.addResultMessage("No flow rules for device " + in.deviceId() + ". Aborting");
- computePath(completePath, trace, null);
+ // Get the device state in the form of DataPlaneEntity objects - do not proceed if there is no state
+ List<DataPlaneEntity> dataPlaneEntities = getDataPlaneEntities(in.deviceId());
+ if (dataPlaneEntities.isEmpty()) {
+ trace.addResultMessage("No device state for " + in.deviceId() + ". Aborting");
+ TroubleshootUtils.computePath(completePath, trace, null);
trace.setSuccess(false);
return trace;
}
- TableId tableId = nextTableIdEntry.table();
- FlowEntry flowEntry;
- boolean output = false;
- while (!output) {
- log.debug("Searching a Flow Entry on table {} for packet {}", tableId, packet);
- //get the rule that matches the incoming packet
- flowEntry = matchHighestPriority(packet, in, tableId);
- log.debug("Found Flow Entry {}", flowEntry);
- boolean isOfdpaHardware = TroubleshootUtils.hardwareOfdpaMap
- .getOrDefault(driverNib.getDriverName(in.deviceId()), false);
+ // Applies pipeline processing
+ PipelineTraceableInput input = new PipelineTraceableInput(packet, in, dataPlaneEntities);
+ PipelineTraceableOutput output = pipelineMatchable.apply(input);
- //if the flow entry on a table is null and we are on hardware we treat as table miss, with few exceptions
- if (flowEntry == null && isOfdpaHardware) {
- log.debug("Ofdpa Hw setup, no flow rule means table miss");
+ // Update the trace
+ List<PipelineTraceableHitChain> hitChains = output.getHitChains();
+ hitChains.forEach(hitChain -> trace.addHitChain(in.deviceId(), hitChain));
+ trace.addResultMessage(output.getLog());
- if (((IndexTableId) tableId).id() == 27) {
- //Apparently a miss but Table 27 on OFDPA is a fixed table
- packet = handleOfdpa27FixedTable(trace, packet);
- }
-
- //Finding next table to go In case of miss
- nextTableIdEntry = findNextTableIdEntry(in.deviceId(), ((IndexTableId) tableId).id());
- log.debug("Next table id entry {}", nextTableIdEntry);
-
- //FIXME find better solution that enable granularity greater than 0 or all rules
- //(another possibility is max tableId)
- if (nextTableIdEntry == null && flows.size() == 0) {
- trace.addResultMessage("No matching flow rules for device " + in.deviceId() + ". Aborting");
- computePath(completePath, trace, null);
- trace.setSuccess(false);
- return trace;
-
- } else if (nextTableIdEntry == null) {
- //Means that no more flow rules are present
- output = true;
-
- } else if (((IndexTableId) tableId).id() == 20) {
- //if the table is 20 OFDPA skips to table 50
- log.debug("A miss on Table 20 on OFDPA means that we skip directly to table 50");
- tableId = IndexTableId.of(50);
-
- } else if (((IndexTableId) tableId).id() == 40) {
- //if the table is 40 OFDPA skips to table 60
- log.debug("A miss on Table 40 on OFDPA means that we skip directly to table 60");
- tableId = IndexTableId.of(60);
- } else {
- tableId = nextTableIdEntry.table();
- }
-
- } else if (flowEntry == null) {
- trace.addResultMessage("Packet has no match on table " + tableId + " in device " +
- in.deviceId() + ". Dropping");
- computePath(completePath, trace, null);
- trace.setSuccess(false);
- return trace;
- } else {
-
- //IF the table has a transition
- if (flowEntry.treatment().tableTransition() != null) {
- //update the next table we transitions to
- tableId = IndexTableId.of(flowEntry.treatment().tableTransition().tableId());
- log.debug("Flow Entry has transition to table Id {}", tableId);
- flows.add(flowEntry);
- } else {
- //table has no transition so it means that it's an output rule if on the last table
- log.debug("Flow Entry has no transition to table, treating as last rule {}", flowEntry);
- flows.add(flowEntry);
- outputFlows.add(flowEntry);
- output = true;
- }
- //update the packet according to the immediate actions of this flow rule.
- packet = updatePacket(packet, flowEntry.treatment().immediate()).build();
-
- //save the deferred rules for later
- deferredInstructions.addAll(flowEntry.treatment().deferred());
-
- //If the flow requires to clear deferred actions we do so for all the ones we encountered.
- if (flowEntry.treatment().clearedDeferred()) {
- deferredInstructions.clear();
- }
-
- //On table 10 OFDPA needs two rules to apply the vlan if none and then to transition to the next table.
- if (needsSecondTable10Flow(flowEntry, isOfdpaHardware)) {
-
- //Let's get the packet vlanId instruction
- VlanIdCriterion packetVlanIdCriterion =
- (VlanIdCriterion) packet.getCriterion(Criterion.Type.VLAN_VID);
-
- //Let's get the flow entry vlan mod instructions
- ModVlanIdInstruction entryModVlanIdInstruction = (ModVlanIdInstruction) flowEntry.treatment()
- .immediate().stream()
- .filter(instruction -> instruction instanceof ModVlanIdInstruction)
- .findFirst().orElse(null);
-
- //If the entry modVlan is not null we need to make sure that the packet has been updated and there
- // is a flow rule that matches on same criteria and with updated vlanId
- if (entryModVlanIdInstruction != null) {
-
- FlowEntry secondVlanFlow = getSecondFlowEntryOnTable10(packet, in,
- packetVlanIdCriterion, entryModVlanIdInstruction);
-
- //We found the flow that we expected
- if (secondVlanFlow != null) {
- flows.add(secondVlanFlow);
- } else {
- trace.addResultMessage("Missing forwarding rule for tagged packet on " + in);
- computePath(completePath, trace, null);
- return trace;
- }
- }
-
- }
-
- }
+ // If there was an error set the success to false
+ if (output.getResult() != PipelineTraceableResult.SUCCESS) {
+ TroubleshootUtils.computePath(completePath, trace, null);
+ trace.setSuccess(false);
}
- //Creating a modifiable builder for the output packet
- Builder builder = DefaultTrafficSelector.builder();
- packet.criteria().forEach(builder::add);
+ log.info("Logs -> {}", output.getLog());
+ hitChains.forEach(hitChain -> log.info("HitChain -> {}", hitChain));
- //Adding all the flows to the trace
- trace.addFlowsForDevice(in.deviceId(), ImmutableList.copyOf(flows));
-
- List<PortNumber> outputPorts = new ArrayList<>();
- List<FlowEntry> outputFlowEntries = handleFlows(trace, packet, in, outputFlows, builder, outputPorts);
-
-
- log.debug("Handling Groups");
- //Analyze Groups
- List<Group> groups = new ArrayList<>();
-
- Collection<FlowEntry> nonOutputFlows = flows;
- nonOutputFlows.removeAll(outputFlowEntries);
-
- //Handling groups pointed at by immediate instructions
- for (FlowEntry entry : flows) {
- getGroupsFromInstructions(trace, groups, entry.treatment().immediate(),
- entry.deviceId(), builder, outputPorts, in, completePath);
- }
-
- //If we have deferred instructions at this point we handle them.
- if (deferredInstructions.size() > 0) {
- builder = handleDeferredActions(trace, packet, in, deferredInstructions, outputPorts, groups, completePath);
-
- }
- packet = builder.build();
-
- log.debug("Output Packet {}", packet);
+ // We are done!
return trace;
}
- private List<FlowEntry> handleFlows(StaticPacketTrace trace, TrafficSelector packet, ConnectPoint in,
- List<FlowEntry> outputFlows, Builder builder, List<PortNumber> outputPorts) {
- //TODO optimization
- //outputFlows contains also last rule of device, so we need filtering for OUTPUT instructions.
- List<FlowEntry> outputFlowEntries = outputFlows.stream().filter(flow -> flow.treatment()
- .allInstructions().stream().filter(instruction -> instruction.type()
- .equals(Instruction.Type.OUTPUT)).count() > 0).collect(Collectors.toList());
-
- if (outputFlowEntries.size() > 1) {
- trace.addResultMessage("More than one flow rule with OUTPUT instruction");
- log.warn("There cannot be more than one flow entry with OUTPUT instruction for {}", packet);
- }
-
- if (outputFlowEntries.size() == 1) {
-
- OutputInstruction outputInstruction = (OutputInstruction) outputFlowEntries.get(0).treatment()
- .allInstructions().stream()
- .filter(instruction -> {
- return instruction.type().equals(Instruction.Type.OUTPUT);
- }).findFirst().get();
-
- //FIXME using GroupsInDevice for output even if flows.
- buildOutputFromDevice(trace, in, builder, outputPorts, outputInstruction, ImmutableList.of());
-
- }
- return outputFlowEntries;
- }
-
+ // Compute whether or not there are multiple routes.
private boolean multipleRoutes(StaticPacketTrace trace) {
boolean multipleRoutes = false;
IPCriterion ipCriterion = ((IPCriterion) trace.getInitialPacket().getCriterion(Criterion.Type.IPV4_DST));
@@ -980,424 +762,51 @@
.collect(Collectors.toList());
//build an output from each one
enabledPorts.forEach(port -> {
- GroupsInDevice output = new GroupsInDevice(new ConnectPoint(port.element().id(), port.number()),
- ImmutableList.of(), trace.getInitialPacket());
- trace.addGroupOutputPath(in.deviceId(), output);
+ PipelineTraceableHitChain hitChain = new PipelineTraceableHitChain(
+ new ConnectPoint(port.element().id(), port.number()), ImmutableList.of(),
+ trace.getInitialPacket());
+ trace.addHitChain(in.deviceId(), hitChain);
});
return trace;
}
return null;
}
- private boolean needsSecondTable10Flow(FlowEntry flowEntry, boolean isOfdpaHardware) {
- return isOfdpaHardware && flowEntry.table().equals(IndexTableId.of(10))
- && flowEntry.selector().getCriterion(Criterion.Type.VLAN_VID) != null
- && ((VlanIdCriterion) flowEntry.selector().getCriterion(Criterion.Type.VLAN_VID))
- .vlanId().equals(VlanId.NONE);
- }
-
- /**
- * Method that finds a flow rule on table 10 that matches the packet and the VLAN of the already
- * found rule on table 10. This is because OFDPA needs two rules on table 10, first to apply the rule,
- * second to transition to following table
- *
- * @param packet the incoming packet
- * @param in the input connect point
- * @param packetVlanIdCriterion the vlan criterion from the packet
- * @param entryModVlanIdInstruction the entry vlan instruction
- * @return the second flow entry that matched
- */
- private FlowEntry getSecondFlowEntryOnTable10(TrafficSelector packet, ConnectPoint in,
- VlanIdCriterion packetVlanIdCriterion,
- ModVlanIdInstruction entryModVlanIdInstruction) {
- FlowEntry secondVlanFlow = null;
- //Check the packet has been update from the first rule.
- if (packetVlanIdCriterion.vlanId().equals(entryModVlanIdInstruction.vlanId())) {
- //find a rule on the same table that matches the vlan and
- // also all the other elements of the flow such as input port
- secondVlanFlow = Lists.newArrayList(flowNib.getFlowEntriesByState(in.deviceId(),
- FlowEntry.FlowEntryState.ADDED)
- .iterator()).stream()
- .filter(entry -> {
- return entry.table().equals(IndexTableId.of(10));
- })
- .filter(entry -> {
- VlanIdCriterion criterion = (VlanIdCriterion) entry.selector()
- .getCriterion(Criterion.Type.VLAN_VID);
- return criterion != null && match(packet, entry)
- && criterion.vlanId().equals(entryModVlanIdInstruction.vlanId());
- }).findFirst().orElse(null);
-
- }
- return secondVlanFlow;
- }
-
-
- /**
- * Handles table 27 in Ofpda which is a fixed table not visible to any controller that handles Mpls Labels.
- *
- * @param packet the incoming packet
- * @return the updated packet
- */
- private TrafficSelector handleOfdpa27FixedTable(StaticPacketTrace trace, TrafficSelector packet) {
- log.debug("Handling table 27 on OFDPA, removing mpls ETH Type and change mpls label");
- Criterion mplsCriterion = packet.getCriterion(Criterion.Type.ETH_TYPE);
- ImmutableList.Builder<Instruction> builder = ImmutableList.builder();
-
- //If the pakcet comes in with the expected elements we update it as per OFDPA spec.
- if (mplsCriterion != null && ((EthTypeCriterion) mplsCriterion).ethType()
- .equals(EtherType.MPLS_UNICAST.ethType())) {
- //TODO update with parsing with eth MPLS pop Instruction for treating label an bos
- Instruction ethInstruction = Instructions.popMpls(((EthTypeCriterion) trace.getInitialPacket()
- .getCriterion(Criterion.Type.ETH_TYPE)).ethType());
- //FIXME what do we use as L3_Unicast mpls Label ?
- //translateInstruction(builder, ethInstruction);
- builder.add(ethInstruction);
- }
- packet = updatePacket(packet, builder.build()).build();
- return packet;
- }
-
- /**
- * Finds the flow entry with the minimun next table Id.
- *
- * @param deviceId the device to search
- * @param currentId the current id. the search will use this as minimum
- * @return the flow entry with the minimum table Id after the given one.
- */
- private FlowEntry findNextTableIdEntry(DeviceId deviceId, int currentId) {
-
- final Comparator<FlowEntry> comparator = Comparator.comparing((FlowEntry f) -> ((IndexTableId) f.table()).id());
- return Lists.newArrayList(flowNib.getFlowEntriesByState(deviceId, FlowEntry.FlowEntryState.ADDED)
- .iterator()).stream()
- .filter(f -> ((IndexTableId) f.table()).id() > currentId).min(comparator).orElse(null);
- }
-
- private Builder handleDeferredActions(StaticPacketTrace trace, TrafficSelector packet,
- ConnectPoint in, List<Instruction> deferredInstructions,
- List<PortNumber> outputPorts, List<Group> groups,
- List<ConnectPoint> completePath) {
-
- //Update the packet with the deferred instructions
- Builder builder = updatePacket(packet, deferredInstructions);
-
- //Gather any output instructions from the deferred instruction
- List<Instruction> outputFlowInstruction = deferredInstructions.stream().filter(instruction -> {
- return instruction.type().equals(Instruction.Type.OUTPUT);
- }).collect(Collectors.toList());
-
- //We are considering deferred instructions from flows, there can only be one output.
- if (outputFlowInstruction.size() > 1) {
- trace.addResultMessage("More than one flow rule with OUTPUT instruction");
- log.warn("There cannot be more than one flow entry with OUTPUT instruction for {}", packet);
- }
- //If there is one output let's go through that
- if (outputFlowInstruction.size() == 1) {
- buildOutputFromDevice(trace, in, builder, outputPorts, (OutputInstruction) outputFlowInstruction.get(0),
- ImmutableList.of());
- }
- //If there is no output let's see if there any deferred instruction point to groups.
- if (outputFlowInstruction.size() == 0) {
- getGroupsFromInstructions(trace, groups, deferredInstructions,
- in.deviceId(), builder, outputPorts, in, completePath);
- }
- return builder;
- }
-
- /**
- * Gets group information from instructions.
- *
- * @param trace the trace we are building
- * @param groupsForDevice the set of groups for this device
- * @param instructions the set of instructions we are searching for groups.
- * @param deviceId the device we are considering
- * @param builder the builder of the input packet
- * @param outputPorts the output ports for that packet
- */
- private void getGroupsFromInstructions(StaticPacketTrace trace, List<Group> groupsForDevice,
- List<Instruction> instructions, DeviceId deviceId,
- Builder builder, List<PortNumber> outputPorts,
- ConnectPoint in, List<ConnectPoint> completePath) {
- List<Instruction> groupInstructionlist = new ArrayList<>();
- // sort instructions according to priority (larger Instruction.Type ENUM constant first)
- // which enables to treat other actions before the OUTPUT action
- //TODO improve the priority scheme according to the OpenFlow ActionSet spec
- List<Instruction> instructionsSorted = new ArrayList<>();
- instructionsSorted.addAll(instructions);
- instructionsSorted.sort((instr1, instr2) -> {
- return Integer.compare(instr2.type().ordinal(), instr1.type().ordinal());
- });
-
- for (Instruction instruction : instructionsSorted) {
- log.debug("Considering Instruction {}", instruction);
- //if the instruction is not group we need to update the packet or add the output
- //to the possible outputs for this packet
- if (!instruction.type().equals(Instruction.Type.GROUP)) {
- //if the instruction is not group we need to update the packet or add the output
- //to the possible outputs for this packet
- if (instruction.type().equals(Instruction.Type.OUTPUT)) {
- buildOutputFromDevice(trace, in, builder, outputPorts,
- (OutputInstruction) instruction, ImmutableList.copyOf(groupsForDevice));
- //clearing the groups because we start from the top.
- groupsForDevice.clear();
- } else {
- builder = translateInstruction(builder, instruction);
- }
- } else {
- //if the instuction is pointing to a group we need to get the group
- groupInstructionlist.add(instruction);
- }
- }
- //handle all the internal instructions pointing to a group.
- for (Instruction instr : groupInstructionlist) {
- GroupInstruction groupInstruction = (GroupInstruction) instr;
- Group group = Lists.newArrayList(groupNib.getGroups(deviceId)).stream().filter(groupInternal -> {
- return groupInternal.id().equals(groupInstruction.groupId());
- }).findAny().orElse(null);
- if (group == null) {
- trace.addResultMessage("Null group for Instruction " + instr);
- trace.setSuccess(false);
- break;
- }
- if (group.buckets().buckets().size() == 0) {
- trace.addResultMessage("Group " + group.id() + " has no buckets");
- trace.setSuccess(false);
- computePath(completePath, trace, null);
- break;
- }
-
- //Cycle in each of the group's buckets and add them to the groups for this Device.
- for (GroupBucket bucket : group.buckets().buckets()) {
-
- //add the group to the traversed groups
- if (!groupsForDevice.contains(group)) {
- groupsForDevice.add(group);
- }
-
- getGroupsFromInstructions(trace, groupsForDevice, bucket.treatment().allInstructions(),
- deviceId, builder, outputPorts, in, completePath);
- }
- }
- }
-
- /**
- * Check if the output is the input port, if so adds a dop result message, otherwise builds
- * a possible output from this device.
- *
- * @param trace the trace
- * @param in the input connect point
- * @param builder the packet builder
- * @param outputPorts the list of output ports for this device
- * @param outputInstruction the output instruction
- * @param groupsForDevice the groups we output from
- */
- private void buildOutputFromDevice(StaticPacketTrace trace, ConnectPoint in, Builder builder,
- List<PortNumber> outputPorts, OutputInstruction outputInstruction,
- List<Group> groupsForDevice) {
- ConnectPoint output = new ConnectPoint(in.deviceId(), outputInstruction.port());
-
- outputPorts.add(outputInstruction.port());
-
- GroupsInDevice device = new GroupsInDevice(output, groupsForDevice, builder.build());
- if (trace.getGroupOuputs(output.deviceId()) != null
- && trace.getGroupOuputs(output.deviceId()).contains(device)) {
- return;
- }
- trace.addGroupOutputPath(in.deviceId(),
- new GroupsInDevice(output, groupsForDevice, builder.build()));
- }
-
- /**
- * Applies all give instructions to the input packet.
- *
- * @param packet the input packet
- * @param instructions the set of instructions
- * @return the packet with the applied instructions
- */
- private Builder updatePacket(TrafficSelector packet, List<Instruction> instructions) {
- Builder newSelector = DefaultTrafficSelector.builder();
- packet.criteria().forEach(newSelector::add);
- //FIXME optimize
- for (Instruction instruction : instructions) {
- newSelector = translateInstruction(newSelector, instruction);
- }
- return newSelector;
- }
-
- /**
- * Applies an instruction to the packet in the form of a selector.
- *
- * @param newSelector the packet selector
- * @param instruction the instruction to be translated
- * @return the new selector with the applied instruction
- */
- private Builder translateInstruction(Builder newSelector, Instruction instruction) {
- log.debug("Translating instruction {}", instruction);
- log.debug("New Selector {}", newSelector.build());
- //TODO add as required
- Criterion criterion = null;
- switch (instruction.type()) {
- case L2MODIFICATION:
- L2ModificationInstruction l2Instruction = (L2ModificationInstruction) instruction;
- switch (l2Instruction.subtype()) {
- case VLAN_ID:
- ModVlanIdInstruction vlanIdInstruction =
- (ModVlanIdInstruction) instruction;
- VlanId id = vlanIdInstruction.vlanId();
- criterion = Criteria.matchVlanId(id);
- break;
- case VLAN_POP:
- criterion = Criteria.matchVlanId(VlanId.NONE);
- break;
- case MPLS_PUSH:
- ModMplsHeaderInstruction mplsEthInstruction =
- (ModMplsHeaderInstruction) instruction;
- criterion = Criteria.matchEthType(mplsEthInstruction.ethernetType().toShort());
- break;
- case MPLS_POP:
- ModMplsHeaderInstruction mplsPopInstruction =
- (ModMplsHeaderInstruction) instruction;
- criterion = Criteria.matchEthType(mplsPopInstruction.ethernetType().toShort());
-
- //When popping MPLS we remove label and BOS
- TrafficSelector temporaryPacket = newSelector.build();
- if (temporaryPacket.getCriterion(Criterion.Type.MPLS_LABEL) != null) {
- Builder noMplsSelector = DefaultTrafficSelector.builder();
- temporaryPacket.criteria().stream().filter(c -> {
- return !c.type().equals(Criterion.Type.MPLS_LABEL) &&
- !c.type().equals(Criterion.Type.MPLS_BOS);
- }).forEach(noMplsSelector::add);
- newSelector = noMplsSelector;
- }
-
- break;
- case MPLS_LABEL:
- ModMplsLabelInstruction mplsLabelInstruction =
- (ModMplsLabelInstruction) instruction;
- criterion = Criteria.matchMplsLabel(mplsLabelInstruction.label());
- newSelector.matchMplsBos(true);
- break;
- case ETH_DST:
- ModEtherInstruction modEtherDstInstruction =
- (ModEtherInstruction) instruction;
- criterion = Criteria.matchEthDst(modEtherDstInstruction.mac());
- break;
- case ETH_SRC:
- ModEtherInstruction modEtherSrcInstruction =
- (ModEtherInstruction) instruction;
- criterion = Criteria.matchEthSrc(modEtherSrcInstruction.mac());
- break;
- default:
- log.debug("Unsupported L2 Instruction");
- break;
- }
- break;
- default:
- log.debug("Unsupported Instruction");
- break;
- }
- if (criterion != null) {
- log.debug("Adding criterion {}", criterion);
- newSelector.add(criterion);
- }
- return newSelector;
- }
-
- /**
- * Finds the rule in the device that mathces the input packet and has the highest priority.
- *
- * @param packet the input packet
- * @param in the connect point the packet comes in from
- * @param tableId the table to search
- * @return the flow entry
- */
- private FlowEntry matchHighestPriority(TrafficSelector packet, ConnectPoint in, TableId tableId) {
- //Computing the possible match rules.
- final Comparator<FlowEntry> comparator = Comparator.comparing(FlowRule::priority);
- return Lists.newArrayList(flowNib.getFlowEntriesByState(in.deviceId(), FlowEntry.FlowEntryState.ADDED)
- .iterator()).stream()
- .filter(flowEntry -> {
- return flowEntry.table().equals(tableId);
- })
- .filter(flowEntry -> {
- return match(packet, flowEntry);
- }).max(comparator).orElse(null);
- }
-
- /**
- * Matches the packet with the given flow entry.
- *
- * @param packet the packet to match
- * @param flowEntry the flow entry to match the packet against
- * @return true if the packet matches the flow.
- */
- private boolean match(TrafficSelector packet, FlowEntry flowEntry) {
- return flowEntry.selector().criteria().stream().allMatch(criterion -> {
- Criterion.Type type = criterion.type();
- //If the criterion has IP we need to do LPM to establish matching.
- if (type.equals(Criterion.Type.IPV4_SRC) || type.equals(Criterion.Type.IPV4_DST) ||
- type.equals(Criterion.Type.IPV6_SRC) || type.equals(Criterion.Type.IPV6_DST)) {
- return matchIp(packet, (IPCriterion) criterion);
- //we check that the packet contains the criterion provided by the flow rule.
- } else if (type.equals(Criterion.Type.ETH_SRC_MASKED)) {
- return matchMac(packet, (EthCriterion) criterion, false);
- } else if (type.equals(Criterion.Type.ETH_DST_MASKED)) {
- return matchMac(packet, (EthCriterion) criterion, true);
- } else {
- return packet.criteria().contains(criterion);
+ ////////////////////////////////
+ // Cemetery - Deprecated code //
+ ////////////////////////////////
+ @Override
+ public List<StaticPacketTrace> pingAll(EtherType type) {
+ ImmutableList.Builder<StaticPacketTrace> tracesBuilder = ImmutableList.builder();
+ hostNib.getHosts().forEach(host -> {
+ List<IpAddress> ipAddresses = getIpAddresses(host, type, false);
+ if (ipAddresses.size() > 0) {
+ //check if the host has only local IPs of that ETH type
+ boolean onlyLocalSrc = ipAddresses.size() == 1 && ipAddresses.get(0).isLinkLocal();
+ hostNib.getHosts().forEach(hostToPing -> {
+ List<IpAddress> ipAddressesToPing = getIpAddresses(hostToPing, type, false);
+ //check if the other host has only local IPs of that ETH type
+ boolean onlyLocalDst = ipAddressesToPing.size() == 1 && ipAddressesToPing.get(0).isLinkLocal();
+ boolean sameLocation = Sets.intersection(host.locations(), hostToPing.locations()).size() > 0;
+ //Trace is done only if they are both local and under the same location
+ // or not local and if they are not the same host.
+ if (((sameLocation && onlyLocalDst && onlyLocalSrc) ||
+ (!onlyLocalSrc && !onlyLocalDst && ipAddressesToPing.size() > 0))
+ && !host.equals(hostToPing)) {
+ tracesBuilder.addAll(trace(host.id(), hostToPing.id(), type));
+ }
+ });
}
});
+ return tracesBuilder.build();
}
- /**
- * Checks if the packet has an dst or src IP and if that IP matches the subnet of the ip criterion.
- *
- * @param packet the incoming packet
- * @param criterion the criterion to match
- * @return true if match
- */
- private boolean matchIp(TrafficSelector packet, IPCriterion criterion) {
- IPCriterion matchCriterion = (IPCriterion) packet.getCriterion(criterion.type());
- //if the packet does not have an IPv4 or IPv6 criterion we return true
- if (matchCriterion == null) {
- return false;
- }
- try {
- log.debug("Checking if {} is under {}", matchCriterion.ip(), criterion.ip());
- Subnet subnet = Subnet.createInstance(criterion.ip().toString());
- return subnet.isInSubnet(matchCriterion.ip().address().toInetAddress());
- } catch (UnknownHostException e) {
- return false;
- }
+ @Override
+ public List<Set<StaticPacketTrace>> getMulitcastTrace(VlanId vlanId) {
+ Generator<Set<StaticPacketTrace>> gen = new McastGenerator(mcastRouteNib, this, vlanId);
+ List<Set<StaticPacketTrace>> multicastTraceList =
+ StreamSupport.stream(gen.spliterator(), false).collect(Collectors.toList());
+ return multicastTraceList;
}
- /**
- * Checks if the packet has a dst or src MAC and if that Mac matches the mask of the mac criterion.
- *
- * @param packet the incoming packet
- * @param hitCriterion the criterion to match
- * @param dst true if we are checking DST MAC
- * @return true if match
- */
- private boolean matchMac(TrafficSelector packet, EthCriterion hitCriterion, boolean dst) {
- //Packet can have only one EthCriterion
- EthCriterion matchCriterion;
- if (dst) {
- matchCriterion = (EthCriterion) packet.criteria().stream().filter(criterion1 -> {
- return criterion1.type().equals(Criterion.Type.ETH_DST_MASKED) ||
- criterion1.type().equals(Criterion.Type.ETH_DST);
- }).findFirst().orElse(null);
- } else {
- matchCriterion = (EthCriterion) packet.criteria().stream().filter(criterion1 -> {
- return criterion1.type().equals(Criterion.Type.ETH_SRC_MASKED) ||
- criterion1.type().equals(Criterion.Type.ETH_SRC);
- }).findFirst().orElse(null);
- }
- //if the packet does not have an ETH criterion we return true
- if (matchCriterion == null) {
- return true;
- }
- log.debug("Checking if {} is under {}/{}", matchCriterion.mac(), hitCriterion.mac(), hitCriterion.mask());
- return compareMac(matchCriterion.mac(), hitCriterion.mac(), hitCriterion.mask());
- }
}
diff --git a/app/src/main/java/org/onosproject/t3/impl/TroubleshootUtils.java b/app/src/main/java/org/onosproject/t3/impl/TroubleshootUtils.java
index 097fa92..ccc4715 100644
--- a/app/src/main/java/org/onosproject/t3/impl/TroubleshootUtils.java
+++ b/app/src/main/java/org/onosproject/t3/impl/TroubleshootUtils.java
@@ -16,10 +16,12 @@
package org.onosproject.t3.impl;
-import com.google.common.collect.ImmutableMap;
-import org.onlab.packet.MacAddress;
+import com.google.common.collect.ImmutableList;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.t3.api.StaticPacketTrace;
-import java.util.Map;
+import java.util.ArrayList;
+import java.util.List;
/**
* Utility class for the troubleshooting tool.
@@ -31,50 +33,33 @@
}
/**
- * Map defining if a specific driver is for a HW switch.
+ * Computes the list of traversed connect points.
+ *
+ * @param completePath the list of devices
+ * @param trace the trace we are building
+ * @param output the final output connect point
+ * @return true only if the path is successfully computed and added to the trace
*/
- //Done with builder() instead of of() for clarity
- static Map<String, Boolean> hardwareOfdpaMap = ImmutableMap.<String, Boolean>builder()
- .put("ofdpa", true)
- .put("ofdpa3", true)
- .put("qmx-ofdpa3", true)
- .put("as7712-32x-premium", true)
- .put("as5912-54x-premium", true)
- .put("as5916-54x-premium", true)
- .put("accton-ofdpa3", true)
- .put("delta-ofdpa3", true)
- .put("znyx-ofdpa", true)
- .build();
-
- /**
- * Checks if the Mac Address is inside a range between the min MAC and the mask.
- * @param macAddress the MAC address to check
- * @param minAddr the min MAC address
- * @param maskAddr the mask
- * @return true if in range, false otherwise.
- */
- static boolean compareMac(MacAddress macAddress, MacAddress minAddr, MacAddress maskAddr) {
- byte[] mac = macAddress.toBytes();
- byte[] min = minAddr.toBytes();
- byte[] mask = maskAddr.toBytes();
- boolean inRange = true;
-
- int i = 0;
-
- //if mask is 00 stop
- while (inRange && i < mask.length && (mask[i] & 0xFF) != 0) {
- int ibmac = mac[i] & 0xFF;
- int ibmin = min[i] & 0xFF;
- int ibmask = mask[i] & 0xFF;
- if (ibmask == 255) {
- inRange = ibmac == ibmin;
- } else if (ibmac < ibmin || ibmac >= ibmask) {
- inRange = false;
- break;
- }
- i++;
+ static boolean computePath(List<ConnectPoint> completePath, StaticPacketTrace trace, ConnectPoint output) {
+ List<ConnectPoint> traverseList = new ArrayList<>();
+ if (!completePath.contains(trace.getInitialConnectPoint())) {
+ traverseList.add(trace.getInitialConnectPoint());
}
- return inRange;
+ if (output != null && trace.getInitialConnectPoint().deviceId().equals(output.deviceId())) {
+ trace.addCompletePath(ImmutableList.of(trace.getInitialConnectPoint(), output));
+ return true;
+ }
+
+ traverseList.addAll(completePath);
+ if (output != null && !completePath.contains(output)) {
+ traverseList.add(output);
+ }
+ if (!trace.getCompletePaths().contains(traverseList)) {
+ trace.addCompletePath(ImmutableList.copyOf(traverseList));
+ return true;
+ }
+ return false;
}
+
}
diff --git a/app/src/main/java/org/onosproject/t3/rest/T3WebResource.java b/app/src/main/java/org/onosproject/t3/rest/T3WebResource.java
index 275be8c..571979f 100644
--- a/app/src/main/java/org/onosproject/t3/rest/T3WebResource.java
+++ b/app/src/main/java/org/onosproject/t3/rest/T3WebResource.java
@@ -23,6 +23,7 @@
import org.onlab.packet.EthType;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.VlanId;
+import org.onlab.util.Generator;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.HostId;
import org.onosproject.net.flow.FlowEntry;
@@ -47,6 +48,8 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.StreamSupport;
import static org.slf4j.LoggerFactory.getLogger;
@@ -153,13 +156,16 @@
final ObjectNode nodeOutput = mapper.createObjectNode();
nodeOutput.put("title", "Tracing all Multicast routes in the System");
- //Create the generator for the list of traces.
- List<Set<StaticPacketTrace>> generator = troubleshootService.getMulitcastTrace(VlanId.vlanId("None"));
+ // FIXME Vlan as argument and use None if not present
+ // Create the generator for the list of traces.
+ Generator<Set<StaticPacketTrace>> gen = troubleshootService.traceMcast(VlanId.NONE);
+ List<Set<StaticPacketTrace>> multicastTraceList = StreamSupport.stream(gen.spliterator(),
+ false).collect(Collectors.toList());
int totalTraces = 0;
List<StaticPacketTrace> failedTraces = new ArrayList<>();
StaticPacketTrace previousTrace = null;
ArrayNode traceArray = mapper.createArrayNode();
- for (Set<StaticPacketTrace> traces : generator) {
+ for (Set<StaticPacketTrace> traces : multicastTraceList) {
ObjectNode genNode = mapper.createObjectNode();
totalTraces++;
//Print also Route if possible or packet
@@ -321,6 +327,10 @@
* @param trace the trace
* @return a json representing the trace.
*/
+ // FIXME This part is completely broken, it will work only if the path size is 1
+ // Plan is to redefine the data model and uses arrays when printing each hop.
+ // In general there is a lot of confusion and the data model is not very clear
+ // and not easy to parse.
private ObjectNode getTrace(StaticPacketTrace trace, boolean verbose) {
ObjectNode nodeOutput = mapper.createObjectNode();
@@ -378,6 +388,7 @@
}
//Return groups Object for a given trace and a specified level of verbosity
+ // FIXME Double check
private ObjectNode getGroupObj(ConnectPoint connectPoint, GroupsInDevice output, boolean verbose) {
ArrayNode groupArray = mapper.createArrayNode();
ObjectNode groupsObj = mapper.createObjectNode();
@@ -402,6 +413,7 @@
}
//Return flows Object for a given trace and a specified level of verbosity
+ // FIXME Double check
private ArrayNode getFlowArray(StaticPacketTrace trace, ConnectPoint connectPoint, boolean verbose) {
ArrayNode flowArray = mapper.createArrayNode();
trace.getFlowsForDevice(connectPoint.deviceId()).forEach(f -> {
diff --git a/app/src/test/java/org/onosproject/t3/impl/T3TestObjects.java b/app/src/test/java/org/onosproject/t3/impl/T3TestObjects.java
index 2ec39b4..2a8d1bf 100644
--- a/app/src/test/java/org/onosproject/t3/impl/T3TestObjects.java
+++ b/app/src/test/java/org/onosproject/t3/impl/T3TestObjects.java
@@ -113,6 +113,10 @@
//ARP
static final DeviceId ARP_FLOW_DEVICE = DeviceId.deviceId("ArpDevice");
+ private static final TrafficSelector PORT_SELECTOR = DefaultTrafficSelector.builder()
+ .matchInPort(PortNumber.portNumber(1))
+ .build();
+
private static final TrafficSelector ARP_FLOW_SELECTOR = DefaultTrafficSelector.builder()
.matchInPort(PortNumber.portNumber(1))
.matchEthType(EthType.EtherType.ARP.ethType().toShort())
@@ -121,7 +125,7 @@
private static final TrafficTreatment ARP_FLOW_TREATMENT = DefaultTrafficTreatment.builder()
.setOutput(PortNumber.CONTROLLER).build();
private static final FlowRule ARP_FLOW = DefaultFlowEntry.builder().forDevice(ARP_FLOW_DEVICE)
- .forTable(0)
+ .forTable(10)
.withPriority(100)
.withSelector(ARP_FLOW_SELECTOR)
.withTreatment(ARP_FLOW_TREATMENT)
@@ -132,13 +136,28 @@
static final ConnectPoint ARP_FLOW_CP = ConnectPoint.deviceConnectPoint(ARP_FLOW_DEVICE + "/" + 1);
+ // ARP Vlan test
+ static final DeviceId ARP_FLOW_VLAN_DEVICE = DeviceId.deviceId("ArpDeviceVlan");
- //Dual Flow Test
- static final DeviceId DUAL_FLOW_DEVICE = DeviceId.deviceId("DualFlowDevice");
private static final TrafficTreatment TRANSITION_FLOW_TREATMENT = DefaultTrafficTreatment.builder()
.setVlanId(VlanId.vlanId((short) 100))
.transition(10)
.build();
+ private static final FlowRule ARP_FLOW_VLAN = DefaultFlowEntry.builder().forDevice(ARP_FLOW_VLAN_DEVICE)
+ .forTable(0)
+ .withPriority(100)
+ .withSelector(PORT_SELECTOR)
+ .withTreatment(TRANSITION_FLOW_TREATMENT)
+ .fromApp(new DefaultApplicationId(0, "TestApp"))
+ .makePermanent()
+ .build();
+ static final FlowEntry ARP_FLOW_VLAN_ENTRY = new DefaultFlowEntry(ARP_FLOW_VLAN);
+
+ static final ConnectPoint ARP_FLOW_VLAN_CP = ConnectPoint.deviceConnectPoint(ARP_FLOW_VLAN_DEVICE + "/" + 1);
+
+ //Dual Flow Test
+ static final DeviceId DUAL_FLOW_DEVICE = DeviceId.deviceId("DualFlowDevice");
+
private static final TrafficSelector VLAN_FLOW_SELECTOR = DefaultTrafficSelector.builder()
.matchVlanId(VlanId.vlanId((short) 100))
.build();
@@ -199,39 +218,6 @@
static final ConnectPoint GROUP_FLOW_OUT_CP = ConnectPoint.deviceConnectPoint(GROUP_FLOW_DEVICE + "/" + 2);
- // Group multiple action order test
- static final DeviceId ACTION_ORDER_DEVICE = DeviceId.deviceId("ActionOrderDevice");
- private static final VlanId ACTION_ORDER_VLAN_ID = VlanId.vlanId("999");
- static final MplsLabel ACTION_ORDER_MPLS_LABEL = MplsLabel.mplsLabel("999");
- private static final TrafficTreatment ACTION_ORDER_FLOW_TREATMENT = DefaultTrafficTreatment.builder()
- .pushVlan()
- .setVlanId(ACTION_ORDER_VLAN_ID)
- .group(GROUP_ID)
- .build();
- private static final FlowRule ACTION_ORDER_FLOW = DefaultFlowEntry.builder().forDevice(ACTION_ORDER_DEVICE)
- .forTable(0)
- .withPriority(100)
- .withSelector(SINGLE_FLOW_SELECTOR)
- .withTreatment(ACTION_ORDER_FLOW_TREATMENT)
- .fromApp(new DefaultApplicationId(0, "TestApp"))
- .makePermanent()
- .build();
- static final FlowEntry ACTION_ORDER_FLOW_ENTRY = new DefaultFlowEntry(ACTION_ORDER_FLOW);
- private static final TrafficTreatment ACTION_ORDER_GROUP_TREATMENT = DefaultTrafficTreatment.builder()
- // make lower order actions come first
- .setOutput(PortNumber.portNumber(2))
- .setMpls(ACTION_ORDER_MPLS_LABEL)
- .pushMpls()
- .popVlan()
- .build();
- private static final GroupBucket ACTION_ORDER_BUCKET = DefaultGroupBucket
- .createSelectGroupBucket(ACTION_ORDER_GROUP_TREATMENT);
- private static final GroupBuckets ACTION_ORDER_BUCKETS = new GroupBuckets(ImmutableList.of(ACTION_ORDER_BUCKET));
- static final Group ACTION_ORDER_GROUP = new DefaultGroup(
- GROUP_ID, ACTION_ORDER_DEVICE, Group.Type.SELECT, ACTION_ORDER_BUCKETS);
- static final ConnectPoint ACTION_ORDER_IN_CP = ConnectPoint.deviceConnectPoint(ACTION_ORDER_DEVICE + "/" + 1);
- static final ConnectPoint ACTION_ORDER_OUT_CP = ConnectPoint.deviceConnectPoint(ACTION_ORDER_DEVICE + "/" + 2);
-
//topology
static final DeviceId TOPO_FLOW_DEVICE = DeviceId.deviceId("SingleFlowDevice1");
@@ -332,116 +318,6 @@
static final ConnectPoint TOPO_FLOW_4_OUT_CP = ConnectPoint.deviceConnectPoint(TOPO_FLOW_4_DEVICE + "/" + 2);
-
- //hardware
-
- static final DeviceId HARDWARE_DEVICE = DeviceId.deviceId("HardwareDevice");
-
- static final ConnectPoint HARDWARE_DEVICE_IN_CP = ConnectPoint.deviceConnectPoint(HARDWARE_DEVICE + "/" + 1);
-
- static final ConnectPoint HARDWARE_DEVICE_OUT_CP = ConnectPoint.deviceConnectPoint(HARDWARE_DEVICE + "/" + 2);
-
- private static final TrafficSelector HARDWARE_FLOW_SELECTOR = DefaultTrafficSelector.builder()
- .matchInPort(PortNumber.portNumber(1))
- .matchIPSrc(IpPrefix.valueOf("127.0.0.1/32"))
- .matchIPDst(IpPrefix.valueOf("127.0.0.2/32"))
- .build();
-
- private static final TrafficTreatment HW_TRANSITION_FLOW_TREATMENT = DefaultTrafficTreatment.builder()
- .pushMpls()
- .transition(27)
- .build();
-
- private static final FlowRule HARDWARE_FLOW = DefaultFlowEntry.builder().forDevice(TOPO_FLOW_3_DEVICE)
- .forTable(0)
- .withPriority(100)
- .withSelector(HARDWARE_FLOW_SELECTOR)
- .withTreatment(HW_TRANSITION_FLOW_TREATMENT)
- .fromApp(new DefaultApplicationId(0, "TestApp"))
- .makePermanent()
- .build();
-
- static final FlowEntry HARDWARE_FLOW_ENTRY = new DefaultFlowEntry(HARDWARE_FLOW);
-
- private static final TrafficSelector HARDWARE_ETH_FLOW_SELECTOR = DefaultTrafficSelector.builder()
- .matchInPort(PortNumber.portNumber(1))
- .matchIPSrc(IpPrefix.valueOf("127.0.0.1/32"))
- .matchIPDst(IpPrefix.valueOf("127.0.0.2/32"))
- .matchEthType(EthType.EtherType.IPV4.ethType().toShort())
- .build();
-
- private static final FlowRule HARDWARE_ETH_FLOW = DefaultFlowEntry.builder().forDevice(TOPO_FLOW_3_DEVICE)
- .forTable(30)
- .withPriority(100)
- .withSelector(HARDWARE_ETH_FLOW_SELECTOR)
- .withTreatment(OUTPUT_FLOW_TREATMENT)
- .fromApp(new DefaultApplicationId(0, "TestApp"))
- .makePermanent()
- .build();
-
- static final FlowEntry HARDWARE_ETH_FLOW_ENTRY = new DefaultFlowEntry(HARDWARE_ETH_FLOW);
-
- //HW Double Rule on 10
-
- static final DeviceId HARDWARE_DEVICE_10 = DeviceId.deviceId("HardwareDevice10");
-
- static final ConnectPoint HARDWARE_DEVICE_10_IN_CP = ConnectPoint.deviceConnectPoint(HARDWARE_DEVICE_10 + "/" + 1);
-
- static final ConnectPoint HARDWARE_DEVICE_10_OUT_CP = ConnectPoint.deviceConnectPoint(HARDWARE_DEVICE_10 + "/" + 2);
-
- private static final TrafficSelector HARDWARE_10_FLOW_SELECTOR = DefaultTrafficSelector.builder()
- .matchInPort(PortNumber.portNumber(1))
- .matchIPSrc(IpPrefix.valueOf("127.0.0.1/32"))
- .matchIPDst(IpPrefix.valueOf("127.0.0.2/32"))
- .matchVlanId(VlanId.NONE)
- .build();
-
- private static final TrafficTreatment HARDWARE_10_TRANSITION_FLOW_TREATMENT = DefaultTrafficTreatment.builder()
- .setVlanId(VlanId.vlanId("10"))
- .transition(20)
- .build();
-
- private static final FlowRule HARDWARE_DEVICE_10_FLOW = DefaultFlowEntry.builder().forDevice(HARDWARE_DEVICE_10)
- .forTable(10)
- .withPriority(100)
- .withSelector(HARDWARE_10_FLOW_SELECTOR)
- .withTreatment(HARDWARE_10_TRANSITION_FLOW_TREATMENT)
- .fromApp(new DefaultApplicationId(0, "TestApp"))
- .makePermanent()
- .build();
-
- static final FlowEntry HARDWARE_10_FLOW_ENTRY = new DefaultFlowEntry(HARDWARE_DEVICE_10_FLOW);
-
- private static final TrafficSelector HARDWARE_10_SECOND_SELECTOR = DefaultTrafficSelector.builder()
- .matchInPort(PortNumber.portNumber(1))
- .matchVlanId(VlanId.vlanId("10"))
- .matchIPSrc(IpPrefix.valueOf("127.0.0.1/32"))
- .matchIPDst(IpPrefix.valueOf("127.0.0.2/32"))
- .matchEthType(EthType.EtherType.IPV4.ethType().toShort())
- .build();
-
- private static final FlowRule HARDWARE_10_SECOND_FLOW = DefaultFlowEntry.builder().forDevice(HARDWARE_DEVICE_10)
- .forTable(10)
- .withPriority(100)
- .withSelector(HARDWARE_10_SECOND_SELECTOR)
- .withTreatment(HARDWARE_10_TRANSITION_FLOW_TREATMENT)
- .fromApp(new DefaultApplicationId(0, "TestApp"))
- .makePermanent()
- .build();
-
- static final FlowEntry HARDWARE_10_SECOND_FLOW_ENTRY = new DefaultFlowEntry(HARDWARE_10_SECOND_FLOW);
-
- private static final FlowRule HARDWARE_10_OUTPUT_FLOW = DefaultFlowEntry.builder().forDevice(HARDWARE_DEVICE_10)
- .forTable(20)
- .withPriority(100)
- .withSelector(SINGLE_FLOW_SELECTOR)
- .withTreatment(OUTPUT_FLOW_TREATMENT)
- .fromApp(new DefaultApplicationId(0, "TestApp"))
- .makePermanent()
- .build();
-
- static final FlowEntry HARDWARE_10_OUTPUT_FLOW_ENTRY = new DefaultFlowEntry(HARDWARE_10_OUTPUT_FLOW);
-
//Dual Links
// - (1) Device 1 (2-3) - (1-4) Device 2 (2-3) - (1-2) Device 3 (3) -
static final DeviceId DUAL_LINK_1 = DeviceId.deviceId("DualLink1");
@@ -538,29 +414,6 @@
static final Group DUAL_LINK_GROUP = new DefaultGroup(GROUP_ID, DUAL_LINK_1, Group.Type.SELECT, BUCKETS_DUAL);
- //Clear Deferred
- static final DeviceId DEFERRED_1 = DeviceId.deviceId("Deferred");
-
- static final ConnectPoint DEFERRED_CP_1_IN = ConnectPoint.deviceConnectPoint(DEFERRED_1 + "/" + 1);
- static final ConnectPoint DEFERRED_CP_2_OUT = ConnectPoint.deviceConnectPoint(DEFERRED_1 + "/" + 2);
-
- //match on port 1 and apply deferred actions
- private static final TrafficTreatment DEFERRED_1_FLOW_TREATMENT = DefaultTrafficTreatment.builder()
- .transition(10)
- .deferred()
- .pushMpls()
- .setMpls(MplsLabel.mplsLabel(100))
- .build();
- private static final FlowRule DEFERRED_FLOW = DefaultFlowEntry.builder().forDevice(DEFERRED_1)
- .forTable(0)
- .withPriority(100)
- .withSelector(SINGLE_FLOW_SELECTOR)
- .withTreatment(DEFERRED_1_FLOW_TREATMENT)
- .fromApp(new DefaultApplicationId(0, "TestApp"))
- .makePermanent()
- .build();
- static final FlowEntry DEFERRED_FLOW_ENTRY = new DefaultFlowEntry(DEFERRED_FLOW);
-
//Multicast Flow and Group Test
static final DeviceId MULTICAST_GROUP_FLOW_DEVICE = DeviceId.deviceId("MulticastGroupFlowDevice");
@@ -592,21 +445,6 @@
static final ConnectPoint MULTICAST_OUT_CP_2 =
ConnectPoint.deviceConnectPoint(MULTICAST_GROUP_FLOW_DEVICE + "/" + 2);
- //match on port 1, clear deferred actions and output
- private static final TrafficTreatment DEFERRED_CLEAR_1_FLOW_TREATMENT = DefaultTrafficTreatment.builder()
- .wipeDeferred()
- .setOutput(PortNumber.portNumber(2))
- .build();
- private static final FlowRule DEFERRED_CLEAR_FLOW = DefaultFlowEntry.builder().forDevice(DEFERRED_1)
- .forTable(10)
- .withPriority(100)
- .withSelector(SINGLE_FLOW_SELECTOR)
- .withTreatment(DEFERRED_CLEAR_1_FLOW_TREATMENT)
- .fromApp(new DefaultApplicationId(0, "TestApp"))
- .makePermanent()
- .build();
- static final FlowEntry DEFERRED_CLEAR_FLOW_ENTRY = new DefaultFlowEntry(DEFERRED_CLEAR_FLOW);
-
//LLDP
static final DeviceId LLDP_FLOW_DEVICE = DeviceId.deviceId("LldpDevice");
@@ -752,6 +590,7 @@
.matchIPSrc(IpPrefix.valueOf("127.0.0.1/32"))
.matchIPDst(IpPrefix.valueOf("127.0.0.2/32"))
.matchVlanId(VlanId.NONE)
+ .matchMetadata(EthType.EtherType.IPV4.ethType().toShort())
.build();
static final TrafficSelector PACKET_OK_TOPO = DefaultTrafficSelector.builder()
@@ -764,6 +603,7 @@
.matchInPort(PortNumber.portNumber(1))
.matchIPDst(IpPrefix.valueOf("255.255.255.255/32"))
.matchEthType(EthType.EtherType.ARP.ethType().toShort())
+ .matchVlanId(VlanId.NONE)
.build();
static final TrafficSelector PACKET_LLDP = DefaultTrafficSelector.builder()
@@ -790,4 +630,11 @@
.matchIPSrc(IpPrefix.valueOf("127.0.0.1/32"))
.matchIPDst(IpPrefix.valueOf("127.0.0.99/32"))
.build();
+
+ static final String OFDPA_DRIVER = "ofdpa";
+ static final String MANUFACTURER = "test";
+ static final String HW_VERSION = "test";
+ static final String SW_VERSION = "test";
+ static final String SERIAL_NUMBER = "test";
+
}
diff --git a/app/src/test/java/org/onosproject/t3/impl/TroubleshootManagerTest.java b/app/src/test/java/org/onosproject/t3/impl/TroubleshootManagerTest.java
index d1eba21..3ab8f91 100644
--- a/app/src/test/java/org/onosproject/t3/impl/TroubleshootManagerTest.java
+++ b/app/src/test/java/org/onosproject/t3/impl/TroubleshootManagerTest.java
@@ -17,6 +17,7 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
import org.junit.Before;
import org.junit.Test;
import org.onlab.packet.ChassisId;
@@ -25,7 +26,12 @@
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onosproject.cluster.NodeId;
+import org.onosproject.driver.pipeline.ofdpa.Ofdpa2Pipeline;
+import org.onosproject.driver.traceable.OfdpaPipelineTraceable;
+import org.onosproject.net.AbstractProjectableModel;
+import org.onosproject.net.AnnotationKeys;
import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DataPlaneEntity;
import org.onosproject.net.DefaultAnnotations;
import org.onosproject.net.DefaultDevice;
import org.onosproject.net.DefaultLink;
@@ -36,11 +42,19 @@
import org.onosproject.net.Link;
import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
+import org.onosproject.net.SparseAnnotations;
+import org.onosproject.net.behaviour.PipelineTraceable;
+import org.onosproject.net.driver.Behaviour;
+import org.onosproject.net.driver.Driver;
+import org.onosproject.net.driver.DriverAdapter;
+import org.onosproject.net.driver.DriverHandler;
+import org.onosproject.net.driver.DriverService;
+import org.onosproject.net.driver.DriverServiceAdapter;
+import org.onosproject.net.driver.HandlerBehaviour;
import org.onosproject.net.flow.FlowEntry;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.criteria.Criterion;
import org.onosproject.net.flow.criteria.EthTypeCriterion;
-import org.onosproject.net.flow.criteria.MplsCriterion;
import org.onosproject.net.flow.criteria.VlanIdCriterion;
import org.onosproject.net.group.Group;
import org.onosproject.net.provider.ProviderId;
@@ -57,6 +71,7 @@
import org.onosproject.t3.api.StaticPacketTrace;
import org.slf4j.Logger;
+import java.util.List;
import java.util.Optional;
import java.util.Set;
@@ -75,11 +90,15 @@
public class TroubleshootManagerTest {
private static final Logger log = getLogger(TroubleshootManager.class);
-
private TroubleshootManager mngr;
+ private Driver baseDriver = new TestDriver();
@Before
public void setUp() throws Exception {
+ // Setup step for the device
+ DriverService testDeviceService = new TestDriverService();
+ AbstractProjectableModel.setDriverService(null, testDeviceService);
+
mngr = new TroubleshootManager();
mngr.flowNib = new TestFlowRuleService();
@@ -87,7 +106,7 @@
mngr.hostNib = new TestHostService();
mngr.linkNib = new TestLinkService();
mngr.deviceNib = new TestDeviceService();
- mngr.driverNib = new TestDriverService();
+ mngr.driverNib = new TestDriverNib();
mngr.mastershipNib = new TestMastershipService();
mngr.edgePortNib = new TestEdgePortService();
mngr.routeNib = new TestRouteService();
@@ -111,6 +130,7 @@
@Test(expected = NullPointerException.class)
public void nonExistentDevice() {
StaticPacketTrace traceFail = mngr.trace(PACKET_OK, ConnectPoint.deviceConnectPoint("nonexistent" + "/1"));
+ log.info("trace {}", traceFail.resultMessage());
}
/**
@@ -120,7 +140,10 @@
public void offlineDevice() {
StaticPacketTrace traceFail = mngr.trace(PACKET_OK, ConnectPoint.deviceConnectPoint(OFFLINE_DEVICE + "/1"));
assertNotNull("Trace should not be null", traceFail);
- assertNull("Trace should have 0 output", traceFail.getGroupOuputs(SINGLE_FLOW_DEVICE));
+ assertTrue("Device should be offline",
+ traceFail.resultMessage().contains("Device is offline"));
+ assertNull("Trace should have 0 output", traceFail.getHitChains(SINGLE_FLOW_DEVICE));
+ log.info("trace {}", traceFail.resultMessage());
}
/**
@@ -146,13 +169,32 @@
traceSuccess.resultMessage().contains(PACKET_TO_CONTROLLER));
assertTrue("Master should be Master1",
traceSuccess.resultMessage().contains(MASTER_1));
- ConnectPoint connectPoint = traceSuccess.getGroupOuputs(ARP_FLOW_DEVICE).get(0).getOutput();
+ ConnectPoint connectPoint = traceSuccess.getHitChains(ARP_FLOW_DEVICE).get(0).getOutputPort();
assertEquals("Packet Should go to CONTROLLER", PortNumber.CONTROLLER, connectPoint.port());
- assertNull("VlanId should be null", traceSuccess.getGroupOuputs(ARP_FLOW_DEVICE).get(0)
- .getFinalPacket().getCriterion(Criterion.Type.VLAN_VID));
+ VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) traceSuccess.getHitChains(ARP_FLOW_DEVICE).get(0)
+ .getEgressPacket().getCriterion(Criterion.Type.VLAN_VID);
+ assertEquals("VlanId should be None", VlanId.NONE, vlanIdCriterion.vlanId());
log.info("trace {}", traceSuccess.resultMessage());
}
+ /**
+ * Tests ARP to controller and Vlan id removal.
+ */
+ @Test
+ public void arpToControllerVlan() {
+ StaticPacketTrace traceSuccess = mngr.trace(PACKET_ARP, ARP_FLOW_VLAN_CP);
+ assertNotNull("Trace should not be null", traceSuccess);
+ assertTrue("Trace should be successful",
+ traceSuccess.resultMessage().contains(PACKET_TO_CONTROLLER));
+ assertTrue("Master should be Master1",
+ traceSuccess.resultMessage().contains(MASTER_1));
+ ConnectPoint connectPoint = traceSuccess.getHitChains(ARP_FLOW_VLAN_DEVICE).get(0).getOutputPort();
+ assertEquals("Packet Should go to CONTROLLER", PortNumber.CONTROLLER, connectPoint.port());
+ VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) traceSuccess.getHitChains(ARP_FLOW_VLAN_DEVICE).get(0)
+ .getEgressPacket().getCriterion(Criterion.Type.VLAN_VID);
+ assertEquals("VlanId should be None", VlanId.NONE, vlanIdCriterion.vlanId());
+ log.info("trace {}", traceSuccess.resultMessage());
+ }
/**
* Tests failure on device with no flows.
@@ -161,7 +203,7 @@
public void noFlows() {
StaticPacketTrace traceFail = mngr.trace(PACKET_OK, ConnectPoint.deviceConnectPoint("test/1"));
assertNotNull("Trace should not be null", traceFail);
- assertNull("Trace should have 0 output", traceFail.getGroupOuputs(SINGLE_FLOW_DEVICE));
+ assertNull("Trace should have 0 output", traceFail.getHitChains(SINGLE_FLOW_DEVICE));
log.info("trace {}", traceFail.resultMessage());
}
@@ -169,14 +211,12 @@
* Test group with no buckets.
*/
@Test
- public void noBucketsTest() throws Exception {
-
+ public void noBucketsTest() {
StaticPacketTrace traceFail = mngr.trace(PACKET_OK, NO_BUCKET_CP);
assertNotNull("Trace should not be null", traceFail);
assertTrue("Trace should be unsuccessful",
traceFail.resultMessage().contains("no buckets"));
log.info("trace {}", traceFail.resultMessage());
-
}
/**
@@ -184,10 +224,10 @@
*/
@Test
public void testSingleFlowRule() {
-
+ // Happy ending
testSuccess(PACKET_OK, SINGLE_FLOW_IN_CP, SINGLE_FLOW_DEVICE, SINGLE_FLOW_OUT_CP, 1, 1);
-
- testFailure(PACKET_FAIL, SINGLE_FLOW_IN_CP, SINGLE_FLOW_DEVICE);
+ // Failure scenario
+ testFailure(PACKET_FAIL, SINGLE_FLOW_IN_CP, SINGLE_FLOW_DEVICE, 1);
}
/**
@@ -195,161 +235,95 @@
*/
@Test
public void testDualFlowRule() {
-
- //Test Success
-
+ // Test Success
StaticPacketTrace traceSuccess = testSuccess(PACKET_OK, DUAL_FLOW_IN_CP, DUAL_FLOW_DEVICE,
DUAL_FLOW_OUT_CP, 1, 1);
-
- //Testing Vlan
- Criterion criterion = traceSuccess.getGroupOuputs(DUAL_FLOW_DEVICE).get(0).
- getFinalPacket().getCriterion(Criterion.Type.VLAN_VID);
+ // Verifying Vlan
+ Criterion criterion = traceSuccess.getHitChains(DUAL_FLOW_DEVICE).get(0).
+ getEgressPacket().getCriterion(Criterion.Type.VLAN_VID);
assertNotNull("Packet Should have Vlan", criterion);
-
VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) criterion;
-
assertEquals("Vlan should be 100", VlanId.vlanId((short) 100), vlanIdCriterion.vlanId());
- //Test Faliure
- testFailure(PACKET_FAIL, DUAL_FLOW_IN_CP, DUAL_FLOW_DEVICE);
-
+ // Test Failure
+ testFailure(PACKET_FAIL, DUAL_FLOW_IN_CP, DUAL_FLOW_DEVICE, 1);
}
/**
* Test a single flow rule that points to a group with output port in it.
*/
@Test
- public void flowAndGroup() throws Exception {
-
+ public void flowAndGroup() {
+ // Test Success
StaticPacketTrace traceSuccess = testSuccess(PACKET_OK, GROUP_FLOW_IN_CP, GROUP_FLOW_DEVICE,
GROUP_FLOW_OUT_CP, 1, 1);
-
- assertTrue("Wrong Output Group", traceSuccess.getGroupOuputs(GROUP_FLOW_DEVICE)
- .get(0).getGroups().contains(GROUP));
+ // Verify the output of the test
+ assertTrue("Wrong Output Group", traceSuccess.getHitChains(GROUP_FLOW_DEVICE)
+ .get(0).getHitChain().contains(new DataPlaneEntity(GROUP)));
assertEquals("Packet should not have MPLS Label", EthType.EtherType.IPV4.ethType(),
- ((EthTypeCriterion) traceSuccess.getGroupOuputs(GROUP_FLOW_DEVICE)
- .get(0).getFinalPacket().getCriterion(Criterion.Type.ETH_TYPE)).ethType());
- assertNull("Packet should not have MPLS Label", traceSuccess.getGroupOuputs(GROUP_FLOW_DEVICE)
- .get(0).getFinalPacket().getCriterion(Criterion.Type.MPLS_LABEL));
- assertNull("Packet should not have MPLS Label", traceSuccess.getGroupOuputs(GROUP_FLOW_DEVICE)
- .get(0).getFinalPacket().getCriterion(Criterion.Type.MPLS_BOS));
-
- }
-
- /**
- * Test a single flow rule that points to a group with multiple actions
- * that need to be executed in the order specified in the OpenFlow spec.
- */
- @Test
- public void testGroupMultipleActionsOrdered() {
-
- StaticPacketTrace traceSuccess = testSuccess(
- PACKET_OK, ACTION_ORDER_IN_CP, ACTION_ORDER_DEVICE, ACTION_ORDER_OUT_CP, 1, 1);
-
- assertEquals("Packet should not have VLAN ID",
- VlanId.NONE,
- ((VlanIdCriterion) traceSuccess.getGroupOuputs(ACTION_ORDER_DEVICE)
- .get(0).getFinalPacket().getCriterion(Criterion.Type.VLAN_VID)).vlanId());
- assertEquals("Packet should have MPLS label",
- ACTION_ORDER_MPLS_LABEL,
- ((MplsCriterion) traceSuccess.getGroupOuputs(ACTION_ORDER_DEVICE)
- .get(0).getFinalPacket().getCriterion(Criterion.Type.MPLS_LABEL)).label());
-
+ ((EthTypeCriterion) traceSuccess.getHitChains(GROUP_FLOW_DEVICE)
+ .get(0).getEgressPacket().getCriterion(Criterion.Type.ETH_TYPE)).ethType());
+ assertNull("Packet should not have MPLS Label", traceSuccess.getHitChains(GROUP_FLOW_DEVICE)
+ .get(0).getEgressPacket().getCriterion(Criterion.Type.MPLS_LABEL));
+ assertNull("Packet should not have MPLS BoS", traceSuccess.getHitChains(GROUP_FLOW_DEVICE)
+ .get(0).getEgressPacket().getCriterion(Criterion.Type.MPLS_BOS));
}
/**
* Test path through a 3 device topology.
*/
@Test
- public void singlePathTopology() throws Exception {
-
+ public void singlePathTopology() {
+ // Test success
StaticPacketTrace traceSuccess = testSuccess(PACKET_OK_TOPO, TOPO_FLOW_1_IN_CP,
TOPO_FLOW_3_DEVICE, TOPO_FLOW_3_OUT_CP, 1, 1);
-
- assertTrue("Incorrect path",
- traceSuccess.getCompletePaths().get(0).contains(TOPO_FLOW_2_IN_CP));
- assertTrue("Incorrect path",
- traceSuccess.getCompletePaths().get(0).contains(TOPO_FLOW_2_OUT_CP));
- assertTrue("Incorrect path",
- traceSuccess.getCompletePaths().get(0).contains(TOPO_FLOW_3_IN_CP));
-
+ // Verify that the complete path contains all the traversed connect points
+ List<ConnectPoint> path = Lists.newArrayList(TOPO_FLOW_1_IN_CP, TOPO_FLOW_1_OUT_CP,
+ TOPO_FLOW_2_IN_CP, TOPO_FLOW_2_OUT_CP, TOPO_FLOW_3_IN_CP, TOPO_FLOW_3_OUT_CP);
+ assertEquals(path, traceSuccess.getCompletePaths().get(0));
}
/**
* Test path through a 4 device topology with first device that has groups with multiple output buckets.
*/
@Test
- public void testGroupTopo() throws Exception {
-
+ public void testGroupTopo() {
+ // Test success
StaticPacketTrace traceSuccess = testSuccess(PACKET_OK_TOPO, TOPO_FLOW_IN_CP,
TOPO_FLOW_3_DEVICE, TOPO_FLOW_3_OUT_CP, 2, 1);
-
- log.info("{}", traceSuccess);
-
+ // Verify the multiple output actions
assertTrue("Incorrect groups",
- traceSuccess.getGroupOuputs(TOPO_GROUP_FLOW_DEVICE).get(0).getGroups().contains(TOPO_GROUP));
+ traceSuccess.getHitChains(TOPO_GROUP_FLOW_DEVICE).get(0).getHitChain()
+ .contains(new DataPlaneEntity(TOPO_GROUP)));
assertTrue("Incorrect bucket",
- traceSuccess.getGroupOuputs(TOPO_GROUP_FLOW_DEVICE).get(1).getGroups().contains(TOPO_GROUP));
- }
-
- /**
- * Test HW support in a single device with 2 flow rules to check hit of static HW rules.
- */
- @Test
- public void hardwareTest() throws Exception {
-
- StaticPacketTrace traceSuccess = testSuccess(PACKET_OK, HARDWARE_DEVICE_IN_CP,
- HARDWARE_DEVICE, HARDWARE_DEVICE_OUT_CP, 1, 1);
-
- assertEquals("wrong ETH type", EthType.EtherType.IPV4.ethType(),
- ((EthTypeCriterion) traceSuccess.getGroupOuputs(HARDWARE_DEVICE).get(0).getFinalPacket()
- .getCriterion(Criterion.Type.ETH_TYPE)).ethType());
-
- }
-
- /**
- * Test that HW has two rules on table 10 for untagged packets.
- */
- @Test
- public void hardwareTable10Test() throws Exception {
-
- StaticPacketTrace traceSuccess = testSuccess(PACKET_OK, HARDWARE_DEVICE_10_IN_CP,
- HARDWARE_DEVICE_10, HARDWARE_DEVICE_10_OUT_CP, 1, 1);
-
- assertTrue("Second flow rule is absent", traceSuccess.getFlowsForDevice(HARDWARE_DEVICE_10)
- .contains(HARDWARE_10_SECOND_FLOW_ENTRY));
-
+ traceSuccess.getHitChains(TOPO_GROUP_FLOW_DEVICE).get(1).getHitChain()
+ .contains(new DataPlaneEntity(TOPO_GROUP)));
}
/**
* Test dual links between 3 topology elements.
*/
@Test
- public void dualLinks() throws Exception {
-
+ public void dualLinks() {
+ // Success
StaticPacketTrace traceSuccess = testSuccess(PACKET_OK, DUAL_LINK_1_CP_1_IN,
DUAL_LINK_3, DUAL_LINK_3_CP_3_OUT, 4, 1);
-
- //TODO tests
-
+ // Verify that the complete path contains all the traversed connect points
+ List<ConnectPoint> path = Lists.newArrayList(DUAL_LINK_1_CP_1_IN, DUAL_LINK_1_CP_2_OUT,
+ DUAL_LINK_2_CP_1_IN, DUAL_LINK_2_CP_2_OUT, DUAL_LINK_3_CP_1_IN, DUAL_LINK_3_CP_3_OUT);
+ assertTrue(traceSuccess.getCompletePaths().contains(path));
+ path = Lists.newArrayList(DUAL_LINK_1_CP_1_IN, DUAL_LINK_1_CP_2_OUT,
+ DUAL_LINK_2_CP_1_IN, DUAL_LINK_2_CP_3_OUT, DUAL_LINK_3_CP_2_IN, DUAL_LINK_3_CP_3_OUT);
+ assertTrue(traceSuccess.getCompletePaths().contains(path));
+ path = Lists.newArrayList(DUAL_LINK_1_CP_1_IN, DUAL_LINK_1_CP_3_OUT,
+ DUAL_LINK_2_CP_4_IN, DUAL_LINK_2_CP_2_OUT, DUAL_LINK_3_CP_1_IN, DUAL_LINK_3_CP_3_OUT);
+ assertTrue(traceSuccess.getCompletePaths().contains(path));
+ path = Lists.newArrayList(DUAL_LINK_1_CP_1_IN, DUAL_LINK_1_CP_3_OUT,
+ DUAL_LINK_2_CP_4_IN, DUAL_LINK_2_CP_3_OUT, DUAL_LINK_3_CP_2_IN, DUAL_LINK_3_CP_3_OUT);
+ assertTrue(traceSuccess.getCompletePaths().contains(path));
}
/**
- * Test proper clear deferred behaviour.
- */
- @Test
- public void clearDeferred() throws Exception {
-
- StaticPacketTrace traceSuccess = testSuccess(PACKET_OK, DEFERRED_CP_1_IN,
- DEFERRED_1, DEFERRED_CP_2_OUT, 1, 1);
-
- assertNull("MPLS should have been not applied due to clear deferred", traceSuccess
- .getGroupOuputs(DEFERRED_1).get(0).getFinalPacket().getCriterion(Criterion.Type.MPLS_LABEL));
-
- }
-
-
- /**
* Test LLDP output to controller.
*/
@Test
@@ -360,7 +334,7 @@
traceSuccess.resultMessage().contains("Packet goes to the controller"));
assertTrue("Master should be Master1",
traceSuccess.resultMessage().contains(MASTER_1));
- ConnectPoint connectPoint = traceSuccess.getGroupOuputs(LLDP_FLOW_DEVICE).get(0).getOutput();
+ ConnectPoint connectPoint = traceSuccess.getHitChains(LLDP_FLOW_DEVICE).get(0).getOutputPort();
assertEquals("Packet Should go to CONTROLLER", PortNumber.CONTROLLER, connectPoint.port());
log.info("trace {}", traceSuccess.resultMessage());
}
@@ -369,37 +343,39 @@
* Test multicast in single device.
*/
@Test
- public void multicastTest() throws Exception {
-
+ public void multicastTest() {
+ // Test success
StaticPacketTrace traceSuccess = mngr.trace(PACKET_OK_MULTICAST, MULTICAST_IN_CP);
-
log.info("trace {}", traceSuccess);
-
log.info("trace {}", traceSuccess.resultMessage());
+ // Verify some conditions on the test
assertNotNull("trace should not be null", traceSuccess);
- assertEquals("Trace should have " + 2 + " output", 2,
- traceSuccess.getGroupOuputs(MULTICAST_GROUP_FLOW_DEVICE).size());
- assertEquals("Trace should only have " + 2 + "output", 2,
+ assertEquals("Trace should have " + 2 + " hitchains", 2,
+ traceSuccess.getHitChains(MULTICAST_GROUP_FLOW_DEVICE).size());
+ assertEquals("Trace should only have " + 2 + "paths", 2,
traceSuccess.getCompletePaths().size());
assertTrue("Trace should be successful",
traceSuccess.resultMessage().contains("reached output"));
assertEquals("Incorrect Output CP", MULTICAST_OUT_CP_2,
- traceSuccess.getGroupOuputs(MULTICAST_GROUP_FLOW_DEVICE).get(0).getOutput());
+ traceSuccess.getHitChains(MULTICAST_GROUP_FLOW_DEVICE).get(0).getOutputPort());
assertEquals("Incorrect Output CP", MULTICAST_OUT_CP,
- traceSuccess.getGroupOuputs(MULTICAST_GROUP_FLOW_DEVICE).get(1).getOutput());
-
+ traceSuccess.getHitChains(MULTICAST_GROUP_FLOW_DEVICE).get(1).getOutputPort());
}
/**
* Tests dual homing of a host.
*/
@Test
- public void dualhomedTest() throws Exception {
+ public void dualhomedTest() {
+ // Test success
StaticPacketTrace traceSuccess = mngr.trace(PACKET_DUAL_HOME, DUAL_HOME_CP_1_1);
+ log.info("trace {}", traceSuccess);
+ log.info("trace {}", traceSuccess.resultMessage());
+ // Verify paths
assertNotNull("trace should not be null", traceSuccess);
- assertTrue("Should have 2 output paths", traceSuccess.getCompletePaths().size() == 2);
+ assertEquals("Should have 2 output paths", 2, traceSuccess.getCompletePaths().size());
assertTrue("Should contain proper path", traceSuccess.getCompletePaths()
.contains(ImmutableList.of(DUAL_HOME_CP_1_1, DUAL_HOME_CP_1_2, DUAL_HOME_CP_2_1, DUAL_HOME_CP_2_2)));
assertTrue("Should contain proper path", traceSuccess.getCompletePaths()
@@ -407,37 +383,36 @@
}
-
- private StaticPacketTrace testSuccess(TrafficSelector packet, ConnectPoint in, DeviceId deviceId, ConnectPoint out,
- int paths, int outputs) {
+ private StaticPacketTrace testSuccess(TrafficSelector packet, ConnectPoint in, DeviceId deviceId,
+ ConnectPoint out, int paths, int hitchains) {
StaticPacketTrace traceSuccess = mngr.trace(packet, in);
-
log.info("trace {}", traceSuccess);
-
log.info("trace {}", traceSuccess.resultMessage());
assertNotNull("trace should not be null", traceSuccess);
- assertEquals("Trace should have " + outputs + " output", outputs,
- traceSuccess.getGroupOuputs(deviceId).size());
+ assertEquals("Trace should have " + hitchains + " hitchains", hitchains,
+ traceSuccess.getHitChains(deviceId).size());
assertEquals("Trace should only have " + paths + "output", paths, traceSuccess.getCompletePaths().size());
assertTrue("Trace should be successful",
traceSuccess.resultMessage().contains("Reached required destination Host"));
assertEquals("Incorrect Output CP", out,
- traceSuccess.getGroupOuputs(deviceId).get(0).getOutput());
+ traceSuccess.getHitChains(deviceId).get(0).getOutputPort());
return traceSuccess;
}
- private void testFailure(TrafficSelector packet, ConnectPoint in, DeviceId deviceId) {
+ private void testFailure(TrafficSelector packet, ConnectPoint in, DeviceId deviceId,
+ int hitchains) {
StaticPacketTrace traceFail = mngr.trace(packet, in);
-
log.info("trace {}", traceFail.resultMessage());
assertNotNull("Trace should not be null", traceFail);
- assertNull("Trace should have 0 output", traceFail.getGroupOuputs(deviceId));
+ assertEquals("Trace should have " + hitchains + " hitchains", hitchains,
+ traceFail.getHitChains(deviceId).size());
}
- private class TestFlowRuleService extends FlowNib {
+ private static class TestFlowRuleService extends FlowNib {
+
@Override
public Iterable<FlowEntry> getFlowEntriesByState(DeviceId deviceId, FlowEntry.FlowEntryState state) {
if (deviceId.equals(SINGLE_FLOW_DEVICE)) {
@@ -453,23 +428,18 @@
return ImmutableList.of(TOPO_SINGLE_FLOW_ENTRY, TOPO_SECOND_INPUT_FLOW_ENTRY);
} else if (deviceId.equals(TOPO_GROUP_FLOW_DEVICE)) {
return ImmutableList.of(TOPO_GROUP_FLOW_ENTRY);
- } else if (deviceId.equals(HARDWARE_DEVICE)) {
- return ImmutableList.of(HARDWARE_ETH_FLOW_ENTRY, HARDWARE_FLOW_ENTRY);
} else if (deviceId.equals(SAME_OUTPUT_FLOW_DEVICE)) {
return ImmutableList.of(SAME_OUTPUT_FLOW_ENTRY);
} else if (deviceId.equals(ARP_FLOW_DEVICE)) {
- return ImmutableList.of(ARP_FLOW_ENTRY);
+ return ImmutableList.of(ARP_FLOW_ENTRY);
+ } else if (deviceId.equals(ARP_FLOW_VLAN_DEVICE)) {
+ return ImmutableList.of(ARP_FLOW_VLAN_ENTRY, ARP_FLOW_ENTRY);
} else if (deviceId.equals(DUAL_LINK_1)) {
return ImmutableList.of(DUAL_LINK_1_GROUP_FLOW_ENTRY);
} else if (deviceId.equals(DUAL_LINK_2)) {
return ImmutableList.of(DUAL_LINK_1_GROUP_FLOW_ENTRY, DUAL_LINK_2_GROUP_FLOW_ENTRY);
} else if (deviceId.equals(DUAL_LINK_3)) {
return ImmutableList.of(DUAL_LINK_3_FLOW_ENTRY, DUAL_LINK_3_FLOW_ENTRY_2);
- } else if (deviceId.equals(DEFERRED_1)) {
- return ImmutableList.of(DEFERRED_FLOW_ENTRY, DEFERRED_CLEAR_FLOW_ENTRY);
- } else if (deviceId.equals(HARDWARE_DEVICE_10)) {
- return ImmutableList.of(HARDWARE_10_FLOW_ENTRY, HARDWARE_10_SECOND_FLOW_ENTRY,
- HARDWARE_10_OUTPUT_FLOW_ENTRY);
} else if (deviceId.equals(LLDP_FLOW_DEVICE)) {
return ImmutableList.of(LLDP_FLOW_ENTRY);
} else if (deviceId.equals(MULTICAST_GROUP_FLOW_DEVICE)) {
@@ -480,16 +450,15 @@
return ImmutableList.of(DUAL_HOME_FLOW_ENTRY);
} else if (deviceId.equals(DUAL_HOME_DEVICE_2) || deviceId.equals(DUAL_HOME_DEVICE_3)) {
return ImmutableList.of(DUAL_HOME_OUT_FLOW_ENTRY);
- } else if (deviceId.equals(ACTION_ORDER_DEVICE)) {
- return ImmutableList.of(ACTION_ORDER_FLOW_ENTRY);
}
return ImmutableList.of();
}
}
- private class TestGroupService extends GroupNib {
+ private static class TestGroupService extends GroupNib {
+
@Override
- public Iterable<Group> getGroups(DeviceId deviceId) {
+ public Iterable<Group> getGroupsByState(DeviceId deviceId, Group.GroupState groupState) {
if (deviceId.equals(GROUP_FLOW_DEVICE)) {
return ImmutableList.of(GROUP);
} else if (deviceId.equals(TOPO_GROUP_FLOW_DEVICE)) {
@@ -502,14 +471,12 @@
return ImmutableList.of(NO_BUCKET_GROUP);
} else if (deviceId.equals(DUAL_HOME_DEVICE_1)) {
return ImmutableList.of(DUAL_HOME_GROUP);
- } else if (deviceId.equals(ACTION_ORDER_DEVICE)) {
- return ImmutableList.of(ACTION_ORDER_GROUP);
}
return ImmutableList.of();
}
}
- private class TestHostService extends HostNib {
+ private static class TestHostService extends HostNib {
@Override
public Set<Host> getConnectedHosts(ConnectPoint connectPoint) {
if (connectPoint.equals(TOPO_FLOW_3_OUT_CP)) {
@@ -521,11 +488,7 @@
if (connectPoint.equals(SINGLE_FLOW_OUT_CP) ||
connectPoint.equals(DUAL_FLOW_OUT_CP) ||
connectPoint.equals(GROUP_FLOW_OUT_CP) ||
- connectPoint.equals(HARDWARE_DEVICE_OUT_CP) ||
- connectPoint.equals(HARDWARE_DEVICE_10_OUT_CP) ||
- connectPoint.equals(DEFERRED_CP_2_OUT) ||
- connectPoint.equals(DUAL_LINK_3_CP_3_OUT) ||
- connectPoint.equals(ACTION_ORDER_OUT_CP)) {
+ connectPoint.equals(DUAL_LINK_3_CP_3_OUT)) {
return ImmutableSet.of(H1);
}
if (connectPoint.equals(DUAL_HOME_CP_2_2) || connectPoint.equals(DUAL_HOME_CP_3_2)) {
@@ -559,7 +522,7 @@
}
}
- private class TestLinkService extends LinkNib {
+ private static class TestLinkService extends LinkNib {
@Override
public Set<Link> getEgressLinks(ConnectPoint connectPoint) {
if (connectPoint.equals(TOPO_FLOW_1_OUT_CP)
@@ -638,15 +601,19 @@
}
}
- private class TestDeviceService extends DeviceNib {
+ private static class TestDeviceService extends DeviceNib {
@Override
public Device getDevice(DeviceId deviceId) {
if (deviceId.equals(DeviceId.deviceId("nonexistent"))) {
return null;
}
- return new DefaultDevice(ProviderId.NONE, DeviceId.deviceId("test"), SWITCH,
- "test", "test", "test", "test", new ChassisId(),
- DefaultAnnotations.builder().set("foo", "bar").build());
+ SparseAnnotations annotations = DefaultAnnotations.builder()
+ .set("foo", "bar")
+ .set(AnnotationKeys.DRIVER, OFDPA_DRIVER)
+ .build();
+ return new DefaultDevice(ProviderId.NONE, deviceId, SWITCH,
+ MANUFACTURER, HW_VERSION, SW_VERSION, SERIAL_NUMBER, new ChassisId(),
+ annotations);
}
@Override
@@ -660,24 +627,21 @@
}
}
- private class TestDriverService extends DriverNib {
+ private static class TestDriverNib extends DriverNib {
@Override
public String getDriverName(DeviceId deviceId) {
- if (deviceId.equals(HARDWARE_DEVICE) || deviceId.equals(HARDWARE_DEVICE_10)) {
- return "ofdpa";
- }
return "NotHWDriver";
}
}
- private class TestMastershipService extends MastershipNib {
+ private static class TestMastershipService extends MastershipNib {
@Override
public NodeId getMasterFor(DeviceId deviceId) {
return NodeId.nodeId(MASTER_1);
}
}
- private class TestEdgePortService extends EdgePortNib {
+ private static class TestEdgePortService extends EdgePortNib {
@Override
public boolean isEdgePoint(ConnectPoint point) {
return point.equals(MULTICAST_OUT_CP) ||
@@ -685,11 +649,58 @@
}
}
- private class TestRouteService extends RouteNib {
+ private static class TestRouteService extends RouteNib {
@Override
public Optional<ResolvedRoute> longestPrefixLookup(IpAddress ip) {
return Optional.empty();
}
}
+ private class TestDriverService extends DriverServiceAdapter {
+ @Override
+ public Driver getDriver(DeviceId deviceId) {
+ return baseDriver;
+ }
+ }
+
+ private static class TestDriver extends DriverAdapter {
+
+ @Override
+ public String manufacturer() {
+ return MANUFACTURER;
+ }
+
+ @Override
+ public String hwVersion() {
+ return HW_VERSION;
+ }
+
+ @Override
+ public String swVersion() {
+ return SW_VERSION;
+ }
+
+ @Override
+ public String name() {
+ return OFDPA_DRIVER;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T extends Behaviour> T createBehaviour(DriverHandler handler, Class<T> behaviourClass) {
+ if (behaviourClass == PipelineTraceable.class) {
+ T behaviour = (T) new OfdpaPipelineTraceable();
+ behaviour.setData(handler.data());
+ ((HandlerBehaviour) behaviour).setHandler(handler);
+ return behaviour;
+ } else {
+ T behaviour = (T) new Ofdpa2Pipeline();
+ behaviour.setData(handler.data());
+ ((HandlerBehaviour) behaviour).setHandler(handler);
+ return behaviour;
+ }
+ }
+
+ }
+
}
\ No newline at end of file
diff --git a/app/src/test/java/org/onosproject/t3/impl/TroubleshootUtilsTest.java b/app/src/test/java/org/onosproject/t3/impl/TroubleshootUtilsTest.java
deleted file mode 100644
index c8195c0..0000000
--- a/app/src/test/java/org/onosproject/t3/impl/TroubleshootUtilsTest.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright 2018-present Open Networking Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.t3.impl;
-
-import org.junit.Test;
-import org.onlab.packet.MacAddress;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-/**
- * Test for util methods of the Trellis Troubleshoot Toolkit.
- */
-public class TroubleshootUtilsTest {
-
- @Test
- public void testMacMatch() {
-
- MacAddress min = MacAddress.valueOf("01:00:5E:00:00:00");
- MacAddress mask = MacAddress.valueOf("FF:FF:FF:80:00:00");
- MacAddress macOk = MacAddress.valueOf("01:00:5E:00:00:01");
-
- assertTrue("False on correct match", TroubleshootUtils.compareMac(macOk, min, mask));
-
- MacAddress macWrong = MacAddress.valueOf("01:00:5E:80:00:00");
-
- assertFalse("True on false match", TroubleshootUtils.compareMac(macWrong, min, mask));
-
- MacAddress maskEmpty = MacAddress.valueOf("00:00:00:00:00:00");
-
- assertTrue("False on empty Mask", TroubleshootUtils.compareMac(macOk, min, maskEmpty));
-
- MacAddress maskFull = MacAddress.valueOf("FF:FF:FF:FF:FF:FF");
-
- assertFalse("True on full Mask", TroubleshootUtils.compareMac(macOk, min, maskFull));
-
- }
-}
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 8a059c7..b20425c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -22,7 +22,7 @@
<parent>
<groupId>org.onosproject</groupId>
<artifactId>onos-dependencies</artifactId>
- <version>2.2.4</version>
+ <version>2.2.7-b2</version>
</parent>
<groupId>org.onosproject</groupId>