net/colo-compare.c: Make colo-compare support vnet_hdr_len

We add the vnet_hdr_support option for colo-compare, default is disabled.
If you use virtio-net-pci or other driver needs vnet_hdr, please enable it.
You can use it for example:
-object colo-compare,id=comp0,primary_in=compare0-0,secondary_in=compare1,outdev=compare_out0,vnet_hdr_support

COLO-compare can get vnet header length from filter,
Add vnet_hdr_len to struct packet and output packet with
the vnet_hdr_len.

Signed-off-by: Zhang Chen <zhangchen.fnst@cn.fujitsu.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>
This commit is contained in:
Zhang Chen 2017-07-04 14:53:52 +08:00 committed by Jason Wang
parent 3037e7a5b7
commit aa3a7032f7
2 changed files with 55 additions and 9 deletions

View File

@ -73,6 +73,7 @@ typedef struct CompareState {
CharBackend chr_out; CharBackend chr_out;
SocketReadState pri_rs; SocketReadState pri_rs;
SocketReadState sec_rs; SocketReadState sec_rs;
bool vnet_hdr;
/* connection list: the connections belonged to this NIC could be found /* connection list: the connections belonged to this NIC could be found
* in this list. * in this list.
@ -99,7 +100,8 @@ enum {
static int compare_chr_send(CompareState *s, static int compare_chr_send(CompareState *s,
const uint8_t *buf, 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) static gint seq_sorter(Packet *a, Packet *b, gpointer data)
{ {
@ -483,7 +485,10 @@ static void colo_compare_connection(void *opaque, void *user_data)
} }
if (result) { if (result) {
ret = compare_chr_send(s, pkt->data, pkt->size); ret = compare_chr_send(s,
pkt->data,
pkt->size,
pkt->vnet_hdr_len);
if (ret < 0) { if (ret < 0) {
error_report("colo_send_primary_packet failed"); error_report("colo_send_primary_packet failed");
} }
@ -506,7 +511,8 @@ static void colo_compare_connection(void *opaque, void *user_data)
static int compare_chr_send(CompareState *s, static int compare_chr_send(CompareState *s,
const uint8_t *buf, const uint8_t *buf,
uint32_t size) uint32_t size,
uint32_t vnet_hdr_len)
{ {
int ret = 0; int ret = 0;
uint32_t len = htonl(size); uint32_t len = htonl(size);
@ -520,6 +526,18 @@ static int compare_chr_send(CompareState *s,
goto err; goto err;
} }
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); ret = qemu_chr_fe_write_all(&s->chr_out, (uint8_t *)buf, size);
if (ret != size) { if (ret != size) {
goto err; goto err;
@ -659,13 +677,32 @@ static void compare_set_outdev(Object *obj, const char *value, Error **errp)
s->outdev = g_strdup(value); 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) static void compare_pri_rs_finalize(SocketReadState *pri_rs)
{ {
CompareState *s = container_of(pri_rs, CompareState, pri_rs); CompareState *s = container_of(pri_rs, CompareState, pri_rs);
if (packet_enqueue(s, PRIMARY_IN)) { if (packet_enqueue(s, PRIMARY_IN)) {
trace_colo_compare_main("primary: unsupported packet in"); trace_colo_compare_main("primary: unsupported packet in");
compare_chr_send(s, pri_rs->buf, pri_rs->packet_len); compare_chr_send(s,
pri_rs->buf,
pri_rs->packet_len,
pri_rs->vnet_hdr_len);
} else { } else {
/* compare connection */ /* compare connection */
g_queue_foreach(&s->conn_list, colo_compare_connection, s); g_queue_foreach(&s->conn_list, colo_compare_connection, s);
@ -747,8 +784,8 @@ static void colo_compare_complete(UserCreatable *uc, Error **errp)
return; return;
} }
net_socket_rs_init(&s->pri_rs, compare_pri_rs_finalize, false); 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, false); net_socket_rs_init(&s->sec_rs, compare_sec_rs_finalize, s->vnet_hdr);
g_queue_init(&s->conn_list); g_queue_init(&s->conn_list);
@ -774,7 +811,10 @@ static void colo_flush_packets(void *opaque, void *user_data)
while (!g_queue_is_empty(&conn->primary_list)) { while (!g_queue_is_empty(&conn->primary_list)) {
pkt = g_queue_pop_head(&conn->primary_list); pkt = g_queue_pop_head(&conn->primary_list);
compare_chr_send(s, pkt->data, pkt->size); compare_chr_send(s,
pkt->data,
pkt->size,
pkt->vnet_hdr_len);
packet_destroy(pkt, NULL); packet_destroy(pkt, NULL);
} }
while (!g_queue_is_empty(&conn->secondary_list)) { while (!g_queue_is_empty(&conn->secondary_list)) {
@ -792,6 +832,8 @@ static void colo_compare_class_init(ObjectClass *oc, void *data)
static void colo_compare_init(Object *obj) static void colo_compare_init(Object *obj)
{ {
CompareState *s = COLO_COMPARE(obj);
object_property_add_str(obj, "primary_in", object_property_add_str(obj, "primary_in",
compare_get_pri_indev, compare_set_pri_indev, compare_get_pri_indev, compare_set_pri_indev,
NULL); NULL);
@ -801,6 +843,10 @@ static void colo_compare_init(Object *obj)
object_property_add_str(obj, "outdev", object_property_add_str(obj, "outdev",
compare_get_outdev, compare_set_outdev, compare_get_outdev, compare_set_outdev,
NULL); 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) static void colo_compare_finalize(Object *obj)

View File

@ -4282,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 The file format is libpcap, so it can be analyzed with tools such as tcpdump
or Wireshark. or Wireshark.
@item -object colo-compare,id=@var{id},primary_in=@var{chardevid},secondary_in=@var{chardevid}, @item -object colo-compare,id=@var{id},primary_in=@var{chardevid},secondary_in=@var{chardevid},outdev=@var{chardevid}[,vnet_hdr_support]
outdev=@var{chardevid}
Colo-compare gets packet from primary_in@var{chardevid} and secondary_in@var{chardevid}, than compare primary packet with 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 secondary packet. If the packets are same, we will output primary
packet to outdev@var{chardevid}, else we will notify colo-frame packet to outdev@var{chardevid}, else we will notify colo-frame
do checkpoint and send primary packet to outdev@var{chardevid}. 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. we must use it with the help of filter-mirror and filter-redirector.