This commit is contained in:
parent
aa2ff7b2f0
commit
2f3113f55d
11742 changed files with 1223940 additions and 0 deletions
142
unikernel/duniverse/mirage-tcpip/test/test_keepalive.ml
Normal file
142
unikernel/duniverse/mirage-tcpip/test/test_keepalive.ml
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
(* Test the functional part *)
|
||||
|
||||
(* Linux default *)
|
||||
let default = Tcpip.Tcp.Keepalive.({
|
||||
after = Duration.of_sec 7200; (* 2 hours *)
|
||||
interval = Duration.of_sec 75; (* 75 seconds *)
|
||||
probes = 9;
|
||||
})
|
||||
|
||||
let simulate configuration iterations nprobes ns state =
|
||||
let rec loop iterations nprobes ns state =
|
||||
if iterations > 3 * configuration.Tcpip.Tcp.Keepalive.probes
|
||||
then Alcotest.fail (Printf.sprintf "too many iteractions: loop in keep-alive test? iterations = %d nprobes = %d ns=%Ld" iterations nprobes ns);
|
||||
let action, state' = Tcp.Keepalive.next ~configuration ~ns state in
|
||||
match action with
|
||||
| `SendProbe ->
|
||||
Logs.info (fun f -> f "iteration %d, ns %Ld: SendProbe" iterations ns);
|
||||
loop (iterations + 1) (nprobes + 1) ns state'
|
||||
| `Wait ns' ->
|
||||
Logs.info (fun f -> f "iteration %d, ns %Ld: Wait %Ld" iterations ns ns');
|
||||
loop (iterations + 1) nprobes (Int64.add ns ns') state'
|
||||
| `Close ->
|
||||
Logs.info (fun f -> f "iteration %d, ns %Ld: Close" iterations ns);
|
||||
nprobes in
|
||||
loop iterations nprobes ns state
|
||||
|
||||
(* check we send the expected number of probes if everything does as expected *)
|
||||
let test_keepalive_sequence () =
|
||||
let configuration = default in
|
||||
let state = Tcp.Keepalive.alive in
|
||||
let nprobes = simulate configuration 0 0 0L state in
|
||||
Alcotest.(check int) "number of probes" (configuration.probes) nprobes
|
||||
|
||||
(* check what happens if we miss a probe *)
|
||||
let test_keepalive_miss_probes () =
|
||||
let configuration = default in
|
||||
let state = Tcp.Keepalive.alive in
|
||||
(* skip sending the first 1 or 2 probes *)
|
||||
let ns = Int64.(add configuration.Tcpip.Tcp.Keepalive.after (mul 2L configuration.Tcpip.Tcp.Keepalive.interval)) in
|
||||
let nprobes = simulate configuration 0 0 ns state in
|
||||
if nprobes >= configuration.Tcpip.Tcp.Keepalive.probes
|
||||
then Alcotest.fail (Printf.sprintf "too many probes: max was %d but we sent %d and we should have skipped the first 1 or 2" configuration.probes nprobes)
|
||||
|
||||
(* check what happens if we exceed the maximum timeout *)
|
||||
let test_keepalive_miss_everything () =
|
||||
let configuration = default in
|
||||
let state = Tcp.Keepalive.alive in
|
||||
(* massive delay *)
|
||||
let ns = Int64.(add configuration.Tcpip.Tcp.Keepalive.after (mul 2L (mul (of_int configuration.Tcpip.Tcp.Keepalive.probes) configuration.Tcpip.Tcp.Keepalive.interval))) in
|
||||
let nprobes = simulate configuration 0 0 ns state in
|
||||
if nprobes <> 0
|
||||
then Alcotest.fail (Printf.sprintf "too many probes: max was %d but we sent %d and we should have skipped all" configuration.probes nprobes)
|
||||
|
||||
let suite_1 = [
|
||||
"correct number of keepalives", `Quick, test_keepalive_sequence;
|
||||
"we don't try to send old keepalives", `Quick, test_keepalive_miss_probes;
|
||||
"check we close if we miss all probes", `Slow, test_keepalive_miss_everything;
|
||||
]
|
||||
|
||||
let suite_1 =
|
||||
List.map (fun (n, s, f) -> n, s, (fun () -> Lwt.return (f ()))) suite_1
|
||||
|
||||
(* Test the end-to-end protocol behaviour *)
|
||||
open Common
|
||||
open Vnetif_common
|
||||
|
||||
let (>>=) = Lwt.(>>=)
|
||||
|
||||
let src = Logs.Src.create "test_keepalive" ~doc:"keepalive tests"
|
||||
module Log = (val Logs.src_log src : Logs.LOG)
|
||||
|
||||
(* Establish a TCP connection, enable keepalives on the connection, tell the network
|
||||
to drop all packets and check that the keep-alives detect the failure. *)
|
||||
module Test_connect = struct
|
||||
module V = VNETIF_STACK (Vnetif_backends.On_off_switch)
|
||||
|
||||
let gateway = Ipaddr.V4.of_string_exn "10.0.0.1"
|
||||
let client_cidr = Ipaddr.V4.Prefix.of_string_exn "10.0.0.101/24"
|
||||
let server_cidr = Ipaddr.V4.Prefix.of_string_exn "10.0.0.100/24"
|
||||
let backend = V.create_backend ()
|
||||
|
||||
let err_read_eof () = failf "accept got EOF while reading"
|
||||
let err_write_eof () = failf "client tried to write, got EOF"
|
||||
|
||||
let err_read e =
|
||||
let err = Format.asprintf "%a" V.Stack.TCP.pp_error e in
|
||||
failf "Error while reading: %s" err
|
||||
|
||||
let accept flow =
|
||||
let ip, port = V.Stack.TCP.dst flow in
|
||||
Logs.debug (fun f -> f "Accepted connection from %s:%d" (Ipaddr.to_string ip) port);
|
||||
V.Stack.TCP.read flow >>= function
|
||||
| Error e -> err_read e
|
||||
| Ok `Eof -> Lwt.return_unit
|
||||
| Ok (`Data _) -> failf "accept: expected to get EOF in read, but got data"
|
||||
|
||||
let test_tcp_keepalive_timeout () =
|
||||
let timeout = 15.0 in
|
||||
Lwt.pick [
|
||||
(Lwt_unix.sleep timeout >>= fun () ->
|
||||
failf "connect test timedout after %f seconds" timeout) ;
|
||||
|
||||
(V.create_stack ~cidr:server_cidr ~gateway backend >>= fun s1 ->
|
||||
V.Stack.TCP.listen (V.Stack.tcp s1) ~port:80 (fun f -> accept f);
|
||||
V.Stack.listen s1) ;
|
||||
|
||||
(Lwt_unix.sleep 0.1 >>= fun () ->
|
||||
V.create_stack ~cidr:client_cidr ~gateway backend >>= fun s2 ->
|
||||
Lwt.pick [
|
||||
V.Stack.listen s2;
|
||||
let keepalive = { Tcpip.Tcp.Keepalive.after = 0L; interval = Duration.of_sec 1; probes = 3 } in
|
||||
(let conn = V.Stack.TCP.create_connection ~keepalive (V.Stack.tcp s2) in
|
||||
or_error "connect" conn (Ipaddr.V4 (Ipaddr.V4.Prefix.address server_cidr), 80) >>= fun flow ->
|
||||
Logs.debug (fun f -> f "Connected to other end...");
|
||||
Vnetif_backends.On_off_switch.send_packets := false;
|
||||
V.Stack.TCP.read flow >>= function
|
||||
| Error e -> err_read e
|
||||
| Ok (`Data _) -> failf "read: expected to get EOF, but got data"
|
||||
| Ok `Eof ->
|
||||
Logs.debug (fun f -> f "connection read EOF as expected");
|
||||
V.Stack.TCP.close flow >>= fun () ->
|
||||
Lwt_unix.sleep 1.0 >>= fun () -> (* record some traffic after close *)
|
||||
Lwt.return_unit)]) ] >>= fun () ->
|
||||
|
||||
Lwt.return_unit
|
||||
|
||||
let record_pcap =
|
||||
V.record_pcap backend
|
||||
|
||||
end
|
||||
|
||||
let test_tcp_keepalive_timeout () =
|
||||
Test_connect.record_pcap
|
||||
"test_tcp_keepalive_timeout.pcap"
|
||||
Test_connect.test_tcp_keepalive_timeout
|
||||
|
||||
let suite_2 = [
|
||||
"check that TCP keepalives detect a network failure", `Slow,
|
||||
test_tcp_keepalive_timeout;
|
||||
]
|
||||
|
||||
let suite = suite_1 @ suite_2
|
||||
Loading…
Add table
Add a link
Reference in a new issue