-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1 iQEcBAABAgAGBQJYvOJVAAoJEO8Ells5jWIRQwEH/32qzm0gLSZnxmrmvn3iizA1 t5lYfy0mpf2kdP4U58OqcgBYoGZmL0i316ZyIn2i9k9i2NXX/1LHp3to31p/msg3 0dFwdajfSkMCZROrbU9XJZRoCSD4+DeDKa/NBA+jbQSZgscRoBjM4bjYB/U72Swp edRp/ZwD5BTO5Hpm3NDqBxmLNGqFxaeNamgx7eCrZ7OBAHFqmkNhdYH7WVKA31tU KH1KaB24POKAr6hItR4Qcs2ZDA1zPBPblKVpmZ9AisQChg/lFphMQjqyJunRRuOk OKV7fMWvfVrhqVR+IR9+J8EDS9lMI/2VA3hhs/umcmsao7uqixX57G8NmDLR6Tw= =0Lht -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/jasowang/tags/net-pull-request' into staging # gpg: Signature made Mon 06 Mar 2017 04:15:17 GMT # 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 sufficiently trusted signatures! # gpg: It is not certain 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: net/filter-mirror: Follow CODING_STYLE COLO-compare: Fix icmp and udp compare different packet always dump bug COLO-compare: Optimize compare_common and compare_tcp COLO-compare: Rename compare function and remove duplicate codes filter-rewriter: skip net_checksum_calculate() while offset = 0 net/colo: fix memory double free error vmxnet3: VMStatify rx/tx q_descr and int_state vmxnet3: Convert ring values to uint32_t's net/colo-compare: Fix memory free error colo-compare: Fix removing fds been watched incorrectly in finalization char: remove the right fd been watched in qemu_chr_fe_set_handlers() colo-compare: kick compare thread to exit after some cleanup in finalization colo-compare: use g_timeout_source_new() to process the stale packets NetRxPkt: Remove code duplication in net_rx_pkt_pull_data() NetRxPkt: Account buffer with ETH header in IOV length NetRxPkt: Do not try to pull more data than present NetRxPkt: Fix memory corruption on VLAN header stripping eth: Extend vlan stripping functions net: Remove useless local var pkt Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
eba44e9339
@ -58,7 +58,7 @@ static gboolean fd_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
|
||||
ret = qio_channel_read(
|
||||
chan, (gchar *)buf, len, NULL);
|
||||
if (ret == 0) {
|
||||
remove_fd_in_watch(chr);
|
||||
remove_fd_in_watch(chr, NULL);
|
||||
qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
|
||||
return FALSE;
|
||||
}
|
||||
@ -89,7 +89,7 @@ static void fd_chr_update_read_handler(Chardev *chr,
|
||||
{
|
||||
FDChardev *s = FD_CHARDEV(chr);
|
||||
|
||||
remove_fd_in_watch(chr);
|
||||
remove_fd_in_watch(chr, NULL);
|
||||
if (s->ioc_in) {
|
||||
chr->fd_in_tag = io_add_watch_poll(chr, s->ioc_in,
|
||||
fd_chr_read_poll,
|
||||
@ -103,7 +103,7 @@ static void char_fd_finalize(Object *obj)
|
||||
Chardev *chr = CHARDEV(obj);
|
||||
FDChardev *s = FD_CHARDEV(obj);
|
||||
|
||||
remove_fd_in_watch(chr);
|
||||
remove_fd_in_watch(chr, NULL);
|
||||
if (s->ioc_in) {
|
||||
object_unref(OBJECT(s->ioc_in));
|
||||
}
|
||||
|
@ -127,14 +127,14 @@ guint io_add_watch_poll(Chardev *chr,
|
||||
return tag;
|
||||
}
|
||||
|
||||
static void io_remove_watch_poll(guint tag)
|
||||
static void io_remove_watch_poll(guint tag, GMainContext *context)
|
||||
{
|
||||
GSource *source;
|
||||
IOWatchPoll *iwp;
|
||||
|
||||
g_return_if_fail(tag > 0);
|
||||
|
||||
source = g_main_context_find_source_by_id(NULL, tag);
|
||||
source = g_main_context_find_source_by_id(context, tag);
|
||||
g_return_if_fail(source != NULL);
|
||||
|
||||
iwp = io_watch_poll_from_source(source);
|
||||
@ -146,10 +146,10 @@ static void io_remove_watch_poll(guint tag)
|
||||
g_source_destroy(&iwp->parent);
|
||||
}
|
||||
|
||||
void remove_fd_in_watch(Chardev *chr)
|
||||
void remove_fd_in_watch(Chardev *chr, GMainContext *context)
|
||||
{
|
||||
if (chr->fd_in_tag) {
|
||||
io_remove_watch_poll(chr->fd_in_tag);
|
||||
io_remove_watch_poll(chr->fd_in_tag, context);
|
||||
chr->fd_in_tag = 0;
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ guint io_add_watch_poll(Chardev *chr,
|
||||
gpointer user_data,
|
||||
GMainContext *context);
|
||||
|
||||
void remove_fd_in_watch(Chardev *chr);
|
||||
void remove_fd_in_watch(Chardev *chr, GMainContext *context);
|
||||
|
||||
int io_channel_send(QIOChannel *ioc, const void *buf, size_t len);
|
||||
|
||||
|
@ -199,7 +199,7 @@ static void pty_chr_state(Chardev *chr, int connected)
|
||||
g_source_remove(s->open_tag);
|
||||
s->open_tag = 0;
|
||||
}
|
||||
remove_fd_in_watch(chr);
|
||||
remove_fd_in_watch(chr, NULL);
|
||||
s->connected = 0;
|
||||
/* (re-)connect poll interval for idle guests: once per second.
|
||||
* We check more frequently in case the guests sends data to
|
||||
|
@ -328,7 +328,7 @@ static void tcp_chr_free_connection(Chardev *chr)
|
||||
}
|
||||
|
||||
tcp_set_msgfds(chr, NULL, 0);
|
||||
remove_fd_in_watch(chr);
|
||||
remove_fd_in_watch(chr, NULL);
|
||||
object_unref(OBJECT(s->sioc));
|
||||
s->sioc = NULL;
|
||||
object_unref(OBJECT(s->ioc));
|
||||
@ -498,7 +498,7 @@ static void tcp_chr_update_read_handler(Chardev *chr,
|
||||
return;
|
||||
}
|
||||
|
||||
remove_fd_in_watch(chr);
|
||||
remove_fd_in_watch(chr, NULL);
|
||||
if (s->ioc) {
|
||||
chr->fd_in_tag = io_add_watch_poll(chr, s->ioc,
|
||||
tcp_chr_read_poll,
|
||||
|
@ -81,7 +81,7 @@ static gboolean udp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
|
||||
ret = qio_channel_read(
|
||||
s->ioc, (char *)s->buf, sizeof(s->buf), NULL);
|
||||
if (ret <= 0) {
|
||||
remove_fd_in_watch(chr);
|
||||
remove_fd_in_watch(chr, NULL);
|
||||
return FALSE;
|
||||
}
|
||||
s->bufcnt = ret;
|
||||
@ -101,7 +101,7 @@ static void udp_chr_update_read_handler(Chardev *chr,
|
||||
{
|
||||
UdpChardev *s = UDP_CHARDEV(chr);
|
||||
|
||||
remove_fd_in_watch(chr);
|
||||
remove_fd_in_watch(chr, NULL);
|
||||
if (s->ioc) {
|
||||
chr->fd_in_tag = io_add_watch_poll(chr, s->ioc,
|
||||
udp_chr_read_poll,
|
||||
@ -115,7 +115,7 @@ static void char_udp_finalize(Object *obj)
|
||||
Chardev *chr = CHARDEV(obj);
|
||||
UdpChardev *s = UDP_CHARDEV(obj);
|
||||
|
||||
remove_fd_in_watch(chr);
|
||||
remove_fd_in_watch(chr, NULL);
|
||||
if (s->ioc) {
|
||||
object_unref(OBJECT(s->ioc));
|
||||
}
|
||||
|
@ -560,7 +560,7 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
|
||||
cc = CHARDEV_GET_CLASS(s);
|
||||
if (!opaque && !fd_can_read && !fd_read && !fd_event) {
|
||||
fe_open = 0;
|
||||
remove_fd_in_watch(s);
|
||||
remove_fd_in_watch(s, context);
|
||||
} else {
|
||||
fe_open = 1;
|
||||
}
|
||||
|
@ -23,13 +23,13 @@
|
||||
|
||||
struct NetRxPkt {
|
||||
struct virtio_net_hdr virt_hdr;
|
||||
uint8_t ehdr_buf[sizeof(struct eth_header)];
|
||||
uint8_t ehdr_buf[sizeof(struct eth_header) + sizeof(struct vlan_header)];
|
||||
struct iovec *vec;
|
||||
uint16_t vec_len_total;
|
||||
uint16_t vec_len;
|
||||
uint32_t tot_len;
|
||||
uint16_t tci;
|
||||
bool vlan_stripped;
|
||||
size_t ehdr_buf_len;
|
||||
bool has_virt_hdr;
|
||||
eth_pkt_types_e packet_type;
|
||||
|
||||
@ -88,21 +88,21 @@ net_rx_pkt_pull_data(struct NetRxPkt *pkt,
|
||||
const struct iovec *iov, int iovcnt,
|
||||
size_t ploff)
|
||||
{
|
||||
if (pkt->vlan_stripped) {
|
||||
uint32_t pllen = iov_size(iov, iovcnt) - ploff;
|
||||
|
||||
if (pkt->ehdr_buf_len) {
|
||||
net_rx_pkt_iovec_realloc(pkt, iovcnt + 1);
|
||||
|
||||
pkt->vec[0].iov_base = pkt->ehdr_buf;
|
||||
pkt->vec[0].iov_len = sizeof(pkt->ehdr_buf);
|
||||
|
||||
pkt->tot_len =
|
||||
iov_size(iov, iovcnt) - ploff + sizeof(struct eth_header);
|
||||
pkt->vec[0].iov_len = pkt->ehdr_buf_len;
|
||||
|
||||
pkt->tot_len = pllen + pkt->ehdr_buf_len;
|
||||
pkt->vec_len = iov_copy(pkt->vec + 1, pkt->vec_len_total - 1,
|
||||
iov, iovcnt, ploff, pkt->tot_len);
|
||||
iov, iovcnt, ploff, pllen) + 1;
|
||||
} else {
|
||||
net_rx_pkt_iovec_realloc(pkt, iovcnt);
|
||||
|
||||
pkt->tot_len = iov_size(iov, iovcnt) - ploff;
|
||||
pkt->tot_len = pllen;
|
||||
pkt->vec_len = iov_copy(pkt->vec, pkt->vec_len_total,
|
||||
iov, iovcnt, ploff, pkt->tot_len);
|
||||
}
|
||||
@ -123,11 +123,12 @@ void net_rx_pkt_attach_iovec(struct NetRxPkt *pkt,
|
||||
uint16_t tci = 0;
|
||||
uint16_t ploff = iovoff;
|
||||
assert(pkt);
|
||||
pkt->vlan_stripped = false;
|
||||
|
||||
if (strip_vlan) {
|
||||
pkt->vlan_stripped = eth_strip_vlan(iov, iovcnt, iovoff, pkt->ehdr_buf,
|
||||
&ploff, &tci);
|
||||
pkt->ehdr_buf_len = eth_strip_vlan(iov, iovcnt, iovoff, pkt->ehdr_buf,
|
||||
&ploff, &tci);
|
||||
} else {
|
||||
pkt->ehdr_buf_len = 0;
|
||||
}
|
||||
|
||||
pkt->tci = tci;
|
||||
@ -143,12 +144,13 @@ void net_rx_pkt_attach_iovec_ex(struct NetRxPkt *pkt,
|
||||
uint16_t tci = 0;
|
||||
uint16_t ploff = iovoff;
|
||||
assert(pkt);
|
||||
pkt->vlan_stripped = false;
|
||||
|
||||
if (strip_vlan) {
|
||||
pkt->vlan_stripped = eth_strip_vlan_ex(iov, iovcnt, iovoff, vet,
|
||||
pkt->ehdr_buf,
|
||||
&ploff, &tci);
|
||||
pkt->ehdr_buf_len = eth_strip_vlan_ex(iov, iovcnt, iovoff, vet,
|
||||
pkt->ehdr_buf,
|
||||
&ploff, &tci);
|
||||
} else {
|
||||
pkt->ehdr_buf_len = 0;
|
||||
}
|
||||
|
||||
pkt->tci = tci;
|
||||
@ -159,11 +161,10 @@ void net_rx_pkt_attach_iovec_ex(struct NetRxPkt *pkt,
|
||||
void net_rx_pkt_dump(struct NetRxPkt *pkt)
|
||||
{
|
||||
#ifdef NET_RX_PKT_DEBUG
|
||||
NetRxPkt *pkt = (NetRxPkt *)pkt;
|
||||
assert(pkt);
|
||||
|
||||
printf("RX PKT: tot_len: %d, vlan_stripped: %d, vlan_tag: %d\n",
|
||||
pkt->tot_len, pkt->vlan_stripped, pkt->tci);
|
||||
printf("RX PKT: tot_len: %d, ehdr_buf_len: %lu, vlan_tag: %d\n",
|
||||
pkt->tot_len, pkt->ehdr_buf_len, pkt->tci);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -426,7 +427,7 @@ bool net_rx_pkt_is_vlan_stripped(struct NetRxPkt *pkt)
|
||||
{
|
||||
assert(pkt);
|
||||
|
||||
return pkt->vlan_stripped;
|
||||
return pkt->ehdr_buf_len ? true : false;
|
||||
}
|
||||
|
||||
bool net_rx_pkt_has_virt_hdr(struct NetRxPkt *pkt)
|
||||
|
284
hw/net/vmxnet3.c
284
hw/net/vmxnet3.c
@ -141,17 +141,17 @@ typedef struct VMXNET3Class {
|
||||
/* Cyclic ring abstraction */
|
||||
typedef struct {
|
||||
hwaddr pa;
|
||||
size_t size;
|
||||
size_t cell_size;
|
||||
size_t next;
|
||||
uint32_t size;
|
||||
uint32_t cell_size;
|
||||
uint32_t next;
|
||||
uint8_t gen;
|
||||
} Vmxnet3Ring;
|
||||
|
||||
static inline void vmxnet3_ring_init(PCIDevice *d,
|
||||
Vmxnet3Ring *ring,
|
||||
hwaddr pa,
|
||||
size_t size,
|
||||
size_t cell_size,
|
||||
uint32_t size,
|
||||
uint32_t cell_size,
|
||||
bool zero_region)
|
||||
{
|
||||
ring->pa = pa;
|
||||
@ -166,7 +166,7 @@ static inline void vmxnet3_ring_init(PCIDevice *d,
|
||||
}
|
||||
|
||||
#define VMXNET3_RING_DUMP(macro, ring_name, ridx, r) \
|
||||
macro("%s#%d: base %" PRIx64 " size %zu cell_size %zu gen %d next %zu", \
|
||||
macro("%s#%d: base %" PRIx64 " size %u cell_size %u gen %d next %u", \
|
||||
(ring_name), (ridx), \
|
||||
(r)->pa, (r)->size, (r)->cell_size, (r)->gen, (r)->next)
|
||||
|
||||
@ -2403,155 +2403,87 @@ static const VMStateDescription vmxstate_vmxnet3_mcast_list = {
|
||||
}
|
||||
};
|
||||
|
||||
static void vmxnet3_get_ring_from_file(QEMUFile *f, Vmxnet3Ring *r)
|
||||
{
|
||||
r->pa = qemu_get_be64(f);
|
||||
r->size = qemu_get_be32(f);
|
||||
r->cell_size = qemu_get_be32(f);
|
||||
r->next = qemu_get_be32(f);
|
||||
r->gen = qemu_get_byte(f);
|
||||
}
|
||||
|
||||
static void vmxnet3_put_ring_to_file(QEMUFile *f, Vmxnet3Ring *r)
|
||||
{
|
||||
qemu_put_be64(f, r->pa);
|
||||
qemu_put_be32(f, r->size);
|
||||
qemu_put_be32(f, r->cell_size);
|
||||
qemu_put_be32(f, r->next);
|
||||
qemu_put_byte(f, r->gen);
|
||||
}
|
||||
|
||||
static void vmxnet3_get_tx_stats_from_file(QEMUFile *f,
|
||||
struct UPT1_TxStats *tx_stat)
|
||||
{
|
||||
tx_stat->TSOPktsTxOK = qemu_get_be64(f);
|
||||
tx_stat->TSOBytesTxOK = qemu_get_be64(f);
|
||||
tx_stat->ucastPktsTxOK = qemu_get_be64(f);
|
||||
tx_stat->ucastBytesTxOK = qemu_get_be64(f);
|
||||
tx_stat->mcastPktsTxOK = qemu_get_be64(f);
|
||||
tx_stat->mcastBytesTxOK = qemu_get_be64(f);
|
||||
tx_stat->bcastPktsTxOK = qemu_get_be64(f);
|
||||
tx_stat->bcastBytesTxOK = qemu_get_be64(f);
|
||||
tx_stat->pktsTxError = qemu_get_be64(f);
|
||||
tx_stat->pktsTxDiscard = qemu_get_be64(f);
|
||||
}
|
||||
|
||||
static void vmxnet3_put_tx_stats_to_file(QEMUFile *f,
|
||||
struct UPT1_TxStats *tx_stat)
|
||||
{
|
||||
qemu_put_be64(f, tx_stat->TSOPktsTxOK);
|
||||
qemu_put_be64(f, tx_stat->TSOBytesTxOK);
|
||||
qemu_put_be64(f, tx_stat->ucastPktsTxOK);
|
||||
qemu_put_be64(f, tx_stat->ucastBytesTxOK);
|
||||
qemu_put_be64(f, tx_stat->mcastPktsTxOK);
|
||||
qemu_put_be64(f, tx_stat->mcastBytesTxOK);
|
||||
qemu_put_be64(f, tx_stat->bcastPktsTxOK);
|
||||
qemu_put_be64(f, tx_stat->bcastBytesTxOK);
|
||||
qemu_put_be64(f, tx_stat->pktsTxError);
|
||||
qemu_put_be64(f, tx_stat->pktsTxDiscard);
|
||||
}
|
||||
|
||||
static int vmxnet3_get_txq_descr(QEMUFile *f, void *pv, size_t size,
|
||||
VMStateField *field)
|
||||
{
|
||||
Vmxnet3TxqDescr *r = pv;
|
||||
|
||||
vmxnet3_get_ring_from_file(f, &r->tx_ring);
|
||||
vmxnet3_get_ring_from_file(f, &r->comp_ring);
|
||||
r->intr_idx = qemu_get_byte(f);
|
||||
r->tx_stats_pa = qemu_get_be64(f);
|
||||
|
||||
vmxnet3_get_tx_stats_from_file(f, &r->txq_stats);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vmxnet3_put_txq_descr(QEMUFile *f, void *pv, size_t size,
|
||||
VMStateField *field, QJSON *vmdesc)
|
||||
{
|
||||
Vmxnet3TxqDescr *r = pv;
|
||||
|
||||
vmxnet3_put_ring_to_file(f, &r->tx_ring);
|
||||
vmxnet3_put_ring_to_file(f, &r->comp_ring);
|
||||
qemu_put_byte(f, r->intr_idx);
|
||||
qemu_put_be64(f, r->tx_stats_pa);
|
||||
vmxnet3_put_tx_stats_to_file(f, &r->txq_stats);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const VMStateInfo txq_descr_info = {
|
||||
.name = "txq_descr",
|
||||
.get = vmxnet3_get_txq_descr,
|
||||
.put = vmxnet3_put_txq_descr
|
||||
static const VMStateDescription vmstate_vmxnet3_ring = {
|
||||
.name = "vmxnet3-ring",
|
||||
.version_id = 0,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT64(pa, Vmxnet3Ring),
|
||||
VMSTATE_UINT32(size, Vmxnet3Ring),
|
||||
VMSTATE_UINT32(cell_size, Vmxnet3Ring),
|
||||
VMSTATE_UINT32(next, Vmxnet3Ring),
|
||||
VMSTATE_UINT8(gen, Vmxnet3Ring),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void vmxnet3_get_rx_stats_from_file(QEMUFile *f,
|
||||
struct UPT1_RxStats *rx_stat)
|
||||
{
|
||||
rx_stat->LROPktsRxOK = qemu_get_be64(f);
|
||||
rx_stat->LROBytesRxOK = qemu_get_be64(f);
|
||||
rx_stat->ucastPktsRxOK = qemu_get_be64(f);
|
||||
rx_stat->ucastBytesRxOK = qemu_get_be64(f);
|
||||
rx_stat->mcastPktsRxOK = qemu_get_be64(f);
|
||||
rx_stat->mcastBytesRxOK = qemu_get_be64(f);
|
||||
rx_stat->bcastPktsRxOK = qemu_get_be64(f);
|
||||
rx_stat->bcastBytesRxOK = qemu_get_be64(f);
|
||||
rx_stat->pktsRxOutOfBuf = qemu_get_be64(f);
|
||||
rx_stat->pktsRxError = qemu_get_be64(f);
|
||||
}
|
||||
|
||||
static void vmxnet3_put_rx_stats_to_file(QEMUFile *f,
|
||||
struct UPT1_RxStats *rx_stat)
|
||||
{
|
||||
qemu_put_be64(f, rx_stat->LROPktsRxOK);
|
||||
qemu_put_be64(f, rx_stat->LROBytesRxOK);
|
||||
qemu_put_be64(f, rx_stat->ucastPktsRxOK);
|
||||
qemu_put_be64(f, rx_stat->ucastBytesRxOK);
|
||||
qemu_put_be64(f, rx_stat->mcastPktsRxOK);
|
||||
qemu_put_be64(f, rx_stat->mcastBytesRxOK);
|
||||
qemu_put_be64(f, rx_stat->bcastPktsRxOK);
|
||||
qemu_put_be64(f, rx_stat->bcastBytesRxOK);
|
||||
qemu_put_be64(f, rx_stat->pktsRxOutOfBuf);
|
||||
qemu_put_be64(f, rx_stat->pktsRxError);
|
||||
}
|
||||
|
||||
static int vmxnet3_get_rxq_descr(QEMUFile *f, void *pv, size_t size,
|
||||
VMStateField *field)
|
||||
{
|
||||
Vmxnet3RxqDescr *r = pv;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < VMXNET3_RX_RINGS_PER_QUEUE; i++) {
|
||||
vmxnet3_get_ring_from_file(f, &r->rx_ring[i]);
|
||||
static const VMStateDescription vmstate_vmxnet3_tx_stats = {
|
||||
.name = "vmxnet3-tx-stats",
|
||||
.version_id = 0,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT64(TSOPktsTxOK, struct UPT1_TxStats),
|
||||
VMSTATE_UINT64(TSOBytesTxOK, struct UPT1_TxStats),
|
||||
VMSTATE_UINT64(ucastPktsTxOK, struct UPT1_TxStats),
|
||||
VMSTATE_UINT64(ucastBytesTxOK, struct UPT1_TxStats),
|
||||
VMSTATE_UINT64(mcastPktsTxOK, struct UPT1_TxStats),
|
||||
VMSTATE_UINT64(mcastBytesTxOK, struct UPT1_TxStats),
|
||||
VMSTATE_UINT64(bcastPktsTxOK, struct UPT1_TxStats),
|
||||
VMSTATE_UINT64(bcastBytesTxOK, struct UPT1_TxStats),
|
||||
VMSTATE_UINT64(pktsTxError, struct UPT1_TxStats),
|
||||
VMSTATE_UINT64(pktsTxDiscard, struct UPT1_TxStats),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
vmxnet3_get_ring_from_file(f, &r->comp_ring);
|
||||
r->intr_idx = qemu_get_byte(f);
|
||||
r->rx_stats_pa = qemu_get_be64(f);
|
||||
|
||||
vmxnet3_get_rx_stats_from_file(f, &r->rxq_stats);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vmxnet3_put_rxq_descr(QEMUFile *f, void *pv, size_t size,
|
||||
VMStateField *field, QJSON *vmdesc)
|
||||
{
|
||||
Vmxnet3RxqDescr *r = pv;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < VMXNET3_RX_RINGS_PER_QUEUE; i++) {
|
||||
vmxnet3_put_ring_to_file(f, &r->rx_ring[i]);
|
||||
static const VMStateDescription vmstate_vmxnet3_txq_descr = {
|
||||
.name = "vmxnet3-txq-descr",
|
||||
.version_id = 0,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_STRUCT(tx_ring, Vmxnet3TxqDescr, 0, vmstate_vmxnet3_ring,
|
||||
Vmxnet3Ring),
|
||||
VMSTATE_STRUCT(comp_ring, Vmxnet3TxqDescr, 0, vmstate_vmxnet3_ring,
|
||||
Vmxnet3Ring),
|
||||
VMSTATE_UINT8(intr_idx, Vmxnet3TxqDescr),
|
||||
VMSTATE_UINT64(tx_stats_pa, Vmxnet3TxqDescr),
|
||||
VMSTATE_STRUCT(txq_stats, Vmxnet3TxqDescr, 0, vmstate_vmxnet3_tx_stats,
|
||||
struct UPT1_TxStats),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
vmxnet3_put_ring_to_file(f, &r->comp_ring);
|
||||
qemu_put_byte(f, r->intr_idx);
|
||||
qemu_put_be64(f, r->rx_stats_pa);
|
||||
vmxnet3_put_rx_stats_to_file(f, &r->rxq_stats);
|
||||
static const VMStateDescription vmstate_vmxnet3_rx_stats = {
|
||||
.name = "vmxnet3-rx-stats",
|
||||
.version_id = 0,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT64(LROPktsRxOK, struct UPT1_RxStats),
|
||||
VMSTATE_UINT64(LROBytesRxOK, struct UPT1_RxStats),
|
||||
VMSTATE_UINT64(ucastPktsRxOK, struct UPT1_RxStats),
|
||||
VMSTATE_UINT64(ucastBytesRxOK, struct UPT1_RxStats),
|
||||
VMSTATE_UINT64(mcastPktsRxOK, struct UPT1_RxStats),
|
||||
VMSTATE_UINT64(mcastBytesRxOK, struct UPT1_RxStats),
|
||||
VMSTATE_UINT64(bcastPktsRxOK, struct UPT1_RxStats),
|
||||
VMSTATE_UINT64(bcastBytesRxOK, struct UPT1_RxStats),
|
||||
VMSTATE_UINT64(pktsRxOutOfBuf, struct UPT1_RxStats),
|
||||
VMSTATE_UINT64(pktsRxError, struct UPT1_RxStats),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
return 0;
|
||||
}
|
||||
static const VMStateDescription vmstate_vmxnet3_rxq_descr = {
|
||||
.name = "vmxnet3-rxq-descr",
|
||||
.version_id = 0,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_STRUCT_ARRAY(rx_ring, Vmxnet3RxqDescr,
|
||||
VMXNET3_RX_RINGS_PER_QUEUE, 0,
|
||||
vmstate_vmxnet3_ring, Vmxnet3Ring),
|
||||
VMSTATE_STRUCT(comp_ring, Vmxnet3RxqDescr, 0, vmstate_vmxnet3_ring,
|
||||
Vmxnet3Ring),
|
||||
VMSTATE_UINT8(intr_idx, Vmxnet3RxqDescr),
|
||||
VMSTATE_UINT64(rx_stats_pa, Vmxnet3RxqDescr),
|
||||
VMSTATE_STRUCT(rxq_stats, Vmxnet3RxqDescr, 0, vmstate_vmxnet3_rx_stats,
|
||||
struct UPT1_RxStats),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static int vmxnet3_post_load(void *opaque, int version_id)
|
||||
{
|
||||
@ -2577,40 +2509,15 @@ static int vmxnet3_post_load(void *opaque, int version_id)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const VMStateInfo rxq_descr_info = {
|
||||
.name = "rxq_descr",
|
||||
.get = vmxnet3_get_rxq_descr,
|
||||
.put = vmxnet3_put_rxq_descr
|
||||
};
|
||||
|
||||
static int vmxnet3_get_int_state(QEMUFile *f, void *pv, size_t size,
|
||||
VMStateField *field)
|
||||
{
|
||||
Vmxnet3IntState *r = pv;
|
||||
|
||||
r->is_masked = qemu_get_byte(f);
|
||||
r->is_pending = qemu_get_byte(f);
|
||||
r->is_asserted = qemu_get_byte(f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vmxnet3_put_int_state(QEMUFile *f, void *pv, size_t size,
|
||||
VMStateField *field, QJSON *vmdesc)
|
||||
{
|
||||
Vmxnet3IntState *r = pv;
|
||||
|
||||
qemu_put_byte(f, r->is_masked);
|
||||
qemu_put_byte(f, r->is_pending);
|
||||
qemu_put_byte(f, r->is_asserted);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const VMStateInfo int_state_info = {
|
||||
.name = "int_state",
|
||||
.get = vmxnet3_get_int_state,
|
||||
.put = vmxnet3_put_int_state
|
||||
static const VMStateDescription vmstate_vmxnet3_int_state = {
|
||||
.name = "vmxnet3-int-state",
|
||||
.version_id = 0,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_BOOL(is_masked, Vmxnet3IntState),
|
||||
VMSTATE_BOOL(is_pending, Vmxnet3IntState),
|
||||
VMSTATE_BOOL(is_asserted, Vmxnet3IntState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static bool vmxnet3_vmstate_need_pcie_device(void *opaque)
|
||||
@ -2667,14 +2574,15 @@ static const VMStateDescription vmstate_vmxnet3 = {
|
||||
VMSTATE_UINT64(drv_shmem, VMXNET3State),
|
||||
VMSTATE_UINT64(temp_shared_guest_driver_memory, VMXNET3State),
|
||||
|
||||
VMSTATE_ARRAY(txq_descr, VMXNET3State,
|
||||
VMXNET3_DEVICE_MAX_TX_QUEUES, 0, txq_descr_info,
|
||||
VMSTATE_STRUCT_ARRAY(txq_descr, VMXNET3State,
|
||||
VMXNET3_DEVICE_MAX_TX_QUEUES, 0, vmstate_vmxnet3_txq_descr,
|
||||
Vmxnet3TxqDescr),
|
||||
VMSTATE_ARRAY(rxq_descr, VMXNET3State,
|
||||
VMXNET3_DEVICE_MAX_RX_QUEUES, 0, rxq_descr_info,
|
||||
VMSTATE_STRUCT_ARRAY(rxq_descr, VMXNET3State,
|
||||
VMXNET3_DEVICE_MAX_RX_QUEUES, 0, vmstate_vmxnet3_rxq_descr,
|
||||
Vmxnet3RxqDescr),
|
||||
VMSTATE_ARRAY(interrupt_states, VMXNET3State, VMXNET3_MAX_INTRS,
|
||||
0, int_state_info, Vmxnet3IntState),
|
||||
VMSTATE_STRUCT_ARRAY(interrupt_states, VMXNET3State,
|
||||
VMXNET3_MAX_INTRS, 0, vmstate_vmxnet3_int_state,
|
||||
Vmxnet3IntState),
|
||||
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
|
@ -331,12 +331,12 @@ eth_get_pkt_tci(const void *p)
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
size_t
|
||||
eth_strip_vlan(const struct iovec *iov, int iovcnt, size_t iovoff,
|
||||
uint8_t *new_ehdr_buf,
|
||||
uint16_t *payload_offset, uint16_t *tci);
|
||||
|
||||
bool
|
||||
size_t
|
||||
eth_strip_vlan_ex(const struct iovec *iov, int iovcnt, size_t iovoff,
|
||||
uint16_t vet, uint8_t *new_ehdr_buf,
|
||||
uint16_t *payload_offset, uint16_t *tci);
|
||||
|
@ -83,9 +83,9 @@ typedef struct CompareState {
|
||||
GHashTable *connection_track_table;
|
||||
/* compare thread, a thread for each NIC */
|
||||
QemuThread thread;
|
||||
/* Timer used on the primary to find packets that are never matched */
|
||||
QEMUTimer *timer;
|
||||
QemuMutex timer_check_lock;
|
||||
|
||||
GMainContext *worker_context;
|
||||
GMainLoop *compare_loop;
|
||||
} CompareState;
|
||||
|
||||
typedef struct CompareClass {
|
||||
@ -180,7 +180,7 @@ static int packet_enqueue(CompareState *s, int mode)
|
||||
* return: 0 means packet same
|
||||
* > 0 || < 0 means packet different
|
||||
*/
|
||||
static int colo_packet_compare(Packet *ppkt, Packet *spkt)
|
||||
static int colo_packet_compare_common(Packet *ppkt, Packet *spkt, int offset)
|
||||
{
|
||||
trace_colo_compare_ip_info(ppkt->size, inet_ntoa(ppkt->ip->ip_src),
|
||||
inet_ntoa(ppkt->ip->ip_dst), spkt->size,
|
||||
@ -188,8 +188,10 @@ static int colo_packet_compare(Packet *ppkt, Packet *spkt)
|
||||
inet_ntoa(spkt->ip->ip_dst));
|
||||
|
||||
if (ppkt->size == spkt->size) {
|
||||
return memcmp(ppkt->data, spkt->data, spkt->size);
|
||||
return memcmp(ppkt->data + offset, spkt->data + offset,
|
||||
spkt->size - offset);
|
||||
} else {
|
||||
trace_colo_compare_main("Net packet size are not the same");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@ -205,12 +207,6 @@ static int colo_packet_compare_tcp(Packet *spkt, Packet *ppkt)
|
||||
int res;
|
||||
|
||||
trace_colo_compare_main("compare tcp");
|
||||
if (ppkt->size != spkt->size) {
|
||||
if (trace_event_get_state(TRACE_COLO_COMPARE_MISCOMPARE)) {
|
||||
trace_colo_compare_main("pkt size not same");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
ptcp = (struct tcphdr *)ppkt->transport_header;
|
||||
stcp = (struct tcphdr *)spkt->transport_header;
|
||||
@ -229,8 +225,11 @@ static int colo_packet_compare_tcp(Packet *spkt, Packet *ppkt)
|
||||
spkt->ip->ip_sum = ppkt->ip->ip_sum;
|
||||
}
|
||||
|
||||
res = memcmp(ppkt->data + ETH_HLEN, spkt->data + ETH_HLEN,
|
||||
(spkt->size - ETH_HLEN));
|
||||
if (ptcp->th_sum == stcp->th_sum) {
|
||||
res = colo_packet_compare_common(ppkt, spkt, ETH_HLEN);
|
||||
} else {
|
||||
res = -1;
|
||||
}
|
||||
|
||||
if (res != 0 && trace_event_get_state(TRACE_COLO_COMPARE_MISCOMPARE)) {
|
||||
trace_colo_compare_pkt_info_src(inet_ntoa(ppkt->ip->ip_src),
|
||||
@ -261,15 +260,32 @@ static int colo_packet_compare_tcp(Packet *spkt, Packet *ppkt)
|
||||
static int colo_packet_compare_udp(Packet *spkt, Packet *ppkt)
|
||||
{
|
||||
int ret;
|
||||
int network_header_length = ppkt->ip->ip_hl * 4;
|
||||
|
||||
trace_colo_compare_main("compare udp");
|
||||
ret = colo_packet_compare(ppkt, spkt);
|
||||
|
||||
/*
|
||||
* Because of ppkt and spkt are both in the same connection,
|
||||
* The ppkt's src ip, dst ip, src port, dst port, ip_proto all are
|
||||
* same with spkt. In addition, IP header's Identification is a random
|
||||
* field, we can handle it in IP fragmentation function later.
|
||||
* COLO just concern the response net packet payload from primary guest
|
||||
* and secondary guest are same or not, So we ignored all IP header include
|
||||
* other field like TOS,TTL,IP Checksum. we only need to compare
|
||||
* the ip payload here.
|
||||
*/
|
||||
ret = colo_packet_compare_common(ppkt, spkt,
|
||||
network_header_length + ETH_HLEN);
|
||||
|
||||
if (ret) {
|
||||
trace_colo_compare_udp_miscompare("primary pkt size", ppkt->size);
|
||||
qemu_hexdump((char *)ppkt->data, stderr, "colo-compare", ppkt->size);
|
||||
trace_colo_compare_udp_miscompare("Secondary pkt size", spkt->size);
|
||||
qemu_hexdump((char *)spkt->data, stderr, "colo-compare", spkt->size);
|
||||
if (trace_event_get_state(TRACE_COLO_COMPARE_MISCOMPARE)) {
|
||||
qemu_hexdump((char *)ppkt->data, stderr, "colo-compare pri pkt",
|
||||
ppkt->size);
|
||||
qemu_hexdump((char *)spkt->data, stderr, "colo-compare sec pkt",
|
||||
spkt->size);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -281,24 +297,32 @@ static int colo_packet_compare_udp(Packet *spkt, Packet *ppkt)
|
||||
*/
|
||||
static int colo_packet_compare_icmp(Packet *spkt, Packet *ppkt)
|
||||
{
|
||||
int network_length;
|
||||
int network_header_length = ppkt->ip->ip_hl * 4;
|
||||
|
||||
trace_colo_compare_main("compare icmp");
|
||||
network_length = ppkt->ip->ip_hl * 4;
|
||||
if (ppkt->size != spkt->size ||
|
||||
ppkt->size < network_length + ETH_HLEN) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (colo_packet_compare(ppkt, spkt)) {
|
||||
/*
|
||||
* Because of ppkt and spkt are both in the same connection,
|
||||
* The ppkt's src ip, dst ip, src port, dst port, ip_proto all are
|
||||
* same with spkt. In addition, IP header's Identification is a random
|
||||
* field, we can handle it in IP fragmentation function later.
|
||||
* COLO just concern the response net packet payload from primary guest
|
||||
* and secondary guest are same or not, So we ignored all IP header include
|
||||
* other field like TOS,TTL,IP Checksum. we only need to compare
|
||||
* the ip payload here.
|
||||
*/
|
||||
if (colo_packet_compare_common(ppkt, spkt,
|
||||
network_header_length + ETH_HLEN)) {
|
||||
trace_colo_compare_icmp_miscompare("primary pkt size",
|
||||
ppkt->size);
|
||||
qemu_hexdump((char *)ppkt->data, stderr, "colo-compare",
|
||||
ppkt->size);
|
||||
trace_colo_compare_icmp_miscompare("Secondary pkt size",
|
||||
spkt->size);
|
||||
qemu_hexdump((char *)spkt->data, stderr, "colo-compare",
|
||||
spkt->size);
|
||||
if (trace_event_get_state(TRACE_COLO_COMPARE_MISCOMPARE)) {
|
||||
qemu_hexdump((char *)ppkt->data, stderr, "colo-compare pri pkt",
|
||||
ppkt->size);
|
||||
qemu_hexdump((char *)spkt->data, stderr, "colo-compare sec pkt",
|
||||
spkt->size);
|
||||
}
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
@ -316,7 +340,7 @@ static int colo_packet_compare_other(Packet *spkt, Packet *ppkt)
|
||||
inet_ntoa(ppkt->ip->ip_dst), spkt->size,
|
||||
inet_ntoa(spkt->ip->ip_src),
|
||||
inet_ntoa(spkt->ip->ip_dst));
|
||||
return colo_packet_compare(ppkt, spkt);
|
||||
return colo_packet_compare_common(ppkt, spkt, 0);
|
||||
}
|
||||
|
||||
static int colo_old_packet_check_one(Packet *pkt, int64_t *check_time)
|
||||
@ -374,9 +398,7 @@ static void colo_compare_connection(void *opaque, void *user_data)
|
||||
|
||||
while (!g_queue_is_empty(&conn->primary_list) &&
|
||||
!g_queue_is_empty(&conn->secondary_list)) {
|
||||
qemu_mutex_lock(&s->timer_check_lock);
|
||||
pkt = g_queue_pop_tail(&conn->primary_list);
|
||||
qemu_mutex_unlock(&s->timer_check_lock);
|
||||
switch (conn->ip_proto) {
|
||||
case IPPROTO_TCP:
|
||||
result = g_queue_find_custom(&conn->secondary_list,
|
||||
@ -411,9 +433,7 @@ static void colo_compare_connection(void *opaque, void *user_data)
|
||||
* until next comparison.
|
||||
*/
|
||||
trace_colo_compare_main("packet different");
|
||||
qemu_mutex_lock(&s->timer_check_lock);
|
||||
g_queue_push_tail(&conn->primary_list, pkt);
|
||||
qemu_mutex_unlock(&s->timer_check_lock);
|
||||
/* TODO: colo_notify_checkpoint();*/
|
||||
break;
|
||||
}
|
||||
@ -486,25 +506,45 @@ static void compare_sec_chr_in(void *opaque, const uint8_t *buf, int size)
|
||||
}
|
||||
}
|
||||
|
||||
static void *colo_compare_thread(void *opaque)
|
||||
/*
|
||||
* Check old packet regularly so it can watch for any packets
|
||||
* that the secondary hasn't produced equivalents of.
|
||||
*/
|
||||
static gboolean check_old_packet_regular(void *opaque)
|
||||
{
|
||||
GMainContext *worker_context;
|
||||
GMainLoop *compare_loop;
|
||||
CompareState *s = opaque;
|
||||
|
||||
worker_context = g_main_context_new();
|
||||
/* if have old packet we will notify checkpoint */
|
||||
colo_old_packet_check(s);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void *colo_compare_thread(void *opaque)
|
||||
{
|
||||
CompareState *s = opaque;
|
||||
GSource *timeout_source;
|
||||
|
||||
s->worker_context = g_main_context_new();
|
||||
|
||||
qemu_chr_fe_set_handlers(&s->chr_pri_in, compare_chr_can_read,
|
||||
compare_pri_chr_in, NULL, s, worker_context, true);
|
||||
compare_pri_chr_in, NULL, s, s->worker_context, true);
|
||||
qemu_chr_fe_set_handlers(&s->chr_sec_in, compare_chr_can_read,
|
||||
compare_sec_chr_in, NULL, s, worker_context, true);
|
||||
compare_sec_chr_in, NULL, s, s->worker_context, true);
|
||||
|
||||
compare_loop = g_main_loop_new(worker_context, FALSE);
|
||||
s->compare_loop = g_main_loop_new(s->worker_context, FALSE);
|
||||
|
||||
g_main_loop_run(compare_loop);
|
||||
/* To kick any packets that the secondary doesn't match */
|
||||
timeout_source = g_timeout_source_new(REGULAR_PACKET_CHECK_MS);
|
||||
g_source_set_callback(timeout_source,
|
||||
(GSourceFunc)check_old_packet_regular, s, NULL);
|
||||
g_source_attach(timeout_source, s->worker_context);
|
||||
|
||||
g_main_loop_unref(compare_loop);
|
||||
g_main_context_unref(worker_context);
|
||||
g_main_loop_run(s->compare_loop);
|
||||
|
||||
g_source_unref(timeout_source);
|
||||
g_main_loop_unref(s->compare_loop);
|
||||
g_main_context_unref(s->worker_context);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -603,26 +643,6 @@ static int find_and_check_chardev(Chardev **chr,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check old packet regularly so it can watch for any packets
|
||||
* that the secondary hasn't produced equivalents of.
|
||||
*/
|
||||
static void check_old_packet_regular(void *opaque)
|
||||
{
|
||||
CompareState *s = opaque;
|
||||
|
||||
timer_mod(s->timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) +
|
||||
REGULAR_PACKET_CHECK_MS);
|
||||
/* if have old packet we will notify checkpoint */
|
||||
/*
|
||||
* TODO: Make timer handler run in compare thread
|
||||
* like qemu_chr_add_handlers_full.
|
||||
*/
|
||||
qemu_mutex_lock(&s->timer_check_lock);
|
||||
colo_old_packet_check(s);
|
||||
qemu_mutex_unlock(&s->timer_check_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called from the main thread on the primary
|
||||
* to setup colo-compare.
|
||||
@ -665,7 +685,6 @@ static void colo_compare_complete(UserCreatable *uc, Error **errp)
|
||||
net_socket_rs_init(&s->sec_rs, compare_sec_rs_finalize);
|
||||
|
||||
g_queue_init(&s->conn_list);
|
||||
qemu_mutex_init(&s->timer_check_lock);
|
||||
|
||||
s->connection_track_table = g_hash_table_new_full(connection_key_hash,
|
||||
connection_key_equal,
|
||||
@ -678,15 +697,26 @@ static void colo_compare_complete(UserCreatable *uc, Error **errp)
|
||||
QEMU_THREAD_JOINABLE);
|
||||
compare_id++;
|
||||
|
||||
/* A regular timer to kick any packets that the secondary doesn't match */
|
||||
s->timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, /* Only when guest runs */
|
||||
check_old_packet_regular, s);
|
||||
timer_mod(s->timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) +
|
||||
REGULAR_PACKET_CHECK_MS);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void colo_flush_packets(void *opaque, void *user_data)
|
||||
{
|
||||
CompareState *s = user_data;
|
||||
Connection *conn = opaque;
|
||||
Packet *pkt = NULL;
|
||||
|
||||
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);
|
||||
packet_destroy(pkt, NULL);
|
||||
}
|
||||
while (!g_queue_is_empty(&conn->secondary_list)) {
|
||||
pkt = g_queue_pop_head(&conn->secondary_list);
|
||||
packet_destroy(pkt, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void colo_compare_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
|
||||
@ -711,24 +741,21 @@ static void colo_compare_finalize(Object *obj)
|
||||
{
|
||||
CompareState *s = COLO_COMPARE(obj);
|
||||
|
||||
qemu_chr_fe_deinit(&s->chr_pri_in);
|
||||
qemu_chr_fe_deinit(&s->chr_sec_in);
|
||||
qemu_chr_fe_set_handlers(&s->chr_pri_in, NULL, NULL, NULL, NULL,
|
||||
s->worker_context, true);
|
||||
qemu_chr_fe_set_handlers(&s->chr_sec_in, NULL, NULL, NULL, NULL,
|
||||
s->worker_context, true);
|
||||
qemu_chr_fe_deinit(&s->chr_out);
|
||||
|
||||
g_queue_free(&s->conn_list);
|
||||
g_main_loop_quit(s->compare_loop);
|
||||
qemu_thread_join(&s->thread);
|
||||
|
||||
if (qemu_thread_is_self(&s->thread)) {
|
||||
/* compare connection */
|
||||
g_queue_foreach(&s->conn_list, colo_compare_connection, s);
|
||||
qemu_thread_join(&s->thread);
|
||||
}
|
||||
/* Release all unhandled packets after compare thead exited */
|
||||
g_queue_foreach(&s->conn_list, colo_flush_packets, s);
|
||||
|
||||
if (s->timer) {
|
||||
timer_del(s->timer);
|
||||
}
|
||||
|
||||
qemu_mutex_destroy(&s->timer_check_lock);
|
||||
g_queue_clear(&s->conn_list);
|
||||
|
||||
g_hash_table_destroy(s->connection_track_table);
|
||||
g_free(s->pri_indev);
|
||||
g_free(s->sec_indev);
|
||||
g_free(s->outdev);
|
||||
|
@ -147,9 +147,9 @@ void connection_destroy(void *opaque)
|
||||
Connection *conn = opaque;
|
||||
|
||||
g_queue_foreach(&conn->primary_list, packet_destroy, NULL);
|
||||
g_queue_free(&conn->primary_list);
|
||||
g_queue_clear(&conn->primary_list);
|
||||
g_queue_foreach(&conn->secondary_list, packet_destroy, NULL);
|
||||
g_queue_free(&conn->secondary_list);
|
||||
g_queue_clear(&conn->secondary_list);
|
||||
g_slice_free(Connection, conn);
|
||||
}
|
||||
|
||||
|
25
net/eth.c
25
net/eth.c
@ -232,7 +232,7 @@ void eth_get_protocols(const struct iovec *iov, int iovcnt,
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
size_t
|
||||
eth_strip_vlan(const struct iovec *iov, int iovcnt, size_t iovoff,
|
||||
uint8_t *new_ehdr_buf,
|
||||
uint16_t *payload_offset, uint16_t *tci)
|
||||
@ -244,7 +244,7 @@ eth_strip_vlan(const struct iovec *iov, int iovcnt, size_t iovoff,
|
||||
new_ehdr, sizeof(*new_ehdr));
|
||||
|
||||
if (copied < sizeof(*new_ehdr)) {
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (be16_to_cpu(new_ehdr->h_proto)) {
|
||||
@ -254,7 +254,7 @@ eth_strip_vlan(const struct iovec *iov, int iovcnt, size_t iovoff,
|
||||
&vlan_hdr, sizeof(vlan_hdr));
|
||||
|
||||
if (copied < sizeof(vlan_hdr)) {
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
new_ehdr->h_proto = vlan_hdr.h_proto;
|
||||
@ -268,18 +268,21 @@ eth_strip_vlan(const struct iovec *iov, int iovcnt, size_t iovoff,
|
||||
PKT_GET_VLAN_HDR(new_ehdr), sizeof(vlan_hdr));
|
||||
|
||||
if (copied < sizeof(vlan_hdr)) {
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*payload_offset += sizeof(vlan_hdr);
|
||||
|
||||
return sizeof(struct eth_header) + sizeof(struct vlan_header);
|
||||
} else {
|
||||
return sizeof(struct eth_header);
|
||||
}
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
size_t
|
||||
eth_strip_vlan_ex(const struct iovec *iov, int iovcnt, size_t iovoff,
|
||||
uint16_t vet, uint8_t *new_ehdr_buf,
|
||||
uint16_t *payload_offset, uint16_t *tci)
|
||||
@ -291,7 +294,7 @@ eth_strip_vlan_ex(const struct iovec *iov, int iovcnt, size_t iovoff,
|
||||
new_ehdr, sizeof(*new_ehdr));
|
||||
|
||||
if (copied < sizeof(*new_ehdr)) {
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (be16_to_cpu(new_ehdr->h_proto) == vet) {
|
||||
@ -299,17 +302,17 @@ eth_strip_vlan_ex(const struct iovec *iov, int iovcnt, size_t iovoff,
|
||||
&vlan_hdr, sizeof(vlan_hdr));
|
||||
|
||||
if (copied < sizeof(vlan_hdr)) {
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
new_ehdr->h_proto = vlan_hdr.h_proto;
|
||||
|
||||
*tci = be16_to_cpu(vlan_hdr.h_tci);
|
||||
*payload_offset = iovoff + sizeof(*new_ehdr) + sizeof(vlan_hdr);
|
||||
return true;
|
||||
return sizeof(struct eth_header);
|
||||
}
|
||||
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -49,7 +49,7 @@ static int filter_mirror_send(CharBackend *chr_out,
|
||||
{
|
||||
int ret = 0;
|
||||
ssize_t size = 0;
|
||||
uint32_t len = 0;
|
||||
uint32_t len = 0;
|
||||
char *buf;
|
||||
|
||||
size = iov_size(iov, iovcnt);
|
||||
@ -77,8 +77,9 @@ err:
|
||||
return ret < 0 ? ret : -EIO;
|
||||
}
|
||||
|
||||
static void
|
||||
redirector_to_filter(NetFilterState *nf, const uint8_t *buf, int len)
|
||||
static void redirector_to_filter(NetFilterState *nf,
|
||||
const uint8_t *buf,
|
||||
int len)
|
||||
{
|
||||
struct iovec iov = {
|
||||
.iov_base = (void *)buf,
|
||||
|
@ -93,10 +93,12 @@ static int handle_primary_tcp_pkt(NetFilterState *nf,
|
||||
conn->offset -= (ntohl(tcp_pkt->th_ack) - 1);
|
||||
conn->syn_flag = 0;
|
||||
}
|
||||
/* handle packets to the secondary from the primary */
|
||||
tcp_pkt->th_ack = htonl(ntohl(tcp_pkt->th_ack) + conn->offset);
|
||||
if (conn->offset) {
|
||||
/* handle packets to the secondary from the primary */
|
||||
tcp_pkt->th_ack = htonl(ntohl(tcp_pkt->th_ack) + conn->offset);
|
||||
|
||||
net_checksum_calculate((uint8_t *)pkt->data, pkt->size);
|
||||
net_checksum_calculate((uint8_t *)pkt->data, pkt->size);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -129,10 +131,13 @@ static int handle_secondary_tcp_pkt(NetFilterState *nf,
|
||||
}
|
||||
|
||||
if ((tcp_pkt->th_flags & (TH_ACK | TH_SYN)) == TH_ACK) {
|
||||
/* handle packets to the primary from the secondary*/
|
||||
tcp_pkt->th_seq = htonl(ntohl(tcp_pkt->th_seq) - conn->offset);
|
||||
/* Only need to adjust seq while offset is Non-zero */
|
||||
if (conn->offset) {
|
||||
/* handle packets to the primary from the secondary*/
|
||||
tcp_pkt->th_seq = htonl(ntohl(tcp_pkt->th_seq) - conn->offset);
|
||||
|
||||
net_checksum_calculate((uint8_t *)pkt->data, pkt->size);
|
||||
net_checksum_calculate((uint8_t *)pkt->data, pkt->size);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
Loading…
Reference in New Issue
Block a user