$ 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@xxxxxxxxxx> --- 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list