[libvirt] [PATCH v2 10/21] virsh: add nwfilter binding commands

Daniel P. Berrangé berrange at redhat.com
Tue May 15 17:43:26 UTC 2018


$ 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 at 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




More information about the libvir-list mailing list