From 62f39e2c08565cd9262ac2ee76f251a1378f5bb6 Mon Sep 17 00:00:00 2001 From: pca006132 Date: Mon, 13 Jul 2020 15:00:53 +0800 Subject: [PATCH] mgmt: Implemented network log access. --- default.nix | 2 +- src/Cargo.lock | 7 +++ src/runtime/Cargo.toml | 1 + src/runtime/src/comms.rs | 2 + src/runtime/src/main.rs | 2 + src/runtime/src/mgmt.rs | 82 ++++++++++++++++++++++++++++++ src/runtime/src/proto_async.rs | 2 +- src/runtime/src/proto_mgmt.rs | 91 ++++++++++++++++++++++++++++++++++ 8 files changed, 187 insertions(+), 2 deletions(-) create mode 100644 src/runtime/src/mgmt.rs create mode 100644 src/runtime/src/proto_mgmt.rs diff --git a/default.nix b/default.nix index 78e2dfe..90a0062 100644 --- a/default.nix +++ b/default.nix @@ -14,7 +14,7 @@ let version = "0.1.0"; src = ./src; - cargoSha256 = "0xminds5fyp7c9vsx651zv3yzyhxnl9a02rhjl2wfxf8m679r45l"; + cargoSha256 = "1q66h2avk0gvw8k07jjazzv1f3n1p4y11vkc15c6s31pcapz3d81"; nativeBuildInputs = [ pkgs.gnumake diff --git a/src/Cargo.lock b/src/Cargo.lock index 2a90898..4e655fb 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -280,6 +280,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "log_buffer" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f033173c9486b7fe97a79c895c0a3483ae395ab6744c985d10078950e2492419" + [[package]] name = "managed" version = "0.7.2" @@ -400,6 +406,7 @@ dependencies = [ "libregister", "libsupport_zynq", "log", + "log_buffer", "nb", "num-derive", "num-traits", diff --git a/src/runtime/Cargo.toml b/src/runtime/Cargo.toml index 56f08e5..91173f0 100644 --- a/src/runtime/Cargo.toml +++ b/src/runtime/Cargo.toml @@ -22,6 +22,7 @@ void = { version = "1", default-features = false } futures = { version = "0.3", default-features = false, features = ["async-await"] } async-recursion = "0.3" fatfs = { version = "0.3", features = ["core_io"], default-features = false } +log_buffer = { version = "1.2" } libboard_zynq = { git = "https://git.m-labs.hk/M-Labs/zc706.git" } libsupport_zynq = { default-features = false, git = "https://git.m-labs.hk/M-Labs/zc706.git" } diff --git a/src/runtime/src/comms.rs b/src/runtime/src/comms.rs index 94d8842..65a83f1 100644 --- a/src/runtime/src/comms.rs +++ b/src/runtime/src/comms.rs @@ -27,6 +27,7 @@ use crate::proto_async::*; use crate::kernel; use crate::rpc; use crate::moninj; +use crate::mgmt; #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -356,6 +357,7 @@ pub fn main(timer: GlobalTimer, cfg: &config::Config) { } }); + mgmt::start(); moninj::start(timer); Sockets::run(&mut iface, || { diff --git a/src/runtime/src/main.rs b/src/runtime/src/main.rs index 1bef8b7..4c20f3f 100644 --- a/src/runtime/src/main.rs +++ b/src/runtime/src/main.rs @@ -20,6 +20,7 @@ mod config; mod net_settings; mod proto_core_io; mod proto_async; +mod proto_mgmt; mod comms; mod rpc; #[path = "../../../build/pl.rs"] @@ -31,6 +32,7 @@ mod load_pl; mod eh_artiq; mod panic; mod logger; +mod mgmt; fn init_gateware() { // Set up PS->PL clocks diff --git a/src/runtime/src/mgmt.rs b/src/runtime/src/mgmt.rs new file mode 100644 index 0000000..24f4bf4 --- /dev/null +++ b/src/runtime/src/mgmt.rs @@ -0,0 +1,82 @@ +use futures::{future::poll_fn, task::Poll}; +use libasync::{smoltcp::TcpStream, task}; +use libboard_zynq::smoltcp; +use log::{self, info, warn}; + +use crate::logger::{BufferLogger, LogBufferRef}; +use crate::proto_async; +use crate::proto_mgmt::*; + +async fn get_logger_buffer() -> LogBufferRef<'static> { + poll_fn(|ctx| { + let logger = unsafe { BufferLogger::get_logger().as_mut().unwrap() }; + match logger.buffer() { + Ok(buffer) => Poll::Ready(buffer), + _ => { + ctx.waker().wake_by_ref(); + Poll::Pending + } + } + }) + .await +} + +async fn handle_connection(stream: &mut TcpStream) -> Result<(), Error> { + Request::read_magic(stream).await?; + + loop { + let req = Request::read_from(stream).await; + if let Err(Error::Io(smoltcp::Error::Illegal)) = req { + return Ok(()); + } + match req? { + Request::GetLog => { + let mut buffer = get_logger_buffer().await; + Reply::LogContent(buffer.extract()).write_to(stream).await?; + } + Request::ClearLog => { + let mut buffer = get_logger_buffer().await; + buffer.clear(); + Reply::Success.write_to(stream).await?; + } + Request::PullLog => loop { + let mut buffer = get_logger_buffer().await; + if buffer.is_empty() { + continue; + } + proto_async::write_chunk(stream, buffer.extract().as_bytes()).await?; + buffer.clear(); + }, + Request::SetLogFilter(lvl) => { + info!("Changing log level to {}", lvl); + log::set_max_level(lvl); + Reply::Success.write_to(stream).await?; + } + Request::SetUartLogFilter(lvl) => { + info!("Changing UART log level to {}", lvl); + unsafe { + BufferLogger::get_logger() + .as_ref() + .unwrap() + .set_uart_log_level(lvl); + } + Reply::Success.write_to(stream).await?; + }, + } + } +} + +pub fn start() { + task::spawn(async move { + loop { + let mut stream = TcpStream::accept(1380, 2048, 2048).await.unwrap(); + task::spawn(async move { + let _ = handle_connection(&mut stream) + .await + .map_err(|e| warn!("connection terminated: {:?}", e)); + let _ = stream.flush().await; + let _ = stream.abort().await; + }); + } + }); +} diff --git a/src/runtime/src/proto_async.rs b/src/runtime/src/proto_async.rs index 366eb78..953c6f2 100644 --- a/src/runtime/src/proto_async.rs +++ b/src/runtime/src/proto_async.rs @@ -7,7 +7,7 @@ use libasync::smoltcp::TcpStream; // TODO: use byteorder, make it more like libio -pub type Result = core::result::Result; +type Result = core::result::Result; pub async fn expect(stream: &TcpStream, pattern: &[u8]) -> Result { stream.recv(|buf| { diff --git a/src/runtime/src/proto_mgmt.rs b/src/runtime/src/proto_mgmt.rs new file mode 100644 index 0000000..70d9043 --- /dev/null +++ b/src/runtime/src/proto_mgmt.rs @@ -0,0 +1,91 @@ +use libasync::smoltcp::TcpStream; +use libboard_zynq::smoltcp::Error as IoError; +use log; + +use crate::proto_async::*; + +pub enum Error { + WrongMagic, + UnknownPacket(u8), + UnknownLogLevel(u8), + Io(IoError), +} + +impl core::fmt::Debug for Error { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + use Error::*; + match self { + WrongMagic => write!(f, "Wrong magic string"), + UnknownPacket(v) => write!(f, "Unknown packet {:#02x}", v), + UnknownLogLevel(v) => write!(f, "Unknown log level {}", v), + Io(e) => write!(f, "{}", e), + } + } +} + +impl From for Error { + fn from(value: IoError) -> Error { + Error::Io(value) + } +} + +#[derive(Debug)] +pub enum Request { + GetLog, + ClearLog, + PullLog, + SetLogFilter(log::LevelFilter), + SetUartLogFilter(log::LevelFilter), +} + +pub enum Reply<'a> { + Success, + LogContent(&'a str), +} + +impl Request { + pub async fn read_from(stream: &mut TcpStream) -> Result { + async fn read_log_level_filter(stream: &mut TcpStream) -> Result { + Ok(match read_i8(stream).await? { + 0 => log::LevelFilter::Off, + 1 => log::LevelFilter::Error, + 2 => log::LevelFilter::Warn, + 3 => log::LevelFilter::Info, + 4 => log::LevelFilter::Debug, + 5 => log::LevelFilter::Trace, + lv => return Err(Error::UnknownLogLevel(lv as u8)), + }) + } + + Ok(match read_i8(stream).await? { + 1 => Request::GetLog, + 2 => Request::ClearLog, + 7 => Request::PullLog, + 3 => Request::SetLogFilter(read_log_level_filter(stream).await?), + 6 => Request::SetUartLogFilter(read_log_level_filter(stream).await?), + ty => return Err(Error::UnknownPacket(ty as u8)), + }) + } + + pub async fn read_magic(stream: &mut TcpStream) -> Result<(), Error> { + if !expect(&stream, b"ARTIQ management\n").await? { + return Err(Error::WrongMagic); + } + Ok(()) + } +} + +impl<'a> Reply<'a> { + pub async fn write_to(&self, stream: &mut TcpStream) -> Result<(), IoError> { + match *self { + Reply::Success => { + write_i8(stream, 1).await?; + } + Reply::LogContent(ref log) => { + write_i8(stream, 2).await?; + write_chunk(stream, log.as_bytes()).await?; + } + } + Ok(()) + } +}