NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

kern/47780: if_vioif doesn't work with QEMU >= 1.4.0 due to features negotiation issues



>Number:         47780
>Category:       kern
>Synopsis:       if_vioif doesn't work with QEMU >= 1.4.0 due to features 
>negotiation issues
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Mon Apr 29 06:45:00 +0000 2013
>Originator:     Aurelien Jarno
>Release:        6.0.1
>Organization:
>Environment:
NetBSD netbsd.aurel32.net 6.0.1 NetBSD 6.0.1 (GENERIC) #0: Mon Apr 29 02:07:25 
CEST 2013  
aurel32%netbsd.aurel32.net@localhost:/usr/src/sys/arch/amd64/compile/GENERIC 
amd64
>Description:
NetBSD includes paravirtualized network drivers to run under QEMU/KVM. While 
they work fine with QEMU < 1.4.0, they fail on QEMU >= 1.4.0 due to features 
negotiation issues on the NetBSD side. In vioif_attach() the negotiation is 
working correctly, however the features set is not saved. Later when the device 
is reset calling vioif_stop() and vioif_start(), the features are renogociated, 
using sc->sc_features which has not be initialized and thus equal to 0. This 
causes the host to drop support for some features, while the NetBSD guest later 
tries to use them. This in turn causes protocol issues (in this case NetBSD 
tries to write to the control queue, which has been disabled by the host), and 
causes QEMU to abort.

The attached patch fixes the issue.
>How-To-Repeat:
Run NetBSD under QEMU 1.4.0 with a virtio network interface:

  qemu-system-x86-64 -cdrom NetBSD-6.0.1-i386.iso -net nic,model=virtio -net 
user

And set and IP address on the virtio interface. This will causes QEMU to abort 
as NetBSD is trying to do forbidden things with the virtio network interface.
>Fix:
Index: if_vioif.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/if_vioif.c,v
retrieving revision 1.2
diff -u -r1.2 if_vioif.c
--- if_vioif.c  19 Nov 2011 12:32:54 -0000      1.2
+++ if_vioif.c  29 Apr 2013 06:11:43 -0000
@@ -459,7 +459,6 @@
 {
        struct vioif_softc *sc = device_private(self);
        struct virtio_softc *vsc = device_private(parent);
-       uint32_t features;
        struct ifnet *ifp = &sc->sc_ethercom.ec_if;
 
        if (vsc->sc_child != NULL) {
@@ -478,13 +477,13 @@
        vsc->sc_config_change = 0;
        vsc->sc_intrhand = virtio_vq_intr;
 
-       features = virtio_negotiate_features(vsc,
-                                            (VIRTIO_NET_F_MAC |
-                                             VIRTIO_NET_F_STATUS |
-                                             VIRTIO_NET_F_CTRL_VQ |
-                                             VIRTIO_NET_F_CTRL_RX |
-                                             VIRTIO_F_NOTIFY_ON_EMPTY));
-       if (features & VIRTIO_NET_F_MAC) {
+       sc->sc_features = virtio_negotiate_features(vsc,
+                                                   (VIRTIO_NET_F_MAC |
+                                                    VIRTIO_NET_F_STATUS |
+                                                    VIRTIO_NET_F_CTRL_VQ |
+                                                    VIRTIO_NET_F_CTRL_RX |
+                                                    VIRTIO_F_NOTIFY_ON_EMPTY));
+       if (sc->sc_features & VIRTIO_NET_F_MAC) {
                sc->sc_mac[0] = virtio_read_device_config_1(vsc,
                                                    VIRTIO_NET_CONFIG_MAC+0);
                sc->sc_mac[1] = virtio_read_device_config_1(vsc,
@@ -544,8 +543,8 @@
        sc->sc_vq[1].vq_done = vioif_tx_vq_done;
        virtio_start_vq_intr(vsc, &sc->sc_vq[0]);
        virtio_stop_vq_intr(vsc, &sc->sc_vq[1]); /* not urgent; do it later */
-       if ((features & VIRTIO_NET_F_CTRL_VQ)
-           && (features & VIRTIO_NET_F_CTRL_RX)) {
+       if ((sc->sc_features & VIRTIO_NET_F_CTRL_VQ)
+           && (sc->sc_features & VIRTIO_NET_F_CTRL_RX)) {
                if (virtio_alloc_vq(vsc, &sc->sc_vq[2], 2,
                                    NBPG, 1, "control") == 0) {
                        sc->sc_vq[2].vq_done = vioif_ctrl_vq_done;



Home | Main Index | Thread Index | Old Index