package mirage-net-xen

  1. Overview
  2. Docs

Source file tX.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
(*
 * Copyright (c) 2010-2013 Anil Madhavapeddy <anil@recoil.org>
 * Copyright (c) 2014-2015 Citrix Inc
 *
 * 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 Request = struct
  type error = { impossible : 'a. 'a }

  type t = {
    gref: int32;
    offset: int;
    flags: Flags.t;
    id: int;

    (* For frames split over multiple requests, first.size is the total
       size of the frame. Each of the following requests gives the size
       of that fragment. The receiver recovers the actual size of the
       first fragment by subtracting all of the other sizes. *)
    size: int;
  }

  let get_req_gref c = Cstruct.LE.get_uint32 c 0
  let set_req_gref c gref = Cstruct.LE.set_uint32 c 0 gref
  let get_req_offset c = Cstruct.LE.get_uint16 c 4
  let set_req_offset c off = Cstruct.LE.set_uint16 c 4 off
  let get_req_flags c = Cstruct.LE.get_uint16 c 6
  let set_req_flags c flags = Cstruct.LE.set_uint16 c 6 flags
  let get_req_id c = Cstruct.LE.get_uint16 c 8
  let set_req_id c id = Cstruct.LE.set_uint16 c 8 id
  let get_req_size c = Cstruct.LE.get_uint16 c 10
  let set_req_size c size = Cstruct.LE.set_uint16 c 10 size
  let sizeof_req = 12

  let write t slot =
    let flags = Flags.to_int t.flags in
    set_req_gref slot t.gref;
    set_req_offset slot t.offset;
    set_req_flags slot flags;
    set_req_id slot t.id;
    set_req_size slot t.size

  let within_page name x =
    if x < 0 || x > 4096
    then Error (Printf.sprintf "%s is corrupt: expected 0 <= %s <= 4096 but got %d" name name x)
    else Ok x

  let read slot =
    let ( let* ) = Result.bind in
    let gref = get_req_gref slot in
    let offset = get_req_offset slot in
    let* offset = within_page "TX.Request.offset" offset in
    let flags = Flags.of_int (get_req_flags slot) in
    let id = get_req_id slot in
    let size = get_req_size slot in
    Ok { gref; offset; flags; id; size }

  let flags t = t.flags

  let size t = Ok t.size
end

module Response = struct
  type status =
    | DROPPED
    | ERROR
    | OKAY
    | NULL

  let status_to_int = function
    | DROPPED -> 0xfffe
    | ERROR -> 0xffff
    | OKAY -> 0
    | NULL -> 1

  let int_to_status = function
    | 0xfffe -> Some DROPPED
    | 0xffff -> Some ERROR
    | 0 -> Some OKAY
    | 1 -> Some NULL
    | _ -> None

  type t = {
    id: int;
    status: status;
  }

  let get_resp_id c = Cstruct.LE.get_uint16 c 0
  let set_resp_id c id = Cstruct.LE.set_uint16 c 0 id
  let get_resp_status c = Cstruct.LE.get_uint16 c 2
  let set_resp_status c status = Cstruct.LE.set_uint16 c 2 status
  let sizeof_resp = 4

  let write t slot =
    set_resp_id slot t.id;
    set_resp_status slot (status_to_int t.status)

  let read slot =
    let id = get_resp_id slot in
    let st = get_resp_status slot in
    match int_to_status st with
    | None -> failwith (Printf.sprintf "Invalid TX.Response.status %d" st)
    | Some status -> { id; status }
end

let total_size = max Request.sizeof_req Response.sizeof_resp
let () = assert(total_size = 12)