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 /* for netmap definitions */
12 #define NETMAP_WITH_LIBS
13 #include "netmap_user.h"
14 /* for poll */
15 #include <sys/poll.h>
16 /* for NBBY */
17 #include <sys/param.h>
18 /*----------------------------------------------------------------------------*/
19 #define MAX_PKT_BURST			64
20 #define ETHERNET_FRAME_SIZE		1514
21 #define MAX_IFNAMELEN			(IF_NAMESIZE + 10)
22 #define EXTRA_BUFS			512
23 #define IDLE_POLL_WAIT			1 /* msecs */
24 #define IDLE_POLL_COUNT			10
25 //#define CONST_POLLING			1
26 /*----------------------------------------------------------------------------*/
27 
28 struct netmap_private_context {
29 	struct nm_desc *local_nmd[MAX_DEVICES];
30 	unsigned char snd_pktbuf[MAX_DEVICES][ETHERNET_FRAME_SIZE];
31 	unsigned char *rcv_pktbuf[MAX_PKT_BURST];
32 	uint16_t rcv_pkt_len[MAX_PKT_BURST];
33 	uint16_t snd_pkt_size[MAX_DEVICES];
34 	uint8_t dev_poll_flag[MAX_DEVICES];
35 	uint8_t idle_poll_count;
36 } __attribute__((aligned(__WORDSIZE)));
37 /*----------------------------------------------------------------------------*/
38 void
netmap_init_handle(struct mtcp_thread_context * ctxt)39 netmap_init_handle(struct mtcp_thread_context *ctxt)
40 {
41 	struct netmap_private_context *npc;
42 	char ifname[MAX_IFNAMELEN];
43 	char nifname[MAX_IFNAMELEN];
44 	struct netdev_entry **ent;
45 	int j;
46 
47 	ent = g_config.mos->netdev_table->ent;
48 	/* create and initialize private I/O module context */
49 	ctxt->io_private_context = calloc(1, sizeof(struct netmap_private_context));
50 	if (ctxt->io_private_context == NULL) {
51 		TRACE_ERROR("Failed to initialize ctxt->io_private_context: "
52 			    "Can't allocate memory\n");
53 		exit(EXIT_FAILURE);
54 	}
55 
56 	npc = (struct netmap_private_context *)ctxt->io_private_context;
57 
58 	/* initialize per-thread netmap interfaces  */
59 	for (j = 0; j < g_config.mos->netdev_table->num; j++) {
60 #if 0
61 		if (if_indextoname(devices_attached[j], ifname) == NULL) {
62 			TRACE_ERROR("Failed to initialize interface %s with ifidx: %d - "
63 				    "error string: %s\n",
64 				    ifname, devices_attached[j], strerror(errno));
65 			exit(EXIT_FAILURE);
66 		}
67 #else
68 		strcpy(ifname, ent[j]->dev_name);
69 #endif
70 		if (unlikely(g_config.mos->num_cores == 1))
71 			sprintf(nifname, "netmap:%s", ifname);
72 		else
73 			sprintf(nifname, "netmap:%s-%d", ifname, ctxt->cpu);
74 
75 		TRACE_INFO("Opening %s with j: %d (cpu: %d)\n", nifname, j, ctxt->cpu);
76 
77 		struct nmreq base_nmd;
78 		memset(&base_nmd, 0, sizeof(base_nmd));
79 		base_nmd.nr_arg3 = EXTRA_BUFS;
80 
81 		npc->local_nmd[j] = nm_open(nifname, &base_nmd, 0, NULL);
82 		if (npc->local_nmd[j] == NULL) {
83 			TRACE_ERROR("Unable to open %s: %s\n",
84 				    nifname, strerror(errno));
85 			exit(EXIT_FAILURE);
86 		}
87 	}
88 }
89 /*----------------------------------------------------------------------------*/
90 int
netmap_link_devices(struct mtcp_thread_context * ctxt)91 netmap_link_devices(struct mtcp_thread_context *ctxt)
92 {
93 	/* linking takes place during mtcp_init() */
94 
95 	return 0;
96 }
97 /*----------------------------------------------------------------------------*/
98 void
netmap_release_pkt(struct mtcp_thread_context * ctxt,int ifidx,unsigned char * pkt_data,int len)99 netmap_release_pkt(struct mtcp_thread_context *ctxt, int ifidx, unsigned char *pkt_data, int len)
100 {
101 	/*
102 	 * do nothing over here - memory reclamation
103 	 * will take place in dpdk_recv_pkts
104 	 */
105 }
106 /*----------------------------------------------------------------------------*/
107 int
netmap_send_pkts(struct mtcp_thread_context * ctxt,int nif)108 netmap_send_pkts(struct mtcp_thread_context *ctxt, int nif)
109 {
110 	int pkt_size, idx;
111 	struct netmap_private_context *npc;
112 	mtcp_manager_t mtcp;
113 
114 	npc = (struct netmap_private_context *)ctxt->io_private_context;
115 	idx = nif;
116 	pkt_size = npc->snd_pkt_size[idx];
117 	mtcp = ctxt->mtcp_manager;
118 
119 	/* assert-type statement */
120 	if (pkt_size == 0) return 0;
121 
122 #ifdef NETSTAT
123 	mtcp->nstat.tx_packets[nif]++;
124 	mtcp->nstat.tx_bytes[nif] += pkt_size + ETHER_OVR;
125 #endif
126 
127  tx_again:
128 	if (nm_inject(npc->local_nmd[idx], npc->snd_pktbuf[idx], pkt_size) == 0) {
129 		TRACE_DBG("Failed to send pkt of size %d on interface: %d\n",
130 			  pkt_size, idx);
131 
132 		ioctl(npc->local_nmd[idx]->fd, NIOCTXSYNC, NULL);
133 		goto tx_again;
134 	}
135 
136 #ifdef NETSTAT
137 	//	mtcp->nstat.rx_errors[idx]++;
138 #endif
139 	npc->snd_pkt_size[idx] = 0;
140 
141 	return 1;
142 }
143 /*----------------------------------------------------------------------------*/
144 uint8_t *
netmap_get_wptr(struct mtcp_thread_context * ctxt,int nif,uint16_t pktsize)145 netmap_get_wptr(struct mtcp_thread_context *ctxt, int nif, uint16_t pktsize)
146 {
147 	struct netmap_private_context *npc;
148 	int idx = nif;
149 
150 	npc = (struct netmap_private_context *)ctxt->io_private_context;
151 	if (npc->snd_pkt_size[idx] != 0)
152 		netmap_send_pkts(ctxt, nif);
153 
154 	npc->snd_pkt_size[idx] = pktsize;
155 
156 	return (uint8_t *)npc->snd_pktbuf[idx];
157 }
158 /*----------------------------------------------------------------------------*/
159 int32_t
netmap_recv_pkts(struct mtcp_thread_context * ctxt,int ifidx)160 netmap_recv_pkts(struct mtcp_thread_context *ctxt, int ifidx)
161 {
162 	struct netmap_private_context *npc;
163 	struct nm_desc *d;
164 	npc = (struct netmap_private_context *)ctxt->io_private_context;
165 	d = npc->local_nmd[ifidx];
166 
167 	int p = 0;
168 	int c, got = 0, ri = d->cur_rx_ring;
169 	int n = d->last_rx_ring - d->first_rx_ring + 1;
170 	int cnt = MAX_PKT_BURST;
171 
172 
173 
174 	for (c = 0; c < n && cnt != got && npc->dev_poll_flag[ifidx]; c++) {
175 		/* compute current ring to use */
176 		struct netmap_ring *ring;
177 
178 		ri = d->cur_rx_ring + c;
179 		if (ri > d->last_rx_ring)
180 			ri = d->first_rx_ring;
181 		ring = NETMAP_RXRING(d->nifp, ri);
182 		for ( ; !nm_ring_empty(ring) && cnt != got; got++) {
183 			u_int i = ring->cur;
184 			u_int idx = ring->slot[i].buf_idx;
185 			npc->rcv_pktbuf[p] = (u_char *)NETMAP_BUF(ring, idx);
186 			npc->rcv_pkt_len[p] = ring->slot[i].len;
187 			p++;
188 			ring->head = ring->cur = nm_ring_next(ring, i);
189 		}
190 	}
191 	d->cur_rx_ring = ri;
192 
193 	npc->dev_poll_flag[ifidx] = 0;
194 
195 	return p;
196 }
197 /*----------------------------------------------------------------------------*/
198 uint8_t *
netmap_get_rptr(struct mtcp_thread_context * ctxt,int ifidx,int index,uint16_t * len)199 netmap_get_rptr(struct mtcp_thread_context *ctxt, int ifidx, int index, uint16_t *len)
200 {
201 	struct netmap_private_context *npc;
202 	npc = (struct netmap_private_context *)ctxt->io_private_context;
203 
204 	*len = npc->rcv_pkt_len[index];
205 	return (unsigned char *)npc->rcv_pktbuf[index];
206 }
207 /*----------------------------------------------------------------------------*/
208 int32_t
netmap_select(struct mtcp_thread_context * ctxt)209 netmap_select(struct mtcp_thread_context *ctxt)
210 {
211 	int i, rc;
212 	struct pollfd pfd[MAX_DEVICES];
213 	struct netmap_private_context *npc =
214 		(struct netmap_private_context *)ctxt->io_private_context;
215 
216 	/* see if num_devices have been registered */
217 	if (npc->local_nmd[0] == NULL)
218 		return -1;
219 
220 	for (i = 0; i < g_config.mos->netdev_table->num; i++) {
221 		pfd[i].fd = npc->local_nmd[i]->fd;
222 		pfd[i].events = POLLIN;
223 	}
224 
225 #ifndef CONST_POLLING
226 	if (npc->idle_poll_count >= IDLE_POLL_COUNT) {
227 		rc = poll(pfd, g_config.mos->netdev_table->num, IDLE_POLL_WAIT);
228 	} else
229 #endif
230 		{
231 			rc = poll(pfd, g_config.mos->netdev_table->num, 0);
232 		}
233 
234 	npc->idle_poll_count = (rc == 0) ? (npc->idle_poll_count + 1) : 0;
235 
236 	for (i = 0; rc > 0 && i < g_config.mos->netdev_table->num; i++)
237 		if (!(pfd[i].revents & (POLLERR)))
238 			npc->dev_poll_flag[i] = 1;
239 	return 0;
240 }
241 /*----------------------------------------------------------------------------*/
242 int
netmap_get_nif(struct ifreq * ifr)243 netmap_get_nif(struct ifreq *ifr)
244 {
245 	int i;
246 	struct netdev_entry **ent = g_config.mos->netdev_table->ent;
247 
248 	for (i = 0; i < g_config.mos->netdev_table->num; i++)
249 		if (!strcmp(ifr->ifr_name, ent[i]->dev_name))
250 			return i;
251 
252 	return -1;
253 }
254 /*----------------------------------------------------------------------------*/
255 int32_t
netmap_dev_ioctl(struct mtcp_thread_context * ctx,int nif,int cmd,void * argp)256 netmap_dev_ioctl(struct mtcp_thread_context *ctx, int nif, int cmd, void *argp)
257 {
258 	/* unimplemented */
259 	return -1;
260 }
261 /*----------------------------------------------------------------------------*/
262 void
netmap_destroy_handle(struct mtcp_thread_context * ctxt)263 netmap_destroy_handle(struct mtcp_thread_context *ctxt)
264 {
265 	int i;
266 	struct netmap_private_context *npc;
267 
268 	npc = (struct netmap_private_context *)ctxt->io_private_context;
269 
270 	for (i = 0; i < g_config.mos->netdev_table->num; i++)
271 		close(npc->local_nmd[i]->fd);
272 }
273 /*----------------------------------------------------------------------------*/
274 void
netmap_load_module_upper_half(void)275 netmap_load_module_upper_half(void)
276 {
277 	int i;
278 	int num_dev;
279 	uint64_t cpu_mask;
280 	int queue_range;
281 
282 	num_dev = g_config.mos->netdev_table->num;
283 
284 	for (i = 0; i < num_dev; i++) {
285 		cpu_mask = g_config.mos->netdev_table->ent[i]->cpu_mask;
286 		queue_range = sizeof(cpu_mask) * NBBY - __builtin_clzll(cpu_mask);
287 		num_queues =  (num_queues < queue_range) ?
288 			queue_range : num_queues;
289 	}
290 }
291 /*----------------------------------------------------------------------------*/
292 static void
set_promisc(char * ifname)293 set_promisc(char *ifname)
294 {
295 	int fd, ret;
296 	struct ifreq eth;
297 
298 	fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
299 	if (fd == -1) {
300 		TRACE_ERROR("Couldn't open socket!\n");
301 		return;
302 	}
303 	strcpy(eth.ifr_name, ifname);
304 	ret = ioctl(fd, SIOCGIFFLAGS, &eth);
305 	if (ret == -1) {
306 		TRACE_ERROR("Get ioctl for %s failed!\n",
307 			    ifname);
308 		close(fd);
309 		return;
310 	}
311 
312 	if (eth.ifr_flags & IFF_PROMISC) {
313 		TRACE_ERROR("Interface %s is already set to "
314 			    "promiscuous mode\n", ifname);
315 		close(fd);
316 		return;
317 	}
318 	eth.ifr_flags |= IFF_PROMISC;
319 
320 	ret = ioctl(fd, SIOCSIFFLAGS, &eth);
321 	if (ret == -1) {
322 		TRACE_ERROR("Set ioctl failed for %s\n", ifname);
323 		close(fd);
324 		return;
325 	}
326 
327 	close(fd);
328 
329 }
330 /*----------------------------------------------------------------------------*/
331 void
netmap_load_module_lower_half(void)332 netmap_load_module_lower_half(void)
333 {
334 	struct netdev_entry **ent;
335 	int j;
336 
337 	ent = g_config.mos->netdev_table->ent;
338 
339 	for (j = 0; j < g_config.mos->netdev_table->num; j++) {
340 		set_promisc(ent[j]->dev_name);
341 	}
342 }
343 /*----------------------------------------------------------------------------*/
344 io_module_func netmap_module_func = {
345 	.load_module_upper_half	   = netmap_load_module_upper_half,
346 	.load_module_lower_half	   = netmap_load_module_lower_half,
347 	.init_handle		   = netmap_init_handle,
348 	.link_devices		   = netmap_link_devices,
349 	.release_pkt		   = netmap_release_pkt,
350 	.send_pkts		   = netmap_send_pkts,
351 	.get_wptr   		   = netmap_get_wptr,
352 	.set_wptr		   = NULL,
353 	.recv_pkts		   = netmap_recv_pkts,
354 	.get_rptr	   	   = netmap_get_rptr,
355 	.get_nif		   = netmap_get_nif,
356 	.select			   = netmap_select,
357 	.destroy_handle		   = netmap_destroy_handle,
358 	.dev_ioctl		   = netmap_dev_ioctl,
359 };
360 /*----------------------------------------------------------------------------*/
361 
362