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,8 +438,8 @@ void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size) | ||
| 438 | vlan->delivering = 1; | 438 | vlan->delivering = 1; |
| 439 | qemu_deliver_packet(vc, buf, size); | 439 | qemu_deliver_packet(vc, buf, size); |
| 440 | while ((packet = vlan->send_queue) != NULL) { | 440 | while ((packet = vlan->send_queue) != NULL) { |
| 441 | - qemu_deliver_packet(packet->sender, packet->data, packet->size); | ||
| 442 | vlan->send_queue = packet->next; | 441 | vlan->send_queue = packet->next; |
| 442 | + qemu_deliver_packet(packet->sender, packet->data, packet->size); | ||
| 443 | qemu_free(packet); | 443 | qemu_free(packet); |
| 444 | } | 444 | } |
| 445 | vlan->delivering = 0; | 445 | vlan->delivering = 0; |
| @@ -476,30 +476,57 @@ static ssize_t calc_iov_length(const struct iovec *iov, int iovcnt) | @@ -476,30 +476,57 @@ static ssize_t calc_iov_length(const struct iovec *iov, int iovcnt) | ||
| 476 | return offset; | 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 | int iovcnt) | 480 | int iovcnt) |
| 481 | { | 481 | { |
| 482 | - VLANState *vlan = vc1->vlan; | 482 | + VLANState *vlan = sender->vlan; |
| 483 | VLANClientState *vc; | 483 | VLANClientState *vc; |
| 484 | + VLANPacket *packet; | ||
| 484 | ssize_t max_len = 0; | 485 | ssize_t max_len = 0; |
| 486 | + int i; | ||
| 485 | 487 | ||
| 486 | - if (vc1->link_down) | 488 | + if (sender->link_down) |
| 487 | return calc_iov_length(iov, iovcnt); | 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 | return max_len; | 532 | return max_len; |