// SPDX-License-Identifier: MPL-2.0 use alloc::{ collections::btree_map::{BTreeMap, Entry}, string::String, sync::Arc, vec::Vec, }; use core::sync::atomic::{AtomicU32, Ordering}; use aster_softirq::BottomHalfDisabled; use bitflags::bitflags; use int_to_c_enum::TryFromInt; use ostd::sync::{SpinLock, SpinLockGuard}; use smoltcp::{ iface::{packet::Packet, Context}, phy::Device, wire::{IpAddress, IpEndpoint, Ipv4Address, Ipv4Packet}, }; use super::{ poll::{FnHelper, PollContext, SocketTableAction}, poll_iface::PollableIface, port::BindPortConfig, time::get_network_timestamp, Iface, }; use crate::{ errors::BindError, ext::Ext, socket::{TcpListenerBg, UdpSocketBg}, socket_table::SocketTable, }; pub struct IfaceCommon { index: u32, name: String, type_: InterfaceType, flags: InterfaceFlags, interface: SpinLock, BottomHalfDisabled>, used_ports: SpinLock, BottomHalfDisabled>, sockets: SpinLock, BottomHalfDisabled>, sched_poll: E::ScheduleNextPoll, } impl IfaceCommon { pub(super) fn new( name: String, type_: InterfaceType, flags: InterfaceFlags, interface: smoltcp::iface::Interface, sched_poll: E::ScheduleNextPoll, ) -> Self { let index = INTERFACE_INDEX_ALLOCATOR.fetch_add(1, Ordering::Relaxed); Self { index, name, type_, flags, interface: SpinLock::new(PollableIface::new(interface)), used_ports: SpinLock::new(BTreeMap::new()), sockets: SpinLock::new(SocketTable::new()), sched_poll, } } pub(super) fn index(&self) -> u32 { self.index } pub(super) fn name(&self) -> &str { &self.name } pub(super) fn type_(&self) -> InterfaceType { self.type_ } pub(super) fn flags(&self) -> InterfaceFlags { self.flags } pub(super) fn ipv4_addr(&self) -> Option { self.interface.lock().ipv4_addr() } pub(super) fn prefix_len(&self) -> Option { self.interface.lock().prefix_len() } pub(super) fn sched_poll(&self) -> &E::ScheduleNextPoll { &self.sched_poll } } /// An allocator that allocates a unique index for each interface. // // FIXME: This allocator is specific to each network namespace. pub static INTERFACE_INDEX_ALLOCATOR: AtomicU32 = AtomicU32::new(1); // Lock order: `interface` -> `sockets` impl IfaceCommon { /// Acquires the lock to the interface. pub(crate) fn interface(&self) -> SpinLockGuard<'_, PollableIface, BottomHalfDisabled> { self.interface.lock() } /// Acquires the lock to the socket table. pub(crate) fn sockets(&self) -> SpinLockGuard<'_, SocketTable, BottomHalfDisabled> { self.sockets.lock() } } const IP_LOCAL_PORT_START: u16 = 32768; const IP_LOCAL_PORT_END: u16 = 60999; impl IfaceCommon { pub(super) fn bind( &self, iface: Arc>, config: BindPortConfig, ) -> core::result::Result, BindError> { let port = self.bind_port(config)?; Ok(BoundPort { iface, port }) } /// Allocates an unused ephemeral port. /// /// We follow the port range that many Linux kernels use by default, which is 32768-60999. /// /// See . fn alloc_ephemeral_port(&self) -> Option { let mut used_ports = self.used_ports.lock(); for port in IP_LOCAL_PORT_START..=IP_LOCAL_PORT_END { if let Entry::Vacant(e) = used_ports.entry(port) { e.insert(0); return Some(port); } } None } fn bind_port(&self, config: BindPortConfig) -> Result { let port = if let Some(port) = config.port() { port } else { match self.alloc_ephemeral_port() { Some(port) => port, None => return Err(BindError::Exhausted), } }; let mut used_ports = self.used_ports.lock(); if let Some(used_times) = used_ports.get_mut(&port) { if *used_times == 0 || config.can_reuse() { // FIXME: Check if the previous socket was bound with SO_REUSEADDR. *used_times += 1; } else { return Err(BindError::InUse); } } else { used_ports.insert(port, 1); } Ok(port) } /// Releases the port so that it can be used again (if it is not being reused). fn release_port(&self, port: u16) { let mut used_ports = self.used_ports.lock(); if let Some(used_times) = used_ports.remove(&port) { if used_times != 1 { used_ports.insert(port, used_times - 1); } } } } impl IfaceCommon { pub(crate) fn register_udp_socket(&self, socket: Arc>) { let mut sockets = self.sockets.lock(); sockets.insert_udp_socket(socket); } pub(crate) fn remove_tcp_listener(&self, socket: &Arc>) { let mut sockets = self.sockets.lock(); let removed = sockets.remove_listener(socket.listener_key()); debug_assert!(removed.is_some()); } pub(crate) fn remove_udp_socket(&self, socket: &Arc>) { let mut sockets = self.sockets.lock(); let removed = sockets.remove_udp_socket(socket); debug_assert!(removed.is_some()); } } impl IfaceCommon { pub(super) fn poll( &self, device: &mut D, mut process_phy: P, mut dispatch_phy: Q, ) -> Option where D: Device + ?Sized, P: for<'pkt, 'cx, 'tx> FnHelper< &'pkt [u8], &'cx mut Context, D::TxToken<'tx>, Option<(Ipv4Packet<&'pkt [u8]>, D::TxToken<'tx>)>, >, Q: FnMut(&Packet, &mut Context, D::TxToken<'_>), { let mut interface = self.interface(); interface.context_mut().now = get_network_timestamp(); let mut sockets = self.sockets.lock(); let mut socket_actions = Vec::new(); let mut context = PollContext::new(interface.as_mut(), &sockets, &mut socket_actions); context.poll_ingress(device, &mut process_phy, &mut dispatch_phy); context.poll_egress(device, &mut dispatch_phy); // Insert new connections and remove dead connections. for action in socket_actions.into_iter() { match action { SocketTableAction::AddTcpConn(new_tcp_conn) => { let res = sockets.insert_connection(new_tcp_conn); debug_assert!(res.is_ok()); } SocketTableAction::DelTcpConn(dead_conn_key) => { sockets.remove_dead_tcp_connection(&dead_conn_key); } } } // Note that only TCP connections can have timers set, so as far as the time to poll is // concerned, we only need to consider TCP connections. interface.next_poll_at_ms() } } /// A port bound to an iface. /// /// When dropped, the port is automatically released. // // FIXME: TCP and UDP ports are independent. Find a way to track the protocol here. pub struct BoundPort { iface: Arc>, port: u16, } impl BoundPort { /// Returns a reference to the iface. pub fn iface(&self) -> &Arc> { &self.iface } /// Returns the port number. pub fn port(&self) -> u16 { self.port } /// Returns the bound endpoint. pub fn endpoint(&self) -> Option { let ip_addr = { let ipv4_addr = self.iface().ipv4_addr()?; IpAddress::Ipv4(ipv4_addr) }; Some(IpEndpoint::new(ip_addr, self.port)) } } impl Drop for BoundPort { fn drop(&mut self) { self.iface.common().release_port(self.port); } } /// Interface type. /// /// Reference: #[repr(u16)] #[derive(Debug, Clone, Copy, TryFromInt, PartialEq, Eq)] pub enum InterfaceType { // Arp protocol hardware identifiers /// from KA9Q: NET/ROM pseudo NETROM = 0, /// Ethernet 10Mbps ETHER = 1, /// Experimental Ethernet EETHER = 2, // Dummy types for non ARP hardware /// IPIP tunnel TUNNEL = 768, /// IP6IP6 tunnel TUNNEL6 = 769, /// Frame Relay Access Device FRAD = 770, /// SKIP vif SKIP = 771, /// Loopback device LOOPBACK = 772, /// Localtalk device LOCALTALK = 773, // TODO: This enum is not exhaustive } bitflags! { /// Interface flags. /// /// Reference: pub struct InterfaceFlags: u32 { /// Interface is up const UP = 1<<0; /// Broadcast address valid const BROADCAST = 1<<1; /// Turn on debugging const DEBUG = 1<<2; /// Loopback net const LOOPBACK = 1<<3; /// Interface is has p-p link const POINTOPOINT = 1<<4; /// Avoid use of trailers const NOTRAILERS = 1<<5; /// Interface RFC2863 OPER_UP const RUNNING = 1<<6; /// No ARP protocol const NOARP = 1<<7; /// Receive all packets const PROMISC = 1<<8; /// Receive all multicast packets const ALLMULTI = 1<<9; /// Master of a load balancer const MASTER = 1<<10; /// Slave of a load balancer const SLAVE = 1<<11; /// Supports multicast const MULTICAST = 1<<12; /// Can set media type const PORTSEL = 1<<13; /// Auto media select active const AUTOMEDIA = 1<<14; /// Dialup device with changing addresses const DYNAMIC = 1<<15; /// Driver signals L1 up const LOWER_UP = 1<<16; /// Driver signals dormant const DORMANT = 1<<17; /// Echo sent packets const ECHO = 1<<18; } }