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