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