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