1 /* Copyright 2003 Renzo Davoli
2 * TNX: 2005.11.18 new syntax mgmt patch by Iain McFarlane <imcfarla@tiscali.co.uk>
3 * Licensed under the GPL
15 #include <sys/ioctl.h>
16 #include <sys/socket.h>
19 #include <sys/types.h>
25 #include <vdecommon.h>
27 #include <libvdeplug.h>
29 #define SWITCH_MAGIC 0xfeedface
34 int exit_value
= 256; /* out of range for exit status possible values */
38 unsigned char bufin
[BUFSIZE
];
46 static int countnics(const char *s
)
56 static int countnewnics(int argc
,char *argv
[])
59 register int netflag
=0;
61 if (strcmp(argv
[0],"-net")==0)
64 if (netflag
&& (strncmp(argv
[0],"vde",3)==0))
74 static int isdaemonize(int argc
,char *argv
[])
76 register int daemonize
=0;
77 if(strcmp(filename
,"qemu")==0){
80 if (strcmp(argv
[0],"-daemonize")==0)
82 if ((strcmp(argv
[0],"-vnc")==0) || (strcmp(argv
[0],"-nographic")==0))
87 if(daemonize
&& !daemonadds
) daemonize
= 0;
90 while (argc
> 0 && !daemonize
) {
91 if (strcmp(argv
[0],"-daemonize")==0)
103 static void usage(void)
105 if (strcmp(vdeqname
,"vdeq") != 0 && strncmp(vdeqname
,"vde",3)==0) {
106 fprintf(stderr
,"Usage: %s [-h]\n"
107 "\t %s ...qemu options... -net vde[,vlan=n][,sock=sock] ... \n"
109 "\t %s [-sock sock1 [,sock2...]] qemu_options\n"
110 "\t (%s executes a qemu machine named %s, \n\t output of \"%s -h\" follows)\n\n", vdeqname
,vdeqname
,vdeqname
,vdeqname
,filename
,filename
);
111 execlp(filename
,filename
,"-h",(char *) 0);
113 fprintf(stderr
,"Usage: %s [-h]\n"
114 "\t %s qemu_executable ...qemu options... -net vde[,vlan=n][,sock=sock] ... \n"
116 "\t %s qemu_executable [-sock sock1 [,sock2...]] qemu_options\n", vdeqname
,vdeqname
, vdeqname
);
121 static void cleanup()
124 for (i
=0; i
<nb_nics
; i
++) {
130 static void sig_handler(int sig
)
132 fprintf(stderr
,"%s: Caught signal %d, cleaning up and exiting\n", vdeqname
, sig
);
134 signal(sig
, SIG_DFL
);
141 static void setsighandlers()
143 /* setting signal handlers.
144 * sets clean termination for SIGHUP, SIGINT and SIGTERM, and simply
145 * ignores all the others signals which could cause termination. */
146 struct { int sig
; const char *name
; int ignore
; } signals
[] = {
147 { SIGHUP
, "SIGHUP", 0 },
148 { SIGINT
, "SIGINT", 0 },
149 { SIGPIPE
, "SIGPIPE", 1 },
150 { SIGALRM
, "SIGALRM", 1 },
151 { SIGTERM
, "SIGTERM", 0 },
152 { SIGUSR1
, "SIGUSR1", 1 },
153 { SIGUSR2
, "SIGUSR2", 1 },
154 { SIGPROF
, "SIGPROF", 1 },
155 { SIGVTALRM
, "SIGVTALRM", 1 },
157 { SIGPOLL
, "SIGPOLL", 1 },
159 { SIGSTKFLT
, "SIGSTKFLT", 1 },
161 { SIGIO
, "SIGIO", 1 },
162 { SIGPWR
, "SIGPWR", 1 },
164 { SIGUNUSED
, "SIGUNUSED", 1 },
168 { SIGXCPU
, "SIGXCPU", 1 },
169 { SIGXFSZ
, "SIGXFSZ", 1 },
175 for(i
= 0; signals
[i
].sig
!= 0; i
++)
176 if(signal(signals
[i
].sig
,
177 signals
[i
].ignore
? SIG_IGN
: sig_handler
) < 0)
178 fprintf(stderr
,"Setting handler for %s: %s\n", signals
[i
].name
,
182 static void sigchld_handler(int sig
)
187 exit_value
=WEXITSTATUS(ev
);
192 static int checkver(char *prog
)
206 if ((f
=fork()) > 0) {
209 len
=read(fd
[0],buf
,256);
212 for(i
=0;i
<len
&& version
==0;i
++) {
213 if(strncmp(buf
+i
,"version ",8)==0) {
215 sscanf(buf
+i
+8,"%d.%d.%d",&v1
,&v2
,&v3
);
216 version
=(v1
<< 16) + (v2
<< 8) + v3
;
221 waitpid(f
,&status
,0);
228 if (execvp(prog
,newargv
) < 0) {
235 static char *parsevdearg(char *arg
,char **sock
,int *pport
, int fd
)
241 printf("arg %s\n", arg
);
243 while (*arg
==',') arg
++;
244 if (strncmp(arg
,"vlan=",5)==0) {
246 while (*arg
!= 0 && *arg
!= ',')
249 else if (strncmp(arg
,"sock=",5)==0) {
254 while (*arg
!= 0 && *arg
!= '\"')
258 while (*arg
!= 0 && *arg
!= ',')
265 else if (strncmp(arg
,"port=",5)==0) {
267 while (*arg
!= 0 && *arg
!= ',')
271 printf("WARNING: unknown parameter in argument %s\n", arg
);
276 snprintf(newarg
,128,"tap,vlan=%d,fd=%d%s%s",vlan
,fd
,(*arg
== 0)?"":",",arg
);
277 return strdup(newarg
);
280 int main(int argc
, char **argv
)
282 char *argsock
=NULL
,**sockname
;
296 vdeqname
=basename(argv
[0]);
299 "NOTE: %s is now DEPRECATED -- both QEMU and KVM have native support for\n"
300 " VDE. This binary will be removed soon from the distribution, consider\n"
301 " stopping using it.\n\n", vdeqname
);
303 //callerpwd=getpwuid(getuid());
304 /* OLD SYNTAX MGMT */
305 if (strncmp(vdeqname
,"vdeo",4) == 0) {
307 if (strcmp(vdeqname
,"vdeoq") != 0) {
311 else if (strcmp(vdeqname
,"vdeq") != 0 && strncmp(vdeqname
,"vde",3)==0) {
321 daemonize
=isdaemonize(argc
-1,argv
+1);
322 if ((ver
=checkver(filename
)) < 0x800)
325 nb_nics
=countnewnics(argc
-1,argv
+1);
330 strcmp(argv
[1],"-h")==0 ||
331 strcmp(argv
[1],"-help")==0 ||
332 strcmp(argv
[1],"--help")==0
334 strcmp(filename
,"-h")==0 ||
335 strcmp(filename
,"-help")==0 ||
336 strcmp(filename
,"--help")==0
339 } else if (argc
> 2 && (
340 (strcmp(argv
[1],"-vdesock")==0) ||
341 (strcmp(argv
[1],"-sock")==0) ||
342 (strcmp(argv
[1],"-unix")==0))
350 if (argc
> 2 && ((strcmp(argv
[1],"--mod")==0))
352 sscanf(argv
[2],"%o",(unsigned int *)&mode
);
361 nb_nics
=countnics(argsock
);
362 if (!oldsyntax
&& nb_nics
> 1)
364 "Warning: all the vde connections will be connected to one net interface\n"
365 " to configure several interface use the new syntax -net vde\n");
368 if ((sp
= (pair
*) malloc(nb_nics
* 2 * sizeof (int)))<0) {
369 perror("malloc nics");
373 if ((conn
=(VDECONN
**) calloc (nb_nics
,sizeof(VDECONN
*))) <0) {
374 perror("calloc conn");
378 for (i
=0; i
<nb_nics
; i
++) {
379 if (socketpair(AF_UNIX
, SOCK_DGRAM
, 0, sp
[i
]) < 0){
380 perror("socketpair");
385 if ((sockname
= (char **) malloc(sizeof(char *) * nb_nics
))<0) {
386 perror("malloc sockname");
389 if ((ports
= (int *) calloc(nb_nics
, sizeof(int)))<0) {
390 perror("malloc ports");
400 for (i
=1,netflag
=0,vdeint
=0;i
<argc
;i
++) {
401 if (strcmp(argv
[i
],"-net")==0)
404 if (netflag
&& strncmp(argv
[i
],"vde",3) == 0)
406 argv
[i
]=parsevdearg(argv
[i
]+3,&sockname
[vdeint
],&ports
[vdeint
],sp
[vdeint
][0]);
418 register char *s
=argsock
;
423 while (*s
!= ',' && *s
!= '\0')
428 } while (oldch
!= 0);
431 /* printf("-- %s --\n",numfd);
432 printf("as %s\n",argsock);
433 for (i=0; i<nb_nics; i++)
434 printf("%d -> %s\n",i,sockname[i]); */
435 newargc
=argc
+2+(2*nb_nics
);
436 if ((newargv
=(char **) malloc ((newargc
+1)* sizeof(char *))) <0) {
443 for (i
=0; i
<nb_nics
; i
++) {
445 sprintf(numfd
,"%d",sp
[i
][0]);
446 newargv
[2*i
+1]="-tun-fd";
447 newargv
[2*i
+2]=strdup(numfd
);
451 sprintf(nnics
,"%d",nb_nics
);
452 newargv
[2*nb_nics
+1]="-nics";
453 newargv
[2*nb_nics
+2]=strdup(nnics
);
456 for (i
=0; i
<nb_nics
; i
++) {
458 sprintf(numfd
,"tap,vlan=0,fd=%d",sp
[i
][0]);
459 newargv
[2*i
+1]="-net";
460 newargv
[2*i
+2]=strdup(numfd
);
462 newargv
[2*nb_nics
+1]="-net";
463 newargv
[2*nb_nics
+2]="nic";
465 for (i
=(2*nb_nics
)+3,j
=1;j
<argc
;i
++,j
++) newargv
[i
]=argv
[j
];
470 if ((pollv
= (struct pollfd
*) malloc(sizeof(struct pollfd
) * 2 * nb_nics
))<0) {
471 perror("malloc pollfd");
475 for (i
=0; i
<nb_nics
; i
++) {
476 struct vde_open_args vdearg
={ports
[i
],NULL
,mode
};
477 conn
[i
]=vde_open(sockname
[i
],"vdeqemu",&vdearg
);
478 pollv
[2*i
+1].fd
=vde_datafd(conn
[i
]);
479 pollv
[2*i
].fd
=sp
[i
][1];
480 pollv
[2*i
].events
= pollv
[2*i
+1].events
=POLLIN
|POLLHUP
;
487 printf("%s ", newargv
[i
++]);
494 signal(SIGCHLD
, sigchld_handler
);
495 for (i
=0; i
<nb_nics
; i
++)
500 if ((result
=poll(pollv
,2*nb_nics
,-1)) < 0) {
501 if (errno
!= EINTR
) {
506 if ((exit_value
< 256) || !daemonize
)
513 for (i
=0; i
<nb_nics
; i
++) {
514 if (pollv
[2*i
].revents
& POLLHUP
|| pollv
[2*i
+1].revents
& POLLHUP
)
516 if (pollv
[2*i
].revents
& POLLIN
) {
517 if ((nx
=read(sp
[i
][1],bufin
,sizeof(bufin
))) <= 0) {
523 //fprintf(stderr,"RX from qemu %d\n",nx);
524 if (vde_send(conn
[i
],bufin
,nx
,0) < 0) {
530 if (pollv
[2*i
+1].revents
& POLLIN
) {
531 if ((nx
=vde_recv(conn
[i
],bufin
,BUFSIZE
,0)) < 0) {
536 //fprintf(stderr,"TX to qemu %d\n",nx);
537 if (write(sp
[i
][1],bufin
,nx
) < 0) {
538 if (errno
!= ECONNREFUSED
)
541 exit(errno
!= ECONNREFUSED
);
548 for (i
=0; i
<nb_nics
; i
++) {
550 close(vde_datafd(conn
[i
]));
551 close(vde_ctlfd(conn
[i
]));
553 execvp(filename
,newargv
);
559 /* vim: set ts=2 sts=2 sw=2: */