igc_rx_offset(rx_ring) + pkt_offset,
                                         size, true);
                        xdp_buff_clear_frags_flag(&ctx.xdp);
+                       ctx.rx_desc = rx_desc;
 
                        skb = igc_xdp_run_prog(adapter, &ctx.xdp);
                }
        napi_gro_receive(&q_vector->napi, skb);
 }
 
+static struct igc_xdp_buff *xsk_buff_to_igc_ctx(struct xdp_buff *xdp)
+{
+       /* xdp_buff pointer used by ZC code path is alloc as xdp_buff_xsk. The
+        * igc_xdp_buff shares its layout with xdp_buff_xsk and private
+        * igc_xdp_buff fields fall into xdp_buff_xsk->cb
+        */
+       return (struct igc_xdp_buff *)xdp;
+}
+
 static int igc_clean_rx_irq_zc(struct igc_q_vector *q_vector, const int budget)
 {
        struct igc_adapter *adapter = q_vector->adapter;
        while (likely(total_packets < budget)) {
                union igc_adv_rx_desc *desc;
                struct igc_rx_buffer *bi;
+               struct igc_xdp_buff *ctx;
                ktime_t timestamp = 0;
                unsigned int size;
                int res;
 
                bi = &ring->rx_buffer_info[ntc];
 
+               ctx = xsk_buff_to_igc_ctx(bi->xdp);
+               ctx->rx_desc = desc;
+
                if (igc_test_staterr(desc, IGC_RXDADV_STAT_TSIP)) {
                        timestamp = igc_ptp_rx_pktstamp(q_vector->adapter,
                                                        bi->xdp->data);
        return value;
 }
 
+/* Mapping HW RSS Type to enum xdp_rss_hash_type */
+static enum xdp_rss_hash_type igc_xdp_rss_type[IGC_RSS_TYPE_MAX_TABLE] = {
+       [IGC_RSS_TYPE_NO_HASH]          = XDP_RSS_TYPE_L2,
+       [IGC_RSS_TYPE_HASH_TCP_IPV4]    = XDP_RSS_TYPE_L4_IPV4_TCP,
+       [IGC_RSS_TYPE_HASH_IPV4]        = XDP_RSS_TYPE_L3_IPV4,
+       [IGC_RSS_TYPE_HASH_TCP_IPV6]    = XDP_RSS_TYPE_L4_IPV6_TCP,
+       [IGC_RSS_TYPE_HASH_IPV6_EX]     = XDP_RSS_TYPE_L3_IPV6_EX,
+       [IGC_RSS_TYPE_HASH_IPV6]        = XDP_RSS_TYPE_L3_IPV6,
+       [IGC_RSS_TYPE_HASH_TCP_IPV6_EX] = XDP_RSS_TYPE_L4_IPV6_TCP_EX,
+       [IGC_RSS_TYPE_HASH_UDP_IPV4]    = XDP_RSS_TYPE_L4_IPV4_UDP,
+       [IGC_RSS_TYPE_HASH_UDP_IPV6]    = XDP_RSS_TYPE_L4_IPV6_UDP,
+       [IGC_RSS_TYPE_HASH_UDP_IPV6_EX] = XDP_RSS_TYPE_L4_IPV6_UDP_EX,
+       [10] = XDP_RSS_TYPE_NONE, /* RSS Type above 9 "Reserved" by HW  */
+       [11] = XDP_RSS_TYPE_NONE, /* keep array sized for SW bit-mask   */
+       [12] = XDP_RSS_TYPE_NONE, /* to handle future HW revisons       */
+       [13] = XDP_RSS_TYPE_NONE,
+       [14] = XDP_RSS_TYPE_NONE,
+       [15] = XDP_RSS_TYPE_NONE,
+};
+
+static int igc_xdp_rx_hash(const struct xdp_md *_ctx, u32 *hash,
+                          enum xdp_rss_hash_type *rss_type)
+{
+       const struct igc_xdp_buff *ctx = (void *)_ctx;
+
+       if (!(ctx->xdp.rxq->dev->features & NETIF_F_RXHASH))
+               return -ENODATA;
+
+       *hash = le32_to_cpu(ctx->rx_desc->wb.lower.hi_dword.rss);
+       *rss_type = igc_xdp_rss_type[igc_rss_type(ctx->rx_desc)];
+
+       return 0;
+}
+
+static const struct xdp_metadata_ops igc_xdp_metadata_ops = {
+       .xmo_rx_hash                    = igc_xdp_rx_hash,
+};
+
 /**
  * igc_probe - Device Initialization Routine
  * @pdev: PCI device information struct
        hw->hw_addr = adapter->io_addr;
 
        netdev->netdev_ops = &igc_netdev_ops;
+       netdev->xdp_metadata_ops = &igc_xdp_metadata_ops;
        igc_ethtool_set_ops(netdev);
        netdev->watchdog_timeo = 5 * HZ;