diff options
| author | Tom Rini <[email protected]> | 2025-05-23 11:29:55 -0600 |
|---|---|---|
| committer | Tom Rini <[email protected]> | 2025-05-23 11:31:03 -0600 |
| commit | da24eb55327978410f5559f44ce1434ae8d8932d (patch) | |
| tree | 441736e6e7c79637a61b8f0dab9cac2260e1e4be | |
| parent | ef305ceff9c875a7c16fdffc5e120d8ddf6243b7 (diff) | |
| parent | 2111bd7e93a3044f0590c942a41f2667d15d923d (diff) | |
Merge patch series "BOOTP/DHCPv4 enhancements"
Sean Edmond <[email protected]> says:
In our datacenter application, a single DHCP server is servicing 36000+ clients.
Improvements are required to the DHCPv4 retransmission behavior to align with
RFC and ensure less pressure is exerted on the server:
- retransmission backoff interval maximum is configurable
(environment variable bootpretransmitperiodmax)
- initial retransmission backoff interval is configurable
(environment variable bootpretransmitperiodinit)
- transaction ID is kept the same for each BOOTP/DHCPv4 request
(not recreated on each retry)
For our application we'll use:
- bootpretransmitperiodmax=16000
- bootpretransmitperiodinit=2000
A new configuration BOOTP_RANDOM_XID has been added to enable a randomized
BOOTP/DHCPv4 transaction ID.
Enhance DHCPv4 sending/parsing option 209 (PXE config file). A previous
patch was accepted. A new patch fixes a possible double free() and
addresses latest review comments.
Link: https://lore.kernel.org/r/[email protected]
| -rw-r--r-- | cmd/Kconfig | 25 | ||||
| -rw-r--r-- | cmd/pxe.c | 2 | ||||
| -rw-r--r-- | lib/Kconfig | 3 | ||||
| -rw-r--r-- | net/bootp.c | 73 | ||||
| -rw-r--r-- | net/bootp.h | 2 |
5 files changed, 87 insertions, 18 deletions
diff --git a/cmd/Kconfig b/cmd/Kconfig index f21d27cb27f..9a70c7a0b83 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -1986,6 +1986,7 @@ config BOOTP_PXE_CLIENTARCH config BOOTP_PXE_DHCP_OPTION bool "Request & store 'pxe_configfile' from BOOTP/DHCP server" + default y depends on BOOTP_PXE config BOOTP_VCI_STRING @@ -1996,6 +1997,30 @@ config BOOTP_VCI_STRING default "U-Boot.arm" if ARM default "U-Boot" +config BOOTP_RANDOM_XID + bool "Send random transaction ID to BOOTP/DHCP server" + depends on CMD_BOOTP && (LIB_RAND || LIB_HW_RAND) + help + Selecting this will allow for a random transaction ID to get + selected for each BOOTP/DHCPv4 exchange. + +if CMD_DHCP6 + +config DHCP6_PXE_CLIENTARCH + hex + default 0x16 if ARM64 + default 0x15 if ARM + default 0xFF + +config DHCP6_PXE_DHCP_OPTION + bool "Request & store 'pxe_configfile' from DHCP6 server" + +config DHCP6_ENTERPRISE_ID + int "Enterprise ID to send in DHCPv6 Vendor Class Option" + default 0 + +endif + config CMD_TFTPPUT bool "tftp put" depends on CMD_TFTPBOOT diff --git a/cmd/pxe.c b/cmd/pxe.c index 0f26b3b4219..71d8b542b28 100644 --- a/cmd/pxe.c +++ b/cmd/pxe.c @@ -64,6 +64,8 @@ static int pxe_dhcp_option_path(struct pxe_context *ctx, unsigned long pxefile_a int ret = get_pxe_file(ctx, pxelinux_configfile, pxefile_addr_r); free(pxelinux_configfile); + /* set to NULL to avoid double-free if DHCP is tried again */ + pxelinux_configfile = NULL; return ret; } diff --git a/lib/Kconfig b/lib/Kconfig index cdf8f7ee0e8..6a89f797bef 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -283,7 +283,8 @@ config REGEX choice prompt "Pseudo-random library support type" depends on NET_RANDOM_ETHADDR || RANDOM_UUID || CMD_UUID || \ - RNG_SANDBOX || UT_LIB && AES || FAT_WRITE + RNG_SANDBOX || UT_LIB && AES || FAT_WRITE || CMD_BOOTP || \ + CMD_DHCP || CMD_DHCP6 default LIB_RAND help Select the library to provide pseudo-random number generator diff --git a/net/bootp.c b/net/bootp.c index afd5b48094a..f22921ed388 100644 --- a/net/bootp.c +++ b/net/bootp.c @@ -41,6 +41,22 @@ */ #define TIMEOUT_MS ((3 + (CONFIG_NET_RETRY_COUNT * 5)) * 1000) +/* + * According to rfc951 : 7.2. Client Retransmission Strategy + * "After the 'average' backoff reaches about 60 seconds, it should be + * increased no further, but still randomized." + * + * U-Boot has saturated this backoff at 2 seconds for a long time. + * To modify, set the environment variable "bootpretransmitperiodmax" + */ +#define RETRANSMIT_PERIOD_MAX_MS 60000 + +/* Retransmission timeout for the initial packet (in milliseconds). + * This timeout will double on each retry. To modify, set the + * environment variable bootpretransmitperiodinit. + */ +#define RETRANSMIT_PERIOD_INIT_MS 250 + #ifndef CFG_DHCP_MIN_EXT_LEN /* minimal length of extension list */ #define CFG_DHCP_MIN_EXT_LEN 64 #endif @@ -52,6 +68,7 @@ u32 bootp_ids[CFG_BOOTP_ID_CACHE_SIZE]; unsigned int bootp_num_ids; int bootp_try; +u32 bootp_id; ulong bootp_start; ulong bootp_timeout; char net_nis_domain[32] = {0,}; /* Our NIS domain */ @@ -59,6 +76,7 @@ char net_hostname[32] = {0,}; /* Our hostname */ char net_root_path[CONFIG_BOOTP_MAX_ROOT_PATH_LEN] = {0,}; /* Our bootpath */ static ulong time_taken_max; +static u32 retransmit_period_max_ms; #if defined(CONFIG_CMD_DHCP) static dhcp_state_t dhcp_state = INIT; @@ -395,6 +413,7 @@ static void bootp_handler(uchar *pkt, unsigned dest, struct in_addr sip, static void bootp_timeout_handler(void) { ulong time_taken = get_timer(bootp_start); + int rand_minus_plus_100; if (time_taken >= time_taken_max) { #ifdef CONFIG_BOOTP_MAY_FAIL @@ -413,8 +432,17 @@ static void bootp_timeout_handler(void) } } else { bootp_timeout *= 2; - if (bootp_timeout > 2000) - bootp_timeout = 2000; + if (bootp_timeout > retransmit_period_max_ms) + bootp_timeout = retransmit_period_max_ms; + + /* Randomize by adding bootp_timeout*RAND, where RAND + * is a randomization factor between -0.1..+0.1 + */ + srand(get_ticks() + rand()); + rand_minus_plus_100 = ((rand() % 200) - 100); + bootp_timeout = bootp_timeout + + (((int)bootp_timeout * rand_minus_plus_100) / 1000); + net_set_timeout_handler(bootp_timeout, bootp_timeout_handler); bootp_request(); } @@ -602,7 +630,7 @@ static int dhcp_extended(u8 *e, int message_type, struct in_addr server_ip, *cnt += 1; #endif if (IS_ENABLED(CONFIG_BOOTP_PXE_DHCP_OPTION)) { - *e++ = 209; /* PXELINUX Config File */ + *e++ = DHCP_OPTION_PXE_CONFIG_FILE; /* PXELINUX Config File */ *cnt += 1; } /* no options, so back up to avoid sending an empty request list */ @@ -713,7 +741,8 @@ void bootp_reset(void) bootp_num_ids = 0; bootp_try = 0; bootp_start = get_timer(0); - bootp_timeout = 250; + + bootp_timeout = env_get_ulong("bootpretransmitperiodinit", 10, RETRANSMIT_PERIOD_INIT_MS); } void bootp_request(void) @@ -725,7 +754,6 @@ void bootp_request(void) #ifdef CONFIG_BOOTP_RANDOM_DELAY ulong rand_ms; #endif - u32 bootp_id; struct in_addr zero_ip; struct in_addr bcast_ip; char *ep; /* Environment pointer */ @@ -741,6 +769,9 @@ void bootp_request(void) else time_taken_max = TIMEOUT_MS; + retransmit_period_max_ms = env_get_ulong("bootpretransmitperiodmax", 10, + RETRANSMIT_PERIOD_MAX_MS); + #ifdef CONFIG_BOOTP_RANDOM_DELAY /* Random BOOTP delay */ if (bootp_try == 0) srand_mac(); @@ -800,19 +831,27 @@ void bootp_request(void) extlen = bootp_extended((u8 *)bp->bp_vend); #endif - /* - * Bootp ID is the lower 4 bytes of our ethernet address - * plus the current time in ms. - */ - bootp_id = ((u32)net_ethaddr[2] << 24) - | ((u32)net_ethaddr[3] << 16) - | ((u32)net_ethaddr[4] << 8) - | (u32)net_ethaddr[5]; - bootp_id += get_timer(0); - bootp_id = htonl(bootp_id); + /* Only generate a new transaction ID for each new BOOTP request */ + if (bootp_try == 1) { + if (IS_ENABLED(CONFIG_BOOTP_RANDOM_XID)) { + srand(get_ticks() + rand()); + bootp_id = rand(); + } else { + /* + * Bootp ID is the lower 4 bytes of our ethernet address + * plus the current time in ms. + */ + bootp_id = ((u32)net_ethaddr[2] << 24) + | ((u32)net_ethaddr[3] << 16) + | ((u32)net_ethaddr[4] << 8) + | (u32)net_ethaddr[5]; + bootp_id += get_timer(0); + bootp_id = htonl(bootp_id); + } + } + bootp_add_id(bootp_id); net_copy_u32(&bp->bp_id, &bootp_id); - /* * Calculate proper packet lengths taking into account the * variable size of the options field @@ -921,7 +960,7 @@ static void dhcp_process_options(uchar *popt, uchar *end) net_boot_file_name[size] = 0; } break; - case 209: /* PXELINUX Config File */ + case DHCP_OPTION_PXE_CONFIG_FILE: /* PXELINUX Config File */ if (IS_ENABLED(CONFIG_BOOTP_PXE_DHCP_OPTION)) { /* In case it has already been allocated when get DHCP Offer packet, * free first to avoid memory leak. diff --git a/net/bootp.h b/net/bootp.h index 521d38f3528..68320bf66cf 100644 --- a/net/bootp.h +++ b/net/bootp.h @@ -90,6 +90,8 @@ typedef enum { INIT, #define DHCP_NAK 6 #define DHCP_RELEASE 7 +#define DHCP_OPTION_PXE_CONFIG_FILE 209 /* "ConfigFile" option according to rfc5071 */ + /**********************************************************************/ #endif /* __BOOTP_H__ */ |
