STCPv8 — runtime module parameters and socket options
This reference describes the public module parameters and SOL_STCP socket
options in the supplied Linux/Raspberry Pi implementation. Zephyr Kconfig is
a separate interface. An installed module may come from another revision:
check modinfo stcp and /sys/module/stcp/parameters/ on the target.
1. Runtime module parameters
Parameters belong to the module instance on each machine. Configure Linux
and Raspberry Pi separately. All parameters below have sysfs permissions
0644: readable by other users and writable by root.
# Read the running module's parameter values.
for p in /sys/module/stcp/parameters/*; do
printf '%s = ' "${p##*/}"
cat "$p"
done
# Change settings without reloading the module.
printf '2\n' | sudo tee /sys/module/stcp/parameters/default_compression_level
printf 'Y\n' | sudo tee /sys/module/stcp/parameters/verbose_debug
# Disable additional diagnostics.
printf 'N\n' | sudo tee /sys/module/stcp/parameters/verbose_debug
Boolean parameters accept values such as Y/N and 1/0. Runtime sysfs
changes do not survive a module reload or reboot.
| Parameter | Type / default | Accepted or recommended values | Effect |
|---|---|---|---|
default_compression_level |
unsigned int, 3 |
1..5; other values rejected |
Maximum compression effort for adaptive AUTO sockets. The selected level is recomputed from each payload, within this ceiling. Existing default-following sockets refresh the ceiling on their next sendmsg() call. Does not enable compression or override explicit socket levels. |
verbose_debug |
bool, N |
Y / N |
Enables additional RX/TX and hot-path diagnostics for subsequent events. Does not suppress all other STCP logging or reset finite trace budgets. Logging can affect CPU load and benchmark results. |
drop_percent |
unsigned int, 0 |
Recommended 0..100; higher values are accepted but treated as 100 |
Deterministically drops a proportion of outgoing STCP-UDP DATA frames. 0 disables this drop policy. Changes also affect existing UDP connections. |
drop_first_data |
bool, N |
Y / N |
One-shot UDP DATA drop test. Its event budget is armed only during module initialization. |
duplicate_first_data |
bool, N |
Y / N |
One-shot UDP DATA duplication test. Its event budget is armed only during module initialization. |
reorder_first_pair |
bool, N |
Y / N |
Holds one UDP DATA frame and sends the next DATA frame first. Its event budget is armed only during module initialization. |
delay_first_data_ms |
unsigned int, 0 |
Milliseconds; 0 means no delay. No separate small upper bound. |
Delays one UDP DATA send with msleep(). The budget is armed at load time if the value is nonzero. Large values can exceed test or connection deadlines. |
OFF, AUTO and a socket-specific level
- OFF: no compression attempt is made and outgoing content is not compressed. A stored compression level does not enable compression.
- Adaptive AUTO: the socket samples each eligible payload and selects no compression or a suitable level. The module default is an effort ceiling, not the level used for every payload. Peer support and the size threshold are checked before sampling.
- AUTO with an explicit level: the socket uses its own selected level. Changes to the module default do not override it. AUTO still sends the original content if compression would not reduce its size.
- Setting a level does not change OFF/AUTO mode. Switching from OFF to AUTO preserves an explicitly selected socket-specific level.
Even in OFF mode, the implementation may refresh the stored level metadata
of a default-following socket at its next send. This does not call the
compression function: CompressionConfig::should_try() always requires AUTO.
Traffic adaptation in AUTO
With the AUTO adaptation update installed, each eligible outgoing payload is sampled independently. Four distributed 32-byte slices are compressed with level 1 to estimate compressibility. The sample selects no compression or a level from L1 to L5. The module default sets the maximum permitted effort: default 3 permits no compression or L1–L3; default 5 permits the full range. This ceiling only applies to sockets without an explicit user-selected level.
An explicit socket level bypasses adaptive sampling and remains fixed. OFF bypasses both sampling and compression. Peer support and the configured size threshold are checked before any sample. Eligible payloads shorter than the 128-byte probe use the configured level directly. The final representation must still be smaller than the original, including its length prefix.
The selection is recomputed for each frame payload, so changing traffic can move from compression to no compression and back without reconnecting. It is a compressibility heuristic, not RTT, bandwidth, energy or CPU-feedback control. The sample's compressed-size bands are: >=126 bytes = skip; 109–125 = L1; 77–108 = L2; 39–76 = L3; 13–38 = L4; <13 = L5, before applying the ceiling.
Deployment scope: this behaviour requires the Linux/Raspberry AUTO
adaptation source update and a rebuild/reload of the module. Older revisions
may define auto_sample_level() without calling it from the send path.
The update does not automatically change Zephyr's separate source copy.
Compression levels
| Value | Name |
|---|---|
| 1 | VeryFast |
| 2 | Fast |
| 3 | Default |
| 4 | High |
| 5 | VeryHigh |
These names describe compression effort, not guaranteed throughput or compression ratios. Measure CPU cost and byte counts with representative data.
Once an application sets STCP_SO_COMPRESSION_LEVEL, that socket stops
following the module default. Explicitly setting 3 also pins level 3;
it does not mean “follow the default.” This implementation has no separate
socket option to restore default-following mode.
getsockopt() reads the socket's cached level, so a changed module default
may only become visible there after the next send.
UDP fault injection: writable does not always mean re-armable
The one-shot drop, duplicate, reorder and delay budgets are shared by the whole module, not allocated per connection. A budget armed at load time is consumed by the first eligible DATA send, which may belong to another socket. These controls do not affect TCP-carrier traffic or handshake frames.
Writing Y to drop_first_data after loading does not re-arm an exhausted
budget. Toggling N → Y does not reset it either. The percentage-drop sequence
counter continues across runtime changes and resets at module initialization.
The drop condition is ((sequence * 37) % 100) < percent, not a random generator.
Injection order is drop, delay, reorder, then duplicate. A dropped frame does not consume budgets for the later stages. Boolean parameters control entry into the shared test path, while individual events consume atomic budgets. Consequently, disabling one boolean does not necessarily prevent its still armed event if another injection keeps the shared path active. Disable all injections to return to the normal send path. This does not reset a frame already held for reordering.
Run one-shot tests through a controlled module reload with no active STCP sockets, for example in an isolated test session:
sudo modprobe -r stcp
sudo modprobe stcp drop_first_data=1
# Run the UDP test, then restore normal module load settings.
A continuous loss policy can be changed at runtime:
printf '10\n' | sudo tee /sys/module/stcp/parameters/drop_percent
# Run the test, then disable this drop policy.
printf '0\n' | sudo tee /sys/module/stcp/parameters/drop_percent
To persist normal defaults, add /etc/modprobe.d/stcp.conf:
options stcp default_compression_level=3 verbose_debug=0
This file applies to the next modprobe load; a direct insmod does not read it.
2. Socket interface
Linux/Raspberry Pi IPv4 sockets:
socket(45 /* AF_STCP */, SOCK_STREAM, 253 /* STCP-TCP */);
socket(45 /* AF_STCP */, SOCK_STREAM, 254 /* STCP-UDP */);
STCP-UDP also uses SOCK_STREAM in this module's public socket API.
Addresses use IPv4 sockaddr_in with sin_family=AF_INET.
Socket options use SOL_STCP = 45. The option level and socket family
are distinct identifiers even though their numeric values match.
Strace may label family 45 as AF_MCTP; also check socket type and protocol.
Options
| Option | Number | Access | Values / default | Purpose |
|---|---|---|---|---|
STCP_SO_COMPRESSION |
1 | set/get | int: 0 = OFF, 1 = AUTO; default 0 |
Allows compression attempts on future outgoing frames. Other values are rejected. |
STCP_SO_COMPRESSION_THRESHOLD |
2 | set/get | int: 0..INT_MAX bytes; default 1024 |
Minimum plaintext size of an internal frame payload for a compression attempt. 0 allows an attempt for every outgoing payload chunk. |
STCP_SO_COMPRESSION_STATS |
3 | get only | 10 × u64, 80 bytes total | Snapshot of this socket's compression counters. No reset/set option. |
STCP_SO_COMPRESSION_LEVEL |
4 | set/get | int: 1..5; default is adaptive AUTO with the current module effort ceiling |
Selects a fixed level for this socket and bypasses adaptive level selection. |
Integer options use a native C int in a buffer at least sizeof(int) bytes
long. They are neither strings nor network-byte-order integers. An unsupported
level/option identifier returns ENOPROTOOPT; an invalid value or undersized
buffer returns EINVAL; an invalid user-memory address can return EFAULT.
Settings are socket-specific. An accepted child inherits compression enablement, threshold and explicit/default-following level policy from its listener at accept time. A default-following child takes the module default current at accept. Later listener changes do not update already accepted children; configure those child sockets separately when needed.
Changing settings on a connected socket affects future compression choices, not frames already queued. Separate option calls do not form an atomic configuration update. Set them before starting the sending thread when an intermediate configuration would be undesirable.
AUTO only attempts compression when the peer advertised support and the frame payload reaches the threshold. The compressed representation is selected only if it is smaller than the original, including its original-length prefix. Otherwise the original content is sent. Compression and encryption are separate: OFF does not disable STCP encryption. Disabling outgoing compression does not prevent decompression of compressed frames received from the peer.
C example
#include <stdint.h>
#include <sys/socket.h>
/* fd is an STCP socket. Check the return value of every call. */
int threshold = 128, level = 3, enabled = 1;
if (setsockopt(fd, 45, 2, &threshold, sizeof threshold) < 0) { /* handle error */ }
if (setsockopt(fd, 45, 4, &level, sizeof level) < 0) { /* handle error */ }
if (setsockopt(fd, 45, 1, &enabled, sizeof enabled) < 0) { /* handle error */ }
/* The level call pins level 3. Omit it to follow the module default. */
int current_level;
socklen_t len = sizeof current_level;
if (getsockopt(fd, 45, 4, ¤t_level, &len) < 0) { /* handle error */ }
Python example
import socket
import struct
SOL_STCP = 45
with socket.socket(45, socket.SOCK_STREAM, 253) as sock:
sock.setsockopt(SOL_STCP, 2, 128) # threshold
sock.setsockopt(SOL_STCP, 4, 3) # explicit socket-specific level
sock.setsockopt(SOL_STCP, 1, 1) # AUTO
print('Compression level:', sock.getsockopt(SOL_STCP, 4))
fields = (
'tx_attempts', 'tx_compressed_frames', 'tx_fallback_frames',
'tx_input_bytes', 'tx_wire_bytes', 'tx_errors',
'rx_compressed_frames', 'rx_wire_bytes', 'rx_output_bytes', 'rx_errors',
)
raw = sock.getsockopt(SOL_STCP, 3, 80)
stats = dict(zip(fields, struct.unpack('=10Q', raw)))
print(stats)
This illustrates options only. Add connect/bind/listen and actual traffic as required. Counters on a new unused socket are zero. Python's custom-family bind/accept needs the libc handling provided by FreeSDK; this example does not perform address operations.
3. Compression counters and interpretation
The ABI field order is shown below. Each field is a native unsigned 64-bit
integer (unsigned long long), not a packed network-format value.
| Field | Meaning |
|---|---|
tx_attempts |
Full payload compression attempts after capability, mode, threshold and adaptive selection. Probe-only rejections are not included. |
tx_compressed_frames |
Attempts that selected a smaller compressed representation. |
tx_fallback_frames |
Attempts that used the original content. |
tx_input_bytes |
Original payload bytes for frames on which compression was attempted. |
tx_wire_bytes |
Selected representation bytes for those attempts: compressed content including its length prefix, or original fallback content. |
tx_errors |
Compression-function errors; sending can still continue using the original content. |
rx_compressed_frames |
Successfully decompressed compressed frames. |
rx_wire_bytes |
Compressed content bytes for those frames, including the length prefix. |
rx_output_bytes |
Original bytes recovered from those frames. |
rx_errors |
Errors handling compressed content. Not a general counter of every socket or network failure. |
tx_wire_bytes and rx_wire_bytes do not include all bytes on the network:
STCP headers, encryption tags and lower-layer protocol headers are outside
these counters. OFF-mode sends and payloads below the threshold do not increment
TX compression-attempt byte counters. RX byte counters cover compressed frames,
so the populations counted by TX and RX are not generally symmetric.
For TX data on which compression was attempted, when the denominator is > 0:
content_saving_percent = 100 × (1 − tx_wire_bytes / tx_input_bytes)
This is not the whole connection's network-byte saving or a direct throughput change. Later send failures do not necessarily roll back attempt counters already updated.
4. Source basis and scope
Checked against the supplied Linux/Raspberry Pi source tree:
kernel/module/src/stcp_module.c: parameters, validation and injection budgets.kernel/module/src/stcp_carrier.c: verbose diagnostics and UDP injection send path.kernel/module/include/stcp.h: option identifiers, defaults and counter layout.kernel/module/src/stcp_ops.c: set/get validation, level refresh and accept inheritance.kernel/module/src/stcp_proto.c: socket initialization.kernel/module/rust/src/session.rsandcompression.rs: compression selection and counters.
The reported socket level is the configured AUTO effort ceiling or the explicit fixed level, not the last sampled selection. Sample-only rejections do not increment TX attempt/input/wire/fallback counters.
This reference is based on source inspection. Sysfs writes and socket calls were not executed on hardware during documentation work. If the current checkout differs from the supplied source, review these locations before publication. Constants such as the 5000 ms handshake timeout are compile-time settings in this source, not module parameters or SOL_STCP options listed here.