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
17 #include <sys/types.h>
33 #include <vdecommon.h>
37 static struct swmodule
*swmh
;
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
;
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) {
66 static void recdelswm(struct swmodule
**p
,struct swmodule
*old
)
68 struct swmodule
*this=*p
;
73 recdelswm(&(this->next
),old
);
77 void del_swm(struct swmodule
*old
)
91 #define MAXFDS_INITIAL 8
92 #define MAXFDS_STEP 16
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
;
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
)
119 if(ntypes
==maxtypes
) {
120 maxtypes
= maxtypes
? 2 * maxtypes
: 8;
121 if (maxtypes
> PRIOFLAG
) {
122 printlog(LOG_ERR
,"too many file types");
125 if((fdtypes
= realloc(fdtypes
, maxtypes
* sizeof(struct swmodule
*))) == NULL
){
126 printlog(LOG_ERR
,"realloc fdtypes %s",strerror(errno
));
129 memset(fdtypes
+ntypes
,0,sizeof(struct swmodule
*) * maxtypes
-ntypes
);
132 for(i
=0; fdtypes
[i
] != NULL
; i
++)
136 return i
| ((prio
!= 0)?PRIOFLAG
:0);
139 void del_type(unsigned char type
)
147 void add_fd(int fd
,unsigned char type
,void *private_data
)
151 /* enlarge fds and fdpp array if needed */
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
));
158 if((fdpp
= realloc(fdpp
, maxfds
* sizeof(struct pollplus
*))) == NULL
){
159 printlog(LOG_ERR
,"realloc pollplus %s",strerror(errno
));
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
));
171 fds
[nfds
]=fds
[nprio
];
172 fdpp
[nfds
]=fdpp
[nprio
];
177 if((fdpp
[index
]=malloc(sizeof(struct pollplus
))) == NULL
) {
178 printlog(LOG_ERR
,"realloc pollplus elem %s",strerror(errno
));
184 p
->events
= POLLIN
| POLLHUP
;
185 fdpp
[index
]->type
=type
;
186 fdpp
[index
]->private_data
=private_data
;
187 fdpp
[index
]->timestamp
=0;
191 static void file_cleanup(void)
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
)
202 for(i
= 0; i
< nfds
; i
++){
203 if(fds
[i
].fd
== fd
) break;
206 printlog(LOG_WARNING
,"remove_fd : Couldn't find descriptor %d", fd
);
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
*));
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
);
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
);
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
);
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
);
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
);
264 fds
[fdperm
[fd
]].events
= events
;
267 static void main_loop()
276 printlog(LOG_WARNING
,"poll %s",strerror(errno
));
278 for(i
= 0; /*i < nfds &&*/ n
>0; i
++){
279 if(fds
[i
].revents
!= 0) {
280 register int prenfds
=nfds
;
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 */
291 if (i
< nfds
&& i
> 0 && i
!= nprio
) {
292 register int i_1
=i
-1;
293 if (fdpp
[i
]->timestamp
> fdpp
[i_1
]->timestamp
) {
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
;
299 fdperm
[fds
[i_1
].fd
]=i_1
;
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) {
317 "Usage: vde_switch [OPTIONS]\n"
318 "Runs a VDE switch.\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"
325 " -F, --fstp Activate the fast spanning tree protocol\n"
327 " --macaddr MAC Set the Switch MAC address\n"
329 " --priority N Set the priority for FST (MAC extension)\n"
331 " --hashsize N Hash table size\n"
333 for(p
=swmh
;p
!= NULL
;p
=p
->next
)
334 if (p
->usage
!= NULL
)
338 "Report bugs to "PACKAGE_BUGREPORT
"\n"
343 static void version(void)
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"
357 static struct option
*optcpy(struct option
*tgt
, struct option
*src
, int n
, int tag
)
360 memcpy(tgt
,src
,sizeof(struct option
) * n
);
362 tgt
[i
].val
=(tgt
[i
].val
& 0xffff) | tag
<< 16;
367 static int parse_globopt(int c
, char *optarg
)
372 /* if it is a HUB FST is disabled */
374 fstflag(P_CLRFLAG
,FSTP_TAG
);
376 portflag(P_SETFLAG
,HUB_TAG
);
378 case HASH_TABLE_SIZE_ARG
:
379 sscanf(optarg
,"%i",&hash_size
);
383 if (!portflag(P_GETFLAG
,HUB_TAG
))
384 fstflag(P_SETFLAG
,FSTP_TAG
);
387 sscanf(optarg
,"%i",&priority
);
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);
396 rv
=sscanf(optarg
,"%x.%x.%x.%x.%x.%x", maci
+0, maci
+1, maci
+2, maci
+3, maci
+4, maci
+5);
398 printlog(LOG_ERR
,"Invalid MAC Addr %s",optarg
);
403 for (i
=0;i
<ETH_ALEN
;i
++)
404 switchmac
[i
]=maci
[i
];
409 sscanf(optarg
,"%i",&numports
);
423 static void parse_args(int argc
, char **argv
)
425 struct swmodule
*swmp
;
426 struct option
*long_options
;
428 static struct option global_options
[] = {
434 {"version", 0, 0, 'v'},
435 {"numports", 1, 0, 'n'},
436 {"hashsize", 1, 0, HASH_TABLE_SIZE_ARG
},
437 {"macaddr", 1, 0, MACADDR_ARG
},
439 {"priority", 1, 0, PRIORITY_ARG
}
442 static struct option optail
= {0,0,0,0};
443 #define N_global_options (sizeof(global_options)/sizeof(struct option))
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
)
453 { /* fill-in the long_options fields */
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
)
468 if(long_options
[i
].has_arg
) *os
++=':';
475 int option_index
= 0;
478 c
= GETOPT_LONG (argc
, argv
, optstring
,
479 long_options
, &option_index
);
482 c
=parse_globopt(c
,optarg
);
483 for(swmp
=swmh
;swmp
!= NULL
&& c
!=0;swmp
=swmp
->next
) {
484 if (swmp
->parseopt
!= NULL
) {
486 c
=swmp
->parseopt(c
,optarg
);
487 else if ((c
>> 16) == swmp
->swmtag
)
488 swmp
->parseopt(c
& 0xffff,optarg
),c
=0;
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
)
511 /* Restore cwd so each module will be initialized with the
512 * original cwd also if the previous one changed it. */
519 static void cleanup(void)
521 struct swmodule
*swmp
;
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
);
532 signal(sig
, SIG_DFL
);
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 },
555 { SIGPOLL
, "SIGPOLL", 1 },
557 { SIGSTKFLT
, "SIGSTKFLT", 1 },
559 { SIGIO
, "SIGIO", 1 },
560 { SIGPWR
, "SIGPWR", 1 },
562 { SIGUNUSED
, "SIGUNUSED", 1 },
566 { SIGXCPU
, "SIGXCPU", 1 },
567 { SIGXFSZ
, "SIGXFSZ", 1 },
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
,
585 gettimeofday(&v
,NULL
);
586 srand48(v
.tv_sec
^ v
.tv_usec
^ getpid());
587 for(i
=0,val
=lrand48();i
<4; i
++,val
>>=8)
593 static void start_modules(void);
595 int main(int argc
, char **argv
)
600 parse_args(argc
,argv
);
602 hash_init(hash_size
);
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);