1 |
/* |
2 |
* Cisco 7200 (Predator) simulation platform. |
3 |
* Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr) |
4 |
* |
5 |
* Network Input/Output Abstraction Layer. |
6 |
*/ |
7 |
|
8 |
/* By default, Cygwin supports only 64 FDs with select()! */ |
9 |
#ifdef __CYGWIN__ |
10 |
#define FD_SETSIZE 1024 |
11 |
#endif |
12 |
|
13 |
#include <stdio.h> |
14 |
#include <stdlib.h> |
15 |
#include <string.h> |
16 |
#include <stdarg.h> |
17 |
#include <unistd.h> |
18 |
#include <errno.h> |
19 |
#include <signal.h> |
20 |
#include <fcntl.h> |
21 |
#include <ctype.h> |
22 |
#include <time.h> |
23 |
#include <sys/time.h> |
24 |
#include <sys/stat.h> |
25 |
#include <sys/types.h> |
26 |
#include <sys/ioctl.h> |
27 |
#include <sys/socket.h> |
28 |
#include <sys/un.h> |
29 |
#include <sys/wait.h> |
30 |
#include <netinet/in.h> |
31 |
#include <arpa/inet.h> |
32 |
#include <netdb.h> |
33 |
#include <pthread.h> |
34 |
|
35 |
#ifdef __linux__ |
36 |
#include <net/if.h> |
37 |
#include <linux/if_tun.h> |
38 |
#endif |
39 |
|
40 |
#include "registry.h" |
41 |
#include "net.h" |
42 |
#include "net_io.h" |
43 |
#include "net_io_filter.h" |
44 |
|
45 |
/* Free a NetIO descriptor */ |
46 |
static int netio_free(void *data,void *arg); |
47 |
|
48 |
/* NIO RX listener */ |
49 |
static pthread_mutex_t netio_rxl_mutex = PTHREAD_MUTEX_INITIALIZER; |
50 |
static pthread_mutex_t netio_rxq_mutex = PTHREAD_MUTEX_INITIALIZER; |
51 |
static struct netio_rx_listener *netio_rxl_list = NULL; |
52 |
static struct netio_rx_listener *netio_rxl_add_list = NULL; |
53 |
static netio_desc_t *netio_rxl_remove_list = NULL; |
54 |
static pthread_t netio_rxl_thread; |
55 |
static pthread_cond_t netio_rxl_cond; |
56 |
|
57 |
#define NETIO_RXL_LOCK() pthread_mutex_lock(&netio_rxl_mutex); |
58 |
#define NETIO_RXL_UNLOCK() pthread_mutex_unlock(&netio_rxl_mutex); |
59 |
|
60 |
#define NETIO_RXQ_LOCK() pthread_mutex_lock(&netio_rxq_mutex); |
61 |
#define NETIO_RXQ_UNLOCK() pthread_mutex_unlock(&netio_rxq_mutex); |
62 |
|
63 |
/* NetIO type */ |
64 |
typedef struct { |
65 |
char *name; |
66 |
char *desc; |
67 |
}netio_type_t; |
68 |
|
69 |
/* NETIO types (must follow the enum definition) */ |
70 |
static netio_type_t netio_types[NETIO_TYPE_MAX] = { |
71 |
{ "unix" , "UNIX local sockets" }, |
72 |
{ "vde" , "Virtual Distributed Ethernet / UML switch" }, |
73 |
{ "tap" , "Linux/FreeBSD TAP device" }, |
74 |
{ "udp" , "UDP sockets" }, |
75 |
{ "tcp_cli" , "TCP client" }, |
76 |
{ "tcp_ser" , "TCP server" }, |
77 |
#ifdef LINUX_ETH |
78 |
{ "linux_eth" , "Linux Ethernet device" }, |
79 |
#endif |
80 |
#ifdef GEN_ETH |
81 |
{ "gen_eth" , "Generic Ethernet device (PCAP)" }, |
82 |
#endif |
83 |
{ "fifo" , "FIFO (intra-hypervisor)" }, |
84 |
{ "null" , "Null device" }, |
85 |
}; |
86 |
|
87 |
/* Get NETIO type given a description */ |
88 |
int netio_get_type(char *type) |
89 |
{ |
90 |
int i; |
91 |
|
92 |
for(i=0;i<NETIO_TYPE_MAX;i++) |
93 |
if (!strcmp(type,netio_types[i].name)) |
94 |
return(i); |
95 |
|
96 |
return(-1); |
97 |
} |
98 |
|
99 |
/* Show the NETIO types */ |
100 |
void netio_show_types(void) |
101 |
{ |
102 |
int i; |
103 |
|
104 |
printf("Available NETIO types:\n"); |
105 |
|
106 |
for(i=0;i<NETIO_TYPE_MAX;i++) |
107 |
printf(" * %-10s : %s\n",netio_types[i].name,netio_types[i].desc); |
108 |
|
109 |
printf("\n"); |
110 |
} |
111 |
|
112 |
/* |
113 |
* ========================================================================= |
114 |
* Generic functions (abstraction layer) |
115 |
* ========================================================================= |
116 |
*/ |
117 |
|
118 |
/* Acquire a reference to NIO from registry (increment reference count) */ |
119 |
netio_desc_t *netio_acquire(char *name) |
120 |
{ |
121 |
return(registry_find(name,OBJ_TYPE_NIO)); |
122 |
} |
123 |
|
124 |
/* Release an NIO (decrement reference count) */ |
125 |
int netio_release(char *name) |
126 |
{ |
127 |
return(registry_unref(name,OBJ_TYPE_NIO)); |
128 |
} |
129 |
|
130 |
/* Record an NIO in registry */ |
131 |
static int netio_record(netio_desc_t *nio) |
132 |
{ |
133 |
return(registry_add(nio->name,OBJ_TYPE_NIO,nio)); |
134 |
} |
135 |
|
136 |
/* Create a new NetIO descriptor */ |
137 |
static netio_desc_t *netio_create(char *name) |
138 |
{ |
139 |
netio_desc_t *nio; |
140 |
|
141 |
if (!(nio = malloc(sizeof(*nio)))) |
142 |
return NULL; |
143 |
|
144 |
/* setup as a NULL descriptor */ |
145 |
memset(nio,0,sizeof(*nio)); |
146 |
nio->type = NETIO_TYPE_NULL; |
147 |
|
148 |
/* save name for registry */ |
149 |
if (!(nio->name = strdup(name))) { |
150 |
free(nio); |
151 |
return NULL; |
152 |
} |
153 |
|
154 |
return nio; |
155 |
} |
156 |
|
157 |
/* Delete a NetIO descriptor */ |
158 |
int netio_delete(char *name) |
159 |
{ |
160 |
return(registry_delete_if_unused(name,OBJ_TYPE_NIO,netio_free,NULL)); |
161 |
} |
162 |
|
163 |
/* Delete all NetIO descriptors */ |
164 |
int netio_delete_all(void) |
165 |
{ |
166 |
return(registry_delete_type(OBJ_TYPE_NIO,netio_free,NULL)); |
167 |
} |
168 |
|
169 |
/* Save the configuration of a NetIO descriptor */ |
170 |
void netio_save_config(netio_desc_t *nio,FILE *fd) |
171 |
{ |
172 |
if (nio->save_cfg) |
173 |
nio->save_cfg(nio,fd); |
174 |
} |
175 |
|
176 |
/* Save configurations of all NetIO descriptors */ |
177 |
static void netio_reg_save_config(registry_entry_t *entry,void *opt,int *err) |
178 |
{ |
179 |
netio_save_config((netio_desc_t *)entry->data,(FILE *)opt); |
180 |
} |
181 |
|
182 |
void netio_save_config_all(FILE *fd) |
183 |
{ |
184 |
registry_foreach_type(OBJ_TYPE_NIO,netio_reg_save_config,fd,NULL); |
185 |
fprintf(fd,"\n"); |
186 |
} |
187 |
|
188 |
/* Send a packet through a NetIO descriptor */ |
189 |
ssize_t netio_send(netio_desc_t *nio,void *pkt,size_t len) |
190 |
{ |
191 |
int res; |
192 |
|
193 |
if (!nio) |
194 |
return(-1); |
195 |
|
196 |
if (nio->debug) { |
197 |
printf("NIO %s: sending a packet of %lu bytes:\n",nio->name,(u_long)len); |
198 |
mem_dump(stdout,pkt,len); |
199 |
} |
200 |
|
201 |
/* Apply the TX filter */ |
202 |
if (nio->tx_filter != NULL) { |
203 |
res = nio->tx_filter->pkt_handler(nio,pkt,len,nio->tx_filter_data); |
204 |
|
205 |
if (res <= 0) |
206 |
return(-1); |
207 |
} |
208 |
|
209 |
return(nio->send(nio->dptr,pkt,len)); |
210 |
} |
211 |
|
212 |
/* Receive a packet through a NetIO descriptor */ |
213 |
ssize_t netio_recv(netio_desc_t *nio,void *pkt,size_t max_len) |
214 |
{ |
215 |
ssize_t len; |
216 |
int res; |
217 |
|
218 |
if (!nio) |
219 |
return(-1); |
220 |
|
221 |
/* Receive the packet */ |
222 |
if ((len = nio->recv(nio->dptr,pkt,max_len)) <= 0) |
223 |
return(-1); |
224 |
|
225 |
if (nio->debug) { |
226 |
printf("NIO %s: receiving a packet of %ld bytes:\n",nio->name,(long)len); |
227 |
mem_dump(stdout,pkt,len); |
228 |
} |
229 |
|
230 |
/* Apply the RX filter */ |
231 |
if (nio->rx_filter != NULL) { |
232 |
res = nio->rx_filter->pkt_handler(nio,pkt,len,nio->rx_filter_data); |
233 |
|
234 |
if (res == NETIO_FILTER_ACTION_DROP) |
235 |
return(-1); |
236 |
} |
237 |
|
238 |
return(len); |
239 |
} |
240 |
|
241 |
/* Get a NetIO FD */ |
242 |
int netio_get_fd(netio_desc_t *nio) |
243 |
{ |
244 |
int fd = -1; |
245 |
|
246 |
switch(nio->type) { |
247 |
case NETIO_TYPE_UNIX: |
248 |
fd = nio->u.nud.fd; |
249 |
break; |
250 |
case NETIO_TYPE_VDE: |
251 |
fd = nio->u.nvd.data_fd; |
252 |
break; |
253 |
case NETIO_TYPE_TAP: |
254 |
fd = nio->u.ntd.fd; |
255 |
break; |
256 |
case NETIO_TYPE_TCP_CLI: |
257 |
case NETIO_TYPE_TCP_SER: |
258 |
case NETIO_TYPE_UDP: |
259 |
fd = nio->u.nid.fd; |
260 |
break; |
261 |
#ifdef LINUX_ETH |
262 |
case NETIO_TYPE_LINUX_ETH: |
263 |
fd = nio->u.nled.fd; |
264 |
break; |
265 |
#endif |
266 |
} |
267 |
|
268 |
return(fd); |
269 |
} |
270 |
|
271 |
/* |
272 |
* ========================================================================= |
273 |
* UNIX sockets |
274 |
* ========================================================================= |
275 |
*/ |
276 |
|
277 |
/* Create an UNIX socket */ |
278 |
static int netio_unix_create_socket(netio_unix_desc_t *nud) |
279 |
{ |
280 |
struct sockaddr_un local_sock; |
281 |
|
282 |
if ((nud->fd = socket(AF_UNIX,SOCK_DGRAM,0)) == -1) { |
283 |
perror("netio_unix: socket"); |
284 |
return(-1); |
285 |
} |
286 |
|
287 |
memset(&local_sock,0,sizeof(local_sock)); |
288 |
local_sock.sun_family = AF_UNIX; |
289 |
strcpy(local_sock.sun_path,nud->local_filename); |
290 |
|
291 |
if (bind(nud->fd,(struct sockaddr *)&local_sock,sizeof(local_sock)) == -1) { |
292 |
perror("netio_unix: bind"); |
293 |
return(-1); |
294 |
} |
295 |
|
296 |
return(nud->fd); |
297 |
} |
298 |
|
299 |
/* Free a NetIO unix descriptor */ |
300 |
static void netio_unix_free(netio_unix_desc_t *nud) |
301 |
{ |
302 |
if (nud->fd != -1) |
303 |
close(nud->fd); |
304 |
|
305 |
if (nud->local_filename) { |
306 |
unlink(nud->local_filename); |
307 |
free(nud->local_filename); |
308 |
} |
309 |
} |
310 |
|
311 |
/* Allocate a new NetIO UNIX descriptor */ |
312 |
static int netio_unix_create(netio_unix_desc_t *nud,char *local,char *remote) |
313 |
{ |
314 |
memset(nud,0,sizeof(*nud)); |
315 |
nud->fd = -1; |
316 |
|
317 |
/* check lengths */ |
318 |
if ((strlen(local) >= sizeof(nud->remote_sock.sun_path)) || |
319 |
(strlen(remote) >= sizeof(nud->remote_sock.sun_path))) |
320 |
goto nomem_error; |
321 |
|
322 |
if (!(nud->local_filename = strdup(local))) |
323 |
goto nomem_error; |
324 |
|
325 |
if (netio_unix_create_socket(nud) == -1) |
326 |
return(-1); |
327 |
|
328 |
/* prepare the remote info */ |
329 |
nud->remote_sock.sun_family = AF_UNIX; |
330 |
strcpy(nud->remote_sock.sun_path,remote); |
331 |
return(0); |
332 |
|
333 |
nomem_error: |
334 |
fprintf(stderr,"netio_unix_create: " |
335 |
"invalid file size or insufficient memory\n"); |
336 |
return(-1); |
337 |
} |
338 |
|
339 |
/* Write a packet to an UNIX socket */ |
340 |
static ssize_t netio_unix_send(netio_unix_desc_t *nud,void *pkt,size_t pkt_len) |
341 |
{ |
342 |
return(sendto(nud->fd,pkt,pkt_len,0, |
343 |
(struct sockaddr *)&nud->remote_sock, |
344 |
sizeof(&nud->remote_sock))); |
345 |
} |
346 |
|
347 |
/* Receive a packet from an UNIX socket */ |
348 |
static ssize_t netio_unix_recv(netio_unix_desc_t *nud,void *pkt,size_t max_len) |
349 |
{ |
350 |
return(recvfrom(nud->fd,pkt,max_len,0,NULL,NULL)); |
351 |
} |
352 |
|
353 |
/* Save the NIO configuration */ |
354 |
static void netio_unix_save_cfg(netio_desc_t *nio,FILE *fd) |
355 |
{ |
356 |
netio_unix_desc_t *nud = nio->dptr; |
357 |
fprintf(fd,"nio create_unix %s %s %s\n", |
358 |
nio->name,nud->local_filename,nud->remote_sock.sun_path); |
359 |
} |
360 |
|
361 |
/* Create a new NetIO descriptor with UNIX method */ |
362 |
netio_desc_t *netio_desc_create_unix(char *nio_name,char *local,char *remote) |
363 |
{ |
364 |
netio_desc_t *nio; |
365 |
|
366 |
if (!(nio = netio_create(nio_name))) |
367 |
return NULL; |
368 |
|
369 |
if (netio_unix_create(&nio->u.nud,local,remote) == -1) { |
370 |
netio_free(nio,NULL); |
371 |
return NULL; |
372 |
} |
373 |
|
374 |
nio->type = NETIO_TYPE_UNIX; |
375 |
nio->send = (void *)netio_unix_send; |
376 |
nio->recv = (void *)netio_unix_recv; |
377 |
nio->save_cfg = netio_unix_save_cfg; |
378 |
nio->dptr = &nio->u.nud; |
379 |
|
380 |
if (netio_record(nio) == -1) { |
381 |
netio_free(nio,NULL); |
382 |
return NULL; |
383 |
} |
384 |
|
385 |
return nio; |
386 |
} |
387 |
|
388 |
/* |
389 |
* ========================================================================= |
390 |
* VDE (Virtual Distributed Ethernet) interface |
391 |
* ========================================================================= |
392 |
*/ |
393 |
|
394 |
/* Free a NetIO VDE descriptor */ |
395 |
static void netio_vde_free(netio_vde_desc_t *nvd) |
396 |
{ |
397 |
if (nvd->data_fd != -1) |
398 |
close(nvd->data_fd); |
399 |
|
400 |
if (nvd->ctrl_fd != -1) |
401 |
close(nvd->ctrl_fd); |
402 |
|
403 |
if (nvd->local_filename) { |
404 |
unlink(nvd->local_filename); |
405 |
free(nvd->local_filename); |
406 |
} |
407 |
} |
408 |
|
409 |
/* Create a new NetIO VDE descriptor */ |
410 |
static int netio_vde_create(netio_vde_desc_t *nvd,char *control,char *local) |
411 |
{ |
412 |
struct sockaddr_un ctrl_sock,tst; |
413 |
struct vde_request_v3 req; |
414 |
ssize_t len; |
415 |
int res; |
416 |
|
417 |
memset(nvd,0,sizeof(*nvd)); |
418 |
nvd->ctrl_fd = nvd->data_fd = -1; |
419 |
|
420 |
if ((strlen(control) >= sizeof(ctrl_sock.sun_path)) || |
421 |
(strlen(local) >= sizeof(nvd->remote_sock.sun_path))) { |
422 |
fprintf(stderr,"netio_vde_create: bad filenames specified\n"); |
423 |
return(-1); |
424 |
} |
425 |
|
426 |
/* Copy the local filename */ |
427 |
if (!(nvd->local_filename = strdup(local))) { |
428 |
fprintf(stderr,"netio_vde_create: insufficient memory\n"); |
429 |
return(-1); |
430 |
} |
431 |
|
432 |
/* Connect to the VDE switch controller */ |
433 |
nvd->ctrl_fd = socket(AF_UNIX,SOCK_STREAM,0); |
434 |
if (nvd->ctrl_fd < 0) { |
435 |
perror("netio_vde_create: socket(control)"); |
436 |
return(-1); |
437 |
} |
438 |
|
439 |
memset(&ctrl_sock,0,sizeof(ctrl_sock)); |
440 |
ctrl_sock.sun_family = AF_UNIX; |
441 |
strcpy(ctrl_sock.sun_path,control); |
442 |
|
443 |
res = connect(nvd->ctrl_fd,(struct sockaddr *)&ctrl_sock, |
444 |
sizeof(ctrl_sock)); |
445 |
|
446 |
if (res < 0) { |
447 |
perror("netio_vde_create: connect(control)"); |
448 |
return(-1); |
449 |
} |
450 |
|
451 |
tst.sun_family = AF_UNIX; |
452 |
strcpy(tst.sun_path,local); |
453 |
|
454 |
/* Create the data connection */ |
455 |
nvd->data_fd = socket(AF_UNIX,SOCK_DGRAM,0); |
456 |
if (nvd->data_fd < 0) { |
457 |
perror("netio_vde_create: socket(data)"); |
458 |
return(-1); |
459 |
} |
460 |
|
461 |
if (bind(nvd->data_fd,(struct sockaddr *)&tst,sizeof(tst))<0) { |
462 |
perror("netio_vde_create: bind(data)"); |
463 |
return(-1); |
464 |
} |
465 |
|
466 |
/* Now, process to registration */ |
467 |
memset(&req,0,sizeof(req)); |
468 |
req.sock.sun_family = AF_UNIX; |
469 |
strcpy(req.sock.sun_path,local); |
470 |
req.magic = VDE_SWITCH_MAGIC; |
471 |
req.version = VDE_SWITCH_VERSION; |
472 |
req.type = VDE_REQ_NEW_CONTROL; |
473 |
|
474 |
len = write(nvd->ctrl_fd,&req,sizeof(req)); |
475 |
if (len != sizeof(req)) { |
476 |
perror("netio_vde_create: write(req)"); |
477 |
return(-1); |
478 |
} |
479 |
|
480 |
/* Read the remote socket descriptor */ |
481 |
len = read(nvd->ctrl_fd,&nvd->remote_sock,sizeof(nvd->remote_sock)); |
482 |
if (len != sizeof(nvd->remote_sock)) { |
483 |
perror("netio_vde_create: read(req)"); |
484 |
return(-1); |
485 |
} |
486 |
|
487 |
return(0); |
488 |
} |
489 |
|
490 |
/* Write a packet to a VDE data socket */ |
491 |
static ssize_t netio_vde_send(netio_vde_desc_t *nvd,void *pkt,size_t pkt_len) |
492 |
{ |
493 |
return(sendto(nvd->data_fd,pkt,pkt_len,0, |
494 |
(struct sockaddr *)&nvd->remote_sock, |
495 |
sizeof(nvd->remote_sock))); |
496 |
} |
497 |
|
498 |
/* Receive a packet from a VDE socket */ |
499 |
static ssize_t netio_vde_recv(netio_vde_desc_t *nvd,void *pkt,size_t max_len) |
500 |
{ |
501 |
return(recvfrom(nvd->data_fd,pkt,max_len,0,NULL,NULL)); |
502 |
} |
503 |
|
504 |
/* Save the NIO configuration */ |
505 |
static void netio_vde_save_cfg(netio_desc_t *nio,FILE *fd) |
506 |
{ |
507 |
netio_vde_desc_t *nvd = nio->dptr; |
508 |
fprintf(fd,"nio create_vde %s %s %s\n", |
509 |
nio->name,nvd->remote_sock.sun_path,nvd->local_filename); |
510 |
} |
511 |
|
512 |
/* Create a new NetIO descriptor with VDE method */ |
513 |
netio_desc_t *netio_desc_create_vde(char *nio_name,char *control,char *local) |
514 |
{ |
515 |
netio_vde_desc_t *nvd; |
516 |
netio_desc_t *nio; |
517 |
|
518 |
if (!(nio = netio_create(nio_name))) |
519 |
return NULL; |
520 |
|
521 |
nvd = &nio->u.nvd; |
522 |
|
523 |
if (netio_vde_create(nvd,control,local) == -1) { |
524 |
netio_free(nio,NULL); |
525 |
return NULL; |
526 |
} |
527 |
|
528 |
nio->type = NETIO_TYPE_VDE; |
529 |
nio->send = (void *)netio_vde_send; |
530 |
nio->recv = (void *)netio_vde_recv; |
531 |
nio->save_cfg = netio_vde_save_cfg; |
532 |
nio->dptr = &nio->u.nvd; |
533 |
|
534 |
if (netio_record(nio) == -1) { |
535 |
netio_free(nio,NULL); |
536 |
return NULL; |
537 |
} |
538 |
|
539 |
return nio; |
540 |
} |
541 |
|
542 |
/* |
543 |
* ========================================================================= |
544 |
* TAP devices |
545 |
* ========================================================================= |
546 |
*/ |
547 |
|
548 |
/* Free a NetIO TAP descriptor */ |
549 |
static void netio_tap_free(netio_tap_desc_t *ntd) |
550 |
{ |
551 |
if (ntd->fd != -1) |
552 |
close(ntd->fd); |
553 |
} |
554 |
|
555 |
/* Open a TAP device */ |
556 |
static int netio_tap_open(char *tap_devname) |
557 |
{ |
558 |
#ifdef __linux__ |
559 |
struct ifreq ifr; |
560 |
int fd,err; |
561 |
|
562 |
if ((fd = open("/dev/net/tun",O_RDWR)) < 0) |
563 |
return(-1); |
564 |
|
565 |
memset(&ifr,0,sizeof(ifr)); |
566 |
|
567 |
/* Flags: IFF_TUN - TUN device (no Ethernet headers) |
568 |
* IFF_TAP - TAP device |
569 |
* |
570 |
* IFF_NO_PI - Do not provide packet information |
571 |
*/ |
572 |
ifr.ifr_flags = IFF_TAP|IFF_NO_PI; |
573 |
if (*tap_devname) |
574 |
strncpy(ifr.ifr_name,tap_devname,IFNAMSIZ); |
575 |
|
576 |
if ((err = ioctl(fd,TUNSETIFF,(void *)&ifr)) < 0) { |
577 |
close(fd); |
578 |
return err; |
579 |
} |
580 |
|
581 |
strcpy(tap_devname,ifr.ifr_name); |
582 |
return(fd); |
583 |
#else |
584 |
int i,fd = -1; |
585 |
|
586 |
if (*tap_devname) { |
587 |
fd = open(tap_devname,O_RDWR); |
588 |
} else { |
589 |
for(i=0;i<16;i++) { |
590 |
snprintf(tap_devname,NETIO_DEV_MAXLEN,"/dev/tap%d",i); |
591 |
|
592 |
if ((fd = open(tap_devname,O_RDWR)) >= 0) |
593 |
break; |
594 |
} |
595 |
} |
596 |
|
597 |
return(fd); |
598 |
#endif |
599 |
} |
600 |
|
601 |
/* Allocate a new NetIO TAP descriptor */ |
602 |
static int netio_tap_create(netio_tap_desc_t *ntd,char *tap_name) |
603 |
{ |
604 |
if (strlen(tap_name) >= NETIO_DEV_MAXLEN) { |
605 |
fprintf(stderr,"netio_tap_create: bad TAP device string specified.\n"); |
606 |
return(-1); |
607 |
} |
608 |
|
609 |
memset(ntd,0,sizeof(*ntd)); |
610 |
strcpy(ntd->filename,tap_name); |
611 |
ntd->fd = netio_tap_open(ntd->filename); |
612 |
|
613 |
if (ntd->fd == -1) { |
614 |
fprintf(stderr,"netio_tap_create: unable to open TAP device %s (%s)\n", |
615 |
tap_name,strerror(errno)); |
616 |
return(-1); |
617 |
} |
618 |
|
619 |
return(0); |
620 |
} |
621 |
|
622 |
/* Write a packet to a TAP device */ |
623 |
static ssize_t netio_tap_send(netio_tap_desc_t *ntd,void *pkt,size_t pkt_len) |
624 |
{ |
625 |
return(write(ntd->fd,pkt,pkt_len)); |
626 |
} |
627 |
|
628 |
/* Receive a packet through a TAP device */ |
629 |
static ssize_t netio_tap_recv(netio_tap_desc_t *ntd,void *pkt,size_t max_len) |
630 |
{ |
631 |
return(read(ntd->fd,pkt,max_len)); |
632 |
} |
633 |
|
634 |
/* Save the NIO configuration */ |
635 |
static void netio_tap_save_cfg(netio_desc_t *nio,FILE *fd) |
636 |
{ |
637 |
netio_tap_desc_t *ntd = nio->dptr; |
638 |
fprintf(fd,"nio create_tap %s %s\n",nio->name,ntd->filename); |
639 |
} |
640 |
|
641 |
/* Create a new NetIO descriptor with TAP method */ |
642 |
netio_desc_t *netio_desc_create_tap(char *nio_name,char *tap_name) |
643 |
{ |
644 |
netio_tap_desc_t *ntd; |
645 |
netio_desc_t *nio; |
646 |
|
647 |
if (!(nio = netio_create(nio_name))) |
648 |
return NULL; |
649 |
|
650 |
ntd = &nio->u.ntd; |
651 |
|
652 |
if (netio_tap_create(ntd,tap_name) == -1) { |
653 |
netio_free(nio,NULL); |
654 |
return NULL; |
655 |
} |
656 |
|
657 |
nio->type = NETIO_TYPE_TAP; |
658 |
nio->send = (void *)netio_tap_send; |
659 |
nio->recv = (void *)netio_tap_recv; |
660 |
nio->save_cfg = netio_tap_save_cfg; |
661 |
nio->dptr = &nio->u.ntd; |
662 |
|
663 |
if (netio_record(nio) == -1) { |
664 |
netio_free(nio,NULL); |
665 |
return NULL; |
666 |
} |
667 |
|
668 |
return nio; |
669 |
} |
670 |
|
671 |
/* |
672 |
* ========================================================================= |
673 |
* TCP sockets |
674 |
* ========================================================================= |
675 |
*/ |
676 |
|
677 |
/* Free a NetIO TCP descriptor */ |
678 |
static void netio_tcp_free(netio_inet_desc_t *nid) |
679 |
{ |
680 |
if (nid->fd != -1) |
681 |
close(nid->fd); |
682 |
} |
683 |
|
684 |
/* |
685 |
* very simple protocol to send packets over tcp |
686 |
* 32 bits in network format - size of packet, then packet itself and so on. |
687 |
*/ |
688 |
static ssize_t netio_tcp_send(netio_inet_desc_t *nid,void *pkt,size_t pkt_len) |
689 |
{ |
690 |
u_long l = htonl(pkt_len); |
691 |
|
692 |
if (write(nid->fd,&l,sizeof(l)) == -1) |
693 |
return(-1); |
694 |
|
695 |
return(write(nid->fd,pkt,pkt_len)); |
696 |
} |
697 |
|
698 |
static ssize_t netio_tcp_recv(netio_inet_desc_t *nid,void *pkt,size_t max_len) |
699 |
{ |
700 |
u_long l; |
701 |
|
702 |
if (read(nid->fd,&l,sizeof(l)) != sizeof(l)) |
703 |
return(-1); |
704 |
|
705 |
if (ntohl(l) > max_len) |
706 |
return(-1); |
707 |
|
708 |
return(read(nid->fd,pkt,ntohl(l))); |
709 |
} |
710 |
|
711 |
static int netio_tcp_cli_create(netio_inet_desc_t *nid,char *host,char *port) |
712 |
{ |
713 |
struct sockaddr_in serv; |
714 |
struct servent *sp; |
715 |
struct hostent *hp; |
716 |
|
717 |
if ((nid->fd = socket(PF_INET,SOCK_STREAM,0)) < 0) { |
718 |
perror("netio_tcp_cli_create: socket"); |
719 |
return(-1); |
720 |
} |
721 |
|
722 |
memset(&serv,0,sizeof(serv)); |
723 |
serv.sin_family = AF_INET; |
724 |
|
725 |
if (atoi(port) == 0) { |
726 |
if (!(sp = getservbyname(port,"tcp"))) { |
727 |
fprintf(stderr,"netio_tcp_cli_create: port %s is neither " |
728 |
"number not service %s\n",port,strerror(errno)); |
729 |
close(nid->fd); |
730 |
return(-1); |
731 |
} |
732 |
serv.sin_port = sp->s_port; |
733 |
} else |
734 |
serv.sin_port = htons(atoi(port)); |
735 |
|
736 |
if (inet_addr(host) == INADDR_NONE) { |
737 |
if (!(hp = gethostbyname(host))) { |
738 |
fprintf(stderr,"netio_tcp_cli_create: no host %s\n",host); |
739 |
close(nid->fd); |
740 |
return(-1); |
741 |
} |
742 |
serv.sin_addr.s_addr = *hp->h_addr; |
743 |
} else |
744 |
serv.sin_addr.s_addr = inet_addr(host); |
745 |
|
746 |
if (connect(nid->fd,(struct sockaddr *)&serv,sizeof(serv)) < 0) { |
747 |
fprintf(stderr,"netio_tcp_cli_create: connect to %s:%s failed %s\n", |
748 |
host,port,strerror(errno)); |
749 |
close(nid->fd); |
750 |
return(-1); |
751 |
} |
752 |
return(0); |
753 |
} |
754 |
|
755 |
/* Create a new NetIO descriptor with TCP_CLI method */ |
756 |
netio_desc_t *netio_desc_create_tcp_cli(char *nio_name,char *host,char *port) |
757 |
{ |
758 |
netio_desc_t *nio; |
759 |
|
760 |
if (!(nio = netio_create(nio_name))) |
761 |
return NULL; |
762 |
|
763 |
if (netio_tcp_cli_create(&nio->u.nid,host,port) < 0) { |
764 |
netio_free(nio,NULL); |
765 |
return NULL; |
766 |
} |
767 |
|
768 |
nio->type = NETIO_TYPE_TCP_CLI; |
769 |
nio->send = (void *)netio_tcp_send; |
770 |
nio->recv = (void *)netio_tcp_recv; |
771 |
nio->dptr = &nio->u.nid; |
772 |
|
773 |
if (netio_record(nio) == -1) { |
774 |
netio_free(nio,NULL); |
775 |
return NULL; |
776 |
} |
777 |
|
778 |
return nio; |
779 |
} |
780 |
|
781 |
static int netio_tcp_ser_create(netio_inet_desc_t *nid,char *port) |
782 |
{ |
783 |
struct sockaddr_in serv; |
784 |
struct servent *sp; |
785 |
int sock_fd; |
786 |
|
787 |
if ((sock_fd = socket(PF_INET,SOCK_STREAM,0)) < 0) { |
788 |
perror("netio_tcp_cli_create: socket\n"); |
789 |
return(-1); |
790 |
} |
791 |
|
792 |
memset(&serv,0,sizeof(serv)); |
793 |
serv.sin_family = AF_INET; |
794 |
serv.sin_addr.s_addr = htonl(INADDR_ANY); |
795 |
|
796 |
if (atoi(port) == 0) { |
797 |
if (!(sp = getservbyname(port,"tcp"))) { |
798 |
fprintf(stderr,"netio_tcp_ser_create: port %s is neither " |
799 |
"number not service %s\n",port,strerror(errno)); |
800 |
close(sock_fd); |
801 |
return(-1); |
802 |
} |
803 |
serv.sin_port = sp->s_port; |
804 |
} else |
805 |
serv.sin_port = htons(atoi(port)); |
806 |
|
807 |
if (bind(sock_fd,(struct sockaddr *)&serv,sizeof(serv)) < 0) { |
808 |
fprintf(stderr,"netio_tcp_ser_create: bind %s failed %s\n", |
809 |
port,strerror(errno)); |
810 |
close(sock_fd); |
811 |
return(-1); |
812 |
} |
813 |
|
814 |
if (listen(sock_fd,1) < 0) { |
815 |
fprintf(stderr,"netio_tcp_ser_create: listen %s failed %s\n", |
816 |
port,strerror(errno)); |
817 |
close(sock_fd); |
818 |
return(-1); |
819 |
} |
820 |
|
821 |
fprintf(stderr,"Waiting connection on port %s...\n",port); |
822 |
|
823 |
if ((nid->fd = accept(sock_fd,NULL,NULL)) < 0) { |
824 |
fprintf(stderr,"netio_tcp_ser_create: accept %s failed %s\n", |
825 |
port,strerror(errno)); |
826 |
close(sock_fd); |
827 |
return(-1); |
828 |
} |
829 |
|
830 |
fprintf(stderr,"Connected\n"); |
831 |
|
832 |
close(sock_fd); |
833 |
return(0); |
834 |
} |
835 |
|
836 |
/* Create a new NetIO descriptor with TCP_SER method */ |
837 |
netio_desc_t *netio_desc_create_tcp_ser(char *nio_name,char *port) |
838 |
{ |
839 |
netio_desc_t *nio; |
840 |
|
841 |
if (!(nio = netio_create(nio_name))) |
842 |
return NULL; |
843 |
|
844 |
if (netio_tcp_ser_create(&nio->u.nid,port) == -1) { |
845 |
netio_free(nio,NULL); |
846 |
return NULL; |
847 |
} |
848 |
|
849 |
nio->type = NETIO_TYPE_TCP_SER; |
850 |
nio->send = (void *)netio_tcp_send; |
851 |
nio->recv = (void *)netio_tcp_recv; |
852 |
nio->dptr = &nio->u.nid; |
853 |
|
854 |
if (netio_record(nio) == -1) { |
855 |
netio_free(nio,NULL); |
856 |
return NULL; |
857 |
} |
858 |
|
859 |
return nio; |
860 |
} |
861 |
|
862 |
/* |
863 |
* ========================================================================= |
864 |
* UDP sockets |
865 |
* ========================================================================= |
866 |
*/ |
867 |
|
868 |
/* Free a NetIO UDP descriptor */ |
869 |
static void netio_udp_free(netio_inet_desc_t *nid) |
870 |
{ |
871 |
if (nid->remote_host) { |
872 |
free(nid->remote_host); |
873 |
nid->remote_host = NULL; |
874 |
} |
875 |
|
876 |
if (nid->fd != -1) |
877 |
close(nid->fd); |
878 |
} |
879 |
|
880 |
/* Write a packet to an UDP socket */ |
881 |
static ssize_t netio_udp_send(netio_inet_desc_t *nid,void *pkt,size_t pkt_len) |
882 |
{ |
883 |
return(send(nid->fd,pkt,pkt_len,0)); |
884 |
} |
885 |
|
886 |
/* Receive a packet from an UDP socket */ |
887 |
static ssize_t netio_udp_recv(netio_inet_desc_t *nid,void *pkt,size_t max_len) |
888 |
{ |
889 |
return(recvfrom(nid->fd,pkt,max_len,0,NULL,NULL)); |
890 |
} |
891 |
|
892 |
/* Save the NIO configuration */ |
893 |
static void netio_udp_save_cfg(netio_desc_t *nio,FILE *fd) |
894 |
{ |
895 |
netio_inet_desc_t *nid = nio->dptr; |
896 |
fprintf(fd,"nio create_udp %s %d %s %d\n", |
897 |
nio->name,nid->local_port,nid->remote_host,nid->remote_port); |
898 |
} |
899 |
|
900 |
/* Create a new NetIO descriptor with UDP method */ |
901 |
netio_desc_t *netio_desc_create_udp(char *nio_name,int local_port, |
902 |
char *remote_host,int remote_port) |
903 |
{ |
904 |
netio_inet_desc_t *nid; |
905 |
netio_desc_t *nio; |
906 |
|
907 |
if (!(nio = netio_create(nio_name))) |
908 |
return NULL; |
909 |
|
910 |
nid = &nio->u.nid; |
911 |
nid->local_port = local_port; |
912 |
nid->remote_port = remote_port; |
913 |
|
914 |
if (!(nid->remote_host = strdup(remote_host))) { |
915 |
fprintf(stderr,"netio_desc_create_udp: insufficient memory\n"); |
916 |
goto error; |
917 |
} |
918 |
|
919 |
if ((nid->fd = udp_connect(local_port,remote_host,remote_port)) < 0) { |
920 |
fprintf(stderr,"netio_desc_create_udp: unable to connect to %s:%d\n", |
921 |
remote_host,remote_port); |
922 |
goto error; |
923 |
} |
924 |
|
925 |
nio->type = NETIO_TYPE_UDP; |
926 |
nio->send = (void *)netio_udp_send; |
927 |
nio->recv = (void *)netio_udp_recv; |
928 |
nio->save_cfg = netio_udp_save_cfg; |
929 |
nio->dptr = &nio->u.nid; |
930 |
|
931 |
if (netio_record(nio) == -1) |
932 |
goto error; |
933 |
|
934 |
return nio; |
935 |
|
936 |
error: |
937 |
netio_free(nio,NULL); |
938 |
return NULL; |
939 |
} |
940 |
|
941 |
/* |
942 |
* ========================================================================= |
943 |
* Linux RAW Ethernet driver |
944 |
* ========================================================================= |
945 |
*/ |
946 |
#ifdef LINUX_ETH |
947 |
/* Free a NetIO raw ethernet descriptor */ |
948 |
static void netio_lnxeth_free(netio_lnxeth_desc_t *nled) |
949 |
{ |
950 |
if (nled->fd != -1) |
951 |
close(nled->fd); |
952 |
} |
953 |
|
954 |
/* Write a packet to a raw Ethernet socket */ |
955 |
static ssize_t netio_lnxeth_send(netio_lnxeth_desc_t *nled, |
956 |
void *pkt,size_t pkt_len) |
957 |
{ |
958 |
return(lnx_eth_send(nled->fd,nled->dev_id,pkt,pkt_len)); |
959 |
} |
960 |
|
961 |
/* Receive a packet from an raw Ethernet socket */ |
962 |
static ssize_t netio_lnxeth_recv(netio_lnxeth_desc_t *nled, |
963 |
void *pkt,size_t max_len) |
964 |
{ |
965 |
return(lnx_eth_recv(nled->fd,pkt,max_len)); |
966 |
} |
967 |
|
968 |
/* Save the NIO configuration */ |
969 |
static void netio_lnxeth_save_cfg(netio_desc_t *nio,FILE *fd) |
970 |
{ |
971 |
netio_lnxeth_desc_t *nled = nio->dptr; |
972 |
fprintf(fd,"nio create_linux_eth %s %s\n",nio->name,nled->dev_name); |
973 |
} |
974 |
|
975 |
/* Create a new NetIO descriptor with raw Ethernet method */ |
976 |
netio_desc_t *netio_desc_create_lnxeth(char *nio_name,char *dev_name) |
977 |
{ |
978 |
netio_lnxeth_desc_t *nled; |
979 |
netio_desc_t *nio; |
980 |
|
981 |
if (!(nio = netio_create(nio_name))) |
982 |
return NULL; |
983 |
|
984 |
nled = &nio->u.nled; |
985 |
|
986 |
if (strlen(dev_name) >= NETIO_DEV_MAXLEN) { |
987 |
fprintf(stderr,"netio_desc_create_lnxeth: bad Ethernet device string " |
988 |
"specified.\n"); |
989 |
netio_free(nio,NULL); |
990 |
return NULL; |
991 |
} |
992 |
|
993 |
strcpy(nled->dev_name,dev_name); |
994 |
|
995 |
nled->fd = lnx_eth_init_socket(dev_name); |
996 |
nled->dev_id = lnx_eth_get_dev_index(dev_name); |
997 |
|
998 |
if (nled->fd < 0) { |
999 |
netio_free(nio,NULL); |
1000 |
return NULL; |
1001 |
} |
1002 |
|
1003 |
nio->type = NETIO_TYPE_LINUX_ETH; |
1004 |
nio->send = (void *)netio_lnxeth_send; |
1005 |
nio->recv = (void *)netio_lnxeth_recv; |
1006 |
nio->save_cfg = netio_lnxeth_save_cfg; |
1007 |
nio->dptr = &nio->u.nled; |
1008 |
|
1009 |
if (netio_record(nio) == -1) { |
1010 |
netio_free(nio,NULL); |
1011 |
return NULL; |
1012 |
} |
1013 |
|
1014 |
return nio; |
1015 |
} |
1016 |
#endif /* LINUX_ETH */ |
1017 |
|
1018 |
/* |
1019 |
* ========================================================================= |
1020 |
* Generic RAW Ethernet driver |
1021 |
* ========================================================================= |
1022 |
*/ |
1023 |
#ifdef GEN_ETH |
1024 |
/* Free a NetIO raw ethernet descriptor */ |
1025 |
static void netio_geneth_free(netio_geneth_desc_t *nged) |
1026 |
{ |
1027 |
gen_eth_close(nged->pcap_dev); |
1028 |
} |
1029 |
|
1030 |
/* Write a packet to an Ethernet device */ |
1031 |
static ssize_t netio_geneth_send(netio_geneth_desc_t *nged, |
1032 |
void *pkt,size_t pkt_len) |
1033 |
{ |
1034 |
return(gen_eth_send(nged->pcap_dev,pkt,pkt_len)); |
1035 |
} |
1036 |
|
1037 |
/* Receive a packet from an Ethernet device */ |
1038 |
static ssize_t netio_geneth_recv(netio_geneth_desc_t *nged, |
1039 |
void *pkt,size_t max_len) |
1040 |
{ |
1041 |
return(gen_eth_recv(nged->pcap_dev,pkt,max_len)); |
1042 |
} |
1043 |
|
1044 |
/* Save the NIO configuration */ |
1045 |
static void netio_geneth_save_cfg(netio_desc_t *nio,FILE *fd) |
1046 |
{ |
1047 |
netio_geneth_desc_t *nged = nio->dptr; |
1048 |
fprintf(fd,"nio create_gen_eth %s %s\n",nio->name,nged->dev_name); |
1049 |
} |
1050 |
|
1051 |
/* Create a new NetIO descriptor with generic raw Ethernet method */ |
1052 |
netio_desc_t *netio_desc_create_geneth(char *nio_name,char *dev_name) |
1053 |
{ |
1054 |
netio_geneth_desc_t *nged; |
1055 |
netio_desc_t *nio; |
1056 |
|
1057 |
if (!(nio = netio_create(nio_name))) |
1058 |
return NULL; |
1059 |
|
1060 |
nged = &nio->u.nged; |
1061 |
|
1062 |
if (strlen(dev_name) >= NETIO_DEV_MAXLEN) { |
1063 |
fprintf(stderr,"netio_desc_create_geneth: bad Ethernet device string " |
1064 |
"specified.\n"); |
1065 |
netio_free(nio,NULL); |
1066 |
return NULL; |
1067 |
} |
1068 |
|
1069 |
strcpy(nged->dev_name,dev_name); |
1070 |
|
1071 |
if (!(nged->pcap_dev = gen_eth_init(dev_name))) { |
1072 |
netio_free(nio,NULL); |
1073 |
return NULL; |
1074 |
} |
1075 |
|
1076 |
nio->type = NETIO_TYPE_GEN_ETH; |
1077 |
nio->send = (void *)netio_geneth_send; |
1078 |
nio->recv = (void *)netio_geneth_recv; |
1079 |
nio->save_cfg = netio_geneth_save_cfg; |
1080 |
nio->dptr = &nio->u.nged; |
1081 |
|
1082 |
if (netio_record(nio) == -1) { |
1083 |
netio_free(nio,NULL); |
1084 |
return NULL; |
1085 |
} |
1086 |
|
1087 |
return nio; |
1088 |
} |
1089 |
#endif /* GEN_ETH */ |
1090 |
|
1091 |
/* |
1092 |
* ========================================================================= |
1093 |
* FIFO Driver (intra-hypervisor communications) |
1094 |
* ========================================================================= |
1095 |
*/ |
1096 |
|
1097 |
/* Extract the first packet of the FIFO */ |
1098 |
static netio_fifo_pkt_t *netio_fifo_extract_pkt(netio_fifo_desc_t *nfd) |
1099 |
{ |
1100 |
netio_fifo_pkt_t *p; |
1101 |
|
1102 |
if (!(p = nfd->head)) |
1103 |
return NULL; |
1104 |
|
1105 |
nfd->pkt_count--; |
1106 |
nfd->head = p->next; |
1107 |
|
1108 |
if (!nfd->head) |
1109 |
nfd->last = NULL; |
1110 |
|
1111 |
return p; |
1112 |
} |
1113 |
|
1114 |
/* Insert a packet into the FIFO (in tail) */ |
1115 |
static void netio_fifo_insert_pkt(netio_fifo_desc_t *nfd,netio_fifo_pkt_t *p) |
1116 |
{ |
1117 |
pthread_mutex_lock(&nfd->lock); |
1118 |
|
1119 |
nfd->pkt_count++; |
1120 |
p->next = NULL; |
1121 |
|
1122 |
if (nfd->last) { |
1123 |
nfd->last->next = p; |
1124 |
} else { |
1125 |
nfd->head = p; |
1126 |
} |
1127 |
|
1128 |
nfd->last = p; |
1129 |
pthread_mutex_unlock(&nfd->lock); |
1130 |
} |
1131 |
|
1132 |
/* Free the packet list */ |
1133 |
static void netio_fifo_free_pkt_list(netio_fifo_desc_t *nfd) |
1134 |
{ |
1135 |
netio_fifo_pkt_t *p,*next; |
1136 |
|
1137 |
for(p=nfd->head;p;p=next) { |
1138 |
next = p->next; |
1139 |
free(p); |
1140 |
} |
1141 |
|
1142 |
nfd->head = nfd->last = NULL; |
1143 |
nfd->pkt_count = 0; |
1144 |
} |
1145 |
|
1146 |
/* Establish a cross-connect between two FIFO NetIO */ |
1147 |
int netio_fifo_crossconnect(netio_desc_t *a,netio_desc_t *b) |
1148 |
{ |
1149 |
netio_fifo_desc_t *pa,*pb; |
1150 |
|
1151 |
if ((a->type != NETIO_TYPE_FIFO) || (b->type != NETIO_TYPE_FIFO)) |
1152 |
return(-1); |
1153 |
|
1154 |
pa = &a->u.nfd; |
1155 |
pb = &b->u.nfd; |
1156 |
|
1157 |
/* A => B */ |
1158 |
pthread_mutex_lock(&pa->endpoint_lock); |
1159 |
pthread_mutex_lock(&pa->lock); |
1160 |
pa->endpoint = pb; |
1161 |
netio_fifo_free_pkt_list(pa); |
1162 |
pthread_mutex_unlock(&pa->lock); |
1163 |
pthread_mutex_unlock(&pa->endpoint_lock); |
1164 |
|
1165 |
/* B => A */ |
1166 |
pthread_mutex_lock(&pb->endpoint_lock); |
1167 |
pthread_mutex_lock(&pb->lock); |
1168 |
pb->endpoint = pa; |
1169 |
netio_fifo_free_pkt_list(pb); |
1170 |
pthread_mutex_unlock(&pb->lock); |
1171 |
pthread_mutex_unlock(&pb->endpoint_lock); |
1172 |
return(0); |
1173 |
} |
1174 |
|
1175 |
/* Unbind an endpoint */ |
1176 |
static void netio_fifo_unbind_endpoint(netio_fifo_desc_t *nfd) |
1177 |
{ |
1178 |
pthread_mutex_lock(&nfd->endpoint_lock); |
1179 |
nfd->endpoint = NULL; |
1180 |
pthread_mutex_unlock(&nfd->endpoint_lock); |
1181 |
} |
1182 |
|
1183 |
/* Free a NetIO FIFO descriptor */ |
1184 |
static void netio_fifo_free(netio_fifo_desc_t *nfd) |
1185 |
{ |
1186 |
if (nfd->endpoint) |
1187 |
netio_fifo_unbind_endpoint(nfd->endpoint); |
1188 |
|
1189 |
netio_fifo_free_pkt_list(nfd); |
1190 |
pthread_mutex_destroy(&nfd->lock); |
1191 |
pthread_cond_destroy(&nfd->cond); |
1192 |
} |
1193 |
|
1194 |
/* Send a packet (to the endpoint FIFO) */ |
1195 |
static ssize_t netio_fifo_send(netio_fifo_desc_t *nfd,void *pkt,size_t pkt_len) |
1196 |
{ |
1197 |
netio_fifo_pkt_t *p; |
1198 |
size_t len; |
1199 |
|
1200 |
pthread_mutex_lock(&nfd->endpoint_lock); |
1201 |
|
1202 |
/* The cross-connect must have been established before */ |
1203 |
if (!nfd->endpoint) |
1204 |
goto error; |
1205 |
|
1206 |
/* Allocate a a new packet and insert it into the endpoint FIFO */ |
1207 |
len = sizeof(netio_fifo_pkt_t) + pkt_len; |
1208 |
if (!(p = malloc(len))) |
1209 |
goto error; |
1210 |
|
1211 |
memcpy(p->pkt,pkt,pkt_len); |
1212 |
p->pkt_len = pkt_len; |
1213 |
netio_fifo_insert_pkt(nfd->endpoint,p); |
1214 |
pthread_cond_signal(&nfd->endpoint->cond); |
1215 |
pthread_mutex_unlock(&nfd->endpoint_lock); |
1216 |
return(pkt_len); |
1217 |
|
1218 |
error: |
1219 |
pthread_mutex_unlock(&nfd->endpoint_lock); |
1220 |
return(-1); |
1221 |
} |
1222 |
|
1223 |
/* Read a packet from the local FIFO queue */ |
1224 |
static ssize_t netio_fifo_recv(netio_fifo_desc_t *nfd,void *pkt,size_t max_len) |
1225 |
{ |
1226 |
struct timespec ts; |
1227 |
m_tmcnt_t expire; |
1228 |
netio_fifo_pkt_t *p; |
1229 |
size_t len = -1; |
1230 |
|
1231 |
/* Wait for the endpoint to signal a new arriving packet */ |
1232 |
expire = m_gettime_usec() + 50000; |
1233 |
ts.tv_sec = expire / 1000000; |
1234 |
ts.tv_nsec = (expire % 1000000) * 1000; |
1235 |
|
1236 |
pthread_mutex_lock(&nfd->lock); |
1237 |
pthread_cond_timedwait(&nfd->cond,&nfd->lock,&ts); |
1238 |
|
1239 |
/* Extract a packet from the list */ |
1240 |
p = netio_fifo_extract_pkt(nfd); |
1241 |
pthread_mutex_unlock(&nfd->lock); |
1242 |
|
1243 |
if (p) { |
1244 |
len = m_min(p->pkt_len,max_len); |
1245 |
memcpy(pkt,p->pkt,len); |
1246 |
free(p); |
1247 |
} |
1248 |
|
1249 |
return(len); |
1250 |
} |
1251 |
|
1252 |
/* Create a new NetIO descriptor with FIFO method */ |
1253 |
netio_desc_t *netio_desc_create_fifo(char *nio_name) |
1254 |
{ |
1255 |
netio_fifo_desc_t *nfd; |
1256 |
netio_desc_t *nio; |
1257 |
|
1258 |
if (!(nio = netio_create(nio_name))) |
1259 |
return NULL; |
1260 |
|
1261 |
nfd = &nio->u.nfd; |
1262 |
pthread_mutex_init(&nfd->lock,NULL); |
1263 |
pthread_mutex_init(&nfd->endpoint_lock,NULL); |
1264 |
pthread_cond_init(&nfd->cond,NULL); |
1265 |
|
1266 |
nio->type = NETIO_TYPE_FIFO; |
1267 |
nio->send = (void *)netio_fifo_send; |
1268 |
nio->recv = (void *)netio_fifo_recv; |
1269 |
nio->dptr = nfd; |
1270 |
|
1271 |
if (netio_record(nio) == -1) { |
1272 |
netio_free(nio,NULL); |
1273 |
return NULL; |
1274 |
} |
1275 |
|
1276 |
return nio; |
1277 |
} |
1278 |
|
1279 |
/* |
1280 |
* ========================================================================= |
1281 |
* NULL Driver (does nothing, used for debugging) |
1282 |
* ========================================================================= |
1283 |
*/ |
1284 |
static ssize_t netio_null_send(void *null_ptr,void *pkt,size_t pkt_len) |
1285 |
{ |
1286 |
return(pkt_len); |
1287 |
} |
1288 |
|
1289 |
static ssize_t netio_null_recv(void *null_ptr,void *pkt,size_t max_len) |
1290 |
{ |
1291 |
usleep(200000); |
1292 |
return(-1); |
1293 |
} |
1294 |
|
1295 |
static void netio_null_save_cfg(netio_desc_t *nio,FILE *fd) |
1296 |
{ |
1297 |
fprintf(fd,"nio create_null %s\n",nio->name); |
1298 |
} |
1299 |
|
1300 |
/* Create a new NetIO descriptor with NULL method */ |
1301 |
netio_desc_t *netio_desc_create_null(char *nio_name) |
1302 |
{ |
1303 |
netio_desc_t *nio; |
1304 |
|
1305 |
if (!(nio = netio_create(nio_name))) |
1306 |
return NULL; |
1307 |
|
1308 |
nio->type = NETIO_TYPE_NULL; |
1309 |
nio->send = (void *)netio_null_send; |
1310 |
nio->recv = (void *)netio_null_recv; |
1311 |
nio->save_cfg = netio_null_save_cfg; |
1312 |
nio->dptr = NULL; |
1313 |
|
1314 |
if (netio_record(nio) == -1) { |
1315 |
netio_free(nio,NULL); |
1316 |
return NULL; |
1317 |
} |
1318 |
|
1319 |
return nio; |
1320 |
} |
1321 |
|
1322 |
/* Free a NetIO descriptor */ |
1323 |
static int netio_free(void *data,void *arg) |
1324 |
{ |
1325 |
netio_desc_t *nio = data; |
1326 |
|
1327 |
if (nio) { |
1328 |
netio_filter_unbind(nio,NETIO_FILTER_DIR_RX); |
1329 |
netio_filter_unbind(nio,NETIO_FILTER_DIR_TX); |
1330 |
|
1331 |
switch(nio->type) { |
1332 |
case NETIO_TYPE_UNIX: |
1333 |
netio_unix_free(&nio->u.nud); |
1334 |
break; |
1335 |
case NETIO_TYPE_VDE: |
1336 |
netio_vde_free(&nio->u.nvd); |
1337 |
break; |
1338 |
case NETIO_TYPE_TAP: |
1339 |
netio_tap_free(&nio->u.ntd); |
1340 |
break; |
1341 |
case NETIO_TYPE_TCP_CLI: |
1342 |
case NETIO_TYPE_TCP_SER: |
1343 |
netio_tcp_free(&nio->u.nid); |
1344 |
break; |
1345 |
case NETIO_TYPE_UDP: |
1346 |
netio_udp_free(&nio->u.nid); |
1347 |
break; |
1348 |
#ifdef LINUX_ETH |
1349 |
case NETIO_TYPE_LINUX_ETH: |
1350 |
netio_lnxeth_free(&nio->u.nled); |
1351 |
break; |
1352 |
#endif |
1353 |
#ifdef GEN_ETH |
1354 |
case NETIO_TYPE_GEN_ETH: |
1355 |
netio_geneth_free(&nio->u.nged); |
1356 |
break; |
1357 |
#endif |
1358 |
case NETIO_TYPE_FIFO: |
1359 |
netio_fifo_free(&nio->u.nfd); |
1360 |
break; |
1361 |
case NETIO_TYPE_NULL: |
1362 |
break; |
1363 |
default: |
1364 |
fprintf(stderr,"NETIO: unknown descriptor type %u\n",nio->type); |
1365 |
} |
1366 |
|
1367 |
free(nio->name); |
1368 |
free(nio); |
1369 |
} |
1370 |
|
1371 |
return(TRUE); |
1372 |
} |
1373 |
|
1374 |
/* |
1375 |
* ========================================================================= |
1376 |
* RX Listeners |
1377 |
* ========================================================================= |
1378 |
*/ |
1379 |
|
1380 |
/* Find a RX listener */ |
1381 |
static inline struct netio_rx_listener *netio_rxl_find(netio_desc_t *nio) |
1382 |
{ |
1383 |
struct netio_rx_listener *rxl; |
1384 |
|
1385 |
for(rxl=netio_rxl_list;rxl;rxl=rxl->next) |
1386 |
if (rxl->nio == nio) |
1387 |
return rxl; |
1388 |
|
1389 |
return NULL; |
1390 |
} |
1391 |
|
1392 |
/* Remove a NIO from the listener list */ |
1393 |
static int netio_rxl_remove_internal(netio_desc_t *nio) |
1394 |
{ |
1395 |
struct netio_rx_listener *rxl; |
1396 |
int res = -1; |
1397 |
|
1398 |
if ((rxl = netio_rxl_find(nio))) { |
1399 |
/* we suppress this NIO only when the ref count hits 0 */ |
1400 |
rxl->ref_count--; |
1401 |
|
1402 |
if (!rxl->ref_count) { |
1403 |
/* remove this listener from the double linked list */ |
1404 |
if (rxl->next) |
1405 |
rxl->next->prev = rxl->prev; |
1406 |
|
1407 |
if (rxl->prev) |
1408 |
rxl->prev->next = rxl->next; |
1409 |
else |
1410 |
netio_rxl_list = rxl->next; |
1411 |
|
1412 |
/* if this is non-FD NIO, wait for thread to terminate */ |
1413 |
if (netio_get_fd(rxl->nio) == -1) { |
1414 |
rxl->running = FALSE; |
1415 |
pthread_join(rxl->spec_thread,NULL); |
1416 |
} |
1417 |
|
1418 |
free(rxl); |
1419 |
} |
1420 |
|
1421 |
res = 0; |
1422 |
} |
1423 |
|
1424 |
return(res); |
1425 |
} |
1426 |
|
1427 |
/* Add a RXL listener to the listener list */ |
1428 |
static void netio_rxl_add_internal(struct netio_rx_listener *rxl) |
1429 |
{ |
1430 |
struct netio_rx_listener *tmp; |
1431 |
|
1432 |
if ((tmp = netio_rxl_find(rxl->nio))) { |
1433 |
tmp->ref_count++; |
1434 |
free(rxl); |
1435 |
} else { |
1436 |
rxl->prev = NULL; |
1437 |
rxl->next = netio_rxl_list; |
1438 |
if (rxl->next) rxl->next->prev = rxl; |
1439 |
netio_rxl_list = rxl; |
1440 |
} |
1441 |
} |
1442 |
|
1443 |
/* RX Listener dedicated thread (for non-FD NIO) */ |
1444 |
static void *netio_rxl_spec_thread(void *arg) |
1445 |
{ |
1446 |
struct netio_rx_listener *rxl = arg; |
1447 |
u_char pkt[NETIO_MAX_PKT_SIZE]; |
1448 |
ssize_t pkt_len; |
1449 |
|
1450 |
while(rxl->running) { |
1451 |
pkt_len = netio_recv(rxl->nio,pkt,sizeof(pkt)); |
1452 |
|
1453 |
if (pkt_len > 0) |
1454 |
rxl->rx_handler(rxl->nio,pkt,pkt_len,rxl->arg1,rxl->arg2); |
1455 |
} |
1456 |
|
1457 |
return NULL; |
1458 |
} |
1459 |
|
1460 |
/* RX Listener General Thread */ |
1461 |
void *netio_rxl_gen_thread(void *arg) |
1462 |
{ |
1463 |
struct netio_rx_listener *rxl; |
1464 |
u_char pkt[NETIO_MAX_PKT_SIZE]; |
1465 |
ssize_t pkt_len; |
1466 |
netio_desc_t *nio; |
1467 |
struct timeval tv; |
1468 |
int fd,fd_max,res; |
1469 |
fd_set rfds; |
1470 |
|
1471 |
for(;;) { |
1472 |
NETIO_RXL_LOCK(); |
1473 |
|
1474 |
NETIO_RXQ_LOCK(); |
1475 |
/* Add the new waiting NIO to the active list */ |
1476 |
while(netio_rxl_add_list != NULL) { |
1477 |
rxl = netio_rxl_add_list; |
1478 |
netio_rxl_add_list = netio_rxl_add_list->next; |
1479 |
netio_rxl_add_internal(rxl); |
1480 |
} |
1481 |
|
1482 |
/* Delete the NIO present in the remove list */ |
1483 |
while(netio_rxl_remove_list != NULL) { |
1484 |
nio = netio_rxl_remove_list; |
1485 |
netio_rxl_remove_list = netio_rxl_remove_list->rxl_next; |
1486 |
netio_rxl_remove_internal(nio); |
1487 |
} |
1488 |
|
1489 |
pthread_cond_broadcast(&netio_rxl_cond); |
1490 |
NETIO_RXQ_UNLOCK(); |
1491 |
|
1492 |
/* Build the FD set */ |
1493 |
FD_ZERO(&rfds); |
1494 |
fd_max = -1; |
1495 |
for(rxl=netio_rxl_list;rxl;rxl=rxl->next) { |
1496 |
if ((fd = netio_get_fd(rxl->nio)) == -1) |
1497 |
continue; |
1498 |
|
1499 |
if (fd > fd_max) fd_max = fd; |
1500 |
FD_SET(fd,&rfds); |
1501 |
} |
1502 |
NETIO_RXL_UNLOCK(); |
1503 |
|
1504 |
/* Wait for incoming packets */ |
1505 |
tv.tv_sec = 0; |
1506 |
tv.tv_usec = 200 * 1000; /* 200 ms */ |
1507 |
res = select(fd_max+1,&rfds,NULL,NULL,&tv); |
1508 |
|
1509 |
if (res == -1) { |
1510 |
if (errno != EINTR) |
1511 |
perror("netio_rxl_thread: select"); |
1512 |
continue; |
1513 |
} |
1514 |
|
1515 |
/* Examine active FDs and call user handlers */ |
1516 |
NETIO_RXL_LOCK(); |
1517 |
|
1518 |
for(rxl=netio_rxl_list;rxl;rxl=rxl->next) { |
1519 |
if ((fd = netio_get_fd(rxl->nio)) == -1) |
1520 |
continue; |
1521 |
|
1522 |
if (FD_ISSET(fd,&rfds)) { |
1523 |
pkt_len = netio_recv(rxl->nio,pkt,sizeof(pkt)); |
1524 |
|
1525 |
if (pkt_len > 0) |
1526 |
rxl->rx_handler(rxl->nio,pkt,pkt_len,rxl->arg1,rxl->arg2); |
1527 |
} |
1528 |
} |
1529 |
|
1530 |
NETIO_RXL_UNLOCK(); |
1531 |
} |
1532 |
|
1533 |
return NULL; |
1534 |
} |
1535 |
|
1536 |
/* Add a RX listener in the listener list */ |
1537 |
int netio_rxl_add(netio_desc_t *nio,netio_rx_handler_t rx_handler, |
1538 |
void *arg1,void *arg2) |
1539 |
{ |
1540 |
struct netio_rx_listener *rxl; |
1541 |
|
1542 |
NETIO_RXQ_LOCK(); |
1543 |
|
1544 |
if (!(rxl = malloc(sizeof(*rxl)))) { |
1545 |
NETIO_RXQ_UNLOCK(); |
1546 |
fprintf(stderr,"netio_rxl_add: unable to create structure.\n"); |
1547 |
return(-1); |
1548 |
} |
1549 |
|
1550 |
memset(rxl,0,sizeof(*rxl)); |
1551 |
rxl->nio = nio; |
1552 |
rxl->ref_count = 1; |
1553 |
rxl->rx_handler = rx_handler; |
1554 |
rxl->arg1 = arg1; |
1555 |
rxl->arg2 = arg2; |
1556 |
rxl->running = TRUE; |
1557 |
|
1558 |
if ((netio_get_fd(rxl->nio) == -1) && |
1559 |
pthread_create(&rxl->spec_thread,NULL,netio_rxl_spec_thread,rxl)) |
1560 |
{ |
1561 |
NETIO_RXQ_UNLOCK(); |
1562 |
fprintf(stderr,"netio_rxl_add: unable to create specific thread.\n"); |
1563 |
free(rxl); |
1564 |
return(-1); |
1565 |
} |
1566 |
|
1567 |
rxl->next = netio_rxl_add_list; |
1568 |
netio_rxl_add_list = rxl; |
1569 |
|
1570 |
pthread_cond_wait(&netio_rxl_cond,&netio_rxq_mutex); |
1571 |
NETIO_RXQ_UNLOCK(); |
1572 |
return(0); |
1573 |
} |
1574 |
|
1575 |
/* Remove a NIO from the listener list */ |
1576 |
int netio_rxl_remove(netio_desc_t *nio) |
1577 |
{ |
1578 |
NETIO_RXQ_LOCK(); |
1579 |
nio->rxl_next = netio_rxl_remove_list; |
1580 |
netio_rxl_remove_list = nio; |
1581 |
pthread_cond_wait(&netio_rxl_cond,&netio_rxq_mutex); |
1582 |
NETIO_RXQ_UNLOCK(); |
1583 |
return(0); |
1584 |
} |
1585 |
|
1586 |
/* Initialize the RXL thread */ |
1587 |
int netio_rxl_init(void) |
1588 |
{ |
1589 |
pthread_cond_init(&netio_rxl_cond,NULL); |
1590 |
|
1591 |
if (pthread_create(&netio_rxl_thread,NULL,netio_rxl_gen_thread,NULL)) { |
1592 |
perror("netio_rxl_init: pthread_create"); |
1593 |
return(-1); |
1594 |
} |
1595 |
|
1596 |
return(0); |
1597 |
} |