Commit c27ff60871aff588a35e51d1a90faed410993e55
Committed by
Mark McLoughlin
1 parent
c8aa237c
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: Jan Kiszka <jan.kiszka@siemens.com> Signed-off-by: Mark McLoughlin <markmc@redhat.com>
Showing
1 changed file
with
42 additions
and
15 deletions
net.c
... | ... | @@ -438,8 +438,8 @@ void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size) |
438 | 438 | vlan->delivering = 1; |
439 | 439 | qemu_deliver_packet(vc, buf, size); |
440 | 440 | while ((packet = vlan->send_queue) != NULL) { |
441 | - qemu_deliver_packet(packet->sender, packet->data, packet->size); | |
442 | 441 | vlan->send_queue = packet->next; |
442 | + qemu_deliver_packet(packet->sender, packet->data, packet->size); | |
443 | 443 | qemu_free(packet); |
444 | 444 | } |
445 | 445 | vlan->delivering = 0; |
... | ... | @@ -476,30 +476,57 @@ static ssize_t calc_iov_length(const struct iovec *iov, int iovcnt) |
476 | 476 | return offset; |
477 | 477 | } |
478 | 478 | |
479 | -ssize_t qemu_sendv_packet(VLANClientState *vc1, const struct iovec *iov, | |
479 | +ssize_t qemu_sendv_packet(VLANClientState *sender, const struct iovec *iov, | |
480 | 480 | int iovcnt) |
481 | 481 | { |
482 | - VLANState *vlan = vc1->vlan; | |
482 | + VLANState *vlan = sender->vlan; | |
483 | 483 | VLANClientState *vc; |
484 | + VLANPacket *packet; | |
484 | 485 | ssize_t max_len = 0; |
486 | + int i; | |
485 | 487 | |
486 | - if (vc1->link_down) | |
488 | + if (sender->link_down) | |
487 | 489 | return calc_iov_length(iov, iovcnt); |
488 | 490 | |
489 | - for (vc = vlan->first_client; vc != NULL; vc = vc->next) { | |
490 | - ssize_t len = 0; | |
491 | + if (vlan->delivering) { | |
492 | + max_len = calc_iov_length(iov, iovcnt); | |
491 | 493 | |
492 | - if (vc == vc1) | |
493 | - continue; | |
494 | + packet = qemu_malloc(sizeof(VLANPacket) + max_len); | |
495 | + packet->next = vlan->send_queue; | |
496 | + packet->sender = sender; | |
497 | + packet->size = 0; | |
498 | + for (i = 0; i < iovcnt; i++) { | |
499 | + size_t len = iov[i].iov_len; | |
500 | + | |
501 | + memcpy(packet->data + packet->size, iov[i].iov_base, len); | |
502 | + packet->size += len; | |
503 | + } | |
504 | + vlan->send_queue = packet; | |
505 | + } else { | |
506 | + vlan->delivering = 1; | |
507 | + | |
508 | + for (vc = vlan->first_client; vc != NULL; vc = vc->next) { | |
509 | + ssize_t len = 0; | |
494 | 510 | |
495 | - if (vc->link_down) | |
496 | - len = calc_iov_length(iov, iovcnt); | |
497 | - else if (vc->fd_readv) | |
498 | - len = vc->fd_readv(vc->opaque, iov, iovcnt); | |
499 | - else if (vc->fd_read) | |
500 | - len = vc_sendv_compat(vc, iov, iovcnt); | |
511 | + if (vc == sender) { | |
512 | + continue; | |
513 | + } | |
514 | + if (vc->link_down) { | |
515 | + len = calc_iov_length(iov, iovcnt); | |
516 | + } else if (vc->fd_readv) { | |
517 | + len = vc->fd_readv(vc->opaque, iov, iovcnt); | |
518 | + } else if (vc->fd_read) { | |
519 | + len = vc_sendv_compat(vc, iov, iovcnt); | |
520 | + } | |
521 | + max_len = MAX(max_len, len); | |
522 | + } | |
501 | 523 | |
502 | - max_len = MAX(max_len, len); | |
524 | + while ((packet = vlan->send_queue) != NULL) { | |
525 | + vlan->send_queue = packet->next; | |
526 | + qemu_deliver_packet(packet->sender, packet->data, packet->size); | |
527 | + qemu_free(packet); | |
528 | + } | |
529 | + vlan->delivering = 0; | |
503 | 530 | } |
504 | 531 | |
505 | 532 | return max_len; | ... | ... |