strat9_kernel/hardware/nic/
mod.rs1pub mod common;
7pub mod data_plane;
8pub mod e1000_drv;
9pub mod e1000e_drv;
10pub mod igc_drv;
11pub mod pcnet_drv;
12pub mod rtl8139_drv;
13pub mod scheme;
14pub mod virtio_net;
15
16pub use net_core::{NetError, NetworkDevice, MTU};
17
18use alloc::{format, string::String, sync::Arc, vec::Vec};
19use spin::RwLock;
20
21struct NetDeviceEntry {
22 iface: String,
23 device: Arc<dyn NetworkDevice>,
24}
25
26static NET_DEVICES: RwLock<Vec<NetDeviceEntry>> = RwLock::new(Vec::new());
27
28fn bsd_prefix(driver_name: &str) -> &'static str {
36 let lower = driver_name.as_bytes();
37 if lower.len() >= 4
39 && (lower[0] | 0x20) == b'e'
40 && (lower[1] | 0x20) == b'1'
41 && lower[2] == b'0'
42 && lower[3] == b'0'
43 {
44 return "em"; }
46 if lower.len() >= 6
47 && (lower[0] | 0x20) == b'v'
48 && (lower[1] | 0x20) == b'i'
49 && (lower[2] | 0x20) == b'r'
50 && (lower[3] | 0x20) == b't'
51 && (lower[4] | 0x20) == b'i'
52 && (lower[5] | 0x20) == b'o'
53 {
54 return "vtnet"; }
56 "net" }
58
59static PREFIX_COUNTERS: RwLock<Vec<(String, usize)>> = RwLock::new(Vec::new());
61
62fn next_index_for(prefix: &str) -> usize {
64 let mut counters = PREFIX_COUNTERS.write();
65 for entry in counters.iter_mut() {
66 if entry.0 == prefix {
67 let idx = entry.1;
68 entry.1 += 1;
69 return idx;
70 }
71 }
72 counters.push((String::from(prefix), 1));
73 0
74}
75
76pub static NIC_IRQ_LINE: core::sync::atomic::AtomicU8 = core::sync::atomic::AtomicU8::new(0xFF);
83
84static NIC_DEVICE: spin::Mutex<Option<Arc<dyn NetworkDevice>>> = spin::Mutex::new(None);
92
93pub fn set_nic_device(dev: Arc<dyn NetworkDevice>, irq: u8) {
98 NIC_IRQ_LINE.store(irq, core::sync::atomic::Ordering::Relaxed);
99 *NIC_DEVICE.lock() = Some(dev);
100 log::info!("NIC dispatch set for IRQ {}", irq);
101}
102
103pub fn nic_irq_ready() -> bool {
108 NIC_DEVICE.lock().is_some()
109}
110
111static STRATE_NET_TID: core::sync::atomic::AtomicU64 = core::sync::atomic::AtomicU64::new(0);
125
126pub fn register_strate_net_tid(tid: u64) {
128 STRATE_NET_TID.store(tid, core::sync::atomic::Ordering::Relaxed);
129 log::info!("NIC: strate-net task {} registered for IRQ wakeup", tid);
130}
131
132pub fn handle_interrupt() {
137 let dev = {
139 let guard = NIC_DEVICE.lock();
140 guard.as_ref().map(|d| {
141 d.handle_interrupt();
142 d.clone()
143 })
144 };
145 let dev = match dev {
146 Some(d) => d,
147 None => {
148 crate::serial_println!("[net] IRQ: no NIC device registered");
149 return;
150 }
151 };
152
153 if let Some(ref dp) = *NIC_DATA_PLANE.lock() {
156 const MAX_IRQ_DRAIN: usize = 32;
159 let mut buf = [0u8; 2048];
160 let mut rx_count = 0usize;
161 let mut backpressure = false;
162 while rx_count < MAX_IRQ_DRAIN {
163 let n = match dev.receive(&mut buf) {
164 Ok(0) | Err(_) => break,
165 Ok(n) => n,
166 };
167 rx_count += 1;
168 if rx_count <= 3 {
169 crate::serial_println!("[net] IRQ rx {} bytes (slot {})", n, rx_count);
170 }
171 if dp.push_rx(0, &buf[..n]).is_err() {
172 crate::serial_println!("[net] IRQ RX ring full, backpressure");
173 backpressure = true;
174 break;
175 }
176 }
177 if rx_count > 3 {
178 crate::serial_println!("[net] IRQ rx total {} packets", rx_count);
179 }
180 if rx_count == 0 {
181 crate::serial_println!("[net] IRQ rx: no packets received from HW");
182 }
183
184 if backpressure {
186 crate::ipc::n1::notify_scheduler(crate::ipc::n1::N1Event::NicBackpressure);
187 }
188
189 if rx_count > 0 {
191 dp.notify_rx_consumer(0);
192 }
193
194 let mut tx_buf = [0u8; 2048];
196 while let Ok(Some(n)) = dp.pop_tx(0, &mut tx_buf) {
197 if dev.transmit(&tx_buf[..n]).is_err() {
198 break;
199 }
200 }
201
202 if let Some(event) = crate::ipc::n1::poll_nic_events() {
204 log::trace!("[net] N1 sched=>NIC event: {:?}", event);
205 }
206 } else {
207 crate::serial_println!("[net] IRQ: N2 data plane not initialized");
208 }
209
210 let tid_u64 = STRATE_NET_TID.load(core::sync::atomic::Ordering::Relaxed);
211 if tid_u64 != 0 {
212 let _ = crate::process::scheduler::wake_task(crate::process::TaskId(tid_u64));
213 } else {
214 crate::serial_println!("[net] IRQ: strate-net not registered (TID=0)");
215 }
216}
217
218pub fn register_device(device: Arc<dyn NetworkDevice>) -> String {
220 let prefix = bsd_prefix(device.name());
221 let idx = next_index_for(prefix);
222 let iface = format!("{}{}", prefix, idx);
223 let mac = device.mac_address();
224 log::info!(
225 "[net] {} -> {} (MAC {:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x})",
226 device.name(),
227 iface,
228 mac[0],
229 mac[1],
230 mac[2],
231 mac[3],
232 mac[4],
233 mac[5],
234 );
235 let mut devs = NET_DEVICES.write();
236 devs.push(NetDeviceEntry {
237 iface: iface.clone(),
238 device,
239 });
240 iface
241}
242
243pub fn get_device(name: &str) -> Option<Arc<dyn NetworkDevice>> {
245 NET_DEVICES
246 .read()
247 .iter()
248 .find(|e| e.iface == name)
249 .map(|e| e.device.clone())
250}
251
252pub fn get_default_device() -> Option<Arc<dyn NetworkDevice>> {
254 NET_DEVICES.read().first().map(|e| e.device.clone())
255}
256
257pub fn list_interfaces() -> Vec<String> {
259 NET_DEVICES.read().iter().map(|e| e.iface.clone()).collect()
260}
261
262pub fn poll_all() {
266 {
267 let guard = NET_DEVICES.read();
268 for entry in guard.iter() {
269 entry.device.poll();
270 }
271 }
272
273 if !nic_irq_ready() {
276 service_data_plane_polling();
277 }
278}
279
280fn service_data_plane_polling() {
282 let device = match get_default_device() {
283 Some(d) => d,
284 None => return,
285 };
286 let dp_guard = NIC_DATA_PLANE.lock();
287 let dp = match dp_guard.as_ref() {
288 Some(dp) => dp,
289 None => {
290 return;
292 }
293 };
294
295 let mut buf = [0u8; 2048];
296 let mut rx_count = 0usize;
297 while rx_count < 8 {
298 let n = match device.receive(&mut buf) {
299 Ok(0) | Err(_) => break,
300 Ok(n) => n,
301 };
302 if dp.push_rx(0, &buf[..n]).is_err() {
303 break;
304 }
305 rx_count += 1;
306 }
307 if rx_count > 0 {
308 dp.notify_rx_consumer(0);
309 }
310
311 let mut tx_buf = [0u8; 2048];
312 while let Ok(Some(n)) = dp.pop_tx(0, &mut tx_buf) {
313 if device.transmit(&tx_buf[..n]).is_err() {
314 break;
315 }
316 }
317}
318
319pub fn try_register_strate_net() {
321 if STRATE_NET_TID.load(core::sync::atomic::Ordering::Relaxed) != 0 {
322 return;
323 }
324 if let Some(tasks) = crate::process::get_all_tasks() {
325 for t in &tasks {
326 if t.name == "strate-net" {
327 register_strate_net_tid(t.id.0);
328 return;
329 }
330 }
331 }
332}
333
334pub fn init() {
336 log::info!("[net] Scanning for network devices...");
337 e1000e_drv::init();
339 igc_drv::init();
340 e1000_drv::init();
341 pcnet_drv::init();
342 rtl8139_drv::init();
343 virtio_net::init();
344 if let Err(e) = scheme::register_net_scheme() {
345 log::warn!("[net] Failed to register net scheme: {:?}", e);
346 }
347 init_data_plane();
349}
350
351use data_plane::NicDataPlane;
354use spin::Mutex;
355
356static NIC_DATA_PLANE: Mutex<Option<NicDataPlane>> = Mutex::new(None);
358
359fn init_data_plane() {
362 let count = NET_DEVICES.read().len();
363 if count == 0 {
364 log::debug!("[net] No NIC devices found : skipping data plane init");
365 return;
366 }
367 match NicDataPlane::new(count, 256, 2048) {
369 Ok(dp) => {
370 *NIC_DATA_PLANE.lock() = Some(dp);
371 log::info!("[net] N2 data plane initialised with {} queue(s)", count);
372 }
373 Err(e) => {
374 log::warn!("[net] Failed to initialise N2 data plane: {}", e);
375 }
376 }
377}
378
379pub fn data_plane() -> &'static Mutex<Option<NicDataPlane>> {
381 &NIC_DATA_PLANE
382}