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