diff --git a/Cargo.lock b/Cargo.lock index 148ea0cf..b4c83385 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -82,6 +82,7 @@ version = "0.1.0" dependencies = [ "aster-softirq", "bitflags 1.3.2", + "int-to-c-enum", "jhash", "ostd", "smoltcp", diff --git a/kernel/libs/aster-bigtcp/Cargo.toml b/kernel/libs/aster-bigtcp/Cargo.toml index 07d10ba1..b740fc38 100644 --- a/kernel/libs/aster-bigtcp/Cargo.toml +++ b/kernel/libs/aster-bigtcp/Cargo.toml @@ -8,6 +8,7 @@ edition = "2021" [dependencies] aster-softirq = { path = "../../comps/softirq" } bitflags = "1.3" +int-to-c-enum = { path = "../int-to-c-enum" } jhash = { path = "../jhash" } ostd = { path = "../../../ostd" } smoltcp = { git = "https://github.com/asterinas/smoltcp", tag = "r_2024-11-08_f07e5b5", default-features = false, features = [ diff --git a/kernel/libs/aster-bigtcp/src/iface/common.rs b/kernel/libs/aster-bigtcp/src/iface/common.rs index 48456020..424e1fae 100644 --- a/kernel/libs/aster-bigtcp/src/iface/common.rs +++ b/kernel/libs/aster-bigtcp/src/iface/common.rs @@ -6,8 +6,11 @@ use alloc::{ 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}, @@ -30,7 +33,11 @@ use crate::{ }; pub struct IfaceCommon { + index: u32, name: String, + type_: InterfaceType, + flags: InterfaceFlags, + interface: SpinLock, BottomHalfDisabled>, used_ports: SpinLock, BottomHalfDisabled>, sockets: SpinLock, BottomHalfDisabled>, @@ -40,11 +47,18 @@ pub struct IfaceCommon { 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()), @@ -52,19 +66,40 @@ impl IfaceCommon { } } + 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. @@ -245,3 +280,79 @@ impl Drop for BoundPort { 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; + } +} diff --git a/kernel/libs/aster-bigtcp/src/iface/iface.rs b/kernel/libs/aster-bigtcp/src/iface/iface.rs index eedf2c75..891ef25e 100644 --- a/kernel/libs/aster-bigtcp/src/iface/iface.rs +++ b/kernel/libs/aster-bigtcp/src/iface/iface.rs @@ -4,7 +4,7 @@ use alloc::sync::Arc; use smoltcp::wire::Ipv4Address; -use super::{port::BindPortConfig, BoundPort}; +use super::{port::BindPortConfig, BoundPort, InterfaceFlags, InterfaceType}; use crate::{errors::BindError, ext::Ext}; /// A network interface. @@ -16,6 +16,9 @@ use crate::{errors::BindError, ext::Ext}; pub trait Iface: internal::IfaceInternal + Send + Sync { /// Transmits or receives packets queued in the iface, and updates socket status accordingly. fn poll(&self); + + /// Returns the maximum transmission unit. + fn mtu(&self) -> usize; } impl dyn Iface { @@ -38,6 +41,11 @@ impl dyn Iface { common.bind(self.clone(), config) } + /// Returns the interface index. + pub fn index(&self) -> u32 { + self.common().index() + } + /// Gets the name of the iface. /// /// In Linux, the name is usually the driver name followed by a unit number. @@ -45,6 +53,16 @@ impl dyn Iface { self.common().name() } + /// Returns the interface type. + pub fn type_(&self) -> InterfaceType { + self.common().type_() + } + + /// Returns the interface flags. + pub fn flags(&self) -> InterfaceFlags { + self.common().flags() + } + /// Gets the IPv4 address of the iface, if any. /// /// FIXME: One iface may have multiple IPv4 addresses. @@ -52,6 +70,14 @@ impl dyn Iface { self.common().ipv4_addr() } + /// Retrieves the prefix length of the interface's IPv4 address. + /// + /// Both [`Self::ipv4_addr`] and this method will either return `Some(_)` + /// or both will return `None`. + pub fn prefix_len(&self) -> Option { + self.common().prefix_len() + } + /// Returns a reference to the associated [`ScheduleNextPoll`]. pub fn sched_poll(&self) -> &E::ScheduleNextPoll { self.common().sched_poll() diff --git a/kernel/libs/aster-bigtcp/src/iface/mod.rs b/kernel/libs/aster-bigtcp/src/iface/mod.rs index 9cff7ef7..95eebd75 100644 --- a/kernel/libs/aster-bigtcp/src/iface/mod.rs +++ b/kernel/libs/aster-bigtcp/src/iface/mod.rs @@ -10,7 +10,7 @@ mod port; mod sched; mod time; -pub use common::BoundPort; +pub use common::{BoundPort, InterfaceFlags, InterfaceType}; pub use iface::Iface; pub use phy::{EtherIface, IpIface}; pub(crate) use poll_iface::{PollKey, PollableIfaceMut}; diff --git a/kernel/libs/aster-bigtcp/src/iface/phy/ether.rs b/kernel/libs/aster-bigtcp/src/iface/phy/ether.rs index 949bd2c2..dbaaf872 100644 --- a/kernel/libs/aster-bigtcp/src/iface/phy/ether.rs +++ b/kernel/libs/aster-bigtcp/src/iface/phy/ether.rs @@ -6,7 +6,7 @@ use aster_softirq::BottomHalfDisabled; use ostd::sync::SpinLock; use smoltcp::{ iface::{packet::Packet, Config, Context}, - phy::{DeviceCapabilities, TxToken}, + phy::{Device, DeviceCapabilities, TxToken}, wire::{ self, ArpOperation, ArpPacket, ArpRepr, EthernetAddress, EthernetFrame, EthernetProtocol, EthernetRepr, IpAddress, Ipv4Address, Ipv4AddressExt, Ipv4Cidr, Ipv4Packet, @@ -17,8 +17,10 @@ use crate::{ device::{NotifyDevice, WithDevice}, ext::Ext, iface::{ - common::IfaceCommon, iface::internal::IfaceInternal, time::get_network_timestamp, Iface, - ScheduleNextPoll, + common::{IfaceCommon, InterfaceType}, + iface::internal::IfaceInternal, + time::get_network_timestamp, + Iface, InterfaceFlags, ScheduleNextPoll, }, }; @@ -37,6 +39,7 @@ impl EtherIface { gateway: Ipv4Address, name: String, sched_poll: E::ScheduleNextPoll, + flags: InterfaceFlags, ) -> Arc { let interface = driver.with(|device| { let config = Config::new(wire::HardwareAddress::Ethernet(ether_addr)); @@ -54,7 +57,7 @@ impl EtherIface { interface }); - let common = IfaceCommon::new(name, interface, sched_poll); + let common = IfaceCommon::new(name, InterfaceType::ETHER, flags, interface, sched_poll); Arc::new(Self { driver, @@ -86,6 +89,11 @@ where self.common.sched_poll().schedule_next_poll(next_poll); }); } + + fn mtu(&self) -> usize { + self.driver + .with(|device| device.capabilities().max_transmission_unit) + } } impl EtherIface { diff --git a/kernel/libs/aster-bigtcp/src/iface/phy/ip.rs b/kernel/libs/aster-bigtcp/src/iface/phy/ip.rs index f8c010c5..84f33bd6 100644 --- a/kernel/libs/aster-bigtcp/src/iface/phy/ip.rs +++ b/kernel/libs/aster-bigtcp/src/iface/phy/ip.rs @@ -4,7 +4,7 @@ use alloc::{string::String, sync::Arc}; use smoltcp::{ iface::Config, - phy::TxToken, + phy::{Device, TxToken}, wire::{self, Ipv4Cidr, Ipv4Packet}, }; @@ -12,8 +12,10 @@ use crate::{ device::WithDevice, ext::Ext, iface::{ - common::IfaceCommon, iface::internal::IfaceInternal, time::get_network_timestamp, Iface, - ScheduleNextPoll, + common::{IfaceCommon, InterfaceFlags, InterfaceType}, + iface::internal::IfaceInternal, + time::get_network_timestamp, + Iface, ScheduleNextPoll, }, }; @@ -28,6 +30,8 @@ impl IpIface { ip_cidr: Ipv4Cidr, name: String, sched_poll: E::ScheduleNextPoll, + type_: InterfaceType, + flags: InterfaceFlags, ) -> Arc { let interface = driver.with(|device| { let config = Config::new(smoltcp::wire::HardwareAddress::Ip); @@ -41,7 +45,7 @@ impl IpIface { interface }); - let common = IfaceCommon::new(name, interface, sched_poll); + let common = IfaceCommon::new(name, type_, flags, interface, sched_poll); Arc::new(Self { driver, common }) } @@ -74,4 +78,9 @@ impl Iface for IpIface { self.common.sched_poll().schedule_next_poll(next_poll); }); } + + fn mtu(&self) -> usize { + self.driver + .with(|device| device.capabilities().max_transmission_unit) + } } diff --git a/kernel/libs/aster-bigtcp/src/iface/poll_iface.rs b/kernel/libs/aster-bigtcp/src/iface/poll_iface.rs index 288023d7..ea4184ef 100644 --- a/kernel/libs/aster-bigtcp/src/iface/poll_iface.rs +++ b/kernel/libs/aster-bigtcp/src/iface/poll_iface.rs @@ -39,6 +39,13 @@ impl PollableIface { self.interface.ipv4_addr() } + pub(super) fn prefix_len(&self) -> Option { + self.interface + .ip_addrs() + .first() + .map(|ip_addr| ip_addr.prefix_len()) + } + /// Returns the next poll time. pub(super) fn next_poll_at_ms(&self) -> Option { self.pending_conns.next_poll_at_ms() diff --git a/kernel/src/net/iface/init.rs b/kernel/src/net/iface/init.rs index 03f14f9c..b12ed22f 100644 --- a/kernel/src/net/iface/init.rs +++ b/kernel/src/net/iface/init.rs @@ -2,7 +2,10 @@ use alloc::{borrow::ToOwned, sync::Arc}; -use aster_bigtcp::device::WithDevice; +use aster_bigtcp::{ + device::WithDevice, + iface::{InterfaceFlags, InterfaceType}, +}; use aster_softirq::BottomHalfDisabled; use spin::Once; @@ -15,10 +18,13 @@ pub fn init() { IFACES.call_once(|| { let mut ifaces = Vec::with_capacity(2); + // Initialize loopback before virtio + // to ensure the loopback interface index is ahead of virtio. + ifaces.push(new_loopback()); + if let Some(iface_virtio) = new_virtio() { ifaces.push(iface_virtio); } - ifaces.push(new_loopback()); ifaces }); @@ -66,13 +72,22 @@ fn new_virtio() -> Option> { } } + // FIXME: These flags are currently hardcoded. + // In the future, we should set appropriate values. + let flags = InterfaceFlags::UP + | InterfaceFlags::BROADCAST + | InterfaceFlags::RUNNING + | InterfaceFlags::MULTICAST + | InterfaceFlags::LOWER_UP; + Some(EtherIface::new( Wrapper(virtio_net), EthernetAddress(ether_addr), Ipv4Cidr::new(VIRTIO_ADDRESS, VIRTIO_ADDRESS_PREFIX_LEN), VIRTIO_GATEWAY, - "virtio".to_owned(), + "eth0".to_owned(), PollScheduler::new(), + flags, )) } @@ -100,10 +115,19 @@ fn new_loopback() -> Arc { } } + // FIXME: These flags are currently hardcoded. + // In the future, we should set appropriate values. + let flags = InterfaceFlags::UP + | InterfaceFlags::LOOPBACK + | InterfaceFlags::RUNNING + | InterfaceFlags::LOWER_UP; + IpIface::new( Wrapper(Mutex::new(Loopback::new(Medium::Ip))), Ipv4Cidr::new(LOOPBACK_ADDRESS, LOOPBACK_ADDRESS_PREFIX_LEN), "lo".to_owned(), PollScheduler::new(), - ) as _ + InterfaceType::LOOPBACK, + flags, + ) as Arc }