Coverage Report

Created: 2026-11-12 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
221k
    {
153
221k
      return port == DefaultPort;
154
221k
    }
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