2012-07-24 12:56:49 +04:00
/*
* virsh - interface . c : Commands to manage host interface
*
2016-01-09 16:36:29 +03:00
* Copyright ( C ) 2005 , 2007 - 2016 Red Hat , Inc .
2012-07-24 12:56:49 +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
2012-09-21 02:30:55 +04:00
* License along with this library . If not , see
2012-07-24 12:56:49 +04:00
* < http : //www.gnu.org/licenses/>.
*/
2018-01-12 16:26:35 +03:00
# define VIRSH_COMMON_OPT_INTERFACE(cflags) \
2017-11-03 15:09:47 +03:00
{ . name = " interface " , \
. type = VSH_OT_DATA , \
. flags = VSH_OFLAG_REQ , \
2018-01-12 16:26:35 +03:00
. help = N_ ( " interface name or MAC address " ) , \
. completer = virshInterfaceNameCompleter , \
. completer_flags = cflags , \
2017-10-31 13:47:36 +03:00
}
2016-01-09 16:36:35 +03:00
2012-08-21 00:30:53 +04:00
# include <config.h>
# include "virsh-interface.h"
2012-07-24 12:56:49 +04:00
2012-08-21 00:30:53 +04:00
# include <libxml/parser.h>
# include <libxml/xpath.h>
# include "internal.h"
2012-12-12 22:06:53 +04:00
# include "viralloc.h"
2013-05-09 22:59:04 +04:00
# include "virfile.h"
2013-05-15 18:15:03 +04:00
# include "virmacaddr.h"
2012-12-13 22:13:21 +04:00
# include "virxml.h"
2018-09-21 17:17:12 +03:00
# include "vsh-table.h"
2012-08-21 00:30:53 +04:00
virInterfacePtr
2015-06-15 19:53:58 +03:00
virshCommandOptInterfaceBy ( vshControl * ctl , const vshCmd * cmd ,
const char * optname ,
const char * * name , unsigned int flags )
2012-07-24 12:56:49 +04:00
{
virInterfacePtr iface = NULL ;
const char * n = NULL ;
2013-05-15 18:15:03 +04:00
bool is_mac = false ;
virMacAddr dummy ;
2015-06-15 19:53:58 +03:00
virshControlPtr priv = ctl - > privData ;
2012-07-24 12:56:49 +04:00
2020-08-03 18:27:58 +03:00
virCheckFlags ( VIRSH_BYNAME | VIRSH_BYMAC , NULL ) ;
2012-07-24 12:56:49 +04:00
if ( ! optname )
optname = " interface " ;
2013-01-21 20:25:05 +04:00
if ( vshCommandOptStringReq ( ctl , cmd , optname , & n ) < 0 )
2012-07-24 12:56:49 +04:00
return NULL ;
vshDebug ( ctl , VSH_ERR_INFO , " %s: found option <%s>: %s \n " ,
cmd - > def - > name , optname , n ) ;
if ( name )
* name = n ;
2013-05-15 18:15:03 +04:00
if ( virMacAddrParse ( n , & dummy ) = = 0 )
is_mac = true ;
2012-07-24 12:56:49 +04:00
/* try it by NAME */
2015-06-15 19:53:58 +03:00
if ( ! is_mac & & ( flags & VIRSH_BYNAME ) ) {
2012-07-24 12:56:49 +04:00
vshDebug ( ctl , VSH_ERR_DEBUG , " %s: <%s> trying as interface NAME \n " ,
cmd - > def - > name , optname ) ;
2015-06-15 19:53:58 +03:00
iface = virInterfaceLookupByName ( priv - > conn , n ) ;
2013-05-15 18:15:03 +04:00
2012-07-24 12:56:49 +04:00
/* try it by MAC */
2015-06-15 19:53:58 +03:00
} else if ( is_mac & & ( flags & VIRSH_BYMAC ) ) {
2012-07-24 12:56:49 +04:00
vshDebug ( ctl , VSH_ERR_DEBUG , " %s: <%s> trying as interface MAC \n " ,
cmd - > def - > name , optname ) ;
2015-06-15 19:53:58 +03:00
iface = virInterfaceLookupByMACString ( priv - > conn , n ) ;
2012-07-24 12:56:49 +04:00
}
if ( ! iface )
vshError ( ctl , _ ( " failed to get interface '%s' " ) , n ) ;
return iface ;
}
/*
* " iface-edit " command
*/
static const vshCmdInfo info_interface_edit [ ] = {
2013-02-07 19:25:10 +04:00
{ . name = " help " ,
. data = N_ ( " edit XML configuration for a physical host interface " )
} ,
{ . name = " desc " ,
. data = N_ ( " Edit the XML configuration for a physical host interface. " )
} ,
{ . name = NULL }
2012-07-24 12:56:49 +04:00
} ;
static const vshCmdOptDef opts_interface_edit [ ] = {
2018-01-12 16:26:35 +03:00
VIRSH_COMMON_OPT_INTERFACE ( 0 ) ,
2013-01-14 18:24:04 +04:00
{ . name = NULL }
2012-07-24 12:56:49 +04:00
} ;
static bool
cmdInterfaceEdit ( vshControl * ctl , const vshCmd * cmd )
{
bool ret = false ;
virInterfacePtr iface = NULL ;
virInterfacePtr iface_edited = NULL ;
unsigned int flags = VIR_INTERFACE_XML_INACTIVE ;
2015-06-15 19:53:58 +03:00
virshControlPtr priv = ctl - > privData ;
2012-07-24 12:56:49 +04:00
2015-06-15 19:53:58 +03:00
iface = virshCommandOptInterface ( ctl , cmd , NULL ) ;
2012-07-24 12:56:49 +04:00
if ( iface = = NULL )
goto cleanup ;
# define EDIT_GET_XML virInterfaceGetXMLDesc(iface, flags)
2017-11-03 15:09:47 +03:00
# define EDIT_NOT_CHANGED \
do { \
2016-11-04 17:22:26 +03:00
vshPrintExtra ( ctl , _ ( " Interface %s XML configuration not changed. \n " ) , \
2017-11-03 15:09:47 +03:00
virInterfaceGetName ( iface ) ) ; \
ret = true ; \
goto edit_cleanup ; \
2014-11-14 17:57:17 +03:00
} while ( 0 )
2012-07-24 12:56:49 +04:00
# define EDIT_DEFINE \
2015-06-15 19:53:58 +03:00
( iface_edited = virInterfaceDefineXML ( priv - > conn , doc_edited , 0 ) )
2012-07-24 12:56:49 +04:00
# include "virsh-edit.c"
2016-11-04 17:22:26 +03:00
vshPrintExtra ( ctl , _ ( " Interface %s XML configuration edited. \n " ) ,
virInterfaceGetName ( iface_edited ) ) ;
2012-07-24 12:56:49 +04:00
ret = true ;
2014-03-25 10:53:59 +04:00
cleanup :
2012-07-24 12:56:49 +04:00
if ( iface )
virInterfaceFree ( iface ) ;
if ( iface_edited )
virInterfaceFree ( iface_edited ) ;
return ret ;
}
2012-09-04 20:10:18 +04:00
static int
2015-06-15 19:53:58 +03:00
virshInterfaceSorter ( const void * a , const void * b )
2012-09-04 20:10:18 +04:00
{
virInterfacePtr * ia = ( virInterfacePtr * ) a ;
virInterfacePtr * ib = ( virInterfacePtr * ) b ;
if ( * ia & & ! * ib )
return - 1 ;
if ( ! * ia )
return * ib ! = NULL ;
return vshStrcasecmp ( virInterfaceGetName ( * ia ) ,
virInterfaceGetName ( * ib ) ) ;
}
2015-06-15 19:53:58 +03:00
struct virshInterfaceList {
2012-09-04 20:10:18 +04:00
virInterfacePtr * ifaces ;
size_t nifaces ;
} ;
2015-06-15 19:53:58 +03:00
typedef struct virshInterfaceList * virshInterfaceListPtr ;
2012-09-04 20:10:18 +04:00
static void
2015-06-15 19:53:58 +03:00
virshInterfaceListFree ( virshInterfaceListPtr list )
2012-09-04 20:10:18 +04:00
{
Convert 'int i' to 'size_t i' in tools/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 18:09:33 +04:00
size_t i ;
2012-09-04 20:10:18 +04:00
2013-08-27 15:27:50 +04:00
if ( list & & list - > ifaces ) {
2012-09-04 20:10:18 +04:00
for ( i = 0 ; i < list - > nifaces ; i + + ) {
if ( list - > ifaces [ i ] )
virInterfaceFree ( list - > ifaces [ i ] ) ;
}
VIR_FREE ( list - > ifaces ) ;
}
VIR_FREE ( list ) ;
}
2015-06-15 19:53:58 +03:00
static virshInterfaceListPtr
virshInterfaceListCollect ( vshControl * ctl ,
unsigned int flags )
2012-09-04 20:10:18 +04:00
{
2020-10-05 19:50:09 +03:00
virshInterfaceListPtr list = g_new0 ( struct virshInterfaceList , 1 ) ;
Convert 'int i' to 'size_t i' in tools/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 18:09:33 +04:00
size_t i ;
2012-09-04 20:10:18 +04:00
int ret ;
char * * activeNames = NULL ;
char * * inactiveNames = NULL ;
virInterfacePtr iface ;
bool success = false ;
size_t deleted = 0 ;
int nActiveIfaces = 0 ;
int nInactiveIfaces = 0 ;
int nAllIfaces = 0 ;
2015-06-15 19:53:58 +03:00
virshControlPtr priv = ctl - > privData ;
2012-09-04 20:10:18 +04:00
/* try the list with flags support (0.10.2 and later) */
2015-06-15 19:53:58 +03:00
if ( ( ret = virConnectListAllInterfaces ( priv - > conn ,
2012-09-04 20:10:18 +04:00
& list - > ifaces ,
flags ) ) > = 0 ) {
list - > nifaces = ret ;
goto finished ;
}
/* check if the command is actually supported */
if ( last_error & & last_error - > code = = VIR_ERR_NO_SUPPORT )
goto fallback ;
/* there was an error during the first or second call */
vshError ( ctl , " %s " , _ ( " Failed to list interfaces " ) ) ;
goto cleanup ;
2014-03-25 10:53:59 +04:00
fallback :
2012-09-04 20:10:18 +04:00
/* fall back to old method (0.10.1 and older) */
vshResetLibvirtError ( ) ;
if ( flags & VIR_CONNECT_LIST_INTERFACES_ACTIVE ) {
2015-06-15 19:53:58 +03:00
nActiveIfaces = virConnectNumOfInterfaces ( priv - > conn ) ;
2012-09-04 20:10:18 +04:00
if ( nActiveIfaces < 0 ) {
vshError ( ctl , " %s " , _ ( " Failed to list active interfaces " ) ) ;
goto cleanup ;
}
if ( nActiveIfaces ) {
2020-10-05 19:50:09 +03:00
activeNames = g_new0 ( char * , nActiveIfaces ) ;
2012-09-04 20:10:18 +04:00
2015-06-15 19:53:58 +03:00
if ( ( nActiveIfaces = virConnectListInterfaces ( priv - > conn , activeNames ,
2012-09-04 20:10:18 +04:00
nActiveIfaces ) ) < 0 ) {
vshError ( ctl , " %s " , _ ( " Failed to list active interfaces " ) ) ;
goto cleanup ;
}
}
}
if ( flags & VIR_CONNECT_LIST_INTERFACES_INACTIVE ) {
2015-06-15 19:53:58 +03:00
nInactiveIfaces = virConnectNumOfDefinedInterfaces ( priv - > conn ) ;
2012-09-04 20:10:18 +04:00
if ( nInactiveIfaces < 0 ) {
vshError ( ctl , " %s " , _ ( " Failed to list inactive interfaces " ) ) ;
goto cleanup ;
}
if ( nInactiveIfaces ) {
2020-10-05 19:50:09 +03:00
inactiveNames = g_new0 ( char * , nInactiveIfaces ) ;
2012-09-04 20:10:18 +04:00
if ( ( nInactiveIfaces =
2015-06-15 19:53:58 +03:00
virConnectListDefinedInterfaces ( priv - > conn , inactiveNames ,
2012-09-04 20:10:18 +04:00
nInactiveIfaces ) ) < 0 ) {
vshError ( ctl , " %s " , _ ( " Failed to list inactive interfaces " ) ) ;
goto cleanup ;
}
}
}
nAllIfaces = nActiveIfaces + nInactiveIfaces ;
if ( nAllIfaces = = 0 ) {
VIR_FREE ( activeNames ) ;
VIR_FREE ( inactiveNames ) ;
return list ;
}
2020-10-05 19:50:09 +03:00
list - > ifaces = g_new0 ( virInterfacePtr , nAllIfaces ) ;
2012-09-04 20:10:18 +04:00
list - > nifaces = 0 ;
/* get active interfaces */
for ( i = 0 ; i < nActiveIfaces ; i + + ) {
2015-06-15 19:53:58 +03:00
if ( ! ( iface = virInterfaceLookupByName ( priv - > conn , activeNames [ i ] ) ) ) {
2012-09-04 20:10:18 +04:00
vshResetLibvirtError ( ) ;
continue ;
}
list - > ifaces [ list - > nifaces + + ] = iface ;
}
/* get inactive interfaces */
for ( i = 0 ; i < nInactiveIfaces ; i + + ) {
2015-06-15 19:53:58 +03:00
if ( ! ( iface = virInterfaceLookupByName ( priv - > conn , inactiveNames [ i ] ) ) ) {
2012-09-04 20:10:18 +04:00
vshResetLibvirtError ( ) ;
continue ;
}
list - > ifaces [ list - > nifaces + + ] = iface ;
}
/* truncate interfaces that weren't found */
deleted = nAllIfaces - list - > nifaces ;
2014-03-25 10:53:59 +04:00
finished :
2012-09-04 20:10:18 +04:00
/* sort the list */
if ( list - > ifaces & & list - > nifaces )
qsort ( list - > ifaces , list - > nifaces ,
2015-06-15 19:53:58 +03:00
sizeof ( * list - > ifaces ) , virshInterfaceSorter ) ;
2012-09-04 20:10:18 +04:00
/* truncate the list if filter simulation deleted entries */
if ( deleted )
VIR_SHRINK_N ( list - > ifaces , list - > nifaces , deleted ) ;
success = true ;
2014-03-25 10:53:59 +04:00
cleanup :
2013-07-11 18:31:15 +04:00
for ( i = 0 ; nActiveIfaces ! = - 1 & & i < nActiveIfaces ; i + + )
2012-09-04 20:10:18 +04:00
VIR_FREE ( activeNames [ i ] ) ;
2013-07-11 18:31:15 +04:00
for ( i = 0 ; nInactiveIfaces ! = - 1 & & i < nInactiveIfaces ; i + + )
2012-09-04 20:10:18 +04:00
VIR_FREE ( inactiveNames [ i ] ) ;
VIR_FREE ( activeNames ) ;
VIR_FREE ( inactiveNames ) ;
if ( ! success ) {
2015-06-15 19:53:58 +03:00
virshInterfaceListFree ( list ) ;
2012-09-04 20:10:18 +04:00
list = NULL ;
}
return list ;
}
2012-07-24 12:56:49 +04:00
/*
* " iface-list " command
*/
static const vshCmdInfo info_interface_list [ ] = {
2013-02-07 19:25:10 +04:00
{ . name = " help " ,
. data = N_ ( " list physical host interfaces " )
} ,
{ . name = " desc " ,
. data = N_ ( " Returns list of physical host interfaces. " )
} ,
{ . name = NULL }
2012-07-24 12:56:49 +04:00
} ;
static const vshCmdOptDef opts_interface_list [ ] = {
2013-01-14 18:24:04 +04:00
{ . name = " inactive " ,
. type = VSH_OT_BOOL ,
. help = N_ ( " list inactive interfaces " )
} ,
{ . name = " all " ,
. type = VSH_OT_BOOL ,
. help = N_ ( " list inactive & active interfaces " )
} ,
{ . name = NULL }
2012-07-24 12:56:49 +04:00
} ;
2012-09-04 20:10:18 +04:00
2012-07-24 12:56:49 +04:00
static bool
2019-10-14 15:44:29 +03:00
cmdInterfaceList ( vshControl * ctl , const vshCmd * cmd G_GNUC_UNUSED )
2012-07-24 12:56:49 +04:00
{
bool inactive = vshCommandOptBool ( cmd , " inactive " ) ;
bool all = vshCommandOptBool ( cmd , " all " ) ;
2012-09-04 20:10:18 +04:00
unsigned int flags = VIR_CONNECT_LIST_INTERFACES_ACTIVE ;
2015-06-15 19:53:58 +03:00
virshInterfaceListPtr list = NULL ;
Convert 'int i' to 'size_t i' in tools/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 18:09:33 +04:00
size_t i ;
2018-09-21 17:17:12 +03:00
bool ret = false ;
vshTablePtr table = NULL ;
2012-07-24 12:56:49 +04:00
2020-09-11 10:06:16 +03:00
VSH_EXCLUSIVE_OPTIONS_VAR ( all , inactive ) ;
2012-09-04 20:10:18 +04:00
if ( inactive )
flags = VIR_CONNECT_LIST_INTERFACES_INACTIVE ;
if ( all )
flags = VIR_CONNECT_LIST_INTERFACES_INACTIVE |
VIR_CONNECT_LIST_INTERFACES_ACTIVE ;
2012-07-24 12:56:49 +04:00
2015-06-15 19:53:58 +03:00
if ( ! ( list = virshInterfaceListCollect ( ctl , flags ) ) )
2012-09-04 20:10:18 +04:00
return false ;
2012-07-24 12:56:49 +04:00
2018-09-21 17:17:12 +03:00
table = vshTableNew ( _ ( " Name " ) , _ ( " State " ) , _ ( " MAC Address " ) , NULL ) ;
if ( ! table )
goto cleanup ;
2012-07-24 12:56:49 +04:00
2012-09-04 20:10:18 +04:00
for ( i = 0 ; i < list - > nifaces ; i + + ) {
virInterfacePtr iface = list - > ifaces [ i ] ;
2012-07-24 12:56:49 +04:00
2018-09-21 17:17:12 +03:00
if ( vshTableRowAppend ( table ,
virInterfaceGetName ( iface ) ,
virInterfaceIsActive ( iface ) ? _ ( " active " )
: _ ( " inactive " ) ,
virInterfaceGetMACString ( iface ) ,
NULL ) < 0 )
goto cleanup ;
2012-07-24 12:56:49 +04:00
}
2018-09-21 17:17:12 +03:00
vshTablePrintToStdout ( table , ctl ) ;
ret = true ;
cleanup :
vshTableFree ( table ) ;
2015-06-15 19:53:58 +03:00
virshInterfaceListFree ( list ) ;
2018-09-21 17:17:12 +03:00
return ret ;
2012-07-24 12:56:49 +04:00
}
/*
* " iface-name " command
*/
static const vshCmdInfo info_interface_name [ ] = {
2013-02-07 19:25:10 +04:00
{ . name = " help " ,
. data = N_ ( " convert an interface MAC address to interface name " )
} ,
{ . name = " desc " ,
. data = " "
} ,
{ . name = NULL }
2012-07-24 12:56:49 +04:00
} ;
static const vshCmdOptDef opts_interface_name [ ] = {
2013-01-14 18:24:04 +04:00
{ . name = " interface " ,
. type = VSH_OT_DATA ,
. flags = VSH_OFLAG_REQ ,
2020-11-10 12:50:56 +03:00
. completer = virshInterfaceMacCompleter ,
2013-01-14 18:24:04 +04:00
. help = N_ ( " interface mac " )
} ,
{ . name = NULL }
2012-07-24 12:56:49 +04:00
} ;
static bool
cmdInterfaceName ( vshControl * ctl , const vshCmd * cmd )
{
virInterfacePtr iface ;
2015-06-15 19:53:58 +03:00
if ( ! ( iface = virshCommandOptInterfaceBy ( ctl , cmd , NULL , NULL ,
VIRSH_BYMAC ) ) )
2012-07-24 12:56:49 +04:00
return false ;
vshPrint ( ctl , " %s \n " , virInterfaceGetName ( iface ) ) ;
virInterfaceFree ( iface ) ;
return true ;
}
/*
* " iface-mac " command
*/
static const vshCmdInfo info_interface_mac [ ] = {
2013-02-07 19:25:10 +04:00
{ . name = " help " ,
. data = N_ ( " convert an interface name to interface MAC address " )
} ,
{ . name = " desc " ,
. data = " "
} ,
{ . name = NULL }
2012-07-24 12:56:49 +04:00
} ;
static const vshCmdOptDef opts_interface_mac [ ] = {
2013-01-14 18:24:04 +04:00
{ . name = " interface " ,
. type = VSH_OT_DATA ,
. flags = VSH_OFLAG_REQ ,
. help = N_ ( " interface name " )
} ,
{ . name = NULL }
2012-07-24 12:56:49 +04:00
} ;
static bool
cmdInterfaceMAC ( vshControl * ctl , const vshCmd * cmd )
{
virInterfacePtr iface ;
2015-06-15 19:53:58 +03:00
if ( ! ( iface = virshCommandOptInterfaceBy ( ctl , cmd , NULL , NULL ,
VIRSH_BYNAME ) ) )
2012-07-24 12:56:49 +04:00
return false ;
vshPrint ( ctl , " %s \n " , virInterfaceGetMACString ( iface ) ) ;
virInterfaceFree ( iface ) ;
return true ;
}
/*
* " iface-dumpxml " command
*/
static const vshCmdInfo info_interface_dumpxml [ ] = {
2013-02-07 19:25:10 +04:00
{ . name = " help " ,
. data = N_ ( " interface information in XML " )
} ,
{ . name = " desc " ,
. data = N_ ( " Output the physical host interface information as an XML dump to stdout. " )
} ,
{ . name = NULL }
2012-07-24 12:56:49 +04:00
} ;
static const vshCmdOptDef opts_interface_dumpxml [ ] = {
2018-01-12 16:26:35 +03:00
VIRSH_COMMON_OPT_INTERFACE ( 0 ) ,
2013-01-14 18:24:04 +04:00
{ . name = " inactive " ,
. type = VSH_OT_BOOL ,
. help = N_ ( " show inactive defined XML " )
} ,
{ . name = NULL }
2012-07-24 12:56:49 +04:00
} ;
static bool
cmdInterfaceDumpXML ( vshControl * ctl , const vshCmd * cmd )
{
virInterfacePtr iface ;
bool ret = true ;
char * dump ;
unsigned int flags = 0 ;
bool inactive = vshCommandOptBool ( cmd , " inactive " ) ;
if ( inactive )
flags | = VIR_INTERFACE_XML_INACTIVE ;
2015-06-15 19:53:58 +03:00
if ( ! ( iface = virshCommandOptInterface ( ctl , cmd , NULL ) ) )
2012-07-24 12:56:49 +04:00
return false ;
dump = virInterfaceGetXMLDesc ( iface , flags ) ;
if ( dump ! = NULL ) {
vshPrint ( ctl , " %s " , dump ) ;
VIR_FREE ( dump ) ;
} else {
ret = false ;
}
virInterfaceFree ( iface ) ;
return ret ;
}
/*
* " iface-define " command
*/
static const vshCmdInfo info_interface_define [ ] = {
2013-02-07 19:25:10 +04:00
{ . name = " help " ,
2015-02-25 17:37:00 +03:00
. data = N_ ( " define an inactive persistent physical host interface or "
" modify an existing persistent one from an XML file " )
2013-02-07 19:25:10 +04:00
} ,
{ . name = " desc " ,
2015-02-25 17:37:00 +03:00
. data = N_ ( " Define or modify a persistent physical host interface. " )
2013-02-07 19:25:10 +04:00
} ,
{ . name = NULL }
2012-07-24 12:56:49 +04:00
} ;
static const vshCmdOptDef opts_interface_define [ ] = {
2016-01-09 16:36:29 +03:00
VIRSH_COMMON_OPT_FILE ( N_ ( " file containing an XML interface description " ) ) ,
2013-01-14 18:24:04 +04:00
{ . name = NULL }
2012-07-24 12:56:49 +04:00
} ;
static bool
cmdInterfaceDefine ( vshControl * ctl , const vshCmd * cmd )
{
virInterfacePtr iface ;
const char * from = NULL ;
bool ret = true ;
char * buffer ;
2015-06-15 19:53:58 +03:00
virshControlPtr priv = ctl - > privData ;
2012-07-24 12:56:49 +04:00
2013-01-21 20:25:05 +04:00
if ( vshCommandOptStringReq ( ctl , cmd , " file " , & from ) < 0 )
2012-07-24 12:56:49 +04:00
return false ;
virsh: use common namespacing
Convert the exported items in virsh.h to use a common 'vsh' prefix.
* tools/virsh.h (VIRSH_MAX_XML_FILE): Rename...
(VSH_MAX_XML_FILE): ...and parenthesize.
(DIFF_MSEC, CTRL_CLOSE_BRACKET): Delete.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Remove prototype.
(editWriteToTempFile, editFile, editReadBackFile, prettyCapacity)
(virshReportError): Rename...
(vshEditWriteToTempFile, vshEditFile, vshEditReadBackFile)
(vshPrettyCapacity, vshReportError): ...into vsh namespace.
(jobWatchTimeoutFunc): Move to virsh-domain.c.
* tools/virsh.c (vshCommandRun): Inline former DIFF_MSEC.
(main): Inline former CTRL_CLOSE_BRACKET.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Make static.
(prettyCapacity, virshReportError, editWriteToTempFile, editFile):
Fix naming, and adjust usage.
(vshAskReedit, vshCommandRun, vshEventLoop, vshInit): Adjust
usage.
* tools/virsh-domain.c (cmdAttachDevice, cmdCPUCompare)
(cmdCPUBaseline, cmdCreate, cmdDefine, cmdDetachDevice)
(cmdUpdateDevice, cmdDesc, cmdUndefine, cmdStart, cmdVcpucount)
(cmdAttachDevice, cmdDomjobinfo): Likewise.
* tools/virsh-edit.c (do): Likewise.
* tools/virsh-interface.c (cmdInterfaceDefine): Likewise.
* tools/virsh-network.c (cmdNetworkCreate, cmdNetworkDefine):
Likewise.
* tools/virsh-nodedev.c (cmdNodeDeviceCreate): Likewise.
* tools/virsh-nwfilter.c (cmdNWFilterDefine): Likewise.
* tools/virsh-pool.c (cmdPoolCreate, cmdPoolDefine)
(cmdPoolDiscoverSources, cmdPoolList): Likewise.
* tools/virsh-secret.c (cmdSecretDefine): Likewise.
* tools/virsh-snapshot.c (cmdSnapshotCreate, vshSnapshotCreate)
(vshLookupSnapshot, cmdSnapshotEdit, cmdSnapshotCurrent)
(vshGetSnapshotParent): Likewise.
* tools/virsh-volume.c (cmdVolCreate, cmdVolCreateFrom)
(cmdVolInfo, cmdVolList): Likewise.
2012-08-19 08:10:17 +04:00
if ( virFileReadAll ( from , VSH_MAX_XML_FILE , & buffer ) < 0 )
2012-07-24 12:56:49 +04:00
return false ;
2015-06-15 19:53:58 +03:00
iface = virInterfaceDefineXML ( priv - > conn , buffer , 0 ) ;
2012-07-24 12:56:49 +04:00
VIR_FREE ( buffer ) ;
if ( iface ! = NULL ) {
2016-08-24 17:14:23 +03:00
vshPrintExtra ( ctl , _ ( " Interface %s defined from %s \n " ) ,
virInterfaceGetName ( iface ) , from ) ;
2012-07-24 12:56:49 +04:00
virInterfaceFree ( iface ) ;
} else {
vshError ( ctl , _ ( " Failed to define interface from %s " ) , from ) ;
ret = false ;
}
return ret ;
}
/*
* " iface-undefine " command
*/
static const vshCmdInfo info_interface_undefine [ ] = {
2013-02-07 19:25:10 +04:00
{ . name = " help " ,
. data = N_ ( " undefine a physical host interface (remove it from configuration) " )
} ,
{ . name = " desc " ,
. data = N_ ( " undefine an interface. " )
} ,
{ . name = NULL }
2012-07-24 12:56:49 +04:00
} ;
static const vshCmdOptDef opts_interface_undefine [ ] = {
2018-01-12 16:26:35 +03:00
VIRSH_COMMON_OPT_INTERFACE ( 0 ) ,
2013-01-14 18:24:04 +04:00
{ . name = NULL }
2012-07-24 12:56:49 +04:00
} ;
static bool
cmdInterfaceUndefine ( vshControl * ctl , const vshCmd * cmd )
{
virInterfacePtr iface ;
bool ret = true ;
const char * name ;
2015-06-15 19:53:58 +03:00
if ( ! ( iface = virshCommandOptInterface ( ctl , cmd , & name ) ) )
2012-07-24 12:56:49 +04:00
return false ;
if ( virInterfaceUndefine ( iface ) = = 0 ) {
2016-08-24 17:14:23 +03:00
vshPrintExtra ( ctl , _ ( " Interface %s undefined \n " ) , name ) ;
2012-07-24 12:56:49 +04:00
} else {
vshError ( ctl , _ ( " Failed to undefine interface %s " ) , name ) ;
ret = false ;
}
virInterfaceFree ( iface ) ;
return ret ;
}
/*
* " iface-start " command
*/
static const vshCmdInfo info_interface_start [ ] = {
2013-02-07 19:25:10 +04:00
{ . name = " help " ,
. data = N_ ( " start a physical host interface (enable it / \" if-up \" ) " )
} ,
{ . name = " desc " ,
. data = N_ ( " start a physical host interface. " )
} ,
{ . name = NULL }
2012-07-24 12:56:49 +04:00
} ;
static const vshCmdOptDef opts_interface_start [ ] = {
2018-01-12 16:26:35 +03:00
VIRSH_COMMON_OPT_INTERFACE ( VIR_CONNECT_LIST_INTERFACES_INACTIVE ) ,
2013-01-14 18:24:04 +04:00
{ . name = NULL }
2012-07-24 12:56:49 +04:00
} ;
static bool
cmdInterfaceStart ( vshControl * ctl , const vshCmd * cmd )
{
virInterfacePtr iface ;
bool ret = true ;
const char * name ;
2015-06-15 19:53:58 +03:00
if ( ! ( iface = virshCommandOptInterface ( ctl , cmd , & name ) ) )
2012-07-24 12:56:49 +04:00
return false ;
if ( virInterfaceCreate ( iface , 0 ) = = 0 ) {
2016-08-24 17:14:23 +03:00
vshPrintExtra ( ctl , _ ( " Interface %s started \n " ) , name ) ;
2012-07-24 12:56:49 +04:00
} else {
vshError ( ctl , _ ( " Failed to start interface %s " ) , name ) ;
ret = false ;
}
virInterfaceFree ( iface ) ;
return ret ;
}
/*
* " iface-destroy " command
*/
static const vshCmdInfo info_interface_destroy [ ] = {
2013-02-07 19:25:10 +04:00
{ . name = " help " ,
. data = N_ ( " destroy a physical host interface (disable it / \" if-down \" ) " )
} ,
{ . name = " desc " ,
. data = N_ ( " forcefully stop a physical host interface. " )
} ,
{ . name = NULL }
2012-07-24 12:56:49 +04:00
} ;
static const vshCmdOptDef opts_interface_destroy [ ] = {
2018-01-12 16:26:35 +03:00
VIRSH_COMMON_OPT_INTERFACE ( VIR_CONNECT_LIST_INTERFACES_ACTIVE ) ,
2013-01-14 18:24:04 +04:00
{ . name = NULL }
2012-07-24 12:56:49 +04:00
} ;
static bool
cmdInterfaceDestroy ( vshControl * ctl , const vshCmd * cmd )
{
virInterfacePtr iface ;
bool ret = true ;
const char * name ;
2015-06-15 19:53:58 +03:00
if ( ! ( iface = virshCommandOptInterface ( ctl , cmd , & name ) ) )
2012-07-24 12:56:49 +04:00
return false ;
if ( virInterfaceDestroy ( iface , 0 ) = = 0 ) {
2016-08-24 17:14:23 +03:00
vshPrintExtra ( ctl , _ ( " Interface %s destroyed \n " ) , name ) ;
2012-07-24 12:56:49 +04:00
} else {
vshError ( ctl , _ ( " Failed to destroy interface %s " ) , name ) ;
ret = false ;
}
virInterfaceFree ( iface ) ;
return ret ;
}
/*
* " iface-begin " command
*/
static const vshCmdInfo info_interface_begin [ ] = {
2013-02-07 19:25:10 +04:00
{ . name = " help " ,
. data = N_ ( " create a snapshot of current interfaces settings, "
2012-07-24 12:56:49 +04:00
" which can be later committed (iface-commit) or "
2013-02-07 19:25:10 +04:00
" restored (iface-rollback) " )
} ,
{ . name = " desc " ,
. data = N_ ( " Create a restore point for interfaces settings " )
} ,
{ . name = NULL }
2012-07-24 12:56:49 +04:00
} ;
static const vshCmdOptDef opts_interface_begin [ ] = {
2013-01-14 18:24:04 +04:00
{ . name = NULL }
2012-07-24 12:56:49 +04:00
} ;
static bool
2019-10-14 15:44:29 +03:00
cmdInterfaceBegin ( vshControl * ctl , const vshCmd * cmd G_GNUC_UNUSED )
2012-07-24 12:56:49 +04:00
{
2015-06-15 19:53:58 +03:00
virshControlPtr priv = ctl - > privData ;
if ( virInterfaceChangeBegin ( priv - > conn , 0 ) < 0 ) {
2012-07-24 12:56:49 +04:00
vshError ( ctl , " %s " , _ ( " Failed to begin network config change transaction " ) ) ;
return false ;
}
2016-08-24 17:14:23 +03:00
vshPrintExtra ( ctl , " %s " , _ ( " Network config change transaction started \n " ) ) ;
2012-07-24 12:56:49 +04:00
return true ;
}
/*
* " iface-commit " command
*/
static const vshCmdInfo info_interface_commit [ ] = {
2013-02-07 19:25:10 +04:00
{ . name = " help " ,
. data = N_ ( " commit changes made since iface-begin and free restore point " )
} ,
{ . name = " desc " ,
. data = N_ ( " commit changes and free restore point " )
} ,
{ . name = NULL }
2012-07-24 12:56:49 +04:00
} ;
static const vshCmdOptDef opts_interface_commit [ ] = {
2013-01-14 18:24:04 +04:00
{ . name = NULL }
2012-07-24 12:56:49 +04:00
} ;
static bool
2019-10-14 15:44:29 +03:00
cmdInterfaceCommit ( vshControl * ctl , const vshCmd * cmd G_GNUC_UNUSED )
2012-07-24 12:56:49 +04:00
{
2015-06-15 19:53:58 +03:00
virshControlPtr priv = ctl - > privData ;
if ( virInterfaceChangeCommit ( priv - > conn , 0 ) < 0 ) {
2012-07-24 12:56:49 +04:00
vshError ( ctl , " %s " , _ ( " Failed to commit network config change transaction " ) ) ;
return false ;
}
2016-08-24 17:14:23 +03:00
vshPrintExtra ( ctl , " %s " , _ ( " Network config change transaction committed \n " ) ) ;
2012-07-24 12:56:49 +04:00
return true ;
}
/*
* " iface-rollback " command
*/
static const vshCmdInfo info_interface_rollback [ ] = {
2013-02-07 19:25:10 +04:00
{ . name = " help " ,
. data = N_ ( " rollback to previous saved configuration created via iface-begin " )
} ,
{ . name = " desc " ,
. data = N_ ( " rollback to previous restore point " )
} ,
{ . name = NULL }
2012-07-24 12:56:49 +04:00
} ;
static const vshCmdOptDef opts_interface_rollback [ ] = {
2013-01-14 18:24:04 +04:00
{ . name = NULL }
2012-07-24 12:56:49 +04:00
} ;
static bool
2019-10-14 15:44:29 +03:00
cmdInterfaceRollback ( vshControl * ctl , const vshCmd * cmd G_GNUC_UNUSED )
2012-07-24 12:56:49 +04:00
{
2015-06-15 19:53:58 +03:00
virshControlPtr priv = ctl - > privData ;
if ( virInterfaceChangeRollback ( priv - > conn , 0 ) < 0 ) {
2012-07-24 12:56:49 +04:00
vshError ( ctl , " %s " , _ ( " Failed to rollback network config change transaction " ) ) ;
return false ;
}
2016-08-24 17:14:23 +03:00
vshPrintExtra ( ctl , " %s " , _ ( " Network config change transaction rolled back \n " ) ) ;
2012-07-24 12:56:49 +04:00
return true ;
}
/*
* " iface-bridge " command
*/
static const vshCmdInfo info_interface_bridge [ ] = {
2013-02-07 19:25:10 +04:00
{ . name = " help " ,
. data = N_ ( " create a bridge device and attach an existing network device to it " )
} ,
{ . name = " desc " ,
. data = N_ ( " bridge an existing network device " )
} ,
{ . name = NULL }
2012-07-24 12:56:49 +04:00
} ;
static const vshCmdOptDef opts_interface_bridge [ ] = {
2013-01-14 18:24:04 +04:00
{ . name = " interface " ,
. type = VSH_OT_DATA ,
. flags = VSH_OFLAG_REQ ,
2020-11-10 12:50:57 +03:00
. completer = virshInterfaceNameCompleter ,
2013-01-14 18:24:04 +04:00
. help = N_ ( " existing interface name " )
} ,
{ . name = " bridge " ,
. type = VSH_OT_DATA ,
. flags = VSH_OFLAG_REQ ,
. help = N_ ( " new bridge device name " )
} ,
{ . name = " no-stp " ,
. type = VSH_OT_BOOL ,
. help = N_ ( " do not enable STP for this bridge " )
} ,
{ . name = " delay " ,
. type = VSH_OT_INT ,
. help = N_ ( " number of seconds to squelch traffic on newly connected ports " )
} ,
{ . name = " no-start " ,
. type = VSH_OT_BOOL ,
. help = N_ ( " don't start the bridge immediately " )
} ,
{ . name = NULL }
2012-07-24 12:56:49 +04:00
} ;
static bool
cmdInterfaceBridge ( vshControl * ctl , const vshCmd * cmd )
{
bool ret = false ;
virInterfacePtr if_handle = NULL , br_handle = NULL ;
const char * if_name , * br_name ;
char * if_type = NULL , * if2_name = NULL , * delay_str = NULL ;
bool stp = false , nostart = false ;
unsigned int delay = 0 ;
char * if_xml = NULL ;
xmlChar * br_xml = NULL ;
int br_xml_size ;
xmlDocPtr xml_doc = NULL ;
xmlXPathContextPtr ctxt = NULL ;
xmlNodePtr top_node , br_node , if_node , cur ;
2015-06-15 19:53:58 +03:00
virshControlPtr priv = ctl - > privData ;
2012-07-24 12:56:49 +04:00
/* Get a handle to the original device */
2015-06-15 19:53:58 +03:00
if ( ! ( if_handle = virshCommandOptInterfaceBy ( ctl , cmd , " interface " ,
& if_name , VIRSH_BYNAME ) ) ) {
2012-07-24 12:56:49 +04:00
goto cleanup ;
}
/* Name for new bridge device */
2013-01-21 20:25:05 +04:00
if ( vshCommandOptStringReq ( ctl , cmd , " bridge " , & br_name ) < 0 )
2012-07-24 12:56:49 +04:00
goto cleanup ;
/* make sure "new" device doesn't already exist */
2015-06-15 19:53:58 +03:00
if ( ( br_handle = virInterfaceLookupByName ( priv - > conn , br_name ) ) ) {
2012-07-24 12:56:49 +04:00
vshError ( ctl , _ ( " Network device %s already exists " ) , br_name ) ;
goto cleanup ;
}
/* use "no-stp" because we want "stp" to default true */
stp = ! vshCommandOptBool ( cmd , " no-stp " ) ;
2015-06-02 12:17:29 +03:00
if ( vshCommandOptUInt ( ctl , cmd , " delay " , & delay ) < 0 )
2012-07-24 12:56:49 +04:00
goto cleanup ;
nostart = vshCommandOptBool ( cmd , " no-start " ) ;
/* Get the original interface into an xmlDoc */
if ( ! ( if_xml = virInterfaceGetXMLDesc ( if_handle , VIR_INTERFACE_XML_INACTIVE ) ) )
goto cleanup ;
if ( ! ( xml_doc = virXMLParseStringCtxt ( if_xml ,
_ ( " (interface definition) " ) , & ctxt ) ) ) {
vshError ( ctl , _ ( " Failed to parse configuration of %s " ) , if_name ) ;
goto cleanup ;
}
top_node = ctxt - > node ;
/* Verify that the original device isn't already a bridge. */
if ( ! ( if_type = virXMLPropString ( top_node , " type " ) ) ) {
vshError ( ctl , _ ( " Existing device %s has no type " ) , if_name ) ;
goto cleanup ;
}
if ( STREQ ( if_type , " bridge " ) ) {
vshError ( ctl , _ ( " Existing device %s is already a bridge " ) , if_name ) ;
goto cleanup ;
}
/* verify the name in the XML matches the device name */
if ( ! ( if2_name = virXMLPropString ( top_node , " name " ) ) | |
STRNEQ ( if2_name , if_name ) ) {
vshError ( ctl , _ ( " Interface name from config %s doesn't match given supplied name %s " ) ,
if2_name , if_name ) ;
goto cleanup ;
}
/* Create a <bridge> node under <interface>. */
if ( ! ( br_node = xmlNewChild ( top_node , NULL , BAD_CAST " bridge " , NULL ) ) ) {
vshError ( ctl , " %s " , _ ( " Failed to create bridge node in xml document " ) ) ;
goto cleanup ;
}
/* Set stp and delay attributes in <bridge> according to the
* commandline options .
*/
2012-10-17 13:23:12 +04:00
if ( ! xmlSetProp ( br_node , BAD_CAST " stp " , BAD_CAST ( stp ? " on " : " off " ) ) ) {
2012-07-24 12:56:49 +04:00
vshError ( ctl , " %s " , _ ( " Failed to set stp attribute in xml document " ) ) ;
goto cleanup ;
}
2019-10-22 16:26:14 +03:00
if ( stp ) {
delay_str = g_strdup_printf ( " %d " , delay ) ;
if ( ! xmlSetProp ( br_node , BAD_CAST " delay " , BAD_CAST delay_str ) ) {
vshError ( ctl , _ ( " Failed to set bridge delay %d in xml document " ) , delay ) ;
goto cleanup ;
}
2012-07-24 12:56:49 +04:00
}
/* Change the type of the outer/master interface to "bridge" and the
* name to the provided bridge name .
*/
if ( ! xmlSetProp ( top_node , BAD_CAST " type " , BAD_CAST " bridge " ) ) {
vshError ( ctl , " %s " , _ ( " Failed to set bridge interface type to 'bridge' in xml document " ) ) ;
goto cleanup ;
}
if ( ! xmlSetProp ( top_node , BAD_CAST " name " , BAD_CAST br_name ) ) {
vshError ( ctl , _ ( " Failed to set master bridge interface name to '%s' in xml document " ) ,
br_name ) ;
goto cleanup ;
}
/* Create an <interface> node under <bridge> that uses the
* original interface ' s type and name .
*/
if ( ! ( if_node = xmlNewChild ( br_node , NULL , BAD_CAST " interface " , NULL ) ) ) {
vshError ( ctl , " %s " , _ ( " Failed to create interface node under bridge node in xml document " ) ) ;
goto cleanup ;
}
2020-06-17 12:44:39 +03:00
/* set the type of the attached interface to the original
2012-07-24 12:56:49 +04:00
* if_type , and the name to the original if_name .
*/
if ( ! xmlSetProp ( if_node , BAD_CAST " type " , BAD_CAST if_type ) ) {
2020-06-17 12:44:39 +03:00
vshError ( ctl , _ ( " Failed to set new attached interface type to '%s' in xml document " ) ,
2012-11-28 17:34:49 +04:00
if_type ) ;
2012-07-24 12:56:49 +04:00
goto cleanup ;
}
if ( ! xmlSetProp ( if_node , BAD_CAST " name " , BAD_CAST if_name ) ) {
2020-06-17 12:44:39 +03:00
vshError ( ctl , _ ( " Failed to set new attached interface name to '%s' in xml document " ) ,
2012-11-28 17:34:49 +04:00
if_name ) ;
2012-07-24 12:56:49 +04:00
goto cleanup ;
}
/* Cycle through all the nodes under the original <interface>,
* moving all < mac > , < bond > and < vlan > nodes down into the new
* lower level < interface > .
*/
cur = top_node - > children ;
while ( cur ) {
xmlNodePtr old = cur ;
cur = cur - > next ;
if ( ( old - > type = = XML_ELEMENT_NODE ) & &
2017-08-14 15:31:52 +03:00
( virXMLNodeNameEqual ( old , " mac " ) | | /* ethernet stuff to move down */
virXMLNodeNameEqual ( old , " bond " ) | | /* bond stuff to move down */
virXMLNodeNameEqual ( old , " vlan " ) ) ) { /* vlan stuff to move down */
2012-07-24 12:56:49 +04:00
xmlUnlinkNode ( old ) ;
if ( ! xmlAddChild ( if_node , old ) ) {
vshError ( ctl , _ ( " Failed to move '%s' element in xml document " ) , old - > name ) ;
xmlFreeNode ( old ) ;
goto cleanup ;
}
}
}
/* The document should now be fully converted; write it out to a string. */
xmlDocDumpMemory ( xml_doc , & br_xml , & br_xml_size ) ;
if ( ! br_xml | | br_xml_size < = 0 ) {
vshError ( ctl , _ ( " Failed to format new xml document for bridge %s " ) , br_name ) ;
goto cleanup ;
}
/* br_xml is the new interface to define. It will automatically undefine the
* independent original interface .
*/
2015-06-15 19:53:58 +03:00
if ( ! ( br_handle = virInterfaceDefineXML ( priv - > conn , ( char * ) br_xml , 0 ) ) ) {
2012-07-24 12:56:49 +04:00
vshError ( ctl , _ ( " Failed to define new bridge interface %s " ) ,
br_name ) ;
goto cleanup ;
}
2016-11-04 17:22:26 +03:00
vshPrintExtra ( ctl , _ ( " Created bridge %s with attached device %s \n " ) ,
br_name , if_name ) ;
2012-07-24 12:56:49 +04:00
/* start it up unless requested not to */
if ( ! nostart ) {
if ( virInterfaceCreate ( br_handle , 0 ) < 0 ) {
vshError ( ctl , _ ( " Failed to start bridge interface %s " ) , br_name ) ;
goto cleanup ;
}
2016-11-04 17:22:26 +03:00
vshPrintExtra ( ctl , _ ( " Bridge interface %s started \n " ) , br_name ) ;
2012-07-24 12:56:49 +04:00
}
ret = true ;
cleanup :
if ( if_handle )
virInterfaceFree ( if_handle ) ;
if ( br_handle )
virInterfaceFree ( br_handle ) ;
VIR_FREE ( if_xml ) ;
VIR_FREE ( br_xml ) ;
VIR_FREE ( if_type ) ;
VIR_FREE ( if2_name ) ;
VIR_FREE ( delay_str ) ;
xmlXPathFreeContext ( ctxt ) ;
xmlFreeDoc ( xml_doc ) ;
return ret ;
}
/*
* " iface-unbridge " command
*/
static const vshCmdInfo info_interface_unbridge [ ] = {
2013-02-07 19:25:10 +04:00
{ . name = " help " ,
2020-06-17 12:44:39 +03:00
. data = N_ ( " undefine a bridge device after detaching its device(s) " )
2013-02-07 19:25:10 +04:00
} ,
{ . name = " desc " ,
. data = N_ ( " unbridge a network device " )
} ,
{ . name = NULL }
2012-07-24 12:56:49 +04:00
} ;
static const vshCmdOptDef opts_interface_unbridge [ ] = {
2013-01-14 18:24:04 +04:00
{ . name = " bridge " ,
. type = VSH_OT_DATA ,
. flags = VSH_OFLAG_REQ ,
. help = N_ ( " current bridge device name " )
} ,
{ . name = " no-start " ,
. type = VSH_OT_BOOL ,
2020-06-17 12:44:39 +03:00
. help = N_ ( " don't start the detached interface immediately (not recommended) " )
2013-01-14 18:24:04 +04:00
} ,
{ . name = NULL }
2012-07-24 12:56:49 +04:00
} ;
static bool
cmdInterfaceUnbridge ( vshControl * ctl , const vshCmd * cmd )
{
bool ret = false ;
virInterfacePtr if_handle = NULL , br_handle = NULL ;
const char * br_name ;
char * if_type = NULL , * if_name = NULL ;
bool nostart = false ;
char * br_xml = NULL ;
xmlChar * if_xml = NULL ;
int if_xml_size ;
xmlDocPtr xml_doc = NULL ;
xmlXPathContextPtr ctxt = NULL ;
2013-01-15 22:38:18 +04:00
xmlNodePtr top_node , if_node , cur ;
2015-06-15 19:53:58 +03:00
virshControlPtr priv = ctl - > privData ;
2012-07-24 12:56:49 +04:00
/* Get a handle to the original device */
2015-06-15 19:53:58 +03:00
if ( ! ( br_handle = virshCommandOptInterfaceBy ( ctl , cmd , " bridge " ,
& br_name , VIRSH_BYNAME ) ) ) {
2012-07-24 12:56:49 +04:00
goto cleanup ;
}
nostart = vshCommandOptBool ( cmd , " no-start " ) ;
/* Get the bridge xml into an xmlDoc */
if ( ! ( br_xml = virInterfaceGetXMLDesc ( br_handle , VIR_INTERFACE_XML_INACTIVE ) ) )
goto cleanup ;
if ( ! ( xml_doc = virXMLParseStringCtxt ( br_xml ,
_ ( " (bridge interface definition) " ) ,
& ctxt ) ) ) {
vshError ( ctl , _ ( " Failed to parse configuration of %s " ) , br_name ) ;
goto cleanup ;
}
top_node = ctxt - > node ;
/* Verify that the device really is a bridge. */
if ( ! ( if_type = virXMLPropString ( top_node , " type " ) ) ) {
vshError ( ctl , _ ( " Existing device %s has no type " ) , br_name ) ;
goto cleanup ;
}
if ( STRNEQ ( if_type , " bridge " ) ) {
vshError ( ctl , _ ( " Device %s is not a bridge " ) , br_name ) ;
goto cleanup ;
}
VIR_FREE ( if_type ) ;
/* verify the name in the XML matches the device name */
if ( ! ( if_name = virXMLPropString ( top_node , " name " ) ) | |
STRNEQ ( if_name , br_name ) ) {
vshError ( ctl , _ ( " Interface name from config %s doesn't match given supplied name %s " ) ,
if_name , br_name ) ;
goto cleanup ;
}
VIR_FREE ( if_name ) ;
/* Find the <bridge> node under <interface>. */
2013-01-15 22:38:18 +04:00
if ( virXPathNode ( " ./bridge " , ctxt ) = = NULL ) {
2012-07-24 12:56:49 +04:00
vshError ( ctl , " %s " , _ ( " No bridge node in xml document " ) ) ;
goto cleanup ;
}
2013-01-15 22:38:18 +04:00
if ( virXPathNode ( " ./bridge/interface[2] " , ctxt ) ! = NULL ) {
2012-07-24 12:56:49 +04:00
vshError ( ctl , " %s " , _ ( " Multiple interfaces attached to bridge " ) ) ;
goto cleanup ;
}
if ( ! ( if_node = virXPathNode ( " ./bridge/interface " , ctxt ) ) ) {
vshError ( ctl , " %s " , _ ( " No interface attached to bridge " ) ) ;
goto cleanup ;
}
2020-06-17 12:44:39 +03:00
/* Change the type and name of the bridge interface to
* the type / name of the attached interface .
2012-07-24 12:56:49 +04:00
*/
if ( ! ( if_name = virXMLPropString ( if_node , " name " ) ) ) {
vshError ( ctl , _ ( " Device attached to bridge %s has no name " ) , br_name ) ;
goto cleanup ;
}
if ( ! ( if_type = virXMLPropString ( if_node , " type " ) ) ) {
vshError ( ctl , _ ( " Attached device %s has no type " ) , if_name ) ;
goto cleanup ;
}
if ( ! xmlSetProp ( top_node , BAD_CAST " type " , BAD_CAST if_type ) ) {
vshError ( ctl , _ ( " Failed to set interface type to '%s' in xml document " ) ,
if_type ) ;
goto cleanup ;
}
if ( ! xmlSetProp ( top_node , BAD_CAST " name " , BAD_CAST if_name ) ) {
vshError ( ctl , _ ( " Failed to set interface name to '%s' in xml document " ) ,
if_name ) ;
goto cleanup ;
}
/* Cycle through all the nodes under the attached <interface>,
* moving all < mac > , < bond > and < vlan > nodes up into the toplevel
* < interface > .
*/
cur = if_node - > children ;
while ( cur ) {
xmlNodePtr old = cur ;
cur = cur - > next ;
if ( ( old - > type = = XML_ELEMENT_NODE ) & &
2017-08-14 15:31:52 +03:00
( virXMLNodeNameEqual ( old , " mac " ) | | /* ethernet stuff to move down */
virXMLNodeNameEqual ( old , " bond " ) | | /* bond stuff to move down */
virXMLNodeNameEqual ( old , " vlan " ) ) ) { /* vlan stuff to move down */
2012-07-24 12:56:49 +04:00
xmlUnlinkNode ( old ) ;
if ( ! xmlAddChild ( top_node , old ) ) {
vshError ( ctl , _ ( " Failed to move '%s' element in xml document " ) , old - > name ) ;
xmlFreeNode ( old ) ;
goto cleanup ;
}
}
}
/* The document should now be fully converted; write it out to a string. */
xmlDocDumpMemory ( xml_doc , & if_xml , & if_xml_size ) ;
if ( ! if_xml | | if_xml_size < = 0 ) {
2020-06-17 12:44:39 +03:00
vshError ( ctl , _ ( " Failed to format new xml document for detached interface %s " ) ,
2012-07-24 12:56:49 +04:00
if_name ) ;
goto cleanup ;
}
/* Destroy and Undefine the bridge device, since we otherwise
* can ' t safely define the unattached device .
*/
if ( virInterfaceDestroy ( br_handle , 0 ) < 0 ) {
vshError ( ctl , _ ( " Failed to destroy bridge interface %s " ) , br_name ) ;
goto cleanup ;
}
if ( virInterfaceUndefine ( br_handle ) < 0 ) {
vshError ( ctl , _ ( " Failed to undefine bridge interface %s " ) , br_name ) ;
goto cleanup ;
}
/* if_xml is the new interface to define.
*/
2015-06-15 19:53:58 +03:00
if ( ! ( if_handle = virInterfaceDefineXML ( priv - > conn , ( char * ) if_xml , 0 ) ) ) {
2012-07-24 12:56:49 +04:00
vshError ( ctl , _ ( " Failed to define new interface %s " ) , if_name ) ;
goto cleanup ;
}
2016-11-04 17:22:26 +03:00
vshPrintExtra ( ctl , _ ( " Device %s un-attached from bridge %s \n " ) ,
if_name , br_name ) ;
2012-07-24 12:56:49 +04:00
/* unless requested otherwise, undefine the bridge device */
if ( ! nostart ) {
if ( virInterfaceCreate ( if_handle , 0 ) < 0 ) {
vshError ( ctl , _ ( " Failed to start interface %s " ) , if_name ) ;
goto cleanup ;
}
2016-11-04 17:22:26 +03:00
vshPrintExtra ( ctl , _ ( " Interface %s started \n " ) , if_name ) ;
2012-07-24 12:56:49 +04:00
}
ret = true ;
cleanup :
if ( if_handle )
virInterfaceFree ( if_handle ) ;
if ( br_handle )
virInterfaceFree ( br_handle ) ;
VIR_FREE ( if_xml ) ;
VIR_FREE ( br_xml ) ;
VIR_FREE ( if_type ) ;
VIR_FREE ( if_name ) ;
xmlXPathFreeContext ( ctxt ) ;
xmlFreeDoc ( xml_doc ) ;
return ret ;
}
2012-07-23 11:19:04 +04:00
2012-08-21 00:30:53 +04:00
const vshCmdDef ifaceCmds [ ] = {
2013-02-07 19:25:10 +04:00
{ . name = " iface-begin " ,
. handler = cmdInterfaceBegin ,
. opts = opts_interface_begin ,
. info = info_interface_begin ,
. flags = 0
} ,
{ . name = " iface-bridge " ,
. handler = cmdInterfaceBridge ,
. opts = opts_interface_bridge ,
. info = info_interface_bridge ,
. flags = 0
} ,
{ . name = " iface-commit " ,
. handler = cmdInterfaceCommit ,
. opts = opts_interface_commit ,
. info = info_interface_commit ,
. flags = 0
} ,
{ . name = " iface-define " ,
. handler = cmdInterfaceDefine ,
. opts = opts_interface_define ,
. info = info_interface_define ,
. flags = 0
} ,
{ . name = " iface-destroy " ,
. handler = cmdInterfaceDestroy ,
. opts = opts_interface_destroy ,
. info = info_interface_destroy ,
. flags = 0
} ,
{ . name = " iface-dumpxml " ,
. handler = cmdInterfaceDumpXML ,
. opts = opts_interface_dumpxml ,
. info = info_interface_dumpxml ,
. flags = 0
} ,
{ . name = " iface-edit " ,
. handler = cmdInterfaceEdit ,
. opts = opts_interface_edit ,
. info = info_interface_edit ,
. flags = 0
} ,
{ . name = " iface-list " ,
. handler = cmdInterfaceList ,
. opts = opts_interface_list ,
. info = info_interface_list ,
. flags = 0
} ,
{ . name = " iface-mac " ,
. handler = cmdInterfaceMAC ,
. opts = opts_interface_mac ,
. info = info_interface_mac ,
. flags = 0
} ,
{ . name = " iface-name " ,
. handler = cmdInterfaceName ,
. opts = opts_interface_name ,
. info = info_interface_name ,
. flags = 0
} ,
{ . name = " iface-rollback " ,
. handler = cmdInterfaceRollback ,
. opts = opts_interface_rollback ,
. info = info_interface_rollback ,
. flags = 0
} ,
{ . name = " iface-start " ,
. handler = cmdInterfaceStart ,
. opts = opts_interface_start ,
. info = info_interface_start ,
. flags = 0
} ,
{ . name = " iface-unbridge " ,
. handler = cmdInterfaceUnbridge ,
. opts = opts_interface_unbridge ,
. info = info_interface_unbridge ,
. flags = 0
} ,
{ . name = " iface-undefine " ,
. handler = cmdInterfaceUndefine ,
. opts = opts_interface_undefine ,
. info = info_interface_undefine ,
. flags = 0
} ,
{ . name = NULL }
2012-07-23 11:19:04 +04:00
} ;