~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/bpf/progs/test_tc_dtime.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 // Copyright (c) 2022 Meta
  3 
  4 #include <stddef.h>
  5 #include <stdint.h>
  6 #include <stdbool.h>
  7 #include <linux/bpf.h>
  8 #include <linux/stddef.h>
  9 #include <linux/pkt_cls.h>
 10 #include <linux/if_ether.h>
 11 #include <linux/in.h>
 12 #include <linux/ip.h>
 13 #include <linux/ipv6.h>
 14 #include <linux/tcp.h>
 15 #include <linux/udp.h>
 16 #include <bpf/bpf_helpers.h>
 17 #include <bpf/bpf_endian.h>
 18 
 19 /* veth_src --- veth_src_fwd --- veth_det_fwd --- veth_dst
 20  *           |                                 |
 21  *  ns_src   |              ns_fwd             |   ns_dst
 22  *
 23  * ns_src and ns_dst: ENDHOST namespace
 24  *            ns_fwd: Fowarding namespace
 25  */
 26 
 27 #define ctx_ptr(field)          (void *)(long)(field)
 28 
 29 #define ip4_src                 __bpf_htonl(0xac100164) /* 172.16.1.100 */
 30 #define ip4_dst                 __bpf_htonl(0xac100264) /* 172.16.2.100 */
 31 
 32 #define ip6_src                 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
 33                                   0x00, 0x01, 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe }
 34 #define ip6_dst                 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
 35                                   0x00, 0x02, 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe }
 36 
 37 #define v6_equal(a, b)          (a.s6_addr32[0] == b.s6_addr32[0] && \
 38                                  a.s6_addr32[1] == b.s6_addr32[1] && \
 39                                  a.s6_addr32[2] == b.s6_addr32[2] && \
 40                                  a.s6_addr32[3] == b.s6_addr32[3])
 41 
 42 volatile const __u32 IFINDEX_SRC;
 43 volatile const __u32 IFINDEX_DST;
 44 
 45 #define EGRESS_ENDHOST_MAGIC    0x0b9fbeef
 46 #define INGRESS_FWDNS_MAGIC     0x1b9fbeef
 47 #define EGRESS_FWDNS_MAGIC      0x2b9fbeef
 48 
 49 enum {
 50         INGRESS_FWDNS_P100,
 51         INGRESS_FWDNS_P101,
 52         EGRESS_FWDNS_P100,
 53         EGRESS_FWDNS_P101,
 54         INGRESS_ENDHOST,
 55         EGRESS_ENDHOST,
 56         SET_DTIME,
 57         __MAX_CNT,
 58 };
 59 
 60 enum {
 61         TCP_IP6_CLEAR_DTIME,
 62         TCP_IP4,
 63         TCP_IP6,
 64         UDP_IP4,
 65         UDP_IP6,
 66         TCP_IP4_RT_FWD,
 67         TCP_IP6_RT_FWD,
 68         UDP_IP4_RT_FWD,
 69         UDP_IP6_RT_FWD,
 70         UKN_TEST,
 71         __NR_TESTS,
 72 };
 73 
 74 enum {
 75         SRC_NS = 1,
 76         DST_NS,
 77 };
 78 
 79 __u32 dtimes[__NR_TESTS][__MAX_CNT] = {};
 80 __u32 errs[__NR_TESTS][__MAX_CNT] = {};
 81 __u32 test = 0;
 82 
 83 static void inc_dtimes(__u32 idx)
 84 {
 85         if (test < __NR_TESTS)
 86                 dtimes[test][idx]++;
 87         else
 88                 dtimes[UKN_TEST][idx]++;
 89 }
 90 
 91 static void inc_errs(__u32 idx)
 92 {
 93         if (test < __NR_TESTS)
 94                 errs[test][idx]++;
 95         else
 96                 errs[UKN_TEST][idx]++;
 97 }
 98 
 99 static int skb_proto(int type)
100 {
101         return type & 0xff;
102 }
103 
104 static int skb_ns(int type)
105 {
106         return (type >> 8) & 0xff;
107 }
108 
109 static bool fwdns_clear_dtime(void)
110 {
111         return test == TCP_IP6_CLEAR_DTIME;
112 }
113 
114 static bool bpf_fwd(void)
115 {
116         return test < TCP_IP4_RT_FWD;
117 }
118 
119 static __u8 get_proto(void)
120 {
121         switch (test) {
122         case UDP_IP4:
123         case UDP_IP6:
124         case UDP_IP4_RT_FWD:
125         case UDP_IP6_RT_FWD:
126                 return IPPROTO_UDP;
127         default:
128                 return IPPROTO_TCP;
129         }
130 }
131 
132 /* -1: parse error: TC_ACT_SHOT
133  *  0: not testing traffic: TC_ACT_OK
134  * >0: first byte is the inet_proto, second byte has the netns
135  *     of the sender
136  */
137 static int skb_get_type(struct __sk_buff *skb)
138 {
139         __u16 dst_ns_port = __bpf_htons(50000 + test);
140         void *data_end = ctx_ptr(skb->data_end);
141         void *data = ctx_ptr(skb->data);
142         __u8 inet_proto = 0, ns = 0;
143         struct ipv6hdr *ip6h;
144         __u16 sport, dport;
145         struct iphdr *iph;
146         struct tcphdr *th;
147         struct udphdr *uh;
148         void *trans;
149 
150         switch (skb->protocol) {
151         case __bpf_htons(ETH_P_IP):
152                 iph = data + sizeof(struct ethhdr);
153                 if (iph + 1 > data_end)
154                         return -1;
155                 if (iph->saddr == ip4_src)
156                         ns = SRC_NS;
157                 else if (iph->saddr == ip4_dst)
158                         ns = DST_NS;
159                 inet_proto = iph->protocol;
160                 trans = iph + 1;
161                 break;
162         case __bpf_htons(ETH_P_IPV6):
163                 ip6h = data + sizeof(struct ethhdr);
164                 if (ip6h + 1 > data_end)
165                         return -1;
166                 if (v6_equal(ip6h->saddr, (struct in6_addr){{ip6_src}}))
167                         ns = SRC_NS;
168                 else if (v6_equal(ip6h->saddr, (struct in6_addr){{ip6_dst}}))
169                         ns = DST_NS;
170                 inet_proto = ip6h->nexthdr;
171                 trans = ip6h + 1;
172                 break;
173         default:
174                 return 0;
175         }
176 
177         /* skb is not from src_ns or dst_ns.
178          * skb is not the testing IPPROTO.
179          */
180         if (!ns || inet_proto != get_proto())
181                 return 0;
182 
183         switch (inet_proto) {
184         case IPPROTO_TCP:
185                 th = trans;
186                 if (th + 1 > data_end)
187                         return -1;
188                 sport = th->source;
189                 dport = th->dest;
190                 break;
191         case IPPROTO_UDP:
192                 uh = trans;
193                 if (uh + 1 > data_end)
194                         return -1;
195                 sport = uh->source;
196                 dport = uh->dest;
197                 break;
198         default:
199                 return 0;
200         }
201 
202         /* The skb is the testing traffic */
203         if ((ns == SRC_NS && dport == dst_ns_port) ||
204             (ns == DST_NS && sport == dst_ns_port))
205                 return (ns << 8 | inet_proto);
206 
207         return 0;
208 }
209 
210 /* format: direction@iface@netns
211  * egress@veth_(src|dst)@ns_(src|dst)
212  */
213 SEC("tc")
214 int egress_host(struct __sk_buff *skb)
215 {
216         int skb_type;
217 
218         skb_type = skb_get_type(skb);
219         if (skb_type == -1)
220                 return TC_ACT_SHOT;
221         if (!skb_type)
222                 return TC_ACT_OK;
223 
224         if (skb_proto(skb_type) == IPPROTO_TCP) {
225                 if (skb->tstamp_type == BPF_SKB_CLOCK_MONOTONIC &&
226                     skb->tstamp)
227                         inc_dtimes(EGRESS_ENDHOST);
228                 else
229                         inc_errs(EGRESS_ENDHOST);
230         } else if (skb_proto(skb_type) == IPPROTO_UDP) {
231                 if (skb->tstamp_type == BPF_SKB_CLOCK_TAI &&
232                     skb->tstamp)
233                         inc_dtimes(EGRESS_ENDHOST);
234                 else
235                         inc_errs(EGRESS_ENDHOST);
236         } else {
237                 if (skb->tstamp_type == BPF_SKB_CLOCK_REALTIME &&
238                     skb->tstamp)
239                         inc_errs(EGRESS_ENDHOST);
240         }
241 
242         skb->tstamp = EGRESS_ENDHOST_MAGIC;
243 
244         return TC_ACT_OK;
245 }
246 
247 /* ingress@veth_(src|dst)@ns_(src|dst) */
248 SEC("tc")
249 int ingress_host(struct __sk_buff *skb)
250 {
251         int skb_type;
252 
253         skb_type = skb_get_type(skb);
254         if (skb_type == -1)
255                 return TC_ACT_SHOT;
256         if (!skb_type)
257                 return TC_ACT_OK;
258 
259         if (skb->tstamp_type == BPF_SKB_CLOCK_MONOTONIC &&
260             skb->tstamp == EGRESS_FWDNS_MAGIC)
261                 inc_dtimes(INGRESS_ENDHOST);
262         else
263                 inc_errs(INGRESS_ENDHOST);
264 
265         return TC_ACT_OK;
266 }
267 
268 /* ingress@veth_(src|dst)_fwd@ns_fwd priority 100 */
269 SEC("tc")
270 int ingress_fwdns_prio100(struct __sk_buff *skb)
271 {
272         int skb_type;
273 
274         skb_type = skb_get_type(skb);
275         if (skb_type == -1)
276                 return TC_ACT_SHOT;
277         if (!skb_type)
278                 return TC_ACT_OK;
279 
280         /* delivery_time is only available to the ingress
281          * if the tc-bpf checks the skb->tstamp_type.
282          */
283         if (skb->tstamp == EGRESS_ENDHOST_MAGIC)
284                 inc_errs(INGRESS_FWDNS_P100);
285 
286         if (fwdns_clear_dtime())
287                 skb->tstamp = 0;
288 
289         return TC_ACT_UNSPEC;
290 }
291 
292 /* egress@veth_(src|dst)_fwd@ns_fwd priority 100 */
293 SEC("tc")
294 int egress_fwdns_prio100(struct __sk_buff *skb)
295 {
296         int skb_type;
297 
298         skb_type = skb_get_type(skb);
299         if (skb_type == -1)
300                 return TC_ACT_SHOT;
301         if (!skb_type)
302                 return TC_ACT_OK;
303 
304         /* delivery_time is always available to egress even
305          * the tc-bpf did not use the tstamp_type.
306          */
307         if (skb->tstamp == INGRESS_FWDNS_MAGIC)
308                 inc_dtimes(EGRESS_FWDNS_P100);
309         else
310                 inc_errs(EGRESS_FWDNS_P100);
311 
312         if (fwdns_clear_dtime())
313                 skb->tstamp = 0;
314 
315         return TC_ACT_UNSPEC;
316 }
317 
318 /* ingress@veth_(src|dst)_fwd@ns_fwd priority 101 */
319 SEC("tc")
320 int ingress_fwdns_prio101(struct __sk_buff *skb)
321 {
322         int skb_type;
323 
324         skb_type = skb_get_type(skb);
325         if (skb_type == -1 || !skb_type)
326                 /* Should have handled in prio100 */
327                 return TC_ACT_SHOT;
328 
329         if (skb->tstamp_type) {
330                 if (fwdns_clear_dtime() ||
331                     (skb->tstamp_type != BPF_SKB_CLOCK_MONOTONIC &&
332                     skb->tstamp_type != BPF_SKB_CLOCK_TAI) ||
333                     skb->tstamp != EGRESS_ENDHOST_MAGIC)
334                         inc_errs(INGRESS_FWDNS_P101);
335                 else
336                         inc_dtimes(INGRESS_FWDNS_P101);
337         } else {
338                 if (!fwdns_clear_dtime())
339                         inc_errs(INGRESS_FWDNS_P101);
340         }
341 
342         if (skb->tstamp_type == BPF_SKB_CLOCK_MONOTONIC) {
343                 skb->tstamp = INGRESS_FWDNS_MAGIC;
344         } else {
345                 if (bpf_skb_set_tstamp(skb, INGRESS_FWDNS_MAGIC,
346                                        BPF_SKB_CLOCK_MONOTONIC))
347                         inc_errs(SET_DTIME);
348         }
349 
350         if (skb_ns(skb_type) == SRC_NS)
351                 return bpf_fwd() ?
352                         bpf_redirect_neigh(IFINDEX_DST, NULL, 0, 0) : TC_ACT_OK;
353         else
354                 return bpf_fwd() ?
355                         bpf_redirect_neigh(IFINDEX_SRC, NULL, 0, 0) : TC_ACT_OK;
356 }
357 
358 /* egress@veth_(src|dst)_fwd@ns_fwd priority 101 */
359 SEC("tc")
360 int egress_fwdns_prio101(struct __sk_buff *skb)
361 {
362         int skb_type;
363 
364         skb_type = skb_get_type(skb);
365         if (skb_type == -1 || !skb_type)
366                 /* Should have handled in prio100 */
367                 return TC_ACT_SHOT;
368 
369         if (skb->tstamp_type) {
370                 if (fwdns_clear_dtime() ||
371                     skb->tstamp_type != BPF_SKB_CLOCK_MONOTONIC ||
372                     skb->tstamp != INGRESS_FWDNS_MAGIC)
373                         inc_errs(EGRESS_FWDNS_P101);
374                 else
375                         inc_dtimes(EGRESS_FWDNS_P101);
376         } else {
377                 if (!fwdns_clear_dtime())
378                         inc_errs(EGRESS_FWDNS_P101);
379         }
380 
381         if (skb->tstamp_type == BPF_SKB_CLOCK_MONOTONIC) {
382                 skb->tstamp = EGRESS_FWDNS_MAGIC;
383         } else {
384                 if (bpf_skb_set_tstamp(skb, EGRESS_FWDNS_MAGIC,
385                                        BPF_SKB_CLOCK_MONOTONIC))
386                         inc_errs(SET_DTIME);
387         }
388 
389         return TC_ACT_OK;
390 }
391 
392 char __license[] SEC("license") = "GPL";
393 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php