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