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