libvirt/tools/virsh-nwfilter.c

483 lines
12 KiB
C

/*
* virsh-nwfilter.c: Commands to manage network filters
*
* Copyright (C) 2005, 2007-2014 Red Hat, Inc.
*
* 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/>.
*
* Daniel Veillard <veillard@redhat.com>
* Karel Zak <kzak@redhat.com>
* Daniel P. Berrange <berrange@redhat.com>
*
*/
#include <config.h>
#include "virsh-nwfilter.h"
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xpath.h>
#include <libxml/xmlsave.h>
#include "internal.h"
#include "virbuffer.h"
#include "viralloc.h"
#include "virfile.h"
#include "virutil.h"
#include "virxml.h"
virNWFilterPtr
vshCommandOptNWFilterBy(vshControl *ctl, const vshCmd *cmd,
const char **name, unsigned int flags)
{
virNWFilterPtr nwfilter = NULL;
const char *n = NULL;
const char *optname = "nwfilter";
virCheckFlags(VSH_BYUUID | VSH_BYNAME, NULL);
if (!vshCmdHasOption(ctl, cmd, optname))
return NULL;
if (vshCommandOptStringReq(ctl, cmd, optname, &n) < 0)
return NULL;
vshDebug(ctl, VSH_ERR_INFO, "%s: found option <%s>: %s\n",
cmd->def->name, optname, n);
if (name)
*name = n;
/* try it by UUID */
if ((flags & VSH_BYUUID) && strlen(n) == VIR_UUID_STRING_BUFLEN-1) {
vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as nwfilter UUID\n",
cmd->def->name, optname);
nwfilter = virNWFilterLookupByUUIDString(ctl->conn, n);
}
/* try it by NAME */
if (!nwfilter && (flags & VSH_BYNAME)) {
vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as nwfilter NAME\n",
cmd->def->name, optname);
nwfilter = virNWFilterLookupByName(ctl->conn, n);
}
if (!nwfilter)
vshError(ctl, _("failed to get nwfilter '%s'"), n);
return nwfilter;
}
/*
* "nwfilter-define" command
*/
static const vshCmdInfo info_nwfilter_define[] = {
{.name = "help",
.data = N_("define or update a network filter from an XML file")
},
{.name = "desc",
.data = N_("Define a new network filter or update an existing one.")
},
{.name = NULL}
};
static const vshCmdOptDef opts_nwfilter_define[] = {
{.name = "file",
.type = VSH_OT_DATA,
.flags = VSH_OFLAG_REQ,
.help = N_("file containing an XML network filter description")
},
{.name = NULL}
};
static bool
cmdNWFilterDefine(vshControl *ctl, const vshCmd *cmd)
{
virNWFilterPtr nwfilter;
const char *from = NULL;
bool ret = true;
char *buffer;
if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0)
return false;
if (virFileReadAll(from, VSH_MAX_XML_FILE, &buffer) < 0)
return false;
nwfilter = virNWFilterDefineXML(ctl->conn, buffer);
VIR_FREE(buffer);
if (nwfilter != NULL) {
vshPrint(ctl, _("Network filter %s defined from %s\n"),
virNWFilterGetName(nwfilter), from);
virNWFilterFree(nwfilter);
} else {
vshError(ctl, _("Failed to define network filter from %s"), from);
ret = false;
}
return ret;
}
/*
* "nwfilter-undefine" command
*/
static const vshCmdInfo info_nwfilter_undefine[] = {
{.name = "help",
.data = N_("undefine a network filter")
},
{.name = "desc",
.data = N_("Undefine a given network filter.")
},
{.name = NULL}
};
static const vshCmdOptDef opts_nwfilter_undefine[] = {
{.name = "nwfilter",
.type = VSH_OT_DATA,
.flags = VSH_OFLAG_REQ,
.help = N_("network filter name or uuid")
},
{.name = NULL}
};
static bool
cmdNWFilterUndefine(vshControl *ctl, const vshCmd *cmd)
{
virNWFilterPtr nwfilter;
bool ret = true;
const char *name;
if (!(nwfilter = vshCommandOptNWFilter(ctl, cmd, &name)))
return false;
if (virNWFilterUndefine(nwfilter) == 0) {
vshPrint(ctl, _("Network filter %s undefined\n"), name);
} else {
vshError(ctl, _("Failed to undefine network filter %s"), name);
ret = false;
}
virNWFilterFree(nwfilter);
return ret;
}
/*
* "nwfilter-dumpxml" command
*/
static const vshCmdInfo info_nwfilter_dumpxml[] = {
{.name = "help",
.data = N_("network filter information in XML")
},
{.name = "desc",
.data = N_("Output the network filter information as an XML dump to stdout.")
},
{.name = NULL}
};
static const vshCmdOptDef opts_nwfilter_dumpxml[] = {
{.name = "nwfilter",
.type = VSH_OT_DATA,
.flags = VSH_OFLAG_REQ,
.help = N_("network filter name or uuid")
},
{.name = NULL}
};
static bool
cmdNWFilterDumpXML(vshControl *ctl, const vshCmd *cmd)
{
virNWFilterPtr nwfilter;
bool ret = true;
char *dump;
if (!(nwfilter = vshCommandOptNWFilter(ctl, cmd, NULL)))
return false;
dump = virNWFilterGetXMLDesc(nwfilter, 0);
if (dump != NULL) {
vshPrint(ctl, "%s", dump);
VIR_FREE(dump);
} else {
ret = false;
}
virNWFilterFree(nwfilter);
return ret;
}
static int
vshNWFilterSorter(const void *a, const void *b)
{
virNWFilterPtr *fa = (virNWFilterPtr *) a;
virNWFilterPtr *fb = (virNWFilterPtr *) b;
if (*fa && !*fb)
return -1;
if (!*fa)
return *fb != NULL;
return vshStrcasecmp(virNWFilterGetName(*fa),
virNWFilterGetName(*fb));
}
struct vshNWFilterList {
virNWFilterPtr *filters;
size_t nfilters;
};
typedef struct vshNWFilterList *vshNWFilterListPtr;
static void
vshNWFilterListFree(vshNWFilterListPtr list)
{
size_t i;
if (list && list->filters) {
for (i = 0; i < list->nfilters; i++) {
if (list->filters[i])
virNWFilterFree(list->filters[i]);
}
VIR_FREE(list->filters);
}
VIR_FREE(list);
}
static vshNWFilterListPtr
vshNWFilterListCollect(vshControl *ctl,
unsigned int flags)
{
vshNWFilterListPtr list = vshMalloc(ctl, sizeof(*list));
size_t i;
int ret;
virNWFilterPtr filter;
bool success = false;
size_t deleted = 0;
int nfilters = 0;
char **names = NULL;
/* try the list with flags support (0.10.2 and later) */
if ((ret = virConnectListAllNWFilters(ctl->conn,
&list->filters,
flags)) >= 0) {
list->nfilters = ret;
goto finished;
}
/* check if the command is actually supported */
if (last_error && last_error->code == VIR_ERR_NO_SUPPORT) {
vshResetLibvirtError();
goto fallback;
}
/* there was an error during the call */
vshError(ctl, "%s", _("Failed to list node filters"));
goto cleanup;
fallback:
/* fall back to old method (0.9.13 and older) */
vshResetLibvirtError();
nfilters = virConnectNumOfNWFilters(ctl->conn);
if (nfilters < 0) {
vshError(ctl, "%s", _("Failed to count network filters"));
goto cleanup;
}
if (nfilters == 0)
return list;
names = vshMalloc(ctl, sizeof(char *) * nfilters);
nfilters = virConnectListNWFilters(ctl->conn, names, nfilters);
if (nfilters < 0) {
vshError(ctl, "%s", _("Failed to list network filters"));
goto cleanup;
}
list->filters = vshMalloc(ctl, sizeof(virNWFilterPtr) * nfilters);
list->nfilters = 0;
/* get the network filters */
for (i = 0; i < nfilters; i++) {
if (!(filter = virNWFilterLookupByName(ctl->conn, names[i])))
continue;
list->filters[list->nfilters++] = filter;
}
/* truncate network filters that weren't found */
deleted = nfilters - list->nfilters;
finished:
/* sort the list */
if (list->filters && list->nfilters)
qsort(list->filters, list->nfilters,
sizeof(*list->filters), vshNWFilterSorter);
/* truncate the list for not found filter objects */
if (deleted)
VIR_SHRINK_N(list->filters, list->nfilters, deleted);
success = true;
cleanup:
for (i = 0; nfilters != -1 && i < nfilters; i++)
VIR_FREE(names[i]);
VIR_FREE(names);
if (!success) {
vshNWFilterListFree(list);
list = NULL;
}
return list;
}
/*
* "nwfilter-list" command
*/
static const vshCmdInfo info_nwfilter_list[] = {
{.name = "help",
.data = N_("list network filters")
},
{.name = "desc",
.data = N_("Returns list of network filters.")
},
{.name = NULL}
};
static const vshCmdOptDef opts_nwfilter_list[] = {
{.name = NULL}
};
static bool
cmdNWFilterList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
{
size_t i;
char uuid[VIR_UUID_STRING_BUFLEN];
vshNWFilterListPtr list = NULL;
if (!(list = vshNWFilterListCollect(ctl, 0)))
return false;
vshPrintExtra(ctl, " %-36s %-20s \n", _("UUID"), _("Name"));
vshPrintExtra(ctl, "---------------------------------"
"---------------------------------\n");
for (i = 0; i < list->nfilters; i++) {
virNWFilterPtr nwfilter = list->filters[i];
virNWFilterGetUUIDString(nwfilter, uuid);
vshPrint(ctl, " %-36s %-20s\n",
uuid,
virNWFilterGetName(nwfilter));
}
vshNWFilterListFree(list);
return true;
}
/*
* "nwfilter-edit" command
*/
static const vshCmdInfo info_nwfilter_edit[] = {
{.name = "help",
.data = N_("edit XML configuration for a network filter")
},
{.name = "desc",
.data = N_("Edit the XML configuration for a network filter.")
},
{.name = NULL}
};
static const vshCmdOptDef opts_nwfilter_edit[] = {
{.name = "nwfilter",
.type = VSH_OT_DATA,
.flags = VSH_OFLAG_REQ,
.help = N_("network filter name or uuid")
},
{.name = NULL}
};
static bool
cmdNWFilterEdit(vshControl *ctl, const vshCmd *cmd)
{
bool ret = false;
virNWFilterPtr nwfilter = NULL;
virNWFilterPtr nwfilter_edited = NULL;
nwfilter = vshCommandOptNWFilter(ctl, cmd, NULL);
if (nwfilter == NULL)
goto cleanup;
#define EDIT_GET_XML virNWFilterGetXMLDesc(nwfilter, 0)
#define EDIT_NOT_CHANGED \
do { \
vshPrint(ctl, _("Network filter %s XML " \
"configuration not changed.\n"), \
virNWFilterGetName(nwfilter)); \
ret = true; \
goto edit_cleanup; \
} while (0)
#define EDIT_DEFINE \
(nwfilter_edited = virNWFilterDefineXML(ctl->conn, doc_edited))
#include "virsh-edit.c"
vshPrint(ctl, _("Network filter %s XML configuration edited.\n"),
virNWFilterGetName(nwfilter_edited));
ret = true;
cleanup:
if (nwfilter)
virNWFilterFree(nwfilter);
if (nwfilter_edited)
virNWFilterFree(nwfilter_edited);
return ret;
}
const vshCmdDef nwfilterCmds[] = {
{.name = "nwfilter-define",
.handler = cmdNWFilterDefine,
.opts = opts_nwfilter_define,
.info = info_nwfilter_define,
.flags = 0
},
{.name = "nwfilter-dumpxml",
.handler = cmdNWFilterDumpXML,
.opts = opts_nwfilter_dumpxml,
.info = info_nwfilter_dumpxml,
.flags = 0
},
{.name = "nwfilter-edit",
.handler = cmdNWFilterEdit,
.opts = opts_nwfilter_edit,
.info = info_nwfilter_edit,
.flags = 0
},
{.name = "nwfilter-list",
.handler = cmdNWFilterList,
.opts = opts_nwfilter_list,
.info = info_nwfilter_list,
.flags = 0
},
{.name = "nwfilter-undefine",
.handler = cmdNWFilterUndefine,
.opts = opts_nwfilter_undefine,
.info = info_nwfilter_undefine,
.flags = 0
},
{.name = NULL}
};