Allow filter-buffer on the same vhost backend as filter-redirector,
add an internal redirector-injected packet flag, and route indev packets
through the preceding filter-buffer before they are reinjected.
Signed-off-by: Cindy Lu <lulu@redhat.com>
---
include/net/queue.h | 5 +++
net/filter-mirror.c | 98 +++++++++++++++++++++++++++++++++++++++++----
net/filter.c | 5 ++-
3 files changed, 98 insertions(+), 10 deletions(-)
diff --git a/include/net/queue.h b/include/net/queue.h
index 2e686b1b61..213abe62ec 100644
--- a/include/net/queue.h
+++ b/include/net/queue.h
@@ -32,6 +32,11 @@ typedef void (NetPacketSent) (NetClientState *sender, ssize_t ret);
#define QEMU_NET_PACKET_FLAG_NONE 0
#define QEMU_NET_PACKET_FLAG_RAW (1<<0)
+/*
+ * Internal marker used by filter-redirector when packets are injected from
+ * indev through filter-buffer before being reinjected.
+ */
+#define QEMU_NET_PACKET_FLAG_REDIRECTOR_INJECT (1<<1)
/* Returns:
* >0 - success
diff --git a/net/filter-mirror.c b/net/filter-mirror.c
index 1ff58e1d27..dabf52275a 100644
--- a/net/filter-mirror.c
+++ b/net/filter-mirror.c
@@ -233,6 +233,73 @@ static ssize_t filter_redirector_send_netdev_iov(MirrorState *s,
return filter_redirector_send_netdev_packet(s, iov, iovcnt);
}
+static NetFilterState *filter_redirector_prev_in_direction(NetFilterState *nf,
+ NetFilterDirection dir)
+{
+ if (dir == NET_FILTER_DIRECTION_TX) {
+ return QTAILQ_PREV(nf, next);
+ }
+ return QTAILQ_NEXT(nf, next);
+}
+
+static NetFilterState *filter_redirector_find_buffer_before(NetFilterState *nf,
+ NetFilterDirection dir)
+{
+ NetFilterState *iter = filter_redirector_prev_in_direction(nf, dir);
+
+ while (iter) {
+ if ((iter->direction == dir ||
+ iter->direction == NET_FILTER_DIRECTION_ALL) &&
+ object_dynamic_cast(OBJECT(iter), "filter-buffer")) {
+ return iter;
+ }
+ iter = filter_redirector_prev_in_direction(iter, dir);
+ }
+
+ return NULL;
+}
+
+static bool filter_redirector_inject_to_buffer(NetFilterState *nf,
+ const uint8_t *buf,
+ int len)
+{
+ struct iovec iov = {
+ .iov_base = (void *)buf,
+ .iov_len = len,
+ };
+ NetFilterState *buffer;
+ bool injected = false;
+
+ if (nf->direction == NET_FILTER_DIRECTION_ALL ||
+ nf->direction == NET_FILTER_DIRECTION_TX) {
+ buffer = filter_redirector_find_buffer_before(nf,
+ NET_FILTER_DIRECTION_TX);
+ if (buffer) {
+ qemu_netfilter_receive(buffer, NET_FILTER_DIRECTION_TX,
+ nf->netdev,
+ QEMU_NET_PACKET_FLAG_REDIRECTOR_INJECT,
+ &iov, 1, NULL);
+ injected = true;
+ }
+ }
+
+ if ((nf->direction == NET_FILTER_DIRECTION_ALL ||
+ nf->direction == NET_FILTER_DIRECTION_RX) &&
+ nf->netdev->peer) {
+ buffer = filter_redirector_find_buffer_before(nf,
+ NET_FILTER_DIRECTION_RX);
+ if (buffer) {
+ qemu_netfilter_receive(buffer, NET_FILTER_DIRECTION_RX,
+ nf->netdev->peer,
+ QEMU_NET_PACKET_FLAG_REDIRECTOR_INJECT,
+ &iov, 1, NULL);
+ injected = true;
+ }
+ }
+
+ return injected;
+}
+
static void redirector_to_filter(NetFilterState *nf,
const uint8_t *buf,
int len)
@@ -310,7 +377,6 @@ static void filter_redirector_recv_from_chardev(NetFilterState *nf,
int len)
{
MirrorState *s = FILTER_REDIRECTOR(nf);
- bool inject_netdev = filter_redirector_use_inject_netdev(nf);
ssize_t ret;
struct iovec iov = {
.iov_base = (void *)buf,
@@ -325,7 +391,11 @@ static void filter_redirector_recv_from_chardev(NetFilterState *nf,
s->indev_packets++;
s->indev_bytes += len;
- if (inject_netdev) {
+ if (!s->outdev && filter_redirector_inject_to_buffer(nf, buf, len)) {
+ return;
+ }
+
+ if (s->out_netfd >= 0) {
ret = filter_redirector_send_netdev_iov(s, &iov, 1);
if (ret < 0) {
error_report("filter redirector send failed(%s)", strerror(-ret));
@@ -446,16 +516,22 @@ static ssize_t filter_redirector_receive_iov(NetFilterState *nf,
NetPacketSent *sent_cb)
{
MirrorState *s = FILTER_REDIRECTOR(nf);
- bool capture_netdev = filter_redirector_use_capture_netdev(nf);
- bool inject_netdev = filter_redirector_use_inject_netdev(nf);
int ret;
- if (s->indev || inject_netdev) {
- return 0;
+ if (s->out_netfd >= 0) {
+ if (!(flags & QEMU_NET_PACKET_FLAG_REDIRECTOR_INJECT)) {
+ return 0;
+ }
+
+ ret = filter_redirector_send_netdev_iov(s, iov, iovcnt);
+ if (ret < 0) {
+ error_report("filter redirector send failed(%s)", strerror(-ret));
+ }
+ return iov_size(iov, iovcnt);
}
- if (capture_netdev || s->outdev) {
- if (capture_netdev) {
+ if (s->outdev) {
+ if (s->in_netfd >= 0) {
return 0;
}
@@ -473,6 +549,12 @@ static ssize_t filter_redirector_receive_iov(NetFilterState *nf,
return 0;
}
+ if (s->indev) {
+ if (!(flags & QEMU_NET_PACKET_FLAG_REDIRECTOR_INJECT)) {
+ return 0;
+ }
+ }
+
return 0;
}
diff --git a/net/filter.c b/net/filter.c
index b9646b9e00..cc23e743cf 100644
--- a/net/filter.c
+++ b/net/filter.c
@@ -260,8 +260,9 @@ static void netfilter_complete(UserCreatable *uc, Error **errp)
bool buffer = object_dynamic_cast(OBJECT(uc), "filter-buffer");
bool vhost_filter = redirector || buffer;
- if (!redirector) {
- error_setg(errp, "Vhost is not supported");
+ if (!vhost_filter) {
+ error_setg(errp, "Vhost only supports filter-redirector and "
+ "filter-buffer");
return;
}
if (vhost_filter && ncs[0]->info->type != NET_CLIENT_DRIVER_TAP) {
--
2.52.0