/src/PcapPlusPlus/Packet++/header/GeneveLayer.h
Line | Count | Source |
1 | | #pragma once |
2 | | |
3 | | #include "EthLayer.h" |
4 | | #include "Layer.h" |
5 | | |
6 | | /// @file |
7 | | |
8 | | /// @namespace pcpp |
9 | | /// @brief The main namespace for the PcapPlusPlus lib |
10 | | namespace pcpp |
11 | | { |
12 | | class GeneveLayer; |
13 | | |
14 | | /// @class GeneveOption |
15 | | /// A non-owning view of a GENEVE option. The view is invalidated when its underlying data is destroyed or moved, |
16 | | /// including when options are added to or removed from the containing GeneveLayer |
17 | | class GeneveOption |
18 | | { |
19 | | friend class GeneveLayer; |
20 | | |
21 | | private: |
22 | | #pragma pack(push, 1) |
23 | | struct geneve_option_header |
24 | | { |
25 | | uint16_t optionClass; |
26 | | uint8_t type; |
27 | | #if (BYTE_ORDER == LITTLE_ENDIAN) |
28 | | uint8_t length : 5; |
29 | | uint8_t reserved : 3; |
30 | | #else |
31 | | uint8_t reserved : 3; |
32 | | uint8_t length : 5; |
33 | | #endif |
34 | | }; |
35 | | #pragma pack(pop) |
36 | | static_assert(sizeof(geneve_option_header) == 4, "geneve_option_header size is not 4 bytes"); |
37 | | |
38 | | static constexpr size_t HeaderLength = sizeof(geneve_option_header); |
39 | | static constexpr size_t DataLengthUnit = 4; |
40 | | static constexpr size_t MaxDataLength = ((1 << 5) - 1) * DataLengthUnit; |
41 | | static constexpr uint8_t TypeMask = 0x7f; |
42 | | static constexpr uint8_t CriticalBitMask = 0x80; |
43 | | |
44 | | geneve_option_header* m_Data; |
45 | | |
46 | | /// Construct a view over an option encoded at optionData. |
47 | 292 | explicit GeneveOption(uint8_t* optionData) : m_Data(reinterpret_cast<geneve_option_header*>(optionData)) |
48 | 292 | {} |
49 | | |
50 | | static bool canAssign(const uint8_t* optionRawData, size_t optionDataLen); |
51 | | void setOptionClass(uint16_t value); |
52 | | void setType(uint8_t value, bool critical); |
53 | | void setDataSize(size_t value); |
54 | | |
55 | | static uint8_t extractType(uint8_t value) |
56 | 0 | { |
57 | 0 | return static_cast<uint8_t>(value & TypeMask); |
58 | 0 | } |
59 | | |
60 | | static size_t alignDataSize(size_t value) |
61 | 0 | { |
62 | 0 | constexpr size_t AlignmentMask = DataLengthUnit - 1; |
63 | 0 | return (value + AlignmentMask) & ~AlignmentMask; |
64 | 0 | } |
65 | | |
66 | | uint8_t* getRecordBasePtr() const |
67 | 0 | { |
68 | 0 | return reinterpret_cast<uint8_t*>(m_Data); |
69 | 0 | } |
70 | | |
71 | | public: |
72 | | /// Construct a null option view. |
73 | 383 | GeneveOption() : m_Data(nullptr) |
74 | 383 | {} |
75 | | |
76 | | /// @return True if this option view does not refer to a complete option |
77 | | bool isNull() const |
78 | 967 | { |
79 | 967 | return m_Data == nullptr; |
80 | 967 | } |
81 | | |
82 | | /// @return Option class in host byte order, or zero if this option is null |
83 | | uint16_t getOptionClass() const; |
84 | | |
85 | | /// @return The 7-bit option type without the critical bit, or zero if this option is null |
86 | | uint8_t getType() const; |
87 | | |
88 | | /// @return True if the option is critical, or false if this option is null |
89 | | bool isCritical() const; |
90 | | |
91 | | /// @return Option data length in bytes, or zero if this option is null |
92 | | size_t getDataSize() const; |
93 | | |
94 | | /// @return Total option size including its 4-byte header, or zero if this option is null |
95 | | size_t getTotalSize() const; |
96 | | |
97 | | /// @return A pointer to the option data, or nullptr if this option is null |
98 | | uint8_t* getData() const; |
99 | | |
100 | | /// @return True if both options are null or have the same class, type, critical flag, and data |
101 | | bool operator==(const GeneveOption& other) const; |
102 | | |
103 | | /// @return True if the options are not equal according to operator== |
104 | | bool operator!=(const GeneveOption& other) const |
105 | 0 | { |
106 | 0 | return !(*this == other); |
107 | 0 | } |
108 | | }; |
109 | | /// @class GeneveLayer |
110 | | /// Represents a GENEVE (Generic Network Virtualization Encapsulation) protocol layer. |
111 | | /// Layer methods assume that the fixed header and its declared options area are complete. Data passed to the |
112 | | /// raw-data constructor must first pass isDataValid(); crafted layers establish this layout internally. Callers |
113 | | /// modifying raw layer data must preserve this layout. Individual options may still be malformed and are checked |
114 | | /// during traversal. |
115 | | class GeneveLayer : public Layer |
116 | | { |
117 | | public: |
118 | | /// The IANA-assigned UDP destination port for GENEVE |
119 | | static constexpr uint16_t DefaultPort = 6081; |
120 | | |
121 | | /// Construct a layer from existing packet data |
122 | | /// @param[in] data A pointer to the raw data |
123 | | /// @param[in] dataLen Size of the data in bytes |
124 | | /// @param[in] prevLayer A pointer to the previous layer |
125 | | /// @param[in] packet A pointer to the Packet instance where the layer is stored |
126 | | /// @note This constructor does not validate the input. The caller must ensure isDataValid(data, dataLen) |
127 | | /// returns true before calling it. |
128 | | GeneveLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) |
129 | 5.66k | : Layer(data, dataLen, prevLayer, packet, Geneve) |
130 | 5.66k | {} |
131 | | |
132 | | /// Construct a new GENEVE layer |
133 | | /// @param[in] vni The 24-bit virtual network identifier |
134 | | /// @param[in] protocolType EtherType of the encapsulated protocol. Defaults to Transparent Ethernet Bridging |
135 | | /// @param[in] oamFlag Set the operations, administration, and maintenance flag |
136 | | explicit GeneveLayer(uint32_t vni = 0, uint16_t protocolType = PCPP_ETHERTYPE_ETHBRIDGE, bool oamFlag = false); |
137 | | |
138 | | ~GeneveLayer() override = default; |
139 | | |
140 | | /// Validate the fixed GENEVE header and its declared options area. |
141 | | /// @param[in] data The beginning of the GENEVE header |
142 | | /// @param[in] dataLen Available bytes |
143 | | /// @return True if the fixed header is supported and the declared options area fits in dataLen |
144 | | /// @note This is a fast-path check and does not parse individual options. Option accessors take into account |
145 | | /// that the data might be malformed and return a null option when an option cannot be read safely. |
146 | | static bool isDataValid(const uint8_t* data, size_t dataLen); |
147 | | |
148 | | /// Check whether a UDP port is the standard GENEVE destination port |
149 | | /// @param[in] port UDP port in host byte order |
150 | | /// @return True for port 6081 |
151 | | static bool isGenevePort(uint16_t port) |
152 | 619k | { |
153 | 619k | return port == DefaultPort; |
154 | 619k | } |
155 | | |
156 | | /// @return The VNI in host byte order |
157 | | uint32_t getVNI() const; |
158 | | |
159 | | /// Set the VNI. Only the least significant 24 bits are used |
160 | | /// @param[in] vni The VNI to set |
161 | | void setVNI(uint32_t vni); |
162 | | |
163 | | /// @return Encapsulated protocol EtherType in host byte order |
164 | | uint16_t getProtocolType() const; |
165 | | |
166 | | /// Set the encapsulated protocol EtherType |
167 | | /// @param[in] protocolType EtherType in host byte order |
168 | | void setProtocolType(uint16_t protocolType); |
169 | | |
170 | | /// @return True if the GENEVE OAM flag is set |
171 | | bool getOamFlag() const; |
172 | | |
173 | | /// Set the GENEVE OAM flag |
174 | | /// @param[in] value Whether to set the OAM flag |
175 | | void setOamFlag(bool value); |
176 | | |
177 | | /// @return True if the GENEVE critical options flag is set |
178 | | bool getCriticalFlag() const; |
179 | | |
180 | | /// @return Total options length in bytes declared by the fixed header |
181 | | size_t getOptionsLength() const; |
182 | | |
183 | | /// @return Number of options that can be traversed safely before malformed data, in this layer |
184 | | size_t getOptionCount() const; |
185 | | |
186 | | /// @return The first option, or a null option if no complete option is available |
187 | | GeneveOption getFirstOption() const; |
188 | | |
189 | | /// Get the option following a previous option. |
190 | | /// @param[in] option An option previously returned by this layer |
191 | | /// @return The next option, or a null option if the input is null, malformed, doesn't belong to this layer, is |
192 | | /// the last option, or the next option is malformed |
193 | | GeneveOption getNextOption(const GeneveOption& option) const; |
194 | | |
195 | | /// Find the first option with the given class and type. |
196 | | /// @param[in] optionClass Option namespace assigned by IANA |
197 | | /// @param[in] optionType The 7-bit option type |
198 | | /// @return The matching option, or a null option if it is not present or traversal reaches malformed data |
199 | | GeneveOption getOption(uint16_t optionClass, uint8_t optionType) const; |
200 | | |
201 | | /// Add an option after all existing options. Option data is padded with zeroes to a 4-byte boundary. |
202 | | /// @param[in] optionClass Option namespace assigned by IANA |
203 | | /// @param[in] optionType The 7-bit option type |
204 | | /// @param[in] optionData A read-only buffer containing option data |
205 | | /// @param[in] optionDataLen Option data length in bytes. The maximum supported length is 124 bytes |
206 | | /// @param[in] critical Set the option critical bit |
207 | | /// @return True if the option was added successfully |
208 | | bool addOption(uint16_t optionClass, uint8_t optionType, const uint8_t* optionData, size_t optionDataLen, |
209 | | bool critical = false); |
210 | | |
211 | | /// Remove the first option matching a class and type |
212 | | /// @param[in] optionClass Option class in host byte order |
213 | | /// @param[in] optionType The 7-bit option type |
214 | | /// @return True if an option was found and removed |
215 | | bool removeOption(uint16_t optionClass, uint8_t optionType); |
216 | | |
217 | | /// Remove all options |
218 | | /// @return True if all options were removed |
219 | | bool removeAllOptions(); |
220 | | |
221 | | /// Parse the encapsulated protocol according to the Protocol Type field. |
222 | | /// Supported next layers are IPv4, ARP, IPv6, VLAN/QinQ, MPLS, Ethernet and EthernetDot3; unsupported or |
223 | | /// malformed payloads are represented as a generic PayloadLayer. |
224 | | void parseNextLayer() override; |
225 | | |
226 | | /// @return The fixed header plus the declared options length |
227 | | size_t getHeaderLen() const override; |
228 | | |
229 | | /// Update the Protocol Type and Critical flag from the following layer and options |
230 | | void computeCalculateFields() override; |
231 | | |
232 | | std::string toString() const override; |
233 | | |
234 | | OsiModelLayer getOsiModelLayer() const override |
235 | 675 | { |
236 | 675 | return OsiModelDataLinkLayer; |
237 | 675 | } |
238 | | |
239 | | /// @struct SerializedFields |
240 | | /// Fields written by GeneveLayer's serializeLayer(), in addition to |
241 | | /// Layer::SerializedFields. |
242 | | struct SerializedFields : Layer::SerializedFields |
243 | | { |
244 | | /// @return All field descriptors for GeneveLayer |
245 | | static std::vector<FieldDescriptor> all() |
246 | 0 | { |
247 | 0 | auto result = Layer::SerializedFields::all(); |
248 | 0 | std::initializer_list<FieldDescriptor> extra{ OptionsLength, ProtocolType, VNI, |
249 | 0 | OamFlag, CriticalFlag, Options }; |
250 | 0 | std::copy(extra.begin(), extra.end(), std::back_inserter(result)); |
251 | 0 | return result; |
252 | 0 | } |
253 | | |
254 | | /// @struct OptionObject |
255 | | /// Fields describing one element of the options array. |
256 | | struct OptionObject : ObjectFieldDescriptor<OptionObject> |
257 | | { |
258 | | using ObjectFieldDescriptor::ObjectFieldDescriptor; |
259 | | |
260 | | /// @return All field descriptors for one GENEVE option |
261 | | static std::vector<FieldDescriptor> all() |
262 | 0 | { |
263 | 0 | return { OptionClass, Type, Critical, DataSize }; |
264 | 0 | } |
265 | | |
266 | | /// @brief Option class in host byte order |
267 | | static const FieldDescriptor OptionClass; |
268 | | |
269 | | /// @brief Option type without the critical bit |
270 | | static const FieldDescriptor Type; |
271 | | |
272 | | /// @brief True if the option critical bit is set |
273 | | static const FieldDescriptor Critical; |
274 | | |
275 | | /// @brief Option data length in bytes |
276 | | static const FieldDescriptor DataSize; |
277 | | }; |
278 | | |
279 | | /// @brief Total options length in bytes declared by the GENEVE header |
280 | | static const FieldDescriptor OptionsLength; |
281 | | |
282 | | /// @brief Encapsulated protocol EtherType in host byte order |
283 | | static const FieldDescriptor ProtocolType; |
284 | | |
285 | | /// @brief The 24-bit virtual network identifier |
286 | | static const FieldDescriptor VNI; |
287 | | |
288 | | /// @brief True if the GENEVE OAM flag is set |
289 | | static const FieldDescriptor OamFlag; |
290 | | |
291 | | /// @brief True if the GENEVE critical options flag is set |
292 | | static const FieldDescriptor CriticalFlag; |
293 | | |
294 | | /// @brief GENEVE options |
295 | | static const FieldDescriptor Options; |
296 | | |
297 | | /// Descriptor for one element of the options array |
298 | | static const OptionObject Option; |
299 | | }; |
300 | | |
301 | | protected: |
302 | | void serializeLayer(ObjectScope& serializer) const override; |
303 | | |
304 | | private: |
305 | | #pragma pack(push, 1) |
306 | | struct geneve_header |
307 | | { |
308 | | #if (BYTE_ORDER == LITTLE_ENDIAN) |
309 | | uint8_t optionsLength : 6; |
310 | | uint8_t version : 2; |
311 | | uint8_t reserved1 : 6; |
312 | | uint8_t criticalFlag : 1; |
313 | | uint8_t oamFlag : 1; |
314 | | #else |
315 | | uint8_t version : 2; |
316 | | uint8_t optionsLength : 6; |
317 | | uint8_t oamFlag : 1; |
318 | | uint8_t criticalFlag : 1; |
319 | | uint8_t reserved1 : 6; |
320 | | #endif |
321 | | uint16_t protocolType; |
322 | | uint8_t vni[3]; |
323 | | uint8_t reserved2; |
324 | | }; |
325 | | #pragma pack(pop) |
326 | | static_assert(sizeof(geneve_header) == 8, "geneve_header size is not 8 bytes"); |
327 | | |
328 | | static constexpr size_t HeaderLength = sizeof(geneve_header); |
329 | | static constexpr size_t OptionsLengthUnit = 4; |
330 | | static constexpr size_t MaxOptionsLength = ((1 << 6) - 1) * OptionsLengthUnit; |
331 | | |
332 | | geneve_header* getGeneveHeader() const |
333 | 16.9k | { |
334 | 16.9k | return reinterpret_cast<geneve_header*>(m_Data); |
335 | 16.9k | } |
336 | | |
337 | | void setOptionsLength(size_t value); |
338 | | |
339 | | void updateCriticalFlag(); |
340 | | }; |
341 | | } // namespace pcpp |