[patch] pxeloader sometimes "freezes" if called via pxechain
Alexander V. Chernikov
melifaro at yandex-team.ru
Fri Jul 26 14:51:38 UTC 2013
Hello list!
Currently our pxeloader prefer to get NFS server information by its own
instead of using cached one.
This is how it is done:
pxe_open() indirectly opens socket (PXENV_UDP_OPEN, with cached IP from
BOOTPLAYER).
After that, bootp() resolve is done, resulting in (probably) more
"valid" server address.
Current code incorrectly assumes that DHCP server returns the same IP
address for given MAC regardless of other parameters.
If this is not true, outgoing packets are send via cached IP (since the
only way to change source IP is to reopen pxe handle),
but receive filter is programmed to use "new" one. This leads to random
timeouts in some DHCP configurations.
What we can probably do:
1) try cached server address if any without doing DHCP (possibly
breaking some users setups)
2) try to reopen PXE handle with new address (netif_close() /
netif_open(), which is complicated due to many open/close calls reading
'old' address)
3) save address/gw and restore them (if differs) before/after bootp().
4) probably a bunch of others
Patch implementing (3) is attached.
I'll commit it on the end of next week if there will be no objections.
-------------- next part --------------
Index: sys/boot/i386/libi386/pxe.c
===================================================================
--- sys/boot/i386/libi386/pxe.c (revision 239353)
+++ sys/boot/i386/libi386/pxe.c (working copy)
@@ -255,11 +255,17 @@ pxe_open(struct open_file *f, ...)
char temp[FNAME_SIZE];
int error = 0;
int i;
+ struct in_addr _myip, _gateip, _rootip;
+ struct iodesc *d;
va_start(args, f);
devname = va_arg(args, char*);
va_end(args);
+ _myip.s_addr = INADDR_ANY;
+ _gateip.s_addr = INADDR_ANY;
+ _rootip.s_addr = INADDR_ANY;
+
/* On first open, do netif open, mount, etc. */
if (pxe_opens == 0) {
/* Find network interface. */
@@ -271,6 +277,16 @@ pxe_open(struct open_file *f, ...)
}
if (pxe_debug)
printf("pxe_open: netif_open() succeeded\n");
+ if (bootplayer.yip != INADDR_ANY) {
+ _myip.s_addr = bootplayer.yip;
+ _rootip.s_addr = bootplayer.sip;
+ _gateip.s_addr = bootplayer.gip;
+ if (pxe_debug) {
+ printf("pxe_open: cached myip: %s\n", inet_ntoa(_myip));
+ printf("pxe_open: cached gw: %s\n", inet_ntoa(_gateip));
+ printf("pxe_open: cached server: %s\n", inet_ntoa(_rootip));
+ }
+ }
}
if (rootip.s_addr == 0) {
/*
@@ -280,9 +296,24 @@ pxe_open(struct open_file *f, ...)
* which brought us to life and a default rootpath.
*/
bootp(pxe_sock, BOOTP_PXE);
+ if (_myip.s_addr != INADDR_ANY && _myip.s_addr != myip.s_addr) {
+ if (!(d = socktodesc(pxe_sock))) {
+ printf("pxe_open: bad socket. %d\n", pxe_sock);
+ return (ENXIO);
+ }
+ if (pxe_debug) {
+ printf("pxe_open: reverting IP back to %s\n",
+ inet_ntoa(_myip));
+ printf("pxe_open: (unused)DHCP IP is %s\n",
+ inet_ntoa(myip));
+ }
+ myip = _myip;
+ gateip = _gateip;
+ d->myip = myip;
+ }
if (rootip.s_addr == 0)
rootip.s_addr = bootplayer.sip;
- if (!rootpath[0])
+ if ((!rootpath[0]) || (!strcmp(rootpath, "/")))
strcpy(rootpath, PXENFSROOTPATH);
for (i = 0; rootpath[i] != '\0' && i < FNAME_SIZE; i++)
@@ -297,6 +328,7 @@ pxe_open(struct open_file *f, ...)
}
printf("pxe_open: server addr: %s\n", inet_ntoa(rootip));
printf("pxe_open: server path: %s\n", rootpath);
+ printf("pxe_open: local addr: %s\n", inet_ntoa(myip));
printf("pxe_open: gateway ip: %s\n", inet_ntoa(gateip));
setenv("boot.netif.ip", inet_ntoa(myip), 1);
@@ -590,6 +622,9 @@ pxe_netif_probe(struct netif *nif, void *machdep_h
bzero(udpopen_p, sizeof(*udpopen_p));
udpopen_p->src_ip = bootplayer.yip;
+#ifdef PXE_DEBUG
+ printf("pxe_netif_probe: IP=%s\n", inet_ntoa(udpopen->src_ip));
+#endif
pxe_call(PXENV_UDP_OPEN);
if (udpopen_p->status != 0) {
More information about the freebsd-net
mailing list