Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c7114b1

Browse files
AndrewAtDaynixmstsirkin
authored andcommitted
drivers/net/virtio_net: Added basic RSS support.
Added features for RSS. Added initialization, RXHASH feature and ethtool ops. By default RSS/RXHASH is disabled. Virtio RSS "IPv6 extensions" hashes disabled. Added ethtools ops to set key and indirection table. Signed-off-by: Andrew Melnychenko <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Michael S. Tsirkin <[email protected]>
1 parent c1ddc42 commit c7114b1

File tree

1 file changed

+186
-6
lines changed

1 file changed

+186
-6
lines changed

drivers/net/virtio_net.c

Lines changed: 186 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,24 @@ struct receive_queue {
169169
struct xdp_rxq_info xdp_rxq;
170170
};
171171

172+
/* This structure can contain rss message with maximum settings for indirection table and keysize
173+
* Note, that default structure that describes RSS configuration virtio_net_rss_config
174+
* contains same info but can't handle table values.
175+
* In any case, structure would be passed to virtio hw through sg_buf split by parts
176+
* because table sizes may be differ according to the device configuration.
177+
*/
178+
#define VIRTIO_NET_RSS_MAX_KEY_SIZE 40
179+
#define VIRTIO_NET_RSS_MAX_TABLE_LEN 128
180+
struct virtio_net_ctrl_rss {
181+
u32 hash_types;
182+
u16 indirection_table_mask;
183+
u16 unclassified_queue;
184+
u16 indirection_table[VIRTIO_NET_RSS_MAX_TABLE_LEN];
185+
u16 max_tx_vq;
186+
u8 hash_key_length;
187+
u8 key[VIRTIO_NET_RSS_MAX_KEY_SIZE];
188+
};
189+
172190
/* Control VQ buffers: protected by the rtnl lock */
173191
struct control_buf {
174192
struct virtio_net_ctrl_hdr hdr;
@@ -178,6 +196,7 @@ struct control_buf {
178196
u8 allmulti;
179197
__virtio16 vid;
180198
__virtio64 offloads;
199+
struct virtio_net_ctrl_rss rss;
181200
};
182201

183202
struct virtnet_info {
@@ -206,6 +225,12 @@ struct virtnet_info {
206225
/* Host will merge rx buffers for big packets (shake it! shake it!) */
207226
bool mergeable_rx_bufs;
208227

228+
/* Host supports rss and/or hash report */
229+
bool has_rss;
230+
u8 rss_key_size;
231+
u16 rss_indir_table_size;
232+
u32 rss_hash_types_supported;
233+
209234
/* Has control virtqueue */
210235
bool has_cvq;
211236

@@ -2184,6 +2209,57 @@ static void virtnet_get_ringparam(struct net_device *dev,
21842209
ring->tx_pending = ring->tx_max_pending;
21852210
}
21862211

2212+
static bool virtnet_commit_rss_command(struct virtnet_info *vi)
2213+
{
2214+
struct net_device *dev = vi->dev;
2215+
struct scatterlist sgs[4];
2216+
unsigned int sg_buf_size;
2217+
2218+
/* prepare sgs */
2219+
sg_init_table(sgs, 4);
2220+
2221+
sg_buf_size = offsetof(struct virtio_net_ctrl_rss, indirection_table);
2222+
sg_set_buf(&sgs[0], &vi->ctrl->rss, sg_buf_size);
2223+
2224+
sg_buf_size = sizeof(uint16_t) * (vi->ctrl->rss.indirection_table_mask + 1);
2225+
sg_set_buf(&sgs[1], vi->ctrl->rss.indirection_table, sg_buf_size);
2226+
2227+
sg_buf_size = offsetof(struct virtio_net_ctrl_rss, key)
2228+
- offsetof(struct virtio_net_ctrl_rss, max_tx_vq);
2229+
sg_set_buf(&sgs[2], &vi->ctrl->rss.max_tx_vq, sg_buf_size);
2230+
2231+
sg_buf_size = vi->rss_key_size;
2232+
sg_set_buf(&sgs[3], vi->ctrl->rss.key, sg_buf_size);
2233+
2234+
if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_MQ,
2235+
VIRTIO_NET_CTRL_MQ_RSS_CONFIG, sgs)) {
2236+
dev_warn(&dev->dev, "VIRTIONET issue with committing RSS sgs\n");
2237+
return false;
2238+
}
2239+
return true;
2240+
}
2241+
2242+
static void virtnet_init_default_rss(struct virtnet_info *vi)
2243+
{
2244+
u32 indir_val = 0;
2245+
int i = 0;
2246+
2247+
vi->ctrl->rss.hash_types = vi->rss_hash_types_supported;
2248+
vi->ctrl->rss.indirection_table_mask = vi->rss_indir_table_size
2249+
? vi->rss_indir_table_size - 1 : 0;
2250+
vi->ctrl->rss.unclassified_queue = 0;
2251+
2252+
for (; i < vi->rss_indir_table_size; ++i) {
2253+
indir_val = ethtool_rxfh_indir_default(i, vi->curr_queue_pairs);
2254+
vi->ctrl->rss.indirection_table[i] = indir_val;
2255+
}
2256+
2257+
vi->ctrl->rss.max_tx_vq = vi->curr_queue_pairs;
2258+
vi->ctrl->rss.hash_key_length = vi->rss_key_size;
2259+
2260+
netdev_rss_key_fill(vi->ctrl->rss.key, vi->rss_key_size);
2261+
}
2262+
21872263

21882264
static void virtnet_get_drvinfo(struct net_device *dev,
21892265
struct ethtool_drvinfo *info)
@@ -2412,6 +2488,71 @@ static void virtnet_update_settings(struct virtnet_info *vi)
24122488
vi->duplex = duplex;
24132489
}
24142490

2491+
static u32 virtnet_get_rxfh_key_size(struct net_device *dev)
2492+
{
2493+
return ((struct virtnet_info *)netdev_priv(dev))->rss_key_size;
2494+
}
2495+
2496+
static u32 virtnet_get_rxfh_indir_size(struct net_device *dev)
2497+
{
2498+
return ((struct virtnet_info *)netdev_priv(dev))->rss_indir_table_size;
2499+
}
2500+
2501+
static int virtnet_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, u8 *hfunc)
2502+
{
2503+
struct virtnet_info *vi = netdev_priv(dev);
2504+
int i;
2505+
2506+
if (indir) {
2507+
for (i = 0; i < vi->rss_indir_table_size; ++i)
2508+
indir[i] = vi->ctrl->rss.indirection_table[i];
2509+
}
2510+
2511+
if (key)
2512+
memcpy(key, vi->ctrl->rss.key, vi->rss_key_size);
2513+
2514+
if (hfunc)
2515+
*hfunc = ETH_RSS_HASH_TOP;
2516+
2517+
return 0;
2518+
}
2519+
2520+
static int virtnet_set_rxfh(struct net_device *dev, const u32 *indir, const u8 *key, const u8 hfunc)
2521+
{
2522+
struct virtnet_info *vi = netdev_priv(dev);
2523+
int i;
2524+
2525+
if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
2526+
return -EOPNOTSUPP;
2527+
2528+
if (indir) {
2529+
for (i = 0; i < vi->rss_indir_table_size; ++i)
2530+
vi->ctrl->rss.indirection_table[i] = indir[i];
2531+
}
2532+
if (key)
2533+
memcpy(vi->ctrl->rss.key, key, vi->rss_key_size);
2534+
2535+
virtnet_commit_rss_command(vi);
2536+
2537+
return 0;
2538+
}
2539+
2540+
static int virtnet_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, u32 *rule_locs)
2541+
{
2542+
struct virtnet_info *vi = netdev_priv(dev);
2543+
int rc = 0;
2544+
2545+
switch (info->cmd) {
2546+
case ETHTOOL_GRXRINGS:
2547+
info->data = vi->curr_queue_pairs;
2548+
break;
2549+
default:
2550+
rc = -EOPNOTSUPP;
2551+
}
2552+
2553+
return rc;
2554+
}
2555+
24152556
static const struct ethtool_ops virtnet_ethtool_ops = {
24162557
.supported_coalesce_params = ETHTOOL_COALESCE_MAX_FRAMES,
24172558
.get_drvinfo = virtnet_get_drvinfo,
@@ -2427,6 +2568,11 @@ static const struct ethtool_ops virtnet_ethtool_ops = {
24272568
.set_link_ksettings = virtnet_set_link_ksettings,
24282569
.set_coalesce = virtnet_set_coalesce,
24292570
.get_coalesce = virtnet_get_coalesce,
2571+
.get_rxfh_key_size = virtnet_get_rxfh_key_size,
2572+
.get_rxfh_indir_size = virtnet_get_rxfh_indir_size,
2573+
.get_rxfh = virtnet_get_rxfh,
2574+
.set_rxfh = virtnet_set_rxfh,
2575+
.get_rxnfc = virtnet_get_rxnfc,
24302576
};
24312577

24322578
static void virtnet_freeze_down(struct virtio_device *vdev)
@@ -2679,6 +2825,16 @@ static int virtnet_set_features(struct net_device *dev,
26792825
vi->guest_offloads = offloads;
26802826
}
26812827

2828+
if ((dev->features ^ features) & NETIF_F_RXHASH) {
2829+
if (features & NETIF_F_RXHASH)
2830+
vi->ctrl->rss.hash_types = vi->rss_hash_types_supported;
2831+
else
2832+
vi->ctrl->rss.hash_types = VIRTIO_NET_HASH_REPORT_NONE;
2833+
2834+
if (!virtnet_commit_rss_command(vi))
2835+
return -EINVAL;
2836+
}
2837+
26822838
return 0;
26832839
}
26842840

@@ -3073,6 +3229,8 @@ static bool virtnet_validate_features(struct virtio_device *vdev)
30733229
"VIRTIO_NET_F_CTRL_VQ") ||
30743230
VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_MQ, "VIRTIO_NET_F_CTRL_VQ") ||
30753231
VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_CTRL_MAC_ADDR,
3232+
"VIRTIO_NET_F_CTRL_VQ") ||
3233+
VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_RSS,
30763234
"VIRTIO_NET_F_CTRL_VQ"))) {
30773235
return false;
30783236
}
@@ -3113,13 +3271,14 @@ static int virtnet_probe(struct virtio_device *vdev)
31133271
u16 max_queue_pairs;
31143272
int mtu;
31153273

3116-
/* Find if host supports multiqueue virtio_net device */
3117-
err = virtio_cread_feature(vdev, VIRTIO_NET_F_MQ,
3118-
struct virtio_net_config,
3119-
max_virtqueue_pairs, &max_queue_pairs);
3274+
/* Find if host supports multiqueue/rss virtio_net device */
3275+
max_queue_pairs = 1;
3276+
if (virtio_has_feature(vdev, VIRTIO_NET_F_MQ) || virtio_has_feature(vdev, VIRTIO_NET_F_RSS))
3277+
max_queue_pairs =
3278+
virtio_cread16(vdev, offsetof(struct virtio_net_config, max_virtqueue_pairs));
31203279

31213280
/* We need at least 2 queue's */
3122-
if (err || max_queue_pairs < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN ||
3281+
if (max_queue_pairs < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN ||
31233282
max_queue_pairs > VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX ||
31243283
!virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ))
31253284
max_queue_pairs = 1;
@@ -3207,6 +3366,23 @@ static int virtnet_probe(struct virtio_device *vdev)
32073366
if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF))
32083367
vi->mergeable_rx_bufs = true;
32093368

3369+
if (virtio_has_feature(vdev, VIRTIO_NET_F_RSS)) {
3370+
vi->has_rss = true;
3371+
vi->rss_indir_table_size =
3372+
virtio_cread16(vdev, offsetof(struct virtio_net_config,
3373+
rss_max_indirection_table_length));
3374+
vi->rss_key_size =
3375+
virtio_cread8(vdev, offsetof(struct virtio_net_config, rss_max_key_size));
3376+
3377+
vi->rss_hash_types_supported =
3378+
virtio_cread32(vdev, offsetof(struct virtio_net_config, supported_hash_types));
3379+
vi->rss_hash_types_supported &=
3380+
~(VIRTIO_NET_RSS_HASH_TYPE_IP_EX |
3381+
VIRTIO_NET_RSS_HASH_TYPE_TCP_EX |
3382+
VIRTIO_NET_RSS_HASH_TYPE_UDP_EX);
3383+
3384+
dev->hw_features |= NETIF_F_RXHASH;
3385+
}
32103386
if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF) ||
32113387
virtio_has_feature(vdev, VIRTIO_F_VERSION_1))
32123388
vi->hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
@@ -3275,6 +3451,9 @@ static int virtnet_probe(struct virtio_device *vdev)
32753451
}
32763452
}
32773453

3454+
if (vi->has_rss)
3455+
virtnet_init_default_rss(vi);
3456+
32783457
err = register_netdev(dev);
32793458
if (err) {
32803459
pr_debug("virtio_net: registering device failed\n");
@@ -3406,7 +3585,8 @@ static struct virtio_device_id id_table[] = {
34063585
VIRTIO_NET_F_GUEST_ANNOUNCE, VIRTIO_NET_F_MQ, \
34073586
VIRTIO_NET_F_CTRL_MAC_ADDR, \
34083587
VIRTIO_NET_F_MTU, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS, \
3409-
VIRTIO_NET_F_SPEED_DUPLEX, VIRTIO_NET_F_STANDBY
3588+
VIRTIO_NET_F_SPEED_DUPLEX, VIRTIO_NET_F_STANDBY, \
3589+
VIRTIO_NET_F_RSS
34103590

34113591
static unsigned int features[] = {
34123592
VIRTNET_FEATURES,

0 commit comments

Comments
 (0)