dd6d4f91895dca6b7af2b1d824b688d5fd40df21
[dpdk.git] / examples / netmap_compat / lib / compat_netmap.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 #include <errno.h>
35 #include <inttypes.h>
36 #include <poll.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <net/if.h>
40 #include <sys/types.h>
41 #include <sys/resource.h>
42 #include <sys/mman.h>
43
44 #include <rte_common.h>
45 #include <rte_errno.h>
46 #include <rte_ethdev.h>
47 #include <rte_log.h>
48 #include <rte_malloc.h>
49 #include <rte_mbuf.h>
50 #include <rte_memzone.h>
51 #include <rte_spinlock.h>
52 #include <rte_string_fns.h>
53
54 #include "compat_netmap.h"
55
56 struct netmap_port {
57         struct rte_mempool   *pool;
58         struct netmap_if     *nmif;
59         struct rte_eth_conf   eth_conf;
60         struct rte_eth_txconf tx_conf;
61         struct rte_eth_rxconf rx_conf;
62         int32_t  socket_id;
63         uint16_t nr_tx_rings;
64         uint16_t nr_rx_rings;
65         uint32_t nr_tx_slots;
66         uint32_t nr_rx_slots;
67         uint16_t tx_burst;
68         uint16_t rx_burst;
69         uint32_t fd;
70 };
71
72 struct fd_port {
73         uint32_t port;
74 };
75
76 #ifndef POLLRDNORM
77 #define POLLRDNORM      0x0040
78 #endif
79
80 #ifndef POLLWRNORM
81 #define POLLWRNORM      0x0100
82 #endif
83
84 #define FD_PORT_FREE    UINT32_MAX
85 #define FD_PORT_RSRV    (FD_PORT_FREE - 1)
86
87 struct netmap_state {
88         struct rte_netmap_conf conf;
89         uintptr_t buf_start;
90         void     *mem;
91         uint32_t  mem_sz;
92         uint32_t  netif_memsz;
93 };
94
95
96 #define COMPAT_NETMAP_MAX_NOFILE        (2 * RTE_MAX_ETHPORTS)
97 #define COMPAT_NETMAP_MAX_BURST         64
98 #define COMPAT_NETMAP_MAX_PKT_PER_SYNC  (2 * COMPAT_NETMAP_MAX_BURST)
99
100 static struct netmap_port ports[RTE_MAX_ETHPORTS];
101 static struct netmap_state netmap;
102
103 static struct fd_port fd_port[COMPAT_NETMAP_MAX_NOFILE];
104 static const int next_fd_start = RLIMIT_NOFILE + 1;
105 static rte_spinlock_t netmap_lock;
106
107 #define IDX_TO_FD(x)    ((x) + next_fd_start)
108 #define FD_TO_IDX(x)    ((x) - next_fd_start)
109 #define FD_VALID(x)     ((x) >= next_fd_start && \
110         (x) < (typeof (x))(RTE_DIM(fd_port) + next_fd_start))
111
112 #define PORT_NUM_RINGS  (2 * netmap.conf.max_rings)
113 #define PORT_NUM_SLOTS  (PORT_NUM_RINGS * netmap.conf.max_slots)
114
115 #define BUF_IDX(port, ring, slot)            \
116         (((port) * PORT_NUM_RINGS + (ring)) * netmap.conf.max_slots + \
117         (slot))
118
119 #define NETMAP_IF_RING_OFS(rid, rings, slots)   ({\
120         struct netmap_if *_if;                    \
121         struct netmap_ring *_rg;                  \
122         sizeof(*_if) +                            \
123         (rings) * sizeof(_if->ring_ofs[0]) +      \
124         (rid) * sizeof(*_rg) +                    \
125         (slots) * sizeof(_rg->slot[0]);           \
126         })
127
128 static void netmap_unregif(uint32_t idx, uint32_t port);
129
130
131 static int32_t
132 ifname_to_portid(const char *ifname, uint8_t *port)
133 {
134         char *endptr;
135         uint64_t portid;
136
137         errno = 0;
138         portid = strtoul(ifname, &endptr, 10);
139         if (endptr == ifname || *endptr != '\0' ||
140                         portid >= RTE_DIM(ports) || errno != 0)
141                 return (-EINVAL);
142
143         *port = (uint8_t)portid;
144         return (0);
145 }
146
147 /**
148  * Given a dpdk mbuf, fill in the Netmap slot in ring r and its associated
149  * buffer with the data held by the mbuf.
150  * Note that mbuf chains are not supported.
151  */
152 static void
153 mbuf_to_slot(struct rte_mbuf *mbuf, struct netmap_ring *r, uint32_t index)
154 {
155         char *data;
156         uint16_t length;
157
158         data   = rte_pktmbuf_mtod(mbuf, char *);
159         length = rte_pktmbuf_data_len(mbuf);
160
161         if (length > r->nr_buf_size)
162                 length = 0;
163
164         r->slot[index].len = length;
165         rte_memcpy(NETMAP_BUF(r, r->slot[index].buf_idx), data, length);
166 }
167
168 /**
169  * Given a Netmap ring and a slot index for that ring, construct a dpdk mbuf
170  * from the data held in the buffer associated with the slot.
171  * Allocation/deallocation of the dpdk mbuf are the responsability of the
172  * caller.
173  * Note that mbuf chains are not supported.
174  */
175 static void
176 slot_to_mbuf(struct netmap_ring *r, uint32_t index, struct rte_mbuf *mbuf)
177 {
178         char *data;
179         uint16_t length;
180
181         rte_pktmbuf_reset(mbuf);
182         length = r->slot[index].len;
183         data = rte_pktmbuf_append(mbuf, length);
184
185         if (data != NULL)
186             rte_memcpy(data, NETMAP_BUF(r, r->slot[index].buf_idx), length);
187 }
188
189 static int32_t
190 fd_reserve(void)
191 {
192         uint32_t i;
193
194         for (i = 0; i != RTE_DIM(fd_port) && fd_port[i].port != FD_PORT_FREE;
195                         i++)
196                 ;
197
198         if (i == RTE_DIM(fd_port))
199                 return (-ENOMEM);
200
201         fd_port[i].port = FD_PORT_RSRV;
202         return (IDX_TO_FD(i));
203 }
204
205 static int32_t
206 fd_release(int32_t fd)
207 {
208         uint32_t idx, port;
209
210         idx = FD_TO_IDX(fd);
211
212         if (!FD_VALID(fd) || (port = fd_port[idx].port) == FD_PORT_FREE)
213                 return (-EINVAL);
214
215         /* if we still have a valid port attached, release the port */
216         if (port < RTE_DIM(ports) && ports[port].fd == idx) {
217                 netmap_unregif(idx, port);
218         }
219
220         fd_port[idx].port = FD_PORT_FREE;
221         return (0);
222 }
223
224 static int
225 check_nmreq(struct nmreq *req, uint8_t *port)
226 {
227         int32_t rc;
228         uint8_t portid;
229
230         if (req == NULL)
231                 return (-EINVAL);
232
233         if (req->nr_version != NETMAP_API) {
234                 req->nr_version = NETMAP_API;
235                 return (-EINVAL);
236         }
237
238         if ((rc = ifname_to_portid(req->nr_name, &portid)) != 0) {
239                 RTE_LOG(ERR, USER1, "Invalid interface name:\"%s\" "
240                         "in NIOCGINFO call\n", req->nr_name);
241                 return (rc);
242         }
243
244         if (ports[portid].pool == NULL) {
245                 RTE_LOG(ERR, USER1, "Misconfigured portid %hhu\n", portid);
246                 return (-EINVAL);
247         }
248
249         *port = portid;
250         return (0);
251 }
252
253 /**
254  * Simulate a Netmap NIOCGINFO ioctl: given a struct nmreq holding an interface
255  * name (a port number in our case), fill the struct nmreq in with advisory
256  * information about the interface: number of rings and their size, total memory
257  * required in the map, ...
258  * Those are preconfigured using rte_eth_{,tx,rx}conf and
259  * rte_netmap_port_conf structures
260  * and calls to rte_netmap_init_port() in the Netmap application.
261  */
262 static int
263 ioctl_niocginfo(__rte_unused int fd, void * param)
264 {
265         uint8_t portid;
266         struct nmreq *req;
267         int32_t rc;
268
269         req = (struct nmreq *)param;
270         if ((rc = check_nmreq(req, &portid)) != 0)
271                 return (rc);
272
273         req->nr_tx_rings = (uint16_t)(ports[portid].nr_tx_rings - 1);
274         req->nr_rx_rings = (uint16_t)(ports[portid].nr_rx_rings - 1);
275         req->nr_tx_slots = ports[portid].nr_tx_slots;
276         req->nr_rx_slots = ports[portid].nr_rx_slots;
277
278         /* in current implementation we have all NETIFs shared aone region. */
279         req->nr_memsize = netmap.mem_sz;
280         req->nr_offset = 0;
281
282         return (0);
283 }
284
285 static void
286 netmap_ring_setup(struct netmap_ring *ring, uint8_t port, uint32_t ringid,
287         uint32_t num_slots)
288 {
289         uint32_t j;
290
291         ring->buf_ofs = netmap.buf_start - (uintptr_t)ring;
292         ring->num_slots = num_slots;
293         ring->cur = 0;
294         ring->reserved = 0;
295         ring->nr_buf_size = netmap.conf.max_bufsz;
296         ring->flags = 0;
297         ring->ts.tv_sec = 0;
298         ring->ts.tv_usec = 0;
299
300         for (j = 0; j < ring->num_slots; j++) {
301                 ring->slot[j].buf_idx = BUF_IDX(port, ringid, j);
302                 ring->slot[j].len = 0;
303                 ring->flags = 0;
304         }
305 }
306
307 static int
308 netmap_regif(struct nmreq *req, uint32_t idx, uint8_t port)
309 {
310         struct netmap_if *nmif;
311         struct netmap_ring *ring;
312         uint32_t i, slots, start_ring;
313         int32_t rc;
314
315         if (ports[port].fd < RTE_DIM(fd_port)) {
316                 RTE_LOG(ERR, USER1, "port %hhu already in use by fd: %u\n",
317                         port, IDX_TO_FD(ports[port].fd));
318                 return (-EBUSY);
319         }
320         if (fd_port[idx].port != FD_PORT_RSRV) {
321                 RTE_LOG(ERR, USER1, "fd: %u is misconfigured\n",
322                         IDX_TO_FD(idx));
323                 return (-EBUSY);
324         }
325
326         nmif = ports[port].nmif;
327
328         /* setup netmap_if fields. */
329         memset(nmif, 0, netmap.netif_memsz);
330
331         /* only ALL rings supported right now. */
332         if (req->nr_ringid != 0)
333                 return (-EINVAL);
334
335         snprintf(nmif->ni_name, sizeof(nmif->ni_name), "%s", req->nr_name);
336         nmif->ni_version  = req->nr_version;
337
338         /* Netmap uses ni_(r|t)x_rings + 1 */
339         nmif->ni_rx_rings = ports[port].nr_rx_rings - 1;
340         nmif->ni_tx_rings = ports[port].nr_tx_rings - 1;
341
342         /*
343          * Setup TX rings and slots.
344          * Refer to the comments in netmap.h for details
345          */
346
347         slots = 0;
348         for (i = 0; i < nmif->ni_tx_rings + 1; i++) {
349
350                 nmif->ring_ofs[i] = NETMAP_IF_RING_OFS(i,
351                         PORT_NUM_RINGS, slots);
352
353                 ring = NETMAP_TXRING(nmif, i);
354                 netmap_ring_setup(ring, port, i, ports[port].nr_tx_slots);
355                 ring->avail = ring->num_slots;
356
357                 slots += ports[port].nr_tx_slots;
358         }
359
360         /*
361          * Setup  RX rings and slots.
362          * Refer to the comments in netmap.h for details
363          */
364
365         start_ring = i;
366
367         for (; i < nmif->ni_rx_rings + 1 + start_ring; i++) {
368
369                 nmif->ring_ofs[i] = NETMAP_IF_RING_OFS(i,
370                         PORT_NUM_RINGS, slots);
371
372                 ring = NETMAP_RXRING(nmif, (i - start_ring));
373                 netmap_ring_setup(ring, port, i, ports[port].nr_rx_slots);
374                 ring->avail = 0;
375
376                 slots += ports[port].nr_rx_slots;
377         }
378
379         if ((rc = rte_eth_dev_start(port)) < 0) {
380                 RTE_LOG(ERR, USER1,
381                         "Couldn't start ethernet device %s (error %d)\n",
382                         req->nr_name, rc);
383             return (rc);
384         }
385
386         /* setup fdi <--> port relationtip. */
387         ports[port].fd = idx;
388         fd_port[idx].port = port;
389
390         req->nr_memsize = netmap.mem_sz;
391         req->nr_offset = (uintptr_t)nmif - (uintptr_t)netmap.mem;
392
393         return (0);
394 }
395
396 /**
397  * Simulate a Netmap NIOCREGIF ioctl:
398  */
399 static int
400 ioctl_niocregif(int32_t fd, void * param)
401 {
402         uint8_t portid;
403         int32_t rc;
404         uint32_t idx;
405         struct nmreq *req;
406
407         req = (struct nmreq *)param;
408         if ((rc = check_nmreq(req, &portid)) != 0)
409                 return (rc);
410
411         idx = FD_TO_IDX(fd);
412
413         rte_spinlock_lock(&netmap_lock);
414         rc = netmap_regif(req, idx, portid);
415         rte_spinlock_unlock(&netmap_lock);
416
417         return (rc);
418 }
419
420 static void
421 netmap_unregif(uint32_t idx, uint32_t port)
422 {
423         fd_port[idx].port = FD_PORT_RSRV;
424         ports[port].fd = UINT32_MAX;
425         rte_eth_dev_stop((uint8_t)port);
426 }
427
428 /**
429  * Simulate a Netmap NIOCUNREGIF ioctl: put an interface running in Netmap
430  * mode back in "normal" mode. In our case, we just stop the port associated
431  * with this file descriptor.
432  */
433 static int
434 ioctl_niocunregif(int fd)
435 {
436         uint32_t idx, port;
437         int32_t rc;
438
439         idx = FD_TO_IDX(fd);
440
441         rte_spinlock_lock(&netmap_lock);
442
443         port = fd_port[idx].port;
444         if (port < RTE_DIM(ports) && ports[port].fd == idx) {
445                 netmap_unregif(idx, port);
446                 rc = 0;
447         } else {
448                 RTE_LOG(ERR, USER1,
449                         "%s: %d is not associated with valid port\n",
450                         __func__, fd);
451                 rc = -EINVAL;
452         }
453
454         rte_spinlock_unlock(&netmap_lock);
455         return (rc);
456 }
457
458 /**
459  * A call to rx_sync_ring will try to fill a Netmap RX ring with as many
460  * packets as it can hold coming from its dpdk port.
461  */
462 static inline int
463 rx_sync_ring(struct netmap_ring *ring, uint8_t port, uint16_t ring_number,
464         uint16_t max_burst)
465 {
466         int32_t i, n_rx;
467         uint16_t burst_size;
468         uint32_t cur_slot, n_free_slots;
469         struct rte_mbuf *rx_mbufs[COMPAT_NETMAP_MAX_BURST];
470
471         n_free_slots = ring->num_slots - (ring->avail + ring->reserved);
472         n_free_slots = RTE_MIN(n_free_slots, max_burst);
473         cur_slot = (ring->cur + ring->avail) & (ring->num_slots - 1);
474
475         while (n_free_slots) {
476                 burst_size = (uint16_t)RTE_MIN(n_free_slots, RTE_DIM(rx_mbufs));
477
478                 /* receive up to burst_size packets from the NIC's queue */
479                 n_rx = rte_eth_rx_burst(port, ring_number, rx_mbufs,
480                         burst_size);
481
482                 if (n_rx == 0)
483                         return 0;
484                 if (unlikely(n_rx < 0))
485                         return -1;
486
487                 /* Put those n_rx packets in the Netmap structures */
488                 for (i = 0; i < n_rx ; i++) {
489                         mbuf_to_slot(rx_mbufs[i], ring, cur_slot);
490                         rte_pktmbuf_free(rx_mbufs[i]);
491                         cur_slot = NETMAP_RING_NEXT(ring, cur_slot);
492                 }
493
494                 /* Update the Netmap ring structure to reflect the change */
495                 ring->avail += n_rx;
496                 n_free_slots -= n_rx;
497         }
498
499         return 0;
500 }
501
502 static inline int
503 rx_sync_if(uint32_t port)
504 {
505         uint16_t burst;
506         uint32_t i, rc;
507         struct netmap_if *nifp;
508         struct netmap_ring *r;
509
510         nifp = ports[port].nmif;
511         burst = ports[port].rx_burst;
512         rc = 0;
513
514         for (i = 0; i < nifp->ni_rx_rings + 1; i++) {
515                 r = NETMAP_RXRING(nifp, i);
516                 rx_sync_ring(r, (uint8_t)port, (uint16_t)i, burst);
517                 rc += r->avail;
518         }
519
520         return (rc);
521 }
522
523 /**
524  * Simulate a Netmap NIOCRXSYNC ioctl:
525  */
526 static int
527 ioctl_niocrxsync(int fd)
528 {
529         uint32_t idx, port;
530
531         idx = FD_TO_IDX(fd);
532         if ((port = fd_port[idx].port) < RTE_DIM(ports) &&
533                         ports[port].fd == idx) {
534                 return (rx_sync_if(fd_port[idx].port));
535         } else  {
536                 return (-EINVAL);
537         }
538 }
539
540 /**
541  * A call to tx_sync_ring will try to empty a Netmap TX ring by converting its
542  * buffers into rte_mbufs and sending them out on the rings's dpdk port.
543  */
544 static int
545 tx_sync_ring(struct netmap_ring *ring, uint8_t port, uint16_t ring_number,
546         struct rte_mempool *pool, uint16_t max_burst)
547 {
548         uint32_t i, n_tx;
549         uint16_t burst_size;
550         uint32_t cur_slot, n_used_slots;
551         struct rte_mbuf *tx_mbufs[COMPAT_NETMAP_MAX_BURST];
552
553         n_used_slots = ring->num_slots - ring->avail;
554         n_used_slots = RTE_MIN(n_used_slots, max_burst);
555         cur_slot = (ring->cur + ring->avail) & (ring->num_slots - 1);
556
557         while (n_used_slots) {
558                 burst_size = (uint16_t)RTE_MIN(n_used_slots, RTE_DIM(tx_mbufs));
559
560                 for (i = 0; i < burst_size; i++) {
561                         tx_mbufs[i] = rte_pktmbuf_alloc(pool);
562                         if (tx_mbufs[i] == NULL)
563                                 goto err;
564
565                         slot_to_mbuf(ring, cur_slot, tx_mbufs[i]);
566                         cur_slot = NETMAP_RING_NEXT(ring, cur_slot);
567                 }
568
569                 n_tx = rte_eth_tx_burst(port, ring_number, tx_mbufs,
570                         burst_size);
571
572                 /* Update the Netmap ring structure to reflect the change */
573                 ring->avail += n_tx;
574                 n_used_slots -= n_tx;
575
576                 /* Return the mbufs that failed to transmit to their pool */
577                 if (unlikely(n_tx != burst_size)) {
578                         for (i = n_tx; i < burst_size; i++)
579                                 rte_pktmbuf_free(tx_mbufs[i]);
580                         break;
581                 }
582         }
583
584         return 0;
585
586 err:
587         for (; i == 0; --i)
588                 rte_pktmbuf_free(tx_mbufs[i]);
589
590         RTE_LOG(ERR, USER1,
591                 "Couldn't get mbuf from mempool is the mempool too small?\n");
592         return -1;
593 }
594
595 static int
596 tx_sync_if(uint32_t port)
597 {
598         uint16_t burst;
599         uint32_t i, rc;
600         struct netmap_if *nifp;
601         struct netmap_ring *r;
602         struct rte_mempool *mp;
603
604         nifp = ports[port].nmif;
605         mp = ports[port].pool;
606         burst = ports[port].tx_burst;
607         rc = 0;
608
609         for (i = 0; i < nifp->ni_tx_rings + 1; i++) {
610                 r = NETMAP_TXRING(nifp, i);
611                 tx_sync_ring(r, (uint8_t)port, (uint16_t)i, mp, burst);
612                 rc += r->avail;
613         }
614
615         return (rc);
616 }
617
618 /**
619  * Simulate a Netmap NIOCTXSYNC ioctl:
620  */
621 static inline int
622 ioctl_nioctxsync(int fd)
623 {
624         uint32_t idx, port;
625
626         idx = FD_TO_IDX(fd);
627         if ((port = fd_port[idx].port) < RTE_DIM(ports) &&
628                         ports[port].fd == idx) {
629                 return (tx_sync_if(fd_port[idx].port));
630         } else  {
631                 return (-EINVAL);
632         }
633 }
634
635 /**
636  * Give the library a mempool of rte_mbufs with which it can do the
637  * rte_mbuf <--> netmap slot conversions.
638  */
639 int
640 rte_netmap_init(const struct rte_netmap_conf *conf)
641 {
642         size_t buf_ofs, nmif_sz, sz;
643         size_t port_rings, port_slots, port_bufs;
644         uint32_t i, port_num;
645
646         port_num = RTE_MAX_ETHPORTS;
647         port_rings = 2 * conf->max_rings;
648         port_slots = port_rings * conf->max_slots;
649         port_bufs = port_slots;
650
651         nmif_sz = NETMAP_IF_RING_OFS(port_rings, port_rings, port_slots);
652         sz = nmif_sz * port_num;
653
654         buf_ofs = RTE_ALIGN_CEIL(sz, RTE_CACHE_LINE_SIZE);
655         sz = buf_ofs + port_bufs * conf->max_bufsz * port_num;
656
657         if (sz > UINT32_MAX ||
658                         (netmap.mem = rte_zmalloc_socket(__func__, sz,
659                         RTE_CACHE_LINE_SIZE, conf->socket_id)) == NULL) {
660                 RTE_LOG(ERR, USER1, "%s: failed to allocate %zu bytes\n",
661                         __func__, sz);
662                 return (-ENOMEM);
663         }
664
665         netmap.mem_sz = sz;
666         netmap.netif_memsz = nmif_sz;
667         netmap.buf_start = (uintptr_t)netmap.mem + buf_ofs;
668         netmap.conf = *conf;
669
670         rte_spinlock_init(&netmap_lock);
671
672         /* Mark all ports as unused and set NETIF pointer. */
673         for (i = 0; i != RTE_DIM(ports); i++) {
674                 ports[i].fd = UINT32_MAX;
675                 ports[i].nmif = (struct netmap_if *)
676                         ((uintptr_t)netmap.mem + nmif_sz * i);
677         }
678
679         /* Mark all fd_ports as unused. */
680         for (i = 0; i != RTE_DIM(fd_port); i++) {
681                 fd_port[i].port = FD_PORT_FREE;
682         }
683
684         return (0);
685 }
686
687
688 int
689 rte_netmap_init_port(uint8_t portid, const struct rte_netmap_port_conf *conf)
690 {
691         int32_t ret;
692         uint16_t i;
693         uint16_t rx_slots, tx_slots;
694
695         if (conf == NULL ||
696                         portid >= RTE_DIM(ports) ||
697                         conf->nr_tx_rings > netmap.conf.max_rings ||
698                         conf->nr_rx_rings > netmap.conf.max_rings) {
699                 RTE_LOG(ERR, USER1, "%s(%hhu): invalid parameters\n",
700                         __func__, portid);
701                 return (-EINVAL);
702         }
703
704                 rx_slots = (uint16_t)rte_align32pow2(conf->nr_rx_slots);
705                 tx_slots = (uint16_t)rte_align32pow2(conf->nr_tx_slots);
706
707         if (tx_slots > netmap.conf.max_slots ||
708                         rx_slots > netmap.conf.max_slots) {
709                 RTE_LOG(ERR, USER1, "%s(%hhu): invalid parameters\n",
710                         __func__, portid);
711                 return (-EINVAL);
712         }
713
714         ret = rte_eth_dev_configure(portid, conf->nr_rx_rings,
715                 conf->nr_tx_rings, conf->eth_conf);
716
717         if (ret < 0) {
718             RTE_LOG(ERR, USER1, "Couldn't configure port %hhu\n", portid);
719             return (ret);
720         }
721
722         for (i = 0; i < conf->nr_tx_rings; i++) {
723                 ret = rte_eth_tx_queue_setup(portid, i, tx_slots,
724                         conf->socket_id, NULL);
725
726                 if (ret < 0) {
727                         RTE_LOG(ERR, USER1,
728                                 "Couldn't configure TX queue %"PRIu16" of "
729                                 "port %"PRIu8"\n",
730                                 i, portid);
731                         return (ret);
732                 }
733
734                 ret = rte_eth_rx_queue_setup(portid, i, rx_slots,
735                         conf->socket_id, NULL, conf->pool);
736
737                 if (ret < 0) {
738                         RTE_LOG(ERR, USER1,
739                                 "Couldn't configure RX queue %"PRIu16" of "
740                                 "port %"PRIu8"\n",
741                                 i, portid);
742                         return (ret);
743                 }
744         }
745
746         /* copy config to the private storage. */
747         ports[portid].eth_conf = conf->eth_conf[0];
748         ports[portid].pool = conf->pool;
749         ports[portid].socket_id = conf->socket_id;
750         ports[portid].nr_tx_rings = conf->nr_tx_rings;
751         ports[portid].nr_rx_rings = conf->nr_rx_rings;
752         ports[portid].nr_tx_slots = tx_slots;
753         ports[portid].nr_rx_slots = rx_slots;
754         ports[portid].tx_burst = conf->tx_burst;
755         ports[portid].rx_burst = conf->rx_burst;
756
757         return (0);
758 }
759
760 int
761 rte_netmap_close(__rte_unused int fd)
762 {
763         int32_t rc;
764
765         rte_spinlock_lock(&netmap_lock);
766         rc = fd_release(fd);
767         rte_spinlock_unlock(&netmap_lock);
768
769         if (rc < 0) {
770                 errno =-rc;
771                 rc = -1;
772         }
773         return (rc);
774 }
775
776 int rte_netmap_ioctl(int fd, uint32_t op, void *param)
777 {
778         int ret;
779
780         if (!FD_VALID(fd)) {
781             errno = EBADF;
782             return (-1);
783         }
784
785         switch (op) {
786
787             case NIOCGINFO:
788                 ret = ioctl_niocginfo(fd, param);
789                 break;
790
791             case NIOCREGIF:
792                 ret = ioctl_niocregif(fd, param);
793                 break;
794
795             case NIOCUNREGIF:
796                 ret = ioctl_niocunregif(fd);
797                 break;
798
799             case NIOCRXSYNC:
800                 ret = ioctl_niocrxsync(fd);
801                 break;
802
803             case NIOCTXSYNC:
804                 ret = ioctl_nioctxsync(fd);
805                 break;
806
807             default:
808                 ret = -ENOTTY;
809         }
810
811         if (ret < 0) {
812                 errno = -ret;
813                 ret = -1;
814         } else {
815                 ret = 0;
816         }
817
818         return (ret);
819 }
820
821 void *
822 rte_netmap_mmap(void *addr, size_t length,
823         int prot, int flags, int fd, off_t offset)
824 {
825         static const int cprot = PROT_WRITE | PROT_READ;
826
827         if (!FD_VALID(fd) || length + offset > netmap.mem_sz ||
828                         (prot & cprot) != cprot ||
829                         ((flags & MAP_FIXED) != 0 && addr != NULL)) {
830
831                 errno = EINVAL;
832                 return (MAP_FAILED);
833         }
834
835         return (void *)((uintptr_t)netmap.mem + (uintptr_t)offset);
836 }
837
838 /**
839  * Return a "fake" file descriptor with a value above RLIMIT_NOFILE so that
840  * any attempt to use that file descriptor with the usual API will fail.
841  */
842 int
843 rte_netmap_open(__rte_unused const char *pathname, __rte_unused int flags)
844 {
845         int fd;
846
847         rte_spinlock_lock(&netmap_lock);
848         fd = fd_reserve();
849         rte_spinlock_unlock(&netmap_lock);
850
851         if (fd < 0) {
852                 errno = -fd;
853                 fd = -1;
854         }
855         return (fd);
856 }
857
858 /**
859  * Doesn't support timeout other than 0 or infinite (negative) timeout
860  */
861 int
862 rte_netmap_poll(struct pollfd *fds, nfds_t nfds, int timeout)
863 {
864         int32_t count_it, ret;
865         uint32_t i, idx, port;
866         uint32_t want_rx, want_tx;
867
868         ret = 0;
869         do {
870                 for (i = 0; i < nfds; i++) {
871
872                         count_it = 0;
873
874                         if (!FD_VALID(fds[i].fd) || fds[i].events == 0) {
875                                 fds[i].revents = 0;
876                                 continue;
877                         }
878
879                         idx = FD_TO_IDX(fds[i].fd);
880                         if ((port = fd_port[idx].port) >= RTE_DIM(ports) ||
881                 ports[port].fd != idx) {
882
883                                 fds[i].revents |= POLLERR;
884                                 ret++;
885                                 continue;
886                         }
887
888                         want_rx = fds[i].events & (POLLIN  | POLLRDNORM);
889                         want_tx = fds[i].events & (POLLOUT | POLLWRNORM);
890
891                         if (want_rx && rx_sync_if(port) > 0) {
892                                 fds[i].revents = (uint16_t)
893                                         (fds[i].revents | want_rx);
894                                 count_it = 1;
895                         }
896                         if (want_tx && tx_sync_if(port) > 0) {
897                                 fds[i].revents = (uint16_t)
898                                         (fds[i].revents | want_tx);
899                                 count_it = 1;
900                         }
901
902                         ret += count_it;
903                 }
904         }
905         while ((ret == 0 && timeout < 0) || timeout);
906
907         return ret;
908 }