xref: /openbmc/qemu/net/net.c (revision 47f9f158)
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  */
242744d920SPeter Maydell #include "qemu/osdep.h"
25fd9400b3SPaolo Bonzini 
261422e32dSPaolo Bonzini #include "net/net.h"
27fd9400b3SPaolo Bonzini #include "clients.h"
28fd9400b3SPaolo Bonzini #include "hub.h"
291422e32dSPaolo Bonzini #include "net/slirp.h"
30d60b20cfSDmitry Krivenok #include "net/eth.h"
31fd9400b3SPaolo Bonzini #include "util.h"
32fd9400b3SPaolo Bonzini 
3383c9089eSPaolo Bonzini #include "monitor/monitor.h"
34fd9400b3SPaolo Bonzini #include "qemu-common.h"
35f348b6d1SVeronia Bahaa #include "qemu/help_option.h"
36cc7a8ea7SMarkus Armbruster #include "qapi/qmp/qerror.h"
37d49b6836SMarkus Armbruster #include "qemu/error-report.h"
381de7afc9SPaolo Bonzini #include "qemu/sockets.h"
39f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
401de7afc9SPaolo Bonzini #include "qemu/config-file.h"
41fd9400b3SPaolo Bonzini #include "qmp-commands.h"
42fd9400b3SPaolo Bonzini #include "hw/qdev.h"
431de7afc9SPaolo Bonzini #include "qemu/iov.h"
446a1751b7SAlex Bligh #include "qemu/main-loop.h"
45fd9400b3SPaolo Bonzini #include "qapi-visit.h"
46fd9400b3SPaolo Bonzini #include "qapi/opts-visitor.h"
47e1d64c08Szhanghailiang #include "sysemu/sysemu.h"
48fdccce45SYang Hongyang #include "net/filter.h"
49aa9156f4Szhanghailiang #include "qapi/string-output-visitor.h"
50fd9400b3SPaolo Bonzini 
51fd9400b3SPaolo Bonzini /* Net bridge is currently not supported for W32. */
52fd9400b3SPaolo Bonzini #if !defined(_WIN32)
53fd9400b3SPaolo Bonzini # define CONFIG_NET_BRIDGE
54fd9400b3SPaolo Bonzini #endif
55fd9400b3SPaolo Bonzini 
56ca77d85eSMichael S. Tsirkin static VMChangeStateEntry *net_change_state_entry;
57fd9400b3SPaolo Bonzini static QTAILQ_HEAD(, NetClientState) net_clients;
58fd9400b3SPaolo Bonzini 
5984007e81SHani Benhabiles const char *host_net_devices[] = {
6084007e81SHani Benhabiles     "tap",
6184007e81SHani Benhabiles     "socket",
6284007e81SHani Benhabiles     "dump",
6384007e81SHani Benhabiles #ifdef CONFIG_NET_BRIDGE
6484007e81SHani Benhabiles     "bridge",
6584007e81SHani Benhabiles #endif
66027a247bSStefan Hajnoczi #ifdef CONFIG_NETMAP
67027a247bSStefan Hajnoczi     "netmap",
68027a247bSStefan Hajnoczi #endif
6984007e81SHani Benhabiles #ifdef CONFIG_SLIRP
7084007e81SHani Benhabiles     "user",
7184007e81SHani Benhabiles #endif
7284007e81SHani Benhabiles #ifdef CONFIG_VDE
7384007e81SHani Benhabiles     "vde",
7484007e81SHani Benhabiles #endif
7503ce5744SNikolay Nikolaev     "vhost-user",
7684007e81SHani Benhabiles     NULL,
7784007e81SHani Benhabiles };
7884007e81SHani Benhabiles 
79fd9400b3SPaolo Bonzini /***********************************************************/
80fd9400b3SPaolo Bonzini /* network device redirectors */
81fd9400b3SPaolo Bonzini 
82fd9400b3SPaolo Bonzini static int get_str_sep(char *buf, int buf_size, const char **pp, int sep)
83fd9400b3SPaolo Bonzini {
84fd9400b3SPaolo Bonzini     const char *p, *p1;
85fd9400b3SPaolo Bonzini     int len;
86fd9400b3SPaolo Bonzini     p = *pp;
87fd9400b3SPaolo Bonzini     p1 = strchr(p, sep);
88fd9400b3SPaolo Bonzini     if (!p1)
89fd9400b3SPaolo Bonzini         return -1;
90fd9400b3SPaolo Bonzini     len = p1 - p;
91fd9400b3SPaolo Bonzini     p1++;
92fd9400b3SPaolo Bonzini     if (buf_size > 0) {
93fd9400b3SPaolo Bonzini         if (len > buf_size - 1)
94fd9400b3SPaolo Bonzini             len = buf_size - 1;
95fd9400b3SPaolo Bonzini         memcpy(buf, p, len);
96fd9400b3SPaolo Bonzini         buf[len] = '\0';
97fd9400b3SPaolo Bonzini     }
98fd9400b3SPaolo Bonzini     *pp = p1;
99fd9400b3SPaolo Bonzini     return 0;
100fd9400b3SPaolo Bonzini }
101fd9400b3SPaolo Bonzini 
102fd9400b3SPaolo Bonzini int parse_host_port(struct sockaddr_in *saddr, const char *str)
103fd9400b3SPaolo Bonzini {
104fd9400b3SPaolo Bonzini     char buf[512];
105fd9400b3SPaolo Bonzini     struct hostent *he;
106fd9400b3SPaolo Bonzini     const char *p, *r;
107fd9400b3SPaolo Bonzini     int port;
108fd9400b3SPaolo Bonzini 
109fd9400b3SPaolo Bonzini     p = str;
110fd9400b3SPaolo Bonzini     if (get_str_sep(buf, sizeof(buf), &p, ':') < 0)
111fd9400b3SPaolo Bonzini         return -1;
112fd9400b3SPaolo Bonzini     saddr->sin_family = AF_INET;
113fd9400b3SPaolo Bonzini     if (buf[0] == '\0') {
114fd9400b3SPaolo Bonzini         saddr->sin_addr.s_addr = 0;
115fd9400b3SPaolo Bonzini     } else {
116fd9400b3SPaolo Bonzini         if (qemu_isdigit(buf[0])) {
117fd9400b3SPaolo Bonzini             if (!inet_aton(buf, &saddr->sin_addr))
118fd9400b3SPaolo Bonzini                 return -1;
119fd9400b3SPaolo Bonzini         } else {
120fd9400b3SPaolo Bonzini             if ((he = gethostbyname(buf)) == NULL)
121fd9400b3SPaolo Bonzini                 return - 1;
122fd9400b3SPaolo Bonzini             saddr->sin_addr = *(struct in_addr *)he->h_addr;
123fd9400b3SPaolo Bonzini         }
124fd9400b3SPaolo Bonzini     }
125fd9400b3SPaolo Bonzini     port = strtol(p, (char **)&r, 0);
126fd9400b3SPaolo Bonzini     if (r == p)
127fd9400b3SPaolo Bonzini         return -1;
128fd9400b3SPaolo Bonzini     saddr->sin_port = htons(port);
129fd9400b3SPaolo Bonzini     return 0;
130fd9400b3SPaolo Bonzini }
131fd9400b3SPaolo Bonzini 
132890ee6abSScott Feldman char *qemu_mac_strdup_printf(const uint8_t *macaddr)
133890ee6abSScott Feldman {
134890ee6abSScott Feldman     return g_strdup_printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",
135890ee6abSScott Feldman                            macaddr[0], macaddr[1], macaddr[2],
136890ee6abSScott Feldman                            macaddr[3], macaddr[4], macaddr[5]);
137890ee6abSScott Feldman }
138890ee6abSScott Feldman 
139fd9400b3SPaolo Bonzini void qemu_format_nic_info_str(NetClientState *nc, uint8_t macaddr[6])
140fd9400b3SPaolo Bonzini {
141fd9400b3SPaolo Bonzini     snprintf(nc->info_str, sizeof(nc->info_str),
142fd9400b3SPaolo Bonzini              "model=%s,macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
143fd9400b3SPaolo Bonzini              nc->model,
144fd9400b3SPaolo Bonzini              macaddr[0], macaddr[1], macaddr[2],
145fd9400b3SPaolo Bonzini              macaddr[3], macaddr[4], macaddr[5]);
146fd9400b3SPaolo Bonzini }
147fd9400b3SPaolo Bonzini 
1482bc22a58SShannon Zhao static int mac_table[256] = {0};
1492bc22a58SShannon Zhao 
1502bc22a58SShannon Zhao static void qemu_macaddr_set_used(MACAddr *macaddr)
1512bc22a58SShannon Zhao {
1522bc22a58SShannon Zhao     int index;
1532bc22a58SShannon Zhao 
1542bc22a58SShannon Zhao     for (index = 0x56; index < 0xFF; index++) {
1552bc22a58SShannon Zhao         if (macaddr->a[5] == index) {
1562bc22a58SShannon Zhao             mac_table[index]++;
1572bc22a58SShannon Zhao         }
1582bc22a58SShannon Zhao     }
1592bc22a58SShannon Zhao }
1602bc22a58SShannon Zhao 
1612bc22a58SShannon Zhao static void qemu_macaddr_set_free(MACAddr *macaddr)
1622bc22a58SShannon Zhao {
1632bc22a58SShannon Zhao     int index;
1642bc22a58SShannon Zhao     static const MACAddr base = { .a = { 0x52, 0x54, 0x00, 0x12, 0x34, 0 } };
1652bc22a58SShannon Zhao 
1662bc22a58SShannon Zhao     if (memcmp(macaddr->a, &base.a, (sizeof(base.a) - 1)) != 0) {
1672bc22a58SShannon Zhao         return;
1682bc22a58SShannon Zhao     }
1692bc22a58SShannon Zhao     for (index = 0x56; index < 0xFF; index++) {
1702bc22a58SShannon Zhao         if (macaddr->a[5] == index) {
1712bc22a58SShannon Zhao             mac_table[index]--;
1722bc22a58SShannon Zhao         }
1732bc22a58SShannon Zhao     }
1742bc22a58SShannon Zhao }
1752bc22a58SShannon Zhao 
1762bc22a58SShannon Zhao static int qemu_macaddr_get_free(void)
1772bc22a58SShannon Zhao {
1782bc22a58SShannon Zhao     int index;
1792bc22a58SShannon Zhao 
1802bc22a58SShannon Zhao     for (index = 0x56; index < 0xFF; index++) {
1812bc22a58SShannon Zhao         if (mac_table[index] == 0) {
1822bc22a58SShannon Zhao             return index;
1832bc22a58SShannon Zhao         }
1842bc22a58SShannon Zhao     }
1852bc22a58SShannon Zhao 
1862bc22a58SShannon Zhao     return -1;
1872bc22a58SShannon Zhao }
1882bc22a58SShannon Zhao 
189fd9400b3SPaolo Bonzini void qemu_macaddr_default_if_unset(MACAddr *macaddr)
190fd9400b3SPaolo Bonzini {
191fd9400b3SPaolo Bonzini     static const MACAddr zero = { .a = { 0,0,0,0,0,0 } };
1922bc22a58SShannon Zhao     static const MACAddr base = { .a = { 0x52, 0x54, 0x00, 0x12, 0x34, 0 } };
193fd9400b3SPaolo Bonzini 
1942bc22a58SShannon Zhao     if (memcmp(macaddr, &zero, sizeof(zero)) != 0) {
1952bc22a58SShannon Zhao         if (memcmp(macaddr->a, &base.a, (sizeof(base.a) - 1)) != 0) {
196fd9400b3SPaolo Bonzini             return;
1972bc22a58SShannon Zhao         } else {
1982bc22a58SShannon Zhao             qemu_macaddr_set_used(macaddr);
1992bc22a58SShannon Zhao             return;
2002bc22a58SShannon Zhao         }
2012bc22a58SShannon Zhao     }
2022bc22a58SShannon Zhao 
203fd9400b3SPaolo Bonzini     macaddr->a[0] = 0x52;
204fd9400b3SPaolo Bonzini     macaddr->a[1] = 0x54;
205fd9400b3SPaolo Bonzini     macaddr->a[2] = 0x00;
206fd9400b3SPaolo Bonzini     macaddr->a[3] = 0x12;
207fd9400b3SPaolo Bonzini     macaddr->a[4] = 0x34;
2082bc22a58SShannon Zhao     macaddr->a[5] = qemu_macaddr_get_free();
2092bc22a58SShannon Zhao     qemu_macaddr_set_used(macaddr);
210fd9400b3SPaolo Bonzini }
211fd9400b3SPaolo Bonzini 
212fd9400b3SPaolo Bonzini /**
213fd9400b3SPaolo Bonzini  * Generate a name for net client
214fd9400b3SPaolo Bonzini  *
215c963530aSAmos Kong  * Only net clients created with the legacy -net option and NICs need this.
216fd9400b3SPaolo Bonzini  */
217fd9400b3SPaolo Bonzini static char *assign_name(NetClientState *nc1, const char *model)
218fd9400b3SPaolo Bonzini {
219fd9400b3SPaolo Bonzini     NetClientState *nc;
220fd9400b3SPaolo Bonzini     int id = 0;
221fd9400b3SPaolo Bonzini 
222fd9400b3SPaolo Bonzini     QTAILQ_FOREACH(nc, &net_clients, next) {
223fd9400b3SPaolo Bonzini         if (nc == nc1) {
224fd9400b3SPaolo Bonzini             continue;
225fd9400b3SPaolo Bonzini         }
226c963530aSAmos Kong         if (strcmp(nc->model, model) == 0) {
227fd9400b3SPaolo Bonzini             id++;
228fd9400b3SPaolo Bonzini         }
229fd9400b3SPaolo Bonzini     }
230fd9400b3SPaolo Bonzini 
2314bf2c138SHani Benhabiles     return g_strdup_printf("%s.%d", model, id);
232fd9400b3SPaolo Bonzini }
233fd9400b3SPaolo Bonzini 
234f7860455SJason Wang static void qemu_net_client_destructor(NetClientState *nc)
235f7860455SJason Wang {
236f7860455SJason Wang     g_free(nc);
237f7860455SJason Wang }
238f7860455SJason Wang 
23918a1541aSJason Wang static void qemu_net_client_setup(NetClientState *nc,
24018a1541aSJason Wang                                   NetClientInfo *info,
241fd9400b3SPaolo Bonzini                                   NetClientState *peer,
242fd9400b3SPaolo Bonzini                                   const char *model,
243f7860455SJason Wang                                   const char *name,
244f7860455SJason Wang                                   NetClientDestructor *destructor)
245fd9400b3SPaolo Bonzini {
246fd9400b3SPaolo Bonzini     nc->info = info;
247fd9400b3SPaolo Bonzini     nc->model = g_strdup(model);
248fd9400b3SPaolo Bonzini     if (name) {
249fd9400b3SPaolo Bonzini         nc->name = g_strdup(name);
250fd9400b3SPaolo Bonzini     } else {
251fd9400b3SPaolo Bonzini         nc->name = assign_name(nc, model);
252fd9400b3SPaolo Bonzini     }
253fd9400b3SPaolo Bonzini 
254fd9400b3SPaolo Bonzini     if (peer) {
255fd9400b3SPaolo Bonzini         assert(!peer->peer);
256fd9400b3SPaolo Bonzini         nc->peer = peer;
257fd9400b3SPaolo Bonzini         peer->peer = nc;
258fd9400b3SPaolo Bonzini     }
259fd9400b3SPaolo Bonzini     QTAILQ_INSERT_TAIL(&net_clients, nc, next);
260fd9400b3SPaolo Bonzini 
2613e033a46SYang Hongyang     nc->incoming_queue = qemu_new_net_queue(qemu_deliver_packet_iov, nc);
262f7860455SJason Wang     nc->destructor = destructor;
263fdccce45SYang Hongyang     QTAILQ_INIT(&nc->filters);
26418a1541aSJason Wang }
26518a1541aSJason Wang 
26618a1541aSJason Wang NetClientState *qemu_new_net_client(NetClientInfo *info,
26718a1541aSJason Wang                                     NetClientState *peer,
26818a1541aSJason Wang                                     const char *model,
26918a1541aSJason Wang                                     const char *name)
27018a1541aSJason Wang {
27118a1541aSJason Wang     NetClientState *nc;
27218a1541aSJason Wang 
27318a1541aSJason Wang     assert(info->size >= sizeof(NetClientState));
27418a1541aSJason Wang 
27518a1541aSJason Wang     nc = g_malloc0(info->size);
276f7860455SJason Wang     qemu_net_client_setup(nc, info, peer, model, name,
277f7860455SJason Wang                           qemu_net_client_destructor);
27818a1541aSJason Wang 
279fd9400b3SPaolo Bonzini     return nc;
280fd9400b3SPaolo Bonzini }
281fd9400b3SPaolo Bonzini 
282fd9400b3SPaolo Bonzini NICState *qemu_new_nic(NetClientInfo *info,
283fd9400b3SPaolo Bonzini                        NICConf *conf,
284fd9400b3SPaolo Bonzini                        const char *model,
285fd9400b3SPaolo Bonzini                        const char *name,
286fd9400b3SPaolo Bonzini                        void *opaque)
287fd9400b3SPaolo Bonzini {
2881ceef9f2SJason Wang     NetClientState **peers = conf->peers.ncs;
289fd9400b3SPaolo Bonzini     NICState *nic;
290575a1c0eSJiri Pirko     int i, queues = MAX(1, conf->peers.queues);
291fd9400b3SPaolo Bonzini 
292f394b2e2SEric Blake     assert(info->type == NET_CLIENT_DRIVER_NIC);
293fd9400b3SPaolo Bonzini     assert(info->size >= sizeof(NICState));
294fd9400b3SPaolo Bonzini 
295f6b26cf2SJason Wang     nic = g_malloc0(info->size + sizeof(NetClientState) * queues);
296f6b26cf2SJason Wang     nic->ncs = (void *)nic + info->size;
297fd9400b3SPaolo Bonzini     nic->conf = conf;
298fd9400b3SPaolo Bonzini     nic->opaque = opaque;
299fd9400b3SPaolo Bonzini 
300f6b26cf2SJason Wang     for (i = 0; i < queues; i++) {
301f6b26cf2SJason Wang         qemu_net_client_setup(&nic->ncs[i], info, peers[i], model, name,
3021ceef9f2SJason Wang                               NULL);
3031ceef9f2SJason Wang         nic->ncs[i].queue_index = i;
3041ceef9f2SJason Wang     }
3051ceef9f2SJason Wang 
306fd9400b3SPaolo Bonzini     return nic;
307fd9400b3SPaolo Bonzini }
308fd9400b3SPaolo Bonzini 
3091ceef9f2SJason Wang NetClientState *qemu_get_subqueue(NICState *nic, int queue_index)
3101ceef9f2SJason Wang {
311f6b26cf2SJason Wang     return nic->ncs + queue_index;
3121ceef9f2SJason Wang }
3131ceef9f2SJason Wang 
314b356f76dSJason Wang NetClientState *qemu_get_queue(NICState *nic)
315b356f76dSJason Wang {
3161ceef9f2SJason Wang     return qemu_get_subqueue(nic, 0);
317b356f76dSJason Wang }
318b356f76dSJason Wang 
319cc1f0f45SJason Wang NICState *qemu_get_nic(NetClientState *nc)
320cc1f0f45SJason Wang {
3211ceef9f2SJason Wang     NetClientState *nc0 = nc - nc->queue_index;
3221ceef9f2SJason Wang 
323f6b26cf2SJason Wang     return (NICState *)((void *)nc0 - nc->info->size);
324cc1f0f45SJason Wang }
325cc1f0f45SJason Wang 
326cc1f0f45SJason Wang void *qemu_get_nic_opaque(NetClientState *nc)
327cc1f0f45SJason Wang {
328cc1f0f45SJason Wang     NICState *nic = qemu_get_nic(nc);
329cc1f0f45SJason Wang 
330cc1f0f45SJason Wang     return nic->opaque;
331cc1f0f45SJason Wang }
332cc1f0f45SJason Wang 
333fd9400b3SPaolo Bonzini static void qemu_cleanup_net_client(NetClientState *nc)
334fd9400b3SPaolo Bonzini {
335fd9400b3SPaolo Bonzini     QTAILQ_REMOVE(&net_clients, nc, next);
336fd9400b3SPaolo Bonzini 
337cc2a9043SAndreas Färber     if (nc->info->cleanup) {
338fd9400b3SPaolo Bonzini         nc->info->cleanup(nc);
339fd9400b3SPaolo Bonzini     }
340cc2a9043SAndreas Färber }
341fd9400b3SPaolo Bonzini 
342fd9400b3SPaolo Bonzini static void qemu_free_net_client(NetClientState *nc)
343fd9400b3SPaolo Bonzini {
344067404beSJan Kiszka     if (nc->incoming_queue) {
345067404beSJan Kiszka         qemu_del_net_queue(nc->incoming_queue);
346fd9400b3SPaolo Bonzini     }
347fd9400b3SPaolo Bonzini     if (nc->peer) {
348fd9400b3SPaolo Bonzini         nc->peer->peer = NULL;
349fd9400b3SPaolo Bonzini     }
350fd9400b3SPaolo Bonzini     g_free(nc->name);
351fd9400b3SPaolo Bonzini     g_free(nc->model);
352f7860455SJason Wang     if (nc->destructor) {
353f7860455SJason Wang         nc->destructor(nc);
354f7860455SJason Wang     }
355fd9400b3SPaolo Bonzini }
356fd9400b3SPaolo Bonzini 
357fd9400b3SPaolo Bonzini void qemu_del_net_client(NetClientState *nc)
358fd9400b3SPaolo Bonzini {
3591ceef9f2SJason Wang     NetClientState *ncs[MAX_QUEUE_NUM];
3601ceef9f2SJason Wang     int queues, i;
361fdccce45SYang Hongyang     NetFilterState *nf, *next;
3621ceef9f2SJason Wang 
363f394b2e2SEric Blake     assert(nc->info->type != NET_CLIENT_DRIVER_NIC);
3647fb43911SPaolo Bonzini 
3651ceef9f2SJason Wang     /* If the NetClientState belongs to a multiqueue backend, we will change all
3661ceef9f2SJason Wang      * other NetClientStates also.
3671ceef9f2SJason Wang      */
3681ceef9f2SJason Wang     queues = qemu_find_net_clients_except(nc->name, ncs,
369f394b2e2SEric Blake                                           NET_CLIENT_DRIVER_NIC,
3701ceef9f2SJason Wang                                           MAX_QUEUE_NUM);
3711ceef9f2SJason Wang     assert(queues != 0);
3721ceef9f2SJason Wang 
373fdccce45SYang Hongyang     QTAILQ_FOREACH_SAFE(nf, &nc->filters, next, next) {
374fdccce45SYang Hongyang         object_unparent(OBJECT(nf));
375fdccce45SYang Hongyang     }
376fdccce45SYang Hongyang 
377fd9400b3SPaolo Bonzini     /* If there is a peer NIC, delete and cleanup client, but do not free. */
378f394b2e2SEric Blake     if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_NIC) {
379cc1f0f45SJason Wang         NICState *nic = qemu_get_nic(nc->peer);
380fd9400b3SPaolo Bonzini         if (nic->peer_deleted) {
381fd9400b3SPaolo Bonzini             return;
382fd9400b3SPaolo Bonzini         }
383fd9400b3SPaolo Bonzini         nic->peer_deleted = true;
3841ceef9f2SJason Wang 
3851ceef9f2SJason Wang         for (i = 0; i < queues; i++) {
3861ceef9f2SJason Wang             ncs[i]->peer->link_down = true;
3871ceef9f2SJason Wang         }
3881ceef9f2SJason Wang 
389fd9400b3SPaolo Bonzini         if (nc->peer->info->link_status_changed) {
390fd9400b3SPaolo Bonzini             nc->peer->info->link_status_changed(nc->peer);
391fd9400b3SPaolo Bonzini         }
3921ceef9f2SJason Wang 
3931ceef9f2SJason Wang         for (i = 0; i < queues; i++) {
3941ceef9f2SJason Wang             qemu_cleanup_net_client(ncs[i]);
3951ceef9f2SJason Wang         }
3961ceef9f2SJason Wang 
397fd9400b3SPaolo Bonzini         return;
398fd9400b3SPaolo Bonzini     }
399fd9400b3SPaolo Bonzini 
4001ceef9f2SJason Wang     for (i = 0; i < queues; i++) {
4011ceef9f2SJason Wang         qemu_cleanup_net_client(ncs[i]);
4021ceef9f2SJason Wang         qemu_free_net_client(ncs[i]);
4031ceef9f2SJason Wang     }
404948ecf21SJason Wang }
405948ecf21SJason Wang 
406948ecf21SJason Wang void qemu_del_nic(NICState *nic)
407948ecf21SJason Wang {
408575a1c0eSJiri Pirko     int i, queues = MAX(nic->conf->peers.queues, 1);
4091ceef9f2SJason Wang 
4102bc22a58SShannon Zhao     qemu_macaddr_set_free(&nic->conf->macaddr);
4112bc22a58SShannon Zhao 
412fd9400b3SPaolo Bonzini     /* If this is a peer NIC and peer has already been deleted, free it now. */
413fd9400b3SPaolo Bonzini     if (nic->peer_deleted) {
4141ceef9f2SJason Wang         for (i = 0; i < queues; i++) {
4151ceef9f2SJason Wang             qemu_free_net_client(qemu_get_subqueue(nic, i)->peer);
416fd9400b3SPaolo Bonzini         }
417fd9400b3SPaolo Bonzini     }
418fd9400b3SPaolo Bonzini 
4191ceef9f2SJason Wang     for (i = queues - 1; i >= 0; i--) {
4201ceef9f2SJason Wang         NetClientState *nc = qemu_get_subqueue(nic, i);
4211ceef9f2SJason Wang 
422fd9400b3SPaolo Bonzini         qemu_cleanup_net_client(nc);
423fd9400b3SPaolo Bonzini         qemu_free_net_client(nc);
424fd9400b3SPaolo Bonzini     }
425f6b26cf2SJason Wang 
426f6b26cf2SJason Wang     g_free(nic);
4271ceef9f2SJason Wang }
428fd9400b3SPaolo Bonzini 
429fd9400b3SPaolo Bonzini void qemu_foreach_nic(qemu_nic_foreach func, void *opaque)
430fd9400b3SPaolo Bonzini {
431fd9400b3SPaolo Bonzini     NetClientState *nc;
432fd9400b3SPaolo Bonzini 
433fd9400b3SPaolo Bonzini     QTAILQ_FOREACH(nc, &net_clients, next) {
434f394b2e2SEric Blake         if (nc->info->type == NET_CLIENT_DRIVER_NIC) {
4351ceef9f2SJason Wang             if (nc->queue_index == 0) {
436cc1f0f45SJason Wang                 func(qemu_get_nic(nc), opaque);
437fd9400b3SPaolo Bonzini             }
438fd9400b3SPaolo Bonzini         }
439fd9400b3SPaolo Bonzini     }
4401ceef9f2SJason Wang }
441fd9400b3SPaolo Bonzini 
442d6085e3aSStefan Hajnoczi bool qemu_has_ufo(NetClientState *nc)
4431f55ac45SVincenzo Maffione {
444d6085e3aSStefan Hajnoczi     if (!nc || !nc->info->has_ufo) {
4451f55ac45SVincenzo Maffione         return false;
4461f55ac45SVincenzo Maffione     }
4471f55ac45SVincenzo Maffione 
448d6085e3aSStefan Hajnoczi     return nc->info->has_ufo(nc);
4491f55ac45SVincenzo Maffione }
4501f55ac45SVincenzo Maffione 
451d6085e3aSStefan Hajnoczi bool qemu_has_vnet_hdr(NetClientState *nc)
4521f55ac45SVincenzo Maffione {
453d6085e3aSStefan Hajnoczi     if (!nc || !nc->info->has_vnet_hdr) {
4541f55ac45SVincenzo Maffione         return false;
4551f55ac45SVincenzo Maffione     }
4561f55ac45SVincenzo Maffione 
457d6085e3aSStefan Hajnoczi     return nc->info->has_vnet_hdr(nc);
4581f55ac45SVincenzo Maffione }
4591f55ac45SVincenzo Maffione 
460d6085e3aSStefan Hajnoczi bool qemu_has_vnet_hdr_len(NetClientState *nc, int len)
4611f55ac45SVincenzo Maffione {
462d6085e3aSStefan Hajnoczi     if (!nc || !nc->info->has_vnet_hdr_len) {
4631f55ac45SVincenzo Maffione         return false;
4641f55ac45SVincenzo Maffione     }
4651f55ac45SVincenzo Maffione 
466d6085e3aSStefan Hajnoczi     return nc->info->has_vnet_hdr_len(nc, len);
4671f55ac45SVincenzo Maffione }
4681f55ac45SVincenzo Maffione 
469d6085e3aSStefan Hajnoczi void qemu_using_vnet_hdr(NetClientState *nc, bool enable)
4701f55ac45SVincenzo Maffione {
471d6085e3aSStefan Hajnoczi     if (!nc || !nc->info->using_vnet_hdr) {
4721f55ac45SVincenzo Maffione         return;
4731f55ac45SVincenzo Maffione     }
4741f55ac45SVincenzo Maffione 
475d6085e3aSStefan Hajnoczi     nc->info->using_vnet_hdr(nc, enable);
4761f55ac45SVincenzo Maffione }
4771f55ac45SVincenzo Maffione 
478d6085e3aSStefan Hajnoczi void qemu_set_offload(NetClientState *nc, int csum, int tso4, int tso6,
4791f55ac45SVincenzo Maffione                           int ecn, int ufo)
4801f55ac45SVincenzo Maffione {
481d6085e3aSStefan Hajnoczi     if (!nc || !nc->info->set_offload) {
4821f55ac45SVincenzo Maffione         return;
4831f55ac45SVincenzo Maffione     }
4841f55ac45SVincenzo Maffione 
485d6085e3aSStefan Hajnoczi     nc->info->set_offload(nc, csum, tso4, tso6, ecn, ufo);
4861f55ac45SVincenzo Maffione }
4871f55ac45SVincenzo Maffione 
488d6085e3aSStefan Hajnoczi void qemu_set_vnet_hdr_len(NetClientState *nc, int len)
4891f55ac45SVincenzo Maffione {
490d6085e3aSStefan Hajnoczi     if (!nc || !nc->info->set_vnet_hdr_len) {
4911f55ac45SVincenzo Maffione         return;
4921f55ac45SVincenzo Maffione     }
4931f55ac45SVincenzo Maffione 
494d6085e3aSStefan Hajnoczi     nc->info->set_vnet_hdr_len(nc, len);
4951f55ac45SVincenzo Maffione }
4961f55ac45SVincenzo Maffione 
497c80cd6bbSGreg Kurz int qemu_set_vnet_le(NetClientState *nc, bool is_le)
498c80cd6bbSGreg Kurz {
499052bd52fSMichael S. Tsirkin #ifdef HOST_WORDS_BIGENDIAN
500c80cd6bbSGreg Kurz     if (!nc || !nc->info->set_vnet_le) {
501c80cd6bbSGreg Kurz         return -ENOSYS;
502c80cd6bbSGreg Kurz     }
503c80cd6bbSGreg Kurz 
504c80cd6bbSGreg Kurz     return nc->info->set_vnet_le(nc, is_le);
505052bd52fSMichael S. Tsirkin #else
506052bd52fSMichael S. Tsirkin     return 0;
507052bd52fSMichael S. Tsirkin #endif
508c80cd6bbSGreg Kurz }
509c80cd6bbSGreg Kurz 
510c80cd6bbSGreg Kurz int qemu_set_vnet_be(NetClientState *nc, bool is_be)
511c80cd6bbSGreg Kurz {
512052bd52fSMichael S. Tsirkin #ifdef HOST_WORDS_BIGENDIAN
513052bd52fSMichael S. Tsirkin     return 0;
514052bd52fSMichael S. Tsirkin #else
515c80cd6bbSGreg Kurz     if (!nc || !nc->info->set_vnet_be) {
516c80cd6bbSGreg Kurz         return -ENOSYS;
517c80cd6bbSGreg Kurz     }
518c80cd6bbSGreg Kurz 
519c80cd6bbSGreg Kurz     return nc->info->set_vnet_be(nc, is_be);
520052bd52fSMichael S. Tsirkin #endif
521c80cd6bbSGreg Kurz }
522c80cd6bbSGreg Kurz 
523fd9400b3SPaolo Bonzini int qemu_can_send_packet(NetClientState *sender)
524fd9400b3SPaolo Bonzini {
525e1d64c08Szhanghailiang     int vm_running = runstate_is_running();
526e1d64c08Szhanghailiang 
527e1d64c08Szhanghailiang     if (!vm_running) {
528e1d64c08Szhanghailiang         return 0;
529e1d64c08Szhanghailiang     }
530e1d64c08Szhanghailiang 
531fd9400b3SPaolo Bonzini     if (!sender->peer) {
532fd9400b3SPaolo Bonzini         return 1;
533fd9400b3SPaolo Bonzini     }
534fd9400b3SPaolo Bonzini 
535fd9400b3SPaolo Bonzini     if (sender->peer->receive_disabled) {
536fd9400b3SPaolo Bonzini         return 0;
537fd9400b3SPaolo Bonzini     } else if (sender->peer->info->can_receive &&
538fd9400b3SPaolo Bonzini                !sender->peer->info->can_receive(sender->peer)) {
539fd9400b3SPaolo Bonzini         return 0;
540fd9400b3SPaolo Bonzini     }
541fd9400b3SPaolo Bonzini     return 1;
542fd9400b3SPaolo Bonzini }
543fd9400b3SPaolo Bonzini 
544e64c770dSYang Hongyang static ssize_t filter_receive_iov(NetClientState *nc,
545e64c770dSYang Hongyang                                   NetFilterDirection direction,
546e64c770dSYang Hongyang                                   NetClientState *sender,
547e64c770dSYang Hongyang                                   unsigned flags,
548e64c770dSYang Hongyang                                   const struct iovec *iov,
549e64c770dSYang Hongyang                                   int iovcnt,
550e64c770dSYang Hongyang                                   NetPacketSent *sent_cb)
551e64c770dSYang Hongyang {
552e64c770dSYang Hongyang     ssize_t ret = 0;
553e64c770dSYang Hongyang     NetFilterState *nf = NULL;
554e64c770dSYang Hongyang 
55525aaadf0SLi Zhijian     if (direction == NET_FILTER_DIRECTION_TX) {
556e64c770dSYang Hongyang         QTAILQ_FOREACH(nf, &nc->filters, next) {
557e64c770dSYang Hongyang             ret = qemu_netfilter_receive(nf, direction, sender, flags, iov,
558e64c770dSYang Hongyang                                          iovcnt, sent_cb);
559e64c770dSYang Hongyang             if (ret) {
560e64c770dSYang Hongyang                 return ret;
561e64c770dSYang Hongyang             }
562e64c770dSYang Hongyang         }
56325aaadf0SLi Zhijian     } else {
56425aaadf0SLi Zhijian         QTAILQ_FOREACH_REVERSE(nf, &nc->filters, NetFilterHead, next) {
56525aaadf0SLi Zhijian             ret = qemu_netfilter_receive(nf, direction, sender, flags, iov,
56625aaadf0SLi Zhijian                                          iovcnt, sent_cb);
56725aaadf0SLi Zhijian             if (ret) {
56825aaadf0SLi Zhijian                 return ret;
56925aaadf0SLi Zhijian             }
57025aaadf0SLi Zhijian         }
57125aaadf0SLi Zhijian     }
572e64c770dSYang Hongyang 
573e64c770dSYang Hongyang     return ret;
574e64c770dSYang Hongyang }
575e64c770dSYang Hongyang 
576e64c770dSYang Hongyang static ssize_t filter_receive(NetClientState *nc,
577e64c770dSYang Hongyang                               NetFilterDirection direction,
578e64c770dSYang Hongyang                               NetClientState *sender,
579e64c770dSYang Hongyang                               unsigned flags,
580e64c770dSYang Hongyang                               const uint8_t *data,
581e64c770dSYang Hongyang                               size_t size,
582e64c770dSYang Hongyang                               NetPacketSent *sent_cb)
583e64c770dSYang Hongyang {
584e64c770dSYang Hongyang     struct iovec iov = {
585e64c770dSYang Hongyang         .iov_base = (void *)data,
586e64c770dSYang Hongyang         .iov_len = size
587e64c770dSYang Hongyang     };
588e64c770dSYang Hongyang 
589e64c770dSYang Hongyang     return filter_receive_iov(nc, direction, sender, flags, &iov, 1, sent_cb);
590e64c770dSYang Hongyang }
591e64c770dSYang Hongyang 
592fd9400b3SPaolo Bonzini void qemu_purge_queued_packets(NetClientState *nc)
593fd9400b3SPaolo Bonzini {
594fd9400b3SPaolo Bonzini     if (!nc->peer) {
595fd9400b3SPaolo Bonzini         return;
596fd9400b3SPaolo Bonzini     }
597fd9400b3SPaolo Bonzini 
598067404beSJan Kiszka     qemu_net_queue_purge(nc->peer->incoming_queue, nc);
599fd9400b3SPaolo Bonzini }
600fd9400b3SPaolo Bonzini 
601ca77d85eSMichael S. Tsirkin static
602ca77d85eSMichael S. Tsirkin void qemu_flush_or_purge_queued_packets(NetClientState *nc, bool purge)
603fd9400b3SPaolo Bonzini {
604fd9400b3SPaolo Bonzini     nc->receive_disabled = 0;
605fd9400b3SPaolo Bonzini 
606f394b2e2SEric Blake     if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_HUBPORT) {
607199ee608SLuigi Rizzo         if (net_hub_flush(nc->peer)) {
608199ee608SLuigi Rizzo             qemu_notify_event();
609199ee608SLuigi Rizzo         }
610199ee608SLuigi Rizzo     }
611067404beSJan Kiszka     if (qemu_net_queue_flush(nc->incoming_queue)) {
612fd9400b3SPaolo Bonzini         /* We emptied the queue successfully, signal to the IO thread to repoll
613fd9400b3SPaolo Bonzini          * the file descriptor (for tap, for example).
614fd9400b3SPaolo Bonzini          */
615fd9400b3SPaolo Bonzini         qemu_notify_event();
616ca77d85eSMichael S. Tsirkin     } else if (purge) {
617ca77d85eSMichael S. Tsirkin         /* Unable to empty the queue, purge remaining packets */
618ca77d85eSMichael S. Tsirkin         qemu_net_queue_purge(nc->incoming_queue, nc);
619fd9400b3SPaolo Bonzini     }
620fd9400b3SPaolo Bonzini }
621fd9400b3SPaolo Bonzini 
622ca77d85eSMichael S. Tsirkin void qemu_flush_queued_packets(NetClientState *nc)
623ca77d85eSMichael S. Tsirkin {
624ca77d85eSMichael S. Tsirkin     qemu_flush_or_purge_queued_packets(nc, false);
625ca77d85eSMichael S. Tsirkin }
626ca77d85eSMichael S. Tsirkin 
627fd9400b3SPaolo Bonzini static ssize_t qemu_send_packet_async_with_flags(NetClientState *sender,
628fd9400b3SPaolo Bonzini                                                  unsigned flags,
629fd9400b3SPaolo Bonzini                                                  const uint8_t *buf, int size,
630fd9400b3SPaolo Bonzini                                                  NetPacketSent *sent_cb)
631fd9400b3SPaolo Bonzini {
632fd9400b3SPaolo Bonzini     NetQueue *queue;
633e64c770dSYang Hongyang     int ret;
634fd9400b3SPaolo Bonzini 
635fd9400b3SPaolo Bonzini #ifdef DEBUG_NET
636fd9400b3SPaolo Bonzini     printf("qemu_send_packet_async:\n");
637a1555559SIsaac Lozano     qemu_hexdump((const char *)buf, stdout, "net", size);
638fd9400b3SPaolo Bonzini #endif
639fd9400b3SPaolo Bonzini 
640fd9400b3SPaolo Bonzini     if (sender->link_down || !sender->peer) {
641fd9400b3SPaolo Bonzini         return size;
642fd9400b3SPaolo Bonzini     }
643fd9400b3SPaolo Bonzini 
644e64c770dSYang Hongyang     /* Let filters handle the packet first */
645e64c770dSYang Hongyang     ret = filter_receive(sender, NET_FILTER_DIRECTION_TX,
646e64c770dSYang Hongyang                          sender, flags, buf, size, sent_cb);
647e64c770dSYang Hongyang     if (ret) {
648e64c770dSYang Hongyang         return ret;
649e64c770dSYang Hongyang     }
650e64c770dSYang Hongyang 
651e64c770dSYang Hongyang     ret = filter_receive(sender->peer, NET_FILTER_DIRECTION_RX,
652e64c770dSYang Hongyang                          sender, flags, buf, size, sent_cb);
653e64c770dSYang Hongyang     if (ret) {
654e64c770dSYang Hongyang         return ret;
655e64c770dSYang Hongyang     }
656e64c770dSYang Hongyang 
657067404beSJan Kiszka     queue = sender->peer->incoming_queue;
658fd9400b3SPaolo Bonzini 
659fd9400b3SPaolo Bonzini     return qemu_net_queue_send(queue, sender, flags, buf, size, sent_cb);
660fd9400b3SPaolo Bonzini }
661fd9400b3SPaolo Bonzini 
662fd9400b3SPaolo Bonzini ssize_t qemu_send_packet_async(NetClientState *sender,
663fd9400b3SPaolo Bonzini                                const uint8_t *buf, int size,
664fd9400b3SPaolo Bonzini                                NetPacketSent *sent_cb)
665fd9400b3SPaolo Bonzini {
666fd9400b3SPaolo Bonzini     return qemu_send_packet_async_with_flags(sender, QEMU_NET_PACKET_FLAG_NONE,
667fd9400b3SPaolo Bonzini                                              buf, size, sent_cb);
668fd9400b3SPaolo Bonzini }
669fd9400b3SPaolo Bonzini 
670fd9400b3SPaolo Bonzini void qemu_send_packet(NetClientState *nc, const uint8_t *buf, int size)
671fd9400b3SPaolo Bonzini {
672fd9400b3SPaolo Bonzini     qemu_send_packet_async(nc, buf, size, NULL);
673fd9400b3SPaolo Bonzini }
674fd9400b3SPaolo Bonzini 
675fd9400b3SPaolo Bonzini ssize_t qemu_send_packet_raw(NetClientState *nc, const uint8_t *buf, int size)
676fd9400b3SPaolo Bonzini {
677fd9400b3SPaolo Bonzini     return qemu_send_packet_async_with_flags(nc, QEMU_NET_PACKET_FLAG_RAW,
678fd9400b3SPaolo Bonzini                                              buf, size, NULL);
679fd9400b3SPaolo Bonzini }
680fd9400b3SPaolo Bonzini 
681fd9400b3SPaolo Bonzini static ssize_t nc_sendv_compat(NetClientState *nc, const struct iovec *iov,
682fefe2a78SYang Hongyang                                int iovcnt, unsigned flags)
683fd9400b3SPaolo Bonzini {
68474044c8fSPooja Dhannawat     uint8_t *buf = NULL;
685fefe2a78SYang Hongyang     uint8_t *buffer;
686fd9400b3SPaolo Bonzini     size_t offset;
68774044c8fSPooja Dhannawat     ssize_t ret;
688fd9400b3SPaolo Bonzini 
689fefe2a78SYang Hongyang     if (iovcnt == 1) {
690fefe2a78SYang Hongyang         buffer = iov[0].iov_base;
691fefe2a78SYang Hongyang         offset = iov[0].iov_len;
692fefe2a78SYang Hongyang     } else {
693*47f9f158SPeter Lieven         offset = iov_size(iov, iovcnt);
694*47f9f158SPeter Lieven         if (offset > NET_BUFSIZE) {
695*47f9f158SPeter Lieven             return -1;
696*47f9f158SPeter Lieven         }
697*47f9f158SPeter Lieven         buf = g_malloc(offset);
698fefe2a78SYang Hongyang         buffer = buf;
699*47f9f158SPeter Lieven         offset = iov_to_buf(iov, iovcnt, 0, buf, offset);
700fefe2a78SYang Hongyang     }
701fd9400b3SPaolo Bonzini 
702fefe2a78SYang Hongyang     if (flags & QEMU_NET_PACKET_FLAG_RAW && nc->info->receive_raw) {
70374044c8fSPooja Dhannawat         ret = nc->info->receive_raw(nc, buffer, offset);
704fefe2a78SYang Hongyang     } else {
70574044c8fSPooja Dhannawat         ret = nc->info->receive(nc, buffer, offset);
706fd9400b3SPaolo Bonzini     }
70774044c8fSPooja Dhannawat 
70874044c8fSPooja Dhannawat     g_free(buf);
70974044c8fSPooja Dhannawat     return ret;
710fefe2a78SYang Hongyang }
711fd9400b3SPaolo Bonzini 
712fd9400b3SPaolo Bonzini ssize_t qemu_deliver_packet_iov(NetClientState *sender,
713fd9400b3SPaolo Bonzini                                 unsigned flags,
714fd9400b3SPaolo Bonzini                                 const struct iovec *iov,
715fd9400b3SPaolo Bonzini                                 int iovcnt,
716fd9400b3SPaolo Bonzini                                 void *opaque)
717fd9400b3SPaolo Bonzini {
718fd9400b3SPaolo Bonzini     NetClientState *nc = opaque;
719fd9400b3SPaolo Bonzini     int ret;
720fd9400b3SPaolo Bonzini 
721fd9400b3SPaolo Bonzini     if (nc->link_down) {
722fd9400b3SPaolo Bonzini         return iov_size(iov, iovcnt);
723fd9400b3SPaolo Bonzini     }
724fd9400b3SPaolo Bonzini 
725fd9400b3SPaolo Bonzini     if (nc->receive_disabled) {
726fd9400b3SPaolo Bonzini         return 0;
727fd9400b3SPaolo Bonzini     }
728fd9400b3SPaolo Bonzini 
729ca1ee3d6SPeter Lieven     if (nc->info->receive_iov && !(flags & QEMU_NET_PACKET_FLAG_RAW)) {
730fd9400b3SPaolo Bonzini         ret = nc->info->receive_iov(nc, iov, iovcnt);
731fd9400b3SPaolo Bonzini     } else {
732fefe2a78SYang Hongyang         ret = nc_sendv_compat(nc, iov, iovcnt, flags);
733fd9400b3SPaolo Bonzini     }
734fd9400b3SPaolo Bonzini 
735fd9400b3SPaolo Bonzini     if (ret == 0) {
736fd9400b3SPaolo Bonzini         nc->receive_disabled = 1;
737fd9400b3SPaolo Bonzini     }
738fd9400b3SPaolo Bonzini 
739fd9400b3SPaolo Bonzini     return ret;
740fd9400b3SPaolo Bonzini }
741fd9400b3SPaolo Bonzini 
742fd9400b3SPaolo Bonzini ssize_t qemu_sendv_packet_async(NetClientState *sender,
743fd9400b3SPaolo Bonzini                                 const struct iovec *iov, int iovcnt,
744fd9400b3SPaolo Bonzini                                 NetPacketSent *sent_cb)
745fd9400b3SPaolo Bonzini {
746fd9400b3SPaolo Bonzini     NetQueue *queue;
747e64c770dSYang Hongyang     int ret;
748fd9400b3SPaolo Bonzini 
749fd9400b3SPaolo Bonzini     if (sender->link_down || !sender->peer) {
750fd9400b3SPaolo Bonzini         return iov_size(iov, iovcnt);
751fd9400b3SPaolo Bonzini     }
752fd9400b3SPaolo Bonzini 
753e64c770dSYang Hongyang     /* Let filters handle the packet first */
754e64c770dSYang Hongyang     ret = filter_receive_iov(sender, NET_FILTER_DIRECTION_TX, sender,
755e64c770dSYang Hongyang                              QEMU_NET_PACKET_FLAG_NONE, iov, iovcnt, sent_cb);
756e64c770dSYang Hongyang     if (ret) {
757e64c770dSYang Hongyang         return ret;
758e64c770dSYang Hongyang     }
759e64c770dSYang Hongyang 
760e64c770dSYang Hongyang     ret = filter_receive_iov(sender->peer, NET_FILTER_DIRECTION_RX, sender,
761e64c770dSYang Hongyang                              QEMU_NET_PACKET_FLAG_NONE, iov, iovcnt, sent_cb);
762e64c770dSYang Hongyang     if (ret) {
763e64c770dSYang Hongyang         return ret;
764e64c770dSYang Hongyang     }
765e64c770dSYang Hongyang 
766067404beSJan Kiszka     queue = sender->peer->incoming_queue;
767fd9400b3SPaolo Bonzini 
768fd9400b3SPaolo Bonzini     return qemu_net_queue_send_iov(queue, sender,
769fd9400b3SPaolo Bonzini                                    QEMU_NET_PACKET_FLAG_NONE,
770fd9400b3SPaolo Bonzini                                    iov, iovcnt, sent_cb);
771fd9400b3SPaolo Bonzini }
772fd9400b3SPaolo Bonzini 
773fd9400b3SPaolo Bonzini ssize_t
774fd9400b3SPaolo Bonzini qemu_sendv_packet(NetClientState *nc, const struct iovec *iov, int iovcnt)
775fd9400b3SPaolo Bonzini {
776fd9400b3SPaolo Bonzini     return qemu_sendv_packet_async(nc, iov, iovcnt, NULL);
777fd9400b3SPaolo Bonzini }
778fd9400b3SPaolo Bonzini 
779fd9400b3SPaolo Bonzini NetClientState *qemu_find_netdev(const char *id)
780fd9400b3SPaolo Bonzini {
781fd9400b3SPaolo Bonzini     NetClientState *nc;
782fd9400b3SPaolo Bonzini 
783fd9400b3SPaolo Bonzini     QTAILQ_FOREACH(nc, &net_clients, next) {
784f394b2e2SEric Blake         if (nc->info->type == NET_CLIENT_DRIVER_NIC)
785fd9400b3SPaolo Bonzini             continue;
786fd9400b3SPaolo Bonzini         if (!strcmp(nc->name, id)) {
787fd9400b3SPaolo Bonzini             return nc;
788fd9400b3SPaolo Bonzini         }
789fd9400b3SPaolo Bonzini     }
790fd9400b3SPaolo Bonzini 
791fd9400b3SPaolo Bonzini     return NULL;
792fd9400b3SPaolo Bonzini }
793fd9400b3SPaolo Bonzini 
7946c51ae73SJason Wang int qemu_find_net_clients_except(const char *id, NetClientState **ncs,
795f394b2e2SEric Blake                                  NetClientDriver type, int max)
7966c51ae73SJason Wang {
7976c51ae73SJason Wang     NetClientState *nc;
7986c51ae73SJason Wang     int ret = 0;
7996c51ae73SJason Wang 
8006c51ae73SJason Wang     QTAILQ_FOREACH(nc, &net_clients, next) {
8016c51ae73SJason Wang         if (nc->info->type == type) {
8026c51ae73SJason Wang             continue;
8036c51ae73SJason Wang         }
80440d19394SHani Benhabiles         if (!id || !strcmp(nc->name, id)) {
8056c51ae73SJason Wang             if (ret < max) {
8066c51ae73SJason Wang                 ncs[ret] = nc;
8076c51ae73SJason Wang             }
8086c51ae73SJason Wang             ret++;
8096c51ae73SJason Wang         }
8106c51ae73SJason Wang     }
8116c51ae73SJason Wang 
8126c51ae73SJason Wang     return ret;
8136c51ae73SJason Wang }
8146c51ae73SJason Wang 
815fd9400b3SPaolo Bonzini static int nic_get_free_idx(void)
816fd9400b3SPaolo Bonzini {
817fd9400b3SPaolo Bonzini     int index;
818fd9400b3SPaolo Bonzini 
819fd9400b3SPaolo Bonzini     for (index = 0; index < MAX_NICS; index++)
820fd9400b3SPaolo Bonzini         if (!nd_table[index].used)
821fd9400b3SPaolo Bonzini             return index;
822fd9400b3SPaolo Bonzini     return -1;
823fd9400b3SPaolo Bonzini }
824fd9400b3SPaolo Bonzini 
825fd9400b3SPaolo Bonzini int qemu_show_nic_models(const char *arg, const char *const *models)
826fd9400b3SPaolo Bonzini {
827fd9400b3SPaolo Bonzini     int i;
828fd9400b3SPaolo Bonzini 
829fd9400b3SPaolo Bonzini     if (!arg || !is_help_option(arg)) {
830fd9400b3SPaolo Bonzini         return 0;
831fd9400b3SPaolo Bonzini     }
832fd9400b3SPaolo Bonzini 
833fd9400b3SPaolo Bonzini     fprintf(stderr, "qemu: Supported NIC models: ");
834fd9400b3SPaolo Bonzini     for (i = 0 ; models[i]; i++)
835fd9400b3SPaolo Bonzini         fprintf(stderr, "%s%c", models[i], models[i+1] ? ',' : '\n');
836fd9400b3SPaolo Bonzini     return 1;
837fd9400b3SPaolo Bonzini }
838fd9400b3SPaolo Bonzini 
839fd9400b3SPaolo Bonzini void qemu_check_nic_model(NICInfo *nd, const char *model)
840fd9400b3SPaolo Bonzini {
841fd9400b3SPaolo Bonzini     const char *models[2];
842fd9400b3SPaolo Bonzini 
843fd9400b3SPaolo Bonzini     models[0] = model;
844fd9400b3SPaolo Bonzini     models[1] = NULL;
845fd9400b3SPaolo Bonzini 
846fd9400b3SPaolo Bonzini     if (qemu_show_nic_models(nd->model, models))
847fd9400b3SPaolo Bonzini         exit(0);
848fd9400b3SPaolo Bonzini     if (qemu_find_nic_model(nd, models, model) < 0)
849fd9400b3SPaolo Bonzini         exit(1);
850fd9400b3SPaolo Bonzini }
851fd9400b3SPaolo Bonzini 
852fd9400b3SPaolo Bonzini int qemu_find_nic_model(NICInfo *nd, const char * const *models,
853fd9400b3SPaolo Bonzini                         const char *default_model)
854fd9400b3SPaolo Bonzini {
855fd9400b3SPaolo Bonzini     int i;
856fd9400b3SPaolo Bonzini 
857fd9400b3SPaolo Bonzini     if (!nd->model)
858fd9400b3SPaolo Bonzini         nd->model = g_strdup(default_model);
859fd9400b3SPaolo Bonzini 
860fd9400b3SPaolo Bonzini     for (i = 0 ; models[i]; i++) {
861fd9400b3SPaolo Bonzini         if (strcmp(nd->model, models[i]) == 0)
862fd9400b3SPaolo Bonzini             return i;
863fd9400b3SPaolo Bonzini     }
864fd9400b3SPaolo Bonzini 
865fd9400b3SPaolo Bonzini     error_report("Unsupported NIC model: %s", nd->model);
866fd9400b3SPaolo Bonzini     return -1;
867fd9400b3SPaolo Bonzini }
868fd9400b3SPaolo Bonzini 
869cebea510SKővágó, Zoltán static int net_init_nic(const Netdev *netdev, const char *name,
870a30ecde6SMarkus Armbruster                         NetClientState *peer, Error **errp)
871fd9400b3SPaolo Bonzini {
872fd9400b3SPaolo Bonzini     int idx;
873fd9400b3SPaolo Bonzini     NICInfo *nd;
874fd9400b3SPaolo Bonzini     const NetLegacyNicOptions *nic;
875fd9400b3SPaolo Bonzini 
876f394b2e2SEric Blake     assert(netdev->type == NET_CLIENT_DRIVER_NIC);
877f394b2e2SEric Blake     nic = &netdev->u.nic;
878fd9400b3SPaolo Bonzini 
879fd9400b3SPaolo Bonzini     idx = nic_get_free_idx();
880fd9400b3SPaolo Bonzini     if (idx == -1 || nb_nics >= MAX_NICS) {
88166308868SMarkus Armbruster         error_setg(errp, "too many NICs");
882fd9400b3SPaolo Bonzini         return -1;
883fd9400b3SPaolo Bonzini     }
884fd9400b3SPaolo Bonzini 
885fd9400b3SPaolo Bonzini     nd = &nd_table[idx];
886fd9400b3SPaolo Bonzini 
887fd9400b3SPaolo Bonzini     memset(nd, 0, sizeof(*nd));
888fd9400b3SPaolo Bonzini 
889fd9400b3SPaolo Bonzini     if (nic->has_netdev) {
890fd9400b3SPaolo Bonzini         nd->netdev = qemu_find_netdev(nic->netdev);
891fd9400b3SPaolo Bonzini         if (!nd->netdev) {
89266308868SMarkus Armbruster             error_setg(errp, "netdev '%s' not found", nic->netdev);
893fd9400b3SPaolo Bonzini             return -1;
894fd9400b3SPaolo Bonzini         }
895fd9400b3SPaolo Bonzini     } else {
896fd9400b3SPaolo Bonzini         assert(peer);
897fd9400b3SPaolo Bonzini         nd->netdev = peer;
898fd9400b3SPaolo Bonzini     }
899fd9400b3SPaolo Bonzini     nd->name = g_strdup(name);
900fd9400b3SPaolo Bonzini     if (nic->has_model) {
901fd9400b3SPaolo Bonzini         nd->model = g_strdup(nic->model);
902fd9400b3SPaolo Bonzini     }
903fd9400b3SPaolo Bonzini     if (nic->has_addr) {
904fd9400b3SPaolo Bonzini         nd->devaddr = g_strdup(nic->addr);
905fd9400b3SPaolo Bonzini     }
906fd9400b3SPaolo Bonzini 
907fd9400b3SPaolo Bonzini     if (nic->has_macaddr &&
908fd9400b3SPaolo Bonzini         net_parse_macaddr(nd->macaddr.a, nic->macaddr) < 0) {
90966308868SMarkus Armbruster         error_setg(errp, "invalid syntax for ethernet address");
910fd9400b3SPaolo Bonzini         return -1;
911fd9400b3SPaolo Bonzini     }
912d60b20cfSDmitry Krivenok     if (nic->has_macaddr &&
913d60b20cfSDmitry Krivenok         is_multicast_ether_addr(nd->macaddr.a)) {
91466308868SMarkus Armbruster         error_setg(errp,
91566308868SMarkus Armbruster                    "NIC cannot have multicast MAC address (odd 1st byte)");
916d60b20cfSDmitry Krivenok         return -1;
917d60b20cfSDmitry Krivenok     }
918fd9400b3SPaolo Bonzini     qemu_macaddr_default_if_unset(&nd->macaddr);
919fd9400b3SPaolo Bonzini 
920fd9400b3SPaolo Bonzini     if (nic->has_vectors) {
921fd9400b3SPaolo Bonzini         if (nic->vectors > 0x7ffffff) {
92266308868SMarkus Armbruster             error_setg(errp, "invalid # of vectors: %"PRIu32, nic->vectors);
923fd9400b3SPaolo Bonzini             return -1;
924fd9400b3SPaolo Bonzini         }
925fd9400b3SPaolo Bonzini         nd->nvectors = nic->vectors;
926fd9400b3SPaolo Bonzini     } else {
927fd9400b3SPaolo Bonzini         nd->nvectors = DEV_NVECTORS_UNSPECIFIED;
928fd9400b3SPaolo Bonzini     }
929fd9400b3SPaolo Bonzini 
930fd9400b3SPaolo Bonzini     nd->used = 1;
931fd9400b3SPaolo Bonzini     nb_nics++;
932fd9400b3SPaolo Bonzini 
933fd9400b3SPaolo Bonzini     return idx;
934fd9400b3SPaolo Bonzini }
935fd9400b3SPaolo Bonzini 
936fd9400b3SPaolo Bonzini 
937f394b2e2SEric Blake static int (* const net_client_init_fun[NET_CLIENT_DRIVER__MAX])(
938cebea510SKővágó, Zoltán     const Netdev *netdev,
939fd9400b3SPaolo Bonzini     const char *name,
940a30ecde6SMarkus Armbruster     NetClientState *peer, Error **errp) = {
941f394b2e2SEric Blake         [NET_CLIENT_DRIVER_NIC]       = net_init_nic,
942fd9400b3SPaolo Bonzini #ifdef CONFIG_SLIRP
943f394b2e2SEric Blake         [NET_CLIENT_DRIVER_USER]      = net_init_slirp,
944fd9400b3SPaolo Bonzini #endif
945f394b2e2SEric Blake         [NET_CLIENT_DRIVER_TAP]       = net_init_tap,
946f394b2e2SEric Blake         [NET_CLIENT_DRIVER_SOCKET]    = net_init_socket,
947fd9400b3SPaolo Bonzini #ifdef CONFIG_VDE
948f394b2e2SEric Blake         [NET_CLIENT_DRIVER_VDE]       = net_init_vde,
949fd9400b3SPaolo Bonzini #endif
95058952137SVincenzo Maffione #ifdef CONFIG_NETMAP
951f394b2e2SEric Blake         [NET_CLIENT_DRIVER_NETMAP]    = net_init_netmap,
95258952137SVincenzo Maffione #endif
953f394b2e2SEric Blake         [NET_CLIENT_DRIVER_DUMP]      = net_init_dump,
954fd9400b3SPaolo Bonzini #ifdef CONFIG_NET_BRIDGE
955f394b2e2SEric Blake         [NET_CLIENT_DRIVER_BRIDGE]    = net_init_bridge,
956fd9400b3SPaolo Bonzini #endif
957f394b2e2SEric Blake         [NET_CLIENT_DRIVER_HUBPORT]   = net_init_hubport,
95803ce5744SNikolay Nikolaev #ifdef CONFIG_VHOST_NET_USED
959f394b2e2SEric Blake         [NET_CLIENT_DRIVER_VHOST_USER] = net_init_vhost_user,
96003ce5744SNikolay Nikolaev #endif
961015a33bdSGonglei #ifdef CONFIG_L2TPV3
962f394b2e2SEric Blake         [NET_CLIENT_DRIVER_L2TPV3]    = net_init_l2tpv3,
9633fb69aa1SAnton Ivanov #endif
964fd9400b3SPaolo Bonzini };
965fd9400b3SPaolo Bonzini 
966fd9400b3SPaolo Bonzini 
9670e55c381SEric Blake static int net_client_init1(const void *object, bool is_netdev, Error **errp)
968fd9400b3SPaolo Bonzini {
969cebea510SKővágó, Zoltán     Netdev legacy = {0};
970cebea510SKővágó, Zoltán     const Netdev *netdev;
971fd9400b3SPaolo Bonzini     const char *name;
9724ef0defbSStefan Hajnoczi     NetClientState *peer = NULL;
973fd9400b3SPaolo Bonzini 
974fd9400b3SPaolo Bonzini     if (is_netdev) {
975cebea510SKővágó, Zoltán         netdev = object;
9761e81aba5SStefan Hajnoczi         name = netdev->id;
977fd9400b3SPaolo Bonzini 
978f394b2e2SEric Blake         if (netdev->type == NET_CLIENT_DRIVER_DUMP ||
979f394b2e2SEric Blake             netdev->type == NET_CLIENT_DRIVER_NIC ||
980f394b2e2SEric Blake             !net_client_init_fun[netdev->type]) {
981c6bd8c70SMarkus Armbruster             error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "type",
982fd9400b3SPaolo Bonzini                        "a netdev backend type");
983fd9400b3SPaolo Bonzini             return -1;
984fd9400b3SPaolo Bonzini         }
985fd9400b3SPaolo Bonzini     } else {
9861e81aba5SStefan Hajnoczi         const NetLegacy *net = object;
987f394b2e2SEric Blake         const NetLegacyOptions *opts = net->opts;
988cebea510SKővágó, Zoltán         legacy.id = net->id;
989cebea510SKővágó, Zoltán         netdev = &legacy;
9901e81aba5SStefan Hajnoczi         /* missing optional values have been initialized to "all bits zero" */
9911e81aba5SStefan Hajnoczi         name = net->has_id ? net->id : net->name;
9921e81aba5SStefan Hajnoczi 
993f394b2e2SEric Blake         /* Map the old options to the new flat type */
994f394b2e2SEric Blake         switch (opts->type) {
995f394b2e2SEric Blake         case NET_LEGACY_OPTIONS_KIND_NONE:
9961e81aba5SStefan Hajnoczi             return 0; /* nothing to do */
997f394b2e2SEric Blake         case NET_LEGACY_OPTIONS_KIND_NIC:
998f394b2e2SEric Blake             legacy.type = NET_CLIENT_DRIVER_NIC;
999f394b2e2SEric Blake             legacy.u.nic = *opts->u.nic.data;
1000f394b2e2SEric Blake             break;
1001f394b2e2SEric Blake         case NET_LEGACY_OPTIONS_KIND_USER:
1002f394b2e2SEric Blake             legacy.type = NET_CLIENT_DRIVER_USER;
1003f394b2e2SEric Blake             legacy.u.user = *opts->u.user.data;
1004f394b2e2SEric Blake             break;
1005f394b2e2SEric Blake         case NET_LEGACY_OPTIONS_KIND_TAP:
1006f394b2e2SEric Blake             legacy.type = NET_CLIENT_DRIVER_TAP;
1007f394b2e2SEric Blake             legacy.u.tap = *opts->u.tap.data;
1008f394b2e2SEric Blake             break;
1009f394b2e2SEric Blake         case NET_LEGACY_OPTIONS_KIND_L2TPV3:
1010f394b2e2SEric Blake             legacy.type = NET_CLIENT_DRIVER_L2TPV3;
1011f394b2e2SEric Blake             legacy.u.l2tpv3 = *opts->u.l2tpv3.data;
1012f394b2e2SEric Blake             break;
1013f394b2e2SEric Blake         case NET_LEGACY_OPTIONS_KIND_SOCKET:
1014f394b2e2SEric Blake             legacy.type = NET_CLIENT_DRIVER_SOCKET;
1015f394b2e2SEric Blake             legacy.u.socket = *opts->u.socket.data;
1016f394b2e2SEric Blake             break;
1017f394b2e2SEric Blake         case NET_LEGACY_OPTIONS_KIND_VDE:
1018f394b2e2SEric Blake             legacy.type = NET_CLIENT_DRIVER_VDE;
1019f394b2e2SEric Blake             legacy.u.vde = *opts->u.vde.data;
1020f394b2e2SEric Blake             break;
1021f394b2e2SEric Blake         case NET_LEGACY_OPTIONS_KIND_DUMP:
1022f394b2e2SEric Blake             legacy.type = NET_CLIENT_DRIVER_DUMP;
1023f394b2e2SEric Blake             legacy.u.dump = *opts->u.dump.data;
1024f394b2e2SEric Blake             break;
1025f394b2e2SEric Blake         case NET_LEGACY_OPTIONS_KIND_BRIDGE:
1026f394b2e2SEric Blake             legacy.type = NET_CLIENT_DRIVER_BRIDGE;
1027f394b2e2SEric Blake             legacy.u.bridge = *opts->u.bridge.data;
1028f394b2e2SEric Blake             break;
1029f394b2e2SEric Blake         case NET_LEGACY_OPTIONS_KIND_NETMAP:
1030f394b2e2SEric Blake             legacy.type = NET_CLIENT_DRIVER_NETMAP;
1031f394b2e2SEric Blake             legacy.u.netmap = *opts->u.netmap.data;
1032f394b2e2SEric Blake             break;
1033f394b2e2SEric Blake         case NET_LEGACY_OPTIONS_KIND_VHOST_USER:
1034f394b2e2SEric Blake             legacy.type = NET_CLIENT_DRIVER_VHOST_USER;
1035f394b2e2SEric Blake             legacy.u.vhost_user = *opts->u.vhost_user.data;
1036f394b2e2SEric Blake             break;
1037f394b2e2SEric Blake         default:
1038f394b2e2SEric Blake             abort();
1039ca7eb184SMarkus Armbruster         }
1040d139e9a6SStefan Hajnoczi 
1041f394b2e2SEric Blake         if (!net_client_init_fun[netdev->type]) {
1042d139e9a6SStefan Hajnoczi             error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "type",
1043d139e9a6SStefan Hajnoczi                        "a net backend type (maybe it is not compiled "
1044d139e9a6SStefan Hajnoczi                        "into this binary)");
1045d139e9a6SStefan Hajnoczi             return -1;
1046d139e9a6SStefan Hajnoczi         }
1047fd9400b3SPaolo Bonzini 
10481e81aba5SStefan Hajnoczi         /* Do not add to a vlan if it's a nic with a netdev= parameter. */
1049f394b2e2SEric Blake         if (netdev->type != NET_CLIENT_DRIVER_NIC ||
105032bafa8fSEric Blake             !opts->u.nic.data->has_netdev) {
10511e81aba5SStefan Hajnoczi             peer = net_hub_add_port(net->has_vlan ? net->vlan : 0, NULL);
10521e81aba5SStefan Hajnoczi         }
1053fd9400b3SPaolo Bonzini     }
1054fd9400b3SPaolo Bonzini 
1055f394b2e2SEric Blake     if (net_client_init_fun[netdev->type](netdev, name, peer, errp) < 0) {
1056a30ecde6SMarkus Armbruster         /* FIXME drop when all init functions store an Error */
1057a30ecde6SMarkus Armbruster         if (errp && !*errp) {
1058c6bd8c70SMarkus Armbruster             error_setg(errp, QERR_DEVICE_INIT_FAILED,
1059f394b2e2SEric Blake                        NetClientDriver_lookup[netdev->type]);
1060a30ecde6SMarkus Armbruster         }
1061fd9400b3SPaolo Bonzini         return -1;
1062fd9400b3SPaolo Bonzini     }
1063fd9400b3SPaolo Bonzini     return 0;
1064fd9400b3SPaolo Bonzini }
1065fd9400b3SPaolo Bonzini 
1066fd9400b3SPaolo Bonzini 
10670e55c381SEric Blake int net_client_init(QemuOpts *opts, bool is_netdev, Error **errp)
1068fd9400b3SPaolo Bonzini {
1069fd9400b3SPaolo Bonzini     void *object = NULL;
1070fd9400b3SPaolo Bonzini     Error *err = NULL;
1071fd9400b3SPaolo Bonzini     int ret = -1;
107209204eacSEric Blake     Visitor *v = opts_visitor_new(opts);
1073fd9400b3SPaolo Bonzini 
10747aac531eSYann Bordenave     {
10757aac531eSYann Bordenave         /* Parse convenience option format ip6-net=fec0::0[/64] */
1076891a2bb5SSamuel Thibault         const char *ip6_net = qemu_opt_get(opts, "ipv6-net");
10777aac531eSYann Bordenave 
10787aac531eSYann Bordenave         if (ip6_net) {
10797aac531eSYann Bordenave             char buf[strlen(ip6_net) + 1];
10807aac531eSYann Bordenave 
10817aac531eSYann Bordenave             if (get_str_sep(buf, sizeof(buf), &ip6_net, '/') < 0) {
10827aac531eSYann Bordenave                 /* Default 64bit prefix length.  */
1083891a2bb5SSamuel Thibault                 qemu_opt_set(opts, "ipv6-prefix", ip6_net, &error_abort);
1084891a2bb5SSamuel Thibault                 qemu_opt_set_number(opts, "ipv6-prefixlen", 64, &error_abort);
10857aac531eSYann Bordenave             } else {
10867aac531eSYann Bordenave                 /* User-specified prefix length.  */
10877aac531eSYann Bordenave                 unsigned long len;
10887aac531eSYann Bordenave                 int err;
10897aac531eSYann Bordenave 
1090891a2bb5SSamuel Thibault                 qemu_opt_set(opts, "ipv6-prefix", buf, &error_abort);
10917aac531eSYann Bordenave                 err = qemu_strtoul(ip6_net, NULL, 10, &len);
10927aac531eSYann Bordenave 
10937aac531eSYann Bordenave                 if (err) {
10947aac531eSYann Bordenave                     error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
1095891a2bb5SSamuel Thibault                               "ipv6-prefix", "a number");
10967aac531eSYann Bordenave                 } else {
1097891a2bb5SSamuel Thibault                     qemu_opt_set_number(opts, "ipv6-prefixlen", len,
10987aac531eSYann Bordenave                                         &error_abort);
10997aac531eSYann Bordenave                 }
11007aac531eSYann Bordenave             }
1101891a2bb5SSamuel Thibault             qemu_opt_unset(opts, "ipv6-net");
11027aac531eSYann Bordenave         }
11037aac531eSYann Bordenave     }
11047aac531eSYann Bordenave 
110596a1616cSEric Blake     if (is_netdev) {
110696a1616cSEric Blake         visit_type_Netdev(v, NULL, (Netdev **)&object, &err);
110796a1616cSEric Blake     } else {
110896a1616cSEric Blake         visit_type_NetLegacy(v, NULL, (NetLegacy **)&object, &err);
1109fd9400b3SPaolo Bonzini     }
1110fd9400b3SPaolo Bonzini 
1111fd9400b3SPaolo Bonzini     if (!err) {
1112fd9400b3SPaolo Bonzini         ret = net_client_init1(object, is_netdev, &err);
1113fd9400b3SPaolo Bonzini     }
1114fd9400b3SPaolo Bonzini 
111596a1616cSEric Blake     if (is_netdev) {
111696a1616cSEric Blake         qapi_free_Netdev(object);
111796a1616cSEric Blake     } else {
111896a1616cSEric Blake         qapi_free_NetLegacy(object);
1119fd9400b3SPaolo Bonzini     }
1120fd9400b3SPaolo Bonzini 
1121fd9400b3SPaolo Bonzini     error_propagate(errp, err);
112209204eacSEric Blake     visit_free(v);
1123fd9400b3SPaolo Bonzini     return ret;
1124fd9400b3SPaolo Bonzini }
1125fd9400b3SPaolo Bonzini 
1126fd9400b3SPaolo Bonzini 
1127fd9400b3SPaolo Bonzini static int net_host_check_device(const char *device)
1128fd9400b3SPaolo Bonzini {
1129fd9400b3SPaolo Bonzini     int i;
113084007e81SHani Benhabiles     for (i = 0; host_net_devices[i]; i++) {
113184007e81SHani Benhabiles         if (!strncmp(host_net_devices[i], device,
113284007e81SHani Benhabiles                      strlen(host_net_devices[i]))) {
1133fd9400b3SPaolo Bonzini             return 1;
1134fd9400b3SPaolo Bonzini         }
113584007e81SHani Benhabiles     }
1136fd9400b3SPaolo Bonzini 
1137fd9400b3SPaolo Bonzini     return 0;
1138fd9400b3SPaolo Bonzini }
1139fd9400b3SPaolo Bonzini 
11403e5a50d6SMarkus Armbruster void hmp_host_net_add(Monitor *mon, const QDict *qdict)
1141fd9400b3SPaolo Bonzini {
1142fd9400b3SPaolo Bonzini     const char *device = qdict_get_str(qdict, "device");
1143fd9400b3SPaolo Bonzini     const char *opts_str = qdict_get_try_str(qdict, "opts");
1144fd9400b3SPaolo Bonzini     Error *local_err = NULL;
1145fd9400b3SPaolo Bonzini     QemuOpts *opts;
1146fd9400b3SPaolo Bonzini 
1147fd9400b3SPaolo Bonzini     if (!net_host_check_device(device)) {
1148fd9400b3SPaolo Bonzini         monitor_printf(mon, "invalid host network device %s\n", device);
1149fd9400b3SPaolo Bonzini         return;
1150fd9400b3SPaolo Bonzini     }
1151fd9400b3SPaolo Bonzini 
115270b94331SMarkus Armbruster     opts = qemu_opts_parse_noisily(qemu_find_opts("net"),
115370b94331SMarkus Armbruster                                    opts_str ? opts_str : "", false);
1154fd9400b3SPaolo Bonzini     if (!opts) {
1155fd9400b3SPaolo Bonzini         return;
1156fd9400b3SPaolo Bonzini     }
1157fd9400b3SPaolo Bonzini 
1158f43e47dbSMarkus Armbruster     qemu_opt_set(opts, "type", device, &error_abort);
1159fd9400b3SPaolo Bonzini 
11600e55c381SEric Blake     net_client_init(opts, false, &local_err);
116184d18f06SMarkus Armbruster     if (local_err) {
116212d0cc2dSMarkus Armbruster         error_report_err(local_err);
1163fd9400b3SPaolo Bonzini         monitor_printf(mon, "adding host network device %s failed\n", device);
1164fd9400b3SPaolo Bonzini     }
1165fd9400b3SPaolo Bonzini }
1166fd9400b3SPaolo Bonzini 
11673e5a50d6SMarkus Armbruster void hmp_host_net_remove(Monitor *mon, const QDict *qdict)
1168fd9400b3SPaolo Bonzini {
1169fd9400b3SPaolo Bonzini     NetClientState *nc;
1170fd9400b3SPaolo Bonzini     int vlan_id = qdict_get_int(qdict, "vlan_id");
1171fd9400b3SPaolo Bonzini     const char *device = qdict_get_str(qdict, "device");
1172fd9400b3SPaolo Bonzini 
1173fd9400b3SPaolo Bonzini     nc = net_hub_find_client_by_name(vlan_id, device);
1174fd9400b3SPaolo Bonzini     if (!nc) {
117586e11772SHani Benhabiles         error_report("Host network device '%s' on hub '%d' not found",
117686e11772SHani Benhabiles                      device, vlan_id);
1177fd9400b3SPaolo Bonzini         return;
1178fd9400b3SPaolo Bonzini     }
1179f394b2e2SEric Blake     if (nc->info->type == NET_CLIENT_DRIVER_NIC) {
118086e11772SHani Benhabiles         error_report("invalid host network device '%s'", device);
1181fd9400b3SPaolo Bonzini         return;
1182fd9400b3SPaolo Bonzini     }
118364a55d60SJason Wang 
118464a55d60SJason Wang     qemu_del_net_client(nc->peer);
1185fd9400b3SPaolo Bonzini     qemu_del_net_client(nc);
1186a4543b1bSShmulik Ladkani     qemu_opts_del(qemu_opts_find(qemu_find_opts("net"), device));
1187fd9400b3SPaolo Bonzini }
1188fd9400b3SPaolo Bonzini 
1189fd9400b3SPaolo Bonzini void netdev_add(QemuOpts *opts, Error **errp)
1190fd9400b3SPaolo Bonzini {
11910e55c381SEric Blake     net_client_init(opts, true, errp);
1192fd9400b3SPaolo Bonzini }
1193fd9400b3SPaolo Bonzini 
1194485febc6SMarkus Armbruster void qmp_netdev_add(QDict *qdict, QObject **ret, Error **errp)
1195fd9400b3SPaolo Bonzini {
1196fd9400b3SPaolo Bonzini     Error *local_err = NULL;
1197fd9400b3SPaolo Bonzini     QemuOptsList *opts_list;
1198fd9400b3SPaolo Bonzini     QemuOpts *opts;
1199fd9400b3SPaolo Bonzini 
1200fd9400b3SPaolo Bonzini     opts_list = qemu_find_opts_err("netdev", &local_err);
120184d18f06SMarkus Armbruster     if (local_err) {
1202485febc6SMarkus Armbruster         goto out;
1203fd9400b3SPaolo Bonzini     }
1204fd9400b3SPaolo Bonzini 
1205fd9400b3SPaolo Bonzini     opts = qemu_opts_from_qdict(opts_list, qdict, &local_err);
120684d18f06SMarkus Armbruster     if (local_err) {
1207485febc6SMarkus Armbruster         goto out;
1208fd9400b3SPaolo Bonzini     }
1209fd9400b3SPaolo Bonzini 
1210fd9400b3SPaolo Bonzini     netdev_add(opts, &local_err);
121184d18f06SMarkus Armbruster     if (local_err) {
1212fd9400b3SPaolo Bonzini         qemu_opts_del(opts);
1213485febc6SMarkus Armbruster         goto out;
1214fd9400b3SPaolo Bonzini     }
1215fd9400b3SPaolo Bonzini 
1216485febc6SMarkus Armbruster out:
1217485febc6SMarkus Armbruster     error_propagate(errp, local_err);
1218fd9400b3SPaolo Bonzini }
1219fd9400b3SPaolo Bonzini 
1220fd9400b3SPaolo Bonzini void qmp_netdev_del(const char *id, Error **errp)
1221fd9400b3SPaolo Bonzini {
1222fd9400b3SPaolo Bonzini     NetClientState *nc;
1223fd9400b3SPaolo Bonzini     QemuOpts *opts;
1224fd9400b3SPaolo Bonzini 
1225fd9400b3SPaolo Bonzini     nc = qemu_find_netdev(id);
1226fd9400b3SPaolo Bonzini     if (!nc) {
122775158ebbSMarkus Armbruster         error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
122875158ebbSMarkus Armbruster                   "Device '%s' not found", id);
1229fd9400b3SPaolo Bonzini         return;
1230fd9400b3SPaolo Bonzini     }
1231fd9400b3SPaolo Bonzini 
1232fd9400b3SPaolo Bonzini     opts = qemu_opts_find(qemu_find_opts_err("netdev", NULL), id);
1233fd9400b3SPaolo Bonzini     if (!opts) {
1234fd9400b3SPaolo Bonzini         error_setg(errp, "Device '%s' is not a netdev", id);
1235fd9400b3SPaolo Bonzini         return;
1236fd9400b3SPaolo Bonzini     }
1237fd9400b3SPaolo Bonzini 
1238fd9400b3SPaolo Bonzini     qemu_del_net_client(nc);
1239fd9400b3SPaolo Bonzini     qemu_opts_del(opts);
1240fd9400b3SPaolo Bonzini }
1241fd9400b3SPaolo Bonzini 
1242aa9156f4Szhanghailiang static void netfilter_print_info(Monitor *mon, NetFilterState *nf)
1243aa9156f4Szhanghailiang {
1244aa9156f4Szhanghailiang     char *str;
1245aa9156f4Szhanghailiang     ObjectProperty *prop;
1246aa9156f4Szhanghailiang     ObjectPropertyIterator iter;
12473b098d56SEric Blake     Visitor *v;
1248aa9156f4Szhanghailiang 
1249aa9156f4Szhanghailiang     /* generate info str */
1250aa9156f4Szhanghailiang     object_property_iter_init(&iter, OBJECT(nf));
1251aa9156f4Szhanghailiang     while ((prop = object_property_iter_next(&iter))) {
1252aa9156f4Szhanghailiang         if (!strcmp(prop->name, "type")) {
1253aa9156f4Szhanghailiang             continue;
1254aa9156f4Szhanghailiang         }
12553b098d56SEric Blake         v = string_output_visitor_new(false, &str);
12563b098d56SEric Blake         object_property_get(OBJECT(nf), v, prop->name, NULL);
12573b098d56SEric Blake         visit_complete(v, &str);
12583b098d56SEric Blake         visit_free(v);
1259aa9156f4Szhanghailiang         monitor_printf(mon, ",%s=%s", prop->name, str);
1260aa9156f4Szhanghailiang         g_free(str);
1261aa9156f4Szhanghailiang     }
1262aa9156f4Szhanghailiang     monitor_printf(mon, "\n");
1263aa9156f4Szhanghailiang }
1264aa9156f4Szhanghailiang 
1265fd9400b3SPaolo Bonzini void print_net_client(Monitor *mon, NetClientState *nc)
1266fd9400b3SPaolo Bonzini {
1267a4960f52SYang Hongyang     NetFilterState *nf;
1268a4960f52SYang Hongyang 
12691ceef9f2SJason Wang     monitor_printf(mon, "%s: index=%d,type=%s,%s\n", nc->name,
12701ceef9f2SJason Wang                    nc->queue_index,
1271f394b2e2SEric Blake                    NetClientDriver_lookup[nc->info->type],
12721ceef9f2SJason Wang                    nc->info_str);
1273a4960f52SYang Hongyang     if (!QTAILQ_EMPTY(&nc->filters)) {
1274a4960f52SYang Hongyang         monitor_printf(mon, "filters:\n");
1275a4960f52SYang Hongyang     }
1276a4960f52SYang Hongyang     QTAILQ_FOREACH(nf, &nc->filters, next) {
1277a3e8a3f3SYang Hongyang         char *path = object_get_canonical_path_component(OBJECT(nf));
1278aa9156f4Szhanghailiang 
1279aa9156f4Szhanghailiang         monitor_printf(mon, "  - %s: type=%s", path,
1280aa9156f4Szhanghailiang                        object_get_typename(OBJECT(nf)));
1281aa9156f4Szhanghailiang         netfilter_print_info(mon, nf);
1282a3e8a3f3SYang Hongyang         g_free(path);
1283a4960f52SYang Hongyang     }
1284fd9400b3SPaolo Bonzini }
1285fd9400b3SPaolo Bonzini 
1286b1be4280SAmos Kong RxFilterInfoList *qmp_query_rx_filter(bool has_name, const char *name,
1287b1be4280SAmos Kong                                       Error **errp)
1288b1be4280SAmos Kong {
1289b1be4280SAmos Kong     NetClientState *nc;
1290b1be4280SAmos Kong     RxFilterInfoList *filter_list = NULL, *last_entry = NULL;
1291b1be4280SAmos Kong 
1292b1be4280SAmos Kong     QTAILQ_FOREACH(nc, &net_clients, next) {
1293b1be4280SAmos Kong         RxFilterInfoList *entry;
1294b1be4280SAmos Kong         RxFilterInfo *info;
1295b1be4280SAmos Kong 
1296b1be4280SAmos Kong         if (has_name && strcmp(nc->name, name) != 0) {
1297b1be4280SAmos Kong             continue;
1298b1be4280SAmos Kong         }
1299b1be4280SAmos Kong 
1300b1be4280SAmos Kong         /* only query rx-filter information of NIC */
1301f394b2e2SEric Blake         if (nc->info->type != NET_CLIENT_DRIVER_NIC) {
1302b1be4280SAmos Kong             if (has_name) {
1303b1be4280SAmos Kong                 error_setg(errp, "net client(%s) isn't a NIC", name);
13049083da1dSMarkus Armbruster                 return NULL;
1305b1be4280SAmos Kong             }
1306b1be4280SAmos Kong             continue;
1307b1be4280SAmos Kong         }
1308b1be4280SAmos Kong 
13095320c2caSVladislav Yasevich         /* only query information on queue 0 since the info is per nic,
13105320c2caSVladislav Yasevich          * not per queue
13115320c2caSVladislav Yasevich          */
13125320c2caSVladislav Yasevich         if (nc->queue_index != 0)
13135320c2caSVladislav Yasevich             continue;
13145320c2caSVladislav Yasevich 
1315b1be4280SAmos Kong         if (nc->info->query_rx_filter) {
1316b1be4280SAmos Kong             info = nc->info->query_rx_filter(nc);
1317b1be4280SAmos Kong             entry = g_malloc0(sizeof(*entry));
1318b1be4280SAmos Kong             entry->value = info;
1319b1be4280SAmos Kong 
1320b1be4280SAmos Kong             if (!filter_list) {
1321b1be4280SAmos Kong                 filter_list = entry;
1322b1be4280SAmos Kong             } else {
1323b1be4280SAmos Kong                 last_entry->next = entry;
1324b1be4280SAmos Kong             }
1325b1be4280SAmos Kong             last_entry = entry;
1326b1be4280SAmos Kong         } else if (has_name) {
1327b1be4280SAmos Kong             error_setg(errp, "net client(%s) doesn't support"
1328b1be4280SAmos Kong                        " rx-filter querying", name);
13299083da1dSMarkus Armbruster             return NULL;
1330b1be4280SAmos Kong         }
1331638fb141SMarkus Armbruster 
1332638fb141SMarkus Armbruster         if (has_name) {
1333638fb141SMarkus Armbruster             break;
1334638fb141SMarkus Armbruster         }
1335b1be4280SAmos Kong     }
1336b1be4280SAmos Kong 
13379083da1dSMarkus Armbruster     if (filter_list == NULL && has_name) {
1338b1be4280SAmos Kong         error_setg(errp, "invalid net client name: %s", name);
1339b1be4280SAmos Kong     }
1340b1be4280SAmos Kong 
1341b1be4280SAmos Kong     return filter_list;
1342b1be4280SAmos Kong }
1343b1be4280SAmos Kong 
13441ce6be24SMarkus Armbruster void hmp_info_network(Monitor *mon, const QDict *qdict)
1345fd9400b3SPaolo Bonzini {
1346fd9400b3SPaolo Bonzini     NetClientState *nc, *peer;
1347f394b2e2SEric Blake     NetClientDriver type;
1348fd9400b3SPaolo Bonzini 
1349fd9400b3SPaolo Bonzini     net_hub_info(mon);
1350fd9400b3SPaolo Bonzini 
1351fd9400b3SPaolo Bonzini     QTAILQ_FOREACH(nc, &net_clients, next) {
1352fd9400b3SPaolo Bonzini         peer = nc->peer;
1353fd9400b3SPaolo Bonzini         type = nc->info->type;
1354fd9400b3SPaolo Bonzini 
1355fd9400b3SPaolo Bonzini         /* Skip if already printed in hub info */
1356fd9400b3SPaolo Bonzini         if (net_hub_id_for_client(nc, NULL) == 0) {
1357fd9400b3SPaolo Bonzini             continue;
1358fd9400b3SPaolo Bonzini         }
1359fd9400b3SPaolo Bonzini 
1360f394b2e2SEric Blake         if (!peer || type == NET_CLIENT_DRIVER_NIC) {
1361fd9400b3SPaolo Bonzini             print_net_client(mon, nc);
1362fd9400b3SPaolo Bonzini         } /* else it's a netdev connected to a NIC, printed with the NIC */
1363f394b2e2SEric Blake         if (peer && type == NET_CLIENT_DRIVER_NIC) {
1364fd9400b3SPaolo Bonzini             monitor_printf(mon, " \\ ");
1365fd9400b3SPaolo Bonzini             print_net_client(mon, peer);
1366fd9400b3SPaolo Bonzini         }
1367fd9400b3SPaolo Bonzini     }
1368fd9400b3SPaolo Bonzini }
1369fd9400b3SPaolo Bonzini 
1370fd9400b3SPaolo Bonzini void qmp_set_link(const char *name, bool up, Error **errp)
1371fd9400b3SPaolo Bonzini {
13721ceef9f2SJason Wang     NetClientState *ncs[MAX_QUEUE_NUM];
13731ceef9f2SJason Wang     NetClientState *nc;
13741ceef9f2SJason Wang     int queues, i;
1375fd9400b3SPaolo Bonzini 
13761ceef9f2SJason Wang     queues = qemu_find_net_clients_except(name, ncs,
1377f394b2e2SEric Blake                                           NET_CLIENT_DRIVER__MAX,
13781ceef9f2SJason Wang                                           MAX_QUEUE_NUM);
13791ceef9f2SJason Wang 
13801ceef9f2SJason Wang     if (queues == 0) {
138175158ebbSMarkus Armbruster         error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
138275158ebbSMarkus Armbruster                   "Device '%s' not found", name);
1383fd9400b3SPaolo Bonzini         return;
1384fd9400b3SPaolo Bonzini     }
13851ceef9f2SJason Wang     nc = ncs[0];
1386fd9400b3SPaolo Bonzini 
13871ceef9f2SJason Wang     for (i = 0; i < queues; i++) {
13881ceef9f2SJason Wang         ncs[i]->link_down = !up;
13891ceef9f2SJason Wang     }
1390fd9400b3SPaolo Bonzini 
1391fd9400b3SPaolo Bonzini     if (nc->info->link_status_changed) {
1392fd9400b3SPaolo Bonzini         nc->info->link_status_changed(nc);
1393fd9400b3SPaolo Bonzini     }
1394fd9400b3SPaolo Bonzini 
139502d38fcbSVlad Yasevich     if (nc->peer) {
139602d38fcbSVlad Yasevich         /* Change peer link only if the peer is NIC and then notify peer.
139702d38fcbSVlad Yasevich          * If the peer is a HUBPORT or a backend, we do not change the
139802d38fcbSVlad Yasevich          * link status.
1399fd9400b3SPaolo Bonzini          *
140002d38fcbSVlad Yasevich          * This behavior is compatible with qemu vlans where there could be
1401fd9400b3SPaolo Bonzini          * multiple clients that can still communicate with each other in
140202d38fcbSVlad Yasevich          * disconnected mode. For now maintain this compatibility.
140302d38fcbSVlad Yasevich          */
1404f394b2e2SEric Blake         if (nc->peer->info->type == NET_CLIENT_DRIVER_NIC) {
140502d38fcbSVlad Yasevich             for (i = 0; i < queues; i++) {
140602d38fcbSVlad Yasevich                 ncs[i]->peer->link_down = !up;
140702d38fcbSVlad Yasevich             }
140802d38fcbSVlad Yasevich         }
140902d38fcbSVlad Yasevich         if (nc->peer->info->link_status_changed) {
1410fd9400b3SPaolo Bonzini             nc->peer->info->link_status_changed(nc->peer);
1411fd9400b3SPaolo Bonzini         }
1412fd9400b3SPaolo Bonzini     }
141302d38fcbSVlad Yasevich }
1414fd9400b3SPaolo Bonzini 
1415ca77d85eSMichael S. Tsirkin static void net_vm_change_state_handler(void *opaque, int running,
1416ca77d85eSMichael S. Tsirkin                                         RunState state)
1417ca77d85eSMichael S. Tsirkin {
1418ca77d85eSMichael S. Tsirkin     NetClientState *nc;
1419ca77d85eSMichael S. Tsirkin     NetClientState *tmp;
1420ca77d85eSMichael S. Tsirkin 
1421ca77d85eSMichael S. Tsirkin     QTAILQ_FOREACH_SAFE(nc, &net_clients, next, tmp) {
1422625de449SFam Zheng         if (running) {
1423625de449SFam Zheng             /* Flush queued packets and wake up backends. */
1424625de449SFam Zheng             if (nc->peer && qemu_can_send_packet(nc)) {
1425625de449SFam Zheng                 qemu_flush_queued_packets(nc->peer);
1426625de449SFam Zheng             }
1427625de449SFam Zheng         } else {
1428625de449SFam Zheng             /* Complete all queued packets, to guarantee we don't modify
1429625de449SFam Zheng              * state later when VM is not running.
1430625de449SFam Zheng              */
1431ca77d85eSMichael S. Tsirkin             qemu_flush_or_purge_queued_packets(nc, true);
1432ca77d85eSMichael S. Tsirkin         }
1433ca77d85eSMichael S. Tsirkin     }
1434ca77d85eSMichael S. Tsirkin }
1435ca77d85eSMichael S. Tsirkin 
1436fd9400b3SPaolo Bonzini void net_cleanup(void)
1437fd9400b3SPaolo Bonzini {
14381ceef9f2SJason Wang     NetClientState *nc;
1439fd9400b3SPaolo Bonzini 
14401ceef9f2SJason Wang     /* We may del multiple entries during qemu_del_net_client(),
14411ceef9f2SJason Wang      * so QTAILQ_FOREACH_SAFE() is also not safe here.
14421ceef9f2SJason Wang      */
14431ceef9f2SJason Wang     while (!QTAILQ_EMPTY(&net_clients)) {
14441ceef9f2SJason Wang         nc = QTAILQ_FIRST(&net_clients);
1445f394b2e2SEric Blake         if (nc->info->type == NET_CLIENT_DRIVER_NIC) {
1446948ecf21SJason Wang             qemu_del_nic(qemu_get_nic(nc));
1447948ecf21SJason Wang         } else {
1448fd9400b3SPaolo Bonzini             qemu_del_net_client(nc);
1449fd9400b3SPaolo Bonzini         }
1450fd9400b3SPaolo Bonzini     }
1451ca77d85eSMichael S. Tsirkin 
1452ca77d85eSMichael S. Tsirkin     qemu_del_vm_change_state_handler(net_change_state_entry);
1453948ecf21SJason Wang }
1454fd9400b3SPaolo Bonzini 
1455fd9400b3SPaolo Bonzini void net_check_clients(void)
1456fd9400b3SPaolo Bonzini {
1457fd9400b3SPaolo Bonzini     NetClientState *nc;
1458fd9400b3SPaolo Bonzini     int i;
1459fd9400b3SPaolo Bonzini 
1460fd9400b3SPaolo Bonzini     net_hub_check_clients();
1461fd9400b3SPaolo Bonzini 
1462fd9400b3SPaolo Bonzini     QTAILQ_FOREACH(nc, &net_clients, next) {
1463fd9400b3SPaolo Bonzini         if (!nc->peer) {
1464fd9400b3SPaolo Bonzini             fprintf(stderr, "Warning: %s %s has no peer\n",
1465f394b2e2SEric Blake                     nc->info->type == NET_CLIENT_DRIVER_NIC ?
1466fd9400b3SPaolo Bonzini                     "nic" : "netdev", nc->name);
1467fd9400b3SPaolo Bonzini         }
1468fd9400b3SPaolo Bonzini     }
1469fd9400b3SPaolo Bonzini 
1470fd9400b3SPaolo Bonzini     /* Check that all NICs requested via -net nic actually got created.
1471fd9400b3SPaolo Bonzini      * NICs created via -device don't need to be checked here because
1472fd9400b3SPaolo Bonzini      * they are always instantiated.
1473fd9400b3SPaolo Bonzini      */
1474fd9400b3SPaolo Bonzini     for (i = 0; i < MAX_NICS; i++) {
1475fd9400b3SPaolo Bonzini         NICInfo *nd = &nd_table[i];
1476fd9400b3SPaolo Bonzini         if (nd->used && !nd->instantiated) {
1477fd9400b3SPaolo Bonzini             fprintf(stderr, "Warning: requested NIC (%s, model %s) "
1478fd9400b3SPaolo Bonzini                     "was not created (not supported by this machine?)\n",
1479fd9400b3SPaolo Bonzini                     nd->name ? nd->name : "anonymous",
1480fd9400b3SPaolo Bonzini                     nd->model ? nd->model : "unspecified");
1481fd9400b3SPaolo Bonzini         }
1482fd9400b3SPaolo Bonzini     }
1483fd9400b3SPaolo Bonzini }
1484fd9400b3SPaolo Bonzini 
148528d0de7aSMarkus Armbruster static int net_init_client(void *dummy, QemuOpts *opts, Error **errp)
1486fd9400b3SPaolo Bonzini {
1487fd9400b3SPaolo Bonzini     Error *local_err = NULL;
1488fd9400b3SPaolo Bonzini 
14890e55c381SEric Blake     net_client_init(opts, false, &local_err);
149084d18f06SMarkus Armbruster     if (local_err) {
149112d0cc2dSMarkus Armbruster         error_report_err(local_err);
1492fd9400b3SPaolo Bonzini         return -1;
1493fd9400b3SPaolo Bonzini     }
1494fd9400b3SPaolo Bonzini 
1495fd9400b3SPaolo Bonzini     return 0;
1496fd9400b3SPaolo Bonzini }
1497fd9400b3SPaolo Bonzini 
149828d0de7aSMarkus Armbruster static int net_init_netdev(void *dummy, QemuOpts *opts, Error **errp)
1499fd9400b3SPaolo Bonzini {
1500fd9400b3SPaolo Bonzini     Error *local_err = NULL;
1501fd9400b3SPaolo Bonzini     int ret;
1502fd9400b3SPaolo Bonzini 
15030e55c381SEric Blake     ret = net_client_init(opts, true, &local_err);
150484d18f06SMarkus Armbruster     if (local_err) {
150512d0cc2dSMarkus Armbruster         error_report_err(local_err);
1506fd9400b3SPaolo Bonzini         return -1;
1507fd9400b3SPaolo Bonzini     }
1508fd9400b3SPaolo Bonzini 
1509fd9400b3SPaolo Bonzini     return ret;
1510fd9400b3SPaolo Bonzini }
1511fd9400b3SPaolo Bonzini 
1512fd9400b3SPaolo Bonzini int net_init_clients(void)
1513fd9400b3SPaolo Bonzini {
1514fd9400b3SPaolo Bonzini     QemuOptsList *net = qemu_find_opts("net");
1515fd9400b3SPaolo Bonzini 
1516ca77d85eSMichael S. Tsirkin     net_change_state_entry =
1517ca77d85eSMichael S. Tsirkin         qemu_add_vm_change_state_handler(net_vm_change_state_handler, NULL);
1518ca77d85eSMichael S. Tsirkin 
1519fd9400b3SPaolo Bonzini     QTAILQ_INIT(&net_clients);
1520fd9400b3SPaolo Bonzini 
152128d0de7aSMarkus Armbruster     if (qemu_opts_foreach(qemu_find_opts("netdev"),
152228d0de7aSMarkus Armbruster                           net_init_netdev, NULL, NULL)) {
1523fd9400b3SPaolo Bonzini         return -1;
1524a4c7367fSMarkus Armbruster     }
1525fd9400b3SPaolo Bonzini 
152628d0de7aSMarkus Armbruster     if (qemu_opts_foreach(net, net_init_client, NULL, NULL)) {
1527fd9400b3SPaolo Bonzini         return -1;
1528fd9400b3SPaolo Bonzini     }
1529fd9400b3SPaolo Bonzini 
1530fd9400b3SPaolo Bonzini     return 0;
1531fd9400b3SPaolo Bonzini }
1532fd9400b3SPaolo Bonzini 
1533fd9400b3SPaolo Bonzini int net_client_parse(QemuOptsList *opts_list, const char *optarg)
1534fd9400b3SPaolo Bonzini {
1535fd9400b3SPaolo Bonzini #if defined(CONFIG_SLIRP)
1536fd9400b3SPaolo Bonzini     int ret;
1537fd9400b3SPaolo Bonzini     if (net_slirp_parse_legacy(opts_list, optarg, &ret)) {
1538fd9400b3SPaolo Bonzini         return ret;
1539fd9400b3SPaolo Bonzini     }
1540fd9400b3SPaolo Bonzini #endif
1541fd9400b3SPaolo Bonzini 
154270b94331SMarkus Armbruster     if (!qemu_opts_parse_noisily(opts_list, optarg, true)) {
1543fd9400b3SPaolo Bonzini         return -1;
1544fd9400b3SPaolo Bonzini     }
1545fd9400b3SPaolo Bonzini 
1546fd9400b3SPaolo Bonzini     return 0;
1547fd9400b3SPaolo Bonzini }
1548fd9400b3SPaolo Bonzini 
1549fd9400b3SPaolo Bonzini /* From FreeBSD */
1550fd9400b3SPaolo Bonzini /* XXX: optimize */
1551fd9400b3SPaolo Bonzini unsigned compute_mcast_idx(const uint8_t *ep)
1552fd9400b3SPaolo Bonzini {
1553fd9400b3SPaolo Bonzini     uint32_t crc;
1554fd9400b3SPaolo Bonzini     int carry, i, j;
1555fd9400b3SPaolo Bonzini     uint8_t b;
1556fd9400b3SPaolo Bonzini 
1557fd9400b3SPaolo Bonzini     crc = 0xffffffff;
1558fd9400b3SPaolo Bonzini     for (i = 0; i < 6; i++) {
1559fd9400b3SPaolo Bonzini         b = *ep++;
1560fd9400b3SPaolo Bonzini         for (j = 0; j < 8; j++) {
1561fd9400b3SPaolo Bonzini             carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01);
1562fd9400b3SPaolo Bonzini             crc <<= 1;
1563fd9400b3SPaolo Bonzini             b >>= 1;
1564fd9400b3SPaolo Bonzini             if (carry) {
1565fd9400b3SPaolo Bonzini                 crc = ((crc ^ POLYNOMIAL) | carry);
1566fd9400b3SPaolo Bonzini             }
1567fd9400b3SPaolo Bonzini         }
1568fd9400b3SPaolo Bonzini     }
1569fd9400b3SPaolo Bonzini     return crc >> 26;
1570fd9400b3SPaolo Bonzini }
15714d454574SPaolo Bonzini 
15724d454574SPaolo Bonzini QemuOptsList qemu_netdev_opts = {
15734d454574SPaolo Bonzini     .name = "netdev",
15744d454574SPaolo Bonzini     .implied_opt_name = "type",
15754d454574SPaolo Bonzini     .head = QTAILQ_HEAD_INITIALIZER(qemu_netdev_opts.head),
15764d454574SPaolo Bonzini     .desc = {
15774d454574SPaolo Bonzini         /*
15784d454574SPaolo Bonzini          * no elements => accept any params
15794d454574SPaolo Bonzini          * validation will happen later
15804d454574SPaolo Bonzini          */
15814d454574SPaolo Bonzini         { /* end of list */ }
15824d454574SPaolo Bonzini     },
15834d454574SPaolo Bonzini };
15844d454574SPaolo Bonzini 
15854d454574SPaolo Bonzini QemuOptsList qemu_net_opts = {
15864d454574SPaolo Bonzini     .name = "net",
15874d454574SPaolo Bonzini     .implied_opt_name = "type",
15884d454574SPaolo Bonzini     .head = QTAILQ_HEAD_INITIALIZER(qemu_net_opts.head),
15894d454574SPaolo Bonzini     .desc = {
15904d454574SPaolo Bonzini         /*
15914d454574SPaolo Bonzini          * no elements => accept any params
15924d454574SPaolo Bonzini          * validation will happen later
15934d454574SPaolo Bonzini          */
15944d454574SPaolo Bonzini         { /* end of list */ }
15954d454574SPaolo Bonzini     },
15964d454574SPaolo Bonzini };
159716a3df40SZhang Chen 
159816a3df40SZhang Chen void net_socket_rs_init(SocketReadState *rs,
159916a3df40SZhang Chen                         SocketReadStateFinalize *finalize)
160016a3df40SZhang Chen {
160116a3df40SZhang Chen     rs->state = 0;
160216a3df40SZhang Chen     rs->index = 0;
160316a3df40SZhang Chen     rs->packet_len = 0;
160416a3df40SZhang Chen     memset(rs->buf, 0, sizeof(rs->buf));
160516a3df40SZhang Chen     rs->finalize = finalize;
160616a3df40SZhang Chen }
160716a3df40SZhang Chen 
160816a3df40SZhang Chen /*
160916a3df40SZhang Chen  * Returns
1610e9e0a585SZhang Chen  * 0: success
1611e9e0a585SZhang Chen  * -1: error occurs
161216a3df40SZhang Chen  */
161316a3df40SZhang Chen int net_fill_rstate(SocketReadState *rs, const uint8_t *buf, int size)
161416a3df40SZhang Chen {
161516a3df40SZhang Chen     unsigned int l;
161616a3df40SZhang Chen 
161716a3df40SZhang Chen     while (size > 0) {
161816a3df40SZhang Chen         /* reassemble a packet from the network */
161916a3df40SZhang Chen         switch (rs->state) { /* 0 = getting length, 1 = getting data */
162016a3df40SZhang Chen         case 0:
162116a3df40SZhang Chen             l = 4 - rs->index;
162216a3df40SZhang Chen             if (l > size) {
162316a3df40SZhang Chen                 l = size;
162416a3df40SZhang Chen             }
162516a3df40SZhang Chen             memcpy(rs->buf + rs->index, buf, l);
162616a3df40SZhang Chen             buf += l;
162716a3df40SZhang Chen             size -= l;
162816a3df40SZhang Chen             rs->index += l;
162916a3df40SZhang Chen             if (rs->index == 4) {
163016a3df40SZhang Chen                 /* got length */
163116a3df40SZhang Chen                 rs->packet_len = ntohl(*(uint32_t *)rs->buf);
163216a3df40SZhang Chen                 rs->index = 0;
163316a3df40SZhang Chen                 rs->state = 1;
163416a3df40SZhang Chen             }
163516a3df40SZhang Chen             break;
163616a3df40SZhang Chen         case 1:
163716a3df40SZhang Chen             l = rs->packet_len - rs->index;
163816a3df40SZhang Chen             if (l > size) {
163916a3df40SZhang Chen                 l = size;
164016a3df40SZhang Chen             }
164116a3df40SZhang Chen             if (rs->index + l <= sizeof(rs->buf)) {
164216a3df40SZhang Chen                 memcpy(rs->buf + rs->index, buf, l);
164316a3df40SZhang Chen             } else {
164416a3df40SZhang Chen                 fprintf(stderr, "serious error: oversized packet received,"
164516a3df40SZhang Chen                     "connection terminated.\n");
164616a3df40SZhang Chen                 rs->index = rs->state = 0;
164716a3df40SZhang Chen                 return -1;
164816a3df40SZhang Chen             }
164916a3df40SZhang Chen 
165016a3df40SZhang Chen             rs->index += l;
165116a3df40SZhang Chen             buf += l;
165216a3df40SZhang Chen             size -= l;
165316a3df40SZhang Chen             if (rs->index >= rs->packet_len) {
165416a3df40SZhang Chen                 rs->index = 0;
165516a3df40SZhang Chen                 rs->state = 0;
165616a3df40SZhang Chen                 if (rs->finalize) {
165716a3df40SZhang Chen                     rs->finalize(rs);
165816a3df40SZhang Chen                 }
165916a3df40SZhang Chen             }
166016a3df40SZhang Chen             break;
166116a3df40SZhang Chen         }
166216a3df40SZhang Chen     }
1663e9e0a585SZhang Chen 
1664e9e0a585SZhang Chen     assert(size == 0);
166516a3df40SZhang Chen     return 0;
166616a3df40SZhang Chen }
1667