mirror of
https://github.com/faucetsdn/ryu.git
synced 2026-05-09 06:16:10 +02:00
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:
parent
06e50ce710
commit
40e979b92b
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user