diff options
-rw-r--r-- | ryu/lib/packet/gre.py | 128 |
1 files changed, 108 insertions, 20 deletions
diff --git a/ryu/lib/packet/gre.py b/ryu/lib/packet/gre.py index c22032e9..a62f0d18 100644 --- a/ryu/lib/packet/gre.py +++ b/ryu/lib/packet/gre.py @@ -15,10 +15,10 @@ import struct +from ryu.lib.pack_utils import msg_pack_into from . import packet_base from . import packet_utils -from . import ether_types as ether -from ryu.lib.pack_utils import msg_pack_into +from . import ether_types GRE_CHECKSUM_FLG = 1 << 7 @@ -36,6 +36,7 @@ class gre(packet_base.PacketBase): ============== ======================================================== Attribute Description ============== ======================================================== + version Version. protocol Protocol Type field. The Protocol Type is defined as "ETHER TYPES". checksum Checksum field(optional). @@ -44,6 +45,12 @@ class gre(packet_base.PacketBase): key Key field(optional) This field is intended to be used for identifying an individual traffic flow within a tunnel. + vsid Virtual Subnet ID field(optional) + This field is a 24-bit value that is used + to identify the NVGRE-based Virtual Layer 2 Network. + flow_id FlowID field(optional) + This field is an 8-bit value that is used to provide + per-flow entropy for flows in the same VSID. seq_number Sequence Number field(optional) ============== ======================================================== """ @@ -54,16 +61,76 @@ class gre(packet_base.PacketBase): _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): + _SEQNUM_PACK_LEN = struct.calcsize(_SEQNUM_PACK_STR) + + # GRE header + # 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 + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # |C| |K|S| Reserved0 | Ver | Protocol Type | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | Checksum (optional) | Reserved1 (Optional) | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | Key (optional) | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | Sequence Number (Optional) | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + def __init__(self, version=0, protocol=ether_types.ETH_TYPE_IP, + checksum=None, key=None, vsid=None, flow_id=None, + seq_number=None): super(gre, self).__init__() + self.version = version self.protocol = protocol self.checksum = checksum - self.key = key self.seq_number = seq_number + if key is not None: + self._key = key + self._vsid = self._key >> 8 + self._flow_id = self._key & 0xff + elif (vsid is not None) and (flow_id is not None): + self._key = vsid << 8 | flow_id + self._vsid = vsid + self._flow_id = flow_id + else: + self._key = None + self._vsid = None + self._flow_id = None + + @property + def key(self): + return self._key + + @key.setter + def key(self, key): + if key is not None: + self._key = key + self._vsid = self._key >> 8 + self._flow_id = self._key & 0xff + else: + self._key = None + self._vsid = None + self._flow_id = None + + @property + def vsid(self): + return self._vsid + + @vsid.setter + def vsid(self, vsid): + self._key = vsid << 8 | (self._key & 0xff) + self._vsid = vsid + + @property + def flow_id(self): + return self._flow_id + + @flow_id.setter + def flow_id(self, flow_id): + self._key = (self._key & 0xffffff00) | flow_id + self._flow_id = flow_id + @classmethod def parser(cls, buf): present, version, protocol = struct.unpack_from(cls._PACK_STR, buf) @@ -82,25 +149,25 @@ class gre(packet_base.PacketBase): if present & GRE_SEQUENCE_NUM_FLG: seq_number, = struct.unpack_from(cls._SEQNUM_PACK_STR, buf, gre_offset) + gre_offset += cls._SEQNUM_PACK_LEN - msg = cls(protocol, checksum, key, seq_number) + msg = cls(version=version, protocol=protocol, checksum=checksum, + key=key, seq_number=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 + gre.register_packet_type(ethernet.ethernet, + ether_types.ETH_TYPE_TEB) 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 + if self.checksum is not None: + present |= GRE_CHECKSUM_FLG # For purposes of computing the checksum, # the value of the checksum field is zero. @@ -108,16 +175,16 @@ class gre(packet_base.PacketBase): # 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._key is not None: + present |= GRE_KEY_FLG + optional += struct.pack(self._KEY_PACK_STR, self._key) - if self.seq_number: - present += GRE_SEQUENCE_NUM_FLG + if self.seq_number is not None: + 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) + msg_pack_into(self._PACK_STR, hdr, 0, present, self.version, + self.protocol) hdr += optional @@ -127,3 +194,24 @@ class gre(packet_base.PacketBase): self.checksum) return hdr + + +def nvgre(version=0, vsid=0, flow_id=0): + """ + Generate instance of GRE class with information for NVGRE (RFC7637). + + :param version: Version. + :param vsid: Virtual Subnet ID. + :param flow_id: FlowID. + :return: Instance of GRE class with information for NVGRE. + """ + + # NVGRE header + # 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 + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # |0| |1|0| Reserved0 | Ver | Protocol Type 0x6558 | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | Virtual Subnet ID (VSID) | FlowID | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + return gre(version=version, protocol=ether_types.ETH_TYPE_TEB, + vsid=vsid, flow_id=flow_id) |