140dc3e7cSSebastien Boeuf // Copyright (c) 2021 Intel Corporation. All rights reserved. 240dc3e7cSSebastien Boeuf // 340dc3e7cSSebastien Boeuf // SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause 440dc3e7cSSebastien Boeuf 54becb11aSSebastien Boeuf use std::sync::Arc; 688a9f799SRob Bradford 7ea6d5a04SPhilipp Schuster use thiserror::Error; 81d55de9cSdependabot[bot] use virtio_bindings::virtio_net::{ 940dc3e7cSSebastien Boeuf VIRTIO_NET_CTRL_GUEST_OFFLOADS, VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET, VIRTIO_NET_CTRL_MQ, 1040dc3e7cSSebastien Boeuf VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX, VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN, 11*8338fa64SHengqi Chen VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET, VIRTIO_NET_ERR, VIRTIO_NET_OK, 1240dc3e7cSSebastien Boeuf }; 1387f57f7cSSebastien Boeuf use virtio_queue::{Queue, QueueT}; 14a423bf13SSebastien Boeuf use vm_memory::{ByteValued, Bytes, GuestMemoryError}; 1577df4e67SSebastien Boeuf use vm_virtio::{AccessPlatform, Translatable}; 1640dc3e7cSSebastien Boeuf 17*8338fa64SHengqi Chen use super::virtio_features_to_tap_offload; 1861e57e1cSRuoqing He use crate::{GuestMemoryMmap, Tap}; 1988a9f799SRob Bradford 20ea6d5a04SPhilipp Schuster #[derive(Error, Debug)] 2140dc3e7cSSebastien Boeuf pub enum Error { 2240dc3e7cSSebastien Boeuf /// Read queue failed. 23ea6d5a04SPhilipp Schuster #[error("Read queue failed")] 24ea6d5a04SPhilipp Schuster GuestMemory(#[source] GuestMemoryError), 250249e864SSebastien Boeuf /// No control header descriptor 26ea6d5a04SPhilipp Schuster #[error("No control header descriptor")] 270249e864SSebastien Boeuf NoControlHeaderDescriptor, 28f151a860SSebastien Boeuf /// Missing the data descriptor in the chain. 29ea6d5a04SPhilipp Schuster #[error("Missing the data descriptor in the chain")] 30f151a860SSebastien Boeuf NoDataDescriptor, 3140dc3e7cSSebastien Boeuf /// No status descriptor 32ea6d5a04SPhilipp Schuster #[error("No status descriptor")] 3340dc3e7cSSebastien Boeuf NoStatusDescriptor, 340249e864SSebastien Boeuf /// Failed adding used index 35ea6d5a04SPhilipp Schuster #[error("Failed adding used index")] 36ea6d5a04SPhilipp Schuster QueueAddUsed(#[source] virtio_queue::Error), 370249e864SSebastien Boeuf /// Failed creating an iterator over the queue 38ea6d5a04SPhilipp Schuster #[error("Failed creating an iterator over the queue")] 39ea6d5a04SPhilipp Schuster QueueIterator(#[source] virtio_queue::Error), 400249e864SSebastien Boeuf /// Failed enabling notification for the queue 41ea6d5a04SPhilipp Schuster #[error("Failed enabling notification for the queue")] 42ea6d5a04SPhilipp Schuster QueueEnableNotification(#[source] virtio_queue::Error), 4340dc3e7cSSebastien Boeuf } 4440dc3e7cSSebastien Boeuf 4540dc3e7cSSebastien Boeuf type Result<T> = std::result::Result<T, Error>; 4640dc3e7cSSebastien Boeuf 4740dc3e7cSSebastien Boeuf #[repr(C, packed)] 4840dc3e7cSSebastien Boeuf #[derive(Debug, Clone, Copy, Default)] 4940dc3e7cSSebastien Boeuf pub struct ControlHeader { 5040dc3e7cSSebastien Boeuf pub class: u8, 5140dc3e7cSSebastien Boeuf pub cmd: u8, 5240dc3e7cSSebastien Boeuf } 5340dc3e7cSSebastien Boeuf 548ee253cdSWei Liu // SAFETY: ControlHeader only contains a series of integers 5540dc3e7cSSebastien Boeuf unsafe impl ByteValued for ControlHeader {} 5640dc3e7cSSebastien Boeuf 5740dc3e7cSSebastien Boeuf pub struct CtrlQueue { 5840dc3e7cSSebastien Boeuf pub taps: Vec<Tap>, 5940dc3e7cSSebastien Boeuf } 6040dc3e7cSSebastien Boeuf 6140dc3e7cSSebastien Boeuf impl CtrlQueue { new(taps: Vec<Tap>) -> Self6240dc3e7cSSebastien Boeuf pub fn new(taps: Vec<Tap>) -> Self { 6340dc3e7cSSebastien Boeuf CtrlQueue { taps } 6440dc3e7cSSebastien Boeuf } 6540dc3e7cSSebastien Boeuf process( &mut self, mem: &GuestMemoryMmap, queue: &mut Queue, access_platform: Option<&Arc<dyn AccessPlatform>>, ) -> Result<()>660249e864SSebastien Boeuf pub fn process( 670249e864SSebastien Boeuf &mut self, 68a423bf13SSebastien Boeuf mem: &GuestMemoryMmap, 69a423bf13SSebastien Boeuf queue: &mut Queue, 704becb11aSSebastien Boeuf access_platform: Option<&Arc<dyn AccessPlatform>>, 71b9aeaf66SRob Bradford ) -> Result<()> { 7287f57f7cSSebastien Boeuf while let Some(mut desc_chain) = queue.pop_descriptor_chain(mem) { 730249e864SSebastien Boeuf let ctrl_desc = desc_chain.next().ok_or(Error::NoControlHeaderDescriptor)?; 740249e864SSebastien Boeuf 750249e864SSebastien Boeuf let ctrl_hdr: ControlHeader = desc_chain 760249e864SSebastien Boeuf .memory() 7777df4e67SSebastien Boeuf .read_obj( 7877df4e67SSebastien Boeuf ctrl_desc 7977df4e67SSebastien Boeuf .addr() 80059e787cSSebastien Boeuf .translate_gva(access_platform, ctrl_desc.len() as usize), 8177df4e67SSebastien Boeuf ) 820249e864SSebastien Boeuf .map_err(Error::GuestMemory)?; 83f151a860SSebastien Boeuf let data_desc = desc_chain.next().ok_or(Error::NoDataDescriptor)?; 844becb11aSSebastien Boeuf 8577df4e67SSebastien Boeuf let data_desc_addr = data_desc 8677df4e67SSebastien Boeuf .addr() 87059e787cSSebastien Boeuf .translate_gva(access_platform, data_desc.len() as usize); 884becb11aSSebastien Boeuf 890249e864SSebastien Boeuf let status_desc = desc_chain.next().ok_or(Error::NoStatusDescriptor)?; 9040dc3e7cSSebastien Boeuf 9140dc3e7cSSebastien Boeuf let ok = match u32::from(ctrl_hdr.class) { 9240dc3e7cSSebastien Boeuf VIRTIO_NET_CTRL_MQ => { 930249e864SSebastien Boeuf let queue_pairs = desc_chain 940249e864SSebastien Boeuf .memory() 954becb11aSSebastien Boeuf .read_obj::<u16>(data_desc_addr) 9640dc3e7cSSebastien Boeuf .map_err(Error::GuestMemory)?; 9740dc3e7cSSebastien Boeuf if u32::from(ctrl_hdr.cmd) != VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET { 9840dc3e7cSSebastien Boeuf warn!("Unsupported command: {}", ctrl_hdr.cmd); 9940dc3e7cSSebastien Boeuf false 10040dc3e7cSSebastien Boeuf } else if (queue_pairs < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN as u16) 10140dc3e7cSSebastien Boeuf || (queue_pairs > VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX as u16) 10240dc3e7cSSebastien Boeuf { 10340dc3e7cSSebastien Boeuf warn!("Number of MQ pairs out of range: {}", queue_pairs); 10440dc3e7cSSebastien Boeuf false 10540dc3e7cSSebastien Boeuf } else { 10640dc3e7cSSebastien Boeuf info!("Number of MQ pairs requested: {}", queue_pairs); 10740dc3e7cSSebastien Boeuf true 10840dc3e7cSSebastien Boeuf } 10940dc3e7cSSebastien Boeuf } 11040dc3e7cSSebastien Boeuf VIRTIO_NET_CTRL_GUEST_OFFLOADS => { 1110249e864SSebastien Boeuf let features = desc_chain 1120249e864SSebastien Boeuf .memory() 1134becb11aSSebastien Boeuf .read_obj::<u64>(data_desc_addr) 11440dc3e7cSSebastien Boeuf .map_err(Error::GuestMemory)?; 11540dc3e7cSSebastien Boeuf if u32::from(ctrl_hdr.cmd) != VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET { 11640dc3e7cSSebastien Boeuf warn!("Unsupported command: {}", ctrl_hdr.cmd); 11740dc3e7cSSebastien Boeuf false 11840dc3e7cSSebastien Boeuf } else { 11940dc3e7cSSebastien Boeuf let mut ok = true; 12040dc3e7cSSebastien Boeuf for tap in self.taps.iter_mut() { 12140dc3e7cSSebastien Boeuf info!("Reprogramming tap offload with features: {}", features); 12240dc3e7cSSebastien Boeuf tap.set_offload(virtio_features_to_tap_offload(features)) 12340dc3e7cSSebastien Boeuf .map_err(|e| { 12440dc3e7cSSebastien Boeuf error!("Error programming tap offload: {:?}", e); 12540dc3e7cSSebastien Boeuf ok = false 12640dc3e7cSSebastien Boeuf }) 12740dc3e7cSSebastien Boeuf .ok(); 12840dc3e7cSSebastien Boeuf } 12940dc3e7cSSebastien Boeuf ok 13040dc3e7cSSebastien Boeuf } 13140dc3e7cSSebastien Boeuf } 13240dc3e7cSSebastien Boeuf _ => { 13340dc3e7cSSebastien Boeuf warn!("Unsupported command {:?}", ctrl_hdr); 13440dc3e7cSSebastien Boeuf false 13540dc3e7cSSebastien Boeuf } 13640dc3e7cSSebastien Boeuf }; 13740dc3e7cSSebastien Boeuf 1380249e864SSebastien Boeuf desc_chain 1390249e864SSebastien Boeuf .memory() 1400249e864SSebastien Boeuf .write_obj( 14140dc3e7cSSebastien Boeuf if ok { VIRTIO_NET_OK } else { VIRTIO_NET_ERR } as u8, 14277df4e67SSebastien Boeuf status_desc 14377df4e67SSebastien Boeuf .addr() 144059e787cSSebastien Boeuf .translate_gva(access_platform, status_desc.len() as usize), 14540dc3e7cSSebastien Boeuf ) 14640dc3e7cSSebastien Boeuf .map_err(Error::GuestMemory)?; 1470249e864SSebastien Boeuf let len = ctrl_desc.len() + data_desc.len() + status_desc.len(); 148a4859ffeSSebastien Boeuf 149a4859ffeSSebastien Boeuf queue 150a4859ffeSSebastien Boeuf .add_used(desc_chain.memory(), desc_chain.head_index(), len) 151a4859ffeSSebastien Boeuf .map_err(Error::QueueAddUsed)?; 1521fc3fef6SRob Bradford 1531fc3fef6SRob Bradford if !queue 154a423bf13SSebastien Boeuf .enable_notification(mem) 1551fc3fef6SRob Bradford .map_err(Error::QueueEnableNotification)? 1561fc3fef6SRob Bradford { 1571fc3fef6SRob Bradford break; 1581fc3fef6SRob Bradford } 15940dc3e7cSSebastien Boeuf } 16040dc3e7cSSebastien Boeuf 161b9aeaf66SRob Bradford Ok(()) 16240dc3e7cSSebastien Boeuf } 16340dc3e7cSSebastien Boeuf } 164