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: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2017-05-11 21:30:58 -04:00
commit 4e3c60ed2f
6 changed files with 89 additions and 47 deletions

View File

@ -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,

View File

@ -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,

View File

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

View File

@ -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);
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;
@ -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]) {

View File

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

View File

@ -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");
}
@ -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};
@ -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;