• Daniel Borkmann's avatar
    bpf: avoid retpoline for lookup/update/delete calls on maps · 09772d92
    Daniel Borkmann authored
    While some of the BPF map lookup helpers provide a ->map_gen_lookup()
    callback for inlining the map lookup altogether it is not available
    for every map, so the remaining ones have to call bpf_map_lookup_elem()
    helper which does a dispatch to map->ops->map_lookup_elem(). In
    times of retpolines, this will control and trap speculative execution
    rather than letting it do its work for the indirect call and will
    therefore cause a slowdown. Likewise, bpf_map_update_elem() and
    bpf_map_delete_elem() do not have an inlined version and need to call
    into their map->ops->map_update_elem() resp. map->ops->map_delete_elem()
    handlers.
    
    Before:
    
      # bpftool prog dump xlated id 1
        0: (bf) r2 = r10
        1: (07) r2 += -8
        2: (7a) *(u64 *)(r2 +0) = 0
        3: (18) r1 = map[id:1]
        5: (85) call __htab_map_lookup_elem#232656
        6: (15) if r0 == 0x0 goto pc+4
        7: (71) r1 = *(u8 *)(r0 +35)
        8: (55) if r1 != 0x0 goto pc+1
        9: (72) *(u8 *)(r0 +35) = 1
       10: (07) r0 += 56
       11: (15) if r0 == 0x0 goto pc+4
       12: (bf) r2 = r0
       13: (18) r1 = map[id:1]
       15: (85) call bpf_map_delete_elem#215008  <-- indirect call via
       16: (95) exit                                 helper
    
    After:
    
      # bpftool prog dump xlated id 1
        0: (bf) r2 = r10
        1: (07) r2 += -8
        2: (7a) *(u64 *)(r2 +0) = 0
        3: (18) r1 = map[id:1]
        5: (85) call __htab_map_lookup_elem#233328
        6: (15) if r0 == 0x0 goto pc+4
        7: (71) r1 = *(u8 *)(r0 +35)
        8: (55) if r1 != 0x0 goto pc+1
        9: (72) *(u8 *)(r0 +35) = 1
       10: (07) r0 += 56
       11: (15) if r0 == 0x0 goto pc+4
       12: (bf) r2 = r0
       13: (18) r1 = map[id:1]
       15: (85) call htab_lru_map_delete_elem#238240  <-- direct call
       16: (95) exit
    
    In all three lookup/update/delete cases however we can use the actual
    address of the map callback directly if we find that there's only a
    single path with a map pointer leading to the helper call, meaning
    when the map pointer has not been poisoned from verifier side.
    Example code can be seen above for the delete case.
    Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
    Acked-by: default avatarAlexei Starovoitov <ast@kernel.org>
    Acked-by: default avatarSong Liu <songliubraving@fb.com>
    Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
    09772d92
hashtab.c 35.1 KB