Skip to content

Commit 0399309

Browse files
netoptimizerdavem330
authored andcommitted
xdp: transition into using xdp_frame for return API
Changing API xdp_return_frame() to take struct xdp_frame as argument, seems like a natural choice. But there are some subtle performance details here that needs extra care, which is a deliberate choice. When de-referencing xdp_frame on a remote CPU during DMA-TX completion, result in the cache-line is change to "Shared" state. Later when the page is reused for RX, then this xdp_frame cache-line is written, which change the state to "Modified". This situation already happens (naturally) for, virtio_net, tun and cpumap as the xdp_frame pointer is the queued object. In tun and cpumap, the ptr_ring is used for efficiently transferring cache-lines (with pointers) between CPUs. Thus, the only option is to de-referencing xdp_frame. It is only the ixgbe driver that had an optimization, in which it can avoid doing the de-reference of xdp_frame. The driver already have TX-ring queue, which (in case of remote DMA-TX completion) have to be transferred between CPUs anyhow. In this data area, we stored a struct xdp_mem_info and a data pointer, which allowed us to avoid de-referencing xdp_frame. To compensate for this, a prefetchw is used for telling the cache coherency protocol about our access pattern. My benchmarks show that this prefetchw is enough to compensate the ixgbe driver. V7: Adjust for commit d9314c4 ("i40e: add support for XDP_REDIRECT") V8: Adjust for commit bd658dd ("net/mlx5e: Separate dma base address and offset in dma_sync call") Signed-off-by: Jesper Dangaard Brouer <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 60bbf7e commit 0399309

File tree

9 files changed

+25
-20
lines changed

9 files changed

+25
-20
lines changed

drivers/net/ethernet/intel/i40e/i40e_txrx.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -638,8 +638,7 @@ static void i40e_unmap_and_free_tx_resource(struct i40e_ring *ring,
638638
if (tx_buffer->tx_flags & I40E_TX_FLAGS_FD_SB)
639639
kfree(tx_buffer->raw_buf);
640640
else if (ring_is_xdp(ring))
641-
xdp_return_frame(tx_buffer->xdpf->data,
642-
&tx_buffer->xdpf->mem);
641+
xdp_return_frame(tx_buffer->xdpf);
643642
else
644643
dev_kfree_skb_any(tx_buffer->skb);
645644
if (dma_unmap_len(tx_buffer, len))
@@ -842,7 +841,7 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
842841

843842
/* free the skb/XDP data */
844843
if (ring_is_xdp(tx_ring))
845-
xdp_return_frame(tx_buf->xdpf->data, &tx_buf->xdpf->mem);
844+
xdp_return_frame(tx_buf->xdpf);
846845
else
847846
napi_consume_skb(tx_buf->skb, napi_budget);
848847

drivers/net/ethernet/intel/ixgbe/ixgbe.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -241,16 +241,14 @@ struct ixgbe_tx_buffer {
241241
unsigned long time_stamp;
242242
union {
243243
struct sk_buff *skb;
244-
/* XDP uses address ptr on irq_clean */
245-
void *data;
244+
struct xdp_frame *xdpf;
246245
};
247246
unsigned int bytecount;
248247
unsigned short gso_segs;
249248
__be16 protocol;
250249
DEFINE_DMA_UNMAP_ADDR(dma);
251250
DEFINE_DMA_UNMAP_LEN(len);
252251
u32 tx_flags;
253-
struct xdp_mem_info xdp_mem;
254252
};
255253

256254
struct ixgbe_rx_buffer {

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

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1216,7 +1216,7 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
12161216

12171217
/* free the skb */
12181218
if (ring_is_xdp(tx_ring))
1219-
xdp_return_frame(tx_buffer->data, &tx_buffer->xdp_mem);
1219+
xdp_return_frame(tx_buffer->xdpf);
12201220
else
12211221
napi_consume_skb(tx_buffer->skb, napi_budget);
12221222

@@ -2386,6 +2386,7 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
23862386
xdp.data_hard_start = xdp.data -
23872387
ixgbe_rx_offset(rx_ring);
23882388
xdp.data_end = xdp.data + size;
2389+
prefetchw(xdp.data_hard_start); /* xdp_frame write */
23892390

23902391
skb = ixgbe_run_xdp(adapter, rx_ring, &xdp);
23912392
}
@@ -5797,7 +5798,7 @@ static void ixgbe_clean_tx_ring(struct ixgbe_ring *tx_ring)
57975798

57985799
/* Free all the Tx ring sk_buffs */
57995800
if (ring_is_xdp(tx_ring))
5800-
xdp_return_frame(tx_buffer->data, &tx_buffer->xdp_mem);
5801+
xdp_return_frame(tx_buffer->xdpf);
58015802
else
58025803
dev_kfree_skb_any(tx_buffer->skb);
58035804

@@ -8348,16 +8349,21 @@ static int ixgbe_xmit_xdp_ring(struct ixgbe_adapter *adapter,
83488349
struct ixgbe_ring *ring = adapter->xdp_ring[smp_processor_id()];
83498350
struct ixgbe_tx_buffer *tx_buffer;
83508351
union ixgbe_adv_tx_desc *tx_desc;
8352+
struct xdp_frame *xdpf;
83518353
u32 len, cmd_type;
83528354
dma_addr_t dma;
83538355
u16 i;
83548356

8355-
len = xdp->data_end - xdp->data;
8357+
xdpf = convert_to_xdp_frame(xdp);
8358+
if (unlikely(!xdpf))
8359+
return -EOVERFLOW;
8360+
8361+
len = xdpf->len;
83568362

83578363
if (unlikely(!ixgbe_desc_unused(ring)))
83588364
return IXGBE_XDP_CONSUMED;
83598365

8360-
dma = dma_map_single(ring->dev, xdp->data, len, DMA_TO_DEVICE);
8366+
dma = dma_map_single(ring->dev, xdpf->data, len, DMA_TO_DEVICE);
83618367
if (dma_mapping_error(ring->dev, dma))
83628368
return IXGBE_XDP_CONSUMED;
83638369

@@ -8372,8 +8378,7 @@ static int ixgbe_xmit_xdp_ring(struct ixgbe_adapter *adapter,
83728378

83738379
dma_unmap_len_set(tx_buffer, len, len);
83748380
dma_unmap_addr_set(tx_buffer, dma, dma);
8375-
tx_buffer->data = xdp->data;
8376-
tx_buffer->xdp_mem = xdp->rxq->mem;
8381+
tx_buffer->xdpf = xdpf;
83778382

83788383
tx_desc->read.buffer_addr = cpu_to_le64(dma);
83798384

drivers/net/ethernet/mellanox/mlx5/core/en_rx.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -890,6 +890,7 @@ struct sk_buff *skb_from_cqe(struct mlx5e_rq *rq, struct mlx5_cqe64 *cqe,
890890

891891
dma_sync_single_range_for_cpu(rq->pdev, di->addr, wi->offset,
892892
frag_size, DMA_FROM_DEVICE);
893+
prefetchw(va); /* xdp_frame data area */
893894
prefetch(data);
894895
wi->offset += frag_size;
895896

drivers/net/tun.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -663,7 +663,7 @@ void tun_ptr_free(void *ptr)
663663
if (tun_is_xdp_frame(ptr)) {
664664
struct xdp_frame *xdpf = tun_ptr_to_xdp(ptr);
665665

666-
xdp_return_frame(xdpf->data, &xdpf->mem);
666+
xdp_return_frame(xdpf);
667667
} else {
668668
__skb_array_destroy_skb(ptr);
669669
}
@@ -2196,7 +2196,7 @@ static ssize_t tun_do_read(struct tun_struct *tun, struct tun_file *tfile,
21962196
struct xdp_frame *xdpf = tun_ptr_to_xdp(ptr);
21972197

21982198
ret = tun_put_user_xdp(tun, tfile, xdpf, to);
2199-
xdp_return_frame(xdpf->data, &xdpf->mem);
2199+
xdp_return_frame(xdpf);
22002200
} else {
22012201
struct sk_buff *skb = ptr;
22022202

drivers/net/virtio_net.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ static int __virtnet_xdp_xmit(struct virtnet_info *vi,
430430

431431
/* Free up any pending old buffers before queueing new ones. */
432432
while ((xdpf_sent = virtqueue_get_buf(sq->vq, &len)) != NULL)
433-
xdp_return_frame(xdpf_sent->data, &xdpf_sent->mem);
433+
xdp_return_frame(xdpf_sent);
434434

435435
xdpf = convert_to_xdp_frame(xdp);
436436
if (unlikely(!xdpf))

include/net/xdp.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ struct xdp_frame *convert_to_xdp_frame(struct xdp_buff *xdp)
103103
return xdp_frame;
104104
}
105105

106-
void xdp_return_frame(void *data, struct xdp_mem_info *mem);
106+
void xdp_return_frame(struct xdp_frame *xdpf);
107107

108108
int xdp_rxq_info_reg(struct xdp_rxq_info *xdp_rxq,
109109
struct net_device *dev, u32 queue_index);

kernel/bpf/cpumap.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ static void __cpu_map_ring_cleanup(struct ptr_ring *ring)
219219

220220
while ((xdpf = ptr_ring_consume(ring)))
221221
if (WARN_ON_ONCE(xdpf))
222-
xdp_return_frame(xdpf->data, &xdpf->mem);
222+
xdp_return_frame(xdpf);
223223
}
224224

225225
static void put_cpu_map_entry(struct bpf_cpu_map_entry *rcpu)
@@ -275,7 +275,7 @@ static int cpu_map_kthread_run(void *data)
275275

276276
skb = cpu_map_build_skb(rcpu, xdpf);
277277
if (!skb) {
278-
xdp_return_frame(xdpf->data, &xdpf->mem);
278+
xdp_return_frame(xdpf);
279279
continue;
280280
}
281281

@@ -578,7 +578,7 @@ static int bq_flush_to_queue(struct bpf_cpu_map_entry *rcpu,
578578
err = __ptr_ring_produce(q, xdpf);
579579
if (err) {
580580
drops++;
581-
xdp_return_frame(xdpf->data, &xdpf->mem);
581+
xdp_return_frame(xdpf);
582582
}
583583
processed++;
584584
}

net/core/xdp.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,9 +308,11 @@ int xdp_rxq_info_reg_mem_model(struct xdp_rxq_info *xdp_rxq,
308308
}
309309
EXPORT_SYMBOL_GPL(xdp_rxq_info_reg_mem_model);
310310

311-
void xdp_return_frame(void *data, struct xdp_mem_info *mem)
311+
void xdp_return_frame(struct xdp_frame *xdpf)
312312
{
313+
struct xdp_mem_info *mem = &xdpf->mem;
313314
struct xdp_mem_allocator *xa;
315+
void *data = xdpf->data;
314316
struct page *page;
315317

316318
switch (mem->type) {

0 commit comments

Comments
 (0)