2 * Copyright (C) 2012 Luigi Rizzo. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * utilities to use netmap devices.
31 * This does the basic functions of opening a device and issuing
40 nm_do_ioctl(struct my_ring *me, u_long what, int subcmd)
44 #if defined( __FreeBSD__ ) || defined (__APPLE__)
48 struct ethtool_value eval;
50 fd = socket(AF_INET, SOCK_DGRAM, 0);
52 printf("Error: cannot get device control socket.\n");
57 (void)subcmd; // unused
58 bzero(&ifr, sizeof(ifr));
59 strncpy(ifr.ifr_name, me->ifname, sizeof(ifr.ifr_name));
63 ifr.ifr_flagshigh = me->if_flags >> 16;
65 ifr.ifr_flags = me->if_flags & 0xffff;
68 #if defined( __FreeBSD__ )
70 ifr.ifr_reqcap = me->if_reqcap;
71 ifr.ifr_curcap = me->if_curcap;
78 ifr.ifr_data = (caddr_t)&eval;
82 error = ioctl(fd, what, &ifr);
88 me->if_flags = (ifr.ifr_flagshigh << 16) |
89 (0xffff & ifr.ifr_flags);
92 D("flags are 0x%x", me->if_flags);
95 #if defined( __FreeBSD__ )
97 me->if_reqcap = ifr.ifr_reqcap;
98 me->if_curcap = ifr.ifr_curcap;
100 D("curcap are 0x%x", me->if_curcap);
102 #endif /* __FreeBSD__ */
109 D("ioctl error %d %lu", error, what);
114 * open a device. if me->mem is null then do an mmap.
115 * Returns the file descriptor.
116 * The extra flag checks configures promisc mode.
119 netmap_open(struct my_ring *me, int ringid, int promisc)
124 me->fd = fd = open("/dev/netmap", O_RDWR);
126 D("Unable to open /dev/netmap");
129 bzero(&req, sizeof(req));
130 req.nr_version = NETMAP_API;
131 strncpy(req.nr_name, me->ifname, sizeof(req.nr_name));
132 req.nr_ringid = ringid;
133 err = ioctl(fd, NIOCGINFO, &req);
135 D("cannot get info on %s, errno %d ver %d",
136 me->ifname, errno, req.nr_version);
139 me->memsize = l = req.nr_memsize;
141 D("memsize is %d MB", l>>20);
142 err = ioctl(fd, NIOCREGIF, &req);
144 D("Unable to register %s", me->ifname);
148 if (me->mem == NULL) {
149 me->mem = mmap(0, l, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0);
150 if (me->mem == MAP_FAILED) {
158 /* Set the operating mode. */
159 if (ringid != NETMAP_SW_RING) {
160 nm_do_ioctl(me, SIOCGIFFLAGS, 0);
161 if ((me[0].if_flags & IFF_UP) == 0) {
162 D("%s is down, bringing up...", me[0].ifname);
163 me[0].if_flags |= IFF_UP;
166 me[0].if_flags |= IFF_PPROMISC;
167 nm_do_ioctl(me, SIOCSIFFLAGS, 0);
171 /* also disable checksums etc. */
172 nm_do_ioctl(me, SIOCGIFCAP, 0);
173 me[0].if_reqcap = me[0].if_curcap;
174 me[0].if_reqcap &= ~(IFCAP_HWCSUM | IFCAP_TSO | IFCAP_TOE);
175 nm_do_ioctl(me+0, SIOCSIFCAP, 0);
179 * - generic-segmentation-offload
180 * - tcp-segmentation-offload
183 * XXX check how to set back the caps.
185 nm_do_ioctl(me, SIOCETHTOOL, ETHTOOL_SGSO);
186 nm_do_ioctl(me, SIOCETHTOOL, ETHTOOL_STSO);
187 nm_do_ioctl(me, SIOCETHTOOL, ETHTOOL_SRXCSUM);
188 nm_do_ioctl(me, SIOCETHTOOL, ETHTOOL_STXCSUM);
192 me->nifp = NETMAP_IF(me->mem, req.nr_offset);
193 me->queueid = ringid;
194 if (ringid & NETMAP_SW_RING) {
195 me->begin = req.nr_rx_rings;
196 me->end = me->begin + 1;
197 me->tx = NETMAP_TXRING(me->nifp, req.nr_tx_rings);
198 me->rx = NETMAP_RXRING(me->nifp, req.nr_rx_rings);
199 } else if (ringid & NETMAP_HW_RING) {
200 D("XXX check multiple threads");
201 me->begin = ringid & NETMAP_RING_MASK;
202 me->end = me->begin + 1;
203 me->tx = NETMAP_TXRING(me->nifp, me->begin);
204 me->rx = NETMAP_RXRING(me->nifp, me->begin);
207 me->end = req.nr_rx_rings; // XXX max of the two
208 me->tx = NETMAP_TXRING(me->nifp, 0);
209 me->rx = NETMAP_RXRING(me->nifp, 0);
219 netmap_close(struct my_ring *me)
223 munmap(me->mem, me->memsize);
224 ioctl(me->fd, NIOCUNREGIF, NULL);
231 * how many packets on this set of queues ?
234 pkt_queued(struct my_ring *me, int tx)
238 ND("me %p begin %d end %d", me, me->begin, me->end);
239 for (i = me->begin; i < me->end; i++) {
240 struct netmap_ring *ring = tx ?
241 NETMAP_TXRING(me->nifp, i) : NETMAP_RXRING(me->nifp, i);
244 if (0 && verbose && tot && !tx)
245 D("ring %s %s %s has %d avail at %d",
246 me->ifname, tx ? "tx": "rx",
247 me->end >= me->nifp->ni_tx_rings ? // XXX who comes first ?
249 tot, NETMAP_TXRING(me->nifp, me->begin)->cur);