Select the types of activity you want to include in your feed.
slirp-eio: add reusable gateway startup
In-process launchers need the same frame accounting, source selection, and control-server wiring. Keep that policy with slirp so VM backends can share it.
···11-(* A small HTTP+JSON control plane over a Unix socket, the shape gvproxy and
22- Docker expose: curl-able, no protobuf, no codegen. It drives the gateway's
33- runtime {!Slirp_eio.controller} -- publish and unpublish host ports, reload
44- the DNS forwarder, dump state -- and reports byte counters.
11+(* A small HTTP+JSON control plane over a Unix socket, compatible with the
22+ endpoints exposed by gvproxy and Docker and usable with curl. It drives the
33+ gateway's runtime {!Slirp_eio.controller} -- publish and unpublish host
44+ ports, reload the DNS forwarder, dump state -- and reports byte counters.
5566- The HTTP is Respond's server (nox-http request parsing, so malformed and
77- request-smuggling shapes are rejected before a handler runs); every JSON body
88- and reply goes through a nox-json {!Json.Codec}, never a hand-scan or a
99- hand-built string. The routes:
66+ The HTTP server uses Respond over nox-http for request framing. nox-json
77+ {!Json.Codec} values parse every JSON body and encode every reply. The routes:
108 GET /stats byte counters and live-flow counts
119 GET /connections the live NAT flows
1210 GET /services/forwarder/all the published forwards
···2220let add_rx t bytes = ignore (Atomic.fetch_and_add t.rx_bytes bytes : int)
2321let add_tx t bytes = ignore (Atomic.fetch_and_add t.tx_bytes bytes : int)
24222323+let count_transport counters (base : Eio_net.Frame.t) =
2424+ let count_rx frame = add_rx counters (String.length frame) in
2525+ let send rope =
2626+ add_tx counters (Rope.length rope);
2727+ base.Eio_net.Frame.send rope
2828+ in
2929+ {
3030+ base with
3131+ Eio_net.Frame.recv =
3232+ (fun () ->
3333+ let frame = base.Eio_net.Frame.recv () in
3434+ count_rx frame;
3535+ frame);
3636+ recv_batch =
3737+ (fun () ->
3838+ let frames = base.Eio_net.Frame.recv_batch () in
3939+ List.iter count_rx frames;
4040+ frames);
4141+ send;
4242+ send_batch = List.iter send;
4343+ }
4444+4545+let count_sources counters ~shards tx_sources =
4646+ Option.map
4747+ (fun sources shard ->
4848+ List.map
4949+ (fun pull () ->
5050+ let frames = pull () in
5151+ List.iter
5252+ (function
5353+ | Slirp.Frame frame -> add_rx counters (String.length frame)
5454+ | Slirp.Frame_rope { headers; payload } ->
5555+ add_rx counters (String.length headers + Rope.length payload)
5656+ | _ -> ())
5757+ frames;
5858+ frames)
5959+ (sources ~shards shard))
6060+ tx_sources
6161+6262+let count_owned counters owned_frames =
6363+ Option.map
6464+ (fun (source : Slirp_eio.owned_frames) ->
6565+ let recv_batch () =
6666+ let frames = source.recv_batch () in
6767+ List.iter
6868+ (fun (frame : Slirp_eio.owned_frame) -> add_rx counters frame.length)
6969+ frames;
7070+ frames
7171+ in
7272+ Slirp_eio.{ source with recv_batch })
7373+ owned_frames
7474+7575+let count_emitters counters shard_emitters =
7676+ Option.map
7777+ (fun emitters shard ->
7878+ let emit = emitters shard in
7979+ fun emission ->
8080+ let frame =
8181+ match emission with
8282+ | Slirp_eio.Frame frame -> frame
8383+ | Slirp_eio.Gso { frame; _ } -> frame
8484+ in
8585+ add_tx counters (Rope.length frame);
8686+ emit emission)
8787+ shard_emitters
8888+8989+let histogram_stats name recorder =
9090+ let histogram = Hdr.Recorder.snapshot recorder in
9191+ let metric field value = (Fmt.str "%s.%s" name field, value) in
9292+ [
9393+ metric "count" (Hdr.count histogram);
9494+ metric "min" (Hdr.min histogram);
9595+ metric "p50" (Hdr.value_at_percentile histogram 50.);
9696+ metric "p90" (Hdr.value_at_percentile histogram 90.);
9797+ metric "p99" (Hdr.value_at_percentile histogram 99.);
9898+ metric "p999" (Hdr.value_at_percentile histogram 99.9);
9999+ metric "max" (Hdr.max histogram);
100100+ metric "mean" (int_of_float (Float.round (Hdr.mean histogram)));
101101+ metric "stddev" (int_of_float (Float.round (Hdr.stddev histogram)));
102102+ ]
103103+25104type transport_counter = { name : string; value : int }
2610527106module C = Json.Codec
···78157 |> O.member "value" C.int ~enc:(fun c -> c.value)
79158 |> O.seal
801598181-(* A published forward. Structured fields, so the address needs no bespoke
8282- parsing: [guest_ip] is validated with {!Ipaddr.V4.of_string}. *)
160160+(* A published forward. [guest_ip] is validated with
161161+ {!Ipaddr.V4.of_string}. *)
83162type forward = { host_port : int; guest_ip : string; guest_port : int }
8416385164let forward_codec =
···217296218297(* {1 The SQLite snapshot download} *)
219298220220-(* A per-request name for the on-disk snapshot, unique within the process
221221- without a clock or RNG. *)
299299+(* An atomic sequence number gives each on-disk snapshot a process-local name. *)
222300let snapshot_seq = Atomic.make 0
223301224302(* Render the live NAT state to a self-contained SQLite database and return its
···245323let bad_request = error 400
246324247325(* Decode a request body with [codec], passing the value to [k]; a body that is
248248- not valid JSON of the expected shape is a 400. *)
326326+ not valid JSON for that codec is a 400. *)
249327let with_body codec (req : Respond.post_request) k =
250328 match Json.of_string codec req.body with
251329 | Ok v -> k v
···320398let routes ~tmp ?transport_stats ctrl counters =
321399 read_routes ~tmp ?transport_stats ctrl counters @ write_routes ctrl
322400323323-(* Serve the control API on a Unix socket until the switch ends. Its own switch
324324- so the blocking [run] does not hold up gateway setup. [tmp] is a scratch
325325- directory the snapshot endpoint stages its SQLite file in. *)
401401+(* Serve the control API on a Unix socket until the switch ends. A daemon switch
402402+ starts it asynchronously with gateway setup. The snapshot endpoint stages
403403+ its SQLite file in [tmp]. *)
326404let serve ~sw ~net ~tmp ?transport_stats ctrl counters path =
327405 (try Unix.unlink path with Unix.Unix_error _ -> ());
328406 Eio.Fiber.fork_daemon ~sw (fun () ->
···11+(** Tests for in-process slirp gateway startup configuration. *)
22+33+val suite : string * unit Alcotest.test_case list
44+(** Alcotest suite for {!Slirp_eio_gateway}. *)