diff mbox

[PATCHv2] slirp: Allow to disable IPv4 or IPv6

Message ID 1458853245-7363-1-git-send-email-samuel.thibault@ens-lyon.org (mailing list archive)
State New, archived
Headers show

Commit Message

Samuel Thibault March 24, 2016, 9 p.m. UTC
Make net=none disable IPv4 and ip6-net=none disable IPv6, so the user can
setup IPv4-only and IPv6-only network environments.

Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
---
 net/slirp.c       | 19 +++++++++++++------
 qapi-schema.json  | 15 +++++++++++++--
 qemu-options.hx   | 19 ++++++++++++-------
 slirp/ip6_icmp.c  |  8 ++++++++
 slirp/ip6_input.c |  5 +++++
 slirp/ip_input.c  |  4 ++++
 slirp/libslirp.h  |  3 ++-
 slirp/slirp.c     | 10 +++++++++-
 slirp/slirp.h     |  2 ++
 9 files changed, 68 insertions(+), 17 deletions(-)

Comments

Eric Blake March 24, 2016, 9:36 p.m. UTC | #1
On 03/24/2016 03:00 PM, Samuel Thibault wrote:

In the subject line: "Allow to" is not idiomatic English.  "Allow"
requires either a subject ("Allow someone to disable"), or a gerund
("Allow disabling").

> Make net=none disable IPv4 and ip6-net=none disable IPv6, so the user can
> setup IPv4-only and IPv6-only network environments.

This mentions 'net=none', but I don't see that in the patch below;
instead I see a new boolean.

> 
> Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
> ---

> +++ b/qapi-schema.json
> @@ -2425,9 +2425,16 @@
>  #
>  # @restrict: #optional isolate the guest from the host
>  #
> +# @ip4: #optional whether to support IPv4, default is to support both IPv4 and IPv6.
> +#
> +# @ip6: #optional whether to support IPv6, default is to support both IPv4 and IPv6.
> +#

Missing '(since 2.6)' decorations (or 2.7, if this is too late for 2.6).

>  # @ip: #optional legacy parameter, use net= instead
>  #
> -# @net: #optional IP address and optional netmask
> +# @net: #optional IP network address that the guest will see, in the
> +# form addr[/netmask] (default is 10.0.2.0/24). The netmask is optional,
> +# and can be either in the form a.b.c.d or as a number of valid top-most
> +# bits.

What happens if 'net' is provided but 'ip4' is false?  Is that a user error?

The existing 'InetSocketAddress' QAPI type spells these as 'ipv4' and
ipv6'; should we use the same spelling for consistency?

>  #
>  # @host: #optional guest-visible address of the host
>  #
> @@ -2443,7 +2450,9 @@
>  # @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-prefix: #optional IPv6 network prefix (default is fec0::) (since
> +# 2.6). The network prefix is given in the usual hexadecimal IPv6
> +# address notation.

Likeiwse if 'ip6-prefix' is provided but 'ip6' is false?

What if both 'ip4' and 'ip6' are false, user error?

Was the intent to allow 'ip6-prefix':'none' as the special case for
disabling IPv6?  At least the new 'ip6' boolean is introspectible;
adding a special-case interpretation of an existing field is not.

>  @item net=@var{addr}[/@var{mask}]
> -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
> -10.0.2.0/24.
> +Set IP network address the guest will see or 'none'. Default is
> +10.0.2.0/24.  The netmask is optional, and can be either in the form
> +a.b.c.d or as number of valid top-most bits. 'none' disables IPv4
> +completely.

HMP can have syntactic sugar; I'm just fine if HMP's net=none translates
into QMP's 'ip4':false.
Samuel Thibault March 24, 2016, 9:41 p.m. UTC | #2
Eric Blake, on Thu 24 Mar 2016 15:36:19 -0600, wrote:
> > Make net=none disable IPv4 and ip6-net=none disable IPv6, so the user can
> > setup IPv4-only and IPv6-only network environments.
> 
> This mentions 'net=none', but I don't see that in the patch below;
> instead I see a new boolean.

Eeergl, sorry, after the suggestion to use booleans, I didn't rechecked
once again the documentation.

Let me fix all that.

Samuel
Samuel Thibault March 24, 2016, 9:44 p.m. UTC | #3
Hello,

Eric Blake, on Thu 24 Mar 2016 15:36:19 -0600, wrote:
> What happens if 'net' is provided but 'ip4' is false?  Is that a user error?

We could do that, yes.

> The existing 'InetSocketAddress' QAPI type spells these as 'ipv4' and
> ipv6'; should we use the same spelling for consistency?

Then it's inconsistent with the ip6-* options, but we can change those,
since they are still new.

> Was the intent to allow 'ip6-prefix':'none' as the special case for
> disabling IPv6?

That was the original plan, but a boolean was suggested instead.

Samuel
diff mbox

Patch

diff --git a/net/slirp.c b/net/slirp.c
index 95239bc..4c9319e 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -135,8 +135,8 @@  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,
+                          bool ip4, const char *vnetwork, const char *vhost,
+                          bool ip6, const char *vprefix6, int vprefix6_len,
                           const char *vhost6,
                           const char *vhostname, const char *tftp_export,
                           const char *bootfile, const char *vdhcp_start,
@@ -164,6 +164,12 @@  static int net_slirp_init(NetClientState *peer, const char *model,
     char *end;
     struct slirp_config_str *config;
 
+    if (!ip4 && !ip6) {
+        /* Enable both by default */
+        ip4 = 1;
+        ip6 = 1;
+    }
+
     if (!tftp_export) {
         tftp_export = legacy_tftp_prefix;
     }
@@ -308,8 +314,8 @@  static int net_slirp_init(NetClientState *peer, const char *model,
 
     s = DO_UPCAST(SlirpState, nc, nc);
 
-    s->slirp = slirp_init(restricted, net, mask, host,
-                          ip6_prefix, vprefix6_len, ip6_host,
+    s->slirp = slirp_init(restricted, ip4, net, mask, host,
+                          ip6, ip6_prefix, vprefix6_len, ip6_host,
                           vhostname, tftp_export, bootfile, dhcp,
                           dns, ip6_dns, dnssearch, s);
     QTAILQ_INSERT_TAIL(&slirp_stacks, s, entry);
@@ -827,8 +833,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->guestfwd, 0);
 
-    ret = net_slirp_init(peer, "user", name, user->q_restrict, vnet,
-                         user->host, user->ip6_prefix, user->ip6_prefixlen,
+    ret = net_slirp_init(peer, "user", name, user->q_restrict,
+                         user->ip4, vnet, user->host,
+                         user->ip6, user->ip6_prefix, user->ip6_prefixlen,
                          user->ip6_host, user->hostname, user->tftp,
                          user->bootfile, user->dhcpstart,
                          user->dns, user->ip6_dns, user->smb,
diff --git a/qapi-schema.json b/qapi-schema.json
index 88f9b81..0b693ec 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -2425,9 +2425,16 @@ 
 #
 # @restrict: #optional isolate the guest from the host
 #
+# @ip4: #optional whether to support IPv4, default is to support both IPv4 and IPv6.
+#
+# @ip6: #optional whether to support IPv6, default is to support both IPv4 and IPv6.
+#
 # @ip: #optional legacy parameter, use net= instead
 #
-# @net: #optional IP address and optional netmask
+# @net: #optional IP network address that the guest will see, in the
+# form addr[/netmask] (default is 10.0.2.0/24). The netmask is optional,
+# and can be either in the form a.b.c.d or as a number of valid top-most
+# bits.
 #
 # @host: #optional guest-visible address of the host
 #
@@ -2443,7 +2450,9 @@ 
 # @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-prefix: #optional IPv6 network prefix (default is fec0::) (since
+# 2.6). The network prefix is given in the usual hexadecimal IPv6
+# address notation.
 #
 # @ip6-prefixlen: #optional IPv6 network prefix length (default is 64) (since 2.6)
 #
@@ -2466,6 +2475,8 @@ 
   'data': {
     '*hostname':  'str',
     '*restrict':  'bool',
+    '*ip4':       'bool',
+    '*ip6':       'bool',
     '*ip':        'str',
     '*net':       'str',
     '*host':      'str',
diff --git a/qemu-options.hx b/qemu-options.hx
index 732ed8c..cc43c32 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -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][,ip6-net=addr[/int]]\n"
-    "         [,ip6-host=addr][,restrict=on|off][,hostname=host][,dhcpstart=addr]\n"
+    "-netdev user,id=str[,ip4][,net=addr[/mask]][,host=addr]\n"
+    "         [,ip6][,ip6-net=addr[/int]][,ip6-host=addr]\n"
+    "         [,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
@@ -1711,17 +1712,21 @@  Connect user mode stack to VLAN @var{n} (@var{n} = 0 is the default).
 Assign symbolic name for use in monitor commands.
 
 @item net=@var{addr}[/@var{mask}]
-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
-10.0.2.0/24.
+Set IP network address the guest will see or 'none'. Default is
+10.0.2.0/24.  The netmask is optional, and can be either in the form
+a.b.c.d or as number of valid top-most bits. 'none' disables IPv4
+completely.
 
 @item host=@var{addr}
 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.
+Set IPv6 network address the guest will see or 'none' (default is
+fec0::/64). The network prefix is given in the usual hexadecimal IPv6
+address notation. The prefix size is optional, and is given as the
+number of valid top-most bits (default is 64). 'none' disables IPv6
+completely.
 
 @item ip6-host=@var{addr}
 Specify the guest-visible IPv6 address of the host. Default is the 2nd IPv6 in
diff --git a/slirp/ip6_icmp.c b/slirp/ip6_icmp.c
index 9d61349..09571bc 100644
--- a/slirp/ip6_icmp.c
+++ b/slirp/ip6_icmp.c
@@ -24,6 +24,10 @@  static void ra_timer_handler(void *opaque)
 
 void icmp6_init(Slirp *slirp)
 {
+    if (!slirp->in6_enabled) {
+        return;
+    }
+
     slirp->ra_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, ra_timer_handler, slirp);
     timer_mod(slirp->ra_timer,
               qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + NDP_Interval);
@@ -31,6 +35,10 @@  void icmp6_init(Slirp *slirp)
 
 void icmp6_cleanup(Slirp *slirp)
 {
+    if (!slirp->in6_enabled) {
+        return;
+    }
+
     timer_del(slirp->ra_timer);
     timer_free(slirp->ra_timer);
 }
diff --git a/slirp/ip6_input.c b/slirp/ip6_input.c
index c0b11e7..ac2e3ea 100644
--- a/slirp/ip6_input.c
+++ b/slirp/ip6_input.c
@@ -24,6 +24,11 @@  void ip6_cleanup(Slirp *slirp)
 void ip6_input(struct mbuf *m)
 {
     struct ip6 *ip6;
+    Slirp *slirp = m->slirp;
+
+    if (!slirp->in6_enabled) {
+        goto bad;
+    }
 
     DEBUG_CALL("ip6_input");
     DEBUG_ARG("m = %lx", (long)m);
diff --git a/slirp/ip_input.c b/slirp/ip_input.c
index b464f6b..cdd5483 100644
--- a/slirp/ip_input.c
+++ b/slirp/ip_input.c
@@ -80,6 +80,10 @@  ip_input(struct mbuf *m)
 	register struct ip *ip;
 	int hlen;
 
+	if (!slirp->in_enabled) {
+		goto bad;
+	}
+
 	DEBUG_CALL("ip_input");
 	DEBUG_ARG("m = %p", m);
 	DEBUG_ARG("m_len = %d", m->m_len);
diff --git a/slirp/libslirp.h b/slirp/libslirp.h
index c4b25c9..127aa41 100644
--- a/slirp/libslirp.h
+++ b/slirp/libslirp.h
@@ -8,8 +8,9 @@  typedef struct Slirp Slirp;
 
 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,
+                  bool in6_enabled,
                   struct in6_addr vprefix_addr6, uint8_t vprefix_len,
                   struct in6_addr vhost6, const char *vhostname,
                   const char *tftp_path, const char *bootfile,
diff --git a/slirp/slirp.c b/slirp/slirp.c
index 9ccf415..6256c89 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -199,8 +199,9 @@  static void slirp_init_once(void)
 static void slirp_state_save(QEMUFile *f, void *opaque);
 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,
+                  bool in6_enabled,
                   struct in6_addr vprefix_addr6, uint8_t vprefix_len,
                   struct in6_addr vhost6, const char *vhostname,
                   const char *tftp_path, const char *bootfile,
@@ -215,6 +216,9 @@  Slirp *slirp_init(int restricted, struct in_addr vnetwork,
     slirp->grand = g_rand_new();
     slirp->restricted = restricted;
 
+    slirp->in_enabled = in_enabled;
+    slirp->in6_enabled = in6_enabled;
+
     if_init(slirp);
     ip_init(slirp);
     ip6_init(slirp);
@@ -693,6 +697,10 @@  static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
     int ar_op;
     struct ex_list *ex_ptr;
 
+    if (!slirp->in_enabled) {
+        return;
+    }
+
     ar_op = ntohs(ah->ar_op);
     switch(ar_op) {
     case ARPOP_REQUEST:
diff --git a/slirp/slirp.h b/slirp/slirp.h
index 9ad88e7..0b84027 100644
--- a/slirp/slirp.h
+++ b/slirp/slirp.h
@@ -179,6 +179,8 @@  struct Slirp {
     u_int last_slowtimo;
     bool do_slowtimo;
 
+    bool in_enabled, in6_enabled;
+
     /* virtual network configuration */
     struct in_addr vnetwork_addr;
     struct in_addr vnetwork_mask;