[libvirt] [PATCH] Add virsh commands for virInterface* functions.

Laine Stump laine at laine.org
Tue Jun 16 02:56:41 UTC 2009


On 06/15/2009 03:26 PM, Daniel P. Berrange wrote:
> On Fri, Jun 12, 2009 at 10:25:19AM -0400, Laine Stump wrote:
>   
>> I think this is complete (can't really try it out until the test
>> driver is running), but have a few questions about it:
>>
>> 1) Does the command set look complete?
>>
>> 2) Do you agree with the naming (using "if-", and following the
>>    libvirt convention for if-create/if-destroy, rather than the fedora
>>    convention (if-up/if-down)?
>>     
>
> Sigh. I wish we hadn't called our original commands 'net-XXX' as it
> is a rather misleading name.
>
> I think perhaps I'd go slightly longer and suggest  'iface-XXX' as
> the prefix.
>   

Okay.

>   
>> 3) I'm all for eliminating unnecessary copy/paste in code, but the way
>>    that cmdNetworkEdit() and cmdPoolEdit() are created (by
>>    awking/seding virsh.c to create a modified version of the cmdEdit
>>    function that lives in a separate .c which is #included by virsh.c)
>>    seems just a bit convoluted to me. I've made it one step worse for
>>    cmdInterfaceEdit because virInterfaceDefineXML has an extra
>>    argument (flags) that virDomainDefineXML doesn't. What are your
>>    opinions?  Should I continue on in the tradition for consistency's
>>    sake (as I've done in this patch), or manually put
>>    cmdInterfaceEdit() directly into virsh.c?
>>     
>
> Personally I think this auto-generation of network/pool edit commands
> is overkill, and has actually caused bugs in the past.
>   

So it's not just me. I'll pull the generated code into virsh.c then.

>   
>> ---
>>  src/Makefile.am |   18 +++-
>>  src/virsh.c     |  398 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>>  2 files changed, 414 insertions(+), 2 deletions(-)
>>
>> diff --git a/src/Makefile.am b/src/Makefile.am
>> index d4f7ea1..7601611 100644
>> --- a/src/Makefile.am
>> +++ b/src/Makefile.am
>> @@ -585,7 +585,7 @@ virsh_LDADD =							\
>>  		../gnulib/lib/libgnu.la				\
>>  		$(VIRSH_LIBS)
>>  virsh_CFLAGS = $(COVERAGE_CFLAGS) $(READLINE_CFLAGS) $(NUMACTL_CFLAGS)
>> -BUILT_SOURCES = virsh-net-edit.c virsh-pool-edit.c libvirt.syms
>> +BUILT_SOURCES = virsh-net-edit.c virsh-if-edit.c virsh-pool-edit.c libvirt.syms
>>  
>>  virsh-net-edit.c: virsh.c Makefile.am
>>  	rm -f $@-tmp
>> @@ -602,6 +602,22 @@ virsh-net-edit.c: virsh.c Makefile.am
>>  	rm -f $@
>>  	mv $@-tmp $@
>>  
>> +virsh-if-edit.c: virsh.c Makefile.am
>> +	rm -f $@-tmp
>> +	echo '/* Automatically generated from: $^ */' > $@-tmp
>> +	echo 'static int' >> $@-tmp
>> +	awk '/^cmdEdit/, /^}/' $< \
>> +	  | sed -e 's/domain/interface/g' \
>> +	      -e 's/Domain/Interface/g' \
>> +	      -e 's/cmdEdit/cmdInterfaceEdit/g' \
>> +	      -e 's/dom/iface/g' \
>> +	      -e 's/int flags.*/int flags = 0;/g' \
>> +	      -e 's/DefineXML\(.*\))/DefineXML\1, 0)/' \
>> +	>> $@-tmp
>> +	chmod a-w $@-tmp
>> +	rm -f $@
>> +	mv $@-tmp $@
>> +
>>  virsh-pool-edit.c: virsh.c Makefile.am
>>  	rm -f $@-tmp
>>  	echo '/* Automatically generated from: $^ */' > $@-tmp
>> diff --git a/src/virsh.c b/src/virsh.c
>> index f5248d9..6fd090c 100644
>> --- a/src/virsh.c
>> +++ b/src/virsh.c
>> @@ -228,6 +228,7 @@ static int vshCommandOptBool(const vshCmd *cmd, const char *name);
>>  #define VSH_BYID     (1 << 1)
>>  #define VSH_BYUUID   (1 << 2)
>>  #define VSH_BYNAME   (1 << 3)
>> +#define VSH_BYMAC    (1 << 4)
>>  
>>  static virDomainPtr vshCommandOptDomainBy(vshControl *ctl, const vshCmd *cmd,
>>                                            char **name, int flag);
>> @@ -244,6 +245,14 @@ static virNetworkPtr vshCommandOptNetworkBy(vshControl *ctl, const vshCmd *cmd,
>>      vshCommandOptNetworkBy(_ctl, _cmd, _name,                      \
>>                             VSH_BYUUID|VSH_BYNAME)
>>  
>> +static virInterfacePtr vshCommandOptInterfaceBy(vshControl *ctl, const vshCmd *cmd,
>> +                                                char **name, int flag);
>> +
>> +/* default is lookup by Name and MAC */
>> +#define vshCommandOptInterface(_ctl, _cmd, _name)                    \
>> +    vshCommandOptInterfaceBy(_ctl, _cmd, _name,                      \
>> +                           VSH_BYMAC|VSH_BYNAME)
>> +
>>  static virStoragePoolPtr vshCommandOptPoolBy(vshControl *ctl, const vshCmd *cmd,
>>                              const char *optname, char **name, int flag);
>>  
>> @@ -2955,6 +2964,325 @@ cmdNetworkUuid(vshControl *ctl, const vshCmd *cmd)
>>  }
>>  
>>  
>> +/**************************************************************************/
>> +/*
>> + * "if-list" command
>> + */
>> +static const vshCmdInfo info_interface_list[] = {
>> +    {"help", gettext_noop("list physical host interfaces")},
>> +    {"desc", gettext_noop("Returns list of physical host interfaces.")},
>> +    {NULL, NULL}
>> +};
>> +
>> +static int
>> +cmdInterfaceList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
>> +{
>> +    int ifCount = 0, i;
>> +    char **ifNames = NULL;
>> +
>> +    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
>> +        return FALSE;
>> +
>> +    ifCount = virConnectNumOfInterfaces(ctl->conn);
>> +    if (ifCount < 0) {
>> +        vshError(ctl, FALSE, "%s", _("Failed to list interfaces"));
>> +        return FALSE;
>> +    }
>> +    if (ifCount) {
>> +        ifNames = vshMalloc(ctl, sizeof(char *) * ifCount);
>> +
>> +        if ((ifCount = virConnectListInterfaces(ctl->conn,
>> +                                                ifNames, ifCount)) < 0) {
>> +            vshError(ctl, FALSE, "%s", _("Failed to list interfaces"));
>> +            free(ifNames);
>> +            return FALSE;
>> +        }
>> +
>> +        qsort(&ifNames[0], ifCount, sizeof(char *), namesorter);
>> +    }
>> +
>> +    vshPrintExtra(ctl, "%-20s %-30s\n", _("Name"), _("MAC Address"));
>> +    vshPrintExtra(ctl, "--------------------------------------------------\n");
>> +
>> +    for (i = 0; i < ifCount; i++) {
>> +        virInterfacePtr iface = virInterfaceLookupByName(ctl->conn, ifNames[i]);
>> +
>> +        /* this kind of work with interfaces is not atomic operation */
>> +        if (!iface) {
>> +            free(ifNames[i]);
>> +            continue;
>> +        }
>> +
>> +        vshPrint(ctl, "%-20s %-30s\n",
>> +                 virInterfaceGetName(iface),
>> +                 virInterfaceGetMACString(iface));
>> +        virInterfaceFree(iface);
>> +        free(ifNames[i]);
>> +    }
>> +    free(ifNames);
>> +    return TRUE;
>> +}
>>     
>
>
> This one should also take the flags --inactive / --all to allow
> selection of offline NICs vs online NICs. Which reminds me that
> the current public APIs are missing the equivalent for listing
> inactive interfaces. eg, virConnectNumOfDefinedInterfaces and
> virConnectListDefinedInterfaces
>   


They're missing it because netcf is missing it, and I've so far just 
been implementing a conduit to channel netcf functionality through 
libvirt. The problem is that netcf currently interacts with the host OS 
in only two ways: 1) modifying the ifcfg-XXX config files, and 2) 
exec'ing the if-up and if-down scripts, and has nothing to get current 
state of the interface.

I talked to lutter about this and he agrees that this would be useful 
functionality to add to netcf, it just needs a person to do it (I'll 
even volunteer, just not this week!). Possibly we could add a flag now 
to the virConnectListInterfaces() API function in libvirt, in 
anticipation of a similar flag being added to netcf's 
ncf_list_interfaces() function. Is it too late to modify the API? (it is 
in a minor release, but nobody has used it yet. I guess the problem 
would be if someone happened to run libvirt 0.6.4 with an application 
that *did* use the new functions.). (Now I'm wondering why, when we 
thought of adding flags to all those other API functions, we didn't 
think to add flags to this one :-( )

Alternately (or maybe additionally) we can/should add a new function to 
return current state/statistics for interfaces. Along with 
throughput/packet counts, that API could return flags for the interface 
(all the flags shown in the output of ifconfig) as well as the current 
IP address(es). The virsh command could then get the list of interfaces, 
and iterate through looking at the state of each, eliminating the 
interfaces that weren't UP (or DOWN).


>> +
>> +/*
>> + * "if-name" command
>> + */
>> +static const vshCmdInfo info_interface_name[] = {
>> +    {"help", gettext_noop("convert an interface MAC address to interface name")},
>> +    {"desc", ""},
>> +    {NULL, NULL}
>> +};
>> +
>> +static const vshCmdOptDef opts_interface_name[] = {
>> +    {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("interface mac")},
>> +    {NULL, 0, 0, NULL}
>> +};
>> +
>> +static int
>> +cmdInterfaceName(vshControl *ctl, const vshCmd *cmd)
>> +{
>> +    virInterfacePtr iface;
>> +
>> +    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
>> +        return FALSE;
>> +    if (!(iface = vshCommandOptInterfaceBy(ctl, cmd, NULL,
>> +                                           VSH_BYMAC)))
>> +        return FALSE;
>> +
>> +    vshPrint(ctl, "%s\n", virInterfaceGetName(iface));
>> +    virInterfaceFree(iface);
>> +    return TRUE;
>> +}
>> +
>> +/*
>> + * "if-mac" command
>> + */
>> +static const vshCmdInfo info_interface_mac[] = {
>> +    {"help", gettext_noop("convert an interface name to interface MAC address")},
>> +    {"desc", ""},
>> +    {NULL, NULL}
>> +};
>> +
>> +static const vshCmdOptDef opts_interface_mac[] = {
>> +    {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("interface name")},
>> +    {NULL, 0, 0, NULL}
>> +};
>> +
>> +static int
>> +cmdInterfaceMAC(vshControl *ctl, const vshCmd *cmd)
>> +{
>> +    virInterfacePtr iface;
>> +
>> +    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
>> +        return FALSE;
>> +    if (!(iface = vshCommandOptInterfaceBy(ctl, cmd, NULL,
>> +                                           VSH_BYNAME)))
>> +        return FALSE;
>> +
>> +    vshPrint(ctl, "%s\n", virInterfaceGetMACString(iface));
>> +    virInterfaceFree(iface);
>> +    return TRUE;
>> +}
>> +
>> +/*
>> + * "if-dumpxml" command
>> + */
>> +static const vshCmdInfo info_interface_dumpxml[] = {
>> +    {"help", gettext_noop("interface information in XML")},
>> +    {"desc", gettext_noop("Output the physical host interface information as an XML dump to stdout.")},
>> +    {NULL, NULL}
>> +};
>> +
>> +static const vshCmdOptDef opts_interface_dumpxml[] = {
>> +    {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("interface name or MAC address")},
>> +    {NULL, 0, 0, NULL}
>> +};
>> +
>> +static int
>> +cmdInterfaceDumpXML(vshControl *ctl, const vshCmd *cmd)
>> +{
>> +    virInterfacePtr iface;
>> +    int ret = TRUE;
>> +    char *dump;
>> +
>> +    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
>> +        return FALSE;
>> +
>> +    if (!(iface = vshCommandOptInterface(ctl, cmd, NULL)))
>> +        return FALSE;
>> +
>> +    dump = virInterfaceGetXMLDesc(iface, 0);
>> +    if (dump != NULL) {
>> +        printf("%s", dump);
>> +        free(dump);
>> +    } else {
>> +        ret = FALSE;
>> +    }
>> +
>> +    virInterfaceFree(iface);
>> +    return ret;
>> +}
>> +
>> +/*
>> + * "if-define" command
>> + */
>> +static const vshCmdInfo info_interface_define[] = {
>> +    {"help", gettext_noop("define (but don't start) a physical host interface from an XML file")},
>> +    {"desc", gettext_noop("Define a physical host interface.")},
>> +    {NULL, NULL}
>> +};
>> +
>> +static const vshCmdOptDef opts_interface_define[] = {
>> +    {"file", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("file containing an XML interface description")},
>> +    {NULL, 0, 0, NULL}
>> +};
>> +
>> +static int
>> +cmdInterfaceDefine(vshControl *ctl, const vshCmd *cmd)
>> +{
>> +    virInterfacePtr interface;
>> +    char *from;
>> +    int found;
>> +    int ret = TRUE;
>> +    char *buffer;
>> +
>> +    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
>> +        return FALSE;
>> +
>> +    from = vshCommandOptString(cmd, "file", &found);
>> +    if (!found)
>> +        return FALSE;
>> +
>> +    if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
>> +        return FALSE;
>> +
>> +    interface = virInterfaceDefineXML(ctl->conn, buffer, 0);
>> +    free (buffer);
>> +
>> +    if (interface != NULL) {
>> +        vshPrint(ctl, _("Interface %s defined from %s\n"),
>> +                 virInterfaceGetName(interface), from);
>> +    } else {
>> +        vshError(ctl, FALSE, _("Failed to define interface from %s"), from);
>> +        ret = FALSE;
>> +    }
>> +    return ret;
>> +}
>> +
>> +/*
>> + * "if-undefine" command
>> + */
>> +static const vshCmdInfo info_interface_undefine[] = {
>> +    {"help", gettext_noop("undefine a physical host interface (remove it from configuration)")},
>> +    {"desc", gettext_noop("undefine an interface.")},
>> +    {NULL, NULL}
>> +};
>> +
>> +static const vshCmdOptDef opts_interface_undefine[] = {
>> +    {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("interface name or MAC address")},
>> +    {NULL, 0, 0, NULL}
>> +};
>> +
>> +static int
>> +cmdInterfaceUndefine(vshControl *ctl, const vshCmd *cmd)
>> +{
>> +    virInterfacePtr iface;
>> +    int ret = TRUE;
>> +    char *name;
>> +
>> +    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
>> +        return FALSE;
>> +
>> +    if (!(iface = vshCommandOptInterface(ctl, cmd, &name)))
>> +        return FALSE;
>> +
>> +    if (virInterfaceUndefine(iface) == 0) {
>> +        vshPrint(ctl, _("Interface %s undefined\n"), name);
>> +    } else {
>> +        vshError(ctl, FALSE, _("Failed to undefine interface %s"), name);
>> +        ret = FALSE;
>> +    }
>> +
>> +    virInterfaceFree(iface);
>> +    return ret;
>> +}
>> +
>> +/*
>> + * "if-create" command
>> + */
>> +static const vshCmdInfo info_interface_create[] = {
>> +    {"help", gettext_noop("create a physical host interface (enable it / \"if-up\")")},
>> +    {"desc", gettext_noop("create a physical host interface.")},
>> +    {NULL, NULL}
>> +};
>> +
>> +static const vshCmdOptDef opts_interface_create[] = {
>> +    {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("interface name or MAC address")},
>> +    {NULL, 0, 0, NULL}
>> +};
>> +
>> +static int
>> +cmdInterfaceCreate(vshControl *ctl, const vshCmd *cmd)
>> +{
>> +    virInterfacePtr iface;
>> +    int ret = TRUE;
>> +    char *name;
>> +
>> +    if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
>> +        return FALSE;
>> +
>> +    if (!(iface = vshCommandOptInterface(ctl, cmd, &name)))
>> +        return FALSE;
>> +
>> +    if (virInterfaceCreate(iface, 0) == 0) {
>> +        vshPrint(ctl, _("Interface %s created\n"), name);
>> +    } else {
>> +        vshError(ctl, FALSE, _("Failed to create interface %s"), name);
>> +        ret = FALSE;
>> +    }
>> +
>> +    virInterfaceFree(iface);
>> +    return ret;
>> +}
>>     
>
>
> This command should be called 'start' for consistency with other commands.
>
> 'create' is the command name we use for creating a transient object,
> rather than starting a persistent object.
>   

I see what you mean - "net-start" hooks up to virNetworkCreate(), so 
virInterfaceCreate() should be connected to "iface-start". It's a bit 
confusing, though, that the virsh commands don't match the libvirt API 
names. (I guess at least they should *consistently* mismatch! ;-)




More information about the libvir-list mailing list