From patchwork Wed Nov 1 02:29:46 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Kicinski X-Patchwork-Id: 832821 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=netronome-com.20150623.gappssmtp.com header.i=@netronome-com.20150623.gappssmtp.com header.b="lSceHUq0"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3yRXHR5CkWz9t3r for ; Wed, 1 Nov 2017 13:29:55 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933219AbdKAC3x (ORCPT ); Tue, 31 Oct 2017 22:29:53 -0400 Received: from mail-pg0-f65.google.com ([74.125.83.65]:47314 "EHLO mail-pg0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932742AbdKAC3w (ORCPT ); Tue, 31 Oct 2017 22:29:52 -0400 Received: by mail-pg0-f65.google.com with SMTP id r25so867534pgn.4 for ; Tue, 31 Oct 2017 19:29:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=netronome-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id; bh=RrLALTxlOlTCsyze41sElrhOEpURVXgi6qPU3E6sccM=; b=lSceHUq0MpAPAZOG/jOly9Sn6SdD3WPU7mIbBbr74TZuD1nWPIPwTMa8kcwydYHaIh qcuTtQmQg8uY8j+TCk5R2d5O0oJro2IdGjPIC2zX5HMj48vmLqM7QNejuC8S2QKMzmvi q2YIJGdFDF2RK/L4gs/UpF4inNQ8w3x1Q5Jj+pLkbpcwxIdyMchR9ilrzG+WAcKpGrYZ jpH7TgpXxBoQpf26kmUt27TXcjtawid5FTjWgNaR9lFVxyINO1L+phPfAp8jyhE3ZwOG qFUqwm6WfBfUls+2ZyHF4zkb+M8YGEVAv4cbGJDebcWpBxBMThaWjdM0Wn6FXJpa7dPQ gpRg== 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; bh=RrLALTxlOlTCsyze41sElrhOEpURVXgi6qPU3E6sccM=; b=UO1vg/p4XRWWt+WJ3lUl4uaWKhaWzkQ9TuXxzXaSBFyKWL1Giges1EWy9edGcvWd1x K4fOP/aIHI7SBJbpsJWpwXlKss/73ie1vWygBrRrV4p0RqEI6lx+u7/shTc6AgFXKbHE UuJQMEInZ5fx3bopK7MpiBvVwTeuWkWd5DkGdWS+zw3FrcMjg7KY2x1yG3PiQK5JXUY4 bpyO37xcTTDQLaEyEJPiW4fQvgwIVik2KplqfpLfrMkA/OCrZ2X7ci/zW33UgsLqBpa2 aw6NU7t4V/xfruo8rxtpJUsSvfqS/lXE+pISEKk4wqMw6iMXXtTIp6gJ1jXaXLq8BC9Y Z2Pw== X-Gm-Message-State: AMCzsaWu5buK3MfQ9+SgG68Ld65+Rm4l9F4Fcksvi2C6d8ys3MwXNW+z D6/JFvQGvHHNRf74uHjzs7ttKKvx X-Google-Smtp-Source: ABhQp+SMvgMRq2I6nAXNF0zOkGIuol4VVb2SMppjk6BEKHy0ClHpU1sCKrv/iyQsVXoXzVwXymoDug== X-Received: by 10.98.68.8 with SMTP id r8mr4445263pfa.161.1509503391180; Tue, 31 Oct 2017 19:29:51 -0700 (PDT) Received: from jkicinski-Precision-T1700.netronome.com ([75.53.12.129]) by smtp.gmail.com with ESMTPSA id i62sm5022722pfe.73.2017.10.31.19.29.50 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 31 Oct 2017 19:29:50 -0700 (PDT) From: Jakub Kicinski To: netdev@vger.kernel.org Cc: oss-drivers@netronome.com, alexei.starovoitov@gmail.com, daniel@iogearbox.net, Jakub Kicinski Subject: [RFC] net: dummy: add BPF offload callbacks for test purposes Date: Tue, 31 Oct 2017 19:29:46 -0700 Message-Id: <20171101022946.27114-1-jakub.kicinski@netronome.com> X-Mailer: git-send-email 2.14.1 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Add callbacks for BPF offload, a handful of checks and DebugFS files to be able to test BPF offload without any offload- -capable HW. Signed-off-by: Jakub Kicinski Reviewed-by: Quentin Monnet --- This was a little useful for testing, I'm not sure we want it upstream, though? drivers/net/dummy.c | 162 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 154 insertions(+), 8 deletions(-) diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c index 58483af80bdb..e1a1ad7902de 100644 --- a/drivers/net/dummy.c +++ b/drivers/net/dummy.c @@ -28,6 +28,10 @@ Alan Cox, 30th May 1994 */ +#include +#include +#include +#include #include #include #include @@ -47,6 +51,7 @@ static int numdummies = 1; static int num_vfs; +static bool debugfs; struct vf_data_storage { u8 vf_mac[ETH_ALEN]; @@ -61,8 +66,21 @@ struct vf_data_storage { int link_state; }; +struct dummy_bpf_offload_prog { + struct dummy_priv *dummy; + struct bpf_prog *prog; + const char *state; + struct list_head l; +}; + struct dummy_priv { struct vf_data_storage *vfinfo; + struct bpf_prog *xdp_prog; + int xdp_prog_mode; + struct dentry *ddir; + bool bpf_offload_accept; + u32 bpf_offload_verifier_delay; + struct list_head bpf_offload_progs; }; static int dummy_num_vf(struct device *dev) @@ -85,6 +103,35 @@ static struct device dummy_parent = { .release = release_dummy_parent, }; +static int dummy_debugfs_bpf_offload_read(struct seq_file *file, void *data) +{ + struct dummy_priv *priv = file->private; + struct dummy_bpf_offload_prog *state; + unsigned int i = 0; + + rtnl_lock(); + list_for_each_entry(state, &priv->bpf_offload_progs, l) + seq_printf(file, "%u %u %s %d\n", + i++, state->prog->aux->id, state->state, + state->prog == state->dummy->xdp_prog); + rtnl_unlock(); + + return 0; +} + +static int dummy_debugfs_bpf_offload_open(struct inode *inode, struct file *f) +{ + return single_open(f, dummy_debugfs_bpf_offload_read, inode->i_private); +} + +static const struct file_operations dummy_bpf_offload_fops = { + .owner = THIS_MODULE, + .open = dummy_debugfs_bpf_offload_open, + .release = single_release, + .read = seq_read, + .llseek = seq_lseek +}; + /* fake multicast ability */ static void set_multicast_list(struct net_device *dev) { @@ -141,18 +188,36 @@ static int dummy_dev_init(struct net_device *dev) priv->vfinfo = NULL; - if (!num_vfs) - return 0; + if (num_vfs) { + dev->dev.parent = &dummy_parent; + priv->vfinfo = kcalloc(num_vfs, sizeof(struct vf_data_storage), + GFP_KERNEL); + if (!priv->vfinfo) + goto err_free_dstats; + } - dev->dev.parent = &dummy_parent; - priv->vfinfo = kcalloc(num_vfs, sizeof(struct vf_data_storage), - GFP_KERNEL); - if (!priv->vfinfo) { - free_percpu(dev->dstats); - return -ENOMEM; + INIT_LIST_HEAD(&priv->bpf_offload_progs); + if (debugfs) { + priv->ddir = debugfs_create_dir(dev->name, NULL); + if (!priv->ddir) + goto err_free_vfinfo; + + debugfs_create_bool("bpf_offload_accept", 0600, + priv->ddir, &priv->bpf_offload_accept); + debugfs_create_u32("bpf_offload_verifier_delay", 0600, + priv->ddir, + &priv->bpf_offload_verifier_delay); + debugfs_create_file("bpf_offload_list", 0600, priv->ddir, + priv, &dummy_bpf_offload_fops); } return 0; + +err_free_vfinfo: + kfree(priv->vfinfo); +err_free_dstats: + free_percpu(dev->dstats); + return -ENOMEM; } static void dummy_dev_uninit(struct net_device *dev) @@ -280,6 +345,81 @@ static int dummy_set_vf_link_state(struct net_device *dev, int vf, int state) return 0; } +static int +dummy_bpf_verify_insn(struct bpf_verifier_env *env, int insn_idx, int prev_insn) +{ + struct dummy_bpf_offload_prog *state; + + state = env->prog->aux->offload->dev_priv; + if (state->dummy->bpf_offload_verifier_delay && !insn_idx) + msleep(state->dummy->bpf_offload_verifier_delay); + + return 0; +} + +static const struct bpf_ext_analyzer_ops dummy_bpf_analyzer_ops = { + .insn_hook = dummy_bpf_verify_insn, +}; + +static int dummy_bpf(struct net_device *dev, struct netdev_bpf *bpf) +{ + struct dummy_priv *priv = netdev_priv(dev); + struct dummy_bpf_offload_prog *state; + + ASSERT_RTNL(); + + switch (bpf->command) { + case BPF_OFFLOAD_VERIFIER_PREP: + if (!priv->bpf_offload_accept) + return -EOPNOTSUPP; + + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) + return -ENOMEM; + bpf->verifier.prog->aux->offload->dev_priv = state; + bpf->verifier.ops = &dummy_bpf_analyzer_ops; + + state->dummy = priv; + state->prog = bpf->verifier.prog; + state->state = "verify"; + list_add_tail(&state->l, &priv->bpf_offload_progs); + return 0; + case BPF_OFFLOAD_TRANSLATE: + state = bpf->offload.prog->aux->offload->dev_priv; + + state->state = "xlated"; + return 0; + case BPF_OFFLOAD_DESTROY: + state = bpf->offload.prog->aux->offload->dev_priv; + + list_del(&state->l); + kfree(state); + return 0; + case XDP_QUERY_PROG: + if (priv->xdp_prog) { + bpf->prog_attached = priv->xdp_prog_mode; + bpf->prog_id = priv->xdp_prog->aux->id; + } + return 0; + case XDP_SETUP_PROG: + case XDP_SETUP_PROG_HW: + if (bpf->prog->aux->offload) { + WARN_ON(bpf->prog->aux->offload->netdev != dev); + state = bpf->prog->aux->offload->dev_priv; + WARN_ON(strcmp(state->state, "xlated")); + } + + if (priv->xdp_prog) + bpf_prog_put(priv->xdp_prog); + priv->xdp_prog = bpf->prog; + priv->xdp_prog_mode = bpf->command == XDP_SETUP_PROG ? + XDP_ATTACHED_DRV : XDP_ATTACHED_HW; + return 0; + default: + return -EINVAL; + } +} + static const struct net_device_ops dummy_netdev_ops = { .ndo_init = dummy_dev_init, .ndo_uninit = dummy_dev_uninit, @@ -297,6 +437,7 @@ static const struct net_device_ops dummy_netdev_ops = { .ndo_get_vf_config = dummy_get_vf_config, .ndo_set_vf_link_state = dummy_set_vf_link_state, .ndo_set_vf_rss_query_en = dummy_set_vf_rss_query_en, + .ndo_bpf = dummy_bpf, }; static void dummy_get_drvinfo(struct net_device *dev, @@ -327,6 +468,8 @@ static void dummy_free_netdev(struct net_device *dev) { struct dummy_priv *priv = netdev_priv(dev); + WARN_ON(!list_empty(&priv->bpf_offload_progs)); + debugfs_remove_recursive(priv->ddir); kfree(priv->vfinfo); } @@ -382,6 +525,9 @@ MODULE_PARM_DESC(numdummies, "Number of dummy pseudo devices"); module_param(num_vfs, int, 0); MODULE_PARM_DESC(num_vfs, "Number of dummy VFs per dummy device"); +module_param(debugfs, bool, false); +MODULE_PARM_DESC(debugfs, "Expose control interface in DebugFS"); + static int __init dummy_init_one(void) { struct net_device *dev_dummy;