Skip to content

Commit

Permalink
Merge branch 'generic-xdp-followups'
Browse files Browse the repository at this point in the history
Daniel Borkmann says:

====================
Two generic xdp related follow-ups

Two follow-ups for the generic XDP API, would be great if
both could still be considered, since the XDP API is not
frozen yet. For details please see individual patches.

v1 -> v2:
  - Implemented feedback from Jakub Kicinski (reusing
    attribute on dump), thanks!
  - Rest as is.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed May 12, 2017
2 parents 0a5539f + d67b9cd commit 4e3c60e
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 48 deletions.
8 changes: 6 additions & 2 deletions include/linux/netdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -3296,11 +3296,15 @@ int dev_get_phys_port_id(struct net_device *dev,
int dev_get_phys_port_name(struct net_device *dev,
char *name, size_t len);
int dev_change_proto_down(struct net_device *dev, bool proto_down);
int dev_change_xdp_fd(struct net_device *dev, struct netlink_ext_ack *extack,
int fd, u32 flags);
struct sk_buff *validate_xmit_skb_list(struct sk_buff *skb, struct net_device *dev);
struct sk_buff *dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
struct netdev_queue *txq, int *ret);

typedef int (*xdp_op_t)(struct net_device *dev, struct netdev_xdp *xdp);
int dev_change_xdp_fd(struct net_device *dev, struct netlink_ext_ack *extack,
int fd, u32 flags);
bool __dev_xdp_attached(struct net_device *dev, xdp_op_t xdp_op);

int __dev_forward_skb(struct net_device *dev, struct sk_buff *skb);
int dev_forward_skb(struct net_device *dev, struct sk_buff *skb);
bool is_skb_forwardable(const struct net_device *dev,
Expand Down
13 changes: 11 additions & 2 deletions include/uapi/linux/if_link.h
Original file line number Diff line number Diff line change
Expand Up @@ -888,9 +888,18 @@ enum {
/* XDP section */

#define XDP_FLAGS_UPDATE_IF_NOEXIST (1U << 0)
#define XDP_FLAGS_SKB_MODE (2U << 0)
#define XDP_FLAGS_SKB_MODE (1U << 1)
#define XDP_FLAGS_DRV_MODE (1U << 2)
#define XDP_FLAGS_MASK (XDP_FLAGS_UPDATE_IF_NOEXIST | \
XDP_FLAGS_SKB_MODE)
XDP_FLAGS_SKB_MODE | \
XDP_FLAGS_DRV_MODE)

/* These are stored into IFLA_XDP_ATTACHED on dump. */
enum {
XDP_ATTACHED_NONE = 0,
XDP_ATTACHED_DRV,
XDP_ATTACHED_SKB,
};

enum {
IFLA_XDP_UNSPEC,
Expand Down
57 changes: 38 additions & 19 deletions net/core/dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -6852,6 +6852,32 @@ int dev_change_proto_down(struct net_device *dev, bool proto_down)
}
EXPORT_SYMBOL(dev_change_proto_down);

bool __dev_xdp_attached(struct net_device *dev, xdp_op_t xdp_op)
{
struct netdev_xdp xdp;

memset(&xdp, 0, sizeof(xdp));
xdp.command = XDP_QUERY_PROG;

/* Query must always succeed. */
WARN_ON(xdp_op(dev, &xdp) < 0);
return xdp.prog_attached;
}

static int dev_xdp_install(struct net_device *dev, xdp_op_t xdp_op,
struct netlink_ext_ack *extack,
struct bpf_prog *prog)
{
struct netdev_xdp xdp;

memset(&xdp, 0, sizeof(xdp));
xdp.command = XDP_SETUP_PROG;
xdp.extack = extack;
xdp.prog = prog;

return xdp_op(dev, &xdp);
}

/**
* dev_change_xdp_fd - set or clear a bpf program for a device rx path
* @dev: device
Expand All @@ -6864,41 +6890,34 @@ EXPORT_SYMBOL(dev_change_proto_down);
int dev_change_xdp_fd(struct net_device *dev, struct netlink_ext_ack *extack,
int fd, u32 flags)
{
int (*xdp_op)(struct net_device *dev, struct netdev_xdp *xdp);
const struct net_device_ops *ops = dev->netdev_ops;
struct bpf_prog *prog = NULL;
struct netdev_xdp xdp;
xdp_op_t xdp_op, xdp_chk;
int err;

ASSERT_RTNL();

xdp_op = ops->ndo_xdp;
xdp_op = xdp_chk = ops->ndo_xdp;
if (!xdp_op && (flags & XDP_FLAGS_DRV_MODE))
return -EOPNOTSUPP;
if (!xdp_op || (flags & XDP_FLAGS_SKB_MODE))
xdp_op = generic_xdp_install;
if (xdp_op == xdp_chk)
xdp_chk = generic_xdp_install;

if (fd >= 0) {
if (flags & XDP_FLAGS_UPDATE_IF_NOEXIST) {
memset(&xdp, 0, sizeof(xdp));
xdp.command = XDP_QUERY_PROG;

err = xdp_op(dev, &xdp);
if (err < 0)
return err;
if (xdp.prog_attached)
return -EBUSY;
}
if (xdp_chk && __dev_xdp_attached(dev, xdp_chk))
return -EEXIST;
if ((flags & XDP_FLAGS_UPDATE_IF_NOEXIST) &&
__dev_xdp_attached(dev, xdp_op))
return -EBUSY;

prog = bpf_prog_get_type(fd, BPF_PROG_TYPE_XDP);
if (IS_ERR(prog))
return PTR_ERR(prog);
}

memset(&xdp, 0, sizeof(xdp));
xdp.command = XDP_SETUP_PROG;
xdp.extack = extack;
xdp.prog = prog;

err = xdp_op(dev, &xdp);
err = dev_xdp_install(dev, xdp_op, extack, prog);
if (err < 0 && prog)
bpf_prog_put(prog);

Expand Down
45 changes: 23 additions & 22 deletions net/core/rtnetlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -899,8 +899,7 @@ static size_t rtnl_port_size(const struct net_device *dev,
static size_t rtnl_xdp_size(void)
{
size_t xdp_size = nla_total_size(0) + /* nest IFLA_XDP */
nla_total_size(1) + /* XDP_ATTACHED */
nla_total_size(4); /* XDP_FLAGS */
nla_total_size(1); /* XDP_ATTACHED */

return xdp_size;
}
Expand Down Expand Up @@ -1247,37 +1246,34 @@ static int rtnl_fill_link_ifmap(struct sk_buff *skb, struct net_device *dev)
return 0;
}

static u8 rtnl_xdp_attached_mode(struct net_device *dev)
{
const struct net_device_ops *ops = dev->netdev_ops;

ASSERT_RTNL();

if (rcu_access_pointer(dev->xdp_prog))
return XDP_ATTACHED_SKB;
if (ops->ndo_xdp && __dev_xdp_attached(dev, ops->ndo_xdp))
return XDP_ATTACHED_DRV;

return XDP_ATTACHED_NONE;
}

static int rtnl_xdp_fill(struct sk_buff *skb, struct net_device *dev)
{
struct nlattr *xdp;
u32 xdp_flags = 0;
u8 val = 0;
int err;

xdp = nla_nest_start(skb, IFLA_XDP);
if (!xdp)
return -EMSGSIZE;
if (rcu_access_pointer(dev->xdp_prog)) {
xdp_flags = XDP_FLAGS_SKB_MODE;
val = 1;
} else if (dev->netdev_ops->ndo_xdp) {
struct netdev_xdp xdp_op = {};

xdp_op.command = XDP_QUERY_PROG;
err = dev->netdev_ops->ndo_xdp(dev, &xdp_op);
if (err)
goto err_cancel;
val = xdp_op.prog_attached;
}
err = nla_put_u8(skb, IFLA_XDP_ATTACHED, val);

err = nla_put_u8(skb, IFLA_XDP_ATTACHED,
rtnl_xdp_attached_mode(dev));
if (err)
goto err_cancel;

if (xdp_flags) {
err = nla_put_u32(skb, IFLA_XDP_FLAGS, xdp_flags);
if (err)
goto err_cancel;
}
nla_nest_end(skb, xdp);
return 0;

Expand Down Expand Up @@ -2199,6 +2195,11 @@ static int do_setlink(const struct sk_buff *skb,
err = -EINVAL;
goto errout;
}
if ((xdp_flags & XDP_FLAGS_SKB_MODE) &&
(xdp_flags & XDP_FLAGS_DRV_MODE)) {
err = -EINVAL;
goto errout;
}
}

if (xdp[IFLA_XDP_FD]) {
Expand Down
8 changes: 6 additions & 2 deletions samples/bpf/xdp1_user.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,14 @@ static void usage(const char *prog)
fprintf(stderr,
"usage: %s [OPTS] IFINDEX\n\n"
"OPTS:\n"
" -S use skb-mode\n",
" -S use skb-mode\n"
" -N enforce native mode\n",
prog);
}

int main(int argc, char **argv)
{
const char *optstr = "S";
const char *optstr = "SN";
char filename[256];
int opt;

Expand All @@ -77,6 +78,9 @@ int main(int argc, char **argv)
case 'S':
xdp_flags |= XDP_FLAGS_SKB_MODE;
break;
case 'N':
xdp_flags |= XDP_FLAGS_DRV_MODE;
break;
default:
usage(basename(argv[0]));
return 1;
Expand Down
7 changes: 6 additions & 1 deletion samples/bpf/xdp_tx_iptunnel_user.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ static void usage(const char *cmd)
printf(" -m <dest-MAC> Used in sending the IP Tunneled pkt\n");
printf(" -T <stop-after-X-seconds> Default: 0 (forever)\n");
printf(" -P <IP-Protocol> Default is TCP\n");
printf(" -S use skb-mode\n");
printf(" -N enforce native mode\n");
printf(" -h Display this help\n");
}

Expand Down Expand Up @@ -138,7 +140,7 @@ int main(int argc, char **argv)
{
unsigned char opt_flags[256] = {};
unsigned int kill_after_s = 0;
const char *optstr = "i:a:p:s:d:m:T:P:Sh";
const char *optstr = "i:a:p:s:d:m:T:P:SNh";
int min_port = 0, max_port = 0;
struct iptnl_info tnl = {};
struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
Expand Down Expand Up @@ -206,6 +208,9 @@ int main(int argc, char **argv)
case 'S':
xdp_flags |= XDP_FLAGS_SKB_MODE;
break;
case 'N':
xdp_flags |= XDP_FLAGS_DRV_MODE;
break;
default:
usage(argv[0]);
return 1;
Expand Down

0 comments on commit 4e3c60e

Please sign in to comment.