Merge into master from pull request #245:
Rewrite LOCI validator (https://github.com/floodlight/loxigen/pull/245)
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_match.py b/c_gen/c_match.py
index fdb8afe..7fd6a21 100644
--- a/c_gen/c_match.py
+++ b/c_gen/c_match.py
@@ -177,15 +177,19 @@
     of_match_fields_t masks;
 } of_match_t;
 
-/**
- * Mask the values in the match structure according to its fields
+/*
+ * AND 'len' bytes starting from 'value' with the corresponding byte in
+ * 'mask'.
  */
-static inline void of_match_values_mask(of_match_t *match)
+static inline void
+of_memmask(void *value, const void *mask, size_t len)
 {
-    int idx;
+    int i;
+    uint8_t *v = value;
+    const uint8_t *m = mask;
 
-    for (idx = 0; idx < sizeof(of_match_fields_t); idx++) {
-        ((uint8_t *)&match->fields)[idx] &= ((uint8_t *)&match->masks)[idx];
+    for (i = 0; i < len; i++) {
+        v[i] &= m[i];
     }
 }
 
@@ -755,6 +759,7 @@
     if (OF_VARIABLE_IS_NON_ZERO(&dst->masks.%(key)s)) { /* Matching something */
         of_match_v2_%(key)s_get(src, &dst->fields.%(key)s);
     }
+    of_memmask(&dst->fields.%(key)s, &dst->masks.%(key)s, sizeof(&dst->fields.%(key)s));
 """ % dict(ku=key.upper(), key=key))
         else:
             out.write("""
@@ -765,8 +770,6 @@
 """ % dict(ku=key.upper(), key=key))
 
     out.write("""
-    /* Clear values outside of masks */
-    of_match_values_mask(dst);
 
     return OF_ERROR_NONE;
 }
@@ -810,6 +813,7 @@
             of_oxm_%(key)s_masked_value_get(
                 &oxm_entry.%(key)s,
                 &dst->fields.%(key)s);
+            of_memmask(&dst->fields.%(key)s, &dst->masks.%(key)s, sizeof(&dst->fields.%(key)s));
             break;
         case OF_OXM_%(ku)s:
             OF_MATCH_MASK_%(ku)s_EXACT_SET(dst);
@@ -827,9 +831,6 @@
         rv = of_list_oxm_next(&oxm_list, &oxm_entry);
     } /* end OXM iteration */
 
-    /* Clear values outside of masks */
-    of_match_values_mask(dst);
-
     return OF_ERROR_NONE;
 }
 """)
diff --git a/c_gen/c_test_gen.py b/c_gen/c_test_gen.py
index 3eaaf82..57d141d 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",
@@ -273,7 +274,7 @@
     }
 
     /* Restrict values according to masks */
-    of_match_values_mask(match);
+    of_memmask(&match->fields, &match->masks, sizeof(match->fields));
     return value;
 }
 
@@ -1305,6 +1306,8 @@
     for m_type in member_types:
         if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
             out.write("    %s %s;\n" % (m_type, var_name_map(m_type)))
+        elif m_type == "of_bsn_vport_header_t":
+            out.write("    of_bsn_vport_q_in_q_t *%s;\n" % var_name_map(m_type))
         else:
             out.write("    %s *%s;\n" % (m_type, var_name_map(m_type)))
     out.write("""
@@ -1315,6 +1318,8 @@
         m_name = member["name"]
         if loxi_utils.skip_member_name(m_name):
             continue
+        if m_type == "of_bsn_vport_header_t":
+            continue
         if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
             out.write("""\
     %(cls)s_%(m_name)s_get(obj, &%(var_name)s);
@@ -1363,6 +1368,20 @@
         FREE(octets.data);
     }
 """ % dict(var_name=var_name_map(m_type), cls=cls, m_name=m_name))
+        elif m_type == "of_bsn_vport_header_t": # test q_in_q
+            sub_cls = "of_bsn_vport_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_%(v_name)s_populate(
+        %(var_name)s, 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 +1448,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_header_t": # tests only q_in_q
+            sub_cls = "of_bsn_vport_q_in_q"
+            out.write("""
+    { /* Use get/delete to access on check */
+        %(sub_cls)s_t *%(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_%(v_name)s_check(
+            %(m_name)s_ptr, 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("""
@@ -1698,6 +1733,11 @@
         if loxi_utils.type_is_scalar(m_type) or m_type in ["of_match_t", "of_octets_t"]:
             # Declare instance of these
             out.write("    %s %s;\n" % (m_type, var_name_map(m_type)))
+        elif m_type == "of_bsn_vport_header_t": # test q_in_q
+            out.write("""
+    of_bsn_vport_q_in_q_t src_%(v_name)s;
+    of_bsn_vport_q_in_q_t *dst_%(v_name)s;
+""" % dict(v_name=var_name_map(m_type)))
         else:
             out.write("""
     %(m_type)s src_%(v_name)s;
@@ -1725,6 +1765,20 @@
     %(cls)s_%(m_name)s_get(src, &%(v_name)s);
     %(cls)s_%(m_name)s_set(dst, &%(v_name)s);
 """ % dict(cls=cls, m_name=m_name, v_name=var_name_map(m_type)))
+        elif m_type == "of_bsn_vport_header_t": # test q_in_q
+            sub_cls = "of_bsn_vport_q_in_q"
+            out.write("""
+    %(cls)s_%(m_name)s_bind(
+        src, &src_%(v_name)s);
+    dst_%(v_name)s = %(sub_cls)s_%(ver_name)s_dup(&src_%(v_name)s);
+    if (dst_%(v_name)s == NULL) {
+        %(cls)s_delete(dst);
+        return NULL;
+    }
+    %(cls)s_%(m_name)s_set(dst, dst_%(v_name)s);
+    %(sub_cls)s_delete(dst_%(v_name)s);
+""" % dict(sub_cls=sub_cls, cls=cls, m_name=m_name,
+           v_name=var_name_map(m_type), ver_name=ver_name))
         else:
             sub_cls = m_type[:-2] # Trim _t
             out.write("""
@@ -1893,7 +1947,19 @@
                 continue
             if cls in type_maps.inheritance_map:
                 continue
-            out.write("""
+            if cls == "of_bsn_virtual_port_create_request": # test q_in_q
+                out.write("""
+    obj = (of_object_t *)%(cls)s_new(%(version)s);
+    {
+        of_object_t *vport = of_bsn_vport_q_in_q_new(%(version)s);
+        %(cls)s_vport_set(obj, vport);
+        of_object_delete(vport);
+    }
+    of_object_dump((loci_writer_f)fprintf, out, obj);
+    of_object_delete(obj);
+""" % dict(cls=cls, version=of_g.of_version_wire2name[version]))
+            else:
+                out.write("""
     obj = (of_object_t *)%(cls)s_new(%(version)s);
     of_object_dump((loci_writer_f)fprintf, out, obj);
     of_object_delete(obj);
diff --git a/c_gen/codegen.py b/c_gen/codegen.py
index fe5e2ad..9af9223 100644
--- a/c_gen/codegen.py
+++ b/c_gen/codegen.py
@@ -122,7 +122,7 @@
 # TODO remove header classes and use the corresponding class instead
 def generate_header_classes(install_dir):
     for cls in of_g.standard_class_order:
-        if cls.find("_header") < 0:
+        if cls.find("_header") < 0 or cls in ["of_header", "of_bsn_header", "of_nicira_header"]:
             continue
         with template_utils.open_output(install_dir, "loci/src/%s.c" % cls) as out:
             util.render_template(out, "class.c",
@@ -206,6 +206,10 @@
                 wire_length_set = 'of_tlv16_wire_length_set'
                 wire_length_get = 'of_tlv16_wire_length_get'
                 wire_type_get = 'of_action_wire_object_id_get'
+            elif uclass.is_instanceof('of_bsn_vport'):
+                wire_length_set = 'of_tlv16_wire_length_set'
+                wire_length_get = 'of_tlv16_wire_length_get'
+                wire_type_get = 'of_bsn_vport_wire_object_id_get'
             elif uclass.is_action_id:
                 wire_length_set = 'of_tlv16_wire_length_set'
                 wire_length_get = 'of_tlv16_wire_length_get'
@@ -280,6 +284,12 @@
                 wire_type_get='of_action_id_wire_object_id_get',
                 wire_type_set='NULL'),
             ClassMetadata(
+                name="of_bsn_vport_header",
+                wire_length_set='of_tlv16_wire_length_set',
+                wire_length_get='of_tlv16_wire_length_get',
+                wire_type_get='of_bsn_vport_wire_object_id_get',
+                wire_type_set='NULL'),
+            ClassMetadata(
                 name="of_instruction_header",
                 wire_length_set='of_tlv16_wire_length_set',
                 wire_length_get='of_tlv16_wire_length_get',
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..909df71 100644
--- a/c_gen/templates/loci_show.h
+++ b/c_gen/templates/loci_show.h
@@ -398,5 +398,16 @@
 #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)
+#define LOCI_SHOW_u32_flags(writer, cookie, val) LOCI_SHOW_u32(writer, cookie, val)
+#define LOCI_SHOW_desc_str_image_checksum(write, cookie, val) LOCI_SHOW_desc_str(writer, cookie, val)
+#define LOCI_SHOW_desc_str_startup_config_checksum(write, cookie, val) LOCI_SHOW_desc_str(writer, cookie, val)
 
 #endif /* _LOCI_SHOW_H_ */
diff --git a/c_gen/templates/locitest/Makefile b/c_gen/templates/locitest/Makefile
index 70e57ca..00a2f95 100644
--- a/c_gen/templates/locitest/Makefile
+++ b/c_gen/templates/locitest/Makefile
@@ -10,7 +10,7 @@
 all: locitest
 
 locitest: $(LOCITEST_OBJS) loci.a
-	$(CC) $^ -o $@
+	$(CC) -Wl,--whole-archive $^ -Wl,--no-whole-archive -o $@
 
 loci.a: $(LOCI_OBJS)
 	ar rc $@ $^
diff --git a/c_gen/templates/of_type_maps.c b/c_gen/templates/of_type_maps.c
index 0b0bf15..13b879a 100644
--- a/c_gen/templates/of_type_maps.c
+++ b/c_gen/templates/of_type_maps.c
@@ -328,6 +328,7 @@
         case 11: return OF_BSN_TABLE_CHECKSUM_STATS_REQUEST;
         case 12: return OF_BSN_DEBUG_COUNTER_STATS_REQUEST;
         case 13: return OF_BSN_DEBUG_COUNTER_DESC_STATS_REQUEST;
+        case 14: return OF_BSN_IMAGE_DESC_STATS_REQUEST;
         }
     }
     return OF_OBJECT_INVALID;
@@ -352,6 +353,7 @@
         case 11: return OF_BSN_TABLE_CHECKSUM_STATS_REPLY;
         case 12: return OF_BSN_DEBUG_COUNTER_STATS_REPLY;
         case 13: return OF_BSN_DEBUG_COUNTER_DESC_STATS_REPLY;
+        case 14: return OF_BSN_IMAGE_DESC_STATS_REPLY;
         }
     }
     return OF_OBJECT_INVALID;
diff --git a/c_gen/type_maps.py b/c_gen/type_maps.py
index af43a15..7b745a6 100644
--- a/c_gen/type_maps.py
+++ b/c_gen/type_maps.py
@@ -89,22 +89,10 @@
     }
 
 bsn_vport_types = {
-    # version 1.0
-    of_g.VERSION_1_0:dict(
-        q_in_q      = 0,
-        ),
-    # version 1.1
-    of_g.VERSION_1_1:dict(
-        q_in_q      = 0,
-        ),
-    # version 1.2
-    of_g.VERSION_1_2:dict(
-        q_in_q      = 0,
-        ),
-    # version 1.3
-    of_g.VERSION_1_3:dict(
-        q_in_q      = 0,
-        )
+    of_g.VERSION_1_0:dict(),
+    of_g.VERSION_1_1:dict(),
+    of_g.VERSION_1_2:dict(),
+    of_g.VERSION_1_3:dict(),
     }
 
 oxm_types = {
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/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/VlanVid.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/VlanVid.java
index 2e675d4..ee605de 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/VlanVid.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/VlanVid.java
@@ -33,6 +33,8 @@
     }
 
     public static VlanVid ofVlan(int vid) {
+        if (vid == NO_MASK.vid)
+            return NO_MASK;
         if ((vid & VALIDATION_MASK) != vid)
             throw new IllegalArgumentException(String.format("Illegal VLAN value: %x", vid));
         return new VlanVid((short) vid);
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/util/MultiplePktInReasonUtil.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/util/MultiplePktInReasonUtil.java
new file mode 100644
index 0000000..a919f62
--- /dev/null
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/util/MultiplePktInReasonUtil.java
@@ -0,0 +1,46 @@
+package org.projectfloodlight.openflow.util;
+
+import java.util.Set;
+
+import com.google.common.collect.ImmutableSet;
+
+import org.projectfloodlight.openflow.types.U64;
+import org.projectfloodlight.openflow.protocol.OFBsnPktinFlag;
+import org.projectfloodlight.openflow.protocol.OFPacketIn;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+import org.projectfloodlight.openflow.protocol.match.MatchField;
+import org.projectfloodlight.openflow.protocol.match.Match;
+import org.projectfloodlight.openflow.protocol.ver13.OFBsnPktinFlagSerializerVer13;
+import org.projectfloodlight.openflow.types.OFMetadata;
+
+
+public class MultiplePktInReasonUtil {
+    private MultiplePktInReasonUtil() {}
+
+    /**
+     * This function is used in BVS T5/6 to decode the multiple packet in
+     * reasons in Match.MetaData field.
+     * */
+    public static Set<OFBsnPktinFlag> getOFBsnPktinFlags(OFPacketIn pktIn) {
+        if(pktIn.getVersion() != OFVersion.OF_13) {
+            throw new IllegalArgumentException("multiple pkt in reasons are "
+                                               + "only supported by BVS using "
+                                               + "openflow 1.3");
+        }
+
+        Match match = pktIn.getMatch();
+        if(match == null) {
+            return ImmutableSet.<OFBsnPktinFlag>of();
+        }
+        OFMetadata metaData = match.get(MatchField.METADATA);
+        if(metaData == null) {
+            return ImmutableSet.<OFBsnPktinFlag>of();
+        }
+        U64 metaDataValue = metaData.getValue();
+        if(metaDataValue == null) {
+            return ImmutableSet.<OFBsnPktinFlag>of();
+        }
+        return OFBsnPktinFlagSerializerVer13.ofWireValue(metaDataValue
+                                                               .getValue());
+    }
+}
diff --git a/openflow_input/bsn_image b/openflow_input/bsn_image
new file mode 100644
index 0000000..05a1a97
--- /dev/null
+++ b/openflow_input/bsn_image
@@ -0,0 +1,57 @@
+// Copyright 2013, Big Switch Networks, Inc.
+//
+// LoxiGen is licensed under the Eclipse Public License,
+// version 1.0 (EPL), with the following special exception:
+//
+// LOXI Exception
+//
+// As a special exception to the terms of the EPL, you may
+// distribute libraries generated by LoxiGen (LoxiGen Libraries)
+// under the terms of your choice, provided that copyright and
+// licensing notices generated by LoxiGen are not altered or removed
+// from the LoxiGen Libraries and the notice provided below is (i)
+// included in the LoxiGen Libraries, if distributed in source code
+// form and (ii) included in any documentation for the LoxiGen
+// Libraries, if distributed in binary form.
+//
+// Notice: "Copyright 2013, Big Switch Networks, Inc.
+// This library was generated by the LoxiGen Compiler."
+//
+// You may not use this file except in compliance with the EPL or
+// LOXI Exception. You may obtain a copy of the EPL at:
+//
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an "AS
+// IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+// express or implied. See the EPL for the specific language
+// governing permissions and limitations under the EPL.
+
+#version 4
+
+struct of_bsn_image_desc_stats_request : of_bsn_stats_request {
+    uint8_t version;
+    uint8_t type == 18;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 0xffff;
+    enum ofp_stats_request_flags flags;
+    pad(4);
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 14;
+};
+
+struct of_bsn_image_desc_stats_reply : of_bsn_stats_reply {
+    uint8_t version;
+    uint8_t type == 19;
+    uint16_t length;
+    uint32_t xid;
+    uint16_t stats_type == 0xffff;
+    enum ofp_stats_reply_flags flags;
+    pad(4);
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 14;
+    of_desc_str_t image_checksum;
+    of_desc_str_t startup_config_checksum;
+};
diff --git a/openflow_input/bsn_pktin_flag b/openflow_input/bsn_pktin_flag
new file mode 100644
index 0000000..54c942f
--- /dev/null
+++ b/openflow_input/bsn_pktin_flag
@@ -0,0 +1,45 @@
+// Copyright 2014, Big Switch Networks, Inc.
+//
+// LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
+// the following special exception:
+//
+// LOXI Exception
+//
+// As a special exception to the terms of the EPL, you may distribute libraries
+// generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
+// that copyright and licensing notices generated by LoxiGen are not altered or removed
+// from the LoxiGen Libraries and the notice provided below is (i) included in
+// the LoxiGen Libraries, if distributed in source code form and (ii) included in any
+// documentation for the LoxiGen Libraries, if distributed in binary form.
+//
+// Notice: "Copyright 2014, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
+//
+// You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
+// a copy of the EPL at:
+//
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// EPL for the specific language governing permissions and limitations
+// under the EPL.
+
+#version 4
+
+// In a realistic switch pipeline there are multiple reasons a given packet
+// should be sent to the controller. The packet-in reason field is only 8 bits,
+// so we use the metadata OXM to carry this information.
+
+enum ofp_bsn_pktin_flag(wire_type=uint64_t, bitmask=True) {
+    OFP_BSN_PKTIN_FLAG_PDU = 0x1,
+    OFP_BSN_PKTIN_FLAG_NEW_HOST = 0x2,
+    OFP_BSN_PKTIN_FLAG_STATION_MOVE = 0x4,
+    OFP_BSN_PKTIN_FLAG_ARP = 0x8,
+    OFP_BSN_PKTIN_FLAG_DHCP = 0x10,
+    OFP_BSN_PKTIN_FLAG_L2_CPU = 0x20,
+    OFP_BSN_PKTIN_FLAG_DEBUG = 0x40,
+    OFP_BSN_PKTIN_FLAG_TTL_EXPIRED = 0x80,
+    OFP_BSN_PKTIN_FLAG_L3_MISS = 0x100,
+    OFP_BSN_PKTIN_FLAG_L3_CPU = 0x200,
+};
diff --git a/openflow_input/bsn_vport b/openflow_input/bsn_vport
index 4eeda8c..82d9d33 100644
--- a/openflow_input/bsn_vport
+++ b/openflow_input/bsn_vport
@@ -42,6 +42,14 @@
     OF_BSN_VPORT_Q_IN_Q_UNTAGGED = 0xffff,
 };
 
+enum ofp_bsn_vport_l2gre_flags(wire_type=uint32_t, bitmask=True) {
+    OF_BSN_VPORT_L2GRE_LOCAL_MAC_IS_VALID = 0x1,
+
+    /* DSCP flags are mutually exclusive */
+    OF_BSN_VPORT_L2GRE_DSCP_ASSIGN = 0x2,
+    OF_BSN_VPORT_L2GRE_DSCP_COPY = 0x4,
+};
+
 // BSN Virtual port object header
 // FIXME For now, inheritance is not exercised.  See below.
 struct of_bsn_vport {
@@ -55,7 +63,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 +72,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;
+    enum ofp_bsn_vport_l2gre_flags flags;
+    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 */
+    uint8_t dscp;
+    uint8_t ttl;
+    pad(2);
+    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;
@@ -72,8 +100,7 @@
     uint32_t xid;
     uint32_t experimenter == 0x5c16c7;
     uint32_t subtype == 15;
-    // FIXME This should be an instance of the inheritance superclass
-    of_bsn_vport_q_in_q_t vport;   // Description of vport to create
+    of_bsn_vport_t vport;   // Description of vport to create
     // Additional data follows depending on header type
 };
 
diff --git a/py_gen/oftype.py b/py_gen/oftype.py
index ddde14a..7bd242e 100644
--- a/py_gen/oftype.py
+++ b/py_gen/oftype.py
@@ -142,7 +142,7 @@
     'of_match_t': 'common.match',
     'of_port_desc_t': 'common.port_desc',
     'of_meter_features_t': 'common.meter_features',
-    'of_bsn_vport_q_in_q_t': 'common.bsn_vport_q_in_q',
+    'of_bsn_vport_t': 'common.bsn_vport',
 }
 
 for (cls, pyclass) in embedded_structs.items():
diff --git a/test_data/of13/bsn_virtual_port_create_request__l2gre.data b/test_data/of13/bsn_virtual_port_create_request__l2gre.data
new file mode 100644
index 0000000..b5fd5fa
--- /dev/null
+++ b/test_data/of13/bsn_virtual_port_create_request__l2gre.data
@@ -0,0 +1,77 @@
+-- binary
+04 04               # version, type
+00 48               # len
+01 02 03 04         # xid
+00 5c 16 c7         # experimenter
+00 00 00 0f         # subtype
+00 01               # vport type
+00 38               # vport len
+00 00 00 03         # vport flags
+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
+01 40 00 00         # dscp, ttl, pad(2)
+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(
+flags=ofp.OF_BSN_VPORT_L2GRE_LOCAL_MAC_IS_VALID | ofp.OF_BSN_VPORT_L2GRE_DSCP_ASSIGN,
+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=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_flags_set(vport,
+            OF_BSN_VPORT_L2GRE_LOCAL_MAC_IS_VALID |
+            OF_BSN_VPORT_L2GRE_DSCP_ASSIGN);
+        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_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);
+}
+-- java
+builder.setXid(0x01020304)
+    .setVport(
+        factory.buildBsnVportL2Gre()
+            .setFlags(
+                ImmutableSet.<OFBsnVportL2GreFlags>of(
+                    OFBsnVportL2GreFlags.BSN_VPORT_L2GRE_LOCAL_MAC_IS_VALID,
+                    OFBsnVportL2GreFlags.BSN_VPORT_L2GRE_DSCP_ASSIGN
+                )
+            )
+            .setPortNo(OFPort.of(1))
+            .setLocalMac(MacAddress.of("0a:0b:0c:0d:0e:0f"))
+            .setNhMac(MacAddress.of("01:02:03:04:05:06"))
+            .setSrcIp(IPv4Address.of("192.0.0.2"))
+            .setDstIp(IPv4Address.of("192.0.16.2"))
+            .setDscp((short)1)
+            .setTtl((short)64)
+            .setVpn(0xbeef)
+            .setIfName("foo")
+            .build()
+    );
diff --git a/test_data/of13/bsn_virtual_port_create_request__q_in_q.data b/test_data/of13/bsn_virtual_port_create_request__q_in_q.data
new file mode 100644
index 0000000..ca53fbe
--- /dev/null
+++ b/test_data/of13/bsn_virtual_port_create_request__q_in_q.data
@@ -0,0 +1,53 @@
+-- binary
+04 04           # version, type
+00 30           # len
+01 02 03 04     # xid
+00 5c 16 c7     # experimenter
+00 00 00 0f     # subtype
+00 00           # vport type
+00 20           # vport len
+00 00 00 01     # vport port no
+00 02           # vport ingress tpid
+00 03           # vport ingress vlan id
+00 04           # vport egress tpid
+00 05           # vport egress vlan id
+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_q_in_q(
+port_no=1,
+ingress_tpid=2,
+ingress_vlan_id=3,
+egress_tpid=4,
+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);
+}
+-- java
+builder.setXid(0x01020304)
+    .setVport(
+        factory.buildBsnVportQInQ()
+            .setPortNo(1)
+            .setIngressTpid(2)
+            .setIngressVlanId(3)
+            .setEgressTpid(4)
+            .setEgressVlanId(5)
+            .setIfName("foo")
+            .build()
+    );