diff options
Diffstat (limited to 'tcp_vu.c')
| -rw-r--r-- | tcp_vu.c | 57 |
1 files changed, 32 insertions, 25 deletions
@@ -40,17 +40,16 @@ static struct vu_virtq_element elem[VIRTQUEUE_MAX_SIZE]; static int head[VIRTQUEUE_MAX_SIZE + 1]; /** - * tcp_vu_hdrlen() - return the size of the header in level 2 frame (TCP) + * tcp_vu_hdrlen() - Sum size of all headers, from TCP to virtio-net * @v6: Set for IPv6 packet * - * Return: return the size of the header + * Return: total size of virtio-net, Ethernet, IP, and TCP headers */ static size_t tcp_vu_hdrlen(bool v6) { size_t hdrlen; - hdrlen = sizeof(struct virtio_net_hdr_mrg_rxbuf) + - sizeof(struct ethhdr) + sizeof(struct tcphdr); + hdrlen = VNET_HLEN + sizeof(struct ethhdr) + sizeof(struct tcphdr); if (v6) hdrlen += sizeof(struct ipv6hdr); @@ -72,8 +71,8 @@ int tcp_vu_send_flag(const struct ctx *c, struct tcp_tap_conn *conn, int flags) { struct vu_dev *vdev = c->vdev; struct vu_virtq *vq = &vdev->vq[VHOST_USER_RX_QUEUE]; - size_t optlen, hdrlen; struct vu_virtq_element flags_elem[2]; + size_t optlen, hdrlen, l2len; struct ipv6hdr *ip6h = NULL; struct iphdr *ip4h = NULL; struct iovec flags_iov[2]; @@ -91,14 +90,14 @@ int tcp_vu_send_flag(const struct ctx *c, struct tcp_tap_conn *conn, int flags) vu_set_element(&flags_elem[0], NULL, &flags_iov[0]); elem_cnt = vu_collect(vdev, vq, &flags_elem[0], 1, - hdrlen + sizeof(struct tcp_syn_opts), NULL); + MAX(hdrlen + sizeof(*opts), ETH_ZLEN + VNET_HLEN), NULL); if (elem_cnt != 1) return -1; ASSERT(flags_elem[0].in_sg[0].iov_len >= - hdrlen + sizeof(struct tcp_syn_opts)); + MAX(hdrlen + sizeof(*opts), ETH_ZLEN + VNET_HLEN)); - vu_set_vnethdr(vdev, flags_elem[0].in_sg[0].iov_base, 1); + vu_set_vnethdr(flags_elem[0].in_sg[0].iov_base, 1); eh = vu_eth(flags_elem[0].in_sg[0].iov_base); @@ -135,13 +134,17 @@ int tcp_vu_send_flag(const struct ctx *c, struct tcp_tap_conn *conn, int flags) flags_elem[0].in_sg[0].iov_len = hdrlen + optlen; payload = IOV_TAIL(flags_elem[0].in_sg, 1, hdrlen); - tcp_fill_headers(c, conn, NULL, eh, ip4h, ip6h, th, &payload, + if (flags & KEEPALIVE) + seq--; + + tcp_fill_headers(c, conn, eh, ip4h, ip6h, th, &payload, NULL, seq, !*c->pcap); - if (*c->pcap) { - pcap_iov(&flags_elem[0].in_sg[0], 1, - sizeof(struct virtio_net_hdr_mrg_rxbuf)); - } + l2len = optlen + hdrlen - VNET_HLEN; + vu_pad(&flags_elem[0].in_sg[0], l2len); + + if (*c->pcap) + pcap_iov(&flags_elem[0].in_sg[0], 1, VNET_HLEN); nb_ack = 1; if (flags & DUP_ACK) { @@ -157,10 +160,8 @@ int tcp_vu_send_flag(const struct ctx *c, struct tcp_tap_conn *conn, int flags) flags_elem[0].in_sg[0].iov_len); nb_ack++; - if (*c->pcap) { - pcap_iov(&flags_elem[1].in_sg[0], 1, - sizeof(struct virtio_net_hdr_mrg_rxbuf)); - } + if (*c->pcap) + pcap_iov(&flags_elem[1].in_sg[0], 1, VNET_HLEN); } } @@ -211,7 +212,8 @@ static ssize_t tcp_vu_sock_recv(const struct ctx *c, struct vu_virtq *vq, cnt = vu_collect(vdev, vq, &elem[elem_cnt], VIRTQUEUE_MAX_SIZE - elem_cnt, - MIN(mss, fillsize) + hdrlen, &frame_size); + MAX(MIN(mss, fillsize) + hdrlen, ETH_ZLEN + VNET_HLEN), + &frame_size); if (cnt == 0) break; @@ -254,6 +256,7 @@ static ssize_t tcp_vu_sock_recv(const struct ctx *c, struct vu_virtq *vq, len -= iov->iov_len; } + /* adjust head count */ while (*head_cnt > 0 && head[*head_cnt - 1] >= i) (*head_cnt)--; @@ -301,7 +304,7 @@ static void tcp_vu_prepare(const struct ctx *c, struct tcp_tap_conn *conn, struct ethhdr *eh; /* we guess the first iovec provided by the guest can embed - * all the headers needed by L2 frame + * all the headers needed by L2 frame, including any padding */ ASSERT(iov[0].iov_len >= hdrlen); @@ -331,7 +334,7 @@ static void tcp_vu_prepare(const struct ctx *c, struct tcp_tap_conn *conn, th->ack = 1; th->psh = push; - tcp_fill_headers(c, conn, NULL, eh, ip4h, ip6h, th, &payload, + tcp_fill_headers(c, conn, eh, ip4h, ip6h, th, &payload, *check, conn->seq_to_tap, no_tcp_csum); if (ip4h) *check = &ip4h->check; @@ -421,6 +424,7 @@ int tcp_vu_data_from_sock(const struct ctx *c, struct tcp_tap_conn *conn) } conn_event(c, conn, TAP_FIN_SENT); + conn_flag(c, conn, ACK_FROM_TAP_DUE); } return 0; @@ -446,8 +450,9 @@ int tcp_vu_data_from_sock(const struct ctx *c, struct tcp_tap_conn *conn) int buf_cnt = head[i + 1] - head[i]; ssize_t dlen = iov_size(iov, buf_cnt) - hdrlen; bool push = i == head_cnt - 1; + size_t l2len; - vu_set_vnethdr(vdev, iov->iov_base, buf_cnt); + vu_set_vnethdr(iov->iov_base, buf_cnt); /* The IPv4 header checksum varies only with dlen */ if (previous_dlen != dlen) @@ -456,10 +461,12 @@ int tcp_vu_data_from_sock(const struct ctx *c, struct tcp_tap_conn *conn) tcp_vu_prepare(c, conn, iov, buf_cnt, &check, !*c->pcap, push); - if (*c->pcap) { - pcap_iov(iov, buf_cnt, - sizeof(struct virtio_net_hdr_mrg_rxbuf)); - } + /* Pad first/single buffer only, it's at least ETH_ZLEN long */ + l2len = dlen + hdrlen - VNET_HLEN; + vu_pad(iov, l2len); + + if (*c->pcap) + pcap_iov(iov, buf_cnt, VNET_HLEN); conn->seq_to_tap += dlen; } |
