2013-10-23 17:44:40 +04:00
/*
2014-03-17 13:38:38 +04:00
* Copyright ( C ) 2013 , 2014 Red Hat , Inc .
2013-10-23 17:44:40 +04:00
*
* 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 : Michal Privoznik < mprivozn @ redhat . com >
*/
# include <config.h>
# include "testutils.h"
# ifdef __linux__
# include <stdlib.h>
# include <stdio.h>
# include <sys / types.h>
# include <sys / stat.h>
# include <fcntl.h>
# include <virpci.h>
# define VIR_FROM_THIS VIR_FROM_NONE
2014-01-15 13:20:55 +04:00
static int
testVirPCIDeviceCheckDriver ( virPCIDevicePtr dev , const char * expected )
{
char * path = NULL ;
char * driver = NULL ;
int ret = - 1 ;
if ( virPCIDeviceGetDriverPathAndName ( dev , & path , & driver ) < 0 )
goto cleanup ;
if ( STRNEQ_NULLABLE ( driver , expected ) ) {
virReportError ( VIR_ERR_INTERNAL_ERROR ,
" PCI device %s driver mismatch: %s, expecting %s " ,
virPCIDeviceGetName ( dev ) , NULLSTR ( driver ) ,
NULLSTR ( expected ) ) ;
goto cleanup ;
}
ret = 0 ;
2014-03-25 10:53:44 +04:00
cleanup :
2014-01-15 13:20:55 +04:00
VIR_FREE ( path ) ;
VIR_FREE ( driver ) ;
return ret ;
}
2013-10-23 17:44:40 +04:00
static int
testVirPCIDeviceNew ( const void * opaque ATTRIBUTE_UNUSED )
{
int ret = - 1 ;
virPCIDevicePtr dev ;
const char * devName ;
if ( ! ( dev = virPCIDeviceNew ( 0 , 0 , 0 , 0 ) ) )
goto cleanup ;
devName = virPCIDeviceGetName ( dev ) ;
if ( STRNEQ ( devName , " 0000:00:00.0 " ) ) {
virReportError ( VIR_ERR_INTERNAL_ERROR ,
" PCI device name mismatch: %s, expecting %s " ,
devName , " 0000:00:00.0 " ) ;
goto cleanup ;
}
ret = 0 ;
2014-03-25 10:53:44 +04:00
cleanup :
2013-10-23 17:44:40 +04:00
virPCIDeviceFree ( dev ) ;
return ret ;
}
2013-10-23 19:55:02 +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, " \
2013-11-05 18:07:49 +04:00
" expecting %zu " , count , ( size_t ) cnt ) ; \
2013-10-23 19:55:02 +04:00
goto cleanup ; \
}
static int
testVirPCIDeviceDetach ( const void * oaque ATTRIBUTE_UNUSED )
{
int ret = - 1 ;
2013-11-05 18:07:49 +04:00
virPCIDevicePtr dev [ ] = { NULL , NULL , NULL } ;
size_t i , nDev = ARRAY_CARDINALITY ( dev ) ;
2013-10-23 19:55:02 +04:00
virPCIDeviceListPtr activeDevs = NULL , inactiveDevs = NULL ;
int count ;
2013-11-05 18:07:49 +04:00
if ( ! ( activeDevs = virPCIDeviceListNew ( ) ) | |
2013-10-23 19:55:02 +04:00
! ( inactiveDevs = virPCIDeviceListNew ( ) ) )
goto cleanup ;
CHECK_LIST_COUNT ( activeDevs , 0 ) ;
CHECK_LIST_COUNT ( inactiveDevs , 0 ) ;
2013-11-05 18:07:49 +04:00
for ( i = 0 ; i < nDev ; i + + ) {
if ( ! ( dev [ i ] = virPCIDeviceNew ( 0 , 0 , i + 1 , 0 ) ) | |
virPCIDeviceSetStubDriver ( dev [ i ] , " pci-stub " ) < 0 )
goto cleanup ;
2013-10-23 19:55:02 +04:00
2013-11-05 18:07:49 +04:00
if ( virPCIDeviceDetach ( dev [ i ] , activeDevs , inactiveDevs ) < 0 )
goto cleanup ;
2013-10-23 19:55:02 +04:00
2014-01-15 13:20:55 +04:00
if ( testVirPCIDeviceCheckDriver ( dev [ i ] , " pci-stub " ) < 0 )
goto cleanup ;
2013-11-05 18:07:49 +04:00
CHECK_LIST_COUNT ( activeDevs , 0 ) ;
CHECK_LIST_COUNT ( inactiveDevs , i + 1 ) ;
}
ret = 0 ;
2014-03-25 10:53:44 +04:00
cleanup :
2013-11-05 18:07:49 +04:00
for ( i = 0 ; i < nDev ; i + + )
virPCIDeviceFree ( dev [ i ] ) ;
virObjectUnref ( activeDevs ) ;
virObjectUnref ( inactiveDevs ) ;
return ret ;
}
2013-10-23 19:55:02 +04:00
2013-11-05 18:07:49 +04:00
static int
testVirPCIDeviceReset ( const void * opaque ATTRIBUTE_UNUSED )
{
int ret = - 1 ;
virPCIDevicePtr dev [ ] = { NULL , NULL , NULL } ;
size_t i , nDev = ARRAY_CARDINALITY ( dev ) ;
virPCIDeviceListPtr activeDevs = NULL , inactiveDevs = NULL ;
int count ;
if ( ! ( activeDevs = virPCIDeviceListNew ( ) ) | |
! ( inactiveDevs = virPCIDeviceListNew ( ) ) )
2013-10-31 15:05:20 +04:00
goto cleanup ;
CHECK_LIST_COUNT ( activeDevs , 0 ) ;
2013-11-05 18:07:49 +04:00
CHECK_LIST_COUNT ( inactiveDevs , 0 ) ;
for ( i = 0 ; i < nDev ; i + + ) {
if ( ! ( dev [ i ] = virPCIDeviceNew ( 0 , 0 , i + 1 , 0 ) ) | |
virPCIDeviceSetStubDriver ( dev [ i ] , " pci-stub " ) < 0 )
goto cleanup ;
if ( virPCIDeviceReset ( dev [ i ] , activeDevs , inactiveDevs ) < 0 )
goto cleanup ;
}
2013-10-31 15:05:20 +04:00
2013-10-23 19:55:02 +04:00
ret = 0 ;
2014-03-25 10:53:44 +04:00
cleanup :
2013-11-05 18:07:49 +04:00
for ( i = 0 ; i < nDev ; i + + )
virPCIDeviceFree ( dev [ i ] ) ;
2013-10-23 19:55:02 +04:00
virObjectUnref ( activeDevs ) ;
virObjectUnref ( inactiveDevs ) ;
return ret ;
}
2013-10-31 14:57:56 +04:00
static int
2013-11-05 18:07:49 +04:00
testVirPCIDeviceReattach ( const void * opaque ATTRIBUTE_UNUSED )
2013-10-31 14:57:56 +04:00
{
int ret = - 1 ;
2013-11-05 18:07:49 +04:00
virPCIDevicePtr dev [ ] = { NULL , NULL , NULL } ;
size_t i , nDev = ARRAY_CARDINALITY ( dev ) ;
2013-10-31 14:57:56 +04:00
virPCIDeviceListPtr activeDevs = NULL , inactiveDevs = NULL ;
int count ;
2013-11-05 18:07:49 +04:00
if ( ! ( activeDevs = virPCIDeviceListNew ( ) ) | |
2013-10-31 14:57:56 +04:00
! ( inactiveDevs = virPCIDeviceListNew ( ) ) )
goto cleanup ;
2013-11-05 18:07:49 +04:00
for ( i = 0 ; i < nDev ; i + + ) {
if ( ! ( dev [ i ] = virPCIDeviceNew ( 0 , 0 , i + 1 , 0 ) ) )
goto cleanup ;
2013-10-31 14:57:56 +04:00
2013-11-05 18:07:49 +04:00
if ( virPCIDeviceListAdd ( inactiveDevs , dev [ i ] ) < 0 ) {
virPCIDeviceFree ( dev [ i ] ) ;
goto cleanup ;
}
2013-10-31 14:57:56 +04:00
2013-11-05 18:07:49 +04:00
CHECK_LIST_COUNT ( activeDevs , 0 ) ;
CHECK_LIST_COUNT ( inactiveDevs , i + 1 ) ;
2013-10-31 14:57:56 +04:00
2013-11-05 18:07:49 +04:00
if ( virPCIDeviceSetStubDriver ( dev [ i ] , " pci-stub " ) < 0 )
goto cleanup ;
}
2013-10-31 14:57:56 +04:00
2013-10-31 15:05:20 +04:00
CHECK_LIST_COUNT ( activeDevs , 0 ) ;
2013-11-05 18:07:49 +04:00
CHECK_LIST_COUNT ( inactiveDevs , nDev ) ;
2013-10-31 15:05:20 +04:00
2013-11-05 18:07:49 +04:00
for ( i = 0 ; i < nDev ; i + + ) {
if ( virPCIDeviceReattach ( dev [ i ] , activeDevs , inactiveDevs ) < 0 )
goto cleanup ;
2013-10-31 15:05:20 +04:00
2013-11-05 18:07:49 +04:00
CHECK_LIST_COUNT ( activeDevs , 0 ) ;
CHECK_LIST_COUNT ( inactiveDevs , nDev - i - 1 ) ;
}
2013-10-31 14:57:56 +04:00
ret = 0 ;
2014-03-25 10:53:44 +04:00
cleanup :
2013-10-31 14:57:56 +04:00
virObjectUnref ( activeDevs ) ;
virObjectUnref ( inactiveDevs ) ;
return ret ;
}
2013-11-05 18:07:49 +04:00
2013-12-24 22:07:27 +04:00
struct testPCIDevData {
unsigned int domain ;
unsigned int bus ;
unsigned int slot ;
unsigned int function ;
2014-01-15 13:20:55 +04:00
const char * driver ;
2013-12-24 22:07:27 +04:00
} ;
static int
testVirPCIDeviceIsAssignable ( const void * opaque )
{
const struct testPCIDevData * data = opaque ;
int ret = - 1 ;
virPCIDevicePtr dev ;
if ( ! ( dev = virPCIDeviceNew ( data - > domain , data - > bus , data - > slot , data - > function ) ) )
goto cleanup ;
if ( virPCIDeviceIsAssignable ( dev , true ) )
ret = 0 ;
virPCIDeviceFree ( dev ) ;
2014-03-25 10:53:44 +04:00
cleanup :
2013-12-24 22:07:27 +04:00
return ret ;
}
2014-01-15 13:20:55 +04:00
static int
testVirPCIDeviceDetachSingle ( const void * opaque )
{
const struct testPCIDevData * data = opaque ;
int ret = - 1 ;
virPCIDevicePtr dev ;
dev = virPCIDeviceNew ( data - > domain , data - > bus , data - > slot , data - > function ) ;
if ( ! dev )
goto cleanup ;
if ( virPCIDeviceSetStubDriver ( dev , " pci-stub " ) < 0 | |
virPCIDeviceDetach ( dev , NULL , NULL ) < 0 )
goto cleanup ;
ret = 0 ;
2014-03-25 10:53:44 +04:00
cleanup :
2014-01-15 13:20:55 +04:00
virPCIDeviceFree ( dev ) ;
return ret ;
}
2014-01-16 17:06:22 +04:00
static int
testVirPCIDeviceDetachFail ( const void * opaque )
{
const struct testPCIDevData * data = opaque ;
int ret = - 1 ;
virPCIDevicePtr dev ;
dev = virPCIDeviceNew ( data - > domain , data - > bus , data - > slot , data - > function ) ;
if ( ! dev )
goto cleanup ;
if ( virPCIDeviceSetStubDriver ( dev , " vfio-pci " ) < 0 )
goto cleanup ;
if ( virPCIDeviceDetach ( dev , NULL , NULL ) < 0 ) {
if ( virTestGetVerbose ( ) | | virTestGetDebug ( ) )
virDispatchError ( NULL ) ;
virResetLastError ( ) ;
ret = 0 ;
} else {
virReportError ( VIR_ERR_INTERNAL_ERROR ,
" Attaching device %s to %s should have failed " ,
virPCIDeviceGetName ( dev ) ,
virPCIDeviceGetStubDriver ( dev ) ) ;
}
2014-03-25 10:53:44 +04:00
cleanup :
2014-01-16 17:06:22 +04:00
virPCIDeviceFree ( dev ) ;
return ret ;
}
2014-01-15 13:20:55 +04:00
static int
testVirPCIDeviceReattachSingle ( const void * opaque )
{
const struct testPCIDevData * data = opaque ;
int ret = - 1 ;
virPCIDevicePtr dev ;
dev = virPCIDeviceNew ( data - > domain , data - > bus , data - > slot , data - > function ) ;
if ( ! dev )
goto cleanup ;
virPCIDeviceReattachInit ( dev ) ;
if ( virPCIDeviceReattach ( dev , NULL , NULL ) < 0 )
goto cleanup ;
ret = 0 ;
2014-03-25 10:53:44 +04:00
cleanup :
2014-01-15 13:20:55 +04:00
virPCIDeviceFree ( dev ) ;
return ret ;
}
static int
testVirPCIDeviceCheckDriverTest ( const void * opaque )
{
const struct testPCIDevData * data = opaque ;
int ret = - 1 ;
virPCIDevicePtr dev ;
dev = virPCIDeviceNew ( data - > domain , data - > bus , data - > slot , data - > function ) ;
if ( ! dev )
goto cleanup ;
if ( testVirPCIDeviceCheckDriver ( dev , data - > driver ) < 0 )
goto cleanup ;
ret = 0 ;
2014-03-25 10:53:44 +04:00
cleanup :
2014-01-15 13:20:55 +04:00
virPCIDeviceFree ( dev ) ;
return ret ;
}
static int
testVirPCIDeviceUnbind ( const void * opaque )
{
const struct testPCIDevData * data = opaque ;
int ret = - 1 ;
virPCIDevicePtr dev ;
dev = virPCIDeviceNew ( data - > domain , data - > bus , data - > slot , data - > function ) ;
if ( ! dev )
goto cleanup ;
if ( virPCIDeviceUnbind ( dev , false ) < 0 )
goto cleanup ;
ret = 0 ;
2014-03-25 10:53:44 +04:00
cleanup :
2014-01-15 13:20:55 +04:00
virPCIDeviceFree ( dev ) ;
return ret ;
}
2013-11-05 18:07:49 +04:00
# define FAKESYSFSDIRTEMPLATE abs_builddir " / fakesysfsdir-XXXXXX"
2013-10-23 17:44:40 +04:00
static int
mymain ( void )
{
int ret = 0 ;
char * fakesysfsdir ;
if ( VIR_STRDUP_QUIET ( fakesysfsdir , FAKESYSFSDIRTEMPLATE ) < 0 ) {
2015-04-23 20:38:00 +03:00
VIR_TEST_DEBUG ( " Out of memory \n " ) ;
2013-10-23 17:44:40 +04:00
abort ( ) ;
}
if ( ! mkdtemp ( fakesysfsdir ) ) {
2015-04-23 20:38:00 +03:00
VIR_TEST_DEBUG ( " Cannot create fakesysfsdir " ) ;
2013-10-23 17:44:40 +04:00
abort ( ) ;
}
setenv ( " LIBVIRT_FAKE_SYSFS_DIR " , fakesysfsdir , 1 ) ;
# define DO_TEST(fnc) \
do { \
if ( virtTestRun ( # fnc , fnc , NULL ) < 0 ) \
ret = - 1 ; \
} while ( 0 )
2013-12-24 22:07:27 +04:00
# define DO_TEST_PCI(fnc, domain, bus, slot, function) \
do { \
2014-01-15 13:20:55 +04:00
struct testPCIDevData data = { \
domain , bus , slot , function , NULL \
} ; \
2014-01-14 17:59:37 +04:00
char * label = NULL ; \
if ( virAsprintf ( & label , " %s(%04x:%02x:%02x.%x) " , \
# fnc, domain, bus, slot, function) < 0) { \
2013-12-24 22:07:27 +04:00
ret = - 1 ; \
2014-01-14 17:59:37 +04:00
break ; \
} \
if ( virtTestRun ( label , fnc , & data ) < 0 ) \
ret = - 1 ; \
VIR_FREE ( label ) ; \
2013-12-24 22:07:27 +04:00
} while ( 0 )
2014-01-15 13:20:55 +04:00
# define DO_TEST_PCI_DRIVER(domain, bus, slot, function, driver) \
do { \
struct testPCIDevData data = { \
domain , bus , slot , function , driver \
} ; \
char * label = NULL ; \
if ( virAsprintf ( & label , " PCI driver %04x:%02x:%02x.%x is %s " , \
domain , bus , slot , function , \
NULLSTR ( driver ) ) < 0 ) { \
ret = - 1 ; \
break ; \
} \
if ( virtTestRun ( label , testVirPCIDeviceCheckDriverTest , \
& data ) < 0 ) \
ret = - 1 ; \
VIR_FREE ( label ) ; \
} while ( 0 )
/* Changes made to individual devices are persistent and the
* tests often rely on the state set by previous tests .
*/
2013-10-23 17:44:40 +04:00
DO_TEST ( testVirPCIDeviceNew ) ;
2013-10-23 19:55:02 +04:00
DO_TEST ( testVirPCIDeviceDetach ) ;
2013-11-05 18:07:49 +04:00
DO_TEST ( testVirPCIDeviceReset ) ;
2013-10-31 14:57:56 +04:00
DO_TEST ( testVirPCIDeviceReattach ) ;
2013-12-24 22:07:27 +04:00
DO_TEST_PCI ( testVirPCIDeviceIsAssignable , 5 , 0x90 , 1 , 0 ) ;
DO_TEST_PCI ( testVirPCIDeviceIsAssignable , 1 , 1 , 0 , 0 ) ;
2013-10-23 17:44:40 +04:00
2014-01-16 17:06:22 +04:00
DO_TEST_PCI ( testVirPCIDeviceDetachFail , 0 , 0x0a , 1 , 0 ) ;
2014-01-15 13:20:55 +04:00
/* Reattach a device already bound to non-stub a driver */
DO_TEST_PCI_DRIVER ( 0 , 0x0a , 1 , 0 , " i915 " ) ;
DO_TEST_PCI ( testVirPCIDeviceReattachSingle , 0 , 0x0a , 1 , 0 ) ;
DO_TEST_PCI_DRIVER ( 0 , 0x0a , 1 , 0 , " i915 " ) ;
/* Reattach an unbound device */
DO_TEST_PCI ( testVirPCIDeviceUnbind , 0 , 0x0a , 1 , 0 ) ;
DO_TEST_PCI_DRIVER ( 0 , 0x0a , 1 , 0 , NULL ) ;
DO_TEST_PCI ( testVirPCIDeviceReattachSingle , 0 , 0x0a , 1 , 0 ) ;
DO_TEST_PCI_DRIVER ( 0 , 0x0a , 1 , 0 , " i915 " ) ;
/* Detach an unbound device */
DO_TEST_PCI_DRIVER ( 0 , 0x0a , 2 , 0 , NULL ) ;
DO_TEST_PCI ( testVirPCIDeviceDetachSingle , 0 , 0x0a , 2 , 0 ) ;
DO_TEST_PCI_DRIVER ( 0 , 0x0a , 2 , 0 , " pci-stub " ) ;
/* Reattach an unknown unbound device */
DO_TEST_PCI_DRIVER ( 0 , 0x0a , 3 , 0 , NULL ) ;
DO_TEST_PCI ( testVirPCIDeviceReattachSingle , 0 , 0x0a , 3 , 0 ) ;
DO_TEST_PCI_DRIVER ( 0 , 0x0a , 3 , 0 , NULL ) ;
2013-10-23 17:44:40 +04:00
if ( getenv ( " LIBVIRT_SKIP_CLEANUP " ) = = NULL )
virFileDeleteTree ( fakesysfsdir ) ;
VIR_FREE ( fakesysfsdir ) ;
2014-03-17 13:38:38 +04:00
return ret = = 0 ? EXIT_SUCCESS : EXIT_FAILURE ;
2013-10-23 17:44:40 +04:00
}
VIRT_TEST_MAIN_PRELOAD ( mymain , abs_builddir " /.libs/virpcimock.so " )
# else
int
main ( void )
{
return EXIT_AM_SKIP ;
}
# endif