Merge into master from pull request #102:
Java gen: fix alignment for action set_field, add java_gen unit tests for actions (https://github.com/floodlight/loxigen/pull/102)
diff --git a/java_gen/java_model.py b/java_gen/java_model.py
index f2191c0..feb3c72 100644
--- a/java_gen/java_model.py
+++ b/java_gen/java_model.py
@@ -773,6 +773,10 @@
return int(self.ir_class.params['align']) if 'align' in self.ir_class.params else 0
@property
+ def length_includes_align(self):
+ return self.ir_class.params['length_includes_align'] == "True" if 'length_includes_align' in self.ir_class.params else False
+
+ @property
@memoize
def superclass(self):
return find(lambda c: c.version == self.version and c.c_name == self.ir_class.superclass, model.all_classes)
@@ -1001,16 +1005,23 @@
self.java_class = java_class
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"
+ glob_file_name = "of{version}/{name}__*.data".format(version=java_class.version.of_version,
+ name=java_class.c_name[3:])
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
+ for f in test_data.glob(glob_file_name):
+ m = re.match(".*__(.*).data", f)
+ if m:
+ suffix = java_type.name_c_to_caps_camel(m.group(1))
+ else:
+ suffix = str(i)
+ i += 1
+ test_class_name = self.java_class.name + suffix + "Test"
+ self.test_units.append(JavaUnitTest(java_class, f, test_class_name))
@property
def package(self):
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFGroup.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFGroup.java
index d522202..b05d5fa 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFGroup.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFGroup.java
@@ -25,32 +25,25 @@
private static final int ANY_VAL = 0xffffffff;
- // ////////////// public constants - use to access well known OpenFlow ports
+ // ////////////// public constants - use to access well known OpenFlow group constants
- /** Maximum number of physical and logical switch ports. */
+ /** Maximum number of physical and logical switch groups. */
public final static OFGroup MAX = new NamedGroup(MAX_VAL, "max");
- /**
- * Send the packet out the input port. This reserved port must be explicitly
- * used in order to send back out of the input port.
- */
+ /** All groups */
public final static OFGroup ALL = new NamedGroup(ALL_VAL, "all");
/**
- * Wildcard group used only for flow mod (delete) and flow stats requests.
- * Selects all flows regardless of output port (including flows with no
- * output port). NOTE: OpenFlow 1.0 calls this 'NONE'
- */
+ * Wildcard group used only for flow mod (delete) and flow stats requests. */
public final static OFGroup ANY = new NamedGroup(ANY_VAL, "any");
- /** group 0 in case we need it
- */
+ /** group 0 in case we need it */
public static final OFGroup ZERO = OFGroup.of(ZERO_VAL);
public static final OFGroup NO_MASK = ANY;
public static final OFGroup FULL_MASK = ZERO;
- /** raw openflow port number as a signed 32 bit integer */
+ /** raw openflow group number as a signed 32 bit integer */
private final int groupNumber;
/** private constructor. use of*-Factory methods instead */
@@ -59,11 +52,11 @@
}
/**
- * get an OFPort object corresponding to a raw 32-bit integer port number.
- * NOTE: The port object may either be newly allocated or cached. Do not
+ * get an OFGroup object corresponding to a raw 32-bit integer group number.
+ * NOTE: The group object may either be newly allocated or cached. Do not
* rely on either behavior.
*
- * @param portNumber
+ * @param groupNumber the raw 32-bit group number
* @return a corresponding OFPort
*/
public static OFGroup of(final int groupNumber) {
@@ -86,7 +79,7 @@
}
}
- /** return the port number as a int32 */
+ /** return the group number as a int32 */
public int getGroupNumber() {
return groupNumber;
}
@@ -96,7 +89,7 @@
return UnsignedInts.toString(groupNumber);
}
- /** Extension of OFPort for named groups */
+ /** Extension of OFGroup for named groups */
static class NamedGroup extends OFGroup {
private final String name;
diff --git a/java_gen/templates/of_class.java b/java_gen/templates/of_class.java
index ef927fd..7b3b762 100644
--- a/java_gen/templates/of_class.java
+++ b/java_gen/templates/of_class.java
@@ -229,9 +229,14 @@
//:: #endif
//:: #endfor
//:: if msg.align:
- // align message to ${msg.align} bytes
+ //:: if msg.length_includes_align:
+ // align message to ${msg.align} bytes (length contains aligned value)
+ bb.skipBytes(length - (bb.readerIndex() - start));
+ //:: else:
+ // align message to ${msg.align} bytes (length does not contain alignment)
bb.skipBytes(((length + ${msg.align-1})/${msg.align} * ${msg.align} ) - length );
//:: #endif
+ //:: #endif
//:: if msg.data_members:
//:: if os.path.exists("%s/custom/%s.Reader_normalize_stanza.java" % (template_dir, msg.name)):
@@ -327,10 +332,13 @@
//:: if not msg.is_fixed_length:
// update length field
int length = bb.writerIndex() - startIndex;
- bb.setShort(lengthIndex, length);
+ //:: if msg.align:
+ int alignedLength = ((length + ${msg.align-1})/${msg.align} * ${msg.align});
+ //:: #endif
+ bb.setShort(lengthIndex, ${"alignedLength" if msg.length_includes_align else "length"});
//:: if msg.align:
// align message to ${msg.align} bytes
- bb.writeZero( ((length + ${msg.align-1})/${msg.align} * ${msg.align}) - length);
+ bb.writeZero(alignedLength - length);
//:: #endif
//:: #end
diff --git a/java_gen/templates/unit_test.java b/java_gen/templates/unit_test.java
index 5a525e4..cd85a74 100644
--- a/java_gen/templates/unit_test.java
+++ b/java_gen/templates/unit_test.java
@@ -80,6 +80,7 @@
// FIXME should invoke the overall reader once implemented
${var_type} ${var_name}Read = ${msg.name}.READER.readFrom(input);
+ assertEquals(${msg.constant_name}_SERIALIZED.length, input.readerIndex());
assertEquals(${var_name}Built, ${var_name}Read);
}
@@ -93,6 +94,7 @@
// FIXME should invoke the overall reader once implemented
${var_type} ${var_name} = ${msg.name}.READER.readFrom(input);
+ assertEquals(${msg.constant_name}_SERIALIZED.length, input.readerIndex());
// write message again
ChannelBuffer bb = ChannelBuffers.dynamicBuffer();
diff --git a/loxi_front_end/parser.py b/loxi_front_end/parser.py
index f2cf4b0..4a465f7 100644
--- a/loxi_front_end/parser.py
+++ b/loxi_front_end/parser.py
@@ -56,7 +56,7 @@
type_member = P.Group(tag('type') + any_type + identifier + s('==') + integer)
data_member = P.Group(tag('data') + any_type - identifier)
-struct_param_name = kw("align")
+struct_param_name = kw("align") | kw("length_includes_align")
struct_param = P.Group(struct_param_name - s('=') - word)
struct_param_list = P.Forward()
struct_param_list << struct_param + P.Optional(s(',') - P.Optional(struct_param_list))
diff --git a/openflow_input/standard-1.2 b/openflow_input/standard-1.2
index a804643..cf146e0 100644
--- a/openflow_input/standard-1.2
+++ b/openflow_input/standard-1.2
@@ -603,7 +603,7 @@
pad(4);
};
-struct of_match_v3(align=8) {
+struct of_match_v3(align=8, length_includes_align=False) {
uint16_t type == 1;
uint16_t length;
list(of_oxm_t) oxm_list;
@@ -694,13 +694,13 @@
pad(4);
};
-struct of_action_set_field : of_action {
+struct of_action_set_field(align=8, length_includes_align=True) : of_action {
uint16_t type == 25;
uint16_t len;
of_oxm_t field;
};
-struct of_action_experimenter : of_action {
+struct of_action_experimenter(align=8, length_includes_align=True) : of_action {
uint16_t type == 65535;
uint16_t len;
uint32_t experimenter == ?;
diff --git a/openflow_input/standard-1.3 b/openflow_input/standard-1.3
index 29e6c76..0d4a8c5 100644
--- a/openflow_input/standard-1.3
+++ b/openflow_input/standard-1.3
@@ -730,7 +730,7 @@
};
// FIXME Does this need to be v4?
-struct of_match_v3(align=8) {
+struct of_match_v3(align=8, length_includes_align=False) {
uint16_t type == 1;
uint16_t length;
list(of_oxm_t) oxm_list;
@@ -829,13 +829,13 @@
pad(4);
};
-struct of_action_set_field : of_action {
+struct of_action_set_field(align=8, length_includes_align=True) : of_action {
uint16_t type == 25;
uint16_t len;
of_oxm_t field;
};
-struct of_action_experimenter : of_action {
+struct of_action_experimenter(align=8, length_includes_align=True): of_action {
uint16_t type == 65535;
uint16_t len;
uint32_t experimenter == ?;
diff --git a/test_data/__init__.py b/test_data/__init__.py
index 7a55c11..dc063fa 100644
--- a/test_data/__init__.py
+++ b/test_data/__init__.py
@@ -26,6 +26,7 @@
# EPL for the specific language governing permissions and limitations
# under the EPL.
+import fnmatch
import os
_test_data_dir = os.path.dirname(os.path.realpath(__file__))
@@ -45,6 +46,11 @@
result.append(dirname + '/' + filename)
return sorted(result)
+def glob(pattern):
+ for f in list_files():
+ if fnmatch.fnmatch(f, pattern):
+ yield f
+
def exists(name):
return os.path.exists(os.path.join(_test_data_dir, name))
diff --git a/test_data/of13/action_output.data b/test_data/of13/action_output.data
index 7cd52ce..7653a30 100644
--- a/test_data/of13/action_output.data
+++ b/test_data/of13/action_output.data
@@ -6,3 +6,5 @@
00 00 00 00 00 00 # pad
-- python
ofp.action.output(port=50, max_len=65535)
+-- java
+builder.setPort(OFPort.of(50)).setMaxLen(65535)
diff --git a/test_data/of13/action_set_field__eth_dst.data b/test_data/of13/action_set_field__eth_dst.data
new file mode 100644
index 0000000..833bb36
--- /dev/null
+++ b/test_data/of13/action_set_field__eth_dst.data
@@ -0,0 +1,11 @@
+-- binary
+00 19 # type
+00 10 # length
+80 00 06 06 # OXM header
+00 01 02 03 04 05 # OXM value
+00 00 # pad
+-- python
+ofp.action.set_field(field=ofp.oxm.eth_dst([0, 1, 2, 3, 4, 5]))
+-- java
+OFOxms oxms = OFFactories.getFactory(OFVersion.OF_13).oxms();
+builder.setField(oxms.ethDst(MacAddress.of("00:01:02:03:04:05")))
diff --git a/test_data/of13/action_set_field_ipv6_src.data b/test_data/of13/action_set_field__ipv6_src.data
similarity index 60%
rename from test_data/of13/action_set_field_ipv6_src.data
rename to test_data/of13/action_set_field__ipv6_src.data
index f440dee..cfa2738 100644
--- a/test_data/of13/action_set_field_ipv6_src.data
+++ b/test_data/of13/action_set_field__ipv6_src.data
@@ -5,3 +5,6 @@
00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f # OXM value
-- python
ofp.action.set_field(field=ofp.oxm.ipv6_src("\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"))
+-- java
+OFOxms oxms = OFFactories.getFactory(OFVersion.OF_13).oxms();
+builder.setField(oxms.ipv6Src(IPv6Address.of("0001:0203:0405:0607:0809:0a0b:0c0d:0e0f")))
diff --git a/test_data/of13/action_set_field__tcp_src.data b/test_data/of13/action_set_field__tcp_src.data
new file mode 100644
index 0000000..41c4780
--- /dev/null
+++ b/test_data/of13/action_set_field__tcp_src.data
@@ -0,0 +1,11 @@
+-- binary
+00 19 # type
+00 10 # length
+80 00 1a 02 # OXM header
+00 32 # OXM value
+00 00 00 00 00 00 # pad
+-- python
+ofp.action.set_field(field=ofp.oxm.tcp_src(50))
+-- java
+OFOxms oxms = OFFactories.getFactory(OFVersion.OF_13).oxms();
+builder.setField(oxms.tcpSrc(TransportPort.of(50)))
diff --git a/test_data/of13/action_set_field_eth_dst.data b/test_data/of13/action_set_field_eth_dst.data
deleted file mode 100644
index 1e4a971..0000000
--- a/test_data/of13/action_set_field_eth_dst.data
+++ /dev/null
@@ -1,8 +0,0 @@
--- binary
-00 19 # type
-00 10 # length
-80 00 06 06 # OXM header
-00 01 02 03 04 05 # OXM value
-00 00 # pad
--- python
-ofp.action.set_field(field=ofp.oxm.eth_dst([0, 1, 2, 3, 4, 5]))
diff --git a/test_data/of13/action_set_field_tcp_src.data b/test_data/of13/action_set_field_tcp_src.data
deleted file mode 100644
index a69c7c0..0000000
--- a/test_data/of13/action_set_field_tcp_src.data
+++ /dev/null
@@ -1,8 +0,0 @@
--- binary
-00 19 # type
-00 10 # length
-80 00 1a 02 # OXM header
-00 32 # OXM value
-00 00 00 00 00 00 # pad
--- python
-ofp.action.set_field(field=ofp.oxm.tcp_src(50))