loci: support bsn_gentable
diff --git a/c_gen/c_code_gen.py b/c_gen/c_code_gen.py
index fbd9826..78a809e 100644
--- a/c_gen/c_code_gen.py
+++ b/c_gen/c_code_gen.py
@@ -449,6 +449,7 @@
 of_object_id_t of_oxm_to_object_id(uint32_t type_len, of_version_t version);
 of_object_id_t of_message_experimenter_to_object_id(of_message_t msg, of_version_t version);
 of_object_id_t of_message_to_object_id(of_message_t msg, int length);
+of_object_id_t of_bsn_tlv_to_object_id(int tlv_type, of_version_t version);
 
 int of_object_wire_init(of_object_t *obj, of_object_id_t base_object_id, int max_len);
 
@@ -1549,7 +1550,7 @@
         m_type = "octets_data"
     return "of_wire_buffer_%s_%s" % (m_type, a_type)
 
-def get_len_macro(cls, m_type, version):
+def get_len_macro(cls, m_name, m_type, version):
     """
     Get the length macro for m_type in cls
     """
@@ -1561,6 +1562,12 @@
         return "_TLV16_LEN(obj, offset)"
     if cls == "of_packet_out" and m_type == "of_list_action_t":
         return "_PACKET_OUT_ACTION_LEN(obj)"
+    if cls == "of_bsn_gentable_entry_add" and m_name == "key":
+        return "of_object_u16_get(obj, 18)"
+    if cls == "of_bsn_gentable_entry_desc_stats_entry" and m_name == "key":
+        return "of_object_u16_get(obj, 2)"
+    if cls == "of_bsn_gentable_entry_stats_entry" and m_name == "key":
+        return "of_object_u16_get(obj, 2)"
     # Default is everything to the end of the object
     return "_END_LEN(obj, offset)"
 
@@ -1587,6 +1594,12 @@
             pass
         elif (cls == "of_packet_out" and m_name == "data"):
             pass
+        elif (cls == "of_bsn_gentable_entry_add" and m_name == "value"):
+            pass
+        elif (cls == "of_bsn_gentable_entry_desc_stats_entry" and m_name == "value"):
+            pass
+        elif (cls == "of_bsn_gentable_entry_stats_entry" and m_name == "stats"):
+            pass
         else:
             debug("Error: Unknown member with offset == -1")
             debug("  cls %s, m_name %s, version %d" % (cls, m_name, version))
@@ -1601,7 +1614,7 @@
     if not loxi_utils.type_is_scalar(m_type):
         if loxi_utils.class_is_var_len(m_type[:-2], version) or \
                 m_type == "of_match_t":
-            len_macro = get_len_macro(cls, m_type, version)
+            len_macro = get_len_macro(cls, m_name, m_type, version)
         else:
             len_macro = "%d" % of_g.base_length[(m_type[:-2], version)]
         out.write("        cur_len = %s;\n" % len_macro)
@@ -1717,6 +1730,16 @@
     /* Special case for setting action lengths */
     _PACKET_OUT_ACTION_LEN_SET(obj, %(m_name)s->length);
 """ % dict(m_name=m_name))
+        elif cls == "of_bsn_gentable_entry_add" and m_name == "key":
+            out.write("""
+    /* Special case for setting key length */
+    of_object_u16_set(obj, 18, %(m_name)s->length);
+""" % dict(m_name=m_name))
+        elif cls in ["of_bsn_gentable_entry_desc_stats_entry", "of_bsn_gentable_entry_stats_entry"] and m_name == "key":
+            out.write("""
+    /* Special case for setting key length */
+    of_object_u16_set(obj, 2, %(m_name)s->length);
+""" % dict(m_name=m_name))
         elif m_type not in ["of_match_t", "of_octets_t"]:
             out.write("""
     /* @fixme Shouldn't this precede copying value's data to buffer? */
@@ -2357,6 +2380,10 @@
                     out.write("""
     obj->wire_type_get = of_hello_elem_wire_object_id_get;
 """)
+            if loxi_utils.class_is_bsn_tlv(cls):
+                    out.write("""
+    obj->wire_type_get = of_bsn_tlv_wire_object_id_get;
+""")
         if loxi_utils.class_is_oxm(cls):
             out.write("""
     obj->wire_length_get = of_oxm_wire_length_get;
diff --git a/c_gen/c_test_gen.py b/c_gen/c_test_gen.py
index 4c531be..637819c 100644
--- a/c_gen/c_test_gen.py
+++ b/c_gen/c_test_gen.py
@@ -137,7 +137,17 @@
                "of_bsn_port_counter_stats_request",
                "of_bsn_port_counter_stats_reply",
                "of_bsn_vlan_counter_stats_request",
-               "of_bsn_vlan_counter_stats_reply"]
+               "of_bsn_vlan_counter_stats_reply",
+               "of_bsn_gentable_entry_desc_stats_request",
+               "of_bsn_gentable_entry_desc_stats_reply",
+               "of_bsn_gentable_entry_stats_request",
+               "of_bsn_gentable_entry_stats_reply",
+               "of_bsn_gentable_desc_stats_request",
+               "of_bsn_gentable_desc_stats_reply",
+               "of_bsn_gentable_stats_request",
+               "of_bsn_gentable_stats_reply",
+               "of_bsn_gentable_bucket_stats_request",
+               "of_bsn_gentable_bucket_stats_reply"]
 
     if (cls in classes and (
             m_name == "experimenter" or
diff --git a/c_gen/c_type_maps.py b/c_gen/c_type_maps.py
index 06161ec..d4525ba 100644
--- a/c_gen/c_type_maps.py
+++ b/c_gen/c_type_maps.py
@@ -151,6 +151,10 @@
     gen_type_to_object_id(out, "message_type_to_id", "OF_MESSAGE",
                           "OF_%s", type_maps.message_types, max_type_value)
 
+    gen_type_to_object_id(out, "bsn_tlv_type_to_id", "OF_BSN_TLV",
+                          "OF_BSN_TLV_%s", type_maps.bsn_tlv_types,
+                          max_type_value)
+
 def gen_type_to_obj_map_functions(out):
     """
     Generate the templated type map functions
@@ -588,6 +592,12 @@
     out.write(msg_template %
               dict(name="message", u_name="MESSAGE", ar_len=ar_len))
 
+    # BSN TLV elem types array gen
+    ar_len = type_maps.type_array_len(type_maps.bsn_tlv_types,
+                                      max_type_value)
+    out.write(map_template %
+              dict(name="bsn_tlv", u_name="BSN_TLV", ar_len=ar_len))
+
 def gen_type_data_header(out):
 
     out.write("""
@@ -678,6 +688,8 @@
     of_object_id_t *id);
 extern void of_hello_elem_wire_object_id_get(of_object_t *obj,
     of_object_id_t *id);
+extern void of_bsn_tlv_wire_object_id_get(of_object_t *obj,
+    of_object_id_t *id);
 
 #define OF_OXM_LENGTH_GET(hdr) (((hdr) & 0xff) + 4)
 #define OF_OXM_LENGTH_SET(hdr, val)                         \\
diff --git a/c_gen/c_validator_gen.py b/c_gen/c_validator_gen.py
index 126530a..9bb0407 100644
--- a/c_gen/c_validator_gen.py
+++ b/c_gen/c_validator_gen.py
@@ -222,6 +222,12 @@
         %(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))
+        elif cls == "of_bsn_gentable_entry_add" and m_name == "value":
+            continue;
+        elif cls == "of_bsn_gentable_entry_desc_stats_entry" and m_name == "value":
+            continue;
+        elif cls == "of_bsn_gentable_entry_stats_entry" and m_name == "stats":
+            continue;
         else:
             out.write("""
 
diff --git a/c_gen/loxi_utils_legacy.py b/c_gen/loxi_utils_legacy.py
index 6a0fb2e..4092d4f 100644
--- a/c_gen/loxi_utils_legacy.py
+++ b/c_gen/loxi_utils_legacy.py
@@ -118,6 +118,8 @@
         return True
     if cls == "of_match_v4":
         return True
+    if cls.find("of_bsn_tlv") == 0:
+        return True
     return False
 
 def class_is_u16_len(cls):
@@ -126,7 +128,9 @@
     """
     return cls in ["of_group_desc_stats_entry", "of_group_stats_entry",
                    "of_flow_stats_entry", "of_bucket", "of_table_features",
-                   "of_bsn_port_counter_stats_entry", "of_bsn_vlan_counter_stats_entry"]
+                   "of_bsn_port_counter_stats_entry", "of_bsn_vlan_counter_stats_entry",
+                   "of_bsn_gentable_entry_desc_stats_entry", "of_bsn_gentable_entry_stats_entry",
+                   "of_bsn_gentable_desc_stats_entry"]
 
 def class_is_oxm(cls):
     """
@@ -246,6 +250,14 @@
     """
     return (cls.find("of_list_") == 0)
 
+def class_is_bsn_tlv(cls):
+    """
+    Return True if cls_name is a BSN TLV object
+    """
+    if cls.find("of_bsn_tlv") == 0:
+        return True
+    return False
+
 def type_is_of_object(m_type):
     """
     Return True if m_type is an OF object type
diff --git a/c_gen/of_g_legacy.py b/c_gen/of_g_legacy.py
index 08f13ef..1fadba0 100644
--- a/c_gen/of_g_legacy.py
+++ b/c_gen/of_g_legacy.py
@@ -77,7 +77,7 @@
 ## These members do not get normal accessors
 
 skip_members = ["version", "type", "length", "err_type", "stats_type", "len",
-                "type_len", "actions_len", "_command", "command"]
+                "type_len", "actions_len", "_command", "command", "key_length"]
 
 ## Some OpenFlow string length constants
 #
diff --git a/c_gen/templates/loci_int.h b/c_gen/templates/loci_int.h
index 241cf7b..01ad4a8 100644
--- a/c_gen/templates/loci_int.h
+++ b/c_gen/templates/loci_int.h
@@ -277,4 +277,21 @@
      ((object_id) == OF_FLOW_DELETE_STRICT) ||         \
      ((object_id) == OF_FLOW_ADD))
 
+/**
+ * Macro to calculate variable offset of value member in of_bsn_gentable_entry_add
+ * @param obj An object of type of_bsn_gentable_entry_add_t
+ */
+
+#define _BSN_GENTABLE_ENTRY_ADD_VALUE_OFFSET(obj) \
+    (of_object_u16_get(obj, 18) + \
+        of_object_fixed_len[(obj)->version][OF_BSN_GENTABLE_ENTRY_ADD])
+
+#define _BSN_GENTABLE_ENTRY_DESC_STATS_ENTRY_VALUE_OFFSET(obj) \
+    (of_object_u16_get(obj, 2) + \
+        of_object_fixed_len[(obj)->version][OF_BSN_GENTABLE_ENTRY_DESC_STATS_ENTRY])
+
+#define _BSN_GENTABLE_ENTRY_STATS_ENTRY_STATS_OFFSET(obj) \
+    (of_object_u16_get(obj, 2) + \
+        of_object_fixed_len[(obj)->version][OF_BSN_GENTABLE_ENTRY_STATS_ENTRY])
+
 #endif /* __LOCI_INT_H__ */
diff --git a/c_gen/templates/loci_show.h b/c_gen/templates/loci_show.h
index 8241f3e..1856ae5 100644
--- a/c_gen/templates/loci_show.h
+++ b/c_gen/templates/loci_show.h
@@ -375,5 +375,12 @@
 #define LOCI_SHOW_u64_time_ms(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
 #define LOCI_SHOW_desc_str_uri(writer, cookie, val) LOCI_SHOW_desc_str(writer, cookie, val)
 #define LOCI_SHOW_u8_state(writer, cookie, val) LOCI_SHOW_u8(writer, cookie, val)
+#define LOCI_SHOW_u16_table_id(writer, cookie, val) LOCI_SHOW_u16(writer, cookie, val)
+#define LOCI_SHOW_u32_deleted_count(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
+#define LOCI_SHOW_u32_error_count(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
+#define LOCI_SHOW_checksum_128_checksum(writer, cookie, val) LOCI_SHOW_checksum_128(writer, cookie, val)
+#define LOCI_SHOW_checksum_128_checksum_mask(writer, cookie, val) LOCI_SHOW_checksum_128(writer, cookie, val)
+#define LOCI_SHOW_u32_buckets_size(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
+#define LOCI_SHOW_u32_entry_count(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
 
 #endif /* _LOCI_SHOW_H_ */
diff --git a/c_gen/templates/of_type_maps.c b/c_gen/templates/of_type_maps.c
index 7310988..15b3816 100644
--- a/c_gen/templates/of_type_maps.c
+++ b/c_gen/templates/of_type_maps.c
@@ -446,6 +446,23 @@
     ASSERT(*id != OF_OBJECT_INVALID);
 }
 
+/**
+ * Get the object ID based on the wire buffer for a bsn_tlv object
+ * @param obj The object being referenced
+ * @param id Where to store the object ID
+ */
+
+void
+of_bsn_tlv_wire_object_id_get(of_object_t *obj, of_object_id_t *id)
+{
+    int wire_type;
+
+    of_tlv16_wire_type_get(obj, &wire_type);
+    ASSERT(wire_type >= 0 && wire_type < OF_BSN_TLV_ITEM_COUNT);
+    *id = of_bsn_tlv_type_to_id[obj->version][wire_type];
+    ASSERT(*id != OF_OBJECT_INVALID);
+}
+
 /****************************************************************
  * OXM type/length functions.
  ****************************************************************/
@@ -715,7 +732,12 @@
     case OF_EXPERIMENTER_ID_BSN:
         switch (subtype) {
         case 1: return OF_BSN_LACP_STATS_REQUEST;
+        case 2: return OF_BSN_GENTABLE_ENTRY_DESC_STATS_REQUEST;
+        case 3: return OF_BSN_GENTABLE_ENTRY_STATS_REQUEST;
+        case 4: return OF_BSN_GENTABLE_DESC_STATS_REQUEST;
+        case 5: return OF_BSN_GENTABLE_BUCKET_STATS_REQUEST;
         case 6: return OF_BSN_SWITCH_PIPELINE_STATS_REQUEST;
+        case 7: return OF_BSN_GENTABLE_STATS_REQUEST;
         case 8: return OF_BSN_PORT_COUNTER_STATS_REQUEST;
         case 9: return OF_BSN_VLAN_COUNTER_STATS_REQUEST;
         }
@@ -730,7 +752,12 @@
     case OF_EXPERIMENTER_ID_BSN:
         switch (subtype) {
         case 1: return OF_BSN_LACP_STATS_REPLY;
+        case 2: return OF_BSN_GENTABLE_ENTRY_DESC_STATS_REPLY;
+        case 3: return OF_BSN_GENTABLE_ENTRY_STATS_REPLY;
+        case 4: return OF_BSN_GENTABLE_DESC_STATS_REPLY;
+        case 5: return OF_BSN_GENTABLE_BUCKET_STATS_REPLY;
         case 6: return OF_BSN_SWITCH_PIPELINE_STATS_REPLY;
+        case 7: return OF_BSN_GENTABLE_STATS_REPLY;
         case 8: return OF_BSN_PORT_COUNTER_STATS_REPLY;
         case 9: return OF_BSN_VLAN_COUNTER_STATS_REPLY;
         }
diff --git a/c_gen/type_maps.py b/c_gen/type_maps.py
index f285a33..2a53519 100644
--- a/c_gen/type_maps.py
+++ b/c_gen/type_maps.py
@@ -136,6 +136,13 @@
     of_g.VERSION_1_3:dict(),
     }
 
+bsn_tlv_types = {
+    of_g.VERSION_1_0:dict(),
+    of_g.VERSION_1_1:dict(),
+    of_g.VERSION_1_2:dict(),
+    of_g.VERSION_1_3:dict(),
+    }
+
 # All inheritance data for non-messages
 inheritance_data = dict(
     of_instruction = instruction_types,
@@ -148,7 +155,8 @@
     of_table_feature_prop = table_feature_prop_types,
     of_meter_band = meter_band_types,
     # BSN specific inheritance extensions
-    of_bsn_vport = bsn_vport_types
+    of_bsn_vport = bsn_vport_types,
+    of_bsn_tlv = bsn_tlv_types,
     )
 
 def class_is_virtual(cls):