On 04/12/2017 08:54 PM, David Miller wrote: [...]
+static u32 netif_receive_generic_xdp(struct sk_buff *skb, + struct bpf_prog *xdp_prog) +{ + struct xdp_buff xdp; + u32 act = XDP_DROP; + void *orig_data; + int hlen, off; + + if (skb_linearize(skb))
Btw, given the skb can come from all kind of points in the stack, it could also be a clone at this point. One example is act_mirred which in fact does skb_clone() and can push the skb back to ingress path through netif_receive_skb() and thus could then go into generic xdp processing, where skb can be mangled. Instead of skb_linearize() we would therefore need to use something like skb_ensure_writable(skb, skb->len) as equivalent, which also makes sure that we unclone whenever needed.
+ goto do_drop; + + /* The XDP program wants to see the packet starting at the MAC + * header. + */ + hlen = skb_headlen(skb) + skb->mac_len; + xdp.data = skb->data - skb->mac_len; + xdp.data_end = xdp.data + hlen; + xdp.data_hard_start = xdp.data - skb_headroom(skb); + orig_data = xdp.data; + + act = bpf_prog_run_xdp(xdp_prog, &xdp); + + off = xdp.data - orig_data; + if (off) + __skb_push(skb, off); + + switch (act) { + case XDP_TX: + __skb_push(skb, skb->mac_len); + /* fall through */ + case XDP_PASS: + break; + + default: + bpf_warn_invalid_xdp_action(act); + /* fall through */ + case XDP_ABORTED: + trace_xdp_exception(skb->dev, xdp_prog, act); + /* fall through */ + case XDP_DROP: + do_drop: + kfree_skb(skb); + break; + } + + return act; +} + static int netif_receive_skb_internal(struct sk_buff *skb) { int ret; @@ -4258,6 +4341,21 @@ static int netif_receive_skb_internal(struct sk_buff *skb) rcu_read_lock(); + if (static_key_false(&generic_xdp_needed)) { + struct bpf_prog *xdp_prog = rcu_dereference(skb->dev->xdp_prog); + + if (xdp_prog) { + u32 act = netif_receive_generic_xdp(skb, xdp_prog); + + if (act != XDP_PASS) { + rcu_read_unlock(); + if (act == XDP_TX) + dev_queue_xmit(skb); + return NET_RX_DROP; + } + } + } +
[...]