@@ -231,6 +231,7 @@ struct virtnet_info {
231231 u8 rss_key_size ;
232232 u16 rss_indir_table_size ;
233233 u32 rss_hash_types_supported ;
234+ u32 rss_hash_types_saved ;
234235
235236 /* Has control virtqueue */
236237 bool has_cvq ;
@@ -2278,6 +2279,7 @@ static void virtnet_init_default_rss(struct virtnet_info *vi)
22782279 int i = 0 ;
22792280
22802281 vi -> ctrl -> rss .hash_types = vi -> rss_hash_types_supported ;
2282+ vi -> rss_hash_types_saved = vi -> rss_hash_types_supported ;
22812283 vi -> ctrl -> rss .indirection_table_mask = vi -> rss_indir_table_size
22822284 ? vi -> rss_indir_table_size - 1 : 0 ;
22832285 vi -> ctrl -> rss .unclassified_queue = 0 ;
@@ -2293,6 +2295,121 @@ static void virtnet_init_default_rss(struct virtnet_info *vi)
22932295 netdev_rss_key_fill (vi -> ctrl -> rss .key , vi -> rss_key_size );
22942296}
22952297
2298+ static void virtnet_get_hashflow (const struct virtnet_info * vi , struct ethtool_rxnfc * info )
2299+ {
2300+ info -> data = 0 ;
2301+ switch (info -> flow_type ) {
2302+ case TCP_V4_FLOW :
2303+ if (vi -> rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_TCPv4 ) {
2304+ info -> data = RXH_IP_SRC | RXH_IP_DST |
2305+ RXH_L4_B_0_1 | RXH_L4_B_2_3 ;
2306+ } else if (vi -> rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_IPv4 ) {
2307+ info -> data = RXH_IP_SRC | RXH_IP_DST ;
2308+ }
2309+ break ;
2310+ case TCP_V6_FLOW :
2311+ if (vi -> rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_TCPv6 ) {
2312+ info -> data = RXH_IP_SRC | RXH_IP_DST |
2313+ RXH_L4_B_0_1 | RXH_L4_B_2_3 ;
2314+ } else if (vi -> rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_IPv6 ) {
2315+ info -> data = RXH_IP_SRC | RXH_IP_DST ;
2316+ }
2317+ break ;
2318+ case UDP_V4_FLOW :
2319+ if (vi -> rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_UDPv4 ) {
2320+ info -> data = RXH_IP_SRC | RXH_IP_DST |
2321+ RXH_L4_B_0_1 | RXH_L4_B_2_3 ;
2322+ } else if (vi -> rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_IPv4 ) {
2323+ info -> data = RXH_IP_SRC | RXH_IP_DST ;
2324+ }
2325+ break ;
2326+ case UDP_V6_FLOW :
2327+ if (vi -> rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_UDPv6 ) {
2328+ info -> data = RXH_IP_SRC | RXH_IP_DST |
2329+ RXH_L4_B_0_1 | RXH_L4_B_2_3 ;
2330+ } else if (vi -> rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_IPv6 ) {
2331+ info -> data = RXH_IP_SRC | RXH_IP_DST ;
2332+ }
2333+ break ;
2334+ case IPV4_FLOW :
2335+ if (vi -> rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_IPv4 )
2336+ info -> data = RXH_IP_SRC | RXH_IP_DST ;
2337+
2338+ break ;
2339+ case IPV6_FLOW :
2340+ if (vi -> rss_hash_types_saved & VIRTIO_NET_RSS_HASH_TYPE_IPv6 )
2341+ info -> data = RXH_IP_SRC | RXH_IP_DST ;
2342+
2343+ break ;
2344+ default :
2345+ info -> data = 0 ;
2346+ break ;
2347+ }
2348+ }
2349+
2350+ static bool virtnet_set_hashflow (struct virtnet_info * vi , struct ethtool_rxnfc * info )
2351+ {
2352+ u32 new_hashtypes = vi -> rss_hash_types_saved ;
2353+ bool is_disable = info -> data & RXH_DISCARD ;
2354+ bool is_l4 = info -> data == (RXH_IP_SRC | RXH_IP_DST | RXH_L4_B_0_1 | RXH_L4_B_2_3 );
2355+
2356+ /* supports only 'sd', 'sdfn' and 'r' */
2357+ if (!((info -> data == (RXH_IP_SRC | RXH_IP_DST )) | is_l4 | is_disable ))
2358+ return false;
2359+
2360+ switch (info -> flow_type ) {
2361+ case TCP_V4_FLOW :
2362+ new_hashtypes &= ~(VIRTIO_NET_RSS_HASH_TYPE_IPv4 | VIRTIO_NET_RSS_HASH_TYPE_TCPv4 );
2363+ if (!is_disable )
2364+ new_hashtypes |= VIRTIO_NET_RSS_HASH_TYPE_IPv4
2365+ | (is_l4 ? VIRTIO_NET_RSS_HASH_TYPE_TCPv4 : 0 );
2366+ break ;
2367+ case UDP_V4_FLOW :
2368+ new_hashtypes &= ~(VIRTIO_NET_RSS_HASH_TYPE_IPv4 | VIRTIO_NET_RSS_HASH_TYPE_UDPv4 );
2369+ if (!is_disable )
2370+ new_hashtypes |= VIRTIO_NET_RSS_HASH_TYPE_IPv4
2371+ | (is_l4 ? VIRTIO_NET_RSS_HASH_TYPE_UDPv4 : 0 );
2372+ break ;
2373+ case IPV4_FLOW :
2374+ new_hashtypes &= ~VIRTIO_NET_RSS_HASH_TYPE_IPv4 ;
2375+ if (!is_disable )
2376+ new_hashtypes = VIRTIO_NET_RSS_HASH_TYPE_IPv4 ;
2377+ break ;
2378+ case TCP_V6_FLOW :
2379+ new_hashtypes &= ~(VIRTIO_NET_RSS_HASH_TYPE_IPv6 | VIRTIO_NET_RSS_HASH_TYPE_TCPv6 );
2380+ if (!is_disable )
2381+ new_hashtypes |= VIRTIO_NET_RSS_HASH_TYPE_IPv6
2382+ | (is_l4 ? VIRTIO_NET_RSS_HASH_TYPE_TCPv6 : 0 );
2383+ break ;
2384+ case UDP_V6_FLOW :
2385+ new_hashtypes &= ~(VIRTIO_NET_RSS_HASH_TYPE_IPv6 | VIRTIO_NET_RSS_HASH_TYPE_UDPv6 );
2386+ if (!is_disable )
2387+ new_hashtypes |= VIRTIO_NET_RSS_HASH_TYPE_IPv6
2388+ | (is_l4 ? VIRTIO_NET_RSS_HASH_TYPE_UDPv6 : 0 );
2389+ break ;
2390+ case IPV6_FLOW :
2391+ new_hashtypes &= ~VIRTIO_NET_RSS_HASH_TYPE_IPv6 ;
2392+ if (!is_disable )
2393+ new_hashtypes = VIRTIO_NET_RSS_HASH_TYPE_IPv6 ;
2394+ break ;
2395+ default :
2396+ /* unsupported flow */
2397+ return false;
2398+ }
2399+
2400+ /* if unsupported hashtype was set */
2401+ if (new_hashtypes != (new_hashtypes & vi -> rss_hash_types_supported ))
2402+ return false;
2403+
2404+ if (new_hashtypes != vi -> rss_hash_types_saved ) {
2405+ vi -> rss_hash_types_saved = new_hashtypes ;
2406+ vi -> ctrl -> rss .hash_types = vi -> rss_hash_types_saved ;
2407+ if (vi -> dev -> features & NETIF_F_RXHASH )
2408+ return virtnet_commit_rss_command (vi );
2409+ }
2410+
2411+ return true;
2412+ }
22962413
22972414static void virtnet_get_drvinfo (struct net_device * dev ,
22982415 struct ethtool_drvinfo * info )
@@ -2578,6 +2695,27 @@ static int virtnet_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info,
25782695 switch (info -> cmd ) {
25792696 case ETHTOOL_GRXRINGS :
25802697 info -> data = vi -> curr_queue_pairs ;
2698+ break ;
2699+ case ETHTOOL_GRXFH :
2700+ virtnet_get_hashflow (vi , info );
2701+ break ;
2702+ default :
2703+ rc = - EOPNOTSUPP ;
2704+ }
2705+
2706+ return rc ;
2707+ }
2708+
2709+ static int virtnet_set_rxnfc (struct net_device * dev , struct ethtool_rxnfc * info )
2710+ {
2711+ struct virtnet_info * vi = netdev_priv (dev );
2712+ int rc = 0 ;
2713+
2714+ switch (info -> cmd ) {
2715+ case ETHTOOL_SRXFH :
2716+ if (!virtnet_set_hashflow (vi , info ))
2717+ rc = - EINVAL ;
2718+
25812719 break ;
25822720 default :
25832721 rc = - EOPNOTSUPP ;
@@ -2606,6 +2744,7 @@ static const struct ethtool_ops virtnet_ethtool_ops = {
26062744 .get_rxfh = virtnet_get_rxfh ,
26072745 .set_rxfh = virtnet_set_rxfh ,
26082746 .get_rxnfc = virtnet_get_rxnfc ,
2747+ .set_rxnfc = virtnet_set_rxnfc ,
26092748};
26102749
26112750static void virtnet_freeze_down (struct virtio_device * vdev )
@@ -2860,7 +2999,7 @@ static int virtnet_set_features(struct net_device *dev,
28602999
28613000 if ((dev -> features ^ features ) & NETIF_F_RXHASH ) {
28623001 if (features & NETIF_F_RXHASH )
2863- vi -> ctrl -> rss .hash_types = vi -> rss_hash_types_supported ;
3002+ vi -> ctrl -> rss .hash_types = vi -> rss_hash_types_saved ;
28643003 else
28653004 vi -> ctrl -> rss .hash_types = VIRTIO_NET_HASH_REPORT_NONE ;
28663005
0 commit comments