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" 301422e32dSPaolo Bonzini #include "net/slirp.h" 31d60b20cfSDmitry Krivenok #include "net/eth.h" 32fd9400b3SPaolo Bonzini #include "util.h" 33fd9400b3SPaolo Bonzini 3483c9089eSPaolo Bonzini #include "monitor/monitor.h" 35f348b6d1SVeronia Bahaa #include "qemu/help_option.h" 36*9af23989SMarkus Armbruster #include "qapi/qapi-commands-net.h" 37*9af23989SMarkus Armbruster #include "qapi/qapi-visit-net.h" 38452fcdbcSMarkus Armbruster #include "qapi/qmp/qdict.h" 39cc7a8ea7SMarkus Armbruster #include "qapi/qmp/qerror.h" 40d49b6836SMarkus Armbruster #include "qemu/error-report.h" 411de7afc9SPaolo Bonzini #include "qemu/sockets.h" 42f348b6d1SVeronia Bahaa #include "qemu/cutils.h" 431de7afc9SPaolo Bonzini #include "qemu/config-file.h" 44fd9400b3SPaolo Bonzini #include "hw/qdev.h" 451de7afc9SPaolo Bonzini #include "qemu/iov.h" 466a1751b7SAlex Bligh #include "qemu/main-loop.h" 47922a01a0SMarkus Armbruster #include "qemu/option.h" 48e688df6bSMarkus Armbruster #include "qapi/error.h" 49fd9400b3SPaolo Bonzini #include "qapi/opts-visitor.h" 50e1d64c08Szhanghailiang #include "sysemu/sysemu.h" 51559964a1SThomas Huth #include "sysemu/qtest.h" 52fdccce45SYang Hongyang #include "net/filter.h" 53aa9156f4Szhanghailiang #include "qapi/string-output-visitor.h" 54fd9400b3SPaolo Bonzini 55fd9400b3SPaolo Bonzini /* Net bridge is currently not supported for W32. */ 56fd9400b3SPaolo Bonzini #if !defined(_WIN32) 57fd9400b3SPaolo Bonzini # define CONFIG_NET_BRIDGE 58fd9400b3SPaolo Bonzini #endif 59fd9400b3SPaolo Bonzini 60ca77d85eSMichael S. Tsirkin static VMChangeStateEntry *net_change_state_entry; 61fd9400b3SPaolo Bonzini static QTAILQ_HEAD(, NetClientState) net_clients; 62fd9400b3SPaolo Bonzini 6384007e81SHani Benhabiles const char *host_net_devices[] = { 6484007e81SHani Benhabiles "tap", 6584007e81SHani Benhabiles "socket", 6684007e81SHani Benhabiles "dump", 6784007e81SHani Benhabiles #ifdef CONFIG_NET_BRIDGE 6884007e81SHani Benhabiles "bridge", 6984007e81SHani Benhabiles #endif 70027a247bSStefan Hajnoczi #ifdef CONFIG_NETMAP 71027a247bSStefan Hajnoczi "netmap", 72027a247bSStefan Hajnoczi #endif 7384007e81SHani Benhabiles #ifdef CONFIG_SLIRP 7484007e81SHani Benhabiles "user", 7584007e81SHani Benhabiles #endif 7684007e81SHani Benhabiles #ifdef CONFIG_VDE 7784007e81SHani Benhabiles "vde", 7884007e81SHani Benhabiles #endif 7903ce5744SNikolay Nikolaev "vhost-user", 8084007e81SHani Benhabiles NULL, 8184007e81SHani Benhabiles }; 8284007e81SHani Benhabiles 83fd9400b3SPaolo Bonzini /***********************************************************/ 84fd9400b3SPaolo Bonzini /* network device redirectors */ 85fd9400b3SPaolo Bonzini 86fd9400b3SPaolo Bonzini static int get_str_sep(char *buf, int buf_size, const char **pp, int sep) 87fd9400b3SPaolo Bonzini { 88fd9400b3SPaolo Bonzini const char *p, *p1; 89fd9400b3SPaolo Bonzini int len; 90fd9400b3SPaolo Bonzini p = *pp; 91fd9400b3SPaolo Bonzini p1 = strchr(p, sep); 92fd9400b3SPaolo Bonzini if (!p1) 93fd9400b3SPaolo Bonzini return -1; 94fd9400b3SPaolo Bonzini len = p1 - p; 95fd9400b3SPaolo Bonzini p1++; 96fd9400b3SPaolo Bonzini if (buf_size > 0) { 97fd9400b3SPaolo Bonzini if (len > buf_size - 1) 98fd9400b3SPaolo Bonzini len = buf_size - 1; 99fd9400b3SPaolo Bonzini memcpy(buf, p, len); 100fd9400b3SPaolo Bonzini buf[len] = '\0'; 101fd9400b3SPaolo Bonzini } 102fd9400b3SPaolo Bonzini *pp = p1; 103fd9400b3SPaolo Bonzini return 0; 104fd9400b3SPaolo Bonzini } 105fd9400b3SPaolo Bonzini 106bcd4dfd6SMao Zhongyi int parse_host_port(struct sockaddr_in *saddr, const char *str, 107bcd4dfd6SMao Zhongyi Error **errp) 108fd9400b3SPaolo Bonzini { 109fd9400b3SPaolo Bonzini char buf[512]; 110fd9400b3SPaolo Bonzini struct hostent *he; 111fd9400b3SPaolo Bonzini const char *p, *r; 112fd9400b3SPaolo Bonzini int port; 113fd9400b3SPaolo Bonzini 114fd9400b3SPaolo Bonzini p = str; 115bcd4dfd6SMao Zhongyi if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { 116bcd4dfd6SMao Zhongyi error_setg(errp, "host address '%s' doesn't contain ':' " 117bcd4dfd6SMao Zhongyi "separating host from port", str); 118fd9400b3SPaolo Bonzini return -1; 119bcd4dfd6SMao Zhongyi } 120fd9400b3SPaolo Bonzini saddr->sin_family = AF_INET; 121fd9400b3SPaolo Bonzini if (buf[0] == '\0') { 122fd9400b3SPaolo Bonzini saddr->sin_addr.s_addr = 0; 123fd9400b3SPaolo Bonzini } else { 124fd9400b3SPaolo Bonzini if (qemu_isdigit(buf[0])) { 125bcd4dfd6SMao Zhongyi if (!inet_aton(buf, &saddr->sin_addr)) { 126bcd4dfd6SMao Zhongyi error_setg(errp, "host address '%s' is not a valid " 127bcd4dfd6SMao Zhongyi "IPv4 address", buf); 128fd9400b3SPaolo Bonzini return -1; 129bcd4dfd6SMao Zhongyi } 130fd9400b3SPaolo Bonzini } else { 131bcd4dfd6SMao Zhongyi he = gethostbyname(buf); 132bcd4dfd6SMao Zhongyi if (he == NULL) { 133bcd4dfd6SMao Zhongyi error_setg(errp, "can't resolve host address '%s'", buf); 134fd9400b3SPaolo Bonzini return - 1; 135bcd4dfd6SMao Zhongyi } 136fd9400b3SPaolo Bonzini saddr->sin_addr = *(struct in_addr *)he->h_addr; 137fd9400b3SPaolo Bonzini } 138fd9400b3SPaolo Bonzini } 139fd9400b3SPaolo Bonzini port = strtol(p, (char **)&r, 0); 140bcd4dfd6SMao Zhongyi if (r == p) { 141bcd4dfd6SMao Zhongyi error_setg(errp, "port number '%s' is invalid", p); 142fd9400b3SPaolo Bonzini return -1; 143bcd4dfd6SMao Zhongyi } 144fd9400b3SPaolo Bonzini saddr->sin_port = htons(port); 145fd9400b3SPaolo Bonzini return 0; 146fd9400b3SPaolo Bonzini } 147fd9400b3SPaolo Bonzini 148890ee6abSScott Feldman char *qemu_mac_strdup_printf(const uint8_t *macaddr) 149890ee6abSScott Feldman { 150890ee6abSScott Feldman return g_strdup_printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", 151890ee6abSScott Feldman macaddr[0], macaddr[1], macaddr[2], 152890ee6abSScott Feldman macaddr[3], macaddr[4], macaddr[5]); 153890ee6abSScott Feldman } 154890ee6abSScott Feldman 155fd9400b3SPaolo Bonzini void qemu_format_nic_info_str(NetClientState *nc, uint8_t macaddr[6]) 156fd9400b3SPaolo Bonzini { 157fd9400b3SPaolo Bonzini snprintf(nc->info_str, sizeof(nc->info_str), 158fd9400b3SPaolo Bonzini "model=%s,macaddr=%02x:%02x:%02x:%02x:%02x:%02x", 159fd9400b3SPaolo Bonzini nc->model, 160fd9400b3SPaolo Bonzini macaddr[0], macaddr[1], macaddr[2], 161fd9400b3SPaolo Bonzini macaddr[3], macaddr[4], macaddr[5]); 162fd9400b3SPaolo Bonzini } 163fd9400b3SPaolo Bonzini 1642bc22a58SShannon Zhao static int mac_table[256] = {0}; 1652bc22a58SShannon Zhao 1662bc22a58SShannon Zhao static void qemu_macaddr_set_used(MACAddr *macaddr) 1672bc22a58SShannon Zhao { 1682bc22a58SShannon Zhao int index; 1692bc22a58SShannon Zhao 1702bc22a58SShannon Zhao for (index = 0x56; index < 0xFF; index++) { 1712bc22a58SShannon Zhao if (macaddr->a[5] == index) { 1722bc22a58SShannon Zhao mac_table[index]++; 1732bc22a58SShannon Zhao } 1742bc22a58SShannon Zhao } 1752bc22a58SShannon Zhao } 1762bc22a58SShannon Zhao 1772bc22a58SShannon Zhao static void qemu_macaddr_set_free(MACAddr *macaddr) 1782bc22a58SShannon Zhao { 1792bc22a58SShannon Zhao int index; 1802bc22a58SShannon Zhao static const MACAddr base = { .a = { 0x52, 0x54, 0x00, 0x12, 0x34, 0 } }; 1812bc22a58SShannon Zhao 1822bc22a58SShannon Zhao if (memcmp(macaddr->a, &base.a, (sizeof(base.a) - 1)) != 0) { 1832bc22a58SShannon Zhao return; 1842bc22a58SShannon Zhao } 1852bc22a58SShannon Zhao for (index = 0x56; index < 0xFF; index++) { 1862bc22a58SShannon Zhao if (macaddr->a[5] == index) { 1872bc22a58SShannon Zhao mac_table[index]--; 1882bc22a58SShannon Zhao } 1892bc22a58SShannon Zhao } 1902bc22a58SShannon Zhao } 1912bc22a58SShannon Zhao 1922bc22a58SShannon Zhao static int qemu_macaddr_get_free(void) 1932bc22a58SShannon Zhao { 1942bc22a58SShannon Zhao int index; 1952bc22a58SShannon Zhao 1962bc22a58SShannon Zhao for (index = 0x56; index < 0xFF; index++) { 1972bc22a58SShannon Zhao if (mac_table[index] == 0) { 1982bc22a58SShannon Zhao return index; 1992bc22a58SShannon Zhao } 2002bc22a58SShannon Zhao } 2012bc22a58SShannon Zhao 2022bc22a58SShannon Zhao return -1; 2032bc22a58SShannon Zhao } 2042bc22a58SShannon Zhao 205fd9400b3SPaolo Bonzini void qemu_macaddr_default_if_unset(MACAddr *macaddr) 206fd9400b3SPaolo Bonzini { 207fd9400b3SPaolo Bonzini static const MACAddr zero = { .a = { 0,0,0,0,0,0 } }; 2082bc22a58SShannon Zhao static const MACAddr base = { .a = { 0x52, 0x54, 0x00, 0x12, 0x34, 0 } }; 209fd9400b3SPaolo Bonzini 2102bc22a58SShannon Zhao if (memcmp(macaddr, &zero, sizeof(zero)) != 0) { 2112bc22a58SShannon Zhao if (memcmp(macaddr->a, &base.a, (sizeof(base.a) - 1)) != 0) { 212fd9400b3SPaolo Bonzini return; 2132bc22a58SShannon Zhao } else { 2142bc22a58SShannon Zhao qemu_macaddr_set_used(macaddr); 2152bc22a58SShannon Zhao return; 2162bc22a58SShannon Zhao } 2172bc22a58SShannon Zhao } 2182bc22a58SShannon Zhao 219fd9400b3SPaolo Bonzini macaddr->a[0] = 0x52; 220fd9400b3SPaolo Bonzini macaddr->a[1] = 0x54; 221fd9400b3SPaolo Bonzini macaddr->a[2] = 0x00; 222fd9400b3SPaolo Bonzini macaddr->a[3] = 0x12; 223fd9400b3SPaolo Bonzini macaddr->a[4] = 0x34; 2242bc22a58SShannon Zhao macaddr->a[5] = qemu_macaddr_get_free(); 2252bc22a58SShannon Zhao qemu_macaddr_set_used(macaddr); 226fd9400b3SPaolo Bonzini } 227fd9400b3SPaolo Bonzini 228fd9400b3SPaolo Bonzini /** 229fd9400b3SPaolo Bonzini * Generate a name for net client 230fd9400b3SPaolo Bonzini * 231c963530aSAmos Kong * Only net clients created with the legacy -net option and NICs need this. 232fd9400b3SPaolo Bonzini */ 233fd9400b3SPaolo Bonzini static char *assign_name(NetClientState *nc1, const char *model) 234fd9400b3SPaolo Bonzini { 235fd9400b3SPaolo Bonzini NetClientState *nc; 236fd9400b3SPaolo Bonzini int id = 0; 237fd9400b3SPaolo Bonzini 238fd9400b3SPaolo Bonzini QTAILQ_FOREACH(nc, &net_clients, next) { 239fd9400b3SPaolo Bonzini if (nc == nc1) { 240fd9400b3SPaolo Bonzini continue; 241fd9400b3SPaolo Bonzini } 242c963530aSAmos Kong if (strcmp(nc->model, model) == 0) { 243fd9400b3SPaolo Bonzini id++; 244fd9400b3SPaolo Bonzini } 245fd9400b3SPaolo Bonzini } 246fd9400b3SPaolo Bonzini 2474bf2c138SHani Benhabiles return g_strdup_printf("%s.%d", model, id); 248fd9400b3SPaolo Bonzini } 249fd9400b3SPaolo Bonzini 250f7860455SJason Wang static void qemu_net_client_destructor(NetClientState *nc) 251f7860455SJason Wang { 252f7860455SJason Wang g_free(nc); 253f7860455SJason Wang } 254f7860455SJason Wang 25518a1541aSJason Wang static void qemu_net_client_setup(NetClientState *nc, 25618a1541aSJason Wang NetClientInfo *info, 257fd9400b3SPaolo Bonzini NetClientState *peer, 258fd9400b3SPaolo Bonzini const char *model, 259f7860455SJason Wang const char *name, 260f7860455SJason Wang NetClientDestructor *destructor) 261fd9400b3SPaolo Bonzini { 262fd9400b3SPaolo Bonzini nc->info = info; 263fd9400b3SPaolo Bonzini nc->model = g_strdup(model); 264fd9400b3SPaolo Bonzini if (name) { 265fd9400b3SPaolo Bonzini nc->name = g_strdup(name); 266fd9400b3SPaolo Bonzini } else { 267fd9400b3SPaolo Bonzini nc->name = assign_name(nc, model); 268fd9400b3SPaolo Bonzini } 269fd9400b3SPaolo Bonzini 270fd9400b3SPaolo Bonzini if (peer) { 271fd9400b3SPaolo Bonzini assert(!peer->peer); 272fd9400b3SPaolo Bonzini nc->peer = peer; 273fd9400b3SPaolo Bonzini peer->peer = nc; 274fd9400b3SPaolo Bonzini } 275fd9400b3SPaolo Bonzini QTAILQ_INSERT_TAIL(&net_clients, nc, next); 276fd9400b3SPaolo Bonzini 2773e033a46SYang Hongyang nc->incoming_queue = qemu_new_net_queue(qemu_deliver_packet_iov, nc); 278f7860455SJason Wang nc->destructor = destructor; 279fdccce45SYang Hongyang QTAILQ_INIT(&nc->filters); 28018a1541aSJason Wang } 28118a1541aSJason Wang 28218a1541aSJason Wang NetClientState *qemu_new_net_client(NetClientInfo *info, 28318a1541aSJason Wang NetClientState *peer, 28418a1541aSJason Wang const char *model, 28518a1541aSJason Wang const char *name) 28618a1541aSJason Wang { 28718a1541aSJason Wang NetClientState *nc; 28818a1541aSJason Wang 28918a1541aSJason Wang assert(info->size >= sizeof(NetClientState)); 29018a1541aSJason Wang 29118a1541aSJason Wang nc = g_malloc0(info->size); 292f7860455SJason Wang qemu_net_client_setup(nc, info, peer, model, name, 293f7860455SJason Wang qemu_net_client_destructor); 29418a1541aSJason Wang 295fd9400b3SPaolo Bonzini return nc; 296fd9400b3SPaolo Bonzini } 297fd9400b3SPaolo Bonzini 298fd9400b3SPaolo Bonzini NICState *qemu_new_nic(NetClientInfo *info, 299fd9400b3SPaolo Bonzini NICConf *conf, 300fd9400b3SPaolo Bonzini const char *model, 301fd9400b3SPaolo Bonzini const char *name, 302fd9400b3SPaolo Bonzini void *opaque) 303fd9400b3SPaolo Bonzini { 3041ceef9f2SJason Wang NetClientState **peers = conf->peers.ncs; 305fd9400b3SPaolo Bonzini NICState *nic; 306575a1c0eSJiri Pirko int i, queues = MAX(1, conf->peers.queues); 307fd9400b3SPaolo Bonzini 308f394b2e2SEric Blake assert(info->type == NET_CLIENT_DRIVER_NIC); 309fd9400b3SPaolo Bonzini assert(info->size >= sizeof(NICState)); 310fd9400b3SPaolo Bonzini 311f6b26cf2SJason Wang nic = g_malloc0(info->size + sizeof(NetClientState) * queues); 312f6b26cf2SJason Wang nic->ncs = (void *)nic + info->size; 313fd9400b3SPaolo Bonzini nic->conf = conf; 314fd9400b3SPaolo Bonzini nic->opaque = opaque; 315fd9400b3SPaolo Bonzini 316f6b26cf2SJason Wang for (i = 0; i < queues; i++) { 317f6b26cf2SJason Wang qemu_net_client_setup(&nic->ncs[i], info, peers[i], model, name, 3181ceef9f2SJason Wang NULL); 3191ceef9f2SJason Wang nic->ncs[i].queue_index = i; 3201ceef9f2SJason Wang } 3211ceef9f2SJason Wang 322fd9400b3SPaolo Bonzini return nic; 323fd9400b3SPaolo Bonzini } 324fd9400b3SPaolo Bonzini 3251ceef9f2SJason Wang NetClientState *qemu_get_subqueue(NICState *nic, int queue_index) 3261ceef9f2SJason Wang { 327f6b26cf2SJason Wang return nic->ncs + queue_index; 3281ceef9f2SJason Wang } 3291ceef9f2SJason Wang 330b356f76dSJason Wang NetClientState *qemu_get_queue(NICState *nic) 331b356f76dSJason Wang { 3321ceef9f2SJason Wang return qemu_get_subqueue(nic, 0); 333b356f76dSJason Wang } 334b356f76dSJason Wang 335cc1f0f45SJason Wang NICState *qemu_get_nic(NetClientState *nc) 336cc1f0f45SJason Wang { 3371ceef9f2SJason Wang NetClientState *nc0 = nc - nc->queue_index; 3381ceef9f2SJason Wang 339f6b26cf2SJason Wang return (NICState *)((void *)nc0 - nc->info->size); 340cc1f0f45SJason Wang } 341cc1f0f45SJason Wang 342cc1f0f45SJason Wang void *qemu_get_nic_opaque(NetClientState *nc) 343cc1f0f45SJason Wang { 344cc1f0f45SJason Wang NICState *nic = qemu_get_nic(nc); 345cc1f0f45SJason Wang 346cc1f0f45SJason Wang return nic->opaque; 347cc1f0f45SJason Wang } 348cc1f0f45SJason Wang 349fd9400b3SPaolo Bonzini static void qemu_cleanup_net_client(NetClientState *nc) 350fd9400b3SPaolo Bonzini { 351fd9400b3SPaolo Bonzini QTAILQ_REMOVE(&net_clients, nc, next); 352fd9400b3SPaolo Bonzini 353cc2a9043SAndreas Färber if (nc->info->cleanup) { 354fd9400b3SPaolo Bonzini nc->info->cleanup(nc); 355fd9400b3SPaolo Bonzini } 356cc2a9043SAndreas Färber } 357fd9400b3SPaolo Bonzini 358fd9400b3SPaolo Bonzini static void qemu_free_net_client(NetClientState *nc) 359fd9400b3SPaolo Bonzini { 360067404beSJan Kiszka if (nc->incoming_queue) { 361067404beSJan Kiszka qemu_del_net_queue(nc->incoming_queue); 362fd9400b3SPaolo Bonzini } 363fd9400b3SPaolo Bonzini if (nc->peer) { 364fd9400b3SPaolo Bonzini nc->peer->peer = NULL; 365fd9400b3SPaolo Bonzini } 366fd9400b3SPaolo Bonzini g_free(nc->name); 367fd9400b3SPaolo Bonzini g_free(nc->model); 368f7860455SJason Wang if (nc->destructor) { 369f7860455SJason Wang nc->destructor(nc); 370f7860455SJason Wang } 371fd9400b3SPaolo Bonzini } 372fd9400b3SPaolo Bonzini 373fd9400b3SPaolo Bonzini void qemu_del_net_client(NetClientState *nc) 374fd9400b3SPaolo Bonzini { 3751ceef9f2SJason Wang NetClientState *ncs[MAX_QUEUE_NUM]; 3761ceef9f2SJason Wang int queues, i; 377fdccce45SYang Hongyang NetFilterState *nf, *next; 3781ceef9f2SJason Wang 379f394b2e2SEric Blake assert(nc->info->type != NET_CLIENT_DRIVER_NIC); 3807fb43911SPaolo Bonzini 3811ceef9f2SJason Wang /* If the NetClientState belongs to a multiqueue backend, we will change all 3821ceef9f2SJason Wang * other NetClientStates also. 3831ceef9f2SJason Wang */ 3841ceef9f2SJason Wang queues = qemu_find_net_clients_except(nc->name, ncs, 385f394b2e2SEric Blake NET_CLIENT_DRIVER_NIC, 3861ceef9f2SJason Wang MAX_QUEUE_NUM); 3871ceef9f2SJason Wang assert(queues != 0); 3881ceef9f2SJason Wang 389fdccce45SYang Hongyang QTAILQ_FOREACH_SAFE(nf, &nc->filters, next, next) { 390fdccce45SYang Hongyang object_unparent(OBJECT(nf)); 391fdccce45SYang Hongyang } 392fdccce45SYang Hongyang 393fd9400b3SPaolo Bonzini /* If there is a peer NIC, delete and cleanup client, but do not free. */ 394f394b2e2SEric Blake if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_NIC) { 395cc1f0f45SJason Wang NICState *nic = qemu_get_nic(nc->peer); 396fd9400b3SPaolo Bonzini if (nic->peer_deleted) { 397fd9400b3SPaolo Bonzini return; 398fd9400b3SPaolo Bonzini } 399fd9400b3SPaolo Bonzini nic->peer_deleted = true; 4001ceef9f2SJason Wang 4011ceef9f2SJason Wang for (i = 0; i < queues; i++) { 4021ceef9f2SJason Wang ncs[i]->peer->link_down = true; 4031ceef9f2SJason Wang } 4041ceef9f2SJason Wang 405fd9400b3SPaolo Bonzini if (nc->peer->info->link_status_changed) { 406fd9400b3SPaolo Bonzini nc->peer->info->link_status_changed(nc->peer); 407fd9400b3SPaolo Bonzini } 4081ceef9f2SJason Wang 4091ceef9f2SJason Wang for (i = 0; i < queues; i++) { 4101ceef9f2SJason Wang qemu_cleanup_net_client(ncs[i]); 4111ceef9f2SJason Wang } 4121ceef9f2SJason Wang 413fd9400b3SPaolo Bonzini return; 414fd9400b3SPaolo Bonzini } 415fd9400b3SPaolo Bonzini 4161ceef9f2SJason Wang for (i = 0; i < queues; i++) { 4171ceef9f2SJason Wang qemu_cleanup_net_client(ncs[i]); 4181ceef9f2SJason Wang qemu_free_net_client(ncs[i]); 4191ceef9f2SJason Wang } 420948ecf21SJason Wang } 421948ecf21SJason Wang 422948ecf21SJason Wang void qemu_del_nic(NICState *nic) 423948ecf21SJason Wang { 424575a1c0eSJiri Pirko int i, queues = MAX(nic->conf->peers.queues, 1); 4251ceef9f2SJason Wang 4262bc22a58SShannon Zhao qemu_macaddr_set_free(&nic->conf->macaddr); 4272bc22a58SShannon Zhao 428fd9400b3SPaolo Bonzini /* If this is a peer NIC and peer has already been deleted, free it now. */ 429fd9400b3SPaolo Bonzini if (nic->peer_deleted) { 4301ceef9f2SJason Wang for (i = 0; i < queues; i++) { 4311ceef9f2SJason Wang qemu_free_net_client(qemu_get_subqueue(nic, i)->peer); 432fd9400b3SPaolo Bonzini } 433fd9400b3SPaolo Bonzini } 434fd9400b3SPaolo Bonzini 4351ceef9f2SJason Wang for (i = queues - 1; i >= 0; i--) { 4361ceef9f2SJason Wang NetClientState *nc = qemu_get_subqueue(nic, i); 4371ceef9f2SJason Wang 438fd9400b3SPaolo Bonzini qemu_cleanup_net_client(nc); 439fd9400b3SPaolo Bonzini qemu_free_net_client(nc); 440fd9400b3SPaolo Bonzini } 441f6b26cf2SJason Wang 442f6b26cf2SJason Wang g_free(nic); 4431ceef9f2SJason Wang } 444fd9400b3SPaolo Bonzini 445fd9400b3SPaolo Bonzini void qemu_foreach_nic(qemu_nic_foreach func, void *opaque) 446fd9400b3SPaolo Bonzini { 447fd9400b3SPaolo Bonzini NetClientState *nc; 448fd9400b3SPaolo Bonzini 449fd9400b3SPaolo Bonzini QTAILQ_FOREACH(nc, &net_clients, next) { 450f394b2e2SEric Blake if (nc->info->type == NET_CLIENT_DRIVER_NIC) { 4511ceef9f2SJason Wang if (nc->queue_index == 0) { 452cc1f0f45SJason Wang func(qemu_get_nic(nc), opaque); 453fd9400b3SPaolo Bonzini } 454fd9400b3SPaolo Bonzini } 455fd9400b3SPaolo Bonzini } 4561ceef9f2SJason Wang } 457fd9400b3SPaolo Bonzini 458d6085e3aSStefan Hajnoczi bool qemu_has_ufo(NetClientState *nc) 4591f55ac45SVincenzo Maffione { 460d6085e3aSStefan Hajnoczi if (!nc || !nc->info->has_ufo) { 4611f55ac45SVincenzo Maffione return false; 4621f55ac45SVincenzo Maffione } 4631f55ac45SVincenzo Maffione 464d6085e3aSStefan Hajnoczi return nc->info->has_ufo(nc); 4651f55ac45SVincenzo Maffione } 4661f55ac45SVincenzo Maffione 467d6085e3aSStefan Hajnoczi bool qemu_has_vnet_hdr(NetClientState *nc) 4681f55ac45SVincenzo Maffione { 469d6085e3aSStefan Hajnoczi if (!nc || !nc->info->has_vnet_hdr) { 4701f55ac45SVincenzo Maffione return false; 4711f55ac45SVincenzo Maffione } 4721f55ac45SVincenzo Maffione 473d6085e3aSStefan Hajnoczi return nc->info->has_vnet_hdr(nc); 4741f55ac45SVincenzo Maffione } 4751f55ac45SVincenzo Maffione 476d6085e3aSStefan Hajnoczi bool qemu_has_vnet_hdr_len(NetClientState *nc, int len) 4771f55ac45SVincenzo Maffione { 478d6085e3aSStefan Hajnoczi if (!nc || !nc->info->has_vnet_hdr_len) { 4791f55ac45SVincenzo Maffione return false; 4801f55ac45SVincenzo Maffione } 4811f55ac45SVincenzo Maffione 482d6085e3aSStefan Hajnoczi return nc->info->has_vnet_hdr_len(nc, len); 4831f55ac45SVincenzo Maffione } 4841f55ac45SVincenzo Maffione 485d6085e3aSStefan Hajnoczi void qemu_using_vnet_hdr(NetClientState *nc, bool enable) 4861f55ac45SVincenzo Maffione { 487d6085e3aSStefan Hajnoczi if (!nc || !nc->info->using_vnet_hdr) { 4881f55ac45SVincenzo Maffione return; 4891f55ac45SVincenzo Maffione } 4901f55ac45SVincenzo Maffione 491d6085e3aSStefan Hajnoczi nc->info->using_vnet_hdr(nc, enable); 4921f55ac45SVincenzo Maffione } 4931f55ac45SVincenzo Maffione 494d6085e3aSStefan Hajnoczi void qemu_set_offload(NetClientState *nc, int csum, int tso4, int tso6, 4951f55ac45SVincenzo Maffione int ecn, int ufo) 4961f55ac45SVincenzo Maffione { 497d6085e3aSStefan Hajnoczi if (!nc || !nc->info->set_offload) { 4981f55ac45SVincenzo Maffione return; 4991f55ac45SVincenzo Maffione } 5001f55ac45SVincenzo Maffione 501d6085e3aSStefan Hajnoczi nc->info->set_offload(nc, csum, tso4, tso6, ecn, ufo); 5021f55ac45SVincenzo Maffione } 5031f55ac45SVincenzo Maffione 504d6085e3aSStefan Hajnoczi void qemu_set_vnet_hdr_len(NetClientState *nc, int len) 5051f55ac45SVincenzo Maffione { 506d6085e3aSStefan Hajnoczi if (!nc || !nc->info->set_vnet_hdr_len) { 5071f55ac45SVincenzo Maffione return; 5081f55ac45SVincenzo Maffione } 5091f55ac45SVincenzo Maffione 510d6b732e9SZhang Chen nc->vnet_hdr_len = len; 511d6085e3aSStefan Hajnoczi nc->info->set_vnet_hdr_len(nc, len); 5121f55ac45SVincenzo Maffione } 5131f55ac45SVincenzo Maffione 514c80cd6bbSGreg Kurz int qemu_set_vnet_le(NetClientState *nc, bool is_le) 515c80cd6bbSGreg Kurz { 516052bd52fSMichael S. Tsirkin #ifdef HOST_WORDS_BIGENDIAN 517c80cd6bbSGreg Kurz if (!nc || !nc->info->set_vnet_le) { 518c80cd6bbSGreg Kurz return -ENOSYS; 519c80cd6bbSGreg Kurz } 520c80cd6bbSGreg Kurz 521c80cd6bbSGreg Kurz return nc->info->set_vnet_le(nc, is_le); 522052bd52fSMichael S. Tsirkin #else 523052bd52fSMichael S. Tsirkin return 0; 524052bd52fSMichael S. Tsirkin #endif 525c80cd6bbSGreg Kurz } 526c80cd6bbSGreg Kurz 527c80cd6bbSGreg Kurz int qemu_set_vnet_be(NetClientState *nc, bool is_be) 528c80cd6bbSGreg Kurz { 529052bd52fSMichael S. Tsirkin #ifdef HOST_WORDS_BIGENDIAN 530052bd52fSMichael S. Tsirkin return 0; 531052bd52fSMichael S. Tsirkin #else 532c80cd6bbSGreg Kurz if (!nc || !nc->info->set_vnet_be) { 533c80cd6bbSGreg Kurz return -ENOSYS; 534c80cd6bbSGreg Kurz } 535c80cd6bbSGreg Kurz 536c80cd6bbSGreg Kurz return nc->info->set_vnet_be(nc, is_be); 537052bd52fSMichael S. Tsirkin #endif 538c80cd6bbSGreg Kurz } 539c80cd6bbSGreg Kurz 540fd9400b3SPaolo Bonzini int qemu_can_send_packet(NetClientState *sender) 541fd9400b3SPaolo Bonzini { 542e1d64c08Szhanghailiang int vm_running = runstate_is_running(); 543e1d64c08Szhanghailiang 544e1d64c08Szhanghailiang if (!vm_running) { 545e1d64c08Szhanghailiang return 0; 546e1d64c08Szhanghailiang } 547e1d64c08Szhanghailiang 548fd9400b3SPaolo Bonzini if (!sender->peer) { 549fd9400b3SPaolo Bonzini return 1; 550fd9400b3SPaolo Bonzini } 551fd9400b3SPaolo Bonzini 552fd9400b3SPaolo Bonzini if (sender->peer->receive_disabled) { 553fd9400b3SPaolo Bonzini return 0; 554fd9400b3SPaolo Bonzini } else if (sender->peer->info->can_receive && 555fd9400b3SPaolo Bonzini !sender->peer->info->can_receive(sender->peer)) { 556fd9400b3SPaolo Bonzini return 0; 557fd9400b3SPaolo Bonzini } 558fd9400b3SPaolo Bonzini return 1; 559fd9400b3SPaolo Bonzini } 560fd9400b3SPaolo Bonzini 561e64c770dSYang Hongyang static ssize_t filter_receive_iov(NetClientState *nc, 562e64c770dSYang Hongyang NetFilterDirection direction, 563e64c770dSYang Hongyang NetClientState *sender, 564e64c770dSYang Hongyang unsigned flags, 565e64c770dSYang Hongyang const struct iovec *iov, 566e64c770dSYang Hongyang int iovcnt, 567e64c770dSYang Hongyang NetPacketSent *sent_cb) 568e64c770dSYang Hongyang { 569e64c770dSYang Hongyang ssize_t ret = 0; 570e64c770dSYang Hongyang NetFilterState *nf = NULL; 571e64c770dSYang Hongyang 57225aaadf0SLi Zhijian if (direction == NET_FILTER_DIRECTION_TX) { 573e64c770dSYang Hongyang QTAILQ_FOREACH(nf, &nc->filters, next) { 574e64c770dSYang Hongyang ret = qemu_netfilter_receive(nf, direction, sender, flags, iov, 575e64c770dSYang Hongyang iovcnt, sent_cb); 576e64c770dSYang Hongyang if (ret) { 577e64c770dSYang Hongyang return ret; 578e64c770dSYang Hongyang } 579e64c770dSYang Hongyang } 58025aaadf0SLi Zhijian } else { 58125aaadf0SLi Zhijian QTAILQ_FOREACH_REVERSE(nf, &nc->filters, NetFilterHead, next) { 58225aaadf0SLi Zhijian ret = qemu_netfilter_receive(nf, direction, sender, flags, iov, 58325aaadf0SLi Zhijian iovcnt, sent_cb); 58425aaadf0SLi Zhijian if (ret) { 58525aaadf0SLi Zhijian return ret; 58625aaadf0SLi Zhijian } 58725aaadf0SLi Zhijian } 58825aaadf0SLi Zhijian } 589e64c770dSYang Hongyang 590e64c770dSYang Hongyang return ret; 591e64c770dSYang Hongyang } 592e64c770dSYang Hongyang 593e64c770dSYang Hongyang static ssize_t filter_receive(NetClientState *nc, 594e64c770dSYang Hongyang NetFilterDirection direction, 595e64c770dSYang Hongyang NetClientState *sender, 596e64c770dSYang Hongyang unsigned flags, 597e64c770dSYang Hongyang const uint8_t *data, 598e64c770dSYang Hongyang size_t size, 599e64c770dSYang Hongyang NetPacketSent *sent_cb) 600e64c770dSYang Hongyang { 601e64c770dSYang Hongyang struct iovec iov = { 602e64c770dSYang Hongyang .iov_base = (void *)data, 603e64c770dSYang Hongyang .iov_len = size 604e64c770dSYang Hongyang }; 605e64c770dSYang Hongyang 606e64c770dSYang Hongyang return filter_receive_iov(nc, direction, sender, flags, &iov, 1, sent_cb); 607e64c770dSYang Hongyang } 608e64c770dSYang Hongyang 609fd9400b3SPaolo Bonzini void qemu_purge_queued_packets(NetClientState *nc) 610fd9400b3SPaolo Bonzini { 611fd9400b3SPaolo Bonzini if (!nc->peer) { 612fd9400b3SPaolo Bonzini return; 613fd9400b3SPaolo Bonzini } 614fd9400b3SPaolo Bonzini 615067404beSJan Kiszka qemu_net_queue_purge(nc->peer->incoming_queue, nc); 616fd9400b3SPaolo Bonzini } 617fd9400b3SPaolo Bonzini 618ca77d85eSMichael S. Tsirkin static 619ca77d85eSMichael S. Tsirkin void qemu_flush_or_purge_queued_packets(NetClientState *nc, bool purge) 620fd9400b3SPaolo Bonzini { 621fd9400b3SPaolo Bonzini nc->receive_disabled = 0; 622fd9400b3SPaolo Bonzini 623f394b2e2SEric Blake if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_HUBPORT) { 624199ee608SLuigi Rizzo if (net_hub_flush(nc->peer)) { 625199ee608SLuigi Rizzo qemu_notify_event(); 626199ee608SLuigi Rizzo } 627199ee608SLuigi Rizzo } 628067404beSJan Kiszka if (qemu_net_queue_flush(nc->incoming_queue)) { 629fd9400b3SPaolo Bonzini /* We emptied the queue successfully, signal to the IO thread to repoll 630fd9400b3SPaolo Bonzini * the file descriptor (for tap, for example). 631fd9400b3SPaolo Bonzini */ 632fd9400b3SPaolo Bonzini qemu_notify_event(); 633ca77d85eSMichael S. Tsirkin } else if (purge) { 634ca77d85eSMichael S. Tsirkin /* Unable to empty the queue, purge remaining packets */ 635ca77d85eSMichael S. Tsirkin qemu_net_queue_purge(nc->incoming_queue, nc); 636fd9400b3SPaolo Bonzini } 637fd9400b3SPaolo Bonzini } 638fd9400b3SPaolo Bonzini 639ca77d85eSMichael S. Tsirkin void qemu_flush_queued_packets(NetClientState *nc) 640ca77d85eSMichael S. Tsirkin { 641ca77d85eSMichael S. Tsirkin qemu_flush_or_purge_queued_packets(nc, false); 642ca77d85eSMichael S. Tsirkin } 643ca77d85eSMichael S. Tsirkin 644fd9400b3SPaolo Bonzini static ssize_t qemu_send_packet_async_with_flags(NetClientState *sender, 645fd9400b3SPaolo Bonzini unsigned flags, 646fd9400b3SPaolo Bonzini const uint8_t *buf, int size, 647fd9400b3SPaolo Bonzini NetPacketSent *sent_cb) 648fd9400b3SPaolo Bonzini { 649fd9400b3SPaolo Bonzini NetQueue *queue; 650e64c770dSYang Hongyang int ret; 651fd9400b3SPaolo Bonzini 652fd9400b3SPaolo Bonzini #ifdef DEBUG_NET 653fd9400b3SPaolo Bonzini printf("qemu_send_packet_async:\n"); 654a1555559SIsaac Lozano qemu_hexdump((const char *)buf, stdout, "net", size); 655fd9400b3SPaolo Bonzini #endif 656fd9400b3SPaolo Bonzini 657fd9400b3SPaolo Bonzini if (sender->link_down || !sender->peer) { 658fd9400b3SPaolo Bonzini return size; 659fd9400b3SPaolo Bonzini } 660fd9400b3SPaolo Bonzini 661e64c770dSYang Hongyang /* Let filters handle the packet first */ 662e64c770dSYang Hongyang ret = filter_receive(sender, NET_FILTER_DIRECTION_TX, 663e64c770dSYang Hongyang sender, flags, buf, size, sent_cb); 664e64c770dSYang Hongyang if (ret) { 665e64c770dSYang Hongyang return ret; 666e64c770dSYang Hongyang } 667e64c770dSYang Hongyang 668e64c770dSYang Hongyang ret = filter_receive(sender->peer, NET_FILTER_DIRECTION_RX, 669e64c770dSYang Hongyang sender, flags, buf, size, sent_cb); 670e64c770dSYang Hongyang if (ret) { 671e64c770dSYang Hongyang return ret; 672e64c770dSYang Hongyang } 673e64c770dSYang Hongyang 674067404beSJan Kiszka queue = sender->peer->incoming_queue; 675fd9400b3SPaolo Bonzini 676fd9400b3SPaolo Bonzini return qemu_net_queue_send(queue, sender, flags, buf, size, sent_cb); 677fd9400b3SPaolo Bonzini } 678fd9400b3SPaolo Bonzini 679fd9400b3SPaolo Bonzini ssize_t qemu_send_packet_async(NetClientState *sender, 680fd9400b3SPaolo Bonzini const uint8_t *buf, int size, 681fd9400b3SPaolo Bonzini NetPacketSent *sent_cb) 682fd9400b3SPaolo Bonzini { 683fd9400b3SPaolo Bonzini return qemu_send_packet_async_with_flags(sender, QEMU_NET_PACKET_FLAG_NONE, 684fd9400b3SPaolo Bonzini buf, size, sent_cb); 685fd9400b3SPaolo Bonzini } 686fd9400b3SPaolo Bonzini 687fd9400b3SPaolo Bonzini void qemu_send_packet(NetClientState *nc, const uint8_t *buf, int size) 688fd9400b3SPaolo Bonzini { 689fd9400b3SPaolo Bonzini qemu_send_packet_async(nc, buf, size, NULL); 690fd9400b3SPaolo Bonzini } 691fd9400b3SPaolo Bonzini 692fd9400b3SPaolo Bonzini ssize_t qemu_send_packet_raw(NetClientState *nc, const uint8_t *buf, int size) 693fd9400b3SPaolo Bonzini { 694fd9400b3SPaolo Bonzini return qemu_send_packet_async_with_flags(nc, QEMU_NET_PACKET_FLAG_RAW, 695fd9400b3SPaolo Bonzini buf, size, NULL); 696fd9400b3SPaolo Bonzini } 697fd9400b3SPaolo Bonzini 698fd9400b3SPaolo Bonzini static ssize_t nc_sendv_compat(NetClientState *nc, const struct iovec *iov, 699fefe2a78SYang Hongyang int iovcnt, unsigned flags) 700fd9400b3SPaolo Bonzini { 70174044c8fSPooja Dhannawat uint8_t *buf = NULL; 702fefe2a78SYang Hongyang uint8_t *buffer; 703fd9400b3SPaolo Bonzini size_t offset; 70474044c8fSPooja Dhannawat ssize_t ret; 705fd9400b3SPaolo Bonzini 706fefe2a78SYang Hongyang if (iovcnt == 1) { 707fefe2a78SYang Hongyang buffer = iov[0].iov_base; 708fefe2a78SYang Hongyang offset = iov[0].iov_len; 709fefe2a78SYang Hongyang } else { 71047f9f158SPeter Lieven offset = iov_size(iov, iovcnt); 71147f9f158SPeter Lieven if (offset > NET_BUFSIZE) { 71247f9f158SPeter Lieven return -1; 71347f9f158SPeter Lieven } 71447f9f158SPeter Lieven buf = g_malloc(offset); 715fefe2a78SYang Hongyang buffer = buf; 71647f9f158SPeter Lieven offset = iov_to_buf(iov, iovcnt, 0, buf, offset); 717fefe2a78SYang Hongyang } 718fd9400b3SPaolo Bonzini 719fefe2a78SYang Hongyang if (flags & QEMU_NET_PACKET_FLAG_RAW && nc->info->receive_raw) { 72074044c8fSPooja Dhannawat ret = nc->info->receive_raw(nc, buffer, offset); 721fefe2a78SYang Hongyang } else { 72274044c8fSPooja Dhannawat ret = nc->info->receive(nc, buffer, offset); 723fd9400b3SPaolo Bonzini } 72474044c8fSPooja Dhannawat 72574044c8fSPooja Dhannawat g_free(buf); 72674044c8fSPooja Dhannawat return ret; 727fefe2a78SYang Hongyang } 728fd9400b3SPaolo Bonzini 729fd9400b3SPaolo Bonzini ssize_t qemu_deliver_packet_iov(NetClientState *sender, 730fd9400b3SPaolo Bonzini unsigned flags, 731fd9400b3SPaolo Bonzini const struct iovec *iov, 732fd9400b3SPaolo Bonzini int iovcnt, 733fd9400b3SPaolo Bonzini void *opaque) 734fd9400b3SPaolo Bonzini { 735fd9400b3SPaolo Bonzini NetClientState *nc = opaque; 736fd9400b3SPaolo Bonzini int ret; 737fd9400b3SPaolo Bonzini 738fd9400b3SPaolo Bonzini if (nc->link_down) { 739fd9400b3SPaolo Bonzini return iov_size(iov, iovcnt); 740fd9400b3SPaolo Bonzini } 741fd9400b3SPaolo Bonzini 742fd9400b3SPaolo Bonzini if (nc->receive_disabled) { 743fd9400b3SPaolo Bonzini return 0; 744fd9400b3SPaolo Bonzini } 745fd9400b3SPaolo Bonzini 746ca1ee3d6SPeter Lieven if (nc->info->receive_iov && !(flags & QEMU_NET_PACKET_FLAG_RAW)) { 747fd9400b3SPaolo Bonzini ret = nc->info->receive_iov(nc, iov, iovcnt); 748fd9400b3SPaolo Bonzini } else { 749fefe2a78SYang Hongyang ret = nc_sendv_compat(nc, iov, iovcnt, flags); 750fd9400b3SPaolo Bonzini } 751fd9400b3SPaolo Bonzini 752fd9400b3SPaolo Bonzini if (ret == 0) { 753fd9400b3SPaolo Bonzini nc->receive_disabled = 1; 754fd9400b3SPaolo Bonzini } 755fd9400b3SPaolo Bonzini 756fd9400b3SPaolo Bonzini return ret; 757fd9400b3SPaolo Bonzini } 758fd9400b3SPaolo Bonzini 759fd9400b3SPaolo Bonzini ssize_t qemu_sendv_packet_async(NetClientState *sender, 760fd9400b3SPaolo Bonzini const struct iovec *iov, int iovcnt, 761fd9400b3SPaolo Bonzini NetPacketSent *sent_cb) 762fd9400b3SPaolo Bonzini { 763fd9400b3SPaolo Bonzini NetQueue *queue; 764e64c770dSYang Hongyang int ret; 765fd9400b3SPaolo Bonzini 766fd9400b3SPaolo Bonzini if (sender->link_down || !sender->peer) { 767fd9400b3SPaolo Bonzini return iov_size(iov, iovcnt); 768fd9400b3SPaolo Bonzini } 769fd9400b3SPaolo Bonzini 770e64c770dSYang Hongyang /* Let filters handle the packet first */ 771e64c770dSYang Hongyang ret = filter_receive_iov(sender, NET_FILTER_DIRECTION_TX, sender, 772e64c770dSYang Hongyang QEMU_NET_PACKET_FLAG_NONE, iov, iovcnt, sent_cb); 773e64c770dSYang Hongyang if (ret) { 774e64c770dSYang Hongyang return ret; 775e64c770dSYang Hongyang } 776e64c770dSYang Hongyang 777e64c770dSYang Hongyang ret = filter_receive_iov(sender->peer, NET_FILTER_DIRECTION_RX, sender, 778e64c770dSYang Hongyang QEMU_NET_PACKET_FLAG_NONE, iov, iovcnt, sent_cb); 779e64c770dSYang Hongyang if (ret) { 780e64c770dSYang Hongyang return ret; 781e64c770dSYang Hongyang } 782e64c770dSYang Hongyang 783067404beSJan Kiszka queue = sender->peer->incoming_queue; 784fd9400b3SPaolo Bonzini 785fd9400b3SPaolo Bonzini return qemu_net_queue_send_iov(queue, sender, 786fd9400b3SPaolo Bonzini QEMU_NET_PACKET_FLAG_NONE, 787fd9400b3SPaolo Bonzini iov, iovcnt, sent_cb); 788fd9400b3SPaolo Bonzini } 789fd9400b3SPaolo Bonzini 790fd9400b3SPaolo Bonzini ssize_t 791fd9400b3SPaolo Bonzini qemu_sendv_packet(NetClientState *nc, const struct iovec *iov, int iovcnt) 792fd9400b3SPaolo Bonzini { 793fd9400b3SPaolo Bonzini return qemu_sendv_packet_async(nc, iov, iovcnt, NULL); 794fd9400b3SPaolo Bonzini } 795fd9400b3SPaolo Bonzini 796fd9400b3SPaolo Bonzini NetClientState *qemu_find_netdev(const char *id) 797fd9400b3SPaolo Bonzini { 798fd9400b3SPaolo Bonzini NetClientState *nc; 799fd9400b3SPaolo Bonzini 800fd9400b3SPaolo Bonzini QTAILQ_FOREACH(nc, &net_clients, next) { 801f394b2e2SEric Blake if (nc->info->type == NET_CLIENT_DRIVER_NIC) 802fd9400b3SPaolo Bonzini continue; 803fd9400b3SPaolo Bonzini if (!strcmp(nc->name, id)) { 804fd9400b3SPaolo Bonzini return nc; 805fd9400b3SPaolo Bonzini } 806fd9400b3SPaolo Bonzini } 807fd9400b3SPaolo Bonzini 808fd9400b3SPaolo Bonzini return NULL; 809fd9400b3SPaolo Bonzini } 810fd9400b3SPaolo Bonzini 8116c51ae73SJason Wang int qemu_find_net_clients_except(const char *id, NetClientState **ncs, 812f394b2e2SEric Blake NetClientDriver type, int max) 8136c51ae73SJason Wang { 8146c51ae73SJason Wang NetClientState *nc; 8156c51ae73SJason Wang int ret = 0; 8166c51ae73SJason Wang 8176c51ae73SJason Wang QTAILQ_FOREACH(nc, &net_clients, next) { 8186c51ae73SJason Wang if (nc->info->type == type) { 8196c51ae73SJason Wang continue; 8206c51ae73SJason Wang } 82140d19394SHani Benhabiles if (!id || !strcmp(nc->name, id)) { 8226c51ae73SJason Wang if (ret < max) { 8236c51ae73SJason Wang ncs[ret] = nc; 8246c51ae73SJason Wang } 8256c51ae73SJason Wang ret++; 8266c51ae73SJason Wang } 8276c51ae73SJason Wang } 8286c51ae73SJason Wang 8296c51ae73SJason Wang return ret; 8306c51ae73SJason Wang } 8316c51ae73SJason Wang 832fd9400b3SPaolo Bonzini static int nic_get_free_idx(void) 833fd9400b3SPaolo Bonzini { 834fd9400b3SPaolo Bonzini int index; 835fd9400b3SPaolo Bonzini 836fd9400b3SPaolo Bonzini for (index = 0; index < MAX_NICS; index++) 837fd9400b3SPaolo Bonzini if (!nd_table[index].used) 838fd9400b3SPaolo Bonzini return index; 839fd9400b3SPaolo Bonzini return -1; 840fd9400b3SPaolo Bonzini } 841fd9400b3SPaolo Bonzini 842fd9400b3SPaolo Bonzini int qemu_show_nic_models(const char *arg, const char *const *models) 843fd9400b3SPaolo Bonzini { 844fd9400b3SPaolo Bonzini int i; 845fd9400b3SPaolo Bonzini 846fd9400b3SPaolo Bonzini if (!arg || !is_help_option(arg)) { 847fd9400b3SPaolo Bonzini return 0; 848fd9400b3SPaolo Bonzini } 849fd9400b3SPaolo Bonzini 850fd9400b3SPaolo Bonzini fprintf(stderr, "qemu: Supported NIC models: "); 851fd9400b3SPaolo Bonzini for (i = 0 ; models[i]; i++) 852fd9400b3SPaolo Bonzini fprintf(stderr, "%s%c", models[i], models[i+1] ? ',' : '\n'); 853fd9400b3SPaolo Bonzini return 1; 854fd9400b3SPaolo Bonzini } 855fd9400b3SPaolo Bonzini 856fd9400b3SPaolo Bonzini void qemu_check_nic_model(NICInfo *nd, const char *model) 857fd9400b3SPaolo Bonzini { 858fd9400b3SPaolo Bonzini const char *models[2]; 859fd9400b3SPaolo Bonzini 860fd9400b3SPaolo Bonzini models[0] = model; 861fd9400b3SPaolo Bonzini models[1] = NULL; 862fd9400b3SPaolo Bonzini 863fd9400b3SPaolo Bonzini if (qemu_show_nic_models(nd->model, models)) 864fd9400b3SPaolo Bonzini exit(0); 865fd9400b3SPaolo Bonzini if (qemu_find_nic_model(nd, models, model) < 0) 866fd9400b3SPaolo Bonzini exit(1); 867fd9400b3SPaolo Bonzini } 868fd9400b3SPaolo Bonzini 869fd9400b3SPaolo Bonzini int qemu_find_nic_model(NICInfo *nd, const char * const *models, 870fd9400b3SPaolo Bonzini const char *default_model) 871fd9400b3SPaolo Bonzini { 872fd9400b3SPaolo Bonzini int i; 873fd9400b3SPaolo Bonzini 874fd9400b3SPaolo Bonzini if (!nd->model) 875fd9400b3SPaolo Bonzini nd->model = g_strdup(default_model); 876fd9400b3SPaolo Bonzini 877fd9400b3SPaolo Bonzini for (i = 0 ; models[i]; i++) { 878fd9400b3SPaolo Bonzini if (strcmp(nd->model, models[i]) == 0) 879fd9400b3SPaolo Bonzini return i; 880fd9400b3SPaolo Bonzini } 881fd9400b3SPaolo Bonzini 882fd9400b3SPaolo Bonzini error_report("Unsupported NIC model: %s", nd->model); 883fd9400b3SPaolo Bonzini return -1; 884fd9400b3SPaolo Bonzini } 885fd9400b3SPaolo Bonzini 886cebea510SKővágó, Zoltán static int net_init_nic(const Netdev *netdev, const char *name, 887a30ecde6SMarkus Armbruster NetClientState *peer, Error **errp) 888fd9400b3SPaolo Bonzini { 889fd9400b3SPaolo Bonzini int idx; 890fd9400b3SPaolo Bonzini NICInfo *nd; 891fd9400b3SPaolo Bonzini const NetLegacyNicOptions *nic; 892fd9400b3SPaolo Bonzini 893f394b2e2SEric Blake assert(netdev->type == NET_CLIENT_DRIVER_NIC); 894f394b2e2SEric Blake nic = &netdev->u.nic; 895fd9400b3SPaolo Bonzini 896fd9400b3SPaolo Bonzini idx = nic_get_free_idx(); 897fd9400b3SPaolo Bonzini if (idx == -1 || nb_nics >= MAX_NICS) { 89866308868SMarkus Armbruster error_setg(errp, "too many NICs"); 899fd9400b3SPaolo Bonzini return -1; 900fd9400b3SPaolo Bonzini } 901fd9400b3SPaolo Bonzini 902fd9400b3SPaolo Bonzini nd = &nd_table[idx]; 903fd9400b3SPaolo Bonzini 904fd9400b3SPaolo Bonzini memset(nd, 0, sizeof(*nd)); 905fd9400b3SPaolo Bonzini 906fd9400b3SPaolo Bonzini if (nic->has_netdev) { 907fd9400b3SPaolo Bonzini nd->netdev = qemu_find_netdev(nic->netdev); 908fd9400b3SPaolo Bonzini if (!nd->netdev) { 90966308868SMarkus Armbruster error_setg(errp, "netdev '%s' not found", nic->netdev); 910fd9400b3SPaolo Bonzini return -1; 911fd9400b3SPaolo Bonzini } 912fd9400b3SPaolo Bonzini } else { 913fd9400b3SPaolo Bonzini assert(peer); 914fd9400b3SPaolo Bonzini nd->netdev = peer; 915fd9400b3SPaolo Bonzini } 916fd9400b3SPaolo Bonzini nd->name = g_strdup(name); 917fd9400b3SPaolo Bonzini if (nic->has_model) { 918fd9400b3SPaolo Bonzini nd->model = g_strdup(nic->model); 919fd9400b3SPaolo Bonzini } 920fd9400b3SPaolo Bonzini if (nic->has_addr) { 921fd9400b3SPaolo Bonzini nd->devaddr = g_strdup(nic->addr); 922fd9400b3SPaolo Bonzini } 923fd9400b3SPaolo Bonzini 924fd9400b3SPaolo Bonzini if (nic->has_macaddr && 925fd9400b3SPaolo Bonzini net_parse_macaddr(nd->macaddr.a, nic->macaddr) < 0) { 92666308868SMarkus Armbruster error_setg(errp, "invalid syntax for ethernet address"); 927fd9400b3SPaolo Bonzini return -1; 928fd9400b3SPaolo Bonzini } 929d60b20cfSDmitry Krivenok if (nic->has_macaddr && 930d60b20cfSDmitry Krivenok is_multicast_ether_addr(nd->macaddr.a)) { 93166308868SMarkus Armbruster error_setg(errp, 93266308868SMarkus Armbruster "NIC cannot have multicast MAC address (odd 1st byte)"); 933d60b20cfSDmitry Krivenok return -1; 934d60b20cfSDmitry Krivenok } 935fd9400b3SPaolo Bonzini qemu_macaddr_default_if_unset(&nd->macaddr); 936fd9400b3SPaolo Bonzini 937fd9400b3SPaolo Bonzini if (nic->has_vectors) { 938fd9400b3SPaolo Bonzini if (nic->vectors > 0x7ffffff) { 93966308868SMarkus Armbruster error_setg(errp, "invalid # of vectors: %"PRIu32, nic->vectors); 940fd9400b3SPaolo Bonzini return -1; 941fd9400b3SPaolo Bonzini } 942fd9400b3SPaolo Bonzini nd->nvectors = nic->vectors; 943fd9400b3SPaolo Bonzini } else { 944fd9400b3SPaolo Bonzini nd->nvectors = DEV_NVECTORS_UNSPECIFIED; 945fd9400b3SPaolo Bonzini } 946fd9400b3SPaolo Bonzini 947fd9400b3SPaolo Bonzini nd->used = 1; 948fd9400b3SPaolo Bonzini nb_nics++; 949fd9400b3SPaolo Bonzini 950fd9400b3SPaolo Bonzini return idx; 951fd9400b3SPaolo Bonzini } 952fd9400b3SPaolo Bonzini 953fd9400b3SPaolo Bonzini 954f394b2e2SEric Blake static int (* const net_client_init_fun[NET_CLIENT_DRIVER__MAX])( 955cebea510SKővágó, Zoltán const Netdev *netdev, 956fd9400b3SPaolo Bonzini const char *name, 957a30ecde6SMarkus Armbruster NetClientState *peer, Error **errp) = { 958f394b2e2SEric Blake [NET_CLIENT_DRIVER_NIC] = net_init_nic, 959fd9400b3SPaolo Bonzini #ifdef CONFIG_SLIRP 960f394b2e2SEric Blake [NET_CLIENT_DRIVER_USER] = net_init_slirp, 961fd9400b3SPaolo Bonzini #endif 962f394b2e2SEric Blake [NET_CLIENT_DRIVER_TAP] = net_init_tap, 963f394b2e2SEric Blake [NET_CLIENT_DRIVER_SOCKET] = net_init_socket, 964fd9400b3SPaolo Bonzini #ifdef CONFIG_VDE 965f394b2e2SEric Blake [NET_CLIENT_DRIVER_VDE] = net_init_vde, 966fd9400b3SPaolo Bonzini #endif 96758952137SVincenzo Maffione #ifdef CONFIG_NETMAP 968f394b2e2SEric Blake [NET_CLIENT_DRIVER_NETMAP] = net_init_netmap, 96958952137SVincenzo Maffione #endif 970f394b2e2SEric Blake [NET_CLIENT_DRIVER_DUMP] = net_init_dump, 971fd9400b3SPaolo Bonzini #ifdef CONFIG_NET_BRIDGE 972f394b2e2SEric Blake [NET_CLIENT_DRIVER_BRIDGE] = net_init_bridge, 973fd9400b3SPaolo Bonzini #endif 974f394b2e2SEric Blake [NET_CLIENT_DRIVER_HUBPORT] = net_init_hubport, 97503ce5744SNikolay Nikolaev #ifdef CONFIG_VHOST_NET_USED 976f394b2e2SEric Blake [NET_CLIENT_DRIVER_VHOST_USER] = net_init_vhost_user, 97703ce5744SNikolay Nikolaev #endif 978015a33bdSGonglei #ifdef CONFIG_L2TPV3 979f394b2e2SEric Blake [NET_CLIENT_DRIVER_L2TPV3] = net_init_l2tpv3, 9803fb69aa1SAnton Ivanov #endif 981fd9400b3SPaolo Bonzini }; 982fd9400b3SPaolo Bonzini 983fd9400b3SPaolo Bonzini 9840e55c381SEric Blake static int net_client_init1(const void *object, bool is_netdev, Error **errp) 985fd9400b3SPaolo Bonzini { 986cebea510SKővágó, Zoltán Netdev legacy = {0}; 987cebea510SKővágó, Zoltán const Netdev *netdev; 988fd9400b3SPaolo Bonzini const char *name; 9894ef0defbSStefan Hajnoczi NetClientState *peer = NULL; 990a2dbe135SThomas Huth static bool vlan_warned; 991fd9400b3SPaolo Bonzini 992fd9400b3SPaolo Bonzini if (is_netdev) { 993cebea510SKővágó, Zoltán netdev = object; 9941e81aba5SStefan Hajnoczi name = netdev->id; 995fd9400b3SPaolo Bonzini 996f394b2e2SEric Blake if (netdev->type == NET_CLIENT_DRIVER_DUMP || 997f394b2e2SEric Blake netdev->type == NET_CLIENT_DRIVER_NIC || 998f394b2e2SEric Blake !net_client_init_fun[netdev->type]) { 999c6bd8c70SMarkus Armbruster error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "type", 1000fd9400b3SPaolo Bonzini "a netdev backend type"); 1001fd9400b3SPaolo Bonzini return -1; 1002fd9400b3SPaolo Bonzini } 1003fd9400b3SPaolo Bonzini } else { 10041e81aba5SStefan Hajnoczi const NetLegacy *net = object; 1005f394b2e2SEric Blake const NetLegacyOptions *opts = net->opts; 1006cebea510SKővágó, Zoltán legacy.id = net->id; 1007cebea510SKővágó, Zoltán netdev = &legacy; 10081e81aba5SStefan Hajnoczi /* missing optional values have been initialized to "all bits zero" */ 10091e81aba5SStefan Hajnoczi name = net->has_id ? net->id : net->name; 10101e81aba5SStefan Hajnoczi 1011f394b2e2SEric Blake /* Map the old options to the new flat type */ 1012f394b2e2SEric Blake switch (opts->type) { 1013d3be4b57SMarkus Armbruster case NET_LEGACY_OPTIONS_TYPE_NONE: 10141e81aba5SStefan Hajnoczi return 0; /* nothing to do */ 1015d3be4b57SMarkus Armbruster case NET_LEGACY_OPTIONS_TYPE_NIC: 1016f394b2e2SEric Blake legacy.type = NET_CLIENT_DRIVER_NIC; 1017d3be4b57SMarkus Armbruster legacy.u.nic = opts->u.nic; 1018f394b2e2SEric Blake break; 1019d3be4b57SMarkus Armbruster case NET_LEGACY_OPTIONS_TYPE_USER: 1020f394b2e2SEric Blake legacy.type = NET_CLIENT_DRIVER_USER; 1021d3be4b57SMarkus Armbruster legacy.u.user = opts->u.user; 1022f394b2e2SEric Blake break; 1023d3be4b57SMarkus Armbruster case NET_LEGACY_OPTIONS_TYPE_TAP: 1024f394b2e2SEric Blake legacy.type = NET_CLIENT_DRIVER_TAP; 1025d3be4b57SMarkus Armbruster legacy.u.tap = opts->u.tap; 1026f394b2e2SEric Blake break; 1027d3be4b57SMarkus Armbruster case NET_LEGACY_OPTIONS_TYPE_L2TPV3: 1028f394b2e2SEric Blake legacy.type = NET_CLIENT_DRIVER_L2TPV3; 1029d3be4b57SMarkus Armbruster legacy.u.l2tpv3 = opts->u.l2tpv3; 1030f394b2e2SEric Blake break; 1031d3be4b57SMarkus Armbruster case NET_LEGACY_OPTIONS_TYPE_SOCKET: 1032f394b2e2SEric Blake legacy.type = NET_CLIENT_DRIVER_SOCKET; 1033d3be4b57SMarkus Armbruster legacy.u.socket = opts->u.socket; 1034f394b2e2SEric Blake break; 1035d3be4b57SMarkus Armbruster case NET_LEGACY_OPTIONS_TYPE_VDE: 1036f394b2e2SEric Blake legacy.type = NET_CLIENT_DRIVER_VDE; 1037d3be4b57SMarkus Armbruster legacy.u.vde = opts->u.vde; 1038f394b2e2SEric Blake break; 1039d3be4b57SMarkus Armbruster case NET_LEGACY_OPTIONS_TYPE_DUMP: 1040f394b2e2SEric Blake legacy.type = NET_CLIENT_DRIVER_DUMP; 1041d3be4b57SMarkus Armbruster legacy.u.dump = opts->u.dump; 1042f394b2e2SEric Blake break; 1043d3be4b57SMarkus Armbruster case NET_LEGACY_OPTIONS_TYPE_BRIDGE: 1044f394b2e2SEric Blake legacy.type = NET_CLIENT_DRIVER_BRIDGE; 1045d3be4b57SMarkus Armbruster legacy.u.bridge = opts->u.bridge; 1046f394b2e2SEric Blake break; 1047d3be4b57SMarkus Armbruster case NET_LEGACY_OPTIONS_TYPE_NETMAP: 1048f394b2e2SEric Blake legacy.type = NET_CLIENT_DRIVER_NETMAP; 1049d3be4b57SMarkus Armbruster legacy.u.netmap = opts->u.netmap; 1050f394b2e2SEric Blake break; 1051d3be4b57SMarkus Armbruster case NET_LEGACY_OPTIONS_TYPE_VHOST_USER: 1052f394b2e2SEric Blake legacy.type = NET_CLIENT_DRIVER_VHOST_USER; 1053d3be4b57SMarkus Armbruster legacy.u.vhost_user = opts->u.vhost_user; 1054f394b2e2SEric Blake break; 1055f394b2e2SEric Blake default: 1056f394b2e2SEric Blake abort(); 1057ca7eb184SMarkus Armbruster } 1058d139e9a6SStefan Hajnoczi 1059f394b2e2SEric Blake if (!net_client_init_fun[netdev->type]) { 1060d139e9a6SStefan Hajnoczi error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "type", 1061d139e9a6SStefan Hajnoczi "a net backend type (maybe it is not compiled " 1062d139e9a6SStefan Hajnoczi "into this binary)"); 1063d139e9a6SStefan Hajnoczi return -1; 1064d139e9a6SStefan Hajnoczi } 1065fd9400b3SPaolo Bonzini 10661e81aba5SStefan Hajnoczi /* Do not add to a vlan if it's a nic with a netdev= parameter. */ 1067f394b2e2SEric Blake if (netdev->type != NET_CLIENT_DRIVER_NIC || 1068d3be4b57SMarkus Armbruster !opts->u.nic.has_netdev) { 106918d65d22SThomas Huth peer = net_hub_add_port(net->has_vlan ? net->vlan : 0, NULL, NULL); 10701e81aba5SStefan Hajnoczi } 1071a2dbe135SThomas Huth 1072a2dbe135SThomas Huth if (net->has_vlan && !vlan_warned) { 1073a2dbe135SThomas Huth error_report("'vlan' is deprecated. Please use 'netdev' instead."); 1074a2dbe135SThomas Huth vlan_warned = true; 1075a2dbe135SThomas Huth } 1076fd9400b3SPaolo Bonzini } 1077fd9400b3SPaolo Bonzini 1078f394b2e2SEric Blake if (net_client_init_fun[netdev->type](netdev, name, peer, errp) < 0) { 1079a30ecde6SMarkus Armbruster /* FIXME drop when all init functions store an Error */ 1080a30ecde6SMarkus Armbruster if (errp && !*errp) { 1081c6bd8c70SMarkus Armbruster error_setg(errp, QERR_DEVICE_INIT_FAILED, 1082977c736fSMarkus Armbruster NetClientDriver_str(netdev->type)); 1083a30ecde6SMarkus Armbruster } 1084fd9400b3SPaolo Bonzini return -1; 1085fd9400b3SPaolo Bonzini } 1086fd9400b3SPaolo Bonzini return 0; 1087fd9400b3SPaolo Bonzini } 1088fd9400b3SPaolo Bonzini 1089fd9400b3SPaolo Bonzini 10900e55c381SEric Blake int net_client_init(QemuOpts *opts, bool is_netdev, Error **errp) 1091fd9400b3SPaolo Bonzini { 1092fd9400b3SPaolo Bonzini void *object = NULL; 1093fd9400b3SPaolo Bonzini Error *err = NULL; 1094fd9400b3SPaolo Bonzini int ret = -1; 109509204eacSEric Blake Visitor *v = opts_visitor_new(opts); 1096fd9400b3SPaolo Bonzini 10977aac531eSYann Bordenave { 10987aac531eSYann Bordenave /* Parse convenience option format ip6-net=fec0::0[/64] */ 1099891a2bb5SSamuel Thibault const char *ip6_net = qemu_opt_get(opts, "ipv6-net"); 11007aac531eSYann Bordenave 11017aac531eSYann Bordenave if (ip6_net) { 11027aac531eSYann Bordenave char buf[strlen(ip6_net) + 1]; 11037aac531eSYann Bordenave 11047aac531eSYann Bordenave if (get_str_sep(buf, sizeof(buf), &ip6_net, '/') < 0) { 11057aac531eSYann Bordenave /* Default 64bit prefix length. */ 1106891a2bb5SSamuel Thibault qemu_opt_set(opts, "ipv6-prefix", ip6_net, &error_abort); 1107891a2bb5SSamuel Thibault qemu_opt_set_number(opts, "ipv6-prefixlen", 64, &error_abort); 11087aac531eSYann Bordenave } else { 11097aac531eSYann Bordenave /* User-specified prefix length. */ 11107aac531eSYann Bordenave unsigned long len; 11117aac531eSYann Bordenave int err; 11127aac531eSYann Bordenave 1113891a2bb5SSamuel Thibault qemu_opt_set(opts, "ipv6-prefix", buf, &error_abort); 11147aac531eSYann Bordenave err = qemu_strtoul(ip6_net, NULL, 10, &len); 11157aac531eSYann Bordenave 11167aac531eSYann Bordenave if (err) { 11177aac531eSYann Bordenave error_setg(errp, QERR_INVALID_PARAMETER_VALUE, 1118891a2bb5SSamuel Thibault "ipv6-prefix", "a number"); 11197aac531eSYann Bordenave } else { 1120891a2bb5SSamuel Thibault qemu_opt_set_number(opts, "ipv6-prefixlen", len, 11217aac531eSYann Bordenave &error_abort); 11227aac531eSYann Bordenave } 11237aac531eSYann Bordenave } 1124891a2bb5SSamuel Thibault qemu_opt_unset(opts, "ipv6-net"); 11257aac531eSYann Bordenave } 11267aac531eSYann Bordenave } 11277aac531eSYann Bordenave 112896a1616cSEric Blake if (is_netdev) { 112996a1616cSEric Blake visit_type_Netdev(v, NULL, (Netdev **)&object, &err); 113096a1616cSEric Blake } else { 113196a1616cSEric Blake visit_type_NetLegacy(v, NULL, (NetLegacy **)&object, &err); 1132fd9400b3SPaolo Bonzini } 1133fd9400b3SPaolo Bonzini 1134fd9400b3SPaolo Bonzini if (!err) { 1135fd9400b3SPaolo Bonzini ret = net_client_init1(object, is_netdev, &err); 1136fd9400b3SPaolo Bonzini } 1137fd9400b3SPaolo Bonzini 113896a1616cSEric Blake if (is_netdev) { 113996a1616cSEric Blake qapi_free_Netdev(object); 114096a1616cSEric Blake } else { 114196a1616cSEric Blake qapi_free_NetLegacy(object); 1142fd9400b3SPaolo Bonzini } 1143fd9400b3SPaolo Bonzini 1144fd9400b3SPaolo Bonzini error_propagate(errp, err); 114509204eacSEric Blake visit_free(v); 1146fd9400b3SPaolo Bonzini return ret; 1147fd9400b3SPaolo Bonzini } 1148fd9400b3SPaolo Bonzini 1149fd9400b3SPaolo Bonzini 1150fd9400b3SPaolo Bonzini static int net_host_check_device(const char *device) 1151fd9400b3SPaolo Bonzini { 1152fd9400b3SPaolo Bonzini int i; 115384007e81SHani Benhabiles for (i = 0; host_net_devices[i]; i++) { 115484007e81SHani Benhabiles if (!strncmp(host_net_devices[i], device, 115584007e81SHani Benhabiles strlen(host_net_devices[i]))) { 1156fd9400b3SPaolo Bonzini return 1; 1157fd9400b3SPaolo Bonzini } 115884007e81SHani Benhabiles } 1159fd9400b3SPaolo Bonzini 1160fd9400b3SPaolo Bonzini return 0; 1161fd9400b3SPaolo Bonzini } 1162fd9400b3SPaolo Bonzini 11633e5a50d6SMarkus Armbruster void hmp_host_net_add(Monitor *mon, const QDict *qdict) 1164fd9400b3SPaolo Bonzini { 1165fd9400b3SPaolo Bonzini const char *device = qdict_get_str(qdict, "device"); 1166fd9400b3SPaolo Bonzini const char *opts_str = qdict_get_try_str(qdict, "opts"); 1167fd9400b3SPaolo Bonzini Error *local_err = NULL; 1168fd9400b3SPaolo Bonzini QemuOpts *opts; 1169559964a1SThomas Huth static bool warned; 1170559964a1SThomas Huth 1171559964a1SThomas Huth if (!warned && !qtest_enabled()) { 1172559964a1SThomas Huth error_report("host_net_add is deprecated, use netdev_add instead"); 1173559964a1SThomas Huth warned = true; 1174559964a1SThomas Huth } 1175fd9400b3SPaolo Bonzini 1176fd9400b3SPaolo Bonzini if (!net_host_check_device(device)) { 1177fd9400b3SPaolo Bonzini monitor_printf(mon, "invalid host network device %s\n", device); 1178fd9400b3SPaolo Bonzini return; 1179fd9400b3SPaolo Bonzini } 1180fd9400b3SPaolo Bonzini 118170b94331SMarkus Armbruster opts = qemu_opts_parse_noisily(qemu_find_opts("net"), 118270b94331SMarkus Armbruster opts_str ? opts_str : "", false); 1183fd9400b3SPaolo Bonzini if (!opts) { 1184fd9400b3SPaolo Bonzini return; 1185fd9400b3SPaolo Bonzini } 1186fd9400b3SPaolo Bonzini 1187f43e47dbSMarkus Armbruster qemu_opt_set(opts, "type", device, &error_abort); 1188fd9400b3SPaolo Bonzini 11890e55c381SEric Blake net_client_init(opts, false, &local_err); 119084d18f06SMarkus Armbruster if (local_err) { 119112d0cc2dSMarkus Armbruster error_report_err(local_err); 1192fd9400b3SPaolo Bonzini monitor_printf(mon, "adding host network device %s failed\n", device); 1193fd9400b3SPaolo Bonzini } 1194fd9400b3SPaolo Bonzini } 1195fd9400b3SPaolo Bonzini 11963e5a50d6SMarkus Armbruster void hmp_host_net_remove(Monitor *mon, const QDict *qdict) 1197fd9400b3SPaolo Bonzini { 1198fd9400b3SPaolo Bonzini NetClientState *nc; 1199fd9400b3SPaolo Bonzini int vlan_id = qdict_get_int(qdict, "vlan_id"); 1200fd9400b3SPaolo Bonzini const char *device = qdict_get_str(qdict, "device"); 1201559964a1SThomas Huth static bool warned; 1202559964a1SThomas Huth 1203559964a1SThomas Huth if (!warned && !qtest_enabled()) { 1204559964a1SThomas Huth error_report("host_net_remove is deprecated, use netdev_del instead"); 1205559964a1SThomas Huth warned = true; 1206559964a1SThomas Huth } 1207fd9400b3SPaolo Bonzini 1208fd9400b3SPaolo Bonzini nc = net_hub_find_client_by_name(vlan_id, device); 1209fd9400b3SPaolo Bonzini if (!nc) { 121086e11772SHani Benhabiles error_report("Host network device '%s' on hub '%d' not found", 121186e11772SHani Benhabiles device, vlan_id); 1212fd9400b3SPaolo Bonzini return; 1213fd9400b3SPaolo Bonzini } 1214f394b2e2SEric Blake if (nc->info->type == NET_CLIENT_DRIVER_NIC) { 121586e11772SHani Benhabiles error_report("invalid host network device '%s'", device); 1216fd9400b3SPaolo Bonzini return; 1217fd9400b3SPaolo Bonzini } 121864a55d60SJason Wang 121964a55d60SJason Wang qemu_del_net_client(nc->peer); 1220fd9400b3SPaolo Bonzini qemu_del_net_client(nc); 1221a4543b1bSShmulik Ladkani qemu_opts_del(qemu_opts_find(qemu_find_opts("net"), device)); 1222fd9400b3SPaolo Bonzini } 1223fd9400b3SPaolo Bonzini 1224fd9400b3SPaolo Bonzini void netdev_add(QemuOpts *opts, Error **errp) 1225fd9400b3SPaolo Bonzini { 12260e55c381SEric Blake net_client_init(opts, true, errp); 1227fd9400b3SPaolo Bonzini } 1228fd9400b3SPaolo Bonzini 1229485febc6SMarkus Armbruster void qmp_netdev_add(QDict *qdict, QObject **ret, Error **errp) 1230fd9400b3SPaolo Bonzini { 1231fd9400b3SPaolo Bonzini Error *local_err = NULL; 1232fd9400b3SPaolo Bonzini QemuOptsList *opts_list; 1233fd9400b3SPaolo Bonzini QemuOpts *opts; 1234fd9400b3SPaolo Bonzini 1235fd9400b3SPaolo Bonzini opts_list = qemu_find_opts_err("netdev", &local_err); 123684d18f06SMarkus Armbruster if (local_err) { 1237485febc6SMarkus Armbruster goto out; 1238fd9400b3SPaolo Bonzini } 1239fd9400b3SPaolo Bonzini 1240fd9400b3SPaolo Bonzini opts = qemu_opts_from_qdict(opts_list, qdict, &local_err); 124184d18f06SMarkus Armbruster if (local_err) { 1242485febc6SMarkus Armbruster goto out; 1243fd9400b3SPaolo Bonzini } 1244fd9400b3SPaolo Bonzini 1245fd9400b3SPaolo Bonzini netdev_add(opts, &local_err); 124684d18f06SMarkus Armbruster if (local_err) { 1247fd9400b3SPaolo Bonzini qemu_opts_del(opts); 1248485febc6SMarkus Armbruster goto out; 1249fd9400b3SPaolo Bonzini } 1250fd9400b3SPaolo Bonzini 1251485febc6SMarkus Armbruster out: 1252485febc6SMarkus Armbruster error_propagate(errp, local_err); 1253fd9400b3SPaolo Bonzini } 1254fd9400b3SPaolo Bonzini 1255fd9400b3SPaolo Bonzini void qmp_netdev_del(const char *id, Error **errp) 1256fd9400b3SPaolo Bonzini { 1257fd9400b3SPaolo Bonzini NetClientState *nc; 1258fd9400b3SPaolo Bonzini QemuOpts *opts; 1259fd9400b3SPaolo Bonzini 1260fd9400b3SPaolo Bonzini nc = qemu_find_netdev(id); 1261fd9400b3SPaolo Bonzini if (!nc) { 126275158ebbSMarkus Armbruster error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 126375158ebbSMarkus Armbruster "Device '%s' not found", id); 1264fd9400b3SPaolo Bonzini return; 1265fd9400b3SPaolo Bonzini } 1266fd9400b3SPaolo Bonzini 1267fd9400b3SPaolo Bonzini opts = qemu_opts_find(qemu_find_opts_err("netdev", NULL), id); 1268fd9400b3SPaolo Bonzini if (!opts) { 1269fd9400b3SPaolo Bonzini error_setg(errp, "Device '%s' is not a netdev", id); 1270fd9400b3SPaolo Bonzini return; 1271fd9400b3SPaolo Bonzini } 1272fd9400b3SPaolo Bonzini 1273fd9400b3SPaolo Bonzini qemu_del_net_client(nc); 1274fd9400b3SPaolo Bonzini qemu_opts_del(opts); 1275fd9400b3SPaolo Bonzini } 1276fd9400b3SPaolo Bonzini 1277aa9156f4Szhanghailiang static void netfilter_print_info(Monitor *mon, NetFilterState *nf) 1278aa9156f4Szhanghailiang { 1279aa9156f4Szhanghailiang char *str; 1280aa9156f4Szhanghailiang ObjectProperty *prop; 1281aa9156f4Szhanghailiang ObjectPropertyIterator iter; 12823b098d56SEric Blake Visitor *v; 1283aa9156f4Szhanghailiang 1284aa9156f4Szhanghailiang /* generate info str */ 1285aa9156f4Szhanghailiang object_property_iter_init(&iter, OBJECT(nf)); 1286aa9156f4Szhanghailiang while ((prop = object_property_iter_next(&iter))) { 1287aa9156f4Szhanghailiang if (!strcmp(prop->name, "type")) { 1288aa9156f4Szhanghailiang continue; 1289aa9156f4Szhanghailiang } 12903b098d56SEric Blake v = string_output_visitor_new(false, &str); 12913b098d56SEric Blake object_property_get(OBJECT(nf), v, prop->name, NULL); 12923b098d56SEric Blake visit_complete(v, &str); 12933b098d56SEric Blake visit_free(v); 1294aa9156f4Szhanghailiang monitor_printf(mon, ",%s=%s", prop->name, str); 1295aa9156f4Szhanghailiang g_free(str); 1296aa9156f4Szhanghailiang } 1297aa9156f4Szhanghailiang monitor_printf(mon, "\n"); 1298aa9156f4Szhanghailiang } 1299aa9156f4Szhanghailiang 1300fd9400b3SPaolo Bonzini void print_net_client(Monitor *mon, NetClientState *nc) 1301fd9400b3SPaolo Bonzini { 1302a4960f52SYang Hongyang NetFilterState *nf; 1303a4960f52SYang Hongyang 13041ceef9f2SJason Wang monitor_printf(mon, "%s: index=%d,type=%s,%s\n", nc->name, 13051ceef9f2SJason Wang nc->queue_index, 1306977c736fSMarkus Armbruster NetClientDriver_str(nc->info->type), 13071ceef9f2SJason Wang nc->info_str); 1308a4960f52SYang Hongyang if (!QTAILQ_EMPTY(&nc->filters)) { 1309a4960f52SYang Hongyang monitor_printf(mon, "filters:\n"); 1310a4960f52SYang Hongyang } 1311a4960f52SYang Hongyang QTAILQ_FOREACH(nf, &nc->filters, next) { 1312a3e8a3f3SYang Hongyang char *path = object_get_canonical_path_component(OBJECT(nf)); 1313aa9156f4Szhanghailiang 1314aa9156f4Szhanghailiang monitor_printf(mon, " - %s: type=%s", path, 1315aa9156f4Szhanghailiang object_get_typename(OBJECT(nf))); 1316aa9156f4Szhanghailiang netfilter_print_info(mon, nf); 1317a3e8a3f3SYang Hongyang g_free(path); 1318a4960f52SYang Hongyang } 1319fd9400b3SPaolo Bonzini } 1320fd9400b3SPaolo Bonzini 1321b1be4280SAmos Kong RxFilterInfoList *qmp_query_rx_filter(bool has_name, const char *name, 1322b1be4280SAmos Kong Error **errp) 1323b1be4280SAmos Kong { 1324b1be4280SAmos Kong NetClientState *nc; 1325b1be4280SAmos Kong RxFilterInfoList *filter_list = NULL, *last_entry = NULL; 1326b1be4280SAmos Kong 1327b1be4280SAmos Kong QTAILQ_FOREACH(nc, &net_clients, next) { 1328b1be4280SAmos Kong RxFilterInfoList *entry; 1329b1be4280SAmos Kong RxFilterInfo *info; 1330b1be4280SAmos Kong 1331b1be4280SAmos Kong if (has_name && strcmp(nc->name, name) != 0) { 1332b1be4280SAmos Kong continue; 1333b1be4280SAmos Kong } 1334b1be4280SAmos Kong 1335b1be4280SAmos Kong /* only query rx-filter information of NIC */ 1336f394b2e2SEric Blake if (nc->info->type != NET_CLIENT_DRIVER_NIC) { 1337b1be4280SAmos Kong if (has_name) { 1338b1be4280SAmos Kong error_setg(errp, "net client(%s) isn't a NIC", name); 13399083da1dSMarkus Armbruster return NULL; 1340b1be4280SAmos Kong } 1341b1be4280SAmos Kong continue; 1342b1be4280SAmos Kong } 1343b1be4280SAmos Kong 13445320c2caSVladislav Yasevich /* only query information on queue 0 since the info is per nic, 13455320c2caSVladislav Yasevich * not per queue 13465320c2caSVladislav Yasevich */ 13475320c2caSVladislav Yasevich if (nc->queue_index != 0) 13485320c2caSVladislav Yasevich continue; 13495320c2caSVladislav Yasevich 1350b1be4280SAmos Kong if (nc->info->query_rx_filter) { 1351b1be4280SAmos Kong info = nc->info->query_rx_filter(nc); 1352b1be4280SAmos Kong entry = g_malloc0(sizeof(*entry)); 1353b1be4280SAmos Kong entry->value = info; 1354b1be4280SAmos Kong 1355b1be4280SAmos Kong if (!filter_list) { 1356b1be4280SAmos Kong filter_list = entry; 1357b1be4280SAmos Kong } else { 1358b1be4280SAmos Kong last_entry->next = entry; 1359b1be4280SAmos Kong } 1360b1be4280SAmos Kong last_entry = entry; 1361b1be4280SAmos Kong } else if (has_name) { 1362b1be4280SAmos Kong error_setg(errp, "net client(%s) doesn't support" 1363b1be4280SAmos Kong " rx-filter querying", name); 13649083da1dSMarkus Armbruster return NULL; 1365b1be4280SAmos Kong } 1366638fb141SMarkus Armbruster 1367638fb141SMarkus Armbruster if (has_name) { 1368638fb141SMarkus Armbruster break; 1369638fb141SMarkus Armbruster } 1370b1be4280SAmos Kong } 1371b1be4280SAmos Kong 13729083da1dSMarkus Armbruster if (filter_list == NULL && has_name) { 1373b1be4280SAmos Kong error_setg(errp, "invalid net client name: %s", name); 1374b1be4280SAmos Kong } 1375b1be4280SAmos Kong 1376b1be4280SAmos Kong return filter_list; 1377b1be4280SAmos Kong } 1378b1be4280SAmos Kong 13791ce6be24SMarkus Armbruster void hmp_info_network(Monitor *mon, const QDict *qdict) 1380fd9400b3SPaolo Bonzini { 1381fd9400b3SPaolo Bonzini NetClientState *nc, *peer; 1382f394b2e2SEric Blake NetClientDriver type; 1383fd9400b3SPaolo Bonzini 1384fd9400b3SPaolo Bonzini net_hub_info(mon); 1385fd9400b3SPaolo Bonzini 1386fd9400b3SPaolo Bonzini QTAILQ_FOREACH(nc, &net_clients, next) { 1387fd9400b3SPaolo Bonzini peer = nc->peer; 1388fd9400b3SPaolo Bonzini type = nc->info->type; 1389fd9400b3SPaolo Bonzini 1390fd9400b3SPaolo Bonzini /* Skip if already printed in hub info */ 1391fd9400b3SPaolo Bonzini if (net_hub_id_for_client(nc, NULL) == 0) { 1392fd9400b3SPaolo Bonzini continue; 1393fd9400b3SPaolo Bonzini } 1394fd9400b3SPaolo Bonzini 1395f394b2e2SEric Blake if (!peer || type == NET_CLIENT_DRIVER_NIC) { 1396fd9400b3SPaolo Bonzini print_net_client(mon, nc); 1397fd9400b3SPaolo Bonzini } /* else it's a netdev connected to a NIC, printed with the NIC */ 1398f394b2e2SEric Blake if (peer && type == NET_CLIENT_DRIVER_NIC) { 1399fd9400b3SPaolo Bonzini monitor_printf(mon, " \\ "); 1400fd9400b3SPaolo Bonzini print_net_client(mon, peer); 1401fd9400b3SPaolo Bonzini } 1402fd9400b3SPaolo Bonzini } 1403fd9400b3SPaolo Bonzini } 1404fd9400b3SPaolo Bonzini 1405fd9400b3SPaolo Bonzini void qmp_set_link(const char *name, bool up, Error **errp) 1406fd9400b3SPaolo Bonzini { 14071ceef9f2SJason Wang NetClientState *ncs[MAX_QUEUE_NUM]; 14081ceef9f2SJason Wang NetClientState *nc; 14091ceef9f2SJason Wang int queues, i; 1410fd9400b3SPaolo Bonzini 14111ceef9f2SJason Wang queues = qemu_find_net_clients_except(name, ncs, 1412f394b2e2SEric Blake NET_CLIENT_DRIVER__MAX, 14131ceef9f2SJason Wang MAX_QUEUE_NUM); 14141ceef9f2SJason Wang 14151ceef9f2SJason Wang if (queues == 0) { 141675158ebbSMarkus Armbruster error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 141775158ebbSMarkus Armbruster "Device '%s' not found", name); 1418fd9400b3SPaolo Bonzini return; 1419fd9400b3SPaolo Bonzini } 14201ceef9f2SJason Wang nc = ncs[0]; 1421fd9400b3SPaolo Bonzini 14221ceef9f2SJason Wang for (i = 0; i < queues; i++) { 14231ceef9f2SJason Wang ncs[i]->link_down = !up; 14241ceef9f2SJason Wang } 1425fd9400b3SPaolo Bonzini 1426fd9400b3SPaolo Bonzini if (nc->info->link_status_changed) { 1427fd9400b3SPaolo Bonzini nc->info->link_status_changed(nc); 1428fd9400b3SPaolo Bonzini } 1429fd9400b3SPaolo Bonzini 143002d38fcbSVlad Yasevich if (nc->peer) { 143102d38fcbSVlad Yasevich /* Change peer link only if the peer is NIC and then notify peer. 143202d38fcbSVlad Yasevich * If the peer is a HUBPORT or a backend, we do not change the 143302d38fcbSVlad Yasevich * link status. 1434fd9400b3SPaolo Bonzini * 143502d38fcbSVlad Yasevich * This behavior is compatible with qemu vlans where there could be 1436fd9400b3SPaolo Bonzini * multiple clients that can still communicate with each other in 143702d38fcbSVlad Yasevich * disconnected mode. For now maintain this compatibility. 143802d38fcbSVlad Yasevich */ 1439f394b2e2SEric Blake if (nc->peer->info->type == NET_CLIENT_DRIVER_NIC) { 144002d38fcbSVlad Yasevich for (i = 0; i < queues; i++) { 144102d38fcbSVlad Yasevich ncs[i]->peer->link_down = !up; 144202d38fcbSVlad Yasevich } 144302d38fcbSVlad Yasevich } 144402d38fcbSVlad Yasevich if (nc->peer->info->link_status_changed) { 1445fd9400b3SPaolo Bonzini nc->peer->info->link_status_changed(nc->peer); 1446fd9400b3SPaolo Bonzini } 1447fd9400b3SPaolo Bonzini } 144802d38fcbSVlad Yasevich } 1449fd9400b3SPaolo Bonzini 1450ca77d85eSMichael S. Tsirkin static void net_vm_change_state_handler(void *opaque, int running, 1451ca77d85eSMichael S. Tsirkin RunState state) 1452ca77d85eSMichael S. Tsirkin { 1453ca77d85eSMichael S. Tsirkin NetClientState *nc; 1454ca77d85eSMichael S. Tsirkin NetClientState *tmp; 1455ca77d85eSMichael S. Tsirkin 1456ca77d85eSMichael S. Tsirkin QTAILQ_FOREACH_SAFE(nc, &net_clients, next, tmp) { 1457625de449SFam Zheng if (running) { 1458625de449SFam Zheng /* Flush queued packets and wake up backends. */ 1459625de449SFam Zheng if (nc->peer && qemu_can_send_packet(nc)) { 1460625de449SFam Zheng qemu_flush_queued_packets(nc->peer); 1461625de449SFam Zheng } 1462625de449SFam Zheng } else { 1463625de449SFam Zheng /* Complete all queued packets, to guarantee we don't modify 1464625de449SFam Zheng * state later when VM is not running. 1465625de449SFam Zheng */ 1466ca77d85eSMichael S. Tsirkin qemu_flush_or_purge_queued_packets(nc, true); 1467ca77d85eSMichael S. Tsirkin } 1468ca77d85eSMichael S. Tsirkin } 1469ca77d85eSMichael S. Tsirkin } 1470ca77d85eSMichael S. Tsirkin 1471fd9400b3SPaolo Bonzini void net_cleanup(void) 1472fd9400b3SPaolo Bonzini { 14731ceef9f2SJason Wang NetClientState *nc; 1474fd9400b3SPaolo Bonzini 14751ceef9f2SJason Wang /* We may del multiple entries during qemu_del_net_client(), 14761ceef9f2SJason Wang * so QTAILQ_FOREACH_SAFE() is also not safe here. 14771ceef9f2SJason Wang */ 14781ceef9f2SJason Wang while (!QTAILQ_EMPTY(&net_clients)) { 14791ceef9f2SJason Wang nc = QTAILQ_FIRST(&net_clients); 1480f394b2e2SEric Blake if (nc->info->type == NET_CLIENT_DRIVER_NIC) { 1481948ecf21SJason Wang qemu_del_nic(qemu_get_nic(nc)); 1482948ecf21SJason Wang } else { 1483fd9400b3SPaolo Bonzini qemu_del_net_client(nc); 1484fd9400b3SPaolo Bonzini } 1485fd9400b3SPaolo Bonzini } 1486ca77d85eSMichael S. Tsirkin 1487ca77d85eSMichael S. Tsirkin qemu_del_vm_change_state_handler(net_change_state_entry); 1488948ecf21SJason Wang } 1489fd9400b3SPaolo Bonzini 1490fd9400b3SPaolo Bonzini void net_check_clients(void) 1491fd9400b3SPaolo Bonzini { 1492fd9400b3SPaolo Bonzini NetClientState *nc; 1493fd9400b3SPaolo Bonzini int i; 1494fd9400b3SPaolo Bonzini 1495fd9400b3SPaolo Bonzini net_hub_check_clients(); 1496fd9400b3SPaolo Bonzini 1497fd9400b3SPaolo Bonzini QTAILQ_FOREACH(nc, &net_clients, next) { 1498fd9400b3SPaolo Bonzini if (!nc->peer) { 14998297be80SAlistair Francis warn_report("%s %s has no peer", 1500b62e39b4SAlistair Francis nc->info->type == NET_CLIENT_DRIVER_NIC 1501b62e39b4SAlistair Francis ? "nic" : "netdev", 1502b62e39b4SAlistair Francis nc->name); 1503fd9400b3SPaolo Bonzini } 1504fd9400b3SPaolo Bonzini } 1505fd9400b3SPaolo Bonzini 1506fd9400b3SPaolo Bonzini /* Check that all NICs requested via -net nic actually got created. 1507fd9400b3SPaolo Bonzini * NICs created via -device don't need to be checked here because 1508fd9400b3SPaolo Bonzini * they are always instantiated. 1509fd9400b3SPaolo Bonzini */ 1510fd9400b3SPaolo Bonzini for (i = 0; i < MAX_NICS; i++) { 1511fd9400b3SPaolo Bonzini NICInfo *nd = &nd_table[i]; 1512fd9400b3SPaolo Bonzini if (nd->used && !nd->instantiated) { 15138297be80SAlistair Francis warn_report("requested NIC (%s, model %s) " 15148297be80SAlistair Francis "was not created (not supported by this machine?)", 1515fd9400b3SPaolo Bonzini nd->name ? nd->name : "anonymous", 1516fd9400b3SPaolo Bonzini nd->model ? nd->model : "unspecified"); 1517fd9400b3SPaolo Bonzini } 1518fd9400b3SPaolo Bonzini } 1519fd9400b3SPaolo Bonzini } 1520fd9400b3SPaolo Bonzini 152128d0de7aSMarkus Armbruster static int net_init_client(void *dummy, QemuOpts *opts, Error **errp) 1522fd9400b3SPaolo Bonzini { 1523fd9400b3SPaolo Bonzini Error *local_err = NULL; 1524fd9400b3SPaolo Bonzini 15250e55c381SEric Blake net_client_init(opts, false, &local_err); 152684d18f06SMarkus Armbruster if (local_err) { 152712d0cc2dSMarkus Armbruster error_report_err(local_err); 1528fd9400b3SPaolo Bonzini return -1; 1529fd9400b3SPaolo Bonzini } 1530fd9400b3SPaolo Bonzini 1531fd9400b3SPaolo Bonzini return 0; 1532fd9400b3SPaolo Bonzini } 1533fd9400b3SPaolo Bonzini 153428d0de7aSMarkus Armbruster static int net_init_netdev(void *dummy, QemuOpts *opts, Error **errp) 1535fd9400b3SPaolo Bonzini { 1536fd9400b3SPaolo Bonzini Error *local_err = NULL; 1537fd9400b3SPaolo Bonzini int ret; 1538fd9400b3SPaolo Bonzini 15390e55c381SEric Blake ret = net_client_init(opts, true, &local_err); 154084d18f06SMarkus Armbruster if (local_err) { 154112d0cc2dSMarkus Armbruster error_report_err(local_err); 1542fd9400b3SPaolo Bonzini return -1; 1543fd9400b3SPaolo Bonzini } 1544fd9400b3SPaolo Bonzini 1545fd9400b3SPaolo Bonzini return ret; 1546fd9400b3SPaolo Bonzini } 1547fd9400b3SPaolo Bonzini 1548fd9400b3SPaolo Bonzini int net_init_clients(void) 1549fd9400b3SPaolo Bonzini { 1550fd9400b3SPaolo Bonzini QemuOptsList *net = qemu_find_opts("net"); 1551fd9400b3SPaolo Bonzini 1552ca77d85eSMichael S. Tsirkin net_change_state_entry = 1553ca77d85eSMichael S. Tsirkin qemu_add_vm_change_state_handler(net_vm_change_state_handler, NULL); 1554ca77d85eSMichael S. Tsirkin 1555fd9400b3SPaolo Bonzini QTAILQ_INIT(&net_clients); 1556fd9400b3SPaolo Bonzini 155728d0de7aSMarkus Armbruster if (qemu_opts_foreach(qemu_find_opts("netdev"), 155828d0de7aSMarkus Armbruster net_init_netdev, NULL, NULL)) { 1559fd9400b3SPaolo Bonzini return -1; 1560a4c7367fSMarkus Armbruster } 1561fd9400b3SPaolo Bonzini 156228d0de7aSMarkus Armbruster if (qemu_opts_foreach(net, net_init_client, NULL, NULL)) { 1563fd9400b3SPaolo Bonzini return -1; 1564fd9400b3SPaolo Bonzini } 1565fd9400b3SPaolo Bonzini 1566fd9400b3SPaolo Bonzini return 0; 1567fd9400b3SPaolo Bonzini } 1568fd9400b3SPaolo Bonzini 1569fd9400b3SPaolo Bonzini int net_client_parse(QemuOptsList *opts_list, const char *optarg) 1570fd9400b3SPaolo Bonzini { 157170b94331SMarkus Armbruster if (!qemu_opts_parse_noisily(opts_list, optarg, true)) { 1572fd9400b3SPaolo Bonzini return -1; 1573fd9400b3SPaolo Bonzini } 1574fd9400b3SPaolo Bonzini 1575fd9400b3SPaolo Bonzini return 0; 1576fd9400b3SPaolo Bonzini } 1577fd9400b3SPaolo Bonzini 1578fd9400b3SPaolo Bonzini /* From FreeBSD */ 1579fd9400b3SPaolo Bonzini /* XXX: optimize */ 1580eaba8f34SMark Cave-Ayland uint32_t net_crc32(const uint8_t *p, int len) 1581fd9400b3SPaolo Bonzini { 1582fd9400b3SPaolo Bonzini uint32_t crc; 1583fd9400b3SPaolo Bonzini int carry, i, j; 1584fd9400b3SPaolo Bonzini uint8_t b; 1585fd9400b3SPaolo Bonzini 1586fd9400b3SPaolo Bonzini crc = 0xffffffff; 1587eaba8f34SMark Cave-Ayland for (i = 0; i < len; i++) { 1588eaba8f34SMark Cave-Ayland b = *p++; 1589fd9400b3SPaolo Bonzini for (j = 0; j < 8; j++) { 1590fd9400b3SPaolo Bonzini carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01); 1591fd9400b3SPaolo Bonzini crc <<= 1; 1592fd9400b3SPaolo Bonzini b >>= 1; 1593fd9400b3SPaolo Bonzini if (carry) { 1594eaba8f34SMark Cave-Ayland crc = ((crc ^ POLYNOMIAL_BE) | carry); 1595fd9400b3SPaolo Bonzini } 1596fd9400b3SPaolo Bonzini } 1597fd9400b3SPaolo Bonzini } 1598eaba8f34SMark Cave-Ayland 1599eaba8f34SMark Cave-Ayland return crc; 1600eaba8f34SMark Cave-Ayland } 1601eaba8f34SMark Cave-Ayland 1602f1a7deb9SMark Cave-Ayland uint32_t net_crc32_le(const uint8_t *p, int len) 1603f1a7deb9SMark Cave-Ayland { 1604f1a7deb9SMark Cave-Ayland uint32_t crc; 1605f1a7deb9SMark Cave-Ayland int carry, i, j; 1606f1a7deb9SMark Cave-Ayland uint8_t b; 1607f1a7deb9SMark Cave-Ayland 1608f1a7deb9SMark Cave-Ayland crc = 0xffffffff; 1609f1a7deb9SMark Cave-Ayland for (i = 0; i < len; i++) { 1610f1a7deb9SMark Cave-Ayland b = *p++; 1611f1a7deb9SMark Cave-Ayland for (j = 0; j < 8; j++) { 1612f1a7deb9SMark Cave-Ayland carry = (crc & 0x1) ^ (b & 0x01); 1613f1a7deb9SMark Cave-Ayland crc >>= 1; 1614f1a7deb9SMark Cave-Ayland b >>= 1; 1615f1a7deb9SMark Cave-Ayland if (carry) { 1616f1a7deb9SMark Cave-Ayland crc ^= POLYNOMIAL_LE; 1617f1a7deb9SMark Cave-Ayland } 1618f1a7deb9SMark Cave-Ayland } 1619f1a7deb9SMark Cave-Ayland } 1620f1a7deb9SMark Cave-Ayland 1621f1a7deb9SMark Cave-Ayland return crc; 1622f1a7deb9SMark Cave-Ayland } 1623f1a7deb9SMark Cave-Ayland 16244d454574SPaolo Bonzini QemuOptsList qemu_netdev_opts = { 16254d454574SPaolo Bonzini .name = "netdev", 16264d454574SPaolo Bonzini .implied_opt_name = "type", 16274d454574SPaolo Bonzini .head = QTAILQ_HEAD_INITIALIZER(qemu_netdev_opts.head), 16284d454574SPaolo Bonzini .desc = { 16294d454574SPaolo Bonzini /* 16304d454574SPaolo Bonzini * no elements => accept any params 16314d454574SPaolo Bonzini * validation will happen later 16324d454574SPaolo Bonzini */ 16334d454574SPaolo Bonzini { /* end of list */ } 16344d454574SPaolo Bonzini }, 16354d454574SPaolo Bonzini }; 16364d454574SPaolo Bonzini 16374d454574SPaolo Bonzini QemuOptsList qemu_net_opts = { 16384d454574SPaolo Bonzini .name = "net", 16394d454574SPaolo Bonzini .implied_opt_name = "type", 16404d454574SPaolo Bonzini .head = QTAILQ_HEAD_INITIALIZER(qemu_net_opts.head), 16414d454574SPaolo Bonzini .desc = { 16424d454574SPaolo Bonzini /* 16434d454574SPaolo Bonzini * no elements => accept any params 16444d454574SPaolo Bonzini * validation will happen later 16454d454574SPaolo Bonzini */ 16464d454574SPaolo Bonzini { /* end of list */ } 16474d454574SPaolo Bonzini }, 16484d454574SPaolo Bonzini }; 164916a3df40SZhang Chen 165016a3df40SZhang Chen void net_socket_rs_init(SocketReadState *rs, 16513cde5ea2SZhang Chen SocketReadStateFinalize *finalize, 16523cde5ea2SZhang Chen bool vnet_hdr) 165316a3df40SZhang Chen { 165416a3df40SZhang Chen rs->state = 0; 16553cde5ea2SZhang Chen rs->vnet_hdr = vnet_hdr; 165616a3df40SZhang Chen rs->index = 0; 165716a3df40SZhang Chen rs->packet_len = 0; 16583cde5ea2SZhang Chen rs->vnet_hdr_len = 0; 165916a3df40SZhang Chen memset(rs->buf, 0, sizeof(rs->buf)); 166016a3df40SZhang Chen rs->finalize = finalize; 166116a3df40SZhang Chen } 166216a3df40SZhang Chen 166316a3df40SZhang Chen /* 166416a3df40SZhang Chen * Returns 1665e9e0a585SZhang Chen * 0: success 1666e9e0a585SZhang Chen * -1: error occurs 166716a3df40SZhang Chen */ 166816a3df40SZhang Chen int net_fill_rstate(SocketReadState *rs, const uint8_t *buf, int size) 166916a3df40SZhang Chen { 167016a3df40SZhang Chen unsigned int l; 167116a3df40SZhang Chen 167216a3df40SZhang Chen while (size > 0) { 16733cde5ea2SZhang Chen /* Reassemble a packet from the network. 16743cde5ea2SZhang Chen * 0 = getting length. 16753cde5ea2SZhang Chen * 1 = getting vnet header length. 16763cde5ea2SZhang Chen * 2 = getting data. 16773cde5ea2SZhang Chen */ 16783cde5ea2SZhang Chen switch (rs->state) { 167916a3df40SZhang Chen case 0: 168016a3df40SZhang Chen l = 4 - rs->index; 168116a3df40SZhang Chen if (l > size) { 168216a3df40SZhang Chen l = size; 168316a3df40SZhang Chen } 168416a3df40SZhang Chen memcpy(rs->buf + rs->index, buf, l); 168516a3df40SZhang Chen buf += l; 168616a3df40SZhang Chen size -= l; 168716a3df40SZhang Chen rs->index += l; 168816a3df40SZhang Chen if (rs->index == 4) { 168916a3df40SZhang Chen /* got length */ 169016a3df40SZhang Chen rs->packet_len = ntohl(*(uint32_t *)rs->buf); 169116a3df40SZhang Chen rs->index = 0; 16923cde5ea2SZhang Chen if (rs->vnet_hdr) { 169316a3df40SZhang Chen rs->state = 1; 16943cde5ea2SZhang Chen } else { 16953cde5ea2SZhang Chen rs->state = 2; 16963cde5ea2SZhang Chen rs->vnet_hdr_len = 0; 16973cde5ea2SZhang Chen } 169816a3df40SZhang Chen } 169916a3df40SZhang Chen break; 170016a3df40SZhang Chen case 1: 17013cde5ea2SZhang Chen l = 4 - rs->index; 17023cde5ea2SZhang Chen if (l > size) { 17033cde5ea2SZhang Chen l = size; 17043cde5ea2SZhang Chen } 17053cde5ea2SZhang Chen memcpy(rs->buf + rs->index, buf, l); 17063cde5ea2SZhang Chen buf += l; 17073cde5ea2SZhang Chen size -= l; 17083cde5ea2SZhang Chen rs->index += l; 17093cde5ea2SZhang Chen if (rs->index == 4) { 17103cde5ea2SZhang Chen /* got vnet header length */ 17113cde5ea2SZhang Chen rs->vnet_hdr_len = ntohl(*(uint32_t *)rs->buf); 17123cde5ea2SZhang Chen rs->index = 0; 17133cde5ea2SZhang Chen rs->state = 2; 17143cde5ea2SZhang Chen } 17153cde5ea2SZhang Chen break; 17163cde5ea2SZhang Chen case 2: 171716a3df40SZhang Chen l = rs->packet_len - rs->index; 171816a3df40SZhang Chen if (l > size) { 171916a3df40SZhang Chen l = size; 172016a3df40SZhang Chen } 172116a3df40SZhang Chen if (rs->index + l <= sizeof(rs->buf)) { 172216a3df40SZhang Chen memcpy(rs->buf + rs->index, buf, l); 172316a3df40SZhang Chen } else { 172416a3df40SZhang Chen fprintf(stderr, "serious error: oversized packet received," 172516a3df40SZhang Chen "connection terminated.\n"); 172616a3df40SZhang Chen rs->index = rs->state = 0; 172716a3df40SZhang Chen return -1; 172816a3df40SZhang Chen } 172916a3df40SZhang Chen 173016a3df40SZhang Chen rs->index += l; 173116a3df40SZhang Chen buf += l; 173216a3df40SZhang Chen size -= l; 173316a3df40SZhang Chen if (rs->index >= rs->packet_len) { 173416a3df40SZhang Chen rs->index = 0; 173516a3df40SZhang Chen rs->state = 0; 1736e79cd406SDaniel P. Berrange assert(rs->finalize); 173716a3df40SZhang Chen rs->finalize(rs); 173816a3df40SZhang Chen } 173916a3df40SZhang Chen break; 174016a3df40SZhang Chen } 174116a3df40SZhang Chen } 1742e9e0a585SZhang Chen 1743e9e0a585SZhang Chen assert(size == 0); 174416a3df40SZhang Chen return 0; 174516a3df40SZhang Chen } 1746