Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bb45e51c authored by Jakub Kicinski's avatar Jakub Kicinski Committed by David S. Miller
Browse files

nfp: move bpf offload code to the BPF app



Move bulk of the eBPF offload code out of common vNIC code into
app-specific callbacks.

Signed-off-by: default avatarJakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d9ae7f2b
Loading
Loading
Loading
Loading
+84 −0
Original line number Original line Diff line number Diff line
@@ -31,11 +31,57 @@
 * SOFTWARE.
 * SOFTWARE.
 */
 */


#include <net/pkt_cls.h>

#include "../nfpcore/nfp_cpp.h"
#include "../nfpcore/nfp_cpp.h"
#include "../nfp_app.h"
#include "../nfp_app.h"
#include "../nfp_main.h"
#include "../nfp_main.h"
#include "../nfp_net.h"
#include "../nfp_net.h"
#include "../nfp_port.h"
#include "../nfp_port.h"
#include "main.h"

static bool nfp_net_ebpf_capable(struct nfp_net *nn)
{
	if (nn->cap & NFP_NET_CFG_CTRL_BPF &&
	    nn_readb(nn, NFP_NET_CFG_BPF_ABI) == NFP_NET_BPF_ABI)
		return true;
	return false;
}

static int
nfp_bpf_xdp_offload(struct nfp_app *app, struct nfp_net *nn,
		    struct bpf_prog *prog)
{
	struct tc_cls_bpf_offload cmd = {
		.prog = prog,
	};
	int ret;

	if (!nfp_net_ebpf_capable(nn))
		return -EINVAL;

	if (nn->dp.ctrl & NFP_NET_CFG_CTRL_BPF) {
		if (!nn->dp.bpf_offload_xdp)
			return prog ? -EBUSY : 0;
		cmd.command = prog ? TC_CLSBPF_REPLACE : TC_CLSBPF_DESTROY;
	} else {
		if (!prog)
			return 0;
		cmd.command = TC_CLSBPF_ADD;
	}

	ret = nfp_net_bpf_offload(nn, &cmd);
	/* Stop offload if replace not possible */
	if (ret && cmd.command == TC_CLSBPF_REPLACE)
		nfp_bpf_xdp_offload(app, nn, NULL);
	nn->dp.bpf_offload_xdp = prog && !ret;
	return ret;
}

static const char *nfp_bpf_extra_cap(struct nfp_app *app, struct nfp_net *nn)
{
	return nfp_net_ebpf_capable(nn) ? "BPF" : "";
}


static int
static int
nfp_bpf_vnic_init(struct nfp_app *app, struct nfp_net *nn, unsigned int id)
nfp_bpf_vnic_init(struct nfp_app *app, struct nfp_net *nn, unsigned int id)
@@ -51,9 +97,47 @@ nfp_bpf_vnic_init(struct nfp_app *app, struct nfp_net *nn, unsigned int id)
	return nfp_app_nic_vnic_init(app, nn, id);
	return nfp_app_nic_vnic_init(app, nn, id);
}
}


static void nfp_bpf_vnic_clean(struct nfp_app *app, struct nfp_net *nn)
{
	if (nn->dp.bpf_offload_xdp)
		nfp_bpf_xdp_offload(app, nn, NULL);
}

static int nfp_bpf_setup_tc(struct nfp_app *app, struct net_device *netdev,
			    u32 handle, __be16 proto, struct tc_to_netdev *tc)
{
	struct nfp_net *nn = netdev_priv(netdev);

	if (TC_H_MAJ(handle) != TC_H_MAJ(TC_H_INGRESS))
		return -EOPNOTSUPP;
	if (proto != htons(ETH_P_ALL))
		return -EOPNOTSUPP;

	if (tc->type == TC_SETUP_CLSBPF && nfp_net_ebpf_capable(nn)) {
		if (!nn->dp.bpf_offload_xdp)
			return nfp_net_bpf_offload(nn, tc->cls_bpf);
		else
			return -EBUSY;
	}

	return -EINVAL;
}

static bool nfp_bpf_tc_busy(struct nfp_app *app, struct nfp_net *nn)
{
	return nn->dp.ctrl & NFP_NET_CFG_CTRL_BPF;
}

const struct nfp_app_type app_bpf = {
const struct nfp_app_type app_bpf = {
	.id		= NFP_APP_BPF_NIC,
	.id		= NFP_APP_BPF_NIC,
	.name		= "ebpf",
	.name		= "ebpf",


	.extra_cap	= nfp_bpf_extra_cap,

	.vnic_init	= nfp_bpf_vnic_init,
	.vnic_init	= nfp_bpf_vnic_init,
	.vnic_clean	= nfp_bpf_vnic_clean,

	.setup_tc	= nfp_bpf_setup_tc,
	.tc_busy	= nfp_bpf_tc_busy,
	.xdp_offload	= nfp_bpf_xdp_offload,
};
};
+5 −0
Original line number Original line Diff line number Diff line
@@ -198,4 +198,9 @@ nfp_bpf_jit(struct bpf_prog *filter, void *prog, enum nfp_bpf_action_type act,


int nfp_prog_verify(struct nfp_prog *nfp_prog, struct bpf_prog *prog);
int nfp_prog_verify(struct nfp_prog *nfp_prog, struct bpf_prog *prog);


struct nfp_net;
struct tc_cls_bpf_offload;

int nfp_net_bpf_offload(struct nfp_net *nn, struct tc_cls_bpf_offload *cls_bpf);

#endif
#endif
+61 −0
Original line number Original line Diff line number Diff line
@@ -34,7 +34,10 @@
#ifndef _NFP_APP_H
#ifndef _NFP_APP_H
#define _NFP_APP_H 1
#define _NFP_APP_H 1


struct bpf_prog;
struct net_device;
struct pci_dev;
struct pci_dev;
struct tc_to_netdev;
struct nfp_app;
struct nfp_app;
struct nfp_cpp;
struct nfp_cpp;
struct nfp_pf;
struct nfp_pf;
@@ -55,7 +58,12 @@ extern const struct nfp_app_type app_bpf;
 *
 *
 * Callbacks
 * Callbacks
 * @init:	perform basic app checks
 * @init:	perform basic app checks
 * @extra_cap:	extra capabilities string
 * @vnic_init:	init vNICs (assign port types, etc.)
 * @vnic_init:	init vNICs (assign port types, etc.)
 * @vnic_clean:	clean up app's vNIC state
 * @setup_tc:	setup TC ndo
 * @tc_busy:	TC HW offload busy (rules loaded)
 * @xdp_offload:    offload an XDP program
 */
 */
struct nfp_app_type {
struct nfp_app_type {
	enum nfp_app_id id;
	enum nfp_app_id id;
@@ -63,8 +71,17 @@ struct nfp_app_type {


	int (*init)(struct nfp_app *app);
	int (*init)(struct nfp_app *app);


	const char *(*extra_cap)(struct nfp_app *app, struct nfp_net *nn);

	int (*vnic_init)(struct nfp_app *app, struct nfp_net *nn,
	int (*vnic_init)(struct nfp_app *app, struct nfp_net *nn,
			 unsigned int id);
			 unsigned int id);
	void (*vnic_clean)(struct nfp_app *app, struct nfp_net *nn);

	int (*setup_tc)(struct nfp_app *app, struct net_device *netdev,
			u32 handle, __be16 proto, struct tc_to_netdev *tc);
	bool (*tc_busy)(struct nfp_app *app, struct nfp_net *nn);
	int (*xdp_offload)(struct nfp_app *app, struct nfp_net *nn,
			   struct bpf_prog *prog);
};
};


/**
/**
@@ -95,6 +112,12 @@ static inline int nfp_app_vnic_init(struct nfp_app *app, struct nfp_net *nn,
	return app->type->vnic_init(app, nn, id);
	return app->type->vnic_init(app, nn, id);
}
}


static inline void nfp_app_vnic_clean(struct nfp_app *app, struct nfp_net *nn)
{
	if (app->type->vnic_clean)
		app->type->vnic_clean(app, nn);
}

static inline const char *nfp_app_name(struct nfp_app *app)
static inline const char *nfp_app_name(struct nfp_app *app)
{
{
	if (!app)
	if (!app)
@@ -102,6 +125,44 @@ static inline const char *nfp_app_name(struct nfp_app *app)
	return app->type->name;
	return app->type->name;
}
}


static inline const char *nfp_app_extra_cap(struct nfp_app *app,
					    struct nfp_net *nn)
{
	if (!app || !app->type->extra_cap)
		return "";
	return app->type->extra_cap(app, nn);
}

static inline bool nfp_app_has_tc(struct nfp_app *app)
{
	return app && app->type->setup_tc;
}

static inline bool nfp_app_tc_busy(struct nfp_app *app, struct nfp_net *nn)
{
	if (!app || !app->type->tc_busy)
		return false;
	return app->type->tc_busy(app, nn);
}

static inline int nfp_app_setup_tc(struct nfp_app *app,
				   struct net_device *netdev,
				   u32 handle, __be16 proto,
				   struct tc_to_netdev *tc)
{
	if (!app || !app->type->setup_tc)
		return -EOPNOTSUPP;
	return app->type->setup_tc(app, netdev, handle, proto, tc);
}

static inline int nfp_app_xdp_offload(struct nfp_app *app, struct nfp_net *nn,
				      struct bpf_prog *prog)
{
	if (!app || !app->type->xdp_offload)
		return -EOPNOTSUPP;
	return app->type->xdp_offload(app, nn, prog);
}

struct nfp_app *nfp_app_alloc(struct nfp_pf *pf, enum nfp_app_id id);
struct nfp_app *nfp_app_alloc(struct nfp_pf *pf, enum nfp_app_id id);
void nfp_app_free(struct nfp_app *app);
void nfp_app_free(struct nfp_app *app);


+0 −1
Original line number Original line Diff line number Diff line
@@ -868,6 +868,5 @@ static inline void nfp_net_debugfs_dir_clean(struct dentry **dir)
#endif /* CONFIG_NFP_DEBUG */
#endif /* CONFIG_NFP_DEBUG */


void nfp_net_filter_stats_timer(unsigned long data);
void nfp_net_filter_stats_timer(unsigned long data);
int nfp_net_bpf_offload(struct nfp_net *nn, struct tc_cls_bpf_offload *cls_bpf);


#endif /* _NFP_NET_H_ */
#endif /* _NFP_NET_H_ */
+8 −58
Original line number Original line Diff line number Diff line
@@ -64,10 +64,10 @@


#include <linux/ktime.h>
#include <linux/ktime.h>


#include <net/pkt_cls.h>
#include <net/vxlan.h>
#include <net/vxlan.h>


#include "nfpcore/nfp_nsp.h"
#include "nfpcore/nfp_nsp.h"
#include "nfp_app.h"
#include "nfp_net_ctrl.h"
#include "nfp_net_ctrl.h"
#include "nfp_net.h"
#include "nfp_net.h"
#include "nfp_port.h"
#include "nfp_port.h"
@@ -2681,33 +2681,13 @@ static void nfp_net_stat64(struct net_device *netdev,
	}
	}
}
}


static bool nfp_net_ebpf_capable(struct nfp_net *nn)
{
	if (nn->cap & NFP_NET_CFG_CTRL_BPF &&
	    nn_readb(nn, NFP_NET_CFG_BPF_ABI) == NFP_NET_BPF_ABI)
		return true;
	return false;
}

static int
static int
nfp_net_setup_tc(struct net_device *netdev, u32 handle, __be16 proto,
nfp_net_setup_tc(struct net_device *netdev, u32 handle, __be16 proto,
		 struct tc_to_netdev *tc)
		 struct tc_to_netdev *tc)
{
{
	struct nfp_net *nn = netdev_priv(netdev);
	struct nfp_net *nn = netdev_priv(netdev);


	if (TC_H_MAJ(handle) != TC_H_MAJ(TC_H_INGRESS))
	return nfp_app_setup_tc(nn->app, netdev, handle, proto, tc);
		return -EOPNOTSUPP;
	if (proto != htons(ETH_P_ALL))
		return -EOPNOTSUPP;

	if (tc->type == TC_SETUP_CLSBPF && nfp_net_ebpf_capable(nn)) {
		if (!nn->dp.bpf_offload_xdp)
			return nfp_net_bpf_offload(nn, tc->cls_bpf);
		else
			return -EBUSY;
	}

	return -EINVAL;
}
}


static int nfp_net_set_features(struct net_device *netdev,
static int nfp_net_set_features(struct net_device *netdev,
@@ -2765,7 +2745,7 @@ static int nfp_net_set_features(struct net_device *netdev,
			new_ctrl &= ~NFP_NET_CFG_CTRL_GATHER;
			new_ctrl &= ~NFP_NET_CFG_CTRL_GATHER;
	}
	}


	if (changed & NETIF_F_HW_TC && nn->dp.ctrl & NFP_NET_CFG_CTRL_BPF) {
	if (changed & NETIF_F_HW_TC && nfp_app_tc_busy(nn->app, nn)) {
		nn_err(nn, "Cannot disable HW TC offload while in use\n");
		nn_err(nn, "Cannot disable HW TC offload while in use\n");
		return -EBUSY;
		return -EBUSY;
	}
	}
@@ -2914,34 +2894,6 @@ static void nfp_net_del_vxlan_port(struct net_device *netdev,
		nfp_net_set_vxlan_port(nn, idx, 0);
		nfp_net_set_vxlan_port(nn, idx, 0);
}
}


static int nfp_net_xdp_offload(struct nfp_net *nn, struct bpf_prog *prog)
{
	struct tc_cls_bpf_offload cmd = {
		.prog = prog,
	};
	int ret;

	if (!nfp_net_ebpf_capable(nn))
		return -EINVAL;

	if (nn->dp.ctrl & NFP_NET_CFG_CTRL_BPF) {
		if (!nn->dp.bpf_offload_xdp)
			return prog ? -EBUSY : 0;
		cmd.command = prog ? TC_CLSBPF_REPLACE : TC_CLSBPF_DESTROY;
	} else {
		if (!prog)
			return 0;
		cmd.command = TC_CLSBPF_ADD;
	}

	ret = nfp_net_bpf_offload(nn, &cmd);
	/* Stop offload if replace not possible */
	if (ret && cmd.command == TC_CLSBPF_REPLACE)
		nfp_net_xdp_offload(nn, NULL);
	nn->dp.bpf_offload_xdp = prog && !ret;
	return ret;
}

static int nfp_net_xdp_setup(struct nfp_net *nn, struct netdev_xdp *xdp)
static int nfp_net_xdp_setup(struct nfp_net *nn, struct netdev_xdp *xdp)
{
{
	struct bpf_prog *old_prog = nn->dp.xdp_prog;
	struct bpf_prog *old_prog = nn->dp.xdp_prog;
@@ -2954,7 +2906,7 @@ static int nfp_net_xdp_setup(struct nfp_net *nn, struct netdev_xdp *xdp)
	if (prog && nn->dp.xdp_prog) {
	if (prog && nn->dp.xdp_prog) {
		prog = xchg(&nn->dp.xdp_prog, prog);
		prog = xchg(&nn->dp.xdp_prog, prog);
		bpf_prog_put(prog);
		bpf_prog_put(prog);
		nfp_net_xdp_offload(nn, nn->dp.xdp_prog);
		nfp_app_xdp_offload(nn->app, nn, nn->dp.xdp_prog);
		return 0;
		return 0;
	}
	}


@@ -2975,7 +2927,7 @@ static int nfp_net_xdp_setup(struct nfp_net *nn, struct netdev_xdp *xdp)
	if (old_prog)
	if (old_prog)
		bpf_prog_put(old_prog);
		bpf_prog_put(old_prog);


	nfp_net_xdp_offload(nn, nn->dp.xdp_prog);
	nfp_app_xdp_offload(nn->app, nn, nn->dp.xdp_prog);


	return 0;
	return 0;
}
}
@@ -3068,10 +3020,10 @@ void nfp_net_info(struct nfp_net *nn)
		nn->cap & NFP_NET_CFG_CTRL_IRQMOD   ? "IRQMOD "   : "",
		nn->cap & NFP_NET_CFG_CTRL_IRQMOD   ? "IRQMOD "   : "",
		nn->cap & NFP_NET_CFG_CTRL_VXLAN    ? "VXLAN "    : "",
		nn->cap & NFP_NET_CFG_CTRL_VXLAN    ? "VXLAN "    : "",
		nn->cap & NFP_NET_CFG_CTRL_NVGRE    ? "NVGRE "	  : "",
		nn->cap & NFP_NET_CFG_CTRL_NVGRE    ? "NVGRE "	  : "",
		nfp_net_ebpf_capable(nn)            ? "BPF "	  : "",
		nn->cap & NFP_NET_CFG_CTRL_CSUM_COMPLETE ?
		nn->cap & NFP_NET_CFG_CTRL_CSUM_COMPLETE ?
						      "RXCSUM_COMPLETE " : "",
						      "RXCSUM_COMPLETE " : "",
		nn->cap & NFP_NET_CFG_CTRL_LIVE_ADDR ? "LIVE_ADDR " : "");
		nn->cap & NFP_NET_CFG_CTRL_LIVE_ADDR ? "LIVE_ADDR " : "",
		nfp_app_extra_cap(nn->app, nn));
}
}


/**
/**
@@ -3316,7 +3268,7 @@ int nfp_net_init(struct nfp_net *nn)


	netdev->features = netdev->hw_features;
	netdev->features = netdev->hw_features;


	if (nfp_net_ebpf_capable(nn))
	if (nfp_app_has_tc(nn->app))
		netdev->hw_features |= NETIF_F_HW_TC;
		netdev->hw_features |= NETIF_F_HW_TC;


	/* Advertise but disable TSO by default. */
	/* Advertise but disable TSO by default. */
@@ -3373,6 +3325,4 @@ void nfp_net_clean(struct nfp_net *nn)


	if (nn->dp.xdp_prog)
	if (nn->dp.xdp_prog)
		bpf_prog_put(nn->dp.xdp_prog);
		bpf_prog_put(nn->dp.xdp_prog);
	if (nn->dp.bpf_offload_xdp)
		nfp_net_xdp_offload(nn, NULL);
}
}
Loading