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