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, ð);
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, ð);
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