[U-Boot] [PATCH] net: BOOTP retry timeout improvements

Stephen Warren swarren at wwwdotorg.org
Sat Jul 26 01:30:48 CEST 2014


From: Stephen Warren <swarren at nvidia.com>

Currently, the BOOTP code sends out its initial request as soon as the
Ethernet driver indicates "link up". If this packet is lost or not
replied to for some reason, the code waits for a 1s timeout before
retrying. For some reason, such early packets are often lost on my
system, so this causes an annoying delay.

To optimize this, modify the BOOTP code to have very short timeouts for
the first packet transmitted, but gradually increase the timeout each
time a timeout occurs. This way, if the first packet is lost, the second
packet is transmitted quite quickly and hence the overall delay is low.
However, if there's still no response, we don't keep spewing out packets
at an insane speed.

It's arguably more correct to try and find out why the first packet is
lost. However, it seems to disappear inside my Ethenet chip; the TX chip
indicates no error during TX (not that it has much in the way of
reporting...), yet wireshark on the RX side doesn't see any packet.
FWIW, I'm using an ASIX USB Ethernet adapter. Perhaps "link up" is
reported too early or based on the wrong condition in HW, and we should
add some fixed extra delay into the driver. However, this would slow down
every link up event even if it ends up not being needed in some cases.
Having BOOTP retry quickly applies the fix/WAR to every possible
Ethernet device, and is quite simple to implement, so seems a better
solution.

Signed-off-by: Stephen Warren <swarren at nvidia.com>
---
 net/bootp.c | 38 +++++++++++++++++++++++++++++++-------
 net/bootp.h |  3 +--
 net/net.c   |  4 ++--
 3 files changed, 34 insertions(+), 11 deletions(-)

diff --git a/net/bootp.c b/net/bootp.c
index 189a00383543..697184f22d73 100644
--- a/net/bootp.c
+++ b/net/bootp.c
@@ -23,12 +23,22 @@
 
 #define BOOTP_VENDOR_MAGIC	0x63825363	/* RFC1048 Magic Cookie */
 
-#define TIMEOUT		5000UL	/* Milliseconds before trying BOOTP again */
+/*
+ * The timeout for the initial BOOTP/DHCP request used to be described by a
+ * counter of fixed-length timeout periods. TIMEOUT_COUNT represents
+ * that counter
+ *
+ * Now that the timeout periods are variable (exponential backoff and retry)
+ * we convert the timeout count to the absolute time it would have take to
+ * execute that many retries, and keep sending retry packets until that time
+ * is reached.
+ */
 #ifndef CONFIG_NET_RETRY_COUNT
 # define TIMEOUT_COUNT	5		/* # of timeouts before giving up */
 #else
 # define TIMEOUT_COUNT	(CONFIG_NET_RETRY_COUNT)
 #endif
+#define TIMEOUT_MS	((3 + (TIMEOUT_COUNT * 5)) * 1000)
 
 #define PORT_BOOTPS	67		/* BOOTP server UDP port */
 #define PORT_BOOTPC	68		/* BOOTP client UDP port */
@@ -39,6 +49,8 @@
 
 ulong		BootpID;
 int		BootpTry;
+ulong		bootp_start;
+ulong		bootp_timeout;
 
 #if defined(CONFIG_CMD_DHCP)
 static dhcp_state_t dhcp_state = INIT;
@@ -327,16 +339,21 @@ BootpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
 static void
 BootpTimeout(void)
 {
-	if (BootpTry >= TIMEOUT_COUNT) {
+	ulong time_taken = get_timer(bootp_start);
+
+	if (time_taken >= TIMEOUT_MS) {
 #ifdef CONFIG_BOOTP_MAY_FAIL
-		puts("\nRetry count exceeded\n");
+		puts("\nRetry time exceeded\n");
 		net_set_state(NETLOOP_FAIL);
 #else
-		puts("\nRetry count exceeded; starting again\n");
+		puts("\nRetry time exceeded; starting again\n");
 		NetStartAgain();
 #endif
 	} else {
-		NetSetTimeout(TIMEOUT, BootpTimeout);
+		bootp_timeout *= 2;
+		if (bootp_timeout > 1000)
+			bootp_timeout = 1000;
+		NetSetTimeout(bootp_timeout, BootpTimeout);
 		BootpRequest();
 	}
 }
@@ -597,6 +614,13 @@ static int BootpExtended(u8 *e)
 }
 #endif
 
+void BootpReset(void)
+{
+	BootpTry = 0;
+	bootp_start = get_timer(0);
+	bootp_timeout = 10;
+}
+
 void
 BootpRequest(void)
 {
@@ -686,7 +710,7 @@ BootpRequest(void)
 	iplen = BOOTP_HDR_SIZE - OPT_FIELD_SIZE + extlen;
 	pktlen = eth_hdr_size + IP_UDP_HDR_SIZE + iplen;
 	net_set_udp_header(iphdr, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, iplen);
-	NetSetTimeout(SELECT_TIMEOUT, BootpTimeout);
+	NetSetTimeout(bootp_timeout, BootpTimeout);
 
 #if defined(CONFIG_CMD_DHCP)
 	dhcp_state = SELECTING;
@@ -919,7 +943,7 @@ DhcpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
 						htonl(BOOTP_VENDOR_MAGIC))
 				DhcpOptionsProcess((u8 *)&bp->bp_vend[4], bp);
 
-			NetSetTimeout(TIMEOUT, BootpTimeout);
+			NetSetTimeout(5000, BootpTimeout);
 			DhcpSendRequestPkt(bp);
 #ifdef CONFIG_SYS_BOOTFILE_PREFIX
 		}
diff --git a/net/bootp.h b/net/bootp.h
index ecbcc4d5093c..3b95a0a2ded8 100644
--- a/net/bootp.h
+++ b/net/bootp.h
@@ -65,6 +65,7 @@ extern int	BootpTry;
 
 
 /* Send a BOOTP request */
+extern void BootpReset(void);
 extern void BootpRequest(void);
 
 /****************** DHCP Support *********************/
@@ -88,8 +89,6 @@ typedef enum { INIT,
 #define DHCP_NAK      6
 #define DHCP_RELEASE  7
 
-#define SELECT_TIMEOUT 3000UL	/* Milliseconds to wait for offers */
-
 /**********************************************************************/
 
 #endif /* __BOOTP_H__ */
diff --git a/net/net.c b/net/net.c
index 0f7625fde1dc..722089f3b931 100644
--- a/net/net.c
+++ b/net/net.c
@@ -385,14 +385,14 @@ restart:
 #endif
 #if defined(CONFIG_CMD_DHCP)
 		case DHCP:
-			BootpTry = 0;
+			BootpReset();
 			NetOurIP = 0;
 			DhcpRequest();		/* Basically same as BOOTP */
 			break;
 #endif
 
 		case BOOTP:
-			BootpTry = 0;
+			BootpReset();
 			NetOurIP = 0;
 			BootpRequest();
 			break;
-- 
1.9.1



More information about the U-Boot mailing list