Carmelo Cascone
Committed by Gerrit Code Review

ONOS-4410 Implemented PacketProgrammable and Pipeliner behaviors in the

BMv2 driver

Also other minor fixes / refactorings

Change-Id: I2205890b76471e8e8490beccd6b36e5358f8d407
......@@ -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
......
......@@ -42,11 +42,14 @@ import java.util.Collections;
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();
......
/*
* 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);
}
}
}
/*
* 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);
}
}
......@@ -34,7 +34,7 @@ import org.slf4j.LoggerFactory;
import java.util.Collections;
import java.util.List;
public class Bmv2PortGetterDriver extends AbstractHandlerBehaviour
public class Bmv2PortDiscovery extends AbstractHandlerBehaviour
implements PortDiscovery {
private final Logger log =
......
......@@ -67,7 +67,7 @@ import org.onosproject.net.flow.instructions.Instructions.ExtensionInstructionWr
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)
......
......@@ -23,6 +23,7 @@ import com.google.common.collect.Maps;
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 @@ import java.util.Map;
/**
* 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 @@ public class Bmv2SimplePipelineTranslatorConfig implements Bmv2FlowRuleTranslato
.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 @@ public class Bmv2SimplePipelineTranslatorConfig implements Bmv2FlowRuleTranslato
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 @@ public class Bmv2SimplePipelineTranslatorConfig implements Bmv2FlowRuleTranslato
}
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);
......
......@@ -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>
......
......@@ -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": []
......
......@@ -20,7 +20,7 @@
<feature>onos-drivers-bmv2</feature>
<bundle>mvn:${project.groupId}/${project.artifactId}/${project.version}</bundle>
<bundle>mvn:${project.groupId}/onos-bmv2-provider-device/${project.version}</bundle>
<bundle>mvn:org.apache.thrift/libthrift/0.9.2</bundle>
<bundle>mvn:org.apache.thrift/libthrift/0.9.3</bundle>
<bundle>mvn:${project.groupId}/onos-bmv2-protocol/${project.version}</bundle>
</feature>
</features>
......