net_srv/
device.rs

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}