Signed-off-by: itoyuichi <[email protected]>
---
 ryu/lib/packet/ipv6.py             |   83 +++++++++++++++++++++++++++++++--
 ryu/tests/unit/packet/test_ipv6.py |   89 +++++++++++++++++++++++++++++-------
 2 files changed, 151 insertions(+), 21 deletions(-)

diff --git a/ryu/lib/packet/ipv6.py b/ryu/lib/packet/ipv6.py
index 325f834..6bcc608 100644
--- a/ryu/lib/packet/ipv6.py
+++ b/ryu/lib/packet/ipv6.py
@@ -13,6 +13,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.

+import abc
 import struct
 import socket
 from . import packet_base
@@ -21,6 +22,7 @@ from . import icmpv6
 from . import tcp
 from ryu.ofproto import inet
 from ryu.lib import addrconv
+from ryu.lib import stringify


 IPV6_ADDRESS_PACK_STR = '!16s'
@@ -51,14 +53,23 @@ class ipv6(packet_base.PacketBase):
     hop_limit      Hop Limit
     src            Source Address                           'ff02::1'
     dst            Destination Address                      '::'
+    ext_hdrs       Extension Headers
     ============== ======================================== ==================
     """

     _PACK_STR = '!IHBB16s16s'
     _MIN_LEN = struct.calcsize(_PACK_STR)
+    _IPV6_EXT_HEADER_TYPE = {}
+
+    @staticmethod
+    def register_header_type(type_):
+        def _register_header_type(cls):
+            ipv6._IPV6_EXT_HEADER_TYPE[type_] = cls
+            return cls
+        return _register_header_type

     def __init__(self, version, traffic_class, flow_label, payload_length,
-                 nxt, hop_limit, src, dst):
+                 nxt, hop_limit, src, dst, ext_hdrs=[]):
         super(ipv6, self).__init__()
         self.version = version
         self.traffic_class = traffic_class
@@ -68,6 +79,19 @@ class ipv6(packet_base.PacketBase):
         self.hop_limit = hop_limit
         self.src = src
         self.dst = dst
+        if ext_hdrs:
+            assert isinstance(ext_hdrs, list)
+            last_hdr = None
+            for ext_hdr in ext_hdrs:
+                assert isinstance(ext_hdr, header)
+                if last_hdr:
+                    ext_hdr.set_nxt(last_hdr.nxt)
+                    last_hdr.nxt = ext_hdr.TYPE
+                else:
+                    ext_hdr.set_nxt(self.nxt)
+                    self.nxt = ext_hdr.TYPE
+                last_hdr = ext_hdr
+        self.ext_hdrs = ext_hdrs

     @classmethod
     def parser(cls, buf):
@@ -77,11 +101,24 @@ class ipv6(packet_base.PacketBase):
         traffic_class = (v_tc_flow >> 20) & 0xff
         flow_label = v_tc_flow & 0xfffff
         hop_limit = hlim
+        offset = cls._MIN_LEN
+        last = nxt
+        ext_hdrs = []
+        while True:
+            cls_ = cls._IPV6_EXT_HEADER_TYPE.get(last)
+            if not cls_:
+                break
+            hdr = cls_.parser(buf[offset:])
+            ext_hdrs.append(hdr)
+            offset += len(hdr)
+            last = hdr.nxt
+        # call ipv6.__init__() using 'nxt' of the last extension
+        # header that points the next protocol.
         msg = cls(version, traffic_class, flow_label, payload_length,
-                  nxt, hop_limit, addrconv.ipv6.bin_to_text(src),
-                  addrconv.ipv6.bin_to_text(dst))
-        return (msg, ipv6.get_packet_type(nxt),
-                buf[cls._MIN_LEN:cls._MIN_LEN+payload_length])
+                  last, hop_limit, addrconv.ipv6.bin_to_text(src),
+                  addrconv.ipv6.bin_to_text(dst), ext_hdrs)
+        return (msg, ipv6.get_packet_type(last),
+                buf[offset:offset+payload_length])

     def serialize(self, payload, prev):
         hdr = bytearray(40)
@@ -91,7 +128,43 @@ class ipv6(packet_base.PacketBase):
                          self.payload_length, self.nxt, self.hop_limit,
                          addrconv.ipv6.text_to_bin(self.src),
                          addrconv.ipv6.text_to_bin(self.dst))
+        if self.ext_hdrs:
+            for ext_hdr in self.ext_hdrs:
+                hdr.extend(ext_hdr.serialize())
         return hdr

+    def __len__(self):
+        ext_hdrs_len = 0
+        for ext_hdr in self.ext_hdrs:
+            ext_hdrs_len += len(ext_hdr)
+        return self._MIN_LEN + ext_hdrs_len
+
 ipv6.register_packet_type(icmpv6.icmpv6, inet.IPPROTO_ICMPV6)
 ipv6.register_packet_type(tcp.tcp, inet.IPPROTO_TCP)
+
+
+class header(stringify.StringifyMixin):
+    """extension header abstract class."""
+
+    __metaclass__ = abc.ABCMeta
+
+    def __init__(self):
+        self.nxt = None
+
+    def set_nxt(self, nxt):
+        self.nxt = nxt
+
+    @classmethod
+    @abc.abstractmethod
+    def parser(cls, buf):
+        pass
+
+    @abc.abstractmethod
+    def serialize(self):
+        pass
+
+    @abc.abstractmethod
+    def __len__(self):
+        pass
+
+# TODO: implement a class for routing header
diff --git a/ryu/tests/unit/packet/test_ipv6.py 
b/ryu/tests/unit/packet/test_ipv6.py
index 5454fbf..e4c0e5e 100644
--- a/ryu/tests/unit/packet/test_ipv6.py
+++ b/ryu/tests/unit/packet/test_ipv6.py
@@ -17,9 +17,11 @@
 import unittest
 import logging
 import inspect
+import struct

 from nose.tools import *
 from nose.plugins.skip import Skip, SkipTest
+from ryu.lib import addrconv
 from ryu.lib import ip
 from ryu.lib.packet import ipv6

@@ -29,24 +31,75 @@ LOG = logging.getLogger(__name__)

 class Test_ipv6(unittest.TestCase):

-    version = 6
-    traffic_class = 0
-    flow_label = 0
-    payload_length = 817
-    nxt = 6
-    hop_limit = 128
-    src = ip.ipv6_to_bin('2002:4637:d5d3::4637:d5d3')
-    dst = ip.ipv6_to_bin('2001:4860:0:2001::68')
-
-    ip = ipv6.ipv6(version, traffic_class, flow_label, payload_length,
-                   nxt, hop_limit, src, dst)
-
     def setUp(self):
-        pass
+        self.version = 6
+        self.traffic_class = 0
+        self.flow_label = 0
+        self.payload_length = 817
+        self.nxt = 6
+        self.hop_limit = 128
+        self.src = '2002:4637:d5d3::4637:d5d3'
+        self.dst = '2001:4860:0:2001::68'
+        self.ext_hdrs = []
+        self.ip = ipv6.ipv6(
+            self.version, self.traffic_class, self.flow_label,
+            self.payload_length, self.nxt, self.hop_limit, self.src,
+            self.dst, self.ext_hdrs)
+
+        self.v_tc_flow = (
+            self.version << 28 | self.traffic_class << 20 |
+            self.flow_label << 12)
+        self.buf = struct.pack(
+            ipv6.ipv6._PACK_STR, self.v_tc_flow,
+            self.payload_length, self.nxt, self.hop_limit,
+            addrconv.ipv6.text_to_bin(self.src),
+            addrconv.ipv6.text_to_bin(self.dst))

     def tearDown(self):
         pass

+    def test_init(self):
+        eq_(self.version, self.ip.version)
+        eq_(self.traffic_class, self.ip.traffic_class)
+        eq_(self.flow_label, self.ip.flow_label)
+        eq_(self.payload_length, self.ip.payload_length)
+        eq_(self.nxt, self.ip.nxt)
+        eq_(self.hop_limit, self.ip.hop_limit)
+        eq_(self.src, self.ip.src)
+        eq_(self.dst, self.ip.dst)
+        eq_(str(self.ext_hdrs), str(self.ip.ext_hdrs))
+
+    def test_parser(self):
+        _res = self.ip.parser(str(self.buf))
+        if type(_res) is tuple:
+            res = _res[0]
+        else:
+            res = _res
+
+        eq_(self.version, res.version)
+        eq_(self.traffic_class, res.traffic_class)
+        eq_(self.flow_label, res.flow_label)
+        eq_(self.payload_length, res.payload_length)
+        eq_(self.nxt, res.nxt)
+        eq_(self.hop_limit, res.hop_limit)
+        eq_(self.src, res.src)
+        eq_(self.dst, res.dst)
+        eq_(str(self.ext_hdrs), str(res.ext_hdrs))
+
+    def test_serialize(self):
+        data = bytearray()
+        prev = None
+        buf = self.ip.serialize(data, prev)
+
+        res = struct.unpack_from(ipv6.ipv6._PACK_STR, str(buf))
+
+        eq_(self.v_tc_flow, res[0])
+        eq_(self.payload_length, res[1])
+        eq_(self.nxt, res[2])
+        eq_(self.hop_limit, res[3])
+        eq_(self.src, addrconv.ipv6.bin_to_text(res[4]))
+        eq_(self.dst, addrconv.ipv6.bin_to_text(res[5]))
+
     def test_to_string(self):
         ipv6_values = {'version': self.version,
                        'traffic_class': self.traffic_class,
@@ -54,12 +107,16 @@ class Test_ipv6(unittest.TestCase):
                        'payload_length': self.payload_length,
                        'nxt': self.nxt,
                        'hop_limit': self.hop_limit,
-                       'src': self.src,
-                       'dst': self.dst}
-        _ipv6_str = ','.join(['%s=%s' % (k, repr(ipv6_values[k]))
+                       'src': repr(self.src),
+                       'dst': repr(self.dst),
+                       'ext_hdrs': self.ext_hdrs}
+        _ipv6_str = ','.join(['%s=%s' % (k, ipv6_values[k])
                               for k, v in inspect.getmembers(self.ip)
                               if k in ipv6_values])
         ipv6_str = '%s(%s)' % (ipv6.ipv6.__name__, _ipv6_str)

         eq_(str(self.ip), ipv6_str)
         eq_(repr(self.ip), ipv6_str)
+
+    def test_len(self):
+        eq_(len(self.ip), 40)
-- 
1.7.10.4


------------------------------------------------------------------------------
LIMITED TIME SALE - Full Year of Microsoft Training For Just $49.99!
1,500+ hours of tutorials including VisualStudio 2012, Windows 8, SharePoint
2013, SQL 2012, MVC 4, more. BEST VALUE: New Multi-Library Power Pack includes
Mobile, Cloud, Java, and UX Design. Lowest price ever! Ends 9/20/13. 
http://pubads.g.doubleclick.net/gampad/clk?id=58041151&iu=/4140/ostg.clktrk
_______________________________________________
Ryu-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/ryu-devel

Reply via email to