albatross/src/vmm_core.ml

330 lines
9.6 KiB
OCaml
Raw Normal View History

2018-11-10 00:02:07 +00:00
(* (c) 2017, 2018 Hannes Mehnert, all rights reserved *)
2017-05-26 14:30:34 +00:00
open Astring
let tmpdir = Fpath.(v "/var" / "run" / "albatross")
let sockdir = Fpath.(tmpdir / "util")
2018-10-23 22:03:36 +00:00
type service = [ `Console | `Log | `Stats | `Vmmd ]
let socket_path t =
let path = match t with
2019-10-10 20:26:36 +00:00
| `Console -> "console"
| `Vmmd -> "vmmd"
| `Stats -> "stat"
| `Log -> "log"
in
2019-10-10 20:26:36 +00:00
Fpath.to_string Fpath.(sockdir / path + "sock")
let pp_socket ppf t =
let name = socket_path t in
Fmt.pf ppf "socket: %s" name
2017-05-26 14:30:34 +00:00
module I = struct
type t = int
let compare : int -> int -> int = compare
end
module IS = Set.Make(I)
module IM = Map.Make(I)
module Name = struct
type t = string list
let root = []
let is_root x = x = []
let rec equal x y = match x, y with
| [], [] -> true
| x::xs, y::ys -> x = y && equal xs ys
| _ -> false
let [@inline always] valid_label s =
String.length s < 20 &&
String.length s > 0 &&
String.get s 0 <> '-' && (* leading may not be '-' *)
String.for_all (function
| 'a'..'z' | 'A'..'Z' | '0'..'9' | '-' -> true
| _ -> false)
s (* only LDH (letters, digits, hyphen)! *)
let to_string ids = String.concat ~sep:"." ids
let to_list x = x
2019-10-10 20:26:36 +00:00
let drop x = match List.rev x with
| [] -> []
| _::tl -> List.rev tl
let append_exn lbl x =
if valid_label lbl then
x @ [ lbl ]
else
invalid_arg "label not valid"
let append lbl x =
if valid_label lbl then
Ok (x @ [ lbl ])
else
Error (`Msg "label not valid")
let prepend lbl x =
if valid_label lbl then
Ok (lbl :: x)
else
Error (`Msg "label not valid")
let domain id = match List.rev id with
| _::prefix -> List.rev prefix
| [] -> []
let image_file name =
let file = to_string name in
Fpath.(tmpdir / file + "img")
let fifo_file name =
let file = to_string name in
Fpath.(tmpdir / "fifo" / file)
let block_name vm_name dev =
List.rev (dev :: List.rev (domain vm_name))
let of_string str =
let id = String.cuts ~sep:"." str in
if List.for_all valid_label id then
Ok id
else
Error (`Msg "invalid name")
let of_list labels =
if List.for_all valid_label labels then
Ok labels
else
Error (`Msg "invalid name")
let drop_super ~super ~sub =
let rec go sup sub = match sup, sub with
| [], xs -> Some xs
| _, [] -> None
| x::xs, z::zs -> if String.equal x z then go xs zs else None
in
go super sub
let is_sub ~super ~sub =
match drop_super ~super ~sub with None -> false | Some _ -> true
let pp ppf ids =
Fmt.(pf ppf "[vm: %a]" (list ~sep:(unit ".") string) ids)
end
2017-05-26 14:30:34 +00:00
2018-11-11 02:09:37 +00:00
module Policy = struct
let pp_is ppf is = Fmt.pf ppf "%a" Fmt.(list ~sep:(unit ",") int) (IS.elements is)
let eq_int (a : int) (b : int) = a = b
type t = {
vms : int ;
cpuids : IS.t ;
memory : int ;
block : int option ;
bridges : String.Set.t ;
2018-11-11 02:09:37 +00:00
}
let equal p1 p2 =
let eq_opt a b = match a, b with
| None, None -> true
| Some a, Some b -> eq_int a b
| _ -> false
in
eq_int p1.vms p2.vms &&
IS.equal p1.cpuids p2.cpuids &&
eq_int p1.memory p2.memory &&
eq_opt p1.block p2.block &&
String.Set.equal p1.bridges p2.bridges
2018-11-11 02:09:37 +00:00
let pp ppf res =
Fmt.pf ppf "policy: %d vms %a cpus %d MB memory %a MB block bridges: %a"
res.vms pp_is res.cpuids res.memory
Fmt.(option ~none:(unit "no") int) res.block
(String.Set.pp ~sep:Fmt.(unit ", ") Fmt.string) res.bridges
2018-11-11 02:09:37 +00:00
end
2017-05-26 14:30:34 +00:00
2018-11-13 00:02:05 +00:00
module Unikernel = struct
type typ = [ `Hvt_amd64 | `Hvt_arm64 | `Hvt_amd64_compressed ]
2018-11-11 02:20:22 +00:00
2018-11-13 00:02:05 +00:00
let pp_typ ppf = function
2018-11-11 02:20:22 +00:00
| `Hvt_amd64 -> Fmt.pf ppf "hvt-amd64"
| `Hvt_amd64_compressed -> Fmt.pf ppf "hvt-amd64-compressed"
| `Hvt_arm64 -> Fmt.pf ppf "hvt-arm64"
2019-10-10 23:10:33 +00:00
type fail_behaviour = [ `Quit | `Restart ]
let pp_fail_behaviour ppf f =
Fmt.string ppf (match f with `Quit -> "quit" | `Restart -> "restart")
2018-11-11 02:20:22 +00:00
type config = {
cpuid : int ;
2018-11-13 00:02:05 +00:00
memory : int ;
block_devices : string list ;
bridges : string list ;
2018-11-13 00:02:05 +00:00
image : typ * Cstruct.t ;
2018-11-11 02:20:22 +00:00
argv : string list option ;
2019-10-10 23:10:33 +00:00
fail_behaviour : fail_behaviour;
2018-11-11 02:20:22 +00:00
}
let pp_image ppf (typ, blob) =
let l = Cstruct.len blob in
2018-11-13 00:02:05 +00:00
Fmt.pf ppf "%a: %d bytes" pp_typ typ l
2018-11-11 02:20:22 +00:00
let pp_config ppf (vm : config) =
2019-10-10 23:10:33 +00:00
Fmt.pf ppf "fail behaviour %a, cpu %d, %d MB memory, block devices %a@ bridge %a, image %a, argv %a"
pp_fail_behaviour vm.fail_behaviour
2018-11-13 00:02:05 +00:00
vm.cpuid vm.memory
Fmt.(list ~sep:(unit ", ") string) vm.block_devices
Fmt.(list ~sep:(unit ", ") string) vm.bridges
2018-11-13 00:02:05 +00:00
pp_image vm.image
2018-11-11 02:20:22 +00:00
Fmt.(option ~none:(unit "no") (list ~sep:(unit " ") string)) vm.argv
type t = {
config : config ;
cmd : Bos.Cmd.t ;
pid : int ;
taps : string list ;
}
let pp ppf vm =
Fmt.pf ppf "pid %d@ taps %a (block %a) cmdline %a"
vm.pid
Fmt.(list ~sep:(unit ", ") string) vm.taps
Fmt.(list ~sep:(unit ", ") string) vm.config.block_devices
2018-11-11 02:20:22 +00:00
Bos.Cmd.pp vm.cmd
end
2018-10-23 22:03:36 +00:00
module Stats = struct
type rusage = {
utime : (int64 * int) ;
stime : (int64 * int) ;
maxrss : int64 ;
ixrss : int64 ;
idrss : int64 ;
isrss : int64 ;
minflt : int64 ;
majflt : int64 ;
nswap : int64 ;
inblock : int64 ;
outblock : int64 ;
msgsnd : int64 ;
msgrcv : int64 ;
nsignals : int64 ;
nvcsw : int64 ;
nivcsw : int64 ;
}
let pp_rusage ppf r =
Fmt.pf ppf "utime %Lu.%d stime %Lu.%d maxrss %Lu ixrss %Lu idrss %Lu isrss %Lu minflt %Lu majflt %Lu nswap %Lu inblock %Lu outblock %Lu msgsnd %Lu msgrcv %Lu signals %Lu nvcsw %Lu nivcsw %Lu"
(fst r.utime) (snd r.utime) (fst r.stime) (snd r.stime) r.maxrss r.ixrss r.idrss r.isrss r.minflt r.majflt r.nswap r.inblock r.outblock r.msgsnd r.msgrcv r.nsignals r.nvcsw r.nivcsw
let pp_rusage_mem ppf r =
Fmt.pf ppf "maxrss %Lu ixrss %Lu idrss %Lu isrss %Lu minflt %Lu majflt %Lu"
r.maxrss r.ixrss r.idrss r.isrss r.minflt r.majflt
type kinfo_mem = {
vsize : int64 ;
rss : int64 ;
tsize : int64 ;
dsize : int64 ;
ssize : int64 ;
runtime : int64 ;
cow : int ;
start : (int64 * int) ;
}
2018-10-23 22:03:36 +00:00
let pp_kinfo_mem ppf t =
Fmt.pf ppf "virtual-size %Lu rss %Lu text-size %Lu data-size %Lu stack-size %Lu runtime %Lu cow %u start %Lu.%d"
t.vsize t.rss t.tsize t.dsize t.ssize t.runtime t.cow (fst t.start) (snd t.start)
2018-10-23 22:03:36 +00:00
type vmm = (string * int64) list
let pp_vmm ppf vmm =
Fmt.(list ~sep:(unit "@.") (pair ~sep:(unit ": ") string int64)) ppf vmm
let pp_vmm_mem ppf vmm =
Fmt.(list ~sep:(unit "@.") (pair ~sep:(unit ": ") string int64)) ppf
(List.filter (fun (k, _) -> k = "Resident memory" || k = "Wired memory") vmm)
2018-10-23 22:03:36 +00:00
type ifdata = {
bridge : string ;
2018-10-23 22:03:36 +00:00
flags : int32 ;
send_length : int32 ;
max_send_length : int32 ;
send_drops : int32 ;
mtu : int32 ;
baudrate : int64 ;
input_packets : int64 ;
input_errors : int64 ;
output_packets : int64 ;
output_errors : int64 ;
collisions : int64 ;
input_bytes : int64 ;
output_bytes : int64 ;
input_mcast : int64 ;
output_mcast : int64 ;
input_dropped : int64 ;
output_dropped : int64 ;
}
let pp_ifdata ppf i =
Fmt.pf ppf "bridge %s flags %lX send_length %lu max_send_length %lu send_drops %lu mtu %lu baudrate %Lu input_packets %Lu input_errors %Lu output_packets %Lu output_errors %Lu collisions %Lu input_bytes %Lu output_bytes %Lu input_mcast %Lu output_mcast %Lu input_dropped %Lu output_dropped %Lu"
i.bridge i.flags i.send_length i.max_send_length i.send_drops i.mtu i.baudrate i.input_packets i.input_errors i.output_packets i.output_errors i.collisions i.input_bytes i.output_bytes i.input_mcast i.output_mcast i.input_dropped i.output_dropped
2018-10-23 22:03:36 +00:00
type t = rusage * kinfo_mem option * vmm option * ifdata list
let pp ppf (ru, mem, vmm, ifs) =
Fmt.pf ppf "%a@.%a@.%a@.%a"
2018-10-23 22:03:36 +00:00
pp_rusage ru
Fmt.(option ~none:(unit "no kinfo_mem stats") pp_kinfo_mem) mem
2018-10-23 22:03:36 +00:00
Fmt.(option ~none:(unit "no vmm stats") pp_vmm) vmm
Fmt.(list ~sep:(unit "@.@.") pp_ifdata) ifs
end
2017-05-26 14:30:34 +00:00
2018-10-23 22:03:36 +00:00
type process_exit = [ `Exit of int | `Signal of int | `Stop of int ]
2017-05-26 14:30:34 +00:00
2018-10-23 22:03:36 +00:00
let pp_process_exit ppf = function
2019-10-10 23:10:33 +00:00
| `Exit n -> Fmt.pf ppf "exit %d" n
| `Signal n -> Fmt.pf ppf "signal %a (numeric %d)" Fmt.Dump.signal n n
| `Stop n -> Fmt.pf ppf "stop %a (numeric %d)" Fmt.Dump.signal n n
2018-10-23 19:53:44 +00:00
2017-05-26 14:30:34 +00:00
module Log = struct
2018-10-23 22:03:36 +00:00
type log_event = [
| `Login of Name.t * Ipaddr.V4.t * int
| `Logout of Name.t * Ipaddr.V4.t * int
2018-10-23 22:03:36 +00:00
| `Startup
| `Unikernel_start of Name.t * int * (string * string) list * (string * Name.t) list
2018-11-13 00:02:05 +00:00
| `Unikernel_stop of Name.t * int * process_exit
2018-12-06 21:53:15 +00:00
| `Hup
2018-10-23 22:03:36 +00:00
]
let name = function
| `Startup -> []
| `Login (name, _, _) -> name
| `Logout (name, _, _) -> name
2018-11-13 00:02:05 +00:00
| `Unikernel_start (name, _, _ ,_) -> name
| `Unikernel_stop (name, _, _) -> name
2018-12-06 21:53:15 +00:00
| `Hup -> []
2018-10-23 22:03:36 +00:00
let pp_log_event ppf = function
2018-12-06 21:53:15 +00:00
| `Startup -> Fmt.string ppf "startup"
| `Login (name, ip, port) -> Fmt.pf ppf "%a login %a:%d" Name.pp name Ipaddr.V4.pp ip port
| `Logout (name, ip, port) -> Fmt.pf ppf "%a logout %a:%d" Name.pp name Ipaddr.V4.pp ip port
| `Unikernel_start (name, pid, taps, blocks) ->
Fmt.pf ppf "%a started %d (taps %a, block %a)"
Name.pp name pid Fmt.(list ~sep:(unit "; ") (pair ~sep:(unit "=") string string)) taps
Fmt.(list ~sep:(unit "; ") (pair ~sep:(unit "=") string Name.pp)) blocks
2018-11-13 00:02:05 +00:00
| `Unikernel_stop (name, pid, code) ->
Fmt.pf ppf "%a stopped %d with %a" Name.pp name pid pp_process_exit code
2018-12-06 21:53:15 +00:00
| `Hup -> Fmt.string ppf "hup"
2018-10-23 22:03:36 +00:00
type t = Ptime.t * log_event
let pp ppf (ts, ev) =
Fmt.pf ppf "%a: %a" (Ptime.pp_rfc3339 ()) ts pp_log_event ev
2017-05-26 14:30:34 +00:00
end