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