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