VBVX 0.1.0
Header-only C++23 library for safe, zero-copy parsing of packet buffers.
Loading...
Searching...
No Matches
srv6_header.hxx
Go to the documentation of this file.
1#pragma once
2
3#include <cstdint>
4#include <optional>
5#include <span>
6
7#include "utils.hxx"
8
9namespace vbvx {
10
12enum class SRv6TlvType : uint8_t { Pad1 = 0u, PadN = 4u, Hmac = 5u };
13
22struct [[gnu::packed]] SRv6Header {
23 uint8_t next_header;
24 uint8_t hdr_ext_len;
25 uint8_t routing_type;
27 uint8_t last_entry;
28 uint8_t flags;
29 uint16_t tag_be;
30
31 constexpr auto header_length_bytes() const noexcept -> uint16_t {
32 return ((static_cast<uint16_t>(hdr_ext_len) + 1u) * 8u);
33 }
34
35 constexpr auto last_entry_index() const noexcept -> uint8_t {
36 return last_entry;
37 }
38
39 constexpr auto segments_count() const noexcept -> uint8_t {
40 return static_cast<uint8_t>(static_cast<uint8_t>(last_entry) + 1u);
41 }
42
43 constexpr auto tag() const noexcept -> uint16_t { return autoswap(tag_be); }
44
45 constexpr auto routing_type_value() const noexcept -> uint8_t {
46 return routing_type;
47 }
48
49 constexpr bool is_valid_routing_type() const noexcept {
50 return routing_type == 4u;
51 }
52
53 constexpr auto segment_list_ptr() const noexcept -> const uint8_t* {
54 return reinterpret_cast<const uint8_t*>(this) + 8u;
55 }
56
57 constexpr auto segment_at(uint8_t idx) const noexcept
58 -> std::span<const uint8_t, 16> {
59 return std::span<const uint8_t, 16>{
60 segment_list_ptr() + (static_cast<uint16_t>(idx) * 16u), 16u};
61 }
62
63 constexpr auto segment_list_bytes_len() const noexcept -> uint16_t {
64 return static_cast<uint16_t>(segments_count()) * 16u;
65 }
66
67 constexpr auto tlv_offset() const noexcept -> uint16_t {
68 return 8u + segment_list_bytes_len();
69 }
70
76 constexpr auto max_last_entry() const noexcept -> uint8_t {
77 return (hdr_ext_len < 2u) ? 0u
78 : static_cast<uint8_t>((hdr_ext_len / 2u) - 1u);
79 }
80
88 constexpr bool
89 validate_srh_bounds(uint16_t packet_remaining_len) const noexcept {
90 const uint16_t hdr_len = header_length_bytes();
91 if (hdr_len < 8u || (hdr_len % 8u) != 0u) {
92 return false;
93 }
94 if (packet_remaining_len < hdr_len) {
95 return false;
96 }
97 if (hdr_ext_len < 2u) {
98 return false;
99 }
100 if (last_entry > max_last_entry()) {
101 return false;
102 }
103 if (segments_left > static_cast<uint8_t>(last_entry + 1u)) {
104 return false;
105 }
106 if (tlv_offset() > hdr_len) {
107 return false;
108 }
109 return true;
110 }
111
112 constexpr auto tlv_bytes_len() const noexcept -> uint16_t {
113 auto total = header_length_bytes();
114 if (total <= tlv_offset()) {
115 return 0u;
116 }
117 return total - tlv_offset();
118 }
119
120 constexpr auto tlv_first_ptr() const noexcept -> const uint8_t* {
121 return reinterpret_cast<const uint8_t*>(this) + tlv_offset();
122 }
123
131 constexpr auto safe_tlv_region(uint16_t packet_remaining_len) const noexcept
132 -> std::optional<std::span<const uint8_t>> {
133 if (!validate_srh_bounds(packet_remaining_len)) {
134 return std::nullopt;
135 }
136 return std::span<const uint8_t>{tlv_first_ptr(), tlv_bytes_len()};
137 }
138
147 constexpr auto safe_segment_at(uint8_t idx,
148 uint16_t packet_remaining_len) const noexcept
149 -> std::optional<std::span<const uint8_t, 16>> {
150 if (!validate_srh_bounds(packet_remaining_len)) {
151 return std::nullopt;
152 }
153 if (idx >= segments_count()) {
154 return std::nullopt;
155 }
156 return segment_at(idx);
157 }
158};
159
161struct SRv6Tlv {
162 uint8_t type;
163 uint8_t length;
164 const uint8_t* value;
165 uint16_t total_len;
166};
167
170public:
171 constexpr SRv6TlvIterator(const uint8_t* ptr, uint16_t len) noexcept
172 : ptr_{ptr}, len_{len}, pos_{0} {}
173
174 constexpr bool next(SRv6Tlv& out) noexcept {
175 if (pos_ >= len_) {
176 return false;
177 }
178
179 const uint8_t t = ptr_[pos_];
180 if (t == static_cast<uint8_t>(SRv6TlvType::Pad1)) {
181 out = SRv6Tlv{t, 0, nullptr, 1u};
182 pos_ += 1u;
183 return true;
184 }
185
186 // Need at least type + length
187 if (pos_ + 2u > len_) {
188 return false;
189 }
190
191 const uint8_t len = ptr_[pos_ + 1u];
192 if (static_cast<uint16_t>(pos_ + 2u + len) > len_) {
193 return false;
194 }
195
196 out = SRv6Tlv{t, len, ptr_ + pos_ + 2u, static_cast<uint16_t>(2u + len)};
197 pos_ += out.total_len;
198 return true;
199 }
200
201private:
202 const uint8_t* ptr_;
203 uint16_t len_;
204 uint16_t pos_;
205};
206
213 const uint8_t* value;
214 uint8_t length;
215
216 constexpr bool valid() const noexcept { return value && (length >= 6u); }
217
218 constexpr bool d_bit() const noexcept {
219 if (!valid())
220 return false;
221
222 uint16_t b = read_from_bytes<uint16_t>(value);
223 return ((autoswap(b) >> 15) & 0x1u) != 0u;
224 }
225
226 constexpr auto key_id() const noexcept -> uint32_t {
227 if (!valid())
228 return 0u;
229
230 uint32_t v = read_from_bytes<uint32_t>(value + 2u);
231 return autoswap(v);
232 }
233
234 constexpr auto hmac() const noexcept -> std::span<const uint8_t> {
235 if (!valid())
236 return {};
237 const uint8_t* p = value + 6u;
238 return std::span<const uint8_t>{p, static_cast<uint16_t>(length - 6u)};
239 }
240};
241
242static_assert(sizeof(SRv6Header) == 8, "Wrong SRH header size");
243static_assert(alignof(SRv6Header) == 1, "Wrong SRH header alignment");
244
245} // namespace vbvx
constexpr SRv6TlvIterator(const uint8_t *ptr, uint16_t len) noexcept
Definition srv6_header.hxx:171
constexpr bool next(SRv6Tlv &out) noexcept
Definition srv6_header.hxx:174
Definition arp.hxx:11
SRv6TlvType
SRv6 Segment Routing Header (SRH) TLV types.
Definition srv6_header.hxx:12
@ Hmac
Definition srv6_header.hxx:12
@ PadN
Definition srv6_header.hxx:12
@ Pad1
Definition srv6_header.hxx:12
constexpr _Tp read_from_bytes(const uint8_t *src)
Read a trivially copyable type from a byte array.
Definition utils.hxx:24
constexpr _Tp autoswap(_Tp tp)
Byte-swap a value if the host is little-endian.
Definition utils.hxx:13
IPv6 Segment Routing Header (SRH) as defined in RFC 8754.
Definition srv6_header.hxx:22
constexpr auto tag() const noexcept -> uint16_t
Definition srv6_header.hxx:43
constexpr auto segments_count() const noexcept -> uint8_t
Definition srv6_header.hxx:39
constexpr auto routing_type_value() const noexcept -> uint8_t
Definition srv6_header.hxx:45
constexpr bool validate_srh_bounds(uint16_t packet_remaining_len) const noexcept
Validate SRH structural metadata against available packet bytes.
Definition srv6_header.hxx:89
constexpr auto safe_tlv_region(uint16_t packet_remaining_len) const noexcept -> std::optional< std::span< const uint8_t > >
Return a bounded TLV-byte view when SRH validation succeeds.
Definition srv6_header.hxx:131
constexpr auto max_last_entry() const noexcept -> uint8_t
Return the maximum valid Last Entry derived from Hdr Ext Len.
Definition srv6_header.hxx:76
uint8_t flags
Definition srv6_header.hxx:28
constexpr auto tlv_bytes_len() const noexcept -> uint16_t
Definition srv6_header.hxx:112
uint8_t next_header
Definition srv6_header.hxx:23
constexpr auto last_entry_index() const noexcept -> uint8_t
Definition srv6_header.hxx:35
uint16_t tag_be
Definition srv6_header.hxx:29
uint8_t hdr_ext_len
Definition srv6_header.hxx:24
uint8_t last_entry
Definition srv6_header.hxx:27
constexpr auto safe_segment_at(uint8_t idx, uint16_t packet_remaining_len) const noexcept -> std::optional< std::span< const uint8_t, 16 > >
Return a segment view only when SRH validation succeeds.
Definition srv6_header.hxx:147
constexpr auto tlv_offset() const noexcept -> uint16_t
Definition srv6_header.hxx:67
uint8_t segments_left
Definition srv6_header.hxx:26
constexpr auto segment_list_ptr() const noexcept -> const uint8_t *
Definition srv6_header.hxx:53
constexpr auto segment_list_bytes_len() const noexcept -> uint16_t
Definition srv6_header.hxx:63
constexpr bool is_valid_routing_type() const noexcept
Definition srv6_header.hxx:49
constexpr auto segment_at(uint8_t idx) const noexcept -> std::span< const uint8_t, 16 >
Definition srv6_header.hxx:57
uint8_t routing_type
Definition srv6_header.hxx:25
constexpr auto header_length_bytes() const noexcept -> uint16_t
Definition srv6_header.hxx:31
constexpr auto tlv_first_ptr() const noexcept -> const uint8_t *
Definition srv6_header.hxx:120
HMAC TLV view for type==5 (HMAC). The 'value' pointer is the TLV variable data where the first two by...
Definition srv6_header.hxx:212
uint8_t length
Definition srv6_header.hxx:214
constexpr bool valid() const noexcept
Definition srv6_header.hxx:216
const uint8_t * value
Definition srv6_header.hxx:213
constexpr bool d_bit() const noexcept
Definition srv6_header.hxx:218
constexpr auto key_id() const noexcept -> uint32_t
Definition srv6_header.hxx:226
constexpr auto hmac() const noexcept -> std::span< const uint8_t >
Definition srv6_header.hxx:234
TLV view returned by the iterator.
Definition srv6_header.hxx:161
uint16_t total_len
Definition srv6_header.hxx:165
uint8_t type
Definition srv6_header.hxx:162
const uint8_t * value
Definition srv6_header.hxx:164
uint8_t length
Definition srv6_header.hxx:163