Index: xend_internal.c
===================================================================
RCS file: /data/cvs/libvirt/src/xend_internal.c,v
retrieving revision 1.173
diff -u -p -r1.173 xend_internal.c
--- xend_internal.c	7 Mar 2008 09:23:30 -0000	1.173
+++ xend_internal.c	13 Mar 2008 05:41:33 -0000
@@ -65,6 +65,18 @@ static int xenDaemonAttachDevice(virDoma
 static int xenDaemonDetachDevice(virDomainPtr domain, const char *xml);
 static int xenDaemonDomainCoreDump(virDomainPtr domain, const char *filename,
                                    int flags);
+static char *xenDaemonGetSchedulerType(virDomainPtr domain, int *nparams);
+static int xenDaemonGetSchedulerParameters(virDomainPtr domain,
+                                 virSchedParameterPtr params, int *nparams);
+static int xenDaemonSetSchedulerParameters(virDomainPtr domain,
+                                 virSchedParameterPtr params, int nparams);
+
+/*
+ * The number of Xen scheduler parameters
+ */
+#define XEN_SCHED_SEDF_NPARAM   6
+#define XEN_SCHED_CRED_NPARAM   2
+
 #endif /* PROXY */
 
 #ifndef PROXY
@@ -105,9 +117,9 @@ struct xenUnifiedDriver xenDaemonDriver 
     xenDaemonDetachDevice, /* domainDetachDevice */
     NULL, /* domainGetAutostart */
     NULL, /* domainSetAutostart */
-    NULL, /* domainGetSchedulerType */
-    NULL, /* domainGetSchedulerParameters */
-    NULL, /* domainSetSchedulerParameters */
+    xenDaemonGetSchedulerType, /* domainGetSchedulerType */
+    xenDaemonGetSchedulerParameters, /* domainGetSchedulerParameters */
+    xenDaemonSetSchedulerParameters, /* domainSetSchedulerParameters */
 };
 
 /**
@@ -3658,6 +3670,283 @@ error:
     return(ret);
 }
 
+/**
+ * xenDaemonGetSchedulerType:
+ * @domain: pointer to the Domain block
+ * @nparams: give a number of scheduler parameters
+ *
+ * Get the scheduler type of Xen
+ *
+ * Returns a scheduler name (credit or sedf) which must be freed by the 
+ * caller or NULL in case of failure
+ */
+static char *
+xenDaemonGetSchedulerType(virDomainPtr domain, int *nparams)
+{
+    xenUnifiedPrivatePtr priv;
+    struct sexpr *root;
+    const char *ret = NULL;
+    char *schedulertype = NULL;
+
+    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)
+        || (nparams == NULL)) {
+        virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+                     __FUNCTION__);
+        return NULL;
+    }
+
+    /* Support only xendConfigVersion >=4 */
+    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
+    if (priv->xendConfigVersion < 4) {
+        virXendError (domain->conn, VIR_ERR_NO_SUPPORT,
+                      "unsupported in xendConfigVersion < 4");
+        return NULL;
+    }
+
+    root = sexpr_get(domain->conn, "/xend/node/");
+    if (root == NULL)
+        return NULL;
+
+    /* get xen_scheduler from xend/node */
+    ret = sexpr_node(root, "node/xen_scheduler");
+    if (ret == NULL){
+        virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR,
+                     _("node information incomplete, missing scheduler name"));
+        goto error;
+    }
+    if (STREQ (ret, "credit")) {
+        schedulertype = strdup("credit");
+        if (schedulertype == NULL){
+            virXendError(domain->conn, VIR_ERR_SYSTEM_ERROR, _("strdup failed"));
+            goto error;
+        }
+        *nparams = XEN_SCHED_CRED_NPARAM;
+    } else if (STREQ (ret, "sedf")) {
+        schedulertype = strdup("sedf");
+        if (schedulertype == NULL){
+            virXendError(domain->conn, VIR_ERR_SYSTEM_ERROR, _("strdup failed"));
+            goto error;
+        }
+        *nparams = XEN_SCHED_SEDF_NPARAM;
+    } else {
+        virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR, _("Unknown scheduler"));
+        goto error;
+    }
+
+error:
+    sexpr_free(root);
+    return schedulertype;
+
+}
+
+static const char *str_weight = "weight";
+static const char *str_cap = "cap";
+
+/**
+ * xenDaemonGetSchedulerParameters:
+ * @domain: pointer to the Domain block
+ * @params: pointer to scheduler parameters
+ *          This memory area must be allocated by the caller
+ * @nparams: a number of scheduler parameters which should be same as a 
+ *           given number from xenDaemonGetSchedulerType()
+ *
+ * Get the scheduler parameters
+ *
+ * Returns 0 or -1 in case of failure
+ */
+static int
+xenDaemonGetSchedulerParameters(virDomainPtr domain,
+                                 virSchedParameterPtr params, int *nparams)
+{
+    xenUnifiedPrivatePtr priv;
+    struct sexpr *root;
+    char *sched_type = NULL;
+    int sched_nparam = 0;
+    int ret = -1;
+
+    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)
+        || (params == NULL) || (nparams == NULL)) {
+        virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+                     __FUNCTION__);
+        return (-1);
+    }
+
+    /* Support only xendConfigVersion >=4 */
+    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
+    if (priv->xendConfigVersion < 4) {
+        virXendError (domain->conn, VIR_ERR_NO_SUPPORT,
+                      "unsupported in xendConfigVersion < 4");
+        return (-1);
+    }
+
+    /* look up the information by domain name */
+    root = sexpr_get(domain->conn, "/xend/domain/%s?detail=1", domain->name);
+    if (root == NULL)
+        return (-1);
+
+    /* get the scheduler type */
+    sched_type = xenDaemonGetSchedulerType(domain, &sched_nparam);
+    if (sched_type == NULL) {
+        virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR,
+                     _("Failed to get a scheduler name"));
+        goto error;
+    }
+
+    switch (sched_nparam){
+        case XEN_SCHED_SEDF_NPARAM:
+            /* TODO: Implement for Xen/SEDF */
+            TODO
+            goto error;
+        case XEN_SCHED_CRED_NPARAM:
+            /* get cpu_weight/cpu_cap from xend/domain */
+            if (sexpr_node(root, "domain/cpu_weight") == NULL) {
+                virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR,
+                        _("domain information incomplete, missing cpu_weight"));
+                goto error;
+            }
+            if (sexpr_node(root, "domain/cpu_cap") == NULL) {
+                virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR,
+                        _("domain information incomplete, missing cpu_cap"));
+                goto error;
+            }
+
+            strncpy (params[0].field, str_weight, VIR_DOMAIN_SCHED_FIELD_LENGTH);
+            params[0].field[VIR_DOMAIN_SCHED_FIELD_LENGTH-1] = '\0';
+            params[0].type = VIR_DOMAIN_SCHED_FIELD_UINT;
+            params[0].value.ui = sexpr_int(root, "domain/cpu_weight");
+
+            strncpy (params[1].field, str_cap, VIR_DOMAIN_SCHED_FIELD_LENGTH);
+            params[1].field[VIR_DOMAIN_SCHED_FIELD_LENGTH-1] = '\0';
+            params[1].type = VIR_DOMAIN_SCHED_FIELD_UINT;
+            params[1].value.ui = sexpr_int(root, "domain/cpu_cap");
+            *nparams = XEN_SCHED_CRED_NPARAM;
+            ret = 0;
+            break;
+        default:
+            virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR, _("Unknown scheduler"));
+            goto error;
+    }
+
+error:
+    sexpr_free(root);
+    if (sched_type != NULL)
+        free(sched_type);
+    return (ret);
+}
+
+/**
+ * xenDaemonSetSchedulerParameters:
+ * @domain: pointer to the Domain block
+ * @params: pointer to scheduler parameters
+ * @nparams: a number of scheduler setting parameters
+ *
+ * Set the scheduler parameters
+ *
+ * Returns 0 or -1 in case of failure
+ */
+static int
+xenDaemonSetSchedulerParameters(virDomainPtr domain,
+                                virSchedParameterPtr params, int nparams)
+{
+    xenUnifiedPrivatePtr priv;
+    struct sexpr *root;
+    char *sched_type = NULL;
+    int i;
+    int sched_nparam = 0;
+    int ret = -1;
+
+    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)
+        || (params == NULL)) {
+        virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
+                     __FUNCTION__);
+        return (-1);
+    }
+
+    /* Support only xendConfigVersion >=4 and active domains */
+    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
+    if (priv->xendConfigVersion < 4) {
+        virXendError (domain->conn, VIR_ERR_NO_SUPPORT,
+                      "unsupported in xendConfigVersion < 4");
+        return (-1);
+    }
+
+    /* look up the information by domain name */
+    root = sexpr_get(domain->conn, "/xend/domain/%s?detail=1", domain->name);
+    if (root == NULL)
+        return (-1);
+
+    /* get the scheduler type */
+    sched_type = xenDaemonGetSchedulerType(domain, &sched_nparam);
+    if (sched_type == NULL) {
+        virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR,
+                     _("Failed to get a scheduler name"));
+        goto error;
+    }
+
+    switch (sched_nparam){
+        case XEN_SCHED_SEDF_NPARAM:
+            /* TODO: Implement for Xen/SEDF */
+            TODO
+            goto error;
+        case XEN_SCHED_CRED_NPARAM: {
+            char buf_weight[VIR_UUID_BUFLEN];
+            char buf_cap[VIR_UUID_BUFLEN];
+            const char *weight = NULL;
+            const char *cap = NULL;
+
+            /* get the scheduler parameters */
+            memset(&buf_weight, 0, VIR_UUID_BUFLEN);
+            memset(&buf_cap, 0, VIR_UUID_BUFLEN);
+            for (i = 0; i < nparams; i++) {
+                if (STREQ (params[i].field, str_weight) &&
+                    params[i].type == VIR_DOMAIN_SCHED_FIELD_UINT) {
+                    snprintf(buf_weight, sizeof(buf_weight), "%u", params[i].value.ui);
+                } else if (STREQ (params[i].field, str_cap) &&
+                    params[i].type == VIR_DOMAIN_SCHED_FIELD_UINT) {
+                    snprintf(buf_cap, sizeof(buf_cap), "%u", params[i].value.ui);
+                } else {
+                    virXendError(domain->conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+                    goto error;
+                }
+            }
+
+            /* if not get the scheduler parameter, set the current setting */
+            if (strlen(buf_weight) == 0) {
+                weight = sexpr_node(root, "domain/cpu_weight");
+                if (weight == NULL) {
+                    virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR,
+                                _("domain information incomplete, missing cpu_weight"));
+                    goto error;
+                }
+                snprintf(buf_weight, sizeof(buf_weight), "%s", weight);
+            }
+            if (strlen(buf_cap) == 0) {
+                cap = sexpr_node(root, "domain/cpu_cap");
+                if (cap == NULL) {
+                    virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR,
+                                _("domain information incomplete, missing cpu_cap"));
+                    goto error;
+                }
+                snprintf(buf_cap, sizeof(buf_cap), "%s", cap);
+            }
+
+            ret = xend_op(domain->conn, domain->name, "op",
+                          "domain_sched_credit_set", "weight", buf_weight, 
+                          "cap", buf_cap, NULL);
+            break;
+        }
+        default:
+            virXendError(domain->conn, VIR_ERR_INTERNAL_ERROR, _("Unknown scheduler"));
+            goto error;
+    }
+
+error:
+    sexpr_free(root);
+    if (sched_type != NULL)
+        free(sched_type);
+    return (ret);
+}
+
 #endif /* ! PROXY */
 #endif /* WITH_XEN */
 
