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