Re: [Qemu-devel] [PATCH RFC 4/4] net/slirp: add ipv6-hostfwd option for user netdev type

2018-10-30 Thread Maxim Samoylov




On 26.10.2018 09:14, Thomas Huth wrote:

On 2018-10-26 01:03, Maxim Samoylov wrote:

This allows forwarding TCP6 and UDP6 connections down to
netdev=user connected guests.

Signed-off-by: Maxim Samoylov 
---
  hmp-commands.hx |  31 
  include/net/slirp.h |   2 +
  net/slirp.c | 214 
  qapi/net.json   |   3 +-
  4 files changed, 249 insertions(+), 1 deletion(-)

diff --git a/hmp-commands.hx b/hmp-commands.hx
index db0c681..b0e1a08 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1448,6 +1448,37 @@ STEXI
  Remove host-to-guest TCP or UDP redirection.
  ETEXI
  
+#ifdef CONFIG_SLIRP

+{
+.name   = "ipv6_hostfwd_add",
+.args_type  = "arg1:s,arg2:s?,arg3:s?",
+.params = "[hub_id name]|[netdev_id] 
[tcp|udp]:[hostaddr6]:hostport-guestaddr6:guestport",
+.help   = "redirect TCP6 or UDP6 connections from host to guest 
(requires -net user)",
+.cmd= hmp_ipv6_hostfwd_add,
+},
+#endif
+STEXI
+@item hostfwd_add
+@findex hostfwd_add
+Redirect TCP6 or UDP6 connections from host to guest (requires -net user).
+ETEXI
+
+#ifdef CONFIG_SLIRP
+{
+.name   = "ipv6_hostfwd_remove",
+.args_type  = "arg1:s,arg2:s?,arg3:s?",
+.params = "[hub_id name]|[netdev_id] 
[tcp|udp]:[hostaddr6]:hostport",
+.help   = "remove host-to-guest TCP6 or UDP6 redirection",
+.cmd= hmp_ipv6_hostfwd_remove,
+},


  Hi,

could you please remove the "[hub_id name]" touple here? I recently sent
a patch to deprecate it for the IPv4 version, too:

https://lists.gnu.org/archive/html/qemu-devel/2018-09/msg03198.html



Ok


Also I think it would make sense if you mention in the help text that
IPv6 addresses have to be given with square brackets?

  Thanks,
   Thomas



Sure, missed that thing.

---
Maxim Samoylov, max7...@yandex-team.ru



Re: [Qemu-devel] [PATCH RFC 1/4] slirp: add helper for tcp6 socket creation

2018-10-30 Thread Maxim Samoylov




On 27.10.2018 14:11, Samuel Thibault wrote:

Hello,

Thanks for working on this!



Hi!

I preferred to make this RFC simple and straightforward
with dumb code duplication because I wasn't sure if the feature is
useful for upstream at all :)

I will then unify v4 and v6 implementations as you suggested
(for other patches in the series too) and post the re-spin.


There is a lot of overlap with tcp_listen. It'd be much better to
refactor it this way:

struct socket *
tcpx_listen(Slirp *slirp, struct sockaddr *addr, socklen_t *addrlen, int flags)
{
... The current content of tcp_listen, with all heading and
trailing addr manipulations removed...

... so->so_lfamily = addr->sa_family;...
... s = qemu_socket(addr->sa_family, SOCK_STREAM, 0);...
 ... (bind(s, addr, *addrlen) < 0) ||...
... getsockname(s, addr, addrlen);
}

struct socket *
tcp_listen(Slirp *slirp, uint32_t haddr, u_int hport, uint32_t laddr,
u_int lport, int flags)
{
struct sockaddr_in addr;
struct socket *so;
socklen_t addrsize = sizeof(addr);

addr.sin_family = AF_INET;
addr.sin_addr.s_addr = haddr;
addr.sin_port = hport;

so = tcpx_listen(slirp, (struct sockaddr *) , , flags);

so->so_lport = lport; /* Kept in network format */
so->so_laddr.s_addr = laddr; /* Ditto */

so->so_ffamily = AF_INET;
so->so_fport = addr.sin_port;
if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == 
loopback_addr.s_addr)
   so->so_faddr = slirp->vhost_addr;
else
   so->so_faddr = addr.sin_addr;
}

The v6 version then boils down to

struct socket *
tcp6_listen(Slirp *slirp, struct in6_addr haddr, u_int hport, struct
in6_addr laddr, u_int lport, int flags)
{
struct sockaddr_in6 addr;
struct socket *so;
socklen_t addrsize = sizeof(addr);

addr.sin6_family = AF_INET6;
addr.sin6_addr = haddr;
addr.sin6_port = hport;

so = tcpx_listen(slirp, (struct sockaddr *) , , flags);

so->so_lport6 = lport; /* Kept in network format */
so->so_laddr6 = laddr; /* Ditto */

so->fhost.sin6 = addr;

if (!memcmp(_addr, _any, sizeof(in6addr_any)) ||
!memcmp(_addr, _loopback,
sizeof(in6addr_loopback))) {

memcpy(>so_faddr6, >vhost_addr6, 
sizeof(slirp->vhost_addr6));
    }
}

modulo all typos etc. I may have done.

Maxim Samoylov, le ven. 26 oct. 2018 03:03:40 +0300, a ecrit:

+qemu_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, , sizeof(int));


Is there a reason why you set SO_OOBINLINE, but not TCP_NODELAY? That's
the kind of discrepancy we don't want to let unseen, thus the reason for
a shared implementation :)


Actually my code was initially based on the last year master state, so I
missed your changes on TCP_NODELAY while rebasing, will fix.



Samuel



---
Maxim Samoylov, max7...@yandex-team.ru



[Qemu-devel] [PATCH RFC 4/4] net/slirp: add ipv6-hostfwd option for user netdev type

2018-10-25 Thread Maxim Samoylov
This allows forwarding TCP6 and UDP6 connections down to
netdev=user connected guests.

Signed-off-by: Maxim Samoylov 
---
 hmp-commands.hx |  31 
 include/net/slirp.h |   2 +
 net/slirp.c | 214 
 qapi/net.json   |   3 +-
 4 files changed, 249 insertions(+), 1 deletion(-)

diff --git a/hmp-commands.hx b/hmp-commands.hx
index db0c681..b0e1a08 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1448,6 +1448,37 @@ STEXI
 Remove host-to-guest TCP or UDP redirection.
 ETEXI
 
+#ifdef CONFIG_SLIRP
+{
+.name   = "ipv6_hostfwd_add",
+.args_type  = "arg1:s,arg2:s?,arg3:s?",
+.params = "[hub_id name]|[netdev_id] 
[tcp|udp]:[hostaddr6]:hostport-guestaddr6:guestport",
+.help   = "redirect TCP6 or UDP6 connections from host to guest 
(requires -net user)",
+.cmd= hmp_ipv6_hostfwd_add,
+},
+#endif
+STEXI
+@item hostfwd_add
+@findex hostfwd_add
+Redirect TCP6 or UDP6 connections from host to guest (requires -net user).
+ETEXI
+
+#ifdef CONFIG_SLIRP
+{
+.name   = "ipv6_hostfwd_remove",
+.args_type  = "arg1:s,arg2:s?,arg3:s?",
+.params = "[hub_id name]|[netdev_id] 
[tcp|udp]:[hostaddr6]:hostport",
+.help   = "remove host-to-guest TCP6 or UDP6 redirection",
+.cmd= hmp_ipv6_hostfwd_remove,
+},
+
+#endif
+STEXI
+@item hostfwd_remove
+@findex hostfwd_remove
+Remove host-to-guest TCP6 or UDP6 redirection.
+ETEXI
+
 {
 .name   = "balloon",
 .args_type  = "value:M",
diff --git a/include/net/slirp.h b/include/net/slirp.h
index bad3e1e..4796a5c 100644
--- a/include/net/slirp.h
+++ b/include/net/slirp.h
@@ -29,6 +29,8 @@
 
 void hmp_hostfwd_add(Monitor *mon, const QDict *qdict);
 void hmp_hostfwd_remove(Monitor *mon, const QDict *qdict);
+void hmp_ipv6_hostfwd_add(Monitor *mon, const QDict *qdict);
+void hmp_ipv6_hostfwd_remove(Monitor *mon, const QDict *qdict);
 
 void hmp_info_usernet(Monitor *mon, const QDict *qdict);
 
diff --git a/net/slirp.c b/net/slirp.c
index f6dc039..abe112b 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -67,6 +67,7 @@ static int get_str_sep(char *buf, int buf_size, const char 
**pp, int sep)
 /* slirp network adapter */
 
 #define SLIRP_CFG_HOSTFWD 1
+#define SLIRP_CFG_IPV6_HOSTFWD 2
 
 struct slirp_config_str {
 struct slirp_config_str *next;
@@ -89,6 +90,8 @@ static QTAILQ_HEAD(slirp_stacks, SlirpState) slirp_stacks =
 QTAILQ_HEAD_INITIALIZER(slirp_stacks);
 
 static int slirp_hostfwd(SlirpState *s, const char *redir_str, Error **errp);
+static int slirp_ipv6_hostfwd(SlirpState *s, const char *redir_str,
+  Error **errp);
 static int slirp_guestfwd(SlirpState *s, const char *config_str, Error **errp);
 
 #ifndef _WIN32
@@ -386,6 +389,10 @@ static int net_slirp_init(NetClientState *peer, const char 
*model,
 if (slirp_hostfwd(s, config->str, errp) < 0) {
 goto error;
 }
+} else if (config->flags & SLIRP_CFG_IPV6_HOSTFWD) {
+if (slirp_ipv6_hostfwd(s, config->str, errp) < 0) {
+goto error;
+}
 } else {
 if (slirp_guestfwd(s, config->str, errp) < 0) {
 goto error;
@@ -504,6 +511,73 @@ void hmp_hostfwd_remove(Monitor *mon, const QDict *qdict)
 monitor_printf(mon, "invalid format\n");
 }
 
+void hmp_ipv6_hostfwd_remove(Monitor *mon, const QDict *qdict)
+{
+struct in6_addr host_addr = in6addr_any;
+int host_port;
+char buf[256];
+const char *src_str, *p;
+SlirpState *s;
+int is_udp = 0;
+int err;
+const char *arg1 = qdict_get_str(qdict, "arg1");
+const char *arg2 = qdict_get_try_str(qdict, "arg2");
+const char *arg3 = qdict_get_try_str(qdict, "arg3");
+
+if (arg2) {
+s = slirp_lookup(mon, arg1, arg2);
+src_str = arg3;
+} else {
+s = slirp_lookup(mon, NULL, NULL);
+src_str = arg1;
+}
+if (!s) {
+return;
+}
+
+p = src_str;
+if (!p || get_str_sep(buf, sizeof(buf), , ':') < 0) {
+goto fail_syntax;
+}
+
+if (!strcmp(buf, "tcp") || buf[0] == '\0') {
+is_udp = 0;
+} else if (!strcmp(buf, "udp")) {
+is_udp = 1;
+} else {
+goto fail_syntax;
+}
+
+if (*(p++) != '[') {
+goto fail_syntax;
+}
+
+if (get_str_sep(buf, sizeof(buf), , ']') < 0) {
+goto fail_syntax;
+}
+
+if (!inet_pton(AF_INET6, buf, _addr)) {
+goto fail_syntax;
+}
+
+if (get_str_sep(buf, sizeof(buf), , ':') < 0) {
+goto fail_syntax;
+}
+
+if (qemu_strtoi(p, NULL, 10, _port) < 0) {
+goto fail_syntax;
+}
+
+err = slirp

[Qemu-devel] [PATCH RFC 3/4] slirp: add helpers for ipv6 hostfwd manipulation

2018-10-25 Thread Maxim Samoylov
Signed-off-by: Maxim Samoylov 
---
 slirp/libslirp.h |  6 ++
 slirp/slirp.c| 43 +++
 2 files changed, 49 insertions(+)

diff --git a/slirp/libslirp.h b/slirp/libslirp.h
index 42e42e9..3710650 100644
--- a/slirp/libslirp.h
+++ b/slirp/libslirp.h
@@ -34,6 +34,12 @@ int slirp_add_hostfwd(Slirp *slirp, int is_udp,
   struct in_addr guest_addr, int guest_port);
 int slirp_remove_hostfwd(Slirp *slirp, int is_udp,
  struct in_addr host_addr, int host_port);
+int slirp_add_ipv6_hostfwd(Slirp *slirp, int is_udp,
+   struct in6_addr host_addr, int host_port,
+   struct in6_addr guest_addr, int guest_port);
+int slirp_remove_ipv6_hostfwd(Slirp *slirp, int is_udp,
+  struct in6_addr host_addr, int host_port);
+
 int slirp_add_exec(Slirp *slirp, int do_pty, const void *args,
struct in_addr *guest_addr, int guest_port);
 
diff --git a/slirp/slirp.c b/slirp/slirp.c
index 51de41f..143ddea 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -1065,6 +1065,49 @@ int slirp_add_hostfwd(Slirp *slirp, int is_udp, struct 
in_addr host_addr,
 return 0;
 }
 
+int slirp_remove_ipv6_hostfwd(Slirp *slirp, int is_udp,
+  struct in6_addr host_addr, int host_port)
+{
+struct socket *so;
+struct socket *head = (is_udp ? >udb : >tcb);
+struct sockaddr_in6 addr;
+int port = htons(host_port);
+socklen_t addr_len;
+
+for (so = head->so_next; so != head; so = so->so_next) {
+addr_len = sizeof(addr);
+if ((so->so_state & SS_HOSTFWD) &&
+getsockname(so->s, (struct sockaddr *), _len) == 0 &&
+addr_len == sizeof(host_addr) &&
+!memcmp(_addr, , addr_len) &&
+addr.sin6_port == port) {
+
+close(so->s);
+sofree(so);
+return 0;
+}
+}
+
+return -1;
+}
+
+int slirp_add_ipv6_hostfwd(Slirp *slirp, int is_udp,
+  struct in6_addr host_addr, int host_port,
+  struct in6_addr guest_addr, int guest_port)
+{
+if (is_udp) {
+if (!udp6_listen(slirp, host_addr, htons(host_port),
+ guest_addr, htons(guest_port), SS_HOSTFWD))
+return -1;
+} else {
+if (!tcp6_listen(slirp, host_addr, htons(host_port),
+ guest_addr, htons(guest_port), SS_HOSTFWD))
+return -1;
+}
+
+return 0;
+}
+
 int slirp_add_exec(Slirp *slirp, int do_pty, const void *args,
struct in_addr *guest_addr, int guest_port)
 {
-- 
2.7.4




[Qemu-devel] [PATCH RFC 2/4] slirp: add helper for udp6 socket creation

2018-10-25 Thread Maxim Samoylov
Signed-off-by: Maxim Samoylov 
---
 slirp/udp.c | 48 
 slirp/udp.h |  2 ++
 2 files changed, 50 insertions(+)

diff --git a/slirp/udp.c b/slirp/udp.c
index e5bf065..ab24935 100644
--- a/slirp/udp.c
+++ b/slirp/udp.c
@@ -366,3 +366,51 @@ udp_listen(Slirp *slirp, uint32_t haddr, u_int hport, 
uint32_t laddr,
 
return so;
 }
+
+struct socket *
+udp6_listen(Slirp *slirp, struct in6_addr haddr, u_int hport,
+struct in6_addr laddr, u_int lport, int flags)
+{
+struct sockaddr_in6 addr;
+struct socket *so;
+socklen_t addrlen = sizeof(addr);
+
+memset(, 0, sizeof(addr));
+
+so = socreate(slirp);
+if (!so) {
+return NULL;
+}
+so->s = qemu_socket(AF_INET6, SOCK_DGRAM, 0);
+if (so->s < 0) {
+sofree(so);
+return NULL;
+}
+so->so_expire = curtime + SO_EXPIRE;
+insque(so, >udb);
+
+addr.sin6_family = AF_INET6;
+addr.sin6_addr = haddr;
+addr.sin6_port = hport;
+
+if (bind(so->s, (struct sockaddr *), addrlen) < 0) {
+udp_detach(so);
+return NULL;
+}
+socket_set_fast_reuse(so->s);
+
+getsockname(so->s, (struct sockaddr *), );
+so->fhost.sin6 = addr;
+sotranslate_accept(so);
+so->so_lfamily = AF_INET6;
+so->so_lport = lport;
+so->so_laddr6 = laddr;
+if (flags != SS_FACCEPTONCE) {
+so->so_expire = 0;
+}
+
+so->so_state &= SS_PERSISTENT_MASK;
+so->so_state |= SS_ISFCONNECTED | flags;
+
+return so;
+}
diff --git a/slirp/udp.h b/slirp/udp.h
index be657cf..862c6e8 100644
--- a/slirp/udp.h
+++ b/slirp/udp.h
@@ -80,6 +80,8 @@ int udp_attach(struct socket *, unsigned short af);
 void udp_detach(struct socket *);
 struct socket * udp_listen(Slirp *, uint32_t, u_int, uint32_t, u_int,
int);
+struct socket *udp6_listen(Slirp *slirp, struct in6_addr, u_int,
+struct in6_addr, u_int, int);
 int udp_output(struct socket *so, struct mbuf *m,
 struct sockaddr_in *saddr, struct sockaddr_in *daddr,
 int iptos);
-- 
2.7.4




[Qemu-devel] [PATCH RFC 1/4] slirp: add helper for tcp6 socket creation

2018-10-25 Thread Maxim Samoylov
Signed-off-by: Maxim Samoylov 
---
 slirp/socket.c | 73 ++
 slirp/socket.h |  2 ++
 2 files changed, 75 insertions(+)

diff --git a/slirp/socket.c b/slirp/socket.c
index 322383a..e16e6c1 100644
--- a/slirp/socket.c
+++ b/slirp/socket.c
@@ -776,6 +776,79 @@ tcp_listen(Slirp *slirp, uint32_t haddr, u_int hport, 
uint32_t laddr,
return so;
 }
 
+struct socket *
+tcp6_listen(Slirp *slirp, struct in6_addr haddr, u_int hport,
+struct in6_addr laddr, u_int lport, int flags)
+{
+struct sockaddr_in6 addr;
+struct socket *so;
+int s, opt = 1;
+socklen_t addrlen = sizeof(addr);
+memset(, 0, addrlen);
+
+/* The same flow as in tcp_listen above */
+
+so = socreate(slirp);
+if (!so) {
+return NULL;
+}
+
+so->so_tcpcb = tcp_newtcpcb(so);
+if (so->so_tcpcb == NULL) {
+free(so);
+return NULL;
+}
+
+insque(so, >tcb);
+
+if (flags & SS_FACCEPTONCE) {
+so->so_tcpcb->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT * 2;
+}
+
+so->so_state &= SS_PERSISTENT_MASK;
+so->so_state |= (SS_FACCEPTCONN | flags);
+so->so_lfamily = AF_INET6;
+so->so_lport6 = lport; /* Kept in network format */
+so->so_laddr6 = laddr;
+
+addr.sin6_family = AF_INET6;
+addr.sin6_addr = haddr;
+addr.sin6_port = hport;
+
+s = qemu_socket(AF_INET6, SOCK_STREAM, 0);
+if ((s < 0) ||
+(socket_set_fast_reuse(s) < 0) ||
+(bind(s, (struct sockaddr *), sizeof(addr)) < 0) ||
+(listen(s, 1) < 0)) {
+int tmperrno = errno; /* Don't clobber the real reason we failed */
+if (s >= 0) {
+closesocket(s);
+}
+sofree(so);
+/* Restore the real errno */
+#ifdef _WIN32
+WSASetLastError(tmperrno);
+#else
+errno = tmperrno;
+#endif
+return NULL;
+}
+qemu_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, , sizeof(int));
+
+getsockname(s, (struct sockaddr *), );
+so->fhost.sin6 = addr;
+
+if (!memcmp(_addr, _any, sizeof(in6addr_any)) ||
+!memcmp(_addr, _loopback,
+sizeof(in6addr_loopback))) {
+
+memcpy(>so_faddr6, >vhost_addr6, 
sizeof(slirp->vhost_addr6));
+}
+
+so->s = s;
+return so;
+}
+
 /*
  * Various session state calls
  * XXX Should be #define's
diff --git a/slirp/socket.h b/slirp/socket.h
index 2f224bc..b200bb6 100644
--- a/slirp/socket.h
+++ b/slirp/socket.h
@@ -144,6 +144,8 @@ void sorecvfrom(struct socket *);
 int sosendto(struct socket *, struct mbuf *);
 struct socket * tcp_listen(Slirp *, uint32_t, u_int, uint32_t, u_int,
int);
+struct socket *tcp6_listen(Slirp *, struct in6_addr, u_int,
+   struct in6_addr, u_int, int);
 void soisfconnecting(register struct socket *);
 void soisfconnected(register struct socket *);
 void sofwdrain(struct socket *);
-- 
2.7.4




[Qemu-devel] [PATCH RFC 0/4] slirp: support hostfwd for ipv6 addresses

2018-10-25 Thread Maxim Samoylov
The following patch implements ipv6 host port forwarding support
for qemu slirp net subsystem.

The slirp itself supports ipv6 communication, but
hostfwd currently does not allow listening on and forwarding
ports for ipv6 addresses.

This should be useful, when host works in v6-capable environment
and guests should be accessible there.

Turns out the only thing should be done is to properly parse 
ipv6 addresses and pass them down to listening socket create logic.

The proposed option ipv6-hostfwd syntax is the same as for the hostfwd option,
but one should enclose their ipv6 addresses into square brackets, e.g.:

ipv6-hostfwd=tcp::7255-[fec0::5054:ff:fe12:3456]:80

The guest ipv6 address intended to be specified explicitly,
because there is no dhcpv6 server in slirp.


Maxim Samoylov (4):
  slirp: add helper for tcp6 socket creation
  slirp: add helper for udp6 socket creation
  slirp: add helpers for ipv6 hostfwd manipulation
  net/slirp: add ipv6-hostfwd option for user netdev type

 hmp-commands.hx |  31 
 include/net/slirp.h |   2 +
 net/slirp.c | 214 
 qapi/net.json   |   3 +-
 slirp/libslirp.h|   6 ++
 slirp/slirp.c   |  43 +++
 slirp/socket.c  |  73 ++
 slirp/socket.h  |   2 +
 slirp/udp.c |  48 
 slirp/udp.h |   2 +
 10 files changed, 423 insertions(+), 1 deletion(-)

-- 
2.7.4