summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorShinpei Muraoka <shinpei.muraoka@gmail.com>2016-12-20 11:46:36 +0900
committerFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2016-12-29 22:04:20 +0900
commitb6c1189cc90ea6301caca15164041a2733617769 (patch)
treeb5812c1a33d10af1c74f082153e8befa274c2f7d
parent6ea6e86e16d1aa7379322db9e9ad3cbd35f1ad7d (diff)
packet lib: Add packet library of Geneve
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.rst3
-rw-r--r--ryu/lib/packet/ether_types.py1
-rw-r--r--ryu/lib/packet/geneve.py189
-rw-r--r--ryu/lib/packet/udp.py3
4 files changed, 196 insertions, 0 deletions
diff --git a/doc/source/library_packet_ref.rst b/doc/source/library_packet_ref.rst
index 29c68a20..56c09f9f 100644
--- a/doc/source/library_packet_ref.rst
+++ b/doc/source/library_packet_ref.rst
@@ -56,6 +56,9 @@ Protocol Header classes
.. automodule:: ryu.lib.packet.vxlan
:members:
+.. automodule:: ryu.lib.packet.geneve
+ :members:
+
.. automodule:: ryu.lib.packet.gre
:members:
diff --git a/ryu/lib/packet/ether_types.py b/ryu/lib/packet/ether_types.py
index bfa78995..e8287d3b 100644
--- a/ryu/lib/packet/ether_types.py
+++ b/ryu/lib/packet/ether_types.py
@@ -16,6 +16,7 @@
ETH_TYPE_IP = 0x0800
ETH_TYPE_ARP = 0x0806
+ETH_TYPE_TEB = 0x6558
ETH_TYPE_8021Q = 0x8100
ETH_TYPE_IPV6 = 0x86dd
ETH_TYPE_SLOW = 0x8809
diff --git a/ryu/lib/packet/geneve.py b/ryu/lib/packet/geneve.py
new file mode 100644
index 00000000..6cbba495
--- /dev/null
+++ b/ryu/lib/packet/geneve.py
@@ -0,0 +1,189 @@
+# 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.
+
+"""
+Geneve packet parser/serializer
+"""
+
+import struct
+
+from ryu.lib import stringify
+from ryu.lib import type_desc
+from . import packet_base
+from . import ether_types
+
+
+UDP_DST_PORT = 6081
+
+
+class geneve(packet_base.PacketBase):
+ """Geneve (RFC draft-ietf-nvo3-geneve-03) 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
+ ============== ========================================================
+ version Version.
+ opt_len The length of the options fields.
+ flags Flag field for OAM packet and Critical options present.
+ protocol Protocol Type field.
+ The Protocol Type is defined as "ETHER TYPES".
+ vni Identifier for unique element of virtual network.
+ options List of ``Option*`` instance.
+ ============== ========================================================
+ """
+ _HEADER_FMT = "!BBHI"
+ _MIN_LEN = struct.calcsize(_HEADER_FMT)
+
+ # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # |Ver| Opt Len |O|C| Rsvd. | Protocol Type |
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | Virtual Network Identifier (VNI) | Reserved |
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | Variable Length Options |
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ # Flags
+ OAM_PACKET_FLAG = 1 << 7
+ CRITICAL_OPTIONS_FLAG = 1 << 6
+
+ def __init__(self, version=0, opt_len=0, flags=0,
+ protocol=ether_types.ETH_TYPE_TEB, vni=None, options=None):
+ super(geneve, self).__init__()
+
+ self.version = version
+ self.opt_len = opt_len
+ assert (flags & 0x3F) == 0
+ self.flags = flags
+ self.protocol = protocol
+ self.vni = vni
+ for o in options:
+ assert isinstance(o, Option)
+ self.options = options
+
+ @classmethod
+ def parser(cls, buf):
+ (ver_opt_len, flags, protocol,
+ vni) = struct.unpack_from(cls._HEADER_FMT, buf)
+ version = ver_opt_len >> 6
+ # The Opt Len field expressed in four byte multiples.
+ opt_len = (ver_opt_len & 0x3F) * 4
+
+ opt_bin = buf[cls._MIN_LEN:cls._MIN_LEN + opt_len]
+ options = []
+ while opt_bin:
+ option, opt_bin = Option.parser(opt_bin)
+ options.append(option)
+
+ msg = cls(version, opt_len, flags, protocol, vni >> 8, options)
+
+ from . import ethernet
+ geneve._TYPES = ethernet.ethernet._TYPES
+ geneve.register_packet_type(ethernet.ethernet,
+ ether_types.ETH_TYPE_TEB)
+
+ return (msg, geneve.get_packet_type(protocol),
+ buf[cls._MIN_LEN + opt_len:])
+
+ def serialize(self, payload=None, prev=None):
+ tunnel_options = bytearray()
+ for o in self.options:
+ tunnel_options += o.serialize()
+ self.opt_len = len(tunnel_options)
+ # The Opt Len field expressed in four byte multiples.
+ opt_len = self.opt_len // 4
+
+ return (struct.pack(self._HEADER_FMT,
+ (self.version << 6) | opt_len,
+ self.flags, self.protocol, self.vni << 8)
+ + tunnel_options)
+
+
+class Option(stringify.StringifyMixin, type_desc.TypeDisp):
+ """
+ Tunnel Options
+ """
+ _OPTION_PACK_STR = "!HBB"
+ _OPTION_LEN = struct.calcsize(_OPTION_PACK_STR)
+
+ # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | Option Class | Type |R|R|R| Length |
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ # | Variable Option Data |
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ def __init__(self, option_class=None, type_=None, length=0):
+ super(Option, self).__init__()
+ if option_class is None or type_ is None:
+ (option_class, type_) = self._rev_lookup_type(self.__class__)
+ self.option_class = option_class
+ self.type = type_
+ self.length = length
+
+ @classmethod
+ def parse_value(cls, buf):
+ # Sub-classes should override this method, if needed.
+ return {}
+
+ def serialize_value(self):
+ # Sub-classes should override this method, if needed.
+ return b''
+
+ @classmethod
+ def parser(cls, buf):
+ (option_class, type_,
+ length) = struct.unpack_from(cls._OPTION_PACK_STR, buf)
+
+ # The Length field expressed in four byte multiples.
+ length *= 4
+ subcls = Option._lookup_type((option_class, type_))
+
+ return (
+ subcls(option_class=option_class, type_=type_, length=length,
+ **subcls.parse_value(
+ buf[cls._OPTION_LEN:cls._OPTION_LEN + length])),
+ buf[cls._OPTION_LEN + length:])
+
+ def serialize(self, _payload=None, _prev=None):
+ data = self.serialize_value()
+ self.length = len(data)
+ # The Length field expressed in four byte multiples.
+ length = self.length // 4
+
+ return (struct.pack(self._OPTION_PACK_STR, int(self.option_class),
+ self.type, length) + data)
+
+
+@Option.register_unknown_type()
+class OptionDataUnknown(Option):
+ """
+ Unknown Option Class and Type specific Option
+ """
+ def __init__(self, buf, option_class=None, type_=None, length=0):
+ super(OptionDataUnknown, self).__init__(option_class=option_class,
+ type_=type_,
+ length=length)
+ self.buf = buf
+
+ @classmethod
+ def parse_value(cls, buf):
+ return {"buf": buf}
+
+ def serialize_value(self):
+ return self.buf
diff --git a/ryu/lib/packet/udp.py b/ryu/lib/packet/udp.py
index f39fb901..9d3ed3c5 100644
--- a/ryu/lib/packet/udp.py
+++ b/ryu/lib/packet/udp.py
@@ -19,6 +19,7 @@ from . import packet_base
from . import packet_utils
from . import dhcp
from . import vxlan
+from . import geneve
class udp(packet_base.PacketBase):
@@ -60,6 +61,8 @@ class udp(packet_base.PacketBase):
if (dst_port == vxlan.UDP_DST_PORT or
dst_port == vxlan.UDP_DST_PORT_OLD):
return vxlan.vxlan
+ if dst_port == geneve.UDP_DST_PORT:
+ return geneve.geneve
return None
@classmethod