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>
This commit is contained in:
parent
4ca81f9624
commit
d0992e24ae
@ -50,6 +50,9 @@ Protocol Header classes
|
|||||||
.. automodule:: ryu.lib.packet.icmpv6
|
.. automodule:: ryu.lib.packet.icmpv6
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
.. automodule:: ryu.lib.packet.gre
|
||||||
|
:members:
|
||||||
|
|
||||||
.. automodule:: ryu.lib.packet.cfm
|
.. automodule:: ryu.lib.packet.cfm
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
129
ryu/lib/packet/gre.py
Normal file
129
ryu/lib/packet/gre.py
Normal file
@ -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
|
@ -22,6 +22,7 @@ IPPROTO_TCP = 6
|
|||||||
IPPROTO_UDP = 17
|
IPPROTO_UDP = 17
|
||||||
IPPROTO_ROUTING = 43
|
IPPROTO_ROUTING = 43
|
||||||
IPPROTO_FRAGMENT = 44
|
IPPROTO_FRAGMENT = 44
|
||||||
|
IPPROTO_GRE = 47
|
||||||
IPPROTO_AH = 51
|
IPPROTO_AH = 51
|
||||||
IPPROTO_ICMPV6 = 58
|
IPPROTO_ICMPV6 = 58
|
||||||
IPPROTO_NONE = 59
|
IPPROTO_NONE = 59
|
||||||
|
@ -23,6 +23,7 @@ from . import udp
|
|||||||
from . import tcp
|
from . import tcp
|
||||||
from . import sctp
|
from . import sctp
|
||||||
from . import ospf
|
from . import ospf
|
||||||
|
from . import gre
|
||||||
from . import in_proto as inet
|
from . import in_proto as inet
|
||||||
from ryu.lib import addrconv
|
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(udp.udp, inet.IPPROTO_UDP)
|
||||||
ipv4.register_packet_type(sctp.sctp, inet.IPPROTO_SCTP)
|
ipv4.register_packet_type(sctp.sctp, inet.IPPROTO_SCTP)
|
||||||
ipv4.register_packet_type(ospf.ospf, inet.IPPROTO_OSPF)
|
ipv4.register_packet_type(ospf.ospf, inet.IPPROTO_OSPF)
|
||||||
|
ipv4.register_packet_type(gre.gre, inet.IPPROTO_GRE)
|
||||||
|
@ -21,6 +21,7 @@ from . import icmpv6
|
|||||||
from . import tcp
|
from . import tcp
|
||||||
from . import udp
|
from . import udp
|
||||||
from . import sctp
|
from . import sctp
|
||||||
|
from . import gre
|
||||||
from . import in_proto as inet
|
from . import in_proto as inet
|
||||||
from ryu.lib import addrconv
|
from ryu.lib import addrconv
|
||||||
from ryu.lib import stringify
|
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(tcp.tcp, inet.IPPROTO_TCP)
|
||||||
ipv6.register_packet_type(udp.udp, inet.IPPROTO_UDP)
|
ipv6.register_packet_type(udp.udp, inet.IPPROTO_UDP)
|
||||||
ipv6.register_packet_type(sctp.sctp, inet.IPPROTO_SCTP)
|
ipv6.register_packet_type(sctp.sctp, inet.IPPROTO_SCTP)
|
||||||
|
ipv6.register_packet_type(gre.gre, inet.IPPROTO_GRE)
|
||||||
|
|
||||||
|
|
||||||
@six.add_metaclass(abc.ABCMeta)
|
@six.add_metaclass(abc.ABCMeta)
|
||||||
|
81
ryu/tests/unit/packet/test_gre.py
Normal file
81
ryu/tests/unit/packet/test_gre.py
Normal file
@ -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))
|
Loading…
Reference in New Issue
Block a user