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