diff mbox

[16/16] qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6 addresses

Message ID 1382280980-21676-16-git-send-email-samuel.thibault@ens-lyon.org
State New
Headers show

Commit Message

Samuel Thibault Oct. 20, 2013, 2:56 p.m. UTC
This patchs adds parameters to manage some new options in the qemu -net
command.
Slirp IPv6 address, network prefix, and DNS IPv6 address can be given in
argument to the qemu command.
Defaults parameters are respectively fc00::1, fc00::, /64 and fc00::2.

Signed-off-by: Yann Bordenave <meow@meowstars.org>
---
 net/slirp.c      | 56 ++++++++++++++++++++++++++++++++++++++++++++++++--------
 qapi-schema.json | 37 +++++++++++++++++++++++--------------
 qemu-options.hx  |  5 +++--
 slirp/libslirp.h |  8 +++++---
 slirp/slirp.c    | 20 +++++++++-----------
 5 files changed, 88 insertions(+), 38 deletions(-)

Comments

Eric Blake Oct. 21, 2013, 9:04 p.m. UTC | #1
On 10/20/2013 03:56 PM, Samuel Thibault wrote:
> This patchs adds parameters to manage some new options in the qemu -net
> command.
> Slirp IPv6 address, network prefix, and DNS IPv6 address can be given in
> argument to the qemu command.
> Defaults parameters are respectively fc00::1, fc00::, /64 and fc00::2.
> 
> Signed-off-by: Yann Bordenave <meow@meowstars.org>
> ---

Just focusing on interface for now...

> +++ b/qapi-schema.json
> @@ -2807,6 +2807,12 @@
>  # @dnssearch: #optional list of DNS suffixes to search, passed as DHCP option
>  #             to the guest
>  #
> +# @ip6_prefix: #optional IPv6 network prefix

Please mention '(since 1.8)' for each new field.  Also, this command
doesn't have any '_', so your new field names should be named with '-',
as in @ip6-prefix

> +#
> +# @ip6_host: guest-visible IPv6 address of the host
> +#
> +# @ip6_dns: guest-visible IPv6 address of the virtual nameserver
> +#
>  # @smb: #optional root directory of the built-in SMB server
>  #
>  # @smbserver: #optional IP address of the built-in SMB server
> @@ -2820,20 +2826,23 @@
>  ##

> +    '*ip6_prefix':      'str',

Why is this a str instead of an integer?

> +    '*ip6_host':        'str',
> +    '*ip6_dns':         'str',

These look okay (other than the - vs _ issue)
Samuel Thibault Oct. 22, 2013, 10:22 a.m. UTC | #2
Hello,

Eric Blake, le Mon 21 Oct 2013 22:04:23 +0100, a écrit :
> > +    '*ip6_prefix':      'str',
> 
> Why is this a str instead of an integer?

prefix would be e.g. fc00::1/64.

Samuel
Eric Blake Oct. 22, 2013, 10:27 a.m. UTC | #3
On 10/22/2013 11:22 AM, Samuel Thibault wrote:
> Hello,
> 
> Eric Blake, le Mon 21 Oct 2013 22:04:23 +0100, a écrit :
>>> +    '*ip6_prefix':      'str',
>>
>> Why is this a str instead of an integer?
> 
> prefix would be e.g. fc00::1/64.

That requires me to post-parse it. Would it be smarter to represent this
as two elements, one for the "fc00::1" string, and another for the 64
width, so that I don't have to post-parse?
Samuel Thibault Oct. 22, 2013, 10:31 a.m. UTC | #4
Hello,

Eric Blake, le Tue 22 Oct 2013 11:27:27 +0100, a écrit :
> On 10/22/2013 11:22 AM, Samuel Thibault wrote:
> > Eric Blake, le Mon 21 Oct 2013 22:04:23 +0100, a écrit :
> >>> +    '*ip6_prefix':      'str',
> >>
> >> Why is this a str instead of an integer?
> > 
> > prefix would be e.g. fc00::1/64.
> 
> That requires me to post-parse it. Would it be smarter to represent this
> as two elements, one for the "fc00::1" string, and another for the 64
> width, so that I don't have to post-parse?

It makes sense, yes, the syntax would be [ip6-prefix=net[/netsize]] . I
just don't know how to express that in qapi :)

Samuel
Eric Blake Oct. 22, 2013, 10:33 a.m. UTC | #5
On 10/22/2013 11:31 AM, Samuel Thibault wrote:
> Hello,
> 
> Eric Blake, le Tue 22 Oct 2013 11:27:27 +0100, a écrit :
>> On 10/22/2013 11:22 AM, Samuel Thibault wrote:
>>> Eric Blake, le Mon 21 Oct 2013 22:04:23 +0100, a écrit :
>>>>> +    '*ip6_prefix':      'str',
>>>>
>>>> Why is this a str instead of an integer?
>>>
>>> prefix would be e.g. fc00::1/64.
>>
>> That requires me to post-parse it. Would it be smarter to represent this
>> as two elements, one for the "fc00::1" string, and another for the 64
>> width, so that I don't have to post-parse?
> 
> It makes sense, yes, the syntax would be [ip6-prefix=net[/netsize]] . I
> just don't know how to express that in qapi :)

'*ip6_net':'str', '*ip6_netsize':'int'

passed on the wire as:

"ip6_net":"fc00::1", "ip6_netsize":64
Samuel Thibault Oct. 22, 2013, 10:45 a.m. UTC | #6
Eric Blake, le Tue 22 Oct 2013 11:33:52 +0100, a écrit :
> On 10/22/2013 11:31 AM, Samuel Thibault wrote:
> > Hello,
> > 
> > Eric Blake, le Tue 22 Oct 2013 11:27:27 +0100, a écrit :
> >> On 10/22/2013 11:22 AM, Samuel Thibault wrote:
> >>> Eric Blake, le Mon 21 Oct 2013 22:04:23 +0100, a écrit :
> >>>>> +    '*ip6_prefix':      'str',
> >>>>
> >>>> Why is this a str instead of an integer?
> >>>
> >>> prefix would be e.g. fc00::1/64.
> >>
> >> That requires me to post-parse it. Would it be smarter to represent this
> >> as two elements, one for the "fc00::1" string, and another for the 64
> >> width, so that I don't have to post-parse?
> > 
> > It makes sense, yes, the syntax would be [ip6-prefix=net[/netsize]] . I
> > just don't know how to express that in qapi :)
> 
> '*ip6_net':'str', '*ip6_netsize':'int'
> 
> passed on the wire as:
> 
> "ip6_net":"fc00::1", "ip6_netsize":64

Err, so that means that the user would have to pass
"ip6-net=fc00::1,ip6_netsize=64"?  This would look awkward, compared to
the ipv4 situation, which is a mere "net=10.0.2.2/24".

Samuel
Eric Blake Oct. 22, 2013, 10:48 a.m. UTC | #7
On 10/22/2013 11:45 AM, Samuel Thibault wrote:

>>> It makes sense, yes, the syntax would be [ip6-prefix=net[/netsize]] . I
>>> just don't know how to express that in qapi :)
>>
>> '*ip6_net':'str', '*ip6_netsize':'int'
>>
>> passed on the wire as:
>>
>> "ip6_net":"fc00::1", "ip6_netsize":64
> 
> Err, so that means that the user would have to pass
> "ip6-net=fc00::1,ip6_netsize=64"?  This would look awkward, compared to
> the ipv4 situation, which is a mere "net=10.0.2.2/24".

Err, yes.  QMP is machine-parseable.  HMP can let the user abbreviate to
net=10.0.2.2/24, but QMP should not require reparsing.  So what if it's
longer, it's easier for machines to manipulate if it's already broken
into parts.  Trust me - I wouldn't be asking you to split it into two
fields unless I thought that libvirt would much rather send it to you as
two fields.
Eric Blake Oct. 22, 2013, 10:52 a.m. UTC | #8
On 10/22/2013 11:48 AM, Eric Blake wrote:
> On 10/22/2013 11:45 AM, Samuel Thibault wrote:
> 
>>>> It makes sense, yes, the syntax would be [ip6-prefix=net[/netsize]] . I
>>>> just don't know how to express that in qapi :)
>>>
>>> '*ip6_net':'str', '*ip6_netsize':'int'
>>>
>>> passed on the wire as:
>>>
>>> "ip6_net":"fc00::1", "ip6_netsize":64
>>
>> Err, so that means that the user would have to pass
>> "ip6-net=fc00::1,ip6_netsize=64"?  This would look awkward, compared to
>> the ipv4 situation, which is a mere "net=10.0.2.2/24".
> 
> Err, yes.  QMP is machine-parseable.  HMP can let the user abbreviate to
> net=10.0.2.2/24, but QMP should not require reparsing.  So what if it's
> longer, it's easier for machines to manipulate if it's already broken
> into parts.  Trust me - I wouldn't be asking you to split it into two
> fields unless I thought that libvirt would much rather send it to you as
> two fields.

The command line, just like HMP, can use shorthand for convenience.  I
guess you do have a point about consistency of ipv4's @net requiring
post-processing, but that doesn't mean we have to repeat the mistake for
IPv6.
Samuel Thibault Oct. 22, 2013, 2:11 p.m. UTC | #9
Eric Blake, le Tue 22 Oct 2013 11:52:11 +0100, a écrit :
> On 10/22/2013 11:48 AM, Eric Blake wrote:
> > HMP can let the user abbreviate to net=10.0.2.2/24,
> 
> The command line, just like HMP, can use shorthand for convenience.

How are these usually defined?  A quick search didn't provide me an
example.

Samuel
Eric Blake Oct. 22, 2013, 2:48 p.m. UTC | #10
On 10/22/2013 03:11 PM, Samuel Thibault wrote:
> Eric Blake, le Tue 22 Oct 2013 11:52:11 +0100, a écrit :
>> On 10/22/2013 11:48 AM, Eric Blake wrote:
>>> HMP can let the user abbreviate to net=10.0.2.2/24,
>>
>> The command line, just like HMP, can use shorthand for convenience.
> 
> How are these usually defined?  A quick search didn't provide me an
> example.

Hmm, I'm not actually sure myself.  I know Keven recently added some
code in his blockdev parsing that aliased old commands to re-inject
themselves back into a QDict in the preferred spelling, before passing
the QDict on down to the final client that handles the options; maybe he
has some better ideas on creating a command line shorthand while still
keeping QMP fully-structured.
diff mbox

Patch

diff --git a/net/slirp.c b/net/slirp.c
index 124e953..68f4aa9 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -134,17 +134,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, 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 */
+    /* default settings according to historic slirp and updated for IPv6 */
     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 in6_addr ip6_prefix;
+    uint8_t ip6_prefix_len = 64;
+    struct in6_addr ip6_host;
     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_dns;
 #ifndef _WIN32
     struct in_addr smbsrv = { .s_addr = 0 };
 #endif
@@ -156,6 +162,11 @@  static int net_slirp_init(NetClientState *peer, const char *model,
     char *end;
     struct slirp_config_str *config;
 
+    /* IPv6 defaults initialisations */
+    inet_pton(AF_INET6, "fc00::0", &ip6_prefix);
+    inet_pton(AF_INET6, "fc00::1", &ip6_host);
+    inet_pton(AF_INET6, "fc00::2", &ip6_dns);
+
     if (!tftp_export) {
         tftp_export = legacy_tftp_prefix;
     }
@@ -228,6 +239,32 @@  static int net_slirp_init(NetClientState *peer, const char *model,
         return -1;
     }
 
+    if (vprefix6) {
+        if (get_str_sep(buf, sizeof(buf), &vprefix6, '/') < 0) {
+            if (!inet_pton(AF_INET6, vprefix6, &ip6_prefix)) {
+                return -1;
+            }
+        } else {
+            if (!inet_pton(AF_INET6, buf, &ip6_prefix)) {
+                return -1;
+            }
+            shift = strtol(vprefix6, &end, 10);
+            if (*end != '\0' || (shift > 0 && shift < 129)) {
+                ip6_prefix_len = shift;
+            } else {
+                return -1;
+            }
+        }
+    }
+
+    if (vhost6 && !inet_pton(AF_INET6, vhost6, &ip6_host)) {
+        return -1;
+    }
+
+    if (vnameserver6 && !inet_pton(AF_INET6, vnameserver6, &ip6_dns)) {
+        return -1;
+    }
+
 #ifndef _WIN32
     if (vsmbserver && !inet_aton(vsmbserver, &smbsrv)) {
         return -1;
@@ -242,8 +279,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, ip6_prefix_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) {
@@ -750,9 +789,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->smbserver, dnssearch);
+                         user->host, user->ip6_prefix, user->ip6_host,
+                         user->hostname, user->tftp, user->bootfile,
+                         user->dhcpstart, user->dns, user->ip6_dns,
+                         user->smb, user->smbserver, dnssearch);
 
     while (slirp_configs) {
         config = slirp_configs;
diff --git a/qapi-schema.json b/qapi-schema.json
index 60f3fd1..16a34c5 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -2807,6 +2807,12 @@ 
 # @dnssearch: #optional list of DNS suffixes to search, passed as DHCP option
 #             to the guest
 #
+# @ip6_prefix: #optional IPv6 network prefix
+#
+# @ip6_host: guest-visible IPv6 address of the host
+#
+# @ip6_dns: guest-visible IPv6 address of the virtual nameserver
+#
 # @smb: #optional root directory of the built-in SMB server
 #
 # @smbserver: #optional IP address of the built-in SMB server
@@ -2820,20 +2826,23 @@ 
 ##
 { 'type': 'NetdevUserOptions',
   'data': {
-    '*hostname':  'str',
-    '*restrict':  'bool',
-    '*ip':        'str',
-    '*net':       'str',
-    '*host':      'str',
-    '*tftp':      'str',
-    '*bootfile':  'str',
-    '*dhcpstart': 'str',
-    '*dns':       'str',
-    '*dnssearch': ['String'],
-    '*smb':       'str',
-    '*smbserver': 'str',
-    '*hostfwd':   ['String'],
-    '*guestfwd':  ['String'] } }
+    '*hostname':        'str',
+    '*restrict':        'bool',
+    '*ip':              'str',
+    '*net':             'str',
+    '*host':            'str',
+    '*tftp':            'str',
+    '*bootfile':        'str',
+    '*dhcpstart':       'str',
+    '*dns':             'str',
+    '*dnssearch':       ['String'],
+    '*ip6_prefix':      'str',
+    '*ip6_host':        'str',
+    '*ip6_dns':         'str',
+    '*smb':             'str',
+    '*smbserver':       'str',
+    '*hostfwd':         ['String'],
+    '*guestfwd':        ['String'] } }
 
 ##
 # @NetdevTapOptions
diff --git a/qemu-options.hx b/qemu-options.hx
index 5dc8b75..eb3a19f 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1357,8 +1357,9 @@  DEF("net", HAS_ARG, QEMU_OPTION_net,
     "-net nic[,vlan=n][,macaddr=mac][,model=type][,name=str][,addr=str][,vectors=v]\n"
     "                create a new Network Interface Card and connect it to VLAN 'n'\n"
 #ifdef CONFIG_SLIRP
-    "-net user[,vlan=n][,name=str][,net=addr[/mask]][,host=addr][,restrict=on|off]\n"
-    "         [,hostname=host][,dhcpstart=addr][,dns=addr][,dnssearch=domain][,tftp=dir]\n"
+    "-net user[,vlan=n][,name=str][,net=addr[/mask]][,host=addr][,ip6_prefix=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"
diff --git a/slirp/libslirp.h b/slirp/libslirp.h
index 5bdcbd5..c4b25c9 100644
--- a/slirp/libslirp.h
+++ b/slirp/libslirp.h
@@ -10,9 +10,11 @@  int get_dns_addr(struct in_addr *pdns_addr);
 
 Slirp *slirp_init(int restricted, struct in_addr vnetwork,
                   struct in_addr vnetmask, struct in_addr vhost,
-                  const char *vhostname, const char *tftp_path,
-                  const char *bootfile, struct in_addr vdhcp_start,
-                  struct in_addr vnameserver, const char **vdnssearch,
+                  struct in6_addr vprefix_addr6, uint8_t vprefix_len,
+                  struct in6_addr vhost6, const char *vhostname,
+                  const char *tftp_path, const char *bootfile,
+                  struct in_addr vdhcp_start, struct in_addr vnameserver,
+                  struct in6_addr vnameserver6, const char **vdnssearch,
                   void *opaque);
 void slirp_cleanup(Slirp *slirp);
 
diff --git a/slirp/slirp.c b/slirp/slirp.c
index 695e8a6..48e39f2 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -201,9 +201,11 @@  static int slirp_state_load(QEMUFile *f, void *opaque, int version_id);
 
 Slirp *slirp_init(int restricted, struct in_addr vnetwork,
                   struct in_addr vnetmask, struct in_addr vhost,
-                  const char *vhostname, const char *tftp_path,
-                  const char *bootfile, struct in_addr vdhcp_start,
-                  struct in_addr vnameserver, const char **vdnssearch,
+                  struct in6_addr vprefix_addr6, uint8_t vprefix_len,
+                  struct in6_addr vhost6, const char *vhostname,
+                  const char *tftp_path, const char *bootfile,
+                  struct in_addr vdhcp_start, struct in_addr vnameserver,
+                  struct in6_addr vnameserver6, const char **vdnssearch,
                   void *opaque)
 {
     Slirp *slirp = g_malloc0(sizeof(Slirp));
@@ -222,12 +224,9 @@  Slirp *slirp_init(int restricted, struct in_addr vnetwork,
     slirp->vnetwork_addr = vnetwork;
     slirp->vnetwork_mask = vnetmask;
     slirp->vhost_addr = vhost;
-    /* :TODO:maethor:130311: Use a parameter passed to the function */
-    inet_pton(AF_INET6, "fc00::0", &slirp->vprefix_addr6);
-    /* :TODO:maethor:130311: Use a parameter passed to the function */
-    slirp->vprefix_len = 64;
-    /* :TODO:maethor:130311: Use a parameter passed to the function */
-    inet_pton(AF_INET6, "fc00::1", &slirp->vhost_addr6);
+    slirp->vprefix_addr6 = vprefix_addr6;
+    slirp->vprefix_len = vprefix_len;
+    slirp->vhost_addr6 = vhost6;
     if (vhostname) {
         pstrcpy(slirp->client_hostname, sizeof(slirp->client_hostname),
                 vhostname);
@@ -236,8 +235,7 @@  Slirp *slirp_init(int restricted, struct in_addr vnetwork,
     slirp->bootp_filename = g_strdup(bootfile);
     slirp->vdhcp_startaddr = vdhcp_start;
     slirp->vnameserver_addr = vnameserver;
-    /* :TODO:maethor:130311: Use a parameter passed to the function */
-    inet_pton(AF_INET6, "fc00::2", &slirp->vnameserver_addr6);
+    slirp->vnameserver_addr6 = vnameserver6;
 
     if (vdnssearch) {
         translate_dnssearch(slirp, vdnssearch);