In 2014, I think we can stop trying to outsmart the compiler. Remove
[vde.git] / vde-2 / src / kvde_switch / kvde_switch.c
blobda4ee11e5537d156d0c6fcf7ffd0aceb5eaf1efb
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 <sys/types.h>
18 #include <sys/stat.h>
19 #include <fcntl.h>
20 #include <sys/time.h>
21 #include <time.h>
23 #include <config.h>
24 #include <vde.h>
25 #include <vdecommon.h>
27 #include "../vde_switch/switch.h"
28 #include "consmgmt.h"
29 #include "datasock.h"
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 void *private_data;
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 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,void *private_data)
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]->private_data=private_data;
166 nfds++;
169 static void file_cleanup(void)
171 int i;
172 for(i = 0; i < nfds; i++)
173 TYPE2MGR(fdpp[i]->type)->cleanup(fdpp[i]->type,fds[i].fd,fdpp[i]->private_data);
176 void remove_fd(int fd)
178 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]->private_data);
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 int n,i;
200 while(1) {
201 n=poll(fds,nfds,-1);
202 now=time(NULL);
203 if(n < 0){
204 if(errno != EINTR)
205 printlog(LOG_WARNING,"poll %s",strerror(errno));
206 } else {
207 for(i = 0; /*i < nfds &&*/ n>0; i++){
208 if(fds[i].revents != 0) {
209 int prenfds=nfds;
210 n--;
211 fdpp[i]->timestamp=now;
212 TYPE2MGR(fdpp[i]->type)->handle_io(fdpp[i]->type,fds[i].fd,fds[i].revents,fdpp[i]->private_data);
213 if (nfds!=prenfds) /* the current fd has been deleted */
214 break; /* PERFORMANCE it is faster returning to poll */
216 /* optimization: most used descriptors migrate to the head of the poll array */
222 /* starting/ending routines, main_loop, main*/
223 #define HASH_TABLE_SIZE_ARG 0x100
224 #define MACADDR_ARG 0x101
225 #define PRIORITY_ARG 0x102
227 static void Usage(void) {
228 struct swmodule *p;
229 printf(
230 "Usage: vde_switch [OPTIONS]\n"
231 "Runs a VDE switch.\n"
232 "(global opts)\n"
233 " -h, --help Display this help and exit\n"
234 " -v, --version Display informations on version and exit\n"
236 for(p=swmh;p != NULL;p=p->next)
237 if (p->usage != NULL)
238 p->usage();
239 printf(
240 "\n"
241 "Report bugs to "PACKAGE_BUGREPORT "\n"
243 exit(1);
246 static void version(void)
248 printf(
249 "VDE " PACKAGE_VERSION "\n"
250 "Copyright 2003,2004,2005,2006,2007,2008 Renzo Davoli\n"
251 "VDE comes with NO WARRANTY, to the extent permitted by law.\n"
252 "You may redistribute copies of VDE under the terms of the\n"
253 "GNU General Public License v2.\n"
254 "For more information about these matters, see the files\n"
255 "named COPYING.\n");
256 exit(check_kernel_support());
259 static struct option *optcpy(struct option *tgt, struct option *src, int n, int tag)
261 int i;
262 memcpy(tgt,src,sizeof(struct option) * n);
263 for (i=0;i<n;i++) {
264 tgt[i].val=(tgt[i].val & 0xffff) | tag << 16;
266 return tgt+n;
269 static int parse_globopt(int c, char *optarg)
271 int outc=0;
272 switch (c) {
273 case 'v':
274 version();
275 break;
276 case 'h':
277 Usage();
278 break;
279 default:
280 outc=c;
282 return outc;
285 static void parse_args(int argc, char **argv)
287 struct swmodule *swmp;
288 struct option *long_options;
289 char *optstring;
290 static struct option global_options[] = {
291 {"help",0 , 0, 'h'},
292 {"version", 0, 0, 'v'},
294 static struct option optail = {0,0,0,0};
295 #define N_global_options (sizeof(global_options)/sizeof(struct option))
296 prog = argv[0];
297 int totopts=N_global_options+1;
299 for(swmp=swmh;swmp != NULL;swmp=swmp->next)
300 totopts += swmp->swmnopts;
301 long_options=malloc(totopts * sizeof(struct option));
302 optstring=malloc(2 * totopts * sizeof(char));
303 if (long_options == NULL || optstring==NULL)
304 exit(2);
305 { /* fill-in the long_options fields */
306 int i;
307 char *os=optstring;
308 char last=0;
309 struct option *opp=long_options;
310 opp=optcpy(opp,global_options,N_global_options,0);
311 for(swmp=swmh;swmp != NULL;swmp=swmp->next)
312 opp=optcpy(opp,swmp->swmopts,swmp->swmnopts,swmp->swmtag);
313 optcpy(opp,&optail,1,0);
314 for (i=0;i<totopts-1;i++)
316 int val=long_options[i].val & 0xffff;
317 if(val > ' ' && val <= '~' && val != last)
319 *os++=val;
320 if(long_options[i].has_arg) *os++=':';
323 *os=0;
326 /* Parse args */
327 int option_index = 0;
328 int c;
329 while (1) {
330 c = GETOPT_LONG (argc, argv, optstring,
331 long_options, &option_index);
332 if (c == -1)
333 break;
334 c=parse_globopt(c,optarg);
335 for(swmp=swmh;swmp != NULL && c!=0;swmp=swmp->next) {
336 if (swmp->parseopt != NULL) {
337 if((c >> 7) == 0)
338 c=swmp->parseopt(c,optarg);
339 else if ((c >> 16) == swmp->swmtag)
340 swmp->parseopt(c & 0xffff,optarg),c=0;
345 if(optind < argc)
346 Usage();
347 free(long_options);
348 free(optstring);
351 static void init_mods(void)
353 struct swmodule *swmp;
355 /* Keep track of the initial cwd */
356 int cwfd = open(".", O_RDONLY);
358 for(swmp=swmh;swmp != NULL;swmp=swmp->next)
359 if (swmp->init != NULL)
361 swmp->init();
362 if (cwfd >= 0)
363 /* Restore cwd so each module will be initialized with the
364 * original cwd also if the previous one changed it. */
365 if(fchdir(cwfd) < 0) {
366 printlog(LOG_WARNING,"Error restoring original working dir");
369 close(cwfd);
372 static void cleanup(void)
374 struct swmodule *swmp;
375 file_cleanup();
376 for(swmp=swmh;swmp != NULL;swmp=swmp->next)
377 if (swmp->cleanup != NULL)
378 swmp->cleanup(0,-1,NULL);
381 static void sig_handler(int sig)
383 printlog(LOG_ERR,"Caught signal %d, cleaning up and exiting", sig);
384 cleanup();
385 signal(sig, SIG_DFL);
386 if (sig == SIGTERM)
387 _exit(0);
388 else
389 kill(getpid(), sig);
392 static void setsighandlers()
394 /* setting signal handlers.
395 * sets clean termination for SIGHUP, SIGINT and SIGTERM, and simply
396 * ignores all the others signals which could cause termination. */
397 struct { int sig; const char *name; int ignore; } signals[] = {
398 { SIGHUP, "SIGHUP", 0 },
399 { SIGINT, "SIGINT", 0 },
400 { SIGPIPE, "SIGPIPE", 1 },
401 { SIGALRM, "SIGALRM", 1 },
402 { SIGTERM, "SIGTERM", 0 },
403 { SIGUSR1, "SIGUSR1", 1 },
404 { SIGUSR2, "SIGUSR2", 1 },
405 { SIGPROF, "SIGPROF", 1 },
406 { SIGVTALRM, "SIGVTALRM", 1 },
407 #ifdef VDE_LINUX
408 { SIGPOLL, "SIGPOLL", 1 },
409 #ifdef SIGSTKFLT
410 { SIGSTKFLT, "SIGSTKFLT", 1 },
411 #endif
412 { SIGIO, "SIGIO", 1 },
413 { SIGPWR, "SIGPWR", 1 },
414 #ifdef SIGUNUSED
415 { SIGUNUSED, "SIGUNUSED", 1 },
416 #endif
417 #endif
418 #ifdef VDE_DARWIN
419 { SIGXCPU, "SIGXCPU", 1 },
420 { SIGXFSZ, "SIGXFSZ", 1 },
421 #endif
422 { 0, NULL, 0 }
425 int i;
426 for(i = 0; signals[i].sig != 0; i++)
427 if(signal(signals[i].sig,
428 signals[i].ignore ? SIG_IGN : sig_handler) < 0)
429 printlog(LOG_ERR,"Setting handler for %s: %s", signals[i].name,
430 strerror(errno));
433 static void start_modules(void);
435 int main(int argc, char **argv)
437 starting_time=time(NULL);
438 start_modules();
439 parse_args(argc,argv);
440 atexit(cleanup);
441 setsighandlers();
442 init_mods();
443 loadrcfile();
444 main_loop();
445 return 0;
448 /* modules: module references are only here! */
449 static void start_modules(void)
451 void start_datasock(void);
452 void start_consmgmt(void);
453 start_datasock();
454 start_consmgmt();