Commit c27ff60871aff588a35e51d1a90faed410993e55

Authored by Jan Kiszka
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
@@ -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;