[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH] pypxeboot bootloader
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 # HG changeset patch # User childss@xxxxxxxxxxxxx # Date 1170673641 0 # Node ID 7f1a38c5c08659ae123e5f94696cbca19e4e10fb # Parent 01ec7dba9ff805a5c74a0318997b747d3e3e3327 Added pypxeboot bootloader for simulating PXE boot for DomUs. Signed-off-by: Stephen Childs <childss@xxxxxxxxx> 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@xxxxxxxxx> + +# 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@xxxxxxxxx> +# +# 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 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |