Merge git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next
authorDavid S. Miller <davem@davemloft.net>
Thu, 17 Jun 2021 18:54:56 +0000 (11:54 -0700)
committerDavid S. Miller <davem@davemloft.net>
Thu, 17 Jun 2021 18:54:56 +0000 (11:54 -0700)
Daniel Borkmann says:

====================
pull-request: bpf-next 2021-06-17

The following pull-request contains BPF updates for your *net-next* tree.

We've added 50 non-merge commits during the last 25 day(s) which contain
a total of 148 files changed, 4779 insertions(+), 1248 deletions(-).

The main changes are:

1) BPF infrastructure to migrate TCP child sockets from a listener to another
   in the same reuseport group/map, from Kuniyuki Iwashima.

2) Add a provably sound, faster and more precise algorithm for tnum_mul() as
   noted in https://arxiv.org/abs/2105.05398, from Harishankar Vishwanathan.

3) Streamline error reporting changes in libbpf as planned out in the
   'libbpf: the road to v1.0' effort, from Andrii Nakryiko.

4) Add broadcast support to xdp_redirect_map(), from Hangbin Liu.

5) Extends bpf_map_lookup_and_delete_elem() functionality to 4 more map
   types, that is, {LRU_,PERCPU_,LRU_PERCPU_,}HASH, from Denis Salopek.

6) Support new LLVM relocations in libbpf to make them more linker friendly,
   also add a doc to describe the BPF backend relocations, from Yonghong Song.

7) Silence long standing KUBSAN complaints on register-based shifts in
   interpreter, from Daniel Borkmann and Eric Biggers.

8) Add dummy PT_REGS macros in libbpf to fail BPF program compilation when
   target arch cannot be determined, from Lorenz Bauer.

9) Extend AF_XDP to support large umems with 1M+ pages, from Magnus Karlsson.

10) Fix two minor libbpf tc BPF API issues, from Kumar Kartikeya Dwivedi.

11) Move libbpf BPF_SEQ_PRINTF/BPF_SNPRINTF macros that can be used by BPF
    programs to bpf_helpers.h header, from Florent Revest.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
1  2 
kernel/bpf/bpf_lsm.c
kernel/bpf/btf.c
kernel/bpf/syscall.c
kernel/bpf/verifier.c
net/core/filter.c
tools/lib/bpf/libbpf.c
tools/lib/bpf/libbpf_internal.h

diff --combined kernel/bpf/bpf_lsm.c
@@@ -107,12 -107,10 +107,12 @@@ bpf_lsm_func_proto(enum bpf_func_id fun
                return &bpf_inode_storage_get_proto;
        case BPF_FUNC_inode_storage_delete:
                return &bpf_inode_storage_delete_proto;
 +#ifdef CONFIG_NET
        case BPF_FUNC_sk_storage_get:
                return &bpf_sk_storage_get_proto;
        case BPF_FUNC_sk_storage_delete:
                return &bpf_sk_storage_delete_proto;
 +#endif /* CONFIG_NET */
        case BPF_FUNC_spin_lock:
                return &bpf_spin_lock_proto;
        case BPF_FUNC_spin_unlock:
  }
  
  /* The set of hooks which are called without pagefaults disabled and are allowed
-  * to "sleep" and thus can be used for sleeable BPF programs.
+  * to "sleep" and thus can be used for sleepable BPF programs.
   */
  BTF_SET_START(sleepable_lsm_hooks)
  BTF_ID(func, bpf_lsm_bpf)
diff --combined kernel/bpf/btf.c
@@@ -51,7 -51,7 +51,7 @@@
   * The BTF type section contains a list of 'struct btf_type' objects.
   * Each one describes a C type.  Recall from the above section
   * that a 'struct btf_type' object could be immediately followed by extra
-  * data in order to desribe some particular C types.
+  * data in order to describe some particular C types.
   *
   * type_id:
   * ~~~~~~~
@@@ -1143,7 -1143,7 +1143,7 @@@ static void *btf_show_obj_safe(struct b
  
        /*
         * We need a new copy to our safe object, either because we haven't
-        * yet copied and are intializing safe data, or because the data
+        * yet copied and are initializing safe data, or because the data
         * we want falls outside the boundaries of the safe object.
         */
        if (!safe) {
@@@ -3417,7 -3417,7 +3417,7 @@@ static struct btf_kind_operations func_
         * BTF_KIND_FUNC_PROTO cannot be directly referred by
         * a struct's member.
         *
-        * It should be a funciton pointer instead.
+        * It should be a function pointer instead.
         * (i.e. struct's member -> BTF_KIND_PTR -> BTF_KIND_FUNC_PROTO)
         *
         * Hence, there is no btf_func_check_member().
@@@ -5206,12 -5206,6 +5206,12 @@@ int btf_distill_func_proto(struct bpf_v
        m->ret_size = ret;
  
        for (i = 0; i < nargs; i++) {
 +              if (i == nargs - 1 && args[i].type == 0) {
 +                      bpf_log(log,
 +                              "The function %s with variable args is unsupported.\n",
 +                              tname);
 +                      return -EINVAL;
 +              }
                ret = __get_type_size(btf, args[i].type, &t);
                if (ret < 0) {
                        bpf_log(log,
                                tname, i, btf_kind_str[BTF_INFO_KIND(t->info)]);
                        return -EINVAL;
                }
 +              if (ret == 0) {
 +                      bpf_log(log,
 +                              "The function %s has malformed void argument.\n",
 +                              tname);
 +                      return -EINVAL;
 +              }
                m->arg_size[i] = ret;
        }
        m->nr_args = nargs;
diff --combined kernel/bpf/syscall.c
@@@ -50,8 -50,7 +50,8 @@@ static DEFINE_SPINLOCK(map_idr_lock)
  static DEFINE_IDR(link_idr);
  static DEFINE_SPINLOCK(link_idr_lock);
  
 -int sysctl_unprivileged_bpf_disabled __read_mostly;
 +int sysctl_unprivileged_bpf_disabled __read_mostly =
 +      IS_BUILTIN(CONFIG_BPF_UNPRIV_DEFAULT_OFF) ? 2 : 0;
  
  static const struct bpf_map_ops * const bpf_map_types[] = {
  #define BPF_PROG_TYPE(_id, _name, prog_ctx_type, kern_ctx_type)
@@@ -1484,7 -1483,7 +1484,7 @@@ free_buf
        return err;
  }
  
- #define BPF_MAP_LOOKUP_AND_DELETE_ELEM_LAST_FIELD value
+ #define BPF_MAP_LOOKUP_AND_DELETE_ELEM_LAST_FIELD flags
  
  static int map_lookup_and_delete_elem(union bpf_attr *attr)
  {
        if (CHECK_ATTR(BPF_MAP_LOOKUP_AND_DELETE_ELEM))
                return -EINVAL;
  
+       if (attr->flags & ~BPF_F_LOCK)
+               return -EINVAL;
        f = fdget(ufd);
        map = __bpf_map_get(f);
        if (IS_ERR(map))
                goto err_put;
        }
  
+       if (attr->flags &&
+           (map->map_type == BPF_MAP_TYPE_QUEUE ||
+            map->map_type == BPF_MAP_TYPE_STACK)) {
+               err = -EINVAL;
+               goto err_put;
+       }
+       if ((attr->flags & BPF_F_LOCK) &&
+           !map_value_has_spin_lock(map)) {
+               err = -EINVAL;
+               goto err_put;
+       }
        key = __bpf_copy_key(ukey, map->key_size);
        if (IS_ERR(key)) {
                err = PTR_ERR(key);
                goto err_put;
        }
  
-       value_size = map->value_size;
+       value_size = bpf_map_value_size(map);
  
        err = -ENOMEM;
        value = kmalloc(value_size, GFP_USER | __GFP_NOWARN);
        if (!value)
                goto free_key;
  
+       err = -ENOTSUPP;
        if (map->map_type == BPF_MAP_TYPE_QUEUE ||
            map->map_type == BPF_MAP_TYPE_STACK) {
                err = map->ops->map_pop_elem(map, value);
-       } else {
-               err = -ENOTSUPP;
+       } else if (map->map_type == BPF_MAP_TYPE_HASH ||
+                  map->map_type == BPF_MAP_TYPE_PERCPU_HASH ||
+                  map->map_type == BPF_MAP_TYPE_LRU_HASH ||
+                  map->map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH) {
+               if (!bpf_map_is_dev_bound(map)) {
+                       bpf_disable_instrumentation();
+                       rcu_read_lock();
+                       err = map->ops->map_lookup_and_delete_elem(map, key, value, attr->flags);
+                       rcu_read_unlock();
+                       bpf_enable_instrumentation();
+               }
        }
  
        if (err)
@@@ -1947,6 -1972,11 +1973,11 @@@ static void bpf_prog_load_fixup_attach_
                        attr->expected_attach_type =
                                BPF_CGROUP_INET_SOCK_CREATE;
                break;
+       case BPF_PROG_TYPE_SK_REUSEPORT:
+               if (!attr->expected_attach_type)
+                       attr->expected_attach_type =
+                               BPF_SK_REUSEPORT_SELECT;
+               break;
        }
  }
  
@@@ -2030,6 -2060,14 +2061,14 @@@ bpf_prog_load_check_attach(enum bpf_pro
                if (expected_attach_type == BPF_SK_LOOKUP)
                        return 0;
                return -EINVAL;
+       case BPF_PROG_TYPE_SK_REUSEPORT:
+               switch (expected_attach_type) {
+               case BPF_SK_REUSEPORT_SELECT:
+               case BPF_SK_REUSEPORT_SELECT_OR_MIGRATE:
+                       return 0;
+               default:
+                       return -EINVAL;
+               }
        case BPF_PROG_TYPE_SYSCALL:
        case BPF_PROG_TYPE_EXT:
                if (expected_attach_type)
diff --combined kernel/bpf/verifier.c
@@@ -47,7 -47,7 +47,7 @@@ static const struct bpf_verifier_ops * 
   * - unreachable insns exist (shouldn't be a forest. program = one function)
   * - out of bounds or malformed jumps
   * The second pass is all possible path descent from the 1st insn.
-  * Since it's analyzing all pathes through the program, the length of the
+  * Since it's analyzing all paths through the program, the length of the
   * analysis is limited to 64k insn, which may be hit even if total number of
   * insn is less then 4K, but there are too many branches that change stack/regs.
   * Number of 'branches to be analyzed' is limited to 1k
   * If it's ok, then verifier allows this BPF_CALL insn and looks at
   * .ret_type which is RET_PTR_TO_MAP_VALUE_OR_NULL, so it sets
   * R0->type = PTR_TO_MAP_VALUE_OR_NULL which means bpf_map_lookup_elem() function
-  * returns ether pointer to map value or NULL.
+  * returns either pointer to map value or NULL.
   *
   * When type PTR_TO_MAP_VALUE_OR_NULL passes through 'if (reg != 0) goto +off'
   * insn, the register holding that pointer in the true branch changes state to
@@@ -2616,7 -2616,7 +2616,7 @@@ static int check_stack_write_fixed_off(
                if (dst_reg != BPF_REG_FP) {
                        /* The backtracking logic can only recognize explicit
                         * stack slot address like [fp - 8]. Other spill of
-                        * scalar via different register has to be conervative.
+                        * scalar via different register has to be conservative.
                         * Backtrack from here and mark all registers as precise
                         * that contributed into 'reg' being a constant.
                         */
@@@ -6411,10 -6411,18 +6411,10 @@@ enum 
  };
  
  static int retrieve_ptr_limit(const struct bpf_reg_state *ptr_reg,
 -                            const struct bpf_reg_state *off_reg,
 -                            u32 *alu_limit, u8 opcode)
 +                            u32 *alu_limit, bool mask_to_left)
  {
 -      bool off_is_neg = off_reg->smin_value < 0;
 -      bool mask_to_left = (opcode == BPF_ADD &&  off_is_neg) ||
 -                          (opcode == BPF_SUB && !off_is_neg);
        u32 max = 0, ptr_limit = 0;
  
 -      if (!tnum_is_const(off_reg->var_off) &&
 -          (off_reg->smin_value < 0) != (off_reg->smax_value < 0))
 -              return REASON_BOUNDS;
 -
        switch (ptr_reg->type) {
        case PTR_TO_STACK:
                /* Offset 0 is out-of-bounds, but acceptable start for the
@@@ -6480,20 -6488,15 +6480,20 @@@ static bool sanitize_needed(u8 opcode
        return opcode == BPF_ADD || opcode == BPF_SUB;
  }
  
 +struct bpf_sanitize_info {
 +      struct bpf_insn_aux_data aux;
 +      bool mask_to_left;
 +};
 +
  static int sanitize_ptr_alu(struct bpf_verifier_env *env,
                            struct bpf_insn *insn,
                            const struct bpf_reg_state *ptr_reg,
                            const struct bpf_reg_state *off_reg,
                            struct bpf_reg_state *dst_reg,
 -                          struct bpf_insn_aux_data *tmp_aux,
 +                          struct bpf_sanitize_info *info,
                            const bool commit_window)
  {
 -      struct bpf_insn_aux_data *aux = commit_window ? cur_aux(env) : tmp_aux;
 +      struct bpf_insn_aux_data *aux = commit_window ? cur_aux(env) : &info->aux;
        struct bpf_verifier_state *vstate = env->cur_state;
        bool off_is_imm = tnum_is_const(off_reg->var_off);
        bool off_is_neg = off_reg->smin_value < 0;
        if (vstate->speculative)
                goto do_sim;
  
 -      err = retrieve_ptr_limit(ptr_reg, off_reg, &alu_limit, opcode);
 +      if (!commit_window) {
 +              if (!tnum_is_const(off_reg->var_off) &&
 +                  (off_reg->smin_value < 0) != (off_reg->smax_value < 0))
 +                      return REASON_BOUNDS;
 +
 +              info->mask_to_left = (opcode == BPF_ADD &&  off_is_neg) ||
 +                                   (opcode == BPF_SUB && !off_is_neg);
 +      }
 +
 +      err = retrieve_ptr_limit(ptr_reg, &alu_limit, info->mask_to_left);
        if (err < 0)
                return err;
  
                /* In commit phase we narrow the masking window based on
                 * the observed pointer move after the simulated operation.
                 */
 -              alu_state = tmp_aux->alu_state;
 -              alu_limit = abs(tmp_aux->alu_limit - alu_limit);
 +              alu_state = info->aux.alu_state;
 +              alu_limit = abs(info->aux.alu_limit - alu_limit);
        } else {
                alu_state  = off_is_neg ? BPF_ALU_NEG_VALUE : 0;
                alu_state |= off_is_imm ? BPF_ALU_IMMEDIATE : 0;
@@@ -6547,12 -6541,8 +6547,12 @@@ do_sim
        /* If we're in commit phase, we're done here given we already
         * pushed the truncated dst_reg into the speculative verification
         * stack.
 +       *
 +       * Also, when register is a known constant, we rewrite register-based
 +       * operation to immediate-based, and thus do not need masking (and as
 +       * a consequence, do not need to simulate the zero-truncation either).
         */
 -      if (commit_window)
 +      if (commit_window || off_is_imm)
                return 0;
  
        /* Simulate and find potential out-of-bounds access under
@@@ -6697,7 -6687,7 +6697,7 @@@ static int adjust_ptr_min_max_vals(stru
            smin_ptr = ptr_reg->smin_value, smax_ptr = ptr_reg->smax_value;
        u64 umin_val = off_reg->umin_value, umax_val = off_reg->umax_value,
            umin_ptr = ptr_reg->umin_value, umax_ptr = ptr_reg->umax_value;
 -      struct bpf_insn_aux_data tmp_aux = {};
 +      struct bpf_sanitize_info info = {};
        u8 opcode = BPF_OP(insn->code);
        u32 dst = insn->dst_reg;
        int ret;
  
        if (sanitize_needed(opcode)) {
                ret = sanitize_ptr_alu(env, insn, ptr_reg, off_reg, dst_reg,
 -                                     &tmp_aux, false);
 +                                     &info, false);
                if (ret < 0)
                        return sanitize_err(env, insn, ret, off_reg, dst_reg);
        }
                return -EACCES;
        if (sanitize_needed(opcode)) {
                ret = sanitize_ptr_alu(env, insn, dst_reg, off_reg, dst_reg,
 -                                     &tmp_aux, true);
 +                                     &info, true);
                if (ret < 0)
                        return sanitize_err(env, insn, ret, off_reg, dst_reg);
        }
@@@ -7096,10 -7086,11 +7096,10 @@@ static void scalar32_min_max_and(struc
        s32 smin_val = src_reg->s32_min_value;
        u32 umax_val = src_reg->u32_max_value;
  
 -      /* Assuming scalar64_min_max_and will be called so its safe
 -       * to skip updating register for known 32-bit case.
 -       */
 -      if (src_known && dst_known)
 +      if (src_known && dst_known) {
 +              __mark_reg32_known(dst_reg, var32_off.value);
                return;
 +      }
  
        /* We get our minimum from the var_off, since that's inherently
         * bitwise.  Our maximum is the minimum of the operands' maxima.
                dst_reg->s32_min_value = dst_reg->u32_min_value;
                dst_reg->s32_max_value = dst_reg->u32_max_value;
        }
 -
  }
  
  static void scalar_min_max_and(struct bpf_reg_state *dst_reg,
@@@ -7165,10 -7157,11 +7165,10 @@@ static void scalar32_min_max_or(struct 
        s32 smin_val = src_reg->s32_min_value;
        u32 umin_val = src_reg->u32_min_value;
  
 -      /* Assuming scalar64_min_max_or will be called so it is safe
 -       * to skip updating register for known case.
 -       */
 -      if (src_known && dst_known)
 +      if (src_known && dst_known) {
 +              __mark_reg32_known(dst_reg, var32_off.value);
                return;
 +      }
  
        /* We get our maximum from the var_off, and our minimum is the
         * maximum of the operands' minima
@@@ -7233,10 -7226,11 +7233,10 @@@ static void scalar32_min_max_xor(struc
        struct tnum var32_off = tnum_subreg(dst_reg->var_off);
        s32 smin_val = src_reg->s32_min_value;
  
 -      /* Assuming scalar64_min_max_xor will be called so it is safe
 -       * to skip updating register for known case.
 -       */
 -      if (src_known && dst_known)
 +      if (src_known && dst_known) {
 +              __mark_reg32_known(dst_reg, var32_off.value);
                return;
 +      }
  
        /* We get both minimum and maximum from the var32_off. */
        dst_reg->u32_min_value = var32_off.value;
@@@ -9059,7 -9053,7 +9059,7 @@@ static int check_return_code(struct bpf
            !prog->aux->attach_func_proto->type)
                return 0;
  
-       /* eBPF calling convetion is such that R0 is used
+       /* eBPF calling convention is such that R0 is used
         * to return the value from eBPF program.
         * Make sure that it's readable at this time
         * of bpf_exit, which means that program wrote
@@@ -9850,7 -9844,7 +9850,7 @@@ static void clean_verifier_state(struc
   * Since the verifier pushes the branch states as it sees them while exploring
   * the program the condition of walking the branch instruction for the second
   * time means that all states below this branch were already explored and
-  * their final liveness markes are already propagated.
+  * their final liveness marks are already propagated.
   * Hence when the verifier completes the search of state list in is_state_visited()
   * we can call this clean_live_states() function to mark all liveness states
   * as REG_LIVE_DONE to indicate that 'parent' pointers of 'struct bpf_reg_state'
@@@ -12470,7 -12464,7 +12470,7 @@@ static int do_misc_fixups(struct bpf_ve
                        prog->aux->max_pkt_offset = MAX_PACKET_OFF;
  
                        /* mark bpf_tail_call as different opcode to avoid
-                        * conditional branch in the interpeter for every normal
+                        * conditional branch in the interpreter for every normal
                         * call and to prevent accidental JITing by JIT compiler
                         * that doesn't support bpf_tail_call yet
                         */
@@@ -13221,17 -13215,6 +13221,17 @@@ int bpf_check_attach_target(struct bpf_
        return 0;
  }
  
 +BTF_SET_START(btf_id_deny)
 +BTF_ID_UNUSED
 +#ifdef CONFIG_SMP
 +BTF_ID(func, migrate_disable)
 +BTF_ID(func, migrate_enable)
 +#endif
 +#if !defined CONFIG_PREEMPT_RCU && !defined CONFIG_TINY_RCU
 +BTF_ID(func, rcu_read_unlock_strict)
 +#endif
 +BTF_SET_END(btf_id_deny)
 +
  static int check_attach_btf_id(struct bpf_verifier_env *env)
  {
        struct bpf_prog *prog = env->prog;
                ret = bpf_lsm_verify_prog(&env->log, prog);
                if (ret < 0)
                        return ret;
 +      } else if (prog->type == BPF_PROG_TYPE_TRACING &&
 +                 btf_id_set_contains(&btf_id_deny, btf_id)) {
 +              return -EINVAL;
        }
  
        key = bpf_trampoline_compute_key(tgt_prog, prog->aux->attach_btf, btf_id);
@@@ -13401,6 -13381,12 +13401,6 @@@ int bpf_check(struct bpf_prog **prog, u
        if (is_priv)
                env->test_state_freq = attr->prog_flags & BPF_F_TEST_STATE_FREQ;
  
 -      if (bpf_prog_is_dev_bound(env->prog->aux)) {
 -              ret = bpf_prog_offload_verifier_prep(env->prog);
 -              if (ret)
 -                      goto skip_full_check;
 -      }
 -
        env->explored_states = kvcalloc(state_htab_size(env),
                                       sizeof(struct bpf_verifier_state_list *),
                                       GFP_USER);
        if (ret < 0)
                goto skip_full_check;
  
 +      if (bpf_prog_is_dev_bound(env->prog->aux)) {
 +              ret = bpf_prog_offload_verifier_prep(env->prog);
 +              if (ret)
 +                      goto skip_full_check;
 +      }
 +
        ret = check_cfg(env);
        if (ret < 0)
                goto skip_full_check;
diff --combined net/core/filter.c
@@@ -3788,7 -3788,6 +3788,7 @@@ static inline int __bpf_skb_change_head
                __skb_push(skb, head_room);
                memset(skb->data, 0, head_room);
                skb_reset_mac_header(skb);
 +              skb_reset_mac_len(skb);
        }
  
        return ret;
@@@ -3931,6 -3930,23 +3931,23 @@@ void xdp_do_flush(void
  }
  EXPORT_SYMBOL_GPL(xdp_do_flush);
  
+ void bpf_clear_redirect_map(struct bpf_map *map)
+ {
+       struct bpf_redirect_info *ri;
+       int cpu;
+       for_each_possible_cpu(cpu) {
+               ri = per_cpu_ptr(&bpf_redirect_info, cpu);
+               /* Avoid polluting remote cacheline due to writes if
+                * not needed. Once we pass this test, we need the
+                * cmpxchg() to make sure it hasn't been changed in
+                * the meantime by remote CPU.
+                */
+               if (unlikely(READ_ONCE(ri->map) == map))
+                       cmpxchg(&ri->map, map, NULL);
+       }
+ }
  int xdp_do_redirect(struct net_device *dev, struct xdp_buff *xdp,
                    struct bpf_prog *xdp_prog)
  {
        enum bpf_map_type map_type = ri->map_type;
        void *fwd = ri->tgt_value;
        u32 map_id = ri->map_id;
+       struct bpf_map *map;
        int err;
  
        ri->map_id = 0; /* Valid map id idr range: [1,INT_MAX[ */
        case BPF_MAP_TYPE_DEVMAP:
                fallthrough;
        case BPF_MAP_TYPE_DEVMAP_HASH:
-               err = dev_map_enqueue(fwd, xdp, dev);
+               map = READ_ONCE(ri->map);
+               if (unlikely(map)) {
+                       WRITE_ONCE(ri->map, NULL);
+                       err = dev_map_enqueue_multi(xdp, dev, map,
+                                                   ri->flags & BPF_F_EXCLUDE_INGRESS);
+               } else {
+                       err = dev_map_enqueue(fwd, xdp, dev);
+               }
                break;
        case BPF_MAP_TYPE_CPUMAP:
                err = cpu_map_enqueue(fwd, xdp, dev);
@@@ -3989,13 -4013,21 +4014,21 @@@ static int xdp_do_generic_redirect_map(
                                       enum bpf_map_type map_type, u32 map_id)
  {
        struct bpf_redirect_info *ri = this_cpu_ptr(&bpf_redirect_info);
+       struct bpf_map *map;
        int err;
  
        switch (map_type) {
        case BPF_MAP_TYPE_DEVMAP:
                fallthrough;
        case BPF_MAP_TYPE_DEVMAP_HASH:
-               err = dev_map_generic_redirect(fwd, skb, xdp_prog);
+               map = READ_ONCE(ri->map);
+               if (unlikely(map)) {
+                       WRITE_ONCE(ri->map, NULL);
+                       err = dev_map_redirect_multi(dev, skb, xdp_prog, map,
+                                                    ri->flags & BPF_F_EXCLUDE_INGRESS);
+               } else {
+                       err = dev_map_generic_redirect(fwd, skb, xdp_prog);
+               }
                if (unlikely(err))
                        goto err;
                break;
  static void bpf_init_reuseport_kern(struct sk_reuseport_kern *reuse_kern,
                                    struct sock_reuseport *reuse,
                                    struct sock *sk, struct sk_buff *skb,
+                                   struct sock *migrating_sk,
                                    u32 hash)
  {
        reuse_kern->skb = skb;
        reuse_kern->sk = sk;
        reuse_kern->selected_sk = NULL;
+       reuse_kern->migrating_sk = migrating_sk;
        reuse_kern->data_end = skb->data + skb_headlen(skb);
        reuse_kern->hash = hash;
        reuse_kern->reuseport_id = reuse->reuseport_id;
  
  struct sock *bpf_run_sk_reuseport(struct sock_reuseport *reuse, struct sock *sk,
                                  struct bpf_prog *prog, struct sk_buff *skb,
+                                 struct sock *migrating_sk,
                                  u32 hash)
  {
        struct sk_reuseport_kern reuse_kern;
        enum sk_action action;
  
-       bpf_init_reuseport_kern(&reuse_kern, reuse, sk, skb, hash);
+       bpf_init_reuseport_kern(&reuse_kern, reuse, sk, skb, migrating_sk, hash);
        action = BPF_PROG_RUN(prog, &reuse_kern);
  
        if (action == SK_PASS)
@@@ -10140,6 -10175,8 +10176,8 @@@ sk_reuseport_func_proto(enum bpf_func_i
                return &sk_reuseport_load_bytes_proto;
        case BPF_FUNC_skb_load_bytes_relative:
                return &sk_reuseport_load_bytes_relative_proto;
+       case BPF_FUNC_get_socket_cookie:
+               return &bpf_get_socket_ptr_cookie_proto;
        default:
                return bpf_base_func_proto(func_id);
        }
@@@ -10169,6 -10206,14 +10207,14 @@@ sk_reuseport_is_valid_access(int off, i
        case offsetof(struct sk_reuseport_md, hash):
                return size == size_default;
  
+       case offsetof(struct sk_reuseport_md, sk):
+               info->reg_type = PTR_TO_SOCKET;
+               return size == sizeof(__u64);
+       case offsetof(struct sk_reuseport_md, migrating_sk):
+               info->reg_type = PTR_TO_SOCK_COMMON_OR_NULL;
+               return size == sizeof(__u64);
        /* Fields that allow narrowing */
        case bpf_ctx_range(struct sk_reuseport_md, eth_protocol):
                if (size < sizeof_field(struct sk_buff, protocol))
@@@ -10241,6 -10286,14 +10287,14 @@@ static u32 sk_reuseport_convert_ctx_acc
        case offsetof(struct sk_reuseport_md, bind_inany):
                SK_REUSEPORT_LOAD_FIELD(bind_inany);
                break;
+       case offsetof(struct sk_reuseport_md, sk):
+               SK_REUSEPORT_LOAD_FIELD(sk);
+               break;
+       case offsetof(struct sk_reuseport_md, migrating_sk):
+               SK_REUSEPORT_LOAD_FIELD(migrating_sk);
+               break;
        }
  
        return insn - insn_buf;
diff --combined tools/lib/bpf/libbpf.c
@@@ -151,6 -151,23 +151,23 @@@ static inline __u64 ptr_to_u64(const vo
        return (__u64) (unsigned long) ptr;
  }
  
+ /* this goes away in libbpf 1.0 */
+ enum libbpf_strict_mode libbpf_mode = LIBBPF_STRICT_NONE;
+ int libbpf_set_strict_mode(enum libbpf_strict_mode mode)
+ {
+       /* __LIBBPF_STRICT_LAST is the last power-of-2 value used + 1, so to
+        * get all possible values we compensate last +1, and then (2*x - 1)
+        * to get the bit mask
+        */
+       if (mode != LIBBPF_STRICT_ALL
+           && (mode & ~((__LIBBPF_STRICT_LAST - 1) * 2 - 1)))
+               return errno = EINVAL, -EINVAL;
+       libbpf_mode = mode;
+       return 0;
+ }
  enum kern_feature_id {
        /* v4.14: kernel support for program & map names. */
        FEAT_PROG_NAME,
@@@ -2448,10 -2465,8 +2465,8 @@@ static int bpf_object__init_maps(struc
        err = err ?: bpf_object__init_global_data_maps(obj);
        err = err ?: bpf_object__init_kconfig_map(obj);
        err = err ?: bpf_object__init_struct_ops_maps(obj);
-       if (err)
-               return err;
  
-       return 0;
+       return err;
  }
  
  static bool section_have_execinstr(struct bpf_object *obj, int idx)
@@@ -2562,16 -2577,14 +2577,14 @@@ static int bpf_object__init_btf(struct 
  
        if (btf_data) {
                obj->btf = btf__new(btf_data->d_buf, btf_data->d_size);
-               if (IS_ERR(obj->btf)) {
-                       err = PTR_ERR(obj->btf);
+               err = libbpf_get_error(obj->btf);
+               if (err) {
                        obj->btf = NULL;
-                       pr_warn("Error loading ELF section %s: %d.\n",
-                               BTF_ELF_SEC, err);
+                       pr_warn("Error loading ELF section %s: %d.\n", BTF_ELF_SEC, err);
                        goto out;
                }
                /* enforce 8-byte pointers for BPF-targeted BTFs */
                btf__set_pointer_size(obj->btf, 8);
-               err = 0;
        }
        if (btf_ext_data) {
                if (!obj->btf) {
                                 BTF_EXT_ELF_SEC, BTF_ELF_SEC);
                        goto out;
                }
-               obj->btf_ext = btf_ext__new(btf_ext_data->d_buf,
-                                           btf_ext_data->d_size);
-               if (IS_ERR(obj->btf_ext)) {
-                       pr_warn("Error loading ELF section %s: %ld. Ignored and continue.\n",
-                               BTF_EXT_ELF_SEC, PTR_ERR(obj->btf_ext));
+               obj->btf_ext = btf_ext__new(btf_ext_data->d_buf, btf_ext_data->d_size);
+               err = libbpf_get_error(obj->btf_ext);
+               if (err) {
+                       pr_warn("Error loading ELF section %s: %d. Ignored and continue.\n",
+                               BTF_EXT_ELF_SEC, err);
                        obj->btf_ext = NULL;
                        goto out;
                }
@@@ -2667,8 -2680,8 +2680,8 @@@ static int bpf_object__load_vmlinux_btf
                return 0;
  
        obj->btf_vmlinux = libbpf_find_kernel_btf();
-       if (IS_ERR(obj->btf_vmlinux)) {
-               err = PTR_ERR(obj->btf_vmlinux);
+       err = libbpf_get_error(obj->btf_vmlinux);
+       if (err) {
                pr_warn("Error loading vmlinux BTF: %d\n", err);
                obj->btf_vmlinux = NULL;
                return err;
@@@ -2734,8 -2747,9 +2747,9 @@@ static int bpf_object__sanitize_and_loa
                /* clone BTF to sanitize a copy and leave the original intact */
                raw_data = btf__get_raw_data(obj->btf, &sz);
                kern_btf = btf__new(raw_data, sz);
-               if (IS_ERR(kern_btf))
-                       return PTR_ERR(kern_btf);
+               err = libbpf_get_error(kern_btf);
+               if (err)
+                       return err;
  
                /* enforce 8-byte pointers for BPF-targeted BTFs */
                btf__set_pointer_size(obj->btf, 8);
@@@ -3252,9 -3266,6 +3266,9 @@@ static int add_dummy_ksym_var(struct bt
        const struct btf_var_secinfo *vs;
        const struct btf_type *sec;
  
 +      if (!btf)
 +              return 0;
 +
        sec_btf_id = btf__find_by_name_kind(btf, KSYMS_SEC,
                                            BTF_KIND_DATASEC);
        if (sec_btf_id < 0)
@@@ -3509,7 -3520,7 +3523,7 @@@ bpf_object__find_program_by_title(cons
                if (pos->sec_name && !strcmp(pos->sec_name, title))
                        return pos;
        }
-       return NULL;
+       return errno = ENOENT, NULL;
  }
  
  static bool prog_is_subprog(const struct bpf_object *obj,
@@@ -3542,7 -3553,7 +3556,7 @@@ bpf_object__find_program_by_name(const 
                if (!strcmp(prog->name, name))
                        return prog;
        }
-       return NULL;
+       return errno = ENOENT, NULL;
  }
  
  static bool bpf_object__shndx_is_data(const struct bpf_object *obj,
@@@ -3889,11 -3900,11 +3903,11 @@@ int bpf_map__reuse_fd(struct bpf_map *m
  
        err = bpf_obj_get_info_by_fd(fd, &info, &len);
        if (err)
-               return err;
+               return libbpf_err(err);
  
        new_name = strdup(info.name);
        if (!new_name)
-               return -errno;
+               return libbpf_err(-errno);
  
        new_fd = open("/", O_RDONLY | O_CLOEXEC);
        if (new_fd < 0) {
@@@ -3931,7 -3942,7 +3945,7 @@@ err_close_new_fd
        close(new_fd);
  err_free_new_name:
        free(new_name);
-       return err;
+       return libbpf_err(err);
  }
  
  __u32 bpf_map__max_entries(const struct bpf_map *map)
  struct bpf_map *bpf_map__inner_map(struct bpf_map *map)
  {
        if (!bpf_map_type__is_map_in_map(map->def.type))
-               return NULL;
+               return errno = EINVAL, NULL;
  
        return map->inner_map;
  }
  int bpf_map__set_max_entries(struct bpf_map *map, __u32 max_entries)
  {
        if (map->fd >= 0)
-               return -EBUSY;
+               return libbpf_err(-EBUSY);
        map->def.max_entries = max_entries;
        return 0;
  }
  int bpf_map__resize(struct bpf_map *map, __u32 max_entries)
  {
        if (!map || !max_entries)
-               return -EINVAL;
+               return libbpf_err(-EINVAL);
  
        return bpf_map__set_max_entries(map, max_entries);
  }
@@@ -3974,6 -3985,9 +3988,9 @@@ bpf_object__probe_loading(struct bpf_ob
        };
        int ret;
  
+       if (obj->gen_loader)
+               return 0;
        /* make sure basic loading works */
  
        memset(&attr, 0, sizeof(attr));
@@@ -4565,7 -4579,7 +4582,7 @@@ static int init_map_slots(struct bpf_ob
                targ_map = map->init_slots[i];
                fd = bpf_map__fd(targ_map);
                if (obj->gen_loader) {
-                       pr_warn("// TODO map_update_elem: idx %ld key %d value==map_idx %ld\n",
+                       pr_warn("// TODO map_update_elem: idx %td key %d value==map_idx %td\n",
                                map - obj->maps, i, targ_map - obj->maps);
                        return -ENOTSUP;
                } else {
@@@ -5086,10 -5100,10 +5103,10 @@@ static int load_module_btfs(struct bpf_
                }
  
                btf = btf_get_from_fd(fd, obj->btf_vmlinux);
-               if (IS_ERR(btf)) {
-                       pr_warn("failed to load module [%s]'s BTF object #%d: %ld\n",
-                               name, id, PTR_ERR(btf));
-                       err = PTR_ERR(btf);
+               err = libbpf_get_error(btf);
+               if (err) {
+                       pr_warn("failed to load module [%s]'s BTF object #%d: %d\n",
+                               name, id, err);
                        goto err_out;
                }
  
@@@ -6189,7 -6203,7 +6206,7 @@@ static int bpf_core_apply_relo(struct b
                return -EINVAL;
  
        if (prog->obj->gen_loader) {
-               pr_warn("// TODO core_relo: prog %ld insn[%d] %s %s kind %d\n",
+               pr_warn("// TODO core_relo: prog %td insn[%d] %s %s kind %d\n",
                        prog - prog->obj->programs, relo->insn_off / 8,
                        local_name, spec_str, relo->kind);
                return -ENOTSUP;
@@@ -6349,8 -6363,8 +6366,8 @@@ bpf_object__relocate_core(struct bpf_ob
  
        if (targ_btf_path) {
                obj->btf_vmlinux_override = btf__parse(targ_btf_path, NULL);
-               if (IS_ERR_OR_NULL(obj->btf_vmlinux_override)) {
-                       err = PTR_ERR(obj->btf_vmlinux_override);
+               err = libbpf_get_error(obj->btf_vmlinux_override);
+               if (err) {
                        pr_warn("failed to parse target BTF: %d\n", err);
                        return err;
                }
@@@ -7407,7 -7421,7 +7424,7 @@@ int bpf_program__load(struct bpf_progra
  
        if (prog->obj->loaded) {
                pr_warn("prog '%s': can't load after object was loaded\n", prog->name);
-               return -EINVAL;
+               return libbpf_err(-EINVAL);
        }
  
        if ((prog->type == BPF_PROG_TYPE_TRACING ||
  
                err = libbpf_find_attach_btf_id(prog, &btf_obj_fd, &btf_type_id);
                if (err)
-                       return err;
+                       return libbpf_err(err);
  
                prog->attach_btf_obj_fd = btf_obj_fd;
                prog->attach_btf_id = btf_type_id;
                if (prog->preprocessor) {
                        pr_warn("Internal error: can't load program '%s'\n",
                                prog->name);
-                       return -LIBBPF_ERRNO__INTERNAL;
+                       return libbpf_err(-LIBBPF_ERRNO__INTERNAL);
                }
  
                prog->instances.fds = malloc(sizeof(int));
                if (!prog->instances.fds) {
                        pr_warn("Not enough memory for BPF fds\n");
-                       return -ENOMEM;
+                       return libbpf_err(-ENOMEM);
                }
                prog->instances.nr = 1;
                prog->instances.fds[0] = -1;
@@@ -7492,7 -7506,7 +7509,7 @@@ out
                pr_warn("failed to load program '%s'\n", prog->name);
        zfree(&prog->insns);
        prog->insns_cnt = 0;
-       return err;
+       return libbpf_err(err);
  }
  
  static int
@@@ -7625,7 -7639,7 +7642,7 @@@ __bpf_object__open_xattr(struct bpf_obj
  
  struct bpf_object *bpf_object__open_xattr(struct bpf_object_open_attr *attr)
  {
-       return __bpf_object__open_xattr(attr, 0);
+       return libbpf_ptr(__bpf_object__open_xattr(attr, 0));
  }
  
  struct bpf_object *bpf_object__open(const char *path)
                .prog_type      = BPF_PROG_TYPE_UNSPEC,
        };
  
-       return bpf_object__open_xattr(&attr);
+       return libbpf_ptr(__bpf_object__open_xattr(&attr, 0));
  }
  
  struct bpf_object *
  bpf_object__open_file(const char *path, const struct bpf_object_open_opts *opts)
  {
        if (!path)
-               return ERR_PTR(-EINVAL);
+               return libbpf_err_ptr(-EINVAL);
  
        pr_debug("loading %s\n", path);
  
-       return __bpf_object__open(path, NULL, 0, opts);
+       return libbpf_ptr(__bpf_object__open(path, NULL, 0, opts));
  }
  
  struct bpf_object *
@@@ -7654,9 -7668,9 +7671,9 @@@ bpf_object__open_mem(const void *obj_bu
                     const struct bpf_object_open_opts *opts)
  {
        if (!obj_buf || obj_buf_sz == 0)
-               return ERR_PTR(-EINVAL);
+               return libbpf_err_ptr(-EINVAL);
  
-       return __bpf_object__open(NULL, obj_buf, obj_buf_sz, opts);
+       return libbpf_ptr(__bpf_object__open(NULL, obj_buf, obj_buf_sz, opts));
  }
  
  struct bpf_object *
@@@ -7671,9 -7685,9 +7688,9 @@@ bpf_object__open_buffer(const void *obj
  
        /* returning NULL is wrong, but backwards-compatible */
        if (!obj_buf || obj_buf_sz == 0)
-               return NULL;
+               return errno = EINVAL, NULL;
  
-       return bpf_object__open_mem(obj_buf, obj_buf_sz, &opts);
+       return libbpf_ptr(__bpf_object__open(NULL, obj_buf, obj_buf_sz, &opts));
  }
  
  int bpf_object__unload(struct bpf_object *obj)
        size_t i;
  
        if (!obj)
-               return -EINVAL;
+               return libbpf_err(-EINVAL);
  
        for (i = 0; i < obj->nr_maps; i++) {
                zclose(obj->maps[i].fd);
@@@ -8014,14 -8028,14 +8031,14 @@@ int bpf_object__load_xattr(struct bpf_o
        int err, i;
  
        if (!attr)
-               return -EINVAL;
+               return libbpf_err(-EINVAL);
        obj = attr->obj;
        if (!obj)
-               return -EINVAL;
+               return libbpf_err(-EINVAL);
  
        if (obj->loaded) {
                pr_warn("object '%s': load can't be attempted twice\n", obj->name);
-               return -EINVAL;
+               return libbpf_err(-EINVAL);
        }
  
        if (obj->gen_loader)
@@@ -8072,7 -8086,7 +8089,7 @@@ out
  
        bpf_object__unload(obj);
        pr_warn("failed to load object '%s'\n", obj->path);
-       return err;
+       return libbpf_err(err);
  }
  
  int bpf_object__load(struct bpf_object *obj)
@@@ -8144,28 -8158,28 +8161,28 @@@ int bpf_program__pin_instance(struct bp
  
        err = make_parent_dir(path);
        if (err)
-               return err;
+               return libbpf_err(err);
  
        err = check_path(path);
        if (err)
-               return err;
+               return libbpf_err(err);
  
        if (prog == NULL) {
                pr_warn("invalid program pointer\n");
-               return -EINVAL;
+               return libbpf_err(-EINVAL);
        }
  
        if (instance < 0 || instance >= prog->instances.nr) {
                pr_warn("invalid prog instance %d of prog %s (max %d)\n",
                        instance, prog->name, prog->instances.nr);
-               return -EINVAL;
+               return libbpf_err(-EINVAL);
        }
  
        if (bpf_obj_pin(prog->instances.fds[instance], path)) {
                err = -errno;
                cp = libbpf_strerror_r(err, errmsg, sizeof(errmsg));
                pr_warn("failed to pin program: %s\n", cp);
-               return err;
+               return libbpf_err(err);
        }
        pr_debug("pinned program '%s'\n", path);
  
@@@ -8179,22 -8193,23 +8196,23 @@@ int bpf_program__unpin_instance(struct 
  
        err = check_path(path);
        if (err)
-               return err;
+               return libbpf_err(err);
  
        if (prog == NULL) {
                pr_warn("invalid program pointer\n");
-               return -EINVAL;
+               return libbpf_err(-EINVAL);
        }
  
        if (instance < 0 || instance >= prog->instances.nr) {
                pr_warn("invalid prog instance %d of prog %s (max %d)\n",
                        instance, prog->name, prog->instances.nr);
-               return -EINVAL;
+               return libbpf_err(-EINVAL);
        }
  
        err = unlink(path);
        if (err != 0)
-               return -errno;
+               return libbpf_err(-errno);
        pr_debug("unpinned program '%s'\n", path);
  
        return 0;
@@@ -8206,20 -8221,20 +8224,20 @@@ int bpf_program__pin(struct bpf_progra
  
        err = make_parent_dir(path);
        if (err)
-               return err;
+               return libbpf_err(err);
  
        err = check_path(path);
        if (err)
-               return err;
+               return libbpf_err(err);
  
        if (prog == NULL) {
                pr_warn("invalid program pointer\n");
-               return -EINVAL;
+               return libbpf_err(-EINVAL);
        }
  
        if (prog->instances.nr <= 0) {
                pr_warn("no instances of prog %s to pin\n", prog->name);
-               return -EINVAL;
+               return libbpf_err(-EINVAL);
        }
  
        if (prog->instances.nr == 1) {
@@@ -8263,7 -8278,7 +8281,7 @@@ err_unpin
  
        rmdir(path);
  
-       return err;
+       return libbpf_err(err);
  }
  
  int bpf_program__unpin(struct bpf_program *prog, const char *path)
  
        err = check_path(path);
        if (err)
-               return err;
+               return libbpf_err(err);
  
        if (prog == NULL) {
                pr_warn("invalid program pointer\n");
-               return -EINVAL;
+               return libbpf_err(-EINVAL);
        }
  
        if (prog->instances.nr <= 0) {
                pr_warn("no instances of prog %s to pin\n", prog->name);
-               return -EINVAL;
+               return libbpf_err(-EINVAL);
        }
  
        if (prog->instances.nr == 1) {
  
                len = snprintf(buf, PATH_MAX, "%s/%d", path, i);
                if (len < 0)
-                       return -EINVAL;
+                       return libbpf_err(-EINVAL);
                else if (len >= PATH_MAX)
-                       return -ENAMETOOLONG;
+                       return libbpf_err(-ENAMETOOLONG);
  
                err = bpf_program__unpin_instance(prog, buf, i);
                if (err)
  
        err = rmdir(path);
        if (err)
-               return -errno;
+               return libbpf_err(-errno);
  
        return 0;
  }
@@@ -8318,14 -8333,14 +8336,14 @@@ int bpf_map__pin(struct bpf_map *map, c
  
        if (map == NULL) {
                pr_warn("invalid map pointer\n");
-               return -EINVAL;
+               return libbpf_err(-EINVAL);
        }
  
        if (map->pin_path) {
                if (path && strcmp(path, map->pin_path)) {
                        pr_warn("map '%s' already has pin path '%s' different from '%s'\n",
                                bpf_map__name(map), map->pin_path, path);
-                       return -EINVAL;
+                       return libbpf_err(-EINVAL);
                } else if (map->pinned) {
                        pr_debug("map '%s' already pinned at '%s'; not re-pinning\n",
                                 bpf_map__name(map), map->pin_path);
                if (!path) {
                        pr_warn("missing a path to pin map '%s' at\n",
                                bpf_map__name(map));
-                       return -EINVAL;
+                       return libbpf_err(-EINVAL);
                } else if (map->pinned) {
                        pr_warn("map '%s' already pinned\n", bpf_map__name(map));
-                       return -EEXIST;
+                       return libbpf_err(-EEXIST);
                }
  
                map->pin_path = strdup(path);
  
        err = make_parent_dir(map->pin_path);
        if (err)
-               return err;
+               return libbpf_err(err);
  
        err = check_path(map->pin_path);
        if (err)
-               return err;
+               return libbpf_err(err);
  
        if (bpf_obj_pin(map->fd, map->pin_path)) {
                err = -errno;
  out_err:
        cp = libbpf_strerror_r(-err, errmsg, sizeof(errmsg));
        pr_warn("failed to pin map: %s\n", cp);
-       return err;
+       return libbpf_err(err);
  }
  
  int bpf_map__unpin(struct bpf_map *map, const char *path)
  
        if (map == NULL) {
                pr_warn("invalid map pointer\n");
-               return -EINVAL;
+               return libbpf_err(-EINVAL);
        }
  
        if (map->pin_path) {
                if (path && strcmp(path, map->pin_path)) {
                        pr_warn("map '%s' already has pin path '%s' different from '%s'\n",
                                bpf_map__name(map), map->pin_path, path);
-                       return -EINVAL;
+                       return libbpf_err(-EINVAL);
                }
                path = map->pin_path;
        } else if (!path) {
                pr_warn("no path to unpin map '%s' from\n",
                        bpf_map__name(map));
-               return -EINVAL;
+               return libbpf_err(-EINVAL);
        }
  
        err = check_path(path);
        if (err)
-               return err;
+               return libbpf_err(err);
  
        err = unlink(path);
        if (err != 0)
-               return -errno;
+               return libbpf_err(-errno);
  
        map->pinned = false;
        pr_debug("unpinned map '%s' from '%s'\n", bpf_map__name(map), path);
@@@ -8415,7 -8430,7 +8433,7 @@@ int bpf_map__set_pin_path(struct bpf_ma
        if (path) {
                new = strdup(path);
                if (!new)
-                       return -errno;
+                       return libbpf_err(-errno);
        }
  
        free(map->pin_path);
@@@ -8449,11 -8464,11 +8467,11 @@@ int bpf_object__pin_maps(struct bpf_obj
        int err;
  
        if (!obj)
-               return -ENOENT;
+               return libbpf_err(-ENOENT);
  
        if (!obj->loaded) {
                pr_warn("object not yet loaded; load it first\n");
-               return -ENOENT;
+               return libbpf_err(-ENOENT);
        }
  
        bpf_object__for_each_map(map, obj) {
@@@ -8493,7 -8508,7 +8511,7 @@@ err_unpin_maps
                bpf_map__unpin(map, NULL);
        }
  
-       return err;
+       return libbpf_err(err);
  }
  
  int bpf_object__unpin_maps(struct bpf_object *obj, const char *path)
        int err;
  
        if (!obj)
-               return -ENOENT;
+               return libbpf_err(-ENOENT);
  
        bpf_object__for_each_map(map, obj) {
                char *pin_path = NULL;
                        len = snprintf(buf, PATH_MAX, "%s/%s", path,
                                       bpf_map__name(map));
                        if (len < 0)
-                               return -EINVAL;
+                               return libbpf_err(-EINVAL);
                        else if (len >= PATH_MAX)
-                               return -ENAMETOOLONG;
+                               return libbpf_err(-ENAMETOOLONG);
                        sanitize_pin_path(buf);
                        pin_path = buf;
                } else if (!map->pin_path) {
  
                err = bpf_map__unpin(map, pin_path);
                if (err)
-                       return err;
+                       return libbpf_err(err);
        }
  
        return 0;
@@@ -8537,11 -8552,11 +8555,11 @@@ int bpf_object__pin_programs(struct bpf
        int err;
  
        if (!obj)
-               return -ENOENT;
+               return libbpf_err(-ENOENT);
  
        if (!obj->loaded) {
                pr_warn("object not yet loaded; load it first\n");
-               return -ENOENT;
+               return libbpf_err(-ENOENT);
        }
  
        bpf_object__for_each_program(prog, obj) {
@@@ -8580,7 -8595,7 +8598,7 @@@ err_unpin_programs
                bpf_program__unpin(prog, buf);
        }
  
-       return err;
+       return libbpf_err(err);
  }
  
  int bpf_object__unpin_programs(struct bpf_object *obj, const char *path)
        int err;
  
        if (!obj)
-               return -ENOENT;
+               return libbpf_err(-ENOENT);
  
        bpf_object__for_each_program(prog, obj) {
                char buf[PATH_MAX];
                len = snprintf(buf, PATH_MAX, "%s/%s", path,
                               prog->pin_name);
                if (len < 0)
-                       return -EINVAL;
+                       return libbpf_err(-EINVAL);
                else if (len >= PATH_MAX)
-                       return -ENAMETOOLONG;
+                       return libbpf_err(-ENAMETOOLONG);
  
                err = bpf_program__unpin(prog, buf);
                if (err)
-                       return err;
+                       return libbpf_err(err);
        }
  
        return 0;
@@@ -8616,12 -8631,12 +8634,12 @@@ int bpf_object__pin(struct bpf_object *
  
        err = bpf_object__pin_maps(obj, path);
        if (err)
-               return err;
+               return libbpf_err(err);
  
        err = bpf_object__pin_programs(obj, path);
        if (err) {
                bpf_object__unpin_maps(obj, path);
-               return err;
+               return libbpf_err(err);
        }
  
        return 0;
@@@ -8718,7 -8733,7 +8736,7 @@@ bpf_object__next(struct bpf_object *pre
  
  const char *bpf_object__name(const struct bpf_object *obj)
  {
-       return obj ? obj->name : ERR_PTR(-EINVAL);
+       return obj ? obj->name : libbpf_err_ptr(-EINVAL);
  }
  
  unsigned int bpf_object__kversion(const struct bpf_object *obj)
@@@ -8739,7 -8754,7 +8757,7 @@@ int bpf_object__btf_fd(const struct bpf
  int bpf_object__set_kversion(struct bpf_object *obj, __u32 kern_version)
  {
        if (obj->loaded)
-               return -EINVAL;
+               return libbpf_err(-EINVAL);
  
        obj->kern_version = kern_version;
  
@@@ -8759,7 -8774,7 +8777,7 @@@ int bpf_object__set_priv(struct bpf_obj
  
  void *bpf_object__priv(const struct bpf_object *obj)
  {
-       return obj ? obj->priv : ERR_PTR(-EINVAL);
+       return obj ? obj->priv : libbpf_err_ptr(-EINVAL);
  }
  
  int bpf_object__gen_loader(struct bpf_object *obj, struct gen_loader_opts *opts)
@@@ -8795,7 -8810,7 +8813,7 @@@ __bpf_program__iter(const struct bpf_pr
  
        if (p->obj != obj) {
                pr_warn("error: program handler doesn't match object\n");
-               return NULL;
+               return errno = EINVAL, NULL;
        }
  
        idx = (p - obj->programs) + (forward ? 1 : -1);
@@@ -8841,7 -8856,7 +8859,7 @@@ int bpf_program__set_priv(struct bpf_pr
  
  void *bpf_program__priv(const struct bpf_program *prog)
  {
-       return prog ? prog->priv : ERR_PTR(-EINVAL);
+       return prog ? prog->priv : libbpf_err_ptr(-EINVAL);
  }
  
  void bpf_program__set_ifindex(struct bpf_program *prog, __u32 ifindex)
@@@ -8868,7 -8883,7 +8886,7 @@@ const char *bpf_program__title(const st
                title = strdup(title);
                if (!title) {
                        pr_warn("failed to strdup program title\n");
-                       return ERR_PTR(-ENOMEM);
+                       return libbpf_err_ptr(-ENOMEM);
                }
        }
  
@@@ -8883,7 -8898,7 +8901,7 @@@ bool bpf_program__autoload(const struc
  int bpf_program__set_autoload(struct bpf_program *prog, bool autoload)
  {
        if (prog->obj->loaded)
-               return -EINVAL;
+               return libbpf_err(-EINVAL);
  
        prog->load = autoload;
        return 0;
@@@ -8905,17 -8920,17 +8923,17 @@@ int bpf_program__set_prep(struct bpf_pr
        int *instances_fds;
  
        if (nr_instances <= 0 || !prep)
-               return -EINVAL;
+               return libbpf_err(-EINVAL);
  
        if (prog->instances.nr > 0 || prog->instances.fds) {
                pr_warn("Can't set pre-processor after loading\n");
-               return -EINVAL;
+               return libbpf_err(-EINVAL);
        }
  
        instances_fds = malloc(sizeof(int) * nr_instances);
        if (!instances_fds) {
                pr_warn("alloc memory failed for fds\n");
-               return -ENOMEM;
+               return libbpf_err(-ENOMEM);
        }
  
        /* fill all fd with -1 */
@@@ -8932,19 -8947,19 +8950,19 @@@ int bpf_program__nth_fd(const struct bp
        int fd;
  
        if (!prog)
-               return -EINVAL;
+               return libbpf_err(-EINVAL);
  
        if (n >= prog->instances.nr || n < 0) {
                pr_warn("Can't get the %dth fd from program %s: only %d instances\n",
                        n, prog->name, prog->instances.nr);
-               return -EINVAL;
+               return libbpf_err(-EINVAL);
        }
  
        fd = prog->instances.fds[n];
        if (fd < 0) {
                pr_warn("%dth instance of program '%s' is invalid\n",
                        n, prog->name);
-               return -ENOENT;
+               return libbpf_err(-ENOENT);
        }
  
        return fd;
@@@ -8970,7 -8985,7 +8988,7 @@@ static bool bpf_program__is_type(const 
  int bpf_program__set_##NAME(struct bpf_program *prog)         \
  {                                                             \
        if (!prog)                                              \
-               return -EINVAL;                                 \
+               return libbpf_err(-EINVAL);                     \
        bpf_program__set_type(prog, TYPE);                      \
        return 0;                                               \
  }                                                             \
@@@ -9060,7 -9075,10 +9078,10 @@@ static struct bpf_link *attach_iter(con
  
  static const struct bpf_sec_def section_defs[] = {
        BPF_PROG_SEC("socket",                  BPF_PROG_TYPE_SOCKET_FILTER),
-       BPF_PROG_SEC("sk_reuseport",            BPF_PROG_TYPE_SK_REUSEPORT),
+       BPF_EAPROG_SEC("sk_reuseport/migrate",  BPF_PROG_TYPE_SK_REUSEPORT,
+                                               BPF_SK_REUSEPORT_SELECT_OR_MIGRATE),
+       BPF_EAPROG_SEC("sk_reuseport",          BPF_PROG_TYPE_SK_REUSEPORT,
+                                               BPF_SK_REUSEPORT_SELECT),
        SEC_DEF("kprobe/", KPROBE,
                .attach_fn = attach_kprobe),
        BPF_PROG_SEC("uprobe/",                 BPF_PROG_TYPE_KPROBE),
@@@ -9257,7 -9275,7 +9278,7 @@@ int libbpf_prog_type_by_name(const cha
        char *type_names;
  
        if (!name)
-               return -EINVAL;
+               return libbpf_err(-EINVAL);
  
        sec_def = find_sec_def(name);
        if (sec_def) {
                free(type_names);
        }
  
-       return -ESRCH;
+       return libbpf_err(-ESRCH);
  }
  
  static struct bpf_map *find_struct_ops_map_by_offset(struct bpf_object *obj,
@@@ -9471,9 -9489,10 +9492,10 @@@ int libbpf_find_vmlinux_btf_id(const ch
        int err;
  
        btf = libbpf_find_kernel_btf();
-       if (IS_ERR(btf)) {
+       err = libbpf_get_error(btf);
+       if (err) {
                pr_warn("vmlinux BTF is not found\n");
-               return -EINVAL;
+               return libbpf_err(err);
        }
  
        err = find_attach_btf_id(btf, name, attach_type);
                pr_warn("%s is not found in vmlinux BTF\n", name);
  
        btf__free(btf);
-       return err;
+       return libbpf_err(err);
  }
  
  static int libbpf_find_prog_btf_id(const char *name, __u32 attach_prog_fd)
        int err = -EINVAL;
  
        info_linear = bpf_program__get_prog_info_linear(attach_prog_fd, 0);
-       if (IS_ERR_OR_NULL(info_linear)) {
+       err = libbpf_get_error(info_linear);
+       if (err) {
                pr_warn("failed get_prog_info_linear for FD %d\n",
                        attach_prog_fd);
-               return -EINVAL;
+               return err;
        }
        info = &info_linear->info;
        if (!info->btf_id) {
@@@ -9616,13 -9636,13 +9639,13 @@@ int libbpf_attach_type_by_name(const ch
        int i;
  
        if (!name)
-               return -EINVAL;
+               return libbpf_err(-EINVAL);
  
        for (i = 0; i < ARRAY_SIZE(section_defs); i++) {
                if (strncmp(name, section_defs[i].sec, section_defs[i].len))
                        continue;
                if (!section_defs[i].is_attachable)
-                       return -EINVAL;
+                       return libbpf_err(-EINVAL);
                *attach_type = section_defs[i].expected_attach_type;
                return 0;
        }
                free(type_names);
        }
  
-       return -EINVAL;
+       return libbpf_err(-EINVAL);
  }
  
  int bpf_map__fd(const struct bpf_map *map)
  {
-       return map ? map->fd : -EINVAL;
+       return map ? map->fd : libbpf_err(-EINVAL);
  }
  
  const struct bpf_map_def *bpf_map__def(const struct bpf_map *map)
  {
-       return map ? &map->def : ERR_PTR(-EINVAL);
+       return map ? &map->def : libbpf_err_ptr(-EINVAL);
  }
  
  const char *bpf_map__name(const struct bpf_map *map)
@@@ -9659,7 -9679,7 +9682,7 @@@ enum bpf_map_type bpf_map__type(const s
  int bpf_map__set_type(struct bpf_map *map, enum bpf_map_type type)
  {
        if (map->fd >= 0)
-               return -EBUSY;
+               return libbpf_err(-EBUSY);
        map->def.type = type;
        return 0;
  }
@@@ -9672,7 -9692,7 +9695,7 @@@ __u32 bpf_map__map_flags(const struct b
  int bpf_map__set_map_flags(struct bpf_map *map, __u32 flags)
  {
        if (map->fd >= 0)
-               return -EBUSY;
+               return libbpf_err(-EBUSY);
        map->def.map_flags = flags;
        return 0;
  }
@@@ -9685,7 -9705,7 +9708,7 @@@ __u32 bpf_map__numa_node(const struct b
  int bpf_map__set_numa_node(struct bpf_map *map, __u32 numa_node)
  {
        if (map->fd >= 0)
-               return -EBUSY;
+               return libbpf_err(-EBUSY);
        map->numa_node = numa_node;
        return 0;
  }
@@@ -9698,7 -9718,7 +9721,7 @@@ __u32 bpf_map__key_size(const struct bp
  int bpf_map__set_key_size(struct bpf_map *map, __u32 size)
  {
        if (map->fd >= 0)
-               return -EBUSY;
+               return libbpf_err(-EBUSY);
        map->def.key_size = size;
        return 0;
  }
@@@ -9711,7 -9731,7 +9734,7 @@@ __u32 bpf_map__value_size(const struct 
  int bpf_map__set_value_size(struct bpf_map *map, __u32 size)
  {
        if (map->fd >= 0)
-               return -EBUSY;
+               return libbpf_err(-EBUSY);
        map->def.value_size = size;
        return 0;
  }
@@@ -9730,7 -9750,7 +9753,7 @@@ int bpf_map__set_priv(struct bpf_map *m
                     bpf_map_clear_priv_t clear_priv)
  {
        if (!map)
-               return -EINVAL;
+               return libbpf_err(-EINVAL);
  
        if (map->priv) {
                if (map->clear_priv)
  
  void *bpf_map__priv(const struct bpf_map *map)
  {
-       return map ? map->priv : ERR_PTR(-EINVAL);
+       return map ? map->priv : libbpf_err_ptr(-EINVAL);
  }
  
  int bpf_map__set_initial_value(struct bpf_map *map,
  {
        if (!map->mmaped || map->libbpf_type == LIBBPF_MAP_KCONFIG ||
            size != map->def.value_size || map->fd >= 0)
-               return -EINVAL;
+               return libbpf_err(-EINVAL);
  
        memcpy(map->mmaped, data, size);
        return 0;
@@@ -9784,7 -9804,7 +9807,7 @@@ __u32 bpf_map__ifindex(const struct bpf
  int bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex)
  {
        if (map->fd >= 0)
-               return -EBUSY;
+               return libbpf_err(-EBUSY);
        map->map_ifindex = ifindex;
        return 0;
  }
@@@ -9793,11 -9813,11 +9816,11 @@@ int bpf_map__set_inner_map_fd(struct bp
  {
        if (!bpf_map_type__is_map_in_map(map->def.type)) {
                pr_warn("error: unsupported map type\n");
-               return -EINVAL;
+               return libbpf_err(-EINVAL);
        }
        if (map->inner_map_fd != -1) {
                pr_warn("error: inner_map_fd already specified\n");
-               return -EINVAL;
+               return libbpf_err(-EINVAL);
        }
        zfree(&map->inner_map);
        map->inner_map_fd = fd;
@@@ -9811,7 -9831,7 +9834,7 @@@ __bpf_map__iter(const struct bpf_map *m
        struct bpf_map *s, *e;
  
        if (!obj || !obj->maps)
-               return NULL;
+               return errno = EINVAL, NULL;
  
        s = obj->maps;
        e = obj->maps + obj->nr_maps;
        if ((m < s) || (m >= e)) {
                pr_warn("error in %s: map handler doesn't belong to object\n",
                         __func__);
-               return NULL;
+               return errno = EINVAL, NULL;
        }
  
        idx = (m - obj->maps) + i;
@@@ -9858,7 -9878,7 +9881,7 @@@ bpf_object__find_map_by_name(const stru
                if (pos->name && !strcmp(pos->name, name))
                        return pos;
        }
-       return NULL;
+       return errno = ENOENT, NULL;
  }
  
  int
@@@ -9870,12 -9890,23 +9893,23 @@@ bpf_object__find_map_fd_by_name(const s
  struct bpf_map *
  bpf_object__find_map_by_offset(struct bpf_object *obj, size_t offset)
  {
-       return ERR_PTR(-ENOTSUP);
+       return libbpf_err_ptr(-ENOTSUP);
  }
  
  long libbpf_get_error(const void *ptr)
  {
-       return PTR_ERR_OR_ZERO(ptr);
+       if (!IS_ERR_OR_NULL(ptr))
+               return 0;
+       if (IS_ERR(ptr))
+               errno = -PTR_ERR(ptr);
+       /* If ptr == NULL, then errno should be already set by the failing
+        * API, because libbpf never returns NULL on success and it now always
+        * sets errno on error. So no extra errno handling for ptr == NULL
+        * case.
+        */
+       return -errno;
  }
  
  int bpf_prog_load(const char *file, enum bpf_prog_type type,
@@@ -9901,16 -9932,17 +9935,17 @@@ int bpf_prog_load_xattr(const struct bp
        int err;
  
        if (!attr)
-               return -EINVAL;
+               return libbpf_err(-EINVAL);
        if (!attr->file)
-               return -EINVAL;
+               return libbpf_err(-EINVAL);
  
        open_attr.file = attr->file;
        open_attr.prog_type = attr->prog_type;
  
        obj = bpf_object__open_xattr(&open_attr);
-       if (IS_ERR_OR_NULL(obj))
-               return -ENOENT;
+       err = libbpf_get_error(obj);
+       if (err)
+               return libbpf_err(-ENOENT);
  
        bpf_object__for_each_program(prog, obj) {
                enum bpf_attach_type attach_type = attr->expected_attach_type;
                         * didn't provide a fallback type, too bad...
                         */
                        bpf_object__close(obj);
-                       return -EINVAL;
+                       return libbpf_err(-EINVAL);
                }
  
                prog->prog_ifindex = attr->ifindex;
        if (!first_prog) {
                pr_warn("object file doesn't contain bpf program\n");
                bpf_object__close(obj);
-               return -ENOENT;
+               return libbpf_err(-ENOENT);
        }
  
        err = bpf_object__load(obj);
        if (err) {
                bpf_object__close(obj);
-               return err;
+               return libbpf_err(err);
        }
  
        *pobj = obj;
@@@ -9973,7 -10005,10 +10008,10 @@@ struct bpf_link 
  /* Replace link's underlying BPF program with the new one */
  int bpf_link__update_program(struct bpf_link *link, struct bpf_program *prog)
  {
-       return bpf_link_update(bpf_link__fd(link), bpf_program__fd(prog), NULL);
+       int ret;
+       
+       ret = bpf_link_update(bpf_link__fd(link), bpf_program__fd(prog), NULL);
+       return libbpf_err_errno(ret);
  }
  
  /* Release "ownership" of underlying BPF resource (typically, BPF program
@@@ -10006,7 -10041,7 +10044,7 @@@ int bpf_link__destroy(struct bpf_link *
                free(link->pin_path);
        free(link);
  
-       return err;
+       return libbpf_err(err);
  }
  
  int bpf_link__fd(const struct bpf_link *link)
@@@ -10021,7 -10056,7 +10059,7 @@@ const char *bpf_link__pin_path(const st
  
  static int bpf_link__detach_fd(struct bpf_link *link)
  {
-       return close(link->fd);
+       return libbpf_err_errno(close(link->fd));
  }
  
  struct bpf_link *bpf_link__open(const char *path)
        if (fd < 0) {
                fd = -errno;
                pr_warn("failed to open link at %s: %d\n", path, fd);
-               return ERR_PTR(fd);
+               return libbpf_err_ptr(fd);
        }
  
        link = calloc(1, sizeof(*link));
        if (!link) {
                close(fd);
-               return ERR_PTR(-ENOMEM);
+               return libbpf_err_ptr(-ENOMEM);
        }
        link->detach = &bpf_link__detach_fd;
        link->fd = fd;
        link->pin_path = strdup(path);
        if (!link->pin_path) {
                bpf_link__destroy(link);
-               return ERR_PTR(-ENOMEM);
+               return libbpf_err_ptr(-ENOMEM);
        }
  
        return link;
@@@ -10063,22 -10098,22 +10101,22 @@@ int bpf_link__pin(struct bpf_link *link
        int err;
  
        if (link->pin_path)
-               return -EBUSY;
+               return libbpf_err(-EBUSY);
        err = make_parent_dir(path);
        if (err)
-               return err;
+               return libbpf_err(err);
        err = check_path(path);
        if (err)
-               return err;
+               return libbpf_err(err);
  
        link->pin_path = strdup(path);
        if (!link->pin_path)
-               return -ENOMEM;
+               return libbpf_err(-ENOMEM);
  
        if (bpf_obj_pin(link->fd, link->pin_path)) {
                err = -errno;
                zfree(&link->pin_path);
-               return err;
+               return libbpf_err(err);
        }
  
        pr_debug("link fd=%d: pinned at %s\n", link->fd, link->pin_path);
@@@ -10090,11 -10125,11 +10128,11 @@@ int bpf_link__unpin(struct bpf_link *li
        int err;
  
        if (!link->pin_path)
-               return -EINVAL;
+               return libbpf_err(-EINVAL);
  
        err = unlink(link->pin_path);
        if (err != 0)
-               return -errno;
+               return libbpf_err_errno(err);
  
        pr_debug("link fd=%d: unpinned from %s\n", link->fd, link->pin_path);
        zfree(&link->pin_path);
@@@ -10110,11 -10145,10 +10148,10 @@@ static int bpf_link__detach_perf_event(
                err = -errno;
  
        close(link->fd);
-       return err;
+       return libbpf_err(err);
  }
  
- struct bpf_link *bpf_program__attach_perf_event(struct bpf_program *prog,
-                                               int pfd)
+ struct bpf_link *bpf_program__attach_perf_event(struct bpf_program *prog, int pfd)
  {
        char errmsg[STRERR_BUFSIZE];
        struct bpf_link *link;
        if (pfd < 0) {
                pr_warn("prog '%s': invalid perf event FD %d\n",
                        prog->name, pfd);
-               return ERR_PTR(-EINVAL);
+               return libbpf_err_ptr(-EINVAL);
        }
        prog_fd = bpf_program__fd(prog);
        if (prog_fd < 0) {
                pr_warn("prog '%s': can't attach BPF program w/o FD (did you load it?)\n",
                        prog->name);
-               return ERR_PTR(-EINVAL);
+               return libbpf_err_ptr(-EINVAL);
        }
  
        link = calloc(1, sizeof(*link));
        if (!link)
-               return ERR_PTR(-ENOMEM);
+               return libbpf_err_ptr(-ENOMEM);
        link->detach = &bpf_link__detach_perf_event;
        link->fd = pfd;
  
                if (err == -EPROTO)
                        pr_warn("prog '%s': try add PERF_SAMPLE_CALLCHAIN to or remove exclude_callchain_[kernel|user] from pfd %d\n",
                                prog->name, pfd);
-               return ERR_PTR(err);
+               return libbpf_err_ptr(err);
        }
        if (ioctl(pfd, PERF_EVENT_IOC_ENABLE, 0) < 0) {
                err = -errno;
                free(link);
                pr_warn("prog '%s': failed to enable pfd %d: %s\n",
                        prog->name, pfd, libbpf_strerror_r(err, errmsg, sizeof(errmsg)));
-               return ERR_PTR(err);
+               return libbpf_err_ptr(err);
        }
        return link;
  }
@@@ -10277,16 -10311,16 +10314,16 @@@ struct bpf_link *bpf_program__attach_kp
                pr_warn("prog '%s': failed to create %s '%s' perf event: %s\n",
                        prog->name, retprobe ? "kretprobe" : "kprobe", func_name,
                        libbpf_strerror_r(pfd, errmsg, sizeof(errmsg)));
-               return ERR_PTR(pfd);
+               return libbpf_err_ptr(pfd);
        }
        link = bpf_program__attach_perf_event(prog, pfd);
-       if (IS_ERR(link)) {
+       err = libbpf_get_error(link);
+       if (err) {
                close(pfd);
-               err = PTR_ERR(link);
                pr_warn("prog '%s': failed to attach to %s '%s': %s\n",
                        prog->name, retprobe ? "kretprobe" : "kprobe", func_name,
                        libbpf_strerror_r(err, errmsg, sizeof(errmsg)));
-               return link;
+               return libbpf_err_ptr(err);
        }
        return link;
  }
@@@ -10319,17 -10353,17 +10356,17 @@@ struct bpf_link *bpf_program__attach_up
                        prog->name, retprobe ? "uretprobe" : "uprobe",
                        binary_path, func_offset,
                        libbpf_strerror_r(pfd, errmsg, sizeof(errmsg)));
-               return ERR_PTR(pfd);
+               return libbpf_err_ptr(pfd);
        }
        link = bpf_program__attach_perf_event(prog, pfd);
-       if (IS_ERR(link)) {
+       err = libbpf_get_error(link);
+       if (err) {
                close(pfd);
-               err = PTR_ERR(link);
                pr_warn("prog '%s': failed to attach to %s '%s:0x%zx': %s\n",
                        prog->name, retprobe ? "uretprobe" : "uprobe",
                        binary_path, func_offset,
                        libbpf_strerror_r(err, errmsg, sizeof(errmsg)));
-               return link;
+               return libbpf_err_ptr(err);
        }
        return link;
  }
@@@ -10397,16 -10431,16 +10434,16 @@@ struct bpf_link *bpf_program__attach_tr
                pr_warn("prog '%s': failed to create tracepoint '%s/%s' perf event: %s\n",
                        prog->name, tp_category, tp_name,
                        libbpf_strerror_r(pfd, errmsg, sizeof(errmsg)));
-               return ERR_PTR(pfd);
+               return libbpf_err_ptr(pfd);
        }
        link = bpf_program__attach_perf_event(prog, pfd);
-       if (IS_ERR(link)) {
+       err = libbpf_get_error(link);
+       if (err) {
                close(pfd);
-               err = PTR_ERR(link);
                pr_warn("prog '%s': failed to attach to tracepoint '%s/%s': %s\n",
                        prog->name, tp_category, tp_name,
                        libbpf_strerror_r(err, errmsg, sizeof(errmsg)));
-               return link;
+               return libbpf_err_ptr(err);
        }
        return link;
  }
@@@ -10419,20 -10453,19 +10456,19 @@@ static struct bpf_link *attach_tp(cons
  
        sec_name = strdup(prog->sec_name);
        if (!sec_name)
-               return ERR_PTR(-ENOMEM);
+               return libbpf_err_ptr(-ENOMEM);
  
        /* extract "tp/<category>/<name>" */
        tp_cat = sec_name + sec->len;
        tp_name = strchr(tp_cat, '/');
        if (!tp_name) {
-               link = ERR_PTR(-EINVAL);
-               goto out;
+               free(sec_name);
+               return libbpf_err_ptr(-EINVAL);
        }
        *tp_name = '\0';
        tp_name++;
  
        link = bpf_program__attach_tracepoint(prog, tp_cat, tp_name);
- out:
        free(sec_name);
        return link;
  }
@@@ -10447,12 -10480,12 +10483,12 @@@ struct bpf_link *bpf_program__attach_ra
        prog_fd = bpf_program__fd(prog);
        if (prog_fd < 0) {
                pr_warn("prog '%s': can't attach before loaded\n", prog->name);
-               return ERR_PTR(-EINVAL);
+               return libbpf_err_ptr(-EINVAL);
        }
  
        link = calloc(1, sizeof(*link));
        if (!link)
-               return ERR_PTR(-ENOMEM);
+               return libbpf_err_ptr(-ENOMEM);
        link->detach = &bpf_link__detach_fd;
  
        pfd = bpf_raw_tracepoint_open(tp_name, prog_fd);
                free(link);
                pr_warn("prog '%s': failed to attach to raw tracepoint '%s': %s\n",
                        prog->name, tp_name, libbpf_strerror_r(pfd, errmsg, sizeof(errmsg)));
-               return ERR_PTR(pfd);
+               return libbpf_err_ptr(pfd);
        }
        link->fd = pfd;
        return link;
@@@ -10485,12 -10518,12 +10521,12 @@@ static struct bpf_link *bpf_program__at
        prog_fd = bpf_program__fd(prog);
        if (prog_fd < 0) {
                pr_warn("prog '%s': can't attach before loaded\n", prog->name);
-               return ERR_PTR(-EINVAL);
+               return libbpf_err_ptr(-EINVAL);
        }
  
        link = calloc(1, sizeof(*link));
        if (!link)
-               return ERR_PTR(-ENOMEM);
+               return libbpf_err_ptr(-ENOMEM);
        link->detach = &bpf_link__detach_fd;
  
        pfd = bpf_raw_tracepoint_open(NULL, prog_fd);
                free(link);
                pr_warn("prog '%s': failed to attach: %s\n",
                        prog->name, libbpf_strerror_r(pfd, errmsg, sizeof(errmsg)));
-               return ERR_PTR(pfd);
+               return libbpf_err_ptr(pfd);
        }
        link->fd = pfd;
        return (struct bpf_link *)link;
@@@ -10527,12 -10560,6 +10563,6 @@@ static struct bpf_link *attach_lsm(cons
        return bpf_program__attach_lsm(prog);
  }
  
- static struct bpf_link *attach_iter(const struct bpf_sec_def *sec,
-                                   struct bpf_program *prog)
- {
-       return bpf_program__attach_iter(prog, NULL);
- }
  static struct bpf_link *
  bpf_program__attach_fd(struct bpf_program *prog, int target_fd, int btf_id,
                       const char *target_name)
        prog_fd = bpf_program__fd(prog);
        if (prog_fd < 0) {
                pr_warn("prog '%s': can't attach before loaded\n", prog->name);
-               return ERR_PTR(-EINVAL);
+               return libbpf_err_ptr(-EINVAL);
        }
  
        link = calloc(1, sizeof(*link));
        if (!link)
-               return ERR_PTR(-ENOMEM);
+               return libbpf_err_ptr(-ENOMEM);
        link->detach = &bpf_link__detach_fd;
  
        attach_type = bpf_program__get_expected_attach_type(prog);
                pr_warn("prog '%s': failed to attach to %s: %s\n",
                        prog->name, target_name,
                        libbpf_strerror_r(link_fd, errmsg, sizeof(errmsg)));
-               return ERR_PTR(link_fd);
+               return libbpf_err_ptr(link_fd);
        }
        link->fd = link_fd;
        return link;
@@@ -10596,19 -10623,19 +10626,19 @@@ struct bpf_link *bpf_program__attach_fr
        if (!!target_fd != !!attach_func_name) {
                pr_warn("prog '%s': supply none or both of target_fd and attach_func_name\n",
                        prog->name);
-               return ERR_PTR(-EINVAL);
+               return libbpf_err_ptr(-EINVAL);
        }
  
        if (prog->type != BPF_PROG_TYPE_EXT) {
                pr_warn("prog '%s': only BPF_PROG_TYPE_EXT can attach as freplace",
                        prog->name);
-               return ERR_PTR(-EINVAL);
+               return libbpf_err_ptr(-EINVAL);
        }
  
        if (target_fd) {
                btf_id = libbpf_find_prog_btf_id(attach_func_name, target_fd);
                if (btf_id < 0)
-                       return ERR_PTR(btf_id);
+                       return libbpf_err_ptr(btf_id);
  
                return bpf_program__attach_fd(prog, target_fd, btf_id, "freplace");
        } else {
@@@ -10630,7 -10657,7 +10660,7 @@@ bpf_program__attach_iter(struct bpf_pro
        __u32 target_fd = 0;
  
        if (!OPTS_VALID(opts, bpf_iter_attach_opts))
-               return ERR_PTR(-EINVAL);
+               return libbpf_err_ptr(-EINVAL);
  
        link_create_opts.iter_info = OPTS_GET(opts, link_info, (void *)0);
        link_create_opts.iter_info_len = OPTS_GET(opts, link_info_len, 0);
        prog_fd = bpf_program__fd(prog);
        if (prog_fd < 0) {
                pr_warn("prog '%s': can't attach before loaded\n", prog->name);
-               return ERR_PTR(-EINVAL);
+               return libbpf_err_ptr(-EINVAL);
        }
  
        link = calloc(1, sizeof(*link));
        if (!link)
-               return ERR_PTR(-ENOMEM);
+               return libbpf_err_ptr(-ENOMEM);
        link->detach = &bpf_link__detach_fd;
  
        link_fd = bpf_link_create(prog_fd, target_fd, BPF_TRACE_ITER,
                free(link);
                pr_warn("prog '%s': failed to attach to iterator: %s\n",
                        prog->name, libbpf_strerror_r(link_fd, errmsg, sizeof(errmsg)));
-               return ERR_PTR(link_fd);
+               return libbpf_err_ptr(link_fd);
        }
        link->fd = link_fd;
        return link;
  }
  
+ static struct bpf_link *attach_iter(const struct bpf_sec_def *sec,
+                                   struct bpf_program *prog)
+ {
+       return bpf_program__attach_iter(prog, NULL);
+ }
  struct bpf_link *bpf_program__attach(struct bpf_program *prog)
  {
        const struct bpf_sec_def *sec_def;
  
        sec_def = find_sec_def(prog->sec_name);
        if (!sec_def || !sec_def->attach_fn)
-               return ERR_PTR(-ESRCH);
+               return libbpf_err_ptr(-ESRCH);
  
        return sec_def->attach_fn(sec_def, prog);
  }
@@@ -10688,11 -10721,11 +10724,11 @@@ struct bpf_link *bpf_map__attach_struct
        int err;
  
        if (!bpf_map__is_struct_ops(map) || map->fd == -1)
-               return ERR_PTR(-EINVAL);
+               return libbpf_err_ptr(-EINVAL);
  
        link = calloc(1, sizeof(*link));
        if (!link)
-               return ERR_PTR(-EINVAL);
+               return libbpf_err_ptr(-EINVAL);
  
        st_ops = map->st_ops;
        for (i = 0; i < btf_vlen(st_ops->type); i++) {
        if (err) {
                err = -errno;
                free(link);
-               return ERR_PTR(err);
+               return libbpf_err_ptr(err);
        }
  
        link->detach = bpf_link__detach_struct_ops;
@@@ -10766,7 -10799,7 +10802,7 @@@ bpf_perf_event_read_simple(void *mmap_m
        }
  
        ring_buffer_write_tail(header, data_tail);
-       return ret;
+       return libbpf_err(ret);
  }
  
  struct perf_buffer;
@@@ -10919,7 -10952,7 +10955,7 @@@ struct perf_buffer *perf_buffer__new(in
        p.lost_cb = opts ? opts->lost_cb : NULL;
        p.ctx = opts ? opts->ctx : NULL;
  
-       return __perf_buffer__new(map_fd, page_cnt, &p);
+       return libbpf_ptr(__perf_buffer__new(map_fd, page_cnt, &p));
  }
  
  struct perf_buffer *
@@@ -10935,7 -10968,7 +10971,7 @@@ perf_buffer__new_raw(int map_fd, size_
        p.cpus = opts->cpus;
        p.map_keys = opts->map_keys;
  
-       return __perf_buffer__new(map_fd, page_cnt, &p);
+       return libbpf_ptr(__perf_buffer__new(map_fd, page_cnt, &p));
  }
  
  static struct perf_buffer *__perf_buffer__new(int map_fd, size_t page_cnt,
@@@ -11156,16 -11189,19 +11192,19 @@@ int perf_buffer__poll(struct perf_buffe
        int i, cnt, err;
  
        cnt = epoll_wait(pb->epoll_fd, pb->events, pb->cpu_cnt, timeout_ms);
+       if (cnt < 0)
+               return libbpf_err_errno(cnt);
        for (i = 0; i < cnt; i++) {
                struct perf_cpu_buf *cpu_buf = pb->events[i].data.ptr;
  
                err = perf_buffer__process_records(pb, cpu_buf);
                if (err) {
                        pr_warn("error while processing records: %d\n", err);
-                       return err;
+                       return libbpf_err(err);
                }
        }
-       return cnt < 0 ? -errno : cnt;
+       return cnt;
  }
  
  /* Return number of PERF_EVENT_ARRAY map slots set up by this perf_buffer
@@@ -11186,11 -11222,11 +11225,11 @@@ int perf_buffer__buffer_fd(const struc
        struct perf_cpu_buf *cpu_buf;
  
        if (buf_idx >= pb->cpu_cnt)
-               return -EINVAL;
+               return libbpf_err(-EINVAL);
  
        cpu_buf = pb->cpu_bufs[buf_idx];
        if (!cpu_buf)
-               return -ENOENT;
+               return libbpf_err(-ENOENT);
  
        return cpu_buf->fd;
  }
@@@ -11208,11 -11244,11 +11247,11 @@@ int perf_buffer__consume_buffer(struct 
        struct perf_cpu_buf *cpu_buf;
  
        if (buf_idx >= pb->cpu_cnt)
-               return -EINVAL;
+               return libbpf_err(-EINVAL);
  
        cpu_buf = pb->cpu_bufs[buf_idx];
        if (!cpu_buf)
-               return -ENOENT;
+               return libbpf_err(-ENOENT);
  
        return perf_buffer__process_records(pb, cpu_buf);
  }
@@@ -11230,7 -11266,7 +11269,7 @@@ int perf_buffer__consume(struct perf_bu
                err = perf_buffer__process_records(pb, cpu_buf);
                if (err) {
                        pr_warn("perf_buffer: failed to process records in buffer #%d: %d\n", i, err);
-                       return err;
+                       return libbpf_err(err);
                }
        }
        return 0;
@@@ -11342,13 -11378,13 +11381,13 @@@ bpf_program__get_prog_info_linear(int f
        void *ptr;
  
        if (arrays >> BPF_PROG_INFO_LAST_ARRAY)
-               return ERR_PTR(-EINVAL);
+               return libbpf_err_ptr(-EINVAL);
  
        /* step 1: get array dimensions */
        err = bpf_obj_get_info_by_fd(fd, &info, &info_len);
        if (err) {
                pr_debug("can't get prog info: %s", strerror(errno));
-               return ERR_PTR(-EFAULT);
+               return libbpf_err_ptr(-EFAULT);
        }
  
        /* step 2: calculate total size of all arrays */
        data_len = roundup(data_len, sizeof(__u64));
        info_linear = malloc(sizeof(struct bpf_prog_info_linear) + data_len);
        if (!info_linear)
-               return ERR_PTR(-ENOMEM);
+               return libbpf_err_ptr(-ENOMEM);
  
        /* step 4: fill data to info_linear->info */
        info_linear->arrays = arrays;
        if (err) {
                pr_debug("can't get prog info: %s", strerror(errno));
                free(info_linear);
-               return ERR_PTR(-EFAULT);
+               return libbpf_err_ptr(-EFAULT);
        }
  
        /* step 6: verify the data */
@@@ -11491,26 -11527,26 +11530,26 @@@ int bpf_program__set_attach_target(stru
        int btf_obj_fd = 0, btf_id = 0, err;
  
        if (!prog || attach_prog_fd < 0 || !attach_func_name)
-               return -EINVAL;
+               return libbpf_err(-EINVAL);
  
        if (prog->obj->loaded)
-               return -EINVAL;
+               return libbpf_err(-EINVAL);
  
        if (attach_prog_fd) {
                btf_id = libbpf_find_prog_btf_id(attach_func_name,
                                                 attach_prog_fd);
                if (btf_id < 0)
-                       return btf_id;
+                       return libbpf_err(btf_id);
        } else {
                /* load btf_vmlinux, if not yet */
                err = bpf_object__load_vmlinux_btf(prog->obj, true);
                if (err)
-                       return err;
+                       return libbpf_err(err);
                err = find_kernel_btf_id(prog->obj, attach_func_name,
                                         prog->expected_attach_type,
                                         &btf_obj_fd, &btf_id);
                if (err)
-                       return err;
+                       return libbpf_err(err);
        }
  
        prog->attach_btf_id = btf_id;
@@@ -11609,7 -11645,7 +11648,7 @@@ int libbpf_num_possible_cpus(void
  
        err = parse_cpu_mask_file(fcpu, &mask, &n);
        if (err)
-               return err;
+               return libbpf_err(err);
  
        tmp_cpus = 0;
        for (i = 0; i < n; i++) {
@@@ -11629,7 -11665,7 +11668,7 @@@ int bpf_object__open_skeleton(struct bp
                .object_name = s->name,
        );
        struct bpf_object *obj;
-       int i;
+       int i, err;
  
        /* Attempt to preserve opts->object_name, unless overriden by user
         * explicitly. Overwriting object name for skeletons is discouraged,
        }
  
        obj = bpf_object__open_mem(s->data, s->data_sz, &skel_opts);
-       if (IS_ERR(obj)) {
-               pr_warn("failed to initialize skeleton BPF object '%s': %ld\n",
-                       s->name, PTR_ERR(obj));
-               return PTR_ERR(obj);
+       err = libbpf_get_error(obj);
+       if (err) {
+               pr_warn("failed to initialize skeleton BPF object '%s': %d\n",
+                       s->name, err);
+               return libbpf_err(err);
        }
  
        *s->obj = obj;
                *map = bpf_object__find_map_by_name(obj, name);
                if (!*map) {
                        pr_warn("failed to find skeleton map '%s'\n", name);
-                       return -ESRCH;
+                       return libbpf_err(-ESRCH);
                }
  
                /* externs shouldn't be pre-setup from user code */
                *prog = bpf_object__find_program_by_name(obj, name);
                if (!*prog) {
                        pr_warn("failed to find skeleton program '%s'\n", name);
-                       return -ESRCH;
+                       return libbpf_err(-ESRCH);
                }
        }
  
@@@ -11689,7 -11726,7 +11729,7 @@@ int bpf_object__load_skeleton(struct bp
        err = bpf_object__load(*s->obj);
        if (err) {
                pr_warn("failed to load BPF skeleton '%s': %d\n", s->name, err);
-               return err;
+               return libbpf_err(err);
        }
  
        for (i = 0; i < s->map_cnt; i++) {
                        *mmaped = NULL;
                        pr_warn("failed to re-mmap() map '%s': %d\n",
                                 bpf_map__name(map), err);
-                       return err;
+                       return libbpf_err(err);
                }
        }
  
  
  int bpf_object__attach_skeleton(struct bpf_object_skeleton *s)
  {
-       int i;
+       int i, err;
  
        for (i = 0; i < s->prog_cnt; i++) {
                struct bpf_program *prog = *s->progs[i].prog;
                        continue;
  
                *link = sec_def->attach_fn(sec_def, prog);
-               if (IS_ERR(*link)) {
-                       pr_warn("failed to auto-attach program '%s': %ld\n",
-                               bpf_program__name(prog), PTR_ERR(*link));
-                       return PTR_ERR(*link);
+               err = libbpf_get_error(*link);
+               if (err) {
+                       pr_warn("failed to auto-attach program '%s': %d\n",
+                               bpf_program__name(prog), err);
+                       return libbpf_err(err);
                }
        }
  
@@@ -11,6 -11,9 +11,9 @@@
  
  #include <stdlib.h>
  #include <limits.h>
+ #include <errno.h>
+ #include <linux/err.h>
+ #include "libbpf_legacy.h"
  
  /* make sure libbpf doesn't use kernel-only integer typedefs */
  #pragma GCC poison u8 u16 u32 u64 s8 s16 s32 s64
  #ifndef R_BPF_64_64
  #define R_BPF_64_64 1
  #endif
+ #ifndef R_BPF_64_ABS64
+ #define R_BPF_64_ABS64 2
+ #endif
+ #ifndef R_BPF_64_ABS32
+ #define R_BPF_64_ABS32 3
+ #endif
  #ifndef R_BPF_64_32
  #define R_BPF_64_32 10
  #endif
  #define ELF_C_READ_MMAP ELF_C_READ
  #endif
  
 +/* Older libelf all end up in this expression, for both 32 and 64 bit */
 +#ifndef GELF_ST_VISIBILITY
 +#define GELF_ST_VISIBILITY(o) ((o) & 0x03)
 +#endif
 +
  #define BTF_INFO_ENC(kind, kind_flag, vlen) \
        ((!!(kind_flag) << 31) | ((kind) << 24) | ((vlen) & BTF_MAX_VLEN))
  #define BTF_TYPE_ENC(name, info, size_or_type) (name), (info), (size_or_type)
@@@ -435,4 -439,54 +444,54 @@@ int btf_type_visit_str_offs(struct btf_
  int btf_ext_visit_type_ids(struct btf_ext *btf_ext, type_id_visit_fn visit, void *ctx);
  int btf_ext_visit_str_offs(struct btf_ext *btf_ext, str_off_visit_fn visit, void *ctx);
  
+ extern enum libbpf_strict_mode libbpf_mode;
+ /* handle direct returned errors */
+ static inline int libbpf_err(int ret)
+ {
+       if (ret < 0)
+               errno = -ret;
+       return ret;
+ }
+ /* handle errno-based (e.g., syscall or libc) errors according to libbpf's
+  * strict mode settings
+  */
+ static inline int libbpf_err_errno(int ret)
+ {
+       if (libbpf_mode & LIBBPF_STRICT_DIRECT_ERRS)
+               /* errno is already assumed to be set on error */
+               return ret < 0 ? -errno : ret;
+       /* legacy: on error return -1 directly and don't touch errno */
+       return ret;
+ }
+ /* handle error for pointer-returning APIs, err is assumed to be < 0 always */
+ static inline void *libbpf_err_ptr(int err)
+ {
+       /* set errno on error, this doesn't break anything */
+       errno = -err;
+       if (libbpf_mode & LIBBPF_STRICT_CLEAN_PTRS)
+               return NULL;
+       /* legacy: encode err as ptr */
+       return ERR_PTR(err);
+ }
+ /* handle pointer-returning APIs' error handling */
+ static inline void *libbpf_ptr(void *ret)
+ {
+       /* set errno on error, this doesn't break anything */
+       if (IS_ERR(ret))
+               errno = -PTR_ERR(ret);
+       if (libbpf_mode & LIBBPF_STRICT_CLEAN_PTRS)
+               return IS_ERR(ret) ? NULL : ret;
+       /* legacy: pass-through original pointer */
+       return ret;
+ }
  #endif /* __LIBBPF_LIBBPF_INTERNAL_H */