1fd9400b3SPaolo Bonzini /* 2fd9400b3SPaolo Bonzini * QEMU System Emulator 3fd9400b3SPaolo Bonzini * 4fd9400b3SPaolo Bonzini * Copyright (c) 2003-2008 Fabrice Bellard 5fd9400b3SPaolo Bonzini * 6fd9400b3SPaolo Bonzini * Permission is hereby granted, free of charge, to any person obtaining a copy 7fd9400b3SPaolo Bonzini * of this software and associated documentation files (the "Software"), to deal 8fd9400b3SPaolo Bonzini * in the Software without restriction, including without limitation the rights 9fd9400b3SPaolo Bonzini * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10fd9400b3SPaolo Bonzini * copies of the Software, and to permit persons to whom the Software is 11fd9400b3SPaolo Bonzini * furnished to do so, subject to the following conditions: 12fd9400b3SPaolo Bonzini * 13fd9400b3SPaolo Bonzini * The above copyright notice and this permission notice shall be included in 14fd9400b3SPaolo Bonzini * all copies or substantial portions of the Software. 15fd9400b3SPaolo Bonzini * 16fd9400b3SPaolo Bonzini * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17fd9400b3SPaolo Bonzini * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18fd9400b3SPaolo Bonzini * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19fd9400b3SPaolo Bonzini * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20fd9400b3SPaolo Bonzini * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21fd9400b3SPaolo Bonzini * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22fd9400b3SPaolo Bonzini * THE SOFTWARE. 23fd9400b3SPaolo Bonzini */ 24fd9400b3SPaolo Bonzini #include "config-host.h" 25fd9400b3SPaolo Bonzini 261422e32dSPaolo Bonzini #include "net/net.h" 27fd9400b3SPaolo Bonzini #include "clients.h" 28fd9400b3SPaolo Bonzini #include "hub.h" 291422e32dSPaolo Bonzini #include "net/slirp.h" 30fd9400b3SPaolo Bonzini #include "util.h" 31fd9400b3SPaolo Bonzini 3283c9089eSPaolo Bonzini #include "monitor/monitor.h" 33fd9400b3SPaolo Bonzini #include "qemu-common.h" 341de7afc9SPaolo Bonzini #include "qemu/sockets.h" 351de7afc9SPaolo Bonzini #include "qemu/config-file.h" 36fd9400b3SPaolo Bonzini #include "qmp-commands.h" 37fd9400b3SPaolo Bonzini #include "hw/qdev.h" 381de7afc9SPaolo Bonzini #include "qemu/iov.h" 39fd9400b3SPaolo Bonzini #include "qapi-visit.h" 40fd9400b3SPaolo Bonzini #include "qapi/opts-visitor.h" 417b1b5d19SPaolo Bonzini #include "qapi/dealloc-visitor.h" 42fd9400b3SPaolo Bonzini 43fd9400b3SPaolo Bonzini /* Net bridge is currently not supported for W32. */ 44fd9400b3SPaolo Bonzini #if !defined(_WIN32) 45fd9400b3SPaolo Bonzini # define CONFIG_NET_BRIDGE 46fd9400b3SPaolo Bonzini #endif 47fd9400b3SPaolo Bonzini 48fd9400b3SPaolo Bonzini static QTAILQ_HEAD(, NetClientState) net_clients; 49fd9400b3SPaolo Bonzini 50fd9400b3SPaolo Bonzini int default_net = 1; 51fd9400b3SPaolo Bonzini 52fd9400b3SPaolo Bonzini /***********************************************************/ 53fd9400b3SPaolo Bonzini /* network device redirectors */ 54fd9400b3SPaolo Bonzini 55fd9400b3SPaolo Bonzini #if defined(DEBUG_NET) 56fd9400b3SPaolo Bonzini static void hex_dump(FILE *f, const uint8_t *buf, int size) 57fd9400b3SPaolo Bonzini { 58fd9400b3SPaolo Bonzini int len, i, j, c; 59fd9400b3SPaolo Bonzini 60fd9400b3SPaolo Bonzini for(i=0;i<size;i+=16) { 61fd9400b3SPaolo Bonzini len = size - i; 62fd9400b3SPaolo Bonzini if (len > 16) 63fd9400b3SPaolo Bonzini len = 16; 64fd9400b3SPaolo Bonzini fprintf(f, "%08x ", i); 65fd9400b3SPaolo Bonzini for(j=0;j<16;j++) { 66fd9400b3SPaolo Bonzini if (j < len) 67fd9400b3SPaolo Bonzini fprintf(f, " %02x", buf[i+j]); 68fd9400b3SPaolo Bonzini else 69fd9400b3SPaolo Bonzini fprintf(f, " "); 70fd9400b3SPaolo Bonzini } 71fd9400b3SPaolo Bonzini fprintf(f, " "); 72fd9400b3SPaolo Bonzini for(j=0;j<len;j++) { 73fd9400b3SPaolo Bonzini c = buf[i+j]; 74fd9400b3SPaolo Bonzini if (c < ' ' || c > '~') 75fd9400b3SPaolo Bonzini c = '.'; 76fd9400b3SPaolo Bonzini fprintf(f, "%c", c); 77fd9400b3SPaolo Bonzini } 78fd9400b3SPaolo Bonzini fprintf(f, "\n"); 79fd9400b3SPaolo Bonzini } 80fd9400b3SPaolo Bonzini } 81fd9400b3SPaolo Bonzini #endif 82fd9400b3SPaolo Bonzini 83fd9400b3SPaolo Bonzini static int get_str_sep(char *buf, int buf_size, const char **pp, int sep) 84fd9400b3SPaolo Bonzini { 85fd9400b3SPaolo Bonzini const char *p, *p1; 86fd9400b3SPaolo Bonzini int len; 87fd9400b3SPaolo Bonzini p = *pp; 88fd9400b3SPaolo Bonzini p1 = strchr(p, sep); 89fd9400b3SPaolo Bonzini if (!p1) 90fd9400b3SPaolo Bonzini return -1; 91fd9400b3SPaolo Bonzini len = p1 - p; 92fd9400b3SPaolo Bonzini p1++; 93fd9400b3SPaolo Bonzini if (buf_size > 0) { 94fd9400b3SPaolo Bonzini if (len > buf_size - 1) 95fd9400b3SPaolo Bonzini len = buf_size - 1; 96fd9400b3SPaolo Bonzini memcpy(buf, p, len); 97fd9400b3SPaolo Bonzini buf[len] = '\0'; 98fd9400b3SPaolo Bonzini } 99fd9400b3SPaolo Bonzini *pp = p1; 100fd9400b3SPaolo Bonzini return 0; 101fd9400b3SPaolo Bonzini } 102fd9400b3SPaolo Bonzini 103fd9400b3SPaolo Bonzini int parse_host_port(struct sockaddr_in *saddr, const char *str) 104fd9400b3SPaolo Bonzini { 105fd9400b3SPaolo Bonzini char buf[512]; 106fd9400b3SPaolo Bonzini struct hostent *he; 107fd9400b3SPaolo Bonzini const char *p, *r; 108fd9400b3SPaolo Bonzini int port; 109fd9400b3SPaolo Bonzini 110fd9400b3SPaolo Bonzini p = str; 111fd9400b3SPaolo Bonzini if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) 112fd9400b3SPaolo Bonzini return -1; 113fd9400b3SPaolo Bonzini saddr->sin_family = AF_INET; 114fd9400b3SPaolo Bonzini if (buf[0] == '\0') { 115fd9400b3SPaolo Bonzini saddr->sin_addr.s_addr = 0; 116fd9400b3SPaolo Bonzini } else { 117fd9400b3SPaolo Bonzini if (qemu_isdigit(buf[0])) { 118fd9400b3SPaolo Bonzini if (!inet_aton(buf, &saddr->sin_addr)) 119fd9400b3SPaolo Bonzini return -1; 120fd9400b3SPaolo Bonzini } else { 121fd9400b3SPaolo Bonzini if ((he = gethostbyname(buf)) == NULL) 122fd9400b3SPaolo Bonzini return - 1; 123fd9400b3SPaolo Bonzini saddr->sin_addr = *(struct in_addr *)he->h_addr; 124fd9400b3SPaolo Bonzini } 125fd9400b3SPaolo Bonzini } 126fd9400b3SPaolo Bonzini port = strtol(p, (char **)&r, 0); 127fd9400b3SPaolo Bonzini if (r == p) 128fd9400b3SPaolo Bonzini return -1; 129fd9400b3SPaolo Bonzini saddr->sin_port = htons(port); 130fd9400b3SPaolo Bonzini return 0; 131fd9400b3SPaolo Bonzini } 132fd9400b3SPaolo Bonzini 133fd9400b3SPaolo Bonzini void qemu_format_nic_info_str(NetClientState *nc, uint8_t macaddr[6]) 134fd9400b3SPaolo Bonzini { 135fd9400b3SPaolo Bonzini snprintf(nc->info_str, sizeof(nc->info_str), 136fd9400b3SPaolo Bonzini "model=%s,macaddr=%02x:%02x:%02x:%02x:%02x:%02x", 137fd9400b3SPaolo Bonzini nc->model, 138fd9400b3SPaolo Bonzini macaddr[0], macaddr[1], macaddr[2], 139fd9400b3SPaolo Bonzini macaddr[3], macaddr[4], macaddr[5]); 140fd9400b3SPaolo Bonzini } 141fd9400b3SPaolo Bonzini 142fd9400b3SPaolo Bonzini void qemu_macaddr_default_if_unset(MACAddr *macaddr) 143fd9400b3SPaolo Bonzini { 144fd9400b3SPaolo Bonzini static int index = 0; 145fd9400b3SPaolo Bonzini static const MACAddr zero = { .a = { 0,0,0,0,0,0 } }; 146fd9400b3SPaolo Bonzini 147fd9400b3SPaolo Bonzini if (memcmp(macaddr, &zero, sizeof(zero)) != 0) 148fd9400b3SPaolo Bonzini return; 149fd9400b3SPaolo Bonzini macaddr->a[0] = 0x52; 150fd9400b3SPaolo Bonzini macaddr->a[1] = 0x54; 151fd9400b3SPaolo Bonzini macaddr->a[2] = 0x00; 152fd9400b3SPaolo Bonzini macaddr->a[3] = 0x12; 153fd9400b3SPaolo Bonzini macaddr->a[4] = 0x34; 154fd9400b3SPaolo Bonzini macaddr->a[5] = 0x56 + index++; 155fd9400b3SPaolo Bonzini } 156fd9400b3SPaolo Bonzini 157fd9400b3SPaolo Bonzini /** 158fd9400b3SPaolo Bonzini * Generate a name for net client 159fd9400b3SPaolo Bonzini * 160fd9400b3SPaolo Bonzini * Only net clients created with the legacy -net option need this. Naming is 161fd9400b3SPaolo Bonzini * mandatory for net clients created with -netdev. 162fd9400b3SPaolo Bonzini */ 163fd9400b3SPaolo Bonzini static char *assign_name(NetClientState *nc1, const char *model) 164fd9400b3SPaolo Bonzini { 165fd9400b3SPaolo Bonzini NetClientState *nc; 166fd9400b3SPaolo Bonzini char buf[256]; 167fd9400b3SPaolo Bonzini int id = 0; 168fd9400b3SPaolo Bonzini 169fd9400b3SPaolo Bonzini QTAILQ_FOREACH(nc, &net_clients, next) { 170fd9400b3SPaolo Bonzini if (nc == nc1) { 171fd9400b3SPaolo Bonzini continue; 172fd9400b3SPaolo Bonzini } 173fd9400b3SPaolo Bonzini /* For compatibility only bump id for net clients on a vlan */ 174fd9400b3SPaolo Bonzini if (strcmp(nc->model, model) == 0 && 175fd9400b3SPaolo Bonzini net_hub_id_for_client(nc, NULL) == 0) { 176fd9400b3SPaolo Bonzini id++; 177fd9400b3SPaolo Bonzini } 178fd9400b3SPaolo Bonzini } 179fd9400b3SPaolo Bonzini 180fd9400b3SPaolo Bonzini snprintf(buf, sizeof(buf), "%s.%d", model, id); 181fd9400b3SPaolo Bonzini 182fd9400b3SPaolo Bonzini return g_strdup(buf); 183fd9400b3SPaolo Bonzini } 184fd9400b3SPaolo Bonzini 185f7860455SJason Wang static void qemu_net_client_destructor(NetClientState *nc) 186f7860455SJason Wang { 187f7860455SJason Wang g_free(nc); 188f7860455SJason Wang } 189f7860455SJason Wang 19018a1541aSJason Wang static void qemu_net_client_setup(NetClientState *nc, 19118a1541aSJason Wang NetClientInfo *info, 192fd9400b3SPaolo Bonzini NetClientState *peer, 193fd9400b3SPaolo Bonzini const char *model, 194f7860455SJason Wang const char *name, 195f7860455SJason Wang NetClientDestructor *destructor) 196fd9400b3SPaolo Bonzini { 197fd9400b3SPaolo Bonzini nc->info = info; 198fd9400b3SPaolo Bonzini nc->model = g_strdup(model); 199fd9400b3SPaolo Bonzini if (name) { 200fd9400b3SPaolo Bonzini nc->name = g_strdup(name); 201fd9400b3SPaolo Bonzini } else { 202fd9400b3SPaolo Bonzini nc->name = assign_name(nc, model); 203fd9400b3SPaolo Bonzini } 204fd9400b3SPaolo Bonzini 205fd9400b3SPaolo Bonzini if (peer) { 206fd9400b3SPaolo Bonzini assert(!peer->peer); 207fd9400b3SPaolo Bonzini nc->peer = peer; 208fd9400b3SPaolo Bonzini peer->peer = nc; 209fd9400b3SPaolo Bonzini } 210fd9400b3SPaolo Bonzini QTAILQ_INSERT_TAIL(&net_clients, nc, next); 211fd9400b3SPaolo Bonzini 212fd9400b3SPaolo Bonzini nc->send_queue = qemu_new_net_queue(nc); 213f7860455SJason Wang nc->destructor = destructor; 21418a1541aSJason Wang } 21518a1541aSJason Wang 21618a1541aSJason Wang NetClientState *qemu_new_net_client(NetClientInfo *info, 21718a1541aSJason Wang NetClientState *peer, 21818a1541aSJason Wang const char *model, 21918a1541aSJason Wang const char *name) 22018a1541aSJason Wang { 22118a1541aSJason Wang NetClientState *nc; 22218a1541aSJason Wang 22318a1541aSJason Wang assert(info->size >= sizeof(NetClientState)); 22418a1541aSJason Wang 22518a1541aSJason Wang nc = g_malloc0(info->size); 226f7860455SJason Wang qemu_net_client_setup(nc, info, peer, model, name, 227f7860455SJason Wang qemu_net_client_destructor); 22818a1541aSJason Wang 229fd9400b3SPaolo Bonzini return nc; 230fd9400b3SPaolo Bonzini } 231fd9400b3SPaolo Bonzini 232fd9400b3SPaolo Bonzini NICState *qemu_new_nic(NetClientInfo *info, 233fd9400b3SPaolo Bonzini NICConf *conf, 234fd9400b3SPaolo Bonzini const char *model, 235fd9400b3SPaolo Bonzini const char *name, 236fd9400b3SPaolo Bonzini void *opaque) 237fd9400b3SPaolo Bonzini { 238fd9400b3SPaolo Bonzini NetClientState *nc; 239*1ceef9f2SJason Wang NetClientState **peers = conf->peers.ncs; 240fd9400b3SPaolo Bonzini NICState *nic; 241*1ceef9f2SJason Wang int i; 242fd9400b3SPaolo Bonzini 243fd9400b3SPaolo Bonzini assert(info->type == NET_CLIENT_OPTIONS_KIND_NIC); 244fd9400b3SPaolo Bonzini assert(info->size >= sizeof(NICState)); 245fd9400b3SPaolo Bonzini 246*1ceef9f2SJason Wang nc = qemu_new_net_client(info, peers[0], model, name); 247*1ceef9f2SJason Wang nc->queue_index = 0; 248fd9400b3SPaolo Bonzini 249cc1f0f45SJason Wang nic = qemu_get_nic(nc); 250fd9400b3SPaolo Bonzini nic->conf = conf; 251fd9400b3SPaolo Bonzini nic->opaque = opaque; 252fd9400b3SPaolo Bonzini 253*1ceef9f2SJason Wang for (i = 1; i < conf->queues; i++) { 254*1ceef9f2SJason Wang qemu_net_client_setup(&nic->ncs[i], info, peers[i], model, nc->name, 255*1ceef9f2SJason Wang NULL); 256*1ceef9f2SJason Wang nic->ncs[i].queue_index = i; 257*1ceef9f2SJason Wang } 258*1ceef9f2SJason Wang 259fd9400b3SPaolo Bonzini return nic; 260fd9400b3SPaolo Bonzini } 261fd9400b3SPaolo Bonzini 262*1ceef9f2SJason Wang NetClientState *qemu_get_subqueue(NICState *nic, int queue_index) 263*1ceef9f2SJason Wang { 264*1ceef9f2SJason Wang return &nic->ncs[queue_index]; 265*1ceef9f2SJason Wang } 266*1ceef9f2SJason Wang 267b356f76dSJason Wang NetClientState *qemu_get_queue(NICState *nic) 268b356f76dSJason Wang { 269*1ceef9f2SJason Wang return qemu_get_subqueue(nic, 0); 270b356f76dSJason Wang } 271b356f76dSJason Wang 272cc1f0f45SJason Wang NICState *qemu_get_nic(NetClientState *nc) 273cc1f0f45SJason Wang { 274*1ceef9f2SJason Wang NetClientState *nc0 = nc - nc->queue_index; 275*1ceef9f2SJason Wang 276*1ceef9f2SJason Wang return DO_UPCAST(NICState, ncs[0], nc0); 277cc1f0f45SJason Wang } 278cc1f0f45SJason Wang 279cc1f0f45SJason Wang void *qemu_get_nic_opaque(NetClientState *nc) 280cc1f0f45SJason Wang { 281cc1f0f45SJason Wang NICState *nic = qemu_get_nic(nc); 282cc1f0f45SJason Wang 283cc1f0f45SJason Wang return nic->opaque; 284cc1f0f45SJason Wang } 285cc1f0f45SJason Wang 286fd9400b3SPaolo Bonzini static void qemu_cleanup_net_client(NetClientState *nc) 287fd9400b3SPaolo Bonzini { 288fd9400b3SPaolo Bonzini QTAILQ_REMOVE(&net_clients, nc, next); 289fd9400b3SPaolo Bonzini 290fd9400b3SPaolo Bonzini nc->info->cleanup(nc); 291fd9400b3SPaolo Bonzini } 292fd9400b3SPaolo Bonzini 293fd9400b3SPaolo Bonzini static void qemu_free_net_client(NetClientState *nc) 294fd9400b3SPaolo Bonzini { 295fd9400b3SPaolo Bonzini if (nc->send_queue) { 296fd9400b3SPaolo Bonzini qemu_del_net_queue(nc->send_queue); 297fd9400b3SPaolo Bonzini } 298fd9400b3SPaolo Bonzini if (nc->peer) { 299fd9400b3SPaolo Bonzini nc->peer->peer = NULL; 300fd9400b3SPaolo Bonzini } 301fd9400b3SPaolo Bonzini g_free(nc->name); 302fd9400b3SPaolo Bonzini g_free(nc->model); 303f7860455SJason Wang if (nc->destructor) { 304f7860455SJason Wang nc->destructor(nc); 305f7860455SJason Wang } 306fd9400b3SPaolo Bonzini } 307fd9400b3SPaolo Bonzini 308fd9400b3SPaolo Bonzini void qemu_del_net_client(NetClientState *nc) 309fd9400b3SPaolo Bonzini { 310*1ceef9f2SJason Wang NetClientState *ncs[MAX_QUEUE_NUM]; 311*1ceef9f2SJason Wang int queues, i; 312*1ceef9f2SJason Wang 313*1ceef9f2SJason Wang /* If the NetClientState belongs to a multiqueue backend, we will change all 314*1ceef9f2SJason Wang * other NetClientStates also. 315*1ceef9f2SJason Wang */ 316*1ceef9f2SJason Wang queues = qemu_find_net_clients_except(nc->name, ncs, 317*1ceef9f2SJason Wang NET_CLIENT_OPTIONS_KIND_NIC, 318*1ceef9f2SJason Wang MAX_QUEUE_NUM); 319*1ceef9f2SJason Wang assert(queues != 0); 320*1ceef9f2SJason Wang 321fd9400b3SPaolo Bonzini /* If there is a peer NIC, delete and cleanup client, but do not free. */ 322fd9400b3SPaolo Bonzini if (nc->peer && nc->peer->info->type == NET_CLIENT_OPTIONS_KIND_NIC) { 323cc1f0f45SJason Wang NICState *nic = qemu_get_nic(nc->peer); 324fd9400b3SPaolo Bonzini if (nic->peer_deleted) { 325fd9400b3SPaolo Bonzini return; 326fd9400b3SPaolo Bonzini } 327fd9400b3SPaolo Bonzini nic->peer_deleted = true; 328*1ceef9f2SJason Wang 329*1ceef9f2SJason Wang for (i = 0; i < queues; i++) { 330*1ceef9f2SJason Wang ncs[i]->peer->link_down = true; 331*1ceef9f2SJason Wang } 332*1ceef9f2SJason Wang 333fd9400b3SPaolo Bonzini if (nc->peer->info->link_status_changed) { 334fd9400b3SPaolo Bonzini nc->peer->info->link_status_changed(nc->peer); 335fd9400b3SPaolo Bonzini } 336*1ceef9f2SJason Wang 337*1ceef9f2SJason Wang for (i = 0; i < queues; i++) { 338*1ceef9f2SJason Wang qemu_cleanup_net_client(ncs[i]); 339*1ceef9f2SJason Wang } 340*1ceef9f2SJason Wang 341fd9400b3SPaolo Bonzini return; 342fd9400b3SPaolo Bonzini } 343fd9400b3SPaolo Bonzini 344948ecf21SJason Wang assert(nc->info->type != NET_CLIENT_OPTIONS_KIND_NIC); 345948ecf21SJason Wang 346*1ceef9f2SJason Wang for (i = 0; i < queues; i++) { 347*1ceef9f2SJason Wang qemu_cleanup_net_client(ncs[i]); 348*1ceef9f2SJason Wang qemu_free_net_client(ncs[i]); 349*1ceef9f2SJason Wang } 350948ecf21SJason Wang } 351948ecf21SJason Wang 352948ecf21SJason Wang void qemu_del_nic(NICState *nic) 353948ecf21SJason Wang { 354*1ceef9f2SJason Wang int i, queues = nic->conf->queues; 355*1ceef9f2SJason Wang 356fd9400b3SPaolo Bonzini /* If this is a peer NIC and peer has already been deleted, free it now. */ 357fd9400b3SPaolo Bonzini if (nic->peer_deleted) { 358*1ceef9f2SJason Wang for (i = 0; i < queues; i++) { 359*1ceef9f2SJason Wang qemu_free_net_client(qemu_get_subqueue(nic, i)->peer); 360fd9400b3SPaolo Bonzini } 361fd9400b3SPaolo Bonzini } 362fd9400b3SPaolo Bonzini 363*1ceef9f2SJason Wang for (i = queues - 1; i >= 0; i--) { 364*1ceef9f2SJason Wang NetClientState *nc = qemu_get_subqueue(nic, i); 365*1ceef9f2SJason Wang 366fd9400b3SPaolo Bonzini qemu_cleanup_net_client(nc); 367fd9400b3SPaolo Bonzini qemu_free_net_client(nc); 368fd9400b3SPaolo Bonzini } 369*1ceef9f2SJason Wang } 370fd9400b3SPaolo Bonzini 371fd9400b3SPaolo Bonzini void qemu_foreach_nic(qemu_nic_foreach func, void *opaque) 372fd9400b3SPaolo Bonzini { 373fd9400b3SPaolo Bonzini NetClientState *nc; 374fd9400b3SPaolo Bonzini 375fd9400b3SPaolo Bonzini QTAILQ_FOREACH(nc, &net_clients, next) { 376fd9400b3SPaolo Bonzini if (nc->info->type == NET_CLIENT_OPTIONS_KIND_NIC) { 377*1ceef9f2SJason Wang if (nc->queue_index == 0) { 378cc1f0f45SJason Wang func(qemu_get_nic(nc), opaque); 379fd9400b3SPaolo Bonzini } 380fd9400b3SPaolo Bonzini } 381fd9400b3SPaolo Bonzini } 382*1ceef9f2SJason Wang } 383fd9400b3SPaolo Bonzini 384fd9400b3SPaolo Bonzini int qemu_can_send_packet(NetClientState *sender) 385fd9400b3SPaolo Bonzini { 386fd9400b3SPaolo Bonzini if (!sender->peer) { 387fd9400b3SPaolo Bonzini return 1; 388fd9400b3SPaolo Bonzini } 389fd9400b3SPaolo Bonzini 390fd9400b3SPaolo Bonzini if (sender->peer->receive_disabled) { 391fd9400b3SPaolo Bonzini return 0; 392fd9400b3SPaolo Bonzini } else if (sender->peer->info->can_receive && 393fd9400b3SPaolo Bonzini !sender->peer->info->can_receive(sender->peer)) { 394fd9400b3SPaolo Bonzini return 0; 395fd9400b3SPaolo Bonzini } 396fd9400b3SPaolo Bonzini return 1; 397fd9400b3SPaolo Bonzini } 398fd9400b3SPaolo Bonzini 399fd9400b3SPaolo Bonzini ssize_t qemu_deliver_packet(NetClientState *sender, 400fd9400b3SPaolo Bonzini unsigned flags, 401fd9400b3SPaolo Bonzini const uint8_t *data, 402fd9400b3SPaolo Bonzini size_t size, 403fd9400b3SPaolo Bonzini void *opaque) 404fd9400b3SPaolo Bonzini { 405fd9400b3SPaolo Bonzini NetClientState *nc = opaque; 406fd9400b3SPaolo Bonzini ssize_t ret; 407fd9400b3SPaolo Bonzini 408fd9400b3SPaolo Bonzini if (nc->link_down) { 409fd9400b3SPaolo Bonzini return size; 410fd9400b3SPaolo Bonzini } 411fd9400b3SPaolo Bonzini 412fd9400b3SPaolo Bonzini if (nc->receive_disabled) { 413fd9400b3SPaolo Bonzini return 0; 414fd9400b3SPaolo Bonzini } 415fd9400b3SPaolo Bonzini 416fd9400b3SPaolo Bonzini if (flags & QEMU_NET_PACKET_FLAG_RAW && nc->info->receive_raw) { 417fd9400b3SPaolo Bonzini ret = nc->info->receive_raw(nc, data, size); 418fd9400b3SPaolo Bonzini } else { 419fd9400b3SPaolo Bonzini ret = nc->info->receive(nc, data, size); 420fd9400b3SPaolo Bonzini } 421fd9400b3SPaolo Bonzini 422fd9400b3SPaolo Bonzini if (ret == 0) { 423fd9400b3SPaolo Bonzini nc->receive_disabled = 1; 424fd9400b3SPaolo Bonzini }; 425fd9400b3SPaolo Bonzini 426fd9400b3SPaolo Bonzini return ret; 427fd9400b3SPaolo Bonzini } 428fd9400b3SPaolo Bonzini 429fd9400b3SPaolo Bonzini void qemu_purge_queued_packets(NetClientState *nc) 430fd9400b3SPaolo Bonzini { 431fd9400b3SPaolo Bonzini if (!nc->peer) { 432fd9400b3SPaolo Bonzini return; 433fd9400b3SPaolo Bonzini } 434fd9400b3SPaolo Bonzini 435fd9400b3SPaolo Bonzini qemu_net_queue_purge(nc->peer->send_queue, nc); 436fd9400b3SPaolo Bonzini } 437fd9400b3SPaolo Bonzini 438fd9400b3SPaolo Bonzini void qemu_flush_queued_packets(NetClientState *nc) 439fd9400b3SPaolo Bonzini { 440fd9400b3SPaolo Bonzini nc->receive_disabled = 0; 441fd9400b3SPaolo Bonzini 442fd9400b3SPaolo Bonzini if (qemu_net_queue_flush(nc->send_queue)) { 443fd9400b3SPaolo Bonzini /* We emptied the queue successfully, signal to the IO thread to repoll 444fd9400b3SPaolo Bonzini * the file descriptor (for tap, for example). 445fd9400b3SPaolo Bonzini */ 446fd9400b3SPaolo Bonzini qemu_notify_event(); 447fd9400b3SPaolo Bonzini } 448fd9400b3SPaolo Bonzini } 449fd9400b3SPaolo Bonzini 450fd9400b3SPaolo Bonzini static ssize_t qemu_send_packet_async_with_flags(NetClientState *sender, 451fd9400b3SPaolo Bonzini unsigned flags, 452fd9400b3SPaolo Bonzini const uint8_t *buf, int size, 453fd9400b3SPaolo Bonzini NetPacketSent *sent_cb) 454fd9400b3SPaolo Bonzini { 455fd9400b3SPaolo Bonzini NetQueue *queue; 456fd9400b3SPaolo Bonzini 457fd9400b3SPaolo Bonzini #ifdef DEBUG_NET 458fd9400b3SPaolo Bonzini printf("qemu_send_packet_async:\n"); 459fd9400b3SPaolo Bonzini hex_dump(stdout, buf, size); 460fd9400b3SPaolo Bonzini #endif 461fd9400b3SPaolo Bonzini 462fd9400b3SPaolo Bonzini if (sender->link_down || !sender->peer) { 463fd9400b3SPaolo Bonzini return size; 464fd9400b3SPaolo Bonzini } 465fd9400b3SPaolo Bonzini 466fd9400b3SPaolo Bonzini queue = sender->peer->send_queue; 467fd9400b3SPaolo Bonzini 468fd9400b3SPaolo Bonzini return qemu_net_queue_send(queue, sender, flags, buf, size, sent_cb); 469fd9400b3SPaolo Bonzini } 470fd9400b3SPaolo Bonzini 471fd9400b3SPaolo Bonzini ssize_t qemu_send_packet_async(NetClientState *sender, 472fd9400b3SPaolo Bonzini const uint8_t *buf, int size, 473fd9400b3SPaolo Bonzini NetPacketSent *sent_cb) 474fd9400b3SPaolo Bonzini { 475fd9400b3SPaolo Bonzini return qemu_send_packet_async_with_flags(sender, QEMU_NET_PACKET_FLAG_NONE, 476fd9400b3SPaolo Bonzini buf, size, sent_cb); 477fd9400b3SPaolo Bonzini } 478fd9400b3SPaolo Bonzini 479fd9400b3SPaolo Bonzini void qemu_send_packet(NetClientState *nc, const uint8_t *buf, int size) 480fd9400b3SPaolo Bonzini { 481fd9400b3SPaolo Bonzini qemu_send_packet_async(nc, buf, size, NULL); 482fd9400b3SPaolo Bonzini } 483fd9400b3SPaolo Bonzini 484fd9400b3SPaolo Bonzini ssize_t qemu_send_packet_raw(NetClientState *nc, const uint8_t *buf, int size) 485fd9400b3SPaolo Bonzini { 486fd9400b3SPaolo Bonzini return qemu_send_packet_async_with_flags(nc, QEMU_NET_PACKET_FLAG_RAW, 487fd9400b3SPaolo Bonzini buf, size, NULL); 488fd9400b3SPaolo Bonzini } 489fd9400b3SPaolo Bonzini 490fd9400b3SPaolo Bonzini static ssize_t nc_sendv_compat(NetClientState *nc, const struct iovec *iov, 491fd9400b3SPaolo Bonzini int iovcnt) 492fd9400b3SPaolo Bonzini { 493fd9400b3SPaolo Bonzini uint8_t buffer[4096]; 494fd9400b3SPaolo Bonzini size_t offset; 495fd9400b3SPaolo Bonzini 496fd9400b3SPaolo Bonzini offset = iov_to_buf(iov, iovcnt, 0, buffer, sizeof(buffer)); 497fd9400b3SPaolo Bonzini 498fd9400b3SPaolo Bonzini return nc->info->receive(nc, buffer, offset); 499fd9400b3SPaolo Bonzini } 500fd9400b3SPaolo Bonzini 501fd9400b3SPaolo Bonzini ssize_t qemu_deliver_packet_iov(NetClientState *sender, 502fd9400b3SPaolo Bonzini unsigned flags, 503fd9400b3SPaolo Bonzini const struct iovec *iov, 504fd9400b3SPaolo Bonzini int iovcnt, 505fd9400b3SPaolo Bonzini void *opaque) 506fd9400b3SPaolo Bonzini { 507fd9400b3SPaolo Bonzini NetClientState *nc = opaque; 508fd9400b3SPaolo Bonzini int ret; 509fd9400b3SPaolo Bonzini 510fd9400b3SPaolo Bonzini if (nc->link_down) { 511fd9400b3SPaolo Bonzini return iov_size(iov, iovcnt); 512fd9400b3SPaolo Bonzini } 513fd9400b3SPaolo Bonzini 514fd9400b3SPaolo Bonzini if (nc->receive_disabled) { 515fd9400b3SPaolo Bonzini return 0; 516fd9400b3SPaolo Bonzini } 517fd9400b3SPaolo Bonzini 518fd9400b3SPaolo Bonzini if (nc->info->receive_iov) { 519fd9400b3SPaolo Bonzini ret = nc->info->receive_iov(nc, iov, iovcnt); 520fd9400b3SPaolo Bonzini } else { 521fd9400b3SPaolo Bonzini ret = nc_sendv_compat(nc, iov, iovcnt); 522fd9400b3SPaolo Bonzini } 523fd9400b3SPaolo Bonzini 524fd9400b3SPaolo Bonzini if (ret == 0) { 525fd9400b3SPaolo Bonzini nc->receive_disabled = 1; 526fd9400b3SPaolo Bonzini } 527fd9400b3SPaolo Bonzini 528fd9400b3SPaolo Bonzini return ret; 529fd9400b3SPaolo Bonzini } 530fd9400b3SPaolo Bonzini 531fd9400b3SPaolo Bonzini ssize_t qemu_sendv_packet_async(NetClientState *sender, 532fd9400b3SPaolo Bonzini const struct iovec *iov, int iovcnt, 533fd9400b3SPaolo Bonzini NetPacketSent *sent_cb) 534fd9400b3SPaolo Bonzini { 535fd9400b3SPaolo Bonzini NetQueue *queue; 536fd9400b3SPaolo Bonzini 537fd9400b3SPaolo Bonzini if (sender->link_down || !sender->peer) { 538fd9400b3SPaolo Bonzini return iov_size(iov, iovcnt); 539fd9400b3SPaolo Bonzini } 540fd9400b3SPaolo Bonzini 541fd9400b3SPaolo Bonzini queue = sender->peer->send_queue; 542fd9400b3SPaolo Bonzini 543fd9400b3SPaolo Bonzini return qemu_net_queue_send_iov(queue, sender, 544fd9400b3SPaolo Bonzini QEMU_NET_PACKET_FLAG_NONE, 545fd9400b3SPaolo Bonzini iov, iovcnt, sent_cb); 546fd9400b3SPaolo Bonzini } 547fd9400b3SPaolo Bonzini 548fd9400b3SPaolo Bonzini ssize_t 549fd9400b3SPaolo Bonzini qemu_sendv_packet(NetClientState *nc, const struct iovec *iov, int iovcnt) 550fd9400b3SPaolo Bonzini { 551fd9400b3SPaolo Bonzini return qemu_sendv_packet_async(nc, iov, iovcnt, NULL); 552fd9400b3SPaolo Bonzini } 553fd9400b3SPaolo Bonzini 554fd9400b3SPaolo Bonzini NetClientState *qemu_find_netdev(const char *id) 555fd9400b3SPaolo Bonzini { 556fd9400b3SPaolo Bonzini NetClientState *nc; 557fd9400b3SPaolo Bonzini 558fd9400b3SPaolo Bonzini QTAILQ_FOREACH(nc, &net_clients, next) { 559fd9400b3SPaolo Bonzini if (nc->info->type == NET_CLIENT_OPTIONS_KIND_NIC) 560fd9400b3SPaolo Bonzini continue; 561fd9400b3SPaolo Bonzini if (!strcmp(nc->name, id)) { 562fd9400b3SPaolo Bonzini return nc; 563fd9400b3SPaolo Bonzini } 564fd9400b3SPaolo Bonzini } 565fd9400b3SPaolo Bonzini 566fd9400b3SPaolo Bonzini return NULL; 567fd9400b3SPaolo Bonzini } 568fd9400b3SPaolo Bonzini 5696c51ae73SJason Wang int qemu_find_net_clients_except(const char *id, NetClientState **ncs, 5706c51ae73SJason Wang NetClientOptionsKind type, int max) 5716c51ae73SJason Wang { 5726c51ae73SJason Wang NetClientState *nc; 5736c51ae73SJason Wang int ret = 0; 5746c51ae73SJason Wang 5756c51ae73SJason Wang QTAILQ_FOREACH(nc, &net_clients, next) { 5766c51ae73SJason Wang if (nc->info->type == type) { 5776c51ae73SJason Wang continue; 5786c51ae73SJason Wang } 5796c51ae73SJason Wang if (!strcmp(nc->name, id)) { 5806c51ae73SJason Wang if (ret < max) { 5816c51ae73SJason Wang ncs[ret] = nc; 5826c51ae73SJason Wang } 5836c51ae73SJason Wang ret++; 5846c51ae73SJason Wang } 5856c51ae73SJason Wang } 5866c51ae73SJason Wang 5876c51ae73SJason Wang return ret; 5886c51ae73SJason Wang } 5896c51ae73SJason Wang 590fd9400b3SPaolo Bonzini static int nic_get_free_idx(void) 591fd9400b3SPaolo Bonzini { 592fd9400b3SPaolo Bonzini int index; 593fd9400b3SPaolo Bonzini 594fd9400b3SPaolo Bonzini for (index = 0; index < MAX_NICS; index++) 595fd9400b3SPaolo Bonzini if (!nd_table[index].used) 596fd9400b3SPaolo Bonzini return index; 597fd9400b3SPaolo Bonzini return -1; 598fd9400b3SPaolo Bonzini } 599fd9400b3SPaolo Bonzini 600fd9400b3SPaolo Bonzini int qemu_show_nic_models(const char *arg, const char *const *models) 601fd9400b3SPaolo Bonzini { 602fd9400b3SPaolo Bonzini int i; 603fd9400b3SPaolo Bonzini 604fd9400b3SPaolo Bonzini if (!arg || !is_help_option(arg)) { 605fd9400b3SPaolo Bonzini return 0; 606fd9400b3SPaolo Bonzini } 607fd9400b3SPaolo Bonzini 608fd9400b3SPaolo Bonzini fprintf(stderr, "qemu: Supported NIC models: "); 609fd9400b3SPaolo Bonzini for (i = 0 ; models[i]; i++) 610fd9400b3SPaolo Bonzini fprintf(stderr, "%s%c", models[i], models[i+1] ? ',' : '\n'); 611fd9400b3SPaolo Bonzini return 1; 612fd9400b3SPaolo Bonzini } 613fd9400b3SPaolo Bonzini 614fd9400b3SPaolo Bonzini void qemu_check_nic_model(NICInfo *nd, const char *model) 615fd9400b3SPaolo Bonzini { 616fd9400b3SPaolo Bonzini const char *models[2]; 617fd9400b3SPaolo Bonzini 618fd9400b3SPaolo Bonzini models[0] = model; 619fd9400b3SPaolo Bonzini models[1] = NULL; 620fd9400b3SPaolo Bonzini 621fd9400b3SPaolo Bonzini if (qemu_show_nic_models(nd->model, models)) 622fd9400b3SPaolo Bonzini exit(0); 623fd9400b3SPaolo Bonzini if (qemu_find_nic_model(nd, models, model) < 0) 624fd9400b3SPaolo Bonzini exit(1); 625fd9400b3SPaolo Bonzini } 626fd9400b3SPaolo Bonzini 627fd9400b3SPaolo Bonzini int qemu_find_nic_model(NICInfo *nd, const char * const *models, 628fd9400b3SPaolo Bonzini const char *default_model) 629fd9400b3SPaolo Bonzini { 630fd9400b3SPaolo Bonzini int i; 631fd9400b3SPaolo Bonzini 632fd9400b3SPaolo Bonzini if (!nd->model) 633fd9400b3SPaolo Bonzini nd->model = g_strdup(default_model); 634fd9400b3SPaolo Bonzini 635fd9400b3SPaolo Bonzini for (i = 0 ; models[i]; i++) { 636fd9400b3SPaolo Bonzini if (strcmp(nd->model, models[i]) == 0) 637fd9400b3SPaolo Bonzini return i; 638fd9400b3SPaolo Bonzini } 639fd9400b3SPaolo Bonzini 640fd9400b3SPaolo Bonzini error_report("Unsupported NIC model: %s", nd->model); 641fd9400b3SPaolo Bonzini return -1; 642fd9400b3SPaolo Bonzini } 643fd9400b3SPaolo Bonzini 644fd9400b3SPaolo Bonzini static int net_init_nic(const NetClientOptions *opts, const char *name, 645fd9400b3SPaolo Bonzini NetClientState *peer) 646fd9400b3SPaolo Bonzini { 647fd9400b3SPaolo Bonzini int idx; 648fd9400b3SPaolo Bonzini NICInfo *nd; 649fd9400b3SPaolo Bonzini const NetLegacyNicOptions *nic; 650fd9400b3SPaolo Bonzini 651fd9400b3SPaolo Bonzini assert(opts->kind == NET_CLIENT_OPTIONS_KIND_NIC); 652fd9400b3SPaolo Bonzini nic = opts->nic; 653fd9400b3SPaolo Bonzini 654fd9400b3SPaolo Bonzini idx = nic_get_free_idx(); 655fd9400b3SPaolo Bonzini if (idx == -1 || nb_nics >= MAX_NICS) { 656fd9400b3SPaolo Bonzini error_report("Too Many NICs"); 657fd9400b3SPaolo Bonzini return -1; 658fd9400b3SPaolo Bonzini } 659fd9400b3SPaolo Bonzini 660fd9400b3SPaolo Bonzini nd = &nd_table[idx]; 661fd9400b3SPaolo Bonzini 662fd9400b3SPaolo Bonzini memset(nd, 0, sizeof(*nd)); 663fd9400b3SPaolo Bonzini 664fd9400b3SPaolo Bonzini if (nic->has_netdev) { 665fd9400b3SPaolo Bonzini nd->netdev = qemu_find_netdev(nic->netdev); 666fd9400b3SPaolo Bonzini if (!nd->netdev) { 667fd9400b3SPaolo Bonzini error_report("netdev '%s' not found", nic->netdev); 668fd9400b3SPaolo Bonzini return -1; 669fd9400b3SPaolo Bonzini } 670fd9400b3SPaolo Bonzini } else { 671fd9400b3SPaolo Bonzini assert(peer); 672fd9400b3SPaolo Bonzini nd->netdev = peer; 673fd9400b3SPaolo Bonzini } 674fd9400b3SPaolo Bonzini nd->name = g_strdup(name); 675fd9400b3SPaolo Bonzini if (nic->has_model) { 676fd9400b3SPaolo Bonzini nd->model = g_strdup(nic->model); 677fd9400b3SPaolo Bonzini } 678fd9400b3SPaolo Bonzini if (nic->has_addr) { 679fd9400b3SPaolo Bonzini nd->devaddr = g_strdup(nic->addr); 680fd9400b3SPaolo Bonzini } 681fd9400b3SPaolo Bonzini 682fd9400b3SPaolo Bonzini if (nic->has_macaddr && 683fd9400b3SPaolo Bonzini net_parse_macaddr(nd->macaddr.a, nic->macaddr) < 0) { 684fd9400b3SPaolo Bonzini error_report("invalid syntax for ethernet address"); 685fd9400b3SPaolo Bonzini return -1; 686fd9400b3SPaolo Bonzini } 687fd9400b3SPaolo Bonzini qemu_macaddr_default_if_unset(&nd->macaddr); 688fd9400b3SPaolo Bonzini 689fd9400b3SPaolo Bonzini if (nic->has_vectors) { 690fd9400b3SPaolo Bonzini if (nic->vectors > 0x7ffffff) { 691fd9400b3SPaolo Bonzini error_report("invalid # of vectors: %"PRIu32, nic->vectors); 692fd9400b3SPaolo Bonzini return -1; 693fd9400b3SPaolo Bonzini } 694fd9400b3SPaolo Bonzini nd->nvectors = nic->vectors; 695fd9400b3SPaolo Bonzini } else { 696fd9400b3SPaolo Bonzini nd->nvectors = DEV_NVECTORS_UNSPECIFIED; 697fd9400b3SPaolo Bonzini } 698fd9400b3SPaolo Bonzini 699fd9400b3SPaolo Bonzini nd->used = 1; 700fd9400b3SPaolo Bonzini nb_nics++; 701fd9400b3SPaolo Bonzini 702fd9400b3SPaolo Bonzini return idx; 703fd9400b3SPaolo Bonzini } 704fd9400b3SPaolo Bonzini 705fd9400b3SPaolo Bonzini 706fd9400b3SPaolo Bonzini static int (* const net_client_init_fun[NET_CLIENT_OPTIONS_KIND_MAX])( 707fd9400b3SPaolo Bonzini const NetClientOptions *opts, 708fd9400b3SPaolo Bonzini const char *name, 709fd9400b3SPaolo Bonzini NetClientState *peer) = { 710fd9400b3SPaolo Bonzini [NET_CLIENT_OPTIONS_KIND_NIC] = net_init_nic, 711fd9400b3SPaolo Bonzini #ifdef CONFIG_SLIRP 712fd9400b3SPaolo Bonzini [NET_CLIENT_OPTIONS_KIND_USER] = net_init_slirp, 713fd9400b3SPaolo Bonzini #endif 714fd9400b3SPaolo Bonzini [NET_CLIENT_OPTIONS_KIND_TAP] = net_init_tap, 715fd9400b3SPaolo Bonzini [NET_CLIENT_OPTIONS_KIND_SOCKET] = net_init_socket, 716fd9400b3SPaolo Bonzini #ifdef CONFIG_VDE 717fd9400b3SPaolo Bonzini [NET_CLIENT_OPTIONS_KIND_VDE] = net_init_vde, 718fd9400b3SPaolo Bonzini #endif 719fd9400b3SPaolo Bonzini [NET_CLIENT_OPTIONS_KIND_DUMP] = net_init_dump, 720fd9400b3SPaolo Bonzini #ifdef CONFIG_NET_BRIDGE 721fd9400b3SPaolo Bonzini [NET_CLIENT_OPTIONS_KIND_BRIDGE] = net_init_bridge, 722fd9400b3SPaolo Bonzini #endif 723fd9400b3SPaolo Bonzini [NET_CLIENT_OPTIONS_KIND_HUBPORT] = net_init_hubport, 724fd9400b3SPaolo Bonzini }; 725fd9400b3SPaolo Bonzini 726fd9400b3SPaolo Bonzini 727fd9400b3SPaolo Bonzini static int net_client_init1(const void *object, int is_netdev, Error **errp) 728fd9400b3SPaolo Bonzini { 729fd9400b3SPaolo Bonzini union { 730fd9400b3SPaolo Bonzini const Netdev *netdev; 731fd9400b3SPaolo Bonzini const NetLegacy *net; 732fd9400b3SPaolo Bonzini } u; 733fd9400b3SPaolo Bonzini const NetClientOptions *opts; 734fd9400b3SPaolo Bonzini const char *name; 735fd9400b3SPaolo Bonzini 736fd9400b3SPaolo Bonzini if (is_netdev) { 737fd9400b3SPaolo Bonzini u.netdev = object; 738fd9400b3SPaolo Bonzini opts = u.netdev->opts; 739fd9400b3SPaolo Bonzini name = u.netdev->id; 740fd9400b3SPaolo Bonzini 741fd9400b3SPaolo Bonzini switch (opts->kind) { 742fd9400b3SPaolo Bonzini #ifdef CONFIG_SLIRP 743fd9400b3SPaolo Bonzini case NET_CLIENT_OPTIONS_KIND_USER: 744fd9400b3SPaolo Bonzini #endif 745fd9400b3SPaolo Bonzini case NET_CLIENT_OPTIONS_KIND_TAP: 746fd9400b3SPaolo Bonzini case NET_CLIENT_OPTIONS_KIND_SOCKET: 747fd9400b3SPaolo Bonzini #ifdef CONFIG_VDE 748fd9400b3SPaolo Bonzini case NET_CLIENT_OPTIONS_KIND_VDE: 749fd9400b3SPaolo Bonzini #endif 750fd9400b3SPaolo Bonzini #ifdef CONFIG_NET_BRIDGE 751fd9400b3SPaolo Bonzini case NET_CLIENT_OPTIONS_KIND_BRIDGE: 752fd9400b3SPaolo Bonzini #endif 753fd9400b3SPaolo Bonzini case NET_CLIENT_OPTIONS_KIND_HUBPORT: 754fd9400b3SPaolo Bonzini break; 755fd9400b3SPaolo Bonzini 756fd9400b3SPaolo Bonzini default: 757fd9400b3SPaolo Bonzini error_set(errp, QERR_INVALID_PARAMETER_VALUE, "type", 758fd9400b3SPaolo Bonzini "a netdev backend type"); 759fd9400b3SPaolo Bonzini return -1; 760fd9400b3SPaolo Bonzini } 761fd9400b3SPaolo Bonzini } else { 762fd9400b3SPaolo Bonzini u.net = object; 763fd9400b3SPaolo Bonzini opts = u.net->opts; 764fd9400b3SPaolo Bonzini /* missing optional values have been initialized to "all bits zero" */ 765fd9400b3SPaolo Bonzini name = u.net->has_id ? u.net->id : u.net->name; 766fd9400b3SPaolo Bonzini } 767fd9400b3SPaolo Bonzini 768fd9400b3SPaolo Bonzini if (net_client_init_fun[opts->kind]) { 769fd9400b3SPaolo Bonzini NetClientState *peer = NULL; 770fd9400b3SPaolo Bonzini 771fd9400b3SPaolo Bonzini /* Do not add to a vlan if it's a -netdev or a nic with a netdev= 772fd9400b3SPaolo Bonzini * parameter. */ 773fd9400b3SPaolo Bonzini if (!is_netdev && 774fd9400b3SPaolo Bonzini (opts->kind != NET_CLIENT_OPTIONS_KIND_NIC || 775fd9400b3SPaolo Bonzini !opts->nic->has_netdev)) { 776fd9400b3SPaolo Bonzini peer = net_hub_add_port(u.net->has_vlan ? u.net->vlan : 0, NULL); 777fd9400b3SPaolo Bonzini } 778fd9400b3SPaolo Bonzini 779fd9400b3SPaolo Bonzini if (net_client_init_fun[opts->kind](opts, name, peer) < 0) { 780fd9400b3SPaolo Bonzini /* TODO push error reporting into init() methods */ 781fd9400b3SPaolo Bonzini error_set(errp, QERR_DEVICE_INIT_FAILED, 782fd9400b3SPaolo Bonzini NetClientOptionsKind_lookup[opts->kind]); 783fd9400b3SPaolo Bonzini return -1; 784fd9400b3SPaolo Bonzini } 785fd9400b3SPaolo Bonzini } 786fd9400b3SPaolo Bonzini return 0; 787fd9400b3SPaolo Bonzini } 788fd9400b3SPaolo Bonzini 789fd9400b3SPaolo Bonzini 790fd9400b3SPaolo Bonzini static void net_visit(Visitor *v, int is_netdev, void **object, Error **errp) 791fd9400b3SPaolo Bonzini { 792fd9400b3SPaolo Bonzini if (is_netdev) { 793fd9400b3SPaolo Bonzini visit_type_Netdev(v, (Netdev **)object, NULL, errp); 794fd9400b3SPaolo Bonzini } else { 795fd9400b3SPaolo Bonzini visit_type_NetLegacy(v, (NetLegacy **)object, NULL, errp); 796fd9400b3SPaolo Bonzini } 797fd9400b3SPaolo Bonzini } 798fd9400b3SPaolo Bonzini 799fd9400b3SPaolo Bonzini 800fd9400b3SPaolo Bonzini int net_client_init(QemuOpts *opts, int is_netdev, Error **errp) 801fd9400b3SPaolo Bonzini { 802fd9400b3SPaolo Bonzini void *object = NULL; 803fd9400b3SPaolo Bonzini Error *err = NULL; 804fd9400b3SPaolo Bonzini int ret = -1; 805fd9400b3SPaolo Bonzini 806fd9400b3SPaolo Bonzini { 807fd9400b3SPaolo Bonzini OptsVisitor *ov = opts_visitor_new(opts); 808fd9400b3SPaolo Bonzini 809fd9400b3SPaolo Bonzini net_visit(opts_get_visitor(ov), is_netdev, &object, &err); 810fd9400b3SPaolo Bonzini opts_visitor_cleanup(ov); 811fd9400b3SPaolo Bonzini } 812fd9400b3SPaolo Bonzini 813fd9400b3SPaolo Bonzini if (!err) { 814fd9400b3SPaolo Bonzini ret = net_client_init1(object, is_netdev, &err); 815fd9400b3SPaolo Bonzini } 816fd9400b3SPaolo Bonzini 817fd9400b3SPaolo Bonzini if (object) { 818fd9400b3SPaolo Bonzini QapiDeallocVisitor *dv = qapi_dealloc_visitor_new(); 819fd9400b3SPaolo Bonzini 820fd9400b3SPaolo Bonzini net_visit(qapi_dealloc_get_visitor(dv), is_netdev, &object, NULL); 821fd9400b3SPaolo Bonzini qapi_dealloc_visitor_cleanup(dv); 822fd9400b3SPaolo Bonzini } 823fd9400b3SPaolo Bonzini 824fd9400b3SPaolo Bonzini error_propagate(errp, err); 825fd9400b3SPaolo Bonzini return ret; 826fd9400b3SPaolo Bonzini } 827fd9400b3SPaolo Bonzini 828fd9400b3SPaolo Bonzini 829fd9400b3SPaolo Bonzini static int net_host_check_device(const char *device) 830fd9400b3SPaolo Bonzini { 831fd9400b3SPaolo Bonzini int i; 832fd9400b3SPaolo Bonzini const char *valid_param_list[] = { "tap", "socket", "dump" 833fd9400b3SPaolo Bonzini #ifdef CONFIG_NET_BRIDGE 834fd9400b3SPaolo Bonzini , "bridge" 835fd9400b3SPaolo Bonzini #endif 836fd9400b3SPaolo Bonzini #ifdef CONFIG_SLIRP 837fd9400b3SPaolo Bonzini ,"user" 838fd9400b3SPaolo Bonzini #endif 839fd9400b3SPaolo Bonzini #ifdef CONFIG_VDE 840fd9400b3SPaolo Bonzini ,"vde" 841fd9400b3SPaolo Bonzini #endif 842fd9400b3SPaolo Bonzini }; 843fd9400b3SPaolo Bonzini for (i = 0; i < sizeof(valid_param_list) / sizeof(char *); i++) { 844fd9400b3SPaolo Bonzini if (!strncmp(valid_param_list[i], device, 845fd9400b3SPaolo Bonzini strlen(valid_param_list[i]))) 846fd9400b3SPaolo Bonzini return 1; 847fd9400b3SPaolo Bonzini } 848fd9400b3SPaolo Bonzini 849fd9400b3SPaolo Bonzini return 0; 850fd9400b3SPaolo Bonzini } 851fd9400b3SPaolo Bonzini 852fd9400b3SPaolo Bonzini void net_host_device_add(Monitor *mon, const QDict *qdict) 853fd9400b3SPaolo Bonzini { 854fd9400b3SPaolo Bonzini const char *device = qdict_get_str(qdict, "device"); 855fd9400b3SPaolo Bonzini const char *opts_str = qdict_get_try_str(qdict, "opts"); 856fd9400b3SPaolo Bonzini Error *local_err = NULL; 857fd9400b3SPaolo Bonzini QemuOpts *opts; 858fd9400b3SPaolo Bonzini 859fd9400b3SPaolo Bonzini if (!net_host_check_device(device)) { 860fd9400b3SPaolo Bonzini monitor_printf(mon, "invalid host network device %s\n", device); 861fd9400b3SPaolo Bonzini return; 862fd9400b3SPaolo Bonzini } 863fd9400b3SPaolo Bonzini 864fd9400b3SPaolo Bonzini opts = qemu_opts_parse(qemu_find_opts("net"), opts_str ? opts_str : "", 0); 865fd9400b3SPaolo Bonzini if (!opts) { 866fd9400b3SPaolo Bonzini return; 867fd9400b3SPaolo Bonzini } 868fd9400b3SPaolo Bonzini 869fd9400b3SPaolo Bonzini qemu_opt_set(opts, "type", device); 870fd9400b3SPaolo Bonzini 871fd9400b3SPaolo Bonzini net_client_init(opts, 0, &local_err); 872fd9400b3SPaolo Bonzini if (error_is_set(&local_err)) { 873fd9400b3SPaolo Bonzini qerror_report_err(local_err); 874fd9400b3SPaolo Bonzini error_free(local_err); 875fd9400b3SPaolo Bonzini monitor_printf(mon, "adding host network device %s failed\n", device); 876fd9400b3SPaolo Bonzini } 877fd9400b3SPaolo Bonzini } 878fd9400b3SPaolo Bonzini 879fd9400b3SPaolo Bonzini void net_host_device_remove(Monitor *mon, const QDict *qdict) 880fd9400b3SPaolo Bonzini { 881fd9400b3SPaolo Bonzini NetClientState *nc; 882fd9400b3SPaolo Bonzini int vlan_id = qdict_get_int(qdict, "vlan_id"); 883fd9400b3SPaolo Bonzini const char *device = qdict_get_str(qdict, "device"); 884fd9400b3SPaolo Bonzini 885fd9400b3SPaolo Bonzini nc = net_hub_find_client_by_name(vlan_id, device); 886fd9400b3SPaolo Bonzini if (!nc) { 887fd9400b3SPaolo Bonzini return; 888fd9400b3SPaolo Bonzini } 889fd9400b3SPaolo Bonzini if (!net_host_check_device(nc->model)) { 890fd9400b3SPaolo Bonzini monitor_printf(mon, "invalid host network device %s\n", device); 891fd9400b3SPaolo Bonzini return; 892fd9400b3SPaolo Bonzini } 893fd9400b3SPaolo Bonzini qemu_del_net_client(nc); 894fd9400b3SPaolo Bonzini } 895fd9400b3SPaolo Bonzini 896fd9400b3SPaolo Bonzini void netdev_add(QemuOpts *opts, Error **errp) 897fd9400b3SPaolo Bonzini { 898fd9400b3SPaolo Bonzini net_client_init(opts, 1, errp); 899fd9400b3SPaolo Bonzini } 900fd9400b3SPaolo Bonzini 901fd9400b3SPaolo Bonzini int qmp_netdev_add(Monitor *mon, const QDict *qdict, QObject **ret) 902fd9400b3SPaolo Bonzini { 903fd9400b3SPaolo Bonzini Error *local_err = NULL; 904fd9400b3SPaolo Bonzini QemuOptsList *opts_list; 905fd9400b3SPaolo Bonzini QemuOpts *opts; 906fd9400b3SPaolo Bonzini 907fd9400b3SPaolo Bonzini opts_list = qemu_find_opts_err("netdev", &local_err); 908fd9400b3SPaolo Bonzini if (error_is_set(&local_err)) { 909fd9400b3SPaolo Bonzini goto exit_err; 910fd9400b3SPaolo Bonzini } 911fd9400b3SPaolo Bonzini 912fd9400b3SPaolo Bonzini opts = qemu_opts_from_qdict(opts_list, qdict, &local_err); 913fd9400b3SPaolo Bonzini if (error_is_set(&local_err)) { 914fd9400b3SPaolo Bonzini goto exit_err; 915fd9400b3SPaolo Bonzini } 916fd9400b3SPaolo Bonzini 917fd9400b3SPaolo Bonzini netdev_add(opts, &local_err); 918fd9400b3SPaolo Bonzini if (error_is_set(&local_err)) { 919fd9400b3SPaolo Bonzini qemu_opts_del(opts); 920fd9400b3SPaolo Bonzini goto exit_err; 921fd9400b3SPaolo Bonzini } 922fd9400b3SPaolo Bonzini 923fd9400b3SPaolo Bonzini return 0; 924fd9400b3SPaolo Bonzini 925fd9400b3SPaolo Bonzini exit_err: 926fd9400b3SPaolo Bonzini qerror_report_err(local_err); 927fd9400b3SPaolo Bonzini error_free(local_err); 928fd9400b3SPaolo Bonzini return -1; 929fd9400b3SPaolo Bonzini } 930fd9400b3SPaolo Bonzini 931fd9400b3SPaolo Bonzini void qmp_netdev_del(const char *id, Error **errp) 932fd9400b3SPaolo Bonzini { 933fd9400b3SPaolo Bonzini NetClientState *nc; 934fd9400b3SPaolo Bonzini QemuOpts *opts; 935fd9400b3SPaolo Bonzini 936fd9400b3SPaolo Bonzini nc = qemu_find_netdev(id); 937fd9400b3SPaolo Bonzini if (!nc) { 938fd9400b3SPaolo Bonzini error_set(errp, QERR_DEVICE_NOT_FOUND, id); 939fd9400b3SPaolo Bonzini return; 940fd9400b3SPaolo Bonzini } 941fd9400b3SPaolo Bonzini 942fd9400b3SPaolo Bonzini opts = qemu_opts_find(qemu_find_opts_err("netdev", NULL), id); 943fd9400b3SPaolo Bonzini if (!opts) { 944fd9400b3SPaolo Bonzini error_setg(errp, "Device '%s' is not a netdev", id); 945fd9400b3SPaolo Bonzini return; 946fd9400b3SPaolo Bonzini } 947fd9400b3SPaolo Bonzini 948fd9400b3SPaolo Bonzini qemu_del_net_client(nc); 949fd9400b3SPaolo Bonzini qemu_opts_del(opts); 950fd9400b3SPaolo Bonzini } 951fd9400b3SPaolo Bonzini 952fd9400b3SPaolo Bonzini void print_net_client(Monitor *mon, NetClientState *nc) 953fd9400b3SPaolo Bonzini { 954*1ceef9f2SJason Wang monitor_printf(mon, "%s: index=%d,type=%s,%s\n", nc->name, 955*1ceef9f2SJason Wang nc->queue_index, 956*1ceef9f2SJason Wang NetClientOptionsKind_lookup[nc->info->type], 957*1ceef9f2SJason Wang nc->info_str); 958fd9400b3SPaolo Bonzini } 959fd9400b3SPaolo Bonzini 96084f2d0eaSWenchao Xia void do_info_network(Monitor *mon, const QDict *qdict) 961fd9400b3SPaolo Bonzini { 962fd9400b3SPaolo Bonzini NetClientState *nc, *peer; 963fd9400b3SPaolo Bonzini NetClientOptionsKind type; 964fd9400b3SPaolo Bonzini 965fd9400b3SPaolo Bonzini net_hub_info(mon); 966fd9400b3SPaolo Bonzini 967fd9400b3SPaolo Bonzini QTAILQ_FOREACH(nc, &net_clients, next) { 968fd9400b3SPaolo Bonzini peer = nc->peer; 969fd9400b3SPaolo Bonzini type = nc->info->type; 970fd9400b3SPaolo Bonzini 971fd9400b3SPaolo Bonzini /* Skip if already printed in hub info */ 972fd9400b3SPaolo Bonzini if (net_hub_id_for_client(nc, NULL) == 0) { 973fd9400b3SPaolo Bonzini continue; 974fd9400b3SPaolo Bonzini } 975fd9400b3SPaolo Bonzini 976fd9400b3SPaolo Bonzini if (!peer || type == NET_CLIENT_OPTIONS_KIND_NIC) { 977fd9400b3SPaolo Bonzini print_net_client(mon, nc); 978fd9400b3SPaolo Bonzini } /* else it's a netdev connected to a NIC, printed with the NIC */ 979fd9400b3SPaolo Bonzini if (peer && type == NET_CLIENT_OPTIONS_KIND_NIC) { 980fd9400b3SPaolo Bonzini monitor_printf(mon, " \\ "); 981fd9400b3SPaolo Bonzini print_net_client(mon, peer); 982fd9400b3SPaolo Bonzini } 983fd9400b3SPaolo Bonzini } 984fd9400b3SPaolo Bonzini } 985fd9400b3SPaolo Bonzini 986fd9400b3SPaolo Bonzini void qmp_set_link(const char *name, bool up, Error **errp) 987fd9400b3SPaolo Bonzini { 988*1ceef9f2SJason Wang NetClientState *ncs[MAX_QUEUE_NUM]; 989*1ceef9f2SJason Wang NetClientState *nc; 990*1ceef9f2SJason Wang int queues, i; 991fd9400b3SPaolo Bonzini 992*1ceef9f2SJason Wang queues = qemu_find_net_clients_except(name, ncs, 993*1ceef9f2SJason Wang NET_CLIENT_OPTIONS_KIND_MAX, 994*1ceef9f2SJason Wang MAX_QUEUE_NUM); 995*1ceef9f2SJason Wang 996*1ceef9f2SJason Wang if (queues == 0) { 997fd9400b3SPaolo Bonzini error_set(errp, QERR_DEVICE_NOT_FOUND, name); 998fd9400b3SPaolo Bonzini return; 999fd9400b3SPaolo Bonzini } 1000*1ceef9f2SJason Wang nc = ncs[0]; 1001fd9400b3SPaolo Bonzini 1002*1ceef9f2SJason Wang for (i = 0; i < queues; i++) { 1003*1ceef9f2SJason Wang ncs[i]->link_down = !up; 1004*1ceef9f2SJason Wang } 1005fd9400b3SPaolo Bonzini 1006fd9400b3SPaolo Bonzini if (nc->info->link_status_changed) { 1007fd9400b3SPaolo Bonzini nc->info->link_status_changed(nc); 1008fd9400b3SPaolo Bonzini } 1009fd9400b3SPaolo Bonzini 1010fd9400b3SPaolo Bonzini /* Notify peer. Don't update peer link status: this makes it possible to 1011fd9400b3SPaolo Bonzini * disconnect from host network without notifying the guest. 1012fd9400b3SPaolo Bonzini * FIXME: is disconnected link status change operation useful? 1013fd9400b3SPaolo Bonzini * 1014fd9400b3SPaolo Bonzini * Current behaviour is compatible with qemu vlans where there could be 1015fd9400b3SPaolo Bonzini * multiple clients that can still communicate with each other in 1016fd9400b3SPaolo Bonzini * disconnected mode. For now maintain this compatibility. */ 1017fd9400b3SPaolo Bonzini if (nc->peer && nc->peer->info->link_status_changed) { 1018fd9400b3SPaolo Bonzini nc->peer->info->link_status_changed(nc->peer); 1019fd9400b3SPaolo Bonzini } 1020fd9400b3SPaolo Bonzini } 1021fd9400b3SPaolo Bonzini 1022fd9400b3SPaolo Bonzini void net_cleanup(void) 1023fd9400b3SPaolo Bonzini { 1024*1ceef9f2SJason Wang NetClientState *nc; 1025fd9400b3SPaolo Bonzini 1026*1ceef9f2SJason Wang /* We may del multiple entries during qemu_del_net_client(), 1027*1ceef9f2SJason Wang * so QTAILQ_FOREACH_SAFE() is also not safe here. 1028*1ceef9f2SJason Wang */ 1029*1ceef9f2SJason Wang while (!QTAILQ_EMPTY(&net_clients)) { 1030*1ceef9f2SJason Wang nc = QTAILQ_FIRST(&net_clients); 1031948ecf21SJason Wang if (nc->info->type == NET_CLIENT_OPTIONS_KIND_NIC) { 1032948ecf21SJason Wang qemu_del_nic(qemu_get_nic(nc)); 1033948ecf21SJason Wang } else { 1034fd9400b3SPaolo Bonzini qemu_del_net_client(nc); 1035fd9400b3SPaolo Bonzini } 1036fd9400b3SPaolo Bonzini } 1037948ecf21SJason Wang } 1038fd9400b3SPaolo Bonzini 1039fd9400b3SPaolo Bonzini void net_check_clients(void) 1040fd9400b3SPaolo Bonzini { 1041fd9400b3SPaolo Bonzini NetClientState *nc; 1042fd9400b3SPaolo Bonzini int i; 1043fd9400b3SPaolo Bonzini 1044fd9400b3SPaolo Bonzini /* Don't warn about the default network setup that you get if 1045fd9400b3SPaolo Bonzini * no command line -net or -netdev options are specified. There 1046fd9400b3SPaolo Bonzini * are two cases that we would otherwise complain about: 1047fd9400b3SPaolo Bonzini * (1) board doesn't support a NIC but the implicit "-net nic" 1048fd9400b3SPaolo Bonzini * requested one 1049fd9400b3SPaolo Bonzini * (2) CONFIG_SLIRP not set, in which case the implicit "-net nic" 1050fd9400b3SPaolo Bonzini * sets up a nic that isn't connected to anything. 1051fd9400b3SPaolo Bonzini */ 1052fd9400b3SPaolo Bonzini if (default_net) { 1053fd9400b3SPaolo Bonzini return; 1054fd9400b3SPaolo Bonzini } 1055fd9400b3SPaolo Bonzini 1056fd9400b3SPaolo Bonzini net_hub_check_clients(); 1057fd9400b3SPaolo Bonzini 1058fd9400b3SPaolo Bonzini QTAILQ_FOREACH(nc, &net_clients, next) { 1059fd9400b3SPaolo Bonzini if (!nc->peer) { 1060fd9400b3SPaolo Bonzini fprintf(stderr, "Warning: %s %s has no peer\n", 1061fd9400b3SPaolo Bonzini nc->info->type == NET_CLIENT_OPTIONS_KIND_NIC ? 1062fd9400b3SPaolo Bonzini "nic" : "netdev", nc->name); 1063fd9400b3SPaolo Bonzini } 1064fd9400b3SPaolo Bonzini } 1065fd9400b3SPaolo Bonzini 1066fd9400b3SPaolo Bonzini /* Check that all NICs requested via -net nic actually got created. 1067fd9400b3SPaolo Bonzini * NICs created via -device don't need to be checked here because 1068fd9400b3SPaolo Bonzini * they are always instantiated. 1069fd9400b3SPaolo Bonzini */ 1070fd9400b3SPaolo Bonzini for (i = 0; i < MAX_NICS; i++) { 1071fd9400b3SPaolo Bonzini NICInfo *nd = &nd_table[i]; 1072fd9400b3SPaolo Bonzini if (nd->used && !nd->instantiated) { 1073fd9400b3SPaolo Bonzini fprintf(stderr, "Warning: requested NIC (%s, model %s) " 1074fd9400b3SPaolo Bonzini "was not created (not supported by this machine?)\n", 1075fd9400b3SPaolo Bonzini nd->name ? nd->name : "anonymous", 1076fd9400b3SPaolo Bonzini nd->model ? nd->model : "unspecified"); 1077fd9400b3SPaolo Bonzini } 1078fd9400b3SPaolo Bonzini } 1079fd9400b3SPaolo Bonzini } 1080fd9400b3SPaolo Bonzini 1081fd9400b3SPaolo Bonzini static int net_init_client(QemuOpts *opts, void *dummy) 1082fd9400b3SPaolo Bonzini { 1083fd9400b3SPaolo Bonzini Error *local_err = NULL; 1084fd9400b3SPaolo Bonzini 1085fd9400b3SPaolo Bonzini net_client_init(opts, 0, &local_err); 1086fd9400b3SPaolo Bonzini if (error_is_set(&local_err)) { 1087fd9400b3SPaolo Bonzini qerror_report_err(local_err); 1088fd9400b3SPaolo Bonzini error_free(local_err); 1089fd9400b3SPaolo Bonzini return -1; 1090fd9400b3SPaolo Bonzini } 1091fd9400b3SPaolo Bonzini 1092fd9400b3SPaolo Bonzini return 0; 1093fd9400b3SPaolo Bonzini } 1094fd9400b3SPaolo Bonzini 1095fd9400b3SPaolo Bonzini static int net_init_netdev(QemuOpts *opts, void *dummy) 1096fd9400b3SPaolo Bonzini { 1097fd9400b3SPaolo Bonzini Error *local_err = NULL; 1098fd9400b3SPaolo Bonzini int ret; 1099fd9400b3SPaolo Bonzini 1100fd9400b3SPaolo Bonzini ret = net_client_init(opts, 1, &local_err); 1101fd9400b3SPaolo Bonzini if (error_is_set(&local_err)) { 1102fd9400b3SPaolo Bonzini qerror_report_err(local_err); 1103fd9400b3SPaolo Bonzini error_free(local_err); 1104fd9400b3SPaolo Bonzini return -1; 1105fd9400b3SPaolo Bonzini } 1106fd9400b3SPaolo Bonzini 1107fd9400b3SPaolo Bonzini return ret; 1108fd9400b3SPaolo Bonzini } 1109fd9400b3SPaolo Bonzini 1110fd9400b3SPaolo Bonzini int net_init_clients(void) 1111fd9400b3SPaolo Bonzini { 1112fd9400b3SPaolo Bonzini QemuOptsList *net = qemu_find_opts("net"); 1113fd9400b3SPaolo Bonzini 1114fd9400b3SPaolo Bonzini if (default_net) { 1115fd9400b3SPaolo Bonzini /* if no clients, we use a default config */ 1116fd9400b3SPaolo Bonzini qemu_opts_set(net, NULL, "type", "nic"); 1117fd9400b3SPaolo Bonzini #ifdef CONFIG_SLIRP 1118fd9400b3SPaolo Bonzini qemu_opts_set(net, NULL, "type", "user"); 1119fd9400b3SPaolo Bonzini #endif 1120fd9400b3SPaolo Bonzini } 1121fd9400b3SPaolo Bonzini 1122fd9400b3SPaolo Bonzini QTAILQ_INIT(&net_clients); 1123fd9400b3SPaolo Bonzini 1124fd9400b3SPaolo Bonzini if (qemu_opts_foreach(qemu_find_opts("netdev"), net_init_netdev, NULL, 1) == -1) 1125fd9400b3SPaolo Bonzini return -1; 1126fd9400b3SPaolo Bonzini 1127fd9400b3SPaolo Bonzini if (qemu_opts_foreach(net, net_init_client, NULL, 1) == -1) { 1128fd9400b3SPaolo Bonzini return -1; 1129fd9400b3SPaolo Bonzini } 1130fd9400b3SPaolo Bonzini 1131fd9400b3SPaolo Bonzini return 0; 1132fd9400b3SPaolo Bonzini } 1133fd9400b3SPaolo Bonzini 1134fd9400b3SPaolo Bonzini int net_client_parse(QemuOptsList *opts_list, const char *optarg) 1135fd9400b3SPaolo Bonzini { 1136fd9400b3SPaolo Bonzini #if defined(CONFIG_SLIRP) 1137fd9400b3SPaolo Bonzini int ret; 1138fd9400b3SPaolo Bonzini if (net_slirp_parse_legacy(opts_list, optarg, &ret)) { 1139fd9400b3SPaolo Bonzini return ret; 1140fd9400b3SPaolo Bonzini } 1141fd9400b3SPaolo Bonzini #endif 1142fd9400b3SPaolo Bonzini 1143fd9400b3SPaolo Bonzini if (!qemu_opts_parse(opts_list, optarg, 1)) { 1144fd9400b3SPaolo Bonzini return -1; 1145fd9400b3SPaolo Bonzini } 1146fd9400b3SPaolo Bonzini 1147fd9400b3SPaolo Bonzini default_net = 0; 1148fd9400b3SPaolo Bonzini return 0; 1149fd9400b3SPaolo Bonzini } 1150fd9400b3SPaolo Bonzini 1151fd9400b3SPaolo Bonzini /* From FreeBSD */ 1152fd9400b3SPaolo Bonzini /* XXX: optimize */ 1153fd9400b3SPaolo Bonzini unsigned compute_mcast_idx(const uint8_t *ep) 1154fd9400b3SPaolo Bonzini { 1155fd9400b3SPaolo Bonzini uint32_t crc; 1156fd9400b3SPaolo Bonzini int carry, i, j; 1157fd9400b3SPaolo Bonzini uint8_t b; 1158fd9400b3SPaolo Bonzini 1159fd9400b3SPaolo Bonzini crc = 0xffffffff; 1160fd9400b3SPaolo Bonzini for (i = 0; i < 6; i++) { 1161fd9400b3SPaolo Bonzini b = *ep++; 1162fd9400b3SPaolo Bonzini for (j = 0; j < 8; j++) { 1163fd9400b3SPaolo Bonzini carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01); 1164fd9400b3SPaolo Bonzini crc <<= 1; 1165fd9400b3SPaolo Bonzini b >>= 1; 1166fd9400b3SPaolo Bonzini if (carry) { 1167fd9400b3SPaolo Bonzini crc = ((crc ^ POLYNOMIAL) | carry); 1168fd9400b3SPaolo Bonzini } 1169fd9400b3SPaolo Bonzini } 1170fd9400b3SPaolo Bonzini } 1171fd9400b3SPaolo Bonzini return crc >> 26; 1172fd9400b3SPaolo Bonzini } 11734d454574SPaolo Bonzini 11744d454574SPaolo Bonzini QemuOptsList qemu_netdev_opts = { 11754d454574SPaolo Bonzini .name = "netdev", 11764d454574SPaolo Bonzini .implied_opt_name = "type", 11774d454574SPaolo Bonzini .head = QTAILQ_HEAD_INITIALIZER(qemu_netdev_opts.head), 11784d454574SPaolo Bonzini .desc = { 11794d454574SPaolo Bonzini /* 11804d454574SPaolo Bonzini * no elements => accept any params 11814d454574SPaolo Bonzini * validation will happen later 11824d454574SPaolo Bonzini */ 11834d454574SPaolo Bonzini { /* end of list */ } 11844d454574SPaolo Bonzini }, 11854d454574SPaolo Bonzini }; 11864d454574SPaolo Bonzini 11874d454574SPaolo Bonzini QemuOptsList qemu_net_opts = { 11884d454574SPaolo Bonzini .name = "net", 11894d454574SPaolo Bonzini .implied_opt_name = "type", 11904d454574SPaolo Bonzini .head = QTAILQ_HEAD_INITIALIZER(qemu_net_opts.head), 11914d454574SPaolo Bonzini .desc = { 11924d454574SPaolo Bonzini /* 11934d454574SPaolo Bonzini * no elements => accept any params 11944d454574SPaolo Bonzini * validation will happen later 11954d454574SPaolo Bonzini */ 11964d454574SPaolo Bonzini { /* end of list */ } 11974d454574SPaolo Bonzini }, 11984d454574SPaolo Bonzini }; 1199