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" 30a27bd6c7SMarkus 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" 47ad6f932fSPaolo Bonzini #include "qemu/qemu-print.h" 486a1751b7SAlex Bligh #include "qemu/main-loop.h" 49922a01a0SMarkus Armbruster #include "qemu/option.h" 50e688df6bSMarkus Armbruster #include "qapi/error.h" 51fd9400b3SPaolo Bonzini #include "qapi/opts-visitor.h" 52e1d64c08Szhanghailiang #include "sysemu/sysemu.h" 53559964a1SThomas Huth #include "sysemu/qtest.h" 5454d31236SMarkus Armbruster #include "sysemu/runstate.h" 5554d31236SMarkus Armbruster #include "sysemu/sysemu.h" 56fdccce45SYang Hongyang #include "net/filter.h" 57aa9156f4Szhanghailiang #include "qapi/string-output-visitor.h" 58fd9400b3SPaolo Bonzini 59fd9400b3SPaolo Bonzini /* Net bridge is currently not supported for W32. */ 60fd9400b3SPaolo Bonzini #if !defined(_WIN32) 61fd9400b3SPaolo Bonzini # define CONFIG_NET_BRIDGE 62fd9400b3SPaolo Bonzini #endif 63fd9400b3SPaolo Bonzini 64ca77d85eSMichael S. Tsirkin static VMChangeStateEntry *net_change_state_entry; 65fd9400b3SPaolo Bonzini static QTAILQ_HEAD(, NetClientState) net_clients; 66fd9400b3SPaolo Bonzini 67fd9400b3SPaolo Bonzini /***********************************************************/ 68fd9400b3SPaolo Bonzini /* network device redirectors */ 69fd9400b3SPaolo Bonzini 70bcd4dfd6SMao Zhongyi int parse_host_port(struct sockaddr_in *saddr, const char *str, 71bcd4dfd6SMao Zhongyi Error **errp) 72fd9400b3SPaolo Bonzini { 73add99347SStefano Garzarella gchar **substrings; 74fd9400b3SPaolo Bonzini struct hostent *he; 75add99347SStefano Garzarella const char *addr, *p, *r; 76add99347SStefano Garzarella int port, ret = 0; 77fd9400b3SPaolo Bonzini 78add99347SStefano Garzarella substrings = g_strsplit(str, ":", 2); 79add99347SStefano Garzarella if (!substrings || !substrings[0] || !substrings[1]) { 80bcd4dfd6SMao Zhongyi error_setg(errp, "host address '%s' doesn't contain ':' " 81bcd4dfd6SMao Zhongyi "separating host from port", str); 82add99347SStefano Garzarella ret = -1; 83add99347SStefano Garzarella goto out; 84bcd4dfd6SMao Zhongyi } 85add99347SStefano Garzarella 86add99347SStefano Garzarella addr = substrings[0]; 87add99347SStefano Garzarella p = substrings[1]; 88add99347SStefano Garzarella 89fd9400b3SPaolo Bonzini saddr->sin_family = AF_INET; 90add99347SStefano Garzarella if (addr[0] == '\0') { 91fd9400b3SPaolo Bonzini saddr->sin_addr.s_addr = 0; 92fd9400b3SPaolo Bonzini } else { 93add99347SStefano Garzarella if (qemu_isdigit(addr[0])) { 94add99347SStefano Garzarella if (!inet_aton(addr, &saddr->sin_addr)) { 95bcd4dfd6SMao Zhongyi error_setg(errp, "host address '%s' is not a valid " 96add99347SStefano Garzarella "IPv4 address", addr); 97add99347SStefano Garzarella ret = -1; 98add99347SStefano Garzarella goto out; 99bcd4dfd6SMao Zhongyi } 100fd9400b3SPaolo Bonzini } else { 101add99347SStefano Garzarella he = gethostbyname(addr); 102bcd4dfd6SMao Zhongyi if (he == NULL) { 103add99347SStefano Garzarella error_setg(errp, "can't resolve host address '%s'", addr); 104add99347SStefano Garzarella ret = -1; 105add99347SStefano Garzarella goto out; 106bcd4dfd6SMao Zhongyi } 107fd9400b3SPaolo Bonzini saddr->sin_addr = *(struct in_addr *)he->h_addr; 108fd9400b3SPaolo Bonzini } 109fd9400b3SPaolo Bonzini } 110fd9400b3SPaolo Bonzini port = strtol(p, (char **)&r, 0); 111bcd4dfd6SMao Zhongyi if (r == p) { 112bcd4dfd6SMao Zhongyi error_setg(errp, "port number '%s' is invalid", p); 113add99347SStefano Garzarella ret = -1; 114add99347SStefano Garzarella goto out; 115bcd4dfd6SMao Zhongyi } 116fd9400b3SPaolo Bonzini saddr->sin_port = htons(port); 117add99347SStefano Garzarella 118add99347SStefano Garzarella out: 119add99347SStefano Garzarella g_strfreev(substrings); 120add99347SStefano Garzarella return ret; 121fd9400b3SPaolo Bonzini } 122fd9400b3SPaolo Bonzini 123890ee6abSScott Feldman char *qemu_mac_strdup_printf(const uint8_t *macaddr) 124890ee6abSScott Feldman { 125890ee6abSScott Feldman return g_strdup_printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", 126890ee6abSScott Feldman macaddr[0], macaddr[1], macaddr[2], 127890ee6abSScott Feldman macaddr[3], macaddr[4], macaddr[5]); 128890ee6abSScott Feldman } 129890ee6abSScott Feldman 130fd9400b3SPaolo Bonzini void qemu_format_nic_info_str(NetClientState *nc, uint8_t macaddr[6]) 131fd9400b3SPaolo Bonzini { 132fd9400b3SPaolo Bonzini snprintf(nc->info_str, sizeof(nc->info_str), 133fd9400b3SPaolo Bonzini "model=%s,macaddr=%02x:%02x:%02x:%02x:%02x:%02x", 134fd9400b3SPaolo Bonzini nc->model, 135fd9400b3SPaolo Bonzini macaddr[0], macaddr[1], macaddr[2], 136fd9400b3SPaolo Bonzini macaddr[3], macaddr[4], macaddr[5]); 137fd9400b3SPaolo Bonzini } 138fd9400b3SPaolo Bonzini 1392bc22a58SShannon Zhao static int mac_table[256] = {0}; 1402bc22a58SShannon Zhao 1412bc22a58SShannon Zhao static void qemu_macaddr_set_used(MACAddr *macaddr) 1422bc22a58SShannon Zhao { 1432bc22a58SShannon Zhao int index; 1442bc22a58SShannon Zhao 1452bc22a58SShannon Zhao for (index = 0x56; index < 0xFF; index++) { 1462bc22a58SShannon Zhao if (macaddr->a[5] == index) { 1472bc22a58SShannon Zhao mac_table[index]++; 1482bc22a58SShannon Zhao } 1492bc22a58SShannon Zhao } 1502bc22a58SShannon Zhao } 1512bc22a58SShannon Zhao 1522bc22a58SShannon Zhao static void qemu_macaddr_set_free(MACAddr *macaddr) 1532bc22a58SShannon Zhao { 1542bc22a58SShannon Zhao int index; 1552bc22a58SShannon Zhao static const MACAddr base = { .a = { 0x52, 0x54, 0x00, 0x12, 0x34, 0 } }; 1562bc22a58SShannon Zhao 1572bc22a58SShannon Zhao if (memcmp(macaddr->a, &base.a, (sizeof(base.a) - 1)) != 0) { 1582bc22a58SShannon Zhao return; 1592bc22a58SShannon Zhao } 1602bc22a58SShannon Zhao for (index = 0x56; index < 0xFF; index++) { 1612bc22a58SShannon Zhao if (macaddr->a[5] == index) { 1622bc22a58SShannon Zhao mac_table[index]--; 1632bc22a58SShannon Zhao } 1642bc22a58SShannon Zhao } 1652bc22a58SShannon Zhao } 1662bc22a58SShannon Zhao 1672bc22a58SShannon Zhao static int qemu_macaddr_get_free(void) 1682bc22a58SShannon Zhao { 1692bc22a58SShannon Zhao int index; 1702bc22a58SShannon Zhao 1712bc22a58SShannon Zhao for (index = 0x56; index < 0xFF; index++) { 1722bc22a58SShannon Zhao if (mac_table[index] == 0) { 1732bc22a58SShannon Zhao return index; 1742bc22a58SShannon Zhao } 1752bc22a58SShannon Zhao } 1762bc22a58SShannon Zhao 1772bc22a58SShannon Zhao return -1; 1782bc22a58SShannon Zhao } 1792bc22a58SShannon Zhao 180fd9400b3SPaolo Bonzini void qemu_macaddr_default_if_unset(MACAddr *macaddr) 181fd9400b3SPaolo Bonzini { 182fd9400b3SPaolo Bonzini static const MACAddr zero = { .a = { 0,0,0,0,0,0 } }; 1832bc22a58SShannon Zhao static const MACAddr base = { .a = { 0x52, 0x54, 0x00, 0x12, 0x34, 0 } }; 184fd9400b3SPaolo Bonzini 1852bc22a58SShannon Zhao if (memcmp(macaddr, &zero, sizeof(zero)) != 0) { 1862bc22a58SShannon Zhao if (memcmp(macaddr->a, &base.a, (sizeof(base.a) - 1)) != 0) { 187fd9400b3SPaolo Bonzini return; 1882bc22a58SShannon Zhao } else { 1892bc22a58SShannon Zhao qemu_macaddr_set_used(macaddr); 1902bc22a58SShannon Zhao return; 1912bc22a58SShannon Zhao } 1922bc22a58SShannon Zhao } 1932bc22a58SShannon Zhao 194fd9400b3SPaolo Bonzini macaddr->a[0] = 0x52; 195fd9400b3SPaolo Bonzini macaddr->a[1] = 0x54; 196fd9400b3SPaolo Bonzini macaddr->a[2] = 0x00; 197fd9400b3SPaolo Bonzini macaddr->a[3] = 0x12; 198fd9400b3SPaolo Bonzini macaddr->a[4] = 0x34; 1992bc22a58SShannon Zhao macaddr->a[5] = qemu_macaddr_get_free(); 2002bc22a58SShannon Zhao qemu_macaddr_set_used(macaddr); 201fd9400b3SPaolo Bonzini } 202fd9400b3SPaolo Bonzini 203fd9400b3SPaolo Bonzini /** 204fd9400b3SPaolo Bonzini * Generate a name for net client 205fd9400b3SPaolo Bonzini * 206c963530aSAmos Kong * Only net clients created with the legacy -net option and NICs need this. 207fd9400b3SPaolo Bonzini */ 208fd9400b3SPaolo Bonzini static char *assign_name(NetClientState *nc1, const char *model) 209fd9400b3SPaolo Bonzini { 210fd9400b3SPaolo Bonzini NetClientState *nc; 211fd9400b3SPaolo Bonzini int id = 0; 212fd9400b3SPaolo Bonzini 213fd9400b3SPaolo Bonzini QTAILQ_FOREACH(nc, &net_clients, next) { 214fd9400b3SPaolo Bonzini if (nc == nc1) { 215fd9400b3SPaolo Bonzini continue; 216fd9400b3SPaolo Bonzini } 217c963530aSAmos Kong if (strcmp(nc->model, model) == 0) { 218fd9400b3SPaolo Bonzini id++; 219fd9400b3SPaolo Bonzini } 220fd9400b3SPaolo Bonzini } 221fd9400b3SPaolo Bonzini 2224bf2c138SHani Benhabiles return g_strdup_printf("%s.%d", model, id); 223fd9400b3SPaolo Bonzini } 224fd9400b3SPaolo Bonzini 225f7860455SJason Wang static void qemu_net_client_destructor(NetClientState *nc) 226f7860455SJason Wang { 227f7860455SJason Wang g_free(nc); 228f7860455SJason Wang } 22925c01bd1SJason Wang static ssize_t qemu_deliver_packet_iov(NetClientState *sender, 23025c01bd1SJason Wang unsigned flags, 23125c01bd1SJason Wang const struct iovec *iov, 23225c01bd1SJason Wang int iovcnt, 23325c01bd1SJason Wang void *opaque); 234f7860455SJason Wang 23518a1541aSJason Wang static void qemu_net_client_setup(NetClientState *nc, 23618a1541aSJason Wang NetClientInfo *info, 237fd9400b3SPaolo Bonzini NetClientState *peer, 238fd9400b3SPaolo Bonzini const char *model, 239f7860455SJason Wang const char *name, 240f7860455SJason Wang NetClientDestructor *destructor) 241fd9400b3SPaolo Bonzini { 242fd9400b3SPaolo Bonzini nc->info = info; 243fd9400b3SPaolo Bonzini nc->model = g_strdup(model); 244fd9400b3SPaolo Bonzini if (name) { 245fd9400b3SPaolo Bonzini nc->name = g_strdup(name); 246fd9400b3SPaolo Bonzini } else { 247fd9400b3SPaolo Bonzini nc->name = assign_name(nc, model); 248fd9400b3SPaolo Bonzini } 249fd9400b3SPaolo Bonzini 250fd9400b3SPaolo Bonzini if (peer) { 251fd9400b3SPaolo Bonzini assert(!peer->peer); 252fd9400b3SPaolo Bonzini nc->peer = peer; 253fd9400b3SPaolo Bonzini peer->peer = nc; 254fd9400b3SPaolo Bonzini } 255fd9400b3SPaolo Bonzini QTAILQ_INSERT_TAIL(&net_clients, nc, next); 256fd9400b3SPaolo Bonzini 2573e033a46SYang Hongyang nc->incoming_queue = qemu_new_net_queue(qemu_deliver_packet_iov, nc); 258f7860455SJason Wang nc->destructor = destructor; 259fdccce45SYang Hongyang QTAILQ_INIT(&nc->filters); 26018a1541aSJason Wang } 26118a1541aSJason Wang 26218a1541aSJason Wang NetClientState *qemu_new_net_client(NetClientInfo *info, 26318a1541aSJason Wang NetClientState *peer, 26418a1541aSJason Wang const char *model, 26518a1541aSJason Wang const char *name) 26618a1541aSJason Wang { 26718a1541aSJason Wang NetClientState *nc; 26818a1541aSJason Wang 26918a1541aSJason Wang assert(info->size >= sizeof(NetClientState)); 27018a1541aSJason Wang 27118a1541aSJason Wang nc = g_malloc0(info->size); 272f7860455SJason Wang qemu_net_client_setup(nc, info, peer, model, name, 273f7860455SJason Wang qemu_net_client_destructor); 27418a1541aSJason Wang 275fd9400b3SPaolo Bonzini return nc; 276fd9400b3SPaolo Bonzini } 277fd9400b3SPaolo Bonzini 278fd9400b3SPaolo Bonzini NICState *qemu_new_nic(NetClientInfo *info, 279fd9400b3SPaolo Bonzini NICConf *conf, 280fd9400b3SPaolo Bonzini const char *model, 281fd9400b3SPaolo Bonzini const char *name, 282fd9400b3SPaolo Bonzini void *opaque) 283fd9400b3SPaolo Bonzini { 2841ceef9f2SJason Wang NetClientState **peers = conf->peers.ncs; 285fd9400b3SPaolo Bonzini NICState *nic; 286575a1c0eSJiri Pirko int i, queues = MAX(1, conf->peers.queues); 287fd9400b3SPaolo Bonzini 288f394b2e2SEric Blake assert(info->type == NET_CLIENT_DRIVER_NIC); 289fd9400b3SPaolo Bonzini assert(info->size >= sizeof(NICState)); 290fd9400b3SPaolo Bonzini 291f6b26cf2SJason Wang nic = g_malloc0(info->size + sizeof(NetClientState) * queues); 292f6b26cf2SJason Wang nic->ncs = (void *)nic + info->size; 293fd9400b3SPaolo Bonzini nic->conf = conf; 294fd9400b3SPaolo Bonzini nic->opaque = opaque; 295fd9400b3SPaolo Bonzini 296f6b26cf2SJason Wang for (i = 0; i < queues; i++) { 297f6b26cf2SJason Wang qemu_net_client_setup(&nic->ncs[i], info, peers[i], model, name, 2981ceef9f2SJason Wang NULL); 2991ceef9f2SJason Wang nic->ncs[i].queue_index = i; 3001ceef9f2SJason Wang } 3011ceef9f2SJason Wang 302fd9400b3SPaolo Bonzini return nic; 303fd9400b3SPaolo Bonzini } 304fd9400b3SPaolo Bonzini 3051ceef9f2SJason Wang NetClientState *qemu_get_subqueue(NICState *nic, int queue_index) 3061ceef9f2SJason Wang { 307f6b26cf2SJason Wang return nic->ncs + queue_index; 3081ceef9f2SJason Wang } 3091ceef9f2SJason Wang 310b356f76dSJason Wang NetClientState *qemu_get_queue(NICState *nic) 311b356f76dSJason Wang { 3121ceef9f2SJason Wang return qemu_get_subqueue(nic, 0); 313b356f76dSJason Wang } 314b356f76dSJason Wang 315cc1f0f45SJason Wang NICState *qemu_get_nic(NetClientState *nc) 316cc1f0f45SJason Wang { 3171ceef9f2SJason Wang NetClientState *nc0 = nc - nc->queue_index; 3181ceef9f2SJason Wang 319f6b26cf2SJason Wang return (NICState *)((void *)nc0 - nc->info->size); 320cc1f0f45SJason Wang } 321cc1f0f45SJason Wang 322cc1f0f45SJason Wang void *qemu_get_nic_opaque(NetClientState *nc) 323cc1f0f45SJason Wang { 324cc1f0f45SJason Wang NICState *nic = qemu_get_nic(nc); 325cc1f0f45SJason Wang 326cc1f0f45SJason Wang return nic->opaque; 327cc1f0f45SJason Wang } 328cc1f0f45SJason Wang 3290165daaeSCindy Lu NetClientState *qemu_get_peer(NetClientState *nc, int queue_index) 3300165daaeSCindy Lu { 3310165daaeSCindy Lu assert(nc != NULL); 3320165daaeSCindy Lu NetClientState *ncs = nc + queue_index; 3330165daaeSCindy Lu return ncs->peer; 3340165daaeSCindy Lu } 3350165daaeSCindy Lu 336fd9400b3SPaolo Bonzini static void qemu_cleanup_net_client(NetClientState *nc) 337fd9400b3SPaolo Bonzini { 338fd9400b3SPaolo Bonzini QTAILQ_REMOVE(&net_clients, nc, next); 339fd9400b3SPaolo Bonzini 340cc2a9043SAndreas Färber if (nc->info->cleanup) { 341fd9400b3SPaolo Bonzini nc->info->cleanup(nc); 342fd9400b3SPaolo Bonzini } 343cc2a9043SAndreas Färber } 344fd9400b3SPaolo Bonzini 345fd9400b3SPaolo Bonzini static void qemu_free_net_client(NetClientState *nc) 346fd9400b3SPaolo Bonzini { 347067404beSJan Kiszka if (nc->incoming_queue) { 348067404beSJan Kiszka qemu_del_net_queue(nc->incoming_queue); 349fd9400b3SPaolo Bonzini } 350fd9400b3SPaolo Bonzini if (nc->peer) { 351fd9400b3SPaolo Bonzini nc->peer->peer = NULL; 352fd9400b3SPaolo Bonzini } 353fd9400b3SPaolo Bonzini g_free(nc->name); 354fd9400b3SPaolo Bonzini g_free(nc->model); 355f7860455SJason Wang if (nc->destructor) { 356f7860455SJason Wang nc->destructor(nc); 357f7860455SJason Wang } 358fd9400b3SPaolo Bonzini } 359fd9400b3SPaolo Bonzini 360fd9400b3SPaolo Bonzini void qemu_del_net_client(NetClientState *nc) 361fd9400b3SPaolo Bonzini { 3621ceef9f2SJason Wang NetClientState *ncs[MAX_QUEUE_NUM]; 3631ceef9f2SJason Wang int queues, i; 364fdccce45SYang Hongyang NetFilterState *nf, *next; 3651ceef9f2SJason Wang 366f394b2e2SEric Blake assert(nc->info->type != NET_CLIENT_DRIVER_NIC); 3677fb43911SPaolo Bonzini 3681ceef9f2SJason Wang /* If the NetClientState belongs to a multiqueue backend, we will change all 3691ceef9f2SJason Wang * other NetClientStates also. 3701ceef9f2SJason Wang */ 3711ceef9f2SJason Wang queues = qemu_find_net_clients_except(nc->name, ncs, 372f394b2e2SEric Blake NET_CLIENT_DRIVER_NIC, 3731ceef9f2SJason Wang MAX_QUEUE_NUM); 3741ceef9f2SJason Wang assert(queues != 0); 3751ceef9f2SJason Wang 376fdccce45SYang Hongyang QTAILQ_FOREACH_SAFE(nf, &nc->filters, next, next) { 377fdccce45SYang Hongyang object_unparent(OBJECT(nf)); 378fdccce45SYang Hongyang } 379fdccce45SYang Hongyang 380fd9400b3SPaolo Bonzini /* If there is a peer NIC, delete and cleanup client, but do not free. */ 381f394b2e2SEric Blake if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_NIC) { 382cc1f0f45SJason Wang NICState *nic = qemu_get_nic(nc->peer); 383fd9400b3SPaolo Bonzini if (nic->peer_deleted) { 384fd9400b3SPaolo Bonzini return; 385fd9400b3SPaolo Bonzini } 386fd9400b3SPaolo Bonzini nic->peer_deleted = true; 3871ceef9f2SJason Wang 3881ceef9f2SJason Wang for (i = 0; i < queues; i++) { 3891ceef9f2SJason Wang ncs[i]->peer->link_down = true; 3901ceef9f2SJason Wang } 3911ceef9f2SJason Wang 392fd9400b3SPaolo Bonzini if (nc->peer->info->link_status_changed) { 393fd9400b3SPaolo Bonzini nc->peer->info->link_status_changed(nc->peer); 394fd9400b3SPaolo Bonzini } 3951ceef9f2SJason Wang 3961ceef9f2SJason Wang for (i = 0; i < queues; i++) { 3971ceef9f2SJason Wang qemu_cleanup_net_client(ncs[i]); 3981ceef9f2SJason Wang } 3991ceef9f2SJason Wang 400fd9400b3SPaolo Bonzini return; 401fd9400b3SPaolo Bonzini } 402fd9400b3SPaolo Bonzini 4031ceef9f2SJason Wang for (i = 0; i < queues; i++) { 4041ceef9f2SJason Wang qemu_cleanup_net_client(ncs[i]); 4051ceef9f2SJason Wang qemu_free_net_client(ncs[i]); 4061ceef9f2SJason Wang } 407948ecf21SJason Wang } 408948ecf21SJason Wang 409948ecf21SJason Wang void qemu_del_nic(NICState *nic) 410948ecf21SJason Wang { 411575a1c0eSJiri Pirko int i, queues = MAX(nic->conf->peers.queues, 1); 4121ceef9f2SJason Wang 4132bc22a58SShannon Zhao qemu_macaddr_set_free(&nic->conf->macaddr); 4142bc22a58SShannon Zhao 415d2abc563SYuri Benditovich for (i = 0; i < queues; i++) { 416d2abc563SYuri Benditovich NetClientState *nc = qemu_get_subqueue(nic, i); 417fd9400b3SPaolo Bonzini /* If this is a peer NIC and peer has already been deleted, free it now. */ 418fd9400b3SPaolo Bonzini if (nic->peer_deleted) { 419d2abc563SYuri Benditovich qemu_free_net_client(nc->peer); 420d2abc563SYuri Benditovich } else if (nc->peer) { 421d2abc563SYuri Benditovich /* if there are RX packets pending, complete them */ 422d2abc563SYuri Benditovich qemu_purge_queued_packets(nc->peer); 423fd9400b3SPaolo Bonzini } 424fd9400b3SPaolo Bonzini } 425fd9400b3SPaolo Bonzini 4261ceef9f2SJason Wang for (i = queues - 1; i >= 0; i--) { 4271ceef9f2SJason Wang NetClientState *nc = qemu_get_subqueue(nic, i); 4281ceef9f2SJason Wang 429fd9400b3SPaolo Bonzini qemu_cleanup_net_client(nc); 430fd9400b3SPaolo Bonzini qemu_free_net_client(nc); 431fd9400b3SPaolo Bonzini } 432f6b26cf2SJason Wang 433f6b26cf2SJason Wang g_free(nic); 4341ceef9f2SJason Wang } 435fd9400b3SPaolo Bonzini 436fd9400b3SPaolo Bonzini void qemu_foreach_nic(qemu_nic_foreach func, void *opaque) 437fd9400b3SPaolo Bonzini { 438fd9400b3SPaolo Bonzini NetClientState *nc; 439fd9400b3SPaolo Bonzini 440fd9400b3SPaolo Bonzini QTAILQ_FOREACH(nc, &net_clients, next) { 441f394b2e2SEric Blake if (nc->info->type == NET_CLIENT_DRIVER_NIC) { 4421ceef9f2SJason Wang if (nc->queue_index == 0) { 443cc1f0f45SJason Wang func(qemu_get_nic(nc), opaque); 444fd9400b3SPaolo Bonzini } 445fd9400b3SPaolo Bonzini } 446fd9400b3SPaolo Bonzini } 4471ceef9f2SJason Wang } 448fd9400b3SPaolo Bonzini 449d6085e3aSStefan Hajnoczi bool qemu_has_ufo(NetClientState *nc) 4501f55ac45SVincenzo Maffione { 451d6085e3aSStefan Hajnoczi if (!nc || !nc->info->has_ufo) { 4521f55ac45SVincenzo Maffione return false; 4531f55ac45SVincenzo Maffione } 4541f55ac45SVincenzo Maffione 455d6085e3aSStefan Hajnoczi return nc->info->has_ufo(nc); 4561f55ac45SVincenzo Maffione } 4571f55ac45SVincenzo Maffione 458d6085e3aSStefan Hajnoczi bool qemu_has_vnet_hdr(NetClientState *nc) 4591f55ac45SVincenzo Maffione { 460d6085e3aSStefan Hajnoczi if (!nc || !nc->info->has_vnet_hdr) { 4611f55ac45SVincenzo Maffione return false; 4621f55ac45SVincenzo Maffione } 4631f55ac45SVincenzo Maffione 464d6085e3aSStefan Hajnoczi return nc->info->has_vnet_hdr(nc); 4651f55ac45SVincenzo Maffione } 4661f55ac45SVincenzo Maffione 467d6085e3aSStefan Hajnoczi bool qemu_has_vnet_hdr_len(NetClientState *nc, int len) 4681f55ac45SVincenzo Maffione { 469d6085e3aSStefan Hajnoczi if (!nc || !nc->info->has_vnet_hdr_len) { 4701f55ac45SVincenzo Maffione return false; 4711f55ac45SVincenzo Maffione } 4721f55ac45SVincenzo Maffione 473d6085e3aSStefan Hajnoczi return nc->info->has_vnet_hdr_len(nc, len); 4741f55ac45SVincenzo Maffione } 4751f55ac45SVincenzo Maffione 476d6085e3aSStefan Hajnoczi void qemu_using_vnet_hdr(NetClientState *nc, bool enable) 4771f55ac45SVincenzo Maffione { 478d6085e3aSStefan Hajnoczi if (!nc || !nc->info->using_vnet_hdr) { 4791f55ac45SVincenzo Maffione return; 4801f55ac45SVincenzo Maffione } 4811f55ac45SVincenzo Maffione 482d6085e3aSStefan Hajnoczi nc->info->using_vnet_hdr(nc, enable); 4831f55ac45SVincenzo Maffione } 4841f55ac45SVincenzo Maffione 485d6085e3aSStefan Hajnoczi void qemu_set_offload(NetClientState *nc, int csum, int tso4, int tso6, 4861f55ac45SVincenzo Maffione int ecn, int ufo) 4871f55ac45SVincenzo Maffione { 488d6085e3aSStefan Hajnoczi if (!nc || !nc->info->set_offload) { 4891f55ac45SVincenzo Maffione return; 4901f55ac45SVincenzo Maffione } 4911f55ac45SVincenzo Maffione 492d6085e3aSStefan Hajnoczi nc->info->set_offload(nc, csum, tso4, tso6, ecn, ufo); 4931f55ac45SVincenzo Maffione } 4941f55ac45SVincenzo Maffione 495d6085e3aSStefan Hajnoczi void qemu_set_vnet_hdr_len(NetClientState *nc, int len) 4961f55ac45SVincenzo Maffione { 497d6085e3aSStefan Hajnoczi if (!nc || !nc->info->set_vnet_hdr_len) { 4981f55ac45SVincenzo Maffione return; 4991f55ac45SVincenzo Maffione } 5001f55ac45SVincenzo Maffione 501d6b732e9SZhang Chen nc->vnet_hdr_len = len; 502d6085e3aSStefan Hajnoczi nc->info->set_vnet_hdr_len(nc, len); 5031f55ac45SVincenzo Maffione } 5041f55ac45SVincenzo Maffione 505c80cd6bbSGreg Kurz int qemu_set_vnet_le(NetClientState *nc, bool is_le) 506c80cd6bbSGreg Kurz { 507052bd52fSMichael S. Tsirkin #ifdef HOST_WORDS_BIGENDIAN 508c80cd6bbSGreg Kurz if (!nc || !nc->info->set_vnet_le) { 509c80cd6bbSGreg Kurz return -ENOSYS; 510c80cd6bbSGreg Kurz } 511c80cd6bbSGreg Kurz 512c80cd6bbSGreg Kurz return nc->info->set_vnet_le(nc, is_le); 513052bd52fSMichael S. Tsirkin #else 514052bd52fSMichael S. Tsirkin return 0; 515052bd52fSMichael S. Tsirkin #endif 516c80cd6bbSGreg Kurz } 517c80cd6bbSGreg Kurz 518c80cd6bbSGreg Kurz int qemu_set_vnet_be(NetClientState *nc, bool is_be) 519c80cd6bbSGreg Kurz { 520052bd52fSMichael S. Tsirkin #ifdef HOST_WORDS_BIGENDIAN 521052bd52fSMichael S. Tsirkin return 0; 522052bd52fSMichael S. Tsirkin #else 523c80cd6bbSGreg Kurz if (!nc || !nc->info->set_vnet_be) { 524c80cd6bbSGreg Kurz return -ENOSYS; 525c80cd6bbSGreg Kurz } 526c80cd6bbSGreg Kurz 527c80cd6bbSGreg Kurz return nc->info->set_vnet_be(nc, is_be); 528052bd52fSMichael S. Tsirkin #endif 529c80cd6bbSGreg Kurz } 530c80cd6bbSGreg Kurz 531fd9400b3SPaolo Bonzini int qemu_can_send_packet(NetClientState *sender) 532fd9400b3SPaolo Bonzini { 533e1d64c08Szhanghailiang int vm_running = runstate_is_running(); 534e1d64c08Szhanghailiang 535e1d64c08Szhanghailiang if (!vm_running) { 536e1d64c08Szhanghailiang return 0; 537e1d64c08Szhanghailiang } 538e1d64c08Szhanghailiang 539fd9400b3SPaolo Bonzini if (!sender->peer) { 540fd9400b3SPaolo Bonzini return 1; 541fd9400b3SPaolo Bonzini } 542fd9400b3SPaolo Bonzini 543fd9400b3SPaolo Bonzini if (sender->peer->receive_disabled) { 544fd9400b3SPaolo Bonzini return 0; 545fd9400b3SPaolo Bonzini } else if (sender->peer->info->can_receive && 546fd9400b3SPaolo Bonzini !sender->peer->info->can_receive(sender->peer)) { 547fd9400b3SPaolo Bonzini return 0; 548fd9400b3SPaolo Bonzini } 549fd9400b3SPaolo Bonzini return 1; 550fd9400b3SPaolo Bonzini } 551fd9400b3SPaolo Bonzini 552e64c770dSYang Hongyang static ssize_t filter_receive_iov(NetClientState *nc, 553e64c770dSYang Hongyang NetFilterDirection direction, 554e64c770dSYang Hongyang NetClientState *sender, 555e64c770dSYang Hongyang unsigned flags, 556e64c770dSYang Hongyang const struct iovec *iov, 557e64c770dSYang Hongyang int iovcnt, 558e64c770dSYang Hongyang NetPacketSent *sent_cb) 559e64c770dSYang Hongyang { 560e64c770dSYang Hongyang ssize_t ret = 0; 561e64c770dSYang Hongyang NetFilterState *nf = NULL; 562e64c770dSYang Hongyang 56325aaadf0SLi Zhijian if (direction == NET_FILTER_DIRECTION_TX) { 564e64c770dSYang Hongyang QTAILQ_FOREACH(nf, &nc->filters, next) { 565e64c770dSYang Hongyang ret = qemu_netfilter_receive(nf, direction, sender, flags, iov, 566e64c770dSYang Hongyang iovcnt, sent_cb); 567e64c770dSYang Hongyang if (ret) { 568e64c770dSYang Hongyang return ret; 569e64c770dSYang Hongyang } 570e64c770dSYang Hongyang } 57125aaadf0SLi Zhijian } else { 572eae3eb3eSPaolo Bonzini QTAILQ_FOREACH_REVERSE(nf, &nc->filters, next) { 57325aaadf0SLi Zhijian ret = qemu_netfilter_receive(nf, direction, sender, flags, iov, 57425aaadf0SLi Zhijian iovcnt, sent_cb); 57525aaadf0SLi Zhijian if (ret) { 57625aaadf0SLi Zhijian return ret; 57725aaadf0SLi Zhijian } 57825aaadf0SLi Zhijian } 57925aaadf0SLi Zhijian } 580e64c770dSYang Hongyang 581e64c770dSYang Hongyang return ret; 582e64c770dSYang Hongyang } 583e64c770dSYang Hongyang 584e64c770dSYang Hongyang static ssize_t filter_receive(NetClientState *nc, 585e64c770dSYang Hongyang NetFilterDirection direction, 586e64c770dSYang Hongyang NetClientState *sender, 587e64c770dSYang Hongyang unsigned flags, 588e64c770dSYang Hongyang const uint8_t *data, 589e64c770dSYang Hongyang size_t size, 590e64c770dSYang Hongyang NetPacketSent *sent_cb) 591e64c770dSYang Hongyang { 592e64c770dSYang Hongyang struct iovec iov = { 593e64c770dSYang Hongyang .iov_base = (void *)data, 594e64c770dSYang Hongyang .iov_len = size 595e64c770dSYang Hongyang }; 596e64c770dSYang Hongyang 597e64c770dSYang Hongyang return filter_receive_iov(nc, direction, sender, flags, &iov, 1, sent_cb); 598e64c770dSYang Hongyang } 599e64c770dSYang Hongyang 600fd9400b3SPaolo Bonzini void qemu_purge_queued_packets(NetClientState *nc) 601fd9400b3SPaolo Bonzini { 602fd9400b3SPaolo Bonzini if (!nc->peer) { 603fd9400b3SPaolo Bonzini return; 604fd9400b3SPaolo Bonzini } 605fd9400b3SPaolo Bonzini 606067404beSJan Kiszka qemu_net_queue_purge(nc->peer->incoming_queue, nc); 607fd9400b3SPaolo Bonzini } 608fd9400b3SPaolo Bonzini 609ca77d85eSMichael S. Tsirkin void qemu_flush_or_purge_queued_packets(NetClientState *nc, bool purge) 610fd9400b3SPaolo Bonzini { 611fd9400b3SPaolo Bonzini nc->receive_disabled = 0; 612fd9400b3SPaolo Bonzini 613f394b2e2SEric Blake if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_HUBPORT) { 614199ee608SLuigi Rizzo if (net_hub_flush(nc->peer)) { 615199ee608SLuigi Rizzo qemu_notify_event(); 616199ee608SLuigi Rizzo } 617199ee608SLuigi Rizzo } 618067404beSJan Kiszka if (qemu_net_queue_flush(nc->incoming_queue)) { 619fd9400b3SPaolo Bonzini /* We emptied the queue successfully, signal to the IO thread to repoll 620fd9400b3SPaolo Bonzini * the file descriptor (for tap, for example). 621fd9400b3SPaolo Bonzini */ 622fd9400b3SPaolo Bonzini qemu_notify_event(); 623ca77d85eSMichael S. Tsirkin } else if (purge) { 624ca77d85eSMichael S. Tsirkin /* Unable to empty the queue, purge remaining packets */ 6255fe19fb8SJason Wang qemu_net_queue_purge(nc->incoming_queue, nc->peer); 626fd9400b3SPaolo Bonzini } 627fd9400b3SPaolo Bonzini } 628fd9400b3SPaolo Bonzini 629ca77d85eSMichael S. Tsirkin void qemu_flush_queued_packets(NetClientState *nc) 630ca77d85eSMichael S. Tsirkin { 631ca77d85eSMichael S. Tsirkin qemu_flush_or_purge_queued_packets(nc, false); 632ca77d85eSMichael S. Tsirkin } 633ca77d85eSMichael S. Tsirkin 634fd9400b3SPaolo Bonzini static ssize_t qemu_send_packet_async_with_flags(NetClientState *sender, 635fd9400b3SPaolo Bonzini unsigned flags, 636fd9400b3SPaolo Bonzini const uint8_t *buf, int size, 637fd9400b3SPaolo Bonzini NetPacketSent *sent_cb) 638fd9400b3SPaolo Bonzini { 639fd9400b3SPaolo Bonzini NetQueue *queue; 640e64c770dSYang Hongyang int ret; 641fd9400b3SPaolo Bonzini 642fd9400b3SPaolo Bonzini #ifdef DEBUG_NET 643fd9400b3SPaolo Bonzini printf("qemu_send_packet_async:\n"); 644b42581f5SPhilippe Mathieu-Daudé qemu_hexdump(stdout, "net", buf, size); 645fd9400b3SPaolo Bonzini #endif 646fd9400b3SPaolo Bonzini 647fd9400b3SPaolo Bonzini if (sender->link_down || !sender->peer) { 648fd9400b3SPaolo Bonzini return size; 649fd9400b3SPaolo Bonzini } 650fd9400b3SPaolo Bonzini 651e64c770dSYang Hongyang /* Let filters handle the packet first */ 652e64c770dSYang Hongyang ret = filter_receive(sender, NET_FILTER_DIRECTION_TX, 653e64c770dSYang Hongyang sender, flags, buf, size, sent_cb); 654e64c770dSYang Hongyang if (ret) { 655e64c770dSYang Hongyang return ret; 656e64c770dSYang Hongyang } 657e64c770dSYang Hongyang 658e64c770dSYang Hongyang ret = filter_receive(sender->peer, NET_FILTER_DIRECTION_RX, 659e64c770dSYang Hongyang sender, flags, buf, size, sent_cb); 660e64c770dSYang Hongyang if (ret) { 661e64c770dSYang Hongyang return ret; 662e64c770dSYang Hongyang } 663e64c770dSYang Hongyang 664067404beSJan Kiszka queue = sender->peer->incoming_queue; 665fd9400b3SPaolo Bonzini 666fd9400b3SPaolo Bonzini return qemu_net_queue_send(queue, sender, flags, buf, size, sent_cb); 667fd9400b3SPaolo Bonzini } 668fd9400b3SPaolo Bonzini 669fd9400b3SPaolo Bonzini ssize_t qemu_send_packet_async(NetClientState *sender, 670fd9400b3SPaolo Bonzini const uint8_t *buf, int size, 671fd9400b3SPaolo Bonzini NetPacketSent *sent_cb) 672fd9400b3SPaolo Bonzini { 673fd9400b3SPaolo Bonzini return qemu_send_packet_async_with_flags(sender, QEMU_NET_PACKET_FLAG_NONE, 674fd9400b3SPaolo Bonzini buf, size, sent_cb); 675fd9400b3SPaolo Bonzini } 676fd9400b3SPaolo Bonzini 677625a526bSMarc-André Lureau ssize_t qemu_send_packet(NetClientState *nc, const uint8_t *buf, int size) 678fd9400b3SPaolo Bonzini { 679625a526bSMarc-André Lureau return qemu_send_packet_async(nc, buf, size, NULL); 680fd9400b3SPaolo Bonzini } 681fd9400b3SPaolo Bonzini 682fd9400b3SPaolo Bonzini ssize_t qemu_send_packet_raw(NetClientState *nc, const uint8_t *buf, int size) 683fd9400b3SPaolo Bonzini { 684fd9400b3SPaolo Bonzini return qemu_send_packet_async_with_flags(nc, QEMU_NET_PACKET_FLAG_RAW, 685fd9400b3SPaolo Bonzini buf, size, NULL); 686fd9400b3SPaolo Bonzini } 687fd9400b3SPaolo Bonzini 688fd9400b3SPaolo Bonzini static ssize_t nc_sendv_compat(NetClientState *nc, const struct iovec *iov, 689fefe2a78SYang Hongyang int iovcnt, unsigned flags) 690fd9400b3SPaolo Bonzini { 69174044c8fSPooja Dhannawat uint8_t *buf = NULL; 692fefe2a78SYang Hongyang uint8_t *buffer; 693fd9400b3SPaolo Bonzini size_t offset; 69474044c8fSPooja Dhannawat ssize_t ret; 695fd9400b3SPaolo Bonzini 696fefe2a78SYang Hongyang if (iovcnt == 1) { 697fefe2a78SYang Hongyang buffer = iov[0].iov_base; 698fefe2a78SYang Hongyang offset = iov[0].iov_len; 699fefe2a78SYang Hongyang } else { 70047f9f158SPeter Lieven offset = iov_size(iov, iovcnt); 70147f9f158SPeter Lieven if (offset > NET_BUFSIZE) { 70247f9f158SPeter Lieven return -1; 70347f9f158SPeter Lieven } 70447f9f158SPeter Lieven buf = g_malloc(offset); 705fefe2a78SYang Hongyang buffer = buf; 70647f9f158SPeter Lieven offset = iov_to_buf(iov, iovcnt, 0, buf, offset); 707fefe2a78SYang Hongyang } 708fd9400b3SPaolo Bonzini 709fefe2a78SYang Hongyang if (flags & QEMU_NET_PACKET_FLAG_RAW && nc->info->receive_raw) { 71074044c8fSPooja Dhannawat ret = nc->info->receive_raw(nc, buffer, offset); 711fefe2a78SYang Hongyang } else { 71274044c8fSPooja Dhannawat ret = nc->info->receive(nc, buffer, offset); 713fd9400b3SPaolo Bonzini } 71474044c8fSPooja Dhannawat 71574044c8fSPooja Dhannawat g_free(buf); 71674044c8fSPooja Dhannawat return ret; 717fefe2a78SYang Hongyang } 718fd9400b3SPaolo Bonzini 71925c01bd1SJason Wang static ssize_t qemu_deliver_packet_iov(NetClientState *sender, 720fd9400b3SPaolo Bonzini unsigned flags, 721fd9400b3SPaolo Bonzini const struct iovec *iov, 722fd9400b3SPaolo Bonzini int iovcnt, 723fd9400b3SPaolo Bonzini void *opaque) 724fd9400b3SPaolo Bonzini { 725fd9400b3SPaolo Bonzini NetClientState *nc = opaque; 726fd9400b3SPaolo Bonzini int ret; 727fd9400b3SPaolo Bonzini 7281592a994SJason Wang 729fd9400b3SPaolo Bonzini if (nc->link_down) { 73025c01bd1SJason Wang return iov_size(iov, iovcnt); 731fd9400b3SPaolo Bonzini } 732fd9400b3SPaolo Bonzini 733fd9400b3SPaolo Bonzini if (nc->receive_disabled) { 734fd9400b3SPaolo Bonzini return 0; 735fd9400b3SPaolo Bonzini } 736fd9400b3SPaolo Bonzini 737ca1ee3d6SPeter Lieven if (nc->info->receive_iov && !(flags & QEMU_NET_PACKET_FLAG_RAW)) { 738fd9400b3SPaolo Bonzini ret = nc->info->receive_iov(nc, iov, iovcnt); 739fd9400b3SPaolo Bonzini } else { 740fefe2a78SYang Hongyang ret = nc_sendv_compat(nc, iov, iovcnt, flags); 741fd9400b3SPaolo Bonzini } 742fd9400b3SPaolo Bonzini 743fd9400b3SPaolo Bonzini if (ret == 0) { 744fd9400b3SPaolo Bonzini nc->receive_disabled = 1; 745fd9400b3SPaolo Bonzini } 746fd9400b3SPaolo Bonzini 747fd9400b3SPaolo Bonzini return ret; 748fd9400b3SPaolo Bonzini } 749fd9400b3SPaolo Bonzini 750fd9400b3SPaolo Bonzini ssize_t qemu_sendv_packet_async(NetClientState *sender, 751fd9400b3SPaolo Bonzini const struct iovec *iov, int iovcnt, 752fd9400b3SPaolo Bonzini NetPacketSent *sent_cb) 753fd9400b3SPaolo Bonzini { 754fd9400b3SPaolo Bonzini NetQueue *queue; 75525c01bd1SJason Wang size_t size = iov_size(iov, iovcnt); 756e64c770dSYang Hongyang int ret; 757fd9400b3SPaolo Bonzini 75825c01bd1SJason Wang if (size > NET_BUFSIZE) { 75925c01bd1SJason Wang return size; 76025c01bd1SJason Wang } 76125c01bd1SJason Wang 762fd9400b3SPaolo Bonzini if (sender->link_down || !sender->peer) { 76325c01bd1SJason Wang return size; 764fd9400b3SPaolo Bonzini } 765fd9400b3SPaolo Bonzini 766e64c770dSYang Hongyang /* Let filters handle the packet first */ 767e64c770dSYang Hongyang ret = filter_receive_iov(sender, NET_FILTER_DIRECTION_TX, sender, 768e64c770dSYang Hongyang QEMU_NET_PACKET_FLAG_NONE, iov, iovcnt, sent_cb); 769e64c770dSYang Hongyang if (ret) { 770e64c770dSYang Hongyang return ret; 771e64c770dSYang Hongyang } 772e64c770dSYang Hongyang 773e64c770dSYang Hongyang ret = filter_receive_iov(sender->peer, NET_FILTER_DIRECTION_RX, sender, 774e64c770dSYang Hongyang QEMU_NET_PACKET_FLAG_NONE, iov, iovcnt, sent_cb); 775e64c770dSYang Hongyang if (ret) { 776e64c770dSYang Hongyang return ret; 777e64c770dSYang Hongyang } 778e64c770dSYang Hongyang 779067404beSJan Kiszka queue = sender->peer->incoming_queue; 780fd9400b3SPaolo Bonzini 781fd9400b3SPaolo Bonzini return qemu_net_queue_send_iov(queue, sender, 782fd9400b3SPaolo Bonzini QEMU_NET_PACKET_FLAG_NONE, 783fd9400b3SPaolo Bonzini iov, iovcnt, sent_cb); 784fd9400b3SPaolo Bonzini } 785fd9400b3SPaolo Bonzini 786fd9400b3SPaolo Bonzini ssize_t 787fd9400b3SPaolo Bonzini qemu_sendv_packet(NetClientState *nc, const struct iovec *iov, int iovcnt) 788fd9400b3SPaolo Bonzini { 789fd9400b3SPaolo Bonzini return qemu_sendv_packet_async(nc, iov, iovcnt, NULL); 790fd9400b3SPaolo Bonzini } 791fd9400b3SPaolo Bonzini 792fd9400b3SPaolo Bonzini NetClientState *qemu_find_netdev(const char *id) 793fd9400b3SPaolo Bonzini { 794fd9400b3SPaolo Bonzini NetClientState *nc; 795fd9400b3SPaolo Bonzini 796fd9400b3SPaolo Bonzini QTAILQ_FOREACH(nc, &net_clients, next) { 797f394b2e2SEric Blake if (nc->info->type == NET_CLIENT_DRIVER_NIC) 798fd9400b3SPaolo Bonzini continue; 799fd9400b3SPaolo Bonzini if (!strcmp(nc->name, id)) { 800fd9400b3SPaolo Bonzini return nc; 801fd9400b3SPaolo Bonzini } 802fd9400b3SPaolo Bonzini } 803fd9400b3SPaolo Bonzini 804fd9400b3SPaolo Bonzini return NULL; 805fd9400b3SPaolo Bonzini } 806fd9400b3SPaolo Bonzini 8076c51ae73SJason Wang int qemu_find_net_clients_except(const char *id, NetClientState **ncs, 808f394b2e2SEric Blake NetClientDriver type, int max) 8096c51ae73SJason Wang { 8106c51ae73SJason Wang NetClientState *nc; 8116c51ae73SJason Wang int ret = 0; 8126c51ae73SJason Wang 8136c51ae73SJason Wang QTAILQ_FOREACH(nc, &net_clients, next) { 8146c51ae73SJason Wang if (nc->info->type == type) { 8156c51ae73SJason Wang continue; 8166c51ae73SJason Wang } 81740d19394SHani Benhabiles if (!id || !strcmp(nc->name, id)) { 8186c51ae73SJason Wang if (ret < max) { 8196c51ae73SJason Wang ncs[ret] = nc; 8206c51ae73SJason Wang } 8216c51ae73SJason Wang ret++; 8226c51ae73SJason Wang } 8236c51ae73SJason Wang } 8246c51ae73SJason Wang 8256c51ae73SJason Wang return ret; 8266c51ae73SJason Wang } 8276c51ae73SJason Wang 828fd9400b3SPaolo Bonzini static int nic_get_free_idx(void) 829fd9400b3SPaolo Bonzini { 830fd9400b3SPaolo Bonzini int index; 831fd9400b3SPaolo Bonzini 832fd9400b3SPaolo Bonzini for (index = 0; index < MAX_NICS; index++) 833fd9400b3SPaolo Bonzini if (!nd_table[index].used) 834fd9400b3SPaolo Bonzini return index; 835fd9400b3SPaolo Bonzini return -1; 836fd9400b3SPaolo Bonzini } 837fd9400b3SPaolo Bonzini 838fd9400b3SPaolo Bonzini int qemu_show_nic_models(const char *arg, const char *const *models) 839fd9400b3SPaolo Bonzini { 840fd9400b3SPaolo Bonzini int i; 841fd9400b3SPaolo Bonzini 842fd9400b3SPaolo Bonzini if (!arg || !is_help_option(arg)) { 843fd9400b3SPaolo Bonzini return 0; 844fd9400b3SPaolo Bonzini } 845fd9400b3SPaolo Bonzini 8467b71e03aSThomas Huth printf("Supported NIC models:\n"); 8477b71e03aSThomas Huth for (i = 0 ; models[i]; i++) { 8487b71e03aSThomas Huth printf("%s\n", models[i]); 8497b71e03aSThomas Huth } 850fd9400b3SPaolo Bonzini return 1; 851fd9400b3SPaolo Bonzini } 852fd9400b3SPaolo Bonzini 853fd9400b3SPaolo Bonzini void qemu_check_nic_model(NICInfo *nd, const char *model) 854fd9400b3SPaolo Bonzini { 855fd9400b3SPaolo Bonzini const char *models[2]; 856fd9400b3SPaolo Bonzini 857fd9400b3SPaolo Bonzini models[0] = model; 858fd9400b3SPaolo Bonzini models[1] = NULL; 859fd9400b3SPaolo Bonzini 860fd9400b3SPaolo Bonzini if (qemu_show_nic_models(nd->model, models)) 861fd9400b3SPaolo Bonzini exit(0); 862fd9400b3SPaolo Bonzini if (qemu_find_nic_model(nd, models, model) < 0) 863fd9400b3SPaolo Bonzini exit(1); 864fd9400b3SPaolo Bonzini } 865fd9400b3SPaolo Bonzini 866fd9400b3SPaolo Bonzini int qemu_find_nic_model(NICInfo *nd, const char * const *models, 867fd9400b3SPaolo Bonzini const char *default_model) 868fd9400b3SPaolo Bonzini { 869fd9400b3SPaolo Bonzini int i; 870fd9400b3SPaolo Bonzini 871fd9400b3SPaolo Bonzini if (!nd->model) 872fd9400b3SPaolo Bonzini nd->model = g_strdup(default_model); 873fd9400b3SPaolo Bonzini 874fd9400b3SPaolo Bonzini for (i = 0 ; models[i]; i++) { 875fd9400b3SPaolo Bonzini if (strcmp(nd->model, models[i]) == 0) 876fd9400b3SPaolo Bonzini return i; 877fd9400b3SPaolo Bonzini } 878fd9400b3SPaolo Bonzini 879fd9400b3SPaolo Bonzini error_report("Unsupported NIC model: %s", nd->model); 880fd9400b3SPaolo Bonzini return -1; 881fd9400b3SPaolo Bonzini } 882fd9400b3SPaolo Bonzini 883cebea510SKővágó, Zoltán static int net_init_nic(const Netdev *netdev, const char *name, 884a30ecde6SMarkus Armbruster NetClientState *peer, Error **errp) 885fd9400b3SPaolo Bonzini { 886fd9400b3SPaolo Bonzini int idx; 887fd9400b3SPaolo Bonzini NICInfo *nd; 888fd9400b3SPaolo Bonzini const NetLegacyNicOptions *nic; 889fd9400b3SPaolo Bonzini 890f394b2e2SEric Blake assert(netdev->type == NET_CLIENT_DRIVER_NIC); 891f394b2e2SEric Blake nic = &netdev->u.nic; 892fd9400b3SPaolo Bonzini 893fd9400b3SPaolo Bonzini idx = nic_get_free_idx(); 894fd9400b3SPaolo Bonzini if (idx == -1 || nb_nics >= MAX_NICS) { 89566308868SMarkus Armbruster error_setg(errp, "too many NICs"); 896fd9400b3SPaolo Bonzini return -1; 897fd9400b3SPaolo Bonzini } 898fd9400b3SPaolo Bonzini 899fd9400b3SPaolo Bonzini nd = &nd_table[idx]; 900fd9400b3SPaolo Bonzini 901fd9400b3SPaolo Bonzini memset(nd, 0, sizeof(*nd)); 902fd9400b3SPaolo Bonzini 903fd9400b3SPaolo Bonzini if (nic->has_netdev) { 904fd9400b3SPaolo Bonzini nd->netdev = qemu_find_netdev(nic->netdev); 905fd9400b3SPaolo Bonzini if (!nd->netdev) { 90666308868SMarkus Armbruster error_setg(errp, "netdev '%s' not found", nic->netdev); 907fd9400b3SPaolo Bonzini return -1; 908fd9400b3SPaolo Bonzini } 909fd9400b3SPaolo Bonzini } else { 910fd9400b3SPaolo Bonzini assert(peer); 911fd9400b3SPaolo Bonzini nd->netdev = peer; 912fd9400b3SPaolo Bonzini } 913fd9400b3SPaolo Bonzini nd->name = g_strdup(name); 914fd9400b3SPaolo Bonzini if (nic->has_model) { 915fd9400b3SPaolo Bonzini nd->model = g_strdup(nic->model); 916fd9400b3SPaolo Bonzini } 917fd9400b3SPaolo Bonzini if (nic->has_addr) { 918fd9400b3SPaolo Bonzini nd->devaddr = g_strdup(nic->addr); 919fd9400b3SPaolo Bonzini } 920fd9400b3SPaolo Bonzini 921fd9400b3SPaolo Bonzini if (nic->has_macaddr && 922fd9400b3SPaolo Bonzini net_parse_macaddr(nd->macaddr.a, nic->macaddr) < 0) { 92366308868SMarkus Armbruster error_setg(errp, "invalid syntax for ethernet address"); 924fd9400b3SPaolo Bonzini return -1; 925fd9400b3SPaolo Bonzini } 926d60b20cfSDmitry Krivenok if (nic->has_macaddr && 927d60b20cfSDmitry Krivenok is_multicast_ether_addr(nd->macaddr.a)) { 92866308868SMarkus Armbruster error_setg(errp, 92966308868SMarkus Armbruster "NIC cannot have multicast MAC address (odd 1st byte)"); 930d60b20cfSDmitry Krivenok return -1; 931d60b20cfSDmitry Krivenok } 932fd9400b3SPaolo Bonzini qemu_macaddr_default_if_unset(&nd->macaddr); 933fd9400b3SPaolo Bonzini 934fd9400b3SPaolo Bonzini if (nic->has_vectors) { 935fd9400b3SPaolo Bonzini if (nic->vectors > 0x7ffffff) { 93666308868SMarkus Armbruster error_setg(errp, "invalid # of vectors: %"PRIu32, nic->vectors); 937fd9400b3SPaolo Bonzini return -1; 938fd9400b3SPaolo Bonzini } 939fd9400b3SPaolo Bonzini nd->nvectors = nic->vectors; 940fd9400b3SPaolo Bonzini } else { 941fd9400b3SPaolo Bonzini nd->nvectors = DEV_NVECTORS_UNSPECIFIED; 942fd9400b3SPaolo Bonzini } 943fd9400b3SPaolo Bonzini 944fd9400b3SPaolo Bonzini nd->used = 1; 945fd9400b3SPaolo Bonzini nb_nics++; 946fd9400b3SPaolo Bonzini 947fd9400b3SPaolo Bonzini return idx; 948fd9400b3SPaolo Bonzini } 949fd9400b3SPaolo Bonzini 950fd9400b3SPaolo Bonzini 951f394b2e2SEric Blake static int (* const net_client_init_fun[NET_CLIENT_DRIVER__MAX])( 952cebea510SKővágó, Zoltán const Netdev *netdev, 953fd9400b3SPaolo Bonzini const char *name, 954a30ecde6SMarkus Armbruster NetClientState *peer, Error **errp) = { 955f394b2e2SEric Blake [NET_CLIENT_DRIVER_NIC] = net_init_nic, 956fd9400b3SPaolo Bonzini #ifdef CONFIG_SLIRP 957f394b2e2SEric Blake [NET_CLIENT_DRIVER_USER] = net_init_slirp, 958fd9400b3SPaolo Bonzini #endif 959f394b2e2SEric Blake [NET_CLIENT_DRIVER_TAP] = net_init_tap, 960f394b2e2SEric Blake [NET_CLIENT_DRIVER_SOCKET] = net_init_socket, 961fd9400b3SPaolo Bonzini #ifdef CONFIG_VDE 962f394b2e2SEric Blake [NET_CLIENT_DRIVER_VDE] = net_init_vde, 963fd9400b3SPaolo Bonzini #endif 96458952137SVincenzo Maffione #ifdef CONFIG_NETMAP 965f394b2e2SEric Blake [NET_CLIENT_DRIVER_NETMAP] = net_init_netmap, 96658952137SVincenzo Maffione #endif 967fd9400b3SPaolo Bonzini #ifdef CONFIG_NET_BRIDGE 968f394b2e2SEric Blake [NET_CLIENT_DRIVER_BRIDGE] = net_init_bridge, 969fd9400b3SPaolo Bonzini #endif 970f394b2e2SEric Blake [NET_CLIENT_DRIVER_HUBPORT] = net_init_hubport, 97156f41de7SPaolo Bonzini #ifdef CONFIG_VHOST_NET_USER 972f394b2e2SEric Blake [NET_CLIENT_DRIVER_VHOST_USER] = net_init_vhost_user, 97303ce5744SNikolay Nikolaev #endif 9741e0a84eaSCindy Lu #ifdef CONFIG_VHOST_NET_VDPA 9751e0a84eaSCindy Lu [NET_CLIENT_DRIVER_VHOST_VDPA] = net_init_vhost_vdpa, 9761e0a84eaSCindy Lu #endif 977015a33bdSGonglei #ifdef CONFIG_L2TPV3 978f394b2e2SEric Blake [NET_CLIENT_DRIVER_L2TPV3] = net_init_l2tpv3, 9793fb69aa1SAnton Ivanov #endif 980fd9400b3SPaolo Bonzini }; 981fd9400b3SPaolo Bonzini 982fd9400b3SPaolo Bonzini 98371830d84SThomas Huth static int net_client_init1(const Netdev *netdev, bool is_netdev, Error **errp) 984fd9400b3SPaolo Bonzini { 9854ef0defbSStefan Hajnoczi NetClientState *peer = NULL; 986831734ccSMarkus Armbruster NetClientState *nc; 987fd9400b3SPaolo Bonzini 988fd9400b3SPaolo Bonzini if (is_netdev) { 989857d2087SThomas Huth if (netdev->type == NET_CLIENT_DRIVER_NIC || 990f394b2e2SEric Blake !net_client_init_fun[netdev->type]) { 991c6bd8c70SMarkus Armbruster error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "type", 992fd9400b3SPaolo Bonzini "a netdev backend type"); 993fd9400b3SPaolo Bonzini return -1; 994fd9400b3SPaolo Bonzini } 995fd9400b3SPaolo Bonzini } else { 99671830d84SThomas Huth if (netdev->type == NET_CLIENT_DRIVER_NONE) { 9971e81aba5SStefan Hajnoczi return 0; /* nothing to do */ 998ca7eb184SMarkus Armbruster } 99971830d84SThomas Huth if (netdev->type == NET_CLIENT_DRIVER_HUBPORT || 100071830d84SThomas Huth !net_client_init_fun[netdev->type]) { 1001d139e9a6SStefan Hajnoczi error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "type", 1002d139e9a6SStefan Hajnoczi "a net backend type (maybe it is not compiled " 1003d139e9a6SStefan Hajnoczi "into this binary)"); 1004d139e9a6SStefan Hajnoczi return -1; 1005d139e9a6SStefan Hajnoczi } 1006fd9400b3SPaolo Bonzini 1007af1a5c3eSThomas Huth /* Do not add to a hub if it's a nic with a netdev= parameter. */ 1008f394b2e2SEric Blake if (netdev->type != NET_CLIENT_DRIVER_NIC || 100971830d84SThomas Huth !netdev->u.nic.has_netdev) { 1010af1a5c3eSThomas Huth peer = net_hub_add_port(0, NULL, NULL); 1011a2dbe135SThomas Huth } 1012fd9400b3SPaolo Bonzini } 1013fd9400b3SPaolo Bonzini 1014831734ccSMarkus Armbruster nc = qemu_find_netdev(netdev->id); 1015831734ccSMarkus Armbruster if (nc) { 1016831734ccSMarkus Armbruster error_setg(errp, "Duplicate ID '%s'", netdev->id); 1017831734ccSMarkus Armbruster return -1; 1018831734ccSMarkus Armbruster } 1019831734ccSMarkus Armbruster 10209d903f30SThomas Huth if (net_client_init_fun[netdev->type](netdev, netdev->id, peer, errp) < 0) { 1021a30ecde6SMarkus Armbruster /* FIXME drop when all init functions store an Error */ 1022a30ecde6SMarkus Armbruster if (errp && !*errp) { 1023f820af87SMarkus Armbruster error_setg(errp, "Device '%s' could not be initialized", 1024977c736fSMarkus Armbruster NetClientDriver_str(netdev->type)); 1025a30ecde6SMarkus Armbruster } 1026fd9400b3SPaolo Bonzini return -1; 1027fd9400b3SPaolo Bonzini } 102808712fcbSEric Blake 102908712fcbSEric Blake if (is_netdev) { 103008712fcbSEric Blake nc = qemu_find_netdev(netdev->id); 103108712fcbSEric Blake assert(nc); 103208712fcbSEric Blake nc->is_netdev = true; 103308712fcbSEric Blake } 103408712fcbSEric Blake 1035fd9400b3SPaolo Bonzini return 0; 1036fd9400b3SPaolo Bonzini } 1037fd9400b3SPaolo Bonzini 1038ad6f932fSPaolo Bonzini void show_netdevs(void) 1039547203eaSThomas Huth { 1040547203eaSThomas Huth int idx; 1041547203eaSThomas Huth const char *available_netdevs[] = { 1042547203eaSThomas Huth "socket", 1043547203eaSThomas Huth "hubport", 1044547203eaSThomas Huth "tap", 1045547203eaSThomas Huth #ifdef CONFIG_SLIRP 1046547203eaSThomas Huth "user", 1047547203eaSThomas Huth #endif 1048547203eaSThomas Huth #ifdef CONFIG_L2TPV3 1049547203eaSThomas Huth "l2tpv3", 1050547203eaSThomas Huth #endif 1051547203eaSThomas Huth #ifdef CONFIG_VDE 1052547203eaSThomas Huth "vde", 1053547203eaSThomas Huth #endif 1054547203eaSThomas Huth #ifdef CONFIG_NET_BRIDGE 1055547203eaSThomas Huth "bridge", 1056547203eaSThomas Huth #endif 1057547203eaSThomas Huth #ifdef CONFIG_NETMAP 1058547203eaSThomas Huth "netmap", 1059547203eaSThomas Huth #endif 1060547203eaSThomas Huth #ifdef CONFIG_POSIX 1061547203eaSThomas Huth "vhost-user", 1062547203eaSThomas Huth #endif 10631bc211a1SCindy Lu #ifdef CONFIG_VHOST_VDPA 10641bc211a1SCindy Lu "vhost-vdpa", 10651bc211a1SCindy Lu #endif 1066547203eaSThomas Huth }; 1067fd9400b3SPaolo Bonzini 1068ad6f932fSPaolo Bonzini qemu_printf("Available netdev backend types:\n"); 1069547203eaSThomas Huth for (idx = 0; idx < ARRAY_SIZE(available_netdevs); idx++) { 1070ad6f932fSPaolo Bonzini qemu_printf("%s\n", available_netdevs[idx]); 1071547203eaSThomas Huth } 1072547203eaSThomas Huth } 1073fd9400b3SPaolo Bonzini 1074aa09a485SThomas Huth static int net_client_init(QemuOpts *opts, bool is_netdev, Error **errp) 1075fd9400b3SPaolo Bonzini { 1076c1112b2dSStefano Garzarella gchar **substrings = NULL; 107771830d84SThomas Huth Netdev *object = NULL; 1078fd9400b3SPaolo Bonzini int ret = -1; 107909204eacSEric Blake Visitor *v = opts_visitor_new(opts); 1080fd9400b3SPaolo Bonzini 10817aac531eSYann Bordenave /* Parse convenience option format ip6-net=fec0::0[/64] */ 1082891a2bb5SSamuel Thibault const char *ip6_net = qemu_opt_get(opts, "ipv6-net"); 10837aac531eSYann Bordenave 10847aac531eSYann Bordenave if (ip6_net) { 1085c1112b2dSStefano Garzarella char *prefix_addr; 1086c1112b2dSStefano Garzarella unsigned long prefix_len = 64; /* Default 64bit prefix length. */ 10877aac531eSYann Bordenave 1088c1112b2dSStefano Garzarella substrings = g_strsplit(ip6_net, "/", 2); 1089c1112b2dSStefano Garzarella if (!substrings || !substrings[0]) { 1090c1112b2dSStefano Garzarella error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "ipv6-net", 1091c1112b2dSStefano Garzarella "a valid IPv6 prefix"); 1092c1112b2dSStefano Garzarella goto out; 1093c1112b2dSStefano Garzarella } 1094c1112b2dSStefano Garzarella 1095c1112b2dSStefano Garzarella prefix_addr = substrings[0]; 1096c1112b2dSStefano Garzarella 109733c9642fSVladimir Sementsov-Ogievskiy /* Handle user-specified prefix length. */ 109833c9642fSVladimir Sementsov-Ogievskiy if (substrings[1] && 109933c9642fSVladimir Sementsov-Ogievskiy qemu_strtoul(substrings[1], NULL, 10, &prefix_len)) 110033c9642fSVladimir Sementsov-Ogievskiy { 11017aac531eSYann Bordenave error_setg(errp, QERR_INVALID_PARAMETER_VALUE, 110221c520d0SStefano Garzarella "ipv6-prefixlen", "a number"); 110321c520d0SStefano Garzarella goto out; 11047aac531eSYann Bordenave } 1105c1112b2dSStefano Garzarella 1106c1112b2dSStefano Garzarella qemu_opt_set(opts, "ipv6-prefix", prefix_addr, &error_abort); 1107c1112b2dSStefano Garzarella qemu_opt_set_number(opts, "ipv6-prefixlen", prefix_len, 1108c1112b2dSStefano Garzarella &error_abort); 1109891a2bb5SSamuel Thibault qemu_opt_unset(opts, "ipv6-net"); 11107aac531eSYann Bordenave } 11117aac531eSYann Bordenave 111271830d84SThomas Huth /* Create an ID for -net if the user did not specify one */ 111371830d84SThomas Huth if (!is_netdev && !qemu_opts_id(opts)) { 111471830d84SThomas Huth static int idx; 111571830d84SThomas Huth qemu_opts_set_id(opts, g_strdup_printf("__org.qemu.net%i", idx++)); 1116fd9400b3SPaolo Bonzini } 1117fd9400b3SPaolo Bonzini 111814217038SMarkus Armbruster if (visit_type_Netdev(v, NULL, &object, errp)) { 111914217038SMarkus Armbruster ret = net_client_init1(object, is_netdev, errp); 1120fd9400b3SPaolo Bonzini } 1121fd9400b3SPaolo Bonzini 112296a1616cSEric Blake qapi_free_Netdev(object); 1123fd9400b3SPaolo Bonzini 112421c520d0SStefano Garzarella out: 1125c1112b2dSStefano Garzarella g_strfreev(substrings); 112609204eacSEric Blake visit_free(v); 1127fd9400b3SPaolo Bonzini return ret; 1128fd9400b3SPaolo Bonzini } 1129fd9400b3SPaolo Bonzini 1130fd9400b3SPaolo Bonzini void netdev_add(QemuOpts *opts, Error **errp) 1131fd9400b3SPaolo Bonzini { 11320e55c381SEric Blake net_client_init(opts, true, errp); 1133fd9400b3SPaolo Bonzini } 1134fd9400b3SPaolo Bonzini 1135db2a380cSEric Blake void qmp_netdev_add(Netdev *netdev, Error **errp) 1136fd9400b3SPaolo Bonzini { 113708712fcbSEric Blake net_client_init1(netdev, true, errp); 1138fd9400b3SPaolo Bonzini } 1139fd9400b3SPaolo Bonzini 1140fd9400b3SPaolo Bonzini void qmp_netdev_del(const char *id, Error **errp) 1141fd9400b3SPaolo Bonzini { 1142fd9400b3SPaolo Bonzini NetClientState *nc; 1143831734ccSMarkus Armbruster QemuOpts *opts; 1144fd9400b3SPaolo Bonzini 1145fd9400b3SPaolo Bonzini nc = qemu_find_netdev(id); 1146fd9400b3SPaolo Bonzini if (!nc) { 114775158ebbSMarkus Armbruster error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 114875158ebbSMarkus Armbruster "Device '%s' not found", id); 1149fd9400b3SPaolo Bonzini return; 1150fd9400b3SPaolo Bonzini } 1151fd9400b3SPaolo Bonzini 115208712fcbSEric Blake if (!nc->is_netdev) { 1153fd9400b3SPaolo Bonzini error_setg(errp, "Device '%s' is not a netdev", id); 1154fd9400b3SPaolo Bonzini return; 1155fd9400b3SPaolo Bonzini } 1156fd9400b3SPaolo Bonzini 1157fd9400b3SPaolo Bonzini qemu_del_net_client(nc); 1158831734ccSMarkus Armbruster 1159831734ccSMarkus Armbruster /* 1160831734ccSMarkus Armbruster * Wart: we need to delete the QemuOpts associated with netdevs 1161831734ccSMarkus Armbruster * created via CLI or HMP, to avoid bogus "Duplicate ID" errors in 1162831734ccSMarkus Armbruster * HMP netdev_add. 1163831734ccSMarkus Armbruster */ 1164831734ccSMarkus Armbruster opts = qemu_opts_find(qemu_find_opts("netdev"), id); 1165831734ccSMarkus Armbruster if (opts) { 1166831734ccSMarkus Armbruster qemu_opts_del(opts); 1167831734ccSMarkus Armbruster } 1168fd9400b3SPaolo Bonzini } 1169fd9400b3SPaolo Bonzini 1170aa9156f4Szhanghailiang static void netfilter_print_info(Monitor *mon, NetFilterState *nf) 1171aa9156f4Szhanghailiang { 1172aa9156f4Szhanghailiang char *str; 1173aa9156f4Szhanghailiang ObjectProperty *prop; 1174aa9156f4Szhanghailiang ObjectPropertyIterator iter; 11753b098d56SEric Blake Visitor *v; 1176aa9156f4Szhanghailiang 1177aa9156f4Szhanghailiang /* generate info str */ 1178aa9156f4Szhanghailiang object_property_iter_init(&iter, OBJECT(nf)); 1179aa9156f4Szhanghailiang while ((prop = object_property_iter_next(&iter))) { 1180aa9156f4Szhanghailiang if (!strcmp(prop->name, "type")) { 1181aa9156f4Szhanghailiang continue; 1182aa9156f4Szhanghailiang } 11833b098d56SEric Blake v = string_output_visitor_new(false, &str); 11845325cc34SMarkus Armbruster object_property_get(OBJECT(nf), prop->name, v, NULL); 11853b098d56SEric Blake visit_complete(v, &str); 11863b098d56SEric Blake visit_free(v); 1187aa9156f4Szhanghailiang monitor_printf(mon, ",%s=%s", prop->name, str); 1188aa9156f4Szhanghailiang g_free(str); 1189aa9156f4Szhanghailiang } 1190aa9156f4Szhanghailiang monitor_printf(mon, "\n"); 1191aa9156f4Szhanghailiang } 1192aa9156f4Szhanghailiang 1193fd9400b3SPaolo Bonzini void print_net_client(Monitor *mon, NetClientState *nc) 1194fd9400b3SPaolo Bonzini { 1195a4960f52SYang Hongyang NetFilterState *nf; 1196a4960f52SYang Hongyang 11971ceef9f2SJason Wang monitor_printf(mon, "%s: index=%d,type=%s,%s\n", nc->name, 11981ceef9f2SJason Wang nc->queue_index, 1199977c736fSMarkus Armbruster NetClientDriver_str(nc->info->type), 12001ceef9f2SJason Wang nc->info_str); 1201a4960f52SYang Hongyang if (!QTAILQ_EMPTY(&nc->filters)) { 1202a4960f52SYang Hongyang monitor_printf(mon, "filters:\n"); 1203a4960f52SYang Hongyang } 1204a4960f52SYang Hongyang QTAILQ_FOREACH(nf, &nc->filters, next) { 12057a309cc9SMarkus Armbruster monitor_printf(mon, " - %s: type=%s", 12067a309cc9SMarkus Armbruster object_get_canonical_path_component(OBJECT(nf)), 1207aa9156f4Szhanghailiang object_get_typename(OBJECT(nf))); 1208aa9156f4Szhanghailiang netfilter_print_info(mon, nf); 1209a4960f52SYang Hongyang } 1210fd9400b3SPaolo Bonzini } 1211fd9400b3SPaolo Bonzini 1212b1be4280SAmos Kong RxFilterInfoList *qmp_query_rx_filter(bool has_name, const char *name, 1213b1be4280SAmos Kong Error **errp) 1214b1be4280SAmos Kong { 1215b1be4280SAmos Kong NetClientState *nc; 1216b1be4280SAmos Kong RxFilterInfoList *filter_list = NULL, *last_entry = NULL; 1217b1be4280SAmos Kong 1218b1be4280SAmos Kong QTAILQ_FOREACH(nc, &net_clients, next) { 1219b1be4280SAmos Kong RxFilterInfoList *entry; 1220b1be4280SAmos Kong RxFilterInfo *info; 1221b1be4280SAmos Kong 1222b1be4280SAmos Kong if (has_name && strcmp(nc->name, name) != 0) { 1223b1be4280SAmos Kong continue; 1224b1be4280SAmos Kong } 1225b1be4280SAmos Kong 1226b1be4280SAmos Kong /* only query rx-filter information of NIC */ 1227f394b2e2SEric Blake if (nc->info->type != NET_CLIENT_DRIVER_NIC) { 1228b1be4280SAmos Kong if (has_name) { 1229b1be4280SAmos Kong error_setg(errp, "net client(%s) isn't a NIC", name); 1230*e9d635eaSEric Blake assert(!filter_list); 12319083da1dSMarkus Armbruster return NULL; 1232b1be4280SAmos Kong } 1233b1be4280SAmos Kong continue; 1234b1be4280SAmos Kong } 1235b1be4280SAmos Kong 12365320c2caSVladislav Yasevich /* only query information on queue 0 since the info is per nic, 12375320c2caSVladislav Yasevich * not per queue 12385320c2caSVladislav Yasevich */ 12395320c2caSVladislav Yasevich if (nc->queue_index != 0) 12405320c2caSVladislav Yasevich continue; 12415320c2caSVladislav Yasevich 1242b1be4280SAmos Kong if (nc->info->query_rx_filter) { 1243b1be4280SAmos Kong info = nc->info->query_rx_filter(nc); 1244b1be4280SAmos Kong entry = g_malloc0(sizeof(*entry)); 1245b1be4280SAmos Kong entry->value = info; 1246b1be4280SAmos Kong 1247b1be4280SAmos Kong if (!filter_list) { 1248b1be4280SAmos Kong filter_list = entry; 1249b1be4280SAmos Kong } else { 1250b1be4280SAmos Kong last_entry->next = entry; 1251b1be4280SAmos Kong } 1252b1be4280SAmos Kong last_entry = entry; 1253b1be4280SAmos Kong } else if (has_name) { 1254b1be4280SAmos Kong error_setg(errp, "net client(%s) doesn't support" 1255b1be4280SAmos Kong " rx-filter querying", name); 1256*e9d635eaSEric Blake assert(!filter_list); 12579083da1dSMarkus Armbruster return NULL; 1258b1be4280SAmos Kong } 1259638fb141SMarkus Armbruster 1260638fb141SMarkus Armbruster if (has_name) { 1261638fb141SMarkus Armbruster break; 1262638fb141SMarkus Armbruster } 1263b1be4280SAmos Kong } 1264b1be4280SAmos Kong 12659083da1dSMarkus Armbruster if (filter_list == NULL && has_name) { 1266b1be4280SAmos Kong error_setg(errp, "invalid net client name: %s", name); 1267b1be4280SAmos Kong } 1268b1be4280SAmos Kong 1269b1be4280SAmos Kong return filter_list; 1270b1be4280SAmos Kong } 1271b1be4280SAmos Kong 12721ce6be24SMarkus Armbruster void hmp_info_network(Monitor *mon, const QDict *qdict) 1273fd9400b3SPaolo Bonzini { 1274fd9400b3SPaolo Bonzini NetClientState *nc, *peer; 1275f394b2e2SEric Blake NetClientDriver type; 1276fd9400b3SPaolo Bonzini 1277fd9400b3SPaolo Bonzini net_hub_info(mon); 1278fd9400b3SPaolo Bonzini 1279fd9400b3SPaolo Bonzini QTAILQ_FOREACH(nc, &net_clients, next) { 1280fd9400b3SPaolo Bonzini peer = nc->peer; 1281fd9400b3SPaolo Bonzini type = nc->info->type; 1282fd9400b3SPaolo Bonzini 1283fd9400b3SPaolo Bonzini /* Skip if already printed in hub info */ 1284fd9400b3SPaolo Bonzini if (net_hub_id_for_client(nc, NULL) == 0) { 1285fd9400b3SPaolo Bonzini continue; 1286fd9400b3SPaolo Bonzini } 1287fd9400b3SPaolo Bonzini 1288f394b2e2SEric Blake if (!peer || type == NET_CLIENT_DRIVER_NIC) { 1289fd9400b3SPaolo Bonzini print_net_client(mon, nc); 1290fd9400b3SPaolo Bonzini } /* else it's a netdev connected to a NIC, printed with the NIC */ 1291f394b2e2SEric Blake if (peer && type == NET_CLIENT_DRIVER_NIC) { 1292fd9400b3SPaolo Bonzini monitor_printf(mon, " \\ "); 1293fd9400b3SPaolo Bonzini print_net_client(mon, peer); 1294fd9400b3SPaolo Bonzini } 1295fd9400b3SPaolo Bonzini } 1296fd9400b3SPaolo Bonzini } 1297fd9400b3SPaolo Bonzini 12985fbba3d6SZhang Chen void colo_notify_filters_event(int event, Error **errp) 12995fbba3d6SZhang Chen { 13005fbba3d6SZhang Chen NetClientState *nc; 13015fbba3d6SZhang Chen NetFilterState *nf; 13025fbba3d6SZhang Chen NetFilterClass *nfc = NULL; 13035fbba3d6SZhang Chen Error *local_err = NULL; 13045fbba3d6SZhang Chen 13055fbba3d6SZhang Chen QTAILQ_FOREACH(nc, &net_clients, next) { 13065fbba3d6SZhang Chen QTAILQ_FOREACH(nf, &nc->filters, next) { 13075fbba3d6SZhang Chen nfc = NETFILTER_GET_CLASS(OBJECT(nf)); 13085fbba3d6SZhang Chen nfc->handle_event(nf, event, &local_err); 13095fbba3d6SZhang Chen if (local_err) { 13105fbba3d6SZhang Chen error_propagate(errp, local_err); 13115fbba3d6SZhang Chen return; 13125fbba3d6SZhang Chen } 13135fbba3d6SZhang Chen } 13145fbba3d6SZhang Chen } 13155fbba3d6SZhang Chen } 13165fbba3d6SZhang Chen 1317fd9400b3SPaolo Bonzini void qmp_set_link(const char *name, bool up, Error **errp) 1318fd9400b3SPaolo Bonzini { 13191ceef9f2SJason Wang NetClientState *ncs[MAX_QUEUE_NUM]; 13201ceef9f2SJason Wang NetClientState *nc; 13211ceef9f2SJason Wang int queues, i; 1322fd9400b3SPaolo Bonzini 13231ceef9f2SJason Wang queues = qemu_find_net_clients_except(name, ncs, 1324f394b2e2SEric Blake NET_CLIENT_DRIVER__MAX, 13251ceef9f2SJason Wang MAX_QUEUE_NUM); 13261ceef9f2SJason Wang 13271ceef9f2SJason Wang if (queues == 0) { 132875158ebbSMarkus Armbruster error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 132975158ebbSMarkus Armbruster "Device '%s' not found", name); 1330fd9400b3SPaolo Bonzini return; 1331fd9400b3SPaolo Bonzini } 13321ceef9f2SJason Wang nc = ncs[0]; 1333fd9400b3SPaolo Bonzini 13341ceef9f2SJason Wang for (i = 0; i < queues; i++) { 13351ceef9f2SJason Wang ncs[i]->link_down = !up; 13361ceef9f2SJason Wang } 1337fd9400b3SPaolo Bonzini 1338fd9400b3SPaolo Bonzini if (nc->info->link_status_changed) { 1339fd9400b3SPaolo Bonzini nc->info->link_status_changed(nc); 1340fd9400b3SPaolo Bonzini } 1341fd9400b3SPaolo Bonzini 134202d38fcbSVlad Yasevich if (nc->peer) { 134302d38fcbSVlad Yasevich /* Change peer link only if the peer is NIC and then notify peer. 134402d38fcbSVlad Yasevich * If the peer is a HUBPORT or a backend, we do not change the 134502d38fcbSVlad Yasevich * link status. 1346fd9400b3SPaolo Bonzini * 1347af1a5c3eSThomas Huth * This behavior is compatible with qemu hubs where there could be 1348fd9400b3SPaolo Bonzini * multiple clients that can still communicate with each other in 134902d38fcbSVlad Yasevich * disconnected mode. For now maintain this compatibility. 135002d38fcbSVlad Yasevich */ 1351f394b2e2SEric Blake if (nc->peer->info->type == NET_CLIENT_DRIVER_NIC) { 135202d38fcbSVlad Yasevich for (i = 0; i < queues; i++) { 135302d38fcbSVlad Yasevich ncs[i]->peer->link_down = !up; 135402d38fcbSVlad Yasevich } 135502d38fcbSVlad Yasevich } 135602d38fcbSVlad Yasevich if (nc->peer->info->link_status_changed) { 1357fd9400b3SPaolo Bonzini nc->peer->info->link_status_changed(nc->peer); 1358fd9400b3SPaolo Bonzini } 1359fd9400b3SPaolo Bonzini } 136002d38fcbSVlad Yasevich } 1361fd9400b3SPaolo Bonzini 1362ca77d85eSMichael S. Tsirkin static void net_vm_change_state_handler(void *opaque, int running, 1363ca77d85eSMichael S. Tsirkin RunState state) 1364ca77d85eSMichael S. Tsirkin { 1365ca77d85eSMichael S. Tsirkin NetClientState *nc; 1366ca77d85eSMichael S. Tsirkin NetClientState *tmp; 1367ca77d85eSMichael S. Tsirkin 1368ca77d85eSMichael S. Tsirkin QTAILQ_FOREACH_SAFE(nc, &net_clients, next, tmp) { 1369625de449SFam Zheng if (running) { 1370625de449SFam Zheng /* Flush queued packets and wake up backends. */ 1371625de449SFam Zheng if (nc->peer && qemu_can_send_packet(nc)) { 1372625de449SFam Zheng qemu_flush_queued_packets(nc->peer); 1373625de449SFam Zheng } 1374625de449SFam Zheng } else { 1375625de449SFam Zheng /* Complete all queued packets, to guarantee we don't modify 1376625de449SFam Zheng * state later when VM is not running. 1377625de449SFam Zheng */ 1378ca77d85eSMichael S. Tsirkin qemu_flush_or_purge_queued_packets(nc, true); 1379ca77d85eSMichael S. Tsirkin } 1380ca77d85eSMichael S. Tsirkin } 1381ca77d85eSMichael S. Tsirkin } 1382ca77d85eSMichael S. Tsirkin 1383fd9400b3SPaolo Bonzini void net_cleanup(void) 1384fd9400b3SPaolo Bonzini { 13851ceef9f2SJason Wang NetClientState *nc; 1386fd9400b3SPaolo Bonzini 13871ceef9f2SJason Wang /* We may del multiple entries during qemu_del_net_client(), 13881ceef9f2SJason Wang * so QTAILQ_FOREACH_SAFE() is also not safe here. 13891ceef9f2SJason Wang */ 13901ceef9f2SJason Wang while (!QTAILQ_EMPTY(&net_clients)) { 13911ceef9f2SJason Wang nc = QTAILQ_FIRST(&net_clients); 1392f394b2e2SEric Blake if (nc->info->type == NET_CLIENT_DRIVER_NIC) { 1393948ecf21SJason Wang qemu_del_nic(qemu_get_nic(nc)); 1394948ecf21SJason Wang } else { 1395fd9400b3SPaolo Bonzini qemu_del_net_client(nc); 1396fd9400b3SPaolo Bonzini } 1397fd9400b3SPaolo Bonzini } 1398ca77d85eSMichael S. Tsirkin 1399ca77d85eSMichael S. Tsirkin qemu_del_vm_change_state_handler(net_change_state_entry); 1400948ecf21SJason Wang } 1401fd9400b3SPaolo Bonzini 1402fd9400b3SPaolo Bonzini void net_check_clients(void) 1403fd9400b3SPaolo Bonzini { 1404fd9400b3SPaolo Bonzini NetClientState *nc; 1405fd9400b3SPaolo Bonzini int i; 1406fd9400b3SPaolo Bonzini 1407fd9400b3SPaolo Bonzini net_hub_check_clients(); 1408fd9400b3SPaolo Bonzini 1409fd9400b3SPaolo Bonzini QTAILQ_FOREACH(nc, &net_clients, next) { 1410fd9400b3SPaolo Bonzini if (!nc->peer) { 14118297be80SAlistair Francis warn_report("%s %s has no peer", 1412b62e39b4SAlistair Francis nc->info->type == NET_CLIENT_DRIVER_NIC 1413b62e39b4SAlistair Francis ? "nic" : "netdev", 1414b62e39b4SAlistair Francis nc->name); 1415fd9400b3SPaolo Bonzini } 1416fd9400b3SPaolo Bonzini } 1417fd9400b3SPaolo Bonzini 1418fd9400b3SPaolo Bonzini /* Check that all NICs requested via -net nic actually got created. 1419fd9400b3SPaolo Bonzini * NICs created via -device don't need to be checked here because 1420fd9400b3SPaolo Bonzini * they are always instantiated. 1421fd9400b3SPaolo Bonzini */ 1422fd9400b3SPaolo Bonzini for (i = 0; i < MAX_NICS; i++) { 1423fd9400b3SPaolo Bonzini NICInfo *nd = &nd_table[i]; 1424fd9400b3SPaolo Bonzini if (nd->used && !nd->instantiated) { 14258297be80SAlistair Francis warn_report("requested NIC (%s, model %s) " 14268297be80SAlistair Francis "was not created (not supported by this machine?)", 1427fd9400b3SPaolo Bonzini nd->name ? nd->name : "anonymous", 1428fd9400b3SPaolo Bonzini nd->model ? nd->model : "unspecified"); 1429fd9400b3SPaolo Bonzini } 1430fd9400b3SPaolo Bonzini } 1431fd9400b3SPaolo Bonzini } 1432fd9400b3SPaolo Bonzini 143328d0de7aSMarkus Armbruster static int net_init_client(void *dummy, QemuOpts *opts, Error **errp) 1434fd9400b3SPaolo Bonzini { 143534f708b0SThomas Huth return net_client_init(opts, false, errp); 1436fd9400b3SPaolo Bonzini } 1437fd9400b3SPaolo Bonzini 143828d0de7aSMarkus Armbruster static int net_init_netdev(void *dummy, QemuOpts *opts, Error **errp) 1439fd9400b3SPaolo Bonzini { 1440ad6f932fSPaolo Bonzini const char *type = qemu_opt_get(opts, "type"); 1441ad6f932fSPaolo Bonzini 1442ad6f932fSPaolo Bonzini if (type && is_help_option(type)) { 1443ad6f932fSPaolo Bonzini show_netdevs(); 1444ad6f932fSPaolo Bonzini exit(0); 1445ad6f932fSPaolo Bonzini } 144634f708b0SThomas Huth return net_client_init(opts, true, errp); 1447fd9400b3SPaolo Bonzini } 1448fd9400b3SPaolo Bonzini 144978cd6f7bSThomas Huth /* For the convenience "--nic" parameter */ 145078cd6f7bSThomas Huth static int net_param_nic(void *dummy, QemuOpts *opts, Error **errp) 145178cd6f7bSThomas Huth { 145278cd6f7bSThomas Huth char *mac, *nd_id; 145378cd6f7bSThomas Huth int idx, ret; 145478cd6f7bSThomas Huth NICInfo *ni; 145578cd6f7bSThomas Huth const char *type; 145678cd6f7bSThomas Huth 145778cd6f7bSThomas Huth type = qemu_opt_get(opts, "type"); 145878cd6f7bSThomas Huth if (type && g_str_equal(type, "none")) { 145978cd6f7bSThomas Huth return 0; /* Nothing to do, default_net is cleared in vl.c */ 146078cd6f7bSThomas Huth } 146178cd6f7bSThomas Huth 146278cd6f7bSThomas Huth idx = nic_get_free_idx(); 146378cd6f7bSThomas Huth if (idx == -1 || nb_nics >= MAX_NICS) { 146478cd6f7bSThomas Huth error_setg(errp, "no more on-board/default NIC slots available"); 1465fd9400b3SPaolo Bonzini return -1; 1466fd9400b3SPaolo Bonzini } 1467fd9400b3SPaolo Bonzini 146878cd6f7bSThomas Huth if (!type) { 146978cd6f7bSThomas Huth qemu_opt_set(opts, "type", "user", &error_abort); 147078cd6f7bSThomas Huth } 147178cd6f7bSThomas Huth 147278cd6f7bSThomas Huth ni = &nd_table[idx]; 147378cd6f7bSThomas Huth memset(ni, 0, sizeof(*ni)); 147478cd6f7bSThomas Huth ni->model = qemu_opt_get_del(opts, "model"); 147578cd6f7bSThomas Huth 147678cd6f7bSThomas Huth /* Create an ID if the user did not specify one */ 147778cd6f7bSThomas Huth nd_id = g_strdup(qemu_opts_id(opts)); 147878cd6f7bSThomas Huth if (!nd_id) { 14790561dfacSThomas Huth nd_id = g_strdup_printf("__org.qemu.nic%i", idx); 148078cd6f7bSThomas Huth qemu_opts_set_id(opts, nd_id); 148178cd6f7bSThomas Huth } 148278cd6f7bSThomas Huth 148378cd6f7bSThomas Huth /* Handle MAC address */ 148478cd6f7bSThomas Huth mac = qemu_opt_get_del(opts, "mac"); 148578cd6f7bSThomas Huth if (mac) { 148678cd6f7bSThomas Huth ret = net_parse_macaddr(ni->macaddr.a, mac); 148778cd6f7bSThomas Huth g_free(mac); 148878cd6f7bSThomas Huth if (ret) { 148978cd6f7bSThomas Huth error_setg(errp, "invalid syntax for ethernet address"); 14909d946191SThomas Huth goto out; 149178cd6f7bSThomas Huth } 149278cd6f7bSThomas Huth if (is_multicast_ether_addr(ni->macaddr.a)) { 149378cd6f7bSThomas Huth error_setg(errp, "NIC cannot have multicast MAC address"); 14949d946191SThomas Huth ret = -1; 14959d946191SThomas Huth goto out; 149678cd6f7bSThomas Huth } 149778cd6f7bSThomas Huth } 149878cd6f7bSThomas Huth qemu_macaddr_default_if_unset(&ni->macaddr); 149978cd6f7bSThomas Huth 150078cd6f7bSThomas Huth ret = net_client_init(opts, true, errp); 150178cd6f7bSThomas Huth if (ret == 0) { 150278cd6f7bSThomas Huth ni->netdev = qemu_find_netdev(nd_id); 150378cd6f7bSThomas Huth ni->used = true; 150478cd6f7bSThomas Huth nb_nics++; 150578cd6f7bSThomas Huth } 150678cd6f7bSThomas Huth 15079d946191SThomas Huth out: 150878cd6f7bSThomas Huth g_free(nd_id); 1509fd9400b3SPaolo Bonzini return ret; 1510fd9400b3SPaolo Bonzini } 1511fd9400b3SPaolo Bonzini 151234f708b0SThomas Huth int net_init_clients(Error **errp) 1513fd9400b3SPaolo Bonzini { 1514ca77d85eSMichael S. Tsirkin net_change_state_entry = 1515ca77d85eSMichael S. Tsirkin qemu_add_vm_change_state_handler(net_vm_change_state_handler, NULL); 1516ca77d85eSMichael S. Tsirkin 1517fd9400b3SPaolo Bonzini QTAILQ_INIT(&net_clients); 1518fd9400b3SPaolo Bonzini 151928d0de7aSMarkus Armbruster if (qemu_opts_foreach(qemu_find_opts("netdev"), 152034f708b0SThomas Huth net_init_netdev, NULL, errp)) { 1521fd9400b3SPaolo Bonzini return -1; 1522a4c7367fSMarkus Armbruster } 1523fd9400b3SPaolo Bonzini 152478cd6f7bSThomas Huth if (qemu_opts_foreach(qemu_find_opts("nic"), net_param_nic, NULL, errp)) { 152578cd6f7bSThomas Huth return -1; 152678cd6f7bSThomas Huth } 152778cd6f7bSThomas Huth 152834f708b0SThomas Huth if (qemu_opts_foreach(qemu_find_opts("net"), net_init_client, NULL, errp)) { 1529fd9400b3SPaolo Bonzini return -1; 1530fd9400b3SPaolo Bonzini } 1531fd9400b3SPaolo Bonzini 1532fd9400b3SPaolo Bonzini return 0; 1533fd9400b3SPaolo Bonzini } 1534fd9400b3SPaolo Bonzini 1535fd9400b3SPaolo Bonzini int net_client_parse(QemuOptsList *opts_list, const char *optarg) 1536fd9400b3SPaolo Bonzini { 153770b94331SMarkus Armbruster if (!qemu_opts_parse_noisily(opts_list, optarg, true)) { 1538fd9400b3SPaolo Bonzini return -1; 1539fd9400b3SPaolo Bonzini } 1540fd9400b3SPaolo Bonzini 1541fd9400b3SPaolo Bonzini return 0; 1542fd9400b3SPaolo Bonzini } 1543fd9400b3SPaolo Bonzini 1544fd9400b3SPaolo Bonzini /* From FreeBSD */ 1545fd9400b3SPaolo Bonzini /* XXX: optimize */ 1546eaba8f34SMark Cave-Ayland uint32_t net_crc32(const uint8_t *p, int len) 1547fd9400b3SPaolo Bonzini { 1548fd9400b3SPaolo Bonzini uint32_t crc; 1549fd9400b3SPaolo Bonzini int carry, i, j; 1550fd9400b3SPaolo Bonzini uint8_t b; 1551fd9400b3SPaolo Bonzini 1552fd9400b3SPaolo Bonzini crc = 0xffffffff; 1553eaba8f34SMark Cave-Ayland for (i = 0; i < len; i++) { 1554eaba8f34SMark Cave-Ayland b = *p++; 1555fd9400b3SPaolo Bonzini for (j = 0; j < 8; j++) { 1556fd9400b3SPaolo Bonzini carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01); 1557fd9400b3SPaolo Bonzini crc <<= 1; 1558fd9400b3SPaolo Bonzini b >>= 1; 1559fd9400b3SPaolo Bonzini if (carry) { 1560eaba8f34SMark Cave-Ayland crc = ((crc ^ POLYNOMIAL_BE) | carry); 1561fd9400b3SPaolo Bonzini } 1562fd9400b3SPaolo Bonzini } 1563fd9400b3SPaolo Bonzini } 1564eaba8f34SMark Cave-Ayland 1565eaba8f34SMark Cave-Ayland return crc; 1566eaba8f34SMark Cave-Ayland } 1567eaba8f34SMark Cave-Ayland 1568f1a7deb9SMark Cave-Ayland uint32_t net_crc32_le(const uint8_t *p, int len) 1569f1a7deb9SMark Cave-Ayland { 1570f1a7deb9SMark Cave-Ayland uint32_t crc; 1571f1a7deb9SMark Cave-Ayland int carry, i, j; 1572f1a7deb9SMark Cave-Ayland uint8_t b; 1573f1a7deb9SMark Cave-Ayland 1574f1a7deb9SMark Cave-Ayland crc = 0xffffffff; 1575f1a7deb9SMark Cave-Ayland for (i = 0; i < len; i++) { 1576f1a7deb9SMark Cave-Ayland b = *p++; 1577f1a7deb9SMark Cave-Ayland for (j = 0; j < 8; j++) { 1578f1a7deb9SMark Cave-Ayland carry = (crc & 0x1) ^ (b & 0x01); 1579f1a7deb9SMark Cave-Ayland crc >>= 1; 1580f1a7deb9SMark Cave-Ayland b >>= 1; 1581f1a7deb9SMark Cave-Ayland if (carry) { 1582f1a7deb9SMark Cave-Ayland crc ^= POLYNOMIAL_LE; 1583f1a7deb9SMark Cave-Ayland } 1584f1a7deb9SMark Cave-Ayland } 1585f1a7deb9SMark Cave-Ayland } 1586f1a7deb9SMark Cave-Ayland 1587f1a7deb9SMark Cave-Ayland return crc; 1588f1a7deb9SMark Cave-Ayland } 1589f1a7deb9SMark Cave-Ayland 15904d454574SPaolo Bonzini QemuOptsList qemu_netdev_opts = { 15914d454574SPaolo Bonzini .name = "netdev", 15924d454574SPaolo Bonzini .implied_opt_name = "type", 15934d454574SPaolo Bonzini .head = QTAILQ_HEAD_INITIALIZER(qemu_netdev_opts.head), 15944d454574SPaolo Bonzini .desc = { 15954d454574SPaolo Bonzini /* 15964d454574SPaolo Bonzini * no elements => accept any params 15974d454574SPaolo Bonzini * validation will happen later 15984d454574SPaolo Bonzini */ 15994d454574SPaolo Bonzini { /* end of list */ } 16004d454574SPaolo Bonzini }, 16014d454574SPaolo Bonzini }; 16024d454574SPaolo Bonzini 160378cd6f7bSThomas Huth QemuOptsList qemu_nic_opts = { 160478cd6f7bSThomas Huth .name = "nic", 160578cd6f7bSThomas Huth .implied_opt_name = "type", 160678cd6f7bSThomas Huth .head = QTAILQ_HEAD_INITIALIZER(qemu_nic_opts.head), 160778cd6f7bSThomas Huth .desc = { 160878cd6f7bSThomas Huth /* 160978cd6f7bSThomas Huth * no elements => accept any params 161078cd6f7bSThomas Huth * validation will happen later 161178cd6f7bSThomas Huth */ 161278cd6f7bSThomas Huth { /* end of list */ } 161378cd6f7bSThomas Huth }, 161478cd6f7bSThomas Huth }; 161578cd6f7bSThomas Huth 16164d454574SPaolo Bonzini QemuOptsList qemu_net_opts = { 16174d454574SPaolo Bonzini .name = "net", 16184d454574SPaolo Bonzini .implied_opt_name = "type", 16194d454574SPaolo Bonzini .head = QTAILQ_HEAD_INITIALIZER(qemu_net_opts.head), 16204d454574SPaolo Bonzini .desc = { 16214d454574SPaolo Bonzini /* 16224d454574SPaolo Bonzini * no elements => accept any params 16234d454574SPaolo Bonzini * validation will happen later 16244d454574SPaolo Bonzini */ 16254d454574SPaolo Bonzini { /* end of list */ } 16264d454574SPaolo Bonzini }, 16274d454574SPaolo Bonzini }; 162816a3df40SZhang Chen 162916a3df40SZhang Chen void net_socket_rs_init(SocketReadState *rs, 16303cde5ea2SZhang Chen SocketReadStateFinalize *finalize, 16313cde5ea2SZhang Chen bool vnet_hdr) 163216a3df40SZhang Chen { 163316a3df40SZhang Chen rs->state = 0; 16343cde5ea2SZhang Chen rs->vnet_hdr = vnet_hdr; 163516a3df40SZhang Chen rs->index = 0; 163616a3df40SZhang Chen rs->packet_len = 0; 16373cde5ea2SZhang Chen rs->vnet_hdr_len = 0; 163816a3df40SZhang Chen memset(rs->buf, 0, sizeof(rs->buf)); 163916a3df40SZhang Chen rs->finalize = finalize; 164016a3df40SZhang Chen } 164116a3df40SZhang Chen 164216a3df40SZhang Chen /* 164316a3df40SZhang Chen * Returns 1644e9e0a585SZhang Chen * 0: success 1645e9e0a585SZhang Chen * -1: error occurs 164616a3df40SZhang Chen */ 164716a3df40SZhang Chen int net_fill_rstate(SocketReadState *rs, const uint8_t *buf, int size) 164816a3df40SZhang Chen { 164916a3df40SZhang Chen unsigned int l; 165016a3df40SZhang Chen 165116a3df40SZhang Chen while (size > 0) { 16523cde5ea2SZhang Chen /* Reassemble a packet from the network. 16533cde5ea2SZhang Chen * 0 = getting length. 16543cde5ea2SZhang Chen * 1 = getting vnet header length. 16553cde5ea2SZhang Chen * 2 = getting data. 16563cde5ea2SZhang Chen */ 16573cde5ea2SZhang Chen switch (rs->state) { 165816a3df40SZhang Chen case 0: 165916a3df40SZhang Chen l = 4 - rs->index; 166016a3df40SZhang Chen if (l > size) { 166116a3df40SZhang Chen l = size; 166216a3df40SZhang Chen } 166316a3df40SZhang Chen memcpy(rs->buf + rs->index, buf, l); 166416a3df40SZhang Chen buf += l; 166516a3df40SZhang Chen size -= l; 166616a3df40SZhang Chen rs->index += l; 166716a3df40SZhang Chen if (rs->index == 4) { 166816a3df40SZhang Chen /* got length */ 166916a3df40SZhang Chen rs->packet_len = ntohl(*(uint32_t *)rs->buf); 167016a3df40SZhang Chen rs->index = 0; 16713cde5ea2SZhang Chen if (rs->vnet_hdr) { 167216a3df40SZhang Chen rs->state = 1; 16733cde5ea2SZhang Chen } else { 16743cde5ea2SZhang Chen rs->state = 2; 16753cde5ea2SZhang Chen rs->vnet_hdr_len = 0; 16763cde5ea2SZhang Chen } 167716a3df40SZhang Chen } 167816a3df40SZhang Chen break; 167916a3df40SZhang Chen case 1: 16803cde5ea2SZhang Chen l = 4 - rs->index; 16813cde5ea2SZhang Chen if (l > size) { 16823cde5ea2SZhang Chen l = size; 16833cde5ea2SZhang Chen } 16843cde5ea2SZhang Chen memcpy(rs->buf + rs->index, buf, l); 16853cde5ea2SZhang Chen buf += l; 16863cde5ea2SZhang Chen size -= l; 16873cde5ea2SZhang Chen rs->index += l; 16883cde5ea2SZhang Chen if (rs->index == 4) { 16893cde5ea2SZhang Chen /* got vnet header length */ 16903cde5ea2SZhang Chen rs->vnet_hdr_len = ntohl(*(uint32_t *)rs->buf); 16913cde5ea2SZhang Chen rs->index = 0; 16923cde5ea2SZhang Chen rs->state = 2; 16933cde5ea2SZhang Chen } 16943cde5ea2SZhang Chen break; 16953cde5ea2SZhang Chen case 2: 169616a3df40SZhang Chen l = rs->packet_len - rs->index; 169716a3df40SZhang Chen if (l > size) { 169816a3df40SZhang Chen l = size; 169916a3df40SZhang Chen } 170016a3df40SZhang Chen if (rs->index + l <= sizeof(rs->buf)) { 170116a3df40SZhang Chen memcpy(rs->buf + rs->index, buf, l); 170216a3df40SZhang Chen } else { 170316a3df40SZhang Chen fprintf(stderr, "serious error: oversized packet received," 170416a3df40SZhang Chen "connection terminated.\n"); 170516a3df40SZhang Chen rs->index = rs->state = 0; 170616a3df40SZhang Chen return -1; 170716a3df40SZhang Chen } 170816a3df40SZhang Chen 170916a3df40SZhang Chen rs->index += l; 171016a3df40SZhang Chen buf += l; 171116a3df40SZhang Chen size -= l; 171216a3df40SZhang Chen if (rs->index >= rs->packet_len) { 171316a3df40SZhang Chen rs->index = 0; 171416a3df40SZhang Chen rs->state = 0; 1715e79cd406SDaniel P. Berrange assert(rs->finalize); 171616a3df40SZhang Chen rs->finalize(rs); 171716a3df40SZhang Chen } 171816a3df40SZhang Chen break; 171916a3df40SZhang Chen } 172016a3df40SZhang Chen } 1721e9e0a585SZhang Chen 1722e9e0a585SZhang Chen assert(size == 0); 172316a3df40SZhang Chen return 0; 172416a3df40SZhang Chen } 1725