Skip to content

Commit

Permalink
Add lease release support in ASYNC API
Browse files Browse the repository at this point in the history
Introducing these functions to release the lease:
 * `DhcpV6ClientAsync::release()`
 * `DhcpV4ClientAsync::release()`

If user want to get new release after lease been released, new instance
of DHCP Client should be created.

Example code and integration test cases updated.

Signed-off-by: Gris Ge <[email protected]>
  • Loading branch information
cathay4t committed Dec 16, 2024
1 parent f0d93aa commit 8f97403
Show file tree
Hide file tree
Showing 10 changed files with 98 additions and 11 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,6 @@ TODO:
# The `eth1.ep` is DHCP server interface running dnsmasq in `mozim` network
# namespace.
sudo ./utils/test_env_mozim &
cargo run --example mozim_dhcpv4_sync
cargo run --example mozim_dhcpv4_async
cargo run --example mozim_dhcpv6_sync
```
14 changes: 8 additions & 6 deletions examples/mozim_dhcpv4_sync.rs → examples/mozim_dhcpv4_async.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
config.set_timeout(60);
let mut cli = DhcpV4ClientAsync::init(config, None).unwrap();

while let Some(Ok(lease)) = cli.next().await {
// You need to code to apply the IP address in lease to this NIC, so
// follow up renew can work.
println!("Got lease {lease:?}");
loop {
if let Some(Ok(lease)) = cli.next().await {
// You need to code to apply the IP address in lease to this NIC, so
// follow up renew can work.
println!("Got lease {lease:?}");
cli.release(&lease)?;
return Ok(());
}
}

Ok(())
}

fn enable_log() {
Expand Down
2 changes: 2 additions & 0 deletions examples/mozim_dhcpv6_sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
for event in cli.poll(POLL_WAIT_TIME)? {
if let Some(lease) = cli.process(event)? {
println!("Got DHCPv6 lease {:?}", lease);
cli.release(&lease)?;
return Ok(());
}
}
}
Expand Down
14 changes: 14 additions & 0 deletions src/client_async.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ pub struct DhcpV4ClientAsync {
share_state: Arc<Mutex<ShareState>>,
}

impl DhcpV4ClientAsync {
/// Release the lease acquired from DHCPv4 server.
pub fn release(&mut self, lease: &DhcpV4Lease) -> Result<(), DhcpError> {
self.client.release(lease)
}
}

impl Stream for DhcpV4ClientAsync {
type Item = Result<DhcpV4Lease, DhcpError>;

Expand Down Expand Up @@ -241,3 +248,10 @@ impl std::ops::Drop for DhcpV6ClientAsync {
}
}
}

impl DhcpV6ClientAsync {
/// Release the lease acquired from DHCPv6 server.
pub fn release(&mut self, lease: &DhcpV6Lease) -> Result<(), DhcpError> {
self.client.release(lease)
}
}
22 changes: 19 additions & 3 deletions src/dhcpv4/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,9 @@ impl DhcpV4Client {
}
}

/// Release the DHCPv4 lease.
/// To request new lease once released, please create new instance of
/// [DhcpV4Client].
pub fn release(&mut self, lease: &DhcpV4Lease) -> Result<(), DhcpError> {
let mut dhcp_msg = DhcpV4Message::new(
&self.config,
Expand All @@ -553,13 +556,26 @@ impl DhcpV4Client {
let raw_socket = DhcpRawSocket::new(&self.config)?;
raw_socket.send(&dhcp_msg.to_proxy_eth_pkg_unicast()?)?;
} else {
let udp_socket = DhcpUdpSocket::new(
// Cannot create UDP socket when interface does not have DHCP IP
// assigned, so we fallback to RAW socket
match DhcpUdpSocket::new(
self.config.iface_name.as_str(),
&lease.yiaddr,
&lease.siaddr,
self.config.socket_timeout,
)?;
udp_socket.send(&dhcp_msg.to_dhcp_pkg()?)?;
) {
Ok(udp_socket) => {
udp_socket.send(&dhcp_msg.to_dhcp_pkg()?)?;
}
Err(e) => {
log::debug!(
"Failed to create UDP socket to release lease {e}, \
fallback to RAW socket"
);
let raw_socket = DhcpRawSocket::new(&self.config)?;
raw_socket.send(&dhcp_msg.to_proxy_eth_pkg_unicast()?)?;
}
}
}
self.clean_up();
Ok(())
Expand Down
42 changes: 42 additions & 0 deletions src/dhcpv6/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,14 @@ impl AsRawFd for DhcpV6Client {
}

impl DhcpV6Client {
fn clean_up(&mut self) {
self.lease = None;
self.retrans_count = 0;
self.phase = DhcpV6Phase::Done;
self.event_pool.remove_all_event();
self.udp_socket = None;
}

pub fn init(
mut config: DhcpV6Config,
lease: Option<DhcpV6Lease>,
Expand Down Expand Up @@ -167,6 +175,40 @@ impl DhcpV6Client {
}
}

/// The RFC 8415:
/// Implementations SHOULD retransmit one or more times but MAY choose
/// to terminate the retransmission procedure early.
/// So here we decided not to wait reply from DHCPv6 server.
/// To request new release, you need to create new instance of
/// [DhcpV6Client].
pub fn release(&mut self, lease: &DhcpV6Lease) -> Result<(), DhcpError> {
if self.udp_socket.is_none() {
let socket = DhcpUdpSocket::new_v6(
self.config.iface_index,
&self.config.src_ip,
self.config.socket_timeout,
)?;
self.udp_socket = Some(socket);
}
let socket = self.udp_socket.as_ref().unwrap();

let mut dhcp_msg = DhcpV6Message::new(
&self.config,
DhcpV6MessageType::RELEASE,
self.xid,
);
dhcp_msg.load_lease(lease.clone())?;
let dst = if lease.srv_ip.is_unspecified() {
&DHCPV6_REPLAY_AND_SRVS
} else {
&lease.srv_ip
};
socket.send_to_v6(dst, &dhcp_msg.to_dhcp_pkg()?)?;

self.clean_up();
Ok(())
}

fn process_solicit(&mut self) -> Result<(), DhcpError> {
self.phase = DhcpV6Phase::PreSolicit;
self.lease = None;
Expand Down
5 changes: 5 additions & 0 deletions src/dhcpv6/lease.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ pub struct DhcpV6Lease {
pub cli_duid: Vec<u8>,
pub srv_duid: Vec<u8>,
pub dhcp_opts: Vec<dhcproto::v6::DhcpOption>,
pub srv_ip: Ipv6Addr,
}

impl Default for DhcpV6Lease {
Expand All @@ -45,6 +46,7 @@ impl Default for DhcpV6Lease {
cli_duid: Vec::new(),
srv_duid: Vec::new(),
dhcp_opts: Vec::new(),
srv_ip: Ipv6Addr::UNSPECIFIED,
}
}
}
Expand Down Expand Up @@ -79,6 +81,9 @@ impl std::convert::TryFrom<&v6::Message> for DhcpV6Lease {
ret.t2 = v.t2;
parse_dhcp_opt_iaadr(&v.opts, &mut ret);
}
DhcpOption::ServerUnicast(srv_ip) => {
ret.srv_ip = *srv_ip;
}
DhcpOption::StatusCode(v) => {
if v.status != v6::Status::Success {
return Err(DhcpError::new(
Expand Down
6 changes: 5 additions & 1 deletion src/dhcpv6/msg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ impl DhcpV6MessageType {
pub(crate) const REPLY: Self = DhcpV6MessageType(v6::MessageType::Reply);
pub(crate) const RENEW: Self = DhcpV6MessageType(v6::MessageType::Renew);
pub(crate) const REBIND: Self = DhcpV6MessageType(v6::MessageType::Rebind);
pub(crate) const RELEASE: Self =
DhcpV6MessageType(v6::MessageType::Release);
}

impl Default for DhcpV6MessageType {
Expand Down Expand Up @@ -170,7 +172,9 @@ impl DhcpV6Message {

match self.msg_type {
DhcpV6MessageType::SOLICIT | DhcpV6MessageType::REBIND => (),
DhcpV6MessageType::REQUEST | DhcpV6MessageType::RENEW => {
DhcpV6MessageType::REQUEST
| DhcpV6MessageType::RENEW
| DhcpV6MessageType::RELEASE => {
if let Some(lease) = self.lease.as_ref() {
dhcp_msg
.opts_mut()
Expand Down
1 change: 1 addition & 0 deletions src/integ_tests/dhcpv4_async.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ fn test_dhcpv4_async() {
// call to use_host_name_as_client_id(), then the server should
// return FOO1_STATIC_IP_HOSTNAME_AS_CLIENT_ID.
assert_eq!(lease.yiaddr, FOO1_STATIC_IP_HOSTNAME_AS_CLIENT_ID,);
cli.release(&lease).unwrap();
}
})
}
Expand Down
1 change: 1 addition & 0 deletions src/integ_tests/dhcpv6_async.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ fn test_dhcpv6_async() {
// call to use_host_name_as_client_id(), then the server should
// return FOO1_STATIC_IP_HOSTNAME_AS_CLIENT_ID.
assert_eq!(lease.addr, FOO1_STATIC_IPV6);
cli.release(&lease).unwrap();
}
})
}
Expand Down

0 comments on commit 8f97403

Please sign in to comment.