* [Qemu-devel] [PATCH v2 0/5] For QEMU 2.5: Network traffic dumping for -netdev devices
@ 2015-07-13 7:39 Thomas Huth
2015-07-13 7:39 ` [Qemu-devel] [PATCH v2 1/5] net/dump: Add support for receive_iov function Thomas Huth
` (6 more replies)
0 siblings, 7 replies; 35+ messages in thread
From: Thomas Huth @ 2015-07-13 7:39 UTC (permalink / raw)
To: qemu-devel, Stefan Hajnoczi, Jason Wang; +Cc: Markus Armbruster
The "-net dump" option only works with the "-net" option. So far, it
is not possible to dump network traffic with the "-netdev" option yet.
This patch series now fixes this ugliness by enabling dumping for the
"-netdev" option, too.
Unlike with the "-net dump" option, the "-netdev" parameter does not
"abuse" the disliked internal vlan hub infrastructure to achieve this
functionality. This patch series introduces a new, clean "dumpfile=xxx"
option for the -netdev parameters instead.
The patches are intended for QEMU version 2.5, but I'm sending them
now already in case somebody got some spare minutes left for reviewing
them again.
Note: I did not address multiqueue devices yet (but added a TODO in the
source code) ... I will address that later when the basic patches have
been accepted.
v2:
- Restructured the code a little bit
- Updated target QEMU version from 2.4. to 2.5
- Addressed review feedback from Jason, Stefan and Markus:
- Use iov_copy() instead of copying the iov manually
- Fix return value of net_dump_receive_iov() if fd is invalid
- Use get_vhost_net() to detect vhost devices
- Close the fd when netdev is deleted
- Added some more comments in the source code
Thomas Huth (5):
net/dump: Add support for receive_iov function
net/dump: Move DumpState into NetClientState
net/dump: Rework net-dump init functions
net/dump: Add dump option for netdev devices
qemu options: Add information about dumpfile to help text
include/net/net.h | 8 +++++
net/clients.h | 6 ++++
net/dump.c | 99 +++++++++++++++++++++++++++++++++++++++----------------
net/net.c | 38 ++++++++++++++++++++-
qapi-schema.json | 12 +++++--
qemu-options.hx | 26 ++++++++++-----
6 files changed, 149 insertions(+), 40 deletions(-)
--
1.8.3.1
^ permalink raw reply [flat|nested] 35+ messages in thread
* [Qemu-devel] [PATCH v2 1/5] net/dump: Add support for receive_iov function
2015-07-13 7:39 [Qemu-devel] [PATCH v2 0/5] For QEMU 2.5: Network traffic dumping for -netdev devices Thomas Huth
@ 2015-07-13 7:39 ` Thomas Huth
2015-07-13 7:39 ` [Qemu-devel] [PATCH v2 2/5] net/dump: Move DumpState into NetClientState Thomas Huth
` (5 subsequent siblings)
6 siblings, 0 replies; 35+ messages in thread
From: Thomas Huth @ 2015-07-13 7:39 UTC (permalink / raw)
To: qemu-devel, Stefan Hajnoczi, Jason Wang; +Cc: Markus Armbruster
Adding a proper receive_iov function to the net dump module. This
will make it easier to support the dump feature for the -netdev
option in later patches.
Also make the receive functions (and the cleanup function) available
to the other parts of the source code so we can later use them for
dumping from net.c, too.
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
net/clients.h | 4 ++++
net/dump.c | 30 ++++++++++++++++++++++++------
2 files changed, 28 insertions(+), 6 deletions(-)
diff --git a/net/clients.h b/net/clients.h
index d47530e..403dc88 100644
--- a/net/clients.h
+++ b/net/clients.h
@@ -29,6 +29,10 @@
int net_init_dump(const NetClientOptions *opts, const char *name,
NetClientState *peer, Error **errp);
+void net_dump_cleanup(NetClientState *nc);
+ssize_t net_dump_receive(NetClientState *nc, const uint8_t *buf, size_t size);
+ssize_t net_dump_receive_iov(NetClientState *nc, const struct iovec *iov,
+ int cnt);
#ifdef CONFIG_SLIRP
int net_init_slirp(const NetClientOptions *opts, const char *name,
diff --git a/net/dump.c b/net/dump.c
index 02c8064..935918e 100644
--- a/net/dump.c
+++ b/net/dump.c
@@ -25,6 +25,7 @@
#include "clients.h"
#include "qemu-common.h"
#include "qemu/error-report.h"
+#include "qemu/iov.h"
#include "qemu/log.h"
#include "qemu/timer.h"
#include "hub.h"
@@ -57,12 +58,15 @@ struct pcap_sf_pkthdr {
uint32_t len;
};
-static ssize_t dump_receive(NetClientState *nc, const uint8_t *buf, size_t size)
+ssize_t net_dump_receive_iov(NetClientState *nc, const struct iovec *iov,
+ int cnt)
{
DumpState *s = DO_UPCAST(DumpState, nc, nc);
struct pcap_sf_pkthdr hdr;
int64_t ts;
int caplen;
+ size_t size = iov_size(iov, cnt);
+ struct iovec dumpiov[cnt + 1];
/* Early return in case of previous error. */
if (s->fd < 0) {
@@ -76,8 +80,12 @@ static ssize_t dump_receive(NetClientState *nc, const uint8_t *buf, size_t size)
hdr.ts.tv_usec = ts % 1000000;
hdr.caplen = caplen;
hdr.len = size;
- if (write(s->fd, &hdr, sizeof(hdr)) != sizeof(hdr) ||
- write(s->fd, buf, caplen) != caplen) {
+
+ dumpiov[0].iov_base = &hdr;
+ dumpiov[0].iov_len = sizeof(hdr);
+ cnt = iov_copy(&dumpiov[1], cnt, iov, cnt, 0, caplen);
+
+ if (writev(s->fd, dumpiov, cnt + 1) != sizeof(hdr) + caplen) {
qemu_log("-net dump write error - stop dump\n");
close(s->fd);
s->fd = -1;
@@ -86,7 +94,16 @@ static ssize_t dump_receive(NetClientState *nc, const uint8_t *buf, size_t size)
return size;
}
-static void dump_cleanup(NetClientState *nc)
+ssize_t net_dump_receive(NetClientState *nc, const uint8_t *buf, size_t size)
+{
+ struct iovec iov = {
+ .iov_base = (void *)buf,
+ .iov_len = size
+ };
+ return net_dump_receive_iov(nc, &iov, 1);
+}
+
+void net_dump_cleanup(NetClientState *nc)
{
DumpState *s = DO_UPCAST(DumpState, nc, nc);
@@ -96,8 +113,9 @@ static void dump_cleanup(NetClientState *nc)
static NetClientInfo net_dump_info = {
.type = NET_CLIENT_OPTIONS_KIND_DUMP,
.size = sizeof(DumpState),
- .receive = dump_receive,
- .cleanup = dump_cleanup,
+ .receive = net_dump_receive,
+ .receive_iov = net_dump_receive_iov,
+ .cleanup = net_dump_cleanup,
};
static int net_dump_init(NetClientState *peer, const char *device,
--
1.8.3.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [Qemu-devel] [PATCH v2 2/5] net/dump: Move DumpState into NetClientState
2015-07-13 7:39 [Qemu-devel] [PATCH v2 0/5] For QEMU 2.5: Network traffic dumping for -netdev devices Thomas Huth
2015-07-13 7:39 ` [Qemu-devel] [PATCH v2 1/5] net/dump: Add support for receive_iov function Thomas Huth
@ 2015-07-13 7:39 ` Thomas Huth
2015-07-13 7:39 ` [Qemu-devel] [PATCH v2 3/5] net/dump: Rework net-dump init functions Thomas Huth
` (4 subsequent siblings)
6 siblings, 0 replies; 35+ messages in thread
From: Thomas Huth @ 2015-07-13 7:39 UTC (permalink / raw)
To: qemu-devel, Stefan Hajnoczi, Jason Wang; +Cc: Markus Armbruster
We want to provide (almost) every netdev device with the ability
to dump network traffic, so let's embed the DumpState into the
NetClientState structure.
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
include/net/net.h | 7 +++++++
net/dump.c | 17 +++++------------
2 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/include/net/net.h b/include/net/net.h
index 6a6cbef..b265047 100644
--- a/include/net/net.h
+++ b/include/net/net.h
@@ -58,6 +58,12 @@ typedef void (SetVnetHdrLen)(NetClientState *, int);
typedef int (SetVnetLE)(NetClientState *, bool);
typedef int (SetVnetBE)(NetClientState *, bool);
+typedef struct NetDumpState {
+ int64_t start_ts;
+ int fd;
+ int pcap_caplen;
+} NetDumpState;
+
typedef struct NetClientInfo {
NetClientOptionsKind type;
size_t size;
@@ -92,6 +98,7 @@ struct NetClientState {
NetClientDestructor *destructor;
unsigned int queue_index;
unsigned rxfilter_notify_enabled:1;
+ NetDumpState nds;
};
typedef struct NICState {
diff --git a/net/dump.c b/net/dump.c
index 935918e..a430b96 100644
--- a/net/dump.c
+++ b/net/dump.c
@@ -30,13 +30,6 @@
#include "qemu/timer.h"
#include "hub.h"
-typedef struct DumpState {
- NetClientState nc;
- int64_t start_ts;
- int fd;
- int pcap_caplen;
-} DumpState;
-
#define PCAP_MAGIC 0xa1b2c3d4
struct pcap_file_hdr {
@@ -61,7 +54,7 @@ struct pcap_sf_pkthdr {
ssize_t net_dump_receive_iov(NetClientState *nc, const struct iovec *iov,
int cnt)
{
- DumpState *s = DO_UPCAST(DumpState, nc, nc);
+ NetDumpState *s = &nc->nds;
struct pcap_sf_pkthdr hdr;
int64_t ts;
int caplen;
@@ -105,14 +98,14 @@ ssize_t net_dump_receive(NetClientState *nc, const uint8_t *buf, size_t size)
void net_dump_cleanup(NetClientState *nc)
{
- DumpState *s = DO_UPCAST(DumpState, nc, nc);
+ NetDumpState *s = &nc->nds;
close(s->fd);
}
static NetClientInfo net_dump_info = {
.type = NET_CLIENT_OPTIONS_KIND_DUMP,
- .size = sizeof(DumpState),
+ .size = sizeof(NetClientState),
.receive = net_dump_receive,
.receive_iov = net_dump_receive_iov,
.cleanup = net_dump_cleanup,
@@ -124,7 +117,7 @@ static int net_dump_init(NetClientState *peer, const char *device,
{
struct pcap_file_hdr hdr;
NetClientState *nc;
- DumpState *s;
+ NetDumpState *s;
struct tm tm;
int fd;
@@ -153,7 +146,7 @@ static int net_dump_init(NetClientState *peer, const char *device,
snprintf(nc->info_str, sizeof(nc->info_str),
"dump to %s (len=%d)", filename, len);
- s = DO_UPCAST(DumpState, nc, nc);
+ s = &nc->nds;
s->fd = fd;
s->pcap_caplen = len;
--
1.8.3.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [Qemu-devel] [PATCH v2 3/5] net/dump: Rework net-dump init functions
2015-07-13 7:39 [Qemu-devel] [PATCH v2 0/5] For QEMU 2.5: Network traffic dumping for -netdev devices Thomas Huth
2015-07-13 7:39 ` [Qemu-devel] [PATCH v2 1/5] net/dump: Add support for receive_iov function Thomas Huth
2015-07-13 7:39 ` [Qemu-devel] [PATCH v2 2/5] net/dump: Move DumpState into NetClientState Thomas Huth
@ 2015-07-13 7:39 ` Thomas Huth
2015-07-13 7:39 ` [Qemu-devel] [PATCH v2 4/5] net/dump: Add dump option for netdev devices Thomas Huth
` (3 subsequent siblings)
6 siblings, 0 replies; 35+ messages in thread
From: Thomas Huth @ 2015-07-13 7:39 UTC (permalink / raw)
To: qemu-devel, Stefan Hajnoczi, Jason Wang; +Cc: Markus Armbruster
Move the creation of the dump client from net_dump_init() into
net_init_dump(), so we can later use the former function for netdev
devices, too. Also rename net_dump_init() to net_dump_state_init()
to make it easier distinguishable from net_init_dump().
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
net/dump.c | 24 +++++++++++++-----------
1 file changed, 13 insertions(+), 11 deletions(-)
diff --git a/net/dump.c b/net/dump.c
index a430b96..fa63f0b 100644
--- a/net/dump.c
+++ b/net/dump.c
@@ -111,12 +111,10 @@ static NetClientInfo net_dump_info = {
.cleanup = net_dump_cleanup,
};
-static int net_dump_init(NetClientState *peer, const char *device,
- const char *name, const char *filename, int len,
- Error **errp)
+static int net_dump_state_init(NetClientState *nc, const char *filename,
+ int len, Error **errp)
{
struct pcap_file_hdr hdr;
- NetClientState *nc;
NetDumpState *s;
struct tm tm;
int fd;
@@ -141,11 +139,6 @@ static int net_dump_init(NetClientState *peer, const char *device,
return -1;
}
- nc = qemu_new_net_client(&net_dump_info, peer, device, name);
-
- snprintf(nc->info_str, sizeof(nc->info_str),
- "dump to %s (len=%d)", filename, len);
-
s = &nc->nds;
s->fd = fd;
@@ -160,10 +153,11 @@ static int net_dump_init(NetClientState *peer, const char *device,
int net_init_dump(const NetClientOptions *opts, const char *name,
NetClientState *peer, Error **errp)
{
- int len;
+ int len, rc;
const char *file;
char def_file[128];
const NetdevDumpOptions *dump;
+ NetClientState *nc;
assert(opts->kind == NET_CLIENT_OPTIONS_KIND_DUMP);
dump = opts->dump;
@@ -193,5 +187,13 @@ int net_init_dump(const NetClientOptions *opts, const char *name,
len = 65536;
}
- return net_dump_init(peer, "dump", name, file, len, errp);
+ nc = qemu_new_net_client(&net_dump_info, peer, "dump", name);
+ snprintf(nc->info_str, sizeof(nc->info_str),
+ "dump to %s (len=%d)", file, len);
+
+ rc = net_dump_state_init(nc, file, len, errp);
+ if (rc) {
+ qemu_del_net_client(nc);
+ }
+ return rc;
}
--
1.8.3.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [Qemu-devel] [PATCH v2 4/5] net/dump: Add dump option for netdev devices
2015-07-13 7:39 [Qemu-devel] [PATCH v2 0/5] For QEMU 2.5: Network traffic dumping for -netdev devices Thomas Huth
` (2 preceding siblings ...)
2015-07-13 7:39 ` [Qemu-devel] [PATCH v2 3/5] net/dump: Rework net-dump init functions Thomas Huth
@ 2015-07-13 7:39 ` Thomas Huth
2015-07-13 7:39 ` [Qemu-devel] [PATCH v2 5/5] qemu options: Add information about dumpfile to help text Thomas Huth
` (2 subsequent siblings)
6 siblings, 0 replies; 35+ messages in thread
From: Thomas Huth @ 2015-07-13 7:39 UTC (permalink / raw)
To: qemu-devel, Stefan Hajnoczi, Jason Wang; +Cc: Markus Armbruster
So far it is not possible to dump network traffic with the "-netdev"
option yet - this is only possible with the "-net" option and an
internal "hub".
This patch now fixes this ugliness by adding a proper, generic
dumpfile parameter to the "-netdev" option.
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
include/net/net.h | 1 +
net/clients.h | 2 ++
net/dump.c | 28 ++++++++++++++++++++++++++++
net/net.c | 38 +++++++++++++++++++++++++++++++++++++-
qapi-schema.json | 12 ++++++++++--
5 files changed, 78 insertions(+), 3 deletions(-)
diff --git a/include/net/net.h b/include/net/net.h
index b265047..62abc98 100644
--- a/include/net/net.h
+++ b/include/net/net.h
@@ -98,6 +98,7 @@ struct NetClientState {
NetClientDestructor *destructor;
unsigned int queue_index;
unsigned rxfilter_notify_enabled:1;
+ unsigned netdev_dump_enabled:1;
NetDumpState nds;
};
diff --git a/net/clients.h b/net/clients.h
index 403dc88..e120ed0 100644
--- a/net/clients.h
+++ b/net/clients.h
@@ -29,6 +29,8 @@
int net_init_dump(const NetClientOptions *opts, const char *name,
NetClientState *peer, Error **errp);
+int netdev_init_dumpfile(const Netdev *netdev, const char *name,
+ Error **errp);
void net_dump_cleanup(NetClientState *nc);
ssize_t net_dump_receive(NetClientState *nc, const uint8_t *buf, size_t size);
ssize_t net_dump_receive_iov(NetClientState *nc, const struct iovec *iov,
diff --git a/net/dump.c b/net/dump.c
index fa63f0b..2cb3b4b 100644
--- a/net/dump.c
+++ b/net/dump.c
@@ -28,6 +28,7 @@
#include "qemu/iov.h"
#include "qemu/log.h"
#include "qemu/timer.h"
+#include "net/vhost_net.h"
#include "hub.h"
#define PCAP_MAGIC 0xa1b2c3d4
@@ -197,3 +198,30 @@ int net_init_dump(const NetClientOptions *opts, const char *name,
}
return rc;
}
+
+int netdev_init_dumpfile(const Netdev *netdev, const char *name,
+ Error **errp)
+{
+ NetClientState *nc;
+ int dumplen = 65536;
+ int rc;
+
+ nc = qemu_find_netdev(name);
+ assert(nc);
+ if (get_vhost_net(nc)) {
+ error_setg(errp, "dumping does not work with vhost enabled");
+ return -1;
+ }
+
+ if (netdev->has_dumplen) {
+ dumplen = netdev->dumplen;
+ }
+
+ rc = net_dump_state_init(nc, netdev->dumpfile, dumplen, errp);
+ if (rc == 0) {
+ nc->netdev_dump_enabled = true;
+ }
+ /* TODO: Setup for multiqueue devices? */
+
+ return rc;
+}
diff --git a/net/net.c b/net/net.c
index 6ff7fec..1bdb731 100644
--- a/net/net.c
+++ b/net/net.c
@@ -360,6 +360,11 @@ static void qemu_cleanup_net_client(NetClientState *nc)
{
QTAILQ_REMOVE(&net_clients, nc, next);
+ if (nc->netdev_dump_enabled) {
+ net_dump_cleanup(nc);
+ nc->netdev_dump_enabled = 0;
+ }
+
if (nc->info->cleanup) {
nc->info->cleanup(nc);
}
@@ -571,6 +576,21 @@ ssize_t qemu_deliver_packet(NetClientState *sender,
return 0;
}
+ /*
+ * Log network traffic into a dump file. Note: This should ideally
+ * be done after calling the ->receive() function below to make sure
+ * that we only log the packets that have really been sent. However,
+ * this does not work right with slirp networking since it immediately
+ * sends reply packets during the receive() function already, so we
+ * would get a wrong order of the packets in the dump file in that case.
+ */
+ if (sender->netdev_dump_enabled) {
+ net_dump_receive(sender, data, size);
+ }
+ if (nc->netdev_dump_enabled) {
+ net_dump_receive(nc, data, size);
+ }
+
if (flags & QEMU_NET_PACKET_FLAG_RAW && nc->info->receive_raw) {
ret = nc->info->receive_raw(nc, data, size);
} else {
@@ -687,6 +707,13 @@ ssize_t qemu_deliver_packet_iov(NetClientState *sender,
return 0;
}
+ if (sender->netdev_dump_enabled) {
+ net_dump_receive_iov(sender, iov, iovcnt);
+ }
+ if (nc->netdev_dump_enabled) {
+ net_dump_receive_iov(nc, iov, iovcnt);
+ }
+
if (nc->info->receive_iov) {
ret = nc->info->receive_iov(nc, iov, iovcnt);
} else {
@@ -880,7 +907,6 @@ static int net_init_nic(const NetClientOptions *opts, const char *name,
return idx;
}
-
static int (* const net_client_init_fun[NET_CLIENT_OPTIONS_KIND_MAX])(
const NetClientOptions *opts,
const char *name,
@@ -966,6 +992,16 @@ static int net_client_init1(const void *object, int is_netdev, Error **errp)
}
return -1;
}
+
+ if (is_netdev) {
+ const Netdev *netdev = object;
+ if (netdev->has_dumpfile) {
+ if (netdev_init_dumpfile(netdev, name, errp)) {
+ return -1;
+ }
+ }
+ }
+
return 0;
}
diff --git a/qapi-schema.json b/qapi-schema.json
index 1285b8c..e7cd21f 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -2531,14 +2531,22 @@
#
# @id: identifier for monitor commands.
#
+# @dumpfile: #optional name of a file where network traffic should be logged
+# (since: 2.5)
+#
+# @dumplen: #optional maximum length of the network packets in the dump
+# (since: 2.5)
+#
# @opts: device type specific properties
#
# Since 1.2
##
{ 'struct': 'Netdev',
'data': {
- 'id': 'str',
- 'opts': 'NetClientOptions' } }
+ 'id': 'str',
+ '*dumpfile': 'str',
+ '*dumplen': 'int32',
+ 'opts': 'NetClientOptions' } }
##
# @InetSocketAddress
--
1.8.3.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [Qemu-devel] [PATCH v2 5/5] qemu options: Add information about dumpfile to help text
2015-07-13 7:39 [Qemu-devel] [PATCH v2 0/5] For QEMU 2.5: Network traffic dumping for -netdev devices Thomas Huth
` (3 preceding siblings ...)
2015-07-13 7:39 ` [Qemu-devel] [PATCH v2 4/5] net/dump: Add dump option for netdev devices Thomas Huth
@ 2015-07-13 7:39 ` Thomas Huth
2015-07-22 6:35 ` [Qemu-devel] [PATCH v2 0/5] For QEMU 2.5: Network traffic dumping for -netdev devices Jason Wang
2015-07-22 10:52 ` Yang Hongyang
6 siblings, 0 replies; 35+ messages in thread
From: Thomas Huth @ 2015-07-13 7:39 UTC (permalink / raw)
To: qemu-devel, Stefan Hajnoczi, Jason Wang; +Cc: Markus Armbruster
Describe the new dumpfile and dumplen options in the help text.
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
qemu-options.hx | 26 ++++++++++++++++++--------
1 file changed, 18 insertions(+), 8 deletions(-)
diff --git a/qemu-options.hx b/qemu-options.hx
index 7b8efbf..58cf53f 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1461,20 +1461,21 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
#ifdef CONFIG_SLIRP
"-netdev user,id=str[,net=addr[/mask]][,host=addr][,restrict=on|off]\n"
" [,hostname=host][,dhcpstart=addr][,dns=addr][,dnssearch=domain][,tftp=dir]\n"
- " [,bootfile=f][,hostfwd=rule][,guestfwd=rule]"
+ " [,bootfile=f][,hostfwd=rule][,guestfwd=rule][,dumpfile=file[,dumplen=len]]\n"
#ifndef _WIN32
- "[,smb=dir[,smbserver=addr]]\n"
+ " [,smb=dir[,smbserver=addr]]\n"
#endif
" configure a user mode network backend with ID 'str',\n"
" its DHCP server and optional services\n"
#endif
#ifdef _WIN32
- "-netdev tap,id=str,ifname=name\n"
+ "-netdev tap,id=str,ifname=name[,dumpfile=file[,dumplen=len]]\n"
" configure a host TAP network backend with ID 'str'\n"
#else
"-netdev tap,id=str[,fd=h][,fds=x:y:...:z][,ifname=name][,script=file][,downscript=dfile]\n"
" [,helper=helper][,sndbuf=nbytes][,vnet_hdr=on|off][,vhost=on|off]\n"
" [,vhostfd=h][,vhostfds=x:y:...:z][,vhostforce=on|off][,queues=n]\n"
+ " [,dumpfile=file[,dumplen=len]]\n"
" configure a host TAP network backend with ID 'str'\n"
" use network scripts 'file' (default=" DEFAULT_NETWORK_SCRIPT ")\n"
" to configure it and 'dfile' (default=" DEFAULT_NETWORK_DOWN_SCRIPT ")\n"
@@ -1494,7 +1495,7 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
" use 'vhostfd=h' to connect to an already opened vhost net device\n"
" use 'vhostfds=x:y:...:z to connect to multiple already opened vhost net devices\n"
" use 'queues=n' to specify the number of queues to be created for multiqueue TAP\n"
- "-netdev bridge,id=str[,br=bridge][,helper=helper]\n"
+ "-netdev bridge,id=str[,br=bridge][,helper=helper][,dumpfile=file[,dumplen=len]]\n"
" configure a host TAP network backend with ID 'str' that is\n"
" connected to a bridge (default=" DEFAULT_BRIDGE_INTERFACE ")\n"
" using the program 'helper (default=" DEFAULT_BRIDGE_HELPER ")\n"
@@ -1503,7 +1504,7 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
"-netdev l2tpv3,id=str,src=srcaddr,dst=dstaddr[,srcport=srcport][,dstport=dstport]\n"
" [,rxsession=rxsession],txsession=txsession[,ipv6=on/off][,udp=on/off]\n"
" [,cookie64=on/off][,counter][,pincounter][,txcookie=txcookie]\n"
- " [,rxcookie=rxcookie][,offset=offset]\n"
+ " [,rxcookie=rxcookie][,offset=offset][,dumpfile=file[,dumplen=len]]\n"
" configure a network backend with ID 'str' connected to\n"
" an Ethernet over L2TPv3 pseudowire.\n"
" Linux kernel 3.3+ as well as most routers can talk\n"
@@ -1527,30 +1528,34 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
" use 'offset=X' to add an extra offset between header and data\n"
#endif
"-netdev socket,id=str[,fd=h][,listen=[host]:port][,connect=host:port]\n"
+ " [,dumpfile=file[,dumplen=len]]\n"
" configure a network backend to connect to another network\n"
" using a socket connection\n"
"-netdev socket,id=str[,fd=h][,mcast=maddr:port[,localaddr=addr]]\n"
+ " [,dumpfile=file[,dumplen=len]]\n"
" configure a network backend to connect to a multicast maddr and port\n"
" use 'localaddr=addr' to specify the host address to send packets from\n"
"-netdev socket,id=str[,fd=h][,udp=host:port][,localaddr=host:port]\n"
+ " [,dumpfile=file[,dumplen=len]]\n"
" configure a network backend to connect to another network\n"
" using an UDP tunnel\n"
#ifdef CONFIG_VDE
"-netdev vde,id=str[,sock=socketpath][,port=n][,group=groupname][,mode=octalmode]\n"
+ " [,dumpfile=file[,dumplen=len]]\n"
" configure a network backend to connect to port 'n' of a vde switch\n"
" running on host and listening for incoming connections on 'socketpath'.\n"
" Use group 'groupname' and mode 'octalmode' to change default\n"
" ownership and permissions for communication port.\n"
#endif
#ifdef CONFIG_NETMAP
- "-netdev netmap,id=str,ifname=name[,devname=nmname]\n"
+ "-netdev netmap,id=str,ifname=name[,devname=nmname][,dumpfile=file[,dumplen=len]]\n"
" attach to the existing netmap-enabled network interface 'name', or to a\n"
" VALE port (created on the fly) called 'name' ('nmname' is name of the \n"
" netmap device, defaults to '/dev/netmap')\n"
#endif
"-netdev vhost-user,id=str,chardev=dev[,vhostforce=on|off]\n"
" configure a vhost-user network, backed by a chardev 'dev'\n"
- "-netdev hubport,id=str,hubid=n\n"
+ "-netdev hubport,id=str,hubid=n[,dumpfile=file[,dumplen=len]]\n"
" configure a hub port on QEMU VLAN 'n'\n", QEMU_ARCH_ALL)
DEF("net", HAS_ARG, QEMU_OPTION_net,
"-net nic[,vlan=n][,macaddr=mac][,model=type][,name=str][,addr=str][,vectors=v]\n"
@@ -1981,10 +1986,15 @@ qemu -m 512 -object memory-backend-file,id=mem,size=512M,mem-path=/hugetlbfs,sha
-device virtio-net-pci,netdev=net0
@end example
+@item -netdev ...,dumpfile=@var{file}[,dumplen=@var{len}]
@item -net dump[,vlan=@var{n}][,file=@var{file}][,len=@var{len}]
-Dump network traffic on VLAN @var{n} to file @var{file} (@file{qemu-vlan0.pcap} by default).
+Dump network traffic to file @var{file} (@file{qemu-vlan0.pcap} by default).
At most @var{len} bytes (64k by default) per packet are stored. The file format is
libpcap, so it can be analyzed with tools such as tcpdump or Wireshark.
+When dumping is wanted for -netdev devices, simply add the 'dumpfile=file'
+option as additional parameter. When dumping is wanted for a legacy -net
+network, specify an additional "-net dump,..." to dump the traffic on
+VLAN @var{n} (0 by default).
@item -net none
Indicate that no network devices should be configured. It is used to
--
1.8.3.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* Re: [Qemu-devel] [PATCH v2 0/5] For QEMU 2.5: Network traffic dumping for -netdev devices
2015-07-13 7:39 [Qemu-devel] [PATCH v2 0/5] For QEMU 2.5: Network traffic dumping for -netdev devices Thomas Huth
` (4 preceding siblings ...)
2015-07-13 7:39 ` [Qemu-devel] [PATCH v2 5/5] qemu options: Add information about dumpfile to help text Thomas Huth
@ 2015-07-22 6:35 ` Jason Wang
2015-07-22 10:52 ` Yang Hongyang
6 siblings, 0 replies; 35+ messages in thread
From: Jason Wang @ 2015-07-22 6:35 UTC (permalink / raw)
To: Thomas Huth, qemu-devel, Stefan Hajnoczi; +Cc: Markus Armbruster
On 07/13/2015 03:39 PM, Thomas Huth wrote:
> The "-net dump" option only works with the "-net" option. So far, it
> is not possible to dump network traffic with the "-netdev" option yet.
> This patch series now fixes this ugliness by enabling dumping for the
> "-netdev" option, too.
>
> Unlike with the "-net dump" option, the "-netdev" parameter does not
> "abuse" the disliked internal vlan hub infrastructure to achieve this
> functionality. This patch series introduces a new, clean "dumpfile=xxx"
> option for the -netdev parameters instead.
>
> The patches are intended for QEMU version 2.5, but I'm sending them
> now already in case somebody got some spare minutes left for reviewing
> them again.
>
> Note: I did not address multiqueue devices yet (but added a TODO in the
> source code) ... I will address that later when the basic patches have
> been accepted.
>
> v2:
> - Restructured the code a little bit
> - Updated target QEMU version from 2.4. to 2.5
> - Addressed review feedback from Jason, Stefan and Markus:
> - Use iov_copy() instead of copying the iov manually
> - Fix return value of net_dump_receive_iov() if fd is invalid
> - Use get_vhost_net() to detect vhost devices
> - Close the fd when netdev is deleted
> - Added some more comments in the source code
>
> Thomas Huth (5):
> net/dump: Add support for receive_iov function
> net/dump: Move DumpState into NetClientState
> net/dump: Rework net-dump init functions
> net/dump: Add dump option for netdev devices
> qemu options: Add information about dumpfile to help text
>
> include/net/net.h | 8 +++++
> net/clients.h | 6 ++++
> net/dump.c | 99 +++++++++++++++++++++++++++++++++++++++----------------
> net/net.c | 38 ++++++++++++++++++++-
> qapi-schema.json | 12 +++++--
> qemu-options.hx | 26 ++++++++++-----
> 6 files changed, 149 insertions(+), 40 deletions(-)
>
Reviewed-by: Jason Wang <jasowang@redhat.com>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [Qemu-devel] [PATCH v2 0/5] For QEMU 2.5: Network traffic dumping for -netdev devices
2015-07-13 7:39 [Qemu-devel] [PATCH v2 0/5] For QEMU 2.5: Network traffic dumping for -netdev devices Thomas Huth
` (5 preceding siblings ...)
2015-07-22 6:35 ` [Qemu-devel] [PATCH v2 0/5] For QEMU 2.5: Network traffic dumping for -netdev devices Jason Wang
@ 2015-07-22 10:52 ` Yang Hongyang
2015-07-22 10:55 ` [Qemu-devel] [PATCH] RFC/net: Add a net filter Yang Hongyang
6 siblings, 1 reply; 35+ messages in thread
From: Yang Hongyang @ 2015-07-22 10:52 UTC (permalink / raw)
To: Thomas Huth, qemu-devel, Stefan Hajnoczi, Jason Wang; +Cc: Markus Armbruster
Hi Thomas, Jason, Stefan
I'm reading the QEMU network subsystem and am thinking implement a
network filter between network backend and NIC devices. All packets
will pass by this filter, therefore, dump can be easily done with
the filter.
+--------------+ +-------------+
+----------+ | filter | |frontend(NIC)|
| real | | | | |
| network <--+backend <-------+ |
| backend | | peer +-------> peer |
+----------+ +--------------+ +-------------+
The filter is actually a full featured network backend, either you
can call this a transparent proxy.
A prototype patch will be sent in reply to this mail. The patch tested
with tap backend.
I want your input about whether this is plausible or the design of this
is completely wrong?
Thank you in advance.
On 07/13/2015 03:39 PM, Thomas Huth wrote:
> The "-net dump" option only works with the "-net" option. So far, it
> is not possible to dump network traffic with the "-netdev" option yet.
> This patch series now fixes this ugliness by enabling dumping for the
> "-netdev" option, too.
>
> Unlike with the "-net dump" option, the "-netdev" parameter does not
> "abuse" the disliked internal vlan hub infrastructure to achieve this
> functionality. This patch series introduces a new, clean "dumpfile=xxx"
> option for the -netdev parameters instead.
>
> The patches are intended for QEMU version 2.5, but I'm sending them
> now already in case somebody got some spare minutes left for reviewing
> them again.
>
> Note: I did not address multiqueue devices yet (but added a TODO in the
> source code) ... I will address that later when the basic patches have
> been accepted.
>
> v2:
> - Restructured the code a little bit
> - Updated target QEMU version from 2.4. to 2.5
> - Addressed review feedback from Jason, Stefan and Markus:
> - Use iov_copy() instead of copying the iov manually
> - Fix return value of net_dump_receive_iov() if fd is invalid
> - Use get_vhost_net() to detect vhost devices
> - Close the fd when netdev is deleted
> - Added some more comments in the source code
>
> Thomas Huth (5):
> net/dump: Add support for receive_iov function
> net/dump: Move DumpState into NetClientState
> net/dump: Rework net-dump init functions
> net/dump: Add dump option for netdev devices
> qemu options: Add information about dumpfile to help text
>
> include/net/net.h | 8 +++++
> net/clients.h | 6 ++++
> net/dump.c | 99 +++++++++++++++++++++++++++++++++++++++----------------
> net/net.c | 38 ++++++++++++++++++++-
> qapi-schema.json | 12 +++++--
> qemu-options.hx | 26 ++++++++++-----
> 6 files changed, 149 insertions(+), 40 deletions(-)
>
--
Thanks,
Yang.
^ permalink raw reply [flat|nested] 35+ messages in thread
* [Qemu-devel] [PATCH] RFC/net: Add a net filter
2015-07-22 10:52 ` Yang Hongyang
@ 2015-07-22 10:55 ` Yang Hongyang
2015-07-22 11:06 ` Daniel P. Berrange
` (3 more replies)
0 siblings, 4 replies; 35+ messages in thread
From: Yang Hongyang @ 2015-07-22 10:55 UTC (permalink / raw)
To: qemu-devel; +Cc: jasowang, Yang Hongyang, thuth, stefanha
This patch add a net filter between network backend and NIC devices.
All packets will pass by this filter.
TODO:
multiqueue support.
plugin support.
+--------------+ +-------------+
+----------+ | filter | |frontend(NIC)|
| real | | | | |
| network <--+backend <-------+ |
| backend | | peer +-------> peer |
+----------+ +--------------+ +-------------+
Usage:
-netdev tap,id=bn0 # you can use whatever backend as needed
-netdev filter,id=f0,backend=bn0,plugin=dump
-device e1000,netdev=f0
Signed-off-by: Yang Hongyang <yanghy@cn.fujitsu.com>
---
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
--
1.9.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* Re: [Qemu-devel] [PATCH] RFC/net: Add a net filter
2015-07-22 10:55 ` [Qemu-devel] [PATCH] RFC/net: Add a net filter Yang Hongyang
@ 2015-07-22 11:06 ` Daniel P. Berrange
2015-07-22 15:16 ` Yang Hongyang
2015-07-22 13:05 ` Thomas Huth
` (2 subsequent siblings)
3 siblings, 1 reply; 35+ messages in thread
From: Daniel P. Berrange @ 2015-07-22 11:06 UTC (permalink / raw)
To: Yang Hongyang; +Cc: thuth, jasowang, qemu-devel, stefanha
On Wed, Jul 22, 2015 at 06:55:36PM +0800, Yang Hongyang wrote:
> This patch add a net filter between network backend and NIC devices.
> All packets will pass by this filter.
> TODO:
> multiqueue support.
> plugin support.
>
> +--------------+ +-------------+
> +----------+ | filter | |frontend(NIC)|
> | real | | | | |
> | network <--+backend <-------+ |
> | backend | | peer +-------> peer |
> +----------+ +--------------+ +-------------+
>
> Usage:
> -netdev tap,id=bn0 # you can use whatever backend as needed
> -netdev filter,id=f0,backend=bn0,plugin=dump
> -device e1000,netdev=f0
I don't know enough about the net layer to know if this is a good
idea or not, but here goes...
I wonder if filters would be better done as a standalone object
as opposed to chaining together netdev backends. With the -netdev
approach you're constrained by the existing netdev design, which
might not be sufficiently flexible if we want to be able to easily
dynamically add/remove/change filters on the fly to existing
netdevs. Could we instead imagine
-netfilter id=f0,plugin=dump
-netdev tap,id=bn0,filter=f0
-device e1000,netdev=bn0
And perhaps some monitor commands to add/remove filters, as well
as changing which plugin(s) are enabld for filters on the fly.
You could possilby also allow the filter to be started/stopped
on the fly, so you aren't restricted to capturing a dump for the
entire lifetime of the QEMU process. eg montor commands
netfilter_start f0
netfilter_stop f0
With your -netdev based approach adding monitor commands for
filter specific actions becomes a little more painful, as
-netdev is a generic object type, but the commands would only
work for a specific impl of that object type.
>
> Signed-off-by: Yang Hongyang <yanghy@cn.fujitsu.com>
> ---
> 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
> --
> 1.9.1
>
>
Regards,
Daniel
--
|: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org -o- http://virt-manager.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [Qemu-devel] [PATCH] RFC/net: Add a net filter
2015-07-22 10:55 ` [Qemu-devel] [PATCH] RFC/net: Add a net filter Yang Hongyang
2015-07-22 11:06 ` Daniel P. Berrange
@ 2015-07-22 13:05 ` Thomas Huth
2015-07-22 15:06 ` Yang Hongyang
2015-07-22 13:26 ` Stefan Hajnoczi
2015-07-23 5:59 ` Jason Wang
3 siblings, 1 reply; 35+ messages in thread
From: Thomas Huth @ 2015-07-22 13:05 UTC (permalink / raw)
To: Yang Hongyang, qemu-devel; +Cc: jasowang, stefanha
On 22/07/15 12:55, Yang Hongyang wrote:
> This patch add a net filter between network backend and NIC devices.
> All packets will pass by this filter.
> TODO:
> multiqueue support.
> plugin support.
>
> +--------------+ +-------------+
> +----------+ | filter | |frontend(NIC)|
> | real | | | | |
> | network <--+backend <-------+ |
> | backend | | peer +-------> peer |
> +----------+ +--------------+ +-------------+
>
> Usage:
> -netdev tap,id=bn0 # you can use whatever backend as needed
> -netdev filter,id=f0,backend=bn0,plugin=dump
> -device e1000,netdev=f0
That's basically a neat idea... however, one question remains: Will
there be other filters beside the "dump" filter that you mentioned in
your example? Do you already have something in mind?
If not, I think this is likely not worth the effort - and we likely
should keep it simple and implement the dump option as suggested with my
patches instead.
> 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)
This looks like a bad copy-n-paste comment... ?
> + * 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.
> + */
...
Thomas
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [Qemu-devel] [PATCH] RFC/net: Add a net filter
2015-07-22 10:55 ` [Qemu-devel] [PATCH] RFC/net: Add a net filter Yang Hongyang
2015-07-22 11:06 ` Daniel P. Berrange
2015-07-22 13:05 ` Thomas Huth
@ 2015-07-22 13:26 ` Stefan Hajnoczi
2015-07-22 14:57 ` Yang Hongyang
2015-07-23 5:59 ` Jason Wang
3 siblings, 1 reply; 35+ messages in thread
From: Stefan Hajnoczi @ 2015-07-22 13:26 UTC (permalink / raw)
To: Yang Hongyang; +Cc: Thomas Huth, Jason Wang, qemu-devel, Stefan Hajnoczi
On Wed, Jul 22, 2015 at 11:55 AM, Yang Hongyang <yanghy@cn.fujitsu.com> wrote:
> This patch add a net filter between network backend and NIC devices.
> All packets will pass by this filter.
> TODO:
> multiqueue support.
> plugin support.
What do you mean by plugin?
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [Qemu-devel] [PATCH] RFC/net: Add a net filter
2015-07-22 13:26 ` Stefan Hajnoczi
@ 2015-07-22 14:57 ` Yang Hongyang
2015-07-23 11:57 ` Stefan Hajnoczi
0 siblings, 1 reply; 35+ messages in thread
From: Yang Hongyang @ 2015-07-22 14:57 UTC (permalink / raw)
To: Stefan Hajnoczi; +Cc: Thomas Huth, Jason Wang, qemu-devel, Stefan Hajnoczi
Hi Stefan,
On 07/22/2015 09:26 PM, Stefan Hajnoczi wrote:
> On Wed, Jul 22, 2015 at 11:55 AM, Yang Hongyang <yanghy@cn.fujitsu.com> wrote:
>> This patch add a net filter between network backend and NIC devices.
>> All packets will pass by this filter.
>> TODO:
>> multiqueue support.
>> plugin support.
>
> What do you mean by plugin?
>
A filter without plugin supplied will do nothing except pass by all packets, a
plugin like dump for example, will dump all packets into a file. Or other
plugins like a netbuffer plugin, will simply buffer the packets, release
the packets when needed. However, these are my thoughts about the usecase,
there might be more usecase about this.
--
Thanks,
Yang.
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [Qemu-devel] [PATCH] RFC/net: Add a net filter
2015-07-22 13:05 ` Thomas Huth
@ 2015-07-22 15:06 ` Yang Hongyang
0 siblings, 0 replies; 35+ messages in thread
From: Yang Hongyang @ 2015-07-22 15:06 UTC (permalink / raw)
To: Thomas Huth, qemu-devel; +Cc: jasowang, stefanha
On 07/22/2015 09:05 PM, Thomas Huth wrote:
> On 22/07/15 12:55, Yang Hongyang wrote:
>> This patch add a net filter between network backend and NIC devices.
>> All packets will pass by this filter.
>> TODO:
>> multiqueue support.
>> plugin support.
>>
>> +--------------+ +-------------+
>> +----------+ | filter | |frontend(NIC)|
>> | real | | | | |
>> | network <--+backend <-------+ |
>> | backend | | peer +-------> peer |
>> +----------+ +--------------+ +-------------+
>>
>> Usage:
>> -netdev tap,id=bn0 # you can use whatever backend as needed
>> -netdev filter,id=f0,backend=bn0,plugin=dump
>> -device e1000,netdev=f0
>
> That's basically a neat idea... however, one question remains: Will
> there be other filters beside the "dump" filter that you mentioned in
> your example? Do you already have something in mind?
Yes, one usecase I can think of is a netbuffer plugin, which simply
buffer the packets, and then release the packets on demand, this can
be used by vm ft solutions like microcheckpoiting, will simplify the
network configuration of MC, currently MC network replication needs
kernel support and some extra configuration.
Another use case could be COLO ft solution, it needs to capture packets
from both primary/secondary and compare them to decide whether we
should start a checkpoint.
>
> If not, I think this is likely not worth the effort - and we likely
> should keep it simple and implement the dump option as suggested with my
> patches instead.
>
>> 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)
>
> This looks like a bad copy-n-paste comment... ?
>
>> + * 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.
>> + */
> ...
>
> Thomas
>
>
>
>
--
Thanks,
Yang.
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [Qemu-devel] [PATCH] RFC/net: Add a net filter
2015-07-22 11:06 ` Daniel P. Berrange
@ 2015-07-22 15:16 ` Yang Hongyang
0 siblings, 0 replies; 35+ messages in thread
From: Yang Hongyang @ 2015-07-22 15:16 UTC (permalink / raw)
To: Daniel P. Berrange; +Cc: thuth, jasowang, qemu-devel, stefanha
On 07/22/2015 07:06 PM, Daniel P. Berrange wrote:
> On Wed, Jul 22, 2015 at 06:55:36PM +0800, Yang Hongyang wrote:
>> This patch add a net filter between network backend and NIC devices.
>> All packets will pass by this filter.
>> TODO:
>> multiqueue support.
>> plugin support.
>>
>> +--------------+ +-------------+
>> +----------+ | filter | |frontend(NIC)|
>> | real | | | | |
>> | network <--+backend <-------+ |
>> | backend | | peer +-------> peer |
>> +----------+ +--------------+ +-------------+
>>
>> Usage:
>> -netdev tap,id=bn0 # you can use whatever backend as needed
>> -netdev filter,id=f0,backend=bn0,plugin=dump
>> -device e1000,netdev=f0
>
> I don't know enough about the net layer to know if this is a good
> idea or not, but here goes...
>
> I wonder if filters would be better done as a standalone object
> as opposed to chaining together netdev backends. With the -netdev
> approach you're constrained by the existing netdev design, which
> might not be sufficiently flexible if we want to be able to easily
> dynamically add/remove/change filters on the fly to existing
> netdevs. Could we instead imagine
>
> -netfilter id=f0,plugin=dump
> -netdev tap,id=bn0,filter=f0
> -device e1000,netdev=bn0
>
> And perhaps some monitor commands to add/remove filters, as well
> as changing which plugin(s) are enabld for filters on the fly.
> You could possilby also allow the filter to be started/stopped
> on the fly, so you aren't restricted to capturing a dump for the
> entire lifetime of the QEMU process. eg montor commands
>
> netfilter_start f0
> netfilter_stop f0
>
> With your -netdev based approach adding monitor commands for
> filter specific actions becomes a little more painful, as
> -netdev is a generic object type, but the commands would only
> work for a specific impl of that object type.
Thank you Daniel, this might be a good idea and reduce the
complexity of the commands implementation.
>
>>
>> Signed-off-by: Yang Hongyang <yanghy@cn.fujitsu.com>
>> ---
>> 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
>> --
>> 1.9.1
>>
>>
>
> Regards,
> Daniel
>
--
Thanks,
Yang.
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [Qemu-devel] [PATCH] RFC/net: Add a net filter
2015-07-22 10:55 ` [Qemu-devel] [PATCH] RFC/net: Add a net filter Yang Hongyang
` (2 preceding siblings ...)
2015-07-22 13:26 ` Stefan Hajnoczi
@ 2015-07-23 5:59 ` Jason Wang
2015-07-27 5:27 ` Yang Hongyang
3 siblings, 1 reply; 35+ messages in thread
From: Jason Wang @ 2015-07-23 5:59 UTC (permalink / raw)
To: Yang Hongyang, qemu-devel; +Cc: thuth, stefanha
On 07/22/2015 06:55 PM, Yang Hongyang wrote:
> This patch add a net filter between network backend and NIC devices.
> All packets will pass by this filter.
> TODO:
> multiqueue support.
> plugin support.
>
> +--------------+ +-------------+
> +----------+ | filter | |frontend(NIC)|
> | real | | | | |
> | network <--+backend <-------+ |
> | backend | | peer +-------> peer |
> +----------+ +--------------+ +-------------+
>
> Usage:
> -netdev tap,id=bn0 # you can use whatever backend as needed
> -netdev filter,id=f0,backend=bn0,plugin=dump
> -device e1000,netdev=f0
>
> Signed-off-by: Yang Hongyang <yanghy@cn.fujitsu.com>
Hi:
Several questions:
- Looks like we can do more than filter, so may be something like
traffic control or other is more suitable?
- What's the advantages of introducing a new type of netdev? As far as I
can see, just replace the dump function in Tomas' series with a
configurable function pointer will do the trick? (Probably with some
monitor commands). And then you won't even need to deal with vnet hder
and offload stuffs?
- I'm not sure the value of doing this especially consider host (linux)
has much more functional and powerful traffic control system.
Thanks.
> ---
> 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
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [Qemu-devel] [PATCH] RFC/net: Add a net filter
2015-07-22 14:57 ` Yang Hongyang
@ 2015-07-23 11:57 ` Stefan Hajnoczi
0 siblings, 0 replies; 35+ messages in thread
From: Stefan Hajnoczi @ 2015-07-23 11:57 UTC (permalink / raw)
To: Yang Hongyang; +Cc: Thomas Huth, Stefan Hajnoczi, Jason Wang, qemu-devel
[-- Attachment #1: Type: text/plain, Size: 820 bytes --]
On Wed, Jul 22, 2015 at 10:57:16PM +0800, Yang Hongyang wrote:
> Hi Stefan,
>
> On 07/22/2015 09:26 PM, Stefan Hajnoczi wrote:
> >On Wed, Jul 22, 2015 at 11:55 AM, Yang Hongyang <yanghy@cn.fujitsu.com> wrote:
> >>This patch add a net filter between network backend and NIC devices.
> >>All packets will pass by this filter.
> >>TODO:
> >> multiqueue support.
> >> plugin support.
> >
> >What do you mean by plugin?
> >
>
> A filter without plugin supplied will do nothing except pass by all packets, a
> plugin like dump for example, will dump all packets into a file. Or other
> plugins like a netbuffer plugin, will simply buffer the packets, release
> the packets when needed. However, these are my thoughts about the usecase,
> there might be more usecase about this.
Thanks, I understand.
[-- Attachment #2: Type: application/pgp-signature, Size: 473 bytes --]
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [Qemu-devel] [PATCH] RFC/net: Add a net filter
2015-07-23 5:59 ` Jason Wang
@ 2015-07-27 5:27 ` Yang Hongyang
2015-07-27 6:02 ` Yang Hongyang
2015-07-27 6:39 ` Jason Wang
0 siblings, 2 replies; 35+ messages in thread
From: Yang Hongyang @ 2015-07-27 5:27 UTC (permalink / raw)
To: Jason Wang, qemu-devel; +Cc: thuth, stefanha
On 07/23/2015 01:59 PM, Jason Wang wrote:
>
>
> On 07/22/2015 06:55 PM, Yang Hongyang wrote:
>> This patch add a net filter between network backend and NIC devices.
>> All packets will pass by this filter.
>> TODO:
>> multiqueue support.
>> plugin support.
>>
>> +--------------+ +-------------+
>> +----------+ | filter | |frontend(NIC)|
>> | real | | | | |
>> | network <--+backend <-------+ |
>> | backend | | peer +-------> peer |
>> +----------+ +--------------+ +-------------+
>>
>> Usage:
>> -netdev tap,id=bn0 # you can use whatever backend as needed
>> -netdev filter,id=f0,backend=bn0,plugin=dump
>> -device e1000,netdev=f0
>>
>> Signed-off-by: Yang Hongyang <yanghy@cn.fujitsu.com>
>
> Hi:
>
> Several questions:
>
> - Looks like we can do more than filter, so may be something like
> traffic control or other is more suitable?
The filter is just a transparent proxy of a backend if no filter plugin
is inserted. It just by pass all packets. Capture all traffic is the purpose
of the filter. As long as we have an entry to capture all packets, we
can do more, this is what a filter plugin will do. There are some use cases
I can think of:
- dump, by using filter, we can dump either output/input packets.
- buffer, to buffer/release packets, this feature can be used when using
macrocheckpoing. Or other Remus like VM FT solutions. You can
also supply an interval to a buffer plugin, which will release
packets by interval.
May be other use cases based on this special backend.
> - What's the advantages of introducing a new type of netdev? As far as I
> can see, just replace the dump function in Tomas' series with a
> configurable function pointer will do the trick? (Probably with some
> monitor commands). And then you won't even need to deal with vnet hder
> and offload stuffs?
I think dump function focus on every netdev, it adds an dump_enabled to
NetClientState, and dump the packet when the netdev receive been called,
This filter function more focus on packets between backend/frontend,
it's kind of an injection to the network packets flow.
So the semantics are different I think.
> - I'm not sure the value of doing this especially consider host (linux)
> has much more functional and powerful traffic control system.
>
> Thanks.
>
>
>> ---
>> 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
>
> .
>
--
Thanks,
Yang.
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [Qemu-devel] [PATCH] RFC/net: Add a net filter
2015-07-27 5:27 ` Yang Hongyang
@ 2015-07-27 6:02 ` Yang Hongyang
2015-07-27 6:39 ` Jason Wang
1 sibling, 0 replies; 35+ messages in thread
From: Yang Hongyang @ 2015-07-27 6:02 UTC (permalink / raw)
To: Jason Wang, qemu-devel; +Cc: thuth, stefanha
On 07/27/2015 01:27 PM, Yang Hongyang wrote:
> On 07/23/2015 01:59 PM, Jason Wang wrote:
>>
>>
>> On 07/22/2015 06:55 PM, Yang Hongyang wrote:
>>> This patch add a net filter between network backend and NIC devices.
>>> All packets will pass by this filter.
>>> TODO:
>>> multiqueue support.
>>> plugin support.
>>>
>>> +--------------+ +-------------+
>>> +----------+ | filter | |frontend(NIC)|
>>> | real | | | | |
>>> | network <--+backend <-------+ |
>>> | backend | | peer +-------> peer |
>>> +----------+ +--------------+ +-------------+
>>>
>>> Usage:
>>> -netdev tap,id=bn0 # you can use whatever backend as needed
>>> -netdev filter,id=f0,backend=bn0,plugin=dump
>>> -device e1000,netdev=f0
>>>
>>> Signed-off-by: Yang Hongyang <yanghy@cn.fujitsu.com>
>>
>> Hi:
>>
>> Several questions:
>>
>> - Looks like we can do more than filter, so may be something like
>> traffic control or other is more suitable?
>
> The filter is just a transparent proxy of a backend if no filter plugin
> is inserted. It just by pass all packets. Capture all traffic is the purpose
> of the filter. As long as we have an entry to capture all packets, we
> can do more, this is what a filter plugin will do. There are some use cases
> I can think of:
> - dump, by using filter, we can dump either output/input packets.
> - buffer, to buffer/release packets, this feature can be used when using
> macrocheckpoing. Or other Remus like VM FT solutions. You can
> also supply an interval to a buffer plugin, which will release
> packets by interval.
> May be other use cases based on this special backend.
>
>> - What's the advantages of introducing a new type of netdev?
You can take the filter as a full featured network backend, And by implement
it as a new type of netdev, we can reuse the existing netdev design, reuse as
many existing code/design as we can.
>> As far as I
>> can see, just replace the dump function in Tomas' series with a
>> configurable function pointer will do the trick? (Probably with some
>> monitor commands). And then you won't even need to deal with vnet hder
>> and offload stuffs?
>
> I think dump function focus on every netdev, it adds an dump_enabled to
> NetClientState, and dump the packet when the netdev receive been called,
> This filter function more focus on packets between backend/frontend,
> it's kind of an injection to the network packets flow.
> So the semantics are different I think.
>
>> - I'm not sure the value of doing this especially consider host (linux)
>> has much more functional and powerful traffic control system.
>>
>> Thanks.
>>
>>
>>> ---
>>> 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
>>
>> .
>>
>
--
Thanks,
Yang.
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [Qemu-devel] [PATCH] RFC/net: Add a net filter
2015-07-27 5:27 ` Yang Hongyang
2015-07-27 6:02 ` Yang Hongyang
@ 2015-07-27 6:39 ` Jason Wang
2015-07-27 7:00 ` Yang Hongyang
1 sibling, 1 reply; 35+ messages in thread
From: Jason Wang @ 2015-07-27 6:39 UTC (permalink / raw)
To: Yang Hongyang, qemu-devel; +Cc: thuth, stefanha
On 07/27/2015 01:27 PM, Yang Hongyang wrote:
> On 07/23/2015 01:59 PM, Jason Wang wrote:
>>
>>
>> On 07/22/2015 06:55 PM, Yang Hongyang wrote:
>>> This patch add a net filter between network backend and NIC devices.
>>> All packets will pass by this filter.
>>> TODO:
>>> multiqueue support.
>>> plugin support.
>>>
>>> +--------------+ +-------------+
>>> +----------+ | filter | |frontend(NIC)|
>>> | real | | | | |
>>> | network <--+backend <-------+ |
>>> | backend | | peer +-------> peer |
>>> +----------+ +--------------+ +-------------+
>>>
>>> Usage:
>>> -netdev tap,id=bn0 # you can use whatever backend as needed
>>> -netdev filter,id=f0,backend=bn0,plugin=dump
>>> -device e1000,netdev=f0
>>>
>>> Signed-off-by: Yang Hongyang <yanghy@cn.fujitsu.com>
>>
>> Hi:
>>
>> Several questions:
>>
>> - Looks like we can do more than filter, so may be something like
>> traffic control or other is more suitable?
>
> The filter is just a transparent proxy of a backend if no filter plugin
> is inserted. It just by pass all packets. Capture all traffic is the
> purpose
> of the filter. As long as we have an entry to capture all packets, we
> can do more, this is what a filter plugin will do. There are some use
> cases
> I can think of:
> - dump, by using filter, we can dump either output/input packets.
> - buffer, to buffer/release packets, this feature can be used when using
> macrocheckpoing. Or other Remus like VM FT solutions. You can
> also supply an interval to a buffer plugin, which will release
> packets by interval.
This sounds like traffic shaping.
> May be other use cases based on this special backend.
>
>> - What's the advantages of introducing a new type of netdev? As far as I
>> can see, just replace the dump function in Tomas' series with a
>> configurable function pointer will do the trick? (Probably with some
>> monitor commands). And then you won't even need to deal with vnet hder
>> and offload stuffs?
>
> I think dump function focus on every netdev, it adds an dump_enabled to
> NetClientState, and dump the packet when the netdev receive been called,
> This filter function more focus on packets between backend/frontend,
> it's kind of an injection to the network packets flow.
> So the semantics are different I think.
Yes, their functions are different. But the packet paths are similar,
both require the packets go through themselves before reaching the
peers. So simply passing the packets to the filter function before
calling nc->info->receive{_raw}() in qemu_deliver_packet() will also work?
This seems saves a lot of unnecessary stuffs. E.g netdev, vnet header or
offload.
>
>> - I'm not sure the value of doing this especially consider host (linux)
>> has much more functional and powerful traffic control system.
>>
>> Thanks.
>>
>>
>>> ---
>>> 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
>>
>> .
>>
>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [Qemu-devel] [PATCH] RFC/net: Add a net filter
2015-07-27 6:39 ` Jason Wang
@ 2015-07-27 7:00 ` Yang Hongyang
2015-07-27 7:31 ` Jason Wang
0 siblings, 1 reply; 35+ messages in thread
From: Yang Hongyang @ 2015-07-27 7:00 UTC (permalink / raw)
To: Jason Wang, qemu-devel; +Cc: thuth, stefanha
On 07/27/2015 02:39 PM, Jason Wang wrote:
>
>
> On 07/27/2015 01:27 PM, Yang Hongyang wrote:
>> On 07/23/2015 01:59 PM, Jason Wang wrote:
>>>
>>>
>>> On 07/22/2015 06:55 PM, Yang Hongyang wrote:
>>>> This patch add a net filter between network backend and NIC devices.
>>>> All packets will pass by this filter.
>>>> TODO:
>>>> multiqueue support.
>>>> plugin support.
>>>>
>>>> +--------------+ +-------------+
>>>> +----------+ | filter | |frontend(NIC)|
>>>> | real | | | | |
>>>> | network <--+backend <-------+ |
>>>> | backend | | peer +-------> peer |
>>>> +----------+ +--------------+ +-------------+
>>>>
>>>> Usage:
>>>> -netdev tap,id=bn0 # you can use whatever backend as needed
>>>> -netdev filter,id=f0,backend=bn0,plugin=dump
>>>> -device e1000,netdev=f0
>>>>
>>>> Signed-off-by: Yang Hongyang <yanghy@cn.fujitsu.com>
>>>
>>> Hi:
>>>
>>> Several questions:
>>>
>>> - Looks like we can do more than filter, so may be something like
>>> traffic control or other is more suitable?
>>
>> The filter is just a transparent proxy of a backend if no filter plugin
>> is inserted. It just by pass all packets. Capture all traffic is the
>> purpose
>> of the filter. As long as we have an entry to capture all packets, we
>> can do more, this is what a filter plugin will do. There are some use
>> cases
>> I can think of:
>> - dump, by using filter, we can dump either output/input packets.
>> - buffer, to buffer/release packets, this feature can be used when using
>> macrocheckpoing. Or other Remus like VM FT solutions. You can
>> also supply an interval to a buffer plugin, which will release
>> packets by interval.
>
> This sounds like traffic shaping.
>
>> May be other use cases based on this special backend.
>>
>>> - What's the advantages of introducing a new type of netdev? As far as I
>>> can see, just replace the dump function in Tomas' series with a
>>> configurable function pointer will do the trick? (Probably with some
>>> monitor commands). And then you won't even need to deal with vnet hder
>>> and offload stuffs?
>>
>> I think dump function focus on every netdev, it adds an dump_enabled to
>> NetClientState, and dump the packet when the netdev receive been called,
>> This filter function more focus on packets between backend/frontend,
>> it's kind of an injection to the network packets flow.
>> So the semantics are different I think.
>
> Yes, their functions are different. But the packet paths are similar,
> both require the packets go through themselves before reaching the
> peers. So simply passing the packets to the filter function before
> calling nc->info->receive{_raw}() in qemu_deliver_packet() will also work?
I think this won't work for the buffer case? If we want the buffer case
to work under this, we should modify the generic netdev layer code, to
check the return value of the filter function call. And it is not as
extensible as we abstract the filter function to a netdev, We can
flexibly add/remove/change filter plugins on the fly.
>
> This seems saves a lot of unnecessary stuffs. E.g netdev, vnet header or
> offload.
>
>>
>>> - I'm not sure the value of doing this especially consider host (linux)
>>> has much more functional and powerful traffic control system.
>>>
>>> Thanks.
>>>
>>>
>>>> ---
>>>> 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
>>>
>>> .
>>>
>>
>
> .
>
--
Thanks,
Yang.
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [Qemu-devel] [PATCH] RFC/net: Add a net filter
2015-07-27 7:00 ` Yang Hongyang
@ 2015-07-27 7:31 ` Jason Wang
2015-07-27 7:45 ` Yang Hongyang
0 siblings, 1 reply; 35+ messages in thread
From: Jason Wang @ 2015-07-27 7:31 UTC (permalink / raw)
To: Yang Hongyang, qemu-devel; +Cc: thuth, stefanha
On 07/27/2015 03:00 PM, Yang Hongyang wrote:
>
>
> On 07/27/2015 02:39 PM, Jason Wang wrote:
>>
>>
>> On 07/27/2015 01:27 PM, Yang Hongyang wrote:
>>> On 07/23/2015 01:59 PM, Jason Wang wrote:
>>>>
>>>>
>>>> On 07/22/2015 06:55 PM, Yang Hongyang wrote:
>>>>> This patch add a net filter between network backend and NIC devices.
>>>>> All packets will pass by this filter.
>>>>> TODO:
>>>>> multiqueue support.
>>>>> plugin support.
>>>>>
>>>>> +--------------+ +-------------+
>>>>> +----------+ | filter | |frontend(NIC)|
>>>>> | real | | | | |
>>>>> | network <--+backend <-------+ |
>>>>> | backend | | peer +-------> peer |
>>>>> +----------+ +--------------+ +-------------+
>>>>>
>>>>> Usage:
>>>>> -netdev tap,id=bn0 # you can use whatever backend as needed
>>>>> -netdev filter,id=f0,backend=bn0,plugin=dump
>>>>> -device e1000,netdev=f0
>>>>>
>>>>> Signed-off-by: Yang Hongyang <yanghy@cn.fujitsu.com>
>>>>
>>>> Hi:
>>>>
>>>> Several questions:
>>>>
>>>> - Looks like we can do more than filter, so may be something like
>>>> traffic control or other is more suitable?
>>>
>>> The filter is just a transparent proxy of a backend if no filter plugin
>>> is inserted. It just by pass all packets. Capture all traffic is the
>>> purpose
>>> of the filter. As long as we have an entry to capture all packets, we
>>> can do more, this is what a filter plugin will do. There are some use
>>> cases
>>> I can think of:
>>> - dump, by using filter, we can dump either output/input packets.
>>> - buffer, to buffer/release packets, this feature can be used when
>>> using
>>> macrocheckpoing. Or other Remus like VM FT solutions. You
>>> can
>>> also supply an interval to a buffer plugin, which will
>>> release
>>> packets by interval.
>>
>> This sounds like traffic shaping.
>>
>>> May be other use cases based on this special backend.
>>>
>>>> - What's the advantages of introducing a new type of netdev? As far
>>>> as I
>>>> can see, just replace the dump function in Tomas' series with a
>>>> configurable function pointer will do the trick? (Probably with some
>>>> monitor commands). And then you won't even need to deal with vnet hder
>>>> and offload stuffs?
>>>
>>> I think dump function focus on every netdev, it adds an dump_enabled to
>>> NetClientState, and dump the packet when the netdev receive been
>>> called,
>>> This filter function more focus on packets between backend/frontend,
>>> it's kind of an injection to the network packets flow.
>>> So the semantics are different I think.
>>
>> Yes, their functions are different. But the packet paths are similar,
>> both require the packets go through themselves before reaching the
>> peers. So simply passing the packets to the filter function before
>> calling nc->info->receive{_raw}() in qemu_deliver_packet() will also
>> work?
>
> I think this won't work for the buffer case? If we want the buffer case
> to work under this, we should modify the generic netdev layer code, to
> check the return value of the filter function call.
But checking return value is rather simpler than a new netdev type,
isn't it?
> And it is not as
> extensible as we abstract the filter function to a netdev, We can
> flexibly add/remove/change filter plugins on the fly.
I don't see why we lose the flexibility like what I suggested. Actually,
implement it through a netdev will complex this. E.g:
-netdev tap,id=bn0 # you can use whatever backend as needed
-netdev filter,id=f0,backend=bn0,plugin=dump
-device e1000,netdev=f0
How did you remove filter id=f0? Looks like you need also remove e1000 nic?
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [Qemu-devel] [PATCH] RFC/net: Add a net filter
2015-07-27 7:31 ` Jason Wang
@ 2015-07-27 7:45 ` Yang Hongyang
2015-07-27 8:01 ` Jason Wang
0 siblings, 1 reply; 35+ messages in thread
From: Yang Hongyang @ 2015-07-27 7:45 UTC (permalink / raw)
To: Jason Wang, qemu-devel; +Cc: thuth, stefanha
On 07/27/2015 03:31 PM, Jason Wang wrote:
>
>
> On 07/27/2015 03:00 PM, Yang Hongyang wrote:
>>
>>
>> On 07/27/2015 02:39 PM, Jason Wang wrote:
>>>
>>>
>>> On 07/27/2015 01:27 PM, Yang Hongyang wrote:
>>>> On 07/23/2015 01:59 PM, Jason Wang wrote:
>>>>>
>>>>>
>>>>> On 07/22/2015 06:55 PM, Yang Hongyang wrote:
>>>>>> This patch add a net filter between network backend and NIC devices.
>>>>>> All packets will pass by this filter.
>>>>>> TODO:
>>>>>> multiqueue support.
>>>>>> plugin support.
>>>>>>
>>>>>> +--------------+ +-------------+
>>>>>> +----------+ | filter | |frontend(NIC)|
>>>>>> | real | | | | |
>>>>>> | network <--+backend <-------+ |
>>>>>> | backend | | peer +-------> peer |
>>>>>> +----------+ +--------------+ +-------------+
>>>>>>
>>>>>> Usage:
>>>>>> -netdev tap,id=bn0 # you can use whatever backend as needed
>>>>>> -netdev filter,id=f0,backend=bn0,plugin=dump
>>>>>> -device e1000,netdev=f0
>>>>>>
>>>>>> Signed-off-by: Yang Hongyang <yanghy@cn.fujitsu.com>
>>>>>
>>>>> Hi:
>>>>>
>>>>> Several questions:
>>>>>
>>>>> - Looks like we can do more than filter, so may be something like
>>>>> traffic control or other is more suitable?
>>>>
>>>> The filter is just a transparent proxy of a backend if no filter plugin
>>>> is inserted. It just by pass all packets. Capture all traffic is the
>>>> purpose
>>>> of the filter. As long as we have an entry to capture all packets, we
>>>> can do more, this is what a filter plugin will do. There are some use
>>>> cases
>>>> I can think of:
>>>> - dump, by using filter, we can dump either output/input packets.
>>>> - buffer, to buffer/release packets, this feature can be used when
>>>> using
>>>> macrocheckpoing. Or other Remus like VM FT solutions. You
>>>> can
>>>> also supply an interval to a buffer plugin, which will
>>>> release
>>>> packets by interval.
>>>
>>> This sounds like traffic shaping.
>>>
>>>> May be other use cases based on this special backend.
>>>>
>>>>> - What's the advantages of introducing a new type of netdev? As far
>>>>> as I
>>>>> can see, just replace the dump function in Tomas' series with a
>>>>> configurable function pointer will do the trick? (Probably with some
>>>>> monitor commands). And then you won't even need to deal with vnet hder
>>>>> and offload stuffs?
>>>>
>>>> I think dump function focus on every netdev, it adds an dump_enabled to
>>>> NetClientState, and dump the packet when the netdev receive been
>>>> called,
>>>> This filter function more focus on packets between backend/frontend,
>>>> it's kind of an injection to the network packets flow.
>>>> So the semantics are different I think.
>>>
>>> Yes, their functions are different. But the packet paths are similar,
>>> both require the packets go through themselves before reaching the
>>> peers. So simply passing the packets to the filter function before
>>> calling nc->info->receive{_raw}() in qemu_deliver_packet() will also
>>> work?
>>
>> I think this won't work for the buffer case? If we want the buffer case
>> to work under this, we should modify the generic netdev layer code, to
>> check the return value of the filter function call.
>
> But checking return value is rather simpler than a new netdev type,
> isn't it?
But how to implement a plugin which suppose to do the actual work on
the packets? how to configure params related to the plugin? different
plugins may need different params, implement as another netdev?
>
>> And it is not as
>> extensible as we abstract the filter function to a netdev, We can
>> flexibly add/remove/change filter plugins on the fly.
>
> I don't see why we lose the flexibility like what I suggested. Actually,
> implement it through a netdev will complex this. E.g:
>
> -netdev tap,id=bn0 # you can use whatever backend as needed
> -netdev filter,id=f0,backend=bn0,plugin=dump
> -device e1000,netdev=f0
>
> How did you remove filter id=f0? Looks like you need also remove e1000 nic?
No, when remove filter, we restore the connection between network backend and
NIC. Just like filter does not ever exists.
>
>
>
> .
>
--
Thanks,
Yang.
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [Qemu-devel] [PATCH] RFC/net: Add a net filter
2015-07-27 7:45 ` Yang Hongyang
@ 2015-07-27 8:01 ` Jason Wang
2015-07-27 8:39 ` Yang Hongyang
0 siblings, 1 reply; 35+ messages in thread
From: Jason Wang @ 2015-07-27 8:01 UTC (permalink / raw)
To: Yang Hongyang, qemu-devel; +Cc: thuth, stefanha
On 07/27/2015 03:45 PM, Yang Hongyang wrote:
> On 07/27/2015 03:31 PM, Jason Wang wrote:
>>
>>
>> On 07/27/2015 03:00 PM, Yang Hongyang wrote:
>>>
>>>
>>> On 07/27/2015 02:39 PM, Jason Wang wrote:
>>>>
>>>>
>>>> On 07/27/2015 01:27 PM, Yang Hongyang wrote:
>>>>> On 07/23/2015 01:59 PM, Jason Wang wrote:
>>>>>>
>>>>>>
>>>>>> On 07/22/2015 06:55 PM, Yang Hongyang wrote:
>>>>>>> This patch add a net filter between network backend and NIC
>>>>>>> devices.
>>>>>>> All packets will pass by this filter.
>>>>>>> TODO:
>>>>>>> multiqueue support.
>>>>>>> plugin support.
>>>>>>>
>>>>>>> +--------------+ +-------------+
>>>>>>> +----------+ | filter | |frontend(NIC)|
>>>>>>> | real | | | | |
>>>>>>> | network <--+backend <-------+ |
>>>>>>> | backend | | peer +-------> peer |
>>>>>>> +----------+ +--------------+ +-------------+
>>>>>>>
>>>>>>> Usage:
>>>>>>> -netdev tap,id=bn0 # you can use whatever backend as needed
>>>>>>> -netdev filter,id=f0,backend=bn0,plugin=dump
>>>>>>> -device e1000,netdev=f0
>>>>>>>
>>>>>>> Signed-off-by: Yang Hongyang <yanghy@cn.fujitsu.com>
>>>>>>
>>>>>> Hi:
>>>>>>
>>>>>> Several questions:
>>>>>>
>>>>>> - Looks like we can do more than filter, so may be something like
>>>>>> traffic control or other is more suitable?
>>>>>
>>>>> The filter is just a transparent proxy of a backend if no filter
>>>>> plugin
>>>>> is inserted. It just by pass all packets. Capture all traffic is the
>>>>> purpose
>>>>> of the filter. As long as we have an entry to capture all packets, we
>>>>> can do more, this is what a filter plugin will do. There are some use
>>>>> cases
>>>>> I can think of:
>>>>> - dump, by using filter, we can dump either output/input packets.
>>>>> - buffer, to buffer/release packets, this feature can be used when
>>>>> using
>>>>> macrocheckpoing. Or other Remus like VM FT solutions. You
>>>>> can
>>>>> also supply an interval to a buffer plugin, which will
>>>>> release
>>>>> packets by interval.
>>>>
>>>> This sounds like traffic shaping.
>>>>
>>>>> May be other use cases based on this special backend.
>>>>>
>>>>>> - What's the advantages of introducing a new type of netdev? As far
>>>>>> as I
>>>>>> can see, just replace the dump function in Tomas' series with a
>>>>>> configurable function pointer will do the trick? (Probably with some
>>>>>> monitor commands). And then you won't even need to deal with vnet
>>>>>> hder
>>>>>> and offload stuffs?
>>>>>
>>>>> I think dump function focus on every netdev, it adds an
>>>>> dump_enabled to
>>>>> NetClientState, and dump the packet when the netdev receive been
>>>>> called,
>>>>> This filter function more focus on packets between backend/frontend,
>>>>> it's kind of an injection to the network packets flow.
>>>>> So the semantics are different I think.
>>>>
>>>> Yes, their functions are different. But the packet paths are similar,
>>>> both require the packets go through themselves before reaching the
>>>> peers. So simply passing the packets to the filter function before
>>>> calling nc->info->receive{_raw}() in qemu_deliver_packet() will also
>>>> work?
>>>
>>> I think this won't work for the buffer case? If we want the buffer case
>>> to work under this, we should modify the generic netdev layer code, to
>>> check the return value of the filter function call.
>>
>> But checking return value is rather simpler than a new netdev type,
>> isn't it?
>
> But how to implement a plugin which suppose to do the actual work on
> the packets?
Well, the filter get the packets, so it can do everything it wants.
> how to configure params related to the plugin? different
> plugins may need different params, implement as another netdev?
I belive qmp can do this? something like -filter dump,id=f0,len=10000?
>
>>
>>> And it is not as
>>> extensible as we abstract the filter function to a netdev, We can
>>> flexibly add/remove/change filter plugins on the fly.
>>
>> I don't see why we lose the flexibility like what I suggested. Actually,
>> implement it through a netdev will complex this. E.g:
>>
>> -netdev tap,id=bn0 # you can use whatever backend as needed
>> -netdev filter,id=f0,backend=bn0,plugin=dump
>> -device e1000,netdev=f0
>>
>> How did you remove filter id=f0? Looks like you need also remove
>> e1000 nic?
>
> No, when remove filter, we restore the connection between network
> backend and
> NIC. Just like filter does not ever exists.
But e1000's peer is f0. You mean you will modify the peer pointer during
filter removing? Sounds scary.
>
>>
>>
>>
>> .
>>
>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [Qemu-devel] [PATCH] RFC/net: Add a net filter
2015-07-27 8:01 ` Jason Wang
@ 2015-07-27 8:39 ` Yang Hongyang
2015-07-27 9:16 ` Jason Wang
0 siblings, 1 reply; 35+ messages in thread
From: Yang Hongyang @ 2015-07-27 8:39 UTC (permalink / raw)
To: Jason Wang, qemu-devel; +Cc: thuth, stefanha
On 07/27/2015 04:01 PM, Jason Wang wrote:
>
> On 07/27/2015 03:45 PM, Yang Hongyang wrote:
>> On 07/27/2015 03:31 PM, Jason Wang wrote:
>>>
>>>
>>> On 07/27/2015 03:00 PM, Yang Hongyang wrote:
>>>>
>>>>
>>>> On 07/27/2015 02:39 PM, Jason Wang wrote:
>>>>>
>>>>>
>>>>> On 07/27/2015 01:27 PM, Yang Hongyang wrote:
>>>>>> On 07/23/2015 01:59 PM, Jason Wang wrote:
>>>>>>>
>>>>>>>
>>>>>>> On 07/22/2015 06:55 PM, Yang Hongyang wrote:
>>>>>>>> This patch add a net filter between network backend and NIC
>>>>>>>> devices.
>>>>>>>> All packets will pass by this filter.
>>>>>>>> TODO:
>>>>>>>> multiqueue support.
>>>>>>>> plugin support.
>>>>>>>>
>>>>>>>> +--------------+ +-------------+
>>>>>>>> +----------+ | filter | |frontend(NIC)|
>>>>>>>> | real | | | | |
>>>>>>>> | network <--+backend <-------+ |
>>>>>>>> | backend | | peer +-------> peer |
>>>>>>>> +----------+ +--------------+ +-------------+
>>>>>>>>
>>>>>>>> Usage:
>>>>>>>> -netdev tap,id=bn0 # you can use whatever backend as needed
>>>>>>>> -netdev filter,id=f0,backend=bn0,plugin=dump
>>>>>>>> -device e1000,netdev=f0
>>>>>>>>
>>>>>>>> Signed-off-by: Yang Hongyang <yanghy@cn.fujitsu.com>
>>>>>>>
>>>>>>> Hi:
>>>>>>>
>>>>>>> Several questions:
>>>>>>>
>>>>>>> - Looks like we can do more than filter, so may be something like
>>>>>>> traffic control or other is more suitable?
>>>>>>
>>>>>> The filter is just a transparent proxy of a backend if no filter
>>>>>> plugin
>>>>>> is inserted. It just by pass all packets. Capture all traffic is the
>>>>>> purpose
>>>>>> of the filter. As long as we have an entry to capture all packets, we
>>>>>> can do more, this is what a filter plugin will do. There are some use
>>>>>> cases
>>>>>> I can think of:
>>>>>> - dump, by using filter, we can dump either output/input packets.
>>>>>> - buffer, to buffer/release packets, this feature can be used when
>>>>>> using
>>>>>> macrocheckpoing. Or other Remus like VM FT solutions. You
>>>>>> can
>>>>>> also supply an interval to a buffer plugin, which will
>>>>>> release
>>>>>> packets by interval.
>>>>>
>>>>> This sounds like traffic shaping.
>>>>>
>>>>>> May be other use cases based on this special backend.
>>>>>>
>>>>>>> - What's the advantages of introducing a new type of netdev? As far
>>>>>>> as I
>>>>>>> can see, just replace the dump function in Tomas' series with a
>>>>>>> configurable function pointer will do the trick? (Probably with some
>>>>>>> monitor commands). And then you won't even need to deal with vnet
>>>>>>> hder
>>>>>>> and offload stuffs?
>>>>>>
>>>>>> I think dump function focus on every netdev, it adds an
>>>>>> dump_enabled to
>>>>>> NetClientState, and dump the packet when the netdev receive been
>>>>>> called,
>>>>>> This filter function more focus on packets between backend/frontend,
>>>>>> it's kind of an injection to the network packets flow.
>>>>>> So the semantics are different I think.
>>>>>
>>>>> Yes, their functions are different. But the packet paths are similar,
>>>>> both require the packets go through themselves before reaching the
>>>>> peers. So simply passing the packets to the filter function before
>>>>> calling nc->info->receive{_raw}() in qemu_deliver_packet() will also
>>>>> work?
>>>>
>>>> I think this won't work for the buffer case? If we want the buffer case
>>>> to work under this, we should modify the generic netdev layer code, to
>>>> check the return value of the filter function call.
>>>
>>> But checking return value is rather simpler than a new netdev type,
>>> isn't it?
>>
>> But how to implement a plugin which suppose to do the actual work on
>> the packets?
>
> Well, the filter get the packets, so it can do everything it wants.
>
>> how to configure params related to the plugin? different
>> plugins may need different params, implement as another netdev?
>
> I belive qmp can do this? something like -filter dump,id=f0,len=10000?
So you mean implement another object filter? and the structure is like netdev?
That will duplicate some of the netdev layer code. Implement it as
a netdev can reuse the existing netdev design. And current dump is implemented
as a netdev right? even if we simply passing the packets to the filter function
before calling nc->info->receive{_raw}(), we might also need to implement as
a netdev as dump dose.
>
>>
>>>
>>>> And it is not as
>>>> extensible as we abstract the filter function to a netdev, We can
>>>> flexibly add/remove/change filter plugins on the fly.
>>>
>>> I don't see why we lose the flexibility like what I suggested. Actually,
>>> implement it through a netdev will complex this. E.g:
>>>
>>> -netdev tap,id=bn0 # you can use whatever backend as needed
>>> -netdev filter,id=f0,backend=bn0,plugin=dump
>>> -device e1000,netdev=f0
>>>
>>> How did you remove filter id=f0? Looks like you need also remove
>>> e1000 nic?
>>
>> No, when remove filter, we restore the connection between network
>> backend and
>> NIC. Just like filter does not ever exists.
>
> But e1000's peer is f0. You mean you will modify the peer pointer during
> filter removing?
Yes.
> Sounds scary.
>
>>
>>>
>>>
>>>
>>> .
>>>
>>
>
> .
>
--
Thanks,
Yang.
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [Qemu-devel] [PATCH] RFC/net: Add a net filter
2015-07-27 8:39 ` Yang Hongyang
@ 2015-07-27 9:16 ` Jason Wang
2015-07-27 10:03 ` Yang Hongyang
0 siblings, 1 reply; 35+ messages in thread
From: Jason Wang @ 2015-07-27 9:16 UTC (permalink / raw)
To: Yang Hongyang, qemu-devel; +Cc: thuth, stefanha
On 07/27/2015 04:39 PM, Yang Hongyang wrote:
> On 07/27/2015 04:01 PM, Jason Wang wrote:
>>
>> On 07/27/2015 03:45 PM, Yang Hongyang wrote:
>>> On 07/27/2015 03:31 PM, Jason Wang wrote:
>>>>
>>>>
>>>> On 07/27/2015 03:00 PM, Yang Hongyang wrote:
>>>>>
>>>>>
>>>>> On 07/27/2015 02:39 PM, Jason Wang wrote:
>>>>>>
>>>>>>
>>>>>> On 07/27/2015 01:27 PM, Yang Hongyang wrote:
>>>>>>> On 07/23/2015 01:59 PM, Jason Wang wrote:
>>>>>>>>
>>>>>>>>
>>>>>>>> On 07/22/2015 06:55 PM, Yang Hongyang wrote:
>>>>>>>>> This patch add a net filter between network backend and NIC
>>>>>>>>> devices.
>>>>>>>>> All packets will pass by this filter.
>>>>>>>>> TODO:
>>>>>>>>> multiqueue support.
>>>>>>>>> plugin support.
>>>>>>>>>
>>>>>>>>> +--------------+ +-------------+
>>>>>>>>> +----------+ | filter | |frontend(NIC)|
>>>>>>>>> | real | | | | |
>>>>>>>>> | network <--+backend <-------+ |
>>>>>>>>> | backend | | peer +-------> peer |
>>>>>>>>> +----------+ +--------------+ +-------------+
>>>>>>>>>
>>>>>>>>> Usage:
>>>>>>>>> -netdev tap,id=bn0 # you can use whatever backend as needed
>>>>>>>>> -netdev filter,id=f0,backend=bn0,plugin=dump
>>>>>>>>> -device e1000,netdev=f0
>>>>>>>>>
>>>>>>>>> Signed-off-by: Yang Hongyang <yanghy@cn.fujitsu.com>
>>>>>>>>
>>>>>>>> Hi:
>>>>>>>>
>>>>>>>> Several questions:
>>>>>>>>
>>>>>>>> - Looks like we can do more than filter, so may be something like
>>>>>>>> traffic control or other is more suitable?
>>>>>>>
>>>>>>> The filter is just a transparent proxy of a backend if no filter
>>>>>>> plugin
>>>>>>> is inserted. It just by pass all packets. Capture all traffic is
>>>>>>> the
>>>>>>> purpose
>>>>>>> of the filter. As long as we have an entry to capture all
>>>>>>> packets, we
>>>>>>> can do more, this is what a filter plugin will do. There are
>>>>>>> some use
>>>>>>> cases
>>>>>>> I can think of:
>>>>>>> - dump, by using filter, we can dump either output/input packets.
>>>>>>> - buffer, to buffer/release packets, this feature can be used when
>>>>>>> using
>>>>>>> macrocheckpoing. Or other Remus like VM FT
>>>>>>> solutions. You
>>>>>>> can
>>>>>>> also supply an interval to a buffer plugin, which will
>>>>>>> release
>>>>>>> packets by interval.
>>>>>>
>>>>>> This sounds like traffic shaping.
>>>>>>
>>>>>>> May be other use cases based on this special backend.
>>>>>>>
>>>>>>>> - What's the advantages of introducing a new type of netdev? As
>>>>>>>> far
>>>>>>>> as I
>>>>>>>> can see, just replace the dump function in Tomas' series with a
>>>>>>>> configurable function pointer will do the trick? (Probably with
>>>>>>>> some
>>>>>>>> monitor commands). And then you won't even need to deal with vnet
>>>>>>>> hder
>>>>>>>> and offload stuffs?
>>>>>>>
>>>>>>> I think dump function focus on every netdev, it adds an
>>>>>>> dump_enabled to
>>>>>>> NetClientState, and dump the packet when the netdev receive been
>>>>>>> called,
>>>>>>> This filter function more focus on packets between
>>>>>>> backend/frontend,
>>>>>>> it's kind of an injection to the network packets flow.
>>>>>>> So the semantics are different I think.
>>>>>>
>>>>>> Yes, their functions are different. But the packet paths are
>>>>>> similar,
>>>>>> both require the packets go through themselves before reaching the
>>>>>> peers. So simply passing the packets to the filter function before
>>>>>> calling nc->info->receive{_raw}() in qemu_deliver_packet() will also
>>>>>> work?
>>>>>
>>>>> I think this won't work for the buffer case? If we want the buffer
>>>>> case
>>>>> to work under this, we should modify the generic netdev layer
>>>>> code, to
>>>>> check the return value of the filter function call.
>>>>
>>>> But checking return value is rather simpler than a new netdev type,
>>>> isn't it?
>>>
>>> But how to implement a plugin which suppose to do the actual work on
>>> the packets?
>>
>> Well, the filter get the packets, so it can do everything it wants.
>>
>>> how to configure params related to the plugin? different
>>> plugins may need different params, implement as another netdev?
>>
>> I belive qmp can do this? something like -filter dump,id=f0,len=10000?
>
> So you mean implement another object filter?
Yes.
> and the structure is like netdev?
No, it is embedded in netdev.
> That will duplicate some of the netdev layer code.
Not at all, it only cares about how to deal with the packet.
> Implement it as
> a netdev can reuse the existing netdev design. And current dump is
> implemented
> as a netdev right?
Right but it only works for hub, and that's why Thomas wrote his series
to make it work for all other backends
> even if we simply passing the packets to the filter function before
> calling nc->info->receive{_raw}(), we might also need to implement as
> a netdev as dump dose.
Why? The reason why we still keep -netdev dump is for backward
compatibility. If we only care about using it for new netdevs, we can
get rid of all netdev stuffs from dump.
>
>>
>>>
>>>>
>>>>> And it is not as
>>>>> extensible as we abstract the filter function to a netdev, We can
>>>>> flexibly add/remove/change filter plugins on the fly.
>>>>
>>>> I don't see why we lose the flexibility like what I suggested.
>>>> Actually,
>>>> implement it through a netdev will complex this. E.g:
>>>>
>>>> -netdev tap,id=bn0 # you can use whatever backend as needed
>>>> -netdev filter,id=f0,backend=bn0,plugin=dump
>>>> -device e1000,netdev=f0
>>>>
>>>> How did you remove filter id=f0? Looks like you need also remove
>>>> e1000 nic?
>>>
>>> No, when remove filter, we restore the connection between network
>>> backend and
>>> NIC. Just like filter does not ever exists.
>>
>> But e1000's peer is f0. You mean you will modify the peer pointer during
>> filter removing?
>
> Yes.
>
>> Sounds scary.
>>
>>>
>>>>
>>>>
>>>>
>>>> .
>>>>
>>>
>>
>> .
>>
>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [Qemu-devel] [PATCH] RFC/net: Add a net filter
2015-07-27 9:16 ` Jason Wang
@ 2015-07-27 10:03 ` Yang Hongyang
2015-07-28 3:28 ` Jason Wang
0 siblings, 1 reply; 35+ messages in thread
From: Yang Hongyang @ 2015-07-27 10:03 UTC (permalink / raw)
To: Jason Wang, qemu-devel; +Cc: thuth, stefanha
On 07/27/2015 05:16 PM, Jason Wang wrote:
[...]
>>>>>> I think this won't work for the buffer case? If we want the buffer
>>>>>> case
>>>>>> to work under this, we should modify the generic netdev layer
>>>>>> code, to
>>>>>> check the return value of the filter function call.
>>>>>
>>>>> But checking return value is rather simpler than a new netdev type,
>>>>> isn't it?
>>>>
>>>> But how to implement a plugin which suppose to do the actual work on
>>>> the packets?
>>>
>>> Well, the filter get the packets, so it can do everything it wants.
>>>
>>>> how to configure params related to the plugin? different
>>>> plugins may need different params, implement as another netdev?
>>>
>>> I belive qmp can do this? something like -filter dump,id=f0,len=10000?
>>
>> So you mean implement another object filter?
>
> Yes.
>
>> and the structure is like netdev?
>
> No, it is embedded in netdev.
Ah, I see what you mean, thank you for the patience...
does the command line looks like:
-filter dump,id=f0,len=10000
-netdev tap,XXX,filter=dump
If I need both dump and packets buffering, how will the qmp be?
-filter dump,id=f0,len=10000
-filter buffer,XXX
-netdev tap,XXX,filter=dump:buffer:XXX ?
or
-netdev tap,id=bn0,XXX
-filter dump,id=f0,len=10000,netdev=bn0
-filter buffer,XXX,netdev=bn0 ?
And do you care if we add a filter list to NetClientInfo?
and modify the generic layer to deal with these filters?
E.g, init/cleanup filters, go through these filters, check
for return values, stop call peer's receiving.
This is our main concern at the beginning, we want to avoid
modify the netdev generic layer too much, and do all things
within the filter dev so that this could be a bolt-on
feature. But if you don't care about this, we could simply
implement it as you said.
>
>> That will duplicate some of the netdev layer code.
>
> Not at all, it only cares about how to deal with the packet.
>
>> Implement it as
>> a netdev can reuse the existing netdev design. And current dump is
>> implemented
>> as a netdev right?
>
> Right but it only works for hub, and that's why Thomas wrote his series
> to make it work for all other backends
>
>> even if we simply passing the packets to the filter function before
>> calling nc->info->receive{_raw}(), we might also need to implement as
>> a netdev as dump dose.
>
> Why? The reason why we still keep -netdev dump is for backward
> compatibility. If we only care about using it for new netdevs, we can
> get rid of all netdev stuffs from dump.
Thank you, I see the points.
>
>>
>>>
>>>>
>>>>>
>>>>>> And it is not as
>>>>>> extensible as we abstract the filter function to a netdev, We can
>>>>>> flexibly add/remove/change filter plugins on the fly.
>>>>>
>>>>> I don't see why we lose the flexibility like what I suggested.
>>>>> Actually,
>>>>> implement it through a netdev will complex this. E.g:
>>>>>
>>>>> -netdev tap,id=bn0 # you can use whatever backend as needed
>>>>> -netdev filter,id=f0,backend=bn0,plugin=dump
>>>>> -device e1000,netdev=f0
>>>>>
>>>>> How did you remove filter id=f0? Looks like you need also remove
>>>>> e1000 nic?
>>>>
>>>> No, when remove filter, we restore the connection between network
>>>> backend and
>>>> NIC. Just like filter does not ever exists.
>>>
>>> But e1000's peer is f0. You mean you will modify the peer pointer during
>>> filter removing?
>>
>> Yes.
>>
>>> Sounds scary.
>>>
>>>>
>>>>>
>>>>>
>>>>>
>>>>> .
>>>>>
>>>>
>>>
>>> .
>>>
>>
>
> .
>
--
Thanks,
Yang.
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [Qemu-devel] [PATCH] RFC/net: Add a net filter
2015-07-27 10:03 ` Yang Hongyang
@ 2015-07-28 3:28 ` Jason Wang
2015-07-28 4:00 ` Yang Hongyang
0 siblings, 1 reply; 35+ messages in thread
From: Jason Wang @ 2015-07-28 3:28 UTC (permalink / raw)
To: Yang Hongyang, qemu-devel; +Cc: thuth, stefanha
On 07/27/2015 06:03 PM, Yang Hongyang wrote:
> On 07/27/2015 05:16 PM, Jason Wang wrote:
> [...]
>>>>>>> I think this won't work for the buffer case? If we want the buffer
>>>>>>> case
>>>>>>> to work under this, we should modify the generic netdev layer
>>>>>>> code, to
>>>>>>> check the return value of the filter function call.
>>>>>>
>>>>>> But checking return value is rather simpler than a new netdev type,
>>>>>> isn't it?
>>>>>
>>>>> But how to implement a plugin which suppose to do the actual work on
>>>>> the packets?
>>>>
>>>> Well, the filter get the packets, so it can do everything it wants.
>>>>
>>>>> how to configure params related to the plugin? different
>>>>> plugins may need different params, implement as another netdev?
>>>>
>>>> I belive qmp can do this? something like -filter dump,id=f0,len=10000?
>>>
>>> So you mean implement another object filter?
>>
>> Yes.
>>
>>> and the structure is like netdev?
>>
>> No, it is embedded in netdev.
>
> Ah, I see what you mean, thank you for the patience...
> does the command line looks like:
> -filter dump,id=f0,len=10000
> -netdev tap,XXX,filter=dump
>
> If I need both dump and packets buffering, how will the qmp be?
> -filter dump,id=f0,len=10000
> -filter buffer,XXX
> -netdev tap,XXX,filter=dump:buffer:XXX ?
This is ok but we have several choices, e.g you may want to have a next
field like:
- filter buffer,id=f0
- filter dump,id=f1,len=1000,next=f0
- netdev tap,XXX,filter_root=f1
> or
> -netdev tap,id=bn0,XXX
> -filter dump,id=f0,len=10000,netdev=bn0
> -filter buffer,XXX,netdev=bn0 ?
>
> And do you care if we add a filter list to NetClientInfo?
I don't care, and in fact this also shows great advantages over the
proposal of new netdevs. In that case, if you want two filters, two
netdevs is needed and I can't image how to handle offloads or link
status in this case.
> and modify the generic layer to deal with these filters?
> E.g, init/cleanup filters, go through these filters, check
> for return values, stop call peer's receiving.
I think it's ok to do these. What we really need is an new layer before
peer's receiving not new kinds of netdevs.
> This is our main concern at the beginning, we want to avoid
> modify the netdev generic layer too much, and do all things
> within the filter dev so that this could be a bolt-on
> feature. But if you don't care about this, we could simply
> implement it as you said.
I don't think much will be modified. Maybe just add callbacks on
receive, initialization and cleanup. Most of the codes should be limited
to filter itself. The point is 'filter' is not a kind of device or
backend, so most of the fields will be unnecessary. Treating it as
pseudo netdev will bring burdens too. E.g: dealing with vnet headers,
offloads, be/le setting and link status and probably even more.
>
>>
>>> That will duplicate some of the netdev layer code.
>>
>> Not at all, it only cares about how to deal with the packet.
>>
>>> Implement it as
>>> a netdev can reuse the existing netdev design. And current dump is
>>> implemented
>>> as a netdev right?
>>
>> Right but it only works for hub, and that's why Thomas wrote his series
>> to make it work for all other backends
>>
>>> even if we simply passing the packets to the filter function before
>>> calling nc->info->receive{_raw}(), we might also need to implement as
>>> a netdev as dump dose.
>>
>> Why? The reason why we still keep -netdev dump is for backward
>> compatibility. If we only care about using it for new netdevs, we can
>> get rid of all netdev stuffs from dump.
>
> Thank you, I see the points.
>
>>
>>>
>>>>
>>>>>
>>>>>>
>>>>>>> And it is not as
>>>>>>> extensible as we abstract the filter function to a netdev, We can
>>>>>>> flexibly add/remove/change filter plugins on the fly.
>>>>>>
>>>>>> I don't see why we lose the flexibility like what I suggested.
>>>>>> Actually,
>>>>>> implement it through a netdev will complex this. E.g:
>>>>>>
>>>>>> -netdev tap,id=bn0 # you can use whatever backend as needed
>>>>>> -netdev filter,id=f0,backend=bn0,plugin=dump
>>>>>> -device e1000,netdev=f0
>>>>>>
>>>>>> How did you remove filter id=f0? Looks like you need also remove
>>>>>> e1000 nic?
>>>>>
>>>>> No, when remove filter, we restore the connection between network
>>>>> backend and
>>>>> NIC. Just like filter does not ever exists.
>>>>
>>>> But e1000's peer is f0. You mean you will modify the peer pointer
>>>> during
>>>> filter removing?
>>>
>>> Yes.
>>>
>>>> Sounds scary.
>>>>
>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> .
>>>>>>
>>>>>
>>>>
>>>> .
>>>>
>>>
>>
>> .
>>
>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [Qemu-devel] [PATCH] RFC/net: Add a net filter
2015-07-28 3:28 ` Jason Wang
@ 2015-07-28 4:00 ` Yang Hongyang
2015-07-28 8:52 ` Yang Hongyang
2015-07-28 9:19 ` Yang Hongyang
0 siblings, 2 replies; 35+ messages in thread
From: Yang Hongyang @ 2015-07-28 4:00 UTC (permalink / raw)
To: Jason Wang, qemu-devel; +Cc: thuth, stefanha
On 07/28/2015 11:28 AM, Jason Wang wrote:
> On 07/27/2015 06:03 PM, Yang Hongyang wrote:
>> On 07/27/2015 05:16 PM, Jason Wang wrote:
>> [...]
>>>>>>>> I think this won't work for the buffer case? If we want the buffer
>>>>>>>> case
>>>>>>>> to work under this, we should modify the generic netdev layer
>>>>>>>> code, to
>>>>>>>> check the return value of the filter function call.
>>>>>>>
>>>>>>> But checking return value is rather simpler than a new netdev type,
>>>>>>> isn't it?
>>>>>>
>>>>>> But how to implement a plugin which suppose to do the actual work on
>>>>>> the packets?
>>>>>
>>>>> Well, the filter get the packets, so it can do everything it wants.
>>>>>
>>>>>> how to configure params related to the plugin? different
>>>>>> plugins may need different params, implement as another netdev?
>>>>>
>>>>> I belive qmp can do this? something like -filter dump,id=f0,len=10000?
>>>>
>>>> So you mean implement another object filter?
>>>
>>> Yes.
>>>
>>>> and the structure is like netdev?
>>>
>>> No, it is embedded in netdev.
>>
>> Ah, I see what you mean, thank you for the patience...
>> does the command line looks like:
>> -filter dump,id=f0,len=10000
>> -netdev tap,XXX,filter=dump
>>
>> If I need both dump and packets buffering, how will the qmp be?
>> -filter dump,id=f0,len=10000
>> -filter buffer,XXX
>> -netdev tap,XXX,filter=dump:buffer:XXX ?
>
> This is ok but we have several choices, e.g you may want to have a next
> field like:
>
> - filter buffer,id=f0
> - filter dump,id=f1,len=1000,next=f0
> - netdev tap,XXX,filter_root=f1
This seems better, thank you!
>
>> or
>> -netdev tap,id=bn0,XXX
>> -filter dump,id=f0,len=10000,netdev=bn0
>> -filter buffer,XXX,netdev=bn0 ?
>>
>> And do you care if we add a filter list to NetClientInfo?
>
> I don't care, and in fact this also shows great advantages over the
> proposal of new netdevs. In that case, if you want two filters, two
> netdevs is needed and I can't image how to handle offloads or link
> status in this case.
>
>> and modify the generic layer to deal with these filters?
>> E.g, init/cleanup filters, go through these filters, check
>> for return values, stop call peer's receiving.
>
> I think it's ok to do these. What we really need is an new layer before
> peer's receiving not new kinds of netdevs.
>
>> This is our main concern at the beginning, we want to avoid
>> modify the netdev generic layer too much, and do all things
>> within the filter dev so that this could be a bolt-on
>> feature. But if you don't care about this, we could simply
>> implement it as you said.
>
> I don't think much will be modified. Maybe just add callbacks on
> receive, initialization and cleanup. Most of the codes should be limited
> to filter itself. The point is 'filter' is not a kind of device or
> backend, so most of the fields will be unnecessary. Treating it as
> pseudo netdev will bring burdens too. E.g: dealing with vnet headers,
> offloads, be/le setting and link status and probably even more.
Thank you for the explanation. will do as you said.
>>
>>>
>>>> That will duplicate some of the netdev layer code.
>>>
>>> Not at all, it only cares about how to deal with the packet.
>>>
>>>> Implement it as
>>>> a netdev can reuse the existing netdev design. And current dump is
>>>> implemented
>>>> as a netdev right?
>>>
>>> Right but it only works for hub, and that's why Thomas wrote his series
>>> to make it work for all other backends
>>>
>>>> even if we simply passing the packets to the filter function before
>>>> calling nc->info->receive{_raw}(), we might also need to implement as
>>>> a netdev as dump dose.
>>>
>>> Why? The reason why we still keep -netdev dump is for backward
>>> compatibility. If we only care about using it for new netdevs, we can
>>> get rid of all netdev stuffs from dump.
>>
>> Thank you, I see the points.
>>
>>>
>>>>
>>>>>
>>>>>>
>>>>>>>
>>>>>>>> And it is not as
>>>>>>>> extensible as we abstract the filter function to a netdev, We can
>>>>>>>> flexibly add/remove/change filter plugins on the fly.
>>>>>>>
>>>>>>> I don't see why we lose the flexibility like what I suggested.
>>>>>>> Actually,
>>>>>>> implement it through a netdev will complex this. E.g:
>>>>>>>
>>>>>>> -netdev tap,id=bn0 # you can use whatever backend as needed
>>>>>>> -netdev filter,id=f0,backend=bn0,plugin=dump
>>>>>>> -device e1000,netdev=f0
>>>>>>>
>>>>>>> How did you remove filter id=f0? Looks like you need also remove
>>>>>>> e1000 nic?
>>>>>>
>>>>>> No, when remove filter, we restore the connection between network
>>>>>> backend and
>>>>>> NIC. Just like filter does not ever exists.
>>>>>
>>>>> But e1000's peer is f0. You mean you will modify the peer pointer
>>>>> during
>>>>> filter removing?
>>>>
>>>> Yes.
>>>>
>>>>> Sounds scary.
>>>>>
>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> .
>>>>>>>
>>>>>>
>>>>>
>>>>> .
>>>>>
>>>>
>>>
>>> .
>>>
>>
>
> .
>
--
Thanks,
Yang.
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [Qemu-devel] [PATCH] RFC/net: Add a net filter
2015-07-28 4:00 ` Yang Hongyang
@ 2015-07-28 8:52 ` Yang Hongyang
2015-07-28 9:19 ` Yang Hongyang
1 sibling, 0 replies; 35+ messages in thread
From: Yang Hongyang @ 2015-07-28 8:52 UTC (permalink / raw)
To: qemu-devel
On 07/28/2015 12:00 PM, Yang Hongyang wrote:
> On 07/28/2015 11:28 AM, Jason Wang wrote:
>> On 07/27/2015 06:03 PM, Yang Hongyang wrote:
>>> On 07/27/2015 05:16 PM, Jason Wang wrote:
>>> [...]
>>>>>>>>> I think this won't work for the buffer case? If we want the buffer
>>>>>>>>> case
>>>>>>>>> to work under this, we should modify the generic netdev layer
>>>>>>>>> code, to
>>>>>>>>> check the return value of the filter function call.
>>>>>>>>
>>>>>>>> But checking return value is rather simpler than a new netdev type,
>>>>>>>> isn't it?
>>>>>>>
>>>>>>> But how to implement a plugin which suppose to do the actual work on
>>>>>>> the packets?
>>>>>>
>>>>>> Well, the filter get the packets, so it can do everything it wants.
>>>>>>
>>>>>>> how to configure params related to the plugin? different
>>>>>>> plugins may need different params, implement as another netdev?
>>>>>>
>>>>>> I belive qmp can do this? something like -filter dump,id=f0,len=10000?
>>>>>
>>>>> So you mean implement another object filter?
>>>>
>>>> Yes.
>>>>
>>>>> and the structure is like netdev?
>>>>
>>>> No, it is embedded in netdev.
>>>
>>> Ah, I see what you mean, thank you for the patience...
>>> does the command line looks like:
>>> -filter dump,id=f0,len=10000
>>> -netdev tap,XXX,filter=dump
>>>
>>> If I need both dump and packets buffering, how will the qmp be?
>>> -filter dump,id=f0,len=10000
>>> -filter buffer,XXX
>>> -netdev tap,XXX,filter=dump:buffer:XXX ?
>>
>> This is ok but we have several choices, e.g you may want to have a next
>> field like:
>>
>> - filter buffer,id=f0
>> - filter dump,id=f1,len=1000,next=f0
>> - netdev tap,XXX,filter_root=f1
>
> This seems better, thank you!
Sorry, when try to implement it, I found this qmp is not that good when it
comes to dynamically add/remove filters, can I use below instead:
-netdev tap,id=bn0
-netfilter dump,id=f0,netdev=bn0
-netfilter buffer,id=f1,netdev=bn0
by this, I can introduce a QTAILQ of filters to NetClentState and
netdev_{add|del}_filter to dynamically add/remove filters.
>
>>
>>> or
>>> -netdev tap,id=bn0,XXX
>>> -filter dump,id=f0,len=10000,netdev=bn0
>>> -filter buffer,XXX,netdev=bn0 ?
>>>
>>> And do you care if we add a filter list to NetClientInfo?
>>
>> I don't care, and in fact this also shows great advantages over the
>> proposal of new netdevs. In that case, if you want two filters, two
>> netdevs is needed and I can't image how to handle offloads or link
>> status in this case.
>>
>>> and modify the generic layer to deal with these filters?
>>> E.g, init/cleanup filters, go through these filters, check
>>> for return values, stop call peer's receiving.
>>
>> I think it's ok to do these. What we really need is an new layer before
>> peer's receiving not new kinds of netdevs.
>>
>>> This is our main concern at the beginning, we want to avoid
>>> modify the netdev generic layer too much, and do all things
>>> within the filter dev so that this could be a bolt-on
>>> feature. But if you don't care about this, we could simply
>>> implement it as you said.
>>
>> I don't think much will be modified. Maybe just add callbacks on
>> receive, initialization and cleanup. Most of the codes should be limited
>> to filter itself. The point is 'filter' is not a kind of device or
>> backend, so most of the fields will be unnecessary. Treating it as
>> pseudo netdev will bring burdens too. E.g: dealing with vnet headers,
>> offloads, be/le setting and link status and probably even more.
>
> Thank you for the explanation. will do as you said.
>
>>>
>>>>
>>>>> That will duplicate some of the netdev layer code.
>>>>
>>>> Not at all, it only cares about how to deal with the packet.
>>>>
>>>>> Implement it as
>>>>> a netdev can reuse the existing netdev design. And current dump is
>>>>> implemented
>>>>> as a netdev right?
>>>>
>>>> Right but it only works for hub, and that's why Thomas wrote his series
>>>> to make it work for all other backends
>>>>
>>>>> even if we simply passing the packets to the filter function before
>>>>> calling nc->info->receive{_raw}(), we might also need to implement as
>>>>> a netdev as dump dose.
>>>>
>>>> Why? The reason why we still keep -netdev dump is for backward
>>>> compatibility. If we only care about using it for new netdevs, we can
>>>> get rid of all netdev stuffs from dump.
>>>
>>> Thank you, I see the points.
>>>
>>>>
>>>>>
>>>>>>
>>>>>>>
>>>>>>>>
>>>>>>>>> And it is not as
>>>>>>>>> extensible as we abstract the filter function to a netdev, We can
>>>>>>>>> flexibly add/remove/change filter plugins on the fly.
>>>>>>>>
>>>>>>>> I don't see why we lose the flexibility like what I suggested.
>>>>>>>> Actually,
>>>>>>>> implement it through a netdev will complex this. E.g:
>>>>>>>>
>>>>>>>> -netdev tap,id=bn0 # you can use whatever backend as needed
>>>>>>>> -netdev filter,id=f0,backend=bn0,plugin=dump
>>>>>>>> -device e1000,netdev=f0
>>>>>>>>
>>>>>>>> How did you remove filter id=f0? Looks like you need also remove
>>>>>>>> e1000 nic?
>>>>>>>
>>>>>>> No, when remove filter, we restore the connection between network
>>>>>>> backend and
>>>>>>> NIC. Just like filter does not ever exists.
>>>>>>
>>>>>> But e1000's peer is f0. You mean you will modify the peer pointer
>>>>>> during
>>>>>> filter removing?
>>>>>
>>>>> Yes.
>>>>>
>>>>>> Sounds scary.
>>>>>>
>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> .
>>>>>>>>
>>>>>>>
>>>>>>
>>>>>> .
>>>>>>
>>>>>
>>>>
>>>> .
>>>>
>>>
>>
>> .
>>
>
--
Thanks,
Yang.
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [Qemu-devel] [PATCH] RFC/net: Add a net filter
2015-07-28 4:00 ` Yang Hongyang
2015-07-28 8:52 ` Yang Hongyang
@ 2015-07-28 9:19 ` Yang Hongyang
2015-07-28 9:30 ` Jason Wang
1 sibling, 1 reply; 35+ messages in thread
From: Yang Hongyang @ 2015-07-28 9:19 UTC (permalink / raw)
To: Jason Wang, qemu-devel; +Cc: thuth, stefanha
On 07/28/2015 12:00 PM, Yang Hongyang wrote:
> On 07/28/2015 11:28 AM, Jason Wang wrote:
>> On 07/27/2015 06:03 PM, Yang Hongyang wrote:
>>> On 07/27/2015 05:16 PM, Jason Wang wrote:
>>> [...]
>>>>>>>>> I think this won't work for the buffer case? If we want the buffer
>>>>>>>>> case
>>>>>>>>> to work under this, we should modify the generic netdev layer
>>>>>>>>> code, to
>>>>>>>>> check the return value of the filter function call.
>>>>>>>>
>>>>>>>> But checking return value is rather simpler than a new netdev type,
>>>>>>>> isn't it?
>>>>>>>
>>>>>>> But how to implement a plugin which suppose to do the actual work on
>>>>>>> the packets?
>>>>>>
>>>>>> Well, the filter get the packets, so it can do everything it wants.
>>>>>>
>>>>>>> how to configure params related to the plugin? different
>>>>>>> plugins may need different params, implement as another netdev?
>>>>>>
>>>>>> I belive qmp can do this? something like -filter dump,id=f0,len=10000?
>>>>>
>>>>> So you mean implement another object filter?
>>>>
>>>> Yes.
>>>>
>>>>> and the structure is like netdev?
>>>>
>>>> No, it is embedded in netdev.
>>>
>>> Ah, I see what you mean, thank you for the patience...
>>> does the command line looks like:
>>> -filter dump,id=f0,len=10000
>>> -netdev tap,XXX,filter=dump
>>>
>>> If I need both dump and packets buffering, how will the qmp be?
>>> -filter dump,id=f0,len=10000
>>> -filter buffer,XXX
>>> -netdev tap,XXX,filter=dump:buffer:XXX ?
>>
>> This is ok but we have several choices, e.g you may want to have a next
>> field like:
>>
>> - filter buffer,id=f0
>> - filter dump,id=f1,len=1000,next=f0
>> - netdev tap,XXX,filter_root=f1
>
> This seems better, thank you!
Sorry, when try to implement it, I found this qmp is not that good when it
comes to dynamically add/remove filters, can I use below instead:
-netdev tap,id=bn0
-netfilter dump,id=f0,netdev=bn0
-netfilter buffer,id=f1,netdev=bn0
by this, I can introduce a QTAILQ of filters to NetClentState and
netdev_{add|del}_filter to dynamically add/remove filters.
>
>>
>>> or
>>> -netdev tap,id=bn0,XXX
>>> -filter dump,id=f0,len=10000,netdev=bn0
>>> -filter buffer,XXX,netdev=bn0 ?
>>>
>>> And do you care if we add a filter list to NetClientInfo?
>>
>> I don't care, and in fact this also shows great advantages over the
>> proposal of new netdevs. In that case, if you want two filters, two
>> netdevs is needed and I can't image how to handle offloads or link
>> status in this case.
>>
>>> and modify the generic layer to deal with these filters?
>>> E.g, init/cleanup filters, go through these filters, check
>>> for return values, stop call peer's receiving.
>>
>> I think it's ok to do these. What we really need is an new layer before
>> peer's receiving not new kinds of netdevs.
>>
>>> This is our main concern at the beginning, we want to avoid
>>> modify the netdev generic layer too much, and do all things
>>> within the filter dev so that this could be a bolt-on
>>> feature. But if you don't care about this, we could simply
>>> implement it as you said.
>>
>> I don't think much will be modified. Maybe just add callbacks on
>> receive, initialization and cleanup. Most of the codes should be limited
>> to filter itself. The point is 'filter' is not a kind of device or
>> backend, so most of the fields will be unnecessary. Treating it as
>> pseudo netdev will bring burdens too. E.g: dealing with vnet headers,
>> offloads, be/le setting and link status and probably even more.
>
> Thank you for the explanation. will do as you said.
>
>>>
>>>>
>>>>> That will duplicate some of the netdev layer code.
>>>>
>>>> Not at all, it only cares about how to deal with the packet.
>>>>
>>>>> Implement it as
>>>>> a netdev can reuse the existing netdev design. And current dump is
>>>>> implemented
>>>>> as a netdev right?
>>>>
>>>> Right but it only works for hub, and that's why Thomas wrote his series
>>>> to make it work for all other backends
>>>>
>>>>> even if we simply passing the packets to the filter function before
>>>>> calling nc->info->receive{_raw}(), we might also need to implement as
>>>>> a netdev as dump dose.
>>>>
>>>> Why? The reason why we still keep -netdev dump is for backward
>>>> compatibility. If we only care about using it for new netdevs, we can
>>>> get rid of all netdev stuffs from dump.
>>>
>>> Thank you, I see the points.
>>>
>>>>
>>>>>
>>>>>>
>>>>>>>
>>>>>>>>
>>>>>>>>> And it is not as
>>>>>>>>> extensible as we abstract the filter function to a netdev, We can
>>>>>>>>> flexibly add/remove/change filter plugins on the fly.
>>>>>>>>
>>>>>>>> I don't see why we lose the flexibility like what I suggested.
>>>>>>>> Actually,
>>>>>>>> implement it through a netdev will complex this. E.g:
>>>>>>>>
>>>>>>>> -netdev tap,id=bn0 # you can use whatever backend as needed
>>>>>>>> -netdev filter,id=f0,backend=bn0,plugin=dump
>>>>>>>> -device e1000,netdev=f0
>>>>>>>>
>>>>>>>> How did you remove filter id=f0? Looks like you need also remove
>>>>>>>> e1000 nic?
>>>>>>>
>>>>>>> No, when remove filter, we restore the connection between network
>>>>>>> backend and
>>>>>>> NIC. Just like filter does not ever exists.
>>>>>>
>>>>>> But e1000's peer is f0. You mean you will modify the peer pointer
>>>>>> during
>>>>>> filter removing?
>>>>>
>>>>> Yes.
>>>>>
>>>>>> Sounds scary.
>>>>>>
>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> .
>>>>>>>>
>>>>>>>
>>>>>>
>>>>>> .
>>>>>>
>>>>>
>>>>
>>>> .
>>>>
>>>
>>
>> .
>>
>
--
Thanks,
Yang.
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [Qemu-devel] [PATCH] RFC/net: Add a net filter
2015-07-28 9:19 ` Yang Hongyang
@ 2015-07-28 9:30 ` Jason Wang
2015-07-28 9:41 ` Yang Hongyang
0 siblings, 1 reply; 35+ messages in thread
From: Jason Wang @ 2015-07-28 9:30 UTC (permalink / raw)
To: Yang Hongyang, qemu-devel; +Cc: thuth, stefanha
On 07/28/2015 05:19 PM, Yang Hongyang wrote:
> On 07/28/2015 12:00 PM, Yang Hongyang wrote:
>> On 07/28/2015 11:28 AM, Jason Wang wrote:
>>> On 07/27/2015 06:03 PM, Yang Hongyang wrote:
>>>> On 07/27/2015 05:16 PM, Jason Wang wrote:
>>>> [...]
>>>>>>>>>> I think this won't work for the buffer case? If we want the
>>>>>>>>>> buffer
>>>>>>>>>> case
>>>>>>>>>> to work under this, we should modify the generic netdev layer
>>>>>>>>>> code, to
>>>>>>>>>> check the return value of the filter function call.
>>>>>>>>>
>>>>>>>>> But checking return value is rather simpler than a new netdev
>>>>>>>>> type,
>>>>>>>>> isn't it?
>>>>>>>>
>>>>>>>> But how to implement a plugin which suppose to do the actual
>>>>>>>> work on
>>>>>>>> the packets?
>>>>>>>
>>>>>>> Well, the filter get the packets, so it can do everything it wants.
>>>>>>>
>>>>>>>> how to configure params related to the plugin? different
>>>>>>>> plugins may need different params, implement as another netdev?
>>>>>>>
>>>>>>> I belive qmp can do this? something like -filter
>>>>>>> dump,id=f0,len=10000?
>>>>>>
>>>>>> So you mean implement another object filter?
>>>>>
>>>>> Yes.
>>>>>
>>>>>> and the structure is like netdev?
>>>>>
>>>>> No, it is embedded in netdev.
>>>>
>>>> Ah, I see what you mean, thank you for the patience...
>>>> does the command line looks like:
>>>> -filter dump,id=f0,len=10000
>>>> -netdev tap,XXX,filter=dump
>>>>
>>>> If I need both dump and packets buffering, how will the qmp be?
>>>> -filter dump,id=f0,len=10000
>>>> -filter buffer,XXX
>>>> -netdev tap,XXX,filter=dump:buffer:XXX ?
>>>
>>> This is ok but we have several choices, e.g you may want to have a next
>>> field like:
>>>
>>> - filter buffer,id=f0
>>> - filter dump,id=f1,len=1000,next=f0
>>> - netdev tap,XXX,filter_root=f1
>>
>> This seems better, thank you!
>
> Sorry, when try to implement it, I found this qmp is not that good
> when it
> comes to dynamically add/remove filters, can I use below instead:
> -netdev tap,id=bn0
> -netfilter dump,id=f0,netdev=bn0
> -netfilter buffer,id=f1,netdev=bn0
>
> by this, I can introduce a QTAILQ of filters to NetClentState and
> netdev_{add|del}_filter to dynamically add/remove filters.
This looks good.
Thanks
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [Qemu-devel] [PATCH] RFC/net: Add a net filter
2015-07-28 9:30 ` Jason Wang
@ 2015-07-28 9:41 ` Yang Hongyang
0 siblings, 0 replies; 35+ messages in thread
From: Yang Hongyang @ 2015-07-28 9:41 UTC (permalink / raw)
To: Jason Wang, qemu-devel; +Cc: thuth, stefanha
On 07/28/2015 05:30 PM, Jason Wang wrote:
> On 07/28/2015 05:19 PM, Yang Hongyang wrote:
>> On 07/28/2015 12:00 PM, Yang Hongyang wrote:
>>> On 07/28/2015 11:28 AM, Jason Wang wrote:
>>>> On 07/27/2015 06:03 PM, Yang Hongyang wrote:
>>>>> On 07/27/2015 05:16 PM, Jason Wang wrote:
>>>>> [...]
>>>>>>>>>>> I think this won't work for the buffer case? If we want the
>>>>>>>>>>> buffer
>>>>>>>>>>> case
>>>>>>>>>>> to work under this, we should modify the generic netdev layer
>>>>>>>>>>> code, to
>>>>>>>>>>> check the return value of the filter function call.
>>>>>>>>>>
>>>>>>>>>> But checking return value is rather simpler than a new netdev
>>>>>>>>>> type,
>>>>>>>>>> isn't it?
>>>>>>>>>
>>>>>>>>> But how to implement a plugin which suppose to do the actual
>>>>>>>>> work on
>>>>>>>>> the packets?
>>>>>>>>
>>>>>>>> Well, the filter get the packets, so it can do everything it wants.
>>>>>>>>
>>>>>>>>> how to configure params related to the plugin? different
>>>>>>>>> plugins may need different params, implement as another netdev?
>>>>>>>>
>>>>>>>> I belive qmp can do this? something like -filter
>>>>>>>> dump,id=f0,len=10000?
>>>>>>>
>>>>>>> So you mean implement another object filter?
>>>>>>
>>>>>> Yes.
>>>>>>
>>>>>>> and the structure is like netdev?
>>>>>>
>>>>>> No, it is embedded in netdev.
>>>>>
>>>>> Ah, I see what you mean, thank you for the patience...
>>>>> does the command line looks like:
>>>>> -filter dump,id=f0,len=10000
>>>>> -netdev tap,XXX,filter=dump
>>>>>
>>>>> If I need both dump and packets buffering, how will the qmp be?
>>>>> -filter dump,id=f0,len=10000
>>>>> -filter buffer,XXX
>>>>> -netdev tap,XXX,filter=dump:buffer:XXX ?
>>>>
>>>> This is ok but we have several choices, e.g you may want to have a next
>>>> field like:
>>>>
>>>> - filter buffer,id=f0
>>>> - filter dump,id=f1,len=1000,next=f0
>>>> - netdev tap,XXX,filter_root=f1
>>>
>>> This seems better, thank you!
>>
>> Sorry, when try to implement it, I found this qmp is not that good
>> when it
>> comes to dynamically add/remove filters, can I use below instead:
>> -netdev tap,id=bn0
>> -netfilter dump,id=f0,netdev=bn0
>> -netfilter buffer,id=f1,netdev=bn0
>>
>> by this, I can introduce a QTAILQ of filters to NetClentState and
>> netdev_{add|del}_filter to dynamically add/remove filters.
>
> This looks good.
Thank you.
>
> Thanks
> .
>
--
Thanks,
Yang.
^ permalink raw reply [flat|nested] 35+ messages in thread
* [Qemu-devel] [PATCH v2 1/5] net/dump: Add support for receive_iov function
2015-10-13 10:39 [Qemu-devel] [PATCH v2 0/5] Network traffic dumping via netfilter Thomas Huth
@ 2015-10-13 10:39 ` Thomas Huth
2015-10-14 2:13 ` Yang Hongyang
0 siblings, 1 reply; 35+ messages in thread
From: Thomas Huth @ 2015-10-13 10:39 UTC (permalink / raw)
To: qemu-devel, jasowang; +Cc: yanghy, armbru, stefanha, mst
Adding a proper receive_iov function to the net dump module.
This will make it easier to support the dump filter feature for
the -netdev option in later patches.
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
net/dump.c | 24 +++++++++++++++++++++---
1 file changed, 21 insertions(+), 3 deletions(-)
diff --git a/net/dump.c b/net/dump.c
index 08259af..aa0d45d 100644
--- a/net/dump.c
+++ b/net/dump.c
@@ -25,6 +25,7 @@
#include "clients.h"
#include "qemu-common.h"
#include "qemu/error-report.h"
+#include "qemu/iov.h"
#include "qemu/log.h"
#include "qemu/timer.h"
#include "hub.h"
@@ -57,12 +58,15 @@ struct pcap_sf_pkthdr {
uint32_t len;
};
-static ssize_t dump_receive(NetClientState *nc, const uint8_t *buf, size_t size)
+static ssize_t dump_receive_iov(NetClientState *nc, const struct iovec *iov,
+ int cnt)
{
DumpState *s = DO_UPCAST(DumpState, nc, nc);
struct pcap_sf_pkthdr hdr;
int64_t ts;
int caplen;
+ size_t size = iov_size(iov, cnt);
+ struct iovec dumpiov[cnt + 1];
/* Early return in case of previous error. */
if (s->fd < 0) {
@@ -76,8 +80,12 @@ static ssize_t dump_receive(NetClientState *nc, const uint8_t *buf, size_t size)
hdr.ts.tv_usec = ts % 1000000;
hdr.caplen = caplen;
hdr.len = size;
- if (write(s->fd, &hdr, sizeof(hdr)) != sizeof(hdr) ||
- write(s->fd, buf, caplen) != caplen) {
+
+ dumpiov[0].iov_base = &hdr;
+ dumpiov[0].iov_len = sizeof(hdr);
+ cnt = iov_copy(&dumpiov[1], cnt, iov, cnt, 0, caplen);
+
+ if (writev(s->fd, dumpiov, cnt + 1) != sizeof(hdr) + caplen) {
qemu_log("-net dump write error - stop dump\n");
close(s->fd);
s->fd = -1;
@@ -86,6 +94,15 @@ static ssize_t dump_receive(NetClientState *nc, const uint8_t *buf, size_t size)
return size;
}
+static ssize_t dump_receive(NetClientState *nc, const uint8_t *buf, size_t size)
+{
+ struct iovec iov = {
+ .iov_base = (void *)buf,
+ .iov_len = size
+ };
+ return dump_receive_iov(nc, &iov, 1);
+}
+
static void dump_cleanup(NetClientState *nc)
{
DumpState *s = DO_UPCAST(DumpState, nc, nc);
@@ -97,6 +114,7 @@ static NetClientInfo net_dump_info = {
.type = NET_CLIENT_OPTIONS_KIND_DUMP,
.size = sizeof(DumpState),
.receive = dump_receive,
+ .receive_iov = dump_receive_iov,
.cleanup = dump_cleanup,
};
--
1.8.3.1
^ permalink raw reply related [flat|nested] 35+ messages in thread
* Re: [Qemu-devel] [PATCH v2 1/5] net/dump: Add support for receive_iov function
2015-10-13 10:39 ` [Qemu-devel] [PATCH v2 1/5] net/dump: Add support for receive_iov function Thomas Huth
@ 2015-10-14 2:13 ` Yang Hongyang
0 siblings, 0 replies; 35+ messages in thread
From: Yang Hongyang @ 2015-10-14 2:13 UTC (permalink / raw)
To: Thomas Huth, qemu-devel, jasowang; +Cc: armbru, stefanha, mst
On 10/13/2015 06:39 PM, Thomas Huth wrote:
> Adding a proper receive_iov function to the net dump module.
> This will make it easier to support the dump filter feature for
> the -netdev option in later patches.
>
> Signed-off-by: Thomas Huth <thuth@redhat.com>
Reviewed-by: Yang Hongyang <yanghy@cn.fujitsu.com>
> ---
> net/dump.c | 24 +++++++++++++++++++++---
> 1 file changed, 21 insertions(+), 3 deletions(-)
>
> diff --git a/net/dump.c b/net/dump.c
> index 08259af..aa0d45d 100644
> --- a/net/dump.c
> +++ b/net/dump.c
> @@ -25,6 +25,7 @@
> #include "clients.h"
> #include "qemu-common.h"
> #include "qemu/error-report.h"
> +#include "qemu/iov.h"
> #include "qemu/log.h"
> #include "qemu/timer.h"
> #include "hub.h"
> @@ -57,12 +58,15 @@ struct pcap_sf_pkthdr {
> uint32_t len;
> };
>
> -static ssize_t dump_receive(NetClientState *nc, const uint8_t *buf, size_t size)
> +static ssize_t dump_receive_iov(NetClientState *nc, const struct iovec *iov,
> + int cnt)
> {
> DumpState *s = DO_UPCAST(DumpState, nc, nc);
> struct pcap_sf_pkthdr hdr;
> int64_t ts;
> int caplen;
> + size_t size = iov_size(iov, cnt);
> + struct iovec dumpiov[cnt + 1];
>
> /* Early return in case of previous error. */
> if (s->fd < 0) {
> @@ -76,8 +80,12 @@ static ssize_t dump_receive(NetClientState *nc, const uint8_t *buf, size_t size)
> hdr.ts.tv_usec = ts % 1000000;
> hdr.caplen = caplen;
> hdr.len = size;
> - if (write(s->fd, &hdr, sizeof(hdr)) != sizeof(hdr) ||
> - write(s->fd, buf, caplen) != caplen) {
> +
> + dumpiov[0].iov_base = &hdr;
> + dumpiov[0].iov_len = sizeof(hdr);
> + cnt = iov_copy(&dumpiov[1], cnt, iov, cnt, 0, caplen);
> +
> + if (writev(s->fd, dumpiov, cnt + 1) != sizeof(hdr) + caplen) {
> qemu_log("-net dump write error - stop dump\n");
> close(s->fd);
> s->fd = -1;
> @@ -86,6 +94,15 @@ static ssize_t dump_receive(NetClientState *nc, const uint8_t *buf, size_t size)
> return size;
> }
>
> +static ssize_t dump_receive(NetClientState *nc, const uint8_t *buf, size_t size)
> +{
> + struct iovec iov = {
> + .iov_base = (void *)buf,
> + .iov_len = size
> + };
> + return dump_receive_iov(nc, &iov, 1);
> +}
> +
> static void dump_cleanup(NetClientState *nc)
> {
> DumpState *s = DO_UPCAST(DumpState, nc, nc);
> @@ -97,6 +114,7 @@ static NetClientInfo net_dump_info = {
> .type = NET_CLIENT_OPTIONS_KIND_DUMP,
> .size = sizeof(DumpState),
> .receive = dump_receive,
> + .receive_iov = dump_receive_iov,
> .cleanup = dump_cleanup,
> };
>
>
--
Thanks,
Yang.
^ permalink raw reply [flat|nested] 35+ messages in thread
end of thread, other threads:[~2015-10-14 2:13 UTC | newest]
Thread overview: 35+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-07-13 7:39 [Qemu-devel] [PATCH v2 0/5] For QEMU 2.5: Network traffic dumping for -netdev devices Thomas Huth
2015-07-13 7:39 ` [Qemu-devel] [PATCH v2 1/5] net/dump: Add support for receive_iov function Thomas Huth
2015-07-13 7:39 ` [Qemu-devel] [PATCH v2 2/5] net/dump: Move DumpState into NetClientState Thomas Huth
2015-07-13 7:39 ` [Qemu-devel] [PATCH v2 3/5] net/dump: Rework net-dump init functions Thomas Huth
2015-07-13 7:39 ` [Qemu-devel] [PATCH v2 4/5] net/dump: Add dump option for netdev devices Thomas Huth
2015-07-13 7:39 ` [Qemu-devel] [PATCH v2 5/5] qemu options: Add information about dumpfile to help text Thomas Huth
2015-07-22 6:35 ` [Qemu-devel] [PATCH v2 0/5] For QEMU 2.5: Network traffic dumping for -netdev devices Jason Wang
2015-07-22 10:52 ` Yang Hongyang
2015-07-22 10:55 ` [Qemu-devel] [PATCH] RFC/net: Add a net filter Yang Hongyang
2015-07-22 11:06 ` Daniel P. Berrange
2015-07-22 15:16 ` Yang Hongyang
2015-07-22 13:05 ` Thomas Huth
2015-07-22 15:06 ` Yang Hongyang
2015-07-22 13:26 ` Stefan Hajnoczi
2015-07-22 14:57 ` Yang Hongyang
2015-07-23 11:57 ` Stefan Hajnoczi
2015-07-23 5:59 ` Jason Wang
2015-07-27 5:27 ` Yang Hongyang
2015-07-27 6:02 ` Yang Hongyang
2015-07-27 6:39 ` Jason Wang
2015-07-27 7:00 ` Yang Hongyang
2015-07-27 7:31 ` Jason Wang
2015-07-27 7:45 ` Yang Hongyang
2015-07-27 8:01 ` Jason Wang
2015-07-27 8:39 ` Yang Hongyang
2015-07-27 9:16 ` Jason Wang
2015-07-27 10:03 ` Yang Hongyang
2015-07-28 3:28 ` Jason Wang
2015-07-28 4:00 ` Yang Hongyang
2015-07-28 8:52 ` Yang Hongyang
2015-07-28 9:19 ` Yang Hongyang
2015-07-28 9:30 ` Jason Wang
2015-07-28 9:41 ` Yang Hongyang
-- strict thread matches above, loose matches on Subject: below --
2015-10-13 10:39 [Qemu-devel] [PATCH v2 0/5] Network traffic dumping via netfilter Thomas Huth
2015-10-13 10:39 ` [Qemu-devel] [PATCH v2 1/5] net/dump: Add support for receive_iov function Thomas Huth
2015-10-14 2:13 ` 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).