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

Commit 4e3c60ed authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'generic-xdp-followups'



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: default avatarDavid S. Miller <davem@davemloft.net>
parents 0a5539f6 d67b9cd2
Loading
Loading
Loading
Loading
+6 −2
Original line number Diff line number Diff line
@@ -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,
+11 −2
Original line number Diff line number Diff line
@@ -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,
+38 −19
Original line number Diff line number Diff line
@@ -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
@@ -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)
		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);

+23 −22
Original line number Diff line number Diff line
@@ -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;
}
@@ -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);
	if (err)
		goto err_cancel;

	if (xdp_flags) {
		err = nla_put_u32(skb, IFLA_XDP_FLAGS, xdp_flags);
	err = nla_put_u8(skb, IFLA_XDP_ATTACHED,
			 rtnl_xdp_attached_mode(dev));
	if (err)
		goto err_cancel;
	}

	nla_nest_end(skb, xdp);
	return 0;

@@ -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]) {
+6 −2
Original line number Diff line number Diff line
@@ -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;

@@ -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;
Loading