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; | ... | ... |