1#![no_std]
36
37#[macro_use]
38extern crate log;
39extern crate alloc;
40#[cfg(all(test, not(target_os = "none")))]
41extern crate ax_runtime as _;
42#[cfg(test)]
43extern crate std;
44
45mod addr;
46mod config;
47mod consts;
48mod device;
49mod dhcp_server;
50mod error;
51mod general;
52mod ip_tos;
53mod listen_table;
54pub mod options;
56mod orphan;
57mod poll_runtime;
58mod queue_runtime;
59pub mod raw;
61mod readiness;
62mod router;
63mod rx_meta;
64mod service;
65mod socket;
66pub(crate) mod state;
67pub mod tcp;
69pub mod udp;
71pub mod unix;
73#[cfg(feature = "vsock")]
75pub mod vsock;
76mod wrapper;
77
78use alloc::{
79 borrow::ToOwned, boxed::Box, format, string::String, sync::Arc, task::Wake, vec, vec::Vec,
80};
81use core::{
82 net::{IpAddr, Ipv4Addr},
83 sync::atomic::{AtomicBool, AtomicU8, AtomicU64, Ordering},
84 time::Duration,
85};
86
87use ax_lazyinit::{LazyLock, OnceLock};
88use ax_sync::Mutex;
89use axpoll::IoEvents;
90use axpoll_set::PollSet;
91pub use error::{NetError, NetResult};
92use rand_chacha::ChaCha20Rng;
93use rand_core::{RngCore, SeedableRng};
94pub use rd_net::{WifiLinkPolicy, WifiOperation, WifiTransaction, Wpa2Pmk};
95use smoltcp::{
96 socket::dns::{self, GetQueryResultError, StartQueryError},
97 wire::{DnsQueryType, EthernetAddress, IpAddress, Ipv4Address, Ipv4Cidr},
98};
99
100#[cfg(feature = "vsock")]
101pub use self::device::{VsockDevice, VsockDeviceInput, VsockDeviceList, VsockRuntimeError};
102use self::{
103 addr::mask_from_prefix,
104 device::{EthernetDevice, LoopbackDevice},
105 listen_table::ListenTable,
106 poll_runtime::{ProtocolPollBudget, ProtocolPollRuntime},
107 router::{RouteTable, Router, Rule, SharedRouteTable},
108 service::{NetControl, NetInterface, Service},
109 wrapper::SocketSetWrapper,
110};
111pub use self::{
112 config::{
113 DeviceBinding, InterfaceConfig, InterfaceFlags, InterfaceId, InterfaceInfo, InterfaceKind,
114 InterfaceMatcher, Ipv4InterfaceConfig, NetworkConfig, RouteInfo, StaticIpConfig,
115 },
116 device::{ArpEntry, EthernetFramePort, EthernetFramePortList, NetDeviceError, NetDeviceResult},
117 queue_runtime::{
118 NetQueueStats, NetworkDeviceInput, NetworkQueueRuntime, NetworkRuntimeBuilder,
119 NetworkRuntimeError, PinnedNetIrqAction, PinnedNetIrqError, PinnedNetIrqOutcome,
120 PinnedNetIrqRegistrar, PinnedNetIrqRegistration, ResolvedNetIrqSource, TxQueueDiscipline,
121 },
122 readiness::poll_socket_io,
123 router::NetDevStats,
124 socket::{
125 CMsgData, ConnectStatus, IpCmsg, RecvFlags, RecvOptions, SendFlags, SendOptions, Shutdown,
126 Socket, SocketAddrEx, SocketCmsg, SocketOps, SocketWaitPolicy,
127 },
128};
129
130static LISTEN_TABLE: LazyLock<ListenTable> = LazyLock::new(ListenTable::new);
131static SOCKET_SET: LazyLock<SocketSetWrapper> = LazyLock::new(SocketSetWrapper::new);
132
133static SERVICE: OnceLock<Mutex<Service>> = OnceLock::new();
134static NET_CONTROL: OnceLock<Arc<NetControl>> = OnceLock::new();
135static QUEUE_RUNTIME: OnceLock<Mutex<NetworkQueueRuntime>> = OnceLock::new();
136static WIFI_INTERFACES: OnceLock<Vec<WifiInterfaceControl>> = OnceLock::new();
137static WIFI_ENTROPY: OnceLock<Mutex<WifiEntropy>> = OnceLock::new();
138static PROTOCOL_POLL: ProtocolPollRuntime = ProtocolPollRuntime::new();
139static PROTOCOL_AFFINITY_STATUS: AtomicU8 = AtomicU8::new(0);
140type DeferredPollEntry = (Arc<PollSet>, IoEvents);
141static DEFERRED_POLL_WAKE_PENDING: AtomicBool = AtomicBool::new(false);
142static DEFERRED_POLL_WAKES: LazyLock<Mutex<Vec<DeferredPollEntry>>> =
143 LazyLock::new(|| Mutex::new(Vec::new()));
144
145struct WifiInterfaceControl {
146 ifname: alloc::string::String,
147 device_index: usize,
148 mac: EthernetAddress,
149 handle: queue_runtime::WifiRuntimeHandle,
150}
151
152struct WifiEntropy {
153 generator: ChaCha20Rng,
154}
155
156impl WifiEntropy {
157 fn from_seed(seed: [u8; 32]) -> Self {
158 Self {
159 generator: ChaCha20Rng::from_seed(seed),
160 }
161 }
162
163 fn next_connection_entropy(&mut self) -> [u8; 32] {
164 let mut entropy = [0; 32];
165 self.generator.fill_bytes(&mut entropy);
166 entropy
167 }
168}
169
170fn next_wifi_connection_entropy() -> NetResult<[u8; 32]> {
171 if WIFI_ENTROPY.get().is_none() {
172 let seed = ax_hal::boot::boot_entropy().ok_or(NetError::EntropyUnavailable)?;
173 WIFI_ENTROPY.call_once(|| Mutex::new(WifiEntropy::from_seed(seed)));
174 }
175 Ok(WIFI_ENTROPY
176 .get()
177 .expect("Wi-Fi entropy was initialized above")
178 .lock()
179 .next_connection_entropy())
180}
181
182pub(crate) struct DeferPollWake {
183 pub(crate) poll: Arc<PollSet>,
184 pub(crate) ready: IoEvents,
185}
186
187impl Wake for DeferPollWake {
188 fn wake(self: Arc<Self>) {
189 self.wake_by_ref();
190 }
191
192 fn wake_by_ref(self: &Arc<Self>) {
193 defer_poll_wake(self.poll.clone(), self.ready);
197 }
198}
199
200#[derive(Clone)]
201pub(crate) struct ReadinessVersion(Arc<AtomicU64>);
202
203impl ReadinessVersion {
204 pub(crate) fn new() -> Self {
205 Self(Arc::new(AtomicU64::new(0)))
206 }
207
208 pub(crate) fn publish(&self) {
209 self.0.fetch_add(1, Ordering::Release);
212 }
213
214 pub(crate) fn current(&self) -> u64 {
215 self.0.load(Ordering::Acquire)
216 }
217}
218
219pub(crate) struct SocketDeferPollWake {
220 poll: Arc<PollSet>,
221 ready: IoEvents,
222 readiness_version: ReadinessVersion,
223}
224
225impl SocketDeferPollWake {
226 pub(crate) fn new(
227 poll: Arc<PollSet>,
228 ready: IoEvents,
229 readiness_version: ReadinessVersion,
230 ) -> Self {
231 Self {
232 poll,
233 ready,
234 readiness_version,
235 }
236 }
237}
238
239impl Wake for SocketDeferPollWake {
240 fn wake(self: Arc<Self>) {
241 self.wake_by_ref();
242 }
243
244 fn wake_by_ref(self: &Arc<Self>) {
245 self.readiness_version.publish();
246 defer_poll_wake(self.poll.clone(), self.ready);
247 }
248}
249
250pub(crate) const fn receive_starts_next_edge(consumed: usize, remaining: usize) -> bool {
251 consumed != 0 && remaining == 0
252}
253
254const DHCP_BOOTSTRAP_TIMEOUT: Duration = Duration::from_secs(2);
255
256fn get_service() -> ax_sync::MutexGuard<'static, Service> {
257 SERVICE
258 .get()
259 .expect("Network service not initialized")
260 .lock()
261}
262
263pub(crate) fn get_control() -> &'static NetControl {
264 NET_CONTROL
265 .get()
266 .expect("Network service not initialized")
267 .as_ref()
268}
269
270fn map_driver_net_error(error: rd_net::NetError) -> NetError {
271 match error {
272 rd_net::NetError::DeviceNotPresent => NetError::NoSuchDevice,
273 rd_net::NetError::NotSupported | rd_net::NetError::IrqUnavailable => {
274 NetError::OperationNotSupported
275 }
276 rd_net::NetError::Retry => NetError::ResourceBusy,
277 rd_net::NetError::NoMemory => NetError::NoMemory,
278 rd_net::NetError::LinkDown => NetError::NoSuchDeviceOrAddress,
279 rd_net::NetError::InvalidParts => NetError::InvalidData,
280 rd_net::NetError::Stopped | rd_net::NetError::DmaShutdownUnconfirmed => NetError::BadState,
281 rd_net::NetError::Other(_) => NetError::BackendIo,
282 }
283}
284
285pub fn reconfigure_wifi(ifname: &str, mut transaction: WifiTransaction) -> NetResult {
291 let interface = WIFI_INTERFACES
292 .get()
293 .and_then(|interfaces| {
294 interfaces
295 .iter()
296 .find(|interface| interface.ifname == ifname)
297 })
298 .ok_or(NetError::NoSuchDevice)?;
299
300 if transaction.needs_connect_entropy() {
301 transaction.provide_connect_entropy(next_wifi_connection_entropy()?);
302 log::info!("[wifi] {ifname}: secure connection entropy prepared");
303 }
304
305 log::info!("[wifi] {ifname}: submitting control transaction");
306 if let Err(error) = interface.handle.submit(transaction.clone()) {
307 log::error!("[wifi] {ifname}: control transaction failed: {error:?}");
308 return Err(map_driver_net_error(error));
309 }
310 log::info!("[wifi] {ifname}: control transaction complete");
311
312 let mut service = get_service();
313 match transaction.operation() {
314 WifiOperation::Connect { .. } => {
315 service.reconfigure_as_sta(interface.device_index, interface.mac);
316 }
317 WifiOperation::Disconnect => {
318 service.reconfigure_as_disconnected(interface.device_index);
319 }
320 WifiOperation::StartOpenAccessPoint { .. } => {
321 let policy = transaction.link_policy().ok_or(NetError::InvalidInput)?;
322 service.reconfigure_as_ap(
323 interface.device_index,
324 Ipv4Address::from(policy.ip),
325 policy.prefix_len,
326 policy.dhcp_server_client_ip.map(Ipv4Address::from),
327 );
328 }
329 }
330 drop(service);
331 request_poll();
332 Ok(())
333}
334
335#[cfg(test)]
336mod wifi_entropy_tests {
337 use alloc::boxed::Box;
338
339 use super::{NetError, WifiEntropy, default_interface_name, map_driver_net_error};
340
341 #[test]
342 fn one_seed_produces_unique_entropy_for_each_connection() {
343 let mut source = WifiEntropy::from_seed([0x5a; 32]);
344 let first = source.next_connection_entropy();
345 let second = source.next_connection_entropy();
346 assert_ne!(first, second);
347 assert_ne!(first, [0; 32]);
348 assert_ne!(second, [0; 32]);
349 }
350
351 #[test]
352 fn wifi_capability_preserves_the_driver_registered_interface_name() {
353 assert_eq!(default_interface_name(0, "wlan0", true), "wlan0");
354 assert_eq!(default_interface_name(0, "virtio-net", false), "eth0");
355 }
356
357 #[test]
358 fn driver_io_failures_do_not_become_bad_user_addresses() {
359 let driver_error = rd_net::NetError::Other(Box::new(ax_io::IoError::Io));
360 assert_eq!(map_driver_net_error(driver_error), NetError::BackendIo);
361 }
362
363 #[test]
364 fn missing_driver_device_maps_to_no_such_device() {
365 assert_eq!(
366 map_driver_net_error(rd_net::NetError::DeviceNotPresent),
367 NetError::NoSuchDevice
368 );
369 }
370}
371
372pub fn init_network(
378 queue_runtime: NetworkQueueRuntime,
379 mut frame_ports: EthernetFramePortList,
380 config: NetworkConfig,
381) {
382 if SERVICE.get().is_some() {
383 panic!("init_network() called more than once");
384 }
385
386 info!("Initialize network subsystem...");
387
388 validate_config(&config);
389
390 let routes: SharedRouteTable = Arc::new(ax_sync::SpinRwLock::new(RouteTable::new()));
391 let mut router = Router::new(routes.clone());
392 let mut interfaces = Vec::new();
393 let mut dns = Vec::new();
394
395 let lo_ip = register_loopback(&mut router, &mut interfaces);
396
397 if frame_ports.is_empty() {
398 warn!(" No network device found!");
399 }
400
401 let mut used_configs = vec![false; config.interfaces.len()];
402 let mut dhcp_ifaces = Vec::new();
403 let mut eth_ips = Vec::new();
404 let mut wifi_dhcp_servers = Vec::new();
405 let mut wifi_interfaces = Vec::new();
406
407 for (order, dev) in frame_ports.drain(..).enumerate() {
408 info!(" use NIC {}: {:?}", order, dev.device_name());
409 let wifi_capable = queue_runtime.wifi_handle(order).is_some();
410 let default_name = default_interface_name(order, dev.device_name(), wifi_capable);
411 let mac = EthernetAddress(dev.mac_address());
412 let cfg_idx = find_interface_config(
413 &config.interfaces,
414 &mut used_configs,
415 queue_runtime.discovery_order(order),
416 mac,
417 dev.device_name(),
418 );
419 let cfg = cfg_idx.map(|idx| &config.interfaces[idx]);
420 let name = cfg.map_or(default_name, |cfg| cfg.name.clone());
421 if interfaces.iter().any(|interface| interface.name == name) {
422 panic!("interface name conflict: {}", name);
423 }
424 let id = InterfaceId::new((order as u32) + 2);
425 let metric = cfg.map_or(100, |cfg| cfg.metric);
426 let wifi_policy = queue_runtime.initial_wifi_policy(order);
427 let static_ip = cfg.and_then(|cfg| cfg.static_ip.as_ref());
428 let ipv4 = static_ip
429 .map(|cfg| Ipv4Cidr::new(Ipv4Address::from(cfg.ip.octets()), cfg.prefix_len))
430 .or_else(|| {
431 (cfg.is_none())
432 .then_some(wifi_policy)
433 .flatten()
434 .map(|policy| Ipv4Cidr::new(Ipv4Address::from(policy.ip), policy.prefix_len))
435 });
436 let gateway = static_ip.and_then(|cfg| {
437 (!cfg.gateway.is_unspecified()).then(|| Ipv4Address::from(cfg.gateway.octets()))
438 });
439 let dhcp_enabled = cfg.map_or(wifi_policy.is_none(), |cfg| cfg.dhcp);
440 let eth_dev = router.add_device(id, Box::new(EthernetDevice::new(name.clone(), dev, ipv4)));
441
442 if let Some(handle) = queue_runtime.wifi_handle(order) {
443 info!(
444 " Wi-Fi control for {name} is owned by CPU {}",
445 handle.owner_cpu()
446 );
447 wifi_interfaces.push(WifiInterfaceControl {
448 ifname: name.clone(),
449 device_index: order,
450 mac,
451 handle,
452 });
453 }
454
455 info!("{name}:");
456 info!(" id: {}", id.get());
457 info!(" mac: {}", mac);
458 if let Some(ipv4) = ipv4 {
459 router.set_ipv4_config(
460 eth_dev,
461 id,
462 metric,
463 Some(ipv4),
464 gateway.map(IpAddress::Ipv4),
465 );
466 eth_ips.push(ipv4);
467 info!(" mode: static");
468 info!(" ip: {}/{}", ipv4.address(), ipv4.prefix_len());
469 if let Some(gateway) = gateway {
470 info!(" gw: {}", gateway);
471 }
472 } else if dhcp_enabled {
473 dhcp_ifaces.push((id, eth_dev, name.clone(), mac, metric));
474 info!(" mode: dhcp");
475 } else {
476 info!(" mode: none");
477 }
478 if cfg.is_none()
479 && let Some(policy) = wifi_policy
480 && let Some(client_ip) = policy.dhcp_server_client_ip
481 {
482 wifi_dhcp_servers.push((
483 order,
484 Ipv4Address::from(policy.ip),
485 Ipv4Address::from(client_ip),
486 mask_from_prefix(policy.prefix_len),
487 ));
488 }
489 if let Some(cfg) = cfg {
490 dns.extend(
491 cfg.dns_servers
492 .iter()
493 .copied()
494 .map(|server| config::DnsServerEntry {
495 server: Ipv4Address::from(server.octets()),
496 interface_id: id,
497 metric,
498 source: config::DnsSource::Static,
499 }),
500 );
501 }
502 interfaces.push(NetInterface {
503 id,
504 name,
505 kind: InterfaceKind::Ethernet,
506 mac: Some(mac),
507 ipv4,
508 gateway,
509 mtu: consts::STANDARD_MTU,
510 metric,
511 flags: InterfaceFlags::UP
512 | InterfaceFlags::RUNNING
513 | InterfaceFlags::BROADCAST
514 | InterfaceFlags::MULTICAST,
515 });
516 }
517
518 ensure_all_interface_configs_used(&config, &used_configs);
519
520 add_default_dns_servers(&config, &mut dns);
521
522 for name in router.device_names() {
523 info!("Device: {}", name);
524 }
525 let control = Arc::new(NetControl::new(interfaces, routes, dns));
526 let mut service = Service::new(router, control.clone());
527 service.iface.update_ip_addrs(|ip_addrs| {
528 ip_addrs.push(lo_ip.into()).unwrap();
529 for ip in eth_ips {
530 ip_addrs.push(ip.into()).unwrap();
531 }
532 });
533 for (id, dev, name, mac, metric) in dhcp_ifaces {
534 service.enable_dhcp(id, dev, name, mac, metric);
535 }
536 for (dev, server_ip, client_ip, subnet_mask) in wifi_dhcp_servers {
537 service.enable_dhcp_server(dev, server_ip, client_ip, subnet_mask);
538 }
539 let dhcp_enabled = service.dhcp_enabled();
540 let protocol_owner_cpu = queue_runtime.protocol_owner_cpu();
541 NET_CONTROL.call_once(|| control);
542 SERVICE.call_once(|| Mutex::new(service));
543 WIFI_INTERFACES.call_once(|| wifi_interfaces);
544 QUEUE_RUNTIME.call_once(|| Mutex::new(queue_runtime));
545 start_protocol_executor(protocol_owner_cpu);
546 if dhcp_enabled {
547 wait_for_dhcp_bootstrap();
548 }
549}
550
551fn validate_config(config: &NetworkConfig) {
552 for cfg in &config.interfaces {
553 if cfg.name == "lo" {
554 panic!("interface name 'lo' is reserved");
555 }
556 if cfg.dhcp && cfg.static_ip.is_some() {
557 panic!(
558 "interface {} has both DHCP and static IP configured",
559 cfg.name
560 );
561 }
562 if let Some(static_cfg) = &cfg.static_ip {
563 if static_cfg.ip.is_unspecified() {
564 panic!("Invalid static IP for {}: unspecified address", cfg.name);
565 }
566 if static_cfg.prefix_len > 32 {
567 panic!("Invalid static IP for {}: prefix length > 32", cfg.name);
568 }
569 }
570 for (i, dns) in cfg.dns_servers.iter().enumerate() {
571 if dns.is_unspecified() {
572 panic!(
573 "Invalid DNS server for {} at index {}: unspecified address",
574 cfg.name, i
575 );
576 }
577 }
578 }
579 for (i, dns) in config.default_dns_servers.iter().enumerate() {
580 if dns.is_unspecified() {
581 panic!("Invalid DNS server at index {}: unspecified address", i);
582 }
583 }
584}
585
586fn register_loopback(router: &mut Router, interfaces: &mut Vec<NetInterface>) -> Ipv4Cidr {
587 let lo_id = InterfaceId::LOOPBACK;
588 let lo_dev = router.add_device(lo_id, Box::new(LoopbackDevice::new()));
589
590 let lo_ip = Ipv4Cidr::new(Ipv4Address::new(127, 0, 0, 1), 8);
591 router.add_rule(Rule::new(
592 lo_ip.into(),
593 None,
594 lo_dev,
595 lo_id,
596 lo_ip.address().into(),
597 0,
598 ));
599 interfaces.push(NetInterface {
600 id: lo_id,
601 name: "lo".to_owned(),
602 kind: InterfaceKind::Loopback,
603 mac: None,
604 ipv4: Some(lo_ip),
605 gateway: None,
606 mtu: consts::STANDARD_MTU,
607 metric: 0,
608 flags: InterfaceFlags::UP | InterfaceFlags::RUNNING | InterfaceFlags::LOOPBACK,
609 });
610 lo_ip
611}
612
613fn ensure_all_interface_configs_used(config: &NetworkConfig, used_configs: &[bool]) {
614 for (i, used) in used_configs.iter().enumerate() {
615 if !used {
616 panic!(
617 "interface config {} did not match any device",
618 config.interfaces[i].name
619 );
620 }
621 }
622}
623
624fn default_interface_name(order: usize, driver_name: &str, wifi_capable: bool) -> String {
625 if wifi_capable {
626 driver_name.into()
627 } else {
628 format!("eth{order}")
629 }
630}
631
632fn add_default_dns_servers(config: &NetworkConfig, dns: &mut Vec<config::DnsServerEntry>) {
633 dns.extend(
634 config
635 .default_dns_servers
636 .iter()
637 .copied()
638 .map(|server| config::DnsServerEntry {
639 server: Ipv4Address::from(server.octets()),
640 interface_id: InterfaceId::LOOPBACK,
641 metric: u32::MAX,
642 source: config::DnsSource::Fallback,
643 }),
644 );
645}
646
647fn find_interface_config(
648 configs: &[InterfaceConfig],
649 used: &mut [bool],
650 order: usize,
651 mac: EthernetAddress,
652 driver_name: &str,
653) -> Option<usize> {
654 let mut matched = None;
655 for (idx, cfg) in configs.iter().enumerate() {
656 if used[idx] {
657 continue;
658 }
659 let is_match = match &cfg.match_by {
660 InterfaceMatcher::ByOrder(expected) => *expected == order,
661 InterfaceMatcher::ByMac(expected) => *expected == mac,
662 InterfaceMatcher::ByDriverName(expected) => expected == driver_name,
663 };
664 if is_match {
665 if matched.is_some() {
666 panic!("multiple interface configs match device {}", driver_name);
667 }
668 matched = Some(idx);
669 }
670 }
671 if let Some(idx) = matched {
672 used[idx] = true;
673 }
674 matched
675}
676
677#[cfg(feature = "vsock")]
679pub fn init_vsock(
680 vsock_devs: device::VsockDeviceList,
681 registrar: &dyn PinnedNetIrqRegistrar,
682 active_cpus: ax_task::sched::CpuSet,
683) -> Result<(), VsockRuntimeError> {
684 info!("Initialize vsock subsystem...");
685 if vsock_devs.is_empty() {
686 warn!(" No vsock device found!");
687 return Ok(());
688 }
689 let owner_cpu = QUEUE_RUNTIME
690 .get()
691 .expect("vsock initialization requires the network queue runtime")
692 .lock()
693 .protocol_owner_cpu();
694 if !active_cpus.contains(ax_task::sched::CpuId::new(owner_cpu as u32)) {
695 return Err(VsockRuntimeError::InvalidTopology);
696 }
697 device::init_vsock_device(vsock_devs, registrar, owner_cpu, active_cpus.topology_len())
698}
699
700fn poll_protocol_until_idle(budget: &mut ProtocolPollBudget) {
701 loop {
702 let more = get_service().poll(&mut SOCKET_SET.inner.lock());
703 if budget.consume(ax_hal::time::monotonic_time_nanos()) {
704 drain_deferred_poll_wakes();
707 yield_network_thread();
708 budget.reset(ax_hal::time::monotonic_time_nanos());
709 }
710 if !more {
711 return;
712 }
713 }
714}
715
716pub fn request_poll() {
720 let _ = PROTOCOL_POLL.request();
721}
722
723pub(crate) fn flush_egress() {
733 let generation = PROTOCOL_POLL.request();
734 #[cfg(test)]
735 {
736 PROTOCOL_POLL.complete(generation);
740 }
741 #[cfg(not(test))]
742 PROTOCOL_POLL.wait_for_completion(generation);
743}
744
745pub(crate) fn defer_poll_wake(poll: Arc<PollSet>, ready: IoEvents) {
746 DEFERRED_POLL_WAKES.lock().push((poll, ready));
747 if !DEFERRED_POLL_WAKE_PENDING.swap(true, Ordering::AcqRel) {
748 PROTOCOL_POLL.schedule();
749 }
750}
751
752fn drain_deferred_poll_wakes() {
753 loop {
754 let wakes = {
755 let mut wakes = DEFERRED_POLL_WAKES.lock();
756 if wakes.is_empty() {
757 DEFERRED_POLL_WAKE_PENDING.store(false, Ordering::Release);
758 return;
759 }
760 core::mem::take(&mut *wakes)
761 };
762 for (poll, ready) in wakes {
763 unsafe { poll.wake(ready) };
766 }
767 }
768}
769
770pub fn arp_entries() -> Vec<ArpEntry> {
772 get_service().arp_entries()
773}
774
775pub fn net_dev_stats() -> Vec<NetDevStats> {
777 get_service().net_dev_stats()
778}
779
780pub fn interfaces() -> Vec<InterfaceInfo> {
782 get_control().interfaces()
783}
784
785pub fn interface_by_name(name: &str) -> Option<InterfaceInfo> {
787 get_control().interface_by_name(name)
788}
789
790pub fn interface_by_id(id: InterfaceId) -> Option<InterfaceInfo> {
792 get_control().interface_by_id(id)
793}
794
795pub fn ipv4_config(name: &str) -> Option<Ipv4InterfaceConfig> {
797 get_control().ipv4_config(name)
798}
799
800pub fn set_interface_ipv4(interface_id: InterfaceId, ip: Ipv4Addr, prefix_len: u8) -> NetResult {
802 {
803 let mut service = get_service();
804 service.configure_static_ipv4(interface_id, Ipv4Address::from(ip.octets()), prefix_len)?;
805 }
806 request_poll();
807 Ok(())
808}
809
810pub fn remove_interface_ipv4(interface_id: InterfaceId, ip: Ipv4Addr, prefix_len: u8) -> NetResult {
812 {
813 let mut service = get_service();
814 service.remove_static_ipv4(interface_id, Ipv4Address::from(ip.octets()), prefix_len)?;
815 }
816 request_poll();
817 Ok(())
818}
819
820pub fn default_routes() -> Vec<RouteInfo> {
822 get_control().default_routes()
823}
824
825fn next_poll_delay() -> Option<Duration> {
826 let next = {
827 let mut service = get_service();
828 let sockets = SOCKET_SET.inner.lock();
829 service.next_poll_at(&sockets)
830 };
831 let next = next?;
832 let now_micros = ax_hal::time::monotonic_time_nanos() / 1_000;
833 let next_micros = next.total_micros().max(0) as u64;
834 if next_micros <= now_micros {
835 Some(Duration::ZERO)
836 } else {
837 Some(Duration::from_micros(next_micros - now_micros))
838 }
839}
840
841fn start_protocol_executor(owner_cpu: usize) {
842 PROTOCOL_AFFINITY_STATUS.store(0, Ordering::Release);
843 let mut affinity = ax_task::sched::CpuSet::empty(ax_hal::cpu_num());
844 assert!(
845 affinity.insert(ax_task::sched::CpuId::new(owner_cpu as u32)),
846 "network protocol owner CPU {owner_cpu} is outside the runtime topology"
847 );
848 let worker = ax_task::thread::ThreadBuilder::new("net-protocol".to_owned())
849 .affinity(affinity)
850 .spawn(move || {
851 if ax_hal::percpu::this_cpu_id() != owner_cpu {
852 PROTOCOL_AFFINITY_STATUS.store(2, Ordering::Release);
853 return;
854 }
855 PROTOCOL_AFFINITY_STATUS.store(1, Ordering::Release);
856 PROTOCOL_POLL.schedule();
857 protocol_executor_main();
858 })
859 .unwrap_or_else(|error| panic!("failed to spawn network protocol executor: {error}"));
860 worker.detach();
861 while PROTOCOL_AFFINITY_STATUS.load(Ordering::Acquire) == 0 {
862 yield_network_thread();
863 }
864 assert_eq!(
865 PROTOCOL_AFFINITY_STATUS.load(Ordering::Acquire),
866 1,
867 "failed to pin the unique network protocol executor to CPU {owner_cpu}"
868 );
869}
870
871fn protocol_executor_main() {
872 let mut budget = ProtocolPollBudget::new(ax_hal::time::monotonic_time_nanos());
873 loop {
874 if let Some(delay) = next_poll_delay() {
875 let _ = PROTOCOL_POLL.wait_timeout(delay);
876 } else {
877 PROTOCOL_POLL.wait();
878 }
879 drain_deferred_poll_wakes();
880 let completed = PROTOCOL_POLL.requested_generation();
881 poll_protocol_until_idle(&mut budget);
882 PROTOCOL_POLL.complete(completed);
883 drain_deferred_poll_wakes();
884 if PROTOCOL_POLL.finish_cycle(|| DEFERRED_POLL_WAKE_PENDING.load(Ordering::Acquire)) {
885 continue;
886 }
887 }
888}
889
890pub fn dns_servers() -> Vec<Ipv4Address> {
895 get_control().dns_servers()
896}
897
898const DNS_DEFAULT_TIMEOUT: Duration = Duration::from_secs(5);
899
900pub fn dns_query(name: &str) -> NetResult<Vec<IpAddr>> {
902 dns_query_timeout(name, DNS_DEFAULT_TIMEOUT)
903}
904
905pub fn dns_query_timeout(name: &str, timeout: Duration) -> NetResult<Vec<IpAddr>> {
907 let servers = dns_servers();
908 if servers.is_empty() {
909 return Err(NetError::NotFound);
910 }
911
912 let servers = servers
913 .into_iter()
914 .filter(|server| {
915 get_control()
916 .select_route(&IpAddress::Ipv4(*server))
917 .is_ok()
918 })
919 .map(IpAddress::Ipv4)
920 .collect::<Vec<_>>();
921 if servers.is_empty() {
922 return Err(NetError::NoSuchDeviceOrAddress);
923 }
924 let handle = SOCKET_SET.add(dns::Socket::new(&servers, vec![]));
925 DnsSocketGuard(handle).query_timeout(name, DnsQueryType::A, timeout)
926}
927
928struct DnsSocketGuard(smoltcp::iface::SocketHandle);
929
930impl DnsSocketGuard {
931 fn query_timeout(
932 &self,
933 name: &str,
934 query_type: DnsQueryType,
935 timeout: Duration,
936 ) -> NetResult<Vec<IpAddr>> {
937 let query_handle = {
938 let mut service = get_service();
939 let mut sockets = SOCKET_SET.inner.lock();
940 sockets.get_mut::<dns::Socket>(self.0).start_query(
941 service.iface.context(),
942 name,
943 query_type,
944 )
945 }
946 .map_err(|err| match err {
947 StartQueryError::NoFreeSlot => NetError::ResourceBusy,
948 StartQueryError::InvalidName => NetError::InvalidInput,
949 StartQueryError::NameTooLong => NetError::InvalidInput,
950 })?;
951
952 let start_time = ax_hal::time::monotonic_time_nanos();
953 let timeout_ns = u64::try_from(timeout.as_nanos()).unwrap_or(u64::MAX);
954 let deadline = start_time.saturating_add(timeout_ns);
955
956 loop {
957 request_poll();
958 match SOCKET_SET.with_socket_mut::<dns::Socket, _, _>(self.0, |socket| {
959 socket
960 .get_query_result(query_handle)
961 .map_err(|err| match err {
962 GetQueryResultError::Pending => NetError::WouldBlock,
963 GetQueryResultError::Failed => NetError::ConnectionRefused,
964 })
965 }) {
966 Ok(addrs) => {
967 return Ok(addrs.into_iter().map(IpAddr::from).collect());
968 }
969 Err(NetError::WouldBlock) => {
970 if ax_hal::time::monotonic_time_nanos() >= deadline {
971 return Err(NetError::TimedOut);
972 }
973 yield_network_thread();
974 }
975 Err(err) => return Err(err),
976 }
977 }
978 }
979}
980
981pub(crate) fn yield_network_thread() {
982 ax_task::thread::current::yield_current_cpu()
983 .unwrap_or_else(|error| panic!("network executor could not yield: {error}"));
984}
985
986impl Drop for DnsSocketGuard {
987 fn drop(&mut self) {
988 SOCKET_SET.remove(self.0);
989 }
990}
991
992fn wait_for_dhcp_bootstrap() {
993 if get_control().wait_for_dhcp_configuration(DHCP_BOOTSTRAP_TIMEOUT) {
994 return;
995 }
996 warn!("DHCP bootstrap timed out");
997}
998
999#[cfg(test)]
1000mod readiness_version_tests {
1001 use super::{ReadinessVersion, receive_starts_next_edge};
1002
1003 #[test]
1004 fn readiness_wake_publishes_a_new_generation() {
1005 let version = ReadinessVersion::new();
1006 let before = version.current();
1007
1008 version.publish();
1009
1010 assert_eq!(version.current(), before.wrapping_add(1));
1011 }
1012
1013 #[test]
1014 fn only_a_drained_receive_starts_the_next_readiness_edge() {
1015 assert!(!receive_starts_next_edge(0, 0));
1016 assert!(!receive_starts_next_edge(1, 1));
1017 assert!(receive_starts_next_edge(1, 0));
1018 }
1019}