update pyloxi to 46b7804026447644fec44c0ad517b41844eeb91b
diff --git a/src/python/loxi/of13/message.py b/src/python/loxi/of13/message.py
index 543442b..4c22e45 100644
--- a/src/python/loxi/of13/message.py
+++ b/src/python/loxi/of13/message.py
@@ -7554,8 +7554,8 @@
 
 def parse_message(buf):
     msg_ver, msg_type, msg_len, msg_xid = parse_header(buf)
-    if msg_ver != const.OFP_VERSION and msg_type != ofp.OFPT_HELLO:
-        raise loxi.ProtocolError("wrong OpenFlow version")
+    if msg_ver != const.OFP_VERSION and msg_type != const.OFPT_HELLO:
+        raise loxi.ProtocolError("wrong OpenFlow version (expected %d, got %d)" % (const.OFP_VERSION, msg_ver))
     if len(buf) != msg_len:
         raise loxi.ProtocolError("incorrect message size")
     if msg_type in parsers:
@@ -7564,9 +7564,10 @@
         raise loxi.ProtocolError("unexpected message type")
 
 def parse_flow_mod(buf):
-    if len(buf) < 56 + 2:
+    if len(buf) < 25 + 1:
         raise loxi.ProtocolError("message too short")
-    cmd, = struct.unpack_from("!H", buf, 56)
+    # Technically uint16_t for OF 1.0
+    cmd, = struct.unpack_from("!B", buf, 25)
     if cmd in flow_mod_parsers:
         return flow_mod_parsers[cmd](buf)
     else:
@@ -7648,7 +7649,39 @@
     const.OFPFC_DELETE_STRICT : flow_delete_strict.unpack,
 }
 
-# TODO OF 1.3 multipart messages
+multipart_reply_parsers = {
+    const.OFPMP_DESC : desc_stats_reply.unpack,
+    const.OFPMP_FLOW : flow_stats_reply.unpack,
+    const.OFPMP_AGGREGATE : aggregate_stats_reply.unpack,
+    const.OFPMP_TABLE : table_stats_reply.unpack,
+    const.OFPMP_PORT_STATS : port_stats_reply.unpack,
+    const.OFPMP_QUEUE : queue_stats_reply.unpack,
+    const.OFPMP_GROUP : group_stats_reply.unpack,
+    const.OFPMP_GROUP_DESC : group_desc_stats_reply.unpack,
+    const.OFPMP_GROUP_FEATURES : group_features_stats_reply.unpack,
+    const.OFPMP_METER : meter_stats_reply.unpack,
+    const.OFPMP_METER_CONFIG : meter_config_stats_reply.unpack,
+    const.OFPMP_METER_FEATURES : meter_features_stats_reply.unpack,
+    const.OFPMP_TABLE_FEATURES : table_features_stats_reply.unpack,
+    const.OFPMP_PORT_DESC : port_desc_stats_reply.unpack,
+}
+
+multipart_request_parsers = {
+    const.OFPMP_DESC : desc_stats_request.unpack,
+    const.OFPMP_FLOW : flow_stats_request.unpack,
+    const.OFPMP_AGGREGATE : aggregate_stats_request.unpack,
+    const.OFPMP_TABLE : table_stats_request.unpack,
+    const.OFPMP_PORT_STATS : port_stats_request.unpack,
+    const.OFPMP_QUEUE : queue_stats_request.unpack,
+    const.OFPMP_GROUP : group_stats_request.unpack,
+    const.OFPMP_GROUP_DESC : group_desc_stats_request.unpack,
+    const.OFPMP_GROUP_FEATURES : group_features_stats_request.unpack,
+    const.OFPMP_METER : meter_stats_request.unpack,
+    const.OFPMP_METER_CONFIG : meter_config_stats_request.unpack,
+    const.OFPMP_METER_FEATURES : meter_features_stats_request.unpack,
+    const.OFPMP_TABLE_FEATURES : table_features_stats_request.unpack,
+    const.OFPMP_PORT_DESC : port_desc_stats_request.unpack,
+}
 
 experimenter_parsers = {
     6035143 : {
diff --git a/src/python/loxi/of13/oxm.py b/src/python/loxi/of13/oxm.py
index fb1291d..f17151e 100644
--- a/src/python/loxi/of13/oxm.py
+++ b/src/python/loxi/of13/oxm.py
@@ -566,114 +566,6 @@
             q.breakable()
         q.text('}')
 
-class dst_meta_id(OXM):
-    type_len = 258561
-
-    def __init__(self, value=None):
-        if value != None:
-            self.value = value
-        else:
-            self.value = 0
-
-    def pack(self):
-        packed = []
-        packed.append(struct.pack("!L", self.type_len))
-        packed.append(struct.pack("!B", self.value))
-        return ''.join(packed)
-
-    @staticmethod
-    def unpack(buf):
-        obj = dst_meta_id()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
-        _type_len = reader.read("!L")[0]
-        assert(_type_len == 258561)
-        obj.value = reader.read("!B")[0]
-        return obj
-
-    def __eq__(self, other):
-        if type(self) != type(other): return False
-        if self.value != other.value: return False
-        return True
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
-    def pretty_print(self, q):
-        q.text("dst_meta_id {")
-        with q.group():
-            with q.indent(2):
-                q.breakable()
-                q.text("value = ");
-                q.text("%#x" % self.value)
-            q.breakable()
-        q.text('}')
-
-class dst_meta_id_masked(OXM):
-    type_len = 258818
-
-    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
-
-    def pack(self):
-        packed = []
-        packed.append(struct.pack("!L", self.type_len))
-        packed.append(struct.pack("!B", self.value))
-        packed.append(struct.pack("!B", self.value_mask))
-        return ''.join(packed)
-
-    @staticmethod
-    def unpack(buf):
-        obj = dst_meta_id_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
-        _type_len = reader.read("!L")[0]
-        assert(_type_len == 258818)
-        obj.value = reader.read("!B")[0]
-        obj.value_mask = reader.read("!B")[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 __ne__(self, other):
-        return not self.__eq__(other)
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
-    def pretty_print(self, q):
-        q.text("dst_meta_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('}')
-
 class eth_dst(OXM):
     type_len = 2147485190
 
@@ -3374,114 +3266,6 @@
             q.breakable()
         q.text('}')
 
-class src_meta_id(OXM):
-    type_len = 258049
-
-    def __init__(self, value=None):
-        if value != None:
-            self.value = value
-        else:
-            self.value = 0
-
-    def pack(self):
-        packed = []
-        packed.append(struct.pack("!L", self.type_len))
-        packed.append(struct.pack("!B", self.value))
-        return ''.join(packed)
-
-    @staticmethod
-    def unpack(buf):
-        obj = src_meta_id()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
-        _type_len = reader.read("!L")[0]
-        assert(_type_len == 258049)
-        obj.value = reader.read("!B")[0]
-        return obj
-
-    def __eq__(self, other):
-        if type(self) != type(other): return False
-        if self.value != other.value: return False
-        return True
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
-    def pretty_print(self, q):
-        q.text("src_meta_id {")
-        with q.group():
-            with q.indent(2):
-                q.breakable()
-                q.text("value = ");
-                q.text("%#x" % self.value)
-            q.breakable()
-        q.text('}')
-
-class src_meta_id_masked(OXM):
-    type_len = 258306
-
-    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
-
-    def pack(self):
-        packed = []
-        packed.append(struct.pack("!L", self.type_len))
-        packed.append(struct.pack("!B", self.value))
-        packed.append(struct.pack("!B", self.value_mask))
-        return ''.join(packed)
-
-    @staticmethod
-    def unpack(buf):
-        obj = src_meta_id_masked()
-        if type(buf) == loxi.generic_util.OFReader:
-            reader = buf
-        else:
-            reader = loxi.generic_util.OFReader(buf)
-        _type_len = reader.read("!L")[0]
-        assert(_type_len == 258306)
-        obj.value = reader.read("!B")[0]
-        obj.value_mask = reader.read("!B")[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 __ne__(self, other):
-        return not self.__eq__(other)
-
-    def show(self):
-        import loxi.pp
-        return loxi.pp.pp(self)
-
-    def pretty_print(self, q):
-        q.text("src_meta_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('}')
-
 class tcp_dst(OXM):
     type_len = 2147490818
 
@@ -4132,10 +3916,6 @@
 
 
 parsers = {
-    258049 : src_meta_id.unpack,
-    258306 : src_meta_id_masked.unpack,
-    258561 : dst_meta_id.unpack,
-    258818 : dst_meta_id_masked.unpack,
     2147483652 : in_port.unpack,
     2147483912 : in_port_masked.unpack,
     2147484164 : in_phy_port.unpack,