Compare commits
No commits in common. "be108ccc326983902065436d112ca7071bb9d07d" and "53516b094c4b035a61df2d2307a2626ecb7b28cd" have entirely different histories.
be108ccc32
...
53516b094c
|
|
@ -92,6 +92,12 @@ 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:
|
||||||
|
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
---
|
|
||||||
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.
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
---
|
|
||||||
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.
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
---
|
|
||||||
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.
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
---
|
|
||||||
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.
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
---
|
|
||||||
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`.
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
---
|
|
||||||
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.
|
|
||||||
|
|
@ -1,191 +0,0 @@
|
||||||
# `/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,7 +16,6 @@ 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:
|
||||||
|
|
||||||
|
|
@ -53,6 +52,5 @@ 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,10 +2,6 @@
|
||||||
|
|
||||||
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)`,
|
||||||
|
|
@ -89,55 +85,30 @@ 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
|
||||||
|
|
||||||
# choose the real wired iface; do not assume `eth0`
|
# over ethernet (L2) — simplest when the hosts share a segment
|
||||||
ip -br link
|
sudo tipc bearer enable media eth device eth0
|
||||||
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
|
||||||
```
|
```
|
||||||
|
|
||||||
If the link does not appear, first verify carrier, a common TIPC
|
Then:
|
||||||
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
|
||||||
uv run python host_a_srv.py
|
python host_a_srv.py
|
||||||
|
|
||||||
# host B
|
# host B
|
||||||
watch -n 0.5 tipc nametable show # optional second terminal
|
python host_b_client.py
|
||||||
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.
|
||||||
|
|
@ -145,51 +116,6 @@ 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
|
||||||
|
|
@ -305,10 +231,12 @@ 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. CI loads it with `sudo modprobe
|
standard Ubuntu kernel package, so a `sudo modprobe tipc` step
|
||||||
tipc` and runs the suite with `--tpt-proto tipc` as a blocking
|
plus a `--tpt-proto tipc` matrix entry should work. That's not
|
||||||
matrix leg. Cross-node bearer testing stays manual — this README
|
wired up yet; verify in a throwaway workflow first, and fall
|
||||||
is that smoke test.
|
back to a container job with `--cap-add NET_ADMIN` if the
|
||||||
|
runners refuse. Cross-node (bearer) testing stays manual — this
|
||||||
|
README is that smoke test.
|
||||||
|
|
||||||
## normative refs
|
## normative refs
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -57,10 +57,7 @@ async def main() -> None:
|
||||||
) as an:
|
) as an:
|
||||||
await an.start_actor(
|
await an.start_actor(
|
||||||
'host_a',
|
'host_a',
|
||||||
# Host B imports this same module name to construct the
|
enable_modules=[__name__],
|
||||||
# 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