From: Yonghong Song <yhs@fb.com>
To: Maxim Mikityanskiy <maximmi@nvidia.com>
Cc: "Toke Høiland-Jørgensen" <toke@redhat.com>,
"Lorenz Bauer" <lmb@cloudflare.com>,
"Alexei Starovoitov" <ast@kernel.org>,
"Daniel Borkmann" <daniel@iogearbox.net>,
"Andrii Nakryiko" <andrii@kernel.org>,
"Martin KaFai Lau" <kafai@fb.com>,
"Song Liu" <songliubraving@fb.com>,
"John Fastabend" <john.fastabend@gmail.com>,
"KP Singh" <kpsingh@kernel.org>,
"Eric Dumazet" <edumazet@google.com>,
"David S. Miller" <davem@davemloft.net>,
"Jakub Kicinski" <kuba@kernel.org>,
"Hideaki YOSHIFUJI" <yoshfuji@linux-ipv6.org>,
"David Ahern" <dsahern@kernel.org>,
"Jesper Dangaard Brouer" <hawk@kernel.org>,
"Nathan Chancellor" <nathan@kernel.org>,
"Nick Desaulniers" <ndesaulniers@google.com>,
"Brendan Jackman" <jackmanb@google.com>,
"Florent Revest" <revest@chromium.org>,
"Joe Stringer" <joe@cilium.io>,
"Tariq Toukan" <tariqt@nvidia.com>,
Networking <netdev@vger.kernel.org>, bpf <bpf@vger.kernel.org>,
clang-built-linux@googlegroups.com
Subject: Re: [PATCH bpf-next 09/10] bpf: Add a helper to issue timestamp cookies in XDP
Date: Tue, 30 Nov 2021 22:39:40 -0800 [thread overview]
Message-ID: <4f895364-a546-c7dd-b6d2-2a80628f2d9a@fb.com> (raw)
In-Reply-To: <0a958197-67ab-8773-3611-f8156ebdb9e0@nvidia.com>
On 11/29/21 9:51 AM, Maxim Mikityanskiy wrote:
> On 2021-11-26 19:07, Yonghong Song wrote:
>>
>>
>> On 11/26/21 8:50 AM, Maxim Mikityanskiy wrote:
>>> On 2021-11-26 07:43, Yonghong Song wrote:
>>>>
>>>>
>>>> On 11/25/21 6:34 AM, Maxim Mikityanskiy wrote:
>>>>> On 2021-11-09 09:11, Yonghong Song wrote:
>>>>>>
>>>>>>
>>>>>> On 11/3/21 7:02 AM, Maxim Mikityanskiy wrote:
>>>>>>> On 2021-11-03 04:10, Yonghong Song wrote:
>>>>>>>>
>>>>>>>>
>>>>>>>> On 11/1/21 4:14 AM, Maxim Mikityanskiy wrote:
>>>>>>>>> On 2021-10-20 19:16, Toke Høiland-Jørgensen wrote:
>>>>>>>>>> Lorenz Bauer <lmb@cloudflare.com> writes:
>>>>>>>>>>
>>>>>>>>>>>> +bool cookie_init_timestamp_raw(struct tcphdr *th, __be32
>>>>>>>>>>>> *tsval, __be32 *tsecr)
>>>>>>>>>>>
>>>>>>>>>>> I'm probably missing context, Is there something in this
>>>>>>>>>>> function that
>>>>>>>>>>> means you can't implement it in BPF?
>>>>>>>>>>
>>>>>>>>>> I was about to reply with some other comments but upon closer
>>>>>>>>>> inspection
>>>>>>>>>> I ended up at the same conclusion: this helper doesn't seem to
>>>>>>>>>> be needed
>>>>>>>>>> at all?
>>>>>>>>>
>>>>>>>>> After trying to put this code into BPF (replacing the
>>>>>>>>> underlying ktime_get_ns with ktime_get_mono_fast_ns), I
>>>>>>>>> experienced issues with passing the verifier.
>>>>>>>>>
>>>>>>>>> In addition to comparing ptr to end, I had to add checks that
>>>>>>>>> compare ptr to data_end, because the verifier can't deduce that
>>>>>>>>> end <= data_end. More branches will add a certain slowdown (not
>>>>>>>>> measured).
>>>>>>>>>
>>>>>>>>> A more serious issue is the overall program complexity. Even
>>>>>>>>> though the loop over the TCP options has an upper bound, and
>>>>>>>>> the pointer advances by at least one byte every iteration, I
>>>>>>>>> had to limit the total number of iterations artificially. The
>>>>>>>>> maximum number of iterations that makes the verifier happy is
>>>>>>>>> 10. With more iterations, I have the following error:
>>>>>>>>>
>>>>>>>>> BPF program is too large. Processed 1000001 insn
>>>>>>>>>
>>>>>>>>> processed 1000001 insns (limit 1000000)
>>>>>>>>> max_states_per_insn 29 total_states 35489 peak_states 596
>>>>>>>>> mark_read 45
>>>>>>>>>
>>>>>>>>> I assume that BPF_COMPLEXITY_LIMIT_INSNS (1 million) is the
>>>>>>>>> accumulated amount of instructions that the verifier can
>>>>>>>>> process in all branches, is that right? It doesn't look
>>>>>>>>> realistic that my program can run 1 million instructions in a
>>>>>>>>> single run, but it might be that if you take all possible flows
>>>>>>>>> and add up the instructions from these flows, it will exceed 1
>>>>>>>>> million.
>>>>>>>>>
>>>>>>>>> The limitation of maximum 10 TCP options might be not enough,
>>>>>>>>> given that valid packets are permitted to include more than 10
>>>>>>>>> NOPs. An alternative of using bpf_load_hdr_opt and calling it
>>>>>>>>> three times doesn't look good either, because it will be about
>>>>>>>>> three times slower than going over the options once. So maybe
>>>>>>>>> having a helper for that is better than trying to fit it into BPF?
>>>>>>>>>
>>>>>>>>> One more interesting fact is the time that it takes for the
>>>>>>>>> verifier to check my program. If it's limited to 10 iterations,
>>>>>>>>> it does it pretty fast, but if I try to increase the number to
>>>>>>>>> 11 iterations, it takes several minutes for the verifier to
>>>>>>>>> reach 1 million instructions and print the error then. I also
>>>>>>>>> tried grouping the NOPs in an inner loop to count only 10 real
>>>>>>>>> options, and the verifier has been running for a few hours
>>>>>>>>> without any response. Is it normal?
>>>>>>>>
>>>>>>>> Maxim, this may expose a verifier bug. Do you have a reproducer
>>>>>>>> I can access? I would like to debug this to see what is the root
>>>>>>>> case. Thanks!
>>>>>>>
>>>>>>> Thanks, I appreciate your help in debugging it. The reproducer is
>>>>>>> based on the modified XDP program from patch 10 in this series.
>>>>>>> You'll need to apply at least patches 6, 7, 8 from this series to
>>>>>>> get new BPF helpers needed for the XDP program (tell me if that's
>>>>>>> a problem, I can try to remove usage of new helpers, but it will
>>>>>>> affect the program length and may produce different results in
>>>>>>> the verifier).
>>>>>>>
>>>>>>> See the C code of the program that passes the verifier (compiled
>>>>>>> with clang version 12.0.0-1ubuntu1) in the bottom of this email.
>>>>>>> If you increase the loop boundary from 10 to at least 11 in
>>>>>>> cookie_init_timestamp_raw(), it fails the verifier after a few
>>>>>>> minutes.
>>>>>>
>>>>>> I tried to reproduce with latest llvm (llvm-project repo),
>>>>>> loop boundary 10 is okay and 11 exceeds the 1M complexity limit.
>>>>>> For 10,
>>>>>> the number of verified instructions is 563626 (more than 0.5M) so
>>>>>> it is
>>>>>> totally possible that one more iteration just blows past the limit.
>>>>>
>>>>> So, does it mean that the verifying complexity grows exponentially
>>>>> with increasing the number of loop iterations (options parsed)?
>>>>
>>>> Depending on verification time pruning results, it is possible
>>>> slightly increase number of branches could result quite some (2x,
>>>> 4x, etc.) of
>>>> to-be-verified dynamic instructions.
>>>
>>> Is it at least theoretically possible to make this coefficient below
>>> 2x? I.e. write a loop, so that adding another iteration will not
>>> double the number of verified instructions, but will have a smaller
>>> increase?
>>>
>>> If that's not possible, then it looks like BPF can't have loops
>>> bigger than ~19 iterations (2^20 > 1M), and this function is not
>>> implementable in BPF.
>>
>> This is the worst case. As I mentioned pruning plays a huge role in
>> verification. Effective pruning can add little increase of dynamic
>> instructions say from 19 iterations to 20 iterations. But we have
>> to look at verifier log to find out whether pruning is less effective or
>> something else... Based on my experience, in most cases, pruning is
>> quite effective. But occasionally it is not... You can look at
>> verifier.c file to roughly understand how pruning work.
>>
>> Not sure whether in this case it is due to less effective pruning or
>> inherently we just have to go through all these dynamic instructions
>> for verification.
>>
>>>
>>>>>
>>>>> Is it a good enough reason to keep this code as a BPF helper,
>>>>> rather than trying to fit it into the BPF program?
>>>>
>>>> Another option is to use global function, which is verified separately
>>>> from the main bpf program.
>>>
>>> Simply removing __always_inline didn't change anything. Do I need to
>>> make any other changes? Will it make sense to call a global function
>>> in a loop, i.e. will it increase chances to pass the verifier?
>>
>> global function cannot be static function. You can try
>> either global function inside the loop or global function
>> containing the loop. It probably more effective to put loops
>> inside the global function. You have to do some experiments
>> to see which one is better.
>
> Sorry for a probably noob question, but how can I pass data_end to a
> global function? I'm getting this error:
>
> Validating cookie_init_timestamp_raw() func#1...
> arg#4 reference type('UNKNOWN ') size cannot be determined: -22
> processed 0 insns (limit 1000000) max_states_per_insn 0 total_states 0
> peak_states 0 mark_read 0
>
> When I removed data_end, I got another one:
>
> ; opcode = ptr[0];
> 969: (71) r8 = *(u8 *)(r0 +0)
> R0=mem(id=0,ref_obj_id=0,off=20,imm=0)
> R1=mem(id=0,ref_obj_id=0,off=0,umin_value=4,umax_value=60,var_off=(0x0;
> 0x3f),s32_min_value=0,s32_max_value=63,u32_max_value=63)
> R2=invP0 R3=invP0 R4=mem_or_null(id=6,ref_obj_id=0,off=0,imm=0)
> R5=invP0 R6=mem_or_null(id=5,ref_obj_id=0,off=0,imm=0)
> R7=mem(id=0,ref_obj_id=0,off=0,imm=0) R10=fp0 fp
> -8=00000000 fp-16=invP15
> invalid access to memory, mem_size=20 off=20 size=1
> R0 min value is outside of the allowed memory range
> processed 20 insns (limit 1000000) max_states_per_insn 0 total_states 2
> peak_states 2 mark_read 1
>
> It looks like pointers to the context aren't supported:
>
> https://www.spinics.net/lists/bpf/msg34907.html
>
> > test_global_func11 - check that CTX pointer cannot be passed
>
> What is the standard way to pass packet data to a global function?
Since global function is separately verified, you need to pass the 'ctx'
to the global function and do the 'data_end' check again in the global
function. This will incur some packet re-parsing overhead similar to
tail calls.
>
> Thanks,
> Max
>
>>>
>>>>>
>>>>>>
>>>>>>> If you apply this tiny change, it fails the verifier after about
>>>>>>> 3 hours:
>>>>>>>
>>>> [...]
>>>
>
next prev parent reply other threads:[~2021-12-01 6:40 UTC|newest]
Thread overview: 48+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-10-19 14:46 [PATCH bpf-next 00/10] New BPF helpers to accelerate synproxy Maxim Mikityanskiy
2021-10-19 14:46 ` [PATCH bpf-next 01/10] bpf: Use ipv6_only_sock in bpf_tcp_gen_syncookie Maxim Mikityanskiy
2021-10-19 14:46 ` [PATCH bpf-next 02/10] bpf: Support dual-stack sockets in bpf_tcp_check_syncookie Maxim Mikityanskiy
2021-10-19 14:46 ` [PATCH bpf-next 03/10] bpf: Use EOPNOTSUPP " Maxim Mikityanskiy
2021-10-19 14:46 ` [PATCH bpf-next 04/10] bpf: Make errors of bpf_tcp_check_syncookie distinguishable Maxim Mikityanskiy
2021-10-20 3:28 ` John Fastabend
2021-10-20 13:16 ` Maxim Mikityanskiy
2021-10-20 15:26 ` Lorenz Bauer
2021-10-19 14:46 ` [PATCH bpf-next 05/10] bpf: Fix documentation of th_len in bpf_tcp_{gen,check}_syncookie Maxim Mikityanskiy
2021-10-19 14:46 ` [PATCH bpf-next 06/10] bpf: Expose struct nf_conn to BPF Maxim Mikityanskiy
2021-10-19 14:46 ` [PATCH bpf-next 07/10] bpf: Add helpers to query conntrack info Maxim Mikityanskiy
2021-10-20 3:56 ` Kumar Kartikeya Dwivedi
2021-10-20 9:28 ` Florian Westphal
2021-10-20 9:48 ` Toke Høiland-Jørgensen
2021-10-20 9:58 ` Florian Westphal
2021-10-20 12:21 ` Toke Høiland-Jørgensen
2021-10-20 12:44 ` Florian Westphal
2021-10-20 20:54 ` Toke Høiland-Jørgensen
2021-10-20 22:55 ` David Ahern
2021-10-21 7:36 ` Florian Westphal
2021-10-20 13:18 ` Maxim Mikityanskiy
2021-10-20 19:17 ` Kumar Kartikeya Dwivedi
2021-10-20 9:46 ` Toke Høiland-Jørgensen
2021-10-19 14:46 ` [PATCH bpf-next 08/10] bpf: Add helpers to issue and check SYN cookies in XDP Maxim Mikityanskiy
2021-10-19 14:46 ` [PATCH bpf-next 09/10] bpf: Add a helper to issue timestamp " Maxim Mikityanskiy
2021-10-19 16:45 ` Eric Dumazet
2021-10-20 13:16 ` Maxim Mikityanskiy
2021-10-20 15:56 ` Lorenz Bauer
2021-10-20 16:16 ` Toke Høiland-Jørgensen
2021-10-22 16:56 ` Maxim Mikityanskiy
2021-10-27 8:34 ` Lorenz Bauer
2021-11-01 11:14 ` Maxim Mikityanskiy
2021-11-03 2:10 ` Yonghong Song
2021-11-03 14:02 ` Maxim Mikityanskiy
2021-11-09 7:11 ` Yonghong Song
2021-11-25 14:34 ` Maxim Mikityanskiy
2021-11-26 5:43 ` Yonghong Song
2021-11-26 16:50 ` Maxim Mikityanskiy
2021-11-26 17:07 ` Yonghong Song
2021-11-29 17:51 ` Maxim Mikityanskiy
2021-12-01 6:39 ` Yonghong Song [this message]
2021-12-01 18:06 ` Andrii Nakryiko
2021-10-19 14:46 ` [PATCH bpf-next 10/10] bpf: Add sample for raw syncookie helpers Maxim Mikityanskiy
2021-10-20 18:01 ` Joe Stringer
2021-10-21 17:19 ` Maxim Mikityanskiy
2021-10-21 1:06 ` Alexei Starovoitov
2021-10-21 17:31 ` Maxim Mikityanskiy
2021-10-21 18:50 ` Alexei Starovoitov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4f895364-a546-c7dd-b6d2-2a80628f2d9a@fb.com \
--to=yhs@fb.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=clang-built-linux@googlegroups.com \
--cc=daniel@iogearbox.net \
--cc=davem@davemloft.net \
--cc=dsahern@kernel.org \
--cc=edumazet@google.com \
--cc=hawk@kernel.org \
--cc=jackmanb@google.com \
--cc=joe@cilium.io \
--cc=john.fastabend@gmail.com \
--cc=kafai@fb.com \
--cc=kpsingh@kernel.org \
--cc=kuba@kernel.org \
--cc=lmb@cloudflare.com \
--cc=maximmi@nvidia.com \
--cc=nathan@kernel.org \
--cc=ndesaulniers@google.com \
--cc=netdev@vger.kernel.org \
--cc=revest@chromium.org \
--cc=songliubraving@fb.com \
--cc=tariqt@nvidia.com \
--cc=toke@redhat.com \
--cc=yoshfuji@linux-ipv6.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox