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