Match field iteration
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/match/Match.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/match/Match.java
index 5e68de5..0efdcbb 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/match/Match.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/match/Match.java
@@ -26,7 +26,7 @@
* them in part. For example, OF1.0 supports exact match and (full) wildcarding for all fields, but it
* does only supports partial masking for IP source/destination fields, and this partial masking must be
* in the CIDR prefix format. Thus, OF1.0 implementation may throw <code>UnsupportedOperationException</code> if given
- * in <code>setMaksed</code> an IP mask of, for example, 255.0.255.0, or if <code>setMasked</code> is called for any field
+ * in <code>setMasked</code> an IP mask of, for example, 255.0.255.0, or if <code>setMasked</code> is called for any field
* which is not IP source/destination address.
* <br><br>
* On prerequisites:<br>
@@ -37,7 +37,7 @@
* be ignored unless the Ethertype is specified as MPLS. Likewise, the IP header and
* transport header fields will be ignored unless the Ethertype is specified as either
* IPv4 or ARP. The tp_src and tp_dst fields will be ignored unless the network protocol
- * specified is as TCP, UDP or SCTP. Fields that are ignored don�t need to be wildcarded
+ * specified is as TCP, UDP or SCTP. Fields that are ignored don't need to be wildcarded
* and should be set to 0."
* <br><br>
* This interface uses generics to assure type safety in users code. However, implementing classes may have to suppress
@@ -124,6 +124,15 @@
public boolean isPartiallyMasked(MatchField<?> field) throws UnsupportedOperationException;
/**
+ * Get an Iterable over the match fields that have been specified for the
+ * match. This includes the match fields that are exact or masked match
+ * (but not fully wildcarded).
+ *
+ * @return
+ */
+ public Iterable<MatchField<?>> getMatchFields();
+
+ /**
* Returns a builder to build new instances of this type of match object.
* @return Match builder
*/
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFMetadata.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFMetadata.java
index d1a23df..fcabdcd 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFMetadata.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFMetadata.java
@@ -27,6 +27,10 @@
return new OFMetadata(U64.ofRaw(raw));
}
+ public U64 getValue() {
+ return u64;
+ }
+
public static OFMetadata read8Bytes(ChannelBuffer cb) {
return OFMetadata.ofRaw(cb.readLong());
}
diff --git a/java_gen/pre-written/src/test/java/org/projectfloodlight/protocol/match/MatchFieldIteration10Test.java b/java_gen/pre-written/src/test/java/org/projectfloodlight/protocol/match/MatchFieldIteration10Test.java
new file mode 100644
index 0000000..c6f4471
--- /dev/null
+++ b/java_gen/pre-written/src/test/java/org/projectfloodlight/protocol/match/MatchFieldIteration10Test.java
@@ -0,0 +1,10 @@
+package org.projectfloodlight.protocol.match;
+
+import org.projectfloodlight.openflow.protocol.OFFactories;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+
+public class MatchFieldIteration10Test extends MatchFieldIterationBase {
+ public MatchFieldIteration10Test() {
+ super(OFFactories.getFactory(OFVersion.OF_10));
+ }
+}
diff --git a/java_gen/pre-written/src/test/java/org/projectfloodlight/protocol/match/MatchFieldIteration13Test.java b/java_gen/pre-written/src/test/java/org/projectfloodlight/protocol/match/MatchFieldIteration13Test.java
new file mode 100644
index 0000000..b654a53
--- /dev/null
+++ b/java_gen/pre-written/src/test/java/org/projectfloodlight/protocol/match/MatchFieldIteration13Test.java
@@ -0,0 +1,10 @@
+package org.projectfloodlight.protocol.match;
+
+import org.projectfloodlight.openflow.protocol.OFFactories;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+
+public class MatchFieldIteration13Test extends MatchFieldIterationBase {
+ public MatchFieldIteration13Test() {
+ super(OFFactories.getFactory(OFVersion.OF_13));
+ }
+}
diff --git a/java_gen/pre-written/src/test/java/org/projectfloodlight/protocol/match/MatchFieldIterationBase.java b/java_gen/pre-written/src/test/java/org/projectfloodlight/protocol/match/MatchFieldIterationBase.java
new file mode 100644
index 0000000..9c72e37
--- /dev/null
+++ b/java_gen/pre-written/src/test/java/org/projectfloodlight/protocol/match/MatchFieldIterationBase.java
@@ -0,0 +1,249 @@
+package org.projectfloodlight.protocol.match;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
+
+import java.util.Iterator;
+
+import org.junit.Test;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+import org.projectfloodlight.openflow.protocol.match.Match;
+import org.projectfloodlight.openflow.protocol.match.MatchField;
+import org.projectfloodlight.openflow.protocol.match.MatchFields;
+import org.projectfloodlight.openflow.types.ArpOpcode;
+import org.projectfloodlight.openflow.types.EthType;
+import org.projectfloodlight.openflow.types.IPv4Address;
+import org.projectfloodlight.openflow.types.IpProtocol;
+import org.projectfloodlight.openflow.types.MacAddress;
+import org.projectfloodlight.openflow.types.Masked;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.TransportPort;
+
+import com.google.common.collect.Iterables;
+
+public class MatchFieldIterationBase {
+
+ private OFFactory factory;
+
+ protected MatchFieldIterationBase(OFFactory factory) {
+ this.factory = factory;
+ }
+
+ @Test
+ public void iterateEmptyMatch() {
+ Match match = factory.buildMatch().build();
+ Iterator<MatchField<?>> iter = match.getMatchFields().iterator();
+ assertThat(iter.hasNext(), is(false));
+ }
+
+ @Test
+ public void iterateSingleExactMatchField() {
+ OFPort port5 = OFPort.of(5);
+ Match match = factory.buildMatch()
+ .setExact(MatchField.IN_PORT, port5)
+ .build();
+ Iterator<MatchField<?>> iter = match.getMatchFields().iterator();
+ assertThat(iter.hasNext(), is(true));
+ MatchField<?> matchField = iter.next();
+ assertThat(matchField.id, is(MatchFields.IN_PORT));
+ assertThat(match.isExact(matchField), is(true));
+ @SuppressWarnings("unchecked")
+ MatchField<OFPort> portMatchField = (MatchField<OFPort>) matchField;
+ OFPort port = match.get(portMatchField);
+ assertThat(port, is(port5));
+ assertThat(iter.hasNext(), is(false));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void iterateExactMatchFields() {
+ OFPort port5 = OFPort.of(5);
+ MacAddress macSrc = MacAddress.of("00:01:02:03:04:05");
+ MacAddress macDst = MacAddress.of("01:01:02:02:03:03");
+ IPv4Address ipSrc = IPv4Address.of("10.192.20.1");
+ IPv4Address ipDst = IPv4Address.of("10.192.20.2");
+ TransportPort tcpSrc = TransportPort.of(100);
+ TransportPort tcpDst = TransportPort.of(200);
+ Match match = factory.buildMatch()
+ .setExact(MatchField.IN_PORT, port5)
+ .setExact(MatchField.ETH_TYPE, EthType.IPv4)
+ .setExact(MatchField.ETH_SRC, macSrc)
+ .setExact(MatchField.ETH_DST, macDst)
+ .setExact(MatchField.IP_PROTO, IpProtocol.TCP)
+ .setExact(MatchField.IPV4_SRC, ipSrc)
+ .setExact(MatchField.IPV4_DST, ipDst)
+ .setExact(MatchField.TCP_SRC, tcpSrc)
+ .setExact(MatchField.TCP_DST, tcpDst)
+ .build();
+ assertThat(Iterables.size(match.getMatchFields()), is(9));
+ for (MatchField<?> matchField: match.getMatchFields()) {
+ switch (matchField.id) {
+ case IN_PORT:
+ OFPort port = match.get((MatchField<OFPort>) matchField);
+ assertThat(port, is(port5));
+ break;
+ case ETH_TYPE:
+ EthType ethType = match.get((MatchField<EthType>) matchField);
+ assertThat(ethType, is(EthType.IPv4));
+ break;
+ case ETH_SRC:
+ MacAddress mac = match.get((MatchField<MacAddress>) matchField);
+ assertThat(mac, is(macSrc));
+ break;
+ case ETH_DST:
+ mac = match.get((MatchField<MacAddress>) matchField);
+ assertThat(mac, is(macDst));
+ break;
+ case IP_PROTO:
+ IpProtocol ipProtocol = match.get((MatchField<IpProtocol>) matchField);
+ assertThat(ipProtocol, is(IpProtocol.TCP));
+ break;
+ case IPV4_SRC:
+ IPv4Address ip = match.get((MatchField<IPv4Address>) matchField);
+ assertThat(ip, is(ipSrc));
+ break;
+ case IPV4_DST:
+ ip = match.get((MatchField<IPv4Address>) matchField);
+ assertThat(ip, is(ipDst));
+ break;
+ case TCP_SRC:
+ TransportPort tcp = match.get((MatchField<TransportPort>) matchField);
+ assertThat(tcp, is(tcpSrc));
+ break;
+ case TCP_DST:
+ tcp = match.get((MatchField<TransportPort>) matchField);
+ assertThat(tcp, is(tcpDst));
+ break;
+ default:
+ fail("Unexpected match field returned from iterator");
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void iterateArpFields() {
+ MacAddress macSrc = MacAddress.of("00:01:02:03:04:05");
+ MacAddress macDst = MacAddress.of("01:01:02:02:03:03");
+ IPv4Address ipSrc = IPv4Address.of("10.192.20.1");
+ IPv4Address ipDst = IPv4Address.of("10.192.20.2");
+ OFVersion version = factory.getVersion();
+ boolean supportsArpHardwareAddress = (version != OFVersion.OF_10) &&
+ (version != OFVersion.OF_11) && (version != OFVersion.OF_12);
+ int matchFieldCount = 4;
+ Match.Builder builder = factory.buildMatch();
+ builder.setExact(MatchField.ETH_TYPE, EthType.ARP)
+ .setExact(MatchField.ARP_OP, ArpOpcode.REPLY)
+ .setExact(MatchField.ARP_SPA, ipSrc)
+ .setExact(MatchField.ARP_TPA, ipDst);
+ if (supportsArpHardwareAddress) {
+ builder.setExact(MatchField.ARP_SHA, macSrc);
+ builder.setExact(MatchField.ARP_THA, macDst);
+ matchFieldCount += 2;
+ }
+ Match match = builder.build();
+ assertThat(Iterables.size(match.getMatchFields()), is(matchFieldCount));
+ for (MatchField<?> matchField: match.getMatchFields()) {
+ switch (matchField.id) {
+ case ETH_TYPE:
+ EthType ethType = match.get((MatchField<EthType>) matchField);
+ assertThat(ethType, is(EthType.ARP));
+ break;
+ case ARP_OP:
+ ArpOpcode opcode = match.get((MatchField<ArpOpcode>) matchField);
+ assertThat(opcode, is(ArpOpcode.REPLY));
+ break;
+ case ARP_SHA:
+ MacAddress mac = match.get((MatchField<MacAddress>) matchField);
+ assertThat(mac, is(macSrc));
+ break;
+ case ARP_THA:
+ mac = match.get((MatchField<MacAddress>) matchField);
+ assertThat(mac, is(macDst));
+ break;
+ case ARP_SPA:
+ IPv4Address ip = match.get((MatchField<IPv4Address>) matchField);
+ assertThat(ip, is(ipSrc));
+ break;
+ case ARP_TPA:
+ ip = match.get((MatchField<IPv4Address>) matchField);
+ assertThat(ip, is(ipDst));
+ break;
+ default:
+ fail("Unexpected match field returned from iterator");
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void iterateMaskedFields() {
+ MacAddress macSrc = MacAddress.of("01:02:03:04:00:00");
+ MacAddress macSrcMask = MacAddress.of("FF:FF:FF:FF:00:00");
+ MacAddress macDst = MacAddress.of("11:22:33:00:00:00");
+ MacAddress macDstMask = MacAddress.of("FF:FF:FF:00:00:00");
+ IPv4Address ipSrc = IPv4Address.of("10.192.20.0");
+ IPv4Address ipSrcMask = IPv4Address.of("255.255.255.0");
+ IPv4Address ipDst = IPv4Address.of("10.192.20.0");
+ IPv4Address ipDstMask = IPv4Address.of("255.255.255.128");
+ TransportPort tcpSrcMask = TransportPort.of(0x01F0);
+ OFVersion version = factory.getVersion();
+ boolean supportsAllMasks = (version != OFVersion.OF_10) &&
+ (version != OFVersion.OF_11) && (version != OFVersion.OF_12);
+ int matchFieldCount = 4;
+ Match.Builder builder = factory.buildMatch()
+ .setExact(MatchField.ETH_TYPE, EthType.IPv4)
+ .setMasked(MatchField.IPV4_SRC, ipSrc, ipSrcMask)
+ .setMasked(MatchField.IPV4_DST, ipDst, ipDstMask)
+ .setExact(MatchField.IP_PROTO, IpProtocol.TCP);
+ if (supportsAllMasks) {
+ builder.setMasked(MatchField.ETH_SRC, macSrc, macSrcMask);
+ builder.setMasked(MatchField.ETH_DST, macDst, macDstMask);
+ builder.setMasked(MatchField.TCP_SRC, tcpSrcMask, tcpSrcMask);
+ matchFieldCount += 3;
+ }
+ Match match = builder.build();
+ assertThat(Iterables.size(match.getMatchFields()), is(matchFieldCount));
+ for (MatchField<?> matchField: match.getMatchFields()) {
+ switch (matchField.id) {
+ case ETH_TYPE:
+ EthType ethType = match.get((MatchField<EthType>) matchField);
+ assertThat(ethType, is(EthType.IPv4));
+ break;
+ case ETH_SRC:
+ Masked<MacAddress> mac = match.getMasked((MatchField<MacAddress>) matchField);
+ assertThat(mac.getValue(), is(macSrc));
+ assertThat(mac.getMask(), is(macSrcMask));
+ break;
+ case ETH_DST:
+ mac = match.getMasked((MatchField<MacAddress>) matchField);
+ assertThat(mac.getValue(), is(macDst));
+ assertThat(mac.getMask(), is(macDstMask));
+ break;
+ case IP_PROTO:
+ IpProtocol ipProtocol = match.get((MatchField<IpProtocol>) matchField);
+ assertThat(ipProtocol, is(IpProtocol.TCP));
+ break;
+ case IPV4_SRC:
+ Masked<IPv4Address> ip = match.getMasked((MatchField<IPv4Address>) matchField);
+ assertThat(ip.getValue(), is(ipSrc));
+ assertThat(ip.getMask(), is(ipSrcMask));
+ break;
+ case IPV4_DST:
+ ip = match.getMasked((MatchField<IPv4Address>) matchField);
+ assertThat(ip.getValue(), is(ipDst));
+ assertThat(ip.getMask(), is(ipDstMask));
+ break;
+ case TCP_SRC:
+ Masked<TransportPort> tcp = match.getMasked((MatchField<TransportPort>) matchField);
+ assertThat(tcp.getValue(), is(tcpSrcMask));
+ assertThat(tcp.getMask(), is(tcpSrcMask));
+ break;
+ default:
+ fail("Unexpected match field returned from iterator");
+ }
+ }
+ }
+}
diff --git a/java_gen/templates/_imports.java b/java_gen/templates/_imports.java
index 2187bab..cf7334d 100644
--- a/java_gen/templates/_imports.java
+++ b/java_gen/templates/_imports.java
@@ -1,6 +1,7 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.Map;
@@ -21,5 +22,6 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
+import com.google.common.collect.UnmodifiableIterator;
import com.google.common.hash.Funnel;
import com.google.common.hash.PrimitiveSink;
diff --git a/java_gen/templates/custom/OFMatchV1Ver10.java b/java_gen/templates/custom/OFMatchV1Ver10.java
index 82ff10f..7b750bb 100644
--- a/java_gen/templates/custom/OFMatchV1Ver10.java
+++ b/java_gen/templates/custom/OFMatchV1Ver10.java
@@ -334,3 +334,77 @@
throw new UnsupportedOperationException("OFMatch does not support masked matching on field " + field.getName());
}
}
+
+ @Override
+ public Iterable<MatchField<?>> getMatchFields() {
+ ImmutableList.Builder<MatchField<?>> builder = ImmutableList.builder();
+ if ((wildcards & OFPFW_IN_PORT) == 0)
+ builder.add(MatchField.IN_PORT);
+ if ((wildcards & OFPFW_DL_VLAN) == 0)
+ builder.add(MatchField.VLAN_VID);
+ if ((wildcards & OFPFW_DL_SRC) == 0)
+ builder.add(MatchField.ETH_SRC);
+ if ((wildcards & OFPFW_DL_DST) == 0)
+ builder.add(MatchField.ETH_DST);
+ if ((wildcards & OFPFW_DL_TYPE) == 0)
+ builder.add(MatchField.ETH_TYPE);
+ if ((wildcards & OFPFW_NW_PROTO) == 0) {
+ if (ethType == EthType.ARP) {
+ builder.add(MatchField.ARP_OP);
+ } else if (ethType == EthType.IPv4) {
+ builder.add(MatchField.IP_PROTO);
+ } else {
+ throw new UnsupportedOperationException(
+ "Unsupported Ethertype for matching on network protocol " + ethType);
+ }
+ }
+ if ((wildcards & OFPFW_TP_SRC) == 0) {
+ if (ipProto == IpProtocol.UDP) {
+ builder.add(MatchField.UDP_SRC);
+ } else if (ipProto == IpProtocol.TCP) {
+ builder.add(MatchField.TCP_SRC);
+ } else if (ipProto == IpProtocol.SCTP) {
+ builder.add(MatchField.SCTP_SRC);
+ } else {
+ throw new UnsupportedOperationException(
+ "Unsupported IP protocol for matching on source port " + ipProto);
+ }
+ }
+ if ((wildcards & OFPFW_TP_DST) == 0) {
+ if (ipProto == IpProtocol.UDP) {
+ builder.add(MatchField.UDP_DST);
+ } else if (ipProto == IpProtocol.TCP) {
+ builder.add(MatchField.TCP_DST);
+ } else if (ipProto == IpProtocol.SCTP) {
+ builder.add(MatchField.SCTP_DST);
+ } else {
+ throw new UnsupportedOperationException(
+ "Unsupported IP protocol for matching on destination port " + ipProto);
+ }
+ }
+ if (((wildcards & OFPFW_NW_SRC_MASK) >> OFPFW_NW_SRC_SHIFT) < 32) {
+ if (ethType == EthType.ARP) {
+ builder.add(MatchField.ARP_SPA);
+ } else if (ethType == EthType.IPv4) {
+ builder.add(MatchField.IPV4_SRC);
+ } else {
+ throw new UnsupportedOperationException(
+ "Unsupported Ethertype for matching on source IP " + ethType);
+ }
+ }
+ if (((wildcards & OFPFW_NW_DST_MASK) >> OFPFW_NW_DST_SHIFT) < 32) {
+ if (ethType == EthType.ARP) {
+ builder.add(MatchField.ARP_TPA);
+ } else if (ethType == EthType.IPv4) {
+ builder.add(MatchField.IPV4_DST);
+ } else {
+ throw new UnsupportedOperationException(
+ "Unsupported Ethertype for matching on destination IP " + ethType);
+ }
+ }
+ if ((wildcards & OFPFW_DL_VLAN_PCP) == 0)
+ builder.add(MatchField.VLAN_PCP);
+ if ((wildcards & OFPFW_NW_TOS) == 0)
+ builder.add(MatchField.IP_DSCP);
+ return builder.build();
+ }
diff --git a/java_gen/templates/custom/OFMatchV2Ver11.java b/java_gen/templates/custom/OFMatchV2Ver11.java
index ec7bfcc..ef79ffb 100644
--- a/java_gen/templates/custom/OFMatchV2Ver11.java
+++ b/java_gen/templates/custom/OFMatchV2Ver11.java
@@ -42,3 +42,8 @@
// FIXME yotam - please replace with real implementation
return false;
}
+
+ @Override
+ public Iterable<MatchField<?>> getMatchFields() {
+ throw new UnsupportedOperationException();
+ }
diff --git a/java_gen/templates/custom/OFMatchV3Ver12.java b/java_gen/templates/custom/OFMatchV3Ver12.java
index a4cc51c..81092c1 100644
--- a/java_gen/templates/custom/OFMatchV3Ver12.java
+++ b/java_gen/templates/custom/OFMatchV3Ver12.java
@@ -106,4 +106,9 @@
OFOxm<?> oxm = this.oxmList.get(field);
return oxm != null && oxm.isMasked();
- }
\ No newline at end of file
+ }
+
+ @Override
+ public Iterable<MatchField<?>> getMatchFields() {
+ throw new UnsupportedOperationException();
+ }
diff --git a/java_gen/templates/custom/OFMatchV3Ver13.java b/java_gen/templates/custom/OFMatchV3Ver13.java
index 8955e1e..9bfb234 100644
--- a/java_gen/templates/custom/OFMatchV3Ver13.java
+++ b/java_gen/templates/custom/OFMatchV3Ver13.java
@@ -108,3 +108,31 @@
return oxm != null && oxm.isMasked();
}
+
+ private class MatchFieldIterator extends UnmodifiableIterator<MatchField<?>> {
+ private Iterator<OFOxm<?>> oxmIterator;
+
+ MatchFieldIterator() {
+ oxmIterator = oxmList.iterator();
+ }
+
+ @Override
+ public boolean hasNext() {
+ return oxmIterator.hasNext();
+ }
+
+ @Override
+ public MatchField<?> next() {
+ OFOxm<?> next = oxmIterator.next();
+ return next.getMatchField();
+ }
+ }
+
+ @Override
+ public Iterable<MatchField<?>> getMatchFields() {
+ return new Iterable<MatchField<?>>() {
+ public Iterator<MatchField<?>> iterator() {
+ return new MatchFieldIterator();
+ }
+ };
+ }