Merge pull request #357 from rlane/in_ports_512

bsn_in_ports_512 OXM
diff --git a/c_gen/c_code_gen.py b/c_gen/c_code_gen.py
index 968d939..a9a0576 100644
--- a/c_gen/c_code_gen.py
+++ b/c_gen/c_code_gen.py
@@ -616,19 +616,26 @@
    uint8_t addr[OF_IPV6_BYTES];
 } of_ipv6_t;
 
+typedef struct of_bitmap_512_s {
+    uint64_t words[8];
+} of_bitmap_512_t;
+
 extern const of_mac_addr_t of_mac_addr_all_ones;
-extern const of_mac_addr_t of_mac_addr_all_zeros;
+extern const of_mac_addr_t of_mac_addr_all_zeroes;
 
 extern const of_ipv6_t of_ipv6_all_ones;
 extern const of_ipv6_t of_ipv6_all_zeros;
 
+extern const of_bitmap_512_t of_bitmap_512_all_ones;
+extern const of_bitmap_512_t of_bitmap_512_all_zeroes;
+
 /**
  * Generic zero and all-ones values of size 16 bytes.
  *
- * IPv6 is longest data type we worry about for comparisons
+ * bitmap_512 is longest data type we worry about for comparisons
  */
-#define of_all_zero_value of_ipv6_all_zeros
-#define of_all_ones_value of_ipv6_all_ones
+#define of_all_zero_value of_bitmap_512_all_zeroes
+#define of_all_ones_value of_bitmap_512_all_ones
 
 /**
  * Non-zero/all ones check for arbitrary type of size <= 16 bytes
diff --git a/c_gen/c_match.py b/c_gen/c_match.py
index a703e4f..ccc503d 100644
--- a/c_gen/c_match.py
+++ b/c_gen/c_match.py
@@ -963,55 +963,31 @@
  */
 
 static inline int
-of_match_more_specific(of_match_t *entry, of_match_t *query)
+of_match_more_specific(const of_match_t *entry, const of_match_t *query)
 {
-    of_match_fields_t *q_m, *e_m;  /* Short hand for masks, fields */
-    of_match_fields_t *q_f, *e_f;
+    LOCI_ASSERT(sizeof(of_match_fields_t) % sizeof(uint8_t) == 0);
 
-    q_m = &query->masks;
-    e_m = &entry->masks;
-    q_f = &query->fields;
-    e_f = &entry->fields;
-""")
-    for key, entry in match.of_match_members.items():
-        q_m = "&q_m->%s" % key
-        e_m = "&e_m->%s" % key
-        q_f = "&q_f->%s" % key
-        e_f = "&e_f->%s" % key
-        if entry["m_type"] == "of_ipv6_t":
-            comp = "OF_MORE_SPECIFIC_IPV6"
-            match_type = "OF_RESTRICTED_MATCH_IPV6"
-        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"
-            q_m = "q_m->%s" % key
-            e_m = "e_m->%s" % key
-            q_f = "q_f->%s" % key
-            e_f = "e_f->%s" % key
-        out.write("""
-    /* Mask and values for %(key)s */
-    if (!%(comp)s(%(e_m)s, %(q_m)s)) {
-        return 0;
-    }
-    if (!%(match_type)s(%(e_f)s, %(q_f)s,
-            %(q_m)s)) {
-        return 0;
-    }
-""" % dict(match_type=match_type, comp=comp, q_f=q_f, e_f=e_f,
-           q_m=q_m, e_m=e_m, key=key))
+    /* Short hand for masks, fields */
+    const uint8_t *qm = (const uint8_t *)&query->masks;
+    const uint8_t *em = (const uint8_t *)&entry->masks;
+    const uint8_t *qf = (const uint8_t *)&query->fields;
+    const uint8_t *ef = (const uint8_t *)&entry->fields;
 
-    out.write("""
+    int i;
+    for (i = 0; i < sizeof(of_match_fields_t)/sizeof(uint8_t); i++) {
+        if (qm[i] & ~em[i]) {
+            /* Query mask has a bit set that isn't set in the entry mask */
+            return 0;
+        }
+
+        if ((qf[i] ^ ef[i]) & qm[i]) {
+            /* Query and entry disagree on a field bit */
+            return 0;
+        }
+    }
+
     return 1;
 }
-""")
-
-    out.write("""
 
 /**
  * Do two entries overlap?
@@ -1022,42 +998,24 @@
  */
 
 static inline int
-of_match_overlap(of_match_t *match1, of_match_t *match2)
+of_match_overlap(const of_match_t *match1, const of_match_t *match2)
 {
-    of_match_fields_t *m1, *m2;  /* Short hand for masks, fields */
-    of_match_fields_t *f1, *f2;
+    LOCI_ASSERT(sizeof(of_match_fields_t) % sizeof(uint8_t) == 0);
 
-    m1 = &match1->masks;
-    m2 = &match2->masks;
-    f1 = &match1->fields;
-    f2 = &match2->fields;
-""")
-    for key, entry in match.of_match_members.items():
-        m1 = "&m1->%s" % key
-        m2 = "&m2->%s" % key
-        f1 = "&f1->%s" % key
-        f2 = "&f2->%s" % key
-        if entry["m_type"] == "of_ipv6_t":
-            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
-            m2 = "m2->%s" % key
-            f1 = "f1->%s" % key
-            f2 = "f2->%s" % key
-        out.write("""
-    /* Check overlap for %(key)s */
-    if (!%(check)s(%(f1)s, %(f2)s,
-        %(m2)s, %(m1)s)) {
-        return 0; /* This field differentiates; all done */
+    /* Short hand for masks, fields */
+    const uint8_t *m1 = (const uint8_t *)&match1->masks;
+    const uint8_t *m2 = (const uint8_t *)&match2->masks;
+    const uint8_t *f1 = (const uint8_t *)&match1->fields;
+    const uint8_t *f2 = (const uint8_t *)&match2->fields;
+
+    int i;
+    for (i = 0; i < sizeof(of_match_fields_t)/sizeof(uint8_t); i++) {
+        if ((f1[i] ^ f2[i]) & (m1[i] & m2[i])) {
+            /* Matches disagree on a field bit they both qualify on */
+            return 0;
+        }
     }
-""" % dict(check=check, f1=f1, f2=f2, m1=m1, m2=m2, key=key))
 
-    out.write("""
     return 1; /* No field differentiates matches */
 }
 """)
diff --git a/c_gen/c_test_gen.py b/c_gen/c_test_gen.py
index 109ab9b..6e88d6d 100644
--- a/c_gen/c_test_gen.py
+++ b/c_gen/c_test_gen.py
@@ -105,6 +105,7 @@
         # BSN extensions
         of_bsn_vport_q_in_q_t="vport",
         of_bitmap_128_t="bitmap_128",
+        of_bitmap_512_t="bitmap_512",
         of_checksum_128_t="checksum_128",
         )
 
@@ -120,7 +121,7 @@
 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_bitmap_128_t", "of_checksum_128_t",
-                "of_str64_t"]
+                "of_str64_t", "of_bitmap_512_t"]
 
 scalar_types = integer_types[:]
 scalar_types.extend(string_types)
diff --git a/c_gen/of_g_legacy.py b/c_gen/of_g_legacy.py
index 87e0680..9c0722c 100644
--- a/c_gen/of_g_legacy.py
+++ b/c_gen/of_g_legacy.py
@@ -213,6 +213,7 @@
 #                         short_name="match_v4"),
     of_octets_t = dict(bytes=-1, short_name="octets"),
     of_bitmap_128_t = dict(bytes=16, short_name="bitmap_128"),
+    of_bitmap_512_t = dict(bytes=64, short_name="bitmap_512"),
     of_checksum_128_t = dict(bytes=16, short_name="checksum_128"),
 )
 
@@ -221,7 +222,7 @@
                    "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_bitmap_128_t", "of_checksum_128_t",
-                   "of_str64_t"]
+                   "of_str64_t", "of_bitmap_512_t"]
 
 ##
 # LOXI identifiers
diff --git a/c_gen/templates/loci_dump.h b/c_gen/templates/loci_dump.h
index 1344565..89c5f2a 100644
--- a/c_gen/templates/loci_dump.h
+++ b/c_gen/templates/loci_dump.h
@@ -99,6 +99,8 @@
 
 #define LOCI_DUMP_checksum_128(writer, cookie, val) writer(cookie, "%016" PRIx64 "%016" PRIx64, (val).hi, (val).lo)
 
+#define LOCI_DUMP_bitmap_512(writer, cookie, val) writer(cookie, "%" PRIx64 "%" PRIx64 "%" PRIx64 "%" PRIx64 "%" PRIx64 "%" PRIx64 "%" PRIx64 "%" PRIx64, (val).words[7], (val).words[6], (val).words[5], (val).words[4], (val).words[3], (val).words[2], (val).words[1], (val).words[0])
+
 /**
  * Generic version for any object
  */
diff --git a/c_gen/templates/loci_show.h b/c_gen/templates/loci_show.h
index a227645..dc35959 100644
--- a/c_gen/templates/loci_show.h
+++ b/c_gen/templates/loci_show.h
@@ -113,6 +113,8 @@
 
 #define LOCI_SHOW_checksum_128(writer, cookie, val) writer(cookie, "%016" PRIx64 "%016" PRIx64, (val).hi, (val).lo)
 
+#define LOCI_SHOW_bitmap_512(writer, cookie, val) writer(cookie, "%" PRIx64 "%" PRIx64 "%" PRIx64 "%" PRIx64 "%" PRIx64 "%" PRIx64 "%" PRIx64 "%" PRIx64, (val).words[7], (val).words[6], (val).words[5], (val).words[4], (val).words[3], (val).words[2], (val).words[1], (val).words[0])
+
 /**
  * Generic version for any object
  */
diff --git a/c_gen/templates/loci_strings.c b/c_gen/templates/loci_strings.c
index f546e12..165bf56 100644
--- a/c_gen/templates/loci_strings.c
+++ b/c_gen/templates/loci_strings.c
@@ -69,6 +69,12 @@
     }
 };
 
+const of_bitmap_512_t of_bitmap_512_all_ones = {
+    { -1, -1, -1, -1, -1, -1, -1, -1, }
+};
+
+const of_bitmap_512_t of_bitmap_512_all_zeroes;
+
 /** @var of_error_strings
  * The error string map; use abs value to index
  */
diff --git a/c_gen/templates/of_wire_buf.h b/c_gen/templates/of_wire_buf.h
index 3d38f53..9ade2c4 100644
--- a/c_gen/templates/of_wire_buf.h
+++ b/c_gen/templates/of_wire_buf.h
@@ -888,6 +888,45 @@
 #define of_wire_buffer_checksum_128_set(buf, offset, checksum) \
     (of_wire_buffer_u64_set(buf, offset, checksum.hi), of_wire_buffer_u64_set(buf, offset+8, checksum.lo))
 
+
+/**
+ * Get a bitmap_512 from a wire buffer
+ * @param wbuf The pointer to the wire buffer structure
+ * @param offset Offset in the wire buffer
+ * @param value Pointer to where to put value
+ *
+ * The underlying buffer accessor funtions handle endian and alignment.
+ */
+
+static inline void
+of_wire_buffer_bitmap_512_get(of_wire_buffer_t *wbuf, int offset, of_bitmap_512_t *value)
+{
+    OF_WIRE_BUFFER_ACCESS_CHECK(wbuf, offset + (int) sizeof(of_bitmap_512_t));
+    int i;
+    for (i = 0; i < 8; i++) {
+        buf_u64_get(OF_WIRE_BUFFER_INDEX(wbuf, offset+i*8), &value->words[i]);
+    }
+}
+
+/**
+ * Set a bitmap_512 in a wire buffer
+ * @param wbuf The pointer to the wire buffer structure
+ * @param offset Offset in the wire buffer
+ * @param value The value to store
+ *
+ * The underlying buffer accessor funtions handle endian and alignment.
+ */
+
+static inline void
+of_wire_buffer_bitmap_512_set(of_wire_buffer_t *wbuf, int offset, of_bitmap_512_t value)
+{
+    OF_WIRE_BUFFER_ACCESS_CHECK(wbuf, offset + (int) sizeof(of_bitmap_512_t));
+    int i;
+    for (i = 0; i < 8; i++) {
+        buf_u64_set(OF_WIRE_BUFFER_INDEX(wbuf, offset+i*8), value.words[i]);
+    }
+}
+
 /* 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/loxi_ir/ir_offset.py b/loxi_ir/ir_offset.py
index db55f24..5eff8e0 100644
--- a/loxi_ir/ir_offset.py
+++ b/loxi_ir/ir_offset.py
@@ -109,6 +109,7 @@
     of_octets_t = (0, False),
     of_bitmap_128_t = (16, True),
     of_checksum_128_t = (16, True),
+    of_bitmap_512_t = (64, True),
 )
 
 def type_dec_to_count_base(m_type):
diff --git a/openflow_input/bsn_in_ports b/openflow_input/bsn_in_ports
index 819bdde..bb4c030 100644
--- a/openflow_input/bsn_in_ports
+++ b/openflow_input/bsn_in_ports
@@ -60,3 +60,14 @@
     of_bitmap_128_t value;
     of_bitmap_128_t value_mask;
 };
+
+struct of_oxm_bsn_in_ports_512 : of_oxm {
+    uint32_t type_len == 0x00032640;
+    of_bitmap_512_t value;
+};
+
+struct of_oxm_bsn_in_ports_512_masked : of_oxm {
+    uint32_t type_len == 0x00032780;
+    of_bitmap_512_t value;
+    of_bitmap_512_t value_mask;
+};
diff --git a/py_gen/oftype.py b/py_gen/oftype.py
index 51b8e13..3893865 100644
--- a/py_gen/oftype.py
+++ b/py_gen/oftype.py
@@ -116,6 +116,11 @@
         init='0',
         pack='util.pack_checksum_128(%s)',
         unpack="util.unpack_checksum_128(%s)"),
+
+    'of_bitmap_512_t': OFTypeData(
+        init='set()',
+        pack='util.pack_bitmap_512(%s)',
+        unpack="util.unpack_bitmap_512(%s)"),
 }
 
 ## Fixed length strings
diff --git a/py_gen/templates/util.py b/py_gen/templates/util.py
index 85181dc..7558576 100644
--- a/py_gen/templates/util.py
+++ b/py_gen/templates/util.py
@@ -173,6 +173,28 @@
         x >>= 1
     return value
 
+def pack_bitmap_512(value):
+    words = [0] * 8
+    for v in value:
+        assert v < 512
+        words[7-v/64] |= 1 << (v % 64)
+    return struct.pack("!8Q", *words)
+
+def unpack_bitmap_512(reader):
+    words = reader.read("!8Q")
+    x = 0l
+    for word in words:
+        x <<= 64
+        x |= word
+    i = 0
+    value = set()
+    while x != 0:
+        if x & 1 == 1:
+            value.add(i)
+        i += 1
+        x >>= 1
+    return value
+
 def pack_checksum_128(value):
     return struct.pack("!QQ", (value >> 64) & MASK64, value & MASK64)
 
diff --git a/py_gen/tests/of13.py b/py_gen/tests/of13.py
index c5a16b2..c99ee34 100644
--- a/py_gen/tests/of13.py
+++ b/py_gen/tests/of13.py
@@ -126,5 +126,18 @@
             else:
                 fn()
 
+class TestUtils(unittest.TestCase):
+    def check_bitmap_512(self, value, data):
+        self.assertEquals(data, ofp.util.pack_bitmap_512(set(value)))
+        self.assertEquals(ofp.util.unpack_bitmap_512(OFReader(data)), set(value))
+
+    def test_bitmap_512(self):
+        self.check_bitmap_512([0], "\x00" * 63 + "\x01")
+        self.check_bitmap_512([8], "\x00" * 62 + "\x01\x00")
+        self.check_bitmap_512([63], "\x00" * 56 + "\x80" + "\x00" * 7)
+        self.check_bitmap_512([64], "\x00" * 55 + "\x01" + "\x00" * 8)
+        self.check_bitmap_512([511], "\x80" + "\x00" * 63)
+        self.check_bitmap_512([5, 67, 90], "\x00" * 52 + "\x04\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x20")
+
 if __name__ == '__main__':
     unittest.main()
diff --git a/test_data/of13/oxm_bsn_in_ports_masked_512.data b/test_data/of13/oxm_bsn_in_ports_masked_512.data
new file mode 100644
index 0000000..82cc45c
--- /dev/null
+++ b/test_data/of13/oxm_bsn_in_ports_masked_512.data
@@ -0,0 +1,36 @@
+-- binary
+00 03 # class
+27 # type/masked
+80 # length
+00 00 00 00 00 00 00 00 # value
+00 00 00 00 00 00 00 00 # ...
+00 00 00 00 00 00 00 00 # ...
+00 00 00 00 00 00 00 00 # ...
+00 00 00 00 00 00 00 00 # ...
+00 00 00 00 00 00 00 00 # ...
+00 00 00 00 00 00 00 00 # ...
+00 00 00 00 00 00 00 00 # ...
+7f ff ff ff ff ff ff ff # mask - Only ports 0, 17, 96, 511 are selected (and thus are zero)
+ff ff ff ff ff ff ff ff # ...
+ff ff ff ff ff ff ff ff # ...
+ff ff ff ff ff ff ff ff # ...
+ff ff ff ff ff ff ff ff # ...
+ff ff ff ff ff ff ff ff # ...
+ff ff ff fe ff ff ff ff # ...
+ff ff ff ff ff fd ff fe # ...
+-- python
+ofp.oxm.bsn_in_ports_512_masked(set(), set(range(0,512)) - set((0, 17, 96, 511)))
+-- c
+obj = of_oxm_bsn_in_ports_512_masked_new(OF_VERSION_1_3);
+{
+    of_bitmap_512_t bmap = { { 0, 0, 0, 0, 0, 0, 0, 0 } };
+    of_oxm_bsn_in_ports_512_masked_value_set(obj, bmap);
+}
+{
+    of_bitmap_512_t bmap = { { 0x7fffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xfffffffeffffffff, 0xfffffffffffdfffe } };
+    of_oxm_bsn_in_ports_512_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());
diff --git a/wireshark_gen/templates/_oftype_readers.lua b/wireshark_gen/templates/_oftype_readers.lua
index 48cb447..ad0f0c2 100644
--- a/wireshark_gen/templates/_oftype_readers.lua
+++ b/wireshark_gen/templates/_oftype_readers.lua
@@ -49,6 +49,10 @@
     read_scalar(reader, subtree, field_name, 16)
 end
 
+function read_of_bitmap_512_t(reader, version, subtree, field_name)
+    read_scalar(reader, subtree, field_name, 64)
+end
+
 function read_of_checksum_128_t(reader, version, subtree, field_name)
     read_scalar(reader, subtree, field_name, 16)
 end