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
19 #include <utils/poll.h>
38 static struct swmodule
*swmh
;
41 unsigned char switchmac
[ETH_ALEN
];
42 unsigned int priority
=DEFAULT_PRIORITY
;
44 static int hash_size
=INIT_HASH_SIZE
;
45 static int numports
=INIT_NUMPORTS
;
48 static void recaddswm(struct swmodule
**p
,struct swmodule
*new)
50 struct swmodule
*this=*p
;
54 recaddswm(&(this->next
),new);
57 void add_swm(struct swmodule
*new)
59 static int lastlwmtag
;
60 new->swmtag
= ++lastlwmtag
;
61 if (new != NULL
&& new->swmtag
!= 0) {
67 static void recdelswm(struct swmodule
**p
,struct swmodule
*old
)
69 struct swmodule
*this=*p
;
74 recdelswm(&(this->next
),old
);
78 void del_swm(struct swmodule
*old
)
94 static struct pollfd
*fds
= NULL
;
95 static struct pollplus
**fdpp
= NULL
;
97 static int maxfds
= 0;
99 static struct swmodule
**fdtypes
;
103 #define PRIOFLAG 0x80
104 #define TYPEMASK 0x7f
105 #define ISPRIO(X) ((X) & PRIOFLAG)
107 #define TYPE2MGR(X) (fdtypes[((X) & TYPEMASK)])
109 unsigned char add_type(struct swmodule
*mgr
,int prio
)
112 if(ntypes
==maxtypes
) {
113 maxtypes
= maxtypes
? 2 * maxtypes
: 8;
114 if (maxtypes
> PRIOFLAG
) {
115 printlog(LOG_ERR
,"too many file types");
118 if((fdtypes
= realloc(fdtypes
, maxtypes
* sizeof(struct swmodule
*))) == NULL
){
119 printlog(LOG_ERR
,"realloc fdtypes %s",strerror(errno
));
122 memset(fdtypes
+ntypes
,0,sizeof(struct swmodule
*) * maxtypes
-ntypes
);
125 for(i
=0; fdtypes
[i
] != NULL
; i
++)
129 return i
| ((prio
!= 0)?PRIOFLAG
:0);
132 void del_type(unsigned char type
)
140 void add_fd(int fd
,unsigned char type
,int arg
)
144 /* enlarge fds and g_fdsdata array if needed */
146 maxfds
= maxfds
? 2 * maxfds
: 8;
147 if((fds
= realloc(fds
, maxfds
* sizeof(struct pollfd
))) == NULL
){
148 printlog(LOG_ERR
,"realloc fds %s",strerror(errno
));
151 if((fdpp
= realloc(fdpp
, maxfds
* sizeof(struct pollplus
*))) == NULL
){
152 printlog(LOG_ERR
,"realloc pollplus %s",strerror(errno
));
157 fds
[nfds
]=fds
[nprio
];
158 fdpp
[nfds
]=fdpp
[nprio
];
163 if((fdpp
[index
]=malloc(sizeof(struct pollplus
))) == NULL
) {
164 printlog(LOG_ERR
,"realloc pollplus elem %s",strerror(errno
));
169 p
->events
= POLLIN
| POLLHUP
;
170 fdpp
[index
]->type
=type
;
171 fdpp
[index
]->arg
=arg
;
175 static void file_cleanup(void)
178 for(i
= 0; i
< nfds
; i
++)
179 TYPE2MGR(fdpp
[i
]->type
)->cleanup(fdpp
[i
]->type
,fds
[i
].fd
,fdpp
[i
]->arg
);
182 void remove_fd(int fd
)
186 for(i
= 0; i
< nfds
; i
++){
187 if(fds
[i
].fd
== fd
) break;
190 printlog(LOG_WARNING
,"remove_fd : Couldn't find descriptor %d", fd
);
192 struct pollplus
*old
=fdpp
[i
];
193 TYPE2MGR(fdpp
[i
]->type
)->cleanup(fdpp
[i
]->type
,fds
[i
].fd
,fdpp
[i
]->arg
);
194 if (ISPRIO(fdpp
[i
]->type
)) nprio
--;
195 memmove(&fds
[i
], &fds
[i
+ 1], (maxfds
- i
- 1) * sizeof(struct pollfd
));
196 memmove(&fdpp
[i
], &fdpp
[i
+ 1], (maxfds
- i
- 1) * sizeof(struct pollplus
*));
203 static void main_loop()
209 n
=poll(fds
,nfds
,packetq_timeout
);
216 printlog(LOG_WARNING
,"poll %s",strerror(errno
));
218 for(i
= 0; /*i < nfds &&*/ n
>0; i
++){
219 if(fds
[i
].revents
!= 0) {
220 register int prenfds
=nfds
;
222 fdpp
[i
]->timestamp
=now
;
223 TYPE2MGR(fdpp
[i
]->type
)->handle_input(fdpp
[i
]->type
,fds
[i
].fd
,fds
[i
].revents
,&(fdpp
[i
]->arg
));
224 if (nfds
!=prenfds
) /* the current fd has been deleted */
225 break; /* PERFORMANCE it is faster returning to poll */
227 /* optimization: most used descriptors migrate to the head of the poll array */
231 if (i
< nfds
&& i
> 0 && i
!= nprio
) {
232 register int i_1
=i
-1;
233 if (fdpp
[i
]->timestamp
> fdpp
[i_1
]->timestamp
) {
235 struct pollplus
*tfdpp
;
236 tfds
=fds
[i
];fds
[i
]=fds
[i_1
];fds
[i_1
]=tfds
;
237 tfdpp
=fdpp
[i
];fdpp
[i
]=fdpp
[i_1
];fdpp
[i_1
]=tfdpp
;
244 if (packetq_timeout
> 0)
251 /* starting/ending routines, main_loop, main*/
252 #define HASH_TABLE_SIZE_ARG 0x100
253 #define MACADDR_ARG 0x101
254 #define PRIORITY_ARG 0x102
256 static void Usage(void) {
259 "Usage: vde_switch [OPTIONS]\n"
260 "Runs a VDE switch.\n"
262 " -h, --help Display this help and exit\n"
263 " -v, --version Display informations on version and exit\n"
264 " -n --numports Number of ports (default %d)\n"
265 " -x, --hub Make the switch act as a hub\n"
267 " -F, --fstp Activate the fast spanning tree protocol\n"
269 " --macaddr MAC Set the Switch MAC address\n"
271 " --priority N Set the priority for FST (MAC extension)\n"
273 " --hashsize N Hash table size\n"
275 for(p
=swmh
;p
!= NULL
;p
=p
->next
)
276 if (p
->usage
!= NULL
)
280 "Report bugs to "PACKAGE_BUGREPORT
"\n"
285 static void version(void)
288 "VDE " PACKAGE_VERSION
"\n"
289 "Copyright 2003,2004,2005 Renzo Davoli\n"
290 "some code from uml_switch Copyright (C) 2001, 2002 Jeff Dike and others\n"
291 "VDE comes with NO WARRANTY, to the extent permitted by law.\n"
292 "You may redistribute copies of VDE under the terms of the\n"
293 "GNU General Public License v2.\n"
294 "For more information about these matters, see the files\n"
299 static struct option
*optcpy(struct option
*tgt
, struct option
*src
, int n
, int tag
)
302 memcpy(tgt
,src
,sizeof(struct option
) * n
);
304 tgt
[i
].val
=(tgt
[i
].val
& 0xffff) | tag
<< 16;
309 static int parse_globopt(int c
, char *optarg
)
314 portflag(P_SETFLAG
,HUB_TAG
);
316 case HASH_TABLE_SIZE_ARG
:
317 sscanf(optarg
,"%i",&hash_size
);
321 fstflag(P_SETFLAG
,FSTP_TAG
);
324 sscanf(optarg
,"%i",&priority
);
329 {int maci
[ETH_ALEN
],rv
;
330 if (index(optarg
,':') != NULL
)
331 rv
=sscanf(optarg
,"%x:%x:%x:%x:%x:%x", maci
+0, maci
+1, maci
+2, maci
+3, maci
+4, maci
+5);
333 rv
=sscanf(optarg
,"%x.%x.%x.%x.%x.%x", maci
+0, maci
+1, maci
+2, maci
+3, maci
+4, maci
+5);
335 printlog(LOG_ERR
,"Invalid MAC Addr %s",optarg
);
340 for (i
=0;i
<ETH_ALEN
;i
++)
341 switchmac
[i
]=maci
[i
];
346 sscanf(optarg
,"%i",&numports
);
360 static void parse_args(int argc
, char **argv
)
362 struct swmodule
*swmp
;
363 struct option
*long_options
;
365 static struct option global_options
[] = {
371 {"version", 0, 0, 'v'},
372 {"numports", 1, 0, 'n'},
373 {"hashsize", 1, 0, HASH_TABLE_SIZE_ARG
},
374 {"macaddr", 1, 0, MACADDR_ARG
},
376 {"priority", 1, 0, PRIORITY_ARG
}
379 static struct option optail
= {0,0,0,0};
380 #define N_global_options (sizeof(global_options)/sizeof(struct option))
382 int totopts
=N_global_options
+1;
384 for(swmp
=swmh
;swmp
!= NULL
;swmp
=swmp
->next
)
385 totopts
+= swmp
->swmnopts
;
386 long_options
=malloc(totopts
* sizeof(struct option
));
387 optstring
=malloc(2 * totopts
* sizeof(char));
388 if (long_options
== NULL
|| optstring
==NULL
)
390 { /* fill-in the long_options fields */
394 struct option
*opp
=long_options
;
395 opp
=optcpy(opp
,global_options
,N_global_options
,0);
396 for(swmp
=swmh
;swmp
!= NULL
;swmp
=swmp
->next
)
397 opp
=optcpy(opp
,swmp
->swmopts
,swmp
->swmnopts
,swmp
->swmtag
);
398 optcpy(opp
,&optail
,1,0);
399 for (i
=0;i
<totopts
-1;i
++)
401 int val
=long_options
[i
].val
& 0xffff;
402 if(val
> ' ' && val
<= '~' && val
!= last
)
405 if(long_options
[i
].has_arg
) *os
++=':';
412 int option_index
= 0;
415 c
= GETOPT_LONG (argc
, argv
, optstring
,
416 long_options
, &option_index
);
419 c
=parse_globopt(c
,optarg
);
420 for(swmp
=swmh
;swmp
!= NULL
&& c
!=0;swmp
=swmp
->next
) {
421 if (swmp
->parseopt
!= NULL
) {
423 c
=swmp
->parseopt(c
,optarg
);
424 else if ((c
>> 16) == swmp
->swmtag
)
425 swmp
->parseopt(c
& 0xffff,optarg
),c
=0;
436 static void init_mods(void)
438 struct swmodule
*swmp
;
439 for(swmp
=swmh
;swmp
!= NULL
;swmp
=swmp
->next
)
440 if (swmp
->init
!= NULL
)
444 static void cleanup(void)
446 struct swmodule
*swmp
;
448 for(swmp
=swmh
;swmp
!= NULL
;swmp
=swmp
->next
)
449 if (swmp
->cleanup
!= NULL
)
450 swmp
->cleanup(0,-1,-1);
453 static void sig_handler(int sig
)
455 printlog(LOG_ERR
,"Caught signal %d, cleaning up and exiting", sig
);
457 signal(sig
, SIG_DFL
);
461 static void setsighandlers()
463 /* setting signal handlers.
464 * * sets clean termination for SIGHUP, SIGINT and SIGTERM, and simply
465 * * ignores all the others signals which could cause termination. */
466 struct { int sig
; const char *name
; int ignore
; } signals
[] = {
467 { SIGHUP
, "SIGHUP", 0 },
468 { SIGINT
, "SIGINT", 0 },
469 { SIGPIPE
, "SIGPIPE", 1 },
470 { SIGALRM
, "SIGALRM", 1 },
471 { SIGTERM
, "SIGTERM", 0 },
472 { SIGUSR1
, "SIGUSR1", 1 },
473 { SIGUSR2
, "SIGUSR2", 1 },
474 { SIGPROF
, "SIGPROF", 1 },
475 { SIGVTALRM
, "SIGVTALRM", 1 },
477 { SIGPOLL
, "SIGPOLL", 1 },
479 { SIGSTKFLT
, "SIGSTKFLT", 1 },
481 { SIGIO
, "SIGIO", 1 },
482 { SIGPWR
, "SIGPWR", 1 },
484 { 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);