@@ -477,6 +477,7 @@ const struct nla_policy ethnl_rss_set_policy[ETHTOOL_A_RSS_START_CONTEXT + 1] =
477477 [ETHTOOL_A_RSS_CONTEXT ] = { .type = NLA_U32 , },
478478 [ETHTOOL_A_RSS_HFUNC ] = NLA_POLICY_MIN (NLA_U32 , 1 ),
479479 [ETHTOOL_A_RSS_INDIR ] = { .type = NLA_BINARY , },
480+ [ETHTOOL_A_RSS_HKEY ] = NLA_POLICY_MIN (NLA_BINARY , 1 ),
480481};
481482
482483static int
@@ -490,8 +491,10 @@ ethnl_rss_set_validate(struct ethnl_req_info *req_info, struct genl_info *info)
490491 if (request -> rss_context && !ops -> create_rxfh_context )
491492 bad_attr = bad_attr ?: tb [ETHTOOL_A_RSS_CONTEXT ];
492493
493- if (request -> rss_context && !ops -> rxfh_per_ctx_key )
494+ if (request -> rss_context && !ops -> rxfh_per_ctx_key ) {
494495 bad_attr = bad_attr ?: tb [ETHTOOL_A_RSS_HFUNC ];
496+ bad_attr = bad_attr ?: tb [ETHTOOL_A_RSS_HKEY ];
497+ }
495498
496499 if (bad_attr ) {
497500 NL_SET_BAD_ATTR (info -> extack , bad_attr );
@@ -581,6 +584,31 @@ rss_set_prep_indir(struct net_device *dev, struct genl_info *info,
581584 return err ;
582585}
583586
587+ static int
588+ rss_set_prep_hkey (struct net_device * dev , struct genl_info * info ,
589+ struct rss_reply_data * data , struct ethtool_rxfh_param * rxfh ,
590+ bool * mod )
591+ {
592+ struct nlattr * * tb = info -> attrs ;
593+
594+ if (!tb [ETHTOOL_A_RSS_HKEY ])
595+ return 0 ;
596+
597+ if (nla_len (tb [ETHTOOL_A_RSS_HKEY ]) != data -> hkey_size ) {
598+ NL_SET_BAD_ATTR (info -> extack , tb [ETHTOOL_A_RSS_HKEY ]);
599+ return - EINVAL ;
600+ }
601+
602+ rxfh -> key_size = data -> hkey_size ;
603+ rxfh -> key = kmemdup (data -> hkey , data -> hkey_size , GFP_KERNEL );
604+ if (!rxfh -> key )
605+ return - ENOMEM ;
606+
607+ ethnl_update_binary (rxfh -> key , rxfh -> key_size , tb [ETHTOOL_A_RSS_HKEY ],
608+ mod );
609+ return 0 ;
610+ }
611+
584612static void
585613rss_set_ctx_update (struct ethtool_rxfh_context * ctx , struct nlattr * * tb ,
586614 struct rss_reply_data * data , struct ethtool_rxfh_param * rxfh )
@@ -592,6 +620,11 @@ rss_set_ctx_update(struct ethtool_rxfh_context *ctx, struct nlattr **tb,
592620 ethtool_rxfh_context_indir (ctx )[i ] = rxfh -> indir [i ];
593621 ctx -> indir_configured = !!nla_len (tb [ETHTOOL_A_RSS_INDIR ]);
594622 }
623+ if (rxfh -> key ) {
624+ memcpy (ethtool_rxfh_context_key (ctx ), rxfh -> key ,
625+ data -> hkey_size );
626+ ctx -> key_configured = !!rxfh -> key_size ;
627+ }
595628 if (rxfh -> hfunc != ETH_RSS_HASH_NO_CHANGE )
596629 ctx -> hfunc = rxfh -> hfunc ;
597630}
@@ -629,6 +662,10 @@ ethnl_rss_set(struct ethnl_req_info *req_info, struct genl_info *info)
629662 if (rxfh .hfunc == data .hfunc )
630663 rxfh .hfunc = ETH_RSS_HASH_NO_CHANGE ;
631664
665+ ret = rss_set_prep_hkey (dev , info , & data , & rxfh , & mod );
666+ if (ret )
667+ goto exit_free_indir ;
668+
632669 rxfh .input_xfrm = RXH_XFRM_NO_CHANGE ;
633670
634671 mutex_lock (& dev -> ethtool -> rss_lock );
@@ -660,6 +697,8 @@ ethnl_rss_set(struct ethnl_req_info *req_info, struct genl_info *info)
660697
661698exit_unlock :
662699 mutex_unlock (& dev -> ethtool -> rss_lock );
700+ kfree (rxfh .key );
701+ exit_free_indir :
663702 kfree (rxfh .indir );
664703exit_clean_data :
665704 rss_cleanup_data (& data .base );
0 commit comments