1 /*
2 * Copyright 2009-2017 Citrix Ltd and other contributors
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
15 #include <stdlib.h>
16 #include <limits.h>
17
18 #include <libxl.h>
19 #include <libxl_utils.h>
20 #include <libxlutil.h>
21
22 #include "xl.h"
23 #include "xl_utils.h"
24 #include "xl_parse.h"
25
print_vcpuinfo(uint32_t tdomid,const libxl_vcpuinfo * vcpuinfo,uint32_t nr_cpus)26 static void print_vcpuinfo(uint32_t tdomid,
27 const libxl_vcpuinfo *vcpuinfo,
28 uint32_t nr_cpus)
29 {
30 char *domname;
31
32 /* NAME ID VCPU */
33 domname = libxl_domid_to_name(ctx, tdomid);
34 printf("%-32s %5u %5u",
35 domname, tdomid, vcpuinfo->vcpuid);
36 free(domname);
37 if (!vcpuinfo->online) {
38 /* CPU STA */
39 printf("%5c %3c%cp ", '-', '-', '-');
40 } else {
41 /* CPU STA */
42 printf("%5u %3c%c- ", vcpuinfo->cpu,
43 vcpuinfo->running ? 'r' : '-',
44 vcpuinfo->blocked ? 'b' : '-');
45 }
46 /* TIM */
47 printf("%9.1f ", ((float)vcpuinfo->vcpu_time / 1e9));
48 /* CPU HARD AND SOFT AFFINITY */
49 print_bitmap(vcpuinfo->cpumap.map, nr_cpus, stdout);
50 printf(" / ");
51 print_bitmap(vcpuinfo->cpumap_soft.map, nr_cpus, stdout);
52 printf("\n");
53 }
54
print_domain_vcpuinfo(uint32_t domid,uint32_t nr_cpus)55 static void print_domain_vcpuinfo(uint32_t domid, uint32_t nr_cpus)
56 {
57 libxl_vcpuinfo *vcpuinfo;
58 int i, nb_vcpu, nrcpus;
59
60 vcpuinfo = libxl_list_vcpu(ctx, domid, &nb_vcpu, &nrcpus);
61
62 if (!vcpuinfo)
63 return;
64
65 for (i = 0; i < nb_vcpu; i++) {
66 print_vcpuinfo(domid, &vcpuinfo[i], nr_cpus);
67 }
68
69 libxl_vcpuinfo_list_free(vcpuinfo, nb_vcpu);
70 }
71
apply_global_affinity_masks(libxl_domain_type type,libxl_bitmap * vcpu_affinity_array,unsigned int size)72 void apply_global_affinity_masks(libxl_domain_type type,
73 libxl_bitmap *vcpu_affinity_array,
74 unsigned int size)
75 {
76 libxl_bitmap *mask = &global_vm_affinity_mask;
77 libxl_bitmap *type_mask;
78 unsigned int i;
79
80 switch (type) {
81 case LIBXL_DOMAIN_TYPE_HVM:
82 case LIBXL_DOMAIN_TYPE_PVH:
83 type_mask = &global_hvm_affinity_mask;
84 break;
85 case LIBXL_DOMAIN_TYPE_PV:
86 type_mask = &global_pv_affinity_mask;
87 break;
88 default:
89 fprintf(stderr, "Unknown guest type\n");
90 exit(EXIT_FAILURE);
91 }
92
93 for (i = 0; i < size; i++) {
94 int rc;
95 libxl_bitmap *t = &vcpu_affinity_array[i];
96 libxl_bitmap b1, b2;
97
98 libxl_bitmap_init(&b1);
99 libxl_bitmap_init(&b2);
100
101 rc = libxl_bitmap_and(ctx, &b1, t, mask);
102 if (rc) {
103 fprintf(stderr, "libxl_bitmap_and errored\n");
104 exit(EXIT_FAILURE);
105 }
106 rc = libxl_bitmap_and(ctx, &b2, &b1, type_mask);
107 if (rc) {
108 fprintf(stderr, "libxl_bitmap_and errored\n");
109 exit(EXIT_FAILURE);
110 }
111
112 if (libxl_bitmap_is_empty(&b2)) {
113 fprintf(stderr, "vcpu hard affinity map is empty\n");
114 exit(EXIT_FAILURE);
115 }
116
117 /* Replace target bitmap with the result */
118 libxl_bitmap_dispose(t);
119 libxl_bitmap_init(t);
120 libxl_bitmap_copy_alloc(ctx, t, &b2);
121
122 libxl_bitmap_dispose(&b1);
123 libxl_bitmap_dispose(&b2);
124 }
125 }
126
vcpulist(int argc,char ** argv)127 static void vcpulist(int argc, char **argv)
128 {
129 libxl_dominfo *dominfo;
130 libxl_physinfo physinfo;
131 int i, nb_domain;
132
133 if (libxl_get_physinfo(ctx, &physinfo) != 0) {
134 fprintf(stderr, "libxl_physinfo failed.\n");
135 goto vcpulist_out;
136 }
137
138 printf("%-32s %5s %5s %5s %5s %9s %s\n",
139 "Name", "ID", "VCPU", "CPU", "State", "Time(s)",
140 "Affinity (Hard / Soft)");
141 if (!argc) {
142 if (!(dominfo = libxl_list_domain(ctx, &nb_domain))) {
143 fprintf(stderr, "libxl_list_domain failed.\n");
144 goto vcpulist_out;
145 }
146
147 for (i = 0; i<nb_domain; i++)
148 print_domain_vcpuinfo(dominfo[i].domid, physinfo.max_cpu_id + 1);
149
150 libxl_dominfo_list_free(dominfo, nb_domain);
151 } else {
152 for (; argc > 0; ++argv, --argc) {
153 uint32_t domid = find_domain(*argv);
154 print_domain_vcpuinfo(domid, physinfo.max_cpu_id + 1);
155 }
156 }
157 vcpulist_out:
158 libxl_physinfo_dispose(&physinfo);
159 }
160
main_vcpulist(int argc,char ** argv)161 int main_vcpulist(int argc, char **argv)
162 {
163 int opt;
164
165 SWITCH_FOREACH_OPT(opt, "", NULL, "vcpu-list", 0) {
166 /* No options */
167 }
168
169 vcpulist(argc - optind, argv + optind);
170 return EXIT_SUCCESS;
171 }
172
main_vcpupin(int argc,char ** argv)173 int main_vcpupin(int argc, char **argv)
174 {
175 static struct option opts[] = {
176 {"force", 0, 0, 'f'},
177 {"ignore-global-affinity-masks", 0, 0, 'i'},
178 COMMON_LONG_OPTS
179 };
180 libxl_vcpuinfo *vcpuinfo;
181 libxl_bitmap cpumap_hard, cpumap_soft;;
182 libxl_bitmap *soft = &cpumap_soft, *hard = &cpumap_hard;
183 uint32_t domid;
184 /*
185 * int would be enough for vcpuid, but we don't want to
186 * mess aroung range checking the return value of strtol().
187 */
188 long vcpuid;
189 const char *vcpu, *hard_str, *soft_str;
190 char *endptr;
191 int opt, nb_cpu, nb_vcpu, rc = EXIT_FAILURE;
192 bool force = false, ignore_masks = false;
193
194 libxl_bitmap_init(&cpumap_hard);
195 libxl_bitmap_init(&cpumap_soft);
196
197 SWITCH_FOREACH_OPT(opt, "fi", opts, "vcpu-pin", 3) {
198 case 'f':
199 force = true;
200 break;
201 case 'i':
202 ignore_masks = true;
203 break;
204 default:
205 break;
206 }
207
208 domid = find_domain(argv[optind]);
209 vcpu = argv[optind+1];
210 hard_str = argv[optind+2];
211 soft_str = (argc > optind+3) ? argv[optind+3] : NULL;
212
213 /* Figure out with which vCPU we are dealing with */
214 vcpuid = strtol(vcpu, &endptr, 10);
215 if (vcpu == endptr || vcpuid < 0) {
216 if (strcmp(vcpu, "all")) {
217 fprintf(stderr, "Error: Invalid argument %s as VCPU.\n", vcpu);
218 goto out;
219 }
220 if (force) {
221 fprintf(stderr, "Error: --force and 'all' as VCPU not allowed.\n");
222 goto out;
223 }
224 vcpuid = -1;
225 }
226
227 if (libxl_cpu_bitmap_alloc(ctx, &cpumap_hard, 0) ||
228 libxl_cpu_bitmap_alloc(ctx, &cpumap_soft, 0))
229 goto out;
230
231 /*
232 * Syntax is: xl vcpu-pin <domid> <vcpu> <hard> <soft>
233 * We want to handle all the following cases ('-' means
234 * "leave it alone"):
235 * xl vcpu-pin 0 3 3,4
236 * xl vcpu-pin 0 3 3,4 -
237 * xl vcpu-pin 0 3 - 6-9
238 * xl vcpu-pin 0 3 3,4 6-9
239 */
240
241 /*
242 * Hard affinity is always present. However, if it's "-", all we need
243 * is passing a NULL pointer to the libxl_set_vcpuaffinity() call below.
244 */
245 if (!strcmp(hard_str, "-"))
246 hard = NULL;
247 else if (parse_cpurange(hard_str, hard))
248 goto out;
249 /*
250 * Soft affinity is handled similarly. Only difference: we also want
251 * to pass NULL to libxl_set_vcpuaffinity() if it is not specified.
252 */
253 if (argc <= optind+3 || !strcmp(soft_str, "-"))
254 soft = NULL;
255 else if (parse_cpurange(soft_str, soft))
256 goto out;
257
258 if (dryrun_only) {
259 nb_cpu = libxl_get_max_cpus(ctx);
260 if (nb_cpu < 0) {
261 fprintf(stderr, "libxl_get_max_cpus failed.\n");
262 goto out;
263 }
264
265 fprintf(stdout, "cpumap: ");
266 if (hard)
267 print_bitmap(hard->map, nb_cpu, stdout);
268 else
269 fprintf(stdout, "-");
270 if (soft) {
271 fprintf(stdout, " ");
272 print_bitmap(soft->map, nb_cpu, stdout);
273 }
274 fprintf(stdout, "\n");
275
276 if (ferror(stdout) || fflush(stdout)) {
277 perror("stdout");
278 exit(EXIT_FAILURE);
279 }
280
281 rc = EXIT_SUCCESS;
282 goto out;
283 }
284
285 /* Only hard affinity matters here */
286 if (!ignore_masks && hard) {
287 libxl_dominfo dominfo;
288
289 if (libxl_domain_info(ctx, &dominfo, domid)) {
290 fprintf(stderr, "Could not get domain info\n");
291 goto out;
292 }
293
294 /* HVM and PVH domains use the same global affinity mask */
295 apply_global_affinity_masks(dominfo.domain_type, hard, 1);
296 }
297
298 if (force) {
299 if (libxl_set_vcpuaffinity_force(ctx, domid, vcpuid, hard, soft)) {
300 fprintf(stderr, "Could not set affinity for vcpu `%ld'.\n",
301 vcpuid);
302 goto out;
303 }
304 }
305 else if (vcpuid != -1) {
306 if (libxl_set_vcpuaffinity(ctx, domid, vcpuid, hard, soft)) {
307 fprintf(stderr, "Could not set affinity for vcpu `%ld'.\n",
308 vcpuid);
309 goto out;
310 }
311 } else {
312 if (!(vcpuinfo = libxl_list_vcpu(ctx, domid, &nb_vcpu, &nb_cpu))) {
313 fprintf(stderr, "libxl_list_vcpu failed.\n");
314 goto out;
315 }
316 if (libxl_set_vcpuaffinity_all(ctx, domid, nb_vcpu, hard, soft))
317 fprintf(stderr, "Could not set affinity.\n");
318 libxl_vcpuinfo_list_free(vcpuinfo, nb_vcpu);
319 }
320
321 rc = EXIT_SUCCESS;
322 out:
323 libxl_bitmap_dispose(&cpumap_soft);
324 libxl_bitmap_dispose(&cpumap_hard);
325 return rc;
326 }
327
vcpuset(uint32_t domid,const char * nr_vcpus,int check_host)328 static int vcpuset(uint32_t domid, const char* nr_vcpus, int check_host)
329 {
330 char *endptr;
331 unsigned int i;
332 unsigned long max_vcpus;
333 libxl_bitmap cpumap;
334 int rc;
335
336 libxl_bitmap_init(&cpumap);
337 max_vcpus = strtoul(nr_vcpus, &endptr, 10);
338 if (nr_vcpus == endptr || max_vcpus > INT_MAX) {
339 fprintf(stderr, "Error: Invalid argument.\n");
340 return 1;
341 }
342
343 /*
344 * Maximum amount of vCPUS the guest is allowed to set is limited
345 * by the host's amount of pCPUs.
346 */
347 if (check_host) {
348 unsigned int online_vcpus, host_cpu = libxl_get_max_cpus(ctx);
349 libxl_dominfo dominfo;
350
351 if (libxl_domain_info(ctx, &dominfo, domid))
352 return 1;
353
354 online_vcpus = dominfo.vcpu_online;
355 libxl_dominfo_dispose(&dominfo);
356
357 if (max_vcpus > online_vcpus && max_vcpus > host_cpu) {
358 fprintf(stderr, "You are overcommmitting! You have %d physical" \
359 " CPUs and want %ld vCPUs! Aborting, use --ignore-host to" \
360 " continue\n", host_cpu, max_vcpus);
361 return 1;
362 }
363 }
364 rc = libxl_cpu_bitmap_alloc(ctx, &cpumap, max_vcpus);
365 if (rc) {
366 fprintf(stderr, "libxl_cpu_bitmap_alloc failed, rc: %d\n", rc);
367 return 1;
368 }
369 for (i = 0; i < max_vcpus; i++)
370 libxl_bitmap_set(&cpumap, i);
371
372 rc = libxl_set_vcpuonline(ctx, domid, &cpumap, NULL);
373 if (rc == ERROR_DOMAIN_NOTFOUND)
374 fprintf(stderr, "Domain %u does not exist.\n", domid);
375 else if (rc)
376 fprintf(stderr, "libxl_set_vcpuonline failed domid=%u max_vcpus=%ld," \
377 " rc: %d\n", domid, max_vcpus, rc);
378
379 libxl_bitmap_dispose(&cpumap);
380 return rc ? 1 : 0;
381 }
382
main_vcpuset(int argc,char ** argv)383 int main_vcpuset(int argc, char **argv)
384 {
385 static struct option opts[] = {
386 {"ignore-host", 0, 0, 'i'},
387 COMMON_LONG_OPTS
388 };
389 int opt, check_host = 1;
390
391 SWITCH_FOREACH_OPT(opt, "i", opts, "vcpu-set", 2) {
392 case 'i':
393 check_host = 0;
394 break;
395 default:
396 break;
397 }
398
399 if (vcpuset(find_domain(argv[optind]), argv[optind + 1], check_host))
400 return EXIT_FAILURE;
401
402 return EXIT_SUCCESS;
403 }
404
405 /*
406 * Local variables:
407 * mode: C
408 * c-basic-offset: 4
409 * indent-tabs-mode: nil
410 * End:
411 */
412