diff options
author | Shinpei Muraoka <shinpei.muraoka@gmail.com> | 2016-07-28 10:06:10 +0900 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2016-07-29 05:55:32 +0900 |
commit | d0992e24aea897920c25099aa841048e2e740cca (patch) | |
tree | 35a2a1da5e7410eb57a641d3704816490e37b529 | |
parent | 4ca81f962483896c5a73f8d0bcf4d56e85b9a583 (diff) |
packet lib: Add packet library of GRE
Signed-off-by: Shinpei Muraoka <shinpei.muraoka@gmail.com>
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
-rw-r--r-- | doc/source/library_packet_ref.rst | 3 | ||||
-rw-r--r-- | ryu/lib/packet/gre.py | 129 | ||||
-rw-r--r-- | ryu/lib/packet/in_proto.py | 1 | ||||
-rw-r--r-- | ryu/lib/packet/ipv4.py | 2 | ||||
-rw-r--r-- | ryu/lib/packet/ipv6.py | 2 | ||||
-rw-r--r-- | ryu/tests/unit/packet/test_gre.py | 81 |
6 files changed, 218 insertions, 0 deletions
diff --git a/doc/source/library_packet_ref.rst b/doc/source/library_packet_ref.rst index 4f17615c..87f44a1c 100644 --- a/doc/source/library_packet_ref.rst +++ b/doc/source/library_packet_ref.rst @@ -50,6 +50,9 @@ Protocol Header classes .. automodule:: ryu.lib.packet.icmpv6 :members: +.. automodule:: ryu.lib.packet.gre + :members: + .. automodule:: ryu.lib.packet.cfm :members: diff --git a/ryu/lib/packet/gre.py b/ryu/lib/packet/gre.py new file mode 100644 index 00000000..c22032e9 --- /dev/null +++ b/ryu/lib/packet/gre.py @@ -0,0 +1,129 @@ +# Copyright (C) 2016 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 struct + +from . import packet_base +from . import packet_utils +from . import ether_types as ether +from ryu.lib.pack_utils import msg_pack_into + + +GRE_CHECKSUM_FLG = 1 << 7 +GRE_KEY_FLG = 1 << 5 +GRE_SEQUENCE_NUM_FLG = 1 << 4 + + +class gre(packet_base.PacketBase): + """GRE (RFC2784,RFC2890) header encoder/decoder class. + + 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. + + ============== ======================================================== + Attribute Description + ============== ======================================================== + protocol Protocol Type field. + The Protocol Type is defined as "ETHER TYPES". + checksum Checksum field(optional). + When you set a value other than None, + this field will be automatically calculated. + key Key field(optional) + This field is intended to be used for identifying + an individual traffic flow within a tunnel. + seq_number Sequence Number field(optional) + ============== ======================================================== + """ + _PACK_STR = "!BBH" + _CHECKSUM_PACK_STR = "!H2x" + _KEY_PACK_STR = "!I" + _SEQNUM_PACK_STR = "!I" + _MIN_LEN = struct.calcsize(_PACK_STR) + _CHECKSUM_LEN = struct.calcsize(_CHECKSUM_PACK_STR) + _KEY_LEN = struct.calcsize(_KEY_PACK_STR) + + def __init__(self, protocol=ether.ETH_TYPE_IP, + checksum=None, key=None, seq_number=None): + super(gre, self).__init__() + + self.protocol = protocol + self.checksum = checksum + self.key = key + self.seq_number = seq_number + + @classmethod + def parser(cls, buf): + present, version, protocol = struct.unpack_from(cls._PACK_STR, buf) + gre_offset = gre._MIN_LEN + checksum = None + key = None + seq_number = None + + if present & GRE_CHECKSUM_FLG: + checksum, = struct.unpack_from(cls._CHECKSUM_PACK_STR, + buf, gre_offset) + gre_offset += cls._CHECKSUM_LEN + if present & GRE_KEY_FLG: + key, = struct.unpack_from(cls._KEY_PACK_STR, buf, gre_offset) + gre_offset += cls._KEY_LEN + if present & GRE_SEQUENCE_NUM_FLG: + seq_number, = struct.unpack_from(cls._SEQNUM_PACK_STR, + buf, gre_offset) + + msg = cls(protocol, checksum, key, seq_number) + + from . import ethernet + # Because the protocol type field could either Ethertype is set, + # Set the _TYPES of ethernet, which owns the Ethernet types + # available in Ryu. + gre._TYPES = ethernet.ethernet._TYPES + + return msg, gre.get_packet_type(protocol), buf[gre_offset:] + + def serialize(self, payload=None, prev=None): + present = 0 + version = 0 + hdr = bytearray() + optional = bytearray() + + if self.checksum: + present += GRE_CHECKSUM_FLG + + # For purposes of computing the checksum, + # the value of the checksum field is zero. + # Also, because Reserved1 is always 0x00 of 2 bytes, + # Set in conjunction with checksum. + optional += b'\x00' * self._CHECKSUM_LEN + + if self.key: + present += GRE_KEY_FLG + optional += struct.pack(self._KEY_PACK_STR, self.key) + + if self.seq_number: + present += GRE_SEQUENCE_NUM_FLG + optional += struct.pack(self._SEQNUM_PACK_STR, self.seq_number) + + msg_pack_into(self._PACK_STR, hdr, 0, + present, version, self.protocol) + + hdr += optional + + if self.checksum: + self.checksum = packet_utils.checksum(hdr) + struct.pack_into(self._CHECKSUM_PACK_STR, hdr, self._MIN_LEN, + self.checksum) + + return hdr diff --git a/ryu/lib/packet/in_proto.py b/ryu/lib/packet/in_proto.py index 64f59fd7..b2773789 100644 --- a/ryu/lib/packet/in_proto.py +++ b/ryu/lib/packet/in_proto.py @@ -22,6 +22,7 @@ IPPROTO_TCP = 6 IPPROTO_UDP = 17 IPPROTO_ROUTING = 43 IPPROTO_FRAGMENT = 44 +IPPROTO_GRE = 47 IPPROTO_AH = 51 IPPROTO_ICMPV6 = 58 IPPROTO_NONE = 59 diff --git a/ryu/lib/packet/ipv4.py b/ryu/lib/packet/ipv4.py index ac9b109d..2547f06a 100644 --- a/ryu/lib/packet/ipv4.py +++ b/ryu/lib/packet/ipv4.py @@ -23,6 +23,7 @@ from . import udp from . import tcp from . import sctp from . import ospf +from . import gre from . import in_proto as inet from ryu.lib import addrconv @@ -147,3 +148,4 @@ 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) ipv4.register_packet_type(ospf.ospf, inet.IPPROTO_OSPF) +ipv4.register_packet_type(gre.gre, inet.IPPROTO_GRE) diff --git a/ryu/lib/packet/ipv6.py b/ryu/lib/packet/ipv6.py index 6ed03187..3ab3aacf 100644 --- a/ryu/lib/packet/ipv6.py +++ b/ryu/lib/packet/ipv6.py @@ -21,6 +21,7 @@ from . import icmpv6 from . import tcp from . import udp from . import sctp +from . import gre from . import in_proto as inet from ryu.lib import addrconv from ryu.lib import stringify @@ -146,6 +147,7 @@ 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) +ipv6.register_packet_type(gre.gre, inet.IPPROTO_GRE) @six.add_metaclass(abc.ABCMeta) diff --git a/ryu/tests/unit/packet/test_gre.py b/ryu/tests/unit/packet/test_gre.py new file mode 100644 index 00000000..a2ca7296 --- /dev/null +++ b/ryu/tests/unit/packet/test_gre.py @@ -0,0 +1,81 @@ +# Copyright (C) 2016 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 unittest +import logging +import struct + +import six +from nose.tools import eq_, raises + +from ryu.lib.packet.gre import gre +from ryu.lib.packet.ether_types import ETH_TYPE_IP + +LOG = logging.getLogger(__name__) + + +class Test_gre(unittest.TestCase): + """ Test case for gre + """ + + protocol = ETH_TYPE_IP + checksum = 0x440d + key = 1000 + seq_number = 10 + + buf = struct.pack("!BBHH2xII", 0xb0, 0, protocol, checksum, key, seq_number) + gre = gre(protocol, checksum, key, seq_number) + + def setUp(self): + pass + + def tearDown(self): + pass + + def test_init(self): + eq_(self.protocol, self.gre.protocol) + eq_(self.checksum, self.gre.checksum) + eq_(self.key, self.gre.key) + eq_(self.seq_number, self.gre.seq_number) + + def test_parser(self): + res, _, _ = self.gre.parser(self.buf) + + eq_(res.protocol, self.protocol) + eq_(res.checksum, self.checksum) + eq_(res.key, self.key) + eq_(res.seq_number, self.seq_number) + + def test_serialize(self): + buf = self.gre.serialize() + res = struct.unpack_from("!BBHH2xII", six.binary_type(buf)) + + eq_(res[0], 0xb0) + eq_(res[1], 0) + eq_(res[2], self.protocol) + eq_(res[3], self.checksum) + eq_(res[4], self.key) + eq_(res[5], self.seq_number) + + @raises(Exception) + def test_malformed_gre(self): + m_short_buf = self.buf[1:gre._MIN_LEN] + gre.parser(m_short_buf) + + def test_json(self): + jsondict = self.gre.to_jsondict() + g = gre.from_jsondict(jsondict['gre']) + eq_(str(self.gre), str(g)) |