From 6b0d75315ffd24eba62cd24a6f985746bf332589 Mon Sep 17 00:00:00 2001 From: lhw2002426 <1466397747@qq.com> Date: Wed, 21 Aug 2024 09:41:03 +0800 Subject: [PATCH] add loopback --- apps/c/httpclient/expect_info.out | 7 +- crates/driver_net/Cargo.toml | 1 + crates/driver_net/src/lib.rs | 3 + crates/driver_net/src/loopback.rs | 131 +++++++++++++++++++++++++ crates/lwip_rust/build.rs | 5 +- crates/lwip_rust/custom/lwipopts.h | 4 +- modules/ruxdriver/Cargo.toml | 1 + modules/ruxdriver/build.rs | 2 +- modules/ruxdriver/src/drivers.rs | 17 ++++ modules/ruxdriver/src/macros.rs | 6 ++ modules/ruxfs/Cargo.toml | 2 +- modules/ruxfs/tests/test_fatfs.rs | 4 +- modules/ruxfs/tests/test_ramfs.rs | 4 +- modules/ruxnet/Cargo.toml | 3 +- modules/ruxnet/src/lib.rs | 9 +- modules/ruxnet/src/lwip_impl/driver.rs | 104 +++++++++++--------- modules/ruxnet/src/lwip_impl/mod.rs | 2 +- modules/ruxnet/src/smoltcp_impl/dns.rs | 9 +- modules/ruxnet/src/smoltcp_impl/mod.rs | 85 ++++++++++++---- modules/ruxnet/src/smoltcp_impl/tcp.rs | 13 ++- 20 files changed, 327 insertions(+), 85 deletions(-) create mode 100644 crates/driver_net/src/loopback.rs diff --git a/apps/c/httpclient/expect_info.out b/apps/c/httpclient/expect_info.out index 19688d533..35cf49e11 100644 --- a/apps/c/httpclient/expect_info.out +++ b/apps/c/httpclient/expect_info.out @@ -17,7 +17,12 @@ Initialize platform devices... Initialize device drivers... registered a new Net device at .\+: "virtio-net" Initialize network subsystem... - use NIC 0: "virtio-net" + net stack: smoltcp + use NIC: "loopback" +created net interface "loopback": + ether: 00-00-00-00-00-00 + ip: 127.0.0.1/24 + use NIC: "virtio-net" created net interface "eth0": ether: 52-54-00-12-34-56 ip: 10.0.2.15/24 diff --git a/crates/driver_net/Cargo.toml b/crates/driver_net/Cargo.toml index 5018c4a7c..dfd40e509 100644 --- a/crates/driver_net/Cargo.toml +++ b/crates/driver_net/Cargo.toml @@ -11,6 +11,7 @@ documentation = "https://rcore-os.github.io/arceos/driver_net/index.html" [features] default = [] +loopback = [] ixgbe = ["dep:ixgbe-driver"] [dependencies] diff --git a/crates/driver_net/src/lib.rs b/crates/driver_net/src/lib.rs index 6fd20c600..ad8536061 100644 --- a/crates/driver_net/src/lib.rs +++ b/crates/driver_net/src/lib.rs @@ -20,6 +20,9 @@ use alloc::sync::Arc; #[cfg(feature = "ixgbe")] /// ixgbe NIC device driver. pub mod ixgbe; +#[cfg(feature = "loopback")] +/// loopback device driver +pub mod loopback; mod net_buf; use core::ptr::NonNull; diff --git a/crates/driver_net/src/loopback.rs b/crates/driver_net/src/loopback.rs new file mode 100644 index 000000000..3574cee75 --- /dev/null +++ b/crates/driver_net/src/loopback.rs @@ -0,0 +1,131 @@ +/* Copyright (c) [2023] [Syswonder Community] +* [Ruxos] is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ +use crate::{EthernetAddress, NetBuf, NetBufBox, NetBufPool, NetBufPtr, NetDriverOps}; +use alloc::collections::VecDeque; +use alloc::sync::Arc; +use driver_common::{BaseDriverOps, DevError, DevResult, DeviceType}; + +extern crate alloc; + +const NET_BUF_LEN: usize = 1526; + +/// The VirtIO network device driver. +/// +/// `QS` is the VirtIO queue size. +pub struct LoopbackDevice { + mac_address: EthernetAddress, + pub(crate) queue: VecDeque, + buf_pool: Arc, +} + +unsafe impl Send for LoopbackDevice {} +unsafe impl Sync for LoopbackDevice {} + +impl LoopbackDevice { + /// Creates a new driver instance and initializes the device + pub fn new(mac_address: Option<[u8; 6]>) -> Self { + let buf_pool = match NetBufPool::new(1024, NET_BUF_LEN) { + Ok(pool) => pool, + Err(_) => { + panic!("fail to create netbufpool"); + } + }; + Self { + mac_address: match mac_address { + Some(address) => EthernetAddress(address), + None => EthernetAddress([0; 6]), + }, + queue: VecDeque::new(), + buf_pool: buf_pool, + } + } +} + +impl BaseDriverOps for LoopbackDevice { + fn device_name(&self) -> &str { + "loopback" + } + + fn device_type(&self) -> DeviceType { + DeviceType::Net + } +} + +use log::info; + +impl NetDriverOps for LoopbackDevice { + #[inline] + fn mac_address(&self) -> EthernetAddress { + EthernetAddress(self.mac_address.0) + } + + #[inline] + fn can_transmit(&self) -> bool { + true + } + + #[inline] + fn can_receive(&self) -> bool { + !self.queue.is_empty() + } + + #[inline] + fn rx_queue_size(&self) -> usize { + self.queue.len() + } + + #[inline] + fn tx_queue_size(&self) -> usize { + self.queue.len() + } + + fn fill_rx_buffers(&mut self, buf_pool: &Arc) -> DevResult { + Ok(()) + } + + fn recycle_rx_buffer(&mut self, rx_buf: NetBufPtr) -> DevResult { + Ok(()) + } + + fn recycle_tx_buffers(&mut self) -> DevResult { + Ok(()) + } + + fn prepare_tx_buffer(&self, tx_buf: &mut NetBuf, pkt_len: usize) -> DevResult { + Ok(()) + } + + fn transmit(&mut self, tx_buf: NetBufPtr) -> DevResult { + unsafe { self.queue.push_back(NetBuf::from_buf_ptr(tx_buf)) } + Ok(()) + } + + fn receive(&mut self) -> DevResult { + if let Some(token) = self.queue.pop_front() { + Ok(token.into_buf_ptr()) + } else { + Err(DevError::Again) + } + } + + fn alloc_tx_buffer(&mut self, size: usize) -> DevResult { + let mut net_buf = self.buf_pool.alloc_boxed().ok_or(DevError::NoMemory)?; + let pkt_len = size; + + // 1. Check if the buffer is large enough. + let hdr_len = net_buf.header_len(); + if hdr_len + pkt_len > net_buf.capacity() { + return Err(DevError::InvalidParam); + } + net_buf.set_packet_len(pkt_len); + + // 2. Return the buffer. + Ok(net_buf.into_buf_ptr()) + } +} diff --git a/crates/lwip_rust/build.rs b/crates/lwip_rust/build.rs index 1fcdf0c3e..fb85d3674 100644 --- a/crates/lwip_rust/build.rs +++ b/crates/lwip_rust/build.rs @@ -1,5 +1,3 @@ -use std::path::PathBuf; - fn main() { println!("cargo:rustc-link-lib=lwip"); println!("cargo:rerun-if-changed=custom"); @@ -28,9 +26,8 @@ fn generate_lwip_bindings() { .generate() .expect("Unable to generate bindings"); - let out_path = PathBuf::from("src"); bindings - .write_to_file(out_path.join("bindings.rs")) + .write_to_file("src/bindings.rs") .expect("Couldn't write bindings!"); } diff --git a/crates/lwip_rust/custom/lwipopts.h b/crates/lwip_rust/custom/lwipopts.h index fefe19fce..f8f519f02 100644 --- a/crates/lwip_rust/custom/lwipopts.h +++ b/crates/lwip_rust/custom/lwipopts.h @@ -25,8 +25,8 @@ #define LWIP_TCP 1 #define LWIP_CALLBACK_API 1 #define LWIP_NETIF_API 0 -#define LWIP_NETIF_LOOPBACK 0 -#define LWIP_HAVE_LOOPIF 1 +#define LWIP_NETIF_LOOPBACK 1 +#define LWIP_HAVE_LOOPIF 0 #define LWIP_HAVE_SLIPIF 0 #define LWIP_NETCONN 0 #define LWIP_SOCKET 0 diff --git a/modules/ruxdriver/Cargo.toml b/modules/ruxdriver/Cargo.toml index b90a247c6..c4f99e04d 100644 --- a/modules/ruxdriver/Cargo.toml +++ b/modules/ruxdriver/Cargo.toml @@ -32,6 +32,7 @@ virtio-9p = ["_9p","virtio", "driver_virtio/v9p"] ramdisk = ["block", "driver_block/ramdisk"] bcm2835-sdhci = ["block", "driver_block/bcm2835-sdhci"] ixgbe = ["net", "driver_net/ixgbe", "dep:axalloc", "dep:ruxhal"] +loopback = ["driver_net/loopback", "dyn"] # more devices example: e1000 = ["net", "driver_net/e1000"] default = ["bus-mmio"] diff --git a/modules/ruxdriver/build.rs b/modules/ruxdriver/build.rs index 6e1c859a8..b57e90b47 100644 --- a/modules/ruxdriver/build.rs +++ b/modules/ruxdriver/build.rs @@ -7,7 +7,7 @@ * See the Mulan PSL v2 for more details. */ -const NET_DEV_FEATURES: &[&str] = &["ixgbe", "virtio-net"]; +const NET_DEV_FEATURES: &[&str] = &["ixgbe", "virtio-net", "loopback"]; const BLOCK_DEV_FEATURES: &[&str] = &["ramdisk", "bcm2835-sdhci", "virtio-blk"]; const DISPLAY_DEV_FEATURES: &[&str] = &["virtio-gpu"]; const _9P_DEV_FEATURES: &[&str] = &["virtio-9p"]; diff --git a/modules/ruxdriver/src/drivers.rs b/modules/ruxdriver/src/drivers.rs index 7fe1115bc..9a214f390 100644 --- a/modules/ruxdriver/src/drivers.rs +++ b/modules/ruxdriver/src/drivers.rs @@ -42,6 +42,23 @@ pub trait DriverProbe { } } +cfg_if::cfg_if! { + if #[cfg(net_dev = "loopback")] + { + pub struct LoopbackDriver; + register_net_driver!(LoopbackDriver, driver_net::loopback::LoopbackDevice); + + impl DriverProbe for LoopbackDriver { + fn probe_global() -> Option { + debug!("mmc probe"); + Some(AxDeviceEnum::from_net( + driver_net::loopback::LoopbackDevice::new(None), + )) + } + } + } +} + #[cfg(net_dev = "virtio-net")] register_net_driver!( ::Driver, diff --git a/modules/ruxdriver/src/macros.rs b/modules/ruxdriver/src/macros.rs index e9aa44192..cfd406d9e 100644 --- a/modules/ruxdriver/src/macros.rs +++ b/modules/ruxdriver/src/macros.rs @@ -51,6 +51,12 @@ macro_rules! for_each_drivers { #[allow(unused_imports)] use crate::virtio::{self, VirtIoDevMeta}; + #[cfg(net_dev = "loopback")] + { + type $drv_type = crate::drivers::LoopbackDriver; + $code + } + #[cfg(net_dev = "virtio-net")] { type $drv_type = ::Driver; diff --git a/modules/ruxfs/Cargo.toml b/modules/ruxfs/Cargo.toml index 0ca624616..88e7415d9 100644 --- a/modules/ruxfs/Cargo.toml +++ b/modules/ruxfs/Cargo.toml @@ -55,7 +55,7 @@ features = [ # no std ] [dev-dependencies] -ruxdriver = { path = "../ruxdriver", features = ["block", "ramdisk"] } +ruxdriver = { path = "../ruxdriver", features = ["block", "ramdisk", "dyn"] } driver_block = { path = "../../crates/driver_block", features = ["ramdisk"] } axsync = { path = "../axsync", features = ["multitask"] } ruxtask = { path = "../ruxtask", features = ["test"] } diff --git a/modules/ruxfs/tests/test_fatfs.rs b/modules/ruxfs/tests/test_fatfs.rs index da542c00a..88d844882 100644 --- a/modules/ruxfs/tests/test_fatfs.rs +++ b/modules/ruxfs/tests/test_fatfs.rs @@ -33,7 +33,9 @@ fn test_fatfs() { // By default, mount_points[0] will be rootfs let mut mount_points: Vec = Vec::new(); // setup and initialize blkfs as one mountpoint for rootfs - mount_points.push(ruxfs::init_blkfs(AxDeviceContainer::from_one(disk))); + mount_points.push(ruxfs::init_blkfs(AxDeviceContainer::from_one(Box::new( + disk, + )))); ruxfs::prepare_commonfs(&mut mount_points); // setup and initialize rootfs diff --git a/modules/ruxfs/tests/test_ramfs.rs b/modules/ruxfs/tests/test_ramfs.rs index da93bff19..61c57a45d 100644 --- a/modules/ruxfs/tests/test_ramfs.rs +++ b/modules/ruxfs/tests/test_ramfs.rs @@ -58,9 +58,9 @@ fn test_ramfs() { // By default, mount_points[0] will be rootfs let mut mount_points: Vec = Vec::new(); // setup and initialize blkfs as one mountpoint for rootfs - mount_points.push(ruxfs::init_blkfs(AxDeviceContainer::from_one( + mount_points.push(ruxfs::init_blkfs(AxDeviceContainer::from_one(Box::new( RamDisk::default(), - ))); + )))); ruxfs::prepare_commonfs(&mut mount_points); // setup and initialize rootfs diff --git a/modules/ruxnet/Cargo.toml b/modules/ruxnet/Cargo.toml index 3c81a2510..bfc19c5f5 100644 --- a/modules/ruxnet/Cargo.toml +++ b/modules/ruxnet/Cargo.toml @@ -11,8 +11,9 @@ documentation = "https://rcore-os.github.io/arceos/ruxnet/index.html" [features] lwip = ["dep:lwip_rust"] +loopback = ["ruxdriver/loopback"] smoltcp = [] -default = ["smoltcp"] +default = ["smoltcp", "loopback"] [dependencies] log = "0.4" diff --git a/modules/ruxnet/src/lib.rs b/modules/ruxnet/src/lib.rs index a8414b105..f7304e199 100644 --- a/modules/ruxnet/src/lib.rs +++ b/modules/ruxnet/src/lib.rs @@ -63,8 +63,6 @@ use ruxdriver::{prelude::*, AxDeviceContainer}; pub fn init_network(mut net_devs: AxDeviceContainer) { info!("Initialize network subsystem..."); - let dev = net_devs.take_one().expect("No NIC device found!"); - info!(" use NIC 0: {:?}", dev.device_name()); cfg_if::cfg_if! { if #[cfg(feature = "lwip")] { info!(" net stack: lwip"); @@ -74,5 +72,10 @@ pub fn init_network(mut net_devs: AxDeviceContainer) { compile_error!("No network stack is selected"); } } - net_impl::init(dev); + net_impl::init(); + while !net_devs.is_empty() { + let dev = net_devs.take_one().expect("No NIC device found!"); + info!(" use NIC: {:?}", dev.device_name()); + net_impl::init_netdev(dev); + } } diff --git a/modules/ruxnet/src/lwip_impl/driver.rs b/modules/ruxnet/src/lwip_impl/driver.rs index 164ea7289..70c546bdd 100644 --- a/modules/ruxnet/src/lwip_impl/driver.rs +++ b/modules/ruxnet/src/lwip_impl/driver.rs @@ -3,7 +3,7 @@ use crate::{ net_impl::addr::{mask_to_prefix, MacAddr}, IpAddr, }; -use alloc::{boxed::Box, collections::VecDeque, sync::Arc}; +use alloc::{boxed::Box, collections::VecDeque, sync::Arc, vec}; #[cfg(feature = "irq")] use axdriver::register_interrupt_handler; use axsync::Mutex; @@ -12,8 +12,8 @@ use driver_net::{DevError, NetBuf, NetBufBox, NetBufPool, NetBufPtr}; use lazy_init::LazyInit; use lwip_rust::bindings::{ err_enum_t_ERR_MEM, err_enum_t_ERR_OK, err_t, etharp_output, ethernet_input, ip4_addr_t, - lwip_htonl, lwip_init, netif, netif_add, netif_set_default, netif_set_link_up, netif_set_up, - pbuf, pbuf_free, rx_custom_pbuf_alloc, rx_custom_pbuf_free, rx_custom_pbuf_init, + lwip_htonl, lwip_init, netif, netif_add, netif_poll, netif_set_default, netif_set_link_up, + netif_set_up, pbuf, pbuf_free, rx_custom_pbuf_alloc, rx_custom_pbuf_free, rx_custom_pbuf_init, rx_custom_pbuf_t, sys_check_timeouts, NETIF_FLAG_BROADCAST, NETIF_FLAG_ETHARP, NETIF_FLAG_ETHERNET, }; @@ -203,6 +203,9 @@ static ETH0: LazyInit = LazyInit::new(); /// packets to the NIC. pub fn poll_interfaces() { ETH0.poll(); + unsafe { + netif_poll(&mut ETH0.netif.lock().0); + } } fn ip4_addr_gen(a: u8, b: u8, c: u8, d: u8) -> ip4_addr_t { @@ -212,58 +215,67 @@ fn ip4_addr_gen(a: u8, b: u8, c: u8, d: u8) -> ip4_addr_t { }, } } +pub fn init() {} -pub fn init(mut net_dev: AxNetDevice) { - LWIP_MUTEX.init_by(Mutex::new(0)); - let _guard = LWIP_MUTEX.lock(); - - let ipaddr: ip4_addr_t = ip4_addr_gen(10, 0, 2, 15); // QEMU user networking default IP - let netmask: ip4_addr_t = ip4_addr_gen(255, 255, 255, 0); - let gw: ip4_addr_t = ip4_addr_gen(10, 0, 2, 2); // QEMU user networking gateway - - let dev = net_dev; - let mut netif: netif = unsafe { core::mem::zeroed() }; - netif.hwaddr_len = 6; - netif.hwaddr = dev.mac_address().0; - - ETH0.init_by(InterfaceWrapper { - name: "eth0", - dev: Arc::new(Mutex::new(DeviceWrapper::new(dev))), - netif: Mutex::new(NetifWrapper(netif)), - }); +pub fn init_netdev(mut net_dev: AxNetDevice) { + match net_dev.device_name() { + "loopback" => { + info!("use lwip netif loopback"); + } + _ => { + LWIP_MUTEX.init_by(Mutex::new(0)); + let _guard = LWIP_MUTEX.lock(); + + let ipaddr: ip4_addr_t = ip4_addr_gen(10, 0, 2, 15); // QEMU user networking default IP + let netmask: ip4_addr_t = ip4_addr_gen(255, 255, 255, 0); + let gw: ip4_addr_t = ip4_addr_gen(10, 0, 2, 2); // QEMU user networking gateway + + let dev = net_dev; + let mut netif: netif = unsafe { core::mem::zeroed() }; + netif.hwaddr_len = 6; + netif.hwaddr = dev.mac_address().0; + + ETH0.init_by(InterfaceWrapper { + name: "eth0", + dev: Arc::new(Mutex::new(DeviceWrapper::new(dev))), + netif: Mutex::new(NetifWrapper(netif)), + }); + + unsafe { + lwip_init(); + rx_custom_pbuf_init(); + netif_add( + &mut ETH0.netif.lock().0, + &ipaddr, + &netmask, + &gw, + Ð0 as *const _ as *mut c_void, + Some(ethif_init), + Some(ethernet_input), + ); + netif_set_link_up(&mut ETH0.netif.lock().0); + netif_set_up(&mut ETH0.netif.lock().0); + netif_set_default(&mut ETH0.netif.lock().0); + } - unsafe { - lwip_init(); - rx_custom_pbuf_init(); - netif_add( - &mut ETH0.netif.lock().0, - &ipaddr, - &netmask, - &gw, - Ð0 as *const _ as *mut c_void, - Some(ethif_init), - Some(ethernet_input), - ); - netif_set_link_up(&mut ETH0.netif.lock().0); - netif_set_up(&mut ETH0.netif.lock().0); - netif_set_default(&mut ETH0.netif.lock().0); + info!("created net interface {:?}:", ETH0.name()); + info!( + " ether: {}", + MacAddr::from_bytes(Ð0.netif.lock().0.hwaddr) + ); + let ip = IpAddr::from(ETH0.netif.lock().0.ip_addr); + let mask = mask_to_prefix(IpAddr::from(ETH0.netif.lock().0.netmask)).unwrap(); + info!(" ip: {}/{}", ip, mask); + info!(" gateway: {}", IpAddr::from(ETH0.netif.lock().0.gw)); + } } - - info!("created net interface {:?}:", ETH0.name()); - info!( - " ether: {}", - MacAddr::from_bytes(Ð0.netif.lock().0.hwaddr) - ); - let ip = IpAddr::from(ETH0.netif.lock().0.ip_addr); - let mask = mask_to_prefix(IpAddr::from(ETH0.netif.lock().0.netmask)).unwrap(); - info!(" ip: {}/{}", ip, mask); - info!(" gateway: {}", IpAddr::from(ETH0.netif.lock().0.gw)); } pub fn lwip_loop_once() { let guard = LWIP_MUTEX.lock(); unsafe { ETH0.poll(); + netif_poll(&mut ETH0.netif.lock().0); sys_check_timeouts(); } drop(guard); diff --git a/modules/ruxnet/src/lwip_impl/mod.rs b/modules/ruxnet/src/lwip_impl/mod.rs index ccc72eca6..87084c607 100644 --- a/modules/ruxnet/src/lwip_impl/mod.rs +++ b/modules/ruxnet/src/lwip_impl/mod.rs @@ -6,7 +6,7 @@ mod udp; pub use self::addr::{IpAddr, Ipv4Addr, SocketAddr}; pub use self::dns::{dns_query, resolve_socket_addr}; -pub use self::driver::{init, poll_interfaces}; +pub use self::driver::{init, init_netdev, poll_interfaces}; pub use self::tcp::TcpSocket; pub use self::udp::UdpSocket; use core::ffi::c_uint; diff --git a/modules/ruxnet/src/smoltcp_impl/dns.rs b/modules/ruxnet/src/smoltcp_impl/dns.rs index 00b7c0575..53e7db29f 100644 --- a/modules/ruxnet/src/smoltcp_impl/dns.rs +++ b/modules/ruxnet/src/smoltcp_impl/dns.rs @@ -16,7 +16,7 @@ use smoltcp::socket::dns::{self, GetQueryResultError, StartQueryError}; use smoltcp::wire::DnsQueryType; use super::addr::into_core_ipaddr; -use super::{SocketSetWrapper, ETH0, SOCKET_SET}; +use super::{SocketSetWrapper, IFACE_LIST, SOCKET_SET}; /// A DNS socket. struct DnsSocket { @@ -44,7 +44,12 @@ impl DnsSocket { pub fn query(&self, name: &str, query_type: DnsQueryType) -> AxResult> { // let local_addr = self.local_addr.unwrap_or_else(f); let handle = self.handle.ok_or_else(|| ax_err_type!(InvalidInput))?; - let iface = Ð0.iface; + let binding = IFACE_LIST.lock(); + let iface = &binding + .iter() + .find(|iface| iface.name() == "eth0") + .unwrap() + .iface; let query_handle = SOCKET_SET .with_socket_mut::(handle, |socket| { socket.start_query(iface.lock().context(), name, query_type) diff --git a/modules/ruxnet/src/smoltcp_impl/mod.rs b/modules/ruxnet/src/smoltcp_impl/mod.rs index da911f2f7..192fe2d93 100644 --- a/modules/ruxnet/src/smoltcp_impl/mod.rs +++ b/modules/ruxnet/src/smoltcp_impl/mod.rs @@ -14,6 +14,7 @@ mod listen_table; mod tcp; mod udp; +use alloc::string::{String, ToString}; use alloc::vec; use core::cell::RefCell; use core::ops::DerefMut; @@ -35,6 +36,8 @@ pub use self::dns::dns_query; pub use self::tcp::TcpSocket; pub use self::udp::UdpSocket; +pub use driver_net::loopback::LoopbackDevice; + macro_rules! env_or_default { ($key:literal) => { match option_env!($key) { @@ -61,7 +64,15 @@ const LISTEN_QUEUE_SIZE: usize = 512; static LISTEN_TABLE: LazyInit = LazyInit::new(); static SOCKET_SET: LazyInit = LazyInit::new(); -static ETH0: LazyInit = LazyInit::new(); +static IFACE_LIST: LazyInit>> = LazyInit::new(); + +fn route_dev(addr: [u8; 4]) -> String { + if addr[0] == 127 { + "loopback".to_string() + } else { + "eth0".to_string() + } +} struct SocketSetWrapper<'a>(Mutex>); @@ -129,7 +140,9 @@ impl<'a> SocketSetWrapper<'a> { } pub fn poll_interfaces(&self) { - ETH0.poll(&self.0); + for iface in IFACE_LIST.lock().iter() { + iface.poll(&self.0); + } } pub fn remove(&self, handle: SocketHandle) { @@ -311,29 +324,65 @@ pub fn poll_interfaces() { /// Benchmark raw socket transmit bandwidth. pub fn bench_transmit() { - ETH0.dev.lock().bench_transmit_bandwidth(); + IFACE_LIST + .lock() + .iter() + .find(|iface| iface.name() == "eth0") + .unwrap() + .dev + .lock() + .bench_transmit_bandwidth(); } /// Benchmark raw socket receive bandwidth. pub fn bench_receive() { - ETH0.dev.lock().bench_receive_bandwidth(); + IFACE_LIST + .lock() + .iter() + .find(|iface| iface.name() == "eth0") + .unwrap() + .dev + .lock() + .bench_receive_bandwidth(); } -pub(crate) fn init(net_dev: AxNetDevice) { - let ether_addr = EthernetAddress(net_dev.mac_address().0); - let eth0 = InterfaceWrapper::new("eth0", net_dev, ether_addr); - - let ip = IP.parse().expect("invalid IP address"); - let gateway = GATEWAY.parse().expect("invalid gateway IP address"); - eth0.setup_ip_addr(ip, IP_PREFIX); - eth0.setup_gateway(gateway); +pub(crate) fn init() { + let mut socketset = SocketSetWrapper::new(); - ETH0.init_by(eth0); - SOCKET_SET.init_by(SocketSetWrapper::new()); + IFACE_LIST.init_by(Mutex::new(vec::Vec::new())); + SOCKET_SET.init_by(socketset); LISTEN_TABLE.init_by(ListenTable::new()); +} + +pub(crate) fn init_netdev(net_dev: AxNetDevice) { + match net_dev.device_name() { + "loopback" => { + let ether_addr = EthernetAddress(net_dev.mac_address().0); + let lo = InterfaceWrapper::new("loopback", net_dev, ether_addr); - info!("created net interface {:?}:", ETH0.name()); - info!(" ether: {}", ETH0.ethernet_address()); - info!(" ip: {}/{}", ip, IP_PREFIX); - info!(" gateway: {}", gateway); + let ip = "127.0.0.1".parse().expect("invalid IP address"); + lo.setup_ip_addr(ip, IP_PREFIX); + + info!("created net interface {:?}:", lo.name()); + info!(" ether: {}", lo.ethernet_address()); + info!(" ip: {}/{}", "127.0.0.1", IP_PREFIX); + IFACE_LIST.lock().push(lo); + } + _ => { + let ether_addr = EthernetAddress(net_dev.mac_address().0); + let eth0 = InterfaceWrapper::new("eth0", net_dev, ether_addr); + + let ip = IP.parse().expect("invalid IP address"); + let gateway = GATEWAY.parse().expect("invalid gateway IP address"); + eth0.setup_ip_addr(ip, IP_PREFIX); + eth0.setup_gateway(gateway); + + info!("created net interface {:?}:", eth0.name()); + info!(" ether: {}", eth0.ethernet_address()); + info!(" ip: {}/{}", ip, IP_PREFIX); + info!(" gateway: {}", gateway); + + IFACE_LIST.lock().push(eth0); + } + } } diff --git a/modules/ruxnet/src/smoltcp_impl/tcp.rs b/modules/ruxnet/src/smoltcp_impl/tcp.rs index de9c14fd5..45978f71e 100644 --- a/modules/ruxnet/src/smoltcp_impl/tcp.rs +++ b/modules/ruxnet/src/smoltcp_impl/tcp.rs @@ -20,7 +20,7 @@ use smoltcp::socket::tcp::{self, ConnectError, State}; use smoltcp::wire::{IpEndpoint, IpListenEndpoint}; use super::addr::{from_core_sockaddr, into_core_sockaddr, is_unspecified, UNSPECIFIED_ENDPOINT}; -use super::{SocketSetWrapper, ETH0, LISTEN_TABLE, SOCKET_SET}; +use super::{route_dev, SocketSetWrapper, IFACE_LIST, LISTEN_TABLE, SOCKET_SET}; // State transitions: // CLOSED -(connect)-> BUSY -> CONNECTING -> CONNECTED -(shutdown)-> BUSY -> CLOSED @@ -139,7 +139,16 @@ impl TcpSocket { // TODO: check remote addr unreachable let remote_endpoint = from_core_sockaddr(remote_addr); let bound_endpoint = self.bound_endpoint()?; - let iface = Ð0.iface; + let binding = IFACE_LIST.lock(); + let iface_name = match remote_addr { + SocketAddr::V4(addr) => route_dev(addr.ip().octets()), + _ => panic!("IPv6 not supported"), + }; + let iface = &binding + .iter() + .find(|iface| iface.name() == iface_name) + .unwrap() + .iface; let (local_endpoint, remote_endpoint) = SOCKET_SET .with_socket_mut::(handle, |socket| { socket