Fix bsn_vport subtype, add l2gre vport and test file.
diff --git a/c_gen/build_of_g.py b/c_gen/build_of_g.py
index 41d8ab2..4d37b36 100755
--- a/c_gen/build_of_g.py
+++ b/c_gen/build_of_g.py
@@ -158,6 +158,11 @@
             # but is variable length
             bytes = -1
             len_update = 4
+        elif base_type == "of_bsn_vport_header_t":
+            # This is a special case: it has non-zero min length
+            # but is variable length
+            bytes = -1
+            len_update = 4
         elif base_type in of_g.of_base_types:
             bytes = of_g.of_base_types[base_type]["bytes"]
         else:
@@ -332,6 +337,9 @@
                     # HACK the C backend does not yet support of_oxm_t
                     if m.oftype == 'of_oxm_t':
                         m_type = 'of_oxm_header_t'
+                    # HACK the C backend does not yet support of_bsn_vport_t
+                    elif m.oftype == 'of_bsn_vport_t':
+                        m_type = 'of_bsn_vport_header_t'
                     else:
                         enum = find(lambda e: e.name == m.oftype, protocol.enums)
                         if enum and "wire_type" in enum.params:
diff --git a/c_gen/c_code_gen.py b/c_gen/c_code_gen.py
index 4f5ee7f..3fa4f3a 100644
--- a/c_gen/c_code_gen.py
+++ b/c_gen/c_code_gen.py
@@ -1585,6 +1585,17 @@
     %(m_name)s->length = cur_len;
     of_object_wire_init(%(m_name)s, OF_OXM, 0);
 """ % dict(m_type=m_type[:-2], m_name=m_name))
+    elif m_type == "of_bsn_vport_header_t":
+        out.write("""
+    /* Initialize child */
+    %(m_type)s_init(%(m_name)s, obj->version, 0, 1);
+    /* Attach to parent */
+    %(m_name)s->parent = (of_object_t *)obj;
+    %(m_name)s->wbuf = obj->wbuf;
+    %(m_name)s->obj_offset = abs_offset;
+    %(m_name)s->length = cur_len;
+    of_object_wire_init(%(m_name)s, OF_BSN_VPORT, 0);
+""" % dict(m_type=m_type[:-2], m_name=m_name))
     else:
         out.write("""
     /* Initialize child */
diff --git a/c_gen/c_test_gen.py b/c_gen/c_test_gen.py
index 3eaaf82..be1b0da 100644
--- a/c_gen/c_test_gen.py
+++ b/c_gen/c_test_gen.py
@@ -100,6 +100,7 @@
         of_meter_features_t="features",
         of_match_t="match",
         of_oxm_header_t="oxm",
+        of_bsn_vport_header_t="bsn_vport",
         # BSN extensions
         of_bsn_vport_q_in_q_t="vport",
         of_bitmap_128_t="bitmap_128",
@@ -1363,6 +1364,19 @@
         FREE(octets.data);
     }
 """ % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
+        elif m_type == "of_bsn_vport_t": # FIXME: tests only q_in_q
+            out.write("""\
+    %(var_name)s = %(sub_cls)s_new(%(v_name)s);
+    TEST_ASSERT(%(var_name)s != NULL);
+    value = %(sub_cls)s_q_in_q_%(v_name)s_populate(
+        &%(var_name)s->q_in_q, value);
+    TEST_ASSERT(value != 0);
+    %(cls)s_%(m_name)s_set(
+        obj, %(var_name)s);
+    %(sub_cls)s_delete(%(var_name)s);
+""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
+           var_name=var_name_map(m_type),
+           v_name=loxi_utils.version_to_name(version)))
         else:
             sub_cls = m_type[:-2] # Trim _t
             out.write("""
@@ -1429,6 +1443,22 @@
     value = of_octets_check(&%(var_name)s, value);
 """ % dict(cls=cls, var_name=var_name_map(m_type), m_name=m_name,
            v_name=loxi_utils.version_to_name(version)))
+        elif m_type == "of_bsn_vport_t": # FIXME: tests only q_in_q
+            sub_cls = m_type[:-2] # Trim _t
+            out.write("""
+    { /* Use get/delete to access on check */
+        %(m_type)s *%(m_name)s_ptr;
+
+        %(m_name)s_ptr = %(cls)s_%(m_name)s_get(obj);
+        TEST_ASSERT(%(m_name)s_ptr != NULL);
+        value = %(sub_cls)s_q_in_q_%(v_name)s_check(
+            &%(m_name)s_ptr->q_in_q, value);
+        TEST_ASSERT(value != 0);
+        %(sub_cls)s_delete(%(m_name)s_ptr);
+    }
+""" % dict(cls=cls, sub_cls=sub_cls, m_name=m_name, m_type=m_type,
+           var_name=var_name_map(m_type),
+           v_name=loxi_utils.version_to_name(version)))
         else:
             sub_cls = m_type[:-2] # Trim _t
             out.write("""
diff --git a/c_gen/loxi_utils_legacy.py b/c_gen/loxi_utils_legacy.py
index 38feb44..220d043 100644
--- a/c_gen/loxi_utils_legacy.py
+++ b/c_gen/loxi_utils_legacy.py
@@ -120,6 +120,8 @@
         return True
     if cls.find("of_bsn_tlv") == 0:
         return True
+    if cls.find("of_bsn_vport") == 0:
+        return True
     return False
 
 def class_is_u16_len(cls):
diff --git a/c_gen/templates/loci_show.h b/c_gen/templates/loci_show.h
index b210570..b21665d 100644
--- a/c_gen/templates/loci_show.h
+++ b/c_gen/templates/loci_show.h
@@ -398,5 +398,13 @@
 #define LOCI_SHOW_u64_counter_id(writer, cookie, val) LOCI_SHOW_u64(writer, cookie, val)
 #define LOCI_SHOW_desc_str_description(writer, cookie, val) LOCI_SHOW_desc_str(writer, cookie, val)
 #define LOCI_SHOW_str64_name(writer, cookie, val) LOCI_SHOW_str64(writer, cookie, val)
+#define LOCI_SHOW_mac_local_mac(writer, cookie, val) LOCI_SHOW_mac(writer, cookie, val)
+#define LOCI_SHOW_mac_nh_mac(writer, cookie, val) LOCI_SHOW_mac(writer, cookie, val)
+#define LOCI_SHOW_ipv4_src_ip(writer, cookie, val) LOCI_SHOW_ipv4(writer, cookie, val)
+#define LOCI_SHOW_ipv4_dst_ip(writer, cookie, val) LOCI_SHOW_ipv4(writer, cookie, val)
+#define LOCI_SHOW_u8_dscp_mode(writer, cookie, val) LOCI_SHOW_u8(writer, cookie, val)
+#define LOCI_SHOW_u8_dscp(writer, cookie, val) LOCI_SHOW_u8(writer, cookie, val)
+#define LOCI_SHOW_u8_ttl(writer, cookie, val) LOCI_SHOW_u8(writer, cookie, val)
+#define LOCI_SHOW_u32_vpn(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
 
 #endif /* _LOCI_SHOW_H_ */
diff --git a/c_gen/type_maps.py b/c_gen/type_maps.py
index af43a15..2f23d61 100644
--- a/c_gen/type_maps.py
+++ b/c_gen/type_maps.py
@@ -92,18 +92,22 @@
     # version 1.0
     of_g.VERSION_1_0:dict(
         q_in_q      = 0,
+        l2gre       = 1,
         ),
     # version 1.1
     of_g.VERSION_1_1:dict(
         q_in_q      = 0,
+        l2gre       = 1,
         ),
     # version 1.2
     of_g.VERSION_1_2:dict(
         q_in_q      = 0,
+        l2gre       = 1,
         ),
     # version 1.3
     of_g.VERSION_1_3:dict(
         q_in_q      = 0,
+        l2gre       = 1,
         )
     }
 
diff --git a/java_gen/java_type.py b/java_gen/java_type.py
index f345e08..452ac58 100644
--- a/java_gen/java_type.py
+++ b/java_gen/java_type.py
@@ -420,8 +420,8 @@
 meter_features = JType("OFMeterFeatures")\
         .op(read="OFMeterFeaturesVer$version.READER.readFrom(bb)",
             write="$name.writeTo(bb)")
-bsn_vport_q_in_q = JType("OFBsnVportQInQ")\
-        .op(read="OFBsnVportQInQVer$version.READER.readFrom(bb)",
+bsn_vport = JType("OFBsnVport")\
+        .op(read="OFBsnVportVer$version.READER.readFrom(bb)",
             write="$name.writeTo(bb)")
 flow_wildcards = JType("int") \
         .op(read='bb.readInt()',
@@ -537,7 +537,7 @@
         'of_meter_features_t': meter_features,
         'of_bitmap_128_t': port_bitmap,
         'of_checksum_128_t': checksum,
-        'of_bsn_vport_q_in_q_t': bsn_vport_q_in_q,
+        'of_bsn_vport_t': bsn_vport,
         }
 
 ## Map that defines exceptions from the standard loxi->java mapping scheme
diff --git a/openflow_input/bsn_vport b/openflow_input/bsn_vport
index 83440e1..97316b4 100644
--- a/openflow_input/bsn_vport
+++ b/openflow_input/bsn_vport
@@ -42,6 +42,19 @@
     OF_BSN_VPORT_Q_IN_Q_UNTAGGED = 0xffff,
 };
 
+enum ofp_bsn_vport_l2gre_dscp_mode(wire_type=uint8_t) {
+    OF_BSN_VPORT_L2GRE_DSCP_ASSIGN = 0,
+    OF_BSN_VPORT_L2GRE_DSCP_COPY = 1,
+};
+
+enum ofp_bsn_vport_l2gre_dscp_dont_care(wire_type=uint8_t, complete=False) {
+    OF_BSN_VPORT_L2GRE_DSCP_DONT_CARE = 0xff,
+};
+
+enum ofp_bsn_vport_l2gre_ttl_dont_care(wire_type=uint8_t, complete=False) {
+    OF_BSN_VPORT_L2GRE_TTL_DONT_CARE = 0xff,
+};
+
 // BSN Virtual port object header
 // FIXME For now, inheritance is not exercised.  See below.
 struct of_bsn_vport {
@@ -55,7 +68,7 @@
 
 struct of_bsn_vport_q_in_q : of_bsn_vport {
     uint16_t type == 0;
-    uint16_t length;  /* 32 */
+    uint16_t length;
     uint32_t port_no;     /* OF port number of parent; usually phys port */
     uint16_t ingress_tpid;
     uint16_t ingress_vlan_id;
@@ -64,6 +77,26 @@
     of_port_name_t if_name;  /* Name to use in create operation */
 };
 
+
+// L2GRE tunnel virtual port specification
+
+struct of_bsn_vport_l2gre : of_bsn_vport {
+    uint16_t type == 1;
+    uint16_t length;
+    of_port_no_t port_no;       /* OF port number of parent */
+    of_mac_addr_t local_mac;    /* Local MAC */
+    of_mac_addr_t nh_mac;       /* Next Hop MAC */
+    of_ipv4_t src_ip;           /* Source IP */
+    of_ipv4_t dst_ip;           /* Destination IP */
+    enum ofp_bsn_vport_l2gre_dscp_mode dscp_mode;
+    uint8_t dscp;
+    uint8_t ttl;
+    pad(1);
+    uint32_t vpn;               /* VPN ID (for GRE Key) */
+    of_port_name_t if_name;     /* Virtual Interface Name */
+};
+
+
 // Request from controller to switch to create vport
 struct of_bsn_virtual_port_create_request : of_bsn_header {
     uint8_t version;
diff --git a/test_data/of13/bsn_vport_create_request__l2gre.data b/test_data/of13/bsn_vport_create_request__l2gre.data
new file mode 100644
index 0000000..f879651
--- /dev/null
+++ b/test_data/of13/bsn_vport_create_request__l2gre.data
@@ -0,0 +1,53 @@
+-- binary
+04 04               # version, type
+00 44               # len
+01 02 03 04         # xid
+00 5c 16 c7         # experimenter
+00 00 00 0f         # subtype
+00 01               # vport type
+00 34               # vport len
+00 00 00 01         # vport port no
+0a 0b 0c 0d 0e 0f   # local mac
+01 02 03 04 05 06   # next hop mac
+c0 00 00 02         # src ip
+c0 00 10 02         # dst ip
+00 01 40 00         # dscp mode, dscp, ttl, pad
+00 00 be ef         # vpn
+66 6f 6f 00 00 00 00 00 00 00 00 00 00 00 00 00 # vport if name
+-- python
+ofp.message.bsn_virtual_port_create_request(
+xid=0x01020304, vport=ofp.bsn_vport_l2gre(
+port_no=1,
+local_mac=[0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f],
+nh_mac=[0x01, 0x02, 0x03, 0x04, 0x05, 0x06],
+src_ip=0xc0000002,
+dst_ip=0xc0001002,
+dscp_mode=0,
+dscp=1,
+ttl=64,
+vpn=0xbeef,
+if_name="foo"
+))
+-- c
+obj = of_bsn_virtual_port_create_request_new(OF_VERSION_1_3);
+of_bsn_virtual_port_create_request_xid_set(obj, 0x01020304);
+{
+    of_object_t *vport = of_bsn_vport_l2gre_new(OF_VERSION_1_3);
+    {
+        of_port_name_t if_name = "foo";
+        of_mac_addr_t local_mac = { { 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f } };
+        of_mac_addr_t nh_mac = { { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 } };
+        of_bsn_vport_l2gre_port_no_set(vport, 1);
+        of_bsn_vport_l2gre_local_mac_set(vport, local_mac);
+        of_bsn_vport_l2gre_nh_mac_set(vport, nh_mac);
+        of_bsn_vport_l2gre_src_ip_set(vport, 0xc0000002);
+        of_bsn_vport_l2gre_dst_ip_set(vport, 0xc0001002);
+        of_bsn_vport_l2gre_dscp_mode_set(vport, 0);
+        of_bsn_vport_l2gre_dscp_set(vport, 1);
+        of_bsn_vport_l2gre_ttl_set(vport, 64);
+        of_bsn_vport_l2gre_vpn_set(vport, 0xbeef);
+        of_bsn_vport_l2gre_if_name_set(vport, if_name);
+    }
+    of_bsn_virtual_port_create_request_vport_set(obj, vport);
+    of_object_delete(vport);
+}
diff --git a/test_data/of13/bsn_vport_create_request__q_in_q.data b/test_data/of13/bsn_vport_create_request__q_in_q.data
index 2c35542..19c5876 100644
--- a/test_data/of13/bsn_vport_create_request__q_in_q.data
+++ b/test_data/of13/bsn_vport_create_request__q_in_q.data
@@ -22,3 +22,20 @@
 egress_vlan_id=5,
 if_name="foo"
 ))
+-- c
+obj = of_bsn_virtual_port_create_request_new(OF_VERSION_1_3);
+of_bsn_virtual_port_create_request_xid_set(obj, 0x01020304);
+{
+    of_object_t *vport = of_bsn_vport_q_in_q_new(OF_VERSION_1_3);
+    {
+        of_port_name_t if_name = "foo";
+        of_bsn_vport_q_in_q_port_no_set(vport, 1);
+        of_bsn_vport_q_in_q_ingress_tpid_set(vport, 2);
+        of_bsn_vport_q_in_q_ingress_vlan_id_set(vport, 3);
+        of_bsn_vport_q_in_q_egress_tpid_set(vport, 4);
+        of_bsn_vport_q_in_q_egress_vlan_id_set(vport, 5);
+        of_bsn_vport_q_in_q_if_name_set(vport, if_name);
+    }
+    of_bsn_virtual_port_create_request_vport_set(obj, vport);
+    of_object_delete(vport);
+}