From patchwork Fri Aug 21 04:43: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: 509289 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 D95EF1402AD for ; Fri, 21 Aug 2015 14:45:15 +1000 (AEST) Received: from localhost ([::1]:39732 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZSeCX-0005qI-W8 for incoming@patchwork.ozlabs.org; Fri, 21 Aug 2015 00:45:14 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:39199) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZSeBq-0004s2-Jy for qemu-devel@nongnu.org; Fri, 21 Aug 2015 00:44:32 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ZSeBp-0000Xi-40 for qemu-devel@nongnu.org; Fri, 21 Aug 2015 00:44:30 -0400 Received: from [59.151.112.132] (port=22348 helo=heian.cn.fujitsu.com) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZSeBo-0000VS-67 for qemu-devel@nongnu.org; Fri, 21 Aug 2015 00:44:29 -0400 X-IronPort-AV: E=Sophos;i="5.15,520,1432569600"; d="scan'208";a="99874165" Received: from unknown (HELO edo.cn.fujitsu.com) ([10.167.33.5]) by heian.cn.fujitsu.com with ESMTP; 21 Aug 2015 12:47:41 +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 t7L4iMx0013789; Fri, 21 Aug 2015 12:44:22 +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; Fri, 21 Aug 2015 12:44:26 +0800 From: Yang Hongyang To: Date: Fri, 21 Aug 2015 12:43:16 +0800 Message-ID: <1440132205-7814-3-git-send-email-yanghy@cn.fujitsu.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1440132205-7814-1-git-send-email-yanghy@cn.fujitsu.com> References: <1440132205-7814-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, mrhines@linux.vnet.ibm.com, stefanha@redhat.com, Yang Hongyang Subject: [Qemu-devel] [PATCH v7 RESEND 02/11] init/cleanup of netfilter object 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 QTAILQ_ENTRY global_list but used by filter layer, so that we can manage all filters together. QTAILQ_ENTRY next used by netdev, filter belongs to the specific netdev is in this queue. This is mostly the same with init/cleanup of netdev object. Signed-off-by: Yang Hongyang --- v7: add check for vhost fix error propagate bug v6: add multiqueue support (net_filter_init1) v5: remove model from NetFilterState add a sent_cb param to receive_iov API --- include/net/filter.h | 42 ++++++++++++++ include/net/net.h | 1 + include/qemu/typedefs.h | 1 + net/filter.c | 148 ++++++++++++++++++++++++++++++++++++++++++++++++ net/net.c | 1 + qapi-schema.json | 37 ++++++++++++ 6 files changed, 230 insertions(+) diff --git a/include/net/filter.h b/include/net/filter.h index 4242ded..7a858d8 100644 --- a/include/net/filter.h +++ b/include/net/filter.h @@ -9,7 +9,49 @@ #define QEMU_NET_FILTER_H #include "qemu-common.h" +#include "qemu/typedefs.h" +#include "net/queue.h" + +/* the netfilter chain */ +enum { + NET_FILTER_IN, + NET_FILTER_OUT, + NET_FILTER_ALL, +}; + +typedef void (FilterCleanup) (NetFilterState *); +/* + * Return: + * 0: finished handling the packet, we should continue + * size: filter stolen this packet, we stop pass this packet further + */ +typedef ssize_t (FilterReceiveIOV)(NetFilterState *nc, + NetClientState *sender, + unsigned flags, + const struct iovec *iov, + int iovcnt, + NetPacketSent *sent_cb); + +typedef struct NetFilterInfo { + NetFilterOptionsKind type; + size_t size; + FilterCleanup *cleanup; + FilterReceiveIOV *receive_iov; +} NetFilterInfo; + +struct NetFilterState { + NetFilterInfo *info; + char *name; + NetClientState *netdev; + int chain; + QTAILQ_ENTRY(NetFilterState) global_list; + QTAILQ_ENTRY(NetFilterState) next; +}; int net_init_filters(void); +NetFilterState *qemu_new_net_filter(NetFilterInfo *info, + NetClientState *netdev, + const char *name, + int chain); #endif /* QEMU_NET_FILTER_H */ diff --git a/include/net/net.h b/include/net/net.h index 6a6cbef..36e5fab 100644 --- a/include/net/net.h +++ b/include/net/net.h @@ -92,6 +92,7 @@ struct NetClientState { NetClientDestructor *destructor; unsigned int queue_index; unsigned rxfilter_notify_enabled:1; + QTAILQ_HEAD(, NetFilterState) filters; }; typedef struct NICState { diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h index f8a9dd6..2c0648f 100644 --- a/include/qemu/typedefs.h +++ b/include/qemu/typedefs.h @@ -45,6 +45,7 @@ typedef struct Monitor Monitor; typedef struct MouseTransformInfo MouseTransformInfo; typedef struct MSIMessage MSIMessage; typedef struct NetClientState NetClientState; +typedef struct NetFilterState NetFilterState; typedef struct NICInfo NICInfo; typedef struct PcGuestInfo PcGuestInfo; typedef struct PCIBridge PCIBridge; diff --git a/net/filter.c b/net/filter.c index 4e40f08..9183cd8 100644 --- a/net/filter.c +++ b/net/filter.c @@ -6,10 +6,158 @@ */ #include "qemu-common.h" +#include "qapi-visit.h" +#include "qapi/qmp/qerror.h" +#include "qemu/error-report.h" +#include "qapi-visit.h" +#include "qapi/opts-visitor.h" +#include "qapi/dealloc-visitor.h" +#include "qemu/config-file.h" + #include "net/filter.h" +#include "net/net.h" + +static QTAILQ_HEAD(, NetFilterState) net_filters; + +NetFilterState *qemu_new_net_filter(NetFilterInfo *info, + NetClientState *netdev, + const char *name, + int chain) +{ + NetFilterState *nf; + + assert(info->size >= sizeof(NetFilterState)); + assert(info->receive_iov); + + nf = g_malloc0(info->size); + nf->info = info; + nf->name = g_strdup(name); + nf->netdev = netdev; + nf->chain = chain; + QTAILQ_INSERT_TAIL(&net_filters, nf, global_list); + QTAILQ_INSERT_TAIL(&netdev->filters, nf, next); + + return nf; +} + +static inline void qemu_cleanup_net_filter(NetFilterState *nf) +{ + QTAILQ_REMOVE(&nf->netdev->filters, nf, next); + QTAILQ_REMOVE(&net_filters, nf, global_list); + + if (nf->info->cleanup) { + nf->info->cleanup(nf); + } + + g_free(nf->name); + g_free(nf); +} + +typedef int (NetFilterInit)(const NetFilterOptions *opts, + const char *name, int chain, + NetClientState *netdev, Error **errp); + +static +NetFilterInit * const net_filter_init_fun[NET_FILTER_OPTIONS_KIND_MAX] = { +}; + +static int net_filter_init1(const NetFilter *netfilter, Error **errp) +{ + NetClientState *ncs[MAX_QUEUE_NUM]; + const char *name = netfilter->id; + const char *netdev_id = netfilter->netdev; + const char *chain_str = NULL; + const NetFilterOptions *opts = netfilter->opts; + int chain, queues, i; + + if (!net_filter_init_fun[opts->kind]) { + error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "type", + "a net filter type"); + return -1; + } + + if (netfilter->has_chain) { + chain_str = netfilter->chain; + if (!strcmp(chain_str, "in")) { + chain = NET_FILTER_IN; + } else if (!strcmp(chain_str, "out")) { + chain = NET_FILTER_OUT; + } else if (!strcmp(chain_str, "all")) { + chain = NET_FILTER_ALL; + } else { + error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "chain", + "netfilter chain (in/out/all)"); + return -1; + } + } else { + /* default */ + chain = NET_FILTER_ALL; + } + + queues = qemu_find_net_clients_except(netdev_id, ncs, + NET_CLIENT_OPTIONS_KIND_NIC, + MAX_QUEUE_NUM); + if (queues < 1) { + error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "netdev", + "a network backend id"); + return -1; + } + + if (get_vhost_net(ncs[0])) { + error_setg(errp, "vhost is not supported"); + return -1; + } + + for (i = 0; i < queues; i++) { + if (net_filter_init_fun[opts->kind](opts, name, + chain, ncs[i], errp) < 0) { + if (errp && !*errp) { + error_setg(errp, QERR_DEVICE_INIT_FAILED, + NetFilterOptionsKind_lookup[opts->kind]); + } + return -1; + } + } + + return 0; +} + +static int net_init_filter(void *dummy, QemuOpts *opts, Error **errp) +{ + NetFilter *object = NULL; + Error *err = NULL; + int ret = -1; + OptsVisitor *ov = opts_visitor_new(opts); + + visit_type_NetFilter(opts_get_visitor(ov), &object, NULL, &err); + opts_visitor_cleanup(ov); + + if (!err) { + ret = net_filter_init1(object, &err); + } + + if (object) { + QapiDeallocVisitor *dv = qapi_dealloc_visitor_new(); + + visit_type_NetFilter(qapi_dealloc_get_visitor(dv), &object, NULL, NULL); + qapi_dealloc_visitor_cleanup(dv); + } + + if (err) { + error_report_err(err); + } + return ret; +} int net_init_filters(void) { + QTAILQ_INIT(&net_filters); + + if (qemu_opts_foreach(qemu_find_opts("netfilter"), + net_init_filter, NULL, NULL)) { + return -1; + } + return 0; } diff --git a/net/net.c b/net/net.c index 28a5597..d9b70cd 100644 --- a/net/net.c +++ b/net/net.c @@ -287,6 +287,7 @@ static void qemu_net_client_setup(NetClientState *nc, nc->incoming_queue = qemu_new_net_queue(nc); nc->destructor = destructor; + QTAILQ_INIT(&nc->filters); } NetClientState *qemu_new_net_client(NetClientInfo *info, diff --git a/qapi-schema.json b/qapi-schema.json index 4342a08..d7fb578 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -2537,6 +2537,43 @@ 'opts': 'NetClientOptions' } } ## +# @NetFilterOptions +# +# A discriminated record of network filters. +# +# Since 2.5 +# +## +{ 'union': 'NetFilterOptions', + 'data': { } } + +## +# @NetFilter +# +# Captures the packets of a network backend. +# +# @id: identifier for monitor commands +# +# @netdev: the network backend it attached to +# +# @chain: #optional accept "in","out","all", if not specified, default is "all" +# "in" means this filter will receive packets sent to the @netdev +# "out" means this filter will receive packets sent from the @netdev +# "all" means this filter will receive packets both sent to/from +# the @netdev +# +# @opts: filter type specific properties +# +# Since 2.5 +## +{ 'struct': 'NetFilter', + 'data': { + 'id': 'str', + 'netdev': 'str', + '*chain': 'str', + 'opts': 'NetFilterOptions' } } + +## # @InetSocketAddress # # Captures a socket address or address range in the Internet namespace.