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 "libxl_osdeps.h"
16 
17 #include "libxl_internal.h"
18 
libxl__set_vcpuaffinity(libxl_ctx * ctx,uint32_t domid,uint32_t vcpuid,const libxl_bitmap * cpumap_hard,const libxl_bitmap * cpumap_soft,unsigned flags)19 static int libxl__set_vcpuaffinity(libxl_ctx *ctx, uint32_t domid,
20                                    uint32_t vcpuid,
21                                    const libxl_bitmap *cpumap_hard,
22                                    const libxl_bitmap *cpumap_soft,
23                                    unsigned flags)
24 {
25     GC_INIT(ctx);
26     libxl_bitmap hard, soft;
27     int rc;
28 
29     libxl_bitmap_init(&hard);
30     libxl_bitmap_init(&soft);
31 
32     if (!cpumap_hard && !cpumap_soft && !flags) {
33         rc = ERROR_INVAL;
34         goto out;
35     }
36 
37     /*
38      * Xen wants writable hard and/or soft cpumaps, to put back in them
39      * the effective hard and/or soft affinity that will be used.
40      */
41     if (cpumap_hard) {
42         rc = libxl_cpu_bitmap_alloc(ctx, &hard, 0);
43         if (rc)
44             goto out;
45 
46         libxl__bitmap_copy_best_effort(gc, &hard, cpumap_hard);
47         flags |= XEN_VCPUAFFINITY_HARD;
48     }
49     if (cpumap_soft) {
50         rc = libxl_cpu_bitmap_alloc(ctx, &soft, 0);
51         if (rc)
52             goto out;
53 
54         libxl__bitmap_copy_best_effort(gc, &soft, cpumap_soft);
55         flags |= XEN_VCPUAFFINITY_SOFT;
56     }
57 
58     if (xc_vcpu_setaffinity(ctx->xch, domid, vcpuid,
59                             cpumap_hard ? hard.map : NULL,
60                             cpumap_soft ? soft.map : NULL,
61                             flags)) {
62         LOGED(ERROR, domid, "Setting vcpu affinity");
63         rc = ERROR_FAIL;
64         goto out;
65     }
66 
67     /*
68      * Let's check the results. Hard affinity will never be empty, but it
69      * is possible that Xen will use something different from what we asked
70      * for various reasons. If that's the case, report it.
71      */
72     if (cpumap_hard &&
73         !libxl_bitmap_equal(cpumap_hard, &hard, 0))
74         LOGD(DEBUG, domid, "New hard affinity for vcpu %d has unreachable cpus", vcpuid);
75     /*
76      * Soft affinity can both be different from what asked and empty. Check
77      * for (and report) both.
78      */
79     if (cpumap_soft) {
80         if (!libxl_bitmap_equal(cpumap_soft, &soft, 0))
81             LOGD(DEBUG, domid, "New soft affinity for vcpu %d has unreachable cpus",
82                  vcpuid);
83         if (libxl_bitmap_is_empty(&soft))
84             LOGD(WARN, domid, "All cpus in soft affinity of vcpu %d are unreachable."
85                  " Only hard affinity will be considered for scheduling",
86                  vcpuid);
87     }
88 
89     rc = 0;
90  out:
91     libxl_bitmap_dispose(&hard);
92     libxl_bitmap_dispose(&soft);
93     GC_FREE;
94     return rc;
95 }
96 
libxl_set_vcpuaffinity(libxl_ctx * ctx,uint32_t domid,uint32_t vcpuid,const libxl_bitmap * cpumap_hard,const libxl_bitmap * cpumap_soft)97 int libxl_set_vcpuaffinity(libxl_ctx *ctx, uint32_t domid, uint32_t vcpuid,
98                            const libxl_bitmap *cpumap_hard,
99                            const libxl_bitmap *cpumap_soft)
100 {
101     return libxl__set_vcpuaffinity(ctx, domid, vcpuid, cpumap_hard,
102                                    cpumap_soft, 0);
103 }
104 
libxl_set_vcpuaffinity_force(libxl_ctx * ctx,uint32_t domid,uint32_t vcpuid,const libxl_bitmap * cpumap_hard,const libxl_bitmap * cpumap_soft)105 int libxl_set_vcpuaffinity_force(libxl_ctx *ctx, uint32_t domid,
106                                  uint32_t vcpuid,
107                                  const libxl_bitmap *cpumap_hard,
108                                  const libxl_bitmap *cpumap_soft)
109 {
110     return libxl__set_vcpuaffinity(ctx, domid, vcpuid, cpumap_hard,
111                                    cpumap_soft, XEN_VCPUAFFINITY_FORCE);
112 }
113 
libxl_set_vcpuaffinity_all(libxl_ctx * ctx,uint32_t domid,unsigned int max_vcpus,const libxl_bitmap * cpumap_hard,const libxl_bitmap * cpumap_soft)114 int libxl_set_vcpuaffinity_all(libxl_ctx *ctx, uint32_t domid,
115                                unsigned int max_vcpus,
116                                const libxl_bitmap *cpumap_hard,
117                                const libxl_bitmap *cpumap_soft)
118 {
119     GC_INIT(ctx);
120     int i, rc = 0;
121 
122     for (i = 0; i < max_vcpus; i++) {
123         if (libxl_set_vcpuaffinity(ctx, domid, i, cpumap_hard, cpumap_soft)) {
124             LOGD(WARN, domid, "Failed to set affinity for %d", i);
125             rc = ERROR_FAIL;
126         }
127     }
128 
129     GC_FREE;
130     return rc;
131 }
132 
libxl_domain_set_nodeaffinity(libxl_ctx * ctx,uint32_t domid,libxl_bitmap * nodemap)133 int libxl_domain_set_nodeaffinity(libxl_ctx *ctx, uint32_t domid,
134                                   libxl_bitmap *nodemap)
135 {
136     GC_INIT(ctx);
137     if (xc_domain_node_setaffinity(ctx->xch, domid, nodemap->map)) {
138         LOGED(ERROR, domid, "Setting node affinity");
139         GC_FREE;
140         return ERROR_FAIL;
141     }
142     GC_FREE;
143     return 0;
144 }
145 
libxl_domain_get_nodeaffinity(libxl_ctx * ctx,uint32_t domid,libxl_bitmap * nodemap)146 int libxl_domain_get_nodeaffinity(libxl_ctx *ctx, uint32_t domid,
147                                   libxl_bitmap *nodemap)
148 {
149     GC_INIT(ctx);
150     if (xc_domain_node_getaffinity(ctx->xch, domid, nodemap->map)) {
151         LOGED(ERROR, domid, "Getting node affinity");
152         GC_FREE;
153         return ERROR_FAIL;
154     }
155     GC_FREE;
156     return 0;
157 }
158 
libxl_get_scheduler(libxl_ctx * ctx)159 int libxl_get_scheduler(libxl_ctx *ctx)
160 {
161     int r, sched;
162 
163     GC_INIT(ctx);
164     r = xc_sched_id(ctx->xch, &sched);
165     if (r != 0) {
166         LOGE(ERROR, "getting current scheduler id");
167         sched = ERROR_FAIL;
168     }
169     GC_FREE;
170     return sched;
171 }
172 
sched_arinc653_domain_set(libxl__gc * gc,uint32_t domid,const libxl_domain_sched_params * scinfo)173 static int sched_arinc653_domain_set(libxl__gc *gc, uint32_t domid,
174                                      const libxl_domain_sched_params *scinfo)
175 {
176     /* Currently, the ARINC 653 scheduler does not take any domain-specific
177          configuration, so we simply return success. */
178     return 0;
179 }
180 
sched_null_domain_set(libxl__gc * gc,uint32_t domid,const libxl_domain_sched_params * scinfo)181 static int sched_null_domain_set(libxl__gc *gc, uint32_t domid,
182                                  const libxl_domain_sched_params *scinfo)
183 {
184     /* There aren't any domain-specific parameters to be set. */
185     return 0;
186 }
187 
sched_null_domain_get(libxl__gc * gc,uint32_t domid,libxl_domain_sched_params * scinfo)188 static int sched_null_domain_get(libxl__gc *gc, uint32_t domid,
189                                  libxl_domain_sched_params *scinfo)
190 {
191     /* There aren't any domain-specific parameters to return. */
192     return 0;
193 }
194 
sched_credit_domain_get(libxl__gc * gc,uint32_t domid,libxl_domain_sched_params * scinfo)195 static int sched_credit_domain_get(libxl__gc *gc, uint32_t domid,
196                                    libxl_domain_sched_params *scinfo)
197 {
198     struct xen_domctl_sched_credit sdom;
199     int rc;
200 
201     rc = xc_sched_credit_domain_get(CTX->xch, domid, &sdom);
202     if (rc != 0) {
203         LOGED(ERROR, domid, "Getting domain sched credit");
204         return ERROR_FAIL;
205     }
206 
207     libxl_domain_sched_params_init(scinfo);
208     scinfo->sched = LIBXL_SCHEDULER_CREDIT;
209     scinfo->weight = sdom.weight;
210     scinfo->cap = sdom.cap;
211 
212     return 0;
213 }
214 
sched_credit_domain_set(libxl__gc * gc,uint32_t domid,const libxl_domain_sched_params * scinfo)215 static int sched_credit_domain_set(libxl__gc *gc, uint32_t domid,
216                                    const libxl_domain_sched_params *scinfo)
217 {
218     struct xen_domctl_sched_credit sdom;
219     xc_domaininfo_t domaininfo;
220     int rc;
221 
222     rc = xc_domain_getinfolist(CTX->xch, domid, 1, &domaininfo);
223     if (rc < 0) {
224         LOGED(ERROR, domid, "Getting domain info list");
225         return ERROR_FAIL;
226     }
227     if (rc != 1 || domaininfo.domain != domid)
228         return ERROR_INVAL;
229 
230     rc = xc_sched_credit_domain_get(CTX->xch, domid, &sdom);
231     if (rc != 0) {
232         LOGED(ERROR, domid, "Getting domain sched credit");
233         return ERROR_FAIL;
234     }
235 
236     if (scinfo->weight != LIBXL_DOMAIN_SCHED_PARAM_WEIGHT_DEFAULT) {
237         if (scinfo->weight < 1 || scinfo->weight > 65535) {
238             LOGD(ERROR, domid, "Cpu weight out of range, "
239                  "valid values are within range from 1 to 65535");
240             return ERROR_INVAL;
241         }
242         sdom.weight = scinfo->weight;
243     }
244 
245     if (scinfo->cap != LIBXL_DOMAIN_SCHED_PARAM_CAP_DEFAULT) {
246         if (scinfo->cap < 0
247             || scinfo->cap > (domaininfo.max_vcpu_id + 1) * 100) {
248             LOGD(ERROR, domid, "Cpu cap out of range, "
249                  "valid range is from 0 to %d for specified number of vcpus",
250                  ((domaininfo.max_vcpu_id + 1) * 100));
251             return ERROR_INVAL;
252         }
253         sdom.cap = scinfo->cap;
254     }
255 
256     rc = xc_sched_credit_domain_set(CTX->xch, domid, &sdom);
257     if ( rc < 0 ) {
258         LOGED(ERROR, domid, "Setting domain sched credit");
259         return ERROR_FAIL;
260     }
261 
262     return 0;
263 }
264 
sched_ratelimit_check(libxl__gc * gc,int ratelimit)265 static int sched_ratelimit_check(libxl__gc *gc, int ratelimit)
266 {
267     if (ratelimit != 0 &&
268         (ratelimit <  XEN_SYSCTL_SCHED_RATELIMIT_MIN ||
269          ratelimit > XEN_SYSCTL_SCHED_RATELIMIT_MAX)) {
270         LOG(ERROR, "Ratelimit out of range, valid range is from %d to %d",
271             XEN_SYSCTL_SCHED_RATELIMIT_MIN, XEN_SYSCTL_SCHED_RATELIMIT_MAX);
272         return ERROR_INVAL;
273     }
274 
275     return 0;
276 }
277 
libxl_sched_credit_params_get(libxl_ctx * ctx,uint32_t poolid,libxl_sched_credit_params * scinfo)278 int libxl_sched_credit_params_get(libxl_ctx *ctx, uint32_t poolid,
279                                   libxl_sched_credit_params *scinfo)
280 {
281     struct xen_sysctl_credit_schedule sparam;
282     int r, rc;
283     GC_INIT(ctx);
284 
285     r = xc_sched_credit_params_get(ctx->xch, poolid, &sparam);
286     if (r < 0) {
287         LOGE(ERROR, "getting Credit scheduler parameters");
288         rc = ERROR_FAIL;
289         goto out;
290     }
291 
292     scinfo->tslice_ms = sparam.tslice_ms;
293     scinfo->ratelimit_us = sparam.ratelimit_us;
294 
295     rc = 0;
296  out:
297     GC_FREE;
298     return rc;
299 }
300 
libxl_sched_credit_params_set(libxl_ctx * ctx,uint32_t poolid,libxl_sched_credit_params * scinfo)301 int libxl_sched_credit_params_set(libxl_ctx *ctx, uint32_t poolid,
302                                   libxl_sched_credit_params *scinfo)
303 {
304     struct xen_sysctl_credit_schedule sparam;
305     int r, rc;
306     GC_INIT(ctx);
307 
308     if (scinfo->tslice_ms <  XEN_SYSCTL_CSCHED_TSLICE_MIN
309         || scinfo->tslice_ms > XEN_SYSCTL_CSCHED_TSLICE_MAX) {
310         LOG(ERROR, "Time slice out of range, valid range is from %d to %d",
311             XEN_SYSCTL_CSCHED_TSLICE_MIN, XEN_SYSCTL_CSCHED_TSLICE_MAX);
312         rc = ERROR_INVAL;
313         goto out;
314     }
315     rc = sched_ratelimit_check(gc, scinfo->ratelimit_us);
316     if (rc) {
317         goto out;
318     }
319     if (scinfo->ratelimit_us > scinfo->tslice_ms*1000) {
320         LOG(ERROR, "Ratelimit cannot be greater than timeslice");
321         rc = ERROR_INVAL;
322         goto out;
323     }
324 
325     sparam.tslice_ms = scinfo->tslice_ms;
326     sparam.ratelimit_us = scinfo->ratelimit_us;
327 
328     r = xc_sched_credit_params_set(ctx->xch, poolid, &sparam);
329     if ( r < 0 ) {
330         LOGE(ERROR, "Setting Credit scheduler parameters");
331         rc = ERROR_FAIL;
332         goto out;
333     }
334 
335     scinfo->tslice_ms = sparam.tslice_ms;
336     scinfo->ratelimit_us = sparam.ratelimit_us;
337 
338     rc = 0;
339  out:
340     GC_FREE;
341     return rc;
342 }
343 
libxl_sched_credit2_params_get(libxl_ctx * ctx,uint32_t poolid,libxl_sched_credit2_params * scinfo)344 int libxl_sched_credit2_params_get(libxl_ctx *ctx, uint32_t poolid,
345                                    libxl_sched_credit2_params *scinfo)
346 {
347     struct xen_sysctl_credit2_schedule sparam;
348     int r, rc;
349     GC_INIT(ctx);
350 
351     r = xc_sched_credit2_params_get(ctx->xch, poolid, &sparam);
352     if (r < 0) {
353         LOGE(ERROR, "getting Credit2 scheduler parameters");
354         rc = ERROR_FAIL;
355         goto out;
356     }
357 
358     scinfo->ratelimit_us = sparam.ratelimit_us;
359 
360     rc = 0;
361  out:
362     GC_FREE;
363     return rc;
364 }
365 
libxl_sched_credit2_params_set(libxl_ctx * ctx,uint32_t poolid,libxl_sched_credit2_params * scinfo)366 int libxl_sched_credit2_params_set(libxl_ctx *ctx, uint32_t poolid,
367                                    libxl_sched_credit2_params *scinfo)
368 {
369     struct xen_sysctl_credit2_schedule sparam;
370     int r, rc;
371     GC_INIT(ctx);
372 
373     rc = sched_ratelimit_check(gc, scinfo->ratelimit_us);
374     if (rc) goto out;
375 
376     sparam.ratelimit_us = scinfo->ratelimit_us;
377 
378     r = xc_sched_credit2_params_set(ctx->xch, poolid, &sparam);
379     if (r < 0) {
380         LOGE(ERROR, "Setting Credit2 scheduler parameters");
381         rc = ERROR_FAIL;
382         goto out;
383     }
384 
385     scinfo->ratelimit_us = sparam.ratelimit_us;
386 
387     rc = 0;
388  out:
389     GC_FREE;
390     return rc;
391 }
392 
sched_credit2_domain_get(libxl__gc * gc,uint32_t domid,libxl_domain_sched_params * scinfo)393 static int sched_credit2_domain_get(libxl__gc *gc, uint32_t domid,
394                                     libxl_domain_sched_params *scinfo)
395 {
396     struct xen_domctl_sched_credit2 sdom;
397     int rc;
398 
399     rc = xc_sched_credit2_domain_get(CTX->xch, domid, &sdom);
400     if (rc != 0) {
401         LOGED(ERROR, domid, "Getting domain sched credit2");
402         return ERROR_FAIL;
403     }
404 
405     libxl_domain_sched_params_init(scinfo);
406     scinfo->sched = LIBXL_SCHEDULER_CREDIT2;
407     scinfo->weight = sdom.weight;
408     scinfo->cap = sdom.cap;
409 
410     return 0;
411 }
412 
sched_credit2_domain_set(libxl__gc * gc,uint32_t domid,const libxl_domain_sched_params * scinfo)413 static int sched_credit2_domain_set(libxl__gc *gc, uint32_t domid,
414                                     const libxl_domain_sched_params *scinfo)
415 {
416     struct xen_domctl_sched_credit2 sdom;
417     xc_domaininfo_t info;
418     int rc;
419 
420     rc = xc_domain_getinfolist(CTX->xch, domid, 1, &info);
421     if (rc < 0) {
422         LOGED(ERROR, domid, "Getting domain info");
423         return ERROR_FAIL;
424     }
425     if (rc != 1 || info.domain != domid)
426         return ERROR_INVAL;
427 
428     rc = xc_sched_credit2_domain_get(CTX->xch, domid, &sdom);
429     if (rc != 0) {
430         LOGED(ERROR, domid, "Getting domain sched credit2");
431         return ERROR_FAIL;
432     }
433 
434     if (scinfo->weight != LIBXL_DOMAIN_SCHED_PARAM_WEIGHT_DEFAULT) {
435         if (scinfo->weight < 1 || scinfo->weight > 65535) {
436             LOGD(ERROR, domid, "Cpu weight out of range, "
437                         "valid values are within range from 1 to 65535");
438             return ERROR_INVAL;
439         }
440         sdom.weight = scinfo->weight;
441     }
442 
443     if (scinfo->cap != LIBXL_DOMAIN_SCHED_PARAM_CAP_DEFAULT) {
444         if (scinfo->cap < 0
445             || scinfo->cap > (info.max_vcpu_id + 1) * 100) {
446             LOGD(ERROR, domid, "Cpu cap out of range, "
447                  "valid range is from 0 to %d for specified number of vcpus",
448                  ((info.max_vcpu_id + 1) * 100));
449             return ERROR_INVAL;
450         }
451         sdom.cap = scinfo->cap;
452     }
453 
454     rc = xc_sched_credit2_domain_set(CTX->xch, domid, &sdom);
455     if ( rc < 0 ) {
456         LOGED(ERROR, domid, "Setting domain sched credit2");
457         return ERROR_FAIL;
458     }
459 
460     return 0;
461 }
462 
sched_rtds_validate_params(libxl__gc * gc,int period,int budget)463 static int sched_rtds_validate_params(libxl__gc *gc, int period, int budget)
464 {
465     int rc;
466 
467     if (period < 1) {
468         LOG(ERROR, "Invalid VCPU period of %d (it should be >= 1)", period);
469         rc = ERROR_INVAL;
470         goto out;
471     }
472 
473     if (budget < 1) {
474         LOG(ERROR, "Invalid VCPU budget of %d (it should be >= 1)", budget);
475         rc = ERROR_INVAL;
476         goto out;
477     }
478 
479     if (budget > period) {
480         LOG(ERROR, "VCPU budget must be smaller than or equal to period, "
481                    "but %d > %d", budget, period);
482         rc = ERROR_INVAL;
483         goto out;
484     }
485     rc = 0;
486 out:
487     return rc;
488 }
489 
490 /* Get the RTDS scheduling parameters of vcpu(s) */
sched_rtds_vcpu_get(libxl__gc * gc,uint32_t domid,libxl_vcpu_sched_params * scinfo)491 static int sched_rtds_vcpu_get(libxl__gc *gc, uint32_t domid,
492                                libxl_vcpu_sched_params *scinfo)
493 {
494     uint32_t num_vcpus;
495     int i, r, rc;
496     xc_dominfo_t info;
497     struct xen_domctl_schedparam_vcpu *vcpus;
498 
499     r = xc_domain_getinfo(CTX->xch, domid, 1, &info);
500     if (r < 0) {
501         LOGED(ERROR, domid, "Getting domain info");
502         rc = ERROR_FAIL;
503         goto out;
504     }
505 
506     if (scinfo->num_vcpus <= 0) {
507         rc = ERROR_INVAL;
508         goto out;
509     } else {
510         num_vcpus = scinfo->num_vcpus;
511         GCNEW_ARRAY(vcpus, num_vcpus);
512         for (i = 0; i < num_vcpus; i++) {
513             if (scinfo->vcpus[i].vcpuid < 0 ||
514                 scinfo->vcpus[i].vcpuid > info.max_vcpu_id) {
515                 LOGD(ERROR, domid, "VCPU index is out of range, "
516                             "valid values are within range from 0 to %d",
517                             info.max_vcpu_id);
518                 rc = ERROR_INVAL;
519                 goto out;
520             }
521             vcpus[i].vcpuid = scinfo->vcpus[i].vcpuid;
522         }
523     }
524 
525     r = xc_sched_rtds_vcpu_get(CTX->xch, domid, vcpus, num_vcpus);
526     if (r != 0) {
527         LOGED(ERROR, domid, "Getting vcpu sched rtds");
528         rc = ERROR_FAIL;
529         goto out;
530     }
531     scinfo->sched = LIBXL_SCHEDULER_RTDS;
532     for (i = 0; i < num_vcpus; i++) {
533         scinfo->vcpus[i].period = vcpus[i].u.rtds.period;
534         scinfo->vcpus[i].budget = vcpus[i].u.rtds.budget;
535         scinfo->vcpus[i].extratime =
536                 !!(vcpus[i].u.rtds.flags & XEN_DOMCTL_SCHEDRT_extra);
537         scinfo->vcpus[i].vcpuid = vcpus[i].vcpuid;
538     }
539     rc = 0;
540 out:
541     return rc;
542 }
543 
544 /* Get the RTDS scheduling parameters of all vcpus of a domain */
sched_rtds_vcpu_get_all(libxl__gc * gc,uint32_t domid,libxl_vcpu_sched_params * scinfo)545 static int sched_rtds_vcpu_get_all(libxl__gc *gc, uint32_t domid,
546                                    libxl_vcpu_sched_params *scinfo)
547 {
548     uint32_t num_vcpus;
549     int i, r, rc;
550     xc_dominfo_t info;
551     struct xen_domctl_schedparam_vcpu *vcpus;
552 
553     r = xc_domain_getinfo(CTX->xch, domid, 1, &info);
554     if (r < 0) {
555         LOGED(ERROR, domid, "Getting domain info");
556         rc = ERROR_FAIL;
557         goto out;
558     }
559 
560     if (scinfo->num_vcpus > 0) {
561         rc = ERROR_INVAL;
562         goto out;
563     } else {
564         num_vcpus = info.max_vcpu_id + 1;
565         GCNEW_ARRAY(vcpus, num_vcpus);
566         for (i = 0; i < num_vcpus; i++)
567             vcpus[i].vcpuid = i;
568     }
569 
570     r = xc_sched_rtds_vcpu_get(CTX->xch, domid, vcpus, num_vcpus);
571     if (r != 0) {
572         LOGED(ERROR, domid, "Getting vcpu sched rtds");
573         rc = ERROR_FAIL;
574         goto out;
575     }
576     scinfo->sched = LIBXL_SCHEDULER_RTDS;
577     scinfo->num_vcpus = num_vcpus;
578     scinfo->vcpus = libxl__calloc(NOGC, num_vcpus,
579                                   sizeof(libxl_sched_params));
580 
581     for (i = 0; i < num_vcpus; i++) {
582         scinfo->vcpus[i].period = vcpus[i].u.rtds.period;
583         scinfo->vcpus[i].budget = vcpus[i].u.rtds.budget;
584         scinfo->vcpus[i].extratime =
585                 !!(vcpus[i].u.rtds.flags & XEN_DOMCTL_SCHEDRT_extra);
586         scinfo->vcpus[i].vcpuid = vcpus[i].vcpuid;
587     }
588     rc = 0;
589 out:
590     return rc;
591 }
592 
593 /* Set the RTDS scheduling parameters of vcpu(s) */
sched_rtds_vcpu_set(libxl__gc * gc,uint32_t domid,const libxl_vcpu_sched_params * scinfo)594 static int sched_rtds_vcpu_set(libxl__gc *gc, uint32_t domid,
595                                const libxl_vcpu_sched_params *scinfo)
596 {
597     int r, rc;
598     int i;
599     uint16_t max_vcpuid;
600     xc_dominfo_t info;
601     struct xen_domctl_schedparam_vcpu *vcpus;
602 
603     r = xc_domain_getinfo(CTX->xch, domid, 1, &info);
604     if (r < 0) {
605         LOGED(ERROR, domid, "Getting domain info");
606         rc = ERROR_FAIL;
607         goto out;
608     }
609     max_vcpuid = info.max_vcpu_id;
610 
611     if (scinfo->num_vcpus <= 0) {
612         rc = ERROR_INVAL;
613         goto out;
614     }
615     for (i = 0; i < scinfo->num_vcpus; i++) {
616         if (scinfo->vcpus[i].vcpuid < 0 ||
617             scinfo->vcpus[i].vcpuid > max_vcpuid) {
618             LOGD(ERROR, domid, "Invalid VCPU %d: valid range is [0, %d]",
619                         scinfo->vcpus[i].vcpuid, max_vcpuid);
620             rc = ERROR_INVAL;
621             goto out;
622         }
623         rc = sched_rtds_validate_params(gc, scinfo->vcpus[i].period,
624                                         scinfo->vcpus[i].budget);
625         if (rc) {
626             rc = ERROR_INVAL;
627             goto out;
628         }
629     }
630     GCNEW_ARRAY(vcpus, scinfo->num_vcpus);
631     for (i = 0; i < scinfo->num_vcpus; i++) {
632         vcpus[i].vcpuid = scinfo->vcpus[i].vcpuid;
633         vcpus[i].u.rtds.period = scinfo->vcpus[i].period;
634         vcpus[i].u.rtds.budget = scinfo->vcpus[i].budget;
635         if (scinfo->vcpus[i].extratime)
636             vcpus[i].u.rtds.flags |= XEN_DOMCTL_SCHEDRT_extra;
637         else
638             vcpus[i].u.rtds.flags &= ~XEN_DOMCTL_SCHEDRT_extra;
639     }
640 
641     r = xc_sched_rtds_vcpu_set(CTX->xch, domid,
642                                vcpus, scinfo->num_vcpus);
643     if (r != 0) {
644         LOGED(ERROR, domid, "Setting vcpu sched rtds");
645         rc = ERROR_FAIL;
646         goto out;
647     }
648     rc = 0;
649 out:
650     return rc;
651 }
652 
653 /* Set the RTDS scheduling parameters of all vcpus of a domain */
sched_rtds_vcpu_set_all(libxl__gc * gc,uint32_t domid,const libxl_vcpu_sched_params * scinfo)654 static int sched_rtds_vcpu_set_all(libxl__gc *gc, uint32_t domid,
655                                    const libxl_vcpu_sched_params *scinfo)
656 {
657     int r, rc;
658     int i;
659     uint16_t max_vcpuid;
660     xc_dominfo_t info;
661     struct xen_domctl_schedparam_vcpu *vcpus;
662     uint32_t num_vcpus;
663 
664     r = xc_domain_getinfo(CTX->xch, domid, 1, &info);
665     if (r < 0) {
666         LOGED(ERROR, domid, "Getting domain info");
667         rc = ERROR_FAIL;
668         goto out;
669     }
670     max_vcpuid = info.max_vcpu_id;
671 
672     if (scinfo->num_vcpus != 1) {
673         rc = ERROR_INVAL;
674         goto out;
675     }
676     if (sched_rtds_validate_params(gc, scinfo->vcpus[0].period,
677                                    scinfo->vcpus[0].budget)) {
678         rc = ERROR_INVAL;
679         goto out;
680     }
681     num_vcpus = max_vcpuid + 1;
682     GCNEW_ARRAY(vcpus, num_vcpus);
683     for (i = 0; i < num_vcpus; i++) {
684         vcpus[i].vcpuid = i;
685         vcpus[i].u.rtds.period = scinfo->vcpus[0].period;
686         vcpus[i].u.rtds.budget = scinfo->vcpus[0].budget;
687         if (scinfo->vcpus[0].extratime)
688             vcpus[i].u.rtds.flags |= XEN_DOMCTL_SCHEDRT_extra;
689         else
690             vcpus[i].u.rtds.flags &= ~XEN_DOMCTL_SCHEDRT_extra;
691     }
692 
693     r = xc_sched_rtds_vcpu_set(CTX->xch, domid,
694                                vcpus, num_vcpus);
695     if (r != 0) {
696         LOGED(ERROR, domid, "Setting vcpu sched rtds");
697         rc = ERROR_FAIL;
698         goto out;
699     }
700     rc = 0;
701 out:
702     return rc;
703 }
704 
sched_rtds_domain_get(libxl__gc * gc,uint32_t domid,libxl_domain_sched_params * scinfo)705 static int sched_rtds_domain_get(libxl__gc *gc, uint32_t domid,
706                                libxl_domain_sched_params *scinfo)
707 {
708     struct xen_domctl_sched_rtds sdom;
709     int rc;
710 
711     rc = xc_sched_rtds_domain_get(CTX->xch, domid, &sdom);
712     if (rc != 0) {
713         LOGED(ERROR, domid, "Getting domain sched rtds");
714         return ERROR_FAIL;
715     }
716 
717     libxl_domain_sched_params_init(scinfo);
718 
719     scinfo->sched = LIBXL_SCHEDULER_RTDS;
720     scinfo->period = sdom.period;
721     scinfo->budget = sdom.budget;
722 
723     return 0;
724 }
725 
sched_rtds_domain_set(libxl__gc * gc,uint32_t domid,const libxl_domain_sched_params * scinfo)726 static int sched_rtds_domain_set(libxl__gc *gc, uint32_t domid,
727                                const libxl_domain_sched_params *scinfo)
728 {
729     struct xen_domctl_sched_rtds sdom;
730     int rc;
731 
732     rc = xc_sched_rtds_domain_get(CTX->xch, domid, &sdom);
733     if (rc != 0) {
734         LOGED(ERROR, domid, "Getting domain sched rtds");
735         return ERROR_FAIL;
736     }
737     if (scinfo->period != LIBXL_DOMAIN_SCHED_PARAM_PERIOD_DEFAULT)
738         sdom.period = scinfo->period;
739     if (scinfo->budget != LIBXL_DOMAIN_SCHED_PARAM_BUDGET_DEFAULT)
740         sdom.budget = scinfo->budget;
741     /* Set extratime by default */
742     if (scinfo->extratime)
743         sdom.flags |= XEN_DOMCTL_SCHEDRT_extra;
744     else
745         sdom.flags &= ~XEN_DOMCTL_SCHEDRT_extra;
746     if (sched_rtds_validate_params(gc, sdom.period, sdom.budget))
747         return ERROR_INVAL;
748 
749     rc = xc_sched_rtds_domain_set(CTX->xch, domid, &sdom);
750     if (rc < 0) {
751         LOGED(ERROR, domid, "Setting domain sched rtds");
752         return ERROR_FAIL;
753     }
754 
755     return 0;
756 }
757 
libxl_domain_sched_params_set(libxl_ctx * ctx,uint32_t domid,const libxl_domain_sched_params * scinfo)758 int libxl_domain_sched_params_set(libxl_ctx *ctx, uint32_t domid,
759                                   const libxl_domain_sched_params *scinfo)
760 {
761     GC_INIT(ctx);
762     libxl_scheduler sched = scinfo->sched;
763     int ret;
764 
765     if (sched == LIBXL_SCHEDULER_UNKNOWN)
766         sched = libxl__domain_scheduler(gc, domid);
767 
768     switch (sched) {
769     case LIBXL_SCHEDULER_SEDF:
770         LOGD(ERROR, domid, "SEDF scheduler no longer available");
771         ret=ERROR_FEATURE_REMOVED;
772         break;
773     case LIBXL_SCHEDULER_CREDIT:
774         ret=sched_credit_domain_set(gc, domid, scinfo);
775         break;
776     case LIBXL_SCHEDULER_CREDIT2:
777         ret=sched_credit2_domain_set(gc, domid, scinfo);
778         break;
779     case LIBXL_SCHEDULER_ARINC653:
780         ret=sched_arinc653_domain_set(gc, domid, scinfo);
781         break;
782     case LIBXL_SCHEDULER_RTDS:
783         ret=sched_rtds_domain_set(gc, domid, scinfo);
784         break;
785     case LIBXL_SCHEDULER_NULL:
786         ret=sched_null_domain_set(gc, domid, scinfo);
787         break;
788     default:
789         LOGD(ERROR, domid, "Unknown scheduler");
790         ret=ERROR_INVAL;
791         break;
792     }
793 
794     GC_FREE;
795     return ret;
796 }
797 
libxl_vcpu_sched_params_set(libxl_ctx * ctx,uint32_t domid,const libxl_vcpu_sched_params * scinfo)798 int libxl_vcpu_sched_params_set(libxl_ctx *ctx, uint32_t domid,
799                                 const libxl_vcpu_sched_params *scinfo)
800 {
801     GC_INIT(ctx);
802     libxl_scheduler sched = scinfo->sched;
803     int rc;
804 
805     if (sched == LIBXL_SCHEDULER_UNKNOWN)
806         sched = libxl__domain_scheduler(gc, domid);
807 
808     switch (sched) {
809     case LIBXL_SCHEDULER_SEDF:
810         LOGD(ERROR, domid, "SEDF scheduler no longer available");
811         rc = ERROR_FEATURE_REMOVED;
812         break;
813     case LIBXL_SCHEDULER_CREDIT:
814     case LIBXL_SCHEDULER_CREDIT2:
815     case LIBXL_SCHEDULER_ARINC653:
816     case LIBXL_SCHEDULER_NULL:
817         LOGD(ERROR, domid, "per-VCPU parameter setting not supported for this scheduler");
818         rc = ERROR_INVAL;
819         break;
820     case LIBXL_SCHEDULER_RTDS:
821         rc = sched_rtds_vcpu_set(gc, domid, scinfo);
822         break;
823     default:
824         LOGD(ERROR, domid, "Unknown scheduler");
825         rc = ERROR_INVAL;
826         break;
827     }
828 
829     GC_FREE;
830     return rc;
831 }
832 
libxl_vcpu_sched_params_set_all(libxl_ctx * ctx,uint32_t domid,const libxl_vcpu_sched_params * scinfo)833 int libxl_vcpu_sched_params_set_all(libxl_ctx *ctx, uint32_t domid,
834                                     const libxl_vcpu_sched_params *scinfo)
835 {
836     GC_INIT(ctx);
837     libxl_scheduler sched = scinfo->sched;
838     int rc;
839 
840     if (sched == LIBXL_SCHEDULER_UNKNOWN)
841         sched = libxl__domain_scheduler(gc, domid);
842 
843     switch (sched) {
844     case LIBXL_SCHEDULER_SEDF:
845         LOGD(ERROR, domid, "SEDF scheduler no longer available");
846         rc = ERROR_FEATURE_REMOVED;
847         break;
848     case LIBXL_SCHEDULER_CREDIT:
849     case LIBXL_SCHEDULER_CREDIT2:
850     case LIBXL_SCHEDULER_ARINC653:
851     case LIBXL_SCHEDULER_NULL:
852         LOGD(ERROR, domid, "per-VCPU parameter setting not supported for this scheduler");
853         rc = ERROR_INVAL;
854         break;
855     case LIBXL_SCHEDULER_RTDS:
856         rc = sched_rtds_vcpu_set_all(gc, domid, scinfo);
857         break;
858     default:
859         LOGD(ERROR, domid, "Unknown scheduler");
860         rc = ERROR_INVAL;
861         break;
862     }
863 
864     GC_FREE;
865     return rc;
866 }
867 
libxl_domain_sched_params_get(libxl_ctx * ctx,uint32_t domid,libxl_domain_sched_params * scinfo)868 int libxl_domain_sched_params_get(libxl_ctx *ctx, uint32_t domid,
869                                   libxl_domain_sched_params *scinfo)
870 {
871     GC_INIT(ctx);
872     int ret;
873 
874     libxl_domain_sched_params_init(scinfo);
875 
876     scinfo->sched = libxl__domain_scheduler(gc, domid);
877 
878     switch (scinfo->sched) {
879     case LIBXL_SCHEDULER_SEDF:
880         LOGD(ERROR, domid, "SEDF scheduler no longer available");
881         ret=ERROR_FEATURE_REMOVED;
882         break;
883     case LIBXL_SCHEDULER_CREDIT:
884         ret=sched_credit_domain_get(gc, domid, scinfo);
885         break;
886     case LIBXL_SCHEDULER_CREDIT2:
887         ret=sched_credit2_domain_get(gc, domid, scinfo);
888         break;
889     case LIBXL_SCHEDULER_RTDS:
890         ret=sched_rtds_domain_get(gc, domid, scinfo);
891         break;
892     case LIBXL_SCHEDULER_NULL:
893         ret=sched_null_domain_get(gc, domid, scinfo);
894         break;
895     default:
896         LOGD(ERROR, domid, "Unknown scheduler");
897         ret=ERROR_INVAL;
898         break;
899     }
900 
901     GC_FREE;
902     return ret;
903 }
904 
libxl_vcpu_sched_params_get(libxl_ctx * ctx,uint32_t domid,libxl_vcpu_sched_params * scinfo)905 int libxl_vcpu_sched_params_get(libxl_ctx *ctx, uint32_t domid,
906                                 libxl_vcpu_sched_params *scinfo)
907 {
908     GC_INIT(ctx);
909     int rc;
910 
911     scinfo->sched = libxl__domain_scheduler(gc, domid);
912 
913     switch (scinfo->sched) {
914     case LIBXL_SCHEDULER_SEDF:
915         LOGD(ERROR, domid, "SEDF scheduler is no longer available");
916         rc = ERROR_FEATURE_REMOVED;
917         break;
918     case LIBXL_SCHEDULER_CREDIT:
919     case LIBXL_SCHEDULER_CREDIT2:
920     case LIBXL_SCHEDULER_ARINC653:
921     case LIBXL_SCHEDULER_NULL:
922         LOGD(ERROR, domid, "per-VCPU parameter getting not supported for this scheduler");
923         rc = ERROR_INVAL;
924         break;
925     case LIBXL_SCHEDULER_RTDS:
926         rc = sched_rtds_vcpu_get(gc, domid, scinfo);
927         break;
928     default:
929         LOGD(ERROR, domid, "Unknown scheduler");
930         rc = ERROR_INVAL;
931         break;
932     }
933 
934     GC_FREE;
935     return rc;
936 }
937 
libxl_vcpu_sched_params_get_all(libxl_ctx * ctx,uint32_t domid,libxl_vcpu_sched_params * scinfo)938 int libxl_vcpu_sched_params_get_all(libxl_ctx *ctx, uint32_t domid,
939                                     libxl_vcpu_sched_params *scinfo)
940 {
941     GC_INIT(ctx);
942     int rc;
943 
944     scinfo->sched = libxl__domain_scheduler(gc, domid);
945 
946     switch (scinfo->sched) {
947     case LIBXL_SCHEDULER_SEDF:
948         LOGD(ERROR, domid, "SEDF scheduler is no longer available");
949         rc = ERROR_FEATURE_REMOVED;
950         break;
951     case LIBXL_SCHEDULER_CREDIT:
952     case LIBXL_SCHEDULER_CREDIT2:
953     case LIBXL_SCHEDULER_ARINC653:
954     case LIBXL_SCHEDULER_NULL:
955         LOGD(ERROR, domid, "per-VCPU parameter getting not supported for this scheduler");
956         rc = ERROR_INVAL;
957         break;
958     case LIBXL_SCHEDULER_RTDS:
959         rc = sched_rtds_vcpu_get_all(gc, domid, scinfo);
960         break;
961     default:
962         LOGD(ERROR, domid, "Unknown scheduler");
963         rc = ERROR_INVAL;
964         break;
965     }
966 
967     GC_FREE;
968     return rc;
969 }
970 
971 /*
972  * Local variables:
973  * mode: C
974  * c-basic-offset: 4
975  * indent-tabs-mode: nil
976  * End:
977  */
978