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 */ 242744d920SPeter Maydell #include "qemu/osdep.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" 30d60b20cfSDmitry Krivenok #include "net/eth.h" 31fd9400b3SPaolo Bonzini #include "util.h" 32fd9400b3SPaolo Bonzini 3383c9089eSPaolo Bonzini #include "monitor/monitor.h" 34fd9400b3SPaolo Bonzini #include "qemu-common.h" 35f348b6d1SVeronia Bahaa #include "qemu/help_option.h" 36cc7a8ea7SMarkus Armbruster #include "qapi/qmp/qerror.h" 37d49b6836SMarkus Armbruster #include "qemu/error-report.h" 381de7afc9SPaolo Bonzini #include "qemu/sockets.h" 39f348b6d1SVeronia Bahaa #include "qemu/cutils.h" 401de7afc9SPaolo Bonzini #include "qemu/config-file.h" 41fd9400b3SPaolo Bonzini #include "qmp-commands.h" 42fd9400b3SPaolo Bonzini #include "hw/qdev.h" 431de7afc9SPaolo Bonzini #include "qemu/iov.h" 446a1751b7SAlex Bligh #include "qemu/main-loop.h" 45fd9400b3SPaolo Bonzini #include "qapi-visit.h" 46fd9400b3SPaolo Bonzini #include "qapi/opts-visitor.h" 47e1d64c08Szhanghailiang #include "sysemu/sysemu.h" 48fdccce45SYang Hongyang #include "net/filter.h" 49aa9156f4Szhanghailiang #include "qapi/string-output-visitor.h" 50fd9400b3SPaolo Bonzini 51fd9400b3SPaolo Bonzini /* Net bridge is currently not supported for W32. */ 52fd9400b3SPaolo Bonzini #if !defined(_WIN32) 53fd9400b3SPaolo Bonzini # define CONFIG_NET_BRIDGE 54fd9400b3SPaolo Bonzini #endif 55fd9400b3SPaolo Bonzini 56ca77d85eSMichael S. Tsirkin static VMChangeStateEntry *net_change_state_entry; 57fd9400b3SPaolo Bonzini static QTAILQ_HEAD(, NetClientState) net_clients; 58fd9400b3SPaolo Bonzini 5984007e81SHani Benhabiles const char *host_net_devices[] = { 6084007e81SHani Benhabiles "tap", 6184007e81SHani Benhabiles "socket", 6284007e81SHani Benhabiles "dump", 6384007e81SHani Benhabiles #ifdef CONFIG_NET_BRIDGE 6484007e81SHani Benhabiles "bridge", 6584007e81SHani Benhabiles #endif 66027a247bSStefan Hajnoczi #ifdef CONFIG_NETMAP 67027a247bSStefan Hajnoczi "netmap", 68027a247bSStefan Hajnoczi #endif 6984007e81SHani Benhabiles #ifdef CONFIG_SLIRP 7084007e81SHani Benhabiles "user", 7184007e81SHani Benhabiles #endif 7284007e81SHani Benhabiles #ifdef CONFIG_VDE 7384007e81SHani Benhabiles "vde", 7484007e81SHani Benhabiles #endif 7503ce5744SNikolay Nikolaev "vhost-user", 7684007e81SHani Benhabiles NULL, 7784007e81SHani Benhabiles }; 7884007e81SHani Benhabiles 79fd9400b3SPaolo Bonzini /***********************************************************/ 80fd9400b3SPaolo Bonzini /* network device redirectors */ 81fd9400b3SPaolo Bonzini 82fd9400b3SPaolo Bonzini static int get_str_sep(char *buf, int buf_size, const char **pp, int sep) 83fd9400b3SPaolo Bonzini { 84fd9400b3SPaolo Bonzini const char *p, *p1; 85fd9400b3SPaolo Bonzini int len; 86fd9400b3SPaolo Bonzini p = *pp; 87fd9400b3SPaolo Bonzini p1 = strchr(p, sep); 88fd9400b3SPaolo Bonzini if (!p1) 89fd9400b3SPaolo Bonzini return -1; 90fd9400b3SPaolo Bonzini len = p1 - p; 91fd9400b3SPaolo Bonzini p1++; 92fd9400b3SPaolo Bonzini if (buf_size > 0) { 93fd9400b3SPaolo Bonzini if (len > buf_size - 1) 94fd9400b3SPaolo Bonzini len = buf_size - 1; 95fd9400b3SPaolo Bonzini memcpy(buf, p, len); 96fd9400b3SPaolo Bonzini buf[len] = '\0'; 97fd9400b3SPaolo Bonzini } 98fd9400b3SPaolo Bonzini *pp = p1; 99fd9400b3SPaolo Bonzini return 0; 100fd9400b3SPaolo Bonzini } 101fd9400b3SPaolo Bonzini 102fd9400b3SPaolo Bonzini int parse_host_port(struct sockaddr_in *saddr, const char *str) 103fd9400b3SPaolo Bonzini { 104fd9400b3SPaolo Bonzini char buf[512]; 105fd9400b3SPaolo Bonzini struct hostent *he; 106fd9400b3SPaolo Bonzini const char *p, *r; 107fd9400b3SPaolo Bonzini int port; 108fd9400b3SPaolo Bonzini 109fd9400b3SPaolo Bonzini p = str; 110fd9400b3SPaolo Bonzini if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) 111fd9400b3SPaolo Bonzini return -1; 112fd9400b3SPaolo Bonzini saddr->sin_family = AF_INET; 113fd9400b3SPaolo Bonzini if (buf[0] == '\0') { 114fd9400b3SPaolo Bonzini saddr->sin_addr.s_addr = 0; 115fd9400b3SPaolo Bonzini } else { 116fd9400b3SPaolo Bonzini if (qemu_isdigit(buf[0])) { 117fd9400b3SPaolo Bonzini if (!inet_aton(buf, &saddr->sin_addr)) 118fd9400b3SPaolo Bonzini return -1; 119fd9400b3SPaolo Bonzini } else { 120fd9400b3SPaolo Bonzini if ((he = gethostbyname(buf)) == NULL) 121fd9400b3SPaolo Bonzini return - 1; 122fd9400b3SPaolo Bonzini saddr->sin_addr = *(struct in_addr *)he->h_addr; 123fd9400b3SPaolo Bonzini } 124fd9400b3SPaolo Bonzini } 125fd9400b3SPaolo Bonzini port = strtol(p, (char **)&r, 0); 126fd9400b3SPaolo Bonzini if (r == p) 127fd9400b3SPaolo Bonzini return -1; 128fd9400b3SPaolo Bonzini saddr->sin_port = htons(port); 129fd9400b3SPaolo Bonzini return 0; 130fd9400b3SPaolo Bonzini } 131fd9400b3SPaolo Bonzini 132890ee6abSScott Feldman char *qemu_mac_strdup_printf(const uint8_t *macaddr) 133890ee6abSScott Feldman { 134890ee6abSScott Feldman return g_strdup_printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", 135890ee6abSScott Feldman macaddr[0], macaddr[1], macaddr[2], 136890ee6abSScott Feldman macaddr[3], macaddr[4], macaddr[5]); 137890ee6abSScott Feldman } 138890ee6abSScott Feldman 139fd9400b3SPaolo Bonzini void qemu_format_nic_info_str(NetClientState *nc, uint8_t macaddr[6]) 140fd9400b3SPaolo Bonzini { 141fd9400b3SPaolo Bonzini snprintf(nc->info_str, sizeof(nc->info_str), 142fd9400b3SPaolo Bonzini "model=%s,macaddr=%02x:%02x:%02x:%02x:%02x:%02x", 143fd9400b3SPaolo Bonzini nc->model, 144fd9400b3SPaolo Bonzini macaddr[0], macaddr[1], macaddr[2], 145fd9400b3SPaolo Bonzini macaddr[3], macaddr[4], macaddr[5]); 146fd9400b3SPaolo Bonzini } 147fd9400b3SPaolo Bonzini 1482bc22a58SShannon Zhao static int mac_table[256] = {0}; 1492bc22a58SShannon Zhao 1502bc22a58SShannon Zhao static void qemu_macaddr_set_used(MACAddr *macaddr) 1512bc22a58SShannon Zhao { 1522bc22a58SShannon Zhao int index; 1532bc22a58SShannon Zhao 1542bc22a58SShannon Zhao for (index = 0x56; index < 0xFF; index++) { 1552bc22a58SShannon Zhao if (macaddr->a[5] == index) { 1562bc22a58SShannon Zhao mac_table[index]++; 1572bc22a58SShannon Zhao } 1582bc22a58SShannon Zhao } 1592bc22a58SShannon Zhao } 1602bc22a58SShannon Zhao 1612bc22a58SShannon Zhao static void qemu_macaddr_set_free(MACAddr *macaddr) 1622bc22a58SShannon Zhao { 1632bc22a58SShannon Zhao int index; 1642bc22a58SShannon Zhao static const MACAddr base = { .a = { 0x52, 0x54, 0x00, 0x12, 0x34, 0 } }; 1652bc22a58SShannon Zhao 1662bc22a58SShannon Zhao if (memcmp(macaddr->a, &base.a, (sizeof(base.a) - 1)) != 0) { 1672bc22a58SShannon Zhao return; 1682bc22a58SShannon Zhao } 1692bc22a58SShannon Zhao for (index = 0x56; index < 0xFF; index++) { 1702bc22a58SShannon Zhao if (macaddr->a[5] == index) { 1712bc22a58SShannon Zhao mac_table[index]--; 1722bc22a58SShannon Zhao } 1732bc22a58SShannon Zhao } 1742bc22a58SShannon Zhao } 1752bc22a58SShannon Zhao 1762bc22a58SShannon Zhao static int qemu_macaddr_get_free(void) 1772bc22a58SShannon Zhao { 1782bc22a58SShannon Zhao int index; 1792bc22a58SShannon Zhao 1802bc22a58SShannon Zhao for (index = 0x56; index < 0xFF; index++) { 1812bc22a58SShannon Zhao if (mac_table[index] == 0) { 1822bc22a58SShannon Zhao return index; 1832bc22a58SShannon Zhao } 1842bc22a58SShannon Zhao } 1852bc22a58SShannon Zhao 1862bc22a58SShannon Zhao return -1; 1872bc22a58SShannon Zhao } 1882bc22a58SShannon Zhao 189fd9400b3SPaolo Bonzini void qemu_macaddr_default_if_unset(MACAddr *macaddr) 190fd9400b3SPaolo Bonzini { 191fd9400b3SPaolo Bonzini static const MACAddr zero = { .a = { 0,0,0,0,0,0 } }; 1922bc22a58SShannon Zhao static const MACAddr base = { .a = { 0x52, 0x54, 0x00, 0x12, 0x34, 0 } }; 193fd9400b3SPaolo Bonzini 1942bc22a58SShannon Zhao if (memcmp(macaddr, &zero, sizeof(zero)) != 0) { 1952bc22a58SShannon Zhao if (memcmp(macaddr->a, &base.a, (sizeof(base.a) - 1)) != 0) { 196fd9400b3SPaolo Bonzini return; 1972bc22a58SShannon Zhao } else { 1982bc22a58SShannon Zhao qemu_macaddr_set_used(macaddr); 1992bc22a58SShannon Zhao return; 2002bc22a58SShannon Zhao } 2012bc22a58SShannon Zhao } 2022bc22a58SShannon Zhao 203fd9400b3SPaolo Bonzini macaddr->a[0] = 0x52; 204fd9400b3SPaolo Bonzini macaddr->a[1] = 0x54; 205fd9400b3SPaolo Bonzini macaddr->a[2] = 0x00; 206fd9400b3SPaolo Bonzini macaddr->a[3] = 0x12; 207fd9400b3SPaolo Bonzini macaddr->a[4] = 0x34; 2082bc22a58SShannon Zhao macaddr->a[5] = qemu_macaddr_get_free(); 2092bc22a58SShannon Zhao qemu_macaddr_set_used(macaddr); 210fd9400b3SPaolo Bonzini } 211fd9400b3SPaolo Bonzini 212fd9400b3SPaolo Bonzini /** 213fd9400b3SPaolo Bonzini * Generate a name for net client 214fd9400b3SPaolo Bonzini * 215c963530aSAmos Kong * Only net clients created with the legacy -net option and NICs need this. 216fd9400b3SPaolo Bonzini */ 217fd9400b3SPaolo Bonzini static char *assign_name(NetClientState *nc1, const char *model) 218fd9400b3SPaolo Bonzini { 219fd9400b3SPaolo Bonzini NetClientState *nc; 220fd9400b3SPaolo Bonzini int id = 0; 221fd9400b3SPaolo Bonzini 222fd9400b3SPaolo Bonzini QTAILQ_FOREACH(nc, &net_clients, next) { 223fd9400b3SPaolo Bonzini if (nc == nc1) { 224fd9400b3SPaolo Bonzini continue; 225fd9400b3SPaolo Bonzini } 226c963530aSAmos Kong if (strcmp(nc->model, model) == 0) { 227fd9400b3SPaolo Bonzini id++; 228fd9400b3SPaolo Bonzini } 229fd9400b3SPaolo Bonzini } 230fd9400b3SPaolo Bonzini 2314bf2c138SHani Benhabiles return g_strdup_printf("%s.%d", model, id); 232fd9400b3SPaolo Bonzini } 233fd9400b3SPaolo Bonzini 234f7860455SJason Wang static void qemu_net_client_destructor(NetClientState *nc) 235f7860455SJason Wang { 236f7860455SJason Wang g_free(nc); 237f7860455SJason Wang } 238f7860455SJason Wang 23918a1541aSJason Wang static void qemu_net_client_setup(NetClientState *nc, 24018a1541aSJason Wang NetClientInfo *info, 241fd9400b3SPaolo Bonzini NetClientState *peer, 242fd9400b3SPaolo Bonzini const char *model, 243f7860455SJason Wang const char *name, 244f7860455SJason Wang NetClientDestructor *destructor) 245fd9400b3SPaolo Bonzini { 246fd9400b3SPaolo Bonzini nc->info = info; 247fd9400b3SPaolo Bonzini nc->model = g_strdup(model); 248fd9400b3SPaolo Bonzini if (name) { 249fd9400b3SPaolo Bonzini nc->name = g_strdup(name); 250fd9400b3SPaolo Bonzini } else { 251fd9400b3SPaolo Bonzini nc->name = assign_name(nc, model); 252fd9400b3SPaolo Bonzini } 253fd9400b3SPaolo Bonzini 254fd9400b3SPaolo Bonzini if (peer) { 255fd9400b3SPaolo Bonzini assert(!peer->peer); 256fd9400b3SPaolo Bonzini nc->peer = peer; 257fd9400b3SPaolo Bonzini peer->peer = nc; 258fd9400b3SPaolo Bonzini } 259fd9400b3SPaolo Bonzini QTAILQ_INSERT_TAIL(&net_clients, nc, next); 260fd9400b3SPaolo Bonzini 2613e033a46SYang Hongyang nc->incoming_queue = qemu_new_net_queue(qemu_deliver_packet_iov, nc); 262f7860455SJason Wang nc->destructor = destructor; 263fdccce45SYang Hongyang QTAILQ_INIT(&nc->filters); 26418a1541aSJason Wang } 26518a1541aSJason Wang 26618a1541aSJason Wang NetClientState *qemu_new_net_client(NetClientInfo *info, 26718a1541aSJason Wang NetClientState *peer, 26818a1541aSJason Wang const char *model, 26918a1541aSJason Wang const char *name) 27018a1541aSJason Wang { 27118a1541aSJason Wang NetClientState *nc; 27218a1541aSJason Wang 27318a1541aSJason Wang assert(info->size >= sizeof(NetClientState)); 27418a1541aSJason Wang 27518a1541aSJason Wang nc = g_malloc0(info->size); 276f7860455SJason Wang qemu_net_client_setup(nc, info, peer, model, name, 277f7860455SJason Wang qemu_net_client_destructor); 27818a1541aSJason Wang 279fd9400b3SPaolo Bonzini return nc; 280fd9400b3SPaolo Bonzini } 281fd9400b3SPaolo Bonzini 282fd9400b3SPaolo Bonzini NICState *qemu_new_nic(NetClientInfo *info, 283fd9400b3SPaolo Bonzini NICConf *conf, 284fd9400b3SPaolo Bonzini const char *model, 285fd9400b3SPaolo Bonzini const char *name, 286fd9400b3SPaolo Bonzini void *opaque) 287fd9400b3SPaolo Bonzini { 2881ceef9f2SJason Wang NetClientState **peers = conf->peers.ncs; 289fd9400b3SPaolo Bonzini NICState *nic; 290575a1c0eSJiri Pirko int i, queues = MAX(1, conf->peers.queues); 291fd9400b3SPaolo Bonzini 292f394b2e2SEric Blake assert(info->type == NET_CLIENT_DRIVER_NIC); 293fd9400b3SPaolo Bonzini assert(info->size >= sizeof(NICState)); 294fd9400b3SPaolo Bonzini 295f6b26cf2SJason Wang nic = g_malloc0(info->size + sizeof(NetClientState) * queues); 296f6b26cf2SJason Wang nic->ncs = (void *)nic + info->size; 297fd9400b3SPaolo Bonzini nic->conf = conf; 298fd9400b3SPaolo Bonzini nic->opaque = opaque; 299fd9400b3SPaolo Bonzini 300f6b26cf2SJason Wang for (i = 0; i < queues; i++) { 301f6b26cf2SJason Wang qemu_net_client_setup(&nic->ncs[i], info, peers[i], model, name, 3021ceef9f2SJason Wang NULL); 3031ceef9f2SJason Wang nic->ncs[i].queue_index = i; 3041ceef9f2SJason Wang } 3051ceef9f2SJason Wang 306fd9400b3SPaolo Bonzini return nic; 307fd9400b3SPaolo Bonzini } 308fd9400b3SPaolo Bonzini 3091ceef9f2SJason Wang NetClientState *qemu_get_subqueue(NICState *nic, int queue_index) 3101ceef9f2SJason Wang { 311f6b26cf2SJason Wang return nic->ncs + queue_index; 3121ceef9f2SJason Wang } 3131ceef9f2SJason Wang 314b356f76dSJason Wang NetClientState *qemu_get_queue(NICState *nic) 315b356f76dSJason Wang { 3161ceef9f2SJason Wang return qemu_get_subqueue(nic, 0); 317b356f76dSJason Wang } 318b356f76dSJason Wang 319cc1f0f45SJason Wang NICState *qemu_get_nic(NetClientState *nc) 320cc1f0f45SJason Wang { 3211ceef9f2SJason Wang NetClientState *nc0 = nc - nc->queue_index; 3221ceef9f2SJason Wang 323f6b26cf2SJason Wang return (NICState *)((void *)nc0 - nc->info->size); 324cc1f0f45SJason Wang } 325cc1f0f45SJason Wang 326cc1f0f45SJason Wang void *qemu_get_nic_opaque(NetClientState *nc) 327cc1f0f45SJason Wang { 328cc1f0f45SJason Wang NICState *nic = qemu_get_nic(nc); 329cc1f0f45SJason Wang 330cc1f0f45SJason Wang return nic->opaque; 331cc1f0f45SJason Wang } 332cc1f0f45SJason Wang 333fd9400b3SPaolo Bonzini static void qemu_cleanup_net_client(NetClientState *nc) 334fd9400b3SPaolo Bonzini { 335fd9400b3SPaolo Bonzini QTAILQ_REMOVE(&net_clients, nc, next); 336fd9400b3SPaolo Bonzini 337cc2a9043SAndreas Färber if (nc->info->cleanup) { 338fd9400b3SPaolo Bonzini nc->info->cleanup(nc); 339fd9400b3SPaolo Bonzini } 340cc2a9043SAndreas Färber } 341fd9400b3SPaolo Bonzini 342fd9400b3SPaolo Bonzini static void qemu_free_net_client(NetClientState *nc) 343fd9400b3SPaolo Bonzini { 344067404beSJan Kiszka if (nc->incoming_queue) { 345067404beSJan Kiszka qemu_del_net_queue(nc->incoming_queue); 346fd9400b3SPaolo Bonzini } 347fd9400b3SPaolo Bonzini if (nc->peer) { 348fd9400b3SPaolo Bonzini nc->peer->peer = NULL; 349fd9400b3SPaolo Bonzini } 350fd9400b3SPaolo Bonzini g_free(nc->name); 351fd9400b3SPaolo Bonzini g_free(nc->model); 352f7860455SJason Wang if (nc->destructor) { 353f7860455SJason Wang nc->destructor(nc); 354f7860455SJason Wang } 355fd9400b3SPaolo Bonzini } 356fd9400b3SPaolo Bonzini 357fd9400b3SPaolo Bonzini void qemu_del_net_client(NetClientState *nc) 358fd9400b3SPaolo Bonzini { 3591ceef9f2SJason Wang NetClientState *ncs[MAX_QUEUE_NUM]; 3601ceef9f2SJason Wang int queues, i; 361fdccce45SYang Hongyang NetFilterState *nf, *next; 3621ceef9f2SJason Wang 363f394b2e2SEric Blake assert(nc->info->type != NET_CLIENT_DRIVER_NIC); 3647fb43911SPaolo Bonzini 3651ceef9f2SJason Wang /* If the NetClientState belongs to a multiqueue backend, we will change all 3661ceef9f2SJason Wang * other NetClientStates also. 3671ceef9f2SJason Wang */ 3681ceef9f2SJason Wang queues = qemu_find_net_clients_except(nc->name, ncs, 369f394b2e2SEric Blake NET_CLIENT_DRIVER_NIC, 3701ceef9f2SJason Wang MAX_QUEUE_NUM); 3711ceef9f2SJason Wang assert(queues != 0); 3721ceef9f2SJason Wang 373fdccce45SYang Hongyang QTAILQ_FOREACH_SAFE(nf, &nc->filters, next, next) { 374fdccce45SYang Hongyang object_unparent(OBJECT(nf)); 375fdccce45SYang Hongyang } 376fdccce45SYang Hongyang 377fd9400b3SPaolo Bonzini /* If there is a peer NIC, delete and cleanup client, but do not free. */ 378f394b2e2SEric Blake if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_NIC) { 379cc1f0f45SJason Wang NICState *nic = qemu_get_nic(nc->peer); 380fd9400b3SPaolo Bonzini if (nic->peer_deleted) { 381fd9400b3SPaolo Bonzini return; 382fd9400b3SPaolo Bonzini } 383fd9400b3SPaolo Bonzini nic->peer_deleted = true; 3841ceef9f2SJason Wang 3851ceef9f2SJason Wang for (i = 0; i < queues; i++) { 3861ceef9f2SJason Wang ncs[i]->peer->link_down = true; 3871ceef9f2SJason Wang } 3881ceef9f2SJason Wang 389fd9400b3SPaolo Bonzini if (nc->peer->info->link_status_changed) { 390fd9400b3SPaolo Bonzini nc->peer->info->link_status_changed(nc->peer); 391fd9400b3SPaolo Bonzini } 3921ceef9f2SJason Wang 3931ceef9f2SJason Wang for (i = 0; i < queues; i++) { 3941ceef9f2SJason Wang qemu_cleanup_net_client(ncs[i]); 3951ceef9f2SJason Wang } 3961ceef9f2SJason Wang 397fd9400b3SPaolo Bonzini return; 398fd9400b3SPaolo Bonzini } 399fd9400b3SPaolo Bonzini 4001ceef9f2SJason Wang for (i = 0; i < queues; i++) { 4011ceef9f2SJason Wang qemu_cleanup_net_client(ncs[i]); 4021ceef9f2SJason Wang qemu_free_net_client(ncs[i]); 4031ceef9f2SJason Wang } 404948ecf21SJason Wang } 405948ecf21SJason Wang 406948ecf21SJason Wang void qemu_del_nic(NICState *nic) 407948ecf21SJason Wang { 408575a1c0eSJiri Pirko int i, queues = MAX(nic->conf->peers.queues, 1); 4091ceef9f2SJason Wang 4102bc22a58SShannon Zhao qemu_macaddr_set_free(&nic->conf->macaddr); 4112bc22a58SShannon Zhao 412fd9400b3SPaolo Bonzini /* If this is a peer NIC and peer has already been deleted, free it now. */ 413fd9400b3SPaolo Bonzini if (nic->peer_deleted) { 4141ceef9f2SJason Wang for (i = 0; i < queues; i++) { 4151ceef9f2SJason Wang qemu_free_net_client(qemu_get_subqueue(nic, i)->peer); 416fd9400b3SPaolo Bonzini } 417fd9400b3SPaolo Bonzini } 418fd9400b3SPaolo Bonzini 4191ceef9f2SJason Wang for (i = queues - 1; i >= 0; i--) { 4201ceef9f2SJason Wang NetClientState *nc = qemu_get_subqueue(nic, i); 4211ceef9f2SJason Wang 422fd9400b3SPaolo Bonzini qemu_cleanup_net_client(nc); 423fd9400b3SPaolo Bonzini qemu_free_net_client(nc); 424fd9400b3SPaolo Bonzini } 425f6b26cf2SJason Wang 426f6b26cf2SJason Wang g_free(nic); 4271ceef9f2SJason Wang } 428fd9400b3SPaolo Bonzini 429fd9400b3SPaolo Bonzini void qemu_foreach_nic(qemu_nic_foreach func, void *opaque) 430fd9400b3SPaolo Bonzini { 431fd9400b3SPaolo Bonzini NetClientState *nc; 432fd9400b3SPaolo Bonzini 433fd9400b3SPaolo Bonzini QTAILQ_FOREACH(nc, &net_clients, next) { 434f394b2e2SEric Blake if (nc->info->type == NET_CLIENT_DRIVER_NIC) { 4351ceef9f2SJason Wang if (nc->queue_index == 0) { 436cc1f0f45SJason Wang func(qemu_get_nic(nc), opaque); 437fd9400b3SPaolo Bonzini } 438fd9400b3SPaolo Bonzini } 439fd9400b3SPaolo Bonzini } 4401ceef9f2SJason Wang } 441fd9400b3SPaolo Bonzini 442d6085e3aSStefan Hajnoczi bool qemu_has_ufo(NetClientState *nc) 4431f55ac45SVincenzo Maffione { 444d6085e3aSStefan Hajnoczi if (!nc || !nc->info->has_ufo) { 4451f55ac45SVincenzo Maffione return false; 4461f55ac45SVincenzo Maffione } 4471f55ac45SVincenzo Maffione 448d6085e3aSStefan Hajnoczi return nc->info->has_ufo(nc); 4491f55ac45SVincenzo Maffione } 4501f55ac45SVincenzo Maffione 451d6085e3aSStefan Hajnoczi bool qemu_has_vnet_hdr(NetClientState *nc) 4521f55ac45SVincenzo Maffione { 453d6085e3aSStefan Hajnoczi if (!nc || !nc->info->has_vnet_hdr) { 4541f55ac45SVincenzo Maffione return false; 4551f55ac45SVincenzo Maffione } 4561f55ac45SVincenzo Maffione 457d6085e3aSStefan Hajnoczi return nc->info->has_vnet_hdr(nc); 4581f55ac45SVincenzo Maffione } 4591f55ac45SVincenzo Maffione 460d6085e3aSStefan Hajnoczi bool qemu_has_vnet_hdr_len(NetClientState *nc, int len) 4611f55ac45SVincenzo Maffione { 462d6085e3aSStefan Hajnoczi if (!nc || !nc->info->has_vnet_hdr_len) { 4631f55ac45SVincenzo Maffione return false; 4641f55ac45SVincenzo Maffione } 4651f55ac45SVincenzo Maffione 466d6085e3aSStefan Hajnoczi return nc->info->has_vnet_hdr_len(nc, len); 4671f55ac45SVincenzo Maffione } 4681f55ac45SVincenzo Maffione 469d6085e3aSStefan Hajnoczi void qemu_using_vnet_hdr(NetClientState *nc, bool enable) 4701f55ac45SVincenzo Maffione { 471d6085e3aSStefan Hajnoczi if (!nc || !nc->info->using_vnet_hdr) { 4721f55ac45SVincenzo Maffione return; 4731f55ac45SVincenzo Maffione } 4741f55ac45SVincenzo Maffione 475d6085e3aSStefan Hajnoczi nc->info->using_vnet_hdr(nc, enable); 4761f55ac45SVincenzo Maffione } 4771f55ac45SVincenzo Maffione 478d6085e3aSStefan Hajnoczi void qemu_set_offload(NetClientState *nc, int csum, int tso4, int tso6, 4791f55ac45SVincenzo Maffione int ecn, int ufo) 4801f55ac45SVincenzo Maffione { 481d6085e3aSStefan Hajnoczi if (!nc || !nc->info->set_offload) { 4821f55ac45SVincenzo Maffione return; 4831f55ac45SVincenzo Maffione } 4841f55ac45SVincenzo Maffione 485d6085e3aSStefan Hajnoczi nc->info->set_offload(nc, csum, tso4, tso6, ecn, ufo); 4861f55ac45SVincenzo Maffione } 4871f55ac45SVincenzo Maffione 488d6085e3aSStefan Hajnoczi void qemu_set_vnet_hdr_len(NetClientState *nc, int len) 4891f55ac45SVincenzo Maffione { 490d6085e3aSStefan Hajnoczi if (!nc || !nc->info->set_vnet_hdr_len) { 4911f55ac45SVincenzo Maffione return; 4921f55ac45SVincenzo Maffione } 4931f55ac45SVincenzo Maffione 494d6085e3aSStefan Hajnoczi nc->info->set_vnet_hdr_len(nc, len); 4951f55ac45SVincenzo Maffione } 4961f55ac45SVincenzo Maffione 497c80cd6bbSGreg Kurz int qemu_set_vnet_le(NetClientState *nc, bool is_le) 498c80cd6bbSGreg Kurz { 499052bd52fSMichael S. Tsirkin #ifdef HOST_WORDS_BIGENDIAN 500c80cd6bbSGreg Kurz if (!nc || !nc->info->set_vnet_le) { 501c80cd6bbSGreg Kurz return -ENOSYS; 502c80cd6bbSGreg Kurz } 503c80cd6bbSGreg Kurz 504c80cd6bbSGreg Kurz return nc->info->set_vnet_le(nc, is_le); 505052bd52fSMichael S. Tsirkin #else 506052bd52fSMichael S. Tsirkin return 0; 507052bd52fSMichael S. Tsirkin #endif 508c80cd6bbSGreg Kurz } 509c80cd6bbSGreg Kurz 510c80cd6bbSGreg Kurz int qemu_set_vnet_be(NetClientState *nc, bool is_be) 511c80cd6bbSGreg Kurz { 512052bd52fSMichael S. Tsirkin #ifdef HOST_WORDS_BIGENDIAN 513052bd52fSMichael S. Tsirkin return 0; 514052bd52fSMichael S. Tsirkin #else 515c80cd6bbSGreg Kurz if (!nc || !nc->info->set_vnet_be) { 516c80cd6bbSGreg Kurz return -ENOSYS; 517c80cd6bbSGreg Kurz } 518c80cd6bbSGreg Kurz 519c80cd6bbSGreg Kurz return nc->info->set_vnet_be(nc, is_be); 520052bd52fSMichael S. Tsirkin #endif 521c80cd6bbSGreg Kurz } 522c80cd6bbSGreg Kurz 523fd9400b3SPaolo Bonzini int qemu_can_send_packet(NetClientState *sender) 524fd9400b3SPaolo Bonzini { 525e1d64c08Szhanghailiang int vm_running = runstate_is_running(); 526e1d64c08Szhanghailiang 527e1d64c08Szhanghailiang if (!vm_running) { 528e1d64c08Szhanghailiang return 0; 529e1d64c08Szhanghailiang } 530e1d64c08Szhanghailiang 531fd9400b3SPaolo Bonzini if (!sender->peer) { 532fd9400b3SPaolo Bonzini return 1; 533fd9400b3SPaolo Bonzini } 534fd9400b3SPaolo Bonzini 535fd9400b3SPaolo Bonzini if (sender->peer->receive_disabled) { 536fd9400b3SPaolo Bonzini return 0; 537fd9400b3SPaolo Bonzini } else if (sender->peer->info->can_receive && 538fd9400b3SPaolo Bonzini !sender->peer->info->can_receive(sender->peer)) { 539fd9400b3SPaolo Bonzini return 0; 540fd9400b3SPaolo Bonzini } 541fd9400b3SPaolo Bonzini return 1; 542fd9400b3SPaolo Bonzini } 543fd9400b3SPaolo Bonzini 544e64c770dSYang Hongyang static ssize_t filter_receive_iov(NetClientState *nc, 545e64c770dSYang Hongyang NetFilterDirection direction, 546e64c770dSYang Hongyang NetClientState *sender, 547e64c770dSYang Hongyang unsigned flags, 548e64c770dSYang Hongyang const struct iovec *iov, 549e64c770dSYang Hongyang int iovcnt, 550e64c770dSYang Hongyang NetPacketSent *sent_cb) 551e64c770dSYang Hongyang { 552e64c770dSYang Hongyang ssize_t ret = 0; 553e64c770dSYang Hongyang NetFilterState *nf = NULL; 554e64c770dSYang Hongyang 55525aaadf0SLi Zhijian if (direction == NET_FILTER_DIRECTION_TX) { 556e64c770dSYang Hongyang QTAILQ_FOREACH(nf, &nc->filters, next) { 557e64c770dSYang Hongyang ret = qemu_netfilter_receive(nf, direction, sender, flags, iov, 558e64c770dSYang Hongyang iovcnt, sent_cb); 559e64c770dSYang Hongyang if (ret) { 560e64c770dSYang Hongyang return ret; 561e64c770dSYang Hongyang } 562e64c770dSYang Hongyang } 56325aaadf0SLi Zhijian } else { 56425aaadf0SLi Zhijian QTAILQ_FOREACH_REVERSE(nf, &nc->filters, NetFilterHead, next) { 56525aaadf0SLi Zhijian ret = qemu_netfilter_receive(nf, direction, sender, flags, iov, 56625aaadf0SLi Zhijian iovcnt, sent_cb); 56725aaadf0SLi Zhijian if (ret) { 56825aaadf0SLi Zhijian return ret; 56925aaadf0SLi Zhijian } 57025aaadf0SLi Zhijian } 57125aaadf0SLi Zhijian } 572e64c770dSYang Hongyang 573e64c770dSYang Hongyang return ret; 574e64c770dSYang Hongyang } 575e64c770dSYang Hongyang 576e64c770dSYang Hongyang static ssize_t filter_receive(NetClientState *nc, 577e64c770dSYang Hongyang NetFilterDirection direction, 578e64c770dSYang Hongyang NetClientState *sender, 579e64c770dSYang Hongyang unsigned flags, 580e64c770dSYang Hongyang const uint8_t *data, 581e64c770dSYang Hongyang size_t size, 582e64c770dSYang Hongyang NetPacketSent *sent_cb) 583e64c770dSYang Hongyang { 584e64c770dSYang Hongyang struct iovec iov = { 585e64c770dSYang Hongyang .iov_base = (void *)data, 586e64c770dSYang Hongyang .iov_len = size 587e64c770dSYang Hongyang }; 588e64c770dSYang Hongyang 589e64c770dSYang Hongyang return filter_receive_iov(nc, direction, sender, flags, &iov, 1, sent_cb); 590e64c770dSYang Hongyang } 591e64c770dSYang Hongyang 592fd9400b3SPaolo Bonzini void qemu_purge_queued_packets(NetClientState *nc) 593fd9400b3SPaolo Bonzini { 594fd9400b3SPaolo Bonzini if (!nc->peer) { 595fd9400b3SPaolo Bonzini return; 596fd9400b3SPaolo Bonzini } 597fd9400b3SPaolo Bonzini 598067404beSJan Kiszka qemu_net_queue_purge(nc->peer->incoming_queue, nc); 599fd9400b3SPaolo Bonzini } 600fd9400b3SPaolo Bonzini 601ca77d85eSMichael S. Tsirkin static 602ca77d85eSMichael S. Tsirkin void qemu_flush_or_purge_queued_packets(NetClientState *nc, bool purge) 603fd9400b3SPaolo Bonzini { 604fd9400b3SPaolo Bonzini nc->receive_disabled = 0; 605fd9400b3SPaolo Bonzini 606f394b2e2SEric Blake if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_HUBPORT) { 607199ee608SLuigi Rizzo if (net_hub_flush(nc->peer)) { 608199ee608SLuigi Rizzo qemu_notify_event(); 609199ee608SLuigi Rizzo } 610199ee608SLuigi Rizzo } 611067404beSJan Kiszka if (qemu_net_queue_flush(nc->incoming_queue)) { 612fd9400b3SPaolo Bonzini /* We emptied the queue successfully, signal to the IO thread to repoll 613fd9400b3SPaolo Bonzini * the file descriptor (for tap, for example). 614fd9400b3SPaolo Bonzini */ 615fd9400b3SPaolo Bonzini qemu_notify_event(); 616ca77d85eSMichael S. Tsirkin } else if (purge) { 617ca77d85eSMichael S. Tsirkin /* Unable to empty the queue, purge remaining packets */ 618ca77d85eSMichael S. Tsirkin qemu_net_queue_purge(nc->incoming_queue, nc); 619fd9400b3SPaolo Bonzini } 620fd9400b3SPaolo Bonzini } 621fd9400b3SPaolo Bonzini 622ca77d85eSMichael S. Tsirkin void qemu_flush_queued_packets(NetClientState *nc) 623ca77d85eSMichael S. Tsirkin { 624ca77d85eSMichael S. Tsirkin qemu_flush_or_purge_queued_packets(nc, false); 625ca77d85eSMichael S. Tsirkin } 626ca77d85eSMichael S. Tsirkin 627fd9400b3SPaolo Bonzini static ssize_t qemu_send_packet_async_with_flags(NetClientState *sender, 628fd9400b3SPaolo Bonzini unsigned flags, 629fd9400b3SPaolo Bonzini const uint8_t *buf, int size, 630fd9400b3SPaolo Bonzini NetPacketSent *sent_cb) 631fd9400b3SPaolo Bonzini { 632fd9400b3SPaolo Bonzini NetQueue *queue; 633e64c770dSYang Hongyang int ret; 634fd9400b3SPaolo Bonzini 635fd9400b3SPaolo Bonzini #ifdef DEBUG_NET 636fd9400b3SPaolo Bonzini printf("qemu_send_packet_async:\n"); 637a1555559SIsaac Lozano qemu_hexdump((const char *)buf, stdout, "net", size); 638fd9400b3SPaolo Bonzini #endif 639fd9400b3SPaolo Bonzini 640fd9400b3SPaolo Bonzini if (sender->link_down || !sender->peer) { 641fd9400b3SPaolo Bonzini return size; 642fd9400b3SPaolo Bonzini } 643fd9400b3SPaolo Bonzini 644e64c770dSYang Hongyang /* Let filters handle the packet first */ 645e64c770dSYang Hongyang ret = filter_receive(sender, NET_FILTER_DIRECTION_TX, 646e64c770dSYang Hongyang sender, flags, buf, size, sent_cb); 647e64c770dSYang Hongyang if (ret) { 648e64c770dSYang Hongyang return ret; 649e64c770dSYang Hongyang } 650e64c770dSYang Hongyang 651e64c770dSYang Hongyang ret = filter_receive(sender->peer, NET_FILTER_DIRECTION_RX, 652e64c770dSYang Hongyang sender, flags, buf, size, sent_cb); 653e64c770dSYang Hongyang if (ret) { 654e64c770dSYang Hongyang return ret; 655e64c770dSYang Hongyang } 656e64c770dSYang Hongyang 657067404beSJan Kiszka queue = sender->peer->incoming_queue; 658fd9400b3SPaolo Bonzini 659fd9400b3SPaolo Bonzini return qemu_net_queue_send(queue, sender, flags, buf, size, sent_cb); 660fd9400b3SPaolo Bonzini } 661fd9400b3SPaolo Bonzini 662fd9400b3SPaolo Bonzini ssize_t qemu_send_packet_async(NetClientState *sender, 663fd9400b3SPaolo Bonzini const uint8_t *buf, int size, 664fd9400b3SPaolo Bonzini NetPacketSent *sent_cb) 665fd9400b3SPaolo Bonzini { 666fd9400b3SPaolo Bonzini return qemu_send_packet_async_with_flags(sender, QEMU_NET_PACKET_FLAG_NONE, 667fd9400b3SPaolo Bonzini buf, size, sent_cb); 668fd9400b3SPaolo Bonzini } 669fd9400b3SPaolo Bonzini 670fd9400b3SPaolo Bonzini void qemu_send_packet(NetClientState *nc, const uint8_t *buf, int size) 671fd9400b3SPaolo Bonzini { 672fd9400b3SPaolo Bonzini qemu_send_packet_async(nc, buf, size, NULL); 673fd9400b3SPaolo Bonzini } 674fd9400b3SPaolo Bonzini 675fd9400b3SPaolo Bonzini ssize_t qemu_send_packet_raw(NetClientState *nc, const uint8_t *buf, int size) 676fd9400b3SPaolo Bonzini { 677fd9400b3SPaolo Bonzini return qemu_send_packet_async_with_flags(nc, QEMU_NET_PACKET_FLAG_RAW, 678fd9400b3SPaolo Bonzini buf, size, NULL); 679fd9400b3SPaolo Bonzini } 680fd9400b3SPaolo Bonzini 681fd9400b3SPaolo Bonzini static ssize_t nc_sendv_compat(NetClientState *nc, const struct iovec *iov, 682fefe2a78SYang Hongyang int iovcnt, unsigned flags) 683fd9400b3SPaolo Bonzini { 68474044c8fSPooja Dhannawat uint8_t *buf = NULL; 685fefe2a78SYang Hongyang uint8_t *buffer; 686fd9400b3SPaolo Bonzini size_t offset; 68774044c8fSPooja Dhannawat ssize_t ret; 688fd9400b3SPaolo Bonzini 689fefe2a78SYang Hongyang if (iovcnt == 1) { 690fefe2a78SYang Hongyang buffer = iov[0].iov_base; 691fefe2a78SYang Hongyang offset = iov[0].iov_len; 692fefe2a78SYang Hongyang } else { 693*47f9f158SPeter Lieven offset = iov_size(iov, iovcnt); 694*47f9f158SPeter Lieven if (offset > NET_BUFSIZE) { 695*47f9f158SPeter Lieven return -1; 696*47f9f158SPeter Lieven } 697*47f9f158SPeter Lieven buf = g_malloc(offset); 698fefe2a78SYang Hongyang buffer = buf; 699*47f9f158SPeter Lieven offset = iov_to_buf(iov, iovcnt, 0, buf, offset); 700fefe2a78SYang Hongyang } 701fd9400b3SPaolo Bonzini 702fefe2a78SYang Hongyang if (flags & QEMU_NET_PACKET_FLAG_RAW && nc->info->receive_raw) { 70374044c8fSPooja Dhannawat ret = nc->info->receive_raw(nc, buffer, offset); 704fefe2a78SYang Hongyang } else { 70574044c8fSPooja Dhannawat ret = nc->info->receive(nc, buffer, offset); 706fd9400b3SPaolo Bonzini } 70774044c8fSPooja Dhannawat 70874044c8fSPooja Dhannawat g_free(buf); 70974044c8fSPooja Dhannawat return ret; 710fefe2a78SYang Hongyang } 711fd9400b3SPaolo Bonzini 712fd9400b3SPaolo Bonzini ssize_t qemu_deliver_packet_iov(NetClientState *sender, 713fd9400b3SPaolo Bonzini unsigned flags, 714fd9400b3SPaolo Bonzini const struct iovec *iov, 715fd9400b3SPaolo Bonzini int iovcnt, 716fd9400b3SPaolo Bonzini void *opaque) 717fd9400b3SPaolo Bonzini { 718fd9400b3SPaolo Bonzini NetClientState *nc = opaque; 719fd9400b3SPaolo Bonzini int ret; 720fd9400b3SPaolo Bonzini 721fd9400b3SPaolo Bonzini if (nc->link_down) { 722fd9400b3SPaolo Bonzini return iov_size(iov, iovcnt); 723fd9400b3SPaolo Bonzini } 724fd9400b3SPaolo Bonzini 725fd9400b3SPaolo Bonzini if (nc->receive_disabled) { 726fd9400b3SPaolo Bonzini return 0; 727fd9400b3SPaolo Bonzini } 728fd9400b3SPaolo Bonzini 729ca1ee3d6SPeter Lieven if (nc->info->receive_iov && !(flags & QEMU_NET_PACKET_FLAG_RAW)) { 730fd9400b3SPaolo Bonzini ret = nc->info->receive_iov(nc, iov, iovcnt); 731fd9400b3SPaolo Bonzini } else { 732fefe2a78SYang Hongyang ret = nc_sendv_compat(nc, iov, iovcnt, flags); 733fd9400b3SPaolo Bonzini } 734fd9400b3SPaolo Bonzini 735fd9400b3SPaolo Bonzini if (ret == 0) { 736fd9400b3SPaolo Bonzini nc->receive_disabled = 1; 737fd9400b3SPaolo Bonzini } 738fd9400b3SPaolo Bonzini 739fd9400b3SPaolo Bonzini return ret; 740fd9400b3SPaolo Bonzini } 741fd9400b3SPaolo Bonzini 742fd9400b3SPaolo Bonzini ssize_t qemu_sendv_packet_async(NetClientState *sender, 743fd9400b3SPaolo Bonzini const struct iovec *iov, int iovcnt, 744fd9400b3SPaolo Bonzini NetPacketSent *sent_cb) 745fd9400b3SPaolo Bonzini { 746fd9400b3SPaolo Bonzini NetQueue *queue; 747e64c770dSYang Hongyang int ret; 748fd9400b3SPaolo Bonzini 749fd9400b3SPaolo Bonzini if (sender->link_down || !sender->peer) { 750fd9400b3SPaolo Bonzini return iov_size(iov, iovcnt); 751fd9400b3SPaolo Bonzini } 752fd9400b3SPaolo Bonzini 753e64c770dSYang Hongyang /* Let filters handle the packet first */ 754e64c770dSYang Hongyang ret = filter_receive_iov(sender, NET_FILTER_DIRECTION_TX, sender, 755e64c770dSYang Hongyang QEMU_NET_PACKET_FLAG_NONE, iov, iovcnt, sent_cb); 756e64c770dSYang Hongyang if (ret) { 757e64c770dSYang Hongyang return ret; 758e64c770dSYang Hongyang } 759e64c770dSYang Hongyang 760e64c770dSYang Hongyang ret = filter_receive_iov(sender->peer, NET_FILTER_DIRECTION_RX, sender, 761e64c770dSYang Hongyang QEMU_NET_PACKET_FLAG_NONE, iov, iovcnt, sent_cb); 762e64c770dSYang Hongyang if (ret) { 763e64c770dSYang Hongyang return ret; 764e64c770dSYang Hongyang } 765e64c770dSYang Hongyang 766067404beSJan Kiszka queue = sender->peer->incoming_queue; 767fd9400b3SPaolo Bonzini 768fd9400b3SPaolo Bonzini return qemu_net_queue_send_iov(queue, sender, 769fd9400b3SPaolo Bonzini QEMU_NET_PACKET_FLAG_NONE, 770fd9400b3SPaolo Bonzini iov, iovcnt, sent_cb); 771fd9400b3SPaolo Bonzini } 772fd9400b3SPaolo Bonzini 773fd9400b3SPaolo Bonzini ssize_t 774fd9400b3SPaolo Bonzini qemu_sendv_packet(NetClientState *nc, const struct iovec *iov, int iovcnt) 775fd9400b3SPaolo Bonzini { 776fd9400b3SPaolo Bonzini return qemu_sendv_packet_async(nc, iov, iovcnt, NULL); 777fd9400b3SPaolo Bonzini } 778fd9400b3SPaolo Bonzini 779fd9400b3SPaolo Bonzini NetClientState *qemu_find_netdev(const char *id) 780fd9400b3SPaolo Bonzini { 781fd9400b3SPaolo Bonzini NetClientState *nc; 782fd9400b3SPaolo Bonzini 783fd9400b3SPaolo Bonzini QTAILQ_FOREACH(nc, &net_clients, next) { 784f394b2e2SEric Blake if (nc->info->type == NET_CLIENT_DRIVER_NIC) 785fd9400b3SPaolo Bonzini continue; 786fd9400b3SPaolo Bonzini if (!strcmp(nc->name, id)) { 787fd9400b3SPaolo Bonzini return nc; 788fd9400b3SPaolo Bonzini } 789fd9400b3SPaolo Bonzini } 790fd9400b3SPaolo Bonzini 791fd9400b3SPaolo Bonzini return NULL; 792fd9400b3SPaolo Bonzini } 793fd9400b3SPaolo Bonzini 7946c51ae73SJason Wang int qemu_find_net_clients_except(const char *id, NetClientState **ncs, 795f394b2e2SEric Blake NetClientDriver type, int max) 7966c51ae73SJason Wang { 7976c51ae73SJason Wang NetClientState *nc; 7986c51ae73SJason Wang int ret = 0; 7996c51ae73SJason Wang 8006c51ae73SJason Wang QTAILQ_FOREACH(nc, &net_clients, next) { 8016c51ae73SJason Wang if (nc->info->type == type) { 8026c51ae73SJason Wang continue; 8036c51ae73SJason Wang } 80440d19394SHani Benhabiles if (!id || !strcmp(nc->name, id)) { 8056c51ae73SJason Wang if (ret < max) { 8066c51ae73SJason Wang ncs[ret] = nc; 8076c51ae73SJason Wang } 8086c51ae73SJason Wang ret++; 8096c51ae73SJason Wang } 8106c51ae73SJason Wang } 8116c51ae73SJason Wang 8126c51ae73SJason Wang return ret; 8136c51ae73SJason Wang } 8146c51ae73SJason Wang 815fd9400b3SPaolo Bonzini static int nic_get_free_idx(void) 816fd9400b3SPaolo Bonzini { 817fd9400b3SPaolo Bonzini int index; 818fd9400b3SPaolo Bonzini 819fd9400b3SPaolo Bonzini for (index = 0; index < MAX_NICS; index++) 820fd9400b3SPaolo Bonzini if (!nd_table[index].used) 821fd9400b3SPaolo Bonzini return index; 822fd9400b3SPaolo Bonzini return -1; 823fd9400b3SPaolo Bonzini } 824fd9400b3SPaolo Bonzini 825fd9400b3SPaolo Bonzini int qemu_show_nic_models(const char *arg, const char *const *models) 826fd9400b3SPaolo Bonzini { 827fd9400b3SPaolo Bonzini int i; 828fd9400b3SPaolo Bonzini 829fd9400b3SPaolo Bonzini if (!arg || !is_help_option(arg)) { 830fd9400b3SPaolo Bonzini return 0; 831fd9400b3SPaolo Bonzini } 832fd9400b3SPaolo Bonzini 833fd9400b3SPaolo Bonzini fprintf(stderr, "qemu: Supported NIC models: "); 834fd9400b3SPaolo Bonzini for (i = 0 ; models[i]; i++) 835fd9400b3SPaolo Bonzini fprintf(stderr, "%s%c", models[i], models[i+1] ? ',' : '\n'); 836fd9400b3SPaolo Bonzini return 1; 837fd9400b3SPaolo Bonzini } 838fd9400b3SPaolo Bonzini 839fd9400b3SPaolo Bonzini void qemu_check_nic_model(NICInfo *nd, const char *model) 840fd9400b3SPaolo Bonzini { 841fd9400b3SPaolo Bonzini const char *models[2]; 842fd9400b3SPaolo Bonzini 843fd9400b3SPaolo Bonzini models[0] = model; 844fd9400b3SPaolo Bonzini models[1] = NULL; 845fd9400b3SPaolo Bonzini 846fd9400b3SPaolo Bonzini if (qemu_show_nic_models(nd->model, models)) 847fd9400b3SPaolo Bonzini exit(0); 848fd9400b3SPaolo Bonzini if (qemu_find_nic_model(nd, models, model) < 0) 849fd9400b3SPaolo Bonzini exit(1); 850fd9400b3SPaolo Bonzini } 851fd9400b3SPaolo Bonzini 852fd9400b3SPaolo Bonzini int qemu_find_nic_model(NICInfo *nd, const char * const *models, 853fd9400b3SPaolo Bonzini const char *default_model) 854fd9400b3SPaolo Bonzini { 855fd9400b3SPaolo Bonzini int i; 856fd9400b3SPaolo Bonzini 857fd9400b3SPaolo Bonzini if (!nd->model) 858fd9400b3SPaolo Bonzini nd->model = g_strdup(default_model); 859fd9400b3SPaolo Bonzini 860fd9400b3SPaolo Bonzini for (i = 0 ; models[i]; i++) { 861fd9400b3SPaolo Bonzini if (strcmp(nd->model, models[i]) == 0) 862fd9400b3SPaolo Bonzini return i; 863fd9400b3SPaolo Bonzini } 864fd9400b3SPaolo Bonzini 865fd9400b3SPaolo Bonzini error_report("Unsupported NIC model: %s", nd->model); 866fd9400b3SPaolo Bonzini return -1; 867fd9400b3SPaolo Bonzini } 868fd9400b3SPaolo Bonzini 869cebea510SKővágó, Zoltán static int net_init_nic(const Netdev *netdev, const char *name, 870a30ecde6SMarkus Armbruster NetClientState *peer, Error **errp) 871fd9400b3SPaolo Bonzini { 872fd9400b3SPaolo Bonzini int idx; 873fd9400b3SPaolo Bonzini NICInfo *nd; 874fd9400b3SPaolo Bonzini const NetLegacyNicOptions *nic; 875fd9400b3SPaolo Bonzini 876f394b2e2SEric Blake assert(netdev->type == NET_CLIENT_DRIVER_NIC); 877f394b2e2SEric Blake nic = &netdev->u.nic; 878fd9400b3SPaolo Bonzini 879fd9400b3SPaolo Bonzini idx = nic_get_free_idx(); 880fd9400b3SPaolo Bonzini if (idx == -1 || nb_nics >= MAX_NICS) { 88166308868SMarkus Armbruster error_setg(errp, "too many NICs"); 882fd9400b3SPaolo Bonzini return -1; 883fd9400b3SPaolo Bonzini } 884fd9400b3SPaolo Bonzini 885fd9400b3SPaolo Bonzini nd = &nd_table[idx]; 886fd9400b3SPaolo Bonzini 887fd9400b3SPaolo Bonzini memset(nd, 0, sizeof(*nd)); 888fd9400b3SPaolo Bonzini 889fd9400b3SPaolo Bonzini if (nic->has_netdev) { 890fd9400b3SPaolo Bonzini nd->netdev = qemu_find_netdev(nic->netdev); 891fd9400b3SPaolo Bonzini if (!nd->netdev) { 89266308868SMarkus Armbruster error_setg(errp, "netdev '%s' not found", nic->netdev); 893fd9400b3SPaolo Bonzini return -1; 894fd9400b3SPaolo Bonzini } 895fd9400b3SPaolo Bonzini } else { 896fd9400b3SPaolo Bonzini assert(peer); 897fd9400b3SPaolo Bonzini nd->netdev = peer; 898fd9400b3SPaolo Bonzini } 899fd9400b3SPaolo Bonzini nd->name = g_strdup(name); 900fd9400b3SPaolo Bonzini if (nic->has_model) { 901fd9400b3SPaolo Bonzini nd->model = g_strdup(nic->model); 902fd9400b3SPaolo Bonzini } 903fd9400b3SPaolo Bonzini if (nic->has_addr) { 904fd9400b3SPaolo Bonzini nd->devaddr = g_strdup(nic->addr); 905fd9400b3SPaolo Bonzini } 906fd9400b3SPaolo Bonzini 907fd9400b3SPaolo Bonzini if (nic->has_macaddr && 908fd9400b3SPaolo Bonzini net_parse_macaddr(nd->macaddr.a, nic->macaddr) < 0) { 90966308868SMarkus Armbruster error_setg(errp, "invalid syntax for ethernet address"); 910fd9400b3SPaolo Bonzini return -1; 911fd9400b3SPaolo Bonzini } 912d60b20cfSDmitry Krivenok if (nic->has_macaddr && 913d60b20cfSDmitry Krivenok is_multicast_ether_addr(nd->macaddr.a)) { 91466308868SMarkus Armbruster error_setg(errp, 91566308868SMarkus Armbruster "NIC cannot have multicast MAC address (odd 1st byte)"); 916d60b20cfSDmitry Krivenok return -1; 917d60b20cfSDmitry Krivenok } 918fd9400b3SPaolo Bonzini qemu_macaddr_default_if_unset(&nd->macaddr); 919fd9400b3SPaolo Bonzini 920fd9400b3SPaolo Bonzini if (nic->has_vectors) { 921fd9400b3SPaolo Bonzini if (nic->vectors > 0x7ffffff) { 92266308868SMarkus Armbruster error_setg(errp, "invalid # of vectors: %"PRIu32, nic->vectors); 923fd9400b3SPaolo Bonzini return -1; 924fd9400b3SPaolo Bonzini } 925fd9400b3SPaolo Bonzini nd->nvectors = nic->vectors; 926fd9400b3SPaolo Bonzini } else { 927fd9400b3SPaolo Bonzini nd->nvectors = DEV_NVECTORS_UNSPECIFIED; 928fd9400b3SPaolo Bonzini } 929fd9400b3SPaolo Bonzini 930fd9400b3SPaolo Bonzini nd->used = 1; 931fd9400b3SPaolo Bonzini nb_nics++; 932fd9400b3SPaolo Bonzini 933fd9400b3SPaolo Bonzini return idx; 934fd9400b3SPaolo Bonzini } 935fd9400b3SPaolo Bonzini 936fd9400b3SPaolo Bonzini 937f394b2e2SEric Blake static int (* const net_client_init_fun[NET_CLIENT_DRIVER__MAX])( 938cebea510SKővágó, Zoltán const Netdev *netdev, 939fd9400b3SPaolo Bonzini const char *name, 940a30ecde6SMarkus Armbruster NetClientState *peer, Error **errp) = { 941f394b2e2SEric Blake [NET_CLIENT_DRIVER_NIC] = net_init_nic, 942fd9400b3SPaolo Bonzini #ifdef CONFIG_SLIRP 943f394b2e2SEric Blake [NET_CLIENT_DRIVER_USER] = net_init_slirp, 944fd9400b3SPaolo Bonzini #endif 945f394b2e2SEric Blake [NET_CLIENT_DRIVER_TAP] = net_init_tap, 946f394b2e2SEric Blake [NET_CLIENT_DRIVER_SOCKET] = net_init_socket, 947fd9400b3SPaolo Bonzini #ifdef CONFIG_VDE 948f394b2e2SEric Blake [NET_CLIENT_DRIVER_VDE] = net_init_vde, 949fd9400b3SPaolo Bonzini #endif 95058952137SVincenzo Maffione #ifdef CONFIG_NETMAP 951f394b2e2SEric Blake [NET_CLIENT_DRIVER_NETMAP] = net_init_netmap, 95258952137SVincenzo Maffione #endif 953f394b2e2SEric Blake [NET_CLIENT_DRIVER_DUMP] = net_init_dump, 954fd9400b3SPaolo Bonzini #ifdef CONFIG_NET_BRIDGE 955f394b2e2SEric Blake [NET_CLIENT_DRIVER_BRIDGE] = net_init_bridge, 956fd9400b3SPaolo Bonzini #endif 957f394b2e2SEric Blake [NET_CLIENT_DRIVER_HUBPORT] = net_init_hubport, 95803ce5744SNikolay Nikolaev #ifdef CONFIG_VHOST_NET_USED 959f394b2e2SEric Blake [NET_CLIENT_DRIVER_VHOST_USER] = net_init_vhost_user, 96003ce5744SNikolay Nikolaev #endif 961015a33bdSGonglei #ifdef CONFIG_L2TPV3 962f394b2e2SEric Blake [NET_CLIENT_DRIVER_L2TPV3] = net_init_l2tpv3, 9633fb69aa1SAnton Ivanov #endif 964fd9400b3SPaolo Bonzini }; 965fd9400b3SPaolo Bonzini 966fd9400b3SPaolo Bonzini 9670e55c381SEric Blake static int net_client_init1(const void *object, bool is_netdev, Error **errp) 968fd9400b3SPaolo Bonzini { 969cebea510SKővágó, Zoltán Netdev legacy = {0}; 970cebea510SKővágó, Zoltán const Netdev *netdev; 971fd9400b3SPaolo Bonzini const char *name; 9724ef0defbSStefan Hajnoczi NetClientState *peer = NULL; 973fd9400b3SPaolo Bonzini 974fd9400b3SPaolo Bonzini if (is_netdev) { 975cebea510SKővágó, Zoltán netdev = object; 9761e81aba5SStefan Hajnoczi name = netdev->id; 977fd9400b3SPaolo Bonzini 978f394b2e2SEric Blake if (netdev->type == NET_CLIENT_DRIVER_DUMP || 979f394b2e2SEric Blake netdev->type == NET_CLIENT_DRIVER_NIC || 980f394b2e2SEric Blake !net_client_init_fun[netdev->type]) { 981c6bd8c70SMarkus Armbruster error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "type", 982fd9400b3SPaolo Bonzini "a netdev backend type"); 983fd9400b3SPaolo Bonzini return -1; 984fd9400b3SPaolo Bonzini } 985fd9400b3SPaolo Bonzini } else { 9861e81aba5SStefan Hajnoczi const NetLegacy *net = object; 987f394b2e2SEric Blake const NetLegacyOptions *opts = net->opts; 988cebea510SKővágó, Zoltán legacy.id = net->id; 989cebea510SKővágó, Zoltán netdev = &legacy; 9901e81aba5SStefan Hajnoczi /* missing optional values have been initialized to "all bits zero" */ 9911e81aba5SStefan Hajnoczi name = net->has_id ? net->id : net->name; 9921e81aba5SStefan Hajnoczi 993f394b2e2SEric Blake /* Map the old options to the new flat type */ 994f394b2e2SEric Blake switch (opts->type) { 995f394b2e2SEric Blake case NET_LEGACY_OPTIONS_KIND_NONE: 9961e81aba5SStefan Hajnoczi return 0; /* nothing to do */ 997f394b2e2SEric Blake case NET_LEGACY_OPTIONS_KIND_NIC: 998f394b2e2SEric Blake legacy.type = NET_CLIENT_DRIVER_NIC; 999f394b2e2SEric Blake legacy.u.nic = *opts->u.nic.data; 1000f394b2e2SEric Blake break; 1001f394b2e2SEric Blake case NET_LEGACY_OPTIONS_KIND_USER: 1002f394b2e2SEric Blake legacy.type = NET_CLIENT_DRIVER_USER; 1003f394b2e2SEric Blake legacy.u.user = *opts->u.user.data; 1004f394b2e2SEric Blake break; 1005f394b2e2SEric Blake case NET_LEGACY_OPTIONS_KIND_TAP: 1006f394b2e2SEric Blake legacy.type = NET_CLIENT_DRIVER_TAP; 1007f394b2e2SEric Blake legacy.u.tap = *opts->u.tap.data; 1008f394b2e2SEric Blake break; 1009f394b2e2SEric Blake case NET_LEGACY_OPTIONS_KIND_L2TPV3: 1010f394b2e2SEric Blake legacy.type = NET_CLIENT_DRIVER_L2TPV3; 1011f394b2e2SEric Blake legacy.u.l2tpv3 = *opts->u.l2tpv3.data; 1012f394b2e2SEric Blake break; 1013f394b2e2SEric Blake case NET_LEGACY_OPTIONS_KIND_SOCKET: 1014f394b2e2SEric Blake legacy.type = NET_CLIENT_DRIVER_SOCKET; 1015f394b2e2SEric Blake legacy.u.socket = *opts->u.socket.data; 1016f394b2e2SEric Blake break; 1017f394b2e2SEric Blake case NET_LEGACY_OPTIONS_KIND_VDE: 1018f394b2e2SEric Blake legacy.type = NET_CLIENT_DRIVER_VDE; 1019f394b2e2SEric Blake legacy.u.vde = *opts->u.vde.data; 1020f394b2e2SEric Blake break; 1021f394b2e2SEric Blake case NET_LEGACY_OPTIONS_KIND_DUMP: 1022f394b2e2SEric Blake legacy.type = NET_CLIENT_DRIVER_DUMP; 1023f394b2e2SEric Blake legacy.u.dump = *opts->u.dump.data; 1024f394b2e2SEric Blake break; 1025f394b2e2SEric Blake case NET_LEGACY_OPTIONS_KIND_BRIDGE: 1026f394b2e2SEric Blake legacy.type = NET_CLIENT_DRIVER_BRIDGE; 1027f394b2e2SEric Blake legacy.u.bridge = *opts->u.bridge.data; 1028f394b2e2SEric Blake break; 1029f394b2e2SEric Blake case NET_LEGACY_OPTIONS_KIND_NETMAP: 1030f394b2e2SEric Blake legacy.type = NET_CLIENT_DRIVER_NETMAP; 1031f394b2e2SEric Blake legacy.u.netmap = *opts->u.netmap.data; 1032f394b2e2SEric Blake break; 1033f394b2e2SEric Blake case NET_LEGACY_OPTIONS_KIND_VHOST_USER: 1034f394b2e2SEric Blake legacy.type = NET_CLIENT_DRIVER_VHOST_USER; 1035f394b2e2SEric Blake legacy.u.vhost_user = *opts->u.vhost_user.data; 1036f394b2e2SEric Blake break; 1037f394b2e2SEric Blake default: 1038f394b2e2SEric Blake abort(); 1039ca7eb184SMarkus Armbruster } 1040d139e9a6SStefan Hajnoczi 1041f394b2e2SEric Blake if (!net_client_init_fun[netdev->type]) { 1042d139e9a6SStefan Hajnoczi error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "type", 1043d139e9a6SStefan Hajnoczi "a net backend type (maybe it is not compiled " 1044d139e9a6SStefan Hajnoczi "into this binary)"); 1045d139e9a6SStefan Hajnoczi return -1; 1046d139e9a6SStefan Hajnoczi } 1047fd9400b3SPaolo Bonzini 10481e81aba5SStefan Hajnoczi /* Do not add to a vlan if it's a nic with a netdev= parameter. */ 1049f394b2e2SEric Blake if (netdev->type != NET_CLIENT_DRIVER_NIC || 105032bafa8fSEric Blake !opts->u.nic.data->has_netdev) { 10511e81aba5SStefan Hajnoczi peer = net_hub_add_port(net->has_vlan ? net->vlan : 0, NULL); 10521e81aba5SStefan Hajnoczi } 1053fd9400b3SPaolo Bonzini } 1054fd9400b3SPaolo Bonzini 1055f394b2e2SEric Blake if (net_client_init_fun[netdev->type](netdev, name, peer, errp) < 0) { 1056a30ecde6SMarkus Armbruster /* FIXME drop when all init functions store an Error */ 1057a30ecde6SMarkus Armbruster if (errp && !*errp) { 1058c6bd8c70SMarkus Armbruster error_setg(errp, QERR_DEVICE_INIT_FAILED, 1059f394b2e2SEric Blake NetClientDriver_lookup[netdev->type]); 1060a30ecde6SMarkus Armbruster } 1061fd9400b3SPaolo Bonzini return -1; 1062fd9400b3SPaolo Bonzini } 1063fd9400b3SPaolo Bonzini return 0; 1064fd9400b3SPaolo Bonzini } 1065fd9400b3SPaolo Bonzini 1066fd9400b3SPaolo Bonzini 10670e55c381SEric Blake int net_client_init(QemuOpts *opts, bool is_netdev, Error **errp) 1068fd9400b3SPaolo Bonzini { 1069fd9400b3SPaolo Bonzini void *object = NULL; 1070fd9400b3SPaolo Bonzini Error *err = NULL; 1071fd9400b3SPaolo Bonzini int ret = -1; 107209204eacSEric Blake Visitor *v = opts_visitor_new(opts); 1073fd9400b3SPaolo Bonzini 10747aac531eSYann Bordenave { 10757aac531eSYann Bordenave /* Parse convenience option format ip6-net=fec0::0[/64] */ 1076891a2bb5SSamuel Thibault const char *ip6_net = qemu_opt_get(opts, "ipv6-net"); 10777aac531eSYann Bordenave 10787aac531eSYann Bordenave if (ip6_net) { 10797aac531eSYann Bordenave char buf[strlen(ip6_net) + 1]; 10807aac531eSYann Bordenave 10817aac531eSYann Bordenave if (get_str_sep(buf, sizeof(buf), &ip6_net, '/') < 0) { 10827aac531eSYann Bordenave /* Default 64bit prefix length. */ 1083891a2bb5SSamuel Thibault qemu_opt_set(opts, "ipv6-prefix", ip6_net, &error_abort); 1084891a2bb5SSamuel Thibault qemu_opt_set_number(opts, "ipv6-prefixlen", 64, &error_abort); 10857aac531eSYann Bordenave } else { 10867aac531eSYann Bordenave /* User-specified prefix length. */ 10877aac531eSYann Bordenave unsigned long len; 10887aac531eSYann Bordenave int err; 10897aac531eSYann Bordenave 1090891a2bb5SSamuel Thibault qemu_opt_set(opts, "ipv6-prefix", buf, &error_abort); 10917aac531eSYann Bordenave err = qemu_strtoul(ip6_net, NULL, 10, &len); 10927aac531eSYann Bordenave 10937aac531eSYann Bordenave if (err) { 10947aac531eSYann Bordenave error_setg(errp, QERR_INVALID_PARAMETER_VALUE, 1095891a2bb5SSamuel Thibault "ipv6-prefix", "a number"); 10967aac531eSYann Bordenave } else { 1097891a2bb5SSamuel Thibault qemu_opt_set_number(opts, "ipv6-prefixlen", len, 10987aac531eSYann Bordenave &error_abort); 10997aac531eSYann Bordenave } 11007aac531eSYann Bordenave } 1101891a2bb5SSamuel Thibault qemu_opt_unset(opts, "ipv6-net"); 11027aac531eSYann Bordenave } 11037aac531eSYann Bordenave } 11047aac531eSYann Bordenave 110596a1616cSEric Blake if (is_netdev) { 110696a1616cSEric Blake visit_type_Netdev(v, NULL, (Netdev **)&object, &err); 110796a1616cSEric Blake } else { 110896a1616cSEric Blake visit_type_NetLegacy(v, NULL, (NetLegacy **)&object, &err); 1109fd9400b3SPaolo Bonzini } 1110fd9400b3SPaolo Bonzini 1111fd9400b3SPaolo Bonzini if (!err) { 1112fd9400b3SPaolo Bonzini ret = net_client_init1(object, is_netdev, &err); 1113fd9400b3SPaolo Bonzini } 1114fd9400b3SPaolo Bonzini 111596a1616cSEric Blake if (is_netdev) { 111696a1616cSEric Blake qapi_free_Netdev(object); 111796a1616cSEric Blake } else { 111896a1616cSEric Blake qapi_free_NetLegacy(object); 1119fd9400b3SPaolo Bonzini } 1120fd9400b3SPaolo Bonzini 1121fd9400b3SPaolo Bonzini error_propagate(errp, err); 112209204eacSEric Blake visit_free(v); 1123fd9400b3SPaolo Bonzini return ret; 1124fd9400b3SPaolo Bonzini } 1125fd9400b3SPaolo Bonzini 1126fd9400b3SPaolo Bonzini 1127fd9400b3SPaolo Bonzini static int net_host_check_device(const char *device) 1128fd9400b3SPaolo Bonzini { 1129fd9400b3SPaolo Bonzini int i; 113084007e81SHani Benhabiles for (i = 0; host_net_devices[i]; i++) { 113184007e81SHani Benhabiles if (!strncmp(host_net_devices[i], device, 113284007e81SHani Benhabiles strlen(host_net_devices[i]))) { 1133fd9400b3SPaolo Bonzini return 1; 1134fd9400b3SPaolo Bonzini } 113584007e81SHani Benhabiles } 1136fd9400b3SPaolo Bonzini 1137fd9400b3SPaolo Bonzini return 0; 1138fd9400b3SPaolo Bonzini } 1139fd9400b3SPaolo Bonzini 11403e5a50d6SMarkus Armbruster void hmp_host_net_add(Monitor *mon, const QDict *qdict) 1141fd9400b3SPaolo Bonzini { 1142fd9400b3SPaolo Bonzini const char *device = qdict_get_str(qdict, "device"); 1143fd9400b3SPaolo Bonzini const char *opts_str = qdict_get_try_str(qdict, "opts"); 1144fd9400b3SPaolo Bonzini Error *local_err = NULL; 1145fd9400b3SPaolo Bonzini QemuOpts *opts; 1146fd9400b3SPaolo Bonzini 1147fd9400b3SPaolo Bonzini if (!net_host_check_device(device)) { 1148fd9400b3SPaolo Bonzini monitor_printf(mon, "invalid host network device %s\n", device); 1149fd9400b3SPaolo Bonzini return; 1150fd9400b3SPaolo Bonzini } 1151fd9400b3SPaolo Bonzini 115270b94331SMarkus Armbruster opts = qemu_opts_parse_noisily(qemu_find_opts("net"), 115370b94331SMarkus Armbruster opts_str ? opts_str : "", false); 1154fd9400b3SPaolo Bonzini if (!opts) { 1155fd9400b3SPaolo Bonzini return; 1156fd9400b3SPaolo Bonzini } 1157fd9400b3SPaolo Bonzini 1158f43e47dbSMarkus Armbruster qemu_opt_set(opts, "type", device, &error_abort); 1159fd9400b3SPaolo Bonzini 11600e55c381SEric Blake net_client_init(opts, false, &local_err); 116184d18f06SMarkus Armbruster if (local_err) { 116212d0cc2dSMarkus Armbruster error_report_err(local_err); 1163fd9400b3SPaolo Bonzini monitor_printf(mon, "adding host network device %s failed\n", device); 1164fd9400b3SPaolo Bonzini } 1165fd9400b3SPaolo Bonzini } 1166fd9400b3SPaolo Bonzini 11673e5a50d6SMarkus Armbruster void hmp_host_net_remove(Monitor *mon, const QDict *qdict) 1168fd9400b3SPaolo Bonzini { 1169fd9400b3SPaolo Bonzini NetClientState *nc; 1170fd9400b3SPaolo Bonzini int vlan_id = qdict_get_int(qdict, "vlan_id"); 1171fd9400b3SPaolo Bonzini const char *device = qdict_get_str(qdict, "device"); 1172fd9400b3SPaolo Bonzini 1173fd9400b3SPaolo Bonzini nc = net_hub_find_client_by_name(vlan_id, device); 1174fd9400b3SPaolo Bonzini if (!nc) { 117586e11772SHani Benhabiles error_report("Host network device '%s' on hub '%d' not found", 117686e11772SHani Benhabiles device, vlan_id); 1177fd9400b3SPaolo Bonzini return; 1178fd9400b3SPaolo Bonzini } 1179f394b2e2SEric Blake if (nc->info->type == NET_CLIENT_DRIVER_NIC) { 118086e11772SHani Benhabiles error_report("invalid host network device '%s'", device); 1181fd9400b3SPaolo Bonzini return; 1182fd9400b3SPaolo Bonzini } 118364a55d60SJason Wang 118464a55d60SJason Wang qemu_del_net_client(nc->peer); 1185fd9400b3SPaolo Bonzini qemu_del_net_client(nc); 1186a4543b1bSShmulik Ladkani qemu_opts_del(qemu_opts_find(qemu_find_opts("net"), device)); 1187fd9400b3SPaolo Bonzini } 1188fd9400b3SPaolo Bonzini 1189fd9400b3SPaolo Bonzini void netdev_add(QemuOpts *opts, Error **errp) 1190fd9400b3SPaolo Bonzini { 11910e55c381SEric Blake net_client_init(opts, true, errp); 1192fd9400b3SPaolo Bonzini } 1193fd9400b3SPaolo Bonzini 1194485febc6SMarkus Armbruster void qmp_netdev_add(QDict *qdict, QObject **ret, Error **errp) 1195fd9400b3SPaolo Bonzini { 1196fd9400b3SPaolo Bonzini Error *local_err = NULL; 1197fd9400b3SPaolo Bonzini QemuOptsList *opts_list; 1198fd9400b3SPaolo Bonzini QemuOpts *opts; 1199fd9400b3SPaolo Bonzini 1200fd9400b3SPaolo Bonzini opts_list = qemu_find_opts_err("netdev", &local_err); 120184d18f06SMarkus Armbruster if (local_err) { 1202485febc6SMarkus Armbruster goto out; 1203fd9400b3SPaolo Bonzini } 1204fd9400b3SPaolo Bonzini 1205fd9400b3SPaolo Bonzini opts = qemu_opts_from_qdict(opts_list, qdict, &local_err); 120684d18f06SMarkus Armbruster if (local_err) { 1207485febc6SMarkus Armbruster goto out; 1208fd9400b3SPaolo Bonzini } 1209fd9400b3SPaolo Bonzini 1210fd9400b3SPaolo Bonzini netdev_add(opts, &local_err); 121184d18f06SMarkus Armbruster if (local_err) { 1212fd9400b3SPaolo Bonzini qemu_opts_del(opts); 1213485febc6SMarkus Armbruster goto out; 1214fd9400b3SPaolo Bonzini } 1215fd9400b3SPaolo Bonzini 1216485febc6SMarkus Armbruster out: 1217485febc6SMarkus Armbruster error_propagate(errp, local_err); 1218fd9400b3SPaolo Bonzini } 1219fd9400b3SPaolo Bonzini 1220fd9400b3SPaolo Bonzini void qmp_netdev_del(const char *id, Error **errp) 1221fd9400b3SPaolo Bonzini { 1222fd9400b3SPaolo Bonzini NetClientState *nc; 1223fd9400b3SPaolo Bonzini QemuOpts *opts; 1224fd9400b3SPaolo Bonzini 1225fd9400b3SPaolo Bonzini nc = qemu_find_netdev(id); 1226fd9400b3SPaolo Bonzini if (!nc) { 122775158ebbSMarkus Armbruster error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 122875158ebbSMarkus Armbruster "Device '%s' not found", id); 1229fd9400b3SPaolo Bonzini return; 1230fd9400b3SPaolo Bonzini } 1231fd9400b3SPaolo Bonzini 1232fd9400b3SPaolo Bonzini opts = qemu_opts_find(qemu_find_opts_err("netdev", NULL), id); 1233fd9400b3SPaolo Bonzini if (!opts) { 1234fd9400b3SPaolo Bonzini error_setg(errp, "Device '%s' is not a netdev", id); 1235fd9400b3SPaolo Bonzini return; 1236fd9400b3SPaolo Bonzini } 1237fd9400b3SPaolo Bonzini 1238fd9400b3SPaolo Bonzini qemu_del_net_client(nc); 1239fd9400b3SPaolo Bonzini qemu_opts_del(opts); 1240fd9400b3SPaolo Bonzini } 1241fd9400b3SPaolo Bonzini 1242aa9156f4Szhanghailiang static void netfilter_print_info(Monitor *mon, NetFilterState *nf) 1243aa9156f4Szhanghailiang { 1244aa9156f4Szhanghailiang char *str; 1245aa9156f4Szhanghailiang ObjectProperty *prop; 1246aa9156f4Szhanghailiang ObjectPropertyIterator iter; 12473b098d56SEric Blake Visitor *v; 1248aa9156f4Szhanghailiang 1249aa9156f4Szhanghailiang /* generate info str */ 1250aa9156f4Szhanghailiang object_property_iter_init(&iter, OBJECT(nf)); 1251aa9156f4Szhanghailiang while ((prop = object_property_iter_next(&iter))) { 1252aa9156f4Szhanghailiang if (!strcmp(prop->name, "type")) { 1253aa9156f4Szhanghailiang continue; 1254aa9156f4Szhanghailiang } 12553b098d56SEric Blake v = string_output_visitor_new(false, &str); 12563b098d56SEric Blake object_property_get(OBJECT(nf), v, prop->name, NULL); 12573b098d56SEric Blake visit_complete(v, &str); 12583b098d56SEric Blake visit_free(v); 1259aa9156f4Szhanghailiang monitor_printf(mon, ",%s=%s", prop->name, str); 1260aa9156f4Szhanghailiang g_free(str); 1261aa9156f4Szhanghailiang } 1262aa9156f4Szhanghailiang monitor_printf(mon, "\n"); 1263aa9156f4Szhanghailiang } 1264aa9156f4Szhanghailiang 1265fd9400b3SPaolo Bonzini void print_net_client(Monitor *mon, NetClientState *nc) 1266fd9400b3SPaolo Bonzini { 1267a4960f52SYang Hongyang NetFilterState *nf; 1268a4960f52SYang Hongyang 12691ceef9f2SJason Wang monitor_printf(mon, "%s: index=%d,type=%s,%s\n", nc->name, 12701ceef9f2SJason Wang nc->queue_index, 1271f394b2e2SEric Blake NetClientDriver_lookup[nc->info->type], 12721ceef9f2SJason Wang nc->info_str); 1273a4960f52SYang Hongyang if (!QTAILQ_EMPTY(&nc->filters)) { 1274a4960f52SYang Hongyang monitor_printf(mon, "filters:\n"); 1275a4960f52SYang Hongyang } 1276a4960f52SYang Hongyang QTAILQ_FOREACH(nf, &nc->filters, next) { 1277a3e8a3f3SYang Hongyang char *path = object_get_canonical_path_component(OBJECT(nf)); 1278aa9156f4Szhanghailiang 1279aa9156f4Szhanghailiang monitor_printf(mon, " - %s: type=%s", path, 1280aa9156f4Szhanghailiang object_get_typename(OBJECT(nf))); 1281aa9156f4Szhanghailiang netfilter_print_info(mon, nf); 1282a3e8a3f3SYang Hongyang g_free(path); 1283a4960f52SYang Hongyang } 1284fd9400b3SPaolo Bonzini } 1285fd9400b3SPaolo Bonzini 1286b1be4280SAmos Kong RxFilterInfoList *qmp_query_rx_filter(bool has_name, const char *name, 1287b1be4280SAmos Kong Error **errp) 1288b1be4280SAmos Kong { 1289b1be4280SAmos Kong NetClientState *nc; 1290b1be4280SAmos Kong RxFilterInfoList *filter_list = NULL, *last_entry = NULL; 1291b1be4280SAmos Kong 1292b1be4280SAmos Kong QTAILQ_FOREACH(nc, &net_clients, next) { 1293b1be4280SAmos Kong RxFilterInfoList *entry; 1294b1be4280SAmos Kong RxFilterInfo *info; 1295b1be4280SAmos Kong 1296b1be4280SAmos Kong if (has_name && strcmp(nc->name, name) != 0) { 1297b1be4280SAmos Kong continue; 1298b1be4280SAmos Kong } 1299b1be4280SAmos Kong 1300b1be4280SAmos Kong /* only query rx-filter information of NIC */ 1301f394b2e2SEric Blake if (nc->info->type != NET_CLIENT_DRIVER_NIC) { 1302b1be4280SAmos Kong if (has_name) { 1303b1be4280SAmos Kong error_setg(errp, "net client(%s) isn't a NIC", name); 13049083da1dSMarkus Armbruster return NULL; 1305b1be4280SAmos Kong } 1306b1be4280SAmos Kong continue; 1307b1be4280SAmos Kong } 1308b1be4280SAmos Kong 13095320c2caSVladislav Yasevich /* only query information on queue 0 since the info is per nic, 13105320c2caSVladislav Yasevich * not per queue 13115320c2caSVladislav Yasevich */ 13125320c2caSVladislav Yasevich if (nc->queue_index != 0) 13135320c2caSVladislav Yasevich continue; 13145320c2caSVladislav Yasevich 1315b1be4280SAmos Kong if (nc->info->query_rx_filter) { 1316b1be4280SAmos Kong info = nc->info->query_rx_filter(nc); 1317b1be4280SAmos Kong entry = g_malloc0(sizeof(*entry)); 1318b1be4280SAmos Kong entry->value = info; 1319b1be4280SAmos Kong 1320b1be4280SAmos Kong if (!filter_list) { 1321b1be4280SAmos Kong filter_list = entry; 1322b1be4280SAmos Kong } else { 1323b1be4280SAmos Kong last_entry->next = entry; 1324b1be4280SAmos Kong } 1325b1be4280SAmos Kong last_entry = entry; 1326b1be4280SAmos Kong } else if (has_name) { 1327b1be4280SAmos Kong error_setg(errp, "net client(%s) doesn't support" 1328b1be4280SAmos Kong " rx-filter querying", name); 13299083da1dSMarkus Armbruster return NULL; 1330b1be4280SAmos Kong } 1331638fb141SMarkus Armbruster 1332638fb141SMarkus Armbruster if (has_name) { 1333638fb141SMarkus Armbruster break; 1334638fb141SMarkus Armbruster } 1335b1be4280SAmos Kong } 1336b1be4280SAmos Kong 13379083da1dSMarkus Armbruster if (filter_list == NULL && has_name) { 1338b1be4280SAmos Kong error_setg(errp, "invalid net client name: %s", name); 1339b1be4280SAmos Kong } 1340b1be4280SAmos Kong 1341b1be4280SAmos Kong return filter_list; 1342b1be4280SAmos Kong } 1343b1be4280SAmos Kong 13441ce6be24SMarkus Armbruster void hmp_info_network(Monitor *mon, const QDict *qdict) 1345fd9400b3SPaolo Bonzini { 1346fd9400b3SPaolo Bonzini NetClientState *nc, *peer; 1347f394b2e2SEric Blake NetClientDriver type; 1348fd9400b3SPaolo Bonzini 1349fd9400b3SPaolo Bonzini net_hub_info(mon); 1350fd9400b3SPaolo Bonzini 1351fd9400b3SPaolo Bonzini QTAILQ_FOREACH(nc, &net_clients, next) { 1352fd9400b3SPaolo Bonzini peer = nc->peer; 1353fd9400b3SPaolo Bonzini type = nc->info->type; 1354fd9400b3SPaolo Bonzini 1355fd9400b3SPaolo Bonzini /* Skip if already printed in hub info */ 1356fd9400b3SPaolo Bonzini if (net_hub_id_for_client(nc, NULL) == 0) { 1357fd9400b3SPaolo Bonzini continue; 1358fd9400b3SPaolo Bonzini } 1359fd9400b3SPaolo Bonzini 1360f394b2e2SEric Blake if (!peer || type == NET_CLIENT_DRIVER_NIC) { 1361fd9400b3SPaolo Bonzini print_net_client(mon, nc); 1362fd9400b3SPaolo Bonzini } /* else it's a netdev connected to a NIC, printed with the NIC */ 1363f394b2e2SEric Blake if (peer && type == NET_CLIENT_DRIVER_NIC) { 1364fd9400b3SPaolo Bonzini monitor_printf(mon, " \\ "); 1365fd9400b3SPaolo Bonzini print_net_client(mon, peer); 1366fd9400b3SPaolo Bonzini } 1367fd9400b3SPaolo Bonzini } 1368fd9400b3SPaolo Bonzini } 1369fd9400b3SPaolo Bonzini 1370fd9400b3SPaolo Bonzini void qmp_set_link(const char *name, bool up, Error **errp) 1371fd9400b3SPaolo Bonzini { 13721ceef9f2SJason Wang NetClientState *ncs[MAX_QUEUE_NUM]; 13731ceef9f2SJason Wang NetClientState *nc; 13741ceef9f2SJason Wang int queues, i; 1375fd9400b3SPaolo Bonzini 13761ceef9f2SJason Wang queues = qemu_find_net_clients_except(name, ncs, 1377f394b2e2SEric Blake NET_CLIENT_DRIVER__MAX, 13781ceef9f2SJason Wang MAX_QUEUE_NUM); 13791ceef9f2SJason Wang 13801ceef9f2SJason Wang if (queues == 0) { 138175158ebbSMarkus Armbruster error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 138275158ebbSMarkus Armbruster "Device '%s' not found", name); 1383fd9400b3SPaolo Bonzini return; 1384fd9400b3SPaolo Bonzini } 13851ceef9f2SJason Wang nc = ncs[0]; 1386fd9400b3SPaolo Bonzini 13871ceef9f2SJason Wang for (i = 0; i < queues; i++) { 13881ceef9f2SJason Wang ncs[i]->link_down = !up; 13891ceef9f2SJason Wang } 1390fd9400b3SPaolo Bonzini 1391fd9400b3SPaolo Bonzini if (nc->info->link_status_changed) { 1392fd9400b3SPaolo Bonzini nc->info->link_status_changed(nc); 1393fd9400b3SPaolo Bonzini } 1394fd9400b3SPaolo Bonzini 139502d38fcbSVlad Yasevich if (nc->peer) { 139602d38fcbSVlad Yasevich /* Change peer link only if the peer is NIC and then notify peer. 139702d38fcbSVlad Yasevich * If the peer is a HUBPORT or a backend, we do not change the 139802d38fcbSVlad Yasevich * link status. 1399fd9400b3SPaolo Bonzini * 140002d38fcbSVlad Yasevich * This behavior is compatible with qemu vlans where there could be 1401fd9400b3SPaolo Bonzini * multiple clients that can still communicate with each other in 140202d38fcbSVlad Yasevich * disconnected mode. For now maintain this compatibility. 140302d38fcbSVlad Yasevich */ 1404f394b2e2SEric Blake if (nc->peer->info->type == NET_CLIENT_DRIVER_NIC) { 140502d38fcbSVlad Yasevich for (i = 0; i < queues; i++) { 140602d38fcbSVlad Yasevich ncs[i]->peer->link_down = !up; 140702d38fcbSVlad Yasevich } 140802d38fcbSVlad Yasevich } 140902d38fcbSVlad Yasevich if (nc->peer->info->link_status_changed) { 1410fd9400b3SPaolo Bonzini nc->peer->info->link_status_changed(nc->peer); 1411fd9400b3SPaolo Bonzini } 1412fd9400b3SPaolo Bonzini } 141302d38fcbSVlad Yasevich } 1414fd9400b3SPaolo Bonzini 1415ca77d85eSMichael S. Tsirkin static void net_vm_change_state_handler(void *opaque, int running, 1416ca77d85eSMichael S. Tsirkin RunState state) 1417ca77d85eSMichael S. Tsirkin { 1418ca77d85eSMichael S. Tsirkin NetClientState *nc; 1419ca77d85eSMichael S. Tsirkin NetClientState *tmp; 1420ca77d85eSMichael S. Tsirkin 1421ca77d85eSMichael S. Tsirkin QTAILQ_FOREACH_SAFE(nc, &net_clients, next, tmp) { 1422625de449SFam Zheng if (running) { 1423625de449SFam Zheng /* Flush queued packets and wake up backends. */ 1424625de449SFam Zheng if (nc->peer && qemu_can_send_packet(nc)) { 1425625de449SFam Zheng qemu_flush_queued_packets(nc->peer); 1426625de449SFam Zheng } 1427625de449SFam Zheng } else { 1428625de449SFam Zheng /* Complete all queued packets, to guarantee we don't modify 1429625de449SFam Zheng * state later when VM is not running. 1430625de449SFam Zheng */ 1431ca77d85eSMichael S. Tsirkin qemu_flush_or_purge_queued_packets(nc, true); 1432ca77d85eSMichael S. Tsirkin } 1433ca77d85eSMichael S. Tsirkin } 1434ca77d85eSMichael S. Tsirkin } 1435ca77d85eSMichael S. Tsirkin 1436fd9400b3SPaolo Bonzini void net_cleanup(void) 1437fd9400b3SPaolo Bonzini { 14381ceef9f2SJason Wang NetClientState *nc; 1439fd9400b3SPaolo Bonzini 14401ceef9f2SJason Wang /* We may del multiple entries during qemu_del_net_client(), 14411ceef9f2SJason Wang * so QTAILQ_FOREACH_SAFE() is also not safe here. 14421ceef9f2SJason Wang */ 14431ceef9f2SJason Wang while (!QTAILQ_EMPTY(&net_clients)) { 14441ceef9f2SJason Wang nc = QTAILQ_FIRST(&net_clients); 1445f394b2e2SEric Blake if (nc->info->type == NET_CLIENT_DRIVER_NIC) { 1446948ecf21SJason Wang qemu_del_nic(qemu_get_nic(nc)); 1447948ecf21SJason Wang } else { 1448fd9400b3SPaolo Bonzini qemu_del_net_client(nc); 1449fd9400b3SPaolo Bonzini } 1450fd9400b3SPaolo Bonzini } 1451ca77d85eSMichael S. Tsirkin 1452ca77d85eSMichael S. Tsirkin qemu_del_vm_change_state_handler(net_change_state_entry); 1453948ecf21SJason Wang } 1454fd9400b3SPaolo Bonzini 1455fd9400b3SPaolo Bonzini void net_check_clients(void) 1456fd9400b3SPaolo Bonzini { 1457fd9400b3SPaolo Bonzini NetClientState *nc; 1458fd9400b3SPaolo Bonzini int i; 1459fd9400b3SPaolo Bonzini 1460fd9400b3SPaolo Bonzini net_hub_check_clients(); 1461fd9400b3SPaolo Bonzini 1462fd9400b3SPaolo Bonzini QTAILQ_FOREACH(nc, &net_clients, next) { 1463fd9400b3SPaolo Bonzini if (!nc->peer) { 1464fd9400b3SPaolo Bonzini fprintf(stderr, "Warning: %s %s has no peer\n", 1465f394b2e2SEric Blake nc->info->type == NET_CLIENT_DRIVER_NIC ? 1466fd9400b3SPaolo Bonzini "nic" : "netdev", nc->name); 1467fd9400b3SPaolo Bonzini } 1468fd9400b3SPaolo Bonzini } 1469fd9400b3SPaolo Bonzini 1470fd9400b3SPaolo Bonzini /* Check that all NICs requested via -net nic actually got created. 1471fd9400b3SPaolo Bonzini * NICs created via -device don't need to be checked here because 1472fd9400b3SPaolo Bonzini * they are always instantiated. 1473fd9400b3SPaolo Bonzini */ 1474fd9400b3SPaolo Bonzini for (i = 0; i < MAX_NICS; i++) { 1475fd9400b3SPaolo Bonzini NICInfo *nd = &nd_table[i]; 1476fd9400b3SPaolo Bonzini if (nd->used && !nd->instantiated) { 1477fd9400b3SPaolo Bonzini fprintf(stderr, "Warning: requested NIC (%s, model %s) " 1478fd9400b3SPaolo Bonzini "was not created (not supported by this machine?)\n", 1479fd9400b3SPaolo Bonzini nd->name ? nd->name : "anonymous", 1480fd9400b3SPaolo Bonzini nd->model ? nd->model : "unspecified"); 1481fd9400b3SPaolo Bonzini } 1482fd9400b3SPaolo Bonzini } 1483fd9400b3SPaolo Bonzini } 1484fd9400b3SPaolo Bonzini 148528d0de7aSMarkus Armbruster static int net_init_client(void *dummy, QemuOpts *opts, Error **errp) 1486fd9400b3SPaolo Bonzini { 1487fd9400b3SPaolo Bonzini Error *local_err = NULL; 1488fd9400b3SPaolo Bonzini 14890e55c381SEric Blake net_client_init(opts, false, &local_err); 149084d18f06SMarkus Armbruster if (local_err) { 149112d0cc2dSMarkus Armbruster error_report_err(local_err); 1492fd9400b3SPaolo Bonzini return -1; 1493fd9400b3SPaolo Bonzini } 1494fd9400b3SPaolo Bonzini 1495fd9400b3SPaolo Bonzini return 0; 1496fd9400b3SPaolo Bonzini } 1497fd9400b3SPaolo Bonzini 149828d0de7aSMarkus Armbruster static int net_init_netdev(void *dummy, QemuOpts *opts, Error **errp) 1499fd9400b3SPaolo Bonzini { 1500fd9400b3SPaolo Bonzini Error *local_err = NULL; 1501fd9400b3SPaolo Bonzini int ret; 1502fd9400b3SPaolo Bonzini 15030e55c381SEric Blake ret = net_client_init(opts, true, &local_err); 150484d18f06SMarkus Armbruster if (local_err) { 150512d0cc2dSMarkus Armbruster error_report_err(local_err); 1506fd9400b3SPaolo Bonzini return -1; 1507fd9400b3SPaolo Bonzini } 1508fd9400b3SPaolo Bonzini 1509fd9400b3SPaolo Bonzini return ret; 1510fd9400b3SPaolo Bonzini } 1511fd9400b3SPaolo Bonzini 1512fd9400b3SPaolo Bonzini int net_init_clients(void) 1513fd9400b3SPaolo Bonzini { 1514fd9400b3SPaolo Bonzini QemuOptsList *net = qemu_find_opts("net"); 1515fd9400b3SPaolo Bonzini 1516ca77d85eSMichael S. Tsirkin net_change_state_entry = 1517ca77d85eSMichael S. Tsirkin qemu_add_vm_change_state_handler(net_vm_change_state_handler, NULL); 1518ca77d85eSMichael S. Tsirkin 1519fd9400b3SPaolo Bonzini QTAILQ_INIT(&net_clients); 1520fd9400b3SPaolo Bonzini 152128d0de7aSMarkus Armbruster if (qemu_opts_foreach(qemu_find_opts("netdev"), 152228d0de7aSMarkus Armbruster net_init_netdev, NULL, NULL)) { 1523fd9400b3SPaolo Bonzini return -1; 1524a4c7367fSMarkus Armbruster } 1525fd9400b3SPaolo Bonzini 152628d0de7aSMarkus Armbruster if (qemu_opts_foreach(net, net_init_client, NULL, NULL)) { 1527fd9400b3SPaolo Bonzini return -1; 1528fd9400b3SPaolo Bonzini } 1529fd9400b3SPaolo Bonzini 1530fd9400b3SPaolo Bonzini return 0; 1531fd9400b3SPaolo Bonzini } 1532fd9400b3SPaolo Bonzini 1533fd9400b3SPaolo Bonzini int net_client_parse(QemuOptsList *opts_list, const char *optarg) 1534fd9400b3SPaolo Bonzini { 1535fd9400b3SPaolo Bonzini #if defined(CONFIG_SLIRP) 1536fd9400b3SPaolo Bonzini int ret; 1537fd9400b3SPaolo Bonzini if (net_slirp_parse_legacy(opts_list, optarg, &ret)) { 1538fd9400b3SPaolo Bonzini return ret; 1539fd9400b3SPaolo Bonzini } 1540fd9400b3SPaolo Bonzini #endif 1541fd9400b3SPaolo Bonzini 154270b94331SMarkus Armbruster if (!qemu_opts_parse_noisily(opts_list, optarg, true)) { 1543fd9400b3SPaolo Bonzini return -1; 1544fd9400b3SPaolo Bonzini } 1545fd9400b3SPaolo Bonzini 1546fd9400b3SPaolo Bonzini return 0; 1547fd9400b3SPaolo Bonzini } 1548fd9400b3SPaolo Bonzini 1549fd9400b3SPaolo Bonzini /* From FreeBSD */ 1550fd9400b3SPaolo Bonzini /* XXX: optimize */ 1551fd9400b3SPaolo Bonzini unsigned compute_mcast_idx(const uint8_t *ep) 1552fd9400b3SPaolo Bonzini { 1553fd9400b3SPaolo Bonzini uint32_t crc; 1554fd9400b3SPaolo Bonzini int carry, i, j; 1555fd9400b3SPaolo Bonzini uint8_t b; 1556fd9400b3SPaolo Bonzini 1557fd9400b3SPaolo Bonzini crc = 0xffffffff; 1558fd9400b3SPaolo Bonzini for (i = 0; i < 6; i++) { 1559fd9400b3SPaolo Bonzini b = *ep++; 1560fd9400b3SPaolo Bonzini for (j = 0; j < 8; j++) { 1561fd9400b3SPaolo Bonzini carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01); 1562fd9400b3SPaolo Bonzini crc <<= 1; 1563fd9400b3SPaolo Bonzini b >>= 1; 1564fd9400b3SPaolo Bonzini if (carry) { 1565fd9400b3SPaolo Bonzini crc = ((crc ^ POLYNOMIAL) | carry); 1566fd9400b3SPaolo Bonzini } 1567fd9400b3SPaolo Bonzini } 1568fd9400b3SPaolo Bonzini } 1569fd9400b3SPaolo Bonzini return crc >> 26; 1570fd9400b3SPaolo Bonzini } 15714d454574SPaolo Bonzini 15724d454574SPaolo Bonzini QemuOptsList qemu_netdev_opts = { 15734d454574SPaolo Bonzini .name = "netdev", 15744d454574SPaolo Bonzini .implied_opt_name = "type", 15754d454574SPaolo Bonzini .head = QTAILQ_HEAD_INITIALIZER(qemu_netdev_opts.head), 15764d454574SPaolo Bonzini .desc = { 15774d454574SPaolo Bonzini /* 15784d454574SPaolo Bonzini * no elements => accept any params 15794d454574SPaolo Bonzini * validation will happen later 15804d454574SPaolo Bonzini */ 15814d454574SPaolo Bonzini { /* end of list */ } 15824d454574SPaolo Bonzini }, 15834d454574SPaolo Bonzini }; 15844d454574SPaolo Bonzini 15854d454574SPaolo Bonzini QemuOptsList qemu_net_opts = { 15864d454574SPaolo Bonzini .name = "net", 15874d454574SPaolo Bonzini .implied_opt_name = "type", 15884d454574SPaolo Bonzini .head = QTAILQ_HEAD_INITIALIZER(qemu_net_opts.head), 15894d454574SPaolo Bonzini .desc = { 15904d454574SPaolo Bonzini /* 15914d454574SPaolo Bonzini * no elements => accept any params 15924d454574SPaolo Bonzini * validation will happen later 15934d454574SPaolo Bonzini */ 15944d454574SPaolo Bonzini { /* end of list */ } 15954d454574SPaolo Bonzini }, 15964d454574SPaolo Bonzini }; 159716a3df40SZhang Chen 159816a3df40SZhang Chen void net_socket_rs_init(SocketReadState *rs, 159916a3df40SZhang Chen SocketReadStateFinalize *finalize) 160016a3df40SZhang Chen { 160116a3df40SZhang Chen rs->state = 0; 160216a3df40SZhang Chen rs->index = 0; 160316a3df40SZhang Chen rs->packet_len = 0; 160416a3df40SZhang Chen memset(rs->buf, 0, sizeof(rs->buf)); 160516a3df40SZhang Chen rs->finalize = finalize; 160616a3df40SZhang Chen } 160716a3df40SZhang Chen 160816a3df40SZhang Chen /* 160916a3df40SZhang Chen * Returns 1610e9e0a585SZhang Chen * 0: success 1611e9e0a585SZhang Chen * -1: error occurs 161216a3df40SZhang Chen */ 161316a3df40SZhang Chen int net_fill_rstate(SocketReadState *rs, const uint8_t *buf, int size) 161416a3df40SZhang Chen { 161516a3df40SZhang Chen unsigned int l; 161616a3df40SZhang Chen 161716a3df40SZhang Chen while (size > 0) { 161816a3df40SZhang Chen /* reassemble a packet from the network */ 161916a3df40SZhang Chen switch (rs->state) { /* 0 = getting length, 1 = getting data */ 162016a3df40SZhang Chen case 0: 162116a3df40SZhang Chen l = 4 - rs->index; 162216a3df40SZhang Chen if (l > size) { 162316a3df40SZhang Chen l = size; 162416a3df40SZhang Chen } 162516a3df40SZhang Chen memcpy(rs->buf + rs->index, buf, l); 162616a3df40SZhang Chen buf += l; 162716a3df40SZhang Chen size -= l; 162816a3df40SZhang Chen rs->index += l; 162916a3df40SZhang Chen if (rs->index == 4) { 163016a3df40SZhang Chen /* got length */ 163116a3df40SZhang Chen rs->packet_len = ntohl(*(uint32_t *)rs->buf); 163216a3df40SZhang Chen rs->index = 0; 163316a3df40SZhang Chen rs->state = 1; 163416a3df40SZhang Chen } 163516a3df40SZhang Chen break; 163616a3df40SZhang Chen case 1: 163716a3df40SZhang Chen l = rs->packet_len - rs->index; 163816a3df40SZhang Chen if (l > size) { 163916a3df40SZhang Chen l = size; 164016a3df40SZhang Chen } 164116a3df40SZhang Chen if (rs->index + l <= sizeof(rs->buf)) { 164216a3df40SZhang Chen memcpy(rs->buf + rs->index, buf, l); 164316a3df40SZhang Chen } else { 164416a3df40SZhang Chen fprintf(stderr, "serious error: oversized packet received," 164516a3df40SZhang Chen "connection terminated.\n"); 164616a3df40SZhang Chen rs->index = rs->state = 0; 164716a3df40SZhang Chen return -1; 164816a3df40SZhang Chen } 164916a3df40SZhang Chen 165016a3df40SZhang Chen rs->index += l; 165116a3df40SZhang Chen buf += l; 165216a3df40SZhang Chen size -= l; 165316a3df40SZhang Chen if (rs->index >= rs->packet_len) { 165416a3df40SZhang Chen rs->index = 0; 165516a3df40SZhang Chen rs->state = 0; 165616a3df40SZhang Chen if (rs->finalize) { 165716a3df40SZhang Chen rs->finalize(rs); 165816a3df40SZhang Chen } 165916a3df40SZhang Chen } 166016a3df40SZhang Chen break; 166116a3df40SZhang Chen } 166216a3df40SZhang Chen } 1663e9e0a585SZhang Chen 1664e9e0a585SZhang Chen assert(size == 0); 166516a3df40SZhang Chen return 0; 166616a3df40SZhang Chen } 1667