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