From patchwork Sat Jun 28 00:06:01 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexei Starovoitov X-Patchwork-Id: 365244 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 88D2B1400B5 for ; Sat, 28 Jun 2014 10:09:40 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754775AbaF1AJC (ORCPT ); Fri, 27 Jun 2014 20:09:02 -0400 Received: from mail-pa0-f51.google.com ([209.85.220.51]:36618 "EHLO mail-pa0-f51.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754653AbaF1AGn (ORCPT ); Fri, 27 Jun 2014 20:06:43 -0400 Received: by mail-pa0-f51.google.com with SMTP id hz1so5289688pad.38 for ; Fri, 27 Jun 2014 17:06:42 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=rGyK9t31JwKdSJUuw4A1NS8IUeDL01QiQPw5pHLVk+g=; b=mus3+csfvZvf9WnUVgpY1kcl0Af9j/gSPRv9JDH+HHZbUdNtIdDy+i1g4yxtBOdeOh dVLDmcpPaf08xWO4e0X1Q15hrNEQLCZWA7g2UEzjYGuJKOg/dEz51z8qL45gbQiRWj+Y n+WlgSbYinm+/tVzMZIfgoTJAOOGSs6533nMzI7HrLoM2Nu0KWtQh7zqeqEygDJ1ip/r rkZhETDbFanbYUnudPl4vK6FHLQsykugwAAAI12i1S6WagFHwIW/B0yqsV2IaWyXHKu3 FoHrIrX5FJixdjsOJB80bUWj2hmR5/VSWWDglL6G+wV/hTWDigSWGv6+A4U7Q+GQOjL4 nzeg== X-Gm-Message-State: ALoCoQlN/sLn8nTxpDGqPsHBMEZptOd4x5tbJIUGtsJmsoH/xLec/p9kJX5TPqud2hxZUI9BlbM7 X-Received: by 10.66.66.135 with SMTP id f7mr35018456pat.22.1403914002706; Fri, 27 Jun 2014 17:06:42 -0700 (PDT) Received: from pg-vmw-gw1.plumgrid.com ([67.21.3.149]) by mx.google.com with ESMTPSA id fk4sm58421568pab.23.2014.06.27.17.06.40 for (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Fri, 27 Jun 2014 17:06:41 -0700 (PDT) From: Alexei Starovoitov To: "David S. Miller" Cc: Ingo Molnar , Linus Torvalds , Steven Rostedt , Daniel Borkmann , Chema Gonzalez , Eric Dumazet , Peter Zijlstra , Arnaldo Carvalho de Melo , Jiri Olsa , Thomas Gleixner , "H. Peter Anvin" , Andrew Morton , Kees Cook , linux-api@vger.kernel.org, netdev@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH RFC net-next 09/14] bpf: allow eBPF programs to use maps Date: Fri, 27 Jun 2014 17:06:01 -0700 Message-Id: <1403913966-4927-10-git-send-email-ast@plumgrid.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1403913966-4927-1-git-send-email-ast@plumgrid.com> References: <1403913966-4927-1-git-send-email-ast@plumgrid.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org expose bpf_map_lookup_elem(), bpf_map_update_elem(), bpf_map_delete_elem() map accessors to eBPF programs Signed-off-by: Alexei Starovoitov --- include/linux/bpf.h | 5 +++ include/uapi/linux/bpf.h | 3 ++ kernel/bpf/syscall.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 67fd49eac904..bc505093683a 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -127,4 +127,9 @@ struct sk_filter *bpf_prog_get(u32 prog_id); /* verify correctness of eBPF program */ int bpf_check(struct sk_filter *fp); +/* in-kernel helper functions called from eBPF programs */ +u64 bpf_map_lookup_elem(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5); +u64 bpf_map_update_elem(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5); +u64 bpf_map_delete_elem(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5); + #endif /* _LINUX_BPF_H */ diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 597a35cc101d..03c65eedd3d5 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -389,6 +389,9 @@ enum bpf_prog_type { */ enum bpf_func_id { BPF_FUNC_unspec, + BPF_FUNC_map_lookup_elem, /* void *map_lookup_elem(map_id, void *key) */ + BPF_FUNC_map_update_elem, /* int map_update_elem(map_id, void *key, void *value) */ + BPF_FUNC_map_delete_elem, /* int map_delete_elem(map_id, void *key) */ __BPF_FUNC_MAX_ID, }; diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 48d8f43da151..266136f0d333 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -691,3 +691,88 @@ SYSCALL_DEFINE5(bpf, int, cmd, unsigned long, arg2, unsigned long, arg3, return -EINVAL; } } + +/* called from eBPF program under rcu lock + * + * if kernel subsystem is allowing eBPF programs to call this function, + * inside its own verifier_ops->get_func_proto() callback it should return + * (struct bpf_func_proto) { + * .ret_type = PTR_TO_MAP_CONDITIONAL, + * .arg1_type = CONST_ARG_MAP_ID, + * .arg2_type = PTR_TO_STACK_IMM_MAP_KEY, + * } + * so that eBPF verifier properly checks the arguments + */ +u64 bpf_map_lookup_elem(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5) +{ + struct bpf_map *map; + int map_id = r1; + void *key = (void *) (unsigned long) r2; + void *value; + + WARN_ON_ONCE(!rcu_read_lock_held()); + + map = idr_find(&bpf_map_id_idr, map_id); + /* eBPF verifier guarantees that map_id is valid for the life of + * the program + */ + BUG_ON(!map); + + value = map->ops->map_lookup_elem(map, key); + + return (unsigned long) value; +} + +/* called from eBPF program under rcu lock + * + * if kernel subsystem is allowing eBPF programs to call this function, + * inside its own verifier_ops->get_func_proto() callback it should return + * (struct bpf_func_proto) { + * .ret_type = RET_INTEGER, + * .arg1_type = CONST_ARG_MAP_ID, + * .arg2_type = PTR_TO_STACK_IMM_MAP_KEY, + * .arg3_type = PTR_TO_STACK_IMM_MAP_VALUE, + * } + * so that eBPF verifier properly checks the arguments + */ +u64 bpf_map_update_elem(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5) +{ + struct bpf_map *map; + int map_id = r1; + void *key = (void *) (unsigned long) r2; + void *value = (void *) (unsigned long) r3; + + WARN_ON_ONCE(!rcu_read_lock_held()); + + map = idr_find(&bpf_map_id_idr, map_id); + /* eBPF verifier guarantees that map_id is valid */ + BUG_ON(!map); + + return map->ops->map_update_elem(map, key, value); +} + +/* called from eBPF program under rcu lock + * + * if kernel subsystem is allowing eBPF programs to call this function, + * inside its own verifier_ops->get_func_proto() callback it should return + * (struct bpf_func_proto) { + * .ret_type = RET_INTEGER, + * .arg1_type = CONST_ARG_MAP_ID, + * .arg2_type = PTR_TO_STACK_IMM_MAP_KEY, + * } + * so that eBPF verifier properly checks the arguments + */ +u64 bpf_map_delete_elem(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5) +{ + struct bpf_map *map; + int map_id = r1; + void *key = (void *) (unsigned long) r2; + + WARN_ON_ONCE(!rcu_read_lock_held()); + + map = idr_find(&bpf_map_id_idr, map_id); + /* eBPF verifier guarantees that map_id is valid */ + BUG_ON(!map); + + return map->ops->map_delete_elem(map, key); +}