From: Stephen Childs <Stephen.Childs@cs.tcd.ie>
To: xen-devel@lists.xensource.com
Subject: [PATCH] pypxeboot bootloader
Date: Mon, 05 Feb 2007 11:13:18 +0000 [thread overview]
Message-ID: <45C7114E.10207@cs.tcd.ie> (raw)
[-- 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
next reply other threads:[~2007-02-05 11:13 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-02-05 11:13 Stephen Childs [this message]
2007-02-05 17:36 ` [PATCH] pypxeboot bootloader 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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=45C7114E.10207@cs.tcd.ie \
--to=stephen.childs@cs.tcd.ie \
--cc=xen-devel@lists.xensource.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.