Skip to content

Commit df28de7

Browse files
jasowangkuba-moo
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]>
1 parent 224de6f commit df28de7

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
@@ -2885,6 +2885,25 @@ static void virtnet_cancel_dim(struct virtnet_info *vi, struct dim *dim)
28852885
net_dim_work_cancel(dim);
28862886
}
28872887

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

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

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

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

3426+
netif_carrier_off(dev);
3427+
33903428
return 0;
33913429
}
33923430

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

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

6546+
/* Disable config change notification until ndo_open. */
6547+
virtio_config_driver_disable(vi->vdev);
6548+
65276549
virtio_device_ready(vdev);
65286550

65296551
virtnet_set_queues(vi, vi->curr_queue_pairs);
@@ -6573,25 +6595,25 @@ static int virtnet_probe(struct virtio_device *vdev)
65736595
vi->device_stats_cap = le64_to_cpu(v);
65746596
}
65756597

6576-
rtnl_unlock();
6577-
6578-
err = virtnet_cpu_notif_add(vi);
6579-
if (err) {
6580-
pr_debug("virtio_net: registering cpu notifier failed\n");
6581-
goto free_unregister_netdev;
6582-
}
6583-
65846598
/* Assume link up if device can't report link status,
65856599
otherwise get link status from config. */
65866600
netif_carrier_off(dev);
65876601
if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
6588-
schedule_work(&vi->config_work);
6602+
virtnet_config_changed_work(&vi->config_work);
65896603
} else {
65906604
vi->status = VIRTIO_NET_S_LINK_UP;
65916605
virtnet_update_settings(vi);
65926606
netif_carrier_on(dev);
65936607
}
65946608

6609+
rtnl_unlock();
6610+
6611+
err = virtnet_cpu_notif_add(vi);
6612+
if (err) {
6613+
pr_debug("virtio_net: registering cpu notifier failed\n");
6614+
goto free_unregister_netdev;
6615+
}
6616+
65956617
for (i = 0; i < ARRAY_SIZE(guest_offloads); i++)
65966618
if (virtio_has_feature(vi->vdev, guest_offloads[i]))
65976619
set_bit(guest_offloads[i], &vi->guest_offloads);

0 commit comments

Comments
 (0)