Skip to content

Commit a25717d

Browse files
Jakub Kicinskiborkmann
authored andcommitted
xdp: support simultaneous driver and hw XDP attachment
Split the query of HW-attached program from the software one. Introduce new .ndo_bpf command to query HW-attached program. This will allow drivers to install different programs in HW and SW at the same time. Netlink can now also carry multiple programs on dump (in which case mode will be set to XDP_ATTACHED_MULTI and user has to check per-attachment point attributes, IFLA_XDP_PROG_ID will not be present). We reuse IFLA_XDP_PROG_ID skb space for second mode, so rtnl_xdp_size() doesn't need to be updated. Note that the installation side is still not there, since all drivers currently reject installing more than one program at the time. Signed-off-by: Jakub Kicinski <[email protected]> Reviewed-by: Quentin Monnet <[email protected]> Signed-off-by: Daniel Borkmann <[email protected]>
1 parent 0529662 commit a25717d

File tree

6 files changed

+96
-62
lines changed

6 files changed

+96
-62
lines changed

drivers/net/ethernet/netronome/nfp/nfp_net_common.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3453,6 +3453,12 @@ static int nfp_net_xdp(struct net_device *netdev, struct netdev_bpf *xdp)
34533453
case XDP_SETUP_PROG_HW:
34543454
return nfp_net_xdp_setup(nn, xdp);
34553455
case XDP_QUERY_PROG:
3456+
if (nn->dp.bpf_offload_xdp)
3457+
return 0;
3458+
return xdp_attachment_query(&nn->xdp, xdp);
3459+
case XDP_QUERY_PROG_HW:
3460+
if (!nn->dp.bpf_offload_xdp)
3461+
return 0;
34563462
return xdp_attachment_query(&nn->xdp, xdp);
34573463
default:
34583464
return nfp_app_bpf(nn->app, nn, xdp);

drivers/net/netdevsim/bpf.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,12 @@ int nsim_bpf(struct net_device *dev, struct netdev_bpf *bpf)
561561
nsim_bpf_destroy_prog(bpf->offload.prog);
562562
return 0;
563563
case XDP_QUERY_PROG:
564+
if (ns->xdp_prog_mode != XDP_ATTACHED_DRV)
565+
return 0;
566+
return xdp_attachment_query(&ns->xdp, bpf);
567+
case XDP_QUERY_PROG_HW:
568+
if (ns->xdp_prog_mode != XDP_ATTACHED_HW)
569+
return 0;
564570
return xdp_attachment_query(&ns->xdp, bpf);
565571
case XDP_SETUP_PROG:
566572
err = nsim_setup_prog_checks(ns, bpf);

include/linux/netdevice.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -820,6 +820,7 @@ enum bpf_netdev_command {
820820
XDP_SETUP_PROG,
821821
XDP_SETUP_PROG_HW,
822822
XDP_QUERY_PROG,
823+
XDP_QUERY_PROG_HW,
823824
/* BPF program for offload callbacks, invoked at program load time. */
824825
BPF_OFFLOAD_VERIFIER_PREP,
825826
BPF_OFFLOAD_TRANSLATE,
@@ -843,7 +844,7 @@ struct netdev_bpf {
843844
struct bpf_prog *prog;
844845
struct netlink_ext_ack *extack;
845846
};
846-
/* XDP_QUERY_PROG */
847+
/* XDP_QUERY_PROG, XDP_QUERY_PROG_HW */
847848
struct {
848849
u32 prog_id;
849850
/* flags with which program was installed */
@@ -3533,8 +3534,8 @@ struct sk_buff *dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
35333534
typedef int (*bpf_op_t)(struct net_device *dev, struct netdev_bpf *bpf);
35343535
int dev_change_xdp_fd(struct net_device *dev, struct netlink_ext_ack *extack,
35353536
int fd, u32 flags);
3536-
void __dev_xdp_query(struct net_device *dev, bpf_op_t xdp_op,
3537-
struct netdev_bpf *xdp);
3537+
u32 __dev_xdp_query(struct net_device *dev, bpf_op_t xdp_op,
3538+
enum bpf_netdev_command cmd);
35383539

35393540
int __dev_forward_skb(struct net_device *dev, struct sk_buff *skb);
35403541
int dev_forward_skb(struct net_device *dev, struct sk_buff *skb);

include/uapi/linux/if_link.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -920,6 +920,7 @@ enum {
920920
XDP_ATTACHED_DRV,
921921
XDP_ATTACHED_SKB,
922922
XDP_ATTACHED_HW,
923+
XDP_ATTACHED_MULTI,
923924
};
924925

925926
enum {

net/core/dev.c

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7582,21 +7582,19 @@ int dev_change_proto_down(struct net_device *dev, bool proto_down)
75827582
}
75837583
EXPORT_SYMBOL(dev_change_proto_down);
75847584

7585-
void __dev_xdp_query(struct net_device *dev, bpf_op_t bpf_op,
7586-
struct netdev_bpf *xdp)
7585+
u32 __dev_xdp_query(struct net_device *dev, bpf_op_t bpf_op,
7586+
enum bpf_netdev_command cmd)
75877587
{
7588-
memset(xdp, 0, sizeof(*xdp));
7589-
xdp->command = XDP_QUERY_PROG;
7588+
struct netdev_bpf xdp;
75907589

7591-
/* Query must always succeed. */
7592-
WARN_ON(bpf_op(dev, xdp) < 0);
7593-
}
7590+
if (!bpf_op)
7591+
return 0;
75947592

7595-
static bool __dev_xdp_attached(struct net_device *dev, bpf_op_t bpf_op)
7596-
{
7597-
struct netdev_bpf xdp;
7593+
memset(&xdp, 0, sizeof(xdp));
7594+
xdp.command = cmd;
75987595

7599-
__dev_xdp_query(dev, bpf_op, &xdp);
7596+
/* Query must always succeed. */
7597+
WARN_ON(bpf_op(dev, &xdp) < 0 && cmd == XDP_QUERY_PROG);
76007598

76017599
return xdp.prog_id;
76027600
}
@@ -7632,12 +7630,19 @@ static void dev_xdp_uninstall(struct net_device *dev)
76327630
if (!ndo_bpf)
76337631
return;
76347632

7635-
__dev_xdp_query(dev, ndo_bpf, &xdp);
7636-
if (!xdp.prog_id)
7637-
return;
7633+
memset(&xdp, 0, sizeof(xdp));
7634+
xdp.command = XDP_QUERY_PROG;
7635+
WARN_ON(ndo_bpf(dev, &xdp));
7636+
if (xdp.prog_id)
7637+
WARN_ON(dev_xdp_install(dev, ndo_bpf, NULL, xdp.prog_flags,
7638+
NULL));
76387639

7639-
/* Program removal should always succeed */
7640-
WARN_ON(dev_xdp_install(dev, ndo_bpf, NULL, xdp.prog_flags, NULL));
7640+
/* Remove HW offload */
7641+
memset(&xdp, 0, sizeof(xdp));
7642+
xdp.command = XDP_QUERY_PROG_HW;
7643+
if (!ndo_bpf(dev, &xdp) && xdp.prog_id)
7644+
WARN_ON(dev_xdp_install(dev, ndo_bpf, NULL, xdp.prog_flags,
7645+
NULL));
76417646
}
76427647

76437648
/**
@@ -7653,12 +7658,15 @@ int dev_change_xdp_fd(struct net_device *dev, struct netlink_ext_ack *extack,
76537658
int fd, u32 flags)
76547659
{
76557660
const struct net_device_ops *ops = dev->netdev_ops;
7661+
enum bpf_netdev_command query;
76567662
struct bpf_prog *prog = NULL;
76577663
bpf_op_t bpf_op, bpf_chk;
76587664
int err;
76597665

76607666
ASSERT_RTNL();
76617667

7668+
query = flags & XDP_FLAGS_HW_MODE ? XDP_QUERY_PROG_HW : XDP_QUERY_PROG;
7669+
76627670
bpf_op = bpf_chk = ops->ndo_bpf;
76637671
if (!bpf_op && (flags & (XDP_FLAGS_DRV_MODE | XDP_FLAGS_HW_MODE)))
76647672
return -EOPNOTSUPP;
@@ -7668,10 +7676,11 @@ int dev_change_xdp_fd(struct net_device *dev, struct netlink_ext_ack *extack,
76687676
bpf_chk = generic_xdp_install;
76697677

76707678
if (fd >= 0) {
7671-
if (bpf_chk && __dev_xdp_attached(dev, bpf_chk))
7679+
if (__dev_xdp_query(dev, bpf_chk, XDP_QUERY_PROG) ||
7680+
__dev_xdp_query(dev, bpf_chk, XDP_QUERY_PROG_HW))
76727681
return -EEXIST;
76737682
if ((flags & XDP_FLAGS_UPDATE_IF_NOEXIST) &&
7674-
__dev_xdp_attached(dev, bpf_op))
7683+
__dev_xdp_query(dev, bpf_op, query))
76757684
return -EBUSY;
76767685

76777686
prog = bpf_prog_get_type_dev(fd, BPF_PROG_TYPE_XDP,

net/core/rtnetlink.c

Lines changed: 52 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -964,7 +964,7 @@ static size_t rtnl_xdp_size(void)
964964
{
965965
size_t xdp_size = nla_total_size(0) + /* nest IFLA_XDP */
966966
nla_total_size(1) + /* XDP_ATTACHED */
967-
nla_total_size(4) + /* XDP_PROG_ID */
967+
nla_total_size(4) + /* XDP_PROG_ID (or 1st mode) */
968968
nla_total_size(4); /* XDP_<mode>_PROG_ID */
969969

970970
return xdp_size;
@@ -1354,73 +1354,84 @@ static int rtnl_fill_link_ifmap(struct sk_buff *skb, struct net_device *dev)
13541354
return 0;
13551355
}
13561356

1357-
static u8 rtnl_xdp_attached_mode(struct net_device *dev, u32 *prog_id)
1357+
static u32 rtnl_xdp_prog_skb(struct net_device *dev)
13581358
{
1359-
const struct net_device_ops *ops = dev->netdev_ops;
13601359
const struct bpf_prog *generic_xdp_prog;
1361-
struct netdev_bpf xdp;
13621360

13631361
ASSERT_RTNL();
13641362

1365-
*prog_id = 0;
13661363
generic_xdp_prog = rtnl_dereference(dev->xdp_prog);
1367-
if (generic_xdp_prog) {
1368-
*prog_id = generic_xdp_prog->aux->id;
1369-
return XDP_ATTACHED_SKB;
1370-
}
1371-
if (!ops->ndo_bpf)
1372-
return XDP_ATTACHED_NONE;
1364+
if (!generic_xdp_prog)
1365+
return 0;
1366+
return generic_xdp_prog->aux->id;
1367+
}
1368+
1369+
static u32 rtnl_xdp_prog_drv(struct net_device *dev)
1370+
{
1371+
return __dev_xdp_query(dev, dev->netdev_ops->ndo_bpf, XDP_QUERY_PROG);
1372+
}
1373+
1374+
static u32 rtnl_xdp_prog_hw(struct net_device *dev)
1375+
{
1376+
return __dev_xdp_query(dev, dev->netdev_ops->ndo_bpf,
1377+
XDP_QUERY_PROG_HW);
1378+
}
1379+
1380+
static int rtnl_xdp_report_one(struct sk_buff *skb, struct net_device *dev,
1381+
u32 *prog_id, u8 *mode, u8 tgt_mode, u32 attr,
1382+
u32 (*get_prog_id)(struct net_device *dev))
1383+
{
1384+
u32 curr_id;
1385+
int err;
1386+
1387+
curr_id = get_prog_id(dev);
1388+
if (!curr_id)
1389+
return 0;
1390+
1391+
*prog_id = curr_id;
1392+
err = nla_put_u32(skb, attr, curr_id);
1393+
if (err)
1394+
return err;
13731395

1374-
__dev_xdp_query(dev, ops->ndo_bpf, &xdp);
1375-
if (!xdp.prog_id)
1376-
return XDP_ATTACHED_NONE;
1396+
if (*mode != XDP_ATTACHED_NONE)
1397+
*mode = XDP_ATTACHED_MULTI;
1398+
else
1399+
*mode = tgt_mode;
13771400

1378-
*prog_id = xdp.prog_id;
1379-
if (xdp.prog_flags & XDP_FLAGS_HW_MODE)
1380-
return XDP_ATTACHED_HW;
1381-
return XDP_ATTACHED_DRV;
1401+
return 0;
13821402
}
13831403

13841404
static int rtnl_xdp_fill(struct sk_buff *skb, struct net_device *dev)
13851405
{
1386-
u32 prog_attr, prog_id;
13871406
struct nlattr *xdp;
1407+
u32 prog_id;
13881408
int err;
13891409
u8 mode;
13901410

13911411
xdp = nla_nest_start(skb, IFLA_XDP);
13921412
if (!xdp)
13931413
return -EMSGSIZE;
13941414

1395-
mode = rtnl_xdp_attached_mode(dev, &prog_id);
1415+
prog_id = 0;
1416+
mode = XDP_ATTACHED_NONE;
1417+
if (rtnl_xdp_report_one(skb, dev, &prog_id, &mode, XDP_ATTACHED_SKB,
1418+
IFLA_XDP_SKB_PROG_ID, rtnl_xdp_prog_skb))
1419+
goto err_cancel;
1420+
if (rtnl_xdp_report_one(skb, dev, &prog_id, &mode, XDP_ATTACHED_DRV,
1421+
IFLA_XDP_DRV_PROG_ID, rtnl_xdp_prog_drv))
1422+
goto err_cancel;
1423+
if (rtnl_xdp_report_one(skb, dev, &prog_id, &mode, XDP_ATTACHED_HW,
1424+
IFLA_XDP_HW_PROG_ID, rtnl_xdp_prog_hw))
1425+
goto err_cancel;
1426+
13961427
err = nla_put_u8(skb, IFLA_XDP_ATTACHED, mode);
13971428
if (err)
13981429
goto err_cancel;
13991430

1400-
if (prog_id) {
1431+
if (prog_id && mode != XDP_ATTACHED_MULTI) {
14011432
err = nla_put_u32(skb, IFLA_XDP_PROG_ID, prog_id);
14021433
if (err)
14031434
goto err_cancel;
1404-
1405-
switch (mode) {
1406-
case XDP_ATTACHED_DRV:
1407-
prog_attr = IFLA_XDP_DRV_PROG_ID;
1408-
break;
1409-
case XDP_ATTACHED_SKB:
1410-
prog_attr = IFLA_XDP_SKB_PROG_ID;
1411-
break;
1412-
case XDP_ATTACHED_HW:
1413-
prog_attr = IFLA_XDP_HW_PROG_ID;
1414-
break;
1415-
case XDP_ATTACHED_NONE:
1416-
default:
1417-
err = -EINVAL;
1418-
goto err_cancel;
1419-
}
1420-
1421-
err = nla_put_u32(skb, prog_attr, prog_id);
1422-
if (err)
1423-
goto err_cancel;
14241435
}
14251436

14261437
nla_nest_end(skb, xdp);

0 commit comments

Comments
 (0)