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