| @@ -95,6 +95,7 @@ · 94 unmodified lines |
| 95 | 95 | #include <linux/notifier.h> |
| 96 | 96 | #include <linux/skbuff.h> |
| 97 | 97 | #include <linux/bpf.h> |
| 98 | +#include <linux/bpf_trace.h> |
| 98 | 99 | #include <net/net_namespace.h> |
| 99 | 100 | #include <net/sock.h> |
| 100 | 101 | #include <net/busy_poll.h> |
| @@ -4251,6 +4252,125 @@ static int __netif_receive_skb(struct sk_buff *skb) · 4150 unmodified lines |
| 4251 | 4252 | return ret; |
| 4252 | 4253 | } |
| 4253 | 4254 | |
| 4255 | +static struct static_key generic_xdp_needed __read_mostly; |
| 4256 | + |
| 4257 | +static int generic_xdp_install(struct net_device *dev, struct netdev_xdp *xdp) |
| 4258 | +{ |
| 4259 | + struct bpf_prog *new = xdp->prog; |
| 4260 | + int ret = 0; |
| 4261 | + |
| 4262 | + switch (xdp->command) { |
| 4263 | + case XDP_SETUP_PROG: { |
| 4264 | + struct bpf_prog *old = rtnl_dereference(dev->xdp_prog); |
| 4265 | + |
| 4266 | + rcu_assign_pointer(dev->xdp_prog, new); |
| 4267 | + if (old) |
| 4268 | + bpf_prog_put(old); |
| 4269 | + |
| 4270 | + if (old && !new) { |
| 4271 | + static_key_slow_dec(&generic_xdp_needed); |
| 4272 | + } else if (new && !old) { |
| 4273 | + static_key_slow_inc(&generic_xdp_needed); |
| 4274 | + dev_disable_lro(dev); |
| 4275 | + } |
| 4276 | + break; |
| 4277 | + } |
| 4278 | + |
| 4279 | + case XDP_QUERY_PROG: |
| 4280 | + xdp->prog_attached = !!rcu_access_pointer(dev->xdp_prog); |
| 4281 | + break; |
| 4282 | + |
| 4283 | + default: |
| 4284 | + ret = -EINVAL; |
| 4285 | + break; |
| 4286 | + } |
| 4287 | + |
| 4288 | + return ret; |
| 4289 | +} |
| 4290 | + |
| 4291 | +static u32 netif_receive_generic_xdp(struct sk_buff *skb, |
| 4292 | + struct bpf_prog *xdp_prog) |
| 4293 | +{ |
| 4294 | + struct xdp_buff xdp; |
| 4295 | + u32 act = XDP_DROP; |
| 4296 | + void *orig_data; |
| 4297 | + int hlen, off; |
| 4298 | + u32 mac_len; |
| 4299 | + |
| 4300 | + /* Reinjected packets coming from act_mirred or similar should |
| 4301 | + * not get XDP generic processing. |
| 4302 | + */ |
| 4303 | + if (skb_cloned(skb)) |
| 4304 | + return XDP_PASS; |
| 4305 | + |
| 4306 | + if (skb_linearize(skb)) |
| 4307 | + goto do_drop; |
| 4308 | + |
| 4309 | + /* The XDP program wants to see the packet starting at the MAC |
| 4310 | + * header. |
| 4311 | + */ |
| 4312 | + mac_len = skb->data - skb_mac_header(skb); |
| 4313 | + hlen = skb_headlen(skb) + mac_len; |
| 4314 | + xdp.data = skb->data - mac_len; |
| 4315 | + xdp.data_end = xdp.data + hlen; |
| 4316 | + xdp.data_hard_start = skb->data - skb_headroom(skb); |
| 4317 | + orig_data = xdp.data; |
| 4318 | + |
| 4319 | + act = bpf_prog_run_xdp(xdp_prog, &xdp); |
| 4320 | + |
| 4321 | + off = xdp.data - orig_data; |
| 4322 | + if (off > 0) |
| 4323 | + __skb_pull(skb, off); |
| 4324 | + else if (off < 0) |
| 4325 | + __skb_push(skb, -off); |
| 4326 | + |
| 4327 | + switch (act) { |
| 4328 | + case XDP_TX: |
| 4329 | + __skb_push(skb, mac_len); |
| 4330 | + /* fall through */ |
| 4331 | + case XDP_PASS: |
| 4332 | + break; |
| 4333 | + |
| 4334 | + default: |
| 4335 | + bpf_warn_invalid_xdp_action(act); |
| 4336 | + /* fall through */ |
| 4337 | + case XDP_ABORTED: |
| 4338 | + trace_xdp_exception(skb->dev, xdp_prog, act); |
| 4339 | + /* fall through */ |
| 4340 | + case XDP_DROP: |
| 4341 | + do_drop: |
| 4342 | + kfree_skb(skb); |
| 4343 | + break; |
| 4344 | + } |
| 4345 | + |
| 4346 | + return act; |
| 4347 | +} |
| 4348 | + |
| 4349 | +/* When doing generic XDP we have to bypass the qdisc layer and the |
| 4350 | + * network taps in order to match in-driver-XDP behavior. |
| 4351 | + */ |
| 4352 | +static void generic_xdp_tx(struct sk_buff *skb, struct bpf_prog *xdp_prog) |
| 4353 | +{ |
| 4354 | + struct net_device *dev = skb->dev; |
| 4355 | + struct netdev_queue *txq; |
| 4356 | + bool free_skb = true; |
| 4357 | + int cpu, rc; |
| 4358 | + |
| 4359 | + txq = netdev_pick_tx(dev, skb, NULL); |
| 4360 | + cpu = smp_processor_id(); |
| 4361 | + HARD_TX_LOCK(dev, txq, cpu); |
| 4362 | + if (!netif_xmit_stopped(txq)) { |
| 4363 | + rc = netdev_start_xmit(skb, dev, txq, 0); |
| 4364 | + if (dev_xmit_complete(rc)) |
| 4365 | + free_skb = false; |
| 4366 | + } |
| 4367 | + HARD_TX_UNLOCK(dev, txq); |
| 4368 | + if (free_skb) { |
| 4369 | + trace_xdp_exception(dev, xdp_prog, XDP_TX); |
| 4370 | + kfree_skb(skb); |
| 4371 | + } |
| 4372 | +} |
| 4373 | + |
| 4254 | 4374 | static int netif_receive_skb_internal(struct sk_buff *skb) |
| 4255 | 4375 | { |
| 4256 | 4376 | int ret; |
| @@ -4262,6 +4382,21 @@ static int netif_receive_skb_internal(struct sk_buff *skb) · 5 unmodified lines |
| 4262 | 4382 | |
| 4263 | 4383 | rcu_read_lock(); |
| 4264 | 4384 | |
| 4385 | + if (static_key_false(&generic_xdp_needed)) { |
| 4386 | + struct bpf_prog *xdp_prog = rcu_dereference(skb->dev->xdp_prog); |
| 4387 | + |
| 4388 | + if (xdp_prog) { |
| 4389 | + u32 act = netif_receive_generic_xdp(skb, xdp_prog); |
| 4390 | + |
| 4391 | + if (act != XDP_PASS) { |
| 4392 | + rcu_read_unlock(); |
| 4393 | + if (act == XDP_TX) |
| 4394 | + generic_xdp_tx(skb, xdp_prog); |
| 4395 | + return NET_RX_DROP; |
| 4396 | + } |
| 4397 | + } |
| 4398 | + } |
| 4399 | + |
| 4265 | 4400 | #ifdef CONFIG_RPS |
| 4266 | 4401 | if (static_key_false(&rps_needed)) { |
| 4267 | 4402 | struct rps_dev_flow voidflow, *rflow = &voidflow; |
| @@ -4494,7 +4629,7 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff · 226 unmodified lines |
| 4494 | 4629 | enum gro_result ret; |
| 4495 | 4630 | int grow; |
| 4496 | 4631 | |
| 4497 | | − if (!(skb->dev->features & NETIF_F_GRO)) |
| 4632 | + if (netif_elide_gro(skb->dev)) |
| 4498 | 4633 | goto normal; |
| 4499 | 4634 | |
| 4500 | 4635 | if (skb->csum_bad) |
| @@ -6723,6 +6858,7 @@ EXPORT_SYMBOL(dev_change_proto_down); · 2222 unmodified lines |
| 6723 | 6858 | */ |
| 6724 | 6859 | int dev_change_xdp_fd(struct net_device *dev, int fd, u32 flags) |
| 6725 | 6860 | { |
| 6861 | + int (*xdp_op)(struct net_device *dev, struct netdev_xdp *xdp); |
| 6726 | 6862 | const struct net_device_ops *ops = dev->netdev_ops; |
| 6727 | 6863 | struct bpf_prog *prog = NULL; |
| 6728 | 6864 | struct netdev_xdp xdp; |
| @@ -6730,14 +6866,16 @@ int dev_change_xdp_fd(struct net_device *dev, int fd, u32 flags) · 1 unmodified line |
| 6730 | 6866 | |
| 6731 | 6867 | ASSERT_RTNL(); |
| 6732 | 6868 | |
| 6733 | | − if (!ops->ndo_xdp) |
| 6734 | | − return -EOPNOTSUPP; |
| 6869 | + xdp_op = ops->ndo_xdp; |
| 6870 | + if (!xdp_op || (flags & XDP_FLAGS_SKB_MODE)) |
| 6871 | + xdp_op = generic_xdp_install; |
| 6872 | + |
| 6735 | 6873 | if (fd >= 0) { |
| 6736 | 6874 | if (flags & XDP_FLAGS_UPDATE_IF_NOEXIST) { |
| 6737 | 6875 | memset(&xdp, 0, sizeof(xdp)); |
| 6738 | 6876 | xdp.command = XDP_QUERY_PROG; |
| 6739 | 6877 | |
| 6740 | | − err = ops->ndo_xdp(dev, &xdp); |
| 6878 | + err = xdp_op(dev, &xdp); |
| 6741 | 6879 | if (err < 0) |
| 6742 | 6880 | return err; |
| 6743 | 6881 | if (xdp.prog_attached) |
| @@ -6753,7 +6891,7 @@ int dev_change_xdp_fd(struct net_device *dev, int fd, u32 flags) · 9 unmodified lines |
| 6753 | 6891 | xdp.command = XDP_SETUP_PROG; |
| 6754 | 6892 | xdp.prog = prog; |
| 6755 | 6893 | |
| 6756 | | − err = ops->ndo_xdp(dev, &xdp); |
| 6894 | + err = xdp_op(dev, &xdp); |
| 6757 | 6895 | if (err < 0 && prog) |
| 6758 | 6896 | bpf_prog_put(prog); |
| 6759 | 6897 | |
| @@ -7793,6 +7931,7 @@ EXPORT_SYMBOL(alloc_netdev_mqs); · 1033 unmodified lines |
| 7793 | 7931 | void free_netdev(struct net_device *dev) |
| 7794 | 7932 | { |
| 7795 | 7933 | struct napi_struct *p, *n; |
| 7934 | + struct bpf_prog *prog; |
| 7796 | 7935 | |
| 7797 | 7936 | might_sleep(); |
| 7798 | 7937 | netif_free_tx_queues(dev); |
| @@ -7811,6 +7950,12 @@ void free_netdev(struct net_device *dev) · 12 unmodified lines |
| 7811 | 7950 | free_percpu(dev->pcpu_refcnt); |
| 7812 | 7951 | dev->pcpu_refcnt = NULL; |
| 7813 | 7952 | |
| 7953 | + prog = rcu_dereference_protected(dev->xdp_prog, 1); |
| 7954 | + if (prog) { |
| 7955 | + bpf_prog_put(prog); |
| 7956 | + static_key_slow_dec(&generic_xdp_needed); |
| 7957 | + } |
| 7958 | + |
| 7814 | 7959 | /* Compatibility with error handling in drivers */ |
| 7815 | 7960 | if (dev->reg_state == NETREG_UNINITIALIZED) { |
| 7816 | 7961 | netdev_freemem(dev); |