mirror of
https://github.com/qemu/qemu.git
synced 2024-11-23 19:03:38 +08:00
-----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
|
||||
-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.
|
||||
|
@ -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,
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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)
|
||||
|
@ -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),
|
||||
};
|
||||
|
||||
|
37
net/net.c
37
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;
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user