diff mbox

[v7,02/11] net: add ndo to setup/query xdp prog in adapter rx

Message ID 1468272598-21390-3-git-send-email-bblanco@plumgrid.com
State Changes Requested, archived
Delegated to: David Miller
Headers show

Commit Message

Brenden Blanco July 11, 2016, 9:29 p.m. UTC
Add one new netdev op for drivers implementing the BPF_PROG_TYPE_XDP
filter. The single op is used for both setup/query of the xdp program,
modelled after ndo_setup_tc.

Signed-off-by: Brenden Blanco <bblanco@plumgrid.com>
---
 include/linux/netdevice.h | 32 ++++++++++++++++++++++++++++++++
 net/core/dev.c            | 33 +++++++++++++++++++++++++++++++++
 2 files changed, 65 insertions(+)

Comments

David Miller July 12, 2016, 6:12 a.m. UTC | #1
From: Brenden Blanco <bblanco@plumgrid.com>
Date: Mon, 11 Jul 2016 14:29:49 -0700

> +	if (fd >= 0) {
> +		prog = bpf_prog_get_type(fd, BPF_PROG_TYPE_XDP);
> +		if (IS_ERR(prog))
> +			return PTR_ERR(prog);
> +	}
> +
> +	xdp.command = XDP_SETUP_PROG;
> +	xdp.prog = prog;
> +	err = ops->ndo_xdp(dev, &xdp);
> +	if (err < 0 && prog)
> +		bpf_prog_put(prog);

I don't understand the reference counting on 'prog' here.

The enumeration documentation states that no matter what, the passed
in prog doesn't need to be mangaged by the ->ndo_xdp() method.

Therefore, if that is true, we must always put the 'prog' here if it
is non-NULL.  Regardless of the 'err' value.
Brenden Blanco July 12, 2016, 6:35 a.m. UTC | #2
On Mon, Jul 11, 2016 at 11:12:24PM -0700, David Miller wrote:
> From: Brenden Blanco <bblanco@plumgrid.com>
> Date: Mon, 11 Jul 2016 14:29:49 -0700
> 
> > +	if (fd >= 0) {
> > +		prog = bpf_prog_get_type(fd, BPF_PROG_TYPE_XDP);
> > +		if (IS_ERR(prog))
> > +			return PTR_ERR(prog);
> > +	}
> > +
> > +	xdp.command = XDP_SETUP_PROG;
> > +	xdp.prog = prog;
> > +	err = ops->ndo_xdp(dev, &xdp);
> > +	if (err < 0 && prog)
> > +		bpf_prog_put(prog);
> 
> I don't understand the reference counting on 'prog' here.
> 
> The enumeration documentation states that no matter what, the passed
> in prog doesn't need to be mangaged by the ->ndo_xdp() method.
> 
> Therefore, if that is true, we must always put the 'prog' here if it
> is non-NULL.  Regardless of the 'err' value.
> 
The documentation is unclear then. What I _meant_ to say is that the callee
is not responsible for putting the program on error, but on success it
takes ownership of the reference. In context of that, does the code make
sense? Is there a more conventional way of handling this?

Thanks for your review.
David Miller July 12, 2016, 6:45 a.m. UTC | #3
From: Brenden Blanco <bblanco@plumgrid.com>
Date: Mon, 11 Jul 2016 23:35:00 -0700

> On Mon, Jul 11, 2016 at 11:12:24PM -0700, David Miller wrote:
>> From: Brenden Blanco <bblanco@plumgrid.com>
>> Date: Mon, 11 Jul 2016 14:29:49 -0700
>> 
>> > +	if (fd >= 0) {
>> > +		prog = bpf_prog_get_type(fd, BPF_PROG_TYPE_XDP);
>> > +		if (IS_ERR(prog))
>> > +			return PTR_ERR(prog);
>> > +	}
>> > +
>> > +	xdp.command = XDP_SETUP_PROG;
>> > +	xdp.prog = prog;
>> > +	err = ops->ndo_xdp(dev, &xdp);
>> > +	if (err < 0 && prog)
>> > +		bpf_prog_put(prog);
>> 
>> I don't understand the reference counting on 'prog' here.
>> 
>> The enumeration documentation states that no matter what, the passed
>> in prog doesn't need to be mangaged by the ->ndo_xdp() method.
>> 
>> Therefore, if that is true, we must always put the 'prog' here if it
>> is non-NULL.  Regardless of the 'err' value.
>> 
> The documentation is unclear then. What I _meant_ to say is that the callee
> is not responsible for putting the program on error, but on success it
> takes ownership of the reference. In context of that, does the code make
> sense? Is there a more conventional way of handling this?

Then please document it more clearly, thanks.
diff mbox

Patch

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 49736a3..2f04746 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -63,6 +63,7 @@  struct wpan_dev;
 struct mpls_dev;
 /* UDP Tunnel offloads */
 struct udp_tunnel_info;
+struct bpf_prog;
 
 void netdev_set_default_ethtool_ops(struct net_device *dev,
 				    const struct ethtool_ops *ops);
@@ -799,6 +800,31 @@  struct tc_to_netdev {
 	};
 };
 
+/* These structures hold the attributes of xdp state that are being passed
+ * to the netdevice through the xdp op.
+ */
+enum xdp_netdev_command {
+	/* Set or clear a bpf program used in the earliest stages of packet
+	 * rx. The prog will have been loaded as BPF_PROG_TYPE_XDP. The callee
+	 * is responsible for calling bpf_prog_put on any old progs that are
+	 * stored, but not on the passed in prog.
+	 */
+	XDP_SETUP_PROG,
+	/* Check if a bpf program is set on the device.  The callee should
+	 * return true if a program is currently attached and running.
+	 */
+	XDP_QUERY_PROG,
+};
+
+struct netdev_xdp {
+	enum xdp_netdev_command command;
+	union {
+		/* XDP_SETUP_PROG */
+		struct bpf_prog *prog;
+		/* XDP_QUERY_PROG */
+		bool prog_attached;
+	};
+};
 
 /*
  * This structure defines the management hooks for network devices.
@@ -1087,6 +1113,9 @@  struct tc_to_netdev {
  *	appropriate rx headroom value allows avoiding skb head copy on
  *	forward. Setting a negative value resets the rx headroom to the
  *	default value.
+ * int (*ndo_xdp)(struct net_device *dev, struct netdev_xdp *xdp);
+ *	This function is used to set or query state related to XDP on the
+ *	netdevice. See definition of enum xdp_netdev_command for details.
  *
  */
 struct net_device_ops {
@@ -1271,6 +1300,8 @@  struct net_device_ops {
 						       struct sk_buff *skb);
 	void			(*ndo_set_rx_headroom)(struct net_device *dev,
 						       int needed_headroom);
+	int			(*ndo_xdp)(struct net_device *dev,
+					   struct netdev_xdp *xdp);
 };
 
 /**
@@ -3257,6 +3288,7 @@  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, int fd);
 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);
diff --git a/net/core/dev.c b/net/core/dev.c
index 7894e40..2a9c39f 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -94,6 +94,7 @@ 
 #include <linux/ethtool.h>
 #include <linux/notifier.h>
 #include <linux/skbuff.h>
+#include <linux/bpf.h>
 #include <net/net_namespace.h>
 #include <net/sock.h>
 #include <net/busy_poll.h>
@@ -6615,6 +6616,38 @@  int dev_change_proto_down(struct net_device *dev, bool proto_down)
 EXPORT_SYMBOL(dev_change_proto_down);
 
 /**
+ *	dev_change_xdp_fd - set or clear a bpf program for a device rx path
+ *	@dev: device
+ *	@fd: new program fd or negative value to clear
+ *
+ *	Set or clear a bpf program for a device
+ */
+int dev_change_xdp_fd(struct net_device *dev, int fd)
+{
+	const struct net_device_ops *ops = dev->netdev_ops;
+	struct bpf_prog *prog = NULL;
+	struct netdev_xdp xdp = {};
+	int err;
+
+	if (!ops->ndo_xdp)
+		return -EOPNOTSUPP;
+	if (fd >= 0) {
+		prog = bpf_prog_get_type(fd, BPF_PROG_TYPE_XDP);
+		if (IS_ERR(prog))
+			return PTR_ERR(prog);
+	}
+
+	xdp.command = XDP_SETUP_PROG;
+	xdp.prog = prog;
+	err = ops->ndo_xdp(dev, &xdp);
+	if (err < 0 && prog)
+		bpf_prog_put(prog);
+
+	return err;
+}
+EXPORT_SYMBOL(dev_change_xdp_fd);
+
+/**
  *	dev_new_index	-	allocate an ifindex
  *	@net: the applicable net namespace
  *