1use std::borrow::Cow;
8use std::collections::HashMap;
9use std::future::Future;
10
11use cm_rust::NativeIntoFidl as _;
12use fidl::endpoints::{DiscoverableProtocolMarker as _, ServiceMarker};
13use fidl_fuchsia_component as fcomponent;
14use fidl_fuchsia_hardware_network as fhwnet;
15use fidl_fuchsia_net_debug as fnet_debug;
16use fidl_fuchsia_net_dhcp as fnet_dhcp;
17use fidl_fuchsia_net_dhcpv6 as fnet_dhcpv6;
18use fidl_fuchsia_net_filter as fnet_filter;
19use fidl_fuchsia_net_filter_deprecated as fnet_filter_deprecated;
20use fidl_fuchsia_net_interfaces as fnet_interfaces;
21use fidl_fuchsia_net_interfaces_admin as fnet_interfaces_admin;
22use fidl_fuchsia_net_interfaces_ext as fnet_interfaces_ext;
23use fidl_fuchsia_net_masquerade as fnet_masquerade;
24use fidl_fuchsia_net_multicast_admin as fnet_multicast_admin;
25use fidl_fuchsia_net_name as fnet_name;
26use fidl_fuchsia_net_ndp as fnet_ndp;
27use fidl_fuchsia_net_neighbor as fnet_neighbor;
28use fidl_fuchsia_net_policy_properties as fnp_properties;
29use fidl_fuchsia_net_policy_socketproxy as fnp_socketproxy;
30use fidl_fuchsia_net_power as fnet_power;
31use fidl_fuchsia_net_reachability as fnet_reachability;
32use fidl_fuchsia_net_root as fnet_root;
33use fidl_fuchsia_net_routes as fnet_routes;
34use fidl_fuchsia_net_routes_admin as fnet_routes_admin;
35use fidl_fuchsia_net_settings as fnet_settings;
36use fidl_fuchsia_net_sockets as fnet_sockets;
37use fidl_fuchsia_net_stack as fnet_stack;
38use fidl_fuchsia_net_test_realm as fntr;
39use fidl_fuchsia_net_virtualization as fnet_virtualization;
40use fidl_fuchsia_netemul as fnetemul;
41use fidl_fuchsia_posix_socket as fposix_socket;
42use fidl_fuchsia_posix_socket_packet as fposix_socket_packet;
43use fidl_fuchsia_posix_socket_raw as fposix_socket_raw;
44use fidl_fuchsia_scheduler as fscheduler;
45use fidl_fuchsia_stash as fstash;
46use fidl_fuchsia_update_verify as fupdate_verify;
47
48use anyhow::Context as _;
49
50use crate::Result;
51
52#[derive(Copy, Clone, Eq, PartialEq, Debug)]
55#[allow(missing_docs)]
56pub enum NetstackVersion {
57 Netstack2 { tracing: bool, fast_udp: bool },
58 Netstack3,
59 ProdNetstack2,
60 ProdNetstack3,
61}
62
63impl NetstackVersion {
64 pub fn get_url(&self) -> &'static str {
66 match self {
67 NetstackVersion::Netstack2 { tracing, fast_udp } => match (tracing, fast_udp) {
68 (false, false) => "#meta/netstack-debug.cm",
69 (false, true) => "#meta/netstack-with-fast-udp-debug.cm",
70 (true, false) => "#meta/netstack-with-tracing.cm",
71 (true, true) => "#meta/netstack-with-fast-udp-tracing.cm",
72 },
73 NetstackVersion::Netstack3 => "#meta/netstack3-debug.cm",
74 NetstackVersion::ProdNetstack2 => "#meta/netstack.cm",
75 NetstackVersion::ProdNetstack3 => "#meta/netstack3.cm",
76 }
77 }
78
79 pub fn get_services(&self) -> &[&'static str] {
81 macro_rules! common_services_and {
82 ($($name:expr),*) => {[
83 fnet_debug::InterfacesMarker::PROTOCOL_NAME,
84 fnet_interfaces_admin::InstallerMarker::PROTOCOL_NAME,
85 fnet_interfaces::StateMarker::PROTOCOL_NAME,
86 fnet_multicast_admin::Ipv4RoutingTableControllerMarker::PROTOCOL_NAME,
87 fnet_multicast_admin::Ipv6RoutingTableControllerMarker::PROTOCOL_NAME,
88 fnet_name::DnsServerWatcherMarker::PROTOCOL_NAME,
89 fnet_neighbor::ControllerMarker::PROTOCOL_NAME,
90 fnet_neighbor::ViewMarker::PROTOCOL_NAME,
91 fnet_root::InterfacesMarker::PROTOCOL_NAME,
92 fnet_root::RoutesV4Marker::PROTOCOL_NAME,
93 fnet_root::RoutesV6Marker::PROTOCOL_NAME,
94 fnet_routes::StateMarker::PROTOCOL_NAME,
95 fnet_routes::StateV4Marker::PROTOCOL_NAME,
96 fnet_routes::StateV6Marker::PROTOCOL_NAME,
97 fnet_routes_admin::RouteTableProviderV4Marker::PROTOCOL_NAME,
98 fnet_routes_admin::RouteTableProviderV6Marker::PROTOCOL_NAME,
99 fnet_routes_admin::RouteTableV4Marker::PROTOCOL_NAME,
100 fnet_routes_admin::RouteTableV6Marker::PROTOCOL_NAME,
101 fnet_routes_admin::RuleTableV4Marker::PROTOCOL_NAME,
102 fnet_routes_admin::RuleTableV6Marker::PROTOCOL_NAME,
103 fnet_stack::StackMarker::PROTOCOL_NAME,
104 fposix_socket_packet::ProviderMarker::PROTOCOL_NAME,
105 fposix_socket_raw::ProviderMarker::PROTOCOL_NAME,
106 fposix_socket::ProviderMarker::PROTOCOL_NAME,
107 fnet_debug::DiagnosticsMarker::PROTOCOL_NAME,
108 fnet_debug::PacketCaptureProviderMarker::PROTOCOL_NAME,
109
110 fupdate_verify::ComponentOtaHealthCheckMarker::PROTOCOL_NAME,
111 $($name),*
112 ]};
113 ($($name:expr),*,) => {common_services_and!($($name),*)}
115 }
116 match self {
117 NetstackVersion::Netstack2 { tracing: _, fast_udp: _ }
118 | NetstackVersion::ProdNetstack2 => &common_services_and!(
119 fnet_filter_deprecated::FilterMarker::PROTOCOL_NAME,
120 fnet_stack::LogMarker::PROTOCOL_NAME,
121 ),
122 NetstackVersion::Netstack3 | NetstackVersion::ProdNetstack3 => &common_services_and!(
123 fnet_filter::ControlMarker::PROTOCOL_NAME,
124 fnet_filter::StateMarker::PROTOCOL_NAME,
125 fnet_ndp::RouterAdvertisementOptionWatcherProviderMarker::PROTOCOL_NAME,
126 fnet_power::WakeGroupProviderMarker::PROTOCOL_NAME,
127 fnet_root::FilterMarker::PROTOCOL_NAME,
128 fnet_settings::StateMarker::PROTOCOL_NAME,
129 fnet_settings::ControlMarker::PROTOCOL_NAME,
130 fnet_sockets::DiagnosticsMarker::PROTOCOL_NAME,
131 fnet_sockets::ControlMarker::PROTOCOL_NAME,
132 ),
133 }
134 }
135
136 pub const fn is_netstack3(&self) -> bool {
138 match self {
139 Self::Netstack3 | Self::ProdNetstack3 => true,
140 Self::Netstack2 { .. } | Self::ProdNetstack2 => false,
141 }
142 }
143}
144
145pub trait NetstackExt {
147 const USE_OUT_OF_STACK_DHCP_CLIENT: bool;
149}
150
151impl<N: Netstack> NetstackExt for N {
152 const USE_OUT_OF_STACK_DHCP_CLIENT: bool = match Self::VERSION {
153 NetstackVersion::Netstack3 | NetstackVersion::ProdNetstack3 => true,
154 NetstackVersion::Netstack2 { .. } | NetstackVersion::ProdNetstack2 => false,
155 };
156}
157
158#[derive(Copy, Clone, Eq, PartialEq, Debug)]
160pub enum NetCfgVersion {
161 Basic,
163 Advanced,
165}
166
167#[derive(Copy, Clone, Eq, PartialEq, Debug)]
169pub enum ManagementAgent {
170 NetCfg(NetCfgVersion),
172}
173
174impl ManagementAgent {
175 pub fn get_url(&self) -> &'static str {
177 match self {
178 Self::NetCfg(NetCfgVersion::Basic) => constants::netcfg::basic::COMPONENT_URL,
179 Self::NetCfg(NetCfgVersion::Advanced) => constants::netcfg::advanced::COMPONENT_URL,
180 }
181 }
182
183 pub fn get_program_args(&self) -> &[&'static str] {
186 match self {
187 Self::NetCfg(NetCfgVersion::Basic) | Self::NetCfg(NetCfgVersion::Advanced) => {
188 &["--min-severity", "DEBUG"]
189 }
190 }
191 }
192
193 pub fn get_services(&self) -> &[&'static str] {
195 match self {
196 Self::NetCfg(NetCfgVersion::Basic) => &[
197 fnet_dhcpv6::PrefixProviderMarker::PROTOCOL_NAME,
198 fnet_masquerade::FactoryMarker::PROTOCOL_NAME,
199 fnet_name::DnsServerWatcherMarker::PROTOCOL_NAME,
200 fnp_properties::NetworksMarker::PROTOCOL_NAME,
201 fnp_socketproxy::NetworkRegistryMarker::PROTOCOL_NAME,
202 fnp_properties::NetworkTokenResolverMarker::PROTOCOL_NAME,
203 fnet_reachability::MonitorMarker::PROTOCOL_NAME,
204 ],
205 Self::NetCfg(NetCfgVersion::Advanced) => &[
206 fnet_dhcpv6::PrefixProviderMarker::PROTOCOL_NAME,
207 fnet_masquerade::FactoryMarker::PROTOCOL_NAME,
208 fnet_name::DnsServerWatcherMarker::PROTOCOL_NAME,
209 fnet_virtualization::ControlMarker::PROTOCOL_NAME,
210 fnp_properties::NetworksMarker::PROTOCOL_NAME,
211 fnp_socketproxy::NetworkRegistryMarker::PROTOCOL_NAME,
212 fnp_properties::NetworkTokenResolverMarker::PROTOCOL_NAME,
213 fnet_reachability::MonitorMarker::PROTOCOL_NAME,
214 ],
215 }
216 }
217}
218
219#[derive(Clone, Eq, PartialEq, Debug)]
221#[allow(missing_docs)]
222pub enum ManagerConfig {
223 Empty,
224 Dhcpv6,
225 Forwarding,
226 AllDelegated,
227 IfacePrefix,
228 DuplicateNames,
229 EnableSocketProxy,
230 EnableSocketProxyAllDelegated,
231 PacketFilterEthernet,
232 PacketFilterWlan,
233 WithBlackhole,
234 AllInterfaceLocalDelegated,
235}
236
237impl ManagerConfig {
238 fn as_str(&self) -> &'static str {
239 match self {
240 ManagerConfig::Empty => "/pkg/netcfg/empty.json",
241 ManagerConfig::Dhcpv6 => "/pkg/netcfg/dhcpv6.json",
242 ManagerConfig::Forwarding => "/pkg/netcfg/forwarding.json",
243 ManagerConfig::AllDelegated => "/pkg/netcfg/all_delegated.json",
244 ManagerConfig::IfacePrefix => "/pkg/netcfg/iface_prefix.json",
245 ManagerConfig::DuplicateNames => "/pkg/netcfg/duplicate_names.json",
246 ManagerConfig::EnableSocketProxy => "/pkg/netcfg/enable_socket_proxy.json",
247 ManagerConfig::EnableSocketProxyAllDelegated => {
248 "/pkg/netcfg/enable_socket_proxy_all_delegated.json"
249 }
250 ManagerConfig::PacketFilterEthernet => "/pkg/netcfg/packet_filter_ethernet.json",
251 ManagerConfig::PacketFilterWlan => "/pkg/netcfg/packet_filter_wlan.json",
252 ManagerConfig::WithBlackhole => "/pkg/netcfg/with_blackhole.json",
253 ManagerConfig::AllInterfaceLocalDelegated => {
254 "/pkg/netcfg/all_interface_local_delegated.json"
255 }
256 }
257 }
258}
259
260#[derive(Copy, Clone, Default, Eq, PartialEq, Debug)]
261pub enum SocketProxyType {
263 #[default]
264 None,
266 Real,
268 Fake,
270}
271
272impl SocketProxyType {
273 pub fn known_service_provider(&self) -> Option<KnownServiceProvider> {
275 match self {
276 SocketProxyType::None => None,
277 SocketProxyType::Real => Some(KnownServiceProvider::SocketProxy),
278 SocketProxyType::Fake => Some(KnownServiceProvider::FakeSocketProxy),
279 }
280 }
281}
282
283#[derive(Clone, Eq, PartialEq, Debug)]
285#[allow(missing_docs)]
286pub enum KnownServiceProvider {
287 Netstack(NetstackVersion),
288 Manager {
289 agent: ManagementAgent,
290 config: ManagerConfig,
291 use_dhcp_server: bool,
292 use_out_of_stack_dhcp_client: bool,
293 socket_proxy_type: SocketProxyType,
294 },
295 SecureStash,
296 DhcpServer {
297 persistent: bool,
298 },
299 DhcpClient,
300 Dhcpv6Client,
301 DnsResolver,
302 Reachability {
303 eager: bool,
304 },
305 SocketProxy,
306 NetworkTestRealm {
307 require_outer_netstack: bool,
308 },
309 FakeClock,
310 FakeSocketProxy,
311 FakeNetcfg,
312}
313
314#[allow(missing_docs)]
317pub mod constants {
318 pub mod netstack {
319 pub const COMPONENT_NAME: &str = "netstack";
320 }
321 pub mod netcfg {
322 pub const COMPONENT_NAME: &str = "netcfg";
323 pub mod basic {
324 pub const COMPONENT_URL: &str = "#meta/netcfg-basic.cm";
325 }
326 pub mod advanced {
327 pub const COMPONENT_URL: &str = "#meta/netcfg-advanced.cm";
328 }
329 pub mod fake {
330 pub const COMPONENT_URL: &str = "#meta/fake_netcfg.cm";
331 }
332 pub const DEV_CLASS_NETWORK: &str = "dev-class-network";
335 pub const CLASS_NETWORK_PATH: &str = "class/network";
336 }
337 pub mod socket_proxy {
338 pub const COMPONENT_NAME: &str = "network-socket-proxy";
339 pub const COMPONENT_URL: &str = "#meta/network-socket-proxy.cm";
340 }
341 pub mod secure_stash {
342 pub const COMPONENT_NAME: &str = "stash_secure";
343 pub const COMPONENT_URL: &str = "#meta/stash_secure.cm";
344 }
345 pub mod dhcp_server {
346 pub const COMPONENT_NAME: &str = "dhcpd";
347 pub const COMPONENT_URL: &str = "#meta/dhcpv4_server.cm";
348 }
349 pub mod dhcp_client {
350 pub const COMPONENT_NAME: &str = "dhcp-client";
351 pub const COMPONENT_URL: &str = "#meta/dhcp-client.cm";
352 }
353 pub mod dhcpv6_client {
354 pub const COMPONENT_NAME: &str = "dhcpv6-client";
355 pub const COMPONENT_URL: &str = "#meta/dhcpv6-client.cm";
356 }
357 pub mod dns_resolver {
358 pub const COMPONENT_NAME: &str = "dns_resolver";
359 pub const COMPONENT_URL: &str = "#meta/dns_resolver_with_fake_time.cm";
360 }
361 pub mod reachability {
362 pub const COMPONENT_NAME: &str = "reachability";
363 pub const COMPONENT_URL: &str = "#meta/reachability_with_fake_time.cm";
364 }
365 pub mod network_test_realm {
366 pub const COMPONENT_NAME: &str = "controller";
367 pub const COMPONENT_URL: &str = "#meta/controller.cm";
368 }
369 pub mod fake_clock {
370 pub const COMPONENT_NAME: &str = "fake_clock";
371 pub const COMPONENT_URL: &str = "#meta/fake_clock.cm";
372 }
373 pub mod fake_socket_proxy {
374 pub const COMPONENT_NAME: &str = "fake_socket_proxy";
375 pub const COMPONENT_URL: &str = "#meta/fake_socket_proxy.cm";
376 }
377}
378
379fn protocol_dep<P>(component_name: &'static str) -> fnetemul::ChildDep
380where
381 P: fidl::endpoints::DiscoverableProtocolMarker,
382{
383 fnetemul::ChildDep {
384 name: Some(component_name.into()),
385 capability: Some(fnetemul::ExposedCapability::Protocol(P::PROTOCOL_NAME.to_string())),
386 ..Default::default()
387 }
388}
389
390fn or_void_protocol_dep<P>(
391 component_name: &'static str,
392 is_child_present: bool,
393) -> fnetemul::ChildDep
394where
395 P: fidl::endpoints::DiscoverableProtocolMarker,
396{
397 if is_child_present { protocol_dep::<P>(component_name) } else { void_protocol_dep::<P>() }
398}
399
400fn void_protocol_dep<P>() -> fnetemul::ChildDep
401where
402 P: fidl::endpoints::DiscoverableProtocolMarker,
403{
404 fnetemul::ChildDep {
405 name: None,
406 capability: Some(fnetemul::ExposedCapability::Protocol(P::PROTOCOL_NAME.to_string())),
407 ..Default::default()
408 }
409}
410
411impl From<KnownServiceProvider> for fnetemul::ChildDef {
412 fn from(s: KnownServiceProvider) -> Self {
413 (&s).into()
414 }
415}
416
417impl<'a> From<&'a KnownServiceProvider> for fnetemul::ChildDef {
418 fn from(s: &'a KnownServiceProvider) -> Self {
419 match s {
420 KnownServiceProvider::Netstack(version) => fnetemul::ChildDef {
421 name: Some(constants::netstack::COMPONENT_NAME.to_string()),
422 source: Some(fnetemul::ChildSource::Component(version.get_url().to_string())),
423 exposes: Some(
424 version.get_services().iter().map(|service| service.to_string()).collect(),
425 ),
426 uses: {
427 let mut uses = vec![fnetemul::Capability::LogSink(fnetemul::Empty {})];
428 match version {
429 NetstackVersion::Netstack2 { tracing: false, fast_udp: _ } => {}
436 NetstackVersion::Netstack2 { tracing: true, fast_udp: _ } => {
437 uses.push(fnetemul::Capability::TracingProvider(fnetemul::Empty));
438 }
439 NetstackVersion::ProdNetstack2 => {
440 uses.push(fnetemul::Capability::ChildDep(protocol_dep::<
441 fstash::SecureStoreMarker,
442 >(
443 constants::secure_stash::COMPONENT_NAME,
444 )));
445 }
446 NetstackVersion::Netstack3 | NetstackVersion::ProdNetstack3 => {
447 uses.push(fnetemul::Capability::TracingProvider(fnetemul::Empty));
448 uses.push(fnetemul::Capability::StorageDep(fnetemul::StorageDep {
449 variant: Some(fnetemul::StorageVariant::Data),
450 path: Some("/data".to_string()),
451 ..Default::default()
452 }));
453 }
454 }
455 Some(fnetemul::ChildUses::Capabilities(uses))
456 },
457 ..Default::default()
458 },
459 KnownServiceProvider::Manager {
460 agent,
461 use_dhcp_server,
462 config,
463 use_out_of_stack_dhcp_client,
464 socket_proxy_type: _,
465 } => {
466 let enable_dhcpv6 = match config {
467 ManagerConfig::Dhcpv6 => true,
468 ManagerConfig::Forwarding
469 | ManagerConfig::Empty
470 | ManagerConfig::AllDelegated
471 | ManagerConfig::IfacePrefix
472 | ManagerConfig::DuplicateNames
473 | ManagerConfig::EnableSocketProxy
474 | ManagerConfig::EnableSocketProxyAllDelegated
475 | ManagerConfig::PacketFilterEthernet
476 | ManagerConfig::PacketFilterWlan
477 | ManagerConfig::WithBlackhole
478 | ManagerConfig::AllInterfaceLocalDelegated => false,
479 };
480
481 fnetemul::ChildDef {
482 name: Some(constants::netcfg::COMPONENT_NAME.to_string()),
483 source: Some(fnetemul::ChildSource::Component(agent.get_url().to_string())),
484 program_args: Some(
485 agent
486 .get_program_args()
487 .iter()
488 .cloned()
489 .chain(std::iter::once("--config-data"))
490 .chain(std::iter::once(config.as_str()))
491 .map(Into::into)
492 .collect(),
493 ),
494 exposes: Some(
495 agent.get_services().iter().map(|service| service.to_string()).collect(),
496 ),
497 uses: Some(fnetemul::ChildUses::Capabilities(
498 std::iter::once(fnetemul::Capability::ChildDep(or_void_protocol_dep::<
499 fnet_dhcp::Server_Marker,
500 >(
501 constants::dhcp_server::COMPONENT_NAME,
502 *use_dhcp_server,
503 )))
504 .chain(std::iter::once(fnetemul::Capability::ChildDep(
505 or_void_protocol_dep::<fnet_dhcpv6::ClientProviderMarker>(
506 constants::dhcpv6_client::COMPONENT_NAME,
507 enable_dhcpv6,
508 ),
509 )))
510 .chain(std::iter::once(fnetemul::Capability::ChildDep(
511 or_void_protocol_dep::<fnet_dhcp::ClientProviderMarker>(
512 constants::dhcp_client::COMPONENT_NAME,
513 *use_out_of_stack_dhcp_client,
514 ),
515 )))
516 .chain(
517 [
518 fnetemul::Capability::LogSink(fnetemul::Empty {}),
519 fnetemul::Capability::ChildDep(fnetemul::ChildDep {
520 dynamically_offer_from_void: Some(true),
521 ..protocol_dep::<fnet_filter::ControlMarker>(
522 constants::netstack::COMPONENT_NAME,
523 )
524 }),
525 fnetemul::Capability::ChildDep(fnetemul::ChildDep {
526 dynamically_offer_from_void: Some(true),
527 ..protocol_dep::<fnet_filter_deprecated::FilterMarker>(
528 constants::netstack::COMPONENT_NAME,
529 )
530 }),
531 fnetemul::Capability::ChildDep(protocol_dep::<
532 fnet_interfaces::StateMarker,
533 >(
534 constants::netstack::COMPONENT_NAME,
535 )),
536 fnetemul::Capability::ChildDep(protocol_dep::<
537 fnet_interfaces_admin::InstallerMarker,
538 >(
539 constants::netstack::COMPONENT_NAME,
540 )),
541 fnetemul::Capability::ChildDep(protocol_dep::<
542 fnet_stack::StackMarker,
543 >(
544 constants::netstack::COMPONENT_NAME,
545 )),
546 fnetemul::Capability::ChildDep(protocol_dep::<
547 fnet_routes_admin::RouteTableV4Marker,
548 >(
549 constants::netstack::COMPONENT_NAME,
550 )),
551 fnetemul::Capability::ChildDep(protocol_dep::<
552 fnet_routes_admin::RouteTableV6Marker,
553 >(
554 constants::netstack::COMPONENT_NAME,
555 )),
556 fnetemul::Capability::ChildDep(protocol_dep::<
557 fnet_routes_admin::RuleTableV4Marker,
558 >(
559 constants::netstack::COMPONENT_NAME,
560 )),
561 fnetemul::Capability::ChildDep(protocol_dep::<
562 fnet_routes_admin::RuleTableV6Marker,
563 >(
564 constants::netstack::COMPONENT_NAME,
565 )),
566 fnetemul::Capability::ChildDep(protocol_dep::<
567 fnet_name::DnsServerWatcherMarker,
568 >(
569 constants::netstack::COMPONENT_NAME,
570 )),
571 fnetemul::Capability::ChildDep(protocol_dep::<
572 fnet_name::LookupAdminMarker,
573 >(
574 constants::dns_resolver::COMPONENT_NAME,
575 )),
576 fnetemul::Capability::ChildDep(protocol_dep::<
577 fnet_ndp::RouterAdvertisementOptionWatcherProviderMarker,
578 >(
579 constants::netstack::COMPONENT_NAME,
580 )),
581 fnetemul::Capability::ChildDep(fnetemul::ChildDep {
582 name: Some(
583 fnetemul::NETEMUL_SERVICES_COMPONENT_NAME.to_string(),
584 ),
585 capability: Some(fnetemul::ExposedCapability::Service(
586 fhwnet::ServiceMarker::SERVICE_NAME.to_string(),
587 )),
588 ..Default::default()
589 }),
590 fnetemul::Capability::StorageDep(fnetemul::StorageDep {
591 variant: Some(fnetemul::StorageVariant::Data),
592 path: Some("/data".to_string()),
593 ..Default::default()
594 }),
595 ]
596 .into_iter(),
597 )
598 .collect(),
599 )),
600 eager: Some(true),
601 ..Default::default()
602 }
603 }
604 KnownServiceProvider::SecureStash => fnetemul::ChildDef {
605 name: Some(constants::secure_stash::COMPONENT_NAME.to_string()),
606 source: Some(fnetemul::ChildSource::Component(
607 constants::secure_stash::COMPONENT_URL.to_string(),
608 )),
609 exposes: Some(vec![fstash::SecureStoreMarker::PROTOCOL_NAME.to_string()]),
610 uses: Some(fnetemul::ChildUses::Capabilities(vec![
611 fnetemul::Capability::LogSink(fnetemul::Empty {}),
612 fnetemul::Capability::StorageDep(fnetemul::StorageDep {
613 variant: Some(fnetemul::StorageVariant::Data),
614 path: Some("/data".to_string()),
615 ..Default::default()
616 }),
617 ])),
618 ..Default::default()
619 },
620 KnownServiceProvider::DhcpServer { persistent } => fnetemul::ChildDef {
621 name: Some(constants::dhcp_server::COMPONENT_NAME.to_string()),
622 source: Some(fnetemul::ChildSource::Component(
623 constants::dhcp_server::COMPONENT_URL.to_string(),
624 )),
625 exposes: Some(vec![fnet_dhcp::Server_Marker::PROTOCOL_NAME.to_string()]),
626 uses: Some(fnetemul::ChildUses::Capabilities(
627 [
628 fnetemul::Capability::LogSink(fnetemul::Empty {}),
629 fnetemul::Capability::ChildDep(protocol_dep::<
630 fnet_neighbor::ControllerMarker,
631 >(
632 constants::netstack::COMPONENT_NAME
633 )),
634 fnetemul::Capability::ChildDep(
635 protocol_dep::<fposix_socket::ProviderMarker>(
636 constants::netstack::COMPONENT_NAME,
637 ),
638 ),
639 fnetemul::Capability::ChildDep(protocol_dep::<
640 fposix_socket_packet::ProviderMarker,
641 >(
642 constants::netstack::COMPONENT_NAME
643 )),
644 ]
645 .into_iter()
646 .chain(persistent.then_some(fnetemul::Capability::ChildDep(protocol_dep::<
647 fstash::SecureStoreMarker,
648 >(
649 constants::secure_stash::COMPONENT_NAME,
650 ))))
651 .collect(),
652 )),
653 program_args: if *persistent {
654 Some(vec![String::from("--persistent")])
655 } else {
656 None
657 },
658 ..Default::default()
659 },
660 KnownServiceProvider::DhcpClient => fnetemul::ChildDef {
661 name: Some(constants::dhcp_client::COMPONENT_NAME.to_string()),
662 source: Some(fnetemul::ChildSource::Component(
663 constants::dhcp_client::COMPONENT_URL.to_string(),
664 )),
665 exposes: Some(vec![fnet_dhcp::ClientProviderMarker::PROTOCOL_NAME.to_string()]),
666 uses: Some(fnetemul::ChildUses::Capabilities(vec![
667 fnetemul::Capability::LogSink(fnetemul::Empty {}),
668 fnetemul::Capability::ChildDep(protocol_dep::<fposix_socket::ProviderMarker>(
669 constants::netstack::COMPONENT_NAME,
670 )),
671 fnetemul::Capability::ChildDep(protocol_dep::<
672 fposix_socket_packet::ProviderMarker,
673 >(
674 constants::netstack::COMPONENT_NAME
675 )),
676 ])),
677 program_args: None,
678 ..Default::default()
679 },
680 KnownServiceProvider::Dhcpv6Client => fnetemul::ChildDef {
681 name: Some(constants::dhcpv6_client::COMPONENT_NAME.to_string()),
682 source: Some(fnetemul::ChildSource::Component(
683 constants::dhcpv6_client::COMPONENT_URL.to_string(),
684 )),
685 exposes: Some(vec![fnet_dhcpv6::ClientProviderMarker::PROTOCOL_NAME.to_string()]),
686 uses: Some(fnetemul::ChildUses::Capabilities(vec![
687 fnetemul::Capability::LogSink(fnetemul::Empty {}),
688 fnetemul::Capability::ChildDep(protocol_dep::<fposix_socket::ProviderMarker>(
689 constants::netstack::COMPONENT_NAME,
690 )),
691 ])),
692 ..Default::default()
693 },
694 KnownServiceProvider::DnsResolver => fnetemul::ChildDef {
695 name: Some(constants::dns_resolver::COMPONENT_NAME.to_string()),
696 source: Some(fnetemul::ChildSource::Component(
697 constants::dns_resolver::COMPONENT_URL.to_string(),
698 )),
699 exposes: Some(vec![
700 fnet_name::LookupAdminMarker::PROTOCOL_NAME.to_string(),
701 fnet_name::LookupMarker::PROTOCOL_NAME.to_string(),
702 ]),
703 uses: Some(fnetemul::ChildUses::Capabilities(vec![
704 fnetemul::Capability::LogSink(fnetemul::Empty {}),
705 fnetemul::Capability::ChildDep(protocol_dep::<fnet_routes::StateMarker>(
706 constants::netstack::COMPONENT_NAME,
707 )),
708 fnetemul::Capability::ChildDep(protocol_dep::<fposix_socket::ProviderMarker>(
709 constants::netstack::COMPONENT_NAME,
710 )),
711 fnetemul::Capability::ChildDep(protocol_dep::<
712 fidl_fuchsia_testing::FakeClockMarker,
713 >(
714 constants::fake_clock::COMPONENT_NAME
715 )),
716 fnetemul::Capability::ChildDep(void_protocol_dep::<
717 fscheduler::RoleManagerMarker,
718 >()),
719 ])),
720 ..Default::default()
721 },
722 KnownServiceProvider::Reachability { eager } => fnetemul::ChildDef {
723 name: Some(constants::reachability::COMPONENT_NAME.to_string()),
724 source: Some(fnetemul::ChildSource::Component(
725 constants::reachability::COMPONENT_URL.to_string(),
726 )),
727 exposes: Some(vec![fnet_reachability::MonitorMarker::PROTOCOL_NAME.to_string()]),
728 uses: Some(fnetemul::ChildUses::Capabilities(vec![
729 fnetemul::Capability::LogSink(fnetemul::Empty {}),
730 fnetemul::Capability::ChildDep(protocol_dep::<fnet_interfaces::StateMarker>(
731 constants::netstack::COMPONENT_NAME,
732 )),
733 fnetemul::Capability::ChildDep(protocol_dep::<fposix_socket::ProviderMarker>(
734 constants::netstack::COMPONENT_NAME,
735 )),
736 fnetemul::Capability::ChildDep(protocol_dep::<fnet_name::LookupMarker>(
737 constants::dns_resolver::COMPONENT_NAME,
738 )),
739 fnetemul::Capability::ChildDep(protocol_dep::<fnet_neighbor::ViewMarker>(
740 constants::netstack::COMPONENT_NAME,
741 )),
742 fnetemul::Capability::ChildDep(protocol_dep::<fnet_debug::InterfacesMarker>(
743 constants::netstack::COMPONENT_NAME,
744 )),
745 fnetemul::Capability::ChildDep(protocol_dep::<fnet_root::InterfacesMarker>(
746 constants::netstack::COMPONENT_NAME,
747 )),
748 fnetemul::Capability::ChildDep(protocol_dep::<fnet_routes::StateV4Marker>(
749 constants::netstack::COMPONENT_NAME,
750 )),
751 fnetemul::Capability::ChildDep(protocol_dep::<fnet_routes::StateV6Marker>(
752 constants::netstack::COMPONENT_NAME,
753 )),
754 fnetemul::Capability::ChildDep(protocol_dep::<fnet_debug::DiagnosticsMarker>(
755 constants::netstack::COMPONENT_NAME,
756 )),
757 fnetemul::Capability::ChildDep(protocol_dep::<
758 fidl_fuchsia_testing::FakeClockMarker,
759 >(
760 constants::fake_clock::COMPONENT_NAME
761 )),
762 ])),
763 eager: Some(*eager),
764 ..Default::default()
765 },
766 KnownServiceProvider::SocketProxy => fnetemul::ChildDef {
767 name: Some(constants::socket_proxy::COMPONENT_NAME.to_string()),
768 source: Some(fnetemul::ChildSource::Component(
769 constants::socket_proxy::COMPONENT_URL.to_string(),
770 )),
771 exposes: Some(vec![
772 fposix_socket::ProviderMarker::PROTOCOL_NAME.to_string(),
773 fposix_socket_raw::ProviderMarker::PROTOCOL_NAME.to_string(),
774 fnp_socketproxy::StarnixNetworksMarker::PROTOCOL_NAME.to_string(),
775 ]),
776 uses: Some(fnetemul::ChildUses::Capabilities(vec![
777 fnetemul::Capability::ChildDep(protocol_dep::<fposix_socket::ProviderMarker>(
778 constants::netstack::COMPONENT_NAME,
779 )),
780 fnetemul::Capability::ChildDep(
781 protocol_dep::<fposix_socket_raw::ProviderMarker>(
782 constants::netstack::COMPONENT_NAME,
783 ),
784 ),
785 fnetemul::Capability::ChildDep(fnetemul::ChildDep {
786 is_weak: Some(true),
787 ..protocol_dep::<fnp_properties::NetworksMarker>(
788 constants::netcfg::COMPONENT_NAME,
789 )
790 }),
791 fnetemul::Capability::ChildDep(fnetemul::ChildDep {
792 is_weak: Some(true),
793 ..protocol_dep::<fnp_socketproxy::NetworkRegistryMarker>(
794 constants::netcfg::COMPONENT_NAME,
795 )
796 }),
797 ])),
798 ..Default::default()
799 },
800 KnownServiceProvider::NetworkTestRealm { require_outer_netstack } => {
801 fnetemul::ChildDef {
802 name: Some(constants::network_test_realm::COMPONENT_NAME.to_string()),
803 source: Some(fnetemul::ChildSource::Component(
804 constants::network_test_realm::COMPONENT_URL.to_string(),
805 )),
806 exposes: Some(vec![
807 fntr::ControllerMarker::PROTOCOL_NAME.to_string(),
808 fcomponent::RealmMarker::PROTOCOL_NAME.to_string(),
809 ]),
810 uses: Some(fnetemul::ChildUses::Capabilities(
811 [
812 fnetemul::Capability::LogSink(fnetemul::Empty {}),
813 fnetemul::Capability::ChildDep(fnetemul::ChildDep {
814 name: Some(fnetemul::NETEMUL_SERVICES_COMPONENT_NAME.to_string()),
815 capability: Some(fnetemul::ExposedCapability::Service(
816 fhwnet::ServiceMarker::SERVICE_NAME.to_string(),
817 )),
818 ..Default::default()
819 }),
820 ]
821 .into_iter()
822 .chain(
823 require_outer_netstack
824 .then_some([
825 fnetemul::Capability::ChildDep(protocol_dep::<
826 fnet_stack::StackMarker,
827 >(
828 constants::netstack::COMPONENT_NAME,
829 )),
830 fnetemul::Capability::ChildDep(protocol_dep::<
831 fnet_debug::InterfacesMarker,
832 >(
833 constants::netstack::COMPONENT_NAME,
834 )),
835 fnetemul::Capability::ChildDep(protocol_dep::<
836 fnet_root::InterfacesMarker,
837 >(
838 constants::netstack::COMPONENT_NAME,
839 )),
840 fnetemul::Capability::ChildDep(protocol_dep::<
841 fnet_interfaces::StateMarker,
842 >(
843 constants::netstack::COMPONENT_NAME,
844 )),
845 ])
846 .into_iter()
847 .flatten(),
848 )
849 .collect::<Vec<_>>(),
850 )),
851 ..Default::default()
852 }
853 }
854 KnownServiceProvider::FakeClock => fnetemul::ChildDef {
855 name: Some(constants::fake_clock::COMPONENT_NAME.to_string()),
856 source: Some(fnetemul::ChildSource::Component(
857 constants::fake_clock::COMPONENT_URL.to_string(),
858 )),
859 exposes: Some(vec![
860 fidl_fuchsia_testing::FakeClockMarker::PROTOCOL_NAME.to_string(),
861 fidl_fuchsia_testing::FakeClockControlMarker::PROTOCOL_NAME.to_string(),
862 ]),
863 uses: Some(fnetemul::ChildUses::Capabilities(vec![fnetemul::Capability::LogSink(
864 fnetemul::Empty {},
865 )])),
866 ..Default::default()
867 },
868 KnownServiceProvider::FakeSocketProxy => fnetemul::ChildDef {
869 name: Some(constants::fake_socket_proxy::COMPONENT_NAME.to_string()),
870 source: Some(fnetemul::ChildSource::Component(
871 constants::fake_socket_proxy::COMPONENT_URL.to_string(),
872 )),
873 exposes: Some(vec![
874 fnp_socketproxy::NetworkRegistryMarker::PROTOCOL_NAME.to_string(),
875 ]),
876 uses: Some(fnetemul::ChildUses::Capabilities(vec![
877 fnetemul::Capability::ChildDep(fnetemul::ChildDep {
878 is_weak: Some(true),
879 ..protocol_dep::<fnp_socketproxy::NetworkRegistryMarker>(
880 constants::netcfg::COMPONENT_NAME,
881 )
882 }),
883 ])),
884 ..Default::default()
885 },
886 KnownServiceProvider::FakeNetcfg => fnetemul::ChildDef {
887 name: Some(constants::netcfg::COMPONENT_NAME.to_string()),
888 source: Some(fnetemul::ChildSource::Component(
889 constants::netcfg::fake::COMPONENT_URL.to_string(),
890 )),
891 exposes: Some(vec![
892 fnp_properties::NetworksMarker::PROTOCOL_NAME.to_string(),
893 fnp_socketproxy::NetworkRegistryMarker::PROTOCOL_NAME.to_string(),
894 ]),
895 ..Default::default()
896 },
897 }
898 }
899}
900
901pub fn set_netstack3_opaque_iids(netstack: &mut fnetemul::ChildDef, value: bool) {
903 const KEY: &str = "opaque_iids";
904 set_structured_config_value(netstack, KEY.to_owned(), cm_rust::ConfigValue::from(value));
905}
906
907pub fn set_netstack3_suspend_enabled(netstack: &mut fnetemul::ChildDef, value: bool) {
909 const KEY: &str = "suspend_enabled";
910 set_structured_config_value(netstack, KEY.to_owned(), cm_rust::ConfigValue::from(value));
911}
912
913fn set_structured_config_value(
915 component: &mut fnetemul::ChildDef,
916 key: String,
917 value: cm_rust::ConfigValue,
918) {
919 component
920 .config_values
921 .get_or_insert_default()
922 .push(fnetemul::ChildConfigValue { key, value: value.native_into_fidl() });
923}
924
925pub trait Netstack: Copy + Clone {
927 const VERSION: NetstackVersion;
929}
930
931#[derive(Copy, Clone)]
934pub enum Netstack2 {}
935
936impl Netstack for Netstack2 {
937 const VERSION: NetstackVersion = NetstackVersion::Netstack2 { tracing: false, fast_udp: false };
938}
939
940#[derive(Copy, Clone)]
943pub enum ProdNetstack2 {}
944
945impl Netstack for ProdNetstack2 {
946 const VERSION: NetstackVersion = NetstackVersion::ProdNetstack2;
947}
948
949#[derive(Copy, Clone)]
952pub enum Netstack3 {}
953
954impl Netstack for Netstack3 {
955 const VERSION: NetstackVersion = NetstackVersion::Netstack3;
956}
957
958#[derive(Copy, Clone)]
961pub enum ProdNetstack3 {}
962
963impl Netstack for ProdNetstack3 {
964 const VERSION: NetstackVersion = NetstackVersion::ProdNetstack3;
965}
966
967pub trait Manager: Copy + Clone {
969 const MANAGEMENT_AGENT: ManagementAgent;
971}
972
973#[derive(Copy, Clone)]
975pub enum NetCfgBasic {}
976
977impl Manager for NetCfgBasic {
978 const MANAGEMENT_AGENT: ManagementAgent = ManagementAgent::NetCfg(NetCfgVersion::Basic);
979}
980
981#[derive(Copy, Clone)]
984pub enum NetCfgAdvanced {}
985
986impl Manager for NetCfgAdvanced {
987 const MANAGEMENT_AGENT: ManagementAgent = ManagementAgent::NetCfg(NetCfgVersion::Advanced);
988}
989
990pub use netemul::{DhcpClient, DhcpClientVersion, InStack, OutOfStack};
991
992pub trait NetstackAndDhcpClient: Copy + Clone {
995 type Netstack: Netstack;
997 type DhcpClient: DhcpClient;
999}
1000
1001#[derive(Copy, Clone)]
1003pub enum Netstack2AndInStackDhcpClient {}
1004
1005impl NetstackAndDhcpClient for Netstack2AndInStackDhcpClient {
1006 type Netstack = Netstack2;
1007 type DhcpClient = InStack;
1008}
1009
1010#[derive(Copy, Clone)]
1012pub enum Netstack2AndOutOfStackDhcpClient {}
1013
1014impl NetstackAndDhcpClient for Netstack2AndOutOfStackDhcpClient {
1015 type Netstack = Netstack2;
1016 type DhcpClient = OutOfStack;
1017}
1018
1019#[derive(Copy, Clone)]
1021pub enum Netstack3AndOutOfStackDhcpClient {}
1022
1023impl NetstackAndDhcpClient for Netstack3AndOutOfStackDhcpClient {
1024 type Netstack = Netstack3;
1025 type DhcpClient = OutOfStack;
1026}
1027
1028pub trait TestSandboxExt {
1030 fn create_netstack_realm<'a, N, S>(&'a self, name: S) -> Result<netemul::TestRealm<'a>>
1032 where
1033 N: Netstack,
1034 S: Into<Cow<'a, str>>;
1035
1036 fn create_netstack_realm_with<'a, N, S, I>(
1039 &'a self,
1040 name: S,
1041 children: I,
1042 ) -> Result<netemul::TestRealm<'a>>
1043 where
1044 S: Into<Cow<'a, str>>,
1045 N: Netstack,
1046 I: IntoIterator,
1047 I::Item: Into<fnetemul::ChildDef>;
1048}
1049
1050impl TestSandboxExt for netemul::TestSandbox {
1051 fn create_netstack_realm<'a, N, S>(&'a self, name: S) -> Result<netemul::TestRealm<'a>>
1052 where
1053 N: Netstack,
1054 S: Into<Cow<'a, str>>,
1055 {
1056 self.create_netstack_realm_with::<N, _, _>(name, std::iter::empty::<fnetemul::ChildDef>())
1057 }
1058
1059 fn create_netstack_realm_with<'a, N, S, I>(
1060 &'a self,
1061 name: S,
1062 children: I,
1063 ) -> Result<netemul::TestRealm<'a>>
1064 where
1065 S: Into<Cow<'a, str>>,
1066 N: Netstack,
1067 I: IntoIterator,
1068 I::Item: Into<fnetemul::ChildDef>,
1069 {
1070 self.create_realm(
1071 name,
1072 [KnownServiceProvider::Netstack(N::VERSION)]
1073 .iter()
1074 .map(fnetemul::ChildDef::from)
1075 .chain(children.into_iter().map(Into::into)),
1076 )
1077 }
1078}
1079
1080pub trait TestRealmExt {
1082 fn loopback_properties(
1085 &self,
1086 ) -> impl Future<
1087 Output = Result<Option<fnet_interfaces_ext::Properties<fnet_interfaces_ext::AllInterest>>>,
1088 >;
1089
1090 fn interface_control(&self, id: u64) -> Result<fnet_interfaces_ext::admin::Control>;
1097}
1098
1099impl TestRealmExt for netemul::TestRealm<'_> {
1100 async fn loopback_properties(
1101 &self,
1102 ) -> Result<Option<fnet_interfaces_ext::Properties<fnet_interfaces_ext::AllInterest>>> {
1103 let interface_state = self
1104 .connect_to_protocol::<fnet_interfaces::StateMarker>()
1105 .context("failed to connect to fuchsia.net.interfaces/State")?;
1106
1107 let properties = fnet_interfaces_ext::existing(
1108 fnet_interfaces_ext::event_stream_from_state(&interface_state, Default::default())
1109 .expect("create watcher event stream"),
1110 HashMap::<u64, fnet_interfaces_ext::PropertiesAndState<(), _>>::new(),
1111 )
1112 .await
1113 .context("failed to get existing interface properties from watcher")?
1114 .into_iter()
1115 .find_map(|(_id, properties_and_state): (u64, _)| {
1116 let fnet_interfaces_ext::PropertiesAndState {
1117 properties: properties @ fnet_interfaces_ext::Properties { port_class, .. },
1118 state: (),
1119 } = properties_and_state;
1120 port_class.is_loopback().then_some(properties)
1121 });
1122 Ok(properties)
1123 }
1124
1125 fn interface_control(&self, id: u64) -> Result<fnet_interfaces_ext::admin::Control> {
1126 let root_control = self
1127 .connect_to_protocol::<fnet_root::InterfacesMarker>()
1128 .context("connect to protocol")?;
1129
1130 let (control, server) = fnet_interfaces_ext::admin::Control::create_endpoints()
1131 .context("create Control proxy")?;
1132 root_control.get_admin(id, server).context("get admin")?;
1133 Ok(control)
1134 }
1135}