Re: [Qemu-devel] [ RFC Patch v4 3/3] virtio-net rsc: support coalescing ipv6 tcp traffic

2016-04-08 Thread Wei Xu



On 2016年04月08日 15:27, Jason Wang wrote:


On 04/08/2016 03:06 PM, Wei Xu wrote:


On 2016年04月05日 10:50, Jason Wang wrote:

On 04/04/2016 03:25 AM, w...@redhat.com wrote:

From: Wei Xu 

Most things like ipv4 except there is a significant difference
between ipv4
and ipv6, the fragment lenght in ipv4 header includes itself, while
it's not

typo

Thanks.

included for ipv6, thus means ipv6 can carry a real '65535' payload.

Signed-off-by: Wei Xu 
---
   hw/net/virtio-net.c | 147
+---
   1 file changed, 141 insertions(+), 6 deletions(-)

diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 81e8e71..2d09352 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -50,6 +50,10 @@
   /* header lenght value in ip header without option */
   #define VIRTIO_NET_IP4_HEADER_LENGTH 5
   +#define ETH_IP6_HDR_SZ (ETH_HDR_SZ + IP6_HDR_SZ)
+#define VIRTIO_NET_IP6_ADDR_SIZE   32  /* ipv6 saddr + daddr */
+#define VIRTIO_NET_MAX_IP6_PAYLOAD VIRTIO_NET_MAX_TCP_PAYLOAD
+
   /* Purge coalesced packets timer interval */
   #define VIRTIO_NET_RSC_INTERVAL  30
   @@ -1725,6 +1729,25 @@ static void
virtio_net_rsc_extract_unit4(NetRscChain *chain,
   unit->payload = htons(*unit->ip_plen) - ip_hdrlen -
unit->tcp_hdrlen;
   }
   +static void virtio_net_rsc_extract_unit6(NetRscChain *chain,
+ const uint8_t *buf,
NetRscUnit* unit)
+{
+uint16_t hdr_len;
+struct ip6_header *ip6;
+
+hdr_len = ((VirtIONet *)(chain->n))->guest_hdr_len;
+ip6 = (struct ip6_header *)(buf + hdr_len + sizeof(struct
eth_header));
+unit->ip = ip6;
+unit->ip_plen = &(ip6->ip6_ctlun.ip6_un1.ip6_un1_plen);
+unit->tcp = (struct tcp_header *)(((uint8_t *)unit->ip)\
++ sizeof(struct ip6_header));
+unit->tcp_hdrlen = (htons(unit->tcp->th_offset_flags) & 0xF000)

10;

+
+/* There is a difference between payload lenght in ipv4 and v6,
+   ip header is excluded in ipv6 */
+unit->payload = htons(*unit->ip_plen) - unit->tcp_hdrlen;
+}
+
   static void virtio_net_rsc_ipv4_checksum(struct ip_header *ip)
   {
   uint32_t sum;
@@ -1738,7 +1761,9 @@ static size_t
virtio_net_rsc_drain_seg(NetRscChain *chain, NetRscSeg *seg)
   {
   int ret;
   -virtio_net_rsc_ipv4_checksum(seg->unit.ip);
+if ((chain->proto == ETH_P_IP) && seg->is_coalesced) {
+virtio_net_rsc_ipv4_checksum(seg->unit.ip);
+}

Why not introduce proto specific checksum function for chain?

Since there are only 2 protocols to be supported, and very limited
extension for this feature, mst suggest to use direct call in v2 patch
to make things simple, and i took it.

Have you tried with my suggestion? I think it will actually simplify the
current code (at least several lines of codes).

ok, will give it a try.




Re: [Qemu-devel] [ RFC Patch v4 3/3] virtio-net rsc: support coalescing ipv6 tcp traffic

2016-04-08 Thread Jason Wang


On 04/08/2016 03:06 PM, Wei Xu wrote:
>
>
> On 2016年04月05日 10:50, Jason Wang wrote:
>>
>> On 04/04/2016 03:25 AM, w...@redhat.com wrote:
>>> From: Wei Xu 
>>>
>>> Most things like ipv4 except there is a significant difference
>>> between ipv4
>>> and ipv6, the fragment lenght in ipv4 header includes itself, while
>>> it's not
>> typo
> Thanks.
>>
>>> included for ipv6, thus means ipv6 can carry a real '65535' payload.
>>>
>>> Signed-off-by: Wei Xu 
>>> ---
>>>   hw/net/virtio-net.c | 147
>>> +---
>>>   1 file changed, 141 insertions(+), 6 deletions(-)
>>>
>>> diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
>>> index 81e8e71..2d09352 100644
>>> --- a/hw/net/virtio-net.c
>>> +++ b/hw/net/virtio-net.c
>>> @@ -50,6 +50,10 @@
>>>   /* header lenght value in ip header without option */
>>>   #define VIRTIO_NET_IP4_HEADER_LENGTH 5
>>>   +#define ETH_IP6_HDR_SZ (ETH_HDR_SZ + IP6_HDR_SZ)
>>> +#define VIRTIO_NET_IP6_ADDR_SIZE   32  /* ipv6 saddr + daddr */
>>> +#define VIRTIO_NET_MAX_IP6_PAYLOAD VIRTIO_NET_MAX_TCP_PAYLOAD
>>> +
>>>   /* Purge coalesced packets timer interval */
>>>   #define VIRTIO_NET_RSC_INTERVAL  30
>>>   @@ -1725,6 +1729,25 @@ static void
>>> virtio_net_rsc_extract_unit4(NetRscChain *chain,
>>>   unit->payload = htons(*unit->ip_plen) - ip_hdrlen -
>>> unit->tcp_hdrlen;
>>>   }
>>>   +static void virtio_net_rsc_extract_unit6(NetRscChain *chain,
>>> + const uint8_t *buf,
>>> NetRscUnit* unit)
>>> +{
>>> +uint16_t hdr_len;
>>> +struct ip6_header *ip6;
>>> +
>>> +hdr_len = ((VirtIONet *)(chain->n))->guest_hdr_len;
>>> +ip6 = (struct ip6_header *)(buf + hdr_len + sizeof(struct
>>> eth_header));
>>> +unit->ip = ip6;
>>> +unit->ip_plen = &(ip6->ip6_ctlun.ip6_un1.ip6_un1_plen);
>>> +unit->tcp = (struct tcp_header *)(((uint8_t *)unit->ip)\
>>> ++ sizeof(struct ip6_header));
>>> +unit->tcp_hdrlen = (htons(unit->tcp->th_offset_flags) & 0xF000)
>>> >> 10;
>>> +
>>> +/* There is a difference between payload lenght in ipv4 and v6,
>>> +   ip header is excluded in ipv6 */
>>> +unit->payload = htons(*unit->ip_plen) - unit->tcp_hdrlen;
>>> +}
>>> +
>>>   static void virtio_net_rsc_ipv4_checksum(struct ip_header *ip)
>>>   {
>>>   uint32_t sum;
>>> @@ -1738,7 +1761,9 @@ static size_t
>>> virtio_net_rsc_drain_seg(NetRscChain *chain, NetRscSeg *seg)
>>>   {
>>>   int ret;
>>>   -virtio_net_rsc_ipv4_checksum(seg->unit.ip);
>>> +if ((chain->proto == ETH_P_IP) && seg->is_coalesced) {
>>> +virtio_net_rsc_ipv4_checksum(seg->unit.ip);
>>> +}
>> Why not introduce proto specific checksum function for chain?
> Since there are only 2 protocols to be supported, and very limited
> extension for this feature, mst suggest to use direct call in v2 patch
> to make things simple, and i took it.

Have you tried with my suggestion? I think it will actually simplify the
current code (at least several lines of codes).



Re: [Qemu-devel] [ RFC Patch v4 3/3] virtio-net rsc: support coalescing ipv6 tcp traffic

2016-04-08 Thread Wei Xu



On 2016年04月05日 10:50, Jason Wang wrote:


On 04/04/2016 03:25 AM, w...@redhat.com wrote:

From: Wei Xu 

Most things like ipv4 except there is a significant difference between ipv4
and ipv6, the fragment lenght in ipv4 header includes itself, while it's not

typo

Thanks.



included for ipv6, thus means ipv6 can carry a real '65535' payload.

Signed-off-by: Wei Xu 
---
  hw/net/virtio-net.c | 147 +---
  1 file changed, 141 insertions(+), 6 deletions(-)

diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 81e8e71..2d09352 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -50,6 +50,10 @@
  /* header lenght value in ip header without option */
  #define VIRTIO_NET_IP4_HEADER_LENGTH 5
  
+#define ETH_IP6_HDR_SZ (ETH_HDR_SZ + IP6_HDR_SZ)

+#define VIRTIO_NET_IP6_ADDR_SIZE   32  /* ipv6 saddr + daddr */
+#define VIRTIO_NET_MAX_IP6_PAYLOAD VIRTIO_NET_MAX_TCP_PAYLOAD
+
  /* Purge coalesced packets timer interval */
  #define VIRTIO_NET_RSC_INTERVAL  30
  
@@ -1725,6 +1729,25 @@ static void virtio_net_rsc_extract_unit4(NetRscChain *chain,

  unit->payload = htons(*unit->ip_plen) - ip_hdrlen - unit->tcp_hdrlen;
  }
  
+static void virtio_net_rsc_extract_unit6(NetRscChain *chain,

+ const uint8_t *buf, NetRscUnit* unit)
+{
+uint16_t hdr_len;
+struct ip6_header *ip6;
+
+hdr_len = ((VirtIONet *)(chain->n))->guest_hdr_len;
+ip6 = (struct ip6_header *)(buf + hdr_len + sizeof(struct eth_header));
+unit->ip = ip6;
+unit->ip_plen = &(ip6->ip6_ctlun.ip6_un1.ip6_un1_plen);
+unit->tcp = (struct tcp_header *)(((uint8_t *)unit->ip)\
++ sizeof(struct ip6_header));
+unit->tcp_hdrlen = (htons(unit->tcp->th_offset_flags) & 0xF000) >> 10;
+
+/* There is a difference between payload lenght in ipv4 and v6,
+   ip header is excluded in ipv6 */
+unit->payload = htons(*unit->ip_plen) - unit->tcp_hdrlen;
+}
+
  static void virtio_net_rsc_ipv4_checksum(struct ip_header *ip)
  {
  uint32_t sum;
@@ -1738,7 +1761,9 @@ static size_t virtio_net_rsc_drain_seg(NetRscChain 
*chain, NetRscSeg *seg)
  {
  int ret;
  
-virtio_net_rsc_ipv4_checksum(seg->unit.ip);

+if ((chain->proto == ETH_P_IP) && seg->is_coalesced) {
+virtio_net_rsc_ipv4_checksum(seg->unit.ip);
+}

Why not introduce proto specific checksum function for chain?
Since there are only 2 protocols to be supported, and very limited 
extension for this feature, mst suggest to use direct call in v2 patch

to make things simple, and i took it.



  ret = virtio_net_do_receive(seg->nc, seg->buf, seg->size);
  QTAILQ_REMOVE(>buffers, seg, next);
  g_free(seg->buf);
@@ -1804,7 +1829,18 @@ static void virtio_net_rsc_cache_buf(NetRscChain *chain, 
NetClientState *nc,
  QTAILQ_INSERT_TAIL(>buffers, seg, next);
  chain->stat.cache++;
  
-virtio_net_rsc_extract_unit4(chain, seg->buf, >unit);

+switch (chain->proto) {
+case ETH_P_IP:
+virtio_net_rsc_extract_unit4(chain, seg->buf, >unit);

Another call for proto specific callbacks maybe?

Same as above.



+break;
+
+case ETH_P_IPV6:
+virtio_net_rsc_extract_unit6(chain, seg->buf, >unit);
+break;
+
+default:
+g_assert_not_reached();
+}
  }
  
  static int32_t virtio_net_rsc_handle_ack(NetRscChain *chain, NetRscSeg *seg,

@@ -1948,6 +1984,24 @@ static int32_t virtio_net_rsc_coalesce4(NetRscChain 
*chain, NetRscSeg *seg,
  return virtio_net_rsc_coalesce_data(chain, seg, buf, unit);
  }
  
+static int32_t virtio_net_rsc_coalesce6(NetRscChain *chain, NetRscSeg *seg,

+const uint8_t *buf, size_t size, NetRscUnit *unit)
+{
+struct ip6_header *ip1, *ip2;
+
+ip1 = (struct ip6_header *)(unit->ip);
+ip2 = (struct ip6_header *)(seg->unit.ip);
+if (memcmp(>ip6_src, >ip6_src, sizeof(struct in6_address))
+|| memcmp(>ip6_dst, >ip6_dst, sizeof(struct in6_address))
+|| (unit->tcp->th_sport ^ seg->unit.tcp->th_sport)
+|| (unit->tcp->th_dport ^ seg->unit.tcp->th_dport)) {
+chain->stat.no_match++;
+return RSC_NO_MATCH;
+}
+
+return virtio_net_rsc_coalesce_data(chain, seg, buf, unit);
+}
+
  /* Pakcets with 'SYN' should bypass, other flag should be sent after drain
   * to prevent out of order */
  static int virtio_net_rsc_tcp_ctrl_check(NetRscChain *chain,
@@ -1991,7 +2045,11 @@ static size_t virtio_net_rsc_do_coalesce(NetRscChain 
*chain, NetClientState *nc,
  NetRscSeg *seg, *nseg;
  
  QTAILQ_FOREACH_SAFE(seg, >buffers, next, nseg) {

-ret = virtio_net_rsc_coalesce4(chain, seg, buf, size, unit);
+if (chain->proto == ETH_P_IP) {
+ret = virtio_net_rsc_coalesce4(chain, seg, buf, size, unit);
+} else {
+ret = virtio_net_rsc_coalesce6(chain, seg, buf, size, unit);

Ditto.


Re: [Qemu-devel] [ RFC Patch v4 3/3] virtio-net rsc: support coalescing ipv6 tcp traffic

2016-04-04 Thread Jason Wang


On 04/04/2016 03:25 AM, w...@redhat.com wrote:
> From: Wei Xu 
>
> Most things like ipv4 except there is a significant difference between ipv4
> and ipv6, the fragment lenght in ipv4 header includes itself, while it's not

typo

> included for ipv6, thus means ipv6 can carry a real '65535' payload.
>
> Signed-off-by: Wei Xu 
> ---
>  hw/net/virtio-net.c | 147 
> +---
>  1 file changed, 141 insertions(+), 6 deletions(-)
>
> diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
> index 81e8e71..2d09352 100644
> --- a/hw/net/virtio-net.c
> +++ b/hw/net/virtio-net.c
> @@ -50,6 +50,10 @@
>  /* header lenght value in ip header without option */
>  #define VIRTIO_NET_IP4_HEADER_LENGTH 5
>  
> +#define ETH_IP6_HDR_SZ (ETH_HDR_SZ + IP6_HDR_SZ)
> +#define VIRTIO_NET_IP6_ADDR_SIZE   32  /* ipv6 saddr + daddr */
> +#define VIRTIO_NET_MAX_IP6_PAYLOAD VIRTIO_NET_MAX_TCP_PAYLOAD
> +
>  /* Purge coalesced packets timer interval */
>  #define VIRTIO_NET_RSC_INTERVAL  30
>  
> @@ -1725,6 +1729,25 @@ static void virtio_net_rsc_extract_unit4(NetRscChain 
> *chain,
>  unit->payload = htons(*unit->ip_plen) - ip_hdrlen - unit->tcp_hdrlen;
>  }
>  
> +static void virtio_net_rsc_extract_unit6(NetRscChain *chain,
> + const uint8_t *buf, NetRscUnit* 
> unit)
> +{
> +uint16_t hdr_len;
> +struct ip6_header *ip6;
> +
> +hdr_len = ((VirtIONet *)(chain->n))->guest_hdr_len;
> +ip6 = (struct ip6_header *)(buf + hdr_len + sizeof(struct eth_header));
> +unit->ip = ip6;
> +unit->ip_plen = &(ip6->ip6_ctlun.ip6_un1.ip6_un1_plen);
> +unit->tcp = (struct tcp_header *)(((uint8_t *)unit->ip)\
> ++ sizeof(struct ip6_header));
> +unit->tcp_hdrlen = (htons(unit->tcp->th_offset_flags) & 0xF000) >> 10;
> +
> +/* There is a difference between payload lenght in ipv4 and v6,
> +   ip header is excluded in ipv6 */
> +unit->payload = htons(*unit->ip_plen) - unit->tcp_hdrlen;
> +}
> +
>  static void virtio_net_rsc_ipv4_checksum(struct ip_header *ip)
>  {
>  uint32_t sum;
> @@ -1738,7 +1761,9 @@ static size_t virtio_net_rsc_drain_seg(NetRscChain 
> *chain, NetRscSeg *seg)
>  {
>  int ret;
>  
> -virtio_net_rsc_ipv4_checksum(seg->unit.ip);
> +if ((chain->proto == ETH_P_IP) && seg->is_coalesced) {
> +virtio_net_rsc_ipv4_checksum(seg->unit.ip);
> +}

Why not introduce proto specific checksum function for chain?

>  ret = virtio_net_do_receive(seg->nc, seg->buf, seg->size);
>  QTAILQ_REMOVE(>buffers, seg, next);
>  g_free(seg->buf);
> @@ -1804,7 +1829,18 @@ static void virtio_net_rsc_cache_buf(NetRscChain 
> *chain, NetClientState *nc,
>  QTAILQ_INSERT_TAIL(>buffers, seg, next);
>  chain->stat.cache++;
>  
> -virtio_net_rsc_extract_unit4(chain, seg->buf, >unit);
> +switch (chain->proto) {
> +case ETH_P_IP:
> +virtio_net_rsc_extract_unit4(chain, seg->buf, >unit);

Another call for proto specific callbacks maybe?

> +break;
> +
> +case ETH_P_IPV6:
> +virtio_net_rsc_extract_unit6(chain, seg->buf, >unit);
> +break;
> +
> +default:
> +g_assert_not_reached();
> +}
>  }
>  
>  static int32_t virtio_net_rsc_handle_ack(NetRscChain *chain, NetRscSeg *seg,
> @@ -1948,6 +1984,24 @@ static int32_t virtio_net_rsc_coalesce4(NetRscChain 
> *chain, NetRscSeg *seg,
>  return virtio_net_rsc_coalesce_data(chain, seg, buf, unit);
>  }
>  
> +static int32_t virtio_net_rsc_coalesce6(NetRscChain *chain, NetRscSeg *seg,
> +const uint8_t *buf, size_t size, NetRscUnit *unit)
> +{
> +struct ip6_header *ip1, *ip2;
> +
> +ip1 = (struct ip6_header *)(unit->ip);
> +ip2 = (struct ip6_header *)(seg->unit.ip);
> +if (memcmp(>ip6_src, >ip6_src, sizeof(struct in6_address))
> +|| memcmp(>ip6_dst, >ip6_dst, sizeof(struct in6_address))
> +|| (unit->tcp->th_sport ^ seg->unit.tcp->th_sport)
> +|| (unit->tcp->th_dport ^ seg->unit.tcp->th_dport)) {
> +chain->stat.no_match++;
> +return RSC_NO_MATCH;
> +}
> +
> +return virtio_net_rsc_coalesce_data(chain, seg, buf, unit);
> +}
> +
>  /* Pakcets with 'SYN' should bypass, other flag should be sent after drain
>   * to prevent out of order */
>  static int virtio_net_rsc_tcp_ctrl_check(NetRscChain *chain,
> @@ -1991,7 +2045,11 @@ static size_t virtio_net_rsc_do_coalesce(NetRscChain 
> *chain, NetClientState *nc,
>  NetRscSeg *seg, *nseg;
>  
>  QTAILQ_FOREACH_SAFE(seg, >buffers, next, nseg) {
> -ret = virtio_net_rsc_coalesce4(chain, seg, buf, size, unit);
> +if (chain->proto == ETH_P_IP) {
> +ret = virtio_net_rsc_coalesce4(chain, seg, buf, size, unit);
> +} else {
> +ret = virtio_net_rsc_coalesce6(chain, seg, buf, size, unit);

Ditto.

> +}
>  
>  if (ret == 

[Qemu-devel] [ RFC Patch v4 3/3] virtio-net rsc: support coalescing ipv6 tcp traffic

2016-04-03 Thread wexu
From: Wei Xu 

Most things like ipv4 except there is a significant difference between ipv4
and ipv6, the fragment lenght in ipv4 header includes itself, while it's not
included for ipv6, thus means ipv6 can carry a real '65535' payload.

Signed-off-by: Wei Xu 
---
 hw/net/virtio-net.c | 147 +---
 1 file changed, 141 insertions(+), 6 deletions(-)

diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 81e8e71..2d09352 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -50,6 +50,10 @@
 /* header lenght value in ip header without option */
 #define VIRTIO_NET_IP4_HEADER_LENGTH 5
 
+#define ETH_IP6_HDR_SZ (ETH_HDR_SZ + IP6_HDR_SZ)
+#define VIRTIO_NET_IP6_ADDR_SIZE   32  /* ipv6 saddr + daddr */
+#define VIRTIO_NET_MAX_IP6_PAYLOAD VIRTIO_NET_MAX_TCP_PAYLOAD
+
 /* Purge coalesced packets timer interval */
 #define VIRTIO_NET_RSC_INTERVAL  30
 
@@ -1725,6 +1729,25 @@ static void virtio_net_rsc_extract_unit4(NetRscChain 
*chain,
 unit->payload = htons(*unit->ip_plen) - ip_hdrlen - unit->tcp_hdrlen;
 }
 
+static void virtio_net_rsc_extract_unit6(NetRscChain *chain,
+ const uint8_t *buf, NetRscUnit* unit)
+{
+uint16_t hdr_len;
+struct ip6_header *ip6;
+
+hdr_len = ((VirtIONet *)(chain->n))->guest_hdr_len;
+ip6 = (struct ip6_header *)(buf + hdr_len + sizeof(struct eth_header));
+unit->ip = ip6;
+unit->ip_plen = &(ip6->ip6_ctlun.ip6_un1.ip6_un1_plen);
+unit->tcp = (struct tcp_header *)(((uint8_t *)unit->ip)\
++ sizeof(struct ip6_header));
+unit->tcp_hdrlen = (htons(unit->tcp->th_offset_flags) & 0xF000) >> 10;
+
+/* There is a difference between payload lenght in ipv4 and v6,
+   ip header is excluded in ipv6 */
+unit->payload = htons(*unit->ip_plen) - unit->tcp_hdrlen;
+}
+
 static void virtio_net_rsc_ipv4_checksum(struct ip_header *ip)
 {
 uint32_t sum;
@@ -1738,7 +1761,9 @@ static size_t virtio_net_rsc_drain_seg(NetRscChain 
*chain, NetRscSeg *seg)
 {
 int ret;
 
-virtio_net_rsc_ipv4_checksum(seg->unit.ip);
+if ((chain->proto == ETH_P_IP) && seg->is_coalesced) {
+virtio_net_rsc_ipv4_checksum(seg->unit.ip);
+}
 ret = virtio_net_do_receive(seg->nc, seg->buf, seg->size);
 QTAILQ_REMOVE(>buffers, seg, next);
 g_free(seg->buf);
@@ -1804,7 +1829,18 @@ static void virtio_net_rsc_cache_buf(NetRscChain *chain, 
NetClientState *nc,
 QTAILQ_INSERT_TAIL(>buffers, seg, next);
 chain->stat.cache++;
 
-virtio_net_rsc_extract_unit4(chain, seg->buf, >unit);
+switch (chain->proto) {
+case ETH_P_IP:
+virtio_net_rsc_extract_unit4(chain, seg->buf, >unit);
+break;
+
+case ETH_P_IPV6:
+virtio_net_rsc_extract_unit6(chain, seg->buf, >unit);
+break;
+
+default:
+g_assert_not_reached();
+}
 }
 
 static int32_t virtio_net_rsc_handle_ack(NetRscChain *chain, NetRscSeg *seg,
@@ -1948,6 +1984,24 @@ static int32_t virtio_net_rsc_coalesce4(NetRscChain 
*chain, NetRscSeg *seg,
 return virtio_net_rsc_coalesce_data(chain, seg, buf, unit);
 }
 
+static int32_t virtio_net_rsc_coalesce6(NetRscChain *chain, NetRscSeg *seg,
+const uint8_t *buf, size_t size, NetRscUnit *unit)
+{
+struct ip6_header *ip1, *ip2;
+
+ip1 = (struct ip6_header *)(unit->ip);
+ip2 = (struct ip6_header *)(seg->unit.ip);
+if (memcmp(>ip6_src, >ip6_src, sizeof(struct in6_address))
+|| memcmp(>ip6_dst, >ip6_dst, sizeof(struct in6_address))
+|| (unit->tcp->th_sport ^ seg->unit.tcp->th_sport)
+|| (unit->tcp->th_dport ^ seg->unit.tcp->th_dport)) {
+chain->stat.no_match++;
+return RSC_NO_MATCH;
+}
+
+return virtio_net_rsc_coalesce_data(chain, seg, buf, unit);
+}
+
 /* Pakcets with 'SYN' should bypass, other flag should be sent after drain
  * to prevent out of order */
 static int virtio_net_rsc_tcp_ctrl_check(NetRscChain *chain,
@@ -1991,7 +2045,11 @@ static size_t virtio_net_rsc_do_coalesce(NetRscChain 
*chain, NetClientState *nc,
 NetRscSeg *seg, *nseg;
 
 QTAILQ_FOREACH_SAFE(seg, >buffers, next, nseg) {
-ret = virtio_net_rsc_coalesce4(chain, seg, buf, size, unit);
+if (chain->proto == ETH_P_IP) {
+ret = virtio_net_rsc_coalesce4(chain, seg, buf, size, unit);
+} else {
+ret = virtio_net_rsc_coalesce6(chain, seg, buf, size, unit);
+}
 
 if (ret == RSC_FINAL) {
 if (virtio_net_rsc_drain_seg(chain, seg) == 0) {
@@ -2116,13 +2174,82 @@ static size_t virtio_net_rsc_receive4(void *opq, 
NetClientState* nc,
 return virtio_net_rsc_do_coalesce(chain, nc, buf, size, );
 }
 
+static int32_t virtio_net_rsc_sanity_check6(NetRscChain *chain,
+struct ip6_header *ip6,
+const uint8_t *buf,