GNU Linux-libre 6.6.15-gnu
[releases.git] / samples / bpf / tcp_tos_reflect_kern.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2018 Facebook
4  *
5  * BPF program to automatically reflect TOS option from received syn packet
6  *
7  * Use "bpftool cgroup attach $cg sock_ops $prog" to load this BPF program.
8  */
9
10 #include <uapi/linux/bpf.h>
11 #include <uapi/linux/tcp.h>
12 #include <uapi/linux/if_ether.h>
13 #include <uapi/linux/if_packet.h>
14 #include <uapi/linux/ip.h>
15 #include <uapi/linux/ipv6.h>
16 #include <uapi/linux/in.h>
17 #include <linux/socket.h>
18 #include <bpf/bpf_helpers.h>
19 #include <bpf/bpf_endian.h>
20
21 #define DEBUG 1
22
23 SEC("sockops")
24 int bpf_basertt(struct bpf_sock_ops *skops)
25 {
26         char header[sizeof(struct ipv6hdr)];
27         struct ipv6hdr *hdr6;
28         struct iphdr *hdr;
29         int hdr_size = 0;
30         int save_syn = 1;
31         int tos = 0;
32         int rv = 0;
33         int op;
34
35         op = (int) skops->op;
36
37 #ifdef DEBUG
38         bpf_printk("BPF command: %d\n", op);
39 #endif
40         switch (op) {
41         case BPF_SOCK_OPS_TCP_LISTEN_CB:
42                 rv = bpf_setsockopt(skops, SOL_TCP, TCP_SAVE_SYN,
43                                    &save_syn, sizeof(save_syn));
44                 break;
45         case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB:
46                 if (skops->family == AF_INET)
47                         hdr_size = sizeof(struct iphdr);
48                 else
49                         hdr_size = sizeof(struct ipv6hdr);
50                 rv = bpf_getsockopt(skops, SOL_TCP, TCP_SAVED_SYN,
51                                     header, hdr_size);
52                 if (!rv) {
53                         if (skops->family == AF_INET) {
54                                 hdr = (struct iphdr *) header;
55                                 tos = hdr->tos;
56                                 if (tos != 0)
57                                         bpf_setsockopt(skops, SOL_IP, IP_TOS,
58                                                        &tos, sizeof(tos));
59                         } else {
60                                 hdr6 = (struct ipv6hdr *) header;
61                                 tos = ((hdr6->priority) << 4 |
62                                        (hdr6->flow_lbl[0]) >>  4);
63                                 if (tos)
64                                         bpf_setsockopt(skops, SOL_IPV6,
65                                                        IPV6_TCLASS,
66                                                        &tos, sizeof(tos));
67                         }
68                         rv = 0;
69                 }
70                 break;
71         default:
72                 rv = -1;
73         }
74 #ifdef DEBUG
75         bpf_printk("Returning %d\n", rv);
76 #endif
77         skops->reply = rv;
78         return 1;
79 }
80 char _license[] SEC("license") = "GPL";