On XDP_PASS, ice builds the skb with xdp_build_skb_from_buff(). Then ice_process_skb_fields() sets the hash and ip_summed from the RX descriptor, and ice_receive_skb() adds the VLAN tag. The values that the XDP program stored in the skb core extension area are not used. ice_clean_rx_irq() takes the skb core extension pointer from the xdp_buff before it builds the skb, and passes it to ice_receive_skb(). ice_receive_skb() calls xdp_skb_ext_to_skb() right before GRO. The stored values then replace the values from the descriptor before the skb leaves the driver. ice now sets the skb-ext-pass XDP feature. Zero-copy is not supported in this patch. ice_clean_rx_irq_zc() passes NULL for the skb core extension pointer to ice_receive_skb(). Hence the skb-ext-pass feature does not cover AF_XDP zero-copy queues. Export xdp_skb_ext_to_skb(), because ice can be a module. Signed-off-by: Tianyi Gao --- drivers/net/ethernet/intel/ice/ice_main.c | 3 ++- drivers/net/ethernet/intel/ice/ice_sf_eth.c | 3 ++- drivers/net/ethernet/intel/ice/ice_txrx.c | 4 +++- drivers/net/ethernet/intel/ice/ice_txrx_lib.c | 7 ++++++- drivers/net/ethernet/intel/ice/ice_txrx_lib.h | 3 ++- drivers/net/ethernet/intel/ice/ice_xsk.c | 2 +- net/core/xdp.c | 5 ++++- 7 files changed, 20 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 454fba07d4ec..cb619689d11a 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -3461,7 +3461,8 @@ static void ice_set_ops(struct ice_vsi *vsi) netdev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT | NETDEV_XDP_ACT_XSK_ZEROCOPY | - NETDEV_XDP_ACT_RX_SG; + NETDEV_XDP_ACT_RX_SG | + NETDEV_XDP_ACT_SKB_EXT_PASS; netdev->xdp_zc_max_segs = ICE_MAX_BUF_TXD; } diff --git a/drivers/net/ethernet/intel/ice/ice_sf_eth.c b/drivers/net/ethernet/intel/ice/ice_sf_eth.c index a730aa368c92..90f2ce5da022 100644 --- a/drivers/net/ethernet/intel/ice/ice_sf_eth.c +++ b/drivers/net/ethernet/intel/ice/ice_sf_eth.c @@ -52,7 +52,8 @@ static int ice_sf_cfg_netdev(struct ice_dynamic_port *dyn_port, netdev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT | NETDEV_XDP_ACT_XSK_ZEROCOPY | - NETDEV_XDP_ACT_RX_SG; + NETDEV_XDP_ACT_RX_SG | + NETDEV_XDP_ACT_SKB_EXT_PASS; netdev->xdp_zc_max_segs = ICE_MAX_BUF_TXD; eth_hw_addr_set(netdev, dyn_port->hw_addr); diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c index a2c7c4962882..06a1a5fdc43b 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx.c +++ b/drivers/net/ethernet/intel/ice/ice_txrx.c @@ -966,6 +966,7 @@ static int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget) /* start the loop to process Rx packets bounded by 'budget' */ while (likely(total_rx_pkts < (unsigned int)budget)) { union ice_32b_rx_flex_desc *rx_desc; + const struct xdp_skb_ext *ext; struct libeth_fqe *rx_buf; struct sk_buff *skb; unsigned int size; @@ -1041,6 +1042,7 @@ static int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget) continue; construct_skb: + ext = xdp_buff_skb_ext(&xdp->base); skb = xdp_build_skb_from_buff(&xdp->base); xdp->data = NULL; @@ -1061,7 +1063,7 @@ static int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget) ice_trace(clean_rx_irq_indicate, rx_ring, rx_desc, skb); /* send completed skb up the stack */ - ice_receive_skb(rx_ring, skb, vlan_tci); + ice_receive_skb(rx_ring, skb, vlan_tci, ext); /* update budget accounting */ total_rx_pkts++; diff --git a/drivers/net/ethernet/intel/ice/ice_txrx_lib.c b/drivers/net/ethernet/intel/ice/ice_txrx_lib.c index e695a664e53d..85439853596f 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_txrx_lib.c @@ -247,17 +247,22 @@ ice_process_skb_fields(struct ice_rx_ring *rx_ring, * @rx_ring: Rx ring in play * @skb: packet to send up * @vlan_tci: VLAN TCI for packet + * @ext: skb core extension area of the packet, or NULL * * This function sends the completed packet (via. skb) up the stack using * gro receive functions (with/without VLAN tag) */ void -ice_receive_skb(struct ice_rx_ring *rx_ring, struct sk_buff *skb, u16 vlan_tci) +ice_receive_skb(struct ice_rx_ring *rx_ring, struct sk_buff *skb, u16 vlan_tci, + const struct xdp_skb_ext *ext) { if ((vlan_tci & VLAN_VID_MASK) && rx_ring->vlan_proto) __vlan_hwaccel_put_tag(skb, rx_ring->vlan_proto, vlan_tci); + if (ext) + xdp_skb_ext_to_skb(skb, ext); + napi_gro_receive(&rx_ring->q_vector->napi, skb); } diff --git a/drivers/net/ethernet/intel/ice/ice_txrx_lib.h b/drivers/net/ethernet/intel/ice/ice_txrx_lib.h index f17990b68b62..cfc77847696e 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_txrx_lib.h @@ -133,6 +133,7 @@ ice_process_skb_fields(struct ice_rx_ring *rx_ring, union ice_32b_rx_flex_desc *rx_desc, struct sk_buff *skb); void -ice_receive_skb(struct ice_rx_ring *rx_ring, struct sk_buff *skb, u16 vlan_tci); +ice_receive_skb(struct ice_rx_ring *rx_ring, struct sk_buff *skb, u16 vlan_tci, + const struct xdp_skb_ext *ext); #endif /* !_ICE_TXRX_LIB_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_xsk.c b/drivers/net/ethernet/intel/ice/ice_xsk.c index 0643017541c3..f64659dc8313 100644 --- a/drivers/net/ethernet/intel/ice/ice_xsk.c +++ b/drivers/net/ethernet/intel/ice/ice_xsk.c @@ -670,7 +670,7 @@ int ice_clean_rx_irq_zc(struct ice_rx_ring *rx_ring, vlan_tci = ice_get_vlan_tci(rx_desc); ice_process_skb_fields(rx_ring, rx_desc, skb); - ice_receive_skb(rx_ring, skb, vlan_tci); + ice_receive_skb(rx_ring, skb, vlan_tci, NULL); } rx_ring->next_to_clean = ntc; diff --git a/net/core/xdp.c b/net/core/xdp.c index 984299199906..fdda072a5858 100644 --- a/net/core/xdp.c +++ b/net/core/xdp.c @@ -1086,7 +1086,9 @@ static const void *xdp_skb_ext_get(const struct xdp_skb_ext *ext, * @skb: The skb that is built from the packet. * @ext: The skb core extension area of the packet. * - * Call it only when the packet has the XDP_FLAGS_HAS_SKB_EXT flag. + * Call it only when the packet has the XDP_FLAGS_HAS_SKB_EXT flag. A driver + * calls it after it sets the skb fields from the RX descriptor, and sets + * NETDEV_XDP_ACT_SKB_EXT_PASS. */ void xdp_skb_ext_to_skb(struct sk_buff *skb, const struct xdp_skb_ext *ext) { @@ -1115,6 +1117,7 @@ void xdp_skb_ext_to_skb(struct sk_buff *skb, const struct xdp_skb_ext *ext) skb->csum_level = csum->level; } } +EXPORT_SYMBOL_GPL(xdp_skb_ext_to_skb); /** * xdp_skb_ext_warn_pass - Warn if XDP_PASS does not use the stored values. -- 2.56.0