/
tcp_pkt_router_kern.c
142 lines (132 loc) · 4.47 KB
/
tcp_pkt_router_kern.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// Copyright (c) Meta Platforms, Inc. and affiliates.
#ifdef KATRAN_CMAKE_BUILD
#include "vmlinux.h"
#else
#include <bpf/vmlinux/vmlinux.h>
#endif
#include <bpf/bpf_helpers.h>
#include "tcp_pkt_router_active_hdlr.h"
#include "tcp_pkt_router_common.h"
#include "tcp_pkt_router_consts.h"
#include "tcp_pkt_router_maps.h"
#include "tcp_pkt_router_passive_hdlr.h"
#include "tcp_pkt_router_structs.h"
static inline int handle_passive_cb(
struct bpf_sock_ops* skops,
struct stats* stat,
const struct server_info* s_info) {
TPR_PRINT(skops, "passive cb", skops->op);
int err;
switch (skops->op) {
case BPF_SOCK_OPS_TCP_LISTEN_CB:
// server mode does not need to read anything.
// Set the WRITE_HDR_OPT_CB now to write server-id on SYN-ACK
// TODO: check if the peer supports hdr-opt and disable writing?
return set_write_hdr_cb_flags(skops, stat);
case BPF_SOCK_OPS_PARSE_HDR_OPT_CB:
/* Read hdr-opt sent by the active side.
* Only for the packets received after 3WHS */
return handle_passive_parse_hdr(skops, stat, s_info);
case BPF_SOCK_OPS_HDR_OPT_LEN_CB:
/* Reserve space for writing the header option later in
* BPF_SOCK_OPS_WRITE_HDR_OPT_CB. */
if (((skops->skb_tcp_flags & TCPHDR_SYNACK) == TCPHDR_SYNACK) &&
!should_ignore_due_to_kde(skops)) {
return handle_hdr_opt_len(skops, stat);
} else {
return SUCCESS;
}
case BPF_SOCK_OPS_WRITE_HDR_OPT_CB:
/* Write the server-id as hdr-opt */
if ((skops->skb_tcp_flags & TCPHDR_SYNACK) == TCPHDR_SYNACK) {
return handle_passive_write_hdr_opt(skops, stat, s_info);
} else {
return SUCCESS;
}
case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB:
/* once the connection is estd, stop writing server-id */
return handle_passive_estab(skops, stat, s_info);
case BPF_SOCK_OPS_TCP_CONNECT_CB:
case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB:
default:
break;
}
return SUCCESS;
}
static inline int handle_active_cb(
struct bpf_sock_ops* skops,
struct stats* stat) {
TPR_PRINT(skops, "active cb", skops->op);
switch (skops->op) {
case BPF_SOCK_OPS_TCP_CONNECT_CB:
/* Called before SYN is sent on active side: nth to do */
break;
case BPF_SOCK_OPS_PARSE_HDR_OPT_CB:
/* Read hdr-opt sent by the passive side
* Only parse the SYNACK because server TPR only sends OPT with SYNACK */
if ((skops->skb_tcp_flags & TCPHDR_SYNACK) == TCPHDR_SYNACK) {
return handle_active_parse_hdr(skops, stat);
} else {
return SUCCESS;
}
case BPF_SOCK_OPS_HDR_OPT_LEN_CB:
/* Reserve space for writing the header option later in
* BPF_SOCK_OPS_WRITE_HDR_OPT_CB.
* Don't attempt to do this for the SYN packet because we only
* get the OPT in the SYNACK */
if ((skops->skb_tcp_flags & TCPHDR_SYN) != TCPHDR_SYN) {
return handle_hdr_opt_len(skops, stat);
} else {
return SUCCESS;
}
case BPF_SOCK_OPS_WRITE_HDR_OPT_CB:
/* Echo back the server-id as hdr-opt
* Don't attempt to do this for the SYN packet because we only
* get the OPT in the SYNACK */
if ((skops->skb_tcp_flags & TCPHDR_SYN) != TCPHDR_SYN) {
return handle_active_write_hdr_opt(skops, stat);
} else {
return SUCCESS;
}
case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB:
/* Connection estd: check for server_id */
return handle_active_estab(skops, stat);
case BPF_SOCK_OPS_TCP_LISTEN_CB:
case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB:
default:
break;
}
return SUCCESS;
}
SEC("sockops")
int tcp_pkt_router(struct bpf_sock_ops* skops) {
__u32 key = GENERIC_STATS_INDEX;
struct stats* prog_stats;
struct server_info* s_info;
prog_stats = bpf_map_lookup_elem(&tpr_stats, &key);
if (!prog_stats) {
return CG_ERR;
}
__u32 sinfo_key = SERVER_INFO_INDEX;
s_info = bpf_map_lookup_elem(&server_infos, &sinfo_key);
if (!s_info) {
// not much we can do.
prog_stats->conns_skipped++;
return CG_OK;
}
if (s_info->running_mode == SERVER_MODE) {
if (handle_passive_cb(skops, prog_stats, s_info)) {
prog_stats->conns_skipped++;
}
} else if (s_info->running_mode == CLIENT_MODE) {
if (handle_active_cb(skops, prog_stats)) {
prog_stats->conns_skipped++;
}
} else {
prog_stats->conns_skipped++;
}
return CG_OK;
}
// bpf_printk requires GPL license
char _license[] SEC("license") = "Facebook";
int _version SEC("version") = 1;