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