* [Qemu-devel] [PATCH v6 00/10] For QEMU 2.5: Add a netfilter object and netbuffer filter
@ 2015-08-07 2:46 Yang Hongyang
2015-08-07 2:46 ` [Qemu-devel] [PATCH v6 01/10] net: add a new object netfilter Yang Hongyang
` (10 more replies)
0 siblings, 11 replies; 20+ messages in thread
From: Yang Hongyang @ 2015-08-07 2:46 UTC (permalink / raw)
To: qemu-devel
Cc: thuth, zhang.zhanghailiang, lizhijian, jasowang, mrhines,
stefanha, Yang Hongyang
Add multiqueue support in v6.
This patch add a new object netfilter, capture all network packets.
Also implement a netbuffer based on this object.
the "buffer" netfilter could be used by VM FT solutions like
MicroCheckpointing, to buffer/release packets. Or to simulate
packet delay.
You can also get the series from:
https://github.com/macrosheep/qemu/tree/netfilter-v6
Usage:
-netdev tap,id=bn0
-netfilter buffer,id=f0,netdev=bn0,chain=in,interval=1000
-device e1000,netdev=bn0
dynamically add/remove netfilters:
netfilter_add buffer,id=f0,netdev=bn0,chain=in,interval=1000
netfilter_del f0
NOTE:
interval's scale is microsecond.
chain is optional, and is one of in|out|all, 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
TODO:
- dump
v6:
- add multiqueue support, please see individual patch for detail
v5:
- add a sent_cb param to filter receive_iov api
- squash the 4th patch into patch 3
- remove dummy sent_cb (buffer filter)
- addressed Jason's other comments, see individual patches for detail
v4:
- get rid of struct Filter
- squash the 4th patch into patch 2
- fix qemu_netfilter_pass_to_next_iov
- get rid of bh (buffer filter)
- release the packet to next filter instead of to receiver (buffer filter)
v3:
- add an api to pass the packet to next filter
- remove netfilters when delete netdev
- add qtest testcases for netfilter
- addressed comments from Jason
v2:
- add a chain option to netfilter object
- move the hook place earlier, before net_queue_send
- drop the unused api in buffer filter
- squash buffer filter patches into one
- remove receive() api from netfilter, only receive_iov() is enough
- addressed comments from Jason&Thomas
v1:
initial patch.
Yang Hongyang (10):
net: add a new object netfilter
init/cleanup of netfilter object
netfilter: add netfilter_{add|del} commands
netfilter: hook packets before net queue send
move out net queue structs define
netfilter: add an API to pass the packet to next filter
net/queue: export qemu_net_queue_append_iov
netfilter: add a netbuffer filter
filter/buffer: update command description and help
tests: add test cases for netfilter object
hmp-commands.hx | 30 +++++
hmp.c | 29 +++++
hmp.h | 4 +
include/net/filter.h | 63 ++++++++++
include/net/net.h | 1 +
include/net/queue.h | 26 +++++
include/qemu/typedefs.h | 1 +
include/sysemu/sysemu.h | 1 +
monitor.c | 33 ++++++
net/Makefile.objs | 2 +
net/filter-buffer.c | 126 ++++++++++++++++++++
net/filter.c | 302 ++++++++++++++++++++++++++++++++++++++++++++++++
net/filters.h | 17 +++
net/net.c | 77 ++++++++++++
net/queue.c | 31 +----
qapi-schema.json | 100 ++++++++++++++++
qemu-options.hx | 4 +
qmp-commands.hx | 57 +++++++++
tests/.gitignore | 1 +
tests/Makefile | 2 +
tests/test-netfilter.c | 194 +++++++++++++++++++++++++++++++
vl.c | 13 +++
22 files changed, 1089 insertions(+), 25 deletions(-)
create mode 100644 include/net/filter.h
create mode 100644 net/filter-buffer.c
create mode 100644 net/filter.c
create mode 100644 net/filters.h
create mode 100644 tests/test-netfilter.c
--
1.9.1
^ permalink raw reply [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH v6 01/10] net: add a new object netfilter
2015-08-07 2:46 [Qemu-devel] [PATCH v6 00/10] For QEMU 2.5: Add a netfilter object and netbuffer filter Yang Hongyang
@ 2015-08-07 2:46 ` Yang Hongyang
2015-08-07 2:46 ` [Qemu-devel] [PATCH v6 02/10] init/cleanup of netfilter object Yang Hongyang
` (9 subsequent siblings)
10 siblings, 0 replies; 20+ messages in thread
From: Yang Hongyang @ 2015-08-07 2:46 UTC (permalink / raw)
To: qemu-devel
Cc: thuth, zhang.zhanghailiang, lizhijian, jasowang, mrhines,
stefanha, Paolo Bonzini, Yang Hongyang
Add the framework for a new netfilter object and a new
-netfilter CLI option as a basis for the following patches.
Signed-off-by: Yang Hongyang <yanghy@cn.fujitsu.com>
CC: Paolo Bonzini <pbonzini@redhat.com>
CC: Eric Blake <eblake@redhat.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
---
include/net/filter.h | 15 +++++++++++++++
include/sysemu/sysemu.h | 1 +
net/Makefile.objs | 1 +
net/filter.c | 27 +++++++++++++++++++++++++++
qemu-options.hx | 1 +
vl.c | 13 +++++++++++++
6 files changed, 58 insertions(+)
create mode 100644 include/net/filter.h
create mode 100644 net/filter.c
diff --git a/include/net/filter.h b/include/net/filter.h
new file mode 100644
index 0000000..4242ded
--- /dev/null
+++ b/include/net/filter.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2015 FUJITSU LIMITED
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * later. See the COPYING file in the top-level directory.
+ */
+
+#ifndef QEMU_NET_FILTER_H
+#define QEMU_NET_FILTER_H
+
+#include "qemu-common.h"
+
+int net_init_filters(void);
+
+#endif /* QEMU_NET_FILTER_H */
diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index 44570d1..15d6d00 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -212,6 +212,7 @@ extern QemuOptsList qemu_chardev_opts;
extern QemuOptsList qemu_device_opts;
extern QemuOptsList qemu_netdev_opts;
extern QemuOptsList qemu_net_opts;
+extern QemuOptsList qemu_netfilter_opts;
extern QemuOptsList qemu_global_opts;
extern QemuOptsList qemu_mon_opts;
diff --git a/net/Makefile.objs b/net/Makefile.objs
index ec19cb3..914aec0 100644
--- a/net/Makefile.objs
+++ b/net/Makefile.objs
@@ -13,3 +13,4 @@ common-obj-$(CONFIG_HAIKU) += tap-haiku.o
common-obj-$(CONFIG_SLIRP) += slirp.o
common-obj-$(CONFIG_VDE) += vde.o
common-obj-$(CONFIG_NETMAP) += netmap.o
+common-obj-y += filter.o
diff --git a/net/filter.c b/net/filter.c
new file mode 100644
index 0000000..4e40f08
--- /dev/null
+++ b/net/filter.c
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2015 FUJITSU LIMITED
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * later. See the COPYING file in the top-level directory.
+ */
+
+#include "qemu-common.h"
+#include "net/filter.h"
+
+int net_init_filters(void)
+{
+ return 0;
+}
+
+QemuOptsList qemu_netfilter_opts = {
+ .name = "netfilter",
+ .implied_opt_name = "type",
+ .head = QTAILQ_HEAD_INITIALIZER(qemu_netfilter_opts.head),
+ .desc = {
+ /*
+ * no elements => accept any params
+ * validation will happen later
+ */
+ { /* end of list */ }
+ },
+};
diff --git a/qemu-options.hx b/qemu-options.hx
index 77f5853..0d52d02 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1575,6 +1575,7 @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
"socket][,vlan=n][,option][,option][,...]\n"
" old way to initialize a host network interface\n"
" (use the -netdev option if possible instead)\n", QEMU_ARCH_ALL)
+DEF("netfilter", HAS_ARG, QEMU_OPTION_netfilter, "", QEMU_ARCH_ALL)
STEXI
@item -net nic[,vlan=@var{n}][,macaddr=@var{mac}][,model=@var{type}] [,name=@var{name}][,addr=@var{addr}][,vectors=@var{v}]
@findex -net
diff --git a/vl.c b/vl.c
index 0adbbd6..3b70371 100644
--- a/vl.c
+++ b/vl.c
@@ -75,6 +75,7 @@ int main(int argc, char **argv)
#include "monitor/qdev.h"
#include "sysemu/bt.h"
#include "net/net.h"
+#include "net/filter.h"
#include "net/slirp.h"
#include "monitor/monitor.h"
#include "ui/console.h"
@@ -2998,6 +2999,7 @@ int main(int argc, char **argv, char **envp)
qemu_add_opts(&qemu_device_opts);
qemu_add_opts(&qemu_netdev_opts);
qemu_add_opts(&qemu_net_opts);
+ qemu_add_opts(&qemu_netfilter_opts);
qemu_add_opts(&qemu_rtc_opts);
qemu_add_opts(&qemu_global_opts);
qemu_add_opts(&qemu_mon_opts);
@@ -3284,6 +3286,13 @@ int main(int argc, char **argv, char **envp)
exit(1);
}
break;
+ case QEMU_OPTION_netfilter:
+ opts = qemu_opts_parse_noisily(qemu_find_opts("netfilter"),
+ optarg, true);
+ if (!opts) {
+ exit(1);
+ }
+ break;
#ifdef CONFIG_LIBISCSI
case QEMU_OPTION_iscsi:
opts = qemu_opts_parse_noisily(qemu_find_opts("iscsi"),
@@ -4413,6 +4422,10 @@ int main(int argc, char **argv, char **envp)
exit(1);
}
+ if (net_init_filters() < 0) {
+ exit(1);
+ }
+
#ifdef CONFIG_TPM
if (tpm_init() < 0) {
exit(1);
--
1.9.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH v6 02/10] init/cleanup of netfilter object
2015-08-07 2:46 [Qemu-devel] [PATCH v6 00/10] For QEMU 2.5: Add a netfilter object and netbuffer filter Yang Hongyang
2015-08-07 2:46 ` [Qemu-devel] [PATCH v6 01/10] net: add a new object netfilter Yang Hongyang
@ 2015-08-07 2:46 ` Yang Hongyang
2015-08-10 9:18 ` Jason Wang
2015-08-07 2:46 ` [Qemu-devel] [PATCH v6 03/10] netfilter: add netfilter_{add|del} commands Yang Hongyang
` (8 subsequent siblings)
10 siblings, 1 reply; 20+ messages in thread
From: Yang Hongyang @ 2015-08-07 2:46 UTC (permalink / raw)
To: qemu-devel
Cc: thuth, zhang.zhanghailiang, lizhijian, jasowang, mrhines,
stefanha, Yang Hongyang
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 <yanghy@cn.fujitsu.com>
---
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 | 141 ++++++++++++++++++++++++++++++++++++++++++++++++
net/net.c | 1 +
qapi-schema.json | 37 +++++++++++++
6 files changed, 223 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 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..0d12abf 100644
--- a/net/filter.c
+++ b/net/filter.c
@@ -6,10 +6,151 @@
*/
#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;
+ }
+
+ 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);
+ }
+
+ 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/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.
--
1.9.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH v6 03/10] netfilter: add netfilter_{add|del} commands
2015-08-07 2:46 [Qemu-devel] [PATCH v6 00/10] For QEMU 2.5: Add a netfilter object and netbuffer filter Yang Hongyang
2015-08-07 2:46 ` [Qemu-devel] [PATCH v6 01/10] net: add a new object netfilter Yang Hongyang
2015-08-07 2:46 ` [Qemu-devel] [PATCH v6 02/10] init/cleanup of netfilter object Yang Hongyang
@ 2015-08-07 2:46 ` Yang Hongyang
2015-08-10 9:20 ` Jason Wang
2015-08-11 7:07 ` Wen Congyang
2015-08-07 2:46 ` [Qemu-devel] [PATCH v6 04/10] netfilter: hook packets before net queue send Yang Hongyang
` (7 subsequent siblings)
10 siblings, 2 replies; 20+ messages in thread
From: Yang Hongyang @ 2015-08-07 2:46 UTC (permalink / raw)
To: qemu-devel
Cc: thuth, zhang.zhanghailiang, lizhijian, jasowang,
Markus Armbruster, mrhines, Luiz Capitulino, stefanha,
Yang Hongyang
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.
Signed-off-by: Yang Hongyang <yanghy@cn.fujitsu.com>
CC: Luiz Capitulino <lcapitulino@redhat.com>
CC: Markus Armbruster <armbru@redhat.com>
CC: Eric Blake <eblake@redhat.com>
---
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 | 3 ++
monitor.c | 33 +++++++++++++++++
net/filter.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++-
net/net.c | 10 +++++
qapi-schema.json | 47 ++++++++++++++++++++++++
qmp-commands.hx | 57 +++++++++++++++++++++++++++++
9 files changed, 313 insertions(+), 1 deletion(-)
diff --git a/hmp-commands.hx b/hmp-commands.hx
index d3b7932..902e2d1 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 = "[type],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 netfilter.
+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 netfilter.
+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 7a858d8..f15d83d 100644
--- a/include/net/filter.h
+++ b/include/net/filter.h
@@ -53,5 +53,8 @@ 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);
+void qmp_netfilter_add(QDict *qdict, QObject **ret, Error **errp);
#endif /* QEMU_NET_FILTER_H */
diff --git a/monitor.c b/monitor.c
index aeea2b5..d6b8f24 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; NetFilterOptionsKind_lookup[i]; i++) {
+ add_completion_option(rs, str, NetFilterOptionsKind_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 0d12abf..1b9ad67 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"
@@ -40,7 +41,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);
@@ -53,6 +54,104 @@ 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;
+
+ 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]);
+ }
+}
+
+static NetFilterState *qemu_find_netfilter(const char *id)
+{
+ NetFilterState *nf;
+
+ QTAILQ_FOREACH(nf, &net_filters, global_list) {
+ if (!strcmp(nf->name, id)) {
+ return nf;
+ }
+ }
+
+ 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);
+}
+
+void qmp_netfilter_add(QDict *qdict, QObject **ret, Error **errp)
+{
+ Error *local_err = NULL;
+ QemuOptsList *opts_list;
+ QemuOpts *opts;
+
+ opts_list = qemu_find_opts_err("netfilter", &local_err);
+ if (local_err) {
+ goto out;
+ }
+
+ opts = qemu_opts_from_qdict(opts_list, qdict, &local_err);
+ if (local_err) {
+ goto out;
+ }
+
+ netfilter_add(opts, &local_err);
+ if (local_err) {
+ qemu_opts_del(opts);
+ goto out;
+ }
+
+out:
+ error_propagate(errp, local_err);
+}
+
+void qmp_netfilter_del(const char *id, Error **errp)
+{
+ NetFilterState *nf;
+ QemuOpts *opts;
+
+ nf = qemu_find_netfilter(id);
+ if (!nf) {
+ error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
+ "Device '%s' not found", id);
+ return;
+ }
+
+ opts = qemu_opts_find(qemu_find_opts_err("netfilter", NULL), id);
+ if (!opts) {
+ error_setg(errp, "Device '%s' is not a netfilter", id);
+ return;
+ }
+
+ qemu_del_net_filter(nf);
+ qemu_opts_del(opts);
+}
+
typedef int (NetFilterInit)(const NetFilterOptions *opts,
const char *name, int chain,
NetClientState *netdev, Error **errp);
diff --git a/net/net.c b/net/net.c
index d9b70cd..6e677f1 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,8 @@ void qemu_del_net_client(NetClientState *nc)
{
NetClientState *ncs[MAX_QUEUE_NUM];
int queues, i;
+ NetFilterState *nf, *next;
+ QemuOpts *opts;
assert(nc->info->type != NET_CLIENT_OPTIONS_KIND_NIC);
@@ -396,6 +399,13 @@ 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) {
+ opts = qemu_opts_find(qemu_find_opts_err("netfilter", NULL), nf->name);
+ qemu_del_net_filter(nf);
+ qemu_opts_del(opts);
+ }
+
/* 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 d7fb578..9d97c21 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -2537,6 +2537,53 @@
'opts': 'NetClientOptions' } }
##
+# @netfilter_add:
+#
+# Add a netfilter.
+#
+# @type: the type of netfilter.
+#
+# @id: the name of the new netfilter.
+#
+# @netdev: the name of the netdev which this filter will be 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
+#
+# @props: #optional a list of properties to be passed to the netfilter in
+# the format of 'name=value'
+#
+# Since: 2.5
+#
+# Returns: Nothing on success
+# If @type is not a valid netfilter, DeviceNotFound
+##
+{ 'command': 'netfilter_add',
+ 'data': {
+ 'type': 'str',
+ 'id': 'str',
+ 'netdev': 'str',
+ '*chain': 'str',
+ '*props': '**'}, 'gen': false }
+
+##
+# @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'} }
+
+##
# @NetFilterOptions
#
# A discriminated record of network filters.
diff --git a/qmp-commands.hx b/qmp-commands.hx
index ba630b1..4f0dc98 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -926,6 +926,63 @@ Example:
EQMP
{
+ .name = "netfilter_add",
+ .args_type = "netfilter:O",
+ .mhandler.cmd_new = qmp_netfilter_add,
+ },
+
+SQMP
+netfilter_add
+----------
+
+Add netfilter.
+
+Arguments:
+
+- "type": the filter type (json-string)
+- "id": the netfilter's ID, must be unique (json-string)
+- "netdev": the netdev's ID which this filter will be attached to(json-string)
+- filter options
+
+Example:
+
+-> { "execute": "netfilter_add",
+ "arguments": { "type": "type", "id": "nf0",
+ "netdev": "bn",
+ "chain": "in" } }
+<- { "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 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
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH v6 04/10] netfilter: hook packets before net queue send
2015-08-07 2:46 [Qemu-devel] [PATCH v6 00/10] For QEMU 2.5: Add a netfilter object and netbuffer filter Yang Hongyang
` (2 preceding siblings ...)
2015-08-07 2:46 ` [Qemu-devel] [PATCH v6 03/10] netfilter: add netfilter_{add|del} commands Yang Hongyang
@ 2015-08-07 2:46 ` Yang Hongyang
2015-08-07 2:46 ` [Qemu-devel] [PATCH v6 05/10] move out net queue structs define Yang Hongyang
` (6 subsequent siblings)
10 siblings, 0 replies; 20+ messages in thread
From: Yang Hongyang @ 2015-08-07 2:46 UTC (permalink / raw)
To: qemu-devel
Cc: thuth, zhang.zhanghailiang, lizhijian, jasowang, mrhines,
stefanha, Yang Hongyang
Capture packets that will be sent.
Signed-off-by: Yang Hongyang <yanghy@cn.fujitsu.com>
---
v5: do not check ret against iov_size
pass sent_cb to filters
---
net/net.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 66 insertions(+)
diff --git a/net/net.c b/net/net.c
index 6e677f1..60e1beb 100644
--- a/net/net.c
+++ b/net/net.c
@@ -565,6 +565,44 @@ int qemu_can_send_packet(NetClientState *sender)
return 1;
}
+static ssize_t filter_receive_iov(NetClientState *nc, int chain,
+ NetClientState *sender,
+ unsigned flags,
+ const struct iovec *iov,
+ int iovcnt,
+ NetPacketSent *sent_cb)
+{
+ ssize_t ret = 0;
+ NetFilterState *nf = NULL;
+
+ QTAILQ_FOREACH(nf, &nc->filters, next) {
+ if (nf->chain == chain || nf->chain == NET_FILTER_ALL) {
+ ret = nf->info->receive_iov(nf, sender, flags,
+ iov, iovcnt, sent_cb);
+ if (ret) {
+ return ret;
+ }
+ }
+ }
+
+ return ret;
+}
+
+static ssize_t filter_receive(NetClientState *nc, int chain,
+ NetClientState *sender,
+ unsigned flags,
+ const uint8_t *data,
+ size_t size,
+ NetPacketSent *sent_cb)
+{
+ struct iovec iov = {
+ .iov_base = (void *)data,
+ .iov_len = size
+ };
+
+ return filter_receive_iov(nc, chain, sender, flags, &iov, 1, sent_cb);
+}
+
ssize_t qemu_deliver_packet(NetClientState *sender,
unsigned flags,
const uint8_t *data,
@@ -636,6 +674,7 @@ static ssize_t qemu_send_packet_async_with_flags(NetClientState *sender,
NetPacketSent *sent_cb)
{
NetQueue *queue;
+ int ret;
#ifdef DEBUG_NET
printf("qemu_send_packet_async:\n");
@@ -646,6 +685,19 @@ static ssize_t qemu_send_packet_async_with_flags(NetClientState *sender,
return size;
}
+ /* Let filters handle the packet first */
+ ret = filter_receive(sender, NET_FILTER_OUT,
+ sender, flags, buf, size, sent_cb);
+ if (ret) {
+ return ret;
+ }
+
+ ret = filter_receive(sender->peer, NET_FILTER_IN,
+ sender, flags, buf, size, sent_cb);
+ if (ret) {
+ return ret;
+ }
+
queue = sender->peer->incoming_queue;
return qemu_net_queue_send(queue, sender, flags, buf, size, sent_cb);
@@ -716,11 +768,25 @@ ssize_t qemu_sendv_packet_async(NetClientState *sender,
NetPacketSent *sent_cb)
{
NetQueue *queue;
+ int ret;
if (sender->link_down || !sender->peer) {
return iov_size(iov, iovcnt);
}
+ /* Let filters handle the packet first */
+ ret = filter_receive_iov(sender, NET_FILTER_OUT, sender,
+ QEMU_NET_PACKET_FLAG_NONE, iov, iovcnt, sent_cb);
+ if (ret) {
+ return ret;
+ }
+
+ ret = filter_receive_iov(sender->peer, NET_FILTER_IN, sender,
+ QEMU_NET_PACKET_FLAG_NONE, iov, iovcnt, sent_cb);
+ if (ret) {
+ return ret;
+ }
+
queue = sender->peer->incoming_queue;
return qemu_net_queue_send_iov(queue, sender,
--
1.9.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH v6 05/10] move out net queue structs define
2015-08-07 2:46 [Qemu-devel] [PATCH v6 00/10] For QEMU 2.5: Add a netfilter object and netbuffer filter Yang Hongyang
` (3 preceding siblings ...)
2015-08-07 2:46 ` [Qemu-devel] [PATCH v6 04/10] netfilter: hook packets before net queue send Yang Hongyang
@ 2015-08-07 2:46 ` Yang Hongyang
2015-08-07 2:46 ` [Qemu-devel] [PATCH v6 06/10] netfilter: add an API to pass the packet to next filter Yang Hongyang
` (5 subsequent siblings)
10 siblings, 0 replies; 20+ messages in thread
From: Yang Hongyang @ 2015-08-07 2:46 UTC (permalink / raw)
To: qemu-devel
Cc: thuth, zhang.zhanghailiang, lizhijian, jasowang, mrhines,
stefanha, Yang Hongyang
Signed-off-by: Yang Hongyang <yanghy@cn.fujitsu.com>
---
include/net/queue.h | 19 +++++++++++++++++++
net/queue.c | 19 -------------------
2 files changed, 19 insertions(+), 19 deletions(-)
diff --git a/include/net/queue.h b/include/net/queue.h
index fc02b33..1d65e47 100644
--- a/include/net/queue.h
+++ b/include/net/queue.h
@@ -31,6 +31,25 @@ typedef struct NetQueue NetQueue;
typedef void (NetPacketSent) (NetClientState *sender, ssize_t ret);
+struct NetPacket {
+ QTAILQ_ENTRY(NetPacket) entry;
+ NetClientState *sender;
+ unsigned flags;
+ int size;
+ NetPacketSent *sent_cb;
+ uint8_t data[0];
+};
+
+struct NetQueue {
+ void *opaque;
+ uint32_t nq_maxlen;
+ uint32_t nq_count;
+
+ QTAILQ_HEAD(packets, NetPacket) packets;
+
+ unsigned delivering:1;
+};
+
#define QEMU_NET_PACKET_FLAG_NONE 0
#define QEMU_NET_PACKET_FLAG_RAW (1<<0)
diff --git a/net/queue.c b/net/queue.c
index ebbe2bb..1499479 100644
--- a/net/queue.c
+++ b/net/queue.c
@@ -39,25 +39,6 @@
* unbounded queueing.
*/
-struct NetPacket {
- QTAILQ_ENTRY(NetPacket) entry;
- NetClientState *sender;
- unsigned flags;
- int size;
- NetPacketSent *sent_cb;
- uint8_t data[0];
-};
-
-struct NetQueue {
- void *opaque;
- uint32_t nq_maxlen;
- uint32_t nq_count;
-
- QTAILQ_HEAD(packets, NetPacket) packets;
-
- unsigned delivering : 1;
-};
-
NetQueue *qemu_new_net_queue(void *opaque)
{
NetQueue *queue;
--
1.9.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH v6 06/10] netfilter: add an API to pass the packet to next filter
2015-08-07 2:46 [Qemu-devel] [PATCH v6 00/10] For QEMU 2.5: Add a netfilter object and netbuffer filter Yang Hongyang
` (4 preceding siblings ...)
2015-08-07 2:46 ` [Qemu-devel] [PATCH v6 05/10] move out net queue structs define Yang Hongyang
@ 2015-08-07 2:46 ` Yang Hongyang
2015-08-07 2:46 ` [Qemu-devel] [PATCH v6 07/10] net/queue: export qemu_net_queue_append_iov Yang Hongyang
` (4 subsequent siblings)
10 siblings, 0 replies; 20+ messages in thread
From: Yang Hongyang @ 2015-08-07 2:46 UTC (permalink / raw)
To: qemu-devel
Cc: thuth, zhang.zhanghailiang, lizhijian, jasowang, mrhines,
stefanha, Yang Hongyang
add an API qemu_netfilter_pass_to_next() to pass the packet
to next filter.
Signed-off-by: Yang Hongyang <yanghy@cn.fujitsu.com>
---
v5: fold params to NetPacket struct
---
include/net/filter.h | 3 +++
net/filter.c | 33 +++++++++++++++++++++++++++++++++
2 files changed, 36 insertions(+)
diff --git a/include/net/filter.h b/include/net/filter.h
index f15d83d..9278d40 100644
--- a/include/net/filter.h
+++ b/include/net/filter.h
@@ -57,4 +57,7 @@ void qemu_del_net_filter(NetFilterState *nf);
void netfilter_add(QemuOpts *opts, Error **errp);
void qmp_netfilter_add(QDict *qdict, QObject **ret, Error **errp);
+/* pass the packet to the next filter */
+ssize_t qemu_netfilter_pass_to_next(NetFilterState *nf, NetPacket *packet);
+
#endif /* QEMU_NET_FILTER_H */
diff --git a/net/filter.c b/net/filter.c
index 1b9ad67..9e9afc8 100644
--- a/net/filter.c
+++ b/net/filter.c
@@ -14,9 +14,11 @@
#include "qapi/dealloc-visitor.h"
#include "qemu/config-file.h"
#include "qmp-commands.h"
+#include "qemu/iov.h"
#include "net/filter.h"
#include "net/net.h"
+#include "net/queue.h"
static QTAILQ_HEAD(, NetFilterState) net_filters;
@@ -152,6 +154,37 @@ void qmp_netfilter_del(const char *id, Error **errp)
qemu_opts_del(opts);
}
+ssize_t qemu_netfilter_pass_to_next(NetFilterState *nf, NetPacket *packet)
+{
+ int ret = 0;
+ NetFilterState *next = QTAILQ_NEXT(nf, next);
+ struct iovec iov = {
+ .iov_base = (void *)packet->data,
+ .iov_len = packet->size
+ };
+
+ while (next) {
+ if (next->chain == nf->chain || next->chain == NET_FILTER_ALL) {
+ ret = next->info->receive_iov(next, packet->sender, packet->flags,
+ &iov, 1, packet->sent_cb);
+ if (ret) {
+ return ret;
+ }
+ }
+ next = QTAILQ_NEXT(next, next);
+ }
+
+ /* we have gone through all filters, pass it to receiver */
+ if (packet->sender && packet->sender->peer) {
+ return qemu_net_queue_send_iov(packet->sender->peer->incoming_queue,
+ packet->sender, packet->flags,
+ &iov, 1, packet->sent_cb);
+ }
+
+ /* no receiver, or sender been deleted */
+ return packet->size;
+}
+
typedef int (NetFilterInit)(const NetFilterOptions *opts,
const char *name, int chain,
NetClientState *netdev, Error **errp);
--
1.9.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH v6 07/10] net/queue: export qemu_net_queue_append_iov
2015-08-07 2:46 [Qemu-devel] [PATCH v6 00/10] For QEMU 2.5: Add a netfilter object and netbuffer filter Yang Hongyang
` (5 preceding siblings ...)
2015-08-07 2:46 ` [Qemu-devel] [PATCH v6 06/10] netfilter: add an API to pass the packet to next filter Yang Hongyang
@ 2015-08-07 2:46 ` Yang Hongyang
2015-08-07 2:46 ` [Qemu-devel] [PATCH v6 08/10] netfilter: add a netbuffer filter Yang Hongyang
` (3 subsequent siblings)
10 siblings, 0 replies; 20+ messages in thread
From: Yang Hongyang @ 2015-08-07 2:46 UTC (permalink / raw)
To: qemu-devel
Cc: thuth, zhang.zhanghailiang, lizhijian, jasowang, mrhines,
stefanha, Yang Hongyang
Signed-off-by: Yang Hongyang <yanghy@cn.fujitsu.com>
---
include/net/queue.h | 7 +++++++
net/queue.c | 12 ++++++------
2 files changed, 13 insertions(+), 6 deletions(-)
diff --git a/include/net/queue.h b/include/net/queue.h
index 1d65e47..e139cc7 100644
--- a/include/net/queue.h
+++ b/include/net/queue.h
@@ -55,6 +55,13 @@ struct NetQueue {
NetQueue *qemu_new_net_queue(void *opaque);
+void qemu_net_queue_append_iov(NetQueue *queue,
+ NetClientState *sender,
+ unsigned flags,
+ const struct iovec *iov,
+ int iovcnt,
+ NetPacketSent *sent_cb);
+
void qemu_del_net_queue(NetQueue *queue);
ssize_t qemu_net_queue_send(NetQueue *queue,
diff --git a/net/queue.c b/net/queue.c
index 1499479..428fdd6 100644
--- a/net/queue.c
+++ b/net/queue.c
@@ -91,12 +91,12 @@ static void qemu_net_queue_append(NetQueue *queue,
QTAILQ_INSERT_TAIL(&queue->packets, packet, entry);
}
-static void qemu_net_queue_append_iov(NetQueue *queue,
- NetClientState *sender,
- unsigned flags,
- const struct iovec *iov,
- int iovcnt,
- NetPacketSent *sent_cb)
+void qemu_net_queue_append_iov(NetQueue *queue,
+ NetClientState *sender,
+ unsigned flags,
+ const struct iovec *iov,
+ int iovcnt,
+ NetPacketSent *sent_cb)
{
NetPacket *packet;
size_t max_len = 0;
--
1.9.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH v6 08/10] netfilter: add a netbuffer filter
2015-08-07 2:46 [Qemu-devel] [PATCH v6 00/10] For QEMU 2.5: Add a netfilter object and netbuffer filter Yang Hongyang
` (6 preceding siblings ...)
2015-08-07 2:46 ` [Qemu-devel] [PATCH v6 07/10] net/queue: export qemu_net_queue_append_iov Yang Hongyang
@ 2015-08-07 2:46 ` Yang Hongyang
2015-08-10 9:21 ` Jason Wang
2015-08-07 2:46 ` [Qemu-devel] [PATCH v6 09/10] filter/buffer: update command description and help Yang Hongyang
` (2 subsequent siblings)
10 siblings, 1 reply; 20+ messages in thread
From: Yang Hongyang @ 2015-08-07 2:46 UTC (permalink / raw)
To: qemu-devel
Cc: thuth, zhang.zhanghailiang, lizhijian, jasowang, mrhines,
stefanha, Yang Hongyang
This filter is to buffer/release packets, this feature can be used
when using MicroCheckpointing, or other Remus like VM FT solutions, you
can also use it to simulate the network delay.
It has an interval option, if supplied, this filter will release
packets by interval.
Usage:
-netdev tap,id=bn0
-netfilter buffer,id=f0,netdev=bn0,chain=in,interval=1000
NOTE:
the scale of interval is microsecond.
Signed-off-by: Yang Hongyang <yanghy@cn.fujitsu.com>
---
v6: move the interval check earlier and some comment adjust
v5: remove dummy sent_cb
change interval type from int64 to uint32
check interval!=0 when initialise
rename FILTERBUFFERState to FilterBufferState
v4: remove bh
pass the packet to next filter instead of receiver
v3: check packet's sender and sender->peer when flush it
---
net/Makefile.objs | 1 +
net/filter-buffer.c | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++++
net/filter.c | 2 +
net/filters.h | 17 +++++++
qapi-schema.json | 18 +++++++-
5 files changed, 163 insertions(+), 1 deletion(-)
create mode 100644 net/filter-buffer.c
create mode 100644 net/filters.h
diff --git a/net/Makefile.objs b/net/Makefile.objs
index 914aec0..5fa2f97 100644
--- a/net/Makefile.objs
+++ b/net/Makefile.objs
@@ -14,3 +14,4 @@ common-obj-$(CONFIG_SLIRP) += slirp.o
common-obj-$(CONFIG_VDE) += vde.o
common-obj-$(CONFIG_NETMAP) += netmap.o
common-obj-y += filter.o
+common-obj-y += filter-buffer.o
diff --git a/net/filter-buffer.c b/net/filter-buffer.c
new file mode 100644
index 0000000..f26276c
--- /dev/null
+++ b/net/filter-buffer.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2015 FUJITSU LIMITED
+ * Author: Yang Hongyang <yanghy@cn.fujitsu.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * later. See the COPYING file in the top-level directory.
+ */
+
+#include "net/filter.h"
+#include "net/queue.h"
+#include "filters.h"
+#include "qemu-common.h"
+#include "qemu/timer.h"
+#include "qemu/iov.h"
+#include "qapi/qmp/qerror.h"
+
+typedef struct FilterBufferState {
+ NetFilterState nf;
+ NetQueue *incoming_queue;
+ uint32_t interval;
+ QEMUTimer release_timer;
+} FilterBufferState;
+
+static void filter_buffer_flush(NetFilterState *nf)
+{
+ FilterBufferState *s = DO_UPCAST(FilterBufferState, nf, nf);
+ NetQueue *queue = s->incoming_queue;
+ NetPacket *packet;
+
+ while (queue && !QTAILQ_EMPTY(&queue->packets)) {
+ packet = QTAILQ_FIRST(&queue->packets);
+ QTAILQ_REMOVE(&queue->packets, packet, entry);
+ queue->nq_count--;
+
+ if (packet->sender && packet->sender->peer) {
+ qemu_netfilter_pass_to_next(nf, packet);
+ }
+
+ /*
+ * now that we have passed the packet to next filter (or there's
+ * no receiver). If it's queued by receiver's incoming_queue, there
+ * will be a copy of the packet->data, so simply free this packet
+ * now.
+ */
+ g_free(packet);
+ }
+}
+
+static void filter_buffer_release_timer(void *opaque)
+{
+ FilterBufferState *s = opaque;
+ filter_buffer_flush(&s->nf);
+ timer_mod(&s->release_timer,
+ qemu_clock_get_us(QEMU_CLOCK_VIRTUAL) + s->interval);
+}
+
+/* filter APIs */
+static ssize_t filter_buffer_receive_iov(NetFilterState *nf,
+ NetClientState *sender,
+ unsigned flags,
+ const struct iovec *iov,
+ int iovcnt,
+ NetPacketSent *sent_cb)
+{
+ FilterBufferState *s = DO_UPCAST(FilterBufferState, nf, nf);
+ NetQueue *queue = s->incoming_queue;
+
+ qemu_net_queue_append_iov(queue, sender, flags, iov, iovcnt, sent_cb);
+ return iov_size(iov, iovcnt);
+}
+
+static void filter_buffer_cleanup(NetFilterState *nf)
+{
+ FilterBufferState *s = DO_UPCAST(FilterBufferState, nf, nf);
+
+ if (s->interval) {
+ timer_del(&s->release_timer);
+ }
+
+ /* flush packets */
+ filter_buffer_flush(nf);
+ g_free(s->incoming_queue);
+ return;
+}
+
+static NetFilterInfo net_filter_buffer_info = {
+ .type = NET_FILTER_OPTIONS_KIND_BUFFER,
+ .size = sizeof(FilterBufferState),
+ .receive_iov = filter_buffer_receive_iov,
+ .cleanup = filter_buffer_cleanup,
+};
+
+int net_init_filter_buffer(const NetFilterOptions *opts, const char *name,
+ int chain, NetClientState *netdev, Error **errp)
+{
+ NetFilterState *nf;
+ FilterBufferState *s;
+ const NetFilterBufferOptions *bufferopt;
+ int interval;
+
+ assert(opts->kind == NET_FILTER_OPTIONS_KIND_BUFFER);
+ bufferopt = opts->buffer;
+ /*
+ * this check will be dropped when there're VM FT solutions like MC
+ * or COLO use this filter to release packets on demand.
+ */
+ interval = bufferopt->has_interval ? bufferopt->interval : 0;
+ if (!interval) {
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "interval",
+ "a non-zero interval");
+ return -1;
+ }
+
+ nf = qemu_new_net_filter(&net_filter_buffer_info, netdev, name, chain);
+ s = DO_UPCAST(FilterBufferState, nf, nf);
+ s->incoming_queue = qemu_new_net_queue(nf);
+ s->interval = interval;
+ if (s->interval) {
+ timer_init_us(&s->release_timer, QEMU_CLOCK_VIRTUAL,
+ filter_buffer_release_timer, s);
+ timer_mod(&s->release_timer,
+ qemu_clock_get_us(QEMU_CLOCK_VIRTUAL) + s->interval);
+ }
+
+ return 0;
+}
diff --git a/net/filter.c b/net/filter.c
index 9e9afc8..15cce60 100644
--- a/net/filter.c
+++ b/net/filter.c
@@ -19,6 +19,7 @@
#include "net/filter.h"
#include "net/net.h"
#include "net/queue.h"
+#include "filters.h"
static QTAILQ_HEAD(, NetFilterState) net_filters;
@@ -191,6 +192,7 @@ typedef int (NetFilterInit)(const NetFilterOptions *opts,
static
NetFilterInit * const net_filter_init_fun[NET_FILTER_OPTIONS_KIND_MAX] = {
+ [NET_FILTER_OPTIONS_KIND_BUFFER] = net_init_filter_buffer,
};
static int net_filter_init1(const NetFilter *netfilter, Error **errp)
diff --git a/net/filters.h b/net/filters.h
new file mode 100644
index 0000000..3b546db
--- /dev/null
+++ b/net/filters.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2015 FUJITSU LIMITED
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * later. See the COPYING file in the top-level directory.
+ */
+
+#ifndef QEMU_NET_FILTERS_H
+#define QEMU_NET_FILTERS_H
+
+#include "net/net.h"
+#include "net/filter.h"
+
+int net_init_filter_buffer(const NetFilterOptions *opts, const char *name,
+ int chain, NetClientState *netdev, Error **errp);
+
+#endif /* QEMU_NET_FILTERS_H */
diff --git a/qapi-schema.json b/qapi-schema.json
index 9d97c21..7882641 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -2584,6 +2584,21 @@
{ 'command': 'netfilter_del', 'data': {'id': 'str'} }
##
+# @NetFilterBufferOptions
+#
+# a netbuffer filter for network backend.
+#
+# @interval: #optional release packets by interval, if no interval supplied,
+# will release packets when filter_buffer_release_all been called.
+# scale: microsecond
+#
+# Since 2.5
+##
+{ 'struct': 'NetFilterBufferOptions',
+ 'data': {
+ '*interval': 'uint32' } }
+
+##
# @NetFilterOptions
#
# A discriminated record of network filters.
@@ -2592,7 +2607,8 @@
#
##
{ 'union': 'NetFilterOptions',
- 'data': { } }
+ 'data': {
+ 'buffer': 'NetFilterBufferOptions'} }
##
# @NetFilter
--
1.9.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH v6 09/10] filter/buffer: update command description and help
2015-08-07 2:46 [Qemu-devel] [PATCH v6 00/10] For QEMU 2.5: Add a netfilter object and netbuffer filter Yang Hongyang
` (7 preceding siblings ...)
2015-08-07 2:46 ` [Qemu-devel] [PATCH v6 08/10] netfilter: add a netbuffer filter Yang Hongyang
@ 2015-08-07 2:46 ` Yang Hongyang
2015-08-07 2:46 ` [Qemu-devel] [PATCH v6 10/10] tests: add test cases for netfilter object Yang Hongyang
2015-08-10 9:17 ` [Qemu-devel] [PATCH v6 00/10] For QEMU 2.5: Add a netfilter object and netbuffer filter Jason Wang
10 siblings, 0 replies; 20+ messages in thread
From: Yang Hongyang @ 2015-08-07 2:46 UTC (permalink / raw)
To: qemu-devel
Cc: thuth, zhang.zhanghailiang, lizhijian, jasowang,
Markus Armbruster, mrhines, Luiz Capitulino, stefanha,
Yang Hongyang
now that we have a buffer netfilter, update the command
description and help.
Signed-off-by: Yang Hongyang <yanghy@cn.fujitsu.com>
CC: Luiz Capitulino <lcapitulino@redhat.com>
CC: Markus Armbruster <armbru@redhat.com>
---
hmp-commands.hx | 2 +-
qemu-options.hx | 5 ++++-
qmp-commands.hx | 2 +-
3 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 902e2d1..63177a8 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1255,7 +1255,7 @@ ETEXI
{
.name = "netfilter_add",
.args_type = "netfilter:O",
- .params = "[type],id=str,netdev=str[,chain=in|out|all,prop=value][,...]",
+ .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,
diff --git a/qemu-options.hx b/qemu-options.hx
index 0d52d02..eeaf2a1 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1575,7 +1575,10 @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
"socket][,vlan=n][,option][,option][,...]\n"
" old way to initialize a host network interface\n"
" (use the -netdev option if possible instead)\n", QEMU_ARCH_ALL)
-DEF("netfilter", HAS_ARG, QEMU_OPTION_netfilter, "", QEMU_ARCH_ALL)
+DEF("netfilter", HAS_ARG, QEMU_OPTION_netfilter,
+ "-netfilter buffer,id=str,netdev=str[,chain=in|out|all,interval=n]\n"
+ " buffer netdev in/out packets. if interval provided, will release\n"
+ " packets by interval. interval scale: microsecond\n", QEMU_ARCH_ALL)
STEXI
@item -net nic[,vlan=@var{n}][,macaddr=@var{mac}][,model=@var{type}] [,name=@var{name}][,addr=@var{addr}][,vectors=@var{v}]
@findex -net
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 4f0dc98..9419a6f 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -947,7 +947,7 @@ Arguments:
Example:
-> { "execute": "netfilter_add",
- "arguments": { "type": "type", "id": "nf0",
+ "arguments": { "type": "buffer", "id": "nf0",
"netdev": "bn",
"chain": "in" } }
<- { "return": {} }
--
1.9.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH v6 10/10] tests: add test cases for netfilter object
2015-08-07 2:46 [Qemu-devel] [PATCH v6 00/10] For QEMU 2.5: Add a netfilter object and netbuffer filter Yang Hongyang
` (8 preceding siblings ...)
2015-08-07 2:46 ` [Qemu-devel] [PATCH v6 09/10] filter/buffer: update command description and help Yang Hongyang
@ 2015-08-07 2:46 ` Yang Hongyang
2015-08-11 7:12 ` Wen Congyang
2015-08-10 9:17 ` [Qemu-devel] [PATCH v6 00/10] For QEMU 2.5: Add a netfilter object and netbuffer filter Jason Wang
10 siblings, 1 reply; 20+ messages in thread
From: Yang Hongyang @ 2015-08-07 2:46 UTC (permalink / raw)
To: qemu-devel
Cc: thuth, zhang.zhanghailiang, lizhijian, jasowang, mrhines,
stefanha, Yang Hongyang
Using qtest qmp interface to implement following cases:
1) add/remove netfilter
2) add a netfilter then delete the netdev
3) add/remove more than one netfilters
4) add more than one netfilters and then delete the netdev
Signed-off-by: Yang Hongyang <yanghy@cn.fujitsu.com>
---
tests/.gitignore | 1 +
tests/Makefile | 2 +
tests/test-netfilter.c | 194 +++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 197 insertions(+)
create mode 100644 tests/test-netfilter.c
diff --git a/tests/.gitignore b/tests/.gitignore
index ccc92e4..395962b 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -41,5 +41,6 @@ test-vmstate
test-write-threshold
test-x86-cpuid
test-xbzrle
+test-netfilter
*-test
qapi-schema/*.test.*
diff --git a/tests/Makefile b/tests/Makefile
index 7494582..e39c7e6 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -185,6 +185,7 @@ check-qtest-i386-y += tests/pc-cpu-test$(EXESUF)
check-qtest-i386-y += tests/q35-test$(EXESUF)
gcov-files-i386-y += hw/pci-host/q35.c
check-qtest-i386-$(CONFIG_LINUX) += tests/vhost-user-test$(EXESUF)
+check-qtest-i386-y += tests/test-netfilter$(EXESUF)
check-qtest-x86_64-y = $(check-qtest-i386-y)
gcov-files-i386-y += i386-softmmu/hw/timer/mc146818rtc.c
gcov-files-x86_64-y = $(subst i386-softmmu/,x86_64-softmmu/,$(gcov-files-i386-y))
@@ -409,6 +410,7 @@ tests/vhost-user-test$(EXESUF): tests/vhost-user-test.o qemu-char.o qemu-timer.o
tests/qemu-iotests/socket_scm_helper$(EXESUF): tests/qemu-iotests/socket_scm_helper.o
tests/test-qemu-opts$(EXESUF): tests/test-qemu-opts.o libqemuutil.a libqemustub.a
tests/test-write-threshold$(EXESUF): tests/test-write-threshold.o $(block-obj-y) libqemuutil.a libqemustub.a
+tests/test-netfilter$(EXESUF): tests/test-netfilter.o $(qtest-obj-y)
ifeq ($(CONFIG_POSIX),y)
LIBS += -lutil
diff --git a/tests/test-netfilter.c b/tests/test-netfilter.c
new file mode 100644
index 0000000..acbea4c
--- /dev/null
+++ b/tests/test-netfilter.c
@@ -0,0 +1,194 @@
+/*
+ * QTest testcase for netfilter
+ *
+ * Copyright (c) 2015 FUJITSU LIMITED
+ * Author: Yang Hongyang <yanghy@cn.fujitsu.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * later. See the COPYING file in the top-level directory.
+ */
+
+#include <glib.h>
+#include "libqtest.h"
+
+/* add a netfilter to a netdev and then remove it */
+static void add_one_netfilter(void)
+{
+ QDict *response;
+
+ response = qmp("{\"execute\": \"netfilter_add\","
+ " \"arguments\": {"
+ " \"type\": \"buffer\","
+ " \"id\": \"qtest-f0\","
+ " \"netdev\": \"qtest-bn0\","
+ " \"chain\": \"in\","
+ " \"interval\": \"1000\""
+ "}}");
+
+ g_assert(response);
+ g_assert(!qdict_haskey(response, "error"));
+ QDECREF(response);
+
+ response = qmp("{\"execute\": \"netfilter_del\","
+ " \"arguments\": {"
+ " \"id\": \"qtest-f0\""
+ "}}");
+ g_assert(response);
+ g_assert(!qdict_haskey(response, "error"));
+ QDECREF(response);
+}
+
+/* add a netfilter to a netdev and then remove the netdev */
+static void remove_netdev_with_one_netfilter(void)
+{
+ QDict *response;
+
+ response = qmp("{\"execute\": \"netfilter_add\","
+ " \"arguments\": {"
+ " \"type\": \"buffer\","
+ " \"id\": \"qtest-f0\","
+ " \"netdev\": \"qtest-bn0\","
+ " \"chain\": \"in\","
+ " \"interval\": \"1000\""
+ "}}");
+
+ g_assert(response);
+ g_assert(!qdict_haskey(response, "error"));
+ QDECREF(response);
+
+ response = qmp("{\"execute\": \"netdev_del\","
+ " \"arguments\": {"
+ " \"id\": \"qtest-bn0\""
+ "}}");
+ g_assert(response);
+ g_assert(!qdict_haskey(response, "error"));
+ QDECREF(response);
+
+ /* add back the netdev */
+ response = qmp("{\"execute\": \"netdev_add\","
+ " \"arguments\": {"
+ " \"type\": \"user\","
+ " \"id\": \"qtest-bn0\""
+ "}}");
+ g_assert(response);
+ g_assert(!qdict_haskey(response, "error"));
+ QDECREF(response);
+}
+
+/* add multi(2) netfilters to a netdev and then remove them */
+static void add_multi_netfilter(void)
+{
+ QDict *response;
+
+ response = qmp("{\"execute\": \"netfilter_add\","
+ " \"arguments\": {"
+ " \"type\": \"buffer\","
+ " \"id\": \"qtest-f0\","
+ " \"netdev\": \"qtest-bn0\","
+ " \"chain\": \"in\","
+ " \"interval\": \"1000\""
+ "}}");
+
+ g_assert(response);
+ g_assert(!qdict_haskey(response, "error"));
+ QDECREF(response);
+
+ response = qmp("{\"execute\": \"netfilter_add\","
+ " \"arguments\": {"
+ " \"type\": \"buffer\","
+ " \"id\": \"qtest-f1\","
+ " \"netdev\": \"qtest-bn0\","
+ " \"chain\": \"in\","
+ " \"interval\": \"1000\""
+ "}}");
+
+ g_assert(response);
+ g_assert(!qdict_haskey(response, "error"));
+ QDECREF(response);
+
+ response = qmp("{\"execute\": \"netfilter_del\","
+ " \"arguments\": {"
+ " \"id\": \"qtest-f0\""
+ "}}");
+ g_assert(response);
+ g_assert(!qdict_haskey(response, "error"));
+ QDECREF(response);
+
+ response = qmp("{\"execute\": \"netfilter_del\","
+ " \"arguments\": {"
+ " \"id\": \"qtest-f1\""
+ "}}");
+ g_assert(response);
+ g_assert(!qdict_haskey(response, "error"));
+ QDECREF(response);
+}
+
+/* add multi(2) netfilters to a netdev and then remove the netdev */
+static void remove_netdev_with_multi_netfilter(void)
+{
+ QDict *response;
+
+ response = qmp("{\"execute\": \"netfilter_add\","
+ " \"arguments\": {"
+ " \"type\": \"buffer\","
+ " \"id\": \"qtest-f0\","
+ " \"netdev\": \"qtest-bn0\","
+ " \"chain\": \"in\","
+ " \"interval\": \"1000\""
+ "}}");
+
+ g_assert(response);
+ g_assert(!qdict_haskey(response, "error"));
+ QDECREF(response);
+
+ response = qmp("{\"execute\": \"netfilter_add\","
+ " \"arguments\": {"
+ " \"type\": \"buffer\","
+ " \"id\": \"qtest-f1\","
+ " \"netdev\": \"qtest-bn0\","
+ " \"chain\": \"in\","
+ " \"interval\": \"1000\""
+ "}}");
+
+ g_assert(response);
+ g_assert(!qdict_haskey(response, "error"));
+ QDECREF(response);
+
+ response = qmp("{\"execute\": \"netdev_del\","
+ " \"arguments\": {"
+ " \"id\": \"qtest-bn0\""
+ "}}");
+ g_assert(response);
+ g_assert(!qdict_haskey(response, "error"));
+ QDECREF(response);
+
+ /* add back the netdev */
+ response = qmp("{\"execute\": \"netdev_add\","
+ " \"arguments\": {"
+ " \"type\": \"user\","
+ " \"id\": \"qtest-bn0\""
+ "}}");
+ g_assert(response);
+ g_assert(!qdict_haskey(response, "error"));
+ QDECREF(response);
+}
+
+int main(int argc, char **argv)
+{
+ int ret;
+
+ g_test_init(&argc, &argv, NULL);
+ qtest_add_func("/netfilter/addremove_one", add_one_netfilter);
+ qtest_add_func("/netfilter/remove_netdev_one",
+ remove_netdev_with_one_netfilter);
+ qtest_add_func("/netfilter/addremove_multi", add_multi_netfilter);
+ qtest_add_func("/netfilter/remove_netdev_multi",
+ remove_netdev_with_multi_netfilter);
+
+ qtest_start("-netdev user,id=qtest-bn0 -device e1000,netdev=qtest-bn0");
+ ret = g_test_run();
+
+ qtest_end();
+
+ return ret;
+}
--
1.9.1
^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [Qemu-devel] [PATCH v6 00/10] For QEMU 2.5: Add a netfilter object and netbuffer filter
2015-08-07 2:46 [Qemu-devel] [PATCH v6 00/10] For QEMU 2.5: Add a netfilter object and netbuffer filter Yang Hongyang
` (9 preceding siblings ...)
2015-08-07 2:46 ` [Qemu-devel] [PATCH v6 10/10] tests: add test cases for netfilter object Yang Hongyang
@ 2015-08-10 9:17 ` Jason Wang
2015-08-14 1:26 ` Yang Hongyang
10 siblings, 1 reply; 20+ messages in thread
From: Jason Wang @ 2015-08-10 9:17 UTC (permalink / raw)
To: Yang Hongyang, qemu-devel
Cc: thuth, zhang.zhanghailiang, lizhijian, mrhines, stefanha
On 08/07/2015 10:46 AM, Yang Hongyang wrote:
> Add multiqueue support in v6.
>
> This patch add a new object netfilter, capture all network packets.
> Also implement a netbuffer based on this object.
> the "buffer" netfilter could be used by VM FT solutions like
> MicroCheckpointing, to buffer/release packets. Or to simulate
> packet delay.
>
> You can also get the series from:
> https://github.com/macrosheep/qemu/tree/netfilter-v6
>
> Usage:
> -netdev tap,id=bn0
> -netfilter buffer,id=f0,netdev=bn0,chain=in,interval=1000
> -device e1000,netdev=bn0
>
> dynamically add/remove netfilters:
> netfilter_add buffer,id=f0,netdev=bn0,chain=in,interval=1000
> netfilter_del f0
>
> NOTE:
> interval's scale is microsecond.
> chain is optional, and is one of in|out|all, 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
>
> TODO:
> - dump
>
> v6:
> - add multiqueue support, please see individual patch for detail
>
> v5:
> - add a sent_cb param to filter receive_iov api
> - squash the 4th patch into patch 3
> - remove dummy sent_cb (buffer filter)
> - addressed Jason's other comments, see individual patches for detail
>
> v4:
> - get rid of struct Filter
> - squash the 4th patch into patch 2
> - fix qemu_netfilter_pass_to_next_iov
> - get rid of bh (buffer filter)
> - release the packet to next filter instead of to receiver (buffer filter)
>
> v3:
> - add an api to pass the packet to next filter
> - remove netfilters when delete netdev
> - add qtest testcases for netfilter
> - addressed comments from Jason
>
> v2:
> - add a chain option to netfilter object
> - move the hook place earlier, before net_queue_send
> - drop the unused api in buffer filter
> - squash buffer filter patches into one
> - remove receive() api from netfilter, only receive_iov() is enough
> - addressed comments from Jason&Thomas
>
> v1:
> initial patch.
>
> Yang Hongyang (10):
> net: add a new object netfilter
> init/cleanup of netfilter object
> netfilter: add netfilter_{add|del} commands
> netfilter: hook packets before net queue send
> move out net queue structs define
> netfilter: add an API to pass the packet to next filter
> net/queue: export qemu_net_queue_append_iov
> netfilter: add a netbuffer filter
> filter/buffer: update command description and help
> tests: add test cases for netfilter object
>
> hmp-commands.hx | 30 +++++
> hmp.c | 29 +++++
> hmp.h | 4 +
> include/net/filter.h | 63 ++++++++++
> include/net/net.h | 1 +
> include/net/queue.h | 26 +++++
> include/qemu/typedefs.h | 1 +
> include/sysemu/sysemu.h | 1 +
> monitor.c | 33 ++++++
> net/Makefile.objs | 2 +
> net/filter-buffer.c | 126 ++++++++++++++++++++
> net/filter.c | 302 ++++++++++++++++++++++++++++++++++++++++++++++++
> net/filters.h | 17 +++
> net/net.c | 77 ++++++++++++
> net/queue.c | 31 +----
> qapi-schema.json | 100 ++++++++++++++++
> qemu-options.hx | 4 +
> qmp-commands.hx | 57 +++++++++
> tests/.gitignore | 1 +
> tests/Makefile | 2 +
> tests/test-netfilter.c | 194 +++++++++++++++++++++++++++++++
> vl.c | 13 +++
> 22 files changed, 1089 insertions(+), 25 deletions(-)
> create mode 100644 include/net/filter.h
> create mode 100644 net/filter-buffer.c
> create mode 100644 net/filter.c
> create mode 100644 net/filters.h
> create mode 100644 tests/test-netfilter.c
>
Thanks for the patches. Overall looks good to me, just have some minor
comments, see individual patches for details.
I think we need something like "info filter" to display filters
information, or just add them in "info network"
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [Qemu-devel] [PATCH v6 02/10] init/cleanup of netfilter object
2015-08-07 2:46 ` [Qemu-devel] [PATCH v6 02/10] init/cleanup of netfilter object Yang Hongyang
@ 2015-08-10 9:18 ` Jason Wang
2015-08-20 16:41 ` Yang Hongyang
0 siblings, 1 reply; 20+ messages in thread
From: Jason Wang @ 2015-08-10 9:18 UTC (permalink / raw)
To: Yang Hongyang, qemu-devel
Cc: thuth, mrhines, stefanha, zhang.zhanghailiang, lizhijian
On 08/07/2015 10:46 AM, Yang Hongyang wrote:
> 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 <yanghy@cn.fujitsu.com>
> ---
> 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 | 141 ++++++++++++++++++++++++++++++++++++++++++++++++
> net/net.c | 1 +
> qapi-schema.json | 37 +++++++++++++
> 6 files changed, 223 insertions(+)
>
> diff --git a/include/net/filter.h b/include/net/filter.h
> index 4242ded..7a858d8 100644
> --- a/include/net/filter.h
[...]
> +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;
> + }
Let's fail when vhost is used here.
> +
> + 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);
> + }
> +
> + 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;
> }
Then errors will be lost here?
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [Qemu-devel] [PATCH v6 03/10] netfilter: add netfilter_{add|del} commands
2015-08-07 2:46 ` [Qemu-devel] [PATCH v6 03/10] netfilter: add netfilter_{add|del} commands Yang Hongyang
@ 2015-08-10 9:20 ` Jason Wang
2015-08-11 7:07 ` Wen Congyang
1 sibling, 0 replies; 20+ messages in thread
From: Jason Wang @ 2015-08-10 9:20 UTC (permalink / raw)
To: Yang Hongyang, qemu-devel
Cc: thuth, zhang.zhanghailiang, lizhijian, Markus Armbruster, mrhines,
Luiz Capitulino, stefanha
On 08/07/2015 10:46 AM, Yang Hongyang wrote:
> 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.
>
> Signed-off-by: Yang Hongyang <yanghy@cn.fujitsu.com>
> CC: Luiz Capitulino <lcapitulino@redhat.com>
> CC: Markus Armbruster <armbru@redhat.com>
> CC: Eric Blake <eblake@redhat.com>
> ---
> 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 | 3 ++
> monitor.c | 33 +++++++++++++++++
> net/filter.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++-
> net/net.c | 10 +++++
> qapi-schema.json | 47 ++++++++++++++++++++++++
> qmp-commands.hx | 57 +++++++++++++++++++++++++++++
> 9 files changed, 313 insertions(+), 1 deletion(-)
>
> diff --git a/hmp-commands.hx b/hmp-commands.hx
> index d3b7932..902e2d1 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 = "[type],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 netfilter.
> +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 netfilter.
> +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 7a858d8..f15d83d 100644
> --- a/include/net/filter.h
> +++ b/include/net/filter.h
> @@ -53,5 +53,8 @@ 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);
> +void qmp_netfilter_add(QDict *qdict, QObject **ret, Error **errp);
>
> #endif /* QEMU_NET_FILTER_H */
> diff --git a/monitor.c b/monitor.c
> index aeea2b5..d6b8f24 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)
> }
> }
>
[...]
> +static int net_init_filter(void *dummy, QemuOpts *opts, Error **errp);
> +void netfilter_add(QemuOpts *opts, Error **errp)
> +{
> + net_init_filter(NULL, opts, errp);
> +}
> +
> +void qmp_netfilter_add(QDict *qdict, QObject **ret, Error **errp)
> +{
> + Error *local_err = NULL;
> + QemuOptsList *opts_list;
> + QemuOpts *opts;
> +
> + opts_list = qemu_find_opts_err("netfilter", &local_err);
> + if (local_err) {
> + goto out;
> + }
> +
> + opts = qemu_opts_from_qdict(opts_list, qdict, &local_err);
> + if (local_err) {
> + goto out;
> + }
> +
> + netfilter_add(opts, &local_err);
> + if (local_err) {
> + qemu_opts_del(opts);
> + goto out;
> + }
> +
> +out:
> + error_propagate(errp, local_err);
> +}
> +
> +void qmp_netfilter_del(const char *id, Error **errp)
> +{
> + NetFilterState *nf;
> + QemuOpts *opts;
> +
> + nf = qemu_find_netfilter(id);
> + if (!nf) {
> + error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
> + "Device '%s' not found", id);
Should be "Filter '%s' not found" ?
> + return;
> + }
> +
> + opts = qemu_opts_find(qemu_find_opts_err("netfilter", NULL), id);
> + if (!opts) {
> + error_setg(errp, "Device '%s' is not a netfilter", id);
Maybe "'%s' is not a filter" ?
> + return;
> + }
> +
> + qemu_del_net_filter(nf);
> + qemu_opts_del(opts);
How about moving qmp_opts_del() into qemu_del_net_filter() to avoid
codes duplication?
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [Qemu-devel] [PATCH v6 08/10] netfilter: add a netbuffer filter
2015-08-07 2:46 ` [Qemu-devel] [PATCH v6 08/10] netfilter: add a netbuffer filter Yang Hongyang
@ 2015-08-10 9:21 ` Jason Wang
0 siblings, 0 replies; 20+ messages in thread
From: Jason Wang @ 2015-08-10 9:21 UTC (permalink / raw)
To: Yang Hongyang, qemu-devel
Cc: thuth, mrhines, stefanha, zhang.zhanghailiang, lizhijian
On 08/07/2015 10:46 AM, Yang Hongyang wrote:
> This filter is to buffer/release packets, this feature can be used
> when using MicroCheckpointing, or other Remus like VM FT solutions, you
> can also use it to simulate the network delay.
> It has an interval option, if supplied, this filter will release
> packets by interval.
>
> Usage:
> -netdev tap,id=bn0
> -netfilter buffer,id=f0,netdev=bn0,chain=in,interval=1000
>
> NOTE:
> the scale of interval is microsecond.
>
> Signed-off-by: Yang Hongyang <yanghy@cn.fujitsu.com>
> ---
> v6: move the interval check earlier and some comment adjust
> v5: remove dummy sent_cb
> change interval type from int64 to uint32
> check interval!=0 when initialise
> rename FILTERBUFFERState to FilterBufferState
> v4: remove bh
> pass the packet to next filter instead of receiver
> v3: check packet's sender and sender->peer when flush it
> ---
> net/Makefile.objs | 1 +
> net/filter-buffer.c | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> net/filter.c | 2 +
> net/filters.h | 17 +++++++
> qapi-schema.json | 18 +++++++-
> 5 files changed, 163 insertions(+), 1 deletion(-)
> create mode 100644 net/filter-buffer.c
> create mode 100644 net/filters.h
>
> diff --git a/net/Makefile.objs b/net/Makefile.objs
> index 914aec0..5fa2f97 100644
> --- a/net/Makefile.objs
> +++ b/net/Makefile.objs
> @@ -14,3 +14,4 @@ common-obj-$(CONFIG_SLIRP) += slirp.o
> common-obj-$(CONFIG_VDE) += vde.o
> common-obj-$(CONFIG_NETMAP) += netmap.o
> common-obj-y += filter.o
> +common-obj-y += filter-buffer.o
> diff --git a/net/filter-buffer.c b/net/filter-buffer.c
> new file mode 100644
> index 0000000..f26276c
> --- /dev/null
> +++ b/net/filter-buffer.c
> @@ -0,0 +1,126 @@
> +/*
> + * Copyright (c) 2015 FUJITSU LIMITED
> + * Author: Yang Hongyang <yanghy@cn.fujitsu.com>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or
> + * later. See the COPYING file in the top-level directory.
> + */
> +
> +#include "net/filter.h"
> +#include "net/queue.h"
> +#include "filters.h"
> +#include "qemu-common.h"
> +#include "qemu/timer.h"
> +#include "qemu/iov.h"
> +#include "qapi/qmp/qerror.h"
> +
> +typedef struct FilterBufferState {
> + NetFilterState nf;
> + NetQueue *incoming_queue;
> + uint32_t interval;
> + QEMUTimer release_timer;
> +} FilterBufferState;
> +
> +static void filter_buffer_flush(NetFilterState *nf)
> +{
> + FilterBufferState *s = DO_UPCAST(FilterBufferState, nf, nf);
> + NetQueue *queue = s->incoming_queue;
> + NetPacket *packet;
> +
> + while (queue && !QTAILQ_EMPTY(&queue->packets)) {
Looks like no need to check queue here. And then you can switch to use
QTAILQ_FOREACH_SAFE() to save one line of QTAILF_FIRST().
> + packet = QTAILQ_FIRST(&queue->packets);
> + QTAILQ_REMOVE(&queue->packets, packet, entry);
> + queue->nq_count--;
> +
> + if (packet->sender && packet->sender->peer) {
> + qemu_netfilter_pass_to_next(nf, packet);
> + }
> +
> + /*
> + * now that we have passed the packet to next filter (or there's
> + * no receiver). If it's queued by receiver's incoming_queue, there
> + * will be a copy of the packet->data, so simply free this packet
> + * now.
> + */
> + g_free(packet);
In the future, we may consider to avoid the extra copy. This could be
done on top of this series.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [Qemu-devel] [PATCH v6 03/10] netfilter: add netfilter_{add|del} commands
2015-08-07 2:46 ` [Qemu-devel] [PATCH v6 03/10] netfilter: add netfilter_{add|del} commands Yang Hongyang
2015-08-10 9:20 ` Jason Wang
@ 2015-08-11 7:07 ` Wen Congyang
1 sibling, 0 replies; 20+ messages in thread
From: Wen Congyang @ 2015-08-11 7:07 UTC (permalink / raw)
To: Yang Hongyang, qemu-devel
Cc: thuth, zhang.zhanghailiang, lizhijian, jasowang,
Markus Armbruster, mrhines, Luiz Capitulino, stefanha
On 08/07/2015 10:46 AM, Yang Hongyang wrote:
> 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.
>
> Signed-off-by: Yang Hongyang <yanghy@cn.fujitsu.com>
> CC: Luiz Capitulino <lcapitulino@redhat.com>
> CC: Markus Armbruster <armbru@redhat.com>
> CC: Eric Blake <eblake@redhat.com>
> ---
> 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 | 3 ++
> monitor.c | 33 +++++++++++++++++
> net/filter.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++-
> net/net.c | 10 +++++
> qapi-schema.json | 47 ++++++++++++++++++++++++
> qmp-commands.hx | 57 +++++++++++++++++++++++++++++
> 9 files changed, 313 insertions(+), 1 deletion(-)
>
> diff --git a/hmp-commands.hx b/hmp-commands.hx
> index d3b7932..902e2d1 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 = "[type],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 netfilter.
> +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 netfilter.
> +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 7a858d8..f15d83d 100644
> --- a/include/net/filter.h
> +++ b/include/net/filter.h
> @@ -53,5 +53,8 @@ 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);
> +void qmp_netfilter_add(QDict *qdict, QObject **ret, Error **errp);
>
> #endif /* QEMU_NET_FILTER_H */
> diff --git a/monitor.c b/monitor.c
> index aeea2b5..d6b8f24 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; NetFilterOptionsKind_lookup[i]; i++) {
> + add_completion_option(rs, str, NetFilterOptionsKind_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 0d12abf..1b9ad67 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"
> @@ -40,7 +41,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);
> @@ -53,6 +54,104 @@ 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;
> +
> + 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]);
> + }
> +}
> +
> +static NetFilterState *qemu_find_netfilter(const char *id)
> +{
> + NetFilterState *nf;
> +
> + QTAILQ_FOREACH(nf, &net_filters, global_list) {
> + if (!strcmp(nf->name, id)) {
> + return nf;
> + }
> + }
> +
> + 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);
> +}
> +
> +void qmp_netfilter_add(QDict *qdict, QObject **ret, Error **errp)
> +{
> + Error *local_err = NULL;
> + QemuOptsList *opts_list;
> + QemuOpts *opts;
> +
> + opts_list = qemu_find_opts_err("netfilter", &local_err);
> + if (local_err) {
> + goto out;
> + }
> +
> + opts = qemu_opts_from_qdict(opts_list, qdict, &local_err);
> + if (local_err) {
> + goto out;
> + }
> +
> + netfilter_add(opts, &local_err);
> + if (local_err) {
> + qemu_opts_del(opts);
> + goto out;
> + }
> +
> +out:
> + error_propagate(errp, local_err);
> +}
> +
> +void qmp_netfilter_del(const char *id, Error **errp)
> +{
> + NetFilterState *nf;
> + QemuOpts *opts;
> +
> + nf = qemu_find_netfilter(id);
> + if (!nf) {
> + error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
> + "Device '%s' not found", id);
> + return;
> + }
> +
> + opts = qemu_opts_find(qemu_find_opts_err("netfilter", NULL), id);
> + if (!opts) {
> + error_setg(errp, "Device '%s' is not a netfilter", id);
> + return;
> + }
> +
> + qemu_del_net_filter(nf);
> + qemu_opts_del(opts);
> +}
> +
> typedef int (NetFilterInit)(const NetFilterOptions *opts,
> const char *name, int chain,
> NetClientState *netdev, Error **errp);
> diff --git a/net/net.c b/net/net.c
> index d9b70cd..6e677f1 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,8 @@ void qemu_del_net_client(NetClientState *nc)
> {
> NetClientState *ncs[MAX_QUEUE_NUM];
> int queues, i;
> + NetFilterState *nf, *next;
> + QemuOpts *opts;
>
> assert(nc->info->type != NET_CLIENT_OPTIONS_KIND_NIC);
>
> @@ -396,6 +399,13 @@ 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) {
> + opts = qemu_opts_find(qemu_find_opts_err("netfilter", NULL), nf->name);
> + qemu_del_net_filter(nf);
> + qemu_opts_del(opts);
> + }
> +
> /* 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 d7fb578..9d97c21 100644
> --- a/qapi-schema.json
> +++ b/qapi-schema.json
> @@ -2537,6 +2537,53 @@
> 'opts': 'NetClientOptions' } }
>
> ##
> +# @netfilter_add:
> +#
> +# Add a netfilter.
> +#
> +# @type: the type of netfilter.
> +#
> +# @id: the name of the new netfilter.
> +#
> +# @netdev: the name of the netdev which this filter will be 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
> +#
> +# @props: #optional a list of properties to be passed to the netfilter in
> +# the format of 'name=value'
> +#
> +# Since: 2.5
> +#
> +# Returns: Nothing on success
> +# If @type is not a valid netfilter, DeviceNotFound
> +##
> +{ 'command': 'netfilter_add',
> + 'data': {
> + 'type': 'str',
> + 'id': 'str',
> + 'netdev': 'str',
> + '*chain': 'str',
> + '*props': '**'}, 'gen': false }
> +
> +##
> +# @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'} }
> +
> +##
> # @NetFilterOptions
> #
> # A discriminated record of network filters.
> diff --git a/qmp-commands.hx b/qmp-commands.hx
> index ba630b1..4f0dc98 100644
> --- a/qmp-commands.hx
> +++ b/qmp-commands.hx
> @@ -926,6 +926,63 @@ Example:
> EQMP
>
> {
> + .name = "netfilter_add",
> + .args_type = "netfilter:O",
> + .mhandler.cmd_new = qmp_netfilter_add,
> + },
> +
> +SQMP
> +netfilter_add
> +----------
> +
> +Add netfilter.
> +
> +Arguments:
> +
> +- "type": the filter type (json-string)
> +- "id": the netfilter's ID, must be unique (json-string)
> +- "netdev": the netdev's ID which this filter will be attached to(json-string)
> +- filter options
> +
> +Example:
> +
> +-> { "execute": "netfilter_add",
> + "arguments": { "type": "type", "id": "nf0",
> + "netdev": "bn",
> + "chain": "in" } }
> +<- { "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
For qmp, the command should be netfilter-add/netfilter-del.
Thanks
Wen Congyang
> +----------
> +
> +Remove 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,
>
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [Qemu-devel] [PATCH v6 10/10] tests: add test cases for netfilter object
2015-08-07 2:46 ` [Qemu-devel] [PATCH v6 10/10] tests: add test cases for netfilter object Yang Hongyang
@ 2015-08-11 7:12 ` Wen Congyang
0 siblings, 0 replies; 20+ messages in thread
From: Wen Congyang @ 2015-08-11 7:12 UTC (permalink / raw)
To: Yang Hongyang, qemu-devel
Cc: thuth, zhang.zhanghailiang, lizhijian, jasowang, mrhines,
stefanha
On 08/07/2015 10:46 AM, Yang Hongyang wrote:
> Using qtest qmp interface to implement following cases:
> 1) add/remove netfilter
> 2) add a netfilter then delete the netdev
> 3) add/remove more than one netfilters
> 4) add more than one netfilters and then delete the netdev
>
> Signed-off-by: Yang Hongyang <yanghy@cn.fujitsu.com>
> ---
> tests/.gitignore | 1 +
> tests/Makefile | 2 +
> tests/test-netfilter.c | 194 +++++++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 197 insertions(+)
> create mode 100644 tests/test-netfilter.c
>
> diff --git a/tests/.gitignore b/tests/.gitignore
> index ccc92e4..395962b 100644
> --- a/tests/.gitignore
> +++ b/tests/.gitignore
> @@ -41,5 +41,6 @@ test-vmstate
> test-write-threshold
> test-x86-cpuid
> test-xbzrle
> +test-netfilter
> *-test
> qapi-schema/*.test.*
> diff --git a/tests/Makefile b/tests/Makefile
> index 7494582..e39c7e6 100644
> --- a/tests/Makefile
> +++ b/tests/Makefile
> @@ -185,6 +185,7 @@ check-qtest-i386-y += tests/pc-cpu-test$(EXESUF)
> check-qtest-i386-y += tests/q35-test$(EXESUF)
> gcov-files-i386-y += hw/pci-host/q35.c
> check-qtest-i386-$(CONFIG_LINUX) += tests/vhost-user-test$(EXESUF)
> +check-qtest-i386-y += tests/test-netfilter$(EXESUF)
> check-qtest-x86_64-y = $(check-qtest-i386-y)
> gcov-files-i386-y += i386-softmmu/hw/timer/mc146818rtc.c
> gcov-files-x86_64-y = $(subst i386-softmmu/,x86_64-softmmu/,$(gcov-files-i386-y))
> @@ -409,6 +410,7 @@ tests/vhost-user-test$(EXESUF): tests/vhost-user-test.o qemu-char.o qemu-timer.o
> tests/qemu-iotests/socket_scm_helper$(EXESUF): tests/qemu-iotests/socket_scm_helper.o
> tests/test-qemu-opts$(EXESUF): tests/test-qemu-opts.o libqemuutil.a libqemustub.a
> tests/test-write-threshold$(EXESUF): tests/test-write-threshold.o $(block-obj-y) libqemuutil.a libqemustub.a
> +tests/test-netfilter$(EXESUF): tests/test-netfilter.o $(qtest-obj-y)
>
> ifeq ($(CONFIG_POSIX),y)
> LIBS += -lutil
> diff --git a/tests/test-netfilter.c b/tests/test-netfilter.c
> new file mode 100644
> index 0000000..acbea4c
> --- /dev/null
> +++ b/tests/test-netfilter.c
> @@ -0,0 +1,194 @@
> +/*
> + * QTest testcase for netfilter
> + *
> + * Copyright (c) 2015 FUJITSU LIMITED
> + * Author: Yang Hongyang <yanghy@cn.fujitsu.com>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or
> + * later. See the COPYING file in the top-level directory.
> + */
> +
> +#include <glib.h>
> +#include "libqtest.h"
> +
> +/* add a netfilter to a netdev and then remove it */
> +static void add_one_netfilter(void)
> +{
> + QDict *response;
> +
> + response = qmp("{\"execute\": \"netfilter_add\","
> + " \"arguments\": {"
> + " \"type\": \"buffer\","
> + " \"id\": \"qtest-f0\","
> + " \"netdev\": \"qtest-bn0\","
> + " \"chain\": \"in\","
> + " \"interval\": \"1000\""
> + "}}");
You can use ' to instead of " in the qmp command:
"{'execute': 'netfilter_add', ...}"
Thanks
Wen Congyang
> +
> + g_assert(response);
> + g_assert(!qdict_haskey(response, "error"));
> + QDECREF(response);
> +
> + response = qmp("{\"execute\": \"netfilter_del\","
> + " \"arguments\": {"
> + " \"id\": \"qtest-f0\""
> + "}}");
> + g_assert(response);
> + g_assert(!qdict_haskey(response, "error"));
> + QDECREF(response);
> +}
> +
> +/* add a netfilter to a netdev and then remove the netdev */
> +static void remove_netdev_with_one_netfilter(void)
> +{
> + QDict *response;
> +
> + response = qmp("{\"execute\": \"netfilter_add\","
> + " \"arguments\": {"
> + " \"type\": \"buffer\","
> + " \"id\": \"qtest-f0\","
> + " \"netdev\": \"qtest-bn0\","
> + " \"chain\": \"in\","
> + " \"interval\": \"1000\""
> + "}}");
> +
> + g_assert(response);
> + g_assert(!qdict_haskey(response, "error"));
> + QDECREF(response);
> +
> + response = qmp("{\"execute\": \"netdev_del\","
> + " \"arguments\": {"
> + " \"id\": \"qtest-bn0\""
> + "}}");
> + g_assert(response);
> + g_assert(!qdict_haskey(response, "error"));
> + QDECREF(response);
> +
> + /* add back the netdev */
> + response = qmp("{\"execute\": \"netdev_add\","
> + " \"arguments\": {"
> + " \"type\": \"user\","
> + " \"id\": \"qtest-bn0\""
> + "}}");
> + g_assert(response);
> + g_assert(!qdict_haskey(response, "error"));
> + QDECREF(response);
> +}
> +
> +/* add multi(2) netfilters to a netdev and then remove them */
> +static void add_multi_netfilter(void)
> +{
> + QDict *response;
> +
> + response = qmp("{\"execute\": \"netfilter_add\","
> + " \"arguments\": {"
> + " \"type\": \"buffer\","
> + " \"id\": \"qtest-f0\","
> + " \"netdev\": \"qtest-bn0\","
> + " \"chain\": \"in\","
> + " \"interval\": \"1000\""
> + "}}");
> +
> + g_assert(response);
> + g_assert(!qdict_haskey(response, "error"));
> + QDECREF(response);
> +
> + response = qmp("{\"execute\": \"netfilter_add\","
> + " \"arguments\": {"
> + " \"type\": \"buffer\","
> + " \"id\": \"qtest-f1\","
> + " \"netdev\": \"qtest-bn0\","
> + " \"chain\": \"in\","
> + " \"interval\": \"1000\""
> + "}}");
> +
> + g_assert(response);
> + g_assert(!qdict_haskey(response, "error"));
> + QDECREF(response);
> +
> + response = qmp("{\"execute\": \"netfilter_del\","
> + " \"arguments\": {"
> + " \"id\": \"qtest-f0\""
> + "}}");
> + g_assert(response);
> + g_assert(!qdict_haskey(response, "error"));
> + QDECREF(response);
> +
> + response = qmp("{\"execute\": \"netfilter_del\","
> + " \"arguments\": {"
> + " \"id\": \"qtest-f1\""
> + "}}");
> + g_assert(response);
> + g_assert(!qdict_haskey(response, "error"));
> + QDECREF(response);
> +}
> +
> +/* add multi(2) netfilters to a netdev and then remove the netdev */
> +static void remove_netdev_with_multi_netfilter(void)
> +{
> + QDict *response;
> +
> + response = qmp("{\"execute\": \"netfilter_add\","
> + " \"arguments\": {"
> + " \"type\": \"buffer\","
> + " \"id\": \"qtest-f0\","
> + " \"netdev\": \"qtest-bn0\","
> + " \"chain\": \"in\","
> + " \"interval\": \"1000\""
> + "}}");
> +
> + g_assert(response);
> + g_assert(!qdict_haskey(response, "error"));
> + QDECREF(response);
> +
> + response = qmp("{\"execute\": \"netfilter_add\","
> + " \"arguments\": {"
> + " \"type\": \"buffer\","
> + " \"id\": \"qtest-f1\","
> + " \"netdev\": \"qtest-bn0\","
> + " \"chain\": \"in\","
> + " \"interval\": \"1000\""
> + "}}");
> +
> + g_assert(response);
> + g_assert(!qdict_haskey(response, "error"));
> + QDECREF(response);
> +
> + response = qmp("{\"execute\": \"netdev_del\","
> + " \"arguments\": {"
> + " \"id\": \"qtest-bn0\""
> + "}}");
> + g_assert(response);
> + g_assert(!qdict_haskey(response, "error"));
> + QDECREF(response);
> +
> + /* add back the netdev */
> + response = qmp("{\"execute\": \"netdev_add\","
> + " \"arguments\": {"
> + " \"type\": \"user\","
> + " \"id\": \"qtest-bn0\""
> + "}}");
> + g_assert(response);
> + g_assert(!qdict_haskey(response, "error"));
> + QDECREF(response);
> +}
> +
> +int main(int argc, char **argv)
> +{
> + int ret;
> +
> + g_test_init(&argc, &argv, NULL);
> + qtest_add_func("/netfilter/addremove_one", add_one_netfilter);
> + qtest_add_func("/netfilter/remove_netdev_one",
> + remove_netdev_with_one_netfilter);
> + qtest_add_func("/netfilter/addremove_multi", add_multi_netfilter);
> + qtest_add_func("/netfilter/remove_netdev_multi",
> + remove_netdev_with_multi_netfilter);
> +
> + qtest_start("-netdev user,id=qtest-bn0 -device e1000,netdev=qtest-bn0");
> + ret = g_test_run();
> +
> + qtest_end();
> +
> + return ret;
> +}
>
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [Qemu-devel] [PATCH v6 00/10] For QEMU 2.5: Add a netfilter object and netbuffer filter
2015-08-10 9:17 ` [Qemu-devel] [PATCH v6 00/10] For QEMU 2.5: Add a netfilter object and netbuffer filter Jason Wang
@ 2015-08-14 1:26 ` Yang Hongyang
0 siblings, 0 replies; 20+ messages in thread
From: Yang Hongyang @ 2015-08-14 1:26 UTC (permalink / raw)
To: Jason Wang, qemu-devel
Cc: thuth, zhang.zhanghailiang, lizhijian, mrhines, stefanha
Hi Jason,
Sorry for the late reply, just come back from vacation, and I won't
have much time until after kvm forum 2015, anyway, I will address the
comments and send a v7 if I have time.
On 08/10/2015 05:17 PM, Jason Wang wrote:
>
>
> On 08/07/2015 10:46 AM, Yang Hongyang wrote:
>> Add multiqueue support in v6.
>>
>> This patch add a new object netfilter, capture all network packets.
>> Also implement a netbuffer based on this object.
>> the "buffer" netfilter could be used by VM FT solutions like
>> MicroCheckpointing, to buffer/release packets. Or to simulate
>> packet delay.
>>
[...]
>>
>
> Thanks for the patches. Overall looks good to me, just have some minor
> comments, see individual patches for details.
Thank you for the review!
>
> I think we need something like "info filter" to display filters
> information, or just add them in "info network"
Ok, thanks!
> .
>
--
Thanks,
Yang.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [Qemu-devel] [PATCH v6 02/10] init/cleanup of netfilter object
2015-08-10 9:18 ` Jason Wang
@ 2015-08-20 16:41 ` Yang Hongyang
2015-08-21 1:35 ` Jason Wang
0 siblings, 1 reply; 20+ messages in thread
From: Yang Hongyang @ 2015-08-20 16:41 UTC (permalink / raw)
To: Jason Wang, qemu-devel
Cc: thuth, mrhines, stefanha, zhang.zhanghailiang, lizhijian
On 08/10/2015 05:18 PM, Jason Wang wrote:
>
>
> On 08/07/2015 10:46 AM, Yang Hongyang wrote:
>> 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 <yanghy@cn.fujitsu.com>
>> ---
>> 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 | 141 ++++++++++++++++++++++++++++++++++++++++++++++++
>> net/net.c | 1 +
>> qapi-schema.json | 37 +++++++++++++
>> 6 files changed, 223 insertions(+)
>>
>> diff --git a/include/net/filter.h b/include/net/filter.h
>> index 4242ded..7a858d8 100644
>> --- a/include/net/filter.h
> [...]
>> +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;
>> + }
>
> Let's fail when vhost is used here.
I think you mean vhost-user here?
>
>> +
>> + 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);
>> + }
>> +
>> + error_propagate(errp, err);
should print out the error here instead of propagate it,otherwise the error msg
is lost.
>> + 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;
>> }
>
> Then errors will be lost here?
>
Yes, good catch, thank you !
> .
>
--
Thanks,
Yang.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [Qemu-devel] [PATCH v6 02/10] init/cleanup of netfilter object
2015-08-20 16:41 ` Yang Hongyang
@ 2015-08-21 1:35 ` Jason Wang
0 siblings, 0 replies; 20+ messages in thread
From: Jason Wang @ 2015-08-21 1:35 UTC (permalink / raw)
To: Yang Hongyang, qemu-devel
Cc: thuth, mrhines, stefanha, zhang.zhanghailiang, lizhijian
On 08/21/2015 12:41 AM, Yang Hongyang wrote:
>
>
> On 08/10/2015 05:18 PM, Jason Wang wrote:
>>
>>
>> On 08/07/2015 10:46 AM, Yang Hongyang wrote:
>>> 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 <yanghy@cn.fujitsu.com>
>>> ---
>>> 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 | 141
>>> ++++++++++++++++++++++++++++++++++++++++++++++++
>>> net/net.c | 1 +
>>> qapi-schema.json | 37 +++++++++++++
>>> 6 files changed, 223 insertions(+)
>>>
>>> diff --git a/include/net/filter.h b/include/net/filter.h
>>> index 4242ded..7a858d8 100644
>>> --- a/include/net/filter.h
>> [...]
>>> +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;
>>> + }
>>
>> Let's fail when vhost is used here.
>
> I think you mean vhost-user here?
I think both we should fail for both vhost-user and vhost-kernel. Since
it does not work for them.
^ permalink raw reply [flat|nested] 20+ messages in thread
end of thread, other threads:[~2015-08-21 1:35 UTC | newest]
Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-08-07 2:46 [Qemu-devel] [PATCH v6 00/10] For QEMU 2.5: Add a netfilter object and netbuffer filter Yang Hongyang
2015-08-07 2:46 ` [Qemu-devel] [PATCH v6 01/10] net: add a new object netfilter Yang Hongyang
2015-08-07 2:46 ` [Qemu-devel] [PATCH v6 02/10] init/cleanup of netfilter object Yang Hongyang
2015-08-10 9:18 ` Jason Wang
2015-08-20 16:41 ` Yang Hongyang
2015-08-21 1:35 ` Jason Wang
2015-08-07 2:46 ` [Qemu-devel] [PATCH v6 03/10] netfilter: add netfilter_{add|del} commands Yang Hongyang
2015-08-10 9:20 ` Jason Wang
2015-08-11 7:07 ` Wen Congyang
2015-08-07 2:46 ` [Qemu-devel] [PATCH v6 04/10] netfilter: hook packets before net queue send Yang Hongyang
2015-08-07 2:46 ` [Qemu-devel] [PATCH v6 05/10] move out net queue structs define Yang Hongyang
2015-08-07 2:46 ` [Qemu-devel] [PATCH v6 06/10] netfilter: add an API to pass the packet to next filter Yang Hongyang
2015-08-07 2:46 ` [Qemu-devel] [PATCH v6 07/10] net/queue: export qemu_net_queue_append_iov Yang Hongyang
2015-08-07 2:46 ` [Qemu-devel] [PATCH v6 08/10] netfilter: add a netbuffer filter Yang Hongyang
2015-08-10 9:21 ` Jason Wang
2015-08-07 2:46 ` [Qemu-devel] [PATCH v6 09/10] filter/buffer: update command description and help Yang Hongyang
2015-08-07 2:46 ` [Qemu-devel] [PATCH v6 10/10] tests: add test cases for netfilter object Yang Hongyang
2015-08-11 7:12 ` Wen Congyang
2015-08-10 9:17 ` [Qemu-devel] [PATCH v6 00/10] For QEMU 2.5: Add a netfilter object and netbuffer filter Jason Wang
2015-08-14 1:26 ` Yang Hongyang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).