Introduce i40e_xdp_rx_hash() which takes the same approach as i40e_rx_hash() to extract the hash from RX descriptors.
Tested with X710 adapter using xdp_hw_metadata, and verified hash consistency between bpf_xdp_metadata_rx_hash() and skb->hash. Signed-off-by: Kohei Enju <[email protected]> --- drivers/net/ethernet/intel/i40e/i40e_main.c | 30 +++++++++++++++++++++ drivers/net/ethernet/intel/i40e/i40e_type.h | 5 ++++ 2 files changed, 35 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 7966d9cb8009..6b7e34b16a8d 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -4,6 +4,7 @@ #include <generated/utsrelease.h> #include <linux/crash_dump.h> #include <linux/intel/libie/pctype.h> +#include <linux/intel/libie/rx.h> #include <linux/if_bridge.h> #include <linux/if_macvlan.h> #include <linux/module.h> @@ -13585,6 +13586,34 @@ static int i40e_xdp(struct net_device *dev, } } +static int i40e_xdp_rx_hash(const struct xdp_md *_ctx, u32 *hash, + enum xdp_rss_hash_type *rss_type) +{ + const struct i40e_xdp_buff *ctx = (const void *)_ctx; + const union i40e_rx_desc *desc = ctx->desc; + struct libeth_rx_pt rx_ptype; + u8 raw_rx_ptype; + u64 status; + + status = le64_to_cpu(desc->wb.qword1.status_error_len); + raw_rx_ptype = FIELD_GET(I40E_RXD_QW1_PTYPE_MASK, status); + rx_ptype = libie_rx_pt_parse(raw_rx_ptype); + + if (!libeth_rx_pt_has_hash(ctx->xdp.rxq->dev, rx_ptype) || + FIELD_GET(I40E_RX_DESC_STATUS_FLTSTAT_MASK, status) != + I40E_RX_DESC_FLTSTAT_RSS_HASH) + return -ENODATA; + + *hash = le32_to_cpu(desc->wb.qword0.hi_dword.rss); + *rss_type = rx_ptype.hash_type; + + return 0; +} + +static const struct xdp_metadata_ops i40e_xdp_metadata_ops = { + .xmo_rx_hash = i40e_xdp_rx_hash, +}; + static const struct net_device_ops i40e_netdev_ops = { .ndo_open = i40e_open, .ndo_stop = i40e_close, @@ -13788,6 +13817,7 @@ static int i40e_config_netdev(struct i40e_vsi *vsi) i40e_vsi_config_netdev_tc(vsi, vsi->tc_config.enabled_tc); netdev->netdev_ops = &i40e_netdev_ops; + netdev->xdp_metadata_ops = &i40e_xdp_metadata_ops; netdev->watchdog_timeo = 5 * HZ; i40e_set_ethtool_ops(netdev); diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index ed8bbdb586da..16a65c6e5153 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -4,6 +4,7 @@ #ifndef _I40E_TYPE_H_ #define _I40E_TYPE_H_ +#include <linux/bits.h> #include <uapi/linux/if_ether.h> #include "i40e_adminq.h" #include "i40e_hmc.h" @@ -699,6 +700,10 @@ enum i40e_rx_desc_status_bits { I40E_RX_DESC_STATUS_LAST /* this entry must be last!!! */ }; +#define I40E_RX_DESC_STATUS_FLTSTAT_MASK \ + GENMASK_ULL(I40E_RX_DESC_STATUS_FLTSTAT_SHIFT + 1, \ + I40E_RX_DESC_STATUS_FLTSTAT_SHIFT) + #define I40E_RXD_QW1_STATUS_SHIFT 0 #define I40E_RXD_QW1_STATUS_MASK ((BIT(I40E_RX_DESC_STATUS_LAST) - 1) \ << I40E_RXD_QW1_STATUS_SHIFT) -- 2.51.0
