1. Nov 19, 2019
  2. Nov 18, 2019
    • Daniel Borkmann's avatar
      Merge branch 'bpf-array-mmap' · b97e12e5
      Daniel Borkmann authored
      
      
      Andrii Nakryiko says:
      
      ====================
      This patch set adds ability to memory-map BPF array maps (single- and
      multi-element). The primary use case is memory-mapping BPF array maps, created
      to back global data variables, created by libbpf implicitly. This allows for
      much better usability, along with avoiding syscalls to read or update data
      completely.
      
      Due to memory-mapping requirements, BPF array map that is supposed to be
      memory-mapped, has to be created with special BPF_F_MMAPABLE attribute, which
      triggers slightly different memory allocation strategy internally. See
      patch 1 for details.
      
      Libbpf is extended to detect kernel support for this flag, and if supported,
      will specify it for all global data maps automatically.
      
      Patch #1 refactors bpf_map_inc() and converts bpf_map's refcnt to atomic64_t
      to make refcounting never fail. Patch #2 does similar refactoring for
      bpf_prog_add()/bpf_prog_inc().
      
      v5->v6:
      - add back uref counting (Daniel);
      
      v4->v5:
      - change bpf_prog's refcnt to atomic64_t (Daniel);
      
      v3->v4:
      - add mmap's open() callback to fix refcounting (Johannes);
      - switch to remap_vmalloc_pages() instead of custom fault handler (Johannes);
      - converted bpf_map's refcnt/usercnt into atomic64_t;
      - provide default bpf_map_default_vmops handling open/close properly;
      
      v2->v3:
      - change allocation strategy to avoid extra pointer dereference (Jakub);
      
      v1->v2:
      - fix map lookup code generation for BPF_F_MMAPABLE case;
      - prevent BPF_F_MMAPABLE flag for all but plain array map type;
      - centralize ref-counting in generic bpf_map_mmap();
      - don't use uref counting (Alexei);
      - use vfree() directly;
      - print flags with %x (Song);
      - extend tests to verify bpf_map_{lookup,update}_elem() logic as well.
      ====================
      
      Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
      b97e12e5
    • Andrii Nakryiko's avatar
      selftests/bpf: Add BPF_TYPE_MAP_ARRAY mmap() tests · 5051b384
      Andrii Nakryiko authored
      
      
      Add selftests validating mmap()-ing BPF array maps: both single-element and
      multi-element ones. Check that plain bpf_map_update_elem() and
      bpf_map_lookup_elem() work correctly with memory-mapped array. Also convert
      CO-RE relocation tests to use memory-mapped views of global data.
      
      Signed-off-by: default avatarAndrii Nakryiko <andriin@fb.com>
      Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
      Acked-by: default avatarSong Liu <songliubraving@fb.com>
      Link: https://lore.kernel.org/bpf/20191117172806.2195367-6-andriin@fb.com
      5051b384
    • Andrii Nakryiko's avatar
      libbpf: Make global data internal arrays mmap()-able, if possible · 7fe74b43
      Andrii Nakryiko authored
      
      
      Add detection of BPF_F_MMAPABLE flag support for arrays and add it as an extra
      flag to internal global data maps, if supported by kernel. This allows users
      to memory-map global data and use it without BPF map operations, greatly
      simplifying user experience.
      
      Signed-off-by: default avatarAndrii Nakryiko <andriin@fb.com>
      Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
      Acked-by: default avatarSong Liu <songliubraving@fb.com>
      Acked-by: default avatarJohn Fastabend <john.fastabend@gmail.com>
      Link: https://lore.kernel.org/bpf/20191117172806.2195367-5-andriin@fb.com
      7fe74b43
    • Andrii Nakryiko's avatar
      bpf: Add mmap() support for BPF_MAP_TYPE_ARRAY · fc970227
      Andrii Nakryiko authored
      
      
      Add ability to memory-map contents of BPF array map. This is extremely useful
      for working with BPF global data from userspace programs. It allows to avoid
      typical bpf_map_{lookup,update}_elem operations, improving both performance
      and usability.
      
      There had to be special considerations for map freezing, to avoid having
      writable memory view into a frozen map. To solve this issue, map freezing and
      mmap-ing is happening under mutex now:
        - if map is already frozen, no writable mapping is allowed;
        - if map has writable memory mappings active (accounted in map->writecnt),
          map freezing will keep failing with -EBUSY;
        - once number of writable memory mappings drops to zero, map freezing can be
          performed again.
      
      Only non-per-CPU plain arrays are supported right now. Maps with spinlocks
      can't be memory mapped either.
      
      For BPF_F_MMAPABLE array, memory allocation has to be done through vmalloc()
      to be mmap()'able. We also need to make sure that array data memory is
      page-sized and page-aligned, so we over-allocate memory in such a way that
      struct bpf_array is at the end of a single page of memory with array->value
      being aligned with the start of the second page. On deallocation we need to
      accomodate this memory arrangement to free vmalloc()'ed memory correctly.
      
      One important consideration regarding how memory-mapping subsystem functions.
      Memory-mapping subsystem provides few optional callbacks, among them open()
      and close().  close() is called for each memory region that is unmapped, so
      that users can decrease their reference counters and free up resources, if
      necessary. open() is *almost* symmetrical: it's called for each memory region
      that is being mapped, **except** the very first one. So bpf_map_mmap does
      initial refcnt bump, while open() will do any extra ones after that. Thus
      number of close() calls is equal to number of open() calls plus one more.
      
      Signed-off-by: default avatarAndrii Nakryiko <andriin@fb.com>
      Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
      Acked-by: default avatarSong Liu <songliubraving@fb.com>
      Acked-by: default avatarJohn Fastabend <john.fastabend@gmail.com>
      Acked-by: default avatarJohannes Weiner <hannes@cmpxchg.org>
      Link: https://lore.kernel.org/bpf/20191117172806.2195367-4-andriin@fb.com
      fc970227
    • Andrii Nakryiko's avatar
      bpf: Convert bpf_prog refcnt to atomic64_t · 85192dbf
      Andrii Nakryiko authored
      
      
      Similarly to bpf_map's refcnt/usercnt, convert bpf_prog's refcnt to atomic64
      and remove artificial 32k limit. This allows to make bpf_prog's refcounting
      non-failing, simplifying logic of users of bpf_prog_add/bpf_prog_inc.
      
      Validated compilation by running allyesconfig kernel build.
      
      Suggested-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
      Signed-off-by: default avatarAndrii Nakryiko <andriin@fb.com>
      Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
      Link: https://lore.kernel.org/bpf/20191117172806.2195367-3-andriin@fb.com
      85192dbf
    • Andrii Nakryiko's avatar
      bpf: Switch bpf_map ref counter to atomic64_t so bpf_map_inc() never fails · 1e0bd5a0
      Andrii Nakryiko authored
      92117d84
      
       ("bpf: fix refcnt overflow") turned refcounting of bpf_map into
      potentially failing operation, when refcount reaches BPF_MAX_REFCNT limit
      (32k). Due to using 32-bit counter, it's possible in practice to overflow
      refcounter and make it wrap around to 0, causing erroneous map free, while
      there are still references to it, causing use-after-free problems.
      
      But having a failing refcounting operations are problematic in some cases. One
      example is mmap() interface. After establishing initial memory-mapping, user
      is allowed to arbitrarily map/remap/unmap parts of mapped memory, arbitrarily
      splitting it into multiple non-contiguous regions. All this happening without
      any control from the users of mmap subsystem. Rather mmap subsystem sends
      notifications to original creator of memory mapping through open/close
      callbacks, which are optionally specified during initial memory mapping
      creation. These callbacks are used to maintain accurate refcount for bpf_map
      (see next patch in this series). The problem is that open() callback is not
      supposed to fail, because memory-mapped resource is set up and properly
      referenced. This is posing a problem for using memory-mapping with BPF maps.
      
      One solution to this is to maintain separate refcount for just memory-mappings
      and do single bpf_map_inc/bpf_map_put when it goes from/to zero, respectively.
      There are similar use cases in current work on tcp-bpf, necessitating extra
      counter as well. This seems like a rather unfortunate and ugly solution that
      doesn't scale well to various new use cases.
      
      Another approach to solve this is to use non-failing refcount_t type, which
      uses 32-bit counter internally, but, once reaching overflow state at UINT_MAX,
      stays there. This utlimately causes memory leak, but prevents use after free.
      
      But given refcounting is not the most performance-critical operation with BPF
      maps (it's not used from running BPF program code), we can also just switch to
      64-bit counter that can't overflow in practice, potentially disadvantaging
      32-bit platforms a tiny bit. This simplifies semantics and allows above
      described scenarios to not worry about failing refcount increment operation.
      
      In terms of struct bpf_map size, we are still good and use the same amount of
      space:
      
      BEFORE (3 cache lines, 8 bytes of padding at the end):
      struct bpf_map {
      	const struct bpf_map_ops  * ops __attribute__((__aligned__(64))); /*     0     8 */
      	struct bpf_map *           inner_map_meta;       /*     8     8 */
      	void *                     security;             /*    16     8 */
      	enum bpf_map_type  map_type;                     /*    24     4 */
      	u32                        key_size;             /*    28     4 */
      	u32                        value_size;           /*    32     4 */
      	u32                        max_entries;          /*    36     4 */
      	u32                        map_flags;            /*    40     4 */
      	int                        spin_lock_off;        /*    44     4 */
      	u32                        id;                   /*    48     4 */
      	int                        numa_node;            /*    52     4 */
      	u32                        btf_key_type_id;      /*    56     4 */
      	u32                        btf_value_type_id;    /*    60     4 */
      	/* --- cacheline 1 boundary (64 bytes) --- */
      	struct btf *               btf;                  /*    64     8 */
      	struct bpf_map_memory memory;                    /*    72    16 */
      	bool                       unpriv_array;         /*    88     1 */
      	bool                       frozen;               /*    89     1 */
      
      	/* XXX 38 bytes hole, try to pack */
      
      	/* --- cacheline 2 boundary (128 bytes) --- */
      	atomic_t                   refcnt __attribute__((__aligned__(64))); /*   128     4 */
      	atomic_t                   usercnt;              /*   132     4 */
      	struct work_struct work;                         /*   136    32 */
      	char                       name[16];             /*   168    16 */
      
      	/* size: 192, cachelines: 3, members: 21 */
      	/* sum members: 146, holes: 1, sum holes: 38 */
      	/* padding: 8 */
      	/* forced alignments: 2, forced holes: 1, sum forced holes: 38 */
      } __attribute__((__aligned__(64)));
      
      AFTER (same 3 cache lines, no extra padding now):
      struct bpf_map {
      	const struct bpf_map_ops  * ops __attribute__((__aligned__(64))); /*     0     8 */
      	struct bpf_map *           inner_map_meta;       /*     8     8 */
      	void *                     security;             /*    16     8 */
      	enum bpf_map_type  map_type;                     /*    24     4 */
      	u32                        key_size;             /*    28     4 */
      	u32                        value_size;           /*    32     4 */
      	u32                        max_entries;          /*    36     4 */
      	u32                        map_flags;            /*    40     4 */
      	int                        spin_lock_off;        /*    44     4 */
      	u32                        id;                   /*    48     4 */
      	int                        numa_node;            /*    52     4 */
      	u32                        btf_key_type_id;      /*    56     4 */
      	u32                        btf_value_type_id;    /*    60     4 */
      	/* --- cacheline 1 boundary (64 bytes) --- */
      	struct btf *               btf;                  /*    64     8 */
      	struct bpf_map_memory memory;                    /*    72    16 */
      	bool                       unpriv_array;         /*    88     1 */
      	bool                       frozen;               /*    89     1 */
      
      	/* XXX 38 bytes hole, try to pack */
      
      	/* --- cacheline 2 boundary (128 bytes) --- */
      	atomic64_t                 refcnt __attribute__((__aligned__(64))); /*   128     8 */
      	atomic64_t                 usercnt;              /*   136     8 */
      	struct work_struct work;                         /*   144    32 */
      	char                       name[16];             /*   176    16 */
      
      	/* size: 192, cachelines: 3, members: 21 */
      	/* sum members: 154, holes: 1, sum holes: 38 */
      	/* forced alignments: 2, forced holes: 1, sum forced holes: 38 */
      } __attribute__((__aligned__(64)));
      
      This patch, while modifying all users of bpf_map_inc, also cleans up its
      interface to match bpf_map_put with separate operations for bpf_map_inc and
      bpf_map_inc_with_uref (to match bpf_map_put and bpf_map_put_with_uref,
      respectively). Also, given there are no users of bpf_map_inc_not_zero
      specifying uref=true, remove uref flag and default to uref=false internally.
      
      Signed-off-by: default avatarAndrii Nakryiko <andriin@fb.com>
      Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
      Acked-by: default avatarSong Liu <songliubraving@fb.com>
      Link: https://lore.kernel.org/bpf/20191117172806.2195367-2-andriin@fb.com
      1e0bd5a0
  3. Nov 16, 2019
  4. Nov 12, 2019
  5. Nov 11, 2019
    • Yonghong Song's avatar
      bpf, testing: Workaround a verifier failure for test_progs · b7a0d65d
      Yonghong Song authored
      
      
      With latest llvm compiler, running test_progs will have the following
      verifier failure for test_sysctl_loop1.o:
      
        libbpf: load bpf program failed: Permission denied
        libbpf: -- BEGIN DUMP LOG ---
        libbpf:
        invalid indirect read from stack var_off (0x0; 0xff)+196 size 7
        ...
        libbpf: -- END LOG --
        libbpf: failed to load program 'cgroup/sysctl'
        libbpf: failed to load object 'test_sysctl_loop1.o'
      
      The related bytecode looks as below:
      
        0000000000000308 LBB0_8:
            97:       r4 = r10
            98:       r4 += -288
            99:       r4 += r7
           100:       w8 &= 255
           101:       r1 = r10
           102:       r1 += -488
           103:       r1 += r8
           104:       r2 = 7
           105:       r3 = 0
           106:       call 106
           107:       w1 = w0
           108:       w1 += -1
           109:       if w1 > 6 goto -24 <LBB0_5>
           110:       w0 += w8
           111:       r7 += 8
           112:       w8 = w0
           113:       if r7 != 224 goto -17 <LBB0_8>
      
      And source code:
      
           for (i = 0; i < ARRAY_SIZE(tcp_mem); ++i) {
                   ret = bpf_strtoul(value + off, MAX_ULONG_STR_LEN, 0,
                                     tcp_mem + i);
                   if (ret <= 0 || ret > MAX_ULONG_STR_LEN)
                           return 0;
                   off += ret & MAX_ULONG_STR_LEN;
           }
      
      Current verifier is not able to conclude that register w0 before '+'
      at insn 110 has a range of 1 to 7 and thinks it is from 0 - 255. This
      leads to more conservative range for w8 at insn 112, and later verifier
      complaint.
      
      Let us workaround this issue until we found a compiler and/or verifier
      solution. The workaround in this patch is to make variable 'ret' volatile,
      which will force a reload and then '&' operation to ensure better value
      range. With this patch, I got the below byte code for the loop:
      
        0000000000000328 LBB0_9:
           101:       r4 = r10
           102:       r4 += -288
           103:       r4 += r7
           104:       w8 &= 255
           105:       r1 = r10
           106:       r1 += -488
           107:       r1 += r8
           108:       r2 = 7
           109:       r3 = 0
           110:       call 106
           111:       *(u32 *)(r10 - 64) = r0
           112:       r1 = *(u32 *)(r10 - 64)
           113:       if w1 s< 1 goto -28 <LBB0_5>
           114:       r1 = *(u32 *)(r10 - 64)
           115:       if w1 s> 7 goto -30 <LBB0_5>
           116:       r1 = *(u32 *)(r10 - 64)
           117:       w1 &= 7
           118:       w1 += w8
           119:       r7 += 8
           120:       w8 = w1
           121:       if r7 != 224 goto -21 <LBB0_9>
      
      Insn 117 did the '&' operation and we got more precise value range
      for 'w8' at insn 120. The test is happy then:
      
        #3/17 test_sysctl_loop1.o:OK
      
      Signed-off-by: default avatarYonghong Song <yhs@fb.com>
      Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
      Acked-by: default avatarSong Liu <songliubraving@fb.com>
      Link: https://lore.kernel.org/bpf/20191107170045.2503480-1-yhs@fb.com
      b7a0d65d
    • Alexei Starovoitov's avatar
      Merge branch 'share-umem' · 0d2ec5b5
      Alexei Starovoitov authored
      Magnus Karlsson says:
      
      ====================
      This patch set extends libbpf and the xdpsock sample program to
      demonstrate the shared umem mode (XDP_SHARED_UMEM) as well as Rx-only
      and Tx-only sockets. This in order for users to have an example to use
      as a blue print and also so that these modes will be exercised more
      frequently.
      
      Note that the user needs to supply an XDP program with the
      XDP_SHARED_UMEM mode that distributes the packets over the sockets
      according to some policy. There is an example supplied with the
      xdpsock program, but there is no default one in libbpf similarly to
      when XDP_SHARED_UMEM is not used. The reason for this is that I felt
      that supplying one that would work for all users in this mode is
      futile. There are just tons of ways to distribute packets, so whatever
      I come up with and build into libbpf would be wrong in most cases.
      
      This patch has been applied against commit 30ee348c
      
       ("Merge branch 'bpf-libbpf-fixes'")
      
      Structure of the patch set:
      
      Patch 1: Adds shared umem support to libbpf
      Patch 2: Shared umem support and example XPD program added to xdpsock sample
      Patch 3: Adds Rx-only and Tx-only support to libbpf
      Patch 4: Uses Rx-only sockets for rxdrop and Tx-only sockets for txpush in
               the xdpsock sample
      Patch 5: Add documentation entries for these two features
      ====================
      
      Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
      0d2ec5b5
    • Magnus Karlsson's avatar
      xsk: Extend documentation for Rx|Tx-only sockets and shared umems · 57afa8b0
      Magnus Karlsson authored
      
      
      Add more documentation about the new Rx-only and Tx-only sockets in
      libbpf and also how libbpf can now support shared umems. Also found
      two pieces that could be improved in the text, that got fixed in this
      commit.
      
      Signed-off-by: default avatarMagnus Karlsson <magnus.karlsson@intel.com>
      Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
      Tested-by: default avatarWilliam Tu <u9012063@gmail.com>
      Acked-by: default avatarJonathan Lemon <jonathan.lemon@gmail.com>
      Link: https://lore.kernel.org/bpf/1573148860-30254-6-git-send-email-magnus.karlsson@intel.com
      57afa8b0
    • Magnus Karlsson's avatar
      samples/bpf: Use Rx-only and Tx-only sockets in xdpsock · 661842c4
      Magnus Karlsson authored
      
      
      Use Rx-only sockets for the rxdrop sample and Tx-only sockets for the
      txpush sample in the xdpsock application. This so that we exercise and
      show case these socket types too.
      
      Signed-off-by: default avatarMagnus Karlsson <magnus.karlsson@intel.com>
      Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
      Tested-by: default avatarWilliam Tu <u9012063@gmail.com>
      Acked-by: default avatarJonathan Lemon <jonathan.lemon@gmail.com>
      Link: https://lore.kernel.org/bpf/1573148860-30254-5-git-send-email-magnus.karlsson@intel.com
      661842c4