~ubuntu-branches/ubuntu/quantal/xen-api/quantal

« back to all changes in this revision

Viewing changes to ocaml/xenops/xenops.ml

  • Committer: Package Import Robot
  • Author(s): Jon Ludlam
  • Date: 2011-07-07 21:50:18 UTC
  • Revision ID: package-import@ubuntu.com-20110707215018-3t9ekbh7qy5y2b1p
Tags: upstream-1.3
ImportĀ upstreamĀ versionĀ 1.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
(*
 
2
 * Copyright (C) 2006-2009 Citrix Systems Inc.
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or modify
 
5
 * it under the terms of the GNU Lesser General Public License as published
 
6
 * by the Free Software Foundation; version 2.1 only. with the special
 
7
 * exception on linking described in file LICENSE.
 
8
 *
 
9
 * This program is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
 * GNU Lesser General Public License for more details.
 
13
 *)
 
14
open Printf
 
15
open Pervasiveext
 
16
open Stringext
 
17
open Device_common
 
18
open Xenops_helpers
 
19
open Xenstore
 
20
 
 
21
let print_xen_dmesg ~xc =
 
22
        let s = Xenctrl.readconsolering xc in
 
23
        printf "%s\n" s
 
24
 
 
25
let print_xen_physinfo ~xc =
 
26
        let physinfo = Xenctrl.physinfo xc in
 
27
        let totalmib = Xenctrl.pages_to_mib (Int64.of_nativeint physinfo.Xenctrl.total_pages)
 
28
        and freemib = Xenctrl.pages_to_mib (Int64.of_nativeint physinfo.Xenctrl.free_pages)
 
29
        and scrubmib = Xenctrl.pages_to_mib (Int64.of_nativeint physinfo.Xenctrl.scrub_pages) in
 
30
        printf "nr_cpus = %d\n" physinfo.Xenctrl.nr_cpus;
 
31
        printf "threads_per_core = %d\n" physinfo.Xenctrl.threads_per_core;
 
32
        printf "cores_per_socket = %d\n" physinfo.Xenctrl.cores_per_socket;
 
33
        (*printf "sockets_per_node = %d\n" physinfo.Xenctrl.sockets_per_node;*)
 
34
        (*printf "nr_nodes = %d\n" physinfo.Xenctrl.nr_nodes;*)
 
35
        printf "cpu_khz = %d\n" physinfo.Xenctrl.cpu_khz;
 
36
        printf "total_pages = %s (%Ld Mb)\n" (Nativeint.to_string physinfo.Xenctrl.total_pages) totalmib;
 
37
        printf "free_pages = %s (%Ld Mb)\n" (Nativeint.to_string physinfo.Xenctrl.free_pages) freemib;
 
38
        printf "scrub_pages = %s (%Ld Mb)\n" (Nativeint.to_string physinfo.Xenctrl.scrub_pages) scrubmib
 
39
 
 
40
let print_pcpus_info ~xc =
 
41
        let physinfo = Xenctrl.physinfo xc in
 
42
        let infos = Xenctrl.pcpu_info xc (physinfo.Xenctrl.nr_cpus) in
 
43
        Array.iteri (fun i info -> printf "cpu: %d  usage: %Ld\n" i info) infos
 
44
 
 
45
let debugkeys ~xc args =
 
46
        List.iter (fun arg ->
 
47
                try Xenctrl.send_debug_keys xc arg
 
48
                with exn ->
 
49
                        printf "sending key \"%s\" failed: %s" arg (Printexc.to_string exn);
 
50
        ) args
 
51
 
 
52
let is_hvm ~xc domid =
 
53
        (Xenctrl.domain_getinfo xc domid).Xenctrl.hvm_guest
 
54
 
 
55
let create_domain ~xc ~xs ~hvm =
 
56
        let uuid = Uuid.make_uuid () in
 
57
        let info = {
 
58
                Domain.ssidref = 0l;
 
59
                Domain.hvm = hvm;
 
60
                Domain.hap = hvm;
 
61
                Domain.name = "";
 
62
                Domain.xsdata = [];
 
63
                Domain.platformdata = [];
 
64
                Domain.bios_strings = [];
 
65
        } in
 
66
        let domid = Domain.make ~xc ~xs info uuid in
 
67
        printf "%u\n" domid
 
68
 
 
69
let build_domain ~xc ~xs ~kernel ?(ramdisk=None) ~cmdline ~domid ~vcpus ~static_max_kib ~target_kib =
 
70
        let (_: Domain.domarch) = Domain.build_linux xc xs static_max_kib target_kib
 
71
                                                     kernel cmdline ramdisk vcpus domid in
 
72
        printf "built domain: %u\n" domid
 
73
 
 
74
let build_hvm ~xc ~xs ~kernel ~domid ~vcpus ~static_max_kib ~target_kib =
 
75
        let (_: Domain.domarch) = Domain.build_hvm xc xs static_max_kib target_kib 1.
 
76
                                                   vcpus kernel "0" 4 domid in
 
77
        printf "built hvm domain: %u\n" domid
 
78
 
 
79
let clean_shutdown_domain ~xal ~domid ~reason ~sync =
 
80
  let xc = Xal.xc_of_ctx xal in
 
81
  let xs = Xal.xs_of_ctx xal in
 
82
  Domain.shutdown ~xs domid reason;
 
83
  (* Wait for any necessary acknowledgement. If we get a Watch.Timeout _ then
 
84
         we abort early; otherwise we continue in Xal.wait_release below. *)
 
85
  let acked = try Domain.shutdown_wait_for_ack ~xc ~xs domid reason; true with Watch.Timeout _ -> false in
 
86
        if not acked then (
 
87
                eprintf "domain %u didn't acknowledged shutdown\n" domid;
 
88
        ) else (
 
89
                printf "shutdown domain: %u\n" domid;
 
90
                if sync then
 
91
                        try
 
92
                                ignore (Xal.wait_release xal ~timeout:30. domid);
 
93
                                printf "domain shutdowned correctly\n"
 
94
                        with Xal.Timeout ->
 
95
                                eprintf "domain %u didn't shutdown\n" domid;
 
96
                                raise Xal.Timeout
 
97
        )
 
98
 
 
99
let hard_shutdown_domain ~xc ~domid ~reason = Domain.hard_shutdown ~xc domid reason
 
100
 
 
101
let sysrq_domain ~xs ~domid ~sysrq =
 
102
        Domain.sysrq ~xs domid sysrq
 
103
 
 
104
let pause_domain ~xc ~domid =
 
105
        Domain.pause ~xc domid;
 
106
        printf "paused domain: %u\n" domid
 
107
 
 
108
let unpause_domain ~xc ~domid =
 
109
        Domain.unpause ~xc domid;
 
110
        printf "unpaused domain: %u\n" domid
 
111
 
 
112
let destroy_domain ~xc ~xs ~domid =
 
113
        Domain.destroy xc xs domid
 
114
 
 
115
let suspend_domain ~xc ~xs ~domid ~file =
 
116
        let suspendfct () =
 
117
                let path = xs.Xs.getdomainpath domid in
 
118
                xs.Xs.write (Printf.sprintf "%s/control/shutdown" path) "suspend";
 
119
                Unix.sleep 1
 
120
                in
 
121
        let hvm = is_hvm ~xc domid in
 
122
        let fd = Unix.openfile file [ Unix.O_WRONLY; Unix.O_CREAT; Unix.O_EXCL ] 0o600 in
 
123
        Domain.suspend xc xs hvm domid fd [] suspendfct;
 
124
        Unix.close fd
 
125
 
 
126
let suspend_domain_and_resume ~xc ~xs ~domid ~file ~cooperative =
 
127
        suspend_domain ~xc ~xs ~domid ~file;
 
128
        Domain.resume ~xc ~xs ~cooperative ~hvm:(is_hvm ~xc domid) domid
 
129
 
 
130
let suspend_domain_and_destroy ~xc ~xs ~domid ~file =
 
131
        suspend_domain ~xc ~xs ~domid ~file;
 
132
        Domain.destroy xc xs domid
 
133
 
 
134
let restore_domain ~xc ~xs ~domid ~vcpus ~static_max_kib ~target_kib ~file =
 
135
        let fd = Unix.openfile file [ Unix.O_RDONLY ] 0o400 in
 
136
        Domain.pv_restore ~xc ~xs domid ~static_max_kib ~target_kib ~vcpus fd;
 
137
        Unix.close fd
 
138
 
 
139
let balloon_domain ~xs ~domid ~mem_mib =
 
140
        if mem_mib <= 16L then
 
141
                failwith (sprintf "cannot balloon domain below 16Mb: %Ld requested" mem_mib);
 
142
        Balloon.set_memory_target ~xs domid (Int64.mul mem_mib 1024L)
 
143
 
 
144
let domain_get_uuid ~xc ~domid =
 
145
        try
 
146
                let h = Xenctrl.domain_getinfo xc domid in
 
147
                let uuid = Uuid.to_string (Uuid.uuid_of_int_array h.Xenctrl.handle) in
 
148
                printf "%s\n" uuid
 
149
        with _ ->
 
150
                ()
 
151
 
 
152
let print_table (rows: string list list) =
 
153
        let widths = Table.compute_col_widths rows in
 
154
        let sll = List.map (List.map2 Table.right widths) rows in
 
155
        List.iter (fun line -> print_endline (String.concat " | " line)) sll
 
156
 
 
157
let list_domains ~xc ~verbose =
 
158
        let header () =
 
159
                if verbose then
 
160
                        [ "id"; "state"; "shutdown code"; "total MiB"; "max MiB";
 
161
                          "sif"; "cpu time"; "vcpus online"; "max vcpu id"; "ssidref";
 
162
                          "uuid" ]
 
163
                else
 
164
                        [ "id"; "state"; "cpu_time"; "uuid" ]
 
165
                in
 
166
        let sl_of_domaininfo (x: Xenctrl.domaininfo) : string list =
 
167
                let page_to_mib pages =
 
168
                        Nativeint.to_string (Nativeint.div pages (Nativeint.of_int 256)) in
 
169
                let int = string_of_int and int64 = Int64.to_string and int32 = Int32.to_string in
 
170
                let domid = int x.Xenctrl.domid in
 
171
                (* Can more than one flag be true at a time? *)
 
172
                let state =
 
173
                        let bool ch = function true -> ch | _ -> " " in
 
174
                        (bool "D" x.Xenctrl.dying) ^ (bool "S" x.Xenctrl.shutdown) ^
 
175
                        (bool "P" x.Xenctrl.paused) ^ (bool "B" x.Xenctrl.blocked) ^
 
176
                        (bool "R" x.Xenctrl.running) ^ (bool "H" x.Xenctrl.hvm_guest) in
 
177
                let shutdown_code     = int x.Xenctrl.shutdown_code in
 
178
                let tot_memory_mib    = page_to_mib x.Xenctrl.total_memory_pages in
 
179
                let max_memory_mib    = page_to_mib x.Xenctrl.max_memory_pages in
 
180
                let shared_info_frame = int64 x.Xenctrl.shared_info_frame in
 
181
                let cpu_time          = int64 x.Xenctrl.cpu_time in
 
182
                let nr_online_vcpus   = int x.Xenctrl.nr_online_vcpus in
 
183
                let max_vcpu_id       = int x.Xenctrl.max_vcpu_id in
 
184
                let ssidref           = int32 x.Xenctrl.ssidref in
 
185
                let handle            = Uuid.to_string (Uuid.uuid_of_int_array x.Xenctrl.handle) in
 
186
 
 
187
                if verbose then
 
188
                        [ domid; state; shutdown_code; tot_memory_mib; max_memory_mib;
 
189
                          shared_info_frame; cpu_time; nr_online_vcpus; max_vcpu_id;
 
190
                          ssidref; handle ]
 
191
                else
 
192
                        [ domid; state; cpu_time; handle ]
 
193
                in
 
194
 
 
195
        let l = Xenctrl.domain_getinfolist xc 0 in
 
196
        let header = header () in
 
197
        let infos = List.map sl_of_domaininfo l in
 
198
        print_table (header :: infos)
 
199
 
 
200
(*
 
201
   backend                  frontend
 
202
   ---------------------------------------------------------------
 
203
   domain domstate ty devid state -> domain domstate ty devid state
 
204
 
 
205
   where domstate = R | S | D | ?
 
206
   state = 1 | 2 | 3 | 4 | 5 | 6 | ?          
 
207
*)
 
208
 
 
209
type device_stat = {
 
210
        device: device;
 
211
        backend_proto: string;   (* blk or net *)
 
212
        backend_device: string;  (* physical device eg. fd:2 *)
 
213
        backend_state: string;   (* 1...6 *)
 
214
        frontend_type: string;   (* cdrom or hd *)
 
215
        frontend_device: string; (* linux device name *)
 
216
        frontend_state: string;  (* 1..6 *)
 
217
}
 
218
let device_state_to_sl ds =
 
219
        let int = string_of_int in
 
220
        [ int ds.device.backend.domid; ds.backend_proto; ds.backend_device; ds.backend_state; "->"; ds.frontend_state; ds.frontend_type; ds.frontend_device; int ds.device.frontend.domid; ]
 
221
 
 
222
let stat ~xs d =
 
223
        let frontend_state = try xs.Xs.read (sprintf "%s/state" (frontend_path_of_device ~xs d)) with Xenbus.Xb.Noent -> "??" in
 
224
        let backend_state = try xs.Xs.read (sprintf "%s/state" (backend_path_of_device ~xs d)) with Xenbus.Xb.Noent -> "??" in
 
225
        (* The params string can be very long, truncate to a more reasonable width *)
 
226
        let truncate params =
 
227
                let limit = 10 in
 
228
                let dots = "..." in
 
229
                let len = String.length params in
 
230
                if len <= limit
 
231
                then params
 
232
                else
 
233
                        let take = limit - (String.length dots) in
 
234
                        dots ^ (String.sub params (len - take) take) in
 
235
        let backend_proto = match d.backend.kind with
 
236
                | Vbd | Tap -> "blk"
 
237
                | Vif -> "net"
 
238
                | x -> string_of_kind x in
 
239
        let frontend_type = match d.frontend.kind with
 
240
                | Vbd | Tap ->
 
241
                        let be = frontend_path_of_device ~xs d in
 
242
                        (try if xs.Xs.read (sprintf "%s/device-type" be) = "cdrom" then "cdrom" else "disk" with _ -> "??")
 
243
                | x -> string_of_kind x in
 
244
        let backend_device = match d.backend.kind with
 
245
                | Vbd | Tap ->
 
246
                        let be = backend_path_of_device ~xs d in
 
247
                        (try xs.Xs.read (sprintf "%s/physical-device" be)
 
248
                        with Xenbus.Xb.Noent ->
 
249
                                (try truncate (xs.Xs.read (sprintf "%s/params" be))
 
250
                                with Xenbus.Xb.Noent -> "??"))
 
251
                | Vif -> "-"
 
252
                | _ -> string_of_int d.backend.devid in
 
253
        let frontend_device = match d.frontend.kind with
 
254
                | Vbd | Tap -> Device_number.to_linux_device (Device_number.of_xenstore_key d.frontend.devid)
 
255
                | _ -> string_of_int d.frontend.devid in
 
256
        { device = d; frontend_state = frontend_state; backend_state = backend_state; frontend_device = frontend_device; frontend_type = frontend_type; backend_proto = backend_proto; backend_device = backend_device }
 
257
 
 
258
let list_devices ~xc ~xs =
 
259
        let header = [ "be"; "proto"; "dev"; "state"; "->"; "state"; "kind"; "dev"; "fe" ] in
 
260
        let of_device (d: device) : string list =
 
261
                device_state_to_sl (stat ~xs d) in
 
262
        let l = Xenctrl.domain_getinfolist xc 0 in
 
263
        let domids = List.map (fun x -> x.Xenctrl.domid) l in
 
264
        let devices =
 
265
                Listext.List.setify (
 
266
                        List.concat (
 
267
                                List.map
 
268
                                        (fun domid ->
 
269
                                                list_backends ~xs domid @ (list_frontends ~xs domid)
 
270
                                ) domids
 
271
                        )
 
272
                ) in
 
273
        let infos = List.map of_device devices in
 
274
        print_table (header :: infos)
 
275
 
 
276
let add_vbd ~xs ~hvm ~domid ~device_number ~phystype ~params ~backend_domid ~dev_type ~mode=
 
277
        let phystype = Device.Vbd.physty_of_string phystype in
 
278
        let dev_type = Device.Vbd.devty_of_string dev_type in
 
279
        Device.Vbd.add ~xs ~hvm ~mode:(Device.Vbd.mode_of_string mode)
 
280
                       ~device_number ~phystype ~params ~backend_domid ~dev_type domid
 
281
 
 
282
let find_device ~xs (frontend: endpoint) (backend: endpoint) = 
 
283
  let all = list_devices_between ~xs backend.domid frontend.domid in
 
284
  match List.filter (fun x -> x.frontend = frontend) all with
 
285
  | [ d ] -> d
 
286
  | _ -> failwith "failed to find device"
 
287
 
 
288
let del_vbd ~xs ~domid ~backend_domid ~device_number ~phystype =
 
289
        let devid = Device_number.to_xenstore_key device_number in
 
290
        let frontend = { domid = domid; kind = Vbd; devid = devid } in
 
291
        let backend = { domid = backend_domid; kind = Vbd; devid = devid } in
 
292
        let device = find_device ~xs frontend backend in
 
293
        Device.clean_shutdown ~xs device
 
294
 
 
295
let add_vif ~xs ~domid ~netty ~devid ~mac ~backend_domid =
 
296
        ignore(Device.Vif.add ~xs ~devid ~netty ~mac ~carrier:true ~backend_domid domid)
 
297
 
 
298
let del_vif ~xs ~domid ~backend_domid ~devid =
 
299
        let frontend = { domid = domid; kind = Vif; devid = devid } in
 
300
        let backend = { domid = backend_domid; kind = Vif; devid = devid } in
 
301
        let device = find_device ~xs frontend backend in
 
302
        Device.clean_shutdown ~xs device
 
303
 
 
304
let pci_of_string x = Scanf.sscanf x "%04x:%02x:%02x.%1x" (fun a b c d -> (a, b, c, d))
 
305
 
 
306
let add_pci ~xc ~xs ~hvm ~domid ~devid ~pci =
 
307
        Printf.printf "pci: %s\n" pci;
 
308
        let pcidevs = List.map pci_of_string (String.split ',' pci) in
 
309
        Device.PCI.add ~xc ~xs ~hvm ~msitranslate:0 ~pci_power_mgmt:0 pcidevs domid devid;
 
310
        ()
 
311
 
 
312
let plug_pci ~xc ~xs ~domid ~devid ~pci = 
 
313
        let pcidev = pci_of_string pci in
 
314
        Device.PCI.plug ~xc ~xs pcidev domid
 
315
 
 
316
let unplug_pci ~xc ~xs ~domid ~devid ~pci = 
 
317
        let pcidev = pci_of_string pci in
 
318
        Device.PCI.unplug ~xc ~xs pcidev domid
 
319
 
 
320
let del_pci ~xc ~xs ~hvm ~domid ~devid ~pci =
 
321
        let pcidevs = List.map (fun d -> 
 
322
                Scanf.sscanf d "%04x:%02x:%02x.%1x" (fun a b c d -> (a, b, c, d))
 
323
        ) (String.split ',' pci) in
 
324
        Device.PCI.release ~xc ~xs ~hvm pcidevs domid devid;
 
325
        ()
 
326
 
 
327
let bind_pci ~pci =
 
328
        let pcidevs = List.map (fun d -> 
 
329
                Scanf.sscanf d "%04x:%02x:%02x.%1x" (fun a b c d -> (a, b, c, d))
 
330
        ) (String.split ',' pci) in
 
331
        Device.PCI.bind pcidevs
 
332
 
 
333
let list_pci ~xc ~xs ~domid = 
 
334
        let pcidevs = Device.PCI.list ~xc ~xs domid in
 
335
        List.iter (fun (id, (domain, bus, dev, func)) ->
 
336
                     Printf.printf "dev-%d %04x:%02x:%02x.%1x\n" id domain bus dev func
 
337
                  ) pcidevs
 
338
 
 
339
let add_dm ~xs ~domid ~static_max_kib ~vcpus ~boot =
 
340
    let dmpath = Xapi_globs.base_path ^ "/libexec/qemu-dm-wrapper" in
 
341
        let info = {
 
342
          Device.Dm.memory = static_max_kib;
 
343
          Device.Dm.boot = boot;
 
344
          Device.Dm.serial = "pty";
 
345
          Device.Dm.vcpus = vcpus;
 
346
          Device.Dm.nics = [];
 
347
          Device.Dm.disks = [];
 
348
          Device.Dm.pci_emulations = [];
 
349
          Device.Dm.pci_passthrough = false;
 
350
          Device.Dm.usb = [];
 
351
          Device.Dm.acpi = true;
 
352
          Device.Dm.disp = Device.Dm.NONE;
 
353
 
 
354
          Device.Dm.xenclient_enabled=false;
 
355
          Device.Dm.hvm=false;
 
356
          Device.Dm.sound=None;
 
357
          Device.Dm.power_mgmt=None;
 
358
          Device.Dm.oem_features=None;
 
359
          Device.Dm.inject_sci=None;
 
360
          Device.Dm.video_mib=0;
 
361
 
 
362
          Device.Dm.extras = []
 
363
        } in
 
364
        Device.Dm.start ~xs ~dmpath info domid
 
365
 
 
366
let add_ioport ~xc ~domid ~ioport_start ~ioport_end =
 
367
        Domain.add_ioport ~xc domid ioport_start ioport_end
 
368
 
 
369
let del_ioport ~xc ~domid ~ioport_start ~ioport_end =
 
370
        Domain.del_ioport ~xc domid ioport_start ioport_end
 
371
 
 
372
let add_iomem ~xc ~domid ~iomem_start ~iomem_end =
 
373
        Domain.add_iomem ~xc domid iomem_start iomem_end
 
374
 
 
375
let del_iomem ~xc ~domid ~iomem_start ~iomem_end =
 
376
        Domain.del_iomem ~xc domid iomem_start iomem_end
 
377
 
 
378
let add_irq ~xc ~domid ~irq =
 
379
        Domain.add_irq ~xc domid irq
 
380
 
 
381
let del_irq ~xc ~domid ~irq =
 
382
        Domain.del_irq ~xc domid irq
 
383
 
 
384
let sched_domain ~xc ~domid ~weight ~cap =
 
385
        if Xenctrl.sched_id xc <> 5 then
 
386
                failwith "not using credit scheduler";
 
387
        match weight, cap with
 
388
        | Some wei, Some cap ->
 
389
                Xenctrl.sched_credit_domain_set xc domid
 
390
                                           { Xenctrl.weight = wei; Xenctrl.cap = cap }
 
391
        | None, Some cap     ->
 
392
                let old = Xenctrl.sched_credit_domain_get xc domid in
 
393
                Xenctrl.sched_credit_domain_set xc domid
 
394
                               { old with Xenctrl.cap = cap }
 
395
        | Some wei, None     ->
 
396
                let old = Xenctrl.sched_credit_domain_get xc domid in
 
397
                Xenctrl.sched_credit_domain_set xc domid
 
398
                               { old with Xenctrl.weight = wei }
 
399
        | None, None         -> ()
 
400
 
 
401
let sched_domain_get ~xc ~domid =
 
402
        if Xenctrl.sched_id xc <> 5 then
 
403
                failwith "not using credit scheduler";
 
404
        let params = Xenctrl.sched_credit_domain_get xc domid in
 
405
        params.Xenctrl.weight, params.Xenctrl.cap
 
406
 
 
407
 
 
408
let affinity_set ~xc ~domid ~vcpu ~bitmap =
 
409
        let init_fct i =
 
410
                match bitmap.[i] with
 
411
                | '0' -> false
 
412
                | '1' -> true
 
413
                | c   -> failwith (sprintf "Unknown character '%c' in bitmap" c) in
 
414
        let cpumap = Array.init (String.length bitmap) init_fct in
 
415
        Domain.vcpu_affinity_set ~xc domid vcpu cpumap
 
416
 
 
417
let affinity_get ~xc ~domid ~vcpu =
 
418
        let cpumap = Domain.vcpu_affinity_get ~xc domid vcpu in
 
419
        let s = String.make (Array.length cpumap) '0' in
 
420
        Array.iteri (fun i b -> s.[i] <- if b then '1' else '0') cpumap;
 
421
        printf "%s\n" s
 
422
 
 
423
let cmd_alias cmd =
 
424
        match cmd with
 
425
        | "init"                    -> "create_domain"
 
426
        | "shutdown"                -> "shutdown_domain"
 
427
        | "sysrq"                   -> "sysrq_domain"
 
428
        | "pause"                   -> "pause_domain"
 
429
        | "unpause"                 -> "unpause_domain"
 
430
        | "list" | "li"             -> "list_domains"
 
431
        | "destroy" | "del"         -> "destroy_domain"
 
432
        | "chkpoint" | "checkpoint" -> "chkpoint_domain"
 
433
        | "restore"                 -> "restore_domain"
 
434
        | "build"                   -> "build_domain"
 
435
        | "hvmbuild"                -> "build_hvm"
 
436
        | "suspend"                 -> "save_domain"
 
437
        | "disk-add"                -> "add_vbd"
 
438
        | "pci-bind"                -> "bind_pci"
 
439
        | "getuuid_domain"          -> "dom-uuid"
 
440
        | _                         -> cmd
 
441
 
 
442
 
 
443
let usage subcmd allcommands =
 
444
    let usage_all () =
 
445
        let l = List.map (fun (cmd, _) -> "\t" ^ cmd) allcommands in
 
446
        sprintf "%s\n" (String.concat "\n" ("usage:" :: l)) in
 
447
    (* Unfortunately we can not reuse Arg.usage since it always output to stdout *)
 
448
    let usage_sub c =
 
449
        let spec = List.assoc c allcommands in
 
450
        let l = List.map (fun (opt, _, doc) -> sprintf "  %s %s" opt doc) spec in
 
451
        sprintf "%s\n" (String.concat "\n" (c :: l)) in
 
452
    match subcmd with
 
453
                | None -> Arg.Help (usage_all ())
 
454
                | Some c ->
 
455
            try Arg.Help (usage_sub c)
 
456
            with Not_found ->
 
457
                Arg.Bad (sprintf "Unknown subcommand: %s\n%s" c (usage_all ()))
 
458
 
 
459
let do_cmd_parsing subcmd init_pos =
 
460
        let domid = ref (-1)
 
461
        and backend_domid = ref (0)
 
462
        and hvm = ref false
 
463
        and vcpus = ref 0
 
464
        and vcpu = ref (-1)
 
465
        and kernel = ref "/boot/vmlinuz-2.6-xenU"
 
466
        and ramdisk = ref None
 
467
        and cmdline = ref "root=/dev/sda1 ro"
 
468
        and mem_max_kib = ref 262144
 
469
        and mem_mib = ref 0
 
470
        and pae = ref false
 
471
        and acpi = ref false
 
472
        and apic = ref false
 
473
        and nx = ref false
 
474
        and viridian = ref false
 
475
        and verbose = ref false
 
476
        and file = ref ""
 
477
        and mode = ref ""
 
478
        and phystype = ref ""
 
479
        and params = ref ""
 
480
        and device_number = ref (Device_number.make (Device_number.Xen(0, 0)))
 
481
        and dev_type = ref "disk"
 
482
        and devid = ref 0
 
483
        and reason = ref None
 
484
        and script = ref "/etc/xen/scripts/vif"
 
485
        and sync = ref false
 
486
        and netty = ref (Netman.Bridge "xenbr0")
 
487
        and weight = ref None
 
488
        and cap = ref None
 
489
        and bitmap = ref ""
 
490
        and cooperative = ref true
 
491
        and boot = ref "cd"
 
492
        and sysrq = ref '\000'
 
493
        and mac = ref ""
 
494
        and pci = ref ""
 
495
        and ioport_start = ref (-1)
 
496
        and ioport_end = ref (-1)
 
497
        and iomem_start = ref (-1L)
 
498
        and iomem_end = ref (-1L)
 
499
        and irq = ref (-1)
 
500
        and otherargs = ref []
 
501
        and slot = ref (-1)
 
502
        and timeout = ref (-1l) in
 
503
 
 
504
        let set_int64 r s =
 
505
                try r := Int64.of_string s
 
506
                with _ -> eprintf "cannot parse %s at integer\n" s
 
507
                in
 
508
        let set_netty s =
 
509
                match String.split ':' s with
 
510
                | "DriverDomain" :: []    -> netty := Netman.DriverDomain
 
511
                | "bridge" :: bname :: [] -> netty := Netman.Bridge bname
 
512
                | _                       -> eprintf "not a valid network type: %s\n" s
 
513
                in
 
514
 
 
515
        let common = [
 
516
                "-debug", Arg.Unit (fun () -> Logs.set_default Log.Debug [ "stderr" ]),
 
517
                          "enable debugging";
 
518
                "-domid", Arg.Set_int domid, "Domain ID to be built";
 
519
        ]
 
520
        and setmaxmem_args = [
 
521
                "-memory", Arg.Set_int mem_max_kib, "memory in kilobytes";
 
522
        ]
 
523
        and common_build = [
 
524
                "-vcpus", Arg.Set_int vcpus, "vcpus available";
 
525
                "-memory", Arg.Set_int mem_max_kib, "memory in kilobytes";
 
526
        ]
 
527
        and hvm_build = [
 
528
                "-kernel", Arg.Set_string kernel, "kernel to build with";
 
529
        ]
 
530
        and normal_build = [
 
531
                "-kernel", Arg.Set_string kernel, "kernel to build with";
 
532
                "-cmdline", Arg.Set_string cmdline, "Set kernel command line";
 
533
                "-ramdisk", Arg.String (fun x -> ramdisk := Some x), "Set ramdisk to use (leave blank for none)";
 
534
        ]
 
535
        and create = [
 
536
                "-hvm", Arg.Set hvm, "specify to create hvm domain";
 
537
        ]
 
538
        and common_suspend = [
 
539
                "-file", Arg.Set_string file, "Suspend/Restore file";
 
540
        ]
 
541
        and resume_args = [
 
542
                "-uncooperative", Arg.Clear cooperative, "Set that the VM is cooperative in resume";
 
543
        ]
 
544
        and vbd_args = [
 
545
                "-mode", Arg.Set_string mode, "Vbd Mode";
 
546
                "-phystype", Arg.Set_string phystype, "Vbd set physical type (file|phy)";
 
547
        "-params", Arg.Set_string params, "Vbd set params (i.e. block device)";
 
548
                "-device-number", Arg.String (fun x -> device_number := (Device_number.of_string false x)), "Vbd set device_number";
 
549
                "-devtype", Arg.Set_string dev_type, "Vbd dev type";
 
550
        ]
 
551
        and vif_args = [
 
552
                "-devid", Arg.Set_int devid, "Vif dev id";
 
553
                "-mac", Arg.Set_string mac, "Vif mac address (mandatory)";
 
554
                "-netty", Arg.String set_netty, "type of network";
 
555
        ]
 
556
        and dm_args = [
 
557
                "-boot", Arg.Set_string boot, "Set boot string of device model";
 
558
        ]
 
559
        and balloon_args = [
 
560
                "-memory", Arg.Set_int mem_mib, "memory in megabytes";
 
561
        ]
 
562
        and list_args = [
 
563
                "-v", Arg.Set verbose, "activate verbose";
 
564
        ]
 
565
        and sched_args = [
 
566
                "-weight", Arg.Int (fun i -> weight := Some i), "Set scheduler weight";
 
567
                "-cap", Arg.Int (fun i -> cap := Some i), "Set scheduler cap";
 
568
        ]
 
569
        and affinity_args = [
 
570
                "-vcpu", Arg.Set_int vcpu, "vcpu number";
 
571
        ]
 
572
        and affinity_set_args = [
 
573
                "-bitmap", Arg.Set_string bitmap, "affinity bitmap";
 
574
        ]
 
575
        and shutdown_args = [
 
576
                "-poweroff", Arg.Unit (fun () -> reason := Some Domain.PowerOff), "Poweroff guest";
 
577
                "-reboot", Arg.Unit (fun () -> reason := Some Domain.Reboot), "Reboot guest";
 
578
                "-suspend", Arg.Unit (fun () -> reason := Some Domain.Suspend), "Suspend guest";
 
579
                "-halt", Arg.Unit (fun () -> reason := Some Domain.Halt), "Halt guest";
 
580
                "-sync", Arg.Set sync, "Wait operation to complete";
 
581
        ]
 
582
        and sysrq_args = [
 
583
                "-key", Arg.String (fun s -> if String.length s = 1 then sysrq := s.[0]), "sysrq key";
 
584
        ]
 
585
        and pci_args = [
 
586
                "-pci", Arg.Set_string pci, "Pci address (format: 0000:00:00.0)";
 
587
                "-devid", Arg.Set_int devid, "Pci dev id";
 
588
        ]
 
589
        and ioport_args = [
 
590
                "-start", Arg.Set_int ioport_start, "Start port";
 
591
                "-end", Arg.Set_int ioport_end, "End port";
 
592
        ]
 
593
        and iomem_args = [
 
594
                "-start", Arg.String (set_int64 iomem_start), "Start address";
 
595
                "-end", Arg.String (set_int64 iomem_end), "End address";
 
596
        ]
 
597
        and irq_args = [
 
598
                "-irq", Arg.Set_int irq, "irq";
 
599
        ]
 
600
        and watchdog_args = [
 
601
                "-slot", Arg.Set_int slot, "slot";
 
602
                "-timeout", Arg.String (fun x -> timeout := Int32.of_string x), "timeout";
 
603
        ]
 
604
        and backend_args = [
 
605
                "-backend-domid", Arg.Set_int backend_domid, "Domain ID of backend domain (default: 0)";
 
606
        ] in
 
607
        let allcommands = [
 
608
                ("create_domain"  , create);
 
609
                ("destroy_domain" , common);
 
610
                ("build_domain"   , common @ common_build @ normal_build);
 
611
                ("build_hvm"      , common @ common_build @ hvm_build);
 
612
                ("setmaxmem"      , common @ setmaxmem_args);
 
613
                ("save_domain"    , common @ common_suspend);
 
614
                ("restore_domain" , common @ common_suspend @ common_build);
 
615
                ("chkpoint_domain", common @ common_suspend @ resume_args);
 
616
                ("shutdown_domain", common @ shutdown_args);
 
617
                ("hard_shutdown_domain", common @ shutdown_args);
 
618
                ("sysrq_domain"   , common @ sysrq_args);
 
619
                ("pause_domain"   , common);
 
620
                ("unpause_domain" , common);
 
621
                ("sched_domain"   , common @ sched_args);
 
622
                ("sched_get"      , common);
 
623
                ("affinity_set"   , common @ affinity_args @ affinity_set_args);
 
624
                ("affinity_get"   , common @ affinity_args);
 
625
                ("list_domains"   , list_args);
 
626
                ("list_devices"   , []);
 
627
                ("add_vbd"        , common @ vbd_args @ backend_args);
 
628
                ("del_vbd"        , common @ vbd_args @ backend_args);
 
629
                ("add_vif"        , common @ vif_args @ backend_args);
 
630
                ("del_vif"        , common @ vif_args @ backend_args);
 
631
                ("add_pci"        , common @ pci_args);
 
632
                ("del_pci"        , common @ pci_args);
 
633
                ("bind_pci"       , pci_args);
 
634
                ("plug_pci"       , common @ pci_args);
 
635
                ("unplug_pci"     , common @ pci_args);
 
636
                ("list_pci"       , common);
 
637
                ("add_dm"         , common @ common_build @ dm_args);
 
638
                ("add_ioport"     , common @ ioport_args);
 
639
                ("del_ioport"     , common @ ioport_args);
 
640
                ("add_iomem"      , common @ iomem_args);
 
641
                ("del_iomem"      , common @ iomem_args);
 
642
                ("add_irq"        , common @ irq_args);
 
643
                ("del_irq"        , common @ irq_args);
 
644
                ("balloon"        , common @ balloon_args);
 
645
                ("dom-uuid"       , common);
 
646
                ("squeeze"        , balloon_args);
 
647
                ("balance"        , []);
 
648
                ("watchdog"       , watchdog_args);
 
649
                ("send-s3resume"  , common);
 
650
                ("trigger-power"  , common);
 
651
                ("trigger-sleep"  , common);
 
652
                ("dmesg"          , []);
 
653
                ("debugkeys"      , []);
 
654
                ("physinfo"       , []);
 
655
                ("pcpuinfo"       , []);
 
656
                ("help"           , []);
 
657
        ] in
 
658
       let () =
 
659
               let () =
 
660
                       match usage (Some subcmd) allcommands with
 
661
                       | Arg.Help _ -> () | e -> raise e in
 
662
               let spec = List.assoc subcmd allcommands in
 
663
               Arg.current := init_pos;
 
664
               Arg.parse_argv Sys.argv spec
 
665
                       (fun x ->
 
666
                               if x.[0] = '-' then
 
667
                                       eprintf "Warning, ignoring unknown argument: %s\n" x
 
668
                               else
 
669
                                       otherargs := x :: !otherargs
 
670
                       ) subcmd in
 
671
                !domid, !backend_domid, !hvm, !vcpus, !vcpu, !kernel,
 
672
                !ramdisk, !cmdline, Int64.of_int !mem_max_kib, Int64.of_int !mem_mib,
 
673
                !pae, !apic, !acpi, !nx, !viridian, !verbose, !file,
 
674
                !mode, !phystype, !params, !device_number, !dev_type, !devid, !mac, !pci,
 
675
                !reason, !sysrq, !script, !sync, !netty, !weight, !cap, !bitmap, !cooperative,
 
676
                !boot, !ioport_start, !ioport_end, !iomem_start, !iomem_end, !irq,
 
677
                !slot, !timeout, List.rev !otherargs, allcommands
 
678
 
 
679
let _ = try
 
680
 
 
681
    let subcmd, init_pos =
 
682
        let cmd = Filename.basename Sys.argv.(0) in
 
683
        if cmd <> "xenops" then cmd, 0
 
684
        else if Array.length Sys.argv > 1 then Sys.argv.(1), 1
 
685
        else "help", 0 in
 
686
 
 
687
    let subcmd = cmd_alias subcmd in
 
688
        let domid, backend_domid, hvm, vcpus, vcpu, kernel, ramdisk, cmdline,
 
689
               max_kib, mem_mib, pae, apic, acpi, nx, viridian, verbose, file, mode,
 
690
               phystype, params, device_number, dev_type, devid, mac, pci, reason, sysrq,
 
691
               script, sync, netty, weight, cap, bitmap, cooperative,
 
692
               boot, ioport_start, ioport_end, iomem_start, iomem_end, irq,
 
693
               slot, timeout, otherargs, allcommands = do_cmd_parsing subcmd init_pos in
 
694
 
 
695
        let is_domain_hvm xc domid = (Xenctrl.domain_getinfo xc domid).Xenctrl.hvm_guest in
 
696
 
 
697
        (* Aliases *)
 
698
        let target_kib = max_kib in
 
699
        let static_max_kib = max_kib in
 
700
 
 
701
        let error s = eprintf "error: \"%s\" argument is not valid\n" s; exit 1 in
 
702
        let assert_domid () = if domid < 0 then error "domid"
 
703
        and assert_vcpus () = if vcpus <= 0 then error "vcpus"
 
704
        and assert_vcpu () = if vcpu < 0 then error "vcpu"
 
705
        and assert_file () = if file = "" then error "file"
 
706
        and assert_bitmap () = if bitmap = "" then error "bitmap"
 
707
        in
 
708
 
 
709
        match subcmd with
 
710
        | "create_domain" ->
 
711
                with_xc_and_xs (fun xc xs -> create_domain ~xc ~xs ~hvm)
 
712
        | "destroy_domain" ->
 
713
                assert_domid ();
 
714
                with_xc_and_xs (fun xc xs -> destroy_domain ~xc ~xs ~domid)
 
715
        | "build_domain"  ->
 
716
                assert_domid (); assert_vcpus ();
 
717
                with_xc_and_xs (fun xc xs ->
 
718
                        build_domain ~xc ~xs ~kernel ~ramdisk ~cmdline ~vcpus ~static_max_kib ~target_kib ~domid)
 
719
        | "build_hvm"     ->
 
720
                assert_domid (); assert_vcpus ();
 
721
                with_xc_and_xs (fun xc xs -> build_hvm ~xc ~xs ~kernel ~vcpus ~static_max_kib ~target_kib ~domid)
 
722
        | "setmaxmem"     ->
 
723
                assert_domid ();
 
724
                with_xc (fun xc -> Xenctrl.domain_setmaxmem xc domid max_kib) (* call takes pages *)
 
725
        | "save_domain"   ->
 
726
                assert_domid (); assert_file ();
 
727
                with_xc_and_xs (fun xc xs -> suspend_domain_and_destroy ~xc ~xs ~domid ~file)
 
728
        | "restore_domain" ->
 
729
                assert_domid (); assert_vcpus ();
 
730
                with_xc_and_xs (fun xc xs -> restore_domain ~xc ~xs ~domid ~vcpus ~static_max_kib ~target_kib ~file)
 
731
        | "chkpoint_domain" ->
 
732
                assert_domid (); assert_file ();
 
733
                with_xc_and_xs (fun xc xs -> suspend_domain_and_resume ~xc ~xs ~domid ~file ~cooperative)
 
734
        | "shutdown_domain" -> (
 
735
                assert_domid ();
 
736
                match reason with
 
737
                | None -> error "no shutdown reason specified"
 
738
                | Some reason ->
 
739
                        with_xal (fun xal -> clean_shutdown_domain ~xal ~domid ~reason ~sync)
 
740
                )
 
741
        | "hard_shutdown_domain" -> (
 
742
                assert_domid ();
 
743
                match reason with
 
744
                | None -> error "no shutdown reason specified"
 
745
                | Some reason ->
 
746
                        with_xc (fun xc -> hard_shutdown_domain ~xc ~domid ~reason)
 
747
                )
 
748
        | "sysrq_domain" ->
 
749
                assert_domid ();
 
750
                with_xs (fun xs -> sysrq_domain ~xs ~domid ~sysrq)
 
751
        | "pause_domain"  ->
 
752
                assert_domid ();
 
753
                with_xc (fun xc -> pause_domain ~xc ~domid)
 
754
        | "unpause_domain" ->
 
755
                assert_domid ();
 
756
                with_xc (fun xc -> unpause_domain ~xc ~domid)
 
757
        | "list_domains" ->
 
758
                with_xc (fun xc -> list_domains ~xc ~verbose)
 
759
        | "list_devices" ->
 
760
                with_xc_and_xs (fun xc xs -> list_devices ~xc ~xs)
 
761
        | "sched_domain" ->
 
762
                assert_domid ();
 
763
                with_xc (fun xc -> sched_domain ~xc ~domid ~weight ~cap)
 
764
        | "sched_get" ->
 
765
                assert_domid ();
 
766
                let w, c = with_xc (fun xc -> sched_domain_get ~xc ~domid) in
 
767
                printf "%d %d\n" w c
 
768
        | "affinity_set" ->
 
769
                assert_domid ();
 
770
                assert_vcpu ();
 
771
                assert_bitmap ();
 
772
                with_xc (fun xc -> affinity_set ~xc ~domid ~vcpu ~bitmap);
 
773
        | "affinity_get" ->
 
774
                assert_domid ();
 
775
                assert_vcpu ();
 
776
                with_xc (fun xc -> affinity_get ~xc ~domid ~vcpu);
 
777
        | "add_vbd" ->
 
778
                assert_domid ();
 
779
                with_xc_and_xs (fun xc xs ->
 
780
                        let hvm = is_domain_hvm xc domid in
 
781
                        ignore(add_vbd ~xs ~hvm ~domid ~device_number ~phystype ~params ~dev_type ~unpluggable:true ~mode ~backend_domid)
 
782
                )
 
783
        | "del_vbd" ->
 
784
                assert_domid ();
 
785
                with_xs (fun xs -> del_vbd ~xs ~domid ~backend_domid ~device_number ~phystype)
 
786
        | "add_vif" ->
 
787
                assert_domid ();
 
788
                with_xs (fun xs -> add_vif ~xs ~domid ~netty ~devid ~mac ~backend_domid)
 
789
        | "del_vif" ->
 
790
                assert_domid ();
 
791
                with_xs (fun xs -> del_vif ~xs ~domid ~backend_domid ~devid)
 
792
        | "add_pci" ->
 
793
                assert_domid ();
 
794
                with_xc_and_xs (fun xc xs -> add_pci ~xc ~xs ~hvm:(is_domain_hvm xc domid) ~domid ~devid ~pci)
 
795
        | "del_pci" ->
 
796
                assert_domid ();
 
797
                with_xc_and_xs (fun xc xs -> del_pci ~xc ~xs ~hvm:(is_domain_hvm xc domid) ~domid ~devid ~pci)
 
798
        | "plug_pci" ->
 
799
                assert_domid ();
 
800
                with_xc_and_xs (fun xc xs -> plug_pci ~xc ~xs ~domid ~devid ~pci)
 
801
        | "unplug_pci" ->
 
802
                assert_domid ();
 
803
                with_xc_and_xs (fun xc xs -> unplug_pci ~xc ~xs ~domid ~devid ~pci)
 
804
        | "bind_pci" ->
 
805
                bind_pci ~pci
 
806
        | "list_pci" ->
 
807
                assert_domid ();
 
808
                with_xc_and_xs (fun xc xs -> list_pci ~xc ~xs ~domid)
 
809
        | "add_ioport" ->
 
810
                assert_domid ();
 
811
                with_xc (fun xc -> add_ioport ~xc ~domid ~ioport_start ~ioport_end)
 
812
        | "del_ioport" ->
 
813
                assert_domid ();
 
814
                with_xc (fun xc -> del_ioport ~xc ~domid ~ioport_start ~ioport_end)
 
815
        | "add_iomem" ->
 
816
                assert_domid ();
 
817
                with_xc (fun xc -> add_iomem ~xc ~domid ~iomem_start ~iomem_end)
 
818
        | "del_iomem" ->
 
819
                assert_domid ();
 
820
                with_xc (fun xc -> del_iomem ~xc ~domid ~iomem_start ~iomem_end)
 
821
        | "add_irq" ->
 
822
                assert_domid ();
 
823
                with_xc (fun xc -> add_irq ~xc ~domid ~irq)
 
824
        | "del_irq" ->
 
825
                assert_domid ();
 
826
                with_xc (fun xc -> del_irq ~xc ~domid ~irq)
 
827
        | "add_dm" ->
 
828
                assert_domid ();
 
829
                with_xs (fun xs ->
 
830
                        add_dm ~xs ~domid ~static_max_kib ~vcpus ~boot
 
831
                )
 
832
        | "balloon" ->
 
833
                assert_domid ();
 
834
                with_xs (fun xs -> balloon_domain ~xs ~domid ~mem_mib)
 
835
        | "squeeze" ->
 
836
                let mem_kib = Int64.mul mem_mib 1024L in
 
837
                with_xc (fun xc -> with_xs (fun xs -> Squeeze_xen.free_memory ~xc ~xs mem_kib))
 
838
        | "balance" ->
 
839
                with_xc (fun xc -> with_xs (fun xs -> Squeeze_xen.balance_memory ~xc ~xs))
 
840
        | "dom-uuid" ->
 
841
                assert_domid ();
 
842
                with_xc (fun xc -> domain_get_uuid ~xc ~domid);
 
843
        | "watchdog" ->
 
844
                if slot < 0 then error "slot";
 
845
                if timeout = -1l then error "timeout";
 
846
                Printf.printf "%d\n" (with_xc (fun xc -> Xenctrl.watchdog xc slot timeout))
 
847
        | "send-s3resume" ->
 
848
                assert_domid ();
 
849
                with_xc (fun xc -> Domain.send_s3resume ~xc domid);
 
850
        | "trigger-power" ->
 
851
                assert_domid ();
 
852
                with_xc (fun xc -> Domain.trigger_power ~xc domid);
 
853
        | "trigger-sleep" ->
 
854
                assert_domid ();
 
855
                with_xc (fun xc -> Domain.trigger_sleep ~xc domid);
 
856
        | "dmesg" ->
 
857
                with_xc (fun xc -> print_xen_dmesg ~xc);
 
858
        | "debugkeys" ->
 
859
                with_xc (fun xc -> debugkeys ~xc otherargs);
 
860
        | "physinfo" ->
 
861
                with_xc (fun xc -> print_xen_physinfo ~xc);
 
862
        | "pcpuinfo" ->
 
863
                with_xc (fun xc -> print_pcpus_info ~xc);
 
864
        | "capabilities" ->
 
865
                with_xc (fun xc -> print_endline (Xenctrl.version_capabilities xc))
 
866
    | "help" ->
 
867
        raise (usage (try Some (List.hd otherargs) with _ -> None) allcommands)
 
868
    | s ->
 
869
        raise (usage (Some s) allcommands)
 
870
with
 
871
| Arg.Help msg -> printf "%s\n" msg; exit 0
 
872
| Arg.Bad msg -> eprintf "%s\n" msg; exit 1