syslimits.h fix for OSX
[vde.git] / vde-2 / vde_switch.c
blob9512a086021bc127d29340cc0d8c679d608ab6c5
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 #ifndef HAVE_BROKEN_POLL
18 #include <sys/poll.h>
19 #endif
20 #include <switch.h>
21 #include <config.h>
22 #include <qtimer.h>
23 #include <hash.h>
24 #include <port.h>
25 #ifdef FSTP
26 #include <fstp.h>
27 #endif
28 #include <consmgmt.h>
29 #include <sys/time.h>
30 #include <time.h>
32 #include <vde.h>
33 #ifdef VDE_PQ
34 #include <packetq.h>
35 #endif
37 #ifdef HAVE_BROKEN_POLL
38 #include "poll2select.h"
39 #define poll poll2select
40 #endif
42 static struct swmodule *swmh;
44 char *prog;
45 unsigned char switchmac[ETH_ALEN];
46 unsigned int priority=DEFAULT_PRIORITY;
48 static int hash_size=INIT_HASH_SIZE;
49 static int numports=INIT_NUMPORTS;
52 static void recaddswm(struct swmodule **p,struct swmodule *new)
54 struct swmodule *this=*p;
55 if (this == NULL)
56 *p=new;
57 else
58 recaddswm(&(this->next),new);
61 void add_swm(struct swmodule *new)
63 static int lastlwmtag;
64 new->swmtag= ++lastlwmtag;
65 if (new != NULL && new->swmtag != 0) {
66 new->next=NULL;
67 recaddswm(&swmh,new);
71 static void recdelswm(struct swmodule **p,struct swmodule *old)
73 struct swmodule *this=*p;
74 if (this != NULL) {
75 if(this == old)
76 *p=this->next;
77 else
78 recdelswm(&(this->next),old);
82 void del_swm(struct swmodule *old)
84 if (old != NULL) {
85 recdelswm(&swmh,old);
89 /* FD MGMT */
90 struct pollplus {
91 unsigned char type;
92 int arg;
93 time_t timestamp;
96 static int nfds = 0;
97 static int nprio =0;
98 static struct pollfd *fds = NULL;
99 static struct pollplus **fdpp = NULL;
101 static int maxfds = 0;
103 static struct swmodule **fdtypes;
104 static int ntypes;
105 static int maxtypes;
107 #define PRIOFLAG 0x80
108 #define TYPEMASK 0x7f
109 #define ISPRIO(X) ((X) & PRIOFLAG)
111 #define TYPE2MGR(X) (fdtypes[((X) & TYPEMASK)])
113 unsigned char add_type(struct swmodule *mgr,int prio)
115 register int i;
116 if(ntypes==maxtypes) {
117 maxtypes = maxtypes ? 2 * maxtypes : 8;
118 if (maxtypes > PRIOFLAG) {
119 printlog(LOG_ERR,"too many file types");
120 exit(1);
122 if((fdtypes = realloc(fdtypes, maxtypes * sizeof(struct swmodule *))) == NULL){
123 printlog(LOG_ERR,"realloc fdtypes %s",strerror(errno));
124 exit(1);
126 memset(fdtypes+ntypes,0,sizeof(struct swmodule *) * maxtypes-ntypes);
127 i=ntypes;
128 } else
129 for(i=0; fdtypes[i] != NULL; i++)
131 fdtypes[i]=mgr;
132 ntypes++;
133 return i | ((prio != 0)?PRIOFLAG:0);
136 void del_type(unsigned char type)
138 type &= TYPEMASK;
139 if (type < maxtypes)
140 fdtypes[type]=NULL;
141 ntypes--;
144 void add_fd(int fd,unsigned char type,int arg)
146 struct pollfd *p;
147 int index;
148 /* enlarge fds and g_fdsdata array if needed */
149 if(nfds == maxfds){
150 maxfds = maxfds ? 2 * maxfds : 8;
151 if((fds = realloc(fds, maxfds * sizeof(struct pollfd))) == NULL){
152 printlog(LOG_ERR,"realloc fds %s",strerror(errno));
153 exit(1);
155 if((fdpp = realloc(fdpp, maxfds * sizeof(struct pollplus *))) == NULL){
156 printlog(LOG_ERR,"realloc pollplus %s",strerror(errno));
157 exit(1);
160 if (ISPRIO(type)) {
161 fds[nfds]=fds[nprio];
162 fdpp[nfds]=fdpp[nprio];
163 index=nprio;
164 nprio++;
165 } else
166 index=nfds;
167 if((fdpp[index]=malloc(sizeof(struct pollplus))) == NULL) {
168 printlog(LOG_ERR,"realloc pollplus elem %s",strerror(errno));
169 exit(1);
171 p = &fds[index];
172 p->fd = fd;
173 p->events = POLLIN | POLLHUP;
174 fdpp[index]->type=type;
175 fdpp[index]->arg=arg;
176 nfds++;
179 static void file_cleanup(void)
181 register int i;
182 for(i = 0; i < nfds; i++)
183 TYPE2MGR(fdpp[i]->type)->cleanup(fdpp[i]->type,fds[i].fd,fdpp[i]->arg);
186 void remove_fd(int fd)
188 register int i;
190 for(i = 0; i < nfds; i++){
191 if(fds[i].fd == fd) break;
193 if(i == nfds){
194 printlog(LOG_WARNING,"remove_fd : Couldn't find descriptor %d", fd);
195 } else {
196 struct pollplus *old=fdpp[i];
197 TYPE2MGR(fdpp[i]->type)->cleanup(fdpp[i]->type,fds[i].fd,fdpp[i]->arg);
198 if (ISPRIO(fdpp[i]->type)) nprio--;
199 memmove(&fds[i], &fds[i + 1], (maxfds - i - 1) * sizeof(struct pollfd));
200 memmove(&fdpp[i], &fdpp[i + 1], (maxfds - i - 1) * sizeof(struct pollplus *));
201 free(old);
202 nfds--;
207 static void main_loop()
209 time_t now;
210 register int n,i;
211 while(1) {
212 #ifdef VDE_PQ
213 n=poll(fds,nfds,packetq_timeout);
214 #else
215 n=poll(fds,nfds,-1);
216 #endif
217 now=qtime();
218 if(n < 0){
219 if(errno != EINTR)
220 printlog(LOG_WARNING,"poll %s",strerror(errno));
221 } else {
222 for(i = 0; /*i < nfds &&*/ n>0; i++){
223 if(fds[i].revents != 0) {
224 register int prenfds=nfds;
225 n--;
226 fdpp[i]->timestamp=now;
227 TYPE2MGR(fdpp[i]->type)->handle_input(fdpp[i]->type,fds[i].fd,fds[i].revents,&(fdpp[i]->arg));
228 if (nfds!=prenfds) /* the current fd has been deleted */
229 break; /* PERFORMANCE it is faster returning to poll */
231 /* optimization: most used descriptors migrate to the head of the poll array */
232 #ifdef OPTPOLL
233 else
235 if (i < nfds && i > 0 && i != nprio) {
236 register int i_1=i-1;
237 if (fdpp[i]->timestamp > fdpp[i_1]->timestamp) {
238 struct pollfd tfds;
239 struct pollplus *tfdpp;
240 tfds=fds[i];fds[i]=fds[i_1];fds[i_1]=tfds;
241 tfdpp=fdpp[i];fdpp[i]=fdpp[i_1];fdpp[i_1]=tfdpp;
245 #endif
247 #ifdef VDE_PQ
248 if (packetq_timeout > 0)
249 packetq_try();
250 #endif
255 /* starting/ending routines, main_loop, main*/
256 #define HASH_TABLE_SIZE_ARG 0x100
257 #define MACADDR_ARG 0x101
258 #define PRIORITY_ARG 0x102
260 static void Usage(void) {
261 struct swmodule *p;
262 printf(
263 "Usage: vde_switch [OPTIONS]\n"
264 "Runs a VDE switch.\n"
265 "(global opts)\n"
266 " -h, --help Display this help and exit\n"
267 " -v, --version Display informations on version and exit\n"
268 " -n --numports Number of ports (default %d)\n"
269 " -x, --hub Make the switch act as a hub\n"
270 #ifdef FSTP
271 " -F, --fstp Activate the fast spanning tree protocol\n"
272 #endif
273 " --macaddr MAC Set the Switch MAC address\n"
274 #ifdef FSTP
275 " --priority N Set the priority for FST (MAC extension)\n"
276 #endif
277 " --hashsize N Hash table size\n"
278 ,numports);
279 for(p=swmh;p != NULL;p=p->next)
280 if (p->usage != NULL)
281 p->usage();
282 printf(
283 "\n"
284 "Report bugs to "PACKAGE_BUGREPORT "\n"
286 exit(1);
289 static void version(void)
291 printf(
292 "VDE " PACKAGE_VERSION "\n"
293 "Copyright 2003,2004,2005 Renzo Davoli\n"
294 "some code from uml_switch Copyright (C) 2001, 2002 Jeff Dike and others\n"
295 "VDE comes with NO WARRANTY, to the extent permitted by law.\n"
296 "You may redistribute copies of VDE under the terms of the\n"
297 "GNU General Public License v2.\n"
298 "For more information about these matters, see the files\n"
299 "named COPYING.\n");
300 exit(0);
303 static struct option *optcpy(struct option *tgt, struct option *src, int n, int tag)
305 register int i;
306 memcpy(tgt,src,sizeof(struct option) * n);
307 for (i=0;i<n;i++) {
308 tgt[i].val=(tgt[i].val & 0xffff) | tag << 16;
310 return tgt+n;
313 static int parse_globopt(int c, char *optarg)
315 int outc=0;
316 switch (c) {
317 case 'x':
318 portflag(P_SETFLAG,HUB_TAG);
319 break;
320 case HASH_TABLE_SIZE_ARG:
321 sscanf(optarg,"%i",&hash_size);
322 break;
323 #ifdef FSTP
324 case 'F':
325 fstflag(P_SETFLAG,FSTP_TAG);
326 break;
327 case PRIORITY_ARG:
328 sscanf(optarg,"%i",&priority);
329 priority &= 0xffff;
330 break;
331 #endif
332 case MACADDR_ARG:
333 {int maci[ETH_ALEN],rv;
334 if (index(optarg,':') != NULL)
335 rv=sscanf(optarg,"%x:%x:%x:%x:%x:%x", maci+0, maci+1, maci+2, maci+3, maci+4, maci+5);
336 else
337 rv=sscanf(optarg,"%x.%x.%x.%x.%x.%x", maci+0, maci+1, maci+2, maci+3, maci+4, maci+5);
338 if (rv != 6) {
339 printlog(LOG_ERR,"Invalid MAC Addr %s",optarg);
340 Usage();
342 else {
343 register int i;
344 for (i=0;i<ETH_ALEN;i++)
345 switchmac[i]=maci[i];
348 break;
349 case 'n':
350 sscanf(optarg,"%i",&numports);
351 break;
352 case 'v':
353 version();
354 break;
355 case 'h':
356 Usage();
357 break;
358 default:
359 outc=c;
361 return outc;
364 static void parse_args(int argc, char **argv)
366 struct swmodule *swmp;
367 struct option *long_options;
368 char *optstring;
369 static struct option global_options[] = {
370 {"help",0 , 0, 'h'},
371 {"hub", 0, 0, 'x'},
372 #ifdef FSTP
373 {"fstp",0 , 0, 'F'},
374 #endif
375 {"version", 0, 0, 'v'},
376 {"numports", 1, 0, 'n'},
377 {"hashsize", 1, 0, HASH_TABLE_SIZE_ARG},
378 {"macaddr", 1, 0, MACADDR_ARG},
379 #ifdef FSTP
380 {"priority", 1, 0, PRIORITY_ARG}
381 #endif
383 static struct option optail = {0,0,0,0};
384 #define N_global_options (sizeof(global_options)/sizeof(struct option))
385 prog = argv[0];
386 int totopts=N_global_options+1;
388 for(swmp=swmh;swmp != NULL;swmp=swmp->next)
389 totopts += swmp->swmnopts;
390 long_options=malloc(totopts * sizeof(struct option));
391 optstring=malloc(2 * totopts * sizeof(char));
392 if (long_options == NULL || optstring==NULL)
393 exit(2);
394 { /* fill-in the long_options fields */
395 register int i;
396 char *os=optstring;
397 char last=0;
398 struct option *opp=long_options;
399 opp=optcpy(opp,global_options,N_global_options,0);
400 for(swmp=swmh;swmp != NULL;swmp=swmp->next)
401 opp=optcpy(opp,swmp->swmopts,swmp->swmnopts,swmp->swmtag);
402 optcpy(opp,&optail,1,0);
403 for (i=0;i<totopts-1;i++)
405 int val=long_options[i].val & 0xffff;
406 if(val > ' ' && val <= '~' && val != last)
408 *os++=val;
409 if(long_options[i].has_arg) *os++=':';
412 *os=0;
415 /* Parse args */
416 int option_index = 0;
417 int c;
418 while (1) {
419 c = GETOPT_LONG (argc, argv, optstring,
420 long_options, &option_index);
421 if (c == -1)
422 break;
423 c=parse_globopt(c,optarg);
424 for(swmp=swmh;swmp != NULL && c!=0;swmp=swmp->next) {
425 if (swmp->parseopt != NULL) {
426 if((c >> 7) == 0)
427 c=swmp->parseopt(c,optarg);
428 else if ((c >> 16) == swmp->swmtag)
429 swmp->parseopt(c & 0xffff,optarg),c=0;
434 if(optind < argc)
435 Usage();
436 free(long_options);
437 free(optstring);
440 static void init_mods(void)
442 struct swmodule *swmp;
443 for(swmp=swmh;swmp != NULL;swmp=swmp->next)
444 if (swmp->init != NULL)
445 swmp->init();
448 static void cleanup(void)
450 struct swmodule *swmp;
451 file_cleanup();
452 for(swmp=swmh;swmp != NULL;swmp=swmp->next)
453 if (swmp->cleanup != NULL)
454 swmp->cleanup(0,-1,-1);
457 static void sig_handler(int sig)
459 printlog(LOG_ERR,"Caught signal %d, cleaning up and exiting", sig);
460 cleanup();
461 signal(sig, SIG_DFL);
462 kill(getpid(), sig);
465 static void setsighandlers()
467 /* setting signal handlers.
468 * * sets clean termination for SIGHUP, SIGINT and SIGTERM, and simply
469 * * ignores all the others signals which could cause termination. */
470 struct { int sig; const char *name; int ignore; } signals[] = {
471 { SIGHUP, "SIGHUP", 0 },
472 { SIGINT, "SIGINT", 0 },
473 { SIGPIPE, "SIGPIPE", 1 },
474 { SIGALRM, "SIGALRM", 1 },
475 { SIGTERM, "SIGTERM", 0 },
476 { SIGUSR1, "SIGUSR1", 1 },
477 { SIGUSR2, "SIGUSR2", 1 },
478 { SIGPROF, "SIGPROF", 1 },
479 { SIGVTALRM, "SIGVTALRM", 1 },
480 #ifdef VDE_LINUX
481 { SIGPOLL, "SIGPOLL", 1 },
482 { SIGSTKFLT, "SIGSTKFLT", 1 },
483 { SIGIO, "SIGIO", 1 },
484 { SIGPWR, "SIGPWR", 1 },
485 { SIGUNUSED, "SIGUNUSED", 1 },
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_consmgmt();
543 start_datasock();
544 start_tuntap();