- fixed poll emulation management
[vde.git] / vde-2 / kvde_switch / kvde_switch.c
blob4695c13252c6851b9fe5a37a8eff35b8b01d3762
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 <consmgmt.h>
21 #include <sys/time.h>
22 #include <time.h>
24 #include <vde.h>
25 #undef VDE_PQ
26 #undef OPTPOLL
27 #ifdef VDE_PQ
28 #include <packetq.h>
29 #endif
31 time_t starting_time;
32 static struct swmodule *swmh;
34 char *prog;
35 unsigned char switchmac[ETH_ALEN];
36 unsigned int priority=DEFAULT_PRIORITY;
38 static int hash_size=INIT_HASH_SIZE;
39 static int numports=INIT_NUMPORTS;
42 static void recaddswm(struct swmodule **p,struct swmodule *new)
44 struct swmodule *this=*p;
45 if (this == NULL)
46 *p=new;
47 else
48 recaddswm(&(this->next),new);
51 void add_swm(struct swmodule *new)
53 static int lastlwmtag;
54 new->swmtag= ++lastlwmtag;
55 if (new != NULL && new->swmtag != 0) {
56 new->next=NULL;
57 recaddswm(&swmh,new);
61 static void recdelswm(struct swmodule **p,struct swmodule *old)
63 struct swmodule *this=*p;
64 if (this != NULL) {
65 if(this == old)
66 *p=this->next;
67 else
68 recdelswm(&(this->next),old);
72 void del_swm(struct swmodule *old)
74 if (old != NULL) {
75 recdelswm(&swmh,old);
79 /* FD MGMT */
80 struct pollplus {
81 unsigned char type;
82 int arg;
83 time_t timestamp;
86 static int nfds = 0;
87 static int nprio =0;
88 static struct pollfd *fds = NULL;
89 static struct pollplus **fdpp = NULL;
91 static int maxfds = 0;
93 static struct swmodule **fdtypes;
94 static int ntypes;
95 static int maxtypes;
97 #define PRIOFLAG 0x80
98 #define TYPEMASK 0x7f
99 #define ISPRIO(X) ((X) & PRIOFLAG)
101 #define TYPE2MGR(X) (fdtypes[((X) & TYPEMASK)])
103 unsigned char add_type(struct swmodule *mgr,int prio)
105 register int i;
106 if(ntypes==maxtypes) {
107 maxtypes = maxtypes ? 2 * maxtypes : 8;
108 if (maxtypes > PRIOFLAG) {
109 printlog(LOG_ERR,"too many file types");
110 exit(1);
112 if((fdtypes = realloc(fdtypes, maxtypes * sizeof(struct swmodule *))) == NULL){
113 printlog(LOG_ERR,"realloc fdtypes %s",strerror(errno));
114 exit(1);
116 memset(fdtypes+ntypes,0,sizeof(struct swmodule *) * maxtypes-ntypes);
117 i=ntypes;
118 } else
119 for(i=0; fdtypes[i] != NULL; i++)
121 fdtypes[i]=mgr;
122 ntypes++;
123 return i | ((prio != 0)?PRIOFLAG:0);
126 void del_type(unsigned char type)
128 type &= TYPEMASK;
129 if (type < maxtypes)
130 fdtypes[type]=NULL;
131 ntypes--;
134 void add_fd(int fd,unsigned char type,int arg)
136 struct pollfd *p;
137 int index;
138 /* enlarge fds and g_fdsdata array if needed */
139 if(nfds == maxfds){
140 maxfds = maxfds ? 2 * maxfds : 8;
141 if((fds = realloc(fds, maxfds * sizeof(struct pollfd))) == NULL){
142 printlog(LOG_ERR,"realloc fds %s",strerror(errno));
143 exit(1);
145 if((fdpp = realloc(fdpp, maxfds * sizeof(struct pollplus *))) == NULL){
146 printlog(LOG_ERR,"realloc pollplus %s",strerror(errno));
147 exit(1);
150 if (ISPRIO(type)) {
151 fds[nfds]=fds[nprio];
152 fdpp[nfds]=fdpp[nprio];
153 index=nprio;
154 nprio++;
155 } else
156 index=nfds;
157 if((fdpp[index]=malloc(sizeof(struct pollplus))) == NULL) {
158 printlog(LOG_ERR,"realloc pollplus elem %s",strerror(errno));
159 exit(1);
161 p = &fds[index];
162 p->fd = fd;
163 p->events = POLLIN | POLLHUP;
164 fdpp[index]->type=type;
165 fdpp[index]->arg=arg;
166 nfds++;
169 static void file_cleanup(void)
171 register int i;
172 for(i = 0; i < nfds; i++)
173 TYPE2MGR(fdpp[i]->type)->cleanup(fdpp[i]->type,fds[i].fd,fdpp[i]->arg);
176 void remove_fd(int fd)
178 register int i;
180 for(i = 0; i < nfds; i++){
181 if(fds[i].fd == fd) break;
183 if(i == nfds){
184 printlog(LOG_WARNING,"remove_fd : Couldn't find descriptor %d", fd);
185 } else {
186 struct pollplus *old=fdpp[i];
187 TYPE2MGR(fdpp[i]->type)->cleanup(fdpp[i]->type,fds[i].fd,fdpp[i]->arg);
188 if (ISPRIO(fdpp[i]->type)) nprio--;
189 memmove(&fds[i], &fds[i + 1], (maxfds - i - 1) * sizeof(struct pollfd));
190 memmove(&fdpp[i], &fdpp[i + 1], (maxfds - i - 1) * sizeof(struct pollplus *));
191 free(old);
192 nfds--;
196 static void main_loop()
198 time_t now;
199 register int n,i;
200 while(1) {
201 #ifdef VDE_PQ
202 n=poll(fds,nfds,packetq_timeout);
203 #else
204 n=poll(fds,nfds,-1);
205 #endif
206 now=time(NULL);
207 if(n < 0){
208 if(errno != EINTR)
209 printlog(LOG_WARNING,"poll %s",strerror(errno));
210 } else {
211 for(i = 0; /*i < nfds &&*/ n>0; i++){
212 if(fds[i].revents != 0) {
213 register int prenfds=nfds;
214 n--;
215 fdpp[i]->timestamp=now;
216 TYPE2MGR(fdpp[i]->type)->handle_input(fdpp[i]->type,fds[i].fd,fds[i].revents,&(fdpp[i]->arg));
217 if (nfds!=prenfds) /* the current fd has been deleted */
218 break; /* PERFORMANCE it is faster returning to poll */
220 /* optimization: most used descriptors migrate to the head of the poll array */
221 #ifdef OPTPOLL
222 else
224 if (i < nfds && i > 0 && i != nprio) {
225 register int i_1=i-1;
226 if (fdpp[i]->timestamp > fdpp[i_1]->timestamp) {
227 struct pollfd tfds;
228 struct pollplus *tfdpp;
229 tfds=fds[i];fds[i]=fds[i_1];fds[i_1]=tfds;
230 tfdpp=fdpp[i];fdpp[i]=fdpp[i_1];fdpp[i_1]=tfdpp;
234 #endif
236 #ifdef VDE_PQ
237 if (packetq_timeout > 0)
238 packetq_try();
239 #endif
244 /* starting/ending routines, main_loop, main*/
245 #define HASH_TABLE_SIZE_ARG 0x100
246 #define MACADDR_ARG 0x101
247 #define PRIORITY_ARG 0x102
249 static void Usage(void) {
250 struct swmodule *p;
251 printf(
252 "Usage: vde_switch [OPTIONS]\n"
253 "Runs a VDE switch.\n"
254 "(global opts)\n"
255 " -h, --help Display this help and exit\n"
256 " -v, --version Display informations on version and exit\n"
258 for(p=swmh;p != NULL;p=p->next)
259 if (p->usage != NULL)
260 p->usage();
261 printf(
262 "\n"
263 "Report bugs to "PACKAGE_BUGREPORT "\n"
265 exit(1);
268 static void version(void)
270 printf(
271 "VDE " PACKAGE_VERSION "\n"
272 "Copyright 2003,2004,2005,2006,2007,2008 Renzo Davoli\n"
273 "VDE comes with NO WARRANTY, to the extent permitted by law.\n"
274 "You may redistribute copies of VDE under the terms of the\n"
275 "GNU General Public License v2.\n"
276 "For more information about these matters, see the files\n"
277 "named COPYING.\n");
278 exit(0);
281 static struct option *optcpy(struct option *tgt, struct option *src, int n, int tag)
283 register int i;
284 memcpy(tgt,src,sizeof(struct option) * n);
285 for (i=0;i<n;i++) {
286 tgt[i].val=(tgt[i].val & 0xffff) | tag << 16;
288 return tgt+n;
291 static int parse_globopt(int c, char *optarg)
293 int outc=0;
294 switch (c) {
295 case 'v':
296 version();
297 break;
298 case 'h':
299 Usage();
300 break;
301 default:
302 outc=c;
304 return outc;
307 static void parse_args(int argc, char **argv)
309 struct swmodule *swmp;
310 struct option *long_options;
311 char *optstring;
312 static struct option global_options[] = {
313 {"help",0 , 0, 'h'},
314 {"version", 0, 0, 'v'},
316 static struct option optail = {0,0,0,0};
317 #define N_global_options (sizeof(global_options)/sizeof(struct option))
318 prog = argv[0];
319 int totopts=N_global_options+1;
321 for(swmp=swmh;swmp != NULL;swmp=swmp->next)
322 totopts += swmp->swmnopts;
323 long_options=malloc(totopts * sizeof(struct option));
324 optstring=malloc(2 * totopts * sizeof(char));
325 if (long_options == NULL || optstring==NULL)
326 exit(2);
327 { /* fill-in the long_options fields */
328 register int i;
329 char *os=optstring;
330 char last=0;
331 struct option *opp=long_options;
332 opp=optcpy(opp,global_options,N_global_options,0);
333 for(swmp=swmh;swmp != NULL;swmp=swmp->next)
334 opp=optcpy(opp,swmp->swmopts,swmp->swmnopts,swmp->swmtag);
335 optcpy(opp,&optail,1,0);
336 for (i=0;i<totopts-1;i++)
338 int val=long_options[i].val & 0xffff;
339 if(val > ' ' && val <= '~' && val != last)
341 *os++=val;
342 if(long_options[i].has_arg) *os++=':';
345 *os=0;
348 /* Parse args */
349 int option_index = 0;
350 int c;
351 while (1) {
352 c = GETOPT_LONG (argc, argv, optstring,
353 long_options, &option_index);
354 if (c == -1)
355 break;
356 c=parse_globopt(c,optarg);
357 for(swmp=swmh;swmp != NULL && c!=0;swmp=swmp->next) {
358 if (swmp->parseopt != NULL) {
359 if((c >> 7) == 0)
360 c=swmp->parseopt(c,optarg);
361 else if ((c >> 16) == swmp->swmtag)
362 swmp->parseopt(c & 0xffff,optarg),c=0;
367 if(optind < argc)
368 Usage();
369 free(long_options);
370 free(optstring);
373 static void init_mods(void)
375 struct swmodule *swmp;
376 for(swmp=swmh;swmp != NULL;swmp=swmp->next)
377 if (swmp->init != NULL)
378 swmp->init();
381 static void cleanup(void)
383 struct swmodule *swmp;
384 file_cleanup();
385 for(swmp=swmh;swmp != NULL;swmp=swmp->next)
386 if (swmp->cleanup != NULL)
387 swmp->cleanup(0,-1,-1);
390 static void sig_handler(int sig)
392 printlog(LOG_ERR,"Caught signal %d, cleaning up and exiting", sig);
393 cleanup();
394 signal(sig, SIG_DFL);
395 kill(getpid(), sig);
398 static void setsighandlers()
400 /* setting signal handlers.
401 * sets clean termination for SIGHUP, SIGINT and SIGTERM, and simply
402 * ignores all the others signals which could cause termination. */
403 struct { int sig; const char *name; int ignore; } signals[] = {
404 { SIGHUP, "SIGHUP", 0 },
405 { SIGINT, "SIGINT", 0 },
406 { SIGPIPE, "SIGPIPE", 1 },
407 { SIGALRM, "SIGALRM", 1 },
408 { SIGTERM, "SIGTERM", 0 },
409 { SIGUSR1, "SIGUSR1", 1 },
410 { SIGUSR2, "SIGUSR2", 1 },
411 { SIGPROF, "SIGPROF", 1 },
412 { SIGVTALRM, "SIGVTALRM", 1 },
413 #ifdef VDE_LINUX
414 { SIGPOLL, "SIGPOLL", 1 },
415 #ifdef SIGSTKFLT
416 { SIGSTKFLT, "SIGSTKFLT", 1 },
417 #endif
418 { SIGIO, "SIGIO", 1 },
419 { SIGPWR, "SIGPWR", 1 },
420 #ifdef SIGUNUSED
421 { SIGUNUSED, "SIGUNUSED", 1 },
422 #endif
423 #endif
424 #ifdef VDE_DARWIN
425 { SIGXCPU, "SIGXCPU", 1 },
426 { SIGXFSZ, "SIGXFSZ", 1 },
427 #endif
428 { 0, NULL, 0 }
431 int i;
432 for(i = 0; signals[i].sig != 0; i++)
433 if(signal(signals[i].sig,
434 signals[i].ignore ? SIG_IGN : sig_handler) < 0)
435 printlog(LOG_ERR,"Setting handler for %s: %s", signals[i].name,
436 strerror(errno));
439 static void start_modules(void);
441 int main(int argc, char **argv)
443 starting_time=time(NULL);
444 start_modules();
445 parse_args(argc,argv);
446 atexit(cleanup);
447 setsighandlers();
448 init_mods();
449 loadrcfile();
450 main_loop();
451 return 0;
454 /* modules: module references are only here! */
455 static void start_modules(void)
457 void start_datasock(void);
458 void start_consmgmt(void);
459 start_datasock();
460 start_consmgmt();