Commit b1c99fcdf57ae4c3e8da22af13013a3aca69ef5e

Authored by Jan Kiszka
Committed by Anthony Liguori
1 parent ad0d8c4c

slirp: Enable multiple instances

Once again this was a long journey to reach the destination: Allow to
instantiate slirp multiple times. But as in the past, the journey was
worthwhile, cleaning up, fixing and enhancing various parts of the user
space network stack along the way.

What is this particular change good for? Multiple slirps instances
allow separated user space networks for guests with multiple NICs. This
is already possible, but without any slirp support for the second
network, ie. without a chance to talk to that network from the host via
IP. We have a legacy guest system here that benefits from this slirp
enhancement, allowing us to run both of its NICs purely over
unprivileged user space IP stacks.

Another benefit of this patch is that it simply removes an artificial
restriction of the configuration space qemu is providing, avoiding
another source of surprises that users may face when playing with
possible setups.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
... ... @@ -678,6 +678,7 @@ struct slirp_config_str {
678 678 };
679 679  
680 680 typedef struct SlirpState {
  681 + TAILQ_ENTRY(SlirpState) entry;
681 682 VLANClientState *vc;
682 683 Slirp *slirp;
683 684 } SlirpState;
... ... @@ -685,7 +686,8 @@ typedef struct SlirpState {
685 686 static struct slirp_config_str *slirp_configs;
686 687 const char *legacy_tftp_prefix;
687 688 const char *legacy_bootp_filename;
688   -static SlirpState *slirp_state;
  689 +static TAILQ_HEAD(slirp_stacks, SlirpState) slirp_stacks =
  690 + TAILQ_HEAD_INITIALIZER(slirp_stacks);
689 691  
690 692 static void slirp_hostfwd(SlirpState *s, Monitor *mon, const char *redir_str,
691 693 int legacy_format);
... ... @@ -734,7 +736,7 @@ static void net_slirp_cleanup(VLANClientState *vc)
734 736 SlirpState *s = vc->opaque;
735 737  
736 738 slirp_cleanup(s->slirp);
737   - slirp_state = NULL;
  739 + TAILQ_REMOVE(&slirp_stacks, s, entry);
738 740 qemu_free(s);
739 741 }
740 742  
... ... @@ -842,7 +844,7 @@ static int net_slirp_init(Monitor *mon, VLANState *vlan, const char *model,
842 844 s = qemu_mallocz(sizeof(SlirpState));
843 845 s->slirp = slirp_init(restricted, net, mask, host, vhostname,
844 846 tftp_export, bootfile, dhcp, dns, s);
845   - slirp_state = s;
  847 + TAILQ_INSERT_TAIL(&slirp_stacks, s, entry);
846 848  
847 849 while (slirp_configs) {
848 850 struct slirp_config_str *config = slirp_configs;
... ... @@ -881,7 +883,7 @@ void net_slirp_hostfwd_remove(Monitor *mon, const char *src_str)
881 883 int is_udp = 0;
882 884 int err;
883 885  
884   - if (!slirp_state) {
  886 + if (TAILQ_EMPTY(&slirp_stacks)) {
885 887 monitor_printf(mon, "user mode network stack not in use\n");
886 888 return;
887 889 }
... ... @@ -908,7 +910,7 @@ void net_slirp_hostfwd_remove(Monitor *mon, const char *src_str)
908 910  
909 911 host_port = atoi(p);
910 912  
911   - err = slirp_remove_hostfwd(slirp_state->slirp, is_udp,
  913 + err = slirp_remove_hostfwd(TAILQ_FIRST(&slirp_stacks)->slirp, is_udp,
912 914 host_addr, host_port);
913 915  
914 916 monitor_printf(mon, "host forwarding rule for %s %s\n", src_str,
... ... @@ -984,19 +986,19 @@ static void slirp_hostfwd(SlirpState *s, Monitor *mon, const char *redir_str,
984 986  
985 987 void net_slirp_hostfwd_add(Monitor *mon, const char *redir_str)
986 988 {
987   - if (!slirp_state) {
  989 + if (TAILQ_EMPTY(&slirp_stacks)) {
988 990 monitor_printf(mon, "user mode network stack not in use\n");
989 991 return;
990 992 }
991 993  
992   - slirp_hostfwd(slirp_state, mon, redir_str, 0);
  994 + slirp_hostfwd(TAILQ_FIRST(&slirp_stacks), mon, redir_str, 0);
993 995 }
994 996  
995 997 void net_slirp_redir(const char *redir_str)
996 998 {
997 999 struct slirp_config_str *config;
998 1000  
999   - if (!slirp_state) {
  1001 + if (TAILQ_EMPTY(&slirp_stacks)) {
1000 1002 config = qemu_malloc(sizeof(*config));
1001 1003 pstrcpy(config->str, sizeof(config->str), redir_str);
1002 1004 config->flags = SLIRP_CFG_HOSTFWD | SLIRP_CFG_LEGACY;
... ... @@ -1005,7 +1007,7 @@ void net_slirp_redir(const char *redir_str)
1005 1007 return;
1006 1008 }
1007 1009  
1008   - slirp_hostfwd(slirp_state, NULL, redir_str, 1);
  1010 + slirp_hostfwd(TAILQ_FIRST(&slirp_stacks), NULL, redir_str, 1);
1009 1011 }
1010 1012  
1011 1013 #ifndef _WIN32
... ... @@ -1106,8 +1108,8 @@ void net_slirp_smb(const char *exported_dir)
1106 1108 exit(1);
1107 1109 }
1108 1110 legacy_smb_export = exported_dir;
1109   - if (slirp_state) {
1110   - slirp_smb(slirp_state, exported_dir, vserver_addr);
  1111 + if (!TAILQ_EMPTY(&slirp_stacks)) {
  1112 + slirp_smb(TAILQ_FIRST(&slirp_stacks), exported_dir, vserver_addr);
1111 1113 }
1112 1114 }
1113 1115  
... ... @@ -1198,13 +1200,12 @@ static void slirp_guestfwd(SlirpState *s, Monitor *mon, const char *config_str,
1198 1200  
1199 1201 void do_info_usernet(Monitor *mon)
1200 1202 {
1201   - SlirpState *s = slirp_state;
  1203 + SlirpState *s;
1202 1204  
1203   - if (!s) {
1204   - return;
  1205 + TAILQ_FOREACH(s, &slirp_stacks, entry) {
  1206 + monitor_printf(mon, "VLAN %d (%s):\n", s->vc->vlan->id, s->vc->name);
  1207 + slirp_connection_info(s->slirp, mon);
1205 1208 }
1206   - monitor_printf(mon, "VLAN %d (%s):\n", s->vc->vlan->id, s->vc->name);
1207   - slirp_connection_info(s->slirp, mon);
1208 1209 }
1209 1210  
1210 1211 #endif /* CONFIG_SLIRP */
... ... @@ -2515,7 +2516,7 @@ int net_client_init(Monitor *mon, const char *device, const char *p)
2515 2516 qemu_free(smb_export);
2516 2517 qemu_free(vsmbsrv);
2517 2518 } else if (!strcmp(device, "channel")) {
2518   - if (!slirp_state) {
  2519 + if (TAILQ_EMPTY(&slirp_stacks)) {
2519 2520 struct slirp_config_str *config;
2520 2521  
2521 2522 config = qemu_malloc(sizeof(*config));
... ... @@ -2524,7 +2525,7 @@ int net_client_init(Monitor *mon, const char *device, const char *p)
2524 2525 config->next = slirp_configs;
2525 2526 slirp_configs = config;
2526 2527 } else {
2527   - slirp_guestfwd(slirp_state, mon, p, 1);
  2528 + slirp_guestfwd(TAILQ_FIRST(&slirp_stacks), mon, p, 1);
2528 2529 }
2529 2530 ret = 0;
2530 2531 } else
... ...
slirp/slirp.c
... ... @@ -47,7 +47,8 @@ u_int curtime;
47 47 static u_int time_fasttimo, last_slowtimo;
48 48 static int do_slowtimo;
49 49  
50   -Slirp *slirp_instance;
  50 +TAILQ_HEAD(slirp_instances, Slirp) slirp_instances =
  51 + TAILQ_HEAD_INITIALIZER(slirp_instances);
51 52  
52 53 #ifdef _WIN32
53 54  
... ... @@ -223,20 +224,20 @@ Slirp *slirp_init(int restricted, struct in_addr vnetwork,
223 224  
224 225 register_savevm("slirp", 0, 2, slirp_state_save, slirp_state_load, slirp);
225 226  
226   - slirp_instance = slirp;
  227 + TAILQ_INSERT_TAIL(&slirp_instances, slirp, entry);
227 228  
228 229 return slirp;
229 230 }
230 231  
231 232 void slirp_cleanup(Slirp *slirp)
232 233 {
  234 + TAILQ_REMOVE(&slirp_instances, slirp, entry);
  235 +
233 236 unregister_savevm("slirp", slirp);
234 237  
235 238 qemu_free(slirp->tftp_prefix);
236 239 qemu_free(slirp->bootp_filename);
237 240 qemu_free(slirp);
238   -
239   - slirp_instance = NULL;
240 241 }
241 242  
242 243 #define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
... ... @@ -269,11 +270,11 @@ static void updtime(void)
269 270 void slirp_select_fill(int *pnfds,
270 271 fd_set *readfds, fd_set *writefds, fd_set *xfds)
271 272 {
272   - Slirp *slirp = slirp_instance;
  273 + Slirp *slirp;
273 274 struct socket *so, *so_next;
274 275 int nfds;
275 276  
276   - if (!slirp_instance) {
  277 + if (TAILQ_EMPTY(&slirp_instances)) {
277 278 return;
278 279 }
279 280  
... ... @@ -288,11 +289,12 @@ void slirp_select_fill(int *pnfds,
288 289 */
289 290 do_slowtimo = 0;
290 291  
  292 + TAILQ_FOREACH(slirp, &slirp_instances, entry) {
291 293 /*
292 294 * *_slowtimo needs calling if there are IP fragments
293 295 * in the fragment queue, or there are TCP connections active
294 296 */
295   - do_slowtimo = ((slirp->tcb.so_next != &slirp->tcb) ||
  297 + do_slowtimo |= ((slirp->tcb.so_next != &slirp->tcb) ||
296 298 (&slirp->ipq.ip_link != slirp->ipq.ip_link.next));
297 299  
298 300 for (so = slirp->tcb.so_next; so != &slirp->tcb;
... ... @@ -383,6 +385,7 @@ void slirp_select_fill(int *pnfds,
383 385 UPD_NFDS(so->s);
384 386 }
385 387 }
  388 + }
386 389  
387 390 *pnfds = nfds;
388 391 }
... ... @@ -390,11 +393,11 @@ void slirp_select_fill(int *pnfds,
390 393 void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds,
391 394 int select_error)
392 395 {
393   - Slirp *slirp = slirp_instance;
  396 + Slirp *slirp;
394 397 struct socket *so, *so_next;
395 398 int ret;
396 399  
397   - if (!slirp_instance) {
  400 + if (TAILQ_EMPTY(&slirp_instances)) {
398 401 return;
399 402 }
400 403  
... ... @@ -405,6 +408,7 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds,
405 408 /* Update time */
406 409 updtime();
407 410  
  411 + TAILQ_FOREACH(slirp, &slirp_instances, entry) {
408 412 /*
409 413 * See if anything has timed out
410 414 */
... ... @@ -559,6 +563,7 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds,
559 563 if (slirp->if_queued) {
560 564 if_start(slirp);
561 565 }
  566 + }
562 567  
563 568 /* clear global file descriptor sets.
564 569 * these reside on the stack in vl.c
... ...
slirp/slirp.h
... ... @@ -185,6 +185,8 @@ int inet_aton _P((const char *cp, struct in_addr *ia));
185 185  
186 186 #include "debug.h"
187 187  
  188 +#include "sys-queue.h"
  189 +
188 190 #include "libslirp.h"
189 191 #include "ip.h"
190 192 #include "tcp.h"
... ... @@ -207,6 +209,8 @@ int inet_aton _P((const char *cp, struct in_addr *ia));
207 209 #include "tftp.h"
208 210  
209 211 struct Slirp {
  212 + TAILQ_ENTRY(Slirp) entry;
  213 +
210 214 /* virtual network configuration */
211 215 struct in_addr vnetwork_addr;
212 216 struct in_addr vnetwork_mask;
... ...