Merge branch 'master' of github.com:andi-bigswitch/loxigen
diff --git a/java_gen/codegen.py b/java_gen/codegen.py
index f3619d4..bc9b9a0 100644
--- a/java_gen/codegen.py
+++ b/java_gen/codegen.py
@@ -37,6 +37,7 @@
from loxi_ir import *
import lang_java
import test_data
+from import_cleaner import ImportCleaner
import loxi_utils.loxi_utils as loxi_utils
@@ -84,6 +85,14 @@
print "filename: %s" % filename
with open(filename, "w") as f:
loxi_utils.render_template(f, template, [self.templates_dir], context, prefix=prefix)
+
+ try:
+ cleaner = ImportCleaner(filename)
+ cleaner.find_used_imports()
+ cleaner.rewrite_file(filename)
+ except:
+ print 'Cannot clean imports from file %s' % filename
+
def create_of_const_enums(self):
for enum in self.java_model.enums:
@@ -126,13 +135,16 @@
else:
print "Class %s ignored by generate_class" % java_class.name
- def create_unit_test(self, unit_test):
- if unit_test.has_test_data:
- self.render_class(clazz=unit_test,
- template='unit_test.java', src_dir="src/test/java",
- version=unit_test.java_class.version,
- test=unit_test, msg=unit_test.java_class,
- test_data=unit_test.test_data)
+ def create_unit_test(self, unit_tests):
+ if unit_tests.has_test_data:
+ for i in range(unit_tests.length):
+ unit_test = unit_tests.get_test_unit(i)
+ if unit_test.has_test_data:
+ self.render_class(clazz=unit_test,
+ template='unit_test.java', src_dir="src/test/java",
+ version=unit_test.java_class.version,
+ test=unit_test, msg=unit_test.java_class,
+ test_data=unit_test.test_data)
def create_of_factories(self):
factory = self.java_model.of_factory
diff --git a/java_gen/import_cleaner.py b/java_gen/import_cleaner.py
new file mode 100755
index 0000000..83897d4
--- /dev/null
+++ b/java_gen/import_cleaner.py
@@ -0,0 +1,77 @@
+#!/usr/bin/python
+
+import sys
+import re
+
+class ImportLine:
+ def __init__(self, line):
+ self.line = line
+ class_name = None
+ if line[len(line) - 1] == '*':
+ class_name = '*'
+ else:
+ i = 7
+ while i < len(line) - 1:
+ if re.match('\.[A-Z][\..]*$', line[i - 1 : len(line) - 1]):
+ class_name = line[i : len(line) - 1]
+ break
+ i = i + 1
+ if class_name is None:
+ class_name = line[line.rfind('.') + 1 : len(line) - 1]
+ self.class_name = class_name
+
+
+class ImportCleaner:
+ def __init__(self, path):
+ f = open(path)
+ self.imp_lines = []
+ self.code_lines = []
+ self.imports_first_line = -1
+ i = 0
+ for line in f:
+ if len(line) > 6 and re.match('^[ \t]*import ', line):
+ self.imp_lines.append(ImportLine(line.rstrip()))
+ if self.imports_first_line == -1:
+ self.imports_first_line = i
+ else:
+ self.code_lines.append(line.rstrip())
+ i = i + 1
+ f.close()
+
+ def find_used_imports(self):
+ self.used_imports = []
+ for line in self.code_lines:
+ temp = []
+ for imp in self.imp_lines:
+ if imp.class_name == '*' or line.find(imp.class_name) > -1:
+ temp.append(imp)
+ for x in temp:
+ self.imp_lines.remove(x)
+ self.used_imports.append(x)
+
+ def rewrite_file(self, path):
+ f = open(path, 'w')
+ imports_written = False
+ for i in range(len(self.code_lines)):
+ if not imports_written and self.imports_first_line == i:
+ # Put all imports
+ for imp in self.used_imports:
+ f.write(imp.line + '\n')
+ imports_written = True
+ # Put next code line
+ f.write(self.code_lines[i] + '\n')
+ f.close()
+
+def main(argv):
+ if len(argv) != 2:
+ print 'Usage: ImportCleaner <java file>'
+ return
+
+ filename = argv[1]
+ print 'Cleaning imports from file %s' % (filename)
+ cleaner = ImportCleaner(filename)
+ cleaner.find_used_imports()
+ cleaner.rewrite_file(filename)
+
+if __name__ == '__main__':
+ main(sys.argv)
diff --git a/java_gen/java_model.py b/java_gen/java_model.py
index 0eb8f11..66eeacd 100644
--- a/java_gen/java_model.py
+++ b/java_gen/java_model.py
@@ -215,7 +215,7 @@
self.parent_interface = parent_interface
else:
self.parent_interface = None
-
+
def class_info(self):
""" return tuple of (package_prefix, parent_class) for the current JavaOFInterface"""
# FIXME: This duplicates inheritance information that is now available in the loxi_ir
@@ -330,7 +330,7 @@
@property
@memoize
def unit_test(self):
- return JavaUnitTest(self)
+ return JavaUnitTestSet(self)
@property
def name(self):
@@ -595,18 +595,58 @@
### Unit Test
#######################################################################
-class JavaUnitTest(object):
+class JavaUnitTestSet(object):
def __init__(self, java_class):
self.java_class = java_class
- self.data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
+ first_data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
name=java_class.c_name[3:])
+ data_file_template = "of{version}/{name}.".format(version=java_class.version.of_version,
+ name=java_class.c_name[3:]) + "{i}.data"
+ test_class_name = self.java_class.name + "Test"
+ self.test_units = []
+ if test_data.exists(first_data_file_name):
+ self.test_units.append(JavaUnitTest(java_class, first_data_file_name, test_class_name))
+ i = 1
+ while test_data.exists(data_file_template.format(i=i)):
+ self.test_units.append(JavaUnitTest(java_class, data_file_template.format(i=i), test_class_name + str(i)))
+ i = i + 1
+
+ @property
+ def package(self):
+ return self.java_class.package
+
+ @property
+ def has_test_data(self):
+ return len(self.test_units) > 0
+
+ @property
+ def length(self):
+ return len(self.test_units)
+
+ def get_test_unit(self, i):
+ return self.test_units[i]
+
+
+class JavaUnitTest(object):
+ def __init__(self, java_class, file_name=None, test_class_name=None):
+ self.java_class = java_class
+ if file_name is None:
+ self.data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
+ name=java_class.c_name[3:])
+ else:
+ self.data_file_name = file_name
+ if test_class_name is None:
+ self.test_class_name = self.java_class.name + "Test"
+ else:
+ self.test_class_name = test_class_name
+
@property
def package(self):
return self.java_class.package
@property
def name(self):
- return self.java_class.name + "Test"
+ return self.test_class_name
@property
def has_test_data(self):
diff --git a/java_gen/java_type.py b/java_gen/java_type.py
index cc34a57..0c5de0e 100644
--- a/java_gen/java_type.py
+++ b/java_gen/java_type.py
@@ -1,6 +1,6 @@
+import errno
import loxi_utils.loxi_utils as loxi_utils
import os
-import errno
import re
import subprocess
import time
@@ -262,6 +262,28 @@
.op(read="Wildcards.of(bb.readInt())", write="bb.writeInt($name.getInt())");
transport_port = JType("TransportPort")\
.op(read="TransportPort.read2Bytes(bb)", write="$name.write2Bytes(bb)")
+eth_type = JType("EthType")\
+ .op(read="EthType.read2Bytes(bb)", write="$name.write2Bytes(bb)")
+vlan_vid = JType("VlanVid")\
+ .op(read="VlanVid.read2Bytes(bb)", write="$name.write2Bytes(bb)")
+vlan_pcp = JType("VlanPcp")\
+ .op(read="VlanPcp.readByte(bb)", write="$name.writeByte(bb)")
+ip_dscp = JType("IpDscp")\
+ .op(read="IpDscp.readByte(bb)", write="$name.writeByte(bb)")
+ip_ecn = JType("IpEcn")\
+ .op(read="IpEcn.readByte(bb)", write="$name.writeByte(bb)")
+ip_proto = JType("IpProtocol")\
+ .op(read="IpProtocol.readByte(bb)", write="$name.writeByte(bb)")
+icmpv4_type = JType("ICMPv4Type")\
+ .op(read="ICMPv4Type.readByte(bb)", write="$name.writeByte(bb)")
+icmpv4_code = JType("ICMPv4Code")\
+ .op(read="ICMPv4Code.readByte(bb)", write="$name.writeByte(bb)")
+arp_op = JType("ArpOpcode")\
+ .op(read="ArpOpcode.read2Bytes(bb)", write="$name.write2Bytes(bb)")
+ipv6_flabel = JType("IPv6FlowLabel")\
+ .op(read="IPv6FlowLabel.read4Bytes(bb)", write="$name.write4Bytes(bb)")
+metadata = JType("OFMetadata")\
+ .op(read="OFMetadata.read8Bytes(bb)", write="$name.write8Bytes(bb)")
oxm = JType("OFOxm")\
.op(read="OFOxmVer$version.READER.readFrom(bb)", write="$name.writeTo(bb)")
meter_features = JType("OFMeterFeatures")\
@@ -300,13 +322,45 @@
## Map that defines exceptions from the standard loxi->java mapping scheme
# map of {<loxi_class_name> : { <loxi_member_name> : <JType instance> } }
exceptions = {
- 'of_packet_in': {
- 'data' : octets,
- 'reason': packetin_reason
- },
- 'of_oxm_tcp_src' : {
- 'value' : transport_port
- },
+ 'of_packet_in': { 'data' : octets, 'reason': packetin_reason },
+ 'of_oxm_tcp_src' : { 'value' : transport_port },
+ 'of_oxm_tcp_src_masked' : { 'value' : transport_port, 'value_mask' : transport_port },
+ 'of_oxm_tcp_dst' : { 'value' : transport_port },
+ 'of_oxm_tcp_dst_masked' : { 'value' : transport_port, 'value_mask' : transport_port },
+ 'of_oxm_udp_src' : { 'value' : transport_port },
+ 'of_oxm_udp_src_masked' : { 'value' : transport_port, 'value_mask' : transport_port },
+ 'of_oxm_udp_dst' : { 'value' : transport_port },
+ 'of_oxm_udp_dst_masked' : { 'value' : transport_port, 'value_mask' : transport_port },
+ 'of_oxm_sctp_src' : { 'value' : transport_port },
+ 'of_oxm_sctp_src_masked' : { 'value' : transport_port, 'value_mask' : transport_port },
+ 'of_oxm_sctp_dst' : { 'value' : transport_port },
+ 'of_oxm_sctp_dst_masked' : { 'value' : transport_port, 'value_mask' : transport_port },
+ 'of_oxm_eth_type' : { 'value' : eth_type },
+ 'of_oxm_eth_type_masked' : { 'value' : eth_type, 'value_mask' : eth_type },
+ 'of_oxm_vlan_vid' : { 'value' : vlan_vid },
+ 'of_oxm_vlan_vid_masked' : { 'value' : vlan_vid, 'value_mask' : vlan_vid },
+ 'of_oxm_vlan_pcp' : { 'value' : vlan_pcp },
+ 'of_oxm_vlan_pcp_masked' : { 'value' : vlan_pcp, 'value_mask' : vlan_pcp },
+ 'of_oxm_ip_dscp' : { 'value' : ip_dscp },
+ 'of_oxm_ip_dscp_masked' : { 'value' : ip_dscp, 'value_mask' : ip_dscp },
+ 'of_oxm_ip_ecn' : { 'value' : ip_ecn },
+ 'of_oxm_ip_ecn_masked' : { 'value' : ip_ecn, 'value_mask' : ip_ecn },
+ 'of_oxm_ip_proto' : { 'value' : ip_proto },
+ 'of_oxm_ip_proto_masked' : { 'value' : ip_proto, 'value_mask' : ip_proto },
+ 'of_oxm_icmpv4_type' : { 'value' : icmpv4_type },
+ 'of_oxm_icmpv4_type_masked' : { 'value' : icmpv4_type, 'value_mask' : icmpv4_type },
+ 'of_oxm_icmpv4_code' : { 'value' : icmpv4_code },
+ 'of_oxm_icmpv4_code_masked' : { 'value' : icmpv4_code, 'value_mask' : icmpv4_code },
+ 'of_oxm_arp_op' : { 'value' : arp_op },
+ 'of_oxm_arp_op_masked' : { 'value' : arp_op, 'value_mask' : arp_op },
+ 'of_oxm_arp_spa' : { 'value' : ipv4 },
+ 'of_oxm_arp_spa_masked' : { 'value' : ipv4, 'value_mask' : ipv4 },
+ 'of_oxm_arp_tpa' : { 'value' : ipv4 },
+ 'of_oxm_arp_tpa_masked' : { 'value' : ipv4, 'value_mask' : ipv4 },
+ 'of_oxm_ipv6_flabel' : { 'value' : ipv6_flabel },
+ 'of_oxm_ipv6_flabel_masked' : { 'value' : ipv6_flabel, 'value_mask' : ipv6_flabel },
+ 'of_oxm_metadata' : { 'value' : metadata },
+ 'of_oxm_metadata_masked' : { 'value' : metadata, 'value_mask' : metadata },
}
diff --git a/java_gen/pre-written/src/main/java/org/openflow/protocol/match/Match.java b/java_gen/pre-written/src/main/java/org/openflow/protocol/match/Match.java
index d35f709..8f17845 100644
--- a/java_gen/pre-written/src/main/java/org/openflow/protocol/match/Match.java
+++ b/java_gen/pre-written/src/main/java/org/openflow/protocol/match/Match.java
@@ -4,89 +4,190 @@
import org.openflow.types.Masked;
import org.openflow.types.OFValueType;
-public interface Match extends OFObject {
-
- /*
- * Preconditions
- * On preconditions (from the OF1.1 spec, page 28, the OF1.0 spec failed to explicitly
- * specify this, but it is the behavior of Of1.0 switches):
- * Protocol-specific fields within ofp_match will be ignored within a single table when
- * the corresponding protocol is not specified in the match. The MPLS match fields will
- * 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
- * and should be set to 0.
- */
+/**
+ * Generic interface for version-agnostic immutable Match structure.
+ * The Match structure is defined in the OpenFlow protocol, and it contains information on
+ * the fields to be matched in a specific flow record.
+ * This interface does not assume anything on the fields in the Match structure. If in
+ * some version, the match structure cannot handle a certain field, it may return <code>false</code>
+ * for <code>supports(...)</code> calls, and throw <code>UnsupportedOperationException</code> from all
+ * other methods in such cases.
+ * <br><br>
+ * On wildcards and masks:<br>
+ * This interface defines the following masking notations for fields:
+ * <ul>
+ * <li><b>Exact</b>: field is matched exactly against a single, fixed value (no mask, or mask is all ones).
+ * <li><b>Wildcarded</b>: field is not being matched. It is fully masked (mask=0) and any value of it
+ * will match the flow record having this match.
+ * <li><b>Partially masked</b>: field is matched using a specified mask which is neither 0 nor all ones. Mask can
+ * be either arbitrary or require some specific structure.
+ * </ul>
+ * Implementing classes may or may not support all types of these masking types. They may also support
+ * 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
+ * which is not IP source/destination address.
+ * <br><br>
+ * On prerequisites:<br>
+ * From the OF1.1 spec, page 28, the OF1.0 spec failed to explicitly specify this, but it
+ * is the behavior of OF1.0 switches:
+ * "Protocol-specific fields within ofp_match will be ignored within a single table when
+ * the corresponding protocol is not specified in the match. The MPLS match fields will
+ * 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
+ * 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
+ * 'unchecked cast' warnings while making sure they correctly cast base on their implementation details.
+ *
+ * @author Yotam Harchol (yotam.harchol@bigswitch.com)
+ */
+public interface Match extends OFObject {
/**
- * Returns the value for the given field from this match.
- *
+ * Returns a value for the given field if:
+ * <ul>
+ * <li>Field is supported
+ * <li>Field is not fully wildcarded
+ * <li>Prerequisites are ok
+ * </ul>
+ * If one of the above conditions does not hold, returns null. Value is returned masked if partially wildcarded.
+ *
* @param field Match field to retrieve
- * @return Value of match field
+ * @return Value of match field (may be masked), or <code>null</code> if field is one of the conditions above does not hold.
+ * @throws UnsupportedOperationException If field is not supported.
*/
public <F extends OFValueType<F>> F get(MatchField<F> field) throws UnsupportedOperationException;
/**
- * Returns the masked value for the given field from this match.
- * Precondition: field is partially wildcarded.
- *
- * @param field Match field to retrieve
- * @return Masked value of match field or null if no mask
+ * Returns the masked value for the given field from this match, along with the mask itself.
+ * Prerequisite: field is partially masked.
+ * If prerequisite is not met, a <code>null</code> is returned.
+ *
+ * @param field Match field to retrieve.
+ * @return Masked value of match field or null if no mask is set.
+ * @throws UnsupportedOperationException If field is not supported.
*/
public <F extends OFValueType<F>> Masked<F> getMasked(MatchField<F> field) throws UnsupportedOperationException;
/**
- * Returns true if this match object supports the given match field.
- *
+ * Returns true if and only if this match object supports the given match field.
+ *
* @param field Match field
- * @return
+ * @return true if field is supported, false otherwise.
*/
public boolean supports(MatchField<?> field);
/**
- * true iff field supports a bitmask mask that wildcards part of the field
+ * Returns true if and only if this match object supports partially bitmasking of the given field.
* (note: not all possible values of this bitmask have to be acceptable)
- *
- * @param field Match field
- * @return
+ *
+ * @param field Match field.
+ * @return true if field can be partially masked, false otherwise.
+ * @throws UnsupportedOperationException If field is not supported.
*/
- public boolean supportsMasked(MatchField<?> field);
+ public boolean supportsMasked(MatchField<?> field) throws UnsupportedOperationException;
/**
- * True iff this field is currently fully specified in the match, i.e., the
- * match will only select packets that match the exact value of getField(field).
- *
- * @param field Match field
- * @return
+ * Returns true if and only if this field is currently specified in the match with an exact value and
+ * no mask. I.e., the specified match will only select packets that match the exact value of getValue(field).
+ *
+ * @param field Match field.
+ * @return true if field has a specific exact value, false if not.
+ * @throws UnsupportedOperationException If field is not supported.
*/
- public boolean isExact(MatchField<?> field);
+ public boolean isExact(MatchField<?> field) throws UnsupportedOperationException;
/**
- * True if this field is currently logically unspecified in the match, i.e, the
- * value returned by getValue(f) has no impact on whether a packet will be selected
+ * True if and only if this field is currently logically unspecified in the match, i.e, the
+ * value returned by getValue(f) has no impact on whether a packet will be selected
* by the match or not.
- *
- * @param field
- * @return
+ *
+ * @param field Match field.
+ * @return true if field is fully wildcarded, false if not.
+ * @throws UnsupportedOperationException If field is not supported.
*/
- public boolean isFullyWildcarded(MatchField<?> field);
+ public boolean isFullyWildcarded(MatchField<?> field) throws UnsupportedOperationException;
/**
- * True if this field is currently partially specified in the match, i.e, the
- * match will select packets that match (p.value & getMask(field)) == getValue(field).
- *
- * @param field
- * @return
+ * True if and only if this field is currently partially specified in the match, i.e, the
+ * match will only select packets that match (p.value & getMask(field)) == getValue(field),
+ * and getMask(field) != 0.
+ *
+ * @param field Match field.
+ * @return true if field is partially masked, false if not.
+ * @throws UnsupportedOperationException If field is not supported.
*/
- public boolean isPartiallyMasked(MatchField<?> field);
-
+ public boolean isPartiallyMasked(MatchField<?> field) throws UnsupportedOperationException;
+
/**
* Returns a builder to build new instances of this type of match object.
* @return Match builder
*/
- public MatchBuilder createBuilder();
+ public Builder createBuilder();
- interface Builder extends MatchBuilder {
+ /**
+ * Builder interface for Match objects.
+ * Builder is used to create new Match objects and it creates the match according to the version it
+ * corresponds to. The builder uses the same notation of wildcards and masks, and can also throw
+ * <code>UnsupportedOperationException</code> if it is asked to create some matching that is not supported in
+ * the version it represents.
+ *
+ * While used, MatchBuilder may not be consistent in terms of field prerequisites. However, user must
+ * solve these before using the generated Match object as these prerequisites should be enforced in the
+ * getters.
+ *
+ * @author Yotam Harchol (yotam.harchol@bigswitch.com)
+ */
+ interface Builder extends Match {
+ /**
+ * Sets a specific exact value for a field.
+ *
+ * @param field Match field to set.
+ * @param value Value of match field.
+ * @return the Builder instance used.
+ * @throws UnsupportedOperationException If field is not supported.
+ */
+ public <F extends OFValueType<F>> Builder setExact(MatchField<F> field, F value) throws UnsupportedOperationException;
+
+ /**
+ * Sets a masked value for a field.
+ *
+ * @param field Match field to set.
+ * @param value Value of field.
+ * @param mask Mask value.
+ * @return the Builder instance used.
+ * @throws UnsupportedOperationException If field is not supported, if field is supported but does not support masking, or if mask structure is not supported.
+ */
+ public <F extends OFValueType<F>> Builder setMasked(MatchField<F> field, F value, F mask) throws UnsupportedOperationException;
+
+ /**
+ * Sets a masked value for a field.
+ *
+ * @param field Match field to set.
+ * @param valueWithMask Compound Masked object contains the value and the mask.
+ * @return the Builder instance used.
+ * @throws UnsupportedOperationException If field is not supported, if field is supported but does not support masking, or if mask structure is not supported.
+ */
+ public <F extends OFValueType<F>> Builder setMasked(MatchField<F> field, Masked<F> valueWithMask) throws UnsupportedOperationException;
+
+ /**
+ * Unsets any value given for the field and wildcards it so that it matches any value.
+ *
+ * @param field Match field to unset.
+ * @return the Builder instance used.
+ * @throws UnsupportedOperationException If field is not supported.
+ */
+ public <F extends OFValueType<F>> Builder wildcard(MatchField<F> field) throws UnsupportedOperationException;
+
+ /**
+ * Returns the match created by this builder.
+ *
+ * @return a Match object.
+ */
+ public Match getMatch();
}
-}
+}
\ No newline at end of file
diff --git a/java_gen/pre-written/src/main/java/org/openflow/protocol/match/MatchBuilder.java b/java_gen/pre-written/src/main/java/org/openflow/protocol/match/MatchBuilder.java
deleted file mode 100644
index be7b8b0..0000000
--- a/java_gen/pre-written/src/main/java/org/openflow/protocol/match/MatchBuilder.java
+++ /dev/null
@@ -1,79 +0,0 @@
-package org.openflow.protocol.match;
-
-import org.openflow.types.Masked;
-import org.openflow.types.OFValueType;
-
-public interface MatchBuilder {
- /**
- * Returns the value for the given field from this match.
- *
- * @param field Match field to retrieve
- * @return Value of match field
- */
- public <F extends OFValueType<F>> F get(MatchField<F> field) throws UnsupportedOperationException;
-
- /**
- * Returns the masked value for the given field from this match.
- * Precondition: field is partially wildcarded.
- *
- * @param field Match field to retrieve
- * @return Masked value of match field or null if no mask
- */
- public <F extends OFValueType<F>> Masked<F> getMasked(MatchField<F> field) throws UnsupportedOperationException;
-
- /**
- * Returns true if this match object supports the given match field.
- *
- * @param field Match field
- * @return
- */
- public boolean supports(MatchField<?> field);
-
- /**
- * true iff field supports a bitmask mask that wildcards part of the field
- * (note: not all possible values of this bitmask have to be acceptable)
- *
- * @param field Match field
- * @return
- */
- public boolean supportsMasked(MatchField<?> field);
-
- /**
- * True iff this field is currently fully specified in the match, i.e., the
- * match will only select packets that match the exact value of getField(field).
- *
- * @param field Match field
- * @return
- */
- public boolean isExact(MatchField<?> field);
-
- /**
- * True if this field is currently logically unspecified in the match, i.e, the
- * value returned by getValue(f) has no impact on whether a packet will be selected
- * by the match or not.
- *
- * @param field
- * @return
- */
- public boolean isFullyWildcarded(MatchField<?> field);
-
- /**
- * True if this field is currently partially specified in the match, i.e, the
- * match will select packets that match (p.value & getMask(field)) == getValue(field).
- *
- * @param field
- * @return
- */
- public boolean isPartiallyMasked(MatchField<?> field);
-
-
- public <F extends OFValueType<F>> MatchBuilder setExact(MatchField<F> field, F value);
-
- public <F extends OFValueType<F>> MatchBuilder setMasked(MatchField<F> field, F value, F mask);
-
- public <F extends OFValueType<F>> MatchBuilder setMasked(MatchField<F> field, Masked<F> valueWithMask);
-
- public <F extends OFValueType<F>> MatchBuilder wildcard(MatchField<F> field);
-
- public Match getMatch();
-}
diff --git a/java_gen/pre-written/src/main/java/org/openflow/protocol/match/MatchField.java b/java_gen/pre-written/src/main/java/org/openflow/protocol/match/MatchField.java
index 4d4935c..5913658 100644
--- a/java_gen/pre-written/src/main/java/org/openflow/protocol/match/MatchField.java
+++ b/java_gen/pre-written/src/main/java/org/openflow/protocol/match/MatchField.java
@@ -11,30 +11,38 @@
import org.openflow.types.IpEcn;
import org.openflow.types.IpProtocol;
import org.openflow.types.MacAddress;
+import org.openflow.types.OFMetadata;
import org.openflow.types.OFPort;
import org.openflow.types.OFValueType;
import org.openflow.types.TransportPort;
import org.openflow.types.VlanPcp;
import org.openflow.types.VlanVid;
+@SuppressWarnings("unchecked")
public class MatchField<F extends OFValueType<F>> {
private final String name;
public final MatchFields id;
+ private final Prerequisite<?>[] prerequisites;
- private MatchField(final String name, final MatchFields id) {
+ private MatchField(final String name, final MatchFields id, Prerequisite<?>... prerequisites) {
this.name = name;
this.id = id;
+ this.prerequisites = prerequisites;
}
public final static MatchField<OFPort> IN_PORT =
new MatchField<OFPort>("in_port", MatchFields.IN_PORT);
+
public final static MatchField<OFPort> IN_PHY_PORT =
- new MatchField<OFPort>("in_phy_port", MatchFields.PHYSICAL_PORT);
- public final static MatchField<OFPort> METADATA =
- new MatchField<OFPort>("metadata", MatchFields.METADATA);
+ new MatchField<OFPort>("in_phy_port", MatchFields.PHYSICAL_PORT,
+ new Prerequisite<OFPort>(MatchField.IN_PORT));
+
+ public final static MatchField<OFMetadata> METADATA =
+ new MatchField<OFMetadata>("metadata", MatchFields.METADATA);
public final static MatchField<MacAddress> ETH_DST =
new MatchField<MacAddress>("eth_dst", MatchFields.ETH_DST);
+
public final static MatchField<MacAddress> ETH_SRC =
new MatchField<MacAddress>("eth_src", MatchFields.ETH_SRC);
@@ -43,63 +51,106 @@
public final static MatchField<VlanVid> VLAN_VID =
new MatchField<VlanVid>("vlan_vid", MatchFields.VLAN_VID);
- public final static MatchField<VlanPcp> VLAN_PCP =
- new MatchField<VlanPcp>("vlan_pcp", MatchFields.VLAN_PCP);
+ public final static MatchField<VlanPcp> VLAN_PCP =
+ new MatchField<VlanPcp>("vlan_pcp", MatchFields.VLAN_PCP,
+ new Prerequisite<VlanVid>(MatchField.VLAN_VID));
public final static MatchField<IpDscp> IP_DSCP =
- new MatchField<IpDscp>("ip_dscp", MatchFields.IP_DSCP);
+ new MatchField<IpDscp>("ip_dscp", MatchFields.IP_DSCP,
+ new Prerequisite<EthType>(MatchField.ETH_TYPE, EthType.ETH_TYPE_IPv4, EthType.ETH_TYPE_IPv6));
+
public final static MatchField<IpEcn> IP_ECN =
- new MatchField<IpEcn>("ip_dscp", MatchFields.IP_ECN);
+ new MatchField<IpEcn>("ip_dscp", MatchFields.IP_ECN,
+ new Prerequisite<EthType>(MatchField.ETH_TYPE, EthType.ETH_TYPE_IPv4, EthType.ETH_TYPE_IPv6));
+
public final static MatchField<IpProtocol> IP_PROTO =
- new MatchField<IpProtocol>("ip_proto", MatchFields.IP_PROTO);
+ new MatchField<IpProtocol>("ip_proto", MatchFields.IP_PROTO,
+ new Prerequisite<EthType>(MatchField.ETH_TYPE, EthType.ETH_TYPE_IPv4, EthType.ETH_TYPE_IPv6));
public final static MatchField<IPv4> IPV4_SRC =
- new MatchField<IPv4>("ipv4_src", MatchFields.IPV4_SRC);
+ new MatchField<IPv4>("ipv4_src", MatchFields.IPV4_SRC,
+ new Prerequisite<EthType>(MatchField.ETH_TYPE, EthType.ETH_TYPE_IPv4));
+
public final static MatchField<IPv4> IPV4_DST =
- new MatchField<IPv4>("ipv4_dst", MatchFields.IPV4_DST);
+ new MatchField<IPv4>("ipv4_dst", MatchFields.IPV4_DST,
+ new Prerequisite<EthType>(MatchField.ETH_TYPE, EthType.ETH_TYPE_IPv4));
public final static MatchField<TransportPort> TCP_SRC = new MatchField<TransportPort>(
- "tcp_src", MatchFields.TCP_SRC);
+ "tcp_src", MatchFields.TCP_SRC,
+ new Prerequisite<IpProtocol>(MatchField.IP_PROTO, IpProtocol.IP_PROTO_TCP));
+
public final static MatchField<TransportPort> TCP_DST = new MatchField<TransportPort>(
- "tcp_dst", MatchFields.TCP_DST);
+ "tcp_dst", MatchFields.TCP_DST,
+ new Prerequisite<IpProtocol>(MatchField.IP_PROTO, IpProtocol.IP_PROTO_TCP));
public final static MatchField<TransportPort> UDP_SRC = new MatchField<TransportPort>(
- "udp_src", MatchFields.UDP_SRC);
+ "udp_src", MatchFields.UDP_SRC,
+ new Prerequisite<IpProtocol>(MatchField.IP_PROTO, IpProtocol.IP_PROTO_UDP));
+
public final static MatchField<TransportPort> UDP_DST = new MatchField<TransportPort>(
- "udp_dst", MatchFields.UDP_DST);
+ "udp_dst", MatchFields.UDP_DST,
+ new Prerequisite<IpProtocol>(MatchField.IP_PROTO, IpProtocol.IP_PROTO_UDP));
public final static MatchField<TransportPort> SCTP_SRC = new MatchField<TransportPort>(
- "sctp_src", MatchFields.SCTP_SRC);
+ "sctp_src", MatchFields.SCTP_SRC,
+ new Prerequisite<IpProtocol>(MatchField.IP_PROTO, IpProtocol.IP_PROTO_SCTP));
+
public final static MatchField<TransportPort> SCTP_DST = new MatchField<TransportPort>(
- "sctp_dst", MatchFields.SCTP_DST);
+ "sctp_dst", MatchFields.SCTP_DST,
+ new Prerequisite<IpProtocol>(MatchField.IP_PROTO, IpProtocol.IP_PROTO_SCTP));
public final static MatchField<ICMPv4Type> ICMPV4_TYPE = new MatchField<ICMPv4Type>(
- "icmpv4_src", MatchFields.ICMPV4_TYPE);
+ "icmpv4_src", MatchFields.ICMPV4_TYPE,
+ new Prerequisite<IpProtocol>(MatchField.IP_PROTO, IpProtocol.IP_PROTO_ICMP));
+
public final static MatchField<ICMPv4Code> ICMPV4_CODE = new MatchField<ICMPv4Code>(
- "icmpv4_dst", MatchFields.ICMPV4_CODE);
+ "icmpv4_dst", MatchFields.ICMPV4_CODE,
+ new Prerequisite<IpProtocol>(MatchField.IP_PROTO, IpProtocol.IP_PROTO_ICMP));
public final static MatchField<ArpOpcode> ARP_OP = new MatchField<ArpOpcode>(
- "arp_op", MatchFields.ARP_OP);
+ "arp_op", MatchFields.ARP_OP,
+ new Prerequisite<EthType>(MatchField.ETH_TYPE, EthType.ETH_TYPE_ARP));
+
public final static MatchField<IPv4> ARP_SPA =
- new MatchField<IPv4>("arp_spa", MatchFields.ARP_SPA);
+ new MatchField<IPv4>("arp_spa", MatchFields.ARP_SPA,
+ new Prerequisite<EthType>(MatchField.ETH_TYPE, EthType.ETH_TYPE_ARP));
+
public final static MatchField<IPv4> ARP_TPA =
- new MatchField<IPv4>("arp_tpa", MatchFields.ARP_TPA);
+ new MatchField<IPv4>("arp_tpa", MatchFields.ARP_TPA,
+ new Prerequisite<EthType>(MatchField.ETH_TYPE, EthType.ETH_TYPE_ARP));
+
public final static MatchField<MacAddress> ARP_SHA =
- new MatchField<MacAddress>("arp_sha", MatchFields.ARP_SHA);
+ new MatchField<MacAddress>("arp_sha", MatchFields.ARP_SHA,
+ new Prerequisite<EthType>(MatchField.ETH_TYPE, EthType.ETH_TYPE_ARP));
+
public final static MatchField<MacAddress> ARP_THA =
- new MatchField<MacAddress>("arp_tha", MatchFields.ARP_THA);
+ new MatchField<MacAddress>("arp_tha", MatchFields.ARP_THA,
+ new Prerequisite<EthType>(MatchField.ETH_TYPE, EthType.ETH_TYPE_ARP));
public final static MatchField<IPv6> IPV6_SRC =
- new MatchField<IPv6>("ipv6_src", MatchFields.IPV6_SRC);
+ new MatchField<IPv6>("ipv6_src", MatchFields.IPV6_SRC,
+ new Prerequisite<EthType>(MatchField.ETH_TYPE, EthType.ETH_TYPE_IPv6));
+
public final static MatchField<IPv6> IPV6_DST =
- new MatchField<IPv6>("ipv6_dst", MatchFields.IPV6_DST);
+ new MatchField<IPv6>("ipv6_dst", MatchFields.IPV6_DST,
+ new Prerequisite<EthType>(MatchField.ETH_TYPE, EthType.ETH_TYPE_IPv6));
public final static MatchField<IPv6FlowLabel> IPV6_FLABEL =
- new MatchField<IPv6FlowLabel>("ipv6_flabel", MatchFields.IPV6_FLOWLABEL);
+ new MatchField<IPv6FlowLabel>("ipv6_flabel", MatchFields.IPV6_FLOWLABEL,
+ new Prerequisite<EthType>(MatchField.ETH_TYPE, EthType.ETH_TYPE_IPv6));
public String getName() {
return name;
}
+
+ public boolean arePrerequisitesOK(Match match) {
+ for (Prerequisite<?> p : this.prerequisites) {
+ if (!p.isStaisfied(match)) {
+ return false;
+ }
+ }
+ return true;
+ }
}
diff --git a/java_gen/pre-written/src/main/java/org/openflow/protocol/match/MatchFields.java b/java_gen/pre-written/src/main/java/org/openflow/protocol/match/MatchFields.java
index 21043f2..309f91f 100644
--- a/java_gen/pre-written/src/main/java/org/openflow/protocol/match/MatchFields.java
+++ b/java_gen/pre-written/src/main/java/org/openflow/protocol/match/MatchFields.java
@@ -1,5 +1,6 @@
package org.openflow.protocol.match;
+// MUST BE ORDERED BY THE ORDER OF OF SPEC!!!
public enum MatchFields {
IN_PORT,
PHYSICAL_PORT,
diff --git a/java_gen/pre-written/src/main/java/org/openflow/protocol/match/Prerequisite.java b/java_gen/pre-written/src/main/java/org/openflow/protocol/match/Prerequisite.java
new file mode 100644
index 0000000..f518925
--- /dev/null
+++ b/java_gen/pre-written/src/main/java/org/openflow/protocol/match/Prerequisite.java
@@ -0,0 +1,44 @@
+package org.openflow.protocol.match;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.openflow.types.OFValueType;
+
+public class Prerequisite<T extends OFValueType<T>> {
+ private MatchField<T> field;
+ private Set<OFValueType<T>> values;
+ private boolean any;
+
+ public Prerequisite(MatchField<T> field, OFValueType<T>... values) {
+ this.values = new HashSet<OFValueType<T>>();
+ this.field = field;
+ if (values == null || values.length == 0) {
+ this.any = true;
+ } else {
+ this.any = false;
+ for (OFValueType<T> value : values) {
+ this.values.add(value);
+ }
+ }
+ }
+
+ /**
+ * Returns true if this prerequisite is satisfied by the given match object.
+ *
+ * @param match Match object
+ * @return true iff prerequisite is satisfied.
+ */
+ public boolean isStaisfied(Match match) {
+ OFValueType<T> res = match.get(this.field);
+ if (res == null)
+ return false;
+ if (this.any)
+ return true;
+ if (this.values.contains(res)) {
+ return true;
+ }
+ return false;
+ }
+
+}
diff --git a/java_gen/pre-written/src/main/java/org/openflow/types/IPv4WithMask.java b/java_gen/pre-written/src/main/java/org/openflow/types/IPv4WithMask.java
index c24c4fd..0a1a6d3 100644
--- a/java_gen/pre-written/src/main/java/org/openflow/types/IPv4WithMask.java
+++ b/java_gen/pre-written/src/main/java/org/openflow/types/IPv4WithMask.java
@@ -36,7 +36,7 @@
return res.toString();
}
- public static OFValueType<?> ofPossiblyMasked(final String string) {
+ public static IPv4WithMask of(final String string) {
int slashPos;
String ip = string;
int maskBits = 0;
@@ -72,7 +72,7 @@
return IPv4WithMask.of(ipv4, maskAddress);
} else if (maskBits == 0) {
// No mask
- return ipv4;
+ return IPv4WithMask.of(ipv4, IPv4.of(0xFFFFFFFF));
} else {
// With mask
int mask = (-1) << (32 - maskBits);
diff --git a/java_gen/pre-written/src/main/java/org/openflow/types/IPv6WithMask.java b/java_gen/pre-written/src/main/java/org/openflow/types/IPv6WithMask.java
index 72319e3..453507a 100644
--- a/java_gen/pre-written/src/main/java/org/openflow/types/IPv6WithMask.java
+++ b/java_gen/pre-written/src/main/java/org/openflow/types/IPv6WithMask.java
@@ -31,7 +31,7 @@
return res.toString();
}
- public static OFValueType<?> ofPossiblyMasked(final String string) {
+ public static IPv6WithMask of(final String string) {
int slashPos;
String ip = string;
int maskBits = 0;
@@ -67,7 +67,7 @@
return IPv6WithMask.of(ipv6, maskAddress);
} else if (maskBits == 0) {
// No mask
- return ipv6;
+ return IPv6WithMask.of(ipv6, IPv6.of(0xFFFFFFFFFFFFFFFFl, 0xFFFFFFFFFFFFFFFFl));
} else {
// With mask
BigInteger mask = BigInteger.ONE.negate().shiftLeft(128 - maskBits);
diff --git a/java_gen/pre-written/src/main/java/org/openflow/types/OFMetadata.java b/java_gen/pre-written/src/main/java/org/openflow/types/OFMetadata.java
new file mode 100644
index 0000000..83d02da
--- /dev/null
+++ b/java_gen/pre-written/src/main/java/org/openflow/types/OFMetadata.java
@@ -0,0 +1,34 @@
+package org.openflow.types;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+public class OFMetadata extends U64 implements OFValueType<OFMetadata> {
+
+ private static int LENGTH = 8;
+
+ protected OFMetadata(long raw) {
+ super(raw);
+ }
+
+ public static OFMetadata of(long raw) {
+ return new OFMetadata(raw);
+ }
+
+ public static OFMetadata read8Bytes(ChannelBuffer cb) {
+ return OFMetadata.of(cb.readLong());
+ }
+
+ public void write8Bytes(ChannelBuffer cb) {
+ cb.writeLong(super.getValue());
+ }
+
+ @Override
+ public int getLength() {
+ return LENGTH;
+ }
+
+ @Override
+ public OFMetadata applyMask(OFMetadata mask) {
+ return OFMetadata.of(this.getValue() & mask.getValue());
+ }
+}
diff --git a/java_gen/pre-written/src/main/java/org/openflow/types/U64.java b/java_gen/pre-written/src/main/java/org/openflow/types/U64.java
index 750398f..7871445 100644
--- a/java_gen/pre-written/src/main/java/org/openflow/types/U64.java
+++ b/java_gen/pre-written/src/main/java/org/openflow/types/U64.java
@@ -24,7 +24,7 @@
private final long raw;
- private U64(final long raw) {
+ protected U64(final long raw) {
this.raw = raw;
}
diff --git a/java_gen/pre-written/src/main/java/org/openflow/types/VlanVid.java b/java_gen/pre-written/src/main/java/org/openflow/types/VlanVid.java
index ca2c3c2..e36a5dd 100644
--- a/java_gen/pre-written/src/main/java/org/openflow/types/VlanVid.java
+++ b/java_gen/pre-written/src/main/java/org/openflow/types/VlanVid.java
@@ -70,7 +70,7 @@
c.writeShort(this.vid);
}
- public VlanVid read2Bytes(ChannelBuffer c) throws OFParseError {
+ public static VlanVid read2Bytes(ChannelBuffer c) throws OFParseError {
return VlanVid.of(c.readShort());
}
diff --git a/java_gen/pre-written/src/test/java/org/openflow/types/IPv4Test.java b/java_gen/pre-written/src/test/java/org/openflow/types/IPv4Test.java
index d344021..a5ac1be 100644
--- a/java_gen/pre-written/src/test/java/org/openflow/types/IPv4Test.java
+++ b/java_gen/pre-written/src/test/java/org/openflow/types/IPv4Test.java
@@ -108,29 +108,23 @@
}
}
- @SuppressWarnings("unchecked")
@Test
- public void testOfPossiblyMasked() throws OFParseError, OFShortRead {
+ public void testOfMasked() throws OFParseError, OFShortRead {
for (int i = 0; i < ipsWithMask.length; i++) {
- OFValueType value = IPv4WithMask.ofPossiblyMasked(ipsWithMask[i]);
- if (value instanceof IPv4 && !hasMask[i]) {
- // Types OK, check values
- IPv4 ip = (IPv4)value;
+ IPv4WithMask value = IPv4WithMask.of(ipsWithMask[i]);
+ if (!hasMask[i]) {
+ IPv4 ip = value.getValue();
assertArrayEquals(ipsWithMaskValues[i][0], ip.getBytes());
- } else if (value instanceof Masked && hasMask[i]) {
- Masked<IPv4> ip = null;
- try {
- ip = (Masked<IPv4>)value;
- } catch (ClassCastException e) {
- fail("Invalid Masked<T> type.");
+ } else if (hasMask[i]) {
+ byte[] ipBytes = new byte[4];
+ System.arraycopy(ipsWithMaskValues[i][0], 0, ipBytes, 0, 4);
+ assertEquals(ipBytes.length, value.getValue().getBytes().length);
+ for (int j = 0; j < ipBytes.length; j++) {
+ ipBytes[j] &= ipsWithMaskValues[i][1][j];
}
- // Types OK, check values
- assertArrayEquals(ipsWithMaskValues[i][0], ip.getValue().getBytes());
- assertArrayEquals(ipsWithMaskValues[i][1], ip.getMask().getBytes());
- } else if (value instanceof IPv4) {
- fail("Expected masked IPv4, got unmasked IPv4.");
- } else {
- fail("Expected unmasked IPv4, got masked IPv4.");
+
+ assertArrayEquals(ipBytes, value.getValue().getBytes());
+ assertArrayEquals(ipsWithMaskValues[i][1], value.getMask().getBytes());
}
}
}
diff --git a/java_gen/pre-written/src/test/java/org/openflow/types/IPv6Test.java b/java_gen/pre-written/src/test/java/org/openflow/types/IPv6Test.java
index f2f6fe8..71ab28e 100644
--- a/java_gen/pre-written/src/test/java/org/openflow/types/IPv6Test.java
+++ b/java_gen/pre-written/src/test/java/org/openflow/types/IPv6Test.java
@@ -58,31 +58,25 @@
@Test
public void testMasked() throws UnknownHostException {
for(int i=0; i < ipsWithMask.length; i++ ) {
- OFValueType value = IPv6WithMask.ofPossiblyMasked(ipsWithMask[i]);
- if (value instanceof IPv6 && !hasMask[i]) {
- // Types OK, check values
- IPv6 ip = (IPv6)value;
+ IPv6WithMask value = IPv6WithMask.of(ipsWithMask[i]);
+ if (!hasMask[i]) {
+ IPv6 ip = value.getValue();
InetAddress inetAddress = InetAddress.getByName(ipsWithMask[i]);
assertArrayEquals(ip.getBytes(), inetAddress.getAddress());
assertEquals(ipsWithMask[i], ip.toString());
} else if (value instanceof IPv6WithMask && hasMask[i]) {
- IPv6WithMask ip = null;
- try {
- ip = (IPv6WithMask)value;
- } catch (ClassCastException e) {
- fail("Invalid Masked<T> type.");
- }
- // Types OK, check values
InetAddress inetAddress = InetAddress.getByName(ipsWithMask[i].substring(0, ipsWithMask[i].indexOf('/')));
- assertArrayEquals(ip.value.getBytes(), inetAddress.getAddress());
- assertEquals(ipsWithMask[i].substring(0, ipsWithMask[i].indexOf('/')), ip.value.toString());
- assertArrayEquals(masks[i], ip.mask.getBytes());
- } else if (value instanceof IPv6) {
- fail("Expected masked IPv6, got unmasked IPv6.");
- } else {
- fail("Expected unmasked IPv6, got masked IPv6.");
+ byte[] address = inetAddress.getAddress();
+ assertEquals(address.length, value.getValue().getBytes().length);
+
+ for (int j = 0; j < address.length; j++) {
+ address[j] &= masks[i][j];
+ }
+
+ assertArrayEquals(value.getValue().getBytes(), address);
+ assertArrayEquals(masks[i], value.getMask().getBytes());
}
}
}