readchar fix
[vde.git] / vde-2 / vde_switch.c
blob8f2b5c0da75b727720bc5018f0fe2b50b410402e
1 /* Copyright 2005 Renzo Davoli VDE-2
2 * Licensed under the GPL
3 * --pidfile/-p and cleanup management by Mattia Belletti.
4 * some code remains from uml_switch Copyright 2001, 2002 Jeff Dike and others
5 * Modified by Ludovico Gardenghi 2005
6 */
8 #include <unistd.h>
9 #define _GNU_SOURCE
10 #include <getopt.h>
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <signal.h>
15 #include <syslog.h>
16 #include <errno.h>
17 #include <sys/poll.h>
18 #ifndef HAVE_POLL
19 #include <utils/poll.h>
20 #endif
21 #include <switch.h>
22 #include <config.h>
23 #include <qtimer.h>
24 #include <hash.h>
25 #include <port.h>
26 #ifdef FSTP
27 #include <fstp.h>
28 #endif
29 #include <consmgmt.h>
30 #include <sys/time.h>
31 #include <time.h>
33 #include <vde.h>
34 #ifdef VDE_PQ
35 #include <packetq.h>
36 #endif
38 static struct swmodule *swmh;
40 char *prog;
41 unsigned char switchmac[ETH_ALEN];
42 unsigned int priority=DEFAULT_PRIORITY;
44 static int hash_size=INIT_HASH_SIZE;
45 static int numports=INIT_NUMPORTS;
48 static void recaddswm(struct swmodule **p,struct swmodule *new)
50 struct swmodule *this=*p;
51 if (this == NULL)
52 *p=new;
53 else
54 recaddswm(&(this->next),new);
57 void add_swm(struct swmodule *new)
59 static int lastlwmtag;
60 new->swmtag= ++lastlwmtag;
61 if (new != NULL && new->swmtag != 0) {
62 new->next=NULL;
63 recaddswm(&swmh,new);
67 static void recdelswm(struct swmodule **p,struct swmodule *old)
69 struct swmodule *this=*p;
70 if (this != NULL) {
71 if(this == old)
72 *p=this->next;
73 else
74 recdelswm(&(this->next),old);
78 void del_swm(struct swmodule *old)
80 if (old != NULL) {
81 recdelswm(&swmh,old);
85 /* FD MGMT */
86 struct pollplus {
87 unsigned char type;
88 int arg;
89 time_t timestamp;
92 static int nfds = 0;
93 static int nprio =0;
94 static struct pollfd *fds = NULL;
95 static struct pollplus **fdpp = NULL;
97 static int maxfds = 0;
99 static struct swmodule **fdtypes;
100 static int ntypes;
101 static int maxtypes;
103 #define PRIOFLAG 0x80
104 #define TYPEMASK 0x7f
105 #define ISPRIO(X) ((X) & PRIOFLAG)
107 #define TYPE2MGR(X) (fdtypes[((X) & TYPEMASK)])
109 unsigned char add_type(struct swmodule *mgr,int prio)
111 register int i;
112 if(ntypes==maxtypes) {
113 maxtypes = maxtypes ? 2 * maxtypes : 8;
114 if (maxtypes > PRIOFLAG) {
115 printlog(LOG_ERR,"too many file types");
116 exit(1);
118 if((fdtypes = realloc(fdtypes, maxtypes * sizeof(struct swmodule *))) == NULL){
119 printlog(LOG_ERR,"realloc fdtypes %s",strerror(errno));
120 exit(1);
122 memset(fdtypes+ntypes,0,sizeof(struct swmodule *) * maxtypes-ntypes);
123 i=ntypes;
124 } else
125 for(i=0; fdtypes[i] != NULL; i++)
127 fdtypes[i]=mgr;
128 ntypes++;
129 return i | ((prio != 0)?PRIOFLAG:0);
132 void del_type(unsigned char type)
134 type &= TYPEMASK;
135 if (type < maxtypes)
136 fdtypes[type]=NULL;
137 ntypes--;
140 void add_fd(int fd,unsigned char type,int arg)
142 struct pollfd *p;
143 int index;
144 /* enlarge fds and g_fdsdata array if needed */
145 if(nfds == maxfds){
146 maxfds = maxfds ? 2 * maxfds : 8;
147 if((fds = realloc(fds, maxfds * sizeof(struct pollfd))) == NULL){
148 printlog(LOG_ERR,"realloc fds %s",strerror(errno));
149 exit(1);
151 if((fdpp = realloc(fdpp, maxfds * sizeof(struct pollplus *))) == NULL){
152 printlog(LOG_ERR,"realloc pollplus %s",strerror(errno));
153 exit(1);
156 if (ISPRIO(type)) {
157 fds[nfds]=fds[nprio];
158 fdpp[nfds]=fdpp[nprio];
159 index=nprio;
160 nprio++;
161 } else
162 index=nfds;
163 if((fdpp[index]=malloc(sizeof(struct pollplus))) == NULL) {
164 printlog(LOG_ERR,"realloc pollplus elem %s",strerror(errno));
165 exit(1);
167 p = &fds[index];
168 p->fd = fd;
169 p->events = POLLIN | POLLHUP;
170 fdpp[index]->type=type;
171 fdpp[index]->arg=arg;
172 nfds++;
175 static void file_cleanup(void)
177 register int i;
178 for(i = 0; i < nfds; i++)
179 TYPE2MGR(fdpp[i]->type)->cleanup(fdpp[i]->type,fds[i].fd,fdpp[i]->arg);
182 void remove_fd(int fd)
184 register int i;
186 for(i = 0; i < nfds; i++){
187 if(fds[i].fd == fd) break;
189 if(i == nfds){
190 printlog(LOG_WARNING,"remove_fd : Couldn't find descriptor %d", fd);
191 } else {
192 struct pollplus *old=fdpp[i];
193 TYPE2MGR(fdpp[i]->type)->cleanup(fdpp[i]->type,fds[i].fd,fdpp[i]->arg);
194 if (ISPRIO(fdpp[i]->type)) nprio--;
195 memmove(&fds[i], &fds[i + 1], (maxfds - i - 1) * sizeof(struct pollfd));
196 memmove(&fdpp[i], &fdpp[i + 1], (maxfds - i - 1) * sizeof(struct pollplus *));
197 free(old);
198 nfds--;
203 static void main_loop()
205 time_t now;
206 register int n,i;
207 while(1) {
208 #ifdef VDE_PQ
209 n=poll(fds,nfds,packetq_timeout);
210 #else
211 n=poll(fds,nfds,-1);
212 #endif
213 now=qtime();
214 if(n < 0){
215 if(errno != EINTR)
216 printlog(LOG_WARNING,"poll %s",strerror(errno));
217 } else {
218 for(i = 0; /*i < nfds &&*/ n>0; i++){
219 if(fds[i].revents != 0) {
220 register int prenfds=nfds;
221 n--;
222 fdpp[i]->timestamp=now;
223 TYPE2MGR(fdpp[i]->type)->handle_input(fdpp[i]->type,fds[i].fd,fds[i].revents,&(fdpp[i]->arg));
224 if (nfds!=prenfds) /* the current fd has been deleted */
225 break; /* PERFORMANCE it is faster returning to poll */
227 /* optimization: most used descriptors migrate to the head of the poll array */
228 #ifdef OPTPOLL
229 else
231 if (i < nfds && i > 0 && i != nprio) {
232 register int i_1=i-1;
233 if (fdpp[i]->timestamp > fdpp[i_1]->timestamp) {
234 struct pollfd tfds;
235 struct pollplus *tfdpp;
236 tfds=fds[i];fds[i]=fds[i_1];fds[i_1]=tfds;
237 tfdpp=fdpp[i];fdpp[i]=fdpp[i_1];fdpp[i_1]=tfdpp;
241 #endif
243 #ifdef VDE_PQ
244 if (packetq_timeout > 0)
245 packetq_try();
246 #endif
251 /* starting/ending routines, main_loop, main*/
252 #define HASH_TABLE_SIZE_ARG 0x100
253 #define MACADDR_ARG 0x101
254 #define PRIORITY_ARG 0x102
256 static void Usage(void) {
257 struct swmodule *p;
258 printf(
259 "Usage: vde_switch [OPTIONS]\n"
260 "Runs a VDE switch.\n"
261 "(global opts)\n"
262 " -h, --help Display this help and exit\n"
263 " -v, --version Display informations on version and exit\n"
264 " -n --numports Number of ports (default %d)\n"
265 " -x, --hub Make the switch act as a hub\n"
266 #ifdef FSTP
267 " -F, --fstp Activate the fast spanning tree protocol\n"
268 #endif
269 " --macaddr MAC Set the Switch MAC address\n"
270 #ifdef FSTP
271 " --priority N Set the priority for FST (MAC extension)\n"
272 #endif
273 " --hashsize N Hash table size\n"
274 ,numports);
275 for(p=swmh;p != NULL;p=p->next)
276 if (p->usage != NULL)
277 p->usage();
278 printf(
279 "\n"
280 "Report bugs to "PACKAGE_BUGREPORT "\n"
282 exit(1);
285 static void version(void)
287 printf(
288 "VDE " PACKAGE_VERSION "\n"
289 "Copyright 2003,2004,2005 Renzo Davoli\n"
290 "some code from uml_switch Copyright (C) 2001, 2002 Jeff Dike and others\n"
291 "VDE comes with NO WARRANTY, to the extent permitted by law.\n"
292 "You may redistribute copies of VDE under the terms of the\n"
293 "GNU General Public License v2.\n"
294 "For more information about these matters, see the files\n"
295 "named COPYING.\n");
296 exit(0);
299 static struct option *optcpy(struct option *tgt, struct option *src, int n, int tag)
301 register int i;
302 memcpy(tgt,src,sizeof(struct option) * n);
303 for (i=0;i<n;i++) {
304 tgt[i].val=(tgt[i].val & 0xffff) | tag << 16;
306 return tgt+n;
309 static int parse_globopt(int c, char *optarg)
311 int outc=0;
312 switch (c) {
313 case 'x':
314 portflag(P_SETFLAG,HUB_TAG);
315 break;
316 case HASH_TABLE_SIZE_ARG:
317 sscanf(optarg,"%i",&hash_size);
318 break;
319 #ifdef FSTP
320 case 'F':
321 fstflag(P_SETFLAG,FSTP_TAG);
322 break;
323 case PRIORITY_ARG:
324 sscanf(optarg,"%i",&priority);
325 priority &= 0xffff;
326 break;
327 #endif
328 case MACADDR_ARG:
329 {int maci[ETH_ALEN],rv;
330 if (index(optarg,':') != NULL)
331 rv=sscanf(optarg,"%x:%x:%x:%x:%x:%x", maci+0, maci+1, maci+2, maci+3, maci+4, maci+5);
332 else
333 rv=sscanf(optarg,"%x.%x.%x.%x.%x.%x", maci+0, maci+1, maci+2, maci+3, maci+4, maci+5);
334 if (rv != 6) {
335 printlog(LOG_ERR,"Invalid MAC Addr %s",optarg);
336 Usage();
338 else {
339 register int i;
340 for (i=0;i<ETH_ALEN;i++)
341 switchmac[i]=maci[i];
344 break;
345 case 'n':
346 sscanf(optarg,"%i",&numports);
347 break;
348 case 'v':
349 version();
350 break;
351 case 'h':
352 Usage();
353 break;
354 default:
355 outc=c;
357 return outc;
360 static void parse_args(int argc, char **argv)
362 struct swmodule *swmp;
363 struct option *long_options;
364 char *optstring;
365 static struct option global_options[] = {
366 {"help",0 , 0, 'h'},
367 {"hub", 0, 0, 'x'},
368 #ifdef FSTP
369 {"fstp",0 , 0, 'F'},
370 #endif
371 {"version", 0, 0, 'v'},
372 {"numports", 1, 0, 'n'},
373 {"hashsize", 1, 0, HASH_TABLE_SIZE_ARG},
374 {"macaddr", 1, 0, MACADDR_ARG},
375 #ifdef FSTP
376 {"priority", 1, 0, PRIORITY_ARG}
377 #endif
379 static struct option optail = {0,0,0,0};
380 #define N_global_options (sizeof(global_options)/sizeof(struct option))
381 prog = argv[0];
382 int totopts=N_global_options+1;
384 for(swmp=swmh;swmp != NULL;swmp=swmp->next)
385 totopts += swmp->swmnopts;
386 long_options=malloc(totopts * sizeof(struct option));
387 optstring=malloc(2 * totopts * sizeof(char));
388 if (long_options == NULL || optstring==NULL)
389 exit(2);
390 { /* fill-in the long_options fields */
391 register int i;
392 char *os=optstring;
393 char last=0;
394 struct option *opp=long_options;
395 opp=optcpy(opp,global_options,N_global_options,0);
396 for(swmp=swmh;swmp != NULL;swmp=swmp->next)
397 opp=optcpy(opp,swmp->swmopts,swmp->swmnopts,swmp->swmtag);
398 optcpy(opp,&optail,1,0);
399 for (i=0;i<totopts-1;i++)
401 int val=long_options[i].val & 0xffff;
402 if(val > ' ' && val <= '~' && val != last)
404 *os++=val;
405 if(long_options[i].has_arg) *os++=':';
408 *os=0;
411 /* Parse args */
412 int option_index = 0;
413 int c;
414 while (1) {
415 c = GETOPT_LONG (argc, argv, optstring,
416 long_options, &option_index);
417 if (c == -1)
418 break;
419 c=parse_globopt(c,optarg);
420 for(swmp=swmh;swmp != NULL && c!=0;swmp=swmp->next) {
421 if (swmp->parseopt != NULL) {
422 if((c >> 7) == 0)
423 c=swmp->parseopt(c,optarg);
424 else if ((c >> 16) == swmp->swmtag)
425 swmp->parseopt(c & 0xffff,optarg),c=0;
430 if(optind < argc)
431 Usage();
432 free(long_options);
433 free(optstring);
436 static void init_mods(void)
438 struct swmodule *swmp;
439 for(swmp=swmh;swmp != NULL;swmp=swmp->next)
440 if (swmp->init != NULL)
441 swmp->init();
444 static void cleanup(void)
446 struct swmodule *swmp;
447 file_cleanup();
448 for(swmp=swmh;swmp != NULL;swmp=swmp->next)
449 if (swmp->cleanup != NULL)
450 swmp->cleanup(0,-1,-1);
453 static void sig_handler(int sig)
455 printlog(LOG_ERR,"Caught signal %d, cleaning up and exiting", sig);
456 cleanup();
457 signal(sig, SIG_DFL);
458 kill(getpid(), sig);
461 static void setsighandlers()
463 /* setting signal handlers.
464 * * sets clean termination for SIGHUP, SIGINT and SIGTERM, and simply
465 * * ignores all the others signals which could cause termination. */
466 struct { int sig; const char *name; int ignore; } signals[] = {
467 { SIGHUP, "SIGHUP", 0 },
468 { SIGINT, "SIGINT", 0 },
469 { SIGPIPE, "SIGPIPE", 1 },
470 { SIGALRM, "SIGALRM", 1 },
471 { SIGTERM, "SIGTERM", 0 },
472 { SIGUSR1, "SIGUSR1", 1 },
473 { SIGUSR2, "SIGUSR2", 1 },
474 { SIGPROF, "SIGPROF", 1 },
475 { SIGVTALRM, "SIGVTALRM", 1 },
476 #ifdef VDE_LINUX
477 { SIGPOLL, "SIGPOLL", 1 },
478 #ifdef SIGSTKFLT
479 { SIGSTKFLT, "SIGSTKFLT", 1 },
480 #endif
481 { SIGIO, "SIGIO", 1 },
482 { SIGPWR, "SIGPWR", 1 },
483 #ifdef SIGUNUSED
484 { SIGUNUSED, "SIGUNUSED", 1 },
485 #endif
486 #endif
487 #ifdef VDE_DARWIN
488 { SIGXCPU, "SIGXCPU", 1 },
489 { SIGXFSZ, "SIGXFSZ", 1 },
490 #endif
491 { 0, NULL, 0 }
494 int i;
495 for(i = 0; signals[i].sig != 0; i++)
496 if(signal(signals[i].sig,
497 signals[i].ignore ? SIG_IGN : sig_handler) < 0)
498 printlog(LOG_ERR,"Setting handler for %s: %s", signals[i].name,
499 strerror(errno));
502 void set_switchmac()
504 struct timeval v;
505 long val;
506 register int i;
507 gettimeofday(&v,NULL);
508 srand48(v.tv_sec ^ v.tv_usec ^ getpid());
509 for(i=0,val=lrand48();i<4; i++,val>>=8)
510 switchmac[i+2]=val;
511 switchmac[0]=0;
512 switchmac[1]=0xff;
515 static void start_modules(void);
517 int main(int argc, char **argv)
519 set_switchmac();
520 start_modules();
521 parse_args(argc,argv);
522 atexit(cleanup);
523 setsighandlers();
524 hash_init(hash_size);
525 #ifdef FSTP
526 fst_init(numports);
527 #endif
528 port_init(numports);
529 init_mods();
530 loadrcfile();
531 qtimer_init();
532 main_loop();
533 return 0;
536 /* modules: module references are only here! */
537 static void start_modules(void)
539 void start_consmgmt(void);
540 void start_datasock(void);
541 void start_tuntap(void);
542 start_datasock();
543 start_consmgmt();
544 #ifdef HAVE_TUNTAP
545 start_tuntap();
546 #endif