0001
0002 #include <stddef.h>
0003 #include <string.h>
0004 #include <netinet/in.h>
0005 #include <linux/bpf.h>
0006 #include <linux/if_ether.h>
0007 #include <linux/if_packet.h>
0008 #include <linux/ip.h>
0009 #include <linux/ipv6.h>
0010 #include <linux/types.h>
0011 #include <linux/socket.h>
0012 #include <linux/tcp.h>
0013 #include <bpf/bpf_helpers.h>
0014 #include <bpf/bpf_endian.h>
0015 #include "bpf_tcp_helpers.h"
0016 #include "test_tcpbpf.h"
0017
0018 struct tcpbpf_globals global = {};
0019
0020
0021
0022
0023
0024 #ifndef SOL_TCP
0025 #define SOL_TCP 6
0026 #endif
0027
0028 static __always_inline int get_tp_window_clamp(struct bpf_sock_ops *skops)
0029 {
0030 struct bpf_sock *sk;
0031 struct tcp_sock *tp;
0032
0033 sk = skops->sk;
0034 if (!sk)
0035 return -1;
0036 tp = bpf_skc_to_tcp_sock(sk);
0037 if (!tp)
0038 return -1;
0039 return tp->window_clamp;
0040 }
0041
0042 SEC("sockops")
0043 int bpf_testcb(struct bpf_sock_ops *skops)
0044 {
0045 char header[sizeof(struct ipv6hdr) + sizeof(struct tcphdr)];
0046 struct bpf_sock_ops *reuse = skops;
0047 struct tcphdr *thdr;
0048 int window_clamp = 9216;
0049 int good_call_rv = 0;
0050 int bad_call_rv = 0;
0051 int save_syn = 1;
0052 int rv = -1;
0053 int v = 0;
0054 int op;
0055
0056
0057 asm volatile (
0058 "%[reuse] = *(u32 *)(%[reuse] +96)"
0059 : [reuse] "+r"(reuse)
0060 :);
0061
0062 asm volatile (
0063 "%[op] = *(u32 *)(%[skops] +96)"
0064 : [op] "+r"(op)
0065 : [skops] "r"(skops)
0066 :);
0067
0068 asm volatile (
0069 "r9 = %[skops];\n"
0070 "r8 = *(u32 *)(r9 +164);\n"
0071 "*(u32 *)(r9 +164) = r8;\n"
0072 :: [skops] "r"(skops)
0073 : "r9", "r8");
0074
0075 asm volatile (
0076 "r1 = %[skops];\n"
0077 "r1 = *(u64 *)(r1 +184);\n"
0078 "if r1 == 0 goto +1;\n"
0079 "r1 = *(u32 *)(r1 +4);\n"
0080 :: [skops] "r"(skops):"r1");
0081
0082 asm volatile (
0083 "r9 = %[skops];\n"
0084 "r9 = *(u64 *)(r9 +184);\n"
0085 "if r9 == 0 goto +1;\n"
0086 "r9 = *(u32 *)(r9 +4);\n"
0087 :: [skops] "r"(skops):"r9");
0088
0089 asm volatile (
0090 "r1 = %[skops];\n"
0091 "r2 = *(u64 *)(r1 +184);\n"
0092 "if r2 == 0 goto +1;\n"
0093 "r2 = *(u32 *)(r2 +4);\n"
0094 :: [skops] "r"(skops):"r1", "r2");
0095
0096 op = (int) skops->op;
0097
0098 global.event_map |= (1 << op);
0099
0100 switch (op) {
0101 case BPF_SOCK_OPS_TCP_CONNECT_CB:
0102 rv = bpf_setsockopt(skops, SOL_TCP, TCP_WINDOW_CLAMP,
0103 &window_clamp, sizeof(window_clamp));
0104 global.window_clamp_client = get_tp_window_clamp(skops);
0105 break;
0106 case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB:
0107
0108 global.bad_cb_test_rv = bpf_sock_ops_cb_flags_set(skops, 0x80);
0109
0110 global.good_cb_test_rv = bpf_sock_ops_cb_flags_set(skops,
0111 BPF_SOCK_OPS_STATE_CB_FLAG);
0112 break;
0113 case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB:
0114 skops->sk_txhash = 0x12345f;
0115 v = 0xff;
0116 rv = bpf_setsockopt(skops, SOL_IPV6, IPV6_TCLASS, &v,
0117 sizeof(v));
0118 if (skops->family == AF_INET6) {
0119 v = bpf_getsockopt(skops, IPPROTO_TCP, TCP_SAVED_SYN,
0120 header, (sizeof(struct ipv6hdr) +
0121 sizeof(struct tcphdr)));
0122 if (!v) {
0123 int offset = sizeof(struct ipv6hdr);
0124
0125 thdr = (struct tcphdr *)(header + offset);
0126 v = thdr->syn;
0127
0128 global.tcp_saved_syn = v;
0129 }
0130 }
0131 rv = bpf_setsockopt(skops, SOL_TCP, TCP_WINDOW_CLAMP,
0132 &window_clamp, sizeof(window_clamp));
0133
0134 global.window_clamp_server = get_tp_window_clamp(skops);
0135 break;
0136 case BPF_SOCK_OPS_RTO_CB:
0137 break;
0138 case BPF_SOCK_OPS_RETRANS_CB:
0139 break;
0140 case BPF_SOCK_OPS_STATE_CB:
0141 if (skops->args[1] == BPF_TCP_CLOSE) {
0142 if (skops->args[0] == BPF_TCP_LISTEN) {
0143 global.num_listen++;
0144 } else {
0145 global.total_retrans = skops->total_retrans;
0146 global.data_segs_in = skops->data_segs_in;
0147 global.data_segs_out = skops->data_segs_out;
0148 global.bytes_received = skops->bytes_received;
0149 global.bytes_acked = skops->bytes_acked;
0150 }
0151 global.num_close_events++;
0152 }
0153 break;
0154 case BPF_SOCK_OPS_TCP_LISTEN_CB:
0155 bpf_sock_ops_cb_flags_set(skops, BPF_SOCK_OPS_STATE_CB_FLAG);
0156 v = bpf_setsockopt(skops, IPPROTO_TCP, TCP_SAVE_SYN,
0157 &save_syn, sizeof(save_syn));
0158
0159 global.tcp_save_syn = v;
0160 break;
0161 default:
0162 rv = -1;
0163 }
0164 skops->reply = rv;
0165 return 1;
0166 }
0167 char _license[] SEC("license") = "GPL";