this repo has no description
1# swim
2
3An OCaml 5 implementation of the SWIM (Scalable Weakly-consistent Infection-style Process Group Membership) protocol for cluster membership and failure detection.
4
5## Overview
6
7This library provides:
8
9- **Membership Management**: Automatic discovery and tracking of cluster nodes
10- **Failure Detection**: Identifies unreachable nodes using periodic probes and indirect checks
11- **Gossip Protocol**: Propagates state changes (Alive/Suspect/Dead) across the cluster
12- **Messaging**: Cluster-wide broadcast (gossip-based) and direct point-to-point UDP messaging
13- **Encryption**: Optional AES-256-GCM encryption for all network traffic
14
15Built on [Eio](https://github.com/ocaml-multicore/eio) for effect-based concurrency and [Kcas](https://github.com/ocaml-multicore/kcas) for lock-free shared state.
16
17## Requirements
18
19- OCaml >= 5.1
20- Dune >= 3.20
21
22## Installation
23
24```bash
25opam install .
26```
27
28Or add to your dune-project:
29
30```
31(depends (swim (>= 0.1.0)))
32```
33
34## Usage
35
36### Basic Example
37
38```ocaml
39open Swim.Types
40
41let config = {
42 default_config with
43 bind_port = 7946;
44 node_name = Some "node-1";
45 secret_key = "your-32-byte-secret-key-here!!!"; (* 32 bytes for AES-256 *)
46 encryption_enabled = true;
47}
48
49let () =
50 Eio_main.run @@ fun env ->
51 Eio.Switch.run @@ fun sw ->
52 let env_wrap = { stdenv = env; sw } in
53 match Swim.Cluster.create ~sw ~env:env_wrap ~config with
54 | Error `Invalid_key -> failwith "Invalid secret key"
55 | Ok cluster ->
56 Swim.Cluster.start cluster;
57
58 (* Join an existing cluster *)
59 let seed_nodes = ["192.168.1.10:7946"] in
60 (match Swim.Cluster.join cluster ~seed_nodes with
61 | Ok () -> Printf.printf "Joined cluster\n"
62 | Error `No_seeds_reachable -> Printf.printf "Failed to join\n");
63
64 (* Send a broadcast message to all nodes *)
65 Swim.Cluster.broadcast cluster ~topic:"config" ~payload:"v2";
66
67 (* Send a direct message to a specific node *)
68 let target = node_id_of_string "node-2" in
69 Swim.Cluster.send cluster ~target ~topic:"ping" ~payload:"hello";
70
71 (* Handle incoming messages *)
72 Swim.Cluster.on_message cluster (fun sender topic payload ->
73 Printf.printf "From %s: [%s] %s\n"
74 (node_id_to_string sender.id) topic payload);
75
76 (* Listen for membership events *)
77 Eio.Fiber.fork ~sw (fun () ->
78 let stream = Swim.Cluster.events cluster in
79 while true do
80 match Eio.Stream.take stream with
81 | Join node -> Printf.printf "Joined: %s\n" (node_id_to_string node.id)
82 | Leave node -> Printf.printf "Left: %s\n" (node_id_to_string node.id)
83 | Suspect_event node -> Printf.printf "Suspect: %s\n" (node_id_to_string node.id)
84 | Alive_event node -> Printf.printf "Alive: %s\n" (node_id_to_string node.id)
85 | Update _ -> ()
86 done);
87
88 Eio.Fiber.await_cancel ()
89```
90
91### Configuration Options
92
93| Field | Default | Description |
94|-------|---------|-------------|
95| `bind_addr` | "0.0.0.0" | Interface to bind listeners |
96| `bind_port` | 7946 | Port for SWIM protocol |
97| `protocol_interval` | 1.0 | Seconds between probe rounds |
98| `probe_timeout` | 0.5 | Seconds to wait for Ack |
99| `indirect_checks` | 3 | Peers to ask for indirect probes |
100| `secret_key` | (zeros) | 32-byte key for AES-256-GCM |
101| `encryption_enabled` | false | Enable encryption |
102
103## Interoperability Testing
104
105The library includes interoperability tests with HashiCorp's [memberlist](https://github.com/hashicorp/memberlist) (Go). This verifies protocol compatibility with the reference implementation.
106
107### Prerequisites
108
109- Go >= 1.19
110- OCaml environment with dune
111
112### Running Interop Tests
113
114The interop test suite starts a Go memberlist node and an OCaml node, then verifies they can discover each other and exchange messages.
115
116```bash
117# Build the OCaml project
118dune build
119
120# Build the Go memberlist server
121cd interop && go build -o memberlist-server main.go && cd ..
122
123# Run the interop test
124bash test/scripts/test_interop.sh
125
126# Run with encryption enabled
127bash test/scripts/test_interop_encrypted.sh
128```
129
130### Manual Interop Testing
131
132Start the Go node:
133
134```bash
135cd interop
136go run main.go -name go-node -bind 127.0.0.1 -port 7946
137```
138
139In another terminal, start the OCaml node:
140
141```bash
142dune exec swim-interop-test
143```
144
145The OCaml node will connect to the Go node and print membership statistics for 30 seconds.
146
147### Available Test Scripts
148
149| Script | Description |
150|--------|-------------|
151| `test/scripts/test_interop.sh` | Basic interop test |
152| `test/scripts/test_interop_encrypted.sh` | Interop with AES encryption |
153| `test/scripts/test_interop_udp_only.sh` | UDP-only communication test |
154| `test/scripts/test_interop_go_joins.sh` | Go node joining OCaml cluster |
155
156### Debug Utilities
157
158```bash
159# Test packet encoding/decoding
160dune exec swim-debug-codec
161
162# Receive and display incoming SWIM packets
163dune exec swim-debug-recv
164
165# Send manual ping to a target node
166dune exec swim-debug-ping
167```
168
169## Running Tests
170
171```bash
172dune runtest
173```
174
175## License
176
177ISC License. See [LICENSE](LICENSE) for details.