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     scinfo->vcpu_migr_delay_us = sparam.vcpu_migr_delay_us;
295 
296     rc = 0;
297  out:
298     GC_FREE;
299     return rc;
300 }
301 
libxl_sched_credit_params_set(libxl_ctx * ctx,uint32_t poolid,libxl_sched_credit_params * scinfo)302 int libxl_sched_credit_params_set(libxl_ctx *ctx, uint32_t poolid,
303                                   libxl_sched_credit_params *scinfo)
304 {
305     struct xen_sysctl_credit_schedule sparam;
306     int r, rc;
307     GC_INIT(ctx);
308 
309     if (scinfo->tslice_ms <  XEN_SYSCTL_CSCHED_TSLICE_MIN
310         || scinfo->tslice_ms > XEN_SYSCTL_CSCHED_TSLICE_MAX) {
311         LOG(ERROR, "Time slice out of range, valid range is from %d to %d",
312             XEN_SYSCTL_CSCHED_TSLICE_MIN, XEN_SYSCTL_CSCHED_TSLICE_MAX);
313         rc = ERROR_INVAL;
314         goto out;
315     }
316     rc = sched_ratelimit_check(gc, scinfo->ratelimit_us);
317     if (rc) {
318         goto out;
319     }
320     if (scinfo->ratelimit_us > scinfo->tslice_ms*1000) {
321         LOG(ERROR, "Ratelimit cannot be greater than timeslice");
322         rc = ERROR_INVAL;
323         goto out;
324     }
325     if (scinfo->vcpu_migr_delay_us > XEN_SYSCTL_CSCHED_MGR_DLY_MAX_US) {
326         LOG(ERROR, "vcpu migration delay should be >= 0 and <= %dus",
327             XEN_SYSCTL_CSCHED_MGR_DLY_MAX_US);
328         rc = ERROR_INVAL;
329         goto out;
330     }
331 
332     sparam.tslice_ms = scinfo->tslice_ms;
333     sparam.ratelimit_us = scinfo->ratelimit_us;
334     sparam.vcpu_migr_delay_us = scinfo->vcpu_migr_delay_us;
335 
336     r = xc_sched_credit_params_set(ctx->xch, poolid, &sparam);
337     if ( r < 0 ) {
338         LOGE(ERROR, "Setting Credit scheduler parameters");
339         rc = ERROR_FAIL;
340         goto out;
341     }
342 
343     scinfo->tslice_ms = sparam.tslice_ms;
344     scinfo->ratelimit_us = sparam.ratelimit_us;
345     scinfo->vcpu_migr_delay_us = sparam.vcpu_migr_delay_us;
346 
347     rc = 0;
348  out:
349     GC_FREE;
350     return rc;
351 }
352 
libxl_sched_credit2_params_get(libxl_ctx * ctx,uint32_t poolid,libxl_sched_credit2_params * scinfo)353 int libxl_sched_credit2_params_get(libxl_ctx *ctx, uint32_t poolid,
354                                    libxl_sched_credit2_params *scinfo)
355 {
356     struct xen_sysctl_credit2_schedule sparam;
357     int r, rc;
358     GC_INIT(ctx);
359 
360     r = xc_sched_credit2_params_get(ctx->xch, poolid, &sparam);
361     if (r < 0) {
362         LOGE(ERROR, "getting Credit2 scheduler parameters");
363         rc = ERROR_FAIL;
364         goto out;
365     }
366 
367     scinfo->ratelimit_us = sparam.ratelimit_us;
368 
369     rc = 0;
370  out:
371     GC_FREE;
372     return rc;
373 }
374 
libxl_sched_credit2_params_set(libxl_ctx * ctx,uint32_t poolid,libxl_sched_credit2_params * scinfo)375 int libxl_sched_credit2_params_set(libxl_ctx *ctx, uint32_t poolid,
376                                    libxl_sched_credit2_params *scinfo)
377 {
378     struct xen_sysctl_credit2_schedule sparam;
379     int r, rc;
380     GC_INIT(ctx);
381 
382     rc = sched_ratelimit_check(gc, scinfo->ratelimit_us);
383     if (rc) goto out;
384 
385     sparam.ratelimit_us = scinfo->ratelimit_us;
386 
387     r = xc_sched_credit2_params_set(ctx->xch, poolid, &sparam);
388     if (r < 0) {
389         LOGE(ERROR, "Setting Credit2 scheduler parameters");
390         rc = ERROR_FAIL;
391         goto out;
392     }
393 
394     scinfo->ratelimit_us = sparam.ratelimit_us;
395 
396     rc = 0;
397  out:
398     GC_FREE;
399     return rc;
400 }
401 
sched_credit2_domain_get(libxl__gc * gc,uint32_t domid,libxl_domain_sched_params * scinfo)402 static int sched_credit2_domain_get(libxl__gc *gc, uint32_t domid,
403                                     libxl_domain_sched_params *scinfo)
404 {
405     struct xen_domctl_sched_credit2 sdom;
406     int rc;
407 
408     rc = xc_sched_credit2_domain_get(CTX->xch, domid, &sdom);
409     if (rc != 0) {
410         LOGED(ERROR, domid, "Getting domain sched credit2");
411         return ERROR_FAIL;
412     }
413 
414     libxl_domain_sched_params_init(scinfo);
415     scinfo->sched = LIBXL_SCHEDULER_CREDIT2;
416     scinfo->weight = sdom.weight;
417     scinfo->cap = sdom.cap;
418 
419     return 0;
420 }
421 
sched_credit2_domain_set(libxl__gc * gc,uint32_t domid,const libxl_domain_sched_params * scinfo)422 static int sched_credit2_domain_set(libxl__gc *gc, uint32_t domid,
423                                     const libxl_domain_sched_params *scinfo)
424 {
425     struct xen_domctl_sched_credit2 sdom;
426     xc_domaininfo_t info;
427     int rc;
428 
429     rc = xc_domain_getinfolist(CTX->xch, domid, 1, &info);
430     if (rc < 0) {
431         LOGED(ERROR, domid, "Getting domain info");
432         return ERROR_FAIL;
433     }
434     if (rc != 1 || info.domain != domid)
435         return ERROR_INVAL;
436 
437     rc = xc_sched_credit2_domain_get(CTX->xch, domid, &sdom);
438     if (rc != 0) {
439         LOGED(ERROR, domid, "Getting domain sched credit2");
440         return ERROR_FAIL;
441     }
442 
443     if (scinfo->weight != LIBXL_DOMAIN_SCHED_PARAM_WEIGHT_DEFAULT) {
444         if (scinfo->weight < 1 || scinfo->weight > 65535) {
445             LOGD(ERROR, domid, "Cpu weight out of range, "
446                         "valid values are within range from 1 to 65535");
447             return ERROR_INVAL;
448         }
449         sdom.weight = scinfo->weight;
450     }
451 
452     if (scinfo->cap != LIBXL_DOMAIN_SCHED_PARAM_CAP_DEFAULT) {
453         if (scinfo->cap < 0
454             || scinfo->cap > (info.max_vcpu_id + 1) * 100) {
455             LOGD(ERROR, domid, "Cpu cap out of range, "
456                  "valid range is from 0 to %d for specified number of vcpus",
457                  ((info.max_vcpu_id + 1) * 100));
458             return ERROR_INVAL;
459         }
460         sdom.cap = scinfo->cap;
461     }
462 
463     rc = xc_sched_credit2_domain_set(CTX->xch, domid, &sdom);
464     if ( rc < 0 ) {
465         LOGED(ERROR, domid, "Setting domain sched credit2");
466         return ERROR_FAIL;
467     }
468 
469     return 0;
470 }
471 
sched_rtds_validate_params(libxl__gc * gc,int period,int budget)472 static int sched_rtds_validate_params(libxl__gc *gc, int period, int budget)
473 {
474     int rc;
475 
476     if (period < 1) {
477         LOG(ERROR, "Invalid VCPU period of %d (it should be >= 1)", period);
478         rc = ERROR_INVAL;
479         goto out;
480     }
481 
482     if (budget < 1) {
483         LOG(ERROR, "Invalid VCPU budget of %d (it should be >= 1)", budget);
484         rc = ERROR_INVAL;
485         goto out;
486     }
487 
488     if (budget > period) {
489         LOG(ERROR, "VCPU budget must be smaller than or equal to period, "
490                    "but %d > %d", budget, period);
491         rc = ERROR_INVAL;
492         goto out;
493     }
494     rc = 0;
495 out:
496     return rc;
497 }
498 
499 /* Get the RTDS scheduling parameters of vcpu(s) */
sched_rtds_vcpu_get(libxl__gc * gc,uint32_t domid,libxl_vcpu_sched_params * scinfo)500 static int sched_rtds_vcpu_get(libxl__gc *gc, uint32_t domid,
501                                libxl_vcpu_sched_params *scinfo)
502 {
503     uint32_t num_vcpus;
504     int i, r, rc;
505     xc_dominfo_t info;
506     struct xen_domctl_schedparam_vcpu *vcpus;
507 
508     r = xc_domain_getinfo(CTX->xch, domid, 1, &info);
509     if (r < 0) {
510         LOGED(ERROR, domid, "Getting domain info");
511         rc = ERROR_FAIL;
512         goto out;
513     }
514 
515     if (scinfo->num_vcpus <= 0) {
516         rc = ERROR_INVAL;
517         goto out;
518     } else {
519         num_vcpus = scinfo->num_vcpus;
520         GCNEW_ARRAY(vcpus, num_vcpus);
521         for (i = 0; i < num_vcpus; i++) {
522             if (scinfo->vcpus[i].vcpuid < 0 ||
523                 scinfo->vcpus[i].vcpuid > info.max_vcpu_id) {
524                 LOGD(ERROR, domid, "VCPU index is out of range, "
525                             "valid values are within range from 0 to %d",
526                             info.max_vcpu_id);
527                 rc = ERROR_INVAL;
528                 goto out;
529             }
530             vcpus[i].vcpuid = scinfo->vcpus[i].vcpuid;
531         }
532     }
533 
534     r = xc_sched_rtds_vcpu_get(CTX->xch, domid, vcpus, num_vcpus);
535     if (r != 0) {
536         LOGED(ERROR, domid, "Getting vcpu sched rtds");
537         rc = ERROR_FAIL;
538         goto out;
539     }
540     scinfo->sched = LIBXL_SCHEDULER_RTDS;
541     for (i = 0; i < num_vcpus; i++) {
542         scinfo->vcpus[i].period = vcpus[i].u.rtds.period;
543         scinfo->vcpus[i].budget = vcpus[i].u.rtds.budget;
544         scinfo->vcpus[i].extratime =
545                 !!(vcpus[i].u.rtds.flags & XEN_DOMCTL_SCHEDRT_extra);
546         scinfo->vcpus[i].vcpuid = vcpus[i].vcpuid;
547     }
548     rc = 0;
549 out:
550     return rc;
551 }
552 
553 /* 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)554 static int sched_rtds_vcpu_get_all(libxl__gc *gc, uint32_t domid,
555                                    libxl_vcpu_sched_params *scinfo)
556 {
557     uint32_t num_vcpus;
558     int i, r, rc;
559     xc_dominfo_t info;
560     struct xen_domctl_schedparam_vcpu *vcpus;
561 
562     r = xc_domain_getinfo(CTX->xch, domid, 1, &info);
563     if (r < 0) {
564         LOGED(ERROR, domid, "Getting domain info");
565         rc = ERROR_FAIL;
566         goto out;
567     }
568 
569     if (scinfo->num_vcpus > 0) {
570         rc = ERROR_INVAL;
571         goto out;
572     } else {
573         num_vcpus = info.max_vcpu_id + 1;
574         GCNEW_ARRAY(vcpus, num_vcpus);
575         for (i = 0; i < num_vcpus; i++)
576             vcpus[i].vcpuid = i;
577     }
578 
579     r = xc_sched_rtds_vcpu_get(CTX->xch, domid, vcpus, num_vcpus);
580     if (r != 0) {
581         LOGED(ERROR, domid, "Getting vcpu sched rtds");
582         rc = ERROR_FAIL;
583         goto out;
584     }
585     scinfo->sched = LIBXL_SCHEDULER_RTDS;
586     scinfo->num_vcpus = num_vcpus;
587     scinfo->vcpus = libxl__calloc(NOGC, num_vcpus,
588                                   sizeof(libxl_sched_params));
589 
590     for (i = 0; i < num_vcpus; i++) {
591         scinfo->vcpus[i].period = vcpus[i].u.rtds.period;
592         scinfo->vcpus[i].budget = vcpus[i].u.rtds.budget;
593         scinfo->vcpus[i].extratime =
594                 !!(vcpus[i].u.rtds.flags & XEN_DOMCTL_SCHEDRT_extra);
595         scinfo->vcpus[i].vcpuid = vcpus[i].vcpuid;
596     }
597     rc = 0;
598 out:
599     return rc;
600 }
601 
602 /* Set the RTDS scheduling parameters of vcpu(s) */
sched_rtds_vcpu_set(libxl__gc * gc,uint32_t domid,const libxl_vcpu_sched_params * scinfo)603 static int sched_rtds_vcpu_set(libxl__gc *gc, uint32_t domid,
604                                const libxl_vcpu_sched_params *scinfo)
605 {
606     int r, rc;
607     int i;
608     uint16_t max_vcpuid;
609     xc_dominfo_t info;
610     struct xen_domctl_schedparam_vcpu *vcpus;
611 
612     r = xc_domain_getinfo(CTX->xch, domid, 1, &info);
613     if (r < 0) {
614         LOGED(ERROR, domid, "Getting domain info");
615         rc = ERROR_FAIL;
616         goto out;
617     }
618     max_vcpuid = info.max_vcpu_id;
619 
620     if (scinfo->num_vcpus <= 0) {
621         rc = ERROR_INVAL;
622         goto out;
623     }
624     for (i = 0; i < scinfo->num_vcpus; i++) {
625         if (scinfo->vcpus[i].vcpuid < 0 ||
626             scinfo->vcpus[i].vcpuid > max_vcpuid) {
627             LOGD(ERROR, domid, "Invalid VCPU %d: valid range is [0, %d]",
628                         scinfo->vcpus[i].vcpuid, max_vcpuid);
629             rc = ERROR_INVAL;
630             goto out;
631         }
632         rc = sched_rtds_validate_params(gc, scinfo->vcpus[i].period,
633                                         scinfo->vcpus[i].budget);
634         if (rc) {
635             rc = ERROR_INVAL;
636             goto out;
637         }
638     }
639     GCNEW_ARRAY(vcpus, scinfo->num_vcpus);
640     for (i = 0; i < scinfo->num_vcpus; i++) {
641         vcpus[i].vcpuid = scinfo->vcpus[i].vcpuid;
642         vcpus[i].u.rtds.period = scinfo->vcpus[i].period;
643         vcpus[i].u.rtds.budget = scinfo->vcpus[i].budget;
644         if (scinfo->vcpus[i].extratime)
645             vcpus[i].u.rtds.flags |= XEN_DOMCTL_SCHEDRT_extra;
646         else
647             vcpus[i].u.rtds.flags &= ~XEN_DOMCTL_SCHEDRT_extra;
648     }
649 
650     r = xc_sched_rtds_vcpu_set(CTX->xch, domid,
651                                vcpus, scinfo->num_vcpus);
652     if (r != 0) {
653         LOGED(ERROR, domid, "Setting vcpu sched rtds");
654         rc = ERROR_FAIL;
655         goto out;
656     }
657     rc = 0;
658 out:
659     return rc;
660 }
661 
662 /* 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)663 static int sched_rtds_vcpu_set_all(libxl__gc *gc, uint32_t domid,
664                                    const libxl_vcpu_sched_params *scinfo)
665 {
666     int r, rc;
667     int i;
668     uint16_t max_vcpuid;
669     xc_dominfo_t info;
670     struct xen_domctl_schedparam_vcpu *vcpus;
671     uint32_t num_vcpus;
672 
673     r = xc_domain_getinfo(CTX->xch, domid, 1, &info);
674     if (r < 0) {
675         LOGED(ERROR, domid, "Getting domain info");
676         rc = ERROR_FAIL;
677         goto out;
678     }
679     max_vcpuid = info.max_vcpu_id;
680 
681     if (scinfo->num_vcpus != 1) {
682         rc = ERROR_INVAL;
683         goto out;
684     }
685     if (sched_rtds_validate_params(gc, scinfo->vcpus[0].period,
686                                    scinfo->vcpus[0].budget)) {
687         rc = ERROR_INVAL;
688         goto out;
689     }
690     num_vcpus = max_vcpuid + 1;
691     GCNEW_ARRAY(vcpus, num_vcpus);
692     for (i = 0; i < num_vcpus; i++) {
693         vcpus[i].vcpuid = i;
694         vcpus[i].u.rtds.period = scinfo->vcpus[0].period;
695         vcpus[i].u.rtds.budget = scinfo->vcpus[0].budget;
696         if (scinfo->vcpus[0].extratime)
697             vcpus[i].u.rtds.flags |= XEN_DOMCTL_SCHEDRT_extra;
698         else
699             vcpus[i].u.rtds.flags &= ~XEN_DOMCTL_SCHEDRT_extra;
700     }
701 
702     r = xc_sched_rtds_vcpu_set(CTX->xch, domid,
703                                vcpus, num_vcpus);
704     if (r != 0) {
705         LOGED(ERROR, domid, "Setting vcpu sched rtds");
706         rc = ERROR_FAIL;
707         goto out;
708     }
709     rc = 0;
710 out:
711     return rc;
712 }
713 
sched_rtds_domain_get(libxl__gc * gc,uint32_t domid,libxl_domain_sched_params * scinfo)714 static int sched_rtds_domain_get(libxl__gc *gc, uint32_t domid,
715                                libxl_domain_sched_params *scinfo)
716 {
717     struct xen_domctl_sched_rtds sdom;
718     int rc;
719 
720     rc = xc_sched_rtds_domain_get(CTX->xch, domid, &sdom);
721     if (rc != 0) {
722         LOGED(ERROR, domid, "Getting domain sched rtds");
723         return ERROR_FAIL;
724     }
725 
726     libxl_domain_sched_params_init(scinfo);
727 
728     scinfo->sched = LIBXL_SCHEDULER_RTDS;
729     scinfo->period = sdom.period;
730     scinfo->budget = sdom.budget;
731 
732     return 0;
733 }
734 
sched_rtds_domain_set(libxl__gc * gc,uint32_t domid,const libxl_domain_sched_params * scinfo)735 static int sched_rtds_domain_set(libxl__gc *gc, uint32_t domid,
736                                const libxl_domain_sched_params *scinfo)
737 {
738     struct xen_domctl_sched_rtds sdom;
739     int rc;
740 
741     rc = xc_sched_rtds_domain_get(CTX->xch, domid, &sdom);
742     if (rc != 0) {
743         LOGED(ERROR, domid, "Getting domain sched rtds");
744         return ERROR_FAIL;
745     }
746     if (scinfo->period != LIBXL_DOMAIN_SCHED_PARAM_PERIOD_DEFAULT)
747         sdom.period = scinfo->period;
748     if (scinfo->budget != LIBXL_DOMAIN_SCHED_PARAM_BUDGET_DEFAULT)
749         sdom.budget = scinfo->budget;
750     /* Set extratime by default */
751     if (scinfo->extratime)
752         sdom.flags |= XEN_DOMCTL_SCHEDRT_extra;
753     else
754         sdom.flags &= ~XEN_DOMCTL_SCHEDRT_extra;
755     if (sched_rtds_validate_params(gc, sdom.period, sdom.budget))
756         return ERROR_INVAL;
757 
758     rc = xc_sched_rtds_domain_set(CTX->xch, domid, &sdom);
759     if (rc < 0) {
760         LOGED(ERROR, domid, "Setting domain sched rtds");
761         return ERROR_FAIL;
762     }
763 
764     return 0;
765 }
766 
libxl_domain_sched_params_set(libxl_ctx * ctx,uint32_t domid,const libxl_domain_sched_params * scinfo)767 int libxl_domain_sched_params_set(libxl_ctx *ctx, uint32_t domid,
768                                   const libxl_domain_sched_params *scinfo)
769 {
770     GC_INIT(ctx);
771     libxl_scheduler sched = scinfo->sched;
772     int ret;
773 
774     if (sched == LIBXL_SCHEDULER_UNKNOWN)
775         sched = libxl__domain_scheduler(gc, domid);
776 
777     switch (sched) {
778     case LIBXL_SCHEDULER_SEDF:
779         LOGD(ERROR, domid, "SEDF scheduler no longer available");
780         ret=ERROR_FEATURE_REMOVED;
781         break;
782     case LIBXL_SCHEDULER_CREDIT:
783         ret=sched_credit_domain_set(gc, domid, scinfo);
784         break;
785     case LIBXL_SCHEDULER_CREDIT2:
786         ret=sched_credit2_domain_set(gc, domid, scinfo);
787         break;
788     case LIBXL_SCHEDULER_ARINC653:
789         ret=sched_arinc653_domain_set(gc, domid, scinfo);
790         break;
791     case LIBXL_SCHEDULER_RTDS:
792         ret=sched_rtds_domain_set(gc, domid, scinfo);
793         break;
794     case LIBXL_SCHEDULER_NULL:
795         ret=sched_null_domain_set(gc, domid, scinfo);
796         break;
797     default:
798         LOGD(ERROR, domid, "Unknown scheduler");
799         ret=ERROR_INVAL;
800         break;
801     }
802 
803     GC_FREE;
804     return ret;
805 }
806 
libxl_vcpu_sched_params_set(libxl_ctx * ctx,uint32_t domid,const libxl_vcpu_sched_params * scinfo)807 int libxl_vcpu_sched_params_set(libxl_ctx *ctx, uint32_t domid,
808                                 const libxl_vcpu_sched_params *scinfo)
809 {
810     GC_INIT(ctx);
811     libxl_scheduler sched = scinfo->sched;
812     int rc;
813 
814     if (sched == LIBXL_SCHEDULER_UNKNOWN)
815         sched = libxl__domain_scheduler(gc, domid);
816 
817     switch (sched) {
818     case LIBXL_SCHEDULER_SEDF:
819         LOGD(ERROR, domid, "SEDF scheduler no longer available");
820         rc = ERROR_FEATURE_REMOVED;
821         break;
822     case LIBXL_SCHEDULER_CREDIT:
823     case LIBXL_SCHEDULER_CREDIT2:
824     case LIBXL_SCHEDULER_ARINC653:
825     case LIBXL_SCHEDULER_NULL:
826         LOGD(ERROR, domid, "per-VCPU parameter setting not supported for this scheduler");
827         rc = ERROR_INVAL;
828         break;
829     case LIBXL_SCHEDULER_RTDS:
830         rc = sched_rtds_vcpu_set(gc, domid, scinfo);
831         break;
832     default:
833         LOGD(ERROR, domid, "Unknown scheduler");
834         rc = ERROR_INVAL;
835         break;
836     }
837 
838     GC_FREE;
839     return rc;
840 }
841 
libxl_vcpu_sched_params_set_all(libxl_ctx * ctx,uint32_t domid,const libxl_vcpu_sched_params * scinfo)842 int libxl_vcpu_sched_params_set_all(libxl_ctx *ctx, uint32_t domid,
843                                     const libxl_vcpu_sched_params *scinfo)
844 {
845     GC_INIT(ctx);
846     libxl_scheduler sched = scinfo->sched;
847     int rc;
848 
849     if (sched == LIBXL_SCHEDULER_UNKNOWN)
850         sched = libxl__domain_scheduler(gc, domid);
851 
852     switch (sched) {
853     case LIBXL_SCHEDULER_SEDF:
854         LOGD(ERROR, domid, "SEDF scheduler no longer available");
855         rc = ERROR_FEATURE_REMOVED;
856         break;
857     case LIBXL_SCHEDULER_CREDIT:
858     case LIBXL_SCHEDULER_CREDIT2:
859     case LIBXL_SCHEDULER_ARINC653:
860     case LIBXL_SCHEDULER_NULL:
861         LOGD(ERROR, domid, "per-VCPU parameter setting not supported for this scheduler");
862         rc = ERROR_INVAL;
863         break;
864     case LIBXL_SCHEDULER_RTDS:
865         rc = sched_rtds_vcpu_set_all(gc, domid, scinfo);
866         break;
867     default:
868         LOGD(ERROR, domid, "Unknown scheduler");
869         rc = ERROR_INVAL;
870         break;
871     }
872 
873     GC_FREE;
874     return rc;
875 }
876 
libxl_domain_sched_params_get(libxl_ctx * ctx,uint32_t domid,libxl_domain_sched_params * scinfo)877 int libxl_domain_sched_params_get(libxl_ctx *ctx, uint32_t domid,
878                                   libxl_domain_sched_params *scinfo)
879 {
880     GC_INIT(ctx);
881     int ret;
882 
883     libxl_domain_sched_params_init(scinfo);
884 
885     scinfo->sched = libxl__domain_scheduler(gc, domid);
886 
887     switch (scinfo->sched) {
888     case LIBXL_SCHEDULER_SEDF:
889         LOGD(ERROR, domid, "SEDF scheduler no longer available");
890         ret=ERROR_FEATURE_REMOVED;
891         break;
892     case LIBXL_SCHEDULER_CREDIT:
893         ret=sched_credit_domain_get(gc, domid, scinfo);
894         break;
895     case LIBXL_SCHEDULER_CREDIT2:
896         ret=sched_credit2_domain_get(gc, domid, scinfo);
897         break;
898     case LIBXL_SCHEDULER_RTDS:
899         ret=sched_rtds_domain_get(gc, domid, scinfo);
900         break;
901     case LIBXL_SCHEDULER_NULL:
902         ret=sched_null_domain_get(gc, domid, scinfo);
903         break;
904     default:
905         LOGD(ERROR, domid, "Unknown scheduler");
906         ret=ERROR_INVAL;
907         break;
908     }
909 
910     GC_FREE;
911     return ret;
912 }
913 
libxl_vcpu_sched_params_get(libxl_ctx * ctx,uint32_t domid,libxl_vcpu_sched_params * scinfo)914 int libxl_vcpu_sched_params_get(libxl_ctx *ctx, uint32_t domid,
915                                 libxl_vcpu_sched_params *scinfo)
916 {
917     GC_INIT(ctx);
918     int rc;
919 
920     scinfo->sched = libxl__domain_scheduler(gc, domid);
921 
922     switch (scinfo->sched) {
923     case LIBXL_SCHEDULER_SEDF:
924         LOGD(ERROR, domid, "SEDF scheduler is no longer available");
925         rc = ERROR_FEATURE_REMOVED;
926         break;
927     case LIBXL_SCHEDULER_CREDIT:
928     case LIBXL_SCHEDULER_CREDIT2:
929     case LIBXL_SCHEDULER_ARINC653:
930     case LIBXL_SCHEDULER_NULL:
931         LOGD(ERROR, domid, "per-VCPU parameter getting not supported for this scheduler");
932         rc = ERROR_INVAL;
933         break;
934     case LIBXL_SCHEDULER_RTDS:
935         rc = sched_rtds_vcpu_get(gc, domid, scinfo);
936         break;
937     default:
938         LOGD(ERROR, domid, "Unknown scheduler");
939         rc = ERROR_INVAL;
940         break;
941     }
942 
943     GC_FREE;
944     return rc;
945 }
946 
libxl_vcpu_sched_params_get_all(libxl_ctx * ctx,uint32_t domid,libxl_vcpu_sched_params * scinfo)947 int libxl_vcpu_sched_params_get_all(libxl_ctx *ctx, uint32_t domid,
948                                     libxl_vcpu_sched_params *scinfo)
949 {
950     GC_INIT(ctx);
951     int rc;
952 
953     scinfo->sched = libxl__domain_scheduler(gc, domid);
954 
955     switch (scinfo->sched) {
956     case LIBXL_SCHEDULER_SEDF:
957         LOGD(ERROR, domid, "SEDF scheduler is no longer available");
958         rc = ERROR_FEATURE_REMOVED;
959         break;
960     case LIBXL_SCHEDULER_CREDIT:
961     case LIBXL_SCHEDULER_CREDIT2:
962     case LIBXL_SCHEDULER_ARINC653:
963     case LIBXL_SCHEDULER_NULL:
964         LOGD(ERROR, domid, "per-VCPU parameter getting not supported for this scheduler");
965         rc = ERROR_INVAL;
966         break;
967     case LIBXL_SCHEDULER_RTDS:
968         rc = sched_rtds_vcpu_get_all(gc, domid, scinfo);
969         break;
970     default:
971         LOGD(ERROR, domid, "Unknown scheduler");
972         rc = ERROR_INVAL;
973         break;
974     }
975 
976     GC_FREE;
977     return rc;
978 }
979 
980 /*
981  * Local variables:
982  * mode: C
983  * c-basic-offset: 4
984  * indent-tabs-mode: nil
985  * End:
986  */
987