Skip to content

Commit

Permalink
Merge remote-tracking branch 'remotes/thibault/tags/samuel-thibault' …
Browse files Browse the repository at this point in the history
…into staging

slirp: Adding IPv6 support to Qemu -net user mode

# gpg: Signature made Tue 15 Mar 2016 16:06:03 GMT using RSA key ID FB6B2F1D
# gpg: Good signature from "Samuel Thibault <samuel.thibault@gnu.org>"
# gpg:                 aka "Samuel Thibault <sthibault@debian.org>"
# gpg:                 aka "Samuel Thibault <samuel.thibault@inria.fr>"
# gpg:                 aka "Samuel Thibault <samuel.thibault@labri.fr>"
# gpg:                 aka "Samuel Thibault <samuel.thibault@ens-lyon.org>"
# gpg: WARNING: This key is not certified with sufficiently trusted signatures!
# gpg:          It is not certain that the signature belongs to the owner.
# Primary key fingerprint: 900C B024 B679 31D4 0F82  304B D017 8C76 7D06 9EE6
#      Subkey fingerprint: F632 74CD C630 0873 CB3D  29D9 E3E5 1CE8 FB6B 2F1D

* remotes/thibault/tags/samuel-thibault:
  slirp: Add IPv6 support to the TFTP code
  qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6 addresses
  slirp: Adding IPv6 address for DNS relay
  slirp: Handle IPv6 in TCP functions
  slirp: Reindent after refactoring
  slirp: Generalizing and neutralizing various TCP functions before adding IPv6 stuff
  slirp: Factorizing tcpiphdr structure with an union
  slirp: Adding IPv6 UDP support
  slirp: Adding ICMPv6 error sending
  slirp: Fix ICMP error sending
  slirp: Adding IPv6, ICMPv6 Echo and NDP autoconfiguration

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
  • Loading branch information
pm215 committed Mar 15, 2016
2 parents a58a4cb + fad7fb9 commit a6cdb77
Show file tree
Hide file tree
Showing 34 changed files with 1,958 additions and 224 deletions.
31 changes: 31 additions & 0 deletions net/net.c
Expand Up @@ -1050,6 +1050,37 @@ int net_client_init(QemuOpts *opts, int is_netdev, Error **errp)
OptsVisitor *ov = opts_visitor_new(opts);
Visitor *v = opts_get_visitor(ov);

{
/* Parse convenience option format ip6-net=fec0::0[/64] */
const char *ip6_net = qemu_opt_get(opts, "ip6-net");

if (ip6_net) {
char buf[strlen(ip6_net) + 1];

if (get_str_sep(buf, sizeof(buf), &ip6_net, '/') < 0) {
/* Default 64bit prefix length. */
qemu_opt_set(opts, "ip6-prefix", ip6_net, &error_abort);
qemu_opt_set_number(opts, "ip6-prefixlen", 64, &error_abort);
} else {
/* User-specified prefix length. */
unsigned long len;
int err;

qemu_opt_set(opts, "ip6-prefix", buf, &error_abort);
err = qemu_strtoul(ip6_net, NULL, 10, &len);

if (err) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
"ip6-prefix", "a number");
} else {
qemu_opt_set_number(opts, "ip6-prefixlen", len,
&error_abort);
}
}
qemu_opt_unset(opts, "ip6-net");
}
}

if (is_netdev) {
visit_type_Netdev(v, NULL, (Netdev **)&object, &err);
} else {
Expand Down
81 changes: 75 additions & 6 deletions net/slirp.c
Expand Up @@ -36,6 +36,7 @@
#include "qemu/error-report.h"
#include "qemu/sockets.h"
#include "slirp/libslirp.h"
#include "slirp/ip6.h"
#include "sysemu/char.h"

static int get_str_sep(char *buf, int buf_size, const char **pp, int sep)
Expand Down Expand Up @@ -135,17 +136,23 @@ static NetClientInfo net_slirp_info = {
static int net_slirp_init(NetClientState *peer, const char *model,
const char *name, int restricted,
const char *vnetwork, const char *vhost,
const char *vprefix6, int vprefix6_len,
const char *vhost6,
const char *vhostname, const char *tftp_export,
const char *bootfile, const char *vdhcp_start,
const char *vnameserver, const char *smb_export,
const char *vsmbserver, const char **dnssearch)
const char *vnameserver, const char *vnameserver6,
const char *smb_export, const char *vsmbserver,
const char **dnssearch)
{
/* default settings according to historic slirp */
struct in_addr net = { .s_addr = htonl(0x0a000200) }; /* 10.0.2.0 */
struct in_addr mask = { .s_addr = htonl(0xffffff00) }; /* 255.255.255.0 */
struct in_addr host = { .s_addr = htonl(0x0a000202) }; /* 10.0.2.2 */
struct in_addr dhcp = { .s_addr = htonl(0x0a00020f) }; /* 10.0.2.15 */
struct in_addr dns = { .s_addr = htonl(0x0a000203) }; /* 10.0.2.3 */
struct in6_addr ip6_prefix;
struct in6_addr ip6_host;
struct in6_addr ip6_dns;
#ifndef _WIN32
struct in_addr smbsrv = { .s_addr = 0 };
#endif
Expand Down Expand Up @@ -235,6 +242,64 @@ static int net_slirp_init(NetClientState *peer, const char *model,
}
#endif

#if defined(_WIN32) && (_WIN32_WINNT < 0x0600)
/* No inet_pton helper before Vista... */
if (vprefix6) {
/* Unsupported */
return -1;
}
memset(&ip6_prefix, 0, sizeof(ip6_prefix));
ip6_prefix.s6_addr[0] = 0xfe;
ip6_prefix.s6_addr[1] = 0xc0;
#else
if (!vprefix6) {
vprefix6 = "fec0::";
}
if (!inet_pton(AF_INET6, vprefix6, &ip6_prefix)) {
return -1;
}
#endif

if (!vprefix6_len) {
vprefix6_len = 64;
}
if (vprefix6_len < 0 || vprefix6_len > 126) {
return -1;
}

if (vhost6) {
#if defined(_WIN32) && (_WIN32_WINNT < 0x0600)
return -1;
#else
if (!inet_pton(AF_INET6, vhost6, &ip6_host)) {
return -1;
}
if (!in6_equal_net(&ip6_prefix, &ip6_host, vprefix6_len)) {
return -1;
}
#endif
} else {
ip6_host = ip6_prefix;
ip6_host.s6_addr[15] |= 2;
}

if (vnameserver6) {
#if defined(_WIN32) && (_WIN32_WINNT < 0x0600)
return -1;
#else
if (!inet_pton(AF_INET6, vnameserver6, &ip6_dns)) {
return -1;
}
if (!in6_equal_net(&ip6_prefix, &ip6_dns, vprefix6_len)) {
return -1;
}
#endif
} else {
ip6_dns = ip6_prefix;
ip6_dns.s6_addr[15] |= 3;
}


nc = qemu_new_net_client(&net_slirp_info, peer, model, name);

snprintf(nc->info_str, sizeof(nc->info_str),
Expand All @@ -243,8 +308,10 @@ static int net_slirp_init(NetClientState *peer, const char *model,

s = DO_UPCAST(SlirpState, nc, nc);

s->slirp = slirp_init(restricted, net, mask, host, vhostname,
tftp_export, bootfile, dhcp, dns, dnssearch, s);
s->slirp = slirp_init(restricted, net, mask, host,
ip6_prefix, vprefix6_len, ip6_host,
vhostname, tftp_export, bootfile, dhcp,
dns, ip6_dns, dnssearch, s);
QTAILQ_INSERT_TAIL(&slirp_stacks, s, entry);

for (config = slirp_configs; config; config = config->next) {
Expand Down Expand Up @@ -761,8 +828,10 @@ int net_init_slirp(const NetClientOptions *opts, const char *name,
net_init_slirp_configs(user->guestfwd, 0);

ret = net_slirp_init(peer, "user", name, user->q_restrict, vnet,
user->host, user->hostname, user->tftp,
user->bootfile, user->dhcpstart, user->dns, user->smb,
user->host, user->ip6_prefix, user->ip6_prefixlen,
user->ip6_host, user->hostname, user->tftp,
user->bootfile, user->dhcpstart,
user->dns, user->ip6_dns, user->smb,
user->smbserver, dnssearch);

while (slirp_configs) {
Expand Down
12 changes: 12 additions & 0 deletions qapi-schema.json
Expand Up @@ -2451,6 +2451,14 @@
# @dnssearch: #optional list of DNS suffixes to search, passed as DHCP option
# to the guest
#
# @ip6-prefix: #optional IPv6 network prefix (default is fec0::) (since 2.6)
#
# @ip6-prefixlen: #optional IPv6 network prefix length (default is 64) (since 2.6)
#
# @ip6-host: #optional guest-visible IPv6 address of the host (since 2.6)
#
# @ip6-dns: #optional guest-visible IPv6 address of the virtual nameserver (since 2.6)
#
# @smb: #optional root directory of the built-in SMB server
#
# @smbserver: #optional IP address of the built-in SMB server
Expand All @@ -2474,6 +2482,10 @@
'*dhcpstart': 'str',
'*dns': 'str',
'*dnssearch': ['String'],
'*ip6-prefix': 'str',
'*ip6-prefixlen': 'int',
'*ip6-host': 'str',
'*ip6-dns': 'str',
'*smb': 'str',
'*smbserver': 'str',
'*hostfwd': ['String'],
Expand Down
18 changes: 16 additions & 2 deletions qemu-options.hx
Expand Up @@ -1560,8 +1560,9 @@ DEF("smb", HAS_ARG, QEMU_OPTION_smb, "", QEMU_ARCH_ALL)

DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
#ifdef CONFIG_SLIRP
"-netdev user,id=str[,net=addr[/mask]][,host=addr][,restrict=on|off]\n"
" [,hostname=host][,dhcpstart=addr][,dns=addr][,dnssearch=domain][,tftp=dir]\n"
"-netdev user,id=str[,net=addr[/mask]][,host=addr][,ip6-net=addr[/int]]\n"
" [,ip6-host=addr][,restrict=on|off][,hostname=host][,dhcpstart=addr]\n"
" [,dns=addr][,ip6-dns=addr][,dnssearch=domain][,tftp=dir]\n"
" [,bootfile=f][,hostfwd=rule][,guestfwd=rule]"
#ifndef _WIN32
"[,smb=dir[,smbserver=addr]]\n"
Expand Down Expand Up @@ -1718,6 +1719,14 @@ either in the form a.b.c.d or as number of valid top-most bits. Default is
Specify the guest-visible address of the host. Default is the 2nd IP in the
guest network, i.e. x.x.x.2.

@item ip6-net=@var{addr}[/@var{int}]
Set IPv6 network address the guest will see. Optionally specify the prefix
size, as number of valid top-most bits. Default is fec0::/64.

@item ip6-host=@var{addr}
Specify the guest-visible IPv6 address of the host. Default is the 2nd IPv6 in
the guest network, i.e. xxxx::2.

@item restrict=on|off
If this option is enabled, the guest will be isolated, i.e. it will not be
able to contact the host and no guest IP packets will be routed over the host
Expand All @@ -1735,6 +1744,11 @@ Specify the guest-visible address of the virtual nameserver. The address must
be different from the host address. Default is the 3rd IP in the guest network,
i.e. x.x.x.3.

@item ip6-dns=@var{addr}
Specify the guest-visible address of the IPv6 virtual nameserver. The address
must be different from the host address. Default is the 3rd IP in the guest
network, i.e. xxxx::3.

@item dnssearch=@var{domain}
Provides an entry for the domain-search list sent by the built-in
DHCP server. More than one domain suffix can be transmitted by specifying
Expand Down
6 changes: 4 additions & 2 deletions slirp/Makefile.objs
@@ -1,3 +1,5 @@
common-obj-y = cksum.o if.o ip_icmp.o ip_input.o ip_output.o dnssearch.o
common-obj-y = cksum.o if.o ip_icmp.o ip6_icmp.o ip6_input.o ip6_output.o \
ip_input.o ip_output.o dnssearch.o
common-obj-y += slirp.o mbuf.o misc.o sbuf.o socket.o tcp_input.o tcp_output.o
common-obj-y += tcp_subr.o tcp_timer.o udp.o bootp.o tftp.o arp_table.o
common-obj-y += tcp_subr.o tcp_timer.o udp.o udp6.o bootp.o tftp.o arp_table.o \
ndp_table.o
25 changes: 25 additions & 0 deletions slirp/cksum.c
Expand Up @@ -138,3 +138,28 @@ int cksum(struct mbuf *m, int len)
REDUCE;
return (~sum & 0xffff);
}

int ip6_cksum(struct mbuf *m)
{
/* TODO: Optimize this by being able to pass the ip6_pseudohdr to cksum
* separately from the mbuf */
struct ip6 save_ip, *ip = mtod(m, struct ip6 *);
struct ip6_pseudohdr *ih = mtod(m, struct ip6_pseudohdr *);
int sum;

save_ip = *ip;

ih->ih_src = save_ip.ip_src;
ih->ih_dst = save_ip.ip_dst;
ih->ih_pl = htonl((uint32_t)ntohs(save_ip.ip_pl));
ih->ih_zero_hi = 0;
ih->ih_zero_lo = 0;
ih->ih_nh = save_ip.ip_nh;

sum = cksum(m, ((int)sizeof(struct ip6_pseudohdr))
+ ntohl(ih->ih_pl));

*ip = save_ip;

return sum;
}
2 changes: 1 addition & 1 deletion slirp/if.c
Expand Up @@ -194,7 +194,7 @@ void if_start(Slirp *slirp)

/* Try to send packet unless it already expired */
if (ifm->expiration_date >= now && !if_encap(slirp, ifm)) {
/* Packet is delayed due to pending ARP resolution */
/* Packet is delayed due to pending ARP or NDP resolution */
continue;
}

Expand Down
4 changes: 2 additions & 2 deletions slirp/if.h
Expand Up @@ -17,7 +17,7 @@
#define IF_MRU 1500
#define IF_COMP IF_AUTOCOMP /* Flags for compression */

/* 2 for alignment, 14 for ethernet, 40 for TCP/IP */
#define IF_MAXLINKHDR (2 + 14 + 40)
/* 2 for alignment, 14 for ethernet */
#define IF_MAXLINKHDR (2 + ETH_HLEN)

#endif

0 comments on commit a6cdb77

Please sign in to comment.