Control Plane (UDP)¶
Control-plane operations are UDP-only and market-data-only.
Order routing has no control-plane channel in this version.
Use this plane for non-hot-path actions:
- Runtime subscription changes
- On-demand snapshot requests
Market and order messages still flow on SHM rings.
Scope¶
- Plane scope: one control-plane endpoint per
stack(masterornightly) - Data scope: one venue per request (set in request header)
- ID scope:
inst_idonly (resolve canonical keys through metadata before sending control requests)
Transport contract¶
- Protocol: UDP unicast
- Reliability: best-effort, client retries required
- Encoding: little-endian packed binary
- Maximum datagram size: 1200 bytes (never rely on IP fragmentation)
Endpoint configuration is in feedd config:
bind_host/bind_port identify the UDP listener for control-plane requests for that stack.
Control-plane payloads are packed exactly as documented below. Do not assume native struct alignment; parse by offset and payload_len.
Wire format¶
Request header (32 bytes)¶
offset size type field
────────────────────────────────────────────
0 2 u16 version protocol version (currently 1)
2 1 u8 op 1=SUBSCRIBE, 2=UNSUBSCRIBE, 3=REQUEST_SNAPSHOT
3 1 u8 stack 1=master, 2=nightly
4 1 u8 venue venue ID from metadata registry
5 1 u8 flags request flags (currently 0)
6 2 u16 payload_len bytes after header
8 8 u64 client_id stable sender identity
16 8 u64 request_id idempotency key per client_id
24 8 u64 send_ts_ns client timestamp (optional; 0 allowed)
────────────────────────────────────────────
Response header (32 bytes)¶
offset size type field
────────────────────────────────────────────
0 2 u16 version protocol version (currently 1)
2 1 u8 op echoes request op
3 1 u8 stack echoes request stack
4 1 u8 venue echoes request venue
5 1 u8 status 0=OK, non-zero=error code
6 2 u16 payload_len bytes after header
8 8 u64 client_id echoes request client_id
16 8 u64 request_id echoes request request_id
24 8 u64 recv_ts_ns feedd receive timestamp
────────────────────────────────────────────
Status / error codes¶
| Code | Name | Meaning |
|---|---|---|
| 0 | OK |
Request accepted |
| 1 | BAD_VERSION |
Unsupported control-plane version |
| 2 | UNKNOWN_OP |
Invalid op code |
| 3 | BAD_PAYLOAD |
Malformed payload or invalid size |
| 4 | UNKNOWN_INSTRUMENT |
inst_id not present/active in metadata |
| 5 | VENUE_UNAVAILABLE |
Venue disconnected or unavailable |
| 6 | RATE_LIMITED |
Snapshot/control rate limit exceeded |
| 7 | TOO_MANY_ITEMS |
Instrument list exceeds server limit |
| 8 | INTERNAL |
Internal error |
Operations¶
subscribe¶
Add one or more instruments for one venue.
Payload:
offset size type field
────────────────────────────────────────
0 2 u16 n_inst
2 ... u64[n_inst] inst_ids
Rules:
- Atomic apply: any invalid
inst_idrejects the full request (UNKNOWN_INSTRUMENT) - Idempotent: re-subscribing an already subscribed instrument is accepted (no-op for that instrument)
n_instmust be greater than 0
Success response payload:
offset size type field
────────────────────────────────────────
0 2 u16 applied_count
2 8 u64 apply_seq_hint
apply_seq_hint is an advisory md-ring sequence watermark. First updates for newly subscribed instruments are published at seq >= apply_seq_hint.
unsubscribe¶
Remove one or more instruments for one venue.
Payload:
offset size type field
────────────────────────────────────────
0 2 u16 n_inst
2 ... u64[n_inst] inst_ids
Rules:
- Idempotent: unsubscribing an instrument not currently active is accepted (no-op for that instrument)
n_instmust be greater than 0
Success response payload:
offset size type field
────────────────────────────────────────
0 2 u16 applied_count
2 8 u64 drain_seq_hint
drain_seq_hint is an advisory watermark. After consumer processes md messages up to this seq, no new updates for removed instruments should arrive (except already-published frames before the cutover).
request_snapshot¶
Request a fresh snapshot for one instrument.
Payload:
offset size type field
────────────────────────────────────────
0 8 u64 inst_id
8 1 u8 snap_type 1=L2_BOOK, 2=L4_ORDERS
9 2 u16 depth 0=full depth, else top N
11 4 u32 timeout_ms advisory; 0 uses server default
Success response payload:
accepted_seq is the md sequence watermark when the request was accepted.
Completion path:
- Client receives
OKresponse forrequest_snapshot feeddpublishesSNAPSHOT_REFon/sorcery-{stack}-md- Client reads snapshot bytes from
/sorcery-{stack}-snapshotand verifies checksum
Correlation rule:
SNAPSHOT_REFdoes not carryrequest_id- Correlate by
(venue, inst_id, snap_type, depth)andsnap_seq >= accepted_seq - Multiple outstanding requests for the same tuple may be coalesced by
feedd
Operational limits¶
These limits are part of the control-plane contract:
payload_lenMUST be<= 1100bytes (BAD_PAYLOADotherwise).subscribe/unsubscriben_instMUST be in[1, 128](TOO_MANY_ITEMSif exceeded,BAD_PAYLOADif zero).request_snapshot.timeout_ms:0means server default1500ms- accepted range is
[10, 10000](BAD_PAYLOADoutside range) - For identical snapshot tuples
(venue, inst_id, snap_type, depth), servers MAY coalesce concurrent requests.
Idempotency and retries¶
Deduplication key: (client_id, request_id).
Server behavior:
- Same key + same payload: return cached prior response
- Same key + different payload: reject with
BAD_PAYLOAD
Client policy:
- Use monotone
request_idperclient_id - Retry with bounded exponential backoff + jitter
- Recommended backoff envelope:
10msinitial,x2, cap250ms, max8attempts - Treat timeout as unknown outcome and retry with the same
(client_id, request_id)pair - Escalate after bounded retry budget exhaustion
Failure handling¶
Clients must handle:
- Lost requests
- Lost responses
- Duplicate responses
- Out-of-order responses
Recovery rules:
- On
request_snapshottimeout or error, keep affected bookINVALID - Continue draining md ring while retrying snapshot request
- Resume normal book use only after applying a valid
SNAPSHOT_REF