-
Notifications
You must be signed in to change notification settings - Fork 2.8k
/
mtu.go
206 lines (175 loc) · 6.34 KB
/
mtu.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
// SPDX-License-Identifier: Apache-2.0
// Copyright Authors of Cilium
package mtu
import (
"net"
)
const (
// MaxMTU is the highest MTU that can be used for devices and routes
// handled by Cilium. It will typically be used to configure inbound
// paths towards containers where it is guaranteed that the packet will
// not be rerouted to another node, and therefore will not lead to
// any form of IP fragmentation.
// One might expect this to be 65535, however Linux seems to cap the
// MTU of routes at 65520, so we use this value below.
MaxMTU = 65520
// EthernetMTU is the standard MTU for Ethernet devices. It is used
// as the MTU for container devices when running direct routing mode.
EthernetMTU = 1500
// TunnelOverhead is an approximation for bytes used for tunnel
// encapsulation. It accounts for:
// (Outer ethernet is not accounted against MTU size)
// Outer IPv4 header: 20B
// Outer UDP header: 8B
// Outer VXLAN header: 8B
// Original Ethernet: 14B
// ---
// Total extra bytes: 50B
TunnelOverhead = 50
// DsrTunnelOverhead is about the GENEVE DSR option that gets inserted
// by the LB, when addressing a Service in hs-ipcache mode
DsrTunnelOverhead = 12
// EncryptionIPsecOverhead is an approximation for bytes used for
// encryption. Depending on key size and encryption type the actual
// size may vary here we do calculations for 128B keys and Auth. The
// overhead is accounted for as:
// Outer IP header: 20B
// SPI: 4B
// Sequece Numbers: 4B
// Next Header: 1B
// ICV: 16B
// Padding: 16B
// 128bit Auth: 16B
// ---
// Total extra bytes: 77B
EncryptionIPsecOverhead = 77
// EncryptionDefaultAuthKeyLength is 16 representing 128B key recommended
// size for GCM(AES*) in RFC4106. Users may input other lengths via
// key secrets.
EncryptionDefaultAuthKeyLength = 16
// WireguardOverhead is an approximation for the overhead of WireGuard
// encapsulation.
//
// https://github.com/torvalds/linux/blob/v5.12/drivers/net/wireguard/device.c#L262:
// MESSAGE_MINIMUM_LENGTH: 32B
// Outer IPv4 or IPv6 header: 40B
// Outer UDP header: 8B
// ---
// Total extra bytes: 80B
WireguardOverhead = 80
)
// Configuration is an MTU configuration as returned by NewConfiguration
type Configuration struct {
// standardMTU is the regular MTU used for configuring devices and
// routes where packets are expected to be delivered outside the node.
//
// Note that this is a singleton for the process including this
// package. This means, for instance, that when using this from the
// ``pkg/plugins/*`` sources, it will not respect the settings
// configured inside the ``daemon/``.
standardMTU int
// tunnelMTU is the MTU used for configuring a tunnel mesh for
// inter-node connectivity.
//
// Similar to StandardMTU, this is a singleton for the process.
tunnelMTU int
// preEncrypMTU is the MTU used for configurations of a encryption route.
// If tunneling is enabled the tunnelMTU is used which will include
// additional encryption overhead if needed.
preEncryptMTU int
// postEncryptMTU is the MTU used for configurations of a encryption
// route _after_ encryption tags have been addded. These will be used
// in the encryption routing table. The MTU accounts for the tunnel
// overhead, if any, but assumes packets are already encrypted.
postEncryptMTU int
encapEnabled bool
encryptEnabled bool
wireguardEnabled bool
}
// NewConfiguration returns a new MTU configuration. The MTU can be manually
// specified, otherwise it will be automatically detected. if encapEnabled is
// true, the MTU is adjusted to account for encapsulation overhead for all
// routes involved in node to node communication.
func NewConfiguration(authKeySize int, encryptEnabled bool, encapEnabled bool, wireguardEnabled bool, hsIpcacheDSRenabled bool, mtu int, mtuDetectIP net.IP) Configuration {
encryptOverhead := 0
if mtu == 0 {
var err error
if mtuDetectIP != nil {
mtu, err = getMTUFromIf(mtuDetectIP)
} else {
mtu, err = autoDetect()
}
if err != nil {
log.WithError(err).Warning("Unable to automatically detect MTU")
mtu = EthernetMTU
}
}
if encryptEnabled {
// Add the difference between the default and the actual key sizes here
// to account for users specifying non-default auth key lengths.
encryptOverhead = EncryptionIPsecOverhead + (authKeySize - EncryptionDefaultAuthKeyLength)
}
fullTunnelOverhead := TunnelOverhead
if hsIpcacheDSRenabled {
fullTunnelOverhead += DsrTunnelOverhead
}
conf := Configuration{
standardMTU: mtu,
tunnelMTU: mtu - (fullTunnelOverhead + encryptOverhead),
postEncryptMTU: mtu - TunnelOverhead,
preEncryptMTU: mtu - encryptOverhead,
encapEnabled: encapEnabled,
encryptEnabled: encryptEnabled,
wireguardEnabled: wireguardEnabled,
}
if conf.tunnelMTU < 0 {
conf.tunnelMTU = 0
}
return conf
}
// GetRoutePostEncryptMTU return the MTU to be used on the encryption routing
// table. This is the MTU without encryption overhead and in the tunnel
// case accounts for the tunnel overhead.
func (c *Configuration) GetRoutePostEncryptMTU() int {
if c.encapEnabled {
if c.postEncryptMTU == 0 {
return EthernetMTU - TunnelOverhead
}
return c.postEncryptMTU
}
return c.GetDeviceMTU()
}
// GetRouteMTU returns the MTU to be used on the network. When running in
// tunneling mode and/or with encryption enabled, this will have tunnel and
// encryption overhead accounted for.
func (c *Configuration) GetRouteMTU() int {
if c.wireguardEnabled {
if c.encapEnabled {
return c.GetDeviceMTU() - (WireguardOverhead + TunnelOverhead)
}
return c.GetDeviceMTU() - WireguardOverhead
}
if !c.encapEnabled && !c.encryptEnabled {
return c.GetDeviceMTU()
}
if c.encryptEnabled && !c.encapEnabled {
if c.preEncryptMTU == 0 {
return EthernetMTU - EncryptionIPsecOverhead
}
return c.preEncryptMTU
}
if c.tunnelMTU == 0 {
if c.encryptEnabled {
return EthernetMTU - (TunnelOverhead + EncryptionIPsecOverhead)
}
return EthernetMTU - TunnelOverhead
}
return c.tunnelMTU
}
// GetDeviceMTU returns the MTU to be used on workload facing devices.
func (c *Configuration) GetDeviceMTU() int {
if c.standardMTU == 0 {
return EthernetMTU
}
return c.standardMTU
}