Merge patch series "BOOTP/DHCPv4 enhancements"
Sean Edmond <seanedmond@microsoft.com> 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/20240509023918.2504185-1-seanedmond@microsoft.com
This commit is contained in:
25
cmd/Kconfig
25
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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
73
net/bootp.c
73
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.
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
Reference in New Issue
Block a user