mirror of
https://github.com/jmcorgan/fips.git
synced 2026-07-22 07:48:26 +00:00
Add per-link MTU support to Transport trait
Add link_mtu(&TransportAddr) method to the Transport trait with a default implementation that falls back to the transport-wide mtu(). This enables transports like BLE to report per-connection MTU values while maintaining backward compatibility for UDP and other transports that use a single MTU for all links. Update the forwarding and session send paths to query link_mtu() with the next-hop peer's current address, falling back to transport-wide mtu() when no address is available.
This commit is contained in:
@@ -64,8 +64,12 @@ impl Node {
|
||||
&& let Some(tid) = peer.transport_id()
|
||||
&& let Some(transport) = self.transports.get(&tid)
|
||||
{
|
||||
if let Some(addr) = peer.current_addr() {
|
||||
datagram.path_mtu = datagram.path_mtu.min(transport.link_mtu(addr));
|
||||
} else {
|
||||
datagram.path_mtu = datagram.path_mtu.min(transport.mtu());
|
||||
}
|
||||
}
|
||||
|
||||
// Forward: re-encode (includes 0x00 type byte) and send
|
||||
let encoded = datagram.encode();
|
||||
|
||||
@@ -1062,8 +1062,12 @@ impl Node {
|
||||
&& let Some(tid) = peer.transport_id()
|
||||
&& let Some(transport) = self.transports.get(&tid)
|
||||
{
|
||||
if let Some(addr) = peer.current_addr() {
|
||||
datagram.path_mtu = datagram.path_mtu.min(transport.link_mtu(addr));
|
||||
} else {
|
||||
datagram.path_mtu = datagram.path_mtu.min(transport.mtu());
|
||||
}
|
||||
}
|
||||
|
||||
// Source-side: seed our PathMtuState.current_mtu from the outbound
|
||||
// transport MTU so it doesn't stay at u16::MAX until the destination
|
||||
|
||||
@@ -740,6 +740,16 @@ pub trait Transport {
|
||||
/// Get the MTU for this transport.
|
||||
fn mtu(&self) -> u16;
|
||||
|
||||
/// Get the MTU for a specific link.
|
||||
///
|
||||
/// Returns the MTU negotiated for the given transport address, or
|
||||
/// falls back to the transport-wide default if the address is unknown
|
||||
/// or the transport doesn't support per-link MTU negotiation.
|
||||
fn link_mtu(&self, addr: &TransportAddr) -> u16 {
|
||||
let _ = addr;
|
||||
self.mtu()
|
||||
}
|
||||
|
||||
/// Start the transport.
|
||||
fn start(&mut self) -> Result<(), TransportError>;
|
||||
|
||||
@@ -824,6 +834,16 @@ impl TransportHandle {
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the MTU for a specific link address.
|
||||
///
|
||||
/// Falls back to transport-wide MTU if the transport doesn't
|
||||
/// support per-link MTU or the address is unknown.
|
||||
pub fn link_mtu(&self, addr: &TransportAddr) -> u16 {
|
||||
match self {
|
||||
TransportHandle::Udp(t) => t.link_mtu(addr),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the local bound address (only valid after start).
|
||||
pub fn local_addr(&self) -> Option<std::net::SocketAddr> {
|
||||
match self {
|
||||
@@ -1116,4 +1136,156 @@ mod tests {
|
||||
let received = rx.recv().await.unwrap();
|
||||
assert_eq!(received.data, vec![1, 2, 3]);
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// link_mtu tests
|
||||
// ========================================================================
|
||||
|
||||
/// Minimal mock transport for testing the default link_mtu() behavior.
|
||||
struct MockTransport {
|
||||
id: TransportId,
|
||||
mtu_value: u16,
|
||||
}
|
||||
|
||||
impl MockTransport {
|
||||
fn new(mtu: u16) -> Self {
|
||||
Self {
|
||||
id: TransportId::new(99),
|
||||
mtu_value: mtu,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Transport for MockTransport {
|
||||
fn transport_id(&self) -> TransportId {
|
||||
self.id
|
||||
}
|
||||
fn transport_type(&self) -> &TransportType {
|
||||
&TransportType::UDP
|
||||
}
|
||||
fn state(&self) -> TransportState {
|
||||
TransportState::Up
|
||||
}
|
||||
fn mtu(&self) -> u16 {
|
||||
self.mtu_value
|
||||
}
|
||||
fn start(&mut self) -> Result<(), TransportError> {
|
||||
Ok(())
|
||||
}
|
||||
fn stop(&mut self) -> Result<(), TransportError> {
|
||||
Ok(())
|
||||
}
|
||||
fn send(&self, _addr: &TransportAddr, _data: &[u8]) -> Result<(), TransportError> {
|
||||
Ok(())
|
||||
}
|
||||
fn discover(&self) -> Result<Vec<DiscoveredPeer>, TransportError> {
|
||||
Ok(vec![])
|
||||
}
|
||||
}
|
||||
|
||||
/// Mock transport that overrides link_mtu() to return per-link values.
|
||||
struct PerLinkMtuTransport {
|
||||
id: TransportId,
|
||||
default_mtu: u16,
|
||||
/// Address-specific MTU overrides.
|
||||
overrides: Vec<(TransportAddr, u16)>,
|
||||
}
|
||||
|
||||
impl PerLinkMtuTransport {
|
||||
fn new(default_mtu: u16, overrides: Vec<(TransportAddr, u16)>) -> Self {
|
||||
Self {
|
||||
id: TransportId::new(100),
|
||||
default_mtu,
|
||||
overrides,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Transport for PerLinkMtuTransport {
|
||||
fn transport_id(&self) -> TransportId {
|
||||
self.id
|
||||
}
|
||||
fn transport_type(&self) -> &TransportType {
|
||||
&TransportType::UDP
|
||||
}
|
||||
fn state(&self) -> TransportState {
|
||||
TransportState::Up
|
||||
}
|
||||
fn mtu(&self) -> u16 {
|
||||
self.default_mtu
|
||||
}
|
||||
fn link_mtu(&self, addr: &TransportAddr) -> u16 {
|
||||
for (a, mtu) in &self.overrides {
|
||||
if a == addr {
|
||||
return *mtu;
|
||||
}
|
||||
}
|
||||
self.mtu()
|
||||
}
|
||||
fn start(&mut self) -> Result<(), TransportError> {
|
||||
Ok(())
|
||||
}
|
||||
fn stop(&mut self) -> Result<(), TransportError> {
|
||||
Ok(())
|
||||
}
|
||||
fn send(&self, _addr: &TransportAddr, _data: &[u8]) -> Result<(), TransportError> {
|
||||
Ok(())
|
||||
}
|
||||
fn discover(&self) -> Result<Vec<DiscoveredPeer>, TransportError> {
|
||||
Ok(vec![])
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_link_mtu_default_falls_back_to_mtu() {
|
||||
let transport = MockTransport::new(1280);
|
||||
let addr = TransportAddr::from_string("192.168.1.1:4000");
|
||||
|
||||
// Default link_mtu() should return the transport-wide mtu()
|
||||
assert_eq!(transport.link_mtu(&addr), 1280);
|
||||
assert_eq!(transport.link_mtu(&addr), transport.mtu());
|
||||
|
||||
// Any address should return the same value
|
||||
let other_addr = TransportAddr::from_string("10.0.0.1:5000");
|
||||
assert_eq!(transport.link_mtu(&other_addr), 1280);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_link_mtu_per_link_override() {
|
||||
let addr_a = TransportAddr::from_string("192.168.1.1:4000");
|
||||
let addr_b = TransportAddr::from_string("10.0.0.1:5000");
|
||||
let addr_unknown = TransportAddr::from_string("172.16.0.1:6000");
|
||||
|
||||
let transport = PerLinkMtuTransport::new(
|
||||
1280,
|
||||
vec![(addr_a.clone(), 512), (addr_b.clone(), 247)],
|
||||
);
|
||||
|
||||
// Known addresses return their per-link MTU
|
||||
assert_eq!(transport.link_mtu(&addr_a), 512);
|
||||
assert_eq!(transport.link_mtu(&addr_b), 247);
|
||||
|
||||
// Unknown address falls back to transport-wide default
|
||||
assert_eq!(transport.link_mtu(&addr_unknown), 1280);
|
||||
assert_eq!(transport.mtu(), 1280);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_transport_handle_link_mtu_delegation() {
|
||||
use crate::config::UdpConfig;
|
||||
use crate::transport::udp::UdpTransport;
|
||||
|
||||
let config = UdpConfig::default();
|
||||
let expected_mtu = config.mtu();
|
||||
let (tx, _rx) = packet_channel(1);
|
||||
let transport = UdpTransport::new(TransportId::new(1), None, config, tx);
|
||||
let handle = TransportHandle::Udp(transport);
|
||||
|
||||
let addr = TransportAddr::from_string("192.168.1.1:4000");
|
||||
|
||||
// TransportHandle::link_mtu() should delegate and return the same
|
||||
// as TransportHandle::mtu() for UDP (no per-link overrides)
|
||||
assert_eq!(handle.link_mtu(&addr), expected_mtu);
|
||||
assert_eq!(handle.link_mtu(&addr), handle.mtu());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user