From patchwork Mon Aug 3 08:30:06 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yang Hongyang X-Patchwork-Id: 503047 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 985221402E2 for ; Mon, 3 Aug 2015 18:31:40 +1000 (AEST) Received: from localhost ([::1]:58020 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZMB9m-0006wb-Lm for incoming@patchwork.ozlabs.org; Mon, 03 Aug 2015 04:31:38 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:59773) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZMB92-0005rR-2V for qemu-devel@nongnu.org; Mon, 03 Aug 2015 04:30:53 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ZMB90-00073O-J4 for qemu-devel@nongnu.org; Mon, 03 Aug 2015 04:30:51 -0400 Received: from [59.151.112.132] (port=4678 helo=heian.cn.fujitsu.com) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZMB8y-00071y-PH for qemu-devel@nongnu.org; Mon, 03 Aug 2015 04:30:50 -0400 X-IronPort-AV: E=Sophos;i="5.15,520,1432569600"; d="scan'208";a="99193358" Received: from unknown (HELO edo.cn.fujitsu.com) ([10.167.33.5]) by heian.cn.fujitsu.com with ESMTP; 03 Aug 2015 16:34:01 +0800 Received: from G08CNEXCHPEKD01.g08.fujitsu.local (localhost.localdomain [127.0.0.1]) by edo.cn.fujitsu.com (8.14.3/8.13.1) with ESMTP id t738ScJw024937; Mon, 3 Aug 2015 16:28:38 +0800 Received: from localhost (10.167.226.223) by G08CNEXCHPEKD01.g08.fujitsu.local (10.167.33.89) with Microsoft SMTP Server (TLS) id 14.3.181.6; Mon, 3 Aug 2015 16:30:30 +0800 From: Yang Hongyang To: Date: Mon, 3 Aug 2015 16:30:06 +0800 Message-ID: <1438590616-21142-3-git-send-email-yanghy@cn.fujitsu.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1438590616-21142-1-git-send-email-yanghy@cn.fujitsu.com> References: <1438590616-21142-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, dgilbert@redhat.com, mrhines@linux.vnet.ibm.com, stefanha@redhat.com, Yang Hongyang Subject: [Qemu-devel] [PATCH v3 02/12] 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 This is mostly the same with init/cleanup of netdev object. Signed-off-by: Yang Hongyang --- include/net/filter.h | 38 +++++++++++++ include/qemu/typedefs.h | 1 + net/filter.c | 148 ++++++++++++++++++++++++++++++++++++++++++++++++ qapi-schema.json | 37 ++++++++++++ 4 files changed, 224 insertions(+) diff --git a/include/net/filter.h b/include/net/filter.h index 4242ded..dee265a 100644 --- a/include/net/filter.h +++ b/include/net/filter.h @@ -9,7 +9,45 @@ #define QEMU_NET_FILTER_H #include "qemu-common.h" +#include "qemu/typedefs.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 *, NetClientState *sender, + unsigned flags, const struct iovec *, int); + +typedef struct NetFilterInfo { + NetFilterOptionsKind type; + size_t size; + FilterCleanup *cleanup; + FilterReceiveIOV *receive_iov; +} NetFilterInfo; + +struct NetFilterState { + NetFilterInfo *info; + char *model; + char *name; + NetClientState *netdev; + int chain; + QTAILQ_ENTRY(NetFilterState) next; +}; int net_init_filters(void); +NetFilterState *qemu_new_net_filter(NetFilterInfo *info, + NetClientState *netdev, + const char *model, + const char *name, + int chain); #endif /* QEMU_NET_FILTER_H */ diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h index 6fdcbcd..2f75109 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..4ffa572 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 *model, + 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->model = g_strdup(model); + nf->name = g_strdup(name); + nf->netdev = netdev; + nf->chain = chain; + QTAILQ_INSERT_TAIL(&net_filters, nf, next); + /* TODO: attach netfilter to netdev */ + + return nf; +} + +static inline void qemu_cleanup_net_filter(NetFilterState *nf) +{ + /* TODO: remove netfilter from netdev */ + + QTAILQ_REMOVE(&net_filters, nf, next); + + if (nf->info->cleanup) { + nf->info->cleanup(nf); + } + + g_free(nf->name); + g_free(nf->model); + 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 *netdev = NULL; + 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; + + 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, "multiqueues is not supported by now"); + return -1; + } else if (queues < 1) { + error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "netdev", + "a network backend id"); + return -1; + } + + netdev = ncs[0]; + + if (net_filter_init_fun[opts->kind](opts, name, chain, netdev, 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); + } + + error_propagate(errp, 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/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.