[Top][All Lists]
[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
- [Qemu-devel] [PATCH 1/1] Making pxe working in the "NAT" mode,
Erwan Velu <=