summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorYuichi Ito <ito.yuichi0@gmail.com>2013-10-21 19:13:24 +0900
committerFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2013-10-21 22:55:31 +0900
commitb493df22cc442f376cead7c4b80b33964f820736 (patch)
treeec7f89f36b00025518834daa23d82188c6976b7a
parent97aff06df429d7067e481a52bbf1e6ee63a43a80 (diff)
packet lib: add Stream Control Transmission Protocol
Signed-off-by: Yuichi Ito <ito.yuichi0@gmail.com> Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
-rw-r--r--ryu/lib/packet/ipv4.py2
-rw-r--r--ryu/lib/packet/ipv6.py2
-rw-r--r--ryu/lib/packet/sctp.py2052
3 files changed, 2056 insertions, 0 deletions
diff --git a/ryu/lib/packet/ipv4.py b/ryu/lib/packet/ipv4.py
index 032e4254..73ad4f3b 100644
--- a/ryu/lib/packet/ipv4.py
+++ b/ryu/lib/packet/ipv4.py
@@ -21,6 +21,7 @@ from . import icmp
from . import igmp
from . import udp
from . import tcp
+from . import sctp
from ryu.ofproto import inet
from ryu.lib import addrconv
@@ -138,3 +139,4 @@ ipv4.register_packet_type(icmp.icmp, inet.IPPROTO_ICMP)
ipv4.register_packet_type(igmp.igmp, inet.IPPROTO_IGMP)
ipv4.register_packet_type(tcp.tcp, inet.IPPROTO_TCP)
ipv4.register_packet_type(udp.udp, inet.IPPROTO_UDP)
+ipv4.register_packet_type(sctp.sctp, inet.IPPROTO_SCTP)
diff --git a/ryu/lib/packet/ipv6.py b/ryu/lib/packet/ipv6.py
index 6a62abaf..e798f5e0 100644
--- a/ryu/lib/packet/ipv6.py
+++ b/ryu/lib/packet/ipv6.py
@@ -19,6 +19,7 @@ from . import packet_base
from . import icmpv6
from . import tcp
from . import udp
+from . import sctp
from ryu.ofproto import inet
from ryu.lib import addrconv
from ryu.lib import stringify
@@ -131,6 +132,7 @@ class ipv6(packet_base.PacketBase):
ipv6.register_packet_type(icmpv6.icmpv6, inet.IPPROTO_ICMPV6)
ipv6.register_packet_type(tcp.tcp, inet.IPPROTO_TCP)
ipv6.register_packet_type(udp.udp, inet.IPPROTO_UDP)
+ipv6.register_packet_type(sctp.sctp, inet.IPPROTO_SCTP)
class header(stringify.StringifyMixin):
diff --git a/ryu/lib/packet/sctp.py b/ryu/lib/packet/sctp.py
new file mode 100644
index 00000000..243c0c65
--- /dev/null
+++ b/ryu/lib/packet/sctp.py
@@ -0,0 +1,2052 @@
+# Copyright (C) 2013 Nippon Telegraph and Telephone Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import abc
+import struct
+
+from ryu.lib import addrconv
+from ryu.lib import stringify
+from ryu.lib.packet import packet_base
+
+# Chunk Types
+TYPE_DATA = 0
+TYPE_INIT = 1
+TYPE_INIT_ACK = 2
+TYPE_SACK = 3
+TYPE_HEARTBEAT = 4
+TYPE_HEARTBEAT_ACK = 5
+TYPE_ABORT = 6
+TYPE_SHUTDOWN = 7
+TYPE_SHUTDOWN_ACK = 8
+TYPE_ERROR = 9
+TYPE_COOKIE_ECHO = 10
+TYPE_COOKIE_ACK = 11
+TYPE_ECN_ECHO = 12
+TYPE_CWR = 13
+TYPE_SHUTDOWN_COMPLETE = 14
+
+# Cause Code
+CCODE_INVALID_STREAM_ID = 1
+CCODE_MISSING_PARAM = 2
+CCODE_STALE_COOKIE = 3
+CCODE_OUT_OF_RESOURCE = 4
+CCODE_UNRESOLVABLE_ADDR = 5
+CCODE_UNRECOGNIZED_CHUNK = 6
+CCODE_INVALID_PARAM = 7
+CCODE_UNRECOGNIZED_PARAM = 8
+CCODE_NO_USERDATA = 9
+CCODE_COOKIE_WHILE_SHUTDOWN = 10
+CCODE_RESTART_WITH_NEW_ADDR = 11
+CCODE_USER_INITIATED_ABORT = 12
+CCODE_PROTOCOL_VIOLATION = 13
+
+# Chunk Parameter Types
+PTYPE_HEARTBEAT = 1
+PTYPE_IPV4 = 5
+PTYPE_IPV6 = 6
+PTYPE_STATE_COOKIE = 7
+PTYPE_UNRECOGNIZED_PARAM = 8
+PTYPE_COOKIE_PRESERVE = 9
+PTYPE_HOST_ADDR = 11
+PTYPE_SUPPORTED_ADDR = 12
+PTYPE_ECN = 32768
+
+
+class sctp(packet_base.PacketBase):
+ """Stream Control Transmission Protocol (SCTP)
+ header encoder/decoder class (RFC 4960).
+
+ 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 correspondig args in this order.
+
+ .. tabularcolumns:: |l|p{30em}|l|
+
+ ============== =====================================================
+ Attribute Description
+ ============== =====================================================
+ src_port Source Port
+ dst_port Destination Port
+ vtag Verification Tag
+ csum Checksum
+ chunks a list of derived classes of ryu.lib.packet.sctp.chunk.
+ ============== =====================================================
+ """
+
+ _PACK_STR = '!HHII'
+ _MIN_LEN = struct.calcsize(_PACK_STR)
+ _SCTP_CHUNK_TYPE = {}
+ _class_prefixes = ['chunk_']
+
+ @staticmethod
+ def register_chunk_type(*args):
+ def _register_chunk_type(cls):
+ sctp._SCTP_CHUNK_TYPE[cls.chunk_type()] = cls
+ return cls
+ return _register_chunk_type(args[0])
+
+ def __init__(self, src_port, dst_port, vtag, csum, chunks=None):
+ super(sctp, self).__init__()
+ self.src_port = src_port
+ self.dst_port = dst_port
+ self.vtag = vtag
+ self.csum = csum
+ chunks = chunks or []
+ assert isinstance(chunks, list)
+ for one in chunks:
+ assert isinstance(one, chunk)
+ self.chunks = chunks
+
+ @classmethod
+ def parser(cls, buf):
+ (src_port, dst_port, vtag, csum) = struct.unpack_from(
+ cls._PACK_STR, buf)
+ chunks = []
+ offset = cls._MIN_LEN
+ while offset < len(buf):
+ (type_, ) = struct.unpack_from('!B', buf, offset)
+ cls_ = cls._SCTP_CHUNK_TYPE.get(type_)
+ if not cls_:
+ break
+ ins = cls_.parser(buf[offset:])
+ chunks.append(ins)
+ offset += len(ins)
+ msg = cls(src_port, dst_port, vtag, csum, chunks)
+ return msg, None, buf[offset:]
+
+ def serialize(self, payload, prev):
+ buf = bytearray(struct.pack(
+ self._PACK_STR, self.src_port, self.dst_port, self.vtag,
+ self.csum))
+ if self.chunks:
+ for one in self.chunks:
+ buf.extend(one.serialize())
+ if self.csum == 0:
+ self.csum = self._checksum(buf)
+ struct.pack_into('!I', buf, 8, self.csum)
+ return str(buf)
+
+ def _checksum(self, data):
+ # from RFC 3309
+ crc_c = [
+ 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4,
+ 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB,
+ 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B,
+ 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24,
+ 0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B,
+ 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384,
+ 0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54,
+ 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B,
+ 0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A,
+ 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35,
+ 0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5,
+ 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA,
+ 0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45,
+ 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A,
+ 0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A,
+ 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595,
+ 0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48,
+ 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957,
+ 0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687,
+ 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198,
+ 0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927,
+ 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38,
+ 0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8,
+ 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7,
+ 0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096,
+ 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789,
+ 0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859,
+ 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46,
+ 0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9,
+ 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6,
+ 0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36,
+ 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829,
+ 0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C,
+ 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93,
+ 0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043,
+ 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C,
+ 0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3,
+ 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC,
+ 0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C,
+ 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033,
+ 0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652,
+ 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D,
+ 0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D,
+ 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982,
+ 0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D,
+ 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622,
+ 0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2,
+ 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED,
+ 0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530,
+ 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F,
+ 0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF,
+ 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0,
+ 0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F,
+ 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540,
+ 0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90,
+ 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F,
+ 0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE,
+ 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1,
+ 0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321,
+ 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E,
+ 0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81,
+ 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E,
+ 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E,
+ 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351,
+ ]
+
+ crc32 = 0xffffffff
+ for c in str(data):
+ crc32 = (crc32 >> 8) ^ crc_c[(crc32 ^ (ord(c))) & 0xFF]
+ crc32 = (~crc32) & 0xffffffff
+ return struct.unpack(">I", struct.pack("<I", crc32))[0]
+
+
+#=======================================================================
+#
+# Chunk Types
+#
+#=======================================================================
+class chunk(stringify.StringifyMixin):
+
+ __metaclass__ = abc.ABCMeta
+ _PACK_STR = '!BBH'
+ _MIN_LEN = struct.calcsize(_PACK_STR)
+
+ @classmethod
+ @abc.abstractproperty
+ def chunk_type(cls):
+ pass
+
+ @abc.abstractmethod
+ def __init__(self, type_, length):
+ self._type = type_
+ self.length = length
+
+ @classmethod
+ @abc.abstractmethod
+ def parser(cls, buf):
+ pass
+
+ def __len__(self):
+ return self.length
+
+
+class chunk_init_base(chunk):
+
+ __metaclass__ = abc.ABCMeta
+ _PACK_STR = '!BBHIIHHI'
+ _MIN_LEN = struct.calcsize(_PACK_STR)
+
+ def __init__(self, flags, length, init_tag, a_rwnd, os, mis, i_tsn,
+ params=None):
+ super(chunk_init_base, self).__init__(self.chunk_type(), length)
+ self.flags = flags
+ self.init_tag = init_tag
+ self.a_rwnd = a_rwnd
+ self.os = os
+ self.mis = mis
+ self.i_tsn = i_tsn
+ params = params or []
+ assert isinstance(params, list)
+ for one in params:
+ assert isinstance(one, param)
+ self.params = params
+
+ @classmethod
+ def parser_base(cls, buf, recog):
+ (_, flags, length, init_tag, a_rwnd, os, mis, i_tsn
+ ) = struct.unpack_from(cls._PACK_STR, buf)
+ params = []
+ offset = cls._MIN_LEN
+ while offset < length:
+ (ptype, ) = struct.unpack_from('!H', buf, offset)
+ cls_ = recog.get(ptype)
+ if not cls_:
+ break
+ ins = cls_.parser(buf[offset:])
+ params.append(ins)
+ offset += len(ins)
+ msg = cls(flags, length, init_tag, a_rwnd, os, mis, i_tsn, params)
+ return msg
+
+ def serialize(self):
+ buf = bytearray(struct.pack(
+ self._PACK_STR, self.chunk_type(), self.flags,
+ self.length, self.init_tag, self.a_rwnd, self.os, self.mis,
+ self.i_tsn))
+ for one in self.params:
+ buf.extend(one.serialize())
+ return str(buf)
+
+
+class chunk_heartbeat_base(chunk):
+
+ __metaclass__ = abc.ABCMeta
+
+ def __init__(self, flags, length, info):
+ super(chunk_heartbeat_base, self).__init__(
+ self.chunk_type(), length)
+ self.flags = flags
+ assert isinstance(info, param)
+ self.info = info
+
+ @classmethod
+ def parser_base(cls, buf, recog):
+ (_, flags, length) = struct.unpack_from(cls._PACK_STR, buf)
+ (ptype, ) = struct.unpack_from('!H', buf, cls._MIN_LEN)
+ cls_ = recog.get(ptype)
+ info = cls_.parser(buf[cls._MIN_LEN:])
+ msg = cls(flags, length, info)
+ return msg
+
+ def serialize(self):
+ buf = bytearray(struct.pack(
+ self._PACK_STR, self.chunk_type(), self.flags,
+ self.length))
+ buf.extend(self.info.serialize())
+ return str(buf)
+
+
+class chunk_ack_base(chunk):
+
+ __metaclass__ = abc.ABCMeta
+
+ def __init__(self, flags, length):
+ super(chunk_ack_base, self).__init__(self.chunk_type(), length)
+ self.flags = flags
+
+ @classmethod
+ def parser(cls, buf):
+ (_, flags, length) = struct.unpack_from(cls._PACK_STR, buf)
+ return cls(flags, length)
+
+ def serialize(self):
+ buf = struct.pack(
+ self._PACK_STR, self.chunk_type(), self.flags,
+ self.length)
+ return buf
+
+
+class chunk_ecn_base(chunk):
+
+ __metaclass__ = abc.ABCMeta
+ _PACK_STR = '!BBHI'
+ _MIN_LEN = struct.calcsize(_PACK_STR)
+
+ def __init__(self, flags, length, low_tsn):
+ super(chunk_ecn_base, self).__init__(self.chunk_type(), length)
+ self.flags = flags
+ self.low_tsn = low_tsn
+
+ @classmethod
+ def parser(cls, buf):
+ (_, flags, length, low_tsn) = struct.unpack_from(cls._PACK_STR, buf)
+ return cls(flags, length, low_tsn)
+
+ def serialize(self):
+ buf = struct.pack(
+ self._PACK_STR, self.chunk_type(), self.flags, self.length,
+ self.low_tsn)
+ return buf
+
+
+@sctp.register_chunk_type
+class chunk_data(chunk):
+ """Stream Control Transmission Protocol (SCTP)
+ sub encoder/decoder class for Payload Data (DATA) chunk (RFC 4960).
+
+ This is used with ryu.lib.packet.sctp.sctp.
+
+ 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 correspondig args in this order.
+
+ .. tabularcolumns:: |l|p{30em}|l|
+
+ ============== =====================================================
+ Attribute Description
+ ============== =====================================================
+ unordered if set to '1', the receiver ignores the sequence number.
+ begin if set to '1', this chunk is the first fragment.
+ end if set to '1', this chunk is the last fragment.
+ length length of this chunk containing this header.
+ tsn Transmission Sequence Number.
+ sid stream id.
+ seq the sequence number.
+ payload_id application specified protocol id. '0' means that
+ no application id is identified.
+ payload_data user data.
+ ============== =====================================================
+ """
+
+ _PACK_STR = '!BBHIHHI'
+ _MIN_LEN = struct.calcsize(_PACK_STR)
+
+ @classmethod
+ def chunk_type(cls):
+ return TYPE_DATA
+
+ def __init__(self, unordered, begin, end, length, tsn, sid, seq,
+ payload_id, payload_data):
+ assert (1 == unordered | 1)
+ assert (1 == begin | 1)
+ assert (1 == end | 1)
+ super(chunk_data, self).__init__(self.chunk_type(), length)
+ self.unordered = unordered
+ self.begin = begin
+ self.end = end
+ self.tsn = tsn
+ self.sid = sid
+ self.seq = seq
+ self.payload_id = payload_id
+ self.payload_data = payload_data
+
+ @classmethod
+ def parser(cls, buf):
+ (_, flags, length, tsn, sid, seq, payload_id
+ ) = struct.unpack_from(cls._PACK_STR, buf)
+ unordered = (flags >> 2) & 1
+ begin = (flags >> 1) & 1
+ end = (flags >> 0) & 1
+ fmt = '!%ds' % (length - cls._MIN_LEN)
+ (payload_data, ) = struct.unpack_from(fmt, buf, cls._MIN_LEN)
+ return cls(unordered, begin, end, length, tsn, sid, seq,
+ payload_id, payload_data)
+
+ def serialize(self):
+ flags = (
+ (self.unordered << 2) |
+ (self.begin << 1) |
+ (self.end << 0))
+ buf = bytearray(struct.pack(
+ self._PACK_STR, self.chunk_type(), flags, self.length,
+ self.tsn, self.sid, self.seq, self.payload_id))
+ buf.extend(self.payload_data)
+ return str(buf)
+
+
+@sctp.register_chunk_type
+class chunk_init(chunk_init_base):
+ """Stream Control Transmission Protocol (SCTP)
+ sub encoder/decoder class for Initiation (INIT) chunk (RFC 4960).
+
+ This is used with ryu.lib.packet.sctp.sctp.
+
+ 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 correspondig args in this order.
+
+ .. tabularcolumns:: |l|p{30em}|l|
+
+ ============== =====================================================
+ Attribute Description
+ ============== =====================================================
+ flags set to '0'. this field will be ignored.
+ length length of this chunk containing this header.
+ init_tag the tag that be used as Verification Tag.
+ a_rwnd Advertised Receiver Window Credit.
+ os number of outbound streams.
+ mis number of inbound streams.
+ i_tsn Transmission Sequence Number that the sender will use.
+ params Optional/Variable-Length Parameters.
+
+ a list of derived classes of ryu.lib.packet.sctp.param.
+ ============== =====================================================
+ """
+
+ _RECOGNIZED_PARAMS = {}
+
+ @staticmethod
+ def register_param_type(*args):
+ def _register_param_type(cls):
+ chunk_init._RECOGNIZED_PARAMS[cls.param_type()] = cls
+ return cls
+ return _register_param_type(args[0])
+
+ @classmethod
+ def chunk_type(cls):
+ return TYPE_INIT
+
+ @classmethod
+ def parser(cls, buf):
+ return super(chunk_init, cls).parser_base(
+ buf, cls._RECOGNIZED_PARAMS)
+
+
+@sctp.register_chunk_type
+class chunk_init_ack(chunk_init_base):
+ """Stream Control Transmission Protocol (SCTP)
+ sub encoder/decoder class for Initiation Acknowledgement (INIT ACK)
+ chunk (RFC 4960).
+
+ This is used with ryu.lib.packet.sctp.sctp.
+
+ 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 correspondig args in this order.
+
+ .. tabularcolumns:: |l|p{30em}|l|
+
+ ============== =====================================================
+ Attribute Description
+ ============== =====================================================
+ flags set to '0'. this field will be ignored.
+ length length of this chunk containing this header.
+ init_tag the tag that be used as Verification Tag.
+ a_rwnd Advertised Receiver Window Credit.
+ os number of outbound streams.
+ mis number of inbound streams.
+ i_tsn Transmission Sequence Number that the sender will use.
+ params Optional/Variable-Length Parameters.
+
+ a list of derived classes of ryu.lib.packet.sctp.param.
+ ============== =====================================================
+ """
+
+ _RECOGNIZED_PARAMS = {}
+
+ @staticmethod
+ def register_param_type(*args):
+ def _register_param_type(cls):
+ chunk_init_ack._RECOGNIZED_PARAMS[cls.param_type()] = cls
+ return cls
+ return _register_param_type(args[0])
+
+ @classmethod
+ def chunk_type(cls):
+ return TYPE_INIT_ACK
+
+ @classmethod
+ def parser(cls, buf):
+ return super(chunk_init_ack, cls).parser_base(
+ buf, cls._RECOGNIZED_PARAMS)
+
+
+@sctp.register_chunk_type
+class chunk_sack(chunk):
+ """Stream Control Transmission Protocol (SCTP)
+ sub encoder/decoder class for Selective Acknowledgement (SACK) chunk
+ (RFC 4960).
+
+ This is used with ryu.lib.packet.sctp.sctp.
+
+ 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 correspondig args in this order.
+
+ .. tabularcolumns:: |l|p{30em}|l|
+
+ ============== =====================================================
+ Attribute Description
+ ============== =====================================================
+ flags set to '0'. this field will be ignored.
+ length length of this chunk containing this header.
+ tsn_ack TSN of the last DATA chunk received in sequence
+ before a gap.
+ a_rwnd Advertised Receiver Window Credit.
+ gapack_num number of Gap Ack blocks.
+ duptsn_num number of duplicate TSNs.
+ gapacks a list of Gap Ack blocks. one block is made of a list
+ with the start offset and the end offset from tsn_ack.
+ e.g.) gapacks = [[2, 3], [10, 12], [19, 21]]
+ duptsns a list of duplicate TSN.
+ ============== =====================================================
+ """
+
+ _PACK_STR = '!BBHIIHH'
+ _MIN_LEN = struct.calcsize(_PACK_STR)
+ _GAPACK_STR = '!HH'
+ _GAPACK_LEN = struct.calcsize(_GAPACK_STR)
+ _DUPTSN_STR = '!I'
+ _DUPTSN_LEN = struct.calcsize(_DUPTSN_STR)
+
+ @classmethod
+ def chunk_type(cls):
+ return TYPE_SACK
+
+ def __init__(self, flags, length, tsn_ack, a_rwnd, gapack_num,
+ duptsn_num, gapacks=None, duptsns=None):
+ super(chunk_sack, self).__init__(self.chunk_type(), length)
+ self.flags = flags
+ self.tsn_ack = tsn_ack
+ self.a_rwnd = a_rwnd
+ self.gapack_num = gapack_num
+ self.duptsn_num = duptsn_num
+ gapacks = gapacks or []
+ assert isinstance(gapacks, list)
+ for one in gapacks:
+ assert isinstance(one, list)
+ assert 2 == len(one)
+ self.gapacks = gapacks
+ duptsns = duptsns or []
+ assert isinstance(duptsns, list)
+ self.duptsns = duptsns
+
+ @classmethod
+ def parser(cls, buf):
+ (_, flags, length, tsn_ack, a_rwnd, gapack_num, duptsn_num
+ ) = struct.unpack_from(cls._PACK_STR, buf)
+ gapacks = []
+ offset = cls._MIN_LEN
+ for _ in range(gapack_num):
+ (gapack_start, gapack_end) = struct.unpack_from(
+ cls._GAPACK_STR, buf, offset)
+ gapacks.append([gapack_start, gapack_end])
+ offset += cls._GAPACK_LEN
+ duptsns = []
+ for _ in range(duptsn_num):
+ (duptsn, ) = struct.unpack_from(cls._DUPTSN_STR, buf, offset)
+ duptsns.append(duptsn)
+ offset += cls._DUPTSN_LEN
+ return cls(flags, length, tsn_ack, a_rwnd, gapack_num, duptsn_num,
+ gapacks, duptsns)
+
+ def serialize(self):
+ buf = bytearray(struct.pack(
+ self._PACK_STR, self.chunk_type(), self.flags,
+ self.length, self.tsn_ack, self.a_rwnd, self.gapack_num,
+ self.duptsn_num))
+ for one in self.gapacks:
+ buf.extend(struct.pack(chunk_sack._GAPACK_STR, one[0], one[1]))
+ for one in self.duptsns:
+ buf.extend(struct.pack(chunk_sack._DUPTSN_STR, one))
+ return str(buf)
+
+
+@sctp.register_chunk_type
+class chunk_heartbeat(chunk_heartbeat_base):
+ """Stream Control Transmission Protocol (SCTP)
+ sub encoder/decoder class for Heartbeat Request (HEARTBEAT) chunk
+ (RFC 4960).
+
+ This is used with ryu.lib.packet.sctp.sctp.
+
+ 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 correspondig args in this order.
+
+ .. tabularcolumns:: |l|p{30em}|l|
+
+ ============== =====================================================
+ Attribute Description
+ ============== =====================================================
+ flags set to '0'. this field will be ignored.
+ length length of this chunk containing this header.
+ info ryu.lib.packet.sctp.param_heartbeat.
+ ============== =====================================================
+ """
+
+ _RECOGNIZED_PARAMS = {}
+
+ @staticmethod
+ def register_param_type(*args):
+ def _register_param_type(cls):
+ chunk_heartbeat._RECOGNIZED_PARAMS[cls.param_type()] = cls
+ return cls
+ return _register_param_type(args[0])
+
+ @classmethod
+ def chunk_type(cls):
+ return TYPE_HEARTBEAT
+
+ @classmethod
+ def parser(cls, buf):
+ return super(chunk_heartbeat, cls).parser_base(
+ buf, cls._RECOGNIZED_PARAMS)
+
+
+@sctp.register_chunk_type
+class chunk_heartbeat_ack(chunk_heartbeat_base):
+ """Stream Control Transmission Protocol (SCTP)
+ sub encoder/decoder class for Heartbeat Acknowledgement
+ (HEARTBEAT ACK) chunk (RFC 4960).
+
+ This is used with ryu.lib.packet.sctp.sctp.
+
+ 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 correspondig args in this order.
+
+ .. tabularcolumns:: |l|p{30em}|l|
+
+ ============== =====================================================
+ Attribute Description
+ ============== =====================================================
+ flags set to '0'. this field will be ignored.
+ length length of this chunk containing this header.
+ info ryu.lib.packet.sctp.param_heartbeat.
+ ============== =====================================================
+ """
+
+ _RECOGNIZED_PARAMS = {}
+
+ @staticmethod
+ def register_param_type(*args):
+ def _register_param_type(cls):
+ chunk_heartbeat_ack._RECOGNIZED_PARAMS[cls.param_type()] = cls
+ return cls
+ return _register_param_type(args[0])
+
+ @classmethod
+ def chunk_type(cls):
+ return TYPE_HEARTBEAT_ACK
+
+ @classmethod
+ def parser(cls, buf):
+ return super(chunk_heartbeat_ack, cls).parser_base(
+ buf, cls._RECOGNIZED_PARAMS)
+
+
+@sctp.register_chunk_type
+class chunk_abort(chunk):
+ """Stream Control Transmission Protocol (SCTP)
+ sub encoder/decoder class for Abort Association (ABORT) chunk (RFC 4960).
+
+ This is used with ryu.lib.packet.sctp.sctp.
+
+ 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 correspondig args in this order.
+
+ .. tabularcolumns:: |l|p{30em}|l|
+
+ ============== =====================================================
+ Attribute Description
+ ============== =====================================================
+ tflag '0' means the Verification tag is normal. '1' means
+ the Verification tag is copy of the sender.
+ length length of this chunk containing this header.
+ causes a list of derived classes of ryu.lib.packet.sctp.causes.
+ ============== =====================================================
+ """
+
+ # TODO: coding and testing
+ _class_prefixes = ['cause_']
+ _RECOGNIZED_CAUSES = {}
+
+ @staticmethod
+ def register_cause_code(*args):
+ def _register_cause_code(cls):
+ chunk_abort._RECOGNIZED_CAUSES[cls.cause_code()] = cls
+ return cls
+ return _register_cause_code(args[0])
+
+ @classmethod
+ def chunk_type(cls):
+ return TYPE_ABORT
+
+ def __init__(self, tflag, length, causes=None):
+ super(chunk_abort, self).__init__(self.chunk_type(), length)
+ assert (1 == tflag | 1)
+ self.tflag = tflag
+ causes = causes or []
+ assert isinstance(causes, list)
+ for one in causes:
+ assert isinstance(one, cause)
+ self.causes = causes
+
+ @classmethod
+ def parser(cls, buf):
+ (_, flags, length) = struct.unpack_from(cls._PACK_STR, buf)
+ tflag = (flags >> 0) & 1
+ causes = []
+ offset = cls._MIN_LEN
+ while offset < length:
+ (ccode, ) = struct.unpack_from('!H', buf, offset)
+ cls_ = cls._RECOGNIZED_CAUSES.get(ccode)
+ if not cls_:
+ break
+ ins = cls_.parser(buf[offset:])
+ causes.append(ins)
+ offset += len(ins)
+ return cls(tflag, length, causes)
+
+ def serialize(self):
+ flags = (self.tflag << 0)
+ buf = bytearray(struct.pack(
+ self._PACK_STR, self.chunk_type(), flags, self.length))
+ for one in self.causes:
+ buf.extend(one.serialize())
+ return str(buf)
+
+
+@sctp.register_chunk_type
+class chunk_shutdown(chunk):
+ """Stream Control Transmission Protocol (SCTP)
+ sub encoder/decoder class for Shutdown Association (SHUTDOWN) chunk
+ (RFC 4960).
+
+ This is used with ryu.lib.packet.sctp.sctp.
+
+ 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 correspondig args in this order.
+
+ .. tabularcolumns:: |l|p{30em}|l|
+
+ ============== =====================================================
+ Attribute Description
+ ============== =====================================================
+ flags set to '0'. this field will be ignored.
+ length length of this chunk containing this header.
+ tsn_ack TSN of the last DATA chunk received in sequence
+ before a gap.
+ ============== =====================================================
+ """
+
+ _PACK_STR = '!BBHI'
+ _MIN_LEN = struct.calcsize(_PACK_STR)
+
+ @classmethod
+ def chunk_type(cls):
+ return TYPE_SHUTDOWN
+
+ def __init__(self, flags, length, tsn_ack):
+ super(chunk_shutdown, self).__init__(self.chunk_type(), length)
+ self.flags = flags
+ self.tsn_ack = tsn_ack
+
+ @classmethod
+ def parser(cls, buf):
+ (_, flags, length, tsn_ack
+ ) = struct.unpack_from(cls._PACK_STR, buf)
+ msg = cls(flags, length, tsn_ack)
+ return msg
+
+ def serialize(self):
+ buf = struct.pack(
+ self._PACK_STR, self.chunk_type(), self.flags,
+ self.length, self.tsn_ack)
+ return buf
+
+
+@sctp.register_chunk_type
+class chunk_shutdown_ack(chunk_ack_base):
+ """Stream Control Transmission Protocol (SCTP)
+ sub encoder/decoder class for Shutdown Acknowledgement (SHUTDOWN ACK)
+ chunk (RFC 4960).
+
+ This is used with ryu.lib.packet.sctp.sctp.
+
+ 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 correspondig args in this order.
+
+ .. tabularcolumns:: |l|p{30em}|l|
+
+ ============== =====================================================
+ Attribute Description
+ ============== =====================================================
+ flags set to '0'. this field will be ignored.
+ length length of this chunk containing this header.
+ ============== =====================================================
+ """
+
+ @classmethod
+ def chunk_type(cls):
+ return TYPE_SHUTDOWN_ACK
+
+
+@sctp.register_chunk_type
+class chunk_error(chunk):
+ """Stream Control Transmission Protocol (SCTP)
+ sub encoder/decoder class for Operation Error (ERROR) chunk (RFC 4960).
+
+ This is used with ryu.lib.packet.sctp.sctp.
+
+ 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 correspondig args in this order.
+
+ .. tabularcolumns:: |l|p{30em}|l|
+
+ ============== =====================================================
+ Attribute Description
+ ============== =====================================================
+ flags set to '0'. this field will be ignored.
+ length length of this chunk containing this header.
+ causes a list of derived classes of ryu.lib.packet.sctp.causes.
+ ============== =====================================================
+ """
+
+ # TODO: coding and testing
+ _class_prefixes = ['cause_']
+ _RECOGNIZED_CAUSES = {}
+
+ @staticmethod
+ def register_cause_code(*args):
+ def _register_cause_code(cls):
+ chunk_error._RECOGNIZED_CAUSES[cls.cause_code()] = cls
+ return cls
+ return _register_cause_code(args[0])
+
+ @classmethod
+ def chunk_type(cls):
+ return TYPE_ERROR
+
+ def __init__(self, flags, length, causes=None):
+ super(chunk_error, self).__init__(self.chunk_type(), length)
+ self.flags = flags
+ causes = causes or []
+ assert isinstance(causes, list)
+ for one in causes:
+ assert isinstance(one, cause)
+ self.causes = causes
+
+ @classmethod
+ def parser(cls, buf):
+ (_, flags, length) = struct.unpack_from(cls._PACK_STR, buf)
+ causes = []
+ offset = cls._MIN_LEN
+ while offset < length:
+ (ccode, ) = struct.unpack_from('!H', buf, offset)
+ cls_ = cls._RECOGNIZED_CAUSES.get(ccode)
+ if not cls_:
+ break
+ ins = cls_.parser(buf[offset:])
+ causes.append(ins)
+ offset += len(ins)
+ return cls(flags, length, causes)
+
+ def serialize(self):
+ buf = bytearray(struct.pack(
+ self._PACK_STR, self.chunk_type(), self.flags, self.length))
+ for one in self.causes:
+ buf.extend(one.serialize())
+ return str(buf)
+
+
+@sctp.register_chunk_type
+class chunk_cookie_echo(chunk):
+ """Stream Control Transmission Protocol (SCTP)
+ sub encoder/decoder class for Cookie Echo (COOKIE ECHO) chunk (RFC 4960).
+
+ This is used with ryu.lib.packet.sctp.sctp.
+
+ 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 correspondig args in this order.
+
+ .. tabularcolumns:: |l|p{30em}|l|
+
+ ============== =====================================================
+ Attribute Description
+ ============== =====================================================
+ flags set to '0'. this field will be ignored.
+ length length of this chunk containing this header.
+ cookie cookie data.
+ ============== =====================================================
+ """
+
+ _PACK_STR = '!BBH'
+ _MIN_LEN = struct.calcsize(_PACK_STR)
+
+ @classmethod
+ def chunk_type(cls):
+ return TYPE_COOKIE_ECHO
+
+ def __init__(self, flags, length, cookie):
+ super(chunk_cookie_echo, self).__init__(self.chunk_type(), length)
+ self.flags = flags
+ self.cookie = cookie
+
+ @classmethod
+ def parser(cls, buf):
+ (_, flags, length) = struct.unpack_from(cls._PACK_STR, buf)
+ fmt = '%ds' % (length - cls._MIN_LEN)
+ (cookie, ) = struct.unpack_from(fmt, buf, cls._MIN_LEN)
+ return cls(flags, length, cookie)
+
+ def serialize(self):
+ buf = bytearray(struct.pack(
+ self._PACK_STR, self.chunk_type(), self.flags,
+ self.length))
+ buf.extend(self.cookie)
+ return str(buf)
+
+
+@sctp.register_chunk_type
+class chunk_cookie_ack(chunk_ack_base):
+ """Stream Control Transmission Protocol (SCTP)
+ sub encoder/decoder class for Cookie Acknowledgement (COOKIE ACK)
+ chunk (RFC 4960).
+
+ This is used with ryu.lib.packet.sctp.sctp.
+
+ 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 correspondig args in this order.
+
+ .. tabularcolumns:: |l|p{30em}|l|
+
+ ============== =====================================================
+ Attribute Description
+ ============== =====================================================
+ flags set to '0'. this field will be ignored.
+ length length of this chunk containing this header.
+ ============== =====================================================
+ """
+
+ @classmethod
+ def chunk_type(cls):
+ return TYPE_COOKIE_ACK
+
+
+@sctp.register_chunk_type
+class chunk_ecn_echo(chunk_ecn_base):
+ """Stream Control Transmission Protocol (SCTP)
+ sub encoder/decoder class for ECN-Echo chunk (RFC 4960 Appendix A.).
+
+ This is used with ryu.lib.packet.sctp.sctp.
+
+ 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 correspondig args in this order.
+
+ .. tabularcolumns:: |l|p{30em}|l|
+
+ ============== =====================================================
+ Attribute Description
+ ============== =====================================================
+ flags set to '0'. this field will be ignored.
+ length length of this chunk containing this header.
+ low_tsn the lowest TSN.
+ ============== =====================================================
+ """
+
+ @classmethod
+ def chunk_type(cls):
+ return TYPE_ECN_ECHO
+
+
+@sctp.register_chunk_type
+class chunk_cwr(chunk_ecn_base):
+ """Stream Control Transmission Protocol (SCTP)
+ sub encoder/decoder class for CWR chunk (RFC 4960 Appendix A.).
+
+ This is used with ryu.lib.packet.sctp.sctp.
+
+ 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 correspondig args in this order.
+
+ .. tabularcolumns:: |l|p{30em}|l|
+
+ ============== =====================================================
+ Attribute Description
+ ============== =====================================================
+ flags set to '0'. this field will be ignored.
+ length length of this chunk containing this header.
+ low_tsn the lowest TSN.
+ ============== =====================================================
+ """
+
+ @classmethod
+ def chunk_type(cls):
+ return TYPE_CWR
+
+
+@sctp.register_chunk_type
+class chunk_shutdown_complete(chunk):
+ """Stream Control Transmission Protocol (SCTP)
+ sub encoder/decoder class for Shutdown Complete (SHUTDOWN COMPLETE)
+ chunk (RFC 4960).
+
+ This is used with ryu.lib.packet.sctp.sctp.
+
+ 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 correspondig args in this order.
+
+ .. tabularcolumns:: |l|p{30em}|l|
+
+ ============== =====================================================
+ Attribute Description
+ ============== =====================================================
+ tflag '0' means the Verification tag is normal. '1' means
+ the Verification tag is copy of the sender.
+ length length of this chunk containing this header.
+ ============== =====================================================
+ """
+
+ _PACK_STR = '!BBH'
+ _MIN_LEN = struct.calcsize(_PACK_STR)
+
+ @classmethod
+ def chunk_type(cls):
+ return TYPE_SHUTDOWN_COMPLETE
+
+ def __init__(self, tflag, length):
+ assert (1 == tflag | 1)
+ super(chunk_shutdown_complete, self).__init__(
+ self.chunk_type(), length)
+ self.tflag = tflag
+
+ @classmethod
+ def parser(cls, buf):
+ (_, flags, length) = struct.unpack_from(cls._PACK_STR, buf)
+ tflag = flags & 1
+ msg = cls(tflag, length)
+ return msg
+
+ def serialize(self):
+ buf = struct.pack(
+ self._PACK_STR, self.chunk_type(),
+ self.tflag, self.length)
+ return buf
+
+
+#=======================================================================
+#
+# Cause Code
+#
+#=======================================================================
+class cause(stringify.StringifyMixin):
+
+ __metaclass__ = abc.ABCMeta
+ _PACK_STR = '!HH'
+ _MIN_LEN = struct.calcsize(_PACK_STR)
+
+ @classmethod
+ @abc.abstractproperty
+ def cause_code(cls):
+ pass
+
+ def __init__(self, length):
+ self.length = length
+
+ @classmethod
+ @abc.abstractmethod
+ def parser(cls, buf):
+ pass
+
+ @abc.abstractmethod
+ def serialize(self):
+ pass
+
+ def __len__(self):
+ return self.length
+
+
+class cause_with_value(cause):
+
+ __metaclass__ = abc.ABCMeta
+
+ def __init__(self, length, value):
+ super(cause_with_value, self).__init__(length)
+ self.value = value
+
+ @classmethod
+ def parser(cls, buf):
+ (_, length) = struct.unpack_from(cls._PACK_STR, buf)
+ value = None
+ if (cls._MIN_LEN < length):
+ fmt = '%ds' % (length - cls._MIN_LEN)
+ (value, ) = struct.unpack_from(fmt, buf, cls._MIN_LEN)
+ return cls(length, value)
+
+ def serialize(self):
+ buf = bytearray(struct.pack(
+ self._PACK_STR, self.cause_code(), self.length))
+ if self.value:
+ buf.extend(self.value)
+ return str(buf)
+
+
+@chunk_abort.register_cause_code
+@chunk_error.register_cause_code
+class cause_invalid_stream_id(cause_with_value):
+ """Stream Control Transmission Protocol (SCTP)
+ sub encoder/decoder class for Invalid Stream Identifier (RFC 4960).
+
+ This is used with ryu.lib.packet.sctp.chunk_abort and
+ ryu.lib.packet.sctp.chunk_error.
+
+ 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 correspondig args in this order.
+
+ .. tabularcolumns:: |l|p{30em}|l|
+
+ ============== =====================================================
+ Attribute Description
+ ============== =====================================================
+ length length of this cause containing this header.
+ value stream id.
+ ============== =====================================================
+ """
+
+ _PACK_STR = '!HHH2x'
+ _MIN_LEN = struct.calcsize(_PACK_STR)
+
+ @classmethod
+ def cause_code(cls):
+ return CCODE_INVALID_STREAM_ID
+
+ @classmethod
+ def parser(cls, buf):
+ (_, length, value) = struct.unpack_from(cls._PACK_STR, buf)
+ return cls(length, value)
+
+ def serialize(self):
+ buf = struct.pack(
+ self._PACK_STR, self.cause_code(), self.length, self.value)
+ return buf
+
+
+@chunk_abort.register_cause_code
+@chunk_error.register_cause_code
+class cause_missing_param(cause):
+ """Stream Control Transmission Protocol (SCTP)
+ sub encoder/decoder class for Missing Mandatory Parameter (RFC 4960).
+
+ This is used with ryu.lib.packet.sctp.chunk_abort and
+ ryu.lib.packet.sctp.chunk_error.
+
+ 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 correspondig args in this order.
+
+ .. tabularcolumns:: |l|p{30em}|l|
+
+ ============== =====================================================
+ Attribute Description
+ ============== =====================================================
+ length length of this cause containing this header.
+ num Number of missing params.
+ types a list of missing params.
+ ============== =====================================================
+ """
+
+ _PACK_STR = '!HHI'
+ _MIN_LEN = struct.calcsize(_PACK_STR)
+
+ @classmethod
+ def cause_code(cls):
+ return CCODE_MISSING_PARAM
+
+ def __init__(self, length, num, types=None):
+ super(cause_missing_param, self).__init__(length)
+ self.num = num
+ types = types or []
+ assert isinstance(types, list)
+ for one in types:
+ assert isinstance(one, int)
+ self.types = types
+
+ @classmethod
+ def parser(cls, buf):
+ (_, length, num) = struct.unpack_from(cls._PACK_STR, buf)
+ types = []
+ offset = cls._MIN_LEN
+ for count in range(num):
+ offset = cls._MIN_LEN + (struct.calcsize('!H') * count)
+ (one, ) = struct.unpack_from('!H', buf, offset)
+ types.append(one)
+ return cls(length, num, types)
+
+ def serialize(self):
+ buf = bytearray(struct.pack(
+ self._PACK_STR, self.cause_code(), self.length, self.num))
+ for one in self.types:
+ buf.extend(struct.pack('!H', one))
+ return str(buf)
+
+
+@chunk_abort.register_cause_code
+@chunk_error.register_cause_code
+class cause_stale_cookie(cause_with_value):
+ """Stream Control Transmission Protocol (SCTP)
+ sub encoder/decoder class for Stale Cookie Error (RFC 4960).
+
+ This is used with ryu.lib.packet.sctp.chunk_abort and
+ ryu.lib.packet.sctp.chunk_error.
+
+ 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 correspondig args in this order.
+
+ .. tabularcolumns:: |l|p{30em}|l|
+
+ ============== =====================================================
+ Attribute Description
+ ============== =====================================================
+ length length of this cause containing this header.
+ value Measure of Staleness.
+ ============== =====================================================
+ """
+
+ @classmethod
+ def cause_code(cls):
+ return CCODE_STALE_COOKIE
+
+
+@chunk_abort.register_cause_code
+@chunk_error.register_cause_code
+class cause_out_of_resource(cause):
+ """Stream Control Transmission Protocol (SCTP)
+ sub encoder/decoder class for Out of Resource (RFC 4960).
+
+ This is used with ryu.lib.packet.sctp.chunk_abort and
+ ryu.lib.packet.sctp.chunk_error.
+
+ 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 correspondig args in this order.
+
+ .. tabularcolumns:: |l|p{30em}|l|
+
+ ============== =====================================================
+ Attribute Description
+ ============== =====================================================
+ length length of this cause containing this header.
+ ============== =====================================================
+ """
+
+ @classmethod
+ def cause_code(cls):
+ return CCODE_OUT_OF_RESOURCE
+
+ @classmethod
+ def parser(cls, buf):
+ (_, length) = struct.unpack_from(cls._PACK_STR, buf)
+ return cls(length)
+
+ def serialize(self):
+ buf = struct.pack(
+ self._PACK_STR, self.cause_code(), self.length)
+ return buf
+
+
+@chunk_abort.register_cause_code
+@chunk_error.register_cause_code
+class cause_unresolvable_addr(cause_with_value):
+ """Stream Control Transmission Protocol (SCTP)
+ sub encoder/decoder class for Unresolvable Address (RFC 4960).
+
+ This is used with ryu.lib.packet.sctp.chunk_abort and
+ ryu.lib.packet.sctp.chunk_error.
+
+ 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 correspondig args in this order.
+
+ .. tabularcolumns:: |l|p{30em}|l|
+
+ ============== =====================================================
+ Attribute Description
+ ============== =====================================================
+ length length of this cause containing this header.
+ value Unresolvable Address. one of follows:
+
+ ryu.lib.packet.sctp.param_host_addr,
+
+ ryu.lib.packet.sctp.param_ipv4, or
+
+ ryu.lib.packet.sctp.param_ipv6.
+ ============== =====================================================
+ """
+
+ _RECOGNIZED_PARAMS = {}
+
+ @staticmethod
+ def register_param_type(*args):
+ def _register_param_type(cls):
+ cause_unresolvable_addr._RECOGNIZED_PARAMS[cls.param_type()] = cls
+ return cls
+ return _register_param_type(args[0])
+
+ @classmethod
+ def cause_code(cls):
+ return CCODE_UNRESOLVABLE_ADDR
+
+ def __init__(self, length, value):
+ super(cause_unresolvable_addr, self).__init__(length, value)
+
+ @classmethod
+ def parser(cls, buf):
+ (_, length) = struct.unpack_from(cls._PACK_STR, buf)
+ (ptype, ) = struct.unpack_from('!H', buf, cls._MIN_LEN)
+ cls_ = cls._RECOGNIZED_PARAMS.get(ptype)
+ value = cls_.parser(buf[cls._MIN_LEN:])
+ return cls(length, value)
+
+ def serialize(self):
+ buf = bytearray(struct.pack(
+ self._PACK_STR, self.cause_code(), self.length))
+ if self.value:
+ buf.extend(self.value.serialize())
+ return str(buf)
+
+
+@chunk_abort.register_cause_code
+@chunk_error.register_cause_code
+class cause_unrecognized_chunk(cause_with_value):
+ """Stream Control Transmission Protocol (SCTP)
+ sub encoder/decoder class for Unrecognized Chunk Type (RFC 4960).
+
+ This is used with ryu.lib.packet.sctp.chunk_abort and
+ ryu.lib.packet.sctp.chunk_error.
+
+ 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 correspondig args in this order.
+
+ .. tabularcolumns:: |l|p{30em}|l|
+
+ ============== =====================================================
+ Attribute Description
+ ============== =====================================================
+ length length of this cause containing this header.
+ value Unrecognized Chunk.
+ ============== =====================================================
+ """
+
+ @classmethod
+ def cause_code(cls):
+ return CCODE_UNRECOGNIZED_CHUNK
+
+
+@chunk_abort.register_cause_code
+@chunk_error.register_cause_code
+class cause_invalid_param(cause):
+ """Stream Control Transmission Protocol (SCTP)
+ sub encoder/decoder class for Invalid Mandatory Parameter (RFC 4960).
+
+ This is used with ryu.lib.packet.sctp.chunk_abort and
+ ryu.lib.packet.sctp.chunk_error.
+
+ 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 correspondig args in this order.
+
+ .. tabularcolumns:: |l|p{30em}|l|
+
+ ============== =====================================================
+ Attribute Description
+ ============== =====================================================
+ length length of this cause containing this header.
+ ============== =====================================================
+ """
+
+ @classmethod
+ def cause_code(cls):
+ return CCODE_INVALID_PARAM
+
+ def __init__(self, length):
+ super(cause_invalid_param, self).__init__(length)
+
+ @classmethod
+ def parser(cls, buf):
+ (_, length) = struct.unpack_from(cls._PACK_STR, buf)
+ return cls(length)
+
+ def serialize(self):
+ buf = struct.pack(
+ self._PACK_STR, self.cause_code(), self.length)
+ return buf
+
+
+@chunk_abort.register_cause_code
+@chunk_error.register_cause_code
+class cause_unrecognized_param(cause_with_value):
+ """Stream Control Transmission Protocol (SCTP)
+ sub encoder/decoder class for Unrecognized Parameters (RFC 4960).
+
+ This is used with ryu.lib.packet.sctp.chunk_abort and
+ ryu.lib.packet.sctp.chunk_error.
+
+ 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 correspondig args in this order.
+
+ .. tabularcolumns:: |l|p{30em}|l|
+
+ ============== =====================================================
+ Attribute Description
+ ============== =====================================================
+ length length of this cause containing this header.
+ value Unrecognized Parameter.
+ ============== =====================================================
+ """
+
+ @classmethod
+ def cause_code(cls):
+ return CCODE_UNRECOGNIZED_PARAM
+
+
+@chunk_abort.register_cause_code
+@chunk_error.register_cause_code
+class cause_no_userdata(cause_with_value):
+ """Stream Control Transmission Protocol (SCTP)
+ sub encoder/decoder class for No User Data (RFC 4960).
+
+ This is used with ryu.lib.packet.sctp.chunk_abort and
+ ryu.lib.packet.sctp.chunk_error.
+
+ 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 correspondig args in this order.
+
+ .. tabularcolumns:: |l|p{30em}|l|
+
+ ============== =====================================================
+ Attribute Description
+ ============== =====================================================
+ length length of this cause containing this header.
+ value the TSN of the DATA chunk received with no user data
+ field.
+ ============== =====================================================
+ """
+
+ @classmethod
+ def cause_code(cls):
+ return CCODE_NO_USERDATA
+
+
+@chunk_abort.register_cause_code
+@chunk_error.register_cause_code
+class cause_cookie_while_shutdown(cause):
+ """Stream Control Transmission Protocol (SCTP)
+ sub encoder/decoder class for Cookie Received While Shutting Down
+ (RFC 4960).
+
+ This is used with ryu.lib.packet.sctp.chunk_abort and
+ ryu.lib.packet.sctp.chunk_error.
+
+ 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 correspondig args in this order.
+
+ .. tabularcolumns:: |l|p{30em}|l|
+
+ ============== =====================================================
+ Attribute Description
+ ============== =====================================================
+ length length of this cause containing this header.
+ ============== =====================================================
+ """
+
+ @classmethod
+ def cause_code(cls):
+ return CCODE_COOKIE_WHILE_SHUTDOWN
+
+ def __init__(self, length):
+ super(cause_cookie_while_shutdown, self).__init__(length)
+
+ @classmethod
+ def parser(cls, buf):
+ (_, length) = struct.unpack_from(cls._PACK_STR, buf)
+ return cls(length)
+
+ def serialize(self):
+ buf = struct.pack(
+ self._PACK_STR, self.cause_code(), self.length)
+ return buf
+
+
+@chunk_abort.register_cause_code
+@chunk_error.register_cause_code
+class cause_restart_with_new_addr(cause_with_value):
+ """Stream Control Transmission Protocol (SCTP)
+ sub encoder/decoder class for Restart of an Association with New
+ Addresses (RFC 4960).
+
+ This is used with ryu.lib.packet.sctp.chunk_abort and
+ ryu.lib.packet.sctp.chunk_error.
+
+ 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 correspondig args in this order.
+
+ .. tabularcolumns:: |l|p{30em}|l|
+
+ ============== =====================================================
+ Attribute Description
+ ============== =====================================================
+ length length of this cause containing this header.
+ value New Address TLVs.
+ ============== =====================================================
+ """
+
+ _RECOGNIZED_PARAMS = {}
+
+ @staticmethod
+ def register_param_type(*args):
+ def _register_param_type(cls):
+ cause_restart_with_new_addr._RECOGNIZED_PARAMS[
+ cls.param_type()] = cls
+ return cls
+ return _register_param_type(args[0])
+
+ @classmethod
+ def cause_code(cls):
+ return CCODE_RESTART_WITH_NEW_ADDR
+
+ def __init__(self, length, value):
+ if not isinstance(value, list):
+ value = [value]
+ super(cause_restart_with_new_addr, self).__init__(length, value)
+
+ @classmethod
+ def parser(cls, buf):
+ (_, length) = struct.unpack_from(cls._PACK_STR, buf)
+ value = []
+ offset = cls._MIN_LEN
+ while offset < length:
+ (ptype, ) = struct.unpack_from('!H', buf, offset)
+ cls_ = cls._RECOGNIZED_PARAMS.get(ptype)
+ if not cls_:
+ break
+ ins = cls_.parser(buf[offset:])
+ value.append(ins)
+ offset += len(ins)
+ return cls(length, value)
+
+ def serialize(self):
+ buf = bytearray(struct.pack(
+ self._PACK_STR, self.cause_code(), self.length))
+ for one in self.value:
+ buf.extend(one.serialize())
+ return str(buf)
+
+
+@chunk_abort.register_cause_code
+@chunk_error.register_cause_code
+class cause_user_initiated_abort(cause_with_value):
+ """Stream Control Transmission Protocol (SCTP)
+ sub encoder/decoder class for User-Initiated Abort (RFC 4960).
+
+ This is used with ryu.lib.packet.sctp.chunk_abort and
+ ryu.lib.packet.sctp.chunk_error.
+
+ 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 correspondig args in this order.
+
+ .. tabularcolumns:: |l|p{30em}|l|
+
+ ============== =====================================================
+ Attribute Description
+ ============== =====================================================
+ length length of this cause containing this header.
+ value Upper Layer Abort Reason.
+ ============== =====================================================
+ """
+
+ @classmethod
+ def cause_code(cls):
+ return CCODE_USER_INITIATED_ABORT
+
+
+@chunk_abort.register_cause_code
+@chunk_error.register_cause_code
+class cause_protocol_violation(cause_with_value):
+ """Stream Control Transmission Protocol (SCTP)
+ sub encoder/decoder class for Protocol Violation (RFC 4960).
+
+ This is used with ryu.lib.packet.sctp.chunk_abort and
+ ryu.lib.packet.sctp.chunk_error.
+
+ 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 correspondig args in this order.
+
+ .. tabularcolumns:: |l|p{30em}|l|
+
+ ============== =====================================================
+ Attribute Description
+ ============== =====================================================
+ length length of this cause containing this header.
+ value Additional Information.
+ ============== =====================================================
+ """
+
+ @classmethod
+ def cause_code(cls):
+ return CCODE_PROTOCOL_VIOLATION
+
+
+#=======================================================================
+#
+# Chunk Parameter Types
+#
+#=======================================================================
+class param(stringify.StringifyMixin):
+
+ __metaclass__ = abc.ABCMeta
+ _PACK_STR = '!HH'
+ _MIN_LEN = struct.calcsize(_PACK_STR)
+
+ @classmethod
+ @abc.abstractproperty
+ def param_type(cls):
+ pass
+
+ def __init__(self, length, value):
+ self.length = length
+ self.value = value
+
+ @classmethod
+ def parser(cls, buf):
+ (_, length) = struct.unpack_from(cls._PACK_STR, buf)
+ value = None
+ if (cls._MIN_LEN < length):
+ fmt = '%ds' % (length - cls._MIN_LEN)
+ (value, ) = struct.unpack_from(fmt, buf, cls._MIN_LEN)
+ return cls(length, value)
+
+ def serialize(self):
+ buf = bytearray(struct.pack(
+ self._PACK_STR, self.param_type(), self.length))
+ if self.value:
+ buf.extend(self.value)
+ return str(buf)
+
+ def __len__(self):
+ return self.length
+
+
+@chunk_heartbeat.register_param_type
+@chunk_heartbeat_ack.register_param_type
+class param_heartbeat(param):
+ """Stream Control Transmission Protocol (SCTP)
+ sub encoder/decoder class for Heartbeat Info Parameter (RFC 4960).
+
+ This is used with ryu.lib.packet.sctp.chunk_heartbeat and
+ ryu.lib.packet.sctp.chunk_heartbeat_ack.
+
+ 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 correspondig args in this order.
+
+ .. tabularcolumns:: |l|p{30em}|l|
+
+ ============== =====================================================
+ Attribute Description
+ ============== =====================================================
+ length length of this param containing this header.
+ value the sender-specific heartbeat information.
+ ============== =====================================================
+ """
+
+ @classmethod
+ def param_type(cls):
+ return PTYPE_HEARTBEAT
+
+
+@chunk_init_ack.register_param_type
+class param_state_cookie(param):
+ """Stream Control Transmission Protocol (SCTP)
+ sub encoder/decoder class for State Cookie Parameter (RFC 4960).
+
+ This is used with ryu.lib.packet.sctp.chunk_init_ack.
+
+ 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 correspondig args in this order.
+
+ .. tabularcolumns:: |l|p{30em}|l|
+
+ ============== =====================================================
+ Attribute Description
+ ============== =====================================================
+ length length of this param containing this header.
+ value the state cookie. see Section 5.1.3 in RFC 4960.
+ ============== =====================================================
+ """
+
+ @classmethod
+ def param_type(cls):
+ return PTYPE_STATE_COOKIE
+
+
+@chunk_init_ack.register_param_type
+class param_unrecognized_param(param):
+ """Stream Control Transmission Protocol (SCTP)
+ sub encoder/decoder class for Unrecognized Parameter (RFC 4960).
+
+ This is used with ryu.lib.packet.sctp.chunk_init_ack.
+
+ 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 correspondig args in this order.
+
+ .. tabularcolumns:: |l|p{30em}|l|
+
+ ============== =====================================================
+ Attribute Description
+ ============== =====================================================
+ length length of this param containing this header.
+ value the unrecognized parameter in the INIT chunk.
+ ============== =====================================================
+ """
+
+ @classmethod
+ def param_type(cls):
+ return PTYPE_UNRECOGNIZED_PARAM
+
+
+@chunk_init.register_param_type
+class param_cookie_preserve(param):
+ """Stream Control Transmission Protocol (SCTP)
+ sub encoder/decoder class for Cookie Preservative Parameter (RFC 4960).
+
+ This is used with ryu.lib.packet.sctp.chunk_init.
+
+ 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 correspondig args in this order.
+
+ .. tabularcolumns:: |l|p{30em}|l|
+
+ ============== =====================================================
+ Attribute Description
+ ============== =====================================================
+ length length of this param containing this header.
+ value Suggested Cookie Life-Span Increment (msec).
+ ============== =====================================================
+ """
+
+ _PACK_STR = '!HHI'
+ _MIN_LEN = struct.calcsize(_PACK_STR)
+
+ @classmethod
+ def param_type(cls):
+ return PTYPE_COOKIE_PRESERVE
+
+ @classmethod
+ def parser(cls, buf):
+ (_, length, value) = struct.unpack_from(cls._PACK_STR, buf)
+ return cls(length, value)
+
+ def serialize(self):
+ buf = struct.pack(
+ self._PACK_STR, self.param_type(), self.length, self.value)
+ return buf
+
+
+@chunk_init.register_param_type
+@chunk_init_ack.register_param_type
+class param_ecn(param):
+ """Stream Control Transmission Protocol (SCTP)
+ sub encoder/decoder class for ECN Parameter (RFC 4960 Appendix A.).
+
+ This is used with ryu.lib.packet.sctp.chunk_init and
+ ryu.lib.packet.sctp.chunk_init_ack.
+
+ 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 correspondig args in this order.
+
+ .. tabularcolumns:: |l|p{30em}|l|
+
+ ============== =====================================================
+ Attribute Description
+ ============== =====================================================
+ length length of this param containing this header.
+ value set to None.
+ ============== =====================================================
+ """
+
+ @classmethod
+ def param_type(cls):
+ return PTYPE_ECN
+
+
+@chunk_init.register_param_type
+@chunk_init_ack.register_param_type
+@cause_unresolvable_addr.register_param_type
+@cause_restart_with_new_addr.register_param_type
+class param_host_addr(param):
+ """Stream Control Transmission Protocol (SCTP)
+ sub encoder/decoder class for Host Name Address Parameter (RFC 4960).
+
+ This is used with ryu.lib.packet.sctp.chunk_init and
+ ryu.lib.packet.sctp.chunk_init_ack.
+
+ 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 correspondig args in this order.
+
+ .. tabularcolumns:: |l|p{30em}|l|
+
+ ============== =====================================================
+ Attribute Description
+ ============== =====================================================
+ length length of this param containing this header.
+ value a host name that ends with null terminator.
+ ============== =====================================================
+ """
+
+ @classmethod
+ def param_type(cls):
+ return PTYPE_HOST_ADDR
+
+
+@chunk_init.register_param_type
+class param_supported_addr(param):
+ """Stream Control Transmission Protocol (SCTP)
+ sub encoder/decoder class for Supported Address Types Parameter (RFC 4960).
+
+ This is used with ryu.lib.packet.sctp.chunk_init.
+
+ 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 correspondig args in this order.
+
+ .. tabularcolumns:: |l|p{30em}|l|
+
+ ============== =====================================================
+ Attribute Description
+ ============== =====================================================
+ length length of this param containing this header.
+ value a list of parameter types. odd cases pad with 0x0000.
+ ============== =====================================================
+ """
+
+ _VALUE_STR = '!H'
+ _VALUE_LEN = struct.calcsize(_VALUE_STR)
+
+ @classmethod
+ def param_type(cls):
+ return PTYPE_SUPPORTED_ADDR
+
+ def __init__(self, length, value):
+ super(param_supported_addr, self).__init__(length, value)
+ if not isinstance(value, list):
+ value = [value]
+ for one in value:
+ assert isinstance(one, int)
+ self.length = length
+ if len(value) % 2:
+ value.append(0)
+ self.value = value
+
+ @classmethod
+ def parser(cls, buf):
+ (_, length) = struct.unpack_from(cls._PACK_STR, buf)
+ value = []
+ offset = cls._MIN_LEN
+ while offset < length:
+ (one, ) = struct.unpack_from(cls._VALUE_STR, buf, offset)
+ value.append(one)
+ offset += cls._VALUE_LEN
+ return cls(length, value)
+
+ def serialize(self):
+ buf = bytearray(struct.pack(
+ self._PACK_STR, self.param_type(), self.length))
+ for one in self.value:
+ buf.extend(struct.pack(param_supported_addr._VALUE_STR, one))
+ return str(buf)
+
+ def __len__(self):
+ return self.length if 0 == self.length % 4 else self.length + 2
+
+
+@chunk_init.register_param_type
+@chunk_init_ack.register_param_type
+@cause_restart_with_new_addr.register_param_type
+class param_ipv4(param):
+ """Stream Control Transmission Protocol (SCTP)
+ sub encoder/decoder class for IPv4 Address Parameter (RFC 4960).
+
+ This is used with ryu.lib.packet.sctp.chunk_init and
+ ryu.lib.packet.sctp.chunk_init_ack.
+
+ 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 correspondig args in this order.
+
+ .. tabularcolumns:: |l|p{30em}|l|
+
+ ============== =====================================================
+ Attribute Description
+ ============== =====================================================
+ length length of this param containing this header.
+ value IPv4 address of the sending endpoint.
+ ============== =====================================================
+ """
+
+ _TYPE = {'ascii': ['value']}
+
+ @classmethod
+ def param_type(cls):
+ return PTYPE_IPV4
+
+ @classmethod
+ def parser(cls, buf):
+ (_, length) = struct.unpack_from(cls._PACK_STR, buf)
+ value = None
+ if (cls._MIN_LEN < length):
+ fmt = '%ds' % (length - cls._MIN_LEN)
+ (value, ) = struct.unpack_from(fmt, buf, cls._MIN_LEN)
+ return cls(length, addrconv.ipv4.bin_to_text(value))
+
+ def serialize(self):
+ buf = bytearray(struct.pack(
+ self._PACK_STR, self.param_type(), self.length))
+ if self.value:
+ buf.extend(addrconv.ipv4.text_to_bin(self.value))
+ return str(buf)
+
+
+@chunk_init.register_param_type
+@chunk_init_ack.register_param_type
+@cause_restart_with_new_addr.register_param_type
+class param_ipv6(param):
+ """Stream Control Transmission Protocol (SCTP)
+ sub encoder/decoder class for IPv6 Address Parameter (RFC 4960).
+
+ This is used with ryu.lib.packet.sctp.chunk_init and
+ ryu.lib.packet.sctp.chunk_init_ack.
+
+ 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 correspondig args in this order.
+
+ .. tabularcolumns:: |l|p{30em}|l|
+
+ ============== =====================================================
+ Attribute Description
+ ============== =====================================================
+ length length of this param containing this header.
+ value IPv6 address of the sending endpoint.
+ ============== =====================================================
+ """
+
+ _TYPE = {'ascii': ['value']}
+
+ @classmethod
+ def param_type(cls):
+ return PTYPE_IPV6
+
+ @classmethod
+ def parser(cls, buf):
+ (_, length) = struct.unpack_from(cls._PACK_STR, buf)
+ value = None
+ if (cls._MIN_LEN < length):
+ fmt = '%ds' % (length - cls._MIN_LEN)
+ (value, ) = struct.unpack_from(fmt, buf, cls._MIN_LEN)
+ return cls(length, addrconv.ipv6.bin_to_text(value))
+
+ def serialize(self):
+ buf = bytearray(struct.pack(
+ self._PACK_STR, self.param_type(), self.length))
+ if self.value:
+ buf.extend(addrconv.ipv6.text_to_bin(self.value))
+ return str(buf)