Date: Fri, 22 Oct 2004 15:29:25 +0200 From: Ralf Wenk <RZ-FreeBSD1004@fh-karlsruhe.de> To: FreeBSD-gnats-submit@FreeBSD.org Cc: Ralf Wenk <RZ-FreeBSD1004@fh-karlsruhe.de> Subject: kern/73004: [patch] PXE loader malfunction in multiple PXE server environment Message-ID: <E1CKzTx-0000hC-3t@localhost> Resent-Message-ID: <200410221330.i9MDURi6039785@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 73004 >Category: kern >Synopsis: [patch] PXE loader malfunction in multiple PXE server environment >Confidential: no >Severity: serious >Priority: low >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Fri Oct 22 13:30:26 GMT 2004 >Closed-Date: >Last-Modified: >Originator: Ralf Wenk >Release: FreeBSD 5.3-STABLE i386 >Organization: FH Karlsruhe, University of Applied Sciences >Environment: System: FreeBSD RZ-Wenk1 5.3-STABLE FreeBSD 5.3-STABLE #0: Fri Oct 22 11:14:32 CEST 2004 root@RZ-Wenk1:/usr/obj/usr/src/sys/fsc-t-diskless i386 >Description: The pxeboot still do not support an environment with multipe DHCP/PXE bootservers. This patch uses the PXEs decision of which bootserver to use as well as enables the kernel to return values for the dhcp.* kernel environment variables used in /etc/rc.d/hostname and /etc/rc.d/resolv. See also problem report 65523. >How-To-Repeat: Use a multipe DHCP/PXE environment an try not to use the nearest DHCP/PXE bootserver. >Fix: --- pxe.c.udiff begins here --- --- pxe.c.old Fri Oct 22 15:03:44 2004 +++ pxe.c Fri Oct 22 15:04:14 2004 @@ -42,6 +42,7 @@ #include <nfsv2.h> #include <iodesc.h> +#define SUPPORT_DHCP /* PXE uses DHCP */ #include <bootp.h> #include <bootstrap.h> #include "btxv86.h" @@ -133,6 +134,102 @@ }; /* + * This is ugly: + * libstand/bootp.c contains a similar RFC 1048 parser function named + * vend_rfc1048(), but the function is local to bootp.c and also uses + * a variable local to bootp.c if compiled with SUPPORT_DHCP defined. + * While the first problem could easily be fixed the second one would + * need an additional function in bootp.c to set the local variable. + */ +static int +pxe_vend_rfc1048(void) +{ + char vm_rfc1048[4] = VM_RFC1048; + u_char buffer[256]; + u_char *cp, *ep; + int size; + u_char tag; + + if (bcmp(bootplayer.vendor.v.magic, vm_rfc1048, sizeof(vm_rfc1048)) == 0) + { + cp = (u_char *)bootplayer.vendor.d; + ep = cp + sizeof(bootplayer.vendor.d); + + /* Step over magic cookie */ + cp += sizeof(int); + + while (cp < ep) { + tag = *cp++; + size = *cp++; + if (tag == TAG_END) + break; + + if (tag == TAG_SUBNET_MASK) { + bcopy(cp, &netmask, sizeof(netmask)); +#ifdef PXE_DEBUG + printf("pxe_vend_rfc1048: SUBNET_MASK %s\n", intoa(netmask)); +#endif + } + if (tag == TAG_GATEWAY) { + bcopy(cp, &gateip.s_addr, sizeof(gateip.s_addr)); +#ifdef PXE_DEBUG + printf("pxe_vend_rfc1048: GATEWAY %s\n", intoa(gateip.s_addr)); +#endif + } + if (tag == TAG_SWAPSERVER) { + /* let it override bp_siaddr */ + bcopy(cp, &rootip.s_addr, sizeof(swapip.s_addr)); +#ifdef PXE_DEBUG + printf("pxe_vend_rfc1048: SWAPSERVER %s\n", intoa(rootip.s_addr)); +#endif + } + if (tag == TAG_ROOTPATH) { + strncpy(rootpath, (char *)cp, sizeof(rootpath)); + rootpath[size] = '\0'; +#ifdef PXE_DEBUG + printf("pxe_vend_rfc1048: ROOTPATH %s\n", rootpath); +#endif + } + if (tag == TAG_HOSTNAME) { + strncpy(hostname, (char *)cp, sizeof(hostname)); + hostname[size] = '\0'; +#ifdef PXE_DEBUG + printf("pxe_vend_rfc1048: HOSTNAME %s\n", hostname); +#endif + setenv("dhcp.host-name", hostname, 1); + } + if (tag == TAG_DOMAINNAME) { + strncpy(buffer, (char *)cp, sizeof(buffer)); + buffer[size] = '\0'; +#ifdef PXE_DEBUG + printf("pxe_vend_rfc1048: DOMAINNAME %s\n", buffer); +#endif + setenv("dhcp.domain-name", buffer, 1); + } + if (tag == TAG_DOMAIN_SERVER) { + int count = 0; /* DNS server(s) */ + + buffer[0] = '\0'; + while ( count < (size >> 2)) { + strcat(buffer, inet_ntoa(*((struct in_addr*)cp + count))); + strcat(buffer, ","); + count++; + } + buffer[strlen(buffer) - 1] = '\0'; +#ifdef PXE_DEBUG + printf("pxe_vend_rfc1048: DOMAINNAMESERVER %s\n", buffer); +#endif + setenv("dhcp.domain-name-server", buffer, 1); + } + cp += size; + } + return(0); + } + else + return(-1); +} + +/* * This function is called by the loader to enable PXE support if we * are booted by PXE. The passed in pointer is a pointer to the * PXENV+ structure. @@ -274,12 +371,52 @@ } if (rootip.s_addr == 0) { /* - * Do a bootp/dhcp request to find out where our - * NFS/TFTP server is. Even if we dont get back - * the proper information, fall back to the server - * which brought us to life and a default rootpath. + * PXE looks into the content of all answers to its request + * and uses a finite state machine to select one of them. + * It is even possible that there are several requests + * generated and the information collected is combined. + * E.g. in the case of several PXE servers it is possible + * that not the answer of the fastest one is selected. This + * breaks the simple way of just using the first answer. + * But fortunately PXE stores the selected information + * in the bootplayer structure for us to use. + */ +#ifdef PXE_DEBUG + printf("pxe_open: bootplayer.cip: %s\n", intoa( bootplayer.cip)); + printf("pxe_open: bootplayer.yip: %s\n", intoa( bootplayer.yip)); + printf("pxe_open: bootplayer.sip: %s\n", intoa( bootplayer.sip)); + printf("pxe_open: bootplayer.gip: %s\n", intoa( bootplayer.gip)); + sprintf(temp, "%6D", bootplayer.CAddr, ":"); + printf("pxe_open: bootplayer.CAddr: %s\n", temp); + printf("pxe_open: bootplayer.Sname: %s\n", bootplayer.Sname); + printf("pxe_open: bootplayer.bootfile: %s\n", bootplayer.bootfile); +#endif + /* + * Calling bootp() sets some global variables as a side effect + * which are used later in the (legacy) code. As we try to avoid + * calling boot(), we had to do the same thing. */ - bootp(pxe_sock, BOOTP_PXE); + myip.s_addr = bootplayer.yip; + if (IN_CLASSA(ntohl(myip.s_addr))) + netmask = htonl(IN_CLASSA_NET); + else if (IN_CLASSB(ntohl(myip.s_addr))) + netmask = htonl(IN_CLASSB_NET); + else + netmask = htonl(IN_CLASSC_NET); + if (pxe_vend_rfc1048() != 0) { + /* + * We are not happy with the information found in the + * bootplayer structure. As some last resort + * do a bootp/dhcp request to find out where our + * NFS/TFTP server is. Even if we dont get back + * the proper information, fall back to the server + * which brought us to life and a default rootpath. + */ + bootp(pxe_sock, BOOTP_PXE); + } +#ifdef PXE_DEBUG + printf("pxe_open: server addr: %s\n", inet_ntoa(rootip)); +#endif if (rootip.s_addr == 0) rootip.s_addr = bootplayer.sip; if (!rootpath[1]) @@ -299,7 +436,7 @@ printf("pxe_open: server path: %s\n", rootpath); printf("pxe_open: gateway ip: %s\n", inet_ntoa(gateip)); - setenv("boot.netif.ip", inet_ntoa(myip), 1); + setenv("boot.netif.ip", intoa(bootplayer.yip), 1); setenv("boot.netif.netmask", intoa(netmask), 1); setenv("boot.netif.gateway", inet_ntoa(gateip), 1); if (bootplayer.Hardware == ETHER_TYPE) { --- pxe.c.udiff ends here --- >Release-Note: >Audit-Trail: >Unformatted:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?E1CKzTx-0000hC-3t>