From patchwork Wed May 27 17:08:34 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Sitnicki X-Patchwork-Id: 218416 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.8 required=3.0 tests=DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 27B34C433E1 for ; Wed, 27 May 2020 17:08:50 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 0717520873 for ; Wed, 27 May 2020 17:08:50 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=cloudflare.com header.i=@cloudflare.com header.b="UbtuMdTd" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731132AbgE0RIt (ORCPT ); Wed, 27 May 2020 13:08:49 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41134 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729875AbgE0RIq (ORCPT ); Wed, 27 May 2020 13:08:46 -0400 Received: from mail-ej1-x643.google.com (mail-ej1-x643.google.com [IPv6:2a00:1450:4864:20::643]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 124BCC03E97D for ; Wed, 27 May 2020 10:08:46 -0700 (PDT) Received: by mail-ej1-x643.google.com with SMTP id x1so28949265ejd.8 for ; Wed, 27 May 2020 10:08:46 -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=4aNYzFZ3HQztQJxIHCfXbNBHtKfIZ7aoRnKs0QLw/oE=; b=UbtuMdTdaVEj1t1nuIVBixpqHZcjOrac9qGZFczd4DtMvVa+hiueDk/NSOW5GT8KRZ YqwyEP2w42/7XndFUvr6Cn4+/LAKTrUD/GMxTlcMgoxZ4I4VQCtBAjZrJzl8VCUmISrP rhm+Cu02/+iztj1R2eXop3lJwrDBagqKqUKpk= 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=4aNYzFZ3HQztQJxIHCfXbNBHtKfIZ7aoRnKs0QLw/oE=; b=bXAP+ElFEHfcCpUjan/mz1ZVheYZiww13NdB5aTGdwhLdqHu4Am/XrsPRpLtRH5YkG Vov+NUwpcsShaLh6L2LAVqImZLXmR61ttY0zt0oWdE3FPFY5+LUm4uTZu8KphUuUBHTO +24XCblrXStevTNrd4fuX/125G2Tafsh2aGu3cg19CviwbtjArTJJ1QKLoUihUM4pVxe Wx9OF4y52FrxvfBueSev/UrASpycSJpLsEvBq2kS/EMjETxQ/cKXz1QKy2QxoZPPawco yjYeoV6iT66uzBUQkkYZSiKunskIm9RoyTdZ6P9f+UOnniPbNY1tHRPfpnWssh/dTa/C /vug== X-Gm-Message-State: AOAM533X96wBVUFJr89UHzpUEJ6nnUZ1ivLlOeZ8m4Cxi7za8TgXlfMD a30fj1xfdgxbuzEcYVqWckWAZS/6FSg= X-Google-Smtp-Source: ABdhPJxM1aq2ausULE8+zhL4DTIGQiqUBoIXA++dwmTCA8sckm6c+YMf2xtAt2Xwf/NVatKH5l7TYg== X-Received: by 2002:a17:906:eda5:: with SMTP id sa5mr6871910ejb.289.1590599324729; Wed, 27 May 2020 10:08:44 -0700 (PDT) Received: from cloudflare.com ([2a02:a310:c262:aa00:b35e:8938:2c2a:ba8b]) by smtp.gmail.com with ESMTPSA id e9sm2716447edl.25.2020.05.27.10.08.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 27 May 2020 10:08:44 -0700 (PDT) From: Jakub Sitnicki To: bpf@vger.kernel.org Cc: netdev@vger.kernel.org, kernel-team@cloudflare.com Subject: [PATCH bpf-next 2/8] flow_dissector: Pull locking up from prog attach callback Date: Wed, 27 May 2020 19:08:34 +0200 Message-Id: <20200527170840.1768178-3-jakub@cloudflare.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: <20200527170840.1768178-1-jakub@cloudflare.com> References: <20200527170840.1768178-1-jakub@cloudflare.com> MIME-Version: 1.0 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Split out the part of attach callback that happens with attach/detach lock acquired. This structures the prog attach callback similar to prog detach, and opens up doors for moving the locking out of flow_dissector and into generic callbacks for attaching/detaching progs to netns in subsequent patches. Signed-off-by: Jakub Sitnicki --- net/core/flow_dissector.c | 40 +++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 73cc085dc2b7..4f73f6c51602 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -109,15 +109,10 @@ int skb_flow_dissector_prog_query(const union bpf_attr *attr, return 0; } -int skb_flow_dissector_bpf_prog_attach(const union bpf_attr *attr, - struct bpf_prog *prog) +static int flow_dissector_bpf_prog_attach(struct net *net, + struct bpf_prog *prog) { struct bpf_prog *attached; - struct net *net; - int ret = 0; - - net = current->nsproxy->net_ns; - mutex_lock(&flow_dissector_mutex); if (net == &init_net) { /* BPF flow dissector in the root namespace overrides @@ -130,33 +125,38 @@ int skb_flow_dissector_bpf_prog_attach(const union bpf_attr *attr, for_each_net(ns) { if (ns == &init_net) continue; - if (rcu_access_pointer(ns->flow_dissector_prog)) { - ret = -EEXIST; - goto out; - } + if (rcu_access_pointer(ns->flow_dissector_prog)) + return -EEXIST; } } else { /* Make sure root flow dissector is not attached * when attaching to the non-root namespace. */ - if (rcu_access_pointer(init_net.flow_dissector_prog)) { - ret = -EEXIST; - goto out; - } + if (rcu_access_pointer(init_net.flow_dissector_prog)) + return -EEXIST; } attached = rcu_dereference_protected(net->flow_dissector_prog, lockdep_is_held(&flow_dissector_mutex)); - if (attached == prog) { + if (attached == prog) /* The same program cannot be attached twice */ - ret = -EINVAL; - goto out; - } + return -EINVAL; + rcu_assign_pointer(net->flow_dissector_prog, prog); if (attached) bpf_prog_put(attached); -out: + return 0; +} + +int skb_flow_dissector_bpf_prog_attach(const union bpf_attr *attr, + struct bpf_prog *prog) +{ + int ret; + + mutex_lock(&flow_dissector_mutex); + ret = flow_dissector_bpf_prog_attach(current->nsproxy->net_ns, prog); mutex_unlock(&flow_dissector_mutex); + return ret; } From patchwork Wed May 27 17:08:36 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Sitnicki X-Patchwork-Id: 218415 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.9 required=3.0 tests=DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id E2A03C433DF for ; Wed, 27 May 2020 17:08:54 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B2D1720873 for ; Wed, 27 May 2020 17:08:54 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=cloudflare.com header.i=@cloudflare.com header.b="yMwj2pRf" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731150AbgE0RIy (ORCPT ); Wed, 27 May 2020 13:08:54 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41152 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731131AbgE0RIt (ORCPT ); Wed, 27 May 2020 13:08:49 -0400 Received: from mail-ed1-x541.google.com (mail-ed1-x541.google.com [IPv6:2a00:1450:4864:20::541]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 25185C03E97D for ; Wed, 27 May 2020 10:08:49 -0700 (PDT) Received: by mail-ed1-x541.google.com with SMTP id s19so20849300edt.12 for ; Wed, 27 May 2020 10:08:49 -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=ahk73YOLkvvyWYNMxGnkIqgt1nGRvSvFH7RHNXZ0uEw=; b=yMwj2pRf55N2y9Q+CDTDEsPGHWWn0C+hL1K5PqwdC2tegDWddI50xYnq5goVqcobvM n7ClDH5Wq3ADKW1kbS1q8D+1qVBIFOwR/jqcndidqd0V1feEi/pcuKpFDF2kZonaEiGY eDjolPjL3J/VJxp+f/EQoGaMvHZLqDMWVXoYM= 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=ahk73YOLkvvyWYNMxGnkIqgt1nGRvSvFH7RHNXZ0uEw=; b=VT4+Cev2O7uk/Roz5FtN2l5y1GNhJMuoq0oFzh9B5TqFqrr7aGGjLt1JXjSLWL8MLR a4niIHjr9+qLRREf/6ddZ1h0WVAtcXImTIkJCLQawUU7u+cRpzNVKS3ElmSP2LPELAom kizaapujuSr+mKnIySW2gy+xbQs9YSKI2H6Ra5SonWcMK1X18uOMtTS1w1uSL9niwYQB Xe5k5gj1llDWoX71gdEyDNRoGIUC10cojsQE0N9t+1LOfNAmgjCeGTqmh58YNSeqnd/p C5okE+Ro9i0vOFjS+cFXQDqBiYYCwJWN9rEHIqsvSEsaN3Z/mUlyWTMMjmNbRq1it0Vv XIlg== X-Gm-Message-State: AOAM533QZYlq5eRTnmU7W9m4i/trLEe4C3d77FZGUmWOJfoHJr1dCJ2v sTv0LGfeGtDBLxNvqghf+KAJJw== X-Google-Smtp-Source: ABdhPJwBDIdpZiJcwUtUgYDBGNfGLoDwQYI07xxyOYvNbZb0908lEoNEyk7sLecndvNtR1OeQdxA4A== X-Received: by 2002:aa7:cb8d:: with SMTP id r13mr24600606edt.12.1590599327756; Wed, 27 May 2020 10:08:47 -0700 (PDT) Received: from cloudflare.com ([2a02:a310:c262:aa00:b35e:8938:2c2a:ba8b]) by smtp.gmail.com with ESMTPSA id h20sm3260217eja.61.2020.05.27.10.08.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 27 May 2020 10:08:47 -0700 (PDT) From: Jakub Sitnicki To: bpf@vger.kernel.org Cc: netdev@vger.kernel.org, kernel-team@cloudflare.com Subject: [PATCH bpf-next 4/8] flow_dissector: Move out netns_bpf prog callbacks Date: Wed, 27 May 2020 19:08:36 +0200 Message-Id: <20200527170840.1768178-5-jakub@cloudflare.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: <20200527170840.1768178-1-jakub@cloudflare.com> References: <20200527170840.1768178-1-jakub@cloudflare.com> MIME-Version: 1.0 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Move functions to manage BPF programs attached to netns that are not specific to flow dissector to a dedicated module named bpf/net_namespace.c. The set of functions will grow with the addition of bpf_link support for netns attached programs. This patch prepares ground for it by creating a place for it. This is a code move with no functional changes intended. Signed-off-by: Jakub Sitnicki --- include/net/flow_dissector.h | 6 ++ kernel/bpf/Makefile | 1 + kernel/bpf/net_namespace.c | 134 +++++++++++++++++++++++++++++++++++ net/core/flow_dissector.c | 126 ++------------------------------ 4 files changed, 145 insertions(+), 122 deletions(-) create mode 100644 kernel/bpf/net_namespace.c diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h index 628383915827..9af143760e35 100644 --- a/include/net/flow_dissector.h +++ b/include/net/flow_dissector.h @@ -8,6 +8,8 @@ #include #include +struct bpf_prog; +struct net; struct sk_buff; /** @@ -357,4 +359,8 @@ flow_dissector_init_keys(struct flow_dissector_key_control *key_control, memset(key_basic, 0, sizeof(*key_basic)); } +#ifdef CONFIG_BPF_SYSCALL +int flow_dissector_bpf_prog_attach(struct net *net, struct bpf_prog *prog); +#endif /* CONFIG_BPF_SYSCALL */ + #endif diff --git a/kernel/bpf/Makefile b/kernel/bpf/Makefile index 375b933010dd..ccecb70bfaa0 100644 --- a/kernel/bpf/Makefile +++ b/kernel/bpf/Makefile @@ -13,6 +13,7 @@ ifeq ($(CONFIG_NET),y) obj-$(CONFIG_BPF_SYSCALL) += devmap.o obj-$(CONFIG_BPF_SYSCALL) += cpumap.o obj-$(CONFIG_BPF_SYSCALL) += offload.o +obj-$(CONFIG_BPF_SYSCALL) += net_namespace.o endif ifeq ($(CONFIG_PERF_EVENTS),y) obj-$(CONFIG_BPF_SYSCALL) += stackmap.o diff --git a/kernel/bpf/net_namespace.c b/kernel/bpf/net_namespace.c new file mode 100644 index 000000000000..fc89154aed27 --- /dev/null +++ b/kernel/bpf/net_namespace.c @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include + +/* + * Functions to manage BPF programs attached to netns + */ + +/* Protects updates to netns_bpf */ +DEFINE_MUTEX(netns_bpf_mutex); + +int netns_bpf_prog_query(const union bpf_attr *attr, + union bpf_attr __user *uattr) +{ + __u32 __user *prog_ids = u64_to_user_ptr(attr->query.prog_ids); + u32 prog_id, prog_cnt = 0, flags = 0; + enum netns_bpf_attach_type type; + struct bpf_prog *attached; + struct net *net; + + if (attr->query.query_flags) + return -EINVAL; + + type = to_netns_bpf_attach_type(attr->query.attach_type); + if (type < 0) + return -EINVAL; + + net = get_net_ns_by_fd(attr->query.target_fd); + if (IS_ERR(net)) + return PTR_ERR(net); + + rcu_read_lock(); + attached = rcu_dereference(net->bpf.progs[type]); + if (attached) { + prog_cnt = 1; + prog_id = attached->aux->id; + } + rcu_read_unlock(); + + put_net(net); + + if (copy_to_user(&uattr->query.attach_flags, &flags, sizeof(flags))) + return -EFAULT; + if (copy_to_user(&uattr->query.prog_cnt, &prog_cnt, sizeof(prog_cnt))) + return -EFAULT; + + if (!attr->query.prog_cnt || !prog_ids || !prog_cnt) + return 0; + + if (copy_to_user(prog_ids, &prog_id, sizeof(u32))) + return -EFAULT; + + return 0; +} + +int netns_bpf_prog_attach(const union bpf_attr *attr, struct bpf_prog *prog) +{ + enum netns_bpf_attach_type type; + struct net *net; + int ret; + + type = to_netns_bpf_attach_type(attr->attach_type); + if (type < 0) + return -EINVAL; + + net = current->nsproxy->net_ns; + mutex_lock(&netns_bpf_mutex); + switch (type) { + case NETNS_BPF_FLOW_DISSECTOR: + ret = flow_dissector_bpf_prog_attach(net, prog); + break; + default: + ret = -EINVAL; + break; + } + mutex_unlock(&netns_bpf_mutex); + + return ret; +} + +static int __netns_bpf_prog_detach(struct net *net, + enum netns_bpf_attach_type type) +{ + struct bpf_prog *attached; + + /* No need for update-side lock when net is going away. */ + attached = rcu_dereference_protected(net->bpf.progs[type], + !check_net(net) || + lockdep_is_held(&netns_bpf_mutex)); + if (!attached) + return -ENOENT; + RCU_INIT_POINTER(net->bpf.progs[type], NULL); + bpf_prog_put(attached); + return 0; +} + +int netns_bpf_prog_detach(const union bpf_attr *attr) +{ + enum netns_bpf_attach_type type; + int ret; + + type = to_netns_bpf_attach_type(attr->attach_type); + if (type < 0) + return -EINVAL; + + mutex_lock(&netns_bpf_mutex); + ret = __netns_bpf_prog_detach(current->nsproxy->net_ns, type); + mutex_unlock(&netns_bpf_mutex); + + return ret; +} + +static void __net_exit netns_bpf_pernet_pre_exit(struct net *net) +{ + enum netns_bpf_attach_type type; + + for (type = 0; type < MAX_NETNS_BPF_ATTACH_TYPE; type++) { + if (rcu_access_pointer(net->bpf.progs[type])) + __netns_bpf_prog_detach(net, type); + } +} + +static struct pernet_operations netns_bpf_pernet_ops __net_initdata = { + .pre_exit = netns_bpf_pernet_pre_exit, +}; + +static int __init netns_bpf_init(void) +{ + return register_pernet_subsys(&netns_bpf_pernet_ops); +} + +subsys_initcall(netns_bpf_init); diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 5c978c87e6bc..9a42ac5114e3 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -33,9 +33,6 @@ #endif #include -/* Protects updates to netns_bpf */ -DEFINE_MUTEX(netns_bpf_mutex); - static void dissector_set_key(struct flow_dissector *flow_dissector, enum flow_dissector_key_id key_id) { @@ -72,52 +69,8 @@ void skb_flow_dissector_init(struct flow_dissector *flow_dissector, } EXPORT_SYMBOL(skb_flow_dissector_init); -int netns_bpf_prog_query(const union bpf_attr *attr, - union bpf_attr __user *uattr) -{ - __u32 __user *prog_ids = u64_to_user_ptr(attr->query.prog_ids); - u32 prog_id, prog_cnt = 0, flags = 0; - enum netns_bpf_attach_type type; - struct bpf_prog *attached; - struct net *net; - - if (attr->query.query_flags) - return -EINVAL; - - type = to_netns_bpf_attach_type(attr->query.attach_type); - if (type < 0) - return -EINVAL; - - net = get_net_ns_by_fd(attr->query.target_fd); - if (IS_ERR(net)) - return PTR_ERR(net); - - rcu_read_lock(); - attached = rcu_dereference(net->bpf.progs[type]); - if (attached) { - prog_cnt = 1; - prog_id = attached->aux->id; - } - rcu_read_unlock(); - - put_net(net); - - if (copy_to_user(&uattr->query.attach_flags, &flags, sizeof(flags))) - return -EFAULT; - if (copy_to_user(&uattr->query.prog_cnt, &prog_cnt, sizeof(prog_cnt))) - return -EFAULT; - - if (!attr->query.prog_cnt || !prog_ids || !prog_cnt) - return 0; - - if (copy_to_user(prog_ids, &prog_id, sizeof(u32))) - return -EFAULT; - - return 0; -} - -static int flow_dissector_bpf_prog_attach(struct net *net, - struct bpf_prog *prog) +#ifdef CONFIG_BPF_SYSCALL +int flow_dissector_bpf_prog_attach(struct net *net, struct bpf_prog *prog) { enum netns_bpf_attach_type type = NETNS_BPF_FLOW_DISSECTOR; struct bpf_prog *attached; @@ -155,77 +108,7 @@ static int flow_dissector_bpf_prog_attach(struct net *net, bpf_prog_put(attached); return 0; } - -int netns_bpf_prog_attach(const union bpf_attr *attr, struct bpf_prog *prog) -{ - enum netns_bpf_attach_type type; - struct net *net; - int ret; - - type = to_netns_bpf_attach_type(attr->attach_type); - if (type < 0) - return -EINVAL; - - net = current->nsproxy->net_ns; - mutex_lock(&netns_bpf_mutex); - switch (type) { - case NETNS_BPF_FLOW_DISSECTOR: - ret = flow_dissector_bpf_prog_attach(net, prog); - break; - default: - ret = -EINVAL; - break; - } - mutex_unlock(&netns_bpf_mutex); - - return ret; -} - -static int __netns_bpf_prog_detach(struct net *net, - enum netns_bpf_attach_type type) -{ - struct bpf_prog *attached; - - /* No need for update-side lock when net is going away. */ - attached = rcu_dereference_protected(net->bpf.progs[type], - !check_net(net) || - lockdep_is_held(&netns_bpf_mutex)); - if (!attached) - return -ENOENT; - RCU_INIT_POINTER(net->bpf.progs[type], NULL); - bpf_prog_put(attached); - return 0; -} - -int netns_bpf_prog_detach(const union bpf_attr *attr) -{ - enum netns_bpf_attach_type type; - int ret; - - type = to_netns_bpf_attach_type(attr->attach_type); - if (type < 0) - return -EINVAL; - - mutex_lock(&netns_bpf_mutex); - ret = __netns_bpf_prog_detach(current->nsproxy->net_ns, type); - mutex_unlock(&netns_bpf_mutex); - - return ret; -} - -static void __net_exit netns_bpf_pernet_pre_exit(struct net *net) -{ - enum netns_bpf_attach_type type; - - for (type = 0; type < MAX_NETNS_BPF_ATTACH_TYPE; type++) { - if (rcu_access_pointer(net->bpf.progs[type])) - __netns_bpf_prog_detach(net, type); - } -} - -static struct pernet_operations netns_bpf_pernet_ops __net_initdata = { - .pre_exit = netns_bpf_pernet_pre_exit, -}; +#endif /* CONFIG_BPF_SYSCALL */ /** * __skb_flow_get_ports - extract the upper layer ports and return them @@ -1886,7 +1769,6 @@ static int __init init_default_flow_dissectors(void) skb_flow_dissector_init(&flow_keys_basic_dissector, flow_keys_basic_dissector_keys, ARRAY_SIZE(flow_keys_basic_dissector_keys)); - - return register_pernet_subsys(&netns_bpf_pernet_ops); + return 0; } core_initcall(init_default_flow_dissectors); From patchwork Wed May 27 17:08:37 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Sitnicki X-Patchwork-Id: 218413 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.8 required=3.0 tests=DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 69357C433DF for ; Wed, 27 May 2020 17:09:03 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 434C220890 for ; Wed, 27 May 2020 17:09:03 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=cloudflare.com header.i=@cloudflare.com header.b="MQOsyiqM" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731146AbgE0RIx (ORCPT ); Wed, 27 May 2020 13:08:53 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41160 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731140AbgE0RIv (ORCPT ); Wed, 27 May 2020 13:08:51 -0400 Received: from mail-ej1-x642.google.com (mail-ej1-x642.google.com [IPv6:2a00:1450:4864:20::642]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D0E3FC08C5C1 for ; Wed, 27 May 2020 10:08:50 -0700 (PDT) Received: by mail-ej1-x642.google.com with SMTP id d7so28972632eja.7 for ; Wed, 27 May 2020 10:08:50 -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=NRufhQKkMUDdRL0tS4oIuBxx8mnNfg6jqoiG3Ma23lg=; b=MQOsyiqM6QuArvMLYfUm0pmhyAiOnNoZdx4b64niy2pQzp0hlf+qZeCkhwDi5sQkmZ ckhkhOPF6wkX8RIOJve7CJvVtWO1RlNSDiXaaIYZ/Zzozw9magS9zZYWxIZZ/6OMf/oC nLXgeUh1imIQni0P7/Mkyi/D7aVyhRnJ93qFw= 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=NRufhQKkMUDdRL0tS4oIuBxx8mnNfg6jqoiG3Ma23lg=; b=r2tYFL6LFmwdxkvOiXK+tFpP2oBqYspxROIb2TtY0MwYEXsB2SAonuBuRL/44TTrNu qG30W5djS5Jm8ti7jg45uIchTAzTneJxoIR4F+b5jYlfJ7yr8GSWcX7W/XzmjHeotzYE D3LtC1eJPmvXUfS33gVDNPvdUs3Df2xM+sweLB5EygUmbGylyD3Cp+TVDKsCPK4B0sW8 rhhZ6HKlTEdEK14Y3yxvITvBPiKUtOIzP/H8qK+QMe/netJEk7wa8jj95gssctc8vJ/q 3svxiRTkQ1r6L1eIB5lkWwl+s30AuM3rgeEg9HJSq1xSmVzE8jgwotB8Sv7gcDXYNAfB HmEQ== X-Gm-Message-State: AOAM532YMc0d+1xtW89W4E9jWaYA7HMi4FusR2/Q77Aw30NZY3R5SXoJ YTM6B+6VhTEh5KOwYJDbGcXC3w== X-Google-Smtp-Source: ABdhPJxfwrVTIeSYabZaNBbvTE70ml2+QR5ey8wuFPtHHojXXqc4feYF8LHWggETcYigSIGDQZCXrQ== X-Received: by 2002:a17:906:934e:: with SMTP id p14mr6902961ejw.502.1590599329360; Wed, 27 May 2020 10:08:49 -0700 (PDT) Received: from cloudflare.com ([2a02:a310:c262:aa00:b35e:8938:2c2a:ba8b]) by smtp.gmail.com with ESMTPSA id s19sm3336713eja.91.2020.05.27.10.08.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 27 May 2020 10:08:48 -0700 (PDT) From: Jakub Sitnicki To: bpf@vger.kernel.org Cc: netdev@vger.kernel.org, kernel-team@cloudflare.com Subject: [PATCH bpf-next 5/8] bpf: Add link-based BPF program attachment to network namespace Date: Wed, 27 May 2020 19:08:37 +0200 Message-Id: <20200527170840.1768178-6-jakub@cloudflare.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: <20200527170840.1768178-1-jakub@cloudflare.com> References: <20200527170840.1768178-1-jakub@cloudflare.com> MIME-Version: 1.0 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Add support for bpf() syscall subcommands that operate on bpf_link (LINK_CREATE, LINK_UPDATE, OBJ_GET_INFO) for attach points tied to network namespaces (that is flow dissector at the moment). Link-based and prog-based attachment can be used interchangeably, but only one can be in use at a time. Attempts to attach a link when a prog is already attached directly, and the other way around, will be met with -EBUSY. Attachment of multiple links of same attach type to one netns is not supported, with the intention to lift it when a use-case presents itself. Because of that attempts to create a netns link, when one already exists result in -E2BIG error, signifying that there is no space left for another attachment. Link-based attachments to netns don't keep a netns alive by holding a ref to it. Instead links get auto-detached from netns when the latter is being destroyed by a pernet pre_exit callback. When auto-detached, link lives in defunct state as long there are open FDs for it. -ENOLINK is returned if a user tries to update a defunct link. Because bpf_link to netns doesn't hold a ref to struct net, special care is taken when releasing the link. The netns might be getting torn down when the release function tries to access it to detach the link. To ensure the struct net object is alive when release function accesses it we rely on the fact that cleanup_net(), struct net destructor, calls synchronize_rcu() after invoking pre_exit callbacks. If auto-detach from pre_exit happens first, link release will not attempt to access struct net. Same applies the other way around, network namespace doesn't keep an attached link alive because by not holding a ref to it. Instead bpf_links to netns are RCU-freed, so that pernet pre_exit callback can safely access and auto-detach the link when racing with link release/free. Signed-off-by: Jakub Sitnicki --- include/linux/bpf-netns.h | 8 + include/net/netns/bpf.h | 1 + include/uapi/linux/bpf.h | 5 + kernel/bpf/net_namespace.c | 257 ++++++++++++++++++++++++++++++++- kernel/bpf/syscall.c | 3 + net/core/filter.c | 1 + tools/include/uapi/linux/bpf.h | 5 + 7 files changed, 278 insertions(+), 2 deletions(-) diff --git a/include/linux/bpf-netns.h b/include/linux/bpf-netns.h index f3aec3d79824..4052d649f36d 100644 --- a/include/linux/bpf-netns.h +++ b/include/linux/bpf-netns.h @@ -34,6 +34,8 @@ int netns_bpf_prog_query(const union bpf_attr *attr, int netns_bpf_prog_attach(const union bpf_attr *attr, struct bpf_prog *prog); int netns_bpf_prog_detach(const union bpf_attr *attr); +int netns_bpf_link_create(const union bpf_attr *attr, + struct bpf_prog *prog); #else static inline int netns_bpf_prog_query(const union bpf_attr *attr, union bpf_attr __user *uattr) @@ -51,6 +53,12 @@ static inline int netns_bpf_prog_detach(const union bpf_attr *attr) { return -EOPNOTSUPP; } + +static inline int netns_bpf_link_create(const union bpf_attr *attr, + struct bpf_prog *prog) +{ + return -EOPNOTSUPP; +} #endif #endif /* _BPF_NETNS_H */ diff --git a/include/net/netns/bpf.h b/include/net/netns/bpf.h index a858d1c5b166..baabefdeb10c 100644 --- a/include/net/netns/bpf.h +++ b/include/net/netns/bpf.h @@ -12,6 +12,7 @@ struct bpf_prog; struct netns_bpf { struct bpf_prog __rcu *progs[MAX_NETNS_BPF_ATTACH_TYPE]; + struct bpf_link __rcu *links[MAX_NETNS_BPF_ATTACH_TYPE]; }; #endif /* __NETNS_BPF_H__ */ diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 54b93f8b49b8..05469d3c5c82 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -235,6 +235,7 @@ enum bpf_link_type { BPF_LINK_TYPE_TRACING = 2, BPF_LINK_TYPE_CGROUP = 3, BPF_LINK_TYPE_ITER = 4, + BPF_LINK_TYPE_NETNS = 5, MAX_BPF_LINK_TYPE, }; @@ -3753,6 +3754,10 @@ struct bpf_link_info { __u64 cgroup_id; __u32 attach_type; } cgroup; + struct { + __u32 netns_ino; + __u32 attach_type; + } netns; }; } __attribute__((aligned(8))); diff --git a/kernel/bpf/net_namespace.c b/kernel/bpf/net_namespace.c index fc89154aed27..1c6009ab93c5 100644 --- a/kernel/bpf/net_namespace.c +++ b/kernel/bpf/net_namespace.c @@ -8,9 +8,155 @@ * Functions to manage BPF programs attached to netns */ -/* Protects updates to netns_bpf */ +struct bpf_netns_link { + struct bpf_link link; + enum bpf_attach_type type; + enum netns_bpf_attach_type netns_type; + + /* struct net is not RCU-freed but we treat it as such because + * our pre_exit callback will NULL this pointer before + * cleanup_net() calls synchronize_rcu(). + */ + struct net __rcu *net; + + /* bpf_netns_link is RCU-freed for pre_exit callback invoked + * by cleanup_net() to safely access the link. + */ + struct rcu_head rcu; +}; + +/* Protects updates to netns_bpf. */ DEFINE_MUTEX(netns_bpf_mutex); +static inline struct bpf_netns_link *to_bpf_netns_link(struct bpf_link *link) +{ + return container_of(link, struct bpf_netns_link, link); +} + +/* Called with RCU read lock. */ +static void __net_exit +bpf_netns_link_auto_detach(struct net *net, enum netns_bpf_attach_type type) +{ + struct bpf_netns_link *net_link; + struct bpf_link *link; + + link = rcu_dereference(net->bpf.links[type]); + if (!link) + return; + net_link = to_bpf_netns_link(link); + RCU_INIT_POINTER(net_link->net, NULL); +} + +static void bpf_netns_link_release(struct bpf_link *link) +{ + struct bpf_netns_link *net_link = to_bpf_netns_link(link); + enum netns_bpf_attach_type type = net_link->netns_type; + struct net *net; + + /* Link auto-detached by dying netns. */ + if (!rcu_access_pointer(net_link->net)) + return; + + mutex_lock(&netns_bpf_mutex); + + /* Recheck after potential sleep. We can race with cleanup_net + * here, but if we see a non-NULL struct net pointer pre_exit + * and following synchronize_rcu() has not happened yet, and + * we have until the end of grace period to access net. + */ + rcu_read_lock(); + net = rcu_dereference(net_link->net); + if (net) { + RCU_INIT_POINTER(net->bpf.links[type], NULL); + RCU_INIT_POINTER(net->bpf.progs[type], NULL); + } + rcu_read_unlock(); + + mutex_unlock(&netns_bpf_mutex); +} + +static void bpf_netns_link_dealloc(struct bpf_link *link) +{ + struct bpf_netns_link *net_link = to_bpf_netns_link(link); + + /* Delay kfree in case we're racing with cleanup_net. */ + kfree_rcu(net_link, rcu); +} + +static int bpf_netns_link_update_prog(struct bpf_link *link, + struct bpf_prog *new_prog, + struct bpf_prog *old_prog) +{ + struct bpf_netns_link *net_link = to_bpf_netns_link(link); + struct net *net; + int ret = 0; + + if (old_prog && old_prog != link->prog) + return -EPERM; + if (new_prog->type != link->prog->type) + return -EINVAL; + + mutex_lock(&netns_bpf_mutex); + rcu_read_lock(); + + net = rcu_dereference(net_link->net); + if (!net || !check_net(net)) { + /* Link auto-detached or netns dying */ + ret = -ENOLINK; + goto out_unlock; + } + + old_prog = xchg(&link->prog, new_prog); + bpf_prog_put(old_prog); + +out_unlock: + rcu_read_unlock(); + mutex_unlock(&netns_bpf_mutex); + + return ret; +} + +static int bpf_netns_link_fill_info(const struct bpf_link *link, + struct bpf_link_info *info) +{ + const struct bpf_netns_link *net_link; + unsigned int inum; + struct net *net; + + net_link = container_of(link, struct bpf_netns_link, link); + + rcu_read_lock(); + net = rcu_dereference(net_link->net); + if (net) + inum = net->ns.inum; + rcu_read_unlock(); + + info->netns.netns_ino = inum; + info->netns.attach_type = net_link->type; + return 0; +} + +static void bpf_netns_link_show_fdinfo(const struct bpf_link *link, + struct seq_file *seq) +{ + struct bpf_link_info info = {}; + + bpf_netns_link_fill_info(link, &info); + seq_printf(seq, + "netns_ino:\t%u\n" + "attach_type:\t%u\n", + info.netns.netns_ino, + info.netns.attach_type); +} + +static const struct bpf_link_ops bpf_netns_link_ops = { + .release = bpf_netns_link_release, + .dealloc = bpf_netns_link_dealloc, + .update_prog = bpf_netns_link_update_prog, + .fill_link_info = bpf_netns_link_fill_info, + .show_fdinfo = bpf_netns_link_show_fdinfo, +}; + int netns_bpf_prog_query(const union bpf_attr *attr, union bpf_attr __user *uattr) { @@ -67,6 +213,13 @@ int netns_bpf_prog_attach(const union bpf_attr *attr, struct bpf_prog *prog) net = current->nsproxy->net_ns; mutex_lock(&netns_bpf_mutex); + + /* Attaching prog directly is not compatible with links */ + if (rcu_access_pointer(net->bpf.links[type])) { + ret = -EBUSY; + goto unlock; + } + switch (type) { case NETNS_BPF_FLOW_DISSECTOR: ret = flow_dissector_bpf_prog_attach(net, prog); @@ -75,6 +228,7 @@ int netns_bpf_prog_attach(const union bpf_attr *attr, struct bpf_prog *prog) ret = -EINVAL; break; } +unlock: mutex_unlock(&netns_bpf_mutex); return ret; @@ -85,6 +239,10 @@ static int __netns_bpf_prog_detach(struct net *net, { struct bpf_prog *attached; + /* Progs attached via links cannot be detached */ + if (rcu_access_pointer(net->bpf.links[type])) + return -EBUSY; + /* No need for update-side lock when net is going away. */ attached = rcu_dereference_protected(net->bpf.progs[type], !check_net(net) || @@ -112,14 +270,109 @@ int netns_bpf_prog_detach(const union bpf_attr *attr) return ret; } +static int __netns_bpf_link_attach(struct net *net, struct bpf_link *link, + enum netns_bpf_attach_type type) +{ + int err; + + /* Allow attaching only one prog or link for now */ + if (rcu_access_pointer(net->bpf.links[type])) + return -E2BIG; + /* Links are not compatible with attaching prog directly */ + if (rcu_access_pointer(net->bpf.progs[type])) + return -EBUSY; + + switch (type) { + case NETNS_BPF_FLOW_DISSECTOR: + err = flow_dissector_bpf_prog_attach(net, link->prog); + break; + default: + err = -EINVAL; + break; + } + if (!err) + rcu_assign_pointer(net->bpf.links[type], link); + return err; +} + +static int netns_bpf_link_attach(struct net *net, struct bpf_link *link, + enum netns_bpf_attach_type type) +{ + int ret; + + mutex_lock(&netns_bpf_mutex); + ret = __netns_bpf_link_attach(net, link, type); + mutex_unlock(&netns_bpf_mutex); + + return ret; +} + +int netns_bpf_link_create(const union bpf_attr *attr, struct bpf_prog *prog) +{ + enum netns_bpf_attach_type netns_type; + struct bpf_link_primer link_primer; + struct bpf_netns_link *net_link; + enum bpf_attach_type type; + struct net *net; + int err; + + if (attr->link_create.flags) + return -EINVAL; + + type = attr->link_create.attach_type; + netns_type = to_netns_bpf_attach_type(type); + if (netns_type < 0) + return -EINVAL; + + net = get_net_ns_by_fd(attr->link_create.target_fd); + if (IS_ERR(net)) + return PTR_ERR(net); + + net_link = kzalloc(sizeof(*net_link), GFP_USER); + if (!net_link) { + err = -ENOMEM; + goto out_put_net; + } + bpf_link_init(&net_link->link, BPF_LINK_TYPE_NETNS, + &bpf_netns_link_ops, prog); + rcu_assign_pointer(net_link->net, net); + net_link->type = type; + net_link->netns_type = netns_type; + + err = bpf_link_prime(&net_link->link, &link_primer); + if (err) { + kfree(net_link); + goto out_put_net; + } + + err = netns_bpf_link_attach(net, &net_link->link, netns_type); + if (err) { + bpf_link_cleanup(&link_primer); + goto out_put_net; + } + + err = bpf_link_settle(&link_primer); +out_put_net: + /* To auto-detach the link from netns when it is getting + * destroyed, we can't hold a ref to it. Instead, we rely on + * RCU when accessing link->net pointer. + */ + put_net(net); + return err; +} + static void __net_exit netns_bpf_pernet_pre_exit(struct net *net) { enum netns_bpf_attach_type type; + rcu_read_lock(); for (type = 0; type < MAX_NETNS_BPF_ATTACH_TYPE; type++) { - if (rcu_access_pointer(net->bpf.progs[type])) + if (rcu_access_pointer(net->bpf.links[type])) + bpf_netns_link_auto_detach(net, type); + else if (rcu_access_pointer(net->bpf.progs[type])) __netns_bpf_prog_detach(net, type); } + rcu_read_unlock(); } static struct pernet_operations netns_bpf_pernet_ops __net_initdata = { diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 93f329a6736d..47a7b426d75c 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -3874,6 +3874,9 @@ static int link_create(union bpf_attr *attr) case BPF_PROG_TYPE_TRACING: ret = tracing_bpf_link_attach(attr, prog); break; + case BPF_PROG_TYPE_FLOW_DISSECTOR: + ret = netns_bpf_link_create(attr, prog); + break; default: ret = -EINVAL; } diff --git a/net/core/filter.c b/net/core/filter.c index a6fc23447f12..b77391a1adb1 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -9081,6 +9081,7 @@ const struct bpf_verifier_ops sk_reuseport_verifier_ops = { const struct bpf_prog_ops sk_reuseport_prog_ops = { }; + #endif /* CONFIG_INET */ DEFINE_BPF_DISPATCHER(xdp) diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 54b93f8b49b8..05469d3c5c82 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -235,6 +235,7 @@ enum bpf_link_type { BPF_LINK_TYPE_TRACING = 2, BPF_LINK_TYPE_CGROUP = 3, BPF_LINK_TYPE_ITER = 4, + BPF_LINK_TYPE_NETNS = 5, MAX_BPF_LINK_TYPE, }; @@ -3753,6 +3754,10 @@ struct bpf_link_info { __u64 cgroup_id; __u32 attach_type; } cgroup; + struct { + __u32 netns_ino; + __u32 attach_type; + } netns; }; } __attribute__((aligned(8))); From patchwork Wed May 27 17:08:39 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Sitnicki X-Patchwork-Id: 218414 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.8 required=3.0 tests=DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1303FC433DF for ; Wed, 27 May 2020 17:08:59 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id E6EF220873 for ; Wed, 27 May 2020 17:08:58 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=cloudflare.com header.i=@cloudflare.com header.b="pJb9l1y4" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731164AbgE0RI6 (ORCPT ); Wed, 27 May 2020 13:08:58 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41170 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731154AbgE0RIy (ORCPT ); Wed, 27 May 2020 13:08:54 -0400 Received: from mail-ej1-x641.google.com (mail-ej1-x641.google.com [IPv6:2a00:1450:4864:20::641]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BC289C03E97D for ; Wed, 27 May 2020 10:08:53 -0700 (PDT) Received: by mail-ej1-x641.google.com with SMTP id x1so28949809ejd.8 for ; Wed, 27 May 2020 10:08:53 -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=q+2bwX22EsAe1QSviW85LaE3gusRIu6tmCK3DJYgP0A=; b=pJb9l1y42ndLHge2lnFbaiY0JdrTHacaAUore46NzLEsmS5kyVGmJm4KcrXr/zOSn4 XVVlG75EF8INWAdz0oYeRKfmtqPxZizcZXON0UaAbyUbfWfQBTWr6FuCAaDtP2li/gK9 2yoYbHR1CxdxTFhSgR8ES9IHl5bGziaJbKitI= 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=q+2bwX22EsAe1QSviW85LaE3gusRIu6tmCK3DJYgP0A=; b=qnxkLk6HxKjPbQCiiemVtaOhqs8eA1qw2wkoePDmo4LNjvsygBE0zNSDOBzsdvr+XN Dgsb3XwDpIQCCM+HIekIzCRxukqd96Xok1rGjlmeo+WTrj2tZiwH1xZU4MBUqZvEUs3D 3nGcq1V3XC2soUepEzwt5KuEplhHY/USOd8H8P1FlFvOIWaOUMUH0JeM6BHAfK0lxqi4 dOFm88p+QGynsQ5anb5e4hjxoAB5EXBze0ot9zU9SgfiM7bLyEA4KuDZSO1bH0sMHwfu jM13xJt1idD2nAx9vD5YmTqcC7V5EBTBDH0cc5Mpkt5W+btZuA+m0HIfWRbaqUdEcbkC sjxQ== X-Gm-Message-State: AOAM5320qsFdeOLaUO1aCB5AvFgOr6Jtc0sulBkcCIi0t+rSSdw8Hz6W nqssHIdNJc3cR98sdQJzucOZmQ== X-Google-Smtp-Source: ABdhPJwKwyXVikczHmirkQfA12LUtINfPEsR3pHynCmpmypONRRw/La2SksS0Yw0oHPT43fqJFgzQg== X-Received: by 2002:a17:906:b24f:: with SMTP id ce15mr6948749ejb.59.1590599332399; Wed, 27 May 2020 10:08:52 -0700 (PDT) Received: from cloudflare.com ([2a02:a310:c262:aa00:b35e:8938:2c2a:ba8b]) by smtp.gmail.com with ESMTPSA id da17sm2604927edb.11.2020.05.27.10.08.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 27 May 2020 10:08:51 -0700 (PDT) From: Jakub Sitnicki To: bpf@vger.kernel.org Cc: netdev@vger.kernel.org, kernel-team@cloudflare.com Subject: [PATCH bpf-next 7/8] bpftool: Support link show for netns-attached links Date: Wed, 27 May 2020 19:08:39 +0200 Message-Id: <20200527170840.1768178-8-jakub@cloudflare.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: <20200527170840.1768178-1-jakub@cloudflare.com> References: <20200527170840.1768178-1-jakub@cloudflare.com> MIME-Version: 1.0 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Make `bpf link show` aware of new link type, that is links attached to netns. When listing netns-attached links, display netns inode number as its identifier and link attach type. Signed-off-by: Jakub Sitnicki --- tools/bpf/bpftool/link.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tools/bpf/bpftool/link.c b/tools/bpf/bpftool/link.c index 670a561dc31b..83a17d62c4c3 100644 --- a/tools/bpf/bpftool/link.c +++ b/tools/bpf/bpftool/link.c @@ -17,6 +17,7 @@ static const char * const link_type_name[] = { [BPF_LINK_TYPE_TRACING] = "tracing", [BPF_LINK_TYPE_CGROUP] = "cgroup", [BPF_LINK_TYPE_ITER] = "iter", + [BPF_LINK_TYPE_NETNS] = "netns", }; static int link_parse_fd(int *argc, char ***argv) @@ -122,6 +123,16 @@ static int show_link_close_json(int fd, struct bpf_link_info *info) jsonw_uint_field(json_wtr, "attach_type", info->cgroup.attach_type); break; + case BPF_LINK_TYPE_NETNS: + jsonw_uint_field(json_wtr, "netns_ino", + info->netns.netns_ino); + if (info->netns.attach_type < ARRAY_SIZE(attach_type_name)) + jsonw_string_field(json_wtr, "attach_type", + attach_type_name[info->netns.attach_type]); + else + jsonw_uint_field(json_wtr, "attach_type", + info->netns.attach_type); + break; default: break; } @@ -190,6 +201,14 @@ static int show_link_close_plain(int fd, struct bpf_link_info *info) else printf("attach_type %u ", info->cgroup.attach_type); break; + case BPF_LINK_TYPE_NETNS: + printf("\n\tnetns_ino %u ", info->netns.netns_ino); + if (info->netns.attach_type < ARRAY_SIZE(attach_type_name)) + printf("attach_type %s ", + attach_type_name[info->netns.attach_type]); + else + printf("attach_type %u ", info->netns.attach_type); + break; default: break; }