Patchwork [slirp] add nextserver support in slirp's dhcp-server

login
register
mail settings
Submitter Bas van Sisseren
Date June 21, 2013, 1:20 p.m.
Message ID <1371820809-19712-1-git-send-email-bas@quarantainenet.nl>
Download mbox | patch
Permalink /patch/253218/
State New
Headers show

Comments

Bas van Sisseren - June 21, 2013, 1:20 p.m.
The slirp dhcp-server normally returns its own address as tftp
nextserver for netbooting. This patch makes that address
configurable, so it is possible to use an external tftp boot-
environment.

Signed-off-by: Bas van Sisseren <bas@quarantainenet.nl>
---
 net/slirp.c      | 10 ++++++++--
 qapi-schema.json |  3 +++
 qemu-options.hx  |  5 ++++-
 slirp/bootp.c    |  6 +++++-
 slirp/libslirp.h |  1 +
 slirp/slirp.c    |  2 ++
 slirp/slirp.h    |  1 +
 7 files changed, 24 insertions(+), 4 deletions(-)
Stefan Hajnoczi - June 24, 2013, 9:37 a.m.
On Fri, Jun 21, 2013 at 03:20:09PM +0200, Bas van Sisseren wrote:
> The slirp dhcp-server normally returns its own address as tftp
> nextserver for netbooting. This patch makes that address
> configurable, so it is possible to use an external tftp boot-
> environment.
> 
> Signed-off-by: Bas van Sisseren <bas@quarantainenet.nl>
> ---
>  net/slirp.c      | 10 ++++++++--
>  qapi-schema.json |  3 +++
>  qemu-options.hx  |  5 ++++-
>  slirp/bootp.c    |  6 +++++-
>  slirp/libslirp.h |  1 +
>  slirp/slirp.c    |  2 ++
>  slirp/slirp.h    |  1 +
>  7 files changed, 24 insertions(+), 4 deletions(-)

CCing Jan Kiszka, the slirp/ maintainer.

> diff --git a/net/slirp.c b/net/slirp.c
> index 124e953..f3e239c 100644
> --- a/net/slirp.c
> +++ b/net/slirp.c
> @@ -136,6 +136,7 @@ static int net_slirp_init(NetClientState *peer, const char *model,
>                            const char *vnetwork, const char *vhost,
>                            const char *vhostname, const char *tftp_export,
>                            const char *bootfile, const char *vdhcp_start,
> +                          const char *vnextserver,
>                            const char *vnameserver, const char *smb_export,
>                            const char *vsmbserver, const char **dnssearch)
>  {
> @@ -145,6 +146,7 @@ static int net_slirp_init(NetClientState *peer, const char *model,
>      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 in_addr nxtsrv = { .s_addr = 0 };
>  #ifndef _WIN32
>      struct in_addr smbsrv = { .s_addr = 0 };
>  #endif
> @@ -228,6 +230,10 @@ static int net_slirp_init(NetClientState *peer, const char *model,
>          return -1;
>      }
>  
> +    if (vnextserver && !inet_aton(vnextserver, &nxtsrv)) {
> +        return -1;
> +    }
> +
>  #ifndef _WIN32
>      if (vsmbserver && !inet_aton(vsmbserver, &smbsrv)) {
>          return -1;
> @@ -243,7 +249,7 @@ 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);
> +                          tftp_export, bootfile, dhcp, nxtsrv, dns, dnssearch, s);
>      QTAILQ_INSERT_TAIL(&slirp_stacks, s, entry);
>  
>      for (config = slirp_configs; config; config = config->next) {
> @@ -751,7 +757,7 @@ int net_init_slirp(const NetClientOptions *opts, const char *name,
>  
>      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->bootfile, user->dhcpstart, user->nextserver, user->dns, user->smb,
>                           user->smbserver, dnssearch);
>  
>      while (slirp_configs) {
> diff --git a/qapi-schema.json b/qapi-schema.json
> index a80ee40..a8e2c3d 100644
> --- a/qapi-schema.json
> +++ b/qapi-schema.json
> @@ -2537,6 +2537,8 @@
>  # @dhcpstart: #optional the first of the 16 IPs the built-in DHCP server can
>  #             assign
>  #
> +# @nextserver: #optional IP address of BOOTP server
> +#
>  # @dns: #optional guest-visible address of the virtual nameserver
>  #
>  # @dnssearch: #optional list of DNS suffixes to search, passed as DHCP option
> @@ -2563,6 +2565,7 @@
>      '*tftp':      'str',
>      '*bootfile':  'str',
>      '*dhcpstart': 'str',
> +    '*nextserver': 'str',
>      '*dns':       'str',
>      '*dnssearch': ['String'],
>      '*smb':       'str',
> diff --git a/qemu-options.hx b/qemu-options.hx
> index 8355f9b..8afe42a 100644
> --- a/qemu-options.hx
> +++ b/qemu-options.hx
> @@ -1350,7 +1350,7 @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
>  #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"
> -    "         [,bootfile=f][,hostfwd=rule][,guestfwd=rule]"
> +    "         [,bootfile=f][,nextserver=addr][,hostfwd=rule][,guestfwd=rule]"
>  #ifndef _WIN32
>                                               "[,smb=dir[,smbserver=addr]]\n"
>  #endif
> @@ -1498,6 +1498,9 @@ When using the user mode network stack, broadcast @var{file} as the BOOTP
>  filename. In conjunction with @option{tftp}, this can be used to network boot
>  a guest from a local directory.
>  
> +@item nextserver=@var{addr}
> +Specify the IP address of the TFTP server.
> +
>  Example (using pxelinux):
>  @example
>  qemu-system-i386 -hda linux.img -boot n -net user,tftp=/path/to/tftp/files,bootfile=/pxelinux.0
> diff --git a/slirp/bootp.c b/slirp/bootp.c
> index b7db9fa..d2e89d6 100644
> --- a/slirp/bootp.c
> +++ b/slirp/bootp.c
> @@ -227,7 +227,11 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
>      memcpy(rbp->bp_hwaddr, bp->bp_hwaddr, ETH_ALEN);
>  
>      rbp->bp_yiaddr = daddr.sin_addr; /* Client IP address */
> -    rbp->bp_siaddr = saddr.sin_addr; /* Server IP address */
> +    if (slirp->vnext_server.s_addr == 0) {
> +        rbp->bp_siaddr = saddr.sin_addr; /* Server IP address */
> +    } else {
> +        rbp->bp_siaddr = slirp->vnext_server; /* Next-Server address */
> +    }
>  
>      q = rbp->bp_vend;
>      memcpy(q, rfc1533_cookie, 4);
> diff --git a/slirp/libslirp.h b/slirp/libslirp.h
> index ceabff8..c3d800b 100644
> --- a/slirp/libslirp.h
> +++ b/slirp/libslirp.h
> @@ -12,6 +12,7 @@ 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 vnext_server,
>                    struct in_addr vnameserver, const char **vdnssearch,
>                    void *opaque);
>  void slirp_cleanup(Slirp *slirp);
> diff --git a/slirp/slirp.c b/slirp/slirp.c
> index 80b28ea..35f2afd 100644
> --- a/slirp/slirp.c
> +++ b/slirp/slirp.c
> @@ -200,6 +200,7 @@ 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 vnext_server,
>                    struct in_addr vnameserver, const char **vdnssearch,
>                    void *opaque)
>  {
> @@ -225,6 +226,7 @@ Slirp *slirp_init(int restricted, struct in_addr vnetwork,
>      slirp->tftp_prefix = g_strdup(tftp_path);
>      slirp->bootp_filename = g_strdup(bootfile);
>      slirp->vdhcp_startaddr = vdhcp_start;
> +    slirp->vnext_server = vnext_server;
>      slirp->vnameserver_addr = vnameserver;
>  
>      if (vdnssearch) {
> diff --git a/slirp/slirp.h b/slirp/slirp.h
> index fe0e65d..a28a8d1 100644
> --- a/slirp/slirp.h
> +++ b/slirp/slirp.h
> @@ -209,6 +209,7 @@ struct Slirp {
>      struct in_addr vnetwork_mask;
>      struct in_addr vhost_addr;
>      struct in_addr vdhcp_startaddr;
> +    struct in_addr vnext_server;
>      struct in_addr vnameserver_addr;
>  
>      struct in_addr client_ipaddr;
> -- 
> 1.8.3.1
> 
>
Eric Blake - July 1, 2013, 8:51 p.m.
On 06/21/2013 07:20 AM, Bas van Sisseren wrote:
> The slirp dhcp-server normally returns its own address as tftp
> nextserver for netbooting. This patch makes that address
> configurable, so it is possible to use an external tftp boot-
> environment.
> 
> Signed-off-by: Bas van Sisseren <bas@quarantainenet.nl>
> ---
>  net/slirp.c      | 10 ++++++++--

> +++ b/qapi-schema.json
> @@ -2537,6 +2537,8 @@
>  # @dhcpstart: #optional the first of the 16 IPs the built-in DHCP server can
>  #             assign
>  #
> +# @nextserver: #optional IP address of BOOTP server
> +#

Please mark this field as '(since 1.6)'.  Does the field work for both
IPv4 and IPv6 addresses?

>  # @dns: #optional guest-visible address of the virtual nameserver
>  #
>  # @dnssearch: #optional list of DNS suffixes to search, passed as DHCP option
> @@ -2563,6 +2565,7 @@
>      '*tftp':      'str',
>      '*bootfile':  'str',
>      '*dhcpstart': 'str',
> +    '*nextserver': 'str',

This is a command addition that libvirt can't take advantage of unless
we get introspection working in a timely manner.
Bas van Sisseren - July 2, 2013, 1:03 p.m.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 01/07/13 22:51, Eric Blake wrote:
> On 06/21/2013 07:20 AM, Bas van Sisseren wrote:
>> The slirp dhcp-server normally returns its own address as tftp
>> nextserver for netbooting. This patch makes that address
>> configurable, so it is possible to use an external tftp boot-
>> environment.
>>
>> Signed-off-by: Bas van Sisseren <bas@quarantainenet.nl>
>> ---
>>  net/slirp.c      | 10 ++++++++--
> 
>> +++ b/qapi-schema.json
>> @@ -2537,6 +2537,8 @@
>>  # @dhcpstart: #optional the first of the 16 IPs the built-in DHCP server can
>>  #             assign
>>  #
>> +# @nextserver: #optional IP address of BOOTP server
>> +#
> 
> Please mark this field as '(since 1.6)'.

Added in my local checkout. I now have to find out how to generate a new
patch and post it into this thread. I'll try to post a new patch somewhere
in the next days. (I'm new to git :-) )


> Does the field work for both IPv4 and IPv6 addresses?

This setting is IPv4 only. (btw, I think all slirp settings are IPv4 only)


>>  # @dns: #optional guest-visible address of the virtual nameserver
>>  #
>>  # @dnssearch: #optional list of DNS suffixes to search, passed as DHCP option
>> @@ -2563,6 +2565,7 @@
>>      '*tftp':      'str',
>>      '*bootfile':  'str',
>>      '*dhcpstart': 'str',
>> +    '*nextserver': 'str',
> 
> This is a command addition that libvirt can't take advantage of unless
> we get introspection working in a timely manner.

It would be a nice addition to libvirt, but is it a problem that libvirt
doesn't support all new settings (yet)?


Met vriendelijke groet,

Bas van Sisseren

- -- 
Bas van Sisseren <bas@quarantainenet.nl>
Quarantainenet
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.12 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/

iEYEARECAAYFAlHSz4sACgkQ19+8tHrpflo3gACgjHd8ApumOrsxN4Wv9nPxsvoJ
r6QAnjTKcoxJ6M3q5oZxauNmFsseYw5b
=rirP
-----END PGP SIGNATURE-----
Eric Blake - July 2, 2013, 1:19 p.m.
On 07/02/2013 07:03 AM, Bas van Sisseren wrote:
>>> +# @nextserver: #optional IP address of BOOTP server
>>> +#
> 
>> Please mark this field as '(since 1.6)'.
> 
> Added in my local checkout. I now have to find out how to generate a new
> patch and post it into this thread. I'll try to post a new patch somewhere
> in the next days. (I'm new to git :-) )

Feel free to ask questions.  Also, see if the wiki page
http://wiki.qemu.org/Contribute/SubmitAPatch helps, or could be improved.

My typical workflow for amending a series to address review comments is
to 'git rebase -i', change the marker on patches I intend to modify from
'pick' to edit' on the screen it pulls up, then exit that editor.  From
there, git will apply patches in turn, halting on each patch I marked
for edit, where I can make the changes, 'git add' them, then 'git rebase
--continue' to merge them into the patch series in the right place.
Read 'git rebase --help' for a lot more hints on what it can do.

>> Does the field work for both IPv4 and IPv6 addresses?
> 
> This setting is IPv4 only. (btw, I think all slirp settings are IPv4 only)

Just making sure we are considering things if it matters; but it sounds
like it doesn't matter here.

>>>  # @dns: #optional guest-visible address of the virtual nameserver
>>>  #
>>>  # @dnssearch: #optional list of DNS suffixes to search, passed as DHCP option
>>> @@ -2563,6 +2565,7 @@
>>>      '*tftp':      'str',
>>>      '*bootfile':  'str',
>>>      '*dhcpstart': 'str',
>>> +    '*nextserver': 'str',
> 
>> This is a command addition that libvirt can't take advantage of unless
>> we get introspection working in a timely manner.
> 
> It would be a nice addition to libvirt, but is it a problem that libvirt
> doesn't support all new settings (yet)?

The problem is that libvirt supports multiple versions of qemu, but
wants to provide sane error messages to the user.  If we add a mapping
to libvirt to expose this new parameter, then libvirt would like to know
whether the qemu version on the user's machine is new enough to honor
that mapping, or old enough to need an upgrade.  A version number check
is not ideal, because distros like to backport features without bumping
the version number (for instance, RHEL 6 ships a qemu that calls itself
0.12.xx, yet behaves like 1.5 for certain features).  Creating a new
qemu command works (if the command exists or does not exist, libvirt
knows the answer without too much effort).  Introspection would let
libvirt do a query: "what fields does this command support"; and if
nextserver is in (or not in) the list, then libvirt knows the answer
without too much effort.  But introspection is not incorporated yet
(we're working on it, and still hopeful it will make 1.6); so that
leaves us with only one other option for discovering if an optional
parameter is supported - try the command and see if it fails.  This is
not as friendly, and depending on the command may have other negative
side effects from even attempting the command at all.

While that's the theory behind QMP additions, there's also the matter
that libvirt won't support the new option at all (whether via
introspection or try-and-fail probing) unless someone writes a patch for
libvirt.  On the other hand, the schedule at which libvirt adds support
for qemu features shouldn't hold up whether qemu adds the features,
since there are more users of qemu than just libvirt.

Patch

diff --git a/net/slirp.c b/net/slirp.c
index 124e953..f3e239c 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -136,6 +136,7 @@  static int net_slirp_init(NetClientState *peer, const char *model,
                           const char *vnetwork, const char *vhost,
                           const char *vhostname, const char *tftp_export,
                           const char *bootfile, const char *vdhcp_start,
+                          const char *vnextserver,
                           const char *vnameserver, const char *smb_export,
                           const char *vsmbserver, const char **dnssearch)
 {
@@ -145,6 +146,7 @@  static int net_slirp_init(NetClientState *peer, const char *model,
     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 in_addr nxtsrv = { .s_addr = 0 };
 #ifndef _WIN32
     struct in_addr smbsrv = { .s_addr = 0 };
 #endif
@@ -228,6 +230,10 @@  static int net_slirp_init(NetClientState *peer, const char *model,
         return -1;
     }
 
+    if (vnextserver && !inet_aton(vnextserver, &nxtsrv)) {
+        return -1;
+    }
+
 #ifndef _WIN32
     if (vsmbserver && !inet_aton(vsmbserver, &smbsrv)) {
         return -1;
@@ -243,7 +249,7 @@  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);
+                          tftp_export, bootfile, dhcp, nxtsrv, dns, dnssearch, s);
     QTAILQ_INSERT_TAIL(&slirp_stacks, s, entry);
 
     for (config = slirp_configs; config; config = config->next) {
@@ -751,7 +757,7 @@  int net_init_slirp(const NetClientOptions *opts, const char *name,
 
     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->bootfile, user->dhcpstart, user->nextserver, user->dns, user->smb,
                          user->smbserver, dnssearch);
 
     while (slirp_configs) {
diff --git a/qapi-schema.json b/qapi-schema.json
index a80ee40..a8e2c3d 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -2537,6 +2537,8 @@ 
 # @dhcpstart: #optional the first of the 16 IPs the built-in DHCP server can
 #             assign
 #
+# @nextserver: #optional IP address of BOOTP server
+#
 # @dns: #optional guest-visible address of the virtual nameserver
 #
 # @dnssearch: #optional list of DNS suffixes to search, passed as DHCP option
@@ -2563,6 +2565,7 @@ 
     '*tftp':      'str',
     '*bootfile':  'str',
     '*dhcpstart': 'str',
+    '*nextserver': 'str',
     '*dns':       'str',
     '*dnssearch': ['String'],
     '*smb':       'str',
diff --git a/qemu-options.hx b/qemu-options.hx
index 8355f9b..8afe42a 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1350,7 +1350,7 @@  DEF("net", HAS_ARG, QEMU_OPTION_net,
 #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"
-    "         [,bootfile=f][,hostfwd=rule][,guestfwd=rule]"
+    "         [,bootfile=f][,nextserver=addr][,hostfwd=rule][,guestfwd=rule]"
 #ifndef _WIN32
                                              "[,smb=dir[,smbserver=addr]]\n"
 #endif
@@ -1498,6 +1498,9 @@  When using the user mode network stack, broadcast @var{file} as the BOOTP
 filename. In conjunction with @option{tftp}, this can be used to network boot
 a guest from a local directory.
 
+@item nextserver=@var{addr}
+Specify the IP address of the TFTP server.
+
 Example (using pxelinux):
 @example
 qemu-system-i386 -hda linux.img -boot n -net user,tftp=/path/to/tftp/files,bootfile=/pxelinux.0
diff --git a/slirp/bootp.c b/slirp/bootp.c
index b7db9fa..d2e89d6 100644
--- a/slirp/bootp.c
+++ b/slirp/bootp.c
@@ -227,7 +227,11 @@  static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
     memcpy(rbp->bp_hwaddr, bp->bp_hwaddr, ETH_ALEN);
 
     rbp->bp_yiaddr = daddr.sin_addr; /* Client IP address */
-    rbp->bp_siaddr = saddr.sin_addr; /* Server IP address */
+    if (slirp->vnext_server.s_addr == 0) {
+        rbp->bp_siaddr = saddr.sin_addr; /* Server IP address */
+    } else {
+        rbp->bp_siaddr = slirp->vnext_server; /* Next-Server address */
+    }
 
     q = rbp->bp_vend;
     memcpy(q, rfc1533_cookie, 4);
diff --git a/slirp/libslirp.h b/slirp/libslirp.h
index ceabff8..c3d800b 100644
--- a/slirp/libslirp.h
+++ b/slirp/libslirp.h
@@ -12,6 +12,7 @@  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 vnext_server,
                   struct in_addr vnameserver, const char **vdnssearch,
                   void *opaque);
 void slirp_cleanup(Slirp *slirp);
diff --git a/slirp/slirp.c b/slirp/slirp.c
index 80b28ea..35f2afd 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -200,6 +200,7 @@  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 vnext_server,
                   struct in_addr vnameserver, const char **vdnssearch,
                   void *opaque)
 {
@@ -225,6 +226,7 @@  Slirp *slirp_init(int restricted, struct in_addr vnetwork,
     slirp->tftp_prefix = g_strdup(tftp_path);
     slirp->bootp_filename = g_strdup(bootfile);
     slirp->vdhcp_startaddr = vdhcp_start;
+    slirp->vnext_server = vnext_server;
     slirp->vnameserver_addr = vnameserver;
 
     if (vdnssearch) {
diff --git a/slirp/slirp.h b/slirp/slirp.h
index fe0e65d..a28a8d1 100644
--- a/slirp/slirp.h
+++ b/slirp/slirp.h
@@ -209,6 +209,7 @@  struct Slirp {
     struct in_addr vnetwork_mask;
     struct in_addr vhost_addr;
     struct in_addr vdhcp_startaddr;
+    struct in_addr vnext_server;
     struct in_addr vnameserver_addr;
 
     struct in_addr client_ipaddr;