Skip to content

Commit d109ed6

Browse files
committed
feat(net): add netlink route
1 parent 5fa4958 commit d109ed6

32 files changed

Lines changed: 2534 additions & 11 deletions

api/axfeat/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ fs-times = ["fs", "axfs/times"]
6868
# Networking
6969
net = ["alloc", "paging", "axdriver/virtio-net", "dep:axnet", "axruntime/net"]
7070
vsock = ["net", "axdriver/virtio-socket", "axruntime/vsock", "axnet/vsock"]
71+
netlink = ["net", "axnet/netlink"]
7172

7273
# Display
7374
display = [

modules/axnet/Cargo.toml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ documentation = "https://arceos-org.github.io/arceos/axnet/index.html"
1111

1212
[features]
1313
vsock = ["axdriver/vsock"]
14+
netlink = []
1415

1516
[dependencies]
1617
async-channel = { version = "2.5", default-features = false }
@@ -25,13 +26,20 @@ axio = { workspace = true }
2526
axpoll = { workspace = true }
2627
axsync = { workspace = true }
2728
axtask = { workspace = true }
28-
bitflags = "2.9.1"
29+
bitflags = { version = "2.9.1", features = ["bytemuck"] }
30+
bytemuck = { version = "1.23", features = ["derive"] }
2931
cfg-if = { workspace = true }
3032
enum_dispatch = { workspace = true }
3133
event-listener = { version = "5.4", default-features = false }
3234
hashbrown = "0.16"
3335
lazy_static = { workspace = true }
3436
log = { workspace = true }
37+
memory_addr = { workspace = true }
38+
num_enum = { version = "0.7", default-features = false }
39+
rand = { version = "0.9", default-features = false, features = [
40+
"alloc",
41+
"small_rng",
42+
] }
3543
ringbuf = { version = "0.4.8", default-features = false, features = ["alloc"] }
3644
spin = { workspace = true }
3745

modules/axnet/src/consts.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,5 @@ pub const LISTEN_QUEUE_SIZE: usize = 512;
2121

2222
pub const SOCKET_BUFFER_SIZE: usize = 64;
2323
pub const ETHERNET_MAX_PENDING_PACKETS: usize = 32;
24+
25+
pub const NETLINK_DEFAULT_BUF_SIZE: usize = 65536;

modules/axnet/src/device/ethernet.rs

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@ use smoltcp::{
99
time::{Duration, Instant},
1010
wire::{
1111
ArpOperation, ArpPacket, ArpRepr, EthernetAddress, EthernetFrame, EthernetProtocol,
12-
EthernetRepr, IpAddress, Ipv4Cidr,
12+
EthernetRepr, IpAddress, Ipv4Address, Ipv4Cidr,
1313
},
1414
};
1515

1616
use crate::{
1717
consts::{ETHERNET_MAX_PENDING_PACKETS, STANDARD_MTU},
18-
device::Device,
18+
device::{Device, DeviceFlags, DeviceType},
1919
};
2020

2121
const EMPTY_MAC: EthernetAddress = EthernetAddress([0; 6]);
@@ -26,6 +26,7 @@ struct Neighbor {
2626
}
2727

2828
pub struct EthernetDevice {
29+
index: u32,
2930
name: String,
3031
inner: AxNetDevice,
3132
neighbors: HashMap<IpAddress, Option<Neighbor>>,
@@ -36,7 +37,7 @@ pub struct EthernetDevice {
3637
impl EthernetDevice {
3738
const NEIGHBOR_TTL: Duration = Duration::from_secs(60);
3839

39-
pub fn new(name: String, inner: AxNetDevice, ip: Ipv4Cidr) -> Self {
40+
pub fn new(index: u32, name: String, inner: AxNetDevice, ip: Ipv4Cidr) -> Self {
4041
let pending_packets = PacketBuffer::new(
4142
vec![PacketMetadata::EMPTY; ETHERNET_MAX_PENDING_PACKETS],
4243
vec![
@@ -46,6 +47,7 @@ impl EthernetDevice {
4647
],
4748
);
4849
Self {
50+
index,
4951
name,
5052
inner,
5153
neighbors: HashMap::new(),
@@ -261,6 +263,30 @@ impl Device for EthernetDevice {
261263
&self.name
262264
}
263265

266+
fn get_type(&self) -> DeviceType {
267+
DeviceType::ETHER
268+
}
269+
270+
fn get_flags(&self) -> DeviceFlags {
271+
DeviceFlags::UP
272+
| DeviceFlags::BROADCAST
273+
| DeviceFlags::RUNNING
274+
| DeviceFlags::LOWER_UP
275+
| DeviceFlags::MULTICAST
276+
}
277+
278+
fn get_index(&self) -> u32 {
279+
self.index
280+
}
281+
282+
fn ipv4_addr(&self) -> Option<Ipv4Address> {
283+
Some(self.ip.address())
284+
}
285+
286+
fn prefix_len(&self) -> Option<u8> {
287+
Some(self.ip.prefix_len())
288+
}
289+
264290
fn recv(&mut self, buffer: &mut PacketBuffer<()>, timestamp: Instant) -> bool {
265291
loop {
266292
let rx_buf = match self.inner.receive() {

modules/axnet/src/device/loopback.rs

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use alloc::vec;
2-
use core::task::Waker;
2+
use core::{net::Ipv4Addr, task::Waker};
33

44
use axpoll::PollSet;
55
use smoltcp::{
@@ -10,20 +10,22 @@ use smoltcp::{
1010

1111
use crate::{
1212
consts::{SOCKET_BUFFER_SIZE, STANDARD_MTU},
13-
device::Device,
13+
device::{Device, DeviceFlags, DeviceType},
1414
};
1515

1616
pub struct LoopbackDevice {
17+
index: u32,
1718
buffer: PacketBuffer<'static, ()>,
1819
poll: PollSet,
1920
}
2021
impl LoopbackDevice {
21-
pub fn new() -> Self {
22+
pub fn new(index: u32) -> Self {
2223
let buffer = PacketBuffer::new(
2324
vec![PacketMetadata::EMPTY; SOCKET_BUFFER_SIZE],
2425
vec![0u8; STANDARD_MTU * SOCKET_BUFFER_SIZE],
2526
);
2627
Self {
28+
index,
2729
buffer,
2830
poll: PollSet::new(),
2931
}
@@ -35,6 +37,26 @@ impl Device for LoopbackDevice {
3537
"lo"
3638
}
3739

40+
fn get_type(&self) -> DeviceType {
41+
DeviceType::LOOPBACK
42+
}
43+
44+
fn get_flags(&self) -> DeviceFlags {
45+
DeviceFlags::UP | DeviceFlags::LOOPBACK | DeviceFlags::RUNNING
46+
}
47+
48+
fn get_index(&self) -> u32 {
49+
self.index
50+
}
51+
52+
fn ipv4_addr(&self) -> Option<Ipv4Addr> {
53+
Some(Ipv4Addr::new(127, 0, 0, 1))
54+
}
55+
56+
fn prefix_len(&self) -> Option<u8> {
57+
Some(8)
58+
}
59+
3860
fn recv(&mut self, buffer: &mut PacketBuffer<()>, _timestamp: Instant) -> bool {
3961
self.buffer.dequeue().ok().is_some_and(|(_, rx_buf)| {
4062
buffer

modules/axnet/src/device/mod.rs

Lines changed: 95 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
use core::task::Waker;
22

3-
use smoltcp::{storage::PacketBuffer, time::Instant, wire::IpAddress};
3+
use bitflags::bitflags;
4+
use num_enum::TryFromPrimitive;
5+
use smoltcp::{
6+
storage::PacketBuffer,
7+
time::Instant,
8+
wire::{IpAddress, Ipv4Address},
9+
};
410

511
mod ethernet;
612
mod loopback;
@@ -15,6 +21,16 @@ pub use vsock::*;
1521
pub trait Device: Send + Sync {
1622
fn name(&self) -> &str;
1723

24+
fn get_type(&self) -> DeviceType;
25+
26+
fn get_flags(&self) -> DeviceFlags;
27+
28+
fn get_index(&self) -> u32;
29+
30+
fn ipv4_addr(&self) -> Option<Ipv4Address>;
31+
32+
fn prefix_len(&self) -> Option<u8>;
33+
1834
fn recv(&mut self, buffer: &mut PacketBuffer<()>, timestamp: Instant) -> bool;
1935
/// Sends a packet to the next hop.
2036
///
@@ -25,3 +41,81 @@ pub trait Device: Send + Sync {
2541

2642
fn register_waker(&self, waker: &Waker);
2743
}
44+
45+
/// Device type.
46+
///
47+
/// Reference: <https://elixir.bootlin.com/linux/v6.0.18/source/include/uapi/linux/if_arp.h#L30>
48+
#[repr(u16)]
49+
#[derive(Debug, Clone, Copy, PartialEq, Eq, TryFromPrimitive)]
50+
#[allow(dead_code)]
51+
pub enum DeviceType {
52+
// Arp protocol hardware identifiers
53+
/// from KA9Q: NET/ROM pseudo
54+
NETROM = 0,
55+
/// Ethernet 10Mbps
56+
ETHER = 1,
57+
/// Experimental Ethernet
58+
EETHER = 2,
59+
60+
// Dummy types for non ARP hardware
61+
/// IPIP tunnel
62+
TUNNEL = 768,
63+
/// IP6IP6 tunnel
64+
TUNNEL6 = 769,
65+
/// Frame Relay Access Device
66+
FRAD = 770,
67+
/// SKIP vif
68+
SKIP = 771,
69+
/// Loopback device
70+
LOOPBACK = 772,
71+
/// Localtalk device
72+
LOCALTALK = 773,
73+
// TODO: This enum is not exhaustive
74+
}
75+
76+
bitflags! {
77+
/// Device flags.
78+
///
79+
/// Reference: <https://elixir.bootlin.com/linux/v6.0.18/source/include/uapi/linux/if.h#L82>
80+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
81+
pub struct DeviceFlags: u32 {
82+
/// Device is up
83+
const UP = 1<<0;
84+
/// Broadcast address valid
85+
const BROADCAST = 1<<1;
86+
/// Turn on debugging
87+
const DEBUG = 1<<2;
88+
/// Loopback net
89+
const LOOPBACK = 1<<3;
90+
/// Device is has p-p link
91+
const POINTOPOINT = 1<<4;
92+
/// Avoid use of trailers
93+
const NOTRAILERS = 1<<5;
94+
/// Device RFC2863 OPER_UP
95+
const RUNNING = 1<<6;
96+
/// No ARP protocol
97+
const NOARP = 1<<7;
98+
/// Receive all packets
99+
const PROMISC = 1<<8;
100+
/// Receive all multicast packets
101+
const ALLMULTI = 1<<9;
102+
/// Master of a load balancer
103+
const MASTER = 1<<10;
104+
/// Slave of a load balancer
105+
const SLAVE = 1<<11;
106+
/// Supports multicast
107+
const MULTICAST = 1<<12;
108+
/// Can set media type
109+
const PORTSEL = 1<<13;
110+
/// Auto media select active
111+
const AUTOMEDIA = 1<<14;
112+
/// Dialup device with changing addresses
113+
const DYNAMIC = 1<<15;
114+
/// Driver signals L1 up
115+
const LOWER_UP = 1<<16;
116+
/// Driver signals dormant
117+
const DORMANT = 1<<17;
118+
/// Echo sent packets
119+
const ECHO = 1<<18;
120+
}
121+
}

modules/axnet/src/lib.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
//! [smoltcp]: https://github.com/smoltcp-rs/smoltcp
1414
1515
#![no_std]
16+
#![feature(associated_type_defaults)]
1617

1718
#[macro_use]
1819
extern crate log;
@@ -32,9 +33,13 @@ pub mod udp;
3233
pub mod unix;
3334
#[cfg(feature = "vsock")]
3435
pub mod vsock;
36+
#[cfg(feature = "netlink")]
37+
pub mod netlink;
38+
3539
mod wrapper;
3640

3741
use alloc::{borrow::ToOwned, boxed::Box};
42+
use core::sync::atomic::{AtomicU32, Ordering};
3843

3944
use axdriver::{AxDeviceContainer, prelude::*};
4045
use axsync::Mutex;
@@ -56,6 +61,8 @@ static SOCKET_SET: Lazy<SocketSetWrapper> = Lazy::new(SocketSetWrapper::new);
5661

5762
static SERVICE: Once<Mutex<Service>> = Once::new();
5863

64+
static DEVICE_INDEX_COUNTER: AtomicU32 = AtomicU32::new(1);
65+
5966
fn get_service() -> axsync::MutexGuard<'static, Service> {
6067
SERVICE
6168
.get()
@@ -68,7 +75,8 @@ pub fn init_network(mut net_devs: AxDeviceContainer<AxNetDevice>) {
6875
info!("Initialize network subsystem...");
6976

7077
let mut router = Router::new();
71-
let lo_dev = router.add_device(Box::new(LoopbackDevice::new()));
78+
let index = DEVICE_INDEX_COUNTER.fetch_add(1, Ordering::Relaxed);
79+
let lo_dev = router.add_device(Box::new(LoopbackDevice::new(index)));
7280

7381
let lo_ip = Ipv4Cidr::new(Ipv4Address::new(127, 0, 0, 1), 8);
7482
router.add_rule(Rule::new(
@@ -85,6 +93,7 @@ pub fn init_network(mut net_devs: AxDeviceContainer<AxNetDevice>) {
8593
let eth0_ip = Ipv4Cidr::new(IP.parse().expect("Invalid IPv4 address"), IP_PREFIX);
8694

8795
let eth0_dev = router.add_device(Box::new(EthernetDevice::new(
96+
DEVICE_INDEX_COUNTER.fetch_add(1, Ordering::Relaxed),
8897
"eth0".to_owned(),
8998
dev,
9099
eth0_ip,

0 commit comments

Comments
 (0)