aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2017-07-18 09:16:43 +0100
committerPeter Maydell <peter.maydell@linaro.org>2017-07-18 09:16:43 +0100
commita778cd5610b40eec037417565671d2717bc49def (patch)
treefe1a06a08038393d5418afad7653edd2f673fc80
parent5a477a78060638b8433e9fb96a3ada100b1ab8e9 (diff)
parent189ae6bb5ce1f5a322f8691d00fe942ba43dd601 (diff)
downloadqemu-a778cd5610b40eec037417565671d2717bc49def.zip
qemu-a778cd5610b40eec037417565671d2717bc49def.tar.gz
qemu-a778cd5610b40eec037417565671d2717bc49def.tar.bz2
Merge remote-tracking branch 'remotes/jasowang/tags/net-pull-request' into staging
# gpg: Signature made Mon 17 Jul 2017 13:17:17 BST # gpg: using RSA key 0xEF04965B398D6211 # gpg: Good signature from "Jason Wang (Jason Wang on RedHat) <jasowang@redhat.com>" # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 215D 46F4 8246 689E C77F 3562 EF04 965B 398D 6211 * remotes/jasowang/tags/net-pull-request: virtio-net: fix offload ctrl endian virtion-net: Prefer is_power_of_2() docs/colo-proxy.txt: Update colo-proxy usage of net driver with vnet_header net/filter-rewriter.c: Make filter-rewriter support vnet_hdr_len net/colo-compare.c: Add vnet packet's tcp/udp/icmp compare net/colo.c: Add vnet packet parse feature in colo-proxy net/colo-compare.c: Make colo-compare support vnet_hdr_len net/colo-compare.c: Introduce parameter for compare_chr_send() net/colo.c: Make vnet_hdr_len as packet property net/filter-mirror.c: Add new option to enable vnet support for filter-redirector net/filter-mirror.c: Make filter mirror support vnet support. net/filter-mirror.c: Introduce parameter for filter_send() net/net.c: Add vnet_hdr support in SocketReadState net: Add vnet_hdr_len arguments in NetClientState Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--docs/colo-proxy.txt26
-rw-r--r--hw/net/virtio-net.c4
-rw-r--r--include/net/net.h10
-rw-r--r--net/colo-compare.c84
-rw-r--r--net/colo.c9
-rw-r--r--net/colo.h4
-rw-r--r--net/filter-mirror.c75
-rw-r--r--net/filter-rewriter.c37
-rw-r--r--net/net.c37
-rw-r--r--net/socket.c8
-rw-r--r--qemu-options.hx19
11 files changed, 265 insertions, 48 deletions
diff --git a/docs/colo-proxy.txt b/docs/colo-proxy.txt
index c4941de..f6a624f 100644
--- a/docs/colo-proxy.txt
+++ b/docs/colo-proxy.txt
@@ -182,6 +182,32 @@ Secondary(ip:3.3.3.8):
-chardev socket,id=red1,host=3.3.3.3,port=9004
-object filter-redirector,id=f1,netdev=hn0,queue=tx,indev=red0
-object filter-redirector,id=f2,netdev=hn0,queue=rx,outdev=red1
+-object filter-rewriter,id=f3,netdev=hn0,queue=all
+
+If you want to use virtio-net-pci or other driver with vnet_header:
+
+Primary(ip:3.3.3.3):
+-netdev tap,id=hn0,vhost=off,script=/etc/qemu-ifup,downscript=/etc/qemu-ifdown
+-device e1000,id=e0,netdev=hn0,mac=52:a4:00:12:78:66
+-chardev socket,id=mirror0,host=3.3.3.3,port=9003,server,nowait
+-chardev socket,id=compare1,host=3.3.3.3,port=9004,server,nowait
+-chardev socket,id=compare0,host=3.3.3.3,port=9001,server,nowait
+-chardev socket,id=compare0-0,host=3.3.3.3,port=9001
+-chardev socket,id=compare_out,host=3.3.3.3,port=9005,server,nowait
+-chardev socket,id=compare_out0,host=3.3.3.3,port=9005
+-object filter-mirror,id=m0,netdev=hn0,queue=tx,outdev=mirror0,vnet_hdr_support
+-object filter-redirector,netdev=hn0,id=redire0,queue=rx,indev=compare_out,vnet_hdr_support
+-object filter-redirector,netdev=hn0,id=redire1,queue=rx,outdev=compare0,vnet_hdr_support
+-object colo-compare,id=comp0,primary_in=compare0-0,secondary_in=compare1,outdev=compare_out0,vnet_hdr_support
+
+Secondary(ip:3.3.3.8):
+-netdev tap,id=hn0,vhost=off,script=/etc/qemu-ifup,down script=/etc/qemu-ifdown
+-device e1000,netdev=hn0,mac=52:a4:00:12:78:66
+-chardev socket,id=red0,host=3.3.3.3,port=9003
+-chardev socket,id=red1,host=3.3.3.3,port=9004
+-object filter-redirector,id=f1,netdev=hn0,queue=tx,indev=red0,vnet_hdr_support
+-object filter-redirector,id=f2,netdev=hn0,queue=rx,outdev=red1,vnet_hdr_support
+-object filter-rewriter,id=f3,netdev=hn0,queue=all,vnet_hdr_support
Note:
a.COLO-proxy must work with COLO-frame and Block-replication.
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 5630a9e..148071a 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -758,6 +758,8 @@ static int virtio_net_handle_offloads(VirtIONet *n, uint8_t cmd,
if (cmd == VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET) {
uint64_t supported_offloads;
+ offloads = virtio_ldq_p(vdev, &offloads);
+
if (!n->has_vnet_hdr) {
return VIRTIO_NET_ERR;
}
@@ -1942,7 +1944,7 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp)
*/
if (n->net_conf.rx_queue_size < VIRTIO_NET_RX_QUEUE_MIN_SIZE ||
n->net_conf.rx_queue_size > VIRTQUEUE_MAX_SIZE ||
- (n->net_conf.rx_queue_size & (n->net_conf.rx_queue_size - 1))) {
+ !is_power_of_2(n->net_conf.rx_queue_size)) {
error_setg(errp, "Invalid rx_queue_size (= %" PRIu16 "), "
"must be a power of 2 between %d and %d.",
n->net_conf.rx_queue_size, VIRTIO_NET_RX_QUEUE_MIN_SIZE,
diff --git a/include/net/net.h b/include/net/net.h
index 99b28d5..1c55a93 100644
--- a/include/net/net.h
+++ b/include/net/net.h
@@ -100,6 +100,7 @@ struct NetClientState {
unsigned int queue_index;
unsigned rxfilter_notify_enabled:1;
int vring_enable;
+ int vnet_hdr_len;
QTAILQ_HEAD(NetFilterHead, NetFilterState) filters;
};
@@ -111,9 +112,13 @@ typedef struct NICState {
} NICState;
struct SocketReadState {
- int state; /* 0 = getting length, 1 = getting data */
+ /* 0 = getting length, 1 = getting vnet header length, 2 = getting data */
+ int state;
+ /* This flag decide whether to read the vnet_hdr_len field */
+ bool vnet_hdr;
uint32_t index;
uint32_t packet_len;
+ uint32_t vnet_hdr_len;
uint8_t buf[NET_BUFSIZE];
SocketReadStateFinalize *finalize;
};
@@ -176,7 +181,8 @@ ssize_t qemu_deliver_packet_iov(NetClientState *sender,
void print_net_client(Monitor *mon, NetClientState *nc);
void hmp_info_network(Monitor *mon, const QDict *qdict);
void net_socket_rs_init(SocketReadState *rs,
- SocketReadStateFinalize *finalize);
+ SocketReadStateFinalize *finalize,
+ bool vnet_hdr);
/* NIC info */
diff --git a/net/colo-compare.c b/net/colo-compare.c
index abfc23c..ca67c68 100644
--- a/net/colo-compare.c
+++ b/net/colo-compare.c
@@ -73,6 +73,7 @@ typedef struct CompareState {
CharBackend chr_out;
SocketReadState pri_rs;
SocketReadState sec_rs;
+ bool vnet_hdr;
/* connection list: the connections belonged to this NIC could be found
* in this list.
@@ -97,9 +98,10 @@ enum {
SECONDARY_IN,
};
-static int compare_chr_send(CharBackend *out,
+static int compare_chr_send(CompareState *s,
const uint8_t *buf,
- uint32_t size);
+ uint32_t size,
+ uint32_t vnet_hdr_len);
static gint seq_sorter(Packet *a, Packet *b, gpointer data)
{
@@ -121,9 +123,13 @@ static int packet_enqueue(CompareState *s, int mode)
Connection *conn;
if (mode == PRIMARY_IN) {
- pkt = packet_new(s->pri_rs.buf, s->pri_rs.packet_len);
+ pkt = packet_new(s->pri_rs.buf,
+ s->pri_rs.packet_len,
+ s->pri_rs.vnet_hdr_len);
} else {
- pkt = packet_new(s->sec_rs.buf, s->sec_rs.packet_len);
+ pkt = packet_new(s->sec_rs.buf,
+ s->sec_rs.packet_len,
+ s->sec_rs.vnet_hdr_len);
}
if (parse_packet_early(pkt)) {
@@ -195,8 +201,11 @@ static int colo_packet_compare_common(Packet *ppkt, Packet *spkt, int offset)
sec_ip_src, sec_ip_dst);
}
+ offset = ppkt->vnet_hdr_len + offset;
+
if (ppkt->size == spkt->size) {
- return memcmp(ppkt->data + offset, spkt->data + offset,
+ return memcmp(ppkt->data + offset,
+ spkt->data + offset,
spkt->size - offset);
} else {
trace_colo_compare_main("Net packet size are not the same");
@@ -255,8 +264,9 @@ static int colo_packet_compare_tcp(Packet *spkt, Packet *ppkt)
*/
if (ptcp->th_off > 5) {
ptrdiff_t tcp_offset;
+
tcp_offset = ppkt->transport_header - (uint8_t *)ppkt->data
- + (ptcp->th_off * 4);
+ + (ptcp->th_off * 4) - ppkt->vnet_hdr_len;
res = colo_packet_compare_common(ppkt, spkt, tcp_offset);
} else if (ptcp->th_sum == stcp->th_sum) {
res = colo_packet_compare_common(ppkt, spkt, ETH_HLEN);
@@ -479,7 +489,10 @@ static void colo_compare_connection(void *opaque, void *user_data)
}
if (result) {
- ret = compare_chr_send(&s->chr_out, pkt->data, pkt->size);
+ ret = compare_chr_send(s,
+ pkt->data,
+ pkt->size,
+ pkt->vnet_hdr_len);
if (ret < 0) {
error_report("colo_send_primary_packet failed");
}
@@ -500,9 +513,10 @@ static void colo_compare_connection(void *opaque, void *user_data)
}
}
-static int compare_chr_send(CharBackend *out,
+static int compare_chr_send(CompareState *s,
const uint8_t *buf,
- uint32_t size)
+ uint32_t size,
+ uint32_t vnet_hdr_len)
{
int ret = 0;
uint32_t len = htonl(size);
@@ -511,12 +525,24 @@ static int compare_chr_send(CharBackend *out,
return 0;
}
- ret = qemu_chr_fe_write_all(out, (uint8_t *)&len, sizeof(len));
+ ret = qemu_chr_fe_write_all(&s->chr_out, (uint8_t *)&len, sizeof(len));
if (ret != sizeof(len)) {
goto err;
}
- ret = qemu_chr_fe_write_all(out, (uint8_t *)buf, size);
+ if (s->vnet_hdr) {
+ /*
+ * We send vnet header len make other module(like filter-redirector)
+ * know how to parse net packet correctly.
+ */
+ len = htonl(vnet_hdr_len);
+ ret = qemu_chr_fe_write_all(&s->chr_out, (uint8_t *)&len, sizeof(len));
+ if (ret != sizeof(len)) {
+ goto err;
+ }
+ }
+
+ ret = qemu_chr_fe_write_all(&s->chr_out, (uint8_t *)buf, size);
if (ret != size) {
goto err;
}
@@ -655,13 +681,32 @@ static void compare_set_outdev(Object *obj, const char *value, Error **errp)
s->outdev = g_strdup(value);
}
+static bool compare_get_vnet_hdr(Object *obj, Error **errp)
+{
+ CompareState *s = COLO_COMPARE(obj);
+
+ return s->vnet_hdr;
+}
+
+static void compare_set_vnet_hdr(Object *obj,
+ bool value,
+ Error **errp)
+{
+ CompareState *s = COLO_COMPARE(obj);
+
+ s->vnet_hdr = value;
+}
+
static void compare_pri_rs_finalize(SocketReadState *pri_rs)
{
CompareState *s = container_of(pri_rs, CompareState, pri_rs);
if (packet_enqueue(s, PRIMARY_IN)) {
trace_colo_compare_main("primary: unsupported packet in");
- compare_chr_send(&s->chr_out, pri_rs->buf, pri_rs->packet_len);
+ compare_chr_send(s,
+ pri_rs->buf,
+ pri_rs->packet_len,
+ pri_rs->vnet_hdr_len);
} else {
/* compare connection */
g_queue_foreach(&s->conn_list, colo_compare_connection, s);
@@ -743,8 +788,8 @@ static void colo_compare_complete(UserCreatable *uc, Error **errp)
return;
}
- net_socket_rs_init(&s->pri_rs, compare_pri_rs_finalize);
- net_socket_rs_init(&s->sec_rs, compare_sec_rs_finalize);
+ net_socket_rs_init(&s->pri_rs, compare_pri_rs_finalize, s->vnet_hdr);
+ net_socket_rs_init(&s->sec_rs, compare_sec_rs_finalize, s->vnet_hdr);
g_queue_init(&s->conn_list);
@@ -770,7 +815,10 @@ static void colo_flush_packets(void *opaque, void *user_data)
while (!g_queue_is_empty(&conn->primary_list)) {
pkt = g_queue_pop_head(&conn->primary_list);
- compare_chr_send(&s->chr_out, pkt->data, pkt->size);
+ compare_chr_send(s,
+ pkt->data,
+ pkt->size,
+ pkt->vnet_hdr_len);
packet_destroy(pkt, NULL);
}
while (!g_queue_is_empty(&conn->secondary_list)) {
@@ -788,6 +836,8 @@ static void colo_compare_class_init(ObjectClass *oc, void *data)
static void colo_compare_init(Object *obj)
{
+ CompareState *s = COLO_COMPARE(obj);
+
object_property_add_str(obj, "primary_in",
compare_get_pri_indev, compare_set_pri_indev,
NULL);
@@ -797,6 +847,10 @@ static void colo_compare_init(Object *obj)
object_property_add_str(obj, "outdev",
compare_get_outdev, compare_set_outdev,
NULL);
+
+ s->vnet_hdr = false;
+ object_property_add_bool(obj, "vnet_hdr_support", compare_get_vnet_hdr,
+ compare_set_vnet_hdr, NULL);
}
static void colo_compare_finalize(Object *obj)
diff --git a/net/colo.c b/net/colo.c
index 8cc166b..28ce7c8 100644
--- a/net/colo.c
+++ b/net/colo.c
@@ -43,11 +43,11 @@ int parse_packet_early(Packet *pkt)
{
int network_length;
static const uint8_t vlan[] = {0x81, 0x00};
- uint8_t *data = pkt->data;
+ uint8_t *data = pkt->data + pkt->vnet_hdr_len;
uint16_t l3_proto;
ssize_t l2hdr_len = eth_get_l2_hdr_length(data);
- if (pkt->size < ETH_HLEN) {
+ if (pkt->size < ETH_HLEN + pkt->vnet_hdr_len) {
trace_colo_proxy_main("pkt->size < ETH_HLEN");
return 1;
}
@@ -73,7 +73,7 @@ int parse_packet_early(Packet *pkt)
}
network_length = pkt->ip->ip_hl * 4;
- if (pkt->size < l2hdr_len + network_length) {
+ if (pkt->size < l2hdr_len + network_length + pkt->vnet_hdr_len) {
trace_colo_proxy_main("pkt->size < network_header + network_length");
return 1;
}
@@ -153,13 +153,14 @@ void connection_destroy(void *opaque)
g_slice_free(Connection, conn);
}
-Packet *packet_new(const void *data, int size)
+Packet *packet_new(const void *data, int size, int vnet_hdr_len)
{
Packet *pkt = g_slice_new(Packet);
pkt->data = g_memdup(data, size);
pkt->size = size;
pkt->creation_ms = qemu_clock_get_ms(QEMU_CLOCK_HOST);
+ pkt->vnet_hdr_len = vnet_hdr_len;
return pkt;
}
diff --git a/net/colo.h b/net/colo.h
index 7c524f3..caedb0d 100644
--- a/net/colo.h
+++ b/net/colo.h
@@ -43,6 +43,8 @@ typedef struct Packet {
int size;
/* Time of packet creation, in wall clock ms */
int64_t creation_ms;
+ /* Get vnet_hdr_len from filter */
+ uint32_t vnet_hdr_len;
} Packet;
typedef struct ConnectionKey {
@@ -82,7 +84,7 @@ Connection *connection_get(GHashTable *connection_track_table,
ConnectionKey *key,
GQueue *conn_list);
void connection_hashtable_reset(GHashTable *connection_track_table);
-Packet *packet_new(const void *data, int size);
+Packet *packet_new(const void *data, int size, int vnet_hdr_len);
void packet_destroy(void *opaque, void *user_data);
#endif /* QEMU_COLO_PROXY_H */
diff --git a/net/filter-mirror.c b/net/filter-mirror.c
index 6043549..90e2c92 100644
--- a/net/filter-mirror.c
+++ b/net/filter-mirror.c
@@ -41,12 +41,14 @@ typedef struct MirrorState {
CharBackend chr_in;
CharBackend chr_out;
SocketReadState rs;
+ bool vnet_hdr;
} MirrorState;
-static int filter_send(CharBackend *chr_out,
+static int filter_send(MirrorState *s,
const struct iovec *iov,
int iovcnt)
{
+ NetFilterState *nf = NETFILTER(s);
int ret = 0;
ssize_t size = 0;
uint32_t len = 0;
@@ -58,14 +60,31 @@ static int filter_send(CharBackend *chr_out,
}
len = htonl(size);
- ret = qemu_chr_fe_write_all(chr_out, (uint8_t *)&len, sizeof(len));
+ ret = qemu_chr_fe_write_all(&s->chr_out, (uint8_t *)&len, sizeof(len));
if (ret != sizeof(len)) {
goto err;
}
+ if (s->vnet_hdr) {
+ /*
+ * If vnet_hdr = on, we send vnet header len to make other
+ * module(like colo-compare) know how to parse net
+ * packet correctly.
+ */
+ ssize_t vnet_hdr_len;
+
+ vnet_hdr_len = nf->netdev->vnet_hdr_len;
+
+ len = htonl(vnet_hdr_len);
+ ret = qemu_chr_fe_write_all(&s->chr_out, (uint8_t *)&len, sizeof(len));
+ if (ret != sizeof(len)) {
+ goto err;
+ }
+ }
+
buf = g_malloc(size);
iov_to_buf(iov, iovcnt, 0, buf, size);
- ret = qemu_chr_fe_write_all(chr_out, (uint8_t *)buf, size);
+ ret = qemu_chr_fe_write_all(&s->chr_out, (uint8_t *)buf, size);
g_free(buf);
if (ret != size) {
goto err;
@@ -141,7 +160,7 @@ static ssize_t filter_mirror_receive_iov(NetFilterState *nf,
MirrorState *s = FILTER_MIRROR(nf);
int ret;
- ret = filter_send(&s->chr_out, iov, iovcnt);
+ ret = filter_send(s, iov, iovcnt);
if (ret) {
error_report("filter mirror send failed(%s)", strerror(-ret));
}
@@ -164,7 +183,7 @@ static ssize_t filter_redirector_receive_iov(NetFilterState *nf,
int ret;
if (qemu_chr_fe_backend_connected(&s->chr_out)) {
- ret = filter_send(&s->chr_out, iov, iovcnt);
+ ret = filter_send(s, iov, iovcnt);
if (ret) {
error_report("filter redirector send failed(%s)", strerror(-ret));
}
@@ -229,7 +248,7 @@ static void filter_redirector_setup(NetFilterState *nf, Error **errp)
}
}
- net_socket_rs_init(&s->rs, redirector_rs_finalize);
+ net_socket_rs_init(&s->rs, redirector_rs_finalize, s->vnet_hdr);
if (s->indev) {
chr = qemu_chr_find(s->indev);
@@ -318,6 +337,20 @@ static void filter_mirror_set_outdev(Object *obj,
}
}
+static bool filter_mirror_get_vnet_hdr(Object *obj, Error **errp)
+{
+ MirrorState *s = FILTER_MIRROR(obj);
+
+ return s->vnet_hdr;
+}
+
+static void filter_mirror_set_vnet_hdr(Object *obj, bool value, Error **errp)
+{
+ MirrorState *s = FILTER_MIRROR(obj);
+
+ s->vnet_hdr = value;
+}
+
static char *filter_redirector_get_outdev(Object *obj, Error **errp)
{
MirrorState *s = FILTER_REDIRECTOR(obj);
@@ -335,18 +368,48 @@ static void filter_redirector_set_outdev(Object *obj,
s->outdev = g_strdup(value);
}
+static bool filter_redirector_get_vnet_hdr(Object *obj, Error **errp)
+{
+ MirrorState *s = FILTER_REDIRECTOR(obj);
+
+ return s->vnet_hdr;
+}
+
+static void filter_redirector_set_vnet_hdr(Object *obj,
+ bool value,
+ Error **errp)
+{
+ MirrorState *s = FILTER_REDIRECTOR(obj);
+
+ s->vnet_hdr = value;
+}
+
static void filter_mirror_init(Object *obj)
{
+ MirrorState *s = FILTER_MIRROR(obj);
+
object_property_add_str(obj, "outdev", filter_mirror_get_outdev,
filter_mirror_set_outdev, NULL);
+
+ s->vnet_hdr = false;
+ object_property_add_bool(obj, "vnet_hdr_support",
+ filter_mirror_get_vnet_hdr,
+ filter_mirror_set_vnet_hdr, NULL);
}
static void filter_redirector_init(Object *obj)
{
+ MirrorState *s = FILTER_REDIRECTOR(obj);
+
object_property_add_str(obj, "indev", filter_redirector_get_indev,
filter_redirector_set_indev, NULL);
object_property_add_str(obj, "outdev", filter_redirector_get_outdev,
filter_redirector_set_outdev, NULL);
+
+ s->vnet_hdr = false;
+ object_property_add_bool(obj, "vnet_hdr_support",
+ filter_redirector_get_vnet_hdr,
+ filter_redirector_set_vnet_hdr, NULL);
}
static void filter_mirror_fini(Object *obj)
diff --git a/net/filter-rewriter.c b/net/filter-rewriter.c
index afa06e8..55a6cf5 100644
--- a/net/filter-rewriter.c
+++ b/net/filter-rewriter.c
@@ -17,6 +17,7 @@
#include "qemu-common.h"
#include "qapi/error.h"
#include "qapi/qmp/qerror.h"
+#include "qemu/error-report.h"
#include "qapi-visit.h"
#include "qom/object.h"
#include "qemu/main-loop.h"
@@ -33,6 +34,7 @@ typedef struct RewriterState {
NetQueue *incoming_queue;
/* hashtable to save connection */
GHashTable *connection_track_table;
+ bool vnet_hdr;
} RewriterState;
static void filter_rewriter_flush(NetFilterState *nf)
@@ -155,10 +157,16 @@ static ssize_t colo_rewriter_receive_iov(NetFilterState *nf,
ConnectionKey key;
Packet *pkt;
ssize_t size = iov_size(iov, iovcnt);
+ ssize_t vnet_hdr_len = 0;
char *buf = g_malloc0(size);
iov_to_buf(iov, iovcnt, 0, buf, size);
- pkt = packet_new(buf, size);
+
+ if (s->vnet_hdr) {
+ vnet_hdr_len = nf->netdev->vnet_hdr_len;
+ }
+
+ pkt = packet_new(buf, size, vnet_hdr_len);
g_free(buf);
/*
@@ -237,6 +245,32 @@ static void colo_rewriter_setup(NetFilterState *nf, Error **errp)
s->incoming_queue = qemu_new_net_queue(qemu_netfilter_pass_to_next, nf);
}
+static bool filter_rewriter_get_vnet_hdr(Object *obj, Error **errp)
+{
+ RewriterState *s = FILTER_COLO_REWRITER(obj);
+
+ return s->vnet_hdr;
+}
+
+static void filter_rewriter_set_vnet_hdr(Object *obj,
+ bool value,
+ Error **errp)
+{
+ RewriterState *s = FILTER_COLO_REWRITER(obj);
+
+ s->vnet_hdr = value;
+}
+
+static void filter_rewriter_init(Object *obj)
+{
+ RewriterState *s = FILTER_COLO_REWRITER(obj);
+
+ s->vnet_hdr = false;
+ object_property_add_bool(obj, "vnet_hdr_support",
+ filter_rewriter_get_vnet_hdr,
+ filter_rewriter_set_vnet_hdr, NULL);
+}
+
static void colo_rewriter_class_init(ObjectClass *oc, void *data)
{
NetFilterClass *nfc = NETFILTER_CLASS(oc);
@@ -250,6 +284,7 @@ static const TypeInfo colo_rewriter_info = {
.name = TYPE_FILTER_REWRITER,
.parent = TYPE_NETFILTER,
.class_init = colo_rewriter_class_init,
+ .instance_init = filter_rewriter_init,
.instance_size = sizeof(RewriterState),
};
diff --git a/net/net.c b/net/net.c
index 6235aab..0e28099 100644
--- a/net/net.c
+++ b/net/net.c
@@ -492,6 +492,7 @@ void qemu_set_vnet_hdr_len(NetClientState *nc, int len)
return;
}
+ nc->vnet_hdr_len = len;
nc->info->set_vnet_hdr_len(nc, len);
}
@@ -1615,11 +1616,14 @@ QemuOptsList qemu_net_opts = {
};
void net_socket_rs_init(SocketReadState *rs,
- SocketReadStateFinalize *finalize)
+ SocketReadStateFinalize *finalize,
+ bool vnet_hdr)
{
rs->state = 0;
+ rs->vnet_hdr = vnet_hdr;
rs->index = 0;
rs->packet_len = 0;
+ rs->vnet_hdr_len = 0;
memset(rs->buf, 0, sizeof(rs->buf));
rs->finalize = finalize;
}
@@ -1634,8 +1638,12 @@ int net_fill_rstate(SocketReadState *rs, const uint8_t *buf, int size)
unsigned int l;
while (size > 0) {
- /* reassemble a packet from the network */
- switch (rs->state) { /* 0 = getting length, 1 = getting data */
+ /* Reassemble a packet from the network.
+ * 0 = getting length.
+ * 1 = getting vnet header length.
+ * 2 = getting data.
+ */
+ switch (rs->state) {
case 0:
l = 4 - rs->index;
if (l > size) {
@@ -1649,10 +1657,31 @@ int net_fill_rstate(SocketReadState *rs, const uint8_t *buf, int size)
/* got length */
rs->packet_len = ntohl(*(uint32_t *)rs->buf);
rs->index = 0;
- rs->state = 1;
+ if (rs->vnet_hdr) {
+ rs->state = 1;
+ } else {
+ rs->state = 2;
+ rs->vnet_hdr_len = 0;
+ }
}
break;
case 1:
+ l = 4 - rs->index;
+ if (l > size) {
+ l = size;
+ }
+ memcpy(rs->buf + rs->index, buf, l);
+ buf += l;
+ size -= l;
+ rs->index += l;
+ if (rs->index == 4) {
+ /* got vnet header length */
+ rs->vnet_hdr_len = ntohl(*(uint32_t *)rs->buf);
+ rs->index = 0;
+ rs->state = 2;
+ }
+ break;
+ case 2:
l = rs->packet_len - rs->index;
if (l > size) {
l = size;
diff --git a/net/socket.c b/net/socket.c
index dcae1ae..f85ef7d 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -174,7 +174,7 @@ static void net_socket_send(void *opaque)
closesocket(s->fd);
s->fd = -1;
- net_socket_rs_init(&s->rs, net_socket_rs_finalize);
+ net_socket_rs_init(&s->rs, net_socket_rs_finalize, false);
s->nc.link_down = true;
memset(s->nc.info_str, 0, sizeof(s->nc.info_str));
@@ -366,7 +366,7 @@ static NetSocketState *net_socket_fd_init_dgram(NetClientState *peer,
s->fd = fd;
s->listen_fd = -1;
s->send_fn = net_socket_send_dgram;
- net_socket_rs_init(&s->rs, net_socket_rs_finalize);
+ net_socket_rs_init(&s->rs, net_socket_rs_finalize, false);
net_socket_read_poll(s, true);
/* mcast: save bound address as dst */
@@ -417,7 +417,7 @@ static NetSocketState *net_socket_fd_init_stream(NetClientState *peer,
s->fd = fd;
s->listen_fd = -1;
- net_socket_rs_init(&s->rs, net_socket_rs_finalize);
+ net_socket_rs_init(&s->rs, net_socket_rs_finalize, false);
/* Disable Nagle algorithm on TCP sockets to reduce latency */
socket_set_nodelay(fd);
@@ -522,7 +522,7 @@ static int net_socket_listen_init(NetClientState *peer,
s->fd = -1;
s->listen_fd = fd;
s->nc.link_down = true;
- net_socket_rs_init(&s->rs, net_socket_rs_finalize);
+ net_socket_rs_init(&s->rs, net_socket_rs_finalize, false);
qemu_set_fd_handler(s->listen_fd, net_socket_accept, NULL, s);
return 0;
diff --git a/qemu-options.hx b/qemu-options.hx
index 9bd6bf0..746b5fa 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -4249,26 +4249,25 @@ queue @var{all|rx|tx} is an option that can be applied to any netfilter.
@option{tx}: the filter is attached to the transmit queue of the netdev,
where it will receive packets sent by the netdev.
-@item -object filter-mirror,id=@var{id},netdev=@var{netdevid},outdev=@var{chardevid}[,queue=@var{all|rx|tx}]
+@item -object filter-mirror,id=@var{id},netdev=@var{netdevid},outdev=@var{chardevid},queue=@var{all|rx|tx}[,vnet_hdr_support]
-filter-mirror on netdev @var{netdevid},mirror net packet to chardev
-@var{chardevid}
+filter-mirror on netdev @var{netdevid},mirror net packet to chardev@var{chardevid}, if it has the vnet_hdr_support flag, filter-mirror will mirror packet with vnet_hdr_len.
-@item -object filter-redirector,id=@var{id},netdev=@var{netdevid},indev=@var{chardevid},
-outdev=@var{chardevid}[,queue=@var{all|rx|tx}]
+@item -object filter-redirector,id=@var{id},netdev=@var{netdevid},indev=@var{chardevid},outdev=@var{chardevid},queue=@var{all|rx|tx}[,vnet_hdr_support]
filter-redirector on netdev @var{netdevid},redirect filter's net packet to chardev
-@var{chardevid},and redirect indev's packet to filter.
+@var{chardevid},and redirect indev's packet to filter.if it has the vnet_hdr_support flag,
+filter-redirector will redirect packet with vnet_hdr_len.
Create a filter-redirector we need to differ outdev id from indev id, id can not
be the same. we can just use indev or outdev, but at least one of indev or outdev
need to be specified.
-@item -object filter-rewriter,id=@var{id},netdev=@var{netdevid}[,queue=@var{all|rx|tx}]
+@item -object filter-rewriter,id=@var{id},netdev=@var{netdevid},queue=@var{all|rx|tx},[vnet_hdr_support]
Filter-rewriter is a part of COLO project.It will rewrite tcp packet to
secondary from primary to keep secondary tcp connection,and rewrite
tcp packet to primary from secondary make tcp packet can be handled by
-client.
+client.if it has the vnet_hdr_support flag, we can parse packet with vnet header.
usage:
colo secondary:
@@ -4283,13 +4282,13 @@ Dump the network traffic on netdev @var{dev} to the file specified by
The file format is libpcap, so it can be analyzed with tools such as tcpdump
or Wireshark.
-@item -object colo-compare,id=@var{id},primary_in=@var{chardevid},secondary_in=@var{chardevid},
-outdev=@var{chardevid}
+@item -object colo-compare,id=@var{id},primary_in=@var{chardevid},secondary_in=@var{chardevid},outdev=@var{chardevid}[,vnet_hdr_support]
Colo-compare gets packet from primary_in@var{chardevid} and secondary_in@var{chardevid}, than compare primary packet with
secondary packet. If the packets are same, we will output primary
packet to outdev@var{chardevid}, else we will notify colo-frame
do checkpoint and send primary packet to outdev@var{chardevid}.
+if it has the vnet_hdr_support flag, colo compare will send/recv packet with vnet_hdr_len.
we must use it with the help of filter-mirror and filter-redirector.