1 // SPDX-License-Identifier: GPL-2.0 2 #include <stddef.h> 3 #include <string.h> 4 #include <netinet/in.h> 5 #include <linux/bpf.h> 6 #include <linux/if_ether.h> 7 #include <linux/if_packet.h> 8 #include <linux/ip.h> 9 #include <linux/ipv6.h> 10 #include <linux/types.h> 11 #include <linux/socket.h> 12 #include <linux/tcp.h> 13 #include <bpf/bpf_helpers.h> 14 #include <bpf/bpf_endian.h> 15 #include "test_tcpbpf.h" 16 17 struct { 18 __uint(type, BPF_MAP_TYPE_ARRAY); 19 __uint(max_entries, 4); 20 __type(key, __u32); 21 __type(value, struct tcpbpf_globals); 22 } global_map SEC(".maps"); 23 24 struct { 25 __uint(type, BPF_MAP_TYPE_ARRAY); 26 __uint(max_entries, 2); 27 __type(key, __u32); 28 __type(value, int); 29 } sockopt_results SEC(".maps"); 30 31 static inline void update_event_map(int event) 32 { 33 __u32 key = 0; 34 struct tcpbpf_globals g, *gp; 35 36 gp = bpf_map_lookup_elem(&global_map, &key); 37 if (gp == NULL) { 38 struct tcpbpf_globals g = {0}; 39 40 g.event_map |= (1 << event); 41 bpf_map_update_elem(&global_map, &key, &g, 42 BPF_ANY); 43 } else { 44 g = *gp; 45 g.event_map |= (1 << event); 46 bpf_map_update_elem(&global_map, &key, &g, 47 BPF_ANY); 48 } 49 } 50 51 int _version SEC("version") = 1; 52 53 SEC("sockops") 54 int bpf_testcb(struct bpf_sock_ops *skops) 55 { 56 char header[sizeof(struct ipv6hdr) + sizeof(struct tcphdr)]; 57 struct bpf_sock_ops *reuse = skops; 58 struct tcphdr *thdr; 59 int good_call_rv = 0; 60 int bad_call_rv = 0; 61 int save_syn = 1; 62 int rv = -1; 63 int v = 0; 64 int op; 65 66 /* Test reading fields in bpf_sock_ops using single register */ 67 asm volatile ( 68 "%[reuse] = *(u32 *)(%[reuse] +96)" 69 : [reuse] "+r"(reuse) 70 :); 71 72 asm volatile ( 73 "%[op] = *(u32 *)(%[skops] +96)" 74 : [op] "+r"(op) 75 : [skops] "r"(skops) 76 :); 77 78 asm volatile ( 79 "r9 = %[skops];\n" 80 "r8 = *(u32 *)(r9 +164);\n" 81 "*(u32 *)(r9 +164) = r8;\n" 82 :: [skops] "r"(skops) 83 : "r9", "r8"); 84 85 asm volatile ( 86 "r1 = %[skops];\n" 87 "r1 = *(u64 *)(r1 +184);\n" 88 "if r1 == 0 goto +1;\n" 89 "r1 = *(u32 *)(r1 +4);\n" 90 :: [skops] "r"(skops):"r1"); 91 92 asm volatile ( 93 "r9 = %[skops];\n" 94 "r9 = *(u64 *)(r9 +184);\n" 95 "if r9 == 0 goto +1;\n" 96 "r9 = *(u32 *)(r9 +4);\n" 97 :: [skops] "r"(skops):"r9"); 98 99 asm volatile ( 100 "r1 = %[skops];\n" 101 "r2 = *(u64 *)(r1 +184);\n" 102 "if r2 == 0 goto +1;\n" 103 "r2 = *(u32 *)(r2 +4);\n" 104 :: [skops] "r"(skops):"r1", "r2"); 105 106 op = (int) skops->op; 107 108 update_event_map(op); 109 110 switch (op) { 111 case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB: 112 /* Test failure to set largest cb flag (assumes not defined) */ 113 bad_call_rv = bpf_sock_ops_cb_flags_set(skops, 0x80); 114 /* Set callback */ 115 good_call_rv = bpf_sock_ops_cb_flags_set(skops, 116 BPF_SOCK_OPS_STATE_CB_FLAG); 117 /* Update results */ 118 { 119 __u32 key = 0; 120 struct tcpbpf_globals g, *gp; 121 122 gp = bpf_map_lookup_elem(&global_map, &key); 123 if (!gp) 124 break; 125 g = *gp; 126 g.bad_cb_test_rv = bad_call_rv; 127 g.good_cb_test_rv = good_call_rv; 128 bpf_map_update_elem(&global_map, &key, &g, 129 BPF_ANY); 130 } 131 break; 132 case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB: 133 skops->sk_txhash = 0x12345f; 134 v = 0xff; 135 rv = bpf_setsockopt(skops, SOL_IPV6, IPV6_TCLASS, &v, 136 sizeof(v)); 137 if (skops->family == AF_INET6) { 138 v = bpf_getsockopt(skops, IPPROTO_TCP, TCP_SAVED_SYN, 139 header, (sizeof(struct ipv6hdr) + 140 sizeof(struct tcphdr))); 141 if (!v) { 142 int offset = sizeof(struct ipv6hdr); 143 144 thdr = (struct tcphdr *)(header + offset); 145 v = thdr->syn; 146 __u32 key = 1; 147 148 bpf_map_update_elem(&sockopt_results, &key, &v, 149 BPF_ANY); 150 } 151 } 152 break; 153 case BPF_SOCK_OPS_RTO_CB: 154 break; 155 case BPF_SOCK_OPS_RETRANS_CB: 156 break; 157 case BPF_SOCK_OPS_STATE_CB: 158 if (skops->args[1] == BPF_TCP_CLOSE) { 159 __u32 key = 0; 160 struct tcpbpf_globals g, *gp; 161 162 gp = bpf_map_lookup_elem(&global_map, &key); 163 if (!gp) 164 break; 165 g = *gp; 166 if (skops->args[0] == BPF_TCP_LISTEN) { 167 g.num_listen++; 168 } else { 169 g.total_retrans = skops->total_retrans; 170 g.data_segs_in = skops->data_segs_in; 171 g.data_segs_out = skops->data_segs_out; 172 g.bytes_received = skops->bytes_received; 173 g.bytes_acked = skops->bytes_acked; 174 } 175 g.num_close_events++; 176 bpf_map_update_elem(&global_map, &key, &g, 177 BPF_ANY); 178 } 179 break; 180 case BPF_SOCK_OPS_TCP_LISTEN_CB: 181 bpf_sock_ops_cb_flags_set(skops, BPF_SOCK_OPS_STATE_CB_FLAG); 182 v = bpf_setsockopt(skops, IPPROTO_TCP, TCP_SAVE_SYN, 183 &save_syn, sizeof(save_syn)); 184 /* Update global map w/ result of setsock opt */ 185 __u32 key = 0; 186 187 bpf_map_update_elem(&sockopt_results, &key, &v, BPF_ANY); 188 break; 189 default: 190 rv = -1; 191 } 192 skops->reply = rv; 193 return 1; 194 } 195 char _license[] SEC("license") = "GPL"; 196