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>
This commit is contained in:
		
							parent
							
								
									c8aa237c64
								
							
						
					
					
						commit
						c27ff60871
					
				
							
								
								
									
										47
									
								
								net.c
									
									
									
									
									
								
							
							
						
						
									
										47
									
								
								net.c
									
									
									
									
									
								
							@ -438,8 +438,8 @@ void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size)
 | 
				
			|||||||
        vlan->delivering = 1;
 | 
					        vlan->delivering = 1;
 | 
				
			||||||
        qemu_deliver_packet(vc, buf, size);
 | 
					        qemu_deliver_packet(vc, buf, size);
 | 
				
			||||||
        while ((packet = vlan->send_queue) != NULL) {
 | 
					        while ((packet = vlan->send_queue) != NULL) {
 | 
				
			||||||
            qemu_deliver_packet(packet->sender, packet->data, packet->size);
 | 
					 | 
				
			||||||
            vlan->send_queue = packet->next;
 | 
					            vlan->send_queue = packet->next;
 | 
				
			||||||
 | 
					            qemu_deliver_packet(packet->sender, packet->data, packet->size);
 | 
				
			||||||
            qemu_free(packet);
 | 
					            qemu_free(packet);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        vlan->delivering = 0;
 | 
					        vlan->delivering = 0;
 | 
				
			||||||
@ -476,32 +476,59 @@ static ssize_t calc_iov_length(const struct iovec *iov, int iovcnt)
 | 
				
			|||||||
    return offset;
 | 
					    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)
 | 
					                          int iovcnt)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    VLANState *vlan = vc1->vlan;
 | 
					    VLANState *vlan = sender->vlan;
 | 
				
			||||||
    VLANClientState *vc;
 | 
					    VLANClientState *vc;
 | 
				
			||||||
 | 
					    VLANPacket *packet;
 | 
				
			||||||
    ssize_t max_len = 0;
 | 
					    ssize_t max_len = 0;
 | 
				
			||||||
 | 
					    int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (vc1->link_down)
 | 
					    if (sender->link_down)
 | 
				
			||||||
        return calc_iov_length(iov, iovcnt);
 | 
					        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) {
 | 
					        for (vc = vlan->first_client; vc != NULL; vc = vc->next) {
 | 
				
			||||||
            ssize_t len = 0;
 | 
					            ssize_t len = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (vc == vc1)
 | 
					            if (vc == sender) {
 | 
				
			||||||
                continue;
 | 
					                continue;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        if (vc->link_down)
 | 
					            if (vc->link_down) {
 | 
				
			||||||
                len = calc_iov_length(iov, iovcnt);
 | 
					                len = calc_iov_length(iov, iovcnt);
 | 
				
			||||||
        else if (vc->fd_readv)
 | 
					            } else if (vc->fd_readv) {
 | 
				
			||||||
                len = vc->fd_readv(vc->opaque, iov, iovcnt);
 | 
					                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);
 | 
					                len = vc_sendv_compat(vc, iov, iovcnt);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            max_len = MAX(max_len, len);
 | 
					            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;
 | 
					    return max_len;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user