net: Generic XDP
This provides a generic SKB based non-optimized XDP path which is used if either the driver lacks a specific XDP implementation, or the user requests it via a new IFLA_XDP_FLAGS value named XDP_FLAGS_SKB_MODE. It is arguable that perhaps I should have required something like this as part of the initial XDP feature merge. I believe this is critical for two reasons: 1) Accessibility. More people can play with XDP with less dependencies. Yes I know we have XDP support in virtio_net, but that just creates another depedency for learning how to use this facility. I wrote this to make life easier for the XDP newbies. 2) As a model for what the expected semantics are. If there is a pure generic core implementation, it serves as a semantic example for driver folks adding XDP support. One thing I have not tried to address here is the issue of XDP_PACKET_HEADROOM, thanks to Daniel for spotting that. It seems incredibly expensive to do a skb_cow(skb, XDP_PACKET_HEADROOM) or whatever even if the XDP program doesn't try to push headers at all. I think we really need the verifier to somehow propagate whether certain XDP helpers are used or not. v5: - Handle both negative and positive offset after running prog - Fix mac length in XDP_TX case (Alexei) - Use rcu_dereference_protected() in free_netdev (kbuild test robot) v4: - Fix MAC header adjustmnet before calling prog (David Ahern) - Disable LRO when generic XDP is installed (Michael Chan) - Bypass qdisc et al. on XDP_TX and record the event (Alexei) - Do not perform generic XDP on reinjected packets (DaveM) v3: - Make sure XDP program sees packet at MAC header, push back MAC header if we do XDP_TX. (Alexei) - Elide GRO when generic XDP is in use. (Alexei) - Add XDP_FLAG_SKB_MODE flag which the user can use to request generic XDP even if the driver has an XDP implementation. (Alexei) - Report whether SKB mode is in use in rtnl_xdp_fill() via XDP_FLAGS attribute. (Daniel) v2: - Add some "fall through" comments in switch statements based upon feedback from Andrew Lunn - Use RCU for generic xdp_prog, thanks to Johannes Berg. Tested-by: Andy Gospodarek <andy@greyhouse.net> Tested-by: Jesper Dangaard Brouer <brouer@redhat.com> Tested-by: David Ahern <dsa@cumulusnetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
@@ -896,15 +896,13 @@ static size_t rtnl_port_size(const struct net_device *dev,
|
||||
return port_self_size;
|
||||
}
|
||||
|
||||
static size_t rtnl_xdp_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(1) + /* XDP_ATTACHED */
|
||||
nla_total_size(4); /* XDP_FLAGS */
|
||||
|
||||
if (!dev->netdev_ops->ndo_xdp)
|
||||
return 0;
|
||||
else
|
||||
return xdp_size;
|
||||
return xdp_size;
|
||||
}
|
||||
|
||||
static noinline size_t if_nlmsg_size(const struct net_device *dev,
|
||||
@@ -943,7 +941,7 @@ static noinline size_t if_nlmsg_size(const struct net_device *dev,
|
||||
+ nla_total_size(MAX_PHYS_ITEM_ID_LEN) /* IFLA_PHYS_PORT_ID */
|
||||
+ nla_total_size(MAX_PHYS_ITEM_ID_LEN) /* IFLA_PHYS_SWITCH_ID */
|
||||
+ nla_total_size(IFNAMSIZ) /* IFLA_PHYS_PORT_NAME */
|
||||
+ rtnl_xdp_size(dev) /* IFLA_XDP */
|
||||
+ rtnl_xdp_size() /* IFLA_XDP */
|
||||
+ nla_total_size(1); /* IFLA_PROTO_DOWN */
|
||||
|
||||
}
|
||||
@@ -1251,23 +1249,35 @@ static int rtnl_fill_link_ifmap(struct sk_buff *skb, struct net_device *dev)
|
||||
|
||||
static int rtnl_xdp_fill(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
struct netdev_xdp xdp_op = {};
|
||||
struct nlattr *xdp;
|
||||
u32 xdp_flags = 0;
|
||||
u8 val = 0;
|
||||
int err;
|
||||
|
||||
if (!dev->netdev_ops->ndo_xdp)
|
||||
return 0;
|
||||
xdp = nla_nest_start(skb, IFLA_XDP);
|
||||
if (!xdp)
|
||||
return -EMSGSIZE;
|
||||
xdp_op.command = XDP_QUERY_PROG;
|
||||
err = dev->netdev_ops->ndo_xdp(dev, &xdp_op);
|
||||
if (err)
|
||||
goto err_cancel;
|
||||
err = nla_put_u8(skb, IFLA_XDP_ATTACHED, xdp_op.prog_attached);
|
||||
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);
|
||||
if (err)
|
||||
goto err_cancel;
|
||||
}
|
||||
nla_nest_end(skb, xdp);
|
||||
return 0;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user