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 */ 24e688df6bSMarkus Armbruster 252744d920SPeter Maydell #include "qemu/osdep.h" 26fd9400b3SPaolo Bonzini 271422e32dSPaolo Bonzini #include "net/net.h" 28fd9400b3SPaolo Bonzini #include "clients.h" 29fd9400b3SPaolo Bonzini #include "hub.h" 30*a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h" 311422e32dSPaolo Bonzini #include "net/slirp.h" 32d60b20cfSDmitry Krivenok #include "net/eth.h" 33fd9400b3SPaolo Bonzini #include "util.h" 34fd9400b3SPaolo Bonzini 3583c9089eSPaolo Bonzini #include "monitor/monitor.h" 36f348b6d1SVeronia Bahaa #include "qemu/help_option.h" 379af23989SMarkus Armbruster #include "qapi/qapi-commands-net.h" 389af23989SMarkus Armbruster #include "qapi/qapi-visit-net.h" 39452fcdbcSMarkus Armbruster #include "qapi/qmp/qdict.h" 40cc7a8ea7SMarkus Armbruster #include "qapi/qmp/qerror.h" 41d49b6836SMarkus Armbruster #include "qemu/error-report.h" 421de7afc9SPaolo Bonzini #include "qemu/sockets.h" 43f348b6d1SVeronia Bahaa #include "qemu/cutils.h" 441de7afc9SPaolo Bonzini #include "qemu/config-file.h" 45856dfd8aSMarkus Armbruster #include "qemu/ctype.h" 461de7afc9SPaolo Bonzini #include "qemu/iov.h" 476a1751b7SAlex Bligh #include "qemu/main-loop.h" 48922a01a0SMarkus Armbruster #include "qemu/option.h" 49e688df6bSMarkus Armbruster #include "qapi/error.h" 50fd9400b3SPaolo Bonzini #include "qapi/opts-visitor.h" 51e1d64c08Szhanghailiang #include "sysemu/sysemu.h" 52559964a1SThomas Huth #include "sysemu/qtest.h" 53fdccce45SYang Hongyang #include "net/filter.h" 54aa9156f4Szhanghailiang #include "qapi/string-output-visitor.h" 55fd9400b3SPaolo Bonzini 56fd9400b3SPaolo Bonzini /* Net bridge is currently not supported for W32. */ 57fd9400b3SPaolo Bonzini #if !defined(_WIN32) 58fd9400b3SPaolo Bonzini # define CONFIG_NET_BRIDGE 59fd9400b3SPaolo Bonzini #endif 60fd9400b3SPaolo Bonzini 61ca77d85eSMichael S. Tsirkin static VMChangeStateEntry *net_change_state_entry; 62fd9400b3SPaolo Bonzini static QTAILQ_HEAD(, NetClientState) net_clients; 63fd9400b3SPaolo Bonzini 64fd9400b3SPaolo Bonzini /***********************************************************/ 65fd9400b3SPaolo Bonzini /* network device redirectors */ 66fd9400b3SPaolo Bonzini 67bcd4dfd6SMao Zhongyi int parse_host_port(struct sockaddr_in *saddr, const char *str, 68bcd4dfd6SMao Zhongyi Error **errp) 69fd9400b3SPaolo Bonzini { 70add99347SStefano Garzarella gchar **substrings; 71fd9400b3SPaolo Bonzini struct hostent *he; 72add99347SStefano Garzarella const char *addr, *p, *r; 73add99347SStefano Garzarella int port, ret = 0; 74fd9400b3SPaolo Bonzini 75add99347SStefano Garzarella substrings = g_strsplit(str, ":", 2); 76add99347SStefano Garzarella if (!substrings || !substrings[0] || !substrings[1]) { 77bcd4dfd6SMao Zhongyi error_setg(errp, "host address '%s' doesn't contain ':' " 78bcd4dfd6SMao Zhongyi "separating host from port", str); 79add99347SStefano Garzarella ret = -1; 80add99347SStefano Garzarella goto out; 81bcd4dfd6SMao Zhongyi } 82add99347SStefano Garzarella 83add99347SStefano Garzarella addr = substrings[0]; 84add99347SStefano Garzarella p = substrings[1]; 85add99347SStefano Garzarella 86fd9400b3SPaolo Bonzini saddr->sin_family = AF_INET; 87add99347SStefano Garzarella if (addr[0] == '\0') { 88fd9400b3SPaolo Bonzini saddr->sin_addr.s_addr = 0; 89fd9400b3SPaolo Bonzini } else { 90add99347SStefano Garzarella if (qemu_isdigit(addr[0])) { 91add99347SStefano Garzarella if (!inet_aton(addr, &saddr->sin_addr)) { 92bcd4dfd6SMao Zhongyi error_setg(errp, "host address '%s' is not a valid " 93add99347SStefano Garzarella "IPv4 address", addr); 94add99347SStefano Garzarella ret = -1; 95add99347SStefano Garzarella goto out; 96bcd4dfd6SMao Zhongyi } 97fd9400b3SPaolo Bonzini } else { 98add99347SStefano Garzarella he = gethostbyname(addr); 99bcd4dfd6SMao Zhongyi if (he == NULL) { 100add99347SStefano Garzarella error_setg(errp, "can't resolve host address '%s'", addr); 101add99347SStefano Garzarella ret = -1; 102add99347SStefano Garzarella goto out; 103bcd4dfd6SMao Zhongyi } 104fd9400b3SPaolo Bonzini saddr->sin_addr = *(struct in_addr *)he->h_addr; 105fd9400b3SPaolo Bonzini } 106fd9400b3SPaolo Bonzini } 107fd9400b3SPaolo Bonzini port = strtol(p, (char **)&r, 0); 108bcd4dfd6SMao Zhongyi if (r == p) { 109bcd4dfd6SMao Zhongyi error_setg(errp, "port number '%s' is invalid", p); 110add99347SStefano Garzarella ret = -1; 111add99347SStefano Garzarella goto out; 112bcd4dfd6SMao Zhongyi } 113fd9400b3SPaolo Bonzini saddr->sin_port = htons(port); 114add99347SStefano Garzarella 115add99347SStefano Garzarella out: 116add99347SStefano Garzarella g_strfreev(substrings); 117add99347SStefano Garzarella return ret; 118fd9400b3SPaolo Bonzini } 119fd9400b3SPaolo Bonzini 120890ee6abSScott Feldman char *qemu_mac_strdup_printf(const uint8_t *macaddr) 121890ee6abSScott Feldman { 122890ee6abSScott Feldman return g_strdup_printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", 123890ee6abSScott Feldman macaddr[0], macaddr[1], macaddr[2], 124890ee6abSScott Feldman macaddr[3], macaddr[4], macaddr[5]); 125890ee6abSScott Feldman } 126890ee6abSScott Feldman 127fd9400b3SPaolo Bonzini void qemu_format_nic_info_str(NetClientState *nc, uint8_t macaddr[6]) 128fd9400b3SPaolo Bonzini { 129fd9400b3SPaolo Bonzini snprintf(nc->info_str, sizeof(nc->info_str), 130fd9400b3SPaolo Bonzini "model=%s,macaddr=%02x:%02x:%02x:%02x:%02x:%02x", 131fd9400b3SPaolo Bonzini nc->model, 132fd9400b3SPaolo Bonzini macaddr[0], macaddr[1], macaddr[2], 133fd9400b3SPaolo Bonzini macaddr[3], macaddr[4], macaddr[5]); 134fd9400b3SPaolo Bonzini } 135fd9400b3SPaolo Bonzini 1362bc22a58SShannon Zhao static int mac_table[256] = {0}; 1372bc22a58SShannon Zhao 1382bc22a58SShannon Zhao static void qemu_macaddr_set_used(MACAddr *macaddr) 1392bc22a58SShannon Zhao { 1402bc22a58SShannon Zhao int index; 1412bc22a58SShannon Zhao 1422bc22a58SShannon Zhao for (index = 0x56; index < 0xFF; index++) { 1432bc22a58SShannon Zhao if (macaddr->a[5] == index) { 1442bc22a58SShannon Zhao mac_table[index]++; 1452bc22a58SShannon Zhao } 1462bc22a58SShannon Zhao } 1472bc22a58SShannon Zhao } 1482bc22a58SShannon Zhao 1492bc22a58SShannon Zhao static void qemu_macaddr_set_free(MACAddr *macaddr) 1502bc22a58SShannon Zhao { 1512bc22a58SShannon Zhao int index; 1522bc22a58SShannon Zhao static const MACAddr base = { .a = { 0x52, 0x54, 0x00, 0x12, 0x34, 0 } }; 1532bc22a58SShannon Zhao 1542bc22a58SShannon Zhao if (memcmp(macaddr->a, &base.a, (sizeof(base.a) - 1)) != 0) { 1552bc22a58SShannon Zhao return; 1562bc22a58SShannon Zhao } 1572bc22a58SShannon Zhao for (index = 0x56; index < 0xFF; index++) { 1582bc22a58SShannon Zhao if (macaddr->a[5] == index) { 1592bc22a58SShannon Zhao mac_table[index]--; 1602bc22a58SShannon Zhao } 1612bc22a58SShannon Zhao } 1622bc22a58SShannon Zhao } 1632bc22a58SShannon Zhao 1642bc22a58SShannon Zhao static int qemu_macaddr_get_free(void) 1652bc22a58SShannon Zhao { 1662bc22a58SShannon Zhao int index; 1672bc22a58SShannon Zhao 1682bc22a58SShannon Zhao for (index = 0x56; index < 0xFF; index++) { 1692bc22a58SShannon Zhao if (mac_table[index] == 0) { 1702bc22a58SShannon Zhao return index; 1712bc22a58SShannon Zhao } 1722bc22a58SShannon Zhao } 1732bc22a58SShannon Zhao 1742bc22a58SShannon Zhao return -1; 1752bc22a58SShannon Zhao } 1762bc22a58SShannon Zhao 177fd9400b3SPaolo Bonzini void qemu_macaddr_default_if_unset(MACAddr *macaddr) 178fd9400b3SPaolo Bonzini { 179fd9400b3SPaolo Bonzini static const MACAddr zero = { .a = { 0,0,0,0,0,0 } }; 1802bc22a58SShannon Zhao static const MACAddr base = { .a = { 0x52, 0x54, 0x00, 0x12, 0x34, 0 } }; 181fd9400b3SPaolo Bonzini 1822bc22a58SShannon Zhao if (memcmp(macaddr, &zero, sizeof(zero)) != 0) { 1832bc22a58SShannon Zhao if (memcmp(macaddr->a, &base.a, (sizeof(base.a) - 1)) != 0) { 184fd9400b3SPaolo Bonzini return; 1852bc22a58SShannon Zhao } else { 1862bc22a58SShannon Zhao qemu_macaddr_set_used(macaddr); 1872bc22a58SShannon Zhao return; 1882bc22a58SShannon Zhao } 1892bc22a58SShannon Zhao } 1902bc22a58SShannon Zhao 191fd9400b3SPaolo Bonzini macaddr->a[0] = 0x52; 192fd9400b3SPaolo Bonzini macaddr->a[1] = 0x54; 193fd9400b3SPaolo Bonzini macaddr->a[2] = 0x00; 194fd9400b3SPaolo Bonzini macaddr->a[3] = 0x12; 195fd9400b3SPaolo Bonzini macaddr->a[4] = 0x34; 1962bc22a58SShannon Zhao macaddr->a[5] = qemu_macaddr_get_free(); 1972bc22a58SShannon Zhao qemu_macaddr_set_used(macaddr); 198fd9400b3SPaolo Bonzini } 199fd9400b3SPaolo Bonzini 200fd9400b3SPaolo Bonzini /** 201fd9400b3SPaolo Bonzini * Generate a name for net client 202fd9400b3SPaolo Bonzini * 203c963530aSAmos Kong * Only net clients created with the legacy -net option and NICs need this. 204fd9400b3SPaolo Bonzini */ 205fd9400b3SPaolo Bonzini static char *assign_name(NetClientState *nc1, const char *model) 206fd9400b3SPaolo Bonzini { 207fd9400b3SPaolo Bonzini NetClientState *nc; 208fd9400b3SPaolo Bonzini int id = 0; 209fd9400b3SPaolo Bonzini 210fd9400b3SPaolo Bonzini QTAILQ_FOREACH(nc, &net_clients, next) { 211fd9400b3SPaolo Bonzini if (nc == nc1) { 212fd9400b3SPaolo Bonzini continue; 213fd9400b3SPaolo Bonzini } 214c963530aSAmos Kong if (strcmp(nc->model, model) == 0) { 215fd9400b3SPaolo Bonzini id++; 216fd9400b3SPaolo Bonzini } 217fd9400b3SPaolo Bonzini } 218fd9400b3SPaolo Bonzini 2194bf2c138SHani Benhabiles return g_strdup_printf("%s.%d", model, id); 220fd9400b3SPaolo Bonzini } 221fd9400b3SPaolo Bonzini 222f7860455SJason Wang static void qemu_net_client_destructor(NetClientState *nc) 223f7860455SJason Wang { 224f7860455SJason Wang g_free(nc); 225f7860455SJason Wang } 22625c01bd1SJason Wang static ssize_t qemu_deliver_packet_iov(NetClientState *sender, 22725c01bd1SJason Wang unsigned flags, 22825c01bd1SJason Wang const struct iovec *iov, 22925c01bd1SJason Wang int iovcnt, 23025c01bd1SJason Wang void *opaque); 231f7860455SJason Wang 23218a1541aSJason Wang static void qemu_net_client_setup(NetClientState *nc, 23318a1541aSJason Wang NetClientInfo *info, 234fd9400b3SPaolo Bonzini NetClientState *peer, 235fd9400b3SPaolo Bonzini const char *model, 236f7860455SJason Wang const char *name, 237f7860455SJason Wang NetClientDestructor *destructor) 238fd9400b3SPaolo Bonzini { 239fd9400b3SPaolo Bonzini nc->info = info; 240fd9400b3SPaolo Bonzini nc->model = g_strdup(model); 241fd9400b3SPaolo Bonzini if (name) { 242fd9400b3SPaolo Bonzini nc->name = g_strdup(name); 243fd9400b3SPaolo Bonzini } else { 244fd9400b3SPaolo Bonzini nc->name = assign_name(nc, model); 245fd9400b3SPaolo Bonzini } 246fd9400b3SPaolo Bonzini 247fd9400b3SPaolo Bonzini if (peer) { 248fd9400b3SPaolo Bonzini assert(!peer->peer); 249fd9400b3SPaolo Bonzini nc->peer = peer; 250fd9400b3SPaolo Bonzini peer->peer = nc; 251fd9400b3SPaolo Bonzini } 252fd9400b3SPaolo Bonzini QTAILQ_INSERT_TAIL(&net_clients, nc, next); 253fd9400b3SPaolo Bonzini 2543e033a46SYang Hongyang nc->incoming_queue = qemu_new_net_queue(qemu_deliver_packet_iov, nc); 255f7860455SJason Wang nc->destructor = destructor; 256fdccce45SYang Hongyang QTAILQ_INIT(&nc->filters); 25718a1541aSJason Wang } 25818a1541aSJason Wang 25918a1541aSJason Wang NetClientState *qemu_new_net_client(NetClientInfo *info, 26018a1541aSJason Wang NetClientState *peer, 26118a1541aSJason Wang const char *model, 26218a1541aSJason Wang const char *name) 26318a1541aSJason Wang { 26418a1541aSJason Wang NetClientState *nc; 26518a1541aSJason Wang 26618a1541aSJason Wang assert(info->size >= sizeof(NetClientState)); 26718a1541aSJason Wang 26818a1541aSJason Wang nc = g_malloc0(info->size); 269f7860455SJason Wang qemu_net_client_setup(nc, info, peer, model, name, 270f7860455SJason Wang qemu_net_client_destructor); 27118a1541aSJason Wang 272fd9400b3SPaolo Bonzini return nc; 273fd9400b3SPaolo Bonzini } 274fd9400b3SPaolo Bonzini 275fd9400b3SPaolo Bonzini NICState *qemu_new_nic(NetClientInfo *info, 276fd9400b3SPaolo Bonzini NICConf *conf, 277fd9400b3SPaolo Bonzini const char *model, 278fd9400b3SPaolo Bonzini const char *name, 279fd9400b3SPaolo Bonzini void *opaque) 280fd9400b3SPaolo Bonzini { 2811ceef9f2SJason Wang NetClientState **peers = conf->peers.ncs; 282fd9400b3SPaolo Bonzini NICState *nic; 283575a1c0eSJiri Pirko int i, queues = MAX(1, conf->peers.queues); 284fd9400b3SPaolo Bonzini 285f394b2e2SEric Blake assert(info->type == NET_CLIENT_DRIVER_NIC); 286fd9400b3SPaolo Bonzini assert(info->size >= sizeof(NICState)); 287fd9400b3SPaolo Bonzini 288f6b26cf2SJason Wang nic = g_malloc0(info->size + sizeof(NetClientState) * queues); 289f6b26cf2SJason Wang nic->ncs = (void *)nic + info->size; 290fd9400b3SPaolo Bonzini nic->conf = conf; 291fd9400b3SPaolo Bonzini nic->opaque = opaque; 292fd9400b3SPaolo Bonzini 293f6b26cf2SJason Wang for (i = 0; i < queues; i++) { 294f6b26cf2SJason Wang qemu_net_client_setup(&nic->ncs[i], info, peers[i], model, name, 2951ceef9f2SJason Wang NULL); 2961ceef9f2SJason Wang nic->ncs[i].queue_index = i; 2971ceef9f2SJason Wang } 2981ceef9f2SJason Wang 299fd9400b3SPaolo Bonzini return nic; 300fd9400b3SPaolo Bonzini } 301fd9400b3SPaolo Bonzini 3021ceef9f2SJason Wang NetClientState *qemu_get_subqueue(NICState *nic, int queue_index) 3031ceef9f2SJason Wang { 304f6b26cf2SJason Wang return nic->ncs + queue_index; 3051ceef9f2SJason Wang } 3061ceef9f2SJason Wang 307b356f76dSJason Wang NetClientState *qemu_get_queue(NICState *nic) 308b356f76dSJason Wang { 3091ceef9f2SJason Wang return qemu_get_subqueue(nic, 0); 310b356f76dSJason Wang } 311b356f76dSJason Wang 312cc1f0f45SJason Wang NICState *qemu_get_nic(NetClientState *nc) 313cc1f0f45SJason Wang { 3141ceef9f2SJason Wang NetClientState *nc0 = nc - nc->queue_index; 3151ceef9f2SJason Wang 316f6b26cf2SJason Wang return (NICState *)((void *)nc0 - nc->info->size); 317cc1f0f45SJason Wang } 318cc1f0f45SJason Wang 319cc1f0f45SJason Wang void *qemu_get_nic_opaque(NetClientState *nc) 320cc1f0f45SJason Wang { 321cc1f0f45SJason Wang NICState *nic = qemu_get_nic(nc); 322cc1f0f45SJason Wang 323cc1f0f45SJason Wang return nic->opaque; 324cc1f0f45SJason Wang } 325cc1f0f45SJason Wang 326fd9400b3SPaolo Bonzini static void qemu_cleanup_net_client(NetClientState *nc) 327fd9400b3SPaolo Bonzini { 328fd9400b3SPaolo Bonzini QTAILQ_REMOVE(&net_clients, nc, next); 329fd9400b3SPaolo Bonzini 330cc2a9043SAndreas Färber if (nc->info->cleanup) { 331fd9400b3SPaolo Bonzini nc->info->cleanup(nc); 332fd9400b3SPaolo Bonzini } 333cc2a9043SAndreas Färber } 334fd9400b3SPaolo Bonzini 335fd9400b3SPaolo Bonzini static void qemu_free_net_client(NetClientState *nc) 336fd9400b3SPaolo Bonzini { 337067404beSJan Kiszka if (nc->incoming_queue) { 338067404beSJan Kiszka qemu_del_net_queue(nc->incoming_queue); 339fd9400b3SPaolo Bonzini } 340fd9400b3SPaolo Bonzini if (nc->peer) { 341fd9400b3SPaolo Bonzini nc->peer->peer = NULL; 342fd9400b3SPaolo Bonzini } 343fd9400b3SPaolo Bonzini g_free(nc->name); 344fd9400b3SPaolo Bonzini g_free(nc->model); 345f7860455SJason Wang if (nc->destructor) { 346f7860455SJason Wang nc->destructor(nc); 347f7860455SJason Wang } 348fd9400b3SPaolo Bonzini } 349fd9400b3SPaolo Bonzini 350fd9400b3SPaolo Bonzini void qemu_del_net_client(NetClientState *nc) 351fd9400b3SPaolo Bonzini { 3521ceef9f2SJason Wang NetClientState *ncs[MAX_QUEUE_NUM]; 3531ceef9f2SJason Wang int queues, i; 354fdccce45SYang Hongyang NetFilterState *nf, *next; 3551ceef9f2SJason Wang 356f394b2e2SEric Blake assert(nc->info->type != NET_CLIENT_DRIVER_NIC); 3577fb43911SPaolo Bonzini 3581ceef9f2SJason Wang /* If the NetClientState belongs to a multiqueue backend, we will change all 3591ceef9f2SJason Wang * other NetClientStates also. 3601ceef9f2SJason Wang */ 3611ceef9f2SJason Wang queues = qemu_find_net_clients_except(nc->name, ncs, 362f394b2e2SEric Blake NET_CLIENT_DRIVER_NIC, 3631ceef9f2SJason Wang MAX_QUEUE_NUM); 3641ceef9f2SJason Wang assert(queues != 0); 3651ceef9f2SJason Wang 366fdccce45SYang Hongyang QTAILQ_FOREACH_SAFE(nf, &nc->filters, next, next) { 367fdccce45SYang Hongyang object_unparent(OBJECT(nf)); 368fdccce45SYang Hongyang } 369fdccce45SYang Hongyang 370fd9400b3SPaolo Bonzini /* If there is a peer NIC, delete and cleanup client, but do not free. */ 371f394b2e2SEric Blake if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_NIC) { 372cc1f0f45SJason Wang NICState *nic = qemu_get_nic(nc->peer); 373fd9400b3SPaolo Bonzini if (nic->peer_deleted) { 374fd9400b3SPaolo Bonzini return; 375fd9400b3SPaolo Bonzini } 376fd9400b3SPaolo Bonzini nic->peer_deleted = true; 3771ceef9f2SJason Wang 3781ceef9f2SJason Wang for (i = 0; i < queues; i++) { 3791ceef9f2SJason Wang ncs[i]->peer->link_down = true; 3801ceef9f2SJason Wang } 3811ceef9f2SJason Wang 382fd9400b3SPaolo Bonzini if (nc->peer->info->link_status_changed) { 383fd9400b3SPaolo Bonzini nc->peer->info->link_status_changed(nc->peer); 384fd9400b3SPaolo Bonzini } 3851ceef9f2SJason Wang 3861ceef9f2SJason Wang for (i = 0; i < queues; i++) { 3871ceef9f2SJason Wang qemu_cleanup_net_client(ncs[i]); 3881ceef9f2SJason Wang } 3891ceef9f2SJason Wang 390fd9400b3SPaolo Bonzini return; 391fd9400b3SPaolo Bonzini } 392fd9400b3SPaolo Bonzini 3931ceef9f2SJason Wang for (i = 0; i < queues; i++) { 3941ceef9f2SJason Wang qemu_cleanup_net_client(ncs[i]); 3951ceef9f2SJason Wang qemu_free_net_client(ncs[i]); 3961ceef9f2SJason Wang } 397948ecf21SJason Wang } 398948ecf21SJason Wang 399948ecf21SJason Wang void qemu_del_nic(NICState *nic) 400948ecf21SJason Wang { 401575a1c0eSJiri Pirko int i, queues = MAX(nic->conf->peers.queues, 1); 4021ceef9f2SJason Wang 4032bc22a58SShannon Zhao qemu_macaddr_set_free(&nic->conf->macaddr); 4042bc22a58SShannon Zhao 405fd9400b3SPaolo Bonzini /* If this is a peer NIC and peer has already been deleted, free it now. */ 406fd9400b3SPaolo Bonzini if (nic->peer_deleted) { 4071ceef9f2SJason Wang for (i = 0; i < queues; i++) { 4081ceef9f2SJason Wang qemu_free_net_client(qemu_get_subqueue(nic, i)->peer); 409fd9400b3SPaolo Bonzini } 410fd9400b3SPaolo Bonzini } 411fd9400b3SPaolo Bonzini 4121ceef9f2SJason Wang for (i = queues - 1; i >= 0; i--) { 4131ceef9f2SJason Wang NetClientState *nc = qemu_get_subqueue(nic, i); 4141ceef9f2SJason Wang 415fd9400b3SPaolo Bonzini qemu_cleanup_net_client(nc); 416fd9400b3SPaolo Bonzini qemu_free_net_client(nc); 417fd9400b3SPaolo Bonzini } 418f6b26cf2SJason Wang 419f6b26cf2SJason Wang g_free(nic); 4201ceef9f2SJason Wang } 421fd9400b3SPaolo Bonzini 422fd9400b3SPaolo Bonzini void qemu_foreach_nic(qemu_nic_foreach func, void *opaque) 423fd9400b3SPaolo Bonzini { 424fd9400b3SPaolo Bonzini NetClientState *nc; 425fd9400b3SPaolo Bonzini 426fd9400b3SPaolo Bonzini QTAILQ_FOREACH(nc, &net_clients, next) { 427f394b2e2SEric Blake if (nc->info->type == NET_CLIENT_DRIVER_NIC) { 4281ceef9f2SJason Wang if (nc->queue_index == 0) { 429cc1f0f45SJason Wang func(qemu_get_nic(nc), opaque); 430fd9400b3SPaolo Bonzini } 431fd9400b3SPaolo Bonzini } 432fd9400b3SPaolo Bonzini } 4331ceef9f2SJason Wang } 434fd9400b3SPaolo Bonzini 435d6085e3aSStefan Hajnoczi bool qemu_has_ufo(NetClientState *nc) 4361f55ac45SVincenzo Maffione { 437d6085e3aSStefan Hajnoczi if (!nc || !nc->info->has_ufo) { 4381f55ac45SVincenzo Maffione return false; 4391f55ac45SVincenzo Maffione } 4401f55ac45SVincenzo Maffione 441d6085e3aSStefan Hajnoczi return nc->info->has_ufo(nc); 4421f55ac45SVincenzo Maffione } 4431f55ac45SVincenzo Maffione 444d6085e3aSStefan Hajnoczi bool qemu_has_vnet_hdr(NetClientState *nc) 4451f55ac45SVincenzo Maffione { 446d6085e3aSStefan Hajnoczi if (!nc || !nc->info->has_vnet_hdr) { 4471f55ac45SVincenzo Maffione return false; 4481f55ac45SVincenzo Maffione } 4491f55ac45SVincenzo Maffione 450d6085e3aSStefan Hajnoczi return nc->info->has_vnet_hdr(nc); 4511f55ac45SVincenzo Maffione } 4521f55ac45SVincenzo Maffione 453d6085e3aSStefan Hajnoczi bool qemu_has_vnet_hdr_len(NetClientState *nc, int len) 4541f55ac45SVincenzo Maffione { 455d6085e3aSStefan Hajnoczi if (!nc || !nc->info->has_vnet_hdr_len) { 4561f55ac45SVincenzo Maffione return false; 4571f55ac45SVincenzo Maffione } 4581f55ac45SVincenzo Maffione 459d6085e3aSStefan Hajnoczi return nc->info->has_vnet_hdr_len(nc, len); 4601f55ac45SVincenzo Maffione } 4611f55ac45SVincenzo Maffione 462d6085e3aSStefan Hajnoczi void qemu_using_vnet_hdr(NetClientState *nc, bool enable) 4631f55ac45SVincenzo Maffione { 464d6085e3aSStefan Hajnoczi if (!nc || !nc->info->using_vnet_hdr) { 4651f55ac45SVincenzo Maffione return; 4661f55ac45SVincenzo Maffione } 4671f55ac45SVincenzo Maffione 468d6085e3aSStefan Hajnoczi nc->info->using_vnet_hdr(nc, enable); 4691f55ac45SVincenzo Maffione } 4701f55ac45SVincenzo Maffione 471d6085e3aSStefan Hajnoczi void qemu_set_offload(NetClientState *nc, int csum, int tso4, int tso6, 4721f55ac45SVincenzo Maffione int ecn, int ufo) 4731f55ac45SVincenzo Maffione { 474d6085e3aSStefan Hajnoczi if (!nc || !nc->info->set_offload) { 4751f55ac45SVincenzo Maffione return; 4761f55ac45SVincenzo Maffione } 4771f55ac45SVincenzo Maffione 478d6085e3aSStefan Hajnoczi nc->info->set_offload(nc, csum, tso4, tso6, ecn, ufo); 4791f55ac45SVincenzo Maffione } 4801f55ac45SVincenzo Maffione 481d6085e3aSStefan Hajnoczi void qemu_set_vnet_hdr_len(NetClientState *nc, int len) 4821f55ac45SVincenzo Maffione { 483d6085e3aSStefan Hajnoczi if (!nc || !nc->info->set_vnet_hdr_len) { 4841f55ac45SVincenzo Maffione return; 4851f55ac45SVincenzo Maffione } 4861f55ac45SVincenzo Maffione 487d6b732e9SZhang Chen nc->vnet_hdr_len = len; 488d6085e3aSStefan Hajnoczi nc->info->set_vnet_hdr_len(nc, len); 4891f55ac45SVincenzo Maffione } 4901f55ac45SVincenzo Maffione 491c80cd6bbSGreg Kurz int qemu_set_vnet_le(NetClientState *nc, bool is_le) 492c80cd6bbSGreg Kurz { 493052bd52fSMichael S. Tsirkin #ifdef HOST_WORDS_BIGENDIAN 494c80cd6bbSGreg Kurz if (!nc || !nc->info->set_vnet_le) { 495c80cd6bbSGreg Kurz return -ENOSYS; 496c80cd6bbSGreg Kurz } 497c80cd6bbSGreg Kurz 498c80cd6bbSGreg Kurz return nc->info->set_vnet_le(nc, is_le); 499052bd52fSMichael S. Tsirkin #else 500052bd52fSMichael S. Tsirkin return 0; 501052bd52fSMichael S. Tsirkin #endif 502c80cd6bbSGreg Kurz } 503c80cd6bbSGreg Kurz 504c80cd6bbSGreg Kurz int qemu_set_vnet_be(NetClientState *nc, bool is_be) 505c80cd6bbSGreg Kurz { 506052bd52fSMichael S. Tsirkin #ifdef HOST_WORDS_BIGENDIAN 507052bd52fSMichael S. Tsirkin return 0; 508052bd52fSMichael S. Tsirkin #else 509c80cd6bbSGreg Kurz if (!nc || !nc->info->set_vnet_be) { 510c80cd6bbSGreg Kurz return -ENOSYS; 511c80cd6bbSGreg Kurz } 512c80cd6bbSGreg Kurz 513c80cd6bbSGreg Kurz return nc->info->set_vnet_be(nc, is_be); 514052bd52fSMichael S. Tsirkin #endif 515c80cd6bbSGreg Kurz } 516c80cd6bbSGreg Kurz 517fd9400b3SPaolo Bonzini int qemu_can_send_packet(NetClientState *sender) 518fd9400b3SPaolo Bonzini { 519e1d64c08Szhanghailiang int vm_running = runstate_is_running(); 520e1d64c08Szhanghailiang 521e1d64c08Szhanghailiang if (!vm_running) { 522e1d64c08Szhanghailiang return 0; 523e1d64c08Szhanghailiang } 524e1d64c08Szhanghailiang 525fd9400b3SPaolo Bonzini if (!sender->peer) { 526fd9400b3SPaolo Bonzini return 1; 527fd9400b3SPaolo Bonzini } 528fd9400b3SPaolo Bonzini 529fd9400b3SPaolo Bonzini if (sender->peer->receive_disabled) { 530fd9400b3SPaolo Bonzini return 0; 531fd9400b3SPaolo Bonzini } else if (sender->peer->info->can_receive && 532fd9400b3SPaolo Bonzini !sender->peer->info->can_receive(sender->peer)) { 533fd9400b3SPaolo Bonzini return 0; 534fd9400b3SPaolo Bonzini } 535fd9400b3SPaolo Bonzini return 1; 536fd9400b3SPaolo Bonzini } 537fd9400b3SPaolo Bonzini 538e64c770dSYang Hongyang static ssize_t filter_receive_iov(NetClientState *nc, 539e64c770dSYang Hongyang NetFilterDirection direction, 540e64c770dSYang Hongyang NetClientState *sender, 541e64c770dSYang Hongyang unsigned flags, 542e64c770dSYang Hongyang const struct iovec *iov, 543e64c770dSYang Hongyang int iovcnt, 544e64c770dSYang Hongyang NetPacketSent *sent_cb) 545e64c770dSYang Hongyang { 546e64c770dSYang Hongyang ssize_t ret = 0; 547e64c770dSYang Hongyang NetFilterState *nf = NULL; 548e64c770dSYang Hongyang 54925aaadf0SLi Zhijian if (direction == NET_FILTER_DIRECTION_TX) { 550e64c770dSYang Hongyang QTAILQ_FOREACH(nf, &nc->filters, next) { 551e64c770dSYang Hongyang ret = qemu_netfilter_receive(nf, direction, sender, flags, iov, 552e64c770dSYang Hongyang iovcnt, sent_cb); 553e64c770dSYang Hongyang if (ret) { 554e64c770dSYang Hongyang return ret; 555e64c770dSYang Hongyang } 556e64c770dSYang Hongyang } 55725aaadf0SLi Zhijian } else { 558eae3eb3eSPaolo Bonzini QTAILQ_FOREACH_REVERSE(nf, &nc->filters, next) { 55925aaadf0SLi Zhijian ret = qemu_netfilter_receive(nf, direction, sender, flags, iov, 56025aaadf0SLi Zhijian iovcnt, sent_cb); 56125aaadf0SLi Zhijian if (ret) { 56225aaadf0SLi Zhijian return ret; 56325aaadf0SLi Zhijian } 56425aaadf0SLi Zhijian } 56525aaadf0SLi Zhijian } 566e64c770dSYang Hongyang 567e64c770dSYang Hongyang return ret; 568e64c770dSYang Hongyang } 569e64c770dSYang Hongyang 570e64c770dSYang Hongyang static ssize_t filter_receive(NetClientState *nc, 571e64c770dSYang Hongyang NetFilterDirection direction, 572e64c770dSYang Hongyang NetClientState *sender, 573e64c770dSYang Hongyang unsigned flags, 574e64c770dSYang Hongyang const uint8_t *data, 575e64c770dSYang Hongyang size_t size, 576e64c770dSYang Hongyang NetPacketSent *sent_cb) 577e64c770dSYang Hongyang { 578e64c770dSYang Hongyang struct iovec iov = { 579e64c770dSYang Hongyang .iov_base = (void *)data, 580e64c770dSYang Hongyang .iov_len = size 581e64c770dSYang Hongyang }; 582e64c770dSYang Hongyang 583e64c770dSYang Hongyang return filter_receive_iov(nc, direction, sender, flags, &iov, 1, sent_cb); 584e64c770dSYang Hongyang } 585e64c770dSYang Hongyang 586fd9400b3SPaolo Bonzini void qemu_purge_queued_packets(NetClientState *nc) 587fd9400b3SPaolo Bonzini { 588fd9400b3SPaolo Bonzini if (!nc->peer) { 589fd9400b3SPaolo Bonzini return; 590fd9400b3SPaolo Bonzini } 591fd9400b3SPaolo Bonzini 592067404beSJan Kiszka qemu_net_queue_purge(nc->peer->incoming_queue, nc); 593fd9400b3SPaolo Bonzini } 594fd9400b3SPaolo Bonzini 595ca77d85eSMichael S. Tsirkin void qemu_flush_or_purge_queued_packets(NetClientState *nc, bool purge) 596fd9400b3SPaolo Bonzini { 597fd9400b3SPaolo Bonzini nc->receive_disabled = 0; 598fd9400b3SPaolo Bonzini 599f394b2e2SEric Blake if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_HUBPORT) { 600199ee608SLuigi Rizzo if (net_hub_flush(nc->peer)) { 601199ee608SLuigi Rizzo qemu_notify_event(); 602199ee608SLuigi Rizzo } 603199ee608SLuigi Rizzo } 604067404beSJan Kiszka if (qemu_net_queue_flush(nc->incoming_queue)) { 605fd9400b3SPaolo Bonzini /* We emptied the queue successfully, signal to the IO thread to repoll 606fd9400b3SPaolo Bonzini * the file descriptor (for tap, for example). 607fd9400b3SPaolo Bonzini */ 608fd9400b3SPaolo Bonzini qemu_notify_event(); 609ca77d85eSMichael S. Tsirkin } else if (purge) { 610ca77d85eSMichael S. Tsirkin /* Unable to empty the queue, purge remaining packets */ 611ca77d85eSMichael S. Tsirkin qemu_net_queue_purge(nc->incoming_queue, nc); 612fd9400b3SPaolo Bonzini } 613fd9400b3SPaolo Bonzini } 614fd9400b3SPaolo Bonzini 615ca77d85eSMichael S. Tsirkin void qemu_flush_queued_packets(NetClientState *nc) 616ca77d85eSMichael S. Tsirkin { 617ca77d85eSMichael S. Tsirkin qemu_flush_or_purge_queued_packets(nc, false); 618ca77d85eSMichael S. Tsirkin } 619ca77d85eSMichael S. Tsirkin 620fd9400b3SPaolo Bonzini static ssize_t qemu_send_packet_async_with_flags(NetClientState *sender, 621fd9400b3SPaolo Bonzini unsigned flags, 622fd9400b3SPaolo Bonzini const uint8_t *buf, int size, 623fd9400b3SPaolo Bonzini NetPacketSent *sent_cb) 624fd9400b3SPaolo Bonzini { 625fd9400b3SPaolo Bonzini NetQueue *queue; 626e64c770dSYang Hongyang int ret; 627fd9400b3SPaolo Bonzini 628fd9400b3SPaolo Bonzini #ifdef DEBUG_NET 629fd9400b3SPaolo Bonzini printf("qemu_send_packet_async:\n"); 630a1555559SIsaac Lozano qemu_hexdump((const char *)buf, stdout, "net", size); 631fd9400b3SPaolo Bonzini #endif 632fd9400b3SPaolo Bonzini 633fd9400b3SPaolo Bonzini if (sender->link_down || !sender->peer) { 634fd9400b3SPaolo Bonzini return size; 635fd9400b3SPaolo Bonzini } 636fd9400b3SPaolo Bonzini 637e64c770dSYang Hongyang /* Let filters handle the packet first */ 638e64c770dSYang Hongyang ret = filter_receive(sender, NET_FILTER_DIRECTION_TX, 639e64c770dSYang Hongyang sender, flags, buf, size, sent_cb); 640e64c770dSYang Hongyang if (ret) { 641e64c770dSYang Hongyang return ret; 642e64c770dSYang Hongyang } 643e64c770dSYang Hongyang 644e64c770dSYang Hongyang ret = filter_receive(sender->peer, NET_FILTER_DIRECTION_RX, 645e64c770dSYang Hongyang sender, flags, buf, size, sent_cb); 646e64c770dSYang Hongyang if (ret) { 647e64c770dSYang Hongyang return ret; 648e64c770dSYang Hongyang } 649e64c770dSYang Hongyang 650067404beSJan Kiszka queue = sender->peer->incoming_queue; 651fd9400b3SPaolo Bonzini 652fd9400b3SPaolo Bonzini return qemu_net_queue_send(queue, sender, flags, buf, size, sent_cb); 653fd9400b3SPaolo Bonzini } 654fd9400b3SPaolo Bonzini 655fd9400b3SPaolo Bonzini ssize_t qemu_send_packet_async(NetClientState *sender, 656fd9400b3SPaolo Bonzini const uint8_t *buf, int size, 657fd9400b3SPaolo Bonzini NetPacketSent *sent_cb) 658fd9400b3SPaolo Bonzini { 659fd9400b3SPaolo Bonzini return qemu_send_packet_async_with_flags(sender, QEMU_NET_PACKET_FLAG_NONE, 660fd9400b3SPaolo Bonzini buf, size, sent_cb); 661fd9400b3SPaolo Bonzini } 662fd9400b3SPaolo Bonzini 663625a526bSMarc-André Lureau ssize_t qemu_send_packet(NetClientState *nc, const uint8_t *buf, int size) 664fd9400b3SPaolo Bonzini { 665625a526bSMarc-André Lureau return qemu_send_packet_async(nc, buf, size, NULL); 666fd9400b3SPaolo Bonzini } 667fd9400b3SPaolo Bonzini 668fd9400b3SPaolo Bonzini ssize_t qemu_send_packet_raw(NetClientState *nc, const uint8_t *buf, int size) 669fd9400b3SPaolo Bonzini { 670fd9400b3SPaolo Bonzini return qemu_send_packet_async_with_flags(nc, QEMU_NET_PACKET_FLAG_RAW, 671fd9400b3SPaolo Bonzini buf, size, NULL); 672fd9400b3SPaolo Bonzini } 673fd9400b3SPaolo Bonzini 674fd9400b3SPaolo Bonzini static ssize_t nc_sendv_compat(NetClientState *nc, const struct iovec *iov, 675fefe2a78SYang Hongyang int iovcnt, unsigned flags) 676fd9400b3SPaolo Bonzini { 67774044c8fSPooja Dhannawat uint8_t *buf = NULL; 678fefe2a78SYang Hongyang uint8_t *buffer; 679fd9400b3SPaolo Bonzini size_t offset; 68074044c8fSPooja Dhannawat ssize_t ret; 681fd9400b3SPaolo Bonzini 682fefe2a78SYang Hongyang if (iovcnt == 1) { 683fefe2a78SYang Hongyang buffer = iov[0].iov_base; 684fefe2a78SYang Hongyang offset = iov[0].iov_len; 685fefe2a78SYang Hongyang } else { 68647f9f158SPeter Lieven offset = iov_size(iov, iovcnt); 68747f9f158SPeter Lieven if (offset > NET_BUFSIZE) { 68847f9f158SPeter Lieven return -1; 68947f9f158SPeter Lieven } 69047f9f158SPeter Lieven buf = g_malloc(offset); 691fefe2a78SYang Hongyang buffer = buf; 69247f9f158SPeter Lieven offset = iov_to_buf(iov, iovcnt, 0, buf, offset); 693fefe2a78SYang Hongyang } 694fd9400b3SPaolo Bonzini 695fefe2a78SYang Hongyang if (flags & QEMU_NET_PACKET_FLAG_RAW && nc->info->receive_raw) { 69674044c8fSPooja Dhannawat ret = nc->info->receive_raw(nc, buffer, offset); 697fefe2a78SYang Hongyang } else { 69874044c8fSPooja Dhannawat ret = nc->info->receive(nc, buffer, offset); 699fd9400b3SPaolo Bonzini } 70074044c8fSPooja Dhannawat 70174044c8fSPooja Dhannawat g_free(buf); 70274044c8fSPooja Dhannawat return ret; 703fefe2a78SYang Hongyang } 704fd9400b3SPaolo Bonzini 70525c01bd1SJason Wang static ssize_t qemu_deliver_packet_iov(NetClientState *sender, 706fd9400b3SPaolo Bonzini unsigned flags, 707fd9400b3SPaolo Bonzini const struct iovec *iov, 708fd9400b3SPaolo Bonzini int iovcnt, 709fd9400b3SPaolo Bonzini void *opaque) 710fd9400b3SPaolo Bonzini { 711fd9400b3SPaolo Bonzini NetClientState *nc = opaque; 712fd9400b3SPaolo Bonzini int ret; 713fd9400b3SPaolo Bonzini 7141592a994SJason Wang 715fd9400b3SPaolo Bonzini if (nc->link_down) { 71625c01bd1SJason Wang return iov_size(iov, iovcnt); 717fd9400b3SPaolo Bonzini } 718fd9400b3SPaolo Bonzini 719fd9400b3SPaolo Bonzini if (nc->receive_disabled) { 720fd9400b3SPaolo Bonzini return 0; 721fd9400b3SPaolo Bonzini } 722fd9400b3SPaolo Bonzini 723ca1ee3d6SPeter Lieven if (nc->info->receive_iov && !(flags & QEMU_NET_PACKET_FLAG_RAW)) { 724fd9400b3SPaolo Bonzini ret = nc->info->receive_iov(nc, iov, iovcnt); 725fd9400b3SPaolo Bonzini } else { 726fefe2a78SYang Hongyang ret = nc_sendv_compat(nc, iov, iovcnt, flags); 727fd9400b3SPaolo Bonzini } 728fd9400b3SPaolo Bonzini 729fd9400b3SPaolo Bonzini if (ret == 0) { 730fd9400b3SPaolo Bonzini nc->receive_disabled = 1; 731fd9400b3SPaolo Bonzini } 732fd9400b3SPaolo Bonzini 733fd9400b3SPaolo Bonzini return ret; 734fd9400b3SPaolo Bonzini } 735fd9400b3SPaolo Bonzini 736fd9400b3SPaolo Bonzini ssize_t qemu_sendv_packet_async(NetClientState *sender, 737fd9400b3SPaolo Bonzini const struct iovec *iov, int iovcnt, 738fd9400b3SPaolo Bonzini NetPacketSent *sent_cb) 739fd9400b3SPaolo Bonzini { 740fd9400b3SPaolo Bonzini NetQueue *queue; 74125c01bd1SJason Wang size_t size = iov_size(iov, iovcnt); 742e64c770dSYang Hongyang int ret; 743fd9400b3SPaolo Bonzini 74425c01bd1SJason Wang if (size > NET_BUFSIZE) { 74525c01bd1SJason Wang return size; 74625c01bd1SJason Wang } 74725c01bd1SJason Wang 748fd9400b3SPaolo Bonzini if (sender->link_down || !sender->peer) { 74925c01bd1SJason Wang return size; 750fd9400b3SPaolo Bonzini } 751fd9400b3SPaolo Bonzini 752e64c770dSYang Hongyang /* Let filters handle the packet first */ 753e64c770dSYang Hongyang ret = filter_receive_iov(sender, NET_FILTER_DIRECTION_TX, sender, 754e64c770dSYang Hongyang QEMU_NET_PACKET_FLAG_NONE, iov, iovcnt, sent_cb); 755e64c770dSYang Hongyang if (ret) { 756e64c770dSYang Hongyang return ret; 757e64c770dSYang Hongyang } 758e64c770dSYang Hongyang 759e64c770dSYang Hongyang ret = filter_receive_iov(sender->peer, NET_FILTER_DIRECTION_RX, sender, 760e64c770dSYang Hongyang QEMU_NET_PACKET_FLAG_NONE, iov, iovcnt, sent_cb); 761e64c770dSYang Hongyang if (ret) { 762e64c770dSYang Hongyang return ret; 763e64c770dSYang Hongyang } 764e64c770dSYang Hongyang 765067404beSJan Kiszka queue = sender->peer->incoming_queue; 766fd9400b3SPaolo Bonzini 767fd9400b3SPaolo Bonzini return qemu_net_queue_send_iov(queue, sender, 768fd9400b3SPaolo Bonzini QEMU_NET_PACKET_FLAG_NONE, 769fd9400b3SPaolo Bonzini iov, iovcnt, sent_cb); 770fd9400b3SPaolo Bonzini } 771fd9400b3SPaolo Bonzini 772fd9400b3SPaolo Bonzini ssize_t 773fd9400b3SPaolo Bonzini qemu_sendv_packet(NetClientState *nc, const struct iovec *iov, int iovcnt) 774fd9400b3SPaolo Bonzini { 775fd9400b3SPaolo Bonzini return qemu_sendv_packet_async(nc, iov, iovcnt, NULL); 776fd9400b3SPaolo Bonzini } 777fd9400b3SPaolo Bonzini 778fd9400b3SPaolo Bonzini NetClientState *qemu_find_netdev(const char *id) 779fd9400b3SPaolo Bonzini { 780fd9400b3SPaolo Bonzini NetClientState *nc; 781fd9400b3SPaolo Bonzini 782fd9400b3SPaolo Bonzini QTAILQ_FOREACH(nc, &net_clients, next) { 783f394b2e2SEric Blake if (nc->info->type == NET_CLIENT_DRIVER_NIC) 784fd9400b3SPaolo Bonzini continue; 785fd9400b3SPaolo Bonzini if (!strcmp(nc->name, id)) { 786fd9400b3SPaolo Bonzini return nc; 787fd9400b3SPaolo Bonzini } 788fd9400b3SPaolo Bonzini } 789fd9400b3SPaolo Bonzini 790fd9400b3SPaolo Bonzini return NULL; 791fd9400b3SPaolo Bonzini } 792fd9400b3SPaolo Bonzini 7936c51ae73SJason Wang int qemu_find_net_clients_except(const char *id, NetClientState **ncs, 794f394b2e2SEric Blake NetClientDriver type, int max) 7956c51ae73SJason Wang { 7966c51ae73SJason Wang NetClientState *nc; 7976c51ae73SJason Wang int ret = 0; 7986c51ae73SJason Wang 7996c51ae73SJason Wang QTAILQ_FOREACH(nc, &net_clients, next) { 8006c51ae73SJason Wang if (nc->info->type == type) { 8016c51ae73SJason Wang continue; 8026c51ae73SJason Wang } 80340d19394SHani Benhabiles if (!id || !strcmp(nc->name, id)) { 8046c51ae73SJason Wang if (ret < max) { 8056c51ae73SJason Wang ncs[ret] = nc; 8066c51ae73SJason Wang } 8076c51ae73SJason Wang ret++; 8086c51ae73SJason Wang } 8096c51ae73SJason Wang } 8106c51ae73SJason Wang 8116c51ae73SJason Wang return ret; 8126c51ae73SJason Wang } 8136c51ae73SJason Wang 814fd9400b3SPaolo Bonzini static int nic_get_free_idx(void) 815fd9400b3SPaolo Bonzini { 816fd9400b3SPaolo Bonzini int index; 817fd9400b3SPaolo Bonzini 818fd9400b3SPaolo Bonzini for (index = 0; index < MAX_NICS; index++) 819fd9400b3SPaolo Bonzini if (!nd_table[index].used) 820fd9400b3SPaolo Bonzini return index; 821fd9400b3SPaolo Bonzini return -1; 822fd9400b3SPaolo Bonzini } 823fd9400b3SPaolo Bonzini 824fd9400b3SPaolo Bonzini int qemu_show_nic_models(const char *arg, const char *const *models) 825fd9400b3SPaolo Bonzini { 826fd9400b3SPaolo Bonzini int i; 827fd9400b3SPaolo Bonzini 828fd9400b3SPaolo Bonzini if (!arg || !is_help_option(arg)) { 829fd9400b3SPaolo Bonzini return 0; 830fd9400b3SPaolo Bonzini } 831fd9400b3SPaolo Bonzini 8327b71e03aSThomas Huth printf("Supported NIC models:\n"); 8337b71e03aSThomas Huth for (i = 0 ; models[i]; i++) { 8347b71e03aSThomas Huth printf("%s\n", models[i]); 8357b71e03aSThomas Huth } 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 953fd9400b3SPaolo Bonzini #ifdef CONFIG_NET_BRIDGE 954f394b2e2SEric Blake [NET_CLIENT_DRIVER_BRIDGE] = net_init_bridge, 955fd9400b3SPaolo Bonzini #endif 956f394b2e2SEric Blake [NET_CLIENT_DRIVER_HUBPORT] = net_init_hubport, 95756f41de7SPaolo Bonzini #ifdef CONFIG_VHOST_NET_USER 958f394b2e2SEric Blake [NET_CLIENT_DRIVER_VHOST_USER] = net_init_vhost_user, 95903ce5744SNikolay Nikolaev #endif 960015a33bdSGonglei #ifdef CONFIG_L2TPV3 961f394b2e2SEric Blake [NET_CLIENT_DRIVER_L2TPV3] = net_init_l2tpv3, 9623fb69aa1SAnton Ivanov #endif 963fd9400b3SPaolo Bonzini }; 964fd9400b3SPaolo Bonzini 965fd9400b3SPaolo Bonzini 9660e55c381SEric Blake static int net_client_init1(const void *object, bool is_netdev, Error **errp) 967fd9400b3SPaolo Bonzini { 968cebea510SKővágó, Zoltán Netdev legacy = {0}; 969cebea510SKővágó, Zoltán const Netdev *netdev; 970fd9400b3SPaolo Bonzini const char *name; 9714ef0defbSStefan Hajnoczi NetClientState *peer = NULL; 972fd9400b3SPaolo Bonzini 973fd9400b3SPaolo Bonzini if (is_netdev) { 974cebea510SKővágó, Zoltán netdev = object; 9751e81aba5SStefan Hajnoczi name = netdev->id; 976fd9400b3SPaolo Bonzini 977857d2087SThomas Huth if (netdev->type == NET_CLIENT_DRIVER_NIC || 978f394b2e2SEric Blake !net_client_init_fun[netdev->type]) { 979c6bd8c70SMarkus Armbruster error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "type", 980fd9400b3SPaolo Bonzini "a netdev backend type"); 981fd9400b3SPaolo Bonzini return -1; 982fd9400b3SPaolo Bonzini } 983fd9400b3SPaolo Bonzini } else { 9841e81aba5SStefan Hajnoczi const NetLegacy *net = object; 985f394b2e2SEric Blake const NetLegacyOptions *opts = net->opts; 986cebea510SKővágó, Zoltán legacy.id = net->id; 987cebea510SKővágó, Zoltán netdev = &legacy; 9881e81aba5SStefan Hajnoczi /* missing optional values have been initialized to "all bits zero" */ 9891e81aba5SStefan Hajnoczi name = net->has_id ? net->id : net->name; 9901e81aba5SStefan Hajnoczi 991101625a4SThomas Huth if (net->has_name) { 992101625a4SThomas Huth warn_report("The 'name' parameter is deprecated, use 'id' instead"); 993101625a4SThomas Huth } 994101625a4SThomas Huth 995f394b2e2SEric Blake /* Map the old options to the new flat type */ 996f394b2e2SEric Blake switch (opts->type) { 997d3be4b57SMarkus Armbruster case NET_LEGACY_OPTIONS_TYPE_NONE: 9981e81aba5SStefan Hajnoczi return 0; /* nothing to do */ 999d3be4b57SMarkus Armbruster case NET_LEGACY_OPTIONS_TYPE_NIC: 1000f394b2e2SEric Blake legacy.type = NET_CLIENT_DRIVER_NIC; 1001d3be4b57SMarkus Armbruster legacy.u.nic = opts->u.nic; 1002f394b2e2SEric Blake break; 1003d3be4b57SMarkus Armbruster case NET_LEGACY_OPTIONS_TYPE_USER: 1004f394b2e2SEric Blake legacy.type = NET_CLIENT_DRIVER_USER; 1005d3be4b57SMarkus Armbruster legacy.u.user = opts->u.user; 1006f394b2e2SEric Blake break; 1007d3be4b57SMarkus Armbruster case NET_LEGACY_OPTIONS_TYPE_TAP: 1008f394b2e2SEric Blake legacy.type = NET_CLIENT_DRIVER_TAP; 1009d3be4b57SMarkus Armbruster legacy.u.tap = opts->u.tap; 1010f394b2e2SEric Blake break; 1011d3be4b57SMarkus Armbruster case NET_LEGACY_OPTIONS_TYPE_L2TPV3: 1012f394b2e2SEric Blake legacy.type = NET_CLIENT_DRIVER_L2TPV3; 1013d3be4b57SMarkus Armbruster legacy.u.l2tpv3 = opts->u.l2tpv3; 1014f394b2e2SEric Blake break; 1015d3be4b57SMarkus Armbruster case NET_LEGACY_OPTIONS_TYPE_SOCKET: 1016f394b2e2SEric Blake legacy.type = NET_CLIENT_DRIVER_SOCKET; 1017d3be4b57SMarkus Armbruster legacy.u.socket = opts->u.socket; 1018f394b2e2SEric Blake break; 1019d3be4b57SMarkus Armbruster case NET_LEGACY_OPTIONS_TYPE_VDE: 1020f394b2e2SEric Blake legacy.type = NET_CLIENT_DRIVER_VDE; 1021d3be4b57SMarkus Armbruster legacy.u.vde = opts->u.vde; 1022f394b2e2SEric Blake break; 1023d3be4b57SMarkus Armbruster case NET_LEGACY_OPTIONS_TYPE_BRIDGE: 1024f394b2e2SEric Blake legacy.type = NET_CLIENT_DRIVER_BRIDGE; 1025d3be4b57SMarkus Armbruster legacy.u.bridge = opts->u.bridge; 1026f394b2e2SEric Blake break; 1027d3be4b57SMarkus Armbruster case NET_LEGACY_OPTIONS_TYPE_NETMAP: 1028f394b2e2SEric Blake legacy.type = NET_CLIENT_DRIVER_NETMAP; 1029d3be4b57SMarkus Armbruster legacy.u.netmap = opts->u.netmap; 1030f394b2e2SEric Blake break; 1031d3be4b57SMarkus Armbruster case NET_LEGACY_OPTIONS_TYPE_VHOST_USER: 1032f394b2e2SEric Blake legacy.type = NET_CLIENT_DRIVER_VHOST_USER; 1033d3be4b57SMarkus Armbruster legacy.u.vhost_user = opts->u.vhost_user; 1034f394b2e2SEric Blake break; 1035f394b2e2SEric Blake default: 1036f394b2e2SEric Blake abort(); 1037ca7eb184SMarkus Armbruster } 1038d139e9a6SStefan Hajnoczi 1039f394b2e2SEric Blake if (!net_client_init_fun[netdev->type]) { 1040d139e9a6SStefan Hajnoczi error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "type", 1041d139e9a6SStefan Hajnoczi "a net backend type (maybe it is not compiled " 1042d139e9a6SStefan Hajnoczi "into this binary)"); 1043d139e9a6SStefan Hajnoczi return -1; 1044d139e9a6SStefan Hajnoczi } 1045fd9400b3SPaolo Bonzini 1046af1a5c3eSThomas Huth /* Do not add to a hub if it's a nic with a netdev= parameter. */ 1047f394b2e2SEric Blake if (netdev->type != NET_CLIENT_DRIVER_NIC || 1048d3be4b57SMarkus Armbruster !opts->u.nic.has_netdev) { 1049af1a5c3eSThomas Huth peer = net_hub_add_port(0, NULL, NULL); 1050a2dbe135SThomas Huth } 1051fd9400b3SPaolo Bonzini } 1052fd9400b3SPaolo Bonzini 1053f394b2e2SEric Blake if (net_client_init_fun[netdev->type](netdev, name, peer, errp) < 0) { 1054a30ecde6SMarkus Armbruster /* FIXME drop when all init functions store an Error */ 1055a30ecde6SMarkus Armbruster if (errp && !*errp) { 1056c6bd8c70SMarkus Armbruster error_setg(errp, QERR_DEVICE_INIT_FAILED, 1057977c736fSMarkus Armbruster NetClientDriver_str(netdev->type)); 1058a30ecde6SMarkus Armbruster } 1059fd9400b3SPaolo Bonzini return -1; 1060fd9400b3SPaolo Bonzini } 1061fd9400b3SPaolo Bonzini return 0; 1062fd9400b3SPaolo Bonzini } 1063fd9400b3SPaolo Bonzini 1064547203eaSThomas Huth static void show_netdevs(void) 1065547203eaSThomas Huth { 1066547203eaSThomas Huth int idx; 1067547203eaSThomas Huth const char *available_netdevs[] = { 1068547203eaSThomas Huth "socket", 1069547203eaSThomas Huth "hubport", 1070547203eaSThomas Huth "tap", 1071547203eaSThomas Huth #ifdef CONFIG_SLIRP 1072547203eaSThomas Huth "user", 1073547203eaSThomas Huth #endif 1074547203eaSThomas Huth #ifdef CONFIG_L2TPV3 1075547203eaSThomas Huth "l2tpv3", 1076547203eaSThomas Huth #endif 1077547203eaSThomas Huth #ifdef CONFIG_VDE 1078547203eaSThomas Huth "vde", 1079547203eaSThomas Huth #endif 1080547203eaSThomas Huth #ifdef CONFIG_NET_BRIDGE 1081547203eaSThomas Huth "bridge", 1082547203eaSThomas Huth #endif 1083547203eaSThomas Huth #ifdef CONFIG_NETMAP 1084547203eaSThomas Huth "netmap", 1085547203eaSThomas Huth #endif 1086547203eaSThomas Huth #ifdef CONFIG_POSIX 1087547203eaSThomas Huth "vhost-user", 1088547203eaSThomas Huth #endif 1089547203eaSThomas Huth }; 1090fd9400b3SPaolo Bonzini 1091547203eaSThomas Huth printf("Available netdev backend types:\n"); 1092547203eaSThomas Huth for (idx = 0; idx < ARRAY_SIZE(available_netdevs); idx++) { 1093547203eaSThomas Huth puts(available_netdevs[idx]); 1094547203eaSThomas Huth } 1095547203eaSThomas Huth } 1096fd9400b3SPaolo Bonzini 1097aa09a485SThomas Huth static int net_client_init(QemuOpts *opts, bool is_netdev, Error **errp) 1098fd9400b3SPaolo Bonzini { 1099c1112b2dSStefano Garzarella gchar **substrings = NULL; 1100fd9400b3SPaolo Bonzini void *object = NULL; 1101fd9400b3SPaolo Bonzini Error *err = NULL; 1102fd9400b3SPaolo Bonzini int ret = -1; 110309204eacSEric Blake Visitor *v = opts_visitor_new(opts); 1104fd9400b3SPaolo Bonzini 11058b43f964SLin Ma const char *type = qemu_opt_get(opts, "type"); 11068b43f964SLin Ma 11078b43f964SLin Ma if (is_netdev && type && is_help_option(type)) { 1108547203eaSThomas Huth show_netdevs(); 1109547203eaSThomas Huth exit(0); 1110547203eaSThomas Huth } else { 11117aac531eSYann Bordenave /* Parse convenience option format ip6-net=fec0::0[/64] */ 1112891a2bb5SSamuel Thibault const char *ip6_net = qemu_opt_get(opts, "ipv6-net"); 11137aac531eSYann Bordenave 11147aac531eSYann Bordenave if (ip6_net) { 1115c1112b2dSStefano Garzarella char *prefix_addr; 1116c1112b2dSStefano Garzarella unsigned long prefix_len = 64; /* Default 64bit prefix length. */ 11177aac531eSYann Bordenave 1118c1112b2dSStefano Garzarella substrings = g_strsplit(ip6_net, "/", 2); 1119c1112b2dSStefano Garzarella if (!substrings || !substrings[0]) { 1120c1112b2dSStefano Garzarella error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "ipv6-net", 1121c1112b2dSStefano Garzarella "a valid IPv6 prefix"); 1122c1112b2dSStefano Garzarella goto out; 1123c1112b2dSStefano Garzarella } 1124c1112b2dSStefano Garzarella 1125c1112b2dSStefano Garzarella prefix_addr = substrings[0]; 1126c1112b2dSStefano Garzarella 1127c1112b2dSStefano Garzarella if (substrings[1]) { 11287aac531eSYann Bordenave /* User-specified prefix length. */ 11297aac531eSYann Bordenave int err; 11307aac531eSYann Bordenave 1131c1112b2dSStefano Garzarella err = qemu_strtoul(substrings[1], NULL, 10, &prefix_len); 11327aac531eSYann Bordenave if (err) { 11337aac531eSYann Bordenave error_setg(errp, QERR_INVALID_PARAMETER_VALUE, 113421c520d0SStefano Garzarella "ipv6-prefixlen", "a number"); 113521c520d0SStefano Garzarella goto out; 11367aac531eSYann Bordenave } 11377aac531eSYann Bordenave } 1138c1112b2dSStefano Garzarella 1139c1112b2dSStefano Garzarella qemu_opt_set(opts, "ipv6-prefix", prefix_addr, &error_abort); 1140c1112b2dSStefano Garzarella qemu_opt_set_number(opts, "ipv6-prefixlen", prefix_len, 1141c1112b2dSStefano Garzarella &error_abort); 1142891a2bb5SSamuel Thibault qemu_opt_unset(opts, "ipv6-net"); 11437aac531eSYann Bordenave } 11447aac531eSYann Bordenave } 11457aac531eSYann Bordenave 114696a1616cSEric Blake if (is_netdev) { 114796a1616cSEric Blake visit_type_Netdev(v, NULL, (Netdev **)&object, &err); 114896a1616cSEric Blake } else { 114996a1616cSEric Blake visit_type_NetLegacy(v, NULL, (NetLegacy **)&object, &err); 1150fd9400b3SPaolo Bonzini } 1151fd9400b3SPaolo Bonzini 1152fd9400b3SPaolo Bonzini if (!err) { 1153fd9400b3SPaolo Bonzini ret = net_client_init1(object, is_netdev, &err); 1154fd9400b3SPaolo Bonzini } 1155fd9400b3SPaolo Bonzini 115696a1616cSEric Blake if (is_netdev) { 115796a1616cSEric Blake qapi_free_Netdev(object); 115896a1616cSEric Blake } else { 115996a1616cSEric Blake qapi_free_NetLegacy(object); 1160fd9400b3SPaolo Bonzini } 1161fd9400b3SPaolo Bonzini 116221c520d0SStefano Garzarella out: 1163fd9400b3SPaolo Bonzini error_propagate(errp, err); 1164c1112b2dSStefano Garzarella g_strfreev(substrings); 116509204eacSEric Blake visit_free(v); 1166fd9400b3SPaolo Bonzini return ret; 1167fd9400b3SPaolo Bonzini } 1168fd9400b3SPaolo Bonzini 1169fd9400b3SPaolo Bonzini void netdev_add(QemuOpts *opts, Error **errp) 1170fd9400b3SPaolo Bonzini { 11710e55c381SEric Blake net_client_init(opts, true, errp); 1172fd9400b3SPaolo Bonzini } 1173fd9400b3SPaolo Bonzini 1174485febc6SMarkus Armbruster void qmp_netdev_add(QDict *qdict, QObject **ret, Error **errp) 1175fd9400b3SPaolo Bonzini { 1176fd9400b3SPaolo Bonzini Error *local_err = NULL; 1177fd9400b3SPaolo Bonzini QemuOptsList *opts_list; 1178fd9400b3SPaolo Bonzini QemuOpts *opts; 1179fd9400b3SPaolo Bonzini 1180fd9400b3SPaolo Bonzini opts_list = qemu_find_opts_err("netdev", &local_err); 118184d18f06SMarkus Armbruster if (local_err) { 1182485febc6SMarkus Armbruster goto out; 1183fd9400b3SPaolo Bonzini } 1184fd9400b3SPaolo Bonzini 1185fd9400b3SPaolo Bonzini opts = qemu_opts_from_qdict(opts_list, qdict, &local_err); 118684d18f06SMarkus Armbruster if (local_err) { 1187485febc6SMarkus Armbruster goto out; 1188fd9400b3SPaolo Bonzini } 1189fd9400b3SPaolo Bonzini 1190fd9400b3SPaolo Bonzini netdev_add(opts, &local_err); 119184d18f06SMarkus Armbruster if (local_err) { 1192fd9400b3SPaolo Bonzini qemu_opts_del(opts); 1193485febc6SMarkus Armbruster goto out; 1194fd9400b3SPaolo Bonzini } 1195fd9400b3SPaolo Bonzini 1196485febc6SMarkus Armbruster out: 1197485febc6SMarkus Armbruster error_propagate(errp, local_err); 1198fd9400b3SPaolo Bonzini } 1199fd9400b3SPaolo Bonzini 1200fd9400b3SPaolo Bonzini void qmp_netdev_del(const char *id, Error **errp) 1201fd9400b3SPaolo Bonzini { 1202fd9400b3SPaolo Bonzini NetClientState *nc; 1203fd9400b3SPaolo Bonzini QemuOpts *opts; 1204fd9400b3SPaolo Bonzini 1205fd9400b3SPaolo Bonzini nc = qemu_find_netdev(id); 1206fd9400b3SPaolo Bonzini if (!nc) { 120775158ebbSMarkus Armbruster error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 120875158ebbSMarkus Armbruster "Device '%s' not found", id); 1209fd9400b3SPaolo Bonzini return; 1210fd9400b3SPaolo Bonzini } 1211fd9400b3SPaolo Bonzini 1212fd9400b3SPaolo Bonzini opts = qemu_opts_find(qemu_find_opts_err("netdev", NULL), id); 1213fd9400b3SPaolo Bonzini if (!opts) { 1214fd9400b3SPaolo Bonzini error_setg(errp, "Device '%s' is not a netdev", id); 1215fd9400b3SPaolo Bonzini return; 1216fd9400b3SPaolo Bonzini } 1217fd9400b3SPaolo Bonzini 1218fd9400b3SPaolo Bonzini qemu_del_net_client(nc); 1219fd9400b3SPaolo Bonzini qemu_opts_del(opts); 1220fd9400b3SPaolo Bonzini } 1221fd9400b3SPaolo Bonzini 1222aa9156f4Szhanghailiang static void netfilter_print_info(Monitor *mon, NetFilterState *nf) 1223aa9156f4Szhanghailiang { 1224aa9156f4Szhanghailiang char *str; 1225aa9156f4Szhanghailiang ObjectProperty *prop; 1226aa9156f4Szhanghailiang ObjectPropertyIterator iter; 12273b098d56SEric Blake Visitor *v; 1228aa9156f4Szhanghailiang 1229aa9156f4Szhanghailiang /* generate info str */ 1230aa9156f4Szhanghailiang object_property_iter_init(&iter, OBJECT(nf)); 1231aa9156f4Szhanghailiang while ((prop = object_property_iter_next(&iter))) { 1232aa9156f4Szhanghailiang if (!strcmp(prop->name, "type")) { 1233aa9156f4Szhanghailiang continue; 1234aa9156f4Szhanghailiang } 12353b098d56SEric Blake v = string_output_visitor_new(false, &str); 12363b098d56SEric Blake object_property_get(OBJECT(nf), v, prop->name, NULL); 12373b098d56SEric Blake visit_complete(v, &str); 12383b098d56SEric Blake visit_free(v); 1239aa9156f4Szhanghailiang monitor_printf(mon, ",%s=%s", prop->name, str); 1240aa9156f4Szhanghailiang g_free(str); 1241aa9156f4Szhanghailiang } 1242aa9156f4Szhanghailiang monitor_printf(mon, "\n"); 1243aa9156f4Szhanghailiang } 1244aa9156f4Szhanghailiang 1245fd9400b3SPaolo Bonzini void print_net_client(Monitor *mon, NetClientState *nc) 1246fd9400b3SPaolo Bonzini { 1247a4960f52SYang Hongyang NetFilterState *nf; 1248a4960f52SYang Hongyang 12491ceef9f2SJason Wang monitor_printf(mon, "%s: index=%d,type=%s,%s\n", nc->name, 12501ceef9f2SJason Wang nc->queue_index, 1251977c736fSMarkus Armbruster NetClientDriver_str(nc->info->type), 12521ceef9f2SJason Wang nc->info_str); 1253a4960f52SYang Hongyang if (!QTAILQ_EMPTY(&nc->filters)) { 1254a4960f52SYang Hongyang monitor_printf(mon, "filters:\n"); 1255a4960f52SYang Hongyang } 1256a4960f52SYang Hongyang QTAILQ_FOREACH(nf, &nc->filters, next) { 1257a3e8a3f3SYang Hongyang char *path = object_get_canonical_path_component(OBJECT(nf)); 1258aa9156f4Szhanghailiang 1259aa9156f4Szhanghailiang monitor_printf(mon, " - %s: type=%s", path, 1260aa9156f4Szhanghailiang object_get_typename(OBJECT(nf))); 1261aa9156f4Szhanghailiang netfilter_print_info(mon, nf); 1262a3e8a3f3SYang Hongyang g_free(path); 1263a4960f52SYang Hongyang } 1264fd9400b3SPaolo Bonzini } 1265fd9400b3SPaolo Bonzini 1266b1be4280SAmos Kong RxFilterInfoList *qmp_query_rx_filter(bool has_name, const char *name, 1267b1be4280SAmos Kong Error **errp) 1268b1be4280SAmos Kong { 1269b1be4280SAmos Kong NetClientState *nc; 1270b1be4280SAmos Kong RxFilterInfoList *filter_list = NULL, *last_entry = NULL; 1271b1be4280SAmos Kong 1272b1be4280SAmos Kong QTAILQ_FOREACH(nc, &net_clients, next) { 1273b1be4280SAmos Kong RxFilterInfoList *entry; 1274b1be4280SAmos Kong RxFilterInfo *info; 1275b1be4280SAmos Kong 1276b1be4280SAmos Kong if (has_name && strcmp(nc->name, name) != 0) { 1277b1be4280SAmos Kong continue; 1278b1be4280SAmos Kong } 1279b1be4280SAmos Kong 1280b1be4280SAmos Kong /* only query rx-filter information of NIC */ 1281f394b2e2SEric Blake if (nc->info->type != NET_CLIENT_DRIVER_NIC) { 1282b1be4280SAmos Kong if (has_name) { 1283b1be4280SAmos Kong error_setg(errp, "net client(%s) isn't a NIC", name); 12849083da1dSMarkus Armbruster return NULL; 1285b1be4280SAmos Kong } 1286b1be4280SAmos Kong continue; 1287b1be4280SAmos Kong } 1288b1be4280SAmos Kong 12895320c2caSVladislav Yasevich /* only query information on queue 0 since the info is per nic, 12905320c2caSVladislav Yasevich * not per queue 12915320c2caSVladislav Yasevich */ 12925320c2caSVladislav Yasevich if (nc->queue_index != 0) 12935320c2caSVladislav Yasevich continue; 12945320c2caSVladislav Yasevich 1295b1be4280SAmos Kong if (nc->info->query_rx_filter) { 1296b1be4280SAmos Kong info = nc->info->query_rx_filter(nc); 1297b1be4280SAmos Kong entry = g_malloc0(sizeof(*entry)); 1298b1be4280SAmos Kong entry->value = info; 1299b1be4280SAmos Kong 1300b1be4280SAmos Kong if (!filter_list) { 1301b1be4280SAmos Kong filter_list = entry; 1302b1be4280SAmos Kong } else { 1303b1be4280SAmos Kong last_entry->next = entry; 1304b1be4280SAmos Kong } 1305b1be4280SAmos Kong last_entry = entry; 1306b1be4280SAmos Kong } else if (has_name) { 1307b1be4280SAmos Kong error_setg(errp, "net client(%s) doesn't support" 1308b1be4280SAmos Kong " rx-filter querying", name); 13099083da1dSMarkus Armbruster return NULL; 1310b1be4280SAmos Kong } 1311638fb141SMarkus Armbruster 1312638fb141SMarkus Armbruster if (has_name) { 1313638fb141SMarkus Armbruster break; 1314638fb141SMarkus Armbruster } 1315b1be4280SAmos Kong } 1316b1be4280SAmos Kong 13179083da1dSMarkus Armbruster if (filter_list == NULL && has_name) { 1318b1be4280SAmos Kong error_setg(errp, "invalid net client name: %s", name); 1319b1be4280SAmos Kong } 1320b1be4280SAmos Kong 1321b1be4280SAmos Kong return filter_list; 1322b1be4280SAmos Kong } 1323b1be4280SAmos Kong 13241ce6be24SMarkus Armbruster void hmp_info_network(Monitor *mon, const QDict *qdict) 1325fd9400b3SPaolo Bonzini { 1326fd9400b3SPaolo Bonzini NetClientState *nc, *peer; 1327f394b2e2SEric Blake NetClientDriver type; 1328fd9400b3SPaolo Bonzini 1329fd9400b3SPaolo Bonzini net_hub_info(mon); 1330fd9400b3SPaolo Bonzini 1331fd9400b3SPaolo Bonzini QTAILQ_FOREACH(nc, &net_clients, next) { 1332fd9400b3SPaolo Bonzini peer = nc->peer; 1333fd9400b3SPaolo Bonzini type = nc->info->type; 1334fd9400b3SPaolo Bonzini 1335fd9400b3SPaolo Bonzini /* Skip if already printed in hub info */ 1336fd9400b3SPaolo Bonzini if (net_hub_id_for_client(nc, NULL) == 0) { 1337fd9400b3SPaolo Bonzini continue; 1338fd9400b3SPaolo Bonzini } 1339fd9400b3SPaolo Bonzini 1340f394b2e2SEric Blake if (!peer || type == NET_CLIENT_DRIVER_NIC) { 1341fd9400b3SPaolo Bonzini print_net_client(mon, nc); 1342fd9400b3SPaolo Bonzini } /* else it's a netdev connected to a NIC, printed with the NIC */ 1343f394b2e2SEric Blake if (peer && type == NET_CLIENT_DRIVER_NIC) { 1344fd9400b3SPaolo Bonzini monitor_printf(mon, " \\ "); 1345fd9400b3SPaolo Bonzini print_net_client(mon, peer); 1346fd9400b3SPaolo Bonzini } 1347fd9400b3SPaolo Bonzini } 1348fd9400b3SPaolo Bonzini } 1349fd9400b3SPaolo Bonzini 13505fbba3d6SZhang Chen void colo_notify_filters_event(int event, Error **errp) 13515fbba3d6SZhang Chen { 13525fbba3d6SZhang Chen NetClientState *nc; 13535fbba3d6SZhang Chen NetFilterState *nf; 13545fbba3d6SZhang Chen NetFilterClass *nfc = NULL; 13555fbba3d6SZhang Chen Error *local_err = NULL; 13565fbba3d6SZhang Chen 13575fbba3d6SZhang Chen QTAILQ_FOREACH(nc, &net_clients, next) { 13585fbba3d6SZhang Chen QTAILQ_FOREACH(nf, &nc->filters, next) { 13595fbba3d6SZhang Chen nfc = NETFILTER_GET_CLASS(OBJECT(nf)); 13605fbba3d6SZhang Chen nfc->handle_event(nf, event, &local_err); 13615fbba3d6SZhang Chen if (local_err) { 13625fbba3d6SZhang Chen error_propagate(errp, local_err); 13635fbba3d6SZhang Chen return; 13645fbba3d6SZhang Chen } 13655fbba3d6SZhang Chen } 13665fbba3d6SZhang Chen } 13675fbba3d6SZhang Chen } 13685fbba3d6SZhang Chen 1369fd9400b3SPaolo Bonzini void qmp_set_link(const char *name, bool up, Error **errp) 1370fd9400b3SPaolo Bonzini { 13711ceef9f2SJason Wang NetClientState *ncs[MAX_QUEUE_NUM]; 13721ceef9f2SJason Wang NetClientState *nc; 13731ceef9f2SJason Wang int queues, i; 1374fd9400b3SPaolo Bonzini 13751ceef9f2SJason Wang queues = qemu_find_net_clients_except(name, ncs, 1376f394b2e2SEric Blake NET_CLIENT_DRIVER__MAX, 13771ceef9f2SJason Wang MAX_QUEUE_NUM); 13781ceef9f2SJason Wang 13791ceef9f2SJason Wang if (queues == 0) { 138075158ebbSMarkus Armbruster error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 138175158ebbSMarkus Armbruster "Device '%s' not found", name); 1382fd9400b3SPaolo Bonzini return; 1383fd9400b3SPaolo Bonzini } 13841ceef9f2SJason Wang nc = ncs[0]; 1385fd9400b3SPaolo Bonzini 13861ceef9f2SJason Wang for (i = 0; i < queues; i++) { 13871ceef9f2SJason Wang ncs[i]->link_down = !up; 13881ceef9f2SJason Wang } 1389fd9400b3SPaolo Bonzini 1390fd9400b3SPaolo Bonzini if (nc->info->link_status_changed) { 1391fd9400b3SPaolo Bonzini nc->info->link_status_changed(nc); 1392fd9400b3SPaolo Bonzini } 1393fd9400b3SPaolo Bonzini 139402d38fcbSVlad Yasevich if (nc->peer) { 139502d38fcbSVlad Yasevich /* Change peer link only if the peer is NIC and then notify peer. 139602d38fcbSVlad Yasevich * If the peer is a HUBPORT or a backend, we do not change the 139702d38fcbSVlad Yasevich * link status. 1398fd9400b3SPaolo Bonzini * 1399af1a5c3eSThomas Huth * This behavior is compatible with qemu hubs where there could be 1400fd9400b3SPaolo Bonzini * multiple clients that can still communicate with each other in 140102d38fcbSVlad Yasevich * disconnected mode. For now maintain this compatibility. 140202d38fcbSVlad Yasevich */ 1403f394b2e2SEric Blake if (nc->peer->info->type == NET_CLIENT_DRIVER_NIC) { 140402d38fcbSVlad Yasevich for (i = 0; i < queues; i++) { 140502d38fcbSVlad Yasevich ncs[i]->peer->link_down = !up; 140602d38fcbSVlad Yasevich } 140702d38fcbSVlad Yasevich } 140802d38fcbSVlad Yasevich if (nc->peer->info->link_status_changed) { 1409fd9400b3SPaolo Bonzini nc->peer->info->link_status_changed(nc->peer); 1410fd9400b3SPaolo Bonzini } 1411fd9400b3SPaolo Bonzini } 141202d38fcbSVlad Yasevich } 1413fd9400b3SPaolo Bonzini 1414ca77d85eSMichael S. Tsirkin static void net_vm_change_state_handler(void *opaque, int running, 1415ca77d85eSMichael S. Tsirkin RunState state) 1416ca77d85eSMichael S. Tsirkin { 1417ca77d85eSMichael S. Tsirkin NetClientState *nc; 1418ca77d85eSMichael S. Tsirkin NetClientState *tmp; 1419ca77d85eSMichael S. Tsirkin 1420ca77d85eSMichael S. Tsirkin QTAILQ_FOREACH_SAFE(nc, &net_clients, next, tmp) { 1421625de449SFam Zheng if (running) { 1422625de449SFam Zheng /* Flush queued packets and wake up backends. */ 1423625de449SFam Zheng if (nc->peer && qemu_can_send_packet(nc)) { 1424625de449SFam Zheng qemu_flush_queued_packets(nc->peer); 1425625de449SFam Zheng } 1426625de449SFam Zheng } else { 1427625de449SFam Zheng /* Complete all queued packets, to guarantee we don't modify 1428625de449SFam Zheng * state later when VM is not running. 1429625de449SFam Zheng */ 1430ca77d85eSMichael S. Tsirkin qemu_flush_or_purge_queued_packets(nc, true); 1431ca77d85eSMichael S. Tsirkin } 1432ca77d85eSMichael S. Tsirkin } 1433ca77d85eSMichael S. Tsirkin } 1434ca77d85eSMichael S. Tsirkin 1435fd9400b3SPaolo Bonzini void net_cleanup(void) 1436fd9400b3SPaolo Bonzini { 14371ceef9f2SJason Wang NetClientState *nc; 1438fd9400b3SPaolo Bonzini 14391ceef9f2SJason Wang /* We may del multiple entries during qemu_del_net_client(), 14401ceef9f2SJason Wang * so QTAILQ_FOREACH_SAFE() is also not safe here. 14411ceef9f2SJason Wang */ 14421ceef9f2SJason Wang while (!QTAILQ_EMPTY(&net_clients)) { 14431ceef9f2SJason Wang nc = QTAILQ_FIRST(&net_clients); 1444f394b2e2SEric Blake if (nc->info->type == NET_CLIENT_DRIVER_NIC) { 1445948ecf21SJason Wang qemu_del_nic(qemu_get_nic(nc)); 1446948ecf21SJason Wang } else { 1447fd9400b3SPaolo Bonzini qemu_del_net_client(nc); 1448fd9400b3SPaolo Bonzini } 1449fd9400b3SPaolo Bonzini } 1450ca77d85eSMichael S. Tsirkin 1451ca77d85eSMichael S. Tsirkin qemu_del_vm_change_state_handler(net_change_state_entry); 1452948ecf21SJason Wang } 1453fd9400b3SPaolo Bonzini 1454fd9400b3SPaolo Bonzini void net_check_clients(void) 1455fd9400b3SPaolo Bonzini { 1456fd9400b3SPaolo Bonzini NetClientState *nc; 1457fd9400b3SPaolo Bonzini int i; 1458fd9400b3SPaolo Bonzini 1459fd9400b3SPaolo Bonzini net_hub_check_clients(); 1460fd9400b3SPaolo Bonzini 1461fd9400b3SPaolo Bonzini QTAILQ_FOREACH(nc, &net_clients, next) { 1462fd9400b3SPaolo Bonzini if (!nc->peer) { 14638297be80SAlistair Francis warn_report("%s %s has no peer", 1464b62e39b4SAlistair Francis nc->info->type == NET_CLIENT_DRIVER_NIC 1465b62e39b4SAlistair Francis ? "nic" : "netdev", 1466b62e39b4SAlistair Francis 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) { 14778297be80SAlistair Francis warn_report("requested NIC (%s, model %s) " 14788297be80SAlistair Francis "was not created (not supported by this machine?)", 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 { 148734f708b0SThomas Huth return net_client_init(opts, false, errp); 1488fd9400b3SPaolo Bonzini } 1489fd9400b3SPaolo Bonzini 149028d0de7aSMarkus Armbruster static int net_init_netdev(void *dummy, QemuOpts *opts, Error **errp) 1491fd9400b3SPaolo Bonzini { 149234f708b0SThomas Huth return net_client_init(opts, true, errp); 1493fd9400b3SPaolo Bonzini } 1494fd9400b3SPaolo Bonzini 149578cd6f7bSThomas Huth /* For the convenience "--nic" parameter */ 149678cd6f7bSThomas Huth static int net_param_nic(void *dummy, QemuOpts *opts, Error **errp) 149778cd6f7bSThomas Huth { 149878cd6f7bSThomas Huth char *mac, *nd_id; 149978cd6f7bSThomas Huth int idx, ret; 150078cd6f7bSThomas Huth NICInfo *ni; 150178cd6f7bSThomas Huth const char *type; 150278cd6f7bSThomas Huth 150378cd6f7bSThomas Huth type = qemu_opt_get(opts, "type"); 150478cd6f7bSThomas Huth if (type && g_str_equal(type, "none")) { 150578cd6f7bSThomas Huth return 0; /* Nothing to do, default_net is cleared in vl.c */ 150678cd6f7bSThomas Huth } 150778cd6f7bSThomas Huth 150878cd6f7bSThomas Huth idx = nic_get_free_idx(); 150978cd6f7bSThomas Huth if (idx == -1 || nb_nics >= MAX_NICS) { 151078cd6f7bSThomas Huth error_setg(errp, "no more on-board/default NIC slots available"); 1511fd9400b3SPaolo Bonzini return -1; 1512fd9400b3SPaolo Bonzini } 1513fd9400b3SPaolo Bonzini 151478cd6f7bSThomas Huth if (!type) { 151578cd6f7bSThomas Huth qemu_opt_set(opts, "type", "user", &error_abort); 151678cd6f7bSThomas Huth } 151778cd6f7bSThomas Huth 151878cd6f7bSThomas Huth ni = &nd_table[idx]; 151978cd6f7bSThomas Huth memset(ni, 0, sizeof(*ni)); 152078cd6f7bSThomas Huth ni->model = qemu_opt_get_del(opts, "model"); 152178cd6f7bSThomas Huth 152278cd6f7bSThomas Huth /* Create an ID if the user did not specify one */ 152378cd6f7bSThomas Huth nd_id = g_strdup(qemu_opts_id(opts)); 152478cd6f7bSThomas Huth if (!nd_id) { 152578cd6f7bSThomas Huth nd_id = g_strdup_printf("__org.qemu.nic%i\n", idx); 152678cd6f7bSThomas Huth qemu_opts_set_id(opts, nd_id); 152778cd6f7bSThomas Huth } 152878cd6f7bSThomas Huth 152978cd6f7bSThomas Huth /* Handle MAC address */ 153078cd6f7bSThomas Huth mac = qemu_opt_get_del(opts, "mac"); 153178cd6f7bSThomas Huth if (mac) { 153278cd6f7bSThomas Huth ret = net_parse_macaddr(ni->macaddr.a, mac); 153378cd6f7bSThomas Huth g_free(mac); 153478cd6f7bSThomas Huth if (ret) { 153578cd6f7bSThomas Huth error_setg(errp, "invalid syntax for ethernet address"); 15369d946191SThomas Huth goto out; 153778cd6f7bSThomas Huth } 153878cd6f7bSThomas Huth if (is_multicast_ether_addr(ni->macaddr.a)) { 153978cd6f7bSThomas Huth error_setg(errp, "NIC cannot have multicast MAC address"); 15409d946191SThomas Huth ret = -1; 15419d946191SThomas Huth goto out; 154278cd6f7bSThomas Huth } 154378cd6f7bSThomas Huth } 154478cd6f7bSThomas Huth qemu_macaddr_default_if_unset(&ni->macaddr); 154578cd6f7bSThomas Huth 154678cd6f7bSThomas Huth ret = net_client_init(opts, true, errp); 154778cd6f7bSThomas Huth if (ret == 0) { 154878cd6f7bSThomas Huth ni->netdev = qemu_find_netdev(nd_id); 154978cd6f7bSThomas Huth ni->used = true; 155078cd6f7bSThomas Huth nb_nics++; 155178cd6f7bSThomas Huth } 155278cd6f7bSThomas Huth 15539d946191SThomas Huth out: 155478cd6f7bSThomas Huth g_free(nd_id); 1555fd9400b3SPaolo Bonzini return ret; 1556fd9400b3SPaolo Bonzini } 1557fd9400b3SPaolo Bonzini 155834f708b0SThomas Huth int net_init_clients(Error **errp) 1559fd9400b3SPaolo Bonzini { 1560ca77d85eSMichael S. Tsirkin net_change_state_entry = 1561ca77d85eSMichael S. Tsirkin qemu_add_vm_change_state_handler(net_vm_change_state_handler, NULL); 1562ca77d85eSMichael S. Tsirkin 1563fd9400b3SPaolo Bonzini QTAILQ_INIT(&net_clients); 1564fd9400b3SPaolo Bonzini 156528d0de7aSMarkus Armbruster if (qemu_opts_foreach(qemu_find_opts("netdev"), 156634f708b0SThomas Huth net_init_netdev, NULL, errp)) { 1567fd9400b3SPaolo Bonzini return -1; 1568a4c7367fSMarkus Armbruster } 1569fd9400b3SPaolo Bonzini 157078cd6f7bSThomas Huth if (qemu_opts_foreach(qemu_find_opts("nic"), net_param_nic, NULL, errp)) { 157178cd6f7bSThomas Huth return -1; 157278cd6f7bSThomas Huth } 157378cd6f7bSThomas Huth 157434f708b0SThomas Huth if (qemu_opts_foreach(qemu_find_opts("net"), net_init_client, NULL, errp)) { 1575fd9400b3SPaolo Bonzini return -1; 1576fd9400b3SPaolo Bonzini } 1577fd9400b3SPaolo Bonzini 1578fd9400b3SPaolo Bonzini return 0; 1579fd9400b3SPaolo Bonzini } 1580fd9400b3SPaolo Bonzini 1581fd9400b3SPaolo Bonzini int net_client_parse(QemuOptsList *opts_list, const char *optarg) 1582fd9400b3SPaolo Bonzini { 158370b94331SMarkus Armbruster if (!qemu_opts_parse_noisily(opts_list, optarg, true)) { 1584fd9400b3SPaolo Bonzini return -1; 1585fd9400b3SPaolo Bonzini } 1586fd9400b3SPaolo Bonzini 1587fd9400b3SPaolo Bonzini return 0; 1588fd9400b3SPaolo Bonzini } 1589fd9400b3SPaolo Bonzini 1590fd9400b3SPaolo Bonzini /* From FreeBSD */ 1591fd9400b3SPaolo Bonzini /* XXX: optimize */ 1592eaba8f34SMark Cave-Ayland uint32_t net_crc32(const uint8_t *p, int len) 1593fd9400b3SPaolo Bonzini { 1594fd9400b3SPaolo Bonzini uint32_t crc; 1595fd9400b3SPaolo Bonzini int carry, i, j; 1596fd9400b3SPaolo Bonzini uint8_t b; 1597fd9400b3SPaolo Bonzini 1598fd9400b3SPaolo Bonzini crc = 0xffffffff; 1599eaba8f34SMark Cave-Ayland for (i = 0; i < len; i++) { 1600eaba8f34SMark Cave-Ayland b = *p++; 1601fd9400b3SPaolo Bonzini for (j = 0; j < 8; j++) { 1602fd9400b3SPaolo Bonzini carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01); 1603fd9400b3SPaolo Bonzini crc <<= 1; 1604fd9400b3SPaolo Bonzini b >>= 1; 1605fd9400b3SPaolo Bonzini if (carry) { 1606eaba8f34SMark Cave-Ayland crc = ((crc ^ POLYNOMIAL_BE) | carry); 1607fd9400b3SPaolo Bonzini } 1608fd9400b3SPaolo Bonzini } 1609fd9400b3SPaolo Bonzini } 1610eaba8f34SMark Cave-Ayland 1611eaba8f34SMark Cave-Ayland return crc; 1612eaba8f34SMark Cave-Ayland } 1613eaba8f34SMark Cave-Ayland 1614f1a7deb9SMark Cave-Ayland uint32_t net_crc32_le(const uint8_t *p, int len) 1615f1a7deb9SMark Cave-Ayland { 1616f1a7deb9SMark Cave-Ayland uint32_t crc; 1617f1a7deb9SMark Cave-Ayland int carry, i, j; 1618f1a7deb9SMark Cave-Ayland uint8_t b; 1619f1a7deb9SMark Cave-Ayland 1620f1a7deb9SMark Cave-Ayland crc = 0xffffffff; 1621f1a7deb9SMark Cave-Ayland for (i = 0; i < len; i++) { 1622f1a7deb9SMark Cave-Ayland b = *p++; 1623f1a7deb9SMark Cave-Ayland for (j = 0; j < 8; j++) { 1624f1a7deb9SMark Cave-Ayland carry = (crc & 0x1) ^ (b & 0x01); 1625f1a7deb9SMark Cave-Ayland crc >>= 1; 1626f1a7deb9SMark Cave-Ayland b >>= 1; 1627f1a7deb9SMark Cave-Ayland if (carry) { 1628f1a7deb9SMark Cave-Ayland crc ^= POLYNOMIAL_LE; 1629f1a7deb9SMark Cave-Ayland } 1630f1a7deb9SMark Cave-Ayland } 1631f1a7deb9SMark Cave-Ayland } 1632f1a7deb9SMark Cave-Ayland 1633f1a7deb9SMark Cave-Ayland return crc; 1634f1a7deb9SMark Cave-Ayland } 1635f1a7deb9SMark Cave-Ayland 16364d454574SPaolo Bonzini QemuOptsList qemu_netdev_opts = { 16374d454574SPaolo Bonzini .name = "netdev", 16384d454574SPaolo Bonzini .implied_opt_name = "type", 16394d454574SPaolo Bonzini .head = QTAILQ_HEAD_INITIALIZER(qemu_netdev_opts.head), 16404d454574SPaolo Bonzini .desc = { 16414d454574SPaolo Bonzini /* 16424d454574SPaolo Bonzini * no elements => accept any params 16434d454574SPaolo Bonzini * validation will happen later 16444d454574SPaolo Bonzini */ 16454d454574SPaolo Bonzini { /* end of list */ } 16464d454574SPaolo Bonzini }, 16474d454574SPaolo Bonzini }; 16484d454574SPaolo Bonzini 164978cd6f7bSThomas Huth QemuOptsList qemu_nic_opts = { 165078cd6f7bSThomas Huth .name = "nic", 165178cd6f7bSThomas Huth .implied_opt_name = "type", 165278cd6f7bSThomas Huth .head = QTAILQ_HEAD_INITIALIZER(qemu_nic_opts.head), 165378cd6f7bSThomas Huth .desc = { 165478cd6f7bSThomas Huth /* 165578cd6f7bSThomas Huth * no elements => accept any params 165678cd6f7bSThomas Huth * validation will happen later 165778cd6f7bSThomas Huth */ 165878cd6f7bSThomas Huth { /* end of list */ } 165978cd6f7bSThomas Huth }, 166078cd6f7bSThomas Huth }; 166178cd6f7bSThomas Huth 16624d454574SPaolo Bonzini QemuOptsList qemu_net_opts = { 16634d454574SPaolo Bonzini .name = "net", 16644d454574SPaolo Bonzini .implied_opt_name = "type", 16654d454574SPaolo Bonzini .head = QTAILQ_HEAD_INITIALIZER(qemu_net_opts.head), 16664d454574SPaolo Bonzini .desc = { 16674d454574SPaolo Bonzini /* 16684d454574SPaolo Bonzini * no elements => accept any params 16694d454574SPaolo Bonzini * validation will happen later 16704d454574SPaolo Bonzini */ 16714d454574SPaolo Bonzini { /* end of list */ } 16724d454574SPaolo Bonzini }, 16734d454574SPaolo Bonzini }; 167416a3df40SZhang Chen 167516a3df40SZhang Chen void net_socket_rs_init(SocketReadState *rs, 16763cde5ea2SZhang Chen SocketReadStateFinalize *finalize, 16773cde5ea2SZhang Chen bool vnet_hdr) 167816a3df40SZhang Chen { 167916a3df40SZhang Chen rs->state = 0; 16803cde5ea2SZhang Chen rs->vnet_hdr = vnet_hdr; 168116a3df40SZhang Chen rs->index = 0; 168216a3df40SZhang Chen rs->packet_len = 0; 16833cde5ea2SZhang Chen rs->vnet_hdr_len = 0; 168416a3df40SZhang Chen memset(rs->buf, 0, sizeof(rs->buf)); 168516a3df40SZhang Chen rs->finalize = finalize; 168616a3df40SZhang Chen } 168716a3df40SZhang Chen 168816a3df40SZhang Chen /* 168916a3df40SZhang Chen * Returns 1690e9e0a585SZhang Chen * 0: success 1691e9e0a585SZhang Chen * -1: error occurs 169216a3df40SZhang Chen */ 169316a3df40SZhang Chen int net_fill_rstate(SocketReadState *rs, const uint8_t *buf, int size) 169416a3df40SZhang Chen { 169516a3df40SZhang Chen unsigned int l; 169616a3df40SZhang Chen 169716a3df40SZhang Chen while (size > 0) { 16983cde5ea2SZhang Chen /* Reassemble a packet from the network. 16993cde5ea2SZhang Chen * 0 = getting length. 17003cde5ea2SZhang Chen * 1 = getting vnet header length. 17013cde5ea2SZhang Chen * 2 = getting data. 17023cde5ea2SZhang Chen */ 17033cde5ea2SZhang Chen switch (rs->state) { 170416a3df40SZhang Chen case 0: 170516a3df40SZhang Chen l = 4 - rs->index; 170616a3df40SZhang Chen if (l > size) { 170716a3df40SZhang Chen l = size; 170816a3df40SZhang Chen } 170916a3df40SZhang Chen memcpy(rs->buf + rs->index, buf, l); 171016a3df40SZhang Chen buf += l; 171116a3df40SZhang Chen size -= l; 171216a3df40SZhang Chen rs->index += l; 171316a3df40SZhang Chen if (rs->index == 4) { 171416a3df40SZhang Chen /* got length */ 171516a3df40SZhang Chen rs->packet_len = ntohl(*(uint32_t *)rs->buf); 171616a3df40SZhang Chen rs->index = 0; 17173cde5ea2SZhang Chen if (rs->vnet_hdr) { 171816a3df40SZhang Chen rs->state = 1; 17193cde5ea2SZhang Chen } else { 17203cde5ea2SZhang Chen rs->state = 2; 17213cde5ea2SZhang Chen rs->vnet_hdr_len = 0; 17223cde5ea2SZhang Chen } 172316a3df40SZhang Chen } 172416a3df40SZhang Chen break; 172516a3df40SZhang Chen case 1: 17263cde5ea2SZhang Chen l = 4 - rs->index; 17273cde5ea2SZhang Chen if (l > size) { 17283cde5ea2SZhang Chen l = size; 17293cde5ea2SZhang Chen } 17303cde5ea2SZhang Chen memcpy(rs->buf + rs->index, buf, l); 17313cde5ea2SZhang Chen buf += l; 17323cde5ea2SZhang Chen size -= l; 17333cde5ea2SZhang Chen rs->index += l; 17343cde5ea2SZhang Chen if (rs->index == 4) { 17353cde5ea2SZhang Chen /* got vnet header length */ 17363cde5ea2SZhang Chen rs->vnet_hdr_len = ntohl(*(uint32_t *)rs->buf); 17373cde5ea2SZhang Chen rs->index = 0; 17383cde5ea2SZhang Chen rs->state = 2; 17393cde5ea2SZhang Chen } 17403cde5ea2SZhang Chen break; 17413cde5ea2SZhang Chen case 2: 174216a3df40SZhang Chen l = rs->packet_len - rs->index; 174316a3df40SZhang Chen if (l > size) { 174416a3df40SZhang Chen l = size; 174516a3df40SZhang Chen } 174616a3df40SZhang Chen if (rs->index + l <= sizeof(rs->buf)) { 174716a3df40SZhang Chen memcpy(rs->buf + rs->index, buf, l); 174816a3df40SZhang Chen } else { 174916a3df40SZhang Chen fprintf(stderr, "serious error: oversized packet received," 175016a3df40SZhang Chen "connection terminated.\n"); 175116a3df40SZhang Chen rs->index = rs->state = 0; 175216a3df40SZhang Chen return -1; 175316a3df40SZhang Chen } 175416a3df40SZhang Chen 175516a3df40SZhang Chen rs->index += l; 175616a3df40SZhang Chen buf += l; 175716a3df40SZhang Chen size -= l; 175816a3df40SZhang Chen if (rs->index >= rs->packet_len) { 175916a3df40SZhang Chen rs->index = 0; 176016a3df40SZhang Chen rs->state = 0; 1761e79cd406SDaniel P. Berrange assert(rs->finalize); 176216a3df40SZhang Chen rs->finalize(rs); 176316a3df40SZhang Chen } 176416a3df40SZhang Chen break; 176516a3df40SZhang Chen } 176616a3df40SZhang Chen } 1767e9e0a585SZhang Chen 1768e9e0a585SZhang Chen assert(size == 0); 176916a3df40SZhang Chen return 0; 177016a3df40SZhang Chen } 1771