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 <limits.h>
16 #include <stdlib.h>
17 #include <unistd.h>
18
19 #include <libxl.h>
20 #include <libxl_utils.h>
21 #include <libxlutil.h>
22
23 #include "xl.h"
24 #include "xl_utils.h"
25 #include "xl_parse.h"
26
main_cpupoolcreate(int argc,char ** argv)27 int main_cpupoolcreate(int argc, char **argv)
28 {
29 const char *filename = NULL, *config_src=NULL;
30 const char *p;
31 char *extra_config = NULL;
32 int opt;
33 static struct option opts[] = {
34 {"defconfig", 1, 0, 'f'},
35 {"dryrun", 0, 0, 'n'},
36 COMMON_LONG_OPTS
37 };
38 int ret;
39 char *config_data = 0;
40 int config_len = 0;
41 XLU_Config *config;
42 const char *buf;
43 char *name = NULL;
44 uint32_t poolid;
45 libxl_scheduler sched = 0;
46 XLU_ConfigList *cpus;
47 XLU_ConfigList *nodes;
48 int n_cpus, n_nodes, i, n;
49 libxl_bitmap freemap;
50 libxl_bitmap cpumap;
51 libxl_uuid uuid;
52 libxl_cputopology *topology;
53 int rc = EXIT_FAILURE;
54
55 SWITCH_FOREACH_OPT(opt, "nf:", opts, "cpupool-create", 0) {
56 case 'f':
57 filename = optarg;
58 break;
59 case 'n':
60 dryrun_only = 1;
61 break;
62 }
63
64 libxl_bitmap_init(&freemap);
65 libxl_bitmap_init(&cpumap);
66
67 while (optind < argc) {
68 if ((p = strchr(argv[optind], '='))) {
69 string_realloc_append(&extra_config, "\n");
70 string_realloc_append(&extra_config, argv[optind]);
71 } else if (!filename) {
72 filename = argv[optind];
73 } else {
74 help("cpupool-create");
75 goto out;
76 }
77 optind++;
78 }
79
80 if (filename)
81 {
82 if (libxl_read_file_contents(ctx, filename, (void **)&config_data,
83 &config_len)) {
84 fprintf(stderr, "Failed to read config file: %s: %s\n",
85 filename, strerror(errno));
86 goto out;
87 }
88 config_src=filename;
89 }
90 else
91 config_src="command line";
92
93 if (extra_config && strlen(extra_config)) {
94 if (config_len > INT_MAX - (strlen(extra_config) + 2)) {
95 fprintf(stderr, "Failed to attach extra configuration\n");
96 goto out;
97 }
98 config_data = xrealloc(config_data,
99 config_len + strlen(extra_config) + 2);
100 if (!config_data) {
101 fprintf(stderr, "Failed to realloc config_data\n");
102 goto out;
103 }
104 config_data[config_len] = 0;
105 strcat(config_data, extra_config);
106 strcat(config_data, "\n");
107 config_len += strlen(extra_config) + 1;
108 }
109
110 config = xlu_cfg_init(stderr, config_src);
111 if (!config) {
112 fprintf(stderr, "Failed to allocate for configuration\n");
113 goto out;
114 }
115
116 ret = xlu_cfg_readdata(config, config_data, config_len);
117 if (ret) {
118 fprintf(stderr, "Failed to parse config file: %s\n", strerror(ret));
119 goto out_cfg;
120 }
121
122 if (!xlu_cfg_get_string (config, "name", &buf, 0))
123 name = strdup(buf);
124 else if (filename)
125 name = libxl_basename(filename);
126 else {
127 fprintf(stderr, "Missing cpupool name!\n");
128 goto out_cfg;
129 }
130 if (!libxl_name_to_cpupoolid(ctx, name, &poolid)) {
131 fprintf(stderr, "Pool name \"%s\" already exists\n", name);
132 goto out_cfg;
133 }
134
135 if (!xlu_cfg_get_string (config, "sched", &buf, 0)) {
136 if ((libxl_scheduler_from_string(buf, &sched)) < 0) {
137 fprintf(stderr, "Unknown scheduler\n");
138 goto out_cfg;
139 }
140 } else {
141 rc = libxl_get_scheduler(ctx);
142 if (rc < 0) {
143 fprintf(stderr, "get_scheduler sysctl failed.\n");
144 goto out_cfg;
145 }
146 sched = rc;
147 }
148
149 if (libxl_get_freecpus(ctx, &freemap)) {
150 fprintf(stderr, "libxl_get_freecpus failed\n");
151 goto out_cfg;
152 }
153 if (libxl_cpu_bitmap_alloc(ctx, &cpumap, 0)) {
154 fprintf(stderr, "Failed to allocate cpumap\n");
155 goto out_cfg;
156 }
157 if (!xlu_cfg_get_list(config, "nodes", &nodes, 0, 0)) {
158 int nr;
159 n_cpus = 0;
160 n_nodes = 0;
161 topology = libxl_get_cpu_topology(ctx, &nr);
162 if (topology == NULL) {
163 fprintf(stderr, "libxl_get_topologyinfo failed\n");
164 goto out_cfg;
165 }
166 while ((buf = xlu_cfg_get_listitem(nodes, n_nodes)) != NULL) {
167 n = atoi(buf);
168 for (i = 0; i < nr; i++) {
169 if ((topology[i].node == n) &&
170 libxl_bitmap_test(&freemap, i)) {
171 libxl_bitmap_set(&cpumap, i);
172 n_cpus++;
173 }
174 }
175 n_nodes++;
176 }
177
178 libxl_cputopology_list_free(topology, nr);
179
180 if (n_cpus == 0) {
181 fprintf(stderr, "no free cpu found\n");
182 goto out_cfg;
183 }
184 } else if (!xlu_cfg_get_list(config, "cpus", &cpus, 0, 1)) {
185 n_cpus = 0;
186 while ((buf = xlu_cfg_get_listitem(cpus, n_cpus)) != NULL) {
187 i = atoi(buf);
188 if ((i < 0) || !libxl_bitmap_test(&freemap, i)) {
189 fprintf(stderr, "cpu %d illegal or not free\n", i);
190 goto out_cfg;
191 }
192 libxl_bitmap_set(&cpumap, i);
193 n_cpus++;
194 }
195 } else if (!xlu_cfg_get_string(config, "cpus", &buf, 0)) {
196 if (parse_cpurange(buf, &cpumap))
197 goto out_cfg;
198
199 n_cpus = 0;
200 libxl_for_each_set_bit(i, cpumap) {
201 if (!libxl_bitmap_test(&freemap, i)) {
202 fprintf(stderr, "cpu %d illegal or not free\n", i);
203 goto out_cfg;
204 }
205 n_cpus++;
206 }
207 } else
208 n_cpus = 0;
209
210 libxl_uuid_generate(&uuid);
211
212 printf("Using config file \"%s\"\n", config_src);
213 printf("cpupool name: %s\n", name);
214 printf("scheduler: %s\n", libxl_scheduler_to_string(sched));
215 printf("number of cpus: %d\n", n_cpus);
216
217 if (!dryrun_only) {
218 poolid = LIBXL_CPUPOOL_POOLID_ANY;
219 if (libxl_cpupool_create(ctx, name, sched, cpumap, &uuid, &poolid)) {
220 fprintf(stderr, "error on creating cpupool\n");
221 goto out_cfg;
222 }
223 }
224 /* We made it! */
225 rc = EXIT_SUCCESS;
226
227 out_cfg:
228 xlu_cfg_destroy(config);
229 out:
230 libxl_bitmap_dispose(&freemap);
231 libxl_bitmap_dispose(&cpumap);
232 free(name);
233 free(config_data);
234 free(extra_config);
235 return rc;
236 }
237
main_cpupoollist(int argc,char ** argv)238 int main_cpupoollist(int argc, char **argv)
239 {
240 int opt;
241 static struct option opts[] = {
242 {"cpus", 0, 0, 'c'},
243 COMMON_LONG_OPTS
244 };
245 int opt_cpus = 0;
246 const char *pool = NULL;
247 libxl_cpupoolinfo *poolinfo;
248 int n_pools, p, c, n;
249 uint32_t poolid;
250 char *name;
251
252 SWITCH_FOREACH_OPT(opt, "c", opts, "cpupool-list", 0) {
253 case 'c':
254 opt_cpus = 1;
255 break;
256 }
257
258 if (optind < argc) {
259 pool = argv[optind];
260 if (libxl_name_to_cpupoolid(ctx, pool, &poolid)) {
261 fprintf(stderr, "Pool \'%s\' does not exist\n", pool);
262 return EXIT_FAILURE;
263 }
264 }
265
266 poolinfo = libxl_list_cpupool(ctx, &n_pools);
267 if (!poolinfo) {
268 fprintf(stderr, "error getting cpupool info\n");
269 return EXIT_FAILURE;
270 }
271
272 printf("%-19s", "Name");
273 if (opt_cpus)
274 printf("CPU list\n");
275 else
276 printf("CPUs Sched Active Domain count\n");
277
278 for (p = 0; p < n_pools; p++) {
279 if (!pool || (poolinfo[p].poolid == poolid)) {
280 name = poolinfo[p].pool_name;
281 printf("%-19s", name);
282 n = 0;
283 libxl_for_each_bit(c, poolinfo[p].cpumap)
284 if (libxl_bitmap_test(&poolinfo[p].cpumap, c)) {
285 if (n && opt_cpus) printf(",");
286 if (opt_cpus) printf("%d", c);
287 n++;
288 }
289 if (!opt_cpus) {
290 printf("%3d %9s y %4d", n,
291 libxl_scheduler_to_string(poolinfo[p].sched),
292 poolinfo[p].n_dom);
293 }
294 printf("\n");
295 }
296 }
297
298 libxl_cpupoolinfo_list_free(poolinfo, n_pools);
299
300 return EXIT_SUCCESS;
301 }
302
main_cpupooldestroy(int argc,char ** argv)303 int main_cpupooldestroy(int argc, char **argv)
304 {
305 int opt;
306 const char *pool;
307 uint32_t poolid;
308
309 SWITCH_FOREACH_OPT(opt, "", NULL, "cpupool-destroy", 1) {
310 /* No options */
311 }
312
313 pool = argv[optind];
314
315 if (libxl_cpupool_qualifier_to_cpupoolid(ctx, pool, &poolid, NULL) ||
316 !libxl_cpupoolid_is_valid(ctx, poolid)) {
317 fprintf(stderr, "unknown cpupool '%s'\n", pool);
318 return EXIT_FAILURE;
319 }
320
321 if (libxl_cpupool_destroy(ctx, poolid)) {
322 fprintf(stderr, "Can't destroy cpupool '%s'\n", pool);
323 return EXIT_FAILURE;
324 }
325
326 return EXIT_SUCCESS;
327 }
328
main_cpupoolrename(int argc,char ** argv)329 int main_cpupoolrename(int argc, char **argv)
330 {
331 int opt;
332 const char *pool;
333 const char *new_name;
334 uint32_t poolid;
335
336 SWITCH_FOREACH_OPT(opt, "", NULL, "cpupool-rename", 2) {
337 /* No options */
338 }
339
340 pool = argv[optind++];
341
342 if (libxl_cpupool_qualifier_to_cpupoolid(ctx, pool, &poolid, NULL) ||
343 !libxl_cpupoolid_is_valid(ctx, poolid)) {
344 fprintf(stderr, "unknown cpupool '%s'\n", pool);
345 return EXIT_FAILURE;
346 }
347
348 new_name = argv[optind];
349
350 if (libxl_cpupool_rename(ctx, new_name, poolid)) {
351 fprintf(stderr, "Can't rename cpupool '%s'\n", pool);
352 return EXIT_FAILURE;
353 }
354
355 return EXIT_SUCCESS;
356 }
357
main_cpupoolcpuadd(int argc,char ** argv)358 int main_cpupoolcpuadd(int argc, char **argv)
359 {
360 int opt;
361 const char *pool;
362 uint32_t poolid;
363 libxl_bitmap cpumap;
364 int rc = EXIT_FAILURE;
365
366 SWITCH_FOREACH_OPT(opt, "", NULL, "cpupool-cpu-add", 2) {
367 /* No options */
368 }
369
370 libxl_bitmap_init(&cpumap);
371 if (libxl_cpu_bitmap_alloc(ctx, &cpumap, 0)) {
372 fprintf(stderr, "Unable to allocate cpumap");
373 return EXIT_FAILURE;
374 }
375
376 pool = argv[optind++];
377 if (parse_cpurange(argv[optind], &cpumap))
378 goto out;
379
380 if (libxl_cpupool_qualifier_to_cpupoolid(ctx, pool, &poolid, NULL) ||
381 !libxl_cpupoolid_is_valid(ctx, poolid)) {
382 fprintf(stderr, "unknown cpupool \'%s\'\n", pool);
383 goto out;
384 }
385
386 if (libxl_cpupool_cpuadd_cpumap(ctx, poolid, &cpumap))
387 fprintf(stderr, "some cpus may not have been added to %s\n", pool);
388
389 rc = EXIT_SUCCESS;
390
391 out:
392 libxl_bitmap_dispose(&cpumap);
393 return rc;
394 }
395
main_cpupoolcpuremove(int argc,char ** argv)396 int main_cpupoolcpuremove(int argc, char **argv)
397 {
398 int opt;
399 const char *pool;
400 uint32_t poolid;
401 libxl_bitmap cpumap;
402 int rc = EXIT_FAILURE;
403
404 libxl_bitmap_init(&cpumap);
405 if (libxl_cpu_bitmap_alloc(ctx, &cpumap, 0)) {
406 fprintf(stderr, "Unable to allocate cpumap");
407 return EXIT_FAILURE;
408 }
409
410 SWITCH_FOREACH_OPT(opt, "", NULL, "cpupool-cpu-remove", 2) {
411 /* No options */
412 }
413
414 pool = argv[optind++];
415 if (parse_cpurange(argv[optind], &cpumap))
416 goto out;
417
418 if (libxl_cpupool_qualifier_to_cpupoolid(ctx, pool, &poolid, NULL) ||
419 !libxl_cpupoolid_is_valid(ctx, poolid)) {
420 fprintf(stderr, "unknown cpupool \'%s\'\n", pool);
421 goto out;
422 }
423
424 if (libxl_cpupool_cpuremove_cpumap(ctx, poolid, &cpumap)) {
425 fprintf(stderr, "Some cpus may have not or only partially been removed from '%s'.\n", pool);
426 fprintf(stderr, "If a cpu can't be added to another cpupool, add it to '%s' again and retry.\n", pool);
427 }
428
429 rc = EXIT_SUCCESS;
430
431 out:
432 libxl_bitmap_dispose(&cpumap);
433 return rc;
434 }
435
main_cpupoolmigrate(int argc,char ** argv)436 int main_cpupoolmigrate(int argc, char **argv)
437 {
438 int opt;
439 const char *pool;
440 uint32_t poolid;
441 const char *dom;
442 uint32_t domid;
443
444 SWITCH_FOREACH_OPT(opt, "", NULL, "cpupool-migrate", 2) {
445 /* No options */
446 }
447
448 dom = argv[optind++];
449 pool = argv[optind];
450
451 if (libxl_domain_qualifier_to_domid(ctx, dom, &domid) ||
452 !libxl_domid_to_name(ctx, domid)) {
453 fprintf(stderr, "unknown domain '%s'\n", dom);
454 return EXIT_FAILURE;
455 }
456
457 if (libxl_cpupool_qualifier_to_cpupoolid(ctx, pool, &poolid, NULL) ||
458 !libxl_cpupoolid_is_valid(ctx, poolid)) {
459 fprintf(stderr, "unknown cpupool '%s'\n", pool);
460 return EXIT_FAILURE;
461 }
462
463 if (libxl_cpupool_movedomain(ctx, poolid, domid))
464 return EXIT_FAILURE;
465
466 return EXIT_SUCCESS;
467 }
468
main_cpupoolnumasplit(int argc,char ** argv)469 int main_cpupoolnumasplit(int argc, char **argv)
470 {
471 int rc;
472 int opt;
473 int p;
474 int c;
475 int n;
476 uint32_t poolid;
477 libxl_scheduler sched;
478 int n_pools;
479 int node;
480 int n_cpus;
481 char *name = NULL;
482 libxl_uuid uuid;
483 libxl_bitmap cpumap;
484 libxl_cpupoolinfo *poolinfo;
485 libxl_cputopology *topology;
486 libxl_dominfo info;
487
488 SWITCH_FOREACH_OPT(opt, "", NULL, "cpupool-numa-split", 0) {
489 /* No options */
490 }
491
492 libxl_dominfo_init(&info);
493
494 rc = EXIT_FAILURE;
495
496 libxl_bitmap_init(&cpumap);
497 poolinfo = libxl_list_cpupool(ctx, &n_pools);
498 if (!poolinfo) {
499 fprintf(stderr, "error getting cpupool info\n");
500 return EXIT_FAILURE;
501 }
502 poolid = poolinfo[0].poolid;
503 sched = poolinfo[0].sched;
504 libxl_cpupoolinfo_list_free(poolinfo, n_pools);
505
506 if (n_pools > 1) {
507 fprintf(stderr, "splitting not possible, already cpupools in use\n");
508 return EXIT_FAILURE;
509 }
510
511 topology = libxl_get_cpu_topology(ctx, &n_cpus);
512 if (topology == NULL) {
513 fprintf(stderr, "libxl_get_topologyinfo failed\n");
514 return EXIT_FAILURE;
515 }
516
517 if (libxl_cpu_bitmap_alloc(ctx, &cpumap, 0)) {
518 fprintf(stderr, "Failed to allocate cpumap\n");
519 goto out;
520 }
521
522 /* Reset Pool-0 to 1st node: first add cpus, then remove cpus to avoid
523 a cpupool without cpus in between */
524
525 node = topology[0].node;
526 if (libxl_cpupool_cpuadd_node(ctx, 0, node, &n)) {
527 fprintf(stderr, "error on adding cpu to Pool 0\n");
528 goto out;
529 }
530
531 xasprintf(&name, "Pool-node%d", node);
532 if (libxl_cpupool_rename(ctx, name, 0)) {
533 fprintf(stderr, "error on renaming Pool 0\n");
534 goto out;
535 }
536
537 n = 0;
538 for (c = 0; c < n_cpus; c++) {
539 if (topology[c].node == node) {
540 topology[c].node = LIBXL_CPUTOPOLOGY_INVALID_ENTRY;
541 libxl_bitmap_set(&cpumap, n);
542 n++;
543 }
544 }
545 if (libxl_domain_info(ctx, &info, 0)) {
546 fprintf(stderr, "error on getting info for Domain-0\n");
547 goto out;
548 }
549 if (info.vcpu_online > n && libxl_set_vcpuonline(ctx, 0, &cpumap, NULL)) {
550 fprintf(stderr, "error on removing vcpus for Domain-0\n");
551 goto out;
552 }
553 for (c = 0; c < 10; c++) {
554 /* We've called libxl_dominfo_init before the loop and will
555 * call libxl_dominfo_dispose after the loop when we're done
556 * with info.
557 */
558 libxl_dominfo_dispose(&info);
559 libxl_dominfo_init(&info);
560 if (libxl_domain_info(ctx, &info, 0)) {
561 fprintf(stderr, "error on getting info for Domain-0\n");
562 goto out;
563 }
564 if (info.vcpu_online <= n) {
565 break;
566 }
567 sleep(1);
568 }
569 if (info.vcpu_online > n) {
570 fprintf(stderr, "failed to offline vcpus\n");
571 goto out;
572 }
573 libxl_bitmap_set_none(&cpumap);
574
575 for (c = 0; c < n_cpus; c++) {
576 if (topology[c].node == LIBXL_CPUTOPOLOGY_INVALID_ENTRY) {
577 continue;
578 }
579
580 node = topology[c].node;
581 if (libxl_cpupool_cpuremove_node(ctx, 0, node, &n)) {
582 fprintf(stderr, "error on removing cpu from Pool 0\n");
583 goto out;
584 }
585
586 free(name);
587 xasprintf(&name, "Pool-node%d", node);
588 libxl_uuid_generate(&uuid);
589 poolid = 0;
590 if (libxl_cpupool_create(ctx, name, sched, cpumap, &uuid, &poolid)) {
591 fprintf(stderr, "error on creating cpupool\n");
592 goto out;
593 }
594
595 if (libxl_cpupool_cpuadd_node(ctx, poolid, node, &n)) {
596 fprintf(stderr, "error on adding cpus to cpupool\n");
597 goto out;
598 }
599
600 for (p = c; p < n_cpus; p++) {
601 if (topology[p].node == node) {
602 topology[p].node = LIBXL_CPUTOPOLOGY_INVALID_ENTRY;
603 }
604 }
605 }
606
607 rc = EXIT_SUCCESS;
608
609 out:
610 libxl_cputopology_list_free(topology, n_cpus);
611 libxl_bitmap_dispose(&cpumap);
612 libxl_dominfo_dispose(&info);
613 free(name);
614
615 return rc;
616 }
617
618 /*
619 * Local variables:
620 * mode: C
621 * c-basic-offset: 4
622 * indent-tabs-mode: nil
623 * End:
624 */
625