All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] pypxeboot bootloader
@ 2007-02-05 11:13 Stephen Childs
  2007-02-05 17:36 ` Tim Deegan
  0 siblings, 1 reply; 13+ messages in thread
From: Stephen Childs @ 2007-02-05 11:13 UTC (permalink / raw)
  To: xen-devel

[-- Attachment #1: Type: text/plain, Size: 402 bytes --]

As promised on Friday here is the patch for the pypxeboot bootloader. It 
would be great if someone could try it out and give me some feedback.

Stephen
-- 
Dr. Stephen Childs,
Research Fellow, EGEE Project,    phone:                    +353-1-8961797
Computer Architecture Group,      email:        Stephen.Childs @ cs.tcd.ie
Trinity College Dublin, Ireland   web: http://www.cs.tcd.ie/Stephen.Childs

[-- Attachment #2: childss_pypxeboot_patch --]
[-- Type: text/plain, Size: 15241 bytes --]

# HG changeset patch
# User childss@tg23.testgrid
# Date 1170673641 0
# Node ID 7f1a38c5c08659ae123e5f94696cbca19e4e10fb
# Parent  01ec7dba9ff805a5c74a0318997b747d3e3e3327
Added pypxeboot bootloader for simulating PXE boot for DomUs.
Signed-off-by: Stephen Childs <childss@cs.tcd.ie>

diff -r 01ec7dba9ff8 -r 7f1a38c5c086 tools/pypxeboot/README
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/pypxeboot/README	Mon Feb 05 11:07:21 2007 +0000
@@ -0,0 +1,44 @@
+pypxeboot is a bootloader for xen that simulates PXE behaviour. It runs on 
+Domain 0 as part of the domain creation process and downloads boot information
+from a previously-configured PXELinux server using TFTP.
+
+pypxeboot requires the following external programs:
+
+1) A patched version of udhcp 0.9.8 (http://udhcp.busybox.net/) that supports 
+a user-specified MAC address. The patch is udhcp_usermac.patch, available
+in this distribution. There is also a script needed to output information
+received from the DHCP server. This is called outputpy.udhcp.sh and
+should be installed at /usr/share/udhcpc/
+
+2) The tftp client program (http://www.kernel.org/pub/software/network/tftp/). 
+RPMs are also available from the DAG repository at
+(http://dag.wieers.com/rpm/packages/tftp/)
+
+To use pypxeboot, add the following lines to your Xen domain configuration
+file:
+
+bootloader="/usr/bin/pypxeboot"
+bootargs=vif[0]
+
+If the pxelinux.cfg entry is set to localboot you should see output like this:
+
+[root@tg23 pypxeboot]# xm create  cagnode50-slc308
+Using config file "/etc/xen/cagnode50-slc308".
+pypxeboot: requesting info for MAC address AA:00:86:e2:35:72
+pypxeboot: getting cfg for IP 134.226.53.114 (86E23572) from server 192.168.12.1
+pypxeboot: dropping to pygrub for local boot
+Going to boot Scientific Linux CERN Xen DomU-xenU (2.4.21-47.0.1.EL.cernxenU)
+  kernel: /vmlinuz-2.4.21-47.0.1.EL.cernxenU
+  initrd: /initrd-2.4.21-47.0.1.EL.cernxenU.img
+
+and something like this if the pxelinux.cfg entry specifies a network boot:
+
+[root@tg23 pypxeboot]# xm create  cagnode50-slc308
+Using config file "/etc/xen/cagnode50-slc308".
+pypxeboot: requesting info for MAC address AA:00:86:e2:35:72
+pypxeboot: getting cfg for IP 134.226.53.114 (86E23572) from server 192.168.12.1
+pypxeboot: downloading initrd using cmd: tftp -c get 192.168.12.1:slc308_i386_xen/initrd.img
+pypxeboot: downloading kernel using cmd: tftp -c get 192.168.12.1:slc308_i386_xen/vmlinuz
+Started domain cagnode50
+
+The kernel and initrd on the tftp server need to be XenLinux images.
diff -r 01ec7dba9ff8 -r 7f1a38c5c086 tools/pypxeboot/outputpy.udhcp.sh
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/pypxeboot/outputpy.udhcp.sh	Mon Feb 05 11:07:21 2007 +0000
@@ -0,0 +1,42 @@
+#!/bin/sh
+#
+# outputpy.udhcp.sh: a simple script called by udhcpc when a lease is
+# obtained. The script takes information passed by udhcpc as environment
+# variables and outputs it formatted as a python dict. Only the variables
+# needed by pypxeboot are currently printed: others are listed in comments
+# for reference.
+# Copyright 2007 Trinity College Dublin
+# Author: Stephen Childs <childss@cs.tcd.ie>
+
+# we only need to process "bound" events
+if [ "$1" == "bound" ]; then
+echo "{ 'ip' : '$ip', 'siaddr' : '$siaddr', 'sname' : '$sname', \
+'boot_file' : '$boot_file', \
+'subnet' : '$subnet', \
+'timezone' : '$timezone', \
+'router' : '$router', \
+'bootfile' : '$bootfile'}" #        - The bootfile name
+fi
+exit 0
+
+#        timesvr         - A list of time servers
+#        namesvr 
+#        dns  
+#        logsvr          - A list of MIT-LCS UDP log servers
+#        cookiesvr       - A list of RFC 865 cookie servers
+#        lprsvr          - A list of LPR servers
+#        hostname        - The assigned hostname
+#        bootsize        - The length in 512 octect blocks of the bootfile
+#        domain          - The domain name of the network
+#        swapsvr         - The IP address of the client's swap server
+#        rootpath        - The path name of the client's root disk
+#        ipttl           - The TTL to use for this network
+#        mtu             - The MTU to use for this network
+#        broadcast       - The broadcast address for this network
+#        ntpsrv          - A list of NTP servers
+#        wins            - A list of WINS servers
+#        lease           - The lease time, in seconds
+#        dhcptype        - DHCP message type (safely ignored)
+#        serverid        - The IP of the server
+#        message         - Reason for a DHCPNAK
+#        tftp            - The TFTP server name
diff -r 01ec7dba9ff8 -r 7f1a38c5c086 tools/pypxeboot/pypxeboot
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/pypxeboot/pypxeboot	Mon Feb 05 11:07:21 2007 +0000
@@ -0,0 +1,202 @@
+#!/usr/bin/python
+#
+# pypxeboot - simple python-based bootloader to fake PXE booting for Xen DomUs
+# Uses a modified version of udhcpc that allows MAC address to be passed on
+# the command line. Also uses tftp client to download configuration and images
+#
+# Copyright 2007 Trinity College Dublin
+# Stephen Childs <childss@cs.tcd.ie>
+#
+# This software may be freely redistributed under the terms of the GNU
+# general public license.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+import commands,sys,re,os,getopt
+
+udhcpc_command="/usr/bin/udhcpc"
+udhcpc_script="/usr/share/udhcpc/outputpy.udhcp.sh"
+havekernelargs=False
+
+def run_pygrub():
+    arglist=[]
+    for arg in sys.argv[1:]:
+        if not (macre.match(arg)):
+            arglist.append(arg)
+
+    program="/usr/bin/pygrub"
+
+    os.execvp(program, (program,) +  tuple(arglist))
+
+def tftp_success(statusoutput):
+    errorre=re.compile("Error*")
+    if errorre.match(statusoutput[1]):
+        return False
+    else:
+        return True
+
+# get arguments from calling program -- most important is MAC address
+macre=re.compile("mac*=*",re.IGNORECASE)
+outputre=re.compile("--output*",re.IGNORECASE)
+
+def usage():
+    print >> sys.stderr, "Usage: %s [-q|--quiet] [--output=] [--entry=] <image>" %(sys.argv[0],)
+
+try:
+    opts, args = getopt.gnu_getopt(sys.argv[1:], 'qh::',
+                                   ["quiet", "help", "output=", "entry=", "mac=",
+                                    "isconfig"])
+except getopt.GetoptError:
+    usage()
+    sys.exit(1)
+
+if len(args) < 1:
+    usage()
+    sys.exit(1)
+
+output = None
+
+for o, a in opts:
+    if o in  ("--output",):
+        output = a
+
+if output is None or output == "-":
+    outputfd = sys.stdout.fileno()
+else:
+    outputfd = os.open(output, os.O_WRONLY)
+
+mac=""
+
+# look for a mac= option in the options passed in
+# should do this properly using getopt?
+for arg in sys.argv[1:]:
+    if macre.match(arg):
+        mac=arg.split('=')[1]
+        print "pypxeboot: requesting info for MAC address "+mac+""
+        break
+
+if mac == "":
+    print "pypxeboot: Didn't get a MAC address, dying"
+    sys.exit(1)
+
+# run modified udhcp with specified MAC address
+udhcp_result=commands.getstatusoutput(udhcpc_command+" -n -q -s "+
+                                      udhcpc_script+" -M "+mac)
+
+if (udhcp_result[0] != 0):
+    print "pypxeboot: udhcpc failed (%s), output: %s\n" %(udhcp_result[0],
+                                                          udhcp_result[1])
+    sys.exit(1)
+
+# parse python formatted output from udhcp-executed script
+udhcplines=udhcp_result[1].split('\n')
+
+dhcpinfo={}
+
+for line in udhcplines:
+    s = line.strip()
+    f = s.split()
+
+    if s[0]=='{' and s[-1]=='}':
+        dhcpinfo=eval(s, {"__builtins__" : {}})
+        for k in dhcpinfo:
+            dhcpinfo[k]=dhcpinfo[k].strip()
+
+# run tftp client to get configuration info
+servaddr=dhcpinfo['siaddr']
+
+ipaddr=dhcpinfo['ip']
+ipaddrlist=ipaddr.split('.')
+hexip=commands.getstatusoutput("/usr/bin/gethostip -x "+ipaddr)[1]
+
+print "pypxeboot: getting cfg for IP %s (%s) from server %s" %(ipaddr,hexip,servaddr)
+
+tmpdir="/var/lib/xen/"
+
+os.chdir(tmpdir)
+commandstr="tftp -c get "+servaddr+":pxelinux.cfg/"+hexip
+#print "running command "+commandstr
+getpxeres=commands.getstatusoutput(commandstr)
+
+# check for errors in tftp output -- it doesn't use return codes properly!
+if not tftp_success(getpxeres):
+    print ("pypxeboot: error getting pxelinux cfg")
+    sys.exit(1)
+
+# read in the downloaded pxelinux cfg file
+cfgfile=open(tmpdir+hexip)
+cfglines=cfgfile.readlines()
+
+# check whether we should drop to localboot
+# XXX should really check that localboot is the default
+localbootre=re.compile("\s*localboot\w*")
+
+for line in cfglines:
+    if (localbootre.match(line)):
+        print "pypxeboot: dropping to pygrub for local boot"
+        run_pygrub()
+        sys.exit(0)
+
+# if "network" boot get kernel to local file and return the location as
+# sxp as pygrub does
+
+kernelre=re.compile("kernel*")
+appendre=re.compile("append*")
+
+# parse the pxelinux entry: add key/value pairs to
+# a dict and dump all other args to a string
+# XXX assumes there's only one entry at the moment
+# XXX need to parse properly and use default entry
+syslinux={}
+simpleargs=""
+for line in cfglines:
+    if (line[0]!='#'):
+        line=line.strip()
+        if (kernelre.match(line)):
+            (k,v)=line.split()
+            syslinux[k]=v
+        elif (appendre.match(line)):
+            havekernelargs=True
+            for entry in line[6:].split():
+                if (entry.find('=') != -1):
+                    (k,v)=entry.split('=')
+                    syslinux[k]=v
+                else:
+                    simpleargs+=entry+' '
+            
+
+# if network boot, get kernel and initrd
+# temp directory should still be the working dir
+dlres={}
+for i in ["initrd","kernel"]:
+    cmd="tftp -c get "+servaddr+":"+syslinux[i]
+    print "pypxeboot: downloading "+i+" using cmd: "+cmd
+    dlres[i]=commands.getstatusoutput(cmd)
+    if not tftp_success (dlres[i]):
+        print "pypxeboot: tftp failed for "+i+": "+dlres[i][1]
+        sys.exit(1)
+
+# format kernel and args as sxp
+# will need to get the --output option and write to that fd
+kernelname=syslinux['kernel'].split('/')[-1]
+initrdname=syslinux['initrd'].split('/')[-1]
+
+sxp="linux (kernel %s)" %(tmpdir+kernelname,)
+
+if 'initrd' in syslinux:
+    sxp+="(ramdisk %s)" % (tmpdir+initrdname,)
+if havekernelargs:
+    sxp+="(args '"
+    for arg in syslinux:
+        if arg != 'kernel' and arg != 'initrd':
+            sxp+=arg+"="+syslinux[arg]+' '
+    sxp+=simpleargs
+    sxp=sxp[0:-1]        
+    sxp+="'"
+sxp+=")"        
+
+sys.stdout.flush()
+os.write(outputfd,sxp)
diff -r 01ec7dba9ff8 -r 7f1a38c5c086 tools/pypxeboot/udhcp_usermac.patch
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/pypxeboot/udhcp_usermac.patch	Mon Feb 05 11:07:21 2007 +0000
@@ -0,0 +1,107 @@
+diff -u udhcp-0.9.8/dhcpc.c udhcp-0.9.8.mod/dhcpc.c
+--- udhcp-0.9.8/dhcpc.c	2002-10-19 02:10:43.000000000 +0100
++++ udhcp-0.9.8.mod/dhcpc.c	2007-02-02 14:41:11.000000000 +0000
+@@ -67,6 +67,7 @@
+ 	foreground: 0,
+ 	quit_after_lease: 0,
+ 	background_if_no_lease: 0,
++	userarp: 0,
+ 	interface: "eth0",
+ 	pidfile: NULL,
+ 	script: DEFAULT_SCRIPT,
+@@ -95,6 +96,7 @@
+ "  -r, --request=IP                IP address to request (default: none)\n"
+ "  -s, --script=file               Run file at dhcp events (default:\n"
+ "                                  " DEFAULT_SCRIPT ")\n"
++"  -M, --mac=MAC                   MAC address to use instead of HW MAC\n"
+ "  -v, --version                   Display version\n"
+ 	);
+ 	exit(0);
+@@ -132,6 +134,7 @@
+ 		state = INIT_SELECTING;
+ 		break;
+ 	case INIT_SELECTING:
++		break;
+ 	}
+ 
+ 	/* start things over */
+@@ -207,6 +210,7 @@
+ #endif
+ {
+ 	unsigned char *temp, *message;
++	unsigned char hwmac[6];
+ 	unsigned long t1 = 0, t2 = 0, xid = 0;
+ 	unsigned long start = 0, lease;
+ 	fd_set rfds;
+@@ -233,14 +237,15 @@
+ 		{"request",	required_argument,	0, 'r'},
+ 		{"script",	required_argument,	0, 's'},
+ 		{"version",	no_argument,		0, 'v'},
++		{"mac",	        required_argument,	0, 'M'},
+ 		{"help",	no_argument,		0, '?'},
+ 		{0, 0, 0, 0}
+ 	};
+ 
+ 	/* get options */
+ 	while (1) {
+-		int option_index = 0;
+-		c = getopt_long(argc, argv, "c:fbH:h:i:np:qr:s:v", arg_options, &option_index);
++		int option_index = 0, nrmacfields=0;
++		c = getopt_long(argc, argv, "c:fbH:h:i:np:qr:s:v:M:", arg_options, &option_index);
+ 		if (c == -1) break;
+ 		
+ 		switch (c) {
+@@ -290,6 +295,16 @@
+ 			printf("udhcpcd, version %s\n\n", VERSION);
+ 			exit_client(0);
+ 			break;
++                case 'M':                      
++			nrmacfields=sscanf(optarg,"%x:%x:%x:%x:%x:%x",
++                                           (unsigned int *)&client_config.arp[0],
++                                           (unsigned int *)&client_config.arp[1],
++                                           (unsigned int *)&client_config.arp[2],
++                                           (unsigned int *)&client_config.arp[3],
++                                           (unsigned int *)&client_config.arp[4],
++                                           (unsigned int *)&client_config.arp[5]);
++                        if (nrmacfields == 6) client_config.userarp=1;
++                        break;
+ 		default:
+ 			show_usage();
+ 		}
+@@ -302,9 +317,11 @@
+ 	pidfile_write_release(pid_fd);
+ 
+ 	if (read_interface(client_config.interface, &client_config.ifindex, 
+-			   NULL, client_config.arp) < 0)
++	         	   NULL, hwmac) < 0)
+ 		exit_client(1);
+-		
++
++	if (!(client_config.userarp)) memcpy(client_config.arp, hwmac, 6);
++
+ 	if (!client_config.clientid) {
+ 		client_config.clientid = xmalloc(6 + 3);
+ 		client_config.clientid[OPT_CODE] = DHCP_CLIENT_ID;
+diff -u udhcp-0.9.8/dhcpc.h udhcp-0.9.8.mod/dhcpc.h
+--- udhcp-0.9.8/dhcpc.h	2002-09-20 21:36:15.000000000 +0100
++++ udhcp-0.9.8.mod/dhcpc.h	2007-02-02 14:13:52.000000000 +0000
+@@ -19,6 +19,7 @@
+ 	char quit_after_lease;		/* Quit after obtaining lease */
+ 	char abort_if_no_lease;		/* Abort if no lease */
+ 	char background_if_no_lease;	/* Fork to background if no lease */
++	char userarp;                   /* Did the user give us an ARP address */
+ 	char *interface;		/* The name of the interface to use */
+ 	char *pidfile;			/* Optionally store the process ID */
+ 	char *script;			/* User script to run at dhcp events */
+diff -u udhcp-0.9.8/README.udhcpc udhcp-0.9.8.mod/README.udhcpc
+--- udhcp-0.9.8/README.udhcpc	2002-10-31 18:02:09.000000000 +0000
++++ udhcp-0.9.8.mod/README.udhcpc	2007-02-02 14:12:47.000000000 +0000
+@@ -24,6 +24,7 @@
+ -r, --request=IP                IP address to request (default: none)
+ -s, --script=file               Run file at dhcp events (default:
+                                 /usr/share/udhcpc/default.script)
++-M, --mac=MAC                   MAC address to use instead of HW MAC
+ -v, --version                   Display version
+ 
+ 
+Common subdirectories: udhcp-0.9.8/samples and udhcp-0.9.8.mod/samples

[-- Attachment #3: Type: text/plain, Size: 138 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel

^ permalink raw reply	[flat|nested] 13+ messages in thread
[parent not found: <E1Hl9dL-0002zJ-Jo@host-192-168-0-1-bcn-london>]

end of thread, other threads:[~2007-05-31 10:10 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-02-05 11:13 [PATCH] pypxeboot bootloader Stephen Childs
2007-02-05 17:36 ` Tim Deegan
2007-02-05 17:57   ` Ewan Mellor
2007-02-08 14:27   ` Stephen Childs
2007-02-08 14:47     ` Ian Pratt
2007-02-08 16:36       ` Stephen Childs
2007-02-08 16:48         ` Ian Pratt
2007-02-20  9:53         ` Tim Deegan
2007-02-20 12:09           ` Stephen Childs
2007-05-07 16:33         ` Daniel Miles
2007-05-07 17:21           ` Ian Pratt
2007-02-08 15:09     ` Tim Deegan
     [not found] <E1Hl9dL-0002zJ-Jo@host-192-168-0-1-bcn-london>
2007-05-31 10:10 ` Stephen Childs

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.