remove dummy mode
[project/unetd.git] / bpf_skb_utils.h
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright (C) 2022 Felix Fietkau <nbd@nbd.name>
4 */
5 #ifndef __BPF_SKB_UTILS_H
6 #define __BPF_SKB_UTILS_H
7
8 #include <uapi/linux/bpf.h>
9 #include <uapi/linux/if_ether.h>
10 #include <uapi/linux/ip.h>
11 #include <uapi/linux/ipv6.h>
12 #include <linux/ip.h>
13 #include <net/ipv6.h>
14 #include <bpf/bpf_helpers.h>
15 #include <bpf/bpf_endian.h>
16
17 struct skb_parser_info {
18 struct __sk_buff *skb;
19 __u32 offset;
20 int proto;
21 };
22
23 static __always_inline void *__skb_data(struct __sk_buff *skb)
24 {
25 return (void *)(long)READ_ONCE(skb->data);
26 }
27
28 static __always_inline void *
29 skb_ptr(struct __sk_buff *skb, __u32 offset, __u32 len)
30 {
31 void *ptr = __skb_data(skb) + offset;
32 void *end = (void *)(long)(skb->data_end);
33
34 if (ptr + len >= end)
35 return NULL;
36
37 return ptr;
38 }
39
40 static __always_inline void *
41 skb_info_ptr(struct skb_parser_info *info, __u32 len)
42 {
43 __u32 offset = info->offset;
44 return skb_ptr(info->skb, offset, len);
45 }
46
47 static __always_inline void
48 skb_parse_init(struct skb_parser_info *info, struct __sk_buff *skb)
49 {
50 *info = (struct skb_parser_info){
51 .skb = skb
52 };
53 }
54
55 static __always_inline struct ethhdr *
56 skb_parse_ethernet(struct skb_parser_info *info)
57 {
58 struct ethhdr *eth;
59
60 eth = skb_info_ptr(info, sizeof(*eth));
61 if (!eth)
62 return NULL;
63
64 info->proto = eth->h_proto;
65 info->offset += sizeof(*eth);
66
67 return eth;
68 }
69
70 static __always_inline struct vlan_hdr *
71 skb_parse_vlan(struct skb_parser_info *info)
72 {
73 struct vlan_hdr *vlh;
74
75 if (info->proto != bpf_htons(ETH_P_8021Q) &&
76 info->proto != bpf_htons(ETH_P_8021AD))
77 return NULL;
78
79 vlh = skb_info_ptr(info, sizeof(*vlh));
80 if (!vlh)
81 return NULL;
82
83 info->proto = vlh->h_vlan_encapsulated_proto;
84 info->offset += sizeof(*vlh);
85
86 return vlh;
87 }
88
89 static __always_inline struct iphdr *
90 skb_parse_ipv4(struct skb_parser_info *info, int min_l4_bytes)
91 {
92 struct iphdr *iph;
93 int proto, hdr_len;
94 __u32 pull_len;
95
96 if (info->proto != bpf_htons(ETH_P_IP))
97 return NULL;
98
99 iph = skb_info_ptr(info, sizeof(*iph));
100 if (!iph)
101 return NULL;
102
103 hdr_len = iph->ihl * 4;
104 if (hdr_len < sizeof(*iph))
105 return NULL;
106
107 pull_len = info->offset + hdr_len + min_l4_bytes;
108 if (pull_len > info->skb->len)
109 pull_len = info->skb->len;
110
111 if (bpf_skb_pull_data(info->skb, pull_len))
112 return NULL;
113
114 iph = skb_info_ptr(info, sizeof(*iph));
115 if (!iph)
116 return NULL;
117
118 info->proto = iph->protocol;
119 info->offset += hdr_len;
120
121 return iph;
122 }
123
124 static __always_inline struct ipv6hdr *
125 skb_parse_ipv6(struct skb_parser_info *info, int max_l4_bytes)
126 {
127 struct ipv6hdr *ip6h;
128 __u32 pull_len;
129
130 if (info->proto != bpf_htons(ETH_P_IPV6))
131 return NULL;
132
133 pull_len = info->offset + sizeof(*ip6h) + max_l4_bytes;
134 if (pull_len > info->skb->len)
135 pull_len = info->skb->len;
136
137 if (bpf_skb_pull_data(info->skb, pull_len))
138 return NULL;
139
140 ip6h = skb_info_ptr(info, sizeof(*ip6h));
141 if (!ip6h)
142 return NULL;
143
144 info->proto = READ_ONCE(ip6h->nexthdr);
145 info->offset += sizeof(*ip6h);
146
147 return ip6h;
148 }
149
150 static __always_inline struct tcphdr *
151 skb_parse_tcp(struct skb_parser_info *info)
152 {
153 struct tcphdr *tcph;
154
155 if (info->proto != IPPROTO_TCP)
156 return NULL;
157
158 tcph = skb_info_ptr(info, sizeof(*tcph));
159 if (!tcph)
160 return NULL;
161
162 info->offset += tcph->doff * 4;
163
164 return tcph;
165 }
166
167 #endif