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 ],
204 Self::NetCfg(NetCfgVersion::Advanced) => &[
205 fnet_dhcpv6::PrefixProviderMarker::PROTOCOL_NAME,
206 fnet_masquerade::FactoryMarker::PROTOCOL_NAME,
207 fnet_name::DnsServerWatcherMarker::PROTOCOL_NAME,
208 fnet_virtualization::ControlMarker::PROTOCOL_NAME,
209 fnp_properties::NetworksMarker::PROTOCOL_NAME,
210 fnp_socketproxy::NetworkRegistryMarker::PROTOCOL_NAME,
211 fnp_properties::NetworkTokenResolverMarker::PROTOCOL_NAME,
212 ],
213 }
214 }
215}
216
217#[derive(Clone, Eq, PartialEq, Debug)]
219#[allow(missing_docs)]
220pub enum ManagerConfig {
221 Empty,
222 Dhcpv6,
223 Forwarding,
224 AllDelegated,
225 IfacePrefix,
226 DuplicateNames,
227 EnableSocketProxy,
228 EnableSocketProxyAllDelegated,
229 PacketFilterEthernet,
230 PacketFilterWlan,
231 WithBlackhole,
232 AllInterfaceLocalDelegated,
233}
234
235impl ManagerConfig {
236 fn as_str(&self) -> &'static str {
237 match self {
238 ManagerConfig::Empty => "/pkg/netcfg/empty.json",
239 ManagerConfig::Dhcpv6 => "/pkg/netcfg/dhcpv6.json",
240 ManagerConfig::Forwarding => "/pkg/netcfg/forwarding.json",
241 ManagerConfig::AllDelegated => "/pkg/netcfg/all_delegated.json",
242 ManagerConfig::IfacePrefix => "/pkg/netcfg/iface_prefix.json",
243 ManagerConfig::DuplicateNames => "/pkg/netcfg/duplicate_names.json",
244 ManagerConfig::EnableSocketProxy => "/pkg/netcfg/enable_socket_proxy.json",
245 ManagerConfig::EnableSocketProxyAllDelegated => {
246 "/pkg/netcfg/enable_socket_proxy_all_delegated.json"
247 }
248 ManagerConfig::PacketFilterEthernet => "/pkg/netcfg/packet_filter_ethernet.json",
249 ManagerConfig::PacketFilterWlan => "/pkg/netcfg/packet_filter_wlan.json",
250 ManagerConfig::WithBlackhole => "/pkg/netcfg/with_blackhole.json",
251 ManagerConfig::AllInterfaceLocalDelegated => {
252 "/pkg/netcfg/all_interface_local_delegated.json"
253 }
254 }
255 }
256}
257
258#[derive(Copy, Clone, Default, Eq, PartialEq, Debug)]
259pub enum SocketProxyType {
261 #[default]
262 None,
264 Real,
266 Fake,
268}
269
270impl SocketProxyType {
271 pub fn known_service_provider(&self) -> Option<KnownServiceProvider> {
273 match self {
274 SocketProxyType::None => None,
275 SocketProxyType::Real => Some(KnownServiceProvider::SocketProxy),
276 SocketProxyType::Fake => Some(KnownServiceProvider::FakeSocketProxy),
277 }
278 }
279
280 fn component_name(&self) -> Option<&'static str> {
281 match self {
282 SocketProxyType::None => None,
283 SocketProxyType::Real => Some(constants::socket_proxy::COMPONENT_NAME),
284 SocketProxyType::Fake => Some(constants::fake_socket_proxy::COMPONENT_NAME),
285 }
286 }
287}
288
289#[derive(Clone, Eq, PartialEq, Debug)]
291#[allow(missing_docs)]
292pub enum KnownServiceProvider {
293 Netstack(NetstackVersion),
294 Manager {
295 agent: ManagementAgent,
296 config: ManagerConfig,
297 use_dhcp_server: bool,
298 use_out_of_stack_dhcp_client: bool,
299 socket_proxy_type: SocketProxyType,
300 },
301 SecureStash,
302 DhcpServer {
303 persistent: bool,
304 },
305 DhcpClient,
306 Dhcpv6Client,
307 DnsResolver,
308 Reachability {
309 eager: bool,
310 },
311 SocketProxy,
312 NetworkTestRealm {
313 require_outer_netstack: bool,
314 },
315 FakeClock,
316 FakeSocketProxy,
317 FakeNetcfg,
318}
319
320#[allow(missing_docs)]
323pub mod constants {
324 pub mod netstack {
325 pub const COMPONENT_NAME: &str = "netstack";
326 }
327 pub mod netcfg {
328 pub const COMPONENT_NAME: &str = "netcfg";
329 pub mod basic {
330 pub const COMPONENT_URL: &str = "#meta/netcfg-basic.cm";
331 }
332 pub mod advanced {
333 pub const COMPONENT_URL: &str = "#meta/netcfg-advanced.cm";
334 }
335 pub mod fake {
336 pub const COMPONENT_URL: &str = "#meta/fake_netcfg.cm";
337 }
338 pub const DEV_CLASS_NETWORK: &str = "dev-class-network";
341 pub const CLASS_NETWORK_PATH: &str = "class/network";
342 }
343 pub mod socket_proxy {
344 pub const COMPONENT_NAME: &str = "network-socket-proxy";
345 pub const COMPONENT_URL: &str = "#meta/network-socket-proxy.cm";
346 }
347 pub mod secure_stash {
348 pub const COMPONENT_NAME: &str = "stash_secure";
349 pub const COMPONENT_URL: &str = "#meta/stash_secure.cm";
350 }
351 pub mod dhcp_server {
352 pub const COMPONENT_NAME: &str = "dhcpd";
353 pub const COMPONENT_URL: &str = "#meta/dhcpv4_server.cm";
354 }
355 pub mod dhcp_client {
356 pub const COMPONENT_NAME: &str = "dhcp-client";
357 pub const COMPONENT_URL: &str = "#meta/dhcp-client.cm";
358 }
359 pub mod dhcpv6_client {
360 pub const COMPONENT_NAME: &str = "dhcpv6-client";
361 pub const COMPONENT_URL: &str = "#meta/dhcpv6-client.cm";
362 }
363 pub mod dns_resolver {
364 pub const COMPONENT_NAME: &str = "dns_resolver";
365 pub const COMPONENT_URL: &str = "#meta/dns_resolver_with_fake_time.cm";
366 }
367 pub mod reachability {
368 pub const COMPONENT_NAME: &str = "reachability";
369 pub const COMPONENT_URL: &str = "#meta/reachability_with_fake_time.cm";
370 }
371 pub mod network_test_realm {
372 pub const COMPONENT_NAME: &str = "controller";
373 pub const COMPONENT_URL: &str = "#meta/controller.cm";
374 }
375 pub mod fake_clock {
376 pub const COMPONENT_NAME: &str = "fake_clock";
377 pub const COMPONENT_URL: &str = "#meta/fake_clock.cm";
378 }
379 pub mod fake_socket_proxy {
380 pub const COMPONENT_NAME: &str = "fake_socket_proxy";
381 pub const COMPONENT_URL: &str = "#meta/fake_socket_proxy.cm";
382 }
383}
384
385fn protocol_dep<P>(component_name: &'static str) -> fnetemul::ChildDep
386where
387 P: fidl::endpoints::DiscoverableProtocolMarker,
388{
389 fnetemul::ChildDep {
390 name: Some(component_name.into()),
391 capability: Some(fnetemul::ExposedCapability::Protocol(P::PROTOCOL_NAME.to_string())),
392 ..Default::default()
393 }
394}
395
396fn or_void_protocol_dep<P>(
397 component_name: &'static str,
398 is_child_present: bool,
399) -> fnetemul::ChildDep
400where
401 P: fidl::endpoints::DiscoverableProtocolMarker,
402{
403 if is_child_present { protocol_dep::<P>(component_name) } else { void_protocol_dep::<P>() }
404}
405
406fn void_protocol_dep<P>() -> fnetemul::ChildDep
407where
408 P: fidl::endpoints::DiscoverableProtocolMarker,
409{
410 fnetemul::ChildDep {
411 name: None,
412 capability: Some(fnetemul::ExposedCapability::Protocol(P::PROTOCOL_NAME.to_string())),
413 ..Default::default()
414 }
415}
416
417impl From<KnownServiceProvider> for fnetemul::ChildDef {
418 fn from(s: KnownServiceProvider) -> Self {
419 (&s).into()
420 }
421}
422
423impl<'a> From<&'a KnownServiceProvider> for fnetemul::ChildDef {
424 fn from(s: &'a KnownServiceProvider) -> Self {
425 match s {
426 KnownServiceProvider::Netstack(version) => fnetemul::ChildDef {
427 name: Some(constants::netstack::COMPONENT_NAME.to_string()),
428 source: Some(fnetemul::ChildSource::Component(version.get_url().to_string())),
429 exposes: Some(
430 version.get_services().iter().map(|service| service.to_string()).collect(),
431 ),
432 uses: {
433 let mut uses = vec![fnetemul::Capability::LogSink(fnetemul::Empty {})];
434 match version {
435 NetstackVersion::Netstack2 { tracing: false, fast_udp: _ } => {}
442 NetstackVersion::Netstack2 { tracing: true, fast_udp: _ } => {
443 uses.push(fnetemul::Capability::TracingProvider(fnetemul::Empty));
444 }
445 NetstackVersion::ProdNetstack2 => {
446 uses.push(fnetemul::Capability::ChildDep(protocol_dep::<
447 fstash::SecureStoreMarker,
448 >(
449 constants::secure_stash::COMPONENT_NAME,
450 )));
451 }
452 NetstackVersion::Netstack3 | NetstackVersion::ProdNetstack3 => {
453 uses.push(fnetemul::Capability::TracingProvider(fnetemul::Empty));
454 uses.push(fnetemul::Capability::StorageDep(fnetemul::StorageDep {
455 variant: Some(fnetemul::StorageVariant::Data),
456 path: Some("/data".to_string()),
457 ..Default::default()
458 }));
459 }
460 }
461 Some(fnetemul::ChildUses::Capabilities(uses))
462 },
463 ..Default::default()
464 },
465 KnownServiceProvider::Manager {
466 agent,
467 use_dhcp_server,
468 config,
469 use_out_of_stack_dhcp_client,
470 socket_proxy_type,
471 } => {
472 let enable_dhcpv6 = match config {
473 ManagerConfig::Dhcpv6 => true,
474 ManagerConfig::Forwarding
475 | ManagerConfig::Empty
476 | ManagerConfig::AllDelegated
477 | ManagerConfig::IfacePrefix
478 | ManagerConfig::DuplicateNames
479 | ManagerConfig::EnableSocketProxy
480 | ManagerConfig::EnableSocketProxyAllDelegated
481 | ManagerConfig::PacketFilterEthernet
482 | ManagerConfig::PacketFilterWlan
483 | ManagerConfig::WithBlackhole
484 | ManagerConfig::AllInterfaceLocalDelegated => false,
485 };
486
487 fnetemul::ChildDef {
488 name: Some(constants::netcfg::COMPONENT_NAME.to_string()),
489 source: Some(fnetemul::ChildSource::Component(agent.get_url().to_string())),
490 program_args: Some(
491 agent
492 .get_program_args()
493 .iter()
494 .cloned()
495 .chain(std::iter::once("--config-data"))
496 .chain(std::iter::once(config.as_str()))
497 .map(Into::into)
498 .collect(),
499 ),
500 exposes: Some(
501 agent.get_services().iter().map(|service| service.to_string()).collect(),
502 ),
503 uses: Some(fnetemul::ChildUses::Capabilities(
504 std::iter::once(fnetemul::Capability::ChildDep(or_void_protocol_dep::<
505 fnet_dhcp::Server_Marker,
506 >(
507 constants::dhcp_server::COMPONENT_NAME,
508 *use_dhcp_server,
509 )))
510 .chain(std::iter::once(fnetemul::Capability::ChildDep(
511 or_void_protocol_dep::<fnet_dhcpv6::ClientProviderMarker>(
512 constants::dhcpv6_client::COMPONENT_NAME,
513 enable_dhcpv6,
514 ),
515 )))
516 .chain(std::iter::once(fnetemul::Capability::ChildDep(
517 or_void_protocol_dep::<fnet_dhcp::ClientProviderMarker>(
518 constants::dhcp_client::COMPONENT_NAME,
519 *use_out_of_stack_dhcp_client,
520 ),
521 )))
522 .chain(
523 socket_proxy_type
524 .component_name()
525 .map(|component_name| {
526 [
527 fnetemul::Capability::ChildDep(protocol_dep::<
528 fnp_socketproxy::FuchsiaNetworksMarker,
529 >(
530 component_name
531 )),
532 fnetemul::Capability::ChildDep(protocol_dep::<
533 fnp_socketproxy::NetworkRegistryMarker,
534 >(
535 component_name
536 )),
537 ]
538 })
539 .into_iter()
540 .flatten(),
541 )
542 .chain(
543 [
544 fnetemul::Capability::LogSink(fnetemul::Empty {}),
545 fnetemul::Capability::ChildDep(fnetemul::ChildDep {
546 dynamically_offer_from_void: Some(true),
547 ..protocol_dep::<fnet_filter::ControlMarker>(
548 constants::netstack::COMPONENT_NAME,
549 )
550 }),
551 fnetemul::Capability::ChildDep(fnetemul::ChildDep {
552 dynamically_offer_from_void: Some(true),
553 ..protocol_dep::<fnet_filter_deprecated::FilterMarker>(
554 constants::netstack::COMPONENT_NAME,
555 )
556 }),
557 fnetemul::Capability::ChildDep(protocol_dep::<
558 fnet_interfaces::StateMarker,
559 >(
560 constants::netstack::COMPONENT_NAME,
561 )),
562 fnetemul::Capability::ChildDep(protocol_dep::<
563 fnet_interfaces_admin::InstallerMarker,
564 >(
565 constants::netstack::COMPONENT_NAME,
566 )),
567 fnetemul::Capability::ChildDep(protocol_dep::<
568 fnet_stack::StackMarker,
569 >(
570 constants::netstack::COMPONENT_NAME,
571 )),
572 fnetemul::Capability::ChildDep(protocol_dep::<
573 fnet_routes_admin::RouteTableV4Marker,
574 >(
575 constants::netstack::COMPONENT_NAME,
576 )),
577 fnetemul::Capability::ChildDep(protocol_dep::<
578 fnet_routes_admin::RouteTableV6Marker,
579 >(
580 constants::netstack::COMPONENT_NAME,
581 )),
582 fnetemul::Capability::ChildDep(protocol_dep::<
583 fnet_routes_admin::RuleTableV4Marker,
584 >(
585 constants::netstack::COMPONENT_NAME,
586 )),
587 fnetemul::Capability::ChildDep(protocol_dep::<
588 fnet_routes_admin::RuleTableV6Marker,
589 >(
590 constants::netstack::COMPONENT_NAME,
591 )),
592 fnetemul::Capability::ChildDep(protocol_dep::<
593 fnet_name::DnsServerWatcherMarker,
594 >(
595 constants::netstack::COMPONENT_NAME,
596 )),
597 fnetemul::Capability::ChildDep(protocol_dep::<
598 fnet_name::LookupAdminMarker,
599 >(
600 constants::dns_resolver::COMPONENT_NAME,
601 )),
602 fnetemul::Capability::ChildDep(protocol_dep::<
603 fnet_ndp::RouterAdvertisementOptionWatcherProviderMarker,
604 >(
605 constants::netstack::COMPONENT_NAME,
606 )),
607 fnetemul::Capability::ChildDep(fnetemul::ChildDep {
608 name: Some(
609 fnetemul::NETEMUL_SERVICES_COMPONENT_NAME.to_string(),
610 ),
611 capability: Some(fnetemul::ExposedCapability::Service(
612 fhwnet::ServiceMarker::SERVICE_NAME.to_string(),
613 )),
614 ..Default::default()
615 }),
616 fnetemul::Capability::StorageDep(fnetemul::StorageDep {
617 variant: Some(fnetemul::StorageVariant::Data),
618 path: Some("/data".to_string()),
619 ..Default::default()
620 }),
621 ]
622 .into_iter(),
623 )
624 .collect(),
625 )),
626 eager: Some(true),
627 ..Default::default()
628 }
629 }
630 KnownServiceProvider::SecureStash => fnetemul::ChildDef {
631 name: Some(constants::secure_stash::COMPONENT_NAME.to_string()),
632 source: Some(fnetemul::ChildSource::Component(
633 constants::secure_stash::COMPONENT_URL.to_string(),
634 )),
635 exposes: Some(vec![fstash::SecureStoreMarker::PROTOCOL_NAME.to_string()]),
636 uses: Some(fnetemul::ChildUses::Capabilities(vec![
637 fnetemul::Capability::LogSink(fnetemul::Empty {}),
638 fnetemul::Capability::StorageDep(fnetemul::StorageDep {
639 variant: Some(fnetemul::StorageVariant::Data),
640 path: Some("/data".to_string()),
641 ..Default::default()
642 }),
643 ])),
644 ..Default::default()
645 },
646 KnownServiceProvider::DhcpServer { persistent } => fnetemul::ChildDef {
647 name: Some(constants::dhcp_server::COMPONENT_NAME.to_string()),
648 source: Some(fnetemul::ChildSource::Component(
649 constants::dhcp_server::COMPONENT_URL.to_string(),
650 )),
651 exposes: Some(vec![fnet_dhcp::Server_Marker::PROTOCOL_NAME.to_string()]),
652 uses: Some(fnetemul::ChildUses::Capabilities(
653 [
654 fnetemul::Capability::LogSink(fnetemul::Empty {}),
655 fnetemul::Capability::ChildDep(protocol_dep::<
656 fnet_neighbor::ControllerMarker,
657 >(
658 constants::netstack::COMPONENT_NAME
659 )),
660 fnetemul::Capability::ChildDep(
661 protocol_dep::<fposix_socket::ProviderMarker>(
662 constants::netstack::COMPONENT_NAME,
663 ),
664 ),
665 fnetemul::Capability::ChildDep(protocol_dep::<
666 fposix_socket_packet::ProviderMarker,
667 >(
668 constants::netstack::COMPONENT_NAME
669 )),
670 ]
671 .into_iter()
672 .chain(persistent.then_some(fnetemul::Capability::ChildDep(protocol_dep::<
673 fstash::SecureStoreMarker,
674 >(
675 constants::secure_stash::COMPONENT_NAME,
676 ))))
677 .collect(),
678 )),
679 program_args: if *persistent {
680 Some(vec![String::from("--persistent")])
681 } else {
682 None
683 },
684 ..Default::default()
685 },
686 KnownServiceProvider::DhcpClient => fnetemul::ChildDef {
687 name: Some(constants::dhcp_client::COMPONENT_NAME.to_string()),
688 source: Some(fnetemul::ChildSource::Component(
689 constants::dhcp_client::COMPONENT_URL.to_string(),
690 )),
691 exposes: Some(vec![fnet_dhcp::ClientProviderMarker::PROTOCOL_NAME.to_string()]),
692 uses: Some(fnetemul::ChildUses::Capabilities(vec![
693 fnetemul::Capability::LogSink(fnetemul::Empty {}),
694 fnetemul::Capability::ChildDep(protocol_dep::<fposix_socket::ProviderMarker>(
695 constants::netstack::COMPONENT_NAME,
696 )),
697 fnetemul::Capability::ChildDep(protocol_dep::<
698 fposix_socket_packet::ProviderMarker,
699 >(
700 constants::netstack::COMPONENT_NAME
701 )),
702 ])),
703 program_args: None,
704 ..Default::default()
705 },
706 KnownServiceProvider::Dhcpv6Client => fnetemul::ChildDef {
707 name: Some(constants::dhcpv6_client::COMPONENT_NAME.to_string()),
708 source: Some(fnetemul::ChildSource::Component(
709 constants::dhcpv6_client::COMPONENT_URL.to_string(),
710 )),
711 exposes: Some(vec![fnet_dhcpv6::ClientProviderMarker::PROTOCOL_NAME.to_string()]),
712 uses: Some(fnetemul::ChildUses::Capabilities(vec![
713 fnetemul::Capability::LogSink(fnetemul::Empty {}),
714 fnetemul::Capability::ChildDep(protocol_dep::<fposix_socket::ProviderMarker>(
715 constants::netstack::COMPONENT_NAME,
716 )),
717 ])),
718 ..Default::default()
719 },
720 KnownServiceProvider::DnsResolver => fnetemul::ChildDef {
721 name: Some(constants::dns_resolver::COMPONENT_NAME.to_string()),
722 source: Some(fnetemul::ChildSource::Component(
723 constants::dns_resolver::COMPONENT_URL.to_string(),
724 )),
725 exposes: Some(vec![
726 fnet_name::LookupAdminMarker::PROTOCOL_NAME.to_string(),
727 fnet_name::LookupMarker::PROTOCOL_NAME.to_string(),
728 ]),
729 uses: Some(fnetemul::ChildUses::Capabilities(vec![
730 fnetemul::Capability::LogSink(fnetemul::Empty {}),
731 fnetemul::Capability::ChildDep(protocol_dep::<fnet_routes::StateMarker>(
732 constants::netstack::COMPONENT_NAME,
733 )),
734 fnetemul::Capability::ChildDep(protocol_dep::<fposix_socket::ProviderMarker>(
735 constants::netstack::COMPONENT_NAME,
736 )),
737 fnetemul::Capability::ChildDep(protocol_dep::<
738 fidl_fuchsia_testing::FakeClockMarker,
739 >(
740 constants::fake_clock::COMPONENT_NAME
741 )),
742 fnetemul::Capability::ChildDep(void_protocol_dep::<
743 fscheduler::RoleManagerMarker,
744 >()),
745 ])),
746 ..Default::default()
747 },
748 KnownServiceProvider::Reachability { eager } => fnetemul::ChildDef {
749 name: Some(constants::reachability::COMPONENT_NAME.to_string()),
750 source: Some(fnetemul::ChildSource::Component(
751 constants::reachability::COMPONENT_URL.to_string(),
752 )),
753 exposes: Some(vec![fnet_reachability::MonitorMarker::PROTOCOL_NAME.to_string()]),
754 uses: Some(fnetemul::ChildUses::Capabilities(vec![
755 fnetemul::Capability::LogSink(fnetemul::Empty {}),
756 fnetemul::Capability::ChildDep(protocol_dep::<fnet_interfaces::StateMarker>(
757 constants::netstack::COMPONENT_NAME,
758 )),
759 fnetemul::Capability::ChildDep(protocol_dep::<fposix_socket::ProviderMarker>(
760 constants::netstack::COMPONENT_NAME,
761 )),
762 fnetemul::Capability::ChildDep(protocol_dep::<fnet_name::LookupMarker>(
763 constants::dns_resolver::COMPONENT_NAME,
764 )),
765 fnetemul::Capability::ChildDep(protocol_dep::<fnet_neighbor::ViewMarker>(
766 constants::netstack::COMPONENT_NAME,
767 )),
768 fnetemul::Capability::ChildDep(protocol_dep::<fnet_debug::InterfacesMarker>(
769 constants::netstack::COMPONENT_NAME,
770 )),
771 fnetemul::Capability::ChildDep(protocol_dep::<fnet_root::InterfacesMarker>(
772 constants::netstack::COMPONENT_NAME,
773 )),
774 fnetemul::Capability::ChildDep(protocol_dep::<fnet_routes::StateV4Marker>(
775 constants::netstack::COMPONENT_NAME,
776 )),
777 fnetemul::Capability::ChildDep(protocol_dep::<fnet_routes::StateV6Marker>(
778 constants::netstack::COMPONENT_NAME,
779 )),
780 fnetemul::Capability::ChildDep(protocol_dep::<fnet_debug::DiagnosticsMarker>(
781 constants::netstack::COMPONENT_NAME,
782 )),
783 fnetemul::Capability::ChildDep(protocol_dep::<
784 fidl_fuchsia_testing::FakeClockMarker,
785 >(
786 constants::fake_clock::COMPONENT_NAME
787 )),
788 ])),
789 eager: Some(*eager),
790 ..Default::default()
791 },
792 KnownServiceProvider::SocketProxy => fnetemul::ChildDef {
793 name: Some(constants::socket_proxy::COMPONENT_NAME.to_string()),
794 source: Some(fnetemul::ChildSource::Component(
795 constants::socket_proxy::COMPONENT_URL.to_string(),
796 )),
797 exposes: Some(vec![
798 fposix_socket::ProviderMarker::PROTOCOL_NAME.to_string(),
799 fposix_socket_raw::ProviderMarker::PROTOCOL_NAME.to_string(),
800 fnp_socketproxy::StarnixNetworksMarker::PROTOCOL_NAME.to_string(),
801 fnp_socketproxy::FuchsiaNetworksMarker::PROTOCOL_NAME.to_string(),
802 ]),
803 uses: Some(fnetemul::ChildUses::Capabilities(vec![
804 fnetemul::Capability::ChildDep(protocol_dep::<fposix_socket::ProviderMarker>(
805 constants::netstack::COMPONENT_NAME,
806 )),
807 fnetemul::Capability::ChildDep(
808 protocol_dep::<fposix_socket_raw::ProviderMarker>(
809 constants::netstack::COMPONENT_NAME,
810 ),
811 ),
812 fnetemul::Capability::ChildDep(fnetemul::ChildDep {
813 is_weak: Some(true),
814 ..protocol_dep::<fnp_socketproxy::NetworkRegistryMarker>(
815 constants::netcfg::COMPONENT_NAME,
816 )
817 }),
818 ])),
819 ..Default::default()
820 },
821 KnownServiceProvider::NetworkTestRealm { require_outer_netstack } => {
822 fnetemul::ChildDef {
823 name: Some(constants::network_test_realm::COMPONENT_NAME.to_string()),
824 source: Some(fnetemul::ChildSource::Component(
825 constants::network_test_realm::COMPONENT_URL.to_string(),
826 )),
827 exposes: Some(vec![
828 fntr::ControllerMarker::PROTOCOL_NAME.to_string(),
829 fcomponent::RealmMarker::PROTOCOL_NAME.to_string(),
830 ]),
831 uses: Some(fnetemul::ChildUses::Capabilities(
832 [
833 fnetemul::Capability::LogSink(fnetemul::Empty {}),
834 fnetemul::Capability::ChildDep(fnetemul::ChildDep {
835 name: Some(fnetemul::NETEMUL_SERVICES_COMPONENT_NAME.to_string()),
836 capability: Some(fnetemul::ExposedCapability::Service(
837 fhwnet::ServiceMarker::SERVICE_NAME.to_string(),
838 )),
839 ..Default::default()
840 }),
841 ]
842 .into_iter()
843 .chain(
844 require_outer_netstack
845 .then_some([
846 fnetemul::Capability::ChildDep(protocol_dep::<
847 fnet_stack::StackMarker,
848 >(
849 constants::netstack::COMPONENT_NAME,
850 )),
851 fnetemul::Capability::ChildDep(protocol_dep::<
852 fnet_debug::InterfacesMarker,
853 >(
854 constants::netstack::COMPONENT_NAME,
855 )),
856 fnetemul::Capability::ChildDep(protocol_dep::<
857 fnet_root::InterfacesMarker,
858 >(
859 constants::netstack::COMPONENT_NAME,
860 )),
861 fnetemul::Capability::ChildDep(protocol_dep::<
862 fnet_interfaces::StateMarker,
863 >(
864 constants::netstack::COMPONENT_NAME,
865 )),
866 ])
867 .into_iter()
868 .flatten(),
869 )
870 .collect::<Vec<_>>(),
871 )),
872 ..Default::default()
873 }
874 }
875 KnownServiceProvider::FakeClock => fnetemul::ChildDef {
876 name: Some(constants::fake_clock::COMPONENT_NAME.to_string()),
877 source: Some(fnetemul::ChildSource::Component(
878 constants::fake_clock::COMPONENT_URL.to_string(),
879 )),
880 exposes: Some(vec![
881 fidl_fuchsia_testing::FakeClockMarker::PROTOCOL_NAME.to_string(),
882 fidl_fuchsia_testing::FakeClockControlMarker::PROTOCOL_NAME.to_string(),
883 ]),
884 uses: Some(fnetemul::ChildUses::Capabilities(vec![fnetemul::Capability::LogSink(
885 fnetemul::Empty {},
886 )])),
887 ..Default::default()
888 },
889 KnownServiceProvider::FakeSocketProxy => fnetemul::ChildDef {
890 name: Some(constants::fake_socket_proxy::COMPONENT_NAME.to_string()),
891 source: Some(fnetemul::ChildSource::Component(
892 constants::fake_socket_proxy::COMPONENT_URL.to_string(),
893 )),
894 exposes: Some(vec![
895 fnp_socketproxy::FuchsiaNetworksMarker::PROTOCOL_NAME.to_string(),
896 fnp_socketproxy::NetworkRegistryMarker::PROTOCOL_NAME.to_string(),
897 ]),
898 uses: Some(fnetemul::ChildUses::Capabilities(vec![
899 fnetemul::Capability::ChildDep(fnetemul::ChildDep {
900 is_weak: Some(true),
901 ..protocol_dep::<fnp_socketproxy::NetworkRegistryMarker>(
902 constants::netcfg::COMPONENT_NAME,
903 )
904 }),
905 ])),
906 ..Default::default()
907 },
908 KnownServiceProvider::FakeNetcfg => fnetemul::ChildDef {
909 name: Some(constants::netcfg::COMPONENT_NAME.to_string()),
910 source: Some(fnetemul::ChildSource::Component(
911 constants::netcfg::fake::COMPONENT_URL.to_string(),
912 )),
913 exposes: Some(vec![
914 fnp_properties::NetworksMarker::PROTOCOL_NAME.to_string(),
915 fnp_socketproxy::NetworkRegistryMarker::PROTOCOL_NAME.to_string(),
916 ]),
917 ..Default::default()
918 },
919 }
920 }
921}
922
923pub fn set_netstack3_opaque_iids(netstack: &mut fnetemul::ChildDef, value: bool) {
925 const KEY: &str = "opaque_iids";
926 set_structured_config_value(netstack, KEY.to_owned(), cm_rust::ConfigValue::from(value));
927}
928
929pub fn set_netstack3_suspend_enabled(netstack: &mut fnetemul::ChildDef, value: bool) {
931 const KEY: &str = "suspend_enabled";
932 set_structured_config_value(netstack, KEY.to_owned(), cm_rust::ConfigValue::from(value));
933}
934
935fn set_structured_config_value(
937 component: &mut fnetemul::ChildDef,
938 key: String,
939 value: cm_rust::ConfigValue,
940) {
941 component
942 .config_values
943 .get_or_insert_default()
944 .push(fnetemul::ChildConfigValue { key, value: value.native_into_fidl() });
945}
946
947pub trait Netstack: Copy + Clone {
949 const VERSION: NetstackVersion;
951}
952
953#[derive(Copy, Clone)]
956pub enum Netstack2 {}
957
958impl Netstack for Netstack2 {
959 const VERSION: NetstackVersion = NetstackVersion::Netstack2 { tracing: false, fast_udp: false };
960}
961
962#[derive(Copy, Clone)]
965pub enum ProdNetstack2 {}
966
967impl Netstack for ProdNetstack2 {
968 const VERSION: NetstackVersion = NetstackVersion::ProdNetstack2;
969}
970
971#[derive(Copy, Clone)]
974pub enum Netstack3 {}
975
976impl Netstack for Netstack3 {
977 const VERSION: NetstackVersion = NetstackVersion::Netstack3;
978}
979
980#[derive(Copy, Clone)]
983pub enum ProdNetstack3 {}
984
985impl Netstack for ProdNetstack3 {
986 const VERSION: NetstackVersion = NetstackVersion::ProdNetstack3;
987}
988
989pub trait Manager: Copy + Clone {
991 const MANAGEMENT_AGENT: ManagementAgent;
993}
994
995#[derive(Copy, Clone)]
997pub enum NetCfgBasic {}
998
999impl Manager for NetCfgBasic {
1000 const MANAGEMENT_AGENT: ManagementAgent = ManagementAgent::NetCfg(NetCfgVersion::Basic);
1001}
1002
1003#[derive(Copy, Clone)]
1006pub enum NetCfgAdvanced {}
1007
1008impl Manager for NetCfgAdvanced {
1009 const MANAGEMENT_AGENT: ManagementAgent = ManagementAgent::NetCfg(NetCfgVersion::Advanced);
1010}
1011
1012pub use netemul::{DhcpClient, DhcpClientVersion, InStack, OutOfStack};
1013
1014pub trait NetstackAndDhcpClient: Copy + Clone {
1017 type Netstack: Netstack;
1019 type DhcpClient: DhcpClient;
1021}
1022
1023#[derive(Copy, Clone)]
1025pub enum Netstack2AndInStackDhcpClient {}
1026
1027impl NetstackAndDhcpClient for Netstack2AndInStackDhcpClient {
1028 type Netstack = Netstack2;
1029 type DhcpClient = InStack;
1030}
1031
1032#[derive(Copy, Clone)]
1034pub enum Netstack2AndOutOfStackDhcpClient {}
1035
1036impl NetstackAndDhcpClient for Netstack2AndOutOfStackDhcpClient {
1037 type Netstack = Netstack2;
1038 type DhcpClient = OutOfStack;
1039}
1040
1041#[derive(Copy, Clone)]
1043pub enum Netstack3AndOutOfStackDhcpClient {}
1044
1045impl NetstackAndDhcpClient for Netstack3AndOutOfStackDhcpClient {
1046 type Netstack = Netstack3;
1047 type DhcpClient = OutOfStack;
1048}
1049
1050pub trait TestSandboxExt {
1052 fn create_netstack_realm<'a, N, S>(&'a self, name: S) -> Result<netemul::TestRealm<'a>>
1054 where
1055 N: Netstack,
1056 S: Into<Cow<'a, str>>;
1057
1058 fn create_netstack_realm_with<'a, N, S, I>(
1061 &'a self,
1062 name: S,
1063 children: I,
1064 ) -> Result<netemul::TestRealm<'a>>
1065 where
1066 S: Into<Cow<'a, str>>,
1067 N: Netstack,
1068 I: IntoIterator,
1069 I::Item: Into<fnetemul::ChildDef>;
1070}
1071
1072impl TestSandboxExt for netemul::TestSandbox {
1073 fn create_netstack_realm<'a, N, S>(&'a self, name: S) -> Result<netemul::TestRealm<'a>>
1074 where
1075 N: Netstack,
1076 S: Into<Cow<'a, str>>,
1077 {
1078 self.create_netstack_realm_with::<N, _, _>(name, std::iter::empty::<fnetemul::ChildDef>())
1079 }
1080
1081 fn create_netstack_realm_with<'a, N, S, I>(
1082 &'a self,
1083 name: S,
1084 children: I,
1085 ) -> Result<netemul::TestRealm<'a>>
1086 where
1087 S: Into<Cow<'a, str>>,
1088 N: Netstack,
1089 I: IntoIterator,
1090 I::Item: Into<fnetemul::ChildDef>,
1091 {
1092 self.create_realm(
1093 name,
1094 [KnownServiceProvider::Netstack(N::VERSION)]
1095 .iter()
1096 .map(fnetemul::ChildDef::from)
1097 .chain(children.into_iter().map(Into::into)),
1098 )
1099 }
1100}
1101
1102pub trait TestRealmExt {
1104 fn loopback_properties(
1107 &self,
1108 ) -> impl Future<
1109 Output = Result<Option<fnet_interfaces_ext::Properties<fnet_interfaces_ext::AllInterest>>>,
1110 >;
1111
1112 fn interface_control(&self, id: u64) -> Result<fnet_interfaces_ext::admin::Control>;
1119}
1120
1121impl TestRealmExt for netemul::TestRealm<'_> {
1122 async fn loopback_properties(
1123 &self,
1124 ) -> Result<Option<fnet_interfaces_ext::Properties<fnet_interfaces_ext::AllInterest>>> {
1125 let interface_state = self
1126 .connect_to_protocol::<fnet_interfaces::StateMarker>()
1127 .context("failed to connect to fuchsia.net.interfaces/State")?;
1128
1129 let properties = fnet_interfaces_ext::existing(
1130 fnet_interfaces_ext::event_stream_from_state(&interface_state, Default::default())
1131 .expect("create watcher event stream"),
1132 HashMap::<u64, fnet_interfaces_ext::PropertiesAndState<(), _>>::new(),
1133 )
1134 .await
1135 .context("failed to get existing interface properties from watcher")?
1136 .into_iter()
1137 .find_map(|(_id, properties_and_state): (u64, _)| {
1138 let fnet_interfaces_ext::PropertiesAndState {
1139 properties: properties @ fnet_interfaces_ext::Properties { port_class, .. },
1140 state: (),
1141 } = properties_and_state;
1142 port_class.is_loopback().then_some(properties)
1143 });
1144 Ok(properties)
1145 }
1146
1147 fn interface_control(&self, id: u64) -> Result<fnet_interfaces_ext::admin::Control> {
1148 let root_control = self
1149 .connect_to_protocol::<fnet_root::InterfacesMarker>()
1150 .context("connect to protocol")?;
1151
1152 let (control, server) = fnet_interfaces_ext::admin::Control::create_endpoints()
1153 .context("create Control proxy")?;
1154 root_control.get_admin(id, server).context("get admin")?;
1155 Ok(control)
1156 }
1157}