1. Feb 14, 2024
  2. Feb 12, 2024
    • Marco Elver's avatar
      bpf: Allow compiler to inline most of bpf_local_storage_lookup() · 68bc61c2
      Marco Elver authored
      In various performance profiles of kernels with BPF programs attached,
      bpf_local_storage_lookup() appears as a significant portion of CPU
      cycles spent. To enable the compiler generate more optimal code, turn
      bpf_local_storage_lookup() into a static inline function, where only the
      cache insertion code path is outlined
      
      Notably, outlining cache insertion helps avoid bloating callers by
      duplicating setting up calls to raw_spin_{lock,unlock}_irqsave() (on
      architectures which do not inline spin_lock/unlock, such as x86), which
      would cause the compiler produce worse code by deciding to outline
      otherwise inlinable functions. The call overhead is neutral, because we
      make 2 calls either way: either calling raw_spin_lock_irqsave() and
      raw_spin_unlock_irqsave(); or call __bpf_local_storage_insert_cache(),
      which calls raw_spin_lock_irqsave(), followed by a tail-call to
      raw_spin_unlock_irqsave() where the compiler can perform TCO and (in
      optimized uninstrumented builds) turns it into a plain jump. The call to
      __bpf_local_storage_insert_cache() can be elided entirely if
      cacheit_lockit is a false constant expression.
      
      Based on results from './benchs/run_bench_local_storage.sh' (21 trials,
      reboot between each trial; x86 defconfig + BPF, clang 16) this produces
      improvements in throughput and latency in the majority of cases, with an
      average (geomean) improvement of 8%:
      
      +---- Hashmap Control --------------------
      |
      | + num keys: 10
      | :                                         <before>             | <after>
      | +-+ hashmap (control) sequential get    +----------------------+----------------------
      |   +- hits throughput                    | 14.789 M ops/s       | 14.745 M ops/s (  ~  )
      |   +- hits latency                       | 67.679 ns/op         | 67.879 ns/op   (  ~  )
      |   +- important_hits throughput          | 14.789 M ops/s       | 14.745 M ops/s (  ~  )
      |
      | + num keys: 1000
      | :                                         <before>             | <after>
      | +-+ hashmap (control) sequential get    +----------------------+----------------------
      |   +- hits throughput                    | 12.233 M ops/s       | 12.170 M ops/s (  ~  )
      |   +- hits latency                       | 81.754 ns/op         | 82.185 ns/op   (  ~  )
      |   +- important_hits throughput          | 12.233 M ops/s       | 12.170 M ops/s (  ~  )
      |
      | + num keys: 10000
      | :                                         <before>             | <after>
      | +-+ hashmap (control) sequential get    +----------------------+----------------------
      |   +- hits throughput                    | 7.220 M ops/s        | 7.204 M ops/s  (  ~  )
      |   +- hits latency                       | 138.522 ns/op        | 138.842 ns/op  (  ~  )
      |   +- important_hits throughput          | 7.220 M ops/s        | 7.204 M ops/s  (  ~  )
      |
      | + num keys: 100000
      | :                                         <before>             | <after>
      | +-+ hashmap (control) sequential get    +----------------------+----------------------
      |   +- hits throughput                    | 5.061 M ops/s        | 5.165 M ops/s  (+2.1%)
      |   +- hits latency                       | 198.483 ns/op        | 194.270 ns/op  (-2.1%)
      |   +- important_hits throughput          | 5.061 M ops/s        | 5.165 M ops/s  (+2.1%)
      |
      | + num keys: 4194304
      | :                                         <before>             | <after>
      | +-+ hashmap (control) sequential get    +----------------------+----------------------
      |   +- hits throughput                    | 2.864 M ops/s        | 2.882 M ops/s  (  ~  )
      |   +- hits latency                       | 365.220 ns/op        | 361.418 ns/op  (-1.0%)
      |   +- important_hits throughput          | 2.864 M ops/s        | 2.882 M ops/s  (  ~  )
      |
      +---- Local Storage ----------------------
      |
      | + num_maps: 1
      | :                                         <before>             | <after>
      | +-+ local_storage cache sequential get  +----------------------+----------------------
      |   +- hits throughput                    | 33.005 M ops/s       | 39.068 M ops/s (+18.4%)
      |   +- hits latency                       | 30.300 ns/op         | 25.598 ns/op   (-15.5%)
      |   +- important_hits throughput          | 33.005 M ops/s       | 39.068 M ops/s (+18.4%)
      | :
      | :                                         <before>             | <after>
      | +-+ local_storage cache interleaved get +----------------------+----------------------
      |   +- hits throughput                    | 37.151 M ops/s       | 44.926 M ops/s (+20.9%)
      |   +- hits latency                       | 26.919 ns/op         | 22.259 ns/op   (-17.3%)
      |   +- important_hits throughput          | 37.151 M ops/s       | 44.926 M ops/s (+20.9%)
      |
      | + num_maps: 10
      | :                                         <before>             | <after>
      | +-+ local_storage cache sequential get  +----------------------+----------------------
      |   +- hits throughput                    | 32.288 M ops/s       | 38.099 M ops/s (+18.0%)
      |   +- hits latency                       | 30.972 ns/op         | 26.248 ns/op   (-15.3%)
      |   +- important_hits throughput          | 3.229 M ops/s        | 3.810 M ops/s  (+18.0%)
      | :
      | :                                         <before>             | <after>
      | +-+ local_storage cache interleaved get +----------------------+----------------------
      |   +- hits throughput                    | 34.473 M ops/s       | 41.145 M ops/s (+19.4%)
      |   +- hits latency                       | 29.010 ns/op         | 24.307 ns/op   (-16.2%)
      |   +- important_hits throughput          | 12.312 M ops/s       | 14.695 M ops/s (+19.4%)
      |
      | + num_maps: 16
      | :                                         <before>             | <after>
      | +-+ local_storage cache sequential get  +----------------------+----------------------
      |   +- hits throughput                    | 32.524 M ops/s       | 38.341 M ops/s (+17.9%)
      |   +- hits latency                       | 30.748 ns/op         | 26.083 ns/op   (-15.2%)
      |   +- important_hits throughput          | 2.033 M ops/s        | 2.396 M ops/s  (+17.9%)
      | :
      | :                                         <before>             | <after>
      | +-+ local_storage cache interleaved get +----------------------+----------------------
      |   +- hits throughput                    | 34.575 M ops/s       | 41.338 M ops/s (+19.6%)
      |   +- hits latency                       | 28.925 ns/op         | 24.193 ns/op   (-16.4%)
      |   +- important_hits throughput          | 11.001 M ops/s       | 13.153 M ops/s (+19.6%)
      |
      | + num_maps: 17
      | :                                         <before>             | <after>
      | +-+ local_storage cache sequential get  +----------------------+----------------------
      |   +- hits throughput                    | 28.861 M ops/s       | 32.756 M ops/s (+13.5%)
      |   +- hits latency                       | 34.649 ns/op         | 30.530 ns/op   (-11.9%)
      |   +- important_hits throughput          | 1.700 M ops/s        | 1.929 M ops/s  (+13.5%)
      | :
      | :                                         <before>             | <after>
      | +-+ local_storage cache interleaved get +----------------------+----------------------
      |   +- hits throughput                    | 31.529 M ops/s       | 36.110 M ops/s (+14.5%)
      |   +- hits latency                       | 31.719 ns/op         | 27.697 ns/op   (-12.7%)
      |   +- important_hits throughput          | 9.598 M ops/s        | 10.993 M ops/s (+14.5%)
      |
      | + num_maps: 24
      | :                                         <before>             | <after>
      | +-+ local_storage cache sequential get  +----------------------+----------------------
      |   +- hits throughput                    | 18.602 M ops/s       | 19.937 M ops/s (+7.2%)
      |   +- hits latency                       | 53.767 ns/op         | 50.166 ns/op   (-6.7%)
      |   +- important_hits throughput          | 0.776 M ops/s        | 0.831 M ops/s  (+7.2%)
      | :
      | :                                         <before>             | <after>
      | +-+ local_storage cache interleaved get +----------------------+----------------------
      |   +- hits throughput                    | 21.718 M ops/s       | 23.332 M ops/s (+7.4%)
      |   +- hits latency                       | 46.047 ns/op         | 42.865 ns/op   (-6.9%)
      |   +- important_hits throughput          | 6.110 M ops/s        | 6.564 M ops/s  (+7.4%)
      |
      | + num_maps: 32
      | :                                         <before>             | <after>
      | +-+ local_storage cache sequential get  +----------------------+----------------------
      |   +- hits throughput                    | 14.118 M ops/s       | 14.626 M ops/s (+3.6%)
      |   +- hits latency                       | 70.856 ns/op         | 68.381 ns/op   (-3.5%)
      |   +- important_hits throughput          | 0.442 M ops/s        | 0.458 M ops/s  (+3.6%)
      | :
      | :                                         <before>             | <after>
      | +-+ local_storage cache interleaved get +----------------------+----------------------
      |   +- hits throughput                    | 17.111 M ops/s       | 17.906 M ops/s (+4.6%)
      |   +- hits latency                       | 58.451 ns/op         | 55.865 ns/op   (-4.4%)
      |   +- important_hits throughput          | 4.776 M ops/s        | 4.998 M ops/s  (+4.6%)
      |
      | + num_maps: 100
      | :                                         <before>             | <after>
      | +-+ local_storage cache sequential get  +----------------------+----------------------
      |   +- hits throughput                    | 5.281 M ops/s        | 5.528 M ops/s  (+4.7%)
      |   +- hits latency                       | 192.398 ns/op        | 183.059 ns/op  (-4.9%)
      |   +- important_hits throughput          | 0.053 M ops/s        | 0.055 M ops/s  (+4.9%)
      | :
      | :                                         <before>             | <after>
      | +-+ local_storage cache interleaved get +----------------------+----------------------
      |   +- hits throughput                    | 6.265 M ops/s        | 6.498 M ops/s  (+3.7%)
      |   +- hits latency                       | 161.436 ns/op        | 152.877 ns/op  (-5.3%)
      |   +- important_hits throughput          | 1.636 M ops/s        | 1.697 M ops/s  (+3.7%)
      |
      | + num_maps: 1000
      | :                                         <before>             | <after>
      | +-+ local_storage cache sequential get  +----------------------+----------------------
      |   +- hits throughput                    | 0.355 M ops/s        | 0.354 M ops/s  (  ~  )
      |   +- hits latency                       | 2826.538 ns/op       | 2827.139 ns/op (  ~  )
      |   +- important_hits throughput          | 0.000 M ops/s        | 0.000 M ops/s  (  ~  )
      | :
      | :                                         <before>             | <after>
      | +-+ local_storage cache interleaved get +----------------------+----------------------
      |   +- hits throughput                    | 0.404 M ops/s        | 0.403 M ops/s  (  ~  )
      |   +- hits latency                       | 2481.190 ns/op       | 2487.555 ns/op (  ~  )
      |   +- important_hits throughput          | 0.102 M ops/s        | 0.101 M ops/s  (  ~  )
      
      The on_lookup test in {cgrp,task}_ls_recursion.c is removed
      because the bpf_local_storage_lookup is no longer traceable
      and adding tracepoint will make the compiler generate worse
      code: https://lore.kernel.org/bpf/ZcJmok64Xqv6l4ZS@elver.google.com/
      
      
      
      Signed-off-by: default avatarMarco Elver <elver@google.com>
      Cc: Martin KaFai Lau <martin.lau@linux.dev>
      Acked-by: default avatarYonghong Song <yonghong.song@linux.dev>
      Link: https://lore.kernel.org/r/20240207122626.3508658-1-elver@google.com
      
      
      Signed-off-by: default avatarMartin KaFai Lau <martin.lau@kernel.org>
      68bc61c2
  3. Feb 09, 2024
  4. Feb 08, 2024
  5. Feb 07, 2024
    • Toke Høiland-Jørgensen's avatar
      libbpf: Use OPTS_SET() macro in bpf_xdp_query() · 92a871ab
      Toke Høiland-Jørgensen authored
      When the feature_flags and xdp_zc_max_segs fields were added to the libbpf
      bpf_xdp_query_opts, the code writing them did not use the OPTS_SET() macro.
      This causes libbpf to write to those fields unconditionally, which means
      that programs compiled against an older version of libbpf (with a smaller
      size of the bpf_xdp_query_opts struct) will have its stack corrupted by
      libbpf writing out of bounds.
      
      The patch adding the feature_flags field has an early bail out if the
      feature_flags field is not part of the opts struct (via the OPTS_HAS)
      macro, but the patch adding xdp_zc_max_segs does not. For consistency, this
      fix just changes the assignments to both fields to use the OPTS_SET()
      macro.
      
      Fixes: 13ce2daa
      
       ("xsk: add new netlink attribute dedicated for ZC max frags")
      Signed-off-by: default avatarToke Høiland-Jørgensen <toke@redhat.com>
      Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
      Link: https://lore.kernel.org/bpf/20240206125922.1992815-1-toke@redhat.com
      92a871ab
    • Jose E. Marchesi's avatar
      bpf: Use -Wno-address-of-packed-member in some selftests · c27aa462
      Jose E. Marchesi authored
      
      
      [Differences from V2:
      - Remove conditionals in the source files pragmas, as the
        pragma is supported by both GCC and clang.]
      
      Both GCC and clang implement the -Wno-address-of-packed-member
      warning, which is enabled by -Wall, that warns about taking the
      address of a packed struct field when it can lead to an "unaligned"
      address.
      
      This triggers the following errors (-Werror) when building three
      particular BPF selftests with GCC:
      
        progs/test_cls_redirect.c
        986 |         if (ipv4_is_fragment((void *)&encap->ip)) {
        progs/test_cls_redirect_dynptr.c
        410 |         pkt_ipv4_checksum((void *)&encap_gre->ip);
        progs/test_cls_redirect.c
        521 |         pkt_ipv4_checksum((void *)&encap_gre->ip);
        progs/test_tc_tunnel.c
         232 |         set_ipv4_csum((void *)&h_outer.ip);
      
      These warnings do not signal any real problem in the tests as far as I
      can see.
      
      This patch adds pragmas to these test files that inhibit the
      -Waddress-of-packed-member warning.
      
      Tested in bpf-next master.
      No regressions.
      
      Signed-off-by: default avatarJose E. Marchesi <jose.marchesi@oracle.com>
      Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
      Acked-by: default avatarYonghong Song <yonghong.song@linux.dev>
      Link: https://lore.kernel.org/bpf/20240206102330.7113-1-jose.marchesi@oracle.com
      c27aa462
  6. Feb 06, 2024
  7. Feb 03, 2024
    • Alexei Starovoitov's avatar
      Merge branch 'two-small-fixes-for-global-subprog-tagging' · 2a79690e
      Alexei Starovoitov authored
      
      
      Andrii Nakryiko says:
      
      ====================
      Two small fixes for global subprog tagging
      
      Fix a bug with passing trusted PTR_TO_BTF_ID_OR_NULL register into global
      subprog that expects `__arg_trusted __arg_nullable` arguments, which was
      discovered when adopting production BPF application.
      
      Also fix annoying warnings that are irrelevant for static subprogs, which are
      just an artifact of using btf_prepare_func_args() for both static and global
      subprogs.
      ====================
      
      Acked-by: default avatarEduard Zingerman <eddyz87@gmail.com>
      Link: https://lore.kernel.org/r/20240202190529.2374377-1-andrii@kernel.org
      
      
      Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
      2a79690e
    • Andrii Nakryiko's avatar
      bpf: don't emit warnings intended for global subprogs for static subprogs · 1eb98674
      Andrii Nakryiko authored
      When btf_prepare_func_args() was generalized to handle both static and
      global subprogs, a few warnings/errors that are meant only for global
      subprog cases started to be emitted for static subprogs, where they are
      sort of expected and irrelavant.
      
      Stop polutting verifier logs with irrelevant scary-looking messages.
      
      Fixes: e26080d0
      
       ("bpf: prepare btf_prepare_func_args() for handling static subprogs")
      Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
      Link: https://lore.kernel.org/r/20240202190529.2374377-4-andrii@kernel.org
      
      
      Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
      1eb98674
    • Andrii Nakryiko's avatar
      selftests/bpf: add more cases for __arg_trusted __arg_nullable args · e2e70535
      Andrii Nakryiko authored
      
      
      Add extra layer of global functions to ensure that passing around
      (trusted) PTR_TO_BTF_ID_OR_NULL registers works as expected. We also
      extend trusted_task_arg_nullable subtest to check three possible valid
      argumements: known NULL, known non-NULL, and maybe NULL cases.
      
      Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
      Link: https://lore.kernel.org/r/20240202190529.2374377-3-andrii@kernel.org
      
      
      Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
      e2e70535
    • Andrii Nakryiko's avatar
      bpf: handle trusted PTR_TO_BTF_ID_OR_NULL in argument check logic · 8f13c340
      Andrii Nakryiko authored
      Add PTR_TRUSTED | PTR_MAYBE_NULL modifiers for PTR_TO_BTF_ID to
      check_reg_type() to support passing trusted nullable PTR_TO_BTF_ID
      registers into global functions accepting `__arg_trusted __arg_nullable`
      arguments. This hasn't been caught earlier because tests were either
      passing known non-NULL PTR_TO_BTF_ID registers or known NULL (SCALAR)
      registers.
      
      When utilizing this functionality in complicated real-world BPF
      application that passes around PTR_TO_BTF_ID_OR_NULL, it became apparent
      that verifier rejects valid case because check_reg_type() doesn't handle
      this case explicitly. Existing check_reg_type() logic is already
      anticipating this combination, so we just need to explicitly list this
      combo in the switch statement.
      
      Fixes: e2b3c4ff
      
       ("bpf: add __arg_trusted global func arg tag")
      Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
      Link: https://lore.kernel.org/r/20240202190529.2374377-2-andrii@kernel.org
      
      
      Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
      8f13c340
    • Shung-Hsi Yu's avatar
      selftests/bpf: trace_helpers.c: do not use poisoned type · a68b50f4
      Shung-Hsi Yu authored
      After commit c698eaeb ("selftests/bpf: trace_helpers.c: Optimize
      kallsyms cache") trace_helpers.c now includes libbpf_internal.h, and
      thus can no longer use the u32 type (among others) since they are poison
      in libbpf_internal.h. Replace u32 with __u32 to fix the following error
      when building trace_helpers.c on powerpc:
      
        error: attempt to use poisoned "u32"
      
      Fixes: c698eaeb
      
       ("selftests/bpf: trace_helpers.c: Optimize kallsyms cache")
      Signed-off-by: default avatarShung-Hsi Yu <shung-hsi.yu@suse.com>
      Acked-by: default avatarJiri Olsa <jolsa@kernel.org>
      Link: https://lore.kernel.org/r/20240202095559.12900-1-shung-hsi.yu@suse.com
      
      
      Signed-off-by: default avatarMartin KaFai Lau <martin.lau@kernel.org>
      a68b50f4
    • Andrii Nakryiko's avatar
      Merge branch 'improvements-for-tracking-scalars-in-the-bpf-verifier' · 6fb3f727
      Andrii Nakryiko authored
      Maxim Mikityanskiy says:
      
      ====================
      Improvements for tracking scalars in the BPF verifier
      
      From: Maxim Mikityanskiy <maxim@isovalent.com>
      
      The goal of this series is to extend the verifier's capabilities of
      tracking scalars when they are spilled to stack, especially when the
      spill or fill is narrowing. It also contains a fix by Eduard for
      infinite loop detection and a state pruning optimization by Eduard that
      compensates for a verification complexity regression introduced by
      tracking unbounded scalars. These improvements reduce the surface of
      false rejections that I saw while working on Cilium codebase.
      
      Patches 1-9 of the original series were previously applied in v2.
      
      Patches 1-2 (Maxim): Support the case when boundary checks are first
      performed after the register was spilled to the stack.
      
      Patches 3-4 (Maxim): Support narrowing fills.
      
      Patches 5-6 (Eduard): Optimization for state pruning in stacksafe() to
      mitigate the verification complexity regression.
      
      veristat -e file,prog,states -f '!states_diff<50' -f '!states_pct<10' -f '!states_a<10' -f '!states_b<10' -C ...
      
       * Without patch 5:
      
      File                  Program   States (A)  States (B)  States    (DIFF)
      --------------------  --------  ----------  ----------  ----------------
      pyperf100.bpf.o       on_event        4878        6528   +1650 (+33.83%)
      pyperf180.bpf.o       on_event        6936       11032   +4096 (+59.05%)
      pyperf600.bpf.o       on_event       22271       39455  +17184 (+77.16%)
      pyperf600_iter.bpf.o  on_event         400         490     +90 (+22.50%)
      strobemeta.bpf.o      on_event        4895       14028  +9133 (+186.58%)
      
       * With patch 5:
      
      File                     Program        States (A)  States (B)  States   (DIFF)
      -----------------------  -------------  ----------  ----------  ---------------
      bpf_xdp.o                tail_lb_ipv4         2770        2224   -546 (-19.71%)
      pyperf100.bpf.o          on_event             4878        5848   +970 (+19.89%)
      pyperf180.bpf.o          on_event             6936        8868  +1932 (+27.85%)
      pyperf600.bpf.o          on_event            22271       29656  +7385 (+33.16%)
      pyperf600_iter.bpf.o     on_event              400         450    +50 (+12.50%)
      xdp_synproxy_kern.bpf.o  syncookie_tc          280         226    -54 (-19.29%)
      xdp_synproxy_kern.bpf.o  syncookie_xdp         302         228    -74 (-24.50%)
      
      v2 changes:
      
      Fixed comments in patch 1, moved endianness checks to header files in
      patch 12 where possible, added Eduard's ACKs.
      
      v3 changes:
      
      Maxim: Removed __is_scalar_unbounded altogether, addressed Andrii's
      comments.
      
      Eduard: Patch #5 (#14 in v2) changed significantly:
      - Logical changes:
        - Handling of STACK_{MISC,ZERO} mix turned out to be incorrect:
          a mix of MISC and ZERO in old state is not equivalent to e.g.
          just MISC is current state, because verifier could have deduced
          zero scalars from ZERO slots in old state for some loads.
        - There is no reason to limit the change only to cases when
          old or current stack is a spill of unbounded scalar,
          it is valid to compare any 64-bit scalar spill with fake
          register impersonating MISC.
        - STACK_ZERO vs spilled zero case was dropped,
          after recent changes for zero handling by Andrii and Yonghong
          it is hard (impossible?) to conjure all ZERO slots for an spi.
          => the case does not make any difference in veristat results.
      - Use global static variable for unbound_reg (Andrii)
      - Code shuffling to remove duplication in stacksafe() (Andrii)
      ====================
      
      Link: https://lore.kernel.org/r/20240127175237.526726-1-maxtram95@gmail.com
      
      
      Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
      6fb3f727