1#![warn(clippy::unused_async)]
7#![warn(missing_docs, unreachable_patterns, unused)]
8#![recursion_limit = "256"]
9
10mod bindings;
11
12use std::num::NonZeroU8;
13
14use fidl::endpoints::RequestStream as _;
15use fidl_fuchsia_process_lifecycle as fprocess_lifecycle;
16use fuchsia_async as fasync;
17use fuchsia_async::SendExecutorBuilder;
18use fuchsia_component::server::{ServiceFs, ServiceFsDir};
19use futures::{Future, StreamExt as _};
20use log::{error, info};
21
22use bindings::{GlobalConfig, InspectPublisher, InterfaceConfigDefaults, NetstackSeed, Service};
23
24pub fn main() {
26 let config = ns3_config::Config::take_from_startup_handle();
27 let ns3_config::Config {
28 num_threads,
29 debug_logs,
30 opaque_iids,
31 suspend_enabled,
32 sampled_stats_enabled,
33 multi_vmo,
34 } = &config;
35 let num_threads = NonZeroU8::new(*num_threads).expect("invalid 0 thread count value");
36 let mut executor = SendExecutorBuilder::new().num_threads(num_threads.get().into()).build();
37
38 let mut log_options = diagnostics_log::PublishOptions::default();
39
40 log_options = log_options.tags(&["netstack"]);
46
47 if *debug_logs {
48 log_options = log_options
51 .minimum_severity(diagnostics_log::Severity::Debug)
52 .listen_for_interest_updates(false);
53 }
54 diagnostics_log::initialize(log_options).expect("failed to initialize log");
55
56 fuchsia_trace_provider::trace_provider_create_with_fdio();
57
58 info!("starting netstack3 with {config:?}");
59
60 let mut fs = ServiceFs::new();
61 let _: &mut ServiceFsDir<'_, _> = fs
62 .dir("svc")
63 .add_proxy_service::<fidl_fuchsia_net_dhcp::ClientProviderMarker, _>()
70 .add_fidl_service(Service::Control)
71 .add_service_connector(Service::DebugDiagnostics)
72 .add_fidl_service(Service::DebugInterfaces)
73 .add_fidl_service(Service::DnsServerWatcher)
74 .add_fidl_service(Service::FilterControl)
75 .add_fidl_service(Service::FilterState)
76 .add_fidl_service(Service::HealthCheck)
77 .add_fidl_service(Service::Interfaces)
78 .add_fidl_service(Service::InterfacesAdmin)
79 .add_fidl_service(Service::MulticastAdminV4)
80 .add_fidl_service(Service::MulticastAdminV6)
81 .add_fidl_service(Service::NdpWatcher)
82 .add_fidl_service(Service::Neighbor)
83 .add_fidl_service(Service::NeighborController)
84 .add_fidl_service(Service::PacketSocket)
85 .add_fidl_service(Service::PacketCapture)
86 .add_fidl_service(Service::RawSocket)
87 .add_fidl_service(Service::RootFilter)
88 .add_fidl_service(Service::RootInterfaces)
89 .add_fidl_service(Service::RootRoutesV4)
90 .add_fidl_service(Service::RootRoutesV6)
91 .add_fidl_service(Service::RoutesAdminV4)
92 .add_fidl_service(Service::RoutesAdminV6)
93 .add_fidl_service(Service::RoutesState)
94 .add_fidl_service(Service::RoutesStateV4)
95 .add_fidl_service(Service::RoutesStateV6)
96 .add_fidl_service(Service::RouteTableProviderV4)
97 .add_fidl_service(Service::RouteTableProviderV6)
98 .add_fidl_service(Service::RuleTableV4)
99 .add_fidl_service(Service::RuleTableV6)
100 .add_fidl_service(Service::SettingsControl)
101 .add_fidl_service(Service::SettingsState)
102 .add_fidl_service(Service::Socket)
103 .add_fidl_service(Service::SocketControl)
104 .add_fidl_service(Service::SocketDiagnostics)
105 .add_fidl_service(Service::Stack)
106 .add_fidl_service(Service::WakeGroupProvider);
107
108 let seed = NetstackSeed::new(
109 GlobalConfig {
110 suspend_enabled: *suspend_enabled,
111 sampled_stats_enabled: *sampled_stats_enabled,
112 multi_vmo: *multi_vmo,
113 },
114 &InterfaceConfigDefaults { opaque_iids: *opaque_iids },
115 );
116
117 let inspect_publisher = InspectPublisher::new();
118 inspect_publisher
119 .inspector()
120 .root()
121 .record_child("Config", |config_node| config.record_inspect(config_node));
122
123 let _: &mut ServiceFs<_> = fs.take_and_serve_directory_handle().expect("directory handle");
124
125 let fs = fs.take_until(get_lifecycle_stop_fut());
127
128 executor.run(seed.serve(fs, inspect_publisher))
129}
130
131fn get_lifecycle_stop_fut() -> impl Future<Output = ()> {
134 const LIFECYCLE_HANDLE_ARG: u16 = 0;
137 let handle = fuchsia_runtime::take_startup_handle(fuchsia_runtime::HandleInfo::new(
138 fuchsia_runtime::HandleType::Lifecycle,
139 LIFECYCLE_HANDLE_ARG,
140 ))
141 .expect("missing lifecycle handle");
142
143 async move {
144 let mut request_stream = fprocess_lifecycle::LifecycleRequestStream::from_channel(
145 fasync::Channel::from_channel(handle.into()).into(),
146 );
147 loop {
148 match request_stream.next().await {
149 Some(Ok(fprocess_lifecycle::LifecycleRequest::Stop { control_handle })) => {
150 info!("received shutdown request");
151 std::mem::drop(control_handle);
160 let (inner, _terminated): (_, bool) = request_stream.into_inner();
161 let inner = std::sync::Arc::try_unwrap(inner)
162 .expect("failed to retrieve lifecycle channel");
163 let inner: zx::Channel = inner.into_channel().into_zx_channel();
164 std::mem::forget(inner);
165 break;
166 }
167 Some(Err(e)) => error!("observed error in lifecycle request stream: {e:?}"),
168 None => {
169 error!("lifecycle channel closed");
173 futures::future::pending::<()>().await;
174 }
175 }
176 }
177 }
178}