slirp: Allow disabling IPv4 or IPv6

Add ipv4 and ipv6 boolean options, so the user can setup IPv4-only and
IPv6-only network environments.

Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
Reviewed-by: Thomas Huth <thuth@redhat.com>
This commit is contained in:
Samuel Thibault 2016-03-20 12:29:54 +01:00
parent de1d099a44
commit 0b11c03662
9 changed files with 74 additions and 10 deletions

View File

@ -136,8 +136,8 @@ static NetClientInfo net_slirp_info = {
static int net_slirp_init(NetClientState *peer, const char *model, static int net_slirp_init(NetClientState *peer, const char *model,
const char *name, int restricted, const char *name, int restricted,
const char *vnetwork, const char *vhost, bool ipv4, const char *vnetwork, const char *vhost,
const char *vprefix6, int vprefix6_len, bool ipv6, const char *vprefix6, int vprefix6_len,
const char *vhost6, const char *vhost6,
const char *vhostname, const char *tftp_export, const char *vhostname, const char *tftp_export,
const char *bootfile, const char *vdhcp_start, const char *bootfile, const char *vdhcp_start,
@ -165,6 +165,19 @@ static int net_slirp_init(NetClientState *peer, const char *model,
char *end; char *end;
struct slirp_config_str *config; struct slirp_config_str *config;
if (!ipv4 && (vnetwork || vhost || vnameserver)) {
return -1;
}
if (!ipv6 && (vprefix6 || vhost6 || vnameserver6)) {
return -1;
}
if (!ipv4 && !ipv6) {
/* It doesn't make sense to disable both */
return -1;
}
if (!tftp_export) { if (!tftp_export) {
tftp_export = legacy_tftp_prefix; tftp_export = legacy_tftp_prefix;
} }
@ -309,8 +322,8 @@ static int net_slirp_init(NetClientState *peer, const char *model,
s = DO_UPCAST(SlirpState, nc, nc); s = DO_UPCAST(SlirpState, nc, nc);
s->slirp = slirp_init(restricted, net, mask, host, s->slirp = slirp_init(restricted, ipv4, net, mask, host,
ip6_prefix, vprefix6_len, ip6_host, ipv6, ip6_prefix, vprefix6_len, ip6_host,
vhostname, tftp_export, bootfile, dhcp, vhostname, tftp_export, bootfile, dhcp,
dns, ip6_dns, dnssearch, s); dns, ip6_dns, dnssearch, s);
QTAILQ_INSERT_TAIL(&slirp_stacks, s, entry); QTAILQ_INSERT_TAIL(&slirp_stacks, s, entry);
@ -813,10 +826,20 @@ int net_init_slirp(const NetClientOptions *opts, const char *name,
int ret; int ret;
const NetdevUserOptions *user; const NetdevUserOptions *user;
const char **dnssearch; const char **dnssearch;
bool ipv4 = true, ipv6 = true;
assert(opts->type == NET_CLIENT_OPTIONS_KIND_USER); assert(opts->type == NET_CLIENT_OPTIONS_KIND_USER);
user = opts->u.user.data; user = opts->u.user.data;
if ((user->has_ipv6 && user->ipv6 && !user->has_ipv4) ||
(user->has_ipv4 && !user->ipv4)) {
ipv4 = 0;
}
if ((user->has_ipv4 && user->ipv4 && !user->has_ipv6) ||
(user->has_ipv6 && !user->ipv6)) {
ipv6 = 0;
}
vnet = user->has_net ? g_strdup(user->net) : vnet = user->has_net ? g_strdup(user->net) :
user->has_ip ? g_strdup_printf("%s/24", user->ip) : user->has_ip ? g_strdup_printf("%s/24", user->ip) :
NULL; NULL;
@ -828,8 +851,9 @@ int net_init_slirp(const NetClientOptions *opts, const char *name,
net_init_slirp_configs(user->hostfwd, SLIRP_CFG_HOSTFWD); net_init_slirp_configs(user->hostfwd, SLIRP_CFG_HOSTFWD);
net_init_slirp_configs(user->guestfwd, 0); net_init_slirp_configs(user->guestfwd, 0);
ret = net_slirp_init(peer, "user", name, user->q_restrict, vnet, ret = net_slirp_init(peer, "user", name, user->q_restrict,
user->host, user->ipv6_prefix, user->ipv6_prefixlen, ipv4, vnet, user->host,
ipv6, user->ipv6_prefix, user->ipv6_prefixlen,
user->ipv6_host, user->hostname, user->tftp, user->ipv6_host, user->hostname, user->tftp,
user->bootfile, user->dhcpstart, user->bootfile, user->dhcpstart,
user->dns, user->ipv6_dns, user->smb, user->dns, user->ipv6_dns, user->smb,

View File

@ -2425,6 +2425,12 @@
# #
# @restrict: #optional isolate the guest from the host # @restrict: #optional isolate the guest from the host
# #
# @ipv4: #optional whether to support IPv4, default true for enabled
# (since 2.6)
#
# @ipv6: #optional whether to support IPv6, default true for enabled
# (since 2.6)
#
# @ip: #optional legacy parameter, use net= instead # @ip: #optional legacy parameter, use net= instead
# #
# @net: #optional IP network address that the guest will see, in the # @net: #optional IP network address that the guest will see, in the
@ -2473,6 +2479,8 @@
'data': { 'data': {
'*hostname': 'str', '*hostname': 'str',
'*restrict': 'bool', '*restrict': 'bool',
'*ipv4': 'bool',
'*ipv6': 'bool',
'*ip': 'str', '*ip': 'str',
'*net': 'str', '*net': 'str',
'*host': 'str', '*host': 'str',

View File

@ -1551,8 +1551,9 @@ DEF("smb", HAS_ARG, QEMU_OPTION_smb, "", QEMU_ARCH_ALL)
DEF("netdev", HAS_ARG, QEMU_OPTION_netdev, DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
#ifdef CONFIG_SLIRP #ifdef CONFIG_SLIRP
"-netdev user,id=str[,net=addr[/mask]][,host=addr][,ipv6-net=addr[/int]]\n" "-netdev user,id=str[,ipv4[=on|off]][,net=addr[/mask]][,host=addr]\n"
" [,ipv6-host=addr][,restrict=on|off][,hostname=host][,dhcpstart=addr]\n" " [,ipv6[=on|off]][,ipv6-net=addr[/int]][,ipv6-host=addr]\n"
" [,restrict=on|off][,hostname=host][,dhcpstart=addr]\n"
" [,dns=addr][,ipv6-dns=addr][,dnssearch=domain][,tftp=dir]\n" " [,dns=addr][,ipv6-dns=addr][,dnssearch=domain][,tftp=dir]\n"
" [,bootfile=f][,hostfwd=rule][,guestfwd=rule]" " [,bootfile=f][,hostfwd=rule][,guestfwd=rule]"
#ifndef _WIN32 #ifndef _WIN32
@ -1701,6 +1702,9 @@ Connect user mode stack to VLAN @var{n} (@var{n} = 0 is the default).
@itemx name=@var{name} @itemx name=@var{name}
Assign symbolic name for use in monitor commands. Assign symbolic name for use in monitor commands.
@option{ipv4} and @option{ipv6} specify that either IPv4 or IPv6 must
be enabled. If neither is specified both protocols are enabled.
@item net=@var{addr}[/@var{mask}] @item net=@var{addr}[/@var{mask}]
Set IP network address the guest will see. Optionally specify the netmask, Set IP network address the guest will see. Optionally specify the netmask,
either in the form a.b.c.d or as number of valid top-most bits. Default is either in the form a.b.c.d or as number of valid top-most bits. Default is

View File

@ -24,6 +24,10 @@ static void ra_timer_handler(void *opaque)
void icmp6_init(Slirp *slirp) void icmp6_init(Slirp *slirp)
{ {
if (!slirp->in6_enabled) {
return;
}
slirp->ra_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, ra_timer_handler, slirp); slirp->ra_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, ra_timer_handler, slirp);
timer_mod(slirp->ra_timer, timer_mod(slirp->ra_timer,
qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + NDP_Interval); qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + NDP_Interval);
@ -31,6 +35,10 @@ void icmp6_init(Slirp *slirp)
void icmp6_cleanup(Slirp *slirp) void icmp6_cleanup(Slirp *slirp)
{ {
if (!slirp->in6_enabled) {
return;
}
timer_del(slirp->ra_timer); timer_del(slirp->ra_timer);
timer_free(slirp->ra_timer); timer_free(slirp->ra_timer);
} }

View File

@ -24,6 +24,11 @@ void ip6_cleanup(Slirp *slirp)
void ip6_input(struct mbuf *m) void ip6_input(struct mbuf *m)
{ {
struct ip6 *ip6; struct ip6 *ip6;
Slirp *slirp = m->slirp;
if (!slirp->in6_enabled) {
goto bad;
}
DEBUG_CALL("ip6_input"); DEBUG_CALL("ip6_input");
DEBUG_ARG("m = %lx", (long)m); DEBUG_ARG("m = %lx", (long)m);

View File

@ -80,6 +80,10 @@ ip_input(struct mbuf *m)
register struct ip *ip; register struct ip *ip;
int hlen; int hlen;
if (!slirp->in_enabled) {
goto bad;
}
DEBUG_CALL("ip_input"); DEBUG_CALL("ip_input");
DEBUG_ARG("m = %p", m); DEBUG_ARG("m = %p", m);
DEBUG_ARG("m_len = %d", m->m_len); DEBUG_ARG("m_len = %d", m->m_len);

View File

@ -8,8 +8,9 @@ typedef struct Slirp Slirp;
int get_dns_addr(struct in_addr *pdns_addr); int get_dns_addr(struct in_addr *pdns_addr);
Slirp *slirp_init(int restricted, struct in_addr vnetwork, Slirp *slirp_init(int restricted, bool in_enabled, struct in_addr vnetwork,
struct in_addr vnetmask, struct in_addr vhost, struct in_addr vnetmask, struct in_addr vhost,
bool in6_enabled,
struct in6_addr vprefix_addr6, uint8_t vprefix_len, struct in6_addr vprefix_addr6, uint8_t vprefix_len,
struct in6_addr vhost6, const char *vhostname, struct in6_addr vhost6, const char *vhostname,
const char *tftp_path, const char *bootfile, const char *tftp_path, const char *bootfile,

View File

@ -200,8 +200,9 @@ static void slirp_init_once(void)
static void slirp_state_save(QEMUFile *f, void *opaque); static void slirp_state_save(QEMUFile *f, void *opaque);
static int slirp_state_load(QEMUFile *f, void *opaque, int version_id); static int slirp_state_load(QEMUFile *f, void *opaque, int version_id);
Slirp *slirp_init(int restricted, struct in_addr vnetwork, Slirp *slirp_init(int restricted, bool in_enabled, struct in_addr vnetwork,
struct in_addr vnetmask, struct in_addr vhost, struct in_addr vnetmask, struct in_addr vhost,
bool in6_enabled,
struct in6_addr vprefix_addr6, uint8_t vprefix_len, struct in6_addr vprefix_addr6, uint8_t vprefix_len,
struct in6_addr vhost6, const char *vhostname, struct in6_addr vhost6, const char *vhostname,
const char *tftp_path, const char *bootfile, const char *tftp_path, const char *bootfile,
@ -216,6 +217,9 @@ Slirp *slirp_init(int restricted, struct in_addr vnetwork,
slirp->grand = g_rand_new(); slirp->grand = g_rand_new();
slirp->restricted = restricted; slirp->restricted = restricted;
slirp->in_enabled = in_enabled;
slirp->in6_enabled = in6_enabled;
if_init(slirp); if_init(slirp);
ip_init(slirp); ip_init(slirp);
ip6_init(slirp); ip6_init(slirp);
@ -694,6 +698,10 @@ static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
int ar_op; int ar_op;
struct ex_list *ex_ptr; struct ex_list *ex_ptr;
if (!slirp->in_enabled) {
return;
}
ar_op = ntohs(ah->ar_op); ar_op = ntohs(ah->ar_op);
switch(ar_op) { switch(ar_op) {
case ARPOP_REQUEST: case ARPOP_REQUEST:

View File

@ -180,6 +180,8 @@ struct Slirp {
u_int last_slowtimo; u_int last_slowtimo;
bool do_slowtimo; bool do_slowtimo;
bool in_enabled, in6_enabled;
/* virtual network configuration */ /* virtual network configuration */
struct in_addr vnetwork_addr; struct in_addr vnetwork_addr;
struct in_addr vnetwork_mask; struct in_addr vnetwork_mask;