Commit 764a4d1deb9304918f3b09b5da6f63fa3a6b4d86
1 parent
a66b11bf
net: Untangle nested qemu_send_packet (Jan Kiszka)
Queue packets that are send during an ongoing packet delivery. This ensures that packets will always arrive in their logical order at each client of a VLAN. Currently, slirp generates such immediate relies, and e.g. packet-sniffing clients on the same VLAN may get confused. Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@7203 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
41 additions
and
6 deletions
net.c
| ... | ... | @@ -403,22 +403,46 @@ int qemu_can_send_packet(VLANClientState *vc1) |
| 403 | 403 | return 0; |
| 404 | 404 | } |
| 405 | 405 | |
| 406 | -void qemu_send_packet(VLANClientState *vc1, const uint8_t *buf, int size) | |
| 406 | +static void | |
| 407 | +qemu_deliver_packet(VLANClientState *sender, const uint8_t *buf, int size) | |
| 407 | 408 | { |
| 408 | - VLANState *vlan = vc1->vlan; | |
| 409 | 409 | VLANClientState *vc; |
| 410 | 410 | |
| 411 | - if (vc1->link_down) | |
| 411 | + for (vc = sender->vlan->first_client; vc != NULL; vc = vc->next) { | |
| 412 | + if (vc != sender && !vc->link_down) { | |
| 413 | + vc->fd_read(vc->opaque, buf, size); | |
| 414 | + } | |
| 415 | + } | |
| 416 | +} | |
| 417 | + | |
| 418 | +void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size) | |
| 419 | +{ | |
| 420 | + VLANState *vlan = vc->vlan; | |
| 421 | + VLANPacket *packet; | |
| 422 | + | |
| 423 | + if (vc->link_down) | |
| 412 | 424 | return; |
| 413 | 425 | |
| 414 | 426 | #ifdef DEBUG_NET |
| 415 | 427 | printf("vlan %d send:\n", vlan->id); |
| 416 | 428 | hex_dump(stdout, buf, size); |
| 417 | 429 | #endif |
| 418 | - for(vc = vlan->first_client; vc != NULL; vc = vc->next) { | |
| 419 | - if (vc != vc1 && !vc->link_down) { | |
| 420 | - vc->fd_read(vc->opaque, buf, size); | |
| 430 | + if (vlan->delivering) { | |
| 431 | + packet = qemu_malloc(sizeof(VLANPacket) + size); | |
| 432 | + packet->next = vlan->send_queue; | |
| 433 | + packet->sender = vc; | |
| 434 | + packet->size = size; | |
| 435 | + memcpy(packet->data, buf, size); | |
| 436 | + vlan->send_queue = packet; | |
| 437 | + } else { | |
| 438 | + vlan->delivering = 1; | |
| 439 | + qemu_deliver_packet(vc, buf, size); | |
| 440 | + while ((packet = vlan->send_queue) != NULL) { | |
| 441 | + qemu_deliver_packet(packet->sender, packet->data, packet->size); | |
| 442 | + vlan->send_queue = packet->next; | |
| 443 | + qemu_free(packet); | |
| 421 | 444 | } |
| 445 | + vlan->delivering = 0; | |
| 422 | 446 | } |
| 423 | 447 | } |
| 424 | 448 | ... | ... |
net.h
| ... | ... | @@ -29,11 +29,22 @@ struct VLANClientState { |
| 29 | 29 | char info_str[256]; |
| 30 | 30 | }; |
| 31 | 31 | |
| 32 | +typedef struct VLANPacket VLANPacket; | |
| 33 | + | |
| 34 | +struct VLANPacket { | |
| 35 | + struct VLANPacket *next; | |
| 36 | + VLANClientState *sender; | |
| 37 | + int size; | |
| 38 | + uint8_t data[0]; | |
| 39 | +}; | |
| 40 | + | |
| 32 | 41 | struct VLANState { |
| 33 | 42 | int id; |
| 34 | 43 | VLANClientState *first_client; |
| 35 | 44 | struct VLANState *next; |
| 36 | 45 | unsigned int nb_guest_devs, nb_host_devs; |
| 46 | + VLANPacket *send_queue; | |
| 47 | + int delivering; | |
| 37 | 48 | }; |
| 38 | 49 | |
| 39 | 50 | VLANState *qemu_find_vlan(int id); | ... | ... |