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(fnetemul::ChildDep {
523 dynamically_offer_from_void: Some(true),
524 ..protocol_dep::<fnet_filter::ControlMarker>(
525 constants::netstack::COMPONENT_NAME,
526 )
527 }),
528 fnetemul::Capability::ChildDep(fnetemul::ChildDep {
529 dynamically_offer_from_void: Some(true),
530 ..protocol_dep::<fnet_filter_deprecated::FilterMarker>(
531 constants::netstack::COMPONENT_NAME,
532 )
533 }),
534 fnetemul::Capability::ChildDep(protocol_dep::<
535 fnet_interfaces::StateMarker,
536 >(
537 constants::netstack::COMPONENT_NAME,
538 )),
539 fnetemul::Capability::ChildDep(protocol_dep::<
540 fnet_interfaces_admin::InstallerMarker,
541 >(
542 constants::netstack::COMPONENT_NAME,
543 )),
544 fnetemul::Capability::ChildDep(protocol_dep::<
545 fnet_stack::StackMarker,
546 >(
547 constants::netstack::COMPONENT_NAME,
548 )),
549 fnetemul::Capability::ChildDep(protocol_dep::<
550 fnet_routes_admin::RouteTableV4Marker,
551 >(
552 constants::netstack::COMPONENT_NAME,
553 )),
554 fnetemul::Capability::ChildDep(protocol_dep::<
555 fnet_routes_admin::RouteTableV6Marker,
556 >(
557 constants::netstack::COMPONENT_NAME,
558 )),
559 fnetemul::Capability::ChildDep(protocol_dep::<
560 fnet_routes_admin::RuleTableV4Marker,
561 >(
562 constants::netstack::COMPONENT_NAME,
563 )),
564 fnetemul::Capability::ChildDep(protocol_dep::<
565 fnet_routes_admin::RuleTableV6Marker,
566 >(
567 constants::netstack::COMPONENT_NAME,
568 )),
569 fnetemul::Capability::ChildDep(protocol_dep::<
570 fnet_name::DnsServerWatcherMarker,
571 >(
572 constants::netstack::COMPONENT_NAME,
573 )),
574 fnetemul::Capability::ChildDep(protocol_dep::<
575 fnet_name::LookupAdminMarker,
576 >(
577 constants::dns_resolver::COMPONENT_NAME,
578 )),
579 fnetemul::Capability::ChildDep(protocol_dep::<
580 fnet_ndp::RouterAdvertisementOptionWatcherProviderMarker,
581 >(
582 constants::netstack::COMPONENT_NAME,
583 )),
584 fnetemul::Capability::NetemulDevfs(fnetemul::DevfsDep {
585 name: Some(
586 constants::netcfg::DEV_CLASS_NETWORK.to_string(),
587 ),
588 subdir: Some(
589 constants::netcfg::CLASS_NETWORK_PATH.to_string(),
590 ),
591 ..Default::default()
592 }),
593 fnetemul::Capability::StorageDep(fnetemul::StorageDep {
594 variant: Some(fnetemul::StorageVariant::Data),
595 path: Some("/data".to_string()),
596 ..Default::default()
597 }),
598 ]
599 .into_iter(),
600 )
601 .collect(),
602 )),
603 eager: Some(true),
604 ..Default::default()
605 }
606 }
607 KnownServiceProvider::SecureStash => fnetemul::ChildDef {
608 name: Some(constants::secure_stash::COMPONENT_NAME.to_string()),
609 source: Some(fnetemul::ChildSource::Component(
610 constants::secure_stash::COMPONENT_URL.to_string(),
611 )),
612 exposes: Some(vec![fstash::SecureStoreMarker::PROTOCOL_NAME.to_string()]),
613 uses: Some(fnetemul::ChildUses::Capabilities(vec![
614 fnetemul::Capability::LogSink(fnetemul::Empty {}),
615 fnetemul::Capability::StorageDep(fnetemul::StorageDep {
616 variant: Some(fnetemul::StorageVariant::Data),
617 path: Some("/data".to_string()),
618 ..Default::default()
619 }),
620 ])),
621 ..Default::default()
622 },
623 KnownServiceProvider::DhcpServer { persistent } => fnetemul::ChildDef {
624 name: Some(constants::dhcp_server::COMPONENT_NAME.to_string()),
625 source: Some(fnetemul::ChildSource::Component(
626 constants::dhcp_server::COMPONENT_URL.to_string(),
627 )),
628 exposes: Some(vec![fnet_dhcp::Server_Marker::PROTOCOL_NAME.to_string()]),
629 uses: Some(fnetemul::ChildUses::Capabilities(
630 [
631 fnetemul::Capability::LogSink(fnetemul::Empty {}),
632 fnetemul::Capability::ChildDep(protocol_dep::<
633 fnet_neighbor::ControllerMarker,
634 >(
635 constants::netstack::COMPONENT_NAME
636 )),
637 fnetemul::Capability::ChildDep(
638 protocol_dep::<fposix_socket::ProviderMarker>(
639 constants::netstack::COMPONENT_NAME,
640 ),
641 ),
642 fnetemul::Capability::ChildDep(protocol_dep::<
643 fposix_socket_packet::ProviderMarker,
644 >(
645 constants::netstack::COMPONENT_NAME
646 )),
647 ]
648 .into_iter()
649 .chain(persistent.then_some(fnetemul::Capability::ChildDep(protocol_dep::<
650 fstash::SecureStoreMarker,
651 >(
652 constants::secure_stash::COMPONENT_NAME,
653 ))))
654 .collect(),
655 )),
656 program_args: if *persistent {
657 Some(vec![String::from("--persistent")])
658 } else {
659 None
660 },
661 ..Default::default()
662 },
663 KnownServiceProvider::DhcpClient => fnetemul::ChildDef {
664 name: Some(constants::dhcp_client::COMPONENT_NAME.to_string()),
665 source: Some(fnetemul::ChildSource::Component(
666 constants::dhcp_client::COMPONENT_URL.to_string(),
667 )),
668 exposes: Some(vec![fnet_dhcp::ClientProviderMarker::PROTOCOL_NAME.to_string()]),
669 uses: Some(fnetemul::ChildUses::Capabilities(vec![
670 fnetemul::Capability::LogSink(fnetemul::Empty {}),
671 fnetemul::Capability::ChildDep(protocol_dep::<fposix_socket::ProviderMarker>(
672 constants::netstack::COMPONENT_NAME,
673 )),
674 fnetemul::Capability::ChildDep(protocol_dep::<
675 fposix_socket_packet::ProviderMarker,
676 >(
677 constants::netstack::COMPONENT_NAME
678 )),
679 ])),
680 program_args: None,
681 ..Default::default()
682 },
683 KnownServiceProvider::Dhcpv6Client => fnetemul::ChildDef {
684 name: Some(constants::dhcpv6_client::COMPONENT_NAME.to_string()),
685 source: Some(fnetemul::ChildSource::Component(
686 constants::dhcpv6_client::COMPONENT_URL.to_string(),
687 )),
688 exposes: Some(vec![fnet_dhcpv6::ClientProviderMarker::PROTOCOL_NAME.to_string()]),
689 uses: Some(fnetemul::ChildUses::Capabilities(vec![
690 fnetemul::Capability::LogSink(fnetemul::Empty {}),
691 fnetemul::Capability::ChildDep(protocol_dep::<fposix_socket::ProviderMarker>(
692 constants::netstack::COMPONENT_NAME,
693 )),
694 ])),
695 ..Default::default()
696 },
697 KnownServiceProvider::DnsResolver => fnetemul::ChildDef {
698 name: Some(constants::dns_resolver::COMPONENT_NAME.to_string()),
699 source: Some(fnetemul::ChildSource::Component(
700 constants::dns_resolver::COMPONENT_URL.to_string(),
701 )),
702 exposes: Some(vec![
703 fnet_name::LookupAdminMarker::PROTOCOL_NAME.to_string(),
704 fnet_name::LookupMarker::PROTOCOL_NAME.to_string(),
705 ]),
706 uses: Some(fnetemul::ChildUses::Capabilities(vec![
707 fnetemul::Capability::LogSink(fnetemul::Empty {}),
708 fnetemul::Capability::ChildDep(protocol_dep::<fnet_routes::StateMarker>(
709 constants::netstack::COMPONENT_NAME,
710 )),
711 fnetemul::Capability::ChildDep(protocol_dep::<fposix_socket::ProviderMarker>(
712 constants::netstack::COMPONENT_NAME,
713 )),
714 fnetemul::Capability::ChildDep(protocol_dep::<
715 fidl_fuchsia_testing::FakeClockMarker,
716 >(
717 constants::fake_clock::COMPONENT_NAME
718 )),
719 ])),
720 ..Default::default()
721 },
722 KnownServiceProvider::Reachability { eager } => fnetemul::ChildDef {
723 name: Some(constants::reachability::COMPONENT_NAME.to_string()),
724 source: Some(fnetemul::ChildSource::Component(
725 constants::reachability::COMPONENT_URL.to_string(),
726 )),
727 exposes: Some(vec![fnet_reachability::MonitorMarker::PROTOCOL_NAME.to_string()]),
728 uses: Some(fnetemul::ChildUses::Capabilities(vec![
729 fnetemul::Capability::LogSink(fnetemul::Empty {}),
730 fnetemul::Capability::ChildDep(protocol_dep::<fnet_interfaces::StateMarker>(
731 constants::netstack::COMPONENT_NAME,
732 )),
733 fnetemul::Capability::ChildDep(protocol_dep::<fposix_socket::ProviderMarker>(
734 constants::netstack::COMPONENT_NAME,
735 )),
736 fnetemul::Capability::ChildDep(protocol_dep::<fnet_name::LookupMarker>(
737 constants::dns_resolver::COMPONENT_NAME,
738 )),
739 fnetemul::Capability::ChildDep(protocol_dep::<fnet_neighbor::ViewMarker>(
740 constants::netstack::COMPONENT_NAME,
741 )),
742 fnetemul::Capability::ChildDep(protocol_dep::<fnet_debug::InterfacesMarker>(
743 constants::netstack::COMPONENT_NAME,
744 )),
745 fnetemul::Capability::ChildDep(protocol_dep::<fnet_root::InterfacesMarker>(
746 constants::netstack::COMPONENT_NAME,
747 )),
748 fnetemul::Capability::ChildDep(protocol_dep::<fnet_routes::StateV4Marker>(
749 constants::netstack::COMPONENT_NAME,
750 )),
751 fnetemul::Capability::ChildDep(protocol_dep::<fnet_routes::StateV6Marker>(
752 constants::netstack::COMPONENT_NAME,
753 )),
754 fnetemul::Capability::ChildDep(protocol_dep::<fnet_debug::DiagnosticsMarker>(
755 constants::netstack::COMPONENT_NAME,
756 )),
757 fnetemul::Capability::ChildDep(protocol_dep::<
758 fidl_fuchsia_testing::FakeClockMarker,
759 >(
760 constants::fake_clock::COMPONENT_NAME
761 )),
762 ])),
763 eager: Some(*eager),
764 ..Default::default()
765 },
766 KnownServiceProvider::SocketProxy => fnetemul::ChildDef {
767 name: Some(constants::socket_proxy::COMPONENT_NAME.to_string()),
768 source: Some(fnetemul::ChildSource::Component(
769 constants::socket_proxy::COMPONENT_URL.to_string(),
770 )),
771 exposes: Some(vec![
772 fposix_socket::ProviderMarker::PROTOCOL_NAME.to_string(),
773 fposix_socket_raw::ProviderMarker::PROTOCOL_NAME.to_string(),
774 fnp_socketproxy::StarnixNetworksMarker::PROTOCOL_NAME.to_string(),
775 fnp_socketproxy::FuchsiaNetworksMarker::PROTOCOL_NAME.to_string(),
776 fnp_socketproxy::DnsServerWatcherMarker::PROTOCOL_NAME.to_string(),
777 fnp_properties::DefaultNetworkWatcherMarker::PROTOCOL_NAME.to_string(),
778 ]),
779 uses: Some(fnetemul::ChildUses::Capabilities(vec![
780 fnetemul::Capability::ChildDep(protocol_dep::<fposix_socket::ProviderMarker>(
781 constants::netstack::COMPONENT_NAME,
782 )),
783 fnetemul::Capability::ChildDep(
784 protocol_dep::<fposix_socket_raw::ProviderMarker>(
785 constants::netstack::COMPONENT_NAME,
786 ),
787 ),
788 ])),
789 ..Default::default()
790 },
791 KnownServiceProvider::NetworkTestRealm { require_outer_netstack } => {
792 fnetemul::ChildDef {
793 name: Some(constants::network_test_realm::COMPONENT_NAME.to_string()),
794 source: Some(fnetemul::ChildSource::Component(
795 constants::network_test_realm::COMPONENT_URL.to_string(),
796 )),
797 exposes: Some(vec![
798 fntr::ControllerMarker::PROTOCOL_NAME.to_string(),
799 fcomponent::RealmMarker::PROTOCOL_NAME.to_string(),
800 ]),
801 uses: Some(fnetemul::ChildUses::Capabilities(
802 std::iter::once(fnetemul::Capability::LogSink(fnetemul::Empty {}))
803 .chain(
804 require_outer_netstack
805 .then_some([
806 fnetemul::Capability::ChildDep(protocol_dep::<
807 fnet_stack::StackMarker,
808 >(
809 constants::netstack::COMPONENT_NAME,
810 )),
811 fnetemul::Capability::ChildDep(protocol_dep::<
812 fnet_debug::InterfacesMarker,
813 >(
814 constants::netstack::COMPONENT_NAME,
815 )),
816 fnetemul::Capability::ChildDep(protocol_dep::<
817 fnet_root::InterfacesMarker,
818 >(
819 constants::netstack::COMPONENT_NAME,
820 )),
821 fnetemul::Capability::ChildDep(protocol_dep::<
822 fnet_interfaces::StateMarker,
823 >(
824 constants::netstack::COMPONENT_NAME,
825 )),
826 ])
827 .into_iter()
828 .flatten(),
829 )
830 .collect::<Vec<_>>(),
831 )),
832 ..Default::default()
833 }
834 }
835 KnownServiceProvider::FakeClock => fnetemul::ChildDef {
836 name: Some(constants::fake_clock::COMPONENT_NAME.to_string()),
837 source: Some(fnetemul::ChildSource::Component(
838 constants::fake_clock::COMPONENT_URL.to_string(),
839 )),
840 exposes: Some(vec![
841 fidl_fuchsia_testing::FakeClockMarker::PROTOCOL_NAME.to_string(),
842 fidl_fuchsia_testing::FakeClockControlMarker::PROTOCOL_NAME.to_string(),
843 ]),
844 uses: Some(fnetemul::ChildUses::Capabilities(vec![fnetemul::Capability::LogSink(
845 fnetemul::Empty {},
846 )])),
847 ..Default::default()
848 },
849 KnownServiceProvider::FakeSocketProxy => fnetemul::ChildDef {
850 name: Some(constants::fake_socket_proxy::COMPONENT_NAME.to_string()),
851 source: Some(fnetemul::ChildSource::Component(
852 constants::fake_socket_proxy::COMPONENT_URL.to_string(),
853 )),
854 exposes: Some(vec![
855 fnp_properties::DefaultNetworkWatcherMarker::PROTOCOL_NAME.to_string(),
856 fnp_socketproxy::DnsServerWatcherMarker::PROTOCOL_NAME.to_string(),
857 fnp_socketproxy::FuchsiaNetworksMarker::PROTOCOL_NAME.to_string(),
858 fnp_testing::FakeSocketProxy_Marker::PROTOCOL_NAME.to_string(),
859 ]),
860 ..Default::default()
861 },
862 KnownServiceProvider::FakeNetcfg => fnetemul::ChildDef {
863 name: Some(constants::netcfg::COMPONENT_NAME.to_string()),
864 source: Some(fnetemul::ChildSource::Component(
865 constants::netcfg::fake::COMPONENT_URL.to_string(),
866 )),
867 exposes: Some(vec![
868 fnp_properties::NetworksMarker::PROTOCOL_NAME.to_string(),
869 fnp_testing::FakeNetcfgMarker::PROTOCOL_NAME.to_string(),
870 ]),
871 ..Default::default()
872 },
873 }
874 }
875}
876
877pub fn set_netstack3_opaque_iids(netstack: &mut fnetemul::ChildDef, value: bool) {
879 const KEY: &str = "opaque_iids";
880 set_structured_config_value(netstack, KEY.to_owned(), cm_rust::ConfigValue::from(value));
881}
882
883pub fn set_netstack3_suspend_enabled(netstack: &mut fnetemul::ChildDef, value: bool) {
885 const KEY: &str = "suspend_enabled";
886 set_structured_config_value(netstack, KEY.to_owned(), cm_rust::ConfigValue::from(value));
887}
888
889fn set_structured_config_value(
891 component: &mut fnetemul::ChildDef,
892 key: String,
893 value: cm_rust::ConfigValue,
894) {
895 component
896 .config_values
897 .get_or_insert_default()
898 .push(fnetemul::ChildConfigValue { key, value: value.native_into_fidl() });
899}
900
901pub trait Netstack: Copy + Clone {
903 const VERSION: NetstackVersion;
905}
906
907#[derive(Copy, Clone)]
910pub enum Netstack2 {}
911
912impl Netstack for Netstack2 {
913 const VERSION: NetstackVersion = NetstackVersion::Netstack2 { tracing: false, fast_udp: false };
914}
915
916#[derive(Copy, Clone)]
919pub enum ProdNetstack2 {}
920
921impl Netstack for ProdNetstack2 {
922 const VERSION: NetstackVersion = NetstackVersion::ProdNetstack2;
923}
924
925#[derive(Copy, Clone)]
928pub enum Netstack3 {}
929
930impl Netstack for Netstack3 {
931 const VERSION: NetstackVersion = NetstackVersion::Netstack3;
932}
933
934#[derive(Copy, Clone)]
937pub enum ProdNetstack3 {}
938
939impl Netstack for ProdNetstack3 {
940 const VERSION: NetstackVersion = NetstackVersion::ProdNetstack3;
941}
942
943pub trait Manager: Copy + Clone {
945 const MANAGEMENT_AGENT: ManagementAgent;
947}
948
949#[derive(Copy, Clone)]
951pub enum NetCfgBasic {}
952
953impl Manager for NetCfgBasic {
954 const MANAGEMENT_AGENT: ManagementAgent = ManagementAgent::NetCfg(NetCfgVersion::Basic);
955}
956
957#[derive(Copy, Clone)]
960pub enum NetCfgAdvanced {}
961
962impl Manager for NetCfgAdvanced {
963 const MANAGEMENT_AGENT: ManagementAgent = ManagementAgent::NetCfg(NetCfgVersion::Advanced);
964}
965
966pub use netemul::{DhcpClient, DhcpClientVersion, InStack, OutOfStack};
967
968pub trait NetstackAndDhcpClient: Copy + Clone {
971 type Netstack: Netstack;
973 type DhcpClient: DhcpClient;
975}
976
977#[derive(Copy, Clone)]
979pub enum Netstack2AndInStackDhcpClient {}
980
981impl NetstackAndDhcpClient for Netstack2AndInStackDhcpClient {
982 type Netstack = Netstack2;
983 type DhcpClient = InStack;
984}
985
986#[derive(Copy, Clone)]
988pub enum Netstack2AndOutOfStackDhcpClient {}
989
990impl NetstackAndDhcpClient for Netstack2AndOutOfStackDhcpClient {
991 type Netstack = Netstack2;
992 type DhcpClient = OutOfStack;
993}
994
995#[derive(Copy, Clone)]
997pub enum Netstack3AndOutOfStackDhcpClient {}
998
999impl NetstackAndDhcpClient for Netstack3AndOutOfStackDhcpClient {
1000 type Netstack = Netstack3;
1001 type DhcpClient = OutOfStack;
1002}
1003
1004#[async_trait]
1006pub trait TestSandboxExt {
1007 fn create_netstack_realm<'a, N, S>(&'a self, name: S) -> Result<netemul::TestRealm<'a>>
1009 where
1010 N: Netstack,
1011 S: Into<Cow<'a, str>>;
1012
1013 fn create_netstack_realm_with<'a, N, S, I>(
1016 &'a self,
1017 name: S,
1018 children: I,
1019 ) -> Result<netemul::TestRealm<'a>>
1020 where
1021 S: Into<Cow<'a, str>>,
1022 N: Netstack,
1023 I: IntoIterator,
1024 I::Item: Into<fnetemul::ChildDef>;
1025}
1026
1027#[async_trait]
1028impl TestSandboxExt for netemul::TestSandbox {
1029 fn create_netstack_realm<'a, N, S>(&'a self, name: S) -> Result<netemul::TestRealm<'a>>
1030 where
1031 N: Netstack,
1032 S: Into<Cow<'a, str>>,
1033 {
1034 self.create_netstack_realm_with::<N, _, _>(name, std::iter::empty::<fnetemul::ChildDef>())
1035 }
1036
1037 fn create_netstack_realm_with<'a, N, S, I>(
1038 &'a self,
1039 name: S,
1040 children: I,
1041 ) -> Result<netemul::TestRealm<'a>>
1042 where
1043 S: Into<Cow<'a, str>>,
1044 N: Netstack,
1045 I: IntoIterator,
1046 I::Item: Into<fnetemul::ChildDef>,
1047 {
1048 self.create_realm(
1049 name,
1050 [KnownServiceProvider::Netstack(N::VERSION)]
1051 .iter()
1052 .map(fnetemul::ChildDef::from)
1053 .chain(children.into_iter().map(Into::into)),
1054 )
1055 }
1056}
1057
1058#[async_trait]
1060pub trait TestRealmExt {
1061 async fn loopback_properties(
1064 &self,
1065 ) -> Result<Option<fnet_interfaces_ext::Properties<fnet_interfaces_ext::AllInterest>>>;
1066
1067 fn interface_control(&self, id: u64) -> Result<fnet_interfaces_ext::admin::Control>;
1074}
1075
1076#[async_trait]
1077impl TestRealmExt for netemul::TestRealm<'_> {
1078 async fn loopback_properties(
1079 &self,
1080 ) -> Result<Option<fnet_interfaces_ext::Properties<fnet_interfaces_ext::AllInterest>>> {
1081 let interface_state = self
1082 .connect_to_protocol::<fnet_interfaces::StateMarker>()
1083 .context("failed to connect to fuchsia.net.interfaces/State")?;
1084
1085 let properties = fnet_interfaces_ext::existing(
1086 fnet_interfaces_ext::event_stream_from_state(&interface_state, Default::default())
1087 .expect("create watcher event stream"),
1088 HashMap::<u64, fnet_interfaces_ext::PropertiesAndState<(), _>>::new(),
1089 )
1090 .await
1091 .context("failed to get existing interface properties from watcher")?
1092 .into_iter()
1093 .find_map(|(_id, properties_and_state): (u64, _)| {
1094 let fnet_interfaces_ext::PropertiesAndState {
1095 properties: properties @ fnet_interfaces_ext::Properties { port_class, .. },
1096 state: (),
1097 } = properties_and_state;
1098 port_class.is_loopback().then_some(properties)
1099 });
1100 Ok(properties)
1101 }
1102
1103 fn interface_control(&self, id: u64) -> Result<fnet_interfaces_ext::admin::Control> {
1104 let root_control = self
1105 .connect_to_protocol::<fnet_root::InterfacesMarker>()
1106 .context("connect to protocol")?;
1107
1108 let (control, server) = fnet_interfaces_ext::admin::Control::create_endpoints()
1109 .context("create Control proxy")?;
1110 let () = root_control.get_admin(id, server).context("get admin")?;
1111 Ok(control)
1112 }
1113}