Compare commits
3 Commits
53516b094c
...
be108ccc32
| Author | SHA1 | Date |
|---|---|---|
|
|
be108ccc32 | |
|
|
ff2b20b7d1 | |
|
|
caf9c3d6d3 |
|
|
@ -92,12 +92,6 @@ jobs:
|
||||||
timeout-minutes: 16
|
timeout-minutes: 16
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
# XXX the `tipc` leg stays NON-blocking until the `modprobe`
|
|
||||||
# step below is proven stable on GH's runners; flip this off
|
|
||||||
# once it's had a few green runs. See plan 01 §7.3 in
|
|
||||||
# `ai/tpt-backends/01_tipc_backend.md`.
|
|
||||||
continue-on-error: ${{ matrix.tpt_proto == 'tipc' }}
|
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
---
|
||||||
|
model: openai/gpt-5.6-sol
|
||||||
|
service: opencode
|
||||||
|
session: a998acff-af66-4969-a65e-f77cbf5ef8dd
|
||||||
|
timestamp: 2026-08-19T00:33:26Z
|
||||||
|
git_ref: wkt/tipc_backend_378
|
||||||
|
scope: config
|
||||||
|
substantive: true
|
||||||
|
raw_file: 20260819T003326Z_53516b09_prompt_io.raw.md
|
||||||
|
---
|
||||||
|
|
||||||
|
## Prompt
|
||||||
|
|
||||||
|
Confirm whether the successful TIPC CI leg can become blocking.
|
||||||
|
|
||||||
|
## Response summary
|
||||||
|
|
||||||
|
Removed the temporary TIPC-only `continue-on-error` expression after
|
||||||
|
every refreshed PR #493 check passed.
|
||||||
|
|
||||||
|
## Files changed
|
||||||
|
|
||||||
|
- `.github/workflows/ci.yml` - make TIPC failures block CI.
|
||||||
|
|
||||||
|
## Human edits
|
||||||
|
|
||||||
|
The human explicitly requested reconsidering the gate after the CI
|
||||||
|
run and chose to leave the generated change local for review before
|
||||||
|
requesting this commit plan.
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
---
|
||||||
|
model: openai/gpt-5.6-sol
|
||||||
|
service: opencode
|
||||||
|
timestamp: 2026-08-19T00:33:26Z
|
||||||
|
git_ref: wkt/tipc_backend_378
|
||||||
|
diff_cmd: git diff HEAD~1..HEAD
|
||||||
|
---
|
||||||
|
|
||||||
|
## Prompt
|
||||||
|
|
||||||
|
The user asked whether the now-green TIPC CI leg could stop using
|
||||||
|
`continue-on-error`.
|
||||||
|
|
||||||
|
## Response
|
||||||
|
|
||||||
|
All checks on PR #493 passed, including the Ubuntu TIPC matrix job.
|
||||||
|
The generated config change removes the temporary non-blocking gate
|
||||||
|
and its obsolete explanatory comment:
|
||||||
|
|
||||||
|
> `git diff HEAD~1..HEAD -- .github/workflows/ci.yml`
|
||||||
|
|
||||||
|
The remaining matrix, Linux-only exclusion and `modprobe tipc` setup
|
||||||
|
stay unchanged.
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
---
|
||||||
|
model: openai/gpt-5.6-sol
|
||||||
|
service: opencode
|
||||||
|
session: a998acff-af66-4969-a65e-f77cbf5ef8dd
|
||||||
|
timestamp: 2026-08-19T00:33:27Z
|
||||||
|
git_ref: wkt/tipc_backend_378
|
||||||
|
scope: code
|
||||||
|
substantive: true
|
||||||
|
raw_file: 20260819T003327Z_53516b09_prompt_io.raw.md
|
||||||
|
---
|
||||||
|
|
||||||
|
## Prompt
|
||||||
|
|
||||||
|
Develop a practical bootstrap plan for testing TIPC across two
|
||||||
|
physical motherboards.
|
||||||
|
|
||||||
|
## Response summary
|
||||||
|
|
||||||
|
Expanded the two-host example into a reproducible smoke-test runbook
|
||||||
|
and made host A authorize the stable module name imported by host B.
|
||||||
|
Documented the cluster-domain-socket analogy and the prospective
|
||||||
|
`pyroute2` management path.
|
||||||
|
|
||||||
|
## Files changed
|
||||||
|
|
||||||
|
- `examples/multihost/tipc_cluster/README.md` - document setup,
|
||||||
|
validation, resilience testing, capture and cleanup.
|
||||||
|
- `examples/multihost/tipc_cluster/host_a_srv.py` - authorize the
|
||||||
|
`host_a_srv` RPC module under direct script execution.
|
||||||
|
|
||||||
|
## Human edits
|
||||||
|
|
||||||
|
The human selected two separate physical motherboards as the target
|
||||||
|
environment and requested that the resulting local work be packaged
|
||||||
|
as its own commit boundary. The human also proposed “Cluster Domain
|
||||||
|
Sockets” as clearer terminology and reusing the planned `pyroute2`
|
||||||
|
dependency for TIPC management.
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
---
|
||||||
|
model: openai/gpt-5.6-sol
|
||||||
|
service: opencode
|
||||||
|
timestamp: 2026-08-19T00:33:27Z
|
||||||
|
git_ref: wkt/tipc_backend_378
|
||||||
|
diff_cmd: git diff HEAD~1..HEAD
|
||||||
|
---
|
||||||
|
|
||||||
|
## Prompt
|
||||||
|
|
||||||
|
The user asked for a bootstrap plan to try TIPC with two real,
|
||||||
|
physically separate Linux motherboards.
|
||||||
|
|
||||||
|
## Response
|
||||||
|
|
||||||
|
The generated changes turn the existing sketch into an operator
|
||||||
|
runbook and correct the RPC module authorization used by direct
|
||||||
|
script execution:
|
||||||
|
|
||||||
|
> `git diff HEAD~1..HEAD -- examples/multihost/tipc_cluster/README.md examples/multihost/tipc_cluster/host_a_srv.py`
|
||||||
|
|
||||||
|
The runbook covers matching revisions, cluster identity, interface
|
||||||
|
selection, Ethernet bearer setup, link and name-table validation,
|
||||||
|
RPC, failure/rejoin testing, diagnostics, cleanup and a future
|
||||||
|
network-namespace fixture. It also records “Cluster Domain Sockets”
|
||||||
|
as explanatory terminology and identifies a future `pyroute2` TIPC
|
||||||
|
generic-netlink codec as the path away from manual `tipc(8)` calls.
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
---
|
||||||
|
model: openai/gpt-5.6-sol
|
||||||
|
service: opencode
|
||||||
|
session: a998acff-af66-4969-a65e-f77cbf5ef8dd
|
||||||
|
timestamp: 2026-08-19T00:33:28Z
|
||||||
|
git_ref: wkt/tipc_backend_378
|
||||||
|
scope: docs
|
||||||
|
substantive: true
|
||||||
|
raw_file: 20260819T003328Z_53516b09_prompt_io.raw.md
|
||||||
|
---
|
||||||
|
|
||||||
|
## Prompt
|
||||||
|
|
||||||
|
Draft an upstream `/tipc` multiaddr issue modeled on the prior `wg`
|
||||||
|
proposal.
|
||||||
|
|
||||||
|
## Response summary
|
||||||
|
|
||||||
|
Added a reviewable upstream issue draft with a concrete binary and
|
||||||
|
text encoding, composition examples, rollout plan and open design
|
||||||
|
questions. Retained the ecosystem-standard `tipc` name while using
|
||||||
|
“Cluster Domain Sockets” as explanatory terminology, and separated
|
||||||
|
the future `pyroute2` management track from address encoding.
|
||||||
|
|
||||||
|
## Files changed
|
||||||
|
|
||||||
|
- `ai/tpt-backends/04_tipc_multiaddr_upstream.md` - candidate
|
||||||
|
`multiformats/multiaddr` issue body.
|
||||||
|
- `ai/tpt-backends/README.md` - roster the upstream proposal.
|
||||||
|
|
||||||
|
## Human edits
|
||||||
|
|
||||||
|
The human chose to track the draft under `ai/tpt-backends/` instead
|
||||||
|
of leaving it in the ignored gish cache, and explicitly requested a
|
||||||
|
Prompt-IO record for this docs-only commit. The human proposed the
|
||||||
|
`cds` alternative and unifying TIPC/WireGuard management through
|
||||||
|
`pyroute2`.
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
---
|
||||||
|
model: openai/gpt-5.6-sol
|
||||||
|
service: opencode
|
||||||
|
timestamp: 2026-08-19T00:33:28Z
|
||||||
|
git_ref: wkt/tipc_backend_378
|
||||||
|
diff_cmd: git diff HEAD~1..HEAD
|
||||||
|
---
|
||||||
|
|
||||||
|
## Prompt
|
||||||
|
|
||||||
|
The user asked to begin drafting an upstream `/tipc` multiaddr issue
|
||||||
|
similar to the existing WireGuard proposal, then chose to track the
|
||||||
|
draft as an AI planning document.
|
||||||
|
|
||||||
|
## Response
|
||||||
|
|
||||||
|
The generated proposal is intended for `multiformats/multiaddr`:
|
||||||
|
|
||||||
|
> `git diff HEAD~1..HEAD -- ai/tpt-backends/04_tipc_multiaddr_upstream.md ai/tpt-backends/README.md`
|
||||||
|
|
||||||
|
It proposes a code allocated upstream, a fixed 72-bit value holding
|
||||||
|
the service type, instance and scope, and the canonical text form
|
||||||
|
`/tipc/<type>:<instance>:<scope>`. It includes WireGuard composition,
|
||||||
|
security boundaries, the `tipc` versus `cds` naming decision,
|
||||||
|
deployment-management separation, implementation phases, test data
|
||||||
|
and open questions for maintainers.
|
||||||
|
|
@ -0,0 +1,191 @@
|
||||||
|
# `/tipc` multiaddr protocol: upstream issue draft
|
||||||
|
|
||||||
|
Candidate issue for `multiformats/multiaddr`, to be submitted after
|
||||||
|
the encoding questions below have been reviewed locally.
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
Linux TIPC (Transparent Inter-Process Communication) addresses a
|
||||||
|
service by a location-independent `(service type, instance)` name.
|
||||||
|
A server publishes that name into the kernel-maintained cluster name
|
||||||
|
table and a client connects by the same name; no host or transport
|
||||||
|
port forms part of the service identity.
|
||||||
|
|
||||||
|
TIPC is also known as **Cluster Domain Sockets**, a useful description
|
||||||
|
of its relationship to Unix-domain sockets. The registered protocol
|
||||||
|
name should nevertheless remain `tipc`: it matches Linux's
|
||||||
|
`AF_TIPC`, socket constants, kernel module and iproute2 frontend.
|
||||||
|
Registering `cds` would create an ecosystem-specific alias that is
|
||||||
|
harder to map back to the normative kernel API.
|
||||||
|
|
||||||
|
We would like to register a `tipc` multiaddr component so these
|
||||||
|
service endpoints can be represented directly and composed with a
|
||||||
|
bearer or tunnel description:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/tipc/1953628160:1616:2
|
||||||
|
|
||||||
|
/ip4/192.168.1.50/udp/51820/wg/u<key>/tipc/1953628160:1616:2
|
||||||
|
\____________ WireGuard bearer ____________/\____ TIPC service ____/
|
||||||
|
```
|
||||||
|
|
||||||
|
In the composed form, the components through `/wg/<key>` identify
|
||||||
|
the routed bearer and tunnel peer. The `/tipc/...` component is pure
|
||||||
|
service identity, resolved to a current publisher by the TIPC kernel
|
||||||
|
name table. Unlike a TCP endpoint, it deliberately has no inner IP
|
||||||
|
address or port.
|
||||||
|
|
||||||
|
This proposal does not imply that parsing the multiaddr configures a
|
||||||
|
TIPC bearer. In particular, TIPC over a WireGuard interface requires
|
||||||
|
a separately configured TIPC UDP bearer; WireGuard interfaces are L3
|
||||||
|
devices and cannot carry TIPC Ethernet media directly.
|
||||||
|
|
||||||
|
Today that bearer is configured through iproute2's `tipc` frontend,
|
||||||
|
which speaks the kernel's `TIPCv2` generic-netlink family. `pyroute2`
|
||||||
|
already provides WireGuard support and generic-netlink primitives but
|
||||||
|
has no TIPC codec/module; adding one is a complementary deployment
|
||||||
|
automation track, not part of this address-format proposal.
|
||||||
|
|
||||||
|
## Proposed protocol
|
||||||
|
|
||||||
|
- Name: `tipc`
|
||||||
|
- Code: TBD, allocated in `multiformats/multicodec` under the
|
||||||
|
`multiaddr` tag before implementations stabilize one
|
||||||
|
- Size: 72 bits
|
||||||
|
- Value: service type, service instance and publication scope
|
||||||
|
|
||||||
|
### Binary form
|
||||||
|
|
||||||
|
Exactly nine bytes with no value-length prefix:
|
||||||
|
|
||||||
|
| Offset | Size | Field | Encoding |
|
||||||
|
| ---: | ---: | --- | --- |
|
||||||
|
| 0 | 4 bytes | service type | unsigned 32-bit big-endian |
|
||||||
|
| 4 | 4 bytes | service instance | unsigned 32-bit big-endian |
|
||||||
|
| 8 | 1 byte | publication scope | unsigned enum byte |
|
||||||
|
|
||||||
|
```text
|
||||||
|
tipc-value = uint32be(type) || uint32be(instance) || uint8(scope)
|
||||||
|
```
|
||||||
|
|
||||||
|
For type `1953628160` (`0x74720000`), instance `1616` and
|
||||||
|
cluster scope `2`, the payload is:
|
||||||
|
|
||||||
|
```text
|
||||||
|
74 72 00 00 00 00 06 50 02
|
||||||
|
```
|
||||||
|
|
||||||
|
### String form
|
||||||
|
|
||||||
|
Use one multiaddr value segment containing three canonical decimal
|
||||||
|
integers:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/tipc/<type>:<instance>:<scope>
|
||||||
|
```
|
||||||
|
|
||||||
|
Canonical values have no sign, whitespace, alternate radix or
|
||||||
|
leading zeroes, except that zero itself is `0`. `type` and `instance`
|
||||||
|
must fit unsigned 32-bit fields. Scope is one of:
|
||||||
|
|
||||||
|
- `2`: `TIPC_CLUSTER_SCOPE`
|
||||||
|
- `3`: `TIPC_NODE_SCOPE`
|
||||||
|
|
||||||
|
The existing experimental spelling
|
||||||
|
`/tipc/<type>/<instance>/<scope>` cannot be registered as one normal
|
||||||
|
multiaddr protocol: generic parsing treats each slash-delimited name
|
||||||
|
as another protocol component. A single structured value preserves
|
||||||
|
TIPC's atomic service-address semantics without registering three
|
||||||
|
artificial protocols.
|
||||||
|
|
||||||
|
## Why scope is included
|
||||||
|
|
||||||
|
TIPC scope controls where a bound service publication is visible.
|
||||||
|
The same address representation is used for listener configuration
|
||||||
|
and dialing, so retaining scope lets a multiaddr round-trip the full
|
||||||
|
socket address rather than silently turning a node-local bind into a
|
||||||
|
cluster publication.
|
||||||
|
|
||||||
|
Modern Linux UAPI defines cluster and node scopes. The deprecated
|
||||||
|
zone spelling should not receive a new wire value; implementations
|
||||||
|
may normalize legacy input to cluster scope before encoding.
|
||||||
|
|
||||||
|
## Composition
|
||||||
|
|
||||||
|
Standalone service:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/tipc/1953628160:1616:2
|
||||||
|
```
|
||||||
|
|
||||||
|
TIPC service reached through a WireGuard bearer:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/ip4/192.168.1.50/udp/51820/wg/u<key>/tipc/1953628160:1616:2
|
||||||
|
```
|
||||||
|
|
||||||
|
This differs intentionally from TCP over WireGuard:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/ip4/192.168.1.50/udp/51820/wg/u<key>/ip4/10.0.11.1/tcp/1616
|
||||||
|
```
|
||||||
|
|
||||||
|
TCP repeats an inner locative address. TIPC does not: its service
|
||||||
|
name is resolved and load-balanced in-kernel across current
|
||||||
|
publishers.
|
||||||
|
|
||||||
|
## Semantics and security
|
||||||
|
|
||||||
|
- A TIPC service name identifies a service, not a unique process.
|
||||||
|
Multiple publishers may bind the same name and connections can be
|
||||||
|
distributed among them.
|
||||||
|
- Publication scope is reachability metadata, not authentication.
|
||||||
|
- A composed `/wg` key authenticates the tunnel peer, not the TIPC
|
||||||
|
service publisher.
|
||||||
|
- TIPC's optional native AES-GCM link encryption is independent of
|
||||||
|
this address codec and of WireGuard.
|
||||||
|
- Codec implementations should validate field widths and canonical
|
||||||
|
text only; cluster membership and publisher authorization remain
|
||||||
|
deployment concerns.
|
||||||
|
|
||||||
|
## Implementation plan
|
||||||
|
|
||||||
|
1. Reserve a `multiaddr`-tagged code in
|
||||||
|
`multiformats/multicodec`.
|
||||||
|
2. Add the fixed-size protocol row and normative encoding text to
|
||||||
|
`multiformats/multiaddr`.
|
||||||
|
3. Add codecs and cross-language test vectors, beginning with
|
||||||
|
`multiformats/py-multiaddr`.
|
||||||
|
4. Verify standalone and composed `wg` + `tipc` string/binary
|
||||||
|
round-trips.
|
||||||
|
|
||||||
|
## Open questions
|
||||||
|
|
||||||
|
1. Is a fixed 72-bit value preferred over a self-describing or
|
||||||
|
variable-width tuple for this kernel-defined address?
|
||||||
|
2. Should node scope be representable in a generally shareable
|
||||||
|
multiaddr, or should the registered form be cluster-only?
|
||||||
|
3. Does multiaddr have an existing convention for structured numeric
|
||||||
|
values that should replace the colon-separated text form?
|
||||||
|
4. Should the specification describe TIPC service *ranges*, or keep
|
||||||
|
this protocol limited to singleton service names used for
|
||||||
|
connection endpoints?
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- Linux TIPC documentation:
|
||||||
|
https://docs.kernel.org/networking/tipc.html
|
||||||
|
- Cluster Domain Sockets terminology:
|
||||||
|
https://en.wikipedia.org/wiki/Transparent_Inter-process_Communication
|
||||||
|
- Linux socket UAPI:
|
||||||
|
https://github.com/torvalds/linux/blob/master/include/uapi/linux/tipc.h
|
||||||
|
- Linux TIPC generic-netlink UAPI:
|
||||||
|
https://github.com/torvalds/linux/blob/master/include/uapi/linux/tipc_netlink.h
|
||||||
|
- pyroute2 WireGuard and generic-netlink APIs:
|
||||||
|
https://docs.pyroute2.org/wireguard.html
|
||||||
|
- WireGuard multiaddr implementation discussion:
|
||||||
|
https://github.com/multiformats/py-multiaddr/issues/107
|
||||||
|
- WireGuard codec implementation:
|
||||||
|
https://github.com/multiformats/py-multiaddr/pull/108
|
||||||
|
- Downstream tracking and prototype:
|
||||||
|
https://github.com/goodboy/tractor/issues/498
|
||||||
|
|
@ -16,6 +16,7 @@ document only their own deltas.
|
||||||
| [01 — TIPC](./01_tipc_backend.md) | [#378] | **none** (stdlib) | small | **landed**, PR [#493] — see the [handoff](./01_tipc_HANDOFF.md) |
|
| [01 — TIPC](./01_tipc_backend.md) | [#378] | **none** (stdlib) | small | **landed**, PR [#493] — see the [handoff](./01_tipc_HANDOFF.md) |
|
||||||
| [02 — QUIC/`iroh`](./02_quic_iroh_backend.md) | [#353] | `iroh` (uniffi FFI) | large | needs a prep PR |
|
| [02 — QUIC/`iroh`](./02_quic_iroh_backend.md) | [#353] | `iroh` (uniffi FFI) | large | needs a prep PR |
|
||||||
| [03 — `wg` bindspace](./03_wg_tunnel_bindspace.md) | [#482], [#443] | `pyroute2` | medium, 3 layers | layer A now |
|
| [03 — `wg` bindspace](./03_wg_tunnel_bindspace.md) | [#482], [#443] | `pyroute2` | medium, 3 layers | layer A now |
|
||||||
|
| [04 — `/tipc` multiaddr](./04_tipc_multiaddr_upstream.md) | [#498] | upstream `multiformats` | issue draft | local review |
|
||||||
|
|
||||||
Headline conclusions:
|
Headline conclusions:
|
||||||
|
|
||||||
|
|
@ -52,5 +53,6 @@ lands first ships it.
|
||||||
[#353]: https://github.com/goodboy/tractor/issues/353
|
[#353]: https://github.com/goodboy/tractor/issues/353
|
||||||
[#482]: https://github.com/goodboy/tractor/issues/482
|
[#482]: https://github.com/goodboy/tractor/issues/482
|
||||||
[#443]: https://github.com/goodboy/tractor/issues/443
|
[#443]: https://github.com/goodboy/tractor/issues/443
|
||||||
|
[#498]: https://github.com/goodboy/tractor/issues/498
|
||||||
|
|
||||||
[#493]: https://github.com/goodboy/tractor/pull/493
|
[#493]: https://github.com/goodboy/tractor/pull/493
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,10 @@
|
||||||
|
|
||||||
TIPC is a linux-kernel cluster IPC protocol whose service names
|
TIPC is a linux-kernel cluster IPC protocol whose service names
|
||||||
live in a **cluster-wide name table maintained by the kernel**.
|
live in a **cluster-wide name table maintained by the kernel**.
|
||||||
|
It is also described as **Cluster Domain Sockets**: the Unix-domain
|
||||||
|
socket model extended from one kernel to a cluster. That name is a
|
||||||
|
useful explanation for new users, while the code keeps `tipc` as its
|
||||||
|
protocol key to match Linux's `AF_TIPC`, kernel module and tooling.
|
||||||
For `tractor` that means:
|
For `tractor` that means:
|
||||||
|
|
||||||
- an actor's IPC address is a service name `(stype, instance)`,
|
- an actor's IPC address is a service name `(stype, instance)`,
|
||||||
|
|
@ -85,30 +89,55 @@ Everything above is single-node (`modprobe` is enough). To span
|
||||||
hosts you need a **bearer** on both, which is the one thing that
|
hosts you need a **bearer** on both, which is the one thing that
|
||||||
can't be CI'd.
|
can't be CI'd.
|
||||||
|
|
||||||
|
For the first physical test, use two wired Linux hosts on the same
|
||||||
|
L2 segment. Prefer a direct cable or uncomplicated switch; avoid
|
||||||
|
Wi-Fi, guest VLANs and port isolation until the basic link works.
|
||||||
|
Use the same checkout and Python environment on both hosts:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# on BOTH hosts
|
# on BOTH hosts
|
||||||
|
git rev-parse HEAD # must match on A and B
|
||||||
|
uv sync --all-extras --dev
|
||||||
sudo modprobe tipc
|
sudo modprobe tipc
|
||||||
|
|
||||||
# over ethernet (L2) — simplest when the hosts share a segment
|
# choose the real wired iface; do not assume `eth0`
|
||||||
sudo tipc bearer enable media eth device eth0
|
ip -br link
|
||||||
|
IFACE=enp3s0
|
||||||
|
|
||||||
|
# inspect existing cluster identity before changing anything
|
||||||
|
tipc node get address # must differ between hosts
|
||||||
|
tipc node get netid # must match between hosts
|
||||||
|
|
||||||
|
# use one private test netid on BOTH hosts, before enabling bearers
|
||||||
|
sudo tipc node set netid 37801
|
||||||
|
|
||||||
|
# ethernet is simplest when the hosts share an L2 segment
|
||||||
|
sudo tipc bearer enable media eth device "$IFACE"
|
||||||
|
|
||||||
# ..or over UDP when L2 isn't available — and MANDATORY over a
|
# ..or over UDP when L2 isn't available — and MANDATORY over a
|
||||||
# `wg` mesh, see below
|
# `wg` mesh, see below
|
||||||
sudo tipc bearer enable media udp name uc localip 10.0.11.1
|
sudo tipc bearer enable media udp name uc localip 10.0.11.1
|
||||||
|
|
||||||
# verify BEFORE running anything: this must list the peer
|
# verify BEFORE running anything: this must list the peer
|
||||||
|
tipc bearer list
|
||||||
tipc link list
|
tipc link list
|
||||||
tipc node list
|
tipc node list
|
||||||
```
|
```
|
||||||
|
|
||||||
Then:
|
If the link does not appear, first verify carrier, a common TIPC
|
||||||
|
network ID, distinct node addresses, a common VLAN and compatible
|
||||||
|
MTUs. Ethernet TIPC uses EtherType traffic rather than IP routing,
|
||||||
|
so a successful `ping` alone does not prove the bearer can work.
|
||||||
|
|
||||||
|
Run each command from `examples/multihost/tipc_cluster/`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# host A
|
# host A
|
||||||
python host_a_srv.py
|
uv run python host_a_srv.py
|
||||||
|
|
||||||
# host B
|
# host B
|
||||||
python host_b_client.py
|
watch -n 0.5 tipc nametable show # optional second terminal
|
||||||
|
uv run python host_b_client.py
|
||||||
```
|
```
|
||||||
|
|
||||||
Note what's absent from both scripts: any IP, hostname or port.
|
Note what's absent from both scripts: any IP, hostname or port.
|
||||||
|
|
@ -116,6 +145,51 @@ Both sides name the *same service*, and the kernel routes it.
|
||||||
Move `host_a_srv.py` to a third node and host B's dial keeps
|
Move `host_a_srv.py` to a third node and host B's dial keeps
|
||||||
working, unchanged.
|
working, unchanged.
|
||||||
|
|
||||||
|
For a first resilience pass, use a local console or separate
|
||||||
|
management link so the test does not cut off your own SSH session:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# host B: record the healthy baseline
|
||||||
|
tipc link list
|
||||||
|
tipc link statistics show
|
||||||
|
|
||||||
|
# either host: withdraw and recreate the bearer
|
||||||
|
sudo tipc bearer disable media eth device "$IFACE"
|
||||||
|
tipc link list
|
||||||
|
sudo tipc bearer enable media eth device "$IFACE"
|
||||||
|
tipc link list
|
||||||
|
|
||||||
|
# prove name withdrawal/republication and RPC recovery
|
||||||
|
tipc nametable show
|
||||||
|
uv run python host_b_client.py
|
||||||
|
```
|
||||||
|
|
||||||
|
Capture `uname -a`, both node addresses, `tipc bearer list`,
|
||||||
|
`tipc link list`, `tipc link statistics show`, the name table and
|
||||||
|
both Python transcripts. Those artifacts distinguish an actor bug
|
||||||
|
from bearer discovery, cluster identity or switch configuration.
|
||||||
|
|
||||||
|
Clean up a disposable Ethernet test on both hosts with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo tipc bearer disable media eth device "$IFACE"
|
||||||
|
tipc link list
|
||||||
|
```
|
||||||
|
|
||||||
|
Restore any pre-existing network ID only after all bearers are
|
||||||
|
disabled. The first useful automation target is a two-node network
|
||||||
|
namespace fixture that asserts link-up, remote publication, RPC,
|
||||||
|
withdrawal and republication in that order; physical hardware then
|
||||||
|
remains the validation layer for real NIC and switch behaviour.
|
||||||
|
|
||||||
|
The commands above use iproute2's `tipc` frontend, which speaks the
|
||||||
|
kernel's `TIPCv2` generic-netlink family. The planned `pyroute2`
|
||||||
|
dependency already manages WireGuard, interfaces and namespaces and
|
||||||
|
provides generic-netlink primitives, but it does not currently ship a
|
||||||
|
TIPC message codec. Adding one upstream would let `tractor` replace
|
||||||
|
these manual commands with one Python netlink stack instead of
|
||||||
|
shelling out; until then, `tipc(8)` remains the canonical frontend.
|
||||||
|
|
||||||
### over a `wg` mesh
|
### over a `wg` mesh
|
||||||
|
|
||||||
TIPC over WireGuard is the intended reference multihost
|
TIPC over WireGuard is the intended reference multihost
|
||||||
|
|
@ -231,12 +305,10 @@ self-skip when the module is absent.
|
||||||
## CI
|
## CI
|
||||||
|
|
||||||
Single-host TIPC *is* CI-able — the module ships with the
|
Single-host TIPC *is* CI-able — the module ships with the
|
||||||
standard Ubuntu kernel package, so a `sudo modprobe tipc` step
|
standard Ubuntu kernel package. CI loads it with `sudo modprobe
|
||||||
plus a `--tpt-proto tipc` matrix entry should work. That's not
|
tipc` and runs the suite with `--tpt-proto tipc` as a blocking
|
||||||
wired up yet; verify in a throwaway workflow first, and fall
|
matrix leg. Cross-node bearer testing stays manual — this README
|
||||||
back to a container job with `--cap-add NET_ADMIN` if the
|
is that smoke test.
|
||||||
runners refuse. Cross-node (bearer) testing stays manual — this
|
|
||||||
README is that smoke test.
|
|
||||||
|
|
||||||
## normative refs
|
## normative refs
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,10 @@ async def main() -> None:
|
||||||
) as an:
|
) as an:
|
||||||
await an.start_actor(
|
await an.start_actor(
|
||||||
'host_a',
|
'host_a',
|
||||||
enable_modules=[__name__],
|
# Host B imports this same module name to construct the
|
||||||
|
# RPC `NamespacePath`; direct script execution would
|
||||||
|
# otherwise expose it as `__main__` on host A.
|
||||||
|
enable_modules=['host_a_srv'],
|
||||||
)
|
)
|
||||||
print(
|
print(
|
||||||
'host_a up — `tipc nametable show` on EITHER host\n'
|
'host_a up — `tipc nametable show` on EITHER host\n'
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue