Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 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 | |
Peter Maydell | 2744d92 | 2016-01-29 17:50:00 +0000 | [diff] [blame] | 26 | #include "qemu/osdep.h" |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 27 | #include <sys/ioctl.h> |
| 28 | #include <net/if.h> |
Vincenzo Maffione | 0a985b3 | 2014-02-20 15:40:43 +0100 | [diff] [blame] | 29 | #define NETMAP_WITH_LIBS |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 30 | #include <net/netmap.h> |
| 31 | #include <net/netmap_user.h> |
| 32 | |
| 33 | #include "net/net.h" |
Vincenzo Maffione | f6c65bf | 2014-02-06 17:02:20 +0100 | [diff] [blame] | 34 | #include "net/tap.h" |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 35 | #include "clients.h" |
| 36 | #include "sysemu/sysemu.h" |
| 37 | #include "qemu/error-report.h" |
Daniel P. Berrange | e31f045 | 2016-03-31 14:08:10 +0100 | [diff] [blame] | 38 | #include "qapi/error.h" |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 39 | #include "qemu/iov.h" |
Veronia Bahaa | f348b6d | 2016-03-20 19:16:19 +0200 | [diff] [blame] | 40 | #include "qemu/cutils.h" |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 41 | |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 42 | typedef struct NetmapState { |
| 43 | NetClientState nc; |
Vincenzo Maffione | ab68522 | 2016-01-25 19:24:35 +0100 | [diff] [blame] | 44 | struct nm_desc *nmd; |
| 45 | char ifname[IFNAMSIZ]; |
| 46 | struct netmap_ring *tx; |
| 47 | struct netmap_ring *rx; |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 48 | bool read_poll; |
| 49 | bool write_poll; |
| 50 | struct iovec iov[IOV_MAX]; |
Vincenzo Maffione | f6c65bf | 2014-02-06 17:02:20 +0100 | [diff] [blame] | 51 | int vnet_hdr_len; /* Current virtio-net header length. */ |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 52 | } NetmapState; |
| 53 | |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 54 | #ifndef __FreeBSD__ |
| 55 | #define pkt_copy bcopy |
| 56 | #else |
| 57 | /* A fast copy routine only for multiples of 64 bytes, non overlapped. */ |
| 58 | static inline void |
| 59 | pkt_copy(const void *_src, void *_dst, int l) |
| 60 | { |
| 61 | const uint64_t *src = _src; |
| 62 | uint64_t *dst = _dst; |
| 63 | if (unlikely(l >= 1024)) { |
| 64 | bcopy(src, dst, l); |
| 65 | return; |
| 66 | } |
| 67 | for (; l > 0; l -= 64) { |
| 68 | *dst++ = *src++; |
| 69 | *dst++ = *src++; |
| 70 | *dst++ = *src++; |
| 71 | *dst++ = *src++; |
| 72 | *dst++ = *src++; |
| 73 | *dst++ = *src++; |
| 74 | *dst++ = *src++; |
| 75 | *dst++ = *src++; |
| 76 | } |
| 77 | } |
| 78 | #endif /* __FreeBSD__ */ |
| 79 | |
| 80 | /* |
| 81 | * Open a netmap device. We assume there is only one queue |
| 82 | * (which is the case for the VALE bridge). |
| 83 | */ |
Vincenzo Maffione | ab68522 | 2016-01-25 19:24:35 +0100 | [diff] [blame] | 84 | static struct nm_desc *netmap_open(const NetdevNetmapOptions *nm_opts, |
| 85 | Error **errp) |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 86 | { |
Vincenzo Maffione | ab68522 | 2016-01-25 19:24:35 +0100 | [diff] [blame] | 87 | struct nm_desc *nmd; |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 88 | struct nmreq req; |
| 89 | |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 90 | memset(&req, 0, sizeof(req)); |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 91 | |
Vincenzo Maffione | ab68522 | 2016-01-25 19:24:35 +0100 | [diff] [blame] | 92 | nmd = nm_open(nm_opts->ifname, &req, NETMAP_NO_TX_POLL, |
| 93 | NULL); |
| 94 | if (nmd == NULL) { |
| 95 | error_setg_errno(errp, errno, "Failed to nm_open() %s", |
| 96 | nm_opts->ifname); |
| 97 | return NULL; |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 98 | } |
| 99 | |
Vincenzo Maffione | ab68522 | 2016-01-25 19:24:35 +0100 | [diff] [blame] | 100 | return nmd; |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 101 | } |
| 102 | |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 103 | static void netmap_send(void *opaque); |
| 104 | static void netmap_writable(void *opaque); |
| 105 | |
| 106 | /* Set the event-loop handlers for the netmap backend. */ |
| 107 | static void netmap_update_fd_handler(NetmapState *s) |
| 108 | { |
Vincenzo Maffione | ab68522 | 2016-01-25 19:24:35 +0100 | [diff] [blame] | 109 | qemu_set_fd_handler(s->nmd->fd, |
Fam Zheng | 82e1cc4 | 2015-06-04 14:45:18 +0800 | [diff] [blame] | 110 | s->read_poll ? netmap_send : NULL, |
| 111 | s->write_poll ? netmap_writable : NULL, |
| 112 | s); |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 113 | } |
| 114 | |
| 115 | /* Update the read handler. */ |
| 116 | static void netmap_read_poll(NetmapState *s, bool enable) |
| 117 | { |
| 118 | if (s->read_poll != enable) { /* Do nothing if not changed. */ |
| 119 | s->read_poll = enable; |
| 120 | netmap_update_fd_handler(s); |
| 121 | } |
| 122 | } |
| 123 | |
| 124 | /* Update the write handler. */ |
| 125 | static void netmap_write_poll(NetmapState *s, bool enable) |
| 126 | { |
| 127 | if (s->write_poll != enable) { |
| 128 | s->write_poll = enable; |
| 129 | netmap_update_fd_handler(s); |
| 130 | } |
| 131 | } |
| 132 | |
| 133 | static void netmap_poll(NetClientState *nc, bool enable) |
| 134 | { |
| 135 | NetmapState *s = DO_UPCAST(NetmapState, nc, nc); |
| 136 | |
| 137 | if (s->read_poll != enable || s->write_poll != enable) { |
Prasad Joshi | 131e744 | 2014-03-23 14:58:43 +0530 | [diff] [blame] | 138 | s->write_poll = enable; |
| 139 | s->read_poll = enable; |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 140 | netmap_update_fd_handler(s); |
| 141 | } |
| 142 | } |
| 143 | |
| 144 | /* |
| 145 | * The fd_write() callback, invoked if the fd is marked as |
| 146 | * writable after a poll. Unregister the handler and flush any |
| 147 | * buffered packets. |
| 148 | */ |
| 149 | static void netmap_writable(void *opaque) |
| 150 | { |
| 151 | NetmapState *s = opaque; |
| 152 | |
| 153 | netmap_write_poll(s, false); |
| 154 | qemu_flush_queued_packets(&s->nc); |
| 155 | } |
| 156 | |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 157 | static ssize_t netmap_receive_iov(NetClientState *nc, |
| 158 | const struct iovec *iov, int iovcnt) |
| 159 | { |
| 160 | NetmapState *s = DO_UPCAST(NetmapState, nc, nc); |
Vincenzo Maffione | ab68522 | 2016-01-25 19:24:35 +0100 | [diff] [blame] | 161 | struct netmap_ring *ring = s->tx; |
Vincenzo Maffione | 4875bf1 | 2018-12-06 17:59:07 +0100 | [diff] [blame] | 162 | unsigned int tail = ring->tail; |
| 163 | ssize_t totlen = 0; |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 164 | uint32_t last; |
| 165 | uint32_t idx; |
| 166 | uint8_t *dst; |
| 167 | int j; |
| 168 | uint32_t i; |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 169 | |
Vincenzo Maffione | 4875bf1 | 2018-12-06 17:59:07 +0100 | [diff] [blame] | 170 | last = i = ring->head; |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 171 | |
Vincenzo Maffione | 0a985b3 | 2014-02-20 15:40:43 +0100 | [diff] [blame] | 172 | if (nm_ring_space(ring) < iovcnt) { |
Vincenzo Maffione | 4875bf1 | 2018-12-06 17:59:07 +0100 | [diff] [blame] | 173 | /* Not enough netmap slots. Tell the kernel that we have seen the new |
| 174 | * available slots (so that it notifies us again when it has more |
| 175 | * ones), but without publishing any new slots to be processed |
| 176 | * (e.g., we don't advance ring->head). */ |
| 177 | ring->cur = tail; |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 178 | netmap_write_poll(s, true); |
| 179 | return 0; |
| 180 | } |
| 181 | |
| 182 | for (j = 0; j < iovcnt; j++) { |
| 183 | int iov_frag_size = iov[j].iov_len; |
| 184 | int offset = 0; |
| 185 | int nm_frag_size; |
| 186 | |
Vincenzo Maffione | 4875bf1 | 2018-12-06 17:59:07 +0100 | [diff] [blame] | 187 | totlen += iov_frag_size; |
| 188 | |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 189 | /* Split each iovec fragment over more netmap slots, if |
| 190 | necessary. */ |
| 191 | while (iov_frag_size) { |
| 192 | nm_frag_size = MIN(iov_frag_size, ring->nr_buf_size); |
| 193 | |
Vincenzo Maffione | 4875bf1 | 2018-12-06 17:59:07 +0100 | [diff] [blame] | 194 | if (unlikely(i == tail)) { |
| 195 | /* We ran out of netmap slots while splitting the |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 196 | iovec fragments. */ |
Vincenzo Maffione | 4875bf1 | 2018-12-06 17:59:07 +0100 | [diff] [blame] | 197 | ring->cur = tail; |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 198 | netmap_write_poll(s, true); |
| 199 | return 0; |
| 200 | } |
| 201 | |
| 202 | idx = ring->slot[i].buf_idx; |
| 203 | dst = (uint8_t *)NETMAP_BUF(ring, idx); |
| 204 | |
| 205 | ring->slot[i].len = nm_frag_size; |
| 206 | ring->slot[i].flags = NS_MOREFRAG; |
| 207 | pkt_copy(iov[j].iov_base + offset, dst, nm_frag_size); |
| 208 | |
| 209 | last = i; |
Vincenzo Maffione | 0a985b3 | 2014-02-20 15:40:43 +0100 | [diff] [blame] | 210 | i = nm_ring_next(ring, i); |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 211 | |
| 212 | offset += nm_frag_size; |
| 213 | iov_frag_size -= nm_frag_size; |
| 214 | } |
| 215 | } |
| 216 | /* The last slot must not have NS_MOREFRAG set. */ |
| 217 | ring->slot[last].flags &= ~NS_MOREFRAG; |
| 218 | |
Vincenzo Maffione | 4875bf1 | 2018-12-06 17:59:07 +0100 | [diff] [blame] | 219 | /* Now update ring->head and ring->cur to publish the new slots and |
| 220 | * the new wakeup point. */ |
| 221 | ring->head = ring->cur = i; |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 222 | |
Vincenzo Maffione | ab68522 | 2016-01-25 19:24:35 +0100 | [diff] [blame] | 223 | ioctl(s->nmd->fd, NIOCTXSYNC, NULL); |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 224 | |
Vincenzo Maffione | 4875bf1 | 2018-12-06 17:59:07 +0100 | [diff] [blame] | 225 | return totlen; |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 226 | } |
| 227 | |
Vincenzo Maffione | c7cbb6b | 2018-12-06 17:59:06 +0100 | [diff] [blame] | 228 | static ssize_t netmap_receive(NetClientState *nc, |
| 229 | const uint8_t *buf, size_t size) |
| 230 | { |
| 231 | struct iovec iov; |
| 232 | |
| 233 | iov.iov_base = (void *)buf; |
| 234 | iov.iov_len = size; |
| 235 | |
| 236 | return netmap_receive_iov(nc, &iov, 1); |
| 237 | } |
| 238 | |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 239 | /* Complete a previous send (backend --> guest) and enable the |
| 240 | fd_read callback. */ |
| 241 | static void netmap_send_completed(NetClientState *nc, ssize_t len) |
| 242 | { |
| 243 | NetmapState *s = DO_UPCAST(NetmapState, nc, nc); |
| 244 | |
| 245 | netmap_read_poll(s, true); |
| 246 | } |
| 247 | |
| 248 | static void netmap_send(void *opaque) |
| 249 | { |
| 250 | NetmapState *s = opaque; |
Vincenzo Maffione | ab68522 | 2016-01-25 19:24:35 +0100 | [diff] [blame] | 251 | struct netmap_ring *ring = s->rx; |
Vincenzo Maffione | cc599ed | 2018-12-06 17:59:05 +0100 | [diff] [blame] | 252 | unsigned int tail = ring->tail; |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 253 | |
Vincenzo Maffione | cc599ed | 2018-12-06 17:59:05 +0100 | [diff] [blame] | 254 | /* Keep sending while there are available slots in the netmap |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 255 | RX ring and the forwarding path towards the peer is open. */ |
Vincenzo Maffione | cc599ed | 2018-12-06 17:59:05 +0100 | [diff] [blame] | 256 | while (ring->head != tail) { |
| 257 | uint32_t i = ring->head; |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 258 | uint32_t idx; |
| 259 | bool morefrag; |
| 260 | int iovcnt = 0; |
| 261 | int iovsize; |
| 262 | |
Vincenzo Maffione | cc599ed | 2018-12-06 17:59:05 +0100 | [diff] [blame] | 263 | /* Get a (possibly multi-slot) packet. */ |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 264 | do { |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 265 | idx = ring->slot[i].buf_idx; |
| 266 | morefrag = (ring->slot[i].flags & NS_MOREFRAG); |
Vincenzo Maffione | cc599ed | 2018-12-06 17:59:05 +0100 | [diff] [blame] | 267 | s->iov[iovcnt].iov_base = (void *)NETMAP_BUF(ring, idx); |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 268 | s->iov[iovcnt].iov_len = ring->slot[i].len; |
| 269 | iovcnt++; |
Vincenzo Maffione | cc599ed | 2018-12-06 17:59:05 +0100 | [diff] [blame] | 270 | i = nm_ring_next(ring, i); |
| 271 | } while (i != tail && morefrag); |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 272 | |
Vincenzo Maffione | cc599ed | 2018-12-06 17:59:05 +0100 | [diff] [blame] | 273 | /* Advance ring->cur to tell the kernel that we have seen the slots. */ |
| 274 | ring->cur = i; |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 275 | |
Vincenzo Maffione | cc599ed | 2018-12-06 17:59:05 +0100 | [diff] [blame] | 276 | if (unlikely(morefrag)) { |
| 277 | /* This is a truncated packet, so we can stop without releasing the |
| 278 | * incomplete slots by updating ring->head. We will hopefully |
| 279 | * re-read the complete packet the next time we are called. */ |
| 280 | break; |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 281 | } |
| 282 | |
| 283 | iovsize = qemu_sendv_packet_async(&s->nc, s->iov, iovcnt, |
| 284 | netmap_send_completed); |
| 285 | |
Vincenzo Maffione | cc599ed | 2018-12-06 17:59:05 +0100 | [diff] [blame] | 286 | /* Release the slots to the kernel. */ |
| 287 | ring->head = i; |
| 288 | |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 289 | if (iovsize == 0) { |
| 290 | /* The peer does not receive anymore. Packet is queued, stop |
Vincenzo Maffione | cc599ed | 2018-12-06 17:59:05 +0100 | [diff] [blame] | 291 | * reading from the backend until netmap_send_completed(). */ |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 292 | netmap_read_poll(s, false); |
| 293 | break; |
| 294 | } |
| 295 | } |
| 296 | } |
| 297 | |
| 298 | /* Flush and close. */ |
| 299 | static void netmap_cleanup(NetClientState *nc) |
| 300 | { |
| 301 | NetmapState *s = DO_UPCAST(NetmapState, nc, nc); |
| 302 | |
| 303 | qemu_purge_queued_packets(nc); |
| 304 | |
| 305 | netmap_poll(nc, false); |
Vincenzo Maffione | ab68522 | 2016-01-25 19:24:35 +0100 | [diff] [blame] | 306 | nm_close(s->nmd); |
| 307 | s->nmd = NULL; |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 308 | } |
| 309 | |
Vincenzo Maffione | f6c65bf | 2014-02-06 17:02:20 +0100 | [diff] [blame] | 310 | /* Offloading manipulation support callbacks. */ |
Vincenzo Maffione | 9fbad2c | 2016-02-24 11:30:41 +0100 | [diff] [blame] | 311 | static int netmap_fd_set_vnet_hdr_len(NetmapState *s, int len) |
Vincenzo Maffione | f6c65bf | 2014-02-06 17:02:20 +0100 | [diff] [blame] | 312 | { |
Vincenzo Maffione | f6c65bf | 2014-02-06 17:02:20 +0100 | [diff] [blame] | 313 | struct nmreq req; |
| 314 | |
| 315 | /* Issue a NETMAP_BDG_VNET_HDR command to change the virtio-net header |
Vincenzo Maffione | ab68522 | 2016-01-25 19:24:35 +0100 | [diff] [blame] | 316 | * length for the netmap adapter associated to 's->ifname'. |
Vincenzo Maffione | f6c65bf | 2014-02-06 17:02:20 +0100 | [diff] [blame] | 317 | */ |
| 318 | memset(&req, 0, sizeof(req)); |
Vincenzo Maffione | ab68522 | 2016-01-25 19:24:35 +0100 | [diff] [blame] | 319 | pstrcpy(req.nr_name, sizeof(req.nr_name), s->ifname); |
Vincenzo Maffione | f6c65bf | 2014-02-06 17:02:20 +0100 | [diff] [blame] | 320 | req.nr_version = NETMAP_API; |
| 321 | req.nr_cmd = NETMAP_BDG_VNET_HDR; |
| 322 | req.nr_arg1 = len; |
Vincenzo Maffione | 9fbad2c | 2016-02-24 11:30:41 +0100 | [diff] [blame] | 323 | |
| 324 | return ioctl(s->nmd->fd, NIOCREGIF, &req); |
| 325 | } |
| 326 | |
| 327 | static bool netmap_has_vnet_hdr_len(NetClientState *nc, int len) |
| 328 | { |
| 329 | NetmapState *s = DO_UPCAST(NetmapState, nc, nc); |
| 330 | int prev_len = s->vnet_hdr_len; |
| 331 | |
| 332 | /* Check that we can set the new length. */ |
| 333 | if (netmap_fd_set_vnet_hdr_len(s, len)) { |
| 334 | return false; |
| 335 | } |
| 336 | |
| 337 | /* Restore the previous length. */ |
| 338 | if (netmap_fd_set_vnet_hdr_len(s, prev_len)) { |
| 339 | error_report("Failed to restore vnet-hdr length %d on %s: %s", |
| 340 | prev_len, s->ifname, strerror(errno)); |
| 341 | abort(); |
| 342 | } |
| 343 | |
| 344 | return true; |
| 345 | } |
| 346 | |
| 347 | /* A netmap interface that supports virtio-net headers always |
| 348 | * supports UFO, so we use this callback also for the has_ufo hook. */ |
| 349 | static bool netmap_has_vnet_hdr(NetClientState *nc) |
| 350 | { |
| 351 | return netmap_has_vnet_hdr_len(nc, sizeof(struct virtio_net_hdr)); |
| 352 | } |
| 353 | |
| 354 | static void netmap_using_vnet_hdr(NetClientState *nc, bool enable) |
| 355 | { |
| 356 | } |
| 357 | |
| 358 | static void netmap_set_vnet_hdr_len(NetClientState *nc, int len) |
| 359 | { |
| 360 | NetmapState *s = DO_UPCAST(NetmapState, nc, nc); |
| 361 | int err; |
| 362 | |
| 363 | err = netmap_fd_set_vnet_hdr_len(s, len); |
Vincenzo Maffione | f6c65bf | 2014-02-06 17:02:20 +0100 | [diff] [blame] | 364 | if (err) { |
Vincenzo Maffione | 9fbad2c | 2016-02-24 11:30:41 +0100 | [diff] [blame] | 365 | error_report("Unable to set vnet-hdr length %d on %s: %s", |
| 366 | len, s->ifname, strerror(errno)); |
Vincenzo Maffione | f6c65bf | 2014-02-06 17:02:20 +0100 | [diff] [blame] | 367 | } else { |
| 368 | /* Keep track of the current length. */ |
| 369 | s->vnet_hdr_len = len; |
| 370 | } |
| 371 | } |
| 372 | |
| 373 | static void netmap_set_offload(NetClientState *nc, int csum, int tso4, int tso6, |
| 374 | int ecn, int ufo) |
| 375 | { |
| 376 | NetmapState *s = DO_UPCAST(NetmapState, nc, nc); |
| 377 | |
| 378 | /* Setting a virtio-net header length greater than zero automatically |
Vincenzo Maffione | 9fbad2c | 2016-02-24 11:30:41 +0100 | [diff] [blame] | 379 | * enables the offloadings. */ |
Vincenzo Maffione | f6c65bf | 2014-02-06 17:02:20 +0100 | [diff] [blame] | 380 | if (!s->vnet_hdr_len) { |
| 381 | netmap_set_vnet_hdr_len(nc, sizeof(struct virtio_net_hdr)); |
| 382 | } |
| 383 | } |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 384 | |
| 385 | /* NetClientInfo methods */ |
| 386 | static NetClientInfo net_netmap_info = { |
Eric Blake | f394b2e | 2016-07-13 21:50:23 -0600 | [diff] [blame] | 387 | .type = NET_CLIENT_DRIVER_NETMAP, |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 388 | .size = sizeof(NetmapState), |
| 389 | .receive = netmap_receive, |
| 390 | .receive_iov = netmap_receive_iov, |
| 391 | .poll = netmap_poll, |
| 392 | .cleanup = netmap_cleanup, |
Vincenzo Maffione | 9fbad2c | 2016-02-24 11:30:41 +0100 | [diff] [blame] | 393 | .has_ufo = netmap_has_vnet_hdr, |
Vincenzo Maffione | f6c65bf | 2014-02-06 17:02:20 +0100 | [diff] [blame] | 394 | .has_vnet_hdr = netmap_has_vnet_hdr, |
| 395 | .has_vnet_hdr_len = netmap_has_vnet_hdr_len, |
| 396 | .using_vnet_hdr = netmap_using_vnet_hdr, |
| 397 | .set_offload = netmap_set_offload, |
| 398 | .set_vnet_hdr_len = netmap_set_vnet_hdr_len, |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 399 | }; |
| 400 | |
| 401 | /* The exported init function |
| 402 | * |
| 403 | * ... -net netmap,ifname="..." |
| 404 | */ |
Kővágó, Zoltán | cebea51 | 2016-07-13 21:50:12 -0600 | [diff] [blame] | 405 | int net_init_netmap(const Netdev *netdev, |
Markus Armbruster | a30ecde | 2015-05-15 13:58:50 +0200 | [diff] [blame] | 406 | const char *name, NetClientState *peer, Error **errp) |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 407 | { |
Eric Blake | f394b2e | 2016-07-13 21:50:23 -0600 | [diff] [blame] | 408 | const NetdevNetmapOptions *netmap_opts = &netdev->u.netmap; |
Vincenzo Maffione | ab68522 | 2016-01-25 19:24:35 +0100 | [diff] [blame] | 409 | struct nm_desc *nmd; |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 410 | NetClientState *nc; |
Vincenzo Maffione | 39bec4f | 2015-11-10 10:47:22 +0100 | [diff] [blame] | 411 | Error *err = NULL; |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 412 | NetmapState *s; |
| 413 | |
Vincenzo Maffione | ab68522 | 2016-01-25 19:24:35 +0100 | [diff] [blame] | 414 | nmd = netmap_open(netmap_opts, &err); |
Vincenzo Maffione | 39bec4f | 2015-11-10 10:47:22 +0100 | [diff] [blame] | 415 | if (err) { |
| 416 | error_propagate(errp, err); |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 417 | return -1; |
| 418 | } |
| 419 | /* Create the object. */ |
| 420 | nc = qemu_new_net_client(&net_netmap_info, peer, "netmap", name); |
| 421 | s = DO_UPCAST(NetmapState, nc, nc); |
Vincenzo Maffione | ab68522 | 2016-01-25 19:24:35 +0100 | [diff] [blame] | 422 | s->nmd = nmd; |
| 423 | s->tx = NETMAP_TXRING(nmd->nifp, 0); |
| 424 | s->rx = NETMAP_RXRING(nmd->nifp, 0); |
Vincenzo Maffione | f6c65bf | 2014-02-06 17:02:20 +0100 | [diff] [blame] | 425 | s->vnet_hdr_len = 0; |
Vincenzo Maffione | ab68522 | 2016-01-25 19:24:35 +0100 | [diff] [blame] | 426 | pstrcpy(s->ifname, sizeof(s->ifname), netmap_opts->ifname); |
Vincenzo Maffione | 5895213 | 2013-11-06 11:44:06 +0100 | [diff] [blame] | 427 | netmap_read_poll(s, true); /* Initially only poll for reads. */ |
| 428 | |
| 429 | return 0; |
| 430 | } |
| 431 | |