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,22 +403,46 @@ int qemu_can_send_packet(VLANClientState *vc1) | ||
403 | return 0; | 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 | VLANClientState *vc; | 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 | return; | 424 | return; |
413 | 425 | ||
414 | #ifdef DEBUG_NET | 426 | #ifdef DEBUG_NET |
415 | printf("vlan %d send:\n", vlan->id); | 427 | printf("vlan %d send:\n", vlan->id); |
416 | hex_dump(stdout, buf, size); | 428 | hex_dump(stdout, buf, size); |
417 | #endif | 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,11 +29,22 @@ struct VLANClientState { | ||
29 | char info_str[256]; | 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 | struct VLANState { | 41 | struct VLANState { |
33 | int id; | 42 | int id; |
34 | VLANClientState *first_client; | 43 | VLANClientState *first_client; |
35 | struct VLANState *next; | 44 | struct VLANState *next; |
36 | unsigned int nb_guest_devs, nb_host_devs; | 45 | unsigned int nb_guest_devs, nb_host_devs; |
46 | + VLANPacket *send_queue; | ||
47 | + int delivering; | ||
37 | }; | 48 | }; |
38 | 49 | ||
39 | VLANState *qemu_find_vlan(int id); | 50 | VLANState *qemu_find_vlan(int id); |