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