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()