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