4 #include <linux/seg6_local.h>
6 #include "bpf_helpers.h"
7 #include "bpf_endian.h"
9 /* Packet parsing state machine helpers. */
10 #define cursor_advance(_cursor, _len) \
11 ({ void *_tmp = _cursor; _cursor += _len; _tmp; })
13 #define SR6_FLAG_ALERT (1 << 4)
15 #define htonll(x) ((bpf_htonl(1)) == 1 ? (x) : ((uint64_t)bpf_htonl((x) & \
16 0xFFFFFFFF) << 32) | bpf_htonl((x) >> 32))
17 #define ntohll(x) ((bpf_ntohl(1)) == 1 ? (x) : ((uint64_t)bpf_ntohl((x) & \
18 0xFFFFFFFF) << 32) | bpf_ntohl((x) >> 32))
19 #define BPF_PACKET_HEADER __attribute__((packed))
23 unsigned int priority
:8;
24 unsigned int flow_label
:20;
25 unsigned short payload_len
;
26 unsigned char next_header
;
27 unsigned char hop_limit
;
28 unsigned long long src_hi
;
29 unsigned long long src_lo
;
30 unsigned long long dst_hi
;
31 unsigned long long dst_lo
;
35 unsigned long long hi
;
36 unsigned long long lo
;
40 unsigned char nexthdr
;
43 unsigned char segments_left
;
44 unsigned char first_segment
;
48 struct ip6_addr_t segments
[0];
54 unsigned char value
[0];
57 static __always_inline
struct ip6_srh_t
*get_srh(struct __sk_buff
*skb
)
59 void *cursor
, *data_end
;
60 struct ip6_srh_t
*srh
;
64 data_end
= (void *)(long)skb
->data_end
;
65 cursor
= (void *)(long)skb
->data
;
66 ipver
= (uint8_t *)cursor
;
68 if ((void *)ipver
+ sizeof(*ipver
) > data_end
)
71 if ((*ipver
>> 4) != 6)
74 ip
= cursor_advance(cursor
, sizeof(*ip
));
75 if ((void *)ip
+ sizeof(*ip
) > data_end
)
78 if (ip
->next_header
!= 43)
81 srh
= cursor_advance(cursor
, sizeof(*srh
));
82 if ((void *)srh
+ sizeof(*srh
) > data_end
)
91 static __always_inline
int update_tlv_pad(struct __sk_buff
*skb
,
92 uint32_t new_pad
, uint32_t old_pad
,
97 if (new_pad
!= old_pad
) {
98 err
= bpf_lwt_seg6_adjust_srh(skb
, pad_off
,
99 (int) new_pad
- (int) old_pad
);
105 char pad_tlv_buf
[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
107 struct sr6_tlv_t
*pad_tlv
= (struct sr6_tlv_t
*) pad_tlv_buf
;
109 pad_tlv
->type
= SR6_TLV_PADDING
;
110 pad_tlv
->len
= new_pad
- 2;
112 err
= bpf_lwt_seg6_store_bytes(skb
, pad_off
,
113 (void *)pad_tlv_buf
, new_pad
);
121 static __always_inline
int is_valid_tlv_boundary(struct __sk_buff
*skb
,
122 struct ip6_srh_t
*srh
,
127 uint32_t srh_off
, cur_off
;
128 int offset_valid
= 0;
131 srh_off
= (char *)srh
- (char *)(long)skb
->data
;
132 // cur_off = end of segments, start of possible TLVs
133 cur_off
= srh_off
+ sizeof(*srh
) +
134 sizeof(struct ip6_addr_t
) * (srh
->first_segment
+ 1);
138 // we can only go as far as ~10 TLVs due to the BPF max stack size
139 #pragma clang loop unroll(disable)
140 for (int i
= 0; i
< 100; i
++) {
141 struct sr6_tlv_t tlv
;
143 if (cur_off
== *tlv_off
)
146 if (cur_off
>= srh_off
+ ((srh
->hdrlen
+ 1) << 3))
149 err
= bpf_skb_load_bytes(skb
, cur_off
, &tlv
, sizeof(tlv
));
153 if (tlv
.type
== SR6_TLV_PADDING
) {
154 *pad_size
= tlv
.len
+ sizeof(tlv
);
157 if (*tlv_off
== srh_off
) {
163 } else if (tlv
.type
== SR6_TLV_HMAC
) {
167 cur_off
+= sizeof(tlv
) + tlv
.len
;
168 } // we reached the padding or HMAC TLVs, or the end of the SRH
175 else if (!offset_valid
)
181 static __always_inline
int add_tlv(struct __sk_buff
*skb
,
182 struct ip6_srh_t
*srh
, uint32_t tlv_off
,
183 struct sr6_tlv_t
*itlv
, uint8_t tlv_size
)
185 uint32_t srh_off
= (char *)srh
- (char *)(long)skb
->data
;
186 uint8_t len_remaining
, new_pad
;
187 uint32_t pad_off
= 0;
188 uint32_t pad_size
= 0;
189 uint32_t partial_srh_len
;
195 if (itlv
->type
== SR6_TLV_PADDING
|| itlv
->type
== SR6_TLV_HMAC
)
198 err
= is_valid_tlv_boundary(skb
, srh
, &tlv_off
, &pad_size
, &pad_off
);
202 err
= bpf_lwt_seg6_adjust_srh(skb
, tlv_off
, sizeof(*itlv
) + itlv
->len
);
206 err
= bpf_lwt_seg6_store_bytes(skb
, tlv_off
, (void *)itlv
, tlv_size
);
210 // the following can't be moved inside update_tlv_pad because the
211 // bpf verifier has some issues with it
212 pad_off
+= sizeof(*itlv
) + itlv
->len
;
213 partial_srh_len
= pad_off
- srh_off
;
214 len_remaining
= partial_srh_len
% 8;
215 new_pad
= 8 - len_remaining
;
217 if (new_pad
== 1) // cannot pad for 1 byte only
219 else if (new_pad
== 8)
222 return update_tlv_pad(skb
, new_pad
, pad_size
, pad_off
);
225 // Add an Egress TLV fc00::4, add the flag A,
226 // and apply End.X action to fc42::1
228 int __add_egr_x(struct __sk_buff
*skb
)
230 unsigned long long hi
= 0xfc42000000000000;
231 unsigned long long lo
= 0x1;
232 struct ip6_srh_t
*srh
= get_srh(skb
);
233 uint8_t new_flags
= SR6_FLAG_ALERT
;
234 struct ip6_addr_t addr
;
240 uint8_t tlv
[20] = {2, 18, 0, 0, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
241 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4};
243 err
= add_tlv(skb
, srh
, (srh
->hdrlen
+1) << 3,
244 (struct sr6_tlv_t
*)&tlv
, 20);
248 offset
= sizeof(struct ip6_t
) + offsetof(struct ip6_srh_t
, flags
);
249 err
= bpf_lwt_seg6_store_bytes(skb
, offset
,
250 (void *)&new_flags
, sizeof(new_flags
));
254 addr
.lo
= htonll(lo
);
255 addr
.hi
= htonll(hi
);
256 err
= bpf_lwt_seg6_action(skb
, SEG6_LOCAL_ACTION_END_X
,
257 (void *)&addr
, sizeof(addr
));
262 char __license
[] SEC("license") = "GPL";