$ virsh nwfilter-binding-list
Port Dev Filter
------------------------------------------------------------------
vnet0 clean-traffic
vnet1 clean-traffic
$ virsh nwfilter-binding-dumpxml vnet1
<filterbinding>
<owner>
<name>f25arm7</name>
<uuid>12ac8b8c-4f23-4248-ae42-fdcd50c400fd</uuid>
</owner>
<portdev name='vnet1'/>
<mac address='52:54:00:9d:81:b1'/>
<filterref filter='clean-traffic'>
<parameter name='MAC' value='52:54:00:9d:81:b1'/>
</filterref>
</filterbinding>
Signed-off-by: Daniel P. Berrangé <berrange(a)redhat.com>
---
tools/virsh-completer.c | 45 ++++++
tools/virsh-completer.h | 4 +
tools/virsh-nwfilter.c | 318 ++++++++++++++++++++++++++++++++++++++++
tools/virsh-nwfilter.h | 8 +
4 files changed, 375 insertions(+)
diff --git a/tools/virsh-completer.c b/tools/virsh-completer.c
index e3b8234b41..b1737130b4 100644
--- a/tools/virsh-completer.c
+++ b/tools/virsh-completer.c
@@ -427,6 +427,51 @@ virshNWFilterNameCompleter(vshControl *ctl,
}
+char **
+virshNWFilterBindingNameCompleter(vshControl *ctl,
+ const vshCmd *cmd ATTRIBUTE_UNUSED,
+ unsigned int flags)
+{
+ virshControlPtr priv = ctl->privData;
+ virNWFilterBindingPtr *bindings = NULL;
+ int nbindings = 0;
+ size_t i = 0;
+ char **ret = NULL;
+
+ virCheckFlags(0, NULL);
+
+ if (!priv->conn || virConnectIsAlive(priv->conn) <= 0)
+ return NULL;
+
+ if ((nbindings = virConnectListAllNWFilterBindings(priv->conn, &bindings,
flags)) < 0)
+ return NULL;
+
+ if (VIR_ALLOC_N(ret, nbindings + 1) < 0)
+ goto error;
+
+ for (i = 0; i < nbindings; i++) {
+ const char *name = virNWFilterBindingGetPortDev(bindings[i]);
+
+ if (VIR_STRDUP(ret[i], name) < 0)
+ goto error;
+
+ virNWFilterBindingFree(bindings[i]);
+ }
+ VIR_FREE(bindings);
+
+ return ret;
+
+ error:
+ for (; i < nbindings; i++)
+ virNWFilterBindingFree(bindings[i]);
+ VIR_FREE(bindings);
+ for (i = 0; i < nbindings; i++)
+ VIR_FREE(ret[i]);
+ VIR_FREE(ret);
+ return NULL;
+}
+
+
char **
virshSecretUUIDCompleter(vshControl *ctl,
const vshCmd *cmd ATTRIBUTE_UNUSED,
diff --git a/tools/virsh-completer.h b/tools/virsh-completer.h
index fa443d3ad7..3abced765c 100644
--- a/tools/virsh-completer.h
+++ b/tools/virsh-completer.h
@@ -62,6 +62,10 @@ char ** virshNWFilterNameCompleter(vshControl *ctl,
const vshCmd *cmd,
unsigned int flags);
+char ** virshNWFilterBindingNameCompleter(vshControl *ctl,
+ const vshCmd *cmd,
+ unsigned int flags);
+
char ** virshSecretUUIDCompleter(vshControl *ctl,
const vshCmd *cmd,
unsigned int flags);
diff --git a/tools/virsh-nwfilter.c b/tools/virsh-nwfilter.c
index 06a002dffd..881afc5dda 100644
--- a/tools/virsh-nwfilter.c
+++ b/tools/virsh-nwfilter.c
@@ -443,6 +443,300 @@ cmdNWFilterEdit(vshControl *ctl, const vshCmd *cmd)
return ret;
}
+virNWFilterBindingPtr
+virshCommandOptNWFilterBindingBy(vshControl *ctl, const vshCmd *cmd,
+ const char **name, unsigned int flags)
+{
+ virNWFilterBindingPtr binding = NULL;
+ const char *n = NULL;
+ const char *optname = "binding";
+ virshControlPtr priv = ctl->privData;
+
+ virCheckFlags(0, 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;
+
+ vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as nwfilter binding port
dev\n",
+ cmd->def->name, optname);
+ binding = virNWFilterBindingLookupByPortDev(priv->conn, n);
+
+ if (!binding)
+ vshError(ctl, _("failed to get nwfilter binding '%s'"), n);
+
+ return binding;
+}
+
+/*
+ * "nwfilter-binding-create" command
+ */
+static const vshCmdInfo info_nwfilter_binding_create[] = {
+ {.name = "help",
+ .data = N_("create a network filter binding from an XML file")
+ },
+ {.name = "desc",
+ .data = N_("Create a new network filter binding.")
+ },
+ {.name = NULL}
+};
+
+static const vshCmdOptDef opts_nwfilter_binding_create[] = {
+ VIRSH_COMMON_OPT_FILE(N_("file containing an XML network "
+ "filter binding description")),
+ {.name = NULL}
+};
+
+static bool
+cmdNWFilterBindingCreate(vshControl *ctl, const vshCmd *cmd)
+{
+ virNWFilterBindingPtr binding;
+ const char *from = NULL;
+ bool ret = true;
+ char *buffer;
+ virshControlPtr priv = ctl->privData;
+
+ if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0)
+ return false;
+
+ if (virFileReadAll(from, VSH_MAX_XML_FILE, &buffer) < 0)
+ return false;
+
+ binding = virNWFilterBindingCreateXML(priv->conn, buffer, 0);
+ VIR_FREE(buffer);
+
+ if (binding != NULL) {
+ vshPrintExtra(ctl, _("Network filter binding on %s created from
%s\n"),
+ virNWFilterBindingGetPortDev(binding), from);
+ virNWFilterBindingFree(binding);
+ } else {
+ vshError(ctl, _("Failed to create network filter from %s"), from);
+ ret = false;
+ }
+ return ret;
+}
+
+/*
+ * "nwfilter-binding-delete" command
+ */
+static const vshCmdInfo info_nwfilter_binding_delete[] = {
+ {.name = "help",
+ .data = N_("delete a network filter binding")
+ },
+ {.name = "desc",
+ .data = N_("Delete a given network filter binding.")
+ },
+ {.name = NULL}
+};
+
+static const vshCmdOptDef opts_nwfilter_binding_delete[] = {
+ {.name = "binding",
+ .type = VSH_OT_DATA,
+ .flags = VSH_OFLAG_REQ,
+ .help = N_("network filter binding port dev"),
+ .completer = virshNWFilterBindingNameCompleter,
+ },
+ {.name = NULL}
+};
+
+static bool
+cmdNWFilterBindingDelete(vshControl *ctl, const vshCmd *cmd)
+{
+ virNWFilterBindingPtr binding;
+ bool ret = true;
+ const char *portdev;
+
+ if (!(binding = virshCommandOptNWFilterBinding(ctl, cmd, &portdev)))
+ return false;
+
+ if (virNWFilterBindingDelete(binding) == 0) {
+ vshPrintExtra(ctl, _("Network filter binding on %s deleted\n"),
portdev);
+ } else {
+ vshError(ctl, _("Failed to delete network filter binding on %s"),
portdev);
+ ret = false;
+ }
+
+ virNWFilterBindingFree(binding);
+ return ret;
+}
+
+/*
+ * "nwfilter-binding-dumpxml" command
+ */
+static const vshCmdInfo info_nwfilter_binding_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_binding_dumpxml[] = {
+ {.name = "binding",
+ .type = VSH_OT_DATA,
+ .flags = VSH_OFLAG_REQ,
+ .help = N_("network filter binding portdev"),
+ .completer = virshNWFilterBindingNameCompleter,
+ },
+ {.name = NULL}
+};
+
+static bool
+cmdNWFilterBindingDumpXML(vshControl *ctl, const vshCmd *cmd)
+{
+ virNWFilterBindingPtr binding;
+ bool ret = true;
+ char *dump;
+
+ if (!(binding = virshCommandOptNWFilterBinding(ctl, cmd, NULL)))
+ return false;
+
+ dump = virNWFilterBindingGetXMLDesc(binding, 0);
+ if (dump != NULL) {
+ vshPrint(ctl, "%s", dump);
+ VIR_FREE(dump);
+ } else {
+ ret = false;
+ }
+
+ virNWFilterBindingFree(binding);
+ return ret;
+}
+
+static int
+virshNWFilterBindingSorter(const void *a, const void *b)
+{
+ virNWFilterBindingPtr *fa = (virNWFilterBindingPtr *) a;
+ virNWFilterBindingPtr *fb = (virNWFilterBindingPtr *) b;
+
+ if (*fa && !*fb)
+ return -1;
+
+ if (!*fa)
+ return *fb != NULL;
+
+ return vshStrcasecmp(virNWFilterBindingGetPortDev(*fa),
+ virNWFilterBindingGetPortDev(*fb));
+}
+
+struct virshNWFilterBindingList {
+ virNWFilterBindingPtr *bindings;
+ size_t nbindings;
+};
+typedef struct virshNWFilterBindingList *virshNWFilterBindingListPtr;
+
+static void
+virshNWFilterBindingListFree(virshNWFilterBindingListPtr list)
+{
+ size_t i;
+
+ if (list && list->bindings) {
+ for (i = 0; i < list->nbindings; i++) {
+ if (list->bindings[i])
+ virNWFilterBindingFree(list->bindings[i]);
+ }
+ VIR_FREE(list->bindings);
+ }
+ VIR_FREE(list);
+}
+
+static virshNWFilterBindingListPtr
+virshNWFilterBindingListCollect(vshControl *ctl,
+ unsigned int flags)
+{
+ virshNWFilterBindingListPtr list = vshMalloc(ctl, sizeof(*list));
+ size_t i;
+ int ret;
+ bool success = false;
+ size_t deleted = 0;
+ int nbindings = 0;
+ char **names = NULL;
+ virshControlPtr priv = ctl->privData;
+
+ /* try the list with flags support (0.10.2 and later) */
+ if ((ret = virConnectListAllNWFilterBindings(priv->conn,
+ &list->bindings,
+ flags)) < 0) {
+ /* there was an error during the call */
+ vshError(ctl, "%s", _("Failed to list network filter
bindings"));
+ goto cleanup;
+ }
+
+ list->nbindings = ret;
+
+ /* sort the list */
+ if (list->bindings && list->nbindings)
+ qsort(list->bindings, list->nbindings,
+ sizeof(*list->bindings), virshNWFilterBindingSorter);
+
+ /* truncate the list for not found filter objects */
+ if (deleted)
+ VIR_SHRINK_N(list->bindings, list->nbindings, deleted);
+
+ success = true;
+
+ cleanup:
+ for (i = 0; nbindings != -1 && i < nbindings; i++)
+ VIR_FREE(names[i]);
+ VIR_FREE(names);
+
+ if (!success) {
+ virshNWFilterBindingListFree(list);
+ list = NULL;
+ }
+
+ return list;
+}
+
+/*
+ * "nwfilter-binding-list" command
+ */
+static const vshCmdInfo info_nwfilter_binding_list[] = {
+ {.name = "help",
+ .data = N_("list network filter bindings")
+ },
+ {.name = "desc",
+ .data = N_("Returns list of network filter bindings.")
+ },
+ {.name = NULL}
+};
+
+static const vshCmdOptDef opts_nwfilter_binding_list[] = {
+ {.name = NULL}
+};
+
+static bool
+cmdNWFilterBindingList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
+{
+ size_t i;
+ virshNWFilterBindingListPtr list = NULL;
+
+ if (!(list = virshNWFilterBindingListCollect(ctl, 0)))
+ return false;
+
+ vshPrintExtra(ctl, " %-36s %-20s \n", _("Port Dev"),
_("Filter"));
+ vshPrintExtra(ctl, "---------------------------------"
+ "---------------------------------\n");
+
+ for (i = 0; i < list->nbindings; i++) {
+ virNWFilterBindingPtr binding = list->bindings[i];
+
+ vshPrint(ctl, " %-20s %-20s\n",
+ virNWFilterBindingGetPortDev(binding),
+ virNWFilterBindingGetFilterName(binding));
+ }
+
+ virshNWFilterBindingListFree(list);
+ return true;
+}
+
const vshCmdDef nwfilterCmds[] = {
{.name = "nwfilter-define",
.handler = cmdNWFilterDefine,
@@ -474,5 +768,29 @@ const vshCmdDef nwfilterCmds[] = {
.info = info_nwfilter_undefine,
.flags = 0
},
+ {.name = "nwfilter-binding-create",
+ .handler = cmdNWFilterBindingCreate,
+ .opts = opts_nwfilter_binding_create,
+ .info = info_nwfilter_binding_create,
+ .flags = 0
+ },
+ {.name = "nwfilter-binding-delete",
+ .handler = cmdNWFilterBindingDelete,
+ .opts = opts_nwfilter_binding_delete,
+ .info = info_nwfilter_binding_delete,
+ .flags = 0
+ },
+ {.name = "nwfilter-binding-dumpxml",
+ .handler = cmdNWFilterBindingDumpXML,
+ .opts = opts_nwfilter_binding_dumpxml,
+ .info = info_nwfilter_binding_dumpxml,
+ .flags = 0
+ },
+ {.name = "nwfilter-binding-list",
+ .handler = cmdNWFilterBindingList,
+ .opts = opts_nwfilter_binding_list,
+ .info = info_nwfilter_binding_list,
+ .flags = 0
+ },
{.name = NULL}
};
diff --git a/tools/virsh-nwfilter.h b/tools/virsh-nwfilter.h
index 2b76a7c849..d8ca0e3960 100644
--- a/tools/virsh-nwfilter.h
+++ b/tools/virsh-nwfilter.h
@@ -32,11 +32,19 @@ virNWFilterPtr
virshCommandOptNWFilterBy(vshControl *ctl, const vshCmd *cmd,
const char **name, unsigned int flags);
+virNWFilterBindingPtr
+virshCommandOptNWFilterBindingBy(vshControl *ctl, const vshCmd *cmd,
+ const char **name, unsigned int flags);
+
/* default is lookup by Name and UUID */
# define virshCommandOptNWFilter(_ctl, _cmd, _name) \
virshCommandOptNWFilterBy(_ctl, _cmd, _name, \
VIRSH_BYUUID | VIRSH_BYNAME)
+/* default is lookup by port dev */
+# define virshCommandOptNWFilterBinding(_ctl, _cmd, _name) \
+ virshCommandOptNWFilterBindingBy(_ctl, _cmd, _name, 0)
+
extern const vshCmdDef nwfilterCmds[];
#endif /* VIRSH_NWFILTER_H */
--
2.17.0