From patchwork Fri Aug 28 09:48:32 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenz Bauer X-Patchwork-Id: 1353143 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Original-To: incoming-bpf@patchwork.ozlabs.org Delivered-To: patchwork-incoming-bpf@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=bpf-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=reject dis=none) header.from=cloudflare.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; secure) header.d=cloudflare.com header.i=@cloudflare.com header.a=rsa-sha256 header.s=google header.b=Mb5FqoTz; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 4BdFDP1fcxz9sSn for ; Fri, 28 Aug 2020 19:49:09 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728554AbgH1JtH (ORCPT ); Fri, 28 Aug 2020 05:49:07 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40526 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728016AbgH1JtF (ORCPT ); Fri, 28 Aug 2020 05:49:05 -0400 Received: from mail-wm1-x341.google.com (mail-wm1-x341.google.com [IPv6:2a00:1450:4864:20::341]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 799CFC061264 for ; Fri, 28 Aug 2020 02:49:04 -0700 (PDT) Received: by mail-wm1-x341.google.com with SMTP id k20so328408wmi.5 for ; Fri, 28 Aug 2020 02:49:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cloudflare.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=B3Nfp/MpmtpH3wyaYcWdTkoL8BnuseGzYkm1FtJR5fE=; b=Mb5FqoTzNfZaB0ZkuV6PBdnZcADU1OY7kF9qnf2j2/yrkpF4moS7s2/d2JSmQrfJSr udUoxsYzTLh1IyzndLo6TmBjkzvwXkXuf9Xaf7JKEoytfM36OodGH3XN16sRgzV17nN3 Pb0s/f4xOrybjIoiffjF0Vn3HXqCkagtzSfrM= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=B3Nfp/MpmtpH3wyaYcWdTkoL8BnuseGzYkm1FtJR5fE=; b=WUm/8q+mIYfJHKkh7SxK1tj4iVQj+7w1HUKcp0fVDtVNvuE82ZhTmNg6Dy9XikSf9y INHleBbo4qLCtHProMQbYDRvHMQwQtAsPUGcquizH+9+3AANkKflFeig98E1Zkjtx5r+ h4CyKa9pxfg8a2ihHxbzgFxuzdh5z6aXgyAsSnuoHVhAlwJ8YJecbbycDq81WaRhJo6Y 4Ok5/3tlLedjOL4sHL7jBk/FIq4Z69GGYzRLaL9WiQUj3HPfNMisHtZlDuL5h3XMnNeA IjXRR7NuOak3qkvWtCF6h/0ABKWq+3T46PZEbcdTV2llmC4TbNS5/UYm7D+b2/wylXCg tz8w== X-Gm-Message-State: AOAM533asD2SihwlsU7Zdsrg/yb7B6s6lKvilG5i8gdPnhWWDBqN/ias lcrCoogSRPwahF3PWubC9skPgw== X-Google-Smtp-Source: ABdhPJwoskH0sb5AmNr8bk68mbCJBNTUsCTBZD2+rmVN6w/T+AzYxT82b9OkokWL14R4uDHj/jkhKQ== X-Received: by 2002:a1c:2742:: with SMTP id n63mr813034wmn.24.1598608141752; Fri, 28 Aug 2020 02:49:01 -0700 (PDT) Received: from antares.lan (5.8.0.7.f.1.6.5.2.2.a.f.0.8.0.0.f.f.6.2.a.5.a.7.0.b.8.0.1.0.0.2.ip6.arpa. [2001:8b0:7a5a:26ff:80:fa22:561f:7085]) by smtp.gmail.com with ESMTPSA id z203sm1371119wmc.31.2020.08.28.02.48.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 28 Aug 2020 02:49:00 -0700 (PDT) From: Lorenz Bauer To: ast@kernel.org, yhs@fb.com, daniel@iogearbox.net, jakub@cloudflare.com, john.fastabend@gmail.com Cc: bpf@vger.kernel.org, kernel-team@cloudflare.com, Lorenz Bauer Subject: [PATCH bpf-next 1/3] net: Allow iterating sockmap and sockhash Date: Fri, 28 Aug 2020 10:48:32 +0100 Message-Id: <20200828094834.23290-2-lmb@cloudflare.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200828094834.23290-1-lmb@cloudflare.com> References: <20200828094834.23290-1-lmb@cloudflare.com> MIME-Version: 1.0 Sender: bpf-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org Add bpf_iter support for sockmap / sockhash, based on the bpf_sk_storage and hashtable implementation. sockmap and sockhash share the same iteration context: a pointer to an arbitrary key and a pointer to a socket. Both pointers may be NULL, and so BPF has to perform a NULL check before accessing them. Technically it's not possible for sockhash iteration to yield a NULL socket, but we ignore this to be able to use a single iteration point. Iteration will visit all keys that remain unmodified during the lifetime of the iterator. It may or may not visit newly added ones. Signed-off-by: Lorenz Bauer --- net/core/sock_map.c | 283 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 283 insertions(+) diff --git a/net/core/sock_map.c b/net/core/sock_map.c index d6c6e1e312fc..31c4332f06e4 100644 --- a/net/core/sock_map.c +++ b/net/core/sock_map.c @@ -703,6 +703,116 @@ const struct bpf_func_proto bpf_msg_redirect_map_proto = { .arg4_type = ARG_ANYTHING, }; +struct sock_map_seq_info { + struct bpf_map *map; + struct sock *sk; + u32 index; +}; + +struct bpf_iter__sockmap { + __bpf_md_ptr(struct bpf_iter_meta *, meta); + __bpf_md_ptr(struct bpf_map *, map); + __bpf_md_ptr(void *, key); + __bpf_md_ptr(struct bpf_sock *, sk); +}; + +DEFINE_BPF_ITER_FUNC(sockmap, struct bpf_iter_meta *meta, + struct bpf_map *map, void *key, + struct sock *sk) + +static void *sock_map_seq_lookup_elem(struct sock_map_seq_info *info) +{ + if (unlikely(info->index >= info->map->max_entries)) + return NULL; + + info->sk = __sock_map_lookup_elem(info->map, info->index); + if (!info->sk || !sk_fullsock(info->sk)) + info->sk = NULL; + + /* continue iterating */ + return info; +} + +static void *sock_map_seq_start(struct seq_file *seq, loff_t *pos) +{ + struct sock_map_seq_info *info = seq->private; + + if (*pos == 0) + ++*pos; + + /* pairs with sock_map_seq_stop */ + rcu_read_lock(); + return sock_map_seq_lookup_elem(info); +} + +static void *sock_map_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct sock_map_seq_info *info = seq->private; + + ++*pos; + ++info->index; + + return sock_map_seq_lookup_elem(info); +} + +static int __sock_map_seq_show(struct seq_file *seq, void *v) +{ + struct sock_map_seq_info *info = seq->private; + struct bpf_iter__sockmap ctx = {}; + struct bpf_iter_meta meta; + struct bpf_prog *prog; + + meta.seq = seq; + prog = bpf_iter_get_info(&meta, !v); + if (!prog) + return 0; + + ctx.meta = &meta; + ctx.map = info->map; + if (v) { + ctx.key = &info->index; + ctx.sk = (struct bpf_sock *)info->sk; + } + + return bpf_iter_run_prog(prog, &ctx); +} + +static int sock_map_seq_show(struct seq_file *seq, void *v) +{ + return __sock_map_seq_show(seq, v); +} + +static void sock_map_seq_stop(struct seq_file *seq, void *v) +{ + if (!v) + (void)__sock_map_seq_show(seq, NULL); + + /* pairs with sock_map_seq_start */ + rcu_read_unlock(); +} + +static const struct seq_operations sock_map_seq_ops = { + .start = sock_map_seq_start, + .next = sock_map_seq_next, + .stop = sock_map_seq_stop, + .show = sock_map_seq_show, +}; + +static int sock_map_init_seq_private(void *priv_data, + struct bpf_iter_aux_info *aux) +{ + struct sock_map_seq_info *info = priv_data; + + info->map = aux->map; + return 0; +} + +static const struct bpf_iter_seq_info sock_map_iter_seq_info = { + .seq_ops = &sock_map_seq_ops, + .init_seq_private = sock_map_init_seq_private, + .seq_priv_size = sizeof(struct sock_map_seq_info), +}; + static int sock_map_btf_id; const struct bpf_map_ops sock_map_ops = { .map_alloc = sock_map_alloc, @@ -716,6 +826,7 @@ const struct bpf_map_ops sock_map_ops = { .map_check_btf = map_check_no_btf, .map_btf_name = "bpf_stab", .map_btf_id = &sock_map_btf_id, + .iter_seq_info = &sock_map_iter_seq_info, }; struct bpf_shtab_elem { @@ -1198,6 +1309,120 @@ const struct bpf_func_proto bpf_msg_redirect_hash_proto = { .arg4_type = ARG_ANYTHING, }; +struct sock_hash_seq_info { + struct bpf_map *map; + struct bpf_shtab *htab; + u32 bucket_id; +}; + +static void *sock_hash_seq_find_next(struct sock_hash_seq_info *info, + struct bpf_shtab_elem *prev_elem) +{ + const struct bpf_shtab *htab = info->htab; + struct bpf_shtab_bucket *bucket; + struct bpf_shtab_elem *elem; + struct hlist_node *node; + + /* try to find next elem in the same bucket */ + if (prev_elem) { + node = rcu_dereference_raw(hlist_next_rcu(&prev_elem->node)); + elem = hlist_entry_safe(node, struct bpf_shtab_elem, node); + if (elem) + return elem; + + /* no more elements, continue in the next bucket */ + info->bucket_id++; + } + + for (; info->bucket_id < htab->buckets_num; info->bucket_id++) { + bucket = &htab->buckets[info->bucket_id]; + node = rcu_dereference_raw(hlist_first_rcu(&bucket->head)); + elem = hlist_entry_safe(node, struct bpf_shtab_elem, node); + if (elem) + return elem; + } + + return NULL; +} + +static void *sock_hash_seq_start(struct seq_file *seq, loff_t *pos) +{ + struct sock_hash_seq_info *info = seq->private; + + if (*pos == 0) + ++*pos; + + /* pairs with sock_hash_seq_stop */ + rcu_read_lock(); + return sock_hash_seq_find_next(info, NULL); +} + +static void *sock_hash_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct sock_hash_seq_info *info = seq->private; + + ++*pos; + return sock_hash_seq_find_next(info, v); +} + +static int __sock_hash_seq_show(struct seq_file *seq, struct bpf_shtab_elem *elem) +{ + struct sock_hash_seq_info *info = seq->private; + struct bpf_iter__sockmap ctx = {}; + struct bpf_iter_meta meta; + struct bpf_prog *prog; + + meta.seq = seq; + prog = bpf_iter_get_info(&meta, !elem); + if (!prog) + return 0; + + ctx.meta = &meta; + ctx.map = info->map; + if (elem) { + ctx.key = elem->key; + ctx.sk = (struct bpf_sock *)elem->sk; + } + + return bpf_iter_run_prog(prog, &ctx); +} + +static int sock_hash_seq_show(struct seq_file *seq, void *v) +{ + return __sock_hash_seq_show(seq, v); +} + +static void sock_hash_seq_stop(struct seq_file *seq, void *v) +{ + if (!v) + (void)__sock_hash_seq_show(seq, NULL); + + /* pairs with sock_hash_seq_start */ + rcu_read_unlock(); +} + +static const struct seq_operations sock_hash_seq_ops = { + .start = sock_hash_seq_start, + .next = sock_hash_seq_next, + .stop = sock_hash_seq_stop, + .show = sock_hash_seq_show, +}; + +static int sock_hash_init_seq_private(void *priv_data, + struct bpf_iter_aux_info *aux) +{ + struct sock_hash_seq_info *info = priv_data; + + info->map = aux->map; + return 0; +} + +static const struct bpf_iter_seq_info sock_hash_iter_seq_info = { + .seq_ops = &sock_hash_seq_ops, + .init_seq_private = sock_hash_init_seq_private, + .seq_priv_size = sizeof(struct sock_hash_seq_info), +}; + static int sock_hash_map_btf_id; const struct bpf_map_ops sock_hash_ops = { .map_alloc = sock_hash_alloc, @@ -1211,6 +1436,7 @@ const struct bpf_map_ops sock_hash_ops = { .map_check_btf = map_check_no_btf, .map_btf_name = "bpf_shtab", .map_btf_id = &sock_hash_map_btf_id, + .iter_seq_info = &sock_hash_iter_seq_info, }; static struct sk_psock_progs *sock_map_progs(struct bpf_map *map) @@ -1321,3 +1547,60 @@ void sock_map_close(struct sock *sk, long timeout) release_sock(sk); saved_close(sk, timeout); } + +static int sock_map_iter_attach_target(struct bpf_prog *prog, + union bpf_iter_link_info *linfo, + struct bpf_iter_aux_info *aux) +{ + struct bpf_map *map; + int err = -EINVAL; + + if (!linfo->map.map_fd) + return -EBADF; + + map = bpf_map_get_with_uref(linfo->map.map_fd); + if (IS_ERR(map)) + return PTR_ERR(map); + + if (map->map_type != BPF_MAP_TYPE_SOCKMAP) + goto put_map; + + if (prog->aux->max_rdonly_access > map->key_size) { + err = -EACCES; + goto put_map; + } + + aux->map = map; + return 0; + +put_map: + bpf_map_put_with_uref(map); + return err; +} + +static void sock_map_iter_detach_target(struct bpf_iter_aux_info *aux) +{ + bpf_map_put_with_uref(aux->map); +} + +static struct bpf_iter_reg sock_map_iter_reg = { + .target = "sockmap", + .attach_target = sock_map_iter_attach_target, + .detach_target = sock_map_iter_detach_target, + .show_fdinfo = bpf_iter_map_show_fdinfo, + .fill_link_info = bpf_iter_map_fill_link_info, + .ctx_arg_info_size = 2, + .ctx_arg_info = { + { offsetof(struct bpf_iter__sockmap, key), + PTR_TO_RDONLY_BUF_OR_NULL }, + { offsetof(struct bpf_iter__sockmap, sk), + PTR_TO_SOCKET_OR_NULL }, + }, + .seq_info = &sock_map_iter_seq_info, +}; + +static int __init bpf_sockmap_iter_init(void) +{ + return bpf_iter_reg_target(&sock_map_iter_reg); +} +late_initcall(bpf_sockmap_iter_init); From patchwork Fri Aug 28 09:48:33 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenz Bauer X-Patchwork-Id: 1353144 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Original-To: incoming-bpf@patchwork.ozlabs.org Delivered-To: patchwork-incoming-bpf@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=bpf-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=reject dis=none) header.from=cloudflare.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; secure) header.d=cloudflare.com header.i=@cloudflare.com header.a=rsa-sha256 header.s=google header.b=y1O/lyDb; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 4BdFDR6YDtz9sSn for ; Fri, 28 Aug 2020 19:49:11 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728016AbgH1JtK (ORCPT ); Fri, 28 Aug 2020 05:49:10 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40528 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728218AbgH1JtF (ORCPT ); Fri, 28 Aug 2020 05:49:05 -0400 Received: from mail-wr1-x441.google.com (mail-wr1-x441.google.com [IPv6:2a00:1450:4864:20::441]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A450EC06121B for ; Fri, 28 Aug 2020 02:49:04 -0700 (PDT) Received: by mail-wr1-x441.google.com with SMTP id y3so703923wrl.4 for ; Fri, 28 Aug 2020 02:49:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cloudflare.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=WJJrBLnUK02XOLSfBNkg9sJ8M9pmMGgqCS2Hxkfo1Jk=; b=y1O/lyDb4QewGMWg7QE58v64J6dA9/n5JRxZQox/IBht2mRQlNBPb0U6wEzdumABaf lT6RVceI58bV78WlPBeAJV+DIYRXqK1t/ZV5i4JUPDVi0tqNUttNNvlK/hMm6S4s6kcN I2tnGiUYpL3eJozA4dP4OwBwLP65Bfp4J5aak= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=WJJrBLnUK02XOLSfBNkg9sJ8M9pmMGgqCS2Hxkfo1Jk=; b=m78iCX1Nw58uZVcLOe3uVGkEwE1abt6NB9o3Tk1cYLXZue5ODGJjQym5hnJysmnf4K dzYKaqsinnPh9OlCHXC6q13tfxRbZZtHsz/Zg1lVqjJlbRoRQ+MQMdB8Dj82gFG7FGSk Hq57ggBEx8Lh4hZt6i5uNt55D2Tz2QoAJpk9pwJDuSODqGiOFHMrZ1vQVWVBATXIKl7B tJY1M2PxOEmSbsFqiC9IlGSDhrT9XfFw1HGU1FgC63fssqHOzNI7CNIObGzFdsNLNNOW KH7drErcRtHKGqcrW2WG9qhvoPm2GmYk5WtSPKi8pSrmlJko07KhVeH+5+iOrTLoG8l/ lp2Q== X-Gm-Message-State: AOAM532+AhyEep2O3FMk1s4pJwdxqCIYAGfSKRvxh9s/qHtnO+cKe2FC hhHgcMW5sJtofcQNuurn/G0qRg== X-Google-Smtp-Source: ABdhPJzK/MDGjj6GdJ9x+5mbg7QzrOipZfBSVFDrw8wtvy9fabpKG3anL67jMxz730nphneZGiWRmg== X-Received: by 2002:adf:e904:: with SMTP id f4mr735625wrm.300.1598608143265; Fri, 28 Aug 2020 02:49:03 -0700 (PDT) Received: from antares.lan (5.8.0.7.f.1.6.5.2.2.a.f.0.8.0.0.f.f.6.2.a.5.a.7.0.b.8.0.1.0.0.2.ip6.arpa. [2001:8b0:7a5a:26ff:80:fa22:561f:7085]) by smtp.gmail.com with ESMTPSA id z203sm1371119wmc.31.2020.08.28.02.49.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 28 Aug 2020 02:49:02 -0700 (PDT) From: Lorenz Bauer To: ast@kernel.org, yhs@fb.com, daniel@iogearbox.net, jakub@cloudflare.com, john.fastabend@gmail.com Cc: bpf@vger.kernel.org, kernel-team@cloudflare.com, Lorenz Bauer Subject: [PATCH bpf-next 2/3] selftests: bpf: Add helper to compare socket cookies Date: Fri, 28 Aug 2020 10:48:33 +0100 Message-Id: <20200828094834.23290-3-lmb@cloudflare.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200828094834.23290-1-lmb@cloudflare.com> References: <20200828094834.23290-1-lmb@cloudflare.com> MIME-Version: 1.0 Sender: bpf-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org We compare socket cookies to ensure that insertion into a sockmap worked. Pull this out into a helper function for use in other tests. Signed-off-by: Lorenz Bauer --- .../selftests/bpf/prog_tests/sockmap_basic.c | 51 ++++++++++++++----- 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c b/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c index 0b79d78b98db..b989f8760f1a 100644 --- a/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c +++ b/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c @@ -47,6 +47,38 @@ static int connected_socket_v4(void) return -1; } +static void compare_cookies(struct bpf_map *src, struct bpf_map *dst) +{ + __u32 i, max_entries = bpf_map__max_entries(src); + int err, duration, src_fd, dst_fd; + + src_fd = bpf_map__fd(src); + dst_fd = bpf_map__fd(src); + + for (i = 0; i < max_entries; i++) { + __u64 src_cookie, dst_cookie; + + err = bpf_map_lookup_elem(src_fd, &i, &src_cookie); + if (err && errno == ENOENT) { + err = bpf_map_lookup_elem(dst_fd, &i, &dst_cookie); + if (err && errno == ENOENT) + continue; + + CHECK(err, "map_lookup_elem(dst)", "element not deleted\n"); + continue; + } + if (CHECK(err, "lookup_elem(src, cookie)", "%s\n", strerror(errno))) + continue; + + err = bpf_map_lookup_elem(dst_fd, &i, &dst_cookie); + if (CHECK(err, "lookup_elem(dst, cookie)", "%s\n", strerror(errno))) + continue; + + CHECK(dst_cookie != src_cookie, "cookie mismatch", + "%llu != %llu (pos %u)\n", dst_cookie, src_cookie, i); + } +} + /* Create a map, populate it with one socket, and free the map. */ static void test_sockmap_create_update_free(enum bpf_map_type map_type) { @@ -106,9 +138,9 @@ static void test_skmsg_helpers(enum bpf_map_type map_type) static void test_sockmap_update(enum bpf_map_type map_type) { struct bpf_prog_test_run_attr tattr; - int err, prog, src, dst, duration = 0; + int err, prog, src, duration = 0; struct test_sockmap_update *skel; - __u64 src_cookie, dst_cookie; + struct bpf_map *dst_map; const __u32 zero = 0; char dummy[14] = {0}; __s64 sk; @@ -124,18 +156,14 @@ static void test_sockmap_update(enum bpf_map_type map_type) prog = bpf_program__fd(skel->progs.copy_sock_map); src = bpf_map__fd(skel->maps.src); if (map_type == BPF_MAP_TYPE_SOCKMAP) - dst = bpf_map__fd(skel->maps.dst_sock_map); + dst_map = skel->maps.dst_sock_map; else - dst = bpf_map__fd(skel->maps.dst_sock_hash); + dst_map = skel->maps.dst_sock_hash; err = bpf_map_update_elem(src, &zero, &sk, BPF_NOEXIST); if (CHECK(err, "update_elem(src)", "errno=%u\n", errno)) goto out; - err = bpf_map_lookup_elem(src, &zero, &src_cookie); - if (CHECK(err, "lookup_elem(src, cookie)", "errno=%u\n", errno)) - goto out; - tattr = (struct bpf_prog_test_run_attr){ .prog_fd = prog, .repeat = 1, @@ -148,12 +176,7 @@ static void test_sockmap_update(enum bpf_map_type map_type) "errno=%u retval=%u\n", errno, tattr.retval)) goto out; - err = bpf_map_lookup_elem(dst, &zero, &dst_cookie); - if (CHECK(err, "lookup_elem(dst, cookie)", "errno=%u\n", errno)) - goto out; - - CHECK(dst_cookie != src_cookie, "cookie mismatch", "%llu != %llu\n", - dst_cookie, src_cookie); + compare_cookies(skel->maps.src, dst_map); out: test_sockmap_update__destroy(skel); From patchwork Fri Aug 28 09:48:34 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenz Bauer X-Patchwork-Id: 1353145 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Original-To: incoming-bpf@patchwork.ozlabs.org Delivered-To: patchwork-incoming-bpf@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=bpf-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=reject dis=none) header.from=cloudflare.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; secure) header.d=cloudflare.com header.i=@cloudflare.com header.a=rsa-sha256 header.s=google header.b=c2RBnblR; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 4BdFDS45YRz9sTC for ; Fri, 28 Aug 2020 19:49:12 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728218AbgH1JtM (ORCPT ); Fri, 28 Aug 2020 05:49:12 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40534 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728532AbgH1JtH (ORCPT ); Fri, 28 Aug 2020 05:49:07 -0400 Received: from mail-wm1-x341.google.com (mail-wm1-x341.google.com [IPv6:2a00:1450:4864:20::341]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 208D8C061232 for ; Fri, 28 Aug 2020 02:49:06 -0700 (PDT) Received: by mail-wm1-x341.google.com with SMTP id a65so345878wme.5 for ; Fri, 28 Aug 2020 02:49:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cloudflare.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=qR8VWUSftgKEzO0XNFqMMxHOeRQBd71aEYXYDTM4bF0=; b=c2RBnblRSroAQ7UXSWYd56aztlCSF6aljhNmrM+4TDptJRe1/6SB51zIcjad55aSR3 A65hnVdgsunIdj5ojRZFIpHxFLxD9K3DoxNf+VDODf+hdypQQ8J/C8X87RvX/D7LIx9C edjwC3LiFku1NYoFnqhFj68aEpUsUwNiwIjsA= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=qR8VWUSftgKEzO0XNFqMMxHOeRQBd71aEYXYDTM4bF0=; b=msvzvb8T4FcrYValqyLa85mOwobevhmYItnNI/5jchKsWFyS8xhlP+kRbh5OQ+KSHb /E3AmHxW+txhoCM4gPXRMXs9q59IAFnfG/++tSywaRc1MFYrp3gmaKxenUnCJtCiBj79 7paDaDqjOFgvhEWxJEq5IfB4X6ZxrZbIfYtkX5kVyY9EQdSbEnVe0MsdsbVhKyZJFkno 2xIC47i5DCxe6158SVN0i+3UVW1zIdEZSrlGz/AqHMP395MrVUCOWuHN7Bf5S5EUekL7 v/HAc+zl1hKNX2zd9T0Z2k6TLnj3xe9TOcQ+6VcJ0ZPcoSZAQ/HqgNuREhrm+LfWb8q4 8jcg== X-Gm-Message-State: AOAM532TXRFSdmKE4nxhHYr4pj10j3McnkZwM9tvEydzLIXvrkx6/an6 okNidRwCwzfnNczZTV7jU1rl1A== X-Google-Smtp-Source: ABdhPJx4GKKd44ZsjgOWoWoYGlkpsrgLwGCo/ts9kmY9jWwkohk8ffN8KusiniZXSRGedF22nJSjog== X-Received: by 2002:a05:600c:410b:: with SMTP id j11mr865471wmi.38.1598608144731; Fri, 28 Aug 2020 02:49:04 -0700 (PDT) Received: from antares.lan (5.8.0.7.f.1.6.5.2.2.a.f.0.8.0.0.f.f.6.2.a.5.a.7.0.b.8.0.1.0.0.2.ip6.arpa. [2001:8b0:7a5a:26ff:80:fa22:561f:7085]) by smtp.gmail.com with ESMTPSA id z203sm1371119wmc.31.2020.08.28.02.49.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 28 Aug 2020 02:49:04 -0700 (PDT) From: Lorenz Bauer To: ast@kernel.org, yhs@fb.com, daniel@iogearbox.net, jakub@cloudflare.com, john.fastabend@gmail.com Cc: bpf@vger.kernel.org, kernel-team@cloudflare.com, Lorenz Bauer Subject: [PATCH bpf-next 3/3] selftests: bpf: Test copying a sockmap via bpf_iter Date: Fri, 28 Aug 2020 10:48:34 +0100 Message-Id: <20200828094834.23290-4-lmb@cloudflare.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200828094834.23290-1-lmb@cloudflare.com> References: <20200828094834.23290-1-lmb@cloudflare.com> MIME-Version: 1.0 Sender: bpf-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org Add a test that exercises a basic sockmap / sockhash copy using bpf_iter. Signed-off-by: Lorenz Bauer --- .../selftests/bpf/prog_tests/sockmap_basic.c | 78 +++++++++++++++++++ tools/testing/selftests/bpf/progs/bpf_iter.h | 9 +++ .../selftests/bpf/progs/bpf_iter_sockmap.c | 50 ++++++++++++ 3 files changed, 137 insertions(+) create mode 100644 tools/testing/selftests/bpf/progs/bpf_iter_sockmap.c diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c b/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c index b989f8760f1a..386aecf1f7ff 100644 --- a/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c +++ b/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c @@ -6,6 +6,7 @@ #include "test_skmsg_load_helpers.skel.h" #include "test_sockmap_update.skel.h" #include "test_sockmap_invalid_update.skel.h" +#include "bpf_iter_sockmap.skel.h" #define TCP_REPAIR 19 /* TCP sock is under repair right now */ @@ -194,6 +195,79 @@ static void test_sockmap_invalid_update(void) test_sockmap_invalid_update__destroy(skel); } +static void test_sockmap_copy(enum bpf_map_type map_type) +{ + DECLARE_LIBBPF_OPTS(bpf_iter_attach_opts, opts); + int err, i, len, src_fd, iter_fd, num_sockets, duration; + struct bpf_iter_sockmap *skel; + struct bpf_map *src, *dst; + union bpf_iter_link_info linfo = {0}; + __s64 sock_fd[2] = {-1, -1}; + struct bpf_link *link; + char buf[64]; + __u32 max_elems; + + skel = bpf_iter_sockmap__open_and_load(); + if (CHECK(!skel, "bpf_iter_sockmap__open_and_load", + "skeleton open_and_load failed\n")) + return; + + if (map_type == BPF_MAP_TYPE_SOCKMAP) + src = skel->maps.sockmap; + else + src = skel->maps.sockhash; + + dst = skel->maps.dst; + src_fd = bpf_map__fd(src); + max_elems = bpf_map__max_entries(src); + + num_sockets = ARRAY_SIZE(sock_fd); + for (i = 0; i < num_sockets; i++) { + sock_fd[i] = connected_socket_v4(); + if (CHECK(sock_fd[i] == -1, "connected_socket_v4", "cannot connect\n")) + goto out; + + err = bpf_map_update_elem(src_fd, &i, &sock_fd[i], BPF_NOEXIST); + if (CHECK(err, "map_update", "map_update failed\n")) + goto out; + } + + linfo.map.map_fd = src_fd; + opts.link_info = &linfo; + opts.link_info_len = sizeof(linfo); + link = bpf_program__attach_iter(skel->progs.copy_sockmap, &opts); + if (CHECK(IS_ERR(link), "attach_iter", "attach_iter failed\n")) + goto out; + + iter_fd = bpf_iter_create(bpf_link__fd(link)); + if (CHECK(iter_fd < 0, "create_iter", "create_iter failed\n")) + goto free_link; + + /* do some tests */ + while ((len = read(iter_fd, buf, sizeof(buf))) > 0) + ; + if (CHECK(len < 0, "read", "failed: %s\n", strerror(errno))) + goto close_iter; + + /* test results */ + if (CHECK(skel->bss->elems != max_elems, "elems", "got %u expected %u\n", + skel->bss->elems, max_elems)) + goto close_iter; + + compare_cookies(src, dst); + +close_iter: + close(iter_fd); +free_link: + bpf_link__destroy(link); +out: + for (i = 0; i < num_sockets; i++) { + if (sock_fd[i] >= 0) + close(sock_fd[i]); + } + bpf_iter_sockmap__destroy(skel); +} + void test_sockmap_basic(void) { if (test__start_subtest("sockmap create_update_free")) @@ -210,4 +284,8 @@ void test_sockmap_basic(void) test_sockmap_update(BPF_MAP_TYPE_SOCKHASH); if (test__start_subtest("sockmap update in unsafe context")) test_sockmap_invalid_update(); + if (test__start_subtest("sockmap copy")) + test_sockmap_copy(BPF_MAP_TYPE_SOCKMAP); + if (test__start_subtest("sockhash copy")) + test_sockmap_copy(BPF_MAP_TYPE_SOCKHASH); } diff --git a/tools/testing/selftests/bpf/progs/bpf_iter.h b/tools/testing/selftests/bpf/progs/bpf_iter.h index c196280df90d..ac32a29f5153 100644 --- a/tools/testing/selftests/bpf/progs/bpf_iter.h +++ b/tools/testing/selftests/bpf/progs/bpf_iter.h @@ -13,6 +13,7 @@ #define udp6_sock udp6_sock___not_used #define bpf_iter__bpf_map_elem bpf_iter__bpf_map_elem___not_used #define bpf_iter__bpf_sk_storage_map bpf_iter__bpf_sk_storage_map___not_used +#define bpf_iter__sockmap bpf_iter__sockmap___not_used #include "vmlinux.h" #undef bpf_iter_meta #undef bpf_iter__bpf_map @@ -26,6 +27,7 @@ #undef udp6_sock #undef bpf_iter__bpf_map_elem #undef bpf_iter__bpf_sk_storage_map +#undef bpf_iter__sockmap struct bpf_iter_meta { struct seq_file *seq; @@ -96,3 +98,10 @@ struct bpf_iter__bpf_sk_storage_map { struct sock *sk; void *value; }; + +struct bpf_iter__sockmap { + struct bpf_iter_meta *meta; + struct bpf_map *map; + void *key; + struct bpf_sock *sk; +}; diff --git a/tools/testing/selftests/bpf/progs/bpf_iter_sockmap.c b/tools/testing/selftests/bpf/progs/bpf_iter_sockmap.c new file mode 100644 index 000000000000..1b4268c9cd31 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/bpf_iter_sockmap.c @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2020 Cloudflare */ +#include "bpf_iter.h" +#include "bpf_tracing_net.h" +#include +#include + +char _license[] SEC("license") = "GPL"; + +struct { + __uint(type, BPF_MAP_TYPE_SOCKMAP); + __uint(max_entries, 3); + __type(key, __u32); + __type(value, __u64); +} sockmap SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_SOCKMAP); + __uint(max_entries, 3); + __type(key, __u32); + __type(value, __u64); +} sockhash SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_SOCKHASH); + __uint(max_entries, 3); + __type(key, __u32); + __type(value, __u64); +} dst SEC(".maps"); + +__u32 elems = 0; + +SEC("iter/sockmap") +int copy_sockmap(struct bpf_iter__sockmap *ctx) +{ + __u32 tmp, *key = ctx->key; + struct bpf_sock *sk = ctx->sk; + + if (key == (void *)0) + return 0; + + elems++; + tmp = *key; + + if (sk != (void *)0) + return bpf_map_update_elem(&dst, &tmp, sk, 0) != 0; + + bpf_map_delete_elem(&dst, &tmp); + return 0; +}