| // Copyright 2020 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. |
| |
| //! Provides utilities for test realms. |
| |
| use std::{borrow::Cow, collections::HashMap}; |
| |
| use fidl::endpoints::DiscoverableProtocolMarker as _; |
| use fidl_fuchsia_component as fcomponent; |
| use fidl_fuchsia_net_debug as fnet_debug; |
| use fidl_fuchsia_net_dhcp as fnet_dhcp; |
| use fidl_fuchsia_net_dhcpv6 as fnet_dhcpv6; |
| use fidl_fuchsia_net_filter as fnet_filter; |
| use fidl_fuchsia_net_filter_deprecated as fnet_filter_deprecated; |
| use fidl_fuchsia_net_interfaces as fnet_interfaces; |
| use fidl_fuchsia_net_interfaces_admin as fnet_interfaces_admin; |
| use fidl_fuchsia_net_interfaces_ext as fnet_interfaces_ext; |
| use fidl_fuchsia_net_masquerade as fnet_masquerade; |
| use fidl_fuchsia_net_multicast_admin as fnet_multicast_admin; |
| use fidl_fuchsia_net_name as fnet_name; |
| use fidl_fuchsia_net_neighbor as fnet_neighbor; |
| use fidl_fuchsia_net_reachability as fnet_reachability; |
| use fidl_fuchsia_net_root as fnet_root; |
| use fidl_fuchsia_net_routes as fnet_routes; |
| use fidl_fuchsia_net_routes_admin as fnet_routes_admin; |
| use fidl_fuchsia_net_stack as fnet_stack; |
| use fidl_fuchsia_net_test_realm as fntr; |
| use fidl_fuchsia_net_virtualization as fnet_virtualization; |
| use fidl_fuchsia_netemul as fnetemul; |
| use fidl_fuchsia_posix_socket as fposix_socket; |
| use fidl_fuchsia_posix_socket_packet as fposix_socket_packet; |
| use fidl_fuchsia_posix_socket_raw as fposix_socket_raw; |
| use fidl_fuchsia_stash as fstash; |
| use fidl_fuchsia_update_verify as fupdate_verify; |
| |
| use anyhow::Context as _; |
| use async_trait::async_trait; |
| |
| use crate::Result; |
| |
| /// The Netstack version. Used to specify which Netstack version to use in a |
| /// [`KnownServiceProvider::Netstack`]. |
| #[derive(Copy, Clone, Eq, PartialEq, Debug)] |
| #[allow(missing_docs)] |
| pub enum NetstackVersion { |
| Netstack2 { tracing: bool, fast_udp: bool }, |
| Netstack3, |
| ProdNetstack2, |
| ProdNetstack3, |
| } |
| |
| impl NetstackVersion { |
| /// Gets the Fuchsia URL for this Netstack component. |
| pub fn get_url(&self) -> &'static str { |
| match self { |
| NetstackVersion::Netstack2 { tracing, fast_udp } => match (tracing, fast_udp) { |
| (false, false) => "#meta/netstack-debug.cm", |
| (false, true) => "#meta/netstack-with-fast-udp-debug.cm", |
| (true, false) => "#meta/netstack-with-tracing.cm", |
| (true, true) => "#meta/netstack-with-fast-udp-tracing.cm", |
| }, |
| NetstackVersion::Netstack3 => "#meta/netstack3-debug.cm", |
| NetstackVersion::ProdNetstack2 => "#meta/netstack.cm", |
| NetstackVersion::ProdNetstack3 => "#meta/netstack3.cm", |
| } |
| } |
| |
| /// Gets the services exposed by this Netstack component. |
| pub fn get_services(&self) -> &[&'static str] { |
| macro_rules! common_services_and { |
| ($($name:expr),*) => {[ |
| fnet_debug::InterfacesMarker::PROTOCOL_NAME, |
| fnet_interfaces_admin::InstallerMarker::PROTOCOL_NAME, |
| fnet_interfaces::StateMarker::PROTOCOL_NAME, |
| fnet_name::DnsServerWatcherMarker::PROTOCOL_NAME, |
| fnet_neighbor::ControllerMarker::PROTOCOL_NAME, |
| fnet_neighbor::ViewMarker::PROTOCOL_NAME, |
| fnet_root::InterfacesMarker::PROTOCOL_NAME, |
| fnet_root::RoutesV4Marker::PROTOCOL_NAME, |
| fnet_root::RoutesV6Marker::PROTOCOL_NAME, |
| fnet_routes::StateMarker::PROTOCOL_NAME, |
| fnet_routes::StateV4Marker::PROTOCOL_NAME, |
| fnet_routes::StateV6Marker::PROTOCOL_NAME, |
| fnet_routes_admin::RouteTableV4Marker::PROTOCOL_NAME, |
| fnet_routes_admin::RouteTableV6Marker::PROTOCOL_NAME, |
| fnet_stack::StackMarker::PROTOCOL_NAME, |
| fposix_socket_packet::ProviderMarker::PROTOCOL_NAME, |
| fposix_socket_raw::ProviderMarker::PROTOCOL_NAME, |
| fposix_socket::ProviderMarker::PROTOCOL_NAME, |
| fnet_debug::DiagnosticsMarker::PROTOCOL_NAME, |
| fupdate_verify::NetstackVerifierMarker::PROTOCOL_NAME, |
| $($name),* |
| ]}; |
| // Strip trailing comma. |
| ($($name:expr),*,) => {common_services_and!($($name),*)} |
| } |
| match self { |
| NetstackVersion::Netstack2 { tracing: _, fast_udp: _ } |
| | NetstackVersion::ProdNetstack2 => &common_services_and!( |
| fnet_filter_deprecated::FilterMarker::PROTOCOL_NAME, |
| fnet_multicast_admin::Ipv4RoutingTableControllerMarker::PROTOCOL_NAME, |
| fnet_multicast_admin::Ipv6RoutingTableControllerMarker::PROTOCOL_NAME, |
| fnet_stack::LogMarker::PROTOCOL_NAME, |
| ), |
| NetstackVersion::Netstack3 | NetstackVersion::ProdNetstack3 => &common_services_and!( |
| fnet_filter::ControlMarker::PROTOCOL_NAME, |
| fnet_filter::StateMarker::PROTOCOL_NAME, |
| ), |
| } |
| } |
| } |
| |
| /// The NetCfg version. |
| #[derive(Copy, Clone, Eq, PartialEq, Debug)] |
| pub enum NetCfgVersion { |
| /// The basic NetCfg version. |
| Basic, |
| /// The advanced NetCfg version. |
| Advanced, |
| } |
| |
| /// The network manager to use in a [`KnownServiceProvider::Manager`]. |
| #[derive(Copy, Clone, Eq, PartialEq, Debug)] |
| pub enum ManagementAgent { |
| /// A version of netcfg. |
| NetCfg(NetCfgVersion), |
| } |
| |
| impl ManagementAgent { |
| /// Gets the component name for this management agent. |
| pub fn get_component_name(&self) -> &'static str { |
| match self { |
| Self::NetCfg(NetCfgVersion::Basic) => constants::netcfg::basic::COMPONENT_NAME, |
| Self::NetCfg(NetCfgVersion::Advanced) => constants::netcfg::advanced::COMPONENT_NAME, |
| } |
| } |
| |
| /// Gets the URL for this network manager component. |
| pub fn get_url(&self) -> &'static str { |
| match self { |
| Self::NetCfg(NetCfgVersion::Basic) => constants::netcfg::basic::COMPONENT_URL, |
| Self::NetCfg(NetCfgVersion::Advanced) => constants::netcfg::advanced::COMPONENT_URL, |
| } |
| } |
| |
| /// Default arguments that should be passed to the component when run in a |
| /// test realm. |
| pub fn get_program_args(&self) -> &[&'static str] { |
| match self { |
| Self::NetCfg(NetCfgVersion::Basic) | Self::NetCfg(NetCfgVersion::Advanced) => { |
| &["--min-severity", "DEBUG"] |
| } |
| } |
| } |
| |
| /// Gets the services exposed by this management agent. |
| pub fn get_services(&self) -> &[&'static str] { |
| match self { |
| Self::NetCfg(NetCfgVersion::Basic) => &[ |
| fnet_dhcpv6::PrefixProviderMarker::PROTOCOL_NAME, |
| fnet_masquerade::FactoryMarker::PROTOCOL_NAME, |
| ], |
| Self::NetCfg(NetCfgVersion::Advanced) => &[ |
| fnet_dhcpv6::PrefixProviderMarker::PROTOCOL_NAME, |
| fnet_virtualization::ControlMarker::PROTOCOL_NAME, |
| fnet_masquerade::FactoryMarker::PROTOCOL_NAME, |
| ], |
| } |
| } |
| } |
| |
| /// Available configurations for a Manager. |
| #[derive(Clone, Eq, PartialEq, Debug)] |
| #[allow(missing_docs)] |
| pub enum ManagerConfig { |
| Empty, |
| Dhcpv6, |
| Forwarding, |
| AllDelegated, |
| IfacePrefix, |
| DuplicateNames, |
| PacketFilterEthernet, |
| PacketFilterWlan, |
| } |
| |
| impl ManagerConfig { |
| fn as_str(&self) -> &'static str { |
| match self { |
| ManagerConfig::Empty => "/pkg/netcfg/empty.json", |
| ManagerConfig::Dhcpv6 => "/pkg/netcfg/dhcpv6.json", |
| ManagerConfig::Forwarding => "/pkg/netcfg/forwarding.json", |
| ManagerConfig::AllDelegated => "/pkg/netcfg/all_delegated.json", |
| ManagerConfig::IfacePrefix => "/pkg/netcfg/iface_prefix.json", |
| ManagerConfig::DuplicateNames => "/pkg/netcfg/duplicate_names.json", |
| ManagerConfig::PacketFilterEthernet => "/pkg/netcfg/packet_filter_ethernet.json", |
| ManagerConfig::PacketFilterWlan => "/pkg/netcfg/packet_filter_wlan.json", |
| } |
| } |
| } |
| |
| /// Components that provide known services used in tests. |
| #[derive(Clone, Eq, PartialEq, Debug)] |
| #[allow(missing_docs)] |
| pub enum KnownServiceProvider { |
| Netstack(NetstackVersion), |
| Manager { |
| agent: ManagementAgent, |
| config: ManagerConfig, |
| use_dhcp_server: bool, |
| use_out_of_stack_dhcp_client: bool, |
| }, |
| SecureStash, |
| DhcpServer { |
| persistent: bool, |
| }, |
| DhcpClient, |
| Dhcpv6Client, |
| DnsResolver, |
| Reachability { |
| eager: bool, |
| }, |
| NetworkTestRealm, |
| FakeClock, |
| } |
| |
| /// Constant properties of components used in networking integration tests, such |
| /// as monikers and URLs. |
| #[allow(missing_docs)] |
| pub mod constants { |
| pub mod netstack { |
| pub const COMPONENT_NAME: &str = "netstack"; |
| } |
| pub mod netcfg { |
| pub mod basic { |
| pub const COMPONENT_NAME: &str = "netcfg"; |
| pub const COMPONENT_URL: &str = "#meta/netcfg-basic.cm"; |
| } |
| pub mod advanced { |
| pub const COMPONENT_NAME: &str = "netcfg-advanced"; |
| pub const COMPONENT_URL: &str = "#meta/netcfg-advanced.cm"; |
| } |
| // These capability names and filepaths should match the devfs capabilities used by netcfg |
| // in its component manifest, i.e. netcfg.cml. |
| pub const DEV_CLASS_NETWORK: &str = "dev-class-network"; |
| pub const CLASS_NETWORK_PATH: &str = "class/network"; |
| } |
| pub mod secure_stash { |
| pub const COMPONENT_NAME: &str = "stash_secure"; |
| pub const COMPONENT_URL: &str = "#meta/stash_secure.cm"; |
| } |
| pub mod dhcp_server { |
| pub const COMPONENT_NAME: &str = "dhcpd"; |
| pub const COMPONENT_URL: &str = "#meta/dhcpv4_server.cm"; |
| } |
| pub mod dhcp_client { |
| pub const COMPONENT_NAME: &str = "dhcp-client"; |
| pub const COMPONENT_URL: &str = "#meta/dhcp-client.cm"; |
| } |
| pub mod dhcpv6_client { |
| pub const COMPONENT_NAME: &str = "dhcpv6-client"; |
| pub const COMPONENT_URL: &str = "#meta/dhcpv6-client.cm"; |
| } |
| pub mod dns_resolver { |
| pub const COMPONENT_NAME: &str = "dns_resolver"; |
| pub const COMPONENT_URL: &str = "#meta/dns_resolver_with_fake_time.cm"; |
| } |
| pub mod reachability { |
| pub const COMPONENT_NAME: &str = "reachability"; |
| pub const COMPONENT_URL: &str = "#meta/reachability_with_fake_time.cm"; |
| } |
| pub mod network_test_realm { |
| pub const COMPONENT_NAME: &str = "controller"; |
| pub const COMPONENT_URL: &str = "#meta/controller.cm"; |
| } |
| pub mod fake_clock { |
| pub const COMPONENT_NAME: &str = "fake_clock"; |
| pub const COMPONENT_URL: &str = "#meta/fake_clock.cm"; |
| } |
| } |
| |
| fn protocol_dep<P>(component_name: &'static str) -> fnetemul::ChildDep |
| where |
| P: fidl::endpoints::DiscoverableProtocolMarker, |
| { |
| fnetemul::ChildDep { |
| name: Some(component_name.into()), |
| capability: Some(fnetemul::ExposedCapability::Protocol(P::PROTOCOL_NAME.to_string())), |
| ..Default::default() |
| } |
| } |
| |
| impl From<KnownServiceProvider> for fnetemul::ChildDef { |
| fn from(s: KnownServiceProvider) -> Self { |
| (&s).into() |
| } |
| } |
| |
| impl<'a> From<&'a KnownServiceProvider> for fnetemul::ChildDef { |
| fn from(s: &'a KnownServiceProvider) -> Self { |
| match s { |
| KnownServiceProvider::Netstack(version) => fnetemul::ChildDef { |
| name: Some(constants::netstack::COMPONENT_NAME.to_string()), |
| source: Some(fnetemul::ChildSource::Component(version.get_url().to_string())), |
| exposes: Some( |
| version.get_services().iter().map(|service| service.to_string()).collect(), |
| ), |
| uses: Some(fnetemul::ChildUses::Capabilities( |
| std::iter::once(fnetemul::Capability::LogSink(fnetemul::Empty {})) |
| .chain(match version { |
| // NB: intentionally do not route SecureStore; it is |
| // intentionally not available in all tests to |
| // ensure that its absence is handled gracefully. |
| // Note also that netstack-debug does not have a use |
| // declaration for this protocol for the same |
| // reason. |
| NetstackVersion::Netstack2 { tracing: false, fast_udp: _ } => { |
| itertools::Either::Left(std::iter::empty()) |
| } |
| NetstackVersion::Netstack2 { tracing: true, fast_udp: _ } |
| | NetstackVersion::Netstack3 |
| | NetstackVersion::ProdNetstack3 => { |
| itertools::Either::Right(std::iter::once( |
| fnetemul::Capability::TracingProvider(fnetemul::Empty), |
| )) |
| } |
| NetstackVersion::ProdNetstack2 => itertools::Either::Right( |
| std::iter::once(fnetemul::Capability::ChildDep(protocol_dep::< |
| fstash::SecureStoreMarker, |
| >( |
| constants::secure_stash::COMPONENT_NAME, |
| ))), |
| ), |
| }) |
| .collect(), |
| )), |
| ..Default::default() |
| }, |
| KnownServiceProvider::Manager { |
| agent, |
| use_dhcp_server, |
| config, |
| use_out_of_stack_dhcp_client, |
| } => { |
| let enable_dhcpv6 = match config { |
| ManagerConfig::Dhcpv6 => true, |
| ManagerConfig::Forwarding |
| | ManagerConfig::Empty |
| | ManagerConfig::AllDelegated |
| | ManagerConfig::IfacePrefix |
| | ManagerConfig::DuplicateNames |
| | ManagerConfig::PacketFilterEthernet |
| | ManagerConfig::PacketFilterWlan => false, |
| }; |
| |
| fnetemul::ChildDef { |
| name: Some(agent.get_component_name().to_string()), |
| source: Some(fnetemul::ChildSource::Component(agent.get_url().to_string())), |
| program_args: Some( |
| agent |
| .get_program_args() |
| .iter() |
| .cloned() |
| .chain(std::iter::once("--config-data")) |
| .chain(std::iter::once(config.as_str())) |
| .map(Into::into) |
| .collect(), |
| ), |
| exposes: Some( |
| agent.get_services().iter().map(|service| service.to_string()).collect(), |
| ), |
| uses: Some(fnetemul::ChildUses::Capabilities( |
| (*use_dhcp_server) |
| .then(|| { |
| fnetemul::Capability::ChildDep(protocol_dep::< |
| fnet_dhcp::Server_Marker, |
| >( |
| constants::dhcp_server::COMPONENT_NAME, |
| )) |
| }) |
| .into_iter() |
| .chain( |
| enable_dhcpv6 |
| .then(|| { |
| fnetemul::Capability::ChildDep(protocol_dep::< |
| fnet_dhcpv6::ClientProviderMarker, |
| >( |
| constants::dhcpv6_client::COMPONENT_NAME, |
| )) |
| }) |
| .into_iter(), |
| ) |
| .chain(use_out_of_stack_dhcp_client.then(|| { |
| fnetemul::Capability::ChildDep(protocol_dep::< |
| fnet_dhcp::ClientProviderMarker, |
| >( |
| constants::dhcp_client::COMPONENT_NAME, |
| )) |
| })) |
| .chain( |
| [ |
| fnetemul::Capability::LogSink(fnetemul::Empty {}), |
| fnetemul::Capability::ChildDep(protocol_dep::< |
| fnet_filter::ControlMarker, |
| >( |
| constants::netstack::COMPONENT_NAME, |
| )), |
| fnetemul::Capability::ChildDep(protocol_dep::< |
| fnet_filter_deprecated::FilterMarker, |
| >( |
| constants::netstack::COMPONENT_NAME, |
| )), |
| fnetemul::Capability::ChildDep(protocol_dep::< |
| fnet_interfaces::StateMarker, |
| >( |
| constants::netstack::COMPONENT_NAME, |
| )), |
| fnetemul::Capability::ChildDep(protocol_dep::< |
| fnet_interfaces_admin::InstallerMarker, |
| >( |
| constants::netstack::COMPONENT_NAME, |
| )), |
| fnetemul::Capability::ChildDep(protocol_dep::< |
| fnet_stack::StackMarker, |
| >( |
| constants::netstack::COMPONENT_NAME, |
| )), |
| fnetemul::Capability::ChildDep(protocol_dep::< |
| fnet_routes_admin::RouteTableV4Marker, |
| >( |
| constants::netstack::COMPONENT_NAME, |
| )), |
| fnetemul::Capability::ChildDep(protocol_dep::< |
| fnet_routes_admin::RouteTableV6Marker, |
| >( |
| constants::netstack::COMPONENT_NAME, |
| )), |
| fnetemul::Capability::ChildDep(protocol_dep::< |
| fnet_name::DnsServerWatcherMarker, |
| >( |
| constants::netstack::COMPONENT_NAME, |
| )), |
| fnetemul::Capability::ChildDep(protocol_dep::< |
| fnet_name::LookupAdminMarker, |
| >( |
| constants::dns_resolver::COMPONENT_NAME, |
| )), |
| fnetemul::Capability::NetemulDevfs(fnetemul::DevfsDep { |
| name: Some( |
| constants::netcfg::DEV_CLASS_NETWORK.to_string(), |
| ), |
| subdir: Some( |
| constants::netcfg::CLASS_NETWORK_PATH.to_string(), |
| ), |
| ..Default::default() |
| }), |
| fnetemul::Capability::StorageDep(fnetemul::StorageDep { |
| variant: Some(fnetemul::StorageVariant::Data), |
| path: Some("/data".to_string()), |
| ..Default::default() |
| }), |
| ] |
| .into_iter(), |
| ) |
| .collect(), |
| )), |
| eager: Some(true), |
| ..Default::default() |
| } |
| } |
| KnownServiceProvider::SecureStash => fnetemul::ChildDef { |
| name: Some(constants::secure_stash::COMPONENT_NAME.to_string()), |
| source: Some(fnetemul::ChildSource::Component( |
| constants::secure_stash::COMPONENT_URL.to_string(), |
| )), |
| exposes: Some(vec![fstash::SecureStoreMarker::PROTOCOL_NAME.to_string()]), |
| uses: Some(fnetemul::ChildUses::Capabilities(vec![ |
| fnetemul::Capability::LogSink(fnetemul::Empty {}), |
| fnetemul::Capability::StorageDep(fnetemul::StorageDep { |
| variant: Some(fnetemul::StorageVariant::Data), |
| path: Some("/data".to_string()), |
| ..Default::default() |
| }), |
| ])), |
| ..Default::default() |
| }, |
| KnownServiceProvider::DhcpServer { persistent } => fnetemul::ChildDef { |
| name: Some(constants::dhcp_server::COMPONENT_NAME.to_string()), |
| source: Some(fnetemul::ChildSource::Component( |
| constants::dhcp_server::COMPONENT_URL.to_string(), |
| )), |
| exposes: Some(vec![fnet_dhcp::Server_Marker::PROTOCOL_NAME.to_string()]), |
| uses: Some(fnetemul::ChildUses::Capabilities( |
| [ |
| fnetemul::Capability::LogSink(fnetemul::Empty {}), |
| fnetemul::Capability::ChildDep(protocol_dep::< |
| fnet_neighbor::ControllerMarker, |
| >( |
| constants::netstack::COMPONENT_NAME |
| )), |
| fnetemul::Capability::ChildDep( |
| protocol_dep::<fposix_socket::ProviderMarker>( |
| constants::netstack::COMPONENT_NAME, |
| ), |
| ), |
| fnetemul::Capability::ChildDep(protocol_dep::< |
| fposix_socket_packet::ProviderMarker, |
| >( |
| constants::netstack::COMPONENT_NAME |
| )), |
| ] |
| .into_iter() |
| .chain(persistent.then_some(fnetemul::Capability::ChildDep(protocol_dep::< |
| fstash::SecureStoreMarker, |
| >( |
| constants::secure_stash::COMPONENT_NAME, |
| )))) |
| .collect(), |
| )), |
| program_args: if *persistent { |
| Some(vec![String::from("--persistent")]) |
| } else { |
| None |
| }, |
| ..Default::default() |
| }, |
| KnownServiceProvider::DhcpClient => fnetemul::ChildDef { |
| name: Some(constants::dhcp_client::COMPONENT_NAME.to_string()), |
| source: Some(fnetemul::ChildSource::Component( |
| constants::dhcp_client::COMPONENT_URL.to_string(), |
| )), |
| exposes: Some(vec![fnet_dhcp::ClientProviderMarker::PROTOCOL_NAME.to_string()]), |
| uses: Some(fnetemul::ChildUses::Capabilities(vec![ |
| fnetemul::Capability::LogSink(fnetemul::Empty {}), |
| fnetemul::Capability::ChildDep(protocol_dep::<fposix_socket::ProviderMarker>( |
| constants::netstack::COMPONENT_NAME, |
| )), |
| fnetemul::Capability::ChildDep(protocol_dep::< |
| fposix_socket_packet::ProviderMarker, |
| >( |
| constants::netstack::COMPONENT_NAME |
| )), |
| ])), |
| program_args: None, |
| ..Default::default() |
| }, |
| KnownServiceProvider::Dhcpv6Client => fnetemul::ChildDef { |
| name: Some(constants::dhcpv6_client::COMPONENT_NAME.to_string()), |
| source: Some(fnetemul::ChildSource::Component( |
| constants::dhcpv6_client::COMPONENT_URL.to_string(), |
| )), |
| exposes: Some(vec![fnet_dhcpv6::ClientProviderMarker::PROTOCOL_NAME.to_string()]), |
| uses: Some(fnetemul::ChildUses::Capabilities(vec![ |
| fnetemul::Capability::LogSink(fnetemul::Empty {}), |
| fnetemul::Capability::ChildDep(protocol_dep::<fposix_socket::ProviderMarker>( |
| constants::netstack::COMPONENT_NAME, |
| )), |
| ])), |
| ..Default::default() |
| }, |
| KnownServiceProvider::DnsResolver => fnetemul::ChildDef { |
| name: Some(constants::dns_resolver::COMPONENT_NAME.to_string()), |
| source: Some(fnetemul::ChildSource::Component( |
| constants::dns_resolver::COMPONENT_URL.to_string(), |
| )), |
| exposes: Some(vec![ |
| fnet_name::LookupAdminMarker::PROTOCOL_NAME.to_string(), |
| fnet_name::LookupMarker::PROTOCOL_NAME.to_string(), |
| ]), |
| uses: Some(fnetemul::ChildUses::Capabilities(vec![ |
| fnetemul::Capability::LogSink(fnetemul::Empty {}), |
| fnetemul::Capability::ChildDep(protocol_dep::<fnet_routes::StateMarker>( |
| constants::netstack::COMPONENT_NAME, |
| )), |
| fnetemul::Capability::ChildDep(protocol_dep::<fposix_socket::ProviderMarker>( |
| constants::netstack::COMPONENT_NAME, |
| )), |
| fnetemul::Capability::ChildDep(protocol_dep::< |
| fidl_fuchsia_testing::FakeClockMarker, |
| >( |
| constants::fake_clock::COMPONENT_NAME |
| )), |
| ])), |
| ..Default::default() |
| }, |
| KnownServiceProvider::Reachability { eager } => fnetemul::ChildDef { |
| name: Some(constants::reachability::COMPONENT_NAME.to_string()), |
| source: Some(fnetemul::ChildSource::Component( |
| constants::reachability::COMPONENT_URL.to_string(), |
| )), |
| exposes: Some(vec![fnet_reachability::MonitorMarker::PROTOCOL_NAME.to_string()]), |
| uses: Some(fnetemul::ChildUses::Capabilities(vec![ |
| fnetemul::Capability::LogSink(fnetemul::Empty {}), |
| fnetemul::Capability::ChildDep(protocol_dep::<fnet_interfaces::StateMarker>( |
| constants::netstack::COMPONENT_NAME, |
| )), |
| fnetemul::Capability::ChildDep(protocol_dep::<fposix_socket::ProviderMarker>( |
| constants::netstack::COMPONENT_NAME, |
| )), |
| fnetemul::Capability::ChildDep(protocol_dep::<fnet_name::LookupMarker>( |
| constants::dns_resolver::COMPONENT_NAME, |
| )), |
| fnetemul::Capability::ChildDep(protocol_dep::<fnet_neighbor::ViewMarker>( |
| constants::netstack::COMPONENT_NAME, |
| )), |
| fnetemul::Capability::ChildDep(protocol_dep::<fnet_debug::InterfacesMarker>( |
| constants::netstack::COMPONENT_NAME, |
| )), |
| fnetemul::Capability::ChildDep(protocol_dep::<fnet_root::InterfacesMarker>( |
| constants::netstack::COMPONENT_NAME, |
| )), |
| fnetemul::Capability::ChildDep(protocol_dep::<fnet_routes::StateV4Marker>( |
| constants::netstack::COMPONENT_NAME, |
| )), |
| fnetemul::Capability::ChildDep(protocol_dep::<fnet_routes::StateV6Marker>( |
| constants::netstack::COMPONENT_NAME, |
| )), |
| fnetemul::Capability::ChildDep(protocol_dep::<fnet_debug::DiagnosticsMarker>( |
| constants::netstack::COMPONENT_NAME, |
| )), |
| fnetemul::Capability::ChildDep(protocol_dep::< |
| fidl_fuchsia_testing::FakeClockMarker, |
| >( |
| constants::fake_clock::COMPONENT_NAME |
| )), |
| ])), |
| eager: Some(*eager), |
| ..Default::default() |
| }, |
| KnownServiceProvider::NetworkTestRealm => fnetemul::ChildDef { |
| name: Some(constants::network_test_realm::COMPONENT_NAME.to_string()), |
| source: Some(fnetemul::ChildSource::Component( |
| constants::network_test_realm::COMPONENT_URL.to_string(), |
| )), |
| exposes: Some(vec![ |
| fntr::ControllerMarker::PROTOCOL_NAME.to_string(), |
| fcomponent::RealmMarker::PROTOCOL_NAME.to_string(), |
| ]), |
| uses: Some(fnetemul::ChildUses::Capabilities(vec![ |
| fnetemul::Capability::LogSink(fnetemul::Empty {}), |
| fnetemul::Capability::ChildDep(protocol_dep::<fnet_stack::StackMarker>( |
| constants::netstack::COMPONENT_NAME, |
| )), |
| fnetemul::Capability::ChildDep(protocol_dep::<fnet_debug::InterfacesMarker>( |
| constants::netstack::COMPONENT_NAME, |
| )), |
| fnetemul::Capability::ChildDep(protocol_dep::<fnet_root::InterfacesMarker>( |
| constants::netstack::COMPONENT_NAME, |
| )), |
| fnetemul::Capability::ChildDep(protocol_dep::<fnet_interfaces::StateMarker>( |
| constants::netstack::COMPONENT_NAME, |
| )), |
| ])), |
| ..Default::default() |
| }, |
| KnownServiceProvider::FakeClock => fnetemul::ChildDef { |
| name: Some(constants::fake_clock::COMPONENT_NAME.to_string()), |
| source: Some(fnetemul::ChildSource::Component( |
| constants::fake_clock::COMPONENT_URL.to_string(), |
| )), |
| exposes: Some(vec![ |
| fidl_fuchsia_testing::FakeClockMarker::PROTOCOL_NAME.to_string(), |
| fidl_fuchsia_testing::FakeClockControlMarker::PROTOCOL_NAME.to_string(), |
| ]), |
| uses: Some(fnetemul::ChildUses::Capabilities(vec![fnetemul::Capability::LogSink( |
| fnetemul::Empty {}, |
| )])), |
| ..Default::default() |
| }, |
| } |
| } |
| } |
| |
| /// Abstraction for a Fuchsia component which offers network stack services. |
| pub trait Netstack: Copy + Clone { |
| /// The Netstack version. |
| const VERSION: NetstackVersion; |
| } |
| |
| /// Uninstantiable type that represents Netstack2's implementation of a |
| /// network stack. |
| #[derive(Copy, Clone)] |
| pub enum Netstack2 {} |
| |
| impl Netstack for Netstack2 { |
| const VERSION: NetstackVersion = NetstackVersion::Netstack2 { tracing: false, fast_udp: false }; |
| } |
| |
| /// Uninstantiable type that represents Netstack2's production implementation of |
| /// a network stack. |
| #[derive(Copy, Clone)] |
| pub enum ProdNetstack2 {} |
| |
| impl Netstack for ProdNetstack2 { |
| const VERSION: NetstackVersion = NetstackVersion::ProdNetstack2; |
| } |
| |
| /// Uninstantiable type that represents Netstack3's implementation of a |
| /// network stack. |
| #[derive(Copy, Clone)] |
| pub enum Netstack3 {} |
| |
| impl Netstack for Netstack3 { |
| const VERSION: NetstackVersion = NetstackVersion::Netstack3; |
| } |
| |
| /// Uninstantiable type that represents Netstack3's production implementation of |
| /// a network stack. |
| #[derive(Copy, Clone)] |
| pub enum ProdNetstack3 {} |
| |
| impl Netstack for ProdNetstack3 { |
| const VERSION: NetstackVersion = NetstackVersion::ProdNetstack3; |
| } |
| |
| /// Abstraction for a Fuchsia component which offers network configuration services. |
| pub trait Manager: Copy + Clone { |
| /// The management agent to be used. |
| const MANAGEMENT_AGENT: ManagementAgent; |
| } |
| |
| /// Uninstantiable type that represents netcfg_basic's implementation of a network manager. |
| #[derive(Copy, Clone)] |
| pub enum NetCfgBasic {} |
| |
| impl Manager for NetCfgBasic { |
| const MANAGEMENT_AGENT: ManagementAgent = ManagementAgent::NetCfg(NetCfgVersion::Basic); |
| } |
| |
| /// Uninstantiable type that represents netcfg_advanced's implementation of a |
| /// network manager. |
| #[derive(Copy, Clone)] |
| pub enum NetCfgAdvanced {} |
| |
| impl Manager for NetCfgAdvanced { |
| const MANAGEMENT_AGENT: ManagementAgent = ManagementAgent::NetCfg(NetCfgVersion::Advanced); |
| } |
| |
| pub use netemul::{DhcpClient, DhcpClientVersion, InStack, OutOfStack}; |
| |
| /// A combination of Netstack and DhcpClient guaranteed to be compatible with |
| /// each other. |
| pub trait NetstackAndDhcpClient: Copy + Clone { |
| /// The netstack to be used. |
| type Netstack: Netstack; |
| /// The DHCP client to be used. |
| type DhcpClient: DhcpClient; |
| } |
| |
| /// Netstack2 with the in-stack DHCP client. |
| #[derive(Copy, Clone)] |
| pub enum Netstack2AndInStackDhcpClient {} |
| |
| impl NetstackAndDhcpClient for Netstack2AndInStackDhcpClient { |
| type Netstack = Netstack2; |
| type DhcpClient = InStack; |
| } |
| |
| /// Netstack2 with the out-of-stack DHCP client. |
| #[derive(Copy, Clone)] |
| pub enum Netstack2AndOutOfStackDhcpClient {} |
| |
| impl NetstackAndDhcpClient for Netstack2AndOutOfStackDhcpClient { |
| type Netstack = Netstack2; |
| type DhcpClient = OutOfStack; |
| } |
| |
| /// Netstack3 with the out-of-stack DHCP client. |
| #[derive(Copy, Clone)] |
| pub enum Netstack3AndOutOfStackDhcpClient {} |
| |
| impl NetstackAndDhcpClient for Netstack3AndOutOfStackDhcpClient { |
| type Netstack = Netstack3; |
| type DhcpClient = OutOfStack; |
| } |
| |
| /// Helpers for `netemul::TestSandbox`. |
| #[async_trait] |
| pub trait TestSandboxExt { |
| /// Creates a realm with Netstack services. |
| fn create_netstack_realm<'a, N, S>(&'a self, name: S) -> Result<netemul::TestRealm<'a>> |
| where |
| N: Netstack, |
| S: Into<Cow<'a, str>>; |
| |
| /// Creates a realm with the base Netstack services plus additional ones in |
| /// `children`. |
| fn create_netstack_realm_with<'a, N, S, I>( |
| &'a self, |
| name: S, |
| children: I, |
| ) -> Result<netemul::TestRealm<'a>> |
| where |
| S: Into<Cow<'a, str>>, |
| N: Netstack, |
| I: IntoIterator, |
| I::Item: Into<fnetemul::ChildDef>; |
| } |
| |
| #[async_trait] |
| impl TestSandboxExt for netemul::TestSandbox { |
| fn create_netstack_realm<'a, N, S>(&'a self, name: S) -> Result<netemul::TestRealm<'a>> |
| where |
| N: Netstack, |
| S: Into<Cow<'a, str>>, |
| { |
| self.create_netstack_realm_with::<N, _, _>(name, std::iter::empty::<fnetemul::ChildDef>()) |
| } |
| |
| fn create_netstack_realm_with<'a, N, S, I>( |
| &'a self, |
| name: S, |
| children: I, |
| ) -> Result<netemul::TestRealm<'a>> |
| where |
| S: Into<Cow<'a, str>>, |
| N: Netstack, |
| I: IntoIterator, |
| I::Item: Into<fnetemul::ChildDef>, |
| { |
| self.create_realm( |
| name, |
| [KnownServiceProvider::Netstack(N::VERSION)] |
| .iter() |
| .map(fnetemul::ChildDef::from) |
| .chain(children.into_iter().map(Into::into)), |
| ) |
| } |
| } |
| |
| /// Helpers for `netemul::TestRealm`. |
| #[async_trait] |
| pub trait TestRealmExt { |
| /// Returns the properties of the loopback interface, or `None` if there is no |
| /// loopback interface. |
| async fn loopback_properties(&self) -> Result<Option<fnet_interfaces_ext::Properties>>; |
| |
| /// Get a `fuchsia.net.interfaces.admin/Control` client proxy for the |
| /// interface identified by [`id`] via `fuchsia.net.root`. |
| /// |
| /// Note that one should prefer to operate on a `TestInterface` if it is |
| /// available; but this method exists in order to obtain a Control channel |
| /// for interfaces such as loopback. |
| fn interface_control(&self, id: u64) -> Result<fnet_interfaces_ext::admin::Control>; |
| } |
| |
| #[async_trait] |
| impl TestRealmExt for netemul::TestRealm<'_> { |
| async fn loopback_properties(&self) -> Result<Option<fnet_interfaces_ext::Properties>> { |
| let interface_state = self |
| .connect_to_protocol::<fnet_interfaces::StateMarker>() |
| .context("failed to connect to fuchsia.net.interfaces/State")?; |
| |
| let properties = fnet_interfaces_ext::existing( |
| fnet_interfaces_ext::event_stream_from_state( |
| &interface_state, |
| fnet_interfaces_ext::IncludedAddresses::OnlyAssigned, |
| ) |
| .expect("create watcher event stream"), |
| HashMap::<u64, fnet_interfaces_ext::PropertiesAndState<()>>::new(), |
| ) |
| .await |
| .context("failed to get existing interface properties from watcher")? |
| .into_iter() |
| .find_map(|(_id, properties_and_state): (u64, _)| { |
| let fnet_interfaces_ext::PropertiesAndState { |
| properties: |
| properties @ fnet_interfaces_ext::Properties { |
| id: _, |
| name: _, |
| device_class, |
| online: _, |
| addresses: _, |
| has_default_ipv4_route: _, |
| has_default_ipv6_route: _, |
| }, |
| state: (), |
| } = properties_and_state; |
| match device_class { |
| fnet_interfaces::DeviceClass::Loopback(fnet_interfaces::Empty) => Some(properties), |
| fnet_interfaces::DeviceClass::Device(_) => None, |
| } |
| }); |
| Ok(properties) |
| } |
| |
| fn interface_control(&self, id: u64) -> Result<fnet_interfaces_ext::admin::Control> { |
| let root_control = self |
| .connect_to_protocol::<fnet_root::InterfacesMarker>() |
| .context("connect to protocol")?; |
| |
| let (control, server) = fnet_interfaces_ext::admin::Control::create_endpoints() |
| .context("create Control proxy")?; |
| let () = root_control.get_admin(id, server).context("get admin")?; |
| Ok(control) |
| } |
| } |