-----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:
Peter Maydell 2017-03-06 15:13:23 +00:00
commit eba44e9339
15 changed files with 274 additions and 329 deletions

View File

@ -58,7 +58,7 @@ static gboolean fd_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
ret = qio_channel_read( ret = qio_channel_read(
chan, (gchar *)buf, len, NULL); chan, (gchar *)buf, len, NULL);
if (ret == 0) { if (ret == 0) {
remove_fd_in_watch(chr); remove_fd_in_watch(chr, NULL);
qemu_chr_be_event(chr, CHR_EVENT_CLOSED); qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
return FALSE; return FALSE;
} }
@ -89,7 +89,7 @@ static void fd_chr_update_read_handler(Chardev *chr,
{ {
FDChardev *s = FD_CHARDEV(chr); FDChardev *s = FD_CHARDEV(chr);
remove_fd_in_watch(chr); remove_fd_in_watch(chr, NULL);
if (s->ioc_in) { if (s->ioc_in) {
chr->fd_in_tag = io_add_watch_poll(chr, s->ioc_in, chr->fd_in_tag = io_add_watch_poll(chr, s->ioc_in,
fd_chr_read_poll, fd_chr_read_poll,
@ -103,7 +103,7 @@ static void char_fd_finalize(Object *obj)
Chardev *chr = CHARDEV(obj); Chardev *chr = CHARDEV(obj);
FDChardev *s = FD_CHARDEV(obj); FDChardev *s = FD_CHARDEV(obj);
remove_fd_in_watch(chr); remove_fd_in_watch(chr, NULL);
if (s->ioc_in) { if (s->ioc_in) {
object_unref(OBJECT(s->ioc_in)); object_unref(OBJECT(s->ioc_in));
} }

View File

@ -127,14 +127,14 @@ guint io_add_watch_poll(Chardev *chr,
return tag; return tag;
} }
static void io_remove_watch_poll(guint tag) static void io_remove_watch_poll(guint tag, GMainContext *context)
{ {
GSource *source; GSource *source;
IOWatchPoll *iwp; IOWatchPoll *iwp;
g_return_if_fail(tag > 0); 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); g_return_if_fail(source != NULL);
iwp = io_watch_poll_from_source(source); iwp = io_watch_poll_from_source(source);
@ -146,10 +146,10 @@ static void io_remove_watch_poll(guint tag)
g_source_destroy(&iwp->parent); 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) { 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; chr->fd_in_tag = 0;
} }
} }

View File

@ -36,7 +36,7 @@ guint io_add_watch_poll(Chardev *chr,
gpointer user_data, gpointer user_data,
GMainContext *context); 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); int io_channel_send(QIOChannel *ioc, const void *buf, size_t len);

View File

@ -199,7 +199,7 @@ static void pty_chr_state(Chardev *chr, int connected)
g_source_remove(s->open_tag); g_source_remove(s->open_tag);
s->open_tag = 0; s->open_tag = 0;
} }
remove_fd_in_watch(chr); remove_fd_in_watch(chr, NULL);
s->connected = 0; s->connected = 0;
/* (re-)connect poll interval for idle guests: once per second. /* (re-)connect poll interval for idle guests: once per second.
* We check more frequently in case the guests sends data to * We check more frequently in case the guests sends data to

View File

@ -328,7 +328,7 @@ static void tcp_chr_free_connection(Chardev *chr)
} }
tcp_set_msgfds(chr, NULL, 0); tcp_set_msgfds(chr, NULL, 0);
remove_fd_in_watch(chr); remove_fd_in_watch(chr, NULL);
object_unref(OBJECT(s->sioc)); object_unref(OBJECT(s->sioc));
s->sioc = NULL; s->sioc = NULL;
object_unref(OBJECT(s->ioc)); object_unref(OBJECT(s->ioc));
@ -498,7 +498,7 @@ static void tcp_chr_update_read_handler(Chardev *chr,
return; return;
} }
remove_fd_in_watch(chr); remove_fd_in_watch(chr, NULL);
if (s->ioc) { if (s->ioc) {
chr->fd_in_tag = io_add_watch_poll(chr, s->ioc, chr->fd_in_tag = io_add_watch_poll(chr, s->ioc,
tcp_chr_read_poll, tcp_chr_read_poll,

View File

@ -81,7 +81,7 @@ static gboolean udp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
ret = qio_channel_read( ret = qio_channel_read(
s->ioc, (char *)s->buf, sizeof(s->buf), NULL); s->ioc, (char *)s->buf, sizeof(s->buf), NULL);
if (ret <= 0) { if (ret <= 0) {
remove_fd_in_watch(chr); remove_fd_in_watch(chr, NULL);
return FALSE; return FALSE;
} }
s->bufcnt = ret; s->bufcnt = ret;
@ -101,7 +101,7 @@ static void udp_chr_update_read_handler(Chardev *chr,
{ {
UdpChardev *s = UDP_CHARDEV(chr); UdpChardev *s = UDP_CHARDEV(chr);
remove_fd_in_watch(chr); remove_fd_in_watch(chr, NULL);
if (s->ioc) { if (s->ioc) {
chr->fd_in_tag = io_add_watch_poll(chr, s->ioc, chr->fd_in_tag = io_add_watch_poll(chr, s->ioc,
udp_chr_read_poll, udp_chr_read_poll,
@ -115,7 +115,7 @@ static void char_udp_finalize(Object *obj)
Chardev *chr = CHARDEV(obj); Chardev *chr = CHARDEV(obj);
UdpChardev *s = UDP_CHARDEV(obj); UdpChardev *s = UDP_CHARDEV(obj);
remove_fd_in_watch(chr); remove_fd_in_watch(chr, NULL);
if (s->ioc) { if (s->ioc) {
object_unref(OBJECT(s->ioc)); object_unref(OBJECT(s->ioc));
} }

View File

@ -560,7 +560,7 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
cc = CHARDEV_GET_CLASS(s); cc = CHARDEV_GET_CLASS(s);
if (!opaque && !fd_can_read && !fd_read && !fd_event) { if (!opaque && !fd_can_read && !fd_read && !fd_event) {
fe_open = 0; fe_open = 0;
remove_fd_in_watch(s); remove_fd_in_watch(s, context);
} else { } else {
fe_open = 1; fe_open = 1;
} }

View File

@ -23,13 +23,13 @@
struct NetRxPkt { struct NetRxPkt {
struct virtio_net_hdr virt_hdr; 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; struct iovec *vec;
uint16_t vec_len_total; uint16_t vec_len_total;
uint16_t vec_len; uint16_t vec_len;
uint32_t tot_len; uint32_t tot_len;
uint16_t tci; uint16_t tci;
bool vlan_stripped; size_t ehdr_buf_len;
bool has_virt_hdr; bool has_virt_hdr;
eth_pkt_types_e packet_type; eth_pkt_types_e packet_type;
@ -88,21 +88,21 @@ net_rx_pkt_pull_data(struct NetRxPkt *pkt,
const struct iovec *iov, int iovcnt, const struct iovec *iov, int iovcnt,
size_t ploff) 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); net_rx_pkt_iovec_realloc(pkt, iovcnt + 1);
pkt->vec[0].iov_base = pkt->ehdr_buf; pkt->vec[0].iov_base = pkt->ehdr_buf;
pkt->vec[0].iov_len = sizeof(pkt->ehdr_buf); pkt->vec[0].iov_len = pkt->ehdr_buf_len;
pkt->tot_len =
iov_size(iov, iovcnt) - ploff + sizeof(struct eth_header);
pkt->tot_len = pllen + pkt->ehdr_buf_len;
pkt->vec_len = iov_copy(pkt->vec + 1, pkt->vec_len_total - 1, 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 { } else {
net_rx_pkt_iovec_realloc(pkt, iovcnt); 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, pkt->vec_len = iov_copy(pkt->vec, pkt->vec_len_total,
iov, iovcnt, ploff, pkt->tot_len); 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 tci = 0;
uint16_t ploff = iovoff; uint16_t ploff = iovoff;
assert(pkt); assert(pkt);
pkt->vlan_stripped = false;
if (strip_vlan) { if (strip_vlan) {
pkt->vlan_stripped = eth_strip_vlan(iov, iovcnt, iovoff, pkt->ehdr_buf, pkt->ehdr_buf_len = eth_strip_vlan(iov, iovcnt, iovoff, pkt->ehdr_buf,
&ploff, &tci); &ploff, &tci);
} else {
pkt->ehdr_buf_len = 0;
} }
pkt->tci = tci; pkt->tci = tci;
@ -143,12 +144,13 @@ void net_rx_pkt_attach_iovec_ex(struct NetRxPkt *pkt,
uint16_t tci = 0; uint16_t tci = 0;
uint16_t ploff = iovoff; uint16_t ploff = iovoff;
assert(pkt); assert(pkt);
pkt->vlan_stripped = false;
if (strip_vlan) { if (strip_vlan) {
pkt->vlan_stripped = eth_strip_vlan_ex(iov, iovcnt, iovoff, vet, pkt->ehdr_buf_len = eth_strip_vlan_ex(iov, iovcnt, iovoff, vet,
pkt->ehdr_buf, pkt->ehdr_buf,
&ploff, &tci); &ploff, &tci);
} else {
pkt->ehdr_buf_len = 0;
} }
pkt->tci = tci; 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) void net_rx_pkt_dump(struct NetRxPkt *pkt)
{ {
#ifdef NET_RX_PKT_DEBUG #ifdef NET_RX_PKT_DEBUG
NetRxPkt *pkt = (NetRxPkt *)pkt;
assert(pkt); assert(pkt);
printf("RX PKT: tot_len: %d, vlan_stripped: %d, vlan_tag: %d\n", printf("RX PKT: tot_len: %d, ehdr_buf_len: %lu, vlan_tag: %d\n",
pkt->tot_len, pkt->vlan_stripped, pkt->tci); pkt->tot_len, pkt->ehdr_buf_len, pkt->tci);
#endif #endif
} }
@ -426,7 +427,7 @@ bool net_rx_pkt_is_vlan_stripped(struct NetRxPkt *pkt)
{ {
assert(pkt); assert(pkt);
return pkt->vlan_stripped; return pkt->ehdr_buf_len ? true : false;
} }
bool net_rx_pkt_has_virt_hdr(struct NetRxPkt *pkt) bool net_rx_pkt_has_virt_hdr(struct NetRxPkt *pkt)

View File

@ -141,17 +141,17 @@ typedef struct VMXNET3Class {
/* Cyclic ring abstraction */ /* Cyclic ring abstraction */
typedef struct { typedef struct {
hwaddr pa; hwaddr pa;
size_t size; uint32_t size;
size_t cell_size; uint32_t cell_size;
size_t next; uint32_t next;
uint8_t gen; uint8_t gen;
} Vmxnet3Ring; } Vmxnet3Ring;
static inline void vmxnet3_ring_init(PCIDevice *d, static inline void vmxnet3_ring_init(PCIDevice *d,
Vmxnet3Ring *ring, Vmxnet3Ring *ring,
hwaddr pa, hwaddr pa,
size_t size, uint32_t size,
size_t cell_size, uint32_t cell_size,
bool zero_region) bool zero_region)
{ {
ring->pa = pa; ring->pa = pa;
@ -166,7 +166,7 @@ static inline void vmxnet3_ring_init(PCIDevice *d,
} }
#define VMXNET3_RING_DUMP(macro, ring_name, ridx, r) \ #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), \ (ring_name), (ridx), \
(r)->pa, (r)->size, (r)->cell_size, (r)->gen, (r)->next) (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) static const VMStateDescription vmstate_vmxnet3_ring = {
{ .name = "vmxnet3-ring",
r->pa = qemu_get_be64(f); .version_id = 0,
r->size = qemu_get_be32(f); .fields = (VMStateField[]) {
r->cell_size = qemu_get_be32(f); VMSTATE_UINT64(pa, Vmxnet3Ring),
r->next = qemu_get_be32(f); VMSTATE_UINT32(size, Vmxnet3Ring),
r->gen = qemu_get_byte(f); VMSTATE_UINT32(cell_size, Vmxnet3Ring),
} VMSTATE_UINT32(next, Vmxnet3Ring),
VMSTATE_UINT8(gen, Vmxnet3Ring),
static void vmxnet3_put_ring_to_file(QEMUFile *f, Vmxnet3Ring *r) VMSTATE_END_OF_LIST()
{ }
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 void vmxnet3_get_rx_stats_from_file(QEMUFile *f, static const VMStateDescription vmstate_vmxnet3_tx_stats = {
struct UPT1_RxStats *rx_stat) .name = "vmxnet3-tx-stats",
{ .version_id = 0,
rx_stat->LROPktsRxOK = qemu_get_be64(f); .fields = (VMStateField[]) {
rx_stat->LROBytesRxOK = qemu_get_be64(f); VMSTATE_UINT64(TSOPktsTxOK, struct UPT1_TxStats),
rx_stat->ucastPktsRxOK = qemu_get_be64(f); VMSTATE_UINT64(TSOBytesTxOK, struct UPT1_TxStats),
rx_stat->ucastBytesRxOK = qemu_get_be64(f); VMSTATE_UINT64(ucastPktsTxOK, struct UPT1_TxStats),
rx_stat->mcastPktsRxOK = qemu_get_be64(f); VMSTATE_UINT64(ucastBytesTxOK, struct UPT1_TxStats),
rx_stat->mcastBytesRxOK = qemu_get_be64(f); VMSTATE_UINT64(mcastPktsTxOK, struct UPT1_TxStats),
rx_stat->bcastPktsRxOK = qemu_get_be64(f); VMSTATE_UINT64(mcastBytesTxOK, struct UPT1_TxStats),
rx_stat->bcastBytesRxOK = qemu_get_be64(f); VMSTATE_UINT64(bcastPktsTxOK, struct UPT1_TxStats),
rx_stat->pktsRxOutOfBuf = qemu_get_be64(f); VMSTATE_UINT64(bcastBytesTxOK, struct UPT1_TxStats),
rx_stat->pktsRxError = qemu_get_be64(f); VMSTATE_UINT64(pktsTxError, struct UPT1_TxStats),
} VMSTATE_UINT64(pktsTxDiscard, struct UPT1_TxStats),
VMSTATE_END_OF_LIST()
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]);
} }
};
vmxnet3_get_ring_from_file(f, &r->comp_ring); static const VMStateDescription vmstate_vmxnet3_txq_descr = {
r->intr_idx = qemu_get_byte(f); .name = "vmxnet3-txq-descr",
r->rx_stats_pa = qemu_get_be64(f); .version_id = 0,
.fields = (VMStateField[]) {
vmxnet3_get_rx_stats_from_file(f, &r->rxq_stats); VMSTATE_STRUCT(tx_ring, Vmxnet3TxqDescr, 0, vmstate_vmxnet3_ring,
Vmxnet3Ring),
return 0; VMSTATE_STRUCT(comp_ring, Vmxnet3TxqDescr, 0, vmstate_vmxnet3_ring,
} Vmxnet3Ring),
VMSTATE_UINT8(intr_idx, Vmxnet3TxqDescr),
static int vmxnet3_put_rxq_descr(QEMUFile *f, void *pv, size_t size, VMSTATE_UINT64(tx_stats_pa, Vmxnet3TxqDescr),
VMStateField *field, QJSON *vmdesc) VMSTATE_STRUCT(txq_stats, Vmxnet3TxqDescr, 0, vmstate_vmxnet3_tx_stats,
{ struct UPT1_TxStats),
Vmxnet3RxqDescr *r = pv; VMSTATE_END_OF_LIST()
int i;
for (i = 0; i < VMXNET3_RX_RINGS_PER_QUEUE; i++) {
vmxnet3_put_ring_to_file(f, &r->rx_ring[i]);
} }
};
vmxnet3_put_ring_to_file(f, &r->comp_ring); static const VMStateDescription vmstate_vmxnet3_rx_stats = {
qemu_put_byte(f, r->intr_idx); .name = "vmxnet3-rx-stats",
qemu_put_be64(f, r->rx_stats_pa); .version_id = 0,
vmxnet3_put_rx_stats_to_file(f, &r->rxq_stats); .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) 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; return 0;
} }
static const VMStateInfo rxq_descr_info = { static const VMStateDescription vmstate_vmxnet3_int_state = {
.name = "rxq_descr", .name = "vmxnet3-int-state",
.get = vmxnet3_get_rxq_descr, .version_id = 0,
.put = vmxnet3_put_rxq_descr .fields = (VMStateField[]) {
}; VMSTATE_BOOL(is_masked, Vmxnet3IntState),
VMSTATE_BOOL(is_pending, Vmxnet3IntState),
static int vmxnet3_get_int_state(QEMUFile *f, void *pv, size_t size, VMSTATE_BOOL(is_asserted, Vmxnet3IntState),
VMStateField *field) VMSTATE_END_OF_LIST()
{ }
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 bool vmxnet3_vmstate_need_pcie_device(void *opaque) 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(drv_shmem, VMXNET3State),
VMSTATE_UINT64(temp_shared_guest_driver_memory, VMXNET3State), VMSTATE_UINT64(temp_shared_guest_driver_memory, VMXNET3State),
VMSTATE_ARRAY(txq_descr, VMXNET3State, VMSTATE_STRUCT_ARRAY(txq_descr, VMXNET3State,
VMXNET3_DEVICE_MAX_TX_QUEUES, 0, txq_descr_info, VMXNET3_DEVICE_MAX_TX_QUEUES, 0, vmstate_vmxnet3_txq_descr,
Vmxnet3TxqDescr), Vmxnet3TxqDescr),
VMSTATE_ARRAY(rxq_descr, VMXNET3State, VMSTATE_STRUCT_ARRAY(rxq_descr, VMXNET3State,
VMXNET3_DEVICE_MAX_RX_QUEUES, 0, rxq_descr_info, VMXNET3_DEVICE_MAX_RX_QUEUES, 0, vmstate_vmxnet3_rxq_descr,
Vmxnet3RxqDescr), Vmxnet3RxqDescr),
VMSTATE_ARRAY(interrupt_states, VMXNET3State, VMXNET3_MAX_INTRS, VMSTATE_STRUCT_ARRAY(interrupt_states, VMXNET3State,
0, int_state_info, Vmxnet3IntState), VMXNET3_MAX_INTRS, 0, vmstate_vmxnet3_int_state,
Vmxnet3IntState),
VMSTATE_END_OF_LIST() VMSTATE_END_OF_LIST()
}, },

View File

@ -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, eth_strip_vlan(const struct iovec *iov, int iovcnt, size_t iovoff,
uint8_t *new_ehdr_buf, uint8_t *new_ehdr_buf,
uint16_t *payload_offset, uint16_t *tci); uint16_t *payload_offset, uint16_t *tci);
bool size_t
eth_strip_vlan_ex(const struct iovec *iov, int iovcnt, size_t iovoff, eth_strip_vlan_ex(const struct iovec *iov, int iovcnt, size_t iovoff,
uint16_t vet, uint8_t *new_ehdr_buf, uint16_t vet, uint8_t *new_ehdr_buf,
uint16_t *payload_offset, uint16_t *tci); uint16_t *payload_offset, uint16_t *tci);

View File

@ -83,9 +83,9 @@ typedef struct CompareState {
GHashTable *connection_track_table; GHashTable *connection_track_table;
/* compare thread, a thread for each NIC */ /* compare thread, a thread for each NIC */
QemuThread thread; QemuThread thread;
/* Timer used on the primary to find packets that are never matched */
QEMUTimer *timer; GMainContext *worker_context;
QemuMutex timer_check_lock; GMainLoop *compare_loop;
} CompareState; } CompareState;
typedef struct CompareClass { typedef struct CompareClass {
@ -180,7 +180,7 @@ static int packet_enqueue(CompareState *s, int mode)
* return: 0 means packet same * return: 0 means packet same
* > 0 || < 0 means packet different * > 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), trace_colo_compare_ip_info(ppkt->size, inet_ntoa(ppkt->ip->ip_src),
inet_ntoa(ppkt->ip->ip_dst), spkt->size, 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)); inet_ntoa(spkt->ip->ip_dst));
if (ppkt->size == spkt->size) { 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 { } else {
trace_colo_compare_main("Net packet size are not the same");
return -1; return -1;
} }
} }
@ -205,12 +207,6 @@ static int colo_packet_compare_tcp(Packet *spkt, Packet *ppkt)
int res; int res;
trace_colo_compare_main("compare tcp"); 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; ptcp = (struct tcphdr *)ppkt->transport_header;
stcp = (struct tcphdr *)spkt->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; spkt->ip->ip_sum = ppkt->ip->ip_sum;
} }
res = memcmp(ppkt->data + ETH_HLEN, spkt->data + ETH_HLEN, if (ptcp->th_sum == stcp->th_sum) {
(spkt->size - ETH_HLEN)); res = colo_packet_compare_common(ppkt, spkt, ETH_HLEN);
} else {
res = -1;
}
if (res != 0 && trace_event_get_state(TRACE_COLO_COMPARE_MISCOMPARE)) { if (res != 0 && trace_event_get_state(TRACE_COLO_COMPARE_MISCOMPARE)) {
trace_colo_compare_pkt_info_src(inet_ntoa(ppkt->ip->ip_src), 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) static int colo_packet_compare_udp(Packet *spkt, Packet *ppkt)
{ {
int ret; int ret;
int network_header_length = ppkt->ip->ip_hl * 4;
trace_colo_compare_main("compare udp"); 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) { if (ret) {
trace_colo_compare_udp_miscompare("primary pkt size", ppkt->size); 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); 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; 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) 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"); 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", trace_colo_compare_icmp_miscompare("primary pkt size",
ppkt->size); ppkt->size);
qemu_hexdump((char *)ppkt->data, stderr, "colo-compare",
ppkt->size);
trace_colo_compare_icmp_miscompare("Secondary pkt size", trace_colo_compare_icmp_miscompare("Secondary pkt size",
spkt->size); spkt->size);
qemu_hexdump((char *)spkt->data, stderr, "colo-compare", 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); spkt->size);
}
return -1; return -1;
} else { } else {
return 0; 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(ppkt->ip->ip_dst), spkt->size,
inet_ntoa(spkt->ip->ip_src), inet_ntoa(spkt->ip->ip_src),
inet_ntoa(spkt->ip->ip_dst)); 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) 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) && while (!g_queue_is_empty(&conn->primary_list) &&
!g_queue_is_empty(&conn->secondary_list)) { !g_queue_is_empty(&conn->secondary_list)) {
qemu_mutex_lock(&s->timer_check_lock);
pkt = g_queue_pop_tail(&conn->primary_list); pkt = g_queue_pop_tail(&conn->primary_list);
qemu_mutex_unlock(&s->timer_check_lock);
switch (conn->ip_proto) { switch (conn->ip_proto) {
case IPPROTO_TCP: case IPPROTO_TCP:
result = g_queue_find_custom(&conn->secondary_list, 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. * until next comparison.
*/ */
trace_colo_compare_main("packet different"); trace_colo_compare_main("packet different");
qemu_mutex_lock(&s->timer_check_lock);
g_queue_push_tail(&conn->primary_list, pkt); g_queue_push_tail(&conn->primary_list, pkt);
qemu_mutex_unlock(&s->timer_check_lock);
/* TODO: colo_notify_checkpoint();*/ /* TODO: colo_notify_checkpoint();*/
break; 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; 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, 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, 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_loop_run(s->compare_loop);
g_main_context_unref(worker_context);
g_source_unref(timeout_source);
g_main_loop_unref(s->compare_loop);
g_main_context_unref(s->worker_context);
return NULL; return NULL;
} }
@ -603,26 +643,6 @@ static int find_and_check_chardev(Chardev **chr,
return 0; 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 * Called from the main thread on the primary
* to setup colo-compare. * 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); net_socket_rs_init(&s->sec_rs, compare_sec_rs_finalize);
g_queue_init(&s->conn_list); 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, s->connection_track_table = g_hash_table_new_full(connection_key_hash,
connection_key_equal, connection_key_equal,
@ -678,15 +697,26 @@ static void colo_compare_complete(UserCreatable *uc, Error **errp)
QEMU_THREAD_JOINABLE); QEMU_THREAD_JOINABLE);
compare_id++; 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; 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) static void colo_compare_class_init(ObjectClass *oc, void *data)
{ {
UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
@ -711,24 +741,21 @@ static void colo_compare_finalize(Object *obj)
{ {
CompareState *s = COLO_COMPARE(obj); CompareState *s = COLO_COMPARE(obj);
qemu_chr_fe_deinit(&s->chr_pri_in); qemu_chr_fe_set_handlers(&s->chr_pri_in, NULL, NULL, NULL, NULL,
qemu_chr_fe_deinit(&s->chr_sec_in); 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); qemu_chr_fe_deinit(&s->chr_out);
g_queue_free(&s->conn_list); g_main_loop_quit(s->compare_loop);
if (qemu_thread_is_self(&s->thread)) {
/* compare connection */
g_queue_foreach(&s->conn_list, colo_compare_connection, s);
qemu_thread_join(&s->thread); qemu_thread_join(&s->thread);
}
if (s->timer) { /* Release all unhandled packets after compare thead exited */
timer_del(s->timer); g_queue_foreach(&s->conn_list, colo_flush_packets, s);
}
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->pri_indev);
g_free(s->sec_indev); g_free(s->sec_indev);
g_free(s->outdev); g_free(s->outdev);

View File

@ -147,9 +147,9 @@ void connection_destroy(void *opaque)
Connection *conn = opaque; Connection *conn = opaque;
g_queue_foreach(&conn->primary_list, packet_destroy, NULL); 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_foreach(&conn->secondary_list, packet_destroy, NULL);
g_queue_free(&conn->secondary_list); g_queue_clear(&conn->secondary_list);
g_slice_free(Connection, conn); g_slice_free(Connection, conn);
} }

View File

@ -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, eth_strip_vlan(const struct iovec *iov, int iovcnt, size_t iovoff,
uint8_t *new_ehdr_buf, uint8_t *new_ehdr_buf,
uint16_t *payload_offset, uint16_t *tci) 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)); new_ehdr, sizeof(*new_ehdr));
if (copied < sizeof(*new_ehdr)) { if (copied < sizeof(*new_ehdr)) {
return false; return 0;
} }
switch (be16_to_cpu(new_ehdr->h_proto)) { 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)); &vlan_hdr, sizeof(vlan_hdr));
if (copied < sizeof(vlan_hdr)) { if (copied < sizeof(vlan_hdr)) {
return false; return 0;
} }
new_ehdr->h_proto = vlan_hdr.h_proto; 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)); PKT_GET_VLAN_HDR(new_ehdr), sizeof(vlan_hdr));
if (copied < sizeof(vlan_hdr)) { if (copied < sizeof(vlan_hdr)) {
return false; return 0;
} }
*payload_offset += sizeof(vlan_hdr); *payload_offset += sizeof(vlan_hdr);
return sizeof(struct eth_header) + sizeof(struct vlan_header);
} else {
return sizeof(struct eth_header);
} }
return true;
default: default:
return false; return 0;
} }
} }
bool size_t
eth_strip_vlan_ex(const struct iovec *iov, int iovcnt, size_t iovoff, eth_strip_vlan_ex(const struct iovec *iov, int iovcnt, size_t iovoff,
uint16_t vet, uint8_t *new_ehdr_buf, uint16_t vet, uint8_t *new_ehdr_buf,
uint16_t *payload_offset, uint16_t *tci) 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)); new_ehdr, sizeof(*new_ehdr));
if (copied < sizeof(*new_ehdr)) { if (copied < sizeof(*new_ehdr)) {
return false; return 0;
} }
if (be16_to_cpu(new_ehdr->h_proto) == vet) { 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)); &vlan_hdr, sizeof(vlan_hdr));
if (copied < sizeof(vlan_hdr)) { if (copied < sizeof(vlan_hdr)) {
return false; return 0;
} }
new_ehdr->h_proto = vlan_hdr.h_proto; new_ehdr->h_proto = vlan_hdr.h_proto;
*tci = be16_to_cpu(vlan_hdr.h_tci); *tci = be16_to_cpu(vlan_hdr.h_tci);
*payload_offset = iovoff + sizeof(*new_ehdr) + sizeof(vlan_hdr); *payload_offset = iovoff + sizeof(*new_ehdr) + sizeof(vlan_hdr);
return true; return sizeof(struct eth_header);
} }
return false; return 0;
} }
void void

View File

@ -77,8 +77,9 @@ err:
return ret < 0 ? ret : -EIO; return ret < 0 ? ret : -EIO;
} }
static void static void redirector_to_filter(NetFilterState *nf,
redirector_to_filter(NetFilterState *nf, const uint8_t *buf, int len) const uint8_t *buf,
int len)
{ {
struct iovec iov = { struct iovec iov = {
.iov_base = (void *)buf, .iov_base = (void *)buf,

View File

@ -93,11 +93,13 @@ static int handle_primary_tcp_pkt(NetFilterState *nf,
conn->offset -= (ntohl(tcp_pkt->th_ack) - 1); conn->offset -= (ntohl(tcp_pkt->th_ack) - 1);
conn->syn_flag = 0; conn->syn_flag = 0;
} }
if (conn->offset) {
/* handle packets to the secondary from the primary */ /* handle packets to the secondary from the primary */
tcp_pkt->th_ack = htonl(ntohl(tcp_pkt->th_ack) + conn->offset); 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; return 0;
} }
@ -129,11 +131,14 @@ static int handle_secondary_tcp_pkt(NetFilterState *nf,
} }
if ((tcp_pkt->th_flags & (TH_ACK | TH_SYN)) == TH_ACK) { if ((tcp_pkt->th_flags & (TH_ACK | TH_SYN)) == TH_ACK) {
/* Only need to adjust seq while offset is Non-zero */
if (conn->offset) {
/* handle packets to the primary from the secondary*/ /* handle packets to the primary from the secondary*/
tcp_pkt->th_seq = htonl(ntohl(tcp_pkt->th_seq) - conn->offset); 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; return 0;
} }