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