On Tue, Sep 01, 2015 at 05:06:16PM +0800, Yang Hongyang wrote: > add netfilter_{add|del} commands > This is mostly the same with netdev_{add|del} commands.
The QOM equivalent here is object-add/object-del. > When we delete the netdev, we also delete the netfilter object > attached to it, because if the netdev is removed, the filters > which attached to it is useless. > > Note that the buffer filter will be implemented in the following > patches. > > Signed-off-by: Yang Hongyang <yan...@cn.fujitsu.com> > CC: Luiz Capitulino <lcapitul...@redhat.com> > CC: Markus Armbruster <arm...@redhat.com> > CC: Eric Blake <ebl...@redhat.com> > Reviewed-by: Thomas Huth <th...@redhat.com> > --- > v9: use buffer filter as an example in the command help > cleanup qapi qmp command according to Markus&Eric's comment > v7: error msg fix > move qmp_opts_del() into qemu_del_net_filter() > v6: add multiqueue support (qemu_del_net_filter) > v5: squash "net: delete netfilter object when delete netdev" > --- > hmp-commands.hx | 30 ++++++++++++++++++++++++ > hmp.c | 29 +++++++++++++++++++++++ > hmp.h | 4 ++++ > include/net/filter.h | 2 ++ > monitor.c | 33 ++++++++++++++++++++++++++ > net/filter.c | 65 > +++++++++++++++++++++++++++++++++++++++++++++++++++- > net/net.c | 7 ++++++ > qapi-schema.json | 29 +++++++++++++++++++++++ > qapi/opts-visitor.c | 16 +++++++++++++ > qmp-commands.hx | 55 ++++++++++++++++++++++++++++++++++++++++++++ > 10 files changed, 269 insertions(+), 1 deletion(-) > > diff --git a/hmp-commands.hx b/hmp-commands.hx > index d3b7932..9e5f39d 100644 > --- a/hmp-commands.hx > +++ b/hmp-commands.hx > @@ -1253,6 +1253,36 @@ Remove host network device. > ETEXI > > { > + .name = "netfilter_add", > + .args_type = "netfilter:O", > + .params = > "buffer,id=str,netdev=str[,chain=in|out|all,prop=value][,...]", > + .help = "add netfilter", > + .mhandler.cmd = hmp_netfilter_add, > + .command_completion = netfilter_add_completion, > + }, > + > +STEXI > +@item netfilter_add > +@findex netfilter_add > +Add a netfilter to @var{netdev}, which captures the network packets on > @var{netdev}. > +ETEXI > + > + { > + .name = "netfilter_del", > + .args_type = "id:s", > + .params = "id", > + .help = "remove netfilter", > + .mhandler.cmd = hmp_netfilter_del, > + .command_completion = netfilter_del_completion, > + }, > + > +STEXI > +@item netfilter_del > +@findex netfilter_del > +Remove the netfilter which named @var{id}. > +ETEXI > + > + { > .name = "object_add", > .args_type = "object:O", > .params = "[qom-type=]type,id=str[,prop=value][,...]", > diff --git a/hmp.c b/hmp.c > index dcc66f1..09e3cda 100644 > --- a/hmp.c > +++ b/hmp.c > @@ -15,6 +15,7 @@ > > #include "hmp.h" > #include "net/net.h" > +#include "net/filter.h" > #include "net/eth.h" > #include "sysemu/char.h" > #include "sysemu/block-backend.h" > @@ -1599,6 +1600,34 @@ void hmp_netdev_del(Monitor *mon, const QDict *qdict) > hmp_handle_error(mon, &err); > } > > +void hmp_netfilter_add(Monitor *mon, const QDict *qdict) > +{ > + Error *err = NULL; > + QemuOpts *opts; > + > + opts = qemu_opts_from_qdict(qemu_find_opts("netfilter"), qdict, &err); > + if (err) { > + goto out; > + } > + > + netfilter_add(opts, &err); > + if (err) { > + qemu_opts_del(opts); > + } > + > +out: > + hmp_handle_error(mon, &err); > +} > + > +void hmp_netfilter_del(Monitor *mon, const QDict *qdict) > +{ > + const char *id = qdict_get_str(qdict, "id"); > + Error *err = NULL; > + > + qmp_netfilter_del(id, &err); > + hmp_handle_error(mon, &err); > +} > + > void hmp_object_add(Monitor *mon, const QDict *qdict) > { > Error *err = NULL; > diff --git a/hmp.h b/hmp.h > index 0cf4f2a..a21dbbb 100644 > --- a/hmp.h > +++ b/hmp.h > @@ -85,6 +85,8 @@ void hmp_device_del(Monitor *mon, const QDict *qdict); > void hmp_dump_guest_memory(Monitor *mon, const QDict *qdict); > void hmp_netdev_add(Monitor *mon, const QDict *qdict); > void hmp_netdev_del(Monitor *mon, const QDict *qdict); > +void hmp_netfilter_add(Monitor *mon, const QDict *qdict); > +void hmp_netfilter_del(Monitor *mon, const QDict *qdict); > void hmp_getfd(Monitor *mon, const QDict *qdict); > void hmp_closefd(Monitor *mon, const QDict *qdict); > void hmp_sendkey(Monitor *mon, const QDict *qdict); > @@ -112,6 +114,8 @@ void chardev_add_completion(ReadLineState *rs, int > nb_args, const char *str); > void set_link_completion(ReadLineState *rs, int nb_args, const char *str); > void netdev_add_completion(ReadLineState *rs, int nb_args, const char *str); > void netdev_del_completion(ReadLineState *rs, int nb_args, const char *str); > +void netfilter_add_completion(ReadLineState *rs, int nb_args, const char > *str); > +void netfilter_del_completion(ReadLineState *rs, int nb_args, const char > *str); > void ringbuf_write_completion(ReadLineState *rs, int nb_args, const char > *str); > void watchdog_action_completion(ReadLineState *rs, int nb_args, > const char *str); > diff --git a/include/net/filter.h b/include/net/filter.h > index ce15f15..083083b 100644 > --- a/include/net/filter.h > +++ b/include/net/filter.h > @@ -53,5 +53,7 @@ NetFilterState *qemu_new_net_filter(NetFilterInfo *info, > NetClientState *netdev, > const char *name, > int chain); > +void qemu_del_net_filter(NetFilterState *nf); > +void netfilter_add(QemuOpts *opts, Error **errp); > > #endif /* QEMU_NET_FILTER_H */ > diff --git a/monitor.c b/monitor.c > index fc32f12..10b1f77 100644 > --- a/monitor.c > +++ b/monitor.c > @@ -31,6 +31,7 @@ > #include "hw/loader.h" > #include "exec/gdbstub.h" > #include "net/net.h" > +#include "net/filter.h" > #include "net/slirp.h" > #include "sysemu/char.h" > #include "ui/qemu-spice.h" > @@ -4193,6 +4194,21 @@ void netdev_add_completion(ReadLineState *rs, int > nb_args, const char *str) > } > } > > +void netfilter_add_completion(ReadLineState *rs, int nb_args, const char > *str) > +{ > + size_t len; > + int i; > + > + if (nb_args != 2) { > + return; > + } > + len = strlen(str); > + readline_set_completion_index(rs, len); > + for (i = 0; NetFilterType_lookup[i]; i++) { > + add_completion_option(rs, str, NetFilterType_lookup[i]); > + } > +} > + > void device_add_completion(ReadLineState *rs, int nb_args, const char *str) > { > GSList *list, *elt; > @@ -4429,6 +4445,23 @@ void netdev_del_completion(ReadLineState *rs, int > nb_args, const char *str) > } > } > > +void netfilter_del_completion(ReadLineState *rs, int nb_args, const char > *str) > +{ > + int len; > + QemuOpts *opts; > + > + if (nb_args != 2) { > + return; > + } > + > + len = strlen(str); > + readline_set_completion_index(rs, len); > + opts = qemu_opts_find(qemu_find_opts_err("netfilter", NULL), str); > + if (opts) { > + readline_add_completion(rs, str); > + } > +} > + > void watchdog_action_completion(ReadLineState *rs, int nb_args, const char > *str) > { > int i; > diff --git a/net/filter.c b/net/filter.c > index 89fb089..904e5c7 100644 > --- a/net/filter.c > +++ b/net/filter.c > @@ -13,6 +13,7 @@ > #include "qapi/opts-visitor.h" > #include "qapi/dealloc-visitor.h" > #include "qemu/config-file.h" > +#include "qmp-commands.h" > > #include "net/filter.h" > #include "net/net.h" > @@ -42,7 +43,7 @@ NetFilterState *qemu_new_net_filter(NetFilterInfo *info, > return nf; > } > > -static inline void qemu_cleanup_net_filter(NetFilterState *nf) > +static void qemu_cleanup_net_filter(NetFilterState *nf) > { > QTAILQ_REMOVE(&nf->netdev->filters, nf, next); > QTAILQ_REMOVE(&net_filters, nf, global_list); > @@ -55,6 +56,42 @@ static inline void qemu_cleanup_net_filter(NetFilterState > *nf) > g_free(nf); > } > > +static int qemu_find_netfilters_by_name(const char *id, NetFilterState **nfs, > + int max) > +{ > + NetFilterState *nf; > + int ret = 0; > + > + QTAILQ_FOREACH(nf, &net_filters, global_list) { > + if (!strcmp(nf->name, id)) { > + if (ret < max) { > + nfs[ret] = nf; > + } > + ret++; > + } > + } > + > + return ret; > +} > + > +void qemu_del_net_filter(NetFilterState *nf) > +{ > + NetFilterState *nfs[MAX_QUEUE_NUM]; > + int queues, i; > + QemuOpts *opts; > + > + opts = qemu_opts_find(qemu_find_opts_err("netfilter", NULL), nf->name); > + > + queues = qemu_find_netfilters_by_name(nf->name, nfs, MAX_QUEUE_NUM); > + assert(queues != 0); > + > + for (i = 0; i < queues; i++) { > + qemu_cleanup_net_filter(nfs[i]); > + } > + > + qemu_opts_del(opts); > +} > + > static NetFilterState *qemu_find_netfilter(const char *id) > { > NetFilterState *nf; > @@ -68,6 +105,32 @@ static NetFilterState *qemu_find_netfilter(const char *id) > return NULL; > } > > +static int net_init_filter(void *dummy, QemuOpts *opts, Error **errp); > +void netfilter_add(QemuOpts *opts, Error **errp) > +{ > + net_init_filter(NULL, opts, errp); > +} > + > +static int net_filter_init1(const NetFilter *netfilter, Error **errp); > +void qmp_netfilter_add(NetFilter *data, Error **errp) > +{ > + net_filter_init1(data, errp); > +} > + > +void qmp_netfilter_del(const char *id, Error **errp) > +{ > + NetFilterState *nf; > + > + nf = qemu_find_netfilter(id); > + if (!nf) { > + error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, > + "Filter '%s' not found", id); > + return; > + } > + > + qemu_del_net_filter(nf); > +} > + > typedef int (NetFilterInit)(const NetFilter *netfilter, > const char *name, int chain, > NetClientState *netdev, Error **errp); > diff --git a/net/net.c b/net/net.c > index d9b70cd..74f3592 100644 > --- a/net/net.c > +++ b/net/net.c > @@ -28,6 +28,7 @@ > #include "hub.h" > #include "net/slirp.h" > #include "net/eth.h" > +#include "net/filter.h" > #include "util.h" > > #include "monitor/monitor.h" > @@ -385,6 +386,7 @@ void qemu_del_net_client(NetClientState *nc) > { > NetClientState *ncs[MAX_QUEUE_NUM]; > int queues, i; > + NetFilterState *nf, *next; > > assert(nc->info->type != NET_CLIENT_OPTIONS_KIND_NIC); > > @@ -396,6 +398,11 @@ void qemu_del_net_client(NetClientState *nc) > MAX_QUEUE_NUM); > assert(queues != 0); > > + /* qemu_del_net_filter() will handle the multiqueue case */ > + QTAILQ_FOREACH_SAFE(nf, &nc->filters, next, next) { > + qemu_del_net_filter(nf); > + } > + > /* If there is a peer NIC, delete and cleanup client, but do not free. */ > if (nc->peer && nc->peer->info->type == NET_CLIENT_OPTIONS_KIND_NIC) { > NICState *nic = qemu_get_nic(nc->peer); > diff --git a/qapi-schema.json b/qapi-schema.json > index 750fc00..d961ac8 100644 > --- a/qapi-schema.json > +++ b/qapi-schema.json > @@ -2537,6 +2537,35 @@ > 'opts': 'NetClientOptions' } } > > ## > +# @netfilter-add: > +# > +# Add a netfilter. > +# > +# @data: see NetFilterBase options and specific type's options. > +# > +# Since: 2.5 > +# > +# Returns: Nothing on success > +# If it is not a valid netfilter, DeviceNotFound > +## > +{ 'command': 'netfilter-add', > + 'data': { 'data': 'NetFilter' } } > + > +## > +# @netfilter-del: > +# > +# Remove a netfilter. > +# > +# @id: the name of the netfilter to remove > +# > +# Returns: Nothing on success > +# If @id is not a valid netfilter, DeviceNotFound > +# > +# Since: 2.5 > +## > +{ 'command': 'netfilter-del', 'data': {'id': 'str'} } > + > +## > # @NetFilterDummyOptions: > # > # An dummy filter for network backend > diff --git a/qapi/opts-visitor.c b/qapi/opts-visitor.c > index 7ae33b3..1271fab 100644 > --- a/qapi/opts-visitor.c > +++ b/qapi/opts-visitor.c > @@ -186,6 +186,20 @@ opts_end_struct(Visitor *v, Error **errp) > } > > > +static void opts_start_implicit_struct(Visitor *v, void **obj, > + size_t size, Error **errp) > +{ > + if (obj) { > + *obj = g_malloc0(size); > + } > +} > + > + > +static void opts_end_implicit_struct(Visitor *v, Error **errp) > +{ > +} > + > + > static GQueue * > lookup_distinct(const OptsVisitor *ov, const char *name, Error **errp) > { > @@ -507,6 +521,8 @@ opts_visitor_new(const QemuOpts *opts) > > ov->visitor.start_struct = &opts_start_struct; > ov->visitor.end_struct = &opts_end_struct; > + ov->visitor.start_implicit_struct = &opts_start_implicit_struct; > + ov->visitor.end_implicit_struct = &opts_end_implicit_struct; > > ov->visitor.start_list = &opts_start_list; > ov->visitor.next_list = &opts_next_list; > diff --git a/qmp-commands.hx b/qmp-commands.hx > index ba630b1..bb73806 100644 > --- a/qmp-commands.hx > +++ b/qmp-commands.hx > @@ -926,6 +926,61 @@ Example: > EQMP > > { > + .name = "netfilter-add", > + .args_type = "data:q", > + .mhandler.cmd_new = qmp_marshal_input_netfilter_add, > + }, > + > +SQMP > +netfilter-add > +---------- > + > +Add a netfilter. > + > +Arguments: > + > +- "data": filter options (json-string) > + > +Example: > + > +-> { "execute": "netfilter-add", > + "arguments": { "data": { "type": "buffer", "id": "nf0", > + "netdev": "bn", > + "chain": "in", > + "interval": 1000 } } } > +<- { "return": {} } > + > +Note: The supported filter options are the same ones supported by the > + '-netfilter' command-line argument, which are listed in the '-help' > + output or QEMU's manual > + > +EQMP > + > + { > + .name = "netfilter-del", > + .args_type = "id:s", > + .mhandler.cmd_new = qmp_marshal_input_netfilter_del, > + }, > + > +SQMP > +netfilter-del > +---------- > + > +Remove a netfilter. > + > +Arguments: > + > +- "id": the netfilter's ID, must be unique (json-string) > + > +Example: > + > +-> { "execute": "netfilter_del", "arguments": { "id": "nf0" } } > +<- { "return": {} } > + > + > +EQMP > + > + { > .name = "object-add", > .args_type = "qom-type:s,id:s,props:q?", > .mhandler.cmd_new = qmp_object_add, > -- > 1.9.1 >