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 #ifndef HAVE_BROKEN_POLL
37 #ifdef HAVE_BROKEN_POLL
38 #include "poll2select.h"
39 #define poll poll2select
42 static struct swmodule
*swmh
;
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
;
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) {
71 static void recdelswm(struct swmodule
**p
,struct swmodule
*old
)
73 struct swmodule
*this=*p
;
78 recdelswm(&(this->next
),old
);
82 void del_swm(struct swmodule
*old
)
98 static struct pollfd
*fds
= NULL
;
99 static struct pollplus
**fdpp
= NULL
;
101 static int maxfds
= 0;
103 static struct swmodule
**fdtypes
;
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
)
116 if(ntypes
==maxtypes
) {
117 maxtypes
= maxtypes
? 2 * maxtypes
: 8;
118 if (maxtypes
> PRIOFLAG
) {
119 printlog(LOG_ERR
,"too many file types");
122 if((fdtypes
= realloc(fdtypes
, maxtypes
* sizeof(struct swmodule
*))) == NULL
){
123 printlog(LOG_ERR
,"realloc fdtypes %s",strerror(errno
));
126 memset(fdtypes
+ntypes
,0,sizeof(struct swmodule
*) * maxtypes
-ntypes
);
129 for(i
=0; fdtypes
[i
] != NULL
; i
++)
133 return i
| ((prio
!= 0)?PRIOFLAG
:0);
136 void del_type(unsigned char type
)
144 void add_fd(int fd
,unsigned char type
,int arg
)
148 /* enlarge fds and g_fdsdata array if needed */
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
));
155 if((fdpp
= realloc(fdpp
, maxfds
* sizeof(struct pollplus
*))) == NULL
){
156 printlog(LOG_ERR
,"realloc pollplus %s",strerror(errno
));
161 fds
[nfds
]=fds
[nprio
];
162 fdpp
[nfds
]=fdpp
[nprio
];
167 if((fdpp
[index
]=malloc(sizeof(struct pollplus
))) == NULL
) {
168 printlog(LOG_ERR
,"realloc pollplus elem %s",strerror(errno
));
173 p
->events
= POLLIN
| POLLHUP
;
174 fdpp
[index
]->type
=type
;
175 fdpp
[index
]->arg
=arg
;
179 static void file_cleanup(void)
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
)
190 for(i
= 0; i
< nfds
; i
++){
191 if(fds
[i
].fd
== fd
) break;
194 printlog(LOG_WARNING
,"remove_fd : Couldn't find descriptor %d", fd
);
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 pollfd
*));
207 static void main_loop()
213 n
=poll(fds
,nfds
,packetq_timeout
);
220 printlog(LOG_WARNING
,"poll %s",strerror(errno
));
222 for(i
= 0; /*i < nfds &&*/ n
>0; i
++){
223 if(fds
[i
].revents
!= 0) {
224 register int prenfds
=nfds
;
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 */
235 if (i
< nfds
&& i
> 0 && i
!= nprio
) {
236 register int i_1
=i
-1;
237 if (fdpp
[i
]->timestamp
> fdpp
[i_1
]->timestamp
) {
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
;
248 if (packetq_timeout
> 0)
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) {
263 "Usage: vde_switch [OPTIONS]\n"
264 "Runs a VDE switch.\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"
271 " -F, --fstp Activate the fast spanning tree protocol\n"
273 " --macaddr MAC Set the Switch MAC address\n"
275 " --priority N Set the priority for FST (MAC extension)\n"
277 " --hashsize N Hash table size\n"
279 for(p
=swmh
;p
!= NULL
;p
=p
->next
)
280 if (p
->usage
!= NULL
)
284 "Report bugs to "PACKAGE_BUGREPORT
"\n"
289 static void version(void)
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"
303 static struct option
*optcpy(struct option
*tgt
, struct option
*src
, int n
, int tag
)
306 memcpy(tgt
,src
,sizeof(struct option
) * n
);
308 tgt
[i
].val
=(tgt
[i
].val
& 0xffff) | tag
<< 16;
313 static int parse_globopt(int c
, char *optarg
)
318 portflag(P_SETFLAG
,HUB_TAG
);
320 case HASH_TABLE_SIZE_ARG
:
321 sscanf(optarg
,"%i",&hash_size
);
325 fstflag(P_SETFLAG
,FSTP_TAG
);
328 sscanf(optarg
,"%i",&priority
);
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);
337 rv
=sscanf(optarg
,"%x.%x.%x.%x.%x.%x", maci
+0, maci
+1, maci
+2, maci
+3, maci
+4, maci
+5);
339 printlog(LOG_ERR
,"Invalid MAC Addr %s",optarg
);
344 for (i
=0;i
<ETH_ALEN
;i
++)
345 switchmac
[i
]=maci
[i
];
350 sscanf(optarg
,"%i",&numports
);
364 static void parse_args(int argc
, char **argv
)
366 struct swmodule
*swmp
;
367 struct option
*long_options
;
369 static struct option global_options
[] = {
375 {"version", 0, 0, 'v'},
376 {"numports", 1, 0, 'n'},
377 {"hashsize", 1, 0, HASH_TABLE_SIZE_ARG
},
378 {"macaddr", 1, 0, MACADDR_ARG
},
380 {"priority", 1, 0, PRIORITY_ARG
}
383 static struct option optail
= {0,0,0,0};
384 #define N_global_options (sizeof(global_options)/sizeof(struct option))
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
)
394 { /* fill-in the long_options fields */
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
)
409 if(long_options
[i
].has_arg
) *os
++=':';
416 int option_index
= 0;
419 c
= GETOPT_LONG (argc
, argv
, optstring
,
420 long_options
, &option_index
);
423 c
=parse_globopt(c
,optarg
);
424 for(swmp
=swmh
;swmp
!= NULL
&& c
!=0;swmp
=swmp
->next
) {
425 if (swmp
->parseopt
!= NULL
) {
427 c
=swmp
->parseopt(c
,optarg
);
428 else if ((c
>> 16) == swmp
->swmtag
)
429 swmp
->parseopt(c
& 0xffff,optarg
),c
=0;
440 static void init_mods(void)
442 struct swmodule
*swmp
;
443 for(swmp
=swmh
;swmp
!= NULL
;swmp
=swmp
->next
)
444 if (swmp
->init
!= NULL
)
448 static void cleanup(void)
450 struct swmodule
*swmp
;
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
);
461 signal(sig
, SIG_DFL
);
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 },
481 { SIGPOLL
, "SIGPOLL", 1 },
482 { SIGSTKFLT
, "SIGSTKFLT", 1 },
483 { SIGIO
, "SIGIO", 1 },
484 { SIGPWR
, "SIGPWR", 1 },
485 { SIGUNUSED
, "SIGUNUSED", 1 },
488 { SIGXCPU
, "SIGXCPU", 1 },
489 { SIGXFSZ
, "SIGXFSZ", 1 },
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
,
507 gettimeofday(&v
,NULL
);
508 srand48(v
.tv_sec
^ v
.tv_usec
^ getpid());
509 for(i
=0,val
=lrand48();i
<4; i
++,val
>>=8)
515 static void start_modules(void);
517 int main(int argc
, char **argv
)
521 parse_args(argc
,argv
);
524 hash_init(hash_size
);
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);