[AETHER-38] Extract pipeline-dependent code from current T3 implementation
- Exposes some ofdpa specific tables and types
- Introduces a new driver behavior PipelineTraceable
- OfdpaPipelineTraceable is the first implementation of the
new driver behavior
- New abstractions are introduced to encapsulate the input/output
of the traceables processing
- Implements some basic unit tests for Ofdpa implementation
Change-Id: I89d3fdeda445983ec7ebfa9ebb78afb1c6d3fd8f
diff --git a/core/api/src/main/java/org/onosproject/net/DataPlaneEntity.java b/core/api/src/main/java/org/onosproject/net/DataPlaneEntity.java
new file mode 100644
index 0000000..0c4628c
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/DataPlaneEntity.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2017-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.net;
+
+import org.onosproject.net.flow.FlowEntry;
+import org.onosproject.net.group.Group;
+
+import java.util.Objects;
+
+/**
+ * Generic abstraction to hold dataplane entities.
+ */
+public class DataPlaneEntity {
+ private FlowEntry flowEntry;
+ private Group groupEntry;
+ private Type type;
+
+ /**
+ * Types of entity.
+ */
+ public enum Type {
+ /**
+ * Flow rule entity.
+ */
+ FLOWRULE,
+
+ /**
+ * Group entity.
+ */
+ GROUP
+ }
+
+ /**
+ * Creates a dataplane entity from a flow entry.
+ *
+ * @param flow the inner flow entry
+ */
+ public DataPlaneEntity(FlowEntry flow) {
+ flowEntry = flow;
+ type = Type.FLOWRULE;
+ }
+
+ /**
+ * Creates a dataplane entity from a group entry.
+ *
+ * @param group the inner group entry
+ */
+ public DataPlaneEntity(Group group) {
+ groupEntry = group;
+ type = Type.GROUP;
+ }
+
+ /**
+ * Returns the flow entry.
+ *
+ * @return the flow entry
+ */
+ public FlowEntry getFlowEntry() {
+ return flowEntry;
+ }
+
+ /**
+ * Returns the group entry.
+ *
+ * @return the group entry
+ */
+ public Group getGroupEntry() {
+ return groupEntry;
+ }
+
+ /**
+ * Returns the type of the entry.
+ *
+ * @return the type
+ */
+ public Type getType() {
+ return type;
+ }
+
+ @Override
+ public int hashCode() {
+ return type == Type.FLOWRULE ? flowEntry.hashCode() : groupEntry.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof DataPlaneEntity) {
+ DataPlaneEntity that = (DataPlaneEntity) obj;
+ if (this.type == that.type) {
+ return Objects.equals(flowEntry, that.flowEntry) &&
+ Objects.equals(groupEntry, that.groupEntry);
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ Object entity = type == Type.FLOWRULE ? flowEntry : groupEntry;
+ return "DataPlaneEntity{" +
+ "entity=" + entity +
+ '}';
+ }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/PipelineTraceableHitChain.java b/core/api/src/main/java/org/onosproject/net/PipelineTraceableHitChain.java
new file mode 100644
index 0000000..4eb26b5
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/PipelineTraceableHitChain.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2020-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.net;
+
+import com.google.common.collect.Lists;
+import org.onosproject.net.flow.TrafficSelector;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Class to represent the pipeline hit chain and the result of the pipeline processing.
+ */
+public class PipelineTraceableHitChain {
+
+ private ConnectPoint outputPort;
+ private List<DataPlaneEntity> hitChain;
+ private TrafficSelector egressPacket;
+ // By default packets are dropped
+ private boolean dropped = true;
+
+ private PipelineTraceableHitChain() {
+ hitChain = Lists.newArrayList();
+ }
+
+ /**
+ * Creates a new PipelineTraceableHitChain.
+ *
+ * @param output the output connect point
+ * @param hits the hits in the pipeline (flows, groups and other abstractions)
+ * @param packet the selector representing the final packet
+ */
+ public PipelineTraceableHitChain(ConnectPoint output, List<DataPlaneEntity> hits,
+ TrafficSelector packet) {
+ this.outputPort = output;
+ this.hitChain = hits;
+ this.egressPacket = packet;
+ }
+
+ /**
+ * Creates an empty pipeline hit chain.
+ *
+ * @return an empty pipeline hit chain
+ */
+ public static PipelineTraceableHitChain emptyHitChain() {
+ return new PipelineTraceableHitChain();
+ }
+
+ /**
+ * Returns the output connect point.
+ *
+ * @return the connect point
+ */
+ public ConnectPoint getOutputPort() {
+ return outputPort;
+ }
+
+ /**
+ * Sets the output port.
+ *
+ * @param outputPort the output port
+ */
+ public void setOutputPort(ConnectPoint outputPort) {
+ this.outputPort = outputPort;
+ }
+
+ /**
+ * Returns the hit chain.
+ *
+ * @return flows and groups that matched.
+ */
+ public List<DataPlaneEntity> getHitChain() {
+ return hitChain;
+ }
+
+ /**
+ * Adds the provided dataplane entity to the end of the chain.
+ *
+ * @param dataPlaneEntity the dataplane entity
+ */
+ public void addDataPlaneEntity(DataPlaneEntity dataPlaneEntity) {
+ if (!hitChain.contains(dataPlaneEntity)) {
+ hitChain.add(dataPlaneEntity);
+ }
+ }
+
+ /**
+ * Removes the provided dataplane entity from the chain.
+ *
+ * @param dataPlaneEntity the dataplane entity
+ */
+ public void removeDataPlaneEntity(DataPlaneEntity dataPlaneEntity) {
+ if (hitChain.isEmpty()) {
+ return;
+ }
+ hitChain.remove(dataPlaneEntity);
+ }
+
+ /**
+ * Returns the egress packet after traversing the pipeline.
+ *
+ * @return the selector representing the packet infos
+ */
+ public TrafficSelector getEgressPacket() {
+ return egressPacket;
+ }
+
+ /**
+ * Sets the egress packet.
+ *
+ * @param egressPacket the egress packet
+ */
+ public void setEgressPacket(TrafficSelector egressPacket) {
+ this.egressPacket = egressPacket;
+ }
+
+ /**
+ * Return whether or not the packet has been dropped by the pipeline.
+ *
+ * @return true if the packet has been dropped. False, otherwise.
+ */
+ public boolean isDropped() {
+ return dropped;
+ }
+
+ /**
+ * Set the dropped flag.
+ */
+ public void dropped() {
+ this.dropped = true;
+ }
+
+ /**
+ * Unset the dropped flag.
+ */
+ public void pass() {
+ this.dropped = false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(outputPort, hitChain, egressPacket, dropped);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof PipelineTraceableHitChain) {
+ PipelineTraceableHitChain that = (PipelineTraceableHitChain) obj;
+ return Objects.equals(this.outputPort, that.outputPort) &&
+ Objects.equals(this.hitChain, that.getHitChain()) &&
+ Objects.equals(this.egressPacket, that.egressPacket) &&
+ Objects.equals(this.dropped, that.dropped);
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return "PipelineTraceableHitChain{" +
+ "outputPort=" + outputPort +
+ ", hitChain=" + hitChain +
+ ", egressPacket=" + egressPacket +
+ ", dropped=" + dropped +
+ '}';
+ }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/PipelineTraceableInput.java b/core/api/src/main/java/org/onosproject/net/PipelineTraceableInput.java
new file mode 100644
index 0000000..2403c5e
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/PipelineTraceableInput.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2020-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.net;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import org.onosproject.core.GroupId;
+import org.onosproject.net.flow.FlowEntry;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.group.Group;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Represents the input of the pipeline traceable processing.
+ */
+public class PipelineTraceableInput {
+
+ // Input state for the traceable behavior
+ TrafficSelector ingressPacket;
+ ConnectPoint ingressPort;
+ // List here all possible device state using
+ // possibly an optimized reference
+ List<FlowEntry> flows = Lists.newArrayList();
+ Map<GroupId, Group> groups = Maps.newHashMap();
+
+ public PipelineTraceableInput(TrafficSelector ingressPacket, ConnectPoint ingressPort,
+ List<DataPlaneEntity> deviceState) {
+ this.ingressPacket = ingressPacket;
+ this.ingressPort = ingressPort;
+ processDeviceState(deviceState);
+ }
+
+ // Init internal device state (flows, groups, etc)
+ private void processDeviceState(List<DataPlaneEntity> deviceState) {
+ deviceState.forEach(entity -> {
+ if (entity.getType() == DataPlaneEntity.Type.FLOWRULE) {
+ flows.add(entity.getFlowEntry());
+ } else if (entity.getType() == DataPlaneEntity.Type.GROUP) {
+ groups.put(entity.getGroupEntry().id(), entity.getGroupEntry());
+ }
+ });
+ }
+
+ /**
+ * Getter for the ingress packet.
+ *
+ * @return the ingress packet
+ */
+ public TrafficSelector ingressPacket() {
+ return ingressPacket;
+ }
+
+ /**
+ * Getter for the ingress port.
+ *
+ * @return the ingress port
+ */
+ public ConnectPoint ingressPort() {
+ return ingressPort;
+ }
+
+ /**
+ * Getter for the flows.
+ *
+ * @return the flows
+ */
+ public List<FlowEntry> flows() {
+ return flows;
+ }
+
+ /**
+ * Getter for the groups.
+ *
+ * @return the groups
+ */
+ public Map<GroupId, Group> groups() {
+ return groups;
+ }
+
+ /**
+ * Returns the group associated with the given group id.
+ *
+ * @param groupId the group id
+ * @return the group, otherwise null.
+ */
+ public Group getGroup(GroupId groupId) {
+ return groups.get(groupId);
+ }
+
+}
diff --git a/core/api/src/main/java/org/onosproject/net/PipelineTraceableOutput.java b/core/api/src/main/java/org/onosproject/net/PipelineTraceableOutput.java
new file mode 100644
index 0000000..21a9819
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/PipelineTraceableOutput.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2020-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.net;
+
+import com.google.common.collect.Lists;
+
+import java.util.List;
+
+/**
+ * Represents the output of the pipeline traceable processing.
+ */
+public final class PipelineTraceableOutput {
+
+ /**
+ * Represents the result of the pipeline traceable processing.
+ */
+ public enum PipelineTraceableResult {
+ /**
+ * Means packet went through the pipeline.
+ */
+ SUCCESS,
+ /**
+ * Means packet stopped due to missing flows.
+ */
+ NO_FLOWS,
+ /**
+ * Means packet stopped due to missing groups.
+ */
+ NO_GROUPS,
+ /**
+ * Means packet stopped due to an empty group.
+ */
+ NO_GROUP_MEMBERS,
+ /**
+ * Means packet is dropped by the pipeline.
+ */
+ DROPPED
+ }
+
+ private String log;
+ private List<PipelineTraceableHitChain> hitChains;
+ private PipelineTraceableResult result;
+
+ /**
+ * Creates a new pipeline traceable output with the specified input.
+ *
+ * @param log the trace log
+ * @param hitChains the hit chains
+ * @param result the apply result
+ */
+ private PipelineTraceableOutput(String log, List<PipelineTraceableHitChain> hitChains,
+ PipelineTraceableResult result) {
+ this.log = log;
+ this.hitChains = hitChains;
+ this.result = result;
+ }
+
+ /**
+ * Returns the log message as string.
+ *
+ * @return the log message
+ */
+ public String getLog() {
+ return log;
+ }
+
+ /**
+ * Returns the hit chains.
+ *
+ * @return the pipeline hit chains
+ */
+ public List<PipelineTraceableHitChain> getHitChains() {
+ return hitChains;
+ }
+
+ /**
+ * Returns the result of the computation.
+ *
+ * @return the pipeline traceable result
+ */
+ public PipelineTraceableResult getResult() {
+ return result;
+ }
+
+ /**
+ * Returns a new builder.
+ *
+ * @return an empty builder
+ */
+ public static PipelineTraceableOutput.Builder builder() {
+ return new PipelineTraceableOutput.Builder();
+ }
+
+ /**
+ * Builder of pipeline traceable entities.
+ */
+ public static final class Builder {
+
+ private StringBuilder log = new StringBuilder();
+ private List<PipelineTraceableHitChain> hitChains = Lists.newArrayList();
+ private PipelineTraceableResult result = PipelineTraceableResult.SUCCESS;
+
+ /**
+ * Appends a message to the log.
+ *
+ * @param message the log message to be appended
+ * @return this builder
+ */
+ public Builder appendToLog(String message) {
+ if (log.length() != 0) {
+ log.append("\n");
+ }
+ log.append(message);
+ return this;
+ }
+
+ private Builder setResult(PipelineTraceableResult result) {
+ // Do not override original failure
+ if (this.result == PipelineTraceableResult.SUCCESS) {
+ this.result = result;
+ }
+ return this;
+ }
+
+ /**
+ * Sets no flows in the result.
+ *
+ * @return this builder
+ */
+ public Builder noFlows() {
+ return setResult(PipelineTraceableResult.NO_FLOWS);
+ }
+
+ /**
+ * Sets no groups in the result.
+ *
+ * @return this builder
+ */
+ public Builder noGroups() {
+ return setResult(PipelineTraceableResult.NO_GROUPS);
+ }
+
+ /**
+ * Sets no flows in the result.
+ *
+ * @return this builder
+ */
+ public Builder noMembers() {
+ return setResult(PipelineTraceableResult.NO_GROUP_MEMBERS);
+ }
+
+ /**
+ * Sets dropped in the result.
+ *
+ * @return this builder
+ */
+ public Builder dropped() {
+ return setResult(PipelineTraceableResult.DROPPED);
+ }
+
+ /**
+ * Stores the provided hit chain.
+ *
+ * @param hitChain the provided hit chain
+ * @return this builder
+ */
+ public Builder addHitChain(PipelineTraceableHitChain hitChain) {
+ if (!hitChains.contains(hitChain)) {
+ hitChains.add(hitChain);
+ }
+ return this;
+ }
+
+ /**
+ * Builds a new pipeline traceable output.
+ *
+ * @return a pipeline traceable object
+ */
+ public PipelineTraceableOutput build() {
+ return new PipelineTraceableOutput(log.toString(), hitChains, result);
+ }
+
+ }
+
+}
diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/PipelineTraceable.java b/core/api/src/main/java/org/onosproject/net/behaviour/PipelineTraceable.java
new file mode 100644
index 0000000..eff59db
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/behaviour/PipelineTraceable.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2020-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.net.behaviour;
+
+import org.onosproject.net.PipelineTraceableInput;
+import org.onosproject.net.PipelineTraceableOutput;
+import org.onosproject.net.driver.HandlerBehaviour;
+
+/**
+ * Represents a driver behavior that enables a logical packet to trace existing flows and groups in a device.
+ */
+public interface PipelineTraceable extends HandlerBehaviour {
+
+ /**
+ * Initializes the traceable with a context required for its operation.
+ */
+ void init();
+
+ /**
+ * Applies pipeline processing on the given ingress state.
+ *
+ * @param input the input of the apply process
+ * @return the output of the apply process
+ */
+ PipelineTraceableOutput apply(PipelineTraceableInput input);
+
+}