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>
This commit is contained in:
parent
6ea6e86e16
commit
b6c1189cc9
@ -56,6 +56,9 @@ Protocol Header classes
|
|||||||
.. automodule:: ryu.lib.packet.vxlan
|
.. automodule:: ryu.lib.packet.vxlan
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
.. automodule:: ryu.lib.packet.geneve
|
||||||
|
:members:
|
||||||
|
|
||||||
.. automodule:: ryu.lib.packet.gre
|
.. automodule:: ryu.lib.packet.gre
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
ETH_TYPE_IP = 0x0800
|
ETH_TYPE_IP = 0x0800
|
||||||
ETH_TYPE_ARP = 0x0806
|
ETH_TYPE_ARP = 0x0806
|
||||||
|
ETH_TYPE_TEB = 0x6558
|
||||||
ETH_TYPE_8021Q = 0x8100
|
ETH_TYPE_8021Q = 0x8100
|
||||||
ETH_TYPE_IPV6 = 0x86dd
|
ETH_TYPE_IPV6 = 0x86dd
|
||||||
ETH_TYPE_SLOW = 0x8809
|
ETH_TYPE_SLOW = 0x8809
|
||||||
|
189
ryu/lib/packet/geneve.py
Normal file
189
ryu/lib/packet/geneve.py
Normal file
@ -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
|
@ -19,6 +19,7 @@ from . import packet_base
|
|||||||
from . import packet_utils
|
from . import packet_utils
|
||||||
from . import dhcp
|
from . import dhcp
|
||||||
from . import vxlan
|
from . import vxlan
|
||||||
|
from . import geneve
|
||||||
|
|
||||||
|
|
||||||
class udp(packet_base.PacketBase):
|
class udp(packet_base.PacketBase):
|
||||||
@ -60,6 +61,8 @@ class udp(packet_base.PacketBase):
|
|||||||
if (dst_port == vxlan.UDP_DST_PORT or
|
if (dst_port == vxlan.UDP_DST_PORT or
|
||||||
dst_port == vxlan.UDP_DST_PORT_OLD):
|
dst_port == vxlan.UDP_DST_PORT_OLD):
|
||||||
return vxlan.vxlan
|
return vxlan.vxlan
|
||||||
|
if dst_port == geneve.UDP_DST_PORT:
|
||||||
|
return geneve.geneve
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
Loading…
Reference in New Issue
Block a user