aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLawrence Brakmo <brakmo@fb.com>2018-01-25 19:14:15 -0500
committerAlexei Starovoitov <ast@kernel.org>2018-01-25 19:41:15 -0500
commitd44874910a26f3a8f81edf873a2473363f07f660 (patch)
tree97438bbc5e9bf77f0cf2bd7f4d8f6eb8f651c605
parenta31ad29e6a30cb0b9084a9425b819cdcd97273ce (diff)
bpf: Add BPF_SOCK_OPS_STATE_CB
Adds support for calling sock_ops BPF program when there is a TCP state change. Two arguments are used; one for the old state and another for the new state. There is a new enum in include/uapi/linux/bpf.h that exports the TCP states that prepends BPF_ to the current TCP state names. If it is ever necessary to change the internal TCP state values (other than adding more to the end), then it will become necessary to convert from the internal TCP state value to the BPF value before calling the BPF sock_ops function. There are a set of compile checks added in tcp.c to detect if the internal and BPF values differ so we can make the necessary fixes. New op: BPF_SOCK_OPS_STATE_CB. Signed-off-by: Lawrence Brakmo <brakmo@fb.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
-rw-r--r--include/uapi/linux/bpf.h29
-rw-r--r--net/ipv4/tcp.c24
2 files changed, 52 insertions, 1 deletions
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 31c93a0bdbc2..db6bdc375126 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -1006,7 +1006,8 @@ struct bpf_sock_ops {
1006/* Definitions for bpf_sock_ops_cb_flags */ 1006/* Definitions for bpf_sock_ops_cb_flags */
1007#define BPF_SOCK_OPS_RTO_CB_FLAG (1<<0) 1007#define BPF_SOCK_OPS_RTO_CB_FLAG (1<<0)
1008#define BPF_SOCK_OPS_RETRANS_CB_FLAG (1<<1) 1008#define BPF_SOCK_OPS_RETRANS_CB_FLAG (1<<1)
1009#define BPF_SOCK_OPS_ALL_CB_FLAGS 0x3 /* Mask of all currently 1009#define BPF_SOCK_OPS_STATE_CB_FLAG (1<<2)
1010#define BPF_SOCK_OPS_ALL_CB_FLAGS 0x7 /* Mask of all currently
1010 * supported cb flags 1011 * supported cb flags
1011 */ 1012 */
1012 1013
@@ -1054,6 +1055,32 @@ enum {
1054 * Arg3: return value of 1055 * Arg3: return value of
1055 * tcp_transmit_skb (0 => success) 1056 * tcp_transmit_skb (0 => success)
1056 */ 1057 */
1058 BPF_SOCK_OPS_STATE_CB, /* Called when TCP changes state.
1059 * Arg1: old_state
1060 * Arg2: new_state
1061 */
1062};
1063
1064/* List of TCP states. There is a build check in net/ipv4/tcp.c to detect
1065 * changes between the TCP and BPF versions. Ideally this should never happen.
1066 * If it does, we need to add code to convert them before calling
1067 * the BPF sock_ops function.
1068 */
1069enum {
1070 BPF_TCP_ESTABLISHED = 1,
1071 BPF_TCP_SYN_SENT,
1072 BPF_TCP_SYN_RECV,
1073 BPF_TCP_FIN_WAIT1,
1074 BPF_TCP_FIN_WAIT2,
1075 BPF_TCP_TIME_WAIT,
1076 BPF_TCP_CLOSE,
1077 BPF_TCP_CLOSE_WAIT,
1078 BPF_TCP_LAST_ACK,
1079 BPF_TCP_LISTEN,
1080 BPF_TCP_CLOSING, /* Now a valid state */
1081 BPF_TCP_NEW_SYN_RECV,
1082
1083 BPF_TCP_MAX_STATES /* Leave at the end! */
1057}; 1084};
1058 1085
1059#define TCP_BPF_IW 1001 /* Set TCP initial congestion window */ 1086#define TCP_BPF_IW 1001 /* Set TCP initial congestion window */
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 88b62441e7e9..f013ddc191e0 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2042,6 +2042,30 @@ void tcp_set_state(struct sock *sk, int state)
2042{ 2042{
2043 int oldstate = sk->sk_state; 2043 int oldstate = sk->sk_state;
2044 2044
2045 /* We defined a new enum for TCP states that are exported in BPF
2046 * so as not force the internal TCP states to be frozen. The
2047 * following checks will detect if an internal state value ever
2048 * differs from the BPF value. If this ever happens, then we will
2049 * need to remap the internal value to the BPF value before calling
2050 * tcp_call_bpf_2arg.
2051 */
2052 BUILD_BUG_ON((int)BPF_TCP_ESTABLISHED != (int)TCP_ESTABLISHED);
2053 BUILD_BUG_ON((int)BPF_TCP_SYN_SENT != (int)TCP_SYN_SENT);
2054 BUILD_BUG_ON((int)BPF_TCP_SYN_RECV != (int)TCP_SYN_RECV);
2055 BUILD_BUG_ON((int)BPF_TCP_FIN_WAIT1 != (int)TCP_FIN_WAIT1);
2056 BUILD_BUG_ON((int)BPF_TCP_FIN_WAIT2 != (int)TCP_FIN_WAIT2);
2057 BUILD_BUG_ON((int)BPF_TCP_TIME_WAIT != (int)TCP_TIME_WAIT);
2058 BUILD_BUG_ON((int)BPF_TCP_CLOSE != (int)TCP_CLOSE);
2059 BUILD_BUG_ON((int)BPF_TCP_CLOSE_WAIT != (int)TCP_CLOSE_WAIT);
2060 BUILD_BUG_ON((int)BPF_TCP_LAST_ACK != (int)TCP_LAST_ACK);
2061 BUILD_BUG_ON((int)BPF_TCP_LISTEN != (int)TCP_LISTEN);
2062 BUILD_BUG_ON((int)BPF_TCP_CLOSING != (int)TCP_CLOSING);
2063 BUILD_BUG_ON((int)BPF_TCP_NEW_SYN_RECV != (int)TCP_NEW_SYN_RECV);
2064 BUILD_BUG_ON((int)BPF_TCP_MAX_STATES != (int)TCP_MAX_STATES);
2065
2066 if (BPF_SOCK_OPS_TEST_FLAG(tcp_sk(sk), BPF_SOCK_OPS_STATE_CB_FLAG))
2067 tcp_call_bpf_2arg(sk, BPF_SOCK_OPS_STATE_CB, oldstate, state);
2068
2045 switch (state) { 2069 switch (state) {
2046 case TCP_ESTABLISHED: 2070 case TCP_ESTABLISHED:
2047 if (oldstate != TCP_ESTABLISHED) 2071 if (oldstate != TCP_ESTABLISHED)