Merge into master from pull request #104:
Wireshark dissector improvements (https://github.com/floodlight/loxigen/pull/104)
diff --git a/c_gen/templates/locitest/Makefile b/c_gen/templates/locitest/Makefile
index ed4ba13..a7a6f37 100644
--- a/c_gen/templates/locitest/Makefile
+++ b/c_gen/templates/locitest/Makefile
@@ -10,3 +10,6 @@
 
 locitest: $(OBJS)
 	$(CC) $^ -o $@
+
+# BSN build system magic
+MODULE := locitest
diff --git a/java_gen/codegen.py b/java_gen/codegen.py
index 776b8c5..4369b30 100644
--- a/java_gen/codegen.py
+++ b/java_gen/codegen.py
@@ -44,6 +44,8 @@
 import java_gen.java_model as java_model
 
 def gen_all_java(out, name):
+    # close the virtual file - we don't need it
+    out.close()
     basedir= '%s/openflowj' % of_g.options.install_dir
     print "Outputting to %s" % basedir
     if os.path.exists(basedir):
@@ -56,7 +58,6 @@
     gen.create_of_const_enums()
     gen.create_of_factories()
 
-    out.close()
 
 
 class JavaGenerator(object):
diff --git a/java_gen/java_model.py b/java_gen/java_model.py
index b9e3ee1..feb3c72 100644
--- a/java_gen/java_model.py
+++ b/java_gen/java_model.py
@@ -49,7 +49,7 @@
 class JavaModel(object):
     # registry for enums that should not be generated
     # set(${java_enum_name})
-    enum_blacklist = set(("OFDefinitions", "OFPortNo", "OFVlanId"))
+    enum_blacklist = set(("OFDefinitions", "OFPortNo", "OFVlanId", "OFGroup"))
     # registry for enum *entry* that should not be generated
     # map: ${java_enum_name} -> set(${java_entry_entry_name})
     enum_entry_blacklist = defaultdict(lambda: set(), OFFlowWildcards=set([ "NW_DST_BITS", "NW_SRC_BITS", "NW_SRC_SHIFT", "NW_DST_SHIFT" ]))
@@ -773,6 +773,10 @@
         return int(self.ir_class.params['align']) if 'align' in self.ir_class.params else 0
 
     @property
+    def length_includes_align(self):
+        return self.ir_class.params['length_includes_align'] == "True" if 'length_includes_align' in self.ir_class.params else False
+
+    @property
     @memoize
     def superclass(self):
         return find(lambda c: c.version == self.version and c.c_name == self.ir_class.superclass, model.all_classes)
@@ -895,9 +899,9 @@
     @property
     def priv_value(self):
         if self.name == "version":
-            return self.msg.version.int_version
+            return self.java_type.format_value(self.msg.version.int_version, pub_type=False)
         elif self.name == "length" or self.name == "len":
-            return self.msg.length
+            return self.java_type.format_value(self.msg.length, pub_type=False)
         else:
             return self.java_type.format_value(self.member.value, pub_type=False)
 
@@ -926,6 +930,8 @@
                 name = 'length'
             elif member.name == 'value_mask':
                 name = 'mask'
+            elif member.name == 'group_id':
+                name = 'group'
             else:
                 name = java_type.name_c_to_camel(member.name)
             j_type = java_type.convert_to_jtype(java_class.c_name, member.name, member.oftype)
@@ -999,16 +1005,23 @@
         self.java_class = java_class
         first_data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
                                                      name=java_class.c_name[3:])
-        data_file_template = "of{version}/{name}.".format(version=java_class.version.of_version,
-                                                     name=java_class.c_name[3:]) + "{i}.data"
+        glob_file_name = "of{version}/{name}__*.data".format(version=java_class.version.of_version,
+                                                     name=java_class.c_name[3:])
         test_class_name = self.java_class.name + "Test"
         self.test_units = []
         if test_data.exists(first_data_file_name):
             self.test_units.append(JavaUnitTest(java_class, first_data_file_name, test_class_name))
+
         i = 1
-        while test_data.exists(data_file_template.format(i=i)):
-            self.test_units.append(JavaUnitTest(java_class, data_file_template.format(i=i), test_class_name + str(i)))
-            i = i + 1
+        for f in test_data.glob(glob_file_name):
+            m = re.match(".*__(.*).data", f)
+            if m:
+                suffix = java_type.name_c_to_caps_camel(m.group(1))
+            else:
+                suffix = str(i)
+                i += 1
+            test_class_name = self.java_class.name + suffix + "Test"
+            self.test_units.append(JavaUnitTest(java_class, f, test_class_name))
 
     @property
     def package(self):
diff --git a/java_gen/java_type.py b/java_gen/java_type.py
index 6de71ba..331aeea 100644
--- a/java_gen/java_type.py
+++ b/java_gen/java_type.py
@@ -38,12 +38,12 @@
 ### info table about java primitive types, for casting literals in the source code
 # { name : (signed?, length_in_bits) }
 java_primitives_info = {
-        'boolean' : (False, 8),
-        'byte' : (True, 8),
-        'char' : (False, 16),
-        'short' : (True, 16),
-        'int' : (True, 32),
-        'long' : (True, 64),
+        'boolean' : (False, 8, False),
+        'byte' : (True, 8, True),
+        'char' : (False, 16, True),
+        'short' : (True, 16, True),
+        'int' : (True, 32, False),
+        'long' : (True, 64, False),
 }
 
 def format_primitive_literal(t, value):
@@ -52,7 +52,7 @@
         appropriately for correct representation despite Java's
         signed-craziness
     """
-    signed, bits = java_primitives_info[t]
+    signed, bits, cast_needed = java_primitives_info[t]
     max = (1 << bits)-1
     if value > max:
         raise Exception("Value %d to large for type %s" % (value, t))
@@ -65,20 +65,21 @@
                 return str((1 << bits) - value)
             else:
                 return "(%s) 0x%x" % (t, value)
-        else:
-            return "0x%x%s" % (value, "L" if t=="long" else "")
+    return "%s0x%x%s" % ("(%s) " % t if cast_needed else "", value, "L" if t=="long" else "")
+
 
 ANY = 0xFFFFFFFFFFFFFFFF
 
 class VersionOp:
-    def __init__(self, version=ANY, read=None, write=None, default=None):
+    def __init__(self, version=ANY, read=None, write=None, default=None, funnel=None):
         self.version = version
         self.read = read
         self.write = write
         self.default = default
+        self.funnel = funnel
 
     def __str__(self):
-        return "[Version: %d, Read: '%s', Write: '%s', Default: '%s' ]" % (self.version, self.read, self.write, self.default )
+        return "[Version: %d, Read: '%s', Write: '%s', Default: '%s', Funnel: '%s' ]" % (self.version, self.read, self.write, self.default, self.funnel )
 
 ### FIXME: This class should really be cleaned up
 class JType(object):
@@ -94,7 +95,11 @@
         self.priv_type = priv_type  # the internal storage type
         self.ops = {}
 
-    def op(self, version=ANY, read=None, write=None, default=None, pub_type=ANY):
+    def set_priv_type(self, priv_type):
+        self.priv_type = priv_type
+        return self
+
+    def op(self, version=ANY, read=None, write=None, default=None, funnel=None, pub_type=ANY):
         """
         define operations to be performed for reading and writing this type
         (when read_op, write_op is called). The operations 'read' and 'write'
@@ -110,7 +115,7 @@
 
         pub_types = [ pub_type ] if pub_type is not ANY else [ False, True ]
         for pub_type in pub_types:
-            self.ops[(version, pub_type)] = VersionOp(version, read, write, default)
+            self.ops[(version, pub_type)] = VersionOp(version, read, write, default, funnel)
         return self
 
     def format_value(self, value, pub_type=True):
@@ -136,6 +141,24 @@
         """ Is the private type different from the public one?"""
         return self.pub_type != self.priv_type
 
+    def get_op(self, op_type, version, pub_type, default_value, arguments):
+        ver = ANY if version is None else version.int_version
+
+        if not "version" in arguments:
+            arguments["version"] = version.of_version
+
+        def lookup(ver, pub_type):
+            if (ver, pub_type) in self.ops:
+                return getattr(self.ops[(ver, pub_type)], op_type)
+            else:
+                return None
+
+        _op = lookup(ver, pub_type) or lookup(ANY, pub_type) or default_value
+        if callable(_op):
+            return _op(**arguments)
+        else:
+            return reduce(lambda a,repl: a.replace("$%s" % repl[0], str(repl[1])),  arguments.items(), _op)
+
     def read_op(self, version=None, length=None, pub_type=True):
         """ return a Java stanza that reads a value of this JType from ChannelBuffer bb.
         @param version int - OF wire version to generate expression for
@@ -149,20 +172,12 @@
              # assumes that
              # (1) length of the message has been read to 'length'
              # (2) readerIndex at the start of the message has been stored in 'start'
-            length = "length - (bb.readerIndex() - start)";
+            length = "length - (bb.readerIndex() - start)"
 
-        ver = ANY if version is None else version.int_version
-        _read_op = None
-        if (ver, pub_type) in self.ops:
-            _read_op = self.ops[(ver, pub_type)].read or self.ops[(ANY, pub_type)].read
-        elif (ANY, pub_type) in self.ops:
-            _read_op = self.ops[(ANY, pub_type)].read
-        if _read_op is None:
-            _read_op = 'ChannelUtilsVer$version.read%s(bb)' % self.pub_type
-        if callable(_read_op):
-            return _read_op(version)
-        else:
-            return _read_op.replace("$length", str(length)).replace("$version", version.of_version)
+        return self.get_op("read", version, pub_type,
+            default_value='ChannelUtilsVer$version.read%s(bb)' % self.pub_type,
+            arguments=dict(length=length)
+            )
 
     def write_op(self, version=None, name=None, pub_type=True):
         """ return a Java stanza that writes a value of this JType contained in Java expression
@@ -172,37 +187,22 @@
         @param pub_type boolean use this JTypes 'public' (True), or private (False) representation
         @return string containing generated Java expression.
         """
-        ver = ANY if version is None else version.int_version
-        _write_op = None
-        if (ver, pub_type) in self.ops:
-            _write_op = self.ops[(ver, pub_type)].write or self.ops[(ANY, pub_type)].write
-        elif (ANY, pub_type) in self.ops:
-            _write_op = self.ops[(ANY, pub_type)].write
-        if _write_op is None:
 
-            _write_op = 'ChannelUtilsVer$version.write%s(bb, $name)' % self.pub_type
-        if callable(_write_op):
-            return _write_op(version, name)
-        else:
-            return _write_op.replace("$name", str(name)).replace("$version", version.of_version)
+        return self.get_op("write", version, pub_type,
+            default_value='ChannelUtilsVer$version.write%s(bb, $name)' % self.pub_type,
+            arguments=dict(name=name)
+            )
+
 
     def default_op(self, version=None, pub_type=True):
         """ return a Java stanza that returns a default value of this JType.
         @param version JavaOFVersion
         @return string containing generated Java expression.
         """
-        ver = ANY if version is None else version.int_version
-        _default_op = None
-        if (ver, pub_type) in self.ops:
-            _default_op = self.ops[(ver, pub_type)].default or self.ops[(ANY, pub_type)].default
-        elif (ANY, pub_type) in self.ops:
-            _default_op = self.ops[(ANY, pub_type)].default
-        if _default_op is None:
-            _default_op = self.format_value(0) if self.is_primitive else "null"
-        if callable(_default_op):
-            return _default_op(version, name)
-        else:
-            return _default_op.replace("$version", version.of_version)
+        return self.get_op("default", version, pub_type,
+            arguments = dict(),
+            default_value = self.format_value(0) if self.is_primitive else "null"
+        )
 
     def skip_op(self, version=None, length=None):
         """ return a java stanza that skips an instance of JType in the input ChannelBuffer 'bb'.
@@ -211,18 +211,68 @@
             Currently just delegates to read_op + throws away the result."""
         return self.read_op(version, length)
 
+    def funnel_op(self, version=None, name=None, pub_type=True):
+        t = self.pub_type if pub_type else self.priv_type
+        return self.get_op("funnel", version, pub_type,
+            arguments = dict(name=name),
+            default_value =  '$name.putTo(sink)' if not self._is_primitive(pub_type) else "sink.put{}($name)".format(t[0].upper() + t[1:])
+        )
+
     @property
     def is_primitive(self):
+        return self._is_primitive()
+
+    def _is_primitive(self, pub_type=True):
         """ return true if the pub_type is a java primitive type (and thus needs
         special treatment, because it doesn't have methods)"""
-        return self.pub_type in java_primitive_types
+        t = self.pub_type if pub_type else self.priv_type
+        return t in java_primitive_types
 
     @property
     def is_array(self):
-        """ return true iff the pub_type is a Java array (and thus requires special
-        treatment for equals / toString etc.) """
-        return self.pub_type.endswith("[]")
+        return self._is_array()
 
+    def _is_array(self, pub_type=True):
+        t = self.pub_type if pub_type else self.priv_type
+        return t.endswith("[]")
+
+# Create a default mapping for a list type. Type defauls to List<${java_mapping_of_name}>
+def gen_enum_jtype(java_name, is_bitmask=False):
+    if is_bitmask:
+        java_type = "Set<{}>".format(java_name)
+        default_value = "ImmutableSet.<{}>of()".format(java_name)
+    else:
+        java_type = java_name
+        default_value = "null"
+
+    serializer = "{}SerializerVer$version".format(java_name)
+
+    return JType(java_type)\
+            .op(read="{}.readFrom(bb)".format(serializer),
+                write="{}.writeTo(bb, $name)".format(serializer),
+                default=default_value,
+                funnel="{}.putTo($name, sink)".format(serializer)
+               )
+
+def gen_list_jtype(java_base_name):
+    # read op assumes the class has a public final static field READER that implements
+    # OFMessageReader<$class> i.e., can deserialize an instance of class from a ChannelBuffer
+    # write op assumes class implements Writeable
+    return JType("List<{}>".format(java_base_name)) \
+        .op(
+            read= 'ChannelUtils.readList(bb, $length, {}Ver$version.READER)'.format(java_base_name), \
+            write='ChannelUtils.writeList(bb, $name)',
+            default="ImmutableList.<{}>of()".format(java_base_name),
+            funnel='FunnelUtils.putList($name, sink)'
+            )
+
+def gen_fixed_length_string_jtype(length):
+    return JType('String').op(
+              read='ChannelUtils.readFixedLengthString(bb, {})'.format(length),
+              write='ChannelUtils.writeFixedLengthString(bb, $name, {})'.format(length),
+              default='""',
+              funnel='sink.putUnencodedChars($name)'
+            )
 
 ##### Predefined JType mappings
 # FIXME: This list needs to be pruned / cleaned up. Most of these are schematic.
@@ -231,7 +281,11 @@
         .op(read='U8.f(bb.readByte())', write='bb.writeByte(U8.t($name))', pub_type=True) \
         .op(read='bb.readByte()', write='bb.writeByte($name)', pub_type=False)
 u8_list =  JType('List<U8>') \
-        .op(read='ChannelUtils.readList(bb, $length, U8.READER)', write='ChannelUtils.writeList(bb, $name)')
+        .op(read='ChannelUtils.readList(bb, $length, U8.READER)',
+            write='ChannelUtils.writeList(bb, $name)',
+            default='ImmutableList.<U8>of()',
+            funnel='FunnelUtils.putList($name, sink)'
+           )
 u16 = JType('int', 'short') \
         .op(read='U16.f(bb.readShort())', write='bb.writeShort(U16.t($name))', pub_type=True) \
         .op(read='bb.readShort()', write='bb.writeShort($name)', pub_type=False)
@@ -242,7 +296,8 @@
         .op(
                 read='ChannelUtils.readList(bb, $length, U32.READER)',
                 write='ChannelUtils.writeList(bb, $name)',
-                default="ImmutableList.<U32>of()");
+                default="ImmutableList.<U32>of()",
+                funnel="FunnelUtils.putList($name, sink)")
 u8obj = JType('U8', 'U8') \
         .op(read='U8.of(bb.readByte())', write='bb.writeByte($name.getRaw())', default="U8.ZERO")
 u32obj = JType('U32', 'U32') \
@@ -255,33 +310,20 @@
 # the same OFPort, but with a default value of ZERO, only for OF10 match
 of_port_match_v1 = JType("OFPort") \
          .op(version=1, read="OFPort.read2Bytes(bb)", write="$name.write2Bytes(bb)", default="OFPort.ZERO")
-actions_list = JType('List<OFAction>') \
-        .op(read='ChannelUtils.readList(bb, $length, OFActionVer$version.READER)',
-            write='ChannelUtils.writeList(bb, $name);',
-            default='ImmutableList.<OFAction>of()')
-instructions_list = JType('List<OFInstruction>') \
-        .op(read='ChannelUtils.readList(bb, $length, OFInstructionVer$version.READER)', \
-            write='ChannelUtils.writeList(bb, $name)',
-            default='ImmutableList.<OFInstruction>of()')
-buckets_list = JType('List<OFBucket>') \
-        .op(read='ChannelUtils.readList(bb, $length, OFBucketVer$version.READER)',
-            write='ChannelUtils.writeList(bb, $name)',
-            default='ImmutableList.<OFBucket>of()')
-port_desc_list = JType('List<OFPortDesc>') \
-        .op(read='ChannelUtils.readList(bb, $length, OFPortDescVer$version.READER)',
-            write='ChannelUtils.writeList(bb, $name)',
-            default='ImmutableList.<OFPortDesc>of()')
+actions_list = gen_list_jtype("OFAction")
+instructions_list = gen_list_jtype("OFInstruction")
+buckets_list = gen_list_jtype("OFBucket")
+port_desc_list = gen_list_jtype("OFPortDesc")
+packet_queue_list = gen_list_jtype("OFPacketQueue")
 port_desc = JType('OFPortDesc') \
         .op(read='OFPortDescVer$version.READER.readFrom(bb)', \
             write='$name.writeTo(bb)')
-packet_queue_list = JType('List<OFPacketQueue>') \
-        .op(read='ChannelUtils.readList(bb, $length, OFPacketQueueVer$version.READER)',
-            write='ChannelUtils.writeList(bb, $name);',
-            default='ImmutableList.<OFPacketQueue>of()')
-octets = JType('byte[]') \
+octets = JType('byte[]')\
         .op(read='ChannelUtils.readBytes(bb, $length)', \
             write='bb.writeBytes($name)', \
-            default="new byte[0]");
+            default="new byte[0]",
+            funnel="sink.putBytes($name)"
+            );
 of_match = JType('Match') \
         .op(read='ChannelUtilsVer$version.readOFMatch(bb)', \
             write='$name.writeTo(bb)',
@@ -293,22 +335,11 @@
         .op(read="MacAddress.read6Bytes(bb)", \
             write="$name.write6Bytes(bb)",
             default="MacAddress.NONE")
-port_name = JType('String') \
-        .op(read='ChannelUtils.readFixedLengthString(bb, 16)', \
-            write='ChannelUtils.writeFixedLengthString(bb, $name, 16)',
-            default='""')
-desc_str = JType('String') \
-        .op(read='ChannelUtils.readFixedLengthString(bb, 256)', \
-            write='ChannelUtils.writeFixedLengthString(bb, $name, 256)',
-            default='""')
-serial_num = JType('String') \
-        .op(read='ChannelUtils.readFixedLengthString(bb, 32)', \
-            write='ChannelUtils.writeFixedLengthString(bb, $name, 32)',
-            default='""')
-table_name = JType('String') \
-        .op(read='ChannelUtils.readFixedLengthString(bb, 32)', \
-            write='ChannelUtils.writeFixedLengthString(bb, $name, 32)',
-            default='""')
+
+port_name = gen_fixed_length_string_jtype(16)
+desc_str = gen_fixed_length_string_jtype(256)
+serial_num = gen_fixed_length_string_jtype(32)
+table_name = gen_fixed_length_string_jtype(32)
 ipv4 = JType("IPv4Address") \
         .op(read="IPv4Address.read4Bytes(bb)", \
             write="$name.write4Bytes(bb)",
@@ -317,9 +348,7 @@
         .op(read="IPv6Address.read16Bytes(bb)", \
             write="$name.write16Bytes(bb)",
             default='IPv6Address.NONE')
-packetin_reason = JType("OFPacketInReason")\
-        .op(read="OFPacketInReasonSerializerVer$version.readFrom(bb)",
-            write="OFPacketInReasonSerializerVer$version.writeTo(bb, $name)")
+packetin_reason = gen_enum_jtype("OFPacketInReason")
 transport_port = JType("TransportPort")\
         .op(read="TransportPort.read2Bytes(bb)",
             write="$name.write2Bytes(bb)",
@@ -403,6 +432,16 @@
 
 port_speed = JType("PortSpeed")
 error_type = JType("OFErrorType")
+of_type = JType("OFType", 'byte') \
+            .op(read='bb.readByte()', write='bb.writeByte($name)')
+action_type= gen_enum_jtype("OFActionType")\
+               .set_priv_type("short")\
+               .op(read='bb.readShort()', write='bb.writeShort($name)', pub_type=False)
+instruction_type = gen_enum_jtype("OFInstructionType")\
+               .set_priv_type('short') \
+               .op(read='bb.readShort()', write='bb.writeShort($name)', pub_type=False)
+buffer_id = JType("OFBufferId") \
+            .op(read="OFBufferId.of(bb.readInt())", write="bb.writeInt($name.getInt())", default="OFBufferId.NO_BUFFER")
 boolean = JType("boolean", "byte") \
         .op(read='(bb.readByte() != 0)',
             write='bb.writeByte($name ? 1 : 0)',
@@ -411,6 +450,18 @@
         .op(read='DatapathId.of(bb.readLong())',
             write='bb.writeLong($name.getLong())',
             default='DatapathId.NONE')
+action_type_set = JType("Set<OFActionType>") \
+        .op(read='ChannelUtilsVer10.readSupportedActions(bb)',
+            write='ChannelUtilsVer10.writeSupportedActions(bb, $name)',
+            default='ImmutableSet.<OFActionType>of()',
+            funnel='ChannelUtilsVer10.putSupportedActionsTo($name, sink)')
+of_group = JType("OFGroup") \
+         .op(version=ANY, read="OFGroup.read4Bytes(bb)", write="$name.write4Bytes(bb)", default="OFGroup.ALL")
+# the outgroup field of of_flow_stats_request has a special default value
+of_group_default_any = JType("OFGroup") \
+         .op(version=ANY, read="OFGroup.read4Bytes(bb)", write="$name.write4Bytes(bb)", default="OFGroup.ANY")
+buffer_id = JType("OFBufferId") \
+         .op(read="OFBufferId.of(bb.readInt())", write="bb.writeInt($name.getInt())", default="OFBufferId.NO_BUFFER")
 
 generic_t = JType("T")
 
@@ -497,7 +548,7 @@
         'of_oxm_mpls_label_masked' : { 'value' : u32obj, 'value_mask' : u32obj },
         'of_oxm_mpls_tc' : { 'value' : u8obj },
         'of_oxm_mpls_tc_masked' : { 'value' : u8obj, 'value_mask' : u8obj },
-        
+
         'of_oxm_bsn_in_ports_128' : { 'value': port_bitmap },
         'of_oxm_bsn_in_ports_128_masked' : { 'value': port_bitmap, 'value_mask': port_bitmap },
 
@@ -509,6 +560,8 @@
                 },
         'of_bsn_set_l2_table_request': { 'l2_table_enable': boolean },
         'of_bsn_set_l2_table_reply': { 'l2_table_enable': boolean },
+        'of_bsn_set_pktin_suppression_request': { 'enabled': boolean },
+        'of_flow_stats_request': { 'out_group': of_group_default_any },
 }
 
 
@@ -519,41 +572,20 @@
     for protocol in of_g.ir.values():
         for enum in protocol.enums:
             java_name = name_c_to_caps_camel(re.sub(r'_t$', "", enum.name))
-            if enum.is_bitmask:
-                java_type = "Set<{}>".format(java_name)
-                default_value = "ImmutableSet.<{}>of()".format(java_name)
-            else:
-                java_type = java_name
-                default_value = "null"
-            enum_types[enum.name] = \
-                    JType(java_type)\
-                      .op(read="{}SerializerVer$version.readFrom(bb)".format(java_name),
-                          write="{}SerializerVer$version.writeTo(bb, $name)".format(java_name),
-                          default=default_value)
+
+            enum_types[enum.name] = gen_enum_jtype(java_name, enum.is_bitmask)
     return enum_types
 
 def make_match_field_jtype(sub_type_name="?"):
     return JType("MatchField<{}>".format(sub_type_name))
 
 
-# Create a default mapping for a list type. Type defauls to List<${java_mapping_of_name}>
-def make_standard_list_jtype(c_type):
+def list_cname_to_java_name(c_type):
     m = re.match(r'list\(of_([a-zA-Z_]+)_t\)', c_type)
     if not m:
         raise Exception("Not a recgonized standard list type declaration: %s" % c_type)
     base_name = m.group(1)
-    java_base_name = name_c_to_caps_camel(base_name)
-
-    # read op assumes the class has a public final static field READER that implements
-    # OFMessageReader<$class> i.e., can deserialize an instance of class from a ChannelBuffer
-    # write op assumes class implements Writeable
-    return JType("List<OF{}>".format(java_base_name)) \
-        .op(
-            read= 'ChannelUtils.readList(bb, $length, OF{}Ver$version.READER)'.format(java_base_name), \
-            write='ChannelUtils.writeList(bb, $name)',
-            default="ImmutableList.<OF{}>of()".format(java_base_name)
-            )
-
+    return "OF" + name_c_to_caps_camel(base_name)
 
 
 #### main entry point for conversion of LOXI types (c_types) Java types.
@@ -565,12 +597,9 @@
     if obj_name in exceptions and field_name in exceptions[obj_name]:
         return exceptions[obj_name][field_name]
     elif ( obj_name == "of_header" or loxi_utils.class_is_message(obj_name)) and field_name == "type" and c_type == "uint8_t":
-        return JType("OFType", 'byte') \
-            .op(read='bb.readByte()', write='bb.writeByte($name)')
+        return of_type
     elif field_name == "type" and re.match(r'of_action.*', obj_name):
-        return JType("OFActionType", 'short') \
-            .op(read='bb.readShort()', write='bb.writeShort($name)', pub_type=False)\
-            .op(read="OFActionTypeSerializerVer$version.readFrom(bb)", write="OFActionTypeSerializerVer$version.writeTo(bb, $name)", pub_type=True)
+        return action_type
     elif field_name == "err_type":
         return JType("OFErrorType", 'short') \
             .op(read='bb.readShort()', write='bb.writeShort($name)')
@@ -578,9 +607,7 @@
         return JType("OFStatsType", 'short') \
             .op(read='bb.readShort()', write='bb.writeShort($name)')
     elif field_name == "type" and re.match(r'of_instruction.*', obj_name):
-        return JType("OFInstructionType", 'short') \
-            .op(read='bb.readShort()', write='bb.writeShort($name)', pub_type=False)\
-            .op(read="OFInstructionTypeSerializerVer$version.readFrom(bb)", write="OFInstructionTypeSerializerVer$version.writeTo(bb, $name)", pub_type=True)
+        return instruction_type
     elif obj_name in ("of_flow_add", "of_flow_modify", "of_flow_modify_strict", "of_delete_strict") and  field_name == "table_id" and c_type == "uint8_t":
         return table_id_default_zero
     elif field_name == "table_id" and c_type == "uint8_t":
@@ -588,19 +615,17 @@
     elif field_name == "version" and c_type == "uint8_t":
         return of_version
     elif field_name == "buffer_id" and c_type == "uint32_t":
-        return JType("OFBufferId") \
-            .op(read="OFBufferId.of(bb.readInt())", write="bb.writeInt($name.getInt())", default="OFBufferId.NO_BUFFER")
+        return buffer_id
+    elif field_name == "group_id" and c_type == "uint32_t":
+        return of_group
     elif field_name == 'datapath_id':
         return datapath_id
     elif field_name == 'actions' and obj_name == 'of_features_reply':
-        return JType("Set<OFActionType>") \
-            .op(read='ChannelUtilsVer10.readSupportedActions(bb)',
-                write='ChannelUtilsVer10.writeSupportedActions(bb, $name)',
-                default='ImmutableSet.<OFActionType>of()')
+        return action_type_set
     elif c_type in default_mtype_to_jtype_convert_map:
         return default_mtype_to_jtype_convert_map[c_type]
     elif re.match(r'list\(of_([a-zA-Z_]+)_t\)', c_type):
-        return make_standard_list_jtype(c_type)
+        return gen_list_jtype(list_cname_to_java_name(c_type))
     elif c_type in enum_java_types():
         return enum_java_types()[c_type]
     else:
diff --git a/java_gen/pre-written/pom.xml b/java_gen/pre-written/pom.xml
index ea9a43f..5715704 100644
--- a/java_gen/pre-written/pom.xml
+++ b/java_gen/pre-written/pom.xml
@@ -10,7 +10,7 @@
 
     <groupId>org.projectfloodlight</groupId>
     <artifactId>openflowj</artifactId>
-    <version>0.2.0-SNAPSHOT</version>
+    <version>0.3.0-SNAPSHOT</version>
     <packaging>jar</packaging>
 
     <name>OpenFlowJ-Loxi</name>
@@ -37,12 +37,12 @@
         <dependency>
             <groupId>com.google.code.findbugs</groupId>
             <artifactId>annotations</artifactId>
-            <version>2.0.1</version>
+            <version>2.0.2</version>
         </dependency>
         <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
-            <version>4.8.2</version>
+            <version>4.11</version>
             <scope>test</scope>
         </dependency>
         <dependency>
@@ -53,7 +53,7 @@
         <dependency>
             <groupId>com.google.guava</groupId>
             <artifactId>guava</artifactId>
-            <version>14.0.1</version>
+            <version>15.0</version>
         </dependency>
     </dependencies>
     <build>
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/OFMatchBmap.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/OFMatchBmap.java
index e17796a..68ca86d 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/OFMatchBmap.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/OFMatchBmap.java
@@ -1,5 +1,13 @@
 package org.projectfloodlight.openflow.protocol;
 
-public class OFMatchBmap {
+import org.projectfloodlight.openflow.types.PrimitiveSinkable;
+
+import com.google.common.hash.PrimitiveSink;
+
+public class OFMatchBmap implements PrimitiveSinkable{
+
+    @Override
+    public void putTo(PrimitiveSink sink) {
+    }
 
 }
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/OFObject.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/OFObject.java
index 852b803..5d37987 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/OFObject.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/OFObject.java
@@ -1,9 +1,11 @@
 package org.projectfloodlight.openflow.protocol;
 
+import org.projectfloodlight.openflow.types.PrimitiveSinkable;
+
 
 /**
  * Base interface of all OpenFlow objects (e.g., messages, actions, stats, etc.)
  */
-public interface OFObject extends Writeable {
+public interface OFObject extends Writeable, PrimitiveSinkable {
     OFVersion getVersion();
 }
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/OFOxmList.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/OFOxmList.java
index ac48c8d..c6ba116 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/OFOxmList.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/OFOxmList.java
@@ -9,13 +9,15 @@
 import org.projectfloodlight.openflow.exceptions.OFParseError;
 import org.projectfloodlight.openflow.protocol.match.MatchField;
 import org.projectfloodlight.openflow.protocol.match.MatchFields;
-import org.projectfloodlight.openflow.types.OFValueType;
-import org.projectfloodlight.openflow.util.ChannelUtils;
 import org.projectfloodlight.openflow.protocol.oxm.OFOxm;
+import org.projectfloodlight.openflow.types.OFValueType;
+import org.projectfloodlight.openflow.types.PrimitiveSinkable;
+import org.projectfloodlight.openflow.util.ChannelUtils;
 
 import com.google.common.collect.ImmutableMap;
+import com.google.common.hash.PrimitiveSink;
 
-public class OFOxmList implements Iterable<OFOxm<?>>, Writeable {
+public class OFOxmList implements Iterable<OFOxm<?>>, Writeable, PrimitiveSinkable {
     private final Map<MatchFields, OFOxm<?>> oxmMap;
 
     public final static OFOxmList EMPTY = new OFOxmList(ImmutableMap.<MatchFields, OFOxm<?>>of());
@@ -124,5 +126,12 @@
         return "OFOxmList" + oxmMap;
     }
 
+    @Override
+    public void putTo(PrimitiveSink sink) {
+        for (OFOxm<?> o : this) {
+            o.putTo(sink);
+        }
+    }
+
 
 }
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/ver10/ChannelUtilsVer10.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/ver10/ChannelUtilsVer10.java
index 3f2f23f..ed7c0c8 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/ver10/ChannelUtilsVer10.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/ver10/ChannelUtilsVer10.java
@@ -5,10 +5,11 @@
 
 import org.jboss.netty.buffer.ChannelBuffer;
 import org.projectfloodlight.openflow.exceptions.OFParseError;
-import org.projectfloodlight.openflow.protocol.match.Match;
-import org.projectfloodlight.openflow.protocol.ver10.OFMatchV1Ver10;
 import org.projectfloodlight.openflow.protocol.OFActionType;
 import org.projectfloodlight.openflow.protocol.OFBsnVportQInQ;
+import org.projectfloodlight.openflow.protocol.match.Match;
+
+import com.google.common.hash.PrimitiveSink;
 
 /**
  * Collection of helper functions for reading and writing into ChannelBuffers
@@ -62,8 +63,7 @@
         return supportedActions;
     }
 
-    public static void writeSupportedActions(ChannelBuffer bb,
-            Set<OFActionType> supportedActions) {
+    public static int supportedActionsToWire(Set<OFActionType> supportedActions) {
         int supportedActionsVal = 0;
         if (supportedActions.contains(OFActionType.OUTPUT))
             supportedActionsVal |= (1 << OFActionTypeSerializerVer10.OUTPUT_VAL);
@@ -89,6 +89,15 @@
             supportedActionsVal |= (1 << OFActionTypeSerializerVer10.SET_TP_DST_VAL);
         if (supportedActions.contains(OFActionType.ENQUEUE))
             supportedActionsVal |= (1 << OFActionTypeSerializerVer10.ENQUEUE_VAL);
-        bb.writeInt(supportedActionsVal);
+        return supportedActionsVal;
     }
+
+    public static void putSupportedActionsTo(Set<OFActionType> supportedActions, PrimitiveSink sink) {
+        sink.putInt(supportedActionsToWire(supportedActions));
+    }
+
+    public static void writeSupportedActions(ChannelBuffer bb, Set<OFActionType> supportedActions) {
+        bb.writeInt(supportedActionsToWire(supportedActions));
+    }
+
 }
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/ArpOpcode.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/ArpOpcode.java
index c8999b8..bfedaeb 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/ArpOpcode.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/ArpOpcode.java
@@ -2,6 +2,7 @@
 
 import org.jboss.netty.buffer.ChannelBuffer;
 
+import com.google.common.hash.PrimitiveSink;
 import com.google.common.primitives.UnsignedInts;
 
 public class ArpOpcode implements OFValueType<ArpOpcode> {
@@ -189,4 +190,9 @@
         return UnsignedInts.compare(opcode, o.opcode);
     }
 
+    @Override
+    public void putTo(PrimitiveSink sink) {
+        sink.putShort((short) this.opcode);
+    }
+
 }
\ No newline at end of file
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/ClassId.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/ClassId.java
index a6f2106..72ed3da 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/ClassId.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/ClassId.java
@@ -2,6 +2,7 @@
 
 import javax.annotation.concurrent.Immutable;
 
+import com.google.common.hash.PrimitiveSink;
 import com.google.common.primitives.UnsignedInts;
 
 @Immutable
@@ -68,4 +69,9 @@
     public int compareTo(ClassId o) {
         return UnsignedInts.compare(rawValue, rawValue);
     }
+
+    @Override
+    public void putTo(PrimitiveSink sink) {
+        sink.putInt(rawValue);
+    }
 }
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/DatapathId.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/DatapathId.java
index aa7191a..79fa14f 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/DatapathId.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/DatapathId.java
@@ -1,14 +1,20 @@
 package org.projectfloodlight.openflow.types;
 
+import org.projectfloodlight.openflow.annotations.Immutable;
 import org.projectfloodlight.openflow.util.HexString;
 
+import com.google.common.hash.PrimitiveSink;
+import com.google.common.primitives.Longs;
+import com.google.common.primitives.UnsignedLongs;
+
 /**
  * Abstraction of a datapath ID that can be set and/or accessed as either a
- * long value or a colon-separated string.
- * 
+ * long value or a colon-separated string. Immutable
+ *
  * @author Rob Vaterlaus <rob.vaterlaus@bigswitch.com>
  */
-public class DatapathId {
+@Immutable
+public class DatapathId implements PrimitiveSinkable, Comparable<DatapathId> {
 
     public static final DatapathId NONE = new DatapathId(0);
 
@@ -26,6 +32,10 @@
         return new DatapathId(HexString.toLong(s));
     }
 
+    public static DatapathId of(byte[] bytes) {
+        return new DatapathId(Longs.fromByteArray(bytes));
+    }
+
     public long getLong() {
         return rawValue;
     }
@@ -34,6 +44,10 @@
         return U64.of(rawValue);
     }
 
+    public byte[] getBytes() {
+        return Longs.toByteArray(rawValue);
+    }
+
     @Override
     public String toString() {
         return HexString.toHexString(rawValue);
@@ -60,4 +74,14 @@
             return false;
         return true;
     }
+
+    @Override
+    public void putTo(PrimitiveSink sink) {
+        sink.putLong(rawValue);
+    }
+
+    @Override
+    public int compareTo(DatapathId o) {
+        return UnsignedLongs.compare(rawValue, o.rawValue);
+    }
 }
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/EthType.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/EthType.java
index 7031a0d..c5f4f86 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/EthType.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/EthType.java
@@ -2,6 +2,7 @@
 
 import org.jboss.netty.buffer.ChannelBuffer;
 
+import com.google.common.hash.PrimitiveSink;
 import com.google.common.primitives.UnsignedInts;
 
 
@@ -260,5 +261,10 @@
         return UnsignedInts.compare(rawValue, o.rawValue);
     }
 
+    @Override
+    public void putTo(PrimitiveSink sink) {
+        sink.putInt(rawValue);
+    }
+
 
 }
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/ICMPv4Code.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/ICMPv4Code.java
index c66486f..6466eee 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/ICMPv4Code.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/ICMPv4Code.java
@@ -2,6 +2,7 @@
 
 import org.jboss.netty.buffer.ChannelBuffer;
 
+import com.google.common.hash.PrimitiveSink;
 import com.google.common.primitives.Shorts;
 
 /**
@@ -84,4 +85,9 @@
     public int compareTo(ICMPv4Code o) {
         return Shorts.compare(code, o.code);
     }
+
+    @Override
+    public void putTo(PrimitiveSink sink) {
+        sink.putShort(code);
+    }
 }
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/ICMPv4Type.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/ICMPv4Type.java
index bfd0d99..a0aa152 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/ICMPv4Type.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/ICMPv4Type.java
@@ -2,6 +2,7 @@
 
 import org.jboss.netty.buffer.ChannelBuffer;
 
+import com.google.common.hash.PrimitiveSink;
 import com.google.common.primitives.Shorts;
 
 public class ICMPv4Type implements OFValueType<ICMPv4Type> {
@@ -193,4 +194,10 @@
     public int compareTo(ICMPv4Type o) {
         return Shorts.compare(type, o.type);
     }
+
+    @Override
+    public void putTo(PrimitiveSink sink) {
+        sink.putShort(type);
+    }
+
 }
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv4Address.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv4Address.java
index 77b792f..51d10f3 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv4Address.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv4Address.java
@@ -4,6 +4,7 @@
 
 import org.jboss.netty.buffer.ChannelBuffer;
 
+import com.google.common.hash.PrimitiveSink;
 import com.google.common.primitives.UnsignedInts;
 
 
@@ -152,4 +153,10 @@
     public int compareTo(IPv4Address o) {
         return UnsignedInts.compare(rawValue, o.rawValue);
     }
+
+    @Override
+    public void putTo(PrimitiveSink sink) {
+        sink.putInt(rawValue);
+    }
+
 }
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv6Address.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv6Address.java
index b58de1a..1aad85b 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv6Address.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv6Address.java
@@ -5,6 +5,7 @@
 import org.jboss.netty.buffer.ChannelBuffer;
 import org.projectfloodlight.openflow.exceptions.OFParseError;
 
+import com.google.common.hash.PrimitiveSink;
 import com.google.common.primitives.Longs;
 
 /**
@@ -308,4 +309,10 @@
         else
             return Longs.compare(raw2, o.raw2);
     }
+
+    @Override
+    public void putTo(PrimitiveSink sink) {
+        sink.putLong(raw1);
+        sink.putLong(raw2);
+    }
 }
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv6FlowLabel.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv6FlowLabel.java
index 45bbf4b..de49b51 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv6FlowLabel.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IPv6FlowLabel.java
@@ -3,6 +3,7 @@
 import org.jboss.netty.buffer.ChannelBuffer;
 import org.projectfloodlight.openflow.exceptions.OFParseError;
 
+import com.google.common.hash.PrimitiveSink;
 import com.google.common.primitives.UnsignedInts;
 
 public class IPv6FlowLabel implements OFValueType<IPv6FlowLabel> {
@@ -76,4 +77,9 @@
     public int compareTo(IPv6FlowLabel o) {
         return UnsignedInts.compare(label, o.label);
     }
+
+    @Override
+    public void putTo(PrimitiveSink sink) {
+        sink.putInt(this.label);
+    }
 }
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IpDscp.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IpDscp.java
index ec78315..27596b7 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IpDscp.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IpDscp.java
@@ -3,6 +3,8 @@
 import org.jboss.netty.buffer.ChannelBuffer;
 import org.projectfloodlight.openflow.exceptions.OFParseError;
 
+import com.google.common.hash.PrimitiveSink;
+
 public enum IpDscp implements OFValueType<IpDscp> {
     DSCP_0((byte)0),
     DSCP_1((byte)1),
@@ -244,4 +246,9 @@
     public byte getDscpValue() {
         return dscp;
     }
+
+    @Override
+    public void putTo(PrimitiveSink sink) {
+        sink.putByte(dscp);
+    }
 }
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IpEcn.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IpEcn.java
index 7e1cdf0..654df01 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IpEcn.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IpEcn.java
@@ -3,6 +3,8 @@
 import org.jboss.netty.buffer.ChannelBuffer;
 import org.projectfloodlight.openflow.exceptions.OFParseError;
 
+import com.google.common.hash.PrimitiveSink;
+
 public enum IpEcn implements OFValueType<IpEcn> {
     ECN_00((byte)0),
     ECN_01((byte)1),
@@ -63,4 +65,9 @@
     public byte getEcnValue() {
         return ecn;
     }
+
+    @Override
+    public void putTo(PrimitiveSink sink) {
+        sink.putByte(ecn);
+    }
 }
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IpProtocol.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IpProtocol.java
index b9eae68..69f497e 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IpProtocol.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/IpProtocol.java
@@ -2,6 +2,7 @@
 
 import org.jboss.netty.buffer.ChannelBuffer;
 
+import com.google.common.hash.PrimitiveSink;
 import com.google.common.primitives.Shorts;
 
 /**
@@ -655,4 +656,10 @@
         return Shorts.compare(proto, o.proto);
     }
 
+
+    @Override
+    public void putTo(PrimitiveSink sink) {
+        sink.putShort(proto);
+    }
+
 }
\ No newline at end of file
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/LagId.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/LagId.java
index b7f7f67..2046d71 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/LagId.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/LagId.java
@@ -4,6 +4,7 @@
 
 import org.jboss.netty.buffer.ChannelBuffer;
 
+import com.google.common.hash.PrimitiveSink;
 import com.google.common.primitives.UnsignedInts;
 
 @Immutable
@@ -72,4 +73,9 @@
     public LagId applyMask(LagId mask) {
         return LagId.of(rawValue & mask.rawValue);
     }
+
+    @Override
+    public void putTo(PrimitiveSink sink) {
+        sink.putInt(rawValue);
+    }
 }
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/MacAddress.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/MacAddress.java
index 87be7c2..aaa31eb 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/MacAddress.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/MacAddress.java
@@ -4,6 +4,7 @@
 import org.projectfloodlight.openflow.exceptions.OFParseError;
 import org.projectfloodlight.openflow.util.HexString;
 
+import com.google.common.hash.PrimitiveSink;
 import com.google.common.primitives.Longs;
 
 /**
@@ -19,6 +20,9 @@
     private final static long NONE_VAL = 0x0L;
     public static final MacAddress NONE = new MacAddress(NONE_VAL);
 
+    private final static long BROADCAST_VAL = 0x0000FFFFFFFFFFFFL;
+    public static final MacAddress BROADCAST = new MacAddress(BROADCAST_VAL);
+
     public static final MacAddress NO_MASK = MacAddress.of(0xFFFFFFFFFFFFFFFFl);
     public static final MacAddress FULL_MASK = MacAddress.of(0x0);
 
@@ -27,6 +31,9 @@
     }
 
     public static MacAddress of(final byte[] address) {
+        if (address.length != MacAddrLen)
+            throw new IllegalArgumentException(
+                    "Mac address byte array must be exactly 6 bytes long; length = " + address.length);
         long raw =
                 (address[0] & 0xFFL) << 40 | (address[1] & 0xFFL) << 32
                         | (address[2] & 0xFFL) << 24 | (address[3] & 0xFFL) << 16
@@ -34,30 +41,36 @@
         return MacAddress.of(raw);
     }
 
-    public static MacAddress of(final long raw) {
+    public static MacAddress of(long raw) {
+        raw &= BROADCAST_VAL;
         if(raw == NONE_VAL)
             return NONE;
-
+        if (raw == BROADCAST_VAL)
+            return BROADCAST;
         return new MacAddress(raw);
     }
 
     public static MacAddress of(final String string) {
         int index = 0;
         int shift = 40;
+        final String FORMAT_ERROR = "Mac address is not well-formed. " +
+                "It must consist of 6 hex digit pairs separated by colons: ";
 
         long raw = 0;
         if (string.length() != 6 * 2 + 5)
-            throw new IllegalArgumentException("Mac address not well formed: " + string);
+            throw new IllegalArgumentException(FORMAT_ERROR + string);
 
         while (shift >= 0) {
-            raw |=
-                    ((long) (Character.digit(string.charAt(index++), 16) << 4 | Character
-                            .digit(string.charAt(index++), 16))) << shift;
+            int digit1 = Character.digit(string.charAt(index++), 16);
+            int digit2 = Character.digit(string.charAt(index++), 16);
+            if ((digit1 < 0) || (digit2 < 0))
+                throw new IllegalArgumentException(FORMAT_ERROR + string);
+            raw |= ((long) (digit1 << 4 | digit2)) << shift;
 
             if (shift == 0)
                 break;
             if (string.charAt(index++) != ':')
-                throw new IllegalArgumentException("Mac address not well formed: " + string);
+                throw new IllegalArgumentException(FORMAT_ERROR + string);
             shift -= 8;
         }
         return MacAddress.of(raw);
@@ -82,6 +95,25 @@
         return bytesCache;
     }
 
+    /**
+     * Returns {@code true} if the MAC address is the broadcast address.
+     * @return {@code true} if the MAC address is the broadcast address.
+     */
+    public boolean isBroadcast() {
+        return this == BROADCAST;
+    }
+
+    /**
+     * Returns {@code true} if the MAC address is a multicast address.
+     * @return {@code true} if the MAC address is a multicast address.
+     */
+    public boolean isMulticast() {
+        if (isBroadcast()) {
+            return false;
+        }
+        return (rawValue & (0x01L << 40)) != 0;
+    }
+
     @Override
     public int getLength() {
         return MacAddrLen;
@@ -138,6 +170,12 @@
         return Longs.compare(rawValue, o.rawValue);
     }
 
+    @Override
+    public void putTo(PrimitiveSink sink) {
+        sink.putInt((int) (this.rawValue >> 16));
+        sink.putShort((short) (this.rawValue & 0xFFFF));
+    }
+
 
 
 }
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/Masked.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/Masked.java
index 4d88793..ea2317a 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/Masked.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/Masked.java
@@ -1,5 +1,7 @@
 package org.projectfloodlight.openflow.types;
 
+import com.google.common.hash.PrimitiveSink;
+
 
 
 public class Masked<T extends OFValueType<T>> implements OFValueType<Masked<T>> {
@@ -66,4 +68,10 @@
         else
             return mask.compareTo(o.mask);
     }
+
+    @Override
+    public void putTo(PrimitiveSink sink) {
+        value.putTo(sink);
+        mask.putTo(sink);
+    }
 }
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFBitMask128.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFBitMask128.java
index 2827a72..5cec233 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFBitMask128.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFBitMask128.java
@@ -2,6 +2,8 @@
 
 import org.jboss.netty.buffer.ChannelBuffer;
 
+import com.google.common.hash.PrimitiveSink;
+
 public class OFBitMask128 implements OFValueType<OFBitMask128> {
 
     static final int LENGTH = 16;
@@ -89,4 +91,10 @@
         return Long.signum(this.raw2 - o.raw2);
     }
 
+    @Override
+    public void putTo(PrimitiveSink sink) {
+        sink.putLong(raw1);
+        sink.putLong(raw2);
+    }
+
 }
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFBufferId.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFBufferId.java
index f541b61..7f76b4d 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFBufferId.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFBufferId.java
@@ -1,9 +1,8 @@
 package org.projectfloodlight.openflow.types;
 
-import org.jboss.netty.buffer.ChannelBuffer;
 import org.projectfloodlight.openflow.annotations.Immutable;
-import org.projectfloodlight.openflow.exceptions.OFParseError;
 
+import com.google.common.hash.PrimitiveSink;
 import com.google.common.primitives.UnsignedInts;
 
 /**
@@ -12,7 +11,7 @@
  * @author Rob Vaterlaus <rob.vaterlaus@bigswitch.com>
  */
 @Immutable
-public class OFBufferId implements Comparable<OFBufferId> {
+public class OFBufferId implements Comparable<OFBufferId>, PrimitiveSinkable {
     public static final OFBufferId NO_BUFFER = new OFBufferId(0xFFFFFFFF);
 
     private final int rawValue;
@@ -62,4 +61,9 @@
     public int compareTo(OFBufferId o) {
         return UnsignedInts.compare(rawValue, o.rawValue);
     }
+
+    @Override
+    public void putTo(PrimitiveSink sink) {
+        sink.putInt(rawValue);
+    }
 }
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFGroup.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFGroup.java
new file mode 100644
index 0000000..b05d5fa
--- /dev/null
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFGroup.java
@@ -0,0 +1,156 @@
+package org.projectfloodlight.openflow.types;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.projectfloodlight.openflow.annotations.Immutable;
+import org.projectfloodlight.openflow.exceptions.OFParseError;
+
+import com.google.common.hash.PrimitiveSink;
+import com.google.common.primitives.UnsignedInts;
+
+/**
+ * Abstraction of an logical / OpenFlow group (ofp_group) in OpenFlow.
+ * Immutable.
+ *
+ * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
+ */
+@Immutable
+public class OFGroup implements OFValueType<OFGroup> {
+    static final int LENGTH = 4;
+
+    // private int constants (OF1.1+) to avoid duplication in the code
+    // should not have to use these outside this class
+    private static final int ZERO_VAL = 0x00;
+    private static final int MAX_VAL = 0xffffff00;
+    private static final int ALL_VAL = 0xfffffffc;
+    private static final int ANY_VAL = 0xffffffff;
+
+
+    // ////////////// public constants - use to access well known OpenFlow group constants
+
+    /** Maximum number of physical and logical switch groups. */
+    public final static OFGroup MAX = new NamedGroup(MAX_VAL, "max");
+
+    /** All groups */
+    public final static OFGroup ALL = new NamedGroup(ALL_VAL, "all");
+
+    /**
+     * Wildcard group used only for flow mod (delete) and flow stats requests. */
+    public final static OFGroup ANY = new NamedGroup(ANY_VAL, "any");
+
+    /** group 0 in case we need it */
+    public static final OFGroup ZERO = OFGroup.of(ZERO_VAL);
+
+    public static final OFGroup NO_MASK = ANY;
+    public static final OFGroup FULL_MASK = ZERO;
+
+    /** raw openflow group number as a signed 32 bit integer */
+    private final int groupNumber;
+
+    /** private constructor. use of*-Factory methods instead */
+    private OFGroup(final int portNumber) {
+        this.groupNumber = portNumber;
+    }
+
+    /**
+     * get an OFGroup object corresponding to a raw 32-bit integer group number.
+     * NOTE: The group object may either be newly allocated or cached. Do not
+     * rely on either behavior.
+     *
+     * @param groupNumber the raw 32-bit group number
+     * @return a corresponding OFPort
+     */
+    public static OFGroup of(final int groupNumber) {
+        switch(groupNumber) {
+            case ZERO_VAL:
+                return MAX;
+            case MAX_VAL:
+                return MAX;
+            case ALL_VAL:
+                return ALL;
+            case ANY_VAL:
+                return ANY;
+            default:
+                if(UnsignedInts.compare(groupNumber, MAX_VAL) > 0) {
+                    // greater than max_val, but not one of the reserved values
+                    throw new IllegalArgumentException("Unknown special group number: "
+                            + groupNumber);
+                }
+                return new OFGroup(groupNumber);
+        }
+    }
+
+    /** return the group number as a int32 */
+    public int getGroupNumber() {
+        return groupNumber;
+    }
+
+    @Override
+    public String toString() {
+        return UnsignedInts.toString(groupNumber);
+    }
+
+    /** Extension of OFGroup for named groups */
+    static class NamedGroup extends OFGroup {
+        private final String name;
+
+        NamedGroup(final int portNo, final String name) {
+            super(portNo);
+            this.name = name;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        @Override
+        public String toString() {
+            return name;
+        }
+    }
+
+    @Override
+    public int getLength() {
+        return LENGTH;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof OFGroup))
+            return false;
+        OFGroup other = (OFGroup)obj;
+        if (other.groupNumber != this.groupNumber)
+            return false;
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 53;
+        int result = 1;
+        result = prime * result + groupNumber;
+        return result;
+    }
+
+    public void write4Bytes(ChannelBuffer c) {
+        c.writeInt(this.groupNumber);
+    }
+
+    public static OFGroup read4Bytes(ChannelBuffer c) throws OFParseError {
+        return OFGroup.of(c.readInt());
+    }
+
+    @Override
+    public OFGroup applyMask(OFGroup mask) {
+        return OFGroup.of(this.groupNumber & mask.groupNumber);
+    }
+
+    @Override
+    public int compareTo(OFGroup o) {
+        return UnsignedInts.compare(this.groupNumber, o.groupNumber);
+    }
+
+    @Override
+    public void putTo(PrimitiveSink sink) {
+        sink.putInt(groupNumber);
+    }
+}
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFMetadata.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFMetadata.java
index 0844d89..d1a23df 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFMetadata.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFMetadata.java
@@ -2,6 +2,8 @@
 
 import org.jboss.netty.buffer.ChannelBuffer;
 
+import com.google.common.hash.PrimitiveSink;
+
 public class OFMetadata implements OFValueType<OFMetadata> {
 
     static int LENGTH = 8;
@@ -67,4 +69,9 @@
     public int compareTo(OFMetadata o) {
         return u64.compareTo(o.u64);
     }
+
+    @Override
+    public void putTo(PrimitiveSink sink) {
+        u64.putTo(sink);
+    }
 }
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFPort.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFPort.java
index 0028cd8..155a9db 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFPort.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFPort.java
@@ -4,6 +4,7 @@
 import org.projectfloodlight.openflow.annotations.Immutable;
 import org.projectfloodlight.openflow.exceptions.OFParseError;
 
+import com.google.common.hash.PrimitiveSink;
 import com.google.common.primitives.UnsignedInts;
 
 /**
@@ -554,4 +555,9 @@
     public int compareTo(OFPort o) {
         return UnsignedInts.compare(this.portNumber, o.portNumber);
     }
+
+    @Override
+    public void putTo(PrimitiveSink sink) {
+        sink.putInt(portNumber);
+    }
 }
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFPortBitMap.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFPortBitMap.java
new file mode 100644
index 0000000..49c8c4e
--- /dev/null
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFPortBitMap.java
@@ -0,0 +1,126 @@
+package org.projectfloodlight.openflow.types;
+
+
+/** User-facing object representing a bitmap of ports that can be matched on.
+ *  This is implemented by the custom BSN OXM type of_oxm_bsn_in_ports_182.
+ *
+ *  You can call set() on the builder for all the Ports you want to match on
+ *  and unset to exclude the port.
+ *
+ *  <b>Implementation note:</b> to comply with the matching semantics of OXM (which is a logical "AND" not "OR")
+ *  the underlying match uses a data format which is very unintuitive. The value is always
+ *  0, and the mask has the bits set for the ports that should <b>NOT</b> be included in the
+ *  range.
+ *
+ *  For the curious: We transformed the bitmap (a logical OR) problem into a logical
+ *  AND NOT problem.
+ *
+ *  We logically mean:   Inport is 1 OR 3
+ *  We technically say:  Inport IS NOT 2 AND IS NOT 4 AND IS NOT 5 AND IS NOT ....
+ *  The second term cannot be represented in OXM, the second can.
+ *
+ *  That said, all that craziness is hidden from the user of this object.
+ * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
+ */
+public class OFPortBitMap extends Masked<OFBitMask128> {
+
+    private OFPortBitMap(OFBitMask128 mask) {
+        super(OFBitMask128.NONE, mask);
+    }
+
+    /** @return whether or not the given port is logically included in the
+     *  match, i.e., whether a packet from in-port <emph>port</emph> be matched by
+     *  this OXM.
+     */
+    public boolean isOn(OFPort port) {
+        // see the implementation note above about the logical inversion of the mask
+        return !(this.mask.isOn(port.getPortNumber()));
+    }
+
+    public static OFPortBitMap ofPorts(OFPort... ports) {
+        Builder builder = new Builder();
+        for (OFPort port: ports) {
+            builder.set(port);
+        }
+        return builder.build();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof OFPortBitMap))
+            return false;
+        OFPortBitMap other = (OFPortBitMap)obj;
+        return (other.value.equals(this.value) && other.mask.equals(this.mask));
+    }
+
+    @Override
+    public int hashCode() {
+        return 619 * mask.hashCode() + 257 * value.hashCode();
+    }
+
+    public static class Builder {
+        private long raw1 = -1, raw2 = -1;
+
+        public Builder() {
+
+        }
+
+        /** @return whether or not the given port is logically included in the
+         *  match, i.e., whether a packet from in-port <emph>port</emph> be matched by
+         *  this OXM.
+         */
+        public boolean isOn(OFPort port) {
+            // see the implementation note above about the logical inversion of the mask
+            return !(OFBitMask128.isBitOn(raw1, raw2, port.getPortNumber()));
+        }
+
+        /** remove this port from the match, i.e., packets from this in-port
+         *  will NOT be matched.
+         */
+        public Builder unset(OFPort port) {
+            // see the implementation note above about the logical inversion of the mask
+            int bit = port.getPortNumber();
+            if (bit < 0 || bit > 127)
+                throw new IndexOutOfBoundsException("Port number is out of bounds");
+            else if (bit == 127)
+                // the highest order bit in the bitmask is reserved. The switch will
+                // set that bit for all ports >= 127. The reason is that we don't want
+                // the OFPortMap to match all ports out of its range (i.e., a packet
+                // coming in on port 181 would match *any* OFPortMap).
+                throw new IndexOutOfBoundsException("The highest order bit in the bitmask is reserved.");
+            else if (bit < 64) {
+                raw2 |= ((long)1 << bit);
+            } else {
+                raw1 |= ((long)1 << (bit - 64));
+            }
+            return this;
+        }
+
+        /** add this port from the match, i.e., packets from this in-port
+         *  will NOT be matched.
+         */
+        public Builder set(OFPort port) {
+            // see the implementation note above about the logical inversion of the mask
+            int bit = port.getPortNumber();
+            if (bit < 0 || bit > 127)
+                throw new IndexOutOfBoundsException("Port number is out of bounds");
+            else if (bit == 127)
+                // the highest order bit in the bitmask is reserved. The switch will
+                // set that bit for all ports >= 127. The reason is that we don't want
+                // the OFPortMap to match all ports out of its range (i.e., a packet
+                // coming in on port 181 would match *any* OFPortMap).
+                throw new IndexOutOfBoundsException("The highest order bit in the bitmask is reserved.");
+            else if (bit < 64) {
+                raw2 &= ~((long)1 << bit);
+            } else {
+                raw1 &= ~((long)1 << (bit - 64));
+            }
+            return this;
+        }
+
+        public OFPortBitMap build() {
+            return new OFPortBitMap(OFBitMask128.of(raw1, raw2));
+        }
+    }
+
+}
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFPortMap.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFPortMap.java
deleted file mode 100644
index 8ec056e..0000000
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFPortMap.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package org.projectfloodlight.openflow.types;
-
-
-public class OFPortMap extends Masked<OFBitMask128> {
-
-    private OFPortMap(OFBitMask128 mask) {
-        super(OFBitMask128.NONE, mask);
-    }
-
-    public boolean isOn(OFPort port) {
-        return !(this.mask.isOn(port.getPortNumber()));
-    }
-
-    public static OFPortMap ofPorts(OFPort... ports) {
-        Builder builder = new Builder();
-        for (OFPort port: ports) {
-            builder.set(port);
-        }
-        return builder.build();
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (!(obj instanceof OFPortMap))
-            return false;
-        OFPortMap other = (OFPortMap)obj;
-        return (other.value.equals(this.value) && other.mask.equals(this.mask));
-    }
-
-    @Override
-    public int hashCode() {
-        return 619 * mask.hashCode() + 257 * value.hashCode();
-    }
-
-    public static class Builder {
-        private long raw1 = -1, raw2 = -1;
-
-        public Builder() {
-
-        }
-
-        public boolean isOn(OFPort port) {
-            return !(OFBitMask128.isBitOn(raw1, raw2, port.getPortNumber()));
-        }
-
-        public Builder unset(OFPort port) {
-            int bit = port.getPortNumber();
-            if (bit < 0 || bit >= 127) // MAX PORT IS 127
-                throw new IndexOutOfBoundsException("Port number is out of bounds");
-            if (bit < 64) {
-                raw2 |= ((long)1 << bit);
-            } else {
-                raw1 |= ((long)1 << (bit - 64));
-            }
-            return this;
-        }
-
-        public Builder set(OFPort port) {
-            int bit = port.getPortNumber();
-            if (bit < 0 || bit >= 127)
-                throw new IndexOutOfBoundsException("Port number is out of bounds");
-            if (bit < 64) {
-                raw2 &= ~((long)1 << bit);
-            } else {
-                raw1 &= ~((long)1 << (bit - 64));
-            }
-            return this;
-        }
-
-        public OFPortMap build() {
-            return new OFPortMap(OFBitMask128.of(raw1, raw2));
-        }
-    }
-
-}
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFValueType.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFValueType.java
index 3d8d1cd..03e84dd 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFValueType.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFValueType.java
@@ -3,8 +3,9 @@
 
 
 
-public interface OFValueType<T extends OFValueType<T>> extends Comparable<T> {
+public interface OFValueType<T extends OFValueType<T>> extends Comparable<T>, PrimitiveSinkable {
     public int getLength();
 
     public T applyMask(T mask);
+
 }
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/PrimitiveSinkable.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/PrimitiveSinkable.java
new file mode 100644
index 0000000..e50cb75
--- /dev/null
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/PrimitiveSinkable.java
@@ -0,0 +1,7 @@
+package org.projectfloodlight.openflow.types;
+
+import com.google.common.hash.PrimitiveSink;
+
+public interface PrimitiveSinkable {
+    public void putTo(PrimitiveSink sink);
+}
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/TableId.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/TableId.java
index 698bc8e..950087d 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/TableId.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/TableId.java
@@ -3,6 +3,7 @@
 import org.jboss.netty.buffer.ChannelBuffer;
 import org.projectfloodlight.openflow.exceptions.OFParseError;
 
+import com.google.common.hash.PrimitiveSink;
 import com.google.common.primitives.Shorts;
 
 public class TableId implements OFValueType<TableId>, Comparable<TableId> {
@@ -91,4 +92,9 @@
         return Shorts.compare(this.id, other.id);
     }
 
+    @Override
+    public void putTo(PrimitiveSink sink) {
+        sink.putByte((byte) id);
+    }
+
 }
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/TransportPort.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/TransportPort.java
index 540ad1a..01019b0 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/TransportPort.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/TransportPort.java
@@ -3,6 +3,7 @@
 import org.jboss.netty.buffer.ChannelBuffer;
 import org.projectfloodlight.openflow.exceptions.OFParseError;
 
+import com.google.common.hash.PrimitiveSink;
 import com.google.common.primitives.Ints;
 
 /**
@@ -87,4 +88,9 @@
         return Ints.compare(port,  o.port);
     }
 
+    @Override
+    public void putTo(PrimitiveSink sink) {
+        sink.putShort((short) port);
+    }
+
 }
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/U16.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/U16.java
index 2f8bfee..9de7e14 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/U16.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/U16.java
@@ -22,6 +22,7 @@
 import org.projectfloodlight.openflow.protocol.OFMessageReader;
 import org.projectfloodlight.openflow.protocol.Writeable;
 
+import com.google.common.hash.PrimitiveSink;
 import com.google.common.primitives.Ints;
 
 public class U16 implements Writeable, OFValueType<U16> {
@@ -117,4 +118,9 @@
     public int compareTo(U16 o) {
         return Ints.compare(f(raw), f(o.raw));
     }
+
+    @Override
+    public void putTo(PrimitiveSink sink) {
+        sink.putShort(raw);
+    }
 }
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/U32.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/U32.java
index daf5fa6..9fafc30 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/U32.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/U32.java
@@ -22,6 +22,7 @@
 import org.projectfloodlight.openflow.protocol.OFMessageReader;
 import org.projectfloodlight.openflow.protocol.Writeable;
 
+import com.google.common.hash.PrimitiveSink;
 import com.google.common.primitives.UnsignedInts;
 
 public class U32 implements Writeable, OFValueType<U32> {
@@ -117,4 +118,7 @@
         return UnsignedInts.compare(raw, o.raw);
     }
 
-}
+    @Override
+    public void putTo(PrimitiveSink sink) {
+        sink.putInt(raw);
+    }}
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/U64.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/U64.java
index 8cd577f..d77d700 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/U64.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/U64.java
@@ -22,6 +22,7 @@
 import org.jboss.netty.buffer.ChannelBuffer;
 import org.projectfloodlight.openflow.protocol.Writeable;
 
+import com.google.common.hash.PrimitiveSink;
 import com.google.common.primitives.UnsignedLongs;
 
 public class U64 implements Writeable, OFValueType<U64> {
@@ -120,4 +121,8 @@
         return UnsignedLongs.compare(raw, o.raw);
     }
 
+    @Override
+    public void putTo(PrimitiveSink sink) {
+        sink.putLong(raw);
+    }
 }
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/U8.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/U8.java
index b85627e..078a846 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/U8.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/U8.java
@@ -22,6 +22,7 @@
 import org.projectfloodlight.openflow.protocol.OFMessageReader;
 import org.projectfloodlight.openflow.protocol.Writeable;
 
+import com.google.common.hash.PrimitiveSink;
 import com.google.common.primitives.UnsignedBytes;
 
 public class U8 implements Writeable, OFValueType<U8> {
@@ -119,4 +120,8 @@
         return UnsignedBytes.compare(raw, o.raw);
     }
 
-}
+    @Override
+    public void putTo(PrimitiveSink sink) {
+        sink.putByte(raw);
+    }
+ }
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/VRF.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/VRF.java
index 10e2ebc..b3f187f 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/VRF.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/VRF.java
@@ -4,6 +4,7 @@
 
 import org.jboss.netty.buffer.ChannelBuffer;
 
+import com.google.common.hash.PrimitiveSink;
 import com.google.common.primitives.UnsignedInts;
 
 @Immutable
@@ -75,4 +76,9 @@
     public int compareTo(VRF o) {
         return UnsignedInts.compare(rawValue, o.rawValue);
     }
+
+    @Override
+    public void putTo(PrimitiveSink sink) {
+        sink.putInt(rawValue);
+    }
 }
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/VlanPcp.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/VlanPcp.java
index dcc7d60..cbb7004 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/VlanPcp.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/VlanPcp.java
@@ -3,6 +3,7 @@
 import org.jboss.netty.buffer.ChannelBuffer;
 import org.projectfloodlight.openflow.exceptions.OFParseError;
 
+import com.google.common.hash.PrimitiveSink;
 import com.google.common.primitives.UnsignedBytes;
 
 public class VlanPcp implements OFValueType<VlanPcp> {
@@ -74,5 +75,8 @@
     public int compareTo(VlanPcp o) {
         return UnsignedBytes.compare(pcp, o.pcp);
     }
-
+    @Override
+    public void putTo(PrimitiveSink sink) {
+        sink.putByte(pcp);
+    }
 }
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 6bd7581..d370711 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
@@ -3,6 +3,7 @@
 import org.jboss.netty.buffer.ChannelBuffer;
 import org.projectfloodlight.openflow.exceptions.OFParseError;
 
+import com.google.common.hash.PrimitiveSink;
 import com.google.common.primitives.Shorts;
 
 /** Represents an OpenFlow Vlan VID, as specified by the OpenFlow 1.3 spec.
@@ -159,5 +160,8 @@
     public int compareTo(VlanVid o) {
         return Shorts.compare(vid, o.vid);
     }
-
+    @Override
+    public void putTo(PrimitiveSink sink) {
+        sink.putShort(vid);
+    }
 }
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/util/ChannelUtils.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/util/ChannelUtils.java
index ea2c4a9..13cfdc7 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/util/ChannelUtils.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/util/ChannelUtils.java
@@ -21,7 +21,12 @@
     public static String readFixedLengthString(ChannelBuffer bb, int length) {
         byte[] dst = new byte[length];
         bb.readBytes(dst, 0, length);
-        return new String(dst, Charsets.US_ASCII);
+        int validLength = 0;
+        for (validLength = 0; validLength < length; validLength++) {
+            if (dst[validLength] == 0)
+                break;
+        }
+        return new String(dst, 0, validLength, Charsets.US_ASCII);
     }
 
     public static void writeFixedLengthString(ChannelBuffer bb, String string,
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/util/FunnelUtils.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/util/FunnelUtils.java
new file mode 100644
index 0000000..f62d7f9
--- /dev/null
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/util/FunnelUtils.java
@@ -0,0 +1,14 @@
+package org.projectfloodlight.openflow.util;
+
+import java.util.List;
+
+import org.projectfloodlight.openflow.types.PrimitiveSinkable;
+
+import com.google.common.hash.PrimitiveSink;
+
+public class FunnelUtils {
+    public static void putList(List<? extends PrimitiveSinkable> sinkables, PrimitiveSink sink) {
+        for(PrimitiveSinkable p: sinkables)
+            p.putTo(sink);
+    }
+}
diff --git a/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/MacAddressTest.java b/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/MacAddressTest.java
index dc25b12..3ccceb3 100644
--- a/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/MacAddressTest.java
+++ b/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/MacAddressTest.java
@@ -2,6 +2,8 @@
 
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import java.util.Arrays;
@@ -29,9 +31,11 @@
             0x00ffffffffffffL
     };
 
-    String[] invalidMacs = {
+    String[] invalidMacStrings = {
             "",
             "1.2.3.4",
+            "0T:00:01:02:03:04",
+            "00:01:02:03:04:05:06",
             "00:ff:ef:12:12:ff:",
             "00:fff:ef:12:12:ff",
             "01:02:03:04:05;06",
@@ -39,6 +43,10 @@
             "01:02:03:04"
     };
 
+    byte[][] invalidMacBytes = {
+            new byte[]{0x01, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06},
+            new byte[]{0x01, 0x01, 0x02, 0x03, 0x04}
+    };
 
     @Test
     public void testOfString() {
@@ -72,14 +80,64 @@
 
 
     @Test
-    public void testInvalidMacss() throws OFParseError {
-        for(String invalid : invalidMacs) {
+    public void testInvalidMacStrings() throws OFParseError {
+        for(String invalid : invalidMacStrings) {
             try {
                 MacAddress.of(invalid);
-                fail("Invalid IP "+invalid+ " should have raised IllegalArgumentException");
+                fail("Invalid MAC address "+invalid+ " should have raised IllegalArgumentException");
             } catch(IllegalArgumentException e) {
                 // ok
             }
         }
     }
+
+    @Test
+    public void testInvalidMacBytes() throws OFParseError {
+        for(byte[] invalid : invalidMacBytes) {
+            try {
+                MacAddress.of(invalid);
+                fail("Invalid MAC address bytes "+ Arrays.toString(invalid) + " should have raised IllegalArgumentException");
+            } catch(IllegalArgumentException e) {
+                // ok
+            }
+        }
+    }
+
+    //  Test data is imported from org.projectfloodlight.packet.EthernetTest
+    @Test
+    public void testToLong() {
+        assertEquals(
+                281474976710655L,
+                MacAddress.of(new byte[]{(byte) 0xff, (byte) 0xff,
+                        (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff}).getLong());
+
+        assertEquals(
+                1103823438081L,
+                MacAddress.of(new byte[] { (byte) 0x01, (byte) 0x01,
+                        (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x01 }).getLong());
+
+        assertEquals(
+                141289400074368L,
+                MacAddress.of(new byte[] { (byte) 0x80, (byte) 0x80,
+                        (byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80 }).getLong());
+
+    }
+
+    @Test
+    public void testIsBroadcast() {
+        assertTrue(MacAddress.of("FF:FF:FF:FF:FF:FF").isBroadcast());
+        assertTrue(MacAddress.of(-1).isBroadcast());
+        assertTrue(MacAddress.of(0x05FFFFFFFFFFFFL).isBroadcast());
+        assertFalse(MacAddress.of("11:22:33:44:55:66").isBroadcast());
+    }
+
+    @Test
+    public void testIsMulticast() {
+        assertTrue(MacAddress.of("01:80:C2:00:00:00").isMulticast());
+        assertFalse(MacAddress.of("00:80:C2:00:00:00").isMulticast());
+        assertFalse(MacAddress.of("FE:80:C2:00:00:00").isMulticast());
+        assertFalse(MacAddress.of(-1).isMulticast());
+        assertFalse(MacAddress.of(0x05FFFFFFFFFFFFL).isMulticast());
+        assertFalse(MacAddress.of("FF:FF:FF:FF:FF:FF").isMulticast());
+    }
 }
diff --git a/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/OFPortMapTest.java b/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/OFPortBitMapTest.java
similarity index 60%
rename from java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/OFPortMapTest.java
rename to java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/OFPortBitMapTest.java
index 7a75248..7f5ab5d 100644
--- a/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/OFPortMapTest.java
+++ b/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/OFPortBitMapTest.java
@@ -5,48 +5,48 @@
 
 import org.junit.Test;
 
-public class OFPortMapTest extends TestCase {
+public class OFPortBitMapTest extends TestCase {
 
     @Test
-    public void testOFPortMap() {
-        Boolean[] on = new Boolean[128];
-        for (int i = 0; i < 128; i++) {
+    public void testOFPortBitMap() {
+        Boolean[] on = new Boolean[127];
+        for (int i = 0; i < 127; i++) {
             on[i] = false;
         }
 
-        OFPortMap.Builder builder = new OFPortMap.Builder();
+        OFPortBitMap.Builder builder = new OFPortBitMap.Builder();
 
-        for (int i = 0; i < 128; i += 3) {
+        for (int i = 0; i < 127; i += 3) {
             OFPort p = OFPort.of(i);
             builder.set(p);
             on[p.getPortNumber()] = true;
         }
 
         // Test that all ports that were added are actually on, and all other ports are off
-        OFPortMap portmap = builder.build();
+        OFPortBitMap portmap = builder.build();
         //System.out.println(portmap);
-        Boolean[] actual = new Boolean[128];
-        for (int i = 0; i < 128; i++) {
+        Boolean[] actual = new Boolean[127];
+        for (int i = 0; i < 127; i++) {
             actual[i] = false;
         }
-        for (int i = 0; i < 128; i++) {
+        for (int i = 0; i < 127; i++) {
             actual[i] = portmap.isOn(OFPort.of(i));
         }
         assertArrayEquals(on, actual);
 
         // Turn some ports off
-        for (int i = 0; i < 128; i += 7) {
+        for (int i = 0; i < 127; i += 7) {
             on[i] = false;
             builder.unset(OFPort.of(i));
         }
 
         // Test again
         portmap = builder.build();
-        actual = new Boolean[128];
-        for (int i = 0; i < 128; i++) {
+        actual = new Boolean[127];
+        for (int i = 0; i < 127; i++) {
             actual[i] = false;
         }
-        for (int i = 0; i < 128; i++) {
+        for (int i = 0; i < 127; i++) {
             actual[i] = portmap.isOn(OFPort.of(i));
         }
         assertArrayEquals(on, actual);
diff --git a/java_gen/templates/_imports.java b/java_gen/templates/_imports.java
index 7fd0719..55e9a2d 100644
--- a/java_gen/templates/_imports.java
+++ b/java_gen/templates/_imports.java
@@ -1,5 +1,6 @@
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.EnumSet;
 import java.util.List;
 import java.util.Set;
 import java.util.Map;
@@ -18,3 +19,5 @@
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Sets;
+import com.google.common.hash.Funnel;
+import com.google.common.hash.PrimitiveSink;
diff --git a/java_gen/templates/const_serializer.java b/java_gen/templates/const_serializer.java
index 5710f9c..12ff28a 100644
--- a/java_gen/templates/const_serializer.java
+++ b/java_gen/templates/const_serializer.java
@@ -33,10 +33,7 @@
 
 package ${package};
 
-import org.projectfloodlight.openflow.types.*;
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.projectfloodlight.openflow.exceptions.OFParseError;
-import org.projectfloodlight.openflow.protocol.OFVersion;
+//:: include('_imports.java')
 import ${enum.package}.${enum.name};
 
 public class ${class_name} {
@@ -60,6 +57,10 @@
         ${wire_type.write_op(version=version, name="toWireValue(e)")};
     }
 
+    public static void putTo(${enum.name} e, PrimitiveSink sink) {
+        ${wire_type.funnel_op(version=version, name="toWireValue(e)")};
+    }
+
     public static ${enum.name} ofWireValue(${int_wire_type} val) {
         switch(val) {
         //:: for entry, _ in entries:
@@ -71,6 +72,7 @@
         }
     }
 
+
     public static ${int_wire_type} toWireValue(${enum.name} e) {
         switch(e) {
         //:: for entry, _ in entries:
diff --git a/java_gen/templates/const_set_serializer.java b/java_gen/templates/const_set_serializer.java
index 4fcff22..4c624ee 100644
--- a/java_gen/templates/const_set_serializer.java
+++ b/java_gen/templates/const_set_serializer.java
@@ -33,14 +33,8 @@
 
 package ${package};
 
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.Set;
+//:: include('_imports.java')
 
-import org.projectfloodlight.openflow.types.*;
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.projectfloodlight.openflow.exceptions.OFParseError;
-import org.projectfloodlight.openflow.protocol.OFVersion;
 import ${enum.package}.${enum.name};
 
 public class ${class_name} {
@@ -64,6 +58,11 @@
         ${wire_type.write_op(version=version, name="toWireValue(set)")};
     }
 
+    public static void putTo(Set<${enum.name}> set, PrimitiveSink sink) {
+        ${wire_type.funnel_op(version=version, name="toWireValue(set)")};
+    }
+
+
     public static Set<${enum.name}> ofWireValue(${int_wire_type} val) {
         EnumSet<${enum.name}> set = EnumSet.noneOf(${enum.name}.class);
 
diff --git a/java_gen/templates/custom/OFMatchV1Ver10.Builder.java b/java_gen/templates/custom/OFMatchV1Ver10.Builder.java
index 38cc127..239828e 100644
--- a/java_gen/templates/custom/OFMatchV1Ver10.Builder.java
+++ b/java_gen/templates/custom/OFMatchV1Ver10.Builder.java
@@ -25,6 +25,15 @@
                 case VLAN_PCP:
                     result = vlanPcp;
                     break;
+                case ARP_OP:
+                    result = ArpOpcode.of(ipProto.getIpProtocolNumber());
+                    break;
+                case ARP_SPA:
+                    result = ipv4Src;
+                    break;
+                case ARP_TPA:
+                    result = ipv4Dst;
+                    break;
                 case IP_DSCP:
                     result = ipDscp;
                     break;
@@ -32,13 +41,13 @@
                     result = ipProto;
                     break;
                 case IPV4_SRC:
-                    result = ipv4Dst;
+                    result = ipv4Src;
                     break;
                 case IPV4_DST:
                     result = ipv4Dst;
                     break;
                 case TCP_SRC:
-                    result = ipv4Src;
+                    result = tcpSrc;
                     break;
                 case TCP_DST:
                     result = tcpDst;
@@ -77,10 +86,12 @@
             Object result;
             switch (field.id) {
                 case IPV4_SRC:
+                case ARP_SPA:
                     int srcBitMask = (-1) << (32 - getIpv4SrcCidrMaskLen());
                     result = IPv4AddressWithMask.of(ipv4Src, IPv4Address.of(srcBitMask));
                     break;
                 case IPV4_DST:
+                case ARP_TPA:
                     int dstMaskedBits = Math.min(32, (wildcards & OFPFW_NW_DST_MASK) >> OFPFW_NW_DST_SHIFT);
                     int dstBitMask = (-1) << (32 - getIpv4DstCidrMaskLen());
 
@@ -101,6 +112,9 @@
                 case ETH_TYPE:
                 case VLAN_VID:
                 case VLAN_PCP:
+                case ARP_OP:
+                case ARP_SPA:
+                case ARP_TPA:
                 case IP_DSCP:
                 case IP_PROTO:
                 case IPV4_SRC:
@@ -122,6 +136,8 @@
         @Override
         public boolean supportsMasked(MatchField<?> field) {
             switch (field.id) {
+                case ARP_SPA:
+                case ARP_TPA:
                 case IPV4_SRC:
                 case IPV4_DST:
                     return true;
@@ -145,6 +161,12 @@
                     return (this.wildcards & OFPFW_DL_VLAN) == 0;
                 case VLAN_PCP:
                     return (this.wildcards & OFPFW_DL_VLAN_PCP) == 0;
+                case ARP_OP:
+                    return (this.wildcards & OFPFW_NW_PROTO) == 0;
+                case ARP_SPA:
+                    return this.getIpv4SrcCidrMaskLen() >= 32;
+                case ARP_TPA:
+                    return this.getIpv4DstCidrMaskLen() >= 32;
                 case IP_DSCP:
                     return (this.wildcards & OFPFW_NW_TOS) == 0;
                 case IP_PROTO:
@@ -216,6 +238,12 @@
                     return (this.wildcards & OFPFW_DL_VLAN) != 0;
                 case VLAN_PCP:
                     return (this.wildcards & OFPFW_DL_VLAN_PCP) != 0;
+                case ARP_OP:
+                    return (this.wildcards & OFPFW_NW_PROTO) != 0;
+                case ARP_SPA:
+                    return this.getIpv4SrcCidrMaskLen() <= 0;
+                case ARP_TPA:
+                    return this.getIpv4DstCidrMaskLen() <= 0;
                 case IP_DSCP:
                     return (this.wildcards & OFPFW_NW_TOS) != 0;
                 case IP_PROTO:
@@ -248,11 +276,13 @@
         @Override
         public boolean isPartiallyMasked(MatchField<?> field) {
             switch (field.id) {
+                case ARP_SPA:
                 case IPV4_SRC:
                     int srcCidrLen = getIpv4SrcCidrMaskLen();
                     return srcCidrLen > 0 && srcCidrLen < 32;
+                case ARP_TPA:
                 case IPV4_DST:
-                    int dstCidrLen = getIpv4SrcCidrMaskLen();
+                    int dstCidrLen = getIpv4DstCidrMaskLen();
                     return dstCidrLen > 0 && dstCidrLen < 32;
                 default:
                     throw new UnsupportedOperationException("OFMatch does not support masked matching on field " + field.getName());
@@ -300,10 +330,16 @@
                     setInPort((OFPort) value);
                     wildcards &= ~OFPFW_IN_PORT;
                     break;
+                case ARP_OP:
+                    setIpProto(IpProtocol.of((short)((ArpOpcode)value).getOpcode()));
+                    wildcards &= ~OFPFW_NW_PROTO;
+                    break;
+                case ARP_TPA:
                 case IPV4_DST:
                     setIpv4Dst((IPv4Address) value);
                     wildcards &= ~OFPFW_NW_DST_MASK;
                     break;
+                case ARP_SPA:
                 case IPV4_SRC:
                     setIpv4Src((IPv4Address) value);
                     wildcards &= ~OFPFW_NW_SRC_MASK;
@@ -347,6 +383,7 @@
                 case VLAN_VID:
                     setVlanVid((VlanVid) value);
                     wildcards &= ~OFPFW_DL_VLAN;
+                    break;
                 default:
                     throw new UnsupportedOperationException(
                             "OFMatch does not support matching on field " + field.getName());
@@ -359,6 +396,8 @@
                 F value, F mask) {
             initWildcards();
             switch (field.id) {
+                case ARP_SPA:
+                case ARP_TPA:
                 case IPV4_DST:
                 case IPV4_SRC:
                     Object valObj = value;
@@ -369,10 +408,12 @@
                         throw new UnsupportedOperationException("OFMatch only supports CIDR masks for IPv4");
                     int maskLen = 32 - Integer.bitCount(maskval);
                     switch(field.id) {
+                        case ARP_TPA:
                         case IPV4_DST:
                             setIpv4Dst(ip);
                             wildcards = (wildcards &~OFPFW_NW_DST_MASK) | (maskLen << OFPFW_NW_DST_SHIFT);
                             break;
+                        case ARP_SPA:
                         case IPV4_SRC:
                             setIpv4Src(ip);
                             wildcards = (wildcards &~OFPFW_NW_SRC_MASK) | (maskLen << OFPFW_NW_SRC_SHIFT);
@@ -428,10 +469,12 @@
                     setInPort(OFPort.of(0)); // NOTE: not 'NONE' -- that is 0xFF for ports
                     wildcards |= OFPFW_IN_PORT;
                     break;
+                case ARP_TPA:
                 case IPV4_DST:
                     setIpv4Dst(IPv4Address.NONE);
                     wildcards |= OFPFW_NW_DST_MASK;
                     break;
+                case ARP_SPA:
                 case IPV4_SRC:
                     setIpv4Src(IPv4Address.NONE);
                     wildcards |= OFPFW_NW_SRC_MASK;
diff --git a/java_gen/templates/custom/OFMatchV1Ver10.java b/java_gen/templates/custom/OFMatchV1Ver10.java
index eaaacb0..82ff10f 100644
--- a/java_gen/templates/custom/OFMatchV1Ver10.java
+++ b/java_gen/templates/custom/OFMatchV1Ver10.java
@@ -61,6 +61,15 @@
             case VLAN_PCP:
                 result = vlanPcp;
                 break;
+            case ARP_OP:
+                result = ArpOpcode.of(ipProto.getIpProtocolNumber());
+                break;
+            case ARP_SPA:
+                result = ipv4Src;
+                break;
+            case ARP_TPA:
+                result = ipv4Dst;
+                break;
             case IP_DSCP:
                 result = ipDscp;
                 break;
@@ -68,7 +77,7 @@
                 result = ipProto;
                 break;
             case IPV4_SRC:
-                result = ipv4Dst;
+                result = ipv4Src;
                 break;
             case IPV4_DST:
                 result = ipv4Dst;
@@ -114,10 +123,12 @@
             return null;
         Object result;
         switch (field.id) {
+            case ARP_SPA:
             case IPV4_SRC:
                 int srcBitMask = (-1) << (32 - getIpv4SrcCidrMaskLen());
                 result = IPv4AddressWithMask.of(ipv4Src, IPv4Address.of(srcBitMask));
                 break;
+            case ARP_TPA:
             case IPV4_DST:
                 int dstBitMask = (-1) << (32 - getIpv4DstCidrMaskLen());
 
@@ -138,6 +149,9 @@
             case ETH_TYPE:
             case VLAN_VID:
             case VLAN_PCP:
+            case ARP_OP:
+            case ARP_SPA:
+            case ARP_TPA:
             case IP_DSCP:
             case IP_PROTO:
             case IPV4_SRC:
@@ -159,6 +173,8 @@
     @Override
     public boolean supportsMasked(MatchField<?> field) {
         switch (field.id) {
+            case ARP_SPA:
+            case ARP_TPA:
             case IPV4_SRC:
             case IPV4_DST:
                 return true;
@@ -185,6 +201,12 @@
                 return (this.wildcards & OFPFW_DL_VLAN) == 0;
             case VLAN_PCP:
                 return (this.wildcards & OFPFW_DL_VLAN_PCP) == 0;
+            case ARP_OP:
+                return (this.wildcards & OFPFW_NW_PROTO) == 0;
+            case ARP_SPA:
+                return this.getIpv4SrcCidrMaskLen() >= 32;
+            case ARP_TPA:
+                return this.getIpv4DstCidrMaskLen() >= 32;
             case IP_DSCP:
                 return (this.wildcards & OFPFW_NW_TOS) == 0;
             case IP_PROTO:
@@ -259,6 +281,12 @@
                 return (this.wildcards & OFPFW_DL_VLAN) != 0;
             case VLAN_PCP:
                 return (this.wildcards & OFPFW_DL_VLAN_PCP) != 0;
+            case ARP_OP:
+                return (this.wildcards & OFPFW_NW_PROTO) != 0;
+            case ARP_SPA:
+                return this.getIpv4SrcCidrMaskLen() <= 0;
+            case ARP_TPA:
+                return this.getIpv4DstCidrMaskLen() <= 0;
             case IP_DSCP:
                 return (this.wildcards & OFPFW_NW_TOS) != 0;
             case IP_PROTO:
@@ -294,9 +322,11 @@
             return false;
 
         switch (field.id) {
+            case ARP_SPA:
             case IPV4_SRC:
                 int srcCidrLen = getIpv4SrcCidrMaskLen();
                 return srcCidrLen > 0 && srcCidrLen < 32;
+            case ARP_TPA:
             case IPV4_DST:
                 int dstCidrLen = getIpv4SrcCidrMaskLen();
                 return dstCidrLen > 0 && dstCidrLen < 32;
diff --git a/java_gen/templates/of_class.java b/java_gen/templates/of_class.java
index 458d3f0..7b3b762 100644
--- a/java_gen/templates/of_class.java
+++ b/java_gen/templates/of_class.java
@@ -229,9 +229,14 @@
 //:: #endif
 //:: #endfor
             //:: if msg.align:
-            // align message to ${msg.align} bytes
+            //:: if msg.length_includes_align:
+            // align message to ${msg.align} bytes (length contains aligned value)
+            bb.skipBytes(length - (bb.readerIndex() - start));
+            //:: else:
+            // align message to ${msg.align} bytes (length does not contain alignment)
             bb.skipBytes(((length + ${msg.align-1})/${msg.align} * ${msg.align} ) - length );
             //:: #endif
+            //:: #endif
 
             //:: if msg.data_members:
             //:: if os.path.exists("%s/custom/%s.Reader_normalize_stanza.java" % (template_dir, msg.name)):
@@ -247,6 +252,33 @@
         }
     }
 
+    public void putTo(PrimitiveSink sink) {
+        FUNNEL.funnel(this, sink);
+    }
+
+    final static ${impl_class}Funnel FUNNEL = new ${impl_class}Funnel();
+    static class ${impl_class}Funnel implements Funnel<${impl_class}> {
+        private static final long serialVersionUID = 1L;
+        @Override
+        public void funnel(${impl_class} message, PrimitiveSink sink) {
+//:: for prop in msg.members:
+//:: if prop.is_virtual:
+//::    continue
+//:: elif prop.is_data:
+            ${prop.java_type.funnel_op(version, "message." + prop.name, pub_type=True)};
+//:: elif prop.is_pad:
+            // skip pad (${prop.length} bytes)
+//:: elif prop.is_fixed_value:
+            // fixed value property ${prop.name} = ${prop.value}
+            ${prop.java_type.funnel_op(version, prop.priv_value, pub_type=False)};
+//:: else:
+            // FIXME: skip funnel of ${prop.name}
+//:: #endif
+//:: #endfor
+        }
+    }
+
+
     public void writeTo(ChannelBuffer bb) {
         WRITER.write(bb, this);
     }
@@ -300,10 +332,13 @@
 //:: if not msg.is_fixed_length:
             // update length field
             int length = bb.writerIndex() - startIndex;
-            bb.setShort(lengthIndex, length);
+            //:: if msg.align:
+            int alignedLength = ((length + ${msg.align-1})/${msg.align} * ${msg.align});
+            //:: #endif
+            bb.setShort(lengthIndex, ${"alignedLength" if msg.length_includes_align else "length"});
             //:: if msg.align:
             // align message to ${msg.align} bytes
-            bb.writeZero( ((length + ${msg.align-1})/${msg.align} * ${msg.align}) - length);
+            bb.writeZero(alignedLength - length);
             //:: #endif
 //:: #end
 
diff --git a/java_gen/templates/of_factories.java b/java_gen/templates/of_factories.java
index 0044335..f8c9a80 100644
--- a/java_gen/templates/of_factories.java
+++ b/java_gen/templates/of_factories.java
@@ -36,6 +36,9 @@
 //:: include("_imports.java")
 
 public final class OFFactories {
+
+    private static final GenericReader GENERIC_READER = new GenericReader();
+
     public static OFFactory getFactory(OFVersion version) {
         switch(version) {
             //:: for v in versions:
@@ -46,4 +49,25 @@
                 throw new IllegalArgumentException("Unknown version: "+version);
             }
     }
+    
+    private static class GenericReader implements OFMessageReader<OFMessage> {
+        public OFMessage readFrom(ChannelBuffer bb) throws OFParseError {
+            short wireVersion = U8.f(bb.getByte(0));
+            OFFactory factory;
+            switch (wireVersion) {
+            //:: for v in versions:
+            case ${v.int_version}:
+                factory = org.projectfloodlight.openflow.protocol.ver${v.of_version}.OFFactoryVer${v.of_version}.INSTANCE;
+                break;
+            //:: #endfor
+            default:
+                throw new IllegalArgumentException("Unknown wire version: " + wireVersion);
+            }
+            return factory.getReader().readFrom(bb);
+        }
+    }
+
+    public static OFMessageReader<OFMessage> getGenericReader() {
+        return GENERIC_READER;
+    }
 }
diff --git a/java_gen/templates/unit_test.java b/java_gen/templates/unit_test.java
index 5a525e4..cd85a74 100644
--- a/java_gen/templates/unit_test.java
+++ b/java_gen/templates/unit_test.java
@@ -80,6 +80,7 @@
 
         // FIXME should invoke the overall reader once implemented
         ${var_type} ${var_name}Read = ${msg.name}.READER.readFrom(input);
+        assertEquals(${msg.constant_name}_SERIALIZED.length, input.readerIndex());
 
         assertEquals(${var_name}Built, ${var_name}Read);
    }
@@ -93,6 +94,7 @@
 
        // FIXME should invoke the overall reader once implemented
        ${var_type} ${var_name} = ${msg.name}.READER.readFrom(input);
+       assertEquals(${msg.constant_name}_SERIALIZED.length, input.readerIndex());
 
        // write message again
        ChannelBuffer bb = ChannelBuffers.dynamicBuffer();
diff --git a/loxi_front_end/parser.py b/loxi_front_end/parser.py
index f2cf4b0..4a465f7 100644
--- a/loxi_front_end/parser.py
+++ b/loxi_front_end/parser.py
@@ -56,7 +56,7 @@
 type_member = P.Group(tag('type') + any_type + identifier + s('==') + integer)
 data_member = P.Group(tag('data') + any_type - identifier)
 
-struct_param_name = kw("align")
+struct_param_name = kw("align") | kw("length_includes_align")
 struct_param = P.Group(struct_param_name - s('=') - word)
 struct_param_list = P.Forward()
 struct_param_list << struct_param + P.Optional(s(',') - P.Optional(struct_param_list))
diff --git a/openflow_input/bsn_flow_idle b/openflow_input/bsn_flow_idle
new file mode 100644
index 0000000..40a95d8
--- /dev/null
+++ b/openflow_input/bsn_flow_idle
@@ -0,0 +1,99 @@
+// 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
+
+/*
+ * Notification of idle flows
+ *
+ * This extension allows the controller to request to be notified periodically
+ * about idle flows. It is very similar to the flow_removed message in standard
+ * OpenFlow, but does not delete the idle flows.
+ *
+ * If the extension is enabled using of_bsn_flow_idle_enable_set_request and
+ * the OFPFF_BSN_SEND_IDLE bit is set in the flow-mod, then the idle_timeout
+ * field in the flow-mod is not used for standard flow expiration. Instead,
+ * the switch will send an of_bsn_flow_idle message every idle_timeout seconds
+ * if the flow was not used during that period.
+ */
+
+struct of_bsn_flow_idle_enable_set_request : of_bsn_header {
+    uint8_t version;
+    uint8_t type == 4;
+    uint16_t length;
+    uint32_t xid;
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 36;
+    uint32_t enable;        // 0 to disable the extension, 1 to enable it
+};
+
+struct of_bsn_flow_idle_enable_set_reply : of_bsn_header {
+    uint8_t version;
+    uint8_t type == 4;
+    uint16_t length;
+    uint32_t xid;
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 37;
+    uint32_t enable;        // Resulting state, 0 disabled, 1 enabled
+    uint32_t status;        // Result code: 0 success
+};
+
+struct of_bsn_flow_idle_enable_get_request : of_bsn_header {
+    uint8_t version;
+    uint8_t type == 4;
+    uint16_t length;
+    uint32_t xid;
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 38;
+};
+
+struct of_bsn_flow_idle_enable_get_reply : of_bsn_header {
+    uint8_t version;
+    uint8_t type == 4;
+    uint16_t length;
+    uint32_t xid;
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 39;
+    uint32_t enabled;       // 0 if feature is disabled; 1 if feature enabled
+};
+
+struct of_bsn_flow_idle : of_bsn_header {
+    uint8_t version;
+    uint8_t type == 4;
+    uint16_t length;
+    uint32_t xid;
+    uint32_t experimenter == 0x5c16c7;
+    uint32_t subtype == 40;
+    uint64_t cookie;
+    uint16_t priority;
+    uint8_t table_id;
+    pad(5); // align to 8 bytes
+    of_match_t match;
+};
diff --git a/openflow_input/standard-1.0 b/openflow_input/standard-1.0
index 3493c6b..ad2e76f 100644
--- a/openflow_input/standard-1.0
+++ b/openflow_input/standard-1.0
@@ -94,6 +94,7 @@
     OFPPC_NO_FLOOD = 0x10,
     OFPPC_NO_FWD = 0x20,
     OFPPC_NO_PACKET_IN = 0x40,
+    OFPPC_BSN_MIRROR_DEST = 0x80000000,
 };
 
 enum ofp_port_state(wire_type=uint32_t, bitmask=True) {
@@ -210,6 +211,10 @@
     OFPFF_EMERG = 0x4,
 };
 
+enum ofp_stats_request_flags(wire_type=uint16_t, bitmask=True) {
+};
+
+
 enum ofp_stats_reply_flags(wire_type=uint16_t, bitmask=True) {
     OFPSF_REPLY_MORE = 0x1,
 };
@@ -824,7 +829,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == ?;
-    uint16_t flags;
+    enum ofp_stats_request_flags flags;
 };
 
 struct of_stats_reply : of_header {
@@ -833,7 +838,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == ?;
-    uint16_t flags;
+    enum ofp_stats_reply_flags flags;
 };
 
 struct of_desc_stats_request : of_stats_request {
@@ -842,7 +847,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 0;
-    uint16_t flags;
+    enum ofp_stats_request_flags flags;
 };
 
 struct of_desc_stats_reply : of_stats_reply {
@@ -851,7 +856,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 0;
-    uint16_t flags;
+    enum ofp_stats_reply_flags flags;
     of_desc_str_t mfr_desc;
     of_desc_str_t hw_desc;
     of_desc_str_t sw_desc;
@@ -865,7 +870,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 1;
-    uint16_t flags;
+    enum ofp_stats_request_flags flags;
     of_match_t match;
     uint8_t table_id;
     pad(1);
@@ -878,7 +883,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 1;
-    uint16_t flags;
+    enum ofp_stats_reply_flags flags;
     list(of_flow_stats_entry_t) entries;
 };
 
@@ -888,7 +893,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 2;
-    uint16_t flags;
+    enum ofp_stats_request_flags flags;
     of_match_t match;
     uint8_t table_id;
     pad(1);
@@ -901,7 +906,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 2;
-    uint16_t flags;
+    enum ofp_stats_reply_flags flags;
     uint64_t packet_count;
     uint64_t byte_count;
     uint32_t flow_count;
@@ -914,7 +919,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 3;
-    uint16_t flags;
+    enum ofp_stats_request_flags flags;
 };
 
 struct of_table_stats_reply : of_stats_reply {
@@ -923,7 +928,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 3;
-    uint16_t flags;
+    enum ofp_stats_reply_flags flags;
     list(of_table_stats_entry_t) entries;
 };
 
@@ -933,7 +938,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 4;
-    uint16_t flags;
+    enum ofp_stats_request_flags flags;
     of_port_no_t port_no;
     pad(6);
 };
@@ -944,7 +949,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 4;
-    uint16_t flags;
+    enum ofp_stats_reply_flags flags;
     list(of_port_stats_entry_t) entries;
 };
 
@@ -954,7 +959,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 5;
-    uint16_t flags;
+    enum ofp_stats_request_flags flags;
     of_port_no_t port_no;
     pad(2);
     uint32_t queue_id;
@@ -966,7 +971,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 5;
-    uint16_t flags;
+    enum ofp_stats_reply_flags flags;
     list(of_queue_stats_entry_t) entries;
 };
 
@@ -976,7 +981,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 0xffff;
-    uint16_t flags;
+    enum ofp_stats_request_flags flags;
     uint32_t experimenter == ?;
     of_octets_t data;
 };
@@ -987,7 +992,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 0xffff;
-    uint16_t flags;
+    enum ofp_stats_reply_flags flags;
     uint32_t experimenter == ?;
     of_octets_t data;
 };
diff --git a/openflow_input/standard-1.1 b/openflow_input/standard-1.1
index e4776e9..9b72e8c 100644
--- a/openflow_input/standard-1.1
+++ b/openflow_input/standard-1.1
@@ -132,6 +132,7 @@
     OFPPC_NO_RECV = 0x4,
     OFPPC_NO_FWD = 0x20,
     OFPPC_NO_PACKET_IN = 0x40,
+    OFPPC_BSN_MIRROR_DEST = 0x80000000,
 };
 
 enum ofp_port_state(wire_type=uint32_t, bitmask=True) {
@@ -395,6 +396,11 @@
     OFPST_EXPERIMENTER = 0xffff,
 };
 
+// none defined
+enum ofp_stats_request_flags(wire_type=uint16_t, bitmask=True) {
+};
+
+
 enum ofp_stats_reply_flags(wire_type=uint16_t, bitmask=True) {
     OFPSF_REPLY_MORE = 0x1,
 };
@@ -1213,7 +1219,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == ?;
-    uint16_t flags;
+    enum ofp_stats_request_flags flags;
     pad(4);
 };
 
@@ -1223,7 +1229,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == ?;
-    uint16_t flags;
+    enum ofp_stats_reply_flags flags;
     pad(4);
 };
 
@@ -1233,7 +1239,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 0;
-    uint16_t flags;
+    enum ofp_stats_request_flags flags;
     pad(4);
 };
 
@@ -1243,7 +1249,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 0;
-    uint16_t flags;
+    enum ofp_stats_reply_flags flags;
     pad(4);
     of_desc_str_t mfr_desc;
     of_desc_str_t hw_desc;
@@ -1258,7 +1264,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 1;
-    uint16_t flags;
+    enum ofp_stats_request_flags flags;
     pad(4);
     uint8_t table_id;
     pad(3);
@@ -1276,7 +1282,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 1;
-    uint16_t flags;
+    enum ofp_stats_reply_flags flags;
     pad(4);
     list(of_flow_stats_entry_t) entries;
 };
@@ -1287,7 +1293,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 2;
-    uint16_t flags;
+    enum ofp_stats_request_flags flags;
     pad(4);
     uint8_t table_id;
     pad(3);
@@ -1305,7 +1311,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 2;
-    uint16_t flags;
+    enum ofp_stats_reply_flags flags;
     pad(4);
     uint64_t packet_count;
     uint64_t byte_count;
@@ -1319,7 +1325,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 3;
-    uint16_t flags;
+    enum ofp_stats_request_flags flags;
     pad(4);
 };
 
@@ -1329,7 +1335,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 3;
-    uint16_t flags;
+    enum ofp_stats_reply_flags flags;
     pad(4);
     list(of_table_stats_entry_t) entries;
 };
@@ -1340,7 +1346,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 4;
-    uint16_t flags;
+    enum ofp_stats_request_flags flags;
     pad(4);
     of_port_no_t port_no;
     pad(4);
@@ -1352,7 +1358,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 4;
-    uint16_t flags;
+    enum ofp_stats_reply_flags flags;
     pad(4);
     list(of_port_stats_entry_t) entries;
 };
@@ -1363,7 +1369,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 5;
-    uint16_t flags;
+    enum ofp_stats_request_flags flags;
     pad(4);
     of_port_no_t port_no;
     uint32_t queue_id;
@@ -1375,7 +1381,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 5;
-    uint16_t flags;
+    enum ofp_stats_reply_flags flags;
     pad(4);
     list(of_queue_stats_entry_t) entries;
 };
@@ -1386,7 +1392,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 6;
-    uint16_t flags;
+    enum ofp_stats_request_flags flags;
     pad(4);
     uint32_t group_id;
     pad(4);
@@ -1398,7 +1404,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 6;
-    uint16_t flags;
+    enum ofp_stats_reply_flags flags;
     pad(4);
     list(of_group_stats_entry_t) entries;
 };
@@ -1409,7 +1415,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 7;
-    uint16_t flags;
+    enum ofp_stats_request_flags flags;
     pad(4);
 };
 
@@ -1419,7 +1425,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 7;
-    uint16_t flags;
+    enum ofp_stats_reply_flags flags;
     pad(4);
     list(of_group_desc_stats_entry_t) entries;
 };
@@ -1430,7 +1436,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 0xffff;
-    uint16_t flags;
+    enum ofp_stats_request_flags flags;
     pad(4);
     uint32_t experimenter == ?;
     pad(4);
@@ -1443,7 +1449,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 0xffff;
-    uint16_t flags;
+    enum ofp_stats_reply_flags flags;
     pad(4);
     uint32_t experimenter == ?;
     pad(4);
diff --git a/openflow_input/standard-1.2 b/openflow_input/standard-1.2
index 1e54141..e9d915a 100644
--- a/openflow_input/standard-1.2
+++ b/openflow_input/standard-1.2
@@ -135,6 +135,7 @@
     OFPPC_NO_RECV = 0x4,
     OFPPC_NO_FWD = 0x20,
     OFPPC_NO_PACKET_IN = 0x40,
+    OFPPC_BSN_MIRROR_DEST = 0x80000000,
 };
 
 enum ofp_port_state(wire_type=uint32_t, bitmask=True) {
@@ -420,6 +421,9 @@
     OFPST_EXPERIMENTER = 0xffff,
 };
 
+enum ofp_stats_request_flags(wire_type=uint16_t, bitmask=True) {
+};
+
 enum ofp_stats_reply_flags(wire_type=uint16_t, bitmask=True) {
     OFPSF_REPLY_MORE = 0x1,
 };
@@ -596,7 +600,7 @@
     pad(4);
 };
 
-struct of_match_v3(align=8) {
+struct of_match_v3(align=8, length_includes_align=False) {
     uint16_t type == 1;
     uint16_t length;
     list(of_oxm_t) oxm_list;
@@ -687,13 +691,13 @@
     pad(4);
 };
 
-struct of_action_set_field : of_action {
+struct of_action_set_field(align=8, length_includes_align=True) : of_action {
     uint16_t type == 25;
     uint16_t len;
     of_oxm_t field;
 };
 
-struct of_action_experimenter : of_action {
+struct of_action_experimenter(align=8, length_includes_align=True) : of_action {
     uint16_t type == 65535;
     uint16_t len;
     uint32_t experimenter == ?;
@@ -1183,7 +1187,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == ?;
-    uint16_t flags;
+    enum ofp_stats_request_flags flags;
     pad(4);
 };
 
@@ -1193,7 +1197,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == ?;
-    uint16_t flags;
+    enum ofp_stats_reply_flags flags;
     pad(4);
 };
 
@@ -1203,7 +1207,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 0;
-    uint16_t flags;
+    enum ofp_stats_request_flags flags;
     pad(4);
 };
 
@@ -1213,7 +1217,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 0;
-    uint16_t flags;
+    enum ofp_stats_reply_flags flags;
     pad(4);
     of_desc_str_t mfr_desc;
     of_desc_str_t hw_desc;
@@ -1228,7 +1232,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 1;
-    uint16_t flags;
+    enum ofp_stats_request_flags flags;
     pad(4);
     uint8_t table_id;
     pad(3);
@@ -1246,7 +1250,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 1;
-    uint16_t flags;
+    enum ofp_stats_reply_flags flags;
     pad(4);
     list(of_flow_stats_entry_t) entries;
 };
@@ -1257,7 +1261,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 2;
-    uint16_t flags;
+    enum ofp_stats_request_flags flags;
     pad(4);
     uint8_t table_id;
     pad(3);
@@ -1275,7 +1279,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 2;
-    uint16_t flags;
+    enum ofp_stats_reply_flags flags;
     pad(4);
     uint64_t packet_count;
     uint64_t byte_count;
@@ -1289,7 +1293,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 3;
-    uint16_t flags;
+    enum ofp_stats_request_flags flags;
     pad(4);
 };
 
@@ -1299,7 +1303,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 3;
-    uint16_t flags;
+    enum ofp_stats_reply_flags flags;
     pad(4);
     list(of_table_stats_entry_t) entries;
 };
@@ -1310,7 +1314,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 4;
-    uint16_t flags;
+    enum ofp_stats_request_flags flags;
     pad(4);
     of_port_no_t port_no;
     pad(4);
@@ -1322,7 +1326,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 4;
-    uint16_t flags;
+    enum ofp_stats_reply_flags flags;
     pad(4);
     list(of_port_stats_entry_t) entries;
 };
@@ -1333,7 +1337,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 5;
-    uint16_t flags;
+    enum ofp_stats_request_flags flags;
     pad(4);
     of_port_no_t port_no;
     uint32_t queue_id;
@@ -1345,7 +1349,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 5;
-    uint16_t flags;
+    enum ofp_stats_reply_flags flags;
     pad(4);
     list(of_queue_stats_entry_t) entries;
 };
@@ -1356,7 +1360,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 6;
-    uint16_t flags;
+    enum ofp_stats_request_flags flags;
     pad(4);
     uint32_t group_id;
     pad(4);
@@ -1368,7 +1372,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 6;
-    uint16_t flags;
+    enum ofp_stats_reply_flags flags;
     pad(4);
     list(of_group_stats_entry_t) entries;
 };
@@ -1379,7 +1383,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 7;
-    uint16_t flags;
+    enum ofp_stats_request_flags flags;
     pad(4);
 };
 
@@ -1389,7 +1393,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 7;
-    uint16_t flags;
+    enum ofp_stats_reply_flags flags;
     pad(4);
     list(of_group_desc_stats_entry_t) entries;
 };
@@ -1400,7 +1404,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 8;
-    uint16_t flags;
+    enum ofp_stats_request_flags flags;
     pad(4);
 };
 
@@ -1410,7 +1414,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 8;
-    uint16_t flags;
+    enum ofp_stats_reply_flags flags;
     pad(4);
     uint32_t types;
     uint32_t capabilities;
@@ -1430,7 +1434,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 0xffff;
-    uint16_t flags;
+    enum ofp_stats_request_flags flags;
     pad(4);
     uint32_t experimenter == ?;
     uint32_t subtype;
@@ -1443,7 +1447,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 0xffff;
-    uint16_t flags;
+    enum ofp_stats_reply_flags flags;
     pad(4);
     uint32_t experimenter == ?;
     uint32_t subtype;
@@ -1515,7 +1519,7 @@
     uint8_t type == 24;
     uint16_t length;
     uint32_t xid;
-    uint32_t role;
+    enum ofp_controller_role role;
     pad(4);
     uint64_t generation_id;
 };
@@ -1525,5 +1529,7 @@
     uint8_t type == 25;
     uint16_t length;
     uint32_t xid;
-    of_octets_t data;
+    enum ofp_controller_role role;
+    pad(4);
+    uint64_t generation_id;
 };
diff --git a/openflow_input/standard-1.3 b/openflow_input/standard-1.3
index ac6fb5c..db7ff0d 100644
--- a/openflow_input/standard-1.3
+++ b/openflow_input/standard-1.3
@@ -134,6 +134,7 @@
     OFPPC_NO_RECV = 0x4,
     OFPPC_NO_FWD = 0x20,
     OFPPC_NO_PACKET_IN = 0x40,
+    OFPPC_BSN_MIRROR_DEST = 0x80000000,
 };
 
 enum ofp_port_state(wire_type=uint32_t, bitmask=True) {
@@ -247,6 +248,10 @@
     OFPFF_RESET_COUNTS = 0x4,
     OFPFF_NO_PKT_COUNTS = 0x8,
     OFPFF_NO_BYT_COUNTS = 0x10,
+
+    /* Non-standard, enabled by an experimenter message */
+    /* See the bsn_flow_idle input file */
+    OFPFF_BSN_SEND_IDLE = 0x80,
 };
 
 enum ofp_group(wire_type=uint32_t, complete=False) {
@@ -272,6 +277,13 @@
     OFPR_NO_MATCH = 0,
     OFPR_ACTION = 1,
     OFPR_INVALID_TTL = 2,
+
+    // non-standard BSN extensions. OF does not have a standard-conformant
+    // way to extend the set of packet_in reasons
+    OFPR_BSN_NEW_HOST = 128,
+    OFPR_BSN_STATION_MOVE = 129,
+    OFPR_BSN_BAD_VLAN = 130,
+    OFPR_BSN_DESTINATION_LOOKUP_FAILURE = 131,
 };
 
 enum ofp_flow_removed_reason(wire_type=uint8_t) {
@@ -722,7 +734,7 @@
 };
 
 // FIXME Does this need to be v4?
-struct of_match_v3(align=8) {
+struct of_match_v3(align=8, length_includes_align=False) {
     uint16_t type == 1;
     uint16_t length;
     list(of_oxm_t) oxm_list;
@@ -821,13 +833,13 @@
     pad(4);
 };
 
-struct of_action_set_field : of_action {
+struct of_action_set_field(align=8, length_includes_align=True) : of_action {
     uint16_t type == 25;
     uint16_t len;
     of_oxm_t field;
 };
 
-struct of_action_experimenter : of_action {
+struct of_action_experimenter(align=8, length_includes_align=True): of_action {
     uint16_t type == 65535;
     uint16_t len;
     uint32_t experimenter == ?;
@@ -1394,7 +1406,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == ?;
-    uint16_t flags;
+    enum ofp_stats_request_flags flags;
     pad(4);
 };
 
@@ -1404,7 +1416,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == ?;
-    uint16_t flags;
+    enum ofp_stats_reply_flags flags;
     pad(4);
 };
 
@@ -1414,7 +1426,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 0;
-    uint16_t flags;
+    enum ofp_stats_request_flags flags;
     pad(4);
 };
 
@@ -1424,7 +1436,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 0;
-    uint16_t flags;
+    enum ofp_stats_reply_flags flags;
     pad(4);
     of_desc_str_t mfr_desc;
     of_desc_str_t hw_desc;
@@ -1439,7 +1451,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 1;
-    uint16_t flags;
+    enum ofp_stats_request_flags flags;
     pad(4);
     uint8_t table_id;
     pad(3);
@@ -1457,7 +1469,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 1;
-    uint16_t flags;
+    enum ofp_stats_reply_flags flags;
     pad(4);
     list(of_flow_stats_entry_t) entries;
 };
@@ -1468,7 +1480,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 2;
-    uint16_t flags;
+    enum ofp_stats_request_flags flags;
     pad(4);
     uint8_t table_id;
     pad(3);
@@ -1486,7 +1498,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 2;
-    uint16_t flags;
+    enum ofp_stats_reply_flags flags;
     pad(4);
     uint64_t packet_count;
     uint64_t byte_count;
@@ -1500,7 +1512,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 3;
-    uint16_t flags;
+    enum ofp_stats_request_flags flags;
     pad(4);
 };
 
@@ -1510,7 +1522,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 3;
-    uint16_t flags;
+    enum ofp_stats_reply_flags flags;
     pad(4);
     list(of_table_stats_entry_t) entries;
 };
@@ -1651,7 +1663,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 4;
-    uint16_t flags;
+    enum ofp_stats_request_flags flags;
     pad(4);
     of_port_no_t port_no;
     pad(4);
@@ -1663,7 +1675,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 4;
-    uint16_t flags;
+    enum ofp_stats_reply_flags flags;
     pad(4);
     list(of_port_stats_entry_t) entries;
 };
@@ -1674,7 +1686,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 5;
-    uint16_t flags;
+    enum ofp_stats_request_flags flags;
     pad(4);
     of_port_no_t port_no;
     uint32_t queue_id;
@@ -1686,7 +1698,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 5;
-    uint16_t flags;
+    enum ofp_stats_reply_flags flags;
     pad(4);
     list(of_queue_stats_entry_t) entries;
 };
@@ -1697,7 +1709,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 6;
-    uint16_t flags;
+    enum ofp_stats_request_flags flags;
     pad(4);
     uint32_t group_id;
     pad(4);
@@ -1709,7 +1721,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 6;
-    uint16_t flags;
+    enum ofp_stats_reply_flags flags;
     pad(4);
     list(of_group_stats_entry_t) entries;
 };
@@ -1720,7 +1732,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 7;
-    uint16_t flags;
+    enum ofp_stats_request_flags flags;
     pad(4);
 };
 
@@ -1730,7 +1742,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 7;
-    uint16_t flags;
+    enum ofp_stats_reply_flags flags;
     pad(4);
     list(of_group_desc_stats_entry_t) entries;
 };
@@ -1741,7 +1753,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 8;
-    uint16_t flags;
+    enum ofp_stats_request_flags flags;
     pad(4);
 };
 
@@ -1751,7 +1763,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 8;
-    uint16_t flags;
+    enum ofp_stats_reply_flags flags;
     pad(4);
     uint32_t types;
     uint32_t capabilities;
@@ -1771,7 +1783,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 9;
-    uint16_t flags;
+    enum ofp_stats_request_flags flags;
     pad(4);
     uint32_t meter_id;
     pad(4);
@@ -1783,7 +1795,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 9;
-    uint16_t flags;
+    enum ofp_stats_reply_flags flags;
     pad(4);
     list(of_meter_stats_t) entries;
 };
@@ -1794,7 +1806,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 10;
-    uint16_t flags;
+    enum ofp_stats_request_flags flags;
     pad(4);
     uint32_t meter_id;
     pad(4);
@@ -1806,7 +1818,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 10;
-    uint16_t flags;
+    enum ofp_stats_reply_flags flags;
     pad(4);
     list(of_meter_band_t) entries;
 };
@@ -1818,7 +1830,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 11;
-    uint16_t flags;
+    enum ofp_stats_request_flags flags;
     pad(4);
 };
 
@@ -1829,7 +1841,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 11;
-    uint16_t flags;
+    enum ofp_stats_reply_flags flags;
     pad(4);
     of_meter_features_t features;
 };
@@ -1841,7 +1853,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 12;
-    uint16_t flags;
+    enum ofp_stats_request_flags flags;
     pad(4);
     list(of_table_features_t) entries;
 };
@@ -1853,7 +1865,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 12;
-    uint16_t flags;
+    enum ofp_stats_reply_flags flags;
     pad(4);
     list(of_table_features_t) entries;
 };
@@ -1865,7 +1877,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 13;
-    uint16_t flags;
+    enum ofp_stats_request_flags flags;
     pad(4);
 };
 
@@ -1876,7 +1888,7 @@
     uint16_t length;
     uint32_t xid;
     uint16_t stats_type == 13;
-    uint16_t flags;
+    enum ofp_stats_reply_flags flags;
     pad(4);
     list(of_port_desc_t) entries;
 };
@@ -1975,7 +1987,7 @@
     uint8_t type == 24;
     uint16_t length;
     uint32_t xid;
-    uint32_t role;
+    enum ofp_controller_role role;
     pad(4);
     uint64_t generation_id;
 };
@@ -1985,7 +1997,9 @@
     uint8_t type == 25;
     uint16_t length;
     uint32_t xid;
-    of_octets_t data;
+    enum ofp_controller_role role;
+    pad(4);
+    uint64_t generation_id;
 };
 
 ////////////////////////////////////////////////////////////////
diff --git a/test_data/__init__.py b/test_data/__init__.py
index 7a55c11..dc063fa 100644
--- a/test_data/__init__.py
+++ b/test_data/__init__.py
@@ -26,6 +26,7 @@
 # EPL for the specific language governing permissions and limitations
 # under the EPL.
 
+import fnmatch
 import os
 
 _test_data_dir = os.path.dirname(os.path.realpath(__file__))
@@ -45,6 +46,11 @@
                 result.append(dirname + '/' + filename)
     return sorted(result)
 
+def glob(pattern):
+    for f in list_files():
+        if fnmatch.fnmatch(f, pattern):
+            yield f
+
 def exists(name):
     return os.path.exists(os.path.join(_test_data_dir, name))
 
diff --git a/test_data/of13/action_output.data b/test_data/of13/action_output.data
index 7cd52ce..7653a30 100644
--- a/test_data/of13/action_output.data
+++ b/test_data/of13/action_output.data
@@ -6,3 +6,5 @@
 00 00 00 00 00 00 # pad
 -- python
 ofp.action.output(port=50, max_len=65535)
+-- java
+builder.setPort(OFPort.of(50)).setMaxLen(65535)
diff --git a/test_data/of13/action_set_field__eth_dst.data b/test_data/of13/action_set_field__eth_dst.data
new file mode 100644
index 0000000..833bb36
--- /dev/null
+++ b/test_data/of13/action_set_field__eth_dst.data
@@ -0,0 +1,11 @@
+-- binary
+00 19 # type
+00 10 # length
+80 00 06 06 # OXM header
+00 01 02 03 04 05 # OXM value
+00 00 # pad
+-- python
+ofp.action.set_field(field=ofp.oxm.eth_dst([0, 1, 2, 3, 4, 5]))
+-- java
+OFOxms oxms = OFFactories.getFactory(OFVersion.OF_13).oxms();
+builder.setField(oxms.ethDst(MacAddress.of("00:01:02:03:04:05")))
diff --git a/test_data/of13/action_set_field_ipv6_src.data b/test_data/of13/action_set_field__ipv6_src.data
similarity index 60%
rename from test_data/of13/action_set_field_ipv6_src.data
rename to test_data/of13/action_set_field__ipv6_src.data
index f440dee..cfa2738 100644
--- a/test_data/of13/action_set_field_ipv6_src.data
+++ b/test_data/of13/action_set_field__ipv6_src.data
@@ -5,3 +5,6 @@
 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f # OXM value
 -- python
 ofp.action.set_field(field=ofp.oxm.ipv6_src("\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"))
+-- java
+OFOxms oxms = OFFactories.getFactory(OFVersion.OF_13).oxms();
+builder.setField(oxms.ipv6Src(IPv6Address.of("0001:0203:0405:0607:0809:0a0b:0c0d:0e0f")))
diff --git a/test_data/of13/action_set_field__tcp_src.data b/test_data/of13/action_set_field__tcp_src.data
new file mode 100644
index 0000000..41c4780
--- /dev/null
+++ b/test_data/of13/action_set_field__tcp_src.data
@@ -0,0 +1,11 @@
+-- binary
+00 19 # type
+00 10 # length
+80 00 1a 02 # OXM header
+00 32 # OXM value
+00 00 00 00 00 00 # pad
+-- python
+ofp.action.set_field(field=ofp.oxm.tcp_src(50))
+-- java
+OFOxms oxms = OFFactories.getFactory(OFVersion.OF_13).oxms();
+builder.setField(oxms.tcpSrc(TransportPort.of(50)))
diff --git a/test_data/of13/action_set_field_eth_dst.data b/test_data/of13/action_set_field_eth_dst.data
deleted file mode 100644
index 1e4a971..0000000
--- a/test_data/of13/action_set_field_eth_dst.data
+++ /dev/null
@@ -1,8 +0,0 @@
--- binary
-00 19 # type
-00 10 # length
-80 00 06 06 # OXM header
-00 01 02 03 04 05 # OXM value
-00 00 # pad
--- python
-ofp.action.set_field(field=ofp.oxm.eth_dst([0, 1, 2, 3, 4, 5]))
diff --git a/test_data/of13/action_set_field_tcp_src.data b/test_data/of13/action_set_field_tcp_src.data
deleted file mode 100644
index a69c7c0..0000000
--- a/test_data/of13/action_set_field_tcp_src.data
+++ /dev/null
@@ -1,8 +0,0 @@
--- binary
-00 19 # type
-00 10 # length
-80 00 1a 02 # OXM header
-00 32 # OXM value
-00 00 00 00 00 00 # pad
--- python
-ofp.action.set_field(field=ofp.oxm.tcp_src(50))
diff --git a/test_data/of13/bsn_flow_idle.data b/test_data/of13/bsn_flow_idle.data
new file mode 100644
index 0000000..61b656f
--- /dev/null
+++ b/test_data/of13/bsn_flow_idle.data
@@ -0,0 +1,54 @@
+-- binary
+04 04 # version, type
+00 38 # length
+12 34 56 78 # xid
+00 5c 16 c7 # experimenter
+00 00 00 28 # subtype
+fe dc ba 98 76 54 32 10 # cookie
+42 68 # priority
+14 # table_id
+00 # pad
+00 00 00 00 # pad
+00 01 # match.type
+00 16 # match.length
+80 00 01 08 # match.oxm_list[0].type_len - IN_PORT
+00 00 00 04 # match.oxm_list[0].value
+00 00 00 05 # match.oxm_list[0].mask
+80 00 2A 02 # match.oxm_list[1].type_len - ARP_OP
+00 01 # match.oxm_list[1].value
+00 00 # match.pad
+-- python
+ofp.message.bsn_flow_idle(
+    xid=0x12345678,
+    cookie=0xFEDCBA9876543210,
+    priority=17000,
+    table_id=20,
+    match=ofp.match([
+        ofp.oxm.in_port_masked(value=4, value_mask=5),
+        ofp.oxm.arp_op(value=1),
+    ]))
+-- c
+obj = of_bsn_flow_idle_new(OF_VERSION_1_3);
+of_bsn_flow_idle_xid_set(obj, 0x12345678);
+of_bsn_flow_idle_cookie_set(obj, 0xFEDCBA9876543210);
+of_bsn_flow_idle_priority_set(obj, 17000);
+of_bsn_flow_idle_table_id_set(obj, 20);
+{
+    of_match_t match = { OF_VERSION_1_3 };
+    match.fields.in_port = 4;
+    match.masks.in_port = 5;
+    match.fields.arp_op = 1;
+    OF_MATCH_MASK_ARP_OP_EXACT_SET(&match);
+    of_bsn_flow_idle_match_set(obj, &match);
+}
+-- java
+builder.setXid(0x12345678)
+    .setCookie(U64.parseHex("FEDCBA9876543210"))
+    .setPriority(17000)
+    .setTableId(TableId.of(20))
+    .setMatch(
+        factory.buildMatch()
+            .setMasked(MatchField.IN_PORT, OFPort.of(4), OFPort.of(5))
+            .setExact(MatchField.ARP_OP, ArpOpcode.of(1))
+                .build()
+    );