diff --git a/lib/arpv4/arpv4.ml b/lib/arpv4/arpv4.ml index b28f83d64..8493ac1b7 100644 --- a/lib/arpv4/arpv4.ml +++ b/lib/arpv4/arpv4.ml @@ -20,16 +20,17 @@ open Lwt.Infix let src = Logs.Src.create "arpv4" ~doc:"Mirage ARP module" module Log = (val Logs.src_log src : Logs.LOG) -module Make (Ethif : V1_LWT.ETHIF) (Clock : V1.CLOCK) (Time : V1_LWT.TIME) = struct +module Make (Ethif : V1_LWT.ETHIF) (Clock : V1.MCLOCK) (Time : V1_LWT.TIME) = struct type result = [ `Ok of Macaddr.t | `Timeout ] type entry = | Pending of result Lwt.t * result Lwt.u - | Confirmed of float * Macaddr.t + | Confirmed of int64 * Macaddr.t type t = { ethif : Ethif.t; + clock : Clock.t; cache: (Ipaddr.V4.t, entry) Hashtbl.t; mutable bound_ips: Ipaddr.V4.t list; } @@ -48,15 +49,19 @@ module Make (Ethif : V1_LWT.ETHIF) (Clock : V1.CLOCK) (Time : V1_LWT.TIME) = str let probe_num = 3 (* how many probes to send before giving up *) let rec tick t () = - let now = Clock.time () in - let expired = Hashtbl.fold (fun ip entry expired -> + let now = Clock.elapsed_ns t.clock in + let remove_expired ip entry = match entry with - | Pending _ -> expired - | Confirmed (t, _) -> if t >= now then ip :: expired else expired) t.cache [] + | Pending _ -> Some entry + | Confirmed (expiry, _) -> + if Int64.compare expiry now > -1 + then Some entry + else begin + Log.info (fun f -> f "ARP: timeout %a" Ipaddr.V4.pp_hum ip); + None + end in - List.iter (fun ip -> - Log.info (fun f -> f "ARP: timeout %a" Ipaddr.V4.pp_hum ip); Hashtbl.remove t.cache ip - ) expired; + Hashtbl.filter_map_inplace remove_expired t.cache; Time.sleep_ns arp_timeout >>= tick t let to_repr t = @@ -64,7 +69,7 @@ module Make (Ethif : V1_LWT.ETHIF) (Clock : V1.CLOCK) (Time : V1_LWT.TIME) = str let key = Ipaddr.V4.to_string ip in match entry with | Pending _ -> acc ^ "\n" ^ key ^ " -> " ^ "Pending" - | Confirmed (time, mac) -> Printf.sprintf "%s\n%s -> Confirmed (%s) (expires %f)\n%!" + | Confirmed (time, mac) -> Printf.sprintf "%s\n%s -> Confirmed (%s) (expires %Lu)\n%!" acc key (Macaddr.to_string mac) time in Lwt.return (Hashtbl.fold print t.cache "") @@ -77,8 +82,8 @@ module Make (Ethif : V1_LWT.ETHIF) (Clock : V1.CLOCK) (Time : V1_LWT.TIME) = str match Ipaddr.V4.is_multicast ip || (Ipaddr.V4.compare ip Ipaddr.V4.any = 0) with | true -> Log.debug (fun f -> f "Ignoring ARP notification request for IP %a" Ipaddr.V4.pp_hum ip) | false -> - let now = Clock.time () in - let expire = now +. Duration.to_f arp_timeout in + let now = Clock.elapsed_ns t.clock in + let expire = Int64.add now arp_timeout in try match Hashtbl.find t.cache ip with | Pending (_, w) -> @@ -197,10 +202,10 @@ module Make (Ethif : V1_LWT.ETHIF) (Clock : V1.CLOCK) (Time : V1_LWT.TIME) = str Lwt.async (retry 0); response - let connect ethif = + let connect ethif clock = let cache = Hashtbl.create 7 in let bound_ips = [] in - let t = { ethif; cache; bound_ips } in + let t = { clock; ethif; cache; bound_ips } in Lwt.async (tick t); Log.info (fun f -> f "Connected arpv4 device on %s" (Macaddr.to_string ( Ethif.mac t.ethif))); diff --git a/lib/arpv4/arpv4.mli b/lib/arpv4/arpv4.mli index 602eac32b..bb87aa6a7 100644 --- a/lib/arpv4/arpv4.mli +++ b/lib/arpv4/arpv4.mli @@ -15,11 +15,11 @@ * *) -module Make (Ethif : V1_LWT.ETHIF) (Clock : V1.CLOCK) (Time : V1_LWT.TIME) : sig +module Make (Ethif : V1_LWT.ETHIF) (Clock : V1.MCLOCK) (Time : V1_LWT.TIME) : sig include V1_LWT.ARP type ethif = Ethif.t (** [connect] creates a value of type [t]. *) - val connect : ethif -> [> `Ok of t | `Error of error ] Lwt.t + val connect : ethif -> Clock.t -> [> `Ok of t | `Error of error ] Lwt.t end diff --git a/lib/ipv6/ipv6.ml b/lib/ipv6/ipv6.ml index fc4ab6b05..578c75fda 100644 --- a/lib/ipv6/ipv6.ml +++ b/lib/ipv6/ipv6.ml @@ -21,7 +21,7 @@ module I = Ipaddr open Lwt.Infix -module Make (E : V1_LWT.ETHIF) (T : V1_LWT.TIME) (C : V1.CLOCK) = struct +module Make (E : V1_LWT.ETHIF) (T : V1_LWT.TIME) (C : V1.MCLOCK) = struct type ethif = E.t type 'a io = 'a Lwt.t type buffer = Cstruct.t @@ -31,6 +31,7 @@ module Make (E : V1_LWT.ETHIF) (T : V1_LWT.TIME) (C : V1.CLOCK) = struct type t = { ethif : E.t; + clock : C.t; mutable ctx : Ndpv6.context } type error = @@ -39,7 +40,7 @@ module Make (E : V1_LWT.ETHIF) (T : V1_LWT.TIME) (C : V1.CLOCK) = struct let start_ticking t = let rec loop () = - let now = C.time () in + let now = C.elapsed_ns t.clock in let ctx, bufs = Ndpv6.tick ~now t.ctx in t.ctx <- ctx; Lwt_list.iter_s (E.writev t.ethif) bufs >>= fun () -> @@ -51,7 +52,7 @@ module Make (E : V1_LWT.ETHIF) (T : V1_LWT.TIME) (C : V1.CLOCK) = struct Ndpv6.allocate_frame t.ctx dst proto let writev t frame bufs = - let now = C.time () in + let now = C.elapsed_ns t.clock in let dst = Ndpv6.ipaddr_of_cstruct (Ipv6_wire.get_ipv6_dst (Cstruct.shift frame Ethif_wire.sizeof_ethernet)) @@ -64,7 +65,7 @@ module Make (E : V1_LWT.ETHIF) (T : V1_LWT.TIME) (C : V1.CLOCK) = struct writev t frame [buf] let input t ~tcp ~udp ~default buf = - let now = C.time () in + let now = C.elapsed_ns t.clock in let _, bufs, actions = Ndpv6.handle ~now t.ctx buf in Lwt_list.iter_s (function | `Tcp (src, dst, buf) -> tcp ~src ~dst buf @@ -81,7 +82,7 @@ module Make (E : V1_LWT.ETHIF) (T : V1_LWT.TIME) (C : V1.CLOCK) = struct let src t ~dst = Ndpv6.select_source t.ctx dst let set_ip t ip = - let now = C.time () in + let now = C.elapsed_ns t.clock in let ctx, bufs = Ndpv6.add_ip ~now t.ctx ip in t.ctx <- ctx; Lwt_list.iter_s (E.writev t.ethif) bufs @@ -90,7 +91,7 @@ module Make (E : V1_LWT.ETHIF) (T : V1_LWT.TIME) (C : V1.CLOCK) = struct Ndpv6.get_ip t.ctx let set_ip_gateways t ips = - let now = C.time () in + let now = C.elapsed_ns t.clock in let ctx = Ndpv6.add_routers ~now t.ctx ips in t.ctx <- ctx; Lwt.return_unit @@ -102,7 +103,7 @@ module Make (E : V1_LWT.ETHIF) (T : V1_LWT.TIME) (C : V1.CLOCK) = struct Ndpv6.get_prefix t.ctx let set_ip_netmask t pfx = - let now = C.time () in + let now = C.elapsed_ns t.clock in let ctx = Ndpv6.add_prefix ~now t.ctx pfx in t.ctx <- ctx; Lwt.return_unit @@ -127,11 +128,11 @@ module Make (E : V1_LWT.ETHIF) (T : V1_LWT.TIME) (C : V1.CLOCK) = struct | Some x -> f x >>= g | None -> g () - let connect ?ip ?netmask ?gateways ethif = + let connect ?ip ?netmask ?gateways ethif clock = Log.info (fun f -> f "IP6: Starting"); - let now = C.time () in + let now = C.elapsed_ns clock in let ctx, bufs = Ndpv6.local ~now (E.mac ethif) in - let t = {ctx; ethif} in + let t = {ctx; clock; ethif} in Lwt_list.iter_s (E.writev t.ethif) bufs >>= fun () -> (ip, set_ip t) >>=? fun () -> (netmask, Lwt_list.iter_s (set_ip_netmask t)) >>=? fun () -> diff --git a/lib/ipv6/ipv6.mli b/lib/ipv6/ipv6.mli index 13f7c0003..c69634985 100644 --- a/lib/ipv6/ipv6.mli +++ b/lib/ipv6/ipv6.mli @@ -14,11 +14,11 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *) -module Make (E : V1_LWT.ETHIF) (T : V1_LWT.TIME) (C : V1.CLOCK) : sig +module Make (E : V1_LWT.ETHIF) (T : V1_LWT.TIME) (Clock : V1.MCLOCK) : sig include V1_LWT.IPV6 with type ethif = E.t val connect : ?ip:Ipaddr.V6.t -> ?netmask:Ipaddr.V6.Prefix.t list -> ?gateways:Ipaddr.V6.t list -> - ethif -> [> `Ok of t | `Error of error ] Lwt.t + ethif -> Clock.t -> [> `Ok of t | `Error of error ] Lwt.t end diff --git a/lib/ipv6/ndpv6.ml b/lib/ipv6/ndpv6.ml index 19d1826eb..2da24a68e 100644 --- a/lib/ipv6/ndpv6.ml +++ b/lib/ipv6/ndpv6.ml @@ -44,6 +44,7 @@ module Ipaddr = Ipaddr.V6 type buffer = Cstruct.t type ipaddr = Ipaddr.t type prefix = Ipaddr.Prefix.t +type time = int64 module BoundedMap (K : Map.OrderedType) : sig type 'a t @@ -74,14 +75,14 @@ let solicited_node_prefix = Ipaddr.(Prefix.make 104 (of_int16 (0xff02, 0, 0, 0, 0, 1, 0xff00, 0))) module Defaults = struct - let _max_rtr_solicitation_delay = 1.0 + let _max_rtr_solicitation_delay = Duration.of_sec 1 let _ptr_solicitation_interval = 4 let _max_rtr_solicitations = 3 let max_multicast_solicit = 3 let max_unicast_solicit = 3 let _max_anycast_delay_time = 1 let _max_neighbor_advertisement = 3 - let delay_first_probe_time = 5.0 + let delay_first_probe_time = Duration.of_sec 5 let link_mtu = 1500 (* RFC 2464, 2. *) let min_link_mtu = 1280 @@ -90,8 +91,8 @@ module Defaults = struct let min_random_factor = 0.5 let max_random_factor = 1.5 - let reachable_time = 30.0 - let retrans_timer = 1.0 + let reachable_time = Duration.of_sec 30 + let retrans_timer = Duration.of_sec 1 end let ipaddr_of_cstruct cs = @@ -138,20 +139,12 @@ let multicast_mac = Cstruct.BE.set_uint32 pbuf 2 n; Macaddr.of_bytes_exn (Cstruct.to_string pbuf) -(* let float_of_uint32 n = Uint32.to_float (Uint32.of_int32 n) - but we can't use uint on Xen. *) -let float_of_uint32 n = - if n >= 0l then - Int32.to_float n - else - let m = Int32.logand n 0x7fffffffl in - Int32.to_float m +. 2. ** 31. - -let compute_reachable_time dt = - let r = - Defaults.(min_random_factor +. Random.float (max_random_factor -. min_random_factor)) +(* vary the reachable time by some random factor between 0.5 and 1.5 *) +let compute_reachable_time reachable_time = + let factor = + Defaults.(min_random_factor +. (max_random_factor -. min_random_factor)) in - r *. dt + Int64.of_float (factor *. Int64.to_float reachable_time) let cksum_buf = let pbuf = Io_page.to_cstruct (Io_page.get 1) in @@ -270,15 +263,15 @@ type ns = type pfx = { pfx_on_link : bool; pfx_autonomous : bool; - pfx_valid_lifetime : float option; - pfx_preferred_lifetime : float option; + pfx_valid_lifetime : time option; + pfx_preferred_lifetime : time option; pfx_prefix : Ipaddr.Prefix.t } type ra = { ra_cur_hop_limit : int; - ra_router_lifetime : float; - ra_reachable_time : float option; - ra_retrans_timer : float option; + ra_router_lifetime : time; + ra_reachable_time : time option; + ra_retrans_timer : time option; ra_slla : Macaddr.t option; ra_prefix : pfx list } @@ -299,9 +292,9 @@ type action = module AddressList = struct type state = - | TENTATIVE of (float * float option) option * int * float - | PREFERRED of (float * float option) option - | DEPRECATED of float option + | TENTATIVE of (time * time option) option * int * time + | PREFERRED of (time * time option) option + | DEPRECATED of time option type t = (Ipaddr.t * state) list @@ -331,19 +324,19 @@ module AddressList = struct let timeout = match timeout with | None -> None | Some (preferred_lifetime, valid_lifetime) -> - Some (now +. preferred_lifetime, valid_lifetime) + Some (Int64.add now preferred_lifetime, valid_lifetime) in Log.debug (fun f -> f "SLAAC: %a --> PREFERRED" Ipaddr.pp_hum ip); Some (ip, PREFERRED timeout), [] else let dst = Ipaddr.Prefix.network_address solicited_node_prefix ip in - Some (ip, TENTATIVE (timeout, n+1, now +. retrans_timer)), + Some (ip, TENTATIVE (timeout, n+1, Int64.add now retrans_timer)), [SendNS (`Unspecified, dst, ip)] | ip, PREFERRED (Some (preferred_timeout, valid_lifetime)) when preferred_timeout <= now -> Log.debug (fun f -> f "SLAAC: %a --> DEPRECATED" Ipaddr.pp_hum ip); let valid_timeout = match valid_lifetime with | None -> None - | Some valid_lifetime -> Some (now +. valid_lifetime) + | Some valid_lifetime -> Some (Int64.add now valid_lifetime) in Some (ip, DEPRECATED valid_timeout), [] | ip, DEPRECATED (Some t) when t <= now -> @@ -371,7 +364,7 @@ module AddressList = struct let add al ~now ~retrans_timer ~lft ip = match List.mem_assoc ip al with | false -> - let al = (ip, TENTATIVE (lft, 0, now +. retrans_timer)) :: al in + let al = (ip, TENTATIVE (lft, 0, Int64.add now retrans_timer)) :: al in let dst = Ipaddr.Prefix.network_address solicited_node_prefix ip in al, [SendNS (`Unspecified, dst, ip)] | true -> @@ -419,7 +412,7 @@ end module PrefixList = struct type t = - (Ipaddr.Prefix.t * float option) list + (Ipaddr.Prefix.t * time option) list let link_local = [Ipaddr.Prefix.link, None] @@ -436,7 +429,7 @@ module PrefixList = struct let add pl ~now pfx ~vlft = let vlft = match vlft with | None -> None - | Some dt -> Some (now +. dt) + | Some dt -> Some (Int64.add now dt) in match List.mem_assoc pfx pl with | false -> @@ -473,18 +466,18 @@ module PrefixList = struct Log.debug (fun f -> f "ND6: Processing PREFIX option in RA"); if Ipaddr.Prefix.link <> pfx then match vlft, List.mem_assoc pfx pl with - | Some 0.0, true -> + | Some 0L, true -> Log.debug (fun f -> f "ND6: Removing PREFIX: pfx=%a" Ipaddr.Prefix.pp_hum pfx); List.remove_assoc pfx pl, [] - | Some 0.0, false -> + | Some 0L, false -> pl, [] | Some dt, true -> - Log.debug (fun f -> f "ND6: Refreshing PREFIX: pfx=%a lft=%f" Ipaddr.Prefix.pp_hum pfx dt); + Log.debug (fun f -> f "ND6: Refreshing PREFIX: pfx=%a lft=%Lu" Ipaddr.Prefix.pp_hum pfx dt); let pl = List.remove_assoc pfx pl in - (pfx, Some (now +. dt)) :: pl, [] + (pfx, Some (Int64.add now dt)) :: pl, [] | Some dt, false -> - Log.debug (fun f -> f "ND6: Received new PREFIX: pfx=%a lft=%f" Ipaddr.Prefix.pp_hum pfx dt); - (pfx, Some (now +. dt)) :: pl, [] + Log.debug (fun f -> f "ND6: Received new PREFIX: pfx=%a lft=%Lu" Ipaddr.Prefix.pp_hum pfx dt); + (pfx, Some (Int64.add now dt)) :: pl, [] | None, true -> Log.debug (fun f -> f "ND6: Refreshing PREFIX: pfx=%a lft=inf" Ipaddr.Prefix.pp_hum pfx); let pl = List.remove_assoc pfx pl in @@ -494,30 +487,16 @@ module PrefixList = struct (pfx, None) :: pl, [] else pl, [] - (* TODO check for 0 (this is checked in update_prefix currently), infinity *) - (* if vlft >= plft && Ipaddr.Prefix.link <> pfx then *) - (* let pl, acts = *) - (* if on_link then *) - (* update pl ~now ~valid:vlft pfx *) - (* else *) - (* pl, [] *) - (* in *) - (* if aut && (vlft :> float) > 0.0 then *) - (* pl, acts, Some (pfx, plft, vlft) *) - (* else *) - (* pl, acts, None *) - (* else *) - (* pl, [], None *) end module NeighborCache = struct type state = - | INCOMPLETE of float * int - | REACHABLE of float * Macaddr.t + | INCOMPLETE of time * int + | REACHABLE of time * Macaddr.t | STALE of Macaddr.t - | DELAY of float * Macaddr.t - | PROBE of float * int * Macaddr.t + | DELAY of time * Macaddr.t + | PROBE of time * int * Macaddr.t type info = { state : state; @@ -537,7 +516,7 @@ module NeighborCache = struct if tn < Defaults.max_multicast_solicit then begin Log.info (fun f -> f "NUD: %a --> INCOMPLETE [Timeout]" Ipaddr.pp_hum ip); let dst = Ipaddr.Prefix.network_address solicited_node_prefix ip in - IpMap.add ip {nb with state = INCOMPLETE (now +. retrans_timer, tn+1)} nc, + IpMap.add ip {nb with state = INCOMPLETE ((Int64.add now retrans_timer), tn+1)} nc, [SendNS (`Specified, dst, ip)] end else begin Log.info (fun f -> f "NUD: %a --> UNREACHABLE [Discarding]" Ipaddr.pp_hum ip); @@ -549,12 +528,12 @@ module NeighborCache = struct IpMap.add ip {nb with state = STALE mac} nc, [] | DELAY (t, dmac) when t <= now -> Log.info (fun f -> f "NUD: %a --> PROBE" Ipaddr.pp_hum ip); - IpMap.add ip {nb with state = PROBE (now +. retrans_timer, 0, dmac)} nc, + IpMap.add ip {nb with state = PROBE ((Int64.add now retrans_timer), 0, dmac)} nc, [SendNS (`Specified, ip, ip)] | PROBE (t, tn, dmac) when t <= now -> if tn < Defaults.max_unicast_solicit then begin Log.info (fun f -> f "NUD: %a --> PROBE [Timeout]" Ipaddr.pp_hum ip); - IpMap.add ip {nb with state = PROBE (now +. retrans_timer, tn+1, dmac)} nc, + IpMap.add ip {nb with state = PROBE ((Int64.add now retrans_timer), tn+1, dmac)} nc, [SendNS (`Specified, ip, ip)] end else begin Log.info (fun f -> f "NUD: %a --> UNREACHABLE [Discarding]" Ipaddr.pp_hum ip); @@ -616,7 +595,7 @@ module NeighborCache = struct IpMap.add tgt nb nc, [SendQueued (tgt, new_mac)] | INCOMPLETE _, Some new_mac, true, _ -> Log.info (fun f -> f "NUD: %a --> REACHABLE" Ipaddr.pp_hum tgt); - let nb = {nb with state = REACHABLE (now +. reachable_time, new_mac)} in + let nb = {nb with state = REACHABLE ((Int64.add now reachable_time), new_mac)} in IpMap.add tgt nb nc, [SendQueued (tgt, new_mac)] | INCOMPLETE _, None, _, _ -> let nc = @@ -628,11 +607,11 @@ module NeighborCache = struct nc, [] | PROBE (_, _, mac), Some new_mac, true, false when mac = new_mac -> Log.info (fun f -> f "NUD: %a --> REACHABLE" Ipaddr.pp_hum tgt); - let nb = {nb with state = REACHABLE (now +. reachable_time, new_mac)} in + let nb = {nb with state = REACHABLE ((Int64.add now reachable_time), new_mac)} in IpMap.add tgt nb nc, [] | PROBE (_, _, mac), None, true, false -> Log.info (fun f -> f "NUD: %a --> REACHABLE" Ipaddr.pp_hum tgt); - let nb = {nb with state = REACHABLE (now +. reachable_time, mac)} in + let nb = {nb with state = REACHABLE ((Int64.add now reachable_time), mac)} in IpMap.add tgt nb nc, [] | (REACHABLE _ | STALE _ | DELAY _ | PROBE _), None, _, _ -> let nc = @@ -648,7 +627,7 @@ module NeighborCache = struct IpMap.add tgt nb nc, [] | (REACHABLE _ | STALE _ | DELAY _ | PROBE _), Some new_mac, true, true -> Log.info (fun f -> f "NUD: %a --> REACHABLE" Ipaddr.pp_hum tgt); - let nb = {nb with state = REACHABLE (now +. reachable_time, new_mac)} in + let nb = {nb with state = REACHABLE ((Int64.add now reachable_time), new_mac)} in IpMap.add tgt nb nc, [] | (REACHABLE (_, mac) | STALE mac | DELAY (_, mac) | PROBE (_, _, mac)), Some new_mac, false, true when mac <> new_mac -> @@ -675,11 +654,11 @@ module NeighborCache = struct nc, Some dmac, [] | STALE dmac -> let dt = Defaults.delay_first_probe_time in - let nc = IpMap.add ip {nb with state = DELAY (now +. dt, dmac)} nc in + let nc = IpMap.add ip {nb with state = DELAY (Int64.add now dt, dmac)} nc in nc, Some dmac, [] with | Not_found -> - let nb = {state = INCOMPLETE (now +. reachable_time, 0); is_router = false} in + let nb = {state = INCOMPLETE (Int64.add now reachable_time, 0); is_router = false} in let nc = IpMap.add ip nb nc in let dst = Ipaddr.Prefix.network_address solicited_node_prefix ip in nc, None, [SendNS (`Specified, dst, ip)] @@ -697,7 +676,7 @@ end module RouterList = struct type t = - (Ipaddr.t * float) list + (Ipaddr.t * time) list let empty = [] @@ -705,10 +684,11 @@ module RouterList = struct let to_list rl = List.map fst rl - let add rl ~now ?(lifetime = max_float) ip = + let add rl ~now ?(lifetime = Duration.of_year 1) ip = (* FIXME *) (* yomimono 2016-06-30: fix what? *) - (ip, now +. lifetime) :: rl + (* yomimono 2016-08-17: maybe fix this default lifetime. *) + (ip, Int64.add now lifetime) :: rl (* FIXME if we are keeping a destination cache, we must remove the stale routers from there as well. *) let tick rl ~now = @@ -718,15 +698,15 @@ module RouterList = struct match List.mem_assoc src rl with | true -> let rl = List.remove_assoc src rl in - if lft > 0.0 then begin - Log.info (fun f -> f "RA: Refreshing Router: src=%a lft=%f" Ipaddr.pp_hum src lft); - (src, now +. lft) :: rl, [] + if lft > 0L then begin + Log.info (fun f -> f "RA: Refreshing Router: src=%a lft=%Lu" Ipaddr.pp_hum src lft); + (src, Int64.add now lft) :: rl, [] end else begin Log.info (fun f -> f "RA: Router Expired: src=%a" Ipaddr.pp_hum src); rl, [] end | false -> - if lft > 0.0 then begin + if lft > 0L then begin Log.info (fun f -> f "RA: Adding Router: src=%a" Ipaddr.pp_hum src); (add rl ~now ~lifetime:lft src), [] end else @@ -735,7 +715,7 @@ module RouterList = struct let add rl ~now:_ ip = match List.mem_assoc ip rl with | true -> rl - | false -> (ip, max_float) :: rl + | false -> (ip, Duration.of_year 1) :: rl let select rl reachable ip = let rec loop = function @@ -793,13 +773,13 @@ module Parser = struct let n = Ipv6_wire.get_opt_prefix_valid_lifetime opt in match n with | 0xffffffffl -> None - | n -> Some (float_of_uint32 n) + | n -> Some (Int64.of_int32 n) in let pfx_preferred_lifetime = let n = Ipv6_wire.get_opt_prefix_preferred_lifetime opt in match n with | 0xffffffffl -> None - | n -> Some (float_of_uint32 n) + | n -> Some (Int64.of_int32 n) in let pfx = {pfx_on_link; pfx_autonomous; pfx_valid_lifetime; pfx_preferred_lifetime; pfx_prefix} @@ -814,20 +794,20 @@ module Parser = struct let parse_ra buf = let ra_cur_hop_limit = Ipv6_wire.get_ra_cur_hop_limit buf in let ra_router_lifetime = - float_of_int (Ipv6_wire.get_ra_router_lifetime buf) + Int64.of_int (Ipv6_wire.get_ra_router_lifetime buf) in let ra_reachable_time = let n = Ipv6_wire.get_ra_reachable_time buf in if n = 0l then None else - let dt = (float_of_uint32 n) /. 1000.0 in + let dt = Int64.of_int32 @@ Int32.div n 1000l in Some dt in let ra_retrans_timer = let n = Ipv6_wire.get_ra_retrans_timer buf in if n = 0l then None else - let dt = (float_of_uint32 n) /. 1000.0 in + let dt = Int64.of_int32 @@ Int32.div n 1000l in Some dt in let opts = Cstruct.shift buf Ipv6_wire.sizeof_ra in @@ -1063,9 +1043,9 @@ type context = address_list : AddressList.t; link_mtu : int; cur_hop_limit : int; - base_reachable_time : float; - reachable_time : float; - retrans_timer : float; + base_reachable_time : time; + reachable_time : time; + retrans_timer : time; packet_queue : (Macaddr.t -> Cstruct.t list) PacketQueue.t } let next_hop ctx ip = @@ -1216,7 +1196,7 @@ let handle_ra ~now ctx ~src ~dst ra = let vlft = pfx.pfx_valid_lifetime in let prefix_list, acts = PrefixList.handle_ra state.prefix_list ~now ~vlft pfx.pfx_prefix in match pfx.pfx_autonomous, vlft with - | _, Some 0.0 -> + | _, Some 0L -> {state with prefix_list}, acts | true, Some _ -> let plft = pfx.pfx_preferred_lifetime in diff --git a/lib/ipv6/ndpv6.mli b/lib/ipv6/ndpv6.mli index d0bc0d184..958695509 100644 --- a/lib/ipv6/ndpv6.mli +++ b/lib/ipv6/ndpv6.mli @@ -17,6 +17,7 @@ type buffer = Cstruct.t type ipaddr = Ipaddr.V6.t type prefix = Ipaddr.V6.Prefix.t +type time = int64 val ipaddr_of_cstruct : buffer -> ipaddr val ipaddr_to_cstruct_raw : ipaddr -> buffer -> int -> unit @@ -29,12 +30,12 @@ type event = type context -val local : now:float -> Macaddr.t -> context * buffer list list +val local : now:time -> Macaddr.t -> context * buffer list list (** [local ~now mac] is a pair [ctx, bufs] where [ctx] is a local IPv6 context associated to the hardware address [mac]. [bufs] is a list of ethif packets to be sent. *) -val add_ip : now:float -> context -> ipaddr -> context * buffer list list +val add_ip : now:time -> context -> ipaddr -> context * buffer list list (** [add_ip ~now ctx ip] is [ctx', bufs] where [ctx'] is [ctx] updated with a new local ip and [bufs] is a list of ethif packets to be sent. *) @@ -49,30 +50,30 @@ val select_source : context -> ipaddr -> ipaddr (** [select_source ctx ip] returns the ip that should be put in the source field of a packet destined to [ip]. *) -val handle : now:float -> context -> buffer -> context * buffer list list * event list +val handle : now:time -> context -> buffer -> context * buffer list list * event list (** [handle ~now ctx buf] handles an incoming ipv6 packet. It returns [ctx', bufs, evs] where [ctx'] is the updated context, [bufs] is a list of packets to be sent and [evs] is a list of packets to be passed to the higher layers (udp, tcp, etc) for further processing. *) -val send : now:float -> context -> ipaddr -> buffer -> buffer list -> context * buffer list list +val send : now:time -> context -> ipaddr -> buffer -> buffer list -> context * buffer list list (** [send ~now ctx ip frame bufs] starts route resolution and assembles an ipv6 packet for sending with header [frame] and body [bufs]. It returns a pair [ctx', bufs] where [ctx'] is the updated context and [bufs] is a list of packets to be sent. *) -val tick : now:float -> context -> context * buffer list list +val tick : now:time -> context -> context * buffer list list (** [tick ~now ctx] should be called periodically (every 1s is good). It returns [ctx', bufs] where [ctx'] is the updated context and [bufs] is a list of packets to be sent. *) -val add_prefix : now:float -> context -> prefix -> context +val add_prefix : now:time -> context -> prefix -> context (** [add_prefix ~now ctx pfx] adds a local prefix to [ctx]. *) val get_prefix : context -> prefix list (** [get_prefix ctx] returns the list of local prefixes known to [ctx]. *) -val add_routers : now:float -> context -> ipaddr list -> context +val add_routers : now:time -> context -> ipaddr list -> context (** [add_routers ~now ctx ips] adds a list of gateways to [ctx] to be used for routing. *) diff --git a/lib/tcp/ack.ml b/lib/tcp/ack.ml index 918ba6cf3..0ba4ab29f 100644 --- a/lib/tcp/ack.ml +++ b/lib/tcp/ack.ml @@ -105,7 +105,7 @@ module Delayed (Time:V1_LWT.TIME) : M = struct let delayedack = last in let r = {send_ack; delayedack; delayed; pushpending} in let expire = ontimer r in - let period = 0.1 in + let period = (Duration.of_f 0.1) in let timer = TT.t ~period ~expire in {r; timer} diff --git a/lib/tcp/flow.ml b/lib/tcp/flow.ml index 0bb91b37e..3c42d4ffb 100644 --- a/lib/tcp/flow.ml +++ b/lib/tcp/flow.ml @@ -23,7 +23,7 @@ exception Refused let src = Logs.Src.create "flow" ~doc:"Mirage TCP Flow module" module Log = (val Logs.src_log src : Logs.LOG) -module Make(IP:V1_LWT.IP)(TM:V1_LWT.TIME)(C:V1.CLOCK)(R:V1.RANDOM) = struct +module Make(IP:V1_LWT.IP)(TM:V1_LWT.TIME)(C:V1.MCLOCK)(R:V1.RANDOM) = struct module Pcb = Pcb.Make(IP)(TM)(C)(R) @@ -83,7 +83,7 @@ module Make(IP:V1_LWT.IP)(TM:V1_LWT.TIME)(C:V1.CLOCK)(R:V1.RANDOM) = struct let writev t views = Pcb.writev t views >|= err_rewrite let write_nodelay t view = Pcb.write_nodelay t view >>= err_raise let writev_nodelay t views = Pcb.writev_nodelay t views >>= err_raise - let connect ipv4 = ok (Pcb.create ipv4) + let connect ipv4 clock = ok (Pcb.create ipv4 clock) let disconnect _ = Lwt.return_unit let create_connection tcp (daddr, dport) = diff --git a/lib/tcp/flow.mli b/lib/tcp/flow.mli index e8d5ad7bf..8f9ba8876 100644 --- a/lib/tcp/flow.mli +++ b/lib/tcp/flow.mli @@ -18,10 +18,10 @@ exception Refused (** {b NOTE}: to be removed in favor of a proper result type in V1.write_nodelay and V1.writev_nodelay.*) -module Make (IP:V1_LWT.IP)(TM:V1_LWT.TIME)(C:V1.CLOCK)(R:V1.RANDOM) : sig +module Make (IP:V1_LWT.IP)(TM:V1_LWT.TIME)(C:V1.MCLOCK)(R:V1.RANDOM) : sig include V1_LWT.TCP with type ip = IP.t and type ipaddr = IP.ipaddr and type ipinput = src:IP.ipaddr -> dst:IP.ipaddr -> Cstruct.t -> unit Lwt.t - val connect : ip -> [> `Ok of t | `Error of error ] Lwt.t + val connect : ip -> C.t -> [> `Ok of t | `Error of error ] Lwt.t end diff --git a/lib/tcp/pcb.ml b/lib/tcp/pcb.ml index f52d842a3..d4149abd2 100644 --- a/lib/tcp/pcb.ml +++ b/lib/tcp/pcb.ml @@ -20,7 +20,7 @@ open Lwt.Infix let src = Logs.Src.create "pcb" ~doc:"Mirage TCP PCB module" module Log = (val Logs.src_log src : Logs.LOG) -module Make(Ip:V1_LWT.IP)(Time:V1_LWT.TIME)(Clock:V1.CLOCK)(Random:V1.RANDOM) = +module Make(Ip:V1_LWT.IP)(Time:V1_LWT.TIME)(Clock:V1.MCLOCK)(Random:V1.RANDOM) = struct module RXS = Segment.Rx(Time) @@ -47,6 +47,7 @@ struct type t = { ip : Ip.t; + clock : Clock.t; mutable localport : int; channels: (WIRE.id, connection) Hashtbl.t; (* server connections the process of connecting - SYN-ACK sent @@ -284,7 +285,7 @@ struct let on_close () = clearpcb t id tx_isn in let state = State.t ~on_close in let txq, _tx_t = - TXS.create ~xmit:(Tx.xmit_pcb t.ip id) ~wnd ~state ~rx_ack ~tx_ack ~tx_wnd_update + TXS.create ~clock:t.clock ~xmit:(Tx.xmit_pcb t.ip id) ~wnd ~state ~rx_ack ~tx_ack ~tx_wnd_update in (* The user application transmit buffer *) let utx = UTX.create ~wnd ~txq ~max_size:16384l in @@ -600,12 +601,12 @@ struct th (* Construct the main TCP thread *) - let create ip = + let create ip clock = Random.self_init (); let localport = 10000 + (Random.int 10000) in let listens = Hashtbl.create 1 in let connects = Hashtbl.create 1 in let channels = Hashtbl.create 7 in - { ip; localport; channels; listens; connects } + { clock; ip; localport; channels; listens; connects } end diff --git a/lib/tcp/pcb.mli b/lib/tcp/pcb.mli index 3a9065c77..7fd02f2dc 100644 --- a/lib/tcp/pcb.mli +++ b/lib/tcp/pcb.mli @@ -14,7 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *) -module Make(Ip:V1_LWT.IP)(Time:V1_LWT.TIME)(Clock:V1.CLOCK)(Random:V1.RANDOM) : sig +module Make(Ip:V1_LWT.IP)(Time:V1_LWT.TIME)(Clock:V1.MCLOCK)(Random:V1.RANDOM) : sig (** Overall state of the TCP stack *) type t @@ -57,5 +57,5 @@ module Make(Ip:V1_LWT.IP)(Time:V1_LWT.TIME)(Clock:V1.CLOCK)(Random:V1.RANDOM) : val write_nodelay: pcb -> Cstruct.t -> (unit, string) Result.result Lwt.t val writev_nodelay: pcb -> Cstruct.t list -> (unit, string) Result.result Lwt.t - val create: Ip.t -> t + val create: Ip.t -> Clock.t -> t end diff --git a/lib/tcp/segment.ml b/lib/tcp/segment.ml index 99803f221..07b575f47 100644 --- a/lib/tcp/segment.ml +++ b/lib/tcp/segment.ml @@ -230,7 +230,7 @@ type tx_flags = (* At most one of Syn/Fin/Rst/Psh allowed *) | Rst | Psh -module Tx (Time:V1_LWT.TIME) (Clock:V1.CLOCK) = struct +module Tx (Time:V1_LWT.TIME) (Clock:V1.MCLOCK) = struct module StateTick = State.Make(Time) module TT = Tcptimer.Make(Time) @@ -263,6 +263,7 @@ module Tx (Time:V1_LWT.TIME) (Clock:V1.CLOCK) = struct with this queue *) tx_wnd_update: int Lwt_mvar.t; (* Received updates to the transmit window *) rexmit_timer: Tcptimer.t; (* Retransmission timer for this connection *) + clock: Clock.t; (* whom to ask for the time *) mutable dup_acks: int; (* dup ack count for re-xmits *) } @@ -282,7 +283,7 @@ module Tx (Time:V1_LWT.TIME) (Clock:V1.CLOCK) = struct match rexmit_seg.seq = seq with | false -> Log.debug (fun fmt -> - fmt "PUSHING TIMER - new time=%f, new seq=%a" + fmt "PUSHING TIMER - new time=%Lu, new seq=%a" (Window.rto wnd) Sequence.pp rexmit_seg.seq); let ret = Tcptimer.ContinueSetPeriod (Window.rto wnd, rexmit_seg.seq) @@ -304,7 +305,7 @@ module Tx (Time:V1_LWT.TIME) (Clock:V1.CLOCK) = struct (fun () -> xmit ~flags ~wnd ~options ~seq rexmit_seg.data); Window.backoff_rto wnd; Log.debug (fun fmt -> - fmt "PUSHING TIMER - new time = %f, new seq = %a" + fmt "PUSHING TIMER - new time = %Lu, new seq = %a" (Window.rto wnd) Sequence.pp rexmit_seg.seq); let ret = Tcptimer.ContinueSetPeriod (Window.rto wnd, rexmit_seg.seq) @@ -341,7 +342,7 @@ module Tx (Time:V1_LWT.TIME) (Clock:V1.CLOCK) = struct let rec tx_ack_t () = let serviceack dupack ack_len seq win = let partleft = clearsegs q ack_len q.segs in - TX.tx_ack q.wnd (Sequence.sub seq partleft) win; + TX.tx_ack q.clock q.wnd (Sequence.sub seq partleft) win; match dupack || Window.fast_rec q.wnd with | true -> q.dup_acks <- q.dup_acks + 1; @@ -392,14 +393,14 @@ module Tx (Time:V1_LWT.TIME) (Clock:V1.CLOCK) = struct in tx_ack_t () - let create ~xmit ~wnd ~state ~rx_ack ~tx_ack ~tx_wnd_update = + let create ~clock ~xmit ~wnd ~state ~rx_ack ~tx_ack ~tx_wnd_update = let segs = Lwt_sequence.create () in let dup_acks = 0 in let expire = ontimer xmit state segs wnd in let period = Window.rto wnd in let rexmit_timer = TT.t ~period ~expire in let q = - { xmit; wnd; state; rx_ack; segs; tx_wnd_update; rexmit_timer; dup_acks } + { clock; xmit; wnd; state; rx_ack; segs; tx_wnd_update; rexmit_timer; dup_acks } in let t = rto_t q tx_ack in q, t @@ -418,7 +419,7 @@ module Tx (Time:V1_LWT.TIME) (Clock:V1.CLOCK) = struct let seq = Window.tx_nxt wnd in let seg = { data; flags; seq } in let seq_len = len seg in - TX.tx_advance q.wnd seq_len; + TX.tx_advance q.clock q.wnd seq_len; (* Queue up segment just sent for retransmission if needed *) let q_rexmit () = match Sequence.(gt seq_len zero) with diff --git a/lib/tcp/segment.mli b/lib/tcp/segment.mli index 18f4b6af5..e5675e569 100644 --- a/lib/tcp/segment.mli +++ b/lib/tcp/segment.mli @@ -55,7 +55,7 @@ type tx_flags = No_flags | Syn | Fin | Rst | Psh (** Either Syn/Fin/Rst allowed, but not combinations *) (** Pre-transmission queue *) -module Tx (Time:V1_LWT.TIME)(Clock:V1.CLOCK) : sig +module Tx (Time:V1_LWT.TIME)(Clock:V1.MCLOCK) : sig type xmit = flags:tx_flags -> wnd:Window.t -> options:Options.t list -> seq:Sequence.t -> Cstruct.t -> unit Lwt.t @@ -64,7 +64,7 @@ module Tx (Time:V1_LWT.TIME)(Clock:V1.CLOCK) : sig (** Queue of pre-transmission segments *) val create: - xmit:xmit -> wnd:Window.t -> state:State.t -> + clock:Clock.t -> xmit:xmit -> wnd:Window.t -> state:State.t -> rx_ack:Sequence.t Lwt_mvar.t -> tx_ack:(Sequence.t * int) Lwt_mvar.t -> tx_wnd_update:int Lwt_mvar.t -> t * unit Lwt.t diff --git a/lib/tcp/tcptimer.ml b/lib/tcp/tcptimer.ml index b77480860..255d2c5bc 100644 --- a/lib/tcp/tcptimer.ml +++ b/lib/tcp/tcptimer.ml @@ -19,14 +19,16 @@ open Lwt.Infix let src = Logs.Src.create "tcptimer" ~doc:"Mirage TCP Tcptimer module" module Log = (val Logs.src_log src : Logs.LOG) +type time = int64 + type tr = | Stoptimer | Continue of Sequence.t - | ContinueSetPeriod of (float * Sequence.t) + | ContinueSetPeriod of (time * Sequence.t) type t = { expire: (Sequence.t -> tr Lwt.t); - mutable period: float; + mutable period: time; mutable running: bool; } @@ -39,7 +41,7 @@ module Make(Time:V1_LWT.TIME) = struct Log.debug (fun f -> f "timerloop"); Stats.incr_timer (); let rec aux t s = - Time.sleep_ns (Duration.of_f t.period) >>= fun () -> + Time.sleep_ns t.period >>= fun () -> t.expire s >>= function | Stoptimer -> Stats.decr_timer (); diff --git a/lib/tcp/tcptimer.mli b/lib/tcp/tcptimer.mli index ffa903c86..b2de5351f 100644 --- a/lib/tcp/tcptimer.mli +++ b/lib/tcp/tcptimer.mli @@ -16,13 +16,15 @@ type t +type time = int64 + type tr = | Stoptimer | Continue of Sequence.t - | ContinueSetPeriod of (float * Sequence.t) + | ContinueSetPeriod of (time * Sequence.t) module Make(T:V1_LWT.TIME) : sig - val t : period: float -> expire: (Sequence.t -> tr Lwt.t) -> t + val t : period: time -> expire: (Sequence.t -> tr Lwt.t) -> t - val start : t -> ?p:float -> Sequence.t -> unit Lwt.t + val start : t -> ?p:time -> Sequence.t -> unit Lwt.t end diff --git a/lib/tcp/user_buffer.ml b/lib/tcp/user_buffer.ml index 5fb832a2b..117f2f3c8 100644 --- a/lib/tcp/user_buffer.ml +++ b/lib/tcp/user_buffer.ml @@ -109,7 +109,7 @@ end to decide how to throttle or breakup its data production with this information. *) -module Tx(Time:V1_LWT.TIME)(Clock:V1.CLOCK) = struct +module Tx(Time:V1_LWT.TIME)(Clock:V1.MCLOCK) = struct module TXS = Segment.Tx(Time)(Clock) diff --git a/lib/tcp/user_buffer.mli b/lib/tcp/user_buffer.mli index 58e9f1314..a6be15678 100644 --- a/lib/tcp/user_buffer.mli +++ b/lib/tcp/user_buffer.mli @@ -26,7 +26,7 @@ module Rx : sig val monitor: t -> int32 Lwt_mvar.t -> unit end -module Tx(Time:V1_LWT.TIME)(Clock:V1.CLOCK) : sig +module Tx(Time:V1_LWT.TIME)(Clock:V1.MCLOCK) : sig type t diff --git a/lib/tcp/window.ml b/lib/tcp/window.ml index 77f66b012..f6b76b31f 100644 --- a/lib/tcp/window.ml +++ b/lib/tcp/window.ml @@ -17,6 +17,8 @@ let src = Logs.Src.create "window" ~doc:"Mirage TCP Window module" module Log = (val Logs.src_log src : Logs.LOG) +type time = int64 + type t = { tx_mss: int; tx_isn: Sequence.t; @@ -47,10 +49,10 @@ type t = { mutable rtt_timer_on: bool; mutable rtt_timer_reset: bool; mutable rtt_timer_seq: Sequence.t; - mutable rtt_timer_starttime: float; - mutable srtt: float; - mutable rttvar: float; - mutable rto: float; + mutable rtt_timer_starttime: time; + mutable srtt: time; + mutable rttvar: time; + mutable rto: int64; mutable backoff_count: int; } @@ -96,10 +98,10 @@ let t ~rx_wnd_scale ~tx_wnd_scale ~rx_wnd ~tx_wnd ~rx_isn ~tx_mss ~tx_isn = let rtt_timer_on = false in let rtt_timer_reset = true in let rtt_timer_seq = tx_nxt in - let rtt_timer_starttime = 0.0 in - let srtt = 1.0 in - let rttvar = 0.0 in - let rto = 3.0 in + let rtt_timer_starttime = 0L in + let srtt = 1L in + let rttvar = 0L in + let rto = 3L in let backoff_count = 0 in { tx_isn; rx_isn; max_rx_wnd; max_tx_wnd; ack_serviced; ack_seq; ack_win; @@ -158,18 +160,18 @@ let set_tx_wnd t sz = let tx_mss t = t.tx_mss -module Make(Clock:V1.CLOCK) = struct +module Make(Clock:V1.MCLOCK) = struct (* Advance transmitted packet sequence number *) - let tx_advance t b = + let tx_advance clock t b = if not t.rtt_timer_on && not t.fast_recovery then begin t.rtt_timer_on <- true; t.rtt_timer_seq <- t.tx_nxt; - t.rtt_timer_starttime <- Clock.time (); + t.rtt_timer_starttime <- Clock.elapsed_ns clock; end; t.tx_nxt <- Sequence.add t.tx_nxt b (* An ACK was received - use it to adjust cwnd *) - let tx_ack t r win = + let tx_ack clock t r win = set_tx_wnd t win; if t.fast_recovery then begin if Sequence.gt r t.snd_una then @@ -187,16 +189,20 @@ module Make(Clock:V1.CLOCK) = struct t.snd_una <- r; if t.rtt_timer_on && Sequence.gt r t.rtt_timer_seq then begin t.rtt_timer_on <- false; - let rtt_m = Clock.time () -. t.rtt_timer_starttime in + let rtt_m = Int64.sub (Clock.elapsed_ns clock) t.rtt_timer_starttime in if t.rtt_timer_reset then begin t.rtt_timer_reset <- false; - t.rttvar <- (0.5 *. rtt_m); + t.rttvar <- Int64.div rtt_m 2L; t.srtt <- rtt_m; end else begin - t.rttvar <- (((1.0 -. beta) *. t.rttvar) +. (beta *. (abs_float (t.srtt -. rtt_m)))); - t.srtt <- (((1.0 -. alpha) *. t.srtt) +. (alpha *. rtt_m)); + let adjusted_rttvar = (1.0 -. beta) *. (Int64.to_float t.rttvar) in + let rttvar_addition = beta *. Int64.(sub t.srtt rtt_m |> abs |> to_float) in + let adjusted_srtt = (1.0 -. alpha) *. (Int64.to_float t.srtt) in + let srtt_addition = alpha *. (Int64.to_float rtt_m) in + t.rttvar <- Int64.of_float (adjusted_rttvar +. rttvar_addition); + t.srtt <- Int64.of_float (adjusted_srtt +. srtt_addition); end; - t.rto <- (max 1.0 (t.srtt +. (4.0 *. t.rttvar))); + t.rto <- (max 1L (Int64.add t.srtt (Int64.mul 4L t.rttvar))); end; end; let cwnd_incr = match t.cwnd < t.ssthresh with @@ -244,7 +250,7 @@ let alert_fast_rexmit t _ = let rto t = match t.backoff_count with | 0 -> t.rto - | _ -> t.rto *. (2. ** (float_of_int t.backoff_count)) + | _ -> Int64.(mul t.rto (shift_left 2L t.backoff_count)) let backoff_rto t = t.backoff_count <- t.backoff_count + 1; diff --git a/lib/tcp/window.mli b/lib/tcp/window.mli index cab17f8f6..2449606cd 100644 --- a/lib/tcp/window.mli +++ b/lib/tcp/window.mli @@ -28,9 +28,9 @@ val rx_advance_inseq : t -> Sequence.t -> unit val rx_nxt : t -> Sequence.t val rx_nxt_inseq : t -> Sequence.t -module Make(C:V1.CLOCK) : sig - val tx_advance : t -> Sequence.t -> unit - val tx_ack: t -> Sequence.t -> int -> unit +module Make(C:V1.MCLOCK) : sig + val tx_advance : C.t -> t -> Sequence.t -> unit + val tx_ack: C.t -> t -> Sequence.t -> int -> unit end val tx_nxt : t -> Sequence.t @@ -63,7 +63,7 @@ val max_tx_wnd : t -> int32 val alert_fast_rexmit : t -> Sequence.t -> unit -val rto : t -> float +val rto : t -> int64 val backoff_rto : t -> unit val max_rexmits_done : t -> bool diff --git a/lib_test/static_arp.ml b/lib_test/static_arp.ml index 2be99d26e..bbb4044e1 100644 --- a/lib_test/static_arp.ml +++ b/lib_test/static_arp.ml @@ -1,6 +1,6 @@ open Lwt.Infix -module Make(E : V1_LWT.ETHIF)(Clock : V1.CLOCK) (Time : V1_LWT.TIME) = struct +module Make(E : V1_LWT.ETHIF)(Clock : V1.MCLOCK) (Time : V1_LWT.TIME) = struct module A = Arpv4.Make(E)(Clock)(Time) (* generally repurpose A, but substitute input and query, and add functions for adding/deleting entries *) @@ -34,7 +34,7 @@ module Make(E : V1_LWT.ETHIF)(Clock : V1.CLOCK) (Time : V1_LWT.TIME) = struct let pp fmt repr = Format.fprintf fmt "%s" repr - let connect e = A.connect e >>= function + let connect e clock = A.connect e clock >>= function | `Ok base -> Lwt.return (`Ok { base; table = (Hashtbl.create 7) }) | `Error e -> Lwt.return (`Error e) diff --git a/lib_test/test_arp.ml b/lib_test/test_arp.ml index c9d08a426..7f55bcc68 100644 --- a/lib_test/test_arp.ml +++ b/lib_test/test_arp.ml @@ -4,42 +4,15 @@ let time_reduction_factor = 60 module Time = Vnetif_common.Time module Fast_clock = struct + let last_read = ref 0 - let last_read = ref (Clock.time ()) - - (* from mirage/types/V1.mli module type CLOCK *) - type tm = - { tm_sec: int; (** Seconds 0..60 *) - tm_min: int; (** Minutes 0..59 *) - tm_hour: int; (** Hours 0..23 *) - tm_mday: int; (** Day of month 1..31 *) - tm_mon: int; (** Month of year 0..11 *) - tm_year: int; (** Year - 1900 *) - tm_wday: int; (** Day of week (Sunday is 0) *) - tm_yday: int; (** Day of year 0..365 *) - tm_isdst: bool; (** Daylight time savings in effect *) - } - - let gmtime time = - let tm = Clock.gmtime time in - { - tm_sec = tm.Clock.tm_sec; - tm_min = tm.Clock.tm_min; - tm_hour = tm.Clock.tm_hour; - tm_mday = tm.Clock.tm_mday; - tm_mon = tm.Clock.tm_mon; - tm_year = tm.Clock.tm_year; - tm_wday = tm.Clock.tm_wday; - tm_yday = tm.Clock.tm_yday; - tm_isdst = tm.Clock.tm_isdst; - } - - let time () = - let this_time = Clock.time () in - let clock_diff = ((this_time -. !last_read) *. (float_of_int time_reduction_factor)) in - last_read := this_time; - this_time +. clock_diff + let advance_clock ns = + last_read := !last_read + ns + let elapsed_ns _ = + !last_read + + let period_ns _ = None end module Fast_time = struct type 'a io = 'a Lwt.t @@ -349,6 +322,9 @@ let entries_expire () = let test = Time.sleep_ns (Duration.of_ms 100) >>= fun () -> set_and_check ~listener:listen.arp ~claimant:speak first_ip >>= fun () -> + (* our custom clock requires some manual time-travel *) + Fast_clock.advance_clock (Duration.of_sec 90); + (* sleep for 1s to make sure we hit `tick` *) Time.sleep_ns (Duration.of_sec 1) >>= fun () -> (* asking now should generate a query *) not_in_cache ~listen:speak.netif expected_arp_query listen.arp first_ip;