virtio specification introduced support for outer network header offset broadcast. This patch implements the needed defines and virtio header parsing capabilities. Signed-off-by: Kommula Shiva Shankar --- include/linux/virtio_net.h | 40 +++++++++++++++++++++++++++++++++ include/uapi/linux/virtio_net.h | 8 +++++++ 2 files changed, 48 insertions(+) diff --git a/include/linux/virtio_net.h b/include/linux/virtio_net.h index 20e0584db1dd..7ab872a11a21 100644 --- a/include/linux/virtio_net.h +++ b/include/linux/virtio_net.h @@ -374,6 +374,46 @@ static inline int virtio_net_handle_csum_offload(struct sk_buff *skb, return 0; } +static inline int +virtio_net_out_net_header_to_skb(struct sk_buff *skb, + struct virtio_net_hdr_v1_hash_tunnel_out_net_hdr *vhdr, + bool out_net_hdr_negotiated, + bool little_endian) +{ + unsigned int out_net_hdr_off; + + if (!out_net_hdr_negotiated) + return 0; + + if (vhdr->outer_nh_offset) { + out_net_hdr_off = le16_to_cpu(vhdr->outer_nh_offset); + skb_set_network_header(skb, out_net_hdr_off); + } + + return 0; +} + +static inline int +virtio_net_out_net_header_from_skb(const struct sk_buff *skb, + struct virtio_net_hdr_v1_hash_tunnel_out_net_hdr *vhdr, + bool out_net_hdr_negotiated, + bool little_endian) +{ + unsigned int out_net_hdr_off; + + if (!out_net_hdr_negotiated) { + vhdr->outer_nh_offset = 0; + return 0; + } + + out_net_hdr_off = skb_network_offset(skb); + if (out_net_hdr_off && (skb->protocol == htons(ETH_P_IP) || + skb->protocol == htons(ETH_P_IPV6))) + vhdr->outer_nh_offset = cpu_to_le16(out_net_hdr_off); + + return 0; +} + /* * vlan_hlen always refers to the outermost MAC header. That also * means it refers to the only MAC header, if the packet does not carry diff --git a/include/uapi/linux/virtio_net.h b/include/uapi/linux/virtio_net.h index 8bf27ab8bcb4..6032b9e443bb 100644 --- a/include/uapi/linux/virtio_net.h +++ b/include/uapi/linux/virtio_net.h @@ -86,6 +86,7 @@ * packets with partial csum * for the outer header */ +#define VIRTIO_NET_F_OUT_NET_HEADER 69 /* Outer network header offset */ /* Offloads bits corresponding to VIRTIO_NET_F_HOST_UDP_TUNNEL_GSO{,_CSUM} * features @@ -214,6 +215,13 @@ struct virtio_net_hdr_v1_hash_tunnel { __le16 inner_nh_offset; }; +/* outer network header */ +struct virtio_net_hdr_v1_hash_tunnel_out_net_hdr { + struct virtio_net_hdr_v1_hash_tunnel tnl_hdr; + __le16 outer_nh_offset; + __u8 padding_reserved_2[6]; +}; + #ifndef VIRTIO_NET_NO_LEGACY /* This header comes first in the scatter-gather list. * For legacy virtio, if VIRTIO_F_ANY_LAYOUT is not negotiated, it must -- 2.48.1 If outer network header feature is set, update header offset in ingress and egress path. If feature is not set, reset header offset to zero. Signed-off-by: Kommula Shiva Shankar --- drivers/net/virtio_net.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 7da5a37917e9..0b60cbbb3d33 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -451,6 +451,9 @@ struct virtnet_info { bool rx_tnl_csum; + /* Outer network header support */ + bool out_net_hdr_negotiated; + /* Is delayed refill enabled? */ bool refill_enabled; @@ -511,6 +514,7 @@ struct virtio_net_common_hdr { struct virtio_net_hdr_mrg_rxbuf mrg_hdr; struct virtio_net_hdr_v1_hash hash_v1_hdr; struct virtio_net_hdr_v1_hash_tunnel tnl_hdr; + struct virtio_net_hdr_v1_hash_tunnel_out_net_hdr out_net_hdr; }; }; @@ -2576,8 +2580,8 @@ static void virtnet_receive_done(struct virtnet_info *vi, struct receive_queue * hdr->hdr.flags = flags; if (virtio_net_handle_csum_offload(skb, &hdr->hdr, vi->rx_tnl_csum)) { net_warn_ratelimited("%s: bad csum: flags: %x, gso_type: %x rx_tnl_csum %d\n", - dev->name, hdr->hdr.flags, - hdr->hdr.gso_type, vi->rx_tnl_csum); + dev->name, hdr->hdr.flags, + hdr->hdr.gso_type, vi->rx_tnl_csum); goto frame_err; } @@ -2591,6 +2595,8 @@ static void virtnet_receive_done(struct virtnet_info *vi, struct receive_queue * goto frame_err; } + virtio_net_out_net_header_to_skb(skb, &hdr->out_net_hdr, vi->out_net_hdr_negotiated, + virtio_is_little_endian(vi->vdev)); skb_record_rx_queue(skb, vq2rxq(rq->vq)); skb->protocol = eth_type_trans(skb, dev); pr_debug("Receiving skb proto 0x%04x len %i type %i\n", @@ -3317,6 +3323,9 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb, bool orphan) else hdr = &skb_vnet_common_hdr(skb)->tnl_hdr; + virtio_net_out_net_header_from_skb(skb, &skb_vnet_common_hdr(skb)->out_net_hdr, + vi->out_net_hdr_negotiated, + virtio_is_little_endian(vi->vdev)); if (virtio_net_hdr_tnl_from_skb(skb, hdr, vi->tx_tnl, virtio_is_little_endian(vi->vdev), 0)) return -EPROTO; @@ -6915,8 +6924,10 @@ static int virtnet_probe(struct virtio_device *vdev) dev->xdp_metadata_ops = &virtnet_xdp_metadata_ops; } - if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_UDP_TUNNEL_GSO) || - virtio_has_feature(vdev, VIRTIO_NET_F_HOST_UDP_TUNNEL_GSO)) + if (virtio_has_feature(vdev, VIRTIO_NET_F_OUT_NET_HEADER)) + vi->hdr_len = sizeof(struct virtio_net_hdr_v1_hash_tunnel_out_net_hdr); + else if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_UDP_TUNNEL_GSO) || + virtio_has_feature(vdev, VIRTIO_NET_F_HOST_UDP_TUNNEL_GSO)) vi->hdr_len = sizeof(struct virtio_net_hdr_v1_hash_tunnel); else if (vi->has_rss_hash_report) vi->hdr_len = sizeof(struct virtio_net_hdr_v1_hash); @@ -6933,6 +6944,9 @@ static int virtnet_probe(struct virtio_device *vdev) if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_UDP_TUNNEL_GSO)) vi->tx_tnl = true; + if (virtio_has_feature(vdev, VIRTIO_NET_F_OUT_NET_HEADER)) + vi->out_net_hdr_negotiated = true; + if (virtio_has_feature(vdev, VIRTIO_F_ANY_LAYOUT) || virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) vi->any_header_sg = true; @@ -7247,6 +7261,7 @@ static unsigned int features[] = { VIRTIO_NET_F_GUEST_UDP_TUNNEL_GSO_CSUM, VIRTIO_NET_F_HOST_UDP_TUNNEL_GSO, VIRTIO_NET_F_HOST_UDP_TUNNEL_GSO_CSUM, + VIRTIO_NET_F_OUT_NET_HEADER, }; static unsigned int features_legacy[] = { -- 2.48.1 apprise vhost net about the virtio net header size. Signed-off-by: Kommula Shiva Shankar --- drivers/vhost/net.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 35ded4330431..8d055405746d 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -78,6 +78,7 @@ static const u64 vhost_net_features[VIRTIO_FEATURES_DWORDS] = { (1ULL << VIRTIO_F_IN_ORDER), VIRTIO_BIT(VIRTIO_NET_F_GUEST_UDP_TUNNEL_GSO) | VIRTIO_BIT(VIRTIO_NET_F_HOST_UDP_TUNNEL_GSO), + VIRTIO_BIT(VIRTIO_NET_F_OUT_NET_HEADER), }; enum { @@ -1655,6 +1656,9 @@ static int vhost_net_set_features(struct vhost_net *n, const u64 *features) sizeof(struct virtio_net_hdr_mrg_rxbuf) : sizeof(struct virtio_net_hdr); + if (virtio_features_test_bit(features, + VIRTIO_NET_F_OUT_NET_HEADER)) + hdr_len = sizeof(struct virtio_net_hdr_v1_hash_tunnel_out_net_hdr); if (virtio_features_test_bit(features, VIRTIO_NET_F_HOST_UDP_TUNNEL_GSO) || virtio_features_test_bit(features, -- 2.48.1