Saurav Das
Committed by Gerrit Code Review

Adding support for writing metadata instruction.

Needed by Centec driver.

Change-Id: I705015c4d7ac881c273a01b36b05d39d9cd9ba87
......@@ -43,6 +43,7 @@ public final class DefaultTrafficTreatment implements TrafficTreatment {
private final List<Instruction> deferred;
private final List<Instruction> all;
private final Instructions.TableTypeTransition table;
private final Instructions.MetadataInstruction meta;
private final boolean hasClear;
......@@ -60,6 +61,7 @@ public final class DefaultTrafficTreatment implements TrafficTreatment {
this.all = this.immediate;
this.hasClear = false;
this.table = null;
this.meta = null;
}
/**
......@@ -73,13 +75,14 @@ public final class DefaultTrafficTreatment implements TrafficTreatment {
private DefaultTrafficTreatment(List<Instruction> deferred,
List<Instruction> immediate,
Instructions.TableTypeTransition table,
boolean clear) {
boolean clear,
Instructions.MetadataInstruction meta) {
this.immediate = ImmutableList.copyOf(checkNotNull(immediate));
this.deferred = ImmutableList.copyOf(checkNotNull(deferred));
this.all = ListUtils.union(this.immediate, this.deferred);
this.table = table;
this.meta = meta;
this.hasClear = clear;
}
@Override
......@@ -107,6 +110,11 @@ public final class DefaultTrafficTreatment implements TrafficTreatment {
return hasClear;
}
@Override
public Instructions.MetadataInstruction writeMetadata() {
return meta;
}
/**
* Returns a new traffic treatment builder.
*
......@@ -139,7 +147,7 @@ public final class DefaultTrafficTreatment implements TrafficTreatment {
//FIXME: Order of instructions may affect hashcode
@Override
public int hashCode() {
return Objects.hash(immediate, deferred, table);
return Objects.hash(immediate, deferred, table, meta);
}
@Override
......@@ -151,7 +159,8 @@ public final class DefaultTrafficTreatment implements TrafficTreatment {
DefaultTrafficTreatment that = (DefaultTrafficTreatment) obj;
return Objects.equals(immediate, that.immediate) &&
Objects.equals(deferred, that.deferred) &&
Objects.equals(table, that.table);
Objects.equals(table, that.table) &&
Objects.equals(meta, that.meta);
}
return false;
......@@ -164,6 +173,7 @@ public final class DefaultTrafficTreatment implements TrafficTreatment {
.add("deferred", deferred)
.add("transition", table == null ? "None" : table.toString())
.add("cleared", hasClear)
.add("metadata", meta)
.toString();
}
......@@ -177,6 +187,8 @@ public final class DefaultTrafficTreatment implements TrafficTreatment {
Instructions.TableTypeTransition table;
Instructions.MetadataInstruction meta;
List<Instruction> deferred = Lists.newLinkedList();
List<Instruction> immediate = Lists.newLinkedList();
......@@ -213,6 +225,9 @@ public final class DefaultTrafficTreatment implements TrafficTreatment {
case TABLE:
table = (Instructions.TableTypeTransition) instruction;
break;
case METADATA:
meta = (Instructions.MetadataInstruction) instruction;
break;
default:
throw new IllegalArgumentException("Unknown instruction type: " +
instruction.type());
......@@ -355,6 +370,11 @@ public final class DefaultTrafficTreatment implements TrafficTreatment {
}
@Override
public Builder writeMetadata(long metadata, long metadataMask) {
return add(Instructions.writeMetadata(metadata, metadataMask));
}
@Override
public TrafficTreatment build() {
//Don't add DROP instruction by default when instruction
//set is empty. This will be handled in DefaultSingleTablePipeline
......@@ -364,7 +384,7 @@ public final class DefaultTrafficTreatment implements TrafficTreatment {
// && table == null && !clear) {
// drop();
//}
return new DefaultTrafficTreatment(deferred, immediate, table, clear);
return new DefaultTrafficTreatment(deferred, immediate, table, clear, meta);
}
}
......
......@@ -67,6 +67,13 @@ public interface TrafficTreatment {
boolean clearedDeferred();
/**
* Returns the metadata instruction if there is one.
*
* @return a metadata instruction that may be null
*/
Instructions.MetadataInstruction writeMetadata();
/**
* Builder of traffic treatment entities.
*/
interface Builder {
......@@ -276,6 +283,20 @@ public interface TrafficTreatment {
Builder wipeDeferred();
/**
* Writes metadata to associate with a packet.
* <pre>
* {@code
* new_metadata = (old_metadata & ̃mask) | (value & mask)
* }
* </pre>
*
* @param value the metadata to write
* @param mask the masked bits for the value
* @return a treatment builder
*/
Builder writeMetadata(long value, long mask);
/**
* Builds an immutable traffic treatment descriptor.
* <p>
* If the treatment is empty when build() is called, it will add a default
......@@ -286,5 +307,7 @@ public interface TrafficTreatment {
* @return traffic treatment
*/
TrafficTreatment build();
}
}
......
......@@ -35,7 +35,7 @@ public interface Instruction {
OUTPUT,
/**
* Signifies that.... (do we need this?)
* Signifies that traffic should be sent out of a group.
*/
GROUP,
......@@ -57,7 +57,12 @@ public interface Instruction {
/**
* Signifies that the traffic should be modified in L3 way.
*/
L3MODIFICATION
L3MODIFICATION,
/**
* Signifies that metadata be attached to traffic.
*/
METADATA
}
/**
......
......@@ -323,6 +323,17 @@ public final class Instructions {
}
/**
* Writes metadata to associate with a packet.
*
* @param metadata the metadata value to write
* @param metadataMask the bits to mask for the metadata value
* @return metadata instruction
*/
public static Instruction writeMetadata(long metadata, long metadataMask) {
return new MetadataInstruction(metadata, metadataMask);
}
/**
* Drop instruction.
*/
public static final class DropInstruction implements Instruction {
......@@ -443,7 +454,9 @@ public final class Instructions {
}
}
/**
* Transition instruction.
*/
public static class TableTypeTransition implements Instruction {
private final Integer tableId;
......@@ -483,7 +496,59 @@ public final class Instructions {
}
return false;
}
}
/**
* Metadata instruction.
*/
public static class MetadataInstruction implements Instruction {
private final long metadata;
private final long metadataMask;
MetadataInstruction(long metadata, long metadataMask) {
this.metadata = metadata;
this.metadataMask = metadataMask;
}
@Override
public Type type() {
return Type.METADATA;
}
public long metadata() {
return this.metadata;
}
public long metadataMask() {
return this.metadataMask;
}
@Override
public String toString() {
return toStringHelper(type().toString())
.add("metadata", Long.toHexString(this.metadata))
.add("metadata mask", Long.toHexString(this.metadataMask))
.toString();
}
@Override
public int hashCode() {
return Objects.hash(type(), metadata, metadataMask);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof MetadataInstruction) {
MetadataInstruction that = (MetadataInstruction) obj;
return Objects.equals(metadata, that.metadata) &&
Objects.equals(metadataMask, that.metadataMask);
}
return false;
}
}
}
......
......@@ -36,6 +36,7 @@ import org.onosproject.net.flow.criteria.Criterion;
import org.onosproject.net.flow.criteria.Criterion.Type;
import org.onosproject.net.flow.instructions.Instruction;
import org.onosproject.net.flow.instructions.Instructions;
import org.onosproject.net.flow.instructions.Instructions.MetadataInstruction;
import org.onosproject.net.resource.link.BandwidthResource;
import org.onosproject.net.resource.link.BandwidthResourceRequest;
import org.onosproject.net.resource.link.LambdaResource;
......@@ -118,6 +119,11 @@ public class IntentTestsMocks {
public boolean clearedDeferred() {
return false;
}
@Override
public MetadataInstruction writeMetadata() {
return null;
}
}
/**
......
......@@ -21,6 +21,7 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
......@@ -58,6 +59,7 @@ import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flow.criteria.Criterion;
import org.onosproject.net.flow.instructions.Instruction;
import org.onosproject.net.flow.instructions.Instructions;
import org.onosproject.net.flow.instructions.Instructions.MetadataInstruction;
import org.onosproject.net.provider.AbstractProvider;
import org.onosproject.net.provider.ProviderId;
import org.onosproject.store.trivial.impl.SimpleFlowRuleStore;
......@@ -595,6 +597,11 @@ public class FlowRuleManagerTest {
return false;
}
@Override
public MetadataInstruction writeMetadata() {
return null;
}
}
public class TestApplicationId extends DefaultApplicationId {
......
......@@ -78,6 +78,7 @@ public class CentecV350Pipeline extends AbstractHandlerBehaviour implements Pipe
protected static final int ROUTE_TABLE = 3;
private static final long DEFAULT_METADATA = 100;
private static final long DEFAULT_METADATA_MASK = 0xff;
// Priority used in PORT_VLAN Table, the only priority accepted is PORT_VLAN_TABLE_PRIORITY.
// The packet passed PORT+VLAN check will goto FILTER Table.
......@@ -408,10 +409,10 @@ public class CentecV350Pipeline extends AbstractHandlerBehaviour implements Pipe
selector.matchInPort(p.port());
// Although the accepted packets will be sent to filter table, we must
// explicitly set goto_table instruction here.
treatment.writeMetadata(DEFAULT_METADATA, DEFAULT_METADATA_MASK);
// set default metadata written by PORT_VLAN Table.
treatment.transition(FILTER_TABLE);
// We do not support strip vlan here, treatment.deferred().popVlan();
// XXX: write_metadata seems not supported by ONOS now, use the switch CLI to
// set default metadata written by PORT_VLAN Table.
// PORT_VLAN table only accept 0xffff priority since it does exact match only.
FlowRule rule = DefaultFlowRule.builder()
.forDevice(deviceId)
......
......@@ -16,6 +16,7 @@
package org.onosproject.provider.of.flow.impl;
import com.google.common.collect.Lists;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip4Prefix;
import org.onlab.packet.Ip6Address;
......@@ -56,6 +57,7 @@ import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
import org.projectfloodlight.openflow.protocol.instruction.OFInstructionApplyActions;
import org.projectfloodlight.openflow.protocol.instruction.OFInstructionGotoTable;
import org.projectfloodlight.openflow.protocol.instruction.OFInstructionWriteActions;
import org.projectfloodlight.openflow.protocol.instruction.OFInstructionWriteMetadata;
import org.projectfloodlight.openflow.protocol.match.Match;
import org.projectfloodlight.openflow.protocol.match.MatchField;
import org.projectfloodlight.openflow.protocol.oxm.OFOxm;
......@@ -219,6 +221,9 @@ public class FlowEntryBuilder {
.getTableId().getValue()));
break;
case WRITE_METADATA:
OFInstructionWriteMetadata m = (OFInstructionWriteMetadata) in;
builder.writeMetadata(m.getMetadata().getValue(),
m.getMetadataMask().getValue());
break;
case WRITE_ACTIONS:
builder.deferred();
......
......@@ -167,6 +167,8 @@ public class FlowModBuilderVer10 extends FlowModBuilder {
break;
case L0MODIFICATION:
case GROUP:
case TABLE:
case METADATA:
log.warn("Instruction type {} not supported with protocol version {}",
i.type(), factory().getVersion());
break;
......
......@@ -117,6 +117,9 @@ public class FlowModBuilderVer13 extends FlowModBuilder {
if (treatment.tableTransition() != null) {
instructions.add(buildTableGoto(treatment.tableTransition()));
}
if (treatment.writeMetadata() != null) {
instructions.add(buildMetadata(treatment.writeMetadata()));
}
long cookie = flowRule().id().value();
......@@ -154,6 +157,9 @@ public class FlowModBuilderVer13 extends FlowModBuilder {
if (treatment.tableTransition() != null) {
instructions.add(buildTableGoto(treatment.tableTransition()));
}
if (treatment.writeMetadata() != null) {
instructions.add(buildMetadata(treatment.writeMetadata()));
}
long cookie = flowRule().id().value();
......@@ -247,6 +253,12 @@ public class FlowModBuilderVer13 extends FlowModBuilder {
return instruction;
}
private OFInstruction buildMetadata(Instructions.MetadataInstruction m) {
OFInstruction instruction = factory().instructions().writeMetadata(
U64.of(m.metadata()), U64.of(m.metadataMask()));
return instruction;
}
private OFAction buildL0Modification(Instruction i) {
L0ModificationInstruction l0m = (L0ModificationInstruction) i;
switch (l0m.subtype()) {
......