xref: /DragonOS/kernel/src/driver/net/virtio_net.rs (revision 881ff6f95e4addc373d815d66cb912bf721c20e6)
113776c11Slogin use core::{
213776c11Slogin     cell::UnsafeCell,
313776c11Slogin     fmt::Debug,
413776c11Slogin     ops::{Deref, DerefMut},
513776c11Slogin };
613776c11Slogin 
7c566df45SLoGin use alloc::{
8c566df45SLoGin     string::String,
9c566df45SLoGin     sync::{Arc, Weak},
10c566df45SLoGin };
11*881ff6f9Syuyi2439 use smoltcp::{iface, phy, wire};
1213776c11Slogin use virtio_drivers::{device::net::VirtIONet, transport::Transport};
1313776c11Slogin 
1491e9d4abSLoGin use super::NetDriver;
1513776c11Slogin use crate::{
16*881ff6f9Syuyi2439     arch::rand::rand,
17b087521eSChiichen     driver::{
1806d5e247SLoGin         base::{
19e2841179SLoGin             device::{bus::Bus, driver::Driver, Device, DeviceId, IdTable},
20a03c4f9dSLoGin             kobject::{KObjType, KObject, KObjectState},
2106d5e247SLoGin         },
22e2841179SLoGin         virtio::{irq::virtio_irq_manager, virtio_impl::HalImpl, VirtIODevice},
23d470019bSLoGin     },
24e2841179SLoGin     exception::{irqdesc::IrqReturn, IrqNumber},
25d470019bSLoGin     kerror, kinfo,
2613776c11Slogin     libs::spinlock::SpinLock,
27e2841179SLoGin     net::{generate_iface_id, net_core::poll_ifaces_try_lock_onetime, NET_DRIVERS},
2813776c11Slogin     time::Instant,
2913776c11Slogin };
3091e9d4abSLoGin use system_error::SystemError;
3113776c11Slogin 
3213776c11Slogin /// @brief Virtio网络设备驱动(加锁)
3313776c11Slogin pub struct VirtioNICDriver<T: Transport> {
3413776c11Slogin     pub inner: Arc<SpinLock<VirtIONet<HalImpl, T, 2>>>,
3513776c11Slogin }
3613776c11Slogin 
3713776c11Slogin impl<T: Transport> Clone for VirtioNICDriver<T> {
3813776c11Slogin     fn clone(&self) -> Self {
3913776c11Slogin         return VirtioNICDriver {
4013776c11Slogin             inner: self.inner.clone(),
4113776c11Slogin         };
4213776c11Slogin     }
4313776c11Slogin }
4413776c11Slogin 
45e2841179SLoGin /// 网卡驱动的包裹器,这是为了获取网卡驱动的可变引用而设计的。
46e2841179SLoGin ///
4713776c11Slogin /// 由于smoltcp的设计,导致需要在poll的时候获取网卡驱动的可变引用,
4813776c11Slogin /// 同时需要在token的consume里面获取可变引用。为了避免双重加锁,所以需要这个包裹器。
4913776c11Slogin struct VirtioNICDriverWrapper<T: Transport>(UnsafeCell<VirtioNICDriver<T>>);
5013776c11Slogin unsafe impl<T: Transport> Send for VirtioNICDriverWrapper<T> {}
5113776c11Slogin unsafe impl<T: Transport> Sync for VirtioNICDriverWrapper<T> {}
5213776c11Slogin 
5313776c11Slogin impl<T: Transport> Deref for VirtioNICDriverWrapper<T> {
5413776c11Slogin     type Target = VirtioNICDriver<T>;
5513776c11Slogin     fn deref(&self) -> &Self::Target {
5613776c11Slogin         unsafe { &*self.0.get() }
5713776c11Slogin     }
5813776c11Slogin }
5913776c11Slogin impl<T: Transport> DerefMut for VirtioNICDriverWrapper<T> {
6013776c11Slogin     fn deref_mut(&mut self) -> &mut Self::Target {
6113776c11Slogin         unsafe { &mut *self.0.get() }
6213776c11Slogin     }
6313776c11Slogin }
6413776c11Slogin 
65b5b571e0SLoGin #[allow(clippy::mut_from_ref)]
6613776c11Slogin impl<T: Transport> VirtioNICDriverWrapper<T> {
6713776c11Slogin     fn force_get_mut(&self) -> &mut VirtioNICDriver<T> {
6813776c11Slogin         unsafe { &mut *self.0.get() }
6913776c11Slogin     }
7013776c11Slogin }
7113776c11Slogin 
7213776c11Slogin impl<T: Transport> Debug for VirtioNICDriver<T> {
7313776c11Slogin     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
7413776c11Slogin         f.debug_struct("VirtioNICDriver").finish()
7513776c11Slogin     }
7613776c11Slogin }
7713776c11Slogin 
7813776c11Slogin pub struct VirtioInterface<T: Transport> {
7913776c11Slogin     driver: VirtioNICDriverWrapper<T>,
8013776c11Slogin     iface_id: usize,
81*881ff6f9Syuyi2439     iface: SpinLock<iface::Interface>,
8213776c11Slogin     name: String,
83e2841179SLoGin     dev_id: Arc<DeviceId>,
8413776c11Slogin }
8513776c11Slogin 
8613776c11Slogin impl<T: Transport> Debug for VirtioInterface<T> {
8713776c11Slogin     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
8813776c11Slogin         f.debug_struct("VirtioInterface")
8913776c11Slogin             .field("driver", self.driver.deref())
9013776c11Slogin             .field("iface_id", &self.iface_id)
9113776c11Slogin             .field("iface", &"smoltcp::iface::Interface")
9213776c11Slogin             .field("name", &self.name)
9313776c11Slogin             .finish()
9413776c11Slogin     }
9513776c11Slogin }
9613776c11Slogin 
9713776c11Slogin impl<T: Transport> VirtioInterface<T> {
98e2841179SLoGin     pub fn new(mut driver: VirtioNICDriver<T>, dev_id: Arc<DeviceId>) -> Arc<Self> {
9913776c11Slogin         let iface_id = generate_iface_id();
100*881ff6f9Syuyi2439         let mut iface_config = iface::Config::new(wire::HardwareAddress::Ethernet(
101*881ff6f9Syuyi2439             wire::EthernetAddress(driver.inner.lock().mac_address()),
10213776c11Slogin         ));
103*881ff6f9Syuyi2439         iface_config.random_seed = rand() as u64;
104*881ff6f9Syuyi2439 
105*881ff6f9Syuyi2439         let iface = iface::Interface::new(iface_config, &mut driver, Instant::now().into());
10613776c11Slogin 
10713776c11Slogin         let driver: VirtioNICDriverWrapper<T> = VirtioNICDriverWrapper(UnsafeCell::new(driver));
10813776c11Slogin         let result = Arc::new(VirtioInterface {
10913776c11Slogin             driver,
11013776c11Slogin             iface_id,
11113776c11Slogin             iface: SpinLock::new(iface),
11213776c11Slogin             name: format!("eth{}", iface_id),
113e2841179SLoGin             dev_id,
11413776c11Slogin         });
11513776c11Slogin 
11613776c11Slogin         return result;
11713776c11Slogin     }
11813776c11Slogin }
11913776c11Slogin 
120e2841179SLoGin impl<T: Transport + 'static> VirtIODevice for VirtioInterface<T> {
121e2841179SLoGin     fn handle_irq(&self, _irq: IrqNumber) -> Result<IrqReturn, SystemError> {
122e2841179SLoGin         poll_ifaces_try_lock_onetime().ok();
123e2841179SLoGin         return Ok(IrqReturn::Handled);
124e2841179SLoGin     }
125e2841179SLoGin 
126e2841179SLoGin     fn dev_id(&self) -> &Arc<DeviceId> {
127e2841179SLoGin         return &self.dev_id;
128e2841179SLoGin     }
129e2841179SLoGin }
130e2841179SLoGin 
131e2841179SLoGin impl<T: Transport> Drop for VirtioInterface<T> {
132e2841179SLoGin     fn drop(&mut self) {
133e2841179SLoGin         // 从全局的网卡接口信息表中删除这个网卡的接口信息
134e2841179SLoGin         NET_DRIVERS.write_irqsave().remove(&self.iface_id);
135e2841179SLoGin     }
136e2841179SLoGin }
137e2841179SLoGin 
13813776c11Slogin impl<T: 'static + Transport> VirtioNICDriver<T> {
13913776c11Slogin     pub fn new(driver_net: VirtIONet<HalImpl, T, 2>) -> Self {
140*881ff6f9Syuyi2439         let mut iface_config = iface::Config::new(wire::HardwareAddress::Ethernet(
141*881ff6f9Syuyi2439             wire::EthernetAddress(driver_net.mac_address()),
14213776c11Slogin         ));
14313776c11Slogin 
144*881ff6f9Syuyi2439         iface_config.random_seed = rand() as u64;
145*881ff6f9Syuyi2439 
14613776c11Slogin         let inner: Arc<SpinLock<VirtIONet<HalImpl, T, 2>>> = Arc::new(SpinLock::new(driver_net));
14713776c11Slogin         let result = VirtioNICDriver { inner };
14813776c11Slogin         return result;
14913776c11Slogin     }
15013776c11Slogin }
15113776c11Slogin 
15213776c11Slogin pub struct VirtioNetToken<T: Transport> {
15313776c11Slogin     driver: VirtioNICDriver<T>,
15413776c11Slogin     rx_buffer: Option<virtio_drivers::device::net::RxBuffer>,
15513776c11Slogin }
15613776c11Slogin 
157b5b571e0SLoGin impl<T: Transport> VirtioNetToken<T> {
15813776c11Slogin     pub fn new(
15913776c11Slogin         driver: VirtioNICDriver<T>,
16013776c11Slogin         rx_buffer: Option<virtio_drivers::device::net::RxBuffer>,
16113776c11Slogin     ) -> Self {
16213776c11Slogin         return Self { driver, rx_buffer };
16313776c11Slogin     }
16413776c11Slogin }
16513776c11Slogin 
16613776c11Slogin impl<T: Transport> phy::Device for VirtioNICDriver<T> {
16713776c11Slogin     type RxToken<'a> = VirtioNetToken<T> where Self: 'a;
16813776c11Slogin     type TxToken<'a> = VirtioNetToken<T> where Self: 'a;
16913776c11Slogin 
17013776c11Slogin     fn receive(
17113776c11Slogin         &mut self,
17213776c11Slogin         _timestamp: smoltcp::time::Instant,
17313776c11Slogin     ) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
17413776c11Slogin         match self.inner.lock().receive() {
17513776c11Slogin             Ok(buf) => Some((
17613776c11Slogin                 VirtioNetToken::new(self.clone(), Some(buf)),
17713776c11Slogin                 VirtioNetToken::new(self.clone(), None),
17813776c11Slogin             )),
17913776c11Slogin             Err(virtio_drivers::Error::NotReady) => None,
18013776c11Slogin             Err(err) => panic!("VirtIO receive failed: {}", err),
18113776c11Slogin         }
18213776c11Slogin     }
18313776c11Slogin 
18413776c11Slogin     fn transmit(&mut self, _timestamp: smoltcp::time::Instant) -> Option<Self::TxToken<'_>> {
18513776c11Slogin         // kdebug!("VirtioNet: transmit");
18640609970SGnoCiYeH         if self.inner.lock_irqsave().can_send() {
18713776c11Slogin             // kdebug!("VirtioNet: can send");
18813776c11Slogin             return Some(VirtioNetToken::new(self.clone(), None));
18913776c11Slogin         } else {
19013776c11Slogin             // kdebug!("VirtioNet: can not send");
19113776c11Slogin             return None;
19213776c11Slogin         }
19313776c11Slogin     }
19413776c11Slogin 
19513776c11Slogin     fn capabilities(&self) -> phy::DeviceCapabilities {
19613776c11Slogin         let mut caps = phy::DeviceCapabilities::default();
19713776c11Slogin         // 网卡的最大传输单元. 请与IP层的MTU进行区分。这个值应当是网卡的最大传输单元,而不是IP层的MTU。
19813776c11Slogin         caps.max_transmission_unit = 2000;
19913776c11Slogin         /*
20013776c11Slogin            Maximum burst size, in terms of MTU.
20113776c11Slogin            The network device is unable to send or receive bursts large than the value returned by this function.
20213776c11Slogin            If None, there is no fixed limit on burst size, e.g. if network buffers are dynamically allocated.
20313776c11Slogin         */
20413776c11Slogin         caps.max_burst_size = Some(1);
20513776c11Slogin         return caps;
20613776c11Slogin     }
20713776c11Slogin }
20813776c11Slogin 
20913776c11Slogin impl<T: Transport> phy::TxToken for VirtioNetToken<T> {
21013776c11Slogin     fn consume<R, F>(self, len: usize, f: F) -> R
21113776c11Slogin     where
21213776c11Slogin         F: FnOnce(&mut [u8]) -> R,
21313776c11Slogin     {
21413776c11Slogin         // // 为了线程安全,这里需要对VirtioNet进行加【写锁】,以保证对设备的互斥访问。
21513776c11Slogin 
21613776c11Slogin         let mut driver_net = self.driver.inner.lock();
21713776c11Slogin         let mut tx_buf = driver_net.new_tx_buffer(len);
21813776c11Slogin         let result = f(tx_buf.packet_mut());
21913776c11Slogin         driver_net.send(tx_buf).expect("virtio_net send failed");
22013776c11Slogin         return result;
22113776c11Slogin     }
22213776c11Slogin }
22313776c11Slogin 
22413776c11Slogin impl<T: Transport> phy::RxToken for VirtioNetToken<T> {
22513776c11Slogin     fn consume<R, F>(self, f: F) -> R
22613776c11Slogin     where
22713776c11Slogin         F: FnOnce(&mut [u8]) -> R,
22813776c11Slogin     {
22913776c11Slogin         // 为了线程安全,这里需要对VirtioNet进行加【写锁】,以保证对设备的互斥访问。
23013776c11Slogin         let mut rx_buf = self.rx_buffer.unwrap();
23113776c11Slogin         let result = f(rx_buf.packet_mut());
23213776c11Slogin         self.driver
23313776c11Slogin             .inner
23413776c11Slogin             .lock()
23513776c11Slogin             .recycle_rx_buffer(rx_buf)
23613776c11Slogin             .expect("virtio_net recv failed");
23713776c11Slogin         result
23813776c11Slogin     }
23913776c11Slogin }
24013776c11Slogin 
24113776c11Slogin /// @brief virtio-net 驱动的初始化与测试
242e2841179SLoGin pub fn virtio_net<T: Transport + 'static>(transport: T, dev_id: Arc<DeviceId>) {
24313776c11Slogin     let driver_net: VirtIONet<HalImpl, T, 2> =
24413776c11Slogin         match VirtIONet::<HalImpl, T, 2>::new(transport, 4096) {
24513776c11Slogin             Ok(net) => net,
24613776c11Slogin             Err(_) => {
24713776c11Slogin                 kerror!("VirtIONet init failed");
24813776c11Slogin                 return;
24913776c11Slogin             }
25013776c11Slogin         };
251*881ff6f9Syuyi2439     let mac = wire::EthernetAddress::from_bytes(&driver_net.mac_address());
25213776c11Slogin     let driver: VirtioNICDriver<T> = VirtioNICDriver::new(driver_net);
253e2841179SLoGin     let iface = VirtioInterface::new(driver, dev_id);
25406d5e247SLoGin     let name = iface.name.clone();
25513776c11Slogin     // 将网卡的接口信息注册到全局的网卡接口信息表中
2560d6cf65aSLoGin     NET_DRIVERS
2570d6cf65aSLoGin         .write_irqsave()
2580d6cf65aSLoGin         .insert(iface.nic_id(), iface.clone());
259e2841179SLoGin 
260e2841179SLoGin     virtio_irq_manager()
261e2841179SLoGin         .register_device(iface.clone())
262e2841179SLoGin         .expect("Register virtio net failed");
26313776c11Slogin     kinfo!(
26413776c11Slogin         "Virtio-net driver init successfully!\tNetDevID: [{}], MAC: [{}]",
26506d5e247SLoGin         name,
26613776c11Slogin         mac
26713776c11Slogin     );
26813776c11Slogin }
26913776c11Slogin 
27006d5e247SLoGin impl<T: Transport + 'static> Driver for VirtioInterface<T> {
271a03c4f9dSLoGin     fn id_table(&self) -> Option<IdTable> {
272b087521eSChiichen         todo!()
273b087521eSChiichen     }
274b087521eSChiichen 
275a03c4f9dSLoGin     fn add_device(&self, _device: Arc<dyn Device>) {
276b087521eSChiichen         todo!()
277b087521eSChiichen     }
278b087521eSChiichen 
279a03c4f9dSLoGin     fn delete_device(&self, _device: &Arc<dyn Device>) {
280a03c4f9dSLoGin         todo!()
281a03c4f9dSLoGin     }
282a03c4f9dSLoGin 
283a03c4f9dSLoGin     fn devices(&self) -> alloc::vec::Vec<Arc<dyn Device>> {
284a03c4f9dSLoGin         todo!()
285a03c4f9dSLoGin     }
286a03c4f9dSLoGin 
287c566df45SLoGin     fn bus(&self) -> Option<Weak<dyn Bus>> {
288a03c4f9dSLoGin         todo!()
289a03c4f9dSLoGin     }
290a03c4f9dSLoGin 
291c566df45SLoGin     fn set_bus(&self, _bus: Option<Weak<dyn Bus>>) {
292b087521eSChiichen         todo!()
293b087521eSChiichen     }
294b087521eSChiichen }
295b087521eSChiichen 
29606d5e247SLoGin impl<T: Transport + 'static> NetDriver for VirtioInterface<T> {
297*881ff6f9Syuyi2439     fn mac(&self) -> wire::EthernetAddress {
29813776c11Slogin         let mac: [u8; 6] = self.driver.inner.lock().mac_address();
299*881ff6f9Syuyi2439         return wire::EthernetAddress::from_bytes(&mac);
30013776c11Slogin     }
30113776c11Slogin 
30213776c11Slogin     #[inline]
30313776c11Slogin     fn nic_id(&self) -> usize {
30413776c11Slogin         return self.iface_id;
30513776c11Slogin     }
30613776c11Slogin 
30713776c11Slogin     #[inline]
30813776c11Slogin     fn name(&self) -> String {
30913776c11Slogin         return self.name.clone();
31013776c11Slogin     }
31113776c11Slogin 
31213776c11Slogin     fn update_ip_addrs(&self, ip_addrs: &[wire::IpCidr]) -> Result<(), SystemError> {
31313776c11Slogin         if ip_addrs.len() != 1 {
31413776c11Slogin             return Err(SystemError::EINVAL);
31513776c11Slogin         }
31613776c11Slogin 
31713776c11Slogin         self.iface.lock().update_ip_addrs(|addrs| {
31813776c11Slogin             let dest = addrs.iter_mut().next();
319b5b571e0SLoGin 
320b5b571e0SLoGin             if let Some(dest) = dest {
32113776c11Slogin                 *dest = ip_addrs[0];
322b5b571e0SLoGin             } else {
323*881ff6f9Syuyi2439                 addrs
324*881ff6f9Syuyi2439                     .push(ip_addrs[0])
325*881ff6f9Syuyi2439                     .expect("Push wire::IpCidr failed: full");
32613776c11Slogin             }
32713776c11Slogin         });
32813776c11Slogin         return Ok(());
32913776c11Slogin     }
33013776c11Slogin 
331*881ff6f9Syuyi2439     fn poll(&self, sockets: &mut iface::SocketSet) -> Result<(), SystemError> {
33213776c11Slogin         let timestamp: smoltcp::time::Instant = Instant::now().into();
33313776c11Slogin         let mut guard = self.iface.lock();
33413776c11Slogin         let poll_res = guard.poll(timestamp, self.driver.force_get_mut(), sockets);
33513776c11Slogin         // todo: notify!!!
336971462beSGnoCiYeH         // kdebug!("Virtio Interface poll:{poll_res}");
33713776c11Slogin         if poll_res {
33813776c11Slogin             return Ok(());
33913776c11Slogin         }
34079a452ceShoumkh         return Err(SystemError::EAGAIN_OR_EWOULDBLOCK);
34113776c11Slogin     }
34213776c11Slogin 
34313776c11Slogin     #[inline(always)]
344*881ff6f9Syuyi2439     fn inner_iface(&self) -> &SpinLock<iface::Interface> {
34513776c11Slogin         return &self.iface;
34613776c11Slogin     }
34713776c11Slogin     // fn as_any_ref(&'static self) -> &'static dyn core::any::Any {
34813776c11Slogin     //     return self;
34913776c11Slogin     // }
35013776c11Slogin }
35113776c11Slogin 
35206d5e247SLoGin impl<T: Transport + 'static> KObject for VirtioInterface<T> {
35306d5e247SLoGin     fn as_any_ref(&self) -> &dyn core::any::Any {
35406d5e247SLoGin         self
35506d5e247SLoGin     }
35606d5e247SLoGin 
35706d5e247SLoGin     fn set_inode(&self, _inode: Option<Arc<crate::filesystem::kernfs::KernFSInode>>) {
35806d5e247SLoGin         todo!()
35906d5e247SLoGin     }
36006d5e247SLoGin 
36106d5e247SLoGin     fn inode(&self) -> Option<Arc<crate::filesystem::kernfs::KernFSInode>> {
36206d5e247SLoGin         todo!()
36306d5e247SLoGin     }
36406d5e247SLoGin 
36506d5e247SLoGin     fn parent(&self) -> Option<alloc::sync::Weak<dyn KObject>> {
36606d5e247SLoGin         todo!()
36706d5e247SLoGin     }
36806d5e247SLoGin 
36906d5e247SLoGin     fn set_parent(&self, _parent: Option<alloc::sync::Weak<dyn KObject>>) {
37006d5e247SLoGin         todo!()
37106d5e247SLoGin     }
37206d5e247SLoGin 
37306d5e247SLoGin     fn kset(&self) -> Option<Arc<crate::driver::base::kset::KSet>> {
37406d5e247SLoGin         todo!()
37506d5e247SLoGin     }
37606d5e247SLoGin 
37706d5e247SLoGin     fn set_kset(&self, _kset: Option<Arc<crate::driver::base::kset::KSet>>) {
37806d5e247SLoGin         todo!()
37906d5e247SLoGin     }
38006d5e247SLoGin 
38106d5e247SLoGin     fn kobj_type(&self) -> Option<&'static dyn crate::driver::base::kobject::KObjType> {
38206d5e247SLoGin         todo!()
38306d5e247SLoGin     }
38406d5e247SLoGin 
38506d5e247SLoGin     fn name(&self) -> String {
38606d5e247SLoGin         self.name.clone()
38706d5e247SLoGin     }
38806d5e247SLoGin 
38906d5e247SLoGin     fn set_name(&self, _name: String) {
39006d5e247SLoGin         todo!()
39106d5e247SLoGin     }
39206d5e247SLoGin 
39306d5e247SLoGin     fn kobj_state(
39406d5e247SLoGin         &self,
39506d5e247SLoGin     ) -> crate::libs::rwlock::RwLockReadGuard<crate::driver::base::kobject::KObjectState> {
39606d5e247SLoGin         todo!()
39706d5e247SLoGin     }
39806d5e247SLoGin 
39906d5e247SLoGin     fn kobj_state_mut(
40006d5e247SLoGin         &self,
40106d5e247SLoGin     ) -> crate::libs::rwlock::RwLockWriteGuard<crate::driver::base::kobject::KObjectState> {
40206d5e247SLoGin         todo!()
40306d5e247SLoGin     }
40406d5e247SLoGin 
405a03c4f9dSLoGin     fn set_kobj_state(&self, _state: KObjectState) {
406a03c4f9dSLoGin         todo!()
407a03c4f9dSLoGin     }
408a03c4f9dSLoGin 
409a03c4f9dSLoGin     fn set_kobj_type(&self, _ktype: Option<&'static dyn KObjType>) {
41006d5e247SLoGin         todo!()
41106d5e247SLoGin     }
41206d5e247SLoGin }
41306d5e247SLoGin 
41413776c11Slogin // 向编译器保证,VirtioNICDriver在线程之间是安全的.
41513776c11Slogin // 由于smoltcp只会在token内真正操作网卡设备,并且在VirtioNetToken的consume
41613776c11Slogin // 方法内,会对VirtioNet进行加【写锁】,因此,能够保证对设备操作的的互斥访问,
41713776c11Slogin // 因此VirtioNICDriver在线程之间是安全的。
41813776c11Slogin // unsafe impl<T: Transport> Sync for VirtioNICDriver<T> {}
41913776c11Slogin // unsafe impl<T: Transport> Send for VirtioNICDriver<T> {}
420