Similar to the skb path issue explained in the previous change, ENETC could end up transmitting short frames coming from XDP. The way in which this could happen is a bit contrived, but it involves XDP_REDIRECT from a veth interface pair. Introduce a xdp_frame_pad() generic helper and call it from enetc's ndo_xdp_xmit() implementation. This should be safe, because ndo_xdp_xmit() is the hand-off function where the XDP frames become the responsibility of the driver, so modifying them is fine. AFAIU, struct xdp_frame doesn't have multiple copies. Fixes: 9d2b68cc108d ("net: enetc: add support for XDP_REDIRECT") Signed-off-by: Vladimir Oltean --- drivers/net/ethernet/freescale/enetc/enetc.c | 3 +++ include/net/xdp.h | 17 +++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c index 4b87fbfde0d6..3ceb9dfd2316 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc.c +++ b/drivers/net/ethernet/freescale/enetc/enetc.c @@ -1801,6 +1801,9 @@ int enetc_xdp_xmit(struct net_device *ndev, int num_frames, prefetchw(ENETC_TXBD(*tx_ring, tx_ring->next_to_use)); for (k = 0; k < num_frames; k++) { + if (unlikely(xdp_frame_pad(frames[k]))) + break; + xdp_tx_bd_cnt = enetc_xdp_frame_to_xdp_tx_swbd(tx_ring, xdp_redirect_arr, frames[k]); diff --git a/include/net/xdp.h b/include/net/xdp.h index aa742f413c35..0cdeb23c6bd7 100644 --- a/include/net/xdp.h +++ b/include/net/xdp.h @@ -477,6 +477,23 @@ xdp_get_frame_len(const struct xdp_frame *xdpf) return len; } +static inline int xdp_frame_pad(struct xdp_frame *xdpf) +{ + void *sinfo; + + if (likely(xdpf->len >= ETH_ZLEN)) + return 0; + + sinfo = xdp_get_shared_info_from_frame(xdpf); + if (unlikely(xdpf->data + ETH_ZLEN > sinfo)) + return -ENOMEM; + + memset(xdpf->data + xdpf->len, 0, ETH_ZLEN - xdpf->len); + xdpf->len = ETH_ZLEN; + + return 0; +} + int __xdp_rxq_info_reg(struct xdp_rxq_info *xdp_rxq, struct net_device *dev, u32 queue_index, unsigned int napi_id, u32 frag_size); -- 2.43.0