diff options
Diffstat (limited to 'meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0')
9 files changed, 0 insertions, 1536 deletions
diff --git a/meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/CHANGELOG.md b/meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/CHANGELOG.md deleted file mode 100644 index 51d3f040..00000000 --- a/meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/CHANGELOG.md +++ /dev/null @@ -1,15 +0,0 @@ -# Changelog -## [Unreleased] - -### Added - -### Changed - -### Fixed - -### Deprecated - -## [0.1.0] - -First release - diff --git a/meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/Cargo.toml b/meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/Cargo.toml deleted file mode 100644 index 08d012c2..00000000 --- a/meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/Cargo.toml +++ /dev/null @@ -1,35 +0,0 @@ -[package] -name = "vhost-device-can" -version = "0.0.1" -authors = ["Timos Ampelikiotis <t.ampelikiotis@virtualopensystems.com>"] -description = "vhost can backend device" -repository = "https://github.com/rust-vmm/vhost-device" -readme = "README.md" -keywords = ["can", "vhost", "virt", "backend"] -license = "Apache-2.0 OR BSD-3-Clause" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[features] -xen = ["vm-memory/xen", "vhost/xen", "vhost-user-backend/xen"] - -[dependencies] -queues = "1.0.2" -socketcan = "3.2" -clap = { version = "4.2.5", features = ["derive"] } -env_logger = "0.10" -libc = "0.2" -log = "0.4" -thiserror = "1.0" -vhost = { version = "0.8", features = ["vhost-user-slave"] } -vhost-user-backend = "0.10" -virtio-bindings = "0.2.1" -virtio-queue = "0.9" -vm-memory = "0.12" -vmm-sys-util = "0.11" - -[dev-dependencies] -assert_matches = "1.5" -virtio-queue = { version = "0.9", features = ["test-utils"] } -vm-memory = { version = "0.12", features = ["backend-mmap", "backend-atomic"] } diff --git a/meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/LICENSE-APACHE b/meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/LICENSE-APACHE deleted file mode 100644 index d6456956..00000000 --- a/meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/LICENSE-APACHE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/LICENSE-BSD-3-Clause b/meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/LICENSE-BSD-3-Clause deleted file mode 100644 index dd975d98..00000000 --- a/meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/LICENSE-BSD-3-Clause +++ /dev/null @@ -1,26 +0,0 @@ -Copyright 2022 The rust-vmm authors. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this -list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, -this list of conditions and the following disclaimer in the documentation -and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its contributors -may be used to endorse or promote products derived from this software without -specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/README.md b/meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/README.md deleted file mode 100644 index fd50c274..00000000 --- a/meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/README.md +++ /dev/null @@ -1,66 +0,0 @@ -# vhost-device-can - CAN emulation backend daemon - -## Description -This program is a vhost-user backend that emulates a VirtIO CAN device. -The device's binary takes three (3) parameters: a socket, a 'can-out' and a -'can-in' device name. The socket is commonly used across all vhost-devices to -communicate with the vhost-user frontend device. - -The 'can-out' represents -the actual CAN/FD device appears in the host system which vhost-device-can will -forward the messages from the frontend side. Finaly, the 'can-in' is again a -CAN/FD device connected on the host systems and vhost-device-can reads CAN/FD -frames and sends them to the frontend. The 'can-in' and 'can-out' can be find -by "ip link show" command. Also, the vhost-device-can may have the same CAN/FD -device name for both 'can-in' and 'can-out', if the user desires to setup a -loopback configuration. - - -This program is tested with Virtio-loopback's `-device vhost-user-can`. -Examples section below. - -## Synopsis - -**vhost-device-can** [*OPTIONS*] - -## Options - -.. program:: vhost-device-gpio - -.. option:: -h, --help - - Print help. - -.. option:: -s, --socket-path=PATH - -.. option:: -i, --can-int='CAN/FD interface name' - - The name of the input CAN interface to retrive CAN frames by - -.. option:: -o, --can-out='CAN/FD interface name' - - The name of the ouput CAN interface to send the CAN frames - -## Examples - -The daemon should be started first: - -:: - - host# vhost-device-can --socket-path=can.sock --can-in="can0" --can-out="can1" - -The virtio-looback invocation needs to insert the [virtio-loopback-transport](https://git.virtualopensystems.com/virtio-loopback/loopback_driver/-/tree/epsilon-release) driver -and then start the [virito-loopback-adapter](https://git.virtualopensystems.com/virtio-loopback/adapter_app/-/tree/epsilon-release) which is the intermediate between -vhost-device and virtio-loopback-transport driver. - -:: - - host# sudo insmod loopback_driver.ko - host# sudo ./adapter -s /path/to/can.sock0 -d vhucan - -## License - -This project is licensed under either of - -- [Apache License](http://www.apache.org/licenses/LICENSE-2.0), Version 2.0 -- [BSD-3-Clause License](https://opensource.org/licenses/BSD-3-Clause) diff --git a/meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/src/backend.rs b/meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/src/backend.rs deleted file mode 100644 index 177c76cc..00000000 --- a/meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/src/backend.rs +++ /dev/null @@ -1,170 +0,0 @@ -// VIRTIO CAN Emulation via vhost-user -// -// Copyright 2023 VIRTUAL OPEN SYSTEMS SAS. All Rights Reserved. -// Timos Ampelikiotis <t.ampelikiotis@virtualopensystems.com> -// -// SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause - -use log::{error, info, warn}; -use std::process::exit; -use std::sync::{Arc, RwLock}; -use std::thread::{spawn, JoinHandle}; - -use clap::Parser; -use thiserror::Error as ThisError; -use vhost::{vhost_user, vhost_user::Listener}; -use vhost_user_backend::VhostUserDaemon; -use vm_memory::{GuestMemoryAtomic, GuestMemoryMmap}; - -use crate::can::{CanController}; -use crate::vhu_can::VhostUserCanBackend; - -pub(crate) type Result<T> = std::result::Result<T, Error>; - -#[derive(Debug, ThisError)] -/// Errors related to low level CAN helpers -pub(crate) enum Error { - #[error("Invalid socket count: {0}")] - SocketCountInvalid(usize), - #[error("Failed to join threads")] - FailedJoiningThreads, - #[error("Could not create can controller: {0}")] - CouldNotCreateCanController(crate::can::Error), - #[error("Could not create can backend: {0}")] - CouldNotCreateBackend(crate::vhu_can::Error), - #[error("Could not create daemon: {0}")] - CouldNotCreateDaemon(vhost_user_backend::Error), -} - -#[derive(Parser, Debug)] -#[clap(author, version, about, long_about = None)] -struct CanArgs { - /// Location of vhost-user Unix domain socket. This is suffixed by 0,1,2..socket_count-1. - #[clap(short, long)] - socket_path: String, - - /// A can device name to be used for reading (ex. vcan, can0, can1, ... etc.) - #[clap(short = 'i', long)] - can_in: String, - - /// A can device name to be used for writing (ex. vcan, can0, can1, ... etc.) - #[clap(short = 'o', long)] - can_out: String, - - /// Number of guests (sockets) to connect to. - #[clap(short = 'c', long, default_value_t = 1)] - socket_count: u32, -} - -#[derive(PartialEq, Debug)] -struct CanConfiguration { - socket_path: String, - socket_count: u32, - can_in: String, - can_out: String, -} - -impl TryFrom<CanArgs> for CanConfiguration { - type Error = Error; - - fn try_from(args: CanArgs) -> Result<Self> { - - if args.socket_count == 0 { - return Err(Error::SocketCountInvalid(0)); - } - - let can_in = args.can_in.trim().to_string(); - let can_out = args.can_out.trim().to_string(); - - Ok(CanConfiguration { - socket_path: args.socket_path, - socket_count: args.socket_count, - can_in, - can_out, - }) - } -} - -fn start_backend(args: CanArgs) -> Result<()> { - - println!("start_backend function!\n"); - - let config = CanConfiguration::try_from(args).unwrap(); - let mut handles = Vec::new(); - - for _ in 0..config.socket_count { - let socket = config.socket_path.to_owned(); - let can_in = config.can_in.to_owned(); - let can_out = config.can_out.to_owned(); - - let handle: JoinHandle<Result<()>> = spawn(move || loop { - // A separate thread is spawned for each socket and can connect to a separate guest. - // These are run in an infinite loop to not require the daemon to be restarted once a - // guest exits. - // - // There isn't much value in complicating code here to return an error from the - // threads, and so the code uses unwrap() instead. The panic on a thread won't cause - // trouble to other threads/guests or the main() function and should be safe for the - // daemon. - - let controller = - CanController::new(can_in.clone(), can_out.clone()).map_err(Error::CouldNotCreateCanController)?; - let shared_controller_1 = Arc::new(RwLock::new(controller)); - let shared_controller_2 = shared_controller_1.clone(); - let vu_can_backend = Arc::new(RwLock::new( - VhostUserCanBackend::new(shared_controller_1).map_err(Error::CouldNotCreateBackend)?, - )); - let _read_hanlde = CanController::start_read_thread(shared_controller_2); - - let mut daemon = VhostUserDaemon::new( - String::from("vhost-device-can-backend"), - vu_can_backend.clone(), - GuestMemoryAtomic::new(GuestMemoryMmap::new()), - ) - .map_err(Error::CouldNotCreateDaemon)?; - - /* Start the read thread -- need to handle it after termination */ - let vring_workers = daemon.get_epoll_handlers(); - vu_can_backend.read() - .unwrap() - .set_vring_worker(&vring_workers[0]); - - let listener = Listener::new(socket.clone(), true).unwrap(); - daemon.start(listener).unwrap(); - - match daemon.wait() { - Ok(()) => { - info!("Stopping cleanly."); - } - Err(vhost_user_backend::Error::HandleRequest( - vhost_user::Error::PartialMessage | vhost_user::Error::Disconnected, - )) => { - info!("vhost-user connection closed with partial message. If the VM is shutting down, this is expected behavior; otherwise, it might be a bug."); - } - Err(e) => { - warn!("Error running daemon: {:?}", e); - } - } - - // No matter the result, we need to shut down the worker thread. - vu_can_backend.read().unwrap().exit_event.write(1).unwrap(); - }); - - handles.push(handle); - } - - for handle in handles { - handle.join().map_err(|_| Error::FailedJoiningThreads)??; - } - - Ok(()) -} - -pub(crate) fn can_init() { - env_logger::init(); - println!("Can_init function!"); - if let Err(e) = start_backend(CanArgs::parse()) { - error!("{e}"); - exit(1); - } -} diff --git a/meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/src/can.rs b/meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/src/can.rs deleted file mode 100644 index 228266f6..00000000 --- a/meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/src/can.rs +++ /dev/null @@ -1,264 +0,0 @@ -// CAN backend device -// -// Copyright 2023 VIRTUAL OPEN SYSTEMS SAS. All Rights Reserved. -// Timos Ampelikiotis <t.ampelikiotis@virtualopensystems.com> -// -// SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause - -use log::{warn, error}; -use std::sync::{Arc, RwLock}; - -use thiserror::Error as ThisError; -use vm_memory::{ByteValued, Le16}; - -extern crate socketcan; -use socketcan::{ - CanFdSocket, CanFdFrame, CanAnyFrame, EmbeddedFrame, Socket, - Frame, StandardId, -}; - -use std::thread::{JoinHandle, spawn}; -use vmm_sys_util::eventfd::{EFD_NONBLOCK, EventFd}; - -extern crate queues; -use queues::*; - -use crate::vhu_can::{VirtioCanFrame, VIRTIO_CAN_STATUS_OK}; - -type Result<T> = std::result::Result<T, Error>; - -#[derive(Copy, Clone, Debug, PartialEq, ThisError)] -/// Errors related to low level gpio helpers -pub(crate) enum Error { - //#[error("Can not enabled yet")] - //CanNotEnabled, - #[error("Can open socket operation failed")] - CanSocketFailed, - #[error("Can write socket operation failed")] - CanSocketWriteFailed, - #[error("Can read socket operation failed")] - CanSocketReadFailed, - #[error("Pop can element operation failed")] - CanPopFailed, - #[error("Creating Eventfd for CAN events failed")] - CanEventFdFailed, - #[error("CanQueueFailed")] - CanQueueFailed, -} - -/* CAN flags to determine type of CAN Id */ -pub(crate) const VIRTIO_CAN_FLAGS_EXTENDED: u32 = 0x8000; -pub(crate) const VIRTIO_CAN_FLAGS_FD: u32 = 0x4000; -pub(crate) const VIRTIO_CAN_FLAGS_RTR: u32 = 0x2000; - -pub(crate) const VIRTIO_CAN_TX: u16 = 0x0001; -pub(crate) const VIRTIO_CAN_RX: u16 = 0x0101; - -pub(crate) const CAN_EFF_FLAG: u32 = 0x80000000; /* EFF/SFF is set in the MSB */ -pub(crate) const CAN_RTR_FLAG: u32 = 0x40000000; /* remote transmission request */ -pub(crate) const CAN_ERR_FLAG: u32 = 0x20000000; /* error message frame */ - -pub(crate) const CAN_SFF_MASK: u32 = 0x000007FF; /* standard frame format (SFF) */ -pub(crate) const CAN_EFF_MASK: u32 = 0x1FFFFFFF; /* extended frame format (EFF) */ - -//pub(crate) const CAN_FRMF_BRS: u32 = 0x01; /* bit rate switch (2nd bitrate for data) */ -//pub(crate) const CAN_FRMF_ESI: u32 = 0x02; /* error state ind. of transmitting node */ -pub(crate) const CAN_FRMF_TYPE_FD: u32 = 0x10; /* internal bit ind. of CAN FD frame */ -pub(crate) const CAN_ERR_BUSOFF: u32 = 0x00000040; /* bus off */ - -/// Virtio Can Configuration -#[derive(Copy, Clone, Debug, Default, PartialEq)] -#[repr(C)] -pub(crate) struct VirtioCanConfig { - /* CAN controller status */ - pub(crate) status: Le16, -} - -// SAFETY: The layout of the structure is fixed and can be initialized by -// reading its content from byte array. -unsafe impl ByteValued for VirtioCanConfig {} - -#[derive(Debug)] -pub(crate) struct CanController { - config: VirtioCanConfig, - pub can_in_name: String, - pub can_out_name: String, - can_out_socket: CanFdSocket, - pub rx_event_fd: EventFd, - rx_fifo: Queue<VirtioCanFrame>, -} - -impl CanController { - // Creates a new controller corresponding to `device`. - pub(crate) fn new(can_in_name: String, can_out_name: String) -> Result<CanController> { - - let can_in_name = can_in_name.to_owned(); - println!("can_in_name: {:?}", can_in_name); - - let can_out_name = can_out_name.to_owned(); - println!("can_out_name: {:?}", can_out_name); - - let can_out_socket = Self::open_can_sockets(can_out_name.clone()); - - let rx_fifo = Queue::new(); - - let rx_efd = EventFd::new(EFD_NONBLOCK).map_err(|_| Error::CanEventFdFailed)?; - - Ok(CanController { - config: VirtioCanConfig { - status: 0x0.into(), - }, - can_in_name, - can_out_name, - can_out_socket, - rx_event_fd: rx_efd, - rx_fifo - }) - } - - pub fn print_can_frame (canframe: VirtioCanFrame) { - println!("canframe.msg_type 0x{:x}", canframe.msg_type.to_native()); - println!("canframe.can_id 0x{:x}", canframe.can_id.to_native()); - println!("canframe.length {}", canframe.length.to_native()); - println!("canframe.flags 0x{:x}", canframe.flags.to_native()); - if canframe.length.to_native() == 0 { - println!("[]"); - return; - } - print!("["); - let last_elem = canframe.length.to_native() as usize - 1; - for (index, sdu) in canframe.sdu.iter().enumerate() { - print!("0x{:x}, ", sdu); - if index == last_elem { - print!("0x{:x}", sdu); - break; - } - } - println!("]"); - } - - /* FIXME: This thread is not handle after termination */ - pub fn start_read_thread (controller: Arc<RwLock<CanController>>) -> JoinHandle<Result<()>> { - spawn(move || { - CanController::read_can_socket(controller) - } - ) - } - - pub fn push(&mut self, rx_elem: VirtioCanFrame) -> Result<()> { - match self.rx_fifo.add(rx_elem) { - Ok(_) => Ok(()), // Successfully added, so return Ok(()) - _ => Err(Error::CanQueueFailed), // Handle other errors - } - } - - pub fn pop(&mut self) -> Result<VirtioCanFrame> { - match self.rx_fifo.remove() { - Ok(item) => Ok(item), - _ => Err(Error::CanPopFailed), - } - } - - fn open_can_sockets (can_out_name: String) -> CanFdSocket { - let can_out_socket = match CanFdSocket::open(&can_out_name) { - Ok(socket) => socket, - Err(_) => { - warn!("Error opening CAN socket"); - panic!("Failed to open CAN socket."); - //return Err(Error::CanSocketFailed); - } - }; - - can_out_socket - } - - pub fn read_can_socket (controller: Arc<RwLock<CanController>>) -> Result<()> { - let can_in_name = &controller.read().unwrap().can_in_name.clone(); - dbg!("Start reading from {} socket!", &can_in_name); - let socket = match CanFdSocket::open(&can_in_name) { - Ok(socket) => socket, - Err(_) => { - warn!("Error opening CAN socket"); - return Err(Error::CanSocketFailed); - } - }; - - // Receive CAN messages - loop { - if let Ok(frame) = socket.read_frame() { - - let mut controller = controller.write().unwrap(); - match frame { - CanAnyFrame::Normal(frame) => { - // Regular CAN frame - println!("Received CAN message: {:?}", frame); - } - CanAnyFrame::Fd(frame) => { - // CAN FD frame - println!("Received CAN FD message: {:?}", frame); - - let read_can_frame = VirtioCanFrame { - msg_type: VIRTIO_CAN_RX.into(), - can_id: frame.raw_id().into(), - length: (frame.data().len() as u16).into(), - reserved: 0.into(), - flags: frame.id_flags().bits().into(), - sdu: { - let mut sdu_data: [u8; 64] = [0; 64]; - for i in 0..frame.data().len() { - sdu_data[i] = frame.data()[i]; - } - sdu_data - }, - }; - - match controller.push(read_can_frame) { - Ok(_) => warn!("New Can frame was received"), - Err(_) => { - warn!("Error read/push CAN frame"); - return Err(Error::CanSocketReadFailed); - } - } - } - CanAnyFrame::Remote(frame) => { - // Remote CAN frame - println!("Received Remote CAN message: {:?}", frame); - } - CanAnyFrame::Error(frame) => { - // Error frame - println!("Received Error frame: {:?}", frame); - } - } - - controller.rx_event_fd.write(1).unwrap(); - } - } - } - - pub(crate) fn config(&self) -> &VirtioCanConfig { - log::trace!("Get config\n"); - &self.config - } - - pub(crate) fn operation(&self, tx_request: VirtioCanFrame) -> Result<u8> { - log::trace!("Can operation\n"); - - // Create a CAN frame with a specific CAN-ID and the data buffer - let can_id = StandardId::new(tx_request.can_id.to_native().try_into().unwrap()).unwrap(); - let data_len = tx_request.length.to_native() as usize; - - let data: Vec<u8> = tx_request.sdu.iter().cloned().take(data_len).collect(); - let frame = CanFdFrame::new(can_id, &data).unwrap(); - - // Send the CAN frame - let write_result = self.can_out_socket.write_frame(&frame); - match write_result { - Ok(_) => Ok(VIRTIO_CAN_STATUS_OK), - Err(_) => { - warn!("Error write CAN socket"); - Err(Error::CanSocketWriteFailed) - } - } - } -} - diff --git a/meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/src/main.rs b/meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/src/main.rs deleted file mode 100644 index e89934ea..00000000 --- a/meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/src/main.rs +++ /dev/null @@ -1,26 +0,0 @@ -// VIRTIO CAN Emulation via vhost-user -// -// Copyright 2023 VIRTUAL OPEN SYSTEMS SAS. All Rights Reserved. -// Timos Ampelikiotis <t.ampelikiotis@virtualopensystems.com> -// -// SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause - -#[cfg(target_env = "gnu")] -mod backend; -#[cfg(target_env = "gnu")] -mod can; -#[cfg(target_env = "gnu")] -mod vhu_can; - -#[cfg(target_env = "gnu")] -fn main() { - println!("Hello to main vhost-user-can"); - backend::can_init() -} - -// Rust vmm container (https://github.com/rust-vmm/rust-vmm-container) doesn't -// have tools to do a musl build at the moment, and adding that support is -// tricky as well to the container. Skip musl builds until the time pre-built -// libgpiod library is available for musl. -#[cfg(target_env = "musl")] -fn main() {} diff --git a/meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/src/vhu_can.rs b/meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/src/vhu_can.rs deleted file mode 100644 index 6aa12488..00000000 --- a/meta-egvirt/recipes-extended/vhost-device-can/vhost-device-can-0.1.0/src/vhu_can.rs +++ /dev/null @@ -1,732 +0,0 @@ -// vhost device can -// -// Copyright 2023 VIRTUAL OPEN SYSTEMS SAS. All Rights Reserved. -// Timos Ampelikiotis <t.ampelikiotis@virtualopensystems.com> -// -// SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause - -use log::{warn, error}; -use std::mem::size_of; -use std::slice::from_raw_parts; -use std::sync::{Arc, RwLock}; -use std::{ - convert, - io::{self, Result as IoResult}, -}; -use std::os::fd::AsRawFd; -use thiserror::Error as ThisError; -use vhost::vhost_user::message::{VhostUserProtocolFeatures, VhostUserVirtioFeatures}; -use vhost_user_backend::{VhostUserBackendMut, VringRwLock, VringT}; -use virtio_bindings::bindings::virtio_config::{VIRTIO_F_NOTIFY_ON_EMPTY, VIRTIO_F_VERSION_1}; -use virtio_bindings::bindings::virtio_ring::{ - VIRTIO_RING_F_EVENT_IDX, VIRTIO_RING_F_INDIRECT_DESC, -}; -use virtio_queue::{DescriptorChain, QueueOwnedT}; -use vm_memory::{ - ByteValued, Bytes, GuestAddressSpace, GuestMemoryAtomic, GuestMemoryLoadGuard, - GuestMemoryMmap, Le16, Le32, -}; -use vmm_sys_util::epoll::EventSet; -use vmm_sys_util::eventfd::{EventFd, EFD_NONBLOCK}; -use crate::can::{ - CanController, CAN_EFF_FLAG, CAN_RTR_FLAG, CAN_ERR_FLAG, CAN_SFF_MASK, - CAN_EFF_MASK, VIRTIO_CAN_FLAGS_FD, VIRTIO_CAN_FLAGS_RTR, - VIRTIO_CAN_FLAGS_EXTENDED, VIRTIO_CAN_TX, VIRTIO_CAN_RX, - CAN_FRMF_TYPE_FD, CAN_ERR_BUSOFF, -}; -use vhost_user_backend::VringEpollHandler; - -/// Feature bit numbers -pub const VIRTIO_CAN_F_CAN_CLASSIC: u16 = 0; -pub const VIRTIO_CAN_F_CAN_FD: u16 = 1; -//pub const VIRTIO_CAN_F_LATE_TX_ACK: u16 = 2; -pub const VIRTIO_CAN_F_RTR_FRAMES: u16 = 3; - -/// Possible values of the status field -pub const VIRTIO_CAN_STATUS_OK: u8 = 0x0; -pub const VIRTIO_CAN_STATUS_ERR: u8 = 0x1; - -/// CAN Control messages -const VIRTIO_CAN_SET_CTRL_MODE_START: u16 = 0x0201; -const VIRTIO_CAN_SET_CTRL_MODE_STOP: u16 = 0x0202; - -/// Virtio configuration -const QUEUE_SIZE: usize = 64; -const NUM_QUEUES: usize = 3; - -/// Queues -const TX_QUEUE: u16 = 0; -const RX_QUEUE: u16 = 1; -const CTRL_QUEUE: u16 = 2; -const BACKEND_EFD: u16 = 4; - -type Result<T> = std::result::Result<T, Error>; - -#[derive(Copy, Clone, Debug, PartialEq, ThisError)] -/// Errors related to vhost-device-gpio-daemon. -pub(crate) enum Error { - #[error("Failed to handle event, didn't match EPOLLIN")] - HandleEventNotEpollIn, - #[error("Failed to handle unknown event")] - HandleEventUnknown, - #[error("Received unexpected write only descriptor at index {0}")] - UnexpectedWriteOnlyDescriptor(usize), - #[error("Received unexpected readable descriptor at index {0}")] - UnexpectedReadableDescriptor(usize), - #[error("Invalid descriptor count {0}")] - UnexpectedDescriptorCount(usize), - #[error("Invalid descriptor size, expected: {0}, found: {1}")] - UnexpectedDescriptorSize(usize, u32), - #[error("Descriptor not found")] - DescriptorNotFound, - #[error("Descriptor read failed")] - DescriptorReadFailed, - #[error("Descriptor write failed")] - DescriptorWriteFailed, - #[error("Failed to send notification")] - NotificationFailed, - #[error("Failed to create new EventFd")] - EventFdFailed, - #[error("Unknown can message type: {0}")] - UnexpectedCanMsgType(u16), - #[error("RTR frames not negotiated")] - UnexpectedRtrFlag, - #[error("Can FD frames not negotiated")] - UnexpectedFdFlag, - #[error("Classic CAN frames not negotiated")] - UnexpectedClassicFlag, -} - -impl convert::From<Error> for io::Error { - fn from(e: Error) -> Self { - io::Error::new(io::ErrorKind::Other, e) - } -} - -/// Virtio CAN Request / Response messages -/// -/// The response message is a stream of bytes, where first byte represents the -/// status, and rest is message specific data. - -#[derive(Copy, Clone, Default)] -#[repr(C)] -struct VirtioCanTxResponse { - result: i8, -} -// SAFETY: The layout of the structure is fixed and can be initialized by -// reading its content from byte array. -unsafe impl ByteValued for VirtioCanTxResponse {} - -#[derive(Copy, Clone, Debug)] -#[repr(C)] -pub struct VirtioCanFrame { - pub msg_type: Le16, - pub length: Le16, /* 0..8 CC, 0..64 CANFD, 0..2048 CANXL, 12 bits */ - pub reserved: Le32, /* May be needed in part for CAN XL priority */ - pub flags: Le32, - pub can_id: Le32, - pub sdu: [u8; 64], -} - -impl Default for VirtioCanFrame { - fn default() -> Self { - VirtioCanFrame { - msg_type: Le16::default(), - length: Le16::default(), - reserved: Le32::default(), - flags: Le32::default(), - can_id: Le32::default(), - sdu: [0; 64], // Initialize "asd" with default value (0 in this case) - } - } -} - -// SAFETY: The layout of the structure is fixed and can be initialized by -// reading its content from byte array. -unsafe impl ByteValued for VirtioCanFrame {} - -#[derive(Copy, Clone, Default)] -#[repr(C)] -struct VirtioCanCtrlRequest { - msg_type: Le16, -} -// SAFETY: The layout of the structure is fixed and can be initialized by -// reading its content from byte array. -unsafe impl ByteValued for VirtioCanCtrlRequest {} - -#[derive(Copy, Clone, Default)] -#[repr(C)] -struct VirtioCanCtrlResponse { - result: i8, -} -// SAFETY: The layout of the structure is fixed and can be initialized by -// reading its content from byte array. -unsafe impl ByteValued for VirtioCanCtrlResponse {} - -pub(crate) struct VhostUserCanBackend { - controller: Arc<RwLock<CanController>>, - acked_features: u64, - event_idx: bool, - pub(crate) exit_event: EventFd, - mem: Option<GuestMemoryAtomic<GuestMemoryMmap>>, -} - -type CanDescriptorChain = DescriptorChain<GuestMemoryLoadGuard<GuestMemoryMmap<()>>>; - -impl VhostUserCanBackend { - pub(crate) fn new(controller: Arc<RwLock<CanController>>) -> Result<Self> { - Ok(VhostUserCanBackend { - controller: controller, - event_idx: false, - acked_features: 0x0, - exit_event: EventFd::new(EFD_NONBLOCK).map_err(|_| Error::EventFdFailed)?, - mem: None, - }) - } - - fn check_features (&self, features: u16) -> bool { - (self.acked_features & (1 << features)) != 0 - } - - fn process_ctrl_requests( - &self, - requests: Vec<CanDescriptorChain>, - vring: &VringRwLock - ) -> Result<bool> { - dbg!("process_ctrl_requests"); - - if requests.is_empty() { - return Ok(true); - } - - for desc_chain in requests { - let descriptors: Vec<_> = desc_chain.clone().collect(); - - if descriptors.len() < 1 { - warn!("Error::UnexpectedDescriptorCount"); - return Err(Error::UnexpectedDescriptorCount(descriptors.len())); - } - - println!("descriptors.len(): {:?}", descriptors.len()); - - let desc_request = descriptors[0]; - if desc_request.is_write_only() { - warn!("Error::UnexpectedWriteOnlyDescriptor"); - return Err(Error::UnexpectedWriteOnlyDescriptor(0)); - } - - if desc_request.len() as usize != size_of::<VirtioCanCtrlRequest>() { - println!("UnexpectedDescriptorSize, len = {:?}", desc_request.len()); - return Err(Error::UnexpectedDescriptorSize( - size_of::<VirtioCanCtrlRequest>(), - desc_request.len(), - )); - } - - let request = desc_chain - .memory() - .read_obj::<VirtioCanCtrlRequest>(desc_request.addr()) - .map_err(|_| Error::DescriptorReadFailed)?; - - - match request.msg_type.into() { - VIRTIO_CAN_SET_CTRL_MODE_START => { - println!("VIRTIO_CAN_SET_CTRL_MODE_START"); - //vcan->busoff = false; - Ok(()) - } - VIRTIO_CAN_SET_CTRL_MODE_STOP => { - println!("VIRTIO_CAN_SET_CTRL_MODE_STOP"); - //vcan->busoff = false; - Ok(()) - } - _ => { - println!("Ctrl queue: msg type 0x{:?} unknown", request.msg_type); - return Err(Error::HandleEventUnknown.into()) - }, - }?; - - let desc_response = descriptors[1]; - if !desc_response.is_write_only() { - println!("This is not wirtable"); - return Err(Error::UnexpectedReadableDescriptor(1)); - } - - let response = VIRTIO_CAN_STATUS_OK; - - desc_chain - .memory() - .write_slice(response.as_slice(), desc_response.addr()) - .map_err(|_| Error::DescriptorWriteFailed)?; - - if vring.add_used(desc_chain.head_index(), desc_response.len()).is_err() { - println!("Couldn't return used descriptors to the ring"); - warn!("Couldn't return used descriptors to the ring"); - } - } - - Ok(true) - } - - fn process_tx_requests( - &self, - requests: Vec<CanDescriptorChain>, - vring: &VringRwLock - ) -> Result<bool> { - dbg!("process_tx_requests"); - - if requests.is_empty() { - return Ok(true); - } - - println!("requests.len: {:?}", requests.len()); - for desc_chain in requests { - let descriptors: Vec<_> = desc_chain.clone().collect(); - - if descriptors.len() != 2 { - println!("Error::UnexpectedDescriptorCount"); - return Err(Error::UnexpectedDescriptorCount(descriptors.len())); - } - - let desc_request = descriptors[0]; - if desc_request.is_write_only() { - println!("Error::UnexpectedReadOnlyDescriptor"); - return Err(Error::UnexpectedWriteOnlyDescriptor(0)); - } - - if desc_request.len() as usize != size_of::<VirtioCanFrame>() { - println!("Tx UnexpectedDescriptorSize, len = {:?}", desc_request.len()); - //return Err(Error::UnexpectedDescriptorSize( - // size_of::<VirtioCanFrame>(), - // desc_request.len(), - //)); - } - - let request = desc_chain - .memory() - .read_obj::<VirtioCanFrame>(desc_request.addr()) - .map_err(|_| Error::DescriptorReadFailed)?; - - CanController::print_can_frame(request); - - let msg_type = request.msg_type.to_native(); - let mut can_id = request.can_id.to_native(); - let mut flags = request.flags.to_native(); - let mut length = request.length.to_native(); - - if msg_type != VIRTIO_CAN_TX { - warn!("TX: Message type 0x{:x} unknown\n", msg_type); - return Err(Error::UnexpectedCanMsgType(msg_type)); - } - - if (flags & VIRTIO_CAN_FLAGS_FD) != 0 { - if length > 64 { - println!("Cut sdu_len from {:?} to 64\n", request.length); - length = 64; - } - } else { - if length > 8 { - println!("Cut sdu_len from {:?} to 8\n", request.length); - length = 8; - } - } - - /* - * Copy Virtio frame structure to qemu frame structure and - * check while doing this whether the frame type was negotiated - */ - if (flags & VIRTIO_CAN_FLAGS_EXTENDED) != 0 { - flags &= CAN_EFF_MASK; - flags |= CAN_EFF_FLAG; - } else { - flags &= CAN_SFF_MASK; - } - - if (flags & VIRTIO_CAN_FLAGS_RTR) != 0 { - if !self.check_features(VIRTIO_CAN_F_CAN_CLASSIC) || - !self.check_features(VIRTIO_CAN_F_RTR_FRAMES) { - warn!("TX: RTR frames not negotiated"); - return Err(Error::UnexpectedRtrFlag); - } - can_id |= flags | CAN_RTR_FLAG; - } - - if (flags & VIRTIO_CAN_FLAGS_FD) != 0 { - if !self.check_features(VIRTIO_CAN_F_CAN_FD) { - warn!("TX: FD frames not negotiated\n"); - return Err(Error::UnexpectedFdFlag); - } - flags |= CAN_FRMF_TYPE_FD; - } else { - if !self.check_features(VIRTIO_CAN_F_CAN_CLASSIC) { - warn!("TX: Classic frames not negotiated\n"); - return Err(Error::UnexpectedClassicFlag); - } - flags = 0; - } - - let mut corrected_request = VirtioCanFrame::default(); - corrected_request.msg_type = msg_type.into(); - corrected_request.can_id = can_id.into(); - corrected_request.flags = flags.into(); - corrected_request.length = length.into(); - corrected_request.sdu.copy_from_slice(&request.sdu[0..64]); - - let desc_response = descriptors[1]; - if !desc_response.is_write_only() { - println!("Error::UnexpectedWriteOnlyDescriptor"); - return Err(Error::UnexpectedReadableDescriptor(1)); - } - - let response = match self.controller.write().unwrap().operation(corrected_request) { - Ok(result) => { - result - } - Err(_) => { - warn!("We got an error from controller send func"); - VIRTIO_CAN_STATUS_ERR - } - }; - - desc_chain - .memory() - .write_slice(response.as_slice(), desc_response.addr()) - .map_err(|_| Error::DescriptorWriteFailed)?; - - if vring.add_used(desc_chain.head_index(), desc_response.len()).is_err() { - println!("Couldn't return used descriptors to the ring"); - warn!("Couldn't return used descriptors to the ring"); - } - } - - Ok(true) - } - - fn process_rx_requests( - &mut self, - requests: Vec<CanDescriptorChain>, - vring: &VringRwLock - ) -> Result<bool> { - dbg!("process_rx_requests"); - - if requests.is_empty() { - return Ok(true); - } - - let desc_chain = &requests[0]; - let descriptors: Vec<_> = desc_chain.clone().collect(); - - if descriptors.len() != 1 { - println!("Error::UnexpectedDescriptorCount"); - return Err(Error::UnexpectedDescriptorCount(descriptors.len())); - } - - let desc_response = descriptors[0]; - if !desc_response.is_write_only() { - return Err(Error::UnexpectedReadableDescriptor(1)); - } - - let mut response = match self.controller.write().unwrap().pop() { - Ok(item) => item, - Err(_) => return Err(Error::HandleEventUnknown), - }; - - CanController::print_can_frame(response); - - if (response.can_id.to_native() & CAN_ERR_FLAG) != 0 { - if (response.can_id.to_native() & CAN_ERR_BUSOFF) != 0 { - warn!("Got BusOff error frame, device does a local bus off\n"); - //vcan->busoff = true; - } else { - println!("Dropping error frame 0x{:x}\n", response.can_id.to_native()); - } - return Ok(true); - } - - let mut can_rx = VirtioCanFrame::default(); - can_rx.msg_type = VIRTIO_CAN_RX.into(); - can_rx.can_id = response.can_id; - can_rx.length = response.length; - can_rx.flags = (can_rx.flags.to_native() | VIRTIO_CAN_FLAGS_FD).into(); - - if (response.flags.to_native() & CAN_FRMF_TYPE_FD) != 0 { - if !self.check_features(VIRTIO_CAN_F_CAN_FD) { - warn!("Drop non-supported CAN FD frame"); - return Err(Error::UnexpectedFdFlag); - } - } else { - if !self.check_features(VIRTIO_CAN_F_CAN_CLASSIC) { - warn!("Drop non-supported CAN classic frame"); - return Err(Error::UnexpectedClassicFlag); - } - } - if (response.can_id.to_native() & CAN_RTR_FLAG) != 0 && - !self.check_features(VIRTIO_CAN_F_RTR_FRAMES) { - warn!("Drop non-supported RTR frame"); - return Err(Error::UnexpectedRtrFlag); - } - - if (response.can_id.to_native() & CAN_EFF_FLAG) != 0 { - can_rx.flags = VIRTIO_CAN_FLAGS_EXTENDED.into(); - can_rx.can_id = (response.can_id.to_native() & CAN_EFF_MASK).into(); - } else { - can_rx.can_id = (response.can_id.to_native() & CAN_SFF_MASK).into(); - } - if (response.can_id.to_native() & CAN_RTR_FLAG) != 0 { - can_rx.flags = (can_rx.flags.to_native() & VIRTIO_CAN_FLAGS_RTR).into(); - } - - // HACK AHEAD: Vcan can not be comfigured as CANFD interface, but possible - // to configure its MTU to 64 bytes. So if a messages bigger than 8 bytes - // is being received we consider it as CANFD message. - let can_in_name = self.controller.read().unwrap().can_in_name.clone(); - if self.check_features(VIRTIO_CAN_F_CAN_FD) && - response.length.to_native() > 8 && can_in_name == "vcan0" { - response.flags = (response.flags.to_native() | CAN_FRMF_TYPE_FD).into(); - warn!("\n\n\nCANFD VCAN0\n\n"); - } - - if (response.flags.to_native() & CAN_FRMF_TYPE_FD) != 0 { - can_rx.flags = (can_rx.flags.to_native() | VIRTIO_CAN_FLAGS_FD).into(); - if response.length.to_native() > 64 { - warn!("%s(): Cut length from {} to 64\n", response.length.to_native()); - can_rx.length = 64.into(); - } - } else { - if response.length.to_native() > 8 { - warn!("%s(): Cut length from {} to 8\n", response.length.to_native()); - can_rx.length = 8.into(); - } - } - - can_rx.sdu.copy_from_slice(&response.sdu[0..64]); - CanController::print_can_frame(can_rx); - - desc_chain - .memory() - .write_slice(can_rx.as_slice(), desc_response.addr()) - .map_err(|_| Error::DescriptorWriteFailed)?; - - if vring.add_used(desc_chain.head_index(), desc_response.len()).is_err() { - warn!("Couldn't return used descriptors to the ring"); - } - - Ok(true) - } - - /// Process the messages in the vring and dispatch replies - fn process_ctrl_queue(&mut self, vring: &VringRwLock) -> Result<()> { - dbg!("process_ctrl_queue"); - let requests: Vec<_> = vring - .get_mut() - .get_queue_mut() - .iter(self.mem.as_ref().unwrap().memory()) - .map_err(|_| Error::DescriptorNotFound)? - .collect(); - - if self.process_ctrl_requests(requests, vring)? { - // Send notification once all the requests are processed - vring - .signal_used_queue() - .map_err(|_| Error::NotificationFailed)?; - } - Ok(()) - } - - /// Process the messages in the vring and dispatch replies - fn process_tx_queue(&self, vring: &VringRwLock) -> Result<()> { - dbg!("process_tx_queue"); - let requests: Vec<_> = vring - .get_mut() - .get_queue_mut() - .iter(self.mem.as_ref().unwrap().memory()) - .map_err(|_| Error::DescriptorNotFound)? - .collect(); - - if self.process_tx_requests(requests, vring)? { - // Send notification once all the requests are processed - vring - .signal_used_queue() - .map_err(|_| { - println!("signal_used_queue error"); - Error::NotificationFailed - })?; - } - - Ok(()) - } - - /// Process the messages in the vring and dispatch replies - fn process_rx_queue(&mut self, vring: &VringRwLock) -> Result<()> { - dbg!("process_rx_queue"); - let requests: Vec<_> = vring - .get_mut() - .get_queue_mut() - .iter(self.mem.as_ref().unwrap().memory()) - .map_err(|_| Error::DescriptorNotFound)? - .collect(); - - if self.process_rx_requests(requests, vring)? { - // Send notification once all the requests are processed - vring - .signal_used_queue() - .map_err(|_| { - println!("NotificationFailed"); - Error::NotificationFailed - })?; - } - Ok(()) - } - - fn process_rx_queue_dump(&mut self, _vring: &VringRwLock) -> Result<()> { - dbg!("Do nothing, if you reach that point!"); - Ok(()) - } - - /// Set self's VringWorker. - pub(crate) fn set_vring_worker( - &self, - vring_worker: &Arc<VringEpollHandler<Arc<RwLock<VhostUserCanBackend>>, VringRwLock, ()>>, - ) { - let rx_event_fd = self.controller.read().unwrap().rx_event_fd.as_raw_fd(); - vring_worker - .register_listener( - rx_event_fd, - EventSet::IN, - //u64::from(BACKEND_EFD)) - 4u64 as u64) - .unwrap(); - } -} - -/// VhostUserBackendMut trait methods -impl VhostUserBackendMut<VringRwLock, ()> - for VhostUserCanBackend -{ - fn num_queues(&self) -> usize { - println!("num_queues: {:?}", NUM_QUEUES); - NUM_QUEUES - } - - fn max_queue_size(&self) -> usize { - println!("max_queue_size: {:?}", QUEUE_SIZE); - QUEUE_SIZE - } - - fn features(&self) -> u64 { - // this matches the current libvhost defaults except VHOST_F_LOG_ALL - let features = 1 << VIRTIO_F_VERSION_1 - | 1 << VIRTIO_F_NOTIFY_ON_EMPTY - | 1 << VIRTIO_RING_F_EVENT_IDX - | 1 << VIRTIO_CAN_F_CAN_CLASSIC - | 1 << VIRTIO_CAN_F_CAN_FD - | 1 << VIRTIO_RING_F_INDIRECT_DESC - | VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits(); - - println!("vhu_can->features: {:x}", features); - features - } - - fn acked_features(&mut self, _features: u64) { - println!("\nacked_features: 0x{:x}\n", _features); - self.acked_features = _features; - } - - fn protocol_features(&self) -> VhostUserProtocolFeatures { - let protocol_features = VhostUserProtocolFeatures::MQ - | VhostUserProtocolFeatures::CONFIG - | VhostUserProtocolFeatures::REPLY_ACK; - //| VhostUserProtocolFeatures::STATUS - - println!("protocol_features: {:x}", protocol_features); - protocol_features - } - - fn get_config(&self, offset: u32, size: u32) -> Vec<u8> { - // SAFETY: The layout of the structure is fixed and can be initialized by - // reading its content from byte array. - dbg!("vhu_can->get_config"); - unsafe { - from_raw_parts( - self.controller.write().unwrap() - .config() - .as_slice() - .as_ptr() - .offset(offset as isize) as *const _ as *const _, - size as usize, - ) - .to_vec() - } - } - - fn set_event_idx(&mut self, enabled: bool) { - dbg!(self.event_idx = enabled); - } - - fn update_memory(&mut self, mem: GuestMemoryAtomic<GuestMemoryMmap>) -> IoResult<()> { - dbg!("update_memory\n"); - self.mem = Some(mem); - Ok(()) - } - - fn handle_event( - &mut self, - device_event: u16, - evset: EventSet, - vrings: &[VringRwLock], - _thread_id: usize, - ) -> IoResult<bool> { - dbg!("\nhandle_event:"); - - if evset != EventSet::IN { - return Err(Error::HandleEventNotEpollIn.into()); - } - if device_event == RX_QUEUE { - println!("RX_QUEUE\n"); - return Ok(false); - }; - let vring = if device_event != BACKEND_EFD { - &vrings[device_event as usize] - } else { - println!("BACKEND_EFD\n"); - let _ = self.controller.write().unwrap().rx_event_fd.read(); - &vrings[RX_QUEUE as usize] - }; - if self.event_idx { - // vm-virtio's Queue implementation only checks avail_index - // once, so to properly support EVENT_IDX we need to keep - // calling process_request_queue() until it stops finding - // new requests on the queue. - loop { - vring.disable_notification().unwrap(); - //match queue_idx { - match device_event { - CTRL_QUEUE => self.process_ctrl_queue(vring), - TX_QUEUE => self.process_tx_queue(vring), - RX_QUEUE => self.process_rx_queue_dump(vring), - BACKEND_EFD => self.process_rx_queue(vring), - _ => Err(Error::HandleEventUnknown.into()), - }?; - if !vring.enable_notification().unwrap() { - break; - } - } - } else { - // Without EVENT_IDX, a single call is enough. - match device_event { - CTRL_QUEUE => self.process_ctrl_queue(vring), - TX_QUEUE => self.process_tx_queue(vring), - RX_QUEUE => self.process_rx_queue_dump(vring), - BACKEND_EFD => self.process_rx_queue(vring), - _ => Err(Error::HandleEventUnknown.into()), - }?; - } - Ok(false) - } - - fn exit_event(&self, _thread_index: usize) -> Option<EventFd> { - dbg!("exit_event\n"); - self.exit_event.try_clone().ok() - } -} - |