-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1 iQEcBAABAgAGBQJZbKrNAAoJEO8Ells5jWIRzWkH/0GgEkT5XqSPR8gTixxR5+aT 1+LvlqI861/oR3aZ/1+6nzbFF4RBHO0TJb9v8HovfaOMU/tjaVMOGOD98+rqToa7 2P2BTQo5jfsQhzGj2GBWnjpTqYunUjXdT0jjZAdERGqrNjoFOGhAjFXPvTKL23d5 haDgRQgTh2z4w+rvuHNQ79S8tCDtUGvH1i9fIpWNnVLlv4Lea8XJlm7p2+jNQslF W2ysoQ6PR/3HihtqMwsh4ZBJAQfhEpJcrcLeq5wWEdg40U2JVA1MjpX0q58X6fRJ YQ36K0vxmdnxdCK6NnoMLkGqI12aRqJnFEq0Avc3dC2U0OWIfNk4mp8X0Vr8o+s= =z3QF -----END PGP SIGNATURE----- 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>
This commit is contained in:
commit
a778cd5610
|
@ -182,6 +182,32 @@ Secondary(ip:3.3.3.8):
|
||||||
-chardev socket,id=red1,host=3.3.3.3,port=9004
|
-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=f1,netdev=hn0,queue=tx,indev=red0
|
||||||
-object filter-redirector,id=f2,netdev=hn0,queue=rx,outdev=red1
|
-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:
|
Note:
|
||||||
a.COLO-proxy must work with COLO-frame and Block-replication.
|
a.COLO-proxy must work with COLO-frame and Block-replication.
|
||||||
|
|
|
@ -758,6 +758,8 @@ static int virtio_net_handle_offloads(VirtIONet *n, uint8_t cmd,
|
||||||
if (cmd == VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET) {
|
if (cmd == VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET) {
|
||||||
uint64_t supported_offloads;
|
uint64_t supported_offloads;
|
||||||
|
|
||||||
|
offloads = virtio_ldq_p(vdev, &offloads);
|
||||||
|
|
||||||
if (!n->has_vnet_hdr) {
|
if (!n->has_vnet_hdr) {
|
||||||
return VIRTIO_NET_ERR;
|
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 ||
|
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 > 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 "), "
|
error_setg(errp, "Invalid rx_queue_size (= %" PRIu16 "), "
|
||||||
"must be a power of 2 between %d and %d.",
|
"must be a power of 2 between %d and %d.",
|
||||||
n->net_conf.rx_queue_size, VIRTIO_NET_RX_QUEUE_MIN_SIZE,
|
n->net_conf.rx_queue_size, VIRTIO_NET_RX_QUEUE_MIN_SIZE,
|
||||||
|
|
|
@ -100,6 +100,7 @@ struct NetClientState {
|
||||||
unsigned int queue_index;
|
unsigned int queue_index;
|
||||||
unsigned rxfilter_notify_enabled:1;
|
unsigned rxfilter_notify_enabled:1;
|
||||||
int vring_enable;
|
int vring_enable;
|
||||||
|
int vnet_hdr_len;
|
||||||
QTAILQ_HEAD(NetFilterHead, NetFilterState) filters;
|
QTAILQ_HEAD(NetFilterHead, NetFilterState) filters;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -111,9 +112,13 @@ typedef struct NICState {
|
||||||
} NICState;
|
} NICState;
|
||||||
|
|
||||||
struct SocketReadState {
|
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 index;
|
||||||
uint32_t packet_len;
|
uint32_t packet_len;
|
||||||
|
uint32_t vnet_hdr_len;
|
||||||
uint8_t buf[NET_BUFSIZE];
|
uint8_t buf[NET_BUFSIZE];
|
||||||
SocketReadStateFinalize *finalize;
|
SocketReadStateFinalize *finalize;
|
||||||
};
|
};
|
||||||
|
@ -176,7 +181,8 @@ ssize_t qemu_deliver_packet_iov(NetClientState *sender,
|
||||||
void print_net_client(Monitor *mon, NetClientState *nc);
|
void print_net_client(Monitor *mon, NetClientState *nc);
|
||||||
void hmp_info_network(Monitor *mon, const QDict *qdict);
|
void hmp_info_network(Monitor *mon, const QDict *qdict);
|
||||||
void net_socket_rs_init(SocketReadState *rs,
|
void net_socket_rs_init(SocketReadState *rs,
|
||||||
SocketReadStateFinalize *finalize);
|
SocketReadStateFinalize *finalize,
|
||||||
|
bool vnet_hdr);
|
||||||
|
|
||||||
/* NIC info */
|
/* NIC info */
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
@ -97,9 +98,10 @@ enum {
|
||||||
SECONDARY_IN,
|
SECONDARY_IN,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int compare_chr_send(CharBackend *out,
|
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)
|
||||||
{
|
{
|
||||||
|
@ -121,9 +123,13 @@ static int packet_enqueue(CompareState *s, int mode)
|
||||||
Connection *conn;
|
Connection *conn;
|
||||||
|
|
||||||
if (mode == PRIMARY_IN) {
|
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 {
|
} 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)) {
|
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);
|
sec_ip_src, sec_ip_dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
offset = ppkt->vnet_hdr_len + offset;
|
||||||
|
|
||||||
if (ppkt->size == spkt->size) {
|
if (ppkt->size == spkt->size) {
|
||||||
return memcmp(ppkt->data + offset, spkt->data + offset,
|
return memcmp(ppkt->data + offset,
|
||||||
|
spkt->data + offset,
|
||||||
spkt->size - offset);
|
spkt->size - offset);
|
||||||
} else {
|
} else {
|
||||||
trace_colo_compare_main("Net packet size are not the same");
|
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) {
|
if (ptcp->th_off > 5) {
|
||||||
ptrdiff_t tcp_offset;
|
ptrdiff_t tcp_offset;
|
||||||
|
|
||||||
tcp_offset = ppkt->transport_header - (uint8_t *)ppkt->data
|
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);
|
res = colo_packet_compare_common(ppkt, spkt, tcp_offset);
|
||||||
} else if (ptcp->th_sum == stcp->th_sum) {
|
} else if (ptcp->th_sum == stcp->th_sum) {
|
||||||
res = colo_packet_compare_common(ppkt, spkt, ETH_HLEN);
|
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) {
|
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) {
|
if (ret < 0) {
|
||||||
error_report("colo_send_primary_packet failed");
|
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,
|
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);
|
||||||
|
@ -511,12 +525,24 @@ static int compare_chr_send(CharBackend *out,
|
||||||
return 0;
|
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)) {
|
if (ret != sizeof(len)) {
|
||||||
goto err;
|
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) {
|
if (ret != size) {
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
@ -655,13 +681,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->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 {
|
} 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);
|
||||||
|
@ -743,8 +788,8 @@ static void colo_compare_complete(UserCreatable *uc, Error **errp)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
net_socket_rs_init(&s->pri_rs, compare_pri_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);
|
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);
|
||||||
|
|
||||||
|
@ -770,7 +815,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->chr_out, 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)) {
|
||||||
|
@ -788,6 +836,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);
|
||||||
|
@ -797,6 +847,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)
|
||||||
|
|
|
@ -43,11 +43,11 @@ int parse_packet_early(Packet *pkt)
|
||||||
{
|
{
|
||||||
int network_length;
|
int network_length;
|
||||||
static const uint8_t vlan[] = {0x81, 0x00};
|
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;
|
uint16_t l3_proto;
|
||||||
ssize_t l2hdr_len = eth_get_l2_hdr_length(data);
|
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");
|
trace_colo_proxy_main("pkt->size < ETH_HLEN");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,7 @@ int parse_packet_early(Packet *pkt)
|
||||||
}
|
}
|
||||||
|
|
||||||
network_length = pkt->ip->ip_hl * 4;
|
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");
|
trace_colo_proxy_main("pkt->size < network_header + network_length");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -153,13 +153,14 @@ void connection_destroy(void *opaque)
|
||||||
g_slice_free(Connection, conn);
|
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);
|
Packet *pkt = g_slice_new(Packet);
|
||||||
|
|
||||||
pkt->data = g_memdup(data, size);
|
pkt->data = g_memdup(data, size);
|
||||||
pkt->size = size;
|
pkt->size = size;
|
||||||
pkt->creation_ms = qemu_clock_get_ms(QEMU_CLOCK_HOST);
|
pkt->creation_ms = qemu_clock_get_ms(QEMU_CLOCK_HOST);
|
||||||
|
pkt->vnet_hdr_len = vnet_hdr_len;
|
||||||
|
|
||||||
return pkt;
|
return pkt;
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,8 @@ typedef struct Packet {
|
||||||
int size;
|
int size;
|
||||||
/* Time of packet creation, in wall clock ms */
|
/* Time of packet creation, in wall clock ms */
|
||||||
int64_t creation_ms;
|
int64_t creation_ms;
|
||||||
|
/* Get vnet_hdr_len from filter */
|
||||||
|
uint32_t vnet_hdr_len;
|
||||||
} Packet;
|
} Packet;
|
||||||
|
|
||||||
typedef struct ConnectionKey {
|
typedef struct ConnectionKey {
|
||||||
|
@ -82,7 +84,7 @@ Connection *connection_get(GHashTable *connection_track_table,
|
||||||
ConnectionKey *key,
|
ConnectionKey *key,
|
||||||
GQueue *conn_list);
|
GQueue *conn_list);
|
||||||
void connection_hashtable_reset(GHashTable *connection_track_table);
|
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);
|
void packet_destroy(void *opaque, void *user_data);
|
||||||
|
|
||||||
#endif /* QEMU_COLO_PROXY_H */
|
#endif /* QEMU_COLO_PROXY_H */
|
||||||
|
|
|
@ -41,12 +41,14 @@ typedef struct MirrorState {
|
||||||
CharBackend chr_in;
|
CharBackend chr_in;
|
||||||
CharBackend chr_out;
|
CharBackend chr_out;
|
||||||
SocketReadState rs;
|
SocketReadState rs;
|
||||||
|
bool vnet_hdr;
|
||||||
} MirrorState;
|
} MirrorState;
|
||||||
|
|
||||||
static int filter_send(CharBackend *chr_out,
|
static int filter_send(MirrorState *s,
|
||||||
const struct iovec *iov,
|
const struct iovec *iov,
|
||||||
int iovcnt)
|
int iovcnt)
|
||||||
{
|
{
|
||||||
|
NetFilterState *nf = NETFILTER(s);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
ssize_t size = 0;
|
ssize_t size = 0;
|
||||||
uint32_t len = 0;
|
uint32_t len = 0;
|
||||||
|
@ -58,14 +60,31 @@ static int filter_send(CharBackend *chr_out,
|
||||||
}
|
}
|
||||||
|
|
||||||
len = htonl(size);
|
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)) {
|
if (ret != sizeof(len)) {
|
||||||
goto err;
|
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);
|
buf = g_malloc(size);
|
||||||
iov_to_buf(iov, iovcnt, 0, buf, 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);
|
g_free(buf);
|
||||||
if (ret != size) {
|
if (ret != size) {
|
||||||
goto err;
|
goto err;
|
||||||
|
@ -141,7 +160,7 @@ static ssize_t filter_mirror_receive_iov(NetFilterState *nf,
|
||||||
MirrorState *s = FILTER_MIRROR(nf);
|
MirrorState *s = FILTER_MIRROR(nf);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = filter_send(&s->chr_out, iov, iovcnt);
|
ret = filter_send(s, iov, iovcnt);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
error_report("filter mirror send failed(%s)", strerror(-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;
|
int ret;
|
||||||
|
|
||||||
if (qemu_chr_fe_backend_connected(&s->chr_out)) {
|
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) {
|
if (ret) {
|
||||||
error_report("filter redirector send failed(%s)", strerror(-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) {
|
if (s->indev) {
|
||||||
chr = qemu_chr_find(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)
|
static char *filter_redirector_get_outdev(Object *obj, Error **errp)
|
||||||
{
|
{
|
||||||
MirrorState *s = FILTER_REDIRECTOR(obj);
|
MirrorState *s = FILTER_REDIRECTOR(obj);
|
||||||
|
@ -335,18 +368,48 @@ static void filter_redirector_set_outdev(Object *obj,
|
||||||
s->outdev = g_strdup(value);
|
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)
|
static void filter_mirror_init(Object *obj)
|
||||||
{
|
{
|
||||||
|
MirrorState *s = FILTER_MIRROR(obj);
|
||||||
|
|
||||||
object_property_add_str(obj, "outdev", filter_mirror_get_outdev,
|
object_property_add_str(obj, "outdev", filter_mirror_get_outdev,
|
||||||
filter_mirror_set_outdev, NULL);
|
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)
|
static void filter_redirector_init(Object *obj)
|
||||||
{
|
{
|
||||||
|
MirrorState *s = FILTER_REDIRECTOR(obj);
|
||||||
|
|
||||||
object_property_add_str(obj, "indev", filter_redirector_get_indev,
|
object_property_add_str(obj, "indev", filter_redirector_get_indev,
|
||||||
filter_redirector_set_indev, NULL);
|
filter_redirector_set_indev, NULL);
|
||||||
object_property_add_str(obj, "outdev", filter_redirector_get_outdev,
|
object_property_add_str(obj, "outdev", filter_redirector_get_outdev,
|
||||||
filter_redirector_set_outdev, NULL);
|
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)
|
static void filter_mirror_fini(Object *obj)
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "qemu-common.h"
|
#include "qemu-common.h"
|
||||||
#include "qapi/error.h"
|
#include "qapi/error.h"
|
||||||
#include "qapi/qmp/qerror.h"
|
#include "qapi/qmp/qerror.h"
|
||||||
|
#include "qemu/error-report.h"
|
||||||
#include "qapi-visit.h"
|
#include "qapi-visit.h"
|
||||||
#include "qom/object.h"
|
#include "qom/object.h"
|
||||||
#include "qemu/main-loop.h"
|
#include "qemu/main-loop.h"
|
||||||
|
@ -33,6 +34,7 @@ typedef struct RewriterState {
|
||||||
NetQueue *incoming_queue;
|
NetQueue *incoming_queue;
|
||||||
/* hashtable to save connection */
|
/* hashtable to save connection */
|
||||||
GHashTable *connection_track_table;
|
GHashTable *connection_track_table;
|
||||||
|
bool vnet_hdr;
|
||||||
} RewriterState;
|
} RewriterState;
|
||||||
|
|
||||||
static void filter_rewriter_flush(NetFilterState *nf)
|
static void filter_rewriter_flush(NetFilterState *nf)
|
||||||
|
@ -155,10 +157,16 @@ static ssize_t colo_rewriter_receive_iov(NetFilterState *nf,
|
||||||
ConnectionKey key;
|
ConnectionKey key;
|
||||||
Packet *pkt;
|
Packet *pkt;
|
||||||
ssize_t size = iov_size(iov, iovcnt);
|
ssize_t size = iov_size(iov, iovcnt);
|
||||||
|
ssize_t vnet_hdr_len = 0;
|
||||||
char *buf = g_malloc0(size);
|
char *buf = g_malloc0(size);
|
||||||
|
|
||||||
iov_to_buf(iov, iovcnt, 0, buf, 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);
|
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);
|
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)
|
static void colo_rewriter_class_init(ObjectClass *oc, void *data)
|
||||||
{
|
{
|
||||||
NetFilterClass *nfc = NETFILTER_CLASS(oc);
|
NetFilterClass *nfc = NETFILTER_CLASS(oc);
|
||||||
|
@ -250,6 +284,7 @@ static const TypeInfo colo_rewriter_info = {
|
||||||
.name = TYPE_FILTER_REWRITER,
|
.name = TYPE_FILTER_REWRITER,
|
||||||
.parent = TYPE_NETFILTER,
|
.parent = TYPE_NETFILTER,
|
||||||
.class_init = colo_rewriter_class_init,
|
.class_init = colo_rewriter_class_init,
|
||||||
|
.instance_init = filter_rewriter_init,
|
||||||
.instance_size = sizeof(RewriterState),
|
.instance_size = sizeof(RewriterState),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
35
net/net.c
35
net/net.c
|
@ -492,6 +492,7 @@ void qemu_set_vnet_hdr_len(NetClientState *nc, int len)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nc->vnet_hdr_len = len;
|
||||||
nc->info->set_vnet_hdr_len(nc, len);
|
nc->info->set_vnet_hdr_len(nc, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1615,11 +1616,14 @@ QemuOptsList qemu_net_opts = {
|
||||||
};
|
};
|
||||||
|
|
||||||
void net_socket_rs_init(SocketReadState *rs,
|
void net_socket_rs_init(SocketReadState *rs,
|
||||||
SocketReadStateFinalize *finalize)
|
SocketReadStateFinalize *finalize,
|
||||||
|
bool vnet_hdr)
|
||||||
{
|
{
|
||||||
rs->state = 0;
|
rs->state = 0;
|
||||||
|
rs->vnet_hdr = vnet_hdr;
|
||||||
rs->index = 0;
|
rs->index = 0;
|
||||||
rs->packet_len = 0;
|
rs->packet_len = 0;
|
||||||
|
rs->vnet_hdr_len = 0;
|
||||||
memset(rs->buf, 0, sizeof(rs->buf));
|
memset(rs->buf, 0, sizeof(rs->buf));
|
||||||
rs->finalize = finalize;
|
rs->finalize = finalize;
|
||||||
}
|
}
|
||||||
|
@ -1634,8 +1638,12 @@ int net_fill_rstate(SocketReadState *rs, const uint8_t *buf, int size)
|
||||||
unsigned int l;
|
unsigned int l;
|
||||||
|
|
||||||
while (size > 0) {
|
while (size > 0) {
|
||||||
/* reassemble a packet from the network */
|
/* Reassemble a packet from the network.
|
||||||
switch (rs->state) { /* 0 = getting length, 1 = getting data */
|
* 0 = getting length.
|
||||||
|
* 1 = getting vnet header length.
|
||||||
|
* 2 = getting data.
|
||||||
|
*/
|
||||||
|
switch (rs->state) {
|
||||||
case 0:
|
case 0:
|
||||||
l = 4 - rs->index;
|
l = 4 - rs->index;
|
||||||
if (l > size) {
|
if (l > size) {
|
||||||
|
@ -1649,10 +1657,31 @@ int net_fill_rstate(SocketReadState *rs, const uint8_t *buf, int size)
|
||||||
/* got length */
|
/* got length */
|
||||||
rs->packet_len = ntohl(*(uint32_t *)rs->buf);
|
rs->packet_len = ntohl(*(uint32_t *)rs->buf);
|
||||||
rs->index = 0;
|
rs->index = 0;
|
||||||
|
if (rs->vnet_hdr) {
|
||||||
rs->state = 1;
|
rs->state = 1;
|
||||||
|
} else {
|
||||||
|
rs->state = 2;
|
||||||
|
rs->vnet_hdr_len = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 1:
|
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;
|
l = rs->packet_len - rs->index;
|
||||||
if (l > size) {
|
if (l > size) {
|
||||||
l = size;
|
l = size;
|
||||||
|
|
|
@ -174,7 +174,7 @@ static void net_socket_send(void *opaque)
|
||||||
closesocket(s->fd);
|
closesocket(s->fd);
|
||||||
|
|
||||||
s->fd = -1;
|
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;
|
s->nc.link_down = true;
|
||||||
memset(s->nc.info_str, 0, sizeof(s->nc.info_str));
|
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->fd = fd;
|
||||||
s->listen_fd = -1;
|
s->listen_fd = -1;
|
||||||
s->send_fn = net_socket_send_dgram;
|
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);
|
net_socket_read_poll(s, true);
|
||||||
|
|
||||||
/* mcast: save bound address as dst */
|
/* mcast: save bound address as dst */
|
||||||
|
@ -417,7 +417,7 @@ static NetSocketState *net_socket_fd_init_stream(NetClientState *peer,
|
||||||
|
|
||||||
s->fd = fd;
|
s->fd = fd;
|
||||||
s->listen_fd = -1;
|
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 */
|
/* Disable Nagle algorithm on TCP sockets to reduce latency */
|
||||||
socket_set_nodelay(fd);
|
socket_set_nodelay(fd);
|
||||||
|
@ -522,7 +522,7 @@ static int net_socket_listen_init(NetClientState *peer,
|
||||||
s->fd = -1;
|
s->fd = -1;
|
||||||
s->listen_fd = fd;
|
s->listen_fd = fd;
|
||||||
s->nc.link_down = true;
|
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);
|
qemu_set_fd_handler(s->listen_fd, net_socket_accept, NULL, s);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -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,
|
@option{tx}: the filter is attached to the transmit queue of the netdev,
|
||||||
where it will receive packets sent by 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
|
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.
|
||||||
@var{chardevid}
|
|
||||||
|
|
||||||
@item -object filter-redirector,id=@var{id},netdev=@var{netdevid},indev=@var{chardevid},
|
@item -object filter-redirector,id=@var{id},netdev=@var{netdevid},indev=@var{chardevid},outdev=@var{chardevid},queue=@var{all|rx|tx}[,vnet_hdr_support]
|
||||||
outdev=@var{chardevid}[,queue=@var{all|rx|tx}]
|
|
||||||
|
|
||||||
filter-redirector on netdev @var{netdevid},redirect filter's net packet to chardev
|
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
|
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
|
be the same. we can just use indev or outdev, but at least one of indev or outdev
|
||||||
need to be specified.
|
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
|
Filter-rewriter is a part of COLO project.It will rewrite tcp packet to
|
||||||
secondary from primary to keep secondary tcp connection,and rewrite
|
secondary from primary to keep secondary tcp connection,and rewrite
|
||||||
tcp packet to primary from secondary make tcp packet can be handled by
|
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:
|
usage:
|
||||||
colo secondary:
|
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
|
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.
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue