Commit c27ff608 authored by Jan Kiszka's avatar Jan Kiszka Committed by Mark McLoughlin
Browse files

net: Fix and improved ordered packet delivery



Fix a race in qemu_send_packet when delivering deferred packets and
add proper deferring also to qemu_sendv_packet.

Signed-off-by: default avatarJan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: default avatarMark McLoughlin <markmc@redhat.com>
parent c8aa237c
Loading
Loading
Loading
Loading
+42 −15
Original line number Diff line number Diff line
@@ -438,8 +438,8 @@ void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size)
        vlan->delivering = 1;
        qemu_deliver_packet(vc, buf, size);
        while ((packet = vlan->send_queue) != NULL) {
            qemu_deliver_packet(packet->sender, packet->data, packet->size);
            vlan->send_queue = packet->next;
            qemu_deliver_packet(packet->sender, packet->data, packet->size);
            qemu_free(packet);
        }
        vlan->delivering = 0;
@@ -476,32 +476,59 @@ static ssize_t calc_iov_length(const struct iovec *iov, int iovcnt)
    return offset;
}

ssize_t qemu_sendv_packet(VLANClientState *vc1, const struct iovec *iov,
ssize_t qemu_sendv_packet(VLANClientState *sender, const struct iovec *iov,
                          int iovcnt)
{
    VLANState *vlan = vc1->vlan;
    VLANState *vlan = sender->vlan;
    VLANClientState *vc;
    VLANPacket *packet;
    ssize_t max_len = 0;
    int i;

    if (vc1->link_down)
    if (sender->link_down)
        return calc_iov_length(iov, iovcnt);

    if (vlan->delivering) {
        max_len = calc_iov_length(iov, iovcnt);

        packet = qemu_malloc(sizeof(VLANPacket) + max_len);
        packet->next = vlan->send_queue;
        packet->sender = sender;
        packet->size = 0;
        for (i = 0; i < iovcnt; i++) {
            size_t len = iov[i].iov_len;

            memcpy(packet->data + packet->size, iov[i].iov_base, len);
            packet->size += len;
        }
        vlan->send_queue = packet;
    } else {
        vlan->delivering = 1;

        for (vc = vlan->first_client; vc != NULL; vc = vc->next) {
            ssize_t len = 0;

        if (vc == vc1)
            if (vc == sender) {
                continue;

        if (vc->link_down)
            }
            if (vc->link_down) {
                len = calc_iov_length(iov, iovcnt);
        else if (vc->fd_readv)
            } else if (vc->fd_readv) {
                len = vc->fd_readv(vc->opaque, iov, iovcnt);
        else if (vc->fd_read)
            } else if (vc->fd_read) {
                len = vc_sendv_compat(vc, iov, iovcnt);

            }
            max_len = MAX(max_len, len);
        }

        while ((packet = vlan->send_queue) != NULL) {
            vlan->send_queue = packet->next;
            qemu_deliver_packet(packet->sender, packet->data, packet->size);
            qemu_free(packet);
        }
        vlan->delivering = 0;
    }

    return max_len;
}