tagging vde-2 version 2.3.2
[vde.git] / 2.3.2 / src / vde_switch / vde_switch.c
blob87a336a79cc3333c9cf588bce8af057d790a87f3
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 #define _GNU_SOURCE
9 #include <unistd.h>
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/types.h>
18 #include <sys/stat.h>
19 #include <fcntl.h>
20 #include "switch.h"
21 #include "qtimer.h"
22 #include "hash.h"
23 #include "port.h"
24 #ifdef FSTP
25 #include "fstp.h"
26 #endif
27 #include "consmgmt.h"
28 #include <sys/time.h>
29 #include <time.h>
31 #include <config.h>
32 #include <vde.h>
33 #include <vdecommon.h>
35 #include <poll.h>
37 static struct swmodule *swmh;
39 char *prog;
40 unsigned char switchmac[ETH_ALEN];
41 unsigned int priority=DEFAULT_PRIORITY;
43 static int hash_size=INIT_HASH_SIZE;
44 static int numports=INIT_NUMPORTS;
47 static void recaddswm(struct swmodule **p,struct swmodule *new)
49 struct swmodule *this=*p;
50 if (this == NULL)
51 *p=new;
52 else
53 recaddswm(&(this->next),new);
56 void add_swm(struct swmodule *new)
58 static int lastlwmtag;
59 new->swmtag= ++lastlwmtag;
60 if (new != NULL && new->swmtag != 0) {
61 new->next=NULL;
62 recaddswm(&swmh,new);
66 static void recdelswm(struct swmodule **p,struct swmodule *old)
68 struct swmodule *this=*p;
69 if (this != NULL) {
70 if(this == old)
71 *p=this->next;
72 else
73 recdelswm(&(this->next),old);
77 void del_swm(struct swmodule *old)
79 if (old != NULL) {
80 recdelswm(&swmh,old);
84 /* FD MGMT */
85 struct pollplus {
86 unsigned char type;
87 void *private_data;
88 time_t timestamp;
91 #define MAXFDS_INITIAL 8
92 #define MAXFDS_STEP 16
93 static int nfds = 0;
94 static int nprio =0;
95 static struct pollfd *fds = NULL;
96 static struct pollplus **fdpp = NULL;
98 /* permutation array: it maps each fd to its index in fds/fdpp */
99 /* fdpermsize is a multiple of 16 */
100 #define FDPERMSIZE_LOGSTEP 4
101 static short *fdperm;
102 static int fdpermsize=0;
104 static int maxfds = 0;
106 static struct swmodule **fdtypes;
107 static int ntypes;
108 static int maxtypes;
110 #define PRIOFLAG 0x80
111 #define TYPEMASK 0x7f
112 #define ISPRIO(X) ((X) & PRIOFLAG)
114 #define TYPE2MGR(X) (fdtypes[((X) & TYPEMASK)])
116 unsigned char add_type(struct swmodule *mgr,int prio)
118 register int i;
119 if(ntypes==maxtypes) {
120 maxtypes = maxtypes ? 2 * maxtypes : 8;
121 if (maxtypes > PRIOFLAG) {
122 printlog(LOG_ERR,"too many file types");
123 exit(1);
125 if((fdtypes = realloc(fdtypes, maxtypes * sizeof(struct swmodule *))) == NULL){
126 printlog(LOG_ERR,"realloc fdtypes %s",strerror(errno));
127 exit(1);
129 memset(fdtypes+ntypes,0,sizeof(struct swmodule *) * maxtypes-ntypes);
130 i=ntypes;
131 } else
132 for(i=0; fdtypes[i] != NULL; i++)
134 fdtypes[i]=mgr;
135 ntypes++;
136 return i | ((prio != 0)?PRIOFLAG:0);
139 void del_type(unsigned char type)
141 type &= TYPEMASK;
142 if (type < maxtypes)
143 fdtypes[type]=NULL;
144 ntypes--;
147 void add_fd(int fd,unsigned char type,void *private_data)
149 struct pollfd *p;
150 int index;
151 /* enlarge fds and fdpp array if needed */
152 if(nfds == maxfds){
153 maxfds = maxfds ? maxfds + MAXFDS_STEP : MAXFDS_INITIAL;
154 if((fds = realloc(fds, maxfds * sizeof(struct pollfd))) == NULL){
155 printlog(LOG_ERR,"realloc fds %s",strerror(errno));
156 exit(1);
158 if((fdpp = realloc(fdpp, maxfds * sizeof(struct pollplus *))) == NULL){
159 printlog(LOG_ERR,"realloc pollplus %s",strerror(errno));
160 exit(1);
163 if (fd >= fdpermsize) {
164 fdpermsize = ((fd >> FDPERMSIZE_LOGSTEP) + 1) << FDPERMSIZE_LOGSTEP;
165 if((fdperm = realloc(fdperm, fdpermsize * sizeof(short))) == NULL){
166 printlog(LOG_ERR,"realloc fdperm %s",strerror(errno));
167 exit(1);
170 if (ISPRIO(type)) {
171 fds[nfds]=fds[nprio];
172 fdpp[nfds]=fdpp[nprio];
173 index=nprio;
174 nprio++;
175 } else
176 index=nfds;
177 if((fdpp[index]=malloc(sizeof(struct pollplus))) == NULL) {
178 printlog(LOG_ERR,"realloc pollplus elem %s",strerror(errno));
179 exit(1);
181 fdperm[fd]=index;
182 p = &fds[index];
183 p->fd = fd;
184 p->events = POLLIN | POLLHUP;
185 fdpp[index]->type=type;
186 fdpp[index]->private_data=private_data;
187 fdpp[index]->timestamp=0;
188 nfds++;
191 static void file_cleanup(void)
193 register int i;
194 for(i = 0; i < nfds; i++)
195 TYPE2MGR(fdpp[i]->type)->cleanup(fdpp[i]->type,fds[i].fd,fdpp[i]->private_data);
198 void remove_fd(int fd)
200 register int i;
202 for(i = 0; i < nfds; i++){
203 if(fds[i].fd == fd) break;
205 if(i == nfds){
206 printlog(LOG_WARNING,"remove_fd : Couldn't find descriptor %d", fd);
207 } else {
208 struct pollplus *old=fdpp[i];
209 TYPE2MGR(fdpp[i]->type)->cleanup(fdpp[i]->type,fds[i].fd,fdpp[i]->private_data);
210 if (ISPRIO(fdpp[i]->type)) nprio--;
211 memmove(&fds[i], &fds[i + 1], (nfds - i - 1) * sizeof(struct pollfd));
212 memmove(&fdpp[i], &fdpp[i + 1], (nfds - i - 1) * sizeof(struct pollplus *));
213 for(;i<nfds;i++)
214 fdperm[fds[i].fd]=i;
215 free(old);
216 nfds--;
220 /* read/update events/private_data */
221 void *mainloop_get_private_data(int fd)
223 if (fd >= 0 && fd < fdpermsize)
224 return (fdpp[fdperm[fd]]->private_data);
225 else
226 return NULL;
229 void mainloop_set_private_data(int fd,void *private_data)
231 if (fd >=0 && fd < fdpermsize)
232 fdpp[fdperm[fd]]->private_data = private_data;
235 short mainloop_pollmask_get(int fd)
237 #if DEBUG_MAINLOOP_MASK
238 if (fds[fdperm[fd]].fd != fd) printf("PERMUTATION ERROR %d %d\n",fds[fdperm[fd]].fd,fd);
239 #endif
240 return fds[fdperm[fd]].events;
243 void mainloop_pollmask_add(int fd, short events)
245 #if DEBUG_MAINLOOP_MASK
246 if (fds[fdperm[fd]].fd != fd) printf("PERMUTATION ERROR %d %d\n",fds[fdperm[fd]].fd,fd);
247 #endif
248 fds[fdperm[fd]].events |= events;
251 void mainloop_pollmask_del(int fd, short events)
253 #if DEBUG_MAINLOOP_MASK
254 if (fds[fdperm[fd]].fd != fd) printf("PERMUTATION ERROR %d %d\n",fds[fdperm[fd]].fd,fd);
255 #endif
256 fds[fdperm[fd]].events &= ~events;
259 void mainloop_pollmask_set(int fd, short events)
261 #if DEBUG_MAINLOOP_MASK
262 if (fds[fdperm[fd]].fd != fd) printf("PERMUTATION ERROR %d %d\n",fds[fdperm[fd]].fd,fd);
263 #endif
264 fds[fdperm[fd]].events = events;
267 static void main_loop()
269 time_t now;
270 register int n,i;
271 while(1) {
272 n=poll(fds,nfds,-1);
273 now=qtime();
274 if(n < 0){
275 if(errno != EINTR)
276 printlog(LOG_WARNING,"poll %s",strerror(errno));
277 } else {
278 for(i = 0; /*i < nfds &&*/ n>0; i++){
279 if(fds[i].revents != 0) {
280 register int prenfds=nfds;
281 n--;
282 fdpp[i]->timestamp=now;
283 TYPE2MGR(fdpp[i]->type)->handle_io(fdpp[i]->type,fds[i].fd,fds[i].revents,fdpp[i]->private_data);
284 if (nfds!=prenfds) /* the current fd has been deleted */
285 break; /* PERFORMANCE it is faster returning to poll */
287 /* optimization: most used descriptors migrate to the head of the poll array */
288 #ifdef OPTPOLL
289 else
291 if (i < nfds && i > 0 && i != nprio) {
292 register int i_1=i-1;
293 if (fdpp[i]->timestamp > fdpp[i_1]->timestamp) {
294 struct pollfd tfds;
295 struct pollplus *tfdpp;
296 tfds=fds[i];fds[i]=fds[i_1];fds[i_1]=tfds;
297 tfdpp=fdpp[i];fdpp[i]=fdpp[i_1];fdpp[i_1]=tfdpp;
298 fdperm[fds[i].fd]=i;
299 fdperm[fds[i_1].fd]=i_1;
303 #endif
309 /* starting/ending routines, main_loop, main*/
310 #define HASH_TABLE_SIZE_ARG 0x100
311 #define MACADDR_ARG 0x101
312 #define PRIORITY_ARG 0x102
314 static void Usage(void) {
315 struct swmodule *p;
316 printf(
317 "Usage: vde_switch [OPTIONS]\n"
318 "Runs a VDE switch.\n"
319 "(global opts)\n"
320 " -h, --help Display this help and exit\n"
321 " -v, --version Display informations on version and exit\n"
322 " -n --numports Number of ports (default %d)\n"
323 " -x, --hub Make the switch act as a hub\n"
324 #ifdef FSTP
325 " -F, --fstp Activate the fast spanning tree protocol\n"
326 #endif
327 " --macaddr MAC Set the Switch MAC address\n"
328 #ifdef FSTP
329 " --priority N Set the priority for FST (MAC extension)\n"
330 #endif
331 " --hashsize N Hash table size\n"
332 ,numports);
333 for(p=swmh;p != NULL;p=p->next)
334 if (p->usage != NULL)
335 p->usage();
336 printf(
337 "\n"
338 "Report bugs to "PACKAGE_BUGREPORT "\n"
340 exit(1);
343 static void version(void)
345 printf(
346 "VDE " PACKAGE_VERSION "\n"
347 "Copyright 2003,...,2011 Renzo Davoli\n"
348 "some code from uml_switch Copyright (C) 2001, 2002 Jeff Dike and others\n"
349 "VDE comes with NO WARRANTY, to the extent permitted by law.\n"
350 "You may redistribute copies of VDE under the terms of the\n"
351 "GNU General Public License v2.\n"
352 "For more information about these matters, see the files\n"
353 "named COPYING.\n");
354 exit(0);
357 static struct option *optcpy(struct option *tgt, struct option *src, int n, int tag)
359 register int i;
360 memcpy(tgt,src,sizeof(struct option) * n);
361 for (i=0;i<n;i++) {
362 tgt[i].val=(tgt[i].val & 0xffff) | tag << 16;
364 return tgt+n;
367 static int parse_globopt(int c, char *optarg)
369 int outc=0;
370 switch (c) {
371 case 'x':
372 /* if it is a HUB FST is disabled */
373 #ifdef FSTP
374 fstflag(P_CLRFLAG,FSTP_TAG);
375 #endif
376 portflag(P_SETFLAG,HUB_TAG);
377 break;
378 case HASH_TABLE_SIZE_ARG:
379 sscanf(optarg,"%i",&hash_size);
380 break;
381 #ifdef FSTP
382 case 'F':
383 if (!portflag(P_GETFLAG,HUB_TAG))
384 fstflag(P_SETFLAG,FSTP_TAG);
385 break;
386 case PRIORITY_ARG:
387 sscanf(optarg,"%i",&priority);
388 priority &= 0xffff;
389 break;
390 #endif
391 case MACADDR_ARG:
392 {int maci[ETH_ALEN],rv;
393 if (index(optarg,':') != NULL)
394 rv=sscanf(optarg,"%x:%x:%x:%x:%x:%x", maci+0, maci+1, maci+2, maci+3, maci+4, maci+5);
395 else
396 rv=sscanf(optarg,"%x.%x.%x.%x.%x.%x", maci+0, maci+1, maci+2, maci+3, maci+4, maci+5);
397 if (rv != 6) {
398 printlog(LOG_ERR,"Invalid MAC Addr %s",optarg);
399 Usage();
401 else {
402 register int i;
403 for (i=0;i<ETH_ALEN;i++)
404 switchmac[i]=maci[i];
407 break;
408 case 'n':
409 sscanf(optarg,"%i",&numports);
410 break;
411 case 'v':
412 version();
413 break;
414 case 'h':
415 Usage();
416 break;
417 default:
418 outc=c;
420 return outc;
423 static void parse_args(int argc, char **argv)
425 struct swmodule *swmp;
426 struct option *long_options;
427 char *optstring;
428 static struct option global_options[] = {
429 {"help",0 , 0, 'h'},
430 {"hub", 0, 0, 'x'},
431 #ifdef FSTP
432 {"fstp",0 , 0, 'F'},
433 #endif
434 {"version", 0, 0, 'v'},
435 {"numports", 1, 0, 'n'},
436 {"hashsize", 1, 0, HASH_TABLE_SIZE_ARG},
437 {"macaddr", 1, 0, MACADDR_ARG},
438 #ifdef FSTP
439 {"priority", 1, 0, PRIORITY_ARG}
440 #endif
442 static struct option optail = {0,0,0,0};
443 #define N_global_options (sizeof(global_options)/sizeof(struct option))
444 prog = argv[0];
445 int totopts=N_global_options+1;
447 for(swmp=swmh;swmp != NULL;swmp=swmp->next)
448 totopts += swmp->swmnopts;
449 long_options=malloc(totopts * sizeof(struct option));
450 optstring=malloc(2 * totopts * sizeof(char));
451 if (long_options == NULL || optstring==NULL)
452 exit(2);
453 { /* fill-in the long_options fields */
454 register int i;
455 char *os=optstring;
456 char last=0;
457 struct option *opp=long_options;
458 opp=optcpy(opp,global_options,N_global_options,0);
459 for(swmp=swmh;swmp != NULL;swmp=swmp->next)
460 opp=optcpy(opp,swmp->swmopts,swmp->swmnopts,swmp->swmtag);
461 optcpy(opp,&optail,1,0);
462 for (i=0;i<totopts-1;i++)
464 int val=long_options[i].val & 0xffff;
465 if(val > ' ' && val <= '~' && val != last)
467 *os++=val;
468 if(long_options[i].has_arg) *os++=':';
471 *os=0;
474 /* Parse args */
475 int option_index = 0;
476 int c;
477 while (1) {
478 c = GETOPT_LONG (argc, argv, optstring,
479 long_options, &option_index);
480 if (c == -1)
481 break;
482 c=parse_globopt(c,optarg);
483 for(swmp=swmh;swmp != NULL && c!=0;swmp=swmp->next) {
484 if (swmp->parseopt != NULL) {
485 if((c >> 7) == 0)
486 c=swmp->parseopt(c,optarg);
487 else if ((c >> 16) == swmp->swmtag)
488 swmp->parseopt(c & 0xffff,optarg),c=0;
493 if(optind < argc)
494 Usage();
495 free(long_options);
496 free(optstring);
499 static void init_mods(void)
501 struct swmodule *swmp;
503 /* Keep track of the initial cwd */
504 int cwfd = open(".", O_RDONLY);
506 for(swmp=swmh;swmp != NULL;swmp=swmp->next)
507 if (swmp->init != NULL)
509 swmp->init();
510 if (cwfd >= 0)
511 /* Restore cwd so each module will be initialized with the
512 * original cwd also if the previous one changed it. */
513 fchdir(cwfd);
516 close(cwfd);
519 static void cleanup(void)
521 struct swmodule *swmp;
522 file_cleanup();
523 for(swmp=swmh;swmp != NULL;swmp=swmp->next)
524 if (swmp->cleanup != NULL)
525 swmp->cleanup(0,-1,NULL);
528 static void sig_handler(int sig)
530 printlog(LOG_ERR,"Caught signal %d, cleaning up and exiting", sig);
531 cleanup();
532 signal(sig, SIG_DFL);
533 if (sig == SIGTERM)
534 _exit(0);
535 else
536 kill(getpid(), sig);
539 static void setsighandlers()
541 /* setting signal handlers.
542 * sets clean termination for SIGHUP, SIGINT and SIGTERM, and simply
543 * ignores all the others signals which could cause termination. */
544 struct { int sig; const char *name; int ignore; } signals[] = {
545 { SIGHUP, "SIGHUP", 0 },
546 { SIGINT, "SIGINT", 0 },
547 { SIGPIPE, "SIGPIPE", 1 },
548 { SIGALRM, "SIGALRM", 1 },
549 { SIGTERM, "SIGTERM", 0 },
550 { SIGUSR1, "SIGUSR1", 1 },
551 { SIGUSR2, "SIGUSR2", 1 },
552 { SIGPROF, "SIGPROF", 1 },
553 { SIGVTALRM, "SIGVTALRM", 1 },
554 #ifdef VDE_LINUX
555 { SIGPOLL, "SIGPOLL", 1 },
556 #ifdef SIGSTKFLT
557 { SIGSTKFLT, "SIGSTKFLT", 1 },
558 #endif
559 { SIGIO, "SIGIO", 1 },
560 { SIGPWR, "SIGPWR", 1 },
561 #ifdef SIGUNUSED
562 { SIGUNUSED, "SIGUNUSED", 1 },
563 #endif
564 #endif
565 #ifdef VDE_DARWIN
566 { SIGXCPU, "SIGXCPU", 1 },
567 { SIGXFSZ, "SIGXFSZ", 1 },
568 #endif
569 { 0, NULL, 0 }
572 int i;
573 for(i = 0; signals[i].sig != 0; i++)
574 if(signal(signals[i].sig,
575 signals[i].ignore ? SIG_IGN : sig_handler) < 0)
576 printlog(LOG_ERR,"Setting handler for %s: %s", signals[i].name,
577 strerror(errno));
580 void set_switchmac()
582 struct timeval v;
583 long val;
584 register int i;
585 gettimeofday(&v,NULL);
586 srand48(v.tv_sec ^ v.tv_usec ^ getpid());
587 for(i=0,val=lrand48();i<4; i++,val>>=8)
588 switchmac[i+2]=val;
589 switchmac[0]=0;
590 switchmac[1]=0xff;
593 static void start_modules(void);
595 int main(int argc, char **argv)
597 set_switchmac();
598 setsighandlers();
599 start_modules();
600 parse_args(argc,argv);
601 atexit(cleanup);
602 hash_init(hash_size);
603 #ifdef FSTP
604 fst_init(numports);
605 #endif
606 port_init(numports);
607 init_mods();
608 loadrcfile();
609 qtimer_init();
610 main_loop();
611 return 0;
614 /* modules: module references are only here! */
615 static void start_modules(void)
617 void start_consmgmt(void);
618 void start_datasock(void);
619 void start_tuntap(void);
620 start_datasock();
621 start_consmgmt();
622 #ifdef HAVE_TUNTAP
623 start_tuntap();
624 #endif