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