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