[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(())
+}