diff mbox

[1/5] slirp: Allow disabling IPv4 or IPv6

Message ID 1459208679-27805-2-git-send-email-samuel.thibault@ens-lyon.org
State New
Headers show

Commit Message

Samuel Thibault March 28, 2016, 11:44 p.m. UTC
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>

---

Changes since previous versions:

- fix coding style
---
 net/slirp.c       | 36 ++++++++++++++++++++++++++++++------
 qapi-schema.json  |  8 ++++++++
 qemu-options.hx   |  8 ++++++--
 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, 74 insertions(+), 10 deletions(-)

Comments

Thomas Huth March 30, 2016, 8:38 a.m. UTC | #1
On 29.03.2016 01:44, Samuel Thibault wrote:
> 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>
> 
> ---
> 
> Changes since previous versions:
> 
> - fix coding style
> ---
>  net/slirp.c       | 36 ++++++++++++++++++++++++++++++------
>  qapi-schema.json  |  8 ++++++++
>  qemu-options.hx   |  8 ++++++--
>  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, 74 insertions(+), 10 deletions(-)
> 
[...]
> diff --git a/qemu-options.hx b/qemu-options.hx
> index 09162f5..705f162 100644
> --- a/qemu-options.hx
> +++ b/qemu-options.hx
> @@ -1551,8 +1551,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][,ipv6-net=addr[/int]]\n"
> -    "         [,ipv6-host=addr][,restrict=on|off][,hostname=host][,dhcpstart=addr]\n"
> +    "-netdev user,id=str[,ipv4][,net=addr[/mask]][,host=addr]\n"
> +    "         [,ipv6][,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"
>      "         [,bootfile=f][,hostfwd=rule][,guestfwd=rule]"

Shouldn't that rather be "[,ipv4=on|off]" and "[,ipv6=on|off]" for a
boolean value?

Apart from that, the patch looks fine to me.

 Thomas
Samuel Thibault March 30, 2016, 3:04 p.m. UTC | #2
Hello,

Thomas Huth, on Wed 30 Mar 2016 10:38:46 +0200, wrote:
> > -    "-netdev user,id=str[,net=addr[/mask]][,host=addr][,ipv6-net=addr[/int]]\n"
> > -    "         [,ipv6-host=addr][,restrict=on|off][,hostname=host][,dhcpstart=addr]\n"
> > +    "-netdev user,id=str[,ipv4][,net=addr[/mask]][,host=addr]\n"
> > +    "         [,ipv6][,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"
> >      "         [,bootfile=f][,hostfwd=rule][,guestfwd=rule]"
> 
> Shouldn't that rather be "[,ipv4=on|off]" and "[,ipv6=on|off]" for a
> boolean value?

Well, just like the rest of these ipv4/ipv6 options, they do accept
=on|off, but it's not documented in the qemu-options.hx file.  Should we
fix them all?

Samuel
Thomas Huth March 30, 2016, 3:06 p.m. UTC | #3
On 30.03.2016 17:04, Samuel Thibault wrote:
> Hello,
> 
> Thomas Huth, on Wed 30 Mar 2016 10:38:46 +0200, wrote:
>>> -    "-netdev user,id=str[,net=addr[/mask]][,host=addr][,ipv6-net=addr[/int]]\n"
>>> -    "         [,ipv6-host=addr][,restrict=on|off][,hostname=host][,dhcpstart=addr]\n"
>>> +    "-netdev user,id=str[,ipv4][,net=addr[/mask]][,host=addr]\n"
>>> +    "         [,ipv6][,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"
>>>      "         [,bootfile=f][,hostfwd=rule][,guestfwd=rule]"
>>
>> Shouldn't that rather be "[,ipv4=on|off]" and "[,ipv6=on|off]" for a
>> boolean value?
> 
> Well, just like the rest of these ipv4/ipv6 options, they do accept
> =on|off, but it's not documented in the qemu-options.hx file.  Should we
> fix them all?

The "restrict" option is listed with "=on|off" here, that's why I
thought it should be there for "ipv4" and "ipv6", too. Which boolean
options are missing the "=on|off" ?

 Thomas
Samuel Thibault March 30, 2016, 3:13 p.m. UTC | #4
Thomas Huth, on Wed 30 Mar 2016 17:06:51 +0200, wrote:
> The "restrict" option is listed with "=on|off" here, that's why I
> thought it should be there for "ipv4" and "ipv6", too. Which boolean
> options are missing the "=on|off" ?

All the ipv4 and ipv6 options in the same file.

Samuel
Thomas Huth March 30, 2016, 3:29 p.m. UTC | #5
On 30.03.2016 17:13, Samuel Thibault wrote:
> Thomas Huth, on Wed 30 Mar 2016 17:06:51 +0200, wrote:
>> The "restrict" option is listed with "=on|off" here, that's why I
>> thought it should be there for "ipv4" and "ipv6", too. Which boolean
>> options are missing the "=on|off" ?
> 
> All the ipv4 and ipv6 options in the same file.

Ugh, ok, now I see it ... most of these are specified in qemu-options.hx
without the "=on|off", only for the "-netdev l2tpv3" it is specified as
"ipv6=on/off" (with slash instead of the pipe character!) ... what a
mess... not sure which is the best way to go here, so maybe keep it
without the "=on|off" for now so that it is consistent with most of the
other options?

 Thomas
Samuel Thibault March 30, 2016, 3:36 p.m. UTC | #6
Thomas Huth, on Wed 30 Mar 2016 17:29:12 +0200, wrote:
> On 30.03.2016 17:13, Samuel Thibault wrote:
> > Thomas Huth, on Wed 30 Mar 2016 17:06:51 +0200, wrote:
> >> The "restrict" option is listed with "=on|off" here, that's why I
> >> thought it should be there for "ipv4" and "ipv6", too. Which boolean
> >> options are missing the "=on|off" ?
> > 
> > All the ipv4 and ipv6 options in the same file.
> 
> Ugh, ok, now I see it ... most of these are specified in qemu-options.hx
> without the "=on|off", only for the "-netdev l2tpv3" it is specified as
> "ipv6=on/off" (with slash instead of the pipe character!) ... what a
> mess... not sure which is the best way to go here, so maybe keep it
> without the "=on|off" for now so that it is consistent with most of the
> other options?

Eric, Markus, what do you prefer?

Samuel
Eric Blake March 30, 2016, 3:54 p.m. UTC | #7
On 03/30/2016 09:36 AM, Samuel Thibault wrote:
> Thomas Huth, on Wed 30 Mar 2016 17:29:12 +0200, wrote:
>> On 30.03.2016 17:13, Samuel Thibault wrote:
>>> Thomas Huth, on Wed 30 Mar 2016 17:06:51 +0200, wrote:
>>>> The "restrict" option is listed with "=on|off" here, that's why I
>>>> thought it should be there for "ipv4" and "ipv6", too. Which boolean
>>>> options are missing the "=on|off" ?
>>>
>>> All the ipv4 and ipv6 options in the same file.
>>
>> Ugh, ok, now I see it ... most of these are specified in qemu-options.hx
>> without the "=on|off", only for the "-netdev l2tpv3" it is specified as
>> "ipv6=on/off" (with slash instead of the pipe character!) ... what a
>> mess... not sure which is the best way to go here, so maybe keep it
>> without the "=on|off" for now so that it is consistent with most of the
>> other options?
> 
> Eric, Markus, what do you prefer?

No strong preference. Libvirt doesn't parse the command line --help
output, precisely because (as you've noticed) it is a big inconsistent
mess already.  Pick one, and that's fine; and it's a bonus if you want
to do a followup cleanup for consistency, but I won't lose any sleep if
you don't do a followup.
diff mbox

Patch

diff --git a/net/slirp.c b/net/slirp.c
index 0013c27..c810dc4 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 ipv4, const char *vnetwork, const char *vhost,
+                          bool ipv6, 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,19 @@  static int net_slirp_init(NetClientState *peer, const char *model,
     char *end;
     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) {
         tftp_export = legacy_tftp_prefix;
     }
@@ -308,8 +321,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, ipv4, net, mask, host,
+                          ipv6, ip6_prefix, vprefix6_len, ip6_host,
                           vhostname, tftp_export, bootfile, dhcp,
                           dns, ip6_dns, dnssearch, s);
     QTAILQ_INSERT_TAIL(&slirp_stacks, s, entry);
@@ -812,10 +825,20 @@  int net_init_slirp(const NetClientOptions *opts, const char *name,
     int ret;
     const NetdevUserOptions *user;
     const char **dnssearch;
+    bool ipv4 = true, ipv6 = true;
 
     assert(opts->type == NET_CLIENT_OPTIONS_KIND_USER);
     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) :
            user->has_ip  ? g_strdup_printf("%s/24", user->ip) :
            NULL;
@@ -827,8 +850,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->ipv6_prefix, user->ipv6_prefixlen,
+    ret = net_slirp_init(peer, "user", name, user->q_restrict,
+                         ipv4, vnet, user->host,
+                         ipv6, user->ipv6_prefix, user->ipv6_prefixlen,
                          user->ipv6_host, user->hostname, user->tftp,
                          user->bootfile, user->dhcpstart,
                          user->dns, user->ipv6_dns, user->smb,
diff --git a/qapi-schema.json b/qapi-schema.json
index 8907790..d83caa3 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -2425,6 +2425,12 @@ 
 #
 # @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
 #
 # @net: #optional IP network address that the guest will see, in the
@@ -2473,6 +2479,8 @@ 
   'data': {
     '*hostname':  'str',
     '*restrict':  'bool',
+    '*ipv4':      'bool',
+    '*ipv6':      'bool',
     '*ip':        'str',
     '*net':       'str',
     '*host':      'str',
diff --git a/qemu-options.hx b/qemu-options.hx
index 09162f5..705f162 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1551,8 +1551,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][,ipv6-net=addr[/int]]\n"
-    "         [,ipv6-host=addr][,restrict=on|off][,hostname=host][,dhcpstart=addr]\n"
+    "-netdev user,id=str[,ipv4][,net=addr[/mask]][,host=addr]\n"
+    "         [,ipv6][,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"
     "         [,bootfile=f][,hostfwd=rule][,guestfwd=rule]"
 #ifndef _WIN32
@@ -1701,6 +1702,9 @@  Connect user mode stack to VLAN @var{n} (@var{n} = 0 is the default).
 @itemx name=@var{name}
 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}]
 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
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 1abbcc6..c99ebb9 100644
--- a/slirp/slirp.h
+++ b/slirp/slirp.h
@@ -180,6 +180,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;