aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorToshiaki Makita <makita.toshiaki@lab.ntt.co.jp>2018-08-03 03:58:14 -0400
committerDaniel Borkmann <daniel@iogearbox.net>2018-08-10 10:12:21 -0400
commitaf87a3aa1b5f397a2f5c99b97b000943c5177da7 (patch)
tree24ef46bf0b5a4f47a2abe78758eef93cdf5b88e1
parent9fc8d518d9d590998209f2686e026a488f65d41e (diff)
veth: Add ndo_xdp_xmit
This allows NIC's XDP to redirect packets to veth. The destination veth device enqueues redirected packets to the napi ring of its peer, then they are processed by XDP on its peer veth device. This can be thought as calling another XDP program by XDP program using REDIRECT, when the peer enables driver XDP. Note that when the peer veth device does not set driver xdp, redirected packets will be dropped because the peer is not ready for NAPI. v4: - Don't use xdp_ok_fwd_dev() because checking IFF_UP is not necessary. Add comments about it and check only MTU. v2: - Drop the part converting xdp_frame into skb when XDP is not enabled. - Implement bulk interface of ndo_xdp_xmit. - Implement XDP_XMIT_FLUSH bit and drop ndo_xdp_flush. Signed-off-by: Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp> Acked-by: John Fastabend <john.fastabend@gmail.com> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
-rw-r--r--drivers/net/veth.c51
1 files changed, 51 insertions, 0 deletions
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 89f3059e603d..dbb693a7795e 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -17,6 +17,7 @@
17#include <net/rtnetlink.h> 17#include <net/rtnetlink.h>
18#include <net/dst.h> 18#include <net/dst.h>
19#include <net/xfrm.h> 19#include <net/xfrm.h>
20#include <net/xdp.h>
20#include <linux/veth.h> 21#include <linux/veth.h>
21#include <linux/module.h> 22#include <linux/module.h>
22#include <linux/bpf.h> 23#include <linux/bpf.h>
@@ -125,6 +126,11 @@ static void *veth_ptr_to_xdp(void *ptr)
125 return (void *)((unsigned long)ptr & ~VETH_XDP_FLAG); 126 return (void *)((unsigned long)ptr & ~VETH_XDP_FLAG);
126} 127}
127 128
129static void *veth_xdp_to_ptr(void *ptr)
130{
131 return (void *)((unsigned long)ptr | VETH_XDP_FLAG);
132}
133
128static void veth_ptr_free(void *ptr) 134static void veth_ptr_free(void *ptr)
129{ 135{
130 if (veth_is_xdp_frame(ptr)) 136 if (veth_is_xdp_frame(ptr))
@@ -267,6 +273,50 @@ static struct sk_buff *veth_build_skb(void *head, int headroom, int len,
267 return skb; 273 return skb;
268} 274}
269 275
276static int veth_xdp_xmit(struct net_device *dev, int n,
277 struct xdp_frame **frames, u32 flags)
278{
279 struct veth_priv *rcv_priv, *priv = netdev_priv(dev);
280 struct net_device *rcv;
281 unsigned int max_len;
282 int i, drops = 0;
283
284 if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK))
285 return -EINVAL;
286
287 rcv = rcu_dereference(priv->peer);
288 if (unlikely(!rcv))
289 return -ENXIO;
290
291 rcv_priv = netdev_priv(rcv);
292 /* Non-NULL xdp_prog ensures that xdp_ring is initialized on receive
293 * side. This means an XDP program is loaded on the peer and the peer
294 * device is up.
295 */
296 if (!rcu_access_pointer(rcv_priv->xdp_prog))
297 return -ENXIO;
298
299 max_len = rcv->mtu + rcv->hard_header_len + VLAN_HLEN;
300
301 spin_lock(&rcv_priv->xdp_ring.producer_lock);
302 for (i = 0; i < n; i++) {
303 struct xdp_frame *frame = frames[i];
304 void *ptr = veth_xdp_to_ptr(frame);
305
306 if (unlikely(frame->len > max_len ||
307 __ptr_ring_produce(&rcv_priv->xdp_ring, ptr))) {
308 xdp_return_frame_rx_napi(frame);
309 drops++;
310 }
311 }
312 spin_unlock(&rcv_priv->xdp_ring.producer_lock);
313
314 if (flags & XDP_XMIT_FLUSH)
315 __veth_xdp_flush(rcv_priv);
316
317 return n - drops;
318}
319
270static struct sk_buff *veth_xdp_rcv_one(struct veth_priv *priv, 320static struct sk_buff *veth_xdp_rcv_one(struct veth_priv *priv,
271 struct xdp_frame *frame) 321 struct xdp_frame *frame)
272{ 322{
@@ -769,6 +819,7 @@ static const struct net_device_ops veth_netdev_ops = {
769 .ndo_features_check = passthru_features_check, 819 .ndo_features_check = passthru_features_check,
770 .ndo_set_rx_headroom = veth_set_rx_headroom, 820 .ndo_set_rx_headroom = veth_set_rx_headroom,
771 .ndo_bpf = veth_xdp, 821 .ndo_bpf = veth_xdp,
822 .ndo_xdp_xmit = veth_xdp_xmit,
772}; 823};
773 824
774#define VETH_FEATURES (NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HW_CSUM | \ 825#define VETH_FEATURES (NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HW_CSUM | \