1 /* for io_module_func def'ns */
2 #include "io_module.h"
3 /* for mtcp related def'ns */
4 #include "mtcp.h"
5 /* for errno */
6 #include <errno.h>
7 /* for logging */
8 #include "debug.h"
9 /* for num_devices_* */
10 #include "config.h"
11 
12 #include <string.h>
13 #include <pcap.h>
14 
15 /*----------------------------------------------------------------------------*/
16 struct pcap_private_context {
17 	pcap_t *handle[MAX_DEVICES];
18 	char   *dev_name[MAX_DEVICES];
19 
20 	struct pcap_pkthdr phdr;
21 	const u_char *rdata;
22 	u_char wdata[ETHERNET_FRAME_LEN];
23 	uint16_t count[MAX_DEVICES];
24 } g_pcap_ctx;
25 
26 #define PCAP_BUFFER_SIZE	(1048576 * 16U)
27 /*----------------------------------------------------------------------------*/
28 void
pcap_init_handle(struct mtcp_thread_context * ctxt)29 pcap_init_handle(struct mtcp_thread_context *ctxt)
30 {
31 	ctxt->io_private_context = &g_pcap_ctx;
32 }
33 /*----------------------------------------------------------------------------*/
34 int32_t
pcap_recv_pkts(struct mtcp_thread_context * ctxt,int ifidx)35 pcap_recv_pkts(struct mtcp_thread_context *ctxt, int ifidx)
36 {
37 	if (ifidx < 0 || ifidx >= MAX_DEVICES)
38 		return -1;
39 
40 	struct pcap_private_context *ppc = ctxt->io_private_context;
41 	if ((ppc->rdata = pcap_next(ppc->handle[ifidx], &ppc->phdr)) == NULL)
42 		return 0;
43 
44 	if (ppc->phdr.caplen != ppc->phdr.len)
45 		TRACE_ERROR("caplen = %u, len: %u\n",
46 			    ppc->phdr.caplen,
47 			    ppc->phdr.len);
48 
49 	/* sanity check */
50 	if (ppc->rdata == NULL)
51 		return 0;
52 
53 	return 1; /* PCAP always receives only one packet */
54 }
55 /*----------------------------------------------------------------------------*/
56 uint8_t *
pcap_get_rptr(struct mtcp_thread_context * ctxt,int ifidx,int index,uint16_t * len)57 pcap_get_rptr(struct mtcp_thread_context *ctxt, int ifidx, int index, uint16_t *len)
58 {
59 	struct pcap_private_context *ppc = ctxt->io_private_context;
60 	if (ppc->rdata == NULL)
61 		return NULL;
62 
63 	*len = ppc->phdr.caplen;
64 	return (uint8_t *)ppc->rdata;
65 }
66 /*----------------------------------------------------------------------------*/
67 int
pcap_send_pkts(struct mtcp_thread_context * ctxt,int nif)68 pcap_send_pkts(struct mtcp_thread_context *ctxt, int nif)
69 {
70 	int ret = 0;
71 	struct pcap_private_context *ppc = ctxt->io_private_context;
72 
73 	if (ppc->count[nif] > 0) {
74 		ret = pcap_inject(ppc->handle[nif], ppc->wdata, ppc->phdr.len);
75 	}
76 
77 	ppc->count[nif] = 0;
78 	return (ret != -1) ? 1 : 0;
79 }
80 /*----------------------------------------------------------------------------*/
81 uint8_t *
pcap_get_wptr(struct mtcp_thread_context * ctxt,int ifidx,uint16_t pktsize)82 pcap_get_wptr(struct mtcp_thread_context *ctxt, int ifidx, uint16_t pktsize)
83 {
84 	struct pcap_private_context *ppc = ctxt->io_private_context;
85 	/* phdr can be reused */
86 	ppc->phdr.caplen = ppc->phdr.len = pktsize;
87 	ppc->count[ifidx] = 1;
88 	return ppc->wdata;
89 }
90 /*----------------------------------------------------------------------------*/
91 int
pcap_get_nif(struct ifreq * ifr)92 pcap_get_nif(struct ifreq *ifr)
93 {
94 	int i;
95 
96 	for (i = 0; i < g_config.mos->netdev_table->num; i++)
97 		if (!strcmp(ifr->ifr_name, g_pcap_ctx.dev_name[i]))
98 			return i;
99 
100 	return -1;
101 }
102 /*----------------------------------------------------------------------------*/
103 int32_t
pcap_select(struct mtcp_thread_context * ctxt)104 pcap_select(struct mtcp_thread_context *ctxt)
105 {
106 	return 0;
107 }
108 /*----------------------------------------------------------------------------*/
109 void
pcap_destroy_handle(struct mtcp_thread_context * ctxt)110 pcap_destroy_handle(struct mtcp_thread_context *ctxt)
111 {
112 	int i;
113 	struct pcap_private_context *ppc = ctxt->io_private_context;
114 	if (!ppc)
115 		return;
116 
117 	for (i = 0; i < g_config.mos->netdev_table->num; i++) {
118 		pcap_close(ppc->handle[i]);
119 	}
120 
121 	ctxt->io_private_context = NULL;
122 }
123 /*----------------------------------------------------------------------------*/
124 void
pcap_load_module_upper_half(void)125 pcap_load_module_upper_half(void)
126 {
127 	int i;
128 	char errbuf[PCAP_ERRBUF_SIZE];
129 	struct netdev_entry **ent = g_config.mos->netdev_table->ent;
130 
131 	for (i = 0; i < g_config.mos->netdev_table->num; i++) {
132 #if 0
133 		g_pcap_ctx.handle[i] = pcap_open_live(ent[i]->dev_name, BUFSIZ, 1,
134 										1, errbuf);
135 		if (!g_pcap_ctx.handle[i]) {
136 			TRACE_ERROR("Interface '%s' not found\n", ent[i]->dev_name);
137 			exit(EXIT_FAILURE);
138 		}
139 #endif
140 		g_pcap_ctx.handle[i] = pcap_create(ent[i]->dev_name, errbuf);
141 		if (!g_pcap_ctx.handle[i]) {
142 			TRACE_ERROR("Interface '%s' not found\n", ent[i]->dev_name);
143 			exit(EXIT_FAILURE);
144 		}
145 		g_pcap_ctx.dev_name[i] = ent[i]->dev_name;
146 
147 		if (pcap_set_buffer_size(g_pcap_ctx.handle[i], PCAP_BUFFER_SIZE) != 0) {
148 			TRACE_ERROR("Can't increase buffer size to %u bytes\n",
149 				    PCAP_BUFFER_SIZE);
150 		}
151 
152 		if (pcap_activate(g_pcap_ctx.handle[i]) < 0) {
153 			TRACE_ERROR("Failed to activate pcap handle!\n");
154 			pcap_perror(g_pcap_ctx.handle[i], "");
155 			exit(EXIT_FAILURE);
156 		}
157 	}
158 
159 	num_queues = 1;
160 }
161 /*----------------------------------------------------------------------------*/
162 io_module_func pcap_module_func = {
163 	.load_module_upper_half	   = pcap_load_module_upper_half,
164 	.load_module_lower_half	   = NULL,
165 	.init_handle		   = pcap_init_handle,
166 	.link_devices		   = NULL,
167 	.release_pkt		   = NULL,
168 	.send_pkts		   = pcap_send_pkts,
169 	.get_wptr   		   = pcap_get_wptr,
170 	.set_wptr   		   = NULL,
171 	.recv_pkts		   = pcap_recv_pkts,
172 	.get_rptr	   	   = pcap_get_rptr,
173 	.select			   = NULL,
174 	.destroy_handle		   = pcap_destroy_handle,
175 	.dev_ioctl		   = NULL,
176 	.get_nif		   = pcap_get_nif,
177 };
178 /*----------------------------------------------------------------------------*/
179