Re: [PATCH v3] virtio-net: define UDP tunnel offload feature

Stefano Garzarella <[email protected]> Mon, 20 May 2024 15:00:06 +0200
Newsgroups dev.linux.lists.virtio-dev
Message-ID <tqnbswminpqjarzevnapzbta3532hc74arg4otwstmv2coojne@4selyuhzsqnb>
On Mon, May 20, 2024 at 10:24:53AM GMT, Paolo Abeni wrote:
>The VIRTIO_NET_HDR_GSO_UDP_TUNNEL is a gso_type flag allowing GSO over
>UDP tunnel. It can be negotiated on both the host and guest sides.
>
>UDP tunnel usage is ubiquitous in container deployment, and the ability
>to offload UDP encapsulated GSO traffic impacts greatly the performances
>and the CPU utilization of such use cases.
>
>One constraint addressed here is that the virtio side (either device or
>driver) receiving a UDP tunneled GSO packet must be able to reconstruct
>completely the inner and outer headers offset - to allow for later GSO.
>
>To accommodate such need, new optional fields are introduced in the
>virtio_net header: outer_th_offset, inner_protocol, inner_mac_offset,
>inner_nh_offset. They map directly to the corresponding header
>information.
>
>Note that the inner transport header is implied by the (inner) checksum
>offload, if present. Otherwise, it's up to the receiver to detect the
>inner transport header offset from the provided information, as it's
>currently the case for plain (not UDP tunneled) GSO packets.
>
>The outer UDP header may carry a second checksum, which can be offloaded
>independently from the inner one. Since UDP tunnel checksum offload
>support makes little sense without UDP tunnel GSO support, to avoid
>unnecessary complex feature negotiation, the
>VIRTIO_NET_HDR_GSO_UDP_TUNNEL feature implies the support for the outer
>header checksum offload and the checksum itself is handled similarly to
>the inner header one.
>
>Note that there is no concept of UDP tunnel type negotiation (e.g.
>vxlan, geneve, vxlan-gpe, etc.). That is intentional because:
>- given the information carried by the guest or host kernel, it's
>  impossible to probe reliably the UDP tunnel type. Specifically, the
>  outer UDP port numbers give a hint, but peers could use nonstandard
>  ones.
>- all the existing UDP tunnel protocols behave the same way WRT GSO
>  offload, carrying an immutable header on top of the outer transport
>  one.
>- if a new UDP tunnel protocol should surface in the future with
>  different constraints, the host and guest kernels will need explicit
>  support for it, including new, different GSO features. Additional
>  virtio support should be designed separately.
>
>Signed-off-by: Paolo Abeni <[email protected]>
>---
>v2 -> v3:
> - UDP_TUNNEL -> UDP_TUNNEL_GSO
> - add explicit fields for the inner meta-data
> - more verbose changelog
> https://lists.oasis-open.org/archives/virtio-dev/202206/msg00026.html
>
>v1 -> v2:
> - explicitly state that the outer header probing is mandatory
> - explicitly state that GSO_UDP is not allowed with GSO_UDP_TUNNEL
> - clarify hdr_len usage
> - clarify UDP_TUNNEL_CSUM bit usage
> - fix a few typos
> https://lists.oasis-open.org/archives/virtio-dev/202205/msg00037.html
>---
> device-types/net/description.tex | 118 ++++++++++++++++++++++++++++---
> 1 file changed, 110 insertions(+), 8 deletions(-)
>
>diff --git a/device-types/net/description.tex b/device-types/net/description.tex
>index 76585b0..2eae797 100644
>--- a/device-types/net/description.tex
>+++ b/device-types/net/description.tex
>@@ -88,6 +88,12 @@ \subsection{Feature bits}\label{sec:Device Types / Network Device / Feature bits
> \item[VIRTIO_NET_F_CTRL_MAC_ADDR(23)] Set MAC address through control
>     channel.
>
>+\item[VIRTIO_NET_F_GUEST_UDP_TUNNEL_GSO (49)] Driver can receive GSO packets
>+  carried by an UDP tunnel and can handle the outer checksum.
>+
>+\item[VIRTIO_NET_F_HOST_UDP_TUNNEL_GSO (50)] Device can receive GSO packets
>+  carried by an UDP tunnel and can handle the outer checksum.
>+
> \item[VIRTIO_NET_F_HASH_TUNNEL(51)] Device supports inner header hash for encapsulated packets.
>
> \item[VIRTIO_NET_F_VQ_NOTF_COAL(52)] Device supports virtqueue notification coalescing.
>@@ -133,12 +139,16 @@ \subsubsection{Feature bit requirements}\label{sec:Device Types / Network Device
> \item[VIRTIO_NET_F_GUEST_UFO] Requires VIRTIO_NET_F_GUEST_CSUM.
> \item[VIRTIO_NET_F_GUEST_USO4] Requires VIRTIO_NET_F_GUEST_CSUM.
> \item[VIRTIO_NET_F_GUEST_USO6] Requires VIRTIO_NET_F_GUEST_CSUM.
>+\item[VIRTIO_NET_F_GUEST_UDP_TUNNEL_GSO] Requires VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6,
>+   VIRTIO_NET_F_GUEST_USO4 or VIRTIO_NET_F_GUEST_USO6.
>
> \item[VIRTIO_NET_F_HOST_TSO4] Requires VIRTIO_NET_F_CSUM.
> \item[VIRTIO_NET_F_HOST_TSO6] Requires VIRTIO_NET_F_CSUM.
> \item[VIRTIO_NET_F_HOST_ECN] Requires VIRTIO_NET_F_HOST_TSO4 or VIRTIO_NET_F_HOST_TSO6.
> \item[VIRTIO_NET_F_HOST_UFO] Requires VIRTIO_NET_F_CSUM.
> \item[VIRTIO_NET_F_HOST_USO] Requires VIRTIO_NET_F_CSUM.
>+\item[VIRTIO_NET_F_HOST_UDP_TUNNEL_GSO] Requires 
>VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_TSO6,
>+   VIRTIO_NET_F_GUEST_USO4 or VIRTIO_NET_F_GUEST_USO6.
>
> \item[VIRTIO_NET_F_CTRL_RX] Requires VIRTIO_NET_F_CTRL_VQ.
> \item[VIRTIO_NET_F_CTRL_VLAN] Requires VIRTIO_NET_F_CTRL_VQ.
>@@ -374,6 +384,9 @@ \subsection{Device Initialization}\label{sec:Device Types / Network Device / Dev
>   segmentation/fragmentation offload by negotiating the VIRTIO_NET_F_HOST_TSO4 (IPv4
>   TCP), VIRTIO_NET_F_HOST_TSO6 (IPv6 TCP), VIRTIO_NET_F_HOST_UFO
>   (UDP fragmentation) and VIRTIO_NET_F_HOST_USO (UDP segmentation) features.
>+  Additionally, it can negotiate the VIRTIO_NET_F_HOST_UDP_TUNNEL_GSO feature
>+  to use TCP segmentation or UDP segmentation on top of UDP encapsulation,
>+  respecting the other negotiated features.
>
> \item The converse features are also available: a driver can save
>   the virtual device some work by negotiating these features.\note{For example, a network packet transported between two guests on
>@@ -382,8 +395,9 @@ \subsection{Device Initialization}\label{sec:Device Types / Network Device / Dev
>    The VIRTIO_NET_F_GUEST_CSUM feature indicates that partially
>   checksummed packets can be received, and if it can do that then
>   the VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6,
>-  VIRTIO_NET_F_GUEST_UFO, VIRTIO_NET_F_GUEST_ECN, VIRTIO_NET_F_GUEST_USO4
>-  and VIRTIO_NET_F_GUEST_USO6 are the input equivalents of the features described above.
>+  VIRTIO_NET_F_GUEST_UFO, VIRTIO_NET_F_GUEST_ECN, VIRTIO_NET_F_GUEST_USO4,
>+  VIRTIO_NET_F_GUEST_USO6 and VIRTIO_NET_F_GUEST_UDP_TUNNEL_GSO
>+  are the input equivalents of the features described above.
>   See \ref{sec:Device Types / Network Device / Device Operation /
> Setting Up Receive Buffers}~\nameref{sec:Device Types / Network
> Device / Device Operation / Setting Up Receive Buffers} and
>@@ -407,12 +421,14 @@ \subsection{Device Operation}\label{sec:Device Types / Network Device / Device O
> #define VIRTIO_NET_HDR_F_NEEDS_CSUM    1
> #define VIRTIO_NET_HDR_F_DATA_VALID    2
> #define VIRTIO_NET_HDR_F_RSC_INFO      4
>+#define VIRTIO_NET_HDR_F_UDP_TUNNEL_CSUM 8
>         u8 flags;
> #define VIRTIO_NET_HDR_GSO_NONE        0
> #define VIRTIO_NET_HDR_GSO_TCPV4       1
> #define VIRTIO_NET_HDR_GSO_UDP         3
> #define VIRTIO_NET_HDR_GSO_TCPV6       4
> #define VIRTIO_NET_HDR_GSO_UDP_L4      5
>+#define VIRTIO_NET_HDR_GSO_UDP_TUNNEL 0x40
> #define VIRTIO_NET_HDR_GSO_ECN      0x80
>         u8 gso_type;
>         le16 hdr_len;
>@@ -423,6 +439,10 @@ \subsection{Device Operation}\label{sec:Device Types / Network Device / Device O
>         le32 hash_value;        (Only if VIRTIO_NET_F_HASH_REPORT negotiated)
>         le16 hash_report;       (Only if VIRTIO_NET_F_HASH_REPORT negotiated)
>         le16 padding_reserved;  (Only if VIRTIO_NET_F_HASH_REPORT negotiated)
>+        le16 outer_th_offset;   (Only if VIRTIO_NET_F_UDP_TUNNEL_GSO negotiated)
>+        le16 inner_protocol;    (Only if VIRTIO_NET_F_UDP_TUNNEL_GSO negotiated)
>+        le16 inner_mac_offset;  (Only if VIRTIO_NET_F_UDP_TUNNEL_GSO negotiated)
>+        le16 inner_nh_offset;   (Only if VIRTIO_NET_F_UDP_TUNNEL_GSO negotiated)

I can't find the definition of VIRTIO_NET_F_UDP_TUNNEL_GSO. Should it be 
VIRTIO_NET_F_GUEST_UDP_TUNNEL_GSO or VIRTIO_NET_F_HOST_UDP_TUNNEL_GSO?

Or are these fiels only present when VIRTIO_NET_HDR_GSO_UDP_TUNNEL is 
set?

Thanks,
Stefano

> };
> \end{lstlisting}
>
>@@ -480,6 +500,8 @@ \subsubsection{Packet Transmission}\label{sec:Device Types / Network Device / De
> followed by the TCP header (with the TCP checksum field 16 bytes
> into that header). \field{csum_start} will be 14+20 = 34 (the TCP
> checksum includes the header), and \field{csum_offset} will be 16.
>+If the given packets has the VIRTIO_NET_HDR_GSO_UDP_TUNNEL bit set,
>+the above checksum fields refer to the inner header checksum.
> \end{note}
>
> \item If the driver negotiated
>@@ -516,6 +538,30 @@ \subsubsection{Packet Transmission}\label{sec:Device Types / Network Device / De
> specifically in the protocol.}.
>    \end{itemize}
>
>+\item If the driver negotiated the VIRTIO_NET_F_HOST_UDP_TUNNEL_GSO feature,
>+  the VIRTIO_NET_HDR_GSO_UDP_TUNNEL bit in \field{gso_type} indicates that
>+  the GSO protocol is encapsulated in an UDP tunnel.
>+  The other tunnel-related fields indicate how to replicate the inner packet
>+  header to cut it into smaller packets:
>+
>+  \begin{itemize}
>+  \item \field{outer_th_offset} field indicates the outer transport header within
>+      the packet
>+
>+  \item \field{inner_protocol} field indicates the ethernet type of the inner
>+      protocol.
>+
>+  \item \field{inner_mac_offset} field indicates the inner mac header within the packet
>+
>+  \item \field{inner_nh_offset} field indicates the inner network header within
>+      the packet
>+
>+  \item If the \field{flags} field has the VIRTIO_NET_HDR_F_UDP_TUNNEL_CSUM set,
>+    the outer UDP checksum field carries the checksum for the UDP pseudo header
>+    and the complete UDP checksum can be computed in a similar way to the
>+    inner TCP.
>+  \end{itemize}
>+
> \item \field{num_buffers} is set to zero.  This field is unused on transmitted packets.
>
> \item The header and packet are added as one output descriptor to the
>@@ -557,6 +603,14 @@ \subsubsection{Packet Transmission}\label{sec:Device Types / Network Device / De
> driver MUST set the VIRTIO_NET_HDR_GSO_ECN bit in
> \field{gso_type}.
>
>+The driver MUST NOT send to the device TCP or UDP GSO packets over UDP tunnel
>+requiring segmentation offload, unless the VIRTIO_NET_F_HOST_UDP_TUNNEL_GSO is
>+negotiated, in which case the driver MUST set the VIRTIO_NET_HDR_GSO_UDP_TUNNEL
>+bit in the \field{gso_type}.
>+
>+The driver MUST NOT set the VIRTIO_NET_HDR_GSO_UDP_TUNNEL together with
>+VIRTIO_NET_HDR_GSO_UDP.
>+
> If the VIRTIO_NET_F_CSUM feature has been negotiated, the
> driver MAY set the VIRTIO_NET_HDR_F_NEEDS_CSUM bit in
> \field{flags}, if so:
>@@ -633,6 +687,18 @@ \subsubsection{Packet Transmission}\label{sec:Device Types / Network Device / De
> 	\end{note}
> \end{itemize}
>
>+If the VIRTIO_NET_F_HOST_UDP_TUNNEL_GSO option has been negotiated:
>+\begin{itemize}
>+\item If the \field{gso_type} has the VIRTIO_NET_HDR_GSO_UDP_TUNNEL bit set
>+	the device MUST use the \field{outer_th_offset}, \field{inner_protocol},
>+  \field{inner_mac_offset} and \field{inner_nh_offset} fields to
>+  locate the corresponding headers inside the packet.
>+\end{itemize}
>+
>+If VIRTIO_NET_HDR_GSO_UDP_TUNNEL bit in \field{gso_type} is not set, the
>+device MUST NOT use the \field{outer_th_offset}, \field{inner_protocol},
>+\field{inner_mac_offset} and \field{inner_nh_offset}.
>+
> If VIRTIO_NET_HDR_F_NEEDS_CSUM is not set, the device MUST NOT
> rely on the packet checksum being correct.
> \paragraph{Packet Transmission Interrupt}\label{sec:Device Types / Network Device / Device Operation / Packet Transmission / Packet Transmission Interrupt}
>@@ -727,8 +793,8 @@ \subsubsection{Processing of Incoming Packets}\label{sec:Device Types / Network
>   has been validated.
> \end{enumerate}
>
>-Additionally, VIRTIO_NET_F_GUEST_CSUM, TSO4, TSO6, UDP and ECN
>-features enable receive checksum, large receive offload and ECN
>+Additionally, VIRTIO_NET_F_GUEST_CSUM, TSO4, TSO6, UDP, UDP_TUNNEL
>+and ECN features enable receive checksum, large receive offload and ECN
> support which are the input equivalents of the transmit checksum,
> transmit segmentation offloading and ECN features, as described
> in \ref{sec:Device Types / Network Device / Device Operation /
>@@ -738,6 +804,15 @@ \subsubsection{Processing of Incoming Packets}\label{sec:Device Types / Network
>   negotiated, then \field{gso_type} MAY be something other than
>   VIRTIO_NET_HDR_GSO_NONE, and \field{gso_size} field indicates the
>   desired MSS (see Packet Transmission point 2).
>+\item If the VIRTIO_NET_F_GUEST_UDP_TUNNEL_GSO option was negotiated and
>+  \field{gso_type} is not VIRTIO_NET_HDR_GSO_NONE, the VIRTIO_NET_HDR_GSO_UDP_TUNNEL
>+  bit MAY be set. In such case the \field{outer_th_offset}, \field{inner_protocol},
>+  \field{inner_mac_offset} and \field{inner_nh_offset} fields indicates corresponding
>+  header information.
>+  Additionally, the VIRTIO_NET_HDR_F_UDP_TUNNEL_CSUM bit in the
>+  \field{flags} MAY be set, indicating that the outer UDP header
>+  carries the UDP pseudo header csum and that the driver can compute
>+  the full UDP checksum on top of it (see Packet Transmission point 3).
> \item If the VIRTIO_NET_F_RSC_EXT option was negotiated (this
>   implies one of VIRTIO_NET_F_GUEST_TSO4, TSO6), the
>   device processes also duplicated ACK segments, reports
>@@ -750,8 +825,9 @@ \subsubsection{Processing of Incoming Packets}\label{sec:Device Types / Network
>   from \field{csum_start} and any preceding checksums
>   have been validated.  The checksum on the packet is incomplete and
>   if bit VIRTIO_NET_HDR_F_RSC_INFO is not set in \field{flags},
>-  then \field{csum_start} and \field{csum_offset} indicate how to calculate it
>-  (see Packet Transmission point 1).
>+  then \field{csum_start} and \field{csum_offset} indicate how to calculate it.
>+  If the VIRTIO_NET_HDR_GSO_UDP_TUNNEL bit is set, the \field{csum_start} field
>+  refers to the inner transport header offset (see Packet Transmission point 1).
>
> \end{enumerate}
>
>@@ -800,6 +876,20 @@ \subsubsection{Processing of Incoming Packets}\label{sec:Device Types / Network
> which have the Explicit Congestion Notification bit set, unless the
> VIRTIO_NET_F_GUEST_ECN feature is negotiated, in which case the
> device MUST set the VIRTIO_NET_HDR_GSO_ECN bit in
>+
>+The device SHOULD NOT send to the driver TCP or UDP GSO packets encapsulated in UDP
>+tunnel and requiring segmentation offload, unless the
>+VIRTIO_NET_F_GUEST_UDP_TUNNEL_GSO is negotiated, in which case the device MUST set
>+the VIRTIO_NET_HDR_GSO_UDP_TUNNEL bit in \field{gso_type} and MUST set the
>+\field{outer_th_offset}, \field{inner_protocol}, \field{inner_mac_offset} and
>+\field{inner_nh_offset}. If the outer UDP header carries a non 0 checksum:
>+\begin{enumerate}
>+\item the device MUST set the VIRTIO_NET_HDR_F_UDP_TUNNEL_CSUM bit in
>+	\field{flags}
>+\item the device MUST set the outer UDP header checksum field to the outer
>+	UDP pseudo header sum
>+\end{enumerate}
>+
> \field{gso_type}.
>
> If the VIRTIO_NET_F_GUEST_CSUM feature has been negotiated, the
>@@ -819,6 +909,12 @@ \subsubsection{Processing of Incoming Packets}\label{sec:Device Types / Network
> 	fully checksummed packet;
> \end{enumerate}
>
>+\begin{note}
>+If the VIRTIO_NET_F_GUEST_UDP_TUNNEL_GSO feature is negotiated and the
>+VIRTIO_NET_HDR_GSO_UDP_TUNNEL bit is set, the VIRTIO_NET_HDR_F_NEEDS_CSUM
>+bit refers to the inner header checksum.
>+\end{note}
>+
> If none of the VIRTIO_NET_F_GUEST_TSO4, TSO6, UFO, USO4 or USO6 options have
> been negotiated, the device MUST set \field{gso_type} to
> VIRTIO_NET_HDR_GSO_NONE.
>@@ -842,8 +938,9 @@ \subsubsection{Processing of Incoming Packets}\label{sec:Device Types / Network
> If the VIRTIO_NET_F_GUEST_CSUM feature has been negotiated, the
> device MAY set the VIRTIO_NET_HDR_F_DATA_VALID bit in
> \field{flags}, if so, the device MUST validate the packet
>-checksum (in case of multiple encapsulated protocols, one level
>-of checksums is validated).
>+checksum. If the VIRTIO_NET_HDR_F_UDP_TUNNEL_CSUM
>+bit in \field{flags} is also set, the device MUST additionally validate
>+the outer UDP header checksum.
>
> \drivernormative{\paragraph}{Processing of Incoming
> Packets}{Device Types / Network Device / Device Operation /
>@@ -863,6 +960,10 @@ \subsubsection{Processing of Incoming Packets}\label{sec:Device Types / Network
> This is due to various bugs in implementations.
> \end{note}
>
>+If the VIRTIO_NET_HDR_GSO_UDP_TUNNEL_GSO bit in \field{gso_type} is not set,
>+the driver MUST NOT use the \field{outer_th_offset}, \field{inner_protocol},
>+\field{inner_mac_offset} and \field{inner_nh_offset}.
>+
> If neither VIRTIO_NET_HDR_F_NEEDS_CSUM nor
> VIRTIO_NET_HDR_F_DATA_VALID is set, the driver MUST NOT
> rely on the packet checksum being correct.
>@@ -1624,6 +1725,7 @@ \subsubsection{Control Virtqueue}\label{sec:Device Types / Network Device / Devi
> #define VIRTIO_NET_F_GUEST_TSO6       8
> #define VIRTIO_NET_F_GUEST_ECN        9
> #define VIRTIO_NET_F_GUEST_UFO        10
>+#define VIRTIO_NET_F_GUEST_UDP_TUNNEL_GSO 49
> #define VIRTIO_NET_F_GUEST_USO4       54
> #define VIRTIO_NET_F_GUEST_USO6       55
>
>-- 
>2.43.2
>
>