1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
//! Configuration shared by every routing role.
use crate::DataType;
#[cfg(feature = "discovery")]
use crate::discovery;
use crate::router::{
CompactTimestampOmissionPolicy, DEFAULT_SIDE_TRANSPORT_TEMPLATE_LIMIT,
IPV4_LIKE_COMPACT_HEADER_TARGET_BYTES, IPV6_LIKE_COMPACT_HEADER_TARGET_BYTES,
SideTransportProfile,
};
#[derive(Clone, Debug)]
pub struct SideOptions {
/// Enables the router's per-link reliable transport layer on this side.
///
/// When `true` and the side uses a packed TX handler, reliable schema types gain
/// sequence numbers, ACKs, packet requests, and retransmits on this specific hop.
/// When `false`, the router strips the reliable framing for that side and sends only the
/// application packet payload once.
///
/// This setting only affects the hop between this router and the side's TX callback. It does
/// not change whether a schema `DataType` is defined as reliable, and it does not disable the
/// router's end-to-end reliable tracking for packets originated elsewhere in the network.
pub reliable_enabled: bool,
/// Marks the side as eligible for link-local-only endpoints and discovery routes.
pub link_local_enabled: bool,
/// Enables a side-local header-template dictionary for packed transport.
///
/// The first frame for a stable header shape is sent in full. Later frames
/// on the same side can replace the repeated static header bytes with a
/// compact template hash plus only the fields that still vary packet to
/// packet.
pub header_template_enabled: bool,
/// Maximum number of bytes to emit per packed TX callback.
///
/// When non-zero and a wrapped packed frame would exceed this size, the
/// router splits it into ordered chunks and reassembles those chunks on RX
/// before normal packet processing.
pub max_frame_bytes: usize,
/// Target total side-transport overhead for compact follow-up frames.
///
/// This is a profiling/negotiation target rather than a hard limit. The
/// canonical packet is still reconstructed before normal router handling,
/// so constrained links should watch runtime stats to confirm compact
/// frames are meeting their IPv4/IPv6-like overhead budget.
pub compact_header_target_bytes: usize,
/// Maximum side-local header templates retained for TX and RX dictionaries.
///
/// This keeps compact-link state bounded. When the dictionary is full, the
/// oldest deterministic entry is evicted and a later packet with that
/// shape will refresh the receiver with a full template frame.
pub max_side_transport_templates: usize,
/// Omits the timestamp field from compact follow-up frames when it is unchanged.
///
/// The receiver reconstructs the canonical packet from the previous timestamp for that
/// side-local template. This is only used after a full or compact frame has established
/// timestamp context.
pub omit_unchanged_compact_timestamps: bool,
/// Optional per-data-type timestamp omission policy for compact follow-up frames.
///
/// This allows a side to omit unchanged timestamps only for selected traffic while keeping
/// absolute/delta timestamps for other data types on the same link.
pub compact_timestamp_omission_types: CompactTimestampOmissionPolicy,
/// Declared compact-link profile for stats and future negotiation.
pub side_transport_profile: SideTransportProfile,
/// Allows packets received from this side to enter router processing.
pub ingress_enabled: bool,
/// Allows the router to transmit packets toward this side.
pub egress_enabled: bool,
}
impl Default for SideOptions {
fn default() -> Self {
Self {
reliable_enabled: false,
link_local_enabled: false,
header_template_enabled: false,
max_frame_bytes: 0,
compact_header_target_bytes: 0,
max_side_transport_templates: DEFAULT_SIDE_TRANSPORT_TEMPLATE_LIMIT,
omit_unchanged_compact_timestamps: false,
compact_timestamp_omission_types: CompactTimestampOmissionPolicy::none(),
side_transport_profile: SideTransportProfile::Canonical,
ingress_enabled: true,
egress_enabled: true,
}
}
}
impl SideOptions {
/// Convenience preset for compact packed-side transport.
///
/// This enables header-template reuse and, when `max_frame_bytes > 0`,
/// router-managed chunking/reassembly for fixed-size transports.
#[inline]
pub fn with_small_packet_transport(mut self, max_frame_bytes: usize) -> Self {
self.header_template_enabled = true;
self.max_frame_bytes = max_frame_bytes;
self.compact_header_target_bytes = IPV6_LIKE_COMPACT_HEADER_TARGET_BYTES;
self.side_transport_profile = SideTransportProfile::Ipv6Like;
self
}
#[inline]
pub fn with_ipv4_like_compact_header_target(mut self) -> Self {
self.header_template_enabled = true;
self.compact_header_target_bytes = IPV4_LIKE_COMPACT_HEADER_TARGET_BYTES;
self.omit_unchanged_compact_timestamps = true;
self.side_transport_profile = SideTransportProfile::Ipv4Like;
self
}
#[inline]
pub fn with_ipv6_like_compact_header_target(mut self) -> Self {
self.header_template_enabled = true;
self.compact_header_target_bytes = IPV6_LIKE_COMPACT_HEADER_TARGET_BYTES;
self.side_transport_profile = SideTransportProfile::Ipv6Like;
self
}
#[inline]
pub fn with_template_transport(mut self) -> Self {
self.header_template_enabled = true;
self.side_transport_profile = SideTransportProfile::Template;
self
}
#[inline]
pub fn with_omitted_unchanged_compact_timestamps(mut self) -> Self {
self.header_template_enabled = true;
self.omit_unchanged_compact_timestamps = true;
self
}
#[inline]
pub fn with_omitted_unchanged_compact_timestamps_for_type(mut self, ty: DataType) -> Self {
self.header_template_enabled = true;
self.compact_timestamp_omission_types.insert(ty);
self
}
#[inline]
pub fn effective_transport_profile(&self) -> SideTransportProfile {
if !self.header_template_enabled && self.max_frame_bytes == 0 {
SideTransportProfile::Canonical
} else if self.side_transport_profile == SideTransportProfile::Canonical {
SideTransportProfile::Template
} else {
self.side_transport_profile
}
}
#[cfg(feature = "discovery")]
#[inline]
pub fn link_capabilities(&self) -> discovery::LinkCapabilities {
let mut flags = discovery::LINK_CAPABILITY_END_TO_END_RELIABILITY;
if self.header_template_enabled {
flags |= discovery::LINK_CAPABILITY_HEADER_TEMPLATES;
}
if self.max_frame_bytes != 0 {
flags |= discovery::LINK_CAPABILITY_CHUNKING;
}
if self.reliable_enabled {
flags |= discovery::LINK_CAPABILITY_RELIABILITY;
}
if self.omit_unchanged_compact_timestamps
|| !self.compact_timestamp_omission_types.is_empty()
{
flags |= discovery::LINK_CAPABILITY_OMIT_UNCHANGED_TIMESTAMPS;
}
#[cfg(feature = "cryptography")]
{
flags |= discovery::LINK_CAPABILITY_CRYPTO;
}
#[cfg(feature = "compression")]
{
flags |= discovery::LINK_CAPABILITY_PAYLOAD_COMPRESSION;
}
discovery::LinkCapabilities {
version: 1,
flags,
profile: self.effective_transport_profile().discovery_code(),
max_frame_bytes: self.max_frame_bytes.min(u32::MAX as usize) as u32,
compact_header_target_bytes: self.compact_header_target_bytes.min(u32::MAX as usize)
as u32,
max_side_transport_templates: self.max_side_transport_templates.min(u32::MAX as usize)
as u32,
}
}
}
/// Immutable internal presets for the shared engine. Public compatibility
/// facades choose a preset; forwarding can never grant application ownership.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) enum RoutingRole {
Router,
Relay,
}
impl RoutingRole {
pub(crate) fn local_services(self) -> bool {
self == Self::Router
}
}