Signed-off-by: Shinpei Muraoka <[email protected]>
---
 doc/source/library_packet_ref.rst |   3 +
 ryu/lib/packet/gre.py             | 129 ++++++++++++++++++++++++++++++++++++++
 ryu/lib/packet/in_proto.py        |   1 +
 ryu/lib/packet/ipv4.py            |   2 +
 ryu/lib/packet/ipv6.py            |   2 +
 ryu/tests/unit/packet/test_gre.py |  81 ++++++++++++++++++++++++
 6 files changed, 218 insertions(+)
 create mode 100644 ryu/lib/packet/gre.py
 create mode 100644 ryu/tests/unit/packet/test_gre.py

diff --git a/doc/source/library_packet_ref.rst 
b/doc/source/library_packet_ref.rst
index 4f17615..87f44a1 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 0000000..c22032e
--- /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 64f59fd..b277378 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 ac9b109..2547f06 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 6ed0318..3ab3aac 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 0000000..a2ca729
--- /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))
-- 
1.9.1


------------------------------------------------------------------------------
_______________________________________________
Ryu-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/ryu-devel

Reply via email to