@@ -4,53 +4,106 @@ type 'a entry =
44 | Dynamic of Macaddr .t * int
55 | Pending of 'a * int
66
7+ let [@ coverage off] pp_entry now k pp =
8+ function
9+ | Static (m , adv ) ->
10+ let adv = if adv then " advertising" else " " in
11+ Format. fprintf pp " %a at %a (static%s)" Ipaddr.V4. pp k Macaddr. pp m adv
12+ | Dynamic (m , t ) ->
13+ Format. fprintf pp " %a at %a (timeout in %d)" Ipaddr.V4. pp k
14+ Macaddr. pp m (t - now)
15+ | Pending (_ , retries ) ->
16+ Format. fprintf pp " %a (incomplete, %d retries left)"
17+ Ipaddr.V4. pp k (retries - now)
18+
719module M = struct
8- module M = Map. Make (Ipaddr. V4 )
9- module Present = struct
10- type t = unit
11- let weight (_ : t ) = 1
20+ module IpMap = Map. Make (Ipaddr. V4 )
21+ module Timeout = struct
22+ type t = int * Ipaddr.V4 .t
23+
24+ let compare (t1 , ip1 ) (t2 , ip2 ) =
25+ match Int. compare t1 t2 with
26+ | 0 -> Ipaddr.V4. compare ip1 ip2
27+ | n -> n
28+
29+ let of_entry k = function
30+ | Static _ | Pending _ -> None
31+ | Dynamic (_ , timeout ) -> Some (timeout, k)
1232 end
13- module LRU = Lru.F. Make (Ipaddr. V4 )(Present )
1433
15- type 'a t =
16- { map : 'a entry M .t
17- ; mutable dynamic_lru : LRU .t
18- }
34+ module Timeouts = Set. Make (Timeout )
35+
36+ type !+'a t =
37+ { map : 'a entry IpMap .t
38+ ; values : Timeouts .t
39+ ; capacity : int
40+ }
41+
42+ let empty capacity =
43+ { map = IpMap. empty; values = Timeouts. empty; capacity }
1944
20- let empty capacity =
21- { map = M. empty; dynamic_lru = LRU. empty capacity }
45+ let cardinal t = IpMap. cardinal t.map
2246
23- let fold f t init =
24- M. fold f t.map init
2547
26- let cardinal t = M. cardinal t.map
48+ let invariant t =
49+ assert (cardinal t < = t.capacity);
50+ (* only dynamic values are stored in TimeoutMap, due to functional 'a we can't easily compare it *)
51+ assert (IpMap. cardinal t.map > = Timeouts. cardinal t.values);
52+ assert (Timeouts. for_all (fun ((_ , k ) as v ) ->
53+ Option. compare Timeout. compare (IpMap. find k t.map |> Timeout. of_entry k) (Some v) = 0 )
54+ t.values);
2755
28- let iter f t = M. iter f t.map
56+ assert (IpMap. for_all (fun k v ->
57+ match Timeout. of_entry k v with
58+ | None -> true
59+ | Some v' ->
60+ Timeouts. mem v' t.values) t.map);
61+ assert (Timeouts. for_all (fun ((_ , k ) as v ) ->
62+ match Timeout. of_entry k (IpMap. find k t.map) with
63+ | None -> false
64+ | Some v' -> Timeout. compare v v' = 0
65+ ) t.values)
2966
30- let find k t =
31- let v = M. find k t.map in
32- t.dynamic_lru < - LRU. promote k t.dynamic_lru;
33- v
67+ let find k t = IpMap. find k t.map
3468
35- let add k v t =
36- let map = M. add k v t.map
37- and dynamic_lru = match v with
38- | Dynamic _ -> LRU. add k () t.dynamic_lru
39- | _ -> LRU. remove k t.dynamic_lru
69+ let fold f t init = IpMap. fold f t.map init
70+
71+ let iter f t = IpMap. iter f t.map
72+
73+ let remove_kv k v t =
74+ let values =
75+ match v with
76+ | None -> t.values
77+ | Some v -> Timeouts. remove v t.values
4078 in
41- let map, dynamic_lru =
42- if LRU. weight t.dynamic_lru > LRU. capacity t.dynamic_lru then begin
43- match LRU. pop_lru t.dynamic_lru with
44- | Some (( drop , () ), dynamic_lru ) ->
45- M. remove drop t.map, dynamic_lru
46- | None -> map, dynamic_lru
47- end else
48- map, dynamic_lru
79+ { t with map = IpMap. remove k t.map
80+ ; values }
81+
82+ let add ~ logsrc ~ epoch k v t =
83+ let values =
84+ match Timeout. of_entry k v with
85+ | None -> t.values
86+ | Some v -> Timeouts. add v t.values
4987 in
50- { map; dynamic_lru }
88+ let t =
89+ { t with map = IpMap. add k v t.map
90+ ; values
91+ }
92+ in
93+ if cardinal t > t.capacity then
94+ let (timeout, k) as v = Timeouts. min_elt t.values in
95+ Logs. debug ~src: logsrc
96+ (fun pp -> pp " dropping ARP entry %a (timeout in %d)"
97+ Ipaddr.V4. pp k (timeout - epoch)) ;
98+ remove_kv k (Some v) t
99+ else
100+ t
51101
52102 let remove k t =
53- { map = M. remove k t.map; dynamic_lru = LRU. remove k t.dynamic_lru }
103+ match IpMap. find_opt k t.map with
104+ | Some v ->
105+ remove_kv k (Timeout. of_entry k v) t
106+ | None -> t
54107end
55108
56109type 'a t = {
@@ -71,19 +124,8 @@ let ips t =
71124
72125let mac t = t.mac
73126
74- let [@ coverage off] pp_entry now k pp =
75- function
76- | Static (m , adv ) ->
77- let adv = if adv then " advertising" else " " in
78- Format. fprintf pp " %a at %a (static%s)" Ipaddr.V4. pp k Macaddr. pp m adv
79- | Dynamic (m , t ) ->
80- Format. fprintf pp " %a at %a (timeout in %d)" Ipaddr.V4. pp k
81- Macaddr. pp m (t - now)
82- | Pending (_ , retries ) ->
83- Format. fprintf pp " %a (incomplete, %d retries left)"
84- Ipaddr.V4. pp k (retries - now)
85-
86127let [@ coverage off] pp pp t =
128+ M. invariant t.cache;
87129 Format. fprintf pp " mac %a ip %a entries %d timeout %d retries %d@."
88130 Macaddr. pp t.mac
89131 Ipaddr.V4. pp t.ip
@@ -100,7 +142,7 @@ let pending t ip =
100142let mac0 = Macaddr. of_octets_exn (Cstruct. to_string (Cstruct. create 6 ))
101143
102144let alias t ip =
103- let cache = M. add ip (Static (t.mac, true )) t.cache in
145+ let cache = M. add ~logsrc: t.logsrc ~epoch: t.epoch ip (Static (t.mac, true )) t.cache in
104146 (* see RFC5227 Section 3 why we send out an ARP request *)
105147 let garp = Arp_packet. ({
106148 operation = Request ;
@@ -131,7 +173,7 @@ let create ?(cache_size=1024) ?(timeout = 800) ?(retries = 5)
131173 t, Some garp
132174
133175let static t ip mac =
134- let cache = M. add ip (Static (mac, false )) t.cache in
176+ let cache = M. add ~logsrc: t.logsrc ~epoch: t.epoch ip (Static (mac, false )) t.cache in
135177 { t with cache }, pending t ip
136178
137179let remove t ip =
@@ -186,7 +228,7 @@ let tick t =
186228
187229let handle_reply t source mac =
188230 let extcache =
189- let cache = M. add source (Dynamic (mac, t.epoch + t.timeout)) t.cache in
231+ let cache = M. add ~logsrc: t.logsrc ~epoch: t.epoch source (Dynamic (mac, t.epoch + t.timeout)) t.cache in
190232 { t with cache }
191233 in
192234 match M. find source t.cache with
@@ -271,11 +313,11 @@ let query t ip a =
271313 match M. find ip t.cache with
272314 | exception Not_found ->
273315 let a = a None in
274- let cache = M. add ip (Pending (a, t.epoch + t.retries)) t.cache in
316+ let cache = M. add ~logsrc: t.logsrc ~epoch: t.epoch ip (Pending (a, t.epoch + t.retries)) t.cache in
275317 { t with cache }, RequestWait (request t ip, a)
276318 | Pending (x , r ) ->
277319 let a = a (Some x) in
278- let cache = M. add ip (Pending (a, r)) t.cache in
320+ let cache = M. add ~logsrc: t.logsrc ~epoch: t.epoch ip (Pending (a, r)) t.cache in
279321 { t with cache }, Wait a
280322 | Static (m , _ ) -> t, Mac m
281323 | Dynamic (m , _ ) -> t, Mac m
0 commit comments