Skip to content

Commit fa1d7d2

Browse files
committed
Signed-off-by: Rishikpulhani <[email protected]>
feat(dhcp): Send DHCPRELEASE on container teardown When a container using DHCP is torn down, its lease is left active on the DHCP server until it expires. This can be problematic in environments with small IP pools or long lease times. In setups using Dynamic DNS (DDNS), it can also lead to stale DNS records. This change introduces the capability for netavark to send a DHCPRELEASE message to the DHCP server when a container's network is torn down. This is implemented by: - Adding a `release_lease` method to the `DhcpV4Service` in `dhcp_service.rs`, which wraps the `release` function from the underlying mozim client. - Modifying the `teardown` gRPC handler in `dhcp_proxy.rs` to create a temporary `DhcpV4Service` instance, retrieve the lease from the cache, and call the new `release_lease` method in a "best-effort" manner.
1 parent 6b44b7e commit fa1d7d2

File tree

3 files changed

+58
-2
lines changed

3 files changed

+58
-2
lines changed

src/commands/dhcp_proxy.rs

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,8 @@ impl<W: Write + Clear + Send + 'static> NetavarkProxy for NetavarkProxyService<W
136136
};
137137
}
138138

139-
/// When a container is shut down this method should be called. It will clear the lease information
140-
/// from the caching system.
139+
/// When a container is shut down this method should be called. It will release the
140+
/// DHCP lease and clear the lease information from the caching system.
141141
async fn teardown(
142142
&self,
143143
request: Request<NetworkConfig>,
@@ -164,6 +164,36 @@ impl<W: Write + Clear + Send + 'static> NetavarkProxy for NetavarkProxyService<W
164164
.remove_lease(&nc.container_mac_addr)
165165
.map_err(|e| Status::internal(e.to_string()))?;
166166

167+
// We have the lease, now try to release it. This is a "best effort"
168+
// operation. If it fails, we log the error but do not fail the
169+
// teardown process.
170+
match mozim::DhcpV4Lease::try_from(lease.clone()) {
171+
Ok(mozim_lease) => {
172+
// We use a clone of 'nc' for the new service, and the original 'nc' for logging.
173+
match DhcpV4Service::new(nc.clone(), self.dora_timeout) {
174+
Ok(mut service) => {
175+
if let Err(e) = service.release_lease(&mozim_lease) {
176+
// Log the error but continue. Use the correct variable for the MAC address.
177+
warn!(
178+
"Failed to send DHCPRELEASE for {}: {}",
179+
&nc.container_mac_addr, e
180+
);
181+
} else {
182+
debug!(
183+
"Successfully sent DHCPRELEASE for {}",
184+
&nc.container_mac_addr
185+
);
186+
}
187+
}
188+
Err(e) => {
189+
warn!("Failed to create DHCP service for release: {e}");
190+
}
191+
}
192+
}
193+
Err(e) => {
194+
warn!("Failed to convert lease for release: {e}");
195+
}
196+
}
167197
Ok(Response::new(lease))
168198
}
169199

src/dhcp_proxy/dhcp_service.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,19 @@ impl DhcpV4Service {
129129
"Could not find a lease within the timeout limit".to_string(),
130130
))
131131
}
132+
133+
/// Sends a DHCPRELEASE message for the given lease.
134+
/// This is a "best effort" operation and should not block teardown.
135+
pub fn release_lease(&mut self, lease: &MozimV4Lease) -> Result<(), DhcpServiceError> {
136+
debug!(
137+
"Attempting to release lease for MAC: {}",
138+
&self.network_config.container_mac_addr
139+
);
140+
// Directly call the release function on the underlying mozim client.
141+
self.client
142+
.release(lease)
143+
.map_err(|e| DhcpServiceError::new(Bug, e.to_string()))
144+
}
132145
}
133146

134147
impl std::fmt::Display for DhcpServiceError {

test-dhcp/003-teardown.bats

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@
55

66
load helpers
77

8+
# Redefine start_proxy locally to enable debug logging for this test only.
9+
# This version will be used instead of the one from helpers.bash.
10+
function start_proxy() {
11+
RUST_LOG=debug ip netns exec "$NS_NAME" $NETAVARK dhcp-proxy --dir "$TMP_TESTDIR" --uds "$TMP_TESTDIR" &>"$TMP_TESTDIR/proxy.log" &
12+
PROXY_PID=$!
13+
}
14+
815
@test "basic teardown" {
916
read -r -d '\0' input_config <<EOF
1017
{
@@ -30,6 +37,12 @@ EOF
3037
assert "$output" == "true"
3138
# Run teardown
3239
run_teardown "$input_config"
40+
# Check the NETAVARK PROXY log to confirm it successfully SENT the release.
41+
# In this test environment, the virtual bridge may not reliably deliver the
42+
# broadcast DHCPRELEASE packet to the dnsmasq listener. We check the
43+
# proxy's own log for the success message, as this directly confirms
44+
# the code path was executed successfully.
45+
run_helper grep "Successfully sent DHCPRELEASE for ${CONTAINER_MAC}" "$TMP_TESTDIR/proxy.log"
3346
run_helper cat "$TMP_TESTDIR/nv-proxy.lease"
3447
# Check that the length of the lease file is now zero
3548
run_helper jq ". | length" <<<"$output"

0 commit comments

Comments
 (0)