mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-09 05:16:47 +00:00
Expose more methods on bigtcp iface
This commit is contained in:
parent
5e9f537222
commit
2c41055470
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -82,6 +82,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"aster-softirq",
|
||||
"bitflags 1.3.2",
|
||||
"int-to-c-enum",
|
||||
"jhash",
|
||||
"ostd",
|
||||
"smoltcp",
|
||||
|
@ -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 = [
|
||||
|
@ -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<E: Ext> {
|
||||
index: u32,
|
||||
name: String,
|
||||
type_: InterfaceType,
|
||||
flags: InterfaceFlags,
|
||||
|
||||
interface: SpinLock<PollableIface<E>, BottomHalfDisabled>,
|
||||
used_ports: SpinLock<BTreeMap<u16, usize>, BottomHalfDisabled>,
|
||||
sockets: SpinLock<SocketTable<E>, BottomHalfDisabled>,
|
||||
@ -40,11 +47,18 @@ pub struct IfaceCommon<E: Ext> {
|
||||
impl<E: Ext> IfaceCommon<E> {
|
||||
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<E: Ext> IfaceCommon<E> {
|
||||
}
|
||||
}
|
||||
|
||||
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<Ipv4Address> {
|
||||
self.interface.lock().ipv4_addr()
|
||||
}
|
||||
|
||||
pub(super) fn prefix_len(&self) -> Option<u8> {
|
||||
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<E: Ext> IfaceCommon<E> {
|
||||
/// Acquires the lock to the interface.
|
||||
@ -245,3 +280,79 @@ impl<E: Ext> Drop for BoundPort<E> {
|
||||
self.iface.common().release_port(self.port);
|
||||
}
|
||||
}
|
||||
|
||||
/// Interface type.
|
||||
///
|
||||
/// Reference: <https://elixir.bootlin.com/linux/v6.0.18/source/include/uapi/linux/if_arp.h#L30>
|
||||
#[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: <https://elixir.bootlin.com/linux/v6.0.18/source/include/uapi/linux/if.h#L82>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -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<E>: internal::IfaceInternal<E> + 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<E: Ext> dyn Iface<E> {
|
||||
@ -38,6 +41,11 @@ impl<E: Ext> dyn Iface<E> {
|
||||
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<E: Ext> dyn Iface<E> {
|
||||
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<E: Ext> dyn Iface<E> {
|
||||
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<u8> {
|
||||
self.common().prefix_len()
|
||||
}
|
||||
|
||||
/// Returns a reference to the associated [`ScheduleNextPoll`].
|
||||
pub fn sched_poll(&self) -> &E::ScheduleNextPoll {
|
||||
self.common().sched_poll()
|
||||
|
@ -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};
|
||||
|
@ -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<D: WithDevice, E: Ext> EtherIface<D, E> {
|
||||
gateway: Ipv4Address,
|
||||
name: String,
|
||||
sched_poll: E::ScheduleNextPoll,
|
||||
flags: InterfaceFlags,
|
||||
) -> Arc<Self> {
|
||||
let interface = driver.with(|device| {
|
||||
let config = Config::new(wire::HardwareAddress::Ethernet(ether_addr));
|
||||
@ -54,7 +57,7 @@ impl<D: WithDevice, E: Ext> EtherIface<D, E> {
|
||||
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<D, E: Ext> EtherIface<D, E> {
|
||||
|
@ -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<D: WithDevice, E: Ext> IpIface<D, E> {
|
||||
ip_cidr: Ipv4Cidr,
|
||||
name: String,
|
||||
sched_poll: E::ScheduleNextPoll,
|
||||
type_: InterfaceType,
|
||||
flags: InterfaceFlags,
|
||||
) -> Arc<Self> {
|
||||
let interface = driver.with(|device| {
|
||||
let config = Config::new(smoltcp::wire::HardwareAddress::Ip);
|
||||
@ -41,7 +45,7 @@ impl<D: WithDevice, E: Ext> IpIface<D, E> {
|
||||
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<D: WithDevice + 'static, E: Ext> Iface<E> for IpIface<D, E> {
|
||||
self.common.sched_poll().schedule_next_poll(next_poll);
|
||||
});
|
||||
}
|
||||
|
||||
fn mtu(&self) -> usize {
|
||||
self.driver
|
||||
.with(|device| device.capabilities().max_transmission_unit)
|
||||
}
|
||||
}
|
||||
|
@ -39,6 +39,13 @@ impl<E: Ext> PollableIface<E> {
|
||||
self.interface.ipv4_addr()
|
||||
}
|
||||
|
||||
pub(super) fn prefix_len(&self) -> Option<u8> {
|
||||
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<u64> {
|
||||
self.pending_conns.next_poll_at_ms()
|
||||
|
@ -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<Arc<Iface>> {
|
||||
}
|
||||
}
|
||||
|
||||
// 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<Iface> {
|
||||
}
|
||||
}
|
||||
|
||||
// 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<Iface>
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user