[dhcp] Add reset_*() to fuchsia.net.dhcp.Server Add reset_options() and reset_parameters() FIDL methods to fuchsia.net.dhcp.Server, implement these methods in dhcpd, use them in dhcpd-cli, and add tests covering this functionality. Test: - fx run-test dhcp_tests - fx run-test dhcpd_tests - fx run-test dhcpd_cli_tests Bug: 109 Change-Id: If2609991c1ac913079089c85f53736125fb1da30
diff --git a/sdk/fidl/fuchsia.net.dhcp/fuchsia.net.dhcp.api b/sdk/fidl/fuchsia.net.dhcp/fuchsia.net.dhcp.api index 47be32e..02d004c 100644 --- a/sdk/fidl/fuchsia.net.dhcp/fuchsia.net.dhcp.api +++ b/sdk/fidl/fuchsia.net.dhcp/fuchsia.net.dhcp.api
@@ -1,5 +1,5 @@ { "fidl/fuchsia.net.dhcp/client.fidl": "ed712ac30e34dd3900d88e730a346ce6", "fidl/fuchsia.net.dhcp/options.fidl": "dab189ad92092bfaa3c910fe34f9609d", - "fidl/fuchsia.net.dhcp/server.fidl": "5d4d1dd038043a108f08bcca7aa00924" + "fidl/fuchsia.net.dhcp/server.fidl": "f85984b657e00e24424697f7ce414ee8" } \ No newline at end of file
diff --git a/sdk/fidl/fuchsia.net.dhcp/server.fidl b/sdk/fidl/fuchsia.net.dhcp/server.fidl index 1f912bc..8b30bf2 100644 --- a/sdk/fidl/fuchsia.net.dhcp/server.fidl +++ b/sdk/fidl/fuchsia.net.dhcp/server.fidl
@@ -106,37 +106,61 @@ /// * error a zx.status indicating why the value could not be retrieved. GetParameter(ParameterName name) -> (Parameter value) error zx.status; - /// Sets the Option to the argument. Each SetOption call is treated as its own atomic - /// transaction. On success, a SetOption will take effect immediately. + /// Sets the Option to the argument. On success, a SetOption will take + /// effect immediately. /// - /// + request `value` an Option whose value will be set to the value of this argument. + /// + request `value` an Option whose value will be set to the value of this + /// argument. /// * error a zx.status indicating the cause of failure. SetOption(Option value) -> () error zx.status; - /// Sets the Parameter to the argument. Each SetParameter call is treated as its own atomic - /// transaction. On success, a SetParameter will take effect immediately. + /// Sets the Parameter to the argument. On success, the new parameter value + /// can be queried by GetParameter or ListParameter immediately. However, + /// the server may require a restart in order for the new Parameter value to + /// take effect. To ensure expected operation, administrators should restart + /// the server after mutating its parameters with SetParameter or + /// ResetParameters. /// - /// + request `value` a Parameter whose value will be set to the value of this argument. + /// + request `value` a Parameter whose value will be set to the value of + /// this argument. /// * error a zx.status indicating the cause of failure. SetParameter(Parameter value) -> () error zx.status; - /// Lists all DHCP options for which the Server has a value. Any option which does - /// not have a value will be omitted from the returned list. ListOptions provides administrators - /// a means to print a server's configuration as opposed to querying the value of a single - /// Option. + /// Lists all DHCP options for which the Server has a value. Any option + /// which does not have a value will be omitted from the returned list. + /// ListOptions provides administrators a means to print a server's + /// configuration as opposed to querying the value of a single Option. /// - /// - response `options` a vector containing all of the options for which the Server has a - /// value. Bounded to 256 as options are identified by a 1 octet code and 256 is the maximum - /// number of such codes. + /// - response `options` a vector containing all of the options for which + /// the Server has a value. Bounded to 256 as options are identified by a 1 + /// octet code and 256 is the maximum number of such codes. /// * error a zx.status indicating the cause of failure. ListOptions() -> (vector<Option>:256 options) error zx.status; - /// Lists all DHCP server parameters. ListParameters provides administrators a means to print a - /// server's configuration as opposed to querying the value of a single Parameter. + /// Lists all DHCP server parameters. ListParameters provides administrators + /// a means to print a server's configuration as opposed to querying the + /// value of a single Parameter. /// - /// - response `parameter` a vector containing the values of all of the Server's parameters. - /// Bounded to 256 to provide a generous upper limit on the number of server parameters while - /// being of the same size as ListOptions. + /// - response `parameter` a vector containing the values of all of the + /// Server's parameters. Bounded to 256 to provide a generous upper limit + /// on the number of server parameters while being of the same size as + /// ListOptions. /// * error a zx.status indicating the cause of failure. ListParameters() -> (vector<Parameter>:256 parameters) error zx.status; + + /// Resets all DHCP options to have no value. On success, ResetOptions will + /// take effect immediately. + /// + /// * error a zx.status indicating the cause of failure. + ResetOptions() -> () error zx.status; + + /// Resets all DHCP server parameters to their default value. On success, + /// the reset parameter values can be queried immediately with GetParameter + /// or ListParameters. However, the server must be restarted before all new + /// parameter values take effect. To ensure expected operation, + /// administrators should restart the server after mutating its parameters + /// with SetParameter or ResetParameters. + /// + /// * error a zx.status indicating the cause of failure. + ResetParameters() -> () error zx.status; };
diff --git a/src/connectivity/network/dhcp/src/configuration.rs b/src/connectivity/network/dhcp/src/configuration.rs index 2638b05..e0d1f2e 100644 --- a/src/connectivity/network/dhcp/src/configuration.rs +++ b/src/connectivity/network/dhcp/src/configuration.rs
@@ -21,7 +21,7 @@ } /// A collection of the basic configuration parameters needed by the server. -#[derive(Debug, Deserialize, PartialEq, Serialize)] +#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] pub struct ServerParameters { /// The IPv4 addresses of the host running the server. pub server_ips: Vec<Ipv4Addr>,
diff --git a/src/connectivity/network/dhcp/src/main.rs b/src/connectivity/network/dhcp/src/main.rs index 6f2876d..b8c3f3a 100644 --- a/src/connectivity/network/dhcp/src/main.rs +++ b/src/connectivity/network/dhcp/src/main.rs
@@ -14,7 +14,6 @@ }, fuchsia_async::{self as fasync, net::UdpSocket, Interval}, fuchsia_component::server::ServiceFs, - fuchsia_syslog::{self as fx_syslog, fx_log_err, fx_log_info}, fuchsia_zircon::DurationNum, futures::{Future, FutureExt, StreamExt, TryFutureExt, TryStreamExt}, net2::unix::UnixUdpBuilderExt, @@ -58,16 +57,17 @@ #[fasync::run_singlethreaded] async fn main() -> Result<(), Error> { - fx_syslog::init_with_tags(&["dhcpd"])?; + fuchsia_syslog::init_with_tags(&["dhcpd"])?; let Args { config, stash } = argh::from_env(); let stash = dhcp::stash::Stash::new(&stash, DEFAULT_STASH_PREFIX) .context("failed to instantiate stash")?; - let params = stash.load_parameters().await.or_else(|e| { - fx_syslog::fx_log_warn!("failed to load parameters from stash: {}", e); - configuration::load_server_params_from_file(&config) - .context("failed to load server parameters from configuration file") - })?; + let default_params = configuration::load_server_params_from_file(&config) + .context("failed to load default server parameters from configuration file")?; + let params = stash.load_parameters().await.unwrap_or_else(|e| { + log::warn!("failed to load parameters from stash: {:?}", e); + default_params.clone() + }); let socks = if params.bound_device_names.len() > 0 { params.bound_device_names.iter().map(String::as_str).try_fold::<_, _, Result<_, Error>>( Vec::new(), @@ -81,14 +81,14 @@ vec![create_socket(None)?] }; if socks.len() == 0 { - return Err(anyhow::format_err!("no valid sockets to receive messages from")); + return Err(anyhow::Error::msg("no valid sockets to receive messages from")); } let options = stash.load_options().await.unwrap_or_else(|e| { - fx_syslog::fx_log_warn!("failed to load options from stash: {}", e); + log::warn!("failed to load options from stash: {:?}", e); std::collections::HashMap::new() }); let cache = stash.load_client_configs().await.unwrap_or_else(|e| { - fx_syslog::fx_log_warn!("failed to load cached client config from stash: {}", e); + log::warn!("failed to load cached client config from stash: {:?}", e); std::collections::HashMap::new() }); let server = RefCell::new(Server::new(stash, params, options, cache)); @@ -100,21 +100,23 @@ fs.then(futures::future::ok).try_for_each_concurrent(None, |incoming_service| async { match incoming_service { IncomingService::Server(stream) => { - run_server(stream, &server).inspect_err(|e| log::info!("{:?}", e)).await?; + run_server(stream, &server, &default_params) + .inspect_err(|e| log::warn!("run_server failed: {:?}", e)) + .await?; Ok(()) } } }); if !server.borrow().is_serving() { - fx_log_info!("starting server in configuration only mode"); + log::info!("starting server in configuration only mode"); let () = admin_fut.await?; } else { let msg_loops = socks .into_iter() .map(|sock| define_msg_handling_loop_future(sock, &server).boxed_local()); let lease_expiration_handler = define_lease_expiration_handler_future(&server); - fx_log_info!("starting server"); + log::info!("starting server"); let (_void, (), ()) = futures::try_join!( futures::future::select_ok(msg_loops), admin_fut, @@ -163,18 +165,18 @@ loop { let (received, mut sender) = sock.recv_from(&mut buf).await.context("failed to read from socket")?; - fx_log_info!("received message from: {}", sender); + log::info!("received message from: {}", sender); let msg = Message::from_buffer(&buf[..received])?; - fx_log_info!("parsed message: {:?}", msg); + log::info!("parsed message: {:?}", msg); // This call should not block because the server is single-threaded. let result = server.borrow_mut().dispatch(msg); match result { - Err(e) => fx_log_err!("error processing client message: {}", e), - Ok(ServerAction::AddressRelease(addr)) => fx_log_info!("released address: {}", addr), - Ok(ServerAction::AddressDecline(addr)) => fx_log_info!("allocated address: {}", addr), + Err(e) => log::error!("error processing client message: {:?}", e), + Ok(ServerAction::AddressRelease(addr)) => log::info!("released address: {}", addr), + Ok(ServerAction::AddressDecline(addr)) => log::info!("allocated address: {}", addr), Ok(ServerAction::SendResponse(message, dest)) => { - fx_log_info!("generated response: {:?}", message); + log::info!("generated response: {:?}", message); // Check if server returned an explicit destination ip. if let Some(addr) = dest { @@ -183,7 +185,7 @@ let response_buffer = message.serialize(); sock.send_to(&response_buffer, sender).await.context("unable to send response")?; - fx_log_info!("response sent to: {}", sender); + log::info!("response sent to: {}", sender); } } } @@ -202,6 +204,7 @@ async fn run_server<S: ServerDispatcher>( stream: fidl_fuchsia_net_dhcp::Server_RequestStream, server: &RefCell<S>, + default_params: &dhcp::configuration::ServerParameters, ) -> Result<(), fidl::Error> { stream .try_for_each(|request| async { @@ -229,6 +232,15 @@ fidl_fuchsia_net_dhcp::Server_Request::ListParameters { responder: r } => r.send( &mut server.borrow().dispatch_list_parameters().map_err(|e| e.into_raw()), ), + fidl_fuchsia_net_dhcp::Server_Request::ResetOptions { responder: r } => r.send( + &mut server.borrow_mut().dispatch_reset_options().map_err(|e| e.into_raw()), + ), + fidl_fuchsia_net_dhcp::Server_Request::ResetParameters { responder: r } => r.send( + &mut server + .borrow_mut() + .dispatch_reset_parameters(&default_params) + .map_err(|e| e.into_raw()), + ), } }) .await @@ -237,6 +249,7 @@ #[cfg(test)] mod tests { use super::*; + use std::convert::TryFrom; struct CannedDispatcher {} @@ -280,6 +293,38 @@ ) -> Result<Vec<fidl_fuchsia_net_dhcp::Parameter>, fuchsia_zircon::Status> { Ok(vec![]) } + fn dispatch_reset_options(&mut self) -> Result<(), fuchsia_zircon::Status> { + Ok(()) + } + fn dispatch_reset_parameters( + &mut self, + _defaults: &dhcp::configuration::ServerParameters, + ) -> Result<(), fuchsia_zircon::Status> { + Ok(()) + } + } + + fn default_params() -> dhcp::configuration::ServerParameters { + dhcp::configuration::ServerParameters { + server_ips: vec![Ipv4Addr::from([192, 168, 0, 1])], + lease_length: dhcp::configuration::LeaseLength { + default_seconds: 86400, + max_seconds: 86400, + }, + managed_addrs: dhcp::configuration::ManagedAddresses { + network_id: Ipv4Addr::from([192, 168, 0, 0]), + broadcast: Ipv4Addr::from([192, 168, 0, 128]), + mask: dhcp::configuration::SubnetMask::try_from(25).unwrap(), + pool_range_start: Ipv4Addr::from([192, 168, 0, 0]), + pool_range_stop: Ipv4Addr::from([192, 168, 0, 0]), + }, + permitted_macs: dhcp::configuration::PermittedMacs(vec![]), + static_assignments: dhcp::configuration::StaticAssignments( + std::collections::HashMap::new(), + ), + arp_probe: false, + bound_device_names: vec![], + } } #[fasync::run_singlethreaded(test)] @@ -288,11 +333,11 @@ fidl::endpoints::create_proxy_and_stream::<fidl_fuchsia_net_dhcp::Server_Marker>()?; let server = RefCell::new(CannedDispatcher {}); - let res = proxy.get_option(fidl_fuchsia_net_dhcp::OptionCode::SubnetMask); - fasync::spawn_local(async move { - let () = run_server(stream, &server).await.unwrap_or(()); - }); - let res = res.await?; + let defaults = default_params(); + let res = futures::select! { + res = proxy.get_option(fidl_fuchsia_net_dhcp::OptionCode::SubnetMask).fuse() => res.context("get_option failed"), + server_fut = run_server(stream, &server, &defaults).fuse() => Err(anyhow::Error::msg("server finished before request")), + }?; let expected_result = Ok(fidl_fuchsia_net_dhcp::Option_::SubnetMask(fidl_fuchsia_net::Ipv4Address { @@ -308,12 +353,11 @@ fidl::endpoints::create_proxy_and_stream::<fidl_fuchsia_net_dhcp::Server_Marker>()?; let server = RefCell::new(CannedDispatcher {}); - let res = proxy.get_parameter(fidl_fuchsia_net_dhcp::ParameterName::LeaseLength); - fasync::spawn_local(async move { - let () = run_server(stream, &server).await.unwrap_or(()); - }); - let res = res.await?; - + let defaults = default_params(); + let res = futures::select! { + res = proxy.get_parameter(fidl_fuchsia_net_dhcp::ParameterName::LeaseLength).fuse() => res.context("get_parameter failed"), + server_fut = run_server(stream, &server, &defaults).fuse() => Err(anyhow::Error::msg("server finished before request")), + }?; let expected_result = Ok(fidl_fuchsia_net_dhcp::Parameter::Lease(fidl_fuchsia_net_dhcp::LeaseLength { default: None, @@ -329,14 +373,13 @@ fidl::endpoints::create_proxy_and_stream::<fidl_fuchsia_net_dhcp::Server_Marker>()?; let server = RefCell::new(CannedDispatcher {}); - let res = proxy.set_option(&mut fidl_fuchsia_net_dhcp::Option_::SubnetMask( + let defaults = default_params(); + let res = futures::select! { + res = proxy.set_option(&mut fidl_fuchsia_net_dhcp::Option_::SubnetMask( fidl_fuchsia_net::Ipv4Address { addr: [0, 0, 0, 0] }, - )); - fasync::spawn_local(async move { - let () = run_server(stream, &server).await.unwrap_or(()); - }); - let res = res.await?; - + )).fuse() => res.context("set_option failed"), + server_fut = run_server(stream, &server, &defaults).fuse() => Err(anyhow::Error::msg("server finished before request")), + }?; assert_eq!(res, Ok(())); Ok(()) } @@ -347,14 +390,13 @@ fidl::endpoints::create_proxy_and_stream::<fidl_fuchsia_net_dhcp::Server_Marker>()?; let server = RefCell::new(CannedDispatcher {}); - let res = proxy.set_parameter(&mut fidl_fuchsia_net_dhcp::Parameter::Lease( + let defaults = default_params(); + let res = futures::select! { + res = proxy.set_parameter(&mut fidl_fuchsia_net_dhcp::Parameter::Lease( fidl_fuchsia_net_dhcp::LeaseLength { default: None, max: None }, - )); - fasync::spawn_local(async move { - let () = run_server(stream, &server).await.unwrap_or(()); - }); - let res = res.await?; - + )).fuse() => res.context("set_parameter failed"), + server_fut = run_server(stream, &server, &defaults).fuse() => Err(anyhow::Error::msg("server finished before request")), + }?; assert_eq!(res, Ok(())); Ok(()) } @@ -365,12 +407,11 @@ fidl::endpoints::create_proxy_and_stream::<fidl_fuchsia_net_dhcp::Server_Marker>()?; let server = RefCell::new(CannedDispatcher {}); - let res = proxy.list_options(); - fasync::spawn_local(async move { - let () = run_server(stream, &server).await.unwrap_or(()); - }); - let res = res.await?; - + let defaults = default_params(); + let res = futures::select! { + res = proxy.list_options().fuse() => res.context("list_options failed"), + server_fut = run_server(stream, &server, &defaults).fuse() => Err(anyhow::Error::msg("server finished before request")), + }?; assert_eq!(res, Ok(vec![])); Ok(()) } @@ -381,13 +422,44 @@ fidl::endpoints::create_proxy_and_stream::<fidl_fuchsia_net_dhcp::Server_Marker>()?; let server = RefCell::new(CannedDispatcher {}); - let res = proxy.list_parameters(); - fasync::spawn_local(async move { - let () = run_server(stream, &server).await.unwrap_or(()); - }); - let res = res.await?; - + let defaults = default_params(); + let res = futures::select! { + res = proxy.list_parameters().fuse() => res.context("list_parameters failed"), + server_fut = run_server(stream, &server, &defaults).fuse() => Err(anyhow::Error::msg("server finished before request")), + }?; assert_eq!(res, Ok(vec![])); Ok(()) } + + #[fasync::run_singlethreaded(test)] + async fn reset_options_returns_unit() -> Result<(), Error> { + let (proxy, stream) = + fidl::endpoints::create_proxy_and_stream::<fidl_fuchsia_net_dhcp::Server_Marker>()?; + let server = RefCell::new(CannedDispatcher {}); + + let defaults = default_params(); + let res = futures::select! { + res = proxy.reset_options().fuse() => res.context("reset_options failed"), + server_fut = run_server(stream, &server, &defaults).fuse() => Err(anyhow::Error::msg("server finished before request")), + }?; + + assert_eq!(res, Ok(())); + Ok(()) + } + + #[fasync::run_singlethreaded(test)] + async fn reset_parameters_returns_unit() -> Result<(), Error> { + let (proxy, stream) = + fidl::endpoints::create_proxy_and_stream::<fidl_fuchsia_net_dhcp::Server_Marker>()?; + let server = RefCell::new(CannedDispatcher {}); + + let defaults = default_params(); + let res = futures::select! { + res = proxy.reset_parameters().fuse() => res.context("reset_parameters failed"), + server_fut = run_server(stream, &server, &defaults).fuse() => Err(anyhow::Error::msg("server finished before request")), + }?; + + assert_eq!(res, Ok(())); + Ok(()) + } }
diff --git a/src/connectivity/network/dhcp/src/server.rs b/src/connectivity/network/dhcp/src/server.rs index b858143..52ac266 100644 --- a/src/connectivity/network/dhcp/src/server.rs +++ b/src/connectivity/network/dhcp/src/server.rs
@@ -655,6 +655,10 @@ fn dispatch_list_options(&self) -> Result<Vec<fidl_fuchsia_net_dhcp::Option_>, Status>; /// Retrieves all of the stored DHCP parameter values. fn dispatch_list_parameters(&self) -> Result<Vec<fidl_fuchsia_net_dhcp::Parameter>, Status>; + /// Resets all DHCP options to have no value. + fn dispatch_reset_options(&mut self) -> Result<(), Status>; + /// Resets all DHCP server parameters to their default values in `defaults`. + fn dispatch_reset_parameters(&mut self, defaults: &ServerParameters) -> Result<(), Status>; } impl ServerDispatcher for Server { @@ -844,6 +848,25 @@ fidl_fuchsia_net_dhcp::Parameter::BoundDeviceNames(bound_device_names.clone()), ]) } + + fn dispatch_reset_options(&mut self) -> Result<(), Status> { + let () = self.options_repo.clear(); + let opts: Vec<DhcpOption> = self.options_repo.values().cloned().collect(); + let () = self.stash.store_options(&opts).map_err(|e| { + log::warn!("store_options({:?}) in stash failed: {}", opts, e); + fuchsia_zircon::Status::INTERNAL + })?; + Ok(()) + } + + fn dispatch_reset_parameters(&mut self, defaults: &ServerParameters) -> Result<(), Status> { + self.params = defaults.clone(); + let () = self.stash.store_parameters(&self.params).map_err(|e| { + log::warn!("store_parameters({:?}) in stash failed: {}", self.params, e); + fuchsia_zircon::Status::INTERNAL + })?; + Ok(()) + } } /// A cache mapping clients to their configuration data. @@ -3040,4 +3063,42 @@ assert!(result.contains(&expected)); Ok(()) } + + #[fuchsia_async::run_singlethreaded(test)] + async fn test_server_dispatcher_reset_options() -> Result<(), Error> { + let mut server = new_test_minimal_server().await?; + let empty_map = HashMap::new(); + assert_ne!(empty_map, server.options_repo); + let () = server.dispatch_reset_options()?; + assert_eq!(empty_map, server.options_repo); + let stored_opts = server.stash.load_options().await?; + assert_eq!(empty_map, stored_opts); + Ok(()) + } + + #[fuchsia_async::run_singlethreaded(test)] + async fn test_server_dispatcher_reset_parameters() -> Result<(), Error> { + let mut server = new_test_minimal_server().await?; + let default_params = ServerParameters { + server_ips: vec![Ipv4Addr::from([192, 168, 0, 1])], + lease_length: LeaseLength { default_seconds: 86400, max_seconds: 86400 }, + managed_addrs: crate::configuration::ManagedAddresses { + network_id: Ipv4Addr::from([192, 168, 0, 0]), + broadcast: Ipv4Addr::from([192, 168, 0, 128]), + mask: crate::configuration::SubnetMask::try_from(25).unwrap(), + pool_range_start: Ipv4Addr::from([192, 168, 0, 0]), + pool_range_stop: Ipv4Addr::from([192, 168, 0, 0]), + }, + permitted_macs: crate::configuration::PermittedMacs(vec![]), + static_assignments: crate::configuration::StaticAssignments(HashMap::new()), + arp_probe: false, + bound_device_names: vec![], + }; + assert_ne!(default_params, server.params); + let () = server.dispatch_reset_parameters(&default_params)?; + assert_eq!(default_params, server.params); + let stored_params = server.stash.load_parameters().await?; + assert_eq!(default_params, stored_params); + Ok(()) + } }
diff --git a/src/connectivity/network/dhcpd-cli/src/args.rs b/src/connectivity/network/dhcpd-cli/src/args.rs index 5e2b535..d33108c 100644 --- a/src/connectivity/network/dhcpd-cli/src/args.rs +++ b/src/connectivity/network/dhcpd-cli/src/args.rs
@@ -25,6 +25,8 @@ Set(Set), /// a primary command to list the values of all DHCP options or server parameters. List(List), + /// a primary command to reset the values of all DHCP options or server parameters. + Reset(Reset), } /// A primary command to retrieve the value of a DHCP option or server parameter. @@ -51,6 +53,14 @@ pub arg: ListArg, } +/// A primary command to reset the values of all DHCP options or server parameters. +#[derive(Debug, FromArgs)] +#[argh(subcommand, name = "reset")] +pub struct Reset { + #[argh(subcommand)] + pub arg: ResetArg, +} + #[derive(Debug, FromArgs)] #[argh(subcommand)] pub enum GetArg { @@ -75,6 +85,14 @@ Parameter(ParameterToken), } +/// A primary command argument to reset the values of all DHCP options or server parameters. +#[derive(Debug, FromArgs)] +#[argh(subcommand)] +pub enum ResetArg { + Option(OptionToken), + Parameter(ParameterToken), +} + /// A secondary command indicating a DHCP option argument. #[derive(Debug, FromArgs)] #[argh(subcommand, name = "option")]
diff --git a/src/connectivity/network/dhcpd-cli/src/lib.rs b/src/connectivity/network/dhcpd-cli/src/lib.rs index fcf616e..37831f2 100644 --- a/src/connectivity/network/dhcpd-cli/src/lib.rs +++ b/src/connectivity/network/dhcpd-cli/src/lib.rs
@@ -234,3 +234,77 @@ }]) .await } + +#[fuchsia_async::run_singlethreaded(test)] +async fn test_reset_option() { + test_cli(vec![ + Command { + args: vec!["set", "option", "subnet-mask", "--mask", "255.255.255.0"], + expected_stdout: "", + expected_stderr: "", + }, + Command { + args: vec!["list", "option"], + expected_stdout: r#"[ + SubnetMask( + Ipv4Address { + addr: [ + 255, + 255, + 255, + 0, + ], + }, + ), +] +"#, + expected_stderr: "", + }, + Command { args: vec!["reset", "option"], expected_stdout: "", expected_stderr: "" }, + Command { args: vec!["list", "option"], expected_stdout: "[]\n", expected_stderr: "" }, + ]) + .await +} + +#[fuchsia_async::run_singlethreaded(test)] +async fn test_reset_parameter() { + test_cli(vec![ + Command { + args: vec!["set", "parameter", "lease-length", "--default", "42"], + expected_stdout: "", + expected_stderr: "", + }, + Command { + args: vec!["get", "parameter", "lease-length"], + expected_stdout: r#"Lease( + LeaseLength { + default: Some( + 42, + ), + max: Some( + 42, + ), + }, +) +"#, + expected_stderr: "", + }, + Command { args: vec!["reset", "parameter"], expected_stdout: "", expected_stderr: "" }, + Command { + args: vec!["get", "parameter", "lease-length"], + expected_stdout: r#"Lease( + LeaseLength { + default: Some( + 86400, + ), + max: Some( + 86400, + ), + }, +) +"#, + expected_stderr: "", + }, + ]) + .await +}
diff --git a/src/connectivity/network/dhcpd-cli/src/main.rs b/src/connectivity/network/dhcpd-cli/src/main.rs index 925e1eb..2287012 100644 --- a/src/connectivity/network/dhcpd-cli/src/main.rs +++ b/src/connectivity/network/dhcpd-cli/src/main.rs
@@ -20,6 +20,7 @@ Cli { cmd: Command::Get(get_arg) } => do_get(get_arg, server).await?, Cli { cmd: Command::Set(set_arg) } => do_set(set_arg, server).await?, Cli { cmd: Command::List(list_arg) } => do_list(list_arg, server).await?, + Cli { cmd: Command::Reset(reset_arg) } => do_reset(reset_arg, server).await?, }; Ok(()) @@ -74,7 +75,7 @@ .list_options() .await? .map_err(|e| fuchsia_zircon::Status::from_raw(e)) - .with_context(|| "list_options() failed")?; + .context("list_options() failed")?; println!("{:#?}", res); } @@ -83,9 +84,29 @@ .list_parameters() .await? .map_err(|e| fuchsia_zircon::Status::from_raw(e)) - .with_context(|| "list_parameters() failed")?; + .context("list_parameters() failed")?; println!("{:#?}", res); } }; Ok(()) } + +async fn do_reset(reset_arg: Reset, server: Server_Proxy) -> Result<(), Error> { + match reset_arg.arg { + ResetArg::Option(OptionToken {}) => { + let () = server + .reset_options() + .await? + .map_err(fuchsia_zircon::Status::from_raw) + .context("reset_options() failed")?; + } + ResetArg::Parameter(ParameterToken {}) => { + let () = server + .reset_parameters() + .await? + .map_err(fuchsia_zircon::Status::from_raw) + .context("reset_parameters() failed")?; + } + }; + Ok(()) +}