Merge into master from pull request #183:
update pyloxi to floodlight/loxigen-artifacts @ 6fb4ac9fe79ec8730ae34928df12cdf671f3ba75 (https://github.com/floodlight/oftest/pull/183)
diff --git a/src/python/loxi/connection.py b/src/python/loxi/connection.py
new file mode 100644
index 0000000..af8bf84
--- /dev/null
+++ b/src/python/loxi/connection.py
@@ -0,0 +1,237 @@
+# Copyright 2015, Big Switch Networks, Inc.
+
+"""
+OpenFlow connection class
+
+This class creates a thread which continually parses OpenFlow messages off the
+supplied socket and places them in a queue. The class has methods for reading messages
+from the RX queue, sending messages, and higher level operations like request-response
+and multipart transactions.
+"""
+
+import loxi
+import loxi.of14
+import logging
+import time
+import socket
+import errno
+import os
+import select
+from threading import Condition, Lock, Thread
+
+DEFAULT_TIMEOUT = 1
+
+class TransactionError(Exception):
+    def __str__(self):
+        return self.args[0]
+
+    @property
+    def msg(self):
+        return self.args[1]
+
+class Connection(Thread):
+    def __init__(self, sock):
+        Thread.__init__(self)
+        self.sock = sock
+        self.logger = logging.getLogger("connection")
+        self.rx = []
+        self.rx_cv = Condition()
+        self.tx_lock = Lock()
+        self.next_xid = 1
+        self.wakeup_rd, self.wakeup_wr = os.pipe()
+        self.finished = False
+        self.read_buffer = None
+
+    def run(self):
+        while not self.finished:
+            rd, wr, err = select.select([self.sock, self.wakeup_rd], [], [])
+            if self.sock in rd:
+                self.process_read()
+            if self.wakeup_rd in rd:
+                os.read(self.wakeup_rd, 1)
+        self.logger.debug("Exited event loop")
+
+    def process_read(self):
+        recvd = self.sock.recv(4096)
+
+        self.logger.debug("Received %d bytes", len(recvd))
+
+        buf = self.read_buffer
+        if buf:
+            buf += recvd
+        else:
+            buf = recvd
+
+        offset = 0
+        while offset < len(buf):
+            if offset + 8 > len(buf):
+                # Not enough data for the OpenFlow header
+                break
+
+            # Parse the header to get type
+            hdr_version, hdr_type, hdr_msglen, hdr_xid = loxi.of14.message.parse_header(buf[offset:])
+
+            # Use loxi to resolve ofp of matching version
+            ofp = loxi.protocol(hdr_version)
+
+            # Extract the raw message bytes
+            if (offset + hdr_msglen) > len(buf):
+                # Not enough data for the body
+                break
+            rawmsg = buf[offset : offset + hdr_msglen]
+            offset += hdr_msglen
+
+            msg = ofp.message.parse_message(rawmsg)
+            if not msg:
+                self.logger.warn("Could not parse message")
+                continue
+
+            self.logger.debug("Received message %s.%s xid %d length %d",
+                              type(msg).__module__, type(msg).__name__, hdr_xid, hdr_msglen)
+
+            with self.rx_cv:
+                self.rx.append(msg)
+                self.rx_cv.notify_all()
+
+        if offset == len(buf):
+            self.read_buffer = None
+        else:
+            self.read_buffer = buf[offset:]
+            self.logger.debug("%d bytes remaining", len(self.read_buffer))
+
+    def recv(self, predicate, timeout=DEFAULT_TIMEOUT):
+        """
+        Remove and return the first message in the RX queue for
+        which 'predicate' returns true
+        """
+        assert self.is_alive()
+
+        deadline = time.time() + timeout
+        while True:
+            with self.rx_cv:
+                for i, msg in enumerate(self.rx):
+                    if predicate(msg):
+                        return self.rx.pop(i)
+
+                now = time.time()
+                if now > deadline:
+                    return None
+                else:
+                    self.rx_cv.wait(deadline - now)
+
+    def recv_any(self, timeout=DEFAULT_TIMEOUT):
+        """
+        Return the first message in the RX queue
+        """
+        return self.recv(lambda msg: True, timeout)
+
+    def recv_xid(self, xid, timeout=DEFAULT_TIMEOUT):
+        """
+        Return the first message in the RX queue with XID 'xid'
+        """
+        return self.recv(lambda msg: msg.xid == xid, timeout)
+
+    def recv_class(self, klass, timeout=DEFAULT_TIMEOUT):
+        """
+        Return the first message in the RX queue which is an instance of 'klass'
+        """
+        return self.recv(lambda msg: isinstance(msg, klass), timeout)
+
+    def send_raw(self, buf):
+        """
+        Send raw bytes on the socket
+        """
+        assert self.is_alive()
+        self.logger.debug("Sending raw message length %d", len(buf))
+        with self.tx_lock:
+            if self.sock.sendall(buf) is not None:
+                raise RuntimeError("failed to send message to switch")
+
+    def send(self, msg):
+        """
+        Send a message
+        """
+        assert self.is_alive()
+
+        if msg.xid is None:
+            msg.xid = self._gen_xid()
+        buf = msg.pack()
+        self.logger.debug("Sending message %s.%s xid %d length %d",
+                          type(msg).__module__, type(msg).__name__, msg.xid, len(buf))
+        with self.tx_lock:
+            if self.sock.sendall(buf) is not None:
+                raise RuntimeError("failed to send message to switch")
+
+    def transact(self, msg, timeout=DEFAULT_TIMEOUT):
+        """
+        Send a message and return the reply
+        """
+        self.send(msg)
+        reply = self.recv_xid(msg.xid, timeout)
+        if reply is None:
+            raise TransactionError("no reply for %s" % type(msg).__name__, None)
+        elif isinstance(reply, loxi.protocol(reply.version).message.error_msg):
+            raise TransactionError("received %s in response to %s" % (type(reply).__name__, type(msg).__name__), reply)
+        return reply
+
+    def transact_multipart_generator(self, msg, timeout=DEFAULT_TIMEOUT):
+        """
+        Send a multipart request and yield each entry from the replies
+        """
+        self.send(msg)
+        finished = False
+        while not finished:
+            reply = self.recv_xid(msg.xid, timeout)
+            if reply is None:
+                raise TransactionError("no reply for %s" % type(msg).__name__, None)
+            elif not isinstance(reply, loxi.protocol(reply.version).message.stats_reply):
+                raise TransactionError("received %s in response to %s" % (type(reply).__name__, type(msg).__name__), reply)
+            for entry in reply.entries:
+                yield entry
+            finished = reply.flags & loxi.protocol(reply.version).OFPSF_REPLY_MORE == 0
+
+    def transact_multipart(self, msg, timeout=DEFAULT_TIMEOUT):
+        """
+        Send a multipart request and return all entries from the replies
+        """
+        entries = []
+        for entry in self.transact_multipart_generator(msg, timeout):
+            entries.append(entry)
+        return entries
+
+    def stop(self):
+        """
+        Signal the thread to exit and wait for it
+        """
+        assert not self.finished
+        self.logger.debug("Stopping connection")
+        self.finished = True
+        os.write(self.wakeup_wr, "x")
+        self.join()
+        self.sock.close()
+        os.close(self.wakeup_rd)
+        os.close(self.wakeup_wr)
+        self.logger.debug("Stopped connection")
+
+    def _gen_xid(self):
+        xid = self.next_xid
+        self.next_xid += 1
+        return xid
+
+def connect(ip, port=6653, daemon=True, ofp=loxi.of14):
+    """
+    Actively connect to a switch
+    """
+    soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+    soc.connect((ip, port))
+    soc.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, True)
+    cxn = Connection(soc)
+    cxn.daemon = daemon
+    cxn.logger.debug("Connected to %s:%d", ip, port)
+    cxn.start()
+
+    cxn.send(ofp.message.hello())
+    if not cxn.recv(lambda msg: msg.type == ofp.OFPT_HELLO):
+        raise Exception("Did not receive HELLO")
+
+    return cxn
diff --git a/src/python/loxi/of13/bsn_tlv.py b/src/python/loxi/of13/bsn_tlv.py
index 66a4839..3559248 100644
--- a/src/python/loxi/of13/bsn_tlv.py
+++ b/src/python/loxi/of13/bsn_tlv.py
@@ -3551,6 +3551,53 @@
 
 bsn_tlv.subtypes[6] = vlan_vid
 
+class vlan_vid_mask(bsn_tlv):
+    type = 77
+
+    def __init__(self, value=None):
+        if value != None:
+            self.value = value
+        else:
+            self.value = 0
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!H", self.type))
+        packed.append(struct.pack("!H", 0)) # placeholder for length at index 1
+        packed.append(struct.pack("!H", self.value))
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = vlan_vid_mask()
+        _type = reader.read("!H")[0]
+        assert(_type == 77)
+        _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length, 4)
+        obj.value = reader.read("!H")[0]
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.value != other.value: return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("vlan_vid_mask {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+                q.text("value = ");
+                q.text("%#x" % self.value)
+            q.breakable()
+        q.text('}')
+
+bsn_tlv.subtypes[77] = vlan_vid_mask
+
 class vrf(bsn_tlv):
     type = 19
 
diff --git a/src/python/loxi/of13/common.py b/src/python/loxi/of13/common.py
index 450c9bb..73011a4 100644
--- a/src/python/loxi/of13/common.py
+++ b/src/python/loxi/of13/common.py
@@ -2951,6 +2951,7 @@
         packed.append(loxi.generic_util.pack_list(self.action_ids))
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
+        packed.append(loxi.generic_util.pad_to(8, length))
         return ''.join(packed)
 
     @staticmethod
@@ -2962,6 +2963,7 @@
         orig_reader = reader
         reader = orig_reader.slice(_length, 4)
         obj.action_ids = loxi.generic_util.unpack_list(reader, ofp.action_id.action_id.unpack)
+        orig_reader.skip_align()
         return obj
 
     def __eq__(self, other):
@@ -2998,6 +3000,7 @@
         packed.append(loxi.generic_util.pack_list(self.action_ids))
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
+        packed.append(loxi.generic_util.pad_to(8, length))
         return ''.join(packed)
 
     @staticmethod
@@ -3009,6 +3012,7 @@
         orig_reader = reader
         reader = orig_reader.slice(_length, 4)
         obj.action_ids = loxi.generic_util.unpack_list(reader, ofp.action_id.action_id.unpack)
+        orig_reader.skip_align()
         return obj
 
     def __eq__(self, other):
@@ -3045,6 +3049,7 @@
         packed.append(loxi.generic_util.pack_list(self.oxm_ids))
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
+        packed.append(loxi.generic_util.pad_to(8, length))
         return ''.join(packed)
 
     @staticmethod
@@ -3056,6 +3061,7 @@
         orig_reader = reader
         reader = orig_reader.slice(_length, 4)
         obj.oxm_ids = loxi.generic_util.unpack_list(reader, ofp.common.uint32.unpack)
+        orig_reader.skip_align()
         return obj
 
     def __eq__(self, other):
@@ -3092,6 +3098,7 @@
         packed.append(loxi.generic_util.pack_list(self.oxm_ids))
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
+        packed.append(loxi.generic_util.pad_to(8, length))
         return ''.join(packed)
 
     @staticmethod
@@ -3103,6 +3110,7 @@
         orig_reader = reader
         reader = orig_reader.slice(_length, 4)
         obj.oxm_ids = loxi.generic_util.unpack_list(reader, ofp.common.uint32.unpack)
+        orig_reader.skip_align()
         return obj
 
     def __eq__(self, other):
@@ -3151,6 +3159,7 @@
         packed.append(self.experimenter_data)
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
+        packed.append(loxi.generic_util.pad_to(8, length))
         return ''.join(packed)
 
     @staticmethod
@@ -3169,6 +3178,7 @@
         obj.experimenter = reader.read("!L")[0]
         obj.subtype = reader.read("!L")[0]
         obj.experimenter_data = str(reader.read_all())
+        orig_reader.skip_align()
         return obj
 
     def __eq__(self, other):
@@ -3222,6 +3232,7 @@
         packed.append(self.experimenter_data)
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
+        packed.append(loxi.generic_util.pad_to(8, length))
         return ''.join(packed)
 
     @staticmethod
@@ -3240,6 +3251,7 @@
         obj.experimenter = reader.read("!L")[0]
         obj.subtype = reader.read("!L")[0]
         obj.experimenter_data = str(reader.read_all())
+        orig_reader.skip_align()
         return obj
 
     def __eq__(self, other):
@@ -3281,6 +3293,7 @@
         packed.append(loxi.generic_util.pack_list(self.instruction_ids))
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
+        packed.append(loxi.generic_util.pad_to(8, length))
         return ''.join(packed)
 
     @staticmethod
@@ -3292,6 +3305,7 @@
         orig_reader = reader
         reader = orig_reader.slice(_length, 4)
         obj.instruction_ids = loxi.generic_util.unpack_list(reader, ofp.instruction_id.instruction_id.unpack)
+        orig_reader.skip_align()
         return obj
 
     def __eq__(self, other):
@@ -3328,6 +3342,7 @@
         packed.append(loxi.generic_util.pack_list(self.instruction_ids))
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
+        packed.append(loxi.generic_util.pad_to(8, length))
         return ''.join(packed)
 
     @staticmethod
@@ -3339,6 +3354,7 @@
         orig_reader = reader
         reader = orig_reader.slice(_length, 4)
         obj.instruction_ids = loxi.generic_util.unpack_list(reader, ofp.instruction_id.instruction_id.unpack)
+        orig_reader.skip_align()
         return obj
 
     def __eq__(self, other):
@@ -3375,6 +3391,7 @@
         packed.append(loxi.generic_util.pack_list(self.oxm_ids))
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
+        packed.append(loxi.generic_util.pad_to(8, length))
         return ''.join(packed)
 
     @staticmethod
@@ -3386,6 +3403,7 @@
         orig_reader = reader
         reader = orig_reader.slice(_length, 4)
         obj.oxm_ids = loxi.generic_util.unpack_list(reader, ofp.common.uint32.unpack)
+        orig_reader.skip_align()
         return obj
 
     def __eq__(self, other):
@@ -3422,6 +3440,7 @@
         packed.append(loxi.generic_util.pack_list(self.next_table_ids))
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
+        packed.append(loxi.generic_util.pad_to(8, length))
         return ''.join(packed)
 
     @staticmethod
@@ -3433,6 +3452,7 @@
         orig_reader = reader
         reader = orig_reader.slice(_length, 4)
         obj.next_table_ids = loxi.generic_util.unpack_list(reader, ofp.common.uint8.unpack)
+        orig_reader.skip_align()
         return obj
 
     def __eq__(self, other):
@@ -3469,6 +3489,7 @@
         packed.append(loxi.generic_util.pack_list(self.next_table_ids))
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
+        packed.append(loxi.generic_util.pad_to(8, length))
         return ''.join(packed)
 
     @staticmethod
@@ -3480,6 +3501,7 @@
         orig_reader = reader
         reader = orig_reader.slice(_length, 4)
         obj.next_table_ids = loxi.generic_util.unpack_list(reader, ofp.common.uint8.unpack)
+        orig_reader.skip_align()
         return obj
 
     def __eq__(self, other):
@@ -3516,6 +3538,7 @@
         packed.append(loxi.generic_util.pack_list(self.oxm_ids))
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
+        packed.append(loxi.generic_util.pad_to(8, length))
         return ''.join(packed)
 
     @staticmethod
@@ -3527,6 +3550,7 @@
         orig_reader = reader
         reader = orig_reader.slice(_length, 4)
         obj.oxm_ids = loxi.generic_util.unpack_list(reader, ofp.common.uint32.unpack)
+        orig_reader.skip_align()
         return obj
 
     def __eq__(self, other):
@@ -3563,6 +3587,7 @@
         packed.append(loxi.generic_util.pack_list(self.action_ids))
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
+        packed.append(loxi.generic_util.pad_to(8, length))
         return ''.join(packed)
 
     @staticmethod
@@ -3574,6 +3599,7 @@
         orig_reader = reader
         reader = orig_reader.slice(_length, 4)
         obj.action_ids = loxi.generic_util.unpack_list(reader, ofp.action_id.action_id.unpack)
+        orig_reader.skip_align()
         return obj
 
     def __eq__(self, other):
@@ -3610,6 +3636,7 @@
         packed.append(loxi.generic_util.pack_list(self.action_ids))
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
+        packed.append(loxi.generic_util.pad_to(8, length))
         return ''.join(packed)
 
     @staticmethod
@@ -3621,6 +3648,7 @@
         orig_reader = reader
         reader = orig_reader.slice(_length, 4)
         obj.action_ids = loxi.generic_util.unpack_list(reader, ofp.action_id.action_id.unpack)
+        orig_reader.skip_align()
         return obj
 
     def __eq__(self, other):
@@ -3657,6 +3685,7 @@
         packed.append(loxi.generic_util.pack_list(self.oxm_ids))
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
+        packed.append(loxi.generic_util.pad_to(8, length))
         return ''.join(packed)
 
     @staticmethod
@@ -3668,6 +3697,7 @@
         orig_reader = reader
         reader = orig_reader.slice(_length, 4)
         obj.oxm_ids = loxi.generic_util.unpack_list(reader, ofp.common.uint32.unpack)
+        orig_reader.skip_align()
         return obj
 
     def __eq__(self, other):
@@ -3704,6 +3734,7 @@
         packed.append(loxi.generic_util.pack_list(self.oxm_ids))
         length = sum([len(x) for x in packed])
         packed[1] = struct.pack("!H", length)
+        packed.append(loxi.generic_util.pad_to(8, length))
         return ''.join(packed)
 
     @staticmethod
@@ -3715,6 +3746,7 @@
         orig_reader = reader
         reader = orig_reader.slice(_length, 4)
         obj.oxm_ids = loxi.generic_util.unpack_list(reader, ofp.common.uint32.unpack)
+        orig_reader.skip_align()
         return obj
 
     def __eq__(self, other):
diff --git a/src/python/loxi/of13/const.py b/src/python/loxi/of13/const.py
index fc0fd7b..35df7f0 100644
--- a/src/python/loxi/of13/const.py
+++ b/src/python/loxi/of13/const.py
@@ -354,6 +354,7 @@
 OFP_BSN_PORT_COUNTER_RX_LENGTH_ERRORS = 24
 OFP_BSN_PORT_COUNTER_RX_OVERFLOW_ERRORS = 25
 OFP_BSN_PORT_COUNTER_TX_CARRIER_ERRORS = 26
+OFP_BSN_PORT_COUNTER_RX_PACKETS_BAD_VLAN = 27
 
 ofp_bsn_port_counter_map = {
     0: 'OFP_BSN_PORT_COUNTER_RX_BYTES',
@@ -383,6 +384,7 @@
     24: 'OFP_BSN_PORT_COUNTER_RX_LENGTH_ERRORS',
     25: 'OFP_BSN_PORT_COUNTER_RX_OVERFLOW_ERRORS',
     26: 'OFP_BSN_PORT_COUNTER_TX_CARRIER_ERRORS',
+    27: 'OFP_BSN_PORT_COUNTER_RX_PACKETS_BAD_VLAN',
 }
 
 # Identifiers from group ofp_bsn_tcp_flag
diff --git a/src/python/loxi/of13/oxm.py b/src/python/loxi/of13/oxm.py
index 603afc3..51b1a73 100644
--- a/src/python/loxi/of13/oxm.py
+++ b/src/python/loxi/of13/oxm.py
@@ -975,6 +975,190 @@
 
 oxm.subtypes[207112] = bsn_ingress_port_group_id_masked
 
+class bsn_inner_eth_dst(oxm):
+    type_len = 207878
+
+    def __init__(self, value=None):
+        if value != None:
+            self.value = value
+        else:
+            self.value = [0,0,0,0,0,0]
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!L", self.type_len))
+        packed.append(struct.pack("!6B", *self.value))
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_inner_eth_dst()
+        _type_len = reader.read("!L")[0]
+        assert(_type_len == 207878)
+        obj.value = list(reader.read('!6B'))
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.value != other.value: return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_inner_eth_dst {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+                q.text("value = ");
+                q.text(util.pretty_mac(self.value))
+            q.breakable()
+        q.text('}')
+
+oxm.subtypes[207878] = bsn_inner_eth_dst
+
+class bsn_inner_eth_dst_masked(oxm):
+    type_len = 208140
+
+    def __init__(self, value=None, value_mask=None):
+        if value != None:
+            self.value = value
+        else:
+            self.value = [0,0,0,0,0,0]
+        if value_mask != None:
+            self.value_mask = value_mask
+        else:
+            self.value_mask = [0,0,0,0,0,0]
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!L", self.type_len))
+        packed.append(struct.pack("!6B", *self.value))
+        packed.append(struct.pack("!6B", *self.value_mask))
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_inner_eth_dst_masked()
+        _type_len = reader.read("!L")[0]
+        assert(_type_len == 208140)
+        obj.value = list(reader.read('!6B'))
+        obj.value_mask = list(reader.read('!6B'))
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.value != other.value: return False
+        if self.value_mask != other.value_mask: return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_inner_eth_dst_masked {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+                q.text("value = ");
+                q.text(util.pretty_mac(self.value))
+                q.text(","); q.breakable()
+                q.text("value_mask = ");
+                q.text(util.pretty_mac(self.value_mask))
+            q.breakable()
+        q.text('}')
+
+oxm.subtypes[208140] = bsn_inner_eth_dst_masked
+
+class bsn_inner_eth_src(oxm):
+    type_len = 208390
+
+    def __init__(self, value=None):
+        if value != None:
+            self.value = value
+        else:
+            self.value = [0,0,0,0,0,0]
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!L", self.type_len))
+        packed.append(struct.pack("!6B", *self.value))
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_inner_eth_src()
+        _type_len = reader.read("!L")[0]
+        assert(_type_len == 208390)
+        obj.value = list(reader.read('!6B'))
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.value != other.value: return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_inner_eth_src {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+                q.text("value = ");
+                q.text(util.pretty_mac(self.value))
+            q.breakable()
+        q.text('}')
+
+oxm.subtypes[208390] = bsn_inner_eth_src
+
+class bsn_inner_eth_src_masked(oxm):
+    type_len = 208652
+
+    def __init__(self, value=None, value_mask=None):
+        if value != None:
+            self.value = value
+        else:
+            self.value = [0,0,0,0,0,0]
+        if value_mask != None:
+            self.value_mask = value_mask
+        else:
+            self.value_mask = [0,0,0,0,0,0]
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!L", self.type_len))
+        packed.append(struct.pack("!6B", *self.value))
+        packed.append(struct.pack("!6B", *self.value_mask))
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_inner_eth_src_masked()
+        _type_len = reader.read("!L")[0]
+        assert(_type_len == 208652)
+        obj.value = list(reader.read('!6B'))
+        obj.value_mask = list(reader.read('!6B'))
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.value != other.value: return False
+        if self.value_mask != other.value_mask: return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_inner_eth_src_masked {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+                q.text("value = ");
+                q.text(util.pretty_mac(self.value))
+                q.text(","); q.breakable()
+                q.text("value_mask = ");
+                q.text(util.pretty_mac(self.value_mask))
+            q.breakable()
+        q.text('}')
+
+oxm.subtypes[208652] = bsn_inner_eth_src_masked
+
 class bsn_l2_cache_hit(oxm):
     type_len = 205825
 
@@ -2447,6 +2631,98 @@
 
 oxm.subtypes[197896] = bsn_vrf_masked
 
+class bsn_vxlan_network_id(oxm):
+    type_len = 207364
+
+    def __init__(self, value=None):
+        if value != None:
+            self.value = value
+        else:
+            self.value = 0
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!L", self.type_len))
+        packed.append(struct.pack("!L", self.value))
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_vxlan_network_id()
+        _type_len = reader.read("!L")[0]
+        assert(_type_len == 207364)
+        obj.value = reader.read("!L")[0]
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.value != other.value: return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_vxlan_network_id {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+                q.text("value = ");
+                q.text("%#x" % self.value)
+            q.breakable()
+        q.text('}')
+
+oxm.subtypes[207364] = bsn_vxlan_network_id
+
+class bsn_vxlan_network_id_masked(oxm):
+    type_len = 207624
+
+    def __init__(self, value=None, value_mask=None):
+        if value != None:
+            self.value = value
+        else:
+            self.value = 0
+        if value_mask != None:
+            self.value_mask = value_mask
+        else:
+            self.value_mask = 0
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!L", self.type_len))
+        packed.append(struct.pack("!L", self.value))
+        packed.append(struct.pack("!L", self.value_mask))
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_vxlan_network_id_masked()
+        _type_len = reader.read("!L")[0]
+        assert(_type_len == 207624)
+        obj.value = reader.read("!L")[0]
+        obj.value_mask = reader.read("!L")[0]
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.value != other.value: return False
+        if self.value_mask != other.value_mask: return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_vxlan_network_id_masked {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+                q.text("value = ");
+                q.text("%#x" % self.value)
+                q.text(","); q.breakable()
+                q.text("value_mask = ");
+                q.text("%#x" % self.value_mask)
+            q.breakable()
+        q.text('}')
+
+oxm.subtypes[207624] = bsn_vxlan_network_id_masked
+
 class eth_dst(oxm):
     type_len = 2147485190
 
diff --git a/src/python/loxi/of14/bsn_tlv.py b/src/python/loxi/of14/bsn_tlv.py
index 97a1619..0211226 100644
--- a/src/python/loxi/of14/bsn_tlv.py
+++ b/src/python/loxi/of14/bsn_tlv.py
@@ -3551,6 +3551,53 @@
 
 bsn_tlv.subtypes[6] = vlan_vid
 
+class vlan_vid_mask(bsn_tlv):
+    type = 77
+
+    def __init__(self, value=None):
+        if value != None:
+            self.value = value
+        else:
+            self.value = 0
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!H", self.type))
+        packed.append(struct.pack("!H", 0)) # placeholder for length at index 1
+        packed.append(struct.pack("!H", self.value))
+        length = sum([len(x) for x in packed])
+        packed[1] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = vlan_vid_mask()
+        _type = reader.read("!H")[0]
+        assert(_type == 77)
+        _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length, 4)
+        obj.value = reader.read("!H")[0]
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.value != other.value: return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("vlan_vid_mask {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+                q.text("value = ");
+                q.text("%#x" % self.value)
+            q.breakable()
+        q.text('}')
+
+bsn_tlv.subtypes[77] = vlan_vid_mask
+
 class vrf(bsn_tlv):
     type = 19
 
diff --git a/src/python/loxi/of14/const.py b/src/python/loxi/of14/const.py
index 89a293d..8b2ad1e 100644
--- a/src/python/loxi/of14/const.py
+++ b/src/python/loxi/of14/const.py
@@ -383,6 +383,7 @@
 OFP_BSN_PORT_COUNTER_RX_LENGTH_ERRORS = 24
 OFP_BSN_PORT_COUNTER_RX_OVERFLOW_ERRORS = 25
 OFP_BSN_PORT_COUNTER_TX_CARRIER_ERRORS = 26
+OFP_BSN_PORT_COUNTER_RX_PACKETS_BAD_VLAN = 27
 
 ofp_bsn_port_counter_map = {
     0: 'OFP_BSN_PORT_COUNTER_RX_BYTES',
@@ -412,6 +413,7 @@
     24: 'OFP_BSN_PORT_COUNTER_RX_LENGTH_ERRORS',
     25: 'OFP_BSN_PORT_COUNTER_RX_OVERFLOW_ERRORS',
     26: 'OFP_BSN_PORT_COUNTER_TX_CARRIER_ERRORS',
+    27: 'OFP_BSN_PORT_COUNTER_RX_PACKETS_BAD_VLAN',
 }
 
 # Identifiers from group ofp_bsn_tcp_flag
diff --git a/src/python/loxi/of14/message.py b/src/python/loxi/of14/message.py
index e1962ee..ae86367 100644
--- a/src/python/loxi/of14/message.py
+++ b/src/python/loxi/of14/message.py
@@ -3373,6 +3373,88 @@
 
 bsn_header.subtypes[36] = bsn_flow_idle_enable_set_request
 
+class bsn_generic_async(bsn_header):
+    version = 5
+    type = 4
+    experimenter = 6035143
+    subtype = 68
+
+    def __init__(self, xid=None, name=None, tlvs=None):
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        if name != None:
+            self.name = name
+        else:
+            self.name = ""
+        if tlvs != None:
+            self.tlvs = tlvs
+        else:
+            self.tlvs = []
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!B", self.version))
+        packed.append(struct.pack("!B", self.type))
+        packed.append(struct.pack("!H", 0)) # placeholder for length at index 2
+        packed.append(struct.pack("!L", self.xid))
+        packed.append(struct.pack("!L", self.experimenter))
+        packed.append(struct.pack("!L", self.subtype))
+        packed.append(struct.pack("!64s", self.name))
+        packed.append(loxi.generic_util.pack_list(self.tlvs))
+        length = sum([len(x) for x in packed])
+        packed[2] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_generic_async()
+        _version = reader.read("!B")[0]
+        assert(_version == 5)
+        _type = reader.read("!B")[0]
+        assert(_type == 4)
+        _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length, 4)
+        obj.xid = reader.read("!L")[0]
+        _experimenter = reader.read("!L")[0]
+        assert(_experimenter == 6035143)
+        _subtype = reader.read("!L")[0]
+        assert(_subtype == 68)
+        obj.name = reader.read("!64s")[0].rstrip("\x00")
+        obj.tlvs = loxi.generic_util.unpack_list(reader, ofp.bsn_tlv.bsn_tlv.unpack)
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.xid != other.xid: return False
+        if self.name != other.name: return False
+        if self.tlvs != other.tlvs: return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_generic_async {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+                q.text("xid = ");
+                if self.xid != None:
+                    q.text("%#x" % self.xid)
+                else:
+                    q.text('None')
+                q.text(","); q.breakable()
+                q.text("name = ");
+                q.pp(self.name)
+                q.text(","); q.breakable()
+                q.text("tlvs = ");
+                q.pp(self.tlvs)
+            q.breakable()
+        q.text('}')
+
+bsn_header.subtypes[68] = bsn_generic_async
+
 class bsn_generic_stats_reply(bsn_stats_reply):
     version = 5
     type = 19
@@ -8096,6 +8178,68 @@
 
 bsn_header.subtypes[61] = bsn_table_set_buckets_size
 
+class bsn_takeover(bsn_header):
+    version = 5
+    type = 4
+    experimenter = 6035143
+    subtype = 69
+
+    def __init__(self, xid=None):
+        if xid != None:
+            self.xid = xid
+        else:
+            self.xid = None
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!B", self.version))
+        packed.append(struct.pack("!B", self.type))
+        packed.append(struct.pack("!H", 0)) # placeholder for length at index 2
+        packed.append(struct.pack("!L", self.xid))
+        packed.append(struct.pack("!L", self.experimenter))
+        packed.append(struct.pack("!L", self.subtype))
+        length = sum([len(x) for x in packed])
+        packed[2] = struct.pack("!H", length)
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_takeover()
+        _version = reader.read("!B")[0]
+        assert(_version == 5)
+        _type = reader.read("!B")[0]
+        assert(_type == 4)
+        _length = reader.read("!H")[0]
+        orig_reader = reader
+        reader = orig_reader.slice(_length, 4)
+        obj.xid = reader.read("!L")[0]
+        _experimenter = reader.read("!L")[0]
+        assert(_experimenter == 6035143)
+        _subtype = reader.read("!L")[0]
+        assert(_subtype == 69)
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.xid != other.xid: return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_takeover {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+                q.text("xid = ");
+                if self.xid != None:
+                    q.text("%#x" % self.xid)
+                else:
+                    q.text('None')
+            q.breakable()
+        q.text('}')
+
+bsn_header.subtypes[69] = bsn_takeover
+
 class bsn_time_reply(bsn_header):
     version = 5
     type = 4
diff --git a/src/python/loxi/of14/oxm.py b/src/python/loxi/of14/oxm.py
index e6964a1..9abd97f 100644
--- a/src/python/loxi/of14/oxm.py
+++ b/src/python/loxi/of14/oxm.py
@@ -883,6 +883,190 @@
 
 oxm.subtypes[207112] = bsn_ingress_port_group_id_masked
 
+class bsn_inner_eth_dst(oxm):
+    type_len = 207878
+
+    def __init__(self, value=None):
+        if value != None:
+            self.value = value
+        else:
+            self.value = [0,0,0,0,0,0]
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!L", self.type_len))
+        packed.append(struct.pack("!6B", *self.value))
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_inner_eth_dst()
+        _type_len = reader.read("!L")[0]
+        assert(_type_len == 207878)
+        obj.value = list(reader.read('!6B'))
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.value != other.value: return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_inner_eth_dst {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+                q.text("value = ");
+                q.text(util.pretty_mac(self.value))
+            q.breakable()
+        q.text('}')
+
+oxm.subtypes[207878] = bsn_inner_eth_dst
+
+class bsn_inner_eth_dst_masked(oxm):
+    type_len = 208140
+
+    def __init__(self, value=None, value_mask=None):
+        if value != None:
+            self.value = value
+        else:
+            self.value = [0,0,0,0,0,0]
+        if value_mask != None:
+            self.value_mask = value_mask
+        else:
+            self.value_mask = [0,0,0,0,0,0]
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!L", self.type_len))
+        packed.append(struct.pack("!6B", *self.value))
+        packed.append(struct.pack("!6B", *self.value_mask))
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_inner_eth_dst_masked()
+        _type_len = reader.read("!L")[0]
+        assert(_type_len == 208140)
+        obj.value = list(reader.read('!6B'))
+        obj.value_mask = list(reader.read('!6B'))
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.value != other.value: return False
+        if self.value_mask != other.value_mask: return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_inner_eth_dst_masked {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+                q.text("value = ");
+                q.text(util.pretty_mac(self.value))
+                q.text(","); q.breakable()
+                q.text("value_mask = ");
+                q.text(util.pretty_mac(self.value_mask))
+            q.breakable()
+        q.text('}')
+
+oxm.subtypes[208140] = bsn_inner_eth_dst_masked
+
+class bsn_inner_eth_src(oxm):
+    type_len = 208390
+
+    def __init__(self, value=None):
+        if value != None:
+            self.value = value
+        else:
+            self.value = [0,0,0,0,0,0]
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!L", self.type_len))
+        packed.append(struct.pack("!6B", *self.value))
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_inner_eth_src()
+        _type_len = reader.read("!L")[0]
+        assert(_type_len == 208390)
+        obj.value = list(reader.read('!6B'))
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.value != other.value: return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_inner_eth_src {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+                q.text("value = ");
+                q.text(util.pretty_mac(self.value))
+            q.breakable()
+        q.text('}')
+
+oxm.subtypes[208390] = bsn_inner_eth_src
+
+class bsn_inner_eth_src_masked(oxm):
+    type_len = 208652
+
+    def __init__(self, value=None, value_mask=None):
+        if value != None:
+            self.value = value
+        else:
+            self.value = [0,0,0,0,0,0]
+        if value_mask != None:
+            self.value_mask = value_mask
+        else:
+            self.value_mask = [0,0,0,0,0,0]
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!L", self.type_len))
+        packed.append(struct.pack("!6B", *self.value))
+        packed.append(struct.pack("!6B", *self.value_mask))
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_inner_eth_src_masked()
+        _type_len = reader.read("!L")[0]
+        assert(_type_len == 208652)
+        obj.value = list(reader.read('!6B'))
+        obj.value_mask = list(reader.read('!6B'))
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.value != other.value: return False
+        if self.value_mask != other.value_mask: return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_inner_eth_src_masked {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+                q.text("value = ");
+                q.text(util.pretty_mac(self.value))
+                q.text(","); q.breakable()
+                q.text("value_mask = ");
+                q.text(util.pretty_mac(self.value_mask))
+            q.breakable()
+        q.text('}')
+
+oxm.subtypes[208652] = bsn_inner_eth_src_masked
+
 class bsn_l3_interface_class_id(oxm):
     type_len = 198660
 
@@ -2171,6 +2355,98 @@
 
 oxm.subtypes[197896] = bsn_vrf_masked
 
+class bsn_vxlan_network_id(oxm):
+    type_len = 207364
+
+    def __init__(self, value=None):
+        if value != None:
+            self.value = value
+        else:
+            self.value = 0
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!L", self.type_len))
+        packed.append(struct.pack("!L", self.value))
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_vxlan_network_id()
+        _type_len = reader.read("!L")[0]
+        assert(_type_len == 207364)
+        obj.value = reader.read("!L")[0]
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.value != other.value: return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_vxlan_network_id {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+                q.text("value = ");
+                q.text("%#x" % self.value)
+            q.breakable()
+        q.text('}')
+
+oxm.subtypes[207364] = bsn_vxlan_network_id
+
+class bsn_vxlan_network_id_masked(oxm):
+    type_len = 207624
+
+    def __init__(self, value=None, value_mask=None):
+        if value != None:
+            self.value = value
+        else:
+            self.value = 0
+        if value_mask != None:
+            self.value_mask = value_mask
+        else:
+            self.value_mask = 0
+        return
+
+    def pack(self):
+        packed = []
+        packed.append(struct.pack("!L", self.type_len))
+        packed.append(struct.pack("!L", self.value))
+        packed.append(struct.pack("!L", self.value_mask))
+        return ''.join(packed)
+
+    @staticmethod
+    def unpack(reader):
+        obj = bsn_vxlan_network_id_masked()
+        _type_len = reader.read("!L")[0]
+        assert(_type_len == 207624)
+        obj.value = reader.read("!L")[0]
+        obj.value_mask = reader.read("!L")[0]
+        return obj
+
+    def __eq__(self, other):
+        if type(self) != type(other): return False
+        if self.value != other.value: return False
+        if self.value_mask != other.value_mask: return False
+        return True
+
+    def pretty_print(self, q):
+        q.text("bsn_vxlan_network_id_masked {")
+        with q.group():
+            with q.indent(2):
+                q.breakable()
+                q.text("value = ");
+                q.text("%#x" % self.value)
+                q.text(","); q.breakable()
+                q.text("value_mask = ");
+                q.text("%#x" % self.value_mask)
+            q.breakable()
+        q.text('}')
+
+oxm.subtypes[207624] = bsn_vxlan_network_id_masked
+
 class eth_dst(oxm):
     type_len = 2147485190