]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
bpf: add TCP_SAVE_SYN/TCP_SAVED_SYN options for bpf_(set|get)sockopt
authorNikita V. Shirokov <tehnerd@fb.com>
Thu, 30 Aug 2018 14:51:53 +0000 (07:51 -0700)
committerDaniel Borkmann <daniel@iogearbox.net>
Fri, 31 Aug 2018 23:35:59 +0000 (01:35 +0200)
Adding support for two new bpf get/set sockopts: TCP_SAVE_SYN (set)
and TCP_SAVED_SYN (get). This would allow for bpf program to build
logic based on data from ingress SYN packet (e.g. doing tcp's tos/
tclass reflection (see sample prog)) and do it transparently from
userspace program point of view.

Signed-off-by: Nikita V. Shirokov <tehnerd@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
net/core/filter.c

index c25eb36f13204e0df620e6d9eb76783fe67ad243..feb578506009f46aa744d381d183e3bb3630b700 100644 (file)
@@ -4007,6 +4007,12 @@ BPF_CALL_5(bpf_setsockopt, struct bpf_sock_ops_kern *, bpf_sock,
                                        tp->snd_ssthresh = val;
                                }
                                break;
+                       case TCP_SAVE_SYN:
+                               if (val < 0 || val > 1)
+                                       ret = -EINVAL;
+                               else
+                                       tp->save_syn = val;
+                               break;
                        default:
                                ret = -EINVAL;
                        }
@@ -4032,21 +4038,32 @@ static const struct bpf_func_proto bpf_setsockopt_proto = {
 BPF_CALL_5(bpf_getsockopt, struct bpf_sock_ops_kern *, bpf_sock,
           int, level, int, optname, char *, optval, int, optlen)
 {
+       struct inet_connection_sock *icsk;
        struct sock *sk = bpf_sock->sk;
+       struct tcp_sock *tp;
 
        if (!sk_fullsock(sk))
                goto err_clear;
-
 #ifdef CONFIG_INET
        if (level == SOL_TCP && sk->sk_prot->getsockopt == tcp_getsockopt) {
-               if (optname == TCP_CONGESTION) {
-                       struct inet_connection_sock *icsk = inet_csk(sk);
+               switch (optname) {
+               case TCP_CONGESTION:
+                       icsk = inet_csk(sk);
 
                        if (!icsk->icsk_ca_ops || optlen <= 1)
                                goto err_clear;
                        strncpy(optval, icsk->icsk_ca_ops->name, optlen);
                        optval[optlen - 1] = 0;
-               } else {
+                       break;
+               case TCP_SAVED_SYN:
+                       tp = tcp_sk(sk);
+
+                       if (optlen <= 0 || !tp->saved_syn ||
+                           optlen > tp->saved_syn[0])
+                               goto err_clear;
+                       memcpy(optval, tp->saved_syn + 1, optlen);
+                       break;
+               default:
                        goto err_clear;
                }
        } else if (level == SOL_IP) {