]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - tools/tools/netmap/nm_util.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / tools / tools / netmap / nm_util.c
1 /*
2  * Copyright (C) 2012 Luigi Rizzo. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
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.
12  *
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
23  * SUCH DAMAGE.
24  */
25
26 /*
27  * $FreeBSD$
28  * $Id$
29  *
30  * utilities to use netmap devices.
31  * This does the basic functions of opening a device and issuing
32  * ioctls()
33  */
34
35 #include "nm_util.h"
36
37 extern int verbose;
38
39 int
40 nm_do_ioctl(struct my_ring *me, u_long what, int subcmd)
41 {
42         struct ifreq ifr;
43         int error;
44 #if defined( __FreeBSD__ ) || defined (__APPLE__)
45         int fd = me->fd;
46 #endif
47 #ifdef linux 
48         struct ethtool_value eval;
49         int fd;
50         fd = socket(AF_INET, SOCK_DGRAM, 0);
51         if (fd < 0) {
52                 printf("Error: cannot get device control socket.\n");
53                 return -1;
54         }
55 #endif /* linux */
56
57         (void)subcmd;   // unused
58         bzero(&ifr, sizeof(ifr));
59         strncpy(ifr.ifr_name, me->ifname, sizeof(ifr.ifr_name));
60         switch (what) {
61         case SIOCSIFFLAGS:
62 #ifndef __APPLE__
63                 ifr.ifr_flagshigh = me->if_flags >> 16;
64 #endif
65                 ifr.ifr_flags = me->if_flags & 0xffff;
66                 break;
67
68 #if defined( __FreeBSD__ )
69         case SIOCSIFCAP:
70                 ifr.ifr_reqcap = me->if_reqcap;
71                 ifr.ifr_curcap = me->if_curcap;
72                 break;
73 #endif
74 #ifdef linux
75         case SIOCETHTOOL:
76                 eval.cmd = subcmd;
77                 eval.data = 0;
78                 ifr.ifr_data = (caddr_t)&eval;
79                 break;
80 #endif /* linux */
81         }
82         error = ioctl(fd, what, &ifr);
83         if (error)
84                 goto done;
85         switch (what) {
86         case SIOCGIFFLAGS:
87 #ifndef __APPLE__
88                 me->if_flags = (ifr.ifr_flagshigh << 16) |
89                         (0xffff & ifr.ifr_flags);
90 #endif
91                 if (verbose)
92                         D("flags are 0x%x", me->if_flags);
93                 break;
94
95 #if defined( __FreeBSD__ )
96         case SIOCGIFCAP:
97                 me->if_reqcap = ifr.ifr_reqcap;
98                 me->if_curcap = ifr.ifr_curcap;
99                 if (verbose)
100                         D("curcap are 0x%x", me->if_curcap);
101                 break;
102 #endif /* __FreeBSD__ */
103         }
104 done:
105 #ifdef linux
106         close(fd);
107 #endif
108         if (error)
109                 D("ioctl error %d %lu", error, what);
110         return error;
111 }
112
113 /*
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.
117  */
118 int
119 netmap_open(struct my_ring *me, int ringid, int promisc)
120 {
121         int fd, err, l;
122         struct nmreq req;
123
124         me->fd = fd = open("/dev/netmap", O_RDWR);
125         if (fd < 0) {
126                 D("Unable to open /dev/netmap");
127                 return (-1);
128         }
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);
134         if (err) {
135                 D("cannot get info on %s, errno %d ver %d",
136                         me->ifname, errno, req.nr_version);
137                 goto error;
138         }
139         me->memsize = l = req.nr_memsize;
140         if (verbose)
141                 D("memsize is %d MB", l>>20);
142         err = ioctl(fd, NIOCREGIF, &req);
143         if (err) {
144                 D("Unable to register %s", me->ifname);
145                 goto error;
146         }
147
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) {
151                         D("Unable to mmap");
152                         me->mem = NULL;
153                         goto error;
154                 }
155         }
156
157
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;
164                 }
165                 if (promisc) {
166                         me[0].if_flags |= IFF_PPROMISC;
167                         nm_do_ioctl(me, SIOCSIFFLAGS, 0);
168                 }
169
170 #ifdef __FreeBSD__
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);
176 #endif
177 #ifdef linux
178                 /* disable:
179                  * - generic-segmentation-offload
180                  * - tcp-segmentation-offload
181                  * - rx-checksumming
182                  * - tx-checksumming
183                  * XXX check how to set back the caps.
184                  */
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);
189 #endif /* linux */
190         }
191
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);
205         } else {
206                 me->begin = 0;
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);
210         }
211         return (0);
212 error:
213         close(me->fd);
214         return -1;
215 }
216
217
218 int
219 netmap_close(struct my_ring *me)
220 {
221         D("");
222         if (me->mem)
223                 munmap(me->mem, me->memsize);
224         close(me->fd);
225         return (0);
226 }
227
228
229 /*
230  * how many packets on this set of queues ?
231  */
232 int
233 pkt_queued(struct my_ring *me, int tx)
234 {
235         u_int i, tot = 0;
236
237         ND("me %p begin %d end %d", me, me->begin, me->end);
238         for (i = me->begin; i < me->end; i++) {
239                 struct netmap_ring *ring = tx ?
240                         NETMAP_TXRING(me->nifp, i) : NETMAP_RXRING(me->nifp, i);
241                 tot += ring->avail;
242         }
243         if (0 && verbose && tot && !tx)
244                 D("ring %s %s %s has %d avail at %d",
245                         me->ifname, tx ? "tx": "rx",
246                         me->end >= me->nifp->ni_tx_rings ? // XXX who comes first ?
247                                 "host":"net",
248                         tot, NETMAP_TXRING(me->nifp, me->begin)->cur);
249         return tot;
250 }