This commit is contained in:
parent
aa2ff7b2f0
commit
2f3113f55d
11742 changed files with 1223940 additions and 0 deletions
303
unikernel/duniverse/mirage-tcpip/test/test_ipv4.ml
Normal file
303
unikernel/duniverse/mirage-tcpip/test/test_ipv4.ml
Normal file
|
|
@ -0,0 +1,303 @@
|
|||
open Common
|
||||
|
||||
let test_unmarshal_with_options () =
|
||||
let datagram = Cstruct.create 40 in
|
||||
Cstruct.blit_from_string ("\x46\xc0\x00\x28\x00\x00\x40\x00\x01\x02" ^
|
||||
"\x42\x49\xc0\xa8\x01\x08\xe0\x00\x00\x16\x94\x04\x00\x00\x22" ^
|
||||
"\x00\xfa\x02\x00\x00\x00\x01\x03\x00\x00\x00\xe0\x00\x00\xfb") 0 datagram 0 40;
|
||||
match Ipv4_packet.Unmarshal.of_cstruct datagram with
|
||||
| Ok ({Ipv4_packet.options ; _}, payload) ->
|
||||
Alcotest.(check int) "options" (Cstruct.length options) 4;
|
||||
Alcotest.(check int) "payload" (Cstruct.length payload) 16;
|
||||
Lwt.return_unit
|
||||
| _ ->
|
||||
Alcotest.fail "Fail to parse ip packet with options"
|
||||
|
||||
|
||||
let test_unmarshal_without_options () =
|
||||
let datagram = Cstruct.create 40 in
|
||||
Cstruct.blit_from_string ("\x45\x00\x00\x28\x19\x29\x40\x00\x34\x06\x98\x75\x36\xb7" ^
|
||||
"\x9c\xca\xc0\xa8\x01\x08\x00\x50\xca\xa6\x6f\x19\xf4\x76" ^
|
||||
"\x00\x00\x00\x00\x50\x04\x00\x00\xec\x27\x00\x00") 0 datagram 0 40;
|
||||
match Ipv4_packet.Unmarshal.of_cstruct datagram with
|
||||
| Ok ({Ipv4_packet.options ; _}, payload) ->
|
||||
Alcotest.(check int) "options" (Cstruct.length options) 0;
|
||||
Alcotest.(check int) "payload" (Cstruct.length payload) 20;
|
||||
Lwt.return_unit
|
||||
| _ ->
|
||||
Alcotest.fail "Fail to parse ip packet with options"
|
||||
|
||||
let test_unmarshal_regression () =
|
||||
let p = Cstruct.of_string "\x49\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30" in
|
||||
Alcotest.(check (result reject pass))
|
||||
"correctly return error for bad packet"
|
||||
(Error "any") (Ipv4_packet.Unmarshal.of_cstruct p);
|
||||
Lwt.return_unit
|
||||
|
||||
let test_size () =
|
||||
let src = Ipaddr.V4.of_string_exn "127.0.0.1" in
|
||||
let dst = Ipaddr.V4.of_string_exn "127.0.0.2" in
|
||||
let ttl = 64 in
|
||||
let ip = { Ipv4_packet.src; dst; proto = 17; ttl; id = 0 ; off = 0 ; options = (Cstruct.of_string "aaaa") } in
|
||||
let payload = Cstruct.of_string "abcdefgh" in
|
||||
let tmp = Ipv4_packet.Marshal.make_cstruct ~payload_len:(Cstruct.length payload) ip in
|
||||
let tmp = Cstruct.concat [tmp; payload] in
|
||||
Ipv4_packet.Unmarshal.of_cstruct tmp
|
||||
|> Alcotest.(check (result (pair ipv4_packet cstruct) string)) "Loading an IP packet with IP options" (Ok (ip, payload));
|
||||
Lwt.return_unit
|
||||
|
||||
let test_packet =
|
||||
let src = Ipaddr.V4.of_string_exn "127.0.0.1" in
|
||||
let dst = Ipaddr.V4.of_string_exn "127.0.0.2" in
|
||||
let ttl = 64 in
|
||||
{ Ipv4_packet.src; dst; proto = 17; ttl; id = 0 ; off = 0 ; options = (Cstruct.of_string "aaaa") }
|
||||
|
||||
let mf = 0x2000
|
||||
|
||||
let white = Cstruct.create 16
|
||||
let black =
|
||||
let buf = Cstruct.create 16 in
|
||||
Cstruct.memset buf 0xFF ;
|
||||
buf
|
||||
let gray =
|
||||
let buf = Cstruct.create 16 in
|
||||
Cstruct.memset buf 0x55 ;
|
||||
buf
|
||||
|
||||
let empty_cache = Fragments.Cache.empty 1000
|
||||
|
||||
let basic_fragments payload () =
|
||||
Alcotest.(check (option (pair ipv4_packet cstruct)) __LOC__
|
||||
(Some (test_packet, payload))
|
||||
(snd @@ Fragments.process empty_cache 0L test_packet payload)) ;
|
||||
let off_packet = { test_packet with off = 1 } in
|
||||
Alcotest.(check (option (pair ipv4_packet cstruct)) __LOC__
|
||||
None
|
||||
(snd @@ Fragments.process empty_cache 0L off_packet payload)) ;
|
||||
Lwt.return_unit
|
||||
|
||||
let basic_reassembly () =
|
||||
let more_frags = { test_packet with off = mf } in
|
||||
let cache, res = Fragments.process empty_cache 0L more_frags black in
|
||||
Alcotest.(check (option (pair ipv4_packet cstruct)) __LOC__ None res) ;
|
||||
let off_packet = { test_packet with off = 2 } in
|
||||
Alcotest.(check (option (pair ipv4_packet cstruct)) "reassembly of two segments works"
|
||||
(Some (test_packet, Cstruct.append black white))
|
||||
(snd @@ Fragments.process cache 0L off_packet white)) ;
|
||||
Lwt.return_unit
|
||||
|
||||
let basic_reassembly_timeout () =
|
||||
let more_frags = { test_packet with off = mf } in
|
||||
let cache, res = Fragments.process empty_cache 0L more_frags black in
|
||||
Alcotest.(check (option (pair ipv4_packet cstruct)) __LOC__ None res) ;
|
||||
let off_packet = { test_packet with off = 2 } in
|
||||
let below_max = Int64.sub Fragments.max_duration 1L in
|
||||
Alcotest.(check (option (pair ipv4_packet cstruct)) "even after just before max duration"
|
||||
(Some (test_packet, Cstruct.append black white))
|
||||
(snd @@ Fragments.process cache below_max off_packet white)) ;
|
||||
Alcotest.(check (option (pair ipv4_packet cstruct)) "none after max duration"
|
||||
None
|
||||
(snd @@ Fragments.process cache Fragments.max_duration off_packet white)) ;
|
||||
let more_off_packet = { test_packet with off = mf lor 2 } in
|
||||
let cache, res = Fragments.process cache below_max more_off_packet gray in
|
||||
Alcotest.(check (option (pair ipv4_packet cstruct)) __LOC__ None res) ;
|
||||
let final_packet = { test_packet with off = 4 } in
|
||||
Alcotest.(check (option (pair ipv4_packet cstruct)) __LOC__
|
||||
(Some (test_packet, Cstruct.concat [ black; gray; white]))
|
||||
(snd @@ Fragments.process cache below_max final_packet white)) ;
|
||||
Alcotest.(check (option (pair ipv4_packet cstruct)) __LOC__
|
||||
None
|
||||
(snd @@ Fragments.process cache Fragments.max_duration off_packet white)) ;
|
||||
Alcotest.(check (option (pair ipv4_packet cstruct)) __LOC__ None res) ;
|
||||
Lwt.return_unit
|
||||
|
||||
let reassembly_out_of_order () =
|
||||
let more_frags = { test_packet with off = mf } in
|
||||
let off_packet = { test_packet with off = 2 } in
|
||||
let cache, res = Fragments.process empty_cache 0L off_packet gray in
|
||||
Alcotest.(check (option (pair ipv4_packet cstruct)) __LOC__ None res) ;
|
||||
Alcotest.(check (option (pair ipv4_packet cstruct)) "reassembly of two segments works"
|
||||
(Some (test_packet, Cstruct.append black gray))
|
||||
(snd @@ Fragments.process cache 0L more_frags black)) ;
|
||||
Lwt.return_unit
|
||||
|
||||
let reassembly_multiple_out_of_order packets final_payload () =
|
||||
let _, res = List.fold_left (fun (cache, res) (off, payload) ->
|
||||
Alcotest.(check (option (pair ipv4_packet cstruct)) __LOC__ None res) ;
|
||||
let packet = { test_packet with off } in
|
||||
Fragments.process cache 0L packet payload)
|
||||
(empty_cache, None) packets
|
||||
in
|
||||
Alcotest.(check (option (pair ipv4_packet cstruct)) __LOC__
|
||||
(Some (test_packet, final_payload))
|
||||
res) ;
|
||||
Lwt.return_unit
|
||||
|
||||
let basic_overlaps () =
|
||||
let more_frags = { test_packet with off = mf } in
|
||||
let off_packet = { test_packet with off = 1 } in
|
||||
let cache, res = Fragments.process empty_cache 0L off_packet black in
|
||||
Alcotest.(check (option (pair ipv4_packet cstruct)) __LOC__ None res) ;
|
||||
Alcotest.(check (option (pair ipv4_packet cstruct)) __LOC__ None
|
||||
(snd @@ Fragments.process cache 0L more_frags white)) ;
|
||||
Lwt.return_unit
|
||||
|
||||
let basic_other_ip_flow () =
|
||||
let more_frags = { test_packet with off = mf } in
|
||||
let cache, res = Fragments.process empty_cache 0L more_frags black in
|
||||
let off_packet = { test_packet with off = 2 ; src = Ipaddr.V4.of_string_exn "127.0.0.2" } in
|
||||
Alcotest.(check (option (pair ipv4_packet cstruct)) __LOC__ None res) ;
|
||||
Alcotest.(check (option (pair ipv4_packet cstruct)) __LOC__ None
|
||||
(snd @@ Fragments.process cache 0L off_packet white)) ;
|
||||
let off_packet' = { test_packet with off = 2 ; proto = 25 } in
|
||||
Alcotest.(check (option (pair ipv4_packet cstruct)) __LOC__ None
|
||||
(snd @@ Fragments.process cache 0L off_packet' white)) ;
|
||||
Lwt.return_unit
|
||||
|
||||
let max_fragment () =
|
||||
let all_16 = [ white; gray; black; white;
|
||||
white; gray; black; white;
|
||||
white; gray; black; white;
|
||||
white; gray; black ; gray ]
|
||||
in
|
||||
let (cache, res), off =
|
||||
List.fold_left (fun ((cache, res), off) payload ->
|
||||
Alcotest.(check (option (pair ipv4_packet cstruct)) __LOC__ None res) ;
|
||||
let r = Fragments.process cache 0L { test_packet with off = off lor mf } payload in
|
||||
(r, Cstruct.length payload / 8 + off))
|
||||
((empty_cache, None), 0)
|
||||
all_16
|
||||
in
|
||||
Alcotest.(check (option (pair ipv4_packet cstruct)) __LOC__ None res) ;
|
||||
Alcotest.(check (option (pair ipv4_packet cstruct)) __LOC__
|
||||
(Some (test_packet, Cstruct.concat (all_16 @ [white ])))
|
||||
(snd @@ Fragments.process cache 0L { test_packet with off } white)) ;
|
||||
let cache, res = Fragments.process cache 0L { test_packet with off = off lor mf } white in
|
||||
Alcotest.(check (option (pair ipv4_packet cstruct)) __LOC__ None res) ;
|
||||
Alcotest.(check (option (pair ipv4_packet cstruct)) __LOC__
|
||||
None
|
||||
(snd @@ Fragments.process cache 0L { test_packet with off = off + 2 } black)) ;
|
||||
Lwt.return_unit
|
||||
|
||||
let none_returned packets () =
|
||||
let _, res = List.fold_left (fun (cache, res) (off, payload) ->
|
||||
Alcotest.(check (option (pair ipv4_packet cstruct)) __LOC__ None res) ;
|
||||
let packet = { test_packet with off } in
|
||||
Fragments.process cache 0L packet payload)
|
||||
(empty_cache, None) packets
|
||||
in
|
||||
Alcotest.(check (option (pair ipv4_packet cstruct)) __LOC__ None res) ;
|
||||
Lwt.return_unit
|
||||
|
||||
let ins_all_positions x l =
|
||||
let rec aux prev acc = function
|
||||
| [] -> List.rev ((prev @ [x]) :: acc)
|
||||
| hd::tl as l -> aux (prev @ [hd]) ((prev @ [x] @ l) :: acc) tl
|
||||
in
|
||||
aux [] [] l
|
||||
|
||||
let rec permutations = function
|
||||
| [] -> []
|
||||
| [x] -> [[x]]
|
||||
| x::xs -> List.fold_left (fun acc p -> acc @ ins_all_positions x p ) []
|
||||
(permutations xs)
|
||||
|
||||
let fragment_simple () =
|
||||
let hdr =
|
||||
{ Ipv4_packet.src = Ipaddr.V4.localhost ; dst = Ipaddr.V4.localhost ;
|
||||
id = 0x42 ; off = 0 ; ttl = 10 ; proto = 10 ; options = Cstruct.empty }
|
||||
in
|
||||
let payload = Cstruct.create 1030 in
|
||||
let fs = Fragments.fragment ~mtu:36 hdr payload in
|
||||
(* 16 byte per packet -> 64 fragments (a 16 byte) + 1 (6 byte) *)
|
||||
Alcotest.(check int __LOC__ 65 (List.length fs));
|
||||
let second, last = List.hd fs, List.(hd (rev fs)) in
|
||||
Alcotest.(check int __LOC__ 26 (Cstruct.length last));
|
||||
match
|
||||
Ipv4_packet.Unmarshal.of_cstruct second,
|
||||
Ipv4_packet.Unmarshal.of_cstruct last
|
||||
with
|
||||
| Error e, _ -> Alcotest.fail ("failed to decode second fragment " ^ e)
|
||||
| _, Error e -> Alcotest.fail ("failed to decode last fragment " ^ e)
|
||||
| Ok (hdr, _payload), Ok (hdr', _payload') ->
|
||||
Alcotest.(check int __LOC__ (0x2000 lor 2) hdr.Ipv4_packet.off);
|
||||
Alcotest.(check int __LOC__ 0x42 hdr.Ipv4_packet.id);
|
||||
Alcotest.(check int __LOC__ 130 hdr'.Ipv4_packet.off);
|
||||
Alcotest.(check int __LOC__ 0x42 hdr'.Ipv4_packet.id);
|
||||
let fs' = Fragments.fragment ~mtu:36 hdr (Cstruct.sub payload 0 1024) in
|
||||
(* 16 byte per packet -> 64 fragments (a 16 byte) *)
|
||||
Alcotest.(check int __LOC__ 64 (List.length fs'));
|
||||
let second', last' = List.hd fs', List.(hd (rev fs')) in
|
||||
Alcotest.(check int __LOC__ 36 (Cstruct.length last'));
|
||||
match
|
||||
Ipv4_packet.Unmarshal.of_cstruct second',
|
||||
Ipv4_packet.Unmarshal.of_cstruct last'
|
||||
with
|
||||
| Error e, _ -> Alcotest.fail ("failed to decode second fragment' " ^ e)
|
||||
| _, Error e -> Alcotest.fail ("failed to decode last fragment' " ^ e)
|
||||
| Ok (hdr'', _payload''), Ok (hdr''', _payload''') ->
|
||||
Alcotest.(check int __LOC__ (0x2000 lor 2) hdr''.Ipv4_packet.off);
|
||||
Alcotest.(check int __LOC__ 0x42 hdr''.Ipv4_packet.id);
|
||||
Alcotest.(check int __LOC__ 128 hdr'''.Ipv4_packet.off);
|
||||
Alcotest.(check int __LOC__ 0x42 hdr'''.Ipv4_packet.id)
|
||||
|
||||
let suite = [
|
||||
"unmarshal ip datagram with options", `Quick, test_unmarshal_with_options;
|
||||
"unmarshal ip datagram without options", `Quick, test_unmarshal_without_options;
|
||||
"unmarshal ip datagram with no payload & hlen > 5", `Quick, test_unmarshal_regression;
|
||||
"size", `Quick, test_size ] @
|
||||
List.mapi (fun i size ->
|
||||
Printf.sprintf "basic fragment %d: payload %d" i size, `Quick, basic_fragments (Cstruct.create size))
|
||||
[ 0 ; 1 ; 2 ; 10 ; 100 ; 1000 ; 5000 ; 10000 ] @ [
|
||||
"basic reassembly", `Quick, basic_reassembly;
|
||||
"basic reassembly timeout", `Quick, basic_reassembly_timeout;
|
||||
"reassembly out of order", `Quick, reassembly_out_of_order ;
|
||||
"other ip flow", `Quick, basic_other_ip_flow ;
|
||||
"maximum amount of fragments", `Quick, max_fragment ] @
|
||||
List.mapi (fun i (packets, final) ->
|
||||
Printf.sprintf "reassembly multiple %d" i, `Quick,
|
||||
reassembly_multiple_out_of_order packets final)
|
||||
([
|
||||
([ (mf, white); (2, black) ], Cstruct.concat [white;black]);
|
||||
([ (mf, black); (2, white) ], Cstruct.concat [black;white]);
|
||||
([ (2, black); (mf, white) ], Cstruct.concat [white;black]);
|
||||
([ (2, white); (mf, black) ], Cstruct.concat [black;white]);
|
||||
([ (mf, Cstruct.create 984); (123, black)], Cstruct.concat [Cstruct.create 984;black]);
|
||||
([ (mf, Cstruct.create 984); (123 lor mf, black); (125, gray)],
|
||||
Cstruct.concat [Cstruct.create 984;black;gray]);
|
||||
([ (mf, Cstruct.create 1000); (125, (Cstruct.concat [black;black;black]))],
|
||||
Cstruct.concat [Cstruct.create 1000;black;black;black]);
|
||||
]@
|
||||
List.map (fun x -> (x, Cstruct.concat [gray;white;black]))
|
||||
(permutations [ (mf, gray); (2 lor mf, white); (4, black)]) @
|
||||
List.map (fun x -> (x, Cstruct.concat [gray;white;black;Cstruct.create 10]))
|
||||
(permutations [ (mf, gray); (2 lor mf, white); (4 lor mf, black); (6, Cstruct.create 10)]) @
|
||||
List.map (fun x -> (x, Cstruct.concat [black;gray;white;black;gray]))
|
||||
(permutations [ (mf, black); (2 lor mf, gray); (4 lor mf, white); (6 lor mf, black); (8, gray)])
|
||||
) @
|
||||
[ "nothing returned", `Quick, basic_overlaps ] @
|
||||
List.mapi (fun i packets ->
|
||||
Printf.sprintf "nothing returned %d" i, `Quick,
|
||||
none_returned packets)
|
||||
([
|
||||
[ (mf, white); (1, black) ];
|
||||
[ (mf, black); (3, white) ];
|
||||
[ (mf, Cstruct.create 992); (124 lor mf, black);(126, gray)];
|
||||
[ (mf, Cstruct.create 1024); (128, black)];
|
||||
] @
|
||||
permutations [ (mf, gray); (2 lor mf, white); (3, black)] @
|
||||
permutations [ (mf, gray); (2 lor mf, white); (5, black)] @
|
||||
permutations [ (mf, gray); (3 lor mf, white); (4, black)] @
|
||||
permutations [ (mf, gray); (3 lor mf, white); (5, black)] @
|
||||
permutations [ (mf, gray); (1 lor mf, white); (3, black)] @
|
||||
permutations [ (mf, gray); (1 lor mf, white); (4, black)] @
|
||||
permutations [ (mf, (Cstruct.append gray gray)); (3 lor mf, white)] @
|
||||
permutations [ (mf, (Cstruct.append gray gray)); (2 lor mf, white)] @
|
||||
permutations [ (mf, gray); (2 lor mf, white); (4 lor mf, black); (6 lor mf, gray)] @
|
||||
permutations [ (mf, gray); (2 lor mf, white); (4 lor mf, black); (5, gray)] @
|
||||
permutations [ (mf, gray); (4 lor mf, white); (4 lor mf, black); (6, gray)] @
|
||||
permutations [ (mf, gray); (1 lor mf, white); (3 lor mf, black); (5, gray)] @
|
||||
permutations [ (mf, gray); (2 lor mf, white); (4 lor mf, black); (7, gray)]
|
||||
) @ [
|
||||
"simple fragment", `Quick, (fun () -> Lwt.return (fragment_simple ()))
|
||||
]
|
||||
Loading…
Add table
Add a link
Reference in a new issue