From 8cabd8778c378802adee7d0c3be4e5b5b5be4bee Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Fri, 1 Mar 2019 10:39:18 +0100 Subject: [PATCH 01/12] slirp: Fix build with gcc 9 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Build fails with gcc 9: CC slirp/ndp_table.o slirp/ndp_table.c: In function ‘ndp_table_add’: slirp/ndp_table.c:31:23: error: taking address of packed member of ‘struct ndpentry’ may result in an unaligned pointer value [-Werror=address-of-packed-member] 31 | if (in6_equal(&ndp_table->table[i].ip_addr, &ip_addr)) { | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ slirp/ndp_table.c: In function ‘ndp_table_search’: slirp/ndp_table.c:75:23: error: taking address of packed member of ‘struct ndpentry’ may result in an unaligned pointer value [-Werror=address-of-packed-member] 75 | if (in6_equal(&ndp_table->table[i].ip_addr, &ip_addr)) { | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ cc1: all warnings being treated as errors The ndpentry structure isn't used to model on-the-wire data or anything else that would care for the struct layout. It doesn't need to be packed actually. Just drop SLIRP_PACKED. Signed-off-by: Greg Kurz Message-Id: <155143315831.102868.17515265400523392682.stgit@bahia.lan> Reviewed-by: Peter Maydell Signed-off-by: Samuel Thibault --- slirp/slirp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slirp/slirp.h b/slirp/slirp.h index 752a4cd8c8..8068ba1d1e 100644 --- a/slirp/slirp.h +++ b/slirp/slirp.h @@ -106,7 +106,7 @@ bool arp_table_search(Slirp *slirp, uint32_t ip_addr, struct ndpentry { unsigned char eth_addr[ETH_ALEN]; /* sender hardware address */ struct in6_addr ip_addr; /* sender IP address */ -} SLIRP_PACKED; +}; #define NDP_TABLE_SIZE 16 From 6c419a1e06c21c4568d5a12a9c5cafcdb00f6aa8 Mon Sep 17 00:00:00 2001 From: Vic Lee Date: Fri, 1 Mar 2019 14:48:09 +0800 Subject: [PATCH 02/12] slirp: check for ioctlsocket error and 0-length udp payload. Sometimes sorecvfrom() is called from slirp.c because revents == G_IO_IN, but there is 0 bytes available and recvfrom could be blocking indefinitely. This is likely due to 0-length udp payload. This also adds an error checking for ioctlsocket. Signed-off-by: Vic Lee Message-Id: <20190301064809.3074-1-llyzs.vic@gmail.com> Signed-off-by: Samuel Thibault --- slirp/socket.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/slirp/socket.c b/slirp/socket.c index 4876ea3f31..4dc5e2907d 100644 --- a/slirp/socket.c +++ b/slirp/socket.c @@ -529,6 +529,15 @@ sorecvfrom(struct socket *so) int n; #endif + if (ioctlsocket(so->s, FIONREAD, &n) != 0) { + DEBUG_MISC(" ioctlsocket errno = %d-%s\n", + errno,strerror(errno)); + return; + } + if (n == 0) { + return; + } + m = m_get(so->slirp); if (!m) { return; @@ -552,7 +561,6 @@ sorecvfrom(struct socket *so) */ len = M_FREEROOM(m); /* if (so->so_fport != htons(53)) { */ - ioctlsocket(so->s, FIONREAD, &n); if (n > len) { n = (m->m_data - m->m_dat) + m->m_len + n + 1; From d3222975c7d6cda9e25809dea05241188457b113 Mon Sep 17 00:00:00 2001 From: William Bowling Date: Fri, 1 Mar 2019 21:45:56 +0000 Subject: [PATCH 03/12] slirp: check sscanf result when emulating ident MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When emulating ident in tcp_emu, if the strchr checks passed but the sscanf check failed, two uninitialized variables would be copied and sent in the reply, so move this code inside the if(sscanf()) clause. Signed-off-by: William Bowling Cc: qemu-stable@nongnu.org Cc: secalert@redhat.com Message-Id: <1551476756-25749-1-git-send-email-will@wbowling.info> Signed-off-by: Samuel Thibault Reviewed-by: Philippe Mathieu-Daudé --- slirp/tcp_subr.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c index 262a42d6c8..ef9d99c154 100644 --- a/slirp/tcp_subr.c +++ b/slirp/tcp_subr.c @@ -664,12 +664,12 @@ tcp_emu(struct socket *so, struct mbuf *m) break; } } + so_rcv->sb_cc = snprintf(so_rcv->sb_data, + so_rcv->sb_datalen, + "%d,%d\r\n", n1, n2); + so_rcv->sb_rptr = so_rcv->sb_data; + so_rcv->sb_wptr = so_rcv->sb_data + so_rcv->sb_cc; } - so_rcv->sb_cc = snprintf(so_rcv->sb_data, - so_rcv->sb_datalen, - "%d,%d\r\n", n1, n2); - so_rcv->sb_rptr = so_rcv->sb_data; - so_rcv->sb_wptr = so_rcv->sb_data + so_rcv->sb_cc; } m_free(m); return 0; From 1fd71067dae501f1c78618e9583c6cc72db0cfa6 Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Fri, 1 Mar 2019 18:23:41 -0800 Subject: [PATCH 04/12] slirp: fix big/little endian conversion in ident protocol MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Samuel Thibault Reviewed-by: Philippe Mathieu-Daudé --- Based-on: <1551476756-25749-1-git-send-email-will@wbowling.info> --- slirp/tcp_subr.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c index ef9d99c154..1d7e72dca7 100644 --- a/slirp/tcp_subr.c +++ b/slirp/tcp_subr.c @@ -660,10 +660,12 @@ tcp_emu(struct socket *so, struct mbuf *m) tmpso->so_fport == n1) { if (getsockname(tmpso->s, (struct sockaddr *)&addr, &addrlen) == 0) - n2 = ntohs(addr.sin_port); + n2 = addr.sin_port; break; } } + NTOHS(n1); + NTOHS(n2); so_rcv->sb_cc = snprintf(so_rcv->sb_data, so_rcv->sb_datalen, "%d,%d\r\n", n1, n2); From ffe02f5585d3fd722f9eb0ecdce6f128444c63d1 Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Fri, 1 Apr 2016 00:46:35 +0200 Subject: [PATCH 05/12] slirp: Mark pieces missing IPv6 support Signed-off-by: Samuel Thibault --- net/slirp.c | 1 + slirp/misc.c | 3 +++ slirp/slirp.c | 5 +++++ slirp/socket.c | 1 + slirp/tcp_input.c | 2 ++ slirp/tcp_subr.c | 2 ++ slirp/udp.c | 1 + 7 files changed, 15 insertions(+) diff --git a/net/slirp.c b/net/slirp.c index 4ec989b592..a8fd9e6364 100644 --- a/net/slirp.c +++ b/net/slirp.c @@ -885,6 +885,7 @@ static ssize_t guestfwd_write(const void *buf, size_t len, void *chr) static int slirp_guestfwd(SlirpState *s, const char *config_str, Error **errp) { + /* TODO: IPv6 */ struct in_addr server = { .s_addr = 0 }; struct GuestFwd *fwd; const char *p; diff --git a/slirp/misc.c b/slirp/misc.c index d9fc586a24..937a418d4e 100644 --- a/slirp/misc.c +++ b/slirp/misc.c @@ -28,6 +28,7 @@ remque(void *a) element->qh_rlink = NULL; } +/* TODO: IPv6 */ struct gfwd_list * add_guestfwd(struct gfwd_list **ex_ptr, SlirpWriteCb write_cb, void *opaque, @@ -254,6 +255,8 @@ char *slirp_connection_info(Slirp *slirp) " Protocol[State] FD Source Address Port " "Dest. Address Port RecvQ SendQ\n"); + /* TODO: IPv6 */ + for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so->so_next) { if (so->so_state & SS_HOSTFWD) { state = "HOST_FORWARD"; diff --git a/slirp/slirp.c b/slirp/slirp.c index 55591430dc..cbdf9f778d 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -729,6 +729,7 @@ static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len) if (ah->ar_tip == slirp->vnameserver_addr.s_addr || ah->ar_tip == slirp->vhost_addr.s_addr) goto arp_ok; + /* TODO: IPv6 */ for (ex_ptr = slirp->guestfwd_list; ex_ptr; ex_ptr = ex_ptr->ex_next) { if (ex_ptr->ex_addr.s_addr == ah->ar_tip) goto arp_ok; @@ -945,6 +946,7 @@ int if_encap(Slirp *slirp, struct mbuf *ifm) } /* Drop host forwarding rule, return 0 if found. */ +/* TODO: IPv6 */ int slirp_remove_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr, int host_port) { @@ -970,6 +972,7 @@ int slirp_remove_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr, return -1; } +/* TODO: IPv6 */ int slirp_add_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr, int host_port, struct in_addr guest_addr, int guest_port) { @@ -988,6 +991,7 @@ int slirp_add_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr, return 0; } +/* TODO: IPv6 */ static bool check_guestfwd(Slirp *slirp, struct in_addr *guest_addr, int guest_port) { @@ -1065,6 +1069,7 @@ slirp_find_ctl_socket(Slirp *slirp, struct in_addr guest_addr, int guest_port) { struct socket *so; + /* TODO: IPv6 */ for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so->so_next) { if (so->so_faddr.s_addr == guest_addr.s_addr && htons(so->so_fport) == guest_port) { diff --git a/slirp/socket.c b/slirp/socket.c index 4dc5e2907d..f2428a3ae8 100644 --- a/slirp/socket.c +++ b/slirp/socket.c @@ -687,6 +687,7 @@ struct socket * tcp_listen(Slirp *slirp, uint32_t haddr, unsigned hport, uint32_t laddr, unsigned lport, int flags) { + /* TODO: IPv6 */ struct sockaddr_in addr; struct socket *so; int s, opt = 1; diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c index 6749b32f5d..b10477fc57 100644 --- a/slirp/tcp_input.c +++ b/slirp/tcp_input.c @@ -388,6 +388,7 @@ findso: * as if it was LISTENING, and continue... */ if (so == NULL) { + /* TODO: IPv6 */ if (slirp->restricted) { /* Any hostfwds will have an existing socket, so we only get here * for non-hostfwd connections. These should be dropped, unless it @@ -609,6 +610,7 @@ findso: * If this is destined for the control address, then flag to * tcp_ctl once connected, otherwise connect */ + /* TODO: IPv6 */ if (af == AF_INET && (so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) == slirp->vnetwork_addr.s_addr) { diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c index 1d7e72dca7..1db59caa89 100644 --- a/slirp/tcp_subr.c +++ b/slirp/tcp_subr.c @@ -626,6 +626,7 @@ tcp_emu(struct socket *so, struct mbuf *m) switch(so->so_emu) { int x, i; + /* TODO: IPv6 */ case EMU_IDENT: /* * Identification protocol as per rfc-1413 @@ -964,6 +965,7 @@ int tcp_ctl(struct socket *so) DEBUG_CALL("tcp_ctl"); DEBUG_ARG("so = %p", so); + /* TODO: IPv6 */ if (so->so_faddr.s_addr != slirp->vhost_addr.s_addr) { /* Check if it's pty_exec */ for (ex_ptr = slirp->guestfwd_list; ex_ptr; ex_ptr = ex_ptr->ex_next) { diff --git a/slirp/udp.c b/slirp/udp.c index 3d9a19b85a..fa9f4a08bd 100644 --- a/slirp/udp.c +++ b/slirp/udp.c @@ -322,6 +322,7 @@ struct socket * udp_listen(Slirp *slirp, uint32_t haddr, unsigned hport, uint32_t laddr, unsigned lport, int flags) { + /* TODO: IPv6 */ struct sockaddr_in addr; struct socket *so; socklen_t addrlen = sizeof(struct sockaddr_in); From b92a1ff497dd2f84902b252ad3de22fcc33b60e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 12 Feb 2019 17:25:18 +0100 Subject: [PATCH 06/12] slirp: adapt a subset of QEMU vmstate code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add vmstate serialization code adapted from QEMU. Keep only the bits that are required for libslirp. Introduce a IStream/OStream interface to replace QEMU QFile abstraction. Signed-off-by: Marc-André Lureau Message-Id: <20190212162524.31504-2-marcandre.lureau@redhat.com> Signed-off-by: Samuel Thibault --- slirp/Makefile.objs | 2 + slirp/libslirp.h | 2 + slirp/stream.c | 119 +++++++++++++ slirp/stream.h | 34 ++++ slirp/vmstate.c | 413 ++++++++++++++++++++++++++++++++++++++++++++ slirp/vmstate.h | 396 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 966 insertions(+) create mode 100644 slirp/stream.c create mode 100644 slirp/stream.h create mode 100644 slirp/vmstate.c create mode 100644 slirp/vmstate.h diff --git a/slirp/Makefile.objs b/slirp/Makefile.objs index 88340a583b..69e140f965 100644 --- a/slirp/Makefile.objs +++ b/slirp/Makefile.objs @@ -21,6 +21,7 @@ slirp.mo-objs = \ slirp.o \ socket.o \ state.o \ + stream.o \ tcp_input.o \ tcp_output.o \ tcp_subr.o \ @@ -29,6 +30,7 @@ slirp.mo-objs = \ udp.o \ udp6.o \ util.o \ + vmstate.o \ $(NULL) slirp.mo-cflags = -DG_LOG_DOMAIN=\"Slirp\" -DWITH_QEMU diff --git a/slirp/libslirp.h b/slirp/libslirp.h index fccab42518..57bd6f597c 100644 --- a/slirp/libslirp.h +++ b/slirp/libslirp.h @@ -3,6 +3,7 @@ #include #include +#include #ifdef _WIN32 #include @@ -26,6 +27,7 @@ enum { SLIRP_POLL_HUP = 1 << 4, }; +typedef ssize_t (*SlirpReadCb)(void *buf, size_t len, void *opaque); typedef ssize_t (*SlirpWriteCb)(const void *buf, size_t len, void *opaque); typedef void (*SlirpTimerCb)(void *opaque); typedef int (*SlirpAddPollCb)(int fd, int events, void *opaque); diff --git a/slirp/stream.c b/slirp/stream.c new file mode 100644 index 0000000000..d114dde334 --- /dev/null +++ b/slirp/stream.c @@ -0,0 +1,119 @@ +/* + * libslirp io streams + * + * Copyright (c) 2018 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "stream.h" +#include + +bool slirp_istream_read(SlirpIStream *f, void *buf, size_t size) +{ + return f->read_cb(buf, size, f->opaque) == size; +} + +bool slirp_ostream_write(SlirpOStream *f, const void *buf, size_t size) +{ + return f->write_cb(buf, size, f->opaque) == size; +} + +uint8_t slirp_istream_read_u8(SlirpIStream *f) +{ + uint8_t b; + + if (slirp_istream_read(f, &b, sizeof(b))) { + return b; + } + + return 0; +} + +bool slirp_ostream_write_u8(SlirpOStream *f, uint8_t b) +{ + return slirp_ostream_write(f, &b, sizeof(b)); +} + +uint16_t slirp_istream_read_u16(SlirpIStream *f) +{ + uint16_t b; + + if (slirp_istream_read(f, &b, sizeof(b))) { + return GUINT16_FROM_BE(b); + } + + return 0; +} + +bool slirp_ostream_write_u16(SlirpOStream *f, uint16_t b) +{ + b = GUINT16_TO_BE(b); + return slirp_ostream_write(f, &b, sizeof(b)); +} + +uint32_t slirp_istream_read_u32(SlirpIStream *f) +{ + uint32_t b; + + if (slirp_istream_read(f, &b, sizeof(b))) { + return GUINT32_FROM_BE(b); + } + + return 0; +} + +bool slirp_ostream_write_u32(SlirpOStream *f, uint32_t b) +{ + b = GUINT32_TO_BE(b); + return slirp_ostream_write(f, &b, sizeof(b)); +} + +int16_t slirp_istream_read_i16(SlirpIStream *f) +{ + int16_t b; + + if (slirp_istream_read(f, &b, sizeof(b))) { + return GINT16_FROM_BE(b); + } + + return 0; +} + +bool slirp_ostream_write_i16(SlirpOStream *f, int16_t b) +{ + b = GINT16_TO_BE(b); + return slirp_ostream_write(f, &b, sizeof(b)); +} + +int32_t slirp_istream_read_i32(SlirpIStream *f) +{ + int32_t b; + + if (slirp_istream_read(f, &b, sizeof(b))) { + return GINT32_FROM_BE(b); + } + + return 0; +} + +bool slirp_ostream_write_i32(SlirpOStream *f, int32_t b) +{ + b = GINT32_TO_BE(b); + return slirp_ostream_write(f, &b, sizeof(b)); +} diff --git a/slirp/stream.h b/slirp/stream.h new file mode 100644 index 0000000000..985334c043 --- /dev/null +++ b/slirp/stream.h @@ -0,0 +1,34 @@ +#ifndef STREAM_H_ +#define STREAM_H_ + +#include "libslirp.h" + +typedef struct SlirpIStream { + SlirpReadCb read_cb; + void *opaque; +} SlirpIStream; + +typedef struct SlirpOStream { + SlirpWriteCb write_cb; + void *opaque; +} SlirpOStream; + +bool slirp_istream_read(SlirpIStream *f, void *buf, size_t size); +bool slirp_ostream_write(SlirpOStream *f, const void *buf, size_t size); + +uint8_t slirp_istream_read_u8(SlirpIStream *f); +bool slirp_ostream_write_u8(SlirpOStream *f, uint8_t b); + +uint16_t slirp_istream_read_u16(SlirpIStream *f); +bool slirp_ostream_write_u16(SlirpOStream *f, uint16_t b); + +uint32_t slirp_istream_read_u32(SlirpIStream *f); +bool slirp_ostream_write_u32(SlirpOStream *f, uint32_t b); + +int16_t slirp_istream_read_i16(SlirpIStream *f); +bool slirp_ostream_write_i16(SlirpOStream *f, int16_t b); + +int32_t slirp_istream_read_i32(SlirpIStream *f); +bool slirp_ostream_write_i32(SlirpOStream *f, int32_t b); + +#endif /* STREAM_H_ */ diff --git a/slirp/vmstate.c b/slirp/vmstate.c new file mode 100644 index 0000000000..4d08b47c61 --- /dev/null +++ b/slirp/vmstate.c @@ -0,0 +1,413 @@ +/* + * VMState interpreter + * + * Copyright (c) 2009-2018 Red Hat Inc + * + * Authors: + * Juan Quintela + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#include +#include +#include +#include + +#include "stream.h" +#include "vmstate.h" + +static int get_nullptr(SlirpIStream *f, void *pv, size_t size, + const VMStateField *field) +{ + if (slirp_istream_read_u8(f) == VMS_NULLPTR_MARKER) { + return 0; + } + g_warning("vmstate: get_nullptr expected VMS_NULLPTR_MARKER"); + return -EINVAL; +} + +static int put_nullptr(SlirpOStream *f, void *pv, size_t size, + const VMStateField *field) + +{ + if (pv == NULL) { + slirp_ostream_write_u8(f, VMS_NULLPTR_MARKER); + return 0; + } + g_warning("vmstate: put_nullptr must be called with pv == NULL"); + return -EINVAL; +} + +const VMStateInfo slirp_vmstate_info_nullptr = { + .name = "uint64", + .get = get_nullptr, + .put = put_nullptr, +}; + +/* 8 bit unsigned int */ + +static int get_uint8(SlirpIStream *f, void *pv, size_t size, const VMStateField *field) +{ + uint8_t *v = pv; + *v = slirp_istream_read_u8(f); + return 0; +} + +static int put_uint8(SlirpOStream *f, void *pv, size_t size, const VMStateField *field) +{ + uint8_t *v = pv; + slirp_ostream_write_u8(f, *v); + return 0; +} + +const VMStateInfo slirp_vmstate_info_uint8 = { + .name = "uint8", + .get = get_uint8, + .put = put_uint8, +}; + +/* 16 bit unsigned int */ + +static int get_uint16(SlirpIStream *f, void *pv, size_t size, + const VMStateField *field) +{ + uint16_t *v = pv; + *v = slirp_istream_read_u16(f); + return 0; +} + +static int put_uint16(SlirpOStream *f, void *pv, size_t size, + const VMStateField *field) +{ + uint16_t *v = pv; + slirp_ostream_write_u16(f, *v); + return 0; +} + +const VMStateInfo slirp_vmstate_info_uint16 = { + .name = "uint16", + .get = get_uint16, + .put = put_uint16, +}; + +/* 32 bit unsigned int */ + +static int get_uint32(SlirpIStream *f, void *pv, size_t size, + const VMStateField *field) +{ + uint32_t *v = pv; + *v = slirp_istream_read_u32(f); + return 0; +} + +static int put_uint32(SlirpOStream *f, void *pv, size_t size, + const VMStateField *field) +{ + uint32_t *v = pv; + slirp_ostream_write_u32(f, *v); + return 0; +} + +const VMStateInfo slirp_vmstate_info_uint32 = { + .name = "uint32", + .get = get_uint32, + .put = put_uint32, +}; + +/* 16 bit int */ + +static int get_int16(SlirpIStream *f, void *pv, size_t size, const VMStateField *field) +{ + int16_t *v = pv; + *v = slirp_istream_read_i16(f); + return 0; +} + +static int put_int16(SlirpOStream *f, void *pv, size_t size, const VMStateField *field) +{ + int16_t *v = pv; + slirp_ostream_write_i16(f, *v); + return 0; +} + +const VMStateInfo slirp_vmstate_info_int16 = { + .name = "int16", + .get = get_int16, + .put = put_int16, +}; + +/* 32 bit int */ + +static int get_int32(SlirpIStream *f, void *pv, size_t size, const VMStateField *field) +{ + int32_t *v = pv; + *v = slirp_istream_read_i32(f); + return 0; +} + +static int put_int32(SlirpOStream *f, void *pv, size_t size, const VMStateField *field) +{ + int32_t *v = pv; + slirp_ostream_write_i32(f, *v); + return 0; +} + +const VMStateInfo slirp_vmstate_info_int32 = { + .name = "int32", + .get = get_int32, + .put = put_int32, +}; + +/* vmstate_info_tmp, see VMSTATE_WITH_TMP, the idea is that we allocate + * a temporary buffer and the pre_load/pre_save methods in the child vmsd + * copy stuff from the parent into the child and do calculations to fill + * in fields that don't really exist in the parent but need to be in the + * stream. + */ +static int get_tmp(SlirpIStream *f, void *pv, size_t size, const VMStateField *field) +{ + int ret; + const VMStateDescription *vmsd = field->vmsd; + int version_id = field->version_id; + void *tmp = g_malloc(size); + + /* Writes the parent field which is at the start of the tmp */ + *(void **)tmp = pv; + ret = slirp_vmstate_load_state(f, vmsd, tmp, version_id); + g_free(tmp); + return ret; +} + +static int put_tmp(SlirpOStream *f, void *pv, size_t size, const VMStateField *field) +{ + const VMStateDescription *vmsd = field->vmsd; + void *tmp = g_malloc(size); + int ret; + + /* Writes the parent field which is at the start of the tmp */ + *(void **)tmp = pv; + ret = slirp_vmstate_save_state(f, vmsd, tmp); + g_free(tmp); + + return ret; +} + +const VMStateInfo slirp_vmstate_info_tmp = { + .name = "tmp", + .get = get_tmp, + .put = put_tmp, +}; + +/* uint8_t buffers */ + +static int get_buffer(SlirpIStream *f, void *pv, size_t size, + const VMStateField *field) +{ + slirp_istream_read(f, pv, size); + return 0; +} + +static int put_buffer(SlirpOStream *f, void *pv, size_t size, + const VMStateField *field) +{ + slirp_ostream_write(f, pv, size); + return 0; +} + +const VMStateInfo slirp_vmstate_info_buffer = { + .name = "buffer", + .get = get_buffer, + .put = put_buffer, +}; + +static int vmstate_n_elems(void *opaque, const VMStateField *field) +{ + int n_elems = 1; + + if (field->flags & VMS_ARRAY) { + n_elems = field->num; + } else if (field->flags & VMS_VARRAY_INT32) { + n_elems = *(int32_t *)(opaque + field->num_offset); + } else if (field->flags & VMS_VARRAY_UINT32) { + n_elems = *(uint32_t *)(opaque + field->num_offset); + } else if (field->flags & VMS_VARRAY_UINT16) { + n_elems = *(uint16_t *)(opaque + field->num_offset); + } else if (field->flags & VMS_VARRAY_UINT8) { + n_elems = *(uint8_t *)(opaque + field->num_offset); + } + + if (field->flags & VMS_MULTIPLY_ELEMENTS) { + n_elems *= field->num; + } + + return n_elems; +} + +static int vmstate_size(void *opaque, const VMStateField *field) +{ + int size = field->size; + + if (field->flags & VMS_VBUFFER) { + size = *(int32_t *)(opaque + field->size_offset); + if (field->flags & VMS_MULTIPLY) { + size *= field->size; + } + } + + return size; +} + +static int +vmstate_save_state_v(SlirpOStream *f, const VMStateDescription *vmsd, + void *opaque, int version_id) +{ + int ret = 0; + const VMStateField *field = vmsd->fields; + + if (vmsd->pre_save) { + ret = vmsd->pre_save(opaque); + if (ret) { + g_warning("pre-save failed: %s", vmsd->name); + return ret; + } + } + + while (field->name) { + if ((field->field_exists && + field->field_exists(opaque, version_id)) || + (!field->field_exists && + field->version_id <= version_id)) { + void *first_elem = opaque + field->offset; + int i, n_elems = vmstate_n_elems(opaque, field); + int size = vmstate_size(opaque, field); + + if (field->flags & VMS_POINTER) { + first_elem = *(void **)first_elem; + assert(first_elem || !n_elems || !size); + } + for (i = 0; i < n_elems; i++) { + void *curr_elem = first_elem + size * i; + ret = 0; + + if (field->flags & VMS_ARRAY_OF_POINTER) { + assert(curr_elem); + curr_elem = *(void **)curr_elem; + } + if (!curr_elem && size) { + /* if null pointer write placeholder and do not follow */ + assert(field->flags & VMS_ARRAY_OF_POINTER); + ret = slirp_vmstate_info_nullptr.put(f, curr_elem, size, NULL); + } else if (field->flags & VMS_STRUCT) { + ret = slirp_vmstate_save_state(f, field->vmsd, curr_elem); + } else if (field->flags & VMS_VSTRUCT) { + ret = vmstate_save_state_v(f, field->vmsd, curr_elem, + field->struct_version_id); + } else { + ret = field->info->put(f, curr_elem, size, field); + } + if (ret) { + g_warning("Save of field %s/%s failed", + vmsd->name, field->name); + return ret; + } + } + } else { + if (field->flags & VMS_MUST_EXIST) { + g_warning("Output state validation failed: %s/%s", + vmsd->name, field->name); + assert(!(field->flags & VMS_MUST_EXIST)); + } + } + field++; + } + + return 0; +} + +int slirp_vmstate_save_state(SlirpOStream *f, const VMStateDescription *vmsd, + void *opaque) +{ + return vmstate_save_state_v(f, vmsd, opaque, vmsd->version_id); +} + +static void vmstate_handle_alloc(void *ptr, VMStateField *field, void *opaque) +{ + if (field->flags & VMS_POINTER && field->flags & VMS_ALLOC) { + size_t size = vmstate_size(opaque, field); + size *= vmstate_n_elems(opaque, field); + if (size) { + *(void **)ptr = g_malloc(size); + } + } +} + +int slirp_vmstate_load_state(SlirpIStream *f, const VMStateDescription *vmsd, + void *opaque, int version_id) +{ + VMStateField *field = vmsd->fields; + int ret = 0; + + if (version_id > vmsd->version_id) { + g_warning("%s: incoming version_id %d is too new " + "for local version_id %d", + vmsd->name, version_id, vmsd->version_id); + return -EINVAL; + } + if (vmsd->pre_load) { + int ret = vmsd->pre_load(opaque); + if (ret) { + return ret; + } + } + while (field->name) { + if ((field->field_exists && + field->field_exists(opaque, version_id)) || + (!field->field_exists && + field->version_id <= version_id)) { + void *first_elem = opaque + field->offset; + int i, n_elems = vmstate_n_elems(opaque, field); + int size = vmstate_size(opaque, field); + + vmstate_handle_alloc(first_elem, field, opaque); + if (field->flags & VMS_POINTER) { + first_elem = *(void **)first_elem; + assert(first_elem || !n_elems || !size); + } + for (i = 0; i < n_elems; i++) { + void *curr_elem = first_elem + size * i; + + if (field->flags & VMS_ARRAY_OF_POINTER) { + curr_elem = *(void **)curr_elem; + } + if (!curr_elem && size) { + /* if null pointer check placeholder and do not follow */ + assert(field->flags & VMS_ARRAY_OF_POINTER); + ret = slirp_vmstate_info_nullptr.get(f, curr_elem, size, NULL); + } else if (field->flags & VMS_STRUCT) { + ret = slirp_vmstate_load_state(f, field->vmsd, curr_elem, + field->vmsd->version_id); + } else if (field->flags & VMS_VSTRUCT) { + ret = slirp_vmstate_load_state(f, field->vmsd, curr_elem, + field->struct_version_id); + } else { + ret = field->info->get(f, curr_elem, size, field); + } + if (ret < 0) { + g_warning("Failed to load %s:%s", vmsd->name, + field->name); + return ret; + } + } + } else if (field->flags & VMS_MUST_EXIST) { + g_warning("Input validation failed: %s/%s", + vmsd->name, field->name); + return -1; + } + field++; + } + if (vmsd->post_load) { + ret = vmsd->post_load(opaque, version_id); + } + return ret; +} diff --git a/slirp/vmstate.h b/slirp/vmstate.h new file mode 100644 index 0000000000..cfa7b8c825 --- /dev/null +++ b/slirp/vmstate.h @@ -0,0 +1,396 @@ +/* + * QEMU migration/snapshot declarations + * + * Copyright (c) 2009-2011 Red Hat, Inc. + * + * Original author: Juan Quintela + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef VMSTATE_H_ +#define VMSTATE_H_ + +#include +#include +#include +#include "slirp.h" +#include "stream.h" + +#define stringify(s) tostring(s) +#define tostring(s) #s + +typedef struct VMStateInfo VMStateInfo; +typedef struct VMStateDescription VMStateDescription; +typedef struct VMStateField VMStateField; + +int slirp_vmstate_save_state(SlirpOStream *f, const VMStateDescription *vmsd, + void *opaque); +int slirp_vmstate_load_state(SlirpIStream *f, const VMStateDescription *vmsd, + void *opaque, int version_id); + +/* VMStateInfo allows customized migration of objects that don't fit in + * any category in VMStateFlags. Additional information is always passed + * into get and put in terms of field and vmdesc parameters. However + * these two parameters should only be used in cases when customized + * handling is needed, such as QTAILQ. For primitive data types such as + * integer, field and vmdesc parameters should be ignored inside get/put. + */ +struct VMStateInfo { + const char *name; + int (*get)(SlirpIStream *f, void *pv, size_t size, const VMStateField *field); + int (*put)(SlirpOStream *f, void *pv, size_t size, const VMStateField *field); +}; + +enum VMStateFlags { + /* Ignored */ + VMS_SINGLE = 0x001, + + /* The struct member at opaque + VMStateField.offset is a pointer + * to the actual field (e.g. struct a { uint8_t *b; + * }). Dereference the pointer before using it as basis for + * further pointer arithmetic (see e.g. VMS_ARRAY). Does not + * affect the meaning of VMStateField.num_offset or + * VMStateField.size_offset; see VMS_VARRAY* and VMS_VBUFFER for + * those. */ + VMS_POINTER = 0x002, + + /* The field is an array of fixed size. VMStateField.num contains + * the number of entries in the array. The size of each entry is + * given by VMStateField.size and / or opaque + + * VMStateField.size_offset; see VMS_VBUFFER and + * VMS_MULTIPLY. Each array entry will be processed individually + * (VMStateField.info.get()/put() if VMS_STRUCT is not set, + * recursion into VMStateField.vmsd if VMS_STRUCT is set). May not + * be combined with VMS_VARRAY*. */ + VMS_ARRAY = 0x004, + + /* The field is itself a struct, containing one or more + * fields. Recurse into VMStateField.vmsd. Most useful in + * combination with VMS_ARRAY / VMS_VARRAY*, recursing into each + * array entry. */ + VMS_STRUCT = 0x008, + + /* The field is an array of variable size. The int32_t at opaque + + * VMStateField.num_offset contains the number of entries in the + * array. See the VMS_ARRAY description regarding array handling + * in general. May not be combined with VMS_ARRAY or any other + * VMS_VARRAY*. */ + VMS_VARRAY_INT32 = 0x010, + + /* Ignored */ + VMS_BUFFER = 0x020, + + /* The field is a (fixed-size or variable-size) array of pointers + * (e.g. struct a { uint8_t *b[]; }). Dereference each array entry + * before using it. Note: Does not imply any one of VMS_ARRAY / + * VMS_VARRAY*; these need to be set explicitly. */ + VMS_ARRAY_OF_POINTER = 0x040, + + /* The field is an array of variable size. The uint16_t at opaque + * + VMStateField.num_offset (subject to VMS_MULTIPLY_ELEMENTS) + * contains the number of entries in the array. See the VMS_ARRAY + * description regarding array handling in general. May not be + * combined with VMS_ARRAY or any other VMS_VARRAY*. */ + VMS_VARRAY_UINT16 = 0x080, + + /* The size of the individual entries (a single array entry if + * VMS_ARRAY or any of VMS_VARRAY* are set, or the field itself if + * neither is set) is variable (i.e. not known at compile-time), + * but the same for all entries. Use the int32_t at opaque + + * VMStateField.size_offset (subject to VMS_MULTIPLY) to determine + * the size of each (and every) entry. */ + VMS_VBUFFER = 0x100, + + /* Multiply the entry size given by the int32_t at opaque + + * VMStateField.size_offset (see VMS_VBUFFER description) with + * VMStateField.size to determine the number of bytes to be + * allocated. Only valid in combination with VMS_VBUFFER. */ + VMS_MULTIPLY = 0x200, + + /* The field is an array of variable size. The uint8_t at opaque + + * VMStateField.num_offset (subject to VMS_MULTIPLY_ELEMENTS) + * contains the number of entries in the array. See the VMS_ARRAY + * description regarding array handling in general. May not be + * combined with VMS_ARRAY or any other VMS_VARRAY*. */ + VMS_VARRAY_UINT8 = 0x400, + + /* The field is an array of variable size. The uint32_t at opaque + * + VMStateField.num_offset (subject to VMS_MULTIPLY_ELEMENTS) + * contains the number of entries in the array. See the VMS_ARRAY + * description regarding array handling in general. May not be + * combined with VMS_ARRAY or any other VMS_VARRAY*. */ + VMS_VARRAY_UINT32 = 0x800, + + /* Fail loading the serialised VM state if this field is missing + * from the input. */ + VMS_MUST_EXIST = 0x1000, + + /* When loading serialised VM state, allocate memory for the + * (entire) field. Only valid in combination with + * VMS_POINTER. Note: Not all combinations with other flags are + * currently supported, e.g. VMS_ALLOC|VMS_ARRAY_OF_POINTER won't + * cause the individual entries to be allocated. */ + VMS_ALLOC = 0x2000, + + /* Multiply the number of entries given by the integer at opaque + + * VMStateField.num_offset (see VMS_VARRAY*) with VMStateField.num + * to determine the number of entries in the array. Only valid in + * combination with one of VMS_VARRAY*. */ + VMS_MULTIPLY_ELEMENTS = 0x4000, + + /* A structure field that is like VMS_STRUCT, but uses + * VMStateField.struct_version_id to tell which version of the + * structure we are referencing to use. */ + VMS_VSTRUCT = 0x8000, +}; + +struct VMStateField { + const char *name; + size_t offset; + size_t size; + size_t start; + int num; + size_t num_offset; + size_t size_offset; + const VMStateInfo *info; + enum VMStateFlags flags; + const VMStateDescription *vmsd; + int version_id; + int struct_version_id; + bool (*field_exists)(void *opaque, int version_id); +}; + +struct VMStateDescription { + const char *name; + int version_id; + int (*pre_load)(void *opaque); + int (*post_load)(void *opaque, int version_id); + int (*pre_save)(void *opaque); + VMStateField *fields; +}; + + +extern const VMStateInfo slirp_vmstate_info_int16; +extern const VMStateInfo slirp_vmstate_info_int32; +extern const VMStateInfo slirp_vmstate_info_uint8; +extern const VMStateInfo slirp_vmstate_info_uint16; +extern const VMStateInfo slirp_vmstate_info_uint32; + +/** Put this in the stream when migrating a null pointer.*/ +#define VMS_NULLPTR_MARKER (0x30U) /* '0' */ +extern const VMStateInfo slirp_vmstate_info_nullptr; + +extern const VMStateInfo slirp_vmstate_info_buffer; +extern const VMStateInfo slirp_vmstate_info_tmp; + +#define type_check_array(t1,t2,n) ((t1(*)[n])0 - (t2*)0) +#define type_check_pointer(t1,t2) ((t1**)0 - (t2*)0) +#define typeof_field(type, field) typeof(((type *)0)->field) +#define type_check(t1,t2) ((t1*)0 - (t2*)0) + +#define vmstate_offset_value(_state, _field, _type) \ + (offsetof(_state, _field) + \ + type_check(_type, typeof_field(_state, _field))) + +#define vmstate_offset_pointer(_state, _field, _type) \ + (offsetof(_state, _field) + \ + type_check_pointer(_type, typeof_field(_state, _field))) + +#define vmstate_offset_array(_state, _field, _type, _num) \ + (offsetof(_state, _field) + \ + type_check_array(_type, typeof_field(_state, _field), _num)) + +#define vmstate_offset_buffer(_state, _field) \ + vmstate_offset_array(_state, _field, uint8_t, \ + sizeof(typeof_field(_state, _field))) + +/* In the macros below, if there is a _version, that means the macro's + * field will be processed only if the version being received is >= + * the _version specified. In general, if you add a new field, you + * would increment the structure's version and put that version + * number into the new field so it would only be processed with the + * new version. + * + * In particular, for VMSTATE_STRUCT() and friends the _version does + * *NOT* pick the version of the sub-structure. It works just as + * specified above. The version of the top-level structure received + * is passed down to all sub-structures. This means that the + * sub-structures must have version that are compatible with all the + * structures that use them. + * + * If you want to specify the version of the sub-structure, use + * VMSTATE_VSTRUCT(), which allows the specific sub-structure version + * to be directly specified. + */ + +#define VMSTATE_SINGLE_TEST(_field, _state, _test, _version, _info, _type) { \ + .name = (stringify(_field)), \ + .version_id = (_version), \ + .field_exists = (_test), \ + .size = sizeof(_type), \ + .info = &(_info), \ + .flags = VMS_SINGLE, \ + .offset = vmstate_offset_value(_state, _field, _type), \ +} + +#define VMSTATE_ARRAY(_field, _state, _num, _version, _info, _type) {\ + .name = (stringify(_field)), \ + .version_id = (_version), \ + .num = (_num), \ + .info = &(_info), \ + .size = sizeof(_type), \ + .flags = VMS_ARRAY, \ + .offset = vmstate_offset_array(_state, _field, _type, _num), \ +} + +#define VMSTATE_STRUCT_TEST(_field, _state, _test, _version, _vmsd, _type) { \ + .name = (stringify(_field)), \ + .version_id = (_version), \ + .field_exists = (_test), \ + .vmsd = &(_vmsd), \ + .size = sizeof(_type), \ + .flags = VMS_STRUCT, \ + .offset = vmstate_offset_value(_state, _field, _type), \ +} + +#define VMSTATE_STRUCT_POINTER_V(_field, _state, _version, _vmsd, _type) { \ + .name = (stringify(_field)), \ + .version_id = (_version), \ + .vmsd = &(_vmsd), \ + .size = sizeof(_type *), \ + .flags = VMS_STRUCT|VMS_POINTER, \ + .offset = vmstate_offset_pointer(_state, _field, _type), \ +} + +#define VMSTATE_STRUCT_ARRAY_TEST(_field, _state, _num, _test, _version, _vmsd, _type) { \ + .name = (stringify(_field)), \ + .num = (_num), \ + .field_exists = (_test), \ + .version_id = (_version), \ + .vmsd = &(_vmsd), \ + .size = sizeof(_type), \ + .flags = VMS_STRUCT|VMS_ARRAY, \ + .offset = vmstate_offset_array(_state, _field, _type, _num),\ +} + +#define VMSTATE_STATIC_BUFFER(_field, _state, _version, _test, _start, _size) { \ + .name = (stringify(_field)), \ + .version_id = (_version), \ + .field_exists = (_test), \ + .size = (_size - _start), \ + .info = &slirp_vmstate_info_buffer, \ + .flags = VMS_BUFFER, \ + .offset = vmstate_offset_buffer(_state, _field) + _start, \ +} + +#define VMSTATE_VBUFFER_UINT32(_field, _state, _version, _test, _field_size) { \ + .name = (stringify(_field)), \ + .version_id = (_version), \ + .field_exists = (_test), \ + .size_offset = vmstate_offset_value(_state, _field_size, uint32_t),\ + .info = &slirp_vmstate_info_buffer, \ + .flags = VMS_VBUFFER|VMS_POINTER, \ + .offset = offsetof(_state, _field), \ +} + +#define QEMU_BUILD_BUG_ON_STRUCT(x) \ + struct { \ + int:(x) ? -1 : 1; \ + } + +#define QEMU_BUILD_BUG_ON_ZERO(x) (sizeof(QEMU_BUILD_BUG_ON_STRUCT(x)) - \ + sizeof(QEMU_BUILD_BUG_ON_STRUCT(x))) + +/* Allocate a temporary of type 'tmp_type', set tmp->parent to _state + * and execute the vmsd on the temporary. Note that we're working with + * the whole of _state here, not a field within it. + * We compile time check that: + * That _tmp_type contains a 'parent' member that's a pointer to the + * '_state' type + * That the pointer is right at the start of _tmp_type. + */ +#define VMSTATE_WITH_TMP(_state, _tmp_type, _vmsd) { \ + .name = "tmp", \ + .size = sizeof(_tmp_type) + \ + QEMU_BUILD_BUG_ON_ZERO(offsetof(_tmp_type, parent) != 0) + \ + type_check_pointer(_state, \ + typeof_field(_tmp_type, parent)), \ + .vmsd = &(_vmsd), \ + .info = &slirp_vmstate_info_tmp, \ +} + +#define VMSTATE_SINGLE(_field, _state, _version, _info, _type) \ + VMSTATE_SINGLE_TEST(_field, _state, NULL, _version, _info, _type) + +#define VMSTATE_STRUCT(_field, _state, _version, _vmsd, _type) \ + VMSTATE_STRUCT_TEST(_field, _state, NULL, _version, _vmsd, _type) + +#define VMSTATE_STRUCT_POINTER(_field, _state, _vmsd, _type) \ + VMSTATE_STRUCT_POINTER_V(_field, _state, 0, _vmsd, _type) + +#define VMSTATE_STRUCT_ARRAY(_field, _state, _num, _version, _vmsd, _type) \ + VMSTATE_STRUCT_ARRAY_TEST(_field, _state, _num, NULL, _version, \ + _vmsd, _type) + +#define VMSTATE_INT16_V(_f, _s, _v) \ + VMSTATE_SINGLE(_f, _s, _v, slirp_vmstate_info_int16, int16_t) +#define VMSTATE_INT32_V(_f, _s, _v) \ + VMSTATE_SINGLE(_f, _s, _v, slirp_vmstate_info_int32, int32_t) + +#define VMSTATE_UINT8_V(_f, _s, _v) \ + VMSTATE_SINGLE(_f, _s, _v, slirp_vmstate_info_uint8, uint8_t) +#define VMSTATE_UINT16_V(_f, _s, _v) \ + VMSTATE_SINGLE(_f, _s, _v, slirp_vmstate_info_uint16, uint16_t) +#define VMSTATE_UINT32_V(_f, _s, _v) \ + VMSTATE_SINGLE(_f, _s, _v, slirp_vmstate_info_uint32, uint32_t) + +#define VMSTATE_INT16(_f, _s) \ + VMSTATE_INT16_V(_f, _s, 0) +#define VMSTATE_INT32(_f, _s) \ + VMSTATE_INT32_V(_f, _s, 0) + +#define VMSTATE_UINT8(_f, _s) \ + VMSTATE_UINT8_V(_f, _s, 0) +#define VMSTATE_UINT16(_f, _s) \ + VMSTATE_UINT16_V(_f, _s, 0) +#define VMSTATE_UINT32(_f, _s) \ + VMSTATE_UINT32_V(_f, _s, 0) + +#define VMSTATE_UINT16_TEST(_f, _s, _t) \ + VMSTATE_SINGLE_TEST(_f, _s, _t, 0, slirp_vmstate_info_uint16, uint16_t) + +#define VMSTATE_UINT32_TEST(_f, _s, _t) \ + VMSTATE_SINGLE_TEST(_f, _s, _t, 0, slirp_vmstate_info_uint32, uint32_t) + +#define VMSTATE_INT16_ARRAY_V(_f, _s, _n, _v) \ + VMSTATE_ARRAY(_f, _s, _n, _v, slirp_vmstate_info_int16, int16_t) + +#define VMSTATE_INT16_ARRAY(_f, _s, _n) \ + VMSTATE_INT16_ARRAY_V(_f, _s, _n, 0) + +#define VMSTATE_BUFFER_V(_f, _s, _v) \ + VMSTATE_STATIC_BUFFER(_f, _s, _v, NULL, 0, sizeof(typeof_field(_s, _f))) + +#define VMSTATE_BUFFER(_f, _s) \ + VMSTATE_BUFFER_V(_f, _s, 0) + +#define VMSTATE_END_OF_LIST() \ + {} + +#endif From d890344166449c2c4cc039f19af61600920cd697 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 12 Feb 2019 17:25:19 +0100 Subject: [PATCH 07/12] slirp: use libslirp migration code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit slirp migration code uses QEMU vmstate so far, when building WITH_QEMU. Introduce slirp_state_{load,save,version}() functions to move the state saving handling to libslirp side. So far, the bitstream compatibility should remain equal with current QEMU, as this is effectively using the same code, with the same format etc. When libslirp is made standalone, we will need some mechanism to ensure bitstream compatibility regardless of the libslirp version installed. See the FIXME note in the code. Signed-off-by: Marc-André Lureau Message-Id: <20190212162524.31504-3-marcandre.lureau@redhat.com> Signed-off-by: Samuel Thibault --- include/migration/qemu-file-types.h | 2 ++ migration/qemu-file.h | 1 - net/slirp.c | 55 +++++++++++++++++++++++++++++ slirp/libslirp.h | 8 +++++ slirp/slirp.c | 9 ----- slirp/state.c | 52 ++++++++++++--------------- slirp/state.h | 9 ----- 7 files changed, 88 insertions(+), 48 deletions(-) diff --git a/include/migration/qemu-file-types.h b/include/migration/qemu-file-types.h index bd6d7dd7f9..bbe04d4484 100644 --- a/include/migration/qemu-file-types.h +++ b/include/migration/qemu-file-types.h @@ -25,6 +25,8 @@ #ifndef QEMU_FILE_H #define QEMU_FILE_H +int qemu_file_get_error(QEMUFile *f); + void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, size_t size); void qemu_put_byte(QEMUFile *f, int v); diff --git a/migration/qemu-file.h b/migration/qemu-file.h index 2ccfcfb2a8..13baf896bd 100644 --- a/migration/qemu-file.h +++ b/migration/qemu-file.h @@ -149,7 +149,6 @@ void qemu_update_position(QEMUFile *f, size_t size); void qemu_file_reset_rate_limit(QEMUFile *f); void qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate); int64_t qemu_file_get_rate_limit(QEMUFile *f); -int qemu_file_get_error(QEMUFile *f); void qemu_file_set_error(QEMUFile *f, int ret); int qemu_file_shutdown(QEMUFile *f); QEMUFile *qemu_file_get_return_path(QEMUFile *f); diff --git a/net/slirp.c b/net/slirp.c index a8fd9e6364..059b2d9b08 100644 --- a/net/slirp.c +++ b/net/slirp.c @@ -44,6 +44,8 @@ #include "qapi/error.h" #include "qapi/qmp/qdict.h" #include "util.h" +#include "migration/register.h" +#include "migration/qemu-file-types.h" static int get_str_sep(char *buf, int buf_size, const char **pp, int sep) { @@ -146,6 +148,7 @@ static void net_slirp_cleanup(NetClientState *nc) g_slist_free_full(s->fwd, slirp_free_fwd); main_loop_poll_remove_notifier(&s->poll_notifier); + unregister_savevm(NULL, "slirp", s->slirp); slirp_cleanup(s->slirp); if (s->exit_notifier.notify) { qemu_remove_exit_notifier(&s->exit_notifier); @@ -303,6 +306,46 @@ static void net_slirp_poll_notify(Notifier *notifier, void *data) } } +static ssize_t +net_slirp_stream_read(void *buf, size_t size, void *opaque) +{ + QEMUFile *f = opaque; + + return qemu_get_buffer(f, buf, size); +} + +static ssize_t +net_slirp_stream_write(const void *buf, size_t size, void *opaque) +{ + QEMUFile *f = opaque; + + qemu_put_buffer(f, buf, size); + if (qemu_file_get_error(f)) { + return -1; + } + + return size; +} + +static int net_slirp_state_load(QEMUFile *f, void *opaque, int version_id) +{ + Slirp *slirp = opaque; + + return slirp_state_load(slirp, version_id, net_slirp_stream_read, f); +} + +static void net_slirp_state_save(QEMUFile *f, void *opaque) +{ + Slirp *slirp = opaque; + + slirp_state_save(slirp, net_slirp_stream_write, f); +} + +static SaveVMHandlers savevm_slirp_state = { + .save_state = net_slirp_state_save, + .load_state = net_slirp_state_load, +}; + static int net_slirp_init(NetClientState *peer, const char *model, const char *name, int restricted, bool ipv4, const char *vnetwork, const char *vhost, @@ -523,6 +566,18 @@ static int net_slirp_init(NetClientState *peer, const char *model, &slirp_cb, s); QTAILQ_INSERT_TAIL(&slirp_stacks, s, entry); + /* + * Make sure the current bitstream version of slirp is 4, to avoid + * QEMU migration incompatibilities, if upstream slirp bumped the + * version. + * + * FIXME: use bitfields of features? teach libslirp to save with + * specific version? + */ + g_assert(slirp_state_version() == 4); + register_savevm_live(NULL, "slirp", 0, slirp_state_version(), + &savevm_slirp_state, s->slirp); + s->poll_notifier.notify = net_slirp_poll_notify; main_loop_poll_add_notifier(&s->poll_notifier); diff --git a/slirp/libslirp.h b/slirp/libslirp.h index 57bd6f597c..2d13950065 100644 --- a/slirp/libslirp.h +++ b/slirp/libslirp.h @@ -102,6 +102,14 @@ void slirp_socket_recv(Slirp *slirp, struct in_addr guest_addr, int guest_port, const uint8_t *buf, int size); size_t slirp_socket_can_recv(Slirp *slirp, struct in_addr guest_addr, int guest_port); + +void slirp_state_save(Slirp *s, SlirpWriteCb write_cb, void *opaque); + +int slirp_state_load(Slirp *s, int version_id, + SlirpReadCb read_cb, void *opaque); + +int slirp_state_version(void); + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/slirp/slirp.c b/slirp/slirp.c index cbdf9f778d..18af670a0a 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -23,9 +23,6 @@ */ #include "slirp.h" -#ifdef WITH_QEMU -#include "state.h" -#endif #ifndef _WIN32 #include @@ -326,9 +323,6 @@ Slirp *slirp_init(int restricted, bool in_enabled, struct in_addr vnetwork, translate_dnssearch(slirp, vdnssearch); } -#ifdef WITH_QEMU - slirp_state_register(slirp); -#endif return slirp; } @@ -342,9 +336,6 @@ void slirp_cleanup(Slirp *slirp) g_free(e); } -#ifdef WITH_QEMU - slirp_state_unregister(slirp); -#endif ip_cleanup(slirp); ip6_cleanup(slirp); m_cleanup(slirp); diff --git a/slirp/state.c b/slirp/state.c index 0e5a706e87..f5dd80cdc8 100644 --- a/slirp/state.c +++ b/slirp/state.c @@ -21,13 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "qemu/osdep.h" - #include "slirp.h" +#include "vmstate.h" #include "state.h" -#include "migration/vmstate.h" -#include "migration/qemu-file-types.h" -#include "migration/register.h" +#include "stream.h" static int slirp_tcp_post_load(void *opaque, int version) { @@ -180,7 +177,7 @@ static int slirp_socket_pre_load(void *opaque) #else /* Win uses u_long rather than uint32_t - but it's still 32bits long */ #define VMSTATE_SIN4_ADDR(f, s, t) VMSTATE_SINGLE_TEST(f, s, t, 0, \ - vmstate_info_uint32, u_long) + slirp_vmstate_info_uint32, u_long) #endif /* The OS provided ss_family field isn't that portable; it's size @@ -322,10 +319,13 @@ static const VMStateDescription vmstate_slirp = { } }; -static void slirp_state_save(QEMUFile *f, void *opaque) +void slirp_state_save(Slirp *slirp, SlirpWriteCb write_cb, void *opaque) { - Slirp *slirp = opaque; struct gfwd_list *ex_ptr; + SlirpOStream f = { + .write_cb = write_cb, + .opaque = opaque, + }; for (ex_ptr = slirp->guestfwd_list; ex_ptr; ex_ptr = ex_ptr->ex_next) if (ex_ptr->write_cb) { @@ -336,25 +336,29 @@ static void slirp_state_save(QEMUFile *f, void *opaque) continue; } - qemu_put_byte(f, 42); - vmstate_save_state(f, &vmstate_slirp_socket, so, NULL); + slirp_ostream_write_u8(&f, 42); + slirp_vmstate_save_state(&f, &vmstate_slirp_socket, so); } - qemu_put_byte(f, 0); + slirp_ostream_write_u8(&f, 0); - vmstate_save_state(f, &vmstate_slirp, slirp, NULL); + slirp_vmstate_save_state(&f, &vmstate_slirp, slirp); } -static int slirp_state_load(QEMUFile *f, void *opaque, int version_id) +int slirp_state_load(Slirp *slirp, int version_id, + SlirpReadCb read_cb, void *opaque) { - Slirp *slirp = opaque; struct gfwd_list *ex_ptr; + SlirpIStream f = { + .read_cb = read_cb, + .opaque = opaque, + }; - while (qemu_get_byte(f)) { + while (slirp_istream_read_u8(&f)) { int ret; struct socket *so = socreate(slirp); - ret = vmstate_load_state(f, &vmstate_slirp_socket, so, version_id); + ret = slirp_vmstate_load_state(&f, &vmstate_slirp_socket, so, version_id); if (ret < 0) { return ret; } @@ -375,20 +379,10 @@ static int slirp_state_load(QEMUFile *f, void *opaque, int version_id) } } - return vmstate_load_state(f, &vmstate_slirp, slirp, version_id); + return slirp_vmstate_load_state(&f, &vmstate_slirp, slirp, version_id); } -void slirp_state_register(Slirp *slirp) +int slirp_state_version(void) { - static SaveVMHandlers savevm_slirp_state = { - .save_state = slirp_state_save, - .load_state = slirp_state_load, - }; - - register_savevm_live(NULL, "slirp", 0, 4, &savevm_slirp_state, slirp); -} - -void slirp_state_unregister(Slirp *slirp) -{ - unregister_savevm(NULL, "slirp", slirp); + return 4; } diff --git a/slirp/state.h b/slirp/state.h index 154866898f..e69de29bb2 100644 --- a/slirp/state.h +++ b/slirp/state.h @@ -1,9 +0,0 @@ -#ifndef SLIRP_STATE_H_ -#define SLIRP_STATE_H_ - -#include "libslirp.h" - -void slirp_state_register(Slirp *slirp); -void slirp_state_unregister(Slirp *slirp); - -#endif /* SLIRP_STATE_H_ */ From 5a4af0d4ee6084fdfde0125c45181fa0e6f48a17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 12 Feb 2019 17:25:20 +0100 Subject: [PATCH 08/12] slirp: use "slirp_" prefix for inet_aton() win32 implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To avoid conflict with QEMU inet_aton() implementation, let's use the "slirp_" prefix. This allows to drop the WITH_QEMU, thus the source won't make a distinction when building with QEMU or not. Signed-off-by: Marc-André Lureau Message-Id: <20190212162524.31504-4-marcandre.lureau@redhat.com> Signed-off-by: Samuel Thibault --- slirp/Makefile.objs | 2 +- slirp/util.c | 4 ++-- slirp/util.h | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/slirp/Makefile.objs b/slirp/Makefile.objs index 69e140f965..e91daf0e91 100644 --- a/slirp/Makefile.objs +++ b/slirp/Makefile.objs @@ -33,4 +33,4 @@ slirp.mo-objs = \ vmstate.o \ $(NULL) -slirp.mo-cflags = -DG_LOG_DOMAIN=\"Slirp\" -DWITH_QEMU +slirp.mo-cflags = -DG_LOG_DOMAIN=\"Slirp\" diff --git a/slirp/util.c b/slirp/util.c index 1cbaa26b60..5ec2fa87ab 100644 --- a/slirp/util.c +++ b/slirp/util.c @@ -31,8 +31,8 @@ #include #include -#if defined(_WIN32) && !defined(WITH_QEMU) -int inet_aton(const char *cp, struct in_addr *ia) +#if defined(_WIN32) +int slirp_inet_aton(const char *cp, struct in_addr *ia) { uint32_t addr = inet_addr(cp); if (addr == 0xffffffff) { diff --git a/slirp/util.h b/slirp/util.h index c4207a49d6..e94ee4e7f1 100644 --- a/slirp/util.h +++ b/slirp/util.h @@ -138,8 +138,8 @@ int slirp_getsockopt_wrap(int sockfd, int level, int optname, #define setsockopt slirp_setsockopt_wrap int slirp_setsockopt_wrap(int sockfd, int level, int optname, const void *optval, int optlen); - -int inet_aton(const char *cp, struct in_addr *ia); +#define inet_aton slirp_inet_aton +int slirp_inet_aton(const char *cp, struct in_addr *ia); #else #define closesocket(s) close(s) #define ioctlsocket(s, r, v) ioctl(s, r, v) From c2d63650d962612cfa1b21302782d4cd12142c74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 12 Feb 2019 17:25:21 +0100 Subject: [PATCH 09/12] slirp: move sources to src/ subdirectory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prepare for making slirp/ a standalone project. Remove some useless includes while at it. Signed-off-by: Marc-André Lureau Message-Id: <20190212162524.31504-5-marcandre.lureau@redhat.com> Signed-off-by: Samuel Thibault --- net/slirp.c | 2 +- slirp/Makefile.objs | 60 ++++++++++++++++++------------------ slirp/{ => src}/arp_table.c | 0 slirp/{ => src}/bootp.c | 0 slirp/{ => src}/bootp.h | 0 slirp/{ => src}/cksum.c | 0 slirp/{ => src}/debug.h | 0 slirp/{ => src}/dhcpv6.c | 0 slirp/{ => src}/dhcpv6.h | 0 slirp/{ => src}/dnssearch.c | 0 slirp/{ => src}/if.c | 0 slirp/{ => src}/if.h | 0 slirp/{ => src}/ip.h | 0 slirp/{ => src}/ip6.h | 0 slirp/{ => src}/ip6_icmp.c | 0 slirp/{ => src}/ip6_icmp.h | 0 slirp/{ => src}/ip6_input.c | 0 slirp/{ => src}/ip6_output.c | 0 slirp/{ => src}/ip_icmp.c | 0 slirp/{ => src}/ip_icmp.h | 0 slirp/{ => src}/ip_input.c | 0 slirp/{ => src}/ip_output.c | 0 slirp/{ => src}/libslirp.h | 0 slirp/{ => src}/main.h | 0 slirp/{ => src}/mbuf.c | 0 slirp/{ => src}/mbuf.h | 0 slirp/{ => src}/misc.c | 0 slirp/{ => src}/misc.h | 0 slirp/{ => src}/ncsi-pkt.h | 0 slirp/{ => src}/ncsi.c | 0 slirp/{ => src}/ndp_table.c | 0 slirp/{ => src}/qtailq.h | 0 slirp/{ => src}/sbuf.c | 0 slirp/{ => src}/sbuf.h | 0 slirp/{ => src}/slirp.c | 0 slirp/{ => src}/slirp.h | 0 slirp/{ => src}/socket.c | 0 slirp/{ => src}/socket.h | 0 slirp/{ => src}/state.c | 0 slirp/{ => src}/state.h | 0 slirp/{ => src}/stream.c | 0 slirp/{ => src}/stream.h | 0 slirp/{ => src}/tcp.h | 0 slirp/{ => src}/tcp_input.c | 0 slirp/{ => src}/tcp_output.c | 0 slirp/{ => src}/tcp_subr.c | 0 slirp/{ => src}/tcp_timer.c | 0 slirp/{ => src}/tcp_timer.h | 0 slirp/{ => src}/tcp_var.h | 0 slirp/{ => src}/tcpip.h | 0 slirp/{ => src}/tftp.c | 0 slirp/{ => src}/tftp.h | 0 slirp/{ => src}/udp.c | 0 slirp/{ => src}/udp.h | 0 slirp/{ => src}/udp6.c | 0 slirp/{ => src}/util.c | 0 slirp/{ => src}/util.h | 0 slirp/{ => src}/vmstate.c | 0 slirp/{ => src}/vmstate.h | 0 util/main-loop.c | 2 -- vl.c | 3 -- 61 files changed, 31 insertions(+), 36 deletions(-) rename slirp/{ => src}/arp_table.c (100%) rename slirp/{ => src}/bootp.c (100%) rename slirp/{ => src}/bootp.h (100%) rename slirp/{ => src}/cksum.c (100%) rename slirp/{ => src}/debug.h (100%) rename slirp/{ => src}/dhcpv6.c (100%) rename slirp/{ => src}/dhcpv6.h (100%) rename slirp/{ => src}/dnssearch.c (100%) rename slirp/{ => src}/if.c (100%) rename slirp/{ => src}/if.h (100%) rename slirp/{ => src}/ip.h (100%) rename slirp/{ => src}/ip6.h (100%) rename slirp/{ => src}/ip6_icmp.c (100%) rename slirp/{ => src}/ip6_icmp.h (100%) rename slirp/{ => src}/ip6_input.c (100%) rename slirp/{ => src}/ip6_output.c (100%) rename slirp/{ => src}/ip_icmp.c (100%) rename slirp/{ => src}/ip_icmp.h (100%) rename slirp/{ => src}/ip_input.c (100%) rename slirp/{ => src}/ip_output.c (100%) rename slirp/{ => src}/libslirp.h (100%) rename slirp/{ => src}/main.h (100%) rename slirp/{ => src}/mbuf.c (100%) rename slirp/{ => src}/mbuf.h (100%) rename slirp/{ => src}/misc.c (100%) rename slirp/{ => src}/misc.h (100%) rename slirp/{ => src}/ncsi-pkt.h (100%) rename slirp/{ => src}/ncsi.c (100%) rename slirp/{ => src}/ndp_table.c (100%) rename slirp/{ => src}/qtailq.h (100%) rename slirp/{ => src}/sbuf.c (100%) rename slirp/{ => src}/sbuf.h (100%) rename slirp/{ => src}/slirp.c (100%) rename slirp/{ => src}/slirp.h (100%) rename slirp/{ => src}/socket.c (100%) rename slirp/{ => src}/socket.h (100%) rename slirp/{ => src}/state.c (100%) rename slirp/{ => src}/state.h (100%) rename slirp/{ => src}/stream.c (100%) rename slirp/{ => src}/stream.h (100%) rename slirp/{ => src}/tcp.h (100%) rename slirp/{ => src}/tcp_input.c (100%) rename slirp/{ => src}/tcp_output.c (100%) rename slirp/{ => src}/tcp_subr.c (100%) rename slirp/{ => src}/tcp_timer.c (100%) rename slirp/{ => src}/tcp_timer.h (100%) rename slirp/{ => src}/tcp_var.h (100%) rename slirp/{ => src}/tcpip.h (100%) rename slirp/{ => src}/tftp.c (100%) rename slirp/{ => src}/tftp.h (100%) rename slirp/{ => src}/udp.c (100%) rename slirp/{ => src}/udp.h (100%) rename slirp/{ => src}/udp6.c (100%) rename slirp/{ => src}/util.c (100%) rename slirp/{ => src}/util.h (100%) rename slirp/{ => src}/vmstate.c (100%) rename slirp/{ => src}/vmstate.h (100%) diff --git a/net/slirp.c b/net/slirp.c index 059b2d9b08..d2f2138bc5 100644 --- a/net/slirp.c +++ b/net/slirp.c @@ -37,7 +37,7 @@ #include "monitor/monitor.h" #include "qemu/error-report.h" #include "qemu/sockets.h" -#include "slirp/libslirp.h" +#include "slirp/src/libslirp.h" #include "chardev/char-fe.h" #include "sysemu/sysemu.h" #include "qemu/cutils.h" diff --git a/slirp/Makefile.objs b/slirp/Makefile.objs index e91daf0e91..0250229dfa 100644 --- a/slirp/Makefile.objs +++ b/slirp/Makefile.objs @@ -1,36 +1,36 @@ slirp-obj-y = slirp.mo slirp.mo-objs = \ - arp_table.o \ - bootp.o \ - cksum.o \ - dhcpv6.o \ - dnssearch.o \ - if.o \ - ip6_icmp.o \ - ip6_input.o \ - ip6_output.o \ - ip_icmp.o \ - ip_input.o \ - ip_output.o \ - mbuf.o \ - misc.o \ - ncsi.o \ - ndp_table.o \ - sbuf.o \ - slirp.o \ - socket.o \ - state.o \ - stream.o \ - tcp_input.o \ - tcp_output.o \ - tcp_subr.o \ - tcp_timer.o \ - tftp.o \ - udp.o \ - udp6.o \ - util.o \ - vmstate.o \ + src/arp_table.o \ + src/bootp.o \ + src/cksum.o \ + src/dhcpv6.o \ + src/dnssearch.o \ + src/if.o \ + src/ip6_icmp.o \ + src/ip6_input.o \ + src/ip6_output.o \ + src/ip_icmp.o \ + src/ip_input.o \ + src/ip_output.o \ + src/mbuf.o \ + src/misc.o \ + src/ncsi.o \ + src/ndp_table.o \ + src/sbuf.o \ + src/slirp.o \ + src/socket.o \ + src/state.o \ + src/stream.o \ + src/tcp_input.o \ + src/tcp_output.o \ + src/tcp_subr.o \ + src/tcp_timer.o \ + src/tftp.o \ + src/udp.o \ + src/udp6.o \ + src/util.o \ + src/vmstate.o \ $(NULL) slirp.mo-cflags = -DG_LOG_DOMAIN=\"Slirp\" diff --git a/slirp/arp_table.c b/slirp/src/arp_table.c similarity index 100% rename from slirp/arp_table.c rename to slirp/src/arp_table.c diff --git a/slirp/bootp.c b/slirp/src/bootp.c similarity index 100% rename from slirp/bootp.c rename to slirp/src/bootp.c diff --git a/slirp/bootp.h b/slirp/src/bootp.h similarity index 100% rename from slirp/bootp.h rename to slirp/src/bootp.h diff --git a/slirp/cksum.c b/slirp/src/cksum.c similarity index 100% rename from slirp/cksum.c rename to slirp/src/cksum.c diff --git a/slirp/debug.h b/slirp/src/debug.h similarity index 100% rename from slirp/debug.h rename to slirp/src/debug.h diff --git a/slirp/dhcpv6.c b/slirp/src/dhcpv6.c similarity index 100% rename from slirp/dhcpv6.c rename to slirp/src/dhcpv6.c diff --git a/slirp/dhcpv6.h b/slirp/src/dhcpv6.h similarity index 100% rename from slirp/dhcpv6.h rename to slirp/src/dhcpv6.h diff --git a/slirp/dnssearch.c b/slirp/src/dnssearch.c similarity index 100% rename from slirp/dnssearch.c rename to slirp/src/dnssearch.c diff --git a/slirp/if.c b/slirp/src/if.c similarity index 100% rename from slirp/if.c rename to slirp/src/if.c diff --git a/slirp/if.h b/slirp/src/if.h similarity index 100% rename from slirp/if.h rename to slirp/src/if.h diff --git a/slirp/ip.h b/slirp/src/ip.h similarity index 100% rename from slirp/ip.h rename to slirp/src/ip.h diff --git a/slirp/ip6.h b/slirp/src/ip6.h similarity index 100% rename from slirp/ip6.h rename to slirp/src/ip6.h diff --git a/slirp/ip6_icmp.c b/slirp/src/ip6_icmp.c similarity index 100% rename from slirp/ip6_icmp.c rename to slirp/src/ip6_icmp.c diff --git a/slirp/ip6_icmp.h b/slirp/src/ip6_icmp.h similarity index 100% rename from slirp/ip6_icmp.h rename to slirp/src/ip6_icmp.h diff --git a/slirp/ip6_input.c b/slirp/src/ip6_input.c similarity index 100% rename from slirp/ip6_input.c rename to slirp/src/ip6_input.c diff --git a/slirp/ip6_output.c b/slirp/src/ip6_output.c similarity index 100% rename from slirp/ip6_output.c rename to slirp/src/ip6_output.c diff --git a/slirp/ip_icmp.c b/slirp/src/ip_icmp.c similarity index 100% rename from slirp/ip_icmp.c rename to slirp/src/ip_icmp.c diff --git a/slirp/ip_icmp.h b/slirp/src/ip_icmp.h similarity index 100% rename from slirp/ip_icmp.h rename to slirp/src/ip_icmp.h diff --git a/slirp/ip_input.c b/slirp/src/ip_input.c similarity index 100% rename from slirp/ip_input.c rename to slirp/src/ip_input.c diff --git a/slirp/ip_output.c b/slirp/src/ip_output.c similarity index 100% rename from slirp/ip_output.c rename to slirp/src/ip_output.c diff --git a/slirp/libslirp.h b/slirp/src/libslirp.h similarity index 100% rename from slirp/libslirp.h rename to slirp/src/libslirp.h diff --git a/slirp/main.h b/slirp/src/main.h similarity index 100% rename from slirp/main.h rename to slirp/src/main.h diff --git a/slirp/mbuf.c b/slirp/src/mbuf.c similarity index 100% rename from slirp/mbuf.c rename to slirp/src/mbuf.c diff --git a/slirp/mbuf.h b/slirp/src/mbuf.h similarity index 100% rename from slirp/mbuf.h rename to slirp/src/mbuf.h diff --git a/slirp/misc.c b/slirp/src/misc.c similarity index 100% rename from slirp/misc.c rename to slirp/src/misc.c diff --git a/slirp/misc.h b/slirp/src/misc.h similarity index 100% rename from slirp/misc.h rename to slirp/src/misc.h diff --git a/slirp/ncsi-pkt.h b/slirp/src/ncsi-pkt.h similarity index 100% rename from slirp/ncsi-pkt.h rename to slirp/src/ncsi-pkt.h diff --git a/slirp/ncsi.c b/slirp/src/ncsi.c similarity index 100% rename from slirp/ncsi.c rename to slirp/src/ncsi.c diff --git a/slirp/ndp_table.c b/slirp/src/ndp_table.c similarity index 100% rename from slirp/ndp_table.c rename to slirp/src/ndp_table.c diff --git a/slirp/qtailq.h b/slirp/src/qtailq.h similarity index 100% rename from slirp/qtailq.h rename to slirp/src/qtailq.h diff --git a/slirp/sbuf.c b/slirp/src/sbuf.c similarity index 100% rename from slirp/sbuf.c rename to slirp/src/sbuf.c diff --git a/slirp/sbuf.h b/slirp/src/sbuf.h similarity index 100% rename from slirp/sbuf.h rename to slirp/src/sbuf.h diff --git a/slirp/slirp.c b/slirp/src/slirp.c similarity index 100% rename from slirp/slirp.c rename to slirp/src/slirp.c diff --git a/slirp/slirp.h b/slirp/src/slirp.h similarity index 100% rename from slirp/slirp.h rename to slirp/src/slirp.h diff --git a/slirp/socket.c b/slirp/src/socket.c similarity index 100% rename from slirp/socket.c rename to slirp/src/socket.c diff --git a/slirp/socket.h b/slirp/src/socket.h similarity index 100% rename from slirp/socket.h rename to slirp/src/socket.h diff --git a/slirp/state.c b/slirp/src/state.c similarity index 100% rename from slirp/state.c rename to slirp/src/state.c diff --git a/slirp/state.h b/slirp/src/state.h similarity index 100% rename from slirp/state.h rename to slirp/src/state.h diff --git a/slirp/stream.c b/slirp/src/stream.c similarity index 100% rename from slirp/stream.c rename to slirp/src/stream.c diff --git a/slirp/stream.h b/slirp/src/stream.h similarity index 100% rename from slirp/stream.h rename to slirp/src/stream.h diff --git a/slirp/tcp.h b/slirp/src/tcp.h similarity index 100% rename from slirp/tcp.h rename to slirp/src/tcp.h diff --git a/slirp/tcp_input.c b/slirp/src/tcp_input.c similarity index 100% rename from slirp/tcp_input.c rename to slirp/src/tcp_input.c diff --git a/slirp/tcp_output.c b/slirp/src/tcp_output.c similarity index 100% rename from slirp/tcp_output.c rename to slirp/src/tcp_output.c diff --git a/slirp/tcp_subr.c b/slirp/src/tcp_subr.c similarity index 100% rename from slirp/tcp_subr.c rename to slirp/src/tcp_subr.c diff --git a/slirp/tcp_timer.c b/slirp/src/tcp_timer.c similarity index 100% rename from slirp/tcp_timer.c rename to slirp/src/tcp_timer.c diff --git a/slirp/tcp_timer.h b/slirp/src/tcp_timer.h similarity index 100% rename from slirp/tcp_timer.h rename to slirp/src/tcp_timer.h diff --git a/slirp/tcp_var.h b/slirp/src/tcp_var.h similarity index 100% rename from slirp/tcp_var.h rename to slirp/src/tcp_var.h diff --git a/slirp/tcpip.h b/slirp/src/tcpip.h similarity index 100% rename from slirp/tcpip.h rename to slirp/src/tcpip.h diff --git a/slirp/tftp.c b/slirp/src/tftp.c similarity index 100% rename from slirp/tftp.c rename to slirp/src/tftp.c diff --git a/slirp/tftp.h b/slirp/src/tftp.h similarity index 100% rename from slirp/tftp.h rename to slirp/src/tftp.h diff --git a/slirp/udp.c b/slirp/src/udp.c similarity index 100% rename from slirp/udp.c rename to slirp/src/udp.c diff --git a/slirp/udp.h b/slirp/src/udp.h similarity index 100% rename from slirp/udp.h rename to slirp/src/udp.h diff --git a/slirp/udp6.c b/slirp/src/udp6.c similarity index 100% rename from slirp/udp6.c rename to slirp/src/udp6.c diff --git a/slirp/util.c b/slirp/src/util.c similarity index 100% rename from slirp/util.c rename to slirp/src/util.c diff --git a/slirp/util.h b/slirp/src/util.h similarity index 100% rename from slirp/util.h rename to slirp/src/util.h diff --git a/slirp/vmstate.c b/slirp/src/vmstate.c similarity index 100% rename from slirp/vmstate.c rename to slirp/src/vmstate.c diff --git a/slirp/vmstate.h b/slirp/src/vmstate.h similarity index 100% rename from slirp/vmstate.h rename to slirp/src/vmstate.h diff --git a/util/main-loop.c b/util/main-loop.c index d4a521caeb..e1e349ca5c 100644 --- a/util/main-loop.c +++ b/util/main-loop.c @@ -26,11 +26,9 @@ #include "qapi/error.h" #include "qemu/cutils.h" #include "qemu/timer.h" -#include "qemu/sockets.h" // struct in_addr needed for libslirp.h #include "sysemu/qtest.h" #include "sysemu/cpus.h" #include "sysemu/replay.h" -#include "slirp/libslirp.h" #include "qemu/main-loop.h" #include "block/aio.h" #include "qemu/error-report.h" diff --git a/vl.c b/vl.c index 4c5cc0d8ad..4a350de5cd 100644 --- a/vl.c +++ b/vl.c @@ -106,9 +106,6 @@ int main(int argc, char **argv) #include "disas/disas.h" - -#include "slirp/libslirp.h" - #include "trace-root.h" #include "trace/control.h" #include "qemu/queue.h" From 12f8beeb9f2b12b351ea096a296da543adc6954d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 12 Feb 2019 17:25:22 +0100 Subject: [PATCH 10/12] slirp: add a standalone Makefile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a simple Makefile to build libslirp.a, a static library version of libslirp, to be used by QEMU during a transition period, until a shared library is available. Signed-off-by: Marc-André Lureau Message-Id: <20190212162524.31504-6-marcandre.lureau@redhat.com> Signed-off-by: Samuel Thibault --- slirp/Makefile | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 slirp/Makefile diff --git a/slirp/Makefile b/slirp/Makefile new file mode 100644 index 0000000000..6d48f626ba --- /dev/null +++ b/slirp/Makefile @@ -0,0 +1,47 @@ +ROOT_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) +BUILD_DIR ?= . + +LIBSLIRP = $(BUILD_DIR)/libslirp.a + +all: $(LIBSLIRP) + +SRCS := $(wildcard src/*.c) +OBJS := $(SRCS:%.c=$(BUILD_DIR)/%.o) +DEPS := $(OBJS:%.o=%.d) + +INC_DIRS := $(BUILD_DIR)/src +INC_FLAGS := $(addprefix -I,$(INC_DIRS)) + +override CFLAGS += \ + -DG_LOG_DOMAIN='"Slirp"' \ + $(shell $(PKG_CONFIG) --cflags glib-2.0) \ + $(INC_FLAGS) \ + -MMD -MP +override LDFLAGS += $(shell $(PKG_CONFIG) --libs glib-2.0) + +$(LIBSLIRP): $(OBJS) + +.PHONY: clean + +clean: + rm -r $(OBJS) $(DEPS) $(LIBSLIRP) + +$(BUILD_DIR)/src/%.o: $(ROOT_DIR)/src/%.c + @$(MKDIR_P) $(dir $@) + $(call quiet-command,$(CC) $(CFLAGS) -c -o $@ $<,"CC","$@") + +%.a: + $(call quiet-command,rm -f $@ && $(AR) rcs $@ $^,"AR","$@") + +PKG_CONFIG ?= pkg-config +MKDIR_P ?= mkdir -p +quiet-command-run = $(if $(V),,$(if $2,printf " %-7s %s\n" $2 $3 && ))$1 +quiet-@ = $(if $(V),,@) +quiet-command = $(quiet-@)$(call quiet-command-run,$1,$2,$3) + +print-%: + @echo '$*=$($*)' + +.SUFFIXES: + +-include $(DEPS) From 675b9b536871aebcce3372923244d2b27b6e185f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 12 Feb 2019 17:25:23 +0100 Subject: [PATCH 11/12] build-sys: link with slirp as an external project MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the "system" libslirp if its present or requested. Else build with a static libslirp.a if slirp/ is checked out ("internal") or a submodule ("git"). Signed-off-by: Marc-André Lureau Message-Id: <20190212162524.31504-7-marcandre.lureau@redhat.com> Signed-off-by: Samuel Thibault --- Makefile | 8 +++--- Makefile.objs | 1 - Makefile.target | 5 +--- configure | 65 +++++++++++++++++++++++++++++++++++++++++++--- net/Makefile.objs | 2 ++ net/slirp.c | 2 +- util/Makefile.objs | 1 + 7 files changed, 72 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index 2208bde419..a99acda9d9 100644 --- a/Makefile +++ b/Makefile @@ -383,8 +383,7 @@ dummy := $(call unnest-vars,, \ ui-obj-m \ audio-obj-y \ audio-obj-m \ - trace-obj-y \ - slirp-obj-y) + trace-obj-y) include $(SRC_PATH)/tests/Makefile.include @@ -458,7 +457,10 @@ CAP_CFLAGS += -DCAPSTONE_HAS_X86 subdir-capstone: .git-submodule-status $(call quiet-command,$(MAKE) -C $(SRC_PATH)/capstone CAPSTONE_SHARED=no BUILDDIR="$(BUILD_DIR)/capstone" CC="$(CC)" AR="$(AR)" LD="$(LD)" RANLIB="$(RANLIB)" CFLAGS="$(CAP_CFLAGS)" $(SUBDIR_MAKEFLAGS) $(BUILD_DIR)/capstone/$(LIBCAPSTONE)) -$(SUBDIR_RULES): libqemuutil.a $(common-obj-y) $(chardev-obj-y) $(slirp-obj-y) \ +subdir-slirp: .git-submodule-status + $(call quiet-command,$(MAKE) -C $(SRC_PATH)/slirp BUILD_DIR="$(BUILD_DIR)/slirp" CC="$(CC)" AR="$(AR)" LD="$(LD)" RANLIB="$(RANLIB)" CFLAGS="$(QEMU_CFLAGS)") + +$(SUBDIR_RULES): libqemuutil.a $(common-obj-y) $(chardev-obj-y) \ $(qom-obj-y) $(crypto-aes-obj-$(CONFIG_USER_ONLY)) ROMSUBDIR_RULES=$(patsubst %,romsubdir-%, $(ROMS)) diff --git a/Makefile.objs b/Makefile.objs index 6e91ee5674..ef65a6c12e 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -4,7 +4,6 @@ stub-obj-y = stubs/ util/ crypto/ util-obj-y = util/ qobject/ qapi/ chardev-obj-y = chardev/ -slirp-obj-$(CONFIG_SLIRP) = slirp/ ####################################################################### # authz-obj-y is code used by both qemu system emulation and qemu-img diff --git a/Makefile.target b/Makefile.target index 3b79e7074c..bd773da756 100644 --- a/Makefile.target +++ b/Makefile.target @@ -174,7 +174,6 @@ target-obj-y := block-obj-y := common-obj-y := chardev-obj-y := -slirp-obj-y := include $(SRC_PATH)/Makefile.objs dummy := $(call unnest-vars,,target-obj-y) target-obj-y-save := $(target-obj-y) @@ -188,8 +187,7 @@ dummy := $(call unnest-vars,.., \ qom-obj-y \ io-obj-y \ common-obj-y \ - common-obj-m \ - slirp-obj-y) + common-obj-m) target-obj-y := $(target-obj-y-save) all-obj-y += $(common-obj-y) all-obj-y += $(target-obj-y) @@ -199,7 +197,6 @@ all-obj-$(CONFIG_SOFTMMU) += $(block-obj-y) $(chardev-obj-y) all-obj-$(CONFIG_USER_ONLY) += $(crypto-aes-obj-y) all-obj-$(CONFIG_SOFTMMU) += $(crypto-obj-y) all-obj-$(CONFIG_SOFTMMU) += $(io-obj-y) -all-obj-$(CONFIG_SOFTMMU) += $(slirp-obj-y) $(QEMU_PROG_BUILD): config-devices.mak diff --git a/configure b/configure index cefeb8fcce..ec43207c18 100755 --- a/configure +++ b/configure @@ -406,7 +406,7 @@ includedir="\${prefix}/include" sysconfdir="\${prefix}/etc" local_statedir="\${prefix}/var" confsuffix="/qemu" -slirp="yes" +slirp="" oss_lib="" bsd="no" linux="no" @@ -1105,6 +1105,10 @@ for opt do ;; --disable-slirp) slirp="no" ;; + --enable-slirp=git) slirp="git" + ;; + --enable-slirp=system) slirp="system" + ;; --disable-vde) vde="no" ;; --enable-vde) vde="yes" @@ -5754,6 +5758,55 @@ if test "$libpmem" != "no"; then fi fi +########################################## +# check for slirp + +case "$slirp" in + "" | yes) + if $pkg_config slirp; then + slirp=system + elif test -e "${source_path}/.git" && test $git_update = 'yes' ; then + slirp=git + elif test -e "${source_path}/slirp/Makefile" ; then + slirp=internal + elif test -z "$slirp" ; then + slirp=no + else + feature_not_found "slirp" "Install slirp devel or git submodule" + fi + ;; + + system) + if ! $pkg_config slirp; then + feature_not_found "slirp" "Install slirp devel" + fi + ;; +esac + +case "$slirp" in + git | internal) + if test "$slirp" = git; then + git_submodules="${git_submodules} slirp" + fi + mkdir -p slirp + slirp_cflags="-I\$(SRC_PATH)/slirp/src -I\$(BUILD_DIR)/slirp/src" + slirp_libs="-L\$(BUILD_DIR)/slirp -lslirp" + ;; + + system) + slirp_version=$($pkg_config --modversion slirp 2>/dev/null) + slirp_cflags=$($pkg_config --cflags slirp 2>/dev/null) + slirp_libs=$($pkg_config --libs slirp 2>/dev/null) + ;; + + no) + ;; + *) + error_exit "Unknown state for slirp: $slirp" + ;; +esac + + ########################################## # End of CC checks # After here, no more $cc or $ld runs @@ -6111,7 +6164,8 @@ echo "QEMU_LDFLAGS $QEMU_LDFLAGS" echo "make $make" echo "install $install" echo "python $python ($python_version)" -if test "$slirp" = "yes" ; then +echo "slirp support $slirp $(echo_version $slirp $slirp_version)" +if test "$slirp" != "no" ; then echo "smbd $smbd" fi echo "module support $modules" @@ -6372,9 +6426,14 @@ fi if test "$profiler" = "yes" ; then echo "CONFIG_PROFILER=y" >> $config_host_mak fi -if test "$slirp" = "yes" ; then +if test "$slirp" != "no"; then echo "CONFIG_SLIRP=y" >> $config_host_mak echo "CONFIG_SMBD_COMMAND=\"$smbd\"" >> $config_host_mak + echo "SLIRP_CFLAGS=$slirp_cflags" >> $config_host_mak + echo "SLIRP_LIBS=$slirp_libs" >> $config_host_mak +fi +if [ "$slirp" = "git" -o "$slirp" = "internal" ]; then + echo "config-host.h: subdir-slirp" >> $config_host_mak fi if test "$vde" = "yes" ; then echo "CONFIG_VDE=y" >> $config_host_mak diff --git a/net/Makefile.objs b/net/Makefile.objs index 8262f033b9..c5d076d19c 100644 --- a/net/Makefile.objs +++ b/net/Makefile.objs @@ -8,6 +8,8 @@ common-obj-$(call land,$(CONFIG_VIRTIO_NET),$(CONFIG_VHOST_NET_USER)) += vhost-u common-obj-$(call land,$(call lnot,$(CONFIG_VIRTIO_NET)),$(CONFIG_VHOST_NET_USER)) += vhost-user-stub.o common-obj-$(CONFIG_ALL) += vhost-user-stub.o common-obj-$(CONFIG_SLIRP) += slirp.o +slirp.o-cflags := $(SLIRP_CFLAGS) +slirp.o-libs := $(SLIRP_LIBS) common-obj-$(CONFIG_VDE) += vde.o common-obj-$(CONFIG_NETMAP) += netmap.o common-obj-y += filter.o diff --git a/net/slirp.c b/net/slirp.c index d2f2138bc5..95934fb36d 100644 --- a/net/slirp.c +++ b/net/slirp.c @@ -37,7 +37,7 @@ #include "monitor/monitor.h" #include "qemu/error-report.h" #include "qemu/sockets.h" -#include "slirp/src/libslirp.h" +#include #include "chardev/char-fe.h" #include "sysemu/sysemu.h" #include "qemu/cutils.h" diff --git a/util/Makefile.objs b/util/Makefile.objs index 0808575e3e..835fcd69e2 100644 --- a/util/Makefile.objs +++ b/util/Makefile.objs @@ -3,6 +3,7 @@ util-obj-y += bufferiszero.o util-obj-y += lockcnt.o util-obj-y += aiocb.o async.o aio-wait.o thread-pool.o qemu-timer.o util-obj-y += main-loop.o iohandler.o +main-loop.o-cflags := $(SLIRP_CFLAGS) util-obj-$(call lnot,$(CONFIG_ATOMIC64)) += atomic64.o util-obj-$(CONFIG_POSIX) += aio-posix.o util-obj-$(CONFIG_POSIX) += compatfd.o From be1911ff7504be95d5cf2c18bc99ce07246a91e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 12 Feb 2019 17:25:24 +0100 Subject: [PATCH 12/12] slirp: remove QEMU Makefile.objs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QEMU no longer includes it, and treats slirp/ as a separate project. Signed-off-by: Marc-André Lureau Message-Id: <20190212162524.31504-8-marcandre.lureau@redhat.com> Signed-off-by: Samuel Thibault --- slirp/Makefile.objs | 36 ------------------------------------ 1 file changed, 36 deletions(-) delete mode 100644 slirp/Makefile.objs diff --git a/slirp/Makefile.objs b/slirp/Makefile.objs deleted file mode 100644 index 0250229dfa..0000000000 --- a/slirp/Makefile.objs +++ /dev/null @@ -1,36 +0,0 @@ -slirp-obj-y = slirp.mo - -slirp.mo-objs = \ - src/arp_table.o \ - src/bootp.o \ - src/cksum.o \ - src/dhcpv6.o \ - src/dnssearch.o \ - src/if.o \ - src/ip6_icmp.o \ - src/ip6_input.o \ - src/ip6_output.o \ - src/ip_icmp.o \ - src/ip_input.o \ - src/ip_output.o \ - src/mbuf.o \ - src/misc.o \ - src/ncsi.o \ - src/ndp_table.o \ - src/sbuf.o \ - src/slirp.o \ - src/socket.o \ - src/state.o \ - src/stream.o \ - src/tcp_input.o \ - src/tcp_output.o \ - src/tcp_subr.o \ - src/tcp_timer.o \ - src/tftp.o \ - src/udp.o \ - src/udp6.o \ - src/util.o \ - src/vmstate.o \ - $(NULL) - -slirp.mo-cflags = -DG_LOG_DOMAIN=\"Slirp\"