---
include/net/net.h | 3 +
net/Makefile.objs | 1 +
net/clients.h | 3 +
net/filter.c | 200
++++++++++++++++++++++++++++++++++++++++++++++++++++++
net/net.c | 6 +-
qapi-schema.json | 23 ++++++-
6 files changed, 233 insertions(+), 3 deletions(-)
create mode 100644 net/filter.c
diff --git a/include/net/net.h b/include/net/net.h
index 6a6cbef..250f365 100644
--- a/include/net/net.h
+++ b/include/net/net.h
@@ -45,6 +45,8 @@ typedef void (NetPoll)(NetClientState *, bool
enable);
typedef int (NetCanReceive)(NetClientState *);
typedef ssize_t (NetReceive)(NetClientState *, const uint8_t *,
size_t);
typedef ssize_t (NetReceiveIOV)(NetClientState *, const struct
iovec *, int);
+typedef ssize_t (NetReceiveFilter)(NetClientState *, NetClientState *,
+ unsigned, const uint8_t *, size_t);
typedef void (NetCleanup) (NetClientState *);
typedef void (LinkStatusChanged)(NetClientState *);
typedef void (NetClientDestructor)(NetClientState *);
@@ -64,6 +66,7 @@ typedef struct NetClientInfo {
NetReceive *receive;
NetReceive *receive_raw;
NetReceiveIOV *receive_iov;
+ NetReceiveFilter *receive_filter;
NetCanReceive *can_receive;
NetCleanup *cleanup;
LinkStatusChanged *link_status_changed;
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/clients.h b/net/clients.h
index d47530e..bcfb34b 100644
--- a/net/clients.h
+++ b/net/clients.h
@@ -62,4 +62,7 @@ int net_init_netmap(const NetClientOptions *opts,
const char *name,
int net_init_vhost_user(const NetClientOptions *opts, const char
*name,
NetClientState *peer, Error **errp);
+int net_init_filter(const NetClientOptions *opts, const char *name,
+ NetClientState *peer, Error **errp);
+
#endif /* QEMU_NET_CLIENTS_H */
diff --git a/net/filter.c b/net/filter.c
new file mode 100644
index 0000000..006c64a
--- /dev/null
+++ b/net/filter.c
@@ -0,0 +1,200 @@
+/*
+ * COarse-grain LOck-stepping Virtual Machines for Non-stop Service
(COLO)
+ * (a.k.a. Fault Tolerance or Continuous Replication)
+ *
+ * Copyright (c) 2015 HUAWEI TECHNOLOGIES CO., LTD.
+ * Copyright (c) 2015 FUJITSU LIMITED
+ * Copyright (c) 2015 Intel Corporation
+ *
+ * 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/net.h"
+#include "clients.h"
+#include "qemu-common.h"
+#include "qemu/error-report.h"
+
+typedef struct FILTERState {
+ NetClientState nc;
+ NetClientState *backend;
+} FILTERState;
+
+static ssize_t filter_receive(NetClientState *nc, NetClientState
*sender,
+ unsigned flags, const uint8_t *data,
size_t size)
+{
+ FILTERState *s = DO_UPCAST(FILTERState, nc, nc);
+ NetClientState *issued_nc = NULL;
+ ssize_t ret;
+
+ if (sender->info->type == NET_CLIENT_OPTIONS_KIND_NIC) {
+ /* packet received from NIC */
+ printf("packet received from NIC!!!\n");
+ issued_nc = s->backend;
+ } else {
+ /* packet received from backend */
+ printf("packet received from backend!!!\n");
+ issued_nc = nc->peer;
+ }
+
+ if (flags & QEMU_NET_PACKET_FLAG_RAW &&
issued_nc->info->receive_raw) {
+ ret = issued_nc->info->receive_raw(issued_nc, data, size);
+ } else {
+ ret = issued_nc->info->receive(issued_nc, data, size);
+ }
+
+ return ret;
+}
+
+static void filter_cleanup(NetClientState *nc)
+{
+ return;
+}
+
+static bool filter_has_ufo(NetClientState *nc)
+{
+ FILTERState *s = DO_UPCAST(FILTERState, nc, nc);
+ NetClientState *backend = s->backend;
+
+ if (!backend->info->has_ufo) {
+ return false;
+ }
+
+ return backend->info->has_ufo(backend);
+}
+
+static bool filter_has_vnet_hdr(NetClientState *nc)
+{
+ FILTERState *s = DO_UPCAST(FILTERState, nc, nc);
+ NetClientState *backend = s->backend;
+
+ if (!backend->info->has_vnet_hdr) {
+ return false;
+ }
+
+ return backend->info->has_vnet_hdr(backend);
+}
+
+static bool filter_has_vnet_hdr_len(NetClientState *nc, int len)
+{
+ FILTERState *s = DO_UPCAST(FILTERState, nc, nc);
+ NetClientState *backend = s->backend;
+
+ if (!backend->info->has_vnet_hdr_len) {
+ return false;
+ }
+
+ return backend->info->has_vnet_hdr_len(backend, len);
+}
+
+static void filter_using_vnet_hdr(NetClientState *nc, bool
using_vnet_hdr)
+{
+ FILTERState *s = DO_UPCAST(FILTERState, nc, nc);
+ NetClientState *backend = s->backend;
+
+ if (!backend->info->using_vnet_hdr) {
+ return;
+ }
+
+ backend->info->using_vnet_hdr(backend, using_vnet_hdr);
+}
+
+static void filter_set_offload(NetClientState *nc, int csum, int tso4,
+ int tso6, int ecn, int ufo)
+{
+ FILTERState *s = DO_UPCAST(FILTERState, nc, nc);
+ NetClientState *backend = s->backend;
+
+ if (!backend->info->set_offload) {
+ return;
+ }
+
+ backend->info->set_offload(backend, csum, tso4, tso6, ecn, ufo);
+}
+
+static void filter_set_vnet_hdr_len(NetClientState *nc, int len)
+{
+ FILTERState *s = DO_UPCAST(FILTERState, nc, nc);
+ NetClientState *backend = s->backend;
+
+ if (!backend->info->set_vnet_hdr_len) {
+ return;
+ }
+
+ backend->info->set_vnet_hdr_len(backend, len);
+}
+
+static int filter_set_vnet_le(NetClientState *nc, bool is_le)
+{
+ FILTERState *s = DO_UPCAST(FILTERState, nc, nc);
+ NetClientState *backend = s->backend;
+
+ if (!backend->info->set_vnet_le) {
+ return -ENOSYS;
+ }
+
+ return backend->info->set_vnet_le(backend, is_le);
+}
+
+static int filter_set_vnet_be(NetClientState *nc, bool is_be)
+{
+ FILTERState *s = DO_UPCAST(FILTERState, nc, nc);
+ NetClientState *backend = s->backend;
+
+ if (!backend->info->set_vnet_be) {
+ return -ENOSYS;
+ }
+
+ return backend->info->set_vnet_be(backend, is_be);
+}
+
+static NetClientInfo net_filter_info = {
+ .type = NET_CLIENT_OPTIONS_KIND_FILTER,
+ .size = sizeof(FILTERState),
+ .receive_filter = filter_receive,
+ .cleanup = filter_cleanup,
+ .has_ufo = filter_has_ufo,
+ .has_vnet_hdr = filter_has_vnet_hdr,
+ .has_vnet_hdr_len = filter_has_vnet_hdr_len,
+ .using_vnet_hdr = filter_using_vnet_hdr,
+ .set_offload = filter_set_offload,
+ .set_vnet_hdr_len = filter_set_vnet_hdr_len,
+ .set_vnet_le = filter_set_vnet_le,
+ .set_vnet_be = filter_set_vnet_be,
+};
+
+int net_init_filter(const NetClientOptions *opts, const char *name,
+ NetClientState *peer, Error **errp)
+{
+ NetClientState *nc;
+ FILTERState *s;
+ const NetdevFilterOptions *filter;
+ char *backend_id = NULL;
+ /* char *plugin = NULL; */
+
+ assert(opts->kind == NET_CLIENT_OPTIONS_KIND_FILTER);
+ filter = opts->filter;
+ assert(filter->has_backend);
+
+ backend_id = filter->backend;
+ /* plugin = filter->has_plugin ? filter->plugin : NULL; */
+
+ nc = qemu_new_net_client(&net_filter_info, peer, "filter", name);
+ /*
+ * TODO: Both backend and frontend packets will use this queue, we
+ * double this queue's maxlen
+ */
+ s = DO_UPCAST(FILTERState, nc, nc);
+ s->backend = qemu_find_netdev(backend_id);
+ if (!s->backend) {
+ error_setg(errp, "invalid backend name specified");
+ return -1;
+ }
+
+ s->backend->peer = nc;
+ /*
+ * TODO:
+ * init filter plugin
+ */
+ return 0;
+}
diff --git a/net/net.c b/net/net.c
index 28a5597..466c6ff 100644
--- a/net/net.c
+++ b/net/net.c
@@ -57,6 +57,7 @@ const char *host_net_devices[] = {
"tap",
"socket",
"dump",
+ "filter",
#ifdef CONFIG_NET_BRIDGE
"bridge",
#endif
@@ -571,7 +572,9 @@ ssize_t qemu_deliver_packet(NetClientState *sender,
return 0;
}
- if (flags & QEMU_NET_PACKET_FLAG_RAW && nc->info->receive_raw) {
+ if (nc->info->receive_filter) {
+ ret = nc->info->receive_filter(nc, sender, flags, data, size);
+ } else if (flags & QEMU_NET_PACKET_FLAG_RAW &&
nc->info->receive_raw) {
ret = nc->info->receive_raw(nc, data, size);
} else {
ret = nc->info->receive(nc, data, size);
@@ -886,6 +889,7 @@ static int (* const
net_client_init_fun[NET_CLIENT_OPTIONS_KIND_MAX])(
const char *name,
NetClientState *peer, Error **errp) = {
[NET_CLIENT_OPTIONS_KIND_NIC] = net_init_nic,
+ [NET_CLIENT_OPTIONS_KIND_FILTER] = net_init_filter,
#ifdef CONFIG_SLIRP
[NET_CLIENT_OPTIONS_KIND_USER] = net_init_slirp,
#endif
diff --git a/qapi-schema.json b/qapi-schema.json
index a0a45f7..3329973 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -2063,7 +2063,7 @@
# Add a network backend.
#
# @type: the type of network backend. Current valid values are
'user', 'tap',
-# 'vde', 'socket', 'dump' and 'bridge'
+# 'vde', 'socket', 'dump' , 'bridge' and 'filter'
#
# @id: the name of the new network backend
#
@@ -2474,6 +2474,24 @@
'*vhostforce': 'bool' } }
##
+# @NetdevFilterOptions
+#
+# A net filter between network backend and NIC device
+#
+# @plugin: #optional a plugin represent a set of filter rules,
+# by default, if no plugin is supplied, the net filter
will do
+# nothing but pass all packets to network backend.
+#
+# @backend: the network backend.
+#
+# Since 2.5
+##
+{ 'struct': 'NetdevFilterOptions',
+ 'data': {
+ '*plugin': 'str',
+ '*backend': 'str' } }
+
+##
# @NetClientOptions
#
# A discriminated record of network device traits.
@@ -2496,7 +2514,8 @@
'bridge': 'NetdevBridgeOptions',
'hubport': 'NetdevHubPortOptions',
'netmap': 'NetdevNetmapOptions',
- 'vhost-user': 'NetdevVhostUserOptions' } }
+ 'vhost-user': 'NetdevVhostUserOptions',
+ 'filter': 'NetdevFilterOptions'} }
##
# @NetLegacy