Merge into master from pull request #33:
Fix OF 1.3 flow mods, flow stats, and OXM (https://github.com/floodlight/loxigen/pull/33)
diff --git a/c_gen/c_code_gen.py b/c_gen/c_code_gen.py
index 6395022..df9d9da 100644
--- a/c_gen/c_code_gen.py
+++ b/c_gen/c_code_gen.py
@@ -552,28 +552,27 @@
#define _END_LEN(obj, offset) ((obj)->length - (offset))
/**
+ * Offset of the action_len member in a packet-out object
+ */
+
+#define _PACKET_OUT_ACTION_LEN_OFFSET(obj) \\
+ (((obj)->version == OF_VERSION_1_0) ? 14 : 16)
+
+/**
* Get length of the action list object in a packet_out object
* @param obj An object of type of_packet_out
- *
- * The length field is just before the end of the fixed length
- * part of the object in all versions.
*/
#define _PACKET_OUT_ACTION_LEN(obj) \\
- (of_object_u16_get((of_object_t *)(obj), \\
- of_object_fixed_len[(obj)->version][OF_PACKET_OUT] - 2))
+ (of_object_u16_get((of_object_t *)(obj), _PACKET_OUT_ACTION_LEN_OFFSET(obj)))
/**
* Set length of the action list object in a packet_out object
* @param obj An object of type of_packet_out
- *
- * The length field is just before the end of the fixed length
- * part of the object in all versions.
*/
#define _PACKET_OUT_ACTION_LEN_SET(obj, len) \\
- (of_object_u16_set((of_object_t *)(obj), \\
- of_object_fixed_len[(obj)->version][OF_PACKET_OUT] - 2, len))
+ (of_object_u16_set((of_object_t *)(obj), _PACKET_OUT_ACTION_LEN_OFFSET(obj), len))
/*
* Match structs in 1.2 come at the end of the fixed length part
@@ -682,11 +681,12 @@
*
* Get length of preceding match object and add to fixed length
* Applies only to version 1.2 and 1.3
+ * The +2 comes from the 2 bytes of padding between the match and packet data.
*/
#define _PACKET_IN_DATA_OFFSET(obj) \\
- _OFFSET_FOLLOWING_MATCH_V3((obj), (obj)->version == OF_VERSION_1_2 ? \
-%(packet_in)d : %(packet_in_1_3)d)
+ (_OFFSET_FOLLOWING_MATCH_V3((obj), (obj)->version == OF_VERSION_1_2 ? \
+%(packet_in)d : %(packet_in_1_3)d) + 2)
/**
* Macro to calculate variable offset of data (packet) member in packet_out
@@ -802,6 +802,7 @@
common_top_matter(out, name)
c_type_maps.gen_type_maps(out)
c_type_maps.gen_length_array(out)
+ c_type_maps.gen_extra_length_array(out)
################################################################
# Top Matter
@@ -2643,7 +2644,7 @@
MEMSET(obj, 0, sizeof(*obj));
}
if (bytes < 0) {
- bytes = of_object_fixed_len[version][%(enum)s];
+ bytes = of_object_fixed_len[version][%(enum)s] + of_object_extra_len[version][%(enum)s];
}
obj->version = version;
obj->length = bytes;
@@ -2790,7 +2791,7 @@
%(cls)s_t *obj;
int bytes;
- bytes = of_object_fixed_len[version][%(enum)s];
+ bytes = of_object_fixed_len[version][%(enum)s] + of_object_extra_len[version][%(enum)s];
/* Allocate a maximum-length wire buffer assuming we'll be appending to it. */
if ((obj = (%(cls)s_t *)of_object_new(OF_WIRE_BUFFER_MAX_LENGTH)) == NULL) {
@@ -3451,7 +3452,6 @@
int entry_match_offset,
int add_match_offset)
{
- of_list_action_t actions;
int entry_len, add_len;
of_wire_buffer_t *wbuf;
int abs_offset;
@@ -3460,15 +3460,6 @@
uint64_t cookie;
of_octets_t match_octets;
- /* Effects may come from different places */
- if (effects != NULL) {
- OF_TRY(of_flow_stats_entry_actions_set(obj,
- (of_list_action_t *)effects));
- } else {
- of_flow_add_actions_bind(flow_add, &actions);
- OF_TRY(of_flow_stats_entry_actions_set(obj, &actions));
- }
-
/* Transfer the match underlying object from add to stats entry */
wbuf = OF_OBJECT_TO_WBUF(obj);
entry_len = _WIRE_MATCH_PADDED_LEN(obj, entry_match_offset);
@@ -3501,6 +3492,27 @@
of_flow_add_hard_timeout_get(flow_add, &val16);
of_flow_stats_entry_hard_timeout_set(obj, val16);
+ /* Effects may come from different places */
+ if (effects != NULL) {
+ if (obj->version == OF_VERSION_1_0) {
+ OF_TRY(of_flow_stats_entry_actions_set(obj,
+ (of_list_action_t *)effects));
+ } else {
+ OF_TRY(of_flow_stats_entry_instructions_set(obj,
+ (of_list_instruction_t *)effects));
+ }
+ } else {
+ if (obj->version == OF_VERSION_1_0) {
+ of_list_action_t actions;
+ of_flow_add_actions_bind(flow_add, &actions);
+ OF_TRY(of_flow_stats_entry_actions_set(obj, &actions));
+ } else {
+ of_list_instruction_t instructions;
+ of_flow_add_instructions_bind(flow_add, &instructions);
+ OF_TRY(of_flow_stats_entry_instructions_set(obj, &instructions));
+ }
+ }
+
return OF_ERROR_NONE;
}
diff --git a/c_gen/c_dump_gen.py b/c_gen/c_dump_gen.py
index aae2dc4..837ff78 100644
--- a/c_gen/c_dump_gen.py
+++ b/c_gen/c_dump_gen.py
@@ -257,7 +257,7 @@
of_object_dump(loci_writer_f writer, void* cookie, of_object_t *obj)
{
if ((obj->object_id > 0) && (obj->object_id < OF_OBJECT_COUNT)) {
- if (((obj)->version > 0) && ((obj)->version <= OF_VERSION_1_2)) {
+ if (((obj)->version > 0) && ((obj)->version <= OF_VERSION_1_3)) {
/* @fixme VERSION */
return dump_funs[obj->version][obj->object_id](writer, cookie, (of_object_t *)obj);
} else {
diff --git a/c_gen/c_match.py b/c_gen/c_match.py
index 84bc782..8befb3f 100644
--- a/c_gen/c_match.py
+++ b/c_gen/c_match.py
@@ -597,7 +597,7 @@
elt = &oxm_entry.%(key)s_masked;
of_oxm_%(key)s_masked_init(elt,
- src->version, -1, 1);
+ oxm_list->version, -1, 1);
of_list_oxm_append_bind(oxm_list, &oxm_entry);
of_oxm_%(key)s_masked_value_set(elt,
src->fields.%(key)s);
@@ -607,7 +607,7 @@
of_oxm_%(key)s_t *elt;
elt = &oxm_entry.%(key)s;
of_oxm_%(key)s_init(elt,
- src->version, -1, 1);
+ oxm_list->version, -1, 1);
of_list_oxm_append_bind(oxm_list, &oxm_entry);
of_oxm_%(key)s_value_set(elt, src->fields.%(key)s);
}
@@ -636,9 +636,9 @@
return OF_ERROR_PARAM;
}
if (dst->object_id != OF_MATCH_V3) {
- of_match_v3_init(dst, src->version, 0, 0);
+ of_match_v3_init(dst, OF_VERSION_1_2, 0, 0);
}
- if ((oxm_list = of_list_oxm_new(src->version)) == NULL) {
+ if ((oxm_list = of_list_oxm_new(dst->version)) == NULL) {
return OF_ERROR_RESOURCE;
}
diff --git a/c_gen/c_test_gen.py b/c_gen/c_test_gen.py
index 74aef8a..54d18b7 100644
--- a/c_gen/c_test_gen.py
+++ b/c_gen/c_test_gen.py
@@ -512,7 +512,7 @@
"""
members, member_types = scalar_member_types_get(cls, version)
- length = of_g.base_length[(cls, version)]
+ length = of_g.base_length[(cls, version)] + of_g.extra_length.get((cls, version), 0)
v_name = loxi_utils.version_to_name(version)
out.write("""
@@ -1079,7 +1079,7 @@
for cls in of_g.ordered_messages:
if not (cls, version) in of_g.base_length:
continue
- bytes = of_g.base_length[(cls, version)]
+ bytes = of_g.base_length[(cls, version)] + of_g.extra_length.get((cls, version), 0)
out.write("""
static int
test_%(cls)s_create_%(v_name)s(void)
@@ -1488,7 +1488,7 @@
"""
members, member_types = scalar_member_types_get(cls, version)
- length = of_g.base_length[(cls, version)]
+ length = of_g.base_length[(cls, version)] + of_g.extra_length.get((cls, version), 0)
v_name = loxi_utils.version_to_name(version)
out.write("""
diff --git a/c_gen/c_type_maps.py b/c_gen/c_type_maps.py
index 6cbf7bc..a0fec7e 100644
--- a/c_gen/c_type_maps.py
+++ b/c_gen/c_type_maps.py
@@ -792,6 +792,7 @@
gen_obj_to_type_map_functions(out)
out.write("extern const int *const of_object_fixed_len[OF_VERSION_ARRAY_MAX];\n")
+ out.write("extern const int *const of_object_extra_len[OF_VERSION_ARRAY_MAX];\n")
out.write("""
/**
@@ -1002,14 +1003,14 @@
extern void of_hello_elem_wire_object_id_get(of_object_t *obj,
of_object_id_t *id);
-/** @fixme VERIFY LENGTH IS NUMBER OF BYTES OF ENTRY INCLUDING HDR */
+/* XXX Hardcoded to the OpenFlow Basic OXM class */
#define OF_OXM_MASKED_TYPE_GET(hdr) (((hdr) >> 8) & 0xff)
#define OF_OXM_MASKED_TYPE_SET(hdr, val) \\
- (hdr) = ((hdr) & 0xffff00ff) + (((val) & 0xff) << 8)
+ (hdr) = ((hdr) & 0x000000ff) + 0x80000000 + (((val) & 0xff) << 8)
-#define OF_OXM_LENGTH_GET(hdr) ((hdr) & 0xff)
+#define OF_OXM_LENGTH_GET(hdr) (((hdr) & 0xff) + 4)
#define OF_OXM_LENGTH_SET(hdr, val) \\
- (hdr) = ((hdr) & 0xffffff00) + ((val) & 0xff)
+ (hdr) = ((hdr) & 0xffffff00) + (((val) - 4) & 0xff)
extern void of_packet_queue_wire_length_get(of_object_t *obj, int *bytes);
extern void of_packet_queue_wire_length_set(of_object_t *obj, int bytes);
@@ -1064,6 +1065,47 @@
""")
+def gen_extra_length_array(out):
+ """
+ Generate an array giving the extra lengths of all objects/versions
+ @param out The file handle to which to write
+ """
+ out.write("""
+/**
+ * An array with the number of bytes in the extra length part
+ * of each OF object
+ */
+""")
+
+ for version in of_g.of_version_range:
+ out.write("""
+static const int\nof_object_extra_len_v%d[OF_OBJECT_COUNT] = {
+ -1, /* of_object is not instantiable */
+""" % version)
+ for i, cls in enumerate(of_g.all_class_order):
+ comma = ","
+ if i == len(of_g.all_class_order) - 1:
+ comma = ""
+ val = "-1" + comma
+ if (cls, version) in of_g.base_length:
+ val = str(of_g.extra_length.get((cls, version), 0)) + comma
+ out.write(" %-5s /* %d: %s */\n" % (val, i + 1, cls))
+ out.write("};\n")
+
+ out.write("""
+/**
+ * Unified map of extra length part of each object
+ */
+const int *const of_object_extra_len[OF_VERSION_ARRAY_MAX] = {
+ NULL,
+""")
+ for version in of_g.of_version_range:
+ out.write(" of_object_extra_len_v%d,\n" % version)
+ out.write("""
+};
+""")
+
+
################################################################
################################################################
diff --git a/c_gen/c_validator_gen.py b/c_gen/c_validator_gen.py
index f617175..2930724 100644
--- a/c_gen/c_validator_gen.py
+++ b/c_gen/c_validator_gen.py
@@ -41,6 +41,7 @@
import loxi_utils.loxi_utils as loxi_utils
import loxi_front_end.identifiers as identifiers
from c_test_gen import var_name_map
+from c_code_gen import v3_match_offset_get
def gen_h(out, name):
loxi_utils.gen_c_copy_license(out)
@@ -208,6 +209,18 @@
return -1;
}
""" % dict(m_name=m_name, m_offset=m_offset, cls=cls))
+ elif version >= of_g.VERSION_1_2 and loxi_utils.cls_is_flow_mod(cls) and m_name == "instructions":
+ # See _FLOW_MOD_INSTRUCTIONS_OFFSET
+ match_offset = v3_match_offset_get(cls)
+ m_offset = '%s_offset' % m_name
+ out.write("""
+ {
+ uint16_t %(m_name)s_len, %(m_name)s_offset;
+ uint16_t match_len;
+ buf_u16_get(buf + %(match_offset)s + 2, &match_len);
+ %(m_name)s_offset = %(match_offset)s + OF_MATCH_BYTES(match_len);
+ %(m_name)s_len = len - %(m_name)s_offset;
+""" % dict(m_name=m_name, cls=cls, match_offset=match_offset))
else:
out.write("""
diff --git a/c_gen/templates/locitest/test_validator.c b/c_gen/templates/locitest/test_validator.c
index db8079e..d7947b9 100644
--- a/c_gen/templates/locitest/test_validator.c
+++ b/c_gen/templates/locitest/test_validator.c
@@ -26,6 +26,9 @@
:: # under the EPL.
::
:: include('_copyright.c')
+:: import of_g
+:: from loxi_utils import loxi_utils
+:: from loxi_front_end import type_maps
/**
* Test message validator
@@ -102,12 +105,45 @@
return TEST_PASS;
}
+/*
+ * Create an instance of every message and run it through the validator.
+ */
+static int
+test_validate_all(void)
+{
+:: for version in of_g.of_version_range:
+:: ver_name = loxi_utils.version_to_name(version)
+::
+:: for cls in reversed(of_g.standard_class_order):
+:: if not loxi_utils.class_in_version(cls, version):
+:: continue
+:: elif cls in type_maps.inheritance_map:
+:: continue
+:: elif not loxi_utils.class_is_message(cls):
+:: continue
+:: #endif
+ {
+ ${cls}_t *obj = ${cls}_new(${ver_name});
+ of_message_t msg;
+ ${cls}_${ver_name}_populate(obj, 1);
+ msg = OF_OBJECT_TO_MESSAGE(obj);
+ TEST_ASSERT(of_validate_message(msg, of_message_length_get(msg)) == 0);
+ ${cls}_delete(obj);
+ }
+
+:: #endfor
+:: #endfor
+
+ return TEST_PASS;
+}
+
int
run_validator_tests(void)
{
RUN_TEST(validate_fixed_length);
RUN_TEST(validate_fixed_length_list);
RUN_TEST(validate_tlv16_list);
+ RUN_TEST(validate_all);
return TEST_PASS;
}
diff --git a/c_gen/templates/of_wire_buf.c b/c_gen/templates/of_wire_buf.c
index 054dc01..13da8e3 100644
--- a/c_gen/templates/of_wire_buf.c
+++ b/c_gen/templates/of_wire_buf.c
@@ -138,11 +138,7 @@
/* Doesn't make sense; mismatch in current buffer info */
ASSERT(old_len + offset <= wbuf->current_bytes);
- if (old_len < new_len) {
- of_wire_buffer_grow(wbuf, offset + new_len);
- } else {
- wbuf->current_bytes += (new_len - old_len); // may decrease size
- }
+ wbuf->current_bytes += (new_len - old_len); // may decrease size
if ((old_len + offset < cur_bytes) && (old_len != new_len)) {
/* Need to move back of buffer */
diff --git a/loxi_front_end/type_maps.py b/loxi_front_end/type_maps.py
index e2b3a83..f9a66f6 100644
--- a/loxi_front_end/type_maps.py
+++ b/loxi_front_end/type_maps.py
@@ -384,8 +384,8 @@
type_val[(name, version)] = value
# Special case OF-1.2 match type
- type_val[("of_match_v3", of_g.VERSION_1_2)] = 0x8000
- type_val[("of_match_v3", of_g.VERSION_1_3)] = 0x8000
+ type_val[("of_match_v3", of_g.VERSION_1_2)] = 1
+ type_val[("of_match_v3", of_g.VERSION_1_3)] = 1
# Utility function
def dict_to_array(d, m_val, def_val=-1):
diff --git a/of_g.py b/of_g.py
index bc9888f..2e8b5ba 100644
--- a/of_g.py
+++ b/of_g.py
@@ -406,6 +406,12 @@
## Map from class, wire_version to size of fixed part of class
base_length = {}
+## Map from class, wire_version to size of variable-offset, fixed length part of class
+extra_length = {
+ ("of_packet_in", 3): 2,
+ ("of_packet_in", 4): 2,
+}
+
## Boolean indication of variable length, per class, wire_version,
is_fixed_length = set()