=====================================  ======  ==============================
   ``ETHTOOL_A_RSS_HEADER``             nested  request header
   ``ETHTOOL_A_RSS_CONTEXT``            u32     context number
+  ``ETHTOOL_A_RSS_HFUNC``              u32     RSS hash func
   ``ETHTOOL_A_RSS_INDIR``              binary  Indir table bytes
 =====================================  ======  ==============================
 
 
 const struct nla_policy ethnl_rss_set_policy[ETHTOOL_A_RSS_START_CONTEXT + 1] = {
        [ETHTOOL_A_RSS_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy),
        [ETHTOOL_A_RSS_CONTEXT] = { .type = NLA_U32, },
+       [ETHTOOL_A_RSS_HFUNC] = NLA_POLICY_MIN(NLA_U32, 1),
        [ETHTOOL_A_RSS_INDIR] = { .type = NLA_BINARY, },
 };
 
        if (request->rss_context && !ops->create_rxfh_context)
                bad_attr = bad_attr ?: tb[ETHTOOL_A_RSS_CONTEXT];
 
+       if (request->rss_context && !ops->rxfh_per_ctx_key)
+               bad_attr = bad_attr ?: tb[ETHTOOL_A_RSS_HFUNC];
+
        if (bad_attr) {
                NL_SET_BAD_ATTR(info->extack, bad_attr);
                return -EOPNOTSUPP;
                        ethtool_rxfh_context_indir(ctx)[i] = rxfh->indir[i];
                ctx->indir_configured = !!nla_len(tb[ETHTOOL_A_RSS_INDIR]);
        }
+       if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE)
+               ctx->hfunc = rxfh->hfunc;
 }
 
 static int
                goto exit_clean_data;
        indir_mod = !!tb[ETHTOOL_A_RSS_INDIR];
 
-       rxfh.hfunc = ETH_RSS_HASH_NO_CHANGE;
+       rxfh.hfunc = data.hfunc;
+       ethnl_update_u8(&rxfh.hfunc, tb[ETHTOOL_A_RSS_HFUNC], &mod);
+       if (rxfh.hfunc == data.hfunc)
+               rxfh.hfunc = ETH_RSS_HASH_NO_CHANGE;
+
        rxfh.input_xfrm = RXH_XFRM_NO_CHANGE;
 
        mutex_lock(&dev->ethtool->rss_lock);