Adding support for VLAN_PUSH with EtherType (incl. Q-in-Q)
- Allowing VLAN_PUSH Instruction to use ethernetType (incl. using REST API)
- Adding QINQ (0x88a8) Ethernet type
- Updating InstructionCodec decoders/encoders
- Updating TrafficTreatment/FlowEntryBuilder
Change-Id: I723cc936a8a49c39da9abe65ba9e5b1bdc1392bf
diff --git a/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java b/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java
index fbe240a..623ece1 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java
@@ -401,6 +401,11 @@
}
@Override
+ public Builder pushVlan(EthType ethType) {
+ return add(Instructions.pushVlan(ethType));
+ }
+
+ @Override
public Builder transition(Integer tableId) {
return add(Instructions.transition(tableId));
}
diff --git a/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java b/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java
index d0de8e4..1ccceea 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java
@@ -291,6 +291,13 @@
Builder pushVlan();
/**
+ * Pushes a new VLAN tag using the supplied Ethernet type.
+ *
+ * @return a treatment builder
+ */
+ Builder pushVlan(EthType ethType);
+
+ /**
* Any instructions preceded by this method call will be deferred.
* @return a treatment builder
*/
diff --git a/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java b/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java
index aaf37e2..01d2c1e 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java
@@ -383,6 +383,18 @@
}
/**
+ * Creates a push VLAN header instruction using the supplied Ethernet type.
+ *
+ * @param ethType the Ethernet type to use
+ * @return a L2 modification
+ */
+ public static Instruction pushVlan(EthType ethType) {
+ return new L2ModificationInstruction.ModVlanHeaderInstruction(
+ L2ModificationInstruction.L2SubType.VLAN_PUSH,
+ ethType);
+ }
+
+ /**
* Sends the packet to the table id.
*
* @param tableId flow rule table id
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/DecodeInstructionCodecHelper.java b/core/common/src/main/java/org/onosproject/codec/impl/DecodeInstructionCodecHelper.java
index 316e9d24..fd8bd74 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/DecodeInstructionCodecHelper.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/DecodeInstructionCodecHelper.java
@@ -19,6 +19,7 @@
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.onlab.osgi.DefaultServiceDirectory;
import org.onlab.osgi.ServiceDirectory;
+import org.onlab.packet.EthType;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onlab.packet.MplsLabel;
@@ -48,6 +49,9 @@
import org.onosproject.net.meter.MeterId;
import org.slf4j.Logger;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
import static org.onlab.util.Tools.nullIsIllegal;
import static org.slf4j.LoggerFactory.getLogger;
@@ -58,6 +62,7 @@
protected static final Logger log = getLogger(DecodeInstructionCodecHelper.class);
private final ObjectNode json;
private final CodecContext context;
+ private static final Pattern ETHTYPE_PATTERN = Pattern.compile("0x([0-9a-fA-F]{4})");
/**
* Creates a decode instruction codec object.
@@ -108,6 +113,9 @@
} else if (subType.equals(L2ModificationInstruction.L2SubType.VLAN_POP.name())) {
return Instructions.popVlan();
} else if (subType.equals(L2ModificationInstruction.L2SubType.VLAN_PUSH.name())) {
+ if (json.has(InstructionCodec.ETHERNET_TYPE)) {
+ return Instructions.pushVlan(getEthType());
+ }
return Instructions.pushVlan();
} else if (subType.equals(L2ModificationInstruction.L2SubType.TUNNEL_ID.name())) {
long tunnelId = nullIsIllegal(json.get(InstructionCodec.TUNNEL_ID),
@@ -312,6 +320,23 @@
}
/**
+ * Returns Ethernet type.
+ *
+ * @return ethernet type
+ * @throws IllegalArgumentException if the JSON is invalid
+ */
+ private EthType getEthType() {
+ String ethTypeStr = nullIsIllegal(json.get(InstructionCodec.ETHERNET_TYPE),
+ InstructionCodec.ETHERNET_TYPE + InstructionCodec.MISSING_MEMBER_MESSAGE).asText();
+ Matcher matcher = ETHTYPE_PATTERN.matcher(ethTypeStr);
+ if (!matcher.matches()) {
+ throw new IllegalArgumentException("ETHERNET_TYPE must be a four digit hex string starting with 0x");
+ }
+ short ethernetType = (short) Integer.parseInt(matcher.group(1), 16);
+ return new EthType(ethernetType);
+ }
+
+ /**
* Decodes the JSON into an instruction object.
*
* @return Criterion object
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/EncodeInstructionCodecHelper.java b/core/common/src/main/java/org/onosproject/codec/impl/EncodeInstructionCodecHelper.java
index 2b3c9d7..f523430 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/EncodeInstructionCodecHelper.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/EncodeInstructionCodecHelper.java
@@ -136,6 +136,11 @@
(L2ModificationInstruction.ModVlanPcpInstruction) l2Instruction;
result.put(InstructionCodec.VLAN_PCP, modVlanPcpInstruction.vlanPcp());
break;
+ case VLAN_PUSH:
+ final L2ModificationInstruction.ModVlanHeaderInstruction pushVlanInstruction =
+ (L2ModificationInstruction.ModVlanHeaderInstruction) l2Instruction;
+ result.put(InstructionCodec.ETHERNET_TYPE, pushVlanInstruction.ethernetType().toString());
+ break;
case MPLS_LABEL:
final L2ModificationInstruction.ModMplsLabelInstruction modMplsLabelInstruction =
(L2ModificationInstruction.ModMplsLabelInstruction) l2Instruction;
diff --git a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/util/FlowEntryBuilder.java b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/util/FlowEntryBuilder.java
index d2ed633..afa2eb2 100644
--- a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/util/FlowEntryBuilder.java
+++ b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/util/FlowEntryBuilder.java
@@ -60,6 +60,7 @@
import org.projectfloodlight.openflow.protocol.action.OFActionGroup;
import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
import org.projectfloodlight.openflow.protocol.action.OFActionPopMpls;
+import org.projectfloodlight.openflow.protocol.action.OFActionPushVlan;
import org.projectfloodlight.openflow.protocol.action.OFActionSetDlDst;
import org.projectfloodlight.openflow.protocol.action.OFActionSetDlSrc;
import org.projectfloodlight.openflow.protocol.action.OFActionSetField;
@@ -400,7 +401,8 @@
builder.popVlan();
break;
case PUSH_VLAN:
- builder.pushVlan();
+ OFActionPushVlan pushVlan = (OFActionPushVlan) act;
+ builder.pushVlan(new EthType((short) pushVlan.getEthertype().getValue()));
break;
case SET_TP_DST:
case SET_TP_SRC:
@@ -438,7 +440,6 @@
} else {
treatmentInterpreter = null;
}
-
OFOxm<?> oxm = action.getField();
switch (oxm.getMatchField().id) {
case VLAN_PCP:
diff --git a/utils/misc/src/main/java/org/onlab/packet/EthType.java b/utils/misc/src/main/java/org/onlab/packet/EthType.java
index 1519ac0..d2dfec0 100644
--- a/utils/misc/src/main/java/org/onlab/packet/EthType.java
+++ b/utils/misc/src/main/java/org/onlab/packet/EthType.java
@@ -33,6 +33,7 @@
IPV6(0x86dd, "ipv6", org.onlab.packet.IPv6.deserializer()),
LLDP(0x88cc, "lldp", org.onlab.packet.LLDP.deserializer()),
VLAN(0x8100, "vlan", null),
+ QINQ(0x88a8, "qinq", null),
BDDP(0x8942, "bddp", org.onlab.packet.LLDP.deserializer()),
MPLS_UNICAST(0x8847, "mpls_unicast", org.onlab.packet.MPLS.deserializer()),
MPLS_MULTICAST(0x8848, "mpls_unicast", org.onlab.packet.MPLS.deserializer()),