Skip to content

Commit

Permalink
{lib/uknetdev, virtio}: PR-unikraft#1088 IPv4/TCP segmentation offload
Browse files Browse the repository at this point in the history
Signed-off-by: Marco Schlumpp <marco@unikraft.io>
  • Loading branch information
mschlumpp authored and michpappas committed Sep 27, 2023
1 parent bd657be commit 0885a2b
Show file tree
Hide file tree
Showing 5 changed files with 190 additions and 11 deletions.
40 changes: 31 additions & 9 deletions drivers/virtio/net/virtio_net.c
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,11 @@ static int virtio_netdev_xmit(struct uk_netdev *dev,
sizeof(*padded_hdr));
vhdr->csum_offset = pkt->csum_offset;
}
vhdr->gso_type = VIRTIO_NET_HDR_GSO_NONE;
if (pkt->flags & UK_NETBUF_F_GSO_TCPV4) {
vhdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
vhdr->hdr_len = pkt->header_len;
vhdr->gso_size = pkt->gso_size;
}

/**
* Prepare the sglist and enqueue the buffer to the virtio-ring.
Expand Down Expand Up @@ -422,17 +426,19 @@ static int virtio_netdev_xmit(struct uk_netdev *dev,
if (pkt->next) {
rc = uk_sglist_append_netbuf(&queue->sg, pkt->next);
if (unlikely(rc != 0)) {
uk_pr_err("Failed to append to the sg list\n");
uk_pr_err("Failed to append to the sg list: %d\n", rc);
goto err_remove_vhdr;
}
}

total_len = uk_sglist_length(&queue->sg);
if (unlikely(total_len > VIRTIO_PKT_BUFFER_LEN)) {
uk_pr_err("Packet size too big: %lu, max:%u\n",
total_len, VIRTIO_PKT_BUFFER_LEN);
rc = -ENOTSUP;
goto err_remove_vhdr;
if (!(pkt->flags & UK_NETBUF_F_GSO_TCPV4)) {
total_len = uk_sglist_length(&queue->sg);
if (unlikely(total_len > VIRTIO_PKT_BUFFER_LEN)) {
uk_pr_err("Packet size too big: %lu, max:%u\n",
total_len, VIRTIO_PKT_BUFFER_LEN);
rc = -ENOTSUP;
goto err_remove_vhdr;
}
}

/**
Expand Down Expand Up @@ -952,6 +958,16 @@ static int virtio_netdev_feature_negotiate(struct uk_netdev *n)
if (VIRTIO_FEATURE_HAS(host_features, VIRTIO_F_EVENT_IDX))
VIRTIO_FEATURE_SET(drv_features, VIRTIO_F_EVENT_IDX);

/**
* TCP Segmentation Offload
* NOTE: This enables sending and receiving of packets marked with
* VIRTIO_NET_HDR_GSO_TCPV4
*/
if (VIRTIO_FEATURE_HAS(host_features, VIRTIO_NET_F_GSO))
VIRTIO_FEATURE_SET(drv_features, VIRTIO_NET_F_GSO);
if (VIRTIO_FEATURE_HAS(host_features, VIRTIO_NET_F_HOST_TSO4))
VIRTIO_FEATURE_SET(drv_features, VIRTIO_NET_F_HOST_TSO4);

/**
* Announce our enabled driver features back to the backend device
*/
Expand Down Expand Up @@ -1154,9 +1170,15 @@ static void virtio_net_info_get(struct uk_netdev *dev,
dev_info->nb_encap_tx = sizeof(struct virtio_net_hdr_padded);
dev_info->nb_encap_rx = sizeof(struct virtio_net_hdr_padded);
dev_info->ioalign = sizeof(void *); /* word size alignment */

dev_info->features = UK_NETDEV_F_RXQ_INTR
| (VIRTIO_FEATURE_HAS(vndev->vdev->features, VIRTIO_NET_F_CSUM)
? UK_NETDEV_F_PARTIAL_CSUM : 0);
? UK_NETDEV_F_PARTIAL_CSUM : 0)
| ((VIRTIO_FEATURE_HAS(vndev->vdev->features,
VIRTIO_NET_F_HOST_TSO4)
|| VIRTIO_FEATURE_HAS(vndev->vdev->features,
VIRTIO_NET_F_GSO))
? UK_NETDEV_F_TSO4 : 0);
}

static int virtio_net_start(struct uk_netdev *n)
Expand Down
2 changes: 1 addition & 1 deletion drivers/virtio/ring/include/virtio/virtio_ring.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ struct vring {
* versa. They are at the end for backwards compatibility.
*/
#define vring_used_event(vr) ((vr)->avail->ring[(vr)->num])
#define vring_avail_event(vr) (*(__virtio_le16 *)&(vr)->used->ring[(vr)->num])
#define vring_avail_event(vr) (*(__virtio16 *)&(vr)->used->ring[(vr)->num])

static inline void vring_init(struct vring *vr, unsigned int num, uint8_t *p,
unsigned long align)
Expand Down
14 changes: 14 additions & 0 deletions lib/uknetdev/include/uk/netbuf.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,12 @@ typedef void (*uk_netbuf_dtor_t)(struct uk_netbuf *);
#define UK_NETBUF_F_PARTIAL_CSUM_BIT 1
#define UK_NETBUF_F_PARTIAL_CSUM (1 << UK_NETBUF_F_PARTIAL_CSUM_BIT)

/* Indicates the packet should be sent with the help of TCP Segmentation
* Offloading. This requires that the device supports this.
*/
#define UK_NETBUF_F_GSO_TCPV4_BIT 2
#define UK_NETBUF_F_GSO_TCPV4 (1 << UK_NETBUF_F_GSO_TCPV4_BIT)

struct uk_netbuf {
struct uk_netbuf *next;
struct uk_netbuf *prev;
Expand All @@ -147,6 +153,14 @@ struct uk_netbuf {
* pointing to the checksum field
*/

uint16_t header_len; /**< Used if UK_NETBUF_F_GSO_* is set;
* Number of bytes to copy into each split
* packet as a header
*/
uint16_t gso_size; /**< Used if UK_NETBUF_F_GSO_* is set;
* Maximum size of each packet beyond the header
*/

uk_netbuf_dtor_t dtor; /**< Destructor callback */
struct uk_alloc *_a; /**< @internal Allocator for free'ing */
void *_b; /**< @internal Base address for free'ing */
Expand Down
8 changes: 7 additions & 1 deletion lib/uknetdev/include/uk/netdev_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,13 +142,19 @@ struct uk_hwaddr {
#define UK_NETDEV_F_PARTIAL_CSUM_BIT 2
#define UK_NETDEV_F_PARTIAL_CSUM (1UL << UK_NETDEV_F_PARTIAL_CSUM_BIT)

/* Indicates that the network device supports sending netbufs with the
* UK_NETBUF_F_GSO_TCPV4 bit set. */
#define UK_NETDEV_F_TSO4_BIT 3
#define UK_NETDEV_F_TSO4 (1UL << UK_NETDEV_F_TSO4_BIT)

#define uk_netdev_rxintr_supported(feature) \
(feature & (UK_NETDEV_F_RXQ_INTR))
#define uk_netdev_txintr_supported(feature) \
(feature & (UK_NETDEV_F_TXQ_INTR))
#define uk_netdev_partial_csum_supported(feature) \
(feature & (UK_NETDEV_F_PARTIAL_CSUM))

#define uk_netdev_tso4_supported(feature) \
(feature & (UK_NETDEV_F_TSO4))
/**
* A structure used to describe network device capabilities.
*/
Expand Down
137 changes: 137 additions & 0 deletions lib/uknetdev/include/uk/netstructs.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/*
* Authors: Marco Schlumpp <marco@unikraft.io>
*
* Copyright (c) 2022, Unikraft GmbH. All rights reserved.
* Copyright (c) 1982, 1986, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __UK_NETSTRUCTS__
#define __UK_NETSTRUCTS__

#include <stdint.h>
#include <uk/essentials.h>

#include "netdev_core.h"

/*
* Some basic Ethernet constants.
*/
#define UK_ETHER_ADDR_LEN 6 /* length of an Ethernet address */
#define UK_ETHER_TYPE_LEN 2 /* length of the Ethernet type field */
#define UK_ETHER_CRC_LEN 4 /* length of the Ethernet CRC */
#define UK_ETHER_HDR_LEN (UK_ETHER_ADDR_LEN*2+UK_ETHER_TYPE_LEN)
#define UK_ETHER_MIN_LEN 64 /* minimum frame len, including CRC */
#define UK_ETHER_MAX_LEN 1518 /* maximum frame len, including CRC */
#define UK_ETHER_MAX_LEN_JUMBO 9018 /* max jumbo frame len, including CRC */

#define UK_ETHER_VLAN_ENCAP_LEN 4 /* len of 802.1Q VLAN encapsulation */

/*
* 802.1q Virtual LAN header.
*/
struct uk_ether_vlan_header {
uint8_t evl_dhost[UK_ETH_ADDR_LEN];
uint8_t evl_shost[UK_ETH_ADDR_LEN];
uint16_t evl_encap_proto;
uint16_t evl_tag;
uint16_t evl_proto;
} __packed;

#define UK_ETHERTYPE_IP 0x0800 /* IP protocol */
#define UK_ETHERTYPE_VLAN 0x8100 /* IEEE 802.1Q VLAN tagging */
#define UK_ETHERTYPE_IPV6 0x86DD /* IP protocol version 6 */

/*
* Structure of an internet header, naked of options.
*/
struct uk_iphdr {
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
uint8_t ip_hl:4, /* header length */
ip_v:4; /* version */
#endif
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
uint8_t ip_v:4, /* version */
ip_hl:4; /* header length */
#endif
uint8_t ip_tos; /* type of service */
uint16_t ip_len; /* total length */
uint16_t ip_id; /* identification */
uint16_t ip_off; /* fragment offset field */
#define UK_IP_RF 0x8000 /* reserved fragment flag */
#define UK_IP_DF 0x4000 /* dont fragment flag */
#define UK_IP_MF 0x2000 /* more fragments flag */
#define UK_IP_OFFMASK 0x1fff /* mask for fragmenting bits */
uint8_t ip_ttl; /* time to live */
uint8_t ip_p; /* protocol */
uint16_t ip_sum; /* checksum */
uint32_t ip_src, ip_dst; /* source and dest address */
} __packed __align(2);

#define UK_IPPROTO_IP 0 /* dummy for IP */
#define UK_IPPROTO_ICMP 1 /* control message protocol */
#define UK_IPPROTO_TCP 6 /* tcp */
#define UK_IPPROTO_UDP 17 /* user datagram protocol */
#define UK_IPPROTO_IPV6 41 /* IP6 header */

/*
* TCP header.
* Per RFC 793, September, 1981.
*/
struct uk_tcphdr {
uint16_t th_sport; /* source port */
uint16_t th_dport; /* destination port */
uint32_t th_seq; /* sequence number */
uint32_t th_ack; /* acknowledgement number */
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
uint8_t th_x2:4, /* upper 4 (reserved) flags */
th_off:4; /* data offset */
#endif
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
uint8_t th_off:4, /* data offset */
th_x2:4; /* upper 4 (reserved) flags */
#endif
uint8_t th_flags;
#define UK_TH_FIN 0x01
#define UK_TH_SYN 0x02
#define UK_TH_RST 0x04
#define UK_TH_PUSH 0x08
#define UK_TH_ACK 0x10
#define UK_TH_URG 0x20
#define UK_TH_ECE 0x40
#define UK_TH_CWR 0x80
#define UK_TH_AE 0x100 /* maps into th_x2 */
#define UK_TH_FLAGS (UK_TH_FIN|UK_TH_SYN|UK_TH_RST|UK_TH_PUSH|UK_TH_ACK| \
UK_TH_URG|UK_TH_ECE|UK_TH_CWR)

uint16_t th_win; /* window */
uint16_t th_sum; /* checksum */
uint16_t th_urp; /* urgent pointer */
};

#endif /* __UK_NETSTRUCTS__ */

0 comments on commit 0885a2b

Please sign in to comment.