]> git.proxmox.com Git - mirror_qemu.git/blob - net/netmap.c
net: add offloading support to netmap backend
[mirror_qemu.git] / net / netmap.c
1 /*
2 * netmap access for qemu
3 *
4 * Copyright (c) 2012-2013 Luigi Rizzo
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24
25
26 #include <sys/ioctl.h>
27 #include <net/if.h>
28 #include <sys/mman.h>
29 #include <stdint.h>
30 #include <net/netmap.h>
31 #include <net/netmap_user.h>
32
33 #include "net/net.h"
34 #include "net/tap.h"
35 #include "clients.h"
36 #include "sysemu/sysemu.h"
37 #include "qemu/error-report.h"
38 #include "qemu/iov.h"
39
40 /* Private netmap device info. */
41 typedef struct NetmapPriv {
42 int fd;
43 size_t memsize;
44 void *mem;
45 struct netmap_if *nifp;
46 struct netmap_ring *rx;
47 struct netmap_ring *tx;
48 char fdname[PATH_MAX]; /* Normally "/dev/netmap". */
49 char ifname[IFNAMSIZ];
50 } NetmapPriv;
51
52 typedef struct NetmapState {
53 NetClientState nc;
54 NetmapPriv me;
55 bool read_poll;
56 bool write_poll;
57 struct iovec iov[IOV_MAX];
58 int vnet_hdr_len; /* Current virtio-net header length. */
59 } NetmapState;
60
61 #define D(format, ...) \
62 do { \
63 struct timeval __xxts; \
64 gettimeofday(&__xxts, NULL); \
65 printf("%03d.%06d %s [%d] " format "\n", \
66 (int)__xxts.tv_sec % 1000, (int)__xxts.tv_usec, \
67 __func__, __LINE__, ##__VA_ARGS__); \
68 } while (0)
69
70 /* Rate limited version of "D", lps indicates how many per second */
71 #define RD(lps, format, ...) \
72 do { \
73 static int t0, __cnt; \
74 struct timeval __xxts; \
75 gettimeofday(&__xxts, NULL); \
76 if (t0 != __xxts.tv_sec) { \
77 t0 = __xxts.tv_sec; \
78 __cnt = 0; \
79 } \
80 if (__cnt++ < lps) { \
81 D(format, ##__VA_ARGS__); \
82 } \
83 } while (0)
84
85
86 #ifndef __FreeBSD__
87 #define pkt_copy bcopy
88 #else
89 /* A fast copy routine only for multiples of 64 bytes, non overlapped. */
90 static inline void
91 pkt_copy(const void *_src, void *_dst, int l)
92 {
93 const uint64_t *src = _src;
94 uint64_t *dst = _dst;
95 if (unlikely(l >= 1024)) {
96 bcopy(src, dst, l);
97 return;
98 }
99 for (; l > 0; l -= 64) {
100 *dst++ = *src++;
101 *dst++ = *src++;
102 *dst++ = *src++;
103 *dst++ = *src++;
104 *dst++ = *src++;
105 *dst++ = *src++;
106 *dst++ = *src++;
107 *dst++ = *src++;
108 }
109 }
110 #endif /* __FreeBSD__ */
111
112 /*
113 * Open a netmap device. We assume there is only one queue
114 * (which is the case for the VALE bridge).
115 */
116 static int netmap_open(NetmapPriv *me)
117 {
118 int fd;
119 int err;
120 size_t l;
121 struct nmreq req;
122
123 me->fd = fd = open(me->fdname, O_RDWR);
124 if (fd < 0) {
125 error_report("Unable to open netmap device '%s' (%s)",
126 me->fdname, strerror(errno));
127 return -1;
128 }
129 memset(&req, 0, sizeof(req));
130 pstrcpy(req.nr_name, sizeof(req.nr_name), me->ifname);
131 req.nr_ringid = NETMAP_NO_TX_POLL;
132 req.nr_version = NETMAP_API;
133 err = ioctl(fd, NIOCREGIF, &req);
134 if (err) {
135 error_report("Unable to register %s: %s", me->ifname, strerror(errno));
136 goto error;
137 }
138 l = me->memsize = req.nr_memsize;
139
140 me->mem = mmap(0, l, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0);
141 if (me->mem == MAP_FAILED) {
142 error_report("Unable to mmap netmap shared memory: %s",
143 strerror(errno));
144 me->mem = NULL;
145 goto error;
146 }
147
148 me->nifp = NETMAP_IF(me->mem, req.nr_offset);
149 me->tx = NETMAP_TXRING(me->nifp, 0);
150 me->rx = NETMAP_RXRING(me->nifp, 0);
151 return 0;
152
153 error:
154 close(me->fd);
155 return -1;
156 }
157
158 /* Tell the event-loop if the netmap backend can send packets
159 to the frontend. */
160 static int netmap_can_send(void *opaque)
161 {
162 NetmapState *s = opaque;
163
164 return qemu_can_send_packet(&s->nc);
165 }
166
167 static void netmap_send(void *opaque);
168 static void netmap_writable(void *opaque);
169
170 /* Set the event-loop handlers for the netmap backend. */
171 static void netmap_update_fd_handler(NetmapState *s)
172 {
173 qemu_set_fd_handler2(s->me.fd,
174 s->read_poll ? netmap_can_send : NULL,
175 s->read_poll ? netmap_send : NULL,
176 s->write_poll ? netmap_writable : NULL,
177 s);
178 }
179
180 /* Update the read handler. */
181 static void netmap_read_poll(NetmapState *s, bool enable)
182 {
183 if (s->read_poll != enable) { /* Do nothing if not changed. */
184 s->read_poll = enable;
185 netmap_update_fd_handler(s);
186 }
187 }
188
189 /* Update the write handler. */
190 static void netmap_write_poll(NetmapState *s, bool enable)
191 {
192 if (s->write_poll != enable) {
193 s->write_poll = enable;
194 netmap_update_fd_handler(s);
195 }
196 }
197
198 static void netmap_poll(NetClientState *nc, bool enable)
199 {
200 NetmapState *s = DO_UPCAST(NetmapState, nc, nc);
201
202 if (s->read_poll != enable || s->write_poll != enable) {
203 s->read_poll = enable;
204 s->read_poll = enable;
205 netmap_update_fd_handler(s);
206 }
207 }
208
209 /*
210 * The fd_write() callback, invoked if the fd is marked as
211 * writable after a poll. Unregister the handler and flush any
212 * buffered packets.
213 */
214 static void netmap_writable(void *opaque)
215 {
216 NetmapState *s = opaque;
217
218 netmap_write_poll(s, false);
219 qemu_flush_queued_packets(&s->nc);
220 }
221
222 static ssize_t netmap_receive(NetClientState *nc,
223 const uint8_t *buf, size_t size)
224 {
225 NetmapState *s = DO_UPCAST(NetmapState, nc, nc);
226 struct netmap_ring *ring = s->me.tx;
227 uint32_t i;
228 uint32_t idx;
229 uint8_t *dst;
230
231 if (unlikely(!ring)) {
232 /* Drop. */
233 return size;
234 }
235
236 if (unlikely(size > ring->nr_buf_size)) {
237 RD(5, "[netmap_receive] drop packet of size %d > %d\n",
238 (int)size, ring->nr_buf_size);
239 return size;
240 }
241
242 if (ring->avail == 0) {
243 /* No available slots in the netmap TX ring. */
244 netmap_write_poll(s, true);
245 return 0;
246 }
247
248 i = ring->cur;
249 idx = ring->slot[i].buf_idx;
250 dst = (uint8_t *)NETMAP_BUF(ring, idx);
251
252 ring->slot[i].len = size;
253 ring->slot[i].flags = 0;
254 pkt_copy(buf, dst, size);
255 ring->cur = NETMAP_RING_NEXT(ring, i);
256 ring->avail--;
257 ioctl(s->me.fd, NIOCTXSYNC, NULL);
258
259 return size;
260 }
261
262 static ssize_t netmap_receive_iov(NetClientState *nc,
263 const struct iovec *iov, int iovcnt)
264 {
265 NetmapState *s = DO_UPCAST(NetmapState, nc, nc);
266 struct netmap_ring *ring = s->me.tx;
267 uint32_t last;
268 uint32_t idx;
269 uint8_t *dst;
270 int j;
271 uint32_t i;
272 uint32_t avail;
273
274 if (unlikely(!ring)) {
275 /* Drop the packet. */
276 return iov_size(iov, iovcnt);
277 }
278
279 last = i = ring->cur;
280 avail = ring->avail;
281
282 if (avail < iovcnt) {
283 /* Not enough netmap slots. */
284 netmap_write_poll(s, true);
285 return 0;
286 }
287
288 for (j = 0; j < iovcnt; j++) {
289 int iov_frag_size = iov[j].iov_len;
290 int offset = 0;
291 int nm_frag_size;
292
293 /* Split each iovec fragment over more netmap slots, if
294 necessary. */
295 while (iov_frag_size) {
296 nm_frag_size = MIN(iov_frag_size, ring->nr_buf_size);
297
298 if (unlikely(avail == 0)) {
299 /* We run out of netmap slots while splitting the
300 iovec fragments. */
301 netmap_write_poll(s, true);
302 return 0;
303 }
304
305 idx = ring->slot[i].buf_idx;
306 dst = (uint8_t *)NETMAP_BUF(ring, idx);
307
308 ring->slot[i].len = nm_frag_size;
309 ring->slot[i].flags = NS_MOREFRAG;
310 pkt_copy(iov[j].iov_base + offset, dst, nm_frag_size);
311
312 last = i;
313 i = NETMAP_RING_NEXT(ring, i);
314 avail--;
315
316 offset += nm_frag_size;
317 iov_frag_size -= nm_frag_size;
318 }
319 }
320 /* The last slot must not have NS_MOREFRAG set. */
321 ring->slot[last].flags &= ~NS_MOREFRAG;
322
323 /* Now update ring->cur and ring->avail. */
324 ring->cur = i;
325 ring->avail = avail;
326
327 ioctl(s->me.fd, NIOCTXSYNC, NULL);
328
329 return iov_size(iov, iovcnt);
330 }
331
332 /* Complete a previous send (backend --> guest) and enable the
333 fd_read callback. */
334 static void netmap_send_completed(NetClientState *nc, ssize_t len)
335 {
336 NetmapState *s = DO_UPCAST(NetmapState, nc, nc);
337
338 netmap_read_poll(s, true);
339 }
340
341 static void netmap_send(void *opaque)
342 {
343 NetmapState *s = opaque;
344 struct netmap_ring *ring = s->me.rx;
345
346 /* Keep sending while there are available packets into the netmap
347 RX ring and the forwarding path towards the peer is open. */
348 while (ring->avail > 0 && qemu_can_send_packet(&s->nc)) {
349 uint32_t i;
350 uint32_t idx;
351 bool morefrag;
352 int iovcnt = 0;
353 int iovsize;
354
355 do {
356 i = ring->cur;
357 idx = ring->slot[i].buf_idx;
358 morefrag = (ring->slot[i].flags & NS_MOREFRAG);
359 s->iov[iovcnt].iov_base = (u_char *)NETMAP_BUF(ring, idx);
360 s->iov[iovcnt].iov_len = ring->slot[i].len;
361 iovcnt++;
362
363 ring->cur = NETMAP_RING_NEXT(ring, i);
364 ring->avail--;
365 } while (ring->avail && morefrag);
366
367 if (unlikely(!ring->avail && morefrag)) {
368 RD(5, "[netmap_send] ran out of slots, with a pending"
369 "incomplete packet\n");
370 }
371
372 iovsize = qemu_sendv_packet_async(&s->nc, s->iov, iovcnt,
373 netmap_send_completed);
374
375 if (iovsize == 0) {
376 /* The peer does not receive anymore. Packet is queued, stop
377 * reading from the backend until netmap_send_completed()
378 */
379 netmap_read_poll(s, false);
380 break;
381 }
382 }
383 }
384
385 /* Flush and close. */
386 static void netmap_cleanup(NetClientState *nc)
387 {
388 NetmapState *s = DO_UPCAST(NetmapState, nc, nc);
389
390 qemu_purge_queued_packets(nc);
391
392 netmap_poll(nc, false);
393 munmap(s->me.mem, s->me.memsize);
394 close(s->me.fd);
395
396 s->me.fd = -1;
397 }
398
399 /* Offloading manipulation support callbacks. */
400 static bool netmap_has_ufo(NetClientState *nc)
401 {
402 return true;
403 }
404
405 static bool netmap_has_vnet_hdr(NetClientState *nc)
406 {
407 return true;
408 }
409
410 static bool netmap_has_vnet_hdr_len(NetClientState *nc, int len)
411 {
412 return len == 0 || len == sizeof(struct virtio_net_hdr) ||
413 len == sizeof(struct virtio_net_hdr_mrg_rxbuf);
414 }
415
416 static void netmap_using_vnet_hdr(NetClientState *nc, bool enable)
417 {
418 }
419
420 static void netmap_set_vnet_hdr_len(NetClientState *nc, int len)
421 {
422 NetmapState *s = DO_UPCAST(NetmapState, nc, nc);
423 int err;
424 struct nmreq req;
425
426 /* Issue a NETMAP_BDG_VNET_HDR command to change the virtio-net header
427 * length for the netmap adapter associated to 'me->ifname'.
428 */
429 memset(&req, 0, sizeof(req));
430 pstrcpy(req.nr_name, sizeof(req.nr_name), s->me.ifname);
431 req.nr_version = NETMAP_API;
432 req.nr_cmd = NETMAP_BDG_VNET_HDR;
433 req.nr_arg1 = len;
434 err = ioctl(s->me.fd, NIOCREGIF, &req);
435 if (err) {
436 error_report("Unable to execute NETMAP_BDG_VNET_HDR on %s: %s",
437 s->me.ifname, strerror(errno));
438 } else {
439 /* Keep track of the current length. */
440 s->vnet_hdr_len = len;
441 }
442 }
443
444 static void netmap_set_offload(NetClientState *nc, int csum, int tso4, int tso6,
445 int ecn, int ufo)
446 {
447 NetmapState *s = DO_UPCAST(NetmapState, nc, nc);
448
449 /* Setting a virtio-net header length greater than zero automatically
450 * enables the offloadings.
451 */
452 if (!s->vnet_hdr_len) {
453 netmap_set_vnet_hdr_len(nc, sizeof(struct virtio_net_hdr));
454 }
455 }
456
457 /* NetClientInfo methods */
458 static NetClientInfo net_netmap_info = {
459 .type = NET_CLIENT_OPTIONS_KIND_NETMAP,
460 .size = sizeof(NetmapState),
461 .receive = netmap_receive,
462 .receive_iov = netmap_receive_iov,
463 .poll = netmap_poll,
464 .cleanup = netmap_cleanup,
465 .has_ufo = netmap_has_ufo,
466 .has_vnet_hdr = netmap_has_vnet_hdr,
467 .has_vnet_hdr_len = netmap_has_vnet_hdr_len,
468 .using_vnet_hdr = netmap_using_vnet_hdr,
469 .set_offload = netmap_set_offload,
470 .set_vnet_hdr_len = netmap_set_vnet_hdr_len,
471 };
472
473 /* The exported init function
474 *
475 * ... -net netmap,ifname="..."
476 */
477 int net_init_netmap(const NetClientOptions *opts,
478 const char *name, NetClientState *peer)
479 {
480 const NetdevNetmapOptions *netmap_opts = opts->netmap;
481 NetClientState *nc;
482 NetmapPriv me;
483 NetmapState *s;
484
485 pstrcpy(me.fdname, sizeof(me.fdname),
486 netmap_opts->has_devname ? netmap_opts->devname : "/dev/netmap");
487 /* Set default name for the port if not supplied. */
488 pstrcpy(me.ifname, sizeof(me.ifname), netmap_opts->ifname);
489 if (netmap_open(&me)) {
490 return -1;
491 }
492 /* Create the object. */
493 nc = qemu_new_net_client(&net_netmap_info, peer, "netmap", name);
494 s = DO_UPCAST(NetmapState, nc, nc);
495 s->me = me;
496 s->vnet_hdr_len = 0;
497 netmap_read_poll(s, true); /* Initially only poll for reads. */
498
499 return 0;
500 }
501