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
380impl From<KnownServiceProvider> for fnetemul::ChildDef {
381 fn from(s: KnownServiceProvider) -> Self {
382 (&s).into()
383 }
384}
385
386impl<'a> From<&'a KnownServiceProvider> for fnetemul::ChildDef {
387 fn from(s: &'a KnownServiceProvider) -> Self {
388 match s {
389 KnownServiceProvider::Netstack(version) => fnetemul::ChildDef {
390 name: Some(constants::netstack::COMPONENT_NAME.to_string()),
391 source: Some(fnetemul::ChildSource::Component(version.get_url().to_string())),
392 exposes: Some(
393 version.get_services().iter().map(|service| service.to_string()).collect(),
394 ),
395 uses: {
396 let mut uses = vec![fnetemul::Capability::LogSink(fnetemul::Empty {})];
397 match version {
398 NetstackVersion::Netstack2 { tracing: false, fast_udp: _ } => {}
405 NetstackVersion::Netstack2 { tracing: true, fast_udp: _ } => {
406 uses.push(fnetemul::Capability::TracingProvider(fnetemul::Empty));
407 }
408 NetstackVersion::ProdNetstack2 => {
409 uses.push(fnetemul::Capability::ChildDep(protocol_dep::<
410 fstash::SecureStoreMarker,
411 >(
412 constants::secure_stash::COMPONENT_NAME,
413 )));
414 }
415 NetstackVersion::Netstack3 | NetstackVersion::ProdNetstack3 => {
416 uses.push(fnetemul::Capability::TracingProvider(fnetemul::Empty));
417 uses.push(fnetemul::Capability::StorageDep(fnetemul::StorageDep {
418 variant: Some(fnetemul::StorageVariant::Data),
419 path: Some("/data".to_string()),
420 ..Default::default()
421 }));
422 }
423 }
424 Some(fnetemul::ChildUses::Capabilities(uses))
425 },
426 ..Default::default()
427 },
428 KnownServiceProvider::Manager {
429 agent,
430 use_dhcp_server,
431 config,
432 use_out_of_stack_dhcp_client,
433 socket_proxy_type,
434 } => {
435 let enable_dhcpv6 = match config {
436 ManagerConfig::Dhcpv6 => true,
437 ManagerConfig::Forwarding
438 | ManagerConfig::Empty
439 | ManagerConfig::AllDelegated
440 | ManagerConfig::IfacePrefix
441 | ManagerConfig::DuplicateNames
442 | ManagerConfig::EnableSocketProxy
443 | ManagerConfig::EnableSocketProxyAllDelegated
444 | ManagerConfig::PacketFilterEthernet
445 | ManagerConfig::PacketFilterWlan
446 | ManagerConfig::WithBlackhole
447 | ManagerConfig::AllInterfaceLocalDelegated => false,
448 };
449
450 fnetemul::ChildDef {
451 name: Some(constants::netcfg::COMPONENT_NAME.to_string()),
452 source: Some(fnetemul::ChildSource::Component(agent.get_url().to_string())),
453 program_args: Some(
454 agent
455 .get_program_args()
456 .iter()
457 .cloned()
458 .chain(std::iter::once("--config-data"))
459 .chain(std::iter::once(config.as_str()))
460 .map(Into::into)
461 .collect(),
462 ),
463 exposes: Some(
464 agent.get_services().iter().map(|service| service.to_string()).collect(),
465 ),
466 uses: Some(fnetemul::ChildUses::Capabilities(
467 (*use_dhcp_server)
468 .then(|| {
469 fnetemul::Capability::ChildDep(protocol_dep::<
470 fnet_dhcp::Server_Marker,
471 >(
472 constants::dhcp_server::COMPONENT_NAME,
473 ))
474 })
475 .into_iter()
476 .chain(
477 enable_dhcpv6
478 .then(|| {
479 fnetemul::Capability::ChildDep(protocol_dep::<
480 fnet_dhcpv6::ClientProviderMarker,
481 >(
482 constants::dhcpv6_client::COMPONENT_NAME,
483 ))
484 })
485 .into_iter(),
486 )
487 .chain(use_out_of_stack_dhcp_client.then(|| {
488 fnetemul::Capability::ChildDep(protocol_dep::<
489 fnet_dhcp::ClientProviderMarker,
490 >(
491 constants::dhcp_client::COMPONENT_NAME,
492 ))
493 }))
494 .chain(
495 socket_proxy_type
496 .component_name()
497 .map(|component_name| {
498 [
499 fnetemul::Capability::ChildDep(protocol_dep::<
500 fnp_socketproxy::FuchsiaNetworksMarker,
501 >(
502 component_name
503 )),
504 fnetemul::Capability::ChildDep(protocol_dep::<
505 fnp_socketproxy::DnsServerWatcherMarker,
506 >(
507 component_name
508 )),
509 fnetemul::Capability::ChildDep(protocol_dep::<
510 fnp_properties::DefaultNetworkWatcherMarker,
511 >(
512 component_name
513 )),
514 ]
515 })
516 .into_iter()
517 .flatten(),
518 )
519 .chain(
520 [
521 fnetemul::Capability::LogSink(fnetemul::Empty {}),
522 fnetemul::Capability::ChildDep(protocol_dep::<
523 fnet_filter::ControlMarker,
524 >(
525 constants::netstack::COMPONENT_NAME,
526 )),
527 fnetemul::Capability::ChildDep(protocol_dep::<
528 fnet_filter_deprecated::FilterMarker,
529 >(
530 constants::netstack::COMPONENT_NAME,
531 )),
532 fnetemul::Capability::ChildDep(protocol_dep::<
533 fnet_interfaces::StateMarker,
534 >(
535 constants::netstack::COMPONENT_NAME,
536 )),
537 fnetemul::Capability::ChildDep(protocol_dep::<
538 fnet_interfaces_admin::InstallerMarker,
539 >(
540 constants::netstack::COMPONENT_NAME,
541 )),
542 fnetemul::Capability::ChildDep(protocol_dep::<
543 fnet_stack::StackMarker,
544 >(
545 constants::netstack::COMPONENT_NAME,
546 )),
547 fnetemul::Capability::ChildDep(protocol_dep::<
548 fnet_routes_admin::RouteTableV4Marker,
549 >(
550 constants::netstack::COMPONENT_NAME,
551 )),
552 fnetemul::Capability::ChildDep(protocol_dep::<
553 fnet_routes_admin::RouteTableV6Marker,
554 >(
555 constants::netstack::COMPONENT_NAME,
556 )),
557 fnetemul::Capability::ChildDep(protocol_dep::<
558 fnet_routes_admin::RuleTableV4Marker,
559 >(
560 constants::netstack::COMPONENT_NAME,
561 )),
562 fnetemul::Capability::ChildDep(protocol_dep::<
563 fnet_routes_admin::RuleTableV6Marker,
564 >(
565 constants::netstack::COMPONENT_NAME,
566 )),
567 fnetemul::Capability::ChildDep(protocol_dep::<
568 fnet_name::DnsServerWatcherMarker,
569 >(
570 constants::netstack::COMPONENT_NAME,
571 )),
572 fnetemul::Capability::ChildDep(protocol_dep::<
573 fnet_name::LookupAdminMarker,
574 >(
575 constants::dns_resolver::COMPONENT_NAME,
576 )),
577 fnetemul::Capability::ChildDep(protocol_dep::<
578 fnet_ndp::RouterAdvertisementOptionWatcherProviderMarker,
579 >(
580 constants::netstack::COMPONENT_NAME,
581 )),
582 fnetemul::Capability::NetemulDevfs(fnetemul::DevfsDep {
583 name: Some(
584 constants::netcfg::DEV_CLASS_NETWORK.to_string(),
585 ),
586 subdir: Some(
587 constants::netcfg::CLASS_NETWORK_PATH.to_string(),
588 ),
589 ..Default::default()
590 }),
591 fnetemul::Capability::StorageDep(fnetemul::StorageDep {
592 variant: Some(fnetemul::StorageVariant::Data),
593 path: Some("/data".to_string()),
594 ..Default::default()
595 }),
596 ]
597 .into_iter(),
598 )
599 .collect(),
600 )),
601 eager: Some(true),
602 ..Default::default()
603 }
604 }
605 KnownServiceProvider::SecureStash => fnetemul::ChildDef {
606 name: Some(constants::secure_stash::COMPONENT_NAME.to_string()),
607 source: Some(fnetemul::ChildSource::Component(
608 constants::secure_stash::COMPONENT_URL.to_string(),
609 )),
610 exposes: Some(vec![fstash::SecureStoreMarker::PROTOCOL_NAME.to_string()]),
611 uses: Some(fnetemul::ChildUses::Capabilities(vec![
612 fnetemul::Capability::LogSink(fnetemul::Empty {}),
613 fnetemul::Capability::StorageDep(fnetemul::StorageDep {
614 variant: Some(fnetemul::StorageVariant::Data),
615 path: Some("/data".to_string()),
616 ..Default::default()
617 }),
618 ])),
619 ..Default::default()
620 },
621 KnownServiceProvider::DhcpServer { persistent } => fnetemul::ChildDef {
622 name: Some(constants::dhcp_server::COMPONENT_NAME.to_string()),
623 source: Some(fnetemul::ChildSource::Component(
624 constants::dhcp_server::COMPONENT_URL.to_string(),
625 )),
626 exposes: Some(vec![fnet_dhcp::Server_Marker::PROTOCOL_NAME.to_string()]),
627 uses: Some(fnetemul::ChildUses::Capabilities(
628 [
629 fnetemul::Capability::LogSink(fnetemul::Empty {}),
630 fnetemul::Capability::ChildDep(protocol_dep::<
631 fnet_neighbor::ControllerMarker,
632 >(
633 constants::netstack::COMPONENT_NAME
634 )),
635 fnetemul::Capability::ChildDep(
636 protocol_dep::<fposix_socket::ProviderMarker>(
637 constants::netstack::COMPONENT_NAME,
638 ),
639 ),
640 fnetemul::Capability::ChildDep(protocol_dep::<
641 fposix_socket_packet::ProviderMarker,
642 >(
643 constants::netstack::COMPONENT_NAME
644 )),
645 ]
646 .into_iter()
647 .chain(persistent.then_some(fnetemul::Capability::ChildDep(protocol_dep::<
648 fstash::SecureStoreMarker,
649 >(
650 constants::secure_stash::COMPONENT_NAME,
651 ))))
652 .collect(),
653 )),
654 program_args: if *persistent {
655 Some(vec![String::from("--persistent")])
656 } else {
657 None
658 },
659 ..Default::default()
660 },
661 KnownServiceProvider::DhcpClient => fnetemul::ChildDef {
662 name: Some(constants::dhcp_client::COMPONENT_NAME.to_string()),
663 source: Some(fnetemul::ChildSource::Component(
664 constants::dhcp_client::COMPONENT_URL.to_string(),
665 )),
666 exposes: Some(vec![fnet_dhcp::ClientProviderMarker::PROTOCOL_NAME.to_string()]),
667 uses: Some(fnetemul::ChildUses::Capabilities(vec![
668 fnetemul::Capability::LogSink(fnetemul::Empty {}),
669 fnetemul::Capability::ChildDep(protocol_dep::<fposix_socket::ProviderMarker>(
670 constants::netstack::COMPONENT_NAME,
671 )),
672 fnetemul::Capability::ChildDep(protocol_dep::<
673 fposix_socket_packet::ProviderMarker,
674 >(
675 constants::netstack::COMPONENT_NAME
676 )),
677 ])),
678 program_args: None,
679 ..Default::default()
680 },
681 KnownServiceProvider::Dhcpv6Client => fnetemul::ChildDef {
682 name: Some(constants::dhcpv6_client::COMPONENT_NAME.to_string()),
683 source: Some(fnetemul::ChildSource::Component(
684 constants::dhcpv6_client::COMPONENT_URL.to_string(),
685 )),
686 exposes: Some(vec![fnet_dhcpv6::ClientProviderMarker::PROTOCOL_NAME.to_string()]),
687 uses: Some(fnetemul::ChildUses::Capabilities(vec![
688 fnetemul::Capability::LogSink(fnetemul::Empty {}),
689 fnetemul::Capability::ChildDep(protocol_dep::<fposix_socket::ProviderMarker>(
690 constants::netstack::COMPONENT_NAME,
691 )),
692 ])),
693 ..Default::default()
694 },
695 KnownServiceProvider::DnsResolver => fnetemul::ChildDef {
696 name: Some(constants::dns_resolver::COMPONENT_NAME.to_string()),
697 source: Some(fnetemul::ChildSource::Component(
698 constants::dns_resolver::COMPONENT_URL.to_string(),
699 )),
700 exposes: Some(vec![
701 fnet_name::LookupAdminMarker::PROTOCOL_NAME.to_string(),
702 fnet_name::LookupMarker::PROTOCOL_NAME.to_string(),
703 ]),
704 uses: Some(fnetemul::ChildUses::Capabilities(vec![
705 fnetemul::Capability::LogSink(fnetemul::Empty {}),
706 fnetemul::Capability::ChildDep(protocol_dep::<fnet_routes::StateMarker>(
707 constants::netstack::COMPONENT_NAME,
708 )),
709 fnetemul::Capability::ChildDep(protocol_dep::<fposix_socket::ProviderMarker>(
710 constants::netstack::COMPONENT_NAME,
711 )),
712 fnetemul::Capability::ChildDep(protocol_dep::<
713 fidl_fuchsia_testing::FakeClockMarker,
714 >(
715 constants::fake_clock::COMPONENT_NAME
716 )),
717 ])),
718 ..Default::default()
719 },
720 KnownServiceProvider::Reachability { eager } => fnetemul::ChildDef {
721 name: Some(constants::reachability::COMPONENT_NAME.to_string()),
722 source: Some(fnetemul::ChildSource::Component(
723 constants::reachability::COMPONENT_URL.to_string(),
724 )),
725 exposes: Some(vec![fnet_reachability::MonitorMarker::PROTOCOL_NAME.to_string()]),
726 uses: Some(fnetemul::ChildUses::Capabilities(vec![
727 fnetemul::Capability::LogSink(fnetemul::Empty {}),
728 fnetemul::Capability::ChildDep(protocol_dep::<fnet_interfaces::StateMarker>(
729 constants::netstack::COMPONENT_NAME,
730 )),
731 fnetemul::Capability::ChildDep(protocol_dep::<fposix_socket::ProviderMarker>(
732 constants::netstack::COMPONENT_NAME,
733 )),
734 fnetemul::Capability::ChildDep(protocol_dep::<fnet_name::LookupMarker>(
735 constants::dns_resolver::COMPONENT_NAME,
736 )),
737 fnetemul::Capability::ChildDep(protocol_dep::<fnet_neighbor::ViewMarker>(
738 constants::netstack::COMPONENT_NAME,
739 )),
740 fnetemul::Capability::ChildDep(protocol_dep::<fnet_debug::InterfacesMarker>(
741 constants::netstack::COMPONENT_NAME,
742 )),
743 fnetemul::Capability::ChildDep(protocol_dep::<fnet_root::InterfacesMarker>(
744 constants::netstack::COMPONENT_NAME,
745 )),
746 fnetemul::Capability::ChildDep(protocol_dep::<fnet_routes::StateV4Marker>(
747 constants::netstack::COMPONENT_NAME,
748 )),
749 fnetemul::Capability::ChildDep(protocol_dep::<fnet_routes::StateV6Marker>(
750 constants::netstack::COMPONENT_NAME,
751 )),
752 fnetemul::Capability::ChildDep(protocol_dep::<fnet_debug::DiagnosticsMarker>(
753 constants::netstack::COMPONENT_NAME,
754 )),
755 fnetemul::Capability::ChildDep(protocol_dep::<
756 fidl_fuchsia_testing::FakeClockMarker,
757 >(
758 constants::fake_clock::COMPONENT_NAME
759 )),
760 ])),
761 eager: Some(*eager),
762 ..Default::default()
763 },
764 KnownServiceProvider::SocketProxy => fnetemul::ChildDef {
765 name: Some(constants::socket_proxy::COMPONENT_NAME.to_string()),
766 source: Some(fnetemul::ChildSource::Component(
767 constants::socket_proxy::COMPONENT_URL.to_string(),
768 )),
769 exposes: Some(vec![
770 fposix_socket::ProviderMarker::PROTOCOL_NAME.to_string(),
771 fposix_socket_raw::ProviderMarker::PROTOCOL_NAME.to_string(),
772 fnp_socketproxy::StarnixNetworksMarker::PROTOCOL_NAME.to_string(),
773 fnp_socketproxy::FuchsiaNetworksMarker::PROTOCOL_NAME.to_string(),
774 fnp_socketproxy::DnsServerWatcherMarker::PROTOCOL_NAME.to_string(),
775 fnp_properties::DefaultNetworkWatcherMarker::PROTOCOL_NAME.to_string(),
776 ]),
777 uses: Some(fnetemul::ChildUses::Capabilities(vec![
778 fnetemul::Capability::ChildDep(protocol_dep::<fposix_socket::ProviderMarker>(
779 constants::netstack::COMPONENT_NAME,
780 )),
781 fnetemul::Capability::ChildDep(
782 protocol_dep::<fposix_socket_raw::ProviderMarker>(
783 constants::netstack::COMPONENT_NAME,
784 ),
785 ),
786 ])),
787 ..Default::default()
788 },
789 KnownServiceProvider::NetworkTestRealm { require_outer_netstack } => {
790 fnetemul::ChildDef {
791 name: Some(constants::network_test_realm::COMPONENT_NAME.to_string()),
792 source: Some(fnetemul::ChildSource::Component(
793 constants::network_test_realm::COMPONENT_URL.to_string(),
794 )),
795 exposes: Some(vec![
796 fntr::ControllerMarker::PROTOCOL_NAME.to_string(),
797 fcomponent::RealmMarker::PROTOCOL_NAME.to_string(),
798 ]),
799 uses: Some(fnetemul::ChildUses::Capabilities(
800 std::iter::once(fnetemul::Capability::LogSink(fnetemul::Empty {}))
801 .chain(
802 require_outer_netstack
803 .then_some([
804 fnetemul::Capability::ChildDep(protocol_dep::<
805 fnet_stack::StackMarker,
806 >(
807 constants::netstack::COMPONENT_NAME,
808 )),
809 fnetemul::Capability::ChildDep(protocol_dep::<
810 fnet_debug::InterfacesMarker,
811 >(
812 constants::netstack::COMPONENT_NAME,
813 )),
814 fnetemul::Capability::ChildDep(protocol_dep::<
815 fnet_root::InterfacesMarker,
816 >(
817 constants::netstack::COMPONENT_NAME,
818 )),
819 fnetemul::Capability::ChildDep(protocol_dep::<
820 fnet_interfaces::StateMarker,
821 >(
822 constants::netstack::COMPONENT_NAME,
823 )),
824 ])
825 .into_iter()
826 .flatten(),
827 )
828 .collect::<Vec<_>>(),
829 )),
830 ..Default::default()
831 }
832 }
833 KnownServiceProvider::FakeClock => fnetemul::ChildDef {
834 name: Some(constants::fake_clock::COMPONENT_NAME.to_string()),
835 source: Some(fnetemul::ChildSource::Component(
836 constants::fake_clock::COMPONENT_URL.to_string(),
837 )),
838 exposes: Some(vec![
839 fidl_fuchsia_testing::FakeClockMarker::PROTOCOL_NAME.to_string(),
840 fidl_fuchsia_testing::FakeClockControlMarker::PROTOCOL_NAME.to_string(),
841 ]),
842 uses: Some(fnetemul::ChildUses::Capabilities(vec![fnetemul::Capability::LogSink(
843 fnetemul::Empty {},
844 )])),
845 ..Default::default()
846 },
847 KnownServiceProvider::FakeSocketProxy => fnetemul::ChildDef {
848 name: Some(constants::fake_socket_proxy::COMPONENT_NAME.to_string()),
849 source: Some(fnetemul::ChildSource::Component(
850 constants::fake_socket_proxy::COMPONENT_URL.to_string(),
851 )),
852 exposes: Some(vec![
853 fnp_properties::DefaultNetworkWatcherMarker::PROTOCOL_NAME.to_string(),
854 fnp_socketproxy::DnsServerWatcherMarker::PROTOCOL_NAME.to_string(),
855 fnp_socketproxy::FuchsiaNetworksMarker::PROTOCOL_NAME.to_string(),
856 fnp_testing::FakeSocketProxy_Marker::PROTOCOL_NAME.to_string(),
857 ]),
858 ..Default::default()
859 },
860 KnownServiceProvider::FakeNetcfg => fnetemul::ChildDef {
861 name: Some(constants::netcfg::COMPONENT_NAME.to_string()),
862 source: Some(fnetemul::ChildSource::Component(
863 constants::netcfg::fake::COMPONENT_URL.to_string(),
864 )),
865 exposes: Some(vec![
866 fnp_properties::NetworksMarker::PROTOCOL_NAME.to_string(),
867 fnp_testing::FakeNetcfgMarker::PROTOCOL_NAME.to_string(),
868 ]),
869 ..Default::default()
870 },
871 }
872 }
873}
874
875pub fn set_netstack3_opaque_iids(netstack: &mut fnetemul::ChildDef, value: bool) {
877 const KEY: &str = "opaque_iids";
878 set_structured_config_value(netstack, KEY.to_owned(), cm_rust::ConfigValue::from(value));
879}
880
881pub fn set_netstack3_suspend_enabled(netstack: &mut fnetemul::ChildDef, value: bool) {
883 const KEY: &str = "suspend_enabled";
884 set_structured_config_value(netstack, KEY.to_owned(), cm_rust::ConfigValue::from(value));
885}
886
887fn set_structured_config_value(
889 component: &mut fnetemul::ChildDef,
890 key: String,
891 value: cm_rust::ConfigValue,
892) {
893 component
894 .config_values
895 .get_or_insert_default()
896 .push(fnetemul::ChildConfigValue { key, value: value.native_into_fidl() });
897}
898
899pub trait Netstack: Copy + Clone {
901 const VERSION: NetstackVersion;
903}
904
905#[derive(Copy, Clone)]
908pub enum Netstack2 {}
909
910impl Netstack for Netstack2 {
911 const VERSION: NetstackVersion = NetstackVersion::Netstack2 { tracing: false, fast_udp: false };
912}
913
914#[derive(Copy, Clone)]
917pub enum ProdNetstack2 {}
918
919impl Netstack for ProdNetstack2 {
920 const VERSION: NetstackVersion = NetstackVersion::ProdNetstack2;
921}
922
923#[derive(Copy, Clone)]
926pub enum Netstack3 {}
927
928impl Netstack for Netstack3 {
929 const VERSION: NetstackVersion = NetstackVersion::Netstack3;
930}
931
932#[derive(Copy, Clone)]
935pub enum ProdNetstack3 {}
936
937impl Netstack for ProdNetstack3 {
938 const VERSION: NetstackVersion = NetstackVersion::ProdNetstack3;
939}
940
941pub trait Manager: Copy + Clone {
943 const MANAGEMENT_AGENT: ManagementAgent;
945}
946
947#[derive(Copy, Clone)]
949pub enum NetCfgBasic {}
950
951impl Manager for NetCfgBasic {
952 const MANAGEMENT_AGENT: ManagementAgent = ManagementAgent::NetCfg(NetCfgVersion::Basic);
953}
954
955#[derive(Copy, Clone)]
958pub enum NetCfgAdvanced {}
959
960impl Manager for NetCfgAdvanced {
961 const MANAGEMENT_AGENT: ManagementAgent = ManagementAgent::NetCfg(NetCfgVersion::Advanced);
962}
963
964pub use netemul::{DhcpClient, DhcpClientVersion, InStack, OutOfStack};
965
966pub trait NetstackAndDhcpClient: Copy + Clone {
969 type Netstack: Netstack;
971 type DhcpClient: DhcpClient;
973}
974
975#[derive(Copy, Clone)]
977pub enum Netstack2AndInStackDhcpClient {}
978
979impl NetstackAndDhcpClient for Netstack2AndInStackDhcpClient {
980 type Netstack = Netstack2;
981 type DhcpClient = InStack;
982}
983
984#[derive(Copy, Clone)]
986pub enum Netstack2AndOutOfStackDhcpClient {}
987
988impl NetstackAndDhcpClient for Netstack2AndOutOfStackDhcpClient {
989 type Netstack = Netstack2;
990 type DhcpClient = OutOfStack;
991}
992
993#[derive(Copy, Clone)]
995pub enum Netstack3AndOutOfStackDhcpClient {}
996
997impl NetstackAndDhcpClient for Netstack3AndOutOfStackDhcpClient {
998 type Netstack = Netstack3;
999 type DhcpClient = OutOfStack;
1000}
1001
1002#[async_trait]
1004pub trait TestSandboxExt {
1005 fn create_netstack_realm<'a, N, S>(&'a self, name: S) -> Result<netemul::TestRealm<'a>>
1007 where
1008 N: Netstack,
1009 S: Into<Cow<'a, str>>;
1010
1011 fn create_netstack_realm_with<'a, N, S, I>(
1014 &'a self,
1015 name: S,
1016 children: I,
1017 ) -> Result<netemul::TestRealm<'a>>
1018 where
1019 S: Into<Cow<'a, str>>,
1020 N: Netstack,
1021 I: IntoIterator,
1022 I::Item: Into<fnetemul::ChildDef>;
1023}
1024
1025#[async_trait]
1026impl TestSandboxExt for netemul::TestSandbox {
1027 fn create_netstack_realm<'a, N, S>(&'a self, name: S) -> Result<netemul::TestRealm<'a>>
1028 where
1029 N: Netstack,
1030 S: Into<Cow<'a, str>>,
1031 {
1032 self.create_netstack_realm_with::<N, _, _>(name, std::iter::empty::<fnetemul::ChildDef>())
1033 }
1034
1035 fn create_netstack_realm_with<'a, N, S, I>(
1036 &'a self,
1037 name: S,
1038 children: I,
1039 ) -> Result<netemul::TestRealm<'a>>
1040 where
1041 S: Into<Cow<'a, str>>,
1042 N: Netstack,
1043 I: IntoIterator,
1044 I::Item: Into<fnetemul::ChildDef>,
1045 {
1046 self.create_realm(
1047 name,
1048 [KnownServiceProvider::Netstack(N::VERSION)]
1049 .iter()
1050 .map(fnetemul::ChildDef::from)
1051 .chain(children.into_iter().map(Into::into)),
1052 )
1053 }
1054}
1055
1056#[async_trait]
1058pub trait TestRealmExt {
1059 async fn loopback_properties(
1062 &self,
1063 ) -> Result<Option<fnet_interfaces_ext::Properties<fnet_interfaces_ext::AllInterest>>>;
1064
1065 fn interface_control(&self, id: u64) -> Result<fnet_interfaces_ext::admin::Control>;
1072}
1073
1074#[async_trait]
1075impl TestRealmExt for netemul::TestRealm<'_> {
1076 async fn loopback_properties(
1077 &self,
1078 ) -> Result<Option<fnet_interfaces_ext::Properties<fnet_interfaces_ext::AllInterest>>> {
1079 let interface_state = self
1080 .connect_to_protocol::<fnet_interfaces::StateMarker>()
1081 .context("failed to connect to fuchsia.net.interfaces/State")?;
1082
1083 let properties = fnet_interfaces_ext::existing(
1084 fnet_interfaces_ext::event_stream_from_state(&interface_state, Default::default())
1085 .expect("create watcher event stream"),
1086 HashMap::<u64, fnet_interfaces_ext::PropertiesAndState<(), _>>::new(),
1087 )
1088 .await
1089 .context("failed to get existing interface properties from watcher")?
1090 .into_iter()
1091 .find_map(|(_id, properties_and_state): (u64, _)| {
1092 let fnet_interfaces_ext::PropertiesAndState {
1093 properties: properties @ fnet_interfaces_ext::Properties { port_class, .. },
1094 state: (),
1095 } = properties_and_state;
1096 port_class.is_loopback().then_some(properties)
1097 });
1098 Ok(properties)
1099 }
1100
1101 fn interface_control(&self, id: u64) -> Result<fnet_interfaces_ext::admin::Control> {
1102 let root_control = self
1103 .connect_to_protocol::<fnet_root::InterfacesMarker>()
1104 .context("connect to protocol")?;
1105
1106 let (control, server) = fnet_interfaces_ext::admin::Control::create_endpoints()
1107 .context("create Control proxy")?;
1108 let () = root_control.get_admin(id, server).context("get admin")?;
1109 Ok(control)
1110 }
1111}