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" 51e688df6bSMarkus Armbruster #include "qapi/error.h" 52fd9400b3SPaolo Bonzini #include "qapi/opts-visitor.h" 5354d31236SMarkus Armbruster #include "sysemu/runstate.h" 540c7af1a7SRao, Lei #include "net/colo-compare.h" 55fdccce45SYang Hongyang #include "net/filter.h" 56aa9156f4Szhanghailiang #include "qapi/string-output-visitor.h" 57fd9400b3SPaolo Bonzini 58fd9400b3SPaolo Bonzini /* Net bridge is currently not supported for W32. */ 59fd9400b3SPaolo Bonzini #if !defined(_WIN32) 60fd9400b3SPaolo Bonzini # define CONFIG_NET_BRIDGE 61fd9400b3SPaolo Bonzini #endif 62fd9400b3SPaolo Bonzini 63ca77d85eSMichael S. Tsirkin static VMChangeStateEntry *net_change_state_entry; 64fd9400b3SPaolo Bonzini static QTAILQ_HEAD(, NetClientState) net_clients; 65fd9400b3SPaolo Bonzini 66fd9400b3SPaolo Bonzini /***********************************************************/ 67fd9400b3SPaolo Bonzini /* network device redirectors */ 68fd9400b3SPaolo Bonzini 6930e4226bSLaurent Vivier int convert_host_port(struct sockaddr_in *saddr, const char *host, 7030e4226bSLaurent Vivier const char *port, Error **errp) 7130e4226bSLaurent Vivier { 7230e4226bSLaurent Vivier struct hostent *he; 7330e4226bSLaurent Vivier const char *r; 7430e4226bSLaurent Vivier long p; 7530e4226bSLaurent Vivier 7630e4226bSLaurent Vivier memset(saddr, 0, sizeof(*saddr)); 7730e4226bSLaurent Vivier 7830e4226bSLaurent Vivier saddr->sin_family = AF_INET; 7930e4226bSLaurent Vivier if (host[0] == '\0') { 8030e4226bSLaurent Vivier saddr->sin_addr.s_addr = 0; 8130e4226bSLaurent Vivier } else { 8230e4226bSLaurent Vivier if (qemu_isdigit(host[0])) { 8330e4226bSLaurent Vivier if (!inet_aton(host, &saddr->sin_addr)) { 8430e4226bSLaurent Vivier error_setg(errp, "host address '%s' is not a valid " 8530e4226bSLaurent Vivier "IPv4 address", host); 8630e4226bSLaurent Vivier return -1; 8730e4226bSLaurent Vivier } 8830e4226bSLaurent Vivier } else { 8930e4226bSLaurent Vivier he = gethostbyname(host); 9030e4226bSLaurent Vivier if (he == NULL) { 9130e4226bSLaurent Vivier error_setg(errp, "can't resolve host address '%s'", host); 9230e4226bSLaurent Vivier return -1; 9330e4226bSLaurent Vivier } 9430e4226bSLaurent Vivier saddr->sin_addr = *(struct in_addr *)he->h_addr; 9530e4226bSLaurent Vivier } 9630e4226bSLaurent Vivier } 9730e4226bSLaurent Vivier if (qemu_strtol(port, &r, 0, &p) != 0) { 9830e4226bSLaurent Vivier error_setg(errp, "port number '%s' is invalid", port); 9930e4226bSLaurent Vivier return -1; 10030e4226bSLaurent Vivier } 10130e4226bSLaurent Vivier saddr->sin_port = htons(p); 10230e4226bSLaurent Vivier return 0; 10330e4226bSLaurent Vivier } 10430e4226bSLaurent Vivier 105bcd4dfd6SMao Zhongyi int parse_host_port(struct sockaddr_in *saddr, const char *str, 106bcd4dfd6SMao Zhongyi Error **errp) 107fd9400b3SPaolo Bonzini { 108add99347SStefano Garzarella gchar **substrings; 10930e4226bSLaurent Vivier int ret; 11059292384SPeter Maydell 111add99347SStefano Garzarella substrings = g_strsplit(str, ":", 2); 112add99347SStefano Garzarella if (!substrings || !substrings[0] || !substrings[1]) { 113bcd4dfd6SMao Zhongyi error_setg(errp, "host address '%s' doesn't contain ':' " 114bcd4dfd6SMao Zhongyi "separating host from port", str); 115add99347SStefano Garzarella ret = -1; 116add99347SStefano Garzarella goto out; 117bcd4dfd6SMao Zhongyi } 118add99347SStefano Garzarella 11930e4226bSLaurent Vivier ret = convert_host_port(saddr, substrings[0], substrings[1], errp); 120add99347SStefano Garzarella 121add99347SStefano Garzarella out: 122add99347SStefano Garzarella g_strfreev(substrings); 123add99347SStefano Garzarella return ret; 124fd9400b3SPaolo Bonzini } 125fd9400b3SPaolo Bonzini 126890ee6abSScott Feldman char *qemu_mac_strdup_printf(const uint8_t *macaddr) 127890ee6abSScott Feldman { 128890ee6abSScott Feldman return g_strdup_printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", 129890ee6abSScott Feldman macaddr[0], macaddr[1], macaddr[2], 130890ee6abSScott Feldman macaddr[3], macaddr[4], macaddr[5]); 131890ee6abSScott Feldman } 132890ee6abSScott Feldman 133fd9400b3SPaolo Bonzini void qemu_format_nic_info_str(NetClientState *nc, uint8_t macaddr[6]) 134fd9400b3SPaolo Bonzini { 13556e6f594SJason Wang snprintf(nc->info_str, sizeof(nc->info_str), 136fd9400b3SPaolo Bonzini "model=%s,macaddr=%02x:%02x:%02x:%02x:%02x:%02x", 137fd9400b3SPaolo Bonzini nc->model, 138fd9400b3SPaolo Bonzini macaddr[0], macaddr[1], macaddr[2], 139fd9400b3SPaolo Bonzini macaddr[3], macaddr[4], macaddr[5]); 140fd9400b3SPaolo Bonzini } 141fd9400b3SPaolo Bonzini 1422bc22a58SShannon Zhao static int mac_table[256] = {0}; 1432bc22a58SShannon Zhao 1442bc22a58SShannon Zhao static void qemu_macaddr_set_used(MACAddr *macaddr) 1452bc22a58SShannon Zhao { 1462bc22a58SShannon Zhao int index; 1472bc22a58SShannon Zhao 1482bc22a58SShannon Zhao for (index = 0x56; index < 0xFF; index++) { 1492bc22a58SShannon Zhao if (macaddr->a[5] == index) { 1502bc22a58SShannon Zhao mac_table[index]++; 1512bc22a58SShannon Zhao } 1522bc22a58SShannon Zhao } 1532bc22a58SShannon Zhao } 1542bc22a58SShannon Zhao 1552bc22a58SShannon Zhao static void qemu_macaddr_set_free(MACAddr *macaddr) 1562bc22a58SShannon Zhao { 1572bc22a58SShannon Zhao int index; 1582bc22a58SShannon Zhao static const MACAddr base = { .a = { 0x52, 0x54, 0x00, 0x12, 0x34, 0 } }; 1592bc22a58SShannon Zhao 1602bc22a58SShannon Zhao if (memcmp(macaddr->a, &base.a, (sizeof(base.a) - 1)) != 0) { 1612bc22a58SShannon Zhao return; 1622bc22a58SShannon Zhao } 1632bc22a58SShannon Zhao for (index = 0x56; index < 0xFF; index++) { 1642bc22a58SShannon Zhao if (macaddr->a[5] == index) { 1652bc22a58SShannon Zhao mac_table[index]--; 1662bc22a58SShannon Zhao } 1672bc22a58SShannon Zhao } 1682bc22a58SShannon Zhao } 1692bc22a58SShannon Zhao 1702bc22a58SShannon Zhao static int qemu_macaddr_get_free(void) 1712bc22a58SShannon Zhao { 1722bc22a58SShannon Zhao int index; 1732bc22a58SShannon Zhao 1742bc22a58SShannon Zhao for (index = 0x56; index < 0xFF; index++) { 1752bc22a58SShannon Zhao if (mac_table[index] == 0) { 1762bc22a58SShannon Zhao return index; 1772bc22a58SShannon Zhao } 1782bc22a58SShannon Zhao } 1792bc22a58SShannon Zhao 1802bc22a58SShannon Zhao return -1; 1812bc22a58SShannon Zhao } 1822bc22a58SShannon Zhao 183fd9400b3SPaolo Bonzini void qemu_macaddr_default_if_unset(MACAddr *macaddr) 184fd9400b3SPaolo Bonzini { 185fd9400b3SPaolo Bonzini static const MACAddr zero = { .a = { 0,0,0,0,0,0 } }; 1862bc22a58SShannon Zhao static const MACAddr base = { .a = { 0x52, 0x54, 0x00, 0x12, 0x34, 0 } }; 187fd9400b3SPaolo Bonzini 1882bc22a58SShannon Zhao if (memcmp(macaddr, &zero, sizeof(zero)) != 0) { 1892bc22a58SShannon Zhao if (memcmp(macaddr->a, &base.a, (sizeof(base.a) - 1)) != 0) { 190fd9400b3SPaolo Bonzini return; 1912bc22a58SShannon Zhao } else { 1922bc22a58SShannon Zhao qemu_macaddr_set_used(macaddr); 1932bc22a58SShannon Zhao return; 1942bc22a58SShannon Zhao } 1952bc22a58SShannon Zhao } 1962bc22a58SShannon Zhao 197fd9400b3SPaolo Bonzini macaddr->a[0] = 0x52; 198fd9400b3SPaolo Bonzini macaddr->a[1] = 0x54; 199fd9400b3SPaolo Bonzini macaddr->a[2] = 0x00; 200fd9400b3SPaolo Bonzini macaddr->a[3] = 0x12; 201fd9400b3SPaolo Bonzini macaddr->a[4] = 0x34; 2022bc22a58SShannon Zhao macaddr->a[5] = qemu_macaddr_get_free(); 2032bc22a58SShannon Zhao qemu_macaddr_set_used(macaddr); 204fd9400b3SPaolo Bonzini } 205fd9400b3SPaolo Bonzini 206fd9400b3SPaolo Bonzini /** 207fd9400b3SPaolo Bonzini * Generate a name for net client 208fd9400b3SPaolo Bonzini * 209c963530aSAmos Kong * Only net clients created with the legacy -net option and NICs need this. 210fd9400b3SPaolo Bonzini */ 211fd9400b3SPaolo Bonzini static char *assign_name(NetClientState *nc1, const char *model) 212fd9400b3SPaolo Bonzini { 213fd9400b3SPaolo Bonzini NetClientState *nc; 214fd9400b3SPaolo Bonzini int id = 0; 215fd9400b3SPaolo Bonzini 216fd9400b3SPaolo Bonzini QTAILQ_FOREACH(nc, &net_clients, next) { 217fd9400b3SPaolo Bonzini if (nc == nc1) { 218fd9400b3SPaolo Bonzini continue; 219fd9400b3SPaolo Bonzini } 220c963530aSAmos Kong if (strcmp(nc->model, model) == 0) { 221fd9400b3SPaolo Bonzini id++; 222fd9400b3SPaolo Bonzini } 223fd9400b3SPaolo Bonzini } 224fd9400b3SPaolo Bonzini 2254bf2c138SHani Benhabiles return g_strdup_printf("%s.%d", model, id); 226fd9400b3SPaolo Bonzini } 227fd9400b3SPaolo Bonzini 228f7860455SJason Wang static void qemu_net_client_destructor(NetClientState *nc) 229f7860455SJason Wang { 230f7860455SJason Wang g_free(nc); 231f7860455SJason Wang } 23225c01bd1SJason Wang static ssize_t qemu_deliver_packet_iov(NetClientState *sender, 23325c01bd1SJason Wang unsigned flags, 23425c01bd1SJason Wang const struct iovec *iov, 23525c01bd1SJason Wang int iovcnt, 23625c01bd1SJason Wang void *opaque); 237f7860455SJason Wang 23818a1541aSJason Wang static void qemu_net_client_setup(NetClientState *nc, 23918a1541aSJason Wang NetClientInfo *info, 240fd9400b3SPaolo Bonzini NetClientState *peer, 241fd9400b3SPaolo Bonzini const char *model, 242f7860455SJason Wang const char *name, 2432f849dbdSJason Wang NetClientDestructor *destructor, 2442f849dbdSJason Wang bool is_datapath) 245fd9400b3SPaolo Bonzini { 246fd9400b3SPaolo Bonzini nc->info = info; 247fd9400b3SPaolo Bonzini nc->model = g_strdup(model); 248fd9400b3SPaolo Bonzini if (name) { 249fd9400b3SPaolo Bonzini nc->name = g_strdup(name); 250fd9400b3SPaolo Bonzini } else { 251fd9400b3SPaolo Bonzini nc->name = assign_name(nc, model); 252fd9400b3SPaolo Bonzini } 253fd9400b3SPaolo Bonzini 254fd9400b3SPaolo Bonzini if (peer) { 255fd9400b3SPaolo Bonzini assert(!peer->peer); 256fd9400b3SPaolo Bonzini nc->peer = peer; 257fd9400b3SPaolo Bonzini peer->peer = nc; 258fd9400b3SPaolo Bonzini } 259fd9400b3SPaolo Bonzini QTAILQ_INSERT_TAIL(&net_clients, nc, next); 260fd9400b3SPaolo Bonzini 2613e033a46SYang Hongyang nc->incoming_queue = qemu_new_net_queue(qemu_deliver_packet_iov, nc); 262f7860455SJason Wang nc->destructor = destructor; 2632f849dbdSJason Wang nc->is_datapath = is_datapath; 264fdccce45SYang Hongyang QTAILQ_INIT(&nc->filters); 26518a1541aSJason Wang } 26618a1541aSJason Wang 26718a1541aSJason Wang NetClientState *qemu_new_net_client(NetClientInfo *info, 26818a1541aSJason Wang NetClientState *peer, 26918a1541aSJason Wang const char *model, 27018a1541aSJason Wang const char *name) 27118a1541aSJason Wang { 27218a1541aSJason Wang NetClientState *nc; 27318a1541aSJason Wang 27418a1541aSJason Wang assert(info->size >= sizeof(NetClientState)); 27518a1541aSJason Wang 27618a1541aSJason Wang nc = g_malloc0(info->size); 277f7860455SJason Wang qemu_net_client_setup(nc, info, peer, model, name, 2782f849dbdSJason Wang qemu_net_client_destructor, true); 2792f849dbdSJason Wang 2802f849dbdSJason Wang return nc; 2812f849dbdSJason Wang } 2822f849dbdSJason Wang 2832f849dbdSJason Wang NetClientState *qemu_new_net_control_client(NetClientInfo *info, 2842f849dbdSJason Wang NetClientState *peer, 2852f849dbdSJason Wang const char *model, 2862f849dbdSJason Wang const char *name) 2872f849dbdSJason Wang { 2882f849dbdSJason Wang NetClientState *nc; 2892f849dbdSJason Wang 2902f849dbdSJason Wang assert(info->size >= sizeof(NetClientState)); 2912f849dbdSJason Wang 2922f849dbdSJason Wang nc = g_malloc0(info->size); 2932f849dbdSJason Wang qemu_net_client_setup(nc, info, peer, model, name, 2942f849dbdSJason Wang qemu_net_client_destructor, false); 29518a1541aSJason Wang 296fd9400b3SPaolo Bonzini return nc; 297fd9400b3SPaolo Bonzini } 298fd9400b3SPaolo Bonzini 299fd9400b3SPaolo Bonzini NICState *qemu_new_nic(NetClientInfo *info, 300fd9400b3SPaolo Bonzini NICConf *conf, 301fd9400b3SPaolo Bonzini const char *model, 302fd9400b3SPaolo Bonzini const char *name, 303fd9400b3SPaolo Bonzini void *opaque) 304fd9400b3SPaolo Bonzini { 3051ceef9f2SJason Wang NetClientState **peers = conf->peers.ncs; 306fd9400b3SPaolo Bonzini NICState *nic; 307575a1c0eSJiri Pirko int i, queues = MAX(1, conf->peers.queues); 308fd9400b3SPaolo Bonzini 309f394b2e2SEric Blake assert(info->type == NET_CLIENT_DRIVER_NIC); 310fd9400b3SPaolo Bonzini assert(info->size >= sizeof(NICState)); 311fd9400b3SPaolo Bonzini 312f6b26cf2SJason Wang nic = g_malloc0(info->size + sizeof(NetClientState) * queues); 313f6b26cf2SJason Wang nic->ncs = (void *)nic + info->size; 314fd9400b3SPaolo Bonzini nic->conf = conf; 315fd9400b3SPaolo Bonzini nic->opaque = opaque; 316fd9400b3SPaolo Bonzini 317f6b26cf2SJason Wang for (i = 0; i < queues; i++) { 318f6b26cf2SJason Wang qemu_net_client_setup(&nic->ncs[i], info, peers[i], model, name, 3192f849dbdSJason Wang NULL, true); 3201ceef9f2SJason Wang nic->ncs[i].queue_index = i; 3211ceef9f2SJason Wang } 3221ceef9f2SJason Wang 323fd9400b3SPaolo Bonzini return nic; 324fd9400b3SPaolo Bonzini } 325fd9400b3SPaolo Bonzini 3261ceef9f2SJason Wang NetClientState *qemu_get_subqueue(NICState *nic, int queue_index) 3271ceef9f2SJason Wang { 328f6b26cf2SJason Wang return nic->ncs + queue_index; 3291ceef9f2SJason Wang } 3301ceef9f2SJason Wang 331b356f76dSJason Wang NetClientState *qemu_get_queue(NICState *nic) 332b356f76dSJason Wang { 3331ceef9f2SJason Wang return qemu_get_subqueue(nic, 0); 334b356f76dSJason Wang } 335b356f76dSJason Wang 336cc1f0f45SJason Wang NICState *qemu_get_nic(NetClientState *nc) 337cc1f0f45SJason Wang { 3381ceef9f2SJason Wang NetClientState *nc0 = nc - nc->queue_index; 3391ceef9f2SJason Wang 340f6b26cf2SJason Wang return (NICState *)((void *)nc0 - nc->info->size); 341cc1f0f45SJason Wang } 342cc1f0f45SJason Wang 343cc1f0f45SJason Wang void *qemu_get_nic_opaque(NetClientState *nc) 344cc1f0f45SJason Wang { 345cc1f0f45SJason Wang NICState *nic = qemu_get_nic(nc); 346cc1f0f45SJason Wang 347cc1f0f45SJason Wang return nic->opaque; 348cc1f0f45SJason Wang } 349cc1f0f45SJason Wang 3500165daaeSCindy Lu NetClientState *qemu_get_peer(NetClientState *nc, int queue_index) 3510165daaeSCindy Lu { 3520165daaeSCindy Lu assert(nc != NULL); 3530165daaeSCindy Lu NetClientState *ncs = nc + queue_index; 3540165daaeSCindy Lu return ncs->peer; 3550165daaeSCindy Lu } 3560165daaeSCindy Lu 357fd9400b3SPaolo Bonzini static void qemu_cleanup_net_client(NetClientState *nc) 358fd9400b3SPaolo Bonzini { 359fd9400b3SPaolo Bonzini QTAILQ_REMOVE(&net_clients, nc, next); 360fd9400b3SPaolo Bonzini 361cc2a9043SAndreas Färber if (nc->info->cleanup) { 362fd9400b3SPaolo Bonzini nc->info->cleanup(nc); 363fd9400b3SPaolo Bonzini } 364cc2a9043SAndreas Färber } 365fd9400b3SPaolo Bonzini 366fd9400b3SPaolo Bonzini static void qemu_free_net_client(NetClientState *nc) 367fd9400b3SPaolo Bonzini { 368067404beSJan Kiszka if (nc->incoming_queue) { 369067404beSJan Kiszka qemu_del_net_queue(nc->incoming_queue); 370fd9400b3SPaolo Bonzini } 371fd9400b3SPaolo Bonzini if (nc->peer) { 372fd9400b3SPaolo Bonzini nc->peer->peer = NULL; 373fd9400b3SPaolo Bonzini } 374fd9400b3SPaolo Bonzini g_free(nc->name); 375fd9400b3SPaolo Bonzini g_free(nc->model); 376f7860455SJason Wang if (nc->destructor) { 377f7860455SJason Wang nc->destructor(nc); 378f7860455SJason Wang } 379fd9400b3SPaolo Bonzini } 380fd9400b3SPaolo Bonzini 381fd9400b3SPaolo Bonzini void qemu_del_net_client(NetClientState *nc) 382fd9400b3SPaolo Bonzini { 3831ceef9f2SJason Wang NetClientState *ncs[MAX_QUEUE_NUM]; 3841ceef9f2SJason Wang int queues, i; 385fdccce45SYang Hongyang NetFilterState *nf, *next; 3861ceef9f2SJason Wang 387f394b2e2SEric Blake assert(nc->info->type != NET_CLIENT_DRIVER_NIC); 3887fb43911SPaolo Bonzini 3891ceef9f2SJason Wang /* If the NetClientState belongs to a multiqueue backend, we will change all 3901ceef9f2SJason Wang * other NetClientStates also. 3911ceef9f2SJason Wang */ 3921ceef9f2SJason Wang queues = qemu_find_net_clients_except(nc->name, ncs, 393f394b2e2SEric Blake NET_CLIENT_DRIVER_NIC, 3941ceef9f2SJason Wang MAX_QUEUE_NUM); 3951ceef9f2SJason Wang assert(queues != 0); 3961ceef9f2SJason Wang 397fdccce45SYang Hongyang QTAILQ_FOREACH_SAFE(nf, &nc->filters, next, next) { 398fdccce45SYang Hongyang object_unparent(OBJECT(nf)); 399fdccce45SYang Hongyang } 400fdccce45SYang Hongyang 401fd9400b3SPaolo Bonzini /* If there is a peer NIC, delete and cleanup client, but do not free. */ 402f394b2e2SEric Blake if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_NIC) { 403cc1f0f45SJason Wang NICState *nic = qemu_get_nic(nc->peer); 404fd9400b3SPaolo Bonzini if (nic->peer_deleted) { 405fd9400b3SPaolo Bonzini return; 406fd9400b3SPaolo Bonzini } 407fd9400b3SPaolo Bonzini nic->peer_deleted = true; 4081ceef9f2SJason Wang 4091ceef9f2SJason Wang for (i = 0; i < queues; i++) { 4101ceef9f2SJason Wang ncs[i]->peer->link_down = true; 4111ceef9f2SJason Wang } 4121ceef9f2SJason Wang 413fd9400b3SPaolo Bonzini if (nc->peer->info->link_status_changed) { 414fd9400b3SPaolo Bonzini nc->peer->info->link_status_changed(nc->peer); 415fd9400b3SPaolo Bonzini } 4161ceef9f2SJason Wang 4171ceef9f2SJason Wang for (i = 0; i < queues; i++) { 4181ceef9f2SJason Wang qemu_cleanup_net_client(ncs[i]); 4191ceef9f2SJason Wang } 4201ceef9f2SJason Wang 421fd9400b3SPaolo Bonzini return; 422fd9400b3SPaolo Bonzini } 423fd9400b3SPaolo Bonzini 4241ceef9f2SJason Wang for (i = 0; i < queues; i++) { 4251ceef9f2SJason Wang qemu_cleanup_net_client(ncs[i]); 4261ceef9f2SJason Wang qemu_free_net_client(ncs[i]); 4271ceef9f2SJason Wang } 428948ecf21SJason Wang } 429948ecf21SJason Wang 430948ecf21SJason Wang void qemu_del_nic(NICState *nic) 431948ecf21SJason Wang { 432575a1c0eSJiri Pirko int i, queues = MAX(nic->conf->peers.queues, 1); 4331ceef9f2SJason Wang 4342bc22a58SShannon Zhao qemu_macaddr_set_free(&nic->conf->macaddr); 4352bc22a58SShannon Zhao 436d2abc563SYuri Benditovich for (i = 0; i < queues; i++) { 437d2abc563SYuri Benditovich NetClientState *nc = qemu_get_subqueue(nic, i); 438fd9400b3SPaolo Bonzini /* If this is a peer NIC and peer has already been deleted, free it now. */ 439fd9400b3SPaolo Bonzini if (nic->peer_deleted) { 440d2abc563SYuri Benditovich qemu_free_net_client(nc->peer); 441d2abc563SYuri Benditovich } else if (nc->peer) { 442d2abc563SYuri Benditovich /* if there are RX packets pending, complete them */ 443d2abc563SYuri Benditovich qemu_purge_queued_packets(nc->peer); 444fd9400b3SPaolo Bonzini } 445fd9400b3SPaolo Bonzini } 446fd9400b3SPaolo Bonzini 4471ceef9f2SJason Wang for (i = queues - 1; i >= 0; i--) { 4481ceef9f2SJason Wang NetClientState *nc = qemu_get_subqueue(nic, i); 4491ceef9f2SJason Wang 450fd9400b3SPaolo Bonzini qemu_cleanup_net_client(nc); 451fd9400b3SPaolo Bonzini qemu_free_net_client(nc); 452fd9400b3SPaolo Bonzini } 453f6b26cf2SJason Wang 454f6b26cf2SJason Wang g_free(nic); 4551ceef9f2SJason Wang } 456fd9400b3SPaolo Bonzini 457fd9400b3SPaolo Bonzini void qemu_foreach_nic(qemu_nic_foreach func, void *opaque) 458fd9400b3SPaolo Bonzini { 459fd9400b3SPaolo Bonzini NetClientState *nc; 460fd9400b3SPaolo Bonzini 461fd9400b3SPaolo Bonzini QTAILQ_FOREACH(nc, &net_clients, next) { 462f394b2e2SEric Blake if (nc->info->type == NET_CLIENT_DRIVER_NIC) { 4631ceef9f2SJason Wang if (nc->queue_index == 0) { 464cc1f0f45SJason Wang func(qemu_get_nic(nc), opaque); 465fd9400b3SPaolo Bonzini } 466fd9400b3SPaolo Bonzini } 467fd9400b3SPaolo Bonzini } 4681ceef9f2SJason Wang } 469fd9400b3SPaolo Bonzini 470d6085e3aSStefan Hajnoczi bool qemu_has_ufo(NetClientState *nc) 4711f55ac45SVincenzo Maffione { 472d6085e3aSStefan Hajnoczi if (!nc || !nc->info->has_ufo) { 4731f55ac45SVincenzo Maffione return false; 4741f55ac45SVincenzo Maffione } 4751f55ac45SVincenzo Maffione 476d6085e3aSStefan Hajnoczi return nc->info->has_ufo(nc); 4771f55ac45SVincenzo Maffione } 4781f55ac45SVincenzo Maffione 479d6085e3aSStefan Hajnoczi bool qemu_has_vnet_hdr(NetClientState *nc) 4801f55ac45SVincenzo Maffione { 481d6085e3aSStefan Hajnoczi if (!nc || !nc->info->has_vnet_hdr) { 4821f55ac45SVincenzo Maffione return false; 4831f55ac45SVincenzo Maffione } 4841f55ac45SVincenzo Maffione 485d6085e3aSStefan Hajnoczi return nc->info->has_vnet_hdr(nc); 4861f55ac45SVincenzo Maffione } 4871f55ac45SVincenzo Maffione 488d6085e3aSStefan Hajnoczi bool qemu_has_vnet_hdr_len(NetClientState *nc, int len) 4891f55ac45SVincenzo Maffione { 490d6085e3aSStefan Hajnoczi if (!nc || !nc->info->has_vnet_hdr_len) { 4911f55ac45SVincenzo Maffione return false; 4921f55ac45SVincenzo Maffione } 4931f55ac45SVincenzo Maffione 494d6085e3aSStefan Hajnoczi return nc->info->has_vnet_hdr_len(nc, len); 4951f55ac45SVincenzo Maffione } 4961f55ac45SVincenzo Maffione 497d6085e3aSStefan Hajnoczi void qemu_using_vnet_hdr(NetClientState *nc, bool enable) 4981f55ac45SVincenzo Maffione { 499d6085e3aSStefan Hajnoczi if (!nc || !nc->info->using_vnet_hdr) { 5001f55ac45SVincenzo Maffione return; 5011f55ac45SVincenzo Maffione } 5021f55ac45SVincenzo Maffione 503d6085e3aSStefan Hajnoczi nc->info->using_vnet_hdr(nc, enable); 5041f55ac45SVincenzo Maffione } 5051f55ac45SVincenzo Maffione 506d6085e3aSStefan Hajnoczi void qemu_set_offload(NetClientState *nc, int csum, int tso4, int tso6, 5071f55ac45SVincenzo Maffione int ecn, int ufo) 5081f55ac45SVincenzo Maffione { 509d6085e3aSStefan Hajnoczi if (!nc || !nc->info->set_offload) { 5101f55ac45SVincenzo Maffione return; 5111f55ac45SVincenzo Maffione } 5121f55ac45SVincenzo Maffione 513d6085e3aSStefan Hajnoczi nc->info->set_offload(nc, csum, tso4, tso6, ecn, ufo); 5141f55ac45SVincenzo Maffione } 5151f55ac45SVincenzo Maffione 516d6085e3aSStefan Hajnoczi void qemu_set_vnet_hdr_len(NetClientState *nc, int len) 5171f55ac45SVincenzo Maffione { 518d6085e3aSStefan Hajnoczi if (!nc || !nc->info->set_vnet_hdr_len) { 5191f55ac45SVincenzo Maffione return; 5201f55ac45SVincenzo Maffione } 5211f55ac45SVincenzo Maffione 522d6b732e9SZhang Chen nc->vnet_hdr_len = len; 523d6085e3aSStefan Hajnoczi nc->info->set_vnet_hdr_len(nc, len); 5241f55ac45SVincenzo Maffione } 5251f55ac45SVincenzo Maffione 526c80cd6bbSGreg Kurz int qemu_set_vnet_le(NetClientState *nc, bool is_le) 527c80cd6bbSGreg Kurz { 528e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN 529c80cd6bbSGreg Kurz if (!nc || !nc->info->set_vnet_le) { 530c80cd6bbSGreg Kurz return -ENOSYS; 531c80cd6bbSGreg Kurz } 532c80cd6bbSGreg Kurz 533c80cd6bbSGreg Kurz return nc->info->set_vnet_le(nc, is_le); 534052bd52fSMichael S. Tsirkin #else 535052bd52fSMichael S. Tsirkin return 0; 536052bd52fSMichael S. Tsirkin #endif 537c80cd6bbSGreg Kurz } 538c80cd6bbSGreg Kurz 539c80cd6bbSGreg Kurz int qemu_set_vnet_be(NetClientState *nc, bool is_be) 540c80cd6bbSGreg Kurz { 541e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN 542052bd52fSMichael S. Tsirkin return 0; 543052bd52fSMichael S. Tsirkin #else 544c80cd6bbSGreg Kurz if (!nc || !nc->info->set_vnet_be) { 545c80cd6bbSGreg Kurz return -ENOSYS; 546c80cd6bbSGreg Kurz } 547c80cd6bbSGreg Kurz 548c80cd6bbSGreg Kurz return nc->info->set_vnet_be(nc, is_be); 549052bd52fSMichael S. Tsirkin #endif 550c80cd6bbSGreg Kurz } 551c80cd6bbSGreg Kurz 552705df546SJason Wang int qemu_can_receive_packet(NetClientState *nc) 553705df546SJason Wang { 554705df546SJason Wang if (nc->receive_disabled) { 555705df546SJason Wang return 0; 556705df546SJason Wang } else if (nc->info->can_receive && 557705df546SJason Wang !nc->info->can_receive(nc)) { 558705df546SJason Wang return 0; 559705df546SJason Wang } 560705df546SJason Wang return 1; 561705df546SJason Wang } 562705df546SJason Wang 563fd9400b3SPaolo Bonzini int qemu_can_send_packet(NetClientState *sender) 564fd9400b3SPaolo Bonzini { 565e1d64c08Szhanghailiang int vm_running = runstate_is_running(); 566e1d64c08Szhanghailiang 567e1d64c08Szhanghailiang if (!vm_running) { 568e1d64c08Szhanghailiang return 0; 569e1d64c08Szhanghailiang } 570e1d64c08Szhanghailiang 571fd9400b3SPaolo Bonzini if (!sender->peer) { 572fd9400b3SPaolo Bonzini return 1; 573fd9400b3SPaolo Bonzini } 574fd9400b3SPaolo Bonzini 575705df546SJason Wang return qemu_can_receive_packet(sender->peer); 576fd9400b3SPaolo Bonzini } 577fd9400b3SPaolo Bonzini 578e64c770dSYang Hongyang static ssize_t filter_receive_iov(NetClientState *nc, 579e64c770dSYang Hongyang NetFilterDirection direction, 580e64c770dSYang Hongyang NetClientState *sender, 581e64c770dSYang Hongyang unsigned flags, 582e64c770dSYang Hongyang const struct iovec *iov, 583e64c770dSYang Hongyang int iovcnt, 584e64c770dSYang Hongyang NetPacketSent *sent_cb) 585e64c770dSYang Hongyang { 586e64c770dSYang Hongyang ssize_t ret = 0; 587e64c770dSYang Hongyang NetFilterState *nf = NULL; 588e64c770dSYang Hongyang 58925aaadf0SLi Zhijian if (direction == NET_FILTER_DIRECTION_TX) { 590e64c770dSYang Hongyang QTAILQ_FOREACH(nf, &nc->filters, next) { 591e64c770dSYang Hongyang ret = qemu_netfilter_receive(nf, direction, sender, flags, iov, 592e64c770dSYang Hongyang iovcnt, sent_cb); 593e64c770dSYang Hongyang if (ret) { 594e64c770dSYang Hongyang return ret; 595e64c770dSYang Hongyang } 596e64c770dSYang Hongyang } 59725aaadf0SLi Zhijian } else { 598eae3eb3eSPaolo Bonzini QTAILQ_FOREACH_REVERSE(nf, &nc->filters, next) { 59925aaadf0SLi Zhijian ret = qemu_netfilter_receive(nf, direction, sender, flags, iov, 60025aaadf0SLi Zhijian iovcnt, sent_cb); 60125aaadf0SLi Zhijian if (ret) { 60225aaadf0SLi Zhijian return ret; 60325aaadf0SLi Zhijian } 60425aaadf0SLi Zhijian } 60525aaadf0SLi Zhijian } 606e64c770dSYang Hongyang 607e64c770dSYang Hongyang return ret; 608e64c770dSYang Hongyang } 609e64c770dSYang Hongyang 610e64c770dSYang Hongyang static ssize_t filter_receive(NetClientState *nc, 611e64c770dSYang Hongyang NetFilterDirection direction, 612e64c770dSYang Hongyang NetClientState *sender, 613e64c770dSYang Hongyang unsigned flags, 614e64c770dSYang Hongyang const uint8_t *data, 615e64c770dSYang Hongyang size_t size, 616e64c770dSYang Hongyang NetPacketSent *sent_cb) 617e64c770dSYang Hongyang { 618e64c770dSYang Hongyang struct iovec iov = { 619e64c770dSYang Hongyang .iov_base = (void *)data, 620e64c770dSYang Hongyang .iov_len = size 621e64c770dSYang Hongyang }; 622e64c770dSYang Hongyang 623e64c770dSYang Hongyang return filter_receive_iov(nc, direction, sender, flags, &iov, 1, sent_cb); 624e64c770dSYang Hongyang } 625e64c770dSYang Hongyang 626fd9400b3SPaolo Bonzini void qemu_purge_queued_packets(NetClientState *nc) 627fd9400b3SPaolo Bonzini { 628fd9400b3SPaolo Bonzini if (!nc->peer) { 629fd9400b3SPaolo Bonzini return; 630fd9400b3SPaolo Bonzini } 631fd9400b3SPaolo Bonzini 632067404beSJan Kiszka qemu_net_queue_purge(nc->peer->incoming_queue, nc); 633fd9400b3SPaolo Bonzini } 634fd9400b3SPaolo Bonzini 635ca77d85eSMichael S. Tsirkin void qemu_flush_or_purge_queued_packets(NetClientState *nc, bool purge) 636fd9400b3SPaolo Bonzini { 637fd9400b3SPaolo Bonzini nc->receive_disabled = 0; 638fd9400b3SPaolo Bonzini 639f394b2e2SEric Blake if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_HUBPORT) { 640199ee608SLuigi Rizzo if (net_hub_flush(nc->peer)) { 641199ee608SLuigi Rizzo qemu_notify_event(); 642199ee608SLuigi Rizzo } 643199ee608SLuigi Rizzo } 644067404beSJan Kiszka if (qemu_net_queue_flush(nc->incoming_queue)) { 645fd9400b3SPaolo Bonzini /* We emptied the queue successfully, signal to the IO thread to repoll 646fd9400b3SPaolo Bonzini * the file descriptor (for tap, for example). 647fd9400b3SPaolo Bonzini */ 648fd9400b3SPaolo Bonzini qemu_notify_event(); 649ca77d85eSMichael S. Tsirkin } else if (purge) { 650ca77d85eSMichael S. Tsirkin /* Unable to empty the queue, purge remaining packets */ 6515fe19fb8SJason Wang qemu_net_queue_purge(nc->incoming_queue, nc->peer); 652fd9400b3SPaolo Bonzini } 653fd9400b3SPaolo Bonzini } 654fd9400b3SPaolo Bonzini 655ca77d85eSMichael S. Tsirkin void qemu_flush_queued_packets(NetClientState *nc) 656ca77d85eSMichael S. Tsirkin { 657ca77d85eSMichael S. Tsirkin qemu_flush_or_purge_queued_packets(nc, false); 658ca77d85eSMichael S. Tsirkin } 659ca77d85eSMichael S. Tsirkin 660fd9400b3SPaolo Bonzini static ssize_t qemu_send_packet_async_with_flags(NetClientState *sender, 661fd9400b3SPaolo Bonzini unsigned flags, 662fd9400b3SPaolo Bonzini const uint8_t *buf, int size, 663fd9400b3SPaolo Bonzini NetPacketSent *sent_cb) 664fd9400b3SPaolo Bonzini { 665fd9400b3SPaolo Bonzini NetQueue *queue; 666e64c770dSYang Hongyang int ret; 667fd9400b3SPaolo Bonzini 668fd9400b3SPaolo Bonzini #ifdef DEBUG_NET 669fd9400b3SPaolo Bonzini printf("qemu_send_packet_async:\n"); 670b42581f5SPhilippe Mathieu-Daudé qemu_hexdump(stdout, "net", buf, size); 671fd9400b3SPaolo Bonzini #endif 672fd9400b3SPaolo Bonzini 673fd9400b3SPaolo Bonzini if (sender->link_down || !sender->peer) { 674fd9400b3SPaolo Bonzini return size; 675fd9400b3SPaolo Bonzini } 676fd9400b3SPaolo Bonzini 677e64c770dSYang Hongyang /* Let filters handle the packet first */ 678e64c770dSYang Hongyang ret = filter_receive(sender, NET_FILTER_DIRECTION_TX, 679e64c770dSYang Hongyang sender, flags, buf, size, sent_cb); 680e64c770dSYang Hongyang if (ret) { 681e64c770dSYang Hongyang return ret; 682e64c770dSYang Hongyang } 683e64c770dSYang Hongyang 684e64c770dSYang Hongyang ret = filter_receive(sender->peer, NET_FILTER_DIRECTION_RX, 685e64c770dSYang Hongyang sender, flags, buf, size, sent_cb); 686e64c770dSYang Hongyang if (ret) { 687e64c770dSYang Hongyang return ret; 688e64c770dSYang Hongyang } 689e64c770dSYang Hongyang 690067404beSJan Kiszka queue = sender->peer->incoming_queue; 691fd9400b3SPaolo Bonzini 692fd9400b3SPaolo Bonzini return qemu_net_queue_send(queue, sender, flags, buf, size, sent_cb); 693fd9400b3SPaolo Bonzini } 694fd9400b3SPaolo Bonzini 695fd9400b3SPaolo Bonzini ssize_t qemu_send_packet_async(NetClientState *sender, 696fd9400b3SPaolo Bonzini const uint8_t *buf, int size, 697fd9400b3SPaolo Bonzini NetPacketSent *sent_cb) 698fd9400b3SPaolo Bonzini { 699fd9400b3SPaolo Bonzini return qemu_send_packet_async_with_flags(sender, QEMU_NET_PACKET_FLAG_NONE, 700fd9400b3SPaolo Bonzini buf, size, sent_cb); 701fd9400b3SPaolo Bonzini } 702fd9400b3SPaolo Bonzini 703625a526bSMarc-André Lureau ssize_t qemu_send_packet(NetClientState *nc, const uint8_t *buf, int size) 704fd9400b3SPaolo Bonzini { 705625a526bSMarc-André Lureau return qemu_send_packet_async(nc, buf, size, NULL); 706fd9400b3SPaolo Bonzini } 707fd9400b3SPaolo Bonzini 708705df546SJason Wang ssize_t qemu_receive_packet(NetClientState *nc, const uint8_t *buf, int size) 709705df546SJason Wang { 710705df546SJason Wang if (!qemu_can_receive_packet(nc)) { 711705df546SJason Wang return 0; 712705df546SJason Wang } 713705df546SJason Wang 714705df546SJason Wang return qemu_net_queue_receive(nc->incoming_queue, buf, size); 715705df546SJason Wang } 716705df546SJason Wang 717705df546SJason Wang ssize_t qemu_receive_packet_iov(NetClientState *nc, const struct iovec *iov, 718705df546SJason Wang int iovcnt) 719705df546SJason Wang { 720705df546SJason Wang if (!qemu_can_receive_packet(nc)) { 721705df546SJason Wang return 0; 722705df546SJason Wang } 723705df546SJason Wang 724705df546SJason Wang return qemu_net_queue_receive_iov(nc->incoming_queue, iov, iovcnt); 725705df546SJason Wang } 726705df546SJason Wang 727fd9400b3SPaolo Bonzini ssize_t qemu_send_packet_raw(NetClientState *nc, const uint8_t *buf, int size) 728fd9400b3SPaolo Bonzini { 729fd9400b3SPaolo Bonzini return qemu_send_packet_async_with_flags(nc, QEMU_NET_PACKET_FLAG_RAW, 730fd9400b3SPaolo Bonzini buf, size, NULL); 731fd9400b3SPaolo Bonzini } 732fd9400b3SPaolo Bonzini 733fd9400b3SPaolo Bonzini static ssize_t nc_sendv_compat(NetClientState *nc, const struct iovec *iov, 734fefe2a78SYang Hongyang int iovcnt, unsigned flags) 735fd9400b3SPaolo Bonzini { 73674044c8fSPooja Dhannawat uint8_t *buf = NULL; 737fefe2a78SYang Hongyang uint8_t *buffer; 738fd9400b3SPaolo Bonzini size_t offset; 73974044c8fSPooja Dhannawat ssize_t ret; 740fd9400b3SPaolo Bonzini 741fefe2a78SYang Hongyang if (iovcnt == 1) { 742fefe2a78SYang Hongyang buffer = iov[0].iov_base; 743fefe2a78SYang Hongyang offset = iov[0].iov_len; 744fefe2a78SYang Hongyang } else { 74547f9f158SPeter Lieven offset = iov_size(iov, iovcnt); 74647f9f158SPeter Lieven if (offset > NET_BUFSIZE) { 74747f9f158SPeter Lieven return -1; 74847f9f158SPeter Lieven } 74947f9f158SPeter Lieven buf = g_malloc(offset); 750fefe2a78SYang Hongyang buffer = buf; 75147f9f158SPeter Lieven offset = iov_to_buf(iov, iovcnt, 0, buf, offset); 752fefe2a78SYang Hongyang } 753fd9400b3SPaolo Bonzini 754fefe2a78SYang Hongyang if (flags & QEMU_NET_PACKET_FLAG_RAW && nc->info->receive_raw) { 75574044c8fSPooja Dhannawat ret = nc->info->receive_raw(nc, buffer, offset); 756fefe2a78SYang Hongyang } else { 75774044c8fSPooja Dhannawat ret = nc->info->receive(nc, buffer, offset); 758fd9400b3SPaolo Bonzini } 75974044c8fSPooja Dhannawat 76074044c8fSPooja Dhannawat g_free(buf); 76174044c8fSPooja Dhannawat return ret; 762fefe2a78SYang Hongyang } 763fd9400b3SPaolo Bonzini 76425c01bd1SJason Wang static ssize_t qemu_deliver_packet_iov(NetClientState *sender, 765fd9400b3SPaolo Bonzini unsigned flags, 766fd9400b3SPaolo Bonzini const struct iovec *iov, 767fd9400b3SPaolo Bonzini int iovcnt, 768fd9400b3SPaolo Bonzini void *opaque) 769fd9400b3SPaolo Bonzini { 770fd9400b3SPaolo Bonzini NetClientState *nc = opaque; 771fd9400b3SPaolo Bonzini int ret; 772fd9400b3SPaolo Bonzini 7731592a994SJason Wang 774fd9400b3SPaolo Bonzini if (nc->link_down) { 77525c01bd1SJason Wang return iov_size(iov, iovcnt); 776fd9400b3SPaolo Bonzini } 777fd9400b3SPaolo Bonzini 778fd9400b3SPaolo Bonzini if (nc->receive_disabled) { 779fd9400b3SPaolo Bonzini return 0; 780fd9400b3SPaolo Bonzini } 781fd9400b3SPaolo Bonzini 782ca1ee3d6SPeter Lieven if (nc->info->receive_iov && !(flags & QEMU_NET_PACKET_FLAG_RAW)) { 783fd9400b3SPaolo Bonzini ret = nc->info->receive_iov(nc, iov, iovcnt); 784fd9400b3SPaolo Bonzini } else { 785fefe2a78SYang Hongyang ret = nc_sendv_compat(nc, iov, iovcnt, flags); 786fd9400b3SPaolo Bonzini } 787fd9400b3SPaolo Bonzini 788fd9400b3SPaolo Bonzini if (ret == 0) { 789fd9400b3SPaolo Bonzini nc->receive_disabled = 1; 790fd9400b3SPaolo Bonzini } 791fd9400b3SPaolo Bonzini 792fd9400b3SPaolo Bonzini return ret; 793fd9400b3SPaolo Bonzini } 794fd9400b3SPaolo Bonzini 795fd9400b3SPaolo Bonzini ssize_t qemu_sendv_packet_async(NetClientState *sender, 796fd9400b3SPaolo Bonzini const struct iovec *iov, int iovcnt, 797fd9400b3SPaolo Bonzini NetPacketSent *sent_cb) 798fd9400b3SPaolo Bonzini { 799fd9400b3SPaolo Bonzini NetQueue *queue; 80025c01bd1SJason Wang size_t size = iov_size(iov, iovcnt); 801e64c770dSYang Hongyang int ret; 802fd9400b3SPaolo Bonzini 80325c01bd1SJason Wang if (size > NET_BUFSIZE) { 80425c01bd1SJason Wang return size; 80525c01bd1SJason Wang } 80625c01bd1SJason Wang 807fd9400b3SPaolo Bonzini if (sender->link_down || !sender->peer) { 80825c01bd1SJason Wang return size; 809fd9400b3SPaolo Bonzini } 810fd9400b3SPaolo Bonzini 811e64c770dSYang Hongyang /* Let filters handle the packet first */ 812e64c770dSYang Hongyang ret = filter_receive_iov(sender, NET_FILTER_DIRECTION_TX, sender, 813e64c770dSYang Hongyang QEMU_NET_PACKET_FLAG_NONE, iov, iovcnt, sent_cb); 814e64c770dSYang Hongyang if (ret) { 815e64c770dSYang Hongyang return ret; 816e64c770dSYang Hongyang } 817e64c770dSYang Hongyang 818e64c770dSYang Hongyang ret = filter_receive_iov(sender->peer, NET_FILTER_DIRECTION_RX, sender, 819e64c770dSYang Hongyang QEMU_NET_PACKET_FLAG_NONE, iov, iovcnt, sent_cb); 820e64c770dSYang Hongyang if (ret) { 821e64c770dSYang Hongyang return ret; 822e64c770dSYang Hongyang } 823e64c770dSYang Hongyang 824067404beSJan Kiszka queue = sender->peer->incoming_queue; 825fd9400b3SPaolo Bonzini 826fd9400b3SPaolo Bonzini return qemu_net_queue_send_iov(queue, sender, 827fd9400b3SPaolo Bonzini QEMU_NET_PACKET_FLAG_NONE, 828fd9400b3SPaolo Bonzini iov, iovcnt, sent_cb); 829fd9400b3SPaolo Bonzini } 830fd9400b3SPaolo Bonzini 831fd9400b3SPaolo Bonzini ssize_t 832fd9400b3SPaolo Bonzini qemu_sendv_packet(NetClientState *nc, const struct iovec *iov, int iovcnt) 833fd9400b3SPaolo Bonzini { 834fd9400b3SPaolo Bonzini return qemu_sendv_packet_async(nc, iov, iovcnt, NULL); 835fd9400b3SPaolo Bonzini } 836fd9400b3SPaolo Bonzini 837fd9400b3SPaolo Bonzini NetClientState *qemu_find_netdev(const char *id) 838fd9400b3SPaolo Bonzini { 839fd9400b3SPaolo Bonzini NetClientState *nc; 840fd9400b3SPaolo Bonzini 841fd9400b3SPaolo Bonzini QTAILQ_FOREACH(nc, &net_clients, next) { 842f394b2e2SEric Blake if (nc->info->type == NET_CLIENT_DRIVER_NIC) 843fd9400b3SPaolo Bonzini continue; 844fd9400b3SPaolo Bonzini if (!strcmp(nc->name, id)) { 845fd9400b3SPaolo Bonzini return nc; 846fd9400b3SPaolo Bonzini } 847fd9400b3SPaolo Bonzini } 848fd9400b3SPaolo Bonzini 849fd9400b3SPaolo Bonzini return NULL; 850fd9400b3SPaolo Bonzini } 851fd9400b3SPaolo Bonzini 8526c51ae73SJason Wang int qemu_find_net_clients_except(const char *id, NetClientState **ncs, 853f394b2e2SEric Blake NetClientDriver type, int max) 8546c51ae73SJason Wang { 8556c51ae73SJason Wang NetClientState *nc; 8566c51ae73SJason Wang int ret = 0; 8576c51ae73SJason Wang 8586c51ae73SJason Wang QTAILQ_FOREACH(nc, &net_clients, next) { 8596c51ae73SJason Wang if (nc->info->type == type) { 8606c51ae73SJason Wang continue; 8616c51ae73SJason Wang } 86240d19394SHani Benhabiles if (!id || !strcmp(nc->name, id)) { 8636c51ae73SJason Wang if (ret < max) { 8646c51ae73SJason Wang ncs[ret] = nc; 8656c51ae73SJason Wang } 8666c51ae73SJason Wang ret++; 8676c51ae73SJason Wang } 8686c51ae73SJason Wang } 8696c51ae73SJason Wang 8706c51ae73SJason Wang return ret; 8716c51ae73SJason Wang } 8726c51ae73SJason Wang 873fd9400b3SPaolo Bonzini static int nic_get_free_idx(void) 874fd9400b3SPaolo Bonzini { 875fd9400b3SPaolo Bonzini int index; 876fd9400b3SPaolo Bonzini 877fd9400b3SPaolo Bonzini for (index = 0; index < MAX_NICS; index++) 878fd9400b3SPaolo Bonzini if (!nd_table[index].used) 879fd9400b3SPaolo Bonzini return index; 880fd9400b3SPaolo Bonzini return -1; 881fd9400b3SPaolo Bonzini } 882fd9400b3SPaolo Bonzini 883fd9400b3SPaolo Bonzini int qemu_show_nic_models(const char *arg, const char *const *models) 884fd9400b3SPaolo Bonzini { 885fd9400b3SPaolo Bonzini int i; 886fd9400b3SPaolo Bonzini 887fd9400b3SPaolo Bonzini if (!arg || !is_help_option(arg)) { 888fd9400b3SPaolo Bonzini return 0; 889fd9400b3SPaolo Bonzini } 890fd9400b3SPaolo Bonzini 8917b71e03aSThomas Huth printf("Supported NIC models:\n"); 8927b71e03aSThomas Huth for (i = 0 ; models[i]; i++) { 8937b71e03aSThomas Huth printf("%s\n", models[i]); 8947b71e03aSThomas Huth } 895fd9400b3SPaolo Bonzini return 1; 896fd9400b3SPaolo Bonzini } 897fd9400b3SPaolo Bonzini 898fd9400b3SPaolo Bonzini void qemu_check_nic_model(NICInfo *nd, const char *model) 899fd9400b3SPaolo Bonzini { 900fd9400b3SPaolo Bonzini const char *models[2]; 901fd9400b3SPaolo Bonzini 902fd9400b3SPaolo Bonzini models[0] = model; 903fd9400b3SPaolo Bonzini models[1] = NULL; 904fd9400b3SPaolo Bonzini 905fd9400b3SPaolo Bonzini if (qemu_show_nic_models(nd->model, models)) 906fd9400b3SPaolo Bonzini exit(0); 907fd9400b3SPaolo Bonzini if (qemu_find_nic_model(nd, models, model) < 0) 908fd9400b3SPaolo Bonzini exit(1); 909fd9400b3SPaolo Bonzini } 910fd9400b3SPaolo Bonzini 911fd9400b3SPaolo Bonzini int qemu_find_nic_model(NICInfo *nd, const char * const *models, 912fd9400b3SPaolo Bonzini const char *default_model) 913fd9400b3SPaolo Bonzini { 914fd9400b3SPaolo Bonzini int i; 915fd9400b3SPaolo Bonzini 916fd9400b3SPaolo Bonzini if (!nd->model) 917fd9400b3SPaolo Bonzini nd->model = g_strdup(default_model); 918fd9400b3SPaolo Bonzini 919fd9400b3SPaolo Bonzini for (i = 0 ; models[i]; i++) { 920fd9400b3SPaolo Bonzini if (strcmp(nd->model, models[i]) == 0) 921fd9400b3SPaolo Bonzini return i; 922fd9400b3SPaolo Bonzini } 923fd9400b3SPaolo Bonzini 924fd9400b3SPaolo Bonzini error_report("Unsupported NIC model: %s", nd->model); 925fd9400b3SPaolo Bonzini return -1; 926fd9400b3SPaolo Bonzini } 927fd9400b3SPaolo Bonzini 928cebea510SKővágó, Zoltán static int net_init_nic(const Netdev *netdev, const char *name, 929a30ecde6SMarkus Armbruster NetClientState *peer, Error **errp) 930fd9400b3SPaolo Bonzini { 931fd9400b3SPaolo Bonzini int idx; 932fd9400b3SPaolo Bonzini NICInfo *nd; 933fd9400b3SPaolo Bonzini const NetLegacyNicOptions *nic; 934fd9400b3SPaolo Bonzini 935f394b2e2SEric Blake assert(netdev->type == NET_CLIENT_DRIVER_NIC); 936f394b2e2SEric Blake nic = &netdev->u.nic; 937fd9400b3SPaolo Bonzini 938fd9400b3SPaolo Bonzini idx = nic_get_free_idx(); 939fd9400b3SPaolo Bonzini if (idx == -1 || nb_nics >= MAX_NICS) { 94066308868SMarkus Armbruster error_setg(errp, "too many NICs"); 941fd9400b3SPaolo Bonzini return -1; 942fd9400b3SPaolo Bonzini } 943fd9400b3SPaolo Bonzini 944fd9400b3SPaolo Bonzini nd = &nd_table[idx]; 945fd9400b3SPaolo Bonzini 946fd9400b3SPaolo Bonzini memset(nd, 0, sizeof(*nd)); 947fd9400b3SPaolo Bonzini 948fd9400b3SPaolo Bonzini if (nic->has_netdev) { 949fd9400b3SPaolo Bonzini nd->netdev = qemu_find_netdev(nic->netdev); 950fd9400b3SPaolo Bonzini if (!nd->netdev) { 95166308868SMarkus Armbruster error_setg(errp, "netdev '%s' not found", nic->netdev); 952fd9400b3SPaolo Bonzini return -1; 953fd9400b3SPaolo Bonzini } 954fd9400b3SPaolo Bonzini } else { 955fd9400b3SPaolo Bonzini assert(peer); 956fd9400b3SPaolo Bonzini nd->netdev = peer; 957fd9400b3SPaolo Bonzini } 958fd9400b3SPaolo Bonzini nd->name = g_strdup(name); 959fd9400b3SPaolo Bonzini if (nic->has_model) { 960fd9400b3SPaolo Bonzini nd->model = g_strdup(nic->model); 961fd9400b3SPaolo Bonzini } 962fd9400b3SPaolo Bonzini if (nic->has_addr) { 963fd9400b3SPaolo Bonzini nd->devaddr = g_strdup(nic->addr); 964fd9400b3SPaolo Bonzini } 965fd9400b3SPaolo Bonzini 966fd9400b3SPaolo Bonzini if (nic->has_macaddr && 967fd9400b3SPaolo Bonzini net_parse_macaddr(nd->macaddr.a, nic->macaddr) < 0) { 96866308868SMarkus Armbruster error_setg(errp, "invalid syntax for ethernet address"); 969fd9400b3SPaolo Bonzini return -1; 970fd9400b3SPaolo Bonzini } 971d60b20cfSDmitry Krivenok if (nic->has_macaddr && 972d60b20cfSDmitry Krivenok is_multicast_ether_addr(nd->macaddr.a)) { 97366308868SMarkus Armbruster error_setg(errp, 97466308868SMarkus Armbruster "NIC cannot have multicast MAC address (odd 1st byte)"); 975d60b20cfSDmitry Krivenok return -1; 976d60b20cfSDmitry Krivenok } 977fd9400b3SPaolo Bonzini qemu_macaddr_default_if_unset(&nd->macaddr); 978fd9400b3SPaolo Bonzini 979fd9400b3SPaolo Bonzini if (nic->has_vectors) { 980fd9400b3SPaolo Bonzini if (nic->vectors > 0x7ffffff) { 98166308868SMarkus Armbruster error_setg(errp, "invalid # of vectors: %"PRIu32, nic->vectors); 982fd9400b3SPaolo Bonzini return -1; 983fd9400b3SPaolo Bonzini } 984fd9400b3SPaolo Bonzini nd->nvectors = nic->vectors; 985fd9400b3SPaolo Bonzini } else { 986fd9400b3SPaolo Bonzini nd->nvectors = DEV_NVECTORS_UNSPECIFIED; 987fd9400b3SPaolo Bonzini } 988fd9400b3SPaolo Bonzini 989fd9400b3SPaolo Bonzini nd->used = 1; 990fd9400b3SPaolo Bonzini nb_nics++; 991fd9400b3SPaolo Bonzini 992fd9400b3SPaolo Bonzini return idx; 993fd9400b3SPaolo Bonzini } 994fd9400b3SPaolo Bonzini 995fd9400b3SPaolo Bonzini 996f394b2e2SEric Blake static int (* const net_client_init_fun[NET_CLIENT_DRIVER__MAX])( 997cebea510SKővágó, Zoltán const Netdev *netdev, 998fd9400b3SPaolo Bonzini const char *name, 999a30ecde6SMarkus Armbruster NetClientState *peer, Error **errp) = { 1000f394b2e2SEric Blake [NET_CLIENT_DRIVER_NIC] = net_init_nic, 1001fd9400b3SPaolo Bonzini #ifdef CONFIG_SLIRP 1002f394b2e2SEric Blake [NET_CLIENT_DRIVER_USER] = net_init_slirp, 1003fd9400b3SPaolo Bonzini #endif 1004f394b2e2SEric Blake [NET_CLIENT_DRIVER_TAP] = net_init_tap, 1005f394b2e2SEric Blake [NET_CLIENT_DRIVER_SOCKET] = net_init_socket, 1006fd9400b3SPaolo Bonzini #ifdef CONFIG_VDE 1007f394b2e2SEric Blake [NET_CLIENT_DRIVER_VDE] = net_init_vde, 1008fd9400b3SPaolo Bonzini #endif 100958952137SVincenzo Maffione #ifdef CONFIG_NETMAP 1010f394b2e2SEric Blake [NET_CLIENT_DRIVER_NETMAP] = net_init_netmap, 101158952137SVincenzo Maffione #endif 1012fd9400b3SPaolo Bonzini #ifdef CONFIG_NET_BRIDGE 1013f394b2e2SEric Blake [NET_CLIENT_DRIVER_BRIDGE] = net_init_bridge, 1014fd9400b3SPaolo Bonzini #endif 1015f394b2e2SEric Blake [NET_CLIENT_DRIVER_HUBPORT] = net_init_hubport, 101656f41de7SPaolo Bonzini #ifdef CONFIG_VHOST_NET_USER 1017f394b2e2SEric Blake [NET_CLIENT_DRIVER_VHOST_USER] = net_init_vhost_user, 101803ce5744SNikolay Nikolaev #endif 10191e0a84eaSCindy Lu #ifdef CONFIG_VHOST_NET_VDPA 10201e0a84eaSCindy Lu [NET_CLIENT_DRIVER_VHOST_VDPA] = net_init_vhost_vdpa, 10211e0a84eaSCindy Lu #endif 1022015a33bdSGonglei #ifdef CONFIG_L2TPV3 1023f394b2e2SEric Blake [NET_CLIENT_DRIVER_L2TPV3] = net_init_l2tpv3, 10243fb69aa1SAnton Ivanov #endif 102581ad2964SVladislav Yaroshchuk #ifdef CONFIG_VMNET 102681ad2964SVladislav Yaroshchuk [NET_CLIENT_DRIVER_VMNET_HOST] = net_init_vmnet_host, 102781ad2964SVladislav Yaroshchuk [NET_CLIENT_DRIVER_VMNET_SHARED] = net_init_vmnet_shared, 102881ad2964SVladislav Yaroshchuk [NET_CLIENT_DRIVER_VMNET_BRIDGED] = net_init_vmnet_bridged, 102981ad2964SVladislav Yaroshchuk #endif /* CONFIG_VMNET */ 1030fd9400b3SPaolo Bonzini }; 1031fd9400b3SPaolo Bonzini 1032fd9400b3SPaolo Bonzini 103371830d84SThomas Huth static int net_client_init1(const Netdev *netdev, bool is_netdev, Error **errp) 1034fd9400b3SPaolo Bonzini { 10354ef0defbSStefan Hajnoczi NetClientState *peer = NULL; 1036831734ccSMarkus Armbruster NetClientState *nc; 1037fd9400b3SPaolo Bonzini 1038fd9400b3SPaolo Bonzini if (is_netdev) { 1039857d2087SThomas Huth if (netdev->type == NET_CLIENT_DRIVER_NIC || 1040f394b2e2SEric Blake !net_client_init_fun[netdev->type]) { 10417d0e12afSDaniel P. Berrangé error_setg(errp, "network backend '%s' is not compiled into this binary", 10427d0e12afSDaniel P. Berrangé NetClientDriver_str(netdev->type)); 1043fd9400b3SPaolo Bonzini return -1; 1044fd9400b3SPaolo Bonzini } 1045fd9400b3SPaolo Bonzini } else { 104671830d84SThomas Huth if (netdev->type == NET_CLIENT_DRIVER_NONE) { 10471e81aba5SStefan Hajnoczi return 0; /* nothing to do */ 1048ca7eb184SMarkus Armbruster } 10497d0e12afSDaniel P. Berrangé if (netdev->type == NET_CLIENT_DRIVER_HUBPORT) { 10507d0e12afSDaniel P. Berrangé error_setg(errp, "network backend '%s' is only supported with -netdev/-nic", 10517d0e12afSDaniel P. Berrangé NetClientDriver_str(netdev->type)); 10527d0e12afSDaniel P. Berrangé return -1; 10537d0e12afSDaniel P. Berrangé } 10547d0e12afSDaniel P. Berrangé 10557d0e12afSDaniel P. Berrangé if (!net_client_init_fun[netdev->type]) { 10567d0e12afSDaniel P. Berrangé error_setg(errp, "network backend '%s' is not compiled into this binary", 10577d0e12afSDaniel P. Berrangé NetClientDriver_str(netdev->type)); 1058d139e9a6SStefan Hajnoczi return -1; 1059d139e9a6SStefan Hajnoczi } 1060fd9400b3SPaolo Bonzini 1061af1a5c3eSThomas Huth /* Do not add to a hub if it's a nic with a netdev= parameter. */ 1062f394b2e2SEric Blake if (netdev->type != NET_CLIENT_DRIVER_NIC || 106371830d84SThomas Huth !netdev->u.nic.has_netdev) { 1064af1a5c3eSThomas Huth peer = net_hub_add_port(0, NULL, NULL); 1065a2dbe135SThomas Huth } 1066fd9400b3SPaolo Bonzini } 1067fd9400b3SPaolo Bonzini 1068831734ccSMarkus Armbruster nc = qemu_find_netdev(netdev->id); 1069831734ccSMarkus Armbruster if (nc) { 1070831734ccSMarkus Armbruster error_setg(errp, "Duplicate ID '%s'", netdev->id); 1071831734ccSMarkus Armbruster return -1; 1072831734ccSMarkus Armbruster } 1073831734ccSMarkus Armbruster 10749d903f30SThomas Huth if (net_client_init_fun[netdev->type](netdev, netdev->id, peer, errp) < 0) { 1075a30ecde6SMarkus Armbruster /* FIXME drop when all init functions store an Error */ 1076a30ecde6SMarkus Armbruster if (errp && !*errp) { 1077f820af87SMarkus Armbruster error_setg(errp, "Device '%s' could not be initialized", 1078977c736fSMarkus Armbruster NetClientDriver_str(netdev->type)); 1079a30ecde6SMarkus Armbruster } 1080fd9400b3SPaolo Bonzini return -1; 1081fd9400b3SPaolo Bonzini } 108208712fcbSEric Blake 108308712fcbSEric Blake if (is_netdev) { 108408712fcbSEric Blake nc = qemu_find_netdev(netdev->id); 108508712fcbSEric Blake assert(nc); 108608712fcbSEric Blake nc->is_netdev = true; 108708712fcbSEric Blake } 108808712fcbSEric Blake 1089fd9400b3SPaolo Bonzini return 0; 1090fd9400b3SPaolo Bonzini } 1091fd9400b3SPaolo Bonzini 1092ad6f932fSPaolo Bonzini void show_netdevs(void) 1093547203eaSThomas Huth { 1094547203eaSThomas Huth int idx; 1095547203eaSThomas Huth const char *available_netdevs[] = { 1096547203eaSThomas Huth "socket", 1097547203eaSThomas Huth "hubport", 1098547203eaSThomas Huth "tap", 1099547203eaSThomas Huth #ifdef CONFIG_SLIRP 1100547203eaSThomas Huth "user", 1101547203eaSThomas Huth #endif 1102547203eaSThomas Huth #ifdef CONFIG_L2TPV3 1103547203eaSThomas Huth "l2tpv3", 1104547203eaSThomas Huth #endif 1105547203eaSThomas Huth #ifdef CONFIG_VDE 1106547203eaSThomas Huth "vde", 1107547203eaSThomas Huth #endif 1108547203eaSThomas Huth #ifdef CONFIG_NET_BRIDGE 1109547203eaSThomas Huth "bridge", 1110547203eaSThomas Huth #endif 1111547203eaSThomas Huth #ifdef CONFIG_NETMAP 1112547203eaSThomas Huth "netmap", 1113547203eaSThomas Huth #endif 1114547203eaSThomas Huth #ifdef CONFIG_POSIX 1115547203eaSThomas Huth "vhost-user", 1116547203eaSThomas Huth #endif 11171bc211a1SCindy Lu #ifdef CONFIG_VHOST_VDPA 11181bc211a1SCindy Lu "vhost-vdpa", 11191bc211a1SCindy Lu #endif 112081ad2964SVladislav Yaroshchuk #ifdef CONFIG_VMNET 112181ad2964SVladislav Yaroshchuk "vmnet-host", 112281ad2964SVladislav Yaroshchuk "vmnet-shared", 112381ad2964SVladislav Yaroshchuk "vmnet-bridged", 112481ad2964SVladislav Yaroshchuk #endif 1125547203eaSThomas Huth }; 1126fd9400b3SPaolo Bonzini 1127ad6f932fSPaolo Bonzini qemu_printf("Available netdev backend types:\n"); 1128547203eaSThomas Huth for (idx = 0; idx < ARRAY_SIZE(available_netdevs); idx++) { 1129ad6f932fSPaolo Bonzini qemu_printf("%s\n", available_netdevs[idx]); 1130547203eaSThomas Huth } 1131547203eaSThomas Huth } 1132fd9400b3SPaolo Bonzini 1133aa09a485SThomas Huth static int net_client_init(QemuOpts *opts, bool is_netdev, Error **errp) 1134fd9400b3SPaolo Bonzini { 1135c1112b2dSStefano Garzarella gchar **substrings = NULL; 113671830d84SThomas Huth Netdev *object = NULL; 1137fd9400b3SPaolo Bonzini int ret = -1; 113809204eacSEric Blake Visitor *v = opts_visitor_new(opts); 1139fd9400b3SPaolo Bonzini 11407aac531eSYann Bordenave /* Parse convenience option format ip6-net=fec0::0[/64] */ 1141891a2bb5SSamuel Thibault const char *ip6_net = qemu_opt_get(opts, "ipv6-net"); 11427aac531eSYann Bordenave 11437aac531eSYann Bordenave if (ip6_net) { 1144c1112b2dSStefano Garzarella char *prefix_addr; 1145c1112b2dSStefano Garzarella unsigned long prefix_len = 64; /* Default 64bit prefix length. */ 11467aac531eSYann Bordenave 1147c1112b2dSStefano Garzarella substrings = g_strsplit(ip6_net, "/", 2); 1148c1112b2dSStefano Garzarella if (!substrings || !substrings[0]) { 1149c1112b2dSStefano Garzarella error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "ipv6-net", 1150c1112b2dSStefano Garzarella "a valid IPv6 prefix"); 1151c1112b2dSStefano Garzarella goto out; 1152c1112b2dSStefano Garzarella } 1153c1112b2dSStefano Garzarella 1154c1112b2dSStefano Garzarella prefix_addr = substrings[0]; 1155c1112b2dSStefano Garzarella 115633c9642fSVladimir Sementsov-Ogievskiy /* Handle user-specified prefix length. */ 115733c9642fSVladimir Sementsov-Ogievskiy if (substrings[1] && 115833c9642fSVladimir Sementsov-Ogievskiy qemu_strtoul(substrings[1], NULL, 10, &prefix_len)) 115933c9642fSVladimir Sementsov-Ogievskiy { 11607aac531eSYann Bordenave error_setg(errp, QERR_INVALID_PARAMETER_VALUE, 116121c520d0SStefano Garzarella "ipv6-prefixlen", "a number"); 116221c520d0SStefano Garzarella goto out; 11637aac531eSYann Bordenave } 1164c1112b2dSStefano Garzarella 1165c1112b2dSStefano Garzarella qemu_opt_set(opts, "ipv6-prefix", prefix_addr, &error_abort); 1166c1112b2dSStefano Garzarella qemu_opt_set_number(opts, "ipv6-prefixlen", prefix_len, 1167c1112b2dSStefano Garzarella &error_abort); 1168891a2bb5SSamuel Thibault qemu_opt_unset(opts, "ipv6-net"); 11697aac531eSYann Bordenave } 11707aac531eSYann Bordenave 117171830d84SThomas Huth /* Create an ID for -net if the user did not specify one */ 117271830d84SThomas Huth if (!is_netdev && !qemu_opts_id(opts)) { 117327eb3722SThomas Huth qemu_opts_set_id(opts, id_generate(ID_NET)); 1174fd9400b3SPaolo Bonzini } 1175fd9400b3SPaolo Bonzini 117614217038SMarkus Armbruster if (visit_type_Netdev(v, NULL, &object, errp)) { 117714217038SMarkus Armbruster ret = net_client_init1(object, is_netdev, errp); 1178fd9400b3SPaolo Bonzini } 1179fd9400b3SPaolo Bonzini 118096a1616cSEric Blake qapi_free_Netdev(object); 1181fd9400b3SPaolo Bonzini 118221c520d0SStefano Garzarella out: 1183c1112b2dSStefano Garzarella g_strfreev(substrings); 118409204eacSEric Blake visit_free(v); 1185fd9400b3SPaolo Bonzini return ret; 1186fd9400b3SPaolo Bonzini } 1187fd9400b3SPaolo Bonzini 1188fd9400b3SPaolo Bonzini void netdev_add(QemuOpts *opts, Error **errp) 1189fd9400b3SPaolo Bonzini { 11900e55c381SEric Blake net_client_init(opts, true, errp); 1191fd9400b3SPaolo Bonzini } 1192fd9400b3SPaolo Bonzini 1193db2a380cSEric Blake void qmp_netdev_add(Netdev *netdev, Error **errp) 1194fd9400b3SPaolo Bonzini { 1195e73b4317SPaolo Bonzini if (!id_wellformed(netdev->id)) { 1196e73b4317SPaolo Bonzini error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "id", "an identifier"); 1197e73b4317SPaolo Bonzini return; 1198e73b4317SPaolo Bonzini } 1199e73b4317SPaolo Bonzini 120008712fcbSEric Blake net_client_init1(netdev, true, errp); 1201fd9400b3SPaolo Bonzini } 1202fd9400b3SPaolo Bonzini 1203fd9400b3SPaolo Bonzini void qmp_netdev_del(const char *id, Error **errp) 1204fd9400b3SPaolo Bonzini { 1205fd9400b3SPaolo Bonzini NetClientState *nc; 1206831734ccSMarkus Armbruster QemuOpts *opts; 1207fd9400b3SPaolo Bonzini 1208fd9400b3SPaolo Bonzini nc = qemu_find_netdev(id); 1209fd9400b3SPaolo Bonzini if (!nc) { 121075158ebbSMarkus Armbruster error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 121175158ebbSMarkus Armbruster "Device '%s' not found", id); 1212fd9400b3SPaolo Bonzini return; 1213fd9400b3SPaolo Bonzini } 1214fd9400b3SPaolo Bonzini 121508712fcbSEric Blake if (!nc->is_netdev) { 1216fd9400b3SPaolo Bonzini error_setg(errp, "Device '%s' is not a netdev", id); 1217fd9400b3SPaolo Bonzini return; 1218fd9400b3SPaolo Bonzini } 1219fd9400b3SPaolo Bonzini 1220fd9400b3SPaolo Bonzini qemu_del_net_client(nc); 1221831734ccSMarkus Armbruster 1222831734ccSMarkus Armbruster /* 1223831734ccSMarkus Armbruster * Wart: we need to delete the QemuOpts associated with netdevs 1224831734ccSMarkus Armbruster * created via CLI or HMP, to avoid bogus "Duplicate ID" errors in 1225831734ccSMarkus Armbruster * HMP netdev_add. 1226831734ccSMarkus Armbruster */ 1227831734ccSMarkus Armbruster opts = qemu_opts_find(qemu_find_opts("netdev"), id); 1228831734ccSMarkus Armbruster if (opts) { 1229831734ccSMarkus Armbruster qemu_opts_del(opts); 1230831734ccSMarkus Armbruster } 1231fd9400b3SPaolo Bonzini } 1232fd9400b3SPaolo Bonzini 1233aa9156f4Szhanghailiang static void netfilter_print_info(Monitor *mon, NetFilterState *nf) 1234aa9156f4Szhanghailiang { 1235aa9156f4Szhanghailiang char *str; 1236aa9156f4Szhanghailiang ObjectProperty *prop; 1237aa9156f4Szhanghailiang ObjectPropertyIterator iter; 12383b098d56SEric Blake Visitor *v; 1239aa9156f4Szhanghailiang 1240aa9156f4Szhanghailiang /* generate info str */ 1241aa9156f4Szhanghailiang object_property_iter_init(&iter, OBJECT(nf)); 1242aa9156f4Szhanghailiang while ((prop = object_property_iter_next(&iter))) { 1243aa9156f4Szhanghailiang if (!strcmp(prop->name, "type")) { 1244aa9156f4Szhanghailiang continue; 1245aa9156f4Szhanghailiang } 12463b098d56SEric Blake v = string_output_visitor_new(false, &str); 12475325cc34SMarkus Armbruster object_property_get(OBJECT(nf), prop->name, v, NULL); 12483b098d56SEric Blake visit_complete(v, &str); 12493b098d56SEric Blake visit_free(v); 1250aa9156f4Szhanghailiang monitor_printf(mon, ",%s=%s", prop->name, str); 1251aa9156f4Szhanghailiang g_free(str); 1252aa9156f4Szhanghailiang } 1253aa9156f4Szhanghailiang monitor_printf(mon, "\n"); 1254aa9156f4Szhanghailiang } 1255aa9156f4Szhanghailiang 1256fd9400b3SPaolo Bonzini void print_net_client(Monitor *mon, NetClientState *nc) 1257fd9400b3SPaolo Bonzini { 1258a4960f52SYang Hongyang NetFilterState *nf; 1259a4960f52SYang Hongyang 12601ceef9f2SJason Wang monitor_printf(mon, "%s: index=%d,type=%s,%s\n", nc->name, 12611ceef9f2SJason Wang nc->queue_index, 1262977c736fSMarkus Armbruster NetClientDriver_str(nc->info->type), 126356e6f594SJason Wang nc->info_str); 1264a4960f52SYang Hongyang if (!QTAILQ_EMPTY(&nc->filters)) { 1265a4960f52SYang Hongyang monitor_printf(mon, "filters:\n"); 1266a4960f52SYang Hongyang } 1267a4960f52SYang Hongyang QTAILQ_FOREACH(nf, &nc->filters, next) { 12687a309cc9SMarkus Armbruster monitor_printf(mon, " - %s: type=%s", 12697a309cc9SMarkus Armbruster object_get_canonical_path_component(OBJECT(nf)), 1270aa9156f4Szhanghailiang object_get_typename(OBJECT(nf))); 1271aa9156f4Szhanghailiang netfilter_print_info(mon, nf); 1272a4960f52SYang Hongyang } 1273fd9400b3SPaolo Bonzini } 1274fd9400b3SPaolo Bonzini 1275b1be4280SAmos Kong RxFilterInfoList *qmp_query_rx_filter(bool has_name, const char *name, 1276b1be4280SAmos Kong Error **errp) 1277b1be4280SAmos Kong { 1278b1be4280SAmos Kong NetClientState *nc; 127995b3a8c8SEric Blake RxFilterInfoList *filter_list = NULL, **tail = &filter_list; 1280b1be4280SAmos Kong 1281b1be4280SAmos Kong QTAILQ_FOREACH(nc, &net_clients, next) { 1282b1be4280SAmos Kong RxFilterInfo *info; 1283b1be4280SAmos Kong 1284b1be4280SAmos Kong if (has_name && strcmp(nc->name, name) != 0) { 1285b1be4280SAmos Kong continue; 1286b1be4280SAmos Kong } 1287b1be4280SAmos Kong 1288b1be4280SAmos Kong /* only query rx-filter information of NIC */ 1289f394b2e2SEric Blake if (nc->info->type != NET_CLIENT_DRIVER_NIC) { 1290b1be4280SAmos Kong if (has_name) { 1291b1be4280SAmos Kong error_setg(errp, "net client(%s) isn't a NIC", name); 1292e9d635eaSEric Blake assert(!filter_list); 12939083da1dSMarkus Armbruster return NULL; 1294b1be4280SAmos Kong } 1295b1be4280SAmos Kong continue; 1296b1be4280SAmos Kong } 1297b1be4280SAmos Kong 12985320c2caSVladislav Yasevich /* only query information on queue 0 since the info is per nic, 12995320c2caSVladislav Yasevich * not per queue 13005320c2caSVladislav Yasevich */ 13015320c2caSVladislav Yasevich if (nc->queue_index != 0) 13025320c2caSVladislav Yasevich continue; 13035320c2caSVladislav Yasevich 1304b1be4280SAmos Kong if (nc->info->query_rx_filter) { 1305b1be4280SAmos Kong info = nc->info->query_rx_filter(nc); 130695b3a8c8SEric Blake QAPI_LIST_APPEND(tail, info); 1307b1be4280SAmos Kong } else if (has_name) { 1308b1be4280SAmos Kong error_setg(errp, "net client(%s) doesn't support" 1309b1be4280SAmos Kong " rx-filter querying", name); 1310e9d635eaSEric Blake assert(!filter_list); 13119083da1dSMarkus Armbruster return NULL; 1312b1be4280SAmos Kong } 1313638fb141SMarkus Armbruster 1314638fb141SMarkus Armbruster if (has_name) { 1315638fb141SMarkus Armbruster break; 1316638fb141SMarkus Armbruster } 1317b1be4280SAmos Kong } 1318b1be4280SAmos Kong 13199083da1dSMarkus Armbruster if (filter_list == NULL && has_name) { 1320b1be4280SAmos Kong error_setg(errp, "invalid net client name: %s", name); 1321b1be4280SAmos Kong } 1322b1be4280SAmos Kong 1323b1be4280SAmos Kong return filter_list; 1324b1be4280SAmos Kong } 1325b1be4280SAmos Kong 13261ce6be24SMarkus Armbruster void hmp_info_network(Monitor *mon, const QDict *qdict) 1327fd9400b3SPaolo Bonzini { 1328fd9400b3SPaolo Bonzini NetClientState *nc, *peer; 1329f394b2e2SEric Blake NetClientDriver type; 1330fd9400b3SPaolo Bonzini 1331fd9400b3SPaolo Bonzini net_hub_info(mon); 1332fd9400b3SPaolo Bonzini 1333fd9400b3SPaolo Bonzini QTAILQ_FOREACH(nc, &net_clients, next) { 1334fd9400b3SPaolo Bonzini peer = nc->peer; 1335fd9400b3SPaolo Bonzini type = nc->info->type; 1336fd9400b3SPaolo Bonzini 1337fd9400b3SPaolo Bonzini /* Skip if already printed in hub info */ 1338fd9400b3SPaolo Bonzini if (net_hub_id_for_client(nc, NULL) == 0) { 1339fd9400b3SPaolo Bonzini continue; 1340fd9400b3SPaolo Bonzini } 1341fd9400b3SPaolo Bonzini 1342f394b2e2SEric Blake if (!peer || type == NET_CLIENT_DRIVER_NIC) { 1343fd9400b3SPaolo Bonzini print_net_client(mon, nc); 1344fd9400b3SPaolo Bonzini } /* else it's a netdev connected to a NIC, printed with the NIC */ 1345f394b2e2SEric Blake if (peer && type == NET_CLIENT_DRIVER_NIC) { 1346fd9400b3SPaolo Bonzini monitor_printf(mon, " \\ "); 1347fd9400b3SPaolo Bonzini print_net_client(mon, peer); 1348fd9400b3SPaolo Bonzini } 1349fd9400b3SPaolo Bonzini } 1350fd9400b3SPaolo Bonzini } 1351fd9400b3SPaolo Bonzini 13525fbba3d6SZhang Chen void colo_notify_filters_event(int event, Error **errp) 13535fbba3d6SZhang Chen { 13545fbba3d6SZhang Chen NetClientState *nc; 13555fbba3d6SZhang Chen NetFilterState *nf; 13565fbba3d6SZhang Chen NetFilterClass *nfc = NULL; 13575fbba3d6SZhang Chen Error *local_err = NULL; 13585fbba3d6SZhang Chen 13595fbba3d6SZhang Chen QTAILQ_FOREACH(nc, &net_clients, next) { 13605fbba3d6SZhang Chen QTAILQ_FOREACH(nf, &nc->filters, next) { 13615fbba3d6SZhang Chen nfc = NETFILTER_GET_CLASS(OBJECT(nf)); 13625fbba3d6SZhang Chen nfc->handle_event(nf, event, &local_err); 13635fbba3d6SZhang Chen if (local_err) { 13645fbba3d6SZhang Chen error_propagate(errp, local_err); 13655fbba3d6SZhang Chen return; 13665fbba3d6SZhang Chen } 13675fbba3d6SZhang Chen } 13685fbba3d6SZhang Chen } 13695fbba3d6SZhang Chen } 13705fbba3d6SZhang Chen 1371fd9400b3SPaolo Bonzini void qmp_set_link(const char *name, bool up, Error **errp) 1372fd9400b3SPaolo Bonzini { 13731ceef9f2SJason Wang NetClientState *ncs[MAX_QUEUE_NUM]; 13741ceef9f2SJason Wang NetClientState *nc; 13751ceef9f2SJason Wang int queues, i; 1376fd9400b3SPaolo Bonzini 13771ceef9f2SJason Wang queues = qemu_find_net_clients_except(name, ncs, 1378f394b2e2SEric Blake NET_CLIENT_DRIVER__MAX, 13791ceef9f2SJason Wang MAX_QUEUE_NUM); 13801ceef9f2SJason Wang 13811ceef9f2SJason Wang if (queues == 0) { 138275158ebbSMarkus Armbruster error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 138375158ebbSMarkus Armbruster "Device '%s' not found", name); 1384fd9400b3SPaolo Bonzini return; 1385fd9400b3SPaolo Bonzini } 13861ceef9f2SJason Wang nc = ncs[0]; 1387fd9400b3SPaolo Bonzini 13881ceef9f2SJason Wang for (i = 0; i < queues; i++) { 13891ceef9f2SJason Wang ncs[i]->link_down = !up; 13901ceef9f2SJason Wang } 1391fd9400b3SPaolo Bonzini 1392fd9400b3SPaolo Bonzini if (nc->info->link_status_changed) { 1393fd9400b3SPaolo Bonzini nc->info->link_status_changed(nc); 1394fd9400b3SPaolo Bonzini } 1395fd9400b3SPaolo Bonzini 139602d38fcbSVlad Yasevich if (nc->peer) { 139702d38fcbSVlad Yasevich /* Change peer link only if the peer is NIC and then notify peer. 139802d38fcbSVlad Yasevich * If the peer is a HUBPORT or a backend, we do not change the 139902d38fcbSVlad Yasevich * link status. 1400fd9400b3SPaolo Bonzini * 1401af1a5c3eSThomas Huth * This behavior is compatible with qemu hubs where there could be 1402fd9400b3SPaolo Bonzini * multiple clients that can still communicate with each other in 140302d38fcbSVlad Yasevich * disconnected mode. For now maintain this compatibility. 140402d38fcbSVlad Yasevich */ 1405f394b2e2SEric Blake if (nc->peer->info->type == NET_CLIENT_DRIVER_NIC) { 140602d38fcbSVlad Yasevich for (i = 0; i < queues; i++) { 140702d38fcbSVlad Yasevich ncs[i]->peer->link_down = !up; 140802d38fcbSVlad Yasevich } 140902d38fcbSVlad Yasevich } 141002d38fcbSVlad Yasevich if (nc->peer->info->link_status_changed) { 1411fd9400b3SPaolo Bonzini nc->peer->info->link_status_changed(nc->peer); 1412fd9400b3SPaolo Bonzini } 1413fd9400b3SPaolo Bonzini } 141402d38fcbSVlad Yasevich } 1415fd9400b3SPaolo Bonzini 1416538f0497SPhilippe Mathieu-Daudé static void net_vm_change_state_handler(void *opaque, bool running, 1417ca77d85eSMichael S. Tsirkin RunState state) 1418ca77d85eSMichael S. Tsirkin { 1419ca77d85eSMichael S. Tsirkin NetClientState *nc; 1420ca77d85eSMichael S. Tsirkin NetClientState *tmp; 1421ca77d85eSMichael S. Tsirkin 1422ca77d85eSMichael S. Tsirkin QTAILQ_FOREACH_SAFE(nc, &net_clients, next, tmp) { 1423625de449SFam Zheng if (running) { 1424625de449SFam Zheng /* Flush queued packets and wake up backends. */ 1425625de449SFam Zheng if (nc->peer && qemu_can_send_packet(nc)) { 1426625de449SFam Zheng qemu_flush_queued_packets(nc->peer); 1427625de449SFam Zheng } 1428625de449SFam Zheng } else { 1429625de449SFam Zheng /* Complete all queued packets, to guarantee we don't modify 1430625de449SFam Zheng * state later when VM is not running. 1431625de449SFam Zheng */ 1432ca77d85eSMichael S. Tsirkin qemu_flush_or_purge_queued_packets(nc, true); 1433ca77d85eSMichael S. Tsirkin } 1434ca77d85eSMichael S. Tsirkin } 1435ca77d85eSMichael S. Tsirkin } 1436ca77d85eSMichael S. Tsirkin 1437fd9400b3SPaolo Bonzini void net_cleanup(void) 1438fd9400b3SPaolo Bonzini { 14391ceef9f2SJason Wang NetClientState *nc; 1440fd9400b3SPaolo Bonzini 14410c7af1a7SRao, Lei /*cleanup colo compare module for COLO*/ 14420c7af1a7SRao, Lei colo_compare_cleanup(); 14430c7af1a7SRao, Lei 14441ceef9f2SJason Wang /* We may del multiple entries during qemu_del_net_client(), 14451ceef9f2SJason Wang * so QTAILQ_FOREACH_SAFE() is also not safe here. 14461ceef9f2SJason Wang */ 14471ceef9f2SJason Wang while (!QTAILQ_EMPTY(&net_clients)) { 14481ceef9f2SJason Wang nc = QTAILQ_FIRST(&net_clients); 1449f394b2e2SEric Blake if (nc->info->type == NET_CLIENT_DRIVER_NIC) { 1450948ecf21SJason Wang qemu_del_nic(qemu_get_nic(nc)); 1451948ecf21SJason Wang } else { 1452fd9400b3SPaolo Bonzini qemu_del_net_client(nc); 1453fd9400b3SPaolo Bonzini } 1454fd9400b3SPaolo Bonzini } 1455ca77d85eSMichael S. Tsirkin 1456ca77d85eSMichael S. Tsirkin qemu_del_vm_change_state_handler(net_change_state_entry); 1457948ecf21SJason Wang } 1458fd9400b3SPaolo Bonzini 1459fd9400b3SPaolo Bonzini void net_check_clients(void) 1460fd9400b3SPaolo Bonzini { 1461fd9400b3SPaolo Bonzini NetClientState *nc; 1462fd9400b3SPaolo Bonzini int i; 1463fd9400b3SPaolo Bonzini 1464fd9400b3SPaolo Bonzini net_hub_check_clients(); 1465fd9400b3SPaolo Bonzini 1466fd9400b3SPaolo Bonzini QTAILQ_FOREACH(nc, &net_clients, next) { 1467fd9400b3SPaolo Bonzini if (!nc->peer) { 14688297be80SAlistair Francis warn_report("%s %s has no peer", 1469b62e39b4SAlistair Francis nc->info->type == NET_CLIENT_DRIVER_NIC 1470b62e39b4SAlistair Francis ? "nic" : "netdev", 1471b62e39b4SAlistair Francis nc->name); 1472fd9400b3SPaolo Bonzini } 1473fd9400b3SPaolo Bonzini } 1474fd9400b3SPaolo Bonzini 1475fd9400b3SPaolo Bonzini /* Check that all NICs requested via -net nic actually got created. 1476fd9400b3SPaolo Bonzini * NICs created via -device don't need to be checked here because 1477fd9400b3SPaolo Bonzini * they are always instantiated. 1478fd9400b3SPaolo Bonzini */ 1479fd9400b3SPaolo Bonzini for (i = 0; i < MAX_NICS; i++) { 1480fd9400b3SPaolo Bonzini NICInfo *nd = &nd_table[i]; 1481fd9400b3SPaolo Bonzini if (nd->used && !nd->instantiated) { 14828297be80SAlistair Francis warn_report("requested NIC (%s, model %s) " 14838297be80SAlistair Francis "was not created (not supported by this machine?)", 1484fd9400b3SPaolo Bonzini nd->name ? nd->name : "anonymous", 1485fd9400b3SPaolo Bonzini nd->model ? nd->model : "unspecified"); 1486fd9400b3SPaolo Bonzini } 1487fd9400b3SPaolo Bonzini } 1488fd9400b3SPaolo Bonzini } 1489fd9400b3SPaolo Bonzini 149028d0de7aSMarkus Armbruster static int net_init_client(void *dummy, QemuOpts *opts, Error **errp) 1491fd9400b3SPaolo Bonzini { 149234f708b0SThomas Huth return net_client_init(opts, false, errp); 1493fd9400b3SPaolo Bonzini } 1494fd9400b3SPaolo Bonzini 149528d0de7aSMarkus Armbruster static int net_init_netdev(void *dummy, QemuOpts *opts, Error **errp) 1496fd9400b3SPaolo Bonzini { 1497ad6f932fSPaolo Bonzini const char *type = qemu_opt_get(opts, "type"); 1498ad6f932fSPaolo Bonzini 1499ad6f932fSPaolo Bonzini if (type && is_help_option(type)) { 1500ad6f932fSPaolo Bonzini show_netdevs(); 1501ad6f932fSPaolo Bonzini exit(0); 1502ad6f932fSPaolo Bonzini } 150334f708b0SThomas Huth return net_client_init(opts, true, errp); 1504fd9400b3SPaolo Bonzini } 1505fd9400b3SPaolo Bonzini 150678cd6f7bSThomas Huth /* For the convenience "--nic" parameter */ 150778cd6f7bSThomas Huth static int net_param_nic(void *dummy, QemuOpts *opts, Error **errp) 150878cd6f7bSThomas Huth { 150978cd6f7bSThomas Huth char *mac, *nd_id; 151078cd6f7bSThomas Huth int idx, ret; 151178cd6f7bSThomas Huth NICInfo *ni; 151278cd6f7bSThomas Huth const char *type; 151378cd6f7bSThomas Huth 151478cd6f7bSThomas Huth type = qemu_opt_get(opts, "type"); 151578cd6f7bSThomas Huth if (type && g_str_equal(type, "none")) { 151678cd6f7bSThomas Huth return 0; /* Nothing to do, default_net is cleared in vl.c */ 151778cd6f7bSThomas Huth } 151878cd6f7bSThomas Huth 151978cd6f7bSThomas Huth idx = nic_get_free_idx(); 152078cd6f7bSThomas Huth if (idx == -1 || nb_nics >= MAX_NICS) { 152178cd6f7bSThomas Huth error_setg(errp, "no more on-board/default NIC slots available"); 1522fd9400b3SPaolo Bonzini return -1; 1523fd9400b3SPaolo Bonzini } 1524fd9400b3SPaolo Bonzini 152578cd6f7bSThomas Huth if (!type) { 152678cd6f7bSThomas Huth qemu_opt_set(opts, "type", "user", &error_abort); 152778cd6f7bSThomas Huth } 152878cd6f7bSThomas Huth 152978cd6f7bSThomas Huth ni = &nd_table[idx]; 153078cd6f7bSThomas Huth memset(ni, 0, sizeof(*ni)); 153178cd6f7bSThomas Huth ni->model = qemu_opt_get_del(opts, "model"); 153278cd6f7bSThomas Huth 153378cd6f7bSThomas Huth /* Create an ID if the user did not specify one */ 153478cd6f7bSThomas Huth nd_id = g_strdup(qemu_opts_id(opts)); 153578cd6f7bSThomas Huth if (!nd_id) { 153627eb3722SThomas Huth nd_id = id_generate(ID_NET); 153778cd6f7bSThomas Huth qemu_opts_set_id(opts, nd_id); 153878cd6f7bSThomas Huth } 153978cd6f7bSThomas Huth 154078cd6f7bSThomas Huth /* Handle MAC address */ 154178cd6f7bSThomas Huth mac = qemu_opt_get_del(opts, "mac"); 154278cd6f7bSThomas Huth if (mac) { 154378cd6f7bSThomas Huth ret = net_parse_macaddr(ni->macaddr.a, mac); 154478cd6f7bSThomas Huth g_free(mac); 154578cd6f7bSThomas Huth if (ret) { 154678cd6f7bSThomas Huth error_setg(errp, "invalid syntax for ethernet address"); 15479d946191SThomas Huth goto out; 154878cd6f7bSThomas Huth } 154978cd6f7bSThomas Huth if (is_multicast_ether_addr(ni->macaddr.a)) { 155078cd6f7bSThomas Huth error_setg(errp, "NIC cannot have multicast MAC address"); 15519d946191SThomas Huth ret = -1; 15529d946191SThomas Huth goto out; 155378cd6f7bSThomas Huth } 155478cd6f7bSThomas Huth } 155578cd6f7bSThomas Huth qemu_macaddr_default_if_unset(&ni->macaddr); 155678cd6f7bSThomas Huth 155778cd6f7bSThomas Huth ret = net_client_init(opts, true, errp); 155878cd6f7bSThomas Huth if (ret == 0) { 155978cd6f7bSThomas Huth ni->netdev = qemu_find_netdev(nd_id); 156078cd6f7bSThomas Huth ni->used = true; 156178cd6f7bSThomas Huth nb_nics++; 156278cd6f7bSThomas Huth } 156378cd6f7bSThomas Huth 15649d946191SThomas Huth out: 156578cd6f7bSThomas Huth g_free(nd_id); 1566fd9400b3SPaolo Bonzini return ret; 1567fd9400b3SPaolo Bonzini } 1568fd9400b3SPaolo Bonzini 1569d63ef17bSLaurent Vivier void net_init_clients(void) 1570fd9400b3SPaolo Bonzini { 1571ca77d85eSMichael S. Tsirkin net_change_state_entry = 1572ca77d85eSMichael S. Tsirkin qemu_add_vm_change_state_handler(net_vm_change_state_handler, NULL); 1573ca77d85eSMichael S. Tsirkin 1574fd9400b3SPaolo Bonzini QTAILQ_INIT(&net_clients); 1575fd9400b3SPaolo Bonzini 1576d63ef17bSLaurent Vivier qemu_opts_foreach(qemu_find_opts("netdev"), net_init_netdev, NULL, 1577d63ef17bSLaurent Vivier &error_fatal); 1578fd9400b3SPaolo Bonzini 1579d63ef17bSLaurent Vivier qemu_opts_foreach(qemu_find_opts("nic"), net_param_nic, NULL, 1580d63ef17bSLaurent Vivier &error_fatal); 158178cd6f7bSThomas Huth 1582d63ef17bSLaurent Vivier qemu_opts_foreach(qemu_find_opts("net"), net_init_client, NULL, 1583d63ef17bSLaurent Vivier &error_fatal); 1584fd9400b3SPaolo Bonzini } 1585fd9400b3SPaolo Bonzini 1586*21fccb2cSLaurent Vivier void net_client_parse(QemuOptsList *opts_list, const char *optarg) 1587fd9400b3SPaolo Bonzini { 158870b94331SMarkus Armbruster if (!qemu_opts_parse_noisily(opts_list, optarg, true)) { 1589*21fccb2cSLaurent Vivier exit(1); 1590fd9400b3SPaolo Bonzini } 1591fd9400b3SPaolo Bonzini } 1592fd9400b3SPaolo Bonzini 1593fd9400b3SPaolo Bonzini /* From FreeBSD */ 1594fd9400b3SPaolo Bonzini /* XXX: optimize */ 1595eaba8f34SMark Cave-Ayland uint32_t net_crc32(const uint8_t *p, int len) 1596fd9400b3SPaolo Bonzini { 1597fd9400b3SPaolo Bonzini uint32_t crc; 1598fd9400b3SPaolo Bonzini int carry, i, j; 1599fd9400b3SPaolo Bonzini uint8_t b; 1600fd9400b3SPaolo Bonzini 1601fd9400b3SPaolo Bonzini crc = 0xffffffff; 1602eaba8f34SMark Cave-Ayland for (i = 0; i < len; i++) { 1603eaba8f34SMark Cave-Ayland b = *p++; 1604fd9400b3SPaolo Bonzini for (j = 0; j < 8; j++) { 1605fd9400b3SPaolo Bonzini carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01); 1606fd9400b3SPaolo Bonzini crc <<= 1; 1607fd9400b3SPaolo Bonzini b >>= 1; 1608fd9400b3SPaolo Bonzini if (carry) { 1609eaba8f34SMark Cave-Ayland crc = ((crc ^ POLYNOMIAL_BE) | carry); 1610fd9400b3SPaolo Bonzini } 1611fd9400b3SPaolo Bonzini } 1612fd9400b3SPaolo Bonzini } 1613eaba8f34SMark Cave-Ayland 1614eaba8f34SMark Cave-Ayland return crc; 1615eaba8f34SMark Cave-Ayland } 1616eaba8f34SMark Cave-Ayland 1617f1a7deb9SMark Cave-Ayland uint32_t net_crc32_le(const uint8_t *p, int len) 1618f1a7deb9SMark Cave-Ayland { 1619f1a7deb9SMark Cave-Ayland uint32_t crc; 1620f1a7deb9SMark Cave-Ayland int carry, i, j; 1621f1a7deb9SMark Cave-Ayland uint8_t b; 1622f1a7deb9SMark Cave-Ayland 1623f1a7deb9SMark Cave-Ayland crc = 0xffffffff; 1624f1a7deb9SMark Cave-Ayland for (i = 0; i < len; i++) { 1625f1a7deb9SMark Cave-Ayland b = *p++; 1626f1a7deb9SMark Cave-Ayland for (j = 0; j < 8; j++) { 1627f1a7deb9SMark Cave-Ayland carry = (crc & 0x1) ^ (b & 0x01); 1628f1a7deb9SMark Cave-Ayland crc >>= 1; 1629f1a7deb9SMark Cave-Ayland b >>= 1; 1630f1a7deb9SMark Cave-Ayland if (carry) { 1631f1a7deb9SMark Cave-Ayland crc ^= POLYNOMIAL_LE; 1632f1a7deb9SMark Cave-Ayland } 1633f1a7deb9SMark Cave-Ayland } 1634f1a7deb9SMark Cave-Ayland } 1635f1a7deb9SMark Cave-Ayland 1636f1a7deb9SMark Cave-Ayland return crc; 1637f1a7deb9SMark Cave-Ayland } 1638f1a7deb9SMark Cave-Ayland 16394d454574SPaolo Bonzini QemuOptsList qemu_netdev_opts = { 16404d454574SPaolo Bonzini .name = "netdev", 16414d454574SPaolo Bonzini .implied_opt_name = "type", 16424d454574SPaolo Bonzini .head = QTAILQ_HEAD_INITIALIZER(qemu_netdev_opts.head), 16434d454574SPaolo Bonzini .desc = { 16444d454574SPaolo Bonzini /* 16454d454574SPaolo Bonzini * no elements => accept any params 16464d454574SPaolo Bonzini * validation will happen later 16474d454574SPaolo Bonzini */ 16484d454574SPaolo Bonzini { /* end of list */ } 16494d454574SPaolo Bonzini }, 16504d454574SPaolo Bonzini }; 16514d454574SPaolo Bonzini 165278cd6f7bSThomas Huth QemuOptsList qemu_nic_opts = { 165378cd6f7bSThomas Huth .name = "nic", 165478cd6f7bSThomas Huth .implied_opt_name = "type", 165578cd6f7bSThomas Huth .head = QTAILQ_HEAD_INITIALIZER(qemu_nic_opts.head), 165678cd6f7bSThomas Huth .desc = { 165778cd6f7bSThomas Huth /* 165878cd6f7bSThomas Huth * no elements => accept any params 165978cd6f7bSThomas Huth * validation will happen later 166078cd6f7bSThomas Huth */ 166178cd6f7bSThomas Huth { /* end of list */ } 166278cd6f7bSThomas Huth }, 166378cd6f7bSThomas Huth }; 166478cd6f7bSThomas Huth 16654d454574SPaolo Bonzini QemuOptsList qemu_net_opts = { 16664d454574SPaolo Bonzini .name = "net", 16674d454574SPaolo Bonzini .implied_opt_name = "type", 16684d454574SPaolo Bonzini .head = QTAILQ_HEAD_INITIALIZER(qemu_net_opts.head), 16694d454574SPaolo Bonzini .desc = { 16704d454574SPaolo Bonzini /* 16714d454574SPaolo Bonzini * no elements => accept any params 16724d454574SPaolo Bonzini * validation will happen later 16734d454574SPaolo Bonzini */ 16744d454574SPaolo Bonzini { /* end of list */ } 16754d454574SPaolo Bonzini }, 16764d454574SPaolo Bonzini }; 167716a3df40SZhang Chen 167816a3df40SZhang Chen void net_socket_rs_init(SocketReadState *rs, 16793cde5ea2SZhang Chen SocketReadStateFinalize *finalize, 16803cde5ea2SZhang Chen bool vnet_hdr) 168116a3df40SZhang Chen { 168216a3df40SZhang Chen rs->state = 0; 16833cde5ea2SZhang Chen rs->vnet_hdr = vnet_hdr; 168416a3df40SZhang Chen rs->index = 0; 168516a3df40SZhang Chen rs->packet_len = 0; 16863cde5ea2SZhang Chen rs->vnet_hdr_len = 0; 168716a3df40SZhang Chen memset(rs->buf, 0, sizeof(rs->buf)); 168816a3df40SZhang Chen rs->finalize = finalize; 168916a3df40SZhang Chen } 169016a3df40SZhang Chen 169116a3df40SZhang Chen /* 169216a3df40SZhang Chen * Returns 1693e9e0a585SZhang Chen * 0: success 1694e9e0a585SZhang Chen * -1: error occurs 169516a3df40SZhang Chen */ 169616a3df40SZhang Chen int net_fill_rstate(SocketReadState *rs, const uint8_t *buf, int size) 169716a3df40SZhang Chen { 169816a3df40SZhang Chen unsigned int l; 169916a3df40SZhang Chen 170016a3df40SZhang Chen while (size > 0) { 17013cde5ea2SZhang Chen /* Reassemble a packet from the network. 17023cde5ea2SZhang Chen * 0 = getting length. 17033cde5ea2SZhang Chen * 1 = getting vnet header length. 17043cde5ea2SZhang Chen * 2 = getting data. 17053cde5ea2SZhang Chen */ 17063cde5ea2SZhang Chen switch (rs->state) { 170716a3df40SZhang Chen case 0: 170816a3df40SZhang Chen l = 4 - rs->index; 170916a3df40SZhang Chen if (l > size) { 171016a3df40SZhang Chen l = size; 171116a3df40SZhang Chen } 171216a3df40SZhang Chen memcpy(rs->buf + rs->index, buf, l); 171316a3df40SZhang Chen buf += l; 171416a3df40SZhang Chen size -= l; 171516a3df40SZhang Chen rs->index += l; 171616a3df40SZhang Chen if (rs->index == 4) { 171716a3df40SZhang Chen /* got length */ 171816a3df40SZhang Chen rs->packet_len = ntohl(*(uint32_t *)rs->buf); 171916a3df40SZhang Chen rs->index = 0; 17203cde5ea2SZhang Chen if (rs->vnet_hdr) { 172116a3df40SZhang Chen rs->state = 1; 17223cde5ea2SZhang Chen } else { 17233cde5ea2SZhang Chen rs->state = 2; 17243cde5ea2SZhang Chen rs->vnet_hdr_len = 0; 17253cde5ea2SZhang Chen } 172616a3df40SZhang Chen } 172716a3df40SZhang Chen break; 172816a3df40SZhang Chen case 1: 17293cde5ea2SZhang Chen l = 4 - rs->index; 17303cde5ea2SZhang Chen if (l > size) { 17313cde5ea2SZhang Chen l = size; 17323cde5ea2SZhang Chen } 17333cde5ea2SZhang Chen memcpy(rs->buf + rs->index, buf, l); 17343cde5ea2SZhang Chen buf += l; 17353cde5ea2SZhang Chen size -= l; 17363cde5ea2SZhang Chen rs->index += l; 17373cde5ea2SZhang Chen if (rs->index == 4) { 17383cde5ea2SZhang Chen /* got vnet header length */ 17393cde5ea2SZhang Chen rs->vnet_hdr_len = ntohl(*(uint32_t *)rs->buf); 17403cde5ea2SZhang Chen rs->index = 0; 17413cde5ea2SZhang Chen rs->state = 2; 17423cde5ea2SZhang Chen } 17433cde5ea2SZhang Chen break; 17443cde5ea2SZhang Chen case 2: 174516a3df40SZhang Chen l = rs->packet_len - rs->index; 174616a3df40SZhang Chen if (l > size) { 174716a3df40SZhang Chen l = size; 174816a3df40SZhang Chen } 174916a3df40SZhang Chen if (rs->index + l <= sizeof(rs->buf)) { 175016a3df40SZhang Chen memcpy(rs->buf + rs->index, buf, l); 175116a3df40SZhang Chen } else { 175216a3df40SZhang Chen fprintf(stderr, "serious error: oversized packet received," 175316a3df40SZhang Chen "connection terminated.\n"); 175416a3df40SZhang Chen rs->index = rs->state = 0; 175516a3df40SZhang Chen return -1; 175616a3df40SZhang Chen } 175716a3df40SZhang Chen 175816a3df40SZhang Chen rs->index += l; 175916a3df40SZhang Chen buf += l; 176016a3df40SZhang Chen size -= l; 176116a3df40SZhang Chen if (rs->index >= rs->packet_len) { 176216a3df40SZhang Chen rs->index = 0; 176316a3df40SZhang Chen rs->state = 0; 1764e79cd406SDaniel P. Berrange assert(rs->finalize); 176516a3df40SZhang Chen rs->finalize(rs); 176616a3df40SZhang Chen } 176716a3df40SZhang Chen break; 176816a3df40SZhang Chen } 176916a3df40SZhang Chen } 1770e9e0a585SZhang Chen 1771e9e0a585SZhang Chen assert(size == 0); 177216a3df40SZhang Chen return 0; 177316a3df40SZhang Chen } 1774