Skip to content

Commit 0c881ef

Browse files
committed
mctp-estack: Make buffer sizes configurable
These can be set by environment variables at build time, documented in mctp_estack::config Some other limits have been increased. Signed-off-by: Matt Johnston <[email protected]>
1 parent ecbb372 commit 0c881ef

File tree

7 files changed

+92
-34
lines changed

7 files changed

+92
-34
lines changed

mctp-estack/src/fragment.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::fmt::{debug, error, info, trace, warn};
1010

1111
use mctp::{Eid, Error, MsgType, Result, Tag, MCTP_HEADER_VERSION_1};
1212

13-
use crate::{AppCookie, Header, HEADER_LEN};
13+
use crate::{AppCookie, Header, HEADER_LEN, MAX_MTU};
1414

1515
#[derive(Debug)]
1616
pub struct Fragmenter {
@@ -47,6 +47,11 @@ impl Fragmenter {
4747
debug_assert!(typ.0 & 0x80 == 0, "IC bit's set in typ");
4848
debug_assert!(initial_seq & !mctp::MCTP_SEQ_MASK == 0);
4949
if mtu < HEADER_LEN+1 {
50+
debug!("mtu too small");
51+
return Err(Error::BadArgument);
52+
}
53+
if mtu > MAX_MTU {
54+
debug!("mtu too large");
5055
return Err(Error::BadArgument);
5156
}
5257
// TODO other validity checks

mctp-estack/src/i2c.rs

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use crate::fmt::{debug, error, info, trace, warn};
1010

1111
use crate::{
1212
AppCookie, Fragmenter, MctpMessage, ReceiveHandle, SendOutput, Stack,
13+
MAX_PAYLOAD,
1314
};
1415
use mctp::{Eid, Error, MsgType, Result, Tag};
1516

@@ -21,15 +22,6 @@ const MCTP_I2C_HEADER: usize = 4;
2122
// bytecount is limited to u8, includes MCTP payload + 1 byte i2c source
2223
pub const MCTP_I2C_MAXMTU: usize = u8::MAX as usize - 1;
2324

24-
/// Size of fixed transmit buffer. This is the maximum size of a MCTP message.
25-
///
26-
/// *TODO:* This will be replaced with a dynamically sized `send_message` buffer
27-
/// passed in.
28-
///
29-
/// Requires finding a replacement for `Vec` in `fill_msg` for `send_enqueue()`.
30-
/// Maybe heapless::VecView once it's in a release.
31-
pub const SENDBUF: usize = 1024;
32-
3325
type MctpI2cHeader =
3426
libmctp::smbus_proto::MCTPSMBusHeader<[u8; MCTP_I2C_HEADER]>;
3527

@@ -180,9 +172,7 @@ impl MctpI2cEncap {
180172
pub struct MctpI2cHandler {
181173
encap: MctpI2cEncap,
182174

183-
// TODO: replace with a &[u8] or similar so that we can avoid
184-
// the const SENDBUF.
185-
send_message: &'static mut Vec<u8, SENDBUF>,
175+
send_message: &'static mut Vec<u8, MAX_PAYLOAD>,
186176
send_state: HandlerSendState,
187177
}
188178

@@ -202,7 +192,7 @@ impl MctpI2cHandler {
202192
/// [`mctp_estack::Vec`](crate::Vec) can be used for API compatibility.
203193
pub fn new(
204194
own_addr: u8,
205-
send_message: &'static mut Vec<u8, SENDBUF>,
195+
send_message: &'static mut Vec<u8, MAX_PAYLOAD>,
206196
) -> Self {
207197
Self {
208198
encap: MctpI2cEncap::new(own_addr),
@@ -300,7 +290,7 @@ impl MctpI2cHandler {
300290
fill_msg: F,
301291
) -> Result<()>
302292
where
303-
F: FnOnce(&mut Vec<u8, SENDBUF>) -> Option<()>,
293+
F: FnOnce(&mut Vec<u8, MAX_PAYLOAD>) -> Option<()>,
304294
{
305295
if !self.is_send_idle() {
306296
return Err(Error::Other);

mctp-estack/src/lib.rs

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@
1717
//! Applications can create [`router::RouterAsyncListener`] and [`router::RouterAsyncReqChannel`]
1818
//! instances to communicate over MCTP. Those implement the standard [`mctp` crate](mctp)
1919
//! async traits.
20+
//!
21+
//! ## Configuration
22+
//!
23+
//! `mctp-estack` uses fixed sizes to be suitable on no-alloc platforms.
24+
//! These can be configured at build time, see [`config`]
2025
2126
#![cfg_attr(not(any(feature = "std", test)), no_std)]
2227
#![forbid(unsafe_code)]
@@ -33,6 +38,7 @@ use mctp::{Eid, MsgType, TagValue, Tag, Error, Result};
3338

3439
mod fragment;
3540
mod reassemble;
41+
mod util;
3642
pub mod i2c;
3743
pub mod serial;
3844
pub mod usb;
@@ -44,11 +50,8 @@ use reassemble::Reassembler;
4450
pub use router::Router;
4551

4652
use crate::fmt::*;
53+
pub(crate) use config::*;
4754

48-
const FLOWS: usize = 8;
49-
50-
const NUM_RECEIVE: usize = 4;
51-
const RECV_PAYLOAD: usize = 1032;
5255

5356
/// Timeout for message reassembly.
5457
///
@@ -68,6 +71,50 @@ pub const DEFERRED_TIMEOUT: u32 = 6000;
6871
/// See [`Stack::update()`].
6972
pub const TIMEOUT_INTERVAL: u32 = 100;
7073

74+
pub(crate) const HEADER_LEN: usize = 4;
75+
76+
/// Build-time configuration and defaults
77+
///
78+
/// To set a non-default value, set the `MCTP_ESTACK_...` environment variable
79+
/// during the build. Those variables can be set in the `[env]`
80+
/// section of `.cargo/config.toml`.
81+
pub mod config {
82+
use crate::get_build_var;
83+
84+
/// Maximum size of a MCTP message payload in bytes, default 1032
85+
///
86+
/// This does not include the MCTP type byte.
87+
///
88+
/// Customise with `MCTP_ESTACK_MAX_MESSAGE` environment variable.
89+
pub const MAX_PAYLOAD: usize = get_build_var!("MCTP_ESTACK_MAX_MESSAGE", 1032);
90+
91+
/// Number of concurrent receive messages, default 4
92+
///
93+
/// The number of in-progress message reassemblies is limited to `NUM_RECEIVE`.
94+
/// Total memory used for reassembly buffers is roughly
95+
/// `MAX_PAYLOAD` * `NUM_RECEIVE` bytes.
96+
///
97+
/// Customise with `MCTP_ESTACK_NUM_RECEIVE` environment variable.
98+
/// Number of outstanding waiting responses, default 64
99+
pub const NUM_RECEIVE: usize = get_build_var!("MCTP_ESTACK_NUM_RECEIVE", 4);
100+
///
101+
/// After a message is sent with Tag Owner (TO) bit set, the stack will accept
102+
/// response messages with the same tag and TO _unset_. `FLOWS` defines
103+
/// the number of slots available for pending responses.
104+
///
105+
/// Customise with `MCTP_ESTACK_FLOWS` environment variable.
106+
/// Must be a power of two.
107+
pub const FLOWS: usize = get_build_var!("MCTP_ESTACK_FLOWS", 64);
108+
109+
/// Maximum allowed MTU, default 255
110+
///
111+
/// The largest MTU allowed for any link.
112+
///
113+
/// Customise with `MCTP_ESTACK_MAX_MTU` environment variable.
114+
pub const MAX_MTU: usize = get_build_var!("MCTP_ESTACK_MAX_MTU", 255);
115+
const _: () = assert!(MAX_MTU >= crate::HEADER_LEN+1, "MAX_MTU too small");
116+
}
117+
71118
#[derive(Debug)]
72119
struct Flow {
73120
// preallocated flows have None expiry
@@ -79,7 +126,6 @@ struct Flow {
79126
#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash)]
80127
pub struct AppCookie(pub usize);
81128

82-
pub(crate) const HEADER_LEN: usize = 4;
83129
type Header = libmctp::base_packet::MCTPTransportHeader<[u8; HEADER_LEN]>;
84130

85131
/// A handle to a received message.
@@ -103,8 +149,8 @@ pub struct Stack {
103149
// The buffer is kept outside of the Reassembler, in case it is borrowed
104150
// from other storage locations in future.
105151
// This is [Option<>] rather than Vec so that indices remain stable
106-
// for the ReceiveHandle. Could use a LinearMap instead?
107-
reassemblers: [Option<(Reassembler, Vec<u8, RECV_PAYLOAD>)>; NUM_RECEIVE],
152+
// for the ReceiveHandle. Could use a Map instead?
153+
reassemblers: [Option<(Reassembler, Vec<u8, MAX_PAYLOAD>)>; NUM_RECEIVE],
108154

109155
/// monotonic time and counter.
110156
now: EventStamp,

mctp-estack/src/router.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use core::future::{poll_fn, Future};
1414
use core::pin::pin;
1515

1616
use mctp::{Eid, Error, MsgType, Result, Tag, TagValue};
17-
use crate::{AppCookie, Fragmenter, ReceiveHandle, SendOutput, Stack, Header};
17+
use crate::{AppCookie, Fragmenter, ReceiveHandle, SendOutput, Stack, MAX_PAYLOAD, MAX_MTU};
1818
use crate::reassemble::Reassembler;
1919

2020
use embassy_sync::zerocopy_channel::{Channel, Sender, Receiver};
@@ -100,7 +100,7 @@ pub struct PortTop<'a> {
100100

101101
/// Temporary storage to flatten vectorised local sent messages
102102
// prior to fragmentation and queueing.
103-
message: AsyncMutex<Vec<u8, MAX_MESSAGE>>,
103+
message: AsyncMutex<Vec<u8, MAX_PAYLOAD>>,
104104

105105
mtu: usize,
106106
}

mctp-estack/src/serial.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
use crate::fmt::{debug, error, info, trace, warn};
1010

1111
use crate::{
12-
AppCookie, MctpMessage, ReceiveHandle, SendOutput, Stack,
12+
AppCookie, MctpMessage, ReceiveHandle, SendOutput, Stack, MAX_PAYLOAD,
1313
};
1414
use mctp::{Eid, Error, MsgType, Result, Tag};
1515

@@ -33,7 +33,6 @@ const FRAMING_ESCAPE: u8 = 0x7d;
3333
const FLAG_ESCAPED: u8 = 0x5e;
3434
const ESCAPE_ESCAPED: u8 = 0x5d;
3535

36-
const TXMSGBUF: usize = 1024;
3736
// 6 serial header/footer bytes, 0xff MCTP packet bytes
3837
const TXFRAGBUF: usize = 6 + 0xff;
3938

@@ -59,7 +58,7 @@ pub struct MctpSerialHandler {
5958
// Last-seen byte count field
6059
rxcount: usize,
6160

62-
send_message: Vec<u8, TXMSGBUF>,
61+
send_message: Vec<u8, MAX_PAYLOAD>,
6362
send_fragment: [u8; TXFRAGBUF]
6463
}
6564

@@ -206,7 +205,7 @@ impl MctpSerialHandler {
206205
// Returns SendOutput::Complete or SendOutput::Error
207206
pub async fn send_fill<F>(&mut self, eid: Eid, typ: MsgType, tag: Option<Tag>,
208207
ic: bool, cookie: Option<AppCookie>, output: &mut impl Write, mctp: &mut Stack, fill_msg: F) -> SendOutput
209-
where F: FnOnce(&mut Vec<u8, TXMSGBUF>) -> Option<()>,
208+
where F: FnOnce(&mut Vec<u8, MAX_PAYLOAD>) -> Option<()>,
210209
{
211210
// Fetch the message from input
212211
self.send_message.clear();

mctp-estack/src/usb.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
use heapless::Vec;
1515
use crate::{
16-
AppCookie, MctpMessage, ReceiveHandle, SendOutput, Stack,
16+
AppCookie, MctpMessage, ReceiveHandle, SendOutput, Stack, MAX_PAYLOAD,
1717
};
1818
use mctp::{Eid, MsgType, Tag, Error, Result};
1919

@@ -29,11 +29,8 @@ const HDR_LEN: usize = 4;
2929
const MCTP_USB_MTU_MAX: usize = u8::MAX as usize - HDR_LEN;
3030
const TX_XFER_SIZE: usize = 512;
3131

32-
// Arbitrary limit
33-
const TX_MSG_SIZE: usize = 1024;
34-
3532
pub struct MctpUsbHandler {
36-
tx_msg: Vec<u8, TX_MSG_SIZE>,
33+
tx_msg: Vec<u8, MAX_PAYLOAD>,
3734
tx_xfer: [u8; TX_XFER_SIZE],
3835
}
3936

@@ -96,7 +93,7 @@ impl MctpUsbHandler {
9693
mctp: &mut Stack,
9794
fill_msg: F,
9895
) -> SendOutput
99-
where F: FnOnce(&mut Vec<u8, TX_MSG_SIZE>) -> Option<()>,
96+
where F: FnOnce(&mut Vec<u8, MAX_PAYLOAD>) -> Option<()>,
10097
{
10198
self.tx_msg.clear();
10299
if fill_msg(&mut self.tx_msg).is_none() {

mctp-estack/src/util.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/// Takes a `usize` from a build-time environment variable.
2+
///
3+
/// If unset, the default is used. Can be used in a const context.
4+
#[macro_export]
5+
macro_rules! get_build_var {
6+
($name:literal, $default:expr) => {
7+
{
8+
match option_env!($name) {
9+
Some(v) => {
10+
let Ok(v) = usize::from_str_radix(v, 10) else {
11+
// concat! because const format_args isn't stable
12+
panic!(concat!("Bad value for environment variable ", $name));
13+
};
14+
v
15+
}
16+
None => $default
17+
}
18+
}
19+
};
20+
}
21+

0 commit comments

Comments
 (0)