Merge into master from pull request #81:
a bunch of smaller improvements (https://github.com/floodlight/loxigen/pull/81)
diff --git a/c_gen/c_code_gen.py b/c_gen/c_code_gen.py
index df9d9da..798f5a4 100644
--- a/c_gen/c_code_gen.py
+++ b/c_gen/c_code_gen.py
@@ -1007,6 +1007,11 @@
 typedef char of_desc_str_t[OF_DESC_STR_LEN];
 typedef char of_serial_num_t[OF_SERIAL_NUM_LEN];
 
+typedef struct of_bitmap_128_s {
+    uint64_t hi;
+    uint64_t lo;
+} of_bitmap_128_t;
+
 /* These are types which change across versions.  */
 typedef uint32_t of_port_no_t;
 typedef uint16_t of_fm_cmd_t;
diff --git a/c_gen/c_match.py b/c_gen/c_match.py
index 7353ae7..e15688e 100644
--- a/c_gen/c_match.py
+++ b/c_gen/c_match.py
@@ -286,6 +286,8 @@
     OF_OXM_INDEX_IPV6_ND_TLL    = 33, /* Target link-layer for ND. */
     OF_OXM_INDEX_MPLS_LABEL     = 34, /* MPLS label. */
     OF_OXM_INDEX_MPLS_TC        = 35, /* MPLS TC. */
+
+    OF_OXM_INDEX_BSN_IN_PORTS_128 = 36,
 };
 
 #define OF_OXM_BIT(index) (((uint64_t) 1) << (index))
@@ -1066,6 +1068,15 @@
 #define OF_OVERLAP_MAC_ADDR(v1, v2, m1, m2) \\
     of_overlap_mac_addr((v1), (v2), (m1), (m2))
 
+#define OF_MORE_SPECIFIC_BITMAP_128(v1, v2) \\
+    (OF_MORE_SPECIFIC_INT((v1)->lo, (v2)->lo) && OF_MORE_SPECIFIC_INT((v1)->hi, (v2)->hi))
+
+#define OF_RESTRICTED_MATCH_BITMAP_128(v1, v2, mask) \\
+    (OF_RESTRICTED_MATCH_INT((v1)->lo, (v2)->lo, (mask)->lo) && OF_RESTRICTED_MATCH_INT((v1)->hi, (v2)->hi, (mask)->hi))
+
+#define OF_OVERLAP_BITMAP_128(v1, v2, m1, m2) \\
+    (OF_OVERLAP_INT((v1)->lo, (v2)->lo, (m1)->lo, (m2)->lo) && OF_OVERLAP_INT((v1)->hi, (v2)->hi, (m1)->hi, (m2)->hi))
+
 /**
  * More-specific-than macro for integer types; see above
  * @return true if v1 is equal to or more specific than v2
@@ -1136,6 +1147,9 @@
         elif entry["m_type"] == "of_mac_addr_t":
             comp = "OF_MORE_SPECIFIC_MAC_ADDR"
             match_type = "OF_RESTRICTED_MATCH_MAC_ADDR"
+        elif entry["m_type"] == "of_bitmap_128_t":
+            comp = "OF_MORE_SPECIFIC_BITMAP_128"
+            match_type = "OF_RESTRICTED_MATCH_BITMAP_128"
         else: # Integer
             comp = "OF_MORE_SPECIFIC_INT"
             match_type = "OF_RESTRICTED_MATCH_INT"
@@ -1190,6 +1204,8 @@
             check = "OF_OVERLAP_IPV6"
         elif entry["m_type"] == "of_mac_addr_t":
             check = "OF_OVERLAP_MAC_ADDR"
+        elif entry["m_type"] == "of_bitmap_128_t":
+            check = "OF_OVERLAP_BITMAP_128"
         else: # Integer
             check = "OF_OVERLAP_INT"
             m1 = "m1->%s" % key
diff --git a/c_gen/c_test_gen.py b/c_gen/c_test_gen.py
index fab9f96..d237cfe 100644
--- a/c_gen/c_test_gen.py
+++ b/c_gen/c_test_gen.py
@@ -98,6 +98,7 @@
         of_match_t="match",
         # BSN extensions
         of_bsn_vport_q_in_q_t="vport",
+        of_bitmap_128_t="bitmap_128",
         )
 
     if m_type.find("of_list_") == 0:
@@ -111,7 +112,7 @@
                  "of_match_bmap_t", "of_ipv4_t"]
 string_types = [ "of_port_name_t", "of_table_name_t",
                 "of_desc_str_t", "of_serial_num_t", "of_mac_addr_t",
-                "of_ipv6_t"]
+                "of_ipv6_t", "of_bitmap_128_t"]
 
 scalar_types = integer_types[:]
 scalar_types.extend(string_types)
diff --git a/c_gen/c_type_maps.py b/c_gen/c_type_maps.py
index a0fec7e..3c523b4 100644
--- a/c_gen/c_type_maps.py
+++ b/c_gen/c_type_maps.py
@@ -507,6 +507,52 @@
 }
 """
 
+    oxm_template = """
+/**
+ * oxm wire type to object ID array.
+ * Treat as private; use function accessor below
+ */
+
+extern const of_object_id_t *const of_oxm_type_to_id[OF_VERSION_ARRAY_MAX];
+
+#define OF_OXM_ITEM_COUNT %(ar_len)d\n
+
+/**
+ * Map an oxm wire value to an OF object
+ * @param oxm The oxm type wire value
+ * @param version The version associated with the check
+ * @return The oxm OF object type
+ * @return OF_OBJECT_INVALID if type does not map to an object
+ *
+ */
+static inline of_object_id_t
+of_oxm_to_object_id(uint32_t type_len, of_version_t version)
+{
+    if (!OF_VERSION_OKAY(version)) {
+        return OF_OBJECT_INVALID;
+    }
+
+    uint16_t class = (type_len >> 16) & 0xffff;
+    uint8_t masked_type = (type_len >> 8) & 0xff;
+
+    if (class == 0x8000) {
+        if (masked_type < 0 || masked_type >= OF_OXM_ITEM_COUNT) {
+            return OF_OBJECT_INVALID;
+        }
+
+        return of_oxm_type_to_id[version][masked_type];
+    } else if (class == 0x0003) {
+        switch (masked_type) {
+        case 0x00: return OF_OXM_BSN_IN_PORTS_128;
+        case 0x01: return OF_OXM_BSN_IN_PORTS_128_MASKED;
+        default: return OF_OBJECT_INVALID;
+        }
+    } else {
+        return OF_OBJECT_INVALID;
+    }
+}
+"""
+
     # Action types array gen
     ar_len = type_maps.type_array_len(type_maps.action_types, max_type_value)
     out.write(map_with_experimenter_template %
@@ -561,13 +607,14 @@
     out.write(map_template %
               dict(name="flow_mod", u_name="FLOW_MOD", ar_len=ar_len))
 
+    # OXM
     ar_len = type_maps.type_array_len(type_maps.oxm_types, max_type_value)
     out.write("""
 /* NOTE: We could optimize the OXM and only generate OF 1.2 versions. */
 """)
-    out.write(map_template %
-              dict(name="oxm", u_name="OXM", ar_len=ar_len))
+    out.write(oxm_template % dict(ar_len=ar_len))
 
+    # Messages
     out.write(experimenter_function)
     # Must follow stats reply/request
     ar_len = type_maps.type_array_len(type_maps.message_types, max_type_value)
@@ -1003,11 +1050,6 @@
 extern void of_hello_elem_wire_object_id_get(of_object_t *obj,
     of_object_id_t *id);
 
-/* XXX Hardcoded to the OpenFlow Basic OXM class */
-#define OF_OXM_MASKED_TYPE_GET(hdr) (((hdr) >> 8) & 0xff)
-#define OF_OXM_MASKED_TYPE_SET(hdr, val)                    \\
-    (hdr) = ((hdr) & 0x000000ff) + 0x80000000 + (((val) & 0xff) << 8)
-
 #define OF_OXM_LENGTH_GET(hdr) (((hdr) & 0xff) + 4)
 #define OF_OXM_LENGTH_SET(hdr, val)                         \\
     (hdr) = ((hdr) & 0xffffff00) + (((val) - 4) & 0xff)
diff --git a/c_gen/templates/loci_dump.h b/c_gen/templates/loci_dump.h
index c2fd53a..d44832a 100644
--- a/c_gen/templates/loci_dump.h
+++ b/c_gen/templates/loci_dump.h
@@ -94,6 +94,8 @@
 int loci_dump_match(loci_writer_f writer, void* cookie, of_match_t *match);
 #define LOCI_DUMP_match(writer, cookie, val) loci_dump_match(writer, cookie, &val)
 
+#define LOCI_DUMP_bitmap_128(writer, cookie, val) writer(cookie, "%" PRIx64 "%" PRIx64, (val).hi, (val).lo)
+
 /**
  * Generic version for any object
  */
diff --git a/c_gen/templates/loci_show.h b/c_gen/templates/loci_show.h
index 948ee92..d2ba8f4 100644
--- a/c_gen/templates/loci_show.h
+++ b/c_gen/templates/loci_show.h
@@ -162,6 +162,8 @@
 int loci_show_match(loci_writer_f writer, void *cookie, of_match_t *match);
 #define LOCI_SHOW_match(writer, cookie, val) loci_show_match(writer, cookie, &val)
 
+#define LOCI_SHOW_bitmap_128(writer, cookie, val) writer(cookie, "%" PRIx64 "%" PRIx64, (val).hi, (val).lo)
+
 /**
  * Generic version for any object
  */
@@ -337,6 +339,9 @@
 #define LOCI_SHOW_ipv4_value_mask(writer, cookie, val) LOCI_SHOW_ipv4(writer, cookie, val)
 #define LOCI_SHOW_u8_hybrid_enable(writer, cookie, val) LOCI_SHOW_u8(writer, cookie, val)
 #define LOCI_SHOW_u16_hybrid_version(writer, cookie, val) LOCI_SHOW_u16(writer, cookie, val)
+#define LOCI_SHOW_bitmap_128_value(writer, cookie, val) LOCI_SHOW_bitmap_128(writer, cookie, val)
+#define LOCI_SHOW_bitmap_128_value_mask(writer, cookie, val) LOCI_SHOW_bitmap_128(writer, cookie, val)
+#define LOCI_SHOW_bitmap_128_bsn_in_ports_128(writer, cookie, val) LOCI_SHOW_bitmap_128(writer, cookie, val)
 
 
 #endif /* _LOCI_SHOW_H_ */
diff --git a/c_gen/templates/of_type_maps.c b/c_gen/templates/of_type_maps.c
index 2c1032d..67c3535 100644
--- a/c_gen/templates/of_type_maps.c
+++ b/c_gen/templates/of_type_maps.c
@@ -559,12 +559,10 @@
 of_oxm_wire_object_id_get(of_object_t *obj, of_object_id_t *id)
 {
     uint32_t type_len;
-    int wire_type;
     of_wire_buffer_t *wbuf;
 
     _GET_OXM_TYPE_LEN(obj, &type_len, wbuf);
-    wire_type = OF_OXM_MASKED_TYPE_GET(type_len);
-    *id = of_oxm_to_object_id(wire_type, obj->version);
+    *id = of_oxm_to_object_id(type_len, obj->version);
 }
 
 /**
@@ -584,9 +582,21 @@
 
     /* Read-modify-write */
     _GET_OXM_TYPE_LEN(obj, &type_len, wbuf);
-    wire_type = of_object_to_wire_type(id, obj->version);
-    ASSERT(wire_type >= 0);
-    OF_OXM_MASKED_TYPE_SET(type_len, wire_type);
+
+    switch (id) {
+    case OF_OXM_BSN_IN_PORTS_128:
+        type_len = 0x00030000 | (type_len & 0xff);
+        break;
+    case OF_OXM_BSN_IN_PORTS_128_MASKED:
+        type_len = 0x00030100 | (type_len & 0xff);
+        break;
+    default:
+        wire_type = of_object_to_wire_type(id, obj->version);
+        ASSERT(wire_type >= 0);
+        type_len = 0x80000000 | (wire_type << 8) | (type_len & 0xff);
+        break;
+    }
+
     of_wire_buffer_u32_set(wbuf, 
            OF_OBJECT_ABSOLUTE_OFFSET(obj, OXM_HDR_OFFSET), type_len);
 }
diff --git a/c_gen/templates/of_wire_buf.h b/c_gen/templates/of_wire_buf.h
index 8750565..117332c 100644
--- a/c_gen/templates/of_wire_buf.h
+++ b/c_gen/templates/of_wire_buf.h
@@ -876,6 +876,30 @@
 #define of_wire_buffer_ipv6_set(buf, offset, addr) \
     _wbuf_octets_set(buf, offset, (uint8_t *)&addr, sizeof(of_ipv6_t))
 
+/**
+ * Get an bitmap_128 address from a wire buffer
+ * @param wbuf The pointer to the wire buffer structure
+ * @param offset Offset in the wire buffer
+ * @param addr Pointer to where to store the bitmap_128 address
+ *
+ * Uses the octets function.
+ */
+
+#define of_wire_buffer_bitmap_128_get(buf, offset, addr) \
+    (of_wire_buffer_u64_get(buf, offset, &addr->hi), of_wire_buffer_u64_get(buf, offset+8, &addr->lo))
+
+/**
+ * Set an bitmap_128 address in a wire buffer
+ * @param wbuf The pointer to the wire buffer structure
+ * @param offset Offset in the wire buffer
+ * @param addr The variable holding bitmap_128 address to store
+ *
+ * Uses the octets function.
+ */
+
+#define of_wire_buffer_bitmap_128_set(buf, offset, addr) \
+    (of_wire_buffer_u64_set(buf, offset, addr.hi), of_wire_buffer_u64_set(buf, offset+8, addr.lo))
+
 /* Relocate data from start offset to the end of the buffer to a new position */
 static inline void
 of_wire_buffer_move_end(of_wire_buffer_t *wbuf, int start_offset, int new_offset)
diff --git a/java_gen/java_model.py b/java_gen/java_model.py
index 7334a1f..81ce8fe 100644
--- a/java_gen/java_model.py
+++ b/java_gen/java_model.py
@@ -229,7 +229,9 @@
                 "OFOxmMplsLabel":           OxmMapEntry("U32", "MPLS_LABEL", False),
                 "OFOxmMplsLabelMasked":     OxmMapEntry("U32", "MPLS_LABEL", True),
                 "OFOxmMplsTc":              OxmMapEntry("U8", "MPLS_TC", False),
-                "OFOxmMplsTcMasked":        OxmMapEntry("U8", "MPLS_TC", True)
+                "OFOxmMplsTcMasked":        OxmMapEntry("U8", "MPLS_TC", True),
+                "OFOxmBsnInPorts128":       OxmMapEntry("OFBitMask128", "BSN_IN_PORTS_128", False),
+                "OFOxmBsnInPorts128Masked": OxmMapEntry("OFBitMask128", "BSN_IN_PORTS_128", True)
                 }
 
     # Registry of nullable properties:
@@ -399,6 +401,13 @@
                         factory.members.append(i)
                         break
         return factories.values()
+    
+    @memoize
+    def factory_of(self, interface):
+        for factory in self.of_factories:
+            if interface in factory.members:
+                return factory
+        return None
 
     def generate_class(self, clazz):
         """ return wether or not to generate implementation class clazz.
@@ -441,6 +450,12 @@
             return "build" + n[0].upper() + n[1:]
         else:
             return n
+    
+    def of_version(self, version):
+        for fc in self.factory_classes:
+            if fc.version == version:
+                return fc
+        return None
 
 OFGenericClass = namedtuple("OFGenericClass", ("package", "name"))
 class OFFactoryClass(namedtuple("OFFactoryClass", ("package", "name", "interface", "version"))):
@@ -1119,7 +1134,11 @@
     @property
     def name(self):
         return self.test_class_name
-
+    
+    @property
+    def interface(self):
+        return self.java_class.interface
+    
     @property
     def has_test_data(self):
         return test_data.exists(self.data_file_name)
diff --git a/java_gen/java_type.py b/java_gen/java_type.py
index 084fc6f..698d869 100644
--- a/java_gen/java_type.py
+++ b/java_gen/java_type.py
@@ -385,6 +385,10 @@
 table_stats_wildcards = JType("int") \
         .op(read='bb.readInt()',
             write='bb.writeInt($name)')
+port_bitmap = JType('OFBitMask128') \
+            .op(read='OFBitMask128.read16Bytes(bb)',
+                write='$name.write16Bytes(bb)',
+                default='OFBitMask128.NONE')
 table_id = JType("TableId") \
         .op(read='TableId.readByte(bb)',
             write='$name.writeByte(bb)',
@@ -427,6 +431,7 @@
         'of_wc_bmap_t': flow_wildcards,
         'of_oxm_t': oxm,
         'of_meter_features_t': meter_features,
+        'of_bitmap_128_t': port_bitmap
         }
 
 ## Map that defines exceptions from the standard loxi->java mapping scheme
@@ -480,6 +485,9 @@
         '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 },
 
         'of_table_stats_entry': { 'wildcards': table_stats_wildcards },
         'of_match_v1': { 'vlan_vid' : vlan_vid, 'vlan_pcp': vlan_pcp,
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/match/MatchField.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/match/MatchField.java
index 47ca9da..5df7012 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/match/MatchField.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/match/MatchField.java
@@ -13,6 +13,7 @@
 import org.projectfloodlight.openflow.types.MacAddress;
 import org.projectfloodlight.openflow.types.OFMetadata;
 import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.OFBitMask128;
 import org.projectfloodlight.openflow.types.OFValueType;
 import org.projectfloodlight.openflow.types.TransportPort;
 import org.projectfloodlight.openflow.types.U32;
@@ -170,6 +171,9 @@
             new MatchField<U8>("mpls_tc", MatchFields.MPLS_TC,
                     new Prerequisite<EthType>(MatchField.ETH_TYPE, EthType.MPLS_UNICAST, EthType.MPLS_MULTICAST));
 
+    public final static MatchField<OFBitMask128> BSN_IN_PORTS_128 =
+            new MatchField<OFBitMask128>("bsn_in_port_masked_128", MatchFields.BSN_IN_PORTS_128);
+
     public String getName() {
         return name;
     }
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/match/MatchFields.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/match/MatchFields.java
index 7deb9af..0de5caf 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/match/MatchFields.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/match/MatchFields.java
@@ -37,5 +37,6 @@
     IPV6_ND_SLL,
     IPV6_ND_TLL,
     MPLS_LABEL,
-    MPLS_TC
+    MPLS_TC,
+    BSN_IN_PORTS_128
 }
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
new file mode 100644
index 0000000..2827a72
--- /dev/null
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFBitMask128.java
@@ -0,0 +1,92 @@
+package org.projectfloodlight.openflow.types;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+public class OFBitMask128 implements OFValueType<OFBitMask128> {
+
+    static final int LENGTH = 16;
+
+    private final long raw1; // MSBs (ports 64-127)
+    private final long raw2; // LSBs (ports 0-63)
+
+    public static final OFBitMask128 ALL = new OFBitMask128(-1, -1);
+    public static final OFBitMask128 NONE = new OFBitMask128(0, 0);
+
+    private OFBitMask128(long raw1, long raw2) {
+        this.raw1 = raw1;
+        this.raw2 = raw2;
+    }
+
+    static OFBitMask128 of(long raw1, long raw2) {
+        if (raw1 == -1 && raw2 == -1)
+            return ALL;
+        if (raw1 == 0 && raw2 == 0)
+            return NONE;
+        return new OFBitMask128(raw1, raw2);
+    }
+
+    @Override
+    public int getLength() {
+        return LENGTH;
+    }
+
+    @Override
+    public OFBitMask128 applyMask(OFBitMask128 mask) {
+        return of(this.raw1 & mask.raw1, this.raw2 & mask.raw2);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof OFBitMask128))
+            return false;
+        OFBitMask128 other = (OFBitMask128)obj;
+        return (other.raw1 == this.raw1 && other.raw2 == this.raw2);
+    }
+
+    @Override
+    public int hashCode() {
+        return (int)(31 * raw1 + raw2);
+    }
+
+    protected static boolean isBitOn(long raw1, long raw2, int bit) {
+        if (bit < 0 || bit >= 128)
+            throw new IndexOutOfBoundsException();
+        long word;
+        if (bit < 64) {
+            word = raw2; // ports 0-63
+        } else {
+            word = raw1; // ports 64-127
+            bit -= 64;
+        }
+        return (word & ((long)1 << bit)) != 0;
+    }
+
+    public void write16Bytes(ChannelBuffer cb) {
+        cb.writeLong(raw1);
+        cb.writeLong(raw2);
+    }
+
+    public static OFBitMask128 read16Bytes(ChannelBuffer cb) {
+        long raw1 = cb.readLong();
+        long raw2 = cb.readLong();
+        return of(raw1, raw2);
+    }
+
+    public boolean isOn(int bit) {
+        return isBitOn(raw1, raw2, bit);
+    }
+
+    @Override
+    public String toString() {
+        return (String.format("%64s", Long.toBinaryString(raw2)) + String.format("%64s", Long.toBinaryString(raw1))).replaceAll(" ", "0");
+    }
+
+    @Override
+    public int compareTo(OFBitMask128 o) {
+        long c = this.raw1 - o.raw1;
+        if (c != 0)
+            return Long.signum(c);
+        return Long.signum(this.raw2 - o.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
new file mode 100644
index 0000000..8ec056e
--- /dev/null
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/OFPortMap.java
@@ -0,0 +1,75 @@
+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/test/java/org/projectfloodlight/openflow/types/OFPortMapTest.java b/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/OFPortMapTest.java
new file mode 100644
index 0000000..7a75248
--- /dev/null
+++ b/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/types/OFPortMapTest.java
@@ -0,0 +1,54 @@
+package org.projectfloodlight.openflow.types;
+
+import static org.junit.Assert.assertArrayEquals;
+import junit.framework.TestCase;
+
+import org.junit.Test;
+
+public class OFPortMapTest extends TestCase {
+
+    @Test
+    public void testOFPortMap() {
+        Boolean[] on = new Boolean[128];
+        for (int i = 0; i < 128; i++) {
+            on[i] = false;
+        }
+
+        OFPortMap.Builder builder = new OFPortMap.Builder();
+
+        for (int i = 0; i < 128; 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();
+        //System.out.println(portmap);
+        Boolean[] actual = new Boolean[128];
+        for (int i = 0; i < 128; i++) {
+            actual[i] = false;
+        }
+        for (int i = 0; i < 128; i++) {
+            actual[i] = portmap.isOn(OFPort.of(i));
+        }
+        assertArrayEquals(on, actual);
+
+        // Turn some ports off
+        for (int i = 0; i < 128; 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[i] = false;
+        }
+        for (int i = 0; i < 128; i++) {
+            actual[i] = portmap.isOn(OFPort.of(i));
+        }
+        assertArrayEquals(on, actual);
+    }
+}
diff --git a/java_gen/templates/unit_test.java b/java_gen/templates/unit_test.java
index 47dcc24..5a525e4 100644
--- a/java_gen/templates/unit_test.java
+++ b/java_gen/templates/unit_test.java
@@ -28,6 +28,7 @@
 //:: from loxi_ir import *
 //:: import itertools
 //:: import of_g
+//:: import java_gen.java_model as java_model
 //:: include('_copyright.java')
 
 //:: include('_autogen.java')
@@ -40,22 +41,25 @@
 import static org.junit.Assert.*;
 
 public class ${test.name} {
+    //:: factory = java_model.model.factory_of(test.interface)
     //:: var_type = msg.interface.name
     //:: var_name = msg.interface.variable_name
-    OFFactory factory;
+    //:: builder_method = factory.method_name(msg.interface)
+    //:: factory_impl = java_model.model.factory_of(test.interface).of_version(test.java_class.version).name
+    ${factory.name if factory.name is not None else "OFFactory"} factory;
 
     final static byte[] ${msg.constant_name}_SERIALIZED =
         new byte[] { ${", ".join("%s0x%x" % (("" if ord(c)<128 else "(byte) "),  ord(c)) for c in test_data["binary"] ) } };
 
     @Before
     public void setup() {
-        factory = OFFactories.getFactory(OFVersion.${version.constant_version});
+        factory = ${factory_impl + ".INSTANCE" if factory_impl is not None else "OFFactories.getFactory(OFVersion." + version.constant_version + ")"};
     }
 
     //:: if "java" in test_data:
     @Test
     public void testWrite() {
-        ${var_type}.Builder builder = factory.build${var_type[2:]}();
+        ${var_type}.Builder builder = factory.${builder_method}();
         ${test_data["java"]};
         ${var_type} ${var_name} = builder.build();
         ChannelBuffer bb = ChannelBuffers.dynamicBuffer();
@@ -68,7 +72,7 @@
 
     @Test
     public void testRead() throws Exception {
-        ${var_type}.Builder builder = factory.build${var_type[2:]}();
+        ${var_type}.Builder builder = factory.${builder_method}();
         ${test_data["java"]};
         ${var_type} ${var_name}Built = builder.build();
 
diff --git a/loxi_front_end/match.py b/loxi_front_end/match.py
index 20d5030..c510477 100644
--- a/loxi_front_end/match.py
+++ b/loxi_front_end/match.py
@@ -394,6 +394,16 @@
         takes_mask_in_spec=False,
         order=501,
         ),
+
+    bsn_in_ports_128 = dict(
+        name="bsn_in_ports_128",
+        m_type="of_bitmap_128_t",
+        v2_wc_shift=9,
+        print_type="p",
+        conditions="",
+        takes_mask_in_spec=True,
+        order=1000,
+        ),
 )
 
 match_keys_sorted = of_match_members.keys()
diff --git a/of_g.py b/of_g.py
index 651ee64..c857e65 100644
--- a/of_g.py
+++ b/of_g.py
@@ -302,14 +302,15 @@
 #    of_match_v4_t = dict(bytes=-1, to_w="match_v4_hton",
 #                         from_w="match_v4_ntoh",
 #                         short_name="match_v4"),
-    of_octets_t = dict(bytes=-1, short_name="octets")
+    of_octets_t = dict(bytes=-1, short_name="octets"),
+    of_bitmap_128_t = dict(bytes=16, short_name="bitmap_128"),
 )
 
 of_scalar_types = ["char", "uint8_t", "uint16_t", "uint32_t", "uint64_t",
                    "of_port_no_t", "of_fm_cmd_t", "of_wc_bmap_t",
                    "of_match_bmap_t", "of_port_name_t", "of_table_name_t",
                    "of_desc_str_t", "of_serial_num_t", "of_mac_addr_t",
-                   "of_ipv6_t", "of_ipv4_t"]
+                   "of_ipv6_t", "of_ipv4_t", "of_bitmap_128_t"]
 
 base_object_members = """\
     /* The control block for the underlying data buffer */
diff --git a/openflow_input/bsn_in_ports b/openflow_input/bsn_in_ports
new file mode 100644
index 0000000..05003b9
--- /dev/null
+++ b/openflow_input/bsn_in_ports
@@ -0,0 +1,61 @@
+// 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 3
+#version 4
+
+/*
+ * Bitmap of input ports
+ *
+ * The representation is not straightforward, but it works with existing OXM
+ * semantics.
+ *
+ * The value should always be zero. The mask should be unset in every bit position
+ * where the corresponding input port is allowed, and set in all other bits.
+ * As a special case, the highest bit in the mask is reserved for higher port
+ * numbers than can be represented in the bitmap.
+ *
+ * The value1 and value_mask1 fields contain the most significant bits. value2
+ * and value_mask2 contain the least significant bits.
+ *
+ * Pseudocode for populating value or mask:
+ *   bitmap |= in_port < 128 ? (1 << in_port) : (1 << 127)
+ */
+
+struct of_oxm_bsn_in_ports_128 : of_oxm {
+    uint32_t type_len == 0x00030020;
+    of_bitmap_128_t value;
+};
+
+struct of_oxm_bsn_in_ports_128_masked : of_oxm {
+    uint32_t type_len == 0x00030120;
+    of_bitmap_128_t value;
+    of_bitmap_128_t value_mask;
+};
diff --git a/py_gen/oftype.py b/py_gen/oftype.py
index a6620ab..c378cea 100644
--- a/py_gen/oftype.py
+++ b/py_gen/oftype.py
@@ -101,6 +101,11 @@
         pack='%s',
         unpack='str(%s.read_all())'),
 
+    'of_bitmap_128_t': OFTypeData(
+        init='set()',
+        pack='util.pack_bitmap_128(%s)',
+        unpack="util.unpack_bitmap_128(%s)"),
+
     # HACK need the match_v3 length field
     'list(of_oxm_t)': OFTypeData(
         init='[]',
diff --git a/py_gen/templates/util.py b/py_gen/templates/util.py
index c4de5a3..1566e82 100644
--- a/py_gen/templates/util.py
+++ b/py_gen/templates/util.py
@@ -142,3 +142,23 @@
 
 def pack_list(values):
     return "".join([x.pack() for x in values])
+
+MASK64 = (1 << 64) - 1
+
+def pack_bitmap_128(value):
+    x = 0l
+    for y in value:
+        x |= 1 << y
+    return struct.pack("!QQ", (x >> 64) & MASK64, x & MASK64)
+
+def unpack_bitmap_128(reader):
+    hi, lo = reader.read("!QQ")
+    x = (hi << 64) | lo
+    i = 0
+    value = set()
+    while x != 0:
+        if x & 1 == 1:
+            value.add(i)
+        i += 1
+        x >>= 1
+    return value
diff --git a/test_data/of13/oxm_bsn_in_ports_masked_128.data b/test_data/of13/oxm_bsn_in_ports_masked_128.data
new file mode 100644
index 0000000..9ef5245
--- /dev/null
+++ b/test_data/of13/oxm_bsn_in_ports_masked_128.data
@@ -0,0 +1,24 @@
+-- binary
+00 03 # class
+01 # type/masked
+20 # length
+00 00 00 00 00 00 00 00 # value
+00 00 00 00 00 00 00 00 # ...
+ff ff ff fe ff ff ff ff # mask - Only ports 0, 17, 96 are selected (and thus are zero)
+ff ff ff ff ff fd ff fe # ...
+-- python
+ofp.oxm.bsn_in_ports_128_masked(set(), set(range(0,128)) - set((0, 17,96)))
+-- c
+obj = of_oxm_bsn_in_ports_128_masked_new(OF_VERSION_1_3);
+{
+    of_bitmap_128_t bmap = { 0, 0 };
+    of_oxm_bsn_in_ports_128_masked_value_set(obj, bmap);
+}
+{
+    of_bitmap_128_t bmap = { 0xfffffffeffffffff , 0xfffffffffffdfffe };
+    of_oxm_bsn_in_ports_128_masked_value_mask_set(obj, bmap);
+}
+-- java
+OFPortMap portmap = OFPortMap.ofPorts(OFPort.of(0), OFPort.of(17), OFPort.of(96));
+builder.setValue(portmap.getValue());
+builder.setMask(portmap.getMask());