Skip to contentSkip to conversation

mvneta: introduce XDP multi-buffer support

PATCH Superseded Lorenzo Bianconi 7 participants 24 messages Aug 19, 2020 – Aug 26, 2020

Subsystems (24)

v1 of 9 Superseded Latest is v9 →

lore
Share & tools
lore
#0 lore raw

cover mvneta: introduce XDP multi-buffer support

Finalize XDP multi-buffer support for mvneta driver introducing the capability to map non-linear buffers on tx side.
Introduce multi-buffer bit (mb) in xdp_frame/xdp_buffer to specify if shared_info area has been properly initialized.
Initialize multi-buffer bit (mb) to 0 in all XDP-capable drivers. Add multi-buff support to xdp_return_{buff/frame} utility routines.

Changes since RFC:
- squash multi-buffer bit initialization in a single patch
- add mvneta non-linear XDP buff support for tx side

Lorenzo Bianconi (6):
xdp: introduce mb in xdp_buff/xdp_frame
xdp: initialize xdp_buff mb bit to 0 in all XDP drivers
net: mvneta: update mb bit before passing the xdp buffer to eBPF layer
xdp: add multi-buff support to xdp_return_{buff/frame}
net: mvneta: add multi buffer support to XDP_TX
net: mvneta: enable jumbo frames for XDP

 drivers/net/ethernet/amazon/ena/ena_netdev.c  |  1 +
 drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c |  1 +
 .../net/ethernet/cavium/thunder/nicvf_main.c  |  1 +
 .../net/ethernet/freescale/dpaa2/dpaa2-eth.c  |  1 +
 drivers/net/ethernet/intel/i40e/i40e_txrx.c   |  1 +
 drivers/net/ethernet/intel/ice/ice_txrx.c     |  1 +
 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c |  1 +
 .../net/ethernet/intel/ixgbevf/ixgbevf_main.c |  1 +
 drivers/net/ethernet/marvell/mvneta.c         | 92 +++++++++++--------
 .../net/ethernet/marvell/mvpp2/mvpp2_main.c   |  1 +
 drivers/net/ethernet/mellanox/mlx4/en_rx.c    |  1 +
 .../net/ethernet/mellanox/mlx5/core/en_rx.c   |  1 +
 .../ethernet/netronome/nfp/nfp_net_common.c   |  1 +
 drivers/net/ethernet/qlogic/qede/qede_fp.c    |  1 +
 drivers/net/ethernet/sfc/rx.c                 |  1 +
 drivers/net/ethernet/socionext/netsec.c       |  1 +
 drivers/net/ethernet/ti/cpsw.c                |  1 +
 drivers/net/ethernet/ti/cpsw_new.c            |  1 +
 drivers/net/hyperv/netvsc_bpf.c               |  1 +
 drivers/net/tun.c                             |  2 +
 drivers/net/veth.c                            |  1 +
 drivers/net/virtio_net.c                      |  2 +
 drivers/net/xen-netfront.c                    |  1 +
 include/net/xdp.h                             | 25 ++++-
 net/core/dev.c                                |  1 +
 net/core/xdp.c                                | 37 ++++++++
 26 files changed, 135 insertions(+), 44 deletions(-)
Signature · 1 line
2.26.2
#1 lore raw

PATCH 1/6 xdp: introduce mb in xdp_buff/xdp_frame

Introduce multi-buffer bit (mb) in xdp_frame/xdp_buffer to specify if shared_info area has been properly initialized for non-linear xdp buffers

---
 include/net/xdp.h | 8 ++++++--
 net/core/xdp.c    | 1 +
 2 files changed, 7 insertions(+), 2 deletions(-)
include/net/xdp.h +6 -2
index 3814fb631d52..42f439f9fcda 100644
@@ -72,7 +72,8 @@ struct xdp_buff {
 	void *data_hard_start;
 	struct xdp_rxq_info *rxq;
 	struct xdp_txq_info *txq;
-	u32 frame_sz; /* frame size to deduce data_hard_end/reserved tailroom*/
+	u32 frame_sz:31; /* frame size to deduce data_hard_end/reserved tailroom*/
+	u32 mb:1; /* xdp non-linear buffer */
 };
 
 /* Reserve memory area at end-of data area.
@@ -96,7 +97,8 @@ struct xdp_frame {
 	u16 len;
 	u16 headroom;
 	u32 metasize:8;
-	u32 frame_sz:24;
+	u32 frame_sz:23;
+	u32 mb:1; /* xdp non-linear frame */
 	/* Lifetime of xdp_rxq_info is limited to NAPI/enqueue time,
 	 * while mem info is valid on remote CPU.
 	 */
@@ -141,6 +143,7 @@ void xdp_convert_frame_to_buff(struct xdp_frame *frame, struct xdp_buff *xdp)
 	xdp->data_end = frame->data + frame->len;
 	xdp->data_meta = frame->data - frame->metasize;
 	xdp->frame_sz = frame->frame_sz;
+	xdp->mb = frame->mb;
 }
 
 static inline
@@ -167,6 +170,7 @@ int xdp_update_frame_from_buff(struct xdp_buff *xdp,
 	xdp_frame->headroom = headroom - sizeof(*xdp_frame);
 	xdp_frame->metasize = metasize;
 	xdp_frame->frame_sz = xdp->frame_sz;
+	xdp_frame->mb = xdp->mb;
 
 	return 0;
 }
net/core/xdp.c +1 -0
index 48aba933a5a8..884f140fc3be 100644
@@ -454,6 +454,7 @@ struct xdp_frame *xdp_convert_zc_to_xdp_frame(struct xdp_buff *xdp)
 	xdpf->headroom = 0;
 	xdpf->metasize = metasize;
 	xdpf->frame_sz = PAGE_SIZE;
+	xdpf->mb = xdp->mb;
 	xdpf->mem.type = MEM_TYPE_PAGE_ORDER0;
 
 	xsk_buff_free(xdp);
Signature · 1 line
2.26.2
#2 lore raw

Re: [PATCH net-next 1/6] xdp: introduce mb in xdp_buff/xdp_frame

Quoted 27 lines · Lorenzo Bianconi

Introduce multi-buffer bit (mb) in xdp_frame/xdp_buffer to specify if shared_info area has been properly initialized for non-linear xdp buffers

---
 include/net/xdp.h | 8 ++++++--
 net/core/xdp.c    | 1 +
 2 files changed, 7 insertions(+), 2 deletions(-)
include/net/xdp.h +0 -1
index 3814fb631d52..42f439f9fcda 100644
@@ -72,7 +72,8 @@ struct xdp_buff {
 	void *data_hard_start;
 	struct xdp_rxq_info *rxq;
 	struct xdp_txq_info *txq;
-	u32 frame_sz; /* frame size to deduce 

data_hard_end/reserved tailroom*/

include/net/xdp.h +1 -0
+	u32 frame_sz:31; /* frame size to deduce 

data_hard_end/reserved tailroom*/

include/net/xdp.h +1 -0
+	u32 mb:1; /* xdp non-linear buffer */
 };
 
 /* Reserve memory area at end-of data area.

include/net/xdp.h struct xdp_frame { · line 101

Quoted 6 lines
include/net/xdp.h +2 -1
@@ -96,7 +97,8 @@ struct xdp_frame {
 	u16 len;
 	u16 headroom;
 	u32 metasize:8;
-	u32 frame_sz:24;
+	u32 frame_sz:23;
+	u32 mb:1; /* xdp non-linear frame */

Although this issue wasn't introduced with this patch, why not make frame_sz field to be the same size in xdp_buff and xdp_frame ?

thanks,
Shay

Quoted 35 lines
include/net/xdp.h +0 -0
 	/* Lifetime of xdp_rxq_info is limited to NAPI/enqueue 
 time,
 	 * while mem info is valid on remote CPU.
include/net/xdp.h +1 -0
 	 */
@@ -141,6 +143,7 @@ void xdp_convert_frame_to_buff(struct 
 xdp_frame *frame, struct xdp_buff *xdp)
 	xdp->data_end = frame->data + frame->len;
 	xdp->data_meta = frame->data - frame->metasize;
 	xdp->frame_sz = frame->frame_sz;
+	xdp->mb = frame->mb;
 }
 

static inline

include/net/xdp.h +1 -0
@@ -167,6 +170,7 @@ int xdp_update_frame_from_buff(struct 
 xdp_buff *xdp,
 	xdp_frame->headroom = headroom - sizeof(*xdp_frame);
 	xdp_frame->metasize = metasize;
 	xdp_frame->frame_sz = xdp->frame_sz;
+	xdp_frame->mb = xdp->mb;
 
 	return 0;

}

net/core/xdp.c +1 -0
index 48aba933a5a8..884f140fc3be 100644
@@ -454,6 +454,7 @@ struct xdp_frame 
 *xdp_convert_zc_to_xdp_frame(struct xdp_buff *xdp)
 	xdpf->headroom = 0;
 	xdpf->metasize = metasize;
 	xdpf->frame_sz = PAGE_SIZE;
+	xdpf->mb = xdp->mb;
 	xdpf->mem.type = MEM_TYPE_PAGE_ORDER0;
 

xsk_buff_free(xdp);

#3 lore raw

Re: [PATCH net-next 1/6] xdp: introduce mb in xdp_buff/xdp_frame

Quoted 15 lines · On Sun, 23 Aug 2020 17:08:30 +0300 Shay Agroskin <[email protected]> wrote:
Quoted 15 lines
include/net/xdp.h +0 -1
index 3814fb631d52..42f439f9fcda 100644
@@ -72,7 +72,8 @@ struct xdp_buff {
 	void *data_hard_start;
 	struct xdp_rxq_info *rxq;
 	struct xdp_txq_info *txq;
-	u32 frame_sz; /* frame size to deduce 

data_hard_end/reserved tailroom*/

include/net/xdp.h +1 -0
+	u32 frame_sz:31; /* frame size to deduce 

data_hard_end/reserved tailroom*/

include/net/xdp.h +1 -0
+	u32 mb:1; /* xdp non-linear buffer */
 };
Quoted 12 lines

include/net/xdp.h struct xdp_frame { · line 101

Quoted 8 lines

/* Reserve memory area at end-of data area.

include/net/xdp.h +2 -1
@@ -96,7 +97,8 @@ struct xdp_frame {
 	u16 len;
 	u16 headroom;
 	u32 metasize:8;
-	u32 frame_sz:24;
+	u32 frame_sz:23;
+	u32 mb:1; /* xdp non-linear frame */  

Although this issue wasn't introduced with this patch, why not make frame_sz field to be the same size in xdp_buff and xdp_frame ?

This is all about struct layout and saving memory size, due to cacheline access. Please read up on this and use the tool pahole to inspect the struct memory layout.

Signature · 4 lines
Best regards,
  Jesper Dangaard Brouer
  MSc.CS, Principal Kernel Engineer at Red Hat
  LinkedIn: http://www.linkedin.com/in/brouer
#4 lore raw

Re: [PATCH net-next 1/6] xdp: introduce mb in xdp_buff/xdp_frame

Quoted 29 lines · Jesper Dangaard Brouer
Quoted 15 lines · On Sun, 23 Aug 2020 17:08:30 +0300 Shay Agroskin <[email protected]> wrote:
Quoted 15 lines
include/net/xdp.h +0 -1
index 3814fb631d52..42f439f9fcda 100644
@@ -72,7 +72,8 @@ struct xdp_buff {
 	void *data_hard_start;
 	struct xdp_rxq_info *rxq;
 	struct xdp_txq_info *txq;
-	u32 frame_sz; /* frame size to deduce 

data_hard_end/reserved tailroom*/

include/net/xdp.h +1 -0
+	u32 frame_sz:31; /* frame size to deduce 

data_hard_end/reserved tailroom*/

include/net/xdp.h +1 -0
+	u32 mb:1; /* xdp non-linear buffer */
 };
Quoted 10 lines

include/net/xdp.h struct xdp_frame { · line 101

Quoted 8 lines

/* Reserve memory area at end-of data area.

include/net/xdp.h +2 -1
@@ -96,7 +97,8 @@ struct xdp_frame {
 	u16 len;
 	u16 headroom;
 	u32 metasize:8;
-	u32 frame_sz:24;
+	u32 frame_sz:23;
+	u32 mb:1; /* xdp non-linear frame */  

Although this issue wasn't introduced with this patch, why not make frame_sz field to be the same size in xdp_buff and xdp_frame ?

Quoted 3 lines

This is all about struct layout and saving memory size, due to cacheline access. Please read up on this and use the tool pahole to inspect the struct memory layout.

I actually meant reducing the size of frame_sz in xdp_buff (without changing xdp_frame so that it still fits 64 byte cache line). Reducing a field size shouldn't affect cache alignment as far as I can see. Doesn't matter all that much to me, I simply find it a better practice that the same field would have same size in different structs.

Shay

#5 lore raw

PATCH 2/6 xdp: initialize xdp_buff mb bit to 0 in all XDP drivers

In reply to Lorenzo Bianconi

Initialize multi-buffer bit (mb) to 0 in all XDP-capable drivers. This is a preliminary patch to enable xdp multi-buffer support.

---
 drivers/net/ethernet/amazon/ena/ena_netdev.c        | 1 +
 drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c       | 1 +
 drivers/net/ethernet/cavium/thunder/nicvf_main.c    | 1 +
 drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c    | 1 +
 drivers/net/ethernet/intel/i40e/i40e_txrx.c         | 1 +
 drivers/net/ethernet/intel/ice/ice_txrx.c           | 1 +
 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c       | 1 +
 drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c   | 1 +
 drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c     | 1 +
 drivers/net/ethernet/mellanox/mlx4/en_rx.c          | 1 +
 drivers/net/ethernet/mellanox/mlx5/core/en_rx.c     | 1 +
 drivers/net/ethernet/netronome/nfp/nfp_net_common.c | 1 +
 drivers/net/ethernet/qlogic/qede/qede_fp.c          | 1 +
 drivers/net/ethernet/sfc/rx.c                       | 1 +
 drivers/net/ethernet/socionext/netsec.c             | 1 +
 drivers/net/ethernet/ti/cpsw.c                      | 1 +
 drivers/net/ethernet/ti/cpsw_new.c                  | 1 +
 drivers/net/hyperv/netvsc_bpf.c                     | 1 +
 drivers/net/tun.c                                   | 2 ++
 drivers/net/veth.c                                  | 1 +
 drivers/net/virtio_net.c                            | 2 ++
 drivers/net/xen-netfront.c                          | 1 +
 net/core/dev.c                                      | 1 +
 23 files changed, 25 insertions(+)
drivers/net/ethernet/amazon/ena/ena_netdev.c +1 -0
index 2a6c9725e092..02a32196c226 100644
@@ -1607,6 +1607,7 @@ static int ena_clean_rx_irq(struct ena_ring *rx_ring, struct napi_struct *napi,
 	res_budget = budget;
 	xdp.rxq = &rx_ring->xdp_rxq;
 	xdp.frame_sz = ENA_PAGE_SIZE;
+	xdp.mb = 0;
 
 	do {
 		xdp_verdict = XDP_PASS;
drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c +1 -0
index 2704a4709bc7..63dde7a369b7 100644
@@ -139,6 +139,7 @@ bool bnxt_rx_xdp(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, u16 cons,
 	xdp.data_end = *data_ptr + *len;
 	xdp.rxq = &rxr->xdp_rxq;
 	xdp.frame_sz = PAGE_SIZE; /* BNXT_RX_PAGE_MODE(bp) when XDP enabled */
+	xdp.mb = 0;
 	orig_data = xdp.data;
 
 	rcu_read_lock();
drivers/net/ethernet/cavium/thunder/nicvf_main.c +1 -0
index c1378b5c780c..28448033750d 100644
@@ -553,6 +553,7 @@ static inline bool nicvf_xdp_rx(struct nicvf *nic, struct bpf_prog *prog,
 	xdp.data_end = xdp.data + len;
 	xdp.rxq = &rq->xdp_rxq;
 	xdp.frame_sz = RCV_FRAG_LEN + XDP_PACKET_HEADROOM;
+	xdp.mb = 0;
 	orig_data = xdp.data;
 
 	rcu_read_lock();
drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c +1 -0
index 457106e761be..3e7b1cf94c09 100644
@@ -361,6 +361,7 @@ static u32 run_xdp(struct dpaa2_eth_priv *priv,
 
 	xdp.frame_sz = DPAA2_ETH_RX_BUF_RAW_SIZE -
 		(dpaa2_fd_get_offset(fd) - XDP_PACKET_HEADROOM);
+	xdp.mb = 0;
 
 	xdp_act = bpf_prog_run_xdp(xdp_prog, &xdp);
 
drivers/net/ethernet/intel/i40e/i40e_txrx.c +1 -0
index 3e5c566ceb01..7d5a8afa8a4c 100644
@@ -2324,6 +2324,7 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
 	xdp.frame_sz = i40e_rx_frame_truesize(rx_ring, 0);
 #endif
 	xdp.rxq = &rx_ring->xdp_rxq;
+	xdp.mb = 0;
 
 	while (likely(total_rx_packets < (unsigned int)budget)) {
 		struct i40e_rx_buffer *rx_buffer;
drivers/net/ethernet/intel/ice/ice_txrx.c +1 -0
index 9d0d6b0025cf..d96a9525942a 100644
@@ -1095,6 +1095,7 @@ int ice_clean_rx_irq(struct ice_ring *rx_ring, int budget)
 #if (PAGE_SIZE < 8192)
 	xdp.frame_sz = ice_rx_frame_truesize(rx_ring, 0);
 #endif
+	xdp.mb = 0;
 
 	/* start the loop to process Rx packets bounded by 'budget' */
 	while (likely(total_rx_pkts < (unsigned int)budget)) {
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +1 -0
index 2f8a4cfc5fa1..46409f66d04d 100644
@@ -2303,6 +2303,7 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
 #if (PAGE_SIZE < 8192)
 	xdp.frame_sz = ixgbe_rx_frame_truesize(rx_ring, 0);
 #endif
+	xdp.mb = 0;
 
 	while (likely(total_rx_packets < budget)) {
 		union ixgbe_adv_rx_desc *rx_desc;
drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +1 -0
index a428113e6d54..f96fe937f4e9 100644
@@ -1133,6 +1133,7 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
 	struct xdp_buff xdp;
 
 	xdp.rxq = &rx_ring->xdp_rxq;
+	xdp.mb = 0;
 
 	/* Frame size depend on rx_ring setup when PAGE_SIZE=4K */
 #if (PAGE_SIZE < 8192)
drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +1 -0
index 2a8a5842eaef..d02e08eb3df8 100644
@@ -3475,6 +3475,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,
 			xdp.data = data + MVPP2_MH_SIZE + MVPP2_SKB_HEADROOM;
 			xdp.data_end = xdp.data + rx_bytes;
 			xdp.frame_sz = PAGE_SIZE;
+			xdp.mb = 0;
 
 			if (bm_pool->pkt_size == MVPP2_BM_SHORT_PKT_SIZE)
 				xdp.rxq = &rxq->xdp_rxq_short;
drivers/net/ethernet/mellanox/mlx4/en_rx.c +1 -0
index b50c567ef508..0bbc666511ba 100644
@@ -684,6 +684,7 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
 	xdp_prog = rcu_dereference(ring->xdp_prog);
 	xdp.rxq = &ring->xdp_rxq;
 	xdp.frame_sz = priv->frag_info[0].frag_stride;
+	xdp.mb = 0;
 	doorbell_pending = 0;
 
 	/* We assume a 1:1 mapping between CQEs and Rx descriptors, so Rx
drivers/net/ethernet/mellanox/mlx5/core/en_rx.c +1 -0
index 65828af120b7..098e0b47812e 100644
@@ -1121,6 +1121,7 @@ static void mlx5e_fill_xdp_buff(struct mlx5e_rq *rq, void *va, u16 headroom,
 	xdp->data_end = xdp->data + len;
 	xdp->rxq = &rq->xdp_rxq;
 	xdp->frame_sz = rq->buff.frame0_sz;
+	xdp->mb = 0;
 }
 
 static struct sk_buff *
drivers/net/ethernet/netronome/nfp/nfp_net_common.c +1 -0
index 39ee23e8c0bf..0bfccf2a7b1c 100644
@@ -1824,6 +1824,7 @@ static int nfp_net_rx(struct nfp_net_rx_ring *rx_ring, int budget)
 	true_bufsz = xdp_prog ? PAGE_SIZE : dp->fl_bufsz;
 	xdp.frame_sz = PAGE_SIZE - NFP_NET_RX_BUF_HEADROOM;
 	xdp.rxq = &rx_ring->xdp_rxq;
+	xdp.mb = 0;
 	tx_ring = r_vec->xdp_ring;
 
 	while (pkts_polled < budget) {
drivers/net/ethernet/qlogic/qede/qede_fp.c +1 -0
index a2494bf85007..14a54094ca08 100644
@@ -1096,6 +1096,7 @@ static bool qede_rx_xdp(struct qede_dev *edev,
 	xdp.data_end = xdp.data + *len;
 	xdp.rxq = &rxq->xdp_rxq;
 	xdp.frame_sz = rxq->rx_buf_seg_size; /* PAGE_SIZE when XDP enabled */
+	xdp.mb = 0;
 
 	/* Queues always have a full reset currently, so for the time
 	 * being until there's atomic program replace just mark read
drivers/net/ethernet/sfc/rx.c +1 -0
index 59a43d586967..8fd6023995d4 100644
@@ -301,6 +301,7 @@ static bool efx_do_xdp(struct efx_nic *efx, struct efx_channel *channel,
 	xdp.data_end = xdp.data + rx_buf->len;
 	xdp.rxq = &rx_queue->xdp_rxq_info;
 	xdp.frame_sz = efx->rx_page_buf_step;
+	xdp.mb = 0;
 
 	xdp_act = bpf_prog_run_xdp(xdp_prog, &xdp);
 	rcu_read_unlock();
drivers/net/ethernet/socionext/netsec.c +1 -0
index 25db667fa879..c73108ce0a32 100644
@@ -947,6 +947,7 @@ static int netsec_process_rx(struct netsec_priv *priv, int budget)
 
 	xdp.rxq = &dring->xdp_rxq;
 	xdp.frame_sz = PAGE_SIZE;
+	xdp.mb = 0;
 
 	rcu_read_lock();
 	xdp_prog = READ_ONCE(priv->xdp_prog);
drivers/net/ethernet/ti/cpsw.c +1 -0
index 9b17bbbe102f..53a55c540adc 100644
@@ -407,6 +407,7 @@ static void cpsw_rx_handler(void *token, int len, int status)
 		xdp.data_hard_start = pa;
 		xdp.rxq = &priv->xdp_rxq[ch];
 		xdp.frame_sz = PAGE_SIZE;
+		xdp.mb = 0;
 
 		port = priv->emac_port + cpsw->data.dual_emac;
 		ret = cpsw_run_xdp(priv, ch, &xdp, page, port);
drivers/net/ethernet/ti/cpsw_new.c +1 -0
index 1247d35d42ef..703d079fd479 100644
@@ -349,6 +349,7 @@ static void cpsw_rx_handler(void *token, int len, int status)
 		xdp.data_hard_start = pa;
 		xdp.rxq = &priv->xdp_rxq[ch];
 		xdp.frame_sz = PAGE_SIZE;
+		xdp.mb = 0;
 
 		ret = cpsw_run_xdp(priv, ch, &xdp, page, priv->emac_port);
 		if (ret != CPSW_XDP_PASS)
drivers/net/hyperv/netvsc_bpf.c +1 -0
index 440486d9c999..a4bafc64997f 100644
@@ -50,6 +50,7 @@ u32 netvsc_run_xdp(struct net_device *ndev, struct netvsc_channel *nvchan,
 	xdp->data_end = xdp->data + len;
 	xdp->rxq = &nvchan->xdp_rxq;
 	xdp->frame_sz = PAGE_SIZE;
+	xdp->mb = 0;
 
 	memcpy(xdp->data, data, len);
 
drivers/net/tun.c +2 -0
index 3c11a77f5709..317fe5c8db60 100644
@@ -1659,6 +1659,7 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun,
 		xdp.data_end = xdp.data + len;
 		xdp.rxq = &tfile->xdp_rxq;
 		xdp.frame_sz = buflen;
+		xdp.mb = 0;
 
 		act = bpf_prog_run_xdp(xdp_prog, &xdp);
 		if (act == XDP_REDIRECT || act == XDP_TX) {
@@ -2406,6 +2407,7 @@ static int tun_xdp_one(struct tun_struct *tun,
 		xdp_set_data_meta_invalid(xdp);
 		xdp->rxq = &tfile->xdp_rxq;
 		xdp->frame_sz = buflen;
+		xdp->mb = 0;
 
 		act = bpf_prog_run_xdp(xdp_prog, xdp);
 		err = tun_xdp_act(tun, xdp_prog, xdp, act);
drivers/net/veth.c +1 -0
index e56cd562a664..71734f4eb8be 100644
@@ -711,6 +711,7 @@ static struct sk_buff *veth_xdp_rcv_skb(struct veth_rq *rq,
 	/* SKB "head" area always have tailroom for skb_shared_info */
 	xdp.frame_sz = (void *)skb_end_pointer(skb) - xdp.data_hard_start;
 	xdp.frame_sz += SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+	xdp.mb = 0;
 
 	orig_data = xdp.data;
 	orig_data_end = xdp.data_end;
drivers/net/virtio_net.c +2 -0
index 0ada48edf749..3bee68f59e19 100644
@@ -690,6 +690,7 @@ static struct sk_buff *receive_small(struct net_device *dev,
 		xdp.data_meta = xdp.data;
 		xdp.rxq = &rq->xdp_rxq;
 		xdp.frame_sz = buflen;
+		xdp.mb = 0;
 		orig_data = xdp.data;
 		act = bpf_prog_run_xdp(xdp_prog, &xdp);
 		stats->xdp_packets++;
@@ -860,6 +861,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
 		xdp.data_meta = xdp.data;
 		xdp.rxq = &rq->xdp_rxq;
 		xdp.frame_sz = frame_sz - vi->hdr_len;
+		xdp.mb = 0;
 
 		act = bpf_prog_run_xdp(xdp_prog, &xdp);
 		stats->xdp_packets++;
drivers/net/xen-netfront.c +1 -0
index 458be6882b98..02ed7f26097d 100644
@@ -870,6 +870,7 @@ static u32 xennet_run_xdp(struct netfront_queue *queue, struct page *pdata,
 	xdp->data_end = xdp->data + len;
 	xdp->rxq = &queue->xdp_rxq;
 	xdp->frame_sz = XEN_PAGE_SIZE - XDP_PACKET_HEADROOM;
+	xdp->mb = 0;
 
 	act = bpf_prog_run_xdp(prog, xdp);
 	switch (act) {
net/core/dev.c +1 -0
index 7df6c9617321..a00aa737ce29 100644
@@ -4639,6 +4639,7 @@ static u32 netif_receive_generic_xdp(struct sk_buff *skb,
 	/* SKB "head" area always have tailroom for skb_shared_info */
 	xdp->frame_sz  = (void *)skb_end_pointer(skb) - xdp->data_hard_start;
 	xdp->frame_sz += SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+	xdp->mb = 0;
 
 	orig_data_end = xdp->data_end;
 	orig_data = xdp->data;
Signature · 1 line
2.26.2
#6 lore raw

PATCH 3/6 net: mvneta: update mb bit before passing the xdp buffer to eBPF layer

In reply to Lorenzo Bianconi

Update multi-buffer bit (mb) in xdp_buff to notify XDP/eBPF layer and XDP remote drivers if this is a "non-linear" XDP buffer

---
 drivers/net/ethernet/marvell/mvneta.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/net/ethernet/marvell/mvneta.c +3 -0
index 832bbb8b05c8..36a3defa63fa 100644
@@ -2170,11 +2170,14 @@ mvneta_run_xdp(struct mvneta_port *pp, struct mvneta_rx_queue *rxq,
 	       struct bpf_prog *prog, struct xdp_buff *xdp,
 	       u32 frame_sz, struct mvneta_stats *stats)
 {
+	struct skb_shared_info *sinfo = xdp_get_shared_info_from_buff(xdp);
 	unsigned int len, data_len, sync;
 	u32 ret, act;
 
 	len = xdp->data_end - xdp->data_hard_start - pp->rx_offset_correction;
 	data_len = xdp->data_end - xdp->data;
+
+	xdp->mb = !!sinfo->nr_frags;
 	act = bpf_prog_run_xdp(prog, xdp);
 
 	/* Due xdp_adjust_tail: DMA sync for_device cover max len CPU touch */
Signature · 1 line
2.26.2
#7 lore raw

Re: [PATCH net-next 3/6] net: mvneta: update mb bit before passing the xdp buffer to eBPF layer

Quoted 15 lines · On Wed, 19 Aug 2020 15:13:48 +0200 Lorenzo Bianconi <[email protected]> wrote:

Update multi-buffer bit (mb) in xdp_buff to notify XDP/eBPF layer and XDP remote drivers if this is a "non-linear" XDP buffer

---
 drivers/net/ethernet/marvell/mvneta.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/net/ethernet/marvell/mvneta.c +0 -0
index 832bbb8b05c8..36a3defa63fa 100644
@@ -2170,11 +2170,14 @@ mvneta_run_xdp(struct mvneta_port *pp, struct mvneta_rx_queue *rxq,
 	       struct bpf_prog *prog, struct xdp_buff *xdp,
 	       u32 frame_sz, struct mvneta_stats *stats)

drivers/net/ethernet/marvell/mvneta.c mvneta_run_xdp(struct mvneta_port *pp, struct mvneta_rx_queue *rxq, · line 2181

Quoted 10 lines
drivers/net/ethernet/marvell/mvneta.c +3 -0
 {
+	struct skb_shared_info *sinfo = xdp_get_shared_info_from_buff(xdp);
 	unsigned int len, data_len, sync;
 	u32 ret, act;
 
 	len = xdp->data_end - xdp->data_hard_start - pp->rx_offset_correction;
 	data_len = xdp->data_end - xdp->data;
+
+	xdp->mb = !!sinfo->nr_frags;
 	act = bpf_prog_run_xdp(prog, xdp);

Reading the memory sinfo->nr_frags could be a performance issue for our baseline case of no-multi-buffer. As you are reading a cache-line that you don't need to (and driver have not touch yet).

Signature · 4 lines
Best regards,
  Jesper Dangaard Brouer
  MSc.CS, Principal Kernel Engineer at Red Hat
  LinkedIn: http://www.linkedin.com/in/brouer
#8 lore raw

Re: [PATCH net-next 3/6] net: mvneta: update mb bit before passing the xdp buffer to eBPF layer

Quoted 23 lines
Quoted 20 lines · On Wed, 19 Aug 2020 15:13:48 +0200 Lorenzo Bianconi <[email protected]> wrote:

Update multi-buffer bit (mb) in xdp_buff to notify XDP/eBPF layer and XDP remote drivers if this is a "non-linear" XDP buffer

---
 drivers/net/ethernet/marvell/mvneta.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/net/ethernet/marvell/mvneta.c +1 -0
index 832bbb8b05c8..36a3defa63fa 100644
@@ -2170,11 +2170,14 @@ mvneta_run_xdp(struct mvneta_port *pp, struct mvneta_rx_queue *rxq,
 	       struct bpf_prog *prog, struct xdp_buff *xdp,
 	       u32 frame_sz, struct mvneta_stats *stats)
 {
+	struct skb_shared_info *sinfo = xdp_get_shared_info_from_buff(xdp);
 	unsigned int len, data_len, sync;
 	u32 ret, act;
 
Quoted 9 lines

drivers/net/ethernet/marvell/mvneta.c mvneta_run_xdp(struct mvneta_port *pp, struct mvneta_rx_queue *rxq, · line 2181

Quoted 5 lines
drivers/net/ethernet/marvell/mvneta.c +2 -0
 	len = xdp->data_end - xdp->data_hard_start - pp->rx_offset_correction;
 	data_len = xdp->data_end - xdp->data;
+
+	xdp->mb = !!sinfo->nr_frags;
 	act = bpf_prog_run_xdp(prog, xdp);

Reading the memory sinfo->nr_frags could be a performance issue for our baseline case of no-multi-buffer. As you are reading a cache-line that you don't need to (and driver have not touch yet).

ack, I will rework it in v2 to remove this access.

Regards,
Lorenzo

Quoted 7 lines
Signature · 5 lines
-- 
Best regards,
  Jesper Dangaard Brouer
  MSc.CS, Principal Kernel Engineer at Red Hat
  LinkedIn: http://www.linkedin.com/in/brouer
#9 lore raw

Re: [PATCH net-next 3/6] net: mvneta: update mb bit before passing the xdp buffer to eBPF layer

In reply to Lorenzo Bianconi
Quoted 14 lines · Lorenzo Bianconi

Update multi-buffer bit (mb) in xdp_buff to notify XDP/eBPF layer and XDP remote drivers if this is a "non-linear" XDP buffer

---
 drivers/net/ethernet/marvell/mvneta.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/net/ethernet/marvell/mvneta.c +0 -0
index 832bbb8b05c8..36a3defa63fa 100644
@@ -2170,11 +2170,14 @@ mvneta_run_xdp(struct mvneta_port *pp, struct mvneta_rx_queue *rxq,
 	       struct bpf_prog *prog, struct xdp_buff *xdp,

drivers/net/ethernet/marvell/mvneta.c mvneta_run_xdp(struct mvneta_port *pp, struct mvneta_rx_queue *rxq, · line 2180

Quoted 10 lines
drivers/net/ethernet/marvell/mvneta.c +3 -0
 	       u32 frame_sz, struct mvneta_stats *stats)
 {
+	struct skb_shared_info *sinfo = xdp_get_shared_info_from_buff(xdp);
 	unsigned int len, data_len, sync;
 	u32 ret, act;
 
 	len = xdp->data_end - xdp->data_hard_start - pp->rx_offset_correction;
 	data_len = xdp->data_end - xdp->data;
+
+	xdp->mb = !!sinfo->nr_frags;

But this set is not utilizing it from BPF side in any way. Personally I would like to see this as a part of work where BPF program would actually be taught how to rely on xdp->mb. Especially after John's comment in other patch.

Quoted 6 lines
drivers/net/ethernet/marvell/mvneta.c +0 -0
 	act = bpf_prog_run_xdp(prog, xdp);
 
 	/* Due xdp_adjust_tail: DMA sync for_device cover max len CPU touch */
Signature · 1 line
2.26.2
#10 lore raw

Re: [PATCH net-next 3/6] net: mvneta: update mb bit before passing the xdp buffer to eBPF layer

Quoted 21 lines · Maciej Fijalkowski
Quoted 20 lines · Lorenzo Bianconi

Update multi-buffer bit (mb) in xdp_buff to notify XDP/eBPF layer and XDP remote drivers if this is a "non-linear" XDP buffer

---
 drivers/net/ethernet/marvell/mvneta.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/net/ethernet/marvell/mvneta.c +1 -0
index 832bbb8b05c8..36a3defa63fa 100644
@@ -2170,11 +2170,14 @@ mvneta_run_xdp(struct mvneta_port *pp, struct mvneta_rx_queue *rxq,
 	       struct bpf_prog *prog, struct xdp_buff *xdp,
 	       u32 frame_sz, struct mvneta_stats *stats)
 {
+	struct skb_shared_info *sinfo = xdp_get_shared_info_from_buff(xdp);
 	unsigned int len, data_len, sync;
 	u32 ret, act;
 
Quoted 10 lines

drivers/net/ethernet/marvell/mvneta.c mvneta_run_xdp(struct mvneta_port *pp, struct mvneta_rx_queue *rxq, · line 2180

Quoted 4 lines
drivers/net/ethernet/marvell/mvneta.c +2 -0
 	len = xdp->data_end - xdp->data_hard_start - pp->rx_offset_correction;
 	data_len = xdp->data_end - xdp->data;
+
+	xdp->mb = !!sinfo->nr_frags;

But this set is not utilizing it from BPF side in any way. Personally I would like to see this as a part of work where BPF program would actually be taught how to rely on xdp->mb. Especially after John's comment in other patch.

Sameeh is working on them. I did not include the patches since IMO they are not strictly related to this series. I will include Sameeh's patches in v2.

Regards,
Lorenzo

Quoted 7 lines
Quoted 6 lines
drivers/net/ethernet/marvell/mvneta.c +0 -0
 	act = bpf_prog_run_xdp(prog, xdp);
 
 	/* Due xdp_adjust_tail: DMA sync for_device cover max len CPU touch */
Signature · 1 line
2.26.2
#11 lore raw

PATCH 4/6 xdp: add multi-buff support to xdp_return_{buff/frame}

In reply to Lorenzo Bianconi

Take into account if the received xdp_buff/xdp_frame is non-linear recycling/returning the frame memory to the allocator

---
 include/net/xdp.h | 17 +++++++++++++++--
 net/core/xdp.c    | 36 ++++++++++++++++++++++++++++++++++++
 2 files changed, 51 insertions(+), 2 deletions(-)
include/net/xdp.h +15 -2
index 42f439f9fcda..37c4522fc1bb 100644
@@ -208,10 +208,23 @@ void __xdp_release_frame(void *data, struct xdp_mem_info *mem);
 static inline void xdp_release_frame(struct xdp_frame *xdpf)
 {
 	struct xdp_mem_info *mem = &xdpf->mem;
+	struct skb_shared_info *sinfo;
+	int i;
 
 	/* Curr only page_pool needs this */
-	if (mem->type == MEM_TYPE_PAGE_POOL)
-		__xdp_release_frame(xdpf->data, mem);
+	if (mem->type != MEM_TYPE_PAGE_POOL)
+		return;
+
+	__xdp_release_frame(xdpf->data, mem);
+	if (!xdpf->mb)
+		return;
+
+	sinfo = xdp_get_shared_info_from_frame(xdpf);
+	for (i = 0; i < sinfo->nr_frags; i++) {
+		struct page *page = skb_frag_page(&sinfo->frags[i]);
+
+		__xdp_release_frame(page_address(page), mem);
+	}
 }
 
 int xdp_rxq_info_reg(struct xdp_rxq_info *xdp_rxq,
net/core/xdp.c +36 -0
index 884f140fc3be..006b24b5d276 100644
@@ -370,19 +370,55 @@ static void __xdp_return(void *data, struct xdp_mem_info *mem, bool napi_direct)
 
 void xdp_return_frame(struct xdp_frame *xdpf)
 {
+	struct skb_shared_info *sinfo;
+	int i;
+
 	__xdp_return(xdpf->data, &xdpf->mem, false);
+	if (!xdpf->mb)
+		return;
+
+	sinfo = xdp_get_shared_info_from_frame(xdpf);
+	for (i = 0; i < sinfo->nr_frags; i++) {
+		struct page *page = skb_frag_page(&sinfo->frags[i]);
+
+		__xdp_return(page_address(page), &xdpf->mem, false);
+	}
 }
 EXPORT_SYMBOL_GPL(xdp_return_frame);
 
 void xdp_return_frame_rx_napi(struct xdp_frame *xdpf)
 {
+	struct skb_shared_info *sinfo;
+	int i;
+
 	__xdp_return(xdpf->data, &xdpf->mem, true);
+	if (!xdpf->mb)
+		return;
+
+	sinfo = xdp_get_shared_info_from_frame(xdpf);
+	for (i = 0; i < sinfo->nr_frags; i++) {
+		struct page *page = skb_frag_page(&sinfo->frags[i]);
+
+		__xdp_return(page_address(page), &xdpf->mem, true);
+	}
 }
 EXPORT_SYMBOL_GPL(xdp_return_frame_rx_napi);
 
 void xdp_return_buff(struct xdp_buff *xdp)
 {
+	struct skb_shared_info *sinfo;
+	int i;
+
 	__xdp_return(xdp->data, &xdp->rxq->mem, true);
+	if (!xdp->mb)
+		return;
+
+	sinfo = xdp_get_shared_info_from_buff(xdp);
+	for (i = 0; i < sinfo->nr_frags; i++) {
+		struct page *page = skb_frag_page(&sinfo->frags[i]);
+
+		__xdp_return(page_address(page), &xdp->rxq->mem, true);
+	}
 }
 
 /* Only called for MEM_TYPE_PAGE_POOL see xdp.h */
Signature · 1 line
2.26.2
#12 lore raw

Re: [PATCH net-next 4/6] xdp: add multi-buff support to xdp_return_{buff/frame}

net/core/xdp.c static void __xdp_return(void *data, struct xdp_mem_info *mem, bool napi_direct) · line 376

Quoted 12 lines · On Wed, 19 Aug 2020 15:13:49 +0200 Lorenzo Bianconi <[email protected]> wrote:
net/core/xdp.c +3 -0
index 884f140fc3be..006b24b5d276 100644
@@ -370,19 +370,55 @@ static void __xdp_return(void *data, struct xdp_mem_info *mem, bool napi_direct)
 
 void xdp_return_frame(struct xdp_frame *xdpf)
 {
+	struct skb_shared_info *sinfo;
+	int i;
+
 	__xdp_return(xdpf->data, &xdpf->mem, false);

There is a use-after-free race here. The xdpf->data contains the shared_info (xdp_get_shared_info_from_frame(xdpf)). Thus you cannot free/return the page and use this data area below.

Quoted 8 lines
net/core/xdp.c +8 -0
+	if (!xdpf->mb)
+		return;
+
+	sinfo = xdp_get_shared_info_from_frame(xdpf);
+	for (i = 0; i < sinfo->nr_frags; i++) {
+		struct page *page = skb_frag_page(&sinfo->frags[i]);
+
+		__xdp_return(page_address(page), &xdpf->mem, false);

net/core/xdp.c static void __xdp_return(void *data, struct xdp_mem_info *mem, bool napi_direct) · line 394

Quoted 10 lines
net/core/xdp.c +4 -0
+	}
 }
 EXPORT_SYMBOL_GPL(xdp_return_frame);
 
 void xdp_return_frame_rx_napi(struct xdp_frame *xdpf)
 {
+	struct skb_shared_info *sinfo;
+	int i;
+
 	__xdp_return(xdpf->data, &xdpf->mem, true);

Same issue.

Quoted 8 lines
net/core/xdp.c +8 -0
+	if (!xdpf->mb)
+		return;
+
+	sinfo = xdp_get_shared_info_from_frame(xdpf);
+	for (i = 0; i < sinfo->nr_frags; i++) {
+		struct page *page = skb_frag_page(&sinfo->frags[i]);
+
+		__xdp_return(page_address(page), &xdpf->mem, true);

net/core/xdp.c static void __xdp_return(void *data, struct xdp_mem_info *mem, bool napi_direct) · line 412

Quoted 10 lines
net/core/xdp.c +4 -0
+	}
 }
 EXPORT_SYMBOL_GPL(xdp_return_frame_rx_napi);
 
 void xdp_return_buff(struct xdp_buff *xdp)
 {
+	struct skb_shared_info *sinfo;
+	int i;
+
 	__xdp_return(xdp->data, &xdp->rxq->mem, true);

Same issue.

Quoted 10 lines
net/core/xdp.c +9 -0
+	if (!xdp->mb)
+		return;
+
+	sinfo = xdp_get_shared_info_from_buff(xdp);
+	for (i = 0; i < sinfo->nr_frags; i++) {
+		struct page *page = skb_frag_page(&sinfo->frags[i]);
+
+		__xdp_return(page_address(page), &xdp->rxq->mem, true);
+	}
 }
Signature · 4 lines
Best regards,
  Jesper Dangaard Brouer
  MSc.CS, Principal Kernel Engineer at Red Hat
  LinkedIn: http://www.linkedin.com/in/brouer
#13 lore raw

Re: [PATCH net-next 4/6] xdp: add multi-buff support to xdp_return_{buff/frame}

Quoted 9 lines
Quoted 6 lines · On Wed, 19 Aug 2020 15:13:49 +0200 Lorenzo Bianconi <[email protected]> wrote:
net/core/xdp.c +0 -0
index 884f140fc3be..006b24b5d276 100644
@@ -370,19 +370,55 @@ static void __xdp_return(void *data, struct xdp_mem_info *mem, bool napi_direct)
 
Quoted 10 lines

net/core/xdp.c static void __xdp_return(void *data, struct xdp_mem_info *mem, bool napi_direct) · line 376

Quoted 6 lines
net/core/xdp.c +3 -0
 void xdp_return_frame(struct xdp_frame *xdpf)
 {
+	struct skb_shared_info *sinfo;
+	int i;
+
 	__xdp_return(xdpf->data, &xdpf->mem, false);

There is a use-after-free race here. The xdpf->data contains the shared_info (xdp_get_shared_info_from_frame(xdpf)). Thus you cannot free/return the page and use this data area below.

right, thx for pointing this out. I will fix it in v2.

Regards,
Lorenzo

Quoted 62 lines
Quoted 9 lines
net/core/xdp.c +8 -0
+	if (!xdpf->mb)
+		return;
+
+	sinfo = xdp_get_shared_info_from_frame(xdpf);
+	for (i = 0; i < sinfo->nr_frags; i++) {
+		struct page *page = skb_frag_page(&sinfo->frags[i]);
+
+		__xdp_return(page_address(page), &xdpf->mem, false);

net/core/xdp.c static void __xdp_return(void *data, struct xdp_mem_info *mem, bool napi_direct) · line 394

Quoted 10 lines
net/core/xdp.c +4 -0
+	}
 }
 EXPORT_SYMBOL_GPL(xdp_return_frame);
 
 void xdp_return_frame_rx_napi(struct xdp_frame *xdpf)
 {
+	struct skb_shared_info *sinfo;
+	int i;
+
 	__xdp_return(xdpf->data, &xdpf->mem, true);

Same issue.

Quoted 8 lines
net/core/xdp.c +8 -0
+	if (!xdpf->mb)
+		return;
+
+	sinfo = xdp_get_shared_info_from_frame(xdpf);
+	for (i = 0; i < sinfo->nr_frags; i++) {
+		struct page *page = skb_frag_page(&sinfo->frags[i]);
+
+		__xdp_return(page_address(page), &xdpf->mem, true);

net/core/xdp.c static void __xdp_return(void *data, struct xdp_mem_info *mem, bool napi_direct) · line 412

Quoted 10 lines
net/core/xdp.c +4 -0
+	}
 }
 EXPORT_SYMBOL_GPL(xdp_return_frame_rx_napi);
 
 void xdp_return_buff(struct xdp_buff *xdp)
 {
+	struct skb_shared_info *sinfo;
+	int i;
+
 	__xdp_return(xdp->data, &xdp->rxq->mem, true);

Same issue.

Quoted 10 lines
net/core/xdp.c +9 -0
+	if (!xdp->mb)
+		return;
+
+	sinfo = xdp_get_shared_info_from_buff(xdp);
+	for (i = 0; i < sinfo->nr_frags; i++) {
+		struct page *page = skb_frag_page(&sinfo->frags[i]);
+
+		__xdp_return(page_address(page), &xdp->rxq->mem, true);
+	}
 }
Signature · 4 lines
Best regards,
  Jesper Dangaard Brouer
  MSc.CS, Principal Kernel Engineer at Red Hat
  LinkedIn: http://www.linkedin.com/in/brouer
#14 lore raw

PATCH 5/6 net: mvneta: add multi buffer support to XDP_TX

In reply to Lorenzo Bianconi

Introduce the capability to map non-linear xdp buffer running mvneta_xdp_submit_frame() for XDP_TX and XDP_REDIRECT

---
 drivers/net/ethernet/marvell/mvneta.c | 79 +++++++++++++++++----------
 1 file changed, 49 insertions(+), 30 deletions(-)
drivers/net/ethernet/marvell/mvneta.c +49 -30
index 36a3defa63fa..efac4a5e0439 100644
@@ -1854,8 +1854,8 @@ static void mvneta_txq_bufs_free(struct mvneta_port *pp,
 			bytes_compl += buf->skb->len;
 			pkts_compl++;
 			dev_kfree_skb_any(buf->skb);
-		} else if (buf->type == MVNETA_TYPE_XDP_TX ||
-			   buf->type == MVNETA_TYPE_XDP_NDO) {
+		} else if ((buf->type == MVNETA_TYPE_XDP_TX ||
+			    buf->type == MVNETA_TYPE_XDP_NDO) && buf->xdpf) {
 			xdp_return_frame(buf->xdpf);
 		}
 	}
@@ -2040,43 +2040,62 @@ static int
 mvneta_xdp_submit_frame(struct mvneta_port *pp, struct mvneta_tx_queue *txq,
 			struct xdp_frame *xdpf, bool dma_map)
 {
-	struct mvneta_tx_desc *tx_desc;
-	struct mvneta_tx_buf *buf;
-	dma_addr_t dma_addr;
+	struct skb_shared_info *sinfo = xdp_get_shared_info_from_frame(xdpf);
+	int i, num_frames = xdpf->mb ? sinfo->nr_frags + 1 : 1;
+	struct mvneta_tx_desc *tx_desc = NULL;
+	struct page *page;
 
-	if (txq->count >= txq->tx_stop_threshold)
+	if (txq->count + num_frames >= txq->tx_stop_threshold)
 		return MVNETA_XDP_DROPPED;
 
-	tx_desc = mvneta_txq_next_desc_get(txq);
+	for (i = 0; i < num_frames; i++) {
+		struct mvneta_tx_buf *buf = &txq->buf[txq->txq_put_index];
+		skb_frag_t *frag = i ? &sinfo->frags[i - 1] : NULL;
+		int len = frag ? skb_frag_size(frag) : xdpf->len;
+		dma_addr_t dma_addr;
 
-	buf = &txq->buf[txq->txq_put_index];
-	if (dma_map) {
-		/* ndo_xdp_xmit */
-		dma_addr = dma_map_single(pp->dev->dev.parent, xdpf->data,
-					  xdpf->len, DMA_TO_DEVICE);
-		if (dma_mapping_error(pp->dev->dev.parent, dma_addr)) {
-			mvneta_txq_desc_put(txq);
-			return MVNETA_XDP_DROPPED;
+		tx_desc = mvneta_txq_next_desc_get(txq);
+		if (dma_map) {
+			/* ndo_xdp_xmit */
+			void *data;
+
+			data = frag ? page_address(skb_frag_page(frag))
+				    : xdpf->data;
+			dma_addr = dma_map_single(pp->dev->dev.parent, data,
+						  len, DMA_TO_DEVICE);
+			if (dma_mapping_error(pp->dev->dev.parent, dma_addr)) {
+				for (; i >= 0; i--)
+					mvneta_txq_desc_put(txq);
+				return MVNETA_XDP_DROPPED;
+			}
+			buf->type = MVNETA_TYPE_XDP_NDO;
+		} else {
+			page = frag ? skb_frag_page(frag)
+				    : virt_to_page(xdpf->data);
+			dma_addr = page_pool_get_dma_addr(page);
+			if (!frag)
+				dma_addr += sizeof(*xdpf) + xdpf->headroom;
+			dma_sync_single_for_device(pp->dev->dev.parent,
+						   dma_addr, len,
+						   DMA_BIDIRECTIONAL);
+			buf->type = MVNETA_TYPE_XDP_TX;
 		}
-		buf->type = MVNETA_TYPE_XDP_NDO;
-	} else {
-		struct page *page = virt_to_page(xdpf->data);
+		buf->xdpf = i ? NULL : xdpf;
 
-		dma_addr = page_pool_get_dma_addr(page) +
-			   sizeof(*xdpf) + xdpf->headroom;
-		dma_sync_single_for_device(pp->dev->dev.parent, dma_addr,
-					   xdpf->len, DMA_BIDIRECTIONAL);
-		buf->type = MVNETA_TYPE_XDP_TX;
+		if (!i)
+			tx_desc->command = MVNETA_TXD_F_DESC;
+		tx_desc->buf_phys_addr = dma_addr;
+		tx_desc->data_size = len;
+
+		mvneta_txq_inc_put(txq);
 	}
-	buf->xdpf = xdpf;
 
-	tx_desc->command = MVNETA_TXD_FLZ_DESC;
-	tx_desc->buf_phys_addr = dma_addr;
-	tx_desc->data_size = xdpf->len;
+	/*last descriptor */
+	if (tx_desc)
+		tx_desc->command |= MVNETA_TXD_L_DESC | MVNETA_TXD_Z_PAD;
 
-	mvneta_txq_inc_put(txq);
-	txq->pending++;
-	txq->count++;
+	txq->pending += num_frames;
+	txq->count += num_frames;
 
 	return MVNETA_XDP_TX;
 }
Signature · 1 line
2.26.2
#15 lore raw

PATCH 6/6 net: mvneta: enable jumbo frames for XDP

In reply to Lorenzo Bianconi

Enable the capability to receive jumbo frames even if the interface is running in XDP mode

---
 drivers/net/ethernet/marvell/mvneta.c | 10 ----------
 1 file changed, 10 deletions(-)
drivers/net/ethernet/marvell/mvneta.c +0 -10
index efac4a5e0439..42f7614cd67c 100644
@@ -3735,11 +3735,6 @@ static int mvneta_change_mtu(struct net_device *dev, int mtu)
 		mtu = ALIGN(MVNETA_RX_PKT_SIZE(mtu), 8);
 	}
 
-	if (pp->xdp_prog && mtu > MVNETA_MAX_RX_BUF_SIZE) {
-		netdev_info(dev, "Illegal MTU value %d for XDP mode\n", mtu);
-		return -EINVAL;
-	}
-
 	dev->mtu = mtu;
 
 	if (!netif_running(dev)) {
@@ -4437,11 +4432,6 @@ static int mvneta_xdp_setup(struct net_device *dev, struct bpf_prog *prog,
 	struct mvneta_port *pp = netdev_priv(dev);
 	struct bpf_prog *old_prog;
 
-	if (prog && dev->mtu > MVNETA_MAX_RX_BUF_SIZE) {
-		NL_SET_ERR_MSG_MOD(extack, "Jumbo frames not supported on XDP");
-		return -EOPNOTSUPP;
-	}
-
 	if (pp->bm_priv) {
 		NL_SET_ERR_MSG_MOD(extack,
 				   "Hardware Buffer Management not supported on XDP");
Signature · 1 line
2.26.2
maintainer
#16 lore raw

Re: [PATCH net-next 6/6] net: mvneta: enable jumbo frames for XDP

Quoted 4 lines · On Wed, 19 Aug 2020 15:13:51 +0200 Lorenzo Bianconi wrote:

Enable the capability to receive jumbo frames even if the interface is running in XDP mode

Hm, already? Is all the infra in place? Or does it not imply multi-buffer.

#17 lore raw

Re: [PATCH net-next 6/6] net: mvneta: enable jumbo frames for XDP

Quoted 9 lines · On Wed, 19 Aug 2020 15:13:51 +0200 Lorenzo Bianconi wrote:
Quoted 4 lines

Enable the capability to receive jumbo frames even if the interface is running in XDP mode

Hm, already? Is all the infra in place? Or does it not imply multi-buffer.

Hi Jakub,

with this series mvneta supports xdp multi-buff on both rx and tx sides (XDP_TX and ndo_xpd_xmit()) so we can remove MTU limitation.

Regards,
Lorenzo

maintainer
#18 lore raw

Re: [PATCH net-next 6/6] net: mvneta: enable jumbo frames for XDP

Quoted 11 lines · On Wed, 19 Aug 2020 22:22:23 +0200 Lorenzo Bianconi wrote:
Quoted 8 lines · On Wed, 19 Aug 2020 15:13:51 +0200 Lorenzo Bianconi wrote:
Quoted 4 lines

Enable the capability to receive jumbo frames even if the interface is running in XDP mode

Hm, already? Is all the infra in place? Or does it not imply multi-buffer.

with this series mvneta supports xdp multi-buff on both rx and tx sides (XDP_TX and ndo_xpd_xmit()) so we can remove MTU limitation.

Is there an API for programs to access the multi-buf frames?

maintainer
#19 lore raw

Re: [PATCH net-next 6/6] net: mvneta: enable jumbo frames for XDP

Quoted 7 lines · Jakub Kicinski
Quoted 6 lines · On Wed, 19 Aug 2020 22:22:23 +0200 Lorenzo Bianconi wrote:
Quoted 6 lines · On Wed, 19 Aug 2020 15:13:51 +0200 Lorenzo Bianconi wrote:
Quoted 4 lines

Enable the capability to receive jumbo frames even if the interface is running in XDP mode

Quoted 7 lines
Quoted 5 lines
Quoted 2 lines

Hm, already? Is all the infra in place? Or does it not imply multi-buffer.

with this series mvneta supports xdp multi-buff on both rx and tx sides (XDP_TX and ndo_xpd_xmit()) so we can remove MTU limitation.

Is there an API for programs to access the multi-buf frames?

Hi Lorenzo,

This is not enough to support multi-buffer in my opinion. I have the same comment as Jakub. We need an API to pull in the multiple buffers otherwise we break the ability to parse the packets and that is a hard requirement to me. I don't want to lose visibility to get jumbo frames.

At minimum we need a bpf_xdp_pull_data() to adjust pointer. In the skmsg case we use this,

bpf_msg_pull_data(u32 start, u32 end, u64 flags)

Where start is the offset into the packet and end is the last byte we want to adjust start/end pointers to. This way we can walk pages if we want and avoid having to linearize the data unless the user actual asks us for a block that crosses a page range. Smart users then never do a start/end that crosses a page boundary if possible. I think the same would apply here.

XDP by default gives you the first page start/end to use freely. If you need to parse deeper into the payload then you call bpf_msg_pull_data with the byte offsets needed.

Also we would want performance numbers to see how good/bad this is compared to the base case.

Thanks,
John

#20 lore raw

Re: [PATCH net-next 6/6] net: mvneta: enable jumbo frames for XDP

Quoted 36 lines · On Wed, 19 Aug 2020 14:58:05 -0700 John Fastabend <[email protected]>…
Quoted 7 lines · Jakub Kicinski
Quoted 6 lines · On Wed, 19 Aug 2020 22:22:23 +0200 Lorenzo Bianconi wrote:
Quoted 6 lines · On Wed, 19 Aug 2020 15:13:51 +0200 Lorenzo Bianconi wrote:
Quoted 4 lines

Enable the capability to receive jumbo frames even if the interface is running in XDP mode

Quoted 7 lines
Quoted 5 lines
Quoted 2 lines

Hm, already? Is all the infra in place? Or does it not imply multi-buffer.

with this series mvneta supports xdp multi-buff on both rx and tx sides (XDP_TX and ndo_xpd_xmit()) so we can remove MTU limitation.

Is there an API for programs to access the multi-buf frames?

Hi Lorenzo,

This is not enough to support multi-buffer in my opinion. I have the same comment as Jakub. We need an API to pull in the multiple buffers otherwise we break the ability to parse the packets and that is a hard requirement to me. I don't want to lose visibility to get jumbo frames.

At minimum we need a bpf_xdp_pull_data() to adjust pointer. In the skmsg case we use this,

bpf_msg_pull_data(u32 start, u32 end, u64 flags)

Where start is the offset into the packet and end is the last byte we want to adjust start/end pointers to. This way we can walk pages if we want and avoid having to linearize the data unless the user actual asks us for a block that crosses a page range. Smart users then never do a start/end that crosses a page boundary if possible. I think the same would apply here.

Quoted 3 lines

XDP by default gives you the first page start/end to use freely. If you need to parse deeper into the payload then you call bpf_msg_pull_data with the byte offsets needed.

I agree that we need a helper like this. (I also think Daniel have proposed this before). This would also be useful for Eric Dumazet / Google's header-split use-case[1]. As I understood from his talk[1], the NIC HW might not always split the packet correctly (due to HW limits). This helper could solve part of this challenge.

[1] https://netdevconf.info/0x14/session.html?talk-the-path-to-tcp-4k-mtu-and-rx-zerocopy

Signature · 4 lines
Best regards,
  Jesper Dangaard Brouer
  MSc.CS, Principal Kernel Engineer at Red Hat
  LinkedIn: http://www.linkedin.com/in/brouer
#21 lore raw

Re: [PATCH net-next 6/6] net: mvneta: enable jumbo frames for XDP

In reply to John Fastabend
Quoted 11 lines
Quoted 10 lines · Jakub Kicinski
Quoted 9 lines · On Wed, 19 Aug 2020 22:22:23 +0200 Lorenzo Bianconi wrote:
Quoted 8 lines · On Wed, 19 Aug 2020 15:13:51 +0200 Lorenzo Bianconi wrote:
Quoted 4 lines

Enable the capability to receive jumbo frames even if the interface is running in XDP mode

Hm, already? Is all the infra in place? Or does it not imply multi-buffer.

Quoted 6 lines
Quoted 4 lines
Quoted 2 lines

with this series mvneta supports xdp multi-buff on both rx and tx sides (XDP_TX and ndo_xpd_xmit()) so we can remove MTU limitation.

Is there an API for programs to access the multi-buf frames?

Hi Lorenzo,

Hi Jakub and John,

Quoted 6 lines

This is not enough to support multi-buffer in my opinion. I have the same comment as Jakub. We need an API to pull in the multiple buffers otherwise we break the ability to parse the packets and that is a hard requirement to me. I don't want to lose visibility to get jumbo frames.

I have not been so clear in the commit message, sorry for that. This series aims to finalize xdp multi-buff support for mvneta driver only. Our plan is to work on the helpers/metadata in subsequent series since driver support is quite orthogonal. If you think we need the helpers in place before removing the mtu constraint, we could just drop last patch (6/6) and apply patches from 1/6 to 5/6 since they are preliminary to remove the mtu constraint. Do you agree?

Quoted 13 lines

At minimum we need a bpf_xdp_pull_data() to adjust pointer. In the skmsg case we use this,

bpf_msg_pull_data(u32 start, u32 end, u64 flags)

Where start is the offset into the packet and end is the last byte we want to adjust start/end pointers to. This way we can walk pages if we want and avoid having to linearize the data unless the user actual asks us for a block that crosses a page range. Smart users then never do a start/end that crosses a page boundary if possible. I think the same would apply here.

Quoted 3 lines

XDP by default gives you the first page start/end to use freely. If you need to parse deeper into the payload then you call bpf_msg_pull_data with the byte offsets needed.

Our first proposal is described here [0][1]. In particular, we are assuming the eBPF layer can access just the first fragment in the non-linear XDP buff and we will provide some non-linear xdp metadata (e.g. # of segments in the xdp_buffer or buffer total length) to the eBPF program attached to the interface. Anyway IMHO this mvneta series is not strictly related to this approach.

Regards,
Lorenzo

[0] https://github.com/xdp-project/xdp-project/blob/master/areas/core/xdp-multi-buffer01-design.org
[1] http://people.redhat.com/lbiancon/conference/NetDevConf2020-0x14/add-xdp-on-driver.html (XDP multi-buffers section)

Quoted 6 lines

Also we would want performance numbers to see how good/bad this is compared to the base case.

Thanks,
John

#22 lore raw
In reply to Lorenzo Bianconi

General issue (that I think must be resolved/discussed as part of this initial patchset).

When XDP_REDIRECT'ing a multi-buffer xdp_frame out of another driver's ndo_xdp_xmit(), what happens if the remote driver doesn't understand the multi-buffer format?

My guess it that it will only send the first part of the packet (in the main page). Fortunately we don't leak memory, because xdp_return_frame() handle freeing the other segments. I assume this isn't acceptable behavior... or maybe it is?

What are our options for handling this:

1. Add mb support in ndo_xdp_xmit in every driver?

2. Drop xdp->mb frames inside ndo_xdp_xmit (in every driver without support)?

3. Add core-code check before calling ndo_xdp_xmit()?

--Jesper

Quoted 10 lines · On Wed, 19 Aug 2020 15:13:45 +0200 Lorenzo Bianconi <[email protected]> wrote:

Finalize XDP multi-buffer support for mvneta driver introducing the capability to map non-linear buffers on tx side.
Introduce multi-buffer bit (mb) in xdp_frame/xdp_buffer to specify if shared_info area has been properly initialized.
Initialize multi-buffer bit (mb) to 0 in all XDP-capable drivers. Add multi-buff support to xdp_return_{buff/frame} utility routines.

Changes since RFC:
- squash multi-buffer bit initialization in a single patch
- add mvneta non-linear XDP buff support for tx side

Signature · 4 lines
Best regards,
  Jesper Dangaard Brouer
  MSc.CS, Principal Kernel Engineer at Red Hat
  LinkedIn: http://www.linkedin.com/in/brouer
#23 lore raw
Quoted 4 lines

General issue (that I think must be resolved/discussed as part of this initial patchset).

I was thinking about this issue as well.

Quoted 5 lines

When XDP_REDIRECT'ing a multi-buffer xdp_frame out of another driver's ndo_xdp_xmit(), what happens if the remote driver doesn't understand the multi-buffer format?

Quoted 8 lines

My guess it that it will only send the first part of the packet (in the main page). Fortunately we don't leak memory, because xdp_return_frame() handle freeing the other segments. I assume this isn't acceptable behavior... or maybe it is?

What are our options for handling this:

1. Add mb support in ndo_xdp_xmit in every driver?

I guess this is the optimal approach.

Quoted 2 lines

2. Drop xdp->mb frames inside ndo_xdp_xmit (in every driver without support)?

Probably this is the easiest solution.
Anyway if we drop patch 6/6 this is not a real issue since the driver is not allowed yet to receive frames bigger than one page and we have time to address this issue in each driver.

Regards,
Lorenzo

Quoted 24 lines

3. Add core-code check before calling ndo_xdp_xmit()?

--Jesper

Quoted 10 lines · On Wed, 19 Aug 2020 15:13:45 +0200 Lorenzo Bianconi <[email protected]> wrote:

Finalize XDP multi-buffer support for mvneta driver introducing the capability to map non-linear buffers on tx side.
Introduce multi-buffer bit (mb) in xdp_frame/xdp_buffer to specify if shared_info area has been properly initialized.
Initialize multi-buffer bit (mb) to 0 in all XDP-capable drivers. Add multi-buff support to xdp_return_{buff/frame} utility routines.

Changes since RFC:
- squash multi-buffer bit initialization in a single patch
- add mvneta non-linear XDP buff support for tx side

--
Best regards,
Jesper Dangaard Brouer
MSc.CS, Principal Kernel Engineer at Red Hat
LinkedIn: http://www.linkedin.com/in/brouer