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