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