@@ -478,6 +478,8 @@ const struct nla_policy ethnl_rss_set_policy[ETHTOOL_A_RSS_START_CONTEXT + 1] =
478478 [ETHTOOL_A_RSS_HFUNC ] = NLA_POLICY_MIN (NLA_U32 , 1 ),
479479 [ETHTOOL_A_RSS_INDIR ] = { .type = NLA_BINARY , },
480480 [ETHTOOL_A_RSS_HKEY ] = NLA_POLICY_MIN (NLA_BINARY , 1 ),
481+ [ETHTOOL_A_RSS_INPUT_XFRM ] =
482+ NLA_POLICY_MAX (NLA_U32 , RXH_XFRM_SYM_OR_XOR ),
481483};
482484
483485static int
@@ -487,15 +489,21 @@ ethnl_rss_set_validate(struct ethnl_req_info *req_info, struct genl_info *info)
487489 struct rss_req_info * request = RSS_REQINFO (req_info );
488490 struct nlattr * * tb = info -> attrs ;
489491 struct nlattr * bad_attr = NULL ;
492+ u32 input_xfrm ;
490493
491494 if (request -> rss_context && !ops -> create_rxfh_context )
492495 bad_attr = bad_attr ?: tb [ETHTOOL_A_RSS_CONTEXT ];
493496
494497 if (request -> rss_context && !ops -> rxfh_per_ctx_key ) {
495498 bad_attr = bad_attr ?: tb [ETHTOOL_A_RSS_HFUNC ];
496499 bad_attr = bad_attr ?: tb [ETHTOOL_A_RSS_HKEY ];
500+ bad_attr = bad_attr ?: tb [ETHTOOL_A_RSS_INPUT_XFRM ];
497501 }
498502
503+ input_xfrm = nla_get_u32_default (tb [ETHTOOL_A_RSS_INPUT_XFRM ], 0 );
504+ if (input_xfrm & ~ops -> supported_input_xfrm )
505+ bad_attr = bad_attr ?: tb [ETHTOOL_A_RSS_INPUT_XFRM ];
506+
499507 if (bad_attr ) {
500508 NL_SET_BAD_ATTR (info -> extack , bad_attr );
501509 return - EOPNOTSUPP ;
@@ -609,6 +617,33 @@ rss_set_prep_hkey(struct net_device *dev, struct genl_info *info,
609617 return 0 ;
610618}
611619
620+ static int
621+ rss_check_rxfh_fields_sym (struct net_device * dev , struct genl_info * info ,
622+ struct rss_reply_data * data , bool xfrm_sym )
623+ {
624+ struct nlattr * * tb = info -> attrs ;
625+ int i ;
626+
627+ if (!xfrm_sym )
628+ return 0 ;
629+ if (!data -> has_flow_hash ) {
630+ NL_SET_ERR_MSG_ATTR (info -> extack , tb [ETHTOOL_A_RSS_INPUT_XFRM ],
631+ "hash field config not reported" );
632+ return - EINVAL ;
633+ }
634+
635+ for (i = 1 ; i < __ETHTOOL_A_FLOW_CNT ; i ++ )
636+ if (data -> flow_hash [i ] >= 0 &&
637+ !ethtool_rxfh_config_is_sym (data -> flow_hash [i ])) {
638+ NL_SET_ERR_MSG_ATTR (info -> extack ,
639+ tb [ETHTOOL_A_RSS_INPUT_XFRM ],
640+ "hash field config is not symmetric" );
641+ return - EINVAL ;
642+ }
643+
644+ return 0 ;
645+ }
646+
612647static void
613648rss_set_ctx_update (struct ethtool_rxfh_context * ctx , struct nlattr * * tb ,
614649 struct rss_reply_data * data , struct ethtool_rxfh_param * rxfh )
@@ -627,16 +662,18 @@ rss_set_ctx_update(struct ethtool_rxfh_context *ctx, struct nlattr **tb,
627662 }
628663 if (rxfh -> hfunc != ETH_RSS_HASH_NO_CHANGE )
629664 ctx -> hfunc = rxfh -> hfunc ;
665+ if (rxfh -> input_xfrm != RXH_XFRM_NO_CHANGE )
666+ ctx -> input_xfrm = rxfh -> input_xfrm ;
630667}
631668
632669static int
633670ethnl_rss_set (struct ethnl_req_info * req_info , struct genl_info * info )
634671{
672+ bool indir_reset = false, indir_mod , xfrm_sym = false;
635673 struct rss_req_info * request = RSS_REQINFO (req_info );
636674 struct ethtool_rxfh_context * ctx = NULL ;
637675 struct net_device * dev = req_info -> dev ;
638676 struct ethtool_rxfh_param rxfh = {};
639- bool indir_reset = false, indir_mod ;
640677 struct nlattr * * tb = info -> attrs ;
641678 struct rss_reply_data data = {};
642679 const struct ethtool_ops * ops ;
@@ -666,7 +703,20 @@ ethnl_rss_set(struct ethnl_req_info *req_info, struct genl_info *info)
666703 if (ret )
667704 goto exit_free_indir ;
668705
669- rxfh .input_xfrm = RXH_XFRM_NO_CHANGE ;
706+ rxfh .input_xfrm = data .input_xfrm ;
707+ ethnl_update_u8 (& rxfh .input_xfrm , tb [ETHTOOL_A_RSS_INPUT_XFRM ], & mod );
708+ /* For drivers which don't support input_xfrm it will be set to 0xff
709+ * in the RSS context info. In all other case input_xfrm != 0 means
710+ * symmetric hashing is requested.
711+ */
712+ if (!request -> rss_context || ops -> rxfh_per_ctx_key )
713+ xfrm_sym = !!rxfh .input_xfrm ;
714+ if (rxfh .input_xfrm == data .input_xfrm )
715+ rxfh .input_xfrm = RXH_XFRM_NO_CHANGE ;
716+
717+ ret = rss_check_rxfh_fields_sym (dev , info , & data , xfrm_sym );
718+ if (ret )
719+ goto exit_clean_data ;
670720
671721 mutex_lock (& dev -> ethtool -> rss_lock );
672722 if (request -> rss_context ) {
0 commit comments