net: add loopback interface
This commit is contained in:
parent
0124003130
commit
f6617da3d6
@ -21,6 +21,7 @@ device-api-macros = { path = "lib/device-api/macros" }
|
||||
# Drivers
|
||||
ygg_driver_block = { path = "driver/block/core" }
|
||||
ygg_driver_net_core = { path = "driver/net/core" }
|
||||
ygg_driver_net_loopback = { path = "driver/net/loopback" }
|
||||
kernel-fs = { path = "driver/fs/kernel-fs" }
|
||||
memfs = { path = "driver/fs/memfs" }
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
use core::{
|
||||
mem::size_of,
|
||||
sync::atomic::{AtomicU32, Ordering},
|
||||
sync::atomic::{AtomicU32, AtomicUsize, Ordering},
|
||||
};
|
||||
|
||||
use alloc::{boxed::Box, collections::BTreeMap, format, sync::Arc};
|
||||
@ -8,6 +8,7 @@ use alloc::{boxed::Box, collections::BTreeMap, format, sync::Arc};
|
||||
use kernel_util::{
|
||||
mem::PageBox,
|
||||
sync::spin_rwlock::{IrqSafeRwLock, IrqSafeRwLockReadGuard},
|
||||
util::OneTimeInit,
|
||||
};
|
||||
use yggdrasil_abi::{
|
||||
error::Error,
|
||||
@ -32,13 +33,28 @@ pub struct NetworkInterface {
|
||||
pub(crate) id: u32,
|
||||
}
|
||||
|
||||
static ETH_INTERFACES: IrqSafeRwLock<BTreeMap<u32, Arc<NetworkInterface>>> =
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub enum NetworkInterfaceType {
|
||||
Ethernet,
|
||||
Loopback,
|
||||
}
|
||||
|
||||
static INTERFACES: IrqSafeRwLock<BTreeMap<u32, Arc<NetworkInterface>>> =
|
||||
IrqSafeRwLock::new(BTreeMap::new());
|
||||
static ETH_INTERFACE_ID: AtomicU32 = AtomicU32::new(1);
|
||||
static LAST_INTERFACE_ID: AtomicU32 = AtomicU32::new(1);
|
||||
static LOOPBACK: OneTimeInit<Arc<NetworkInterface>> = OneTimeInit::new();
|
||||
|
||||
impl NetworkInterface {
|
||||
pub fn id(&self) -> u32 {
|
||||
self.id
|
||||
}
|
||||
|
||||
pub fn loopback() -> &'static Arc<Self> {
|
||||
LOOPBACK.get()
|
||||
}
|
||||
|
||||
pub fn get(id: u32) -> Result<Arc<Self>, Error> {
|
||||
ETH_INTERFACES
|
||||
INTERFACES
|
||||
.read()
|
||||
.get(&id)
|
||||
.cloned()
|
||||
@ -46,7 +62,7 @@ impl NetworkInterface {
|
||||
}
|
||||
|
||||
pub fn query_by_name(name: &str) -> Result<Arc<Self>, Error> {
|
||||
ETH_INTERFACES
|
||||
INTERFACES
|
||||
.read()
|
||||
.iter()
|
||||
.find_map(|(_, iface)| {
|
||||
@ -60,7 +76,7 @@ impl NetworkInterface {
|
||||
}
|
||||
|
||||
pub fn list_ref() -> IrqSafeRwLockReadGuard<'static, BTreeMap<u32, Arc<NetworkInterface>>> {
|
||||
ETH_INTERFACES.read()
|
||||
INTERFACES.read()
|
||||
}
|
||||
|
||||
pub fn set_address(&self, address: IpAddr) {
|
||||
@ -94,11 +110,23 @@ impl NetworkInterface {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register_interface(dev: &'static dyn NetworkDevice) -> u32 {
|
||||
let mac = dev.read_hardware_address();
|
||||
pub fn register_interface(
|
||||
ty: NetworkInterfaceType,
|
||||
dev: &'static dyn NetworkDevice,
|
||||
) -> Arc<NetworkInterface> {
|
||||
let name = match ty {
|
||||
NetworkInterfaceType::Ethernet => {
|
||||
static LAST_ETHERNET_ID: AtomicUsize = AtomicUsize::new(0);
|
||||
let eth_id = LAST_ETHERNET_ID.fetch_add(1, Ordering::SeqCst);
|
||||
format!("eth{}", eth_id).into_boxed_str()
|
||||
}
|
||||
NetworkInterfaceType::Loopback => "lo".into(),
|
||||
};
|
||||
|
||||
let id = ETH_INTERFACE_ID.fetch_add(1, Ordering::SeqCst);
|
||||
let name = format!("eth{}", id).into_boxed_str();
|
||||
let mac = dev.read_hardware_address();
|
||||
let id = LAST_INTERFACE_ID.fetch_add(1, Ordering::SeqCst);
|
||||
|
||||
log::info!("Register network interface {} (#{}): {}", name, id, mac);
|
||||
|
||||
let iface = NetworkInterface {
|
||||
name,
|
||||
@ -107,11 +135,14 @@ pub fn register_interface(dev: &'static dyn NetworkDevice) -> u32 {
|
||||
address: IrqSafeRwLock::new(None),
|
||||
id,
|
||||
};
|
||||
log::info!("Registered network interface #{}: {}", id, mac);
|
||||
|
||||
let interface = Arc::new(iface);
|
||||
|
||||
ETH_INTERFACES.write().insert(id, interface);
|
||||
INTERFACES.write().insert(id, interface.clone());
|
||||
|
||||
id
|
||||
if ty == NetworkInterfaceType::Loopback {
|
||||
LOOPBACK.init(interface.clone());
|
||||
}
|
||||
|
||||
interface
|
||||
}
|
||||
|
@ -70,6 +70,23 @@ impl Route {
|
||||
}
|
||||
|
||||
pub fn lookup(address: IpAddr) -> Option<(u32, Option<IpAddr>)> {
|
||||
// TODO sort routes based on their "specificity"?
|
||||
// Check for local route
|
||||
for (_, interface) in NetworkInterface::list_ref().iter() {
|
||||
if interface
|
||||
.address
|
||||
.read()
|
||||
.map(|addr| addr == address)
|
||||
.unwrap_or(false)
|
||||
{
|
||||
// This is the address of loopback, return it
|
||||
return Some((
|
||||
NetworkInterface::loopback().id,
|
||||
Some(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
let routes = ROUTES.read();
|
||||
for route in routes.iter() {
|
||||
if route.subnet.contains(&address) {
|
||||
|
@ -669,6 +669,7 @@ pub async fn handle(packet: L3Packet) -> Result<(), Error> {
|
||||
.await
|
||||
} else {
|
||||
// RST+ACK
|
||||
log::warn!("SYN {} -> {}: port not listening", remote, local);
|
||||
let window_size = u16::from_network_order(tcp_frame.window_size);
|
||||
send(
|
||||
local,
|
||||
|
@ -136,6 +136,23 @@ impl<T: Socket> SocketTable<T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_insert_with_ephemeral_port<F: FnMut(u16) -> Result<Arc<T>, Error>>(
|
||||
&mut self,
|
||||
local: IpAddr,
|
||||
mut with: F,
|
||||
) -> Result<Arc<T>, Error> {
|
||||
for port in 32768..u16::MAX - 1 {
|
||||
let local = SocketAddr::new(local, port);
|
||||
|
||||
match self.try_insert_with(local, || with(port)) {
|
||||
Ok(socket) => return Ok(socket),
|
||||
Err(Error::AddrInUse) => continue,
|
||||
Err(error) => return Err(error),
|
||||
}
|
||||
}
|
||||
Err(Error::AddrInUse)
|
||||
}
|
||||
|
||||
pub fn try_insert_with<F: FnOnce() -> Result<Arc<T>, Error>>(
|
||||
&mut self,
|
||||
address: SocketAddr,
|
||||
@ -189,19 +206,35 @@ static TCP_LISTENERS: IrqSafeRwLock<SocketTable<TcpListener>> =
|
||||
impl UdpSocket {
|
||||
pub fn bind(address: SocketAddr) -> Result<Arc<UdpSocket>, Error> {
|
||||
let mut sockets = UDP_SOCKETS.write();
|
||||
sockets.try_insert_with(address, move || {
|
||||
let socket = Arc::new(Self {
|
||||
local: address,
|
||||
remote: None,
|
||||
broadcast: AtomicBool::new(false),
|
||||
receive_queue: Mutex::new(RingBuffer::try_with_capacity(128)?),
|
||||
receive_notify: QueueWaker::new(),
|
||||
});
|
||||
if address.port() == 0 {
|
||||
sockets.try_insert_with_ephemeral_port(address.ip(), |port| {
|
||||
let socket = Arc::new(Self {
|
||||
local: SocketAddr::new(address.ip(), port),
|
||||
remote: None,
|
||||
broadcast: AtomicBool::new(false),
|
||||
receive_queue: Mutex::new(RingBuffer::try_with_capacity(128)?),
|
||||
receive_notify: QueueWaker::new(),
|
||||
});
|
||||
|
||||
log::debug!("UDP socket opened: {}", address);
|
||||
log::debug!("UDP socket opened: *{}", socket.local);
|
||||
|
||||
Ok(socket)
|
||||
})
|
||||
Ok(socket)
|
||||
})
|
||||
} else {
|
||||
sockets.try_insert_with(address, move || {
|
||||
let socket = Arc::new(Self {
|
||||
local: address,
|
||||
remote: None,
|
||||
broadcast: AtomicBool::new(false),
|
||||
receive_queue: Mutex::new(RingBuffer::try_with_capacity(128)?),
|
||||
receive_notify: QueueWaker::new(),
|
||||
});
|
||||
|
||||
log::debug!("UDP socket opened: {}", address);
|
||||
|
||||
Ok(socket)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn connect(&self, _address: SocketAddr) -> Result<(), Error> {
|
||||
|
12
driver/net/loopback/Cargo.toml
Normal file
12
driver/net/loopback/Cargo.toml
Normal file
@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "ygg_driver_net_loopback"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
yggdrasil-abi = { git = "https://git.alnyan.me/yggdrasil/yggdrasil-abi.git" }
|
||||
kernel-util = { path = "../../../lib/kernel-util" }
|
||||
|
||||
ygg_driver_net_core = { path = "../../net/core" }
|
41
driver/net/loopback/src/lib.rs
Normal file
41
driver/net/loopback/src/lib.rs
Normal file
@ -0,0 +1,41 @@
|
||||
#![no_std]
|
||||
|
||||
use kernel_util::{mem::PageBox, util::OneTimeInit};
|
||||
use ygg_driver_net_core::{
|
||||
interface::{NetworkDevice, NetworkInterfaceType},
|
||||
Packet,
|
||||
};
|
||||
use yggdrasil_abi::{
|
||||
error::Error,
|
||||
net::{IpAddr, Ipv4Addr, MacAddress},
|
||||
};
|
||||
|
||||
struct LoopbackDevice;
|
||||
|
||||
impl NetworkDevice for LoopbackDevice {
|
||||
fn transmit(&self, packet: PageBox<[u8]>) -> Result<(), Error> {
|
||||
let packet = Packet::new(packet, 0, *LOOPBACK_ID.get());
|
||||
ygg_driver_net_core::receive_packet(packet)
|
||||
}
|
||||
|
||||
fn packet_prefix_size(&self) -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
fn read_hardware_address(&self) -> MacAddress {
|
||||
MacAddress::UNSPECIFIED
|
||||
}
|
||||
}
|
||||
|
||||
static LOOPBACK: OneTimeInit<LoopbackDevice> = OneTimeInit::new();
|
||||
static LOOPBACK_ID: OneTimeInit<u32> = OneTimeInit::new();
|
||||
|
||||
pub fn init() {
|
||||
let loopback = LOOPBACK.init(LoopbackDevice);
|
||||
let interface =
|
||||
ygg_driver_net_core::register_interface(NetworkInterfaceType::Loopback, loopback);
|
||||
|
||||
LOOPBACK_ID.init(interface.id());
|
||||
|
||||
interface.set_address(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)));
|
||||
}
|
@ -18,7 +18,10 @@ use kernel_util::{
|
||||
sync::{spin_rwlock::IrqSafeRwLock, IrqSafeSpinlock, IrqSafeSpinlockGuard},
|
||||
util::OneTimeInit,
|
||||
};
|
||||
use ygg_driver_net_core::{interface::NetworkDevice, Packet};
|
||||
use ygg_driver_net_core::{
|
||||
interface::{NetworkDevice, NetworkInterfaceType},
|
||||
Packet,
|
||||
};
|
||||
use ygg_driver_pci::{
|
||||
capability::{MsiXCapability, MsiXVectorTable},
|
||||
PciConfigurationSpace, PciDeviceInfo,
|
||||
@ -258,8 +261,8 @@ impl<T: Transport + 'static> Device for VirtioNet<T> {
|
||||
|
||||
self.finish_init(status);
|
||||
|
||||
let id = ygg_driver_net_core::register_interface(self);
|
||||
self.interface_id.init(id);
|
||||
let iface = ygg_driver_net_core::register_interface(NetworkInterfaceType::Ethernet, self);
|
||||
self.interface_id.init(iface.id());
|
||||
self.listen(64);
|
||||
|
||||
Ok(())
|
||||
|
@ -28,6 +28,7 @@ fn setup_root() -> Result<NodeRef, Error> {
|
||||
pub fn kinit() -> Result<(), Error> {
|
||||
infoln!("In main");
|
||||
|
||||
ygg_driver_net_loopback::init();
|
||||
ygg_driver_net_core::start_network_tasks()?;
|
||||
|
||||
#[cfg(feature = "fb_console")]
|
||||
|
Loading…
x
Reference in New Issue
Block a user