/* for io_module_func def'ns */ #include "io_module.h" /* for mtcp related def'ns */ #include "mtcp.h" /* for errno */ #include /* for logging */ #include "debug.h" /* for num_devices_* */ #include "config.h" #include #include /*----------------------------------------------------------------------------*/ struct pcap_private_context { pcap_t *handle[MAX_DEVICES]; char *dev_name[MAX_DEVICES]; struct pcap_pkthdr phdr; const u_char *rdata; u_char wdata[ETHERNET_FRAME_LEN]; uint16_t count[MAX_DEVICES]; } g_pcap_ctx; #define PCAP_BUFFER_SIZE (1048576 * 16U) /*----------------------------------------------------------------------------*/ void pcap_init_handle(struct mtcp_thread_context *ctxt) { ctxt->io_private_context = &g_pcap_ctx; } /*----------------------------------------------------------------------------*/ int32_t pcap_recv_pkts(struct mtcp_thread_context *ctxt, int ifidx) { if (ifidx < 0 || ifidx >= MAX_DEVICES) return -1; struct pcap_private_context *ppc = ctxt->io_private_context; if ((ppc->rdata = pcap_next(ppc->handle[ifidx], &ppc->phdr)) == NULL) return 0; if (ppc->phdr.caplen != ppc->phdr.len) TRACE_ERROR("caplen = %u, len: %u\n", ppc->phdr.caplen, ppc->phdr.len); /* sanity check */ if (ppc->rdata == NULL) return 0; return 1; /* PCAP always receives only one packet */ } /*----------------------------------------------------------------------------*/ uint8_t * pcap_get_rptr(struct mtcp_thread_context *ctxt, int ifidx, int index, uint16_t *len) { struct pcap_private_context *ppc = ctxt->io_private_context; if (ppc->rdata == NULL) return NULL; *len = ppc->phdr.caplen; return (uint8_t *)ppc->rdata; } /*----------------------------------------------------------------------------*/ int pcap_send_pkts(struct mtcp_thread_context *ctxt, int nif) { int ret = 0; struct pcap_private_context *ppc = ctxt->io_private_context; if (ppc->count[nif] > 0) { ret = pcap_inject(ppc->handle[nif], ppc->wdata, ppc->phdr.len); } ppc->count[nif] = 0; return (ret != -1) ? 1 : 0; } /*----------------------------------------------------------------------------*/ uint8_t * pcap_get_wptr(struct mtcp_thread_context *ctxt, int ifidx, uint16_t pktsize) { struct pcap_private_context *ppc = ctxt->io_private_context; /* phdr can be reused */ ppc->phdr.caplen = ppc->phdr.len = pktsize; ppc->count[ifidx] = 1; return ppc->wdata; } /*----------------------------------------------------------------------------*/ int pcap_get_nif(struct ifreq *ifr) { int i; for (i = 0; i < g_config.mos->netdev_table->num; i++) if (!strcmp(ifr->ifr_name, g_pcap_ctx.dev_name[i])) return i; return -1; } /*----------------------------------------------------------------------------*/ int32_t pcap_select(struct mtcp_thread_context *ctxt) { return 0; } /*----------------------------------------------------------------------------*/ void pcap_destroy_handle(struct mtcp_thread_context *ctxt) { int i; struct pcap_private_context *ppc = ctxt->io_private_context; if (!ppc) return; for (i = 0; i < g_config.mos->netdev_table->num; i++) { pcap_close(ppc->handle[i]); } ctxt->io_private_context = NULL; } /*----------------------------------------------------------------------------*/ void pcap_load_module_upper_half(void) { int i; char errbuf[PCAP_ERRBUF_SIZE]; struct netdev_entry **ent = g_config.mos->netdev_table->ent; for (i = 0; i < g_config.mos->netdev_table->num; i++) { #if 0 g_pcap_ctx.handle[i] = pcap_open_live(ent[i]->dev_name, BUFSIZ, 1, 1, errbuf); if (!g_pcap_ctx.handle[i]) { TRACE_ERROR("Interface '%s' not found\n", ent[i]->dev_name); exit(EXIT_FAILURE); } #endif g_pcap_ctx.handle[i] = pcap_create(ent[i]->dev_name, errbuf); if (!g_pcap_ctx.handle[i]) { TRACE_ERROR("Interface '%s' not found\n", ent[i]->dev_name); exit(EXIT_FAILURE); } g_pcap_ctx.dev_name[i] = ent[i]->dev_name; if (pcap_set_buffer_size(g_pcap_ctx.handle[i], PCAP_BUFFER_SIZE) != 0) { TRACE_ERROR("Can't increase buffer size to %u bytes\n", PCAP_BUFFER_SIZE); } if (pcap_activate(g_pcap_ctx.handle[i]) < 0) { TRACE_ERROR("Failed to activate pcap handle!\n"); pcap_perror(g_pcap_ctx.handle[i], ""); exit(EXIT_FAILURE); } } num_queues = 1; } /*----------------------------------------------------------------------------*/ io_module_func pcap_module_func = { .load_module_upper_half = pcap_load_module_upper_half, .load_module_lower_half = NULL, .init_handle = pcap_init_handle, .link_devices = NULL, .release_pkt = NULL, .send_pkts = pcap_send_pkts, .get_wptr = pcap_get_wptr, .set_wptr = NULL, .recv_pkts = pcap_recv_pkts, .get_rptr = pcap_get_rptr, .select = NULL, .destroy_handle = pcap_destroy_handle, .dev_ioctl = NULL, .get_nif = pcap_get_nif, }; /*----------------------------------------------------------------------------*/