Commit 4b0bf10e authored by Arseniy Krasnov's avatar Arseniy Krasnov Committed by Paolo Abeni
Browse files

vsock/virtio: non-linear skb handling for tap



For tap device new skb is created and data from the current skb is
copied to it. This adds copying data from non-linear skb to new
the skb.

Signed-off-by: default avatarArseniy Krasnov <avkrasnov@salutedevices.com>
Reviewed-by: default avatarStefano Garzarella <sgarzare@redhat.com>
Acked-by: default avatarMichael S. Tsirkin <mst@redhat.com>
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 64c99d2d
Loading
Loading
Loading
Loading
+28 −3
Original line number Diff line number Diff line
@@ -106,6 +106,27 @@ virtio_transport_alloc_skb(struct virtio_vsock_pkt_info *info,
	return NULL;
}

static void virtio_transport_copy_nonlinear_skb(const struct sk_buff *skb,
						void *dst,
						size_t len)
{
	struct iov_iter iov_iter = { 0 };
	struct kvec kvec;
	size_t to_copy;

	kvec.iov_base = dst;
	kvec.iov_len = len;

	iov_iter.iter_type = ITER_KVEC;
	iov_iter.kvec = &kvec;
	iov_iter.nr_segs = 1;

	to_copy = min_t(size_t, len, skb->len);

	skb_copy_datagram_iter(skb, VIRTIO_VSOCK_SKB_CB(skb)->offset,
			       &iov_iter, to_copy);
}

/* Packet capture */
static struct sk_buff *virtio_transport_build_skb(void *opaque)
{
@@ -114,7 +135,6 @@ static struct sk_buff *virtio_transport_build_skb(void *opaque)
	struct af_vsockmon_hdr *hdr;
	struct sk_buff *skb;
	size_t payload_len;
	void *payload_buf;

	/* A packet could be split to fit the RX buffer, so we can retrieve
	 * the payload length from the header and the buffer pointer taking
@@ -122,7 +142,6 @@ static struct sk_buff *virtio_transport_build_skb(void *opaque)
	 */
	pkt_hdr = virtio_vsock_hdr(pkt);
	payload_len = pkt->len;
	payload_buf = pkt->data;

	skb = alloc_skb(sizeof(*hdr) + sizeof(*pkt_hdr) + payload_len,
			GFP_ATOMIC);
@@ -165,7 +184,13 @@ static struct sk_buff *virtio_transport_build_skb(void *opaque)
	skb_put_data(skb, pkt_hdr, sizeof(*pkt_hdr));

	if (payload_len) {
		skb_put_data(skb, payload_buf, payload_len);
		if (skb_is_nonlinear(pkt)) {
			void *data = skb_put(skb, payload_len);

			virtio_transport_copy_nonlinear_skb(pkt, data, payload_len);
		} else {
			skb_put_data(skb, pkt->data, payload_len);
		}
	}

	return skb;