[dpdk-dev,2/4] vhost: complete TSO settings
Commit Message
Commit d0cf91303d73 ("vhost: add Tx offload capabilities") has only
done partial settings for enabling TSO, and left the following part
to the application, say vhost-switch example, by commit 9fd72e3cbd29
("examples/vhost: add virtio offload").
- Setting PKT_TX_IP_CKSUM and ipv4_hdr->hdr_checksum = 0 for IPv4.
- calculate the pseudo header checksum without taking ip_len in
account, and set it in the TCP header
Here we complete the left part in vhost side, so that an user (such
as OVS) can do minimal (or even no) changes to get TSO enabled.
Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
---
lib/librte_vhost/vhost_rxtx.c | 47 ++++++++++++++++++++++++++++++++-----------
1 file changed, 35 insertions(+), 12 deletions(-)
Comments
On Fri, Mar 25, 2016 at 02:01:32PM +0800, Yuanhan Liu wrote:
> Commit d0cf91303d73 ("vhost: add Tx offload capabilities") has only
> done partial settings for enabling TSO, and left the following part
> to the application, say vhost-switch example, by commit 9fd72e3cbd29
> ("examples/vhost: add virtio offload").
>
> - Setting PKT_TX_IP_CKSUM and ipv4_hdr->hdr_checksum = 0 for IPv4.
>
> - calculate the pseudo header checksum without taking ip_len in
> account, and set it in the TCP header
>
> Here we complete the left part in vhost side, so that an user (such
> as OVS) can do minimal (or even no) changes to get TSO enabled.
>
> Signed-off-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
...
> + ipv4_hdr->hdr_checksum = 0;
Nah.. we can't do that here. This hurts VM2VM case badly.
Thanks Qian for letting me be aware of it.
--yliu
@@ -602,11 +602,11 @@ rte_vhost_enqueue_burst(struct virtio_net *dev, uint16_t queue_id,
}
static void
-parse_ethernet(struct rte_mbuf *m, uint16_t *l4_proto, void **l4_hdr)
+parse_ethernet(struct rte_mbuf *m, void **l3_hdr,
+ void **l4_hdr, uint16_t *l4_proto)
{
struct ipv4_hdr *ipv4_hdr;
struct ipv6_hdr *ipv6_hdr;
- void *l3_hdr = NULL;
struct ether_hdr *eth_hdr;
uint16_t ethertype;
@@ -622,21 +622,19 @@ parse_ethernet(struct rte_mbuf *m, uint16_t *l4_proto, void **l4_hdr)
ethertype = rte_be_to_cpu_16(vlan_hdr->eth_proto);
}
- l3_hdr = (char *)eth_hdr + m->l2_len;
+ *l3_hdr = (char *)eth_hdr + m->l2_len;
switch (ethertype) {
case ETHER_TYPE_IPv4:
- ipv4_hdr = (struct ipv4_hdr *)l3_hdr;
+ ipv4_hdr = *l3_hdr;
*l4_proto = ipv4_hdr->next_proto_id;
m->l3_len = (ipv4_hdr->version_ihl & 0x0f) * 4;
- *l4_hdr = (char *)l3_hdr + m->l3_len;
m->ol_flags |= PKT_TX_IPV4;
break;
case ETHER_TYPE_IPv6:
- ipv6_hdr = (struct ipv6_hdr *)l3_hdr;
+ ipv6_hdr = *l3_hdr;
*l4_proto = ipv6_hdr->proto;
m->l3_len = sizeof(struct ipv6_hdr);
- *l4_hdr = (char *)l3_hdr + m->l3_len;
m->ol_flags |= PKT_TX_IPV6;
break;
default:
@@ -644,16 +642,28 @@ parse_ethernet(struct rte_mbuf *m, uint16_t *l4_proto, void **l4_hdr)
*l4_proto = 0;
break;
}
+
+ *l4_hdr = (char *)*l3_hdr + m->l3_len;
+}
+
+static uint16_t
+get_psd_sum(void *l3_hdr, uint64_t ol_flags)
+{
+ if (ol_flags & PKT_TX_IPV4)
+ return rte_ipv4_phdr_cksum(l3_hdr, ol_flags);
+ else
+ return rte_ipv6_phdr_cksum(l3_hdr, ol_flags);
}
static inline void __attribute__((always_inline))
vhost_dequeue_offload(struct virtio_net_hdr *hdr, struct rte_mbuf *m)
{
- uint16_t l4_proto = 0;
- void *l4_hdr = NULL;
- struct tcp_hdr *tcp_hdr = NULL;
+ void *l3_hdr;
+ void *l4_hdr;
+ uint16_t l4_proto;
+
+ parse_ethernet(m, &l3_hdr, &l4_hdr, &l4_proto);
- parse_ethernet(m, &l4_proto, &l4_hdr);
if (hdr->flags == VIRTIO_NET_HDR_F_NEEDS_CSUM) {
if (hdr->csum_start == (m->l2_len + m->l3_len)) {
switch (hdr->csum_offset) {
@@ -676,13 +686,26 @@ vhost_dequeue_offload(struct virtio_net_hdr *hdr, struct rte_mbuf *m)
}
if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) {
+ struct ipv4_hdr *ipv4_hdr = l3_hdr;
+ struct tcp_hdr *tcp_hdr = l4_hdr;
+
switch (hdr->gso_type & ~VIRTIO_NET_HDR_GSO_ECN) {
case VIRTIO_NET_HDR_GSO_TCPV4:
+ /*
+ * According to comments for PKT_TX_TCP_SEG
+ * at rte_mbuf.h, we need following settings
+ * for IPv4.
+ */
+ m->ol_flags |= PKT_TX_IP_CKSUM;
+ ipv4_hdr->hdr_checksum = 0;
+
+ /* Fall through */
case VIRTIO_NET_HDR_GSO_TCPV6:
- tcp_hdr = (struct tcp_hdr *)l4_hdr;
m->ol_flags |= PKT_TX_TCP_SEG;
m->tso_segsz = hdr->gso_size;
m->l4_len = (tcp_hdr->data_off & 0xf0) >> 2;
+
+ tcp_hdr->cksum = get_psd_sum(l3_hdr, m->ol_flags);
break;
default:
RTE_LOG(WARNING, VHOST_DATA,