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

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
...@@ -3296,11 +3296,15 @@ int dev_get_phys_port_id(struct net_device *dev, ...@@ -3296,11 +3296,15 @@ int dev_get_phys_port_id(struct net_device *dev,
int dev_get_phys_port_name(struct net_device *dev, int dev_get_phys_port_name(struct net_device *dev,
char *name, size_t len); char *name, size_t len);
int dev_change_proto_down(struct net_device *dev, bool proto_down); 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 *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 sk_buff *dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
struct netdev_queue *txq, int *ret); 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);
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, bool is_skb_forwardable(const struct net_device *dev,
......
...@@ -888,9 +888,18 @@ enum { ...@@ -888,9 +888,18 @@ enum {
/* XDP section */ /* XDP section */
#define XDP_FLAGS_UPDATE_IF_NOEXIST (1U << 0) #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 | \ #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 { enum {
IFLA_XDP_UNSPEC, IFLA_XDP_UNSPEC,
......
...@@ -6852,6 +6852,32 @@ int dev_change_proto_down(struct net_device *dev, bool proto_down) ...@@ -6852,6 +6852,32 @@ int dev_change_proto_down(struct net_device *dev, bool proto_down)
} }
EXPORT_SYMBOL(dev_change_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_change_xdp_fd - set or clear a bpf program for a device rx path
* @dev: device * @dev: device
...@@ -6864,41 +6890,34 @@ EXPORT_SYMBOL(dev_change_proto_down); ...@@ -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 dev_change_xdp_fd(struct net_device *dev, struct netlink_ext_ack *extack,
int fd, u32 flags) int fd, u32 flags)
{ {
int (*xdp_op)(struct net_device *dev, struct netdev_xdp *xdp);
const struct net_device_ops *ops = dev->netdev_ops; const struct net_device_ops *ops = dev->netdev_ops;
struct bpf_prog *prog = NULL; struct bpf_prog *prog = NULL;
struct netdev_xdp xdp; xdp_op_t xdp_op, xdp_chk;
int err; int err;
ASSERT_RTNL(); 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)) if (!xdp_op || (flags & XDP_FLAGS_SKB_MODE))
xdp_op = generic_xdp_install; xdp_op = generic_xdp_install;
if (xdp_op == xdp_chk)
xdp_chk = generic_xdp_install;
if (fd >= 0) { if (fd >= 0) {
if (flags & XDP_FLAGS_UPDATE_IF_NOEXIST) { if (xdp_chk && __dev_xdp_attached(dev, xdp_chk))
memset(&xdp, 0, sizeof(xdp)); return -EEXIST;
xdp.command = XDP_QUERY_PROG; if ((flags & XDP_FLAGS_UPDATE_IF_NOEXIST) &&
__dev_xdp_attached(dev, xdp_op))
err = xdp_op(dev, &xdp); return -EBUSY;
if (err < 0)
return err;
if (xdp.prog_attached)
return -EBUSY;
}
prog = bpf_prog_get_type(fd, BPF_PROG_TYPE_XDP); prog = bpf_prog_get_type(fd, BPF_PROG_TYPE_XDP);
if (IS_ERR(prog)) if (IS_ERR(prog))
return PTR_ERR(prog); return PTR_ERR(prog);
} }
memset(&xdp, 0, sizeof(xdp)); err = dev_xdp_install(dev, xdp_op, extack, prog);
xdp.command = XDP_SETUP_PROG;
xdp.extack = extack;
xdp.prog = prog;
err = xdp_op(dev, &xdp);
if (err < 0 && prog) if (err < 0 && prog)
bpf_prog_put(prog); bpf_prog_put(prog);
......
...@@ -899,8 +899,7 @@ static size_t rtnl_port_size(const struct net_device *dev, ...@@ -899,8 +899,7 @@ static size_t rtnl_port_size(const struct net_device *dev,
static size_t rtnl_xdp_size(void) static size_t rtnl_xdp_size(void)
{ {
size_t xdp_size = nla_total_size(0) + /* nest IFLA_XDP */ size_t xdp_size = nla_total_size(0) + /* nest IFLA_XDP */
nla_total_size(1) + /* XDP_ATTACHED */ nla_total_size(1); /* XDP_ATTACHED */
nla_total_size(4); /* XDP_FLAGS */
return xdp_size; return xdp_size;
} }
...@@ -1247,37 +1246,34 @@ static int rtnl_fill_link_ifmap(struct sk_buff *skb, struct net_device *dev) ...@@ -1247,37 +1246,34 @@ static int rtnl_fill_link_ifmap(struct sk_buff *skb, struct net_device *dev)
return 0; 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) static int rtnl_xdp_fill(struct sk_buff *skb, struct net_device *dev)
{ {
struct nlattr *xdp; struct nlattr *xdp;
u32 xdp_flags = 0;
u8 val = 0;
int err; int err;
xdp = nla_nest_start(skb, IFLA_XDP); xdp = nla_nest_start(skb, IFLA_XDP);
if (!xdp) if (!xdp)
return -EMSGSIZE; return -EMSGSIZE;
if (rcu_access_pointer(dev->xdp_prog)) {
xdp_flags = XDP_FLAGS_SKB_MODE; err = nla_put_u8(skb, IFLA_XDP_ATTACHED,
val = 1; rtnl_xdp_attached_mode(dev));
} 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) if (err)
goto err_cancel; 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); nla_nest_end(skb, xdp);
return 0; return 0;
...@@ -2199,6 +2195,11 @@ static int do_setlink(const struct sk_buff *skb, ...@@ -2199,6 +2195,11 @@ static int do_setlink(const struct sk_buff *skb,
err = -EINVAL; err = -EINVAL;
goto errout; goto errout;
} }
if ((xdp_flags & XDP_FLAGS_SKB_MODE) &&
(xdp_flags & XDP_FLAGS_DRV_MODE)) {
err = -EINVAL;
goto errout;
}
} }
if (xdp[IFLA_XDP_FD]) { if (xdp[IFLA_XDP_FD]) {
......
...@@ -62,13 +62,14 @@ static void usage(const char *prog) ...@@ -62,13 +62,14 @@ static void usage(const char *prog)
fprintf(stderr, fprintf(stderr,
"usage: %s [OPTS] IFINDEX\n\n" "usage: %s [OPTS] IFINDEX\n\n"
"OPTS:\n" "OPTS:\n"
" -S use skb-mode\n", " -S use skb-mode\n"
" -N enforce native mode\n",
prog); prog);
} }
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
const char *optstr = "S"; const char *optstr = "SN";
char filename[256]; char filename[256];
int opt; int opt;
...@@ -77,6 +78,9 @@ int main(int argc, char **argv) ...@@ -77,6 +78,9 @@ int main(int argc, char **argv)
case 'S': case 'S':
xdp_flags |= XDP_FLAGS_SKB_MODE; xdp_flags |= XDP_FLAGS_SKB_MODE;
break; break;
case 'N':
xdp_flags |= XDP_FLAGS_DRV_MODE;
break;
default: default:
usage(basename(argv[0])); usage(basename(argv[0]));
return 1; return 1;
......
...@@ -79,6 +79,8 @@ static void usage(const char *cmd) ...@@ -79,6 +79,8 @@ static void usage(const char *cmd)
printf(" -m <dest-MAC> Used in sending the IP Tunneled pkt\n"); printf(" -m <dest-MAC> Used in sending the IP Tunneled pkt\n");
printf(" -T <stop-after-X-seconds> Default: 0 (forever)\n"); printf(" -T <stop-after-X-seconds> Default: 0 (forever)\n");
printf(" -P <IP-Protocol> Default is TCP\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"); printf(" -h Display this help\n");
} }
...@@ -138,7 +140,7 @@ int main(int argc, char **argv) ...@@ -138,7 +140,7 @@ int main(int argc, char **argv)
{ {
unsigned char opt_flags[256] = {}; unsigned char opt_flags[256] = {};
unsigned int kill_after_s = 0; 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; int min_port = 0, max_port = 0;
struct iptnl_info tnl = {}; struct iptnl_info tnl = {};
struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY}; struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
...@@ -206,6 +208,9 @@ int main(int argc, char **argv) ...@@ -206,6 +208,9 @@ int main(int argc, char **argv)
case 'S': case 'S':
xdp_flags |= XDP_FLAGS_SKB_MODE; xdp_flags |= XDP_FLAGS_SKB_MODE;
break; break;
case 'N':
xdp_flags |= XDP_FLAGS_DRV_MODE;
break;
default: default:
usage(argv[0]); usage(argv[0]);
return 1; return 1;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment