tcp: Add saw_unknown to struct tcp_options_received
authorMartin KaFai Lau <kafai@fb.com>
Thu, 20 Aug 2020 19:00:33 +0000 (12:00 -0700)
committerAlexei Starovoitov <ast@kernel.org>
Mon, 24 Aug 2020 21:35:00 +0000 (14:35 -0700)
In a later patch, the bpf prog only wants to be called to handle
a header option if that particular header option cannot be handled by
the kernel.  This unknown option could be written by the peer's bpf-prog.
It could also be a new standard option that the running kernel does not
support it while a bpf-prog can handle it.

This patch adds a "saw_unknown" bit to "struct tcp_options_received"
and it uses an existing one byte hole to do that.  "saw_unknown" will
be set in tcp_parse_options() if it sees an option that the kernel
cannot handle.

Signed-off-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Acked-by: John Fastabend <john.fastabend@gmail.com>
Link: https://lore.kernel.org/bpf/20200820190033.2884430-1-kafai@fb.com
include/linux/tcp.h
net/ipv4/tcp_input.c

index 2088d5a..29d1662 100644 (file)
@@ -92,6 +92,8 @@ struct tcp_options_received {
                smc_ok : 1,     /* SMC seen on SYN packet               */
                snd_wscale : 4, /* Window scaling received from sender  */
                rcv_wscale : 4; /* Window scaling to send to receiver   */
+       u8      saw_unknown:1,  /* Received unknown option              */
+               unused:7;
        u8      num_sacks;      /* Number of SACK blocks                */
        u16     user_mss;       /* mss requested by user in ioctl       */
        u16     mss_clamp;      /* Maximal mss, negotiated at connection setup */
index 4aaedcf..9072d91 100644 (file)
@@ -3801,7 +3801,7 @@ static void tcp_parse_fastopen_option(int len, const unsigned char *cookie,
        foc->exp = exp_opt;
 }
 
-static void smc_parse_options(const struct tcphdr *th,
+static bool smc_parse_options(const struct tcphdr *th,
                              struct tcp_options_received *opt_rx,
                              const unsigned char *ptr,
                              int opsize)
@@ -3810,10 +3810,13 @@ static void smc_parse_options(const struct tcphdr *th,
        if (static_branch_unlikely(&tcp_have_smc)) {
                if (th->syn && !(opsize & 1) &&
                    opsize >= TCPOLEN_EXP_SMC_BASE &&
-                   get_unaligned_be32(ptr) == TCPOPT_SMC_MAGIC)
+                   get_unaligned_be32(ptr) == TCPOPT_SMC_MAGIC) {
                        opt_rx->smc_ok = 1;
+                       return true;
+               }
        }
 #endif
+       return false;
 }
 
 /* Try to parse the MSS option from the TCP header. Return 0 on failure, clamped
@@ -3874,6 +3877,7 @@ void tcp_parse_options(const struct net *net,
 
        ptr = (const unsigned char *)(th + 1);
        opt_rx->saw_tstamp = 0;
+       opt_rx->saw_unknown = 0;
 
        while (length > 0) {
                int opcode = *ptr++;
@@ -3964,15 +3968,21 @@ void tcp_parse_options(const struct net *net,
                                 */
                                if (opsize >= TCPOLEN_EXP_FASTOPEN_BASE &&
                                    get_unaligned_be16(ptr) ==
-                                   TCPOPT_FASTOPEN_MAGIC)
+                                   TCPOPT_FASTOPEN_MAGIC) {
                                        tcp_parse_fastopen_option(opsize -
                                                TCPOLEN_EXP_FASTOPEN_BASE,
                                                ptr + 2, th->syn, foc, true);
-                               else
-                                       smc_parse_options(th, opt_rx, ptr,
-                                                         opsize);
+                                       break;
+                               }
+
+                               if (smc_parse_options(th, opt_rx, ptr, opsize))
+                                       break;
+
+                               opt_rx->saw_unknown = 1;
                                break;
 
+                       default:
+                               opt_rx->saw_unknown = 1;
                        }
                        ptr += opsize-2;
                        length -= opsize;