0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #include <stddef.h>
0014 #include <string.h>
0015 #include <linux/bpf.h>
0016 #include <linux/if_ether.h>
0017 #include <linux/ip.h>
0018 #include <linux/ipv6.h>
0019 #include <linux/tcp.h>
0020 #include <linux/in.h>
0021 #include <bpf/bpf_endian.h>
0022 #include <bpf/bpf_helpers.h>
0023
0024 struct {
0025 __uint(type, BPF_MAP_TYPE_REUSEPORT_SOCKARRAY);
0026 __uint(max_entries, 256);
0027 __type(key, int);
0028 __type(value, __u64);
0029 } reuseport_map SEC(".maps");
0030
0031 struct {
0032 __uint(type, BPF_MAP_TYPE_HASH);
0033 __uint(max_entries, 256);
0034 __type(key, __u64);
0035 __type(value, int);
0036 } migrate_map SEC(".maps");
0037
0038 int migrated_at_close = 0;
0039 int migrated_at_close_fastopen = 0;
0040 int migrated_at_send_synack = 0;
0041 int migrated_at_recv_ack = 0;
0042 __be16 server_port;
0043
0044 SEC("xdp")
0045 int drop_ack(struct xdp_md *xdp)
0046 {
0047 void *data_end = (void *)(long)xdp->data_end;
0048 void *data = (void *)(long)xdp->data;
0049 struct ethhdr *eth = data;
0050 struct tcphdr *tcp = NULL;
0051
0052 if (eth + 1 > data_end)
0053 goto pass;
0054
0055 switch (bpf_ntohs(eth->h_proto)) {
0056 case ETH_P_IP: {
0057 struct iphdr *ip = (struct iphdr *)(eth + 1);
0058
0059 if (ip + 1 > data_end)
0060 goto pass;
0061
0062 if (ip->protocol != IPPROTO_TCP)
0063 goto pass;
0064
0065 tcp = (struct tcphdr *)((void *)ip + ip->ihl * 4);
0066 break;
0067 }
0068 case ETH_P_IPV6: {
0069 struct ipv6hdr *ipv6 = (struct ipv6hdr *)(eth + 1);
0070
0071 if (ipv6 + 1 > data_end)
0072 goto pass;
0073
0074 if (ipv6->nexthdr != IPPROTO_TCP)
0075 goto pass;
0076
0077 tcp = (struct tcphdr *)(ipv6 + 1);
0078 break;
0079 }
0080 default:
0081 goto pass;
0082 }
0083
0084 if (tcp + 1 > data_end)
0085 goto pass;
0086
0087 if (tcp->dest != server_port)
0088 goto pass;
0089
0090 if (!tcp->syn && tcp->ack)
0091 return XDP_DROP;
0092
0093 pass:
0094 return XDP_PASS;
0095 }
0096
0097 SEC("sk_reuseport/migrate")
0098 int migrate_reuseport(struct sk_reuseport_md *reuse_md)
0099 {
0100 int *key, flags = 0, state, err;
0101 __u64 cookie;
0102
0103 if (!reuse_md->migrating_sk)
0104 return SK_PASS;
0105
0106 state = reuse_md->migrating_sk->state;
0107 cookie = bpf_get_socket_cookie(reuse_md->sk);
0108
0109 key = bpf_map_lookup_elem(&migrate_map, &cookie);
0110 if (!key)
0111 return SK_DROP;
0112
0113 err = bpf_sk_select_reuseport(reuse_md, &reuseport_map, key, flags);
0114 if (err)
0115 return SK_PASS;
0116
0117 switch (state) {
0118 case BPF_TCP_ESTABLISHED:
0119 __sync_fetch_and_add(&migrated_at_close, 1);
0120 break;
0121 case BPF_TCP_SYN_RECV:
0122 __sync_fetch_and_add(&migrated_at_close_fastopen, 1);
0123 break;
0124 case BPF_TCP_NEW_SYN_RECV:
0125 if (!reuse_md->len)
0126 __sync_fetch_and_add(&migrated_at_send_synack, 1);
0127 else
0128 __sync_fetch_and_add(&migrated_at_recv_ack, 1);
0129 break;
0130 }
0131
0132 return SK_PASS;
0133 }
0134
0135 char _license[] SEC("license") = "GPL";