Skip to content

Commit 7f0a838

Browse files
anakryikoAlexei Starovoitov
authored and
Alexei Starovoitov
committedJul 26, 2020
bpf, xdp: Maintain info on attached XDP BPF programs in net_device
Instead of delegating to drivers, maintain information about which BPF programs are attached in which XDP modes (generic/skb, driver, or hardware) locally in net_device. This effectively obsoletes XDP_QUERY_PROG command. Such re-organization simplifies existing code already. But it also allows to further add bpf_link-based XDP attachments without drivers having to know about any of this at all, which seems like a good setup. XDP_SETUP_PROG/XDP_SETUP_PROG_HW are just low-level commands to driver to install/uninstall active BPF program. All the higher-level concerns about prog/link interaction will be contained within generic driver-agnostic logic. All the XDP_QUERY_PROG calls to driver in dev_xdp_uninstall() were removed. It's not clear for me why dev_xdp_uninstall() were passing previous prog_flags when resetting installed programs. That seems unnecessary, plus most drivers don't populate prog_flags anyways. Having XDP_SETUP_PROG vs XDP_SETUP_PROG_HW should be enough of an indicator of what is required of driver to correctly reset active BPF program. dev_xdp_uninstall() is also generalized as an iteration over all three supported mode. Signed-off-by: Andrii Nakryiko <andriin@fb.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Link: https://lore.kernel.org/bpf/20200722064603.3350758-3-andriin@fb.com
1 parent 6cc7d1e commit 7f0a838

File tree

3 files changed

+105
-75
lines changed

3 files changed

+105
-75
lines changed
 

‎include/linux/netdevice.h

+15-2
Original file line numberDiff line numberDiff line change
@@ -889,6 +889,17 @@ struct netlink_ext_ack;
889889
struct xdp_umem;
890890
struct xdp_dev_bulk_queue;
891891

892+
enum bpf_xdp_mode {
893+
XDP_MODE_SKB = 0,
894+
XDP_MODE_DRV = 1,
895+
XDP_MODE_HW = 2,
896+
__MAX_XDP_MODE
897+
};
898+
899+
struct bpf_xdp_entity {
900+
struct bpf_prog *prog;
901+
};
902+
892903
struct netdev_bpf {
893904
enum bpf_netdev_command command;
894905
union {
@@ -2142,6 +2153,9 @@ struct net_device {
21422153
#endif
21432154
const struct udp_tunnel_nic_info *udp_tunnel_nic_info;
21442155
struct udp_tunnel_nic *udp_tunnel_nic;
2156+
2157+
/* protected by rtnl_lock */
2158+
struct bpf_xdp_entity xdp_state[__MAX_XDP_MODE];
21452159
};
21462160
#define to_net_dev(d) container_of(d, struct net_device, dev)
21472161

@@ -3817,8 +3831,7 @@ struct sk_buff *dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
38173831
typedef int (*bpf_op_t)(struct net_device *dev, struct netdev_bpf *bpf);
38183832
int dev_change_xdp_fd(struct net_device *dev, struct netlink_ext_ack *extack,
38193833
int fd, int expected_fd, u32 flags);
3820-
u32 __dev_xdp_query(struct net_device *dev, bpf_op_t xdp_op,
3821-
enum bpf_netdev_command cmd);
3834+
u32 dev_xdp_prog_id(struct net_device *dev, enum bpf_xdp_mode mode);
38223835
int xdp_umem_query(struct net_device *dev, u16 queue_id);
38233836

38243837
int __dev_forward_skb(struct net_device *dev, struct sk_buff *skb);

‎net/core/dev.c

+88-70
Original file line numberDiff line numberDiff line change
@@ -8716,84 +8716,103 @@ int dev_change_proto_down_generic(struct net_device *dev, bool proto_down)
87168716
}
87178717
EXPORT_SYMBOL(dev_change_proto_down_generic);
87188718

8719-
u32 __dev_xdp_query(struct net_device *dev, bpf_op_t bpf_op,
8720-
enum bpf_netdev_command cmd)
8719+
static enum bpf_xdp_mode dev_xdp_mode(u32 flags)
87218720
{
8722-
struct netdev_bpf xdp;
8721+
if (flags & XDP_FLAGS_HW_MODE)
8722+
return XDP_MODE_HW;
8723+
if (flags & XDP_FLAGS_DRV_MODE)
8724+
return XDP_MODE_DRV;
8725+
return XDP_MODE_SKB;
8726+
}
87238727

8724-
if (!bpf_op)
8725-
return 0;
8728+
static bpf_op_t dev_xdp_bpf_op(struct net_device *dev, enum bpf_xdp_mode mode)
8729+
{
8730+
switch (mode) {
8731+
case XDP_MODE_SKB:
8732+
return generic_xdp_install;
8733+
case XDP_MODE_DRV:
8734+
case XDP_MODE_HW:
8735+
return dev->netdev_ops->ndo_bpf;
8736+
default:
8737+
return NULL;
8738+
};
8739+
}
87268740

8727-
memset(&xdp, 0, sizeof(xdp));
8728-
xdp.command = cmd;
8741+
static struct bpf_prog *dev_xdp_prog(struct net_device *dev,
8742+
enum bpf_xdp_mode mode)
8743+
{
8744+
return dev->xdp_state[mode].prog;
8745+
}
8746+
8747+
u32 dev_xdp_prog_id(struct net_device *dev, enum bpf_xdp_mode mode)
8748+
{
8749+
struct bpf_prog *prog = dev_xdp_prog(dev, mode);
87298750

8730-
/* Query must always succeed. */
8731-
WARN_ON(bpf_op(dev, &xdp) < 0 && cmd == XDP_QUERY_PROG);
8751+
return prog ? prog->aux->id : 0;
8752+
}
87328753

8733-
return xdp.prog_id;
8754+
static void dev_xdp_set_prog(struct net_device *dev, enum bpf_xdp_mode mode,
8755+
struct bpf_prog *prog)
8756+
{
8757+
dev->xdp_state[mode].prog = prog;
87348758
}
87358759

8736-
static int dev_xdp_install(struct net_device *dev, bpf_op_t bpf_op,
8737-
struct netlink_ext_ack *extack, u32 flags,
8738-
struct bpf_prog *prog)
8760+
static int dev_xdp_install(struct net_device *dev, enum bpf_xdp_mode mode,
8761+
bpf_op_t bpf_op, struct netlink_ext_ack *extack,
8762+
u32 flags, struct bpf_prog *prog)
87398763
{
8740-
bool non_hw = !(flags & XDP_FLAGS_HW_MODE);
8741-
struct bpf_prog *prev_prog = NULL;
87428764
struct netdev_bpf xdp;
87438765
int err;
87448766

8745-
if (non_hw) {
8746-
prev_prog = bpf_prog_by_id(__dev_xdp_query(dev, bpf_op,
8747-
XDP_QUERY_PROG));
8748-
if (IS_ERR(prev_prog))
8749-
prev_prog = NULL;
8750-
}
8751-
87528767
memset(&xdp, 0, sizeof(xdp));
8753-
if (flags & XDP_FLAGS_HW_MODE)
8754-
xdp.command = XDP_SETUP_PROG_HW;
8755-
else
8756-
xdp.command = XDP_SETUP_PROG;
8768+
xdp.command = mode == XDP_MODE_HW ? XDP_SETUP_PROG_HW : XDP_SETUP_PROG;
87578769
xdp.extack = extack;
87588770
xdp.flags = flags;
87598771
xdp.prog = prog;
87608772

8773+
/* Drivers assume refcnt is already incremented (i.e, prog pointer is
8774+
* "moved" into driver), so they don't increment it on their own, but
8775+
* they do decrement refcnt when program is detached or replaced.
8776+
* Given net_device also owns link/prog, we need to bump refcnt here
8777+
* to prevent drivers from underflowing it.
8778+
*/
8779+
if (prog)
8780+
bpf_prog_inc(prog);
87618781
err = bpf_op(dev, &xdp);
8762-
if (!err && non_hw)
8763-
bpf_prog_change_xdp(prev_prog, prog);
8782+
if (err) {
8783+
if (prog)
8784+
bpf_prog_put(prog);
8785+
return err;
8786+
}
87648787

8765-
if (prev_prog)
8766-
bpf_prog_put(prev_prog);
8788+
if (mode != XDP_MODE_HW)
8789+
bpf_prog_change_xdp(dev_xdp_prog(dev, mode), prog);
87678790

8768-
return err;
8791+
return 0;
87698792
}
87708793

87718794
static void dev_xdp_uninstall(struct net_device *dev)
87728795
{
8773-
struct netdev_bpf xdp;
8774-
bpf_op_t ndo_bpf;
8796+
struct bpf_prog *prog;
8797+
enum bpf_xdp_mode mode;
8798+
bpf_op_t bpf_op;
87758799

8776-
/* Remove generic XDP */
8777-
WARN_ON(dev_xdp_install(dev, generic_xdp_install, NULL, 0, NULL));
8800+
ASSERT_RTNL();
87788801

8779-
/* Remove from the driver */
8780-
ndo_bpf = dev->netdev_ops->ndo_bpf;
8781-
if (!ndo_bpf)
8782-
return;
8802+
for (mode = XDP_MODE_SKB; mode < __MAX_XDP_MODE; mode++) {
8803+
prog = dev_xdp_prog(dev, mode);
8804+
if (!prog)
8805+
continue;
87838806

8784-
memset(&xdp, 0, sizeof(xdp));
8785-
xdp.command = XDP_QUERY_PROG;
8786-
WARN_ON(ndo_bpf(dev, &xdp));
8787-
if (xdp.prog_id)
8788-
WARN_ON(dev_xdp_install(dev, ndo_bpf, NULL, xdp.prog_flags,
8789-
NULL));
8807+
bpf_op = dev_xdp_bpf_op(dev, mode);
8808+
if (!bpf_op)
8809+
continue;
87908810

8791-
/* Remove HW offload */
8792-
memset(&xdp, 0, sizeof(xdp));
8793-
xdp.command = XDP_QUERY_PROG_HW;
8794-
if (!ndo_bpf(dev, &xdp) && xdp.prog_id)
8795-
WARN_ON(dev_xdp_install(dev, ndo_bpf, NULL, xdp.prog_flags,
8796-
NULL));
8811+
WARN_ON(dev_xdp_install(dev, mode, bpf_op, NULL, 0, NULL));
8812+
8813+
bpf_prog_put(prog);
8814+
dev_xdp_set_prog(dev, mode, NULL);
8815+
}
87978816
}
87988817

87998818
/**
@@ -8810,29 +8829,22 @@ int dev_change_xdp_fd(struct net_device *dev, struct netlink_ext_ack *extack,
88108829
int fd, int expected_fd, u32 flags)
88118830
{
88128831
const struct net_device_ops *ops = dev->netdev_ops;
8813-
enum bpf_netdev_command query;
8832+
enum bpf_xdp_mode mode = dev_xdp_mode(flags);
8833+
bool offload = mode == XDP_MODE_HW;
88148834
u32 prog_id, expected_id = 0;
8815-
bpf_op_t bpf_op, bpf_chk;
88168835
struct bpf_prog *prog;
8817-
bool offload;
8836+
bpf_op_t bpf_op;
88188837
int err;
88198838

88208839
ASSERT_RTNL();
88218840

8822-
offload = flags & XDP_FLAGS_HW_MODE;
8823-
query = offload ? XDP_QUERY_PROG_HW : XDP_QUERY_PROG;
8824-
8825-
bpf_op = bpf_chk = ops->ndo_bpf;
8826-
if (!bpf_op && (flags & (XDP_FLAGS_DRV_MODE | XDP_FLAGS_HW_MODE))) {
8841+
bpf_op = dev_xdp_bpf_op(dev, mode);
8842+
if (!bpf_op) {
88278843
NL_SET_ERR_MSG(extack, "underlying driver does not support XDP in native mode");
88288844
return -EOPNOTSUPP;
88298845
}
8830-
if (!bpf_op || (flags & XDP_FLAGS_SKB_MODE))
8831-
bpf_op = generic_xdp_install;
8832-
if (bpf_op == bpf_chk)
8833-
bpf_chk = generic_xdp_install;
88348846

8835-
prog_id = __dev_xdp_query(dev, bpf_op, query);
8847+
prog_id = dev_xdp_prog_id(dev, mode);
88368848
if (flags & XDP_FLAGS_REPLACE) {
88378849
if (expected_fd >= 0) {
88388850
prog = bpf_prog_get_type_dev(expected_fd,
@@ -8850,8 +8862,11 @@ int dev_change_xdp_fd(struct net_device *dev, struct netlink_ext_ack *extack,
88508862
}
88518863
}
88528864
if (fd >= 0) {
8853-
if (!offload && __dev_xdp_query(dev, bpf_chk, XDP_QUERY_PROG)) {
8854-
NL_SET_ERR_MSG(extack, "native and generic XDP can't be active at the same time");
8865+
enum bpf_xdp_mode other_mode = mode == XDP_MODE_SKB
8866+
? XDP_MODE_DRV : XDP_MODE_SKB;
8867+
8868+
if (!offload && dev_xdp_prog_id(dev, other_mode)) {
8869+
NL_SET_ERR_MSG(extack, "Native and generic XDP can't be active at the same time");
88558870
return -EEXIST;
88568871
}
88578872

@@ -8866,7 +8881,7 @@ int dev_change_xdp_fd(struct net_device *dev, struct netlink_ext_ack *extack,
88668881
return PTR_ERR(prog);
88678882

88688883
if (!offload && bpf_prog_is_dev_bound(prog->aux)) {
8869-
NL_SET_ERR_MSG(extack, "using device-bound program without HW_MODE flag is not supported");
8884+
NL_SET_ERR_MSG(extack, "Using device-bound program without HW_MODE flag is not supported");
88708885
bpf_prog_put(prog);
88718886
return -EINVAL;
88728887
}
@@ -8895,11 +8910,14 @@ int dev_change_xdp_fd(struct net_device *dev, struct netlink_ext_ack *extack,
88958910
prog = NULL;
88968911
}
88978912

8898-
err = dev_xdp_install(dev, bpf_op, extack, flags, prog);
8899-
if (err < 0 && prog)
8913+
err = dev_xdp_install(dev, mode, bpf_op, extack, flags, prog);
8914+
if (err < 0 && prog) {
89008915
bpf_prog_put(prog);
8916+
return err;
8917+
}
8918+
dev_xdp_set_prog(dev, mode, prog);
89018919

8902-
return err;
8920+
return 0;
89038921
}
89048922

89058923
/**

‎net/core/rtnetlink.c

+2-3
Original file line numberDiff line numberDiff line change
@@ -1416,13 +1416,12 @@ static u32 rtnl_xdp_prog_skb(struct net_device *dev)
14161416

14171417
static u32 rtnl_xdp_prog_drv(struct net_device *dev)
14181418
{
1419-
return __dev_xdp_query(dev, dev->netdev_ops->ndo_bpf, XDP_QUERY_PROG);
1419+
return dev_xdp_prog_id(dev, XDP_MODE_DRV);
14201420
}
14211421

14221422
static u32 rtnl_xdp_prog_hw(struct net_device *dev)
14231423
{
1424-
return __dev_xdp_query(dev, dev->netdev_ops->ndo_bpf,
1425-
XDP_QUERY_PROG_HW);
1424+
return dev_xdp_prog_id(dev, XDP_MODE_HW);
14261425
}
14271426

14281427
static int rtnl_xdp_report_one(struct sk_buff *skb, struct net_device *dev,

0 commit comments

Comments
 (0)
Please sign in to comment.