Skip to content

Commit c117082

Browse files
AndrewAtDaynixmstsirkin
authored andcommitted
drivers/net/virtio_net: Added RSS hash report control.
Now it's possible to control supported hashflows. Added hashflow set/get callbacks. Also, disabling RXH_IP_SRC/DST for TCP would disable then for UDP. TCP and UDP supports only: ethtool -U eth0 rx-flow-hash tcp4 sd RXH_IP_SRC + RXH_IP_DST ethtool -U eth0 rx-flow-hash tcp4 sdfn RXH_IP_SRC + RXH_IP_DST + RXH_L4_B_0_1 + RXH_L4_B_2_3 Disabling happens because VirtioNET hashtype for IP doesn't check L4 proto, it works for all IP packets(TCP, UDP, ICMP, etc.). For TCP and UDP, it's possible to set IP+PORT hashes. But disabling IP hashes will disable them for TCP and UDP simultaneously. It's possible to set IP+PORT for TCP/UDP and disable/enable IP for everything else(UDP, ICMP, etc.). Signed-off-by: Andrew Melnychenko <andrew@daynix.com> Link: https://lore.kernel.org/r/20220328175336.10802-5-andrew@daynix.com Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
1 parent 91f41f0 commit c117082

1 file changed

Lines changed: 140 additions & 1 deletion

File tree

drivers/net/virtio_net.c

Lines changed: 140 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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

22972414
static 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

26112750
static 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

Comments
 (0)