aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael S. Tsirkin <mst@redhat.com>2017-03-29 12:09:14 -0400
committerMichael S. Tsirkin <mst@redhat.com>2017-04-07 09:38:59 -0400
commitfe36cbe0671e868cbd2f534a50ac60273fa5acf2 (patch)
tree0afa0bfd5cc28f9715d2540fafeb0b49ff3ef81d
parent404123c2db798027e852480ed9c4accef9f1d9e6 (diff)
virtio_net: clear MTU when out of range
virtio attempts to clear the MTU feature bit if the value is out of the supported range, but this has no real effect since FEATURES_OK has already been set. Fix this up by checking the MTU in the new validate callback. Fixes: 14de9d114a82 ("virtio-net: Add initial MTU advice feature") Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
-rw-r--r--drivers/net/virtio_net.c41
1 files changed, 30 insertions, 11 deletions
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 006f1a603102..f36584616e7d 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -2230,14 +2230,8 @@ static bool virtnet_validate_features(struct virtio_device *vdev)
2230#define MIN_MTU ETH_MIN_MTU 2230#define MIN_MTU ETH_MIN_MTU
2231#define MAX_MTU ETH_MAX_MTU 2231#define MAX_MTU ETH_MAX_MTU
2232 2232
2233static int virtnet_probe(struct virtio_device *vdev) 2233static int virtnet_validate(struct virtio_device *vdev)
2234{ 2234{
2235 int i, err;
2236 struct net_device *dev;
2237 struct virtnet_info *vi;
2238 u16 max_queue_pairs;
2239 int mtu;
2240
2241 if (!vdev->config->get) { 2235 if (!vdev->config->get) {
2242 dev_err(&vdev->dev, "%s failure: config access disabled\n", 2236 dev_err(&vdev->dev, "%s failure: config access disabled\n",
2243 __func__); 2237 __func__);
@@ -2247,6 +2241,25 @@ static int virtnet_probe(struct virtio_device *vdev)
2247 if (!virtnet_validate_features(vdev)) 2241 if (!virtnet_validate_features(vdev))
2248 return -EINVAL; 2242 return -EINVAL;
2249 2243
2244 if (virtio_has_feature(vdev, VIRTIO_NET_F_MTU)) {
2245 int mtu = virtio_cread16(vdev,
2246 offsetof(struct virtio_net_config,
2247 mtu));
2248 if (mtu < MIN_MTU)
2249 __virtio_clear_bit(vdev, VIRTIO_NET_F_MTU);
2250 }
2251
2252 return 0;
2253}
2254
2255static int virtnet_probe(struct virtio_device *vdev)
2256{
2257 int i, err;
2258 struct net_device *dev;
2259 struct virtnet_info *vi;
2260 u16 max_queue_pairs;
2261 int mtu;
2262
2250 /* Find if host supports multiqueue virtio_net device */ 2263 /* Find if host supports multiqueue virtio_net device */
2251 err = virtio_cread_feature(vdev, VIRTIO_NET_F_MQ, 2264 err = virtio_cread_feature(vdev, VIRTIO_NET_F_MQ,
2252 struct virtio_net_config, 2265 struct virtio_net_config,
@@ -2362,12 +2375,17 @@ static int virtnet_probe(struct virtio_device *vdev)
2362 offsetof(struct virtio_net_config, 2375 offsetof(struct virtio_net_config,
2363 mtu)); 2376 mtu));
2364 if (mtu < dev->min_mtu) { 2377 if (mtu < dev->min_mtu) {
2365 __virtio_clear_bit(vdev, VIRTIO_NET_F_MTU); 2378 /* Should never trigger: MTU was previously validated
2366 } else { 2379 * in virtnet_validate.
2367 dev->mtu = mtu; 2380 */
2368 dev->max_mtu = mtu; 2381 dev_err(&vdev->dev, "device MTU appears to have changed "
2382 "it is now %d < %d", mtu, dev->min_mtu);
2383 goto free_stats;
2369 } 2384 }
2370 2385
2386 dev->mtu = mtu;
2387 dev->max_mtu = mtu;
2388
2371 /* TODO: size buffers correctly in this case. */ 2389 /* TODO: size buffers correctly in this case. */
2372 if (dev->mtu > ETH_DATA_LEN) 2390 if (dev->mtu > ETH_DATA_LEN)
2373 vi->big_packets = true; 2391 vi->big_packets = true;
@@ -2548,6 +2566,7 @@ static struct virtio_driver virtio_net_driver = {
2548 .driver.name = KBUILD_MODNAME, 2566 .driver.name = KBUILD_MODNAME,
2549 .driver.owner = THIS_MODULE, 2567 .driver.owner = THIS_MODULE,
2550 .id_table = id_table, 2568 .id_table = id_table,
2569 .validate = virtnet_validate,
2551 .probe = virtnet_probe, 2570 .probe = virtnet_probe,
2552 .remove = virtnet_remove, 2571 .remove = virtnet_remove,
2553 .config_changed = virtnet_config_changed, 2572 .config_changed = virtnet_config_changed,