Skip to content

Commit 6093ec2

Browse files
committed
Merge branch 'xdp-redirect'
John Fastabend says: ==================== Implement XDP bpf_redirect This series adds two new XDP helper routines bpf_redirect() and bpf_redirect_map(). The first variant bpf_redirect() is meant to be used the same way it is currently being used by the cls_bpf classifier. An xdp packet will be redirected immediately when this is called. The other variant bpf_redirect_map(map, key, flags) uses a new map type called devmap. A devmap uses integers as keys and net_devices as values. The user provies key/ifindex pairs to update the map with new net_devices. This provides two benefits over the normal variant 'bpf_redirect()'. First the datapath bpf program is abstracted away from using hard-coded ifindex values. Allowing a single bpf program to be run any many different environments. Second, and perhaps more important, the map enables batching packet transmits. The map plus small driver changes allows for batching all send requests across a NAPI poll loop. This allows driver writers to optimize the driver xmit path and only call expensive operations once for a batch of xdp_buffs. The devmap was designed to support possible future work for multicast and broadcast as follow-up patches. To see, in more detail, how to leverage the new helpers and map from the userspace side please review these two patches, xdp: sample program for new bpf_redirect helper xdp: bpf redirect with map sample program Performance numbers provided by Jesper are the following, tested using the ixgbe driver with CPU E5-1650 v4 @ 3.60GHz: 13,939,674 pkt/s = XDP_DROP without touching memory 14,290,650 pkt/s = xdp1: XDP_DROP with reading packet data 13,221,812 pkt/s = xdp2: XDP_TX with swap mac (writes into pkt) 7,596,576 pkt/s = xdp_redirect: XDP_REDIRECT with swap mac (like XDP_TX) 13,058,435 pkt/s = xdp_redirect_map:XDP_REDIRECT with swap mac + devmap A big thanks to everyone who helped with this series. Jesper provided fixes, debugging, code review, performance benchmarks! Daniel provided lots of useful feedback and code review. And last but not least Andy provided useful feedback related to supporting additional drivers, generic xdp implementation, testing, etc. Any other feedback is welcome but I believe at this point these are ready to be merged! Whats left... get the rest of the drivers developers to implement this in all the drivers. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents ff65fa6 + 9d6e005 commit 6093ec2

File tree

20 files changed

+1282
-101
lines changed

20 files changed

+1282
-101
lines changed

drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1018,8 +1018,12 @@ static void ixgbe_free_q_vector(struct ixgbe_adapter *adapter, int v_idx)
10181018
struct ixgbe_q_vector *q_vector = adapter->q_vector[v_idx];
10191019
struct ixgbe_ring *ring;
10201020

1021-
ixgbe_for_each_ring(ring, q_vector->tx)
1022-
adapter->tx_ring[ring->queue_index] = NULL;
1021+
ixgbe_for_each_ring(ring, q_vector->tx) {
1022+
if (ring_is_xdp(ring))
1023+
adapter->xdp_ring[ring->queue_index] = NULL;
1024+
else
1025+
adapter->tx_ring[ring->queue_index] = NULL;
1026+
}
10231027

10241028
ixgbe_for_each_ring(ring, q_vector->rx)
10251029
adapter->rx_ring[ring->queue_index] = NULL;

drivers/net/ethernet/intel/ixgbe/ixgbe_main.c

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2214,7 +2214,7 @@ static struct sk_buff *ixgbe_run_xdp(struct ixgbe_adapter *adapter,
22142214
struct ixgbe_ring *rx_ring,
22152215
struct xdp_buff *xdp)
22162216
{
2217-
int result = IXGBE_XDP_PASS;
2217+
int err, result = IXGBE_XDP_PASS;
22182218
struct bpf_prog *xdp_prog;
22192219
u32 act;
22202220

@@ -2231,6 +2231,13 @@ static struct sk_buff *ixgbe_run_xdp(struct ixgbe_adapter *adapter,
22312231
case XDP_TX:
22322232
result = ixgbe_xmit_xdp_ring(adapter, xdp);
22332233
break;
2234+
case XDP_REDIRECT:
2235+
err = xdp_do_redirect(adapter->netdev, xdp, xdp_prog);
2236+
if (!err)
2237+
result = IXGBE_XDP_TX;
2238+
else
2239+
result = IXGBE_XDP_CONSUMED;
2240+
break;
22342241
default:
22352242
bpf_warn_invalid_xdp_action(act);
22362243
/* fallthrough */
@@ -2408,6 +2415,8 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
24082415
*/
24092416
wmb();
24102417
writel(ring->next_to_use, ring->tail);
2418+
2419+
xdp_do_flush_map();
24112420
}
24122421

24132422
u64_stats_update_begin(&rx_ring->syncp);
@@ -5810,6 +5819,9 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
58105819

58115820
usleep_range(10000, 20000);
58125821

5822+
/* synchronize_sched() needed for pending XDP buffers to drain */
5823+
if (adapter->xdp_ring[0])
5824+
synchronize_sched();
58135825
netif_tx_stop_all_queues(netdev);
58145826

58155827
/* call carrier off first to avoid false dev_watchdog timeouts */
@@ -9823,6 +9835,53 @@ static int ixgbe_xdp(struct net_device *dev, struct netdev_xdp *xdp)
98239835
}
98249836
}
98259837

9838+
static int ixgbe_xdp_xmit(struct net_device *dev, struct xdp_buff *xdp)
9839+
{
9840+
struct ixgbe_adapter *adapter = netdev_priv(dev);
9841+
struct ixgbe_ring *ring;
9842+
int err;
9843+
9844+
if (unlikely(test_bit(__IXGBE_DOWN, &adapter->state)))
9845+
return -EINVAL;
9846+
9847+
/* During program transitions its possible adapter->xdp_prog is assigned
9848+
* but ring has not been configured yet. In this case simply abort xmit.
9849+
*/
9850+
ring = adapter->xdp_prog ? adapter->xdp_ring[smp_processor_id()] : NULL;
9851+
if (unlikely(!ring))
9852+
return -EINVAL;
9853+
9854+
err = ixgbe_xmit_xdp_ring(adapter, xdp);
9855+
if (err != IXGBE_XDP_TX)
9856+
return -ENOMEM;
9857+
9858+
return 0;
9859+
}
9860+
9861+
static void ixgbe_xdp_flush(struct net_device *dev)
9862+
{
9863+
struct ixgbe_adapter *adapter = netdev_priv(dev);
9864+
struct ixgbe_ring *ring;
9865+
9866+
/* Its possible the device went down between xdp xmit and flush so
9867+
* we need to ensure device is still up.
9868+
*/
9869+
if (unlikely(test_bit(__IXGBE_DOWN, &adapter->state)))
9870+
return;
9871+
9872+
ring = adapter->xdp_prog ? adapter->xdp_ring[smp_processor_id()] : NULL;
9873+
if (unlikely(!ring))
9874+
return;
9875+
9876+
/* Force memory writes to complete before letting h/w know there
9877+
* are new descriptors to fetch.
9878+
*/
9879+
wmb();
9880+
writel(ring->next_to_use, ring->tail);
9881+
9882+
return;
9883+
}
9884+
98269885
static const struct net_device_ops ixgbe_netdev_ops = {
98279886
.ndo_open = ixgbe_open,
98289887
.ndo_stop = ixgbe_close,
@@ -9869,6 +9928,8 @@ static const struct net_device_ops ixgbe_netdev_ops = {
98699928
.ndo_udp_tunnel_del = ixgbe_del_udp_tunnel_port,
98709929
.ndo_features_check = ixgbe_features_check,
98719930
.ndo_xdp = ixgbe_xdp,
9931+
.ndo_xdp_xmit = ixgbe_xdp_xmit,
9932+
.ndo_xdp_flush = ixgbe_xdp_flush,
98729933
};
98739934

98749935
/**

include/linux/bpf.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,4 +379,9 @@ extern const struct bpf_func_proto bpf_get_stackid_proto;
379379
void bpf_user_rnd_init_once(void);
380380
u64 bpf_user_rnd_u32(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5);
381381

382+
/* Map specifics */
383+
struct net_device *__dev_map_lookup_elem(struct bpf_map *map, u32 key);
384+
void __dev_map_insert_ctx(struct bpf_map *map, u32 index);
385+
void __dev_map_flush(struct bpf_map *map);
386+
382387
#endif /* _LINUX_BPF_H */

include/linux/bpf_types.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,6 @@ BPF_MAP_TYPE(BPF_MAP_TYPE_STACK_TRACE, stack_map_ops)
3535
#endif
3636
BPF_MAP_TYPE(BPF_MAP_TYPE_ARRAY_OF_MAPS, array_of_maps_map_ops)
3737
BPF_MAP_TYPE(BPF_MAP_TYPE_HASH_OF_MAPS, htab_of_maps_map_ops)
38+
#ifdef CONFIG_NET
39+
BPF_MAP_TYPE(BPF_MAP_TYPE_DEVMAP, dev_map_ops)
40+
#endif

include/linux/filter.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -711,7 +711,21 @@ bool bpf_helper_changes_pkt_data(void *func);
711711

712712
struct bpf_prog *bpf_patch_insn_single(struct bpf_prog *prog, u32 off,
713713
const struct bpf_insn *patch, u32 len);
714+
715+
/* The pair of xdp_do_redirect and xdp_do_flush_map MUST be called in the
716+
* same cpu context. Further for best results no more than a single map
717+
* for the do_redirect/do_flush pair should be used. This limitation is
718+
* because we only track one map and force a flush when the map changes.
719+
* This does not appear to be a real limitation for existing software.
720+
*/
721+
int xdp_do_generic_redirect(struct net_device *dev, struct sk_buff *skb);
722+
int xdp_do_redirect(struct net_device *dev,
723+
struct xdp_buff *xdp,
724+
struct bpf_prog *prog);
725+
void xdp_do_flush_map(void);
726+
714727
void bpf_warn_invalid_xdp_action(u32 act);
728+
void bpf_warn_invalid_xdp_redirect(u32 ifindex);
715729

716730
#ifdef CONFIG_BPF_JIT
717731
extern int bpf_jit_enable;

include/linux/netdevice.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ struct mpls_dev;
6666
/* UDP Tunnel offloads */
6767
struct udp_tunnel_info;
6868
struct bpf_prog;
69+
struct xdp_buff;
6970

7071
void netdev_set_default_ethtool_ops(struct net_device *dev,
7172
const struct ethtool_ops *ops);
@@ -1138,7 +1139,12 @@ struct xfrmdev_ops {
11381139
* int (*ndo_xdp)(struct net_device *dev, struct netdev_xdp *xdp);
11391140
* This function is used to set or query state related to XDP on the
11401141
* netdevice. See definition of enum xdp_netdev_command for details.
1141-
*
1142+
* int (*ndo_xdp_xmit)(struct net_device *dev, struct xdp_buff *xdp);
1143+
* This function is used to submit a XDP packet for transmit on a
1144+
* netdevice.
1145+
* void (*ndo_xdp_flush)(struct net_device *dev);
1146+
* This function is used to inform the driver to flush a paticular
1147+
* xpd tx queue. Must be called on same CPU as xdp_xmit.
11421148
*/
11431149
struct net_device_ops {
11441150
int (*ndo_init)(struct net_device *dev);
@@ -1323,6 +1329,9 @@ struct net_device_ops {
13231329
int needed_headroom);
13241330
int (*ndo_xdp)(struct net_device *dev,
13251331
struct netdev_xdp *xdp);
1332+
int (*ndo_xdp_xmit)(struct net_device *dev,
1333+
struct xdp_buff *xdp);
1334+
void (*ndo_xdp_flush)(struct net_device *dev);
13261335
};
13271336

13281337
/**

include/trace/events/xdp.h

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
FN(ABORTED) \
1313
FN(DROP) \
1414
FN(PASS) \
15-
FN(TX)
15+
FN(TX) \
16+
FN(REDIRECT)
1617

1718
#define __XDP_ACT_TP_FN(x) \
1819
TRACE_DEFINE_ENUM(XDP_##x);
@@ -48,6 +49,34 @@ TRACE_EVENT(xdp_exception,
4849
__print_symbolic(__entry->act, __XDP_ACT_SYM_TAB))
4950
);
5051

52+
TRACE_EVENT(xdp_redirect,
53+
54+
TP_PROTO(const struct net_device *from,
55+
const struct net_device *to,
56+
const struct bpf_prog *xdp, u32 act),
57+
58+
TP_ARGS(from, to, xdp, act),
59+
60+
TP_STRUCT__entry(
61+
__string(name_from, from->name)
62+
__string(name_to, to->name)
63+
__array(u8, prog_tag, 8)
64+
__field(u32, act)
65+
),
66+
67+
TP_fast_assign(
68+
BUILD_BUG_ON(sizeof(__entry->prog_tag) != sizeof(xdp->tag));
69+
memcpy(__entry->prog_tag, xdp->tag, sizeof(xdp->tag));
70+
__assign_str(name_from, from->name);
71+
__assign_str(name_to, to->name);
72+
__entry->act = act;
73+
),
74+
75+
TP_printk("prog=%s from=%s to=%s action=%s",
76+
__print_hex_str(__entry->prog_tag, 8),
77+
__get_str(name_from), __get_str(name_to),
78+
__print_symbolic(__entry->act, __XDP_ACT_SYM_TAB))
79+
);
5180
#endif /* _TRACE_XDP_H */
5281

5382
#include <trace/define_trace.h>

include/uapi/linux/bpf.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ enum bpf_map_type {
104104
BPF_MAP_TYPE_LPM_TRIE,
105105
BPF_MAP_TYPE_ARRAY_OF_MAPS,
106106
BPF_MAP_TYPE_HASH_OF_MAPS,
107+
BPF_MAP_TYPE_DEVMAP,
107108
};
108109

109110
enum bpf_prog_type {
@@ -347,6 +348,11 @@ union bpf_attr {
347348
* @flags: bit 0 - if set, redirect to ingress instead of egress
348349
* other bits - reserved
349350
* Return: TC_ACT_REDIRECT
351+
* int bpf_redirect_map(key, map, flags)
352+
* redirect to endpoint in map
353+
* @key: index in map to lookup
354+
* @map: fd of map to do lookup in
355+
* @flags: --
350356
*
351357
* u32 bpf_get_route_realm(skb)
352358
* retrieve a dst's tclassid
@@ -591,7 +597,8 @@ union bpf_attr {
591597
FN(get_socket_uid), \
592598
FN(set_hash), \
593599
FN(setsockopt), \
594-
FN(skb_adjust_room),
600+
FN(skb_adjust_room), \
601+
FN(redirect_map),
595602

596603
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
597604
* function eBPF program intends to call
@@ -717,6 +724,7 @@ enum xdp_action {
717724
XDP_DROP,
718725
XDP_PASS,
719726
XDP_TX,
727+
XDP_REDIRECT,
720728
};
721729

722730
/* user accessible metadata for XDP packet hook

kernel/bpf/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ obj-y := core.o
22

33
obj-$(CONFIG_BPF_SYSCALL) += syscall.o verifier.o inode.o helpers.o
44
obj-$(CONFIG_BPF_SYSCALL) += hashtab.o arraymap.o percpu_freelist.o bpf_lru_list.o lpm_trie.o map_in_map.o
5+
ifeq ($(CONFIG_NET),y)
6+
obj-$(CONFIG_BPF_SYSCALL) += devmap.o
7+
endif
58
ifeq ($(CONFIG_PERF_EVENTS),y)
69
obj-$(CONFIG_BPF_SYSCALL) += stackmap.o
710
endif

0 commit comments

Comments
 (0)