Clean exit (exit status==0) when vde commands receive SIGTERM
[vde.git] / vde-2 / src / kvde_switch / kvde_switch.c
blob6d36933edba1760f32d2cf7486c712754cdf450f
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"
30 #undef VDE_PQ
31 #undef OPTPOLL
32 #ifdef VDE_PQ
33 #include <packetq.h>
34 #endif
36 time_t starting_time;
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 int arg;
88 time_t timestamp;
91 static int nfds = 0;
92 static int nprio =0;
93 static struct pollfd *fds = NULL;
94 static struct pollplus **fdpp = NULL;
96 static int maxfds = 0;
98 static struct swmodule **fdtypes;
99 static int ntypes;
100 static int maxtypes;
102 #define PRIOFLAG 0x80
103 #define TYPEMASK 0x7f
104 #define ISPRIO(X) ((X) & PRIOFLAG)
106 #define TYPE2MGR(X) (fdtypes[((X) & TYPEMASK)])
108 unsigned char add_type(struct swmodule *mgr,int prio)
110 register int i;
111 if(ntypes==maxtypes) {
112 maxtypes = maxtypes ? 2 * maxtypes : 8;
113 if (maxtypes > PRIOFLAG) {
114 printlog(LOG_ERR,"too many file types");
115 exit(1);
117 if((fdtypes = realloc(fdtypes, maxtypes * sizeof(struct swmodule *))) == NULL){
118 printlog(LOG_ERR,"realloc fdtypes %s",strerror(errno));
119 exit(1);
121 memset(fdtypes+ntypes,0,sizeof(struct swmodule *) * maxtypes-ntypes);
122 i=ntypes;
123 } else
124 for(i=0; fdtypes[i] != NULL; i++)
126 fdtypes[i]=mgr;
127 ntypes++;
128 return i | ((prio != 0)?PRIOFLAG:0);
131 void del_type(unsigned char type)
133 type &= TYPEMASK;
134 if (type < maxtypes)
135 fdtypes[type]=NULL;
136 ntypes--;
139 void add_fd(int fd,unsigned char type,int arg)
141 struct pollfd *p;
142 int index;
143 /* enlarge fds and g_fdsdata array if needed */
144 if(nfds == maxfds){
145 maxfds = maxfds ? 2 * maxfds : 8;
146 if((fds = realloc(fds, maxfds * sizeof(struct pollfd))) == NULL){
147 printlog(LOG_ERR,"realloc fds %s",strerror(errno));
148 exit(1);
150 if((fdpp = realloc(fdpp, maxfds * sizeof(struct pollplus *))) == NULL){
151 printlog(LOG_ERR,"realloc pollplus %s",strerror(errno));
152 exit(1);
155 if (ISPRIO(type)) {
156 fds[nfds]=fds[nprio];
157 fdpp[nfds]=fdpp[nprio];
158 index=nprio;
159 nprio++;
160 } else
161 index=nfds;
162 if((fdpp[index]=malloc(sizeof(struct pollplus))) == NULL) {
163 printlog(LOG_ERR,"realloc pollplus elem %s",strerror(errno));
164 exit(1);
166 p = &fds[index];
167 p->fd = fd;
168 p->events = POLLIN | POLLHUP;
169 fdpp[index]->type=type;
170 fdpp[index]->arg=arg;
171 nfds++;
174 static void file_cleanup(void)
176 register int i;
177 for(i = 0; i < nfds; i++)
178 TYPE2MGR(fdpp[i]->type)->cleanup(fdpp[i]->type,fds[i].fd,fdpp[i]->arg);
181 void remove_fd(int fd)
183 register int i;
185 for(i = 0; i < nfds; i++){
186 if(fds[i].fd == fd) break;
188 if(i == nfds){
189 printlog(LOG_WARNING,"remove_fd : Couldn't find descriptor %d", fd);
190 } else {
191 struct pollplus *old=fdpp[i];
192 TYPE2MGR(fdpp[i]->type)->cleanup(fdpp[i]->type,fds[i].fd,fdpp[i]->arg);
193 if (ISPRIO(fdpp[i]->type)) nprio--;
194 memmove(&fds[i], &fds[i + 1], (maxfds - i - 1) * sizeof(struct pollfd));
195 memmove(&fdpp[i], &fdpp[i + 1], (maxfds - i - 1) * sizeof(struct pollplus *));
196 free(old);
197 nfds--;
201 static void main_loop()
203 time_t now;
204 register int n,i;
205 while(1) {
206 #ifdef VDE_PQ
207 n=poll(fds,nfds,packetq_timeout);
208 #else
209 n=poll(fds,nfds,-1);
210 #endif
211 now=time(NULL);
212 if(n < 0){
213 if(errno != EINTR)
214 printlog(LOG_WARNING,"poll %s",strerror(errno));
215 } else {
216 for(i = 0; /*i < nfds &&*/ n>0; i++){
217 if(fds[i].revents != 0) {
218 register int prenfds=nfds;
219 n--;
220 fdpp[i]->timestamp=now;
221 TYPE2MGR(fdpp[i]->type)->handle_input(fdpp[i]->type,fds[i].fd,fds[i].revents,&(fdpp[i]->arg));
222 if (nfds!=prenfds) /* the current fd has been deleted */
223 break; /* PERFORMANCE it is faster returning to poll */
225 /* optimization: most used descriptors migrate to the head of the poll array */
226 #ifdef OPTPOLL
227 else
229 if (i < nfds && i > 0 && i != nprio) {
230 register int i_1=i-1;
231 if (fdpp[i]->timestamp > fdpp[i_1]->timestamp) {
232 struct pollfd tfds;
233 struct pollplus *tfdpp;
234 tfds=fds[i];fds[i]=fds[i_1];fds[i_1]=tfds;
235 tfdpp=fdpp[i];fdpp[i]=fdpp[i_1];fdpp[i_1]=tfdpp;
239 #endif
241 #ifdef VDE_PQ
242 if (packetq_timeout > 0)
243 packetq_try();
244 #endif
249 /* starting/ending routines, main_loop, main*/
250 #define HASH_TABLE_SIZE_ARG 0x100
251 #define MACADDR_ARG 0x101
252 #define PRIORITY_ARG 0x102
254 static void Usage(void) {
255 struct swmodule *p;
256 printf(
257 "Usage: vde_switch [OPTIONS]\n"
258 "Runs a VDE switch.\n"
259 "(global opts)\n"
260 " -h, --help Display this help and exit\n"
261 " -v, --version Display informations on version and exit\n"
263 for(p=swmh;p != NULL;p=p->next)
264 if (p->usage != NULL)
265 p->usage();
266 printf(
267 "\n"
268 "Report bugs to "PACKAGE_BUGREPORT "\n"
270 exit(1);
273 static void version(void)
275 printf(
276 "VDE " PACKAGE_VERSION "\n"
277 "Copyright 2003,2004,2005,2006,2007,2008 Renzo Davoli\n"
278 "VDE comes with NO WARRANTY, to the extent permitted by law.\n"
279 "You may redistribute copies of VDE under the terms of the\n"
280 "GNU General Public License v2.\n"
281 "For more information about these matters, see the files\n"
282 "named COPYING.\n");
283 exit(check_kernel_support());
286 static struct option *optcpy(struct option *tgt, struct option *src, int n, int tag)
288 register int i;
289 memcpy(tgt,src,sizeof(struct option) * n);
290 for (i=0;i<n;i++) {
291 tgt[i].val=(tgt[i].val & 0xffff) | tag << 16;
293 return tgt+n;
296 static int parse_globopt(int c, char *optarg)
298 int outc=0;
299 switch (c) {
300 case 'v':
301 version();
302 break;
303 case 'h':
304 Usage();
305 break;
306 default:
307 outc=c;
309 return outc;
312 static void parse_args(int argc, char **argv)
314 struct swmodule *swmp;
315 struct option *long_options;
316 char *optstring;
317 static struct option global_options[] = {
318 {"help",0 , 0, 'h'},
319 {"version", 0, 0, 'v'},
321 static struct option optail = {0,0,0,0};
322 #define N_global_options (sizeof(global_options)/sizeof(struct option))
323 prog = argv[0];
324 int totopts=N_global_options+1;
326 for(swmp=swmh;swmp != NULL;swmp=swmp->next)
327 totopts += swmp->swmnopts;
328 long_options=malloc(totopts * sizeof(struct option));
329 optstring=malloc(2 * totopts * sizeof(char));
330 if (long_options == NULL || optstring==NULL)
331 exit(2);
332 { /* fill-in the long_options fields */
333 register int i;
334 char *os=optstring;
335 char last=0;
336 struct option *opp=long_options;
337 opp=optcpy(opp,global_options,N_global_options,0);
338 for(swmp=swmh;swmp != NULL;swmp=swmp->next)
339 opp=optcpy(opp,swmp->swmopts,swmp->swmnopts,swmp->swmtag);
340 optcpy(opp,&optail,1,0);
341 for (i=0;i<totopts-1;i++)
343 int val=long_options[i].val & 0xffff;
344 if(val > ' ' && val <= '~' && val != last)
346 *os++=val;
347 if(long_options[i].has_arg) *os++=':';
350 *os=0;
353 /* Parse args */
354 int option_index = 0;
355 int c;
356 while (1) {
357 c = GETOPT_LONG (argc, argv, optstring,
358 long_options, &option_index);
359 if (c == -1)
360 break;
361 c=parse_globopt(c,optarg);
362 for(swmp=swmh;swmp != NULL && c!=0;swmp=swmp->next) {
363 if (swmp->parseopt != NULL) {
364 if((c >> 7) == 0)
365 c=swmp->parseopt(c,optarg);
366 else if ((c >> 16) == swmp->swmtag)
367 swmp->parseopt(c & 0xffff,optarg),c=0;
372 if(optind < argc)
373 Usage();
374 free(long_options);
375 free(optstring);
378 static void init_mods(void)
380 struct swmodule *swmp;
382 /* Keep track of the initial cwd */
383 int cwfd = open(".", O_RDONLY);
385 for(swmp=swmh;swmp != NULL;swmp=swmp->next)
386 if (swmp->init != NULL)
388 swmp->init();
389 if (cwfd >= 0)
390 /* Restore cwd so each module will be initialized with the
391 * original cwd also if the previous one changed it. */
392 if(fchdir(cwfd) < 0) {
393 printlog(LOG_WARNING,"Error restoring original working dir");
396 close(cwfd);
399 static void cleanup(void)
401 struct swmodule *swmp;
402 file_cleanup();
403 for(swmp=swmh;swmp != NULL;swmp=swmp->next)
404 if (swmp->cleanup != NULL)
405 swmp->cleanup(0,-1,-1);
408 static void sig_handler(int sig)
410 printlog(LOG_ERR,"Caught signal %d, cleaning up and exiting", sig);
411 cleanup();
412 signal(sig, SIG_DFL);
413 if (sig == SIGTERM)
414 _exit(0);
415 else
416 kill(getpid(), sig);
419 static void setsighandlers()
421 /* setting signal handlers.
422 * sets clean termination for SIGHUP, SIGINT and SIGTERM, and simply
423 * ignores all the others signals which could cause termination. */
424 struct { int sig; const char *name; int ignore; } signals[] = {
425 { SIGHUP, "SIGHUP", 0 },
426 { SIGINT, "SIGINT", 0 },
427 { SIGPIPE, "SIGPIPE", 1 },
428 { SIGALRM, "SIGALRM", 1 },
429 { SIGTERM, "SIGTERM", 0 },
430 { SIGUSR1, "SIGUSR1", 1 },
431 { SIGUSR2, "SIGUSR2", 1 },
432 { SIGPROF, "SIGPROF", 1 },
433 { SIGVTALRM, "SIGVTALRM", 1 },
434 #ifdef VDE_LINUX
435 { SIGPOLL, "SIGPOLL", 1 },
436 #ifdef SIGSTKFLT
437 { SIGSTKFLT, "SIGSTKFLT", 1 },
438 #endif
439 { SIGIO, "SIGIO", 1 },
440 { SIGPWR, "SIGPWR", 1 },
441 #ifdef SIGUNUSED
442 { SIGUNUSED, "SIGUNUSED", 1 },
443 #endif
444 #endif
445 #ifdef VDE_DARWIN
446 { SIGXCPU, "SIGXCPU", 1 },
447 { SIGXFSZ, "SIGXFSZ", 1 },
448 #endif
449 { 0, NULL, 0 }
452 int i;
453 for(i = 0; signals[i].sig != 0; i++)
454 if(signal(signals[i].sig,
455 signals[i].ignore ? SIG_IGN : sig_handler) < 0)
456 printlog(LOG_ERR,"Setting handler for %s: %s", signals[i].name,
457 strerror(errno));
460 static void start_modules(void);
462 int main(int argc, char **argv)
464 starting_time=time(NULL);
465 start_modules();
466 parse_args(argc,argv);
467 atexit(cleanup);
468 setsighandlers();
469 init_mods();
470 loadrcfile();
471 main_loop();
472 return 0;
475 /* modules: module references are only here! */
476 static void start_modules(void)
478 void start_datasock(void);
479 void start_consmgmt(void);
480 start_datasock();
481 start_consmgmt();