qemu-devel
[Top][All Lists]
Advanced

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

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


From: Erwan Velu
Subject: [Qemu-devel] [PATCH 1/1] Making pxe working in the "NAT" mode
Date: Wed, 14 Feb 2007 23:16:12 +0100
User-agent: Thunderbird 1.5.0.9 (X11/20070111)

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.

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.
diff -rub slirp.old/bootp.c slirp/bootp.c
--- slirp.old/bootp.c   2007-02-06 00:01:54.000000000 +0100
+++ slirp/bootp.c       2007-02-14 22:44:02.000000000 +0100
@@ -82,7 +82,7 @@
 }
 
 static void dhcp_decode(const uint8_t *buf, int size,
-                        int *pmsg_type)
+                        int *pmsg_type, int *pxe_request)
 {
     const uint8_t *p, *p_end;
     int len, tag;
@@ -114,6 +114,11 @@
                 if (len >= 1)
                     *pmsg_type = p[0];
                 break;
+            case RFC1533_CLASSIDENTIFIER:
+               if ((strncmp(p,"PXEClient",9) == 0) || 
(strncmp(p,"Etherboot",9) == 0)) {
+                    *pxe_request=1;
+               }
+               break;
             default:
                 break;
             }
@@ -131,9 +136,10 @@
     struct in_addr dns_addr;
     int dhcp_msg_type, val;
     uint8_t *q;
+    int pxe_request=0;
 
     /* extract exact DHCP msg type */
-    dhcp_decode(bp->bp_vend, DHCP_OPT_LEN, &dhcp_msg_type);
+    dhcp_decode(bp->bp_vend, DHCP_OPT_LEN, &dhcp_msg_type,&pxe_request);
     dprintf("bootp packet op=%d msgtype=%d\n", bp->bp_op, dhcp_msg_type);
     
     if (dhcp_msg_type == 0)
@@ -168,6 +174,12 @@
             goto new_addr;
         }
     }
+
+    if (pxe_request==1) {
+           printf("PXE Request Detected, setting filename\n");
+           strcpy(rbp->bp_file,"/pxelinux.0");
+    }
+
     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 -rub slirp.old/bootp.h slirp/bootp.h
--- slirp.old/bootp.h   2007-02-06 00:01:54.000000000 +0100
+++ slirp/bootp.h       2007-02-14 22:12:48.000000000 +0100
@@ -57,6 +57,7 @@
 #define RFC1533_NBSCOPE                47
 #define RFC1533_XFS            48
 #define RFC1533_XDM            49
+#define RFC1533_CLASSIDENTIFIER 60
 
 #define RFC2132_REQ_ADDR       50
 #define RFC2132_LEASE_TIME      51
Seulement dans slirp: bootp.h~
Seulement dans slirp: debug.c~
diff -rub slirp.old/tftp.c slirp/tftp.c
--- slirp.old/tftp.c    2007-02-06 00:01:54.000000000 +0100
+++ slirp/tftp.c        2007-02-14 22:09:16.000000000 +0100
@@ -120,6 +120,49 @@
   return bytes_read;
 }
 
+static int tftp_send_oack(struct tftp_session *spt, 
+                          int errorcode, const char *msg,
+                          struct tftp_t *recv_tp)
+{
+  struct sockaddr_in saddr, daddr;
+  struct mbuf *m;
+  struct tftp_t *tp;
+  int nobytes;
+  char errcode[16];
+  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);
+  strcpy(tp->x.tp_buf,msg);
+  sprintf(tp->x.tp_buf+strlen(msg)+1,"%u",errorcode);
+  sprintf(errcode,"%u",errorcode);
+
+  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;
+
+  nobytes = 2;
+
+  m->m_len = sizeof(struct tftp_t) - 514 + 2 + strlen(errcode) + strlen(msg) - 
+        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)
@@ -227,8 +270,12 @@
 static void tftp_handle_rrq(struct tftp_t *tp, int pktlen)
 {
   struct tftp_session *spt;
-  int s, k, n;
+  int s, k, n, blksize,tsize;
   u_int8_t *src, *dst;
+  char *blksize_pos, *tsize_pos;
+
+  char tftp_path[TFTP_FILENAME_MAX];
+  struct stat stat_p; 
 
   s = tftp_session_allocate(tp);
 
@@ -261,6 +308,9 @@
     return;
   }
   
+  snprintf(tftp_path,TFTP_FILENAME_MAX, "%s%s%s",getenv("HOME"),"/tftpboot", 
spt->filename);
+  strncpy((char *)spt->filename,tftp_path,TFTP_FILENAME_MAX);
+  
   k++;
   
   /* check mode */
@@ -273,6 +323,34 @@
       return;
   }
 
+ k+=6;/* skipping octet*/
+
+ /* Looking for other options*/ 
+ while (k<n) {
+   blksize_pos=strstr(&src[k],"blksize");
+   if (blksize_pos != NULL) {
+       blksize=atoi(blksize_pos+strlen("blksize")+1);
+       k+=strlen("blksize")+strlen(blksize_pos+strlen("blksize")+1);
+   }
+
+   tsize_pos=strstr(&src[k],"tsize");
+   if (tsize_pos != NULL) {
+       tsize=atoi(tsize_pos+strlen("tsize")+1);
+       if (tsize==0) {
+                /* we need to return the file size to the client*/
+                if ( stat (spt->filename, &stat_p) == 0 ) {
+                       tsize=stat_p.st_size;
+                } else  {
+                       tftp_send_error(spt, 1, "File not found", tp);
+                }
+       }
+       tftp_send_oack(spt,tsize,"tsize",tp);
+       k+=strlen("tsize")+strlen(tsize_pos+strlen("tsize")+1);
+   }
+ k++;
+ }
+
+#if 0
   /* do sanity checks on the filename */
 
   if ((spt->filename[0] != '/')
@@ -289,6 +367,7 @@
       tftp_send_error(spt, 2, "Access violation", tp);
       return;
   }
+#endif
 
   /* check if the file exists */
   
diff -rub slirp.old/tftp.h slirp/tftp.h
--- slirp.old/tftp.h    2007-02-06 00:01:54.000000000 +0100
+++ slirp/tftp.h        2007-02-14 22:09:36.000000000 +0100
@@ -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
 

reply via email to

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