- fixed poll emulation management
[vde.git] / vde-2 / vde_switch / vde_switch.c
blob1497e4d7779a8c5b4bd715d8e8513ad5312c5eda
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 "compat/poll.h"
18 #include <switch.h>
19 #include <config.h>
20 #include <qtimer.h>
21 #include <hash.h>
22 #include <port.h>
23 #ifdef FSTP
24 #include <fstp.h>
25 #endif
26 #include <consmgmt.h>
27 #include <sys/time.h>
28 #include <time.h>
30 #include <vde.h>
31 #ifdef VDE_PQ
32 #include <packetq.h>
33 #endif
35 static struct swmodule *swmh;
37 char *prog;
38 unsigned char switchmac[ETH_ALEN];
39 unsigned int priority=DEFAULT_PRIORITY;
41 static int hash_size=INIT_HASH_SIZE;
42 static int numports=INIT_NUMPORTS;
45 static void recaddswm(struct swmodule **p,struct swmodule *new)
47 struct swmodule *this=*p;
48 if (this == NULL)
49 *p=new;
50 else
51 recaddswm(&(this->next),new);
54 void add_swm(struct swmodule *new)
56 static int lastlwmtag;
57 new->swmtag= ++lastlwmtag;
58 if (new != NULL && new->swmtag != 0) {
59 new->next=NULL;
60 recaddswm(&swmh,new);
64 static void recdelswm(struct swmodule **p,struct swmodule *old)
66 struct swmodule *this=*p;
67 if (this != NULL) {
68 if(this == old)
69 *p=this->next;
70 else
71 recdelswm(&(this->next),old);
75 void del_swm(struct swmodule *old)
77 if (old != NULL) {
78 recdelswm(&swmh,old);
82 /* FD MGMT */
83 struct pollplus {
84 unsigned char type;
85 int arg;
86 time_t timestamp;
89 static int nfds = 0;
90 static int nprio =0;
91 static struct pollfd *fds = NULL;
92 static struct pollplus **fdpp = NULL;
94 static int maxfds = 0;
96 static struct swmodule **fdtypes;
97 static int ntypes;
98 static int maxtypes;
100 #define PRIOFLAG 0x80
101 #define TYPEMASK 0x7f
102 #define ISPRIO(X) ((X) & PRIOFLAG)
104 #define TYPE2MGR(X) (fdtypes[((X) & TYPEMASK)])
106 unsigned char add_type(struct swmodule *mgr,int prio)
108 register int i;
109 if(ntypes==maxtypes) {
110 maxtypes = maxtypes ? 2 * maxtypes : 8;
111 if (maxtypes > PRIOFLAG) {
112 printlog(LOG_ERR,"too many file types");
113 exit(1);
115 if((fdtypes = realloc(fdtypes, maxtypes * sizeof(struct swmodule *))) == NULL){
116 printlog(LOG_ERR,"realloc fdtypes %s",strerror(errno));
117 exit(1);
119 memset(fdtypes+ntypes,0,sizeof(struct swmodule *) * maxtypes-ntypes);
120 i=ntypes;
121 } else
122 for(i=0; fdtypes[i] != NULL; i++)
124 fdtypes[i]=mgr;
125 ntypes++;
126 return i | ((prio != 0)?PRIOFLAG:0);
129 void del_type(unsigned char type)
131 type &= TYPEMASK;
132 if (type < maxtypes)
133 fdtypes[type]=NULL;
134 ntypes--;
137 void add_fd(int fd,unsigned char type,int arg)
139 struct pollfd *p;
140 int index;
141 /* enlarge fds and g_fdsdata array if needed */
142 if(nfds == maxfds){
143 maxfds = maxfds ? 2 * maxfds : 8;
144 if((fds = realloc(fds, maxfds * sizeof(struct pollfd))) == NULL){
145 printlog(LOG_ERR,"realloc fds %s",strerror(errno));
146 exit(1);
148 if((fdpp = realloc(fdpp, maxfds * sizeof(struct pollplus *))) == NULL){
149 printlog(LOG_ERR,"realloc pollplus %s",strerror(errno));
150 exit(1);
153 if (ISPRIO(type)) {
154 fds[nfds]=fds[nprio];
155 fdpp[nfds]=fdpp[nprio];
156 index=nprio;
157 nprio++;
158 } else
159 index=nfds;
160 if((fdpp[index]=malloc(sizeof(struct pollplus))) == NULL) {
161 printlog(LOG_ERR,"realloc pollplus elem %s",strerror(errno));
162 exit(1);
164 p = &fds[index];
165 p->fd = fd;
166 p->events = POLLIN | POLLHUP;
167 fdpp[index]->type=type;
168 fdpp[index]->arg=arg;
169 nfds++;
172 static void file_cleanup(void)
174 register int i;
175 for(i = 0; i < nfds; i++)
176 TYPE2MGR(fdpp[i]->type)->cleanup(fdpp[i]->type,fds[i].fd,fdpp[i]->arg);
179 void remove_fd(int fd)
181 register int i;
183 for(i = 0; i < nfds; i++){
184 if(fds[i].fd == fd) break;
186 if(i == nfds){
187 printlog(LOG_WARNING,"remove_fd : Couldn't find descriptor %d", fd);
188 } else {
189 struct pollplus *old=fdpp[i];
190 TYPE2MGR(fdpp[i]->type)->cleanup(fdpp[i]->type,fds[i].fd,fdpp[i]->arg);
191 if (ISPRIO(fdpp[i]->type)) nprio--;
192 memmove(&fds[i], &fds[i + 1], (maxfds - i - 1) * sizeof(struct pollfd));
193 memmove(&fdpp[i], &fdpp[i + 1], (maxfds - i - 1) * sizeof(struct pollplus *));
194 free(old);
195 nfds--;
200 static void main_loop()
202 time_t now;
203 register int n,i;
204 while(1) {
205 #ifdef VDE_PQ
206 n=poll(fds,nfds,packetq_timeout);
207 #else
208 n=poll(fds,nfds,-1);
209 #endif
210 now=qtime();
211 if(n < 0){
212 if(errno != EINTR)
213 printlog(LOG_WARNING,"poll %s",strerror(errno));
214 } else {
215 for(i = 0; /*i < nfds &&*/ n>0; i++){
216 if(fds[i].revents != 0) {
217 register int prenfds=nfds;
218 n--;
219 fdpp[i]->timestamp=now;
220 TYPE2MGR(fdpp[i]->type)->handle_input(fdpp[i]->type,fds[i].fd,fds[i].revents,&(fdpp[i]->arg));
221 if (nfds!=prenfds) /* the current fd has been deleted */
222 break; /* PERFORMANCE it is faster returning to poll */
224 /* optimization: most used descriptors migrate to the head of the poll array */
225 #ifdef OPTPOLL
226 else
228 if (i < nfds && i > 0 && i != nprio) {
229 register int i_1=i-1;
230 if (fdpp[i]->timestamp > fdpp[i_1]->timestamp) {
231 struct pollfd tfds;
232 struct pollplus *tfdpp;
233 tfds=fds[i];fds[i]=fds[i_1];fds[i_1]=tfds;
234 tfdpp=fdpp[i];fdpp[i]=fdpp[i_1];fdpp[i_1]=tfdpp;
238 #endif
240 #ifdef VDE_PQ
241 if (packetq_timeout > 0)
242 packetq_try();
243 #endif
248 /* starting/ending routines, main_loop, main*/
249 #define HASH_TABLE_SIZE_ARG 0x100
250 #define MACADDR_ARG 0x101
251 #define PRIORITY_ARG 0x102
253 static void Usage(void) {
254 struct swmodule *p;
255 printf(
256 "Usage: vde_switch [OPTIONS]\n"
257 "Runs a VDE switch.\n"
258 "(global opts)\n"
259 " -h, --help Display this help and exit\n"
260 " -v, --version Display informations on version and exit\n"
261 " -n --numports Number of ports (default %d)\n"
262 " -x, --hub Make the switch act as a hub\n"
263 #ifdef FSTP
264 " -F, --fstp Activate the fast spanning tree protocol\n"
265 #endif
266 " --macaddr MAC Set the Switch MAC address\n"
267 #ifdef FSTP
268 " --priority N Set the priority for FST (MAC extension)\n"
269 #endif
270 " --hashsize N Hash table size\n"
271 ,numports);
272 for(p=swmh;p != NULL;p=p->next)
273 if (p->usage != NULL)
274 p->usage();
275 printf(
276 "\n"
277 "Report bugs to "PACKAGE_BUGREPORT "\n"
279 exit(1);
282 static void version(void)
284 printf(
285 "VDE " PACKAGE_VERSION "\n"
286 "Copyright 2003,2004,2005 Renzo Davoli\n"
287 "some code from uml_switch Copyright (C) 2001, 2002 Jeff Dike and others\n"
288 "VDE comes with NO WARRANTY, to the extent permitted by law.\n"
289 "You may redistribute copies of VDE under the terms of the\n"
290 "GNU General Public License v2.\n"
291 "For more information about these matters, see the files\n"
292 "named COPYING.\n");
293 exit(0);
296 static struct option *optcpy(struct option *tgt, struct option *src, int n, int tag)
298 register int i;
299 memcpy(tgt,src,sizeof(struct option) * n);
300 for (i=0;i<n;i++) {
301 tgt[i].val=(tgt[i].val & 0xffff) | tag << 16;
303 return tgt+n;
306 static int parse_globopt(int c, char *optarg)
308 int outc=0;
309 switch (c) {
310 case 'x':
311 portflag(P_SETFLAG,HUB_TAG);
312 break;
313 case HASH_TABLE_SIZE_ARG:
314 sscanf(optarg,"%i",&hash_size);
315 break;
316 #ifdef FSTP
317 case 'F':
318 fstflag(P_SETFLAG,FSTP_TAG);
319 break;
320 case PRIORITY_ARG:
321 sscanf(optarg,"%i",&priority);
322 priority &= 0xffff;
323 break;
324 #endif
325 case MACADDR_ARG:
326 {int maci[ETH_ALEN],rv;
327 if (index(optarg,':') != NULL)
328 rv=sscanf(optarg,"%x:%x:%x:%x:%x:%x", maci+0, maci+1, maci+2, maci+3, maci+4, maci+5);
329 else
330 rv=sscanf(optarg,"%x.%x.%x.%x.%x.%x", maci+0, maci+1, maci+2, maci+3, maci+4, maci+5);
331 if (rv != 6) {
332 printlog(LOG_ERR,"Invalid MAC Addr %s",optarg);
333 Usage();
335 else {
336 register int i;
337 for (i=0;i<ETH_ALEN;i++)
338 switchmac[i]=maci[i];
341 break;
342 case 'n':
343 sscanf(optarg,"%i",&numports);
344 break;
345 case 'v':
346 version();
347 break;
348 case 'h':
349 Usage();
350 break;
351 default:
352 outc=c;
354 return outc;
357 static void parse_args(int argc, char **argv)
359 struct swmodule *swmp;
360 struct option *long_options;
361 char *optstring;
362 static struct option global_options[] = {
363 {"help",0 , 0, 'h'},
364 {"hub", 0, 0, 'x'},
365 #ifdef FSTP
366 {"fstp",0 , 0, 'F'},
367 #endif
368 {"version", 0, 0, 'v'},
369 {"numports", 1, 0, 'n'},
370 {"hashsize", 1, 0, HASH_TABLE_SIZE_ARG},
371 {"macaddr", 1, 0, MACADDR_ARG},
372 #ifdef FSTP
373 {"priority", 1, 0, PRIORITY_ARG}
374 #endif
376 static struct option optail = {0,0,0,0};
377 #define N_global_options (sizeof(global_options)/sizeof(struct option))
378 prog = argv[0];
379 int totopts=N_global_options+1;
381 for(swmp=swmh;swmp != NULL;swmp=swmp->next)
382 totopts += swmp->swmnopts;
383 long_options=malloc(totopts * sizeof(struct option));
384 optstring=malloc(2 * totopts * sizeof(char));
385 if (long_options == NULL || optstring==NULL)
386 exit(2);
387 { /* fill-in the long_options fields */
388 register int i;
389 char *os=optstring;
390 char last=0;
391 struct option *opp=long_options;
392 opp=optcpy(opp,global_options,N_global_options,0);
393 for(swmp=swmh;swmp != NULL;swmp=swmp->next)
394 opp=optcpy(opp,swmp->swmopts,swmp->swmnopts,swmp->swmtag);
395 optcpy(opp,&optail,1,0);
396 for (i=0;i<totopts-1;i++)
398 int val=long_options[i].val & 0xffff;
399 if(val > ' ' && val <= '~' && val != last)
401 *os++=val;
402 if(long_options[i].has_arg) *os++=':';
405 *os=0;
408 /* Parse args */
409 int option_index = 0;
410 int c;
411 while (1) {
412 c = GETOPT_LONG (argc, argv, optstring,
413 long_options, &option_index);
414 if (c == -1)
415 break;
416 c=parse_globopt(c,optarg);
417 for(swmp=swmh;swmp != NULL && c!=0;swmp=swmp->next) {
418 if (swmp->parseopt != NULL) {
419 if((c >> 7) == 0)
420 c=swmp->parseopt(c,optarg);
421 else if ((c >> 16) == swmp->swmtag)
422 swmp->parseopt(c & 0xffff,optarg),c=0;
427 if(optind < argc)
428 Usage();
429 free(long_options);
430 free(optstring);
433 static void init_mods(void)
435 struct swmodule *swmp;
436 for(swmp=swmh;swmp != NULL;swmp=swmp->next)
437 if (swmp->init != NULL)
438 swmp->init();
441 static void cleanup(void)
443 struct swmodule *swmp;
444 file_cleanup();
445 for(swmp=swmh;swmp != NULL;swmp=swmp->next)
446 if (swmp->cleanup != NULL)
447 swmp->cleanup(0,-1,-1);
450 static void sig_handler(int sig)
452 printlog(LOG_ERR,"Caught signal %d, cleaning up and exiting", sig);
453 cleanup();
454 signal(sig, SIG_DFL);
455 kill(getpid(), sig);
458 static void setsighandlers()
460 /* setting signal handlers.
461 * sets clean termination for SIGHUP, SIGINT and SIGTERM, and simply
462 * ignores all the others signals which could cause termination. */
463 struct { int sig; const char *name; int ignore; } signals[] = {
464 { SIGHUP, "SIGHUP", 0 },
465 { SIGINT, "SIGINT", 0 },
466 { SIGPIPE, "SIGPIPE", 1 },
467 { SIGALRM, "SIGALRM", 1 },
468 { SIGTERM, "SIGTERM", 0 },
469 { SIGUSR1, "SIGUSR1", 1 },
470 { SIGUSR2, "SIGUSR2", 1 },
471 { SIGPROF, "SIGPROF", 1 },
472 { SIGVTALRM, "SIGVTALRM", 1 },
473 #ifdef VDE_LINUX
474 { SIGPOLL, "SIGPOLL", 1 },
475 #ifdef SIGSTKFLT
476 { SIGSTKFLT, "SIGSTKFLT", 1 },
477 #endif
478 { SIGIO, "SIGIO", 1 },
479 { SIGPWR, "SIGPWR", 1 },
480 #ifdef SIGUNUSED
481 { SIGUNUSED, "SIGUNUSED", 1 },
482 #endif
483 #endif
484 #ifdef VDE_DARWIN
485 { SIGXCPU, "SIGXCPU", 1 },
486 { SIGXFSZ, "SIGXFSZ", 1 },
487 #endif
488 { 0, NULL, 0 }
491 int i;
492 for(i = 0; signals[i].sig != 0; i++)
493 if(signal(signals[i].sig,
494 signals[i].ignore ? SIG_IGN : sig_handler) < 0)
495 printlog(LOG_ERR,"Setting handler for %s: %s", signals[i].name,
496 strerror(errno));
499 void set_switchmac()
501 struct timeval v;
502 long val;
503 register int i;
504 gettimeofday(&v,NULL);
505 srand48(v.tv_sec ^ v.tv_usec ^ getpid());
506 for(i=0,val=lrand48();i<4; i++,val>>=8)
507 switchmac[i+2]=val;
508 switchmac[0]=0;
509 switchmac[1]=0xff;
512 static void start_modules(void);
514 int main(int argc, char **argv)
516 set_switchmac();
517 start_modules();
518 parse_args(argc,argv);
519 atexit(cleanup);
520 setsighandlers();
521 hash_init(hash_size);
522 #ifdef FSTP
523 fst_init(numports);
524 #endif
525 port_init(numports);
526 init_mods();
527 loadrcfile();
528 qtimer_init();
529 main_loop();
530 return 0;
533 /* modules: module references are only here! */
534 static void start_modules(void)
536 void start_consmgmt(void);
537 void start_datasock(void);
538 void start_tuntap(void);
539 start_datasock();
540 start_consmgmt();
541 #ifdef HAVE_TUNTAP
542 start_tuntap();
543 #endif