2014-03-06 12:08:36 +04:00
/*
* Copyright ( C ) 2014 SUSE LINUX Products GmbH , Nuernberg , Germany .
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2.1 of the License , or ( at your option ) any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library . If not , see
* < http : //www.gnu.org/licenses/>.
*
* Author : Chunyan Liu < cyliu @ suse . com >
*/
# include <config.h>
# include "testutils.h"
# ifdef __linux__
# include <stdlib.h>
# include <stdio.h>
# include <sys / types.h>
# include <sys / stat.h>
# include <sys / ioctl.h>
# include <fcntl.h>
# include "virlog.h"
# include "virhostdev.h"
# define VIR_FROM_THIS VIR_FROM_NONE
2014-02-28 16:16:17 +04:00
VIR_LOG_INIT ( " tests.hostdevtest " ) ;
2014-03-06 12:08:36 +04:00
# define CHECK_LIST_COUNT(list, cnt) \
if ( ( count = virPCIDeviceListCount ( list ) ) ! = cnt ) { \
virReportError ( VIR_ERR_INTERNAL_ERROR , \
" Unexpected count of items in " # list " : %d, " \
" expecting %zu " , count , ( size_t ) cnt ) ; \
goto cleanup ; \
}
# define TEST_STATE_DIR abs_builddir " / hostdevmgr"
static const char * drv_name = " test_driver " ;
static const char * dom_name = " test_domain " ;
static const unsigned char * uuid =
( unsigned char * ) ( " f92360b0-2541-8791-fb32-d1f838811541 " ) ;
static int nhostdevs = 3 ;
static virDomainHostdevDefPtr hostdevs [ ] = { NULL , NULL , NULL } ;
static virPCIDevicePtr dev [ ] = { NULL , NULL , NULL } ;
2014-10-28 21:38:04 +03:00
static virHostdevManagerPtr mgr ;
2014-03-06 12:08:36 +04:00
static void
myCleanup ( void )
{
size_t i ;
for ( i = 0 ; i < nhostdevs ; i + + ) {
virPCIDeviceFree ( dev [ i ] ) ;
virDomainHostdevDefFree ( hostdevs [ i ] ) ;
}
if ( mgr ) {
2015-09-15 23:33:36 +03:00
if ( ! getenv ( " LIBVIRT_SKIP_CLEANUP " ) )
2014-04-28 17:34:52 +04:00
virFileDeleteTree ( mgr - > stateDir ) ;
2014-03-06 12:08:36 +04:00
virObjectUnref ( mgr - > activePCIHostdevs ) ;
virObjectUnref ( mgr - > inactivePCIHostdevs ) ;
virObjectUnref ( mgr - > activeUSBHostdevs ) ;
VIR_FREE ( mgr - > stateDir ) ;
VIR_FREE ( mgr ) ;
}
}
static int
myInit ( void )
{
size_t i ;
for ( i = 0 ; i < nhostdevs ; i + + ) {
virDomainHostdevSubsys subsys ;
hostdevs [ i ] = virDomainHostdevDefAlloc ( ) ;
if ( ! hostdevs [ i ] )
goto cleanup ;
hostdevs [ i ] - > mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ;
subsys . type = VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI ;
subsys . u . pci . addr . domain = 0 ;
subsys . u . pci . addr . bus = 0 ;
subsys . u . pci . addr . slot = i + 1 ;
subsys . u . pci . addr . function = 0 ;
subsys . u . pci . backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM ;
hostdevs [ i ] - > source . subsys = subsys ;
}
for ( i = 0 ; i < nhostdevs ; i + + ) {
if ( ! ( dev [ i ] = virPCIDeviceNew ( 0 , 0 , i + 1 , 0 ) ) | |
virPCIDeviceSetStubDriver ( dev [ i ] , " pci-stub " ) < 0 )
goto cleanup ;
}
if ( VIR_ALLOC ( mgr ) < 0 )
goto cleanup ;
if ( ( mgr - > activePCIHostdevs = virPCIDeviceListNew ( ) ) = = NULL )
goto cleanup ;
if ( ( mgr - > activeUSBHostdevs = virUSBDeviceListNew ( ) ) = = NULL )
goto cleanup ;
if ( ( mgr - > inactivePCIHostdevs = virPCIDeviceListNew ( ) ) = = NULL )
goto cleanup ;
if ( ( mgr - > activeSCSIHostdevs = virSCSIDeviceListNew ( ) ) = = NULL )
goto cleanup ;
if ( VIR_STRDUP ( mgr - > stateDir , TEST_STATE_DIR ) < 0 )
goto cleanup ;
if ( virFileMakePath ( mgr - > stateDir ) < 0 )
goto cleanup ;
return 0 ;
2014-03-25 10:53:44 +04:00
cleanup :
2014-03-06 12:08:36 +04:00
myCleanup ( ) ;
return - 1 ;
}
# if HAVE_LINUX_KVM_H
# include <linux / kvm.h>
static bool
virHostdevHostSupportsPassthroughKVM ( void )
{
int kvmfd = - 1 ;
bool ret = false ;
if ( ( kvmfd = open ( " /dev/kvm " , O_RDONLY ) ) < 0 )
goto cleanup ;
# ifdef KVM_CAP_IOMMU
if ( ( ioctl ( kvmfd , KVM_CHECK_EXTENSION , KVM_CAP_IOMMU ) ) < = 0 )
goto cleanup ;
ret = true ;
# endif
2014-03-25 10:53:44 +04:00
cleanup :
2014-03-06 12:08:36 +04:00
VIR_FORCE_CLOSE ( kvmfd ) ;
return ret ;
}
# else
static bool
virHostdevHostSupportsPassthroughKVM ( void )
{
return false ;
}
# endif
static int
testVirHostdevPreparePCIHostdevs_unmanaged ( const void * oaque ATTRIBUTE_UNUSED )
{
int ret = - 1 ;
size_t i ;
int count , count1 , count2 ;
for ( i = 0 ; i < nhostdevs ; i + + )
hostdevs [ i ] - > managed = false ;
count1 = virPCIDeviceListCount ( mgr - > activePCIHostdevs ) ;
count2 = virPCIDeviceListCount ( mgr - > inactivePCIHostdevs ) ;
/* Test normal functionality */
2015-10-27 21:14:01 +03:00
VIR_DEBUG ( " Test 0 hostdevs " ) ;
2014-03-06 12:08:36 +04:00
if ( virHostdevPreparePCIDevices ( mgr , drv_name , dom_name , uuid ,
NULL , 0 , 0 ) < 0 )
goto cleanup ;
CHECK_LIST_COUNT ( mgr - > activePCIHostdevs , count1 ) ;
/* Test unmanaged hostdevs */
2015-10-27 21:14:01 +03:00
VIR_DEBUG ( " Test >=1 unmanaged hostdevs " ) ;
2014-03-06 12:08:36 +04:00
if ( virHostdevPreparePCIDevices ( mgr , drv_name , dom_name , uuid ,
hostdevs , nhostdevs , 0 ) < 0 )
goto cleanup ;
CHECK_LIST_COUNT ( mgr - > activePCIHostdevs , count1 + 3 ) ;
CHECK_LIST_COUNT ( mgr - > inactivePCIHostdevs , count2 - 3 ) ;
/* Test conflict */
count1 = virPCIDeviceListCount ( mgr - > activePCIHostdevs ) ;
count2 = virPCIDeviceListCount ( mgr - > inactivePCIHostdevs ) ;
2015-10-27 21:14:01 +03:00
VIR_DEBUG ( " Test: prepare same hostdevs for same driver/domain again " ) ;
2014-03-06 12:08:36 +04:00
if ( ! virHostdevPreparePCIDevices ( mgr , drv_name , dom_name , uuid ,
& hostdevs [ 0 ] , 1 , 0 ) )
goto cleanup ;
CHECK_LIST_COUNT ( mgr - > activePCIHostdevs , count1 ) ;
CHECK_LIST_COUNT ( mgr - > inactivePCIHostdevs , count2 ) ;
2015-10-27 21:14:01 +03:00
VIR_DEBUG ( " Test: prepare same hostdevs for same driver, diff domain again " ) ;
2014-03-06 12:08:36 +04:00
if ( ! virHostdevPreparePCIDevices ( mgr , drv_name , " test_domain1 " , uuid ,
& hostdevs [ 1 ] , 1 , 0 ) )
goto cleanup ;
CHECK_LIST_COUNT ( mgr - > activePCIHostdevs , count1 ) ;
CHECK_LIST_COUNT ( mgr - > inactivePCIHostdevs , count2 ) ;
2015-10-27 21:14:01 +03:00
VIR_DEBUG ( " Test: prepare same hostdevs for diff driver/domain again " ) ;
2014-03-06 12:08:36 +04:00
if ( ! virHostdevPreparePCIDevices ( mgr , " test_driver1 " , dom_name , uuid ,
& hostdevs [ 2 ] , 1 , 0 ) )
goto cleanup ;
CHECK_LIST_COUNT ( mgr - > activePCIHostdevs , count1 ) ;
CHECK_LIST_COUNT ( mgr - > inactivePCIHostdevs , count2 ) ;
ret = 0 ;
2014-03-25 10:53:44 +04:00
cleanup :
2014-03-06 12:08:36 +04:00
return ret ;
}
static int
testVirHostdevReAttachPCIHostdevs_unmanaged ( const void * oaque ATTRIBUTE_UNUSED )
{
int ret = - 1 ;
size_t i ;
int count , count1 , count2 ;
for ( i = 0 ; i < nhostdevs ; i + + ) {
if ( hostdevs [ i ] - > managed ! = false ) {
2015-10-27 21:14:01 +03:00
VIR_DEBUG ( " invalid test " ) ;
2014-03-06 12:08:36 +04:00
return - 1 ;
}
}
count1 = virPCIDeviceListCount ( mgr - > activePCIHostdevs ) ;
count2 = virPCIDeviceListCount ( mgr - > inactivePCIHostdevs ) ;
2015-10-27 21:14:01 +03:00
VIR_DEBUG ( " Test 0 hostdevs " ) ;
2014-03-06 12:08:36 +04:00
virHostdevReAttachPCIDevices ( mgr , drv_name , dom_name , NULL , 0 , NULL ) ;
CHECK_LIST_COUNT ( mgr - > activePCIHostdevs , count1 ) ;
2015-10-27 21:14:01 +03:00
VIR_DEBUG ( " Test >=1 unmanaged hostdevs " ) ;
2014-03-06 12:08:36 +04:00
virHostdevReAttachPCIDevices ( mgr , drv_name , dom_name ,
hostdevs , nhostdevs , NULL ) ;
CHECK_LIST_COUNT ( mgr - > activePCIHostdevs , count1 - 3 ) ;
CHECK_LIST_COUNT ( mgr - > inactivePCIHostdevs , count2 + 3 ) ;
ret = 0 ;
2014-03-25 10:53:44 +04:00
cleanup :
2014-03-06 12:08:36 +04:00
return ret ;
}
static int
testVirHostdevPreparePCIHostdevs_managed ( const void * oaque ATTRIBUTE_UNUSED )
{
int ret = - 1 ;
size_t i ;
int count , count1 ;
for ( i = 0 ; i < nhostdevs ; i + + )
hostdevs [ i ] - > managed = true ;
count1 = virPCIDeviceListCount ( mgr - > activePCIHostdevs ) ;
/* Test normal functionality */
2015-10-27 21:14:01 +03:00
VIR_DEBUG ( " Test >=1 hostdevs " ) ;
2014-03-06 12:08:36 +04:00
if ( virHostdevPreparePCIDevices ( mgr , drv_name , dom_name , uuid ,
hostdevs , nhostdevs , 0 ) < 0 )
goto cleanup ;
CHECK_LIST_COUNT ( mgr - > activePCIHostdevs , count1 + 3 ) ;
/* Test conflict */
count1 = virPCIDeviceListCount ( mgr - > activePCIHostdevs ) ;
2015-10-27 21:14:01 +03:00
VIR_DEBUG ( " Test: prepare same hostdevs for same driver/domain again " ) ;
2014-03-06 12:08:36 +04:00
if ( ! virHostdevPreparePCIDevices ( mgr , drv_name , dom_name , uuid ,
& hostdevs [ 0 ] , 1 , 0 ) )
goto cleanup ;
CHECK_LIST_COUNT ( mgr - > activePCIHostdevs , count1 ) ;
2015-10-27 21:14:01 +03:00
VIR_DEBUG ( " Test: prepare same hostdevs for same driver, diff domain again " ) ;
2014-03-06 12:08:36 +04:00
if ( ! virHostdevPreparePCIDevices ( mgr , drv_name , " test_domain1 " , uuid ,
& hostdevs [ 1 ] , 1 , 0 ) )
goto cleanup ;
CHECK_LIST_COUNT ( mgr - > activePCIHostdevs , count1 ) ;
2015-10-27 21:14:01 +03:00
VIR_DEBUG ( " Test: prepare same hostdevs for diff driver/domain again " ) ;
2014-03-06 12:08:36 +04:00
if ( ! virHostdevPreparePCIDevices ( mgr , " test_driver1 " , dom_name , uuid ,
& hostdevs [ 2 ] , 1 , 0 ) )
goto cleanup ;
CHECK_LIST_COUNT ( mgr - > activePCIHostdevs , count1 ) ;
ret = 0 ;
2014-03-25 10:53:44 +04:00
cleanup :
2014-03-06 12:08:36 +04:00
return ret ;
}
static int
testVirHostdevReAttachPCIHostdevs_managed ( const void * oaque ATTRIBUTE_UNUSED )
{
int ret = - 1 ;
size_t i ;
int count , count1 ;
for ( i = 0 ; i < nhostdevs ; i + + ) {
if ( hostdevs [ i ] - > managed ! = true ) {
2015-10-27 21:14:01 +03:00
VIR_DEBUG ( " invalid test " ) ;
2014-03-06 12:08:36 +04:00
return - 1 ;
}
}
count1 = virPCIDeviceListCount ( mgr - > activePCIHostdevs ) ;
2015-10-27 21:14:01 +03:00
VIR_DEBUG ( " Test 0 hostdevs " ) ;
2014-03-06 12:08:36 +04:00
virHostdevReAttachPCIDevices ( mgr , drv_name , dom_name , NULL , 0 , NULL ) ;
CHECK_LIST_COUNT ( mgr - > activePCIHostdevs , count1 ) ;
2015-10-27 21:14:01 +03:00
VIR_DEBUG ( " Test >=1 hostdevs " ) ;
2014-03-06 12:08:36 +04:00
virHostdevReAttachPCIDevices ( mgr , drv_name , dom_name ,
hostdevs , nhostdevs , NULL ) ;
CHECK_LIST_COUNT ( mgr - > activePCIHostdevs , count1 - 3 ) ;
ret = 0 ;
2014-03-25 10:53:44 +04:00
cleanup :
2014-03-06 12:08:36 +04:00
return ret ;
}
static int
testVirHostdevDetachPCINodeDevice ( const void * oaque ATTRIBUTE_UNUSED )
{
int ret = - 1 ;
size_t i ;
int count , count1 ;
for ( i = 0 ; i < nhostdevs ; i + + ) {
count1 = virPCIDeviceListCount ( mgr - > inactivePCIHostdevs ) ;
if ( virHostdevPCINodeDeviceDetach ( mgr , dev [ i ] ) < 0 )
goto cleanup ;
CHECK_LIST_COUNT ( mgr - > inactivePCIHostdevs , count1 + 1 ) ;
}
ret = 0 ;
2014-03-25 10:53:44 +04:00
cleanup :
2014-03-06 12:08:36 +04:00
return ret ;
}
static int
testVirHostdevResetPCINodeDevice ( const void * oaque ATTRIBUTE_UNUSED )
{
int ret = - 1 ;
size_t i ;
for ( i = 0 ; i < nhostdevs ; i + + ) {
if ( virHostdevPCINodeDeviceReset ( mgr , dev [ i ] ) < 0 )
goto cleanup ;
}
ret = 0 ;
2014-03-25 10:53:44 +04:00
cleanup :
2014-03-06 12:08:36 +04:00
return ret ;
}
static int
testVirHostdevReAttachPCINodeDevice ( const void * oaque ATTRIBUTE_UNUSED )
{
int ret = - 1 ;
size_t i ;
int count , count1 ;
for ( i = 0 ; i < nhostdevs ; i + + ) {
count1 = virPCIDeviceListCount ( mgr - > inactivePCIHostdevs ) ;
if ( virHostdevPCINodeDeviceReAttach ( mgr , dev [ i ] ) < 0 )
goto cleanup ;
CHECK_LIST_COUNT ( mgr - > inactivePCIHostdevs , count1 - 1 ) ;
}
ret = 0 ;
2014-03-25 10:53:44 +04:00
cleanup :
2014-03-06 12:08:36 +04:00
return ret ;
}
static int
testVirHostdevUpdateActivePCIHostdevs ( const void * oaque ATTRIBUTE_UNUSED )
{
int ret = - 1 ;
int count , count1 ;
count1 = virPCIDeviceListCount ( mgr - > activePCIHostdevs ) ;
2015-10-27 21:14:01 +03:00
VIR_DEBUG ( " Test 0 hostdevs " ) ;
2014-03-06 12:08:36 +04:00
if ( virHostdevUpdateActivePCIDevices ( mgr , NULL , 0 ,
drv_name , dom_name ) < 0 )
goto cleanup ;
CHECK_LIST_COUNT ( mgr - > activePCIHostdevs , count1 ) ;
2015-10-27 21:14:01 +03:00
VIR_DEBUG ( " Test >=1 hostdevs " ) ;
2014-03-06 12:08:36 +04:00
if ( virHostdevUpdateActivePCIDevices ( mgr , hostdevs , nhostdevs ,
drv_name , dom_name ) < 0 )
goto cleanup ;
CHECK_LIST_COUNT ( mgr - > activePCIHostdevs , count1 + 3 ) ;
ret = 0 ;
2014-03-25 10:53:44 +04:00
cleanup :
2014-03-06 12:08:36 +04:00
return ret ;
}
2015-12-04 15:38:16 +03:00
# define FAKEROOTDIRTEMPLATE abs_builddir " / fakerootdir-XXXXXX"
2014-03-06 12:08:36 +04:00
static int
mymain ( void )
{
int ret = 0 ;
2015-12-04 15:38:16 +03:00
char * fakerootdir ;
2014-03-06 12:08:36 +04:00
2015-12-04 15:38:16 +03:00
if ( VIR_STRDUP_QUIET ( fakerootdir , FAKEROOTDIRTEMPLATE ) < 0 ) {
2014-03-06 12:08:36 +04:00
fprintf ( stderr , " Out of memory \n " ) ;
abort ( ) ;
}
2015-12-04 15:38:16 +03:00
if ( ! mkdtemp ( fakerootdir ) ) {
fprintf ( stderr , " Cannot create fakerootdir " ) ;
2014-03-06 12:08:36 +04:00
abort ( ) ;
}
2015-12-04 15:38:16 +03:00
setenv ( " LIBVIRT_FAKE_ROOT_DIR " , fakerootdir , 1 ) ;
2014-03-06 12:08:36 +04:00
# define DO_TEST(fnc) \
do { \
2015-10-27 21:14:01 +03:00
VIR_DEBUG ( " Testing: %s " , # fnc ) ; \
2014-03-06 12:08:36 +04:00
if ( virtTestRun ( # fnc , fnc , NULL ) < 0 ) \
ret = - 1 ; \
} while ( 0 )
if ( myInit ( ) < 0 )
fprintf ( stderr , " Init data structures failed. " ) ;
DO_TEST ( testVirHostdevDetachPCINodeDevice ) ;
if ( virHostdevHostSupportsPassthroughKVM ( ) ) {
/* following tests would check KVM support */
DO_TEST ( testVirHostdevPreparePCIHostdevs_unmanaged ) ;
DO_TEST ( testVirHostdevReAttachPCIHostdevs_unmanaged ) ;
}
DO_TEST ( testVirHostdevResetPCINodeDevice ) ;
DO_TEST ( testVirHostdevReAttachPCINodeDevice ) ;
if ( virHostdevHostSupportsPassthroughKVM ( ) ) {
/* following tests would check KVM support */
DO_TEST ( testVirHostdevPreparePCIHostdevs_managed ) ;
DO_TEST ( testVirHostdevReAttachPCIHostdevs_managed ) ;
}
DO_TEST ( testVirHostdevUpdateActivePCIHostdevs ) ;
myCleanup ( ) ;
if ( getenv ( " LIBVIRT_SKIP_CLEANUP " ) = = NULL )
2015-12-04 15:38:16 +03:00
virFileDeleteTree ( fakerootdir ) ;
2014-03-06 12:08:36 +04:00
2015-12-04 15:38:16 +03:00
VIR_FREE ( fakerootdir ) ;
2014-03-06 12:08:36 +04:00
2014-03-17 13:38:38 +04:00
return ret = = 0 ? EXIT_SUCCESS : EXIT_FAILURE ;
2014-03-06 12:08:36 +04:00
}
VIRT_TEST_MAIN_PRELOAD ( mymain , abs_builddir " /.libs/virpcimock.so " )
# else
int
main ( void )
{
return EXIT_AM_SKIP ;
}
# endif