Skip to content

Commit cf7313e

Browse files
jasowangBrian Maly
authored andcommitted
virtio-net: synchronize operstate with admin state on up/down
This patch synchronizes operstate with admin state per RFC2863. This is done by trying to toggle the carrier upon open/close and synchronize with the config change work. This allows to propagate status correctly to stacked devices like: ip link add link enp0s3 macvlan0 type macvlan ip link set link enp0s3 down ip link show Before this patch: 3: enp0s3: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 1000 link/ether 00:00:05:00:00:09 brd ff:ff:ff:ff:ff:ff ...... 5: macvlan0@enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000 link/ether b2:a9:c5:04:da:53 brd ff:ff:ff:ff:ff:ff After this patch: 3: enp0s3: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 1000 link/ether 00:00:05:00:00:09 brd ff:ff:ff:ff:ff:ff ... 5: macvlan0@enp0s3: <NO-CARRIER,BROADCAST,MULTICAST,UP,M-DOWN> mtu 1500 qdisc noqueue state LOWERLAYERDOWN mode DEFAULT group default qlen 1000 link/ether b2:a9:c5:04:da:53 brd ff:ff:ff:ff:ff:ff Cc: Venkat Venkatsubra <[email protected]> Cc: Gia-Khanh Nguyen <[email protected]> Acked-by: Michael S. Tsirkin <[email protected]> Signed-off-by: Jason Wang <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]> [Upstream commit df28de7] Orabug: 36637822 Reviewed-by: Dongli Zhang <[email protected]> Signed-off-by: Venkat Venkatsubra <[email protected]> Signed-off-by: Brian Maly <[email protected]>
1 parent 06b4b71 commit cf7313e

File tree

1 file changed

+50
-28
lines changed

1 file changed

+50
-28
lines changed

drivers/net/virtio_net.c

Lines changed: 50 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1641,6 +1641,25 @@ static int virtnet_enable_queue_pair(struct virtnet_info *vi, int qp_index)
16411641
return err;
16421642
}
16431643

1644+
static void virtnet_update_settings(struct virtnet_info *vi)
1645+
{
1646+
u32 speed;
1647+
u8 duplex;
1648+
1649+
if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_SPEED_DUPLEX))
1650+
return;
1651+
1652+
virtio_cread_le(vi->vdev, struct virtio_net_config, speed, &speed);
1653+
1654+
if (ethtool_validate_speed(speed))
1655+
vi->speed = speed;
1656+
1657+
virtio_cread_le(vi->vdev, struct virtio_net_config, duplex, &duplex);
1658+
1659+
if (ethtool_validate_duplex(duplex))
1660+
vi->duplex = duplex;
1661+
}
1662+
16441663
static int virtnet_open(struct net_device *dev)
16451664
{
16461665
struct virtnet_info *vi = netdev_priv(dev);
@@ -1659,6 +1678,15 @@ static int virtnet_open(struct net_device *dev)
16591678
goto err_enable_qp;
16601679
}
16611680

1681+
if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
1682+
if (vi->status & VIRTIO_NET_S_LINK_UP)
1683+
netif_carrier_on(vi->dev);
1684+
virtio_config_driver_enable(vi->vdev);
1685+
} else {
1686+
vi->status = VIRTIO_NET_S_LINK_UP;
1687+
netif_carrier_on(dev);
1688+
}
1689+
16621690
return 0;
16631691

16641692
err_enable_qp:
@@ -2034,10 +2062,20 @@ static int virtnet_close(struct net_device *dev)
20342062
disable_delayed_refill(vi);
20352063
/* Make sure refill_work doesn't re-enable napi! */
20362064
cancel_delayed_work_sync(&vi->refill);
2065+
/* Prevent the config change callback from changing carrier
2066+
* after close
2067+
*/
2068+
virtio_config_driver_disable(vi->vdev);
2069+
/* Stop getting status/speed updates: we don't care until next
2070+
* open
2071+
*/
2072+
cancel_work_sync(&vi->config_work);
20372073

20382074
for (i = 0; i < vi->max_queue_pairs; i++)
20392075
virtnet_disable_queue_pair(vi, i);
20402076

2077+
netif_carrier_off(dev);
2078+
20412079
return 0;
20422080
}
20432081

@@ -2468,25 +2506,6 @@ static void virtnet_init_settings(struct net_device *dev)
24682506
vi->duplex = DUPLEX_UNKNOWN;
24692507
}
24702508

2471-
static void virtnet_update_settings(struct virtnet_info *vi)
2472-
{
2473-
u32 speed;
2474-
u8 duplex;
2475-
2476-
if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_SPEED_DUPLEX))
2477-
return;
2478-
2479-
virtio_cread_le(vi->vdev, struct virtio_net_config, speed, &speed);
2480-
2481-
if (ethtool_validate_speed(speed))
2482-
vi->speed = speed;
2483-
2484-
virtio_cread_le(vi->vdev, struct virtio_net_config, duplex, &duplex);
2485-
2486-
if (ethtool_validate_duplex(duplex))
2487-
vi->duplex = duplex;
2488-
}
2489-
24902509
static const struct ethtool_ops virtnet_ethtool_ops = {
24912510
.supported_coalesce_params = ETHTOOL_COALESCE_MAX_FRAMES,
24922511
.get_drvinfo = virtnet_get_drvinfo,
@@ -3379,29 +3398,32 @@ static int virtnet_probe(struct virtio_device *vdev)
33793398
goto free_failover;
33803399
}
33813400

3401+
/* Disable config change notification until ndo_open. */
3402+
virtio_config_driver_disable(vi->vdev);
3403+
33823404
virtio_device_ready(vdev);
33833405

33843406
_virtnet_set_queues(vi, vi->curr_queue_pairs);
33853407

3386-
rtnl_unlock();
3387-
3388-
err = virtnet_cpu_notif_add(vi);
3389-
if (err) {
3390-
pr_debug("virtio_net: registering cpu notifier failed\n");
3391-
goto free_unregister_netdev;
3392-
}
3393-
33943408
/* Assume link up if device can't report link status,
33953409
otherwise get link status from config. */
33963410
netif_carrier_off(dev);
33973411
if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
3398-
schedule_work(&vi->config_work);
3412+
virtnet_config_changed_work(&vi->config_work);
33993413
} else {
34003414
vi->status = VIRTIO_NET_S_LINK_UP;
34013415
virtnet_update_settings(vi);
34023416
netif_carrier_on(dev);
34033417
}
34043418

3419+
rtnl_unlock();
3420+
3421+
err = virtnet_cpu_notif_add(vi);
3422+
if (err) {
3423+
pr_debug("virtio_net: registering cpu notifier failed\n");
3424+
goto free_unregister_netdev;
3425+
}
3426+
34053427
for (i = 0; i < ARRAY_SIZE(guest_offloads); i++)
34063428
if (virtio_has_feature(vi->vdev, guest_offloads[i]))
34073429
set_bit(guest_offloads[i], &vi->guest_offloads);

0 commit comments

Comments
 (0)