Skip to content

Commit cb06b26

Browse files
jasowanggregkh
authored andcommitted
virtio-net: synchronize operstate with admin state on up/down
[ Upstream commit df28de7 ] 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 <venkat.x.venkatsubra@oracle.com> Cc: Gia-Khanh Nguyen <gia-khanh.nguyen@oracle.com> Acked-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Jason Wang <jasowang@redhat.com> Link: https://patch.msgid.link/20240814052228.4654-4-jasowang@redhat.com Signed-off-by: Jakub Kicinski <kuba@kernel.org> Stable-dep-of: c392d60 ("virtio-net: synchronize probe with ndo_set_features") Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 3cc20be commit cb06b26

1 file changed

Lines changed: 50 additions & 28 deletions

File tree

drivers/net/virtio_net.c

Lines changed: 50 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2884,6 +2884,25 @@ static void virtnet_cancel_dim(struct virtnet_info *vi, struct dim *dim)
28842884
net_dim_work_cancel(dim);
28852885
}
28862886

2887+
static void virtnet_update_settings(struct virtnet_info *vi)
2888+
{
2889+
u32 speed;
2890+
u8 duplex;
2891+
2892+
if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_SPEED_DUPLEX))
2893+
return;
2894+
2895+
virtio_cread_le(vi->vdev, struct virtio_net_config, speed, &speed);
2896+
2897+
if (ethtool_validate_speed(speed))
2898+
vi->speed = speed;
2899+
2900+
virtio_cread_le(vi->vdev, struct virtio_net_config, duplex, &duplex);
2901+
2902+
if (ethtool_validate_duplex(duplex))
2903+
vi->duplex = duplex;
2904+
}
2905+
28872906
static int virtnet_open(struct net_device *dev)
28882907
{
28892908
struct virtnet_info *vi = netdev_priv(dev);
@@ -2902,6 +2921,15 @@ static int virtnet_open(struct net_device *dev)
29022921
goto err_enable_qp;
29032922
}
29042923

2924+
if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
2925+
if (vi->status & VIRTIO_NET_S_LINK_UP)
2926+
netif_carrier_on(vi->dev);
2927+
virtio_config_driver_enable(vi->vdev);
2928+
} else {
2929+
vi->status = VIRTIO_NET_S_LINK_UP;
2930+
netif_carrier_on(dev);
2931+
}
2932+
29052933
return 0;
29062934

29072935
err_enable_qp:
@@ -3380,12 +3408,22 @@ static int virtnet_close(struct net_device *dev)
33803408
disable_delayed_refill(vi);
33813409
/* Make sure refill_work doesn't re-enable napi! */
33823410
cancel_delayed_work_sync(&vi->refill);
3411+
/* Prevent the config change callback from changing carrier
3412+
* after close
3413+
*/
3414+
virtio_config_driver_disable(vi->vdev);
3415+
/* Stop getting status/speed updates: we don't care until next
3416+
* open
3417+
*/
3418+
cancel_work_sync(&vi->config_work);
33833419

33843420
for (i = 0; i < vi->max_queue_pairs; i++) {
33853421
virtnet_disable_queue_pair(vi, i);
33863422
virtnet_cancel_dim(vi, &vi->rq[i].dim);
33873423
}
33883424

3425+
netif_carrier_off(dev);
3426+
33893427
return 0;
33903428
}
33913429

@@ -5094,25 +5132,6 @@ static void virtnet_init_settings(struct net_device *dev)
50945132
vi->duplex = DUPLEX_UNKNOWN;
50955133
}
50965134

5097-
static void virtnet_update_settings(struct virtnet_info *vi)
5098-
{
5099-
u32 speed;
5100-
u8 duplex;
5101-
5102-
if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_SPEED_DUPLEX))
5103-
return;
5104-
5105-
virtio_cread_le(vi->vdev, struct virtio_net_config, speed, &speed);
5106-
5107-
if (ethtool_validate_speed(speed))
5108-
vi->speed = speed;
5109-
5110-
virtio_cread_le(vi->vdev, struct virtio_net_config, duplex, &duplex);
5111-
5112-
if (ethtool_validate_duplex(duplex))
5113-
vi->duplex = duplex;
5114-
}
5115-
51165135
static u32 virtnet_get_rxfh_key_size(struct net_device *dev)
51175136
{
51185137
return ((struct virtnet_info *)netdev_priv(dev))->rss_key_size;
@@ -6521,6 +6540,9 @@ static int virtnet_probe(struct virtio_device *vdev)
65216540
goto free_failover;
65226541
}
65236542

6543+
/* Disable config change notification until ndo_open. */
6544+
virtio_config_driver_disable(vi->vdev);
6545+
65246546
virtio_device_ready(vdev);
65256547

65266548
virtnet_set_queues(vi, vi->curr_queue_pairs);
@@ -6570,25 +6592,25 @@ static int virtnet_probe(struct virtio_device *vdev)
65706592
vi->device_stats_cap = le64_to_cpu(v);
65716593
}
65726594

6573-
rtnl_unlock();
6574-
6575-
err = virtnet_cpu_notif_add(vi);
6576-
if (err) {
6577-
pr_debug("virtio_net: registering cpu notifier failed\n");
6578-
goto free_unregister_netdev;
6579-
}
6580-
65816595
/* Assume link up if device can't report link status,
65826596
otherwise get link status from config. */
65836597
netif_carrier_off(dev);
65846598
if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
6585-
schedule_work(&vi->config_work);
6599+
virtnet_config_changed_work(&vi->config_work);
65866600
} else {
65876601
vi->status = VIRTIO_NET_S_LINK_UP;
65886602
virtnet_update_settings(vi);
65896603
netif_carrier_on(dev);
65906604
}
65916605

6606+
rtnl_unlock();
6607+
6608+
err = virtnet_cpu_notif_add(vi);
6609+
if (err) {
6610+
pr_debug("virtio_net: registering cpu notifier failed\n");
6611+
goto free_unregister_netdev;
6612+
}
6613+
65926614
for (i = 0; i < ARRAY_SIZE(guest_offloads); i++)
65936615
if (virtio_has_feature(vi->vdev, guest_offloads[i]))
65946616
set_bit(guest_offloads[i], &vi->guest_offloads);

0 commit comments

Comments
 (0)