Merge ~nicolasbock/netplan:tristate-jammy into ~ubuntu-core-dev/netplan/+git/ubuntu:ubuntu/jammy
- Git
- lp:~nicolasbock/netplan
- tristate-jammy
- Merge into ubuntu/jammy
Proposed by
Nicolas Bock
Status: | Rejected | ||||
---|---|---|---|---|---|
Rejected by: | Lukas Märdian | ||||
Proposed branch: | ~nicolasbock/netplan:tristate-jammy | ||||
Merge into: | ~ubuntu-core-dev/netplan/+git/ubuntu:ubuntu/jammy | ||||
Diff against target: |
1067 lines (+779/-73) 12 files modified
debian/changelog (+7/-2) debian/patches/0003-Add-tristate-type-for-offload-options-LP-1956264-270.patch (+534/-0) debian/patches/series (+1/-0) doc/netplan.md (+18/-18) netplan/cli/commands/apply.py (+10/-1) src/netplan.c (+14/-7) src/networkd.c (+28/-21) src/parse.c (+48/-7) src/types.c (+8/-0) src/types.h (+28/-7) tests/generator/test_ethernets.py (+24/-10) tests/integration/ethernets.py (+59/-0) |
||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Lukas Märdian | Needs Fixing | ||
Review via email: mp+424017@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Revision history for this message
Lukas Märdian (slyon) wrote : | # |
I've integrated the changes and uploaded them for Focal & Jammy SRU.
Unmerged commits
- 4371541... by Nicolas Bock
-
Backport offloading tristate patches (dc3b335), LP: #1956264
- d/p/0003-
Add-tristate- type-for- offload- options- LP-1956264- 270.patch Signed-off-by: Nicolas Bock <email address hidden>
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/debian/changelog b/debian/changelog |
2 | index 0a35b63..3548933 100644 |
3 | --- a/debian/changelog |
4 | +++ b/debian/changelog |
5 | @@ -1,9 +1,14 @@ |
6 | -netplan.io (0.104-0ubuntu2.1) UNRELEASED; urgency=medium |
7 | +netplan.io (0.104-0ubuntu2.2) UNRELEASED; urgency=medium |
8 | |
9 | + [ Lukas Märdian ] |
10 | * Cherry-pick fix for rendering WPA3 password (8934a1b), LP: #1975576 |
11 | + d/p/0010-nm-fix-rendering-of-password-for-unknown-passthrough.patch |
12 | |
13 | - -- Lukas Märdian <slyon@ubuntu.com> Tue, 24 May 2022 11:15:29 +0200 |
14 | + [ Nicolas Bock ] |
15 | + * Backport offloading tristate patches (dc3b335), LP: #1956264 |
16 | + + d/p/0003-Add-tristate-type-for-offload-options-LP-1956264-270.patch |
17 | + |
18 | + -- Nicolas Bock <nicolas.bock@canonical.com> Mon, 06 Jun 2022 16:20:44 -0600 |
19 | |
20 | netplan.io (0.104-0ubuntu2) jammy; urgency=medium |
21 | |
22 | diff --git a/debian/patches/0003-Add-tristate-type-for-offload-options-LP-1956264-270.patch b/debian/patches/0003-Add-tristate-type-for-offload-options-LP-1956264-270.patch |
23 | new file mode 100644 |
24 | index 0000000..62af06c |
25 | --- /dev/null |
26 | +++ b/debian/patches/0003-Add-tristate-type-for-offload-options-LP-1956264-270.patch |
27 | @@ -0,0 +1,534 @@ |
28 | +From: Nicolas Bock <nicolas.bock@canonical.com> |
29 | +Date: Thu, 12 May 2022 01:18:36 -0600 |
30 | +Subject: Add tristate type for offload options (LP: #1956264) (#270) |
31 | +MIME-Version: 1.0 |
32 | +Content-Type: text/plain; charset="utf-8" |
33 | +Content-Transfer-Encoding: 8bit |
34 | + |
35 | +Closes: https://bugs.launchpad.net/netplan/+bug/1956264 |
36 | + |
37 | +COMMITS: |
38 | +* Add tristate type for offload options |
39 | +* Clarify name matching issues for `networkd` |
40 | +* Fix tests for offload |
41 | +* cli: apply: properly change udev/.link offloading settings |
42 | +* Re-used existing offloading fields, they are ABI compatible |
43 | +Size: |
44 | +Both enum and gboolean reduce to integer, so they are of same size. |
45 | +Content: |
46 | +An old consumer looking at these will interpret UNSET as if it was TRUE, |
47 | +which is the kernel's default (=UNSET) value. |
48 | +* CI: quirk to add ethtool test dependency |
49 | +* tests: ethernets: link offloading validation |
50 | +* doc: be more specific with the offloading docs |
51 | + |
52 | +Co-authored-by: Lukas Märdian <slyon@ubuntu.com> |
53 | +--- |
54 | + doc/netplan.md | 36 ++++++++++++------------ |
55 | + netplan/cli/commands/apply.py | 11 +++++++- |
56 | + src/netplan.c | 21 +++++++++----- |
57 | + src/networkd.c | 49 ++++++++++++++++++-------------- |
58 | + src/parse.c | 55 +++++++++++++++++++++++++++++++----- |
59 | + src/types.c | 8 ++++++ |
60 | + src/types.h | 35 ++++++++++++++++++----- |
61 | + tests/generator/test_ethernets.py | 34 +++++++++++++++------- |
62 | + tests/integration/ethernets.py | 59 +++++++++++++++++++++++++++++++++++++++ |
63 | + 9 files changed, 237 insertions(+), 71 deletions(-) |
64 | + |
65 | +diff --git a/doc/netplan.md b/doc/netplan.md |
66 | +index e9b4e92..373e05d 100644 |
67 | +--- a/doc/netplan.md |
68 | ++++ b/doc/netplan.md |
69 | +@@ -79,6 +79,10 @@ Virtual devices |
70 | + |
71 | + ## Common properties for physical device types |
72 | + |
73 | ++**Note:** Some options will not work reliably for devices matched by name only |
74 | ++and rendered by networkd, due to interactions with device renaming in udev. |
75 | ++Match devices by MAC when setting options like: ``wakeonlan`` or ``*-offload``. |
76 | ++ |
77 | + ``match`` (mapping) |
78 | + |
79 | + : This selects a subset of available physical devices by various hardware |
80 | +@@ -139,54 +143,50 @@ Virtual devices |
81 | + |
82 | + : Enable wake on LAN. Off by default. |
83 | + |
84 | +- **Note:** This will not work reliably for devices matched by name |
85 | +- only and rendered by networkd, due to interactions with device |
86 | +- renaming in udev. Match devices by MAC when setting wake on LAN. |
87 | +- |
88 | + ``emit-lldp`` (bool) – since **0.99** |
89 | + |
90 | + : (networkd backend only) Whether to emit LLDP packets. Off by default. |
91 | + |
92 | + ``receive-checksum-offload`` (bool) – since **0.104** |
93 | + |
94 | +-: (networkd backend only) If set to true, the hardware offload for |
95 | +- checksumming of ingress network packets is enabled. When unset, |
96 | ++: (networkd backend only) If set to true (false), the hardware offload for |
97 | ++ checksumming of ingress network packets is enabled (disabled). When unset, |
98 | + the kernel's default will be used. |
99 | + |
100 | + ``transmit-checksum-offload`` (bool) – since **0.104** |
101 | + |
102 | +-: (networkd backend only) If set to true, the hardware offload for |
103 | +- checksumming of egress network packets is enabled. When unset, |
104 | ++: (networkd backend only) If set to true (false), the hardware offload for |
105 | ++ checksumming of egress network packets is enabled (disabled). When unset, |
106 | + the kernel's default will be used. |
107 | + |
108 | + ``tcp-segmentation-offload`` (bool) – since **0.104** |
109 | + |
110 | +-: (networkd backend only) If set to true, the TCP Segmentation |
111 | +- Offload (TSO) is enabled. When unset, the kernel's default will |
112 | ++: (networkd backend only) If set to true (false), the TCP Segmentation |
113 | ++ Offload (TSO) is enabled (disabled). When unset, the kernel's default will |
114 | + be used. |
115 | + |
116 | + ``tcp6-segmentation-offload`` (bool) – since **0.104** |
117 | + |
118 | +-: (networkd backend only) If set to true, the TCP6 Segmentation |
119 | +- Offload (tx-tcp6-segmentation) is enabled. When unset, the |
120 | ++: (networkd backend only) If set to true (false), the TCP6 Segmentation |
121 | ++ Offload (tx-tcp6-segmentation) is enabled (disabled). When unset, the |
122 | + kernel's default will be used. |
123 | + |
124 | + ``generic-segmentation-offload`` (bool) – since **0.104** |
125 | + |
126 | +-: (networkd backend only) If set to true, the Generic Segmentation |
127 | +- Offload (GSO) is enabled. When unset, the kernel's default will |
128 | ++: (networkd backend only) If set to true (false), the Generic Segmentation |
129 | ++ Offload (GSO) is enabled (disabled). When unset, the kernel's default will |
130 | + be used. |
131 | + |
132 | + ``generic-receive-offload`` (bool) – since **0.104** |
133 | + |
134 | +-: (networkd backend only) If set to true, the Generic Receive |
135 | +- Offload (GRO) is enabled. When unset, the kernel's default will |
136 | ++: (networkd backend only) If set to true (false), the Generic Receive |
137 | ++ Offload (GRO) is enabled (disabled). When unset, the kernel's default will |
138 | + be used. |
139 | + |
140 | + ``large-receive-offload`` (bool) – since **0.104** |
141 | + |
142 | +-: (networkd backend only) If set to true, the Generic Receive |
143 | +- Offload (GRO) is enabled. When unset, the kernel's default will |
144 | ++: (networkd backend only) If set to true (false), the Large Receive Offload |
145 | ++ (LRO) is enabled (disabled). When unset, the kernel's default will |
146 | + be used. |
147 | + |
148 | + ``openvswitch`` (mapping) – since **0.100** |
149 | +diff --git a/netplan/cli/commands/apply.py b/netplan/cli/commands/apply.py |
150 | +index b36662a..9d4511f 100644 |
151 | +--- a/netplan/cli/commands/apply.py |
152 | ++++ b/netplan/cli/commands/apply.py |
153 | +@@ -221,13 +221,22 @@ class NetplanApply(utils.NetplanCommand): |
154 | + '/sys/class/net/' + device], |
155 | + stdout=subprocess.DEVNULL, |
156 | + stderr=subprocess.DEVNULL) |
157 | ++ subprocess.check_call(['udevadm', 'test', |
158 | ++ '/sys/class/net/' + device], |
159 | ++ stdout=subprocess.DEVNULL, |
160 | ++ stderr=subprocess.DEVNULL) |
161 | + except subprocess.CalledProcessError: |
162 | + logging.debug('Ignoring device without syspath: %s', device) |
163 | + |
164 | ++ devices_after_udev = netifaces.interfaces() |
165 | + # apply some more changes manually |
166 | + for iface, settings in changes.items(): |
167 | + # rename non-critical network interfaces |
168 | +- if settings.get('name'): |
169 | ++ new_name = settings.get('name') |
170 | ++ if new_name: |
171 | ++ if iface in devices and new_name in devices_after_udev: |
172 | ++ logging.debug('Interface rename {} -> {} already happened.'.format(iface, new_name)) |
173 | ++ continue # re-name already happened via 'udevadm test' |
174 | + # bring down the interface, using its current (matched) interface name |
175 | + subprocess.check_call(['ip', 'link', 'set', 'dev', iface, 'down'], |
176 | + stdout=subprocess.DEVNULL, |
177 | +diff --git a/src/netplan.c b/src/netplan.c |
178 | +index 7b387b4..d1a27a6 100644 |
179 | +--- a/src/netplan.c |
180 | ++++ b/src/netplan.c |
181 | +@@ -752,13 +752,20 @@ _serialize_yaml( |
182 | + YAML_BOOL_TRUE(def, event, emitter, "wakeonlan", def->wake_on_lan); |
183 | + |
184 | + /* Offload options */ |
185 | +- YAML_BOOL_TRUE(def, event, emitter, "receive-checksum-offload", def->receive_checksum_offload); |
186 | +- YAML_BOOL_TRUE(def, event, emitter, "transmit-checksum-offload", def->transmit_checksum_offload); |
187 | +- YAML_BOOL_TRUE(def, event, emitter, "tcp-segmentation-offload", def->tcp_segmentation_offload); |
188 | +- YAML_BOOL_TRUE(def, event, emitter, "tcp6-segmentation-offload", def->tcp6_segmentation_offload); |
189 | +- YAML_BOOL_TRUE(def, event, emitter, "generic-segmentation-offload", def->generic_segmentation_offload); |
190 | +- YAML_BOOL_TRUE(def, event, emitter, "generic-receive-offload", def->generic_receive_offload); |
191 | +- YAML_BOOL_TRUE(def, event, emitter, "large-receive-offload", def->large_receive_offload); |
192 | ++ if (def->receive_checksum_offload != NETPLAN_TRISTATE_UNSET) |
193 | ++ YAML_BOOL_TRUE(def, event, emitter, "receive-checksum-offload", def->receive_checksum_offload); |
194 | ++ if (def->transmit_checksum_offload != NETPLAN_TRISTATE_UNSET) |
195 | ++ YAML_BOOL_TRUE(def, event, emitter, "transmit-checksum-offload", def->transmit_checksum_offload); |
196 | ++ if (def->tcp_segmentation_offload != NETPLAN_TRISTATE_UNSET) |
197 | ++ YAML_BOOL_TRUE(def, event, emitter, "tcp-segmentation-offload", def->tcp_segmentation_offload); |
198 | ++ if (def->tcp6_segmentation_offload != NETPLAN_TRISTATE_UNSET) |
199 | ++ YAML_BOOL_TRUE(def, event, emitter, "tcp6-segmentation-offload", def->tcp6_segmentation_offload); |
200 | ++ if (def->generic_segmentation_offload != NETPLAN_TRISTATE_UNSET) |
201 | ++ YAML_BOOL_TRUE(def, event, emitter, "generic-segmentation-offload", def->generic_segmentation_offload); |
202 | ++ if (def->generic_receive_offload != NETPLAN_TRISTATE_UNSET) |
203 | ++ YAML_BOOL_TRUE(def, event, emitter, "generic-receive-offload", def->generic_receive_offload); |
204 | ++ if (def->large_receive_offload != NETPLAN_TRISTATE_UNSET) |
205 | ++ YAML_BOOL_TRUE(def, event, emitter, "large-receive-offload", def->large_receive_offload); |
206 | + |
207 | + if (def->wowlan && def->wowlan != NETPLAN_WIFI_WOWLAN_DEFAULT) { |
208 | + YAML_SCALAR_PLAIN(event, emitter, "wakeonwlan"); |
209 | +diff --git a/src/networkd.c b/src/networkd.c |
210 | +index 6d26047..62c87ce 100644 |
211 | +--- a/src/networkd.c |
212 | ++++ b/src/networkd.c |
213 | +@@ -243,13 +243,13 @@ write_link_file(const NetplanNetDefinition* def, const char* rootdir, const char |
214 | + if (!def->set_name && |
215 | + !def->wake_on_lan && |
216 | + !def->mtubytes && |
217 | +- !def->receive_checksum_offload && |
218 | +- !def->transmit_checksum_offload && |
219 | +- !def->tcp_segmentation_offload && |
220 | +- !def->tcp6_segmentation_offload && |
221 | +- !def->generic_segmentation_offload && |
222 | +- !def->generic_receive_offload && |
223 | +- !def->large_receive_offload) |
224 | ++ (def->receive_checksum_offload == NETPLAN_TRISTATE_UNSET) && |
225 | ++ (def->transmit_checksum_offload == NETPLAN_TRISTATE_UNSET) && |
226 | ++ (def->tcp_segmentation_offload == NETPLAN_TRISTATE_UNSET) && |
227 | ++ (def->tcp6_segmentation_offload == NETPLAN_TRISTATE_UNSET) && |
228 | ++ (def->generic_segmentation_offload == NETPLAN_TRISTATE_UNSET) && |
229 | ++ (def->generic_receive_offload == NETPLAN_TRISTATE_UNSET) && |
230 | ++ (def->large_receive_offload == NETPLAN_TRISTATE_UNSET)) |
231 | + return; |
232 | + |
233 | + /* build file contents */ |
234 | +@@ -265,26 +265,33 @@ write_link_file(const NetplanNetDefinition* def, const char* rootdir, const char |
235 | + g_string_append_printf(s, "MTUBytes=%u\n", def->mtubytes); |
236 | + |
237 | + /* Offload options */ |
238 | +- if (def->receive_checksum_offload) |
239 | +- g_string_append_printf(s, "ReceiveChecksumOffload=%u\n", def->receive_checksum_offload); |
240 | ++ if (def->receive_checksum_offload != NETPLAN_TRISTATE_UNSET) |
241 | ++ g_string_append_printf(s, "ReceiveChecksumOffload=%s\n", |
242 | ++ (def->receive_checksum_offload ? "true" : "false")); |
243 | + |
244 | +- if (def->transmit_checksum_offload) |
245 | +- g_string_append_printf(s, "TransmitChecksumOffload=%u\n", def->transmit_checksum_offload); |
246 | ++ if (def->transmit_checksum_offload != NETPLAN_TRISTATE_UNSET) |
247 | ++ g_string_append_printf(s, "TransmitChecksumOffload=%s\n", |
248 | ++ (def->transmit_checksum_offload ? "true" : "false")); |
249 | + |
250 | +- if (def->tcp_segmentation_offload) |
251 | +- g_string_append_printf(s, "TCPSegmentationOffload=%u\n", def->tcp_segmentation_offload); |
252 | ++ if (def->tcp_segmentation_offload != NETPLAN_TRISTATE_UNSET) |
253 | ++ g_string_append_printf(s, "TCPSegmentationOffload=%s\n", |
254 | ++ (def->tcp_segmentation_offload ? "true" : "false")); |
255 | + |
256 | +- if (def->tcp6_segmentation_offload) |
257 | +- g_string_append_printf(s, "TCP6SegmentationOffload=%u\n", def->tcp6_segmentation_offload); |
258 | ++ if (def->tcp6_segmentation_offload != NETPLAN_TRISTATE_UNSET) |
259 | ++ g_string_append_printf(s, "TCP6SegmentationOffload=%s\n", |
260 | ++ (def->tcp6_segmentation_offload ? "true" : "false")); |
261 | + |
262 | +- if (def->generic_segmentation_offload) |
263 | +- g_string_append_printf(s, "GenericSegmentationOffload=%u\n", def->generic_segmentation_offload); |
264 | ++ if (def->generic_segmentation_offload != NETPLAN_TRISTATE_UNSET) |
265 | ++ g_string_append_printf(s, "GenericSegmentationOffload=%s\n", |
266 | ++ (def->generic_segmentation_offload ? "true" : "false")); |
267 | + |
268 | +- if (def->generic_receive_offload) |
269 | +- g_string_append_printf(s, "GenericReceiveOffload=%u\n", def->generic_receive_offload); |
270 | ++ if (def->generic_receive_offload != NETPLAN_TRISTATE_UNSET) |
271 | ++ g_string_append_printf(s, "GenericReceiveOffload=%s\n", |
272 | ++ (def->generic_receive_offload ? "true" : "false")); |
273 | + |
274 | +- if (def->large_receive_offload) |
275 | +- g_string_append_printf(s, "LargeReceiveOffload=%u\n", def->large_receive_offload); |
276 | ++ if (def->large_receive_offload != NETPLAN_TRISTATE_UNSET) |
277 | ++ g_string_append_printf(s, "LargeReceiveOffload=%s\n", |
278 | ++ (def->large_receive_offload ? "true" : "false")); |
279 | + |
280 | + orig_umask = umask(022); |
281 | + g_string_free_to_file(s, rootdir, path, ".link"); |
282 | +diff --git a/src/parse.c b/src/parse.c |
283 | +index 350c508..0cb07d2 100644 |
284 | +--- a/src/parse.c |
285 | ++++ b/src/parse.c |
286 | +@@ -370,6 +370,37 @@ handle_generic_bool(NetplanParser* npp, yaml_node_t* node, void* entryptr, const |
287 | + return TRUE; |
288 | + } |
289 | + |
290 | ++/* |
291 | ++ * Handler for setting a HashTable field from a mapping node, inside a given struct |
292 | ++ * @entryptr: pointer to the beginning of the to-be-modified data structure |
293 | ++ * @data: offset into entryptr struct where the boolean field to write is located |
294 | ++ */ |
295 | ++static gboolean |
296 | ++handle_generic_tristate(NetplanParser* npp, yaml_node_t* node, void* entryptr, const void* data, GError** error) |
297 | ++{ |
298 | ++ g_assert(entryptr); |
299 | ++ NetplanTristate v; |
300 | ++ guint offset = GPOINTER_TO_UINT(data); |
301 | ++ NetplanTristate* dest = ((void*) entryptr + offset); |
302 | ++ |
303 | ++ if (g_ascii_strcasecmp(scalar(node), "true") == 0 || |
304 | ++ g_ascii_strcasecmp(scalar(node), "on") == 0 || |
305 | ++ g_ascii_strcasecmp(scalar(node), "yes") == 0 || |
306 | ++ g_ascii_strcasecmp(scalar(node), "y") == 0) |
307 | ++ v = NETPLAN_TRISTATE_TRUE; |
308 | ++ else if (g_ascii_strcasecmp(scalar(node), "false") == 0 || |
309 | ++ g_ascii_strcasecmp(scalar(node), "off") == 0 || |
310 | ++ g_ascii_strcasecmp(scalar(node), "no") == 0 || |
311 | ++ g_ascii_strcasecmp(scalar(node), "n") == 0) |
312 | ++ v = NETPLAN_TRISTATE_FALSE; |
313 | ++ else |
314 | ++ return yaml_error(npp, node, error, "invalid boolean value '%s'", scalar(node)); |
315 | ++ |
316 | ++ *dest = v; |
317 | ++ mark_data_as_dirty(npp, dest); |
318 | ++ return TRUE; |
319 | ++} |
320 | ++ |
321 | + /* |
322 | + * Handler for setting a HashTable field from a mapping node, inside a given struct |
323 | + * @entryptr: pointer to the beginning of the to-be-modified data structure |
324 | +@@ -516,6 +547,16 @@ handle_netdef_bool(NetplanParser* npp, yaml_node_t* node, const void* data, GErr |
325 | + return handle_generic_bool(npp, node, npp->current.netdef, data, error); |
326 | + } |
327 | + |
328 | ++/** |
329 | ++ * Generic handler for tri-state settings that can bei "UNSET", "TRUE", or "FALSE". |
330 | ++ * @data: offset into NetplanNetDefinition where the guint field to write is located |
331 | ++ */ |
332 | ++static gboolean |
333 | ++handle_netdef_tristate(NetplanParser* npp, yaml_node_t* node, const void* data, GError** error) |
334 | ++{ |
335 | ++ return handle_generic_tristate(npp, node, npp->current.netdef, data, error); |
336 | ++} |
337 | ++ |
338 | + /** |
339 | + * Generic handler for setting a npp->current.netdef guint field from a scalar node |
340 | + * @data: offset into NetplanNetDefinition where the guint field to write is located |
341 | +@@ -2356,13 +2397,13 @@ static const mapping_entry_handler dhcp6_overrides_handlers[] = { |
342 | + {"wakeonlan", YAML_SCALAR_NODE, {.generic=handle_netdef_bool}, netdef_offset(wake_on_lan)}, \ |
343 | + {"wakeonwlan", YAML_SEQUENCE_NODE, {.generic=handle_wowlan}, netdef_offset(wowlan)}, \ |
344 | + {"emit-lldp", YAML_SCALAR_NODE, {.generic=handle_netdef_bool}, netdef_offset(emit_lldp)}, \ |
345 | +- {"receive-checksum-offload", YAML_SCALAR_NODE, {.generic=handle_netdef_bool}, netdef_offset(receive_checksum_offload)}, \ |
346 | +- {"transmit-checksum-offload", YAML_SCALAR_NODE, {.generic=handle_netdef_bool}, netdef_offset(transmit_checksum_offload)}, \ |
347 | +- {"tcp-segmentation-offload", YAML_SCALAR_NODE, {.generic=handle_netdef_bool}, netdef_offset(tcp_segmentation_offload)}, \ |
348 | +- {"tcp6-segmentation-offload", YAML_SCALAR_NODE, {.generic=handle_netdef_bool}, netdef_offset(tcp6_segmentation_offload)}, \ |
349 | +- {"generic-segmentation-offload", YAML_SCALAR_NODE, {.generic=handle_netdef_bool}, netdef_offset(generic_segmentation_offload)}, \ |
350 | +- {"generic-receive-offload", YAML_SCALAR_NODE, {.generic=handle_netdef_bool}, netdef_offset(generic_receive_offload)}, \ |
351 | +- {"large-receive-offload", YAML_SCALAR_NODE, {.generic=handle_netdef_bool}, netdef_offset(large_receive_offload)} |
352 | ++ {"receive-checksum-offload", YAML_SCALAR_NODE, {.generic=handle_netdef_tristate}, netdef_offset(receive_checksum_offload)}, \ |
353 | ++ {"transmit-checksum-offload", YAML_SCALAR_NODE, {.generic=handle_netdef_tristate}, netdef_offset(transmit_checksum_offload)}, \ |
354 | ++ {"tcp-segmentation-offload", YAML_SCALAR_NODE, {.generic=handle_netdef_tristate}, netdef_offset(tcp_segmentation_offload)}, \ |
355 | ++ {"tcp6-segmentation-offload", YAML_SCALAR_NODE, {.generic=handle_netdef_tristate}, netdef_offset(tcp6_segmentation_offload)}, \ |
356 | ++ {"generic-segmentation-offload", YAML_SCALAR_NODE, {.generic=handle_netdef_tristate}, netdef_offset(generic_segmentation_offload)}, \ |
357 | ++ {"generic-receive-offload", YAML_SCALAR_NODE, {.generic=handle_netdef_tristate}, netdef_offset(generic_receive_offload)}, \ |
358 | ++ {"large-receive-offload", YAML_SCALAR_NODE, {.generic=handle_netdef_tristate}, netdef_offset(large_receive_offload)} |
359 | + |
360 | + static const mapping_entry_handler ethernet_def_handlers[] = { |
361 | + COMMON_LINK_HANDLERS, |
362 | +diff --git a/src/types.c b/src/types.c |
363 | +index eb9f780..00c2b0f 100644 |
364 | +--- a/src/types.c |
365 | ++++ b/src/types.c |
366 | +@@ -335,6 +335,14 @@ reset_netdef(NetplanNetDefinition* netdef, NetplanDefType new_type, NetplanBacke |
367 | + |
368 | + reset_private_netdef_data(netdef->_private); |
369 | + FREE_AND_NULLIFY(netdef->_private); |
370 | ++ |
371 | ++ netdef->receive_checksum_offload = NETPLAN_TRISTATE_UNSET; |
372 | ++ netdef->transmit_checksum_offload = NETPLAN_TRISTATE_UNSET; |
373 | ++ netdef->tcp_segmentation_offload = NETPLAN_TRISTATE_UNSET; |
374 | ++ netdef->tcp6_segmentation_offload = NETPLAN_TRISTATE_UNSET; |
375 | ++ netdef->generic_segmentation_offload = NETPLAN_TRISTATE_UNSET; |
376 | ++ netdef->generic_receive_offload = NETPLAN_TRISTATE_UNSET; |
377 | ++ netdef->large_receive_offload = NETPLAN_TRISTATE_UNSET; |
378 | + } |
379 | + |
380 | + static void |
381 | +diff --git a/src/types.h b/src/types.h |
382 | +index 27a23fc..710b1f1 100644 |
383 | +--- a/src/types.h |
384 | ++++ b/src/types.h |
385 | +@@ -171,6 +171,27 @@ typedef union { |
386 | + } networkd; |
387 | + } NetplanBackendSettings; |
388 | + |
389 | ++typedef enum |
390 | ++{ |
391 | ++ /** |
392 | ++ * @brief Tristate enum type |
393 | ++ * |
394 | ++ * This type defines a boolean which can be unset, i.e. |
395 | ++ * this type has three states. The enum is ordered so |
396 | ++ * that |
397 | ++ * |
398 | ++ * UNSET -> -1 |
399 | ++ * FALSE -> 0 |
400 | ++ * TRUE -> 1 |
401 | ++ * |
402 | ++ * And the integer values can be used directly when |
403 | ++ * converting to string. |
404 | ++ */ |
405 | ++ NETPLAN_TRISTATE_UNSET = -1, /* -1 */ |
406 | ++ NETPLAN_TRISTATE_FALSE, /* 0 */ |
407 | ++ NETPLAN_TRISTATE_TRUE, /* 1 */ |
408 | ++} NetplanTristate; |
409 | ++ |
410 | + struct netplan_net_definition { |
411 | + NetplanDefType type; |
412 | + NetplanBackend backend; |
413 | +@@ -333,13 +354,13 @@ struct netplan_net_definition { |
414 | + gboolean ignore_carrier; |
415 | + |
416 | + /* offload options */ |
417 | +- gboolean receive_checksum_offload; |
418 | +- gboolean transmit_checksum_offload; |
419 | +- gboolean tcp_segmentation_offload; |
420 | +- gboolean tcp6_segmentation_offload; |
421 | +- gboolean generic_segmentation_offload; |
422 | +- gboolean generic_receive_offload; |
423 | +- gboolean large_receive_offload; |
424 | ++ NetplanTristate receive_checksum_offload; |
425 | ++ NetplanTristate transmit_checksum_offload; |
426 | ++ NetplanTristate tcp_segmentation_offload; |
427 | ++ NetplanTristate tcp6_segmentation_offload; |
428 | ++ NetplanTristate generic_segmentation_offload; |
429 | ++ NetplanTristate generic_receive_offload; |
430 | ++ NetplanTristate large_receive_offload; |
431 | + |
432 | + struct private_netdef_data* _private; |
433 | + |
434 | +diff --git a/tests/generator/test_ethernets.py b/tests/generator/test_ethernets.py |
435 | +index 46bf764..e81941b 100644 |
436 | +--- a/tests/generator/test_ethernets.py |
437 | ++++ b/tests/generator/test_ethernets.py |
438 | +@@ -772,11 +772,11 @@ method=ignore |
439 | + ethernets: |
440 | + eth1: |
441 | + receive-checksum-offload: true |
442 | +- transmit-checksum-offload: true |
443 | ++ transmit-checksum-offload: off |
444 | + tcp-segmentation-offload: true |
445 | +- tcp6-segmentation-offload: true |
446 | ++ tcp6-segmentation-offload: false |
447 | + generic-segmentation-offload: true |
448 | +- generic-receive-offload: true |
449 | ++ generic-receive-offload: no |
450 | + large-receive-offload: true''') |
451 | + |
452 | + self.assert_networkd({'eth1.link': '''[Match] |
453 | +@@ -784,13 +784,13 @@ OriginalName=eth1 |
454 | + |
455 | + [Link] |
456 | + WakeOnLan=off |
457 | +-ReceiveChecksumOffload=1 |
458 | +-TransmitChecksumOffload=1 |
459 | +-TCPSegmentationOffload=1 |
460 | +-TCP6SegmentationOffload=1 |
461 | +-GenericSegmentationOffload=1 |
462 | +-GenericReceiveOffload=1 |
463 | +-LargeReceiveOffload=1 |
464 | ++ReceiveChecksumOffload=true |
465 | ++TransmitChecksumOffload=false |
466 | ++TCPSegmentationOffload=true |
467 | ++TCP6SegmentationOffload=false |
468 | ++GenericSegmentationOffload=true |
469 | ++GenericReceiveOffload=false |
470 | ++LargeReceiveOffload=true |
471 | + ''', |
472 | + 'eth1.network': '''[Match] |
473 | + Name=eth1 |
474 | +@@ -799,3 +799,17 @@ Name=eth1 |
475 | + LinkLocalAddressing=ipv6 |
476 | + '''}) |
477 | + self.assert_networkd_udev(None) |
478 | ++ |
479 | ++ def test_offload_invalid(self): |
480 | ++ err = self.generate('''network: |
481 | ++ version: 2 |
482 | ++ ethernets: |
483 | ++ eth1: |
484 | ++ generic-receive-offload: n |
485 | ++ receive-checksum-offload: true |
486 | ++ tcp-segmentation-offload: true |
487 | ++ tcp6-segmentation-offload: false |
488 | ++ generic-segmentation-offload: true |
489 | ++ transmit-checksum-offload: xx |
490 | ++ large-receive-offload: true''', expect_fail=True) |
491 | ++ self.assertIn('invalid boolean value \'xx\'', err) |
492 | +diff --git a/tests/integration/ethernets.py b/tests/integration/ethernets.py |
493 | +index 865c0d4..06ac069 100644 |
494 | +--- a/tests/integration/ethernets.py |
495 | ++++ b/tests/integration/ethernets.py |
496 | +@@ -236,6 +236,65 @@ class _CommonTests(): |
497 | + self.assert_iface_up('iface1', ['inet 10.10.10.11']) |
498 | + self.assert_iface_up('iface2', ['inet 10.10.10.22']) |
499 | + |
500 | ++ def test_link_offloading(self): |
501 | ++ self.setup_eth(None, False) |
502 | ++ # check kernel defaults |
503 | ++ out = subprocess.check_output(['ethtool', '-k', self.dev_e_client]) |
504 | ++ self.assertIn(b'rx-checksumming: on', out) |
505 | ++ self.assertIn(b'tx-checksumming: on', out) |
506 | ++ self.assertIn(b'tcp-segmentation-offload: on', out) |
507 | ++ self.assertIn(b'tx-tcp6-segmentation: on', out) |
508 | ++ self.assertIn(b'generic-segmentation-offload: on', out) |
509 | ++ self.assertIn(b'generic-receive-offload: off', out) # off by default |
510 | ++ # validate turning off |
511 | ++ with open(self.config, 'w') as f: |
512 | ++ f.write('''network: |
513 | ++ renderer: %(r)s |
514 | ++ ethernets: |
515 | ++ %(ec)s: |
516 | ++ addresses: [10.10.10.22/24] |
517 | ++ receive-checksum-offload: off |
518 | ++ transmit-checksum-offload: off |
519 | ++ tcp-segmentation-offload: off |
520 | ++ tcp6-segmentation-offload: off |
521 | ++ generic-segmentation-offload: off |
522 | ++ generic-receive-offload: off |
523 | ++ #large-receive-offload: off # not possible on veth |
524 | ++''' % {'r': self.backend, 'ec': self.dev_e_client}) |
525 | ++ self.generate_and_settle([self.dev_e_client]) |
526 | ++ self.assert_iface_up(self.dev_e_client, ['inet 10.10.10.22']) |
527 | ++ out = subprocess.check_output(['ethtool', '-k', self.dev_e_client]) |
528 | ++ self.assertIn(b'rx-checksumming: off', out) |
529 | ++ self.assertIn(b'tx-checksumming: off', out) |
530 | ++ self.assertIn(b'tcp-segmentation-offload: off', out) |
531 | ++ self.assertIn(b'tx-tcp6-segmentation: off', out) |
532 | ++ self.assertIn(b'generic-segmentation-offload: off', out) |
533 | ++ self.assertIn(b'generic-receive-offload: off', out) |
534 | ++ # validate turning on |
535 | ++ with open(self.config, 'w') as f: |
536 | ++ f.write('''network: |
537 | ++ renderer: %(r)s |
538 | ++ ethernets: |
539 | ++ %(ec)s: |
540 | ++ addresses: [10.10.10.22/24] |
541 | ++ receive-checksum-offload: true |
542 | ++ transmit-checksum-offload: true |
543 | ++ tcp-segmentation-offload: true |
544 | ++ tcp6-segmentation-offload: true |
545 | ++ generic-segmentation-offload: true |
546 | ++ generic-receive-offload: true |
547 | ++ #large-receive-offload: true # not possible on veth |
548 | ++''' % {'r': self.backend, 'ec': self.dev_e_client}) |
549 | ++ self.generate_and_settle([self.dev_e_client]) |
550 | ++ self.assert_iface_up(self.dev_e_client, ['inet 10.10.10.22']) |
551 | ++ out = subprocess.check_output(['ethtool', '-k', self.dev_e_client]) |
552 | ++ self.assertIn(b'rx-checksumming: on', out) |
553 | ++ self.assertIn(b'tx-checksumming: on', out) |
554 | ++ self.assertIn(b'tcp-segmentation-offload: on', out) |
555 | ++ self.assertIn(b'tx-tcp6-segmentation: on', out) |
556 | ++ self.assertIn(b'generic-segmentation-offload: on', out) |
557 | ++ self.assertIn(b'generic-receive-offload: on', out) |
558 | ++ |
559 | + |
560 | + @unittest.skipIf("networkd" not in test_backends, |
561 | + "skipping as networkd backend tests are disabled") |
562 | diff --git a/debian/patches/series b/debian/patches/series |
563 | index 27d8728..77cbaaa 100644 |
564 | --- a/debian/patches/series |
565 | +++ b/debian/patches/series |
566 | @@ -1,3 +1,4 @@ |
567 | +0003-Add-tristate-type-for-offload-options-LP-1956264-270.patch |
568 | autopkgtest-fixes.patch |
569 | 0002-cli-apply-fix-potential-race-with-rename-creation-of.patch |
570 | 0010-nm-fix-rendering-of-password-for-unknown-passthrough.patch |
571 | diff --git a/doc/netplan.md b/doc/netplan.md |
572 | index e9b4e92..373e05d 100644 |
573 | --- a/doc/netplan.md |
574 | +++ b/doc/netplan.md |
575 | @@ -79,6 +79,10 @@ Virtual devices |
576 | |
577 | ## Common properties for physical device types |
578 | |
579 | +**Note:** Some options will not work reliably for devices matched by name only |
580 | +and rendered by networkd, due to interactions with device renaming in udev. |
581 | +Match devices by MAC when setting options like: ``wakeonlan`` or ``*-offload``. |
582 | + |
583 | ``match`` (mapping) |
584 | |
585 | : This selects a subset of available physical devices by various hardware |
586 | @@ -139,54 +143,50 @@ Virtual devices |
587 | |
588 | : Enable wake on LAN. Off by default. |
589 | |
590 | - **Note:** This will not work reliably for devices matched by name |
591 | - only and rendered by networkd, due to interactions with device |
592 | - renaming in udev. Match devices by MAC when setting wake on LAN. |
593 | - |
594 | ``emit-lldp`` (bool) – since **0.99** |
595 | |
596 | : (networkd backend only) Whether to emit LLDP packets. Off by default. |
597 | |
598 | ``receive-checksum-offload`` (bool) – since **0.104** |
599 | |
600 | -: (networkd backend only) If set to true, the hardware offload for |
601 | - checksumming of ingress network packets is enabled. When unset, |
602 | +: (networkd backend only) If set to true (false), the hardware offload for |
603 | + checksumming of ingress network packets is enabled (disabled). When unset, |
604 | the kernel's default will be used. |
605 | |
606 | ``transmit-checksum-offload`` (bool) – since **0.104** |
607 | |
608 | -: (networkd backend only) If set to true, the hardware offload for |
609 | - checksumming of egress network packets is enabled. When unset, |
610 | +: (networkd backend only) If set to true (false), the hardware offload for |
611 | + checksumming of egress network packets is enabled (disabled). When unset, |
612 | the kernel's default will be used. |
613 | |
614 | ``tcp-segmentation-offload`` (bool) – since **0.104** |
615 | |
616 | -: (networkd backend only) If set to true, the TCP Segmentation |
617 | - Offload (TSO) is enabled. When unset, the kernel's default will |
618 | +: (networkd backend only) If set to true (false), the TCP Segmentation |
619 | + Offload (TSO) is enabled (disabled). When unset, the kernel's default will |
620 | be used. |
621 | |
622 | ``tcp6-segmentation-offload`` (bool) – since **0.104** |
623 | |
624 | -: (networkd backend only) If set to true, the TCP6 Segmentation |
625 | - Offload (tx-tcp6-segmentation) is enabled. When unset, the |
626 | +: (networkd backend only) If set to true (false), the TCP6 Segmentation |
627 | + Offload (tx-tcp6-segmentation) is enabled (disabled). When unset, the |
628 | kernel's default will be used. |
629 | |
630 | ``generic-segmentation-offload`` (bool) – since **0.104** |
631 | |
632 | -: (networkd backend only) If set to true, the Generic Segmentation |
633 | - Offload (GSO) is enabled. When unset, the kernel's default will |
634 | +: (networkd backend only) If set to true (false), the Generic Segmentation |
635 | + Offload (GSO) is enabled (disabled). When unset, the kernel's default will |
636 | be used. |
637 | |
638 | ``generic-receive-offload`` (bool) – since **0.104** |
639 | |
640 | -: (networkd backend only) If set to true, the Generic Receive |
641 | - Offload (GRO) is enabled. When unset, the kernel's default will |
642 | +: (networkd backend only) If set to true (false), the Generic Receive |
643 | + Offload (GRO) is enabled (disabled). When unset, the kernel's default will |
644 | be used. |
645 | |
646 | ``large-receive-offload`` (bool) – since **0.104** |
647 | |
648 | -: (networkd backend only) If set to true, the Generic Receive |
649 | - Offload (GRO) is enabled. When unset, the kernel's default will |
650 | +: (networkd backend only) If set to true (false), the Large Receive Offload |
651 | + (LRO) is enabled (disabled). When unset, the kernel's default will |
652 | be used. |
653 | |
654 | ``openvswitch`` (mapping) – since **0.100** |
655 | diff --git a/netplan/cli/commands/apply.py b/netplan/cli/commands/apply.py |
656 | index d481184..5bf4ae9 100644 |
657 | --- a/netplan/cli/commands/apply.py |
658 | +++ b/netplan/cli/commands/apply.py |
659 | @@ -221,13 +221,22 @@ class NetplanApply(utils.NetplanCommand): |
660 | '/sys/class/net/' + device], |
661 | stdout=subprocess.DEVNULL, |
662 | stderr=subprocess.DEVNULL) |
663 | + subprocess.check_call(['udevadm', 'test', |
664 | + '/sys/class/net/' + device], |
665 | + stdout=subprocess.DEVNULL, |
666 | + stderr=subprocess.DEVNULL) |
667 | except subprocess.CalledProcessError: |
668 | logging.debug('Ignoring device without syspath: %s', device) |
669 | |
670 | + devices_after_udev = netifaces.interfaces() |
671 | # apply some more changes manually |
672 | for iface, settings in changes.items(): |
673 | # rename non-critical network interfaces |
674 | - if settings.get('name'): |
675 | + new_name = settings.get('name') |
676 | + if new_name: |
677 | + if iface in devices and new_name in devices_after_udev: |
678 | + logging.debug('Interface rename {} -> {} already happened.'.format(iface, new_name)) |
679 | + continue # re-name already happened via 'udevadm test' |
680 | # bring down the interface, using its current (matched) interface name |
681 | subprocess.check_call(['ip', 'link', 'set', 'dev', iface, 'down'], |
682 | stdout=subprocess.DEVNULL, |
683 | diff --git a/src/netplan.c b/src/netplan.c |
684 | index 7b387b4..d1a27a6 100644 |
685 | --- a/src/netplan.c |
686 | +++ b/src/netplan.c |
687 | @@ -752,13 +752,20 @@ _serialize_yaml( |
688 | YAML_BOOL_TRUE(def, event, emitter, "wakeonlan", def->wake_on_lan); |
689 | |
690 | /* Offload options */ |
691 | - YAML_BOOL_TRUE(def, event, emitter, "receive-checksum-offload", def->receive_checksum_offload); |
692 | - YAML_BOOL_TRUE(def, event, emitter, "transmit-checksum-offload", def->transmit_checksum_offload); |
693 | - YAML_BOOL_TRUE(def, event, emitter, "tcp-segmentation-offload", def->tcp_segmentation_offload); |
694 | - YAML_BOOL_TRUE(def, event, emitter, "tcp6-segmentation-offload", def->tcp6_segmentation_offload); |
695 | - YAML_BOOL_TRUE(def, event, emitter, "generic-segmentation-offload", def->generic_segmentation_offload); |
696 | - YAML_BOOL_TRUE(def, event, emitter, "generic-receive-offload", def->generic_receive_offload); |
697 | - YAML_BOOL_TRUE(def, event, emitter, "large-receive-offload", def->large_receive_offload); |
698 | + if (def->receive_checksum_offload != NETPLAN_TRISTATE_UNSET) |
699 | + YAML_BOOL_TRUE(def, event, emitter, "receive-checksum-offload", def->receive_checksum_offload); |
700 | + if (def->transmit_checksum_offload != NETPLAN_TRISTATE_UNSET) |
701 | + YAML_BOOL_TRUE(def, event, emitter, "transmit-checksum-offload", def->transmit_checksum_offload); |
702 | + if (def->tcp_segmentation_offload != NETPLAN_TRISTATE_UNSET) |
703 | + YAML_BOOL_TRUE(def, event, emitter, "tcp-segmentation-offload", def->tcp_segmentation_offload); |
704 | + if (def->tcp6_segmentation_offload != NETPLAN_TRISTATE_UNSET) |
705 | + YAML_BOOL_TRUE(def, event, emitter, "tcp6-segmentation-offload", def->tcp6_segmentation_offload); |
706 | + if (def->generic_segmentation_offload != NETPLAN_TRISTATE_UNSET) |
707 | + YAML_BOOL_TRUE(def, event, emitter, "generic-segmentation-offload", def->generic_segmentation_offload); |
708 | + if (def->generic_receive_offload != NETPLAN_TRISTATE_UNSET) |
709 | + YAML_BOOL_TRUE(def, event, emitter, "generic-receive-offload", def->generic_receive_offload); |
710 | + if (def->large_receive_offload != NETPLAN_TRISTATE_UNSET) |
711 | + YAML_BOOL_TRUE(def, event, emitter, "large-receive-offload", def->large_receive_offload); |
712 | |
713 | if (def->wowlan && def->wowlan != NETPLAN_WIFI_WOWLAN_DEFAULT) { |
714 | YAML_SCALAR_PLAIN(event, emitter, "wakeonwlan"); |
715 | diff --git a/src/networkd.c b/src/networkd.c |
716 | index 6d26047..62c87ce 100644 |
717 | --- a/src/networkd.c |
718 | +++ b/src/networkd.c |
719 | @@ -243,13 +243,13 @@ write_link_file(const NetplanNetDefinition* def, const char* rootdir, const char |
720 | if (!def->set_name && |
721 | !def->wake_on_lan && |
722 | !def->mtubytes && |
723 | - !def->receive_checksum_offload && |
724 | - !def->transmit_checksum_offload && |
725 | - !def->tcp_segmentation_offload && |
726 | - !def->tcp6_segmentation_offload && |
727 | - !def->generic_segmentation_offload && |
728 | - !def->generic_receive_offload && |
729 | - !def->large_receive_offload) |
730 | + (def->receive_checksum_offload == NETPLAN_TRISTATE_UNSET) && |
731 | + (def->transmit_checksum_offload == NETPLAN_TRISTATE_UNSET) && |
732 | + (def->tcp_segmentation_offload == NETPLAN_TRISTATE_UNSET) && |
733 | + (def->tcp6_segmentation_offload == NETPLAN_TRISTATE_UNSET) && |
734 | + (def->generic_segmentation_offload == NETPLAN_TRISTATE_UNSET) && |
735 | + (def->generic_receive_offload == NETPLAN_TRISTATE_UNSET) && |
736 | + (def->large_receive_offload == NETPLAN_TRISTATE_UNSET)) |
737 | return; |
738 | |
739 | /* build file contents */ |
740 | @@ -265,26 +265,33 @@ write_link_file(const NetplanNetDefinition* def, const char* rootdir, const char |
741 | g_string_append_printf(s, "MTUBytes=%u\n", def->mtubytes); |
742 | |
743 | /* Offload options */ |
744 | - if (def->receive_checksum_offload) |
745 | - g_string_append_printf(s, "ReceiveChecksumOffload=%u\n", def->receive_checksum_offload); |
746 | + if (def->receive_checksum_offload != NETPLAN_TRISTATE_UNSET) |
747 | + g_string_append_printf(s, "ReceiveChecksumOffload=%s\n", |
748 | + (def->receive_checksum_offload ? "true" : "false")); |
749 | |
750 | - if (def->transmit_checksum_offload) |
751 | - g_string_append_printf(s, "TransmitChecksumOffload=%u\n", def->transmit_checksum_offload); |
752 | + if (def->transmit_checksum_offload != NETPLAN_TRISTATE_UNSET) |
753 | + g_string_append_printf(s, "TransmitChecksumOffload=%s\n", |
754 | + (def->transmit_checksum_offload ? "true" : "false")); |
755 | |
756 | - if (def->tcp_segmentation_offload) |
757 | - g_string_append_printf(s, "TCPSegmentationOffload=%u\n", def->tcp_segmentation_offload); |
758 | + if (def->tcp_segmentation_offload != NETPLAN_TRISTATE_UNSET) |
759 | + g_string_append_printf(s, "TCPSegmentationOffload=%s\n", |
760 | + (def->tcp_segmentation_offload ? "true" : "false")); |
761 | |
762 | - if (def->tcp6_segmentation_offload) |
763 | - g_string_append_printf(s, "TCP6SegmentationOffload=%u\n", def->tcp6_segmentation_offload); |
764 | + if (def->tcp6_segmentation_offload != NETPLAN_TRISTATE_UNSET) |
765 | + g_string_append_printf(s, "TCP6SegmentationOffload=%s\n", |
766 | + (def->tcp6_segmentation_offload ? "true" : "false")); |
767 | |
768 | - if (def->generic_segmentation_offload) |
769 | - g_string_append_printf(s, "GenericSegmentationOffload=%u\n", def->generic_segmentation_offload); |
770 | + if (def->generic_segmentation_offload != NETPLAN_TRISTATE_UNSET) |
771 | + g_string_append_printf(s, "GenericSegmentationOffload=%s\n", |
772 | + (def->generic_segmentation_offload ? "true" : "false")); |
773 | |
774 | - if (def->generic_receive_offload) |
775 | - g_string_append_printf(s, "GenericReceiveOffload=%u\n", def->generic_receive_offload); |
776 | + if (def->generic_receive_offload != NETPLAN_TRISTATE_UNSET) |
777 | + g_string_append_printf(s, "GenericReceiveOffload=%s\n", |
778 | + (def->generic_receive_offload ? "true" : "false")); |
779 | |
780 | - if (def->large_receive_offload) |
781 | - g_string_append_printf(s, "LargeReceiveOffload=%u\n", def->large_receive_offload); |
782 | + if (def->large_receive_offload != NETPLAN_TRISTATE_UNSET) |
783 | + g_string_append_printf(s, "LargeReceiveOffload=%s\n", |
784 | + (def->large_receive_offload ? "true" : "false")); |
785 | |
786 | orig_umask = umask(022); |
787 | g_string_free_to_file(s, rootdir, path, ".link"); |
788 | diff --git a/src/parse.c b/src/parse.c |
789 | index 350c508..0cb07d2 100644 |
790 | --- a/src/parse.c |
791 | +++ b/src/parse.c |
792 | @@ -374,6 +374,37 @@ handle_generic_bool(NetplanParser* npp, yaml_node_t* node, void* entryptr, const |
793 | * Handler for setting a HashTable field from a mapping node, inside a given struct |
794 | * @entryptr: pointer to the beginning of the to-be-modified data structure |
795 | * @data: offset into entryptr struct where the boolean field to write is located |
796 | + */ |
797 | +static gboolean |
798 | +handle_generic_tristate(NetplanParser* npp, yaml_node_t* node, void* entryptr, const void* data, GError** error) |
799 | +{ |
800 | + g_assert(entryptr); |
801 | + NetplanTristate v; |
802 | + guint offset = GPOINTER_TO_UINT(data); |
803 | + NetplanTristate* dest = ((void*) entryptr + offset); |
804 | + |
805 | + if (g_ascii_strcasecmp(scalar(node), "true") == 0 || |
806 | + g_ascii_strcasecmp(scalar(node), "on") == 0 || |
807 | + g_ascii_strcasecmp(scalar(node), "yes") == 0 || |
808 | + g_ascii_strcasecmp(scalar(node), "y") == 0) |
809 | + v = NETPLAN_TRISTATE_TRUE; |
810 | + else if (g_ascii_strcasecmp(scalar(node), "false") == 0 || |
811 | + g_ascii_strcasecmp(scalar(node), "off") == 0 || |
812 | + g_ascii_strcasecmp(scalar(node), "no") == 0 || |
813 | + g_ascii_strcasecmp(scalar(node), "n") == 0) |
814 | + v = NETPLAN_TRISTATE_FALSE; |
815 | + else |
816 | + return yaml_error(npp, node, error, "invalid boolean value '%s'", scalar(node)); |
817 | + |
818 | + *dest = v; |
819 | + mark_data_as_dirty(npp, dest); |
820 | + return TRUE; |
821 | +} |
822 | + |
823 | +/* |
824 | + * Handler for setting a HashTable field from a mapping node, inside a given struct |
825 | + * @entryptr: pointer to the beginning of the to-be-modified data structure |
826 | + * @data: offset into entryptr struct where the boolean field to write is located |
827 | */ |
828 | static gboolean |
829 | handle_generic_map(NetplanParser *npp, yaml_node_t* node, void* entryptr, const void* data, GError** error) |
830 | @@ -517,6 +548,16 @@ handle_netdef_bool(NetplanParser* npp, yaml_node_t* node, const void* data, GErr |
831 | } |
832 | |
833 | /** |
834 | + * Generic handler for tri-state settings that can bei "UNSET", "TRUE", or "FALSE". |
835 | + * @data: offset into NetplanNetDefinition where the guint field to write is located |
836 | + */ |
837 | +static gboolean |
838 | +handle_netdef_tristate(NetplanParser* npp, yaml_node_t* node, const void* data, GError** error) |
839 | +{ |
840 | + return handle_generic_tristate(npp, node, npp->current.netdef, data, error); |
841 | +} |
842 | + |
843 | +/** |
844 | * Generic handler for setting a npp->current.netdef guint field from a scalar node |
845 | * @data: offset into NetplanNetDefinition where the guint field to write is located |
846 | */ |
847 | @@ -2356,13 +2397,13 @@ static const mapping_entry_handler dhcp6_overrides_handlers[] = { |
848 | {"wakeonlan", YAML_SCALAR_NODE, {.generic=handle_netdef_bool}, netdef_offset(wake_on_lan)}, \ |
849 | {"wakeonwlan", YAML_SEQUENCE_NODE, {.generic=handle_wowlan}, netdef_offset(wowlan)}, \ |
850 | {"emit-lldp", YAML_SCALAR_NODE, {.generic=handle_netdef_bool}, netdef_offset(emit_lldp)}, \ |
851 | - {"receive-checksum-offload", YAML_SCALAR_NODE, {.generic=handle_netdef_bool}, netdef_offset(receive_checksum_offload)}, \ |
852 | - {"transmit-checksum-offload", YAML_SCALAR_NODE, {.generic=handle_netdef_bool}, netdef_offset(transmit_checksum_offload)}, \ |
853 | - {"tcp-segmentation-offload", YAML_SCALAR_NODE, {.generic=handle_netdef_bool}, netdef_offset(tcp_segmentation_offload)}, \ |
854 | - {"tcp6-segmentation-offload", YAML_SCALAR_NODE, {.generic=handle_netdef_bool}, netdef_offset(tcp6_segmentation_offload)}, \ |
855 | - {"generic-segmentation-offload", YAML_SCALAR_NODE, {.generic=handle_netdef_bool}, netdef_offset(generic_segmentation_offload)}, \ |
856 | - {"generic-receive-offload", YAML_SCALAR_NODE, {.generic=handle_netdef_bool}, netdef_offset(generic_receive_offload)}, \ |
857 | - {"large-receive-offload", YAML_SCALAR_NODE, {.generic=handle_netdef_bool}, netdef_offset(large_receive_offload)} |
858 | + {"receive-checksum-offload", YAML_SCALAR_NODE, {.generic=handle_netdef_tristate}, netdef_offset(receive_checksum_offload)}, \ |
859 | + {"transmit-checksum-offload", YAML_SCALAR_NODE, {.generic=handle_netdef_tristate}, netdef_offset(transmit_checksum_offload)}, \ |
860 | + {"tcp-segmentation-offload", YAML_SCALAR_NODE, {.generic=handle_netdef_tristate}, netdef_offset(tcp_segmentation_offload)}, \ |
861 | + {"tcp6-segmentation-offload", YAML_SCALAR_NODE, {.generic=handle_netdef_tristate}, netdef_offset(tcp6_segmentation_offload)}, \ |
862 | + {"generic-segmentation-offload", YAML_SCALAR_NODE, {.generic=handle_netdef_tristate}, netdef_offset(generic_segmentation_offload)}, \ |
863 | + {"generic-receive-offload", YAML_SCALAR_NODE, {.generic=handle_netdef_tristate}, netdef_offset(generic_receive_offload)}, \ |
864 | + {"large-receive-offload", YAML_SCALAR_NODE, {.generic=handle_netdef_tristate}, netdef_offset(large_receive_offload)} |
865 | |
866 | static const mapping_entry_handler ethernet_def_handlers[] = { |
867 | COMMON_LINK_HANDLERS, |
868 | diff --git a/src/types.c b/src/types.c |
869 | index eb9f780..00c2b0f 100644 |
870 | --- a/src/types.c |
871 | +++ b/src/types.c |
872 | @@ -335,6 +335,14 @@ reset_netdef(NetplanNetDefinition* netdef, NetplanDefType new_type, NetplanBacke |
873 | |
874 | reset_private_netdef_data(netdef->_private); |
875 | FREE_AND_NULLIFY(netdef->_private); |
876 | + |
877 | + netdef->receive_checksum_offload = NETPLAN_TRISTATE_UNSET; |
878 | + netdef->transmit_checksum_offload = NETPLAN_TRISTATE_UNSET; |
879 | + netdef->tcp_segmentation_offload = NETPLAN_TRISTATE_UNSET; |
880 | + netdef->tcp6_segmentation_offload = NETPLAN_TRISTATE_UNSET; |
881 | + netdef->generic_segmentation_offload = NETPLAN_TRISTATE_UNSET; |
882 | + netdef->generic_receive_offload = NETPLAN_TRISTATE_UNSET; |
883 | + netdef->large_receive_offload = NETPLAN_TRISTATE_UNSET; |
884 | } |
885 | |
886 | static void |
887 | diff --git a/src/types.h b/src/types.h |
888 | index 27a23fc..710b1f1 100644 |
889 | --- a/src/types.h |
890 | +++ b/src/types.h |
891 | @@ -171,6 +171,27 @@ typedef union { |
892 | } networkd; |
893 | } NetplanBackendSettings; |
894 | |
895 | +typedef enum |
896 | +{ |
897 | + /** |
898 | + * @brief Tristate enum type |
899 | + * |
900 | + * This type defines a boolean which can be unset, i.e. |
901 | + * this type has three states. The enum is ordered so |
902 | + * that |
903 | + * |
904 | + * UNSET -> -1 |
905 | + * FALSE -> 0 |
906 | + * TRUE -> 1 |
907 | + * |
908 | + * And the integer values can be used directly when |
909 | + * converting to string. |
910 | + */ |
911 | + NETPLAN_TRISTATE_UNSET = -1, /* -1 */ |
912 | + NETPLAN_TRISTATE_FALSE, /* 0 */ |
913 | + NETPLAN_TRISTATE_TRUE, /* 1 */ |
914 | +} NetplanTristate; |
915 | + |
916 | struct netplan_net_definition { |
917 | NetplanDefType type; |
918 | NetplanBackend backend; |
919 | @@ -333,13 +354,13 @@ struct netplan_net_definition { |
920 | gboolean ignore_carrier; |
921 | |
922 | /* offload options */ |
923 | - gboolean receive_checksum_offload; |
924 | - gboolean transmit_checksum_offload; |
925 | - gboolean tcp_segmentation_offload; |
926 | - gboolean tcp6_segmentation_offload; |
927 | - gboolean generic_segmentation_offload; |
928 | - gboolean generic_receive_offload; |
929 | - gboolean large_receive_offload; |
930 | + NetplanTristate receive_checksum_offload; |
931 | + NetplanTristate transmit_checksum_offload; |
932 | + NetplanTristate tcp_segmentation_offload; |
933 | + NetplanTristate tcp6_segmentation_offload; |
934 | + NetplanTristate generic_segmentation_offload; |
935 | + NetplanTristate generic_receive_offload; |
936 | + NetplanTristate large_receive_offload; |
937 | |
938 | struct private_netdef_data* _private; |
939 | |
940 | diff --git a/tests/generator/test_ethernets.py b/tests/generator/test_ethernets.py |
941 | index 46bf764..e81941b 100644 |
942 | --- a/tests/generator/test_ethernets.py |
943 | +++ b/tests/generator/test_ethernets.py |
944 | @@ -772,11 +772,11 @@ method=ignore |
945 | ethernets: |
946 | eth1: |
947 | receive-checksum-offload: true |
948 | - transmit-checksum-offload: true |
949 | + transmit-checksum-offload: off |
950 | tcp-segmentation-offload: true |
951 | - tcp6-segmentation-offload: true |
952 | + tcp6-segmentation-offload: false |
953 | generic-segmentation-offload: true |
954 | - generic-receive-offload: true |
955 | + generic-receive-offload: no |
956 | large-receive-offload: true''') |
957 | |
958 | self.assert_networkd({'eth1.link': '''[Match] |
959 | @@ -784,13 +784,13 @@ OriginalName=eth1 |
960 | |
961 | [Link] |
962 | WakeOnLan=off |
963 | -ReceiveChecksumOffload=1 |
964 | -TransmitChecksumOffload=1 |
965 | -TCPSegmentationOffload=1 |
966 | -TCP6SegmentationOffload=1 |
967 | -GenericSegmentationOffload=1 |
968 | -GenericReceiveOffload=1 |
969 | -LargeReceiveOffload=1 |
970 | +ReceiveChecksumOffload=true |
971 | +TransmitChecksumOffload=false |
972 | +TCPSegmentationOffload=true |
973 | +TCP6SegmentationOffload=false |
974 | +GenericSegmentationOffload=true |
975 | +GenericReceiveOffload=false |
976 | +LargeReceiveOffload=true |
977 | ''', |
978 | 'eth1.network': '''[Match] |
979 | Name=eth1 |
980 | @@ -799,3 +799,17 @@ Name=eth1 |
981 | LinkLocalAddressing=ipv6 |
982 | '''}) |
983 | self.assert_networkd_udev(None) |
984 | + |
985 | + def test_offload_invalid(self): |
986 | + err = self.generate('''network: |
987 | + version: 2 |
988 | + ethernets: |
989 | + eth1: |
990 | + generic-receive-offload: n |
991 | + receive-checksum-offload: true |
992 | + tcp-segmentation-offload: true |
993 | + tcp6-segmentation-offload: false |
994 | + generic-segmentation-offload: true |
995 | + transmit-checksum-offload: xx |
996 | + large-receive-offload: true''', expect_fail=True) |
997 | + self.assertIn('invalid boolean value \'xx\'', err) |
998 | diff --git a/tests/integration/ethernets.py b/tests/integration/ethernets.py |
999 | index 865c0d4..06ac069 100644 |
1000 | --- a/tests/integration/ethernets.py |
1001 | +++ b/tests/integration/ethernets.py |
1002 | @@ -236,6 +236,65 @@ class _CommonTests(): |
1003 | self.assert_iface_up('iface1', ['inet 10.10.10.11']) |
1004 | self.assert_iface_up('iface2', ['inet 10.10.10.22']) |
1005 | |
1006 | + def test_link_offloading(self): |
1007 | + self.setup_eth(None, False) |
1008 | + # check kernel defaults |
1009 | + out = subprocess.check_output(['ethtool', '-k', self.dev_e_client]) |
1010 | + self.assertIn(b'rx-checksumming: on', out) |
1011 | + self.assertIn(b'tx-checksumming: on', out) |
1012 | + self.assertIn(b'tcp-segmentation-offload: on', out) |
1013 | + self.assertIn(b'tx-tcp6-segmentation: on', out) |
1014 | + self.assertIn(b'generic-segmentation-offload: on', out) |
1015 | + self.assertIn(b'generic-receive-offload: off', out) # off by default |
1016 | + # validate turning off |
1017 | + with open(self.config, 'w') as f: |
1018 | + f.write('''network: |
1019 | + renderer: %(r)s |
1020 | + ethernets: |
1021 | + %(ec)s: |
1022 | + addresses: [10.10.10.22/24] |
1023 | + receive-checksum-offload: off |
1024 | + transmit-checksum-offload: off |
1025 | + tcp-segmentation-offload: off |
1026 | + tcp6-segmentation-offload: off |
1027 | + generic-segmentation-offload: off |
1028 | + generic-receive-offload: off |
1029 | + #large-receive-offload: off # not possible on veth |
1030 | +''' % {'r': self.backend, 'ec': self.dev_e_client}) |
1031 | + self.generate_and_settle([self.dev_e_client]) |
1032 | + self.assert_iface_up(self.dev_e_client, ['inet 10.10.10.22']) |
1033 | + out = subprocess.check_output(['ethtool', '-k', self.dev_e_client]) |
1034 | + self.assertIn(b'rx-checksumming: off', out) |
1035 | + self.assertIn(b'tx-checksumming: off', out) |
1036 | + self.assertIn(b'tcp-segmentation-offload: off', out) |
1037 | + self.assertIn(b'tx-tcp6-segmentation: off', out) |
1038 | + self.assertIn(b'generic-segmentation-offload: off', out) |
1039 | + self.assertIn(b'generic-receive-offload: off', out) |
1040 | + # validate turning on |
1041 | + with open(self.config, 'w') as f: |
1042 | + f.write('''network: |
1043 | + renderer: %(r)s |
1044 | + ethernets: |
1045 | + %(ec)s: |
1046 | + addresses: [10.10.10.22/24] |
1047 | + receive-checksum-offload: true |
1048 | + transmit-checksum-offload: true |
1049 | + tcp-segmentation-offload: true |
1050 | + tcp6-segmentation-offload: true |
1051 | + generic-segmentation-offload: true |
1052 | + generic-receive-offload: true |
1053 | + #large-receive-offload: true # not possible on veth |
1054 | +''' % {'r': self.backend, 'ec': self.dev_e_client}) |
1055 | + self.generate_and_settle([self.dev_e_client]) |
1056 | + self.assert_iface_up(self.dev_e_client, ['inet 10.10.10.22']) |
1057 | + out = subprocess.check_output(['ethtool', '-k', self.dev_e_client]) |
1058 | + self.assertIn(b'rx-checksumming: on', out) |
1059 | + self.assertIn(b'tx-checksumming: on', out) |
1060 | + self.assertIn(b'tcp-segmentation-offload: on', out) |
1061 | + self.assertIn(b'tx-tcp6-segmentation: on', out) |
1062 | + self.assertIn(b'generic-segmentation-offload: on', out) |
1063 | + self.assertIn(b'generic-receive-offload: on', out) |
1064 | + |
1065 | |
1066 | @unittest.skipIf("networkd" not in test_backends, |
1067 | "skipping as networkd backend tests are disabled") |
Thank you very much Nicolas for preparing a debdiff/ merge-proposal on top of the currently pending netplan Jammy SRU changeset!
The suggested patch is looking good so far, but I left a few inline comments (see below). Furthermore, there might be some misunderstanding of how to apply distro patches. We do not want to modify any files of the "upstream source" in this repository (e.g. src/ doc/ netplan/ ...), but ONLY files in the debian/ packaging subdirectory. Please revert those changes to the upstream source, the new "distro-patch" (quilt) you added in debian/ patches/ 0003-Add- tristate- type-for- offload- options- LP-1956264- 270.patch will apply those changes for us during the package build.
Another thing: You missed to add the "ethtool" test-dependency to the "ethernets" test in debian/ tests/control, this needs to be added in order to make the new offloading autopkgtests PASS (as has been done here: http:// launchpadlibrar ian.net/ 601540356/ netplan. io_0.104- 0ubuntu2_ 0.104-0ubuntu3. diff.gz).
Some of my suggested changes/fixes: /paste. ubuntu. com/p/vKJR7yMN9 2/
https:/
Last but not least, please adopt the bug report in LP: #1956264 according to the SRU template in https:/ /wiki.ubuntu. com/StableRelea seUpdates# SRU_Bug_ Template, describing a proper test case/reporducer and impact analysis, to make it fit for SRU.
Keep up the good work!