qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH 1/1] Making pxe working in the "NAT" mode


From: Anthony Liguori
Subject: Re: [Qemu-devel] [PATCH 1/1] Making pxe working in the "NAT" mode
Date: Thu, 15 Feb 2007 21:49:13 -0600
User-agent: Thunderbird 1.5.0.9 (X11/20070103)

Erwan Velu wrote:
Hey folks,
I saw the lastest qemu support pxe so I tried it using the following command:

qemu -hda /tmp/a.img -net nic n- user -boot n

Note that now qemu support pxe mode, the mandatory -hda option is no more mandatory but this is not directly linked to my patch. I saw qemu integrates a dhcp & a tftp server but they don't seems to be configured/developped for a pxe boot process.
Qemu says "no filename" and exits.

Hi Erwan,

I really like the idea of your patch. Of course, the hard coding is not really reasonable :-) Also, PXE is an x86-ism. What you've really done is added a mechanism to publish a BOOTP name. We do need to add a new option too as one may want to use -boot n without publishing a BOOTP filename.

Using your patch as a basis, I've written three patches. The first one is the tsize negotiation fix for the TFTP server. The second adds a -bootp option for specifying the location of the BOOTP image. The third changes the -tftp option to take root directory. The end result, is that now you can say:

qemu -hda /tmp/a.img -boot n -tftp ~/tftpboot -bootp /pxelinux.0

And you get the same results without the hard coding.  What do you think?

Regards,

Anthony Liguori

A friend of I asked me "how do you boot using pxe in qemu when you don't have a dhcp & a tftp server ?". So I started to look how we can do that, I modified bootp to catch the field 60 of a dhcp request to find if its a pxe request or not. If yes, I set the filename to "/pxelinux.0", currently this is harcoded, maybe you can help me to find a better way to specify a bootloader.

Then, I've patched the tftp server to change the default rootdir in my home dir. "~/tftpboot". This is just for a Proof-of-concept, other methods could be fine. We can also imagine searching in a path restricted to the admin and then in the user dir. So it can give the admin the ability of defining some pxe boot for all the vm of a system or in the user dir if the user wants to have a special pxe boot scheme.

The last patch I did on the tftp server, is to allow the tsize negociation because pxelinux needs it.

This patch apply to 0.9.0, once it is applied and compiled here come the test procedure:

create a ~/tftpboot/pxelinux.cfg directory
copy pxelinux.0 in ~/tfptboot/
create a pxelinux configuration file called "default" in ~/tftpboot/pxelinux.cfg

Et voila ;)

Just call "qemu -hda /tmp/a.img -net nic n- user -boot n", it will start pxelinux.

I think this patch is very usefull because it give users & admin the ability to use pxe inside the VM without installing the full configuration (dhcp,tftp). This patch is mainly a proof-of-concept, this patch can be improved, comments and feedback are welcome.
_______________________________________________
Qemu-devel mailing list
address@hidden
http://lists.nongnu.org/mailman/listinfo/qemu-devel

diff -r ea5eb79ade8d slirp/bootp.c
--- a/slirp/bootp.c     Thu Feb 15 16:49:28 2007 -0600
+++ b/slirp/bootp.c     Thu Feb 15 16:49:30 2007 -0600
@@ -38,6 +38,8 @@ typedef struct {
 
 BOOTPClient bootp_clients[NB_ADDR];
 
+const char *bootp_filename;
+
 static const uint8_t rfc1533_cookie[] = { RFC1533_COOKIE };
 
 #ifdef DEBUG
@@ -168,6 +170,10 @@ static void bootp_reply(struct bootp_t *
             goto new_addr;
         }
     }
+
+    if (bootp_filename)
+        snprintf(rbp->bp_file, sizeof(rbp->bp_file), "%s", bootp_filename);
+
     dprintf("offered addr=%08x\n", ntohl(daddr.sin_addr.s_addr));
 
     saddr.sin_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_ALIAS);
diff -r ea5eb79ade8d vl.c
--- a/vl.c      Thu Feb 15 16:49:28 2007 -0600
+++ b/vl.c      Thu Feb 15 16:57:07 2007 -0600
@@ -6488,6 +6488,7 @@ void help(void)
            "\n"
 #ifdef CONFIG_SLIRP
            "-tftp prefix    allow tftp access to files starting with prefix 
[-net user]\n"
+           "-bootp file     advertise file in BOOTP replies\n"
 #ifndef _WIN32
            "-smb dir        allow SMB access to files in 'dir' [-net user]\n"
 #endif
@@ -6576,6 +6577,7 @@ enum {
 
     QEMU_OPTION_net,
     QEMU_OPTION_tftp,
+    QEMU_OPTION_bootp,
     QEMU_OPTION_smb,
     QEMU_OPTION_redir,
 
@@ -6652,6 +6654,7 @@ const QEMUOption qemu_options[] = {
     { "net", HAS_ARG, QEMU_OPTION_net},
 #ifdef CONFIG_SLIRP
     { "tftp", HAS_ARG, QEMU_OPTION_tftp },
+    { "bootp", HAS_ARG, QEMU_OPTION_bootp },
 #ifndef _WIN32
     { "smb", HAS_ARG, QEMU_OPTION_smb },
 #endif
@@ -7185,6 +7188,9 @@ int main(int argc, char **argv)
             case QEMU_OPTION_tftp:
                tftp_prefix = optarg;
                 break;
+            case QEMU_OPTION_bootp:
+                bootp_filename = optarg;
+                break;
 #ifndef _WIN32
             case QEMU_OPTION_smb:
                net_slirp_smb(optarg);
diff -r ea5eb79ade8d vl.h
--- a/vl.h      Thu Feb 15 16:49:28 2007 -0600
+++ b/vl.h      Thu Feb 15 16:49:30 2007 -0600
@@ -163,6 +163,7 @@ extern int no_quit;
 extern int no_quit;
 extern int semihosting_enabled;
 extern int autostart;
+extern const char *bootp_filename;
 
 #define MAX_OPTION_ROMS 16
 extern const char *option_rom[MAX_OPTION_ROMS];
diff -r ea5eb79ade8d qemu-doc.texi
--- a/qemu-doc.texi     Thu Feb 15 16:49:28 2007 -0600
+++ b/qemu-doc.texi     Thu Feb 15 16:57:23 2007 -0600
@@ -445,6 +445,16 @@ guest must be configured in binary mode 
 guest must be configured in binary mode (use the command @code{bin} of
 the Unix TFTP client). The host IP address on the guest is as usual
 10.0.2.2.
+
address@hidden -bootp file
+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.
+
+Example (using pxelinux):
address@hidden
+qemu -hda linux.img -boot n -tftp /path/to/tftp/files -bootp /pxelinux.0
address@hidden example
 
 @item -smb dir
 When using the user mode network stack, activate a built-in SMB
diff -r 153828edbad3 slirp/tftp.c
--- a/slirp/tftp.c      Thu Feb 15 16:37:56 2007 -0600
+++ b/slirp/tftp.c      Thu Feb 15 21:37:26 2007 -0600
@@ -120,6 +120,45 @@ static int tftp_read_data(struct tftp_se
   return bytes_read;
 }
 
+static int tftp_send_oack(struct tftp_session *spt, 
+                          const char *key, uint32_t value,
+                          struct tftp_t *recv_tp)
+{
+    struct sockaddr_in saddr, daddr;
+    struct mbuf *m;
+    struct tftp_t *tp;
+    int n = 0;
+
+    m = m_get();
+
+    if (!m)
+       return -1;
+
+    memset(m->m_data, 0, m->m_size);
+
+    m->m_data += if_maxlinkhdr;
+    tp = (void *)m->m_data;
+    m->m_data += sizeof(struct udpiphdr);
+    
+    tp->tp_op = htons(TFTP_OACK);
+    n += sprintf(tp->x.tp_buf + n, "%s", key) + 1;
+    n += sprintf(tp->x.tp_buf + n, "%u", value) + 1;
+
+    saddr.sin_addr = recv_tp->ip.ip_dst;
+    saddr.sin_port = recv_tp->udp.uh_dport;
+    
+    daddr.sin_addr = spt->client_ip;
+    daddr.sin_port = spt->client_port;
+
+    m->m_len = sizeof(struct tftp_t) - 514 + n - 
+        sizeof(struct ip) - sizeof(struct udphdr);
+    udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
+
+    return 0;
+}
+
+
+
 static int tftp_send_error(struct tftp_session *spt, 
                           u_int16_t errorcode, const char *msg,
                           struct tftp_t *recv_tp)
@@ -273,6 +312,8 @@ static void tftp_handle_rrq(struct tftp_
       return;
   }
 
+  k += 6;/* skipping octet*/
+
   /* do sanity checks on the filename */
 
   if ((spt->filename[0] != '/')
@@ -297,6 +338,48 @@ static void tftp_handle_rrq(struct tftp_
       return;
   }
 
+  if (src[n - 1] != 0) {
+      tftp_send_error(spt, 2, "Access violation", tp);
+      return;
+  }
+
+  while (k < n) {
+      const char *key, *value;
+
+      key = src + k;
+      k += strlen(key) + 1;
+
+      if (k >= n) {
+         tftp_send_error(spt, 2, "Access violation", tp);
+         return;
+      }
+
+      value = src + k;
+      k += strlen(value) + 1;
+
+      if (strcmp(key, "tsize") == 0) {
+         int tsize = atoi(value);
+         struct stat stat_p;
+
+         if (tsize == 0 && tftp_prefix) {
+             char buffer[1024];
+             int len;
+
+             len = snprintf(buffer, sizeof(buffer), "%s/%s",
+                            tftp_prefix, spt->filename);
+
+             if (stat(buffer, &stat_p) == 0)
+                 tsize = stat_p.st_size;
+             else {
+                 tftp_send_error(spt, 1, "File not found", tp);
+                 return;
+             }
+         }
+
+         tftp_send_oack(spt, "tsize", tsize, tp);
+      }
+  }
+
   tftp_send_data(spt, 1, tp);
 }
 
diff -r 153828edbad3 slirp/tftp.h
--- a/slirp/tftp.h      Thu Feb 15 16:37:56 2007 -0600
+++ b/slirp/tftp.h      Thu Feb 15 16:37:57 2007 -0600
@@ -9,6 +9,7 @@
 #define TFTP_DATA   3
 #define TFTP_ACK    4
 #define TFTP_ERROR  5
+#define TFTP_OACK   6
 
 #define TFTP_FILENAME_MAX 512
 
diff -r 91f98dfbdc3f qemu-doc.texi
--- a/qemu-doc.texi     Thu Feb 15 21:22:02 2007 -0600
+++ b/qemu-doc.texi     Thu Feb 15 21:22:03 2007 -0600
@@ -438,13 +438,12 @@ override the default configuration (@opt
 override the default configuration (@option{-net nic -net user}) which
 is activated if no @option{-net} options are provided.
 
address@hidden -tftp prefix
address@hidden -tftp dir
 When using the user mode network stack, activate a built-in TFTP
-server. All filenames beginning with @var{prefix} can be downloaded
-from the host to the guest using a TFTP client. The TFTP client on the
-guest must be configured in binary mode (use the command @code{bin} of
-the Unix TFTP client). The host IP address on the guest is as usual
-10.0.2.2.
+server. The files in @var{dir} will be exposed as the root of a TFTP server.
+The TFTP client on the guest must be configured in binary mode (use the command
address@hidden of the Unix TFTP client). The host IP address on the guest is as
+usual 10.0.2.2.
 
 @item -bootp file
 When using the user mode network stack, broadcast @var{file} as the BOOTP
diff -r 91f98dfbdc3f slirp/tftp.c
--- a/slirp/tftp.c      Thu Feb 15 21:22:02 2007 -0600
+++ b/slirp/tftp.c      Thu Feb 15 21:22:03 2007 -0600
@@ -102,8 +102,15 @@ static int tftp_read_data(struct tftp_se
 {
   int fd;
   int bytes_read = 0;
-
-  fd = open(spt->filename, O_RDONLY | O_BINARY);
+  char buffer[1024];
+  int n;
+
+  n = snprintf(buffer, sizeof(buffer), "%s/%s",
+              tftp_prefix, spt->filename);
+  if (n >= sizeof(buffer))
+    return -1;
+
+  fd = open(buffer, O_RDONLY | O_BINARY);
 
   if (fd < 0) {
     return -1;
@@ -328,8 +335,7 @@ static void tftp_handle_rrq(struct tftp_
 
   /* only allow exported prefixes */
 
-  if (!tftp_prefix
-      || (strncmp(spt->filename, tftp_prefix, strlen(tftp_prefix)) != 0)) {
+  if (!tftp_prefix) {
       tftp_send_error(spt, 2, "Access violation", tp);
       return;
   }
diff -r 91f98dfbdc3f vl.c
--- a/vl.c      Thu Feb 15 21:22:02 2007 -0600
+++ b/vl.c      Thu Feb 15 21:22:03 2007 -0600
@@ -6487,7 +6487,7 @@ void help(void)
            "                is provided, the default is '-net nic -net user'\n"
            "\n"
 #ifdef CONFIG_SLIRP
-           "-tftp prefix    allow tftp access to files starting with prefix 
[-net user]\n"
+           "-tftp dir       allow tftp access to files in dir [-net user]\n"
            "-bootp file     advertise file in BOOTP replies\n"
 #ifndef _WIN32
            "-smb dir        allow SMB access to files in 'dir' [-net user]\n"

reply via email to

[Prev in Thread] Current Thread [Next in Thread]