1#![expect(missing_docs)]
36#![forbid(unsafe_code)]
37
38pub mod loopback;
39pub mod null;
40pub mod resolve;
41pub mod tests;
42
43use async_trait::async_trait;
44use futures::FutureExt;
45use futures::StreamExt;
46use futures::TryFutureExt;
47use futures::lock::Mutex;
48use futures_concurrency::future::Race;
49use guestmem::GuestMemory;
50use guestmem::GuestMemoryError;
51use inspect::InspectMut;
52use inspect_counters::Counter;
53use mesh::rpc::Rpc;
54use mesh::rpc::RpcSend;
55use null::NullEndpoint;
56use pal_async::driver::Driver;
57use std::future::pending;
58use std::sync::Arc;
59use std::task::Context;
60use std::task::Poll;
61use thiserror::Error;
62
63pub use net_backend_core::*;
64
65pub struct QueueConfig {
70 pub driver: Box<dyn Driver>,
71}
72
73#[async_trait]
84pub trait Endpoint: Send + Sync + InspectMut {
85 fn endpoint_type(&self) -> &'static str;
87
88 async fn get_queues(
90 &mut self,
91 config: Vec<QueueConfig>,
92 rss: Option<&RssConfig<'_>>,
93 queues: &mut Vec<Box<dyn Queue>>,
94 ) -> anyhow::Result<()>;
95
96 async fn stop(&mut self);
100
101 fn is_ordered(&self) -> bool;
105
106 fn tx_offload_support(&self) -> TxOffloadSupport {
108 TxOffloadSupport::default()
109 }
110
111 fn multiqueue_support(&self) -> MultiQueueSupport {
113 MultiQueueSupport {
114 max_queues: 1,
115 indirection_table_size: 0,
116 }
117 }
118
119 fn tx_fast_completions(&self) -> bool {
123 false
124 }
125
126 async fn set_data_path_to_guest_vf(&self, _use_vf: bool) -> anyhow::Result<()> {
129 Err(anyhow::Error::msg("Unsupported in current endpoint"))
130 }
131
132 async fn get_data_path_to_guest_vf(&self) -> anyhow::Result<bool> {
133 Err(anyhow::Error::msg("Unsupported in current endpoint"))
134 }
135
136 async fn wait_for_endpoint_action(&mut self) -> EndpointAction {
138 pending().await
139 }
140
141 fn link_speed(&self) -> u64 {
143 10 * 1000 * 1000 * 1000
146 }
147}
148
149#[derive(Error, Debug)]
150pub enum TxError {
151 #[error("error requiring queue restart. {0}")]
152 TryRestart(#[source] anyhow::Error),
153 #[error("unrecoverable error. {0}")]
154 Fatal(#[source] anyhow::Error),
155}
156pub trait BackendQueueStats {
157 fn rx_errors(&self) -> Counter;
158 fn tx_errors(&self) -> Counter;
159 fn rx_packets(&self) -> Counter;
160 fn tx_packets(&self) -> Counter;
161 fn tx_vlan_packets(&self) -> Counter {
162 Counter::new()
163 }
164 fn rx_vlan_packets(&self) -> Counter {
165 Counter::new()
166 }
167}
168
169#[async_trait]
186pub trait Queue: Send + InspectMut {
187 async fn update_target_vp(&mut self, target_vp: u32) {
189 let _ = target_vp;
190 }
191
192 fn poll_ready(&mut self, cx: &mut Context<'_>, pool: &mut dyn BufferAccess) -> Poll<()>;
194
195 fn rx_avail(&mut self, pool: &mut dyn BufferAccess, done: &[RxId]);
197
198 fn rx_poll(
200 &mut self,
201 pool: &mut dyn BufferAccess,
202 packets: &mut [RxId],
203 ) -> anyhow::Result<usize>;
204
205 fn tx_avail(
209 &mut self,
210 pool: &mut dyn BufferAccess,
211 segments: &[TxSegment],
212 ) -> anyhow::Result<(bool, usize)>;
213
214 fn tx_poll(&mut self, pool: &mut dyn BufferAccess, done: &mut [TxId])
216 -> Result<usize, TxError>;
217
218 fn queue_stats(&self) -> Option<&dyn BackendQueueStats> {
220 None }
222}
223
224pub trait BufferAccess {
235 fn guest_memory(&self) -> &GuestMemory;
237
238 fn write_data(&mut self, id: RxId, data: &[u8]);
240
241 fn push_guest_addresses(&self, id: RxId, buf: &mut Vec<RxBufferSegment>);
246
247 fn capacity(&self, id: RxId) -> u32;
249
250 fn write_header(&mut self, id: RxId, metadata: &RxMetadata);
252
253 fn write_packet(&mut self, id: RxId, metadata: &RxMetadata, data: &[u8]) {
255 self.write_data(id, data);
256 self.write_header(id, metadata);
257 }
258
259 fn write_packet_segments(&mut self, id: RxId, metadata: &RxMetadata, segments: &[&[u8]]) {
272 if let [segment] = segments {
273 self.write_packet(id, metadata, segment);
274 return;
275 }
276 let total = segments.iter().map(|s| s.len()).sum();
277 let mut data = Vec::with_capacity(total);
278 for segment in segments {
279 data.extend_from_slice(segment);
280 }
281 self.write_packet(id, metadata, &data);
282 }
283}
284
285pub fn linearize(
288 pool: &dyn BufferAccess,
289 segments: &mut &[TxSegment],
290) -> Result<Vec<u8>, GuestMemoryError> {
291 let (head, this, rest) = next_packet(segments);
292 let mut v = vec![0; head.len as usize];
293 let mut offset = 0;
294 let mem = pool.guest_memory();
295 for segment in this {
296 let dest = &mut v[offset..offset + segment.len as usize];
297 mem.read_at(segment.gpa, dest)?;
298 offset += segment.len as usize;
299 }
300 assert_eq!(v.len(), offset);
301 *segments = rest;
302 Ok(v)
303}
304
305enum DisconnectableEndpointUpdate {
306 EndpointConnected(Box<dyn Endpoint>),
307 EndpointDisconnected(Rpc<(), Option<Box<dyn Endpoint>>>),
308}
309
310pub struct DisconnectableEndpointControl {
311 send_update: mesh::Sender<DisconnectableEndpointUpdate>,
312 is_ordered: Option<bool>,
313}
314
315impl DisconnectableEndpointControl {
316 pub fn connect(&mut self, endpoint: Box<dyn Endpoint>) -> anyhow::Result<()> {
317 let new_is_ordered = endpoint.is_ordered();
318 if let Some(is_ordered) = self.is_ordered {
319 anyhow::ensure!(
320 !is_ordered || new_is_ordered,
321 "network endpoint cannot be reattached as unordered after being ordered"
322 );
323 } else {
324 self.is_ordered = Some(new_is_ordered);
325 }
326 self.send_update
327 .send(DisconnectableEndpointUpdate::EndpointConnected(endpoint));
328 Ok(())
329 }
330
331 pub async fn disconnect(&mut self) -> anyhow::Result<Option<Box<dyn Endpoint>>> {
332 self.send_update
333 .call(DisconnectableEndpointUpdate::EndpointDisconnected, ())
334 .map_err(anyhow::Error::from)
335 .await
336 }
337}
338
339pub struct DisconnectableEndpointCachedState {
340 is_ordered: bool,
341 tx_offload_support: TxOffloadSupport,
342 multiqueue_support: MultiQueueSupport,
343 tx_fast_completions: bool,
344 link_speed: u64,
345}
346
347pub struct DisconnectableEndpoint {
348 endpoint: Option<Box<dyn Endpoint>>,
349 null_endpoint: Box<dyn Endpoint>,
350 cached_state: Option<DisconnectableEndpointCachedState>,
351 receive_update: Arc<Mutex<mesh::Receiver<DisconnectableEndpointUpdate>>>,
352 notify_disconnect_complete: Option<(
353 Rpc<(), Option<Box<dyn Endpoint>>>,
354 Option<Box<dyn Endpoint>>,
355 )>,
356}
357
358impl InspectMut for DisconnectableEndpoint {
359 fn inspect_mut(&mut self, req: inspect::Request<'_>) {
360 self.current_mut().inspect_mut(req)
361 }
362}
363
364impl DisconnectableEndpoint {
365 pub fn new() -> (Self, DisconnectableEndpointControl) {
366 let (endpoint_tx, endpoint_rx) = mesh::channel();
367 let control = DisconnectableEndpointControl {
368 send_update: endpoint_tx,
369 is_ordered: None,
370 };
371 (
372 Self {
373 endpoint: None,
374 null_endpoint: Box::new(NullEndpoint::new()),
375 cached_state: None,
376 receive_update: Arc::new(Mutex::new(endpoint_rx)),
377 notify_disconnect_complete: None,
378 },
379 control,
380 )
381 }
382
383 fn current(&self) -> &dyn Endpoint {
384 self.endpoint
385 .as_ref()
386 .unwrap_or(&self.null_endpoint)
387 .as_ref()
388 }
389
390 fn current_mut(&mut self) -> &mut dyn Endpoint {
391 self.endpoint
392 .as_mut()
393 .unwrap_or(&mut self.null_endpoint)
394 .as_mut()
395 }
396}
397
398#[async_trait]
399impl Endpoint for DisconnectableEndpoint {
400 fn endpoint_type(&self) -> &'static str {
401 self.current().endpoint_type()
402 }
403
404 async fn get_queues(
405 &mut self,
406 config: Vec<QueueConfig>,
407 rss: Option<&RssConfig<'_>>,
408 queues: &mut Vec<Box<dyn Queue>>,
409 ) -> anyhow::Result<()> {
410 self.current_mut().get_queues(config, rss, queues).await
411 }
412
413 async fn stop(&mut self) {
414 self.current_mut().stop().await
415 }
416
417 fn is_ordered(&self) -> bool {
418 self.cached_state
419 .as_ref()
420 .expect("Endpoint needs connected at least once before use")
421 .is_ordered
422 }
423
424 fn tx_offload_support(&self) -> TxOffloadSupport {
425 self.cached_state
426 .as_ref()
427 .expect("Endpoint needs connected at least once before use")
428 .tx_offload_support
429 }
430
431 fn multiqueue_support(&self) -> MultiQueueSupport {
432 self.cached_state
433 .as_ref()
434 .expect("Endpoint needs connected at least once before use")
435 .multiqueue_support
436 }
437
438 fn tx_fast_completions(&self) -> bool {
439 self.cached_state
440 .as_ref()
441 .expect("Endpoint needs connected at least once before use")
442 .tx_fast_completions
443 }
444
445 async fn set_data_path_to_guest_vf(&self, use_vf: bool) -> anyhow::Result<()> {
446 self.current().set_data_path_to_guest_vf(use_vf).await
447 }
448
449 async fn get_data_path_to_guest_vf(&self) -> anyhow::Result<bool> {
450 self.current().get_data_path_to_guest_vf().await
451 }
452
453 async fn wait_for_endpoint_action(&mut self) -> EndpointAction {
454 if let Some((rpc, old_endpoint)) = self.notify_disconnect_complete.take() {
457 rpc.handle(async |_| old_endpoint).await;
458 }
459
460 enum Message {
461 DisconnectableEndpointUpdate(DisconnectableEndpointUpdate),
462 UpdateFromEndpoint(EndpointAction),
463 }
464 let receiver = self.receive_update.clone();
465 let mut receive_update = receiver.lock().await;
466 let update = async {
467 match receive_update.next().await {
468 Some(m) => Message::DisconnectableEndpointUpdate(m),
469 None => {
470 pending::<()>().await;
471 unreachable!()
472 }
473 }
474 };
475 let ep_update = self
476 .current_mut()
477 .wait_for_endpoint_action()
478 .map(Message::UpdateFromEndpoint);
479 let m = (update, ep_update).race().await;
480 match m {
481 Message::DisconnectableEndpointUpdate(
482 DisconnectableEndpointUpdate::EndpointConnected(endpoint),
483 ) => {
484 let old_endpoint = self.endpoint.take();
485 assert!(old_endpoint.is_none());
486 self.endpoint = Some(endpoint);
487 let new_is_ordered = self.current().is_ordered();
488 let is_ordered = if let Some(prev) = &self.cached_state {
489 assert!(
490 !prev.is_ordered || new_is_ordered,
491 "network endpoint reattached as unordered after being ordered"
492 );
493 prev.is_ordered
494 } else {
495 new_is_ordered
496 };
497 self.cached_state = Some(DisconnectableEndpointCachedState {
498 is_ordered,
499 tx_offload_support: self.current().tx_offload_support(),
500 multiqueue_support: self.current().multiqueue_support(),
501 tx_fast_completions: self.current().tx_fast_completions(),
502 link_speed: self.current().link_speed(),
503 });
504 EndpointAction::RestartRequired
505 }
506 Message::DisconnectableEndpointUpdate(
507 DisconnectableEndpointUpdate::EndpointDisconnected(rpc),
508 ) => {
509 let old_endpoint = self.endpoint.take();
510 self.notify_disconnect_complete = Some((rpc, old_endpoint));
515 EndpointAction::RestartRequired
516 }
517 Message::UpdateFromEndpoint(update) => update,
518 }
519 }
520
521 fn link_speed(&self) -> u64 {
522 self.cached_state
523 .as_ref()
524 .expect("Endpoint needs connected at least once before use")
525 .link_speed
526 }
527}
528
529#[cfg(test)]
530mod disconnectable_endpoint_tests {
531 use super::*;
532 use test_with_tracing::test;
533
534 #[derive(InspectMut)]
535 struct TestEndpoint {
536 is_ordered: bool,
537 }
538
539 #[async_trait]
540 impl Endpoint for TestEndpoint {
541 fn endpoint_type(&self) -> &'static str {
542 "test"
543 }
544
545 async fn get_queues(
546 &mut self,
547 _config: Vec<QueueConfig>,
548 _rss: Option<&RssConfig<'_>>,
549 _queues: &mut Vec<Box<dyn Queue>>,
550 ) -> anyhow::Result<()> {
551 unreachable!()
552 }
553
554 async fn stop(&mut self) {
555 unreachable!()
556 }
557
558 fn is_ordered(&self) -> bool {
559 self.is_ordered
560 }
561 }
562
563 #[test]
564 fn connect_pins_endpoint_ordering() {
565 let (_endpoint, mut control) = DisconnectableEndpoint::new();
566 control
567 .connect(Box::new(TestEndpoint { is_ordered: true }))
568 .unwrap();
569
570 let err = control
571 .connect(Box::new(TestEndpoint { is_ordered: false }))
572 .unwrap_err();
573 assert_eq!(
574 err.to_string(),
575 "network endpoint cannot be reattached as unordered after being ordered"
576 );
577
578 let (_endpoint, mut control) = DisconnectableEndpoint::new();
579 control
580 .connect(Box::new(TestEndpoint { is_ordered: false }))
581 .unwrap();
582 control
583 .connect(Box::new(TestEndpoint { is_ordered: true }))
584 .unwrap();
585 }
586}