1use crate::BufferAccess;
7use crate::Endpoint;
8use crate::MultiQueueSupport;
9use crate::Queue;
10use crate::QueueConfig;
11use crate::RssConfig;
12use crate::RxId;
13use crate::TxError;
14use crate::TxId;
15use crate::TxOffloadSupport;
16use crate::TxSegment;
17use crate::resolve::ResolveEndpointParams;
18use crate::resolve::ResolvedEndpoint;
19use async_trait::async_trait;
20use inspect::InspectMut;
21use net_backend_resources::null::NullHandle;
22use std::convert::Infallible;
23use std::task::Context;
24use std::task::Poll;
25use vm_resource::ResolveResource;
26use vm_resource::declare_static_resolver;
27use vm_resource::kind::NetEndpointHandleKind;
28
29pub struct NullResolver;
30
31declare_static_resolver! {
32 NullResolver,
33 (NetEndpointHandleKind, NullHandle),
34}
35
36impl ResolveResource<NetEndpointHandleKind, NullHandle> for NullResolver {
37 type Output = ResolvedEndpoint;
38 type Error = Infallible;
39
40 fn resolve(
41 &self,
42 _resource: NullHandle,
43 _input: ResolveEndpointParams,
44 ) -> Result<Self::Output, Self::Error> {
45 Ok(NullEndpoint::new().into())
46 }
47}
48
49#[non_exhaustive]
51#[derive(InspectMut)]
52pub struct NullEndpoint {}
53
54impl NullEndpoint {
55 pub fn new() -> Self {
56 Self {}
57 }
58}
59
60#[async_trait]
61impl Endpoint for NullEndpoint {
62 fn endpoint_type(&self) -> &'static str {
63 "null"
64 }
65
66 async fn get_queues(
67 &mut self,
68 config: Vec<QueueConfig>,
69 _rss: Option<&RssConfig<'_>>,
70 queues: &mut Vec<Box<dyn Queue>>,
71 ) -> anyhow::Result<()> {
72 queues.extend(config.iter().map(|_| Box::new(NullQueue) as _));
73 Ok(())
74 }
75
76 async fn stop(&mut self) {}
77
78 fn is_ordered(&self) -> bool {
79 true
80 }
81
82 fn tx_offload_support(&self) -> TxOffloadSupport {
83 TxOffloadSupport {
84 ipv4_header: true,
85 tcp: true,
86 udp: true,
87 tso: true,
88 uso: true,
89 }
90 }
91
92 fn multiqueue_support(&self) -> MultiQueueSupport {
93 MultiQueueSupport {
94 max_queues: u16::MAX,
95 indirection_table_size: 128,
96 }
97 }
98
99 async fn set_data_path_to_guest_vf(&self, use_vf: bool) -> anyhow::Result<()> {
100 anyhow::ensure!(!use_vf, "Null endpoint cannot switch to a guest VF");
101 Ok(())
102 }
103}
104
105#[derive(InspectMut)]
107struct NullQueue;
108
109impl Queue for NullQueue {
110 fn poll_ready(&mut self, _cx: &mut Context<'_>, _pool: &mut dyn BufferAccess) -> Poll<()> {
111 Poll::Pending
112 }
113
114 fn rx_avail(&mut self, _pool: &mut dyn BufferAccess, _done: &[RxId]) {}
115
116 fn rx_poll(
117 &mut self,
118 _pool: &mut dyn BufferAccess,
119 _packets: &mut [RxId],
120 ) -> anyhow::Result<usize> {
121 Ok(0)
122 }
123
124 fn tx_avail(
125 &mut self,
126 _pool: &mut dyn BufferAccess,
127 packets: &[TxSegment],
128 ) -> anyhow::Result<(bool, usize)> {
129 Ok((true, packets.len()))
130 }
131
132 fn tx_poll(
133 &mut self,
134 _pool: &mut dyn BufferAccess,
135 _done: &mut [TxId],
136 ) -> Result<usize, TxError> {
137 Ok(0)
138 }
139}