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

Re: [Xen-devel] [PATCH] pypxeboot bootloader



Ian Pratt wrote:
tftp-hpa as supplied with FC3 seems to work: "tftp tftp-serv -c get foo
/tmp/bar"

Yes and tftp version 0.43 from http://www.kernel.org/pub/software/network/tftp/ works too. I was using a much older one before so everything should be OK as long as people use a recent version. I've put it in the README.

I've attached a fresh patch that addresses this and the other issues you raised, Tim.

Incidentally, what do you do if the guest vif is not going to be on the
same bridge that dom0 eth0 is on? In practice this likely matters more
for the dhcp request than the tftp transfer.
Could you explain what the problem would be? Do you mean that the DHCP server might not be set up to serve requests from the dom0's subnet? To be honest I hadn't thought that much about more complex setups -- as it is there are embedded assumptions about the way pxelinux is set up.

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 1170952399 0
# Node ID 4cf16fd716cf1dff0859afda632f6cf922c35dfa
# Parent  780f097b54c5f9161f7c6cf3f86b2bb72cc43587
pypxeboot, a PXE-like bootloader for getting configuration
and kernel images for Domain Us.
Signed-off-by: Stephen Childs <childss@xxxxxxxxx>

diff -r 780f097b54c5 -r 4cf16fd716cf tools/pypxeboot/README
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/pypxeboot/README    Thu Feb 08 16:33:19 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 (source and RPMs available at
+http://www.kernel.org/pub/software/network/tftp/). N.B. pypxeboot
+has been tested with version 0.43 of 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 780f097b54c5 -r 4cf16fd716cf tools/pypxeboot/outputpy.udhcp.sh
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/pypxeboot/outputpy.udhcp.sh Thu Feb 08 16:33:19 2007 +0000
@@ -0,0 +1,44 @@
+#!/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 key/value pairs. 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
+echo siaddr=$siaddr
+echo sname=$sname
+echo boot_file=$boot_file
+echo subnet=$subnet
+echo timezone=$timezone
+echo router=$router
+echo 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 780f097b54c5 -r 4cf16fd716cf tools/pypxeboot/pypxeboot
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/pypxeboot/pypxeboot Thu Feb 08 16:33:19 2007 +0000
@@ -0,0 +1,209 @@
+#!/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,tempfile,shutil
+
+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=] mac= 
<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 output from udhcp-executed script (looking for key=value
+# pairs)
+udhcplines=udhcp_result[1].split('\n')
+
+dhcpinfo={}
+
+for line in udhcplines:
+    s = line.strip()
+    if (s.find('=') != -1):
+        f=s.split('=')
+        dhcpinfo[f[0]]=f[1]
+
+# run tftp client to get configuration info
+servaddr=dhcpinfo['siaddr']
+
+ipaddr=dhcpinfo['ip']
+ipaddrlist=ipaddr.split('.')
+hexip=(4 * "%2.2X") % tuple(map (int, ipaddrlist))
+
+print "pypxeboot: getting cfg for IP %s (%s) from server %s" 
%(ipaddr,hexip,servaddr)
+
+tmpdir="/var/lib/xen/"
+
+os.chdir(tmpdir)
+commandstr="tftp "+servaddr+" -c get 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
+cfgfilename=tmpdir+hexip
+cfgfile=open(cfgfilename)
+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)
+
+# remove downloaded config file
+cfgfile.close()
+os.remove(cfgfilename)
+
+# 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={}
+tmpimages={}
+for i in ["initrd","kernel"]:
+    (tfd,tfn)=tempfile.mkstemp(prefix=i+".", dir=tmpdir)
+    cmd="tftp "+servaddr+" -c get "+syslinux[i]+" "+tfn
+    tmpimages[i]=tfn
+    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)" %(tmpimages['kernel'],)
+
+if 'initrd' in syslinux:
+    sxp+="(ramdisk %s)" % (tmpimages['initrd'],)
+if havekernelargs:
+    sxp+="(args '"
+    for arg in syslinux:
+        if arg != 'kernel' and arg != 'initrd':
+            sxp+=arg+"="+syslinux[arg]+' '
+    sxp+=simpleargs
+    sxp=sxp[0:-1]       # remove trailing space
+    sxp+="'"
+sxp+=")"        
+
+sys.stdout.flush()
+os.write(outputfd,sxp)
diff -r 780f097b54c5 -r 4cf16fd716cf tools/pypxeboot/udhcp_usermac.patch
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/pypxeboot/udhcp_usermac.patch       Thu Feb 08 16:33:19 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

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.