WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

[Xen-devel] [PATCH] pypxeboot bootloader

To: xen-devel@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-devel] [PATCH] pypxeboot bootloader
From: Stephen Childs <Stephen.Childs@xxxxxxxxx>
Date: Mon, 05 Feb 2007 11:13:18 +0000
Delivery-date: Mon, 05 Feb 2007 03:13:19 -0800
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
Reply-to: Stephen.Childs@xxxxxxxxx
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
User-agent: Thunderbird 1.5.0.9 (X11/20061219)
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