blob: 3dac29b844bb518bb0acf2514376f35f5a593a90 [file] [log] [blame]
aliguori63a01ef2008-10-31 19:10:00 +00001/*
2 * QEMU System Emulator
3 *
4 * Copyright (c) 2003-2008 Fabrice Bellard
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 */
blueswir1d40cdb12009-03-07 16:52:02 +000024#include "config-host.h"
25
Paolo Bonzini1422e322012-10-24 08:43:34 +020026#include "net/net.h"
Paolo Bonzinifd9400b2012-10-24 11:27:28 +020027#include "clients.h"
28#include "hub.h"
Paolo Bonzini1422e322012-10-24 08:43:34 +020029#include "net/slirp.h"
Dmitry Krivenokd60b20c2013-10-21 12:08:44 +040030#include "net/eth.h"
Paolo Bonzinifd9400b2012-10-24 11:27:28 +020031#include "util.h"
Paolo Bonzinia245fc12012-09-17 18:43:51 +020032
Paolo Bonzini83c90892012-12-17 18:19:49 +010033#include "monitor/monitor.h"
Mark McLoughlin1df49e02009-11-25 18:48:58 +000034#include "qemu-common.h"
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010035#include "qemu/sockets.h"
36#include "qemu/config-file.h"
Luiz Capitulino4b371562011-11-23 13:11:55 -020037#include "qmp-commands.h"
Amit Shah75422b02010-02-25 17:24:43 +053038#include "hw/qdev.h"
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010039#include "qemu/iov.h"
Alex Bligh6a1751b2013-08-21 16:02:47 +010040#include "qemu/main-loop.h"
Laszlo Ersek6687b792012-07-17 16:17:13 +020041#include "qapi-visit.h"
42#include "qapi/opts-visitor.h"
Paolo Bonzini7b1b5d12012-12-17 18:19:43 +010043#include "qapi/dealloc-visitor.h"
blueswir1511d2b12009-03-07 15:32:56 +000044
Stefan Weil2944e4e2012-02-04 09:24:46 +010045/* Net bridge is currently not supported for W32. */
46#if !defined(_WIN32)
47# define CONFIG_NET_BRIDGE
48#endif
49
Stefan Hajnoczi4e68f7a2012-07-24 16:35:13 +010050static QTAILQ_HEAD(, NetClientState) net_clients;
aliguori63a01ef2008-10-31 19:10:00 +000051
Hani Benhabiles84007e82014-05-27 23:39:33 +010052const char *host_net_devices[] = {
53 "tap",
54 "socket",
55 "dump",
56#ifdef CONFIG_NET_BRIDGE
57 "bridge",
58#endif
59#ifdef CONFIG_SLIRP
60 "user",
61#endif
62#ifdef CONFIG_VDE
63 "vde",
64#endif
Nikolay Nikolaev03ce5742014-06-10 13:02:16 +030065 "vhost-user",
Hani Benhabiles84007e82014-05-27 23:39:33 +010066 NULL,
67};
68
Gerd Hoffmanncb4522c2009-12-08 13:11:47 +010069int default_net = 1;
70
aliguori63a01ef2008-10-31 19:10:00 +000071/***********************************************************/
72/* network device redirectors */
73
Mark McLoughlin68ac40d2009-11-25 18:48:54 +000074#if defined(DEBUG_NET)
aliguori63a01ef2008-10-31 19:10:00 +000075static void hex_dump(FILE *f, const uint8_t *buf, int size)
76{
77 int len, i, j, c;
78
79 for(i=0;i<size;i+=16) {
80 len = size - i;
81 if (len > 16)
82 len = 16;
83 fprintf(f, "%08x ", i);
84 for(j=0;j<16;j++) {
85 if (j < len)
86 fprintf(f, " %02x", buf[i+j]);
87 else
88 fprintf(f, " ");
89 }
90 fprintf(f, " ");
91 for(j=0;j<len;j++) {
92 c = buf[i+j];
93 if (c < ' ' || c > '~')
94 c = '.';
95 fprintf(f, "%c", c);
96 }
97 fprintf(f, "\n");
98 }
99}
100#endif
101
aliguori63a01ef2008-10-31 19:10:00 +0000102static int get_str_sep(char *buf, int buf_size, const char **pp, int sep)
103{
104 const char *p, *p1;
105 int len;
106 p = *pp;
107 p1 = strchr(p, sep);
108 if (!p1)
109 return -1;
110 len = p1 - p;
111 p1++;
112 if (buf_size > 0) {
113 if (len > buf_size - 1)
114 len = buf_size - 1;
115 memcpy(buf, p, len);
116 buf[len] = '\0';
117 }
118 *pp = p1;
119 return 0;
120}
121
aliguori63a01ef2008-10-31 19:10:00 +0000122int parse_host_port(struct sockaddr_in *saddr, const char *str)
123{
124 char buf[512];
125 struct hostent *he;
126 const char *p, *r;
127 int port;
128
129 p = str;
130 if (get_str_sep(buf, sizeof(buf), &p, ':') < 0)
131 return -1;
132 saddr->sin_family = AF_INET;
133 if (buf[0] == '\0') {
134 saddr->sin_addr.s_addr = 0;
135 } else {
blueswir1cd390082008-11-16 13:53:32 +0000136 if (qemu_isdigit(buf[0])) {
aliguori63a01ef2008-10-31 19:10:00 +0000137 if (!inet_aton(buf, &saddr->sin_addr))
138 return -1;
139 } else {
140 if ((he = gethostbyname(buf)) == NULL)
141 return - 1;
142 saddr->sin_addr = *(struct in_addr *)he->h_addr;
143 }
144 }
145 port = strtol(p, (char **)&r, 0);
146 if (r == p)
147 return -1;
148 saddr->sin_port = htons(port);
149 return 0;
150}
151
Stefan Hajnoczi35277d12012-07-24 16:35:14 +0100152void qemu_format_nic_info_str(NetClientState *nc, uint8_t macaddr[6])
aliguori7cb7434b2009-01-07 17:46:21 +0000153{
Stefan Hajnoczi35277d12012-07-24 16:35:14 +0100154 snprintf(nc->info_str, sizeof(nc->info_str),
aliguori4dda4062009-01-08 19:01:37 +0000155 "model=%s,macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
Stefan Hajnoczi35277d12012-07-24 16:35:14 +0100156 nc->model,
aliguori7cb7434b2009-01-07 17:46:21 +0000157 macaddr[0], macaddr[1], macaddr[2],
158 macaddr[3], macaddr[4], macaddr[5]);
159}
160
Gerd Hoffmann76d32cb2009-10-21 15:25:22 +0200161void qemu_macaddr_default_if_unset(MACAddr *macaddr)
162{
163 static int index = 0;
164 static const MACAddr zero = { .a = { 0,0,0,0,0,0 } };
165
166 if (memcmp(macaddr, &zero, sizeof(zero)) != 0)
167 return;
168 macaddr->a[0] = 0x52;
169 macaddr->a[1] = 0x54;
170 macaddr->a[2] = 0x00;
171 macaddr->a[3] = 0x12;
172 macaddr->a[4] = 0x34;
173 macaddr->a[5] = 0x56 + index++;
174}
175
Stefan Hajnoczid33d93b2012-07-24 16:35:05 +0100176/**
177 * Generate a name for net client
178 *
Amos Kongc9635302013-04-15 18:55:19 +0800179 * Only net clients created with the legacy -net option and NICs need this.
Stefan Hajnoczid33d93b2012-07-24 16:35:05 +0100180 */
Stefan Hajnoczi35277d12012-07-24 16:35:14 +0100181static char *assign_name(NetClientState *nc1, const char *model)
aliguori676cff22009-01-07 17:43:44 +0000182{
Stefan Hajnoczi35277d12012-07-24 16:35:14 +0100183 NetClientState *nc;
aliguori676cff22009-01-07 17:43:44 +0000184 int id = 0;
185
Stefan Hajnoczi35277d12012-07-24 16:35:14 +0100186 QTAILQ_FOREACH(nc, &net_clients, next) {
187 if (nc == nc1) {
Stefan Hajnoczid33d93b2012-07-24 16:35:05 +0100188 continue;
Mark McLoughlin5610c3a2009-10-08 19:58:23 +0100189 }
Amos Kongc9635302013-04-15 18:55:19 +0800190 if (strcmp(nc->model, model) == 0) {
Markus Armbruster53e51d82011-06-16 18:45:36 +0200191 id++;
192 }
193 }
194
Hani Benhabiles4bf2c132014-01-09 19:34:27 +0100195 return g_strdup_printf("%s.%d", model, id);
aliguori676cff22009-01-07 17:43:44 +0000196}
197
Jason Wangf7860452013-01-30 19:12:27 +0800198static void qemu_net_client_destructor(NetClientState *nc)
199{
200 g_free(nc);
201}
202
Jason Wang18a15412013-01-30 19:12:26 +0800203static void qemu_net_client_setup(NetClientState *nc,
204 NetClientInfo *info,
205 NetClientState *peer,
206 const char *model,
Jason Wangf7860452013-01-30 19:12:27 +0800207 const char *name,
208 NetClientDestructor *destructor)
aliguori63a01ef2008-10-31 19:10:00 +0000209{
Stefan Hajnoczi35277d12012-07-24 16:35:14 +0100210 nc->info = info;
211 nc->model = g_strdup(model);
Mark McLoughlin45460d12009-11-25 18:49:02 +0000212 if (name) {
Stefan Hajnoczi35277d12012-07-24 16:35:14 +0100213 nc->name = g_strdup(name);
Mark McLoughlin45460d12009-11-25 18:49:02 +0000214 } else {
Stefan Hajnoczi35277d12012-07-24 16:35:14 +0100215 nc->name = assign_name(nc, model);
Mark McLoughlin45460d12009-11-25 18:49:02 +0000216 }
aliguori63a01ef2008-10-31 19:10:00 +0000217
Stefan Hajnocziab5f3f82012-07-24 16:35:08 +0100218 if (peer) {
219 assert(!peer->peer);
Stefan Hajnoczi35277d12012-07-24 16:35:14 +0100220 nc->peer = peer;
221 peer->peer = nc;
Mark McLoughlind80b9fc2009-10-08 19:58:24 +0100222 }
Stefan Hajnoczi35277d12012-07-24 16:35:14 +0100223 QTAILQ_INSERT_TAIL(&net_clients, nc, next);
Mark McLoughlin5610c3a2009-10-08 19:58:23 +0100224
Jan Kiszka067404b2013-08-02 21:47:08 +0200225 nc->incoming_queue = qemu_new_net_queue(nc);
Jason Wangf7860452013-01-30 19:12:27 +0800226 nc->destructor = destructor;
Jason Wang18a15412013-01-30 19:12:26 +0800227}
228
229NetClientState *qemu_new_net_client(NetClientInfo *info,
230 NetClientState *peer,
231 const char *model,
232 const char *name)
233{
234 NetClientState *nc;
235
236 assert(info->size >= sizeof(NetClientState));
237
238 nc = g_malloc0(info->size);
Jason Wangf7860452013-01-30 19:12:27 +0800239 qemu_net_client_setup(nc, info, peer, model, name,
240 qemu_net_client_destructor);
Jason Wang18a15412013-01-30 19:12:26 +0800241
Stefan Hajnoczi35277d12012-07-24 16:35:14 +0100242 return nc;
aliguori63a01ef2008-10-31 19:10:00 +0000243}
244
Mark McLoughlinebef2c02009-11-25 18:49:10 +0000245NICState *qemu_new_nic(NetClientInfo *info,
246 NICConf *conf,
247 const char *model,
248 const char *name,
249 void *opaque)
250{
Jason Wang1ceef9f2013-01-30 19:12:28 +0800251 NetClientState **peers = conf->peers.ncs;
Mark McLoughlinebef2c02009-11-25 18:49:10 +0000252 NICState *nic;
Jason Wangf6b26cf2013-02-22 23:15:06 +0800253 int i, queues = MAX(1, conf->queues);
Mark McLoughlinebef2c02009-11-25 18:49:10 +0000254
Laszlo Ersek2be64a62012-07-17 16:17:12 +0200255 assert(info->type == NET_CLIENT_OPTIONS_KIND_NIC);
Mark McLoughlinebef2c02009-11-25 18:49:10 +0000256 assert(info->size >= sizeof(NICState));
257
Jason Wangf6b26cf2013-02-22 23:15:06 +0800258 nic = g_malloc0(info->size + sizeof(NetClientState) * queues);
259 nic->ncs = (void *)nic + info->size;
Mark McLoughlinebef2c02009-11-25 18:49:10 +0000260 nic->conf = conf;
261 nic->opaque = opaque;
262
Jason Wangf6b26cf2013-02-22 23:15:06 +0800263 for (i = 0; i < queues; i++) {
264 qemu_net_client_setup(&nic->ncs[i], info, peers[i], model, name,
Jason Wang1ceef9f2013-01-30 19:12:28 +0800265 NULL);
266 nic->ncs[i].queue_index = i;
267 }
268
Mark McLoughlinebef2c02009-11-25 18:49:10 +0000269 return nic;
270}
271
Jason Wang1ceef9f2013-01-30 19:12:28 +0800272NetClientState *qemu_get_subqueue(NICState *nic, int queue_index)
273{
Jason Wangf6b26cf2013-02-22 23:15:06 +0800274 return nic->ncs + queue_index;
Jason Wang1ceef9f2013-01-30 19:12:28 +0800275}
276
Jason Wangb356f762013-01-30 19:12:22 +0800277NetClientState *qemu_get_queue(NICState *nic)
278{
Jason Wang1ceef9f2013-01-30 19:12:28 +0800279 return qemu_get_subqueue(nic, 0);
Jason Wangb356f762013-01-30 19:12:22 +0800280}
281
Jason Wangcc1f0f42013-01-30 19:12:23 +0800282NICState *qemu_get_nic(NetClientState *nc)
283{
Jason Wang1ceef9f2013-01-30 19:12:28 +0800284 NetClientState *nc0 = nc - nc->queue_index;
285
Jason Wangf6b26cf2013-02-22 23:15:06 +0800286 return (NICState *)((void *)nc0 - nc->info->size);
Jason Wangcc1f0f42013-01-30 19:12:23 +0800287}
288
289void *qemu_get_nic_opaque(NetClientState *nc)
290{
291 NICState *nic = qemu_get_nic(nc);
292
293 return nic->opaque;
294}
295
Stefan Hajnoczib20c6b92012-07-24 16:35:15 +0100296static void qemu_cleanup_net_client(NetClientState *nc)
aliguori63a01ef2008-10-31 19:10:00 +0000297{
Stefan Hajnoczi35277d12012-07-24 16:35:14 +0100298 QTAILQ_REMOVE(&net_clients, nc, next);
aliguori63a01ef2008-10-31 19:10:00 +0000299
Andreas Färbercc2a9042013-02-12 23:16:06 +0100300 if (nc->info->cleanup) {
301 nc->info->cleanup(nc);
302 }
Michael S. Tsirkina083a892010-09-20 18:08:41 +0200303}
Mark McLoughlin5610c3a2009-10-08 19:58:23 +0100304
Stefan Hajnoczib20c6b92012-07-24 16:35:15 +0100305static void qemu_free_net_client(NetClientState *nc)
Michael S. Tsirkina083a892010-09-20 18:08:41 +0200306{
Jan Kiszka067404b2013-08-02 21:47:08 +0200307 if (nc->incoming_queue) {
308 qemu_del_net_queue(nc->incoming_queue);
Michael S. Tsirkina083a892010-09-20 18:08:41 +0200309 }
Stefan Hajnoczi35277d12012-07-24 16:35:14 +0100310 if (nc->peer) {
311 nc->peer->peer = NULL;
Mark McLoughlin5610c3a2009-10-08 19:58:23 +0100312 }
Stefan Hajnoczi35277d12012-07-24 16:35:14 +0100313 g_free(nc->name);
314 g_free(nc->model);
Jason Wangf7860452013-01-30 19:12:27 +0800315 if (nc->destructor) {
316 nc->destructor(nc);
317 }
aliguori63a01ef2008-10-31 19:10:00 +0000318}
319
Stefan Hajnoczib20c6b92012-07-24 16:35:15 +0100320void qemu_del_net_client(NetClientState *nc)
Michael S. Tsirkina083a892010-09-20 18:08:41 +0200321{
Jason Wang1ceef9f2013-01-30 19:12:28 +0800322 NetClientState *ncs[MAX_QUEUE_NUM];
323 int queues, i;
324
325 /* If the NetClientState belongs to a multiqueue backend, we will change all
326 * other NetClientStates also.
327 */
328 queues = qemu_find_net_clients_except(nc->name, ncs,
329 NET_CLIENT_OPTIONS_KIND_NIC,
330 MAX_QUEUE_NUM);
331 assert(queues != 0);
332
Michael S. Tsirkina083a892010-09-20 18:08:41 +0200333 /* If there is a peer NIC, delete and cleanup client, but do not free. */
Stefan Hajnoczi35277d12012-07-24 16:35:14 +0100334 if (nc->peer && nc->peer->info->type == NET_CLIENT_OPTIONS_KIND_NIC) {
Jason Wangcc1f0f42013-01-30 19:12:23 +0800335 NICState *nic = qemu_get_nic(nc->peer);
Michael S. Tsirkina083a892010-09-20 18:08:41 +0200336 if (nic->peer_deleted) {
337 return;
338 }
339 nic->peer_deleted = true;
Jason Wang1ceef9f2013-01-30 19:12:28 +0800340
341 for (i = 0; i < queues; i++) {
342 ncs[i]->peer->link_down = true;
343 }
344
Stefan Hajnoczi35277d12012-07-24 16:35:14 +0100345 if (nc->peer->info->link_status_changed) {
346 nc->peer->info->link_status_changed(nc->peer);
Michael S. Tsirkina083a892010-09-20 18:08:41 +0200347 }
Jason Wang1ceef9f2013-01-30 19:12:28 +0800348
349 for (i = 0; i < queues; i++) {
350 qemu_cleanup_net_client(ncs[i]);
351 }
352
Michael S. Tsirkina083a892010-09-20 18:08:41 +0200353 return;
354 }
355
Jason Wang948ecf22013-01-30 19:12:24 +0800356 assert(nc->info->type != NET_CLIENT_OPTIONS_KIND_NIC);
357
Jason Wang1ceef9f2013-01-30 19:12:28 +0800358 for (i = 0; i < queues; i++) {
359 qemu_cleanup_net_client(ncs[i]);
360 qemu_free_net_client(ncs[i]);
361 }
Jason Wang948ecf22013-01-30 19:12:24 +0800362}
363
364void qemu_del_nic(NICState *nic)
365{
Michael Rothb8904922013-02-06 18:25:48 -0600366 int i, queues = MAX(nic->conf->queues, 1);
Jason Wang1ceef9f2013-01-30 19:12:28 +0800367
Michael S. Tsirkina083a892010-09-20 18:08:41 +0200368 /* If this is a peer NIC and peer has already been deleted, free it now. */
Jason Wang1ceef9f2013-01-30 19:12:28 +0800369 if (nic->peer_deleted) {
370 for (i = 0; i < queues; i++) {
371 qemu_free_net_client(qemu_get_subqueue(nic, i)->peer);
Michael S. Tsirkina083a892010-09-20 18:08:41 +0200372 }
373 }
374
Jason Wang1ceef9f2013-01-30 19:12:28 +0800375 for (i = queues - 1; i >= 0; i--) {
376 NetClientState *nc = qemu_get_subqueue(nic, i);
377
378 qemu_cleanup_net_client(nc);
379 qemu_free_net_client(nc);
380 }
Jason Wangf6b26cf2013-02-22 23:15:06 +0800381
382 g_free(nic);
Jan Kiszka1a609522009-06-24 14:42:31 +0200383}
384
Mark McLoughlin57f9ef12009-11-25 18:49:31 +0000385void qemu_foreach_nic(qemu_nic_foreach func, void *opaque)
386{
Stefan Hajnoczi4e68f7a2012-07-24 16:35:13 +0100387 NetClientState *nc;
Mark McLoughlin57f9ef12009-11-25 18:49:31 +0000388
Stefan Hajnoczi94878992012-07-24 16:35:12 +0100389 QTAILQ_FOREACH(nc, &net_clients, next) {
Laszlo Ersek2be64a62012-07-17 16:17:12 +0200390 if (nc->info->type == NET_CLIENT_OPTIONS_KIND_NIC) {
Jason Wang1ceef9f2013-01-30 19:12:28 +0800391 if (nc->queue_index == 0) {
392 func(qemu_get_nic(nc), opaque);
393 }
Mark McLoughlin57f9ef12009-11-25 18:49:31 +0000394 }
395 }
Mark McLoughlin57f9ef12009-11-25 18:49:31 +0000396}
397
Stefan Hajnoczid6085e32014-02-20 12:14:07 +0100398bool qemu_has_ufo(NetClientState *nc)
Vincenzo Maffione1f55ac42014-02-06 17:02:16 +0100399{
Stefan Hajnoczid6085e32014-02-20 12:14:07 +0100400 if (!nc || !nc->info->has_ufo) {
Vincenzo Maffione1f55ac42014-02-06 17:02:16 +0100401 return false;
402 }
403
Stefan Hajnoczid6085e32014-02-20 12:14:07 +0100404 return nc->info->has_ufo(nc);
Vincenzo Maffione1f55ac42014-02-06 17:02:16 +0100405}
406
Stefan Hajnoczid6085e32014-02-20 12:14:07 +0100407bool qemu_has_vnet_hdr(NetClientState *nc)
Vincenzo Maffione1f55ac42014-02-06 17:02:16 +0100408{
Stefan Hajnoczid6085e32014-02-20 12:14:07 +0100409 if (!nc || !nc->info->has_vnet_hdr) {
Vincenzo Maffione1f55ac42014-02-06 17:02:16 +0100410 return false;
411 }
412
Stefan Hajnoczid6085e32014-02-20 12:14:07 +0100413 return nc->info->has_vnet_hdr(nc);
Vincenzo Maffione1f55ac42014-02-06 17:02:16 +0100414}
415
Stefan Hajnoczid6085e32014-02-20 12:14:07 +0100416bool qemu_has_vnet_hdr_len(NetClientState *nc, int len)
Vincenzo Maffione1f55ac42014-02-06 17:02:16 +0100417{
Stefan Hajnoczid6085e32014-02-20 12:14:07 +0100418 if (!nc || !nc->info->has_vnet_hdr_len) {
Vincenzo Maffione1f55ac42014-02-06 17:02:16 +0100419 return false;
420 }
421
Stefan Hajnoczid6085e32014-02-20 12:14:07 +0100422 return nc->info->has_vnet_hdr_len(nc, len);
Vincenzo Maffione1f55ac42014-02-06 17:02:16 +0100423}
424
Stefan Hajnoczid6085e32014-02-20 12:14:07 +0100425void qemu_using_vnet_hdr(NetClientState *nc, bool enable)
Vincenzo Maffione1f55ac42014-02-06 17:02:16 +0100426{
Stefan Hajnoczid6085e32014-02-20 12:14:07 +0100427 if (!nc || !nc->info->using_vnet_hdr) {
Vincenzo Maffione1f55ac42014-02-06 17:02:16 +0100428 return;
429 }
430
Stefan Hajnoczid6085e32014-02-20 12:14:07 +0100431 nc->info->using_vnet_hdr(nc, enable);
Vincenzo Maffione1f55ac42014-02-06 17:02:16 +0100432}
433
Stefan Hajnoczid6085e32014-02-20 12:14:07 +0100434void qemu_set_offload(NetClientState *nc, int csum, int tso4, int tso6,
Vincenzo Maffione1f55ac42014-02-06 17:02:16 +0100435 int ecn, int ufo)
436{
Stefan Hajnoczid6085e32014-02-20 12:14:07 +0100437 if (!nc || !nc->info->set_offload) {
Vincenzo Maffione1f55ac42014-02-06 17:02:16 +0100438 return;
439 }
440
Stefan Hajnoczid6085e32014-02-20 12:14:07 +0100441 nc->info->set_offload(nc, csum, tso4, tso6, ecn, ufo);
Vincenzo Maffione1f55ac42014-02-06 17:02:16 +0100442}
443
Stefan Hajnoczid6085e32014-02-20 12:14:07 +0100444void qemu_set_vnet_hdr_len(NetClientState *nc, int len)
Vincenzo Maffione1f55ac42014-02-06 17:02:16 +0100445{
Stefan Hajnoczid6085e32014-02-20 12:14:07 +0100446 if (!nc || !nc->info->set_vnet_hdr_len) {
Vincenzo Maffione1f55ac42014-02-06 17:02:16 +0100447 return;
448 }
449
Stefan Hajnoczid6085e32014-02-20 12:14:07 +0100450 nc->info->set_vnet_hdr_len(nc, len);
Vincenzo Maffione1f55ac42014-02-06 17:02:16 +0100451}
452
Stefan Hajnoczi4e68f7a2012-07-24 16:35:13 +0100453int qemu_can_send_packet(NetClientState *sender)
aliguori63a01ef2008-10-31 19:10:00 +0000454{
Stefan Hajnoczia005d072012-07-24 16:35:11 +0100455 if (!sender->peer) {
Mark McLoughlind80b9fc2009-10-08 19:58:24 +0100456 return 1;
457 }
458
Stefan Hajnoczia005d072012-07-24 16:35:11 +0100459 if (sender->peer->receive_disabled) {
460 return 0;
461 } else if (sender->peer->info->can_receive &&
462 !sender->peer->info->can_receive(sender->peer)) {
463 return 0;
aliguori63a01ef2008-10-31 19:10:00 +0000464 }
Vincent Palatin60c07d92011-03-02 17:25:02 -0500465 return 1;
aliguori63a01ef2008-10-31 19:10:00 +0000466}
467
Zhi Yong Wu86a77c32012-07-24 16:35:17 +0100468ssize_t qemu_deliver_packet(NetClientState *sender,
469 unsigned flags,
470 const uint8_t *data,
471 size_t size,
472 void *opaque)
Mark McLoughlin9a6ecb32009-10-08 19:58:32 +0100473{
Stefan Hajnoczi35277d12012-07-24 16:35:14 +0100474 NetClientState *nc = opaque;
Mark McLoughlin893379e2009-10-27 18:16:36 +0000475 ssize_t ret;
Mark McLoughlin9a6ecb32009-10-08 19:58:32 +0100476
Stefan Hajnoczi35277d12012-07-24 16:35:14 +0100477 if (nc->link_down) {
Mark McLoughlin9a6ecb32009-10-08 19:58:32 +0100478 return size;
479 }
480
Stefan Hajnoczi35277d12012-07-24 16:35:14 +0100481 if (nc->receive_disabled) {
Mark McLoughlin893379e2009-10-27 18:16:36 +0000482 return 0;
483 }
484
Stefan Hajnoczi35277d12012-07-24 16:35:14 +0100485 if (flags & QEMU_NET_PACKET_FLAG_RAW && nc->info->receive_raw) {
486 ret = nc->info->receive_raw(nc, data, size);
Mark McLoughlin893379e2009-10-27 18:16:36 +0000487 } else {
Stefan Hajnoczi35277d12012-07-24 16:35:14 +0100488 ret = nc->info->receive(nc, data, size);
Mark McLoughlin893379e2009-10-27 18:16:36 +0000489 }
490
491 if (ret == 0) {
Stefan Hajnoczi35277d12012-07-24 16:35:14 +0100492 nc->receive_disabled = 1;
Igor Ryzhovb9259652014-04-16 17:43:07 +0400493 }
Mark McLoughlin893379e2009-10-27 18:16:36 +0000494
495 return ret;
Mark McLoughlin9a6ecb32009-10-08 19:58:32 +0100496}
497
Stefan Hajnoczi35277d12012-07-24 16:35:14 +0100498void qemu_purge_queued_packets(NetClientState *nc)
aliguori63a01ef2008-10-31 19:10:00 +0000499{
Stefan Hajnoczi35277d12012-07-24 16:35:14 +0100500 if (!nc->peer) {
Mark McLoughlin9a6ecb32009-10-08 19:58:32 +0100501 return;
502 }
503
Jan Kiszka067404b2013-08-02 21:47:08 +0200504 qemu_net_queue_purge(nc->peer->incoming_queue, nc);
Mark McLoughlin8cad5512009-06-18 18:21:29 +0100505}
506
Stefan Hajnoczi35277d12012-07-24 16:35:14 +0100507void qemu_flush_queued_packets(NetClientState *nc)
Mark McLoughline94667b2009-04-29 11:48:12 +0100508{
Stefan Hajnoczi35277d12012-07-24 16:35:14 +0100509 nc->receive_disabled = 0;
Mark McLoughlind80b9fc2009-10-08 19:58:24 +0100510
Luigi Rizzo199ee602013-02-05 17:53:31 +0100511 if (nc->peer && nc->peer->info->type == NET_CLIENT_OPTIONS_KIND_HUBPORT) {
512 if (net_hub_flush(nc->peer)) {
513 qemu_notify_event();
514 }
Luigi Rizzo199ee602013-02-05 17:53:31 +0100515 }
Jan Kiszka067404b2013-08-02 21:47:08 +0200516 if (qemu_net_queue_flush(nc->incoming_queue)) {
Paolo Bonzini987a9b42012-08-09 16:45:55 +0200517 /* We emptied the queue successfully, signal to the IO thread to repoll
518 * the file descriptor (for tap, for example).
519 */
520 qemu_notify_event();
521 }
Mark McLoughline94667b2009-04-29 11:48:12 +0100522}
523
Stefan Hajnoczi4e68f7a2012-07-24 16:35:13 +0100524static ssize_t qemu_send_packet_async_with_flags(NetClientState *sender,
Mark McLoughlinca77d172009-10-22 17:43:41 +0100525 unsigned flags,
526 const uint8_t *buf, int size,
527 NetPacketSent *sent_cb)
aliguori764a4d12009-04-21 19:56:41 +0000528{
Mark McLoughlin9a6ecb32009-10-08 19:58:32 +0100529 NetQueue *queue;
Mark McLoughline94667b2009-04-29 11:48:12 +0100530
Mark McLoughlinf3b6c7f2009-04-29 12:15:26 +0100531#ifdef DEBUG_NET
Mark McLoughlind80b9fc2009-10-08 19:58:24 +0100532 printf("qemu_send_packet_async:\n");
Mark McLoughlinf3b6c7f2009-04-29 12:15:26 +0100533 hex_dump(stdout, buf, size);
534#endif
535
Stefan Hajnoczia005d072012-07-24 16:35:11 +0100536 if (sender->link_down || !sender->peer) {
Mark McLoughlin9a6ecb32009-10-08 19:58:32 +0100537 return size;
538 }
539
Jan Kiszka067404b2013-08-02 21:47:08 +0200540 queue = sender->peer->incoming_queue;
Mark McLoughlin9a6ecb32009-10-08 19:58:32 +0100541
Mark McLoughlinca77d172009-10-22 17:43:41 +0100542 return qemu_net_queue_send(queue, sender, flags, buf, size, sent_cb);
543}
544
Stefan Hajnoczi4e68f7a2012-07-24 16:35:13 +0100545ssize_t qemu_send_packet_async(NetClientState *sender,
Mark McLoughlinca77d172009-10-22 17:43:41 +0100546 const uint8_t *buf, int size,
547 NetPacketSent *sent_cb)
548{
549 return qemu_send_packet_async_with_flags(sender, QEMU_NET_PACKET_FLAG_NONE,
550 buf, size, sent_cb);
Mark McLoughlinf3b6c7f2009-04-29 12:15:26 +0100551}
552
Stefan Hajnoczi35277d12012-07-24 16:35:14 +0100553void qemu_send_packet(NetClientState *nc, const uint8_t *buf, int size)
Mark McLoughlinf3b6c7f2009-04-29 12:15:26 +0100554{
Stefan Hajnoczi35277d12012-07-24 16:35:14 +0100555 qemu_send_packet_async(nc, buf, size, NULL);
aliguori63a01ef2008-10-31 19:10:00 +0000556}
557
Stefan Hajnoczi35277d12012-07-24 16:35:14 +0100558ssize_t qemu_send_packet_raw(NetClientState *nc, const uint8_t *buf, int size)
Mark McLoughlinca77d172009-10-22 17:43:41 +0100559{
Stefan Hajnoczi35277d12012-07-24 16:35:14 +0100560 return qemu_send_packet_async_with_flags(nc, QEMU_NET_PACKET_FLAG_RAW,
Mark McLoughlinca77d172009-10-22 17:43:41 +0100561 buf, size, NULL);
562}
563
Stefan Hajnoczi35277d12012-07-24 16:35:14 +0100564static ssize_t nc_sendv_compat(NetClientState *nc, const struct iovec *iov,
aliguorifbe78f42008-12-17 19:13:11 +0000565 int iovcnt)
566{
Scott Feldmand32fcad2013-03-18 11:43:44 -0700567 uint8_t buffer[NET_BUFSIZE];
Benjamin Poirierce053662011-02-23 19:57:21 -0500568 size_t offset;
aliguorifbe78f42008-12-17 19:13:11 +0000569
Michael Tokarevdcf6f5e2012-03-11 18:05:12 +0400570 offset = iov_to_buf(iov, iovcnt, 0, buffer, sizeof(buffer));
aliguorifbe78f42008-12-17 19:13:11 +0000571
Stefan Hajnoczi35277d12012-07-24 16:35:14 +0100572 return nc->info->receive(nc, buffer, offset);
aliguorifbe78f42008-12-17 19:13:11 +0000573}
574
Zhi Yong Wu86a77c32012-07-24 16:35:17 +0100575ssize_t qemu_deliver_packet_iov(NetClientState *sender,
576 unsigned flags,
577 const struct iovec *iov,
578 int iovcnt,
579 void *opaque)
Mark McLoughlin9a6ecb32009-10-08 19:58:32 +0100580{
Stefan Hajnoczi35277d12012-07-24 16:35:14 +0100581 NetClientState *nc = opaque;
Stefan Hajnoczic67f5dc2012-08-17 21:16:42 +0100582 int ret;
Mark McLoughlin9a6ecb32009-10-08 19:58:32 +0100583
Stefan Hajnoczi35277d12012-07-24 16:35:14 +0100584 if (nc->link_down) {
Benjamin Poirierce053662011-02-23 19:57:21 -0500585 return iov_size(iov, iovcnt);
Mark McLoughlin9a6ecb32009-10-08 19:58:32 +0100586 }
587
Stefan Hajnoczic67f5dc2012-08-17 21:16:42 +0100588 if (nc->receive_disabled) {
589 return 0;
Mark McLoughlin9a6ecb32009-10-08 19:58:32 +0100590 }
Stefan Hajnoczic67f5dc2012-08-17 21:16:42 +0100591
592 if (nc->info->receive_iov) {
593 ret = nc->info->receive_iov(nc, iov, iovcnt);
594 } else {
595 ret = nc_sendv_compat(nc, iov, iovcnt);
596 }
597
598 if (ret == 0) {
599 nc->receive_disabled = 1;
600 }
601
602 return ret;
Mark McLoughlin9a6ecb32009-10-08 19:58:32 +0100603}
604
Stefan Hajnoczi4e68f7a2012-07-24 16:35:13 +0100605ssize_t qemu_sendv_packet_async(NetClientState *sender,
Mark McLoughlinf3b6c7f2009-04-29 12:15:26 +0100606 const struct iovec *iov, int iovcnt,
607 NetPacketSent *sent_cb)
aliguorifbe78f42008-12-17 19:13:11 +0000608{
Mark McLoughlin9a6ecb32009-10-08 19:58:32 +0100609 NetQueue *queue;
610
Stefan Hajnoczia005d072012-07-24 16:35:11 +0100611 if (sender->link_down || !sender->peer) {
Benjamin Poirierce053662011-02-23 19:57:21 -0500612 return iov_size(iov, iovcnt);
aliguorifbe78f42008-12-17 19:13:11 +0000613 }
614
Jan Kiszka067404b2013-08-02 21:47:08 +0200615 queue = sender->peer->incoming_queue;
Mark McLoughlin9a6ecb32009-10-08 19:58:32 +0100616
Mark McLoughlinc0b8e492009-10-22 17:43:40 +0100617 return qemu_net_queue_send_iov(queue, sender,
618 QEMU_NET_PACKET_FLAG_NONE,
619 iov, iovcnt, sent_cb);
aliguorifbe78f42008-12-17 19:13:11 +0000620}
621
Mark McLoughlinf3b6c7f2009-04-29 12:15:26 +0100622ssize_t
Stefan Hajnoczi35277d12012-07-24 16:35:14 +0100623qemu_sendv_packet(NetClientState *nc, const struct iovec *iov, int iovcnt)
Mark McLoughlinf3b6c7f2009-04-29 12:15:26 +0100624{
Stefan Hajnoczi35277d12012-07-24 16:35:14 +0100625 return qemu_sendv_packet_async(nc, iov, iovcnt, NULL);
Mark McLoughlinf3b6c7f2009-04-29 12:15:26 +0100626}
627
Stefan Hajnoczi4e68f7a2012-07-24 16:35:13 +0100628NetClientState *qemu_find_netdev(const char *id)
aliguori63a01ef2008-10-31 19:10:00 +0000629{
Stefan Hajnoczi35277d12012-07-24 16:35:14 +0100630 NetClientState *nc;
Mark McLoughlin5610c3a2009-10-08 19:58:23 +0100631
Stefan Hajnoczi35277d12012-07-24 16:35:14 +0100632 QTAILQ_FOREACH(nc, &net_clients, next) {
633 if (nc->info->type == NET_CLIENT_OPTIONS_KIND_NIC)
Markus Armbruster85dde9a2011-06-16 18:45:37 +0200634 continue;
Stefan Hajnoczi35277d12012-07-24 16:35:14 +0100635 if (!strcmp(nc->name, id)) {
636 return nc;
Mark McLoughlin5869c4d2009-10-08 19:58:29 +0100637 }
638 }
639
640 return NULL;
641}
642
Jason Wang6c51ae72013-01-30 19:12:25 +0800643int qemu_find_net_clients_except(const char *id, NetClientState **ncs,
644 NetClientOptionsKind type, int max)
645{
646 NetClientState *nc;
647 int ret = 0;
648
649 QTAILQ_FOREACH(nc, &net_clients, next) {
650 if (nc->info->type == type) {
651 continue;
652 }
Hani Benhabiles40d19392014-05-07 23:41:30 +0100653 if (!id || !strcmp(nc->name, id)) {
Jason Wang6c51ae72013-01-30 19:12:25 +0800654 if (ret < max) {
655 ncs[ret] = nc;
656 }
657 ret++;
658 }
659 }
660
661 return ret;
662}
663
aliguori76970792009-02-11 15:20:03 +0000664static int nic_get_free_idx(void)
665{
666 int index;
667
668 for (index = 0; index < MAX_NICS; index++)
669 if (!nd_table[index].used)
670 return index;
671 return -1;
672}
673
Markus Armbruster07caea32009-09-25 03:53:51 +0200674int qemu_show_nic_models(const char *arg, const char *const *models)
675{
676 int i;
677
Peter Maydellc8057f92012-08-02 13:45:54 +0100678 if (!arg || !is_help_option(arg)) {
Markus Armbruster07caea32009-09-25 03:53:51 +0200679 return 0;
Peter Maydellc8057f92012-08-02 13:45:54 +0100680 }
Markus Armbruster07caea32009-09-25 03:53:51 +0200681
682 fprintf(stderr, "qemu: Supported NIC models: ");
683 for (i = 0 ; models[i]; i++)
684 fprintf(stderr, "%s%c", models[i], models[i+1] ? ',' : '\n');
685 return 1;
686}
687
aliguorid07f22c2009-01-13 19:03:57 +0000688void qemu_check_nic_model(NICInfo *nd, const char *model)
689{
690 const char *models[2];
691
692 models[0] = model;
693 models[1] = NULL;
694
Markus Armbruster07caea32009-09-25 03:53:51 +0200695 if (qemu_show_nic_models(nd->model, models))
696 exit(0);
697 if (qemu_find_nic_model(nd, models, model) < 0)
698 exit(1);
aliguorid07f22c2009-01-13 19:03:57 +0000699}
700
Markus Armbruster07caea32009-09-25 03:53:51 +0200701int qemu_find_nic_model(NICInfo *nd, const char * const *models,
702 const char *default_model)
aliguorid07f22c2009-01-13 19:03:57 +0000703{
Markus Armbruster07caea32009-09-25 03:53:51 +0200704 int i;
aliguorid07f22c2009-01-13 19:03:57 +0000705
706 if (!nd->model)
Anthony Liguori7267c092011-08-20 22:09:37 -0500707 nd->model = g_strdup(default_model);
aliguorid07f22c2009-01-13 19:03:57 +0000708
Markus Armbruster07caea32009-09-25 03:53:51 +0200709 for (i = 0 ; models[i]; i++) {
710 if (strcmp(nd->model, models[i]) == 0)
711 return i;
aliguorid07f22c2009-01-13 19:03:57 +0000712 }
713
Markus Armbruster6daf1942011-06-22 14:03:54 +0200714 error_report("Unsupported NIC model: %s", nd->model);
Markus Armbruster07caea32009-09-25 03:53:51 +0200715 return -1;
aliguorid07f22c2009-01-13 19:03:57 +0000716}
717
Laszlo Ersek1a0c0952012-07-17 16:17:21 +0200718static int net_init_nic(const NetClientOptions *opts, const char *name,
Stefan Hajnoczi4e68f7a2012-07-24 16:35:13 +0100719 NetClientState *peer)
Mark McLoughlinf83c6e12009-10-06 12:17:06 +0100720{
721 int idx;
722 NICInfo *nd;
Laszlo Ersek2456f362012-07-17 16:17:14 +0200723 const NetLegacyNicOptions *nic;
724
725 assert(opts->kind == NET_CLIENT_OPTIONS_KIND_NIC);
726 nic = opts->nic;
Mark McLoughlinf83c6e12009-10-06 12:17:06 +0100727
728 idx = nic_get_free_idx();
729 if (idx == -1 || nb_nics >= MAX_NICS) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100730 error_report("Too Many NICs");
Mark McLoughlinf83c6e12009-10-06 12:17:06 +0100731 return -1;
732 }
733
734 nd = &nd_table[idx];
735
736 memset(nd, 0, sizeof(*nd));
737
Laszlo Ersek2456f362012-07-17 16:17:14 +0200738 if (nic->has_netdev) {
739 nd->netdev = qemu_find_netdev(nic->netdev);
Mark McLoughlin5869c4d2009-10-08 19:58:29 +0100740 if (!nd->netdev) {
Laszlo Ersek2456f362012-07-17 16:17:14 +0200741 error_report("netdev '%s' not found", nic->netdev);
Mark McLoughlin5869c4d2009-10-08 19:58:29 +0100742 return -1;
743 }
744 } else {
Stefan Hajnoczid33d93b2012-07-24 16:35:05 +0100745 assert(peer);
746 nd->netdev = peer;
Mark McLoughlin5869c4d2009-10-08 19:58:29 +0100747 }
Markus Armbrusterc64f50d2013-01-22 11:07:57 +0100748 nd->name = g_strdup(name);
Laszlo Ersek2456f362012-07-17 16:17:14 +0200749 if (nic->has_model) {
750 nd->model = g_strdup(nic->model);
Mark McLoughlinf83c6e12009-10-06 12:17:06 +0100751 }
Laszlo Ersek2456f362012-07-17 16:17:14 +0200752 if (nic->has_addr) {
753 nd->devaddr = g_strdup(nic->addr);
Mark McLoughlinf83c6e12009-10-06 12:17:06 +0100754 }
755
Laszlo Ersek2456f362012-07-17 16:17:14 +0200756 if (nic->has_macaddr &&
757 net_parse_macaddr(nd->macaddr.a, nic->macaddr) < 0) {
Markus Armbruster1ecda022010-02-18 17:25:24 +0100758 error_report("invalid syntax for ethernet address");
Mark McLoughlinf83c6e12009-10-06 12:17:06 +0100759 return -1;
760 }
Dmitry Krivenokd60b20c2013-10-21 12:08:44 +0400761 if (nic->has_macaddr &&
762 is_multicast_ether_addr(nd->macaddr.a)) {
763 error_report("NIC cannot have multicast MAC address (odd 1st byte)");
764 return -1;
765 }
Jan Kiszka6eed1852011-07-20 12:20:22 +0200766 qemu_macaddr_default_if_unset(&nd->macaddr);
Mark McLoughlinf83c6e12009-10-06 12:17:06 +0100767
Laszlo Ersek2456f362012-07-17 16:17:14 +0200768 if (nic->has_vectors) {
769 if (nic->vectors > 0x7ffffff) {
770 error_report("invalid # of vectors: %"PRIu32, nic->vectors);
771 return -1;
772 }
773 nd->nvectors = nic->vectors;
774 } else {
775 nd->nvectors = DEV_NVECTORS_UNSPECIFIED;
Mark McLoughlinf83c6e12009-10-06 12:17:06 +0100776 }
777
778 nd->used = 1;
Mark McLoughlinf83c6e12009-10-06 12:17:06 +0100779 nb_nics++;
780
781 return idx;
782}
783
Mark McLoughlinf83c6e12009-10-06 12:17:06 +0100784
Laszlo Ersek6687b792012-07-17 16:17:13 +0200785static int (* const net_client_init_fun[NET_CLIENT_OPTIONS_KIND_MAX])(
Laszlo Ersek1a0c0952012-07-17 16:17:21 +0200786 const NetClientOptions *opts,
Laszlo Ersek6687b792012-07-17 16:17:13 +0200787 const char *name,
Stefan Hajnoczi4e68f7a2012-07-24 16:35:13 +0100788 NetClientState *peer) = {
Stefan Hajnoczif6c874e2012-07-24 16:35:04 +0100789 [NET_CLIENT_OPTIONS_KIND_NIC] = net_init_nic,
Mark McLoughlinec302ff2009-10-06 12:17:07 +0100790#ifdef CONFIG_SLIRP
Stefan Hajnoczif6c874e2012-07-24 16:35:04 +0100791 [NET_CLIENT_OPTIONS_KIND_USER] = net_init_slirp,
Mark McLoughlinec302ff2009-10-06 12:17:07 +0100792#endif
Stefan Hajnoczif6c874e2012-07-24 16:35:04 +0100793 [NET_CLIENT_OPTIONS_KIND_TAP] = net_init_tap,
794 [NET_CLIENT_OPTIONS_KIND_SOCKET] = net_init_socket,
Mark McLoughlindd510582009-10-06 12:17:10 +0100795#ifdef CONFIG_VDE
Stefan Hajnoczif6c874e2012-07-24 16:35:04 +0100796 [NET_CLIENT_OPTIONS_KIND_VDE] = net_init_vde,
Mark McLoughlindd510582009-10-06 12:17:10 +0100797#endif
Vincenzo Maffione58952132013-11-06 11:44:06 +0100798#ifdef CONFIG_NETMAP
799 [NET_CLIENT_OPTIONS_KIND_NETMAP] = net_init_netmap,
800#endif
Stefan Hajnoczif6c874e2012-07-24 16:35:04 +0100801 [NET_CLIENT_OPTIONS_KIND_DUMP] = net_init_dump,
Stefan Weil2944e4e2012-02-04 09:24:46 +0100802#ifdef CONFIG_NET_BRIDGE
Stefan Hajnoczif6c874e2012-07-24 16:35:04 +0100803 [NET_CLIENT_OPTIONS_KIND_BRIDGE] = net_init_bridge,
Laszlo Ersek6687b792012-07-17 16:17:13 +0200804#endif
Stefan Hajnoczif6c874e2012-07-24 16:35:04 +0100805 [NET_CLIENT_OPTIONS_KIND_HUBPORT] = net_init_hubport,
Nikolay Nikolaev03ce5742014-06-10 13:02:16 +0300806#ifdef CONFIG_VHOST_NET_USED
807 [NET_CLIENT_OPTIONS_KIND_VHOST_USER] = net_init_vhost_user,
808#endif
Mark McLoughlinf83c6e12009-10-06 12:17:06 +0100809};
810
Mark McLoughlinf83c6e12009-10-06 12:17:06 +0100811
Laszlo Ersek1a0c0952012-07-17 16:17:21 +0200812static int net_client_init1(const void *object, int is_netdev, Error **errp)
Laszlo Ersek6687b792012-07-17 16:17:13 +0200813{
814 union {
815 const Netdev *netdev;
816 const NetLegacy *net;
817 } u;
818 const NetClientOptions *opts;
819 const char *name;
Mark McLoughlinf83c6e12009-10-06 12:17:06 +0100820
Markus Armbruster5294e2c2010-03-25 17:22:38 +0100821 if (is_netdev) {
Laszlo Ersek6687b792012-07-17 16:17:13 +0200822 u.netdev = object;
823 opts = u.netdev->opts;
824 name = u.netdev->id;
825
826 switch (opts->kind) {
Mark McLoughlinf6b134a2009-10-08 19:58:27 +0100827#ifdef CONFIG_SLIRP
Laszlo Ersek6687b792012-07-17 16:17:13 +0200828 case NET_CLIENT_OPTIONS_KIND_USER:
Mark McLoughlinf6b134a2009-10-08 19:58:27 +0100829#endif
Laszlo Ersek6687b792012-07-17 16:17:13 +0200830 case NET_CLIENT_OPTIONS_KIND_TAP:
831 case NET_CLIENT_OPTIONS_KIND_SOCKET:
Mark McLoughlinf6b134a2009-10-08 19:58:27 +0100832#ifdef CONFIG_VDE
Laszlo Ersek6687b792012-07-17 16:17:13 +0200833 case NET_CLIENT_OPTIONS_KIND_VDE:
Mark McLoughlinf6b134a2009-10-08 19:58:27 +0100834#endif
Vincenzo Maffione58952132013-11-06 11:44:06 +0100835#ifdef CONFIG_NETMAP
836 case NET_CLIENT_OPTIONS_KIND_NETMAP:
837#endif
Laszlo Ersek6687b792012-07-17 16:17:13 +0200838#ifdef CONFIG_NET_BRIDGE
839 case NET_CLIENT_OPTIONS_KIND_BRIDGE:
840#endif
Stefan Hajnoczif6c874e2012-07-24 16:35:04 +0100841 case NET_CLIENT_OPTIONS_KIND_HUBPORT:
Nikolay Nikolaev03ce5742014-06-10 13:02:16 +0300842#ifdef CONFIG_VHOST_NET_USED
843 case NET_CLIENT_OPTIONS_KIND_VHOST_USER:
844#endif
Laszlo Ersek6687b792012-07-17 16:17:13 +0200845 break;
846
847 default:
Luiz Capitulino4559a1d2012-04-20 16:50:25 -0300848 error_set(errp, QERR_INVALID_PARAMETER_VALUE, "type",
849 "a netdev backend type");
Mark McLoughlinf6b134a2009-10-08 19:58:27 +0100850 return -1;
851 }
Laszlo Ersek6687b792012-07-17 16:17:13 +0200852 } else {
853 u.net = object;
854 opts = u.net->opts;
855 /* missing optional values have been initialized to "all bits zero" */
856 name = u.net->has_id ? u.net->id : u.net->name;
857 }
Mark McLoughlinf6b134a2009-10-08 19:58:27 +0100858
Laszlo Ersek6687b792012-07-17 16:17:13 +0200859 if (net_client_init_fun[opts->kind]) {
Stefan Hajnoczi4e68f7a2012-07-24 16:35:13 +0100860 NetClientState *peer = NULL;
Laszlo Ersek6687b792012-07-17 16:17:13 +0200861
862 /* Do not add to a vlan if it's a -netdev or a nic with a netdev=
863 * parameter. */
864 if (!is_netdev &&
865 (opts->kind != NET_CLIENT_OPTIONS_KIND_NIC ||
866 !opts->nic->has_netdev)) {
Stefan Hajnoczid33d93b2012-07-24 16:35:05 +0100867 peer = net_hub_add_port(u.net->has_vlan ? u.net->vlan : 0, NULL);
Mark McLoughlinf6b134a2009-10-08 19:58:27 +0100868 }
Laszlo Ersek6687b792012-07-17 16:17:13 +0200869
Stefan Hajnoczid33d93b2012-07-24 16:35:05 +0100870 if (net_client_init_fun[opts->kind](opts, name, peer) < 0) {
Laszlo Ersek6687b792012-07-17 16:17:13 +0200871 /* TODO push error reporting into init() methods */
872 error_set(errp, QERR_DEVICE_INIT_FAILED,
873 NetClientOptionsKind_lookup[opts->kind]);
Mark McLoughlinf6b134a2009-10-08 19:58:27 +0100874 return -1;
875 }
876 }
Laszlo Ersek6687b792012-07-17 16:17:13 +0200877 return 0;
Mark McLoughlinf83c6e12009-10-06 12:17:06 +0100878}
879
Laszlo Ersek6687b792012-07-17 16:17:13 +0200880
881static void net_visit(Visitor *v, int is_netdev, void **object, Error **errp)
882{
883 if (is_netdev) {
884 visit_type_Netdev(v, (Netdev **)object, NULL, errp);
885 } else {
886 visit_type_NetLegacy(v, (NetLegacy **)object, NULL, errp);
887 }
888}
889
890
891int net_client_init(QemuOpts *opts, int is_netdev, Error **errp)
892{
893 void *object = NULL;
894 Error *err = NULL;
895 int ret = -1;
896
897 {
898 OptsVisitor *ov = opts_visitor_new(opts);
899
900 net_visit(opts_get_visitor(ov), is_netdev, &object, &err);
901 opts_visitor_cleanup(ov);
902 }
903
904 if (!err) {
Laszlo Ersek1a0c0952012-07-17 16:17:21 +0200905 ret = net_client_init1(object, is_netdev, &err);
Laszlo Ersek6687b792012-07-17 16:17:13 +0200906 }
907
908 if (object) {
909 QapiDeallocVisitor *dv = qapi_dealloc_visitor_new();
910
911 net_visit(qapi_dealloc_get_visitor(dv), is_netdev, &object, NULL);
912 qapi_dealloc_visitor_cleanup(dv);
913 }
914
915 error_propagate(errp, err);
916 return ret;
917}
918
919
aliguori6f338c32009-02-11 15:21:54 +0000920static int net_host_check_device(const char *device)
921{
922 int i;
Hani Benhabiles84007e82014-05-27 23:39:33 +0100923 for (i = 0; host_net_devices[i]; i++) {
924 if (!strncmp(host_net_devices[i], device,
925 strlen(host_net_devices[i]))) {
aliguori6f338c32009-02-11 15:21:54 +0000926 return 1;
Hani Benhabiles84007e82014-05-27 23:39:33 +0100927 }
aliguori6f338c32009-02-11 15:21:54 +0000928 }
929
930 return 0;
931}
932
Luiz Capitulinof18c16d2009-08-28 15:27:14 -0300933void net_host_device_add(Monitor *mon, const QDict *qdict)
aliguori6f338c32009-02-11 15:21:54 +0000934{
Luiz Capitulinof18c16d2009-08-28 15:27:14 -0300935 const char *device = qdict_get_str(qdict, "device");
Mark McLoughlin7f1c9d22009-10-06 12:17:13 +0100936 const char *opts_str = qdict_get_try_str(qdict, "opts");
Luiz Capitulino4559a1d2012-04-20 16:50:25 -0300937 Error *local_err = NULL;
Mark McLoughlin7f1c9d22009-10-06 12:17:13 +0100938 QemuOpts *opts;
Luiz Capitulinof18c16d2009-08-28 15:27:14 -0300939
aliguori6f338c32009-02-11 15:21:54 +0000940 if (!net_host_check_device(device)) {
aliguori376253e2009-03-05 23:01:23 +0000941 monitor_printf(mon, "invalid host network device %s\n", device);
aliguori6f338c32009-02-11 15:21:54 +0000942 return;
943 }
Mark McLoughlin7f1c9d22009-10-06 12:17:13 +0100944
Gerd Hoffmann3329f072010-08-20 13:52:01 +0200945 opts = qemu_opts_parse(qemu_find_opts("net"), opts_str ? opts_str : "", 0);
Mark McLoughlin7f1c9d22009-10-06 12:17:13 +0100946 if (!opts) {
Mark McLoughlin7f1c9d22009-10-06 12:17:13 +0100947 return;
948 }
949
950 qemu_opt_set(opts, "type", device);
951
Luiz Capitulino4559a1d2012-04-20 16:50:25 -0300952 net_client_init(opts, 0, &local_err);
Markus Armbruster84d18f02014-01-30 15:07:28 +0100953 if (local_err) {
Luiz Capitulino4559a1d2012-04-20 16:50:25 -0300954 qerror_report_err(local_err);
955 error_free(local_err);
aliguori5c8be672009-04-21 19:56:32 +0000956 monitor_printf(mon, "adding host network device %s failed\n", device);
957 }
aliguori6f338c32009-02-11 15:21:54 +0000958}
959
Luiz Capitulinof18c16d2009-08-28 15:27:14 -0300960void net_host_device_remove(Monitor *mon, const QDict *qdict)
aliguori6f338c32009-02-11 15:21:54 +0000961{
Stefan Hajnoczi35277d12012-07-24 16:35:14 +0100962 NetClientState *nc;
Luiz Capitulinof18c16d2009-08-28 15:27:14 -0300963 int vlan_id = qdict_get_int(qdict, "vlan_id");
964 const char *device = qdict_get_str(qdict, "device");
aliguori6f338c32009-02-11 15:21:54 +0000965
Stefan Hajnoczi35277d12012-07-24 16:35:14 +0100966 nc = net_hub_find_client_by_name(vlan_id, device);
967 if (!nc) {
Hani Benhabiles86e11772014-04-01 00:05:14 +0100968 error_report("Host network device '%s' on hub '%d' not found",
969 device, vlan_id);
aliguori6f338c32009-02-11 15:21:54 +0000970 return;
971 }
Stefan Hajnoczi35277d12012-07-24 16:35:14 +0100972 if (!net_host_check_device(nc->model)) {
Hani Benhabiles86e11772014-04-01 00:05:14 +0100973 error_report("invalid host network device '%s'", device);
aliguorie8f1f9d2009-04-21 19:56:08 +0000974 return;
975 }
Stefan Hajnoczib20c6b92012-07-24 16:35:15 +0100976 qemu_del_net_client(nc);
aliguori6f338c32009-02-11 15:21:54 +0000977}
978
Luiz Capitulino928059a2012-04-18 17:34:15 -0300979void netdev_add(QemuOpts *opts, Error **errp)
980{
981 net_client_init(opts, 1, errp);
982}
983
984int qmp_netdev_add(Monitor *mon, const QDict *qdict, QObject **ret)
Markus Armbrusterae82d322010-03-25 17:22:40 +0100985{
Luiz Capitulino4e899782012-04-18 17:24:01 -0300986 Error *local_err = NULL;
Luiz Capitulino928059a2012-04-18 17:34:15 -0300987 QemuOptsList *opts_list;
Markus Armbrusterae82d322010-03-25 17:22:40 +0100988 QemuOpts *opts;
Markus Armbrusterae82d322010-03-25 17:22:40 +0100989
Luiz Capitulino928059a2012-04-18 17:34:15 -0300990 opts_list = qemu_find_opts_err("netdev", &local_err);
Markus Armbruster84d18f02014-01-30 15:07:28 +0100991 if (local_err) {
Luiz Capitulino928059a2012-04-18 17:34:15 -0300992 goto exit_err;
Markus Armbrusterae82d322010-03-25 17:22:40 +0100993 }
994
Luiz Capitulino928059a2012-04-18 17:34:15 -0300995 opts = qemu_opts_from_qdict(opts_list, qdict, &local_err);
Markus Armbruster84d18f02014-01-30 15:07:28 +0100996 if (local_err) {
Luiz Capitulino928059a2012-04-18 17:34:15 -0300997 goto exit_err;
998 }
999
1000 netdev_add(opts, &local_err);
Markus Armbruster84d18f02014-01-30 15:07:28 +01001001 if (local_err) {
Yoshiaki Tamura410cbaf2010-06-21 10:41:36 +09001002 qemu_opts_del(opts);
Luiz Capitulino928059a2012-04-18 17:34:15 -03001003 goto exit_err;
Yoshiaki Tamura410cbaf2010-06-21 10:41:36 +09001004 }
1005
Luiz Capitulino928059a2012-04-18 17:34:15 -03001006 return 0;
1007
1008exit_err:
1009 qerror_report_err(local_err);
1010 error_free(local_err);
1011 return -1;
Markus Armbrusterae82d322010-03-25 17:22:40 +01001012}
1013
Luiz Capitulino5f964152012-04-16 14:36:32 -03001014void qmp_netdev_del(const char *id, Error **errp)
Markus Armbrusterae82d322010-03-25 17:22:40 +01001015{
Stefan Hajnoczi35277d12012-07-24 16:35:14 +01001016 NetClientState *nc;
Stefan Hajnoczi645c9492012-10-24 14:34:12 +02001017 QemuOpts *opts;
Markus Armbrusterae82d322010-03-25 17:22:40 +01001018
Stefan Hajnoczi35277d12012-07-24 16:35:14 +01001019 nc = qemu_find_netdev(id);
1020 if (!nc) {
Luiz Capitulino5f964152012-04-16 14:36:32 -03001021 error_set(errp, QERR_DEVICE_NOT_FOUND, id);
1022 return;
Markus Armbrusterae82d322010-03-25 17:22:40 +01001023 }
Luiz Capitulino5f964152012-04-16 14:36:32 -03001024
Stefan Hajnoczi645c9492012-10-24 14:34:12 +02001025 opts = qemu_opts_find(qemu_find_opts_err("netdev", NULL), id);
1026 if (!opts) {
1027 error_setg(errp, "Device '%s' is not a netdev", id);
1028 return;
1029 }
1030
Stefan Hajnoczib20c6b92012-07-24 16:35:15 +01001031 qemu_del_net_client(nc);
Stefan Hajnoczi645c9492012-10-24 14:34:12 +02001032 qemu_opts_del(opts);
Markus Armbrusterae82d322010-03-25 17:22:40 +01001033}
1034
Zhi Yong Wu1a859592012-07-24 16:35:16 +01001035void print_net_client(Monitor *mon, NetClientState *nc)
Jan Kiszka44e798d2011-07-20 12:20:21 +02001036{
Jason Wang1ceef9f2013-01-30 19:12:28 +08001037 monitor_printf(mon, "%s: index=%d,type=%s,%s\n", nc->name,
1038 nc->queue_index,
1039 NetClientOptionsKind_lookup[nc->info->type],
1040 nc->info_str);
Jan Kiszka44e798d2011-07-20 12:20:21 +02001041}
1042
Amos Kongb1be4282013-06-14 15:45:52 +08001043RxFilterInfoList *qmp_query_rx_filter(bool has_name, const char *name,
1044 Error **errp)
1045{
1046 NetClientState *nc;
1047 RxFilterInfoList *filter_list = NULL, *last_entry = NULL;
1048
1049 QTAILQ_FOREACH(nc, &net_clients, next) {
1050 RxFilterInfoList *entry;
1051 RxFilterInfo *info;
1052
1053 if (has_name && strcmp(nc->name, name) != 0) {
1054 continue;
1055 }
1056
1057 /* only query rx-filter information of NIC */
1058 if (nc->info->type != NET_CLIENT_OPTIONS_KIND_NIC) {
1059 if (has_name) {
1060 error_setg(errp, "net client(%s) isn't a NIC", name);
Markus Armbruster9083da12014-04-24 15:44:18 +02001061 return NULL;
Amos Kongb1be4282013-06-14 15:45:52 +08001062 }
1063 continue;
1064 }
1065
1066 if (nc->info->query_rx_filter) {
1067 info = nc->info->query_rx_filter(nc);
1068 entry = g_malloc0(sizeof(*entry));
1069 entry->value = info;
1070
1071 if (!filter_list) {
1072 filter_list = entry;
1073 } else {
1074 last_entry->next = entry;
1075 }
1076 last_entry = entry;
1077 } else if (has_name) {
1078 error_setg(errp, "net client(%s) doesn't support"
1079 " rx-filter querying", name);
Markus Armbruster9083da12014-04-24 15:44:18 +02001080 return NULL;
Amos Kongb1be4282013-06-14 15:45:52 +08001081 }
Markus Armbruster638fb142014-04-24 15:44:17 +02001082
1083 if (has_name) {
1084 break;
1085 }
Amos Kongb1be4282013-06-14 15:45:52 +08001086 }
1087
Markus Armbruster9083da12014-04-24 15:44:18 +02001088 if (filter_list == NULL && has_name) {
Amos Kongb1be4282013-06-14 15:45:52 +08001089 error_setg(errp, "invalid net client name: %s", name);
1090 }
1091
1092 return filter_list;
1093}
1094
Wenchao Xia84f2d0e2013-01-14 14:06:25 +08001095void do_info_network(Monitor *mon, const QDict *qdict)
aliguori63a01ef2008-10-31 19:10:00 +00001096{
Stefan Hajnoczi35277d12012-07-24 16:35:14 +01001097 NetClientState *nc, *peer;
Laszlo Ersek2be64a62012-07-17 16:17:12 +02001098 NetClientOptionsKind type;
aliguori63a01ef2008-10-31 19:10:00 +00001099
Zhi Yong Wu1a859592012-07-24 16:35:16 +01001100 net_hub_info(mon);
Mark McLoughlin5610c3a2009-10-08 19:58:23 +01001101
Stefan Hajnoczi35277d12012-07-24 16:35:14 +01001102 QTAILQ_FOREACH(nc, &net_clients, next) {
1103 peer = nc->peer;
1104 type = nc->info->type;
Zhi Yong Wu1a859592012-07-24 16:35:16 +01001105
1106 /* Skip if already printed in hub info */
1107 if (net_hub_id_for_client(nc, NULL) == 0) {
1108 continue;
Mark McLoughlin5610c3a2009-10-08 19:58:23 +01001109 }
Zhi Yong Wu1a859592012-07-24 16:35:16 +01001110
Laszlo Ersek2be64a62012-07-17 16:17:12 +02001111 if (!peer || type == NET_CLIENT_OPTIONS_KIND_NIC) {
Stefan Hajnoczi35277d12012-07-24 16:35:14 +01001112 print_net_client(mon, nc);
Jan Kiszka19061e62011-07-20 12:20:19 +02001113 } /* else it's a netdev connected to a NIC, printed with the NIC */
Laszlo Ersek2be64a62012-07-17 16:17:12 +02001114 if (peer && type == NET_CLIENT_OPTIONS_KIND_NIC) {
Zhi Yong Wu1a859592012-07-24 16:35:16 +01001115 monitor_printf(mon, " \\ ");
Jan Kiszka44e798d2011-07-20 12:20:21 +02001116 print_net_client(mon, peer);
Markus Armbrustera0104e02010-02-11 14:45:01 +01001117 }
Markus Armbrustera0104e02010-02-11 14:45:01 +01001118 }
aliguori63a01ef2008-10-31 19:10:00 +00001119}
1120
Luiz Capitulino4b371562011-11-23 13:11:55 -02001121void qmp_set_link(const char *name, bool up, Error **errp)
aliguori436e5e52009-01-08 19:44:06 +00001122{
Jason Wang1ceef9f2013-01-30 19:12:28 +08001123 NetClientState *ncs[MAX_QUEUE_NUM];
1124 NetClientState *nc;
1125 int queues, i;
aliguori436e5e52009-01-08 19:44:06 +00001126
Jason Wang1ceef9f2013-01-30 19:12:28 +08001127 queues = qemu_find_net_clients_except(name, ncs,
1128 NET_CLIENT_OPTIONS_KIND_MAX,
1129 MAX_QUEUE_NUM);
1130
1131 if (queues == 0) {
Luiz Capitulino4b371562011-11-23 13:11:55 -02001132 error_set(errp, QERR_DEVICE_NOT_FOUND, name);
1133 return;
aliguori436e5e52009-01-08 19:44:06 +00001134 }
Jason Wang1ceef9f2013-01-30 19:12:28 +08001135 nc = ncs[0];
aliguori436e5e52009-01-08 19:44:06 +00001136
Jason Wang1ceef9f2013-01-30 19:12:28 +08001137 for (i = 0; i < queues; i++) {
1138 ncs[i]->link_down = !up;
1139 }
aliguori436e5e52009-01-08 19:44:06 +00001140
Stefan Hajnoczi35277d12012-07-24 16:35:14 +01001141 if (nc->info->link_status_changed) {
1142 nc->info->link_status_changed(nc);
Mark McLoughlin665a3b02009-11-25 18:49:30 +00001143 }
Michael S. Tsirkinab1cbe12011-02-09 18:45:04 +02001144
Vlad Yasevich02d38fc2013-11-21 21:05:51 -05001145 if (nc->peer) {
1146 /* Change peer link only if the peer is NIC and then notify peer.
1147 * If the peer is a HUBPORT or a backend, we do not change the
1148 * link status.
1149 *
1150 * This behavior is compatible with qemu vlans where there could be
1151 * multiple clients that can still communicate with each other in
1152 * disconnected mode. For now maintain this compatibility.
1153 */
1154 if (nc->peer->info->type == NET_CLIENT_OPTIONS_KIND_NIC) {
1155 for (i = 0; i < queues; i++) {
1156 ncs[i]->peer->link_down = !up;
1157 }
1158 }
1159 if (nc->peer->info->link_status_changed) {
1160 nc->peer->info->link_status_changed(nc->peer);
1161 }
Michael S. Tsirkinab1cbe12011-02-09 18:45:04 +02001162 }
aliguori436e5e52009-01-08 19:44:06 +00001163}
1164
aliguori63a01ef2008-10-31 19:10:00 +00001165void net_cleanup(void)
1166{
Jason Wang1ceef9f2013-01-30 19:12:28 +08001167 NetClientState *nc;
aliguori63a01ef2008-10-31 19:10:00 +00001168
Jason Wang1ceef9f2013-01-30 19:12:28 +08001169 /* We may del multiple entries during qemu_del_net_client(),
1170 * so QTAILQ_FOREACH_SAFE() is also not safe here.
1171 */
1172 while (!QTAILQ_EMPTY(&net_clients)) {
1173 nc = QTAILQ_FIRST(&net_clients);
Jason Wang948ecf22013-01-30 19:12:24 +08001174 if (nc->info->type == NET_CLIENT_OPTIONS_KIND_NIC) {
1175 qemu_del_nic(qemu_get_nic(nc));
1176 } else {
1177 qemu_del_net_client(nc);
1178 }
Mark McLoughlin577c4af2009-10-08 19:58:28 +01001179 }
aliguori63a01ef2008-10-31 19:10:00 +00001180}
1181
Markus Armbruster668680f2010-02-11 14:44:58 +01001182void net_check_clients(void)
aliguori63a01ef2008-10-31 19:10:00 +00001183{
Stefan Hajnoczi35277d12012-07-24 16:35:14 +01001184 NetClientState *nc;
Peter Maydell48e2faf2011-05-20 16:50:01 +01001185 int i;
aliguori63a01ef2008-10-31 19:10:00 +00001186
Peter Maydell641f6ea2011-05-20 16:50:00 +01001187 /* Don't warn about the default network setup that you get if
1188 * no command line -net or -netdev options are specified. There
1189 * are two cases that we would otherwise complain about:
1190 * (1) board doesn't support a NIC but the implicit "-net nic"
1191 * requested one
1192 * (2) CONFIG_SLIRP not set, in which case the implicit "-net nic"
1193 * sets up a nic that isn't connected to anything.
1194 */
1195 if (default_net) {
1196 return;
1197 }
1198
Stefan Hajnoczi81017642012-07-24 16:35:07 +01001199 net_hub_check_clients();
Tristan Gingoldac60cc12011-03-15 14:20:54 +01001200
Stefan Hajnoczi35277d12012-07-24 16:35:14 +01001201 QTAILQ_FOREACH(nc, &net_clients, next) {
1202 if (!nc->peer) {
Markus Armbrusterefe32fd2010-02-11 14:45:00 +01001203 fprintf(stderr, "Warning: %s %s has no peer\n",
Stefan Hajnoczi35277d12012-07-24 16:35:14 +01001204 nc->info->type == NET_CLIENT_OPTIONS_KIND_NIC ?
1205 "nic" : "netdev", nc->name);
Markus Armbrusterefe32fd2010-02-11 14:45:00 +01001206 }
1207 }
Peter Maydell48e2faf2011-05-20 16:50:01 +01001208
1209 /* Check that all NICs requested via -net nic actually got created.
1210 * NICs created via -device don't need to be checked here because
1211 * they are always instantiated.
1212 */
1213 for (i = 0; i < MAX_NICS; i++) {
1214 NICInfo *nd = &nd_table[i];
1215 if (nd->used && !nd->instantiated) {
1216 fprintf(stderr, "Warning: requested NIC (%s, model %s) "
1217 "was not created (not supported by this machine?)\n",
1218 nd->name ? nd->name : "anonymous",
1219 nd->model ? nd->model : "unspecified");
1220 }
1221 }
aliguori63a01ef2008-10-31 19:10:00 +00001222}
Mark McLoughlindc1c9fe2009-10-06 12:17:16 +01001223
1224static int net_init_client(QemuOpts *opts, void *dummy)
1225{
Luiz Capitulino4559a1d2012-04-20 16:50:25 -03001226 Error *local_err = NULL;
1227
1228 net_client_init(opts, 0, &local_err);
Markus Armbruster84d18f02014-01-30 15:07:28 +01001229 if (local_err) {
Luiz Capitulino4559a1d2012-04-20 16:50:25 -03001230 qerror_report_err(local_err);
1231 error_free(local_err);
Mark McLoughlinc1671a02009-10-12 09:52:00 +01001232 return -1;
Luiz Capitulino4559a1d2012-04-20 16:50:25 -03001233 }
1234
Mark McLoughlinc1671a02009-10-12 09:52:00 +01001235 return 0;
Mark McLoughlinf6b134a2009-10-08 19:58:27 +01001236}
1237
1238static int net_init_netdev(QemuOpts *opts, void *dummy)
1239{
Luiz Capitulino4559a1d2012-04-20 16:50:25 -03001240 Error *local_err = NULL;
1241 int ret;
1242
1243 ret = net_client_init(opts, 1, &local_err);
Markus Armbruster84d18f02014-01-30 15:07:28 +01001244 if (local_err) {
Luiz Capitulino4559a1d2012-04-20 16:50:25 -03001245 qerror_report_err(local_err);
1246 error_free(local_err);
1247 return -1;
1248 }
1249
1250 return ret;
Mark McLoughlindc1c9fe2009-10-06 12:17:16 +01001251}
1252
1253int net_init_clients(void)
1254{
Gerd Hoffmann3329f072010-08-20 13:52:01 +02001255 QemuOptsList *net = qemu_find_opts("net");
1256
Gerd Hoffmanncb4522c2009-12-08 13:11:47 +01001257 if (default_net) {
Mark McLoughlindc1c9fe2009-10-06 12:17:16 +01001258 /* if no clients, we use a default config */
Gerd Hoffmann3329f072010-08-20 13:52:01 +02001259 qemu_opts_set(net, NULL, "type", "nic");
Mark McLoughlindc1c9fe2009-10-06 12:17:16 +01001260#ifdef CONFIG_SLIRP
Gerd Hoffmann3329f072010-08-20 13:52:01 +02001261 qemu_opts_set(net, NULL, "type", "user");
Mark McLoughlindc1c9fe2009-10-06 12:17:16 +01001262#endif
1263 }
1264
Stefan Hajnoczi94878992012-07-24 16:35:12 +01001265 QTAILQ_INIT(&net_clients);
Mark McLoughlin5610c3a2009-10-08 19:58:23 +01001266
Gerd Hoffmann3329f072010-08-20 13:52:01 +02001267 if (qemu_opts_foreach(qemu_find_opts("netdev"), net_init_netdev, NULL, 1) == -1)
Mark McLoughlinf6b134a2009-10-08 19:58:27 +01001268 return -1;
1269
Gerd Hoffmann3329f072010-08-20 13:52:01 +02001270 if (qemu_opts_foreach(net, net_init_client, NULL, 1) == -1) {
Mark McLoughlindc1c9fe2009-10-06 12:17:16 +01001271 return -1;
1272 }
1273
Mark McLoughlindc1c9fe2009-10-06 12:17:16 +01001274 return 0;
1275}
1276
Mark McLoughlin7f161aa2009-10-08 19:58:25 +01001277int net_client_parse(QemuOptsList *opts_list, const char *optarg)
Mark McLoughlindc1c9fe2009-10-06 12:17:16 +01001278{
Juan Quintelaa3a766e2009-10-07 23:44:15 +02001279#if defined(CONFIG_SLIRP)
Mark McLoughlin68ac40d2009-11-25 18:48:54 +00001280 int ret;
1281 if (net_slirp_parse_legacy(opts_list, optarg, &ret)) {
Mark McLoughlindc1c9fe2009-10-06 12:17:16 +01001282 return ret;
1283 }
Juan Quintelaa3a766e2009-10-07 23:44:15 +02001284#endif
Mark McLoughlin68ac40d2009-11-25 18:48:54 +00001285
Markus Armbruster8212c642010-02-10 19:52:18 +01001286 if (!qemu_opts_parse(opts_list, optarg, 1)) {
Mark McLoughlindc1c9fe2009-10-06 12:17:16 +01001287 return -1;
1288 }
1289
Gerd Hoffmanncb4522c2009-12-08 13:11:47 +01001290 default_net = 0;
Mark McLoughlindc1c9fe2009-10-06 12:17:16 +01001291 return 0;
1292}
Jason Wang7fc8d912012-03-05 11:08:50 +08001293
1294/* From FreeBSD */
1295/* XXX: optimize */
1296unsigned compute_mcast_idx(const uint8_t *ep)
1297{
1298 uint32_t crc;
1299 int carry, i, j;
1300 uint8_t b;
1301
1302 crc = 0xffffffff;
1303 for (i = 0; i < 6; i++) {
1304 b = *ep++;
1305 for (j = 0; j < 8; j++) {
1306 carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01);
1307 crc <<= 1;
1308 b >>= 1;
1309 if (carry) {
1310 crc = ((crc ^ POLYNOMIAL) | carry);
1311 }
1312 }
1313 }
1314 return crc >> 26;
1315}
Paolo Bonzini4d454572012-11-26 16:03:42 +01001316
1317QemuOptsList qemu_netdev_opts = {
1318 .name = "netdev",
1319 .implied_opt_name = "type",
1320 .head = QTAILQ_HEAD_INITIALIZER(qemu_netdev_opts.head),
1321 .desc = {
1322 /*
1323 * no elements => accept any params
1324 * validation will happen later
1325 */
1326 { /* end of list */ }
1327 },
1328};
1329
1330QemuOptsList qemu_net_opts = {
1331 .name = "net",
1332 .implied_opt_name = "type",
1333 .head = QTAILQ_HEAD_INITIALIZER(qemu_net_opts.head),
1334 .desc = {
1335 /*
1336 * no elements => accept any params
1337 * validation will happen later
1338 */
1339 { /* end of list */ }
1340 },
1341};