← Documents Documentation/networking/checksum-offloads.rst GitHub 원문 ↗

Linux 6.18.37 · Networking

Checksum Offloads

Linux 송신 checksum offload interface와 encapsulation에서 LCO·RCO가 inner·outer checksum을 처리하는 원리를 설명합니다.

Source pathDocumentation/networking/checksum-offloads.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약·해설

checksum-offloads.rst:1-143

TX Checksum Offload는 SKB가 지정한 한 checksum 계산을 NIC에 맡기는 interface입니다. Tunnel packet처럼 여러 checksum layer가 있을 때는 LCO가 inner checksum의 1의 보수 성질로 outer checksum을 미리 계산하거나, RCO가 receiver와의 protocol 합의를 통해 inner checksum 자체를 생략합니다. Device feature가 맞지 않으면 송신 검증 단계에서 software helper로 fallback합니다.

Checksum offload 기술 비교
기법줄이는 계산수행 위치추가 조건
TX Checksum Offload단일 checksumNICSKB start/offset 지원
LCOOuter checksum의 payload 재합산Local 송신 stackInner TX offload 예정
RCOInner checksum 자체송신·수신 양쪽Tunnel protocol과 receiver 지원

세 기법이 계산을 줄이는 위치와 요구 조건을 비교합니다.

TX checksum 위치 지정
Packet 시작`skb->csum_start`여기서 packet 끝까지 16-bit 1의 보수 합`csum_start + csum_offset`에 결과 기록
Checksum field의 기존 값합산에 포함TCP·UDP pseudo-header 보정값 전달

SKB의 두 field가 계산 범위와 결과를 쓸 위치를 정의합니다.

TX offload 제약
항목규칙
Checksum 수SKB당 하나만 offload
`csum_offset`음수 불가
IP header checksum항상 software 계산
CRC32c`skb->csum_not_inet` 설정
Encapsulation나머지 layer는 LCO·RCO 등으로 처리
GSOSegment마다 inner·outer checksum 수정 가능

Hardware와 driver가 SKB 요청을 해석할 때 지켜야 할 경계입니다.

Device feature 검증과 fallback
SKB가 offload 요청`validate_xmit_skb()``netdev->features`와 비교지원·활성Hardware offload
불일치`skb_csum_hwoffload_help()``skb_checksum_help()` 또는 CRC32c helperSoftware checksum

Stack은 늦은 송신 검증 지점에서 실제 device capability를 대조합니다.

LCO 1의 보수 원리
Outer header 합산`csum_start`에서 payload 합산 중단현재 inner checksum word의 보수를 더함Outer checksum 기록
NIC 또는 helper가 실제 inner checksum 기록기존 보정값이 상쇄Outer checksum도 자동으로 정확

Inner checksum이 나중에 채워져도 outer checksum이 맞아지는 산술 관계입니다.

LCO 적용 지점
Encapsulation함수·경로상태
UDP VXLAN·GENEVE`udp_set_csum()`LCO 적용
IPv6 UDP`udp6_set_csum()`LCO 적용
IPv4 GRE`net/ipv4/ip_gre.c:build_header()`LCO 적용
IPv6 GRE`net/ipv6/ip6_gre.c:ip6gre_xmit2()`Packet 전체 계산
공통 helper`include/linux/skbuff.h:lco_csum()`모든 LCO 구현

현재 구현 위치와 아직 최적화되지 않은 경로를 정리합니다.

Nested LCO
Inner payload + checksum offloadMiddle encapsulation headerOuter encapsulation headerOuter layer가 middle까지 합산
장점Payload 재합산 회피
비용Middle header 중복 합산

여러 tunnel layer에서도 계산은 안전하지만 중간 header를 반복 합산합니다.

RCO 협상 경계
Sender tunnel flag 활성Inner checksum 생략 표시Outer checksum offloadNetworkRCO 지원 receiverInner checksum 의미 복원
Receiver 미지원 가능성기본 비활성
VXLAN 예`VXLAN_F_REMCSUM_TX` per `struct vxlan_rdst`

RCO는 local 최적화가 아니라 양 끝점의 protocol 지원이 필요한 최적화입니다.

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
1 .. SPDX-License-Identifier: GPL-2.0
2
3 =================
4 Checksum Offloads
5 =================
6
7
8 Introduction
9 ============
10
11 This document describes a set of techniques in the Linux networking stack to
12 take advantage of checksum offload capabilities of various NICs.
13
14 The following technologies are described:
15
16 * TX Checksum Offload
17 * LCO: Local Checksum Offload
18 * RCO: Remote Checksum Offload
19
20 Things that should be documented here but aren't yet:
21
22 * RX Checksum Offload
23 * CHECKSUM_UNNECESSARY conversion
24
25
26 TX Checksum Offload
27 ===================
28
29 The interface for offloading a transmit checksum to a device is explained in
30 detail in comments near the top of include/linux/skbuff.h.
31
32 In brief, it allows to request the device fill in a single ones-complement
33 checksum defined by the sk_buff fields skb->csum_start and skb->csum_offset.
34 The device should compute the 16-bit ones-complement checksum (i.e. the
35 'IP-style' checksum) from csum_start to the end of the packet, and fill in the
36 result at (csum_start + csum_offset).
37
38 Because csum_offset cannot be negative, this ensures that the previous value of
39 the checksum field is included in the checksum computation, thus it can be used
40 to supply any needed corrections to the checksum (such as the sum of the
41 pseudo-header for UDP or TCP).
42
43 This interface only allows a single checksum to be offloaded. Where
44 encapsulation is used, the packet may have multiple checksum fields in
45 different header layers, and the rest will have to be handled by another
46 mechanism such as LCO or RCO.
47
48 CRC32c can also be offloaded using this interface, by means of filling
49 skb->csum_start and skb->csum_offset as described above, and setting
50 skb->csum_not_inet: see skbuff.h comment (section 'D') for more details.
51
52 No offloading of the IP header checksum is performed; it is always done in
53 software. This is OK because when we build the IP header, we obviously have it
54 in cache, so summing it isn't expensive. It's also rather short.
55
56 The requirements for GSO are more complicated, because when segmenting an
57 encapsulated packet both the inner and outer checksums may need to be edited or
58 recomputed for each resulting segment. See the skbuff.h comment (section 'E')
59 for more details.
60
61 A driver declares its offload capabilities in netdev->hw_features; see
62 Documentation/networking/netdev-features.rst for more. Note that a device
63 which only advertises NETIF_F_IP[V6]_CSUM must still obey the csum_start and
64 csum_offset given in the SKB; if it tries to deduce these itself in hardware
65 (as some NICs do) the driver should check that the values in the SKB match
66 those which the hardware will deduce, and if not, fall back to checksumming in
67 software instead (with skb_csum_hwoffload_help() or one of the
68 skb_checksum_help() / skb_crc32c_csum_help functions, as mentioned in
69 include/linux/skbuff.h).
70
71 The stack should, for the most part, assume that checksum offload is supported
72 by the underlying device. The only place that should check is
73 validate_xmit_skb(), and the functions it calls directly or indirectly. That
74 function compares the offload features requested by the SKB (which may include
75 other offloads besides TX Checksum Offload) and, if they are not supported or
76 enabled on the device (determined by netdev->features), performs the
77 corresponding offload in software. In the case of TX Checksum Offload, that
78 means calling skb_csum_hwoffload_help(skb, features).
79
80
81 LCO: Local Checksum Offload
82 ===========================
83
84 LCO is a technique for efficiently computing the outer checksum of an
85 encapsulated datagram when the inner checksum is due to be offloaded.
86
87 The ones-complement sum of a correctly checksummed TCP or UDP packet is equal
88 to the complement of the sum of the pseudo header, because everything else gets
89 'cancelled out' by the checksum field. This is because the sum was
90 complemented before being written to the checksum field.
91
92 More generally, this holds in any case where the 'IP-style' ones complement
93 checksum is used, and thus any checksum that TX Checksum Offload supports.
94
95 That is, if we have set up TX Checksum Offload with a start/offset pair, we
96 know that after the device has filled in that checksum, the ones complement sum
97 from csum_start to the end of the packet will be equal to the complement of
98 whatever value we put in the checksum field beforehand. This allows us to
99 compute the outer checksum without looking at the payload: we simply stop
100 summing when we get to csum_start, then add the complement of the 16-bit word
101 at (csum_start + csum_offset).
102
103 Then, when the true inner checksum is filled in (either by hardware or by
104 skb_checksum_help()), the outer checksum will become correct by virtue of the
105 arithmetic.
106
107 LCO is performed by the stack when constructing an outer UDP header for an
108 encapsulation such as VXLAN or GENEVE, in udp_set_csum(). Similarly for the
109 IPv6 equivalents, in udp6_set_csum().
110
111 It is also performed when constructing an IPv4 GRE header, in
112 net/ipv4/ip_gre.c:build_header(). It is *not* currently performed when
113 constructing an IPv6 GRE header; the GRE checksum is computed over the whole
114 packet in net/ipv6/ip6_gre.c:ip6gre_xmit2(), but it should be possible to use
115 LCO here as IPv6 GRE still uses an IP-style checksum.
116
117 All of the LCO implementations use a helper function lco_csum(), in
118 include/linux/skbuff.h.
119
120 LCO can safely be used for nested encapsulations; in this case, the outer
121 encapsulation layer will sum over both its own header and the 'middle' header.
122 This does mean that the 'middle' header will get summed multiple times, but
123 there doesn't seem to be a way to avoid that without incurring bigger costs
124 (e.g. in SKB bloat).
125
126
127 RCO: Remote Checksum Offload
128 ============================
129
130 RCO is a technique for eliding the inner checksum of an encapsulated datagram,
131 allowing the outer checksum to be offloaded. It does, however, involve a
132 change to the encapsulation protocols, which the receiver must also support.
133 For this reason, it is disabled by default.
134
135 RCO is detailed in the following Internet-Drafts:
136
137 * https://tools.ietf.org/html/draft-herbert-remotecsumoffload-00
138 * https://tools.ietf.org/html/draft-herbert-vxlan-rco-00
139
140 In Linux, RCO is implemented individually in each encapsulation protocol, and
141 most tunnel types have flags controlling its use. For instance, VXLAN has the
142 flag VXLAN_F_REMCSUM_TX (per struct vxlan_rdst) to indicate that RCO should be
143 used when transmitting to a given remote destination.
144

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

Checksum offload 개요와 문서 범위

1-22

Checksum Offload

소개

이 문서는 다양한 NIC의 checksum offload 기능을 활용하기 위해 Linux networking stack에서 사용하는 여러 기법을 설명합니다.

여기서 다루는 기술은 다음과 같습니다.

  • TX Checksum Offload
  • LCO(Local Checksum Offload)
  • RCO(Remote Checksum Offload)

다음 항목도 이 문서에서 다뤄야 하지만 아직 작성되지 않았습니다.

  • RX Checksum Offload
  • `CHECKSUM_UNNECESSARY` 변환
.. SPDX-License-Identifier: GPL-2.0

=================
Checksum Offloads
=================


Introduction
============

This document describes a set of techniques in the Linux networking stack to
take advantage of checksum offload capabilities of various NICs.

The following technologies are described:

* TX Checksum Offload
* LCO: Local Checksum Offload
* RCO: Remote Checksum Offload

Things that should be documented here but aren't yet:

* RX Checksum Offload

TX Checksum Offload interface와 fallback

23-81

TX Checksum Offload

송신 checksum 계산을 device에 offload하는 interface는 `include/linux/skbuff.h` 앞부분의 주석에 자세히 설명되어 있습니다.

간단히 말해 이 interface는 `sk_buff`의 `skb->csum_start`와 `skb->csum_offset` field로 정의한 단일 1의 보수 checksum을 device가 채우도록 요청합니다. Device는 `csum_start`부터 packet 끝까지 16-bit 1의 보수 checksum, 즉 IP 방식 checksum을 계산하고 그 결과를 `(csum_start + csum_offset)` 위치에 써야 합니다.

`csum_offset`은 음수가 될 수 없으므로 checksum field의 이전 값도 checksum 계산에 반드시 포함됩니다. 따라서 이 값으로 UDP나 TCP의 pseudo-header 합처럼 checksum에 필요한 보정값을 제공할 수 있습니다.

이 interface는 checksum 하나만 offload할 수 있습니다. Encapsulation을 사용한 packet에는 서로 다른 header layer에 checksum field가 여러 개 있을 수 있으므로 나머지는 LCO나 RCO 같은 다른 기법으로 처리해야 합니다.

위와 같이 `skb->csum_start`와 `skb->csum_offset`을 채우고 `skb->csum_not_inet`을 설정하면 이 interface로 CRC32c도 offload할 수 있습니다. 자세한 내용은 `skbuff.h` 주석의 D절을 참고하십시오.

IP header checksum은 offload하지 않고 언제나 software에서 계산합니다. IP header를 만들 때는 해당 데이터가 이미 cache에 있으므로 합산 비용이 크지 않고 header 자체도 상당히 짧기 때문입니다.

GSO 요구 사항은 더 복잡합니다. Encapsulation된 packet을 segment로 나누면 결과 segment마다 inner checksum과 outer checksum을 모두 수정하거나 다시 계산해야 할 수 있습니다. 자세한 내용은 `skbuff.h` 주석의 E절을 참고하십시오.

Driver는 `netdev->hw_features`에 offload capability를 선언합니다. 자세한 내용은 `Documentation/networking/netdev-features.rst`를 참고하십시오. `NETIF_F_IP[V6]_CSUM`만 알리는 device도 SKB가 지정한 `csum_start`와 `csum_offset`을 따라야 합니다.

일부 NIC처럼 hardware가 이 위치를 자체적으로 추론한다면 driver는 SKB의 값이 hardware가 추론할 값과 일치하는지 검사해야 합니다. 일치하지 않으면 `skb_csum_hwoffload_help()`, `skb_checksum_help()` 또는 `skb_crc32c_csum_help()`를 사용해 software checksum으로 fallback해야 합니다. 이 helper들은 `include/linux/skbuff.h`에도 언급되어 있습니다.

Networking stack은 대체로 아래쪽 device가 checksum offload를 지원한다고 가정해야 합니다. 지원 여부를 검사해야 하는 곳은 `validate_xmit_skb()`와 이 함수가 직접 또는 간접 호출하는 함수뿐입니다.

`validate_xmit_skb()`는 SKB가 요청한 offload feature와 `netdev->features`로 확인한 device의 지원·활성 feature를 비교합니다. 요청 feature에는 TX Checksum Offload 외의 offload도 포함될 수 있습니다. Device가 해당 feature를 지원하지 않거나 비활성화했다면 이 함수가 software로 해당 작업을 수행합니다. TX Checksum Offload의 경우 `skb_csum_hwoffload_help(skb, features)`를 호출합니다.

* CHECKSUM_UNNECESSARY conversion


TX Checksum Offload
===================

The interface for offloading a transmit checksum to a device is explained in
detail in comments near the top of include/linux/skbuff.h.

In brief, it allows to request the device fill in a single ones-complement
checksum defined by the sk_buff fields skb->csum_start and skb->csum_offset.
The device should compute the 16-bit ones-complement checksum (i.e. the
'IP-style' checksum) from csum_start to the end of the packet, and fill in the
result at (csum_start + csum_offset).

Because csum_offset cannot be negative, this ensures that the previous value of
the checksum field is included in the checksum computation, thus it can be used
to supply any needed corrections to the checksum (such as the sum of the
pseudo-header for UDP or TCP).

This interface only allows a single checksum to be offloaded.  Where
encapsulation is used, the packet may have multiple checksum fields in
different header layers, and the rest will have to be handled by another
mechanism such as LCO or RCO.

CRC32c can also be offloaded using this interface, by means of filling
skb->csum_start and skb->csum_offset as described above, and setting
skb->csum_not_inet: see skbuff.h comment (section 'D') for more details.

No offloading of the IP header checksum is performed; it is always done in
software.  This is OK because when we build the IP header, we obviously have it
in cache, so summing it isn't expensive.  It's also rather short.

The requirements for GSO are more complicated, because when segmenting an
encapsulated packet both the inner and outer checksums may need to be edited or
recomputed for each resulting segment.  See the skbuff.h comment (section 'E')
for more details.

A driver declares its offload capabilities in netdev->hw_features; see
Documentation/networking/netdev-features.rst for more.  Note that a device
which only advertises NETIF_F_IP[V6]_CSUM must still obey the csum_start and
csum_offset given in the SKB; if it tries to deduce these itself in hardware
(as some NICs do) the driver should check that the values in the SKB match
those which the hardware will deduce, and if not, fall back to checksumming in
software instead (with skb_csum_hwoffload_help() or one of the
skb_checksum_help() / skb_crc32c_csum_help functions, as mentioned in
include/linux/skbuff.h).

The stack should, for the most part, assume that checksum offload is supported
by the underlying device.  The only place that should check is
validate_xmit_skb(), and the functions it calls directly or indirectly.  That
function compares the offload features requested by the SKB (which may include
other offloads besides TX Checksum Offload) and, if they are not supported or
enabled on the device (determined by netdev->features), performs the
corresponding offload in software.  In the case of TX Checksum Offload, that
means calling skb_csum_hwoffload_help(skb, features).


LCO: Local Checksum Offload

LCO의 1의 보수 산술과 tunnel 적용

82-126

LCO: Local Checksum Offload

LCO는 inner checksum을 offload할 예정인 encapsulated datagram에서 outer checksum을 효율적으로 계산하는 기법입니다.

Checksum이 올바른 TCP 또는 UDP packet의 1의 보수 합은 pseudo-header 합의 보수와 같습니다. Checksum field를 제외한 나머지 값은 checksum field에 의해 서로 상쇄되기 때문입니다. 이는 합을 checksum field에 쓰기 전에 보수로 만들었기 때문에 성립합니다.

더 일반적으로 이 성질은 IP 방식 1의 보수 checksum을 쓰는 모든 경우, 즉 TX Checksum Offload가 지원하는 모든 checksum에 적용됩니다.

따라서 start/offset 쌍으로 TX Checksum Offload를 설정했다면 device가 checksum을 채운 뒤 `csum_start`부터 packet 끝까지의 1의 보수 합이 checksum field에 미리 넣어 둔 값의 보수와 같아진다는 사실을 알 수 있습니다.

이 성질을 이용하면 payload를 읽지 않고 outer checksum을 계산할 수 있습니다. `csum_start`에 도달하면 합산을 멈추고 `(csum_start + csum_offset)` 위치의 16-bit word에 대한 보수를 더하기만 하면 됩니다.

그 뒤 실제 inner checksum을 hardware 또는 `skb_checksum_help()`가 채우면 1의 보수 산술에 따라 outer checksum도 올바른 값이 됩니다.

Stack은 VXLAN이나 GENEVE 같은 encapsulation의 outer UDP header를 만들 때 `udp_set_csum()`에서 LCO를 수행합니다. IPv6에 대응하는 작업은 `udp6_set_csum()`에서 수행합니다.

IPv4 GRE header를 만들 때도 `net/ipv4/ip_gre.c:build_header()`에서 LCO를 수행합니다. 현재 IPv6 GRE header를 만들 때는 LCO를 수행하지 않습니다. 대신 `net/ipv6/ip6_gre.c:ip6gre_xmit2()`가 packet 전체의 GRE checksum을 계산합니다. IPv6 GRE 역시 IP 방식 checksum을 사용하므로 여기에도 LCO를 적용할 수 있을 것입니다.

모든 LCO 구현은 `include/linux/skbuff.h`에 있는 `lco_csum()` helper function을 사용합니다.

LCO는 nested encapsulation에도 안전하게 사용할 수 있습니다. 이 경우 outer encapsulation layer는 자신의 header와 중간 header를 모두 합산합니다. 이 때문에 중간 header가 여러 번 합산되지만 SKB 크기 증가 같은 더 큰 비용 없이 이를 피할 방법은 없어 보입니다.

===========================

LCO is a technique for efficiently computing the outer checksum of an
encapsulated datagram when the inner checksum is due to be offloaded.

The ones-complement sum of a correctly checksummed TCP or UDP packet is equal
to the complement of the sum of the pseudo header, because everything else gets
'cancelled out' by the checksum field.  This is because the sum was
complemented before being written to the checksum field.

More generally, this holds in any case where the 'IP-style' ones complement
checksum is used, and thus any checksum that TX Checksum Offload supports.

That is, if we have set up TX Checksum Offload with a start/offset pair, we
know that after the device has filled in that checksum, the ones complement sum
from csum_start to the end of the packet will be equal to the complement of
whatever value we put in the checksum field beforehand.  This allows us to
compute the outer checksum without looking at the payload: we simply stop
summing when we get to csum_start, then add the complement of the 16-bit word
at (csum_start + csum_offset).

Then, when the true inner checksum is filled in (either by hardware or by
skb_checksum_help()), the outer checksum will become correct by virtue of the
arithmetic.

LCO is performed by the stack when constructing an outer UDP header for an
encapsulation such as VXLAN or GENEVE, in udp_set_csum().  Similarly for the
IPv6 equivalents, in udp6_set_csum().

It is also performed when constructing an IPv4 GRE header, in
net/ipv4/ip_gre.c:build_header().  It is *not* currently performed when
constructing an IPv6 GRE header; the GRE checksum is computed over the whole
packet in net/ipv6/ip6_gre.c:ip6gre_xmit2(), but it should be possible to use
LCO here as IPv6 GRE still uses an IP-style checksum.

All of the LCO implementations use a helper function lco_csum(), in
include/linux/skbuff.h.

LCO can safely be used for nested encapsulations; in this case, the outer
encapsulation layer will sum over both its own header and the 'middle' header.
This does mean that the 'middle' header will get summed multiple times, but
there doesn't seem to be a way to avoid that without incurring bigger costs
(e.g. in SKB bloat).

RCO protocol 지원과 Linux tunnel flag

127-143

RCO: Remote Checksum Offload

RCO는 encapsulated datagram의 inner checksum을 생략하여 outer checksum을 offload할 수 있게 하는 기법입니다. 다만 encapsulation protocol을 변경해야 하고 receiver도 이를 지원해야 합니다. 이런 이유로 기본값은 비활성화입니다.

RCO의 자세한 내용은 다음 Internet-Draft에서 설명합니다.

  • https://tools.ietf.org/html/draft-herbert-remotecsumoffload-00
  • https://tools.ietf.org/html/draft-herbert-vxlan-rco-00

Linux에서 RCO는 각 encapsulation protocol이 개별적으로 구현하며, 대부분의 tunnel type에는 사용 여부를 제어하는 flag가 있습니다. 예를 들어 VXLAN은 특정 remote destination으로 송신할 때 RCO를 사용해야 함을 나타내기 위해 `struct vxlan_rdst`별 `VXLAN_F_REMCSUM_TX` flag를 둡니다.

RCO: Remote Checksum Offload
============================

RCO is a technique for eliding the inner checksum of an encapsulated datagram,
allowing the outer checksum to be offloaded.  It does, however, involve a
change to the encapsulation protocols, which the receiver must also support.
For this reason, it is disabled by default.

RCO is detailed in the following Internet-Drafts:

* https://tools.ietf.org/html/draft-herbert-remotecsumoffload-00
* https://tools.ietf.org/html/draft-herbert-vxlan-rco-00

In Linux, RCO is implemented individually in each encapsulation protocol, and
most tunnel types have flags controlling its use.  For instance, VXLAN has the
flag VXLAN_F_REMCSUM_TX (per struct vxlan_rdst) to indicate that RCO should be
used when transmitting to a given remote destination.