This commit is contained in:
swrup 2025-11-11 02:07:51 +01:00
parent aa2ff7b2f0
commit 2f3113f55d
11742 changed files with 1223940 additions and 0 deletions

View file

@ -0,0 +1,148 @@
(*
* Copyright (c) 2010-2011 Anil Madhavapeddy <anil@recoil.org>
* Copyright (c) 2016 Hannes Mehnert <hannes@mehnert.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*)
module type S = sig
type t
val disconnect : t -> unit Lwt.t
type error = private [> `Timeout ]
val pp_error: error Fmt.t
val pp : t Fmt.t
val get_ips : t -> Ipaddr.V4.t list
val set_ips : t -> Ipaddr.V4.t list -> unit Lwt.t
val remove_ip : t -> Ipaddr.V4.t -> unit Lwt.t
val add_ip : t -> Ipaddr.V4.t -> unit Lwt.t
val query : t -> Ipaddr.V4.t -> (Macaddr.t, error) result Lwt.t
val input : t -> Cstruct.t -> unit Lwt.t
end
open Lwt.Infix
let logsrc = Logs.Src.create "ARP" ~doc:"Mirage ARP handler"
module Make (Ethernet : Ethernet.S) = struct
type error = [
| `Timeout
]
let pp_error ppf = function
| `Timeout -> Fmt.pf ppf "could not determine a link-level address for the IP address given"
type t = {
mutable state : ((Macaddr.t, error) result Lwt.t * (Macaddr.t, error) result Lwt.u) Arp_handler.t ;
ethif : Ethernet.t ;
mutable ticking : bool ;
}
let probe_repeat_delay = Duration.of_ms 1500 (* per rfc5227, 2s >= probe_repeat_delay >= 1s *)
let output t (arp, destination) =
let size = Arp_packet.size in
Ethernet.write t.ethif destination `ARP ~size
(fun b -> Arp_packet.encode_into arp b ; size) >|= function
| Ok () -> ()
| Error e ->
Logs.warn ~src:logsrc
(fun m -> m "error %a while outputting packet %a to %a"
Ethernet.pp_error e Arp_packet.pp arp Macaddr.pp destination)
let rec tick ~probe_delay t () =
if t.ticking then
Mirage_sleep.ns probe_delay >>= fun () ->
let state, requests, timeouts = Arp_handler.tick t.state in
t.state <- state ;
Lwt_list.iter_p (output t) requests >>= fun () ->
List.iter (fun (_, u) -> Lwt.wakeup u (Error `Timeout)) timeouts ;
tick ~probe_delay t ()
else
Lwt.return_unit
let pp ppf t = Arp_handler.pp ppf t.state
let input t frame =
let state, out, wake = Arp_handler.input t.state frame in
t.state <- state ;
(match out with
| None -> Lwt.return_unit
| Some pkt -> output t pkt) >|= fun () ->
match wake with
| None -> ()
| Some (mac, (_, u)) -> Lwt.wakeup u (Ok mac)
let get_ips t = Arp_handler.ips t.state
let create ?ipaddr t =
let mac = Arp_handler.mac t.state in
let state, out = Arp_handler.create ~logsrc ?ipaddr mac in
t.state <- state ;
match out with
| None -> Lwt.return_unit
| Some x -> output t x
let add_ip t ipaddr =
match Arp_handler.ips t.state with
| [] -> create ~ipaddr t
| _ ->
let state, out, wake = Arp_handler.alias t.state ipaddr in
t.state <- state ;
output t out >|= fun () ->
match wake with
| None -> ()
| Some (_, u) -> Lwt.wakeup u (Ok (Arp_handler.mac t.state))
let init_empty mac =
let state, _ = Arp_handler.create ~logsrc mac in
state
let set_ips t = function
| [] ->
let mac = Arp_handler.mac t.state in
let state = init_empty mac in
t.state <- state ;
Lwt.return_unit
| ipaddr::xs ->
create ~ipaddr t >>= fun () ->
Lwt_list.iter_s (add_ip t) xs
let remove_ip t ip =
let state = Arp_handler.remove t.state ip in
t.state <- state ;
Lwt.return_unit
let query t ip =
let merge = function
| None -> Lwt.wait ()
| Some a -> a
in
let state, res = Arp_handler.query t.state ip merge in
t.state <- state ;
match res with
| Arp_handler.RequestWait (pkt, (tr, _)) -> output t pkt >>= fun () -> tr
| Arp_handler.Wait (t, _) -> t
| Arp_handler.Mac mac -> Lwt.return (Ok mac)
let connect ?(probe_delay = probe_repeat_delay) ethif =
let mac = Ethernet.mac ethif in
let state = init_empty mac in
let t = { ethif; state; ticking = true} in
Lwt.async (tick ~probe_delay t);
Lwt.return t
let disconnect t =
t.ticking <- false ;
Lwt.return_unit
end

View file

@ -0,0 +1,72 @@
(*
* Copyright (c) 2010-2011 Anil Madhavapeddy <anil@recoil.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*)
(** {2 ARP} *)
(** Address resolution protocol, translating network addresses (e.g. IPv4)
into link layer addresses (MAC). *)
module type S = sig
type t
(** The type representing the internal state of the ARP layer. *)
val disconnect: t -> unit Lwt.t
(** Disconnect from the ARP layer. While this might take some time to
complete, it can never result in an error. *)
type error = private [> `Timeout ]
(** The type for ARP errors. *)
val pp_error: error Fmt.t
(** [pp_error] is the pretty-printer for errors. *)
(** Prettyprint cache contents *)
val pp : t Fmt.t
(** [get_ips arp] gets the bound IP address list in the [arp]
value. *)
val get_ips : t -> Ipaddr.V4.t list
(** [set_ips arp] sets the bound IP address list, which will transmit a
GARP packet also. *)
val set_ips : t -> Ipaddr.V4.t list -> unit Lwt.t
(** [remove_ip arp ip] removes [ip] to the bound IP address list in
the [arp] value, which will transmit a GARP packet for any remaining IPs in
the bound IP address list after the removal. *)
val remove_ip : t -> Ipaddr.V4.t -> unit Lwt.t
(** [add_ip arp ip] adds [ip] to the bound IP address list in the
[arp] value, which will transmit a GARP packet also. *)
val add_ip : t -> Ipaddr.V4.t -> unit Lwt.t
(** [query arp ip] queries the cache in [arp] for an ARP entry
corresponding to [ip], which may result in the sender sleeping
waiting for a response. *)
val query : t -> Ipaddr.V4.t -> (Macaddr.t, error) result Lwt.t
(** [input arp frame] will handle an ARP frame. If it is a response,
it will update its cache, otherwise will try to satisfy the
request. *)
val input : t -> Cstruct.t -> unit Lwt.t
end
module Make (Ethernet : Ethernet.S) : sig
include S
val connect : ?probe_delay:int64 -> Ethernet.t -> t Lwt.t
end

View file

@ -0,0 +1,5 @@
(library
(name arp_mirage)
(public_name arp.mirage)
(wrapped false)
(libraries arp ethernet mirage-sleep lwt logs duration))