loadlwipv6 inlined
[vde.git] / vde-2 / src / vdeq.c
blobdc5f105fe6c16eeb1d957f165e139cda6d1183cf
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
4 */
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <signal.h>
9 #include <errno.h>
10 #include <unistd.h>
11 #include <string.h>
12 #include <stdint.h>
13 #include <libgen.h>
14 #include <signal.h>
15 #include <sys/ioctl.h>
16 #include <sys/socket.h>
17 #include <sys/un.h>
18 #include <sys/uio.h>
19 #include <sys/types.h>
20 #include <sys/wait.h>
21 #include <pwd.h>
23 #include <config.h>
24 #include <vde.h>
25 #include <vdecommon.h>
27 #include <libvdeplug.h>
29 #define SWITCH_MAGIC 0xfeedface
30 #define BUFSIZE 2048
31 #define ETH_ALEN 6
32 #define MAXDESCR 128
34 int exit_value = 256; /* out of range for exit status possible values */
35 static int nb_nics;
36 VDECONN **conn;
38 unsigned char bufin[BUFSIZE];
40 struct pollfd *pollv;
42 char *filename;
43 char *vdeqname;
44 #define NUMW 10
46 static int countnics(const char *s)
48 register int nics=1;
49 while (*s) {
50 if (*s==',') nics++;
51 s++;
53 return nics;
56 static int countnewnics(int argc,char *argv[])
58 register int nics=0;
59 register int netflag=0;
60 while (argc > 0) {
61 if (strcmp(argv[0],"-net")==0)
62 netflag=1;
63 else {
64 if (netflag && (strncmp(argv[0],"vde",3)==0))
65 nics++;
66 netflag=0;
68 argv++;
69 argc--;
71 return nics;
74 static int isdaemonize(int argc,char *argv[])
76 register int daemonize=0;
77 if(strcmp(filename,"qemu")==0){
78 int daemonadds=0;
79 while (argc > 0) {
80 if (strcmp(argv[0],"-daemonize")==0)
81 daemonize=1;
82 if ((strcmp(argv[0],"-vnc")==0) || (strcmp(argv[0],"-nographic")==0))
83 daemonadds=1;
84 argv++;
85 argc--;
87 if(daemonize && !daemonadds) daemonize = 0;
89 else {
90 while (argc > 0 && !daemonize) {
91 if (strcmp(argv[0],"-daemonize")==0)
92 daemonize=1;
93 else {
94 argv++;
95 argc--;
99 return daemonize;
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"
108 "Old syntax:\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);
112 } else {
113 fprintf(stderr,"Usage: %s [-h]\n"
114 "\t %s qemu_executable ...qemu options... -net vde[,vlan=n][,sock=sock] ... \n"
115 "Old syntax:\n"
116 "\t %s qemu_executable [-sock sock1 [,sock2...]] qemu_options\n", vdeqname,vdeqname, vdeqname);
117 exit(0);
121 static void cleanup()
123 register int i;
124 for (i=0; i<nb_nics; i++) {
125 if (conn[i] != NULL)
126 vde_close(conn[i]);
130 static void sig_handler(int sig)
132 fprintf(stderr,"%s: Caught signal %d, cleaning up and exiting\n", vdeqname, sig);
133 cleanup();
134 signal(sig, SIG_DFL);
135 kill(getpid(), sig);
138 static void setsighandlers()
140 /* setting signal handlers.
141 * sets clean termination for SIGHUP, SIGINT and SIGTERM, and simply
142 * ignores all the others signals which could cause termination. */
143 struct { int sig; const char *name; int ignore; } signals[] = {
144 { SIGHUP, "SIGHUP", 0 },
145 { SIGINT, "SIGINT", 0 },
146 { SIGPIPE, "SIGPIPE", 1 },
147 { SIGALRM, "SIGALRM", 1 },
148 { SIGTERM, "SIGTERM", 0 },
149 { SIGUSR1, "SIGUSR1", 1 },
150 { SIGUSR2, "SIGUSR2", 1 },
151 { SIGPROF, "SIGPROF", 1 },
152 { SIGVTALRM, "SIGVTALRM", 1 },
153 #ifdef VDE_LINUX
154 { SIGPOLL, "SIGPOLL", 1 },
155 #ifdef SIGSTKFLT
156 { SIGSTKFLT, "SIGSTKFLT", 1 },
157 #endif
158 { SIGIO, "SIGIO", 1 },
159 { SIGPWR, "SIGPWR", 1 },
160 #ifdef SIGUNUSED
161 { SIGUNUSED, "SIGUNUSED", 1 },
162 #endif
163 #endif
164 #ifdef VDE_DARWIN
165 { SIGXCPU, "SIGXCPU", 1 },
166 { SIGXFSZ, "SIGXFSZ", 1 },
167 #endif
168 { 0, NULL, 0 }
171 int i;
172 for(i = 0; signals[i].sig != 0; i++)
173 if(signal(signals[i].sig,
174 signals[i].ignore ? SIG_IGN : sig_handler) < 0)
175 fprintf(stderr,"Setting handler for %s: %s\n", signals[i].name,
176 strerror(errno));
179 static void sigchld_handler(int sig)
181 int ev;
182 wait(&ev);
183 if (WIFEXITED(ev))
184 exit_value=WEXITSTATUS(ev);
185 else
186 exit_value=255;
189 static int checkver(char *prog)
191 char *newargv[3];
192 int fd[2];
193 int f,len,version=0;
194 char buf[257];
195 newargv[0]=prog;
196 newargv[1]="-h";
197 newargv[2]=0;
198 buf[256]=0;
199 if (pipe(fd) < 0) {
200 perror("pipe");
201 exit(1);
203 if ((f=fork()) > 0) {
204 int status;
205 close(fd[1]);
206 len=read(fd[0],buf,256);
207 if (len>0) {
208 int i;
209 for(i=0;i<len && version==0;i++) {
210 if(strncmp(buf+i,"version ",8)==0) {
211 int v1,v2,v3;
212 sscanf(buf+i+8,"%d.%d.%d",&v1,&v2,&v3);
213 version=(v1 << 16) + (v2 << 8) + v3;
217 close(fd[0]);
218 waitpid(f,&status,0);
220 else if (f==0) {
221 close(fd[0]);
222 dup2(fd[1],1);
223 dup2(fd[1],2);
224 close(fd[1]);
225 if (execvp(prog,newargv) < 0) {
226 exit(1);
229 return version;
232 static char *parsevdearg(char *arg,char **sock,int *pport, int fd)
234 char newarg[128];
235 int vlan=0;
236 *sock=VDESTDSOCK;
237 *pport=0;
238 printf("arg %s\n", arg);
239 while(*arg){
240 while (*arg==',') arg++;
241 if (strncmp(arg,"vlan=",5)==0) {
242 vlan=atoi(arg+5);
243 while (*arg != 0 && *arg != ',')
244 arg++;
246 else if (strncmp(arg,"sock=",5)==0) {
247 arg+=5;
248 if (*arg=='\"') {
249 arg++;
250 *sock=arg;
251 while (*arg != 0 && *arg != '\"')
252 arg++;
253 } else {
254 *sock=arg;
255 while (*arg != 0 && *arg != ',')
256 arg++;
258 if (*arg != 0) {
259 *arg=0; arg++;
262 else if (strncmp(arg,"port=",5)==0) {
263 *pport=atoi(arg+5);
264 while (*arg != 0 && *arg != ',')
265 arg++;
269 snprintf(newarg,128,"tap,vlan=%d,fd=%d%s%s",vlan,fd,(*arg == 0)?"":",",arg);
270 return strdup(newarg);
273 int main(int argc, char **argv)
275 char *argsock=NULL,**sockname;
276 int *ports;
277 int result;
278 register ssize_t nx;
279 int newargc;
280 int daemonize;
281 char **newargv;
282 typedef int pair[2];
283 pair *sp;
284 register int i,j;
285 int oldsyntax=0;
286 int newsyntax=0;
287 int ver;
288 mode_t mode = 0700;
290 vdeqname=basename(argv[0]);
291 //callerpwd=getpwuid(getuid());
292 /* OLD SYNTAX MGMT */
293 if (strncmp(vdeqname,"vdeo",4) == 0) {
294 oldsyntax=1;
295 if (strcmp(vdeqname,"vdeoq") != 0) {
296 filename=vdeqname+4;
299 else if (strcmp(vdeqname,"vdeq") != 0 && strncmp(vdeqname,"vde",3)==0) {
300 filename=vdeqname+3;
302 else if (argc > 1) {
303 filename=argv[1];
304 argc--;
305 argv++;
306 } else {
307 usage();
309 daemonize=isdaemonize(argc-1,argv+1);
310 if ((ver=checkver(filename)) < 0x800)
311 oldsyntax=1;
312 if (!oldsyntax) {
313 nb_nics=countnewnics(argc-1,argv+1);
314 if (nb_nics > 0)
315 newsyntax=1;
317 if ((argc > 1 && (
318 strcmp(argv[1],"-h")==0 ||
319 strcmp(argv[1],"-help")==0 ||
320 strcmp(argv[1],"--help")==0
321 )) || (
322 strcmp(filename,"-h")==0 ||
323 strcmp(filename,"-help")==0 ||
324 strcmp(filename,"--help")==0
325 )) {
326 usage();
327 } else if (argc > 2 && (
328 (strcmp(argv[1],"-vdesock")==0) ||
329 (strcmp(argv[1],"-sock")==0) ||
330 (strcmp(argv[1],"-unix")==0))
332 argsock=argv[2];
333 argv+=2;
334 argc-=2;
335 } else
336 argsock=NULL;
338 if (argc > 2 && ((strcmp(argv[1],"--mod")==0))
340 sscanf(argv[2],"%o",&mode);
341 argv+=2;
342 argc-=2;
345 if (!newsyntax) {
346 if (argsock == NULL)
347 nb_nics=1;
348 else
349 nb_nics=countnics(argsock);
350 if (!oldsyntax && nb_nics > 1)
351 fprintf(stderr,
352 "Warning: all the vde connections will be connected to one net interface\n"
353 " to configure several interface use the new syntax -net vde\n");
356 if ((sp= (pair *) malloc(nb_nics * 2 * sizeof (int)))<0) {
357 perror("malloc nics");
358 exit(1);
361 if ((conn=(VDECONN **) calloc (nb_nics,sizeof(VDECONN *))) <0) {
362 perror("calloc conn");
363 exit(1);
366 for (i=0; i<nb_nics; i++) {
367 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sp[i]) < 0){
368 perror("socketpair");
369 exit(1);
373 if ((sockname= (char **) malloc(sizeof(char *) * nb_nics))<0) {
374 perror("malloc sockname");
375 exit(1);
377 if ((ports= (int *) calloc(nb_nics, sizeof(int)))<0) {
378 perror("malloc ports");
379 exit(1);
382 if (newsyntax)
384 int netflag;
385 int vdeint;
386 newargv=argv;
387 newargc=argc;
388 for (i=1,netflag=0,vdeint=0;i<argc;i++) {
389 if (strcmp(argv[i],"-net")==0)
390 netflag=1;
391 else {
392 if (netflag && strncmp(argv[i],"vde",3) == 0)
394 argv[i]=parsevdearg(argv[i]+3,&sockname[vdeint],&ports[vdeint],sp[vdeint][0]);
395 vdeint++;
397 netflag=0;
400 } else
402 if (argsock==NULL)
403 sockname[0]=VDESTDSOCK;
404 else
406 register char *s=argsock;
407 register char oldch;
408 i=0;
409 do {
410 sockname[i++]=s;
411 while (*s != ',' && *s != '\0')
412 s++;
413 oldch=*s;
414 *s=0;
415 s++;
416 } while (oldch != 0);
419 /* printf("-- %s --\n",numfd);
420 printf("as %s\n",argsock);
421 for (i=0; i<nb_nics; i++)
422 printf("%d -> %s\n",i,sockname[i]); */
423 newargc=argc+2+(2*nb_nics);
424 if ((newargv=(char **) malloc ((newargc+1)* sizeof(char *))) <0) {
425 perror("malloc");
426 exit(1);
429 newargv[0]=filename;
430 if (oldsyntax) {
431 for (i=0; i<nb_nics; i++) {
432 char numfd[10];
433 sprintf(numfd,"%d",sp[i][0]);
434 newargv[2*i+1]="-tun-fd";
435 newargv[2*i+2]=strdup(numfd);
438 char nnics[10];
439 sprintf(nnics,"%d",nb_nics);
440 newargv[2*nb_nics+1]="-nics";
441 newargv[2*nb_nics+2]=strdup(nnics);
443 } else {
444 for (i=0; i<nb_nics; i++) {
445 char numfd[30];
446 sprintf(numfd,"tap,vlan=0,fd=%d",sp[i][0]);
447 newargv[2*i+1]="-net";
448 newargv[2*i+2]=strdup(numfd);
450 newargv[2*nb_nics+1]="-net";
451 newargv[2*nb_nics+2]="nic";
453 for (i=(2*nb_nics)+3,j=1;j<argc;i++,j++) newargv[i]=argv[j];
455 newargv[i]=0;
458 if ((pollv= (struct pollfd *) malloc(sizeof(struct pollfd) * 2 * nb_nics))<0) {
459 perror("malloc pollfd");
460 exit(1);
462 setsighandlers();
463 for (i=0; i<nb_nics; i++) {
464 struct vde_open_args vdearg={ports[i],NULL,mode};
465 conn[i]=vde_open(sockname[i],"vdeqemu",&vdearg);
466 pollv[2*i+1].fd=vde_datafd(conn[i]);
467 pollv[2*i].fd=sp[i][1];
468 pollv[2*i].events= pollv[2*i+1].events=POLLIN|POLLHUP;
471 #if 0
473 int i=0;
474 while(newargv[i])
475 printf("%s ", newargv[i++]);
476 printf("\n");
478 #endif
480 if (fork()) {
481 close(0);
482 signal(SIGCHLD, sigchld_handler);
483 for (i=0; i<nb_nics; i++)
484 close(sp[i][0]);
485 if (daemonize)
486 daemon(1,1);
487 for(;;) {
488 if ((result=poll(pollv,2*nb_nics,-1)) < 0) {
489 if (errno != EINTR) {
490 perror("poll");
491 cleanup();
492 exit(1);
493 } else {
494 if ((exit_value < 256) || !daemonize)
495 exit(exit_value);
497 } else {
498 for (i=0; i<nb_nics; i++) {
499 if (pollv[2*i].revents & POLLHUP || pollv[2*i+1].revents & POLLHUP)
500 break;
501 if (pollv[2*i].revents & POLLIN) {
502 if ((nx=read(sp[i][1],bufin,sizeof(bufin))) <= 0) {
503 if (nx < 0)
504 perror("read");
505 cleanup();
506 exit(nx < 0);
508 //fprintf(stderr,"RX from qemu %d\n",nx);
509 if (vde_send(conn[i],bufin,nx,0) < 0) {
510 perror("sendto");
511 cleanup();
512 exit(1);
515 if (pollv[2*i+1].revents & POLLIN) {
516 if ((nx=vde_recv(conn[i],bufin,BUFSIZE,0)) < 0) {
517 perror("recvfrom");
518 cleanup();
519 exit(1);
521 //fprintf(stderr,"TX to qemu %d\n",nx);
522 if (write(sp[i][1],bufin,nx) < 0) {
523 if (errno != ECONNREFUSED)
524 perror("write");
525 cleanup();
526 exit(errno != ECONNREFUSED);
532 } else {
533 for (i=0; i<nb_nics; i++) {
534 close(sp[i][1]);
535 close(vde_datafd(conn[i]));
536 close(vde_ctlfd(conn[i]));
538 execvp(filename,newargv);
540 cleanup();
541 return(0);