From a8e164a535e0ffbe20eaa652366c33a9ab3d60b7 Mon Sep 17 00:00:00 2001
From: Can Zhang <can@canx.me>
Date: Thu, 28 Mar 2013 18:05:50 +0800
Subject: [PATCH] modified from OHMURA Kei's
 patch(http://sourceforge.net/mailarchive/forum.php?thread_name=1364288359-6956-3-git-send-email-ohmura.kei%40lab.ntt.co.jp&forum_name=ryu-devel)

changed IPv6 addr pack str to '!16s', supports IPv6 src, dest parse, and actions in NXFlowStats
---
 ryu/ofproto/nx_match.py            | 151 +++++++++++++++++++++++++++---
 ryu/ofproto/ofproto_v1_0.py        |  21 +++++
 ryu/ofproto/ofproto_v1_0_parser.py | 185 ++++++++++++++++++++++++++++++++++++-
 3 files changed, 342 insertions(+), 15 deletions(-)

diff --git a/ryu/ofproto/nx_match.py b/ryu/ofproto/nx_match.py
index 63d35ec..e51b763 100644
--- a/ryu/ofproto/nx_match.py
+++ b/ryu/ofproto/nx_match.py
@@ -57,6 +57,7 @@ MF_PACK_STRING_BE32 = '!I'
 MF_PACK_STRING_BE16 = '!H'
 MF_PACK_STRING_8 = '!B'
 MF_PACK_STRING_MAC = '!6s'
+MF_PACK_STRING_IPV6_ADDR = '!16s'
 
 _MF_FIELDS = {}
 
@@ -388,12 +389,50 @@ def mf_from_nxm_header(nxm_header):
 
 
 class MFField(object):
+    _FIELDS_HEADERS = {}
+
+    @staticmethod
+    def register_field_header(headers):
+        def _register_field_header(cls):
+            for header in headers:
+                MFField._FIELDS_HEADERS[header] = cls
+            return cls
+        return _register_field_header
+
     def __init__(self, nxm_header, pack_str):
         self.nxm_header = nxm_header
         self.pack_str = pack_str
         self.n_bytes = struct.calcsize(pack_str)
         self.n_bits = self.n_bytes * 8
 
+    @classmethod
+    def parser(cls, buf, offset):
+        (header,) = struct.unpack_from('!I', buf, offset)
+
+        cls_ = MFField._FIELDS_HEADERS.get(header)
+
+        if cls_:
+            field = cls_.field_parser(header, buf, offset)
+        else:
+            # print 'unknown field type'
+            raise
+        field.length = (header & 0xff) + 4
+
+        return field
+
+    @classmethod
+    def field_parser(cls, header, buf, offset):
+        hasmask = (header >> 8) & 1
+        mask = None
+        if hasmask:
+            pack_str = '!' + cls.pack_str[1:] * 2
+            (value, mask) = struct.unpack_from(pack_str, buf,
+                                               offset + 4)
+        else:
+            (value,) = struct.unpack_from(cls.pack_str, buf,
+                                          offset + 4)
+        return cls(header, value, mask)
+
     def _put(self, buf, offset, value):
         ofproto_parser.msg_pack_into(self.pack_str, buf, offset, value)
         return self.n_bytes
@@ -415,7 +454,7 @@ class MFField(object):
 
     def _putv6(self, buf, offset, value):
         ofproto_parser.msg_pack_into(self.pack_str, buf, offset,
-                                     *value)
+                                     value)
         return self.n_bytes
 
     def putv6(self, buf, offset, value, mask):
@@ -427,10 +466,17 @@ class MFField(object):
 
 @_register_make
 @_set_nxm_headers([ofproto_v1_0.NXM_OF_IN_PORT])
+@MFField.register_field_header([ofproto_v1_0.NXM_OF_IN_PORT])
 class MFInPort(MFField):
+    pack_str = MF_PACK_STRING_BE16
+
+    def __init__(self, header, value, mask=None):
+        super(MFInPort, self).__init__(header, MFInPort.pack_str)
+        self.value = value
+
     @classmethod
     def make(cls, header):
-        return cls(header, MF_PACK_STRING_BE16)
+        return cls(header, MFInPort.pack_str)
 
     def put(self, buf, offset, rule):
         return self._put(buf, offset, rule.flow.in_port)
@@ -438,10 +484,18 @@ class MFInPort(MFField):
 
 @_register_make
 @_set_nxm_headers([ofproto_v1_0.NXM_OF_ETH_DST, ofproto_v1_0.NXM_OF_ETH_DST_W])
+@MFField.register_field_header([ofproto_v1_0.NXM_OF_ETH_DST,
+                                ofproto_v1_0.NXM_OF_ETH_DST_W])
 class MFEthDst(MFField):
+    pack_str = MF_PACK_STRING_MAC
+
+    def __init__(self, header, value, mask=None):
+        super(MFEthDst, self).__init__(header, MFEthDst.pack_str)
+        self.value = value
+
     @classmethod
     def make(cls, header):
-        return cls(header, MF_PACK_STRING_MAC)
+        return cls(header, MFEthDst.pack_str)
 
     def put(self, buf, offset, rule):
         if rule.wc.dl_dst_mask:
@@ -453,10 +507,18 @@ class MFEthDst(MFField):
 
 @_register_make
 @_set_nxm_headers([ofproto_v1_0.NXM_OF_ETH_SRC, ofproto_v1_0.NXM_OF_ETH_SRC_W])
+@MFField.register_field_header([ofproto_v1_0.NXM_OF_ETH_SRC,
+                                ofproto_v1_0.NXM_OF_ETH_SRC_W])
 class MFEthSrc(MFField):
+    pack_str = MF_PACK_STRING_MAC
+
+    def __init__(self, header, value, mask=None):
+        super(MFEthSrc, self).__init__(header, MFEthSrc.pack_str)
+        self.value = value
+
     @classmethod
     def make(cls, header):
-        return cls(header, MF_PACK_STRING_MAC)
+        return cls(header, MFEthSrc.pack_str)
 
     def put(self, buf, offset, rule):
         if rule.wc.dl_src_mask:
@@ -468,10 +530,17 @@ class MFEthSrc(MFField):
 
 @_register_make
 @_set_nxm_headers([ofproto_v1_0.NXM_OF_ETH_TYPE])
+@MFField.register_field_header([ofproto_v1_0.NXM_OF_ETH_TYPE])
 class MFEthType(MFField):
+    pack_str = MF_PACK_STRING_BE16
+
+    def __init__(self, header, value, mask=None):
+        super(MFEthType, self).__init__(header, MFEthType.pack_str)
+        self.value = value
+
     @classmethod
     def make(cls, header):
-        return cls(header, MF_PACK_STRING_BE16)
+        return cls(header, MFEthType.pack_str)
 
     def put(self, buf, offset, rule):
         return self._put(buf, offset, rule.flow.dl_type)
@@ -480,10 +549,18 @@ class MFEthType(MFField):
 @_register_make
 @_set_nxm_headers([ofproto_v1_0.NXM_OF_VLAN_TCI,
                    ofproto_v1_0.NXM_OF_VLAN_TCI_W])
+@MFField.register_field_header([ofproto_v1_0.NXM_OF_VLAN_TCI,
+                                ofproto_v1_0.NXM_OF_VLAN_TCI_W])
 class MFVlan(MFField):
+    pack_str = MF_PACK_STRING_BE16
+
+    def __init__(self, header, value, mask=None):
+        super(MFVlan, self).__init__(header, MFVlan.pack_str)
+        self.value = value
+
     @classmethod
     def make(cls, header):
-        return cls(header, MF_PACK_STRING_BE16)
+        return cls(header, MFVlan.pack_str)
 
     def put(self, buf, offset, rule):
         return self.putm(buf, offset, rule.flow.vlan_tci,
@@ -492,10 +569,17 @@ class MFVlan(MFField):
 
 @_register_make
 @_set_nxm_headers([ofproto_v1_0.NXM_OF_IP_TOS])
+@MFField.register_field_header([ofproto_v1_0.NXM_OF_IP_TOS])
 class MFIPDSCP(MFField):
+    pack_str = MF_PACK_STRING_8
+
+    def __init__(self, header, value, mask=None):
+        super(MFIPDSCP, self).__init__(header, MFIPDSCP.pack_str)
+        self.value = value
+
     @classmethod
     def make(cls, header):
-        return cls(header, MF_PACK_STRING_8)
+        return cls(header, MFIPDSCP.pack_str)
 
     def put(self, buf, offset, rule):
         return self._put(buf, offset,
@@ -503,11 +587,20 @@ class MFIPDSCP(MFField):
 
 
 @_register_make
-@_set_nxm_headers([ofproto_v1_0.NXM_NX_TUN_ID, ofproto_v1_0.NXM_NX_TUN_ID_W])
+@_set_nxm_headers([ofproto_v1_0.NXM_NX_TUN_ID,
+                   ofproto_v1_0.NXM_NX_TUN_ID_W])
+@MFField.register_field_header([ofproto_v1_0.NXM_NX_TUN_ID,
+                                ofproto_v1_0.NXM_NX_TUN_ID_W])
 class MFTunId(MFField):
+    pack_str = MF_PACK_STRING_BE64
+
+    def __init__(self, header, value, mask=None):
+        super(MFTunId, self).__init__(header, MFTunId.pack_str)
+        self.value = value
+
     @classmethod
     def make(cls, header):
-        return cls(header, MF_PACK_STRING_BE64)
+        return cls(header, MFTunId.pack_str)
 
     def put(self, buf, offset, rule):
         return self.putm(buf, offset, rule.flow.tun_id, rule.wc.tun_id_mask)
@@ -515,10 +608,18 @@ class MFTunId(MFField):
 
 @_register_make
 @_set_nxm_headers([ofproto_v1_0.NXM_OF_IP_SRC, ofproto_v1_0.NXM_OF_IP_SRC_W])
+@MFField.register_field_header([ofproto_v1_0.NXM_OF_IP_SRC,
+                                ofproto_v1_0.NXM_OF_IP_SRC_W])
 class MFIPSrc(MFField):
+    pack_str = MF_PACK_STRING_BE32
+
+    def __init__(self, header, value, mask=None):
+        super(MFIPSrc, self).__init__(header, MFIPSrc.pack_str)
+        self.value = value
+
     @classmethod
     def make(cls, header):
-        return cls(header, MF_PACK_STRING_BE32)
+        return cls(header, MFIPSrc.pack_str)
 
     def put(self, buf, offset, rule):
         return self.putm(buf, offset, rule.flow.nw_src, rule.wc.nw_src_mask)
@@ -526,10 +627,18 @@ class MFIPSrc(MFField):
 
 @_register_make
 @_set_nxm_headers([ofproto_v1_0.NXM_OF_IP_DST, ofproto_v1_0.NXM_OF_IP_DST_W])
+@MFField.register_field_header([ofproto_v1_0.NXM_OF_IP_DST,
+                                ofproto_v1_0.NXM_OF_IP_DST_W])
 class MFIPDst(MFField):
+    pack_str = MF_PACK_STRING_BE32
+
+    def __init__(self, header, value, mask=None):
+        super(MFIPDst, self).__init__(header, MFIPDst.pack_str)
+        self.value = value
+
     @classmethod
     def make(cls, header):
-        return cls(header, MF_PACK_STRING_BE32)
+        return cls(header, MFIPDst.pack_str)
 
     def put(self, buf, offset, rule):
         return self.putm(buf, offset, rule.flow.nw_dst, rule.wc.nw_dst_mask)
@@ -617,10 +726,18 @@ class MFArpSha(MFField):
 @_register_make
 @_set_nxm_headers([ofproto_v1_0.NXM_NX_IPV6_SRC,
                    ofproto_v1_0.NXM_NX_IPV6_SRC_W])
+@MFField.register_field_header([ofproto_v1_0.NXM_NX_IPV6_SRC,
+                            ofproto_v1_0.NXM_NX_IPV6_SRC_W])
 class MFIPV6Src(MFField):
+    pack_str = MF_PACK_STRING_IPV6_ADDR
+
+    def __init__(self, header, value, mask = None):
+        super(MFIPV6Src, self).__init__(header, MFIPV6Src.pack_str)
+        self.value = value
+
     @classmethod
     def make(cls, header):
-        return cls(header, '!4I')
+        return cls(header, MFIPV6Src.pack_str)
 
     def put(self, buf, offset, rule):
         return self.putv6(buf, offset,
@@ -631,10 +748,18 @@ class MFIPV6Src(MFField):
 @_register_make
 @_set_nxm_headers([ofproto_v1_0.NXM_NX_IPV6_DST,
                    ofproto_v1_0.NXM_NX_IPV6_DST_W])
+@MFField.register_field_header([ofproto_v1_0.NXM_NX_IPV6_DST,
+                   ofproto_v1_0.NXM_NX_IPV6_DST_W])
 class MFIPV6Dst(MFField):
+    pack_str = MF_PACK_STRING_IPV6_ADDR
+
+    def __init__(self, header, value, mask = None):
+        super(MFIPV6Dst, self).__init__(header, MFIPV6Dst.pack_str)
+        self.value = value
+
     @classmethod
     def make(cls, header):
-        return cls(header, '!4I')
+        return cls(header, MFIPV6Dst.pack_str)
 
     def put(self, buf, offset, rule):
         return self.putv6(buf, offset,
diff --git a/ryu/ofproto/ofproto_v1_0.py b/ryu/ofproto/ofproto_v1_0.py
index 685cc71..ca6e384 100644
--- a/ryu/ofproto/ofproto_v1_0.py
+++ b/ryu/ofproto/ofproto_v1_0.py
@@ -598,6 +598,11 @@ NXFF_NXM = 2
 NXPIF_OPENFLOW10 = 0
 NXPIF_NXM = 1
 
+# enum nx_stats_types
+NXST_FLOW = 0
+NXST_AGGREGATE = 1
+NXST_FLOW_MONITOR = 2
+
 NICIRA_HEADER_PACK_STR = '!II'
 NICIRA_HEADER_SIZE = 16
 assert (calcsize(NICIRA_HEADER_PACK_STR) +
@@ -648,6 +653,22 @@ NX_CONTROLLER_ID_SIZE = 24
 assert (calcsize(NX_CONTROLLER_ID_PACK_STR) +
         NICIRA_HEADER_SIZE == NX_CONTROLLER_ID_SIZE)
 
+NX_STATS_MSG_PACK_STR = '!I4x'
+NX_STATS_MSG0_SIZE = 8
+assert calcsize(NX_STATS_MSG_PACK_STR) == NX_STATS_MSG0_SIZE
+NX_STATS_MSG_SIZE = 24
+assert (calcsize(NX_STATS_MSG_PACK_STR) + OFP_VENDOR_STATS_MSG_SIZE ==
+        NX_STATS_MSG_SIZE)
+
+NX_FLOW_STATS_REQUEST_PACK_STR = '!2HB3x'
+NX_FLOW_STATS_REQUEST_SIZE = 8
+assert (calcsize(NX_FLOW_STATS_REQUEST_PACK_STR) ==
+        NX_FLOW_STATS_REQUEST_SIZE)
+
+NX_FLOW_STATS_PACK_STR = '!HBxIIHHHHHHQQQ'
+NX_FLOW_STATS_SIZE = 48
+assert calcsize(NX_FLOW_STATS_PACK_STR) == NX_FLOW_STATS_SIZE
+
 
 def nxm_header__(vendor, field, hasmask, length):
     return (vendor << 16) | (field << 9) | (hasmask << 8) | length
diff --git a/ryu/ofproto/ofproto_v1_0_parser.py b/ryu/ofproto/ofproto_v1_0_parser.py
index 8a141bd..afc913c 100644
--- a/ryu/ofproto/ofproto_v1_0_parser.py
+++ b/ryu/ofproto/ofproto_v1_0_parser.py
@@ -1025,6 +1025,60 @@ class OFPVendorStats(collections.namedtuple('OFPVendorStats',
         return stats
 
 
+class NXFlowStats(object):
+    def __init__(self):
+        super(NXFlowStats, self).__init__()
+        self.length = None
+        self.table_id = None
+        self.duration_sec = None
+        self.duration_nsec = None
+        self.priority = None
+        self.idle_timeout = None
+        self.hard_timeout = None
+        self.match_len = None
+        self.idle_age = None
+        self.hard_age = None
+        self.cookie = None
+        self.packet_count = None
+        self.byte_count = None
+
+    @classmethod
+    def parser(cls, buf, offset):
+        original_offset = offset
+        nxflow_stats = cls()
+        (nxflow_stats.length, nxflow_stats.table_id,
+         nxflow_stats.duration_sec, nxflow_stats.duration_nsec,
+         nxflow_stats.priority, nxflow_stats.idle_timeout,
+         nxflow_stats.hard_timeout, nxflow_stats.match_len,
+         nxflow_stats.idle_age, nxflow_stats.hard_age,
+         nxflow_stats.cookie, nxflow_stats.packet_count,
+         nxflow_stats.byte_count) = struct.unpack_from(
+             ofproto_v1_0.NX_FLOW_STATS_PACK_STR, buf, offset)
+        offset += ofproto_v1_0.NX_FLOW_STATS_SIZE
+
+        fields = []
+        match_len = nxflow_stats.match_len
+        match_len -= 4
+        while match_len > 0:
+            field = nx_match.MFField.parser(buf, offset)
+            offset += field.length
+            match_len -= field.length
+            fields.append(field)
+        nxflow_stats.fields = fields
+
+        actions = []
+        total_len = original_offset + nxflow_stats.length
+        match_len = nxflow_stats.match_len
+        offset += (match_len + 7) / 8 * 8 - match_len
+        while offset < total_len:
+            action = OFPAction.parser(buf, offset)
+            actions.append(action)
+            offset += action.len
+        nxflow_stats.actions = actions
+
+        return nxflow_stats
+
+
 class OFPQueuePropHeader(object):
     _QUEUE_PROPERTIES = {}
 
@@ -1769,9 +1823,101 @@ class OFPQueueStatsReply(OFPStatsReply):
 @_set_stats_type(ofproto_v1_0.OFPST_VENDOR, OFPVendorStats)
 @_set_msg_type(ofproto_v1_0.OFPT_STATS_REPLY)
 class OFPVendorStatsReply(OFPStatsReply):
+    _STATS_VENDORS = {}
+
+    @staticmethod
+    def register_stats_vendor(vendor):
+        def _register_stats_vendor(cls):
+            cls.cls_vendor = vendor
+            OFPVendorStatsReply._STATS_VENDORS[cls.cls_vendor] = cls
+            return cls
+        return _register_stats_vendor
+
     def __init__(self, datapath):
         super(OFPVendorStatsReply, self).__init__(datapath)
 
+    @classmethod
+    def parser_stats(cls, datapath, version, msg_type, msg_len, xid,
+                     buf):
+        (type_,) = struct.unpack_from(
+            ofproto_v1_0.OFP_VENDOR_STATS_MSG_PACK_STR, buffer(buf),
+            ofproto_v1_0.OFP_STATS_MSG_SIZE)
+
+        cls_ = cls._STATS_VENDORS.get(type_)
+
+        if cls_ is None:
+            msg = MsgBase.parser.__func__(
+                cls, datapath, version, msg_type, msg_len, xid, buf)
+            body_cls = cls.cls_stats_body_cls
+            body = body_cls.parser(buf,
+                                   ofproto_v1_0.OFP_STATS_MSG_SIZE)
+            msg.body = body
+            return msg
+
+        return cls_.parser(
+            datapath, version, msg_type, msg_len, xid, buf,
+            ofproto_v1_0.OFP_VENDOR_STATS_MSG_SIZE)
+
+
+@OFPVendorStatsReply.register_stats_vendor(ofproto_v1_0.NX_VENDOR_ID)
+class NXStatsReply(OFPStatsReply):
+    _NX_STATS_TYPES = {}
+
+    @staticmethod
+    def register_nx_stats_type(body_single_struct=False):
+        def _register_nx_stats_type(cls):
+            assert cls.cls_stats_type is not None
+            assert cls.cls_stats_type not in \
+                NXStatsReply._NX_STATS_TYPES
+            assert cls.cls_stats_body_cls is not None
+            cls.cls_body_single_struct = body_single_struct
+            NXStatsReply._NX_STATS_TYPES[cls.cls_stats_type] = cls
+            return cls
+        return _register_nx_stats_type
+
+    @classmethod
+    def parser_stats_body(cls, buf, msg_len, offset):
+        body_cls = cls.cls_stats_body_cls
+        body = []
+        while offset < msg_len:
+            entry = body_cls.parser(buf, offset)
+            body.append(entry)
+            offset += entry.length
+
+        if cls.cls_body_single_struct:
+            return body[0]
+        return body
+
+    @classmethod
+    def parser_stats(cls, datapath, version, msg_type, msg_len, xid,
+                     buf, offset):
+        msg = MsgBase.parser.__func__(
+            cls, datapath, version, msg_type, msg_len, xid, buf)
+        msg.body = msg.parser_stats_body(msg.buf, msg.msg_len, offset)
+
+        return msg
+
+    @classmethod
+    def parser(cls, datapath, version, msg_type, msg_len, xid, buf,
+               offset):
+        (type_,) = struct.unpack_from(
+            ofproto_v1_0.NX_STATS_MSG_PACK_STR, buffer(buf), offset)
+        offset += ofproto_v1_0.NX_STATS_MSG0_SIZE
+
+        cls_ = cls._NX_STATS_TYPES.get(type_)
+
+        msg = cls_.parser_stats(
+            datapath, version, msg_type, msg_len, xid, buf, offset)
+
+        return msg
+
+
+@NXStatsReply.register_nx_stats_type()
+@_set_stats_type(ofproto_v1_0.NXST_FLOW, NXFlowStats)
+class NXFlowStatsReply(NXStatsReply):
+    def __init__(self, datapath):
+        super(NXFlowStatsReply, self).__init__(datapath)
+
 
 #
 # controller-to-switch message
@@ -2015,13 +2161,48 @@ class OFPQueueStatsRequest(OFPStatsRequest):
 @_set_stats_type(ofproto_v1_0.OFPST_VENDOR, OFPVendorStats)
 @_set_msg_type(ofproto_v1_0.OFPT_STATS_REQUEST)
 class OFPVendorStatsRequest(OFPStatsRequest):
-    def __init__(self, datapath, flags, vendor, specific_data):
+    def __init__(self, datapath, flags, vendor, specific_data=None):
         super(OFPVendorStatsRequest, self).__init__(datapath, flags)
         self.vendor = vendor
         self.specific_data = specific_data
 
+    def _serialize_vendor_stats(self):
+        self.buf += self.specific_data
+
     def _serialize_stats_body(self):
         msg_pack_into(ofproto_v1_0.OFP_VENDOR_STATS_MSG_PACK_STR,
                       self.buf, ofproto_v1_0.OFP_STATS_MSG_SIZE,
                       self.vendor)
-        self.buf += self.specific_data
+        self._serialize_vendor_stats()
+
+
+class NXStatsRequest(OFPVendorStatsRequest):
+    def __init__(self, datapath, flags, subtype):
+        super(NXStatsRequest, self).__init__(datapath, flags,
+                                             ofproto_v1_0.NX_VENDOR_ID)
+        self.subtype = subtype
+
+    def _serialize_vendor_stats_body(self):
+        pass
+
+    def _serialize_vendor_stats(self):
+        msg_pack_into(ofproto_v1_0.NX_STATS_MSG_PACK_STR, self.buf,
+                      ofproto_v1_0.OFP_VENDOR_STATS_MSG_SIZE,
+                      self.subtype)
+        self._serialize_vendor_stats_body()
+
+
+class NXFlowStatsRequest(NXStatsRequest):
+    def __init__(self, datapath, flags, out_port, match_len,
+                 table_id):
+        super(NXFlowStatsRequest, self).__init__(datapath, flags,
+                                                 ofproto_v1_0.NXST_FLOW)
+        self.out_port = out_port
+        self.match_len = match_len
+        self.table_id = table_id
+
+    def _serialize_vendor_stats_body(self):
+        msg_pack_into(
+            ofproto_v1_0.NX_FLOW_STATS_REQUEST_PACK_STR,
+            self.buf, ofproto_v1_0.NX_STATS_MSG_SIZE, self.out_port,
+            self.match_len, self.table_id)
-- 
1.7.11.1

