1 /*
2 ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved.
3 ** Author: Michael R. Altizer <mialtize@cisco.com>
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License Version 2 as
7 ** published by the Free Software Foundation. You may not use, modify or
8 ** distribute this program under any other version of the GNU General
9 ** Public License.
10 **
11 ** This program is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ** GNU General Public License for more details.
15 **
16 ** You should have received a copy of the GNU General Public License
17 ** along with this program; if not, write to the Free Software
18 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <poll.h>
26 #include <stdbool.h>
27
28 #define NETMAP_WITH_LIBS
29 #include <net/netmap_user.h>
30
31 #include "daq_dlt.h"
32 #include "daq_module_api.h"
33
34 #define DAQ_NETMAP_VERSION 3
35
36 /* Hi! I'm completely arbitrary! */
37 #define NETMAP_MAX_INTERFACES 32
38
39 #define SET_ERROR(modinst, ...) daq_base_api.set_errbuf(modinst, __VA_ARGS__)
40
41 typedef struct _netmap_instance
42 {
43 struct _netmap_instance *next;
44 struct _netmap_instance *peer;
45 int fd;
46 int index;
47 struct netmap_if *nifp;
48 /* TX ring info */
49 uint16_t first_tx_ring;
50 uint16_t last_tx_ring;
51 uint16_t cur_tx_ring;
52 /* RX ring info */
53 uint16_t first_rx_ring;
54 uint16_t last_rx_ring;
55 uint16_t cur_rx_ring;
56 /* MMAP'd memory */
57 void *mem;
58 uint32_t memsize;
59 struct nmreq req;
60 unsigned long long tx_discards;
61 } NetmapInstance;
62
63 typedef struct _netmap_pkt_desc
64 {
65 DAQ_Msg_t msg;
66 DAQ_PktHdr_t pkthdr;
67 uint8_t *data;
68 NetmapInstance *instance;
69 unsigned int length;
70 struct _netmap_pkt_desc *next;
71 } NetmapPktDesc;
72
73 typedef struct
74 {
75 NetmapPktDesc *pool;
76 NetmapPktDesc *freelist;
77 DAQ_MsgPoolInfo_t info;
78 } NetmapMsgPool;
79
80 typedef struct _netmap_context
81 {
82 /* Configuration */
83 char *device;
84 int snaplen;
85 int timeout;
86 bool debug;
87 /* State */
88 DAQ_ModuleInstance_h modinst;
89 NetmapMsgPool pool;
90 NetmapInstance *instances;
91 uint32_t intf_count;
92 volatile bool interrupted;
93 DAQ_Stats_t stats;
94 /* Message receive state */
95 NetmapInstance *curr_instance;
96 } Netmap_Context_t;
97
98 static DAQ_VariableDesc_t netmap_variable_descriptions[] = {
99 { "debug", "Enable debugging output to stdout", DAQ_VAR_DESC_FORBIDS_ARGUMENT },
100 };
101
102 static DAQ_BaseAPI_t daq_base_api;
103
nminst_inc_rx_ring(NetmapInstance * instance)104 static inline void nminst_inc_rx_ring(NetmapInstance *instance)
105 {
106 instance->cur_rx_ring++;
107 if (instance->cur_rx_ring > instance->last_rx_ring)
108 instance->cur_rx_ring = instance->first_rx_ring;
109 }
110
nminst_inc_tx_ring(NetmapInstance * instance)111 static inline void nminst_inc_tx_ring(NetmapInstance *instance)
112 {
113 instance->cur_tx_ring++;
114 if (instance->cur_tx_ring > instance->last_tx_ring)
115 instance->cur_tx_ring = instance->first_tx_ring;
116 }
117
destroy_packet_pool(Netmap_Context_t * nmc)118 static void destroy_packet_pool(Netmap_Context_t *nmc)
119 {
120 NetmapMsgPool *pool = &nmc->pool;
121 if (pool->pool)
122 {
123 while (pool->info.size > 0)
124 free(pool->pool[--pool->info.size].data);
125 free(pool->pool);
126 pool->pool = NULL;
127 }
128 pool->freelist = NULL;
129 pool->info.available = 0;
130 pool->info.mem_size = 0;
131 }
132
create_packet_pool(Netmap_Context_t * nmc,unsigned size)133 static int create_packet_pool(Netmap_Context_t *nmc, unsigned size)
134 {
135 NetmapMsgPool *pool = &nmc->pool;
136 pool->pool = calloc(sizeof(NetmapPktDesc), size);
137 if (!pool->pool)
138 {
139 SET_ERROR(nmc->modinst, "%s: Could not allocate %zu bytes for a packet descriptor pool!",
140 __func__, sizeof(NetmapPktDesc) * size);
141 return DAQ_ERROR_NOMEM;
142 }
143 pool->info.mem_size = sizeof(NetmapPktDesc) * size;
144 while (pool->info.size < size)
145 {
146 /* Allocate packet data and set up descriptor */
147 NetmapPktDesc *desc = &pool->pool[pool->info.size];
148 desc->data = malloc(nmc->snaplen);
149 if (!desc->data)
150 {
151 SET_ERROR(nmc->modinst, "%s: Could not allocate %d bytes for a packet descriptor message buffer!",
152 __func__, nmc->snaplen);
153 return DAQ_ERROR_NOMEM;
154 }
155 pool->info.mem_size += nmc->snaplen;
156
157 /* Initialize non-zero invariant packet header fields. */
158 DAQ_PktHdr_t *pkthdr = &desc->pkthdr;
159 pkthdr->ingress_group = DAQ_PKTHDR_UNKNOWN;
160 pkthdr->egress_group = DAQ_PKTHDR_UNKNOWN;
161
162 /* Initialize non-zero invariant message header fields. */
163 DAQ_Msg_t *msg = &desc->msg;
164 msg->type = DAQ_MSG_TYPE_PACKET;
165 msg->hdr_len = sizeof(desc->pkthdr);
166 msg->hdr = &desc->pkthdr;
167 msg->data = desc->data;
168 msg->owner = nmc->modinst;
169 msg->priv = desc;
170
171 /* Place it on the free list */
172 desc->next = pool->freelist;
173 pool->freelist = desc;
174
175 pool->info.size++;
176 }
177 pool->info.available = pool->info.size;
178 return DAQ_SUCCESS;
179 }
180
destroy_instance(NetmapInstance * instance)181 static void destroy_instance(NetmapInstance *instance)
182 {
183 if (instance)
184 {
185 /* Unmap the packet memory region. If we had a peer, notify them that
186 the shared mapping has been freed and that we no longer exist. */
187 if (instance->mem)
188 {
189 munmap(instance->mem, instance->memsize);
190 if (instance->peer)
191 {
192 instance->peer->mem = MAP_FAILED;
193 instance->peer->memsize = 0;
194 }
195 }
196 if (instance->peer)
197 instance->peer->peer = NULL;
198 if (instance->fd != -1)
199 close(instance->fd);
200 free(instance);
201 }
202 }
203
netmap_close(Netmap_Context_t * nmc)204 static int netmap_close(Netmap_Context_t *nmc)
205 {
206 NetmapInstance *instance;
207
208 if (!nmc)
209 return -1;
210
211 /* Free all of the device instances. */
212 while ((instance = nmc->instances) != NULL)
213 {
214 nmc->instances = instance->next;
215 if (nmc->debug)
216 {
217 printf("Netmap instance %s (%d) discarded %llu TX packets.\n",
218 instance->req.nr_name, instance->index, instance->tx_discards);
219 }
220 destroy_instance(instance);
221 }
222
223 return 0;
224 }
225
create_instance(const char * device,NetmapInstance * parent,DAQ_ModuleInstance_h modinst)226 static NetmapInstance *create_instance(const char *device, NetmapInstance *parent, DAQ_ModuleInstance_h modinst)
227 {
228 NetmapInstance *instance;
229 struct nmreq *req;
230 static int index = 0;
231
232 instance = calloc(1, sizeof(NetmapInstance));
233 if (!instance)
234 {
235 SET_ERROR(modinst, "%s: Could not allocate a new instance structure.", __func__);
236 goto err;
237 }
238
239 /* Initialize the instance, including an arbitrary and unique device index. */
240 instance->mem = MAP_FAILED;
241 instance->index = index;
242 index++;
243
244 /* Open /dev/netmap for communications to the driver. */
245 instance->fd = open("/dev/netmap", O_RDWR);
246 if (instance->fd < 0)
247 {
248 SET_ERROR(modinst, "%s: Could not open /dev/netmap: %s (%d)",
249 __func__, strerror(errno), errno);
250 goto err;
251 }
252
253 /* Initialize the netmap request object. */
254 req = &instance->req;
255 strncpy(req->nr_name, device, sizeof(req->nr_name));
256 req->nr_version = NETMAP_API;
257 req->nr_ringid = 0;
258 req->nr_flags = NR_REG_ALL_NIC;
259
260 return instance;
261
262 err:
263 destroy_instance(instance);
264 return NULL;
265 }
266
create_bridge(Netmap_Context_t * nmc,const char * device_name1,const char * device_name2)267 static int create_bridge(Netmap_Context_t *nmc, const char *device_name1, const char *device_name2)
268 {
269 NetmapInstance *instance, *peer1, *peer2;
270
271 peer1 = peer2 = NULL;
272 for (instance = nmc->instances; instance; instance = instance->next)
273 {
274 if (!strcmp(instance->req.nr_name, device_name1))
275 peer1 = instance;
276 else if (!strcmp(instance->req.nr_name, device_name2))
277 peer2 = instance;
278 }
279
280 if (!peer1 || !peer2)
281 return DAQ_ERROR_NODEV;
282
283 peer1->peer = peer2;
284 peer2->peer = peer1;
285
286 return DAQ_SUCCESS;
287 }
288
start_instance(Netmap_Context_t * nmc,NetmapInstance * instance)289 static int start_instance(Netmap_Context_t *nmc, NetmapInstance *instance)
290 {
291 if (ioctl(instance->fd, NIOCREGIF, &instance->req))
292 {
293 SET_ERROR(nmc->modinst, "%s: Netmap registration for %s failed: %s (%d)",
294 __func__, instance->req.nr_name, strerror(errno), errno);
295 return DAQ_ERROR;
296 }
297
298 /* Only mmap the packet memory region for the first interface in a pair. */
299 if (instance->peer && instance->peer->mem != MAP_FAILED)
300 {
301 instance->memsize = instance->peer->memsize;
302 instance->mem = instance->peer->mem;
303 }
304 else
305 {
306 instance->memsize = instance->req.nr_memsize;
307 instance->mem = mmap(0, instance->memsize, PROT_WRITE | PROT_READ, MAP_SHARED, instance->fd, 0);
308 if (instance->mem == MAP_FAILED)
309 {
310 SET_ERROR(nmc->modinst, "%s: Could not MMAP the buffer memory region for %s: %s (%d)",
311 __func__, instance->req.nr_name, strerror(errno), errno);
312 return DAQ_ERROR;
313 }
314 }
315
316 instance->nifp = NETMAP_IF(instance->mem, instance->req.nr_offset);
317
318 instance->first_tx_ring = 0;
319 instance->first_rx_ring = 0;
320 instance->last_tx_ring = instance->req.nr_tx_rings - 1;
321 instance->last_rx_ring = instance->req.nr_rx_rings - 1;
322
323 if (nmc->debug)
324 {
325 struct netmap_ring *ring;
326 int i;
327
328 printf("[%s]\n", instance->req.nr_name);
329 printf(" nr_tx_slots: %u\n", instance->req.nr_tx_slots);
330 printf(" nr_rx_slots: %u\n", instance->req.nr_rx_slots);
331 printf(" nr_tx_rings: %hu\n", instance->req.nr_tx_rings);
332 for (i = instance->first_tx_ring; i <= instance->last_tx_ring; i++)
333 {
334 ring = NETMAP_TXRING(instance->nifp, i);
335 printf(" [TX Ring %d]\n", i);
336 printf(" buf_ofs = %zu\n", ring->buf_ofs);
337 printf(" num_slots = %u\n", ring->num_slots);
338 printf(" nr_buf_size = %u\n", ring->nr_buf_size);
339 printf(" flags = 0x%x\n", ring->flags);
340 }
341 printf(" nr_rx_rings: %hu\n", instance->req.nr_rx_rings);
342 for (i = instance->first_rx_ring; i <= instance->last_rx_ring; i++)
343 {
344 ring = NETMAP_RXRING(instance->nifp, i);
345 printf(" [RX Ring %d]\n", i);
346 printf(" buf_ofs = %zu\n", ring->buf_ofs);
347 printf(" num_slots = %u\n", ring->num_slots);
348 printf(" nr_buf_size = %u\n", ring->nr_buf_size);
349 printf(" flags = 0x%x\n", ring->flags);
350 }
351 printf(" memsize: %u\n", instance->memsize);
352 printf(" index: %d\n", instance->index);
353 }
354
355 return DAQ_SUCCESS;
356 }
357
netmap_daq_module_load(const DAQ_BaseAPI_t * base_api)358 static int netmap_daq_module_load(const DAQ_BaseAPI_t *base_api)
359 {
360 if (base_api->api_version != DAQ_BASE_API_VERSION || base_api->api_size != sizeof(DAQ_BaseAPI_t))
361 return DAQ_ERROR;
362
363 daq_base_api = *base_api;
364
365 return DAQ_SUCCESS;
366 }
367
netmap_daq_module_unload(void)368 static int netmap_daq_module_unload(void)
369 {
370 memset(&daq_base_api, 0, sizeof(daq_base_api));
371 return DAQ_SUCCESS;
372 }
373
netmap_daq_get_variable_descs(const DAQ_VariableDesc_t ** var_desc_table)374 static int netmap_daq_get_variable_descs(const DAQ_VariableDesc_t **var_desc_table)
375 {
376 *var_desc_table = netmap_variable_descriptions;
377
378 return sizeof(netmap_variable_descriptions) / sizeof(DAQ_VariableDesc_t);
379 }
380
netmap_daq_instantiate(const DAQ_ModuleConfig_h modcfg,DAQ_ModuleInstance_h modinst,void ** ctxt_ptr)381 static int netmap_daq_instantiate(const DAQ_ModuleConfig_h modcfg, DAQ_ModuleInstance_h modinst, void **ctxt_ptr)
382 {
383 Netmap_Context_t *nmc;
384 char intf[IFNAMSIZ];
385 size_t len;
386 uint32_t num_intfs = 0;
387 int rval = DAQ_ERROR;
388
389 nmc = calloc(1, sizeof(Netmap_Context_t));
390 if (!nmc)
391 {
392 SET_ERROR(modinst, "%s: Couldn't allocate memory for the new Netmap context!", __func__);
393 rval = DAQ_ERROR_NOMEM;
394 goto err;
395 }
396 nmc->modinst = modinst;
397
398 nmc->device = strdup(daq_base_api.config_get_input(modcfg));
399 if (!nmc->device)
400 {
401 SET_ERROR(modinst, "%s: Couldn't allocate memory for the device string!", __func__);
402 rval = DAQ_ERROR_NOMEM;
403 goto err;
404 }
405
406 nmc->snaplen = daq_base_api.config_get_snaplen(modcfg);
407 nmc->timeout = (daq_base_api.config_get_timeout(modcfg) > 0) ? (int) daq_base_api.config_get_timeout(modcfg) : -1;
408
409 DAQ_Mode mode = daq_base_api.config_get_mode(modcfg);
410 char *dev = nmc->device;
411 if (*dev == ':' || ((len = strlen(dev)) > 0 && *(dev + len - 1) == ':') ||
412 (mode == DAQ_MODE_PASSIVE && strstr(dev, "::")))
413 {
414 SET_ERROR(modinst, "%s: Invalid interface specification: '%s'!", __func__, nmc->device);
415 goto err;
416 }
417
418 while (*dev != '\0')
419 {
420 len = strcspn(dev, ":");
421 if (len >= sizeof(intf))
422 {
423 SET_ERROR(modinst, "%s: Interface name too long! (%zu)", __func__, len);
424 goto err;
425 }
426 if (len != 0)
427 {
428 nmc->intf_count++;
429 if (nmc->intf_count >= NETMAP_MAX_INTERFACES)
430 {
431 SET_ERROR(modinst, "%s: Using more than %d interfaces is not supported!",
432 __func__, NETMAP_MAX_INTERFACES);
433 goto err;
434 }
435 snprintf(intf, len + 1, "%s", dev);
436 NetmapInstance *instance = create_instance(intf, nmc->instances, modinst);
437 if (!instance)
438 goto err;
439
440 instance->next = nmc->instances;
441 nmc->instances = instance;
442 num_intfs++;
443 if (mode != DAQ_MODE_PASSIVE)
444 {
445 if (num_intfs == 2)
446 {
447 const char *name1 = nmc->instances->next->req.nr_name;
448 const char *name2 = nmc->instances->req.nr_name;
449
450 if (create_bridge(nmc, name1, name2) != DAQ_SUCCESS)
451 {
452 SET_ERROR(modinst, "%s: Couldn't create the bridge between %s and %s!",
453 __func__, name1, name2);
454 goto err;
455 }
456 num_intfs = 0;
457 }
458 else if (num_intfs > 2)
459 break;
460 }
461 }
462 else
463 len = 1;
464 dev += len;
465 }
466
467 /* If there are any leftover unbridged interfaces and we're not in Passive mode, error out. */
468 if (!nmc->instances || (mode != DAQ_MODE_PASSIVE && num_intfs != 0))
469 {
470 SET_ERROR(modinst, "%s: Invalid interface specification: '%s'!",
471 __func__, nmc->device);
472 goto err;
473 }
474
475 /* Initialize other default configuration values. */
476 nmc->debug = false;
477
478 /* Import the configuration dictionary requests. */
479 const char *varKey, *varValue;
480 daq_base_api.config_first_variable(modcfg, &varKey, &varValue);
481 while (varKey)
482 {
483 if (!strcmp(varKey, "debug"))
484 nmc->debug = true;
485
486 daq_base_api.config_next_variable(modcfg, &varKey, &varValue);
487 }
488
489 /* Finally, create the message buffer pool. */
490 uint32_t pool_size = daq_base_api.config_get_msg_pool_size(modcfg);
491 if (pool_size == 0)
492 {
493 /* Default the pool size to 256 descriptors per interface for now. */
494 pool_size = nmc->intf_count * 256;
495 }
496 if ((rval = create_packet_pool(nmc, pool_size)) != DAQ_SUCCESS)
497 goto err;
498
499 nmc->curr_instance = nmc->instances;
500
501 *ctxt_ptr = nmc;
502
503 return DAQ_SUCCESS;
504
505 err:
506 if (nmc)
507 {
508 netmap_close(nmc);
509 if (nmc->device)
510 free(nmc->device);
511 destroy_packet_pool(nmc);
512 free(nmc);
513 }
514 return rval;
515 }
516
netmap_daq_destroy(void * handle)517 static void netmap_daq_destroy(void *handle)
518 {
519 Netmap_Context_t *nmc = (Netmap_Context_t *) handle;
520
521 netmap_close(nmc);
522 if (nmc->device)
523 free(nmc->device);
524 destroy_packet_pool(nmc);
525 free(nmc);
526 }
527
netmap_daq_start(void * handle)528 static int netmap_daq_start(void *handle)
529 {
530 Netmap_Context_t *nmc = (Netmap_Context_t *) handle;
531 NetmapInstance *instance;
532
533 for (instance = nmc->instances; instance; instance = instance->next)
534 {
535 if (start_instance(nmc, instance) != DAQ_SUCCESS)
536 return DAQ_ERROR;
537 }
538
539 memset(&nmc->stats, 0, sizeof(DAQ_Stats_t));;
540
541 return DAQ_SUCCESS;
542 }
543
wait_for_tx_slot(Netmap_Context_t * nmc,NetmapInstance * instance)544 static int wait_for_tx_slot(Netmap_Context_t *nmc, NetmapInstance *instance)
545 {
546 struct pollfd pfd;
547
548 pfd.fd = instance->fd;
549 pfd.revents = 0;
550 pfd.events = POLLOUT;
551
552 int ret = poll(&pfd, 1, -1);
553 if (ret > 0)
554 {
555 if (pfd.revents & (POLLHUP | POLLERR | POLLNVAL))
556 {
557 if (pfd.revents & POLLHUP)
558 SET_ERROR(nmc->modinst, "%s: Hang-up on a packet socket", __func__);
559 else if (pfd.revents & POLLERR)
560 SET_ERROR(nmc->modinst, "%s: Encountered error condition on a packet socket", __func__);
561 else if (pfd.revents & POLLNVAL)
562 SET_ERROR(nmc->modinst, "%s: Invalid polling request on a packet socket", __func__);
563 return DAQ_ERROR;
564 }
565 /* All good! A TX slot should be waiting for us somewhere. */
566 return DAQ_SUCCESS;
567 }
568 /* If we were interrupted by a signal, start the loop over. The user should call daq_interrupt to actually exit. */
569 if (ret < 0 && errno != EINTR)
570 {
571 SET_ERROR(nmc->modinst, "%s: Poll failed: %s (%d)", __func__, strerror(errno), errno);
572 return DAQ_ERROR;
573 }
574
575 return DAQ_ERROR_AGAIN;
576 }
577
netmap_transmit_packet(NetmapInstance * egress,const uint8_t * packet_data,unsigned int len)578 static inline int netmap_transmit_packet(NetmapInstance *egress, const uint8_t *packet_data, unsigned int len)
579 {
580 /* Find a TX ring with space to send on. */
581 uint16_t start_tx_ring = egress->cur_tx_ring;
582 do
583 {
584 struct netmap_ring *tx_ring = NETMAP_TXRING(egress->nifp, egress->cur_tx_ring);
585 nminst_inc_tx_ring(egress);
586 if (nm_ring_empty(tx_ring))
587 continue;
588
589 uint32_t tx_cur = tx_ring->cur;
590 struct netmap_slot *tx_slot = &tx_ring->slot[tx_cur];
591 tx_slot->len = len;
592 nm_pkt_copy(packet_data, NETMAP_BUF(tx_ring, tx_slot->buf_idx), tx_slot->len);
593
594 tx_ring->head = tx_ring->cur = nm_ring_next(tx_ring, tx_cur);
595
596 return DAQ_SUCCESS;
597 } while (egress->cur_tx_ring != start_tx_ring);
598
599 /* If we got here, it means we couldn't find an available TX slot. */
600 return DAQ_ERROR_AGAIN;
601 }
602
netmap_inject_packet(Netmap_Context_t * nmc,NetmapInstance * egress,const uint8_t * data,uint32_t data_len)603 static int netmap_inject_packet(Netmap_Context_t *nmc, NetmapInstance *egress, const uint8_t *data, uint32_t data_len)
604 {
605 if (!egress)
606 {
607 SET_ERROR(nmc->modinst, "%s: Could not determine which instance to inject the packet out of!", __func__);
608 return DAQ_ERROR;
609 }
610
611 int rval = netmap_transmit_packet(egress, data, data_len);
612 if (rval != DAQ_SUCCESS)
613 {
614 if (rval == DAQ_ERROR_AGAIN)
615 SET_ERROR(nmc->modinst, "%s: Could not send packet because no TX slots were available.", __func__);
616 else
617 SET_ERROR(nmc->modinst, "%s: Error sending packet: %s (%d)", __func__, strerror(errno), errno);
618 return rval;
619 }
620
621 nmc->stats.packets_injected++;
622
623 return DAQ_SUCCESS;
624 }
625
netmap_daq_inject(void * handle,DAQ_MsgType type,const void * hdr,const uint8_t * data,uint32_t data_len)626 static int netmap_daq_inject(void *handle, DAQ_MsgType type, const void *hdr, const uint8_t *data, uint32_t data_len)
627 {
628 Netmap_Context_t *nmc = (Netmap_Context_t *) handle;
629
630 if (type != DAQ_MSG_TYPE_PACKET)
631 return DAQ_ERROR_NOTSUP;
632
633 const DAQ_PktHdr_t *pkthdr = (const DAQ_PktHdr_t *) hdr;
634 NetmapInstance *egress;
635
636 /* Find the instance that the packet was received on. */
637 for (egress = nmc->instances; egress; egress = egress->next)
638 {
639 if (egress->index == pkthdr->ingress_index)
640 break;
641 }
642
643 if (!egress)
644 {
645 SET_ERROR(nmc->modinst, "%s: Unrecognized ingress interface specified: %u",
646 __func__, pkthdr->ingress_index);
647 return DAQ_ERROR_NODEV;
648 }
649
650 return netmap_inject_packet(nmc, egress, data, data_len);
651 }
652
netmap_daq_inject_relative(void * handle,const DAQ_Msg_t * msg,const uint8_t * data,uint32_t data_len,int reverse)653 static int netmap_daq_inject_relative(void *handle, const DAQ_Msg_t *msg, const uint8_t *data, uint32_t data_len, int reverse)
654 {
655 Netmap_Context_t *nmc = (Netmap_Context_t *) handle;
656 NetmapPktDesc *desc = (NetmapPktDesc *) msg->priv;
657 NetmapInstance *egress = reverse ? desc->instance : desc->instance->peer;
658
659 if (!reverse && !egress)
660 {
661 SET_ERROR(nmc->modinst, "%s: Specified ingress interface has no peer for forward injection.",
662 __func__);
663 return DAQ_ERROR_NODEV;
664 }
665
666 return netmap_inject_packet(nmc, egress, data, data_len);
667 }
668
netmap_daq_interrupt(void * handle)669 static int netmap_daq_interrupt(void *handle)
670 {
671 Netmap_Context_t *nmc = (Netmap_Context_t *) handle;
672
673 nmc->interrupted = true;
674
675 return DAQ_SUCCESS;
676 }
677
netmap_daq_stop(void * handle)678 static int netmap_daq_stop(void *handle)
679 {
680 Netmap_Context_t *nmc = (Netmap_Context_t *) handle;
681
682 netmap_close(nmc);
683
684 return DAQ_SUCCESS;
685 }
686
netmap_daq_ioctl(void * handle,DAQ_IoctlCmd cmd,void * arg,size_t arglen)687 static int netmap_daq_ioctl(void *handle, DAQ_IoctlCmd cmd, void *arg, size_t arglen)
688 {
689 Netmap_Context_t *nmc = (Netmap_Context_t *) handle;
690
691 /* Only supports GET_DEVICE_INDEX for now */
692 if (cmd != DIOCTL_GET_DEVICE_INDEX || arglen != sizeof(DIOCTL_QueryDeviceIndex))
693 return DAQ_ERROR_NOTSUP;
694
695 DIOCTL_QueryDeviceIndex *qdi = (DIOCTL_QueryDeviceIndex *) arg;
696
697 if (!qdi->device)
698 {
699 SET_ERROR(nmc->modinst, "No device name to find the index of!");
700 return DAQ_ERROR_INVAL;
701 }
702
703 for (NetmapInstance *instance = nmc->instances; instance; instance = instance->next)
704 {
705 if (!strcmp(qdi->device, instance->req.nr_name))
706 {
707 qdi->index = instance->index;
708 return DAQ_SUCCESS;
709 }
710 }
711
712 return DAQ_ERROR_NODEV;
713 }
714
netmap_daq_get_stats(void * handle,DAQ_Stats_t * stats)715 static int netmap_daq_get_stats(void *handle, DAQ_Stats_t * stats)
716 {
717 Netmap_Context_t *nmc = (Netmap_Context_t *) handle;
718
719 memcpy(stats, &nmc->stats, sizeof(DAQ_Stats_t));
720
721 return DAQ_SUCCESS;
722 }
723
netmap_daq_reset_stats(void * handle)724 static void netmap_daq_reset_stats(void *handle)
725 {
726 Netmap_Context_t *nmc = (Netmap_Context_t *) handle;
727
728 memset(&nmc->stats, 0, sizeof(DAQ_Stats_t));;
729 }
730
netmap_daq_get_snaplen(void * handle)731 static int netmap_daq_get_snaplen(void *handle)
732 {
733 Netmap_Context_t *nmc = (Netmap_Context_t *) handle;
734
735 return nmc->snaplen;
736 }
737
netmap_daq_get_capabilities(void * handle)738 static uint32_t netmap_daq_get_capabilities(void *handle)
739 {
740 return DAQ_CAPA_BLOCK | DAQ_CAPA_REPLACE | DAQ_CAPA_INJECT |
741 DAQ_CAPA_UNPRIV_START | DAQ_CAPA_INTERRUPT |
742 DAQ_CAPA_DEVICE_INDEX;
743 }
744
netmap_daq_get_datalink_type(void * handle)745 static int netmap_daq_get_datalink_type(void *handle)
746 {
747 return DLT_EN10MB;
748 }
749
find_ring(Netmap_Context_t * nmc)750 static inline struct netmap_ring *find_ring(Netmap_Context_t *nmc)
751 {
752 NetmapInstance *instance;
753
754 /* Iterate over the instances' rings to find the first one with data available.
755 Keep track of the last checked instance and RX ring within that instance
756 to continue the effort on the next call. */
757 instance = nmc->curr_instance;
758 do
759 {
760 instance = instance->next ? instance->next : nmc->instances;
761 uint16_t start_rx_ring = instance->cur_rx_ring;
762 do
763 {
764 struct netmap_ring *rx_ring = NETMAP_RXRING(instance->nifp, instance->cur_rx_ring);
765 nminst_inc_rx_ring(instance);
766 if (!nm_ring_empty(rx_ring))
767 {
768 nmc->curr_instance = instance;
769 return rx_ring;
770 }
771 } while (instance->cur_rx_ring != start_rx_ring);
772 } while (instance != nmc->curr_instance);
773
774 return NULL;
775 }
776
wait_for_packet(Netmap_Context_t * nmc)777 static inline DAQ_RecvStatus wait_for_packet(Netmap_Context_t *nmc)
778 {
779 NetmapInstance *instance;
780 struct pollfd pfd[NETMAP_MAX_INTERFACES];
781 uint32_t i;
782
783 for (i = 0, instance = nmc->instances; instance; i++, instance = instance->next)
784 {
785 pfd[i].fd = instance->fd;
786 pfd[i].revents = 0;
787 pfd[i].events = POLLIN;
788 }
789 /* Chop the timeout into one second chunks (plus any remainer) to improve responsiveness to
790 interruption when there is no traffic and the timeout is very long (or unlimited). */
791 int timeout = nmc->timeout;
792 while (timeout != 0)
793 {
794 /* If the receive has been canceled, break out of the loop and return. */
795 if (nmc->interrupted)
796 {
797 nmc->interrupted = false;
798 return DAQ_RSTAT_INTERRUPTED;
799 }
800
801 int poll_timeout;
802 if (timeout >= 1000)
803 {
804 poll_timeout = 1000;
805 timeout -= 1000;
806 }
807 else if (timeout > 0)
808 {
809 poll_timeout = timeout;
810 timeout = 0;
811 }
812 else
813 poll_timeout = 1000;
814
815 int ret = poll(pfd, nmc->intf_count, poll_timeout);
816 /* If some number of of sockets have events returned, check them all for badness. */
817 if (ret > 0)
818 {
819 for (i = 0; i < nmc->intf_count; i++)
820 {
821 if (pfd[i].revents & (POLLHUP | POLLERR | POLLNVAL))
822 {
823 if (pfd[i].revents & POLLHUP)
824 SET_ERROR(nmc->modinst, "%s: Hang-up on a packet socket", __func__);
825 else if (pfd[i].revents & POLLERR)
826 SET_ERROR(nmc->modinst, "%s: Encountered error condition on a packet socket", __func__);
827 else if (pfd[i].revents & POLLNVAL)
828 SET_ERROR(nmc->modinst, "%s: Invalid polling request on a packet socket", __func__);
829 return DAQ_RSTAT_ERROR;
830 }
831 }
832 /* All good! A packet should be waiting for us somewhere. */
833 return DAQ_RSTAT_OK;
834 }
835 /* If we were interrupted by a signal, start the loop over. The user should call daq_interrupt to actually exit. */
836 if (ret < 0 && errno != EINTR)
837 {
838 SET_ERROR(nmc->modinst, "%s: Poll failed: %s (%d)", __func__, strerror(errno), errno);
839 return DAQ_RSTAT_ERROR;
840 }
841 }
842
843 return DAQ_RSTAT_TIMEOUT;
844 }
845
netmap_daq_msg_receive(void * handle,const unsigned max_recv,const DAQ_Msg_t * msgs[],DAQ_RecvStatus * rstat)846 static unsigned netmap_daq_msg_receive(void *handle, const unsigned max_recv, const DAQ_Msg_t *msgs[], DAQ_RecvStatus *rstat)
847 {
848 Netmap_Context_t *nmc = (Netmap_Context_t *) handle;
849 DAQ_RecvStatus status = DAQ_RSTAT_OK;
850 unsigned idx = 0;
851
852 while (idx < max_recv)
853 {
854 /* Check to see if the receive has been canceled. If so, reset it and return appropriately. */
855 if (nmc->interrupted)
856 {
857 nmc->interrupted = false;
858 status = DAQ_RSTAT_INTERRUPTED;
859 break;
860 }
861
862 /* Make sure that we have a packet descriptor available to populate. */
863 NetmapPktDesc *desc = nmc->pool.freelist;
864 if (!desc)
865 {
866 status = DAQ_RSTAT_NOBUF;
867 break;
868 }
869
870 /* Try to find a packet ready for processing from one of the RX rings. */
871 struct netmap_ring *rx_ring = find_ring(nmc);
872 if (!rx_ring)
873 {
874 /* Only block waiting for a packet if we haven't received anything yet. */
875 if (idx != 0)
876 {
877 status = DAQ_RSTAT_WOULD_BLOCK;
878 break;
879 }
880 status = wait_for_packet(nmc);
881 if (status != DAQ_RSTAT_OK)
882 break;
883 continue;
884 }
885
886 NetmapInstance *instance;
887
888 uint32_t rx_cur = rx_ring->cur;
889 struct netmap_slot *rx_slot = &rx_ring->slot[rx_cur];
890 uint16_t len = rx_slot->len;
891 instance = nmc->curr_instance;
892
893 uint8_t *data = (uint8_t *) NETMAP_BUF(rx_ring, rx_slot->buf_idx);
894
895 nmc->stats.packets_received++;
896
897 /* Populate the packet descriptor, copying the packet data and releasing the packet
898 ring entry back to the kernel for reuse. */
899 memcpy(desc->data, data, len);
900 rx_ring->head = rx_ring->cur = nm_ring_next(rx_ring, rx_cur);
901 desc->instance = instance;
902 desc->length = len;
903
904 /* Next, set up the DAQ message. Most fields are prepopulated and unchanging. */
905 DAQ_Msg_t *msg = &desc->msg;
906 msg->data_len = len;
907 msg->data = data;
908
909 /* Then, set up the DAQ packet header. */
910 DAQ_PktHdr_t *pkthdr = &desc->pkthdr;
911 pkthdr->ts = rx_ring->ts;
912 pkthdr->pktlen = len;
913 pkthdr->ingress_index = instance->index;
914 pkthdr->egress_index = instance->peer ? instance->peer->index : DAQ_PKTHDR_UNKNOWN;
915 pkthdr->flags = 0;
916 /* The following fields should remain in their virgin state:
917 address_space_id (0)
918 ingress_group (DAQ_PKTHDR_UNKNOWN)
919 egress_group (DAQ_PKTHDR_UNKNOWN)
920 opaque (0)
921 flow_id (0)
922 */
923
924 /* Last, but not least, extract this descriptor from the free list and
925 place the message in the return vector. */
926 nmc->pool.freelist = desc->next;
927 desc->next = NULL;
928 nmc->pool.info.available--;
929 msgs[idx] = &desc->msg;
930
931 idx++;
932 }
933
934 *rstat = status;
935
936 return idx;
937 }
938
939 static const DAQ_Verdict verdict_translation_table[MAX_DAQ_VERDICT] = {
940 DAQ_VERDICT_PASS, /* DAQ_VERDICT_PASS */
941 DAQ_VERDICT_BLOCK, /* DAQ_VERDICT_BLOCK */
942 DAQ_VERDICT_PASS, /* DAQ_VERDICT_REPLACE */
943 DAQ_VERDICT_PASS, /* DAQ_VERDICT_WHITELIST */
944 DAQ_VERDICT_BLOCK, /* DAQ_VERDICT_BLACKLIST */
945 DAQ_VERDICT_PASS /* DAQ_VERDICT_IGNORE */
946 };
947
netmap_daq_msg_finalize(void * handle,const DAQ_Msg_t * msg,DAQ_Verdict verdict)948 static int netmap_daq_msg_finalize(void *handle, const DAQ_Msg_t *msg, DAQ_Verdict verdict)
949 {
950 Netmap_Context_t *nmc = (Netmap_Context_t *) handle;
951 NetmapPktDesc *desc = (NetmapPktDesc *) msg->priv;
952 NetmapInstance *peer;
953
954 /* Sanitize and enact the verdict. */
955 if (verdict >= MAX_DAQ_VERDICT)
956 verdict = DAQ_VERDICT_PASS;
957 nmc->stats.verdicts[verdict]++;
958 verdict = verdict_translation_table[verdict];
959 if (verdict == DAQ_VERDICT_PASS && (peer = desc->instance->peer))
960 {
961 int ret = netmap_transmit_packet(peer, desc->data, desc->length);
962 if (ret == DAQ_ERROR_AGAIN && wait_for_tx_slot(nmc, peer) == DAQ_SUCCESS)
963 {
964 if (netmap_transmit_packet(peer, desc->data, desc->length) != DAQ_SUCCESS)
965 peer->tx_discards++;
966 }
967 }
968
969 /* Toss the descriptor back on the free list for reuse. */
970 desc->next = nmc->pool.freelist;
971 nmc->pool.freelist = desc;
972 nmc->pool.info.available++;
973
974 return DAQ_SUCCESS;
975 }
976
netmap_daq_get_msg_pool_info(void * handle,DAQ_MsgPoolInfo_t * info)977 static int netmap_daq_get_msg_pool_info(void *handle, DAQ_MsgPoolInfo_t *info)
978 {
979 Netmap_Context_t *nmc = (Netmap_Context_t *) handle;
980
981 *info = nmc->pool.info;
982
983 return DAQ_SUCCESS;
984 }
985
986 #ifdef BUILDING_SO
987 DAQ_SO_PUBLIC const DAQ_ModuleAPI_t DAQ_MODULE_DATA =
988 #else
989 const DAQ_ModuleAPI_t netmap_daq_module_data =
990 #endif
991 {
992 /* .api_version = */ DAQ_MODULE_API_VERSION,
993 /* .api_size = */ sizeof(DAQ_ModuleAPI_t),
994 /* .module_version = */ DAQ_NETMAP_VERSION,
995 /* .name = */ "netmap",
996 /* .type = */ DAQ_TYPE_INLINE_CAPABLE | DAQ_TYPE_INTF_CAPABLE | DAQ_TYPE_MULTI_INSTANCE,
997 /* .load = */ netmap_daq_module_load,
998 /* .unload = */ netmap_daq_module_unload,
999 /* .get_variable_descs = */ netmap_daq_get_variable_descs,
1000 /* .instantiate = */ netmap_daq_instantiate,
1001 /* .destroy = */ netmap_daq_destroy,
1002 /* .set_filter = */ NULL,
1003 /* .start = */ netmap_daq_start,
1004 /* .inject = */ netmap_daq_inject,
1005 /* .inject_relative = */ netmap_daq_inject_relative,
1006 /* .interrupt = */ netmap_daq_interrupt,
1007 /* .stop = */ netmap_daq_stop,
1008 /* .ioctl = */ netmap_daq_ioctl,
1009 /* .get_stats = */ netmap_daq_get_stats,
1010 /* .reset_stats = */ netmap_daq_reset_stats,
1011 /* .get_snaplen = */ netmap_daq_get_snaplen,
1012 /* .get_capabilities = */ netmap_daq_get_capabilities,
1013 /* .get_datalink_type = */ netmap_daq_get_datalink_type,
1014 /* .config_load = */ NULL,
1015 /* .config_swap = */ NULL,
1016 /* .config_free = */ NULL,
1017 /* .msg_receive = */ netmap_daq_msg_receive,
1018 /* .msg_finalize = */ netmap_daq_msg_finalize,
1019 /* .get_msg_pool_info = */ netmap_daq_get_msg_pool_info,
1020 };
1021