@@ -169,6 +169,24 @@ struct receive_queue {
169
169
struct xdp_rxq_info xdp_rxq ;
170
170
};
171
171
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
+
172
190
/* Control VQ buffers: protected by the rtnl lock */
173
191
struct control_buf {
174
192
struct virtio_net_ctrl_hdr hdr ;
@@ -178,6 +196,7 @@ struct control_buf {
178
196
u8 allmulti ;
179
197
__virtio16 vid ;
180
198
__virtio64 offloads ;
199
+ struct virtio_net_ctrl_rss rss ;
181
200
};
182
201
183
202
struct virtnet_info {
@@ -206,6 +225,12 @@ struct virtnet_info {
206
225
/* Host will merge rx buffers for big packets (shake it! shake it!) */
207
226
bool mergeable_rx_bufs ;
208
227
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
+
209
234
/* Has control virtqueue */
210
235
bool has_cvq ;
211
236
@@ -2184,6 +2209,57 @@ static void virtnet_get_ringparam(struct net_device *dev,
2184
2209
ring -> tx_pending = ring -> tx_max_pending ;
2185
2210
}
2186
2211
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
+
2187
2263
2188
2264
static void virtnet_get_drvinfo (struct net_device * dev ,
2189
2265
struct ethtool_drvinfo * info )
@@ -2412,6 +2488,71 @@ static void virtnet_update_settings(struct virtnet_info *vi)
2412
2488
vi -> duplex = duplex ;
2413
2489
}
2414
2490
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
+
2415
2556
static const struct ethtool_ops virtnet_ethtool_ops = {
2416
2557
.supported_coalesce_params = ETHTOOL_COALESCE_MAX_FRAMES ,
2417
2558
.get_drvinfo = virtnet_get_drvinfo ,
@@ -2427,6 +2568,11 @@ static const struct ethtool_ops virtnet_ethtool_ops = {
2427
2568
.set_link_ksettings = virtnet_set_link_ksettings ,
2428
2569
.set_coalesce = virtnet_set_coalesce ,
2429
2570
.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 ,
2430
2576
};
2431
2577
2432
2578
static void virtnet_freeze_down (struct virtio_device * vdev )
@@ -2679,6 +2825,16 @@ static int virtnet_set_features(struct net_device *dev,
2679
2825
vi -> guest_offloads = offloads ;
2680
2826
}
2681
2827
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
+
2682
2838
return 0 ;
2683
2839
}
2684
2840
@@ -3073,6 +3229,8 @@ static bool virtnet_validate_features(struct virtio_device *vdev)
3073
3229
"VIRTIO_NET_F_CTRL_VQ" ) ||
3074
3230
VIRTNET_FAIL_ON (vdev , VIRTIO_NET_F_MQ , "VIRTIO_NET_F_CTRL_VQ" ) ||
3075
3231
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 ,
3076
3234
"VIRTIO_NET_F_CTRL_VQ" ))) {
3077
3235
return false;
3078
3236
}
@@ -3113,13 +3271,14 @@ static int virtnet_probe(struct virtio_device *vdev)
3113
3271
u16 max_queue_pairs ;
3114
3272
int mtu ;
3115
3273
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 ));
3120
3279
3121
3280
/* 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 ||
3123
3282
max_queue_pairs > VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX ||
3124
3283
!virtio_has_feature (vdev , VIRTIO_NET_F_CTRL_VQ ))
3125
3284
max_queue_pairs = 1 ;
@@ -3207,6 +3366,23 @@ static int virtnet_probe(struct virtio_device *vdev)
3207
3366
if (virtio_has_feature (vdev , VIRTIO_NET_F_MRG_RXBUF ))
3208
3367
vi -> mergeable_rx_bufs = true;
3209
3368
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
+ }
3210
3386
if (virtio_has_feature (vdev , VIRTIO_NET_F_MRG_RXBUF ) ||
3211
3387
virtio_has_feature (vdev , VIRTIO_F_VERSION_1 ))
3212
3388
vi -> hdr_len = sizeof (struct virtio_net_hdr_mrg_rxbuf );
@@ -3275,6 +3451,9 @@ static int virtnet_probe(struct virtio_device *vdev)
3275
3451
}
3276
3452
}
3277
3453
3454
+ if (vi -> has_rss )
3455
+ virtnet_init_default_rss (vi );
3456
+
3278
3457
err = register_netdev (dev );
3279
3458
if (err ) {
3280
3459
pr_debug ("virtio_net: registering device failed\n" );
@@ -3406,7 +3585,8 @@ static struct virtio_device_id id_table[] = {
3406
3585
VIRTIO_NET_F_GUEST_ANNOUNCE, VIRTIO_NET_F_MQ, \
3407
3586
VIRTIO_NET_F_CTRL_MAC_ADDR, \
3408
3587
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
3410
3590
3411
3591
static unsigned int features [] = {
3412
3592
VIRTNET_FEATURES ,
0 commit comments