1#![warn(clippy::unused_async)]
7#![warn(missing_docs, unreachable_patterns, unused)]
8#![recursion_limit = "512"]
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, warn};
21
22use bindings::{GlobalConfig, InspectPublisher, InterfaceConfigDefaults, NetstackSeed, Service};
23
24pub fn main() {
26 let mut config = ns3_config::Config::take_from_startup_handle();
27 if config.max_rolling_capture_buffer_size < fidl_fuchsia_net_debug::MIN_BUFFER_SIZE {
28 warn!(
29 "max rolling capture buffer size configured as {} will be clamped to the minimum {}",
30 config.max_rolling_capture_buffer_size,
31 fidl_fuchsia_net_debug::MIN_BUFFER_SIZE,
32 );
33 config.max_rolling_capture_buffer_size = fidl_fuchsia_net_debug::MIN_BUFFER_SIZE;
34 };
35 let ns3_config::Config {
36 num_threads,
37 debug_logs,
38 opaque_iids,
39 suspend_enabled,
40 sampled_stats_enabled,
41 multi_vmo,
42 max_rolling_capture_buffer_size,
43 } = &config;
44 let num_threads = NonZeroU8::new(*num_threads).expect("invalid 0 thread count value");
45 let mut executor = SendExecutorBuilder::new().num_threads(num_threads.get().into()).build();
46
47 let mut log_options = diagnostics_log::PublishOptions::default();
48
49 log_options = log_options.tags(&["netstack"]);
55
56 if *debug_logs {
57 log_options = log_options
60 .minimum_severity(diagnostics_log::Severity::Debug)
61 .listen_for_interest_updates(false);
62 }
63 diagnostics_log::initialize(log_options).expect("failed to initialize log");
64
65 fuchsia_trace_provider::trace_provider_create_with_fdio();
66
67 info!("starting netstack3 with {config:?}");
68
69 let mut fs = ServiceFs::new();
70 let _: &mut ServiceFsDir<'_, _> = fs
71 .dir("svc")
72 .add_proxy_service::<fidl_fuchsia_net_dhcp::ClientProviderMarker, _>()
79 .add_fidl_service(Service::Control)
80 .add_service_connector(Service::DebugDiagnostics)
81 .add_fidl_service(Service::DebugInterfaces)
82 .add_fidl_service(Service::DnsServerWatcher)
83 .add_fidl_service(Service::FilterControl)
84 .add_fidl_service(Service::FilterState)
85 .add_fidl_service(Service::HealthCheck)
86 .add_fidl_service(Service::Interfaces)
87 .add_fidl_service(Service::InterfacesAdmin)
88 .add_fidl_service(Service::MulticastAdminV4)
89 .add_fidl_service(Service::MulticastAdminV6)
90 .add_fidl_service(Service::NdpWatcher)
91 .add_fidl_service(Service::Neighbor)
92 .add_fidl_service(Service::NeighborController)
93 .add_fidl_service(Service::PacketSocket)
94 .add_fidl_service(Service::PacketCapture)
95 .add_fidl_service(Service::RawSocket)
96 .add_fidl_service(Service::RootFilter)
97 .add_fidl_service(Service::RootInterfaces)
98 .add_fidl_service(Service::RootRoutesV4)
99 .add_fidl_service(Service::RootRoutesV6)
100 .add_fidl_service(Service::RoutesAdminV4)
101 .add_fidl_service(Service::RoutesAdminV6)
102 .add_fidl_service(Service::RoutesState)
103 .add_fidl_service(Service::RoutesStateV4)
104 .add_fidl_service(Service::RoutesStateV6)
105 .add_fidl_service(Service::RouteTableProviderV4)
106 .add_fidl_service(Service::RouteTableProviderV6)
107 .add_fidl_service(Service::RuleTableV4)
108 .add_fidl_service(Service::RuleTableV6)
109 .add_fidl_service(Service::SettingsControl)
110 .add_fidl_service(Service::SettingsState)
111 .add_fidl_service(Service::Socket)
112 .add_fidl_service(Service::SocketControl)
113 .add_fidl_service(Service::SocketDiagnostics)
114 .add_fidl_service(Service::Stack)
115 .add_fidl_service(Service::WakeGroupProvider);
116
117 let seed = NetstackSeed::new(
118 GlobalConfig {
119 suspend_enabled: *suspend_enabled,
120 sampled_stats_enabled: *sampled_stats_enabled,
121 multi_vmo: *multi_vmo,
122 max_rolling_capture_buffer_size: *max_rolling_capture_buffer_size,
123 },
124 &InterfaceConfigDefaults { opaque_iids: *opaque_iids },
125 );
126
127 let inspect_publisher = InspectPublisher::new();
128 inspect_publisher
129 .inspector()
130 .root()
131 .record_child("Config", |config_node| config.record_inspect(config_node));
132
133 let _: &mut ServiceFs<_> = fs.take_and_serve_directory_handle().expect("directory handle");
134
135 let fs = fs.take_until(get_lifecycle_stop_fut());
137
138 executor.run(seed.serve(fs, inspect_publisher))
139}
140
141fn get_lifecycle_stop_fut() -> impl Future<Output = ()> {
144 const LIFECYCLE_HANDLE_ARG: u16 = 0;
147 let handle = fuchsia_runtime::take_startup_handle(fuchsia_runtime::HandleInfo::new(
148 fuchsia_runtime::HandleType::Lifecycle,
149 LIFECYCLE_HANDLE_ARG,
150 ))
151 .expect("missing lifecycle handle");
152
153 async move {
154 let mut request_stream = fprocess_lifecycle::LifecycleRequestStream::from_channel(
155 fasync::Channel::from_channel(handle.into()).into(),
156 );
157 loop {
158 match request_stream.next().await {
159 Some(Ok(fprocess_lifecycle::LifecycleRequest::Stop { control_handle })) => {
160 info!("received shutdown request");
161 std::mem::drop(control_handle);
170 let (inner, _terminated): (_, bool) = request_stream.into_inner();
171 let inner = std::sync::Arc::try_unwrap(inner)
172 .expect("failed to retrieve lifecycle channel");
173 let inner: zx::Channel = inner.into_channel().into_zx_channel();
174 std::mem::forget(inner);
175 break;
176 }
177 Some(Err(e)) => error!("observed error in lifecycle request stream: {e:?}"),
178 None => {
179 error!("lifecycle channel closed");
183 futures::future::pending::<()>().await;
184 }
185 }
186 }
187 }
188}