Merge ~danilogondolfo/netplan:noble_lp1809994 into ~ubuntu-core-dev/netplan/+git/ubuntu:ubuntu-noble

Proposed by Danilo Egea Gondolfo
Status: Merged
Merged at revision: 8fbdc283e462ba8079bf88855076ce0975d4b99b
Proposed branch: ~danilogondolfo/netplan:noble_lp1809994
Merge into: ~ubuntu-core-dev/netplan/+git/ubuntu:ubuntu-noble
Diff against target: 318 lines (+290/-0)
4 files modified
debian/changelog (+12/-0)
debian/patches/lp1809994/0010-parse-improve-the-parsing-of-access-points-LP-180999.patch (+197/-0)
debian/patches/lp1809994/0011-wifi-replace-the-previously-defined-AP-with-the-new-.patch (+79/-0)
debian/patches/series (+2/-0)
Reviewer Review Type Date Requested Status
Lukas Märdian Approve
Ubuntu Core Development Team Pending
Review via email: mp+455627@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Danilo Egea Gondolfo (danilogondolfo) wrote :
Revision history for this message
Lukas Märdian (slyon) wrote :

Thanks for providing build-time (PPA) and autopkgtests. The patches match what we've already reviewed in the upstream PR. LGTM.

Sponsored into Noble.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/debian/changelog b/debian/changelog
2index 2e1f737..07f3dd1 100644
3--- a/debian/changelog
4+++ b/debian/changelog
5@@ -1,3 +1,15 @@
6+netplan.io (0.107-5ubuntu2) noble; urgency=medium
7+
8+ * d/p/lp1809994/0010-parse-improve-the-parsing-of-access-points-LP-180999.patch.
9+ Improve access-points parsing. Properly handle access-points if a second
10+ pass if required in the parser and not report them as duplicates. (LP: #1809994)
11+ * d/p/lp1809994/0011-wifi-replace-the-previously-defined-AP-with-the-new-.patch.
12+ Overwrite the access-point object if another access-point with the same
13+ name is found instead of ignoring the new one. This behavior is closer
14+ to the merging process Netplan does.
15+
16+ -- Danilo Egea Gondolfo <danilo.egea.gondolfo@canonical.com> Tue, 14 Nov 2023 14:13:31 +0000
17+
18 netplan.io (0.107-5ubuntu1) noble; urgency=medium
19
20 * d/p/lp2039821/0008-wireguard-ignore-empty-endpoints.patch (LP: #2039821)
21diff --git a/debian/patches/lp1809994/0010-parse-improve-the-parsing-of-access-points-LP-180999.patch b/debian/patches/lp1809994/0010-parse-improve-the-parsing-of-access-points-LP-180999.patch
22new file mode 100644
23index 0000000..85392c7
24--- /dev/null
25+++ b/debian/patches/lp1809994/0010-parse-improve-the-parsing-of-access-points-LP-180999.patch
26@@ -0,0 +1,197 @@
27+From: Danilo Egea Gondolfo <danilo.egea.gondolfo@canonical.com>
28+Date: Fri, 6 Oct 2023 11:42:36 +0100
29+Subject: parse: improve the parsing of access-points (LP: #1809994)
30+
31+When the parser requires a second pass, it will report access-points it
32+already parsed as duplicates and error out.
33+
34+With this change, access-points will be stored in a local hash table,
35+which will be used to find duplicates in the same netdef, and moved to
36+the netdef->access_points hash table in the end. Access-points already
37+present in the netdef hash table will be considered already parsed and
38+skipped.
39+
40+Add a test to check the problem is fixed and another one to test if
41+merging the access-points when the same interface is present in multiple
42+files is working properly.
43+
44+Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/netplan.io/+bug/1809994
45+Origin: https://github.com/canonical/netplan/pull/413
46+---
47+ src/parse.c | 45 +++++++++++++++++++---------
48+ src/types-internal.h | 3 ++
49+ src/types.c | 2 +-
50+ tests/generator/test_common.py | 54 ++++++++++++++++++++++++++++++++++
51+ 4 files changed, 89 insertions(+), 15 deletions(-)
52+
53+--- a/src/parse.c
54++++ b/src/parse.c
55+@@ -59,6 +59,9 @@
56+
57+ NetplanParser global_parser = {0};
58+
59++static gboolean
60++insert_kv_into_hash(void *key, void *value, void *hash);
61++
62+ /**
63+ * Load YAML file into a yaml_document_t.
64+ *
65+@@ -1404,11 +1407,13 @@
66+ static gboolean
67+ handle_wifi_access_points(NetplanParser* npp, yaml_node_t* node, const char* key_prefix, __unused const void* data, GError** error)
68+ {
69++ GHashTable* access_points = g_hash_table_new(g_str_hash, g_str_equal);
70++
71+ for (yaml_node_pair_t* entry = node->data.mapping.pairs.start; entry < node->data.mapping.pairs.top; entry++) {
72+ NetplanWifiAccessPoint *access_point = NULL;
73+ g_autofree char* full_key = NULL;
74+ yaml_node_t* key, *value;
75+- gboolean ret = TRUE;
76++ const gchar* ssid;
77+
78+ key = yaml_document_get_node(&npp->doc, entry->key);
79+ assert_type(npp, key, YAML_SCALAR_NODE);
80+@@ -1421,31 +1426,43 @@
81+ continue;
82+ }
83+
84++ ssid = scalar(key);
85++
86++ /* Skip access-points that already exist in the netdef */
87++ if (npp->current.netdef->access_points && g_hash_table_contains(npp->current.netdef->access_points, ssid))
88++ continue;
89++
90++ /* Check if there's already an SSID with that name in the list of APs we are parsing */
91++ if (g_hash_table_contains(access_points, ssid)) {
92++ g_hash_table_foreach(access_points, free_access_point, NULL);
93++ g_hash_table_destroy(access_points);
94++ return yaml_error(npp, key, error, "%s: Duplicate access point SSID '%s'", npp->current.netdef->id, ssid);
95++ }
96++
97+ g_assert(access_point == NULL);
98+ access_point = g_new0(NetplanWifiAccessPoint, 1);
99+- access_point->ssid = g_strdup(scalar(key));
100++ access_point->ssid = g_strdup(ssid);
101+ g_debug("%s: adding wifi AP '%s'", npp->current.netdef->id, access_point->ssid);
102+
103+- /* Check if there's already an SSID with that name */
104+- // FIXME: This check fails on multi-pass parsing, e.g. when defined in
105+- // the same YAML file with a set of virtual-ethernets peers.
106+- if (npp->current.netdef->access_points &&
107+- g_hash_table_lookup(npp->current.netdef->access_points, access_point->ssid)) {
108+- ret = yaml_error(npp, key, error, "%s: Duplicate access point SSID '%s'", npp->current.netdef->id, access_point->ssid);
109+- }
110+-
111+ npp->current.access_point = access_point;
112+- if (!ret || !process_mapping(npp, value, full_key, wifi_access_point_handlers, NULL, error)) {
113++ if (!process_mapping(npp, value, full_key, wifi_access_point_handlers, NULL, error)) {
114+ access_point_clear(&npp->current.access_point, npp->current.backend);
115++ g_hash_table_foreach(access_points, free_access_point, NULL);
116++ g_hash_table_destroy(access_points);
117+ return FALSE;
118+ }
119+
120++ g_hash_table_insert(access_points, access_point->ssid, access_point);
121++ npp->current.access_point = NULL;
122++ }
123++
124++ if (g_hash_table_size(access_points) > 0) {
125+ if (!npp->current.netdef->access_points)
126+ npp->current.netdef->access_points = g_hash_table_new(g_str_hash, g_str_equal);
127+- g_hash_table_insert(npp->current.netdef->access_points, access_point->ssid, access_point);
128+- npp->current.access_point = NULL;
129++ g_hash_table_foreach_steal(access_points, insert_kv_into_hash, npp->current.netdef->access_points);
130++ mark_data_as_dirty(npp, &npp->current.netdef->access_points);
131+ }
132+- mark_data_as_dirty(npp, &npp->current.netdef->access_points);
133++ g_hash_table_destroy(access_points);
134+ return TRUE;
135+ }
136+
137+--- a/src/types-internal.h
138++++ b/src/types-internal.h
139+@@ -313,3 +313,6 @@
140+
141+ void
142+ free_address_options(void* ptr);
143++
144++void
145++free_access_point(void* key, void* value, void* data);
146+--- a/src/types.c
147++++ b/src/types.c
148+@@ -200,7 +200,7 @@
149+ * @data: pointer to a NetplanBackend value representing the renderer context in which
150+ * to interpret the processed object, especially regarding the backend settings
151+ */
152+-static void
153++void
154+ free_access_point(__unused void* key, void* value, __unused void* data)
155+ {
156+ NetplanWifiAccessPoint* ap = value;
157+--- a/tests/generator/test_common.py
158++++ b/tests/generator/test_common.py
159+@@ -1557,6 +1557,28 @@
160+ ''',
161+ 'eth0.network': ND_EMPTY % ('eth0', 'no') + 'Bond=aggi\n'})
162+
163++ def test_check_parser_second_pass_will_not_lead_to_duplicate_access_point(self):
164++ '''
165++ When the parser needs more than one pass we shouldn't
166++ try to load the same access-point again from wifi devices.
167++ Testcase for LP: #1809994'''
168++
169++ self.generate('''network:
170++ bridges:
171++ br0:
172++ interfaces:
173++ - eth0
174++ ethernets:
175++ eth0:
176++ dhcp4: false
177++ wifis:
178++ wlan0:
179++ dhcp4: true
180++ access-points:
181++ "mywifi":
182++ password: "aaaaaaaa"
183++''')
184++
185+
186+ class TestMerging(TestBase):
187+ '''multiple *.yaml merging'''
188+@@ -1740,3 +1762,35 @@
189+ ''',
190+ 'enyellow.network': ND_DHCP4 % 'enyellow',
191+ 'enblue.network': ND_DHCP4 % 'enblue'})
192++
193++ def test_wifi_access_points_merging(self):
194++ self.generate('''network:
195++ version: 2
196++ wifis:
197++ wlan0:
198++ dhcp4: true
199++ access-points:
200++ "mywifi":
201++ password: "aaaaaaaa"''',
202++ confs={'newwifi': '''network:
203++ version: 2
204++ wifis:
205++ wlan0:
206++ dhcp4: true
207++ access-points:
208++ "mynewwifi":
209++ password: "aaaaaaaa"'''})
210++
211++ self.assert_wpa_supplicant("wlan0", """ctrl_interface=/run/wpa_supplicant
212++
213++network={
214++ ssid="mynewwifi"
215++ key_mgmt=WPA-PSK
216++ psk="aaaaaaaa"
217++}
218++network={
219++ ssid="mywifi"
220++ key_mgmt=WPA-PSK
221++ psk="aaaaaaaa"
222++}
223++""")
224diff --git a/debian/patches/lp1809994/0011-wifi-replace-the-previously-defined-AP-with-the-new-.patch b/debian/patches/lp1809994/0011-wifi-replace-the-previously-defined-AP-with-the-new-.patch
225new file mode 100644
226index 0000000..c03521e
227--- /dev/null
228+++ b/debian/patches/lp1809994/0011-wifi-replace-the-previously-defined-AP-with-the-new-.patch
229@@ -0,0 +1,79 @@
230+From: Danilo Egea Gondolfo <danilo.egea.gondolfo@canonical.com>
231+Date: Thu, 12 Oct 2023 18:07:31 +0100
232+Subject: wifi: replace the previously defined AP with the new one
233+
234+If we find an AP with the same name in the same interface, we drop the
235+first one and use the new one. This is done to maintain the documented
236+behavior of respecting the order in which the files are parsed. We still
237+need to implement support for merging AP settings.
238+
239+Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/netplan.io/+bug/1809994
240+Origin: https://github.com/canonical/netplan/pull/413
241+---
242+ src/parse.c | 17 +++++++++++++----
243+ tests/generator/test_common.py | 30 ++++++++++++++++++++++++++++++
244+ 2 files changed, 43 insertions(+), 4 deletions(-)
245+
246+--- a/src/parse.c
247++++ b/src/parse.c
248+@@ -1428,11 +1428,20 @@
249+
250+ ssid = scalar(key);
251+
252+- /* Skip access-points that already exist in the netdef */
253+- if (npp->current.netdef->access_points && g_hash_table_contains(npp->current.netdef->access_points, ssid))
254+- continue;
255++ /*
256++ * Delete the access-point if it already exists in the netdef and let the new
257++ * one be added. It has the side effect of reprocessing APs if the parser requires a
258++ * second pass.
259++ *
260++ * TODO: implement support for merging AP settings if they were previously defined
261++ */
262++ if (npp->current.netdef->access_points && g_hash_table_contains(npp->current.netdef->access_points, ssid)) {
263++ NetplanWifiAccessPoint *ap = g_hash_table_lookup(npp->current.netdef->access_points, ssid);
264++ g_hash_table_remove(npp->current.netdef->access_points, ssid);
265++ free_access_point(NULL, ap, NULL);
266++ }
267+
268+- /* Check if there's already an SSID with that name in the list of APs we are parsing */
269++ /* Check if the SSID was already defined in the same netdef in this YAML file we are parsing */
270+ if (g_hash_table_contains(access_points, ssid)) {
271+ g_hash_table_foreach(access_points, free_access_point, NULL);
272+ g_hash_table_destroy(access_points);
273+--- a/tests/generator/test_common.py
274++++ b/tests/generator/test_common.py
275+@@ -1794,3 +1794,33 @@
276+ psk="aaaaaaaa"
277+ }
278+ """)
279++
280++ def test_wifi_access_points_overwriting(self):
281++ ''' If we find an AP that is already defined we drop the first one.
282++ XXX: this test must be removed once we implement support for AP merging
283++ '''
284++ self.generate('''network:
285++ version: 2
286++ wifis:
287++ wlan0:
288++ dhcp4: true
289++ access-points:
290++ "mywifi":
291++ password: "aaaaaaaa"''',
292++ confs={'newwifi': '''network:
293++ version: 2
294++ wifis:
295++ wlan0:
296++ dhcp4: true
297++ access-points:
298++ "mywifi":
299++ password: "bbbbbbbb"'''})
300++
301++ self.assert_wpa_supplicant("wlan0", """ctrl_interface=/run/wpa_supplicant
302++
303++network={
304++ ssid="mywifi"
305++ key_mgmt=WPA-PSK
306++ psk="bbbbbbbb"
307++}
308++""")
309diff --git a/debian/patches/series b/debian/patches/series
310index 837291f..4d9d078 100644
311--- a/debian/patches/series
312+++ b/debian/patches/series
313@@ -7,3 +7,5 @@ lp2034595/0006-apply-bring-lo-back-up-if-it-s-managed-by-NM.patch
314 lp2034595/0007-apply-don-t-assume-the-NM-loopback-connection-is-cal.patch
315 lp2039821/0008-wireguard-ignore-empty-endpoints.patch
316 lp2039825/0009-auth-add-support-for-LEAP-and-EAP-PWD.patch
317+lp1809994/0010-parse-improve-the-parsing-of-access-points-LP-180999.patch
318+lp1809994/0011-wifi-replace-the-previously-defined-AP-with-the-new-.patch

Subscribers

People subscribed via source and target branches