diff mbox

[02/12] init/cleanup of netfilter object

Message ID 1438167116-29270-3-git-send-email-yanghy@cn.fujitsu.com
State New
Headers show

Commit Message

Yang Hongyang July 29, 2015, 10:51 a.m. UTC
This is mostly the same with init/cleanup of netdev object.

Signed-off-by: Yang Hongyang <yanghy@cn.fujitsu.com>
---
 include/net/filter.h    |  21 ++++++++
 include/qemu/typedefs.h |   1 +
 net/filter.c            | 131 ++++++++++++++++++++++++++++++++++++++++++++++++
 qapi-schema.json        |  30 +++++++++++
 4 files changed, 183 insertions(+)

Comments

Thomas Huth July 29, 2015, 1:33 p.m. UTC | #1
On Wednesday, July 29, 2015 12:51:46 PM,
"Yang Hongyang" <yanghy@cn.fujitsu.com> wrote:
>
> This is mostly the same with init/cleanup of netdev object.
> 
> Signed-off-by: Yang Hongyang <yanghy@cn.fujitsu.com>
> ---
>  include/net/filter.h    |  21 ++++++++
>  include/qemu/typedefs.h |   1 +
>  net/filter.c            | 131
>  ++++++++++++++++++++++++++++++++++++++++++++++++
>  qapi-schema.json        |  30 +++++++++++
>  4 files changed, 183 insertions(+)
> 
[...]
> diff --git a/net/filter.c b/net/filter.c
> index 4e40f08..e6fdc26 100644
> --- a/net/filter.c
> +++ b/net/filter.c
> @@ -6,10 +6,141 @@
>   */
>  
>  #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)
> +{
> +    NetFilterState *nf;
> +
> +    assert(info->size >= sizeof(NetFilterState));
> +
> +    nf = g_malloc0(info->size);
> +    nf->info = info;
> +    nf->model = g_strdup(model);
> +    nf->name = g_strdup(name);
> +    nf->netdev = netdev;
> +    QTAILQ_INSERT_TAIL(&net_filters, nf, next);
> +    /* TODO: attach netfilter to netdev */
> +
> +    return nf;
> +}
> +
> +static __attribute__((unused)) void qemu_cleanup_net_filter(NetFilterState
> *nf)

Maybe rather add this function in the patch you really need it? Then you could
avoid the ugly attribute-unused here.

> +{
> +    /* 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,
> +                            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 NetFilterOptions *opts = netfilter->opts;
> +    int queues;
> +
> +    if (!net_filter_init_fun[opts->kind]) {
> +        error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "type",
> +                   "a net filter type");
> +        return -1;
> +    }
> +
> +    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];
> +
> +

One empty line should be enough.

> +    if (net_filter_init_fun[opts->kind](opts, name, 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;
> +
> +    {

Why the extra curly brackets here? Looks somewhat strange, can you also
do it without?

> +        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 a0a45f7..9a7c107 100644
> --- a/qapi-schema.json
> +++ b/qapi-schema.json
> @@ -2537,6 +2537,36 @@
>      '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.
> +#
> +# @opts: filter type specific properties
> +#
> +# Since 2.5
> +##
> +{ 'struct': 'NetFilter',
> +  'data': {
> +    'id':   'str',
> +    'netdev': 'str',
> +    'opts': 'NetFilterOptions' } }
> +
> +##
>  # @InetSocketAddress
>  #
>  # Captures a socket address or address range in the Internet namespace.

Apart from the nits, the patch looks ok to me.

 Thomas
Yang Hongyang July 29, 2015, 1:50 p.m. UTC | #2
Hi Thomas,
   Thanks for the review.

On 07/29/2015 09:33 PM, Thomas Huth wrote:
> On Wednesday, July 29, 2015 12:51:46 PM,
> "Yang Hongyang" <yanghy@cn.fujitsu.com> wrote:
>>
>> This is mostly the same with init/cleanup of netdev object.
>>
>> Signed-off-by: Yang Hongyang <yanghy@cn.fujitsu.com>
>> ---
>>   include/net/filter.h    |  21 ++++++++
>>   include/qemu/typedefs.h |   1 +
>>   net/filter.c            | 131
>>   ++++++++++++++++++++++++++++++++++++++++++++++++
>>   qapi-schema.json        |  30 +++++++++++
>>   4 files changed, 183 insertions(+)
>>
> [...]
>> diff --git a/net/filter.c b/net/filter.c
>> index 4e40f08..e6fdc26 100644
>> --- a/net/filter.c
>> +++ b/net/filter.c
>> @@ -6,10 +6,141 @@
>>    */
>>
>>   #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)
>> +{
>> +    NetFilterState *nf;
>> +
>> +    assert(info->size >= sizeof(NetFilterState));
>> +
>> +    nf = g_malloc0(info->size);
>> +    nf->info = info;
>> +    nf->model = g_strdup(model);
>> +    nf->name = g_strdup(name);
>> +    nf->netdev = netdev;
>> +    QTAILQ_INSERT_TAIL(&net_filters, nf, next);
>> +    /* TODO: attach netfilter to netdev */
>> +
>> +    return nf;
>> +}
>> +
>> +static __attribute__((unused)) void qemu_cleanup_net_filter(NetFilterState
>> *nf)
>
> Maybe rather add this function in the patch you really need it? Then you could
> avoid the ugly attribute-unused here.

It will be removed in the next patch. I put cleanup here in order to pair with
the new function, and could be easy to review...

>
>> +{
>> +    /* 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,
>> +                            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 NetFilterOptions *opts = netfilter->opts;
>> +    int queues;
>> +
>> +    if (!net_filter_init_fun[opts->kind]) {
>> +        error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "type",
>> +                   "a net filter type");
>> +        return -1;
>> +    }
>> +
>> +    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];
>> +
>> +
>
> One empty line should be enough.

Got, thanks!

>
>> +    if (net_filter_init_fun[opts->kind](opts, name, 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;
>> +
>> +    {
>
> Why the extra curly brackets here? Looks somewhat strange, can you also
> do it without?

actually it is almost the same with net.c, but sure, can remove it in
the next version.

>
>> +        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 a0a45f7..9a7c107 100644
>> --- a/qapi-schema.json
>> +++ b/qapi-schema.json
>> @@ -2537,6 +2537,36 @@
>>       '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.
>> +#
>> +# @opts: filter type specific properties
>> +#
>> +# Since 2.5
>> +##
>> +{ 'struct': 'NetFilter',
>> +  'data': {
>> +    'id':   'str',
>> +    'netdev': 'str',
>> +    'opts': 'NetFilterOptions' } }
>> +
>> +##
>>   # @InetSocketAddress
>>   #
>>   # Captures a socket address or address range in the Internet namespace.
>
> Apart from the nits, the patch looks ok to me.

Thank you.

>
>   Thomas
> .
>
Thomas Huth July 29, 2015, 1:58 p.m. UTC | #3
On Wednesday, July 29, 2015 3:50:02 PM,
"Yang Hongyang" <yanghy@cn.fujitsu.com> wrote:
> 
> On 07/29/2015 09:33 PM, Thomas Huth wrote:
> > On Wednesday, July 29, 2015 12:51:46 PM,
> > "Yang Hongyang" <yanghy@cn.fujitsu.com> wrote:
> >>
> >> This is mostly the same with init/cleanup of netdev object.
> >>
> >> Signed-off-by: Yang Hongyang <yanghy@cn.fujitsu.com>
> >> ---
> >>   include/net/filter.h    |  21 ++++++++
> >>   include/qemu/typedefs.h |   1 +
> >>   net/filter.c            | 131
> >>   ++++++++++++++++++++++++++++++++++++++++++++++++
> >>   qapi-schema.json        |  30 +++++++++++
> >>   4 files changed, 183 insertions(+)
> >>
> > [...]
> >> diff --git a/net/filter.c b/net/filter.c
> >> index 4e40f08..e6fdc26 100644
> >> --- a/net/filter.c
> >> +++ b/net/filter.c
> >> @@ -6,10 +6,141 @@
> >>    */
> >>
> >>   #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)
> >> +{
> >> +    NetFilterState *nf;
> >> +
> >> +    assert(info->size >= sizeof(NetFilterState));
> >> +
> >> +    nf = g_malloc0(info->size);
> >> +    nf->info = info;
> >> +    nf->model = g_strdup(model);
> >> +    nf->name = g_strdup(name);
> >> +    nf->netdev = netdev;
> >> +    QTAILQ_INSERT_TAIL(&net_filters, nf, next);
> >> +    /* TODO: attach netfilter to netdev */
> >> +
> >> +    return nf;
> >> +}
> >> +
> >> +static __attribute__((unused)) void
> >> qemu_cleanup_net_filter(NetFilterState
> >> *nf)
> >
> > Maybe rather add this function in the patch you really need it? Then you
> > could
> > avoid the ugly attribute-unused here.
> 
> It will be removed in the next patch. I put cleanup here in order to pair
> with the new function, and could be easy to review...

You could also use another trick: Use "static inline" instead of "static
__attribute__((unused))" ... then GCC also does not complain about unused
static functions!

 Thomas
Yang Hongyang July 29, 2015, 2:08 p.m. UTC | #4
On 07/29/2015 09:58 PM, Thomas Huth wrote:
> On Wednesday, July 29, 2015 3:50:02 PM,
> "Yang Hongyang" <yanghy@cn.fujitsu.com> wrote:
>>
>> On 07/29/2015 09:33 PM, Thomas Huth wrote:
>>> On Wednesday, July 29, 2015 12:51:46 PM,
>>> "Yang Hongyang" <yanghy@cn.fujitsu.com> wrote:
>>>>
>>>> This is mostly the same with init/cleanup of netdev object.
>>>>
>>>> Signed-off-by: Yang Hongyang <yanghy@cn.fujitsu.com>
>>>> ---
>>>>    include/net/filter.h    |  21 ++++++++
>>>>    include/qemu/typedefs.h |   1 +
>>>>    net/filter.c            | 131
>>>>    ++++++++++++++++++++++++++++++++++++++++++++++++
>>>>    qapi-schema.json        |  30 +++++++++++
>>>>    4 files changed, 183 insertions(+)
>>>>
>>> [...]
>>>> diff --git a/net/filter.c b/net/filter.c
>>>> index 4e40f08..e6fdc26 100644
>>>> --- a/net/filter.c
>>>> +++ b/net/filter.c
>>>> @@ -6,10 +6,141 @@
>>>>     */
>>>>
>>>>    #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)
>>>> +{
>>>> +    NetFilterState *nf;
>>>> +
>>>> +    assert(info->size >= sizeof(NetFilterState));
>>>> +
>>>> +    nf = g_malloc0(info->size);
>>>> +    nf->info = info;
>>>> +    nf->model = g_strdup(model);
>>>> +    nf->name = g_strdup(name);
>>>> +    nf->netdev = netdev;
>>>> +    QTAILQ_INSERT_TAIL(&net_filters, nf, next);
>>>> +    /* TODO: attach netfilter to netdev */
>>>> +
>>>> +    return nf;
>>>> +}
>>>> +
>>>> +static __attribute__((unused)) void
>>>> qemu_cleanup_net_filter(NetFilterState
>>>> *nf)
>>>
>>> Maybe rather add this function in the patch you really need it? Then you
>>> could
>>> avoid the ugly attribute-unused here.
>>
>> It will be removed in the next patch. I put cleanup here in order to pair
>> with the new function, and could be easy to review...
>
> You could also use another trick: Use "static inline" instead of "static
> __attribute__((unused))" ... then GCC also does not complain about unused
> static functions!

Ok, thanks.

>
>   Thomas
> .
>
diff mbox

Patch

diff --git a/include/net/filter.h b/include/net/filter.h
index 4242ded..fa813c4 100644
--- a/include/net/filter.h
+++ b/include/net/filter.h
@@ -9,7 +9,28 @@ 
 #define QEMU_NET_FILTER_H
 
 #include "qemu-common.h"
+#include "qemu/typedefs.h"
+
+typedef void (FilterCleanup) (NetFilterState *);
+
+typedef struct NetFilterInfo {
+    NetFilterOptionsKind type;
+    size_t size;
+    FilterCleanup *cleanup;
+} NetFilterInfo;
+
+struct NetFilterState {
+    NetFilterInfo *info;
+    char *model;
+    char *name;
+    NetClientState *netdev;
+    QTAILQ_ENTRY(NetFilterState) next;
+};
 
 int net_init_filters(void);
+NetFilterState *qemu_new_net_filter(NetFilterInfo *info,
+                                    NetClientState *netdev,
+                                    const char *model,
+                                    const char *name);
 
 #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..e6fdc26 100644
--- a/net/filter.c
+++ b/net/filter.c
@@ -6,10 +6,141 @@ 
  */
 
 #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)
+{
+    NetFilterState *nf;
+
+    assert(info->size >= sizeof(NetFilterState));
+
+    nf = g_malloc0(info->size);
+    nf->info = info;
+    nf->model = g_strdup(model);
+    nf->name = g_strdup(name);
+    nf->netdev = netdev;
+    QTAILQ_INSERT_TAIL(&net_filters, nf, next);
+    /* TODO: attach netfilter to netdev */
+
+    return nf;
+}
+
+static __attribute__((unused)) 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,
+                            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 NetFilterOptions *opts = netfilter->opts;
+    int queues;
+
+    if (!net_filter_init_fun[opts->kind]) {
+        error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "type",
+                   "a net filter type");
+        return -1;
+    }
+
+    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, 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 a0a45f7..9a7c107 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -2537,6 +2537,36 @@ 
     '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.
+#
+# @opts: filter type specific properties
+#
+# Since 2.5
+##
+{ 'struct': 'NetFilter',
+  'data': {
+    'id':   'str',
+    'netdev': 'str',
+    'opts': 'NetFilterOptions' } }
+
+##
 # @InetSocketAddress
 #
 # Captures a socket address or address range in the Internet namespace.