Carmelo Cascone
Committed by Thomas Vachuska

Polished BMv2 protocol module

- Improved and fixed typos in javadocs
- Added missing beta API annotations
- Refactored the default interpreter implementation

Change-Id: Ibfb21d31415d8f25cc67307f8bea2871951c9a8f
Showing 29 changed files with 129 additions and 71 deletions
......@@ -18,6 +18,7 @@ package org.onosproject.bmv2.api.context;
import com.eclipsesource.json.JsonArray;
import com.eclipsesource.json.JsonObject;
import com.google.common.annotations.Beta;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableList;
......@@ -36,6 +37,7 @@ import static com.google.common.base.Preconditions.checkArgument;
/**
* Default implementation of a BMv2 configuration backed by a JSON object.
*/
@Beta
public final class Bmv2DefaultConfiguration implements Bmv2Configuration {
private final JsonObject json;
......
......@@ -37,9 +37,9 @@ public interface Bmv2FlowRuleTranslator {
* <li> action: is built using the context interpreter
* {@link Bmv2Interpreter#mapTreatment(org.onosproject.net.flow.TrafficTreatment, Bmv2Configuration)
* treatment mapping function} or the flow rule
* {@link org.onosproject.bmv2.api.runtime.Bmv2ExtensionTreatment} extension treatment} (if any).
* <li> timeout: if the table supports timeout, use the same as the flow rule, otherwise none (i.e. permanent
* entry).
* {@link org.onosproject.bmv2.api.runtime.Bmv2ExtensionTreatment extension treatment} (if any).
* <li> timeout: if the table supports timeout, use the same as the flow rule, otherwise none (i.e. returns a
* permanent entry).
* </ul>
*
* @param rule a flow rule
......
......@@ -16,10 +16,13 @@
package org.onosproject.bmv2.api.context;
import com.google.common.annotations.Beta;
/**
* BMv2 flow rule translator exception.
*/
public class Bmv2FlowRuleTranslatorException extends Exception {
@Beta
public final class Bmv2FlowRuleTranslatorException extends Exception {
public Bmv2FlowRuleTranslatorException(String msg) {
super(msg);
......
......@@ -16,10 +16,13 @@
package org.onosproject.bmv2.api.context;
import com.google.common.annotations.Beta;
/**
* A BMv2 interpreter exception.
*/
public class Bmv2InterpreterException extends Exception {
@Beta
public final class Bmv2InterpreterException extends Exception {
public Bmv2InterpreterException(String message) {
super(message);
......
......@@ -16,6 +16,7 @@
package org.onosproject.bmv2.api.runtime;
import com.google.common.annotations.Beta;
import com.google.common.base.MoreObjects;
import com.google.common.collect.Lists;
import org.onlab.util.ImmutableByteSequence;
......@@ -30,6 +31,7 @@ import static com.google.common.base.Preconditions.checkState;
/**
* An action of a BMv2 match-action table entry.
*/
@Beta
public final class Bmv2Action {
private final String name;
......@@ -58,8 +60,7 @@ public final class Bmv2Action {
}
/**
* Returns an immutable view of the ordered list of parameters of this
* action.
* Returns an immutable view of the list of parameters of this action.
*
* @return list of byte sequence
*/
......@@ -106,7 +107,7 @@ public final class Bmv2Action {
}
/**
* Set the action name.
* Sets the action name.
*
* @param actionName a string value
* @return this
......@@ -117,7 +118,7 @@ public final class Bmv2Action {
}
/**
* Add a parameter at the end of the parameters list.
* Adds a parameter at the end of the parameters list.
*
* @param parameter a ByteBuffer value
* @return this
......
......@@ -16,6 +16,7 @@
package org.onosproject.bmv2.api.runtime;
import com.google.common.annotations.Beta;
import com.google.common.base.Objects;
import org.onosproject.net.DeviceId;
......@@ -27,8 +28,9 @@ import java.util.regex.Pattern;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Representation of a BMv2 device.
* A BMv2 device.
*/
@Beta
public final class Bmv2Device {
public static final String N_A = "n/a";
......@@ -47,9 +49,9 @@ public final class Bmv2Device {
/**
* Creates a new BMv2 device object.
*
* @param thriftServerHost the hostname / IP address of the Thrift runtime server running on the device
* @param thriftServerPort the port of the Thrift runtime server running on the device
* @param internalDeviceId the internal device ID number
* @param thriftServerHost the hostname or IP address of the Thrift RPC server running on the device
* @param thriftServerPort the listening port used by the device Thrift RPC server
* @param internalDeviceId the internal numeric device ID
*/
public Bmv2Device(String thriftServerHost, int thriftServerPort, int internalDeviceId) {
this.thriftServerHost = checkNotNull(thriftServerHost, "host cannot be null");
......@@ -68,7 +70,7 @@ public final class Bmv2Device {
}
/**
* Returns the hostname (or IP address) of the Thrift runtime server running on the device.
* Returns the hostname or IP address of the Thrift RPC server running on the device.
*
* @return a string value
*/
......@@ -77,7 +79,7 @@ public final class Bmv2Device {
}
/**
* Returns the port of the Thrift runtime server running on the device.
* Returns the listening port of the Thrift RPC server running on the device.
*
* @return an integer value
*/
......@@ -102,7 +104,6 @@ public final class Bmv2Device {
*/
public DeviceId asDeviceId() {
try {
// TODO: include internalDeviceId number in the deviceId URI
return DeviceId.deviceId(new URI(SCHEME, this.thriftServerHost + ":" + this.thriftServerPort,
String.valueOf(this.internalDeviceId)));
} catch (URISyntaxException e) {
......
......@@ -16,6 +16,7 @@
package org.onosproject.bmv2.api.runtime;
import com.google.common.annotations.Beta;
import org.apache.commons.lang3.tuple.Pair;
import org.onlab.util.ImmutableByteSequence;
import org.onosproject.net.DeviceId;
......@@ -26,6 +27,7 @@ import java.util.List;
/**
* An agent to control a BMv2 device.
*/
@Beta
public interface Bmv2DeviceAgent {
/**
......@@ -43,20 +45,20 @@ public interface Bmv2DeviceAgent {
boolean ping();
/**
* Adds a new table entry.
* Adds a new table entry. If successful returns a table-specific identifier of the installed entry.
*
* @param entry a table entry value
* @return table-specific entry ID
* @param entry a table entry
* @return a long value
* @throws Bmv2RuntimeException if any error occurs
*/
long addTableEntry(Bmv2TableEntry entry) throws Bmv2RuntimeException;
/**
* Modifies an existing table entry by updating its action.
* Modifies an existing entry at by updating its action.
*
* @param tableName string value of table name
* @param entryId long value of entry ID
* @param action an action value
* @param tableName a string value
* @param entryId a long value
* @param action an action
* @throws Bmv2RuntimeException if any error occurs
*/
void modifyTableEntry(String tableName, long entryId, Bmv2Action action) throws Bmv2RuntimeException;
......@@ -64,16 +66,16 @@ public interface Bmv2DeviceAgent {
/**
* Deletes currently installed entry.
*
* @param tableName string value of table name
* @param entryId long value of entry ID
* @param tableName a string value
* @param entryId a long value
* @throws Bmv2RuntimeException if any error occurs
*/
void deleteTableEntry(String tableName, long entryId) throws Bmv2RuntimeException;
/**
* Sets table default action.
* Sets a default action for the given table.
*
* @param tableName string value of table name
* @param tableName a string value
* @param action an action value
* @throws Bmv2RuntimeException if any error occurs
*/
......@@ -97,7 +99,7 @@ public interface Bmv2DeviceAgent {
List<Bmv2ParsedTableEntry> getTableEntries(String tableName) throws Bmv2RuntimeException;
/**
* Requests the device to transmit a given byte sequence over the given port.
* Requests the device to transmit a given packet over the given port.
*
* @param portNumber a port number
* @param packet a byte sequence
......@@ -106,7 +108,7 @@ public interface Bmv2DeviceAgent {
void transmitPacket(int portNumber, ImmutableByteSequence packet) throws Bmv2RuntimeException;
/**
* Resets the state of the switch (e.g. delete all entries, etc.).
* Resets the state of the switch.
*
* @throws Bmv2RuntimeException if any error occurs
*/
......@@ -121,7 +123,7 @@ public interface Bmv2DeviceAgent {
String dumpJsonConfig() throws Bmv2RuntimeException;
/**
* Returns the md5 sum of the JSON-formatted model configuration currently used to process packets.
* Returns the MD5 sum of the JSON-formatted configuration currently used to process packets.
*
* @return a string value
* @throws Bmv2RuntimeException if any error occurs
......@@ -139,7 +141,7 @@ public interface Bmv2DeviceAgent {
Pair<Long, Long> readTableEntryCounter(String tableName, long entryId) throws Bmv2RuntimeException;
/**
* Returns the counter values for a given counter and index.
* Returns the values of a given counter instance.
*
* @param counterName a counter name
* @param index an integer value
......
......@@ -16,6 +16,7 @@
package org.onosproject.bmv2.api.runtime;
import com.google.common.annotations.Beta;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import org.onlab.util.ImmutableByteSequence;
......@@ -23,8 +24,9 @@ import org.onlab.util.ImmutableByteSequence;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Representation of a BMv2 exact match parameter.
* A BMv2 exact match parameter.
*/
@Beta
public final class Bmv2ExactMatchParam implements Bmv2MatchParam {
private final ImmutableByteSequence value;
......@@ -45,7 +47,7 @@ public final class Bmv2ExactMatchParam implements Bmv2MatchParam {
}
/**
* Return the byte sequence value matched by this parameter.
* Return the byte sequence matched by this parameter.
*
* @return an immutable byte buffer value
*/
......
......@@ -16,6 +16,7 @@
package org.onosproject.bmv2.api.runtime;
import com.google.common.annotations.Beta;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import org.onlab.util.KryoNamespace;
......@@ -31,6 +32,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
/**
* Extension selector for BMv2 used as a wrapper for multiple BMv2 match parameters.
*/
@Beta
public final class Bmv2ExtensionSelector extends AbstractExtension implements ExtensionSelector {
private final KryoNamespace appKryo = new KryoNamespace.Builder()
......
......@@ -16,6 +16,7 @@
package org.onosproject.bmv2.api.runtime;
import com.google.common.annotations.Beta;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import org.onlab.util.KryoNamespace;
......@@ -28,16 +29,27 @@ import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.Exten
/**
* Extension treatment for BMv2 used as a wrapper for a {@link Bmv2Action}.
*/
@Beta
public final class Bmv2ExtensionTreatment extends AbstractExtension implements ExtensionTreatment {
private final KryoNamespace appKryo = new KryoNamespace.Builder().build();
private Bmv2Action action;
/**
* Creates a new extension treatment for the given BMv2 action.
*
* @param action an action
*/
public Bmv2ExtensionTreatment(Bmv2Action action) {
this.action = action;
}
public Bmv2Action getAction() {
/**
* Returns the action contained by this extension selector.
*
* @return an action
*/
public Bmv2Action action() {
return action;
}
......
......@@ -16,15 +16,17 @@
package org.onosproject.bmv2.api.runtime;
import com.google.common.annotations.Beta;
import com.google.common.base.Objects;
import org.onosproject.net.flow.FlowRule;
import java.util.Date;
/**
* A wrapper class for a ONOS flow rule installed on a BMv2 device.
* A wrapper for a ONOS flow rule installed on a BMv2 device.
*/
public class Bmv2FlowRuleWrapper {
@Beta
public final class Bmv2FlowRuleWrapper {
private final FlowRule rule;
private final long entryId;
......
......@@ -16,6 +16,7 @@
package org.onosproject.bmv2.api.runtime;
import com.google.common.annotations.Beta;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import org.onlab.util.ImmutableByteSequence;
......@@ -24,8 +25,9 @@ import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Representation of a BMv2 longest prefix match (LPM) parameter.
* A BMv2 longest prefix match (LPM) parameter.
*/
@Beta
public final class Bmv2LpmMatchParam implements Bmv2MatchParam {
private final ImmutableByteSequence value;
......
......@@ -16,6 +16,7 @@
package org.onosproject.bmv2.api.runtime;
import com.google.common.annotations.Beta;
import com.google.common.base.MoreObjects;
import com.google.common.collect.Lists;
import org.onlab.util.ImmutableByteSequence;
......@@ -30,6 +31,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
/**
* A match key of a BMv2 match-action table entry.
*/
@Beta
public final class Bmv2MatchKey {
private final List<Bmv2MatchParam> matchParams;
......
......@@ -16,9 +16,12 @@
package org.onosproject.bmv2.api.runtime;
import com.google.common.annotations.Beta;
/**
* Representation of a BMv2 match parameter.
*/
@Beta
public interface Bmv2MatchParam {
/**
......
......@@ -16,12 +16,14 @@
package org.onosproject.bmv2.api.runtime;
import com.google.common.annotations.Beta;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
/**
* Representation of a table entry installed on a BMv2 device.
*/
@Beta
public final class Bmv2ParsedTableEntry {
private final long entryId;
private final Bmv2MatchKey matchKey;
......
......@@ -16,12 +16,14 @@
package org.onosproject.bmv2.api.runtime;
import com.google.common.annotations.Beta;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
/**
* Information of a port of a BMv2 device.
*/
@Beta
public final class Bmv2PortInfo {
private final String ifaceName;
......
......@@ -16,9 +16,12 @@
package org.onosproject.bmv2.api.runtime;
import com.google.common.annotations.Beta;
/**
* General exception of the BMv2 runtime APIs.
*/
@Beta
public final class Bmv2RuntimeException extends Exception {
private final Code code;
......
......@@ -16,6 +16,8 @@
package org.onosproject.bmv2.api.runtime;
import com.google.common.annotations.Beta;
import java.util.Objects;
import static com.google.common.base.Preconditions.checkArgument;
......@@ -24,6 +26,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
/**
* An entry of a match-action table in a BMv2 device.
*/
@Beta
public final class Bmv2TableEntry {
private static final int NO_PRIORITY_VALUE = -1;
......
......@@ -16,6 +16,7 @@
package org.onosproject.bmv2.api.runtime;
import com.google.common.annotations.Beta;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import org.onosproject.net.DeviceId;
......@@ -23,6 +24,7 @@ import org.onosproject.net.DeviceId;
/**
* A reference to a table entry installed on a BMv2 device.
*/
@Beta
public final class Bmv2TableEntryReference {
......
......@@ -16,6 +16,7 @@
package org.onosproject.bmv2.api.runtime;
import com.google.common.annotations.Beta;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import org.onlab.util.ImmutableByteSequence;
......@@ -26,6 +27,7 @@ import static com.google.common.base.Preconditions.checkState;
/**
* Representation of a BMv2 ternary match parameter.
*/
@Beta
public final class Bmv2TernaryMatchParam implements Bmv2MatchParam {
private final ImmutableByteSequence value;
......
......@@ -17,6 +17,7 @@
package org.onosproject.bmv2.api.runtime;
import com.google.common.annotations.Beta;
import com.google.common.base.MoreObjects;
import java.util.Objects;
......@@ -24,6 +25,7 @@ import java.util.Objects;
/**
* Representation of a BMv2 valid match parameter.
*/
@Beta
public final class Bmv2ValidMatchParam implements Bmv2MatchParam {
private final boolean flag;
......
......@@ -16,6 +16,7 @@
package org.onosproject.bmv2.api.service;
import com.google.common.annotations.Beta;
import org.onosproject.bmv2.api.runtime.Bmv2DeviceAgent;
import org.onosproject.bmv2.api.runtime.Bmv2RuntimeException;
import org.onosproject.net.DeviceId;
......@@ -23,6 +24,7 @@ import org.onosproject.net.DeviceId;
/**
* A controller of BMv2 devices.
*/
@Beta
public interface Bmv2Controller {
/**
......
......@@ -16,6 +16,7 @@
package org.onosproject.bmv2.api.service;
import com.google.common.annotations.Beta;
import org.onosproject.bmv2.api.context.Bmv2DeviceContext;
import org.onosproject.bmv2.api.context.Bmv2Interpreter;
import org.onosproject.net.DeviceId;
......@@ -23,6 +24,7 @@ import org.onosproject.net.DeviceId;
/**
* A service for managing BMv2 device contexts.
*/
@Beta
public interface Bmv2DeviceContextService {
/**
......
......@@ -16,11 +16,13 @@
package org.onosproject.bmv2.api.service;
import com.google.common.annotations.Beta;
import org.onosproject.bmv2.api.runtime.Bmv2Device;
/**
* A listener of BMv2 device events.
*/
@Beta
public interface Bmv2DeviceListener {
/**
......
......@@ -16,12 +16,14 @@
package org.onosproject.bmv2.api.service;
import com.google.common.annotations.Beta;
import org.onlab.util.ImmutableByteSequence;
import org.onosproject.bmv2.api.runtime.Bmv2Device;
/**
* A listener of BMv2 packet events.
*/
@Beta
public interface Bmv2PacketListener {
/**
......
......@@ -17,6 +17,7 @@
package org.onosproject.bmv2.api.service;
import com.google.common.annotations.Beta;
import org.onosproject.bmv2.api.context.Bmv2FlowRuleTranslator;
import org.onosproject.bmv2.api.runtime.Bmv2FlowRuleWrapper;
import org.onosproject.bmv2.api.runtime.Bmv2TableEntryReference;
......@@ -24,6 +25,7 @@ import org.onosproject.bmv2.api.runtime.Bmv2TableEntryReference;
/**
* A service for managing BMv2 table entries.
*/
@Beta
public interface Bmv2TableEntryService {
/**
......
......@@ -16,6 +16,7 @@
package org.onosproject.bmv2.api.utils;
import com.google.common.annotations.Beta;
import org.onlab.util.HexString;
import org.onlab.util.ImmutableByteSequence;
......@@ -25,8 +26,9 @@ import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Collection of util methods to deal with flow rule translation.
* Collection of utility methods to deal with flow rule translation.
*/
@Beta
public final class Bmv2TranslatorUtils {
private Bmv2TranslatorUtils() {
......
......@@ -22,11 +22,14 @@ import org.onosproject.bmv2.api.context.Bmv2Configuration;
import org.onosproject.bmv2.api.context.Bmv2Interpreter;
import org.onosproject.bmv2.api.context.Bmv2InterpreterException;
import org.onosproject.bmv2.api.runtime.Bmv2Action;
import org.onosproject.bmv2.api.utils.Bmv2TranslatorUtils;
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;
import static org.onlab.util.ImmutableByteSequence.copyFrom;
import static org.onosproject.bmv2.api.utils.Bmv2TranslatorUtils.ByteSequenceFitException;
import static org.onosproject.bmv2.api.utils.Bmv2TranslatorUtils.fitByteSequence;
import static org.onosproject.net.PortNumber.CONTROLLER;
import static org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
......@@ -37,10 +40,10 @@ public final class Bmv2DefaultInterpreterImpl implements Bmv2Interpreter {
public static final String TABLE0 = "table0";
public static final String SEND_TO_CPU = "send_to_cpu";
public static final String PORT = "port";
public static final String DROP = "_drop";
public static final String SET_EGRESS_PORT = "set_egress_port";
// Lazily populate field map.
private static final ImmutableBiMap<Criterion.Type, String> CRITERION_MAP = ImmutableBiMap.of(
Criterion.Type.IN_PORT, "standard_metadata.ingress_port",
Criterion.Type.ETH_DST, "ethernet.dstAddr",
......@@ -64,10 +67,9 @@ public final class Bmv2DefaultInterpreterImpl implements Bmv2Interpreter {
public Bmv2Action mapTreatment(TrafficTreatment treatment, Bmv2Configuration configuration)
throws Bmv2InterpreterException {
if (treatment.allInstructions().size() == 0) {
// No instructions means drop for us.
return Bmv2Action.builder().withName(DROP).build();
return actionWithName(DROP);
} else if (treatment.allInstructions().size() > 1) {
// Otherwise, we understand treatments with only 1 instruction.
throw new Bmv2InterpreterException("Treatment has multiple instructions");
......@@ -78,47 +80,38 @@ public final class Bmv2DefaultInterpreterImpl implements Bmv2Interpreter {
switch (instruction.type()) {
case OUTPUT:
OutputInstruction outInstruction = (OutputInstruction) instruction;
if (outInstruction.port() == CONTROLLER) {
return Bmv2Action.builder().withName(SEND_TO_CPU).build();
PortNumber port = outInstruction.port();
if (!port.isLogical()) {
return buildEgressAction(port, configuration);
} else if (port.equals(CONTROLLER)) {
return actionWithName(SEND_TO_CPU);
} else {
return buildEgressAction(outInstruction, configuration);
throw new Bmv2InterpreterException("Egress on logical port not supported: " + port);
}
case NOACTION:
return Bmv2Action.builder().withName(DROP).build();
return actionWithName(DROP);
default:
throw new Bmv2InterpreterException("Instruction type not supported: " + instruction.type().name());
}
}
/**
* Builds an egress action equivalent to the given output instruction for the given configuration.
*
* @param instruction an output instruction
* @param configuration a configuration
* @return a BMv2 action
* @throws Bmv2InterpreterException if the instruction cannot be translated to a BMv2 action
*/
private Bmv2Action buildEgressAction(OutputInstruction instruction, Bmv2Configuration configuration)
private Bmv2Action buildEgressAction(PortNumber port, Bmv2Configuration configuration)
throws Bmv2InterpreterException {
Bmv2Action.Builder actionBuilder = Bmv2Action.builder();
actionBuilder.withName(SET_EGRESS_PORT);
int portBitWidth = configuration.action(SET_EGRESS_PORT).runtimeData(PORT).bitWidth();
if (instruction.port().isLogical()) {
throw new Bmv2InterpreterException("Output on logic port not supported: " + instruction);
}
// Get the byte sequence for the out port with the right length
long portNumber = instruction.port().toLong();
int bitWidth = configuration.action(SET_EGRESS_PORT).runtimeData("port").bitWidth();
try {
ImmutableByteSequence outPort = Bmv2TranslatorUtils.fitByteSequence(
ImmutableByteSequence.copyFrom(portNumber), bitWidth);
return Bmv2Action.builder().withName(SET_EGRESS_PORT).addParameter(outPort).build();
} catch (Bmv2TranslatorUtils.ByteSequenceFitException e) {
ImmutableByteSequence portBs = fitByteSequence(copyFrom(port.toLong()), portBitWidth);
return Bmv2Action.builder()
.withName(SET_EGRESS_PORT)
.addParameter(portBs)
.build();
} catch (ByteSequenceFitException e) {
throw new Bmv2InterpreterException(e.getMessage());
}
}
private Bmv2Action actionWithName(String name) {
return Bmv2Action.builder().withName(name).build();
}
}
......
......@@ -241,7 +241,7 @@ public class Bmv2FlowRuleTranslatorImpl implements Bmv2FlowRuleTranslator {
if (extTreatment.type() == ExtensionTreatmentTypes.BMV2_ACTION.type()) {
if (extTreatment instanceof Bmv2ExtensionTreatment) {
return ((Bmv2ExtensionTreatment) extTreatment).getAction();
return ((Bmv2ExtensionTreatment) extTreatment).action();
} else {
throw new Bmv2FlowRuleTranslatorException("Unable to decode treatment extension: " + extTreatment);
}
......