From patchwork Tue Sep 1 09:06:16 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yang Hongyang X-Patchwork-Id: 512739 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 21CB114076C for ; Tue, 1 Sep 2015 19:07:40 +1000 (AEST) Received: from localhost ([::1]:51685 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZWhXW-0006Us-AS for incoming@patchwork.ozlabs.org; Tue, 01 Sep 2015 05:07:38 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:45054) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZWhWl-0005C0-CT for qemu-devel@nongnu.org; Tue, 01 Sep 2015 05:06:53 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ZWhWi-0000Xv-0B for qemu-devel@nongnu.org; Tue, 01 Sep 2015 05:06:51 -0400 Received: from [59.151.112.132] (port=42047 helo=heian.cn.fujitsu.com) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZWhWh-0000SE-4I for qemu-devel@nongnu.org; Tue, 01 Sep 2015 05:06:47 -0400 X-IronPort-AV: E=Sophos;i="5.15,520,1432569600"; d="scan'208";a="100234388" Received: from bogon (HELO edo.cn.fujitsu.com) ([10.167.33.5]) by heian.cn.fujitsu.com with ESMTP; 01 Sep 2015 17:09:42 +0800 Received: from G08CNEXCHPEKD02.g08.fujitsu.local (localhost.localdomain [127.0.0.1]) by edo.cn.fujitsu.com (8.14.3/8.13.1) with ESMTP id t8196Srr028895; Tue, 1 Sep 2015 17:06:28 +0800 Received: from localhost (10.167.226.223) by G08CNEXCHPEKD02.g08.fujitsu.local (10.167.33.89) with Microsoft SMTP Server (TLS) id 14.3.181.6; Tue, 1 Sep 2015 17:06:36 +0800 From: Yang Hongyang To: Date: Tue, 1 Sep 2015 17:06:16 +0800 Message-ID: <1441098383-22585-4-git-send-email-yanghy@cn.fujitsu.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1441098383-22585-1-git-send-email-yanghy@cn.fujitsu.com> References: <1441098383-22585-1-git-send-email-yanghy@cn.fujitsu.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 59.151.112.132 Cc: thuth@redhat.com, zhang.zhanghailiang@huawei.com, lizhijian@cn.fujitsu.com, jasowang@redhat.com, armbru@redhat.com, mrhines@linux.vnet.ibm.com, Luiz Capitulino , stefanha@redhat.com, Yang Hongyang Subject: [Qemu-devel] [PATCH v9 03/10] netfilter: add netfilter_{add|del} commands X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org add netfilter_{add|del} commands This is mostly the same with netdev_{add|del} commands. 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 CC: Luiz Capitulino CC: Markus Armbruster CC: Eric Blake Reviewed-by: Thomas Huth --- 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,