cleanup (there was a debug print)
[vde.git] / vde / qemu / vdeq.c
blobc46381ff0d8c0fe2ded9d8e3b4ffc13881e95da2
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 <config.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <signal.h>
10 #include <errno.h>
11 #include <unistd.h>
12 #include <stdint.h>
13 #include <libgen.h>
14 #include <sys/ioctl.h>
15 #include <sys/socket.h>
16 #include <sys/un.h>
17 #include <sys/uio.h>
18 #include <sys/poll.h>
20 #include <vde.h>
22 #define SWITCH_MAGIC 0xfeedface
23 #define BUFSIZE 2048
24 #define ETH_ALEN 6
26 enum request_type { REQ_NEW_CONTROL };
28 struct request_v3 {
29 uint32_t magic;
30 uint32_t version;
31 enum request_type type;
32 struct sockaddr_un sock;
36 static int send_fd(char *name, int fddata, struct sockaddr_un *datasock, int intno, int group)
38 int pid = getpid();
39 struct request_v3 req;
40 int fdctl;
42 struct sockaddr_un sock;
44 if((fdctl = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){
45 perror("socket");
46 exit(1);
49 sock.sun_family = AF_UNIX;
50 snprintf(sock.sun_path, sizeof(sock.sun_path), "%s", name);
51 if(connect(fdctl, (struct sockaddr *) &sock, sizeof(sock))){
52 perror("connect");
53 exit(1);
56 req.magic=SWITCH_MAGIC;
57 req.version=3;
58 req.type=REQ_NEW_CONTROL+((group > 0)?((geteuid()<<8) + group) << 8:0);
60 req.sock.sun_family=AF_UNIX;
61 memset(req.sock.sun_path, 0, sizeof(req.sock.sun_path));
62 sprintf(&req.sock.sun_path[1], "%5d-%2d", pid, intno);
64 if(bind(fddata, (struct sockaddr *) &req.sock, sizeof(req.sock)) < 0){
65 perror("bind");
66 exit(1);
69 if (send(fdctl,&req,sizeof(req),0) < 0) {
70 perror("send");
71 exit(1);
74 if (recv(fdctl,datasock,sizeof(struct sockaddr_un),0)<0) {
75 perror("recv");
76 exit(1);
79 return fdctl;
82 unsigned char bufin[BUFSIZE];
84 struct pollfd *pollv;
86 char *filename;
87 char *vdeqname;
88 #define NUMW 10
90 static int countnics(const char *s)
92 register int nics=1;
93 while (*s) {
94 if (*s==',') nics++;
95 s++;
97 return nics;
100 static int countnewnics(int argc,char *argv[])
102 register int nics=0;
103 register int netflag=0;
104 while (argc > 0) {
105 if (strcmp(argv[0],"-net")==0)
106 netflag=1;
107 else {
108 if (netflag && (strncmp(argv[0],"vde",3)==0))
109 nics++;
110 netflag=0;
112 argv++;
113 argc--;
115 return nics;
118 static void usage()
120 if (strcmp(vdeqname,"vdeq") != 0 && strncmp(vdeqname,"vde",3)==0)
121 fprintf(stderr,"Usage: %s [-h]\n"
122 "\t %s ...qemu options... -net vde[,vlan=n][,sock=sock] ... \n"
123 "Old syntax:\n"
124 "\t %s [-sock sock1 [,sock2...]] qemu_options\n"
125 "\t (%s executes a qemu machine named %s)\n", vdeqname, vdeqname,vdeqname,vdeqname,filename);
126 else
127 fprintf(stderr,"Usage: %s [-h]\n"
128 "\t %s qemu_executable ...qemu options... -net vde[,vlan=n][,sock=sock] ... \n"
129 "Old syntax:\n"
130 "\t %s qemu_executable [-sock sock1 [,sock2...]] qemu_options\n", vdeqname, vdeqname, vdeqname);
131 exit(0);
134 static void leave()
136 fprintf(stderr,"qemu exited: %s quits\n", vdeqname);
137 exit(0);
141 static char *parsevdearg(char *arg,char **sock,int fd)
143 char newarg[128];
144 int vlan=0;
145 *sock=VDESTDSOCK;
146 while (*arg==',') arg++;
147 if (strncmp(arg,"vlan=",5)==0) {
148 vlan=atoi(arg+5);
149 while (*arg != 0 && *arg != ',')
150 arg++;
152 while (*arg==',') arg++;
153 if (strncmp(arg,"sock=",5)==0) {
154 arg+=5;
155 if (*arg=='\"') {
156 arg++;
157 *sock=arg;
158 while (*arg != 0 && *arg != '\"')
159 arg++;
160 } else {
161 *sock=arg;
162 while (*arg != 0 && *arg != ',')
163 arg++;
165 if (*arg != 0) {
166 *arg=0; arg++;
169 while (*arg==',') arg++;
170 snprintf(newarg,128,"tap,vlan=%d,fd=%d%s%s",vlan,fd,(*arg == 0)?"":",",arg);
171 return strdup(newarg);
174 int main(int argc, char **argv)
176 int *fddata;
177 char *argsock,**sockname;
178 struct sockaddr_un *dataout,datain;
179 int datainsize;
180 int result;
181 int group=0;
182 int *connected_fd;
183 register ssize_t nx;
184 int args;
185 int newargc;
186 char **newargv;
187 typedef int pair[2];
188 pair *sp;
189 register int i;
190 int nb_nics;
191 int oldsyntax=0;
192 int newsyntax=0;
194 vdeqname=basename(argv[0]);
195 /* OLD SYNTAX MGMT */
196 if (strncmp(vdeqname,"vdeo",4) == 0) {
197 oldsyntax=1;
198 if (strcmp(vdeqname,"vdeoq") != 0) {
199 filename=vdeqname+4;
200 args=1;
203 else
204 if (strcmp(vdeqname,"vdeq") != 0 && strncmp(vdeqname,"vde",3)==0) {
205 filename=vdeqname+3;
206 args=1;
208 else if (argc > 1) {
209 filename=argv[1];
210 args=2;
211 } else {
212 usage();
214 if (!oldsyntax) {
215 nb_nics=countnewnics(argc-args,argv+args);
216 if (nb_nics > 0)
217 newsyntax=1;
219 if ((argc > args && (
220 strcmp(argv[args],"-h")==0 ||
221 strcmp(argv[args],"-help")==0 ||
222 strcmp(argv[args],"--help")==0
223 )) || (
224 strcmp(filename,"-h")==0 ||
225 strcmp(filename,"-help")==0 ||
226 strcmp(filename,"--help")==0
227 )) {
228 usage();
229 } else if (argc > args+1 && !newsyntax &&
230 ((strcmp(argv[args],"-vdesock")==0) ||
231 (strcmp(argv[args],"-sock")==0) ||
232 (strcmp(argv[args],"--sock")==0) ||
233 (strcmp(argv[args],"-unix")==0) ||
234 (strcmp(argv[args],"-s")==0))
236 argsock=argv[args+1];
237 args+=2;
238 } else
239 argsock=NULL;
241 if (!newsyntax) {
242 if (argsock == NULL)
243 nb_nics=1;
244 else
245 nb_nics=countnics(argsock);
246 if (!oldsyntax && nb_nics > 1)
247 fprintf(stderr,
248 "Warning: all the vde connections will be connected to one net interface\n"
249 " to configure several interface use the new syntax -net vde\n");
251 if ((sp= (pair *) malloc(nb_nics * 2 * sizeof (int)))<0) {
252 perror("malloc nics");
253 exit(1);
256 for (i=0; i<nb_nics; i++) {
257 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sp[i]) < 0){
258 perror("socketpair");
259 exit(1);
263 if ((sockname= (char **) malloc(sizeof(char *) * nb_nics))<0) {
264 perror("malloc sockname");
265 exit(1);
268 if (newsyntax)
270 int netflag;
271 int vdeint;
272 newargv=argv;
273 newargc=argc;
274 for (i=0,netflag=0,vdeint=0;i<argc;i++) {
275 if (strcmp(argv[i],"-net")==0)
276 netflag=1;
277 else {
278 if (netflag && strncmp(argv[i],"vde",3) == 0)
280 argv[i]=parsevdearg(argv[i]+3,&sockname[vdeint],sp[vdeint][0]);
281 vdeint++;
283 netflag=0;
286 } else
288 if (argsock==NULL)
289 sockname[0]=VDESTDSOCK;
290 else
292 register char *s=argsock;
293 register char oldch;
294 i=0;
295 do {
296 sockname[i++]=s;
297 while (*s != ',' && *s != '\0')
298 s++;
299 oldch=*s;
300 *s=0;
301 s++;
302 } while (oldch != 0);
305 /* printf("-- %s --\n",numfd);
306 printf("as %s\n",argsock);
307 for (i=0; i<nb_nics; i++)
308 printf("%d -> %s\n",i,sockname[i]); */
309 newargc=argc+1+2+(2*nb_nics)-args;
310 if ((newargv=(char **) malloc ((newargc+1)* sizeof(char *))) <0) {
311 perror("malloc");
312 exit(1);
315 newargv[0]=filename;
316 if (oldsyntax) {
317 for (i=0; i<nb_nics; i++) {
318 char numfd[10];
319 sprintf(numfd,"%d",sp[i][0]);
320 newargv[2*i+1]="-tun-fd";
321 newargv[2*i+2]=strdup(numfd);
324 char nnics[10];
325 sprintf(nnics,"%d",nb_nics);
326 newargv[2*nb_nics+1]="-nics";
327 newargv[2*nb_nics+2]=strdup(nnics);
329 } else {
330 for (i=0; i<nb_nics; i++) {
331 char numfd[30];
332 sprintf(numfd,"tap,vlan=0,fd=%d",sp[i][0]);
333 newargv[2*i+1]="-net";
334 newargv[2*i+2]=strdup(numfd);
336 newargv[2*nb_nics+1]="-net";
337 newargv[2*nb_nics+2]="nic";
339 for (i=(2*nb_nics)+3;args<argc;i++,args++) newargv[i]=argv[args];
341 newargv[i]=0;
344 if ((fddata= (int *) malloc(sizeof(int) * nb_nics))<0) {
345 perror("malloc fddata");
346 exit(1);
348 if ((connected_fd= (int *) malloc(sizeof(int) * nb_nics))<0) {
349 perror("malloc connected_fd");
350 exit(1);
352 if ((dataout= (struct sockaddr_un *) malloc(sizeof(struct sockaddr_un) * nb_nics))<0) {
353 perror("malloc dataout");
354 exit(1);
357 if ((pollv= (struct pollfd *) malloc(sizeof(struct pollfd) * 2 * nb_nics))<0) {
358 perror("malloc fddata");
359 exit(1);
361 for (i=0; i<nb_nics; i++) {
362 if((fddata[i] = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0){
363 perror("socket");
364 exit(1);
366 connected_fd[i]=send_fd(sockname[i], fddata[i], &(dataout[i]), i, group);
367 pollv[2*i+1].fd=fddata[i];
368 pollv[2*i].fd=sp[i][1];
369 pollv[2*i].events= pollv[2*i+1].events=POLLIN|POLLHUP;
372 if (fork()) {
373 close(0);
374 signal(SIGCHLD, leave);
375 for (i=0; i<nb_nics; i++)
376 close(sp[i][0]);
377 for(;;) {
378 result=poll(pollv,2*nb_nics,-1);
379 for (i=0; i<nb_nics; i++) {
380 if (pollv[2*i].revents & POLLHUP || pollv[2*i+1].revents & POLLHUP)
381 break;
382 if (pollv[2*i].revents & POLLIN) {
383 nx=read(sp[i][1],bufin,sizeof(bufin));
384 //fprintf(stderr,"RX from qemu %d\n",nx);
385 //send(connected_fd,bufin,nx,0);
386 sendto(fddata[i],bufin,nx,0,(struct sockaddr *) &(dataout[i]), sizeof(struct sockaddr_un));
388 if (pollv[2*i+1].revents & POLLIN) {
389 datainsize=sizeof(datain);
390 nx=recvfrom(fddata[i],bufin,BUFSIZE,0,(struct sockaddr *) &datain, &datainsize);
391 //fprintf(stderr,"TX to qemu %d\n",nx);
392 write(sp[i][1],bufin,nx);
396 } else {
397 for (i=0; i<nb_nics; i++) {
398 close(sp[i][1]);
399 close(fddata[i]);
400 close(connected_fd[i]);
402 execvp(filename,newargv);
404 return(0);