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 "compat/poll.h"
35 static struct swmodule
*swmh
;
38 unsigned char switchmac
[ETH_ALEN
];
39 unsigned int priority
=DEFAULT_PRIORITY
;
41 static int hash_size
=INIT_HASH_SIZE
;
42 static int numports
=INIT_NUMPORTS
;
45 static void recaddswm(struct swmodule
**p
,struct swmodule
*new)
47 struct swmodule
*this=*p
;
51 recaddswm(&(this->next
),new);
54 void add_swm(struct swmodule
*new)
56 static int lastlwmtag
;
57 new->swmtag
= ++lastlwmtag
;
58 if (new != NULL
&& new->swmtag
!= 0) {
64 static void recdelswm(struct swmodule
**p
,struct swmodule
*old
)
66 struct swmodule
*this=*p
;
71 recdelswm(&(this->next
),old
);
75 void del_swm(struct swmodule
*old
)
91 static struct pollfd
*fds
= NULL
;
92 static struct pollplus
**fdpp
= NULL
;
94 static int maxfds
= 0;
96 static struct swmodule
**fdtypes
;
100 #define PRIOFLAG 0x80
101 #define TYPEMASK 0x7f
102 #define ISPRIO(X) ((X) & PRIOFLAG)
104 #define TYPE2MGR(X) (fdtypes[((X) & TYPEMASK)])
106 unsigned char add_type(struct swmodule
*mgr
,int prio
)
109 if(ntypes
==maxtypes
) {
110 maxtypes
= maxtypes
? 2 * maxtypes
: 8;
111 if (maxtypes
> PRIOFLAG
) {
112 printlog(LOG_ERR
,"too many file types");
115 if((fdtypes
= realloc(fdtypes
, maxtypes
* sizeof(struct swmodule
*))) == NULL
){
116 printlog(LOG_ERR
,"realloc fdtypes %s",strerror(errno
));
119 memset(fdtypes
+ntypes
,0,sizeof(struct swmodule
*) * maxtypes
-ntypes
);
122 for(i
=0; fdtypes
[i
] != NULL
; i
++)
126 return i
| ((prio
!= 0)?PRIOFLAG
:0);
129 void del_type(unsigned char type
)
137 void add_fd(int fd
,unsigned char type
,int arg
)
141 /* enlarge fds and g_fdsdata array if needed */
143 maxfds
= maxfds
? 2 * maxfds
: 8;
144 if((fds
= realloc(fds
, maxfds
* sizeof(struct pollfd
))) == NULL
){
145 printlog(LOG_ERR
,"realloc fds %s",strerror(errno
));
148 if((fdpp
= realloc(fdpp
, maxfds
* sizeof(struct pollplus
*))) == NULL
){
149 printlog(LOG_ERR
,"realloc pollplus %s",strerror(errno
));
154 fds
[nfds
]=fds
[nprio
];
155 fdpp
[nfds
]=fdpp
[nprio
];
160 if((fdpp
[index
]=malloc(sizeof(struct pollplus
))) == NULL
) {
161 printlog(LOG_ERR
,"realloc pollplus elem %s",strerror(errno
));
166 p
->events
= POLLIN
| POLLHUP
;
167 fdpp
[index
]->type
=type
;
168 fdpp
[index
]->arg
=arg
;
172 static void file_cleanup(void)
175 for(i
= 0; i
< nfds
; i
++)
176 TYPE2MGR(fdpp
[i
]->type
)->cleanup(fdpp
[i
]->type
,fds
[i
].fd
,fdpp
[i
]->arg
);
179 void remove_fd(int fd
)
183 for(i
= 0; i
< nfds
; i
++){
184 if(fds
[i
].fd
== fd
) break;
187 printlog(LOG_WARNING
,"remove_fd : Couldn't find descriptor %d", fd
);
189 struct pollplus
*old
=fdpp
[i
];
190 TYPE2MGR(fdpp
[i
]->type
)->cleanup(fdpp
[i
]->type
,fds
[i
].fd
,fdpp
[i
]->arg
);
191 if (ISPRIO(fdpp
[i
]->type
)) nprio
--;
192 memmove(&fds
[i
], &fds
[i
+ 1], (maxfds
- i
- 1) * sizeof(struct pollfd
));
193 memmove(&fdpp
[i
], &fdpp
[i
+ 1], (maxfds
- i
- 1) * sizeof(struct pollplus
*));
200 static void main_loop()
206 n
=poll(fds
,nfds
,packetq_timeout
);
213 printlog(LOG_WARNING
,"poll %s",strerror(errno
));
215 for(i
= 0; /*i < nfds &&*/ n
>0; i
++){
216 if(fds
[i
].revents
!= 0) {
217 register int prenfds
=nfds
;
219 fdpp
[i
]->timestamp
=now
;
220 TYPE2MGR(fdpp
[i
]->type
)->handle_input(fdpp
[i
]->type
,fds
[i
].fd
,fds
[i
].revents
,&(fdpp
[i
]->arg
));
221 if (nfds
!=prenfds
) /* the current fd has been deleted */
222 break; /* PERFORMANCE it is faster returning to poll */
224 /* optimization: most used descriptors migrate to the head of the poll array */
228 if (i
< nfds
&& i
> 0 && i
!= nprio
) {
229 register int i_1
=i
-1;
230 if (fdpp
[i
]->timestamp
> fdpp
[i_1
]->timestamp
) {
232 struct pollplus
*tfdpp
;
233 tfds
=fds
[i
];fds
[i
]=fds
[i_1
];fds
[i_1
]=tfds
;
234 tfdpp
=fdpp
[i
];fdpp
[i
]=fdpp
[i_1
];fdpp
[i_1
]=tfdpp
;
241 if (packetq_timeout
> 0)
248 /* starting/ending routines, main_loop, main*/
249 #define HASH_TABLE_SIZE_ARG 0x100
250 #define MACADDR_ARG 0x101
251 #define PRIORITY_ARG 0x102
253 static void Usage(void) {
256 "Usage: vde_switch [OPTIONS]\n"
257 "Runs a VDE switch.\n"
259 " -h, --help Display this help and exit\n"
260 " -v, --version Display informations on version and exit\n"
261 " -n --numports Number of ports (default %d)\n"
262 " -x, --hub Make the switch act as a hub\n"
264 " -F, --fstp Activate the fast spanning tree protocol\n"
266 " --macaddr MAC Set the Switch MAC address\n"
268 " --priority N Set the priority for FST (MAC extension)\n"
270 " --hashsize N Hash table size\n"
272 for(p
=swmh
;p
!= NULL
;p
=p
->next
)
273 if (p
->usage
!= NULL
)
277 "Report bugs to "PACKAGE_BUGREPORT
"\n"
282 static void version(void)
285 "VDE " PACKAGE_VERSION
"\n"
286 "Copyright 2003,2004,2005 Renzo Davoli\n"
287 "some code from uml_switch Copyright (C) 2001, 2002 Jeff Dike and others\n"
288 "VDE comes with NO WARRANTY, to the extent permitted by law.\n"
289 "You may redistribute copies of VDE under the terms of the\n"
290 "GNU General Public License v2.\n"
291 "For more information about these matters, see the files\n"
296 static struct option
*optcpy(struct option
*tgt
, struct option
*src
, int n
, int tag
)
299 memcpy(tgt
,src
,sizeof(struct option
) * n
);
301 tgt
[i
].val
=(tgt
[i
].val
& 0xffff) | tag
<< 16;
306 static int parse_globopt(int c
, char *optarg
)
311 portflag(P_SETFLAG
,HUB_TAG
);
313 case HASH_TABLE_SIZE_ARG
:
314 sscanf(optarg
,"%i",&hash_size
);
318 fstflag(P_SETFLAG
,FSTP_TAG
);
321 sscanf(optarg
,"%i",&priority
);
326 {int maci
[ETH_ALEN
],rv
;
327 if (index(optarg
,':') != NULL
)
328 rv
=sscanf(optarg
,"%x:%x:%x:%x:%x:%x", maci
+0, maci
+1, maci
+2, maci
+3, maci
+4, maci
+5);
330 rv
=sscanf(optarg
,"%x.%x.%x.%x.%x.%x", maci
+0, maci
+1, maci
+2, maci
+3, maci
+4, maci
+5);
332 printlog(LOG_ERR
,"Invalid MAC Addr %s",optarg
);
337 for (i
=0;i
<ETH_ALEN
;i
++)
338 switchmac
[i
]=maci
[i
];
343 sscanf(optarg
,"%i",&numports
);
357 static void parse_args(int argc
, char **argv
)
359 struct swmodule
*swmp
;
360 struct option
*long_options
;
362 static struct option global_options
[] = {
368 {"version", 0, 0, 'v'},
369 {"numports", 1, 0, 'n'},
370 {"hashsize", 1, 0, HASH_TABLE_SIZE_ARG
},
371 {"macaddr", 1, 0, MACADDR_ARG
},
373 {"priority", 1, 0, PRIORITY_ARG
}
376 static struct option optail
= {0,0,0,0};
377 #define N_global_options (sizeof(global_options)/sizeof(struct option))
379 int totopts
=N_global_options
+1;
381 for(swmp
=swmh
;swmp
!= NULL
;swmp
=swmp
->next
)
382 totopts
+= swmp
->swmnopts
;
383 long_options
=malloc(totopts
* sizeof(struct option
));
384 optstring
=malloc(2 * totopts
* sizeof(char));
385 if (long_options
== NULL
|| optstring
==NULL
)
387 { /* fill-in the long_options fields */
391 struct option
*opp
=long_options
;
392 opp
=optcpy(opp
,global_options
,N_global_options
,0);
393 for(swmp
=swmh
;swmp
!= NULL
;swmp
=swmp
->next
)
394 opp
=optcpy(opp
,swmp
->swmopts
,swmp
->swmnopts
,swmp
->swmtag
);
395 optcpy(opp
,&optail
,1,0);
396 for (i
=0;i
<totopts
-1;i
++)
398 int val
=long_options
[i
].val
& 0xffff;
399 if(val
> ' ' && val
<= '~' && val
!= last
)
402 if(long_options
[i
].has_arg
) *os
++=':';
409 int option_index
= 0;
412 c
= GETOPT_LONG (argc
, argv
, optstring
,
413 long_options
, &option_index
);
416 c
=parse_globopt(c
,optarg
);
417 for(swmp
=swmh
;swmp
!= NULL
&& c
!=0;swmp
=swmp
->next
) {
418 if (swmp
->parseopt
!= NULL
) {
420 c
=swmp
->parseopt(c
,optarg
);
421 else if ((c
>> 16) == swmp
->swmtag
)
422 swmp
->parseopt(c
& 0xffff,optarg
),c
=0;
433 static void init_mods(void)
435 struct swmodule
*swmp
;
436 for(swmp
=swmh
;swmp
!= NULL
;swmp
=swmp
->next
)
437 if (swmp
->init
!= NULL
)
441 static void cleanup(void)
443 struct swmodule
*swmp
;
445 for(swmp
=swmh
;swmp
!= NULL
;swmp
=swmp
->next
)
446 if (swmp
->cleanup
!= NULL
)
447 swmp
->cleanup(0,-1,-1);
450 static void sig_handler(int sig
)
452 printlog(LOG_ERR
,"Caught signal %d, cleaning up and exiting", sig
);
454 signal(sig
, SIG_DFL
);
458 static void setsighandlers()
460 /* setting signal handlers.
461 * sets clean termination for SIGHUP, SIGINT and SIGTERM, and simply
462 * ignores all the others signals which could cause termination. */
463 struct { int sig
; const char *name
; int ignore
; } signals
[] = {
464 { SIGHUP
, "SIGHUP", 0 },
465 { SIGINT
, "SIGINT", 0 },
466 { SIGPIPE
, "SIGPIPE", 1 },
467 { SIGALRM
, "SIGALRM", 1 },
468 { SIGTERM
, "SIGTERM", 0 },
469 { SIGUSR1
, "SIGUSR1", 1 },
470 { SIGUSR2
, "SIGUSR2", 1 },
471 { SIGPROF
, "SIGPROF", 1 },
472 { SIGVTALRM
, "SIGVTALRM", 1 },
474 { SIGPOLL
, "SIGPOLL", 1 },
476 { SIGSTKFLT
, "SIGSTKFLT", 1 },
478 { SIGIO
, "SIGIO", 1 },
479 { SIGPWR
, "SIGPWR", 1 },
481 { SIGUNUSED
, "SIGUNUSED", 1 },
485 { SIGXCPU
, "SIGXCPU", 1 },
486 { SIGXFSZ
, "SIGXFSZ", 1 },
492 for(i
= 0; signals
[i
].sig
!= 0; i
++)
493 if(signal(signals
[i
].sig
,
494 signals
[i
].ignore
? SIG_IGN
: sig_handler
) < 0)
495 printlog(LOG_ERR
,"Setting handler for %s: %s", signals
[i
].name
,
504 gettimeofday(&v
,NULL
);
505 srand48(v
.tv_sec
^ v
.tv_usec
^ getpid());
506 for(i
=0,val
=lrand48();i
<4; i
++,val
>>=8)
512 static void start_modules(void);
514 int main(int argc
, char **argv
)
518 parse_args(argc
,argv
);
521 hash_init(hash_size
);
533 /* modules: module references are only here! */
534 static void start_modules(void)
536 void start_consmgmt(void);
537 void start_datasock(void);
538 void start_tuntap(void);