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