package mnet
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>
An implementation of TCP (Transmission Control Protocol) in OCaml for Miou & Solo5
Install
dune-project
Dependency
Authors
Maintainers
Sources
mnet-0.0.2.tbz
sha256=92b1cfec8487423090ed7abedee824ca20db86f1a7af7e308b4118bc0f774e03
sha512=ce7685c363581121c7d8ae0c33d7dff30ee2dd9dcd29d56f451ac3261b84a91d35a2fa65b31f1f321ddc4b5984e21840459c63614e81ee814f47ac24376bf018
doc/src/mnet.ethernet/ethernet.ml.html
Source file ethernet.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183let src = Logs.Src.create "mnet.ethernet" module Log = (val Logs.src_log src : Logs.LOG) module Packet = struct type protocol = ARPv4 | IPv4 | IPv6 type t = { src: Macaddr.t; dst: Macaddr.t; protocol: protocol option } let guard err fn = if fn () then Ok () else Error err let protocol_of_int = function | 0x0806 -> Some ARPv4 | 0x0800 -> Some IPv4 | 0x86dd -> Some IPv6 | _ -> None let protocol_to_int = function | ARPv4 -> 0x0806 | IPv4 -> 0x0800 | IPv6 -> 0x86dd let decode bstr ~len = let ( let* ) = Result.bind in let* () = guard `Invalid_ethernet_packet @@ fun () -> len >= 14 in let dst = Macaddr.of_octets_exn (Bstr.sub_string bstr ~off:0 ~len:6) in let src = Macaddr.of_octets_exn (Bstr.sub_string bstr ~off:6 ~len:6) in let protocol = Bstr.get_uint16_be bstr 12 in let protocol = protocol_of_int protocol in let payload = Slice_bstr.make ~off:14 ~len:(len - 14) bstr in Ok ({ src; dst; protocol }, payload) let encode_into t ?(off = 0) bstr = match t.protocol with | None -> Fmt.invalid_arg "Ethernet.Packet.encode_into: you must specify a protocol" | Some protocol -> let protocol = protocol_to_int protocol in Bstr.blit_from_string (Macaddr.to_octets t.dst) ~src_off:0 bstr ~dst_off:(off + 0) ~len:6; Bstr.blit_from_string (Macaddr.to_octets t.src) ~src_off:0 bstr ~dst_off:(off + 6) ~len:6; Bstr.set_uint16_be bstr 12 protocol end type protocol = Packet.protocol = ARPv4 | IPv4 | IPv6 type t = { net: Mkernel.Net.t ; mutable handler: handler ; mtu: int ; mac: Macaddr.t ; tags: Logs.Tag.set ; bstr_ic: Bstr.t ; bstr_oc: Bstr.t ; extern: extern option ; cnt: int Atomic.t } and 'a packet = { src: Macaddr.t option ; dst: Macaddr.t ; protocol: Packet.protocol ; payload: 'a } and extern = External : 'net hypercalls -> extern [@@unboxed] and 'net hypercalls = { device: 'net ; swr: 'net -> ?off:int -> ?len:int -> Bstr.t -> unit ; srd: 'net -> ?off:int -> ?len:int -> Bstr.t -> int } and handler = Slice_bstr.t packet -> unit exception Packet_ignored let mac { mac; _ } = mac let uninteresting_packet _ = raise_notrace Packet_ignored let write_directly_into t ?len:plus (packet : (Bstr.t -> int) packet) = let fn = packet.payload in let src = Option.value ~default:t.mac packet.src in let = Logs.Tag.add Mnet_tags.mac src Logs.Tag.empty in let pkt = { Packet.src; dst= packet.dst; protocol= Some packet.protocol } in (* NOTE(dinosaure): clean-up our buffer. *) Packet.encode_into pkt ~off:0 t.bstr_oc; let bstr = Bstr.sub t.bstr_oc ~off:14 ~len:(Bstr.length t.bstr_oc - 14) in Bstr.memset bstr ~off:0 ~len:(Bstr.length bstr) '\000'; let plus' = fn bstr in Option.iter (fun plus -> assert (plus = plus')) plus; Log.debug (fun m -> m ~tags "write ethernet packet src:%a -> dst:%a (%d byte(s))" Macaddr.pp src Macaddr.pp packet.dst plus'); Log.debug (fun m -> m ~tags "@[<hov>%a@]" (Hxd_string.pp Hxd.default) (Bstr.sub_string t.bstr_oc ~off:0 ~len:(14 + plus'))); (* TODO(dinosaure): we must figure out about the impact of such branch. We also should compare when we directly use [Mkernel.net.write] or if we can wrap [read]/[write] into an [External] value (to simplify the API). *) match t.extern with | None -> (* TODO(dinosaure): use [Mkernel.Net.write_into]. *) Mkernel.Net.write_bigstring t.net ~off:0 ~len:(14 + plus') t.bstr_oc | Some (External { device; swr; _ }) -> swr device ~off:0 ~len:(14 + plus') t.bstr_oc let of_interest t dst = Macaddr.compare dst t.mac == 0 || Macaddr.is_unicast dst == false let handler t bstr ~len = if len >= 14 then let = t.tags in match Packet.decode bstr ~len with | Error _ -> let str = Bstr.sub_string t.bstr_ic ~off:0 ~len in Log.err (fun m -> m ~tags "Invalid Ethernet packet"); Log.err (fun m -> m ~tags "@[<hov>%a@]" (Hxd_string.pp Hxd.default) str) | Ok ({ Packet.protocol= Some protocol; src; dst }, payload) -> begin try if of_interest t dst then t.handler { src= Some src; dst; protocol; payload } with | Packet_ignored -> () | exn -> Log.err (fun m -> m ~tags "Unexpected exception from the user's handler: %s" (Printexc.to_string exn)) end | Ok _ -> () let rec daemon t = let len = match t.extern with | None -> Mkernel.Net.read_bigstring t.net t.bstr_ic | Some (External { device; srd; _ }) -> srd device t.bstr_ic in handler t t.bstr_ic ~len; daemon t let write_directly_into t ?len ?src ~dst ~protocol fn = let pkt = { src; dst; protocol; payload= fn } in write_directly_into t ?len pkt let guard err fn = if fn () then Ok () else Error err type daemon = unit Miou.t let create ?(mtu = 1500) ?(handler = uninteresting_packet) ?hypercalls:extern mac net = let ( let* ) = Result.bind in let* () = guard `MTU_too_small @@ fun () -> mtu > 14 in (* enough for Ethernet packets *) let bstr_ic = Bstr.create (14 + mtu) in let bstr_oc = Bstr.create (14 + mtu) in (* NOTE(dinosaure): the first [Bstr.sub] does a [malloc()], then any [Bstr.sub] are cheap. We should use [Slice] instead of [Bstr]. TODO! *) let bstr_ic = Bstr.sub bstr_ic ~off:0 ~len:(14 + mtu) in let bstr_oc = Bstr.sub bstr_oc ~off:0 ~len:(14 + mtu) in let = Logs.Tag.empty in let = Logs.Tag.add Mnet_tags.mac mac tags in let cnt = Atomic.make 0 in let t = { net; handler; mtu; mac; tags; bstr_ic; bstr_oc; extern; cnt } in let daemon = Miou.async @@ fun () -> daemon t in Ok (daemon, t) let mtu { mtu; _ } = mtu let macaddr { mac; _ } = mac let { ; _ } = tags let set_handler t handler = Atomic.incr t.cnt; t.handler <- handler; let = t.tags in if Atomic.get t.cnt > 1 then Log.warn (fun m -> m ~tags "Ethernet handler modified more than once") let extend_handler_with t handler = let handler pkt = try t.handler pkt with Packet_ignored -> handler pkt in t.handler <- handler let kill = Miou.cancel
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>