[libvirt] [PATCH 1/2] Addition of XenAPI support to libvirt

Matthias Bolte matthias.bolte at googlemail.com
Fri Mar 5 23:31:41 UTC 2010


2010/3/5 Sharadha Prabhakar (3P) <sharadha.prabhakar at citrix.com>:
> Patch includes
> 1) Modification of xenapiDomainGetOSType
> 1) global url and SSL flags removed and placed in private driver struct.
> 2) SSL verify on url parsed using function similar to the one in ESX.
> 3) mapDomainPinVcpu updated in xenapi_utils.c

> diff -Nur ./libvirt_org/src/xenapi/xenapi_driver.c ./libvirt/src/xenapi/xenapi_driver.c
> --- ./libvirt_org/src/xenapi/xenapi_driver.c    1970-01-01 01:00:00.000000000 +0100
> +++ ./libvirt/src/xenapi/xenapi_driver.c        2010-03-04 16:59:01.000000000 +0000
> @@ -0,0 +1,1738 @@
> +
> +/*
> + * xenapi_driver.c: Xen API driver.
> + * Copyright (C) 2009 Citrix Ltd.
> + * Sharadha Prabhakar <sharadha.prabhakar at citrix.com>
> +*/

A license statement is missing. Using LGPL like the rest of libvirt
would be a good choice.

> +
> +/*
> +*getCapsObject
> +*
> +*Build the capabilities of the hypervisor
> +*Return virCapsPtr on success or NULL on failure
> +*/
> +static virCapsPtr
> +getCapsObject (void)
> +{
> +    virCapsPtr caps = virCapabilitiesNew("x86_64", 0, 0);

You're ignoring the actual host architecture here and assume x86_64
even if the host is just x86.

> +    if (!caps) {
> +        virReportOOMError();
> +        return NULL;
> +    }
> +    virCapsGuestPtr guest1 = virCapabilitiesAddGuest(caps, "hvm", "x86_64", 0, "", "", 0, NULL);
> +    if (!guest1)
> +        goto error_cleanup;
> +    virCapsGuestDomainPtr domain1 = virCapabilitiesAddGuestDomain(guest1, "xen", "", "", 0, NULL);
> +    if (!domain1)
> +        goto error_cleanup;
> +    virCapsGuestPtr guest2 = virCapabilitiesAddGuest(caps, "xen", "x86_64", 0, "", "", 0, NULL);
> +    if (!guest2)
> +        goto error_cleanup;
> +    virCapsGuestDomainPtr domain2 = virCapabilitiesAddGuestDomain(guest2, "xen", "", "", 0, NULL);
> +    if (!domain2)
> +        goto error_cleanup;
> +
> +    return caps;
> +
> +  error_cleanup:
> +    virCapabilitiesFree(caps);
> +    return NULL;
> +}
> +
> +/*
> +*XenapiOpen
> +*
> +*Authenticates and creates a session with the server
> +*Return VIR_DRV_OPEN_SUCCESS on success, else VIR_DRV_OPEN_ERROR
> +*/
> +static virDrvOpenStatus
> +xenapiOpen (virConnectPtr conn, virConnectAuthPtr auth , int flags ATTRIBUTE_UNUSED)
> +{
> +    char *passwd;

Initialize passwd to NULL.

> +    xen_session *session;
> +    struct _xenapiPrivate *privP;
> +    int noVerify=0;
> +
> +    if (!STRCASEEQ(conn->uri->scheme,"XenAPI")) {
> +        xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Check URI format: 'XenAPI://user@server'");

The given URI is not for you, this is no error, so don't report an
error, just return VIR_DRV_OPEN_DECLINED.

> +        return VIR_DRV_OPEN_DECLINED;
> +    }
> +    if (conn->uri->server==NULL) {
> +        xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Server name not in URI");
> +        return VIR_DRV_OPEN_ERROR;
> +    }
> +    if (auth) {
> +        passwd = xenapiUtil_RequestPassword(auth,conn->uri->user,conn->uri->server);
> +    } else {
> +        xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Authentication Credentials not found");
> +        return VIR_DRV_OPEN_ERROR;
> +    }
> +    if (!passwd && !conn->uri->user) {

You should use || instead of &&, otherwise you won't catch cases where
passwd is NULL but conn->uri->user isn't and via versa.

> +        xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"Username/Password not valid");

You may leak passwd here. Free is using VIR_FREE(passwd).

> +        return VIR_DRV_OPEN_ERROR;
> +    }
> +    if (VIR_ALLOC(privP) < 0) {
> +        virReportOOMError();

You leak passwd here too.

> +        return VIR_DRV_OPEN_ERROR;
> +    }
> +    if (virAsprintf(&(privP->url),"https://%s",conn->uri->server) < 0) {
> +        virReportOOMError();

You may leak passwd here too.

> +        return VIR_DRV_OPEN_ERROR;
> +    }
> +    privP->SSLflag=2;
> +    xenapiUtil_ParseQuery(conn, conn->uri,&noVerify);
> +    if (noVerify==1) privP->SSLflag=0;
> +    xmlInitParser();
> +    xmlKeepBlanksDefault(0);
> +    xen_init();
> +    curl_global_init(CURL_GLOBAL_ALL);
> +
> +    session = xen_session_login_with_password (call_func, (void *)privP, conn->uri->user, "xenroot", xen_api_latest_version);

No need to cast privP to void *.

Shouldn't the parameter after the username be passwd instead of
hardcoding "xenroot"?

> +
> +    if ( session && session->ok ) {
> +        privP->session = session;
> +        virCapsPtr caps = getCapsObject();
> +        if (caps)
> +            privP->caps = caps;

Why not directly assign caps:

privP->caps = getCapsObject();

getCapsObject() may fail you need to check the return value for NULL,
and report an error.

> +        conn->privateData = privP;

You leak passwd here too.

> +        return VIR_DRV_OPEN_SUCCESS;
> +    } else {
> +        xenapiSessionErrorHandler(conn, VIR_ERR_AUTH_FAILED ,"");
> +        VIR_FREE(privP);

You may also get here if session is not NULL but session->ok is false.
I assume session is allocated, so you need to free it here by some
free function, maybe xen_session_logout does this.

You leak passwd here too.

> +        return VIR_DRV_OPEN_ERROR;
> +    }
> +}
> +


> +
> +
> +/*
> +* xenapiGetVersion:
> +*
> +* Gets the version of XenAPI
> +*
> +*/
> +static int
> +xenapiGetVersion (virConnectPtr conn, unsigned long *hvVer)
> +{
> +    xen_host host;
> +    xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session;
> +    xen_string_string_map *result=NULL;
> +    if (!(xen_session_get_this_host(session, &host,session))) {
> +        xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,NULL);
> +        return -1;
> +    }
> +    if (!(xen_host_get_software_version(session, &result, host))) {
> +        xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,NULL);
> +        xen_host_free(host);
> +        return -1;
> +    }
> +    xen_host_free(host);
> +    if (result && result->size>0) {
> +        int i;
> +        char *version=NULL;
> +        for (i=0; i<result->size; i++) {
> +            if (STREQ(result->contents[i].key,"xen")) {
> +                if (!(version = strdup(result->contents[i].val))) {
> +                    xen_string_string_map_free(result);
> +                    virReportOOMError();
> +                    return -1;
> +                }
> +                break;
> +            }
> +        }
> +        if (version) {
> +           unsigned long major=0,minor=0,release=0;
> +           if (sscanf(version,"%ld.%ld.%ld",&major,&minor,&release)!=3) {
> +               virReportOOMError();

If sscanf fails to parse 3 items, then this is no OOM error.

> +               xen_string_string_map_free(result);
> +               VIR_FREE(version);
> +               return -1;
> +           }
> +           *hvVer = major * 1000000 + minor * 1000 + release;
> +           VIR_FREE(version);
> +           xen_string_string_map_free(result);
> +           return 0;
> +        }
> +    }
> +    return -1;
> +}
> +
> +


> +
> +/*
> +* xenapiGetCapabilities:
> +*
> +*
> +* Returns capabilities as an XML string
> +*/
> +static char *
> +xenapiGetCapabilities (virConnectPtr conn)
> +{
> +    virCapsPtr caps = ((struct _xenapiPrivate *)(conn->privateData))->caps;
> +    if (caps) {
> +        char *xml = virCapabilitiesFormatXML(caps);
> +        return xml;

You need to report an OOM error if virCapabilitiesFormatXML returns NULL.

> +    }
> +    xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,"Capabilities not available");
> +    return NULL;
> +}
> +
> +
> +/*
> +* xenapiListDomains
> +*
> +* Collects the list of active domains, and store their ID in @maxids
> +* Returns the number of domain found or -1 in case of error
> +*/
> +static int
> +xenapiListDomains (virConnectPtr conn, int *ids, int maxids)
> +{
> +    /* vm.list */
> +    xen_host host;
> +    xen_vm_set *result=NULL;
> +    xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session;
> +    if (xen_session_get_this_host(session, &host, session)) {
> +        xen_host_get_resident_vms(session, &result, host);
> +        xen_host_free(host);
> +    } else
> +        xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR ,NULL);
> +
> +    if (result != NULL) {
> +        int i;
> +        for ( i=0; (i < (result->size)) && (i<maxids) ; i++ ) {
> +            int64_t t0;
> +            xen_vm_get_domid(session, &t0, result->contents[i]);

Maybe you should check if the ID doesn't fit into an int and report an
error in that case, instead of just masking out the upper 32bit.

> +            ids[i] = (int)(t0 & 0xffffffff);
> +        }
> +       xen_vm_set_free(result);
> +        return i;
> +    }
> +    return -1;
> +}
> +


> +
> +/*
> +* xenapiDomainCreateXML
> +*
> +* Launches a new domain based on the XML description
> +* Returns the domain pointer or NULL in case of error
> +*/
> +static virDomainPtr
> +xenapiDomainCreateXML (virConnectPtr conn,
> +                       const char *xmlDesc, ATTRIBUTE_UNUSED unsigned int flags)

Normally ATTRIBUTE_UNUSED is placed behind the parameter, not in front of it.

> +{
> +    xen_vm_record *record=NULL;
> +    xen_vm vm=NULL;
> +    virDomainPtr domP=NULL;
> +    xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session;
> +    virCapsPtr caps = ((struct _xenapiPrivate *)(conn->privateData))->caps;
> +    if (!caps)
> +        return NULL;
> +
> +    virDomainDefPtr defPtr = virDomainDefParseString(caps, xmlDesc, flags);
> +    createVMRecordFromXml(conn, defPtr, &record, &vm);
> +    virDomainDefFree(defPtr);
> +    if (record) {
> +        unsigned char raw_uuid[VIR_UUID_BUFLEN];
> +       virUUIDParse(record->uuid,raw_uuid);
> +       if (vm) {
> +            if (xen_vm_start(session, vm, false, false)) {
> +               domP = virGetDomain(conn, record->name_label, raw_uuid);
> +                if (!domP) {
> +                    xen_vm_record_free(record);
> +                    xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Domain Pointer is invalid");
> +                    return domP;
> +                }
> +                domP->id = record->domid;
> +               xen_vm_free(vm);
> +           }
> +            else
> +                xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL);
> +       }
> +        xen_vm_record_free(record);
> +    }
> +    else
> +        xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL);
> +    return domP;
> +}
> +


> +
> +/*
> +* xenapiDomainLookupByName
> +*
> +* Returns the domain pointer of domain with matching name
> +* or -1 in case of error
> +*/
> +static virDomainPtr
> +xenapiDomainLookupByName (virConnectPtr conn,
> +                          const char *name)
> +{
> +    /* vm.get_by_name_label */
> +    xen_vm_set *vms=NULL;
> +    xen_vm vm;
> +    char *uuid=NULL;
> +    unsigned char raw_uuid[VIR_UUID_BUFLEN];
> +    virDomainPtr domP=NULL;
> +    xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session;
> +    if (xen_vm_get_by_name_label(session, &vms, (char *)name)) {
> +        if (vms->size!=1) {
> +            xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique");

You should distinguish between vms->size < 1 and vms->size > 1. If
there is no domain with a given name you'll report an error that says
that the domain name is not unique.

Or is vms->size >= 1 guaranteed if xen_vm_get_by_name_label succeeds?
If not then this applies to all other fucntions too, where you check
vms->size != 1.

> +            xen_vm_set_free(vms);
> +            return NULL;
> +        }
> +        vm = vms->contents[0];
> +       xen_vm_get_uuid(session, &uuid, vm);
> +        if (uuid!=NULL) {
> +           virUUIDParse(uuid,raw_uuid);
> +           domP = virGetDomain(conn, name, raw_uuid);
> +            if (domP != NULL) {
> +                int64_t domid=-1;
> +                xen_vm_get_domid(session, &domid, vm);
> +                domP->id = domid;
> +                xen_uuid_free(uuid);
> +                xen_vm_set_free(vms);
> +               return domP;
> +            } else {
> +                xen_uuid_free(uuid);
> +                xen_vm_set_free(vms);
> +               if (!(session->ok))
> +                   xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL);
> +                return NULL;
> +            }
> +        }

You're leaking vms here.

> +    }
> +    xenapiSessionErrorHandler(conn, VIR_ERR_NO_DOMAIN, NULL);
> +    return NULL;
> +}
> +


> +/*
> +* xenapiDomainGetMaxMemory
> +*
> +* Returns maximum static memory for VM on success
> +* or 0 in case of error
> +*/
> +static unsigned long
> +xenapiDomainGetMaxMemory (virDomainPtr dom)
> +{
> +    int64_t mem_static_max=0;
> +    xen_vm vm;
> +    xen_vm_set *vms;
> +    xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session;
> +    if (xen_vm_get_by_name_label(session, &vms, dom->name)) {
> +        if (vms->size!=1) {
> +            xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique");
> +            xen_vm_set_free(vms);
> +            return 0;
> +        }
> +       vm = vms->contents[0];
> +        xen_vm_get_memory_static_max(session, &mem_static_max, vm);
> +       xen_vm_set_free(vms);
> +        return (unsigned long)(mem_static_max/1024);

Is mem_static_max a value in byte? libvirt expects this value in kilobyte.

> +    } else {
> +        xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL);
> +       return 0;
> +    }
> +}
> +
> +/*
> +* xenapiDomainSetMaxMemory
> +*
> +* Sets maximum static memory for VM on success
> +* Returns 0 on success or -1 in case of error
> +*/
> +static int
> +xenapiDomainSetMaxMemory (virDomainPtr dom, unsigned long memory)
> +{
> +    /* vm.set_memory_static_max */
> +    xen_vm vm;
> +    struct xen_vm_set *vms;
> +    xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session;
> +    if (xen_vm_get_by_name_label(session, &vms, dom->name)) {
> +        if (vms->size!=1) {
> +            xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique");
> +            xen_vm_set_free(vms);
> +            return -1;
> +        }
> +        vm = vms->contents[0];

If mem_static_max is in byte then you need to multiply memory by 1024,
because memory is in kilobyte.

> +        if (!(xen_vm_set_memory_static_max(session, vm, memory))) {
> +            xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL);
> +            xen_vm_set_free(vms);
> +            return -1;
> +        }
> +        xen_vm_set_free(vms);
> +    } else {
> +        xenapiSessionErrorHandler(dom->conn, VIR_ERR_NO_DOMAIN, NULL);
> +        return -1;
> +    }
> +    return 0;
> +}
> +



> +
> +/*
> +* xenapiDomainGetVcpus
> +*
> +* Gets Vcpu information
> +* Return number of structures filled on success or -1 in case of error
> +*/
> +static int
> +xenapiDomainGetVcpus (virDomainPtr dom,
> +                      virVcpuInfoPtr info, int maxinfo,
> +                      unsigned char *cpumaps, int maplen)
> +{
> +
> +    xen_vm_set *vms=NULL;
> +    xen_vm vm=NULL;
> +    xen_string_string_map *vcpu_params=NULL;
> +    int nvcpus=0,cpus=0,i;
> +    virDomainInfoPtr domInfo;
> +    virNodeInfo nodeInfo;
> +    virVcpuInfoPtr ifptr;
> +    xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session;
> +    char *mask=NULL;
> +    if((cpumaps!=NULL) && (maplen < 1))
> +        return -1;
> +    if (VIR_ALLOC(domInfo)<0) {

Don't allocate domInfo here, just use a virDomainInfo directly on the
stack, like you do it with virNodeInfo.

> +        virReportOOMError();
> +        return -1;
> +    }
> +    if (virDomainGetInfo(dom,domInfo)==0) {

You should not call libvirt public API functions from here. You can
call xenapiDomainGetInfo directly.

> +        nvcpus = domInfo->nrVirtCpu;
> +       VIR_FREE(domInfo);

If you put domInfo on the stack, remove this free call.

> +    } else {
> +        xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, "Couldn't fetch Domain Information");
> +        return -1;
> +    }
> +    if ( virNodeGetInfo(dom->conn,&nodeInfo)==0)

Just call xenapiNodeGetInfo directly here.

> +        cpus = nodeInfo.cpus;
> +    else {
> +        xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, "Couldn't fetch Node Information");
> +        return -1;
> +    }
> +    if(nvcpus > maxinfo) nvcpus = maxinfo;
> +
> +    if (cpumaps != NULL)
> +        memset(cpumaps, 0, maxinfo * maplen);
> +    if (!xen_vm_get_by_name_label(session, &vms, dom->name)) return -1;
> +    if (vms->size!=1) {
> +        xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique");
> +        xen_vm_set_free(vms);
> +        return -1;
> +    }
> +    vm = vms->contents[0];
> +    if (!xen_vm_get_vcpus_params(session, &vcpu_params, vm)) {
> +        xen_vm_set_free(vms);
> +        xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, NULL);
> +        return -1;
> +    }
> +    for (i=0; i<vcpu_params->size; i++) {
> +        if (STREQ(vcpu_params->contents[i].key,"mask")) {
> +           if (!(mask = strdup(vcpu_params->contents[i].val))){
> +                 xen_vm_set_free(vms);
> +                 xen_string_string_map_free(vcpu_params);
> +                 virReportOOMError();
> +                 return -1;
> +            }
> +            break;
> +         }
> +    }
> +    xen_string_string_map_free(vcpu_params);
> +    for (i=0,ifptr=info ;i<nvcpus; i++,ifptr++) {
> +        ifptr->number = i;
> +       ifptr->state = VIR_VCPU_RUNNING;
> +       ifptr->cpuTime = 0;
> +       ifptr->cpu = 0;
> +       if (mask !=NULL)
> +           getCpuBitMapfromString(mask,VIR_GET_CPUMAP(cpumaps,maplen,i),maplen);
> +    }
> +    VIR_FREE(mask);
> +    xen_vm_set_free(vms);
> +    return i;
> +}
> +


> +
> +/*
> +* xenapiDomainDumpXML
> +*
> +*
> +* Returns XML string of the domain configuration on success or -1 in case of error
> +*/
> +static char *
> +xenapiDomainDumpXML (virDomainPtr dom, ATTRIBUTE_UNUSED int flags)

Put ATTRIBUTE_UNUSED behind the parameter.

> +{
> +    xen_vm vm=NULL;
> +    xen_vm_set *vms;
> +    xen_string_string_map *result=NULL;
> +    xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session;
> +    virDomainDefPtr defPtr = NULL;
> +
> +    if(!xen_vm_get_by_name_label(session, &vms, dom->name)) return NULL;
> +    if (vms->size!=1) {
> +        xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR,"Domain name is not unique");
> +        xen_vm_set_free(vms);
> +        return NULL;
> +    }
> +    if (VIR_ALLOC(defPtr)<0) {
> +        virReportOOMError();
> +        xen_vm_set_free(vms);
> +        return NULL;
> +    }
> +    vm = vms->contents[0];
> +    defPtr->virtType = VIR_DOMAIN_VIRT_XEN;
> +    defPtr->id = dom->id;
> +    memcpy((char *)defPtr->uuid,(char *)dom->uuid,VIR_UUID_BUFLEN);
> +    if (!(defPtr->name = strdup(dom->name)))
> +        goto error_cleanup;
> +    char *boot_policy=NULL;
> +    xen_vm_get_hvm_boot_policy(session, &boot_policy, vm);
> +    if (STREQ(boot_policy,"BIOS order")) {
> +        if (!(defPtr->os.type = strdup("hvm"))) {
> +            VIR_FREE(boot_policy);
> +            goto error_cleanup;
> +        }
> +        xen_vm_get_hvm_boot_params(session, &result, vm);
> +        if (result!=NULL) {
> +            int i;
> +            for (i=0; i<(result->size); i++) {
> +                if (STREQ(result->contents[i].key,"order")) {
> +                   int cnt=0;
> +                   while(result->contents[i].val[cnt]!='\0') {
> +                        defPtr->os.bootDevs[cnt] = map2LibvirtBootOrder(result->contents[i].val[cnt]);
> +                       cnt++;
> +                   }
> +                    defPtr->os.nBootDevs = cnt;

I think you can break the for loop here.

> +               }
> +           }
> +           xen_string_string_map_free(result);
> +        }
> +        VIR_FREE(boot_policy);
> +    } else {
> +        if(!(defPtr->os.type = strdup("xen"))) {
> +            VIR_FREE(boot_policy);
> +            goto error_cleanup;
> +        }
> +        if(!(defPtr->os.loader = strdup("pygrub"))) {
> +            VIR_FREE(boot_policy);
> +            goto error_cleanup;
> +        }
> +        char *value=NULL;
> +        xen_vm_get_pv_kernel(session, &value, vm);
> +        if (STRNEQ(value,"")) {
> +            if(!(defPtr->os.kernel = strdup(value))) {
> +                VIR_FREE(boot_policy);
> +                VIR_FREE(value);
> +                goto error_cleanup;
> +            }
> +           VIR_FREE(value);
> +        }
> +        xen_vm_get_pv_ramdisk(session, &value, vm);
> +        if (STRNEQ(value,"")) {
> +            if(!(defPtr->os.initrd = strdup(value))) {
> +                VIR_FREE(boot_policy);
> +                VIR_FREE(value);
> +                goto error_cleanup;
> +            }
> +           VIR_FREE(value);
> +        }
> +        xen_vm_get_pv_args(session, &value, vm);
> +        if (STRNEQ(value,"")) {
> +            if(!(defPtr->os.cmdline = strdup(value))) {
> +                VIR_FREE(boot_policy);
> +                VIR_FREE(value);
> +                goto error_cleanup;
> +            }
> +           VIR_FREE(value);
> +        }
> +       VIR_FREE(boot_policy);
> +        if(!(defPtr->os.bootloader = strdup("pygrub")))
> +            goto error_cleanup;
> +    }
> +    char *val=NULL;
> +    xen_vm_get_pv_bootloader_args(session, &val, vm);
> +    if (STRNEQ(val,"")) {
> +        if(!(defPtr->os.bootloaderArgs = strdup(val))) {
> +            VIR_FREE(val);
> +            goto error_cleanup;
> +        }
> +       VIR_FREE(val);
> +    }
> +    unsigned long memory=0;
> +    memory = xenapiDomainGetMaxMemory(dom);
> +    defPtr->maxmem = memory;
> +    int64_t dynamic_mem=0;
> +    if (xen_vm_get_memory_dynamic_max(session, &dynamic_mem, vm)) {
> +        defPtr->memory = (unsigned long) (dynamic_mem/1024);
> +    } else {
> +        defPtr->memory = memory;
> +    }
> +    defPtr->vcpus = xenapiDomainGetMaxVcpus(dom);
> +    enum xen_on_normal_exit action;
> +    if (xen_vm_get_actions_after_shutdown(session, &action, vm)) {
> +        defPtr->onPoweroff = xenapiNormalExitEnum2virDomainLifecycle(action);
> +    }
> +    if (xen_vm_get_actions_after_reboot(session, &action, vm)) {
> +        defPtr->onReboot = xenapiNormalExitEnum2virDomainLifecycle(action);
> +    }
> +    enum xen_on_crash_behaviour crash;
> +    if (xen_vm_get_actions_after_crash(session, &crash, vm)) {
> +        defPtr->onCrash = xenapiCrashExitEnum2virDomainLifecycle(action);
> +    }
> +    xen_vm_get_platform(session, &result, vm);
> +    if (result!=NULL) {
> +        int i;
> +       for(i=0; i< (result->size); i++) {
> +           if (STREQ(result->contents[i].val,"true")) {
> +                if (STREQ(result->contents[i].key,"acpi"))
> +                    defPtr->features = defPtr->features | (1<<VIR_DOMAIN_FEATURE_ACPI);
> +                else if (STREQ(result->contents[i].key,"apic"))
> +                    defPtr->features = defPtr->features | (1<<VIR_DOMAIN_FEATURE_APIC);
> +                else if (STREQ(result->contents[i].key,"pae"))
> +                    defPtr->features = defPtr->features | (1<<VIR_DOMAIN_FEATURE_PAE);
> +           }
> +       }
> +        xen_string_string_map_free(result);
> +    }
> +    struct xen_vif_set *vif_set=NULL;
> +    xen_vm_get_vifs(session, &vif_set, vm);
> +    if (vif_set) {
> +        int i;
> +       xen_vif vif;
> +       xen_vif_record *vif_rec=NULL;
> +       xen_network network;
> +       char *bridge=NULL;
> +        defPtr->nnets = vif_set->size;
> +        if (VIR_ALLOC_N(defPtr->nets, vif_set->size)<0) {
> +            xen_vif_set_free(vif_set);
> +            goto error_cleanup;
> +        }
> +       for (i=0; i<vif_set->size; i++) {
> +            if (VIR_ALLOC(defPtr->nets[i])<0) {
> +                xen_vif_set_free(vif_set);
> +                goto error_cleanup;
> +            }
> +            defPtr->nets[i]->type = VIR_DOMAIN_NET_TYPE_BRIDGE;
> +           vif = vif_set->contents[i];
> +            xen_vif_get_network(session, &network, vif);
> +           if (network!=NULL) {
> +                xen_network_get_bridge(session, &bridge, network);
> +                if (bridge!=NULL)
> +                    defPtr->nets[i]->data.bridge.brname = bridge;
> +               xen_network_free(network);
> +           }
> +           xen_vif_get_record(session, &vif_rec, vif);
> +            if (vif_rec!=NULL) {
> +                if(virParseMacAddr((const char *)vif_rec->mac,defPtr->nets[i]->mac) < 0)
> +                    xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, "Unable to parse given mac address");
> +               xen_vif_record_free(vif_rec);
> +           }
> +        }
> +        xen_vif_set_free(vif_set);
> +    }
> +    if (vms) xen_vm_set_free(vms);
> +    char *xml = virDomainDefFormat(defPtr,0);
> +    virDomainDefFree(defPtr);
> +    return xml;
> +
> +  error_cleanup:
> +        virReportOOMError();
> +        xen_vm_set_free(vms);
> +        virDomainDefFree(defPtr);
> +        return NULL;
> +
> +}
> +
> +/*
> +* xenapiListDefinedDomains
> +*
> +* list the defined but inactive domains, stores the pointers to the names in @names
> +* Returns number of names provided in the array or -1 in case of error
> +*/
> +static int
> +xenapiListDefinedDomains (virConnectPtr conn, char **const names,
> +                          int maxnames)
> +{
> +    int i,j=0,doms;
> +    xen_vm_set *result;
> +    xen_vm_record *record;
> +    xen_session *session = ((struct _xenapiPrivate *)(conn->privateData))->session;
> +    xen_vm_get_all(session, &result);
> +    if (result != NULL) {
> +        for (i=0; i< (result->size) && j< maxnames; i++) {
> +           xen_vm_get_record(session, &record, result->contents[i]);
> +           if ( record!=NULL ) {
> +                if ( record->is_a_template == 0 ) {
> +                    char *usenames;
> +                   if (!(usenames = strdup(record->name_label))) {
> +                        virReportOOMError();
> +                        xen_vm_record_free(record);
> +                        xen_vm_set_free(result);

If you've already srtdup'ed some names when an error occurs, then
you're leaking this already strdup'ed names here.

> +                        return -1;
> +                    }
> +                   names[j++]=usenames;
> +               }
> +                xen_vm_record_free(record);
> +           } else {
> +                xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, "Couldn't get VM record");
> +                xen_vm_set_free(result);

And here you may leak already strdup'ed names too. you need to free
them in bot cases.

> +               return -1;
> +            }
> +       }
> +        doms=j;
> +        xen_vm_set_free(result);
> +        return doms;
> +    }
> +    xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, NULL);
> +    return -1;
> +}
> +


> +
> +/*
> +* call_func
> +* sets curl options, used with xen_session_login_with_password
> +*/
> +int
> +call_func(const void *data, size_t len, void *user_handle,
> +          void *result_handle, xen_result_func result_func)
> +{
> +    //(void)user_handle;
> +    struct _xenapiPrivate *priv = (struct _xenapiPrivate *)user_handle;
> +    #ifdef PRINT_XML
> +
> +        printf("\n\n---Data to server: -----------------------\n");
> +        printf("%s\n",((char*) data));
> +        fflush(stdout);
> +    #endif
> +    CURL *curl = curl_easy_init();
> +    if (!curl) {
> +      return -1;
> +    }
> +    xen_comms comms = {
> +     .func = result_func,
> +     .handle = result_handle
> +    };
> +    curl_easy_setopt(curl, CURLOPT_URL, priv->url);
> +    curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1);
> +    #ifdef CURLOPT_MUTE
> +        curl_easy_setopt(curl, CURLOPT_MUTE, 1);
> +    #endif
> +    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &write_func);
> +    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &comms);
> +    curl_easy_setopt(curl, CURLOPT_POST, 1);
> +    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data);
> +    curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, len);
> +    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, priv->SSLflag);
> +    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, priv->SSLflag);

You set SSLflag to 0 or 2 depending on the no_verify query parameter
in xenapiOpen. For CURLOPT_SSL_VERIFYHOST 2 is the correct value, but
CURLOPT_SSL_VERIFYPEER expects 0 or 1.

Instead of having the SSLflag in the xenapiPrivate struct you could
have the noVerify value there and then decide here to what values this
maps. For example

    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, priv->noVerify ? 0 : 1);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, priv->noVerify ? 0 : 2);

> +    CURLcode result = curl_easy_perform(curl);
> +    curl_easy_cleanup(curl);
> +    return result;
> +
> +}
> +
> +
> +
> diff -Nur ./libvirt_org/src/xenapi/xenapi_driver.h ./libvirt/src/xenapi/xenapi_driver.h
> --- ./libvirt_org/src/xenapi/xenapi_driver.h    1970-01-01 01:00:00.000000000 +0100
> +++ ./libvirt/src/xenapi/xenapi_driver.h        2010-02-26 13:21:50.000000000 +0000
> @@ -0,0 +1,15 @@
> +/*
> + * xenapi_driver.h.c: Xen API driver header file to be included in libvirt.c.
> + * Copyright (C) 2009 Citrix Ltd.
> + * Sharadha Prabhakar <sharadha.prabhakar at citrix.com>
> + */

As in xenapi_driver.c, a license statement is missing here.

> +
> +#ifndef __VIR_XENAPI_PRIV_H__
> +#define __VIR_XENAPI_PRIV_H__
> +
> +
> +extern int xenapiRegister (void);
> +
> +
> +#endif /* __VIR_XENAPI_PRIV_H__ */
> diff -Nur ./libvirt_org/src/xenapi/xenapi_driver_private.h ./libvirt/src/xenapi/xenapi_driver_private.h
> --- ./libvirt_org/src/xenapi/xenapi_driver_private.h    1970-01-01 01:00:00.000000000 +0100
> +++ ./libvirt/src/xenapi/xenapi_driver_private.h        2010-03-03 16:09:47.000000000 +0000
> @@ -0,0 +1,49 @@
> +/*
> + * xenapi_driver_private.h: Xen API driver's private header file.
> + * Copyright (C) 2009 Citrix Ltd.
> + * Sharadha Prabhakar <sharadha.prabhakar at citrix.com>
> + */

A license statement is missing here too.

> +
> +#ifndef __VIR_XENAPI_H__
> +#define __VIR_XENAPI_H__
> +
> +#include <xen/api/xen_common.h>
> +#include <libxml/tree.h>
> +#include "virterror_internal.h"
> +
> +//#define PRINT_XML
> +#define VIR_FROM_THIS VIR_FROM_XENAPI
> +#define LIBVIRT_MODELNAME_LEN  (32)
> +#define xenapiSessionErrorHandler(conn,errNum,buf) xenapiSessionErrorHandle(conn, errNum, \
> +                                                         buf,__FILE__,__FUNCTION__,__LINE__)
> +
> +void
> +xenapiSessionErrorHandle(virConnectPtr conn, virErrorNumber errNum,
> +                         const char *buf, const char *filename, const char *func, size_t lineno);
> +
> +typedef struct
> +{
> +    xen_result_func func;
> +    void *handle;
> +} xen_comms;
> +
> +
> +int
> +call_func(const void *data, size_t len, void *user_handle,
> +          void *result_handle, xen_result_func result_func);
> +size_t
> +write_func(void *ptr, size_t size, size_t nmemb, void *comms);
> +
> +/* xenAPI driver's private data structure */
> +struct _xenapiPrivate {
> +    xen_session *session;
> +    void *handle;
> +    char *uname;
> +    char *pwd;

I think handle, uname, and pwd are actually unused. If that's true you
could remove them from the struct.

> +    char *url;
> +    int SSLflag;
> +    virCapsPtr caps;
> +};
> +
> +#endif /* __VIR_XENAPI_H__ */
> diff -Nur ./libvirt_org/src/xenapi/xenapi_utils.c ./libvirt/src/xenapi/xenapi_utils.c
> --- ./libvirt_org/src/xenapi/xenapi_utils.c     1970-01-01 01:00:00.000000000 +0100
> +++ ./libvirt/src/xenapi/xenapi_utils.c 2010-03-03 18:01:06.000000000 +0000
> @@ -0,0 +1,578 @@
> +/*
> + * xenapi_utils.c: Xen API driver -- utils parts.
> + * Copyright (C) 2009 Citrix Ltd.
> + * Sharadha Prabhakar <sharadha.prabhakar at citrix.com>
> + */

A license statement is missing here too.

> +
> +/* obtains the CPU bitmap from the string passed */
> +void
> +getCpuBitMapfromString(char *mask, unsigned char *cpumap, int maplen)
> +{
> +    int pos;
> +    int max_bits = maplen * 8;
> +    char *num = NULL,*bp=NULL;
> +    bzero(cpumap, maplen);
> +    num = strtok_r (mask, ",", &bp);
> +    while (num != NULL) {
> +        if (sscanf (num, "%d", &pos)!=1)
> +            virReportOOMError();

It isn't an OOM error if sscanf fails.

> +        if (pos<0 || pos>max_bits-1)
> +            VIR_WARN ("number in str %d exceeds cpumap's max bits %d\n", pos, max_bits);

Do not append \n, that'll be done automatically.

> +        else
> +            (cpumap)[pos/8] |= (1<<(pos%8));
> +            num = strtok_r (NULL, ",", &bp);
> +    }
> +}
> +
> +


> +
> +/* allocate a flexible array and fill values(key,val) */
> +int
> +allocStringMap (xen_string_string_map **strings, char *key, char *val)
> +{
> +    int sz = ((*strings) == NULL)?0:(*strings)->size;
> +    sz++;
> +    if(VIR_REALLOC_N(*strings, sizeof(xen_string_string_map)+
> +                            sizeof(xen_string_string_map_contents)*sz)<0) {
> +        virReportOOMError();
> +        return -1;
> +    }
> +    (*strings)->size = sz;
> +    (*strings)->contents[sz-1].key = strdup(key);
> +    (*strings)->contents[sz-1].val = strdup(val);

You should check if strdup returned NULL.

> +    return 0;
> +}
> +
> +/* Error handling function returns error messages from the server if any */
> +void
> +xenapiSessionErrorHandle(virConnectPtr conn, virErrorNumber errNum,
> +                         const char *buf, const char *filename, const char *func, size_t lineno)
> +{
> +    if (buf==NULL) {
> +        char *ret=NULL;
> +        ret = returnErrorFromSession(((struct _xenapiPrivate *)(conn->privateData))->session);
> +        virReportErrorHelper (conn, VIR_FROM_XENAPI, errNum, filename, func, lineno, _("%s\n"), ret);
> +        xen_session_clear_error(((struct _xenapiPrivate *)(conn->privateData))->session);
> +        VIR_FREE(ret);
> +    } else {
> +        virReportErrorHelper (conn, VIR_FROM_XENAPI, errNum, filename, func, lineno, _("%s\n"), buf);
> +    }

No need to append \n here too.

> +}
> +


> +
> +/* Create a VM record from the XML description */
> +int
> +createVMRecordFromXml (virConnectPtr conn, virDomainDefPtr def,
> +                       xen_vm_record **record, xen_vm *vm)
> +{
> +    char uuidStr[VIR_UUID_STRING_BUFLEN];
> +    *record = xen_vm_record_alloc();
> +    if (!((*record)->name_label = strdup(def->name)))
> +        goto error_cleanup;
> +    if (def->uuid) {
> +        virUUIDFormat(def->uuid,uuidStr);
> +        if (!((*record)->uuid = strdup(uuidStr)))
> +            goto error_cleanup;
> +    }
> +    if (STREQ(def->os.type,"hvm")) {
> +        if(!((*record)->hvm_boot_policy = strdup("BIOS order")))
> +            goto error_cleanup;
> +         char *boot_order = NULL;
> +         if (def->os.nBootDevs!=0)
> +             boot_order = createXenAPIBootOrderString(def->os.nBootDevs, &def->os.bootDevs[0]);
> +         if (boot_order!=NULL) {
> +            xen_string_string_map *hvm_boot_params=NULL;
> +            allocStringMap(&hvm_boot_params, (char *)"order",boot_order);
> +             (*record)->hvm_boot_params = hvm_boot_params;
> +            VIR_FREE(boot_order);
> +         }
> +    } else if (STREQ(def->os.type,"xen")) {
> +        if (!((*record)->pv_bootloader = strdup("pygrub")))
> +            goto error_cleanup;
> +        if (def->os.kernel){
> +            if (!((*record)->pv_kernel = strdup(def->os.kernel)))
> +                goto error_cleanup;
> +        }
> +        if (def->os.initrd) {
> +           if (!((*record)->pv_ramdisk = strdup(def->os.initrd)))
> +                goto error_cleanup;
> +        }
> +        if(def->os.cmdline) {
> +            if (!((*record)->pv_args = strdup(def->os.cmdline)))
> +                goto error_cleanup;
> +        }
> +       (*record)->hvm_boot_params = xen_string_string_map_alloc(0);
> +    }
> +    if (def->os.bootloaderArgs)
> +        if(!((*record)->pv_bootloader_args = strdup(def->os.bootloaderArgs)))
> +            goto error_cleanup;
> +
> +    if (def->memory)
> +        (*record)->memory_static_max = (int64_t) (def->memory * 1024);
> +    if (def->maxmem)
> +        (*record)->memory_dynamic_max = (int64_t) (def->maxmem * 1024);
> +    else
> +        (*record)->memory_dynamic_max = (*record)->memory_static_max;
> +
> +    if (def->vcpus) {
> +        (*record)->vcpus_max = (int64_t) def->vcpus;
> +       (*record)->vcpus_at_startup = (int64_t) def->vcpus;
> +    }
> +    if (def->onPoweroff)
> +        (*record)->actions_after_shutdown = actionShutdownLibvirt2XenapiEnum(def->onPoweroff);
> +    if (def->onReboot)
> +        (*record)->actions_after_reboot = actionShutdownLibvirt2XenapiEnum(def->onReboot);
> +    if (def->onCrash)
> +        (*record)->actions_after_crash = actionCrashLibvirt2XenapiEnum(def->onCrash);
> +
> +    xen_string_string_map *strings=NULL;
> +    if (def->features) {
> +        if (def->features & (1<<VIR_DOMAIN_FEATURE_ACPI))
> +            allocStringMap(&strings,(char *)"acpi",(char *)"true");
> +        if (def->features & (1<<VIR_DOMAIN_FEATURE_APIC))
> +            allocStringMap(&strings,(char *)"apic",(char *)"true");
> +        if (def->features & (1<<VIR_DOMAIN_FEATURE_PAE))
> +            allocStringMap(&strings,(char *)"pae",(char *)"true");
> +    }
> +    if (strings!=NULL)
> +        (*record)->platform = strings;
> +
> +    (*record)->vcpus_params = xen_string_string_map_alloc(0);
> +    (*record)->other_config = xen_string_string_map_alloc(0);
> +    (*record)->last_boot_cpu_flags = xen_string_string_map_alloc(0);
> +    (*record)->xenstore_data = xen_string_string_map_alloc(0);
> +    (*record)->hvm_shadow_multiplier = 1.000;
> +    if (!xen_vm_create(((struct _xenapiPrivate *)(conn->privateData))->session,
> +                        vm, *record)) {
> +        xenapiSessionErrorHandler(conn,VIR_ERR_INTERNAL_ERROR,NULL);
> +        return -1;
> +    }
> +
> +    int device_number=0;
> +    char *bridge=NULL,*mac=NULL;
> +    int i;
> +    for (i=0;i<def->nnets;i++) {
> +        if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
> +            if (def->nets[i]->data.bridge.brname)
> +                if(!(bridge = strdup(def->nets[i]->data.bridge.brname)))
> +                    goto error_cleanup;
> +            if (def->nets[i]->mac) {
> +                char macStr[VIR_MAC_STRING_BUFLEN];
> +                virFormatMacAddr(def->nets[i]->mac, macStr);
> +                    if(!(mac = strdup(macStr))) {
> +                        if (bridge) VIR_FREE(bridge);
> +                        goto error_cleanup;
> +                    }
> +            }
> +            if (mac!=NULL && bridge!=NULL) {
> +                char device[NETWORK_DEVID_SIZE]="\0";

You defined NETWORK_DEVID_SIZE to be 10, but 10 is to small for an int
value. You need at least two more chars, one for a possible minus sign
and one for the null terminator.

> +                sprintf(device,"%d",device_number);
> +                createVifNetwork(conn, *vm, device, bridge, mac);
> +                VIR_FREE(bridge);
> +                device_number++;
> +            }
> +            if (bridge) VIR_FREE(bridge);
> +           /*if (mac!=NULL && bridge!=NULL) {
> +               char device[NETWORK_DEVID_SIZE]="\0";
> +               sprintf(device,"%d",device_number);
> +               if (createVifNetwork(conn, *vm, device, bridge, mac)<0) {
> +                    VIR_FREE(mac);
> +                    VIR_FREE(bridge);
> +                    xen_vm_record_free(*record);
> +                    xenapiSessionErrorHandler(conn,VIR_ERR_INTERNAL_ERROR,NULL);
> +                    return -1;
> +                }
> +               VIR_FREE(bridge);
> +               device_number++;
> +           } else {
> +                if (bridge)
> +                    VIR_FREE(bridge);
> +                if (mac)
> +                    VIR_FREE(mac);
> +                xen_vm_record_free(*record);
> +                xenapiSessionErrorHandler(conn,VIR_ERR_INTERNAL_ERROR,NULL);
> +                return -1;
> +            }*/
> +        }
> +    }
> +    return 0;
> +
> +  error_cleanup:
> +    virReportOOMError();
> +    xen_vm_record_free(*record);
> +    return -1;
> +}
> +
> diff -Nur ./libvirt_org/src/xenapi/xenapi_utils.h ./libvirt/src/xenapi/xenapi_utils.h
> --- ./libvirt_org/src/xenapi/xenapi_utils.h     1970-01-01 01:00:00.000000000 +0100
> +++ ./libvirt/src/xenapi/xenapi_utils.h 2010-03-03 18:01:19.000000000 +0000
> @@ -0,0 +1,93 @@
> +/*
> + * xenapi_utils.h: Xen API driver -- utils header
> + * Copyright (C) 2009 Citrix Ltd.
> + * Sharadha Prabhakar <sharadha.prabhakar at citrix.com>
> + */
> +

A license statement is missing here too.


> +
> +#define NETWORK_DEVID_SIZE  (10)
> +

Should be at least 12.

Another thing you probably should fix is the definition of varaibles
in the middle of blocks. Variables should be defined at the beginning
of a block.

Okay, mostly minor issues. I think the next version of this patch can
be applied and remaining issues can be fixed by additional patches.

Matthias




More information about the libvir-list mailing list