From b940d54235579f2534c12494322876fff555cf36 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 2 Apr 2024 19:36:00 +0100 Subject: [PATCH] [cachedhcp] Allow cached DHCPACK to apply to temporary network devices Retain a reference to the cached DHCPACK until the late startup phase, and allow it to be recycled for reuse. This allows the cached DHCPACK to be used for a temporary MNP network device and then subsequently reused for the corresponding real network device. Signed-off-by: Michael Brown --- src/core/cachedhcp.c | 75 +++++++++++++++++++++++++++++++----- src/drivers/net/efi/mnpnet.c | 4 ++ src/include/ipxe/cachedhcp.h | 2 + 3 files changed, 71 insertions(+), 10 deletions(-) diff --git a/src/core/cachedhcp.c b/src/core/cachedhcp.c index 57226e165..04945e646 100644 --- a/src/core/cachedhcp.c +++ b/src/core/cachedhcp.c @@ -46,11 +46,20 @@ struct cached_dhcp_packet { struct dhcp_packet *dhcppkt; /** VLAN tag (if applicable) */ unsigned int vlan; + /** Flags */ + unsigned int flags; }; +/** Cached DHCP packet should be retained */ +#define CACHEDHCP_RETAIN 0x0001 + +/** Cached DHCP packet has been used */ +#define CACHEDHCP_USED 0x0002 + /** Cached DHCPACK */ struct cached_dhcp_packet cached_dhcpack = { .name = DHCP_SETTINGS_NAME, + .flags = CACHEDHCP_RETAIN, }; /** Cached ProxyDHCPOFFER */ @@ -101,8 +110,8 @@ static int cachedhcp_apply ( struct cached_dhcp_packet *cache, size_t ll_addr_len; int rc; - /* Do nothing if cache is empty */ - if ( ! cache->dhcppkt ) + /* Do nothing if cache is empty or already in use */ + if ( ( ! cache->dhcppkt ) || ( cache->flags & CACHEDHCP_USED ) ) return 0; chaddr = cache->dhcppkt->dhcphdr->chaddr; @@ -169,8 +178,12 @@ static int cachedhcp_apply ( struct cached_dhcp_packet *cache, return rc; } - /* Free cached DHCP packet */ - cachedhcp_free ( cache ); + /* Mark as used */ + cache->flags |= CACHEDHCP_USED; + + /* Free cached DHCP packet, if applicable */ + if ( ! ( cache->flags & CACHEDHCP_RETAIN ) ) + cachedhcp_free ( cache ); return 0; } @@ -246,10 +259,10 @@ int cachedhcp_record ( struct cached_dhcp_packet *cache, unsigned int vlan, } /** - * Cached DHCP packet startup function + * Cached DHCP packet early startup function * */ -static void cachedhcp_startup ( void ) { +static void cachedhcp_startup_early ( void ) { /* Apply cached ProxyDHCPOFFER, if any */ cachedhcp_apply ( &cached_proxydhcp, NULL ); @@ -258,6 +271,20 @@ static void cachedhcp_startup ( void ) { /* Apply cached PXEBSACK, if any */ cachedhcp_apply ( &cached_pxebs, NULL ); cachedhcp_free ( &cached_pxebs ); +} + +/** + * Cache DHCP packet late startup function + * + */ +static void cachedhcp_startup_late ( void ) { + + /* Clear retention flag */ + cached_dhcpack.flags &= ~CACHEDHCP_RETAIN; + + /* Free cached DHCPACK, if used by a network device */ + if ( cached_dhcpack.flags & CACHEDHCP_USED ) + cachedhcp_free ( &cached_dhcpack ); /* Report unclaimed DHCPACK, if any. Do not free yet, since * it may still be claimed by a dynamically created device @@ -284,10 +311,16 @@ static void cachedhcp_shutdown ( int booting __unused ) { cachedhcp_free ( &cached_dhcpack ); } -/** Cached DHCPACK startup function */ -struct startup_fn cachedhcp_startup_fn __startup_fn ( STARTUP_LATE ) = { - .name = "cachedhcp", - .startup = cachedhcp_startup, +/** Cached DHCP packet early startup function */ +struct startup_fn cachedhcp_early_fn __startup_fn ( STARTUP_EARLY ) = { + .name = "cachedhcp1", + .startup = cachedhcp_startup_early, +}; + +/** Cached DHCP packet late startup function */ +struct startup_fn cachedhcp_late_fn __startup_fn ( STARTUP_LATE ) = { + .name = "cachedhcp2", + .startup = cachedhcp_startup_late, .shutdown = cachedhcp_shutdown, }; @@ -309,3 +342,25 @@ struct net_driver cachedhcp_driver __net_driver = { .name = "cachedhcp", .probe = cachedhcp_probe, }; + +/** + * Recycle cached DHCPACK + * + * @v netdev Network device + * @v priv Private data + */ +void cachedhcp_recycle ( struct net_device *netdev ) { + struct cached_dhcp_packet *cache = &cached_dhcpack; + struct settings *settings; + + /* Return DHCPACK to cache, if applicable */ + settings = find_child_settings ( netdev_settings ( netdev ), + cache->name ); + if ( cache->dhcppkt && ( settings == &cache->dhcppkt->settings ) ) { + DBGC ( colour, "CACHEDHCP %s recycled from %s\n", + cache->name, netdev->name ); + assert ( cache->flags & CACHEDHCP_USED ); + unregister_settings ( settings ); + cache->flags &= ~CACHEDHCP_USED; + } +} diff --git a/src/drivers/net/efi/mnpnet.c b/src/drivers/net/efi/mnpnet.c index 84f803f45..eb4b129c7 100644 --- a/src/drivers/net/efi/mnpnet.c +++ b/src/drivers/net/efi/mnpnet.c @@ -34,6 +34,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include #include #include @@ -551,6 +552,9 @@ void mnptemp_destroy ( struct net_device *netdev ) { struct mnp_nic *mnp = netdev->priv; struct efi_device *efidev = mnp->efidev; + /* Recycle any cached DHCP packet */ + cachedhcp_recycle ( netdev ); + /* Stop temporary network device */ mnpnet_stop ( efidev ); diff --git a/src/include/ipxe/cachedhcp.h b/src/include/ipxe/cachedhcp.h index 4ce4a9f2a..8ebee3b7b 100644 --- a/src/include/ipxe/cachedhcp.h +++ b/src/include/ipxe/cachedhcp.h @@ -12,6 +12,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include +struct net_device; struct cached_dhcp_packet; extern struct cached_dhcp_packet cached_dhcpack; @@ -21,5 +22,6 @@ extern struct cached_dhcp_packet cached_pxebs; extern int cachedhcp_record ( struct cached_dhcp_packet *cache, unsigned int vlan, userptr_t data, size_t max_len ); +extern void cachedhcp_recycle ( struct net_device *netdev ); #endif /* _IPXE_CACHEDHCP_H */