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_interfaces as fnet_interfaces;
20use fidl_fuchsia_net_interfaces_admin as fnet_interfaces_admin;
21use fidl_fuchsia_net_interfaces_ext as fnet_interfaces_ext;
22use fidl_fuchsia_net_masquerade as fnet_masquerade;
23use fidl_fuchsia_net_multicast_admin as fnet_multicast_admin;
24use fidl_fuchsia_net_name as fnet_name;
25use fidl_fuchsia_net_ndp as fnet_ndp;
26use fidl_fuchsia_net_neighbor as fnet_neighbor;
27use fidl_fuchsia_net_policy_properties as fnp_properties;
28use fidl_fuchsia_net_power as fnet_power;
29use fidl_fuchsia_net_reachability as fnet_reachability;
30use fidl_fuchsia_net_root as fnet_root;
31use fidl_fuchsia_net_routes as fnet_routes;
32use fidl_fuchsia_net_routes_admin as fnet_routes_admin;
33use fidl_fuchsia_net_settings as fnet_settings;
34use fidl_fuchsia_net_sockets as fnet_sockets;
35use fidl_fuchsia_net_stack as fnet_stack;
36use fidl_fuchsia_net_test_realm as fntr;
37use fidl_fuchsia_netemul as fnetemul;
38use fidl_fuchsia_posix_socket as fposix_socket;
39use fidl_fuchsia_posix_socket_packet as fposix_socket_packet;
40use fidl_fuchsia_posix_socket_raw as fposix_socket_raw;
41use fidl_fuchsia_scheduler as fscheduler;
42use fidl_fuchsia_stash as fstash;
43use fidl_fuchsia_update_verify as fupdate_verify;
44
45use anyhow::Context as _;
46
47use crate::Result;
48
49#[derive(Copy, Clone, Eq, PartialEq, Debug)]
52#[allow(missing_docs)]
53pub enum NetstackVersion {
54 Netstack3,
55 ProdNetstack3,
56}
57
58impl NetstackVersion {
59 pub fn get_url(&self) -> &'static str {
61 match self {
62 NetstackVersion::Netstack3 => "#meta/netstack3-debug.cm",
63 NetstackVersion::ProdNetstack3 => "#meta/netstack3.cm",
64 }
65 }
66
67 pub fn get_services(&self) -> &[&'static str] {
69 macro_rules! common_services_and {
70 ($($name:expr),*) => {[
71 fnet_debug::InterfacesMarker::PROTOCOL_NAME,
72 fnet_interfaces_admin::InstallerMarker::PROTOCOL_NAME,
73 fnet_interfaces::StateMarker::PROTOCOL_NAME,
74 fnet_multicast_admin::Ipv4RoutingTableControllerMarker::PROTOCOL_NAME,
75 fnet_multicast_admin::Ipv6RoutingTableControllerMarker::PROTOCOL_NAME,
76 fnet_neighbor::ControllerMarker::PROTOCOL_NAME,
77 fnet_neighbor::ViewMarker::PROTOCOL_NAME,
78 fnet_root::InterfacesMarker::PROTOCOL_NAME,
79 fnet_root::RoutesV4Marker::PROTOCOL_NAME,
80 fnet_root::RoutesV6Marker::PROTOCOL_NAME,
81 fnet_routes::StateMarker::PROTOCOL_NAME,
82 fnet_routes::StateV4Marker::PROTOCOL_NAME,
83 fnet_routes::StateV6Marker::PROTOCOL_NAME,
84 fnet_routes_admin::RouteTableProviderV4Marker::PROTOCOL_NAME,
85 fnet_routes_admin::RouteTableProviderV6Marker::PROTOCOL_NAME,
86 fnet_routes_admin::RouteTableV4Marker::PROTOCOL_NAME,
87 fnet_routes_admin::RouteTableV6Marker::PROTOCOL_NAME,
88 fnet_routes_admin::RuleTableV4Marker::PROTOCOL_NAME,
89 fnet_routes_admin::RuleTableV6Marker::PROTOCOL_NAME,
90 fnet_stack::StackMarker::PROTOCOL_NAME,
91 fposix_socket_packet::ProviderMarker::PROTOCOL_NAME,
92 fposix_socket_raw::ProviderMarker::PROTOCOL_NAME,
93 fposix_socket::ProviderMarker::PROTOCOL_NAME,
94 fnet_debug::DiagnosticsMarker::PROTOCOL_NAME,
95 fnet_debug::PacketCaptureProviderMarker::PROTOCOL_NAME,
96
97 fupdate_verify::ComponentOtaHealthCheckMarker::PROTOCOL_NAME,
98 $($name),*
99 ]};
100 ($($name:expr),*,) => {common_services_and!($($name),*)}
102 }
103 match self {
104 NetstackVersion::Netstack3 | NetstackVersion::ProdNetstack3 => &common_services_and!(
105 fnet_filter::ControlMarker::PROTOCOL_NAME,
106 fnet_filter::StateMarker::PROTOCOL_NAME,
107 fnet_ndp::RouterAdvertisementOptionWatcherProviderMarker::PROTOCOL_NAME,
108 fnet_power::WakeGroupProviderMarker::PROTOCOL_NAME,
109 fnet_root::FilterMarker::PROTOCOL_NAME,
110 fnet_settings::StateMarker::PROTOCOL_NAME,
111 fnet_settings::ControlMarker::PROTOCOL_NAME,
112 fnet_sockets::DiagnosticsMarker::PROTOCOL_NAME,
113 fnet_sockets::ControlMarker::PROTOCOL_NAME,
114 ),
115 }
116 }
117}
118
119#[derive(Clone, Eq, PartialEq, Debug)]
121#[allow(missing_docs)]
122pub enum ManagerConfig {
123 Empty,
124 Dhcpv6,
125 Forwarding,
126 AllDelegated,
127 IfacePrefix,
128 DuplicateNames,
129 EnableSocketProxy,
130 EnableSocketProxyAllDelegated,
131 PacketFilterEthernet,
132 PacketFilterWlan,
133 WithBlackhole,
134 AllInterfaceLocalDelegated,
135}
136
137impl ManagerConfig {
138 fn as_str(&self) -> &'static str {
139 match self {
140 ManagerConfig::Empty => "/pkg/netcfg/empty.json",
141 ManagerConfig::Dhcpv6 => "/pkg/netcfg/dhcpv6.json",
142 ManagerConfig::Forwarding => "/pkg/netcfg/forwarding.json",
143 ManagerConfig::AllDelegated => "/pkg/netcfg/all_delegated.json",
144 ManagerConfig::IfacePrefix => "/pkg/netcfg/iface_prefix.json",
145 ManagerConfig::DuplicateNames => "/pkg/netcfg/duplicate_names.json",
146 ManagerConfig::EnableSocketProxy => "/pkg/netcfg/enable_socket_proxy.json",
147 ManagerConfig::EnableSocketProxyAllDelegated => {
148 "/pkg/netcfg/enable_socket_proxy_all_delegated.json"
149 }
150 ManagerConfig::PacketFilterEthernet => "/pkg/netcfg/packet_filter_ethernet.json",
151 ManagerConfig::PacketFilterWlan => "/pkg/netcfg/packet_filter_wlan.json",
152 ManagerConfig::WithBlackhole => "/pkg/netcfg/with_blackhole.json",
153 ManagerConfig::AllInterfaceLocalDelegated => {
154 "/pkg/netcfg/all_interface_local_delegated.json"
155 }
156 }
157 }
158}
159
160#[derive(Copy, Clone, Default, Eq, PartialEq, Debug)]
161pub enum SocketProxyType {
163 #[default]
164 None,
166 Real,
168 Fake,
170}
171
172impl SocketProxyType {
173 pub fn known_service_provider(&self) -> Option<KnownServiceProvider> {
175 match self {
176 SocketProxyType::None => None,
177 SocketProxyType::Real => Some(KnownServiceProvider::SocketProxy),
178 SocketProxyType::Fake => Some(KnownServiceProvider::FakeSocketProxy),
179 }
180 }
181}
182
183#[derive(Clone, Eq, PartialEq, Debug)]
185#[allow(missing_docs)]
186pub enum KnownServiceProvider {
187 Netstack(NetstackVersion),
188 Manager { config: ManagerConfig, use_dhcp_server: bool, socket_proxy_type: SocketProxyType },
189 SecureStash,
190 DhcpServer { persistent: bool },
191 DhcpClient,
192 Dhcpv6Client,
193 DnsResolver,
194 Reachability { eager: bool },
195 SocketProxy,
196 NetworkTestRealm { require_outer_netstack: bool },
197 FakeClock,
198 FakeSocketProxy,
199 FakeNetcfg,
200}
201
202#[allow(missing_docs)]
205pub mod constants {
206 pub mod netstack {
207 pub const COMPONENT_NAME: &str = "netstack";
208 }
209 pub mod netcfg {
210 pub const COMPONENT_NAME: &str = "netcfg";
211 pub const COMPONENT_URL: &str = "#meta/netcfg.cm";
212 pub mod fake {
213 pub const COMPONENT_URL: &str = "#meta/fake_netcfg.cm";
214 }
215 pub const DEV_CLASS_NETWORK: &str = "dev-class-network";
218 pub const CLASS_NETWORK_PATH: &str = "class/network";
219 }
220 pub mod socket_proxy {
221 pub const COMPONENT_NAME: &str = "network-socket-proxy";
222 pub const COMPONENT_URL: &str = "#meta/network-socket-proxy.cm";
223 }
224 pub mod secure_stash {
225 pub const COMPONENT_NAME: &str = "stash_secure";
226 pub const COMPONENT_URL: &str = "#meta/stash_secure.cm";
227 }
228 pub mod dhcp_server {
229 pub const COMPONENT_NAME: &str = "dhcpd";
230 pub const COMPONENT_URL: &str = "#meta/dhcpv4_server.cm";
231 }
232 pub mod dhcp_client {
233 pub const COMPONENT_NAME: &str = "dhcp-client";
234 pub const COMPONENT_URL: &str = "#meta/dhcp-client.cm";
235 }
236 pub mod dhcpv6_client {
237 pub const COMPONENT_NAME: &str = "dhcpv6-client";
238 pub const COMPONENT_URL: &str = "#meta/dhcpv6-client.cm";
239 }
240 pub mod dns_resolver {
241 pub const COMPONENT_NAME: &str = "dns_resolver";
242 pub const COMPONENT_URL: &str = "#meta/dns_resolver_with_fake_time.cm";
243 }
244 pub mod reachability {
245 pub const COMPONENT_NAME: &str = "reachability";
246 pub const COMPONENT_URL: &str = "#meta/reachability_with_fake_time.cm";
247 }
248 pub mod network_test_realm {
249 pub const COMPONENT_NAME: &str = "controller";
250 pub const COMPONENT_URL: &str = "#meta/controller.cm";
251 }
252 pub mod fake_clock {
253 pub const COMPONENT_NAME: &str = "fake_clock";
254 pub const COMPONENT_URL: &str = "#meta/fake_clock.cm";
255 }
256 pub mod fake_socket_proxy {
257 pub const COMPONENT_NAME: &str = "fake_socket_proxy";
258 pub const COMPONENT_URL: &str = "#meta/fake_socket_proxy.cm";
259 }
260}
261
262fn protocol_dep<P>(component_name: &'static str) -> fnetemul::ChildDep
263where
264 P: fidl::endpoints::DiscoverableProtocolMarker,
265{
266 fnetemul::ChildDep {
267 name: Some(component_name.into()),
268 capability: Some(fnetemul::ExposedCapability::Protocol(P::PROTOCOL_NAME.to_string())),
269 ..Default::default()
270 }
271}
272
273fn or_void_protocol_dep<P>(
274 component_name: &'static str,
275 is_child_present: bool,
276) -> fnetemul::ChildDep
277where
278 P: fidl::endpoints::DiscoverableProtocolMarker,
279{
280 if is_child_present { protocol_dep::<P>(component_name) } else { void_protocol_dep::<P>() }
281}
282
283fn void_protocol_dep<P>() -> fnetemul::ChildDep
284where
285 P: fidl::endpoints::DiscoverableProtocolMarker,
286{
287 fnetemul::ChildDep {
288 name: None,
289 capability: Some(fnetemul::ExposedCapability::Protocol(P::PROTOCOL_NAME.to_string())),
290 ..Default::default()
291 }
292}
293
294impl From<KnownServiceProvider> for fnetemul::ChildDef {
295 fn from(s: KnownServiceProvider) -> Self {
296 (&s).into()
297 }
298}
299
300impl<'a> From<&'a KnownServiceProvider> for fnetemul::ChildDef {
301 fn from(s: &'a KnownServiceProvider) -> Self {
302 match s {
303 KnownServiceProvider::Netstack(version) => fnetemul::ChildDef {
304 name: Some(constants::netstack::COMPONENT_NAME.to_string()),
305 source: Some(fnetemul::ChildSource::Component(version.get_url().to_string())),
306 exposes: Some(
307 version.get_services().iter().map(|service| service.to_string()).collect(),
308 ),
309 uses: {
310 let uses = vec![
311 fnetemul::Capability::LogSink(fnetemul::Empty {}),
312 fnetemul::Capability::TracingProvider(fnetemul::Empty),
313 fnetemul::Capability::StorageDep(fnetemul::StorageDep {
314 variant: Some(fnetemul::StorageVariant::Data),
315 path: Some("/data".to_string()),
316 ..Default::default()
317 }),
318 ];
319 Some(fnetemul::ChildUses::Capabilities(uses))
320 },
321 ..Default::default()
322 },
323 KnownServiceProvider::Manager { use_dhcp_server, config, socket_proxy_type: _ } => {
324 let enable_dhcpv6 = match config {
325 ManagerConfig::Dhcpv6 => true,
326 ManagerConfig::Forwarding
327 | ManagerConfig::Empty
328 | ManagerConfig::AllDelegated
329 | ManagerConfig::IfacePrefix
330 | ManagerConfig::DuplicateNames
331 | ManagerConfig::EnableSocketProxy
332 | ManagerConfig::EnableSocketProxyAllDelegated
333 | ManagerConfig::PacketFilterEthernet
334 | ManagerConfig::PacketFilterWlan
335 | ManagerConfig::WithBlackhole
336 | ManagerConfig::AllInterfaceLocalDelegated => false,
337 };
338
339 fnetemul::ChildDef {
340 name: Some(constants::netcfg::COMPONENT_NAME.to_string()),
341 source: Some(fnetemul::ChildSource::Component(
342 constants::netcfg::COMPONENT_URL.to_string(),
343 )),
344 program_args: Some(
345 ["--min-severity", "DEBUG", "--config-data", config.as_str()]
346 .into_iter()
347 .map(Into::into)
348 .collect(),
349 ),
350 exposes: Some(
351 [
352 fnet_dhcpv6::PrefixProviderMarker::PROTOCOL_NAME,
353 fnet_masquerade::FactoryMarker::PROTOCOL_NAME,
354 fnet_name::DnsServerWatcherMarker::PROTOCOL_NAME,
355 fnp_properties::NetworksMarker::PROTOCOL_NAME,
356 fnp_properties::NetworkRegistryMarker::PROTOCOL_NAME,
357 fnp_properties::NetworkTokenResolverMarker::PROTOCOL_NAME,
358 fnp_properties::PrivilegedNetworkLookupMarker::PROTOCOL_NAME,
359 fnet_reachability::MonitorMarker::PROTOCOL_NAME,
360 ]
361 .into_iter()
362 .map(|service| service.to_string())
363 .collect(),
364 ),
365 uses: Some(fnetemul::ChildUses::Capabilities(
366 std::iter::once(fnetemul::Capability::ChildDep(or_void_protocol_dep::<
367 fnet_dhcp::Server_Marker,
368 >(
369 constants::dhcp_server::COMPONENT_NAME,
370 *use_dhcp_server,
371 )))
372 .chain(std::iter::once(fnetemul::Capability::ChildDep(
373 or_void_protocol_dep::<fnet_dhcpv6::ClientProviderMarker>(
374 constants::dhcpv6_client::COMPONENT_NAME,
375 enable_dhcpv6,
376 ),
377 )))
378 .chain(
379 [
380 fnetemul::Capability::LogSink(fnetemul::Empty {}),
381 fnetemul::Capability::ChildDep(protocol_dep::<
382 fnet_dhcp::ClientProviderMarker,
383 >(
384 constants::dhcp_client::COMPONENT_NAME,
385 )),
386 fnetemul::Capability::ChildDep(protocol_dep::<
387 fnet_filter::ControlMarker,
388 >(
389 constants::netstack::COMPONENT_NAME,
390 )),
391 fnetemul::Capability::ChildDep(protocol_dep::<
392 fnet_interfaces::StateMarker,
393 >(
394 constants::netstack::COMPONENT_NAME,
395 )),
396 fnetemul::Capability::ChildDep(protocol_dep::<
397 fnet_interfaces_admin::InstallerMarker,
398 >(
399 constants::netstack::COMPONENT_NAME,
400 )),
401 fnetemul::Capability::ChildDep(protocol_dep::<
402 fnet_routes_admin::RouteTableV4Marker,
403 >(
404 constants::netstack::COMPONENT_NAME,
405 )),
406 fnetemul::Capability::ChildDep(protocol_dep::<
407 fnet_routes_admin::RouteTableV6Marker,
408 >(
409 constants::netstack::COMPONENT_NAME,
410 )),
411 fnetemul::Capability::ChildDep(protocol_dep::<
412 fnet_routes_admin::RuleTableV4Marker,
413 >(
414 constants::netstack::COMPONENT_NAME,
415 )),
416 fnetemul::Capability::ChildDep(protocol_dep::<
417 fnet_routes_admin::RuleTableV6Marker,
418 >(
419 constants::netstack::COMPONENT_NAME,
420 )),
421 fnetemul::Capability::ChildDep(protocol_dep::<
422 fnet_name::LookupAdminMarker,
423 >(
424 constants::dns_resolver::COMPONENT_NAME,
425 )),
426 fnetemul::Capability::ChildDep(protocol_dep::<
427 fnet_ndp::RouterAdvertisementOptionWatcherProviderMarker,
428 >(
429 constants::netstack::COMPONENT_NAME,
430 )),
431 fnetemul::Capability::ChildDep(fnetemul::ChildDep {
432 name: Some(
433 fnetemul::NETEMUL_SERVICES_COMPONENT_NAME.to_string(),
434 ),
435 capability: Some(fnetemul::ExposedCapability::Service(
436 fhwnet::ServiceMarker::SERVICE_NAME.to_string(),
437 )),
438 ..Default::default()
439 }),
440 fnetemul::Capability::StorageDep(fnetemul::StorageDep {
441 variant: Some(fnetemul::StorageVariant::Data),
442 path: Some("/data".to_string()),
443 ..Default::default()
444 }),
445 ]
446 .into_iter(),
447 )
448 .collect(),
449 )),
450 eager: Some(true),
451 ..Default::default()
452 }
453 }
454 KnownServiceProvider::SecureStash => fnetemul::ChildDef {
455 name: Some(constants::secure_stash::COMPONENT_NAME.to_string()),
456 source: Some(fnetemul::ChildSource::Component(
457 constants::secure_stash::COMPONENT_URL.to_string(),
458 )),
459 exposes: Some(vec![fstash::SecureStoreMarker::PROTOCOL_NAME.to_string()]),
460 uses: Some(fnetemul::ChildUses::Capabilities(vec![
461 fnetemul::Capability::LogSink(fnetemul::Empty {}),
462 fnetemul::Capability::StorageDep(fnetemul::StorageDep {
463 variant: Some(fnetemul::StorageVariant::Data),
464 path: Some("/data".to_string()),
465 ..Default::default()
466 }),
467 ])),
468 ..Default::default()
469 },
470 KnownServiceProvider::DhcpServer { persistent } => fnetemul::ChildDef {
471 name: Some(constants::dhcp_server::COMPONENT_NAME.to_string()),
472 source: Some(fnetemul::ChildSource::Component(
473 constants::dhcp_server::COMPONENT_URL.to_string(),
474 )),
475 exposes: Some(vec![fnet_dhcp::Server_Marker::PROTOCOL_NAME.to_string()]),
476 uses: Some(fnetemul::ChildUses::Capabilities(
477 [
478 fnetemul::Capability::LogSink(fnetemul::Empty {}),
479 fnetemul::Capability::ChildDep(protocol_dep::<
480 fnet_neighbor::ControllerMarker,
481 >(
482 constants::netstack::COMPONENT_NAME
483 )),
484 fnetemul::Capability::ChildDep(
485 protocol_dep::<fposix_socket::ProviderMarker>(
486 constants::netstack::COMPONENT_NAME,
487 ),
488 ),
489 fnetemul::Capability::ChildDep(protocol_dep::<
490 fposix_socket_packet::ProviderMarker,
491 >(
492 constants::netstack::COMPONENT_NAME
493 )),
494 ]
495 .into_iter()
496 .chain(persistent.then_some(fnetemul::Capability::ChildDep(protocol_dep::<
497 fstash::SecureStoreMarker,
498 >(
499 constants::secure_stash::COMPONENT_NAME,
500 ))))
501 .collect(),
502 )),
503 program_args: if *persistent {
504 Some(vec![String::from("--persistent")])
505 } else {
506 None
507 },
508 ..Default::default()
509 },
510 KnownServiceProvider::DhcpClient => fnetemul::ChildDef {
511 name: Some(constants::dhcp_client::COMPONENT_NAME.to_string()),
512 source: Some(fnetemul::ChildSource::Component(
513 constants::dhcp_client::COMPONENT_URL.to_string(),
514 )),
515 exposes: Some(vec![fnet_dhcp::ClientProviderMarker::PROTOCOL_NAME.to_string()]),
516 uses: Some(fnetemul::ChildUses::Capabilities(vec![
517 fnetemul::Capability::LogSink(fnetemul::Empty {}),
518 fnetemul::Capability::ChildDep(protocol_dep::<fposix_socket::ProviderMarker>(
519 constants::netstack::COMPONENT_NAME,
520 )),
521 fnetemul::Capability::ChildDep(protocol_dep::<
522 fposix_socket_packet::ProviderMarker,
523 >(
524 constants::netstack::COMPONENT_NAME
525 )),
526 ])),
527 program_args: None,
528 ..Default::default()
529 },
530 KnownServiceProvider::Dhcpv6Client => fnetemul::ChildDef {
531 name: Some(constants::dhcpv6_client::COMPONENT_NAME.to_string()),
532 source: Some(fnetemul::ChildSource::Component(
533 constants::dhcpv6_client::COMPONENT_URL.to_string(),
534 )),
535 exposes: Some(vec![fnet_dhcpv6::ClientProviderMarker::PROTOCOL_NAME.to_string()]),
536 uses: Some(fnetemul::ChildUses::Capabilities(vec![
537 fnetemul::Capability::LogSink(fnetemul::Empty {}),
538 fnetemul::Capability::ChildDep(protocol_dep::<fposix_socket::ProviderMarker>(
539 constants::netstack::COMPONENT_NAME,
540 )),
541 ])),
542 ..Default::default()
543 },
544 KnownServiceProvider::DnsResolver => fnetemul::ChildDef {
545 name: Some(constants::dns_resolver::COMPONENT_NAME.to_string()),
546 source: Some(fnetemul::ChildSource::Component(
547 constants::dns_resolver::COMPONENT_URL.to_string(),
548 )),
549 exposes: Some(vec![
550 fnet_name::LookupAdminMarker::PROTOCOL_NAME.to_string(),
551 fnet_name::LookupMarker::PROTOCOL_NAME.to_string(),
552 ]),
553 uses: Some(fnetemul::ChildUses::Capabilities(vec![
554 fnetemul::Capability::LogSink(fnetemul::Empty {}),
555 fnetemul::Capability::ChildDep(protocol_dep::<fnet_routes::StateMarker>(
556 constants::netstack::COMPONENT_NAME,
557 )),
558 fnetemul::Capability::ChildDep(protocol_dep::<fposix_socket::ProviderMarker>(
559 constants::netstack::COMPONENT_NAME,
560 )),
561 fnetemul::Capability::ChildDep(protocol_dep::<
562 fidl_fuchsia_testing::FakeClockMarker,
563 >(
564 constants::fake_clock::COMPONENT_NAME
565 )),
566 fnetemul::Capability::ChildDep(void_protocol_dep::<
567 fscheduler::RoleManagerMarker,
568 >()),
569 ])),
570 ..Default::default()
571 },
572 KnownServiceProvider::Reachability { eager } => fnetemul::ChildDef {
573 name: Some(constants::reachability::COMPONENT_NAME.to_string()),
574 source: Some(fnetemul::ChildSource::Component(
575 constants::reachability::COMPONENT_URL.to_string(),
576 )),
577 exposes: Some(vec![fnet_reachability::MonitorMarker::PROTOCOL_NAME.to_string()]),
578 uses: Some(fnetemul::ChildUses::Capabilities(vec![
579 fnetemul::Capability::LogSink(fnetemul::Empty {}),
580 fnetemul::Capability::ChildDep(protocol_dep::<fnet_interfaces::StateMarker>(
581 constants::netstack::COMPONENT_NAME,
582 )),
583 fnetemul::Capability::ChildDep(protocol_dep::<fposix_socket::ProviderMarker>(
584 constants::netstack::COMPONENT_NAME,
585 )),
586 fnetemul::Capability::ChildDep(protocol_dep::<fnet_name::LookupMarker>(
587 constants::dns_resolver::COMPONENT_NAME,
588 )),
589 fnetemul::Capability::ChildDep(protocol_dep::<fnet_neighbor::ViewMarker>(
590 constants::netstack::COMPONENT_NAME,
591 )),
592 fnetemul::Capability::ChildDep(protocol_dep::<fnet_debug::InterfacesMarker>(
593 constants::netstack::COMPONENT_NAME,
594 )),
595 fnetemul::Capability::ChildDep(protocol_dep::<fnet_root::InterfacesMarker>(
596 constants::netstack::COMPONENT_NAME,
597 )),
598 fnetemul::Capability::ChildDep(protocol_dep::<fnet_routes::StateV4Marker>(
599 constants::netstack::COMPONENT_NAME,
600 )),
601 fnetemul::Capability::ChildDep(protocol_dep::<fnet_routes::StateV6Marker>(
602 constants::netstack::COMPONENT_NAME,
603 )),
604 fnetemul::Capability::ChildDep(protocol_dep::<fnet_debug::DiagnosticsMarker>(
605 constants::netstack::COMPONENT_NAME,
606 )),
607 fnetemul::Capability::ChildDep(protocol_dep::<
608 fidl_fuchsia_testing::FakeClockMarker,
609 >(
610 constants::fake_clock::COMPONENT_NAME
611 )),
612 ])),
613 eager: Some(*eager),
614 ..Default::default()
615 },
616 KnownServiceProvider::SocketProxy => fnetemul::ChildDef {
617 name: Some(constants::socket_proxy::COMPONENT_NAME.to_string()),
618 source: Some(fnetemul::ChildSource::Component(
619 constants::socket_proxy::COMPONENT_URL.to_string(),
620 )),
621 exposes: Some(vec![
622 fposix_socket::ProviderMarker::PROTOCOL_NAME.to_string(),
623 fposix_socket_raw::ProviderMarker::PROTOCOL_NAME.to_string(),
624 ]),
625 uses: Some(fnetemul::ChildUses::Capabilities(vec![
626 fnetemul::Capability::ChildDep(protocol_dep::<fposix_socket::ProviderMarker>(
627 constants::netstack::COMPONENT_NAME,
628 )),
629 fnetemul::Capability::ChildDep(
630 protocol_dep::<fposix_socket_raw::ProviderMarker>(
631 constants::netstack::COMPONENT_NAME,
632 ),
633 ),
634 fnetemul::Capability::ChildDep(fnetemul::ChildDep {
635 is_weak: Some(true),
636 ..protocol_dep::<fnp_properties::NetworksMarker>(
637 constants::netcfg::COMPONENT_NAME,
638 )
639 }),
640 ])),
641 ..Default::default()
642 },
643 KnownServiceProvider::NetworkTestRealm { require_outer_netstack } => {
644 fnetemul::ChildDef {
645 name: Some(constants::network_test_realm::COMPONENT_NAME.to_string()),
646 source: Some(fnetemul::ChildSource::Component(
647 constants::network_test_realm::COMPONENT_URL.to_string(),
648 )),
649 exposes: Some(vec![
650 fntr::ControllerMarker::PROTOCOL_NAME.to_string(),
651 fcomponent::RealmMarker::PROTOCOL_NAME.to_string(),
652 ]),
653 uses: Some(fnetemul::ChildUses::Capabilities(
654 [
655 fnetemul::Capability::LogSink(fnetemul::Empty {}),
656 fnetemul::Capability::ChildDep(fnetemul::ChildDep {
657 name: Some(fnetemul::NETEMUL_SERVICES_COMPONENT_NAME.to_string()),
658 capability: Some(fnetemul::ExposedCapability::Service(
659 fhwnet::ServiceMarker::SERVICE_NAME.to_string(),
660 )),
661 ..Default::default()
662 }),
663 ]
664 .into_iter()
665 .chain(
666 require_outer_netstack
667 .then_some([
668 fnetemul::Capability::ChildDep(protocol_dep::<
669 fnet_stack::StackMarker,
670 >(
671 constants::netstack::COMPONENT_NAME,
672 )),
673 fnetemul::Capability::ChildDep(protocol_dep::<
674 fnet_debug::InterfacesMarker,
675 >(
676 constants::netstack::COMPONENT_NAME,
677 )),
678 fnetemul::Capability::ChildDep(protocol_dep::<
679 fnet_root::InterfacesMarker,
680 >(
681 constants::netstack::COMPONENT_NAME,
682 )),
683 fnetemul::Capability::ChildDep(protocol_dep::<
684 fnet_interfaces::StateMarker,
685 >(
686 constants::netstack::COMPONENT_NAME,
687 )),
688 ])
689 .into_iter()
690 .flatten(),
691 )
692 .collect::<Vec<_>>(),
693 )),
694 ..Default::default()
695 }
696 }
697 KnownServiceProvider::FakeClock => fnetemul::ChildDef {
698 name: Some(constants::fake_clock::COMPONENT_NAME.to_string()),
699 source: Some(fnetemul::ChildSource::Component(
700 constants::fake_clock::COMPONENT_URL.to_string(),
701 )),
702 exposes: Some(vec![
703 fidl_fuchsia_testing::FakeClockMarker::PROTOCOL_NAME.to_string(),
704 fidl_fuchsia_testing::FakeClockControlMarker::PROTOCOL_NAME.to_string(),
705 ]),
706 uses: Some(fnetemul::ChildUses::Capabilities(vec![fnetemul::Capability::LogSink(
707 fnetemul::Empty {},
708 )])),
709 ..Default::default()
710 },
711 KnownServiceProvider::FakeSocketProxy => fnetemul::ChildDef {
712 name: Some(constants::fake_socket_proxy::COMPONENT_NAME.to_string()),
713 source: Some(fnetemul::ChildSource::Component(
714 constants::fake_socket_proxy::COMPONENT_URL.to_string(),
715 )),
716 exposes: Some(vec![
717 fnp_properties::NetworkRegistryMarker::PROTOCOL_NAME.to_string(),
718 ]),
719 uses: Some(fnetemul::ChildUses::Capabilities(vec![
720 fnetemul::Capability::ChildDep(fnetemul::ChildDep {
721 is_weak: Some(true),
722 ..protocol_dep::<fnp_properties::NetworkRegistryMarker>(
723 constants::netcfg::COMPONENT_NAME,
724 )
725 }),
726 ])),
727 ..Default::default()
728 },
729 KnownServiceProvider::FakeNetcfg => fnetemul::ChildDef {
730 name: Some(constants::netcfg::COMPONENT_NAME.to_string()),
731 source: Some(fnetemul::ChildSource::Component(
732 constants::netcfg::fake::COMPONENT_URL.to_string(),
733 )),
734 exposes: Some(vec![
735 fnp_properties::NetworksMarker::PROTOCOL_NAME.to_string(),
736 fnp_properties::NetworkRegistryMarker::PROTOCOL_NAME.to_string(),
737 ]),
738 ..Default::default()
739 },
740 }
741 }
742}
743
744pub fn set_netstack3_opaque_iids(netstack: &mut fnetemul::ChildDef, value: bool) {
746 const KEY: &str = "opaque_iids";
747 set_structured_config_value(netstack, KEY.to_owned(), cm_rust::ConfigValue::from(value));
748}
749
750pub fn set_netstack3_suspend_enabled(netstack: &mut fnetemul::ChildDef, value: bool) {
752 const KEY: &str = "suspend_enabled";
753 set_structured_config_value(netstack, KEY.to_owned(), cm_rust::ConfigValue::from(value));
754}
755
756fn set_structured_config_value(
758 component: &mut fnetemul::ChildDef,
759 key: String,
760 value: cm_rust::ConfigValue,
761) {
762 component
763 .config_values
764 .get_or_insert_default()
765 .push(fnetemul::ChildConfigValue { key, value: value.native_into_fidl() });
766}
767
768pub trait Netstack: Copy + Clone {
770 const VERSION: NetstackVersion;
772}
773
774#[derive(Copy, Clone)]
777pub enum Netstack3 {}
778
779impl Netstack for Netstack3 {
780 const VERSION: NetstackVersion = NetstackVersion::Netstack3;
781}
782
783#[derive(Copy, Clone)]
786pub enum ProdNetstack3 {}
787
788impl Netstack for ProdNetstack3 {
789 const VERSION: NetstackVersion = NetstackVersion::ProdNetstack3;
790}
791
792pub trait TestSandboxExt {
794 fn create_netstack_realm<'a, N, S>(&'a self, name: S) -> Result<netemul::TestRealm<'a>>
796 where
797 N: Netstack,
798 S: Into<Cow<'a, str>>;
799
800 fn create_netstack_realm_with<'a, N, S, I>(
803 &'a self,
804 name: S,
805 children: I,
806 ) -> Result<netemul::TestRealm<'a>>
807 where
808 S: Into<Cow<'a, str>>,
809 N: Netstack,
810 I: IntoIterator,
811 I::Item: Into<fnetemul::ChildDef>;
812}
813
814impl TestSandboxExt for netemul::TestSandbox {
815 fn create_netstack_realm<'a, N, S>(&'a self, name: S) -> Result<netemul::TestRealm<'a>>
816 where
817 N: Netstack,
818 S: Into<Cow<'a, str>>,
819 {
820 self.create_netstack_realm_with::<N, _, _>(name, std::iter::empty::<fnetemul::ChildDef>())
821 }
822
823 fn create_netstack_realm_with<'a, N, S, I>(
824 &'a self,
825 name: S,
826 children: I,
827 ) -> Result<netemul::TestRealm<'a>>
828 where
829 S: Into<Cow<'a, str>>,
830 N: Netstack,
831 I: IntoIterator,
832 I::Item: Into<fnetemul::ChildDef>,
833 {
834 self.create_realm(
835 name,
836 [KnownServiceProvider::Netstack(N::VERSION)]
837 .iter()
838 .map(fnetemul::ChildDef::from)
839 .chain(children.into_iter().map(Into::into)),
840 )
841 }
842}
843
844pub trait TestRealmExt {
846 fn loopback_properties(
849 &self,
850 ) -> impl Future<
851 Output = Result<Option<fnet_interfaces_ext::Properties<fnet_interfaces_ext::AllInterest>>>,
852 >;
853
854 fn interface_control(&self, id: u64) -> Result<fnet_interfaces_ext::admin::Control>;
861}
862
863impl TestRealmExt for netemul::TestRealm<'_> {
864 async fn loopback_properties(
865 &self,
866 ) -> Result<Option<fnet_interfaces_ext::Properties<fnet_interfaces_ext::AllInterest>>> {
867 let interface_state = self
868 .connect_to_protocol::<fnet_interfaces::StateMarker>()
869 .context("failed to connect to fuchsia.net.interfaces/State")?;
870
871 let properties = fnet_interfaces_ext::existing(
872 fnet_interfaces_ext::event_stream_from_state(&interface_state, Default::default())
873 .expect("create watcher event stream"),
874 HashMap::<u64, fnet_interfaces_ext::PropertiesAndState<(), _>>::new(),
875 )
876 .await
877 .context("failed to get existing interface properties from watcher")?
878 .into_iter()
879 .find_map(|(_id, properties_and_state): (u64, _)| {
880 let fnet_interfaces_ext::PropertiesAndState {
881 properties: properties @ fnet_interfaces_ext::Properties { port_class, .. },
882 state: (),
883 } = properties_and_state;
884 port_class.is_loopback().then_some(properties)
885 });
886 Ok(properties)
887 }
888
889 fn interface_control(&self, id: u64) -> Result<fnet_interfaces_ext::admin::Control> {
890 let root_control = self
891 .connect_to_protocol::<fnet_root::InterfacesMarker>()
892 .context("connect to protocol")?;
893
894 let (control, server) = fnet_interfaces_ext::admin::Control::create_endpoints()
895 .context("create Control proxy")?;
896 root_control.get_admin(id, server).context("get admin")?;
897 Ok(control)
898 }
899}