1 # Copyright (C) 2016 Nippon Telegraph and Telephone Corporation.
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
18 from ryu.lib.pack_utils import msg_pack_into
19 from . import packet_base
20 from . import packet_utils
21 from . import ether_types
24 GRE_CHECKSUM_FLG = 1 << 7
26 GRE_SEQUENCE_NUM_FLG = 1 << 4
29 class gre(packet_base.PacketBase):
30 """GRE (RFC2784,RFC2890) header encoder/decoder class.
32 An instance has the following attributes at least.
33 Most of them are same to the on-wire counterparts but in host byte order.
34 __init__ takes the corresponding args in this order.
36 ============== ========================================================
38 ============== ========================================================
40 protocol Protocol Type field.
41 The Protocol Type is defined as "ETHER TYPES".
42 checksum Checksum field(optional).
43 When you set a value other than None,
44 this field will be automatically calculated.
45 key Key field(optional)
46 This field is intended to be used for identifying
47 an individual traffic flow within a tunnel.
48 vsid Virtual Subnet ID field(optional)
49 This field is a 24-bit value that is used
50 to identify the NVGRE-based Virtual Layer 2 Network.
51 flow_id FlowID field(optional)
52 This field is an 8-bit value that is used to provide
53 per-flow entropy for flows in the same VSID.
54 seq_number Sequence Number field(optional)
55 ============== ========================================================
58 _CHECKSUM_PACK_STR = "!H2x"
60 _SEQNUM_PACK_STR = "!I"
61 _MIN_LEN = struct.calcsize(_PACK_STR)
62 _CHECKSUM_LEN = struct.calcsize(_CHECKSUM_PACK_STR)
63 _KEY_LEN = struct.calcsize(_KEY_PACK_STR)
64 _SEQNUM_PACK_LEN = struct.calcsize(_SEQNUM_PACK_STR)
67 # 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
68 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
69 # |C| |K|S| Reserved0 | Ver | Protocol Type |
70 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
71 # | Checksum (optional) | Reserved1 (Optional) |
72 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
74 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
75 # | Sequence Number (Optional) |
76 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
78 def __init__(self, version=0, protocol=ether_types.ETH_TYPE_IP,
79 checksum=None, key=None, vsid=None, flow_id=None,
81 super(gre, self).__init__()
83 self.version = version
84 self.protocol = protocol
85 self.checksum = checksum
86 self.seq_number = seq_number
90 self._vsid = self._key >> 8
91 self._flow_id = self._key & 0xff
92 elif (vsid is not None) and (flow_id is not None):
93 self._key = vsid << 8 | flow_id
95 self._flow_id = flow_id
109 self._vsid = self._key >> 8
110 self._flow_id = self._key & 0xff
121 def vsid(self, vsid):
122 self._key = vsid << 8 | (self._key & 0xff)
130 def flow_id(self, flow_id):
131 self._key = (self._key & 0xffffff00) | flow_id
132 self._flow_id = flow_id
135 def parser(cls, buf):
136 present, version, protocol = struct.unpack_from(cls._PACK_STR, buf)
137 gre_offset = gre._MIN_LEN
142 if present & GRE_CHECKSUM_FLG:
143 checksum, = struct.unpack_from(cls._CHECKSUM_PACK_STR,
145 gre_offset += cls._CHECKSUM_LEN
146 if present & GRE_KEY_FLG:
147 key, = struct.unpack_from(cls._KEY_PACK_STR, buf, gre_offset)
148 gre_offset += cls._KEY_LEN
149 if present & GRE_SEQUENCE_NUM_FLG:
150 seq_number, = struct.unpack_from(cls._SEQNUM_PACK_STR,
152 gre_offset += cls._SEQNUM_PACK_LEN
154 msg = cls(version=version, protocol=protocol, checksum=checksum,
155 key=key, seq_number=seq_number)
157 from . import ethernet
158 gre._TYPES = ethernet.ethernet._TYPES
159 gre.register_packet_type(ethernet.ethernet,
160 ether_types.ETH_TYPE_TEB)
162 return msg, gre.get_packet_type(protocol), buf[gre_offset:]
164 def serialize(self, payload=None, prev=None):
167 optional = bytearray()
169 if self.checksum is not None:
170 present |= GRE_CHECKSUM_FLG
172 # For purposes of computing the checksum,
173 # the value of the checksum field is zero.
174 # Also, because Reserved1 is always 0x00 of 2 bytes,
175 # Set in conjunction with checksum.
176 optional += b'\x00' * self._CHECKSUM_LEN
178 if self._key is not None:
179 present |= GRE_KEY_FLG
180 optional += struct.pack(self._KEY_PACK_STR, self._key)
182 if self.seq_number is not None:
183 present |= GRE_SEQUENCE_NUM_FLG
184 optional += struct.pack(self._SEQNUM_PACK_STR, self.seq_number)
186 msg_pack_into(self._PACK_STR, hdr, 0, present, self.version,
192 self.checksum = packet_utils.checksum(hdr)
193 struct.pack_into(self._CHECKSUM_PACK_STR, hdr, self._MIN_LEN,
199 def nvgre(version=0, vsid=0, flow_id=0):
201 Generate instance of GRE class with information for NVGRE (RFC7637).
203 :param version: Version.
204 :param vsid: Virtual Subnet ID.
205 :param flow_id: FlowID.
206 :return: Instance of GRE class with information for NVGRE.
210 # 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
211 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
212 # |0| |1|0| Reserved0 | Ver | Protocol Type 0x6558 |
213 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
214 # | Virtual Subnet ID (VSID) | FlowID |
215 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
216 return gre(version=version, protocol=ether_types.ETH_TYPE_TEB,
217 vsid=vsid, flow_id=flow_id)