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