1use secgate::TwzError;
2use smoltcp::{
3 phy::{Device as _, TxToken},
4 time::Instant,
5 wire::{EthernetFrame, PrettyPrinter},
6};
7use twizzler_abi::syscall::sys_thread_sync;
8use twizzler_net::drivers::{NetDriver, Packet, QueueHandle, WorkItems};
9use virtio_net::{DeviceWrapper, TwizzlerTransport};
10
11use crate::NETINFO;
12
13pub fn device_thread(device: DeviceWrapper<TwizzlerTransport>) {
14 loop {
15 while let Some(mut rx) = device.get_rx() {
16 let buf = rx.packet_mut();
17 if false {
18 let f = EthernetFrame::new_unchecked(&mut *buf);
19 let pp = PrettyPrinter::<EthernetFrame<&mut [u8]>>::print(&f);
20 eprintln!("device thread got {}", pp);
21 }
22 let handles = NETINFO.get().unwrap().handles.lock().unwrap();
23 for (_, _, client) in handles.handles() {
24 let mut ep = client.ep.lock().unwrap();
25 let ctx = ep.transmit(Instant::now()).unwrap();
26 ctx.consume(buf.len(), |cbuf| cbuf.copy_from_slice(buf));
27 }
28 device.recycle(rx);
29 }
30
31 if !device.has_work() {
32 let sleep = device.get_sleep();
33 if !device.has_work() {
34 let _ = sys_thread_sync(&mut [sleep], None);
35 }
36 }
37 }
38}
39
40fn handle_work(
41 device: &mut Box<dyn NetDriver>,
42 queue: QueueHandle,
43 work: WorkItems,
44 inject: &mut impl FnMut(&[Packet]) -> Result<usize, TwzError>,
45 packets: &mut [Packet],
46) {
47 if work.contains(WorkItems::RX_READY) {
48 if let Ok(count) = device.recv_packets(queue, packets) {
49 let mut injected = 0;
50 while injected < count {
51 if let Ok(injected_count) = inject(&packets[injected..count]) {
52 injected += injected_count;
53 } else {
54 break;
55 }
56 }
57 }
58 }
59 if work.contains(WorkItems::STATUS_CHANGE) {
60 tracing::info!("link status change");
61 }
62 if work.contains(WorkItems::TX_ERROR) {
63 tracing::error!("tx error");
64 }
65 if work.contains(WorkItems::RX_ERROR) {
66 tracing::error!("rx error");
67 }
68}
69
70pub fn device_thread_main(
71 mut device: Box<dyn NetDriver>,
72 mut inject: impl FnMut(&[Packet]) -> Result<usize, TwzError>,
73) {
74 let rx_queues = device.rx_queues();
75 let mut packets = vec![Packet::default(); 32];
76 let mut waitpoints = rx_queues
77 .iter()
78 .map(|q| device.waitpoint(*q))
79 .collect::<Vec<_>>();
80 let mut counter = 0;
81 loop {
82 for q in &rx_queues {
83 let work = device.has_work(*q);
84 if !work.is_empty() {
85 counter = 100;
86 handle_work(&mut device, *q, work, &mut inject, packets.as_mut_slice());
87 }
88 }
89 if counter > 0 {
90 counter -= 1;
91 } else {
92 let mut any_ready = false;
93 for (i, q) in rx_queues.iter().enumerate() {
94 let wp = device.waitpoint(*q);
95 let work = device.has_work(*q);
96 if !work.is_empty() {
97 any_ready = true;
98 handle_work(&mut device, *q, work, &mut inject, packets.as_mut_slice());
99 }
100 waitpoints[i] = wp;
101 }
102 if !any_ready {
103 let _ = sys_thread_sync(waitpoints.as_mut_slice(), None);
104 }
105 }
106 }
107}