ONOS-4410 Implemented PacketProgrammable and Pipeliner behaviors in the
BMv2 driver
Also other minor fixes / refactorings
Change-Id: I2205890b76471e8e8490beccd6b36e5358f8d407
diff --git a/drivers/bmv2/pom.xml b/drivers/bmv2/pom.xml
index 680f25d..1722cc4 100644
--- a/drivers/bmv2/pom.xml
+++ b/drivers/bmv2/pom.xml
@@ -49,6 +49,11 @@
<artifactId>onos-bmv2-protocol</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.onosproject</groupId>
+ <artifactId>onos-drivers</artifactId>
+ <version>${project.version}</version>
+ </dependency>
</dependencies>
</project>
\ No newline at end of file
diff --git a/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2FlowRuleDriver.java b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2FlowRuleProgrammable.java
similarity index 96%
rename from drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2FlowRuleDriver.java
rename to drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2FlowRuleProgrammable.java
index 2947b5f..082d1d6 100644
--- a/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2FlowRuleDriver.java
+++ b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2FlowRuleProgrammable.java
@@ -42,11 +42,14 @@
import java.util.List;
import java.util.concurrent.ConcurrentMap;
-public class Bmv2FlowRuleDriver extends AbstractHandlerBehaviour
+/**
+ * Flow rule programmable device behaviour implementation for BMv2.
+ */
+public class Bmv2FlowRuleProgrammable extends AbstractHandlerBehaviour
implements FlowRuleProgrammable {
private static final Logger LOG =
- LoggerFactory.getLogger(Bmv2FlowRuleDriver.class);
+ LoggerFactory.getLogger(Bmv2FlowRuleProgrammable.class);
// There's no Bmv2 client method to poll flow entries from the device device. gitNeed a local store.
private static final ConcurrentMap<Triple<DeviceId, String, Bmv2MatchKey>, Pair<Long, FlowEntry>>
ENTRIES_MAP = Maps.newConcurrentMap();
diff --git a/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2PacketProgrammable.java b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2PacketProgrammable.java
new file mode 100644
index 0000000..5076786
--- /dev/null
+++ b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2PacketProgrammable.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * 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.drivers.bmv2;
+
+import org.onlab.util.ImmutableByteSequence;
+import org.onosproject.bmv2.api.runtime.Bmv2Client;
+import org.onosproject.bmv2.api.runtime.Bmv2RuntimeException;
+import org.onosproject.bmv2.ctl.Bmv2ThriftClient;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.instructions.Instructions;
+import org.onosproject.net.packet.OutboundPacket;
+import org.onosproject.net.packet.PacketProgrammable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static java.lang.Math.toIntExact;
+import static org.onosproject.net.PortNumber.FLOOD;
+import static org.onosproject.net.flow.instructions.Instruction.Type.OUTPUT;
+
+/**
+ * Packet programmable device behaviour implementation for BMv2.
+ */
+public class Bmv2PacketProgrammable extends AbstractHandlerBehaviour implements PacketProgrammable {
+
+ private static final Logger LOG =
+ LoggerFactory.getLogger(Bmv2FlowRuleProgrammable.class);
+
+ @Override
+ public void emit(OutboundPacket packet) {
+
+ TrafficTreatment treatment = packet.treatment();
+
+ treatment.allInstructions().forEach(inst -> {
+ if (inst.type().equals(OUTPUT)) {
+ Instructions.OutputInstruction outInst = (Instructions.OutputInstruction) inst;
+ if (outInst.port().isLogical()) {
+ if (outInst.port() == FLOOD) {
+ // TODO: implement flood
+ LOG.info("Flood not implemented", outInst);
+ }
+ LOG.info("Output on logical port not supported: {}", outInst);
+ } else {
+ try {
+ long longPort = outInst.port().toLong();
+ int portNumber = toIntExact(longPort);
+ send(portNumber, packet);
+ } catch (ArithmeticException e) {
+ LOG.error("Port number overflow! Cannot send packet on port {} (long), as the bmv2" +
+ " device only accepts int port values.");
+ }
+ }
+ } else {
+ LOG.info("Instruction type not supported: {}", inst.type().name());
+ }
+ });
+ }
+
+ private void send(int port, OutboundPacket packet) {
+
+ DeviceId deviceId = handler().data().deviceId();
+
+ Bmv2Client deviceClient;
+ try {
+ deviceClient = Bmv2ThriftClient.of(deviceId);
+ } catch (Bmv2RuntimeException e) {
+ LOG.error("Failed to connect to Bmv2 device", e);
+ return;
+ }
+
+ ImmutableByteSequence bs = ImmutableByteSequence.copyFrom(packet.data());
+ try {
+ deviceClient.transmitPacket(port, bs);
+ } catch (Bmv2RuntimeException e) {
+ LOG.info("Unable to push packet to device: deviceId={}, packet={}", deviceId, bs);
+ }
+ }
+}
diff --git a/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2Pipeliner.java b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2Pipeliner.java
new file mode 100644
index 0000000..b8e4205
--- /dev/null
+++ b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2Pipeliner.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * 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.drivers.bmv2;
+
+import org.onosproject.driver.pipeline.DefaultSingleTablePipeline;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.behaviour.NextGroup;
+import org.onosproject.net.behaviour.Pipeliner;
+import org.onosproject.net.behaviour.PipelinerContext;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.net.flowobjective.FilteringObjective;
+import org.onosproject.net.flowobjective.ForwardingObjective;
+import org.onosproject.net.flowobjective.NextObjective;
+
+import java.util.List;
+
+/**
+ * Pipeliner device behaviour implementation for BMv2.
+ */
+public class Bmv2Pipeliner extends AbstractHandlerBehaviour implements Pipeliner {
+
+ private Pipeliner pipeliner;
+
+ @Override
+ public void init(DeviceId deviceId, PipelinerContext context) {
+ // TODO: get multi-table pipeliner dynamically based on BMv2 device running model
+ // Right now we only support single table pipelines
+ pipeliner = new DefaultSingleTablePipeline();
+ pipeliner.init(deviceId, context);
+ }
+
+ @Override
+ public void filter(FilteringObjective filterObjective) {
+ pipeliner.filter(filterObjective);
+ }
+
+ @Override
+ public void forward(ForwardingObjective forwardObjective) {
+ pipeliner.forward(forwardObjective);
+ }
+
+ @Override
+ public void next(NextObjective nextObjective) {
+ pipeliner.next(nextObjective);
+ }
+
+ @Override
+ public List<String> getNextMappings(NextGroup nextGroup) {
+ return pipeliner.getNextMappings(nextGroup);
+ }
+}
diff --git a/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2PortGetterDriver.java b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2PortDiscovery.java
similarity index 97%
rename from drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2PortGetterDriver.java
rename to drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2PortDiscovery.java
index e1da42b..0825883 100644
--- a/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2PortGetterDriver.java
+++ b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/Bmv2PortDiscovery.java
@@ -34,7 +34,7 @@
import java.util.Collections;
import java.util.List;
-public class Bmv2PortGetterDriver extends AbstractHandlerBehaviour
+public class Bmv2PortDiscovery extends AbstractHandlerBehaviour
implements PortDiscovery {
private final Logger log =
diff --git a/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/translators/Bmv2DefaultFlowRuleTranslator.java b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/translators/Bmv2DefaultFlowRuleTranslator.java
index 1d93499..a54a3c8 100644
--- a/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/translators/Bmv2DefaultFlowRuleTranslator.java
+++ b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/translators/Bmv2DefaultFlowRuleTranslator.java
@@ -67,7 +67,7 @@
public class Bmv2DefaultFlowRuleTranslator implements Bmv2FlowRuleTranslator {
// TODO: config is harcoded now, instead it should be selected based on device model
- private final TranslatorConfig config = new Bmv2SimplePipelineTranslatorConfig();
+ private final TranslatorConfig config = new Bmv2SimpleTranslatorConfig();
private final Bmv2Model model = config.model();
private static Bmv2TernaryMatchParam buildTernaryParam(Bmv2ModelField field, Criterion criterion, int byteWidth)
diff --git a/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/translators/Bmv2SimplePipelineTranslatorConfig.java b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/translators/Bmv2SimpleTranslatorConfig.java
similarity index 85%
rename from drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/translators/Bmv2SimplePipelineTranslatorConfig.java
rename to drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/translators/Bmv2SimpleTranslatorConfig.java
index 13f27e6..565c1e4 100644
--- a/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/translators/Bmv2SimplePipelineTranslatorConfig.java
+++ b/drivers/bmv2/src/main/java/org/onosproject/drivers/bmv2/translators/Bmv2SimpleTranslatorConfig.java
@@ -23,6 +23,7 @@
import org.onlab.util.ImmutableByteSequence;
import org.onosproject.bmv2.api.model.Bmv2Model;
import org.onosproject.bmv2.api.runtime.Bmv2Action;
+import org.onosproject.net.PortNumber;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flow.criteria.Criterion;
import org.onosproject.net.flow.instructions.Instruction;
@@ -36,19 +37,19 @@
/**
* Implementation of a Bmv2 flow rule translator configuration for the
- * simple_pipeline.p4 model.
+ * simple.p4 model.
*/
@Beta
-public class Bmv2SimplePipelineTranslatorConfig implements Bmv2FlowRuleTranslator.TranslatorConfig {
+public class Bmv2SimpleTranslatorConfig implements Bmv2FlowRuleTranslator.TranslatorConfig {
- private static final String JSON_CONFIG_PATH = "/simple_pipeline.json";
+ private static final String JSON_CONFIG_PATH = "/simple.json";
private final Map<String, Criterion.Type> fieldMap = Maps.newHashMap();
private final Bmv2Model model;
/**
* Creates a new simple pipeline translator configuration.
*/
- public Bmv2SimplePipelineTranslatorConfig() {
+ public Bmv2SimpleTranslatorConfig() {
this.model = getModel();
@@ -65,6 +66,12 @@
.build();
}
+ private static Bmv2Action buildPushToCpAction() {
+ return Bmv2Action.builder()
+ .withName("send_to_cpu")
+ .build();
+ }
+
private static Bmv2Action buildFwdAction(Instructions.OutputInstruction inst)
throws Bmv2FlowRuleTranslatorException {
@@ -73,8 +80,12 @@
actionBuilder.withName("fwd");
if (inst.port().isLogical()) {
- throw new Bmv2FlowRuleTranslatorException(
- "Output logic port numbers not supported: " + inst);
+ if (inst.port() == PortNumber.CONTROLLER) {
+ return buildPushToCpAction();
+ } else {
+ throw new Bmv2FlowRuleTranslatorException(
+ "Output logic port number not supported: " + inst);
+ }
}
actionBuilder.addParameter(
@@ -84,7 +95,7 @@
}
private static Bmv2Model getModel() {
- InputStream inputStream = Bmv2SimplePipelineTranslatorConfig.class
+ InputStream inputStream = Bmv2SimpleTranslatorConfig.class
.getResourceAsStream(JSON_CONFIG_PATH);
InputStreamReader reader = new InputStreamReader(inputStream);
BufferedReader bufReader = new BufferedReader(reader);
diff --git a/drivers/bmv2/src/main/resources/bmv2-drivers.xml b/drivers/bmv2/src/main/resources/bmv2-drivers.xml
index 279d470..bf1baac 100644
--- a/drivers/bmv2/src/main/resources/bmv2-drivers.xml
+++ b/drivers/bmv2/src/main/resources/bmv2-drivers.xml
@@ -18,8 +18,12 @@
<drivers>
<driver name="bmv2-thrift" manufacturer="p4.org" hwVersion="bmv2" swVersion="unknown">
<behaviour api="org.onosproject.net.behaviour.PortDiscovery"
- impl="org.onosproject.drivers.bmv2.Bmv2PortGetterDriver"/>
+ impl="org.onosproject.drivers.bmv2.Bmv2PortDiscovery"/>
<behaviour api="org.onosproject.net.flow.FlowRuleProgrammable"
- impl="org.onosproject.drivers.bmv2.Bmv2FlowRuleDriver"/>
+ impl="org.onosproject.drivers.bmv2.Bmv2FlowRuleProgrammable"/>
+ <behaviour api="org.onosproject.net.behaviour.Pipeliner"
+ impl="org.onosproject.drivers.bmv2.Bmv2Pipeliner"/>
+ <behaviour api="org.onosproject.net.packet.PacketProgrammable"
+ impl="org.onosproject.drivers.bmv2.Bmv2PacketProgrammable"/>
</driver>
</drivers>
diff --git a/drivers/bmv2/src/main/resources/simple_pipeline.json b/drivers/bmv2/src/main/resources/simple.json
similarity index 75%
rename from drivers/bmv2/src/main/resources/simple_pipeline.json
rename to drivers/bmv2/src/main/resources/simple.json
index 372bdcd..f6e6752 100644
--- a/drivers/bmv2/src/main/resources/simple_pipeline.json
+++ b/drivers/bmv2/src/main/resources/simple.json
@@ -83,22 +83,6 @@
],
"length_exp": null,
"max_length": null
- },
- {
- "name": "cpu_header_t",
- "id": 3,
- "fields": [
- [
- "device",
- 8
- ],
- [
- "reason",
- 8
- ]
- ],
- "length_exp": null,
- "max_length": null
}
],
"headers": [
@@ -119,12 +103,6 @@
"id": 2,
"header_type": "intrinsic_metadata_t",
"metadata": true
- },
- {
- "name": "cpu_header",
- "id": 3,
- "header_type": "cpu_header_t",
- "metadata": false
}
],
"header_stacks": [],
@@ -138,42 +116,6 @@
"name": "start",
"id": 0,
"parser_ops": [],
- "transition_key": [
- {
- "type": "lookahead",
- "value": [
- 0,
- 64
- ]
- }
- ],
- "transitions": [
- {
- "value": "0x0000000000000000",
- "mask": null,
- "next_state": "parse_cpu_header"
- },
- {
- "value": "default",
- "mask": null,
- "next_state": "parse_ethernet"
- }
- ]
- },
- {
- "name": "parse_cpu_header",
- "id": 1,
- "parser_ops": [
- {
- "op": "extract",
- "parameters": [
- {
- "type": "regular",
- "value": "cpu_header"
- }
- ]
- }
- ],
"transition_key": [],
"transitions": [
{
@@ -185,7 +127,7 @@
},
{
"name": "parse_ethernet",
- "id": 2,
+ "id": 1,
"parser_ops": [
{
"op": "extract",
@@ -214,7 +156,6 @@
"name": "deparser",
"id": 0,
"order": [
- "cpu_header",
"ethernet"
]
}
@@ -301,59 +242,9 @@
{
"name": "send_to_cpu",
"id": 3,
- "runtime_data": [
- {
- "name": "device",
- "bitwidth": 8
- },
- {
- "name": "reason",
- "bitwidth": 8
- }
- ],
+ "runtime_data": [],
"primitives": [
{
- "op": "add_header",
- "parameters": [
- {
- "type": "header",
- "value": "cpu_header"
- }
- ]
- },
- {
- "op": "modify_field",
- "parameters": [
- {
- "type": "field",
- "value": [
- "cpu_header",
- "device"
- ]
- },
- {
- "type": "runtime_data",
- "value": 0
- }
- ]
- },
- {
- "op": "modify_field",
- "parameters": [
- {
- "type": "field",
- "value": [
- "cpu_header",
- "reason"
- ]
- },
- {
- "type": "runtime_data",
- "value": 1
- }
- ]
- },
- {
"op": "modify_field",
"parameters": [
{
@@ -365,7 +256,7 @@
},
{
"type": "hexstr",
- "value": "0xfa"
+ "value": "0xff"
}
]
}
@@ -433,7 +324,8 @@
"send_to_cpu": null,
"_drop": null
},
- "default_action": null
+ "default_action": null,
+ "base_default_next": null
}
],
"conditionals": []