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" 38f9bb0c1fSJason Wang #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" 4627eb3722SThomas Huth #include "qemu/id.h" 471de7afc9SPaolo Bonzini #include "qemu/iov.h" 48ad6f932fSPaolo Bonzini #include "qemu/qemu-print.h" 496a1751b7SAlex Bligh #include "qemu/main-loop.h" 50922a01a0SMarkus Armbruster #include "qemu/option.h" 515166fe0aSLaurent Vivier #include "qemu/keyval.h" 52e688df6bSMarkus Armbruster #include "qapi/error.h" 53fd9400b3SPaolo Bonzini #include "qapi/opts-visitor.h" 5454d31236SMarkus Armbruster #include "sysemu/runstate.h" 550c7af1a7SRao, Lei #include "net/colo-compare.h" 56fdccce45SYang Hongyang #include "net/filter.h" 57aa9156f4Szhanghailiang #include "qapi/string-output-visitor.h" 58f3eedcddSLaurent Vivier #include "qapi/qobject-input-visitor.h" 59*a6775371SAkihiko Odaki #include "standard-headers/linux/virtio_net.h" 60fd9400b3SPaolo Bonzini 61fd9400b3SPaolo Bonzini /* Net bridge is currently not supported for W32. */ 62fd9400b3SPaolo Bonzini #if !defined(_WIN32) 63fd9400b3SPaolo Bonzini # define CONFIG_NET_BRIDGE 64fd9400b3SPaolo Bonzini #endif 65fd9400b3SPaolo Bonzini 66ca77d85eSMichael S. Tsirkin static VMChangeStateEntry *net_change_state_entry; 67ae71d13dSMarkus Armbruster NetClientStateList net_clients; 68fd9400b3SPaolo Bonzini 69f3eedcddSLaurent Vivier typedef struct NetdevQueueEntry { 70f3eedcddSLaurent Vivier Netdev *nd; 71f3eedcddSLaurent Vivier Location loc; 72f3eedcddSLaurent Vivier QSIMPLEQ_ENTRY(NetdevQueueEntry) entry; 73f3eedcddSLaurent Vivier } NetdevQueueEntry; 74f3eedcddSLaurent Vivier 75f3eedcddSLaurent Vivier typedef QSIMPLEQ_HEAD(, NetdevQueueEntry) NetdevQueue; 76f3eedcddSLaurent Vivier 77f3eedcddSLaurent Vivier static NetdevQueue nd_queue = QSIMPLEQ_HEAD_INITIALIZER(nd_queue); 78f3eedcddSLaurent Vivier 792cdeca04SDavid Woodhouse static GHashTable *nic_model_help; 802cdeca04SDavid Woodhouse 81e8c5c452SDavid Woodhouse static int nb_nics; 82e8c5c452SDavid Woodhouse static NICInfo nd_table[MAX_NICS]; 83e8c5c452SDavid Woodhouse 84fd9400b3SPaolo Bonzini /***********************************************************/ 85fd9400b3SPaolo Bonzini /* network device redirectors */ 86fd9400b3SPaolo Bonzini 8730e4226bSLaurent Vivier int convert_host_port(struct sockaddr_in *saddr, const char *host, 8830e4226bSLaurent Vivier const char *port, Error **errp) 8930e4226bSLaurent Vivier { 9030e4226bSLaurent Vivier struct hostent *he; 9130e4226bSLaurent Vivier const char *r; 9230e4226bSLaurent Vivier long p; 9330e4226bSLaurent Vivier 9430e4226bSLaurent Vivier memset(saddr, 0, sizeof(*saddr)); 9530e4226bSLaurent Vivier 9630e4226bSLaurent Vivier saddr->sin_family = AF_INET; 9730e4226bSLaurent Vivier if (host[0] == '\0') { 9830e4226bSLaurent Vivier saddr->sin_addr.s_addr = 0; 9930e4226bSLaurent Vivier } else { 10030e4226bSLaurent Vivier if (qemu_isdigit(host[0])) { 10130e4226bSLaurent Vivier if (!inet_aton(host, &saddr->sin_addr)) { 10230e4226bSLaurent Vivier error_setg(errp, "host address '%s' is not a valid " 10330e4226bSLaurent Vivier "IPv4 address", host); 10430e4226bSLaurent Vivier return -1; 10530e4226bSLaurent Vivier } 10630e4226bSLaurent Vivier } else { 10730e4226bSLaurent Vivier he = gethostbyname(host); 10830e4226bSLaurent Vivier if (he == NULL) { 10930e4226bSLaurent Vivier error_setg(errp, "can't resolve host address '%s'", host); 11030e4226bSLaurent Vivier return -1; 11130e4226bSLaurent Vivier } 11230e4226bSLaurent Vivier saddr->sin_addr = *(struct in_addr *)he->h_addr; 11330e4226bSLaurent Vivier } 11430e4226bSLaurent Vivier } 11530e4226bSLaurent Vivier if (qemu_strtol(port, &r, 0, &p) != 0) { 11630e4226bSLaurent Vivier error_setg(errp, "port number '%s' is invalid", port); 11730e4226bSLaurent Vivier return -1; 11830e4226bSLaurent Vivier } 11930e4226bSLaurent Vivier saddr->sin_port = htons(p); 12030e4226bSLaurent Vivier return 0; 12130e4226bSLaurent Vivier } 12230e4226bSLaurent Vivier 123bcd4dfd6SMao Zhongyi int parse_host_port(struct sockaddr_in *saddr, const char *str, 124bcd4dfd6SMao Zhongyi Error **errp) 125fd9400b3SPaolo Bonzini { 126add99347SStefano Garzarella gchar **substrings; 12730e4226bSLaurent Vivier int ret; 12859292384SPeter Maydell 129add99347SStefano Garzarella substrings = g_strsplit(str, ":", 2); 130add99347SStefano Garzarella if (!substrings || !substrings[0] || !substrings[1]) { 131bcd4dfd6SMao Zhongyi error_setg(errp, "host address '%s' doesn't contain ':' " 132bcd4dfd6SMao Zhongyi "separating host from port", str); 133add99347SStefano Garzarella ret = -1; 134add99347SStefano Garzarella goto out; 135bcd4dfd6SMao Zhongyi } 136add99347SStefano Garzarella 13730e4226bSLaurent Vivier ret = convert_host_port(saddr, substrings[0], substrings[1], errp); 138add99347SStefano Garzarella 139add99347SStefano Garzarella out: 140add99347SStefano Garzarella g_strfreev(substrings); 141add99347SStefano Garzarella return ret; 142fd9400b3SPaolo Bonzini } 143fd9400b3SPaolo Bonzini 144890ee6abSScott Feldman char *qemu_mac_strdup_printf(const uint8_t *macaddr) 145890ee6abSScott Feldman { 146890ee6abSScott Feldman return g_strdup_printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", 147890ee6abSScott Feldman macaddr[0], macaddr[1], macaddr[2], 148890ee6abSScott Feldman macaddr[3], macaddr[4], macaddr[5]); 149890ee6abSScott Feldman } 150890ee6abSScott Feldman 15153b85d95SLaurent Vivier void qemu_set_info_str(NetClientState *nc, const char *fmt, ...) 15253b85d95SLaurent Vivier { 15353b85d95SLaurent Vivier va_list ap; 15453b85d95SLaurent Vivier 15553b85d95SLaurent Vivier va_start(ap, fmt); 15653b85d95SLaurent Vivier vsnprintf(nc->info_str, sizeof(nc->info_str), fmt, ap); 15753b85d95SLaurent Vivier va_end(ap); 15853b85d95SLaurent Vivier } 15953b85d95SLaurent Vivier 160fd9400b3SPaolo Bonzini void qemu_format_nic_info_str(NetClientState *nc, uint8_t macaddr[6]) 161fd9400b3SPaolo Bonzini { 16253b85d95SLaurent Vivier qemu_set_info_str(nc, "model=%s,macaddr=%02x:%02x:%02x:%02x:%02x:%02x", 16353b85d95SLaurent Vivier nc->model, macaddr[0], macaddr[1], macaddr[2], 164fd9400b3SPaolo Bonzini macaddr[3], macaddr[4], macaddr[5]); 165fd9400b3SPaolo Bonzini } 166fd9400b3SPaolo Bonzini 1672bc22a58SShannon Zhao static int mac_table[256] = {0}; 1682bc22a58SShannon Zhao 1692bc22a58SShannon Zhao static void qemu_macaddr_set_used(MACAddr *macaddr) 1702bc22a58SShannon Zhao { 1712bc22a58SShannon Zhao int index; 1722bc22a58SShannon Zhao 1732bc22a58SShannon Zhao for (index = 0x56; index < 0xFF; index++) { 1742bc22a58SShannon Zhao if (macaddr->a[5] == index) { 1752bc22a58SShannon Zhao mac_table[index]++; 1762bc22a58SShannon Zhao } 1772bc22a58SShannon Zhao } 1782bc22a58SShannon Zhao } 1792bc22a58SShannon Zhao 1802bc22a58SShannon Zhao static void qemu_macaddr_set_free(MACAddr *macaddr) 1812bc22a58SShannon Zhao { 1822bc22a58SShannon Zhao int index; 1832bc22a58SShannon Zhao static const MACAddr base = { .a = { 0x52, 0x54, 0x00, 0x12, 0x34, 0 } }; 1842bc22a58SShannon Zhao 1852bc22a58SShannon Zhao if (memcmp(macaddr->a, &base.a, (sizeof(base.a) - 1)) != 0) { 1862bc22a58SShannon Zhao return; 1872bc22a58SShannon Zhao } 1882bc22a58SShannon Zhao for (index = 0x56; index < 0xFF; index++) { 1892bc22a58SShannon Zhao if (macaddr->a[5] == index) { 1902bc22a58SShannon Zhao mac_table[index]--; 1912bc22a58SShannon Zhao } 1922bc22a58SShannon Zhao } 1932bc22a58SShannon Zhao } 1942bc22a58SShannon Zhao 1952bc22a58SShannon Zhao static int qemu_macaddr_get_free(void) 1962bc22a58SShannon Zhao { 1972bc22a58SShannon Zhao int index; 1982bc22a58SShannon Zhao 1992bc22a58SShannon Zhao for (index = 0x56; index < 0xFF; index++) { 2002bc22a58SShannon Zhao if (mac_table[index] == 0) { 2012bc22a58SShannon Zhao return index; 2022bc22a58SShannon Zhao } 2032bc22a58SShannon Zhao } 2042bc22a58SShannon Zhao 2052bc22a58SShannon Zhao return -1; 2062bc22a58SShannon Zhao } 2072bc22a58SShannon Zhao 208fd9400b3SPaolo Bonzini void qemu_macaddr_default_if_unset(MACAddr *macaddr) 209fd9400b3SPaolo Bonzini { 210fd9400b3SPaolo Bonzini static const MACAddr zero = { .a = { 0,0,0,0,0,0 } }; 2112bc22a58SShannon Zhao static const MACAddr base = { .a = { 0x52, 0x54, 0x00, 0x12, 0x34, 0 } }; 212fd9400b3SPaolo Bonzini 2132bc22a58SShannon Zhao if (memcmp(macaddr, &zero, sizeof(zero)) != 0) { 2142bc22a58SShannon Zhao if (memcmp(macaddr->a, &base.a, (sizeof(base.a) - 1)) != 0) { 215fd9400b3SPaolo Bonzini return; 2162bc22a58SShannon Zhao } else { 2172bc22a58SShannon Zhao qemu_macaddr_set_used(macaddr); 2182bc22a58SShannon Zhao return; 2192bc22a58SShannon Zhao } 2202bc22a58SShannon Zhao } 2212bc22a58SShannon Zhao 222fd9400b3SPaolo Bonzini macaddr->a[0] = 0x52; 223fd9400b3SPaolo Bonzini macaddr->a[1] = 0x54; 224fd9400b3SPaolo Bonzini macaddr->a[2] = 0x00; 225fd9400b3SPaolo Bonzini macaddr->a[3] = 0x12; 226fd9400b3SPaolo Bonzini macaddr->a[4] = 0x34; 2272bc22a58SShannon Zhao macaddr->a[5] = qemu_macaddr_get_free(); 2282bc22a58SShannon Zhao qemu_macaddr_set_used(macaddr); 229fd9400b3SPaolo Bonzini } 230fd9400b3SPaolo Bonzini 231fd9400b3SPaolo Bonzini /** 232fd9400b3SPaolo Bonzini * Generate a name for net client 233fd9400b3SPaolo Bonzini * 234c963530aSAmos Kong * Only net clients created with the legacy -net option and NICs need this. 235fd9400b3SPaolo Bonzini */ 236fd9400b3SPaolo Bonzini static char *assign_name(NetClientState *nc1, const char *model) 237fd9400b3SPaolo Bonzini { 238fd9400b3SPaolo Bonzini NetClientState *nc; 239fd9400b3SPaolo Bonzini int id = 0; 240fd9400b3SPaolo Bonzini 241fd9400b3SPaolo Bonzini QTAILQ_FOREACH(nc, &net_clients, next) { 242fd9400b3SPaolo Bonzini if (nc == nc1) { 243fd9400b3SPaolo Bonzini continue; 244fd9400b3SPaolo Bonzini } 245c963530aSAmos Kong if (strcmp(nc->model, model) == 0) { 246fd9400b3SPaolo Bonzini id++; 247fd9400b3SPaolo Bonzini } 248fd9400b3SPaolo Bonzini } 249fd9400b3SPaolo Bonzini 2504bf2c138SHani Benhabiles return g_strdup_printf("%s.%d", model, id); 251fd9400b3SPaolo Bonzini } 252fd9400b3SPaolo Bonzini 253f7860455SJason Wang static void qemu_net_client_destructor(NetClientState *nc) 254f7860455SJason Wang { 255f7860455SJason Wang g_free(nc); 256f7860455SJason Wang } 25725c01bd1SJason Wang static ssize_t qemu_deliver_packet_iov(NetClientState *sender, 25825c01bd1SJason Wang unsigned flags, 25925c01bd1SJason Wang const struct iovec *iov, 26025c01bd1SJason Wang int iovcnt, 26125c01bd1SJason Wang void *opaque); 262f7860455SJason Wang 26318a1541aSJason Wang static void qemu_net_client_setup(NetClientState *nc, 26418a1541aSJason Wang NetClientInfo *info, 265fd9400b3SPaolo Bonzini NetClientState *peer, 266fd9400b3SPaolo Bonzini const char *model, 267f7860455SJason Wang const char *name, 2682f849dbdSJason Wang NetClientDestructor *destructor, 2692f849dbdSJason Wang bool is_datapath) 270fd9400b3SPaolo Bonzini { 271fd9400b3SPaolo Bonzini nc->info = info; 272fd9400b3SPaolo Bonzini nc->model = g_strdup(model); 273fd9400b3SPaolo Bonzini if (name) { 274fd9400b3SPaolo Bonzini nc->name = g_strdup(name); 275fd9400b3SPaolo Bonzini } else { 276fd9400b3SPaolo Bonzini nc->name = assign_name(nc, model); 277fd9400b3SPaolo Bonzini } 278fd9400b3SPaolo Bonzini 279fd9400b3SPaolo Bonzini if (peer) { 280fd9400b3SPaolo Bonzini assert(!peer->peer); 281fd9400b3SPaolo Bonzini nc->peer = peer; 282fd9400b3SPaolo Bonzini peer->peer = nc; 283fd9400b3SPaolo Bonzini } 284fd9400b3SPaolo Bonzini QTAILQ_INSERT_TAIL(&net_clients, nc, next); 285fd9400b3SPaolo Bonzini 2863e033a46SYang Hongyang nc->incoming_queue = qemu_new_net_queue(qemu_deliver_packet_iov, nc); 287f7860455SJason Wang nc->destructor = destructor; 2882f849dbdSJason Wang nc->is_datapath = is_datapath; 289fdccce45SYang Hongyang QTAILQ_INIT(&nc->filters); 29018a1541aSJason Wang } 29118a1541aSJason Wang 29218a1541aSJason Wang NetClientState *qemu_new_net_client(NetClientInfo *info, 29318a1541aSJason Wang NetClientState *peer, 29418a1541aSJason Wang const char *model, 29518a1541aSJason Wang const char *name) 29618a1541aSJason Wang { 29718a1541aSJason Wang NetClientState *nc; 29818a1541aSJason Wang 29918a1541aSJason Wang assert(info->size >= sizeof(NetClientState)); 30018a1541aSJason Wang 30118a1541aSJason Wang nc = g_malloc0(info->size); 302f7860455SJason Wang qemu_net_client_setup(nc, info, peer, model, name, 3032f849dbdSJason Wang qemu_net_client_destructor, true); 3042f849dbdSJason Wang 3052f849dbdSJason Wang return nc; 3062f849dbdSJason Wang } 3072f849dbdSJason Wang 3082f849dbdSJason Wang NetClientState *qemu_new_net_control_client(NetClientInfo *info, 3092f849dbdSJason Wang NetClientState *peer, 3102f849dbdSJason Wang const char *model, 3112f849dbdSJason Wang const char *name) 3122f849dbdSJason Wang { 3132f849dbdSJason Wang NetClientState *nc; 3142f849dbdSJason Wang 3152f849dbdSJason Wang assert(info->size >= sizeof(NetClientState)); 3162f849dbdSJason Wang 3172f849dbdSJason Wang nc = g_malloc0(info->size); 3182f849dbdSJason Wang qemu_net_client_setup(nc, info, peer, model, name, 3192f849dbdSJason Wang qemu_net_client_destructor, false); 32018a1541aSJason Wang 321fd9400b3SPaolo Bonzini return nc; 322fd9400b3SPaolo Bonzini } 323fd9400b3SPaolo Bonzini 324fd9400b3SPaolo Bonzini NICState *qemu_new_nic(NetClientInfo *info, 325fd9400b3SPaolo Bonzini NICConf *conf, 326fd9400b3SPaolo Bonzini const char *model, 327fd9400b3SPaolo Bonzini const char *name, 3287d0fefdfSAkihiko Odaki MemReentrancyGuard *reentrancy_guard, 329fd9400b3SPaolo Bonzini void *opaque) 330fd9400b3SPaolo Bonzini { 3311ceef9f2SJason Wang NetClientState **peers = conf->peers.ncs; 332fd9400b3SPaolo Bonzini NICState *nic; 333575a1c0eSJiri Pirko int i, queues = MAX(1, conf->peers.queues); 334fd9400b3SPaolo Bonzini 335f394b2e2SEric Blake assert(info->type == NET_CLIENT_DRIVER_NIC); 336fd9400b3SPaolo Bonzini assert(info->size >= sizeof(NICState)); 337fd9400b3SPaolo Bonzini 338f6b26cf2SJason Wang nic = g_malloc0(info->size + sizeof(NetClientState) * queues); 339f6b26cf2SJason Wang nic->ncs = (void *)nic + info->size; 340fd9400b3SPaolo Bonzini nic->conf = conf; 3419050f976SAkihiko Odaki nic->reentrancy_guard = reentrancy_guard, 342fd9400b3SPaolo Bonzini nic->opaque = opaque; 343fd9400b3SPaolo Bonzini 344f6b26cf2SJason Wang for (i = 0; i < queues; i++) { 345f6b26cf2SJason Wang qemu_net_client_setup(&nic->ncs[i], info, peers[i], model, name, 3462f849dbdSJason Wang NULL, true); 3471ceef9f2SJason Wang nic->ncs[i].queue_index = i; 3481ceef9f2SJason Wang } 3491ceef9f2SJason Wang 350fd9400b3SPaolo Bonzini return nic; 351fd9400b3SPaolo Bonzini } 352fd9400b3SPaolo Bonzini 3531ceef9f2SJason Wang NetClientState *qemu_get_subqueue(NICState *nic, int queue_index) 3541ceef9f2SJason Wang { 355f6b26cf2SJason Wang return nic->ncs + queue_index; 3561ceef9f2SJason Wang } 3571ceef9f2SJason Wang 358b356f76dSJason Wang NetClientState *qemu_get_queue(NICState *nic) 359b356f76dSJason Wang { 3601ceef9f2SJason Wang return qemu_get_subqueue(nic, 0); 361b356f76dSJason Wang } 362b356f76dSJason Wang 363cc1f0f45SJason Wang NICState *qemu_get_nic(NetClientState *nc) 364cc1f0f45SJason Wang { 3651ceef9f2SJason Wang NetClientState *nc0 = nc - nc->queue_index; 3661ceef9f2SJason Wang 367f6b26cf2SJason Wang return (NICState *)((void *)nc0 - nc->info->size); 368cc1f0f45SJason Wang } 369cc1f0f45SJason Wang 370cc1f0f45SJason Wang void *qemu_get_nic_opaque(NetClientState *nc) 371cc1f0f45SJason Wang { 372cc1f0f45SJason Wang NICState *nic = qemu_get_nic(nc); 373cc1f0f45SJason Wang 374cc1f0f45SJason Wang return nic->opaque; 375cc1f0f45SJason Wang } 376cc1f0f45SJason Wang 3770165daaeSCindy Lu NetClientState *qemu_get_peer(NetClientState *nc, int queue_index) 3780165daaeSCindy Lu { 3790165daaeSCindy Lu assert(nc != NULL); 3800165daaeSCindy Lu NetClientState *ncs = nc + queue_index; 3810165daaeSCindy Lu return ncs->peer; 3820165daaeSCindy Lu } 3830165daaeSCindy Lu 384fd9400b3SPaolo Bonzini static void qemu_cleanup_net_client(NetClientState *nc) 385fd9400b3SPaolo Bonzini { 386fd9400b3SPaolo Bonzini QTAILQ_REMOVE(&net_clients, nc, next); 387fd9400b3SPaolo Bonzini 388cc2a9043SAndreas Färber if (nc->info->cleanup) { 389fd9400b3SPaolo Bonzini nc->info->cleanup(nc); 390fd9400b3SPaolo Bonzini } 391cc2a9043SAndreas Färber } 392fd9400b3SPaolo Bonzini 393fd9400b3SPaolo Bonzini static void qemu_free_net_client(NetClientState *nc) 394fd9400b3SPaolo Bonzini { 395067404beSJan Kiszka if (nc->incoming_queue) { 396067404beSJan Kiszka qemu_del_net_queue(nc->incoming_queue); 397fd9400b3SPaolo Bonzini } 398fd9400b3SPaolo Bonzini if (nc->peer) { 399fd9400b3SPaolo Bonzini nc->peer->peer = NULL; 400fd9400b3SPaolo Bonzini } 401fd9400b3SPaolo Bonzini g_free(nc->name); 402fd9400b3SPaolo Bonzini g_free(nc->model); 403f7860455SJason Wang if (nc->destructor) { 404f7860455SJason Wang nc->destructor(nc); 405f7860455SJason Wang } 406fd9400b3SPaolo Bonzini } 407fd9400b3SPaolo Bonzini 408fd9400b3SPaolo Bonzini void qemu_del_net_client(NetClientState *nc) 409fd9400b3SPaolo Bonzini { 4101ceef9f2SJason Wang NetClientState *ncs[MAX_QUEUE_NUM]; 4111ceef9f2SJason Wang int queues, i; 412fdccce45SYang Hongyang NetFilterState *nf, *next; 4131ceef9f2SJason Wang 414f394b2e2SEric Blake assert(nc->info->type != NET_CLIENT_DRIVER_NIC); 4157fb43911SPaolo Bonzini 4161ceef9f2SJason Wang /* If the NetClientState belongs to a multiqueue backend, we will change all 4171ceef9f2SJason Wang * other NetClientStates also. 4181ceef9f2SJason Wang */ 4191ceef9f2SJason Wang queues = qemu_find_net_clients_except(nc->name, ncs, 420f394b2e2SEric Blake NET_CLIENT_DRIVER_NIC, 4211ceef9f2SJason Wang MAX_QUEUE_NUM); 4221ceef9f2SJason Wang assert(queues != 0); 4231ceef9f2SJason Wang 424fdccce45SYang Hongyang QTAILQ_FOREACH_SAFE(nf, &nc->filters, next, next) { 425fdccce45SYang Hongyang object_unparent(OBJECT(nf)); 426fdccce45SYang Hongyang } 427fdccce45SYang Hongyang 428fd9400b3SPaolo Bonzini /* If there is a peer NIC, delete and cleanup client, but do not free. */ 429f394b2e2SEric Blake if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_NIC) { 430cc1f0f45SJason Wang NICState *nic = qemu_get_nic(nc->peer); 431fd9400b3SPaolo Bonzini if (nic->peer_deleted) { 432fd9400b3SPaolo Bonzini return; 433fd9400b3SPaolo Bonzini } 434fd9400b3SPaolo Bonzini nic->peer_deleted = true; 4351ceef9f2SJason Wang 4361ceef9f2SJason Wang for (i = 0; i < queues; i++) { 4371ceef9f2SJason Wang ncs[i]->peer->link_down = true; 4381ceef9f2SJason Wang } 4391ceef9f2SJason Wang 440fd9400b3SPaolo Bonzini if (nc->peer->info->link_status_changed) { 441fd9400b3SPaolo Bonzini nc->peer->info->link_status_changed(nc->peer); 442fd9400b3SPaolo Bonzini } 4431ceef9f2SJason Wang 4441ceef9f2SJason Wang for (i = 0; i < queues; i++) { 4451ceef9f2SJason Wang qemu_cleanup_net_client(ncs[i]); 4461ceef9f2SJason Wang } 4471ceef9f2SJason Wang 448fd9400b3SPaolo Bonzini return; 449fd9400b3SPaolo Bonzini } 450fd9400b3SPaolo Bonzini 4511ceef9f2SJason Wang for (i = 0; i < queues; i++) { 4521ceef9f2SJason Wang qemu_cleanup_net_client(ncs[i]); 4531ceef9f2SJason Wang qemu_free_net_client(ncs[i]); 4541ceef9f2SJason Wang } 455948ecf21SJason Wang } 456948ecf21SJason Wang 457948ecf21SJason Wang void qemu_del_nic(NICState *nic) 458948ecf21SJason Wang { 459575a1c0eSJiri Pirko int i, queues = MAX(nic->conf->peers.queues, 1); 4601ceef9f2SJason Wang 4612bc22a58SShannon Zhao qemu_macaddr_set_free(&nic->conf->macaddr); 4622bc22a58SShannon Zhao 463d2abc563SYuri Benditovich for (i = 0; i < queues; i++) { 464d2abc563SYuri Benditovich NetClientState *nc = qemu_get_subqueue(nic, i); 465fd9400b3SPaolo Bonzini /* If this is a peer NIC and peer has already been deleted, free it now. */ 466fd9400b3SPaolo Bonzini if (nic->peer_deleted) { 467d2abc563SYuri Benditovich qemu_free_net_client(nc->peer); 468d2abc563SYuri Benditovich } else if (nc->peer) { 469d2abc563SYuri Benditovich /* if there are RX packets pending, complete them */ 470d2abc563SYuri Benditovich qemu_purge_queued_packets(nc->peer); 471fd9400b3SPaolo Bonzini } 472fd9400b3SPaolo Bonzini } 473fd9400b3SPaolo Bonzini 4741ceef9f2SJason Wang for (i = queues - 1; i >= 0; i--) { 4751ceef9f2SJason Wang NetClientState *nc = qemu_get_subqueue(nic, i); 4761ceef9f2SJason Wang 477fd9400b3SPaolo Bonzini qemu_cleanup_net_client(nc); 478fd9400b3SPaolo Bonzini qemu_free_net_client(nc); 479fd9400b3SPaolo Bonzini } 480f6b26cf2SJason Wang 481f6b26cf2SJason Wang g_free(nic); 4821ceef9f2SJason Wang } 483fd9400b3SPaolo Bonzini 484fd9400b3SPaolo Bonzini void qemu_foreach_nic(qemu_nic_foreach func, void *opaque) 485fd9400b3SPaolo Bonzini { 486fd9400b3SPaolo Bonzini NetClientState *nc; 487fd9400b3SPaolo Bonzini 488fd9400b3SPaolo Bonzini QTAILQ_FOREACH(nc, &net_clients, next) { 489f394b2e2SEric Blake if (nc->info->type == NET_CLIENT_DRIVER_NIC) { 4901ceef9f2SJason Wang if (nc->queue_index == 0) { 491cc1f0f45SJason Wang func(qemu_get_nic(nc), opaque); 492fd9400b3SPaolo Bonzini } 493fd9400b3SPaolo Bonzini } 494fd9400b3SPaolo Bonzini } 4951ceef9f2SJason Wang } 496fd9400b3SPaolo Bonzini 497d6085e3aSStefan Hajnoczi bool qemu_has_ufo(NetClientState *nc) 4981f55ac45SVincenzo Maffione { 499d6085e3aSStefan Hajnoczi if (!nc || !nc->info->has_ufo) { 5001f55ac45SVincenzo Maffione return false; 5011f55ac45SVincenzo Maffione } 5021f55ac45SVincenzo Maffione 503d6085e3aSStefan Hajnoczi return nc->info->has_ufo(nc); 5041f55ac45SVincenzo Maffione } 5051f55ac45SVincenzo Maffione 506f03e0cf6SYuri Benditovich bool qemu_has_uso(NetClientState *nc) 507f03e0cf6SYuri Benditovich { 508f03e0cf6SYuri Benditovich if (!nc || !nc->info->has_uso) { 509f03e0cf6SYuri Benditovich return false; 510f03e0cf6SYuri Benditovich } 511f03e0cf6SYuri Benditovich 512f03e0cf6SYuri Benditovich return nc->info->has_uso(nc); 513f03e0cf6SYuri Benditovich } 514f03e0cf6SYuri Benditovich 515d6085e3aSStefan Hajnoczi bool qemu_has_vnet_hdr(NetClientState *nc) 5161f55ac45SVincenzo Maffione { 517d6085e3aSStefan Hajnoczi if (!nc || !nc->info->has_vnet_hdr) { 5181f55ac45SVincenzo Maffione return false; 5191f55ac45SVincenzo Maffione } 5201f55ac45SVincenzo Maffione 521d6085e3aSStefan Hajnoczi return nc->info->has_vnet_hdr(nc); 5221f55ac45SVincenzo Maffione } 5231f55ac45SVincenzo Maffione 524d6085e3aSStefan Hajnoczi bool qemu_has_vnet_hdr_len(NetClientState *nc, int len) 5251f55ac45SVincenzo Maffione { 526d6085e3aSStefan Hajnoczi if (!nc || !nc->info->has_vnet_hdr_len) { 5271f55ac45SVincenzo Maffione return false; 5281f55ac45SVincenzo Maffione } 5291f55ac45SVincenzo Maffione 530d6085e3aSStefan Hajnoczi return nc->info->has_vnet_hdr_len(nc, len); 5311f55ac45SVincenzo Maffione } 5321f55ac45SVincenzo Maffione 533d6085e3aSStefan Hajnoczi void qemu_set_offload(NetClientState *nc, int csum, int tso4, int tso6, 5342ab0ec31SAndrew Melnychenko int ecn, int ufo, int uso4, int uso6) 5351f55ac45SVincenzo Maffione { 536d6085e3aSStefan Hajnoczi if (!nc || !nc->info->set_offload) { 5371f55ac45SVincenzo Maffione return; 5381f55ac45SVincenzo Maffione } 5391f55ac45SVincenzo Maffione 5402ab0ec31SAndrew Melnychenko nc->info->set_offload(nc, csum, tso4, tso6, ecn, ufo, uso4, uso6); 5411f55ac45SVincenzo Maffione } 5421f55ac45SVincenzo Maffione 543481c5232SAkihiko Odaki int qemu_get_vnet_hdr_len(NetClientState *nc) 544481c5232SAkihiko Odaki { 5454b52d632SAkihiko Odaki return nc->vnet_hdr_len; 546481c5232SAkihiko Odaki } 547481c5232SAkihiko Odaki 548d6085e3aSStefan Hajnoczi void qemu_set_vnet_hdr_len(NetClientState *nc, int len) 5491f55ac45SVincenzo Maffione { 550d6085e3aSStefan Hajnoczi if (!nc || !nc->info->set_vnet_hdr_len) { 5511f55ac45SVincenzo Maffione return; 5521f55ac45SVincenzo Maffione } 5531f55ac45SVincenzo Maffione 554*a6775371SAkihiko Odaki assert(len == sizeof(struct virtio_net_hdr_mrg_rxbuf) || 555*a6775371SAkihiko Odaki len == sizeof(struct virtio_net_hdr) || 556*a6775371SAkihiko Odaki len == sizeof(struct virtio_net_hdr_v1_hash)); 557*a6775371SAkihiko Odaki 558d6b732e9SZhang Chen nc->vnet_hdr_len = len; 559d6085e3aSStefan Hajnoczi nc->info->set_vnet_hdr_len(nc, len); 5601f55ac45SVincenzo Maffione } 5611f55ac45SVincenzo Maffione 562c80cd6bbSGreg Kurz int qemu_set_vnet_le(NetClientState *nc, bool is_le) 563c80cd6bbSGreg Kurz { 564e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN 565c80cd6bbSGreg Kurz if (!nc || !nc->info->set_vnet_le) { 566c80cd6bbSGreg Kurz return -ENOSYS; 567c80cd6bbSGreg Kurz } 568c80cd6bbSGreg Kurz 569c80cd6bbSGreg Kurz return nc->info->set_vnet_le(nc, is_le); 570052bd52fSMichael S. Tsirkin #else 571052bd52fSMichael S. Tsirkin return 0; 572052bd52fSMichael S. Tsirkin #endif 573c80cd6bbSGreg Kurz } 574c80cd6bbSGreg Kurz 575c80cd6bbSGreg Kurz int qemu_set_vnet_be(NetClientState *nc, bool is_be) 576c80cd6bbSGreg Kurz { 577e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN 578052bd52fSMichael S. Tsirkin return 0; 579052bd52fSMichael S. Tsirkin #else 580c80cd6bbSGreg Kurz if (!nc || !nc->info->set_vnet_be) { 581c80cd6bbSGreg Kurz return -ENOSYS; 582c80cd6bbSGreg Kurz } 583c80cd6bbSGreg Kurz 584c80cd6bbSGreg Kurz return nc->info->set_vnet_be(nc, is_be); 585052bd52fSMichael S. Tsirkin #endif 586c80cd6bbSGreg Kurz } 587c80cd6bbSGreg Kurz 588705df546SJason Wang int qemu_can_receive_packet(NetClientState *nc) 589705df546SJason Wang { 590705df546SJason Wang if (nc->receive_disabled) { 591705df546SJason Wang return 0; 592705df546SJason Wang } else if (nc->info->can_receive && 593705df546SJason Wang !nc->info->can_receive(nc)) { 594705df546SJason Wang return 0; 595705df546SJason Wang } 596705df546SJason Wang return 1; 597705df546SJason Wang } 598705df546SJason Wang 599fd9400b3SPaolo Bonzini int qemu_can_send_packet(NetClientState *sender) 600fd9400b3SPaolo Bonzini { 601e1d64c08Szhanghailiang int vm_running = runstate_is_running(); 602e1d64c08Szhanghailiang 603e1d64c08Szhanghailiang if (!vm_running) { 604e1d64c08Szhanghailiang return 0; 605e1d64c08Szhanghailiang } 606e1d64c08Szhanghailiang 607fd9400b3SPaolo Bonzini if (!sender->peer) { 608fd9400b3SPaolo Bonzini return 1; 609fd9400b3SPaolo Bonzini } 610fd9400b3SPaolo Bonzini 611705df546SJason Wang return qemu_can_receive_packet(sender->peer); 612fd9400b3SPaolo Bonzini } 613fd9400b3SPaolo Bonzini 614e64c770dSYang Hongyang static ssize_t filter_receive_iov(NetClientState *nc, 615e64c770dSYang Hongyang NetFilterDirection direction, 616e64c770dSYang Hongyang NetClientState *sender, 617e64c770dSYang Hongyang unsigned flags, 618e64c770dSYang Hongyang const struct iovec *iov, 619e64c770dSYang Hongyang int iovcnt, 620e64c770dSYang Hongyang NetPacketSent *sent_cb) 621e64c770dSYang Hongyang { 622e64c770dSYang Hongyang ssize_t ret = 0; 623e64c770dSYang Hongyang NetFilterState *nf = NULL; 624e64c770dSYang Hongyang 62525aaadf0SLi Zhijian if (direction == NET_FILTER_DIRECTION_TX) { 626e64c770dSYang Hongyang QTAILQ_FOREACH(nf, &nc->filters, next) { 627e64c770dSYang Hongyang ret = qemu_netfilter_receive(nf, direction, sender, flags, iov, 628e64c770dSYang Hongyang iovcnt, sent_cb); 629e64c770dSYang Hongyang if (ret) { 630e64c770dSYang Hongyang return ret; 631e64c770dSYang Hongyang } 632e64c770dSYang Hongyang } 63325aaadf0SLi Zhijian } else { 634eae3eb3eSPaolo Bonzini QTAILQ_FOREACH_REVERSE(nf, &nc->filters, next) { 63525aaadf0SLi Zhijian ret = qemu_netfilter_receive(nf, direction, sender, flags, iov, 63625aaadf0SLi Zhijian iovcnt, sent_cb); 63725aaadf0SLi Zhijian if (ret) { 63825aaadf0SLi Zhijian return ret; 63925aaadf0SLi Zhijian } 64025aaadf0SLi Zhijian } 64125aaadf0SLi Zhijian } 642e64c770dSYang Hongyang 643e64c770dSYang Hongyang return ret; 644e64c770dSYang Hongyang } 645e64c770dSYang Hongyang 646e64c770dSYang Hongyang static ssize_t filter_receive(NetClientState *nc, 647e64c770dSYang Hongyang NetFilterDirection direction, 648e64c770dSYang Hongyang NetClientState *sender, 649e64c770dSYang Hongyang unsigned flags, 650e64c770dSYang Hongyang const uint8_t *data, 651e64c770dSYang Hongyang size_t size, 652e64c770dSYang Hongyang NetPacketSent *sent_cb) 653e64c770dSYang Hongyang { 654e64c770dSYang Hongyang struct iovec iov = { 655e64c770dSYang Hongyang .iov_base = (void *)data, 656e64c770dSYang Hongyang .iov_len = size 657e64c770dSYang Hongyang }; 658e64c770dSYang Hongyang 659e64c770dSYang Hongyang return filter_receive_iov(nc, direction, sender, flags, &iov, 1, sent_cb); 660e64c770dSYang Hongyang } 661e64c770dSYang Hongyang 662fd9400b3SPaolo Bonzini void qemu_purge_queued_packets(NetClientState *nc) 663fd9400b3SPaolo Bonzini { 664fd9400b3SPaolo Bonzini if (!nc->peer) { 665fd9400b3SPaolo Bonzini return; 666fd9400b3SPaolo Bonzini } 667fd9400b3SPaolo Bonzini 668067404beSJan Kiszka qemu_net_queue_purge(nc->peer->incoming_queue, nc); 669fd9400b3SPaolo Bonzini } 670fd9400b3SPaolo Bonzini 671ca77d85eSMichael S. Tsirkin void qemu_flush_or_purge_queued_packets(NetClientState *nc, bool purge) 672fd9400b3SPaolo Bonzini { 673fd9400b3SPaolo Bonzini nc->receive_disabled = 0; 674fd9400b3SPaolo Bonzini 675f394b2e2SEric Blake if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_HUBPORT) { 676199ee608SLuigi Rizzo if (net_hub_flush(nc->peer)) { 677199ee608SLuigi Rizzo qemu_notify_event(); 678199ee608SLuigi Rizzo } 679199ee608SLuigi Rizzo } 680067404beSJan Kiszka if (qemu_net_queue_flush(nc->incoming_queue)) { 681fd9400b3SPaolo Bonzini /* We emptied the queue successfully, signal to the IO thread to repoll 682fd9400b3SPaolo Bonzini * the file descriptor (for tap, for example). 683fd9400b3SPaolo Bonzini */ 684fd9400b3SPaolo Bonzini qemu_notify_event(); 685ca77d85eSMichael S. Tsirkin } else if (purge) { 686ca77d85eSMichael S. Tsirkin /* Unable to empty the queue, purge remaining packets */ 6875fe19fb8SJason Wang qemu_net_queue_purge(nc->incoming_queue, nc->peer); 688fd9400b3SPaolo Bonzini } 689fd9400b3SPaolo Bonzini } 690fd9400b3SPaolo Bonzini 691ca77d85eSMichael S. Tsirkin void qemu_flush_queued_packets(NetClientState *nc) 692ca77d85eSMichael S. Tsirkin { 693ca77d85eSMichael S. Tsirkin qemu_flush_or_purge_queued_packets(nc, false); 694ca77d85eSMichael S. Tsirkin } 695ca77d85eSMichael S. Tsirkin 696fd9400b3SPaolo Bonzini static ssize_t qemu_send_packet_async_with_flags(NetClientState *sender, 697fd9400b3SPaolo Bonzini unsigned flags, 698fd9400b3SPaolo Bonzini const uint8_t *buf, int size, 699fd9400b3SPaolo Bonzini NetPacketSent *sent_cb) 700fd9400b3SPaolo Bonzini { 701fd9400b3SPaolo Bonzini NetQueue *queue; 702e64c770dSYang Hongyang int ret; 703fd9400b3SPaolo Bonzini 704fd9400b3SPaolo Bonzini #ifdef DEBUG_NET 705fd9400b3SPaolo Bonzini printf("qemu_send_packet_async:\n"); 706b42581f5SPhilippe Mathieu-Daudé qemu_hexdump(stdout, "net", buf, size); 707fd9400b3SPaolo Bonzini #endif 708fd9400b3SPaolo Bonzini 709fd9400b3SPaolo Bonzini if (sender->link_down || !sender->peer) { 710fd9400b3SPaolo Bonzini return size; 711fd9400b3SPaolo Bonzini } 712fd9400b3SPaolo Bonzini 713e64c770dSYang Hongyang /* Let filters handle the packet first */ 714e64c770dSYang Hongyang ret = filter_receive(sender, NET_FILTER_DIRECTION_TX, 715e64c770dSYang Hongyang sender, flags, buf, size, sent_cb); 716e64c770dSYang Hongyang if (ret) { 717e64c770dSYang Hongyang return ret; 718e64c770dSYang Hongyang } 719e64c770dSYang Hongyang 720e64c770dSYang Hongyang ret = filter_receive(sender->peer, NET_FILTER_DIRECTION_RX, 721e64c770dSYang Hongyang sender, flags, buf, size, sent_cb); 722e64c770dSYang Hongyang if (ret) { 723e64c770dSYang Hongyang return ret; 724e64c770dSYang Hongyang } 725e64c770dSYang Hongyang 726067404beSJan Kiszka queue = sender->peer->incoming_queue; 727fd9400b3SPaolo Bonzini 728fd9400b3SPaolo Bonzini return qemu_net_queue_send(queue, sender, flags, buf, size, sent_cb); 729fd9400b3SPaolo Bonzini } 730fd9400b3SPaolo Bonzini 731fd9400b3SPaolo Bonzini ssize_t qemu_send_packet_async(NetClientState *sender, 732fd9400b3SPaolo Bonzini const uint8_t *buf, int size, 733fd9400b3SPaolo Bonzini NetPacketSent *sent_cb) 734fd9400b3SPaolo Bonzini { 735fd9400b3SPaolo Bonzini return qemu_send_packet_async_with_flags(sender, QEMU_NET_PACKET_FLAG_NONE, 736fd9400b3SPaolo Bonzini buf, size, sent_cb); 737fd9400b3SPaolo Bonzini } 738fd9400b3SPaolo Bonzini 739625a526bSMarc-André Lureau ssize_t qemu_send_packet(NetClientState *nc, const uint8_t *buf, int size) 740fd9400b3SPaolo Bonzini { 741625a526bSMarc-André Lureau return qemu_send_packet_async(nc, buf, size, NULL); 742fd9400b3SPaolo Bonzini } 743fd9400b3SPaolo Bonzini 744705df546SJason Wang ssize_t qemu_receive_packet(NetClientState *nc, const uint8_t *buf, int size) 745705df546SJason Wang { 746705df546SJason Wang if (!qemu_can_receive_packet(nc)) { 747705df546SJason Wang return 0; 748705df546SJason Wang } 749705df546SJason Wang 750705df546SJason Wang return qemu_net_queue_receive(nc->incoming_queue, buf, size); 751705df546SJason Wang } 752705df546SJason Wang 753705df546SJason Wang ssize_t qemu_receive_packet_iov(NetClientState *nc, const struct iovec *iov, 754705df546SJason Wang int iovcnt) 755705df546SJason Wang { 756705df546SJason Wang if (!qemu_can_receive_packet(nc)) { 757705df546SJason Wang return 0; 758705df546SJason Wang } 759705df546SJason Wang 760705df546SJason Wang return qemu_net_queue_receive_iov(nc->incoming_queue, iov, iovcnt); 761705df546SJason Wang } 762705df546SJason Wang 763fd9400b3SPaolo Bonzini ssize_t qemu_send_packet_raw(NetClientState *nc, const uint8_t *buf, int size) 764fd9400b3SPaolo Bonzini { 765fd9400b3SPaolo Bonzini return qemu_send_packet_async_with_flags(nc, QEMU_NET_PACKET_FLAG_RAW, 766fd9400b3SPaolo Bonzini buf, size, NULL); 767fd9400b3SPaolo Bonzini } 768fd9400b3SPaolo Bonzini 769fd9400b3SPaolo Bonzini static ssize_t nc_sendv_compat(NetClientState *nc, const struct iovec *iov, 770fefe2a78SYang Hongyang int iovcnt, unsigned flags) 771fd9400b3SPaolo Bonzini { 77274044c8fSPooja Dhannawat uint8_t *buf = NULL; 773fefe2a78SYang Hongyang uint8_t *buffer; 774fd9400b3SPaolo Bonzini size_t offset; 77574044c8fSPooja Dhannawat ssize_t ret; 776fd9400b3SPaolo Bonzini 777fefe2a78SYang Hongyang if (iovcnt == 1) { 778fefe2a78SYang Hongyang buffer = iov[0].iov_base; 779fefe2a78SYang Hongyang offset = iov[0].iov_len; 780fefe2a78SYang Hongyang } else { 78147f9f158SPeter Lieven offset = iov_size(iov, iovcnt); 78247f9f158SPeter Lieven if (offset > NET_BUFSIZE) { 78347f9f158SPeter Lieven return -1; 78447f9f158SPeter Lieven } 78547f9f158SPeter Lieven buf = g_malloc(offset); 786fefe2a78SYang Hongyang buffer = buf; 78747f9f158SPeter Lieven offset = iov_to_buf(iov, iovcnt, 0, buf, offset); 788fefe2a78SYang Hongyang } 789fd9400b3SPaolo Bonzini 790fefe2a78SYang Hongyang if (flags & QEMU_NET_PACKET_FLAG_RAW && nc->info->receive_raw) { 79174044c8fSPooja Dhannawat ret = nc->info->receive_raw(nc, buffer, offset); 792fefe2a78SYang Hongyang } else { 79374044c8fSPooja Dhannawat ret = nc->info->receive(nc, buffer, offset); 794fd9400b3SPaolo Bonzini } 79574044c8fSPooja Dhannawat 79674044c8fSPooja Dhannawat g_free(buf); 79774044c8fSPooja Dhannawat return ret; 798fefe2a78SYang Hongyang } 799fd9400b3SPaolo Bonzini 80025c01bd1SJason Wang static ssize_t qemu_deliver_packet_iov(NetClientState *sender, 801fd9400b3SPaolo Bonzini unsigned flags, 802fd9400b3SPaolo Bonzini const struct iovec *iov, 803fd9400b3SPaolo Bonzini int iovcnt, 804fd9400b3SPaolo Bonzini void *opaque) 805fd9400b3SPaolo Bonzini { 8069050f976SAkihiko Odaki MemReentrancyGuard *owned_reentrancy_guard; 807fd9400b3SPaolo Bonzini NetClientState *nc = opaque; 808fd9400b3SPaolo Bonzini int ret; 809fd9400b3SPaolo Bonzini 8101592a994SJason Wang 811fd9400b3SPaolo Bonzini if (nc->link_down) { 81225c01bd1SJason Wang return iov_size(iov, iovcnt); 813fd9400b3SPaolo Bonzini } 814fd9400b3SPaolo Bonzini 815fd9400b3SPaolo Bonzini if (nc->receive_disabled) { 816fd9400b3SPaolo Bonzini return 0; 817fd9400b3SPaolo Bonzini } 818fd9400b3SPaolo Bonzini 8199050f976SAkihiko Odaki if (nc->info->type != NET_CLIENT_DRIVER_NIC || 8209050f976SAkihiko Odaki qemu_get_nic(nc)->reentrancy_guard->engaged_in_io) { 8219050f976SAkihiko Odaki owned_reentrancy_guard = NULL; 8229050f976SAkihiko Odaki } else { 8239050f976SAkihiko Odaki owned_reentrancy_guard = qemu_get_nic(nc)->reentrancy_guard; 8249050f976SAkihiko Odaki owned_reentrancy_guard->engaged_in_io = true; 8259050f976SAkihiko Odaki } 8269050f976SAkihiko Odaki 827ca1ee3d6SPeter Lieven if (nc->info->receive_iov && !(flags & QEMU_NET_PACKET_FLAG_RAW)) { 828fd9400b3SPaolo Bonzini ret = nc->info->receive_iov(nc, iov, iovcnt); 829fd9400b3SPaolo Bonzini } else { 830fefe2a78SYang Hongyang ret = nc_sendv_compat(nc, iov, iovcnt, flags); 831fd9400b3SPaolo Bonzini } 832fd9400b3SPaolo Bonzini 8339050f976SAkihiko Odaki if (owned_reentrancy_guard) { 8349050f976SAkihiko Odaki owned_reentrancy_guard->engaged_in_io = false; 8359050f976SAkihiko Odaki } 8369050f976SAkihiko Odaki 837fd9400b3SPaolo Bonzini if (ret == 0) { 838fd9400b3SPaolo Bonzini nc->receive_disabled = 1; 839fd9400b3SPaolo Bonzini } 840fd9400b3SPaolo Bonzini 841fd9400b3SPaolo Bonzini return ret; 842fd9400b3SPaolo Bonzini } 843fd9400b3SPaolo Bonzini 844fd9400b3SPaolo Bonzini ssize_t qemu_sendv_packet_async(NetClientState *sender, 845fd9400b3SPaolo Bonzini const struct iovec *iov, int iovcnt, 846fd9400b3SPaolo Bonzini NetPacketSent *sent_cb) 847fd9400b3SPaolo Bonzini { 848fd9400b3SPaolo Bonzini NetQueue *queue; 84925c01bd1SJason Wang size_t size = iov_size(iov, iovcnt); 850e64c770dSYang Hongyang int ret; 851fd9400b3SPaolo Bonzini 85225c01bd1SJason Wang if (size > NET_BUFSIZE) { 85325c01bd1SJason Wang return size; 85425c01bd1SJason Wang } 85525c01bd1SJason Wang 856fd9400b3SPaolo Bonzini if (sender->link_down || !sender->peer) { 85725c01bd1SJason Wang return size; 858fd9400b3SPaolo Bonzini } 859fd9400b3SPaolo Bonzini 860e64c770dSYang Hongyang /* Let filters handle the packet first */ 861e64c770dSYang Hongyang ret = filter_receive_iov(sender, NET_FILTER_DIRECTION_TX, sender, 862e64c770dSYang Hongyang QEMU_NET_PACKET_FLAG_NONE, iov, iovcnt, sent_cb); 863e64c770dSYang Hongyang if (ret) { 864e64c770dSYang Hongyang return ret; 865e64c770dSYang Hongyang } 866e64c770dSYang Hongyang 867e64c770dSYang Hongyang ret = filter_receive_iov(sender->peer, NET_FILTER_DIRECTION_RX, sender, 868e64c770dSYang Hongyang QEMU_NET_PACKET_FLAG_NONE, iov, iovcnt, sent_cb); 869e64c770dSYang Hongyang if (ret) { 870e64c770dSYang Hongyang return ret; 871e64c770dSYang Hongyang } 872e64c770dSYang Hongyang 873067404beSJan Kiszka queue = sender->peer->incoming_queue; 874fd9400b3SPaolo Bonzini 875fd9400b3SPaolo Bonzini return qemu_net_queue_send_iov(queue, sender, 876fd9400b3SPaolo Bonzini QEMU_NET_PACKET_FLAG_NONE, 877fd9400b3SPaolo Bonzini iov, iovcnt, sent_cb); 878fd9400b3SPaolo Bonzini } 879fd9400b3SPaolo Bonzini 880fd9400b3SPaolo Bonzini ssize_t 881fd9400b3SPaolo Bonzini qemu_sendv_packet(NetClientState *nc, const struct iovec *iov, int iovcnt) 882fd9400b3SPaolo Bonzini { 883fd9400b3SPaolo Bonzini return qemu_sendv_packet_async(nc, iov, iovcnt, NULL); 884fd9400b3SPaolo Bonzini } 885fd9400b3SPaolo Bonzini 886fd9400b3SPaolo Bonzini NetClientState *qemu_find_netdev(const char *id) 887fd9400b3SPaolo Bonzini { 888fd9400b3SPaolo Bonzini NetClientState *nc; 889fd9400b3SPaolo Bonzini 890fd9400b3SPaolo Bonzini QTAILQ_FOREACH(nc, &net_clients, next) { 891f394b2e2SEric Blake if (nc->info->type == NET_CLIENT_DRIVER_NIC) 892fd9400b3SPaolo Bonzini continue; 893fd9400b3SPaolo Bonzini if (!strcmp(nc->name, id)) { 894fd9400b3SPaolo Bonzini return nc; 895fd9400b3SPaolo Bonzini } 896fd9400b3SPaolo Bonzini } 897fd9400b3SPaolo Bonzini 898fd9400b3SPaolo Bonzini return NULL; 899fd9400b3SPaolo Bonzini } 900fd9400b3SPaolo Bonzini 9016c51ae73SJason Wang int qemu_find_net_clients_except(const char *id, NetClientState **ncs, 902f394b2e2SEric Blake NetClientDriver type, int max) 9036c51ae73SJason Wang { 9046c51ae73SJason Wang NetClientState *nc; 9056c51ae73SJason Wang int ret = 0; 9066c51ae73SJason Wang 9076c51ae73SJason Wang QTAILQ_FOREACH(nc, &net_clients, next) { 9086c51ae73SJason Wang if (nc->info->type == type) { 9096c51ae73SJason Wang continue; 9106c51ae73SJason Wang } 91140d19394SHani Benhabiles if (!id || !strcmp(nc->name, id)) { 9126c51ae73SJason Wang if (ret < max) { 9136c51ae73SJason Wang ncs[ret] = nc; 9146c51ae73SJason Wang } 9156c51ae73SJason Wang ret++; 9166c51ae73SJason Wang } 9176c51ae73SJason Wang } 9186c51ae73SJason Wang 9196c51ae73SJason Wang return ret; 9206c51ae73SJason Wang } 9216c51ae73SJason Wang 922fd9400b3SPaolo Bonzini static int nic_get_free_idx(void) 923fd9400b3SPaolo Bonzini { 924fd9400b3SPaolo Bonzini int index; 925fd9400b3SPaolo Bonzini 926fd9400b3SPaolo Bonzini for (index = 0; index < MAX_NICS; index++) 927fd9400b3SPaolo Bonzini if (!nd_table[index].used) 928fd9400b3SPaolo Bonzini return index; 929fd9400b3SPaolo Bonzini return -1; 930fd9400b3SPaolo Bonzini } 931fd9400b3SPaolo Bonzini 932c6941b3bSThomas Huth GPtrArray *qemu_get_nic_models(const char *device_type) 933c6941b3bSThomas Huth { 934c6941b3bSThomas Huth GPtrArray *nic_models = g_ptr_array_new(); 935c6941b3bSThomas Huth GSList *list = object_class_get_list_sorted(device_type, false); 936c6941b3bSThomas Huth 937c6941b3bSThomas Huth while (list) { 938c6941b3bSThomas Huth DeviceClass *dc = OBJECT_CLASS_CHECK(DeviceClass, list->data, 939c6941b3bSThomas Huth TYPE_DEVICE); 940c6941b3bSThomas Huth GSList *next; 941c6941b3bSThomas Huth if (test_bit(DEVICE_CATEGORY_NETWORK, dc->categories) && 942c6941b3bSThomas Huth dc->user_creatable) { 943c6941b3bSThomas Huth const char *name = object_class_get_name(list->data); 944c6941b3bSThomas Huth /* 945c6941b3bSThomas Huth * A network device might also be something else than a NIC, see 946c6941b3bSThomas Huth * e.g. the "rocker" device. Thus we have to look for the "netdev" 947c6941b3bSThomas Huth * property, too. Unfortunately, some devices like virtio-net only 948c6941b3bSThomas Huth * create this property during instance_init, so we have to create 949c6941b3bSThomas Huth * a temporary instance here to be able to check it. 950c6941b3bSThomas Huth */ 951c6941b3bSThomas Huth Object *obj = object_new_with_class(OBJECT_CLASS(dc)); 952c6941b3bSThomas Huth if (object_property_find(obj, "netdev")) { 953c6941b3bSThomas Huth g_ptr_array_add(nic_models, (gpointer)name); 954c6941b3bSThomas Huth } 955c6941b3bSThomas Huth object_unref(obj); 956c6941b3bSThomas Huth } 957c6941b3bSThomas Huth next = list->next; 958c6941b3bSThomas Huth g_slist_free_1(list); 959c6941b3bSThomas Huth list = next; 960c6941b3bSThomas Huth } 961c6941b3bSThomas Huth g_ptr_array_add(nic_models, NULL); 962c6941b3bSThomas Huth 963c6941b3bSThomas Huth return nic_models; 964c6941b3bSThomas Huth } 965c6941b3bSThomas Huth 966cebea510SKővágó, Zoltán static int net_init_nic(const Netdev *netdev, const char *name, 967a30ecde6SMarkus Armbruster NetClientState *peer, Error **errp) 968fd9400b3SPaolo Bonzini { 969fd9400b3SPaolo Bonzini int idx; 970fd9400b3SPaolo Bonzini NICInfo *nd; 971fd9400b3SPaolo Bonzini const NetLegacyNicOptions *nic; 972fd9400b3SPaolo Bonzini 973f394b2e2SEric Blake assert(netdev->type == NET_CLIENT_DRIVER_NIC); 974f394b2e2SEric Blake nic = &netdev->u.nic; 975fd9400b3SPaolo Bonzini 976fd9400b3SPaolo Bonzini idx = nic_get_free_idx(); 977fd9400b3SPaolo Bonzini if (idx == -1 || nb_nics >= MAX_NICS) { 97866308868SMarkus Armbruster error_setg(errp, "too many NICs"); 979fd9400b3SPaolo Bonzini return -1; 980fd9400b3SPaolo Bonzini } 981fd9400b3SPaolo Bonzini 982fd9400b3SPaolo Bonzini nd = &nd_table[idx]; 983fd9400b3SPaolo Bonzini 984fd9400b3SPaolo Bonzini memset(nd, 0, sizeof(*nd)); 985fd9400b3SPaolo Bonzini 9867480874aSMarkus Armbruster if (nic->netdev) { 987fd9400b3SPaolo Bonzini nd->netdev = qemu_find_netdev(nic->netdev); 988fd9400b3SPaolo Bonzini if (!nd->netdev) { 98966308868SMarkus Armbruster error_setg(errp, "netdev '%s' not found", nic->netdev); 990fd9400b3SPaolo Bonzini return -1; 991fd9400b3SPaolo Bonzini } 992fd9400b3SPaolo Bonzini } else { 993fd9400b3SPaolo Bonzini assert(peer); 994fd9400b3SPaolo Bonzini nd->netdev = peer; 995fd9400b3SPaolo Bonzini } 996fd9400b3SPaolo Bonzini nd->name = g_strdup(name); 9977480874aSMarkus Armbruster if (nic->model) { 998fd9400b3SPaolo Bonzini nd->model = g_strdup(nic->model); 999fd9400b3SPaolo Bonzini } 10007480874aSMarkus Armbruster if (nic->addr) { 1001fd9400b3SPaolo Bonzini nd->devaddr = g_strdup(nic->addr); 1002fd9400b3SPaolo Bonzini } 1003fd9400b3SPaolo Bonzini 10047480874aSMarkus Armbruster if (nic->macaddr && 1005fd9400b3SPaolo Bonzini net_parse_macaddr(nd->macaddr.a, nic->macaddr) < 0) { 100666308868SMarkus Armbruster error_setg(errp, "invalid syntax for ethernet address"); 1007fd9400b3SPaolo Bonzini return -1; 1008fd9400b3SPaolo Bonzini } 10097480874aSMarkus Armbruster if (nic->macaddr && 1010d60b20cfSDmitry Krivenok is_multicast_ether_addr(nd->macaddr.a)) { 101166308868SMarkus Armbruster error_setg(errp, 101266308868SMarkus Armbruster "NIC cannot have multicast MAC address (odd 1st byte)"); 1013d60b20cfSDmitry Krivenok return -1; 1014d60b20cfSDmitry Krivenok } 1015fd9400b3SPaolo Bonzini qemu_macaddr_default_if_unset(&nd->macaddr); 1016fd9400b3SPaolo Bonzini 1017fd9400b3SPaolo Bonzini if (nic->has_vectors) { 1018fd9400b3SPaolo Bonzini if (nic->vectors > 0x7ffffff) { 101966308868SMarkus Armbruster error_setg(errp, "invalid # of vectors: %"PRIu32, nic->vectors); 1020fd9400b3SPaolo Bonzini return -1; 1021fd9400b3SPaolo Bonzini } 1022fd9400b3SPaolo Bonzini nd->nvectors = nic->vectors; 1023fd9400b3SPaolo Bonzini } else { 1024fd9400b3SPaolo Bonzini nd->nvectors = DEV_NVECTORS_UNSPECIFIED; 1025fd9400b3SPaolo Bonzini } 1026fd9400b3SPaolo Bonzini 1027fd9400b3SPaolo Bonzini nd->used = 1; 1028fd9400b3SPaolo Bonzini nb_nics++; 1029fd9400b3SPaolo Bonzini 1030fd9400b3SPaolo Bonzini return idx; 1031fd9400b3SPaolo Bonzini } 1032fd9400b3SPaolo Bonzini 10332cdeca04SDavid Woodhouse static gboolean add_nic_result(gpointer key, gpointer value, gpointer user_data) 10342cdeca04SDavid Woodhouse { 10352cdeca04SDavid Woodhouse GPtrArray *results = user_data; 10362cdeca04SDavid Woodhouse GPtrArray *alias_list = value; 10372cdeca04SDavid Woodhouse const char *model = key; 10382cdeca04SDavid Woodhouse char *result; 10392cdeca04SDavid Woodhouse 10402cdeca04SDavid Woodhouse if (!alias_list) { 10412cdeca04SDavid Woodhouse result = g_strdup(model); 10422cdeca04SDavid Woodhouse } else { 10432cdeca04SDavid Woodhouse GString *result_str = g_string_new(model); 10442cdeca04SDavid Woodhouse int i; 10452cdeca04SDavid Woodhouse 10462cdeca04SDavid Woodhouse g_string_append(result_str, " (aka "); 10472cdeca04SDavid Woodhouse for (i = 0; i < alias_list->len; i++) { 10482cdeca04SDavid Woodhouse if (i) { 10492cdeca04SDavid Woodhouse g_string_append(result_str, ", "); 10502cdeca04SDavid Woodhouse } 10512cdeca04SDavid Woodhouse g_string_append(result_str, alias_list->pdata[i]); 10522cdeca04SDavid Woodhouse } 10532cdeca04SDavid Woodhouse g_string_append(result_str, ")"); 10542cdeca04SDavid Woodhouse result = result_str->str; 10552cdeca04SDavid Woodhouse g_string_free(result_str, false); 10562cdeca04SDavid Woodhouse g_ptr_array_unref(alias_list); 10572cdeca04SDavid Woodhouse } 10582cdeca04SDavid Woodhouse g_ptr_array_add(results, result); 10592cdeca04SDavid Woodhouse return true; 10602cdeca04SDavid Woodhouse } 10612cdeca04SDavid Woodhouse 10622cdeca04SDavid Woodhouse static int model_cmp(char **a, char **b) 10632cdeca04SDavid Woodhouse { 10642cdeca04SDavid Woodhouse return strcmp(*a, *b); 10652cdeca04SDavid Woodhouse } 10662cdeca04SDavid Woodhouse 10672cdeca04SDavid Woodhouse static void show_nic_models(void) 10682cdeca04SDavid Woodhouse { 10692cdeca04SDavid Woodhouse GPtrArray *results = g_ptr_array_new(); 10702cdeca04SDavid Woodhouse int i; 10712cdeca04SDavid Woodhouse 10722cdeca04SDavid Woodhouse g_hash_table_foreach_remove(nic_model_help, add_nic_result, results); 10732cdeca04SDavid Woodhouse g_ptr_array_sort(results, (GCompareFunc)model_cmp); 10742cdeca04SDavid Woodhouse 10752cdeca04SDavid Woodhouse printf("Available NIC models for this configuration:\n"); 10762cdeca04SDavid Woodhouse for (i = 0 ; i < results->len; i++) { 10772cdeca04SDavid Woodhouse printf("%s\n", (char *)results->pdata[i]); 10782cdeca04SDavid Woodhouse } 10792cdeca04SDavid Woodhouse g_hash_table_unref(nic_model_help); 10802cdeca04SDavid Woodhouse nic_model_help = NULL; 10812cdeca04SDavid Woodhouse } 10822cdeca04SDavid Woodhouse 10832cdeca04SDavid Woodhouse static void add_nic_model_help(const char *model, const char *alias) 10842cdeca04SDavid Woodhouse { 10852cdeca04SDavid Woodhouse GPtrArray *alias_list = NULL; 10862cdeca04SDavid Woodhouse 10872cdeca04SDavid Woodhouse if (g_hash_table_lookup_extended(nic_model_help, model, NULL, 10882cdeca04SDavid Woodhouse (gpointer *)&alias_list)) { 10892cdeca04SDavid Woodhouse /* Already exists, no alias to add: return */ 10902cdeca04SDavid Woodhouse if (!alias) { 10912cdeca04SDavid Woodhouse return; 10922cdeca04SDavid Woodhouse } 10932cdeca04SDavid Woodhouse if (alias_list) { 10942cdeca04SDavid Woodhouse /* Check if this alias is already in the list. Add if not. */ 10952cdeca04SDavid Woodhouse if (!g_ptr_array_find_with_equal_func(alias_list, alias, 10962cdeca04SDavid Woodhouse g_str_equal, NULL)) { 10972cdeca04SDavid Woodhouse g_ptr_array_add(alias_list, g_strdup(alias)); 10982cdeca04SDavid Woodhouse } 10992cdeca04SDavid Woodhouse return; 11002cdeca04SDavid Woodhouse } 11012cdeca04SDavid Woodhouse } 11022cdeca04SDavid Woodhouse /* Either this model wasn't in the list already, or a first alias added */ 11032cdeca04SDavid Woodhouse if (alias) { 11042cdeca04SDavid Woodhouse alias_list = g_ptr_array_new(); 11052cdeca04SDavid Woodhouse g_ptr_array_set_free_func(alias_list, g_free); 11062cdeca04SDavid Woodhouse g_ptr_array_add(alias_list, g_strdup(alias)); 11072cdeca04SDavid Woodhouse } 11082cdeca04SDavid Woodhouse g_hash_table_replace(nic_model_help, g_strdup(model), alias_list); 11092cdeca04SDavid Woodhouse } 11102cdeca04SDavid Woodhouse 111193e9d730SDavid Woodhouse NICInfo *qemu_find_nic_info(const char *typename, bool match_default, 111293e9d730SDavid Woodhouse const char *alias) 111393e9d730SDavid Woodhouse { 111493e9d730SDavid Woodhouse NICInfo *nd; 111593e9d730SDavid Woodhouse int i; 111693e9d730SDavid Woodhouse 11172cdeca04SDavid Woodhouse if (nic_model_help) { 11182cdeca04SDavid Woodhouse add_nic_model_help(typename, alias); 11192cdeca04SDavid Woodhouse } 11202cdeca04SDavid Woodhouse 112193e9d730SDavid Woodhouse for (i = 0; i < nb_nics; i++) { 112293e9d730SDavid Woodhouse nd = &nd_table[i]; 112393e9d730SDavid Woodhouse 112493e9d730SDavid Woodhouse if (!nd->used || nd->instantiated) { 112593e9d730SDavid Woodhouse continue; 112693e9d730SDavid Woodhouse } 112793e9d730SDavid Woodhouse 112893e9d730SDavid Woodhouse if ((match_default && !nd->model) || !g_strcmp0(nd->model, typename) 112993e9d730SDavid Woodhouse || (alias && !g_strcmp0(nd->model, alias))) { 113093e9d730SDavid Woodhouse return nd; 113193e9d730SDavid Woodhouse } 113293e9d730SDavid Woodhouse } 113393e9d730SDavid Woodhouse return NULL; 113493e9d730SDavid Woodhouse } 113593e9d730SDavid Woodhouse 113693e9d730SDavid Woodhouse 113793e9d730SDavid Woodhouse /* "I have created a device. Please configure it if you can" */ 113893e9d730SDavid Woodhouse bool qemu_configure_nic_device(DeviceState *dev, bool match_default, 113993e9d730SDavid Woodhouse const char *alias) 114093e9d730SDavid Woodhouse { 114193e9d730SDavid Woodhouse NICInfo *nd = qemu_find_nic_info(object_get_typename(OBJECT(dev)), 114293e9d730SDavid Woodhouse match_default, alias); 114393e9d730SDavid Woodhouse 114493e9d730SDavid Woodhouse if (nd) { 114593e9d730SDavid Woodhouse qdev_set_nic_properties(dev, nd); 114693e9d730SDavid Woodhouse return true; 114793e9d730SDavid Woodhouse } 114893e9d730SDavid Woodhouse return false; 114993e9d730SDavid Woodhouse } 115093e9d730SDavid Woodhouse 115193e9d730SDavid Woodhouse /* "Please create a device, if you have a configuration for it" */ 115293e9d730SDavid Woodhouse DeviceState *qemu_create_nic_device(const char *typename, bool match_default, 115393e9d730SDavid Woodhouse const char *alias) 115493e9d730SDavid Woodhouse { 115593e9d730SDavid Woodhouse NICInfo *nd = qemu_find_nic_info(typename, match_default, alias); 115693e9d730SDavid Woodhouse DeviceState *dev; 115793e9d730SDavid Woodhouse 115893e9d730SDavid Woodhouse if (!nd) { 115993e9d730SDavid Woodhouse return NULL; 116093e9d730SDavid Woodhouse } 116193e9d730SDavid Woodhouse 116293e9d730SDavid Woodhouse dev = qdev_new(typename); 116393e9d730SDavid Woodhouse qdev_set_nic_properties(dev, nd); 116493e9d730SDavid Woodhouse return dev; 116593e9d730SDavid Woodhouse } 1166fd9400b3SPaolo Bonzini 116793125e4bSDavid Woodhouse void qemu_create_nic_bus_devices(BusState *bus, const char *parent_type, 116893125e4bSDavid Woodhouse const char *default_model, 116993125e4bSDavid Woodhouse const char *alias, const char *alias_target) 117093125e4bSDavid Woodhouse { 117193125e4bSDavid Woodhouse GPtrArray *nic_models = qemu_get_nic_models(parent_type); 117293125e4bSDavid Woodhouse const char *model; 117393125e4bSDavid Woodhouse DeviceState *dev; 117493125e4bSDavid Woodhouse NICInfo *nd; 117593125e4bSDavid Woodhouse int i; 117693125e4bSDavid Woodhouse 117793125e4bSDavid Woodhouse if (nic_model_help) { 117893125e4bSDavid Woodhouse if (alias_target) { 117993125e4bSDavid Woodhouse add_nic_model_help(alias_target, alias); 118093125e4bSDavid Woodhouse } 118193125e4bSDavid Woodhouse for (i = 0; i < nic_models->len - 1; i++) { 118293125e4bSDavid Woodhouse add_nic_model_help(nic_models->pdata[i], NULL); 118393125e4bSDavid Woodhouse } 118493125e4bSDavid Woodhouse } 118593125e4bSDavid Woodhouse 118693125e4bSDavid Woodhouse /* Drop the NULL terminator which would make g_str_equal() unhappy */ 118793125e4bSDavid Woodhouse nic_models->len--; 118893125e4bSDavid Woodhouse 118993125e4bSDavid Woodhouse for (i = 0; i < nb_nics; i++) { 119093125e4bSDavid Woodhouse nd = &nd_table[i]; 119193125e4bSDavid Woodhouse 119293125e4bSDavid Woodhouse if (!nd->used || nd->instantiated) { 119393125e4bSDavid Woodhouse continue; 119493125e4bSDavid Woodhouse } 119593125e4bSDavid Woodhouse 119693125e4bSDavid Woodhouse model = nd->model ? nd->model : default_model; 119793125e4bSDavid Woodhouse if (!model) { 119893125e4bSDavid Woodhouse continue; 119993125e4bSDavid Woodhouse } 120093125e4bSDavid Woodhouse 120193125e4bSDavid Woodhouse /* Each bus type is allowed *one* substitution */ 120293125e4bSDavid Woodhouse if (g_str_equal(model, alias)) { 120393125e4bSDavid Woodhouse model = alias_target; 120493125e4bSDavid Woodhouse } 120593125e4bSDavid Woodhouse 120693125e4bSDavid Woodhouse if (!g_ptr_array_find_with_equal_func(nic_models, model, 120793125e4bSDavid Woodhouse g_str_equal, NULL)) { 120893125e4bSDavid Woodhouse /* This NIC does not live on this bus. */ 120993125e4bSDavid Woodhouse continue; 121093125e4bSDavid Woodhouse } 121193125e4bSDavid Woodhouse 121293125e4bSDavid Woodhouse dev = qdev_new(model); 121393125e4bSDavid Woodhouse qdev_set_nic_properties(dev, nd); 121493125e4bSDavid Woodhouse qdev_realize_and_unref(dev, bus, &error_fatal); 121593125e4bSDavid Woodhouse } 121693125e4bSDavid Woodhouse 121793125e4bSDavid Woodhouse g_ptr_array_free(nic_models, true); 121893125e4bSDavid Woodhouse } 121993125e4bSDavid Woodhouse 1220f394b2e2SEric Blake static int (* const net_client_init_fun[NET_CLIENT_DRIVER__MAX])( 1221cebea510SKővágó, Zoltán const Netdev *netdev, 1222fd9400b3SPaolo Bonzini const char *name, 1223a30ecde6SMarkus Armbruster NetClientState *peer, Error **errp) = { 1224f394b2e2SEric Blake [NET_CLIENT_DRIVER_NIC] = net_init_nic, 1225fd9400b3SPaolo Bonzini #ifdef CONFIG_SLIRP 1226f394b2e2SEric Blake [NET_CLIENT_DRIVER_USER] = net_init_slirp, 1227fd9400b3SPaolo Bonzini #endif 1228f394b2e2SEric Blake [NET_CLIENT_DRIVER_TAP] = net_init_tap, 1229f394b2e2SEric Blake [NET_CLIENT_DRIVER_SOCKET] = net_init_socket, 12305166fe0aSLaurent Vivier [NET_CLIENT_DRIVER_STREAM] = net_init_stream, 12315166fe0aSLaurent Vivier [NET_CLIENT_DRIVER_DGRAM] = net_init_dgram, 1232fd9400b3SPaolo Bonzini #ifdef CONFIG_VDE 1233f394b2e2SEric Blake [NET_CLIENT_DRIVER_VDE] = net_init_vde, 1234fd9400b3SPaolo Bonzini #endif 123558952137SVincenzo Maffione #ifdef CONFIG_NETMAP 1236f394b2e2SEric Blake [NET_CLIENT_DRIVER_NETMAP] = net_init_netmap, 123758952137SVincenzo Maffione #endif 1238cb039ef3SIlya Maximets #ifdef CONFIG_AF_XDP 1239cb039ef3SIlya Maximets [NET_CLIENT_DRIVER_AF_XDP] = net_init_af_xdp, 1240cb039ef3SIlya Maximets #endif 1241fd9400b3SPaolo Bonzini #ifdef CONFIG_NET_BRIDGE 1242f394b2e2SEric Blake [NET_CLIENT_DRIVER_BRIDGE] = net_init_bridge, 1243fd9400b3SPaolo Bonzini #endif 1244f394b2e2SEric Blake [NET_CLIENT_DRIVER_HUBPORT] = net_init_hubport, 124556f41de7SPaolo Bonzini #ifdef CONFIG_VHOST_NET_USER 1246f394b2e2SEric Blake [NET_CLIENT_DRIVER_VHOST_USER] = net_init_vhost_user, 124703ce5744SNikolay Nikolaev #endif 12481e0a84eaSCindy Lu #ifdef CONFIG_VHOST_NET_VDPA 12491e0a84eaSCindy Lu [NET_CLIENT_DRIVER_VHOST_VDPA] = net_init_vhost_vdpa, 12501e0a84eaSCindy Lu #endif 1251015a33bdSGonglei #ifdef CONFIG_L2TPV3 1252f394b2e2SEric Blake [NET_CLIENT_DRIVER_L2TPV3] = net_init_l2tpv3, 12533fb69aa1SAnton Ivanov #endif 125481ad2964SVladislav Yaroshchuk #ifdef CONFIG_VMNET 125581ad2964SVladislav Yaroshchuk [NET_CLIENT_DRIVER_VMNET_HOST] = net_init_vmnet_host, 125681ad2964SVladislav Yaroshchuk [NET_CLIENT_DRIVER_VMNET_SHARED] = net_init_vmnet_shared, 125781ad2964SVladislav Yaroshchuk [NET_CLIENT_DRIVER_VMNET_BRIDGED] = net_init_vmnet_bridged, 125881ad2964SVladislav Yaroshchuk #endif /* CONFIG_VMNET */ 1259fd9400b3SPaolo Bonzini }; 1260fd9400b3SPaolo Bonzini 1261fd9400b3SPaolo Bonzini 126271830d84SThomas Huth static int net_client_init1(const Netdev *netdev, bool is_netdev, Error **errp) 1263fd9400b3SPaolo Bonzini { 12644ef0defbSStefan Hajnoczi NetClientState *peer = NULL; 1265831734ccSMarkus Armbruster NetClientState *nc; 1266fd9400b3SPaolo Bonzini 1267fd9400b3SPaolo Bonzini if (is_netdev) { 1268857d2087SThomas Huth if (netdev->type == NET_CLIENT_DRIVER_NIC || 1269f394b2e2SEric Blake !net_client_init_fun[netdev->type]) { 12707d0e12afSDaniel P. Berrangé error_setg(errp, "network backend '%s' is not compiled into this binary", 12717d0e12afSDaniel P. Berrangé NetClientDriver_str(netdev->type)); 1272fd9400b3SPaolo Bonzini return -1; 1273fd9400b3SPaolo Bonzini } 1274fd9400b3SPaolo Bonzini } else { 127571830d84SThomas Huth if (netdev->type == NET_CLIENT_DRIVER_NONE) { 12761e81aba5SStefan Hajnoczi return 0; /* nothing to do */ 1277ca7eb184SMarkus Armbruster } 12787d0e12afSDaniel P. Berrangé if (netdev->type == NET_CLIENT_DRIVER_HUBPORT) { 12797d0e12afSDaniel P. Berrangé error_setg(errp, "network backend '%s' is only supported with -netdev/-nic", 12807d0e12afSDaniel P. Berrangé NetClientDriver_str(netdev->type)); 12817d0e12afSDaniel P. Berrangé return -1; 12827d0e12afSDaniel P. Berrangé } 12837d0e12afSDaniel P. Berrangé 12847d0e12afSDaniel P. Berrangé if (!net_client_init_fun[netdev->type]) { 12857d0e12afSDaniel P. Berrangé error_setg(errp, "network backend '%s' is not compiled into this binary", 12867d0e12afSDaniel P. Berrangé NetClientDriver_str(netdev->type)); 1287d139e9a6SStefan Hajnoczi return -1; 1288d139e9a6SStefan Hajnoczi } 1289fd9400b3SPaolo Bonzini 1290af1a5c3eSThomas Huth /* Do not add to a hub if it's a nic with a netdev= parameter. */ 1291f394b2e2SEric Blake if (netdev->type != NET_CLIENT_DRIVER_NIC || 12927480874aSMarkus Armbruster !netdev->u.nic.netdev) { 1293af1a5c3eSThomas Huth peer = net_hub_add_port(0, NULL, NULL); 1294a2dbe135SThomas Huth } 1295fd9400b3SPaolo Bonzini } 1296fd9400b3SPaolo Bonzini 1297831734ccSMarkus Armbruster nc = qemu_find_netdev(netdev->id); 1298831734ccSMarkus Armbruster if (nc) { 1299831734ccSMarkus Armbruster error_setg(errp, "Duplicate ID '%s'", netdev->id); 1300831734ccSMarkus Armbruster return -1; 1301831734ccSMarkus Armbruster } 1302831734ccSMarkus Armbruster 13039d903f30SThomas Huth if (net_client_init_fun[netdev->type](netdev, netdev->id, peer, errp) < 0) { 1304a30ecde6SMarkus Armbruster /* FIXME drop when all init functions store an Error */ 1305a30ecde6SMarkus Armbruster if (errp && !*errp) { 1306f820af87SMarkus Armbruster error_setg(errp, "Device '%s' could not be initialized", 1307977c736fSMarkus Armbruster NetClientDriver_str(netdev->type)); 1308a30ecde6SMarkus Armbruster } 1309fd9400b3SPaolo Bonzini return -1; 1310fd9400b3SPaolo Bonzini } 131108712fcbSEric Blake 131208712fcbSEric Blake if (is_netdev) { 131308712fcbSEric Blake nc = qemu_find_netdev(netdev->id); 131408712fcbSEric Blake assert(nc); 131508712fcbSEric Blake nc->is_netdev = true; 131608712fcbSEric Blake } 131708712fcbSEric Blake 1318fd9400b3SPaolo Bonzini return 0; 1319fd9400b3SPaolo Bonzini } 1320fd9400b3SPaolo Bonzini 1321ad6f932fSPaolo Bonzini void show_netdevs(void) 1322547203eaSThomas Huth { 1323547203eaSThomas Huth int idx; 1324547203eaSThomas Huth const char *available_netdevs[] = { 1325547203eaSThomas Huth "socket", 13265166fe0aSLaurent Vivier "stream", 13275166fe0aSLaurent Vivier "dgram", 1328547203eaSThomas Huth "hubport", 1329547203eaSThomas Huth "tap", 1330547203eaSThomas Huth #ifdef CONFIG_SLIRP 1331547203eaSThomas Huth "user", 1332547203eaSThomas Huth #endif 1333547203eaSThomas Huth #ifdef CONFIG_L2TPV3 1334547203eaSThomas Huth "l2tpv3", 1335547203eaSThomas Huth #endif 1336547203eaSThomas Huth #ifdef CONFIG_VDE 1337547203eaSThomas Huth "vde", 1338547203eaSThomas Huth #endif 1339547203eaSThomas Huth #ifdef CONFIG_NET_BRIDGE 1340547203eaSThomas Huth "bridge", 1341547203eaSThomas Huth #endif 1342547203eaSThomas Huth #ifdef CONFIG_NETMAP 1343547203eaSThomas Huth "netmap", 1344547203eaSThomas Huth #endif 1345cb039ef3SIlya Maximets #ifdef CONFIG_AF_XDP 1346cb039ef3SIlya Maximets "af-xdp", 1347cb039ef3SIlya Maximets #endif 1348547203eaSThomas Huth #ifdef CONFIG_POSIX 1349547203eaSThomas Huth "vhost-user", 1350547203eaSThomas Huth #endif 13511bc211a1SCindy Lu #ifdef CONFIG_VHOST_VDPA 13521bc211a1SCindy Lu "vhost-vdpa", 13531bc211a1SCindy Lu #endif 135481ad2964SVladislav Yaroshchuk #ifdef CONFIG_VMNET 135581ad2964SVladislav Yaroshchuk "vmnet-host", 135681ad2964SVladislav Yaroshchuk "vmnet-shared", 135781ad2964SVladislav Yaroshchuk "vmnet-bridged", 135881ad2964SVladislav Yaroshchuk #endif 1359547203eaSThomas Huth }; 1360fd9400b3SPaolo Bonzini 1361ad6f932fSPaolo Bonzini qemu_printf("Available netdev backend types:\n"); 1362547203eaSThomas Huth for (idx = 0; idx < ARRAY_SIZE(available_netdevs); idx++) { 1363ad6f932fSPaolo Bonzini qemu_printf("%s\n", available_netdevs[idx]); 1364547203eaSThomas Huth } 1365547203eaSThomas Huth } 1366fd9400b3SPaolo Bonzini 1367aa09a485SThomas Huth static int net_client_init(QemuOpts *opts, bool is_netdev, Error **errp) 1368fd9400b3SPaolo Bonzini { 1369c1112b2dSStefano Garzarella gchar **substrings = NULL; 137071830d84SThomas Huth Netdev *object = NULL; 1371fd9400b3SPaolo Bonzini int ret = -1; 137209204eacSEric Blake Visitor *v = opts_visitor_new(opts); 1373fd9400b3SPaolo Bonzini 13740a4a1512SMarkus Armbruster /* Parse convenience option format ipv6-net=fec0::0[/64] */ 1375891a2bb5SSamuel Thibault const char *ip6_net = qemu_opt_get(opts, "ipv6-net"); 13767aac531eSYann Bordenave 13777aac531eSYann Bordenave if (ip6_net) { 1378c1112b2dSStefano Garzarella char *prefix_addr; 1379c1112b2dSStefano Garzarella unsigned long prefix_len = 64; /* Default 64bit prefix length. */ 13807aac531eSYann Bordenave 1381c1112b2dSStefano Garzarella substrings = g_strsplit(ip6_net, "/", 2); 1382c1112b2dSStefano Garzarella if (!substrings || !substrings[0]) { 1383c1112b2dSStefano Garzarella error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "ipv6-net", 1384c1112b2dSStefano Garzarella "a valid IPv6 prefix"); 1385c1112b2dSStefano Garzarella goto out; 1386c1112b2dSStefano Garzarella } 1387c1112b2dSStefano Garzarella 1388c1112b2dSStefano Garzarella prefix_addr = substrings[0]; 1389c1112b2dSStefano Garzarella 139033c9642fSVladimir Sementsov-Ogievskiy /* Handle user-specified prefix length. */ 139133c9642fSVladimir Sementsov-Ogievskiy if (substrings[1] && 139233c9642fSVladimir Sementsov-Ogievskiy qemu_strtoul(substrings[1], NULL, 10, &prefix_len)) 139333c9642fSVladimir Sementsov-Ogievskiy { 13940a4a1512SMarkus Armbruster error_setg(errp, 13950a4a1512SMarkus Armbruster "parameter 'ipv6-net' expects a number after '/'"); 139621c520d0SStefano Garzarella goto out; 13977aac531eSYann Bordenave } 1398c1112b2dSStefano Garzarella 1399c1112b2dSStefano Garzarella qemu_opt_set(opts, "ipv6-prefix", prefix_addr, &error_abort); 1400c1112b2dSStefano Garzarella qemu_opt_set_number(opts, "ipv6-prefixlen", prefix_len, 1401c1112b2dSStefano Garzarella &error_abort); 1402891a2bb5SSamuel Thibault qemu_opt_unset(opts, "ipv6-net"); 14037aac531eSYann Bordenave } 14047aac531eSYann Bordenave 140571830d84SThomas Huth /* Create an ID for -net if the user did not specify one */ 140671830d84SThomas Huth if (!is_netdev && !qemu_opts_id(opts)) { 140727eb3722SThomas Huth qemu_opts_set_id(opts, id_generate(ID_NET)); 1408fd9400b3SPaolo Bonzini } 1409fd9400b3SPaolo Bonzini 141014217038SMarkus Armbruster if (visit_type_Netdev(v, NULL, &object, errp)) { 141114217038SMarkus Armbruster ret = net_client_init1(object, is_netdev, errp); 1412fd9400b3SPaolo Bonzini } 1413fd9400b3SPaolo Bonzini 141496a1616cSEric Blake qapi_free_Netdev(object); 1415fd9400b3SPaolo Bonzini 141621c520d0SStefano Garzarella out: 1417c1112b2dSStefano Garzarella g_strfreev(substrings); 141809204eacSEric Blake visit_free(v); 1419fd9400b3SPaolo Bonzini return ret; 1420fd9400b3SPaolo Bonzini } 1421fd9400b3SPaolo Bonzini 1422fd9400b3SPaolo Bonzini void netdev_add(QemuOpts *opts, Error **errp) 1423fd9400b3SPaolo Bonzini { 14240e55c381SEric Blake net_client_init(opts, true, errp); 1425fd9400b3SPaolo Bonzini } 1426fd9400b3SPaolo Bonzini 1427db2a380cSEric Blake void qmp_netdev_add(Netdev *netdev, Error **errp) 1428fd9400b3SPaolo Bonzini { 1429e73b4317SPaolo Bonzini if (!id_wellformed(netdev->id)) { 1430e73b4317SPaolo Bonzini error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "id", "an identifier"); 1431e73b4317SPaolo Bonzini return; 1432e73b4317SPaolo Bonzini } 1433e73b4317SPaolo Bonzini 143408712fcbSEric Blake net_client_init1(netdev, true, errp); 1435fd9400b3SPaolo Bonzini } 1436fd9400b3SPaolo Bonzini 1437fd9400b3SPaolo Bonzini void qmp_netdev_del(const char *id, Error **errp) 1438fd9400b3SPaolo Bonzini { 1439fd9400b3SPaolo Bonzini NetClientState *nc; 1440831734ccSMarkus Armbruster QemuOpts *opts; 1441fd9400b3SPaolo Bonzini 1442fd9400b3SPaolo Bonzini nc = qemu_find_netdev(id); 1443fd9400b3SPaolo Bonzini if (!nc) { 144475158ebbSMarkus Armbruster error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 144575158ebbSMarkus Armbruster "Device '%s' not found", id); 1446fd9400b3SPaolo Bonzini return; 1447fd9400b3SPaolo Bonzini } 1448fd9400b3SPaolo Bonzini 144908712fcbSEric Blake if (!nc->is_netdev) { 1450fd9400b3SPaolo Bonzini error_setg(errp, "Device '%s' is not a netdev", id); 1451fd9400b3SPaolo Bonzini return; 1452fd9400b3SPaolo Bonzini } 1453fd9400b3SPaolo Bonzini 1454fd9400b3SPaolo Bonzini qemu_del_net_client(nc); 1455831734ccSMarkus Armbruster 1456831734ccSMarkus Armbruster /* 1457831734ccSMarkus Armbruster * Wart: we need to delete the QemuOpts associated with netdevs 1458831734ccSMarkus Armbruster * created via CLI or HMP, to avoid bogus "Duplicate ID" errors in 1459831734ccSMarkus Armbruster * HMP netdev_add. 1460831734ccSMarkus Armbruster */ 1461831734ccSMarkus Armbruster opts = qemu_opts_find(qemu_find_opts("netdev"), id); 1462831734ccSMarkus Armbruster if (opts) { 1463831734ccSMarkus Armbruster qemu_opts_del(opts); 1464831734ccSMarkus Armbruster } 1465fd9400b3SPaolo Bonzini } 1466fd9400b3SPaolo Bonzini 1467aa9156f4Szhanghailiang static void netfilter_print_info(Monitor *mon, NetFilterState *nf) 1468aa9156f4Szhanghailiang { 1469aa9156f4Szhanghailiang char *str; 1470aa9156f4Szhanghailiang ObjectProperty *prop; 1471aa9156f4Szhanghailiang ObjectPropertyIterator iter; 14723b098d56SEric Blake Visitor *v; 1473aa9156f4Szhanghailiang 1474aa9156f4Szhanghailiang /* generate info str */ 1475aa9156f4Szhanghailiang object_property_iter_init(&iter, OBJECT(nf)); 1476aa9156f4Szhanghailiang while ((prop = object_property_iter_next(&iter))) { 1477aa9156f4Szhanghailiang if (!strcmp(prop->name, "type")) { 1478aa9156f4Szhanghailiang continue; 1479aa9156f4Szhanghailiang } 14803b098d56SEric Blake v = string_output_visitor_new(false, &str); 14815325cc34SMarkus Armbruster object_property_get(OBJECT(nf), prop->name, v, NULL); 14823b098d56SEric Blake visit_complete(v, &str); 14833b098d56SEric Blake visit_free(v); 1484aa9156f4Szhanghailiang monitor_printf(mon, ",%s=%s", prop->name, str); 1485aa9156f4Szhanghailiang g_free(str); 1486aa9156f4Szhanghailiang } 1487aa9156f4Szhanghailiang monitor_printf(mon, "\n"); 1488aa9156f4Szhanghailiang } 1489aa9156f4Szhanghailiang 1490fd9400b3SPaolo Bonzini void print_net_client(Monitor *mon, NetClientState *nc) 1491fd9400b3SPaolo Bonzini { 1492a4960f52SYang Hongyang NetFilterState *nf; 1493a4960f52SYang Hongyang 14941ceef9f2SJason Wang monitor_printf(mon, "%s: index=%d,type=%s,%s\n", nc->name, 14951ceef9f2SJason Wang nc->queue_index, 1496977c736fSMarkus Armbruster NetClientDriver_str(nc->info->type), 149756e6f594SJason Wang nc->info_str); 1498a4960f52SYang Hongyang if (!QTAILQ_EMPTY(&nc->filters)) { 1499a4960f52SYang Hongyang monitor_printf(mon, "filters:\n"); 1500a4960f52SYang Hongyang } 1501a4960f52SYang Hongyang QTAILQ_FOREACH(nf, &nc->filters, next) { 15027a309cc9SMarkus Armbruster monitor_printf(mon, " - %s: type=%s", 15037a309cc9SMarkus Armbruster object_get_canonical_path_component(OBJECT(nf)), 1504aa9156f4Szhanghailiang object_get_typename(OBJECT(nf))); 1505aa9156f4Szhanghailiang netfilter_print_info(mon, nf); 1506a4960f52SYang Hongyang } 1507fd9400b3SPaolo Bonzini } 1508fd9400b3SPaolo Bonzini 15097480874aSMarkus Armbruster RxFilterInfoList *qmp_query_rx_filter(const char *name, Error **errp) 1510b1be4280SAmos Kong { 1511b1be4280SAmos Kong NetClientState *nc; 151295b3a8c8SEric Blake RxFilterInfoList *filter_list = NULL, **tail = &filter_list; 1513b1be4280SAmos Kong 1514b1be4280SAmos Kong QTAILQ_FOREACH(nc, &net_clients, next) { 1515b1be4280SAmos Kong RxFilterInfo *info; 1516b1be4280SAmos Kong 15177480874aSMarkus Armbruster if (name && strcmp(nc->name, name) != 0) { 1518b1be4280SAmos Kong continue; 1519b1be4280SAmos Kong } 1520b1be4280SAmos Kong 1521b1be4280SAmos Kong /* only query rx-filter information of NIC */ 1522f394b2e2SEric Blake if (nc->info->type != NET_CLIENT_DRIVER_NIC) { 15237480874aSMarkus Armbruster if (name) { 1524b1be4280SAmos Kong error_setg(errp, "net client(%s) isn't a NIC", name); 1525e9d635eaSEric Blake assert(!filter_list); 15269083da1dSMarkus Armbruster return NULL; 1527b1be4280SAmos Kong } 1528b1be4280SAmos Kong continue; 1529b1be4280SAmos Kong } 1530b1be4280SAmos Kong 15315320c2caSVladislav Yasevich /* only query information on queue 0 since the info is per nic, 15325320c2caSVladislav Yasevich * not per queue 15335320c2caSVladislav Yasevich */ 15345320c2caSVladislav Yasevich if (nc->queue_index != 0) 15355320c2caSVladislav Yasevich continue; 15365320c2caSVladislav Yasevich 1537b1be4280SAmos Kong if (nc->info->query_rx_filter) { 1538b1be4280SAmos Kong info = nc->info->query_rx_filter(nc); 153995b3a8c8SEric Blake QAPI_LIST_APPEND(tail, info); 15407480874aSMarkus Armbruster } else if (name) { 1541b1be4280SAmos Kong error_setg(errp, "net client(%s) doesn't support" 1542b1be4280SAmos Kong " rx-filter querying", name); 1543e9d635eaSEric Blake assert(!filter_list); 15449083da1dSMarkus Armbruster return NULL; 1545b1be4280SAmos Kong } 1546638fb141SMarkus Armbruster 15477480874aSMarkus Armbruster if (name) { 1548638fb141SMarkus Armbruster break; 1549638fb141SMarkus Armbruster } 1550b1be4280SAmos Kong } 1551b1be4280SAmos Kong 15527480874aSMarkus Armbruster if (filter_list == NULL && name) { 1553b1be4280SAmos Kong error_setg(errp, "invalid net client name: %s", name); 1554b1be4280SAmos Kong } 1555b1be4280SAmos Kong 1556b1be4280SAmos Kong return filter_list; 1557b1be4280SAmos Kong } 1558b1be4280SAmos Kong 15595fbba3d6SZhang Chen void colo_notify_filters_event(int event, Error **errp) 15605fbba3d6SZhang Chen { 15615fbba3d6SZhang Chen NetClientState *nc; 15625fbba3d6SZhang Chen NetFilterState *nf; 15635fbba3d6SZhang Chen NetFilterClass *nfc = NULL; 15645fbba3d6SZhang Chen Error *local_err = NULL; 15655fbba3d6SZhang Chen 15665fbba3d6SZhang Chen QTAILQ_FOREACH(nc, &net_clients, next) { 15675fbba3d6SZhang Chen QTAILQ_FOREACH(nf, &nc->filters, next) { 15685fbba3d6SZhang Chen nfc = NETFILTER_GET_CLASS(OBJECT(nf)); 15695fbba3d6SZhang Chen nfc->handle_event(nf, event, &local_err); 15705fbba3d6SZhang Chen if (local_err) { 15715fbba3d6SZhang Chen error_propagate(errp, local_err); 15725fbba3d6SZhang Chen return; 15735fbba3d6SZhang Chen } 15745fbba3d6SZhang Chen } 15755fbba3d6SZhang Chen } 15765fbba3d6SZhang Chen } 15775fbba3d6SZhang Chen 1578fd9400b3SPaolo Bonzini void qmp_set_link(const char *name, bool up, Error **errp) 1579fd9400b3SPaolo Bonzini { 15801ceef9f2SJason Wang NetClientState *ncs[MAX_QUEUE_NUM]; 15811ceef9f2SJason Wang NetClientState *nc; 15821ceef9f2SJason Wang int queues, i; 1583fd9400b3SPaolo Bonzini 15841ceef9f2SJason Wang queues = qemu_find_net_clients_except(name, ncs, 1585f394b2e2SEric Blake NET_CLIENT_DRIVER__MAX, 15861ceef9f2SJason Wang MAX_QUEUE_NUM); 15871ceef9f2SJason Wang 15881ceef9f2SJason Wang if (queues == 0) { 158975158ebbSMarkus Armbruster error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 159075158ebbSMarkus Armbruster "Device '%s' not found", name); 1591fd9400b3SPaolo Bonzini return; 1592fd9400b3SPaolo Bonzini } 15931ceef9f2SJason Wang nc = ncs[0]; 1594fd9400b3SPaolo Bonzini 15951ceef9f2SJason Wang for (i = 0; i < queues; i++) { 15961ceef9f2SJason Wang ncs[i]->link_down = !up; 15971ceef9f2SJason Wang } 1598fd9400b3SPaolo Bonzini 1599fd9400b3SPaolo Bonzini if (nc->info->link_status_changed) { 1600fd9400b3SPaolo Bonzini nc->info->link_status_changed(nc); 1601fd9400b3SPaolo Bonzini } 1602fd9400b3SPaolo Bonzini 160302d38fcbSVlad Yasevich if (nc->peer) { 160402d38fcbSVlad Yasevich /* Change peer link only if the peer is NIC and then notify peer. 160502d38fcbSVlad Yasevich * If the peer is a HUBPORT or a backend, we do not change the 160602d38fcbSVlad Yasevich * link status. 1607fd9400b3SPaolo Bonzini * 1608af1a5c3eSThomas Huth * This behavior is compatible with qemu hubs where there could be 1609fd9400b3SPaolo Bonzini * multiple clients that can still communicate with each other in 161002d38fcbSVlad Yasevich * disconnected mode. For now maintain this compatibility. 161102d38fcbSVlad Yasevich */ 1612f394b2e2SEric Blake if (nc->peer->info->type == NET_CLIENT_DRIVER_NIC) { 161302d38fcbSVlad Yasevich for (i = 0; i < queues; i++) { 161402d38fcbSVlad Yasevich ncs[i]->peer->link_down = !up; 161502d38fcbSVlad Yasevich } 161602d38fcbSVlad Yasevich } 161702d38fcbSVlad Yasevich if (nc->peer->info->link_status_changed) { 1618fd9400b3SPaolo Bonzini nc->peer->info->link_status_changed(nc->peer); 1619fd9400b3SPaolo Bonzini } 1620fd9400b3SPaolo Bonzini } 162102d38fcbSVlad Yasevich } 1622fd9400b3SPaolo Bonzini 1623538f0497SPhilippe Mathieu-Daudé static void net_vm_change_state_handler(void *opaque, bool running, 1624ca77d85eSMichael S. Tsirkin RunState state) 1625ca77d85eSMichael S. Tsirkin { 1626ca77d85eSMichael S. Tsirkin NetClientState *nc; 1627ca77d85eSMichael S. Tsirkin NetClientState *tmp; 1628ca77d85eSMichael S. Tsirkin 1629ca77d85eSMichael S. Tsirkin QTAILQ_FOREACH_SAFE(nc, &net_clients, next, tmp) { 1630625de449SFam Zheng if (running) { 1631625de449SFam Zheng /* Flush queued packets and wake up backends. */ 1632625de449SFam Zheng if (nc->peer && qemu_can_send_packet(nc)) { 1633625de449SFam Zheng qemu_flush_queued_packets(nc->peer); 1634625de449SFam Zheng } 1635625de449SFam Zheng } else { 1636625de449SFam Zheng /* Complete all queued packets, to guarantee we don't modify 1637625de449SFam Zheng * state later when VM is not running. 1638625de449SFam Zheng */ 1639ca77d85eSMichael S. Tsirkin qemu_flush_or_purge_queued_packets(nc, true); 1640ca77d85eSMichael S. Tsirkin } 1641ca77d85eSMichael S. Tsirkin } 1642ca77d85eSMichael S. Tsirkin } 1643ca77d85eSMichael S. Tsirkin 1644fd9400b3SPaolo Bonzini void net_cleanup(void) 1645fd9400b3SPaolo Bonzini { 164684f85eb9SDavid Woodhouse NetClientState *nc, **p = &QTAILQ_FIRST(&net_clients); 1647fd9400b3SPaolo Bonzini 16480c7af1a7SRao, Lei /*cleanup colo compare module for COLO*/ 16490c7af1a7SRao, Lei colo_compare_cleanup(); 16500c7af1a7SRao, Lei 165184f85eb9SDavid Woodhouse /* 165284f85eb9SDavid Woodhouse * Walk the net_clients list and remove the netdevs but *not* any 165384f85eb9SDavid Woodhouse * NET_CLIENT_DRIVER_NIC entries. The latter are owned by the device 165484f85eb9SDavid Woodhouse * model which created them, and in some cases (e.g. xen-net-device) 165584f85eb9SDavid Woodhouse * the device itself may do cleanup at exit and will be upset if we 165684f85eb9SDavid Woodhouse * just delete its NIC from underneath it. 165784f85eb9SDavid Woodhouse * 165884f85eb9SDavid Woodhouse * Since qemu_del_net_client() may delete multiple entries, using 165984f85eb9SDavid Woodhouse * QTAILQ_FOREACH_SAFE() is not safe here. The only safe pointer 166084f85eb9SDavid Woodhouse * to keep as a bookmark is a NET_CLIENT_DRIVER_NIC entry, so keep 166184f85eb9SDavid Woodhouse * 'p' pointing to either the head of the list, or the 'next' field 166284f85eb9SDavid Woodhouse * of the latest NET_CLIENT_DRIVER_NIC, and operate on *p as we walk 166384f85eb9SDavid Woodhouse * the list. 166484f85eb9SDavid Woodhouse * 166584f85eb9SDavid Woodhouse * The 'nc' variable isn't part of the list traversal; it's purely 166684f85eb9SDavid Woodhouse * for convenience as too much '(*p)->' has a tendency to make the 166784f85eb9SDavid Woodhouse * readers' eyes bleed. 16681ceef9f2SJason Wang */ 166984f85eb9SDavid Woodhouse while (*p) { 167084f85eb9SDavid Woodhouse nc = *p; 1671f394b2e2SEric Blake if (nc->info->type == NET_CLIENT_DRIVER_NIC) { 167284f85eb9SDavid Woodhouse /* Skip NET_CLIENT_DRIVER_NIC entries */ 167384f85eb9SDavid Woodhouse p = &QTAILQ_NEXT(nc, next); 1674948ecf21SJason Wang } else { 1675fd9400b3SPaolo Bonzini qemu_del_net_client(nc); 1676fd9400b3SPaolo Bonzini } 1677fd9400b3SPaolo Bonzini } 1678ca77d85eSMichael S. Tsirkin 1679ca77d85eSMichael S. Tsirkin qemu_del_vm_change_state_handler(net_change_state_entry); 1680948ecf21SJason Wang } 1681fd9400b3SPaolo Bonzini 1682fd9400b3SPaolo Bonzini void net_check_clients(void) 1683fd9400b3SPaolo Bonzini { 1684fd9400b3SPaolo Bonzini NetClientState *nc; 1685fd9400b3SPaolo Bonzini int i; 1686fd9400b3SPaolo Bonzini 16872cdeca04SDavid Woodhouse if (nic_model_help) { 16882cdeca04SDavid Woodhouse show_nic_models(); 16892cdeca04SDavid Woodhouse exit(0); 16902cdeca04SDavid Woodhouse } 1691fd9400b3SPaolo Bonzini net_hub_check_clients(); 1692fd9400b3SPaolo Bonzini 1693fd9400b3SPaolo Bonzini QTAILQ_FOREACH(nc, &net_clients, next) { 1694fd9400b3SPaolo Bonzini if (!nc->peer) { 16958297be80SAlistair Francis warn_report("%s %s has no peer", 1696b62e39b4SAlistair Francis nc->info->type == NET_CLIENT_DRIVER_NIC 1697b62e39b4SAlistair Francis ? "nic" : "netdev", 1698b62e39b4SAlistair Francis nc->name); 1699fd9400b3SPaolo Bonzini } 1700fd9400b3SPaolo Bonzini } 1701fd9400b3SPaolo Bonzini 1702fd9400b3SPaolo Bonzini /* Check that all NICs requested via -net nic actually got created. 1703fd9400b3SPaolo Bonzini * NICs created via -device don't need to be checked here because 1704fd9400b3SPaolo Bonzini * they are always instantiated. 1705fd9400b3SPaolo Bonzini */ 1706fd9400b3SPaolo Bonzini for (i = 0; i < MAX_NICS; i++) { 1707fd9400b3SPaolo Bonzini NICInfo *nd = &nd_table[i]; 1708fd9400b3SPaolo Bonzini if (nd->used && !nd->instantiated) { 17098297be80SAlistair Francis warn_report("requested NIC (%s, model %s) " 17108297be80SAlistair Francis "was not created (not supported by this machine?)", 1711fd9400b3SPaolo Bonzini nd->name ? nd->name : "anonymous", 1712fd9400b3SPaolo Bonzini nd->model ? nd->model : "unspecified"); 1713fd9400b3SPaolo Bonzini } 1714fd9400b3SPaolo Bonzini } 1715fd9400b3SPaolo Bonzini } 1716fd9400b3SPaolo Bonzini 171728d0de7aSMarkus Armbruster static int net_init_client(void *dummy, QemuOpts *opts, Error **errp) 1718fd9400b3SPaolo Bonzini { 171934f708b0SThomas Huth return net_client_init(opts, false, errp); 1720fd9400b3SPaolo Bonzini } 1721fd9400b3SPaolo Bonzini 172228d0de7aSMarkus Armbruster static int net_init_netdev(void *dummy, QemuOpts *opts, Error **errp) 1723fd9400b3SPaolo Bonzini { 1724ad6f932fSPaolo Bonzini const char *type = qemu_opt_get(opts, "type"); 1725ad6f932fSPaolo Bonzini 1726ad6f932fSPaolo Bonzini if (type && is_help_option(type)) { 1727ad6f932fSPaolo Bonzini show_netdevs(); 1728ad6f932fSPaolo Bonzini exit(0); 1729ad6f932fSPaolo Bonzini } 173034f708b0SThomas Huth return net_client_init(opts, true, errp); 1731fd9400b3SPaolo Bonzini } 1732fd9400b3SPaolo Bonzini 173378cd6f7bSThomas Huth /* For the convenience "--nic" parameter */ 173478cd6f7bSThomas Huth static int net_param_nic(void *dummy, QemuOpts *opts, Error **errp) 173578cd6f7bSThomas Huth { 173678cd6f7bSThomas Huth char *mac, *nd_id; 173778cd6f7bSThomas Huth int idx, ret; 173878cd6f7bSThomas Huth NICInfo *ni; 173978cd6f7bSThomas Huth const char *type; 174078cd6f7bSThomas Huth 174178cd6f7bSThomas Huth type = qemu_opt_get(opts, "type"); 174227c81924SThomas Huth if (type) { 174327c81924SThomas Huth if (g_str_equal(type, "none")) { 174478cd6f7bSThomas Huth return 0; /* Nothing to do, default_net is cleared in vl.c */ 174578cd6f7bSThomas Huth } 174627c81924SThomas Huth if (is_help_option(type)) { 174727c81924SThomas Huth GPtrArray *nic_models = qemu_get_nic_models(TYPE_DEVICE); 1748481434f9SDavid Woodhouse int i; 174927c81924SThomas Huth show_netdevs(); 175027c81924SThomas Huth printf("\n"); 1751481434f9SDavid Woodhouse printf("Available NIC models " 1752481434f9SDavid Woodhouse "(use -nic model=help for a filtered list):\n"); 1753481434f9SDavid Woodhouse for (i = 0 ; nic_models->pdata[i]; i++) { 1754481434f9SDavid Woodhouse printf("%s\n", (char *)nic_models->pdata[i]); 1755481434f9SDavid Woodhouse } 175627c81924SThomas Huth g_ptr_array_free(nic_models, true); 175727c81924SThomas Huth exit(0); 175827c81924SThomas Huth } 175927c81924SThomas Huth } 176078cd6f7bSThomas Huth 176178cd6f7bSThomas Huth idx = nic_get_free_idx(); 176278cd6f7bSThomas Huth if (idx == -1 || nb_nics >= MAX_NICS) { 176378cd6f7bSThomas Huth error_setg(errp, "no more on-board/default NIC slots available"); 1764fd9400b3SPaolo Bonzini return -1; 1765fd9400b3SPaolo Bonzini } 1766fd9400b3SPaolo Bonzini 176778cd6f7bSThomas Huth if (!type) { 176878cd6f7bSThomas Huth qemu_opt_set(opts, "type", "user", &error_abort); 176978cd6f7bSThomas Huth } 177078cd6f7bSThomas Huth 177178cd6f7bSThomas Huth ni = &nd_table[idx]; 177278cd6f7bSThomas Huth memset(ni, 0, sizeof(*ni)); 177378cd6f7bSThomas Huth ni->model = qemu_opt_get_del(opts, "model"); 177478cd6f7bSThomas Huth 17752cdeca04SDavid Woodhouse if (!nic_model_help && !g_strcmp0(ni->model, "help")) { 17762cdeca04SDavid Woodhouse nic_model_help = g_hash_table_new_full(g_str_hash, g_str_equal, 17772cdeca04SDavid Woodhouse g_free, NULL); 17782cdeca04SDavid Woodhouse return 0; 17792cdeca04SDavid Woodhouse } 17802cdeca04SDavid Woodhouse 178178cd6f7bSThomas Huth /* Create an ID if the user did not specify one */ 178278cd6f7bSThomas Huth nd_id = g_strdup(qemu_opts_id(opts)); 178378cd6f7bSThomas Huth if (!nd_id) { 178427eb3722SThomas Huth nd_id = id_generate(ID_NET); 178578cd6f7bSThomas Huth qemu_opts_set_id(opts, nd_id); 178678cd6f7bSThomas Huth } 178778cd6f7bSThomas Huth 178878cd6f7bSThomas Huth /* Handle MAC address */ 178978cd6f7bSThomas Huth mac = qemu_opt_get_del(opts, "mac"); 179078cd6f7bSThomas Huth if (mac) { 179178cd6f7bSThomas Huth ret = net_parse_macaddr(ni->macaddr.a, mac); 179278cd6f7bSThomas Huth g_free(mac); 179378cd6f7bSThomas Huth if (ret) { 179478cd6f7bSThomas Huth error_setg(errp, "invalid syntax for ethernet address"); 17959d946191SThomas Huth goto out; 179678cd6f7bSThomas Huth } 179778cd6f7bSThomas Huth if (is_multicast_ether_addr(ni->macaddr.a)) { 179878cd6f7bSThomas Huth error_setg(errp, "NIC cannot have multicast MAC address"); 17999d946191SThomas Huth ret = -1; 18009d946191SThomas Huth goto out; 180178cd6f7bSThomas Huth } 180278cd6f7bSThomas Huth } 180378cd6f7bSThomas Huth qemu_macaddr_default_if_unset(&ni->macaddr); 180478cd6f7bSThomas Huth 180578cd6f7bSThomas Huth ret = net_client_init(opts, true, errp); 180678cd6f7bSThomas Huth if (ret == 0) { 180778cd6f7bSThomas Huth ni->netdev = qemu_find_netdev(nd_id); 180878cd6f7bSThomas Huth ni->used = true; 180978cd6f7bSThomas Huth nb_nics++; 181078cd6f7bSThomas Huth } 181178cd6f7bSThomas Huth 18129d946191SThomas Huth out: 181378cd6f7bSThomas Huth g_free(nd_id); 1814fd9400b3SPaolo Bonzini return ret; 1815fd9400b3SPaolo Bonzini } 1816fd9400b3SPaolo Bonzini 1817f3eedcddSLaurent Vivier static void netdev_init_modern(void) 1818f3eedcddSLaurent Vivier { 1819f3eedcddSLaurent Vivier while (!QSIMPLEQ_EMPTY(&nd_queue)) { 1820f3eedcddSLaurent Vivier NetdevQueueEntry *nd = QSIMPLEQ_FIRST(&nd_queue); 1821f3eedcddSLaurent Vivier 1822f3eedcddSLaurent Vivier QSIMPLEQ_REMOVE_HEAD(&nd_queue, entry); 1823f3eedcddSLaurent Vivier loc_push_restore(&nd->loc); 1824f3eedcddSLaurent Vivier net_client_init1(nd->nd, true, &error_fatal); 1825f3eedcddSLaurent Vivier loc_pop(&nd->loc); 1826f3eedcddSLaurent Vivier qapi_free_Netdev(nd->nd); 1827f3eedcddSLaurent Vivier g_free(nd); 1828f3eedcddSLaurent Vivier } 1829f3eedcddSLaurent Vivier } 1830f3eedcddSLaurent Vivier 1831d63ef17bSLaurent Vivier void net_init_clients(void) 1832fd9400b3SPaolo Bonzini { 1833ca77d85eSMichael S. Tsirkin net_change_state_entry = 1834ca77d85eSMichael S. Tsirkin qemu_add_vm_change_state_handler(net_vm_change_state_handler, NULL); 1835ca77d85eSMichael S. Tsirkin 1836fd9400b3SPaolo Bonzini QTAILQ_INIT(&net_clients); 1837fd9400b3SPaolo Bonzini 1838f3eedcddSLaurent Vivier netdev_init_modern(); 1839f3eedcddSLaurent Vivier 1840d63ef17bSLaurent Vivier qemu_opts_foreach(qemu_find_opts("netdev"), net_init_netdev, NULL, 1841d63ef17bSLaurent Vivier &error_fatal); 1842fd9400b3SPaolo Bonzini 1843d63ef17bSLaurent Vivier qemu_opts_foreach(qemu_find_opts("nic"), net_param_nic, NULL, 1844d63ef17bSLaurent Vivier &error_fatal); 184578cd6f7bSThomas Huth 1846d63ef17bSLaurent Vivier qemu_opts_foreach(qemu_find_opts("net"), net_init_client, NULL, 1847d63ef17bSLaurent Vivier &error_fatal); 1848fd9400b3SPaolo Bonzini } 1849fd9400b3SPaolo Bonzini 1850f3eedcddSLaurent Vivier /* 1851f3eedcddSLaurent Vivier * Does this -netdev argument use modern rather than traditional syntax? 1852f3eedcddSLaurent Vivier * Modern syntax is to be parsed with netdev_parse_modern(). 1853f3eedcddSLaurent Vivier * Traditional syntax is to be parsed with net_client_parse(). 1854f3eedcddSLaurent Vivier */ 185573071f19SPhilippe Mathieu-Daudé bool netdev_is_modern(const char *optstr) 1856f3eedcddSLaurent Vivier { 18575166fe0aSLaurent Vivier QemuOpts *opts; 18585166fe0aSLaurent Vivier bool is_modern; 18595166fe0aSLaurent Vivier const char *type; 18605166fe0aSLaurent Vivier static QemuOptsList dummy_opts = { 18615166fe0aSLaurent Vivier .name = "netdev", 18625166fe0aSLaurent Vivier .implied_opt_name = "type", 18635166fe0aSLaurent Vivier .head = QTAILQ_HEAD_INITIALIZER(dummy_opts.head), 18645166fe0aSLaurent Vivier .desc = { { } }, 18655166fe0aSLaurent Vivier }; 18665166fe0aSLaurent Vivier 186773071f19SPhilippe Mathieu-Daudé if (optstr[0] == '{') { 18685166fe0aSLaurent Vivier /* This is JSON, which means it's modern syntax */ 18695166fe0aSLaurent Vivier return true; 18705166fe0aSLaurent Vivier } 18715166fe0aSLaurent Vivier 18725166fe0aSLaurent Vivier opts = qemu_opts_create(&dummy_opts, NULL, false, &error_abort); 187373071f19SPhilippe Mathieu-Daudé qemu_opts_do_parse(opts, optstr, dummy_opts.implied_opt_name, 18745166fe0aSLaurent Vivier &error_abort); 18755166fe0aSLaurent Vivier type = qemu_opt_get(opts, "type"); 18765166fe0aSLaurent Vivier is_modern = !g_strcmp0(type, "stream") || !g_strcmp0(type, "dgram"); 18775166fe0aSLaurent Vivier 18785166fe0aSLaurent Vivier qemu_opts_reset(&dummy_opts); 18795166fe0aSLaurent Vivier 18805166fe0aSLaurent Vivier return is_modern; 1881f3eedcddSLaurent Vivier } 1882f3eedcddSLaurent Vivier 1883f3eedcddSLaurent Vivier /* 1884f3eedcddSLaurent Vivier * netdev_parse_modern() uses modern, more expressive syntax than 1885f3eedcddSLaurent Vivier * net_client_parse(), but supports only the -netdev option. 1886f3eedcddSLaurent Vivier * netdev_parse_modern() appends to @nd_queue, whereas net_client_parse() 1887f3eedcddSLaurent Vivier * appends to @qemu_netdev_opts. 1888f3eedcddSLaurent Vivier */ 188973071f19SPhilippe Mathieu-Daudé void netdev_parse_modern(const char *optstr) 1890f3eedcddSLaurent Vivier { 1891f3eedcddSLaurent Vivier Visitor *v; 1892f3eedcddSLaurent Vivier NetdevQueueEntry *nd; 1893f3eedcddSLaurent Vivier 189473071f19SPhilippe Mathieu-Daudé v = qobject_input_visitor_new_str(optstr, "type", &error_fatal); 1895f3eedcddSLaurent Vivier nd = g_new(NetdevQueueEntry, 1); 1896f3eedcddSLaurent Vivier visit_type_Netdev(v, NULL, &nd->nd, &error_fatal); 1897f3eedcddSLaurent Vivier visit_free(v); 1898f3eedcddSLaurent Vivier loc_save(&nd->loc); 1899f3eedcddSLaurent Vivier 1900f3eedcddSLaurent Vivier QSIMPLEQ_INSERT_TAIL(&nd_queue, nd, entry); 1901f3eedcddSLaurent Vivier } 1902f3eedcddSLaurent Vivier 190373071f19SPhilippe Mathieu-Daudé void net_client_parse(QemuOptsList *opts_list, const char *optstr) 1904fd9400b3SPaolo Bonzini { 190573071f19SPhilippe Mathieu-Daudé if (!qemu_opts_parse_noisily(opts_list, optstr, true)) { 190621fccb2cSLaurent Vivier exit(1); 1907fd9400b3SPaolo Bonzini } 1908fd9400b3SPaolo Bonzini } 1909fd9400b3SPaolo Bonzini 1910fd9400b3SPaolo Bonzini /* From FreeBSD */ 1911fd9400b3SPaolo Bonzini /* XXX: optimize */ 1912eaba8f34SMark Cave-Ayland uint32_t net_crc32(const uint8_t *p, int len) 1913fd9400b3SPaolo Bonzini { 1914fd9400b3SPaolo Bonzini uint32_t crc; 1915fd9400b3SPaolo Bonzini int carry, i, j; 1916fd9400b3SPaolo Bonzini uint8_t b; 1917fd9400b3SPaolo Bonzini 1918fd9400b3SPaolo Bonzini crc = 0xffffffff; 1919eaba8f34SMark Cave-Ayland for (i = 0; i < len; i++) { 1920eaba8f34SMark Cave-Ayland b = *p++; 1921fd9400b3SPaolo Bonzini for (j = 0; j < 8; j++) { 1922fd9400b3SPaolo Bonzini carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01); 1923fd9400b3SPaolo Bonzini crc <<= 1; 1924fd9400b3SPaolo Bonzini b >>= 1; 1925fd9400b3SPaolo Bonzini if (carry) { 1926eaba8f34SMark Cave-Ayland crc = ((crc ^ POLYNOMIAL_BE) | carry); 1927fd9400b3SPaolo Bonzini } 1928fd9400b3SPaolo Bonzini } 1929fd9400b3SPaolo Bonzini } 1930eaba8f34SMark Cave-Ayland 1931eaba8f34SMark Cave-Ayland return crc; 1932eaba8f34SMark Cave-Ayland } 1933eaba8f34SMark Cave-Ayland 1934f1a7deb9SMark Cave-Ayland uint32_t net_crc32_le(const uint8_t *p, int len) 1935f1a7deb9SMark Cave-Ayland { 1936f1a7deb9SMark Cave-Ayland uint32_t crc; 1937f1a7deb9SMark Cave-Ayland int carry, i, j; 1938f1a7deb9SMark Cave-Ayland uint8_t b; 1939f1a7deb9SMark Cave-Ayland 1940f1a7deb9SMark Cave-Ayland crc = 0xffffffff; 1941f1a7deb9SMark Cave-Ayland for (i = 0; i < len; i++) { 1942f1a7deb9SMark Cave-Ayland b = *p++; 1943f1a7deb9SMark Cave-Ayland for (j = 0; j < 8; j++) { 1944f1a7deb9SMark Cave-Ayland carry = (crc & 0x1) ^ (b & 0x01); 1945f1a7deb9SMark Cave-Ayland crc >>= 1; 1946f1a7deb9SMark Cave-Ayland b >>= 1; 1947f1a7deb9SMark Cave-Ayland if (carry) { 1948f1a7deb9SMark Cave-Ayland crc ^= POLYNOMIAL_LE; 1949f1a7deb9SMark Cave-Ayland } 1950f1a7deb9SMark Cave-Ayland } 1951f1a7deb9SMark Cave-Ayland } 1952f1a7deb9SMark Cave-Ayland 1953f1a7deb9SMark Cave-Ayland return crc; 1954f1a7deb9SMark Cave-Ayland } 1955f1a7deb9SMark Cave-Ayland 19564d454574SPaolo Bonzini QemuOptsList qemu_netdev_opts = { 19574d454574SPaolo Bonzini .name = "netdev", 19584d454574SPaolo Bonzini .implied_opt_name = "type", 19594d454574SPaolo Bonzini .head = QTAILQ_HEAD_INITIALIZER(qemu_netdev_opts.head), 19604d454574SPaolo Bonzini .desc = { 19614d454574SPaolo Bonzini /* 19624d454574SPaolo Bonzini * no elements => accept any params 19634d454574SPaolo Bonzini * validation will happen later 19644d454574SPaolo Bonzini */ 19654d454574SPaolo Bonzini { /* end of list */ } 19664d454574SPaolo Bonzini }, 19674d454574SPaolo Bonzini }; 19684d454574SPaolo Bonzini 196978cd6f7bSThomas Huth QemuOptsList qemu_nic_opts = { 197078cd6f7bSThomas Huth .name = "nic", 197178cd6f7bSThomas Huth .implied_opt_name = "type", 197278cd6f7bSThomas Huth .head = QTAILQ_HEAD_INITIALIZER(qemu_nic_opts.head), 197378cd6f7bSThomas Huth .desc = { 197478cd6f7bSThomas Huth /* 197578cd6f7bSThomas Huth * no elements => accept any params 197678cd6f7bSThomas Huth * validation will happen later 197778cd6f7bSThomas Huth */ 197878cd6f7bSThomas Huth { /* end of list */ } 197978cd6f7bSThomas Huth }, 198078cd6f7bSThomas Huth }; 198178cd6f7bSThomas Huth 19824d454574SPaolo Bonzini QemuOptsList qemu_net_opts = { 19834d454574SPaolo Bonzini .name = "net", 19844d454574SPaolo Bonzini .implied_opt_name = "type", 19854d454574SPaolo Bonzini .head = QTAILQ_HEAD_INITIALIZER(qemu_net_opts.head), 19864d454574SPaolo Bonzini .desc = { 19874d454574SPaolo Bonzini /* 19884d454574SPaolo Bonzini * no elements => accept any params 19894d454574SPaolo Bonzini * validation will happen later 19904d454574SPaolo Bonzini */ 19914d454574SPaolo Bonzini { /* end of list */ } 19924d454574SPaolo Bonzini }, 19934d454574SPaolo Bonzini }; 199416a3df40SZhang Chen 199516a3df40SZhang Chen void net_socket_rs_init(SocketReadState *rs, 19963cde5ea2SZhang Chen SocketReadStateFinalize *finalize, 19973cde5ea2SZhang Chen bool vnet_hdr) 199816a3df40SZhang Chen { 199916a3df40SZhang Chen rs->state = 0; 20003cde5ea2SZhang Chen rs->vnet_hdr = vnet_hdr; 200116a3df40SZhang Chen rs->index = 0; 200216a3df40SZhang Chen rs->packet_len = 0; 20033cde5ea2SZhang Chen rs->vnet_hdr_len = 0; 200416a3df40SZhang Chen memset(rs->buf, 0, sizeof(rs->buf)); 200516a3df40SZhang Chen rs->finalize = finalize; 200616a3df40SZhang Chen } 200716a3df40SZhang Chen 200816a3df40SZhang Chen /* 200916a3df40SZhang Chen * Returns 2010e9e0a585SZhang Chen * 0: success 2011e9e0a585SZhang Chen * -1: error occurs 201216a3df40SZhang Chen */ 201316a3df40SZhang Chen int net_fill_rstate(SocketReadState *rs, const uint8_t *buf, int size) 201416a3df40SZhang Chen { 201516a3df40SZhang Chen unsigned int l; 201616a3df40SZhang Chen 201716a3df40SZhang Chen while (size > 0) { 20183cde5ea2SZhang Chen /* Reassemble a packet from the network. 20193cde5ea2SZhang Chen * 0 = getting length. 20203cde5ea2SZhang Chen * 1 = getting vnet header length. 20213cde5ea2SZhang Chen * 2 = getting data. 20223cde5ea2SZhang Chen */ 20233cde5ea2SZhang Chen switch (rs->state) { 202416a3df40SZhang Chen case 0: 202516a3df40SZhang Chen l = 4 - rs->index; 202616a3df40SZhang Chen if (l > size) { 202716a3df40SZhang Chen l = size; 202816a3df40SZhang Chen } 202916a3df40SZhang Chen memcpy(rs->buf + rs->index, buf, l); 203016a3df40SZhang Chen buf += l; 203116a3df40SZhang Chen size -= l; 203216a3df40SZhang Chen rs->index += l; 203316a3df40SZhang Chen if (rs->index == 4) { 203416a3df40SZhang Chen /* got length */ 203516a3df40SZhang Chen rs->packet_len = ntohl(*(uint32_t *)rs->buf); 203616a3df40SZhang Chen rs->index = 0; 20373cde5ea2SZhang Chen if (rs->vnet_hdr) { 203816a3df40SZhang Chen rs->state = 1; 20393cde5ea2SZhang Chen } else { 20403cde5ea2SZhang Chen rs->state = 2; 20413cde5ea2SZhang Chen rs->vnet_hdr_len = 0; 20423cde5ea2SZhang Chen } 204316a3df40SZhang Chen } 204416a3df40SZhang Chen break; 204516a3df40SZhang Chen case 1: 20463cde5ea2SZhang Chen l = 4 - rs->index; 20473cde5ea2SZhang Chen if (l > size) { 20483cde5ea2SZhang Chen l = size; 20493cde5ea2SZhang Chen } 20503cde5ea2SZhang Chen memcpy(rs->buf + rs->index, buf, l); 20513cde5ea2SZhang Chen buf += l; 20523cde5ea2SZhang Chen size -= l; 20533cde5ea2SZhang Chen rs->index += l; 20543cde5ea2SZhang Chen if (rs->index == 4) { 20553cde5ea2SZhang Chen /* got vnet header length */ 20563cde5ea2SZhang Chen rs->vnet_hdr_len = ntohl(*(uint32_t *)rs->buf); 20573cde5ea2SZhang Chen rs->index = 0; 20583cde5ea2SZhang Chen rs->state = 2; 20593cde5ea2SZhang Chen } 20603cde5ea2SZhang Chen break; 20613cde5ea2SZhang Chen case 2: 206216a3df40SZhang Chen l = rs->packet_len - rs->index; 206316a3df40SZhang Chen if (l > size) { 206416a3df40SZhang Chen l = size; 206516a3df40SZhang Chen } 206616a3df40SZhang Chen if (rs->index + l <= sizeof(rs->buf)) { 206716a3df40SZhang Chen memcpy(rs->buf + rs->index, buf, l); 206816a3df40SZhang Chen } else { 206916a3df40SZhang Chen fprintf(stderr, "serious error: oversized packet received," 207016a3df40SZhang Chen "connection terminated.\n"); 207116a3df40SZhang Chen rs->index = rs->state = 0; 207216a3df40SZhang Chen return -1; 207316a3df40SZhang Chen } 207416a3df40SZhang Chen 207516a3df40SZhang Chen rs->index += l; 207616a3df40SZhang Chen buf += l; 207716a3df40SZhang Chen size -= l; 207816a3df40SZhang Chen if (rs->index >= rs->packet_len) { 207916a3df40SZhang Chen rs->index = 0; 208016a3df40SZhang Chen rs->state = 0; 2081e79cd406SDaniel P. Berrange assert(rs->finalize); 208216a3df40SZhang Chen rs->finalize(rs); 208316a3df40SZhang Chen } 208416a3df40SZhang Chen break; 208516a3df40SZhang Chen } 208616a3df40SZhang Chen } 2087e9e0a585SZhang Chen 2088e9e0a585SZhang Chen assert(size == 0); 208916a3df40SZhang Chen return 0; 209016a3df40SZhang Chen } 2091