blob: 21f7d3fbf5e0a25db713391c99ff202f9e8f4b71 [file] [log] [blame]
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// TODO(https://fxbug.dev/42156465): Replace with GN config once available in an ffx_plugin.
#![deny(unused_results)]
use {fidl_fuchsia_net_ext as fnet_ext, fidl_fuchsia_net_test_realm as fntr};
#[ffx_core::ffx_command]
#[derive(argh::ArgsInfo, argh::FromArgs, Debug, PartialEq)]
#[argh(
subcommand,
name = "net-test-realm",
description = "Manage a running Network Test Realm",
note = "This plugin acts as a thin wrapper around the Network Test Realm Controller protocol.
For more specific information regarding each subcommand, see the underlying protocol definition:
https://osscs.corp.google.com/fuchsia/fuchsia/+/main:src/connectivity/network/testing/network-test-realm/fidl/controller.fidl"
)]
pub struct Command {
#[argh(positional)]
/// the moniker of the component that corresponds to the Network Test Realm
/// instance (e.g.
/// "/core/network/test-components:net_test_realm_controller").
pub component_moniker: String,
#[argh(subcommand)]
pub subcommand: Subcommand,
}
#[derive(argh::ArgsInfo, argh::FromArgs, Debug, PartialEq)]
#[argh(subcommand)]
pub enum Subcommand {
AddInterface(AddInterface),
JoinMulticastGroup(JoinMulticastGroup),
LeaveMulticastGroup(LeaveMulticastGroup),
Ping(Ping),
PollUdp(PollUdp),
StartHermeticNetworkRealm(StartHermeticNetworkRealm),
StartStub(StartStub),
StopHermeticNetworkRealm(StopHermeticNetworkRealm),
StopStub(StopStub),
Dhcpv6Client(Dhcpv6Client),
DhcpClient(DhcpClient),
}
#[derive(argh::ArgsInfo, argh::FromArgs, Debug, PartialEq)]
#[argh(subcommand, name = "start-hermetic-network-realm")]
/// Starts a hermetic network realm.
pub struct StartHermeticNetworkRealm {
#[argh(positional, from_str_fn(parse_netstack_type))]
/// the Netstack version to start.
pub netstack: fntr::Netstack,
}
#[derive(argh::ArgsInfo, argh::FromArgs, Debug, PartialEq)]
#[argh(subcommand, name = "stop-hermetic-network-realm")]
/// Stops a running hermetic network realm.
pub struct StopHermeticNetworkRealm {}
#[derive(argh::ArgsInfo, argh::FromArgs, Debug, PartialEq)]
#[argh(subcommand, name = "start-stub")]
/// Starts a test stub within the hermetic network realm.
pub struct StartStub {
#[argh(positional)]
/// the url of the component to start.
pub component_url: String,
}
#[derive(argh::ArgsInfo, argh::FromArgs, Debug, PartialEq)]
#[argh(subcommand, name = "stop-stub")]
/// Stops the currently running test stub.
pub struct StopStub {}
#[derive(argh::ArgsInfo, argh::FromArgs, Debug, PartialEq)]
#[argh(subcommand, name = "add-interface")]
/// Attaches an interface to the hermetic Netstack.
pub struct AddInterface {
#[argh(positional)]
/// address of the interface to be added to the hermetic Netstack.
/// This should correspond to the address of an existing system interface.
pub mac_address: fnet_ext::MacAddress,
#[argh(positional)]
/// the name to assign to the new interface.
pub name: String,
#[argh(switch)]
/// whether to wait for any IP address to be assigned to the interface before returning. This is
/// helpful for tests that want to ensure the autoconfigured IP address is assigned and has
/// completed duplicate address detection before proceeding.
pub wait_any_ip_address: bool,
}
#[derive(argh::ArgsInfo, argh::FromArgs, Debug, PartialEq)]
#[argh(subcommand, name = "join-multicast-group")]
/// Joins a multicast group.
pub struct JoinMulticastGroup {
#[argh(positional)]
/// the group address to join.
pub address: fnet_ext::IpAddress,
#[argh(positional)]
/// the ID of the interface that should be used to join the group.
pub interface_id: u64,
}
#[derive(argh::ArgsInfo, argh::FromArgs, Debug, PartialEq)]
#[argh(subcommand, name = "leave-multicast-group")]
/// Leaves a multicast group that was previously joined.
pub struct LeaveMulticastGroup {
#[argh(positional)]
/// the group address to leave.
pub address: fnet_ext::IpAddress,
#[argh(positional)]
/// the ID of the interface that should be used to leave the group.
pub interface_id: u64,
}
#[derive(argh::ArgsInfo, argh::FromArgs, Debug, PartialEq)]
#[argh(subcommand, name = "ping")]
/// Sends an ICMP echo request to a target using a socket provided by the
/// hermetic Netstack.
pub struct Ping {
#[argh(positional)]
/// the address to ping.
pub target: fnet_ext::IpAddress,
#[argh(positional)]
/// the body size of the ICMP packet. Specifically, the packet body will be
/// filled with zeros of the provided length.
pub payload_length: u16,
#[argh(positional)]
/// a timeout in nanoseconds to wait for a reply. If less than or equal to
/// 0, then returns success immediately after the ping is sent.
pub timeout: i64,
#[argh(option)]
/// the name of the source interface.
pub interface_name: Option<String>,
}
#[derive(argh::ArgsInfo, argh::FromArgs, Debug, PartialEq)]
#[argh(subcommand, name = "poll-udp")]
/// Polls the specified socket address with UDP datagrams containing the specified payload.
/// Waits for a single reply from the target address and prints it to stdout.
pub struct PollUdp {
#[argh(positional)]
/// the socket to which to send datagrams
pub target: std::net::SocketAddr,
#[argh(positional)]
/// the datagram to send
pub payload: String,
#[argh(positional)]
/// the timeout in nanos to wait for a reply, per retry.
pub timeout: i64,
#[argh(positional)]
/// the number of attempts to make
pub num_retries: u16,
}
#[derive(argh::ArgsInfo, argh::FromArgs, Debug, PartialEq)]
#[argh(subcommand, name = "dhcpv6-client")]
/// DHCPv6 client commands.
pub struct Dhcpv6Client {
#[argh(subcommand)]
pub subcommand: Dhcpv6ClientSubcommand,
}
#[derive(argh::ArgsInfo, argh::FromArgs, Debug, PartialEq)]
#[argh(subcommand)]
pub enum Dhcpv6ClientSubcommand {
Start(Dhcpv6ClientStart),
Stop(Dhcpv6ClientStop),
}
fn optional_prefix_from_str(s: &str) -> Result<Option<fnet_ext::SubnetV6>, String> {
match s {
"" => Ok(None),
s => s.parse::<fnet_ext::SubnetV6>().map(Some).map_err(|e| format!("{}", e)),
}
}
#[derive(argh::ArgsInfo, argh::FromArgs, Debug, PartialEq)]
#[argh(subcommand, name = "start")]
/// Start a DHCPv6 client.
pub struct Dhcpv6ClientStart {
#[argh(positional)]
/// the interface to run the DHCPv6 client on
pub interface_id: u64,
#[argh(positional)]
/// the link-local address the DHCPv6 client uses to communicate with servers
pub address: fnet_ext::Ipv6Address,
#[argh(switch)]
/// request non-temporary address from servers
pub request_non_temporary_address: bool,
#[argh(switch)]
/// request DNS servers configuration from servers
pub request_dns_servers: bool,
#[argh(option, from_str_fn(optional_prefix_from_str))]
/// request prefix delegation from servers
pub prefix_delegation_config: Option<Option<fnet_ext::SubnetV6>>,
// TODO(https://fxbug.dev/42125771): Add configuration for Rapid Commit.
// TODO(https://fxbug.dev/42056655): Add configuration for acquiring temporary addresses.
}
#[derive(argh::ArgsInfo, argh::FromArgs, Debug, PartialEq)]
#[argh(subcommand, name = "stop")]
/// Stops all DHCPv6 clients.
pub struct Dhcpv6ClientStop {}
#[derive(argh::ArgsInfo, argh::FromArgs, Debug, PartialEq)]
#[argh(subcommand, name = "dhcp-client")]
/// DHCP client commands.
pub struct DhcpClient {
#[argh(subcommand)]
pub subcommand: DhcpClientSubcommand,
}
#[derive(argh::ArgsInfo, argh::FromArgs, Debug, PartialEq)]
#[argh(subcommand)]
pub enum DhcpClientSubcommand {
Start(DhcpClientStart),
Stop(DhcpClientStop),
}
#[derive(argh::ArgsInfo, argh::FromArgs, Debug, PartialEq)]
#[argh(subcommand, name = "start")]
/// Start a DHCP client.
pub struct DhcpClientStart {
#[argh(positional)]
/// the interface to run the DHCP client on
pub interface_id: u64,
}
#[derive(argh::ArgsInfo, argh::FromArgs, Debug, PartialEq)]
#[argh(subcommand, name = "stop")]
/// Stops all DHCP clients.
pub struct DhcpClientStop {
#[argh(positional)]
/// the interface to run the DHCP client on
pub interface_id: u64,
}
fn parse_netstack_type(value: &str) -> Result<fntr::Netstack, String> {
match &value.to_lowercase()[..] {
"v2" => Ok(fntr::Netstack::V2),
"v3" => Ok(fntr::Netstack::V3),
_ => Err("invalid netstack type".to_string()),
}
}