virsh: add nwfilter binding commands

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

Reviewed-by: John Ferlan <jferlan@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
This commit is contained in:
Daniel P. Berrangé 2018-05-09 17:44:35 +01:00
parent ede0924eb4
commit 278659fff6
4 changed files with 374 additions and 0 deletions

View File

@ -473,6 +473,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,

View File

@ -66,6 +66,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);

View File

@ -443,6 +443,299 @@ 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));
int ret;
bool success = false;
virshControlPtr priv = ctl->privData;
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 > 1)
qsort(list->bindings, list->nbindings,
sizeof(*list->bindings), virshNWFilterBindingSorter);
success = true;
cleanup:
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, " %-20s %-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 +767,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}
};

View File

@ -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 */