packet lib: ipv6: prepare to support extension headers

Signed-off-by: itoyuichi <ito.yuichi0@gmail.com>
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
This commit is contained in:
Yuichi Ito 2013-09-17 13:36:02 +09:00 committed by FUJITA Tomonori
parent 06e50ce710
commit 40e979b92b
2 changed files with 151 additions and 21 deletions

View File

@ -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

View File

@ -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)