diff options
Diffstat (limited to 'meta-egvirt/recipes-extended/vhost-device-console')
13 files changed, 3095 insertions, 773 deletions
diff --git a/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-0.1.0/CHANGELOG.md b/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-0.1.0/CHANGELOG.md index 51d3f040..6c84888c 100644..100755 --- a/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-0.1.0/CHANGELOG.md +++ b/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-0.1.0/CHANGELOG.md @@ -1,5 +1,5 @@ # Changelog -## [Unreleased] +## Unreleased ### Added @@ -9,7 +9,7 @@ ### Deprecated -## [0.1.0] +## v0.1.0 First release diff --git a/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-0.1.0/Cargo.lock b/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-0.1.0/Cargo.lock new file mode 100755 index 00000000..1486b386 --- /dev/null +++ b/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-0.1.0/Cargo.lock @@ -0,0 +1,1343 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "anstream" +version = "0.6.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" + +[[package]] +name = "anstyle-parse" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + +[[package]] +name = "anyhow" +version = "1.0.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10f00e1f6e58a40e807377c75c6a7f97bf9044fab57816f2414e6f5f4499d7b8" + +[[package]] +name = "arc-swap" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" + +[[package]] +name = "assert_matches" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "byte_conv" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "649972315d4931137a26fc2bf3ca95ee257ad796a5b57bdeb04205c91a4b5780" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "4.5.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e5a21b8495e732f1b3c364c9949b201ca7bae518c502c80256c96ad79eaf6ac" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cf2dd12af7a047ad9d6da2b6b249759a22a7abc0f474c1dae1777afa4b21a73" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "clap_lex" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" + +[[package]] +name = "colorchoice" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" + +[[package]] +name = "console" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "unicode-width", + "windows-sys 0.52.0", +] + +[[package]] +name = "crossterm" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df" +dependencies = [ + "bitflags 2.6.0", + "crossterm_winapi", + "libc", + "mio", + "parking_lot", + "signal-hook", + "signal-hook-mio", + "winapi", +] + +[[package]] +name = "crossterm_winapi" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" +dependencies = [ + "winapi", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "embedded-can" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9d2e857f87ac832df68fa498d18ddc679175cf3d2e4aa893988e5601baf9438" +dependencies = [ + "nb", +] + +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + +[[package]] +name = "enumn" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "env_filter" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "env_logger" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", +] + +[[package]] +name = "epoll" +version = "4.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74351c3392ea1ff6cd2628e0042d268ac2371cb613252ff383b6dfa50d22fa79" +dependencies = [ + "bitflags 2.6.0", + "libc", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "fastrand" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" + +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", + "num_cpus", +] + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-timer" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "indexmap" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "is-terminal" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" +dependencies = [ + "hermit-abi 0.4.0", + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.158" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "memoffset" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +dependencies = [ + "autocfg", +] + +[[package]] +name = "mio" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys 0.48.0", +] + +[[package]] +name = "nb" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" + +[[package]] +name = "neli" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1100229e06604150b3becd61a4965d5c70f3be1759544ea7274166f4be41ef43" +dependencies = [ + "byteorder", + "libc", + "log", + "neli-proc-macros", +] + +[[package]] +name = "neli-proc-macros" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c168194d373b1e134786274020dae7fc5513d565ea2ebb9bc9ff17ffb69106d4" +dependencies = [ + "either", + "proc-macro2", + "quote", + "serde", + "syn 1.0.109", +] + +[[package]] +name = "nix" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", + "memoffset", + "pin-utils", +] + +[[package]] +name = "nix" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" +dependencies = [ + "bitflags 2.6.0", + "cfg-if", + "libc", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi 0.3.9", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "proc-macro-crate" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "queues" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1475abae4f8ad4998590fe3acfe20104f0a5d48fc420c817cd2c09c3f56151f0" + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +dependencies = [ + "bitflags 2.6.0", +] + +[[package]] +name = "regex" +version = "1.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + +[[package]] +name = "relative-path" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" + +[[package]] +name = "rstest" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b423f0e62bdd61734b67cd21ff50871dfaeb9cc74f869dcd6af974fbcb19936" +dependencies = [ + "futures", + "futures-timer", + "rstest_macros", + "rustc_version", +] + +[[package]] +name = "rstest_macros" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5e1711e7d14f74b12a58411c542185ef7fb7f2e7f8ee6e2940a883628522b42" +dependencies = [ + "cfg-if", + "glob", + "proc-macro-crate", + "proc-macro2", + "quote", + "regex", + "relative-path", + "rustc_version", + "syn 2.0.77", + "unicode-ident", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.38.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f55e80d50763938498dd5ebb18647174e0c76dc38c5505294bb224624f30f36" +dependencies = [ + "bitflags 2.6.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + +[[package]] +name = "serde" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "signal-hook" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-mio" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd" +dependencies = [ + "libc", + "mio", + "signal-hook", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "socket2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "socketcan" +version = "3.4.0-pre.0" +source = "git+https://github.com/socketcan-rs/socketcan-rs.git?rev=f004ee91e142a37fea36c5d719a57852c7076e87#f004ee91e142a37fea36c5d719a57852c7076e87" +dependencies = [ + "bitflags 1.3.2", + "byte_conv", + "embedded-can", + "hex", + "itertools", + "libc", + "log", + "nb", + "neli", + "nix 0.26.4", + "socket2", + "thiserror", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" +dependencies = [ + "cfg-if", + "fastrand", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" + +[[package]] +name = "toml_edit" +version = "0.22.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" + +[[package]] +name = "unicode-width" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "v4l2r" +version = "0.0.1" +source = "git+https://github.com/Gnurou/v4l2r?rev=110fd77#110fd773d15c787cbc6c2ded1bf8459c8df89f72" +dependencies = [ + "anyhow", + "bitflags 2.6.0", + "enumn", + "log", + "nix 0.27.1", + "thiserror", +] + +[[package]] +name = "vhost" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6be08d1166d41a78861ad50212ab3f9eca0729c349ac3a7a8f557c62406b87cc" +dependencies = [ + "bitflags 2.6.0", + "libc", + "vm-memory", + "vmm-sys-util", +] + +[[package]] +name = "vhost-device-can" +version = "0.1.0" +dependencies = [ + "assert_matches", + "clap", + "env_logger 0.11.5", + "log", + "queues", + "socketcan", + "thiserror", + "vhost", + "vhost-user-backend", + "virtio-bindings", + "virtio-queue", + "vm-memory", + "vmm-sys-util", +] + +[[package]] +name = "vhost-device-console" +version = "0.1.0" +dependencies = [ + "assert_matches", + "clap", + "console", + "crossterm", + "env_logger 0.10.2", + "epoll", + "log", + "nix 0.26.4", + "queues", + "thiserror", + "vhost", + "vhost-user-backend", + "virtio-bindings", + "virtio-queue", + "vm-memory", + "vmm-sys-util", +] + +[[package]] +name = "vhost-device-video" +version = "0.1.0" +dependencies = [ + "assert_matches", + "bitflags 2.6.0", + "clap", + "env_logger 0.11.5", + "epoll", + "futures-executor", + "libc", + "log", + "num_enum", + "rstest", + "tempfile", + "thiserror", + "v4l2r", + "vhost", + "vhost-user-backend", + "virtio-bindings", + "virtio-queue", + "vm-memory", + "vmm-sys-util", +] + +[[package]] +name = "vhost-user-backend" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f0ffb1dd8e00a708a0e2c32d5efec5812953819888591fff9ff68236b8a5096" +dependencies = [ + "libc", + "log", + "vhost", + "virtio-bindings", + "virtio-queue", + "vm-memory", + "vmm-sys-util", +] + +[[package]] +name = "virtio-bindings" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68d0df4f5ad79b1dc81b5913ac737e24a84dcd5100f36ed953a1faec18aba241" + +[[package]] +name = "virtio-queue" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07d8406e7250c934462de585d8f2d2781c31819bca1fbb7c5e964ca6bbaabfe8" +dependencies = [ + "log", + "virtio-bindings", + "vm-memory", + "vmm-sys-util", +] + +[[package]] +name = "vm-memory" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3aba5064cc5f6f7740cddc8dae34d2d9a311cac69b60d942af7f3ab8fc49f4" +dependencies = [ + "arc-swap", + "bitflags 2.6.0", + "libc", + "thiserror", + "vmm-sys-util", + "winapi", +] + +[[package]] +name = "vmm-sys-util" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1435039746e20da4f8d507a72ee1b916f7b4b05af7a91c093d2c6561934ede" +dependencies = [ + "bitflags 1.3.2", + "libc", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +dependencies = [ + "memchr", +] diff --git a/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-0.1.0/Cargo.toml b/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-0.1.0/Cargo.toml index c2f9f71e..aa520360 100644..100755 --- a/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-0.1.0/Cargo.toml +++ b/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-0.1.0/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "vhost-device-console" -version = "0.0.1" +version = "0.1.0" authors = ["Timos Ampelikiotis <t.ampelikiotis@virtualopensystems.com>"] description = "vhost console backend device" repository = "https://github.com/rust-vmm/vhost-device" @@ -16,20 +16,22 @@ xen = ["vm-memory/xen", "vhost/xen", "vhost-user-backend/xen"] [dependencies] console = "0.15.7" +crossterm = "0.27.0" +nix = "0.26.4" queues = "1.0.2" -clap = { version = "4.2.5", features = ["derive"] } +clap = { version = "4.4", features = ["derive"] } env_logger = "0.10" -libc = "0.2" +epoll = "4.3" 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" +vhost = { version = "0.11", features = ["vhost-user-backend"] } +vhost-user-backend = "0.15" +virtio-bindings = "0.2.2" +virtio-queue = "0.12" +vm-memory = "0.14.1" +vmm-sys-util = "0.12" [dev-dependencies] assert_matches = "1.5" -virtio-queue = { version = "0.9", features = ["test-utils"] } -vm-memory = { version = "0.12", features = ["backend-mmap", "backend-atomic"] } +virtio-queue = { version = "0.12", features = ["test-utils"] } +vm-memory = { version = "0.14.1", features = ["backend-mmap", "backend-atomic"] } diff --git a/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-0.1.0/LICENSE-APACHE b/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-0.1.0/LICENSE-APACHE index d6456956..d6456956 100644..100755 --- a/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-0.1.0/LICENSE-APACHE +++ b/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-0.1.0/LICENSE-APACHE diff --git a/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-0.1.0/LICENSE-BSD-3-Clause b/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-0.1.0/LICENSE-BSD-3-Clause index dd975d98..dd975d98 100644..100755 --- a/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-0.1.0/LICENSE-BSD-3-Clause +++ b/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-0.1.0/LICENSE-BSD-3-Clause diff --git a/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-0.1.0/README.md b/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-0.1.0/README.md index b2c92440..c9eba8a7 100644..100755 --- a/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-0.1.0/README.md +++ b/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-0.1.0/README.md @@ -1,9 +1,32 @@ # vhost-device-console - Console emulation backend daemon ## Description -This program is a vhost-user backend that emulates a VirtIO Consolw device. + +This program is a vhost-user backend that emulates a VirtIO Console device. +The device's binary takes as parameters a socket path, a socket number which +is the number of connections, commonly used across all vhost-devices to +communicate with the vhost-user frontend devices, and the backend type +"nested" or "network". + +The "nested" backend allows input/output to the guest console through the +current terminal. + +The "network" backend creates a local TCP port (specified on vhost-device-console +arguments) and allows input/output to the guest console via that socket. + +This program is tested with QEMU's `vhost-user-device-pci` device. +Examples' section below. + +## Staging Device +This device will be in `staging` until we complete the following steps: +- [ ] Increase test coverage +- [ ] Support VIRTIO_CONSOLE_F_SIZE feature (optional) +- [ ] Support VIRTIO_CONSOLE_F_EMERG_WRITE feature (optional) ## Synopsis +```text +vhost-device-console --socket-path=<SOCKET_PATH> +``` ## Options @@ -18,8 +41,95 @@ This program is a vhost-user backend that emulates a VirtIO Consolw device. Location of vhost-user Unix domain sockets, this path will be suffixed with 0,1,2..socket_count-1. +.. option:: -p, --tcp-port=PORT_NUMBER + + The localhost's port to be used for each guest, this part will be increased with + 0,1,2..socket_count-1. + +-- option:: -b, --backend=nested|network + + The backend type vhost-device-console to be used. The current implementation + supports two types of backends: "nested", "network" (described above). + Note: The nested backend is selected by default and can be used only when + socket_count equals 1. + +## Limitations + +This device is still work-in-progress (WIP). The current version has been tested +with VIRTIO_CONSOLE_F_MULTIPORT, but only for one console (`max_nr_ports = 1`). +Also it does not yet support the VIRTIO_CONSOLE_F_EMERG_WRITE and +VIRTIO_CONSOLE_F_SIZE features. + +## Features + +The current device gives access to multiple QEMU guest by providing a login prompt +either by connecting to a localhost server port (network backend) or by creating an +nested command prompt in the current terminal (nested backend). This prompt appears +as soon as the guest is fully booted and gives the ability to user run command as a +in regular terminal. + ## Examples +### Dependencies +For testing the device the required dependencies are: +- Linux: + - Set `CONFIG_VIRTIO_CONSOLE=y` +- QEMU (optional): + - A new vhost-user-console device has been implemented in the following repo: + - https://github.com/virtualopensystems/qemu/tree/vhu-console-rfc + + +### Test the device + +The daemon should be started first: +```shell +host# vhost-device-console --socket-path=/tmp/console.sock --socket-count=1 \ + --tcp-port=12345 --backend=network +``` +>Note: In case the backend is "nested" there is no need to provide + "--socket-count" and "--tcp-port" parameters. + +The QEMU invocation needs to create a chardev socket the device can +use to communicate as well as share the guests memory over a memfd. + +There are two option for running QEMU with vhost-device-console: + +1) Using `vhost-user-console-pci`: +```text +host# qemu-system \ + <normal QEMU options> \ + -machine <machine options>,memory-backend=mem0 \ + -object memory-backend-memfd,id=mem0,size=<Guest RAM size> \ # size == -m size + -chardev socket,path=/tmp/console.sock0,id=con \ + -device vhost-user-console-pci,chardev=con0,id=console \ + ... +``` + +> Note: For testing this scenario the reader needs to clone the QEMU version from the following repo +> which implements `vhost-user-console` device. +> - https://github.com/virtualopensystems/qemu/tree/vhu-console-rfc + +2) Using `vhost-user-device-pci`: +```text +host# qemu-system \ + <normal QEMU options> \ + -machine <machine options>,memory-backend=mem0 \ + -object memory-backend-memfd,id=mem0,size=<Guest RAM size> \ # size == -m size + -chardev socket,id=con0,path=/tmp/console.sock0 \ + -device vhost-user-device-pci,chardev=con0,virtio-id=3,num_vqs=4,config_size=12 \ + ... +``` + +Eventually, the user can connect to the console by running: +```test +host# stty -icanon -echo && nc localhost 12345 && stty echo +``` + +>Note: `stty -icanon -echo` is used to force the tty layer to disable buffering and send / receive each character individually. After closing the connection please run `stty echo` so character are printed back on the local terminal console. + +>Note: In case the backend is "nested" a nested terminal will be shown into + vhost-device-console terminal space. + ## License This project is licensed under either of diff --git a/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-0.1.0/src/backend.rs b/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-0.1.0/src/backend.rs index 15b50a38..62d6745c 100644..100755 --- a/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-0.1.0/src/backend.rs +++ b/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-0.1.0/src/backend.rs @@ -1,22 +1,22 @@ // VIRTIO CONSOLE Emulation via vhost-user // -// Copyright 2023 VIRTUAL OPEN SYSTEMS SAS. All Rights Reserved. +// Copyright 2023-2024 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::any::Any; +use std::collections::HashMap; +use std::path::PathBuf; use std::sync::{Arc, RwLock}; -use std::thread::{spawn, JoinHandle}; +use std::thread::Builder; -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::console::{ConsoleController}; +use crate::console::{BackendType, ConsoleController}; use crate::vhu_console::VhostUserConsoleBackend; pub(crate) type Result<T> = std::result::Result<T, Error>; @@ -26,186 +26,288 @@ pub(crate) type Result<T> = std::result::Result<T, Error>; pub(crate) enum Error { #[error("Invalid socket count: {0}")] SocketCountInvalid(usize), - #[error("Failed to join threads")] - FailedJoiningThreads, - #[error("Could not create console controller: {0}")] - CouldNotCreateConsoleController(crate::console::Error), #[error("Could not create console backend: {0}")] CouldNotCreateBackend(crate::vhu_console::Error), #[error("Could not create daemon: {0}")] CouldNotCreateDaemon(vhost_user_backend::Error), -} - -#[derive(Parser, Debug)] -#[clap(author, version, about, long_about = None)] -struct ConsoleArgs { - /// Location of vhost-user Unix domain socket. This is suffixed by 0,1,2..socket_count-1. - #[clap(short, long)] - socket_path: String, - - /// A console device name to be used for reading (ex. vconsole, console0, console1, ... etc.) - #[clap(short = 'i', long)] - console_path: String, - - /// Number of guests (sockets) to connect to. - #[clap(short = 'c', long, default_value_t = 1)] - socket_count: u32, + #[error("Fatal error: {0}")] + ServeFailed(vhost_user_backend::Error), + #[error("Thread `{0}` panicked")] + ThreadPanic(String, Box<dyn Any + Send>), + #[error("Error using multiple sockets with Nested backend")] + WrongBackendSocket, } #[derive(PartialEq, Debug)] -struct ConsoleConfiguration { - socket_path: String, - socket_count: u32, - console_path: String, +pub struct VuConsoleConfig { + pub(crate) socket_path: PathBuf, + pub(crate) backend: BackendType, + pub(crate) tcp_port: String, + pub(crate) socket_count: u32, } -impl TryFrom<ConsoleArgs> for ConsoleConfiguration { - type Error = Error; +impl VuConsoleConfig { + pub fn generate_socket_paths(&self) -> Vec<PathBuf> { + let socket_file_name = self + .socket_path + .file_name() + .expect("socket_path has no filename."); + let socket_file_parent = self + .socket_path + .parent() + .expect("socket_path has no parent directory."); + + let make_socket_path = |i: u32| -> PathBuf { + let mut file_name = socket_file_name.to_os_string(); + file_name.push(std::ffi::OsStr::new(&i.to_string())); + socket_file_parent.join(&file_name) + }; - fn try_from(args: ConsoleArgs) -> Result<Self> { + (0..self.socket_count).map(make_socket_path).collect() + } - if args.socket_count == 0 { - return Err(Error::SocketCountInvalid(0)); - } + pub fn generate_tcp_addrs(&self) -> Vec<String> { + let tcp_port_base = self.tcp_port.clone(); - let console_path = args.console_path.trim().to_string(); + let make_tcp_port = |i: u32| -> String { + let port_num: u32 = tcp_port_base.clone().parse().unwrap(); + "127.0.0.1:".to_owned() + &(port_num + i).to_string() + }; - Ok(ConsoleConfiguration { - socket_path: args.socket_path, - socket_count: args.socket_count, - console_path, - }) + (0..self.socket_count).map(make_tcp_port).collect() } } -fn start_backend(args: ConsoleArgs) -> Result<()> { - - println!("start_backend function!\n"); - - let config = ConsoleConfiguration::try_from(args).unwrap(); - let mut handles = Vec::new(); +// This is the public API through which an external program starts the +/// vhost-device-console backend server. +pub(crate) fn start_backend_server( + socket: PathBuf, + tcp_addr: String, + backend: BackendType, +) -> Result<()> { + loop { + let controller = ConsoleController::new(backend); + let arc_controller = Arc::new(RwLock::new(controller)); + let vu_console_backend = Arc::new(RwLock::new( + VhostUserConsoleBackend::new(arc_controller).map_err(Error::CouldNotCreateBackend)?, + )); + + let mut daemon = VhostUserDaemon::new( + String::from("vhost-device-console-backend"), + vu_console_backend.clone(), + GuestMemoryAtomic::new(GuestMemoryMmap::new()), + ) + .map_err(Error::CouldNotCreateDaemon)?; + + let vring_workers = daemon.get_epoll_handlers(); + vu_console_backend + .read() + .unwrap() + .set_vring_worker(&vring_workers[0]); + + // Start the corresponding console thread + let read_handle = if backend == BackendType::Nested { + VhostUserConsoleBackend::start_console_thread(&vu_console_backend) + } else { + VhostUserConsoleBackend::start_tcp_console_thread(&vu_console_backend, tcp_addr.clone()) + }; - for _ in 0..config.socket_count { - let socket = config.socket_path.to_owned(); - let console_path = config.console_path.to_owned(); + daemon.serve(&socket).map_err(Error::ServeFailed)?; - let handle: JoinHandle<Result<()>> = spawn(move || loop { - // A separate thread is spawned for each socket and console 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. + // Kill console input thread + vu_console_backend.read().unwrap().kill_console_thread(); - let controller = - ConsoleController::new(console_path.clone()).map_err(Error::CouldNotCreateConsoleController)?; - let arc_controller = Arc::new(RwLock::new(controller)); - let vu_console_backend = Arc::new(RwLock::new( - VhostUserConsoleBackend::new(arc_controller).map_err(Error::CouldNotCreateBackend)?, - )); + // Wait for read thread to exit + match read_handle.join() { + Ok(_) => info!("The read thread returned successfully"), + Err(e) => warn!("The read thread returned the error: {:?}", e), + } + } +} - let mut daemon = VhostUserDaemon::new( - String::from("vhost-device-console-backend"), - vu_console_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_console_backend.read() - .unwrap() - .set_vring_worker(&vring_workers[0]); - VhostUserConsoleBackend::start_console_thread(&vu_console_backend); - - 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_console_backend.read().unwrap().exit_event.write(1).unwrap(); - }); - - handles.push(handle); +pub fn start_backend(config: VuConsoleConfig) -> Result<()> { + let mut handles = HashMap::new(); + let (senders, receiver) = std::sync::mpsc::channel(); + let tcp_addrs = config.generate_tcp_addrs(); + let backend = config.backend; + + for (thread_id, (socket, tcp_addr)) in config + .generate_socket_paths() + .into_iter() + .zip(tcp_addrs.iter()) + .enumerate() + { + let tcp_addr = tcp_addr.clone(); + info!("thread_id: {}, socket: {:?}", thread_id, socket); + + let name = format!("vhu-console-{}", tcp_addr); + let sender = senders.clone(); + let handle = Builder::new() + .name(name.clone()) + .spawn(move || { + let result = std::panic::catch_unwind(move || { + start_backend_server(socket, tcp_addr.to_string(), backend) + }); + + // Notify the main thread that we are done. + sender.send(thread_id).unwrap(); + + result.map_err(|e| Error::ThreadPanic(name, e))? + }) + .unwrap(); + handles.insert(thread_id, handle); } - for handle in handles { - handle.join().map_err(|_| Error::FailedJoiningThreads)??; + while !handles.is_empty() { + let thread_id = receiver.recv().unwrap(); + handles + .remove(&thread_id) + .unwrap() + .join() + .map_err(std::panic::resume_unwind) + .unwrap()?; } Ok(()) } -pub(crate) fn console_init() { - env_logger::init(); - println!("Console_init function!"); - if let Err(e) = start_backend(ConsoleArgs::parse()) { - error!("{e}"); - exit(1); - } -} - #[cfg(test)] mod tests { use super::*; + use crate::ConsoleArgs; + use assert_matches::assert_matches; #[test] - fn test_console_configuration_try_from_valid_args() { + fn test_console_valid_configuration_nested() { let args = ConsoleArgs { - socket_path: String::from("/path/to/socket"), - console_path: String::from("vconsole"), - socket_count: 3, + socket_path: String::from("/tmp/vhost.sock").into(), + backend: BackendType::Nested, + tcp_port: String::from("12345"), + socket_count: 1, }; - let result = ConsoleConfiguration::try_from(args); + assert!(VuConsoleConfig::try_from(args).is_ok()); + } - assert!(result.is_ok()); + #[test] + fn test_console_invalid_configuration_nested_1() { + let args = ConsoleArgs { + socket_path: String::from("/tmp/vhost.sock").into(), + backend: BackendType::Nested, + tcp_port: String::from("12345"), + socket_count: 0, + }; - let config = result.unwrap(); - assert_eq!(config.socket_path, "/path/to/socket"); - assert_eq!(config.console_path, "vconsole"); - assert_eq!(config.socket_count, 3); + assert_matches!( + VuConsoleConfig::try_from(args), + Err(Error::SocketCountInvalid(0)) + ); } #[test] - fn test_console_configuration_try_from_invalid_args() { - // Test with socket_count = 0 - let args_invalid_count = ConsoleArgs { - socket_path: String::from("/path/to/socket"), - console_path: String::from("vconsole"), - socket_count: 0, + fn test_console_invalid_configuration_nested_2() { + let args = ConsoleArgs { + socket_path: String::from("/tmp/vhost.sock").into(), + backend: BackendType::Nested, + tcp_port: String::from("12345"), + socket_count: 2, + }; + + assert_matches!( + VuConsoleConfig::try_from(args), + Err(Error::WrongBackendSocket) + ); + } + + #[test] + fn test_console_valid_configuration_network_1() { + let args = ConsoleArgs { + socket_path: String::from("/tmp/vhost.sock").into(), + backend: BackendType::Network, + tcp_port: String::from("12345"), + socket_count: 1, }; - let result_invalid_count = ConsoleConfiguration::try_from(args_invalid_count); - assert!(result_invalid_count.is_err()); + assert!(VuConsoleConfig::try_from(args).is_ok()); } #[test] - fn test_start_backend_success() { - // Test start_backend with valid arguments + fn test_console_valid_configuration_network_2() { let args = ConsoleArgs { - socket_path: String::from("/path/to/socket"), - console_path: String::from("vconsole"), + socket_path: String::from("/tmp/vhost.sock").into(), + backend: BackendType::Network, + tcp_port: String::from("12345"), socket_count: 2, }; - let result = start_backend(args); + assert!(VuConsoleConfig::try_from(args).is_ok()); + } + + fn test_backend_start_and_stop(args: ConsoleArgs) { + let config = VuConsoleConfig::try_from(args).expect("Wrong config"); + + let tcp_addrs = config.generate_tcp_addrs(); + let backend = config.backend; + + for (_socket, tcp_addr) in config + .generate_socket_paths() + .into_iter() + .zip(tcp_addrs.iter()) + { + let controller = ConsoleController::new(backend); + let arc_controller = Arc::new(RwLock::new(controller)); + let vu_console_backend = Arc::new(RwLock::new( + VhostUserConsoleBackend::new(arc_controller) + .map_err(Error::CouldNotCreateBackend) + .expect("Fail create vhuconsole backend"), + )); + + let mut _daemon = VhostUserDaemon::new( + String::from("vhost-device-console-backend"), + vu_console_backend.clone(), + GuestMemoryAtomic::new(GuestMemoryMmap::new()), + ) + .map_err(Error::CouldNotCreateDaemon) + .expect("Failed create daemon"); + + // Start the corresponinding console thread + let read_handle = if backend == BackendType::Nested { + VhostUserConsoleBackend::start_console_thread(&vu_console_backend) + } else { + VhostUserConsoleBackend::start_tcp_console_thread( + &vu_console_backend, + tcp_addr.clone(), + ) + }; + + // Kill console input thread + vu_console_backend.read().unwrap().kill_console_thread(); + + // Wait for read thread to exit + assert_matches!(read_handle.join(), Ok(_)); + } + } + #[test] + fn test_start_net_backend_success() { + let args = ConsoleArgs { + socket_path: String::from("/tmp/vhost.sock").into(), + backend: BackendType::Network, + tcp_port: String::from("12345"), + socket_count: 1, + }; + + test_backend_start_and_stop(args); + } + + #[test] + fn test_start_nested_backend_success() { + let args = ConsoleArgs { + socket_path: String::from("/tmp/vhost.sock").into(), + backend: BackendType::Nested, + tcp_port: String::from("12345"), + socket_count: 1, + }; - assert!(result.is_ok()); + test_backend_start_and_stop(args); } } diff --git a/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-0.1.0/src/console.rs b/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-0.1.0/src/console.rs index 2e2972b2..079fe0cb 100644..100755 --- a/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-0.1.0/src/console.rs +++ b/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-0.1.0/src/console.rs @@ -1,86 +1,44 @@ -// CAN backend device +// Console backend device // -// Copyright 2023 VIRTUAL OPEN SYSTEMS SAS. All Rights Reserved. +// Copyright 2023-2024 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 crate::virtio_console::VirtioConsoleConfig; +use clap::ValueEnum; +use log::trace; -use thiserror::Error as ThisError; -use vm_memory::{ByteValued, Le16}; - -use crate::vhu_console::{VirtioConsoleConfig, VirtioConsoleControl}; - -type Result<T> = std::result::Result<T, Error>; - -#[derive(Copy, Clone, Debug, PartialEq, ThisError)] -pub(crate) enum Error { - #[error("Console not enabled yet")] - ConsoleNotEnabled, +#[derive(ValueEnum, Clone, Copy, Default, Debug, Eq, PartialEq)] +pub enum BackendType { + #[default] + Nested, + Network, } #[derive(Debug)] pub(crate) struct ConsoleController { config: VirtioConsoleConfig, - pub console_name: String, + pub backend: BackendType, + pub exit: bool, } impl ConsoleController { - // Creates a new controller corresponding to `device`. - pub(crate) fn new(console_name: String) -> Result<ConsoleController> { - - let console_name = console_name.to_owned(); - println!("console_name: {:?}", console_name); - - Ok(ConsoleController { + pub(crate) fn new(backend: BackendType) -> ConsoleController { + ConsoleController { config: VirtioConsoleConfig { - cols: 20.into(), - rows: 20.into(), - max_nr_ports: 1.into(), - emerg_wr: 64.into(), - }, - console_name, - }) + cols: 20.into(), + rows: 20.into(), + max_nr_ports: 1.into(), + emerg_wr: 64.into(), + }, + backend, + exit: false, + } } pub(crate) fn config(&self) -> &VirtioConsoleConfig { - log::trace!("Get config\n"); + trace!("Get config\n"); &self.config } - - pub(crate) fn operation(&self, tx_request: VirtioConsoleControl) -> Result<()> { - log::trace!("Console operation\n"); - Ok(()) - } } - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_new_console_controller() { - let console_name = String::from("test_console"); - let controller = ConsoleController::new(console_name.clone()); - - assert!(controller.is_ok()); - - let controller = controller.unwrap(); - assert_eq!(controller.console_name, "test_console"); - } - - #[test] - fn test_console_controller_config() { - let console_name = String::from("test_console"); - let controller = ConsoleController::new(console_name).unwrap(); - - let config = controller.config(); - assert_eq!(config.cols, 20); - assert_eq!(config.rows, 20); - assert_eq!(config.max_nr_ports, 1); - assert_eq!(config.emerg_wr, 64); - } -} - diff --git a/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-0.1.0/src/main.rs b/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-0.1.0/src/main.rs index cceafb4f..216a01e6 100644..100755 --- a/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-0.1.0/src/main.rs +++ b/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-0.1.0/src/main.rs @@ -1,18 +1,69 @@ // VIRTIO CONSOLE Emulation via vhost-user // -// Copyright 2023 VIRTUAL OPEN SYSTEMS SAS. All Rights Reserved. +// Copyright 2023-2024 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 console; -#[cfg(target_env = "gnu")] mod vhu_console; +mod virtio_console; +use crate::console::BackendType; +use clap::Parser; +use log::error; +use std::path::PathBuf; +use std::process::exit; + +pub(crate) type Result<T> = std::result::Result<T, Error>; +use crate::backend::{start_backend, Error, VuConsoleConfig}; + +#[derive(Parser, Debug)] +#[clap(author, version, about, long_about = None)] +struct ConsoleArgs { + /// Location of vhost-user Unix domain socket. This is suffixed by 0,1,2..socket_count-1. + #[clap(short = 's', long, value_name = "SOCKET")] + socket_path: PathBuf, + + /// Number of guests (sockets) to connect to. + #[clap(short = 'c', long, default_value_t = 1)] + socket_count: u32, + + /// Console backend (Network, Nested) to be used. + #[clap(short = 'b', long, value_enum, default_value = "nested")] + backend: BackendType, + + /// Initial tcp port to be used with "network" backend. If socket_count is N then + /// the following tcp ports will be created: tcp_port, tcp_port + 1, ..., tcp_port + (N - 1). + #[clap(short = 'p', long, value_name = "PORT", default_value = "12345")] + tcp_port: String, +} + +impl TryFrom<ConsoleArgs> for VuConsoleConfig { + type Error = Error; + + fn try_from(args: ConsoleArgs) -> Result<Self> { + if args.socket_count == 0 { + return Err(Error::SocketCountInvalid(0)); + } + + if (args.backend == BackendType::Nested) && (args.socket_count != 1) { + return Err(Error::WrongBackendSocket); + } + + Ok(VuConsoleConfig { + socket_path: args.socket_path, + backend: args.backend, + tcp_port: args.tcp_port, + socket_count: args.socket_count, + }) + } +} -#[cfg(target_env = "gnu")] fn main() { - backend::console_init() + env_logger::init(); + if let Err(e) = VuConsoleConfig::try_from(ConsoleArgs::parse()).and_then(start_backend) { + error!("{e}"); + exit(1); + } } diff --git a/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-0.1.0/src/vhu_console.rs b/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-0.1.0/src/vhu_console.rs index ebddb00d..d5cca74a 100644..100755 --- a/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-0.1.0/src/vhu_console.rs +++ b/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-0.1.0/src/vhu_console.rs @@ -1,22 +1,31 @@ // vhost device console // -// Copyright 2023 VIRTUAL OPEN SYSTEMS SAS. All Rights Reserved. +// Copyright 2023-2024 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 crate::console::{BackendType, ConsoleController}; +use crate::virtio_console::{ + VirtioConsoleControl, VIRTIO_CONSOLE_CONSOLE_PORT, VIRTIO_CONSOLE_DEVICE_READY, + VIRTIO_CONSOLE_F_MULTIPORT, VIRTIO_CONSOLE_PORT_ADD, VIRTIO_CONSOLE_PORT_NAME, + VIRTIO_CONSOLE_PORT_OPEN, VIRTIO_CONSOLE_PORT_READY, +}; +use console::Key; +use crossterm::terminal::{disable_raw_mode, enable_raw_mode}; +use log::{error, trace}; +use nix::sys::select::{select, FdSet}; +use std::os::fd::AsRawFd; use std::slice::from_raw_parts; use std::sync::{Arc, RwLock}; +use std::thread::JoinHandle; use std::{ convert, io::{self, Result as IoResult}, }; -use std::io::{Write}; -use std::os::fd::AsRawFd; use thiserror::Error as ThisError; use vhost::vhost_user::message::{VhostUserProtocolFeatures, VhostUserVirtioFeatures}; +use vhost_user_backend::VringEpollHandler; 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::{ @@ -24,76 +33,61 @@ use virtio_bindings::bindings::virtio_ring::{ }; use virtio_queue::{DescriptorChain, QueueOwnedT}; use vm_memory::{ - ByteValued, Bytes, GuestAddressSpace, GuestMemoryAtomic, GuestMemoryLoadGuard, - GuestMemoryMmap, Le16, Le32, + ByteValued, GuestAddressSpace, GuestMemoryAtomic, GuestMemoryLoadGuard, GuestMemoryMmap, }; use vmm_sys_util::epoll::EventSet; use vmm_sys_util::eventfd::{EventFd, EFD_NONBLOCK}; -use vhost_user_backend::VringEpollHandler; -use crate::console::{ConsoleController}; -use std::thread::{JoinHandle, spawn}; -use queues::{Queue, IsQueue}; -use std::thread; -use std::time::Duration; use console::Term; - -/// Feature bit numbers -pub const VIRTIO_CONSOLE_F_SIZE: u16 = 0; -pub const VIRTIO_CONSOLE_F_MULTIPORT: u16 = 1; -pub const VIRTIO_CONSOLE_F_EMERG_WRITE: u16 = 2; +use queues::{IsQueue, Queue}; +use std::io::Read; +use std::io::Write; +use std::net::TcpListener; +use std::thread::spawn; /// Virtio configuration const QUEUE_SIZE: usize = 128; const NUM_QUEUES: usize = 4; -/// Queues +/// Queue events const RX_QUEUE: u16 = 0; const TX_QUEUE: u16 = 1; const CTRL_RX_QUEUE: u16 = 2; const CTRL_TX_QUEUE: u16 = 3; -const BACKEND_EFD: u16 = (NUM_QUEUES + 1) as u16; -const BACKEND_RX_EFD: u16 = (NUM_QUEUES + 2) as u16; +/// The two following events are used to help the vhu_console +/// backend trigger events to itself. For example: +/// a) BACKEND_RX_EFD is being triggered when the backend +/// has new data to send to the RX queue. +/// b) BACKEND_CTRL_RX_EFD event is used when the backend +/// needs to write to the RX control queue. +const BACKEND_RX_EFD: u16 = (NUM_QUEUES + 1) as u16; +const BACKEND_CTRL_RX_EFD: u16 = (NUM_QUEUES + 2) as u16; -/// Console virtio control messages -const VIRTIO_CONSOLE_DEVICE_READY: u16 = 0 ; -const VIRTIO_CONSOLE_PORT_ADD: u16 = 1; -const VIRTIO_CONSOLE_PORT_REMOVE: u16 = 2; -const VIRTIO_CONSOLE_PORT_READY: u16 = 3; -const VIRTIO_CONSOLE_CONSOLE_PORT: u16 = 4; -const VIRTIO_CONSOLE_RESIZE: u16 = 5; -const VIRTIO_CONSOLE_PORT_OPEN: u16 = 6; -const VIRTIO_CONSOLE_PORT_NAME: u16 = 7; +/// Port name - Need to be updated when MULTIPORT feature +/// is supported for more than one devices. +const PORT_NAME: &[u8] = b"org.test.foo!"; type Result<T> = std::result::Result<T, Error>; #[derive(Copy, Clone, Debug, PartialEq, ThisError)] 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("Failed to send notification")] - NotificationFailed, + #[error("Descriptor not found")] + DescriptorNotFound, + #[error("Failed to send notification")] + NotificationFailed, #[error("Descriptor read failed")] DescriptorReadFailed, #[error("Descriptor write failed")] DescriptorWriteFailed, + #[error("Add used element in vring {0} failed")] + AddUsedElemFailed(u16), #[error("Failed to create new EventFd")] EventFdFailed, - #[error("Failed to remove rx queue")] - EmptyQueue, + #[error("Failed to add control message in the internal queue")] + RxCtrlQueueAddFailed, } impl convert::From<Error> for io::Error { @@ -102,53 +96,19 @@ impl convert::From<Error> for io::Error { } } -/// Virtio Console Config -#[derive(Copy, Clone, Debug, Default, PartialEq)] -#[repr(C)] -pub(crate) struct VirtioConsoleConfig { - pub cols: Le16, - pub rows: Le16, - pub max_nr_ports: Le32, - pub emerg_wr: Le32, -} - -// SAFETY: The layout of the structure is fixed and can be initialized by -// reading its content from byte array. -unsafe impl ByteValued for VirtioConsoleConfig {} - -#[derive(Copy, Clone, Debug, Default, PartialEq)] -#[repr(C)] -pub(crate) struct VirtioConsoleControl { - pub id: Le32, - pub event: Le16, - pub value: Le16, -} - -use std::io::Cursor; - -impl VirtioConsoleControl { - fn to_le_bytes(&self) -> Vec<u8> { - let mut buffer = Vec::new(); - - buffer.extend_from_slice(&self.id.to_native().to_le_bytes()); - buffer.extend_from_slice(&self.event.to_native().to_le_bytes()); - buffer.extend_from_slice(&self.value.to_native().to_le_bytes()); - buffer - } -} - // SAFETY: The layout of the structure is fixed and can be initialized by // reading its content from byte array. unsafe impl ByteValued for VirtioConsoleControl {} pub(crate) struct VhostUserConsoleBackend { controller: Arc<RwLock<ConsoleController>>, - acked_features: u64, + acked_features: u64, event_idx: bool, - rx_fifo: Queue<VirtioConsoleControl>, + rx_ctrl_fifo: Queue<VirtioConsoleControl>, + rx_data_fifo: Queue<String>, pub(crate) ready: bool, pub(crate) ready_to_write: bool, - pub(crate) output_buffer: String, + pub(crate) output_queue: Queue<String>, pub(crate) rx_event: EventFd, pub(crate) rx_ctrl_event: EventFd, pub(crate) exit_event: EventFd, @@ -160,13 +120,14 @@ type ConsoleDescriptorChain = DescriptorChain<GuestMemoryLoadGuard<GuestMemoryMm impl VhostUserConsoleBackend { pub(crate) fn new(controller: Arc<RwLock<ConsoleController>>) -> Result<Self> { Ok(VhostUserConsoleBackend { - controller: controller, + controller, event_idx: false, - rx_fifo: Queue::new(), - acked_features: 0x0, - ready: false, - ready_to_write: false, - output_buffer: String::new(), + rx_ctrl_fifo: Queue::new(), + rx_data_fifo: Queue::new(), + acked_features: 0x0, + ready: false, + ready_to_write: false, + output_queue: Queue::new(), rx_event: EventFd::new(EFD_NONBLOCK).map_err(|_| Error::EventFdFailed)?, rx_ctrl_event: EventFd::new(EFD_NONBLOCK).map_err(|_| Error::EventFdFailed)?, exit_event: EventFd::new(EFD_NONBLOCK).map_err(|_| Error::EventFdFailed)?, @@ -174,292 +135,229 @@ impl VhostUserConsoleBackend { }) } - fn check_features (&self, features: u16) -> bool { - (self.acked_features & (1 << features)) != 0 - } - - fn print_console_frame (&self, control_msg: VirtioConsoleControl) { - println!("id 0x{:x}", control_msg.id.to_native()); - println!("event 0x{:x}", control_msg.event.to_native()); - println!("value 0x{:x}", control_msg.value.to_native()); + fn print_console_frame(&self, control_msg: VirtioConsoleControl) { + trace!("id 0x{:x}", control_msg.id.to_native()); + trace!("event 0x{:x}", control_msg.event.to_native()); + trace!("value 0x{:x}", control_msg.value.to_native()); } fn process_rx_requests( - &mut self, - requests: Vec<ConsoleDescriptorChain>, - vring: &VringRwLock - ) -> Result<bool> { - log::trace!("process_rx_requests"); - + &mut self, + requests: Vec<ConsoleDescriptorChain>, + vring: &VringRwLock, + ) -> Result<bool> { if requests.is_empty() { - log::trace!("requests.is_empty"); - vring.signal_used_queue(); return Ok(true); } - log::trace!("requests.len: {:?}", requests.len()); - let desc_chain = &requests[0]; - let descriptors: Vec<_> = desc_chain.clone().collect(); - - log::trace!("descriptors.len(): {:?}", descriptors.len()); - if descriptors.len() != 1 { - log::trace!("Error::UnexpectedDescriptorCount"); - return Err(Error::UnexpectedDescriptorCount(descriptors.len())); - } - - let desc_request = descriptors[0]; - if !desc_request.is_write_only() { - log::trace!("!desc_request.is_write_only()"); - return Err(Error::UnexpectedReadableDescriptor(1)); - } - - // TODO: if buffer is more than the the desc_request length, - // write the remaining in the next chain. - log::trace!("desc_request.len(): {}", desc_request.len()); - let response = self.output_buffer.clone(); + for desc_chain in requests { + let atomic_mem = self.mem.as_ref().unwrap().memory(); + let mut writer = desc_chain + .clone() + .writer(&atomic_mem) + .map_err(|_| Error::DescriptorWriteFailed)?; + + let response: String = match self.rx_data_fifo.remove() { + Ok(item) => item, + _ => { + return Ok(false); + } + }; - desc_chain - .memory() - .write_slice(response.as_bytes(), desc_request.addr()) - .map_err(|_| Error::DescriptorWriteFailed)?; + for b in response.bytes() { + writer + .write_obj::<u8>(b) + .map_err(|_| Error::DescriptorWriteFailed)?; + } - if vring.add_used(desc_chain.head_index(), response.as_bytes().len() as u32).is_err() { - warn!("Couldn't return used descriptors to the ring"); + vring + .add_used(desc_chain.head_index(), writer.bytes_written() as u32) + .map_err(|_| Error::AddUsedElemFailed(RX_QUEUE))?; } Ok(true) } fn process_tx_requests( - &self, - requests: Vec<ConsoleDescriptorChain>, - vring: &VringRwLock - ) -> Result<bool> { - log::trace!("process_tx_requests"); - + &mut self, + requests: Vec<ConsoleDescriptorChain>, + vring: &VringRwLock, + ) -> Result<bool> { if requests.is_empty() { - log::trace!("requests.is_empty"); return Ok(true); } - log::trace!("requests.len: {:?}", requests.len()); for desc_chain in requests { - let descriptors: Vec<_> = desc_chain.clone().collect(); - - log::trace!("descriptors.len(): {:?}", descriptors.len()); - if descriptors.len() != 1 { - log::trace!("Error::UnexpectedDescriptorCount"); - return Err(Error::UnexpectedDescriptorCount(descriptors.len())); - } - - let desc_request = descriptors[0]; - if desc_request.is_write_only() { - log::trace!("Error::UnexpectedReadOnlyDescriptor"); - return Err(Error::UnexpectedWriteOnlyDescriptor(0)); - } - - log::trace!("desc_request.len(): {}", desc_request.len()); - let desc_len = desc_request.len(); - - let mut buffer = [0 as u8; 4096]; - - let request = desc_chain - .memory() - .read_slice(&mut buffer, desc_request.addr()) + let atomic_mem = self.mem.as_ref().unwrap().memory(); + let mut reader = desc_chain + .clone() + .reader(&atomic_mem) .map_err(|_| Error::DescriptorReadFailed)?; - let new_buff = &buffer[0..desc_len as usize]; - - let my_string = String::from_utf8(new_buff.to_vec()).unwrap(); - log::trace!("{}", my_string); - print!("{}", my_string); - io::stdout().flush().unwrap(); // Ensure the prompt is displayed. + let mut tx_data: Vec<u8> = Vec::new(); + let data_len = reader.available_bytes(); + for _i in 0..data_len { + let data_byte = reader + .read_obj::<u8>() + .map_err(|_| Error::DescriptorReadFailed)?; + tx_data.push(data_byte); + } - if vring.add_used(desc_chain.head_index(), desc_request.len()).is_err() { - log::trace!("Couldn't return used descriptors to the ring"); - warn!("Couldn't return used descriptors to the ring"); + let my_string = String::from_utf8(tx_data).unwrap(); + if self.controller.read().unwrap().backend == BackendType::Nested { + print!("{}", my_string); + io::stdout().flush().unwrap(); + } else { + self.output_queue + .add(my_string) + .expect("Failed to add element in the output queue"); + //.map_err(|_| Error::RxCtrlQueueAddFailed)?; } + + vring + .add_used(desc_chain.head_index(), reader.bytes_read() as u32) + .map_err(|_| Error::AddUsedElemFailed(TX_QUEUE))?; } Ok(true) } fn process_ctrl_rx_requests( - &mut self, - requests: Vec<ConsoleDescriptorChain>, - vring: &VringRwLock, - ) -> Result<bool> { - log::trace!("process_ctrl_rx_requests"); + &mut self, + requests: Vec<ConsoleDescriptorChain>, + vring: &VringRwLock, + ) -> Result<bool> { + let mut used_flag = false; if requests.is_empty() { - log::trace!("requests.is_empty()"); return Ok(true); } - log::trace!("\trequests.len(): {}", requests.len()); for desc_chain in requests { + let atomic_mem = self.mem.as_ref().unwrap().memory(); + let mut writer = desc_chain + .clone() + .writer(&atomic_mem) + .map_err(|_| Error::DescriptorWriteFailed)?; + + let ctrl_msg: VirtioConsoleControl = match self.rx_ctrl_fifo.remove() { + Ok(item) => { + used_flag = true; + item + } + _ => { + return Ok(used_flag); + } + }; - let descriptors: Vec<_> = desc_chain.clone().collect(); + self.print_console_frame(ctrl_msg); - log::trace!("descriptors.len(): {:?}", descriptors.len()); - if descriptors.len() < 1 { - warn!("Error::UnexpectedDescriptorCount"); - return Err(Error::UnexpectedDescriptorCount(descriptors.len())); - } + let mut buffer: Vec<u8> = Vec::new(); + buffer.extend_from_slice(&ctrl_msg.to_le_bytes()); - log::trace!("self.rx_fifo.size(): {}", self.rx_fifo.size()); - let ctrl_msg: VirtioConsoleControl = match self.rx_fifo.remove() { - Ok(item) => item, - _ => { - log::trace!("No rx elements"); - return Ok(false) - }, - }; - - let desc_request = descriptors[0]; - if !desc_request.is_write_only() { - warn!("Error::UnexpectedWriteOnlyDescriptor"); - return Err(Error::UnexpectedWriteOnlyDescriptor(0)); - } + if ctrl_msg.event.to_native() == VIRTIO_CONSOLE_PORT_NAME { + buffer.extend_from_slice(PORT_NAME); + }; - if (desc_request.len() as usize) < size_of::<VirtioConsoleControl>() { - log::trace!("UnexpectedDescriptorSize, len = {:?}", desc_request.len()); - return Err(Error::UnexpectedDescriptorSize( - size_of::<VirtioConsoleControl>(), - desc_request.len(), - )); - } + writer + .write(buffer.as_slice()) + .map_err(|_| Error::DescriptorWriteFailed)?; - log::trace!("desc_request.len(): {}", desc_request.len()); - self.print_console_frame(ctrl_msg); - - let mut buffer: Vec<u8> = Vec::new(); - buffer.extend_from_slice(&ctrl_msg.to_le_bytes()); - - if ctrl_msg.event.to_native() == VIRTIO_CONSOLE_PORT_NAME { - let string_bytes = "org.fedoraproject.console.foo!".as_bytes(); - buffer.extend_from_slice(string_bytes); - }; - - desc_chain - .memory() - .write_slice(&buffer, desc_request.addr()) - .map_err(|_| Error::DescriptorWriteFailed)?; - - if vring.add_used(desc_chain.head_index(), desc_request.len()).is_err() { - log::trace!("Couldn't return used descriptors to the ring"); - warn!("Couldn't return used descriptors to the ring"); - } + vring + .add_used(desc_chain.head_index(), writer.bytes_written() as u32) + .map_err(|_| Error::AddUsedElemFailed(CTRL_RX_QUEUE))?; } Ok(true) } - fn handle_control_msg ( - &mut self, - vring: &VringRwLock, - ctrl_msg: VirtioConsoleControl - ) -> Result<()> { - - let mut ctrl_msg_reply = VirtioConsoleControl { - id: 0.into(), - event: 0.into(), - value: 1.into(), - }; - match ctrl_msg.event.to_native() { - VIRTIO_CONSOLE_DEVICE_READY => { - log::trace!("VIRTIO_CONSOLE_DEVICE_READY"); - self.ready = true; - ctrl_msg_reply.event = VIRTIO_CONSOLE_PORT_ADD.into(); - self.rx_fifo.add(ctrl_msg_reply); - self.process_ctrl_rx_queue(vring)?; - }, - VIRTIO_CONSOLE_PORT_READY => { - log::trace!("VIRTIO_CONSOLE_PORT_READY"); - ctrl_msg_reply.event = VIRTIO_CONSOLE_CONSOLE_PORT.into(); - self.rx_fifo.add(ctrl_msg_reply.clone()); - self.process_ctrl_rx_queue(vring)?; - - ctrl_msg_reply.event = VIRTIO_CONSOLE_PORT_NAME.into(); - self.rx_fifo.add(ctrl_msg_reply.clone()); - self.process_ctrl_rx_queue(vring)?; - - ctrl_msg_reply.event = VIRTIO_CONSOLE_PORT_OPEN.into(); - self.rx_fifo.add(ctrl_msg_reply.clone()); - self.process_ctrl_rx_queue(vring)?; - }, - VIRTIO_CONSOLE_PORT_OPEN => { - log::trace!("VIRTIO_CONSOLE_PORT_OPEN"); - }, - _ => { - log::trace!("Uknown control event"); - return Err(Error::HandleEventUnknown); - } - }; - Ok(()) - } + fn handle_control_msg(&mut self, ctrl_msg: VirtioConsoleControl) -> Result<()> { + let mut ctrl_msg_reply = VirtioConsoleControl { + id: 0.into(), + event: 0.into(), + value: 1.into(), + }; + match ctrl_msg.event.to_native() { + VIRTIO_CONSOLE_DEVICE_READY => { + trace!("VIRTIO_CONSOLE_DEVICE_READY"); - fn process_ctrl_tx_requests( - &mut self, - requests: Vec<ConsoleDescriptorChain>, - vring: &VringRwLock, - rx_ctrl_vring: &VringRwLock - ) -> Result<bool> { - log::trace!("process_ctrl_tx_requests"); + if ctrl_msg.value != 1 { + trace!("Guest failure in adding device"); + return Ok(()); + } - if requests.is_empty() { - log::trace!("requests.is_empty()"); - return Ok(true); - } + self.ready = true; + ctrl_msg_reply.event = VIRTIO_CONSOLE_PORT_ADD.into(); + self.rx_ctrl_fifo + .add(ctrl_msg_reply) + .map_err(|_| Error::RxCtrlQueueAddFailed)?; + } + VIRTIO_CONSOLE_PORT_READY => { + trace!("VIRTIO_CONSOLE_PORT_READY"); - for desc_chain in requests { - let descriptors: Vec<_> = desc_chain.clone().collect(); + if ctrl_msg.value != 1 { + trace!("Guest failure in adding port for device"); + return Ok(()); + } - if descriptors.len() < 1 { - warn!("Error::UnexpectedDescriptorCount"); - return Err(Error::UnexpectedDescriptorCount(descriptors.len())); - } + ctrl_msg_reply.event = VIRTIO_CONSOLE_CONSOLE_PORT.into(); + self.rx_ctrl_fifo + .add(ctrl_msg_reply) + .map_err(|_| Error::RxCtrlQueueAddFailed)?; - log::trace!("descriptors.len(): {:?}", descriptors.len()); + ctrl_msg_reply.event = VIRTIO_CONSOLE_PORT_NAME.into(); + self.rx_ctrl_fifo + .add(ctrl_msg_reply) + .map_err(|_| Error::RxCtrlQueueAddFailed)?; - let desc_request = descriptors[0]; - if desc_request.is_write_only() { - log::trace!("This is write only"); - return Err(Error::UnexpectedWriteOnlyDescriptor(0)); - } else { - log::trace!("This is read only"); - } - - if desc_request.len() as usize != size_of::<VirtioConsoleControl>() { - log::trace!("UnexpectedDescriptorSize, len = {:?}", desc_request.len()); - return Err(Error::UnexpectedDescriptorSize( - size_of::<VirtioConsoleControl>(), - desc_request.len(), - )); + ctrl_msg_reply.event = VIRTIO_CONSOLE_PORT_OPEN.into(); + self.rx_ctrl_fifo + .add(ctrl_msg_reply) + .map_err(|_| Error::RxCtrlQueueAddFailed)?; + } + VIRTIO_CONSOLE_PORT_OPEN => { + trace!("VIRTIO_CONSOLE_PORT_OPEN"); + } + _ => { + trace!("Uknown control event"); + return Err(Error::HandleEventUnknown); } + }; + Ok(()) + } + + fn process_ctrl_tx_requests( + &mut self, + requests: Vec<ConsoleDescriptorChain>, + vring: &VringRwLock, + ) -> Result<bool> { + if requests.is_empty() { + return Ok(true); + } - log::trace!("desc_request.len: {}", desc_request.len()); + for desc_chain in requests { + let atomic_mem = self.mem.as_ref().unwrap().memory(); + let mut reader = desc_chain + .clone() + .reader(&atomic_mem) + .map_err(|_| Error::DescriptorReadFailed)?; - let mut request = desc_chain - .memory() - .read_obj::<VirtioConsoleControl>(desc_request.addr()) + let request = reader + .read_obj::<VirtioConsoleControl>() .map_err(|_| Error::DescriptorReadFailed)?; - self.print_console_frame(request); + // Print the receive console frame + self.print_console_frame(request); - self.handle_control_msg(rx_ctrl_vring, request); + // Process the received control frame + self.handle_control_msg(request)?; - if let Some(event_fd) = rx_ctrl_vring.get_ref().get_kick() { - self.rx_ctrl_event.write(1).unwrap(); - } else { - // Handle the case where `state` is `None`. - log::trace!("EventFd is not available."); - } + // trigger a kick to the CTRL_RT_QUEUE + self.rx_ctrl_event.write(1).unwrap(); - if vring.add_used(desc_chain.head_index(), desc_request.len()).is_err() { - log::trace!("Couldn't return used descriptors to the ring"); - warn!("Couldn't return used descriptors to the ring"); - } + vring + .add_used(desc_chain.head_index(), reader.bytes_read() as u32) + .map_err(|_| Error::AddUsedElemFailed(CTRL_TX_QUEUE))?; } Ok(true) @@ -467,7 +365,6 @@ impl VhostUserConsoleBackend { /// Process the messages in the vring and dispatch replies fn process_rx_queue(&mut self, vring: &VringRwLock) -> Result<()> { - log::trace!("process_rx_queue"); let requests: Vec<_> = vring .get_mut() .get_queue_mut() @@ -477,20 +374,15 @@ impl VhostUserConsoleBackend { if self.process_rx_requests(requests, vring)? { // Send notification once all the requests are processed - log::trace!("Send notification once all the requests of queue 0 are processed"); vring .signal_used_queue() - .map_err(|_| { - log::trace!("NotificationFailed"); - Error::NotificationFailed - })?; + .map_err(|_| Error::NotificationFailed)?; } - Ok(()) + Ok(()) } /// Process the messages in the vring and dispatch replies - fn process_tx_queue(&self, vring: &VringRwLock) -> Result<()> { - log::trace!("process_tx_queue"); + fn process_tx_queue(&mut self, vring: &VringRwLock) -> Result<()> { let requests: Vec<_> = vring .get_mut() .get_queue_mut() @@ -500,21 +392,15 @@ impl VhostUserConsoleBackend { if self.process_tx_requests(requests, vring)? { // Send notification once all the requests are processed - log::trace!("Send notification once all the requests of queue 1 are processed"); vring .signal_used_queue() - .map_err(|_| { - log::trace!("signal_used_queue error"); - Error::NotificationFailed - })?; + .map_err(|_| Error::NotificationFailed)?; } - Ok(()) } /// Process the messages in the vring and dispatch replies fn process_ctrl_rx_queue(&mut self, vring: &VringRwLock) -> Result<()> { - log::trace!("process_ctrl_rx_queue"); let requests: Vec<_> = vring .get_mut() .get_queue_mut() @@ -523,18 +409,16 @@ impl VhostUserConsoleBackend { .collect(); if self.process_ctrl_rx_requests(requests, vring)? { - log::trace!("Send notification once all the requests of queue 2 are processed"); // Send notification once all the requests are processed vring .signal_used_queue() .map_err(|_| Error::NotificationFailed)?; } - Ok(()) + Ok(()) } /// Process the messages in the vring and dispatch replies - fn process_ctrl_tx_queue(&mut self, vring: &VringRwLock, rx_ctrl_vring: &VringRwLock) -> Result<()> { - log::trace!("process_ctrl_tx_queue"); + fn process_ctrl_tx_queue(&mut self, vring: &VringRwLock) -> Result<()> { let requests: Vec<_> = vring .get_mut() .get_queue_mut() @@ -542,113 +426,257 @@ impl VhostUserConsoleBackend { .map_err(|_| Error::DescriptorNotFound)? .collect(); - if self.process_ctrl_tx_requests(requests, vring, rx_ctrl_vring)? { + if self.process_ctrl_tx_requests(requests, vring)? { // Send notification once all the requests are processed vring .signal_used_queue() .map_err(|_| Error::NotificationFailed)?; } - Ok(()) + Ok(()) } /// Set self's VringWorker. pub(crate) fn set_vring_worker( - &self, - vring_worker: &Arc<VringEpollHandler<Arc<RwLock<VhostUserConsoleBackend>>, VringRwLock, ()>>, + &self, + vring_worker: &Arc<VringEpollHandler<Arc<RwLock<VhostUserConsoleBackend>>>>, ) { - let rx_event_fd = self.rx_event.as_raw_fd(); - vring_worker - .register_listener( - rx_event_fd, - EventSet::IN, - u64::from(BACKEND_EFD)) + let rx_event_fd = self.rx_event.as_raw_fd(); + vring_worker + .register_listener(rx_event_fd, EventSet::IN, u64::from(BACKEND_RX_EFD)) .unwrap(); - let rx_ctrl_event_fd = self.rx_ctrl_event.as_raw_fd(); - vring_worker + let rx_ctrl_event_fd = self.rx_ctrl_event.as_raw_fd(); + vring_worker .register_listener( - rx_ctrl_event_fd, - EventSet::IN, - u64::from(BACKEND_RX_EFD)) + rx_ctrl_event_fd, + EventSet::IN, + u64::from(BACKEND_CTRL_RX_EFD), + ) .unwrap(); } + pub(crate) fn start_tcp_console_thread( + vhu_console: &Arc<RwLock<VhostUserConsoleBackend>>, + tcplisener_str: String, + ) -> JoinHandle<Result<()>> { + let vhu_console = Arc::clone(vhu_console); + spawn(move || { + loop { + let ready = vhu_console.read().unwrap().ready_to_write; + let exit = vhu_console.read().unwrap().controller.read().unwrap().exit; + + if exit { + trace!("Thread exits!"); + break; + } else if ready { + let listener = match TcpListener::bind(tcplisener_str.clone()) { + Ok(listener) => listener, + Err(e) => { + eprintln!("Failed to bind to {}: {}", tcplisener_str, e); + return Ok(()); + } + }; + listener.set_nonblocking(true).expect("Non-blocking error"); + + println!("Server listening on address: {}", tcplisener_str.clone()); + for stream in listener.incoming() { + match stream { + Ok(mut stream) => { + trace!("New connection"); + stream.set_nonblocking(true).expect("Non-blocking error"); + + let mut buffer = [0; 1024]; + loop { + let exit = + vhu_console.read().unwrap().controller.read().unwrap().exit; + if exit { + trace!("Thread exits!"); + return Ok(()); + } + // Write to the stream + if vhu_console.read().unwrap().output_queue.size() > 0 { + let byte_stream = vhu_console + .write() + .unwrap() + .output_queue + .remove() + .expect("Error removing element from output queue") + .into_bytes(); + if let Err(e) = stream.write_all(&byte_stream) { + eprintln!("Error writing to stream: {}", e); + } + } + match stream.read(&mut buffer) { + Ok(bytes_read) => { + if bytes_read == 0 { + println!("Close connection"); + break; + } + trace!( + "Received: {}", + String::from_utf8_lossy(&buffer[..bytes_read]) + ); + let input_buffer = + String::from_utf8_lossy(&buffer[..bytes_read]) + .to_string(); + vhu_console + .write() + .unwrap() + .rx_data_fifo + .add(input_buffer) + .unwrap(); + vhu_console.write().unwrap().rx_event.write(1).unwrap(); + } + Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => { + continue; + } + Err(ref e) + if e.kind() == io::ErrorKind::BrokenPipe + || e.kind() == io::ErrorKind::ConnectionReset => + { + trace!("Stream has been closed."); + break; + } + Err(e) => { + eprintln!("Error reading from socket: {}", e); + } + } + } + } + Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => { + let exit = + vhu_console.read().unwrap().controller.read().unwrap().exit; + if exit { + trace!("Thread exits!"); + return Ok(()); + } + continue; + } + Err(e) => { + eprintln!("Error accepting connection: {}", e); + break; + } + } + } + } + } + Ok(()) + }) + } + /// Start console thread. pub(crate) fn start_console_thread( - vhu_console: &Arc<RwLock<VhostUserConsoleBackend>>, - ) { + vhu_console: &Arc<RwLock<VhostUserConsoleBackend>>, + ) -> JoinHandle<Result<()>> { + let vhu_console = Arc::clone(vhu_console); + + let exit_eventfd = vhu_console.read().unwrap().exit_event.as_raw_fd(); + // Spawn a new thread to handle input. + spawn(move || { + let term = Term::stdout(); + let mut fdset = FdSet::new(); + fdset.insert(term.as_raw_fd()); + fdset.insert(exit_eventfd); + let max_fd = fdset.highest().expect("Failed to read fdset!") + 1; - let vhu_console = Arc::clone(&vhu_console); - print!("Enter text and press Enter: "); - - // Spawn a new thread to handle input. - spawn( move || { - loop { + loop { let ready = vhu_console.read().unwrap().ready_to_write; - if ready { - - let term = Term::stdout(); - let character = term.read_char().unwrap(); - log::trace!("You entered: {}", character); + let exit = vhu_console.read().unwrap().controller.read().unwrap().exit; - // Pass the data to vhu_console and trigger an EventFd - vhu_console.write().unwrap().output_buffer = character.to_string(); - vhu_console.write().unwrap().rx_event.write(1).unwrap(); + if exit { + trace!("Exit!"); + break; + } else if ready { + let mut fdset_clone = fdset; + enable_raw_mode().expect("Raw mode error"); + + match select(Some(max_fd), Some(&mut fdset_clone), None, None, None) { + Ok(_num_fds) => { + let exit = vhu_console.read().unwrap().controller.read().unwrap().exit; + if (fdset_clone.contains(exit_eventfd)) && exit { + trace!("Exit!"); + break; + } + + if fdset_clone.contains(term.as_raw_fd()) { + if let Some(character) = match term.read_key().unwrap() { + Key::Char(character) => Some(character), + Key::Enter => Some('\n'), + Key::Tab => Some('\t'), + Key::Backspace => Some('\u{8}'), + _ => None, + } { + // Pass the data to vhu_console and trigger an EventFd + let input_buffer = character.to_string(); + vhu_console + .write() + .unwrap() + .rx_data_fifo + .add(input_buffer) + .unwrap(); + vhu_console.write().unwrap().rx_event.write(1).unwrap(); + } + } + } + Err(e) => { + eprintln!("Error in select: {}", e); + break; + } + } } - } - }); + } + + disable_raw_mode().expect("Raw mode error"); + Ok(()) + }) + } + pub fn kill_console_thread(&self) { + trace!("Kill thread"); + self.controller.write().unwrap().exit = true; + self.exit_event.write(1).unwrap(); } } /// VhostUserBackendMut trait methods -impl VhostUserBackendMut<VringRwLock, ()> - for VhostUserConsoleBackend -{ +impl VhostUserBackendMut for VhostUserConsoleBackend { + type Vring = VringRwLock; + type Bitmap = (); + fn num_queues(&self) -> usize { - log::trace!("num_queues: {:?}", NUM_QUEUES); NUM_QUEUES } fn max_queue_size(&self) -> usize { - log::trace!("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_VERSION_1 | 1 << VIRTIO_F_NOTIFY_ON_EMPTY | 1 << VIRTIO_RING_F_EVENT_IDX - | 1 << VIRTIO_CONSOLE_F_EMERG_WRITE | 1 << VIRTIO_RING_F_INDIRECT_DESC - | 1 << VIRTIO_CONSOLE_F_MULTIPORT // This could be disabled - | VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits(); - - log::trace!("vhu_can->features: {:x}", features); - features + | 1 << VIRTIO_CONSOLE_F_MULTIPORT + | VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits() } - fn acked_features(&mut self, _features: u64) { - log::trace!("\nacked_features: 0x{:x}\n", _features); - self.acked_features = _features; - } + fn acked_features(&mut self, features: u64) { + self.acked_features = features; + } fn protocol_features(&self) -> VhostUserProtocolFeatures { - let protocol_features = VhostUserProtocolFeatures::MQ + VhostUserProtocolFeatures::MQ | VhostUserProtocolFeatures::CONFIG - | VhostUserProtocolFeatures::REPLY_ACK; - - log::trace!("protocol_features: {:x}", protocol_features); - protocol_features + | VhostUserProtocolFeatures::REPLY_ACK } 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. - log::trace!("vhu_can->get_config"); unsafe { from_raw_parts( - self.controller.write().unwrap() + self.controller + .write() + .unwrap() .config() .as_slice() .as_ptr() @@ -660,11 +688,10 @@ impl VhostUserBackendMut<VringRwLock, ()> } fn set_event_idx(&mut self, enabled: bool) { - dbg!(self.event_idx = enabled); + self.event_idx = enabled; } fn update_memory(&mut self, mem: GuestMemoryAtomic<GuestMemoryMmap>) -> IoResult<()> { - log::trace!("update_memory\n"); self.mem = Some(mem); Ok(()) } @@ -672,93 +699,81 @@ impl VhostUserBackendMut<VringRwLock, ()> fn handle_event( &mut self, device_event: u16, - evset: EventSet, + _evset: EventSet, vrings: &[VringRwLock], _thread_id: usize, - ) -> IoResult<bool> { - log::trace!("\nhandle_event:"); - - if device_event == RX_QUEUE { - log::trace!("RX_QUEUE\n"); - return Ok(false); - }; - - if device_event == CTRL_RX_QUEUE { - log::trace!("CTRL_RX_QUEUE\n"); - if !self.ready { - return Ok(false); - } - }; - - let vring = if device_event == BACKEND_EFD { - log::trace!("BACKEND_EFD\n"); - &vrings[RX_QUEUE as usize] - } else if device_event == BACKEND_RX_EFD { - log::trace!("BACKEND_RX_EFD\n"); - &vrings[CTRL_RX_QUEUE as usize] - } else { - &vrings[device_event as usize] - }; + ) -> IoResult<()> { + if device_event == RX_QUEUE { + // Check if there are any available data + if self.rx_data_fifo.size() == 0 { + return Ok(()); + } + }; + + if device_event == CTRL_RX_QUEUE { + // Check if there are any available data and the device is ready + if (!self.ready) || (self.rx_ctrl_fifo.size() == 0) { + return Ok(()); + } + }; + + let vring = if device_event == BACKEND_RX_EFD { + &vrings[RX_QUEUE as usize] + } else if device_event == BACKEND_CTRL_RX_EFD { + &vrings[CTRL_RX_QUEUE as usize] + } else { + &vrings[device_event 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 device_event { + RX_QUEUE => self.process_rx_queue(vring), TX_QUEUE => { - self.ready_to_write = true; + self.ready_to_write = true; self.process_tx_queue(vring) - }, + } CTRL_RX_QUEUE => self.process_ctrl_rx_queue(vring), - CTRL_TX_QUEUE => { - let rx_ctrl_vring = &vrings[CTRL_RX_QUEUE as usize]; - self.process_ctrl_tx_queue(vring, rx_ctrl_vring) - }, - BACKEND_EFD => { - let _ = self.rx_event.read(); - self.process_rx_queue(vring) - }, + CTRL_TX_QUEUE => self.process_ctrl_tx_queue(vring), BACKEND_RX_EFD => { - let _ = self.rx_ctrl_event.read(); - self.process_ctrl_rx_queue(vring) - }, - _ => Err(Error::HandleEventUnknown.into()), + let _ = self.rx_event.read(); + self.process_rx_queue(vring) + } + BACKEND_CTRL_RX_EFD => { + let _ = self.rx_ctrl_event.read(); + self.process_ctrl_rx_queue(vring) + } + _ => Err(Error::HandleEventUnknown), }?; if !vring.enable_notification().unwrap() { break; } } - } else { - // Without EVENT_IDX, a single call is enough. + } else { match device_event { + RX_QUEUE => self.process_rx_queue(vring), TX_QUEUE => { - self.ready_to_write = true; + self.ready_to_write = true; self.process_tx_queue(vring) - }, + } CTRL_RX_QUEUE => self.process_ctrl_rx_queue(vring), - CTRL_TX_QUEUE => { - let rx_ctrl_vring = &vrings[CTRL_RX_QUEUE as usize]; - self.process_ctrl_tx_queue(vring, rx_ctrl_vring) - }, - BACKEND_EFD => { - let _ = self.rx_event.read(); - self.process_rx_queue(vring) - }, + CTRL_TX_QUEUE => self.process_ctrl_tx_queue(vring), BACKEND_RX_EFD => { - let _ = self.rx_ctrl_event.read(); - self.process_ctrl_rx_queue(vring) - }, - _ => Err(Error::HandleEventUnknown.into()), + let _ = self.rx_event.read(); + self.process_rx_queue(vring) + } + BACKEND_CTRL_RX_EFD => { + let _ = self.rx_ctrl_event.read(); + self.process_ctrl_rx_queue(vring) + } + _ => Err(Error::HandleEventUnknown), }?; } - Ok(false) + Ok(()) } fn exit_event(&self, _thread_index: usize) -> Option<EventFd> { - dbg!("exit_event\n"); self.exit_event.try_clone().ok() } } @@ -766,29 +781,503 @@ impl VhostUserBackendMut<VringRwLock, ()> #[cfg(test)] mod tests { use super::*; + use virtio_bindings::virtio_ring::{VRING_DESC_F_NEXT, VRING_DESC_F_WRITE}; + use virtio_queue::{mock::MockSplitQueue, Descriptor, Queue}; + use vm_memory::{Bytes, GuestAddress, GuestMemoryAtomic, GuestMemoryMmap}; + + #[test] + fn test_vhost_user_console_backend_creation() { + let console_controller = Arc::new(RwLock::new(ConsoleController::new(BackendType::Nested))); + let vhost_user_console_backend = VhostUserConsoleBackend::new(console_controller) + .expect("Failed create vhuconsole backend"); + + assert_eq!(vhost_user_console_backend.acked_features, 0); + assert!(!vhost_user_console_backend.event_idx); + assert!(!vhost_user_console_backend.ready); + assert!(!vhost_user_console_backend.ready_to_write); + } + + #[test] + fn test_virtio_console_empty_handle_request() { + let console_controller = Arc::new(RwLock::new(ConsoleController::new(BackendType::Nested))); + let mut vu_console_backend = VhostUserConsoleBackend::new(console_controller) + .expect("Failed create vhuconsole backend"); + + // Artificial memory + let mem = GuestMemoryAtomic::new( + GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x1000)]).unwrap(), + ); + + // Update memory + vu_console_backend.update_memory(mem.clone()).unwrap(); + + // Artificial Vring + let vring = VringRwLock::new(mem, 0x1000).unwrap(); + vring.set_queue_info(0x100, 0x200, 0x300).unwrap(); + vring.set_queue_ready(true); + let list_vrings = [vring.clone(), vring.clone(), vring.clone(), vring.clone()]; + + vu_console_backend + .handle_event(RX_QUEUE, EventSet::IN, &list_vrings, 0) + .unwrap(); + + vu_console_backend + .handle_event(TX_QUEUE, EventSet::IN, &list_vrings, 0) + .unwrap(); + + vu_console_backend + .handle_event(CTRL_RX_QUEUE, EventSet::IN, &list_vrings, 0) + .unwrap(); + + vu_console_backend + .handle_event(CTRL_TX_QUEUE, EventSet::IN, &list_vrings, 0) + .unwrap(); + + vu_console_backend + .handle_event(BACKEND_RX_EFD, EventSet::IN, &list_vrings, 0) + .unwrap(); + + vu_console_backend + .handle_event(BACKEND_CTRL_RX_EFD, EventSet::IN, &list_vrings, 0) + .unwrap(); + } + + #[test] + fn test_virtio_console_empty_requests() { + let console_controller = Arc::new(RwLock::new(ConsoleController::new(BackendType::Nested))); + let mut vu_console_backend = VhostUserConsoleBackend::new(console_controller) + .expect("Failed create vhuconsole backend"); + + // Artificial memory + let mem = GuestMemoryAtomic::new( + GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x1000)]).unwrap(), + ); + + // Artificial Vring + let vring = VringRwLock::new(mem.clone(), 0x1000).unwrap(); + + // Empty descriptor chain should be ignored + assert!(vu_console_backend + .process_rx_requests(Vec::<ConsoleDescriptorChain>::new(), &vring) + .is_ok()); + assert!(vu_console_backend + .process_tx_requests(Vec::<ConsoleDescriptorChain>::new(), &vring) + .is_ok()); + assert!(vu_console_backend + .process_ctrl_rx_requests(Vec::<ConsoleDescriptorChain>::new(), &vring) + .is_ok()); + assert!(vu_console_backend + .process_ctrl_tx_requests(Vec::<ConsoleDescriptorChain>::new(), &vring) + .is_ok()); + } + + fn build_desc_chain( + mem: &GuestMemoryMmap, + count: u16, + flags: Vec<u16>, + len: u32, + ) -> ConsoleDescriptorChain { + let vq = MockSplitQueue::new(mem, 16); + let mut desc_vec = Vec::new(); + + //Create a descriptor chain with @count descriptors. + for i in 0..count { + let desc_flags = if i < count - 1 { + flags[i as usize] | VRING_DESC_F_NEXT as u16 + } else { + flags[i as usize] & !VRING_DESC_F_NEXT as u16 + }; + + let desc = Descriptor::new((0x100 * (i + 1)) as u64, len, desc_flags, i + 1); + desc_vec.push(desc); + } + + vq.add_desc_chains(&desc_vec, 0).unwrap(); + + // Create descriptor chain from pre-filled memory + vq.create_queue::<Queue>() + .unwrap() + .iter(GuestMemoryAtomic::new(mem.clone()).memory()) + .unwrap() + .next() + .unwrap() + } #[test] - fn test_virtio_console_control_byte_valued() { - let control = VirtioConsoleControl { - id: Le32::from(1), - event: Le16::from(2), - value: Le16::from(3), + fn test_virtio_console_ctrl_rx_request() { + let console_controller = Arc::new(RwLock::new(ConsoleController::new(BackendType::Nested))); + let mut vu_console_backend = VhostUserConsoleBackend::new(console_controller) + .expect("Failed create vhuconsole backend"); + + // Artificial memory + let mem = GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x1000)]).unwrap(); + + // Test 1: Empty queue + let mem1 = GuestMemoryAtomic::new(mem.clone()); + let vring = VringRwLock::new(mem1.clone(), 0x1000).unwrap(); + assert!(vu_console_backend + .process_ctrl_rx_requests(vec![], &vring) + .unwrap()); + + // Test 2: Found no rx elements + let desc_chain = build_desc_chain(&mem, 1, vec![0], 0x200); + let mem1 = GuestMemoryAtomic::new(mem.clone()); + let vring = VringRwLock::new(mem1.clone(), 0x1000).unwrap(); + vu_console_backend.update_memory(mem1).unwrap(); + + assert!(!vu_console_backend + .process_ctrl_rx_requests(vec![desc_chain], &vring) + .unwrap()); + + // Test 3: empty queue + let desc_chain = build_desc_chain(&mem, 1, vec![VRING_DESC_F_WRITE as u16], 0x200); + let mem1 = GuestMemoryAtomic::new(mem.clone()); + let vring = VringRwLock::new(mem1.clone(), 0x1000).unwrap(); + vu_console_backend.update_memory(mem1).unwrap(); + assert!(!vu_console_backend + .process_ctrl_rx_requests(vec![desc_chain.clone()], &vring) + .unwrap()); + + // Test 4: the written desc reply + let ctrl_msg = VirtioConsoleControl { + id: 0.into(), + event: VIRTIO_CONSOLE_PORT_ADD.into(), + value: 1.into(), }; + let _ = vu_console_backend.rx_ctrl_fifo.add(ctrl_msg); - let bytes = control.to_le_bytes(); + assert!(vu_console_backend + .process_ctrl_rx_requests(vec![desc_chain.clone()], &vring) + .unwrap()); - assert_eq!(bytes.len(), 10); + let ctrl_msg_reply = desc_chain + .memory() + .read_obj::<VirtioConsoleControl>(vm_memory::GuestAddress(0x100_u64)) + .map_err(|_| Error::DescriptorReadFailed) + .unwrap(); + + assert_eq!(ctrl_msg.id, ctrl_msg_reply.id); + assert_eq!(ctrl_msg.event, ctrl_msg_reply.event); + assert_eq!(ctrl_msg.value, ctrl_msg_reply.value); + + // Test 5: if message is VIRTIO_CONSOLE_PORT_NAME + let desc_chain = build_desc_chain(&mem, 1, vec![VRING_DESC_F_WRITE as u16], 0x200); + let mem1 = GuestMemoryAtomic::new(mem.clone()); + let vring = VringRwLock::new(mem1.clone(), 0x1000).unwrap(); + vu_console_backend.update_memory(mem1).unwrap(); + + let ctrl_msg = VirtioConsoleControl { + id: 0.into(), + event: VIRTIO_CONSOLE_PORT_NAME.into(), + value: 1.into(), + }; + let _ = vu_console_backend.rx_ctrl_fifo.add(ctrl_msg); + + assert!(vu_console_backend + .process_ctrl_rx_requests(vec![desc_chain.clone()], &vring) + .unwrap()); } #[test] - fn test_vhost_user_console_backend_creation() { - let console_controller = Arc::new(RwLock::new(ConsoleController::new(String::from("test_console")).unwrap())); - let vhost_user_console_backend = VhostUserConsoleBackend::new(console_controller).unwrap(); + fn test_virtio_console_ctrl_tx_request() { + let console_controller = Arc::new(RwLock::new(ConsoleController::new(BackendType::Nested))); + let mut vu_console_backend = VhostUserConsoleBackend::new(console_controller) + .expect("Failed create vhuconsole backend"); + + // Artificial memory + let mem = GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x1000)]).unwrap(); + + // Test 1: Empty queue + let mem1 = GuestMemoryAtomic::new(mem.clone()); + let vring = VringRwLock::new(mem1.clone(), 0x1000).unwrap(); + assert!(vu_console_backend + .process_ctrl_tx_requests(vec![], &vring) + .unwrap()); + + // Test 2: Found no descriptors + let desc_chain = build_desc_chain(&mem, 1, vec![VRING_DESC_F_WRITE as u16], 0x200); + let mem1 = GuestMemoryAtomic::new(mem.clone()); + let vring = VringRwLock::new(mem1.clone(), 0x1000).unwrap(); + vu_console_backend.update_memory(mem1).unwrap(); + + assert_eq!( + vu_console_backend + .process_ctrl_tx_requests(vec![desc_chain], &vring) + .unwrap_err(), + Error::DescriptorReadFailed + ); + + // Test 3: Smaller descriptor len than a console ctrl message + let desc_chain = build_desc_chain(&mem, 1, vec![0], 0x2); + let mem1 = GuestMemoryAtomic::new(mem.clone()); + let vring = VringRwLock::new(mem1.clone(), 0x1000).unwrap(); + vu_console_backend.update_memory(mem1).unwrap(); + assert_eq!( + vu_console_backend + .process_ctrl_tx_requests(vec![desc_chain.clone()], &vring) + .unwrap_err(), + Error::DescriptorReadFailed + ); + + // Test 4: Complete function successfully -- VIRTIO_CONSOLE_PORT_READY message + let desc_chain = build_desc_chain(&mem, 1, vec![0], 0x8); + let mem1 = GuestMemoryAtomic::new(mem.clone()); + let vring = VringRwLock::new(mem1.clone(), 0x1000).unwrap(); + vu_console_backend.update_memory(mem1).unwrap(); + assert!(vu_console_backend + .process_ctrl_tx_requests(vec![desc_chain.clone()], &vring) + .unwrap()); + } - assert_eq!(vhost_user_console_backend.acked_features, 0); - assert_eq!(vhost_user_console_backend.event_idx, false); - assert_eq!(vhost_user_console_backend.ready, false); - assert_eq!(vhost_user_console_backend.ready_to_write, false); - assert_eq!(vhost_user_console_backend.output_buffer, String::new()); + #[test] + fn test_virtio_console_handle_control_msg() { + let console_controller = Arc::new(RwLock::new(ConsoleController::new(BackendType::Nested))); + let mut vu_console_backend = VhostUserConsoleBackend::new(console_controller) + .expect("Failed create vhuconsole backend"); + + // Artificial memory & update device's memory + let mem = GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x1000)]).unwrap(); + let mem_1 = GuestMemoryAtomic::new(mem.clone()); + vu_console_backend.update_memory(mem_1.clone()).unwrap(); + + // Test 1: Empty queue + let ctrl_msg_1 = VirtioConsoleControl { + id: 0.into(), + event: VIRTIO_CONSOLE_DEVICE_READY.into(), + value: 1.into(), + }; + + let ctrl_msg_2 = VirtioConsoleControl { + id: 0.into(), + event: VIRTIO_CONSOLE_PORT_READY.into(), + value: 1.into(), + }; + + let ctrl_msg_3 = VirtioConsoleControl { + id: 0.into(), + event: VIRTIO_CONSOLE_PORT_OPEN.into(), + value: 1.into(), + }; + + let ctrl_msg_err = VirtioConsoleControl { + id: 0.into(), + event: 4.into(), + value: 1.into(), + }; + + assert!(vu_console_backend.handle_control_msg(ctrl_msg_3).is_ok()); + + assert_eq!( + vu_console_backend + .handle_control_msg(ctrl_msg_err) + .unwrap_err(), + Error::HandleEventUnknown + ); + + assert!(vu_console_backend.handle_control_msg(ctrl_msg_1).is_ok()); + + // Update memory + let mem_1 = GuestMemoryAtomic::new(mem.clone()); + vu_console_backend.update_memory(mem_1.clone()).unwrap(); + + assert!(vu_console_backend.handle_control_msg(ctrl_msg_2).is_ok()); + } + + #[test] + fn test_virtio_console_tx_request() { + let console_controller = Arc::new(RwLock::new(ConsoleController::new(BackendType::Nested))); + let mut vu_console_backend = VhostUserConsoleBackend::new(console_controller) + .expect("Failed create vhuconsole backend"); + + // Artificial memory + let mem = GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x1000)]).unwrap(); + + // Test 1: Empty queue + let mem1 = GuestMemoryAtomic::new(mem.clone()); + let vring = VringRwLock::new(mem1, 0x1000).unwrap(); + assert!(vu_console_backend + .process_tx_requests(vec![], &vring) + .is_ok()); + + // Test 2: Empty buffer + let desc_chain = build_desc_chain(&mem, 1, vec![0], 0x200); + let mem1 = GuestMemoryAtomic::new(mem.clone()); + let vring = VringRwLock::new(mem1.clone(), 0x1000).unwrap(); + vu_console_backend.update_memory(mem1).unwrap(); + assert!(vu_console_backend + .process_tx_requests(vec![desc_chain], &vring) + .is_ok()); + + // Test 3: Fill message to the buffer + let desc_chain = build_desc_chain(&mem, 1, vec![0], 0x200); + let desc_addr = desc_chain.clone().collect::<Vec<_>>()[0].addr(); + + // Build the Vec with the desired string + let mut buffer: Vec<u8> = Vec::new(); + let string_bytes = "Hello!".as_bytes(); + buffer.extend_from_slice(string_bytes); + + // Write a new buffer into the desc_chain + desc_chain.memory().write_slice(&buffer, desc_addr).unwrap(); + + // Verify that it is written + let mut read_buffer: Vec<u8> = vec![0; 0x200]; + desc_chain + .memory() + .read_slice(&mut read_buffer, desc_addr) + .expect("Failed to read"); + let read_buffer: Vec<u8> = read_buffer.iter().take(buffer.len()).copied().collect(); + + assert_eq!( + String::from_utf8(read_buffer).unwrap(), + String::from_utf8(buffer).unwrap() + ); + + assert!(vu_console_backend + .process_tx_requests(vec![desc_chain], &vring) + .is_ok()); + } + + #[test] + fn test_virtio_console_tx_request_network() { + let console_controller = + Arc::new(RwLock::new(ConsoleController::new(BackendType::Network))); + let mut vu_console_backend = VhostUserConsoleBackend::new(console_controller) + .expect("Failed create vhuconsole backend"); + + // Artificial memory + let mem = GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x1000)]).unwrap(); + let desc_chain = build_desc_chain(&mem, 1, vec![0], 0x200); + let mem1 = GuestMemoryAtomic::new(mem.clone()); + let vring = VringRwLock::new(mem1.clone(), 0x1000).unwrap(); + + // Test: Fill message to the buffer + vu_console_backend.update_memory(mem1).unwrap(); + let desc_addr = desc_chain.clone().collect::<Vec<_>>()[0].addr(); + + // Build the Vec with the desired string + let mut buffer: Vec<u8> = Vec::new(); + let string_bytes = "Hello!".as_bytes(); + buffer.extend_from_slice(string_bytes); + + // Write a new buffer into the desc_chain + desc_chain.memory().write_slice(&buffer, desc_addr).unwrap(); + + // Verify that it is written + let mut read_buffer: Vec<u8> = vec![0; 0x200]; + desc_chain + .memory() + .read_slice(&mut read_buffer, desc_addr) + .expect("Failed to read"); + let read_buffer: Vec<u8> = read_buffer.iter().take(buffer.len()).copied().collect(); + + assert_eq!( + String::from_utf8(read_buffer).unwrap(), + String::from_utf8(buffer).unwrap() + ); + + assert!(vu_console_backend + .process_tx_requests(vec![desc_chain], &vring) + .is_ok()); + } + + #[test] + fn test_virtio_console_rx_request() { + let console_controller = Arc::new(RwLock::new(ConsoleController::new(BackendType::Nested))); + let mut vu_console_backend = VhostUserConsoleBackend::new(console_controller) + .expect("Failed create vhuconsole backend"); + + // Artificial memory + let mem = GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x1000)]).unwrap(); + + // Test 1: Empty queue + let mem1 = GuestMemoryAtomic::new(mem.clone()); + let vring = VringRwLock::new(mem1, 0x1000).unwrap(); + assert!(vu_console_backend + .process_rx_requests(vec![], &vring) + .is_ok()); + + // Test 2: Empty buffer + let desc_chain = build_desc_chain(&mem, 1, vec![0], 0x200); + let mem1 = GuestMemoryAtomic::new(mem.clone()); + let vring = VringRwLock::new(mem1.clone(), 0x1000).unwrap(); + vu_console_backend.update_memory(mem1).unwrap(); + assert!(!vu_console_backend + .process_rx_requests(vec![desc_chain], &vring) + .unwrap()); + + // Test 3: Fill message to the buffer. The descriptor should be write-only + let desc_chain = build_desc_chain(&mem, 1, vec![0], 0x200); + let mem1 = GuestMemoryAtomic::new(mem.clone()); + let vring = VringRwLock::new(mem1.clone(), 0x1000).unwrap(); + vu_console_backend.update_memory(mem1).unwrap(); + + let input_buffer = "Hello!".to_string(); + let _ = vu_console_backend.rx_data_fifo.add(input_buffer.clone()); + assert_eq!( + vu_console_backend + .process_rx_requests(vec![desc_chain], &vring) + .unwrap_err(), + Error::DescriptorWriteFailed + ); + + // Test 4: Fill message to the buffer. Everything should work! + let desc_chain = build_desc_chain(&mem, 1, vec![VRING_DESC_F_WRITE as u16], 0x200); + let mem1 = GuestMemoryAtomic::new(mem.clone()); + let vring = VringRwLock::new(mem1.clone(), 0x1000).unwrap(); + vu_console_backend.update_memory(mem1).unwrap(); + + let input_buffer = "Hello!".to_string(); + let _ = vu_console_backend.rx_data_fifo.add(input_buffer.clone()); + assert!(vu_console_backend + .process_rx_requests(vec![desc_chain.clone()], &vring) + .unwrap()); + + // Test 5: Verify written data + let desc_addr = GuestAddress(0x100); + let mut read_buffer: Vec<u8> = vec![0; 0x100]; + desc_chain + .memory() + .read_slice(&mut read_buffer, desc_addr) + .expect("Failed to read"); + + let read_buffer: Vec<u8> = read_buffer + .iter() + .take(input_buffer.len()) + .copied() + .collect(); + + assert_eq!(String::from_utf8(read_buffer).unwrap(), input_buffer); + } + + #[test] + fn test_virtio_console_start_tcp_console_thread() { + let console_controller = Arc::new(RwLock::new(ConsoleController::new(BackendType::Nested))); + let vu_console_backend = Arc::new(RwLock::new( + VhostUserConsoleBackend::new(console_controller) + .expect("Failed create vhuconsole backend"), + )); + let tcp_addr = "127.0.0.1:12345".to_string(); + + let read_handle = VhostUserConsoleBackend::start_tcp_console_thread( + &vu_console_backend, + tcp_addr.clone(), + ); + vu_console_backend.read().unwrap().kill_console_thread(); + assert!(read_handle.join().is_ok()); + } + + #[test] + fn test_virtio_console_start_nested_console_thread() { + let console_controller = Arc::new(RwLock::new(ConsoleController::new(BackendType::Nested))); + let vu_console_backend = Arc::new(RwLock::new( + VhostUserConsoleBackend::new(console_controller) + .expect("Failed create vhuconsole backend"), + )); + + let read_handle = VhostUserConsoleBackend::start_console_thread(&vu_console_backend); + + vu_console_backend.read().unwrap().kill_console_thread(); + assert!(read_handle.join().is_ok()); } } diff --git a/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-0.1.0/src/virtio_console.rs b/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-0.1.0/src/virtio_console.rs new file mode 100755 index 00000000..323473f6 --- /dev/null +++ b/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-0.1.0/src/virtio_console.rs @@ -0,0 +1,60 @@ +// Console virtio bindings +// +// Copyright 2023-2024 VIRTUAL OPEN SYSTEMS SAS. All Rights Reserved. +// Timos Ampelikiotis <t.ampelikiotis@virtualopensystems.com> +// +// SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause + +use vm_memory::{ByteValued, Le16, Le32}; + +/// Feature bit numbers +#[allow(dead_code)] +pub const VIRTIO_CONSOLE_F_SIZE: u16 = 0; +pub const VIRTIO_CONSOLE_F_MULTIPORT: u16 = 1; +#[allow(dead_code)] +pub const VIRTIO_CONSOLE_F_EMERG_WRITE: u16 = 2; + +/// Console virtio control messages +pub const VIRTIO_CONSOLE_DEVICE_READY: u16 = 0; +pub const VIRTIO_CONSOLE_PORT_ADD: u16 = 1; +#[allow(dead_code)] +pub const VIRTIO_CONSOLE_PORT_REMOVE: u16 = 2; +pub const VIRTIO_CONSOLE_PORT_READY: u16 = 3; +pub const VIRTIO_CONSOLE_CONSOLE_PORT: u16 = 4; +#[allow(dead_code)] +pub const VIRTIO_CONSOLE_RESIZE: u16 = 5; +pub const VIRTIO_CONSOLE_PORT_OPEN: u16 = 6; +pub const VIRTIO_CONSOLE_PORT_NAME: u16 = 7; + +/// Virtio Console Config +#[derive(Copy, Clone, Debug, Default, PartialEq)] +#[repr(C)] +pub(crate) struct VirtioConsoleConfig { + pub cols: Le16, + pub rows: Le16, + pub max_nr_ports: Le32, + pub emerg_wr: Le32, +} + +// SAFETY: The layout of the structure is fixed and can be initialized by +// reading its content from byte array. +unsafe impl ByteValued for VirtioConsoleConfig {} + +#[derive(Copy, Clone, Debug, Default, PartialEq)] +#[repr(C)] +pub(crate) struct VirtioConsoleControl { + pub id: Le32, + pub event: Le16, + pub value: Le16, +} + +impl VirtioConsoleControl { + pub fn to_le_bytes(self) -> Vec<u8> { + let mut buffer = Vec::new(); + + buffer.extend_from_slice(&self.id.to_native().to_le_bytes()); + buffer.extend_from_slice(&self.event.to_native().to_le_bytes()); + buffer.extend_from_slice(&self.value.to_native().to_le_bytes()); + buffer + } +} diff --git a/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-crates.inc b/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-crates.inc index 6026714e..df6d2ae1 100644 --- a/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-crates.inc +++ b/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console-crates.inc @@ -1,87 +1,292 @@ +# Autogenerated with 'bitbake -c update_crates vhost-device-console' + +# from Cargo.lock SRC_URI += " \ - crate://crates.io/encode_unicode/0.3.6 \ - crate://crates.io/unicode-width/0.1.11 \ - crate://crates.io/console/0.14.1 \ - crate://crates.io/lazy_static/1.4.0 \ - crate://crates.io/serde_derive/1.0.193 \ - crate://crates.io/autocfg/1.1.0 \ - crate://crates.io/syn/1.0.109 \ - crate://crates.io/serde/1.0.193 \ - crate://crates.io/memoffset/0.7.0 \ - crate://crates.io/static_assertions/1.1.0 \ - crate://crates.io/pin-utils/0.1.0 \ - crate://crates.io/cfg-if/1.0.0 \ - crate://crates.io/neli-proc-macros/0.1.3 \ - crate://crates.io/byteorder/1.5.0 \ - crate://crates.io/either/1.9.0 \ - crate://crates.io/nix/0.26.0 \ - crate://crates.io/neli/0.6.4 \ - crate://crates.io/nb/1.1.0 \ - crate://crates.io/itertools/0.10.0 \ - crate://crates.io/hex/0.4.3 \ - crate://crates.io/embedded-can/0.4.1 \ - crate://crates.io/byte_conv/0.1.1 \ - crate://crates.io/queues/1.1.0 \ - crate://crates.io/socketcan/3.3.0 \ - crate://crates.io/aho-corasick/1.0.2 \ - crate://crates.io/anstream/0.3.2 \ - crate://crates.io/anstyle/1.0.1 \ - crate://crates.io/anstyle-parse/0.2.1 \ - crate://crates.io/anstyle-query/1.0.0 \ - crate://crates.io/anstyle-wincon/1.0.1 \ - crate://crates.io/arc-swap/1.6.0 \ + crate://crates.io/aho-corasick/1.1.3 \ + crate://crates.io/anstream/0.6.15 \ + crate://crates.io/anstyle/1.0.8 \ + crate://crates.io/anstyle-parse/0.2.5 \ + crate://crates.io/anstyle-query/1.1.1 \ + crate://crates.io/anstyle-wincon/3.0.4 \ + crate://crates.io/anyhow/1.0.87 \ + crate://crates.io/arc-swap/1.7.1 \ crate://crates.io/assert_matches/1.5.0 \ + crate://crates.io/autocfg/1.3.0 \ crate://crates.io/bitflags/1.3.2 \ - crate://crates.io/bitflags/2.3.3 \ - crate://crates.io/cc/1.0.79 \ - crate://crates.io/clap/4.2.5 \ - crate://crates.io/clap_builder/4.2.5 \ - crate://crates.io/clap_derive/4.2.0 \ - crate://crates.io/clap_lex/0.4.0 \ - crate://crates.io/colorchoice/1.0.0 \ - crate://crates.io/env_logger/0.10.0 \ - crate://crates.io/errno/0.3.1 \ - crate://crates.io/errno-dragonfly/0.1.2 \ - crate://crates.io/heck/0.4.1 \ - crate://crates.io/hermit-abi/0.3.2 \ + crate://crates.io/bitflags/2.6.0 \ + crate://crates.io/byte_conv/0.1.1 \ + crate://crates.io/byteorder/1.5.0 \ + crate://crates.io/cfg-if/1.0.0 \ + crate://crates.io/clap/4.5.17 \ + crate://crates.io/clap_builder/4.5.17 \ + crate://crates.io/clap_derive/4.5.13 \ + crate://crates.io/clap_lex/0.7.2 \ + crate://crates.io/colorchoice/1.0.2 \ + crate://crates.io/console/0.15.8 \ + crate://crates.io/crossterm/0.27.0 \ + crate://crates.io/crossterm_winapi/0.9.1 \ + crate://crates.io/either/1.13.0 \ + crate://crates.io/embedded-can/0.4.1 \ + crate://crates.io/encode_unicode/0.3.6 \ + crate://crates.io/enumn/0.1.14 \ + crate://crates.io/env_filter/0.1.2 \ + crate://crates.io/env_logger/0.10.2 \ + crate://crates.io/env_logger/0.11.5 \ + crate://crates.io/epoll/4.3.3 \ + crate://crates.io/equivalent/1.0.1 \ + crate://crates.io/errno/0.3.9 \ + crate://crates.io/fastrand/2.1.1 \ + crate://crates.io/futures/0.3.30 \ + crate://crates.io/futures-channel/0.3.30 \ + crate://crates.io/futures-core/0.3.30 \ + crate://crates.io/futures-executor/0.3.30 \ + crate://crates.io/futures-io/0.3.30 \ + crate://crates.io/futures-macro/0.3.30 \ + crate://crates.io/futures-sink/0.3.30 \ + crate://crates.io/futures-task/0.3.30 \ + crate://crates.io/futures-timer/3.0.3 \ + crate://crates.io/futures-util/0.3.30 \ + crate://crates.io/glob/0.3.1 \ + crate://crates.io/hashbrown/0.14.5 \ + crate://crates.io/heck/0.5.0 \ + crate://crates.io/hermit-abi/0.3.9 \ + crate://crates.io/hermit-abi/0.4.0 \ + crate://crates.io/hex/0.4.3 \ crate://crates.io/humantime/2.1.0 \ - crate://crates.io/is-terminal/0.4.9 \ - crate://crates.io/libc/0.2.147 \ - crate://crates.io/linux-raw-sys/0.4.3 \ - crate://crates.io/log/0.4.19 \ - crate://crates.io/memchr/2.5.0 \ - crate://crates.io/once_cell/1.18.0 \ - crate://crates.io/proc-macro2/1.0.67 \ - crate://crates.io/quote/1.0.29 \ - crate://crates.io/regex/1.9.1 \ - crate://crates.io/regex-automata/0.3.2 \ - crate://crates.io/regex-syntax/0.7.4 \ - crate://crates.io/rustix/0.38.3 \ - crate://crates.io/strsim/0.10.0 \ - crate://crates.io/syn/2.0.28 \ - crate://crates.io/termcolor/1.2.0 \ - crate://crates.io/thiserror/1.0.41 \ - crate://crates.io/thiserror-impl/1.0.41 \ - crate://crates.io/unicode-ident/1.0.11 \ - crate://crates.io/utf8parse/0.2.1 \ - crate://crates.io/vhost/0.8.0 \ - crate://crates.io/vhost-user-backend/0.10.0 \ - crate://crates.io/virtio-bindings/0.2.1 \ - crate://crates.io/virtio-queue/0.9.0 \ - crate://crates.io/vm-memory/0.12.0 \ - crate://crates.io/vmm-sys-util/0.11.1 \ + crate://crates.io/indexmap/2.5.0 \ + crate://crates.io/is-terminal/0.4.13 \ + crate://crates.io/is_terminal_polyfill/1.70.1 \ + crate://crates.io/itertools/0.10.5 \ + crate://crates.io/lazy_static/1.5.0 \ + crate://crates.io/libc/0.2.158 \ + crate://crates.io/linux-raw-sys/0.4.14 \ + crate://crates.io/lock_api/0.4.12 \ + crate://crates.io/log/0.4.22 \ + crate://crates.io/memchr/2.7.4 \ + crate://crates.io/memoffset/0.7.1 \ + crate://crates.io/mio/0.8.11 \ + crate://crates.io/nb/1.1.0 \ + crate://crates.io/neli/0.6.4 \ + crate://crates.io/neli-proc-macros/0.1.3 \ + crate://crates.io/nix/0.26.4 \ + crate://crates.io/nix/0.27.1 \ + crate://crates.io/num_cpus/1.16.0 \ + crate://crates.io/num_enum/0.7.3 \ + crate://crates.io/num_enum_derive/0.7.3 \ + crate://crates.io/once_cell/1.19.0 \ + crate://crates.io/parking_lot/0.12.3 \ + crate://crates.io/parking_lot_core/0.9.10 \ + crate://crates.io/pin-project-lite/0.2.14 \ + crate://crates.io/pin-utils/0.1.0 \ + crate://crates.io/proc-macro-crate/3.2.0 \ + crate://crates.io/proc-macro2/1.0.86 \ + crate://crates.io/queues/1.1.0 \ + crate://crates.io/quote/1.0.37 \ + crate://crates.io/redox_syscall/0.5.3 \ + crate://crates.io/regex/1.10.6 \ + crate://crates.io/regex-automata/0.4.7 \ + crate://crates.io/regex-syntax/0.8.4 \ + crate://crates.io/relative-path/1.9.3 \ + crate://crates.io/rstest/0.22.0 \ + crate://crates.io/rstest_macros/0.22.0 \ + crate://crates.io/rustc_version/0.4.1 \ + crate://crates.io/rustix/0.38.36 \ + crate://crates.io/scopeguard/1.2.0 \ + crate://crates.io/semver/1.0.23 \ + crate://crates.io/serde/1.0.210 \ + crate://crates.io/serde_derive/1.0.210 \ + crate://crates.io/signal-hook/0.3.17 \ + crate://crates.io/signal-hook-mio/0.2.4 \ + crate://crates.io/signal-hook-registry/1.4.2 \ + crate://crates.io/slab/0.4.9 \ + crate://crates.io/smallvec/1.13.2 \ + crate://crates.io/socket2/0.5.7 \ + crate://crates.io/strsim/0.11.1 \ + crate://crates.io/syn/1.0.109 \ + crate://crates.io/syn/2.0.77 \ + crate://crates.io/tempfile/3.12.0 \ + crate://crates.io/termcolor/1.4.1 \ + crate://crates.io/thiserror/1.0.63 \ + crate://crates.io/thiserror-impl/1.0.63 \ + crate://crates.io/toml_datetime/0.6.8 \ + crate://crates.io/toml_edit/0.22.20 \ + crate://crates.io/unicode-ident/1.0.13 \ + crate://crates.io/unicode-width/0.1.13 \ + crate://crates.io/utf8parse/0.2.2 \ + crate://crates.io/vhost/0.11.0 \ + crate://crates.io/vhost-user-backend/0.15.0 \ + crate://crates.io/virtio-bindings/0.2.3 \ + crate://crates.io/virtio-queue/0.12.0 \ + crate://crates.io/vm-memory/0.14.1 \ + crate://crates.io/vmm-sys-util/0.12.1 \ + crate://crates.io/wasi/0.11.0+wasi-snapshot-preview1 \ crate://crates.io/winapi/0.3.9 \ crate://crates.io/winapi-i686-pc-windows-gnu/0.4.0 \ - crate://crates.io/winapi-util/0.1.5 \ + crate://crates.io/winapi-util/0.1.9 \ crate://crates.io/winapi-x86_64-pc-windows-gnu/0.4.0 \ - crate://crates.io/windows-sys/0.45.0 \ - crate://crates.io/windows-targets/0.42.1 \ - crate://crates.io/windows_aarch64_gnullvm/0.42.1 \ - crate://crates.io/windows_aarch64_msvc/0.42.1 \ - crate://crates.io/windows_i686_gnu/0.42.1 \ - crate://crates.io/windows_i686_msvc/0.42.1 \ - crate://crates.io/windows_x86_64_gnu/0.42.1 \ - crate://crates.io/windows_x86_64_gnullvm/0.42.1 \ - crate://crates.io/windows_x86_64_msvc/0.42.1 \ + crate://crates.io/windows-sys/0.48.0 \ + crate://crates.io/windows-sys/0.52.0 \ + crate://crates.io/windows-sys/0.59.0 \ + crate://crates.io/windows-targets/0.48.5 \ + crate://crates.io/windows-targets/0.52.6 \ + crate://crates.io/windows_aarch64_gnullvm/0.48.5 \ + crate://crates.io/windows_aarch64_gnullvm/0.52.6 \ + crate://crates.io/windows_aarch64_msvc/0.48.5 \ + crate://crates.io/windows_aarch64_msvc/0.52.6 \ + crate://crates.io/windows_i686_gnu/0.48.5 \ + crate://crates.io/windows_i686_gnu/0.52.6 \ + crate://crates.io/windows_i686_gnullvm/0.52.6 \ + crate://crates.io/windows_i686_msvc/0.48.5 \ + crate://crates.io/windows_i686_msvc/0.52.6 \ + crate://crates.io/windows_x86_64_gnu/0.48.5 \ + crate://crates.io/windows_x86_64_gnu/0.52.6 \ + crate://crates.io/windows_x86_64_gnullvm/0.48.5 \ + crate://crates.io/windows_x86_64_gnullvm/0.52.6 \ + crate://crates.io/windows_x86_64_msvc/0.48.5 \ + crate://crates.io/windows_x86_64_msvc/0.52.6 \ + crate://crates.io/winnow/0.6.18 \ " +SRC_URI[aho-corasick-1.1.3.sha256sum] = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +SRC_URI[anstream-0.6.15.sha256sum] = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +SRC_URI[anstyle-1.0.8.sha256sum] = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" +SRC_URI[anstyle-parse-0.2.5.sha256sum] = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +SRC_URI[anstyle-query-1.1.1.sha256sum] = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +SRC_URI[anstyle-wincon-3.0.4.sha256sum] = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +SRC_URI[anyhow-1.0.87.sha256sum] = "10f00e1f6e58a40e807377c75c6a7f97bf9044fab57816f2414e6f5f4499d7b8" +SRC_URI[arc-swap-1.7.1.sha256sum] = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" +SRC_URI[assert_matches-1.5.0.sha256sum] = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" +SRC_URI[autocfg-1.3.0.sha256sum] = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +SRC_URI[bitflags-1.3.2.sha256sum] = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +SRC_URI[bitflags-2.6.0.sha256sum] = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +SRC_URI[byte_conv-0.1.1.sha256sum] = "649972315d4931137a26fc2bf3ca95ee257ad796a5b57bdeb04205c91a4b5780" +SRC_URI[byteorder-1.5.0.sha256sum] = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +SRC_URI[cfg-if-1.0.0.sha256sum] = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +SRC_URI[clap-4.5.17.sha256sum] = "3e5a21b8495e732f1b3c364c9949b201ca7bae518c502c80256c96ad79eaf6ac" +SRC_URI[clap_builder-4.5.17.sha256sum] = "8cf2dd12af7a047ad9d6da2b6b249759a22a7abc0f474c1dae1777afa4b21a73" +SRC_URI[clap_derive-4.5.13.sha256sum] = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" +SRC_URI[clap_lex-0.7.2.sha256sum] = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +SRC_URI[colorchoice-1.0.2.sha256sum] = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" +SRC_URI[console-0.15.8.sha256sum] = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +SRC_URI[crossterm-0.27.0.sha256sum] = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df" +SRC_URI[crossterm_winapi-0.9.1.sha256sum] = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" +SRC_URI[either-1.13.0.sha256sum] = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +SRC_URI[embedded-can-0.4.1.sha256sum] = "e9d2e857f87ac832df68fa498d18ddc679175cf3d2e4aa893988e5601baf9438" +SRC_URI[encode_unicode-0.3.6.sha256sum] = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +SRC_URI[enumn-0.1.14.sha256sum] = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38" +SRC_URI[env_filter-0.1.2.sha256sum] = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" +SRC_URI[env_logger-0.10.2.sha256sum] = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" +SRC_URI[env_logger-0.11.5.sha256sum] = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" +SRC_URI[epoll-4.3.3.sha256sum] = "74351c3392ea1ff6cd2628e0042d268ac2371cb613252ff383b6dfa50d22fa79" +SRC_URI[equivalent-1.0.1.sha256sum] = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +SRC_URI[errno-0.3.9.sha256sum] = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +SRC_URI[fastrand-2.1.1.sha256sum] = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" +SRC_URI[futures-0.3.30.sha256sum] = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +SRC_URI[futures-channel-0.3.30.sha256sum] = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +SRC_URI[futures-core-0.3.30.sha256sum] = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +SRC_URI[futures-executor-0.3.30.sha256sum] = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +SRC_URI[futures-io-0.3.30.sha256sum] = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +SRC_URI[futures-macro-0.3.30.sha256sum] = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +SRC_URI[futures-sink-0.3.30.sha256sum] = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +SRC_URI[futures-task-0.3.30.sha256sum] = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +SRC_URI[futures-timer-3.0.3.sha256sum] = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" +SRC_URI[futures-util-0.3.30.sha256sum] = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +SRC_URI[glob-0.3.1.sha256sum] = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +SRC_URI[hashbrown-0.14.5.sha256sum] = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +SRC_URI[heck-0.5.0.sha256sum] = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +SRC_URI[hermit-abi-0.3.9.sha256sum] = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +SRC_URI[hermit-abi-0.4.0.sha256sum] = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" +SRC_URI[hex-0.4.3.sha256sum] = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +SRC_URI[humantime-2.1.0.sha256sum] = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +SRC_URI[indexmap-2.5.0.sha256sum] = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" +SRC_URI[is-terminal-0.4.13.sha256sum] = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" +SRC_URI[is_terminal_polyfill-1.70.1.sha256sum] = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +SRC_URI[itertools-0.10.5.sha256sum] = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +SRC_URI[lazy_static-1.5.0.sha256sum] = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +SRC_URI[libc-0.2.158.sha256sum] = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +SRC_URI[linux-raw-sys-0.4.14.sha256sum] = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +SRC_URI[lock_api-0.4.12.sha256sum] = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +SRC_URI[log-0.4.22.sha256sum] = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +SRC_URI[memchr-2.7.4.sha256sum] = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +SRC_URI[memoffset-0.7.1.sha256sum] = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +SRC_URI[mio-0.8.11.sha256sum] = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +SRC_URI[nb-1.1.0.sha256sum] = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" +SRC_URI[neli-0.6.4.sha256sum] = "1100229e06604150b3becd61a4965d5c70f3be1759544ea7274166f4be41ef43" +SRC_URI[neli-proc-macros-0.1.3.sha256sum] = "c168194d373b1e134786274020dae7fc5513d565ea2ebb9bc9ff17ffb69106d4" +SRC_URI[nix-0.26.4.sha256sum] = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +SRC_URI[nix-0.27.1.sha256sum] = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" +SRC_URI[num_cpus-1.16.0.sha256sum] = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +SRC_URI[num_enum-0.7.3.sha256sum] = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +SRC_URI[num_enum_derive-0.7.3.sha256sum] = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +SRC_URI[once_cell-1.19.0.sha256sum] = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +SRC_URI[parking_lot-0.12.3.sha256sum] = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +SRC_URI[parking_lot_core-0.9.10.sha256sum] = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +SRC_URI[pin-project-lite-0.2.14.sha256sum] = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +SRC_URI[pin-utils-0.1.0.sha256sum] = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +SRC_URI[proc-macro-crate-3.2.0.sha256sum] = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" +SRC_URI[proc-macro2-1.0.86.sha256sum] = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +SRC_URI[queues-1.1.0.sha256sum] = "1475abae4f8ad4998590fe3acfe20104f0a5d48fc420c817cd2c09c3f56151f0" +SRC_URI[quote-1.0.37.sha256sum] = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +SRC_URI[redox_syscall-0.5.3.sha256sum] = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +SRC_URI[regex-1.10.6.sha256sum] = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +SRC_URI[regex-automata-0.4.7.sha256sum] = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +SRC_URI[regex-syntax-0.8.4.sha256sum] = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +SRC_URI[relative-path-1.9.3.sha256sum] = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" +SRC_URI[rstest-0.22.0.sha256sum] = "7b423f0e62bdd61734b67cd21ff50871dfaeb9cc74f869dcd6af974fbcb19936" +SRC_URI[rstest_macros-0.22.0.sha256sum] = "c5e1711e7d14f74b12a58411c542185ef7fb7f2e7f8ee6e2940a883628522b42" +SRC_URI[rustc_version-0.4.1.sha256sum] = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +SRC_URI[rustix-0.38.36.sha256sum] = "3f55e80d50763938498dd5ebb18647174e0c76dc38c5505294bb224624f30f36" +SRC_URI[scopeguard-1.2.0.sha256sum] = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +SRC_URI[semver-1.0.23.sha256sum] = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +SRC_URI[serde-1.0.210.sha256sum] = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +SRC_URI[serde_derive-1.0.210.sha256sum] = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +SRC_URI[signal-hook-0.3.17.sha256sum] = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" +SRC_URI[signal-hook-mio-0.2.4.sha256sum] = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd" +SRC_URI[signal-hook-registry-1.4.2.sha256sum] = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +SRC_URI[slab-0.4.9.sha256sum] = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +SRC_URI[smallvec-1.13.2.sha256sum] = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +SRC_URI[socket2-0.5.7.sha256sum] = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +SRC_URI[strsim-0.11.1.sha256sum] = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +SRC_URI[syn-1.0.109.sha256sum] = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +SRC_URI[syn-2.0.77.sha256sum] = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +SRC_URI[tempfile-3.12.0.sha256sum] = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" +SRC_URI[termcolor-1.4.1.sha256sum] = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +SRC_URI[thiserror-1.0.63.sha256sum] = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +SRC_URI[thiserror-impl-1.0.63.sha256sum] = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +SRC_URI[toml_datetime-0.6.8.sha256sum] = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +SRC_URI[toml_edit-0.22.20.sha256sum] = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" +SRC_URI[unicode-ident-1.0.13.sha256sum] = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +SRC_URI[unicode-width-0.1.13.sha256sum] = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" +SRC_URI[utf8parse-0.2.2.sha256sum] = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +SRC_URI[vhost-0.11.0.sha256sum] = "6be08d1166d41a78861ad50212ab3f9eca0729c349ac3a7a8f557c62406b87cc" +SRC_URI[vhost-user-backend-0.15.0.sha256sum] = "1f0ffb1dd8e00a708a0e2c32d5efec5812953819888591fff9ff68236b8a5096" +SRC_URI[virtio-bindings-0.2.3.sha256sum] = "68d0df4f5ad79b1dc81b5913ac737e24a84dcd5100f36ed953a1faec18aba241" +SRC_URI[virtio-queue-0.12.0.sha256sum] = "07d8406e7250c934462de585d8f2d2781c31819bca1fbb7c5e964ca6bbaabfe8" +SRC_URI[vm-memory-0.14.1.sha256sum] = "3c3aba5064cc5f6f7740cddc8dae34d2d9a311cac69b60d942af7f3ab8fc49f4" +SRC_URI[vmm-sys-util-0.12.1.sha256sum] = "1d1435039746e20da4f8d507a72ee1b916f7b4b05af7a91c093d2c6561934ede" +SRC_URI[wasi-0.11.0+wasi-snapshot-preview1.sha256sum] = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +SRC_URI[winapi-0.3.9.sha256sum] = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +SRC_URI[winapi-i686-pc-windows-gnu-0.4.0.sha256sum] = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +SRC_URI[winapi-util-0.1.9.sha256sum] = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +SRC_URI[winapi-x86_64-pc-windows-gnu-0.4.0.sha256sum] = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +SRC_URI[windows-sys-0.48.0.sha256sum] = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +SRC_URI[windows-sys-0.52.0.sha256sum] = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +SRC_URI[windows-sys-0.59.0.sha256sum] = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +SRC_URI[windows-targets-0.48.5.sha256sum] = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +SRC_URI[windows-targets-0.52.6.sha256sum] = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +SRC_URI[windows_aarch64_gnullvm-0.48.5.sha256sum] = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +SRC_URI[windows_aarch64_gnullvm-0.52.6.sha256sum] = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +SRC_URI[windows_aarch64_msvc-0.48.5.sha256sum] = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +SRC_URI[windows_aarch64_msvc-0.52.6.sha256sum] = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +SRC_URI[windows_i686_gnu-0.48.5.sha256sum] = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +SRC_URI[windows_i686_gnu-0.52.6.sha256sum] = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +SRC_URI[windows_i686_gnullvm-0.52.6.sha256sum] = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +SRC_URI[windows_i686_msvc-0.48.5.sha256sum] = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +SRC_URI[windows_i686_msvc-0.52.6.sha256sum] = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +SRC_URI[windows_x86_64_gnu-0.48.5.sha256sum] = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +SRC_URI[windows_x86_64_gnu-0.52.6.sha256sum] = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +SRC_URI[windows_x86_64_gnullvm-0.48.5.sha256sum] = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +SRC_URI[windows_x86_64_gnullvm-0.52.6.sha256sum] = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +SRC_URI[windows_x86_64_msvc-0.48.5.sha256sum] = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +SRC_URI[windows_x86_64_msvc-0.52.6.sha256sum] = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +SRC_URI[winnow-0.6.18.sha256sum] = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" diff --git a/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console_0.1.0.bb b/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console_0.1.0.bb index e02133bd..5fa2801d 100644 --- a/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console_0.1.0.bb +++ b/meta-egvirt/recipes-extended/vhost-device-console/vhost-device-console_0.1.0.bb @@ -7,8 +7,7 @@ EXTRAPATHS:prepend := "${THISDIR}:" SRC_URI = " file://. " -LICENSE = "Apache-2.0" -LICENSE = "BSD-3-Clause" +LICENSE = "Apache-2.0 | BSD-3-Clause" LIC_FILES_CHKSUM = "\ file://LICENSE-APACHE;md5=3b83ef96387f14655fc854ddc3c6bd57 \ @@ -17,5 +16,8 @@ LIC_FILES_CHKSUM = "\ inherit cargo inherit pkgconfig +inherit cargo-update-recipe-crates include vhost-device-console-crates.inc + +CARGO_BUILD_FLAGS = "-v --offline --target ${RUST_HOST_SYS} ${BUILD_MODE} --manifest-path=${CARGO_MANIFEST_PATH}" |