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"; 81