# swim An OCaml 5 implementation of the SWIM (Scalable Weakly-consistent Infection-style Process Group Membership) protocol for cluster membership and failure detection. ## Overview This library provides: - **Membership Management**: Automatic discovery and tracking of cluster nodes - **Failure Detection**: Identifies unreachable nodes using periodic probes and indirect checks - **Gossip Protocol**: Propagates state changes (Alive/Suspect/Dead) across the cluster - **Messaging**: Cluster-wide broadcast (gossip-based) and direct point-to-point UDP messaging - **Encryption**: Optional AES-256-GCM encryption for all network traffic Built 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. ## Requirements - OCaml >= 5.1 - Dune >= 3.20 ## Installation ```bash opam install . ``` Or add to your dune-project: ``` (depends (swim (>= 0.1.0))) ``` ## Usage ### Basic Example ```ocaml open Swim.Types let config = { default_config with bind_port = 7946; node_name = Some "node-1"; secret_key = "your-32-byte-secret-key-here!!!"; (* 32 bytes for AES-256 *) encryption_enabled = true; } let () = Eio_main.run @@ fun env -> Eio.Switch.run @@ fun sw -> let env_wrap = { stdenv = env; sw } in match Swim.Cluster.create ~sw ~env:env_wrap ~config with | Error `Invalid_key -> failwith "Invalid secret key" | Ok cluster -> Swim.Cluster.start cluster; (* Join an existing cluster *) let seed_nodes = ["192.168.1.10:7946"] in (match Swim.Cluster.join cluster ~seed_nodes with | Ok () -> Printf.printf "Joined cluster\n" | Error `No_seeds_reachable -> Printf.printf "Failed to join\n"); (* Send a broadcast message to all nodes *) Swim.Cluster.broadcast cluster ~topic:"config" ~payload:"v2"; (* Send a direct message to a specific node *) let target = node_id_of_string "node-2" in Swim.Cluster.send cluster ~target ~topic:"ping" ~payload:"hello"; (* Handle incoming messages *) Swim.Cluster.on_message cluster (fun sender topic payload -> Printf.printf "From %s: [%s] %s\n" (node_id_to_string sender.id) topic payload); (* Listen for membership events *) Eio.Fiber.fork ~sw (fun () -> let stream = Swim.Cluster.events cluster in while true do match Eio.Stream.take stream with | Join node -> Printf.printf "Joined: %s\n" (node_id_to_string node.id) | Leave node -> Printf.printf "Left: %s\n" (node_id_to_string node.id) | Suspect_event node -> Printf.printf "Suspect: %s\n" (node_id_to_string node.id) | Alive_event node -> Printf.printf "Alive: %s\n" (node_id_to_string node.id) | Update _ -> () done); Eio.Fiber.await_cancel () ``` ### Configuration Options | Field | Default | Description | |-------|---------|-------------| | `bind_addr` | "0.0.0.0" | Interface to bind listeners | | `bind_port` | 7946 | Port for SWIM protocol | | `protocol_interval` | 1.0 | Seconds between probe rounds | | `probe_timeout` | 0.5 | Seconds to wait for Ack | | `indirect_checks` | 3 | Peers to ask for indirect probes | | `secret_key` | (zeros) | 32-byte key for AES-256-GCM | | `encryption_enabled` | false | Enable encryption | ## Interoperability Testing The library includes interoperability tests with HashiCorp's [memberlist](https://github.com/hashicorp/memberlist) (Go). This verifies protocol compatibility with the reference implementation. ### Prerequisites - Go >= 1.19 - OCaml environment with dune ### Running Interop Tests The interop test suite starts a Go memberlist node and an OCaml node, then verifies they can discover each other and exchange messages. ```bash # Build the OCaml project dune build # Build the Go memberlist server cd interop && go build -o memberlist-server main.go && cd .. # Run the interop test bash test/scripts/test_interop.sh # Run with encryption enabled bash test/scripts/test_interop_encrypted.sh ``` ### Manual Interop Testing Start the Go node: ```bash cd interop go run main.go -name go-node -bind 127.0.0.1 -port 7946 ``` In another terminal, start the OCaml node: ```bash dune exec swim-interop-test ``` The OCaml node will connect to the Go node and print membership statistics for 30 seconds. ### Available Test Scripts | Script | Description | |--------|-------------| | `test/scripts/test_interop.sh` | Basic interop test | | `test/scripts/test_interop_encrypted.sh` | Interop with AES encryption | | `test/scripts/test_interop_udp_only.sh` | UDP-only communication test | | `test/scripts/test_interop_go_joins.sh` | Go node joining OCaml cluster | ### Debug Utilities ```bash # Test packet encoding/decoding dune exec swim-debug-codec # Receive and display incoming SWIM packets dune exec swim-debug-recv # Send manual ping to a target node dune exec swim-debug-ping ``` ## Running Tests ```bash dune runtest ``` ## License ISC License. See [LICENSE](LICENSE) for details.