@@ -472,14 +472,49 @@ void ethtool_rss_notify(struct net_device *dev, u32 rss_context)
472
472
473
473
/* RSS_SET */
474
474
475
- const struct nla_policy ethnl_rss_set_policy [ETHTOOL_A_RSS_START_CONTEXT + 1 ] = {
475
+ #define RFH_MASK (RXH_L2DA | RXH_VLAN | RXH_IP_SRC | RXH_IP_DST | \
476
+ RXH_L3_PROTO | RXH_L4_B_0_1 | RXH_L4_B_2_3 | \
477
+ RXH_GTP_TEID | RXH_DISCARD)
478
+
479
+ static const struct nla_policy ethnl_rss_flows_policy [] = {
480
+ [ETHTOOL_A_FLOW_ETHER ] = NLA_POLICY_MASK (NLA_UINT , RFH_MASK ),
481
+ [ETHTOOL_A_FLOW_IP4 ] = NLA_POLICY_MASK (NLA_UINT , RFH_MASK ),
482
+ [ETHTOOL_A_FLOW_IP6 ] = NLA_POLICY_MASK (NLA_UINT , RFH_MASK ),
483
+ [ETHTOOL_A_FLOW_TCP4 ] = NLA_POLICY_MASK (NLA_UINT , RFH_MASK ),
484
+ [ETHTOOL_A_FLOW_UDP4 ] = NLA_POLICY_MASK (NLA_UINT , RFH_MASK ),
485
+ [ETHTOOL_A_FLOW_SCTP4 ] = NLA_POLICY_MASK (NLA_UINT , RFH_MASK ),
486
+ [ETHTOOL_A_FLOW_AH_ESP4 ] = NLA_POLICY_MASK (NLA_UINT , RFH_MASK ),
487
+ [ETHTOOL_A_FLOW_TCP6 ] = NLA_POLICY_MASK (NLA_UINT , RFH_MASK ),
488
+ [ETHTOOL_A_FLOW_UDP6 ] = NLA_POLICY_MASK (NLA_UINT , RFH_MASK ),
489
+ [ETHTOOL_A_FLOW_SCTP6 ] = NLA_POLICY_MASK (NLA_UINT , RFH_MASK ),
490
+ [ETHTOOL_A_FLOW_AH_ESP6 ] = NLA_POLICY_MASK (NLA_UINT , RFH_MASK ),
491
+ [ETHTOOL_A_FLOW_AH4 ] = NLA_POLICY_MASK (NLA_UINT , RFH_MASK ),
492
+ [ETHTOOL_A_FLOW_ESP4 ] = NLA_POLICY_MASK (NLA_UINT , RFH_MASK ),
493
+ [ETHTOOL_A_FLOW_AH6 ] = NLA_POLICY_MASK (NLA_UINT , RFH_MASK ),
494
+ [ETHTOOL_A_FLOW_ESP6 ] = NLA_POLICY_MASK (NLA_UINT , RFH_MASK ),
495
+ [ETHTOOL_A_FLOW_GTPU4 ] = NLA_POLICY_MASK (NLA_UINT , RFH_MASK ),
496
+ [ETHTOOL_A_FLOW_GTPU6 ] = NLA_POLICY_MASK (NLA_UINT , RFH_MASK ),
497
+ [ETHTOOL_A_FLOW_GTPC4 ] = NLA_POLICY_MASK (NLA_UINT , RFH_MASK ),
498
+ [ETHTOOL_A_FLOW_GTPC6 ] = NLA_POLICY_MASK (NLA_UINT , RFH_MASK ),
499
+ [ETHTOOL_A_FLOW_GTPC_TEID4 ] = NLA_POLICY_MASK (NLA_UINT , RFH_MASK ),
500
+ [ETHTOOL_A_FLOW_GTPC_TEID6 ] = NLA_POLICY_MASK (NLA_UINT , RFH_MASK ),
501
+ [ETHTOOL_A_FLOW_GTPU_EH4 ] = NLA_POLICY_MASK (NLA_UINT , RFH_MASK ),
502
+ [ETHTOOL_A_FLOW_GTPU_EH6 ] = NLA_POLICY_MASK (NLA_UINT , RFH_MASK ),
503
+ [ETHTOOL_A_FLOW_GTPU_UL4 ] = NLA_POLICY_MASK (NLA_UINT , RFH_MASK ),
504
+ [ETHTOOL_A_FLOW_GTPU_UL6 ] = NLA_POLICY_MASK (NLA_UINT , RFH_MASK ),
505
+ [ETHTOOL_A_FLOW_GTPU_DL4 ] = NLA_POLICY_MASK (NLA_UINT , RFH_MASK ),
506
+ [ETHTOOL_A_FLOW_GTPU_DL6 ] = NLA_POLICY_MASK (NLA_UINT , RFH_MASK ),
507
+ };
508
+
509
+ const struct nla_policy ethnl_rss_set_policy [ETHTOOL_A_RSS_FLOW_HASH + 1 ] = {
476
510
[ETHTOOL_A_RSS_HEADER ] = NLA_POLICY_NESTED (ethnl_header_policy ),
477
511
[ETHTOOL_A_RSS_CONTEXT ] = { .type = NLA_U32 , },
478
512
[ETHTOOL_A_RSS_HFUNC ] = NLA_POLICY_MIN (NLA_U32 , 1 ),
479
513
[ETHTOOL_A_RSS_INDIR ] = { .type = NLA_BINARY , },
480
514
[ETHTOOL_A_RSS_HKEY ] = NLA_POLICY_MIN (NLA_BINARY , 1 ),
481
515
[ETHTOOL_A_RSS_INPUT_XFRM ] =
482
516
NLA_POLICY_MAX (NLA_U32 , RXH_XFRM_SYM_OR_XOR ),
517
+ [ETHTOOL_A_RSS_FLOW_HASH ] = NLA_POLICY_NESTED (ethnl_rss_flows_policy ),
483
518
};
484
519
485
520
static int
@@ -504,6 +539,12 @@ ethnl_rss_set_validate(struct ethnl_req_info *req_info, struct genl_info *info)
504
539
if (input_xfrm & ~ops -> supported_input_xfrm )
505
540
bad_attr = bad_attr ?: tb [ETHTOOL_A_RSS_INPUT_XFRM ];
506
541
542
+ if (tb [ETHTOOL_A_RSS_FLOW_HASH ] && !ops -> set_rxfh_fields )
543
+ bad_attr = bad_attr ?: tb [ETHTOOL_A_RSS_FLOW_HASH ];
544
+ if (request -> rss_context &&
545
+ tb [ETHTOOL_A_RSS_FLOW_HASH ] && !ops -> rxfh_per_ctx_fields )
546
+ bad_attr = bad_attr ?: tb [ETHTOOL_A_RSS_FLOW_HASH ];
547
+
507
548
if (bad_attr ) {
508
549
NL_SET_BAD_ATTR (info -> extack , bad_attr );
509
550
return - EOPNOTSUPP ;
@@ -644,6 +685,59 @@ rss_check_rxfh_fields_sym(struct net_device *dev, struct genl_info *info,
644
685
return 0 ;
645
686
}
646
687
688
+ static int
689
+ ethnl_set_rss_fields (struct net_device * dev , struct genl_info * info ,
690
+ u32 rss_context , struct rss_reply_data * data ,
691
+ bool xfrm_sym , bool * mod )
692
+ {
693
+ struct nlattr * flow_nest = info -> attrs [ETHTOOL_A_RSS_FLOW_HASH ];
694
+ struct nlattr * flows [ETHTOOL_A_FLOW_MAX + 1 ];
695
+ const struct ethtool_ops * ops ;
696
+ int i , ret ;
697
+
698
+ ops = dev -> ethtool_ops ;
699
+
700
+ ret = rss_check_rxfh_fields_sym (dev , info , data , xfrm_sym );
701
+ if (ret )
702
+ return ret ;
703
+
704
+ if (!flow_nest )
705
+ return 0 ;
706
+
707
+ ret = nla_parse_nested (flows , ARRAY_SIZE (ethnl_rss_flows_policy ) - 1 ,
708
+ flow_nest , ethnl_rss_flows_policy , info -> extack );
709
+ if (ret < 0 )
710
+ return ret ;
711
+
712
+ for (i = 1 ; i < __ETHTOOL_A_FLOW_CNT ; i ++ ) {
713
+ struct ethtool_rxfh_fields fields = {
714
+ .flow_type = ethtool_rxfh_ft_nl2ioctl [i ],
715
+ .rss_context = rss_context ,
716
+ };
717
+
718
+ if (!flows [i ])
719
+ continue ;
720
+
721
+ fields .data = nla_get_u32 (flows [i ]);
722
+ if (data -> has_flow_hash && data -> flow_hash [i ] == fields .data )
723
+ continue ;
724
+
725
+ if (xfrm_sym && !ethtool_rxfh_config_is_sym (fields .data )) {
726
+ NL_SET_ERR_MSG_ATTR (info -> extack , flows [i ],
727
+ "conflict with xfrm-input" );
728
+ return - EINVAL ;
729
+ }
730
+
731
+ ret = ops -> set_rxfh_fields (dev , & fields , info -> extack );
732
+ if (ret )
733
+ return ret ;
734
+
735
+ * mod = true;
736
+ }
737
+
738
+ return 0 ;
739
+ }
740
+
647
741
static void
648
742
rss_set_ctx_update (struct ethtool_rxfh_context * ctx , struct nlattr * * tb ,
649
743
struct rss_reply_data * data , struct ethtool_rxfh_param * rxfh )
@@ -673,11 +767,11 @@ ethnl_rss_set(struct ethnl_req_info *req_info, struct genl_info *info)
673
767
struct rss_req_info * request = RSS_REQINFO (req_info );
674
768
struct ethtool_rxfh_context * ctx = NULL ;
675
769
struct net_device * dev = req_info -> dev ;
770
+ bool mod = false, fields_mod = false;
676
771
struct ethtool_rxfh_param rxfh = {};
677
772
struct nlattr * * tb = info -> attrs ;
678
773
struct rss_reply_data data = {};
679
774
const struct ethtool_ops * ops ;
680
- bool mod = false;
681
775
int ret ;
682
776
683
777
ops = dev -> ethtool_ops ;
@@ -710,14 +804,10 @@ ethnl_rss_set(struct ethnl_req_info *req_info, struct genl_info *info)
710
804
* symmetric hashing is requested.
711
805
*/
712
806
if (!request -> rss_context || ops -> rxfh_per_ctx_key )
713
- xfrm_sym = !! rxfh .input_xfrm ;
807
+ xfrm_sym = rxfh . input_xfrm || data .input_xfrm ;
714
808
if (rxfh .input_xfrm == data .input_xfrm )
715
809
rxfh .input_xfrm = RXH_XFRM_NO_CHANGE ;
716
810
717
- ret = rss_check_rxfh_fields_sym (dev , info , & data , xfrm_sym );
718
- if (ret )
719
- goto exit_clean_data ;
720
-
721
811
mutex_lock (& dev -> ethtool -> rss_lock );
722
812
if (request -> rss_context ) {
723
813
ctx = xa_load (& dev -> ethtool -> rss_ctx , request -> rss_context );
@@ -727,6 +817,11 @@ ethnl_rss_set(struct ethnl_req_info *req_info, struct genl_info *info)
727
817
}
728
818
}
729
819
820
+ ret = ethnl_set_rss_fields (dev , info , request -> rss_context ,
821
+ & data , xfrm_sym , & fields_mod );
822
+ if (ret )
823
+ goto exit_unlock ;
824
+
730
825
if (!mod )
731
826
ret = 0 ; /* nothing to tell the driver */
732
827
else if (!ops -> set_rxfh )
@@ -753,7 +848,7 @@ ethnl_rss_set(struct ethnl_req_info *req_info, struct genl_info *info)
753
848
exit_clean_data :
754
849
rss_cleanup_data (& data .base );
755
850
756
- return ret ?: mod ;
851
+ return ret ?: mod || fields_mod ;
757
852
}
758
853
759
854
const struct ethnl_request_ops ethnl_rss_request_ops = {
0 commit comments