Received: by 2002:a25:7ec1:0:0:0:0:0 with SMTP id z184csp928974ybc; Tue, 19 Nov 2019 11:33:59 -0800 (PST) X-Google-Smtp-Source: APXvYqy275fVNzmnZmHHzhxmtqP3p6OUXzV+rn9Vp5aOltkDGnKKirG3qLfXN1sP4dWtulH7yTJV X-Received: by 2002:a5d:6a4c:: with SMTP id t12mr4575515wrw.141.1574192039817; Tue, 19 Nov 2019 11:33:59 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1574192039; cv=none; d=google.com; s=arc-20160816; b=OP5ba+3eYEDlkh8D2/aCpyfT+6NzOl7vzk5ki1Bp0H1SXaaV0rrCIkgNTiMvRXkDNm R+R7mmTuKaZNZMfSSxGYQh2wVXt3DICap68tYhB2IQiRwK7zkILekjBhvfKzXu43fMoi fSKE8FZdY6VgraR9qGkEW4FkPh2XC1KF3ixx8ML11rr4DNXQOaPmNyzs27Insh2QEbCV GVrAkkGPXtdbv82xn8U4QDF7nF6z8/Xb3K83JqK/GH9yqsPn7ixvBKo+QFbRROT2m+9t YScCTgyBY1K9wwoNWkLoqE++EMvXOhz8zgGgUuw99hniZjsxSK+eQWUtxrV+hnnPZrFC OCCg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:cc:to:from:subject:references :mime-version:message-id:in-reply-to:date:dkim-signature; bh=paPq1QV4mwCwfbyX9rPU2ygE8/29H1pmhKP3AAocJPk=; b=Xjh8+fQNw+WlNfbDH2++Z0d0JbNnVDe5uHNLyyF2j8odH3kR1ZsKJdyloCGm0kL9pu rBIGIl0SEnb1G8UKzKTkMdj8h2oT/Cg9T/CKVZXpbDub1T24JamfRt04PUdNKtY5JhdZ 0bAY04bZEHiCbDvUZEYkm7OCUUN2XGj5fO5sWfHFGqScExdw7bVP8hJKAloyn10ift77 19D2tQq4KLmHd8deqnqq9hANm7WzaatYPfpU8wndzfY5dJ5HHk/pM2dvDdHmsDQodG6J qguwDukojZ/4wpf7CLfxr3/y/lxN7900vbk6X4RrxFx3AOT1k73EJ8KWJmjxbDwybW2o iJXg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=jcFKJmRc; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id e25si15269615edr.117.2019.11.19.11.33.34; Tue, 19 Nov 2019 11:33:59 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=jcFKJmRc; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727684AbfKSTbc (ORCPT + 99 others); Tue, 19 Nov 2019 14:31:32 -0500 Received: from mail-pf1-f201.google.com ([209.85.210.201]:41606 "EHLO mail-pf1-f201.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727368AbfKSTax (ORCPT ); Tue, 19 Nov 2019 14:30:53 -0500 Received: by mail-pf1-f201.google.com with SMTP id b17so13216006pfb.8 for ; Tue, 19 Nov 2019 11:30:51 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=paPq1QV4mwCwfbyX9rPU2ygE8/29H1pmhKP3AAocJPk=; b=jcFKJmRckPuxfkTZewDK1THPa2GajsqYtYyYWJUFvN+x2hxPQ0T0R0+4MHha838m8L 2YwAo3N/DZB745c5cEgwnhzJB7ThpRjc4HwV65wCKKJNchX7TwUbNNEyhaIgyonCzNVw A8WfzOE72FoPmz/rOw9kr6MmWyGjtdGWA2ZHhwyC4Mz5TG+Kl1C5vtruoY7ZL8P8fhih 9IUNU8aj4qN8ZVvIRpYklYFceRvBBvYbRgHmu75EMxH5z1nZfPnkThKORQJfFvzMXfa0 cuf/HNw38shj7eaNIPdtWNHbQ4y4PKaARk+EkZ3uxziLvUydE9DuZz/wsmL0/X3CLtw0 uiyg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=paPq1QV4mwCwfbyX9rPU2ygE8/29H1pmhKP3AAocJPk=; b=L0wPyjOJaQg1xaKahxWefibnxXLYXsgbCPBCA2uVDJFctcR+KpfOsVBEMGg74mEn4q 6GhuPnQWn97t4joKldceHCMXyrBTa3H6SwuOD67c0/jUVValcQn5Ua4SOzYB7GyaO9rB YNXFgN/K7JR6IeqMCa0XxbWdMReUmIQA4AS2QZ8/El5BNfV8HInNNxT9RThwABTwdqTd RctIFhM6+PjMmf3O5lLXDWPxzOnLh/Q4/L2/4R5BkdH57/HG4VRxbGmeTQTlK/NMe44w xwRxcc6MgSthXOjRLLzuExa/1MxUnXfApp6/lx+Dy/XIbyIw7zcnGVbazCAisK68ATg5 4wkQ== X-Gm-Message-State: APjAAAVMxhf87A5UDf3KjGDz0uYhdcs9hMQ2x/Z2XllgqBpCKOc/W2+Z XWubJYG4WOxIH+7rR9YRz56DhQKmyZ+N X-Received: by 2002:a63:545f:: with SMTP id e31mr3901108pgm.236.1574191850913; Tue, 19 Nov 2019 11:30:50 -0800 (PST) Date: Tue, 19 Nov 2019 11:30:30 -0800 In-Reply-To: <20191119193036.92831-1-brianvv@google.com> Message-Id: <20191119193036.92831-4-brianvv@google.com> Mime-Version: 1.0 References: <20191119193036.92831-1-brianvv@google.com> X-Mailer: git-send-email 2.24.0.432.g9d3f5f5b63-goog Subject: [PATCH v2 bpf-next 3/9] bpf: add generic support for update and delete batch ops From: Brian Vazquez To: Brian Vazquez , Alexei Starovoitov , Daniel Borkmann , "David S . Miller" Cc: Yonghong Song , Stanislav Fomichev , Petar Penkov , Willem de Bruijn , linux-kernel@vger.kernel.org, netdev@vger.kernel.org, bpf@vger.kernel.org, Brian Vazquez Content-Type: text/plain; charset="UTF-8" Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This commit adds generic support for update and delete batch ops that can be used for almost all the bpf maps. These commands share the same UAPI attr that lookup and lookup_and_delete batch ops use and the syscall commands are: BPF_MAP_UPDATE_BATCH BPF_MAP_DELETE_BATCH The main difference between update/delete and lookup/lookup_and_delete batch ops is that for update/delete keys/values must be specified for userspace and because of that, neither in_batch nor out_batch are used. Suggested-by: Stanislav Fomichev Signed-off-by: Brian Vazquez Signed-off-by: Yonghong Song --- include/linux/bpf.h | 10 ++++ include/uapi/linux/bpf.h | 2 + kernel/bpf/syscall.c | 126 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 137 insertions(+), 1 deletion(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 767a823dbac74..96a19e1fd2b5b 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -46,6 +46,10 @@ struct bpf_map_ops { int (*map_lookup_and_delete_batch)(struct bpf_map *map, const union bpf_attr *attr, union bpf_attr __user *uattr); + int (*map_update_batch)(struct bpf_map *map, const union bpf_attr *attr, + union bpf_attr __user *uattr); + int (*map_delete_batch)(struct bpf_map *map, const union bpf_attr *attr, + union bpf_attr __user *uattr); /* funcs callable from userspace and from eBPF programs */ void *(*map_lookup_elem)(struct bpf_map *map, void *key); @@ -808,6 +812,12 @@ int generic_map_lookup_batch(struct bpf_map *map, int generic_map_lookup_and_delete_batch(struct bpf_map *map, const union bpf_attr *attr, union bpf_attr __user *uattr); +int generic_map_update_batch(struct bpf_map *map, + const union bpf_attr *attr, + union bpf_attr __user *uattr); +int generic_map_delete_batch(struct bpf_map *map, + const union bpf_attr *attr, + union bpf_attr __user *uattr); extern int sysctl_unprivileged_bpf_disabled; diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index e60b7b7cda61a..0f6ff0c4d79dd 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -109,6 +109,8 @@ enum bpf_cmd { BPF_BTF_GET_NEXT_ID, BPF_MAP_LOOKUP_BATCH, BPF_MAP_LOOKUP_AND_DELETE_BATCH, + BPF_MAP_UPDATE_BATCH, + BPF_MAP_DELETE_BATCH, }; enum bpf_map_type { diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index d0d3d0e0eaca4..06e1bcf40fb8d 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -1127,6 +1127,120 @@ static int map_get_next_key(union bpf_attr *attr) return err; } +int generic_map_delete_batch(struct bpf_map *map, + const union bpf_attr *attr, + union bpf_attr __user *uattr) +{ + void __user *keys = u64_to_user_ptr(attr->batch.keys); + int ufd = attr->map_fd; + u32 cp, max_count; + struct fd f; + void *key; + int err; + + f = fdget(ufd); + if (attr->batch.elem_flags & ~BPF_F_LOCK) + return -EINVAL; + + if ((attr->batch.elem_flags & BPF_F_LOCK) && + !map_value_has_spin_lock(map)) { + err = -EINVAL; + goto err_put; + } + + max_count = attr->batch.count; + if (!max_count) + return 0; + + err = -ENOMEM; + for (cp = 0; cp < max_count; cp++) { + key = __bpf_copy_key(keys + cp * map->key_size, map->key_size); + if (IS_ERR(key)) { + err = PTR_ERR(key); + break; + } + + if (err) + break; + if (bpf_map_is_dev_bound(map)) { + err = bpf_map_offload_delete_elem(map, key); + break; + } + + preempt_disable(); + __this_cpu_inc(bpf_prog_active); + rcu_read_lock(); + err = map->ops->map_delete_elem(map, key); + rcu_read_unlock(); + __this_cpu_dec(bpf_prog_active); + preempt_enable(); + maybe_wait_bpf_programs(map); + if (err) + break; + } + if (copy_to_user(&uattr->batch.count, &cp, sizeof(cp))) + err = -EFAULT; +err_put: + return err; +} +int generic_map_update_batch(struct bpf_map *map, + const union bpf_attr *attr, + union bpf_attr __user *uattr) +{ + void __user *values = u64_to_user_ptr(attr->batch.values); + void __user *keys = u64_to_user_ptr(attr->batch.keys); + u32 value_size, cp, max_count; + int ufd = attr->map_fd; + void *key, *value; + struct fd f; + int err; + + f = fdget(ufd); + if (attr->batch.elem_flags & ~BPF_F_LOCK) + return -EINVAL; + + if ((attr->batch.elem_flags & BPF_F_LOCK) && + !map_value_has_spin_lock(map)) { + err = -EINVAL; + goto err_put; + } + + value_size = bpf_map_value_size(map); + + max_count = attr->batch.count; + if (!max_count) + return 0; + + err = -ENOMEM; + value = kmalloc(value_size, GFP_USER | __GFP_NOWARN); + if (!value) + goto err_put; + + for (cp = 0; cp < max_count; cp++) { + key = __bpf_copy_key(keys + cp * map->key_size, map->key_size); + if (IS_ERR(key)) { + err = PTR_ERR(key); + break; + } + err = -EFAULT; + if (copy_from_user(value, values + cp * value_size, value_size)) + break; + + err = bpf_map_update_value(map, f, key, value, + attr->batch.elem_flags); + + if (err) + break; + } + + if (copy_to_user(&uattr->batch.count, &cp, sizeof(cp))) + err = -EFAULT; + + kfree(value); +err_put: + return err; +} + static int __generic_map_lookup_batch(struct bpf_map *map, const union bpf_attr *attr, union bpf_attr __user *uattr, @@ -3117,8 +3231,12 @@ static int bpf_map_do_batch(const union bpf_attr *attr, if (cmd == BPF_MAP_LOOKUP_BATCH) BPF_DO_BATCH(map->ops->map_lookup_batch); - else + else if (cmd == BPF_MAP_LOOKUP_AND_DELETE_BATCH) BPF_DO_BATCH(map->ops->map_lookup_and_delete_batch); + else if (cmd == BPF_MAP_UPDATE_BATCH) + BPF_DO_BATCH(map->ops->map_update_batch); + else + BPF_DO_BATCH(map->ops->map_delete_batch); err_put: fdput(f); @@ -3229,6 +3347,12 @@ SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, siz err = bpf_map_do_batch(&attr, uattr, BPF_MAP_LOOKUP_AND_DELETE_BATCH); break; + case BPF_MAP_UPDATE_BATCH: + err = bpf_map_do_batch(&attr, uattr, BPF_MAP_UPDATE_BATCH); + break; + case BPF_MAP_DELETE_BATCH: + err = bpf_map_do_batch(&attr, uattr, BPF_MAP_DELETE_BATCH); + break; default: err = -EINVAL; break; -- 2.24.0.432.g9d3f5f5b63-goog