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

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
...@@ -31,11 +31,57 @@ ...@@ -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) ...@@ -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,
}; };
...@@ -198,4 +198,9 @@ nfp_bpf_jit(struct bpf_prog *filter, void *prog, enum nfp_bpf_action_type act, ...@@ -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
...@@ -34,7 +34,10 @@ ...@@ -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; ...@@ -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 { ...@@ -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, ...@@ -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) ...@@ -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);
......
...@@ -868,6 +868,5 @@ static inline void nfp_net_debugfs_dir_clean(struct dentry **dir) ...@@ -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_ */
...@@ -64,10 +64,10 @@ ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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);
} }
...@@ -427,6 +427,7 @@ static void nfp_net_pf_clean_vnic(struct nfp_pf *pf, struct nfp_net *nn) ...@@ -427,6 +427,7 @@ static void nfp_net_pf_clean_vnic(struct nfp_pf *pf, struct nfp_net *nn)
nfp_devlink_port_unregister(nn->port); nfp_devlink_port_unregister(nn->port);
nfp_net_debugfs_dir_clean(&nn->debugfs_dir); nfp_net_debugfs_dir_clean(&nn->debugfs_dir);
nfp_net_clean(nn); nfp_net_clean(nn);
nfp_app_vnic_clean(pf->app, nn);
} }
static int static int
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment