loci: wire length get/set functions for new special cases

Most of these special cases have a u16 length member, but not at offset 0. A
couple gained the length member in OF 1.4 so we have to check the version
before accessing the length.
diff --git a/c_gen/c_type_maps.py b/c_gen/c_type_maps.py
index 6c45d4d..c7a175f 100644
--- a/c_gen/c_type_maps.py
+++ b/c_gen/c_type_maps.py
@@ -64,6 +64,15 @@
 extern void of_meter_stats_wire_length_get(of_object_t *obj, int *bytes);
 extern void of_meter_stats_wire_length_set(of_object_t *obj, int bytes);
 
+extern void of_port_desc_wire_length_get(of_object_t *obj, int *bytes);
+extern void of_port_desc_wire_length_set(of_object_t *obj, int bytes);
+
+extern void of_port_stats_entry_wire_length_get(of_object_t *obj, int *bytes);
+extern void of_port_stats_entry_wire_length_set(of_object_t *obj, int bytes);
+
+extern void of_queue_stats_entry_wire_length_get(of_object_t *obj, int *bytes);
+extern void of_queue_stats_entry_wire_length_set(of_object_t *obj, int bytes);
+
 """)
 
 
diff --git a/c_gen/codegen.py b/c_gen/codegen.py
index c1b00ad..fa3a79b 100644
--- a/c_gen/codegen.py
+++ b/c_gen/codegen.py
@@ -197,6 +197,13 @@
 class_metadata = []
 class_metadata_dict = {}
 
+# These classes have handwritten C code to get/set their length fields
+# See templates/of_type_maps.c
+special_length_classes = set([
+    'of_packet_queue', 'of_meter_stats', 'of_port_desc',
+    'of_port_stats_entry', 'of_queue_stats_entry',
+])
+
 def build_class_metadata():
     for uclass in loxi_globals.unified.classes:
         wire_length_get = 'NULL'
@@ -216,14 +223,9 @@
             wire_length_set = 'of_object_message_wire_length_set'
         elif uclass.is_oxm:
             wire_length_get = 'of_oxm_wire_length_get'
-        elif uclass.name == "of_packet_queue":
-            # u16 len, but at offset 4
-            wire_length_get = 'of_packet_queue_wire_length_get'
-            wire_length_set = 'of_packet_queue_wire_length_set'
-        elif uclass.name == "of_meter_stats":
-            # u16 len, but at offset 4
-            wire_length_get = 'of_meter_stats_wire_length_get'
-            wire_length_set = 'of_meter_stats_wire_length_set'
+        elif uclass.name in special_length_classes:
+            wire_length_get = '%s_wire_length_get' % uclass.name
+            wire_length_set = '%s_wire_length_set' % uclass.name
         elif loxi_utils_legacy.class_is_tlv16(uclass.name):
             wire_length_set = 'of_tlv16_wire_length_set'
             wire_length_get = 'of_tlv16_wire_length_get'
diff --git a/c_gen/templates/of_type_maps.c b/c_gen/templates/of_type_maps.c
index 9fa59e0..8847515 100644
--- a/c_gen/templates/of_type_maps.c
+++ b/c_gen/templates/of_type_maps.c
@@ -305,3 +305,141 @@
     of_wire_buffer_u16_set(wbuf, 
         OF_OBJECT_ABSOLUTE_OFFSET(obj, OF_METER_STATS_LENGTH_OFFSET), bytes);
 }
+
+/**
+ * Get the wire length for a port desc object
+ * @param obj The object being referenced
+ * @param bytes Pointer to location to store length
+ *
+ * The length is only present for OF 1.4+.
+ */
+void
+of_port_desc_wire_length_get(of_object_t *obj, int *bytes)
+{
+    of_wire_buffer_t *wbuf = OF_OBJECT_TO_WBUF(obj);
+    uint16_t u16;
+
+    LOCI_ASSERT(wbuf != NULL);
+
+    if (obj->version >= OF_VERSION_1_4) {
+        of_wire_buffer_u16_get(wbuf, OF_OBJECT_ABSOLUTE_OFFSET(obj, 4),
+                               &u16);
+        *bytes = u16;
+    } else {
+        *bytes = OF_OBJECT_FIXED_LENGTH(obj);
+    }
+}
+
+/**
+ * Set the wire length for a port desc object
+ * @param obj The object being referenced
+ * @param bytes The length of the object
+ *
+ * The length is only present for OF 1.4+.
+ */
+
+void
+of_port_desc_wire_length_set(of_object_t *obj, int bytes)
+{
+    of_wire_buffer_t *wbuf = OF_OBJECT_TO_WBUF(obj);
+    LOCI_ASSERT(wbuf != NULL);
+
+    if (obj->version >= OF_VERSION_1_4) {
+        of_wire_buffer_u16_set(wbuf, OF_OBJECT_ABSOLUTE_OFFSET(obj, 4),
+                               bytes);
+    } else {
+        LOCI_ASSERT(obj->length == OF_OBJECT_FIXED_LENGTH(obj));
+    }
+}
+
+/**
+ * Get the wire length for a port stats_entry object
+ * @param obj The object being referenced
+ * @param bytes Pointer to location to store length
+ *
+ * The length is only present for OF 1.4+.
+ */
+void
+of_port_stats_entry_wire_length_get(of_object_t *obj, int *bytes)
+{
+    of_wire_buffer_t *wbuf = OF_OBJECT_TO_WBUF(obj);
+    uint16_t u16;
+
+    LOCI_ASSERT(wbuf != NULL);
+
+    if (obj->version >= OF_VERSION_1_4) {
+        of_wire_buffer_u16_get(wbuf, OF_OBJECT_ABSOLUTE_OFFSET(obj, 0),
+                               &u16);
+        *bytes = u16;
+    } else {
+        *bytes = OF_OBJECT_FIXED_LENGTH(obj);
+    }
+}
+
+/**
+ * Set the wire length for a port stats_entry object
+ * @param obj The object being referenced
+ * @param bytes The length of the object
+ *
+ * The length is only present for OF 1.4+.
+ */
+
+void
+of_port_stats_entry_wire_length_set(of_object_t *obj, int bytes)
+{
+    of_wire_buffer_t *wbuf = OF_OBJECT_TO_WBUF(obj);
+    LOCI_ASSERT(wbuf != NULL);
+
+    if (obj->version >= OF_VERSION_1_4) {
+        of_wire_buffer_u16_set(wbuf, OF_OBJECT_ABSOLUTE_OFFSET(obj, 0),
+                               bytes);
+    } else {
+        LOCI_ASSERT(obj->length == OF_OBJECT_FIXED_LENGTH(obj));
+    }
+}
+
+/**
+ * Get the wire length for a queue stats_entry object
+ * @param obj The object being referenced
+ * @param bytes Pointer to location to store length
+ *
+ * The length is only present for OF 1.4+.
+ */
+void
+of_queue_stats_entry_wire_length_get(of_object_t *obj, int *bytes)
+{
+    of_wire_buffer_t *wbuf = OF_OBJECT_TO_WBUF(obj);
+    uint16_t u16;
+
+    LOCI_ASSERT(wbuf != NULL);
+
+    if (obj->version >= OF_VERSION_1_4) {
+        of_wire_buffer_u16_get(wbuf, OF_OBJECT_ABSOLUTE_OFFSET(obj, 0),
+                               &u16);
+        *bytes = u16;
+    } else {
+        *bytes = OF_OBJECT_FIXED_LENGTH(obj);
+    }
+}
+
+/**
+ * Set the wire length for a queue stats_entry object
+ * @param obj The object being referenced
+ * @param bytes The length of the object
+ *
+ * The length is only present for OF 1.4+.
+ */
+
+void
+of_queue_stats_entry_wire_length_set(of_object_t *obj, int bytes)
+{
+    of_wire_buffer_t *wbuf = OF_OBJECT_TO_WBUF(obj);
+    LOCI_ASSERT(wbuf != NULL);
+
+    if (obj->version >= OF_VERSION_1_4) {
+        of_wire_buffer_u16_set(wbuf, OF_OBJECT_ABSOLUTE_OFFSET(obj, 0),
+                               bytes);
+    } else {
+        LOCI_ASSERT(obj->length == OF_OBJECT_FIXED_LENGTH(obj));
+    }
+}