diff options
author | Yuichi Ito <ito.yuichi0@gmail.com> | 2013-09-17 13:37:40 +0900 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2013-09-24 02:09:14 +0900 |
commit | dc26a90bbe3288ef88c348889394afdc1a7b4eff (patch) | |
tree | 57ebd8f32a50bc70f9ca2fab0ff29a314a55251a | |
parent | d174c98421986e0a39c1f1007ff2bd915bef110c (diff) |
packet lib: ipv6: support fragment header
Signed-off-by: itoyuichi <ito.yuichi0@gmail.com>
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
-rw-r--r-- | ryu/lib/packet/ipv6.py | 52 | ||||
-rw-r--r-- | ryu/tests/unit/packet/test_ipv6.py | 89 |
2 files changed, 141 insertions, 0 deletions
diff --git a/ryu/lib/packet/ipv6.py b/ryu/lib/packet/ipv6.py index 747ec407..ff50cdfc 100644 --- a/ryu/lib/packet/ipv6.py +++ b/ryu/lib/packet/ipv6.py @@ -324,3 +324,55 @@ class option(stringify.StringifyMixin): def __len__(self): return self._MIN_LEN + self.len_ + + +@ipv6.register_header_type(inet.IPPROTO_FRAGMENT) +class fragment(header): + """IPv6 (RFC 2460) fragment header encoder/decoder class. + + This is used with ryu.lib.packet.ipv6.ipv6. + + An instance has the following attributes at least. + Most of them are same to the on-wire counterparts but in host byte order. + __init__ takes the corresponding args in this order. + + .. tabularcolumns:: |l|L| + + ============== ======================================= + Attribute Description + ============== ======================================= + offset offset, in 8-octet units, relative to + the start of the fragmentable part of + the original packet. + more 1 means more fragments follow; + 0 means last fragment. + id\_ packet identification value. + ============== ======================================= + """ + TYPE = inet.IPPROTO_FRAGMENT + + _PACK_STR = '!BxHI' + _MIN_LEN = struct.calcsize(_PACK_STR) + + def __init__(self, offset, more, id_): + super(fragment, self).__init__() + self.offset = offset + self.more = more + self.id_ = id_ + + @classmethod + def parser(cls, buf): + (nxt, off_m, id_) = struct.unpack_from(cls._PACK_STR, buf) + offset = off_m >> 3 + more = off_m & 0x1 + ret = cls(offset, more, id_) + ret.set_nxt(nxt) + return ret + + def serialize(self): + off_m = (self.offset << 3 | self.more) + buf = struct.pack(self._PACK_STR, self.nxt, off_m, self.id_) + return buf + + def __len__(self): + return self._MIN_LEN diff --git a/ryu/tests/unit/packet/test_ipv6.py b/ryu/tests/unit/packet/test_ipv6.py index 5a71c567..42c55232 100644 --- a/ryu/tests/unit/packet/test_ipv6.py +++ b/ryu/tests/unit/packet/test_ipv6.py @@ -111,6 +111,27 @@ class Test_ipv6(unittest.TestCase): addrconv.ipv6.text_to_bin(self.dst)) self.buf += self.dst_opts.serialize() + def setUp_with_fragment(self): + self.fragment_offset = 50 + self.fragment_more = 1 + self.fragment_id = 123 + self.fragment = ipv6.fragment( + self.fragment_offset, self.fragment_more, self.fragment_id) + self.ext_hdrs = [self.fragment] + self.payload_length += len(self.fragment) + 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.fragment.nxt = self.nxt + self.nxt = self.fragment.TYPE + 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)) + self.buf += self.fragment.serialize() + def tearDown(self): pass @@ -133,6 +154,10 @@ class Test_ipv6(unittest.TestCase): self.setUp_with_dst_opts() self.test_init() + def test_init_with_fragment(self): + self.setUp_with_fragment() + self.test_init() + def test_parser(self): _res = self.ip.parser(str(self.buf)) if type(_res) is tuple: @@ -158,6 +183,10 @@ class Test_ipv6(unittest.TestCase): self.setUp_with_dst_opts() self.test_parser() + def test_parser_with_fragment(self): + self.setUp_with_fragment() + self.test_parser() + def test_serialize(self): data = bytearray() prev = None @@ -192,6 +221,16 @@ class Test_ipv6(unittest.TestCase): dst_opts = ipv6.dst_opts.parser(str(buf[ipv6.ipv6._MIN_LEN:])) eq_(repr(self.dst_opts), repr(dst_opts)) + def test_serialize_with_fragment(self): + self.setUp_with_fragment() + self.test_serialize() + + data = bytearray() + prev = None + buf = self.ip.serialize(data, prev) + fragment = ipv6.fragment.parser(str(buf[ipv6.ipv6._MIN_LEN:])) + eq_(repr(self.fragment), repr(fragment)) + def test_to_string(self): ipv6_values = {'version': self.version, 'traffic_class': self.traffic_class, @@ -218,6 +257,10 @@ class Test_ipv6(unittest.TestCase): self.setUp_with_dst_opts() self.test_to_string() + def test_to_string_with_fragment(self): + self.setUp_with_fragment() + self.test_to_string() + def test_len(self): eq_(len(self.ip), 40) @@ -229,6 +272,10 @@ class Test_ipv6(unittest.TestCase): self.setUp_with_dst_opts() eq_(len(self.ip), 40 + len(self.dst_opts)) + def test_len_with_fragment(self): + self.setUp_with_fragment() + eq_(len(self.ip), 40 + len(self.fragment)) + class Test_hop_opts(unittest.TestCase): @@ -444,3 +491,45 @@ class Test_option_padN(Test_option): res = struct.unpack_from(self.form, buf) eq_(self.type_, res[0]) eq_(self.len_, res[1]) + + +class Test_fragment(unittest.TestCase): + + def setUp(self): + self.nxt = 44 + self.offset = 50 + self.more = 1 + self.id_ = 123 + self.fragment = ipv6.fragment(self.offset, self.more, self.id_) + self.fragment.set_nxt(self.nxt) + + self.off_m = (self.offset << 3 | self.more) + self.form = '!BxHI' + self.buf = struct.pack(self.form, self.nxt, self.off_m, self.id_) + + def test_init(self): + eq_(self.nxt, self.fragment.nxt) + eq_(self.offset, self.fragment.offset) + eq_(self.more, self.fragment.more) + eq_(self.id_, self.fragment.id_) + + def test_parser(self): + _res = ipv6.fragment.parser(self.buf) + if type(_res) is tuple: + res = _res[0] + else: + res = _res + eq_(self.nxt, res.nxt) + eq_(self.offset, res.offset) + eq_(self.more, res.more) + eq_(self.id_, res.id_) + + def test_serialize(self): + buf = self.fragment.serialize() + res = struct.unpack_from(self.form, str(buf)) + eq_(self.nxt, res[0]) + eq_(self.off_m, res[1]) + eq_(self.id_, res[2]) + + def test_len(self): + eq_(8, len(self.fragment)) |