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