loci: fix OF 1.2+ packet-in data offset

There are two bytes of padding between the match and the packet data.

This commit introduces "extra length", which is the sum of the fixed length
parts of an object having variable offsets (after a variable length member).
The only use is for OF 1.2+ packet-in messages.
diff --git a/c_gen/c_code_gen.py b/c_gen/c_code_gen.py
index 6be7491..df9d9da 100644
--- a/c_gen/c_code_gen.py
+++ b/c_gen/c_code_gen.py
@@ -681,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
@@ -801,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
@@ -2642,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;
@@ -2789,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) {
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 07f8dd5..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("""
 /**
@@ -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/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()