netdevsim: add bpf offload support
Add support for loading programs for netdevsim devices and expose the related information via DebugFS. Both offload of XDP and cls_bpf programs is supported. Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com> Reviewed-by: Simon Horman <simon.horman@netronome.com> Reviewed-by: Quentin Monnet <quentin.monnet@netronome.com> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
This commit is contained in:

committed by
Daniel Borkmann

parent
83c9e13aa3
commit
31d3ad8329
@@ -13,16 +13,45 @@
|
||||
* THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
*/
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/slab.h>
|
||||
#include <net/netlink.h>
|
||||
#include <net/pkt_cls.h>
|
||||
#include <net/rtnetlink.h>
|
||||
|
||||
#include "netdevsim.h"
|
||||
|
||||
static int nsim_init(struct net_device *dev)
|
||||
{
|
||||
struct netdevsim *ns = netdev_priv(dev);
|
||||
int err;
|
||||
|
||||
ns->netdev = dev;
|
||||
ns->ddir = debugfs_create_dir(netdev_name(dev), nsim_ddir);
|
||||
|
||||
err = nsim_bpf_init(ns);
|
||||
if (err)
|
||||
goto err_debugfs_destroy;
|
||||
|
||||
return 0;
|
||||
|
||||
err_debugfs_destroy:
|
||||
debugfs_remove_recursive(ns->ddir);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void nsim_uninit(struct net_device *dev)
|
||||
{
|
||||
struct netdevsim *ns = netdev_priv(dev);
|
||||
|
||||
debugfs_remove_recursive(ns->ddir);
|
||||
nsim_bpf_uninit(ns);
|
||||
}
|
||||
|
||||
static netdev_tx_t nsim_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
struct netdevsim *ns = netdev_priv(dev);
|
||||
@@ -41,6 +70,19 @@ static void nsim_set_rx_mode(struct net_device *dev)
|
||||
{
|
||||
}
|
||||
|
||||
static int nsim_change_mtu(struct net_device *dev, int new_mtu)
|
||||
{
|
||||
struct netdevsim *ns = netdev_priv(dev);
|
||||
|
||||
if (ns->xdp_prog_mode == XDP_ATTACHED_DRV &&
|
||||
new_mtu > NSIM_XDP_MAX_MTU)
|
||||
return -EBUSY;
|
||||
|
||||
dev->mtu = new_mtu;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
nsim_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
|
||||
{
|
||||
@@ -54,12 +96,66 @@ nsim_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
|
||||
} while (u64_stats_fetch_retry(&ns->syncp, start));
|
||||
}
|
||||
|
||||
static int
|
||||
nsim_setup_tc_block_cb(enum tc_setup_type type, void *type_data, void *cb_priv)
|
||||
{
|
||||
return nsim_bpf_setup_tc_block_cb(type, type_data, cb_priv);
|
||||
}
|
||||
|
||||
static int
|
||||
nsim_setup_tc_block(struct net_device *dev, struct tc_block_offload *f)
|
||||
{
|
||||
struct netdevsim *ns = netdev_priv(dev);
|
||||
|
||||
if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
switch (f->command) {
|
||||
case TC_BLOCK_BIND:
|
||||
return tcf_block_cb_register(f->block, nsim_setup_tc_block_cb,
|
||||
ns, ns);
|
||||
case TC_BLOCK_UNBIND:
|
||||
tcf_block_cb_unregister(f->block, nsim_setup_tc_block_cb, ns);
|
||||
return 0;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
nsim_setup_tc(struct net_device *dev, enum tc_setup_type type, void *type_data)
|
||||
{
|
||||
switch (type) {
|
||||
case TC_SETUP_BLOCK:
|
||||
return nsim_setup_tc_block(dev, type_data);
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
nsim_set_features(struct net_device *dev, netdev_features_t features)
|
||||
{
|
||||
struct netdevsim *ns = netdev_priv(dev);
|
||||
|
||||
if ((dev->features & NETIF_F_HW_TC) > (features & NETIF_F_HW_TC))
|
||||
return nsim_bpf_disable_tc(ns);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct net_device_ops nsim_netdev_ops = {
|
||||
.ndo_init = nsim_init,
|
||||
.ndo_uninit = nsim_uninit,
|
||||
.ndo_start_xmit = nsim_start_xmit,
|
||||
.ndo_set_rx_mode = nsim_set_rx_mode,
|
||||
.ndo_set_mac_address = eth_mac_addr,
|
||||
.ndo_validate_addr = eth_validate_addr,
|
||||
.ndo_change_mtu = nsim_change_mtu,
|
||||
.ndo_get_stats64 = nsim_get_stats64,
|
||||
.ndo_setup_tc = nsim_setup_tc,
|
||||
.ndo_set_features = nsim_set_features,
|
||||
.ndo_bpf = nsim_bpf,
|
||||
};
|
||||
|
||||
static void nsim_setup(struct net_device *dev)
|
||||
@@ -80,6 +176,7 @@ static void nsim_setup(struct net_device *dev)
|
||||
NETIF_F_FRAGLIST |
|
||||
NETIF_F_HW_CSUM |
|
||||
NETIF_F_TSO;
|
||||
dev->hw_features |= NETIF_F_HW_TC;
|
||||
dev->max_mtu = ETH_MAX_MTU;
|
||||
}
|
||||
|
||||
@@ -102,14 +199,31 @@ static struct rtnl_link_ops nsim_link_ops __read_mostly = {
|
||||
.validate = nsim_validate,
|
||||
};
|
||||
|
||||
struct dentry *nsim_ddir;
|
||||
|
||||
static int __init nsim_module_init(void)
|
||||
{
|
||||
return rtnl_link_register(&nsim_link_ops);
|
||||
int err;
|
||||
|
||||
nsim_ddir = debugfs_create_dir(DRV_NAME, NULL);
|
||||
if (IS_ERR(nsim_ddir))
|
||||
return PTR_ERR(nsim_ddir);
|
||||
|
||||
err = rtnl_link_register(&nsim_link_ops);
|
||||
if (err)
|
||||
goto err_debugfs_destroy;
|
||||
|
||||
return 0;
|
||||
|
||||
err_debugfs_destroy:
|
||||
debugfs_remove_recursive(nsim_ddir);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __exit nsim_module_exit(void)
|
||||
{
|
||||
rtnl_link_unregister(&nsim_link_ops);
|
||||
debugfs_remove_recursive(nsim_ddir);
|
||||
}
|
||||
|
||||
module_init(nsim_module_init);
|
||||
|
Reference in New Issue
Block a user