Merge ~slyon/netplan/+git/ubuntu:slyon/ubuntu/eoan into ~ubuntu-core-dev/netplan/+git/ubuntu:ubuntu/eoan
- Git
- lp:~slyon/netplan/+git/ubuntu
- slyon/ubuntu/eoan
- Merge into ubuntu/eoan
Proposed by
Lukas Märdian
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Łukasz Zemczak | ||||
Approved revision: | 415bb4b36fecabbcfeee4f153ae07864dc6a15b4 | ||||
Merged at revision: | 415bb4b36fecabbcfeee4f153ae07864dc6a15b4 | ||||
Proposed branch: | ~slyon/netplan/+git/ubuntu:slyon/ubuntu/eoan | ||||
Merge into: | ~ubuntu-core-dev/netplan/+git/ubuntu:ubuntu/eoan | ||||
Diff against target: |
6685 lines (+3711/-538) 44 files modified
Makefile (+28/-6) debian/changelog (+80/-0) debian/control (+35/-0) debian/copyright (+1/-1) debian/libnetplan-dev.dirs (+1/-0) debian/libnetplan-dev.install (+2/-0) debian/libnetplan0.install (+1/-0) debian/libnetplan0.symbols (+25/-0) debian/netplan.io.install (+4/-0) debian/patches/0001-Fix-LP-1874377-Not-connect-to-WiFi-after-netplan-app.patch (+175/-0) debian/patches/series (+1/-0) debian/rules (+4/-1) debian/tests/control (+27/-0) dev/null (+0/-11) doc/netplan.md (+137/-5) examples/dhcp_wired8021x.yaml (+11/-0) examples/direct_connect_gateway_ipv6.yaml (+11/-0) examples/modem.yaml (+15/-0) netplan/cli/commands/apply.py (+24/-23) netplan/cli/sriov.py (+320/-0) netplan/cli/utils.py (+50/-1) src/generate.c (+10/-9) src/networkd.c (+240/-80) src/networkd.h (+1/-1) src/nm.c (+187/-62) src/nm.h (+1/-1) src/parse.c (+326/-156) src/parse.h (+181/-106) src/util.c (+62/-0) src/util.h (+6/-0) src/validation.c (+26/-25) src/validation.h (+2/-2) tests/cli.py (+30/-22) tests/generator/base.py (+3/-0) tests/generator/test_auth.py (+67/-6) tests/generator/test_common.py (+56/-5) tests/generator/test_errors.py (+58/-0) tests/generator/test_ethernets.py (+124/-0) tests/generator/test_modems.py (+374/-0) tests/generator/test_vlans.py (+93/-0) tests/generator/test_wifis.py (+283/-14) tests/integration/base.py (+22/-1) tests/integration/ethernets.py (+2/-0) tests/test_sriov.py (+605/-0) |
||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Łukasz Zemczak | Approve | ||
Review via email: mp+383327@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Revision history for this message
Łukasz Zemczak (sil2100) : | # |
review:
Approve
Update scan failed
At least one of the branches involved have failed to scan. You can manually schedule a rescan if required.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/Makefile b/Makefile |
2 | index d89eb26..3ce1347 100644 |
3 | --- a/Makefile |
4 | +++ b/Makefile |
5 | @@ -1,4 +1,8 @@ |
6 | +NETPLAN_SOVER=0.0 |
7 | + |
8 | BUILDFLAGS = \ |
9 | + -g \ |
10 | + -fPIC \ |
11 | -std=c99 \ |
12 | -D_XOPEN_SOURCE=500 \ |
13 | -DSBINDIR=\"$(SBINDIR)\" \ |
14 | @@ -13,12 +17,14 @@ BASH_COMPLETIONS_DIR=$(shell pkg-config --variable=completionsdir bash-completio |
15 | GCOV ?= gcov |
16 | ROOTPREFIX ?= |
17 | PREFIX ?= /usr |
18 | +LIBDIR ?= $(PREFIX)/lib |
19 | ROOTLIBEXECDIR ?= $(ROOTPREFIX)/lib |
20 | LIBEXECDIR ?= $(PREFIX)/lib |
21 | SBINDIR ?= $(PREFIX)/sbin |
22 | DATADIR ?= $(PREFIX)/share |
23 | DOCDIR ?= $(DATADIR)/doc |
24 | MANDIR ?= $(DATADIR)/man |
25 | +INCLUDEDIR ?= $(PREFIX)/include |
26 | |
27 | PYCODE = netplan/ $(wildcard src/*.py) $(wildcard tests/*.py) $(wildcard tests/generator/*.py) $(wildcard tests/dbus/*.py) |
28 | |
29 | @@ -29,14 +35,22 @@ NOSETESTS3 ?= $(shell which nosetests-3 || which nosetests3 || echo true) |
30 | |
31 | default: netplan/_features.py generate netplan-dbus dbus/io.netplan.Netplan.service doc/netplan.html doc/netplan.5 doc/netplan-generate.8 doc/netplan-apply.8 doc/netplan-try.8 |
32 | |
33 | -generate: src/generate.[hc] src/parse.[hc] src/util.[hc] src/networkd.[hc] src/nm.[hc] src/validation.[hc] src/error.[hc] |
34 | - $(CC) $(BUILDFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $(filter %.c, $^) `pkg-config --cflags --libs glib-2.0 gio-2.0 yaml-0.1 uuid` |
35 | +%.o: src/%.c |
36 | + $(CC) $(BUILDFLAGS) $(CFLAGS) $(LDFLAGS) -c $^ `pkg-config --cflags --libs glib-2.0 gio-2.0 yaml-0.1 uuid` |
37 | + |
38 | +libnetplan.so.$(NETPLAN_SOVER): parse.o util.o validation.o error.o |
39 | + $(CC) -shared -Wl,-soname,libnetplan.so.$(NETPLAN_SOVER) $(BUILDFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $^ `pkg-config --libs yaml-0.1` |
40 | + ln -snf libnetplan.so.$(NETPLAN_SOVER) libnetplan.so |
41 | + |
42 | +#generate: src/generate.[hc] src/parse.[hc] src/util.[hc] src/networkd.[hc] src/nm.[hc] src/validation.[hc] src/error.[hc] |
43 | +generate: libnetplan.so.$(NETPLAN_SOVER) nm.o networkd.o generate.o |
44 | + $(CC) $(BUILDFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $^ -L. -lnetplan `pkg-config --cflags --libs glib-2.0 gio-2.0 yaml-0.1 uuid` |
45 | |
46 | netplan-dbus: src/dbus.c src/_features.h |
47 | - $(CC) $(BUILDFLAGS) $(CFLAGS) -o $@ $^ `pkg-config --cflags --libs libsystemd glib-2.0` |
48 | + $(CC) $(BUILDFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $^ `pkg-config --cflags --libs libsystemd glib-2.0` |
49 | |
50 | src/_features.h: src/[^_]*.[hc] |
51 | - echo "#include <stddef.h>\nstatic const char *feature_flags[] __attribute__((__unused__)) = {" > $@ |
52 | + printf "#include <stddef.h>\nstatic const char *feature_flags[] __attribute__((__unused__)) = {\n" > $@ |
53 | awk 'match ($$0, /netplan-feature:.*/ ) { $$0=substr($$0, RSTART, RLENGTH); print "\""$$2"\"," }' $^ >> $@ |
54 | echo "NULL, };" >> $@ |
55 | |
56 | @@ -49,6 +63,7 @@ netplan/_features.py: src/[^_]*.[hc] |
57 | clean: |
58 | rm -f netplan/_features.py src/_features.h |
59 | rm -f generate doc/*.html doc/*.[1-9] |
60 | + rm -f *.o *.so* |
61 | rm -f netplan-dbus dbus/*.service |
62 | rm -f *.gcda *.gcno generate.info |
63 | rm -rf test-coverage .coverage |
64 | @@ -85,20 +100,27 @@ python-coverage: |
65 | python3-coverage xml --omit=/usr* || true |
66 | |
67 | install: default |
68 | - mkdir -p $(DESTDIR)/$(SBINDIR) $(DESTDIR)/$(ROOTLIBEXECDIR)/netplan $(DESTDIR)/$(SYSTEMD_GENERATOR_DIR) |
69 | + mkdir -p $(DESTDIR)/$(SBINDIR) $(DESTDIR)/$(ROOTLIBEXECDIR)/netplan $(DESTDIR)/$(SYSTEMD_GENERATOR_DIR) $(DESTDIR)/$(LIBDIR) |
70 | mkdir -p $(DESTDIR)/$(MANDIR)/man5 $(DESTDIR)/$(MANDIR)/man8 |
71 | mkdir -p $(DESTDIR)/$(DOCDIR)/netplan/examples |
72 | mkdir -p $(DESTDIR)/$(DATADIR)/netplan/netplan |
73 | + mkdir -p $(DESTDIR)/$(INCLUDEDIR)/netplan |
74 | install -m 755 generate $(DESTDIR)/$(ROOTLIBEXECDIR)/netplan/ |
75 | find netplan/ -name '*.py' -exec install -Dm 644 "{}" "$(DESTDIR)/$(DATADIR)/netplan/{}" \; |
76 | install -m 755 src/netplan.script $(DESTDIR)/$(DATADIR)/netplan/ |
77 | ln -srf $(DESTDIR)/$(DATADIR)/netplan/netplan.script $(DESTDIR)/$(SBINDIR)/netplan |
78 | ln -srf $(DESTDIR)/$(ROOTLIBEXECDIR)/netplan/generate $(DESTDIR)/$(SYSTEMD_GENERATOR_DIR)/netplan |
79 | + # lib |
80 | + install -m 644 *.so.* $(DESTDIR)/$(LIBDIR)/ |
81 | + ln -snf libnetplan.so.$(NETPLAN_SOVER) $(DESTDIR)/$(LIBDIR)/libnetplan.so |
82 | + # headers, dev data |
83 | + install -m 644 src/*.h $(DESTDIR)/$(INCLUDEDIR)/netplan/ |
84 | + # TODO: install pkg-config once available |
85 | + # docs, data |
86 | install -m 644 doc/*.html $(DESTDIR)/$(DOCDIR)/netplan/ |
87 | install -m 644 examples/*.yaml $(DESTDIR)/$(DOCDIR)/netplan/examples/ |
88 | install -m 644 doc/*.5 $(DESTDIR)/$(MANDIR)/man5/ |
89 | install -m 644 doc/*.8 $(DESTDIR)/$(MANDIR)/man8/ |
90 | - install -D -m 644 src/netplan-wpa@.service $(DESTDIR)/$(SYSTEMD_UNIT_DIR)/netplan-wpa@.service |
91 | install -T -D -m 644 netplan.completions $(DESTDIR)/$(BASH_COMPLETIONS_DIR)/netplan |
92 | # dbus |
93 | mkdir -p $(DESTDIR)/$(DATADIR)/dbus-1/system.d $(DESTDIR)/$(DATADIR)/dbus-1/system-services |
94 | diff --git a/debian/changelog b/debian/changelog |
95 | index ad35a3b..2e8084d 100644 |
96 | --- a/debian/changelog |
97 | +++ b/debian/changelog |
98 | @@ -1,3 +1,83 @@ |
99 | +netplan.io (0.99-0ubuntu3~19.10.1) UNRELEASED; urgency=medium |
100 | + |
101 | + * Backport netplan.io 0.99 to 19.10. (LP: #1871825) |
102 | + * Include proper upstream fix for "Not connect to WiFi after 'netplan apply' |
103 | + (LP: #1874377) |
104 | + |
105 | + -- Lukas Märdian <lukas.maerdian@canonical.com> Mon, 04 May 2020 11:48:04 +0200 |
106 | + |
107 | +netplan.io (0.99-0ubuntu3) groovy; urgency=medium |
108 | + |
109 | + * Drop d/p/0001-Not-connect-to-WiFi-after-netplan-apply.patch |
110 | + - Replaced by upstream fix |
111 | + * Add d/p/0001-Fix-LP-1874377-Not-connect-to-WiFi-after-netplan-app.patch: |
112 | + - Proper upstream fix, which handles edge cases better and contains tests |
113 | + |
114 | + -- Lukas Märdian <lukas.maerdian@canonical.com> Thu, 30 Apr 2020 12:51:36 +0200 |
115 | + |
116 | +netplan.io (0.99-0ubuntu2) focal; urgency=medium |
117 | + |
118 | + [ Lukas Märdian ] |
119 | + * debian/patches/0001-Not-connect-to-WiFi-after-netplan-apply.patch: |
120 | + - Seems like the 'netplan apply' command was not properly adopted when |
121 | + wired wpa_supplicant support was introduced. |
122 | + |
123 | + -- Łukasz 'sil2100' Zemczak <lukasz.zemczak@ubuntu.com> Thu, 23 Apr 2020 15:22:07 +0200 |
124 | + |
125 | +netplan.io (0.99-0ubuntu1) focal; urgency=medium |
126 | + |
127 | + [ Łukasz 'sil2100' Zemczak ] |
128 | + * New upstream release: 0.99 (LP: #1871825) |
129 | + - Fixed setting MTUBytes= in .network files as well |
130 | + - Added "phase2" keyword to "auth" section |
131 | + - Allowing "critical" to be used without "dhcp4"/"dhcp6" enabled |
132 | + - Added support for GSM modems in the NetworkManager backend (with the |
133 | + "modems" keyword) |
134 | + - Added "emit-lldp" option for networkd backend (LP: #1862607) |
135 | + - Fixed netplan incorrectly generating WPA PSK hex (LP: #1867690) |
136 | + - Split out the netplan parser into a separate libnetplan library |
137 | + - Added "ipv6-address-generation" field for NM backend |
138 | + - Added WiFi flags for "bssid"/"band"/"channel" |
139 | + - Added support for SR-IOV network devices |
140 | + * debian/copyright: Change contact address as Matt is no longer available |
141 | + via the previous e-mail. |
142 | + * debian/control: Add new libnetplan packages |
143 | + * Drop d/p/0002-Adopt-integration-tests-for-NetworkManager-v1.22-foc.patch: |
144 | + included in upstream release |
145 | + |
146 | + [ Lukas Märdian ] |
147 | + * Drop d/p/workaround_tests_issues.patch: |
148 | + The problem was solved upstream and is integrated via |
149 | + d/p/0002-Adopt-integration-tests-for-NetworkManager-v1.22-foc.patch |
150 | + |
151 | + -- Łukasz 'sil2100' Zemczak <lukasz.zemczak@ubuntu.com> Thu, 16 Apr 2020 09:13:50 +0200 |
152 | + |
153 | +netplan.io (0.98-0ubuntu4) focal; urgency=medium |
154 | + |
155 | + [ Lukas Märdian ] |
156 | + * d/p/0002-Adopt-integration-tests-for-NetworkManager-v1.22-foc.patch: |
157 | + Adopt integration tests for NetworkManager v1.22 (focal) |
158 | + * debian/tests/control: add new autopkgtest dependencies for the new |
159 | + integration tests. |
160 | + |
161 | + -- Łukasz 'sil2100' Zemczak <lukasz.zemczak@ubuntu.com> Mon, 23 Mar 2020 09:24:39 +0100 |
162 | + |
163 | +netplan.io (0.98-0ubuntu3) focal; urgency=medium |
164 | + |
165 | + * No change rebuild to get Testsuite-Triggers restored, the previous |
166 | + upload was built on an older serie/dpkg version which lead to the |
167 | + dsc to be missing the reference |
168 | + |
169 | + -- Sebastien Bacher <seb128@ubuntu.com> Tue, 03 Mar 2020 11:31:26 +0100 |
170 | + |
171 | +netplan.io (0.98-0ubuntu2) focal; urgency=medium |
172 | + |
173 | + * debian/patches/workaround_tests_issues.patch: |
174 | + - workaround a test issue, the default route seems to take a bit of |
175 | + time to be applied in n-m, wait for it before erroring out |
176 | + |
177 | + -- Sebastien Bacher <seb128@ubuntu.com> Wed, 29 Jan 2020 23:33:03 +0100 |
178 | + |
179 | netplan.io (0.98-0ubuntu1) eoan; urgency=medium |
180 | |
181 | * New upstream release: 0.98 (LP: #1840832) |
182 | diff --git a/debian/control b/debian/control |
183 | index 533e943..d6a69b1 100644 |
184 | --- a/debian/control |
185 | +++ b/debian/control |
186 | @@ -34,6 +34,7 @@ Multi-Arch: foreign |
187 | Depends: ${shlibs:Depends}, |
188 | ${misc:Depends}, |
189 | iproute2, |
190 | + libnetplan0 (>= ${binary:Version}), |
191 | python3, |
192 | python3-yaml, |
193 | python3-netifaces, |
194 | @@ -51,3 +52,37 @@ Description: YAML network configuration abstraction for various backends |
195 | networking daemon. |
196 | . |
197 | Currently supported backends are networkd and NetworkManager. |
198 | + |
199 | +Package: libnetplan0 |
200 | +Architecture: any |
201 | +Multi-Arch: same |
202 | +Depends: ${shlibs:Depends}, |
203 | + ${misc:Depends}, |
204 | +Description: YAML network configuration abstraction runtime library |
205 | + netplan reads YAML network configuration files which are written |
206 | + by administrators, installers, cloud image instantiations, or other OS |
207 | + deployments. During early boot it then generates backend specific |
208 | + configuration files in /run to hand off control of devices to a particular |
209 | + networking daemon. |
210 | + . |
211 | + Currently supported backends are networkd and NetworkManager. |
212 | + . |
213 | + This package contains the necessary runtime library files. |
214 | + |
215 | +Package: libnetplan-dev |
216 | +Architecture: any |
217 | +Multi-Arch: same |
218 | +Depends: ${misc:Depends}, |
219 | + libnetplan0 (= ${binary:Version}), |
220 | +Description: Development files for netplan's libnetplan runtime library |
221 | + netplan reads YAML network configuration files which are written |
222 | + by administrators, installers, cloud image instantiations, or other OS |
223 | + deployments. During early boot it then generates backend specific |
224 | + configuration files in /run to hand off control of devices to a particular |
225 | + networking daemon. |
226 | + . |
227 | + Currently supported backends are networkd and NetworkManager. |
228 | + . |
229 | + This package contains development files for developers wanting to use |
230 | + libnetplan in their applications. |
231 | + |
232 | diff --git a/debian/copyright b/debian/copyright |
233 | index 5af515c..556c410 100644 |
234 | --- a/debian/copyright |
235 | +++ b/debian/copyright |
236 | @@ -1,6 +1,6 @@ |
237 | Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ |
238 | Upstream-Name: netplan.io |
239 | -Upstream-Contact: Mathieu Trudel-Lapierre <mathieu.trudel-lapierre@canonical.com> |
240 | +Upstream-Contact: Łukasz 'sil2100' Zemczak <lukasz.zemczak@canonical.com> |
241 | Source: https://github.com/CanonicalLtd/netplan |
242 | |
243 | Files: * |
244 | diff --git a/debian/libnetplan-dev.dirs b/debian/libnetplan-dev.dirs |
245 | new file mode 100644 |
246 | index 0000000..99379cd |
247 | --- /dev/null |
248 | +++ b/debian/libnetplan-dev.dirs |
249 | @@ -0,0 +1 @@ |
250 | +usr/include/netplan |
251 | diff --git a/debian/libnetplan-dev.install b/debian/libnetplan-dev.install |
252 | new file mode 100644 |
253 | index 0000000..911f5de |
254 | --- /dev/null |
255 | +++ b/debian/libnetplan-dev.install |
256 | @@ -0,0 +1,2 @@ |
257 | +usr/include/netplan/*.h |
258 | +usr/lib/*/libnetplan*.so |
259 | diff --git a/debian/libnetplan0.install b/debian/libnetplan0.install |
260 | new file mode 100644 |
261 | index 0000000..514ba93 |
262 | --- /dev/null |
263 | +++ b/debian/libnetplan0.install |
264 | @@ -0,0 +1 @@ |
265 | +usr/lib/*/libnetplan*.so.* |
266 | diff --git a/debian/libnetplan0.symbols b/debian/libnetplan0.symbols |
267 | new file mode 100644 |
268 | index 0000000..62adadd |
269 | --- /dev/null |
270 | +++ b/debian/libnetplan0.symbols |
271 | @@ -0,0 +1,25 @@ |
272 | +libnetplan.so.0.0 libnetplan0 #MINVER# |
273 | + NETPLAN_OPTIONAL_ADDRESS_TYPES@Base 0.99 |
274 | + NETPLAN_WIFI_WOWLAN_TYPES@Base 0.99 |
275 | + current_file@Base 0.99 |
276 | + g_string_free_to_file@Base 0.99 |
277 | + is_ip4_address@Base 0.99 |
278 | + is_ip6_address@Base 0.99 |
279 | + missing_id@Base 0.99 |
280 | + missing_ids_found@Base 0.99 |
281 | + netdefs@Base 0.99 |
282 | + netdefs_ordered@Base 0.99 |
283 | + netplan_finish_parse@Base 0.99 |
284 | + netplan_get_global_backend@Base 0.99 |
285 | + netplan_parse_yaml@Base 0.99 |
286 | + parser_error@Base 0.99 |
287 | + safe_mkdir_p_dir@Base 0.99 |
288 | + tunnel_mode_to_string@Base 0.99 |
289 | + unlink_glob@Base 0.99 |
290 | + validate_backend_rules@Base 0.99 |
291 | + validate_netdef_grammar@Base 0.99 |
292 | + wifi_frequency_24@Base 0.99 |
293 | + wifi_frequency_5@Base 0.99 |
294 | + wifi_get_freq24@Base 0.99 |
295 | + wifi_get_freq5@Base 0.99 |
296 | + yaml_error@Base 0.99 |
297 | diff --git a/debian/dirs b/debian/netplan.io.dirs |
298 | similarity index 100% |
299 | rename from debian/dirs |
300 | rename to debian/netplan.io.dirs |
301 | diff --git a/debian/netplan.io.install b/debian/netplan.io.install |
302 | new file mode 100644 |
303 | index 0000000..88c78f1 |
304 | --- /dev/null |
305 | +++ b/debian/netplan.io.install |
306 | @@ -0,0 +1,4 @@ |
307 | +lib/netplan/* |
308 | +lib/systemd/system-generators/netplan |
309 | +usr/share/* |
310 | +usr/sbin/netplan |
311 | diff --git a/debian/patches/0001-Fix-LP-1874377-Not-connect-to-WiFi-after-netplan-app.patch b/debian/patches/0001-Fix-LP-1874377-Not-connect-to-WiFi-after-netplan-app.patch |
312 | new file mode 100644 |
313 | index 0000000..d401e97 |
314 | --- /dev/null |
315 | +++ b/debian/patches/0001-Fix-LP-1874377-Not-connect-to-WiFi-after-netplan-app.patch |
316 | @@ -0,0 +1,175 @@ |
317 | +From: Lukas Maerdian <lukas.maerdian@canonical.com> |
318 | +Date: Tue, 28 Apr 2020 14:35:36 +0200 |
319 | +Subject: Fix LP#1874377: Not connect to WiFi after 'netplan apply' (#133) |
320 | + |
321 | +* Fix LP#1874377: Not connect to WiFi after 'netplan apply' |
322 | + |
323 | +Seems like the 'netplan apply' command was not properly adopted in #109 when wired wpa_supplicant support was introduced. |
324 | + |
325 | +Fixes: https://bugs.launchpad.net/ubuntu/+source/netplan.io/+bug/1874377 |
326 | +--- |
327 | + netplan/cli/commands/apply.py | 10 ++++-- |
328 | + netplan/cli/utils.py | 7 +++++ |
329 | + src/networkd.c | 4 +++ |
330 | + tests/generator/test_wifis.py | 71 +++++++++++++++++++++++++++++++++++++++++++ |
331 | + tests/integration/base.py | 2 +- |
332 | + 5 files changed, 91 insertions(+), 3 deletions(-) |
333 | + |
334 | +diff --git a/netplan/cli/commands/apply.py b/netplan/cli/commands/apply.py |
335 | +index 0ec95f5..cf9f122 100644 |
336 | +--- a/netplan/cli/commands/apply.py |
337 | ++++ b/netplan/cli/commands/apply.py |
338 | +@@ -108,7 +108,13 @@ class NetplanApply(utils.NetplanCommand): |
339 | + # stop backends |
340 | + if restart_networkd: |
341 | + logging.debug('netplan generated networkd configuration changed, restarting networkd') |
342 | +- utils.systemctl_networkd('stop', sync=sync, extra_services=['netplan-wpa@*.service']) |
343 | ++ wpa_services = ['netplan-wpa-*.service'] |
344 | ++ # Historically (up to v0.98) we had netplan-wpa@*.service files, in case of an |
345 | ++ # upgraded system, we need to make sure to stop those. |
346 | ++ if utils.systemctl_is_active('netplan-wpa@*.service'): |
347 | ++ wpa_services.insert(0, 'netplan-wpa@*.service') |
348 | ++ utils.systemctl_networkd('stop', sync=sync, extra_services=wpa_services) |
349 | ++ |
350 | + else: |
351 | + logging.debug('no netplan generated networkd configuration exists') |
352 | + |
353 | +@@ -169,7 +175,7 @@ class NetplanApply(utils.NetplanCommand): |
354 | + |
355 | + # (re)start backends |
356 | + if restart_networkd: |
357 | +- netplan_wpa = [os.path.basename(f) for f in glob.glob('/run/systemd/system/*.wants/netplan-wpa@*.service')] |
358 | ++ netplan_wpa = [os.path.basename(f) for f in glob.glob('/run/systemd/system/*.wants/netplan-wpa-*.service')] |
359 | + utils.systemctl_networkd('start', sync=sync, extra_services=netplan_wpa) |
360 | + if restart_nm: |
361 | + utils.systemctl_network_manager('start', sync=sync) |
362 | +diff --git a/netplan/cli/utils.py b/netplan/cli/utils.py |
363 | +index 5f54b1a..c0eee03 100644 |
364 | +--- a/netplan/cli/utils.py |
365 | ++++ b/netplan/cli/utils.py |
366 | +@@ -86,6 +86,13 @@ def systemctl_networkd(action, sync=False, extra_services=[]): # pragma: nocove |
367 | + subprocess.check_call(command) |
368 | + |
369 | + |
370 | ++def systemctl_is_active(unit_pattern): # pragma: nocover (covered in autopkgtest) |
371 | ++ '''Return True if at least one matching unit is running''' |
372 | ++ if subprocess.call(['systemctl', '--quiet', 'is-active', unit_pattern]) == 0: |
373 | ++ return True |
374 | ++ return False |
375 | ++ |
376 | ++ |
377 | + def get_interface_driver_name(interface, only_down=False): # pragma: nocover (covered in autopkgtest) |
378 | + devdir = os.path.join('/sys/class/net', interface) |
379 | + if only_down: |
380 | +diff --git a/src/networkd.c b/src/networkd.c |
381 | +index e2bb111..6f6173a 100644 |
382 | +--- a/src/networkd.c |
383 | ++++ b/src/networkd.c |
384 | +@@ -990,8 +990,12 @@ cleanup_networkd_conf(const char* rootdir) |
385 | + { |
386 | + unlink_glob(rootdir, "/run/systemd/network/10-netplan-*"); |
387 | + unlink_glob(rootdir, "/run/netplan/wpa-*.conf"); |
388 | ++ unlink_glob(rootdir, "/run/systemd/system/systemd-networkd.service.wants/netplan-wpa-*.service"); |
389 | + unlink_glob(rootdir, "/run/systemd/system/netplan-wpa-*.service"); |
390 | + unlink_glob(rootdir, "/run/udev/rules.d/99-netplan-*"); |
391 | ++ /* Historically (up to v0.98) we had netplan-wpa@*.service files, in case of an |
392 | ++ * upgraded system, we need to make sure to clean those up. */ |
393 | ++ unlink_glob(rootdir, "/run/systemd/system/systemd-networkd.service.wants/netplan-wpa@*.service"); |
394 | + } |
395 | + |
396 | + /** |
397 | +diff --git a/tests/generator/test_wifis.py b/tests/generator/test_wifis.py |
398 | +index 8eb804e..d5b79cf 100644 |
399 | +--- a/tests/generator/test_wifis.py |
400 | ++++ b/tests/generator/test_wifis.py |
401 | +@@ -116,6 +116,77 @@ network={ |
402 | + self.assertTrue(os.path.islink(os.path.join( |
403 | + self.workdir.name, 'run/systemd/system/systemd-networkd.service.wants/netplan-wpa-wl0.service'))) |
404 | + |
405 | ++ def test_wifi_upgrade(self): |
406 | ++ # pretend an old 'netplan-wpa@*.service' link still exists on an upgraded system |
407 | ++ os.makedirs(os.path.join(self.workdir.name, 'lib/systemd/system')) |
408 | ++ os.makedirs(os.path.join(self.workdir.name, 'run/systemd/system/systemd-networkd.service.wants')) |
409 | ++ with open(os.path.join(self.workdir.name, 'lib/systemd/system/netplan-wpa@.service'), 'w') as out: |
410 | ++ out.write('''[Unit] |
411 | ++Description=WPA supplicant for netplan %I |
412 | ++DefaultDependencies=no |
413 | ++Requires=sys-subsystem-net-devices-%i.device |
414 | ++After=sys-subsystem-net-devices-%i.device |
415 | ++Before=network.target |
416 | ++Wants=network.target |
417 | ++ |
418 | ++[Service] |
419 | ++Type=simple |
420 | ++ExecStart=/sbin/wpa_supplicant -c /run/netplan/wpa-%I.conf -i%I''') |
421 | ++ os.symlink(os.path.join(self.workdir.name, 'lib/systemd/system/netplan-wpa@.service'), |
422 | ++ os.path.join(self.workdir.name, 'run/systemd/system/systemd-networkd.service.wants/netplan-wpa@wl0.service')) |
423 | ++ |
424 | ++ # run generate, which should cleanup the old files/symlinks |
425 | ++ self.generate('''network: |
426 | ++ version: 2 |
427 | ++ wifis: |
428 | ++ wl0: |
429 | ++ access-points: |
430 | ++ "Joe's Home": |
431 | ++ password: "s0s3kr1t" |
432 | ++ dhcp4: yes''') |
433 | ++ |
434 | ++ # verify new files/links exist, while old have been removed |
435 | ++ self.assertTrue(os.path.isfile(os.path.join( |
436 | ++ self.workdir.name, 'run/systemd/system/netplan-wpa-wl0.service'))) |
437 | ++ self.assertTrue(os.path.islink(os.path.join( |
438 | ++ self.workdir.name, 'run/systemd/system/systemd-networkd.service.wants/netplan-wpa-wl0.service'))) |
439 | ++ # old files/links |
440 | ++ self.assertTrue(os.path.isfile(os.path.join( |
441 | ++ self.workdir.name, 'lib/systemd/system/netplan-wpa@.service'))) |
442 | ++ self.assertFalse(os.path.islink(os.path.join( |
443 | ++ self.workdir.name, 'run/systemd/system/systemd-networkd.service.wants/netplan-wpa@wl0.service'))) |
444 | ++ |
445 | ++ # pretend another old systemd service file exists for wl1 |
446 | ++ os.symlink(os.path.join(self.workdir.name, 'lib/systemd/system/netplan-wpa@.service'), |
447 | ++ os.path.join(self.workdir.name, 'run/systemd/system/systemd-networkd.service.wants/netplan-wpa@wl1.service')) |
448 | ++ |
449 | ++ # run generate again, to verify the historical netplan-wpa@.service links and wl0 links are gone |
450 | ++ self.generate('''network: |
451 | ++ version: 2 |
452 | ++ wifis: |
453 | ++ wl1: |
454 | ++ access-points: |
455 | ++ "Other Home": |
456 | ++ password: "s0s3kr1t" |
457 | ++ dhcp4: yes''') |
458 | ++ |
459 | ++ # verify new files/links exist, while old have been removed |
460 | ++ self.assertTrue(os.path.isfile(os.path.join( |
461 | ++ self.workdir.name, 'run/systemd/system/netplan-wpa-wl1.service'))) |
462 | ++ self.assertTrue(os.path.islink(os.path.join( |
463 | ++ self.workdir.name, 'run/systemd/system/systemd-networkd.service.wants/netplan-wpa-wl1.service'))) |
464 | ++ # old files/links |
465 | ++ self.assertTrue(os.path.isfile(os.path.join( |
466 | ++ self.workdir.name, 'lib/systemd/system/netplan-wpa@.service'))) |
467 | ++ self.assertFalse(os.path.islink(os.path.join( |
468 | ++ self.workdir.name, 'run/systemd/system/systemd-networkd.service.wants/netplan-wpa@wl1.service'))) |
469 | ++ self.assertFalse(os.path.islink(os.path.join( |
470 | ++ self.workdir.name, 'run/systemd/system/systemd-networkd.service.wants/netplan-wpa@wl0.service'))) |
471 | ++ self.assertFalse(os.path.isfile(os.path.join( |
472 | ++ self.workdir.name, 'run/systemd/system/netplan-wpa-wl0.service'))) |
473 | ++ self.assertFalse(os.path.islink(os.path.join( |
474 | ++ self.workdir.name, 'run/systemd/system/systemd-networkd.service.wants/netplan-wpa-wl0.service'))) |
475 | ++ |
476 | + def test_wifi_route(self): |
477 | + self.generate('''network: |
478 | + version: 2 |
479 | +diff --git a/tests/integration/base.py b/tests/integration/base.py |
480 | +index ed7100e..16fd2ee 100644 |
481 | +--- a/tests/integration/base.py |
482 | ++++ b/tests/integration/base.py |
483 | +@@ -93,7 +93,7 @@ class IntegrationTestsBase(unittest.TestCase): |
484 | + pass |
485 | + |
486 | + def tearDown(self): |
487 | +- subprocess.call(['systemctl', 'stop', 'NetworkManager', 'systemd-networkd', 'netplan-wpa@*', |
488 | ++ subprocess.call(['systemctl', 'stop', 'NetworkManager', 'systemd-networkd', 'netplan-wpa-*', |
489 | + 'systemd-networkd.socket']) |
490 | + # NM has KillMode=process and leaks dhclient processes |
491 | + subprocess.call(['systemctl', 'kill', 'NetworkManager']) |
492 | diff --git a/debian/patches/series b/debian/patches/series |
493 | index e69de29..817f04c 100644 |
494 | --- a/debian/patches/series |
495 | +++ b/debian/patches/series |
496 | @@ -0,0 +1 @@ |
497 | +0001-Fix-LP-1874377-Not-connect-to-WiFi-after-netplan-app.patch |
498 | diff --git a/debian/rules b/debian/rules |
499 | index 2d33f6a..f64d5f7 100755 |
500 | --- a/debian/rules |
501 | +++ b/debian/rules |
502 | @@ -1,4 +1,7 @@ |
503 | #!/usr/bin/make -f |
504 | |
505 | %: |
506 | - dh $@ |
507 | + dh $@ --fail-missing |
508 | + |
509 | +override_dh_auto_install: |
510 | + dh_auto_install -- LIBDIR=/usr/lib/${DEB_HOST_MULTIARCH}/ |
511 | diff --git a/debian/tests/control b/debian/tests/control |
512 | index 6202b41..727e3da 100644 |
513 | --- a/debian/tests/control |
514 | +++ b/debian/tests/control |
515 | @@ -5,6 +5,9 @@ Depends: @, |
516 | network-manager, |
517 | hostapd, |
518 | dnsmasq-base, |
519 | + libnm0, |
520 | + python3-gi, |
521 | + gir1.2-nm-1.0, |
522 | Restrictions: allow-stderr, needs-root, isolation-machine |
523 | Features: test-name=ethernets |
524 | |
525 | @@ -15,6 +18,9 @@ Depends: @, |
526 | network-manager, |
527 | hostapd, |
528 | dnsmasq-base, |
529 | + libnm0, |
530 | + python3-gi, |
531 | + gir1.2-nm-1.0, |
532 | Restrictions: allow-stderr, needs-root, isolation-machine |
533 | Features: test-name=bridges |
534 | |
535 | @@ -25,6 +31,9 @@ Depends: @, |
536 | network-manager, |
537 | hostapd, |
538 | dnsmasq-base, |
539 | + libnm0, |
540 | + python3-gi, |
541 | + gir1.2-nm-1.0, |
542 | Restrictions: allow-stderr, needs-root, isolation-machine |
543 | Features: test-name=bonds |
544 | |
545 | @@ -35,6 +44,9 @@ Depends: @, |
546 | network-manager, |
547 | hostapd, |
548 | dnsmasq-base, |
549 | + libnm0, |
550 | + python3-gi, |
551 | + gir1.2-nm-1.0, |
552 | Restrictions: allow-stderr, needs-root, isolation-machine |
553 | Features: test-name=routing |
554 | |
555 | @@ -45,6 +57,9 @@ Depends: @, |
556 | network-manager, |
557 | hostapd, |
558 | dnsmasq-base, |
559 | + libnm0, |
560 | + python3-gi, |
561 | + gir1.2-nm-1.0, |
562 | Restrictions: allow-stderr, needs-root, isolation-machine |
563 | Features: test-name=vlans |
564 | |
565 | @@ -55,6 +70,9 @@ Depends: @, |
566 | network-manager, |
567 | hostapd, |
568 | dnsmasq-base, |
569 | + libnm0, |
570 | + python3-gi, |
571 | + gir1.2-nm-1.0, |
572 | Restrictions: allow-stderr, needs-root, isolation-machine, flaky |
573 | Features: test-name=wifi |
574 | |
575 | @@ -65,6 +83,9 @@ Depends: @, |
576 | network-manager, |
577 | hostapd, |
578 | dnsmasq-base, |
579 | + libnm0, |
580 | + python3-gi, |
581 | + gir1.2-nm-1.0, |
582 | Restrictions: allow-stderr, needs-root, isolation-machine |
583 | Features: test-name=tunnels |
584 | |
585 | @@ -75,6 +96,9 @@ Depends: @, |
586 | network-manager, |
587 | hostapd, |
588 | dnsmasq-base, |
589 | + libnm0, |
590 | + python3-gi, |
591 | + gir1.2-nm-1.0, |
592 | Restrictions: allow-stderr, needs-root, isolation-machine |
593 | Features: test-name=scenarios |
594 | |
595 | @@ -85,6 +109,9 @@ Depends: @, |
596 | network-manager, |
597 | hostapd, |
598 | dnsmasq-base, |
599 | + libnm0, |
600 | + python3-gi, |
601 | + gir1.2-nm-1.0, |
602 | Restrictions: allow-stderr, needs-root, isolation-machine |
603 | Features: test-name=regressions |
604 | |
605 | diff --git a/doc/netplan.md b/doc/netplan.md |
606 | index 1cf8ded..c4b0ba3 100644 |
607 | --- a/doc/netplan.md |
608 | +++ b/doc/netplan.md |
609 | @@ -30,7 +30,7 @@ either of those directories shadows a file with the same name in |
610 | The top-level node in a netplan configuration file is a ``network:`` mapping |
611 | that contains ``version: 2`` (the YAML currently being used by curtin, MaaS, |
612 | etc. is version 1), and then device definitions grouped by their type, such as |
613 | -``ethernets:``, ``wifis:``, or ``bridges:``. These are the types that our |
614 | +``ethernets:``, ``modems:``, ``wifis:``, or ``bridges:``. These are the types that our |
615 | renderer can understand and are supported by our backends. |
616 | |
617 | Each type block contains device definitions as a map where the keys (called |
618 | @@ -52,7 +52,7 @@ and the ID field has a different interpretation for each: |
619 | |
620 | Physical devices |
621 | |
622 | -: (Examples: ethernet, wifi) These can dynamically come and go between |
623 | +: (Examples: ethernet, modem, wifi) These can dynamically come and go between |
624 | reboots and even during runtime (hotplugging). In the generic case, they |
625 | can be selected by ``match:`` rules on desired properties, such as name/name |
626 | pattern, MAC address, driver, or device paths. In general these will match |
627 | @@ -133,6 +133,10 @@ Virtual devices |
628 | |
629 | : Enable wake on LAN. Off by default. |
630 | |
631 | +``emit-lldp`` (bool) |
632 | + |
633 | +: (networkd backend only) Whether to emit LLDP packets. Off by default. |
634 | + |
635 | |
636 | ## Common properties for all device types |
637 | |
638 | @@ -143,6 +147,11 @@ Virtual devices |
639 | in ``networks:``, for a device type (in e. g. ``ethernets:``) or |
640 | for a particular device definition. Default is ``networkd``. |
641 | |
642 | + The ``renderer`` property has one additional acceptable value for vlan objects |
643 | + (i. e. defined in ``vlans:``): ``sriov``. If a vlan is defined with the ``sriov`` |
644 | + renderer for an SR-IOV Virtual Function interface, this causes netplan to set |
645 | + up a hardware VLAN filter for it. There can be only one defined per VF. |
646 | + |
647 | ``dhcp4`` (bool) |
648 | |
649 | : Enable DHCP for IPv4. Off by default. |
650 | @@ -198,7 +207,7 @@ Virtual devices |
651 | |
652 | : (networkd backend only) Designate the connection as "critical to the |
653 | system", meaning that special care will be taken by systemd-networkd to |
654 | - not release the IP from DHCP when the daemon is restarted. |
655 | + not release the assigned IP when the daemon is restarted. |
656 | |
657 | ``dhcp-identifier`` (scalar) |
658 | |
659 | @@ -235,6 +244,12 @@ Virtual devices |
660 | |
661 | Example: ``addresses: [192.168.14.2/24, "2001:1::1/64"]`` |
662 | |
663 | +``ipv6-address-generation`` (scalar) |
664 | + |
665 | +: Configure method for creating the address for use with RFC4862 IPv6 |
666 | + Stateless Address Autoconfiguration. Possible values are ``eui64`` |
667 | + or ``stable-privacy``. |
668 | + |
669 | ``gateway4``, ``gateway6`` (scalar) |
670 | |
671 | : Set default gateway for IPv4/6, for manual address configuration. This |
672 | @@ -540,10 +555,77 @@ interfaces, as well as individual wifi networks, by means of the ``auth`` block. |
673 | : Password to use to decrypt the private key specified in |
674 | ``client-key`` if it is encrypted. |
675 | |
676 | + ``phase2-auth`` (scalar) |
677 | + : Phase 2 authentication mechanism. |
678 | + |
679 | |
680 | ## Properties for device type ``ethernets:`` |
681 | -Ethernet device definitions do not support any specific properties beyond the |
682 | -common ones described above. |
683 | +Ethernet device definitions, beyond common ones described above, also support |
684 | +some additional properties that can be used for SR-IOV devices. |
685 | + |
686 | +``link`` (scalar) |
687 | + |
688 | +: (SR-IOV devices only) The ``link`` property declares the device as a |
689 | + Virtual Function of the selected Physical Function device, as identified |
690 | + by the given netplan id. |
691 | + |
692 | +Example: |
693 | + |
694 | + ethernets: |
695 | + enp1: {...} |
696 | + enp1s16f1: |
697 | + link: enp1 |
698 | + |
699 | +``virtual-function-count`` (scalar) |
700 | + |
701 | +: (SR-IOV devices only) In certain special cases VFs might need to be |
702 | + configured outside of netplan. For such configurations ``virtual-function-count`` |
703 | + can be optionally used to set an explicit number of Virtual Functions for |
704 | + the given Physical Function. If unset, the default is to create only as many |
705 | + VFs as are defined in the netplan configuration. This should be used for special |
706 | + cases only. |
707 | + |
708 | +## Properties for device type ``modems:`` |
709 | +GSM/CDMA modem configuration is only supported for the ``NetworkManager`` backend. ``systemd-networkd`` does |
710 | +not support modems. |
711 | + |
712 | +``apn`` (scalar) |
713 | +: Set the carrier APN (Access Point Name). This can be omitted if ``auto-config`` is enabled. |
714 | + |
715 | +``auto-config`` (bool) |
716 | +: Specify whether to try and autoconfigure the modem by doing a lookup of the carrier |
717 | + against the Mobile Broadband Provider database. This may not work for all carriers. |
718 | + |
719 | +``device-id`` (scalar) |
720 | +: Specify the device ID (as given by the WWAN management service) of the modem to match. |
721 | + This can be found using ``mmcli``. |
722 | + |
723 | +``network-id`` (scalar) |
724 | +: Specify the Network ID (GSM LAI format). If this is specified, the device will not roam networks. |
725 | + |
726 | +``number`` (scalar) |
727 | +: The number to dial to establish the connection to the mobile broadband network. (Deprecated for GSM) |
728 | + |
729 | +``password`` (scalar) |
730 | +: Specify the password used to authenticate with the carrier network. This can be omitted |
731 | + if ``auto-config`` is enabled. |
732 | + |
733 | +``pin`` (scalar) |
734 | +: Specify the SIM PIN to allow it to operate if a PIN is set. |
735 | + |
736 | +``sim-id`` (scalar) |
737 | +: Specify the SIM unique identifier (as given by the WWAN management service) which this |
738 | + connection applies to. If given, the connection will apply to any device also allowed by |
739 | + ``device-id`` which contains a SIM card matching the given identifier. |
740 | + |
741 | +``sim-operator-id`` (scalar) |
742 | +: Specify the MCC/MNC string (such as "310260" or "21601") which identifies the carrier that |
743 | + this connection should apply to. If given, the connection will apply to any device also |
744 | + allowed by ``device-id`` and ``sim-id`` which contains a SIM card provisioned by the given operator. |
745 | + |
746 | +``username`` (scalar) |
747 | +: Specify the username used to authentiate with the carrier network. This can be omitted if |
748 | + ``auto-config`` is enabled. |
749 | |
750 | ## Properties for device type ``wifis:`` |
751 | Note that ``systemd-networkd`` does not natively support wifi, so you need |
752 | @@ -575,6 +657,28 @@ wpasupplicant installed if you let the ``networkd`` renderer handle wifi. |
753 | and ``adhoc`` (peer to peer networks without a central access point). |
754 | ``ap`` is only supported with NetworkManager. |
755 | |
756 | + ``bssid`` (scalar) |
757 | + : If specified, directs the device to only associate with the given |
758 | + access point. |
759 | + |
760 | + ``band`` (scalar) |
761 | + : Possible bands are ``5GHz`` (for 5GHz 802.11a) and ``2.4GHz`` |
762 | + (for 2.4GHz 802.11), do not restrict the 802.11 frequency band of the |
763 | + network if unset (the default). |
764 | + |
765 | + ``channel`` (scalar) |
766 | + : Wireless channel to use for the Wi-Fi connection. Because channel |
767 | + numbers overlap between bands, this property takes effect only if |
768 | + the ``band`` property is also set. |
769 | + |
770 | +``wakeonwlan`` (sequence of scalars) |
771 | + |
772 | +: This enables WakeOnWLan on supported devices. Not all drivers support all |
773 | + options. May be any combination of ``any``, ``disconnect``, ``magic_pkt``, |
774 | + ``gtk_rekey_failure``, ``eap_identity_req``, ``four_way_handshake``, |
775 | + ``rfkill_release`` or ``tcp`` (NetworkManager only). Or the exclusive |
776 | + ``default`` flag (the default). |
777 | + |
778 | ## Properties for device type ``bridges:`` |
779 | |
780 | ``interfaces`` (sequence of scalars) |
781 | @@ -898,6 +1002,34 @@ Example: |
782 | addresses: ... |
783 | |
784 | |
785 | +## Backend-specific configuration parameters |
786 | + |
787 | +In addition to the other fields available to configure interfaces, some |
788 | +backends may require to record some of their own parameters in netplan, |
789 | +especially if the netplan definitions are generated automatically by the |
790 | +consumer of that backend. Currently, this is only used with ``NetworkManager``. |
791 | + |
792 | +``networkmanager`` (mapping) |
793 | + |
794 | +: Keeps the NetworkManager-specific configuration parameters used by the |
795 | + daemon to recognize connections. |
796 | + |
797 | + ``name`` (scalar) |
798 | + : Set the display name for the connection. |
799 | + |
800 | + ``uuid`` (scalar) |
801 | + : Defines the UUID (unique identifier) for this connection, as |
802 | + generated by NetworkManager itself. |
803 | + |
804 | + ``stable-id`` (scalar) |
805 | + : Defines the stable ID (a different form of a connection name) used |
806 | + by NetworkManager in case the name of the connection might otherwise |
807 | + change, such as when sharing connections between users. |
808 | + |
809 | + ``device`` (scalar) |
810 | + : Defines the interface name for which this connection applies. |
811 | + |
812 | + |
813 | ## Examples |
814 | Configure an ethernet device with networkd, identified by its name, and enable |
815 | DHCP: |
816 | diff --git a/examples/dhcp_wired8021x.yaml b/examples/dhcp_wired8021x.yaml |
817 | new file mode 100644 |
818 | index 0000000..9f401dd |
819 | --- /dev/null |
820 | +++ b/examples/dhcp_wired8021x.yaml |
821 | @@ -0,0 +1,11 @@ |
822 | +network: |
823 | + version: 2 |
824 | + renderer: networkd |
825 | + ethernets: |
826 | + enp3s0: |
827 | + dhcp4: true |
828 | + auth: |
829 | + key-management: 802.1x |
830 | + method: ttls |
831 | + identity: fluffy@cisco.com |
832 | + password: hash:83...11 |
833 | diff --git a/examples/direct_connect_gateway_ipv6.yaml b/examples/direct_connect_gateway_ipv6.yaml |
834 | new file mode 100644 |
835 | index 0000000..3f821d3 |
836 | --- /dev/null |
837 | +++ b/examples/direct_connect_gateway_ipv6.yaml |
838 | @@ -0,0 +1,11 @@ |
839 | +network: |
840 | + version: 2 |
841 | + renderer: networkd |
842 | + ethernets: |
843 | + addresses: [ "2001:cafe:face:beef::dead:dead/64" ] |
844 | + routes: |
845 | + - to: "2001:cafe:face::1/128" |
846 | + scope: link |
847 | + - to: "::/0" |
848 | + via: "2001:cafe:face::1" |
849 | + on-link: true |
850 | diff --git a/examples/modem.yaml b/examples/modem.yaml |
851 | new file mode 100644 |
852 | index 0000000..043d74a |
853 | --- /dev/null |
854 | +++ b/examples/modem.yaml |
855 | @@ -0,0 +1,15 @@ |
856 | +network: |
857 | + version: 2 |
858 | + renderer: NetworkManager |
859 | + modems: |
860 | + cdc-wdm1: |
861 | + mtu: 1600 |
862 | + apn: ISP.CINGULAR |
863 | + username: ISP@CINGULARGPRS.COM |
864 | + password: CINGULAR1 |
865 | + number: "*99#" |
866 | + network-id: 24005 |
867 | + device-id: da812de91eec16620b06cd0ca5cbc7ea25245222 |
868 | + pin: 2345 |
869 | + sim-id: 89148000000060671234 |
870 | + sim-operator-id: 310260 |
871 | diff --git a/netplan/cli/commands/apply.py b/netplan/cli/commands/apply.py |
872 | index 3e7019d..0ec95f5 100644 |
873 | --- a/netplan/cli/commands/apply.py |
874 | +++ b/netplan/cli/commands/apply.py |
875 | @@ -1,7 +1,8 @@ |
876 | #!/usr/bin/python3 |
877 | # |
878 | -# Copyright (C) 2018 Canonical, Ltd. |
879 | +# Copyright (C) 2018-2020 Canonical, Ltd. |
880 | # Author: Mathieu Trudel-Lapierre <mathieu.trudel-lapierre@canonical.com> |
881 | +# Author: Łukasz 'sil2100' Zemczak <lukasz.zemczak@canonical.com> |
882 | # |
883 | # This program is free software; you can redistribute it and/or modify |
884 | # it under the terms of the GNU General Public License as published by |
885 | @@ -26,6 +27,7 @@ import shutil |
886 | |
887 | import netplan.cli.utils as utils |
888 | from netplan.configmanager import ConfigManager, ConfigurationError |
889 | +from netplan.cli.sriov import apply_sriov_config |
890 | |
891 | import netifaces |
892 | |
893 | @@ -74,7 +76,14 @@ class NetplanApply(utils.NetplanCommand): |
894 | old_files_networkd = bool(glob.glob('/run/systemd/network/*netplan-*')) |
895 | old_files_nm = bool(glob.glob('/run/NetworkManager/system-connections/netplan-*')) |
896 | |
897 | - if run_generate and subprocess.call([utils.get_generator_path()]) != 0: |
898 | + generator_call = [] |
899 | + generate_out = None |
900 | + if 'NETPLAN_PROFILE' in os.environ: |
901 | + generator_call.extend(['valgrind', '--leak-check=full']) |
902 | + generate_out = subprocess.STDOUT |
903 | + |
904 | + generator_call.append(utils.get_generator_path()) |
905 | + if run_generate and subprocess.call(generator_call, stderr=generate_out) != 0: |
906 | if exit_on_error: |
907 | sys.exit(os.EX_CONFIG) |
908 | else: |
909 | @@ -118,11 +127,22 @@ class NetplanApply(utils.NetplanCommand): |
910 | else: |
911 | logging.debug('no netplan generated NM configuration exists') |
912 | |
913 | + # Refresh devices now; restarting a backend might have made something appear. |
914 | + devices = netifaces.interfaces() |
915 | + |
916 | # evaluate config for extra steps we need to take (like renaming) |
917 | # for now, only applies to non-virtual (real) devices. |
918 | config_manager.parse() |
919 | changes = NetplanApply.process_link_changes(devices, config_manager) |
920 | |
921 | + # apply any SR-IOV related changes, if applicable |
922 | + try: |
923 | + apply_sriov_config(devices, config_manager) |
924 | + except (ConfigurationError, RuntimeError) as e: |
925 | + logging.error(str(e)) |
926 | + if exit_on_error: |
927 | + sys.exit(1) |
928 | + |
929 | # if the interface is up, we can still apply some .link file changes |
930 | devices = netifaces.interfaces() |
931 | for device in devices: |
932 | @@ -216,28 +236,9 @@ class NetplanApply(utils.NetplanCommand): |
933 | # do not rename members of virtual devices. MAC addresses |
934 | # may be the same for all interface members. |
935 | continue |
936 | - # try to get the device's driver for matching. |
937 | - devdir = os.path.join('/sys/class/net', interface) |
938 | - try: |
939 | - with open(os.path.join(devdir, 'operstate')) as f: |
940 | - state = f.read().strip() |
941 | - if state != 'down': |
942 | - logging.debug('device %s operstate is %s, not changing', interface, state) |
943 | - continue |
944 | - except IOError as e: |
945 | - logging.error('Cannot determine operstate of %s: %s', interface, str(e)) |
946 | - continue |
947 | |
948 | - try: |
949 | - driver = os.path.realpath(os.path.join(devdir, 'device', 'driver')) |
950 | - driver_name = os.path.basename(driver) |
951 | - except IOError as e: |
952 | - logging.debug('Cannot replug %s: cannot read link %s/device: %s', interface, devdir, str(e)) |
953 | - driver_name = None |
954 | - pass |
955 | - |
956 | - link = netifaces.ifaddresses(interface)[netifaces.AF_LINK][0] |
957 | - macaddress = link.get('addr') |
958 | + driver_name = utils.get_interface_driver_name(interface, only_down=True) |
959 | + macaddress = utils.get_interface_macaddress(interface) |
960 | if driver_name in matches['by-driver']: |
961 | new_name = matches['by-driver'][driver_name] |
962 | logging.debug(new_name) |
963 | diff --git a/netplan/cli/sriov.py b/netplan/cli/sriov.py |
964 | new file mode 100644 |
965 | index 0000000..8feacf1 |
966 | --- /dev/null |
967 | +++ b/netplan/cli/sriov.py |
968 | @@ -0,0 +1,320 @@ |
969 | +#!/usr/bin/python3 |
970 | +# |
971 | +# Copyright (C) 2020 Canonical, Ltd. |
972 | +# Author: Łukasz 'sil2100' Zemczak <lukasz.zemczak@canonical.com> |
973 | +# |
974 | +# This program is free software; you can redistribute it and/or modify |
975 | +# it under the terms of the GNU General Public License as published by |
976 | +# the Free Software Foundation; version 3. |
977 | +# |
978 | +# This program is distributed in the hope that it will be useful, |
979 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
980 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
981 | +# GNU General Public License for more details. |
982 | +# |
983 | +# You should have received a copy of the GNU General Public License |
984 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
985 | + |
986 | +import logging |
987 | +import os |
988 | +import subprocess |
989 | + |
990 | +from collections import defaultdict |
991 | + |
992 | +import netplan.cli.utils as utils |
993 | +from netplan.configmanager import ConfigurationError |
994 | + |
995 | +import netifaces |
996 | + |
997 | + |
998 | +def _get_target_interface(interfaces, config_manager, pf_link, pfs): |
999 | + if pf_link not in pfs: |
1000 | + # handle the match: syntax, get the actual device name |
1001 | + pf_match = config_manager.ethernets[pf_link].get('match') |
1002 | + if pf_match: |
1003 | + by_name = pf_match.get('name') |
1004 | + by_mac = pf_match.get('macaddress') |
1005 | + by_driver = pf_match.get('driver') |
1006 | + |
1007 | + for interface in interfaces: |
1008 | + if ((by_name and not utils.is_interface_matching_name(interface, by_name)) or |
1009 | + (by_mac and not utils.is_interface_matching_macaddress(interface, by_mac)) or |
1010 | + (by_driver and not utils.is_interface_matching_driver_name(interface, by_driver))): |
1011 | + continue |
1012 | + # we have a matching PF |
1013 | + # store the matching interface in the dictionary of |
1014 | + # active PFs, but error out if we matched more than one |
1015 | + if pf_link in pfs: |
1016 | + raise ConfigurationError('matched more than one interface for a PF device: %s' % pf_link) |
1017 | + pfs[pf_link] = interface |
1018 | + else: |
1019 | + # no match field, assume entry name is interface name |
1020 | + if pf_link in interfaces: |
1021 | + pfs[pf_link] = pf_link |
1022 | + |
1023 | + return pfs.get(pf_link, None) |
1024 | + |
1025 | + |
1026 | +def get_vf_count_and_functions(interfaces, config_manager, |
1027 | + vf_counts, vfs, pfs): |
1028 | + """ |
1029 | + Go through the list of netplan ethernet devices and identify which are |
1030 | + PFs and VFs, matching the former with actual networking interfaces. |
1031 | + Count how many VFs each PF will need. |
1032 | + """ |
1033 | + explicit_counts = {} |
1034 | + for ethernet, settings in config_manager.ethernets.items(): |
1035 | + if not settings: |
1036 | + continue |
1037 | + if ethernet == 'renderer': |
1038 | + continue |
1039 | + |
1040 | + # we now also support explicitly stating how many VFs should be |
1041 | + # allocated for a PF |
1042 | + explicit_num = settings.get('virtual-function-count') |
1043 | + if explicit_num: |
1044 | + pf = _get_target_interface(interfaces, config_manager, ethernet, pfs) |
1045 | + if pf: |
1046 | + explicit_counts[pf] = explicit_num |
1047 | + continue |
1048 | + |
1049 | + pf_link = settings.get('link') |
1050 | + if pf_link and pf_link in config_manager.ethernets: |
1051 | + _get_target_interface(interfaces, config_manager, pf_link, pfs) |
1052 | + |
1053 | + if pf_link in pfs: |
1054 | + vf_counts[pfs[pf_link]] += 1 |
1055 | + else: |
1056 | + logging.warning('could not match physical interface for the defined PF: %s' % pf_link) |
1057 | + # continue looking for other VFs |
1058 | + continue |
1059 | + |
1060 | + # we can't yet perform matching on VFs as those are only |
1061 | + # created later - but store, for convenience, all the valid |
1062 | + # VFs that we encounter so far |
1063 | + vfs[ethernet] = None |
1064 | + |
1065 | + # sanity check: since we can explicitly state the VF count, make sure |
1066 | + # that this number isn't smaller than the actual number of VFs declared |
1067 | + # the explicit number also overrides the number of actual VFs |
1068 | + for pf, count in explicit_counts.items(): |
1069 | + if pf in vf_counts and vf_counts[pf] > count: |
1070 | + raise ConfigurationError( |
1071 | + 'more VFs allocated than the explicit size declared: %s > %s' % (vf_counts[pf], count)) |
1072 | + vf_counts[pf] = count |
1073 | + |
1074 | + |
1075 | +def set_numvfs_for_pf(pf, vf_count): |
1076 | + """ |
1077 | + Allocate the required number of VFs for the selected PF. |
1078 | + """ |
1079 | + if vf_count > 256: |
1080 | + raise ConfigurationError( |
1081 | + 'cannot allocate more VFs for PF %s than the SR-IOV maximum: %s > 256' % (pf, vf_count)) |
1082 | + |
1083 | + devdir = os.path.join('/sys/class/net', pf, 'device') |
1084 | + numvfs_path = os.path.join(devdir, 'sriov_numvfs') |
1085 | + totalvfs_path = os.path.join(devdir, 'sriov_totalvfs') |
1086 | + try: |
1087 | + with open(totalvfs_path) as f: |
1088 | + vf_max = int(f.read().strip()) |
1089 | + except IOError as e: |
1090 | + raise RuntimeError('failed parsing sriov_totalvfs for %s: %s' % (pf, str(e))) |
1091 | + except ValueError: |
1092 | + raise RuntimeError('invalid sriov_totalvfs value for %s' % pf) |
1093 | + |
1094 | + if vf_count > vf_max: |
1095 | + raise ConfigurationError( |
1096 | + 'cannot allocate more VFs for PF %s than supported: %s > %s (sriov_totalvfs)' % (pf, vf_count, vf_max)) |
1097 | + |
1098 | + try: |
1099 | + with open(numvfs_path, 'w') as f: |
1100 | + f.write(str(vf_count)) |
1101 | + except IOError as e: |
1102 | + bail = True |
1103 | + if e.errno == 16: # device or resource busy |
1104 | + logging.warning('device or resource busy while setting sriov_numvfs for %s, trying workaround' % pf) |
1105 | + try: |
1106 | + # doing this in two open/close sequences so that |
1107 | + # it's as close to writing via shell as possible |
1108 | + with open(numvfs_path, 'w') as f: |
1109 | + f.write('0') |
1110 | + with open(numvfs_path, 'w') as f: |
1111 | + f.write(str(vf_count)) |
1112 | + except IOError as e_inner: |
1113 | + e = e_inner |
1114 | + else: |
1115 | + bail = False |
1116 | + if bail: |
1117 | + raise RuntimeError('failed setting sriov_numvfs to %s for %s: %s' % (vf_count, pf, str(e))) |
1118 | + |
1119 | + return True |
1120 | + |
1121 | + |
1122 | +def perform_hardware_specific_quirks(pf): |
1123 | + """ |
1124 | + Perform any hardware-specific quirks for the given SR-IOV device to make |
1125 | + sure all the VF-count changes are applied. |
1126 | + """ |
1127 | + devdir = os.path.join('/sys/class/net', pf, 'device') |
1128 | + try: |
1129 | + with open(os.path.join(devdir, 'vendor')) as f: |
1130 | + device_id = f.read().strip()[2:] |
1131 | + with open(os.path.join(devdir, 'device')) as f: |
1132 | + vendor_id = f.read().strip()[2:] |
1133 | + except IOError as e: |
1134 | + raise RuntimeError('could not determine vendor and device ID of %s: %s' % (pf, str(e))) |
1135 | + |
1136 | + combined_id = ':'.join([vendor_id, device_id]) |
1137 | + quirk_devices = () # TODO: add entries to the list |
1138 | + if combined_id in quirk_devices: |
1139 | + # some devices need special handling, so this is the place |
1140 | + |
1141 | + # Currently this part is empty, but has been added as a preemptive |
1142 | + # measure, as apparently a lot of SR-IOV cards have issues with |
1143 | + # dynamically allocating VFs. Some cards seem to require a full |
1144 | + # kernel module reload cycle after changing the sriov_numvfs value |
1145 | + # for the changes to come into effect. |
1146 | + # Any identified card/vendor can then be special-cased here, if |
1147 | + # needed. |
1148 | + pass |
1149 | + |
1150 | + |
1151 | +def apply_vlan_filter_for_vf(pf, vf, vlan_name, vlan_id, prefix='/'): |
1152 | + """ |
1153 | + Apply the hardware VLAN filtering for the selected VF. |
1154 | + """ |
1155 | + |
1156 | + # this is more complicated, because to do this, we actually need to have |
1157 | + # the vf index - just knowing the vf interface name is not enough |
1158 | + vf_index = None |
1159 | + # the prefix argument is here only for unit testing purposes |
1160 | + vf_devdir = os.path.join(prefix, 'sys/class/net', vf, 'device') |
1161 | + vf_dev_id = os.path.basename(os.readlink(vf_devdir)) |
1162 | + pf_devdir = os.path.join(prefix, 'sys/class/net', pf, 'device') |
1163 | + for f in os.listdir(pf_devdir): |
1164 | + if 'virtfn' in f: |
1165 | + dev_path = os.path.join(pf_devdir, f) |
1166 | + dev_id = os.path.basename(os.readlink(dev_path)) |
1167 | + if dev_id == vf_dev_id: |
1168 | + vf_index = f[6:] |
1169 | + break |
1170 | + |
1171 | + if not vf_index: |
1172 | + raise RuntimeError( |
1173 | + 'could not determine the VF index for %s while configuring vlan %s' % (vf, vlan_name)) |
1174 | + |
1175 | + # now, create the VLAN filter |
1176 | + # TODO: would be best if we did this directl via python, without calling |
1177 | + # the iproute tooling |
1178 | + try: |
1179 | + subprocess.check_call(['ip', 'link', 'set', |
1180 | + 'dev', pf, |
1181 | + 'vf', vf_index, |
1182 | + 'vlan', str(vlan_id)], |
1183 | + stdout=subprocess.DEVNULL, |
1184 | + stderr=subprocess.DEVNULL) |
1185 | + except subprocess.CalledProcessError: |
1186 | + raise RuntimeError( |
1187 | + 'failed setting SR-IOV VLAN filter for vlan %s (ip link set command failed)' % vlan_name) |
1188 | + |
1189 | + |
1190 | +def apply_sriov_config(interfaces, config_manager): |
1191 | + """ |
1192 | + Go through all interfaces, identify which ones are SR-IOV VFs, create |
1193 | + them and perform all other necessary setup. |
1194 | + """ |
1195 | + |
1196 | + # for sr-iov devices, we identify VFs by them having a link: field |
1197 | + # pointing to an PF. So let's browse through all ethernet devices, |
1198 | + # find all that are VFs and count how many of those are linked to |
1199 | + # particular PFs, as we need to then set the numvfs for each. |
1200 | + vf_counts = defaultdict(int) |
1201 | + # we also store all matches between VF/PF netplan entry names and |
1202 | + # interface that they're currently matching to |
1203 | + vfs = {} |
1204 | + pfs = {} |
1205 | + |
1206 | + get_vf_count_and_functions( |
1207 | + interfaces, config_manager, vf_counts, vfs, pfs) |
1208 | + |
1209 | + # setup the required number of VFs per PF |
1210 | + # at the same time store which PFs got changed in case the NICs |
1211 | + # require some special quirks for the VF number to change |
1212 | + vf_count_changed = [] |
1213 | + if vf_counts: |
1214 | + for pf, vf_count in vf_counts.items(): |
1215 | + if not set_numvfs_for_pf(pf, vf_count): |
1216 | + continue |
1217 | + |
1218 | + vf_count_changed.append(pf) |
1219 | + |
1220 | + if vf_count_changed: |
1221 | + # some cards need special treatment when we want to change the |
1222 | + # number of enabled VFs |
1223 | + for pf in vf_count_changed: |
1224 | + perform_hardware_specific_quirks(pf) |
1225 | + |
1226 | + # also, since the VF number changed, the interfaces list also |
1227 | + # changed, so we need to refresh it |
1228 | + interfaces = netifaces.interfaces() |
1229 | + |
1230 | + # now in theory we should have all the new VFs set up and existing; |
1231 | + # this is needed because we will have to now match the defined VF |
1232 | + # entries to existing interfaces, otherwise we won't be able to set |
1233 | + # filtered VLANs for those. |
1234 | + # XXX: does matching those even make sense? |
1235 | + for vf in vfs: |
1236 | + settings = config_manager.ethernets.get(vf) |
1237 | + match = settings.get('match') |
1238 | + if match: |
1239 | + # right now we only match by name, as I don't think matching per |
1240 | + # driver and/or macaddress makes sense |
1241 | + by_name = match.get('name') |
1242 | + # by_mac = match.get('macaddress') |
1243 | + # by_driver = match.get('driver') |
1244 | + # TODO: print warning if other matches are provided |
1245 | + |
1246 | + for interface in interfaces: |
1247 | + if by_name and not utils.is_interface_matching_name(interface, by_name): |
1248 | + continue |
1249 | + if vf in vfs and vfs[vf]: |
1250 | + raise ConfigurationError('matched more than one interface for a VF device: %s' % vf) |
1251 | + vfs[vf] = interface |
1252 | + else: |
1253 | + if vf in interfaces: |
1254 | + vfs[vf] = vf |
1255 | + |
1256 | + filtered_vlans_set = set() |
1257 | + for vlan, settings in config_manager.vlans.items(): |
1258 | + # there is a special sriov vlan renderer that one can use to mark |
1259 | + # a selected vlan to be done in hardware (VLAN filtering) |
1260 | + if settings.get('renderer') == 'sriov': |
1261 | + # this only works for SR-IOV VF interfaces |
1262 | + link = settings.get('link') |
1263 | + vlan_id = settings.get('id') |
1264 | + if not vlan_id: |
1265 | + raise ConfigurationError( |
1266 | + 'no id property defined for SR-IOV vlan %s' % vlan) |
1267 | + |
1268 | + vf = vfs.get(link) |
1269 | + if not vf: |
1270 | + # it is possible this is not an error, for instance when |
1271 | + # the configuration has been defined 'for the future' |
1272 | + # XXX: but maybe we should error out here as well? |
1273 | + logging.warning( |
1274 | + 'SR-IOV vlan defined for %s but link %s is either not a VF or has no matches' % (vlan, link)) |
1275 | + continue |
1276 | + |
1277 | + # get the parent pf interface |
1278 | + # first we fetch the related vf netplan entry |
1279 | + vf_parent_entry = config_manager.ethernets.get(link).get('link') |
1280 | + # and finally, get the matched pf interface |
1281 | + pf = pfs.get(vf_parent_entry) |
1282 | + |
1283 | + if vf in filtered_vlans_set: |
1284 | + raise ConfigurationError( |
1285 | + 'interface %s for netplan device %s (%s) already has an SR-IOV vlan defined' % (vf, link, vlan)) |
1286 | + |
1287 | + apply_vlan_filter_for_vf(pf, vf, vlan, vlan_id) |
1288 | + filtered_vlans_set.add(vf) |
1289 | diff --git a/netplan/cli/utils.py b/netplan/cli/utils.py |
1290 | index 0d1b53f..5f54b1a 100644 |
1291 | --- a/netplan/cli/utils.py |
1292 | +++ b/netplan/cli/utils.py |
1293 | @@ -1,7 +1,8 @@ |
1294 | #!/usr/bin/python3 |
1295 | # |
1296 | -# Copyright (C) 2018 Canonical, Ltd. |
1297 | +# Copyright (C) 2018-2020 Canonical, Ltd. |
1298 | # Author: Mathieu Trudel-Lapierre <mathieu.trudel-lapierre@canonical.com> |
1299 | +# Author: Łukasz 'sil2100' Zemczak <lukasz.zemczak@canonical.com> |
1300 | # |
1301 | # This program is free software; you can redistribute it and/or modify |
1302 | # it under the terms of the GNU General Public License as published by |
1303 | @@ -17,8 +18,11 @@ |
1304 | |
1305 | import sys |
1306 | import os |
1307 | +import logging |
1308 | +import fnmatch |
1309 | import argparse |
1310 | import subprocess |
1311 | +import netifaces |
1312 | |
1313 | NM_SERVICE_NAME = 'NetworkManager.service' |
1314 | NM_SNAP_SERVICE_NAME = 'snap.network-manager.networkmanager.service' |
1315 | @@ -82,6 +86,51 @@ def systemctl_networkd(action, sync=False, extra_services=[]): # pragma: nocove |
1316 | subprocess.check_call(command) |
1317 | |
1318 | |
1319 | +def get_interface_driver_name(interface, only_down=False): # pragma: nocover (covered in autopkgtest) |
1320 | + devdir = os.path.join('/sys/class/net', interface) |
1321 | + if only_down: |
1322 | + try: |
1323 | + with open(os.path.join(devdir, 'operstate')) as f: |
1324 | + state = f.read().strip() |
1325 | + if state != 'down': |
1326 | + logging.debug('device %s operstate is %s, not changing', interface, state) |
1327 | + return None |
1328 | + except IOError as e: |
1329 | + logging.error('Cannot determine operstate of %s: %s', interface, str(e)) |
1330 | + return None |
1331 | + |
1332 | + try: |
1333 | + driver = os.path.realpath(os.path.join(devdir, 'device', 'driver')) |
1334 | + driver_name = os.path.basename(driver) |
1335 | + except IOError as e: |
1336 | + logging.debug('Cannot replug %s: cannot read link %s/device: %s', interface, devdir, str(e)) |
1337 | + return None |
1338 | + |
1339 | + return driver_name |
1340 | + |
1341 | + |
1342 | +def get_interface_macaddress(interface): # pragma: nocover (covered in autopkgtest) |
1343 | + link = netifaces.ifaddresses(interface)[netifaces.AF_LINK][0] |
1344 | + |
1345 | + return link.get('addr') |
1346 | + |
1347 | + |
1348 | +def is_interface_matching_name(interface, match_driver): |
1349 | + return fnmatch.fnmatchcase(interface, match_driver) |
1350 | + |
1351 | + |
1352 | +def is_interface_matching_driver_name(interface, match_driver): |
1353 | + driver_name = get_interface_driver_name(interface) |
1354 | + |
1355 | + return match_driver == driver_name |
1356 | + |
1357 | + |
1358 | +def is_interface_matching_macaddress(interface, match_mac): |
1359 | + macaddress = get_interface_macaddress(interface) |
1360 | + |
1361 | + return match_mac == macaddress |
1362 | + |
1363 | + |
1364 | class NetplanCommand(argparse.Namespace): |
1365 | |
1366 | def __init__(self, command_id, description, leaf=True, testing=False): |
1367 | diff --git a/src/generate.c b/src/generate.c |
1368 | index 2106994..c020d8f 100644 |
1369 | --- a/src/generate.c |
1370 | +++ b/src/generate.c |
1371 | @@ -53,9 +53,9 @@ reload_udevd(void) |
1372 | static void |
1373 | nd_iterator_list(gpointer value, gpointer user_data) |
1374 | { |
1375 | - if (write_networkd_conf((net_definition*) value, (const char*) user_data)) |
1376 | + if (write_networkd_conf((NetplanNetDefinition*) value, (const char*) user_data)) |
1377 | any_networkd = TRUE; |
1378 | - write_nm_conf((net_definition*) value, (const char*) user_data); |
1379 | + write_nm_conf((NetplanNetDefinition*) value, (const char*) user_data); |
1380 | } |
1381 | |
1382 | |
1383 | @@ -91,7 +91,7 @@ find_interface(gchar* interface) |
1384 | |
1385 | g_hash_table_iter_init (&iter, netdefs); |
1386 | while (g_hash_table_iter_next (&iter, &key, &value)) { |
1387 | - net_definition *nd = (net_definition *) value; |
1388 | + NetplanNetDefinition *nd = (NetplanNetDefinition *) value; |
1389 | if (!g_strcmp0(nd->set_name, interface)) |
1390 | g_ptr_array_add (found, (gpointer) nd); |
1391 | else if (!g_strcmp0(nd->id, interface)) |
1392 | @@ -104,7 +104,7 @@ find_interface(gchar* interface) |
1393 | // LCOV_EXCL_START |
1394 | g_hash_table_iter_init (&iter, netdefs); |
1395 | while (g_hash_table_iter_next (&iter, &key, &value)) { |
1396 | - net_definition *nd = (net_definition *) value; |
1397 | + NetplanNetDefinition *nd = (NetplanNetDefinition *) value; |
1398 | if (!g_strcmp0(nd->match.driver, driver)) |
1399 | g_ptr_array_add (found, (gpointer) nd); |
1400 | } |
1401 | @@ -118,10 +118,10 @@ find_interface(gchar* interface) |
1402 | goto exit_find; |
1403 | } |
1404 | else { |
1405 | - net_definition *nd = (net_definition *)g_ptr_array_index (found, 0); |
1406 | + const NetplanNetDefinition *nd = (NetplanNetDefinition *)g_ptr_array_index (found, 0); |
1407 | g_printf("id=%s, backend=%s, set_name=%s, match_name=%s, match_mac=%s, match_driver=%s\n", |
1408 | nd->id, |
1409 | - netdef_backend_to_name[nd->backend], |
1410 | + netplan_backend_to_name[nd->backend], |
1411 | nd->set_name, |
1412 | nd->match.original_name, |
1413 | nd->match.mac, |
1414 | @@ -141,7 +141,7 @@ process_input_file(const char* f) |
1415 | GError* error = NULL; |
1416 | |
1417 | g_debug("Processing input file %s..", f); |
1418 | - if (!parse_yaml(f, &error)) { |
1419 | + if (!netplan_parse_yaml(f, &error)) { |
1420 | g_fprintf(stderr, "%s\n", error->message); |
1421 | exit(1); |
1422 | } |
1423 | @@ -237,7 +237,8 @@ int main(int argc, char** argv) |
1424 | process_input_file(g_hash_table_lookup(configs, i->data)); |
1425 | } |
1426 | |
1427 | - if (!finish_parse(&error)) { |
1428 | + netdefs = netplan_finish_parse(&error); |
1429 | + if (error) { |
1430 | g_fprintf(stderr, "%s\n", error->message); |
1431 | exit(1); |
1432 | } |
1433 | @@ -266,7 +267,7 @@ int main(int argc, char** argv) |
1434 | |
1435 | /* Disable /usr/lib/NetworkManager/conf.d/10-globally-managed-devices.conf |
1436 | * (which restricts NM to wifi and wwan) if global renderer is NM */ |
1437 | - if (get_global_backend() == BACKEND_NM) |
1438 | + if (netplan_get_global_backend() == NETPLAN_BACKEND_NM) |
1439 | g_string_free_to_file(g_string_new(NULL), rootdir, "/run/NetworkManager/conf.d/10-globally-managed-devices.conf", NULL); |
1440 | |
1441 | if (called_as_generator) { |
1442 | diff --git a/src/netplan-wpa@.service b/src/netplan-wpa@.service |
1443 | deleted file mode 100644 |
1444 | index d2670d9..0000000 |
1445 | --- a/src/netplan-wpa@.service |
1446 | +++ /dev/null |
1447 | @@ -1,11 +0,0 @@ |
1448 | -[Unit] |
1449 | -Description=WPA supplicant for netplan %I |
1450 | -DefaultDependencies=no |
1451 | -Requires=sys-subsystem-net-devices-%i.device |
1452 | -After=sys-subsystem-net-devices-%i.device |
1453 | -Before=network.target |
1454 | -Wants=network.target |
1455 | - |
1456 | -[Service] |
1457 | -Type=simple |
1458 | -ExecStart=/sbin/wpa_supplicant -c /run/netplan/wpa-%I.conf -i%I |
1459 | diff --git a/src/networkd.c b/src/networkd.c |
1460 | index b6d276f..e2bb111 100644 |
1461 | --- a/src/networkd.c |
1462 | +++ b/src/networkd.c |
1463 | @@ -16,7 +16,9 @@ |
1464 | */ |
1465 | |
1466 | #include <stdlib.h> |
1467 | +#include <string.h> |
1468 | #include <unistd.h> |
1469 | +#include <ctype.h> |
1470 | #include <errno.h> |
1471 | #include <sys/stat.h> |
1472 | |
1473 | @@ -27,12 +29,39 @@ |
1474 | #include "parse.h" |
1475 | #include "util.h" |
1476 | |
1477 | +/** |
1478 | + * Append WiFi frequencies to wpa_supplicant's freq_list= |
1479 | + */ |
1480 | +static void |
1481 | +wifi_append_freq(gpointer key, gpointer value, gpointer user_data) |
1482 | +{ |
1483 | + GString* s = user_data; |
1484 | + g_string_append_printf(s, "%d ", GPOINTER_TO_INT(value)); |
1485 | +} |
1486 | + |
1487 | +/** |
1488 | + * append wowlan_triggers= string for wpa_supplicant.conf |
1489 | + */ |
1490 | +static void |
1491 | +append_wifi_wowlan_flags(NetplanWifiWowlanFlag flag, GString* str) { |
1492 | + if (flag & NETPLAN_WIFI_WOWLAN_TYPES[0].flag || flag >= NETPLAN_WIFI_WOWLAN_TCP) { |
1493 | + g_fprintf(stderr, "ERROR: unsupported wowlan_triggers mask: 0x%x\n", flag); |
1494 | + exit(1); |
1495 | + } |
1496 | + for (unsigned i = 0; NETPLAN_WIFI_WOWLAN_TYPES[i].name != NULL; ++i) { |
1497 | + if (flag & NETPLAN_WIFI_WOWLAN_TYPES[i].flag) { |
1498 | + g_string_append_printf(str, "%s ", NETPLAN_WIFI_WOWLAN_TYPES[i].name); |
1499 | + } |
1500 | + } |
1501 | + /* replace trailing space with newline */ |
1502 | + str = g_string_overwrite(str, str->len-1, "\n"); |
1503 | +} |
1504 | |
1505 | /** |
1506 | * Append [Match] section of @def to @s. |
1507 | */ |
1508 | static void |
1509 | -append_match_section(net_definition* def, GString* s, gboolean match_rename) |
1510 | +append_match_section(const NetplanNetDefinition* def, GString* s, gboolean match_rename) |
1511 | { |
1512 | /* Note: an empty [Match] section is interpreted as matching all devices, |
1513 | * which is what we want for the simple case that you only have one device |
1514 | @@ -48,7 +77,7 @@ append_match_section(net_definition* def, GString* s, gboolean match_rename) |
1515 | if (!match_rename && def->match.original_name) |
1516 | g_string_append_printf(s, "OriginalName=%s\n", def->match.original_name); |
1517 | if (match_rename) { |
1518 | - if (def->type >= ND_VIRTUAL) |
1519 | + if (def->type >= NETPLAN_DEF_TYPE_VIRTUAL) |
1520 | g_string_append_printf(s, "Name=%s\n", def->id); |
1521 | else if (def->set_name) |
1522 | g_string_append_printf(s, "Name=%s\n", def->set_name); |
1523 | @@ -76,7 +105,7 @@ append_match_section(net_definition* def, GString* s, gboolean match_rename) |
1524 | } |
1525 | |
1526 | static void |
1527 | -write_bridge_params(GString* s, net_definition* def) |
1528 | +write_bridge_params(GString* s, const NetplanNetDefinition* def) |
1529 | { |
1530 | GString *params = NULL; |
1531 | |
1532 | @@ -102,14 +131,14 @@ write_bridge_params(GString* s, net_definition* def) |
1533 | } |
1534 | |
1535 | static void |
1536 | -write_tunnel_params(GString* s, net_definition* def) |
1537 | +write_tunnel_params(GString* s, const NetplanNetDefinition* def) |
1538 | { |
1539 | GString *params = NULL; |
1540 | |
1541 | params = g_string_sized_new(200); |
1542 | |
1543 | g_string_printf(params, "Independent=true\n"); |
1544 | - if (def->tunnel.mode == TUNNEL_MODE_IPIP6 || def->tunnel.mode == TUNNEL_MODE_IP6IP6) |
1545 | + if (def->tunnel.mode == NETPLAN_TUNNEL_MODE_IPIP6 || def->tunnel.mode == NETPLAN_TUNNEL_MODE_IP6IP6) |
1546 | g_string_append_printf(params, "Mode=%s\n", tunnel_mode_to_string(def->tunnel.mode)); |
1547 | g_string_append_printf(params, "Local=%s\n", def->tunnel.local_ip); |
1548 | g_string_append_printf(params, "Remote=%s\n", def->tunnel.remote_ip); |
1549 | @@ -123,13 +152,15 @@ write_tunnel_params(GString* s, net_definition* def) |
1550 | } |
1551 | |
1552 | static void |
1553 | -write_link_file(net_definition* def, const char* rootdir, const char* path) |
1554 | +write_link_file(const NetplanNetDefinition* def, const char* rootdir, const char* path) |
1555 | { |
1556 | GString* s = NULL; |
1557 | mode_t orig_umask; |
1558 | |
1559 | - /* Don't write .link files for virtual devices; they use .netdev instead */ |
1560 | - if (def->type >= ND_VIRTUAL) |
1561 | + /* Don't write .link files for virtual devices; they use .netdev instead. |
1562 | + * Don't write .link files for MODEM devices, as they aren't supported by networkd. |
1563 | + */ |
1564 | + if (def->type >= NETPLAN_DEF_TYPE_VIRTUAL || def->type == NETPLAN_DEF_TYPE_MODEM) |
1565 | return; |
1566 | |
1567 | /* do we need to write a .link file? */ |
1568 | @@ -170,7 +201,7 @@ interval_has_suffix(const char* param) { |
1569 | |
1570 | |
1571 | static void |
1572 | -write_bond_parameters(net_definition* def, GString* s) |
1573 | +write_bond_parameters(const NetplanNetDefinition* def, GString* s) |
1574 | { |
1575 | GString* params = NULL; |
1576 | |
1577 | @@ -249,12 +280,17 @@ write_bond_parameters(net_definition* def, GString* s) |
1578 | } |
1579 | |
1580 | static void |
1581 | -write_netdev_file(net_definition* def, const char* rootdir, const char* path) |
1582 | +write_netdev_file(const NetplanNetDefinition* def, const char* rootdir, const char* path) |
1583 | { |
1584 | GString* s = NULL; |
1585 | mode_t orig_umask; |
1586 | |
1587 | - g_assert(def->type >= ND_VIRTUAL); |
1588 | + g_assert(def->type >= NETPLAN_DEF_TYPE_VIRTUAL); |
1589 | + |
1590 | + if (def->type == NETPLAN_DEF_TYPE_VLAN && def->sriov_vlan_filter) { |
1591 | + g_debug("%s is defined as a hardware SR-IOV filtered VLAN, postponing creation", def->id); |
1592 | + return; |
1593 | + } |
1594 | |
1595 | /* build file contents */ |
1596 | s = g_string_sized_new(200); |
1597 | @@ -266,37 +302,37 @@ write_netdev_file(net_definition* def, const char* rootdir, const char* path) |
1598 | g_string_append_printf(s, "MTUBytes=%u\n", def->mtubytes); |
1599 | |
1600 | switch (def->type) { |
1601 | - case ND_BRIDGE: |
1602 | + case NETPLAN_DEF_TYPE_BRIDGE: |
1603 | g_string_append(s, "Kind=bridge\n"); |
1604 | write_bridge_params(s, def); |
1605 | break; |
1606 | |
1607 | - case ND_BOND: |
1608 | + case NETPLAN_DEF_TYPE_BOND: |
1609 | g_string_append(s, "Kind=bond\n"); |
1610 | write_bond_parameters(def, s); |
1611 | break; |
1612 | |
1613 | - case ND_VLAN: |
1614 | + case NETPLAN_DEF_TYPE_VLAN: |
1615 | g_string_append_printf(s, "Kind=vlan\n\n[VLAN]\nId=%u\n", def->vlan_id); |
1616 | break; |
1617 | |
1618 | - case ND_TUNNEL: |
1619 | + case NETPLAN_DEF_TYPE_TUNNEL: |
1620 | switch(def->tunnel.mode) { |
1621 | - case TUNNEL_MODE_GRE: |
1622 | - case TUNNEL_MODE_GRETAP: |
1623 | - case TUNNEL_MODE_IPIP: |
1624 | - case TUNNEL_MODE_IP6GRE: |
1625 | - case TUNNEL_MODE_IP6GRETAP: |
1626 | - case TUNNEL_MODE_SIT: |
1627 | - case TUNNEL_MODE_VTI: |
1628 | - case TUNNEL_MODE_VTI6: |
1629 | + case NETPLAN_TUNNEL_MODE_GRE: |
1630 | + case NETPLAN_TUNNEL_MODE_GRETAP: |
1631 | + case NETPLAN_TUNNEL_MODE_IPIP: |
1632 | + case NETPLAN_TUNNEL_MODE_IP6GRE: |
1633 | + case NETPLAN_TUNNEL_MODE_IP6GRETAP: |
1634 | + case NETPLAN_TUNNEL_MODE_SIT: |
1635 | + case NETPLAN_TUNNEL_MODE_VTI: |
1636 | + case NETPLAN_TUNNEL_MODE_VTI6: |
1637 | g_string_append_printf(s, |
1638 | "Kind=%s\n", |
1639 | tunnel_mode_to_string(def->tunnel.mode)); |
1640 | break; |
1641 | |
1642 | - case TUNNEL_MODE_IP6IP6: |
1643 | - case TUNNEL_MODE_IPIP6: |
1644 | + case NETPLAN_TUNNEL_MODE_IP6IP6: |
1645 | + case NETPLAN_TUNNEL_MODE_IPIP6: |
1646 | g_string_append(s, "Kind=ip6tnl\n"); |
1647 | break; |
1648 | |
1649 | @@ -323,7 +359,7 @@ write_netdev_file(net_definition* def, const char* rootdir, const char* path) |
1650 | } |
1651 | |
1652 | static void |
1653 | -write_route(ip_route* r, GString* s) |
1654 | +write_route(NetplanIPRoute* r, GString* s) |
1655 | { |
1656 | g_string_append_printf(s, "\n[Route]\n"); |
1657 | |
1658 | @@ -340,14 +376,14 @@ write_route(ip_route* r, GString* s) |
1659 | g_string_append_printf(s, "Type=%s\n", r->type); |
1660 | if (r->onlink) |
1661 | g_string_append_printf(s, "GatewayOnlink=true\n"); |
1662 | - if (r->metric != METRIC_UNSPEC) |
1663 | + if (r->metric != NETPLAN_METRIC_UNSPEC) |
1664 | g_string_append_printf(s, "Metric=%d\n", r->metric); |
1665 | - if (r->table != ROUTE_TABLE_UNSPEC) |
1666 | + if (r->table != NETPLAN_ROUTE_TABLE_UNSPEC) |
1667 | g_string_append_printf(s, "Table=%d\n", r->table); |
1668 | } |
1669 | |
1670 | static void |
1671 | -write_ip_rule(ip_rule* r, GString* s) |
1672 | +write_ip_rule(NetplanIPRule* r, GString* s) |
1673 | { |
1674 | g_string_append_printf(s, "\n[RoutingPolicyRule]\n"); |
1675 | |
1676 | @@ -356,13 +392,13 @@ write_ip_rule(ip_rule* r, GString* s) |
1677 | if (r->to) |
1678 | g_string_append_printf(s, "To=%s\n", r->to); |
1679 | |
1680 | - if (r->table != ROUTE_TABLE_UNSPEC) |
1681 | + if (r->table != NETPLAN_ROUTE_TABLE_UNSPEC) |
1682 | g_string_append_printf(s, "Table=%d\n", r->table); |
1683 | - if (r->priority != IP_RULE_PRIO_UNSPEC) |
1684 | + if (r->priority != NETPLAN_IP_RULE_PRIO_UNSPEC) |
1685 | g_string_append_printf(s, "Priority=%d\n", r->priority); |
1686 | - if (r->fwmark != IP_RULE_FW_MARK_UNSPEC) |
1687 | + if (r->fwmark != NETPLAN_IP_RULE_FW_MARK_UNSPEC) |
1688 | g_string_append_printf(s, "FirewallMark=%d\n", r->fwmark); |
1689 | - if (r->tos != IP_RULE_TOS_UNSPEC) |
1690 | + if (r->tos != NETPLAN_IP_RULE_TOS_UNSPEC) |
1691 | g_string_append_printf(s, "TypeOfService=%d\n", r->tos); |
1692 | } |
1693 | |
1694 | @@ -371,7 +407,7 @@ write_ip_rule(ip_rule* r, GString* s) |
1695 | "dhcp4_overrides and dhcp6_overrides\n" |
1696 | |
1697 | static void |
1698 | -combine_dhcp_overrides(net_definition* def, dhcp_overrides* combined_dhcp_overrides) |
1699 | +combine_dhcp_overrides(const NetplanNetDefinition* def, NetplanDHCPOverrides* combined_dhcp_overrides) |
1700 | { |
1701 | /* if only one of dhcp4 or dhcp6 is enabled, those overrides are used */ |
1702 | if (def->dhcp4 && !def->dhcp6) { |
1703 | @@ -424,13 +460,18 @@ combine_dhcp_overrides(net_definition* def, dhcp_overrides* combined_dhcp_overri |
1704 | } |
1705 | |
1706 | static void |
1707 | -write_network_file(net_definition* def, const char* rootdir, const char* path) |
1708 | +write_network_file(const NetplanNetDefinition* def, const char* rootdir, const char* path) |
1709 | { |
1710 | GString* network = NULL; |
1711 | GString* link = NULL; |
1712 | GString* s = NULL; |
1713 | mode_t orig_umask; |
1714 | |
1715 | + if (def->type == NETPLAN_DEF_TYPE_VLAN && def->sriov_vlan_filter) { |
1716 | + g_debug("%s is defined as a hardware SR-IOV filtered VLAN, postponing creation", def->id); |
1717 | + return; |
1718 | + } |
1719 | + |
1720 | /* Prepare the [Link] section of the .network file. */ |
1721 | link = g_string_sized_new(200); |
1722 | |
1723 | @@ -441,13 +482,20 @@ write_network_file(net_definition* def, const char* rootdir, const char* path) |
1724 | if (def->optional) { |
1725 | g_string_append(link, "RequiredForOnline=no\n"); |
1726 | } |
1727 | - for (unsigned i = 0; optional_address_options[i].name != NULL; ++i) { |
1728 | - if (def->optional_addresses & optional_address_options[i].flag) { |
1729 | - g_string_append_printf(link, "OptionalAddresses=%s\n", optional_address_options[i].name); |
1730 | + for (unsigned i = 0; NETPLAN_OPTIONAL_ADDRESS_TYPES[i].name != NULL; ++i) { |
1731 | + if (def->optional_addresses & NETPLAN_OPTIONAL_ADDRESS_TYPES[i].flag) { |
1732 | + g_string_append_printf(link, "OptionalAddresses=%s\n", NETPLAN_OPTIONAL_ADDRESS_TYPES[i].name); |
1733 | } |
1734 | } |
1735 | } |
1736 | |
1737 | + if (def->mtubytes) { |
1738 | + g_string_append_printf(link, "MTUBytes=%d\n", def->mtubytes); |
1739 | + } |
1740 | + |
1741 | + if (def->emit_lldp) { |
1742 | + g_string_append(network, "EmitLLDP=true\n"); |
1743 | + } |
1744 | |
1745 | if (def->dhcp4 && def->dhcp6) |
1746 | g_string_append(network, "DHCP=yes\n"); |
1747 | @@ -476,9 +524,18 @@ write_network_file(net_definition* def, const char* rootdir, const char* path) |
1748 | if (def->ip6_addresses) |
1749 | for (unsigned i = 0; i < def->ip6_addresses->len; ++i) |
1750 | g_string_append_printf(network, "Address=%s\n", g_array_index(def->ip6_addresses, char*, i)); |
1751 | - if (def->accept_ra == ACCEPT_RA_ENABLED) |
1752 | + if (def->ip6_addr_gen_mode) { |
1753 | + /* TODO: Figure out how we can configure ipv6-address-generation for networkd. |
1754 | + * IPv6Token= seems to be the corresponding option, but it doesn't do |
1755 | + * exactly what we need and has quite some restrictions, c.f.: |
1756 | + * https://github.com/systemd/systemd/issues/4625 |
1757 | + * https://github.com/systemd/systemd/pull/14415 */ |
1758 | + g_fprintf(stderr, "ERROR: %s: ipv6-address-generation is not supported by networkd\n", def->id); |
1759 | + exit(1); |
1760 | + } |
1761 | + if (def->accept_ra == NETPLAN_RA_MODE_ENABLED) |
1762 | g_string_append_printf(network, "IPv6AcceptRA=yes\n"); |
1763 | - else if (def->accept_ra == ACCEPT_RA_DISABLED) |
1764 | + else if (def->accept_ra == NETPLAN_RA_MODE_DISABLED) |
1765 | g_string_append_printf(network, "IPv6AcceptRA=no\n"); |
1766 | if (def->ip6_privacy) |
1767 | g_string_append(network, "IPv6PrivacyExtensions=yes\n"); |
1768 | @@ -503,7 +560,7 @@ write_network_file(net_definition* def, const char* rootdir, const char* path) |
1769 | g_string_append_printf(network, "IPv6MTUBytes=%d\n", def->ipv6_mtubytes); |
1770 | } |
1771 | |
1772 | - if (def->type >= ND_VIRTUAL) |
1773 | + if (def->type >= NETPLAN_DEF_TYPE_VIRTUAL) |
1774 | g_string_append(network, "ConfigureWithoutCarrier=yes\n"); |
1775 | |
1776 | if (def->bridge) { |
1777 | @@ -526,41 +583,44 @@ write_network_file(net_definition* def, const char* rootdir, const char* path) |
1778 | if (def->has_vlans) { |
1779 | /* iterate over all netdefs to find VLANs attached to us */ |
1780 | GList *l = netdefs_ordered; |
1781 | - net_definition* nd; |
1782 | + const NetplanNetDefinition* nd; |
1783 | for (; l != NULL; l = l->next) { |
1784 | nd = l->data; |
1785 | - if (nd->vlan_link == def) |
1786 | + if (nd->vlan_link == def && !nd->sriov_vlan_filter) |
1787 | g_string_append_printf(network, "VLAN=%s\n", nd->id); |
1788 | } |
1789 | } |
1790 | |
1791 | if (def->routes != NULL) { |
1792 | for (unsigned i = 0; i < def->routes->len; ++i) { |
1793 | - ip_route* cur_route = g_array_index (def->routes, ip_route*, i); |
1794 | + NetplanIPRoute* cur_route = g_array_index (def->routes, NetplanIPRoute*, i); |
1795 | write_route(cur_route, network); |
1796 | } |
1797 | } |
1798 | if (def->ip_rules != NULL) { |
1799 | for (unsigned i = 0; i < def->ip_rules->len; ++i) { |
1800 | - ip_rule* cur_rule = g_array_index (def->ip_rules, ip_rule*, i); |
1801 | + NetplanIPRule* cur_rule = g_array_index (def->ip_rules, NetplanIPRule*, i); |
1802 | write_ip_rule(cur_rule, network); |
1803 | } |
1804 | } |
1805 | |
1806 | - if (def->dhcp4 || def->dhcp6) { |
1807 | + if (def->dhcp4 || def->dhcp6 || def->critical) { |
1808 | /* NetworkManager compatible route metrics */ |
1809 | g_string_append(network, "\n[DHCP]\n"); |
1810 | + } |
1811 | + |
1812 | + if (def->critical) |
1813 | + g_string_append_printf(network, "CriticalConnection=true\n"); |
1814 | |
1815 | + if (def->dhcp4 || def->dhcp6) { |
1816 | if (g_strcmp0(def->dhcp_identifier, "duid") != 0) |
1817 | g_string_append_printf(network, "ClientIdentifier=%s\n", def->dhcp_identifier); |
1818 | - if (def->critical) |
1819 | - g_string_append_printf(network, "CriticalConnection=true\n"); |
1820 | |
1821 | - dhcp_overrides combined_dhcp_overrides; |
1822 | + NetplanDHCPOverrides combined_dhcp_overrides; |
1823 | combine_dhcp_overrides(def, &combined_dhcp_overrides); |
1824 | |
1825 | - if (combined_dhcp_overrides.metric == METRIC_UNSPEC) { |
1826 | - g_string_append_printf(network, "RouteMetric=%i\n", (def->type == ND_WIFI ? 600 : 100)); |
1827 | + if (combined_dhcp_overrides.metric == NETPLAN_METRIC_UNSPEC) { |
1828 | + g_string_append_printf(network, "RouteMetric=%i\n", (def->type == NETPLAN_DEF_TYPE_WIFI ? 600 : 100)); |
1829 | } else { |
1830 | g_string_append_printf(network, "RouteMetric=%u\n", |
1831 | combined_dhcp_overrides.metric); |
1832 | @@ -613,7 +673,7 @@ write_network_file(net_definition* def, const char* rootdir, const char* path) |
1833 | } |
1834 | |
1835 | static void |
1836 | -write_rules_file(net_definition* def, const char* rootdir) |
1837 | +write_rules_file(const NetplanNetDefinition* def, const char* rootdir) |
1838 | { |
1839 | GString* s = NULL; |
1840 | g_autofree char* path = g_strjoin(NULL, "run/udev/rules.d/99-netplan-", def->id, ".rules", NULL); |
1841 | @@ -622,7 +682,7 @@ write_rules_file(net_definition* def, const char* rootdir) |
1842 | /* do we need to write a .rules file? |
1843 | * It's only required for reliably setting the name of a physical device |
1844 | * until systemd issue #9006 is resolved. */ |
1845 | - if (def->type >= ND_VIRTUAL) |
1846 | + if (def->type >= NETPLAN_DEF_TYPE_VIRTUAL) |
1847 | return; |
1848 | |
1849 | /* Matching by name does not work. |
1850 | @@ -657,39 +717,39 @@ write_rules_file(net_definition* def, const char* rootdir) |
1851 | } |
1852 | |
1853 | static void |
1854 | -append_wpa_auth_conf(GString* s, const authentication_settings* auth) |
1855 | +append_wpa_auth_conf(GString* s, const NetplanAuthenticationSettings* auth, const char* id) |
1856 | { |
1857 | switch (auth->key_management) { |
1858 | - case KEY_MANAGEMENT_NONE: |
1859 | + case NETPLAN_AUTH_KEY_MANAGEMENT_NONE: |
1860 | g_string_append(s, " key_mgmt=NONE\n"); |
1861 | break; |
1862 | |
1863 | - case KEY_MANAGEMENT_WPA_PSK: |
1864 | + case NETPLAN_AUTH_KEY_MANAGEMENT_WPA_PSK: |
1865 | g_string_append(s, " key_mgmt=WPA-PSK\n"); |
1866 | break; |
1867 | |
1868 | - case KEY_MANAGEMENT_WPA_EAP: |
1869 | + case NETPLAN_AUTH_KEY_MANAGEMENT_WPA_EAP: |
1870 | g_string_append(s, " key_mgmt=WPA-EAP\n"); |
1871 | break; |
1872 | |
1873 | - case KEY_MANAGEMENT_8021X: |
1874 | + case NETPLAN_AUTH_KEY_MANAGEMENT_8021X: |
1875 | g_string_append(s, " key_mgmt=IEEE8021X\n"); |
1876 | break; |
1877 | } |
1878 | |
1879 | switch (auth->eap_method) { |
1880 | - case EAP_NONE: |
1881 | + case NETPLAN_AUTH_EAP_NONE: |
1882 | break; |
1883 | |
1884 | - case EAP_TLS: |
1885 | + case NETPLAN_AUTH_EAP_TLS: |
1886 | g_string_append(s, " eap=TLS\n"); |
1887 | break; |
1888 | |
1889 | - case EAP_PEAP: |
1890 | + case NETPLAN_AUTH_EAP_PEAP: |
1891 | g_string_append(s, " eap=PEAP\n"); |
1892 | break; |
1893 | |
1894 | - case EAP_TTLS: |
1895 | + case NETPLAN_AUTH_EAP_TTLS: |
1896 | g_string_append(s, " eap=TTLS\n"); |
1897 | break; |
1898 | } |
1899 | @@ -701,8 +761,25 @@ append_wpa_auth_conf(GString* s, const authentication_settings* auth) |
1900 | g_string_append_printf(s, " anonymous_identity=\"%s\"\n", auth->anonymous_identity); |
1901 | } |
1902 | if (auth->password) { |
1903 | - if (auth->key_management == KEY_MANAGEMENT_WPA_PSK) { |
1904 | - g_string_append_printf(s, " psk=\"%s\"\n", auth->password); |
1905 | + if (auth->key_management == NETPLAN_AUTH_KEY_MANAGEMENT_WPA_PSK) { |
1906 | + size_t len = strlen(auth->password); |
1907 | + if (len == 64) { |
1908 | + /* must be a hex-digit key representation */ |
1909 | + for (unsigned i = 0; i < 64; ++i) |
1910 | + if (!isxdigit(auth->password[i])) { |
1911 | + g_fprintf(stderr, "ERROR: %s: PSK length of 64 is only supported for hex-digit representation\n", id); |
1912 | + exit(1); |
1913 | + } |
1914 | + /* this is required to be unquoted */ |
1915 | + g_string_append_printf(s, " psk=%s\n", auth->password); |
1916 | + } else if (len < 8 || len > 63) { |
1917 | + /* per wpa_supplicant spec, passphrase needs to be between 8 |
1918 | + and 63 characters */ |
1919 | + g_fprintf(stderr, "ERROR: %s: ASCII passphrase must be between 8 and 63 characters (inclusive)\n", id); |
1920 | + exit(1); |
1921 | + } else { |
1922 | + g_string_append_printf(s, " psk=\"%s\"\n", auth->password); |
1923 | + } |
1924 | } else { |
1925 | if (strncmp(auth->password, "hash:", 5) == 0) { |
1926 | g_string_append_printf(s, " password=%s\n", auth->password); |
1927 | @@ -723,10 +800,50 @@ append_wpa_auth_conf(GString* s, const authentication_settings* auth) |
1928 | if (auth->client_key_password) { |
1929 | g_string_append_printf(s, " private_key_passwd=\"%s\"\n", auth->client_key_password); |
1930 | } |
1931 | + if (auth->phase2_auth) { |
1932 | + g_string_append_printf(s, " phase2=\"auth=%s\"\n", auth->phase2_auth); |
1933 | + } |
1934 | + |
1935 | } |
1936 | |
1937 | +/* netplan-feature: generated-supplicant */ |
1938 | static void |
1939 | -write_wpa_conf(net_definition* def, const char* rootdir) |
1940 | +write_wpa_unit(const NetplanNetDefinition* def, const char* rootdir) |
1941 | +{ |
1942 | + g_autoptr(GError) err = NULL; |
1943 | + g_autofree gchar *stdouth = NULL; |
1944 | + g_autofree gchar *stderrh = NULL; |
1945 | + gint exit_status = 0; |
1946 | + |
1947 | + gchar *argv[] = {"bin" "/" "systemd-escape", def->id, NULL}; |
1948 | + g_spawn_sync("/", argv, NULL, 0, NULL, NULL, &stdouth, &stderrh, &exit_status, &err); |
1949 | + g_spawn_check_exit_status(exit_status, &err); |
1950 | + if (err != NULL) { |
1951 | + // LCOV_EXCL_START |
1952 | + g_fprintf(stderr, "failed to ask systemd to escape %s; exit %d\nstdout: '%s'\nstderr: '%s'", def->id, exit_status, stdouth, stderrh); |
1953 | + exit(1); |
1954 | + // LCOV_EXCL_STOP |
1955 | + } |
1956 | + g_strstrip(stdouth); |
1957 | + |
1958 | + GString* s = g_string_new("[Unit]\n"); |
1959 | + g_autofree char* path = g_strjoin(NULL, "/run/systemd/system/netplan-wpa-", stdouth, ".service", NULL); |
1960 | + g_string_append_printf(s, "Description=WPA supplicant for netplan %s\n", stdouth); |
1961 | + g_string_append(s, "DefaultDependencies=no\n"); |
1962 | + g_string_append_printf(s, "Requires=sys-subsystem-net-devices-%s.device\n", stdouth); |
1963 | + g_string_append_printf(s, "After=sys-subsystem-net-devices-%s.device\n", stdouth); |
1964 | + g_string_append(s, "Before=network.target\nWants=network.target\n\n"); |
1965 | + g_string_append(s, "[Service]\nType=simple\n"); |
1966 | + g_string_append_printf(s, "ExecStart=/sbin/wpa_supplicant -c /run/netplan/wpa-%s.conf -i%s", stdouth, stdouth); |
1967 | + |
1968 | + if (def->type != NETPLAN_DEF_TYPE_WIFI) { |
1969 | + g_string_append(s, " -Dwired\n"); |
1970 | + } |
1971 | + g_string_free_to_file(s, rootdir, path, NULL); |
1972 | +} |
1973 | + |
1974 | +static void |
1975 | +write_wpa_conf(const NetplanNetDefinition* def, const char* rootdir) |
1976 | { |
1977 | GHashTableIter iter; |
1978 | GString* s = g_string_new("ctrl_interface=/run/wpa_supplicant\n\n"); |
1979 | @@ -734,26 +851,58 @@ write_wpa_conf(net_definition* def, const char* rootdir) |
1980 | mode_t orig_umask; |
1981 | |
1982 | g_debug("%s: Creating wpa_supplicant configuration file %s", def->id, path); |
1983 | - if (def->type == ND_WIFI) { |
1984 | - wifi_access_point* ap; |
1985 | + if (def->type == NETPLAN_DEF_TYPE_WIFI) { |
1986 | + if (def->wowlan && def->wowlan > NETPLAN_WIFI_WOWLAN_DEFAULT) { |
1987 | + g_string_append(s, "wowlan_triggers="); |
1988 | + append_wifi_wowlan_flags(def->wowlan, s); |
1989 | + } |
1990 | + NetplanWifiAccessPoint* ap; |
1991 | g_hash_table_iter_init(&iter, def->access_points); |
1992 | while (g_hash_table_iter_next(&iter, NULL, (gpointer) &ap)) { |
1993 | g_string_append_printf(s, "network={\n ssid=\"%s\"\n", ap->ssid); |
1994 | + if (ap->bssid) { |
1995 | + g_string_append_printf(s, " bssid=%s\n", ap->bssid); |
1996 | + } |
1997 | + if (ap->band == NETPLAN_WIFI_BAND_24) { |
1998 | + // initialize 2.4GHz frequency hashtable |
1999 | + if(!wifi_frequency_24) |
2000 | + wifi_get_freq24(1); |
2001 | + if (ap->channel) { |
2002 | + g_string_append_printf(s, " freq_list=%d\n", wifi_get_freq24(ap->channel)); |
2003 | + } else { |
2004 | + g_string_append_printf(s, " freq_list="); |
2005 | + g_hash_table_foreach(wifi_frequency_24, wifi_append_freq, s); |
2006 | + // overwrite last whitespace with newline |
2007 | + s = g_string_overwrite(s, s->len-1, "\n"); |
2008 | + } |
2009 | + } else if (ap->band == NETPLAN_WIFI_BAND_5) { |
2010 | + // initialize 5GHz frequency hashtable |
2011 | + if(!wifi_frequency_5) |
2012 | + wifi_get_freq5(7); |
2013 | + if (ap->channel) { |
2014 | + g_string_append_printf(s, " freq_list=%d\n", wifi_get_freq5(ap->channel)); |
2015 | + } else { |
2016 | + g_string_append_printf(s, " freq_list="); |
2017 | + g_hash_table_foreach(wifi_frequency_5, wifi_append_freq, s); |
2018 | + // overwrite last whitespace with newline |
2019 | + s = g_string_overwrite(s, s->len-1, "\n"); |
2020 | + } |
2021 | + } |
2022 | switch (ap->mode) { |
2023 | - case WIFI_MODE_INFRASTRUCTURE: |
2024 | + case NETPLAN_WIFI_MODE_INFRASTRUCTURE: |
2025 | /* default in wpasupplicant */ |
2026 | break; |
2027 | - case WIFI_MODE_ADHOC: |
2028 | + case NETPLAN_WIFI_MODE_ADHOC: |
2029 | g_string_append(s, " mode=1\n"); |
2030 | break; |
2031 | - case WIFI_MODE_AP: |
2032 | + case NETPLAN_WIFI_MODE_AP: |
2033 | g_fprintf(stderr, "ERROR: %s: networkd does not support wifi in access point mode\n", def->id); |
2034 | exit(1); |
2035 | } |
2036 | |
2037 | /* wifi auth trumps netdef auth */ |
2038 | if (ap->has_auth) { |
2039 | - append_wpa_auth_conf(s, &ap->auth); |
2040 | + append_wpa_auth_conf(s, &ap->auth, ap->ssid); |
2041 | } |
2042 | else { |
2043 | g_string_append(s, " key_mgmt=NONE\n"); |
2044 | @@ -764,7 +913,7 @@ write_wpa_conf(net_definition* def, const char* rootdir) |
2045 | else { |
2046 | /* wired 802.1x auth or similar */ |
2047 | g_string_append(s, "network={\n"); |
2048 | - append_wpa_auth_conf(s, &def->auth); |
2049 | + append_wpa_auth_conf(s, &def->auth, def->id); |
2050 | g_string_append(s, "}\n"); |
2051 | } |
2052 | |
2053 | @@ -782,7 +931,7 @@ write_wpa_conf(net_definition* def, const char* rootdir) |
2054 | * Returns: TRUE if @def applies to networkd, FALSE otherwise. |
2055 | */ |
2056 | gboolean |
2057 | -write_networkd_conf(net_definition* def, const char* rootdir) |
2058 | +write_networkd_conf(const NetplanNetDefinition* def, const char* rootdir) |
2059 | { |
2060 | g_autofree char* path_base = g_strjoin(NULL, "run/systemd/network/10-netplan-", def->id, NULL); |
2061 | |
2062 | @@ -791,23 +940,34 @@ write_networkd_conf(net_definition* def, const char* rootdir) |
2063 | write_link_file(def, rootdir, path_base); |
2064 | write_rules_file(def, rootdir); |
2065 | |
2066 | - if (def->backend != BACKEND_NETWORKD) { |
2067 | + if (def->backend != NETPLAN_BACKEND_NETWORKD) { |
2068 | g_debug("networkd: definition %s is not for us (backend %i)", def->id, def->backend); |
2069 | return FALSE; |
2070 | } |
2071 | |
2072 | - if (def->type == ND_WIFI || def->has_auth) { |
2073 | - g_autofree char* link = g_strjoin(NULL, rootdir ?: "", "/run/systemd/system/systemd-networkd.service.wants/netplan-wpa@", def->id, ".service", NULL); |
2074 | - if (def->type == ND_WIFI && def->has_match) { |
2075 | + if (def->type == NETPLAN_DEF_TYPE_MODEM) { |
2076 | + g_fprintf(stderr, "ERROR: %s: networkd backend does not support GSM/CDMA modem configuration\n", def->id); |
2077 | + exit(1); |
2078 | + } |
2079 | + |
2080 | + if (def->type == NETPLAN_DEF_TYPE_WIFI || def->has_auth) { |
2081 | + g_autofree char* link = g_strjoin(NULL, rootdir ?: "", "/run/systemd/system/systemd-networkd.service.wants/netplan-wpa-", def->id, ".service", NULL); |
2082 | + g_autofree char* slink = g_strjoin(NULL, "/run/systemd/system/netplan-wpa-", def->id, ".service", NULL); |
2083 | + if (def->type == NETPLAN_DEF_TYPE_WIFI && def->has_match) { |
2084 | g_fprintf(stderr, "ERROR: %s: networkd backend does not support wifi with match:, only by interface name\n", def->id); |
2085 | exit(1); |
2086 | } |
2087 | |
2088 | + g_debug("Creating wpa_supplicant config"); |
2089 | write_wpa_conf(def, rootdir); |
2090 | |
2091 | + g_debug("Creating wpa_supplicant unit %s", slink); |
2092 | + write_wpa_unit(def, rootdir); |
2093 | + |
2094 | g_debug("Creating wpa_supplicant service enablement link %s", link); |
2095 | safe_mkdir_p_dir(link); |
2096 | - if (symlink("/lib/systemd/system/netplan-wpa@.service", link) < 0 && errno != EEXIST) { |
2097 | + |
2098 | + if (symlink(slink, link) < 0 && errno != EEXIST) { |
2099 | // LCOV_EXCL_START |
2100 | g_fprintf(stderr, "failed to create enablement symlink: %m\n"); |
2101 | exit(1); |
2102 | @@ -816,7 +976,7 @@ write_networkd_conf(net_definition* def, const char* rootdir) |
2103 | |
2104 | } |
2105 | |
2106 | - if (def->type >= ND_VIRTUAL) |
2107 | + if (def->type >= NETPLAN_DEF_TYPE_VIRTUAL) |
2108 | write_netdev_file(def, rootdir, path_base); |
2109 | write_network_file(def, rootdir, path_base); |
2110 | return TRUE; |
2111 | @@ -830,7 +990,7 @@ cleanup_networkd_conf(const char* rootdir) |
2112 | { |
2113 | unlink_glob(rootdir, "/run/systemd/network/10-netplan-*"); |
2114 | unlink_glob(rootdir, "/run/netplan/wpa-*.conf"); |
2115 | - unlink_glob(rootdir, "/run/systemd/system/systemd-networkd.service.wants/netplan-wpa@*.service"); |
2116 | + unlink_glob(rootdir, "/run/systemd/system/netplan-wpa-*.service"); |
2117 | unlink_glob(rootdir, "/run/udev/rules.d/99-netplan-*"); |
2118 | } |
2119 | |
2120 | diff --git a/src/networkd.h b/src/networkd.h |
2121 | index 6660f9c..5629a04 100644 |
2122 | --- a/src/networkd.h |
2123 | +++ b/src/networkd.h |
2124 | @@ -19,6 +19,6 @@ |
2125 | |
2126 | #include "parse.h" |
2127 | |
2128 | -gboolean write_networkd_conf(net_definition* def, const char* rootdir); |
2129 | +gboolean write_networkd_conf(const NetplanNetDefinition* def, const char* rootdir); |
2130 | void cleanup_networkd_conf(const char* rootdir); |
2131 | void enable_networkd(const char* generator_dir); |
2132 | diff --git a/src/nm.c b/src/nm.c |
2133 | index 804037f..2cd1d52 100644 |
2134 | --- a/src/nm.c |
2135 | +++ b/src/nm.c |
2136 | @@ -36,20 +36,20 @@ GString* udev_rules; |
2137 | * Append NM device specifier of @def to @s. |
2138 | */ |
2139 | static void |
2140 | -g_string_append_netdef_match(GString* s, const net_definition* def) |
2141 | +g_string_append_netdef_match(GString* s, const NetplanNetDefinition* def) |
2142 | { |
2143 | g_assert(!def->match.driver || def->set_name); |
2144 | if (def->match.mac) { |
2145 | g_string_append_printf(s, "mac:%s", def->match.mac); |
2146 | - } else if (def->match.original_name || def->set_name || def->type >= ND_VIRTUAL) { |
2147 | + } else if (def->match.original_name || def->set_name || def->type >= NETPLAN_DEF_TYPE_VIRTUAL) { |
2148 | /* we always have the renamed name here */ |
2149 | g_string_append_printf(s, "interface-name:%s", |
2150 | - (def->type >= ND_VIRTUAL) ? def->id |
2151 | + (def->type >= NETPLAN_DEF_TYPE_VIRTUAL) ? def->id |
2152 | : (def->set_name ?: def->match.original_name)); |
2153 | } else { |
2154 | /* no matches → match all devices of that type */ |
2155 | switch (def->type) { |
2156 | - case ND_ETHERNET: |
2157 | + case NETPLAN_DEF_TYPE_ETHERNET: |
2158 | g_string_append(s, "type:ethernet"); |
2159 | break; |
2160 | /* This cannot be reached with just NM and networkd backends, as |
2161 | @@ -57,7 +57,7 @@ g_string_append_netdef_match(GString* s, const net_definition* def) |
2162 | * wifi device from NM. This would become relevant with another |
2163 | * wifi-supporting backend, but until then this just spoils 100% |
2164 | * code coverage. |
2165 | - case ND_WIFI: |
2166 | + case NETPLAN_DEF_TYPE_WIFI: |
2167 | g_string_append(s, "type:wifi"); |
2168 | break; |
2169 | */ |
2170 | @@ -71,23 +71,46 @@ g_string_append_netdef_match(GString* s, const net_definition* def) |
2171 | } |
2172 | |
2173 | /** |
2174 | + * Infer if this is a modem netdef of type GSM. |
2175 | + * This is done by checking for certain modem_params, which are only |
2176 | + * applicable to GSM connections. |
2177 | + */ |
2178 | +static const gboolean |
2179 | +modem_is_gsm(const NetplanNetDefinition* def) |
2180 | +{ |
2181 | + if (def->type == NETPLAN_DEF_TYPE_MODEM && (def->modem_params.apn || |
2182 | + def->modem_params.auto_config || def->modem_params.device_id || |
2183 | + def->modem_params.network_id || def->modem_params.pin || |
2184 | + def->modem_params.sim_id || def->modem_params.sim_operator_id)) |
2185 | + return TRUE; |
2186 | + |
2187 | + return FALSE; |
2188 | +} |
2189 | + |
2190 | +/** |
2191 | * Return NM "type=" string. |
2192 | */ |
2193 | static const char* |
2194 | -type_str(netdef_type type) |
2195 | +type_str(const NetplanNetDefinition* def) |
2196 | { |
2197 | + const NetplanDefType type = def->type; |
2198 | switch (type) { |
2199 | - case ND_ETHERNET: |
2200 | + case NETPLAN_DEF_TYPE_ETHERNET: |
2201 | return "ethernet"; |
2202 | - case ND_WIFI: |
2203 | + case NETPLAN_DEF_TYPE_MODEM: |
2204 | + if (modem_is_gsm(def)) |
2205 | + return "gsm"; |
2206 | + else |
2207 | + return "cdma"; |
2208 | + case NETPLAN_DEF_TYPE_WIFI: |
2209 | return "wifi"; |
2210 | - case ND_BRIDGE: |
2211 | + case NETPLAN_DEF_TYPE_BRIDGE: |
2212 | return "bridge"; |
2213 | - case ND_BOND: |
2214 | + case NETPLAN_DEF_TYPE_BOND: |
2215 | return "bond"; |
2216 | - case ND_VLAN: |
2217 | + case NETPLAN_DEF_TYPE_VLAN: |
2218 | return "vlan"; |
2219 | - case ND_TUNNEL: |
2220 | + case NETPLAN_DEF_TYPE_TUNNEL: |
2221 | return "ip-tunnel"; |
2222 | // LCOV_EXCL_START |
2223 | default: |
2224 | @@ -100,14 +123,14 @@ type_str(netdef_type type) |
2225 | * Return NM wifi "mode=" string. |
2226 | */ |
2227 | static const char* |
2228 | -wifi_mode_str(wifi_mode mode) |
2229 | +wifi_mode_str(const NetplanWifiMode mode) |
2230 | { |
2231 | switch (mode) { |
2232 | - case WIFI_MODE_INFRASTRUCTURE: |
2233 | + case NETPLAN_WIFI_MODE_INFRASTRUCTURE: |
2234 | return "infrastructure"; |
2235 | - case WIFI_MODE_ADHOC: |
2236 | + case NETPLAN_WIFI_MODE_ADHOC: |
2237 | return "adhoc"; |
2238 | - case WIFI_MODE_AP: |
2239 | + case NETPLAN_WIFI_MODE_AP: |
2240 | return "ap"; |
2241 | // LCOV_EXCL_START |
2242 | default: |
2243 | @@ -116,8 +139,44 @@ wifi_mode_str(wifi_mode mode) |
2244 | } |
2245 | } |
2246 | |
2247 | +/** |
2248 | + * Return NM wifi "band=" string. |
2249 | + */ |
2250 | +static const char* |
2251 | +wifi_band_str(const NetplanWifiBand band) |
2252 | +{ |
2253 | + switch (band) { |
2254 | + case NETPLAN_WIFI_BAND_5: |
2255 | + return "a"; |
2256 | + case NETPLAN_WIFI_BAND_24: |
2257 | + return "bg"; |
2258 | + // LCOV_EXCL_START |
2259 | + default: |
2260 | + g_assert_not_reached(); |
2261 | + // LCOV_EXCL_STOP |
2262 | + } |
2263 | +} |
2264 | + |
2265 | +/** |
2266 | + * Return NM addr-gen-mode string. |
2267 | + */ |
2268 | +static const char* |
2269 | +addr_gen_mode_str(const NetplanAddrGenMode mode) |
2270 | +{ |
2271 | + switch (mode) { |
2272 | + case NETPLAN_ADDRGEN_EUI64: |
2273 | + return "0"; |
2274 | + case NETPLAN_ADDRGEN_STABLEPRIVACY: |
2275 | + return "1"; |
2276 | + // LCOV_EXCL_START |
2277 | + default: |
2278 | + g_assert_not_reached(); |
2279 | + // LCOV_EXCL_STOP |
2280 | + } |
2281 | +} |
2282 | + |
2283 | static void |
2284 | -write_search_domains(const net_definition* def, GString *s) |
2285 | +write_search_domains(const NetplanNetDefinition* def, GString *s) |
2286 | { |
2287 | if (def->search_domains) { |
2288 | g_string_append(s, "dns-search="); |
2289 | @@ -128,11 +187,11 @@ write_search_domains(const net_definition* def, GString *s) |
2290 | } |
2291 | |
2292 | static void |
2293 | -write_routes(const net_definition* def, GString *s, int family) |
2294 | +write_routes(const NetplanNetDefinition* def, GString *s, int family) |
2295 | { |
2296 | if (def->routes != NULL) { |
2297 | for (unsigned i = 0, j = 1; i < def->routes->len; ++i) { |
2298 | - ip_route *cur_route = g_array_index(def->routes, ip_route*, i); |
2299 | + const NetplanIPRoute *cur_route = g_array_index(def->routes, NetplanIPRoute*, i); |
2300 | |
2301 | if (cur_route->family != family) |
2302 | continue; |
2303 | @@ -147,7 +206,7 @@ write_routes(const net_definition* def, GString *s, int family) |
2304 | exit(1); |
2305 | } |
2306 | |
2307 | - if (cur_route->table != ROUTE_TABLE_UNSPEC) { |
2308 | + if (cur_route->table != NETPLAN_ROUTE_TABLE_UNSPEC) { |
2309 | g_fprintf(stderr, "ERROR: %s: NetworkManager does not support non-default routing tables\n", def->id); |
2310 | exit(1); |
2311 | } |
2312 | @@ -164,7 +223,7 @@ write_routes(const net_definition* def, GString *s, int family) |
2313 | |
2314 | g_string_append_printf(s, "route%d=%s,%s", |
2315 | j, cur_route->to, cur_route->via); |
2316 | - if (cur_route->metric != METRIC_UNSPEC) |
2317 | + if (cur_route->metric != NETPLAN_METRIC_UNSPEC) |
2318 | g_string_append_printf(s, ",%d", cur_route->metric); |
2319 | g_string_append(s, "\n"); |
2320 | j++; |
2321 | @@ -173,7 +232,7 @@ write_routes(const net_definition* def, GString *s, int family) |
2322 | } |
2323 | |
2324 | static void |
2325 | -write_bond_parameters(const net_definition* def, GString *s) |
2326 | +write_bond_parameters(const NetplanNetDefinition* def, GString *s) |
2327 | { |
2328 | GString* params = NULL; |
2329 | |
2330 | @@ -237,7 +296,7 @@ write_bond_parameters(const net_definition* def, GString *s) |
2331 | } |
2332 | |
2333 | static void |
2334 | -write_bridge_params(const net_definition* def, GString *s) |
2335 | +write_bridge_params(const NetplanNetDefinition* def, GString *s) |
2336 | { |
2337 | GString* params = NULL; |
2338 | |
2339 | @@ -263,7 +322,7 @@ write_bridge_params(const net_definition* def, GString *s) |
2340 | } |
2341 | |
2342 | static void |
2343 | -write_tunnel_params(const net_definition* def, GString *s) |
2344 | +write_tunnel_params(const NetplanNetDefinition* def, GString *s) |
2345 | { |
2346 | g_string_append(s, "\n[ip-tunnel]\n"); |
2347 | |
2348 | @@ -278,23 +337,23 @@ write_tunnel_params(const net_definition* def, GString *s) |
2349 | } |
2350 | |
2351 | static void |
2352 | -write_dot1x_auth_parameters(const authentication_settings* auth, GString *s) |
2353 | +write_dot1x_auth_parameters(const NetplanAuthenticationSettings* auth, GString *s) |
2354 | { |
2355 | - if (auth->eap_method == EAP_NONE) { |
2356 | + if (auth->eap_method == NETPLAN_AUTH_EAP_NONE) { |
2357 | return; |
2358 | } |
2359 | |
2360 | g_string_append_printf(s, "\n[802-1x]\n"); |
2361 | |
2362 | switch (auth->eap_method) { |
2363 | - case EAP_NONE: break; // LCOV_EXCL_LINE |
2364 | - case EAP_TLS: |
2365 | + case NETPLAN_AUTH_EAP_NONE: break; // LCOV_EXCL_LINE |
2366 | + case NETPLAN_AUTH_EAP_TLS: |
2367 | g_string_append(s, "eap=tls\n"); |
2368 | break; |
2369 | - case EAP_PEAP: |
2370 | + case NETPLAN_AUTH_EAP_PEAP: |
2371 | g_string_append(s, "eap=peap\n"); |
2372 | break; |
2373 | - case EAP_TTLS: |
2374 | + case NETPLAN_AUTH_EAP_TTLS: |
2375 | g_string_append(s, "eap=ttls\n"); |
2376 | break; |
2377 | } |
2378 | @@ -305,7 +364,7 @@ write_dot1x_auth_parameters(const authentication_settings* auth, GString *s) |
2379 | if (auth->anonymous_identity) { |
2380 | g_string_append_printf(s, "anonymous-identity=%s\n", auth->anonymous_identity); |
2381 | } |
2382 | - if (auth->password && auth->key_management != KEY_MANAGEMENT_WPA_PSK) { |
2383 | + if (auth->password && auth->key_management != NETPLAN_AUTH_KEY_MANAGEMENT_WPA_PSK) { |
2384 | g_string_append_printf(s, "password=%s\n", auth->password); |
2385 | } |
2386 | if (auth->ca_certificate) { |
2387 | @@ -320,29 +379,33 @@ write_dot1x_auth_parameters(const authentication_settings* auth, GString *s) |
2388 | if (auth->client_key_password) { |
2389 | g_string_append_printf(s, "private-key-password=%s\n", auth->client_key_password); |
2390 | } |
2391 | + if (auth->phase2_auth) { |
2392 | + g_string_append_printf(s, "phase2-auth=%s\n", auth->phase2_auth); |
2393 | + } |
2394 | + |
2395 | } |
2396 | |
2397 | static void |
2398 | -write_wifi_auth_parameters(const authentication_settings* auth, GString *s) |
2399 | +write_wifi_auth_parameters(const NetplanAuthenticationSettings* auth, GString *s) |
2400 | { |
2401 | - if (auth->key_management == KEY_MANAGEMENT_NONE) { |
2402 | + if (auth->key_management == NETPLAN_AUTH_KEY_MANAGEMENT_NONE) { |
2403 | return; |
2404 | } |
2405 | |
2406 | g_string_append(s, "\n[wifi-security]\n"); |
2407 | |
2408 | switch (auth->key_management) { |
2409 | - case KEY_MANAGEMENT_NONE: break; // LCOV_EXCL_LINE |
2410 | - case KEY_MANAGEMENT_WPA_PSK: |
2411 | + case NETPLAN_AUTH_KEY_MANAGEMENT_NONE: break; // LCOV_EXCL_LINE |
2412 | + case NETPLAN_AUTH_KEY_MANAGEMENT_WPA_PSK: |
2413 | g_string_append(s, "key-mgmt=wpa-psk\n"); |
2414 | if (auth->password) { |
2415 | g_string_append_printf(s, "psk=%s\n", auth->password); |
2416 | } |
2417 | break; |
2418 | - case KEY_MANAGEMENT_WPA_EAP: |
2419 | + case NETPLAN_AUTH_KEY_MANAGEMENT_WPA_EAP: |
2420 | g_string_append(s, "key-mgmt=wpa-eap\n"); |
2421 | break; |
2422 | - case KEY_MANAGEMENT_8021X: |
2423 | + case NETPLAN_AUTH_KEY_MANAGEMENT_8021X: |
2424 | g_string_append(s, "key-mgmt=ieee8021x\n"); |
2425 | break; |
2426 | } |
2427 | @@ -351,7 +414,7 @@ write_wifi_auth_parameters(const authentication_settings* auth, GString *s) |
2428 | } |
2429 | |
2430 | static void |
2431 | -maybe_generate_uuid(net_definition* def) |
2432 | +maybe_generate_uuid(NetplanNetDefinition* def) |
2433 | { |
2434 | if (uuid_is_null(def->uuid)) |
2435 | uuid_generate(def->uuid); |
2436 | @@ -359,32 +422,37 @@ maybe_generate_uuid(net_definition* def) |
2437 | |
2438 | /** |
2439 | * Generate NetworkManager configuration in @rootdir/run/NetworkManager/ for a |
2440 | - * particular net_definition and wifi_access_point, as NM requires a separate |
2441 | + * particular NetplanNetDefinition and NetplanWifiAccessPoint, as NM requires a separate |
2442 | * connection file for each SSID. |
2443 | - * @def: The net_definition for which to create a connection |
2444 | + * @def: The NetplanNetDefinition for which to create a connection |
2445 | * @rootdir: If not %NULL, generate configuration in this root directory |
2446 | * (useful for testing). |
2447 | * @ap: The access point for which to create a connection. Must be %NULL for |
2448 | * non-wifi types. |
2449 | */ |
2450 | static void |
2451 | -write_nm_conf_access_point(net_definition* def, const char* rootdir, const wifi_access_point* ap) |
2452 | +write_nm_conf_access_point(NetplanNetDefinition* def, const char* rootdir, const NetplanWifiAccessPoint* ap) |
2453 | { |
2454 | GString *s = NULL; |
2455 | g_autofree char* conf_path = NULL; |
2456 | mode_t orig_umask; |
2457 | char uuidstr[37]; |
2458 | |
2459 | - if (def->type == ND_WIFI) |
2460 | + if (def->type == NETPLAN_DEF_TYPE_WIFI) |
2461 | g_assert(ap); |
2462 | else |
2463 | g_assert(ap == NULL); |
2464 | |
2465 | + if (def->type == NETPLAN_DEF_TYPE_VLAN && def->sriov_vlan_filter) { |
2466 | + g_debug("%s is defined as a hardware SR-IOV filtered VLAN, postponing creation", def->id); |
2467 | + return; |
2468 | + } |
2469 | + |
2470 | s = g_string_new(NULL); |
2471 | g_string_append_printf(s, "[connection]\nid=netplan-%s", def->id); |
2472 | if (ap) |
2473 | g_string_append_printf(s, "-%s", ap->ssid); |
2474 | - g_string_append_printf(s, "\ntype=%s\n", type_str(def->type)); |
2475 | + g_string_append_printf(s, "\ntype=%s\n", type_str(def)); |
2476 | |
2477 | /* VLAN devices refer to us as their parent; if our ID is not a name but we |
2478 | * have matches, parent= must be the connection UUID, so put it into the |
2479 | @@ -395,7 +463,7 @@ write_nm_conf_access_point(net_definition* def, const char* rootdir, const wifi_ |
2480 | g_string_append_printf(s, "uuid=%s\n", uuidstr); |
2481 | } |
2482 | |
2483 | - if (def->type < ND_VIRTUAL) { |
2484 | + if (def->type < NETPLAN_DEF_TYPE_VIRTUAL) { |
2485 | /* physical (existing) devices use matching; driver matching is not |
2486 | * supported, MAC matching is done below (different keyfile section), |
2487 | * so only match names here */ |
2488 | @@ -416,9 +484,43 @@ write_nm_conf_access_point(net_definition* def, const char* rootdir, const wifi_ |
2489 | /* virtual (created) devices set a name */ |
2490 | g_string_append_printf(s, "interface-name=%s\n", def->id); |
2491 | |
2492 | - if (def->type == ND_BRIDGE) |
2493 | + if (def->type == NETPLAN_DEF_TYPE_BRIDGE) |
2494 | write_bridge_params(def, s); |
2495 | } |
2496 | + if (def->type == NETPLAN_DEF_TYPE_MODEM) { |
2497 | + if (modem_is_gsm(def)) |
2498 | + g_string_append_printf(s, "\n[gsm]\n"); |
2499 | + else |
2500 | + g_string_append_printf(s, "\n[cdma]\n"); |
2501 | + |
2502 | + /* Use NetworkManager's auto configuration feature if no APN, username, or password is specified */ |
2503 | + if (def->modem_params.auto_config || (!def->modem_params.apn && |
2504 | + !def->modem_params.username && !def->modem_params.password)) { |
2505 | + g_string_append_printf(s, "auto-config=true\n"); |
2506 | + } else { |
2507 | + if (def->modem_params.apn) |
2508 | + g_string_append_printf(s, "apn=%s\n", def->modem_params.apn); |
2509 | + if (def->modem_params.password) |
2510 | + g_string_append_printf(s, "password=%s\n", def->modem_params.password); |
2511 | + if (def->modem_params.username) |
2512 | + g_string_append_printf(s, "username=%s\n", def->modem_params.username); |
2513 | + } |
2514 | + |
2515 | + if (def->modem_params.device_id) |
2516 | + g_string_append_printf(s, "device-id=%s\n", def->modem_params.device_id); |
2517 | + if (def->mtubytes) |
2518 | + g_string_append_printf(s, "mtu=%u\n", def->mtubytes); |
2519 | + if (def->modem_params.network_id) |
2520 | + g_string_append_printf(s, "network-id=%s\n", def->modem_params.network_id); |
2521 | + if (def->modem_params.number) |
2522 | + g_string_append_printf(s, "number=%s\n", def->modem_params.number); |
2523 | + if (def->modem_params.pin) |
2524 | + g_string_append_printf(s, "pin=%s\n", def->modem_params.pin); |
2525 | + if (def->modem_params.sim_id) |
2526 | + g_string_append_printf(s, "sim-id=%s\n", def->modem_params.sim_id); |
2527 | + if (def->modem_params.sim_operator_id) |
2528 | + g_string_append_printf(s, "sim-operator-id=%s\n", def->modem_params.sim_operator_id); |
2529 | + } |
2530 | if (def->bridge) { |
2531 | g_string_append_printf(s, "slave-type=bridge\nmaster=%s\n", def->bridge); |
2532 | |
2533 | @@ -437,7 +539,7 @@ write_nm_conf_access_point(net_definition* def, const char* rootdir, const wifi_ |
2534 | exit(1); |
2535 | } |
2536 | |
2537 | - if (def->type < ND_VIRTUAL) { |
2538 | + if (def->type < NETPLAN_DEF_TYPE_VIRTUAL) { |
2539 | GString *link_str = NULL; |
2540 | |
2541 | link_str = g_string_new(NULL); |
2542 | @@ -453,11 +555,16 @@ write_nm_conf_access_point(net_definition* def, const char* rootdir, const wifi_ |
2543 | if (def->mtubytes) { |
2544 | g_string_append_printf(link_str, "mtu=%d\n", def->mtubytes); |
2545 | } |
2546 | + if (def->wowlan && def->wowlan > NETPLAN_WIFI_WOWLAN_DEFAULT) |
2547 | + g_string_append_printf(link_str, "wake-on-wlan=%u\n", def->wowlan); |
2548 | |
2549 | if (link_str->len > 0) { |
2550 | switch (def->type) { |
2551 | - case ND_WIFI: |
2552 | + case NETPLAN_DEF_TYPE_WIFI: |
2553 | g_string_append_printf(s, "\n[802-11-wireless]\n%s", link_str->str); break; |
2554 | + case NETPLAN_DEF_TYPE_MODEM: |
2555 | + /* Avoid adding an [ethernet] section into the [gsm/cdma] description. */ |
2556 | + break; |
2557 | default: |
2558 | g_string_append_printf(s, "\n[802-3-ethernet]\n%s", link_str->str); break; |
2559 | } |
2560 | @@ -483,7 +590,7 @@ write_nm_conf_access_point(net_definition* def, const char* rootdir, const wifi_ |
2561 | g_string_free(link_str, TRUE); |
2562 | } |
2563 | |
2564 | - if (def->type == ND_VLAN) { |
2565 | + if (def->type == NETPLAN_DEF_TYPE_VLAN) { |
2566 | g_assert(def->vlan_id < G_MAXUINT); |
2567 | g_assert(def->vlan_link != NULL); |
2568 | g_string_append_printf(s, "\n[vlan]\nid=%u\nparent=", def->vlan_id); |
2569 | @@ -499,22 +606,22 @@ write_nm_conf_access_point(net_definition* def, const char* rootdir, const wifi_ |
2570 | } |
2571 | } |
2572 | |
2573 | - if (def->type == ND_BOND) |
2574 | + if (def->type == NETPLAN_DEF_TYPE_BOND) |
2575 | write_bond_parameters(def, s); |
2576 | |
2577 | - if (def->type == ND_TUNNEL) |
2578 | + if (def->type == NETPLAN_DEF_TYPE_TUNNEL) |
2579 | write_tunnel_params(def, s); |
2580 | |
2581 | g_string_append(s, "\n[ipv4]\n"); |
2582 | |
2583 | - if (ap && ap->mode == WIFI_MODE_AP) |
2584 | + if (ap && ap->mode == NETPLAN_WIFI_MODE_AP) |
2585 | g_string_append(s, "method=shared\n"); |
2586 | else if (def->dhcp4) |
2587 | g_string_append(s, "method=auto\n"); |
2588 | else if (def->ip4_addresses) |
2589 | /* This requires adding at least one address (done below) */ |
2590 | g_string_append(s, "method=manual\n"); |
2591 | - else if (def->type == ND_TUNNEL) |
2592 | + else if (def->type == NETPLAN_DEF_TYPE_TUNNEL) |
2593 | /* sit tunnels will not start in link-local apparently */ |
2594 | g_string_append(s, "method=disabled\n"); |
2595 | else |
2596 | @@ -544,15 +651,18 @@ write_nm_conf_access_point(net_definition* def, const char* rootdir, const wifi_ |
2597 | g_string_append(s, "never-default=true\n"); |
2598 | } |
2599 | |
2600 | - if (def->dhcp4 && def->dhcp4_overrides.metric != METRIC_UNSPEC) |
2601 | + if (def->dhcp4 && def->dhcp4_overrides.metric != NETPLAN_METRIC_UNSPEC) |
2602 | g_string_append_printf(s, "route-metric=%u\n", def->dhcp4_overrides.metric); |
2603 | |
2604 | - if (def->dhcp6 || def->ip6_addresses || def->gateway6 || def->ip6_nameservers) { |
2605 | + if (def->dhcp6 || def->ip6_addresses || def->gateway6 || def->ip6_nameservers || def->ip6_addr_gen_mode) { |
2606 | g_string_append(s, "\n[ipv6]\n"); |
2607 | g_string_append(s, def->dhcp6 ? "method=auto\n" : "method=manual\n"); |
2608 | if (def->ip6_addresses) |
2609 | for (unsigned i = 0; i < def->ip6_addresses->len; ++i) |
2610 | g_string_append_printf(s, "address%i=%s\n", i+1, g_array_index(def->ip6_addresses, char*, i)); |
2611 | + if (def->ip6_addr_gen_mode) { |
2612 | + g_string_append_printf(s, "addr-gen-mode=%s\n", addr_gen_mode_str(def->ip6_addr_gen_mode)); |
2613 | + } |
2614 | if (def->ip6_privacy) |
2615 | g_string_append(s, "ip6-privacy=2\n"); |
2616 | if (def->gateway6) |
2617 | @@ -575,7 +685,7 @@ write_nm_conf_access_point(net_definition* def, const char* rootdir, const wifi_ |
2618 | g_string_append(s, "never-default=true\n"); |
2619 | } |
2620 | |
2621 | - if (def->dhcp6_overrides.metric != METRIC_UNSPEC) |
2622 | + if (def->dhcp6_overrides.metric != NETPLAN_METRIC_UNSPEC) |
2623 | g_string_append_printf(s, "route-metric=%u\n", def->dhcp6_overrides.metric); |
2624 | } |
2625 | else { |
2626 | @@ -587,6 +697,21 @@ write_nm_conf_access_point(net_definition* def, const char* rootdir, const wifi_ |
2627 | conf_path = g_strjoin(NULL, "run/NetworkManager/system-connections/netplan-", def->id, "-", escaped_ssid, ".nmconnection", NULL); |
2628 | |
2629 | g_string_append_printf(s, "\n[wifi]\nssid=%s\nmode=%s\n", ap->ssid, wifi_mode_str(ap->mode)); |
2630 | + if (ap->bssid) { |
2631 | + g_string_append_printf(s, "bssid=%s\n", ap->bssid); |
2632 | + } |
2633 | + if (ap->band == NETPLAN_WIFI_BAND_5 || ap->band == NETPLAN_WIFI_BAND_24) { |
2634 | + g_string_append_printf(s, "band=%s\n", wifi_band_str(ap->band)); |
2635 | + /* Channel is only unambiguous, if band is set. */ |
2636 | + if (ap->channel) { |
2637 | + /* Validate WiFi channel */ |
2638 | + if (ap->band == NETPLAN_WIFI_BAND_5) |
2639 | + wifi_get_freq5(ap->channel); |
2640 | + else |
2641 | + wifi_get_freq24(ap->channel); |
2642 | + g_string_append_printf(s, "channel=%u\n", ap->channel); |
2643 | + } |
2644 | + } |
2645 | if (ap->has_auth) { |
2646 | write_wifi_auth_parameters(&ap->auth, s); |
2647 | } |
2648 | @@ -605,14 +730,14 @@ write_nm_conf_access_point(net_definition* def, const char* rootdir, const wifi_ |
2649 | |
2650 | /** |
2651 | * Generate NetworkManager configuration in @rootdir/run/NetworkManager/ for a |
2652 | - * particular net_definition. |
2653 | + * particular NetplanNetDefinition. |
2654 | * @rootdir: If not %NULL, generate configuration in this root directory |
2655 | * (useful for testing). |
2656 | */ |
2657 | void |
2658 | -write_nm_conf(net_definition* def, const char* rootdir) |
2659 | +write_nm_conf(NetplanNetDefinition* def, const char* rootdir) |
2660 | { |
2661 | - if (def->backend != BACKEND_NM) { |
2662 | + if (def->backend != NETPLAN_BACKEND_NM) { |
2663 | g_debug("NetworkManager: definition %s is not for us (backend %i)", def->id, def->backend); |
2664 | return; |
2665 | } |
2666 | @@ -623,10 +748,10 @@ write_nm_conf(net_definition* def, const char* rootdir) |
2667 | } |
2668 | |
2669 | /* for wifi we need to create a separate connection file for every SSID */ |
2670 | - if (def->type == ND_WIFI) { |
2671 | + if (def->type == NETPLAN_DEF_TYPE_WIFI) { |
2672 | GHashTableIter iter; |
2673 | gpointer key; |
2674 | - wifi_access_point* ap; |
2675 | + const NetplanWifiAccessPoint* ap; |
2676 | g_assert(def->access_points); |
2677 | g_hash_table_iter_init(&iter, def->access_points); |
2678 | while (g_hash_table_iter_next(&iter, &key, (gpointer) &ap)) |
2679 | @@ -640,9 +765,9 @@ write_nm_conf(net_definition* def, const char* rootdir) |
2680 | static void |
2681 | nd_append_non_nm_ids(gpointer data, gpointer str) |
2682 | { |
2683 | - net_definition* nd = data; |
2684 | + const NetplanNetDefinition* nd = data; |
2685 | |
2686 | - if (nd->backend != BACKEND_NM) { |
2687 | + if (nd->backend != NETPLAN_BACKEND_NM) { |
2688 | if (nd->match.driver) { |
2689 | /* NM cannot match on drivers, so ignore these via udev rules */ |
2690 | if (!udev_rules) |
2691 | diff --git a/src/nm.h b/src/nm.h |
2692 | index f25c506..9f8f9ca 100644 |
2693 | --- a/src/nm.h |
2694 | +++ b/src/nm.h |
2695 | @@ -19,6 +19,6 @@ |
2696 | |
2697 | #include "parse.h" |
2698 | |
2699 | -void write_nm_conf(net_definition* def, const char* rootdir); |
2700 | +void write_nm_conf(NetplanNetDefinition* def, const char* rootdir); |
2701 | void write_nm_conf_finish(const char* rootdir); |
2702 | void cleanup_nm_conf(const char* rootdir); |
2703 | diff --git a/src/parse.c b/src/parse.c |
2704 | index c72813f..c1dc175 100644 |
2705 | --- a/src/parse.c |
2706 | +++ b/src/parse.c |
2707 | @@ -30,27 +30,28 @@ |
2708 | #include "error.h" |
2709 | #include "validation.h" |
2710 | |
2711 | -/* convenience macro to put the offset of a net_definition field into "void* data" */ |
2712 | -#define netdef_offset(field) GUINT_TO_POINTER(offsetof(net_definition, field)) |
2713 | -#define route_offset(field) GUINT_TO_POINTER(offsetof(ip_route, field)) |
2714 | -#define ip_rule_offset(field) GUINT_TO_POINTER(offsetof(ip_rule, field)) |
2715 | -#define auth_offset(field) GUINT_TO_POINTER(offsetof(authentication_settings, field)) |
2716 | +/* convenience macro to put the offset of a NetplanNetDefinition field into "void* data" */ |
2717 | +#define netdef_offset(field) GUINT_TO_POINTER(offsetof(NetplanNetDefinition, field)) |
2718 | +#define route_offset(field) GUINT_TO_POINTER(offsetof(NetplanIPRoute, field)) |
2719 | +#define ip_rule_offset(field) GUINT_TO_POINTER(offsetof(NetplanIPRule, field)) |
2720 | +#define auth_offset(field) GUINT_TO_POINTER(offsetof(NetplanAuthenticationSettings, field)) |
2721 | +#define access_point_offset(field) GUINT_TO_POINTER(offsetof(NetplanWifiAccessPoint, field)) |
2722 | |
2723 | -/* net_definition that is currently being processed */ |
2724 | -net_definition* cur_netdef; |
2725 | +/* NetplanNetDefinition that is currently being processed */ |
2726 | +static NetplanNetDefinition* cur_netdef; |
2727 | |
2728 | -/* wifi AP that is currently being processed */ |
2729 | -wifi_access_point* cur_access_point; |
2730 | +/* NetplanWifiAccessPoint that is currently being processed */ |
2731 | +static NetplanWifiAccessPoint* cur_access_point; |
2732 | |
2733 | /* authentication options that are currently being processed */ |
2734 | -authentication_settings* cur_auth; |
2735 | +static NetplanAuthenticationSettings* cur_auth; |
2736 | |
2737 | -ip_route* cur_route; |
2738 | -ip_rule* cur_ip_rule; |
2739 | +static NetplanIPRoute* cur_route; |
2740 | +static NetplanIPRule* cur_ip_rule; |
2741 | |
2742 | -netdef_backend backend_global, backend_cur_type; |
2743 | +static NetplanBackend backend_global, backend_cur_type; |
2744 | |
2745 | -/* Global ID → net_definition* map for all parsed config files */ |
2746 | +/* Global ID → NetplanNetDefinition* map for all parsed config files */ |
2747 | GHashTable* netdefs; |
2748 | |
2749 | /* Contains the same objects as 'netdefs' but ordered by dependency */ |
2750 | @@ -59,7 +60,7 @@ GList* netdefs_ordered; |
2751 | /* Set of IDs in currently parsed YAML file, for being able to detect |
2752 | * "duplicate ID within one file" vs. allowing a drop-in to override/amend an |
2753 | * existing definition */ |
2754 | -GHashTable* ids_in_file; |
2755 | +static GHashTable* ids_in_file; |
2756 | |
2757 | /** |
2758 | * Load YAML file name into a yaml_document_t. |
2759 | @@ -87,6 +88,7 @@ load_yaml(const char* yaml, yaml_document_t* doc, GError** error) |
2760 | ret = parser_error(&parser, yaml, error); |
2761 | } |
2762 | |
2763 | + yaml_parser_delete(&parser); |
2764 | fclose(fyaml); |
2765 | return ret; |
2766 | } |
2767 | @@ -136,13 +138,13 @@ scalar(const yaml_node_t* node) |
2768 | static void |
2769 | add_missing_node(const yaml_node_t* node) |
2770 | { |
2771 | - missing_node* missing; |
2772 | + NetplanMissingNode* missing; |
2773 | |
2774 | /* Let's capture the current netdef we were playing with along with the |
2775 | * actual yaml_node_t that errors (that is an identifier not previously |
2776 | * seen by the compiler). We can use it later to write an sensible error |
2777 | * message and point the user in the right direction. */ |
2778 | - missing = g_new0(missing_node, 1); |
2779 | + missing = g_new0(NetplanMissingNode, 1); |
2780 | missing->netdef_id = cur_netdef->id; |
2781 | missing->node = node; |
2782 | |
2783 | @@ -247,24 +249,88 @@ process_mapping(yaml_document_t* doc, yaml_node_t* node, const mapping_entry_han |
2784 | return TRUE; |
2785 | } |
2786 | |
2787 | +/************************************************************* |
2788 | + * Generic helper functions to extract data from scalar nodes. |
2789 | + *************************************************************/ |
2790 | + |
2791 | /** |
2792 | - * Generic handler for setting a cur_netdef string field from a scalar node |
2793 | - * @data: offset into net_definition where the const char* field to write is |
2794 | + * Handler for setting a guint field from a scalar node, inside a given struct |
2795 | + * @entryptr: pointer to the begining of the to-be-modified data structure |
2796 | + * @data: offset into entryptr struct where the guint field to write is located |
2797 | + */ |
2798 | +static gboolean |
2799 | +handle_generic_guint(yaml_document_t* doc, yaml_node_t* node, const void* entryptr, const void* data, GError** error) |
2800 | +{ |
2801 | + g_assert(entryptr); |
2802 | + guint offset = GPOINTER_TO_UINT(data); |
2803 | + guint64 v; |
2804 | + gchar* endptr; |
2805 | + |
2806 | + v = g_ascii_strtoull(scalar(node), &endptr, 10); |
2807 | + if (*endptr != '\0' || v > G_MAXUINT) |
2808 | + return yaml_error(node, error, "invalid unsigned int value '%s'", scalar(node)); |
2809 | + |
2810 | + *((guint*) ((void*) entryptr + offset)) = (guint) v; |
2811 | + return TRUE; |
2812 | +} |
2813 | + |
2814 | +/** |
2815 | + * Handler for setting a string field from a scalar node, inside a given struct |
2816 | + * @entryptr: pointer to the beginning of the to-be-modified data structure |
2817 | + * @data: offset into entryptr struct where the const char* field to write is |
2818 | * located |
2819 | */ |
2820 | static gboolean |
2821 | -handle_netdef_str(yaml_document_t* doc, yaml_node_t* node, const void* data, GError** error) |
2822 | +handle_generic_str(yaml_document_t* doc, yaml_node_t* node, void* entryptr, const void* data, GError** error) |
2823 | { |
2824 | + g_assert(entryptr); |
2825 | guint offset = GPOINTER_TO_UINT(data); |
2826 | - char** dest = (char**) ((void*) cur_netdef + offset); |
2827 | + char** dest = (char**) ((void*) entryptr + offset); |
2828 | g_free(*dest); |
2829 | *dest = g_strdup(scalar(node)); |
2830 | return TRUE; |
2831 | } |
2832 | |
2833 | +/* |
2834 | + * Handler for setting a MAC address field from a scalar node, inside a given struct |
2835 | + * @entryptr: pointer to the beginning of the to-be-modified data structure |
2836 | + * @data: offset into entryptr struct where the const char* field to write is |
2837 | + * located |
2838 | + */ |
2839 | +static gboolean |
2840 | +handle_generic_mac(yaml_document_t* doc, yaml_node_t* node, void* entryptr, const void* data, GError** error) |
2841 | +{ |
2842 | + g_assert(entryptr); |
2843 | + static regex_t re; |
2844 | + static gboolean re_inited = FALSE; |
2845 | + |
2846 | + g_assert(node->type == YAML_SCALAR_NODE); |
2847 | + |
2848 | + if (!re_inited) { |
2849 | + g_assert(regcomp(&re, "^[[:xdigit:]][[:xdigit:]]:[[:xdigit:]][[:xdigit:]]:[[:xdigit:]][[:xdigit:]]:[[:xdigit:]][[:xdigit:]]:[[:xdigit:]][[:xdigit:]]:[[:xdigit:]][[:xdigit:]]$", REG_EXTENDED|REG_NOSUB) == 0); |
2850 | + re_inited = TRUE; |
2851 | + } |
2852 | + |
2853 | + if (regexec(&re, scalar(node), 0, NULL, 0) != 0) |
2854 | + return yaml_error(node, error, "Invalid MAC address '%s', must be XX:XX:XX:XX:XX:XX", scalar(node)); |
2855 | + |
2856 | + return handle_generic_str(doc, node, entryptr, data, error); |
2857 | +} |
2858 | + |
2859 | +/** |
2860 | + * Generic handler for setting a cur_netdef string field from a scalar node |
2861 | + * @data: offset into NetplanNetDefinition where the const char* field to write is |
2862 | + * located |
2863 | + */ |
2864 | +static gboolean |
2865 | +handle_netdef_str(yaml_document_t* doc, yaml_node_t* node, const void* data, GError** error) |
2866 | +{ |
2867 | + return handle_generic_str(doc, node, cur_netdef, data, error); |
2868 | +} |
2869 | + |
2870 | /** |
2871 | * Generic handler for setting a cur_netdef ID/iface name field from a scalar node |
2872 | - * @data: offset into net_definition where the const char* field to write is |
2873 | + * @data: offset into NetplanNetDefinition where the const char* field to write is |
2874 | * located |
2875 | */ |
2876 | static gboolean |
2877 | @@ -278,20 +344,20 @@ handle_netdef_id(yaml_document_t* doc, yaml_node_t* node, const void* data, GErr |
2878 | /** |
2879 | * Generic handler for setting a cur_netdef ID/iface name field referring to an |
2880 | * existing ID from a scalar node |
2881 | - * @data: offset into net_definition where the net_definition* field to write is |
2882 | + * @data: offset into NetplanNetDefinition where the NetplanNetDefinition* field to write is |
2883 | * located |
2884 | */ |
2885 | static gboolean |
2886 | handle_netdef_id_ref(yaml_document_t* doc, yaml_node_t* node, const void* data, GError** error) |
2887 | { |
2888 | guint offset = GPOINTER_TO_UINT(data); |
2889 | - net_definition* ref = NULL; |
2890 | + NetplanNetDefinition* ref = NULL; |
2891 | |
2892 | ref = g_hash_table_lookup(netdefs, scalar(node)); |
2893 | if (!ref) { |
2894 | add_missing_node(node); |
2895 | } else { |
2896 | - *((net_definition**) ((void*) cur_netdef + offset)) = ref; |
2897 | + *((NetplanNetDefinition**) ((void*) cur_netdef + offset)) = ref; |
2898 | } |
2899 | return TRUE; |
2900 | } |
2901 | @@ -299,31 +365,18 @@ handle_netdef_id_ref(yaml_document_t* doc, yaml_node_t* node, const void* data, |
2902 | |
2903 | /** |
2904 | * Generic handler for setting a cur_netdef MAC address field from a scalar node |
2905 | - * @data: offset into net_definition where the const char* field to write is |
2906 | + * @data: offset into NetplanNetDefinition where the const char* field to write is |
2907 | * located |
2908 | */ |
2909 | static gboolean |
2910 | handle_netdef_mac(yaml_document_t* doc, yaml_node_t* node, const void* data, GError** error) |
2911 | { |
2912 | - static regex_t re; |
2913 | - static gboolean re_inited = FALSE; |
2914 | - |
2915 | - g_assert(node->type == YAML_SCALAR_NODE); |
2916 | - |
2917 | - if (!re_inited) { |
2918 | - g_assert(regcomp(&re, "^[[:xdigit:]][[:xdigit:]]:[[:xdigit:]][[:xdigit:]]:[[:xdigit:]][[:xdigit:]]:[[:xdigit:]][[:xdigit:]]:[[:xdigit:]][[:xdigit:]]:[[:xdigit:]][[:xdigit:]]$", REG_EXTENDED|REG_NOSUB) == 0); |
2919 | - re_inited = TRUE; |
2920 | - } |
2921 | - |
2922 | - if (regexec(&re, scalar(node), 0, NULL, 0) != 0) |
2923 | - return yaml_error(node, error, "Invalid MAC address '%s', must be XX:XX:XX:XX:XX:XX", scalar(node)); |
2924 | - |
2925 | - return handle_netdef_str(doc, node, data, error); |
2926 | + return handle_generic_mac(doc, node, cur_netdef, data, error); |
2927 | } |
2928 | |
2929 | /** |
2930 | * Generic handler for setting a cur_netdef gboolean field from a scalar node |
2931 | - * @data: offset into net_definition where the gboolean field to write is located |
2932 | + * @data: offset into NetplanNetDefinition where the gboolean field to write is located |
2933 | */ |
2934 | static gboolean |
2935 | handle_netdef_bool(yaml_document_t* doc, yaml_node_t* node, const void* data, GError** error) |
2936 | @@ -350,21 +403,12 @@ handle_netdef_bool(yaml_document_t* doc, yaml_node_t* node, const void* data, GE |
2937 | |
2938 | /** |
2939 | * Generic handler for setting a cur_netdef guint field from a scalar node |
2940 | - * @data: offset into net_definition where the guint field to write is located |
2941 | + * @data: offset into NetplanNetDefinition where the guint field to write is located |
2942 | */ |
2943 | static gboolean |
2944 | handle_netdef_guint(yaml_document_t* doc, yaml_node_t* node, const void* data, GError** error) |
2945 | { |
2946 | - guint offset = GPOINTER_TO_UINT(data); |
2947 | - guint64 v; |
2948 | - gchar* endptr; |
2949 | - |
2950 | - v = g_ascii_strtoull(scalar(node), &endptr, 10); |
2951 | - if (*endptr != '\0' || v > G_MAXUINT) |
2952 | - return yaml_error(node, error, "invalid unsigned int value '%s'", scalar(node)); |
2953 | - |
2954 | - *((guint*) ((void*) cur_netdef + offset)) = (guint) v; |
2955 | - return TRUE; |
2956 | + return handle_generic_guint(doc, node, cur_netdef, data, error); |
2957 | } |
2958 | |
2959 | static gboolean |
2960 | @@ -427,12 +471,25 @@ handle_netdef_ip6(yaml_document_t* doc, yaml_node_t* node, const void* data, GEr |
2961 | return TRUE; |
2962 | } |
2963 | |
2964 | +static gboolean |
2965 | +handle_netdef_addrgen(yaml_document_t* doc, yaml_node_t* node, const void* _, GError** error) |
2966 | +{ |
2967 | + g_assert(cur_netdef); |
2968 | + if (strcmp(scalar(node), "eui64") == 0) |
2969 | + cur_netdef->ip6_addr_gen_mode = NETPLAN_ADDRGEN_EUI64; |
2970 | + else if (strcmp(scalar(node), "stable-privacy") == 0) |
2971 | + cur_netdef->ip6_addr_gen_mode = NETPLAN_ADDRGEN_STABLEPRIVACY; |
2972 | + else |
2973 | + return yaml_error(node, error, "unknown ipv6-address-generation '%s'", scalar(node)); |
2974 | + return TRUE; |
2975 | +} |
2976 | + |
2977 | |
2978 | /**************************************************** |
2979 | * Grammar and handlers for network config "match" entry |
2980 | ****************************************************/ |
2981 | |
2982 | -const mapping_entry_handler match_handlers[] = { |
2983 | +static const mapping_entry_handler match_handlers[] = { |
2984 | {"driver", YAML_SCALAR_NODE, handle_netdef_str, NULL, netdef_offset(match.driver)}, |
2985 | {"macaddress", YAML_SCALAR_NODE, handle_netdef_mac, NULL, netdef_offset(match.mac)}, |
2986 | {"name", YAML_SCALAR_NODE, handle_netdef_id, NULL, netdef_offset(match.original_name)}, |
2987 | @@ -459,13 +516,13 @@ handle_auth_key_management(yaml_document_t* doc, yaml_node_t* node, const void* |
2988 | { |
2989 | g_assert(cur_auth); |
2990 | if (strcmp(scalar(node), "none") == 0) |
2991 | - cur_auth->key_management = KEY_MANAGEMENT_NONE; |
2992 | + cur_auth->key_management = NETPLAN_AUTH_KEY_MANAGEMENT_NONE; |
2993 | else if (strcmp(scalar(node), "psk") == 0) |
2994 | - cur_auth->key_management = KEY_MANAGEMENT_WPA_PSK; |
2995 | + cur_auth->key_management = NETPLAN_AUTH_KEY_MANAGEMENT_WPA_PSK; |
2996 | else if (strcmp(scalar(node), "eap") == 0) |
2997 | - cur_auth->key_management = KEY_MANAGEMENT_WPA_EAP; |
2998 | + cur_auth->key_management = NETPLAN_AUTH_KEY_MANAGEMENT_WPA_EAP; |
2999 | else if (strcmp(scalar(node), "802.1x") == 0) |
3000 | - cur_auth->key_management = KEY_MANAGEMENT_8021X; |
3001 | + cur_auth->key_management = NETPLAN_AUTH_KEY_MANAGEMENT_8021X; |
3002 | else |
3003 | return yaml_error(node, error, "unknown key management type '%s'", scalar(node)); |
3004 | return TRUE; |
3005 | @@ -476,17 +533,17 @@ handle_auth_method(yaml_document_t* doc, yaml_node_t* node, const void* _, GErro |
3006 | { |
3007 | g_assert(cur_auth); |
3008 | if (strcmp(scalar(node), "tls") == 0) |
3009 | - cur_auth->eap_method = EAP_TLS; |
3010 | + cur_auth->eap_method = NETPLAN_AUTH_EAP_TLS; |
3011 | else if (strcmp(scalar(node), "peap") == 0) |
3012 | - cur_auth->eap_method = EAP_PEAP; |
3013 | + cur_auth->eap_method = NETPLAN_AUTH_EAP_PEAP; |
3014 | else if (strcmp(scalar(node), "ttls") == 0) |
3015 | - cur_auth->eap_method = EAP_TTLS; |
3016 | + cur_auth->eap_method = NETPLAN_AUTH_EAP_TTLS; |
3017 | else |
3018 | return yaml_error(node, error, "unknown EAP method '%s'", scalar(node)); |
3019 | return TRUE; |
3020 | } |
3021 | |
3022 | -const mapping_entry_handler auth_handlers[] = { |
3023 | +static const mapping_entry_handler auth_handlers[] = { |
3024 | {"key-management", YAML_SCALAR_NODE, handle_auth_key_management}, |
3025 | {"method", YAML_SCALAR_NODE, handle_auth_method}, |
3026 | {"identity", YAML_SCALAR_NODE, handle_auth_str, NULL, auth_offset(identity)}, |
3027 | @@ -496,6 +553,7 @@ const mapping_entry_handler auth_handlers[] = { |
3028 | {"client-certificate", YAML_SCALAR_NODE, handle_auth_str, NULL, auth_offset(client_certificate)}, |
3029 | {"client-key", YAML_SCALAR_NODE, handle_auth_str, NULL, auth_offset(client_key)}, |
3030 | {"client-key-password", YAML_SCALAR_NODE, handle_auth_str, NULL, auth_offset(client_key_password)}, |
3031 | + {"phase2-auth", YAML_SCALAR_NODE, handle_auth_str, NULL, auth_offset(phase2_auth)}, |
3032 | {NULL} |
3033 | }; |
3034 | |
3035 | @@ -503,15 +561,27 @@ const mapping_entry_handler auth_handlers[] = { |
3036 | * Grammar and handlers for network device definition |
3037 | ****************************************************/ |
3038 | |
3039 | -static netdef_backend |
3040 | -get_default_backend_for_type(netdef_type type) |
3041 | +static NetplanBackend |
3042 | +get_default_backend_for_type(NetplanDefType type) |
3043 | { |
3044 | - if (backend_global != BACKEND_NONE) |
3045 | + if (backend_global != NETPLAN_BACKEND_NONE) |
3046 | return backend_global; |
3047 | |
3048 | /* networkd can handle all device types at the moment, so nothing |
3049 | * type-specific */ |
3050 | - return BACKEND_NETWORKD; |
3051 | + return NETPLAN_BACKEND_NETWORKD; |
3052 | +} |
3053 | + |
3054 | +static gboolean |
3055 | +handle_access_point_guint(yaml_document_t* doc, yaml_node_t* node, const void* data, GError** error) |
3056 | +{ |
3057 | + return handle_generic_guint(doc, node, cur_access_point, data, error); |
3058 | +} |
3059 | + |
3060 | +static gboolean |
3061 | +handle_access_point_mac(yaml_document_t* doc, yaml_node_t* node, const void* data, GError** error) |
3062 | +{ |
3063 | + return handle_generic_mac(doc, node, cur_access_point, data, error); |
3064 | } |
3065 | |
3066 | static gboolean |
3067 | @@ -520,7 +590,7 @@ handle_access_point_password(yaml_document_t* doc, yaml_node_t* node, const void |
3068 | g_assert(cur_access_point); |
3069 | /* shortcut for WPA-PSK */ |
3070 | cur_access_point->has_auth = TRUE; |
3071 | - cur_access_point->auth.key_management = KEY_MANAGEMENT_WPA_PSK; |
3072 | + cur_access_point->auth.key_management = NETPLAN_AUTH_KEY_MANAGEMENT_WPA_PSK; |
3073 | g_free(cur_access_point->auth.password); |
3074 | cur_access_point->auth.password = g_strdup(scalar(node)); |
3075 | return TRUE; |
3076 | @@ -546,17 +616,33 @@ handle_access_point_mode(yaml_document_t* doc, yaml_node_t* node, const void* _, |
3077 | { |
3078 | g_assert(cur_access_point); |
3079 | if (strcmp(scalar(node), "infrastructure") == 0) |
3080 | - cur_access_point->mode = WIFI_MODE_INFRASTRUCTURE; |
3081 | + cur_access_point->mode = NETPLAN_WIFI_MODE_INFRASTRUCTURE; |
3082 | else if (strcmp(scalar(node), "adhoc") == 0) |
3083 | - cur_access_point->mode = WIFI_MODE_ADHOC; |
3084 | + cur_access_point->mode = NETPLAN_WIFI_MODE_ADHOC; |
3085 | else if (strcmp(scalar(node), "ap") == 0) |
3086 | - cur_access_point->mode = WIFI_MODE_AP; |
3087 | + cur_access_point->mode = NETPLAN_WIFI_MODE_AP; |
3088 | else |
3089 | return yaml_error(node, error, "unknown wifi mode '%s'", scalar(node)); |
3090 | return TRUE; |
3091 | } |
3092 | |
3093 | -const mapping_entry_handler wifi_access_point_handlers[] = { |
3094 | +static gboolean |
3095 | +handle_access_point_band(yaml_document_t* doc, yaml_node_t* node, const void* _, GError** error) |
3096 | +{ |
3097 | + g_assert(cur_access_point); |
3098 | + if (strcmp(scalar(node), "5GHz") == 0 || strcmp(scalar(node), "5G") == 0) |
3099 | + cur_access_point->band = NETPLAN_WIFI_BAND_5; |
3100 | + else if (strcmp(scalar(node), "2.4GHz") == 0 || strcmp(scalar(node), "2.4G") == 0) |
3101 | + cur_access_point->band = NETPLAN_WIFI_BAND_24; |
3102 | + else |
3103 | + return yaml_error(node, error, "unknown wifi band '%s'", scalar(node)); |
3104 | + return TRUE; |
3105 | +} |
3106 | + |
3107 | +static const mapping_entry_handler wifi_access_point_handlers[] = { |
3108 | + {"band", YAML_SCALAR_NODE, handle_access_point_band}, |
3109 | + {"bssid", YAML_SCALAR_NODE, handle_access_point_mac, NULL, access_point_offset(bssid)}, |
3110 | + {"channel", YAML_SCALAR_NODE, handle_access_point_guint, NULL, access_point_offset(channel)}, |
3111 | {"mode", YAML_SCALAR_NODE, handle_access_point_mode}, |
3112 | {"password", YAML_SCALAR_NODE, handle_access_point_password}, |
3113 | {"auth", YAML_MAPPING_NODE, handle_access_point_auth}, |
3114 | @@ -567,12 +653,12 @@ const mapping_entry_handler wifi_access_point_handlers[] = { |
3115 | * Parse scalar node's string into a netdef_backend. |
3116 | */ |
3117 | static gboolean |
3118 | -parse_renderer(yaml_node_t* node, netdef_backend* backend, GError** error) |
3119 | +parse_renderer(yaml_node_t* node, NetplanBackend* backend, GError** error) |
3120 | { |
3121 | if (strcmp(scalar(node), "networkd") == 0) |
3122 | - *backend = BACKEND_NETWORKD; |
3123 | + *backend = NETPLAN_BACKEND_NETWORKD; |
3124 | else if (strcmp(scalar(node), "NetworkManager") == 0) |
3125 | - *backend = BACKEND_NM; |
3126 | + *backend = NETPLAN_BACKEND_NM; |
3127 | else |
3128 | return yaml_error(node, error, "unknown renderer '%s'", scalar(node)); |
3129 | return TRUE; |
3130 | @@ -581,6 +667,13 @@ parse_renderer(yaml_node_t* node, netdef_backend* backend, GError** error) |
3131 | static gboolean |
3132 | handle_netdef_renderer(yaml_document_t* doc, yaml_node_t* node, const void* _, GError** error) |
3133 | { |
3134 | + if (cur_netdef->type == NETPLAN_DEF_TYPE_VLAN) { |
3135 | + if (strcmp(scalar(node), "sriov") == 0) { |
3136 | + cur_netdef->sriov_vlan_filter = TRUE; |
3137 | + return TRUE; |
3138 | + } |
3139 | + } |
3140 | + |
3141 | return parse_renderer(node, &cur_netdef->backend, error); |
3142 | } |
3143 | |
3144 | @@ -591,12 +684,12 @@ handle_accept_ra(yaml_document_t* doc, yaml_node_t* node, const void* data, GErr |
3145 | g_ascii_strcasecmp(scalar(node), "on") == 0 || |
3146 | g_ascii_strcasecmp(scalar(node), "yes") == 0 || |
3147 | g_ascii_strcasecmp(scalar(node), "y") == 0) |
3148 | - cur_netdef->accept_ra = ACCEPT_RA_ENABLED; |
3149 | + cur_netdef->accept_ra = NETPLAN_RA_MODE_ENABLED; |
3150 | else if (g_ascii_strcasecmp(scalar(node), "false") == 0 || |
3151 | g_ascii_strcasecmp(scalar(node), "off") == 0 || |
3152 | g_ascii_strcasecmp(scalar(node), "no") == 0 || |
3153 | g_ascii_strcasecmp(scalar(node), "n") == 0) |
3154 | - cur_netdef->accept_ra = ACCEPT_RA_DISABLED; |
3155 | + cur_netdef->accept_ra = NETPLAN_RA_MODE_DISABLED; |
3156 | else |
3157 | return yaml_error(node, error, "invalid boolean value '%s'", scalar(node)); |
3158 | |
3159 | @@ -610,6 +703,42 @@ handle_match(yaml_document_t* doc, yaml_node_t* node, const void* _, GError** er |
3160 | return process_mapping(doc, node, match_handlers, error); |
3161 | } |
3162 | |
3163 | +struct NetplanWifiWowlanType NETPLAN_WIFI_WOWLAN_TYPES[] = { |
3164 | + {"default", NETPLAN_WIFI_WOWLAN_DEFAULT}, |
3165 | + {"any", NETPLAN_WIFI_WOWLAN_ANY}, |
3166 | + {"disconnect", NETPLAN_WIFI_WOWLAN_DISCONNECT}, |
3167 | + {"magic_pkt", NETPLAN_WIFI_WOWLAN_MAGIC}, |
3168 | + {"gtk_rekey_failure", NETPLAN_WIFI_WOWLAN_GTK_REKEY_FAILURE}, |
3169 | + {"eap_identity_req", NETPLAN_WIFI_WOWLAN_EAP_IDENTITY_REQ}, |
3170 | + {"four_way_handshake", NETPLAN_WIFI_WOWLAN_4WAY_HANDSHAKE}, |
3171 | + {"rfkill_release", NETPLAN_WIFI_WOWLAN_RFKILL_RELEASE}, |
3172 | + {"tcp", NETPLAN_WIFI_WOWLAN_TCP}, |
3173 | + {NULL}, |
3174 | +}; |
3175 | + |
3176 | +static gboolean |
3177 | +handle_wowlan(yaml_document_t* doc, yaml_node_t* node, const void* _, GError** error) |
3178 | +{ |
3179 | + for (yaml_node_item_t *i = node->data.sequence.items.start; i < node->data.sequence.items.top; i++) { |
3180 | + yaml_node_t *entry = yaml_document_get_node(doc, *i); |
3181 | + assert_type(entry, YAML_SCALAR_NODE); |
3182 | + int found = FALSE; |
3183 | + |
3184 | + for (unsigned i = 0; NETPLAN_WIFI_WOWLAN_TYPES[i].name != NULL; ++i) { |
3185 | + if (g_ascii_strcasecmp(scalar(entry), NETPLAN_WIFI_WOWLAN_TYPES[i].name) == 0) { |
3186 | + cur_netdef->wowlan |= NETPLAN_WIFI_WOWLAN_TYPES[i].flag; |
3187 | + found = TRUE; |
3188 | + break; |
3189 | + } |
3190 | + } |
3191 | + if (!found) |
3192 | + return yaml_error(node, error, "invalid value for wakeonwlan: '%s'", scalar(entry)); |
3193 | + } |
3194 | + if (cur_netdef->wowlan > NETPLAN_WIFI_WOWLAN_DEFAULT && cur_netdef->wowlan & NETPLAN_WIFI_WOWLAN_TYPES[0].flag) |
3195 | + return yaml_error(node, error, "'default' is an exclusive flag for wakeonwlan"); |
3196 | + return TRUE; |
3197 | +} |
3198 | + |
3199 | static gboolean |
3200 | handle_auth(yaml_document_t* doc, yaml_node_t* node, const void* _, GError** error) |
3201 | { |
3202 | @@ -702,7 +831,7 @@ handle_wifi_access_points(yaml_document_t* doc, yaml_node_t* node, const void* d |
3203 | assert_type(value, YAML_MAPPING_NODE); |
3204 | |
3205 | g_assert(cur_access_point == NULL); |
3206 | - cur_access_point = g_new0(wifi_access_point, 1); |
3207 | + cur_access_point = g_new0(NetplanWifiAccessPoint, 1); |
3208 | cur_access_point->ssid = g_strdup(scalar(key)); |
3209 | g_debug("%s: adding wifi AP '%s'", cur_netdef->id, cur_access_point->ssid); |
3210 | |
3211 | @@ -739,7 +868,7 @@ handle_bridge_interfaces(yaml_document_t* doc, yaml_node_t* node, const void* da |
3212 | /* all entries must refer to already defined IDs */ |
3213 | for (yaml_node_item_t *i = node->data.sequence.items.start; i < node->data.sequence.items.top; i++) { |
3214 | yaml_node_t *entry = yaml_document_get_node(doc, *i); |
3215 | - net_definition *component; |
3216 | + NetplanNetDefinition *component; |
3217 | |
3218 | assert_type(entry, YAML_SCALAR_NODE); |
3219 | component = g_hash_table_lookup(netdefs, scalar(entry)); |
3220 | @@ -761,7 +890,7 @@ handle_bridge_interfaces(yaml_document_t* doc, yaml_node_t* node, const void* da |
3221 | |
3222 | /** |
3223 | * Handler for bond "mode" types. |
3224 | - * @data: offset into net_definition where the const char* field to write is |
3225 | + * @data: offset into NetplanNetDefinition where the const char* field to write is |
3226 | * located |
3227 | */ |
3228 | static gboolean |
3229 | @@ -789,7 +918,7 @@ handle_bond_interfaces(yaml_document_t* doc, yaml_node_t* node, const void* data |
3230 | /* all entries must refer to already defined IDs */ |
3231 | for (yaml_node_item_t *i = node->data.sequence.items.start; i < node->data.sequence.items.top; i++) { |
3232 | yaml_node_t *entry = yaml_document_get_node(doc, *i); |
3233 | - net_definition *component; |
3234 | + NetplanNetDefinition *component; |
3235 | |
3236 | assert_type(entry, YAML_SCALAR_NODE); |
3237 | component = g_hash_table_lookup(netdefs, scalar(entry)); |
3238 | @@ -880,12 +1009,12 @@ handle_link_local(yaml_document_t* doc, yaml_node_t* node, const void* _, GError |
3239 | return TRUE; |
3240 | } |
3241 | |
3242 | -struct optional_address_option optional_address_options[] = { |
3243 | - {"ipv4-ll", OPTIONAL_IPV4_LL}, |
3244 | - {"ipv6-ra", OPTIONAL_IPV6_RA}, |
3245 | - {"dhcp4", OPTIONAL_DHCP4}, |
3246 | - {"dhcp6", OPTIONAL_DHCP6}, |
3247 | - {"static", OPTIONAL_STATIC}, |
3248 | +struct NetplanOptionalAddressType NETPLAN_OPTIONAL_ADDRESS_TYPES[] = { |
3249 | + {"ipv4-ll", NETPLAN_OPTIONAL_IPV4_LL}, |
3250 | + {"ipv6-ra", NETPLAN_OPTIONAL_IPV6_RA}, |
3251 | + {"dhcp4", NETPLAN_OPTIONAL_DHCP4}, |
3252 | + {"dhcp6", NETPLAN_OPTIONAL_DHCP6}, |
3253 | + {"static", NETPLAN_OPTIONAL_STATIC}, |
3254 | {NULL}, |
3255 | }; |
3256 | |
3257 | @@ -897,9 +1026,9 @@ handle_optional_addresses(yaml_document_t* doc, yaml_node_t* node, const void* _ |
3258 | assert_type(entry, YAML_SCALAR_NODE); |
3259 | int found = FALSE; |
3260 | |
3261 | - for (unsigned i = 0; optional_address_options[i].name != NULL; ++i) { |
3262 | - if (g_ascii_strcasecmp(scalar(entry), optional_address_options[i].name) == 0) { |
3263 | - cur_netdef->optional_addresses |= optional_address_options[i].flag; |
3264 | + for (unsigned i = 0; NETPLAN_OPTIONAL_ADDRESS_TYPES[i].name != NULL; ++i) { |
3265 | + if (g_ascii_strcasecmp(scalar(entry), NETPLAN_OPTIONAL_ADDRESS_TYPES[i].name) == 0) { |
3266 | + cur_netdef->optional_addresses |= NETPLAN_OPTIONAL_ADDRESS_TYPES[i].flag; |
3267 | found = TRUE; |
3268 | break; |
3269 | } |
3270 | @@ -1131,7 +1260,7 @@ handle_bridge_path_cost(yaml_document_t* doc, yaml_node_t* node, const void* dat |
3271 | yaml_node_t* key, *value; |
3272 | guint v; |
3273 | gchar* endptr; |
3274 | - net_definition *component; |
3275 | + NetplanNetDefinition *component; |
3276 | guint* ref_ptr; |
3277 | |
3278 | key = yaml_document_get_node(doc, entry->key); |
3279 | @@ -1167,7 +1296,7 @@ handle_bridge_port_priority(yaml_document_t* doc, yaml_node_t* node, const void* |
3280 | yaml_node_t* key, *value; |
3281 | guint v; |
3282 | gchar* endptr; |
3283 | - net_definition *component; |
3284 | + NetplanNetDefinition *component; |
3285 | guint* ref_ptr; |
3286 | |
3287 | key = yaml_document_get_node(doc, entry->key); |
3288 | @@ -1197,7 +1326,7 @@ handle_bridge_port_priority(yaml_document_t* doc, yaml_node_t* node, const void* |
3289 | return TRUE; |
3290 | } |
3291 | |
3292 | -const mapping_entry_handler bridge_params_handlers[] = { |
3293 | +static const mapping_entry_handler bridge_params_handlers[] = { |
3294 | {"ageing-time", YAML_SCALAR_NODE, handle_netdef_str, NULL, netdef_offset(bridge_params.ageing_time)}, |
3295 | {"forward-delay", YAML_SCALAR_NODE, handle_netdef_str, NULL, netdef_offset(bridge_params.forward_delay)}, |
3296 | {"hello-time", YAML_SCALAR_NODE, handle_netdef_str, NULL, netdef_offset(bridge_params.hello_time)}, |
3297 | @@ -1221,7 +1350,7 @@ handle_bridge(yaml_document_t* doc, yaml_node_t* node, const void* _, GError** e |
3298 | * Grammar and handlers for network config "routes" entry |
3299 | ****************************************************/ |
3300 | |
3301 | -const mapping_entry_handler routes_handlers[] = { |
3302 | +static const mapping_entry_handler routes_handlers[] = { |
3303 | {"from", YAML_SCALAR_NODE, handle_routes_ip, NULL, route_offset(from)}, |
3304 | {"on-link", YAML_SCALAR_NODE, handle_routes_bool, NULL, route_offset(onlink)}, |
3305 | {"scope", YAML_SCALAR_NODE, handle_routes_scope}, |
3306 | @@ -1239,15 +1368,15 @@ handle_routes(yaml_document_t* doc, yaml_node_t* node, const void* _, GError** e |
3307 | for (yaml_node_item_t *i = node->data.sequence.items.start; i < node->data.sequence.items.top; i++) { |
3308 | yaml_node_t *entry = yaml_document_get_node(doc, *i); |
3309 | |
3310 | - cur_route = g_new0(ip_route, 1); |
3311 | + cur_route = g_new0(NetplanIPRoute, 1); |
3312 | cur_route->type = g_strdup("unicast"); |
3313 | cur_route->scope = g_strdup("global"); |
3314 | cur_route->family = G_MAXUINT; /* 0 is a valid family ID */ |
3315 | - cur_route->metric = METRIC_UNSPEC; /* 0 is a valid metric */ |
3316 | + cur_route->metric = NETPLAN_METRIC_UNSPEC; /* 0 is a valid metric */ |
3317 | |
3318 | if (process_mapping(doc, entry, routes_handlers, error)) { |
3319 | if (!cur_netdef->routes) { |
3320 | - cur_netdef->routes = g_array_new(FALSE, FALSE, sizeof(ip_route*)); |
3321 | + cur_netdef->routes = g_array_new(FALSE, FALSE, sizeof(NetplanIPRoute*)); |
3322 | } |
3323 | |
3324 | g_array_append_val(cur_netdef->routes, cur_route); |
3325 | @@ -1272,7 +1401,7 @@ handle_routes(yaml_document_t* doc, yaml_node_t* node, const void* _, GError** e |
3326 | return TRUE; |
3327 | } |
3328 | |
3329 | -const mapping_entry_handler ip_rules_handlers[] = { |
3330 | +static const mapping_entry_handler ip_rules_handlers[] = { |
3331 | {"from", YAML_SCALAR_NODE, handle_ip_rule_ip, NULL, ip_rule_offset(from)}, |
3332 | {"mark", YAML_SCALAR_NODE, handle_ip_rule_fwmark}, |
3333 | {"priority", YAML_SCALAR_NODE, handle_ip_rule_prio}, |
3334 | @@ -1288,16 +1417,16 @@ handle_ip_rules(yaml_document_t* doc, yaml_node_t* node, const void* _, GError** |
3335 | for (yaml_node_item_t *i = node->data.sequence.items.start; i < node->data.sequence.items.top; i++) { |
3336 | yaml_node_t *entry = yaml_document_get_node(doc, *i); |
3337 | |
3338 | - cur_ip_rule = g_new0(ip_rule, 1); |
3339 | + cur_ip_rule = g_new0(NetplanIPRule, 1); |
3340 | cur_ip_rule->family = G_MAXUINT; /* 0 is a valid family ID */ |
3341 | - cur_ip_rule->priority = IP_RULE_PRIO_UNSPEC; |
3342 | - cur_ip_rule->table = ROUTE_TABLE_UNSPEC; |
3343 | - cur_ip_rule->tos = IP_RULE_TOS_UNSPEC; |
3344 | - cur_ip_rule->fwmark = IP_RULE_FW_MARK_UNSPEC; |
3345 | + cur_ip_rule->priority = NETPLAN_IP_RULE_PRIO_UNSPEC; |
3346 | + cur_ip_rule->table = NETPLAN_ROUTE_TABLE_UNSPEC; |
3347 | + cur_ip_rule->tos = NETPLAN_IP_RULE_TOS_UNSPEC; |
3348 | + cur_ip_rule->fwmark = NETPLAN_IP_RULE_FW_MARK_UNSPEC; |
3349 | |
3350 | if (process_mapping(doc, entry, ip_rules_handlers, error)) { |
3351 | if (!cur_netdef->ip_rules) { |
3352 | - cur_netdef->ip_rules = g_array_new(FALSE, FALSE, sizeof(ip_rule*)); |
3353 | + cur_netdef->ip_rules = g_array_new(FALSE, FALSE, sizeof(NetplanIPRule*)); |
3354 | } |
3355 | |
3356 | g_array_append_val(cur_netdef->ip_rules, cur_ip_rule); |
3357 | @@ -1346,7 +1475,7 @@ handle_arp_ip_targets(yaml_document_t* doc, yaml_node_t* node, const void* _, GE |
3358 | static gboolean |
3359 | handle_bond_primary_slave(yaml_document_t* doc, yaml_node_t* node, const void* data, GError** error) |
3360 | { |
3361 | - net_definition *component; |
3362 | + NetplanNetDefinition *component; |
3363 | char** ref_ptr; |
3364 | |
3365 | component = g_hash_table_lookup(netdefs, scalar(node)); |
3366 | @@ -1365,7 +1494,7 @@ handle_bond_primary_slave(yaml_document_t* doc, yaml_node_t* node, const void* d |
3367 | return TRUE; |
3368 | } |
3369 | |
3370 | -const mapping_entry_handler bond_params_handlers[] = { |
3371 | +static const mapping_entry_handler bond_params_handlers[] = { |
3372 | {"mode", YAML_SCALAR_NODE, handle_bond_mode, NULL, netdef_offset(bond_params.mode)}, |
3373 | {"lacp-rate", YAML_SCALAR_NODE, handle_netdef_str, NULL, netdef_offset(bond_params.lacp_rate)}, |
3374 | {"mii-monitor-interval", YAML_SCALAR_NODE, handle_netdef_str, NULL, netdef_offset(bond_params.monitor_interval)}, |
3375 | @@ -1418,9 +1547,9 @@ handle_dhcp_identifier(yaml_document_t* doc, yaml_node_t* node, const void* data |
3376 | ****************************************************/ |
3377 | |
3378 | const char* |
3379 | -tunnel_mode_to_string(tunnel_mode mode) |
3380 | +tunnel_mode_to_string(NetplanTunnelMode mode) |
3381 | { |
3382 | - return tunnel_mode_table[mode]; |
3383 | + return netplan_tunnel_mode_table[mode]; |
3384 | } |
3385 | |
3386 | static gboolean |
3387 | @@ -1450,11 +1579,11 @@ static gboolean |
3388 | handle_tunnel_mode(yaml_document_t* doc, yaml_node_t* node, const void* _, GError** error) |
3389 | { |
3390 | const char *key = scalar(node); |
3391 | - tunnel_mode i; |
3392 | + NetplanTunnelMode i; |
3393 | |
3394 | // Skip over unknown (0) tunnel mode. |
3395 | - for (i = 1; i < _TUNNEL_MODE_MAX; ++i) { |
3396 | - if (g_strcmp0(tunnel_mode_table[i], key) == 0) { |
3397 | + for (i = 1; i < NETPLAN_TUNNEL_MODE_MAX_; ++i) { |
3398 | + if (g_strcmp0(netplan_tunnel_mode_table[i], key) == 0) { |
3399 | cur_netdef->tunnel.mode = i; |
3400 | return TRUE; |
3401 | } |
3402 | @@ -1485,7 +1614,7 @@ handle_tunnel_key(yaml_document_t* doc, yaml_node_t* node, const void* data, GEr |
3403 | return TRUE; |
3404 | } |
3405 | |
3406 | -const mapping_entry_handler tunnel_keys_handlers[] = { |
3407 | +static const mapping_entry_handler tunnel_keys_handlers[] = { |
3408 | {"input", YAML_SCALAR_NODE, handle_tunnel_key, NULL, netdef_offset(tunnel.input_key)}, |
3409 | {"output", YAML_SCALAR_NODE, handle_tunnel_key, NULL, netdef_offset(tunnel.output_key)}, |
3410 | {NULL} |
3411 | @@ -1519,7 +1648,15 @@ handle_tunnel_key_mapping(yaml_document_t* doc, yaml_node_t* node, const void* _ |
3412 | * Grammar and handlers for network devices |
3413 | ****************************************************/ |
3414 | |
3415 | -const mapping_entry_handler nameservers_handlers[] = { |
3416 | +static const mapping_entry_handler nm_backend_settings_handlers[] = { |
3417 | + {"name", YAML_SCALAR_NODE, handle_netdef_str, NULL, netdef_offset(backend_settings.nm.name)}, |
3418 | + {"uuid", YAML_SCALAR_NODE, handle_netdef_str, NULL, netdef_offset(backend_settings.nm.uuid)}, |
3419 | + {"stable-id", YAML_SCALAR_NODE, handle_netdef_str, NULL, netdef_offset(backend_settings.nm.stable_id)}, |
3420 | + {"device", YAML_SCALAR_NODE, handle_netdef_str, NULL, netdef_offset(backend_settings.nm.device)}, |
3421 | + {NULL} |
3422 | +}; |
3423 | + |
3424 | +static const mapping_entry_handler nameservers_handlers[] = { |
3425 | {"search", YAML_SEQUENCE_NODE, handle_nameservers_search}, |
3426 | {"addresses", YAML_SEQUENCE_NODE, handle_nameservers_addresses}, |
3427 | {NULL} |
3428 | @@ -1537,12 +1674,12 @@ const mapping_entry_handler nameservers_handlers[] = { |
3429 | {"use-ntp", YAML_SCALAR_NODE, handle_netdef_bool, NULL, netdef_offset(overrides.use_ntp)}, \ |
3430 | {"use-routes", YAML_SCALAR_NODE, handle_netdef_bool, NULL, netdef_offset(overrides.use_routes)} |
3431 | |
3432 | -const mapping_entry_handler dhcp4_overrides_handlers[] = { |
3433 | +static const mapping_entry_handler dhcp4_overrides_handlers[] = { |
3434 | COMMON_DHCP_OVERRIDES_HANDLERS(dhcp4_overrides), |
3435 | {NULL}, |
3436 | }; |
3437 | |
3438 | -const mapping_entry_handler dhcp6_overrides_handlers[] = { |
3439 | +static const mapping_entry_handler dhcp6_overrides_handlers[] = { |
3440 | COMMON_DHCP_OVERRIDES_HANDLERS(dhcp6_overrides), |
3441 | {NULL}, |
3442 | }; |
3443 | @@ -1559,6 +1696,7 @@ const mapping_entry_handler dhcp6_overrides_handlers[] = { |
3444 | {"dhcp6-overrides", YAML_MAPPING_NODE, NULL, dhcp6_overrides_handlers}, \ |
3445 | {"gateway4", YAML_SCALAR_NODE, handle_gateway4}, \ |
3446 | {"gateway6", YAML_SCALAR_NODE, handle_gateway6}, \ |
3447 | + {"ipv6-address-generation", YAML_SCALAR_NODE, handle_netdef_addrgen}, \ |
3448 | {"ipv6-mtu", YAML_SCALAR_NODE, handle_netdef_guint, NULL, netdef_offset(ipv6_mtubytes)}, \ |
3449 | {"ipv6-privacy", YAML_SCALAR_NODE, handle_netdef_bool, NULL, netdef_offset(ip6_privacy)}, \ |
3450 | {"link-local", YAML_SEQUENCE_NODE, handle_link_local}, \ |
3451 | @@ -1571,50 +1709,77 @@ const mapping_entry_handler dhcp6_overrides_handlers[] = { |
3452 | {"routes", YAML_SEQUENCE_NODE, handle_routes}, \ |
3453 | {"routing-policy", YAML_SEQUENCE_NODE, handle_ip_rules} |
3454 | |
3455 | +#define COMMON_BACKEND_HANDLERS \ |
3456 | + {"networkmanager", YAML_MAPPING_NODE, NULL, nm_backend_settings_handlers} |
3457 | + |
3458 | /* Handlers for physical links */ |
3459 | #define PHYSICAL_LINK_HANDLERS \ |
3460 | {"match", YAML_MAPPING_NODE, handle_match}, \ |
3461 | {"set-name", YAML_SCALAR_NODE, handle_netdef_str, NULL, netdef_offset(set_name)}, \ |
3462 | - {"wakeonlan", YAML_SCALAR_NODE, handle_netdef_bool, NULL, netdef_offset(wake_on_lan)} |
3463 | + {"wakeonlan", YAML_SCALAR_NODE, handle_netdef_bool, NULL, netdef_offset(wake_on_lan)}, \ |
3464 | + {"wakeonwlan", YAML_SEQUENCE_NODE, handle_wowlan, NULL, netdef_offset(wowlan)}, \ |
3465 | + {"emit-lldp", YAML_SCALAR_NODE, handle_netdef_bool, NULL, netdef_offset(emit_lldp)} |
3466 | |
3467 | -const mapping_entry_handler ethernet_def_handlers[] = { |
3468 | +static const mapping_entry_handler ethernet_def_handlers[] = { |
3469 | COMMON_LINK_HANDLERS, |
3470 | + COMMON_BACKEND_HANDLERS, |
3471 | PHYSICAL_LINK_HANDLERS, |
3472 | {"auth", YAML_MAPPING_NODE, handle_auth}, |
3473 | + {"link", YAML_SCALAR_NODE, handle_netdef_id_ref, NULL, netdef_offset(sriov_link)}, |
3474 | + {"virtual-function-count", YAML_SCALAR_NODE, handle_netdef_guint, NULL, netdef_offset(sriov_explicit_vf_count)}, |
3475 | {NULL} |
3476 | }; |
3477 | |
3478 | -const mapping_entry_handler wifi_def_handlers[] = { |
3479 | +static const mapping_entry_handler wifi_def_handlers[] = { |
3480 | COMMON_LINK_HANDLERS, |
3481 | + COMMON_BACKEND_HANDLERS, |
3482 | PHYSICAL_LINK_HANDLERS, |
3483 | {"access-points", YAML_MAPPING_NODE, handle_wifi_access_points}, |
3484 | {"auth", YAML_MAPPING_NODE, handle_auth}, |
3485 | {NULL} |
3486 | }; |
3487 | |
3488 | -const mapping_entry_handler bridge_def_handlers[] = { |
3489 | +static const mapping_entry_handler bridge_def_handlers[] = { |
3490 | COMMON_LINK_HANDLERS, |
3491 | + COMMON_BACKEND_HANDLERS, |
3492 | {"interfaces", YAML_SEQUENCE_NODE, handle_bridge_interfaces, NULL, NULL}, |
3493 | {"parameters", YAML_MAPPING_NODE, handle_bridge}, |
3494 | {NULL} |
3495 | }; |
3496 | |
3497 | -const mapping_entry_handler bond_def_handlers[] = { |
3498 | +static const mapping_entry_handler bond_def_handlers[] = { |
3499 | COMMON_LINK_HANDLERS, |
3500 | + COMMON_BACKEND_HANDLERS, |
3501 | {"interfaces", YAML_SEQUENCE_NODE, handle_bond_interfaces, NULL, NULL}, |
3502 | {"parameters", YAML_MAPPING_NODE, handle_bonding}, |
3503 | {NULL} |
3504 | }; |
3505 | |
3506 | -const mapping_entry_handler vlan_def_handlers[] = { |
3507 | +static const mapping_entry_handler vlan_def_handlers[] = { |
3508 | COMMON_LINK_HANDLERS, |
3509 | + COMMON_BACKEND_HANDLERS, |
3510 | {"id", YAML_SCALAR_NODE, handle_netdef_guint, NULL, netdef_offset(vlan_id)}, |
3511 | {"link", YAML_SCALAR_NODE, handle_netdef_id_ref, NULL, netdef_offset(vlan_link)}, |
3512 | {NULL} |
3513 | }; |
3514 | |
3515 | -const mapping_entry_handler tunnel_def_handlers[] = { |
3516 | +static const mapping_entry_handler modem_def_handlers[] = { |
3517 | + COMMON_LINK_HANDLERS, |
3518 | + {"apn", YAML_SCALAR_NODE, handle_netdef_str, NULL, netdef_offset(modem_params.apn)}, |
3519 | + {"auto-config", YAML_SCALAR_NODE, handle_netdef_bool, NULL, netdef_offset(modem_params.auto_config)}, |
3520 | + {"device-id", YAML_SCALAR_NODE, handle_netdef_str, NULL, netdef_offset(modem_params.device_id)}, |
3521 | + {"network-id", YAML_SCALAR_NODE, handle_netdef_str, NULL, netdef_offset(modem_params.network_id)}, |
3522 | + {"number", YAML_SCALAR_NODE, handle_netdef_str, NULL, netdef_offset(modem_params.number)}, |
3523 | + {"password", YAML_SCALAR_NODE, handle_netdef_str, NULL, netdef_offset(modem_params.password)}, |
3524 | + {"pin", YAML_SCALAR_NODE, handle_netdef_str, NULL, netdef_offset(modem_params.pin)}, |
3525 | + {"sim-id", YAML_SCALAR_NODE, handle_netdef_str, NULL, netdef_offset(modem_params.sim_id)}, |
3526 | + {"sim-operator-id", YAML_SCALAR_NODE, handle_netdef_str, NULL, netdef_offset(modem_params.sim_operator_id)}, |
3527 | + {"username", YAML_SCALAR_NODE, handle_netdef_str, NULL, netdef_offset(modem_params.username)}, |
3528 | +}; |
3529 | + |
3530 | +static const mapping_entry_handler tunnel_def_handlers[] = { |
3531 | COMMON_LINK_HANDLERS, |
3532 | + COMMON_BACKEND_HANDLERS, |
3533 | {"mode", YAML_SCALAR_NODE, handle_tunnel_mode}, |
3534 | {"local", YAML_SCALAR_NODE, handle_tunnel_addr, NULL, netdef_offset(tunnel.local_ip)}, |
3535 | {"remote", YAML_SCALAR_NODE, handle_tunnel_addr, NULL, netdef_offset(tunnel.remote_ip)}, |
3536 | @@ -1650,7 +1815,7 @@ handle_network_renderer(yaml_document_t* doc, yaml_node_t* node, const void* _, |
3537 | } |
3538 | |
3539 | static void |
3540 | -initialize_dhcp_overrides(dhcp_overrides* overrides) |
3541 | +initialize_dhcp_overrides(NetplanDHCPOverrides* overrides) |
3542 | { |
3543 | overrides->use_dns = TRUE; |
3544 | overrides->use_domains = NULL; |
3545 | @@ -1660,7 +1825,7 @@ initialize_dhcp_overrides(dhcp_overrides* overrides) |
3546 | overrides->use_mtu = TRUE; |
3547 | overrides->use_routes = TRUE; |
3548 | overrides->hostname = NULL; |
3549 | - overrides->metric = METRIC_UNSPEC; |
3550 | + overrides->metric = NETPLAN_METRIC_UNSPEC; |
3551 | } |
3552 | |
3553 | /** |
3554 | @@ -1705,19 +1870,20 @@ handle_network_type(yaml_document_t* doc, yaml_node_t* node, const void* data, G |
3555 | return yaml_error(key, error, "Updated definition '%s' changes device type", scalar(key)); |
3556 | } else { |
3557 | /* create new network definition */ |
3558 | - cur_netdef = g_new0(net_definition, 1); |
3559 | + cur_netdef = g_new0(NetplanNetDefinition, 1); |
3560 | cur_netdef->type = GPOINTER_TO_UINT(data); |
3561 | - cur_netdef->backend = backend_cur_type ?: BACKEND_NONE; |
3562 | + cur_netdef->backend = backend_cur_type ?: NETPLAN_BACKEND_NONE; |
3563 | cur_netdef->id = g_strdup(scalar(key)); |
3564 | |
3565 | /* Set some default values */ |
3566 | cur_netdef->vlan_id = G_MAXUINT; /* 0 is a valid ID */ |
3567 | - cur_netdef->tunnel.mode = TUNNEL_MODE_UNKNOWN; |
3568 | + cur_netdef->tunnel.mode = NETPLAN_TUNNEL_MODE_UNKNOWN; |
3569 | cur_netdef->dhcp_identifier = g_strdup("duid"); /* keep networkd's default */ |
3570 | /* systemd-networkd defaults to IPv6 LL enabled; keep that default */ |
3571 | cur_netdef->linklocal.ipv6 = TRUE; |
3572 | g_hash_table_insert(netdefs, cur_netdef->id, cur_netdef); |
3573 | netdefs_ordered = g_list_append(netdefs_ordered, cur_netdef); |
3574 | + cur_netdef->sriov_vlan_filter = FALSE; |
3575 | |
3576 | /* DHCP override defaults */ |
3577 | initialize_dhcp_overrides(&cur_netdef->dhcp4_overrides); |
3578 | @@ -1732,12 +1898,13 @@ handle_network_type(yaml_document_t* doc, yaml_node_t* node, const void* data, G |
3579 | |
3580 | /* and fill it with definitions */ |
3581 | switch (cur_netdef->type) { |
3582 | - case ND_BOND: handlers = bond_def_handlers; break; |
3583 | - case ND_BRIDGE: handlers = bridge_def_handlers; break; |
3584 | - case ND_ETHERNET: handlers = ethernet_def_handlers; break; |
3585 | - case ND_TUNNEL: handlers = tunnel_def_handlers; break; |
3586 | - case ND_VLAN: handlers = vlan_def_handlers; break; |
3587 | - case ND_WIFI: handlers = wifi_def_handlers; break; |
3588 | + case NETPLAN_DEF_TYPE_BOND: handlers = bond_def_handlers; break; |
3589 | + case NETPLAN_DEF_TYPE_BRIDGE: handlers = bridge_def_handlers; break; |
3590 | + case NETPLAN_DEF_TYPE_ETHERNET: handlers = ethernet_def_handlers; break; |
3591 | + case NETPLAN_DEF_TYPE_MODEM: handlers = modem_def_handlers; break; |
3592 | + case NETPLAN_DEF_TYPE_TUNNEL: handlers = tunnel_def_handlers; break; |
3593 | + case NETPLAN_DEF_TYPE_VLAN: handlers = vlan_def_handlers; break; |
3594 | + case NETPLAN_DEF_TYPE_WIFI: handlers = wifi_def_handlers; break; |
3595 | default: g_assert_not_reached(); // LCOV_EXCL_LINE |
3596 | } |
3597 | if (!process_mapping(doc, value, handlers, error)) |
3598 | @@ -1749,22 +1916,23 @@ handle_network_type(yaml_document_t* doc, yaml_node_t* node, const void* data, G |
3599 | |
3600 | /* convenience shortcut: physical device without match: means match |
3601 | * name on ID */ |
3602 | - if (cur_netdef->type < ND_VIRTUAL && !cur_netdef->has_match) |
3603 | + if (cur_netdef->type < NETPLAN_DEF_TYPE_VIRTUAL && !cur_netdef->has_match) |
3604 | cur_netdef->match.original_name = cur_netdef->id; |
3605 | } |
3606 | - backend_cur_type = BACKEND_NONE; |
3607 | + backend_cur_type = NETPLAN_BACKEND_NONE; |
3608 | return TRUE; |
3609 | } |
3610 | |
3611 | -const mapping_entry_handler network_handlers[] = { |
3612 | - {"bonds", YAML_MAPPING_NODE, handle_network_type, NULL, GUINT_TO_POINTER(ND_BOND)}, |
3613 | - {"bridges", YAML_MAPPING_NODE, handle_network_type, NULL, GUINT_TO_POINTER(ND_BRIDGE)}, |
3614 | - {"ethernets", YAML_MAPPING_NODE, handle_network_type, NULL, GUINT_TO_POINTER(ND_ETHERNET)}, |
3615 | +static const mapping_entry_handler network_handlers[] = { |
3616 | + {"bonds", YAML_MAPPING_NODE, handle_network_type, NULL, GUINT_TO_POINTER(NETPLAN_DEF_TYPE_BOND)}, |
3617 | + {"bridges", YAML_MAPPING_NODE, handle_network_type, NULL, GUINT_TO_POINTER(NETPLAN_DEF_TYPE_BRIDGE)}, |
3618 | + {"ethernets", YAML_MAPPING_NODE, handle_network_type, NULL, GUINT_TO_POINTER(NETPLAN_DEF_TYPE_ETHERNET)}, |
3619 | {"renderer", YAML_SCALAR_NODE, handle_network_renderer}, |
3620 | - {"tunnels", YAML_MAPPING_NODE, handle_network_type, NULL, GUINT_TO_POINTER(ND_TUNNEL)}, |
3621 | + {"tunnels", YAML_MAPPING_NODE, handle_network_type, NULL, GUINT_TO_POINTER(NETPLAN_DEF_TYPE_TUNNEL)}, |
3622 | {"version", YAML_SCALAR_NODE, handle_network_version}, |
3623 | - {"vlans", YAML_MAPPING_NODE, handle_network_type, NULL, GUINT_TO_POINTER(ND_VLAN)}, |
3624 | - {"wifis", YAML_MAPPING_NODE, handle_network_type, NULL, GUINT_TO_POINTER(ND_WIFI)}, |
3625 | + {"vlans", YAML_MAPPING_NODE, handle_network_type, NULL, GUINT_TO_POINTER(NETPLAN_DEF_TYPE_VLAN)}, |
3626 | + {"wifis", YAML_MAPPING_NODE, handle_network_type, NULL, GUINT_TO_POINTER(NETPLAN_DEF_TYPE_WIFI)}, |
3627 | + {"modems", YAML_MAPPING_NODE, handle_network_type, NULL, GUINT_TO_POINTER(NETPLAN_DEF_TYPE_MODEM)}, |
3628 | {NULL} |
3629 | }; |
3630 | |
3631 | @@ -1772,7 +1940,7 @@ const mapping_entry_handler network_handlers[] = { |
3632 | * Grammar and handlers for root node |
3633 | ****************************************************/ |
3634 | |
3635 | -const mapping_entry_handler root_handlers[] = { |
3636 | +static const mapping_entry_handler root_handlers[] = { |
3637 | {"network", YAML_MAPPING_NODE, NULL, network_handlers}, |
3638 | {NULL} |
3639 | }; |
3640 | @@ -1809,7 +1977,7 @@ process_document(yaml_document_t* doc, GError** error) |
3641 | if (g_hash_table_size(missing_id) > 0) { |
3642 | GHashTableIter iter; |
3643 | gpointer key, value; |
3644 | - missing_node *missing; |
3645 | + NetplanMissingNode *missing; |
3646 | |
3647 | g_clear_error(error); |
3648 | |
3649 | @@ -1817,7 +1985,7 @@ process_document(yaml_document_t* doc, GError** error) |
3650 | * approximate early failure and give the user a meaningful error. */ |
3651 | g_hash_table_iter_init (&iter, missing_id); |
3652 | g_hash_table_iter_next (&iter, &key, &value); |
3653 | - missing = (missing_node*) value; |
3654 | + missing = (NetplanMissingNode*) value; |
3655 | |
3656 | return yaml_error(missing->node, error, "%s: interface '%s' is not defined", |
3657 | missing->netdef_id, |
3658 | @@ -1833,7 +2001,7 @@ process_document(yaml_document_t* doc, GError** error) |
3659 | * Parse given YAML file and create/update global "netdefs" list. |
3660 | */ |
3661 | gboolean |
3662 | -parse_yaml(const char* filename, GError** error) |
3663 | +netplan_parse_yaml(const char* filename, GError** error) |
3664 | { |
3665 | yaml_document_t doc; |
3666 | gboolean ret; |
3667 | @@ -1841,13 +2009,13 @@ parse_yaml(const char* filename, GError** error) |
3668 | if (!load_yaml(filename, &doc, error)) |
3669 | return FALSE; |
3670 | |
3671 | + if (!netdefs) |
3672 | + netdefs = g_hash_table_new(g_str_hash, g_str_equal); |
3673 | + |
3674 | /* empty file? */ |
3675 | if (yaml_document_get_root_node(&doc) == NULL) |
3676 | return TRUE; |
3677 | |
3678 | - if (!netdefs) |
3679 | - netdefs = g_hash_table_new(g_str_hash, g_str_equal); |
3680 | - |
3681 | g_assert(ids_in_file == NULL); |
3682 | ids_in_file = g_hash_table_new(g_str_hash, NULL); |
3683 | |
3684 | @@ -1864,10 +2032,10 @@ static void |
3685 | finish_iterator(gpointer key, gpointer value, gpointer user_data) |
3686 | { |
3687 | GError **error = (GError **)user_data; |
3688 | - net_definition* nd = value; |
3689 | + NetplanNetDefinition* nd = value; |
3690 | |
3691 | /* Take more steps to make sure we always have a backend set for netdefs */ |
3692 | - if (nd->backend == BACKEND_NONE) { |
3693 | + if (nd->backend == NETPLAN_BACKEND_NONE) { |
3694 | nd->backend = get_default_backend_for_type(nd->type); |
3695 | g_debug("%s: setting default backend to %i", nd->id, nd->backend); |
3696 | } |
3697 | @@ -1880,23 +2048,25 @@ finish_iterator(gpointer key, gpointer value, gpointer user_data) |
3698 | /** |
3699 | * Post-processing after parsing all config files |
3700 | */ |
3701 | -gboolean |
3702 | -finish_parse(GError** error) |
3703 | +GHashTable * |
3704 | +netplan_finish_parse(GError** error) |
3705 | { |
3706 | - if (netdefs) |
3707 | + if (netdefs) { |
3708 | + g_debug("We have some netdefs, pass them through a final round of validation"); |
3709 | g_hash_table_foreach(netdefs, finish_iterator, error); |
3710 | + } |
3711 | |
3712 | if (error && *error) |
3713 | - return FALSE; |
3714 | + return NULL; |
3715 | |
3716 | - return TRUE; |
3717 | + return netdefs; |
3718 | } |
3719 | |
3720 | /** |
3721 | * Return current global backend. |
3722 | */ |
3723 | -netdef_backend |
3724 | -get_global_backend() |
3725 | +NetplanBackend |
3726 | +netplan_get_global_backend() |
3727 | { |
3728 | return backend_global; |
3729 | } |
3730 | diff --git a/src/parse.h b/src/parse.h |
3731 | index 381d450..b84ff4c 100644 |
3732 | --- a/src/parse.h |
3733 | +++ b/src/parse.h |
3734 | @@ -39,114 +39,140 @@ int missing_ids_found; |
3735 | ****************************************************/ |
3736 | |
3737 | typedef enum { |
3738 | - ND_NONE, |
3739 | + NETPLAN_DEF_TYPE_NONE, |
3740 | /* physical devices */ |
3741 | - ND_ETHERNET, |
3742 | - ND_WIFI, |
3743 | + NETPLAN_DEF_TYPE_ETHERNET, |
3744 | + NETPLAN_DEF_TYPE_WIFI, |
3745 | + NETPLAN_DEF_TYPE_MODEM, |
3746 | /* virtual devices */ |
3747 | - ND_VIRTUAL, |
3748 | - ND_BRIDGE = ND_VIRTUAL, |
3749 | - ND_BOND, |
3750 | - ND_VLAN, |
3751 | - ND_TUNNEL, |
3752 | -} netdef_type; |
3753 | + NETPLAN_DEF_TYPE_VIRTUAL, |
3754 | + NETPLAN_DEF_TYPE_BRIDGE = NETPLAN_DEF_TYPE_VIRTUAL, |
3755 | + NETPLAN_DEF_TYPE_BOND, |
3756 | + NETPLAN_DEF_TYPE_VLAN, |
3757 | + NETPLAN_DEF_TYPE_TUNNEL, |
3758 | +} NetplanDefType; |
3759 | |
3760 | typedef enum { |
3761 | - BACKEND_NONE, |
3762 | - BACKEND_NETWORKD, |
3763 | - BACKEND_NM, |
3764 | - _BACKEND_MAX, |
3765 | -} netdef_backend; |
3766 | - |
3767 | -static const char* const netdef_backend_to_name[_BACKEND_MAX] = { |
3768 | - [BACKEND_NONE] = "none", |
3769 | - [BACKEND_NETWORKD] = "networkd", |
3770 | - [BACKEND_NM] = "NetworkManager", |
3771 | + NETPLAN_BACKEND_NONE, |
3772 | + NETPLAN_BACKEND_NETWORKD, |
3773 | + NETPLAN_BACKEND_NM, |
3774 | + NETPLAN_BACKEND_MAX_, |
3775 | +} NetplanBackend; |
3776 | + |
3777 | +static const char* const netplan_backend_to_name[NETPLAN_BACKEND_MAX_] = { |
3778 | + [NETPLAN_BACKEND_NONE] = "none", |
3779 | + [NETPLAN_BACKEND_NETWORKD] = "networkd", |
3780 | + [NETPLAN_BACKEND_NM] = "NetworkManager", |
3781 | }; |
3782 | |
3783 | typedef enum { |
3784 | - ACCEPT_RA_KERNEL, |
3785 | - ACCEPT_RA_ENABLED, |
3786 | - ACCEPT_RA_DISABLED, |
3787 | -} ra_mode; |
3788 | + NETPLAN_RA_MODE_KERNEL, |
3789 | + NETPLAN_RA_MODE_ENABLED, |
3790 | + NETPLAN_RA_MODE_DISABLED, |
3791 | +} NetplanRAMode; |
3792 | |
3793 | typedef enum { |
3794 | - OPTIONAL_IPV4_LL = 1<<0, |
3795 | - OPTIONAL_IPV6_RA = 1<<1, |
3796 | - OPTIONAL_DHCP4 = 1<<2, |
3797 | - OPTIONAL_DHCP6 = 1<<3, |
3798 | - OPTIONAL_STATIC = 1<<4, |
3799 | -} optional_addr; |
3800 | + NETPLAN_OPTIONAL_IPV4_LL = 1<<0, |
3801 | + NETPLAN_OPTIONAL_IPV6_RA = 1<<1, |
3802 | + NETPLAN_OPTIONAL_DHCP4 = 1<<2, |
3803 | + NETPLAN_OPTIONAL_DHCP6 = 1<<3, |
3804 | + NETPLAN_OPTIONAL_STATIC = 1<<4, |
3805 | +} NetplanOptionalAddressFlag; |
3806 | + |
3807 | +typedef enum { |
3808 | + NETPLAN_ADDRGEN_DEFAULT, |
3809 | + NETPLAN_ADDRGEN_EUI64, |
3810 | + NETPLAN_ADDRGEN_STABLEPRIVACY, |
3811 | +} NetplanAddrGenMode; |
3812 | + |
3813 | +struct NetplanOptionalAddressType { |
3814 | + char* name; |
3815 | + NetplanOptionalAddressFlag flag; |
3816 | +}; |
3817 | + |
3818 | +extern struct NetplanOptionalAddressType NETPLAN_OPTIONAL_ADDRESS_TYPES[]; |
3819 | |
3820 | /* Tunnel mode enum; sync with NetworkManager's DBUS API */ |
3821 | /* TODO: figure out whether networkd's GRETAP and NM's ISATAP |
3822 | * are the same thing. |
3823 | */ |
3824 | typedef enum { |
3825 | - TUNNEL_MODE_UNKNOWN = 0, |
3826 | - TUNNEL_MODE_IPIP = 1, |
3827 | - TUNNEL_MODE_GRE = 2, |
3828 | - TUNNEL_MODE_SIT = 3, |
3829 | - TUNNEL_MODE_ISATAP = 4, // NM only. |
3830 | - TUNNEL_MODE_VTI = 5, |
3831 | - TUNNEL_MODE_IP6IP6 = 6, |
3832 | - TUNNEL_MODE_IPIP6 = 7, |
3833 | - TUNNEL_MODE_IP6GRE = 8, |
3834 | - TUNNEL_MODE_VTI6 = 9, |
3835 | + NETPLAN_TUNNEL_MODE_UNKNOWN = 0, |
3836 | + NETPLAN_TUNNEL_MODE_IPIP = 1, |
3837 | + NETPLAN_TUNNEL_MODE_GRE = 2, |
3838 | + NETPLAN_TUNNEL_MODE_SIT = 3, |
3839 | + NETPLAN_TUNNEL_MODE_ISATAP = 4, // NM only. |
3840 | + NETPLAN_TUNNEL_MODE_VTI = 5, |
3841 | + NETPLAN_TUNNEL_MODE_IP6IP6 = 6, |
3842 | + NETPLAN_TUNNEL_MODE_IPIP6 = 7, |
3843 | + NETPLAN_TUNNEL_MODE_IP6GRE = 8, |
3844 | + NETPLAN_TUNNEL_MODE_VTI6 = 9, |
3845 | |
3846 | /* systemd-only, apparently? */ |
3847 | - TUNNEL_MODE_GRETAP = 101, |
3848 | - TUNNEL_MODE_IP6GRETAP = 102, |
3849 | + NETPLAN_TUNNEL_MODE_GRETAP = 101, |
3850 | + NETPLAN_TUNNEL_MODE_IP6GRETAP = 102, |
3851 | |
3852 | - _TUNNEL_MODE_MAX, |
3853 | -} tunnel_mode; |
3854 | + NETPLAN_TUNNEL_MODE_MAX_, |
3855 | +} NetplanTunnelMode; |
3856 | |
3857 | static const char* const |
3858 | -tunnel_mode_table[_TUNNEL_MODE_MAX] = { |
3859 | - [TUNNEL_MODE_UNKNOWN] = "unknown", |
3860 | - [TUNNEL_MODE_IPIP] = "ipip", |
3861 | - [TUNNEL_MODE_GRE] = "gre", |
3862 | - [TUNNEL_MODE_SIT] = "sit", |
3863 | - [TUNNEL_MODE_ISATAP] = "isatap", |
3864 | - [TUNNEL_MODE_VTI] = "vti", |
3865 | - [TUNNEL_MODE_IP6IP6] = "ip6ip6", |
3866 | - [TUNNEL_MODE_IPIP6] = "ipip6", |
3867 | - [TUNNEL_MODE_IP6GRE] = "ip6gre", |
3868 | - [TUNNEL_MODE_VTI6] = "vti6", |
3869 | - |
3870 | - [TUNNEL_MODE_GRETAP] = "gretap", |
3871 | - [TUNNEL_MODE_IP6GRETAP] = "ip6gretap", |
3872 | +netplan_tunnel_mode_table[NETPLAN_TUNNEL_MODE_MAX_] = { |
3873 | + [NETPLAN_TUNNEL_MODE_UNKNOWN] = "unknown", |
3874 | + [NETPLAN_TUNNEL_MODE_IPIP] = "ipip", |
3875 | + [NETPLAN_TUNNEL_MODE_GRE] = "gre", |
3876 | + [NETPLAN_TUNNEL_MODE_SIT] = "sit", |
3877 | + [NETPLAN_TUNNEL_MODE_ISATAP] = "isatap", |
3878 | + [NETPLAN_TUNNEL_MODE_VTI] = "vti", |
3879 | + [NETPLAN_TUNNEL_MODE_IP6IP6] = "ip6ip6", |
3880 | + [NETPLAN_TUNNEL_MODE_IPIP6] = "ipip6", |
3881 | + [NETPLAN_TUNNEL_MODE_IP6GRE] = "ip6gre", |
3882 | + [NETPLAN_TUNNEL_MODE_VTI6] = "vti6", |
3883 | + |
3884 | + [NETPLAN_TUNNEL_MODE_GRETAP] = "gretap", |
3885 | + [NETPLAN_TUNNEL_MODE_IP6GRETAP] = "ip6gretap", |
3886 | }; |
3887 | |
3888 | -struct optional_address_option { |
3889 | +typedef enum { |
3890 | + NETPLAN_WIFI_WOWLAN_DEFAULT = 1<<0, |
3891 | + NETPLAN_WIFI_WOWLAN_ANY = 1<<1, |
3892 | + NETPLAN_WIFI_WOWLAN_DISCONNECT = 1<<2, |
3893 | + NETPLAN_WIFI_WOWLAN_MAGIC = 1<<3, |
3894 | + NETPLAN_WIFI_WOWLAN_GTK_REKEY_FAILURE = 1<<4, |
3895 | + NETPLAN_WIFI_WOWLAN_EAP_IDENTITY_REQ = 1<<5, |
3896 | + NETPLAN_WIFI_WOWLAN_4WAY_HANDSHAKE = 1<<6, |
3897 | + NETPLAN_WIFI_WOWLAN_RFKILL_RELEASE = 1<<7, |
3898 | + NETPLAN_WIFI_WOWLAN_TCP = 1<<8, |
3899 | +} NetplanWifiWowlanFlag; |
3900 | + |
3901 | +struct NetplanWifiWowlanType { |
3902 | char* name; |
3903 | - optional_addr flag; |
3904 | + NetplanWifiWowlanFlag flag; |
3905 | }; |
3906 | |
3907 | -extern struct optional_address_option optional_address_options[]; |
3908 | +extern struct NetplanWifiWowlanType NETPLAN_WIFI_WOWLAN_TYPES[]; |
3909 | |
3910 | typedef enum { |
3911 | - KEY_MANAGEMENT_NONE, |
3912 | - KEY_MANAGEMENT_WPA_PSK, |
3913 | - KEY_MANAGEMENT_WPA_EAP, |
3914 | - KEY_MANAGEMENT_8021X, |
3915 | -} auth_key_management_type; |
3916 | + NETPLAN_AUTH_KEY_MANAGEMENT_NONE, |
3917 | + NETPLAN_AUTH_KEY_MANAGEMENT_WPA_PSK, |
3918 | + NETPLAN_AUTH_KEY_MANAGEMENT_WPA_EAP, |
3919 | + NETPLAN_AUTH_KEY_MANAGEMENT_8021X, |
3920 | +} NetplanAuthKeyManagementType; |
3921 | |
3922 | typedef enum { |
3923 | - EAP_NONE, |
3924 | - EAP_TLS, |
3925 | - EAP_PEAP, |
3926 | - EAP_TTLS, |
3927 | -} auth_eap_method; |
3928 | + NETPLAN_AUTH_EAP_NONE, |
3929 | + NETPLAN_AUTH_EAP_TLS, |
3930 | + NETPLAN_AUTH_EAP_PEAP, |
3931 | + NETPLAN_AUTH_EAP_TTLS, |
3932 | +} NetplanAuthEAPMethod; |
3933 | |
3934 | typedef struct missing_node { |
3935 | char* netdef_id; |
3936 | const yaml_node_t* node; |
3937 | -} missing_node; |
3938 | +} NetplanMissingNode; |
3939 | |
3940 | typedef struct authentication_settings { |
3941 | - auth_key_management_type key_management; |
3942 | - auth_eap_method eap_method; |
3943 | + NetplanAuthKeyManagementType key_management; |
3944 | + NetplanAuthEAPMethod eap_method; |
3945 | char* identity; |
3946 | char* anonymous_identity; |
3947 | char* password; |
3948 | @@ -154,7 +180,8 @@ typedef struct authentication_settings { |
3949 | char* client_certificate; |
3950 | char* client_key; |
3951 | char* client_key_password; |
3952 | -} authentication_settings; |
3953 | + char* phase2_auth; /* netplan-feature: auth-phase2 */ |
3954 | +} NetplanAuthenticationSettings; |
3955 | |
3956 | /* Fields below are valid for dhcp4 and dhcp6 unless otherwise noted. */ |
3957 | typedef struct dhcp_overrides { |
3958 | @@ -167,33 +194,39 @@ typedef struct dhcp_overrides { |
3959 | char* use_domains; /* netplan-feature: dhcp-use-domains */ |
3960 | char* hostname; |
3961 | guint metric; |
3962 | -} dhcp_overrides; |
3963 | +} NetplanDHCPOverrides; |
3964 | |
3965 | /** |
3966 | * Represent a configuration stanza |
3967 | */ |
3968 | -typedef struct net_definition { |
3969 | - netdef_type type; |
3970 | - netdef_backend backend; |
3971 | + |
3972 | +struct net_definition; |
3973 | + |
3974 | +typedef struct net_definition NetplanNetDefinition; |
3975 | + |
3976 | +struct net_definition { |
3977 | + NetplanDefType type; |
3978 | + NetplanBackend backend; |
3979 | char* id; |
3980 | /* only necessary for NetworkManager connection UUIDs in some cases */ |
3981 | uuid_t uuid; |
3982 | |
3983 | /* status options */ |
3984 | gboolean optional; |
3985 | - optional_addr optional_addresses; |
3986 | + NetplanOptionalAddressFlag optional_addresses; |
3987 | gboolean critical; |
3988 | |
3989 | /* addresses */ |
3990 | gboolean dhcp4; |
3991 | gboolean dhcp6; |
3992 | char* dhcp_identifier; |
3993 | - dhcp_overrides dhcp4_overrides; |
3994 | - dhcp_overrides dhcp6_overrides; |
3995 | - ra_mode accept_ra; |
3996 | + NetplanDHCPOverrides dhcp4_overrides; |
3997 | + NetplanDHCPOverrides dhcp6_overrides; |
3998 | + NetplanRAMode accept_ra; |
3999 | GArray* ip4_addresses; |
4000 | GArray* ip6_addresses; |
4001 | gboolean ip6_privacy; |
4002 | + guint ip6_addr_gen_mode; |
4003 | char* gateway4; |
4004 | char* gateway6; |
4005 | GArray* ip4_nameservers; |
4006 | @@ -212,7 +245,7 @@ typedef struct net_definition { |
4007 | |
4008 | /* vlan */ |
4009 | guint vlan_id; |
4010 | - struct net_definition* vlan_link; |
4011 | + NetplanNetDefinition* vlan_link; |
4012 | gboolean has_vlans; |
4013 | |
4014 | /* Configured custom MAC address */ |
4015 | @@ -233,9 +266,12 @@ typedef struct net_definition { |
4016 | } match; |
4017 | gboolean has_match; |
4018 | gboolean wake_on_lan; |
4019 | + NetplanWifiWowlanFlag wowlan; |
4020 | + gboolean emit_lldp; |
4021 | + |
4022 | |
4023 | - /* these properties are only valid for ND_WIFI */ |
4024 | - GHashTable* access_points; /* SSID → wifi_access_point* */ |
4025 | + /* these properties are only valid for NETPLAN_DEF_TYPE_WIFI */ |
4026 | + GHashTable* access_points; /* SSID → NetplanWifiAccessPoint* */ |
4027 | |
4028 | struct { |
4029 | char* mode; |
4030 | @@ -262,6 +298,19 @@ typedef struct net_definition { |
4031 | } bond_params; |
4032 | |
4033 | struct { |
4034 | + char* apn; |
4035 | + gboolean auto_config; |
4036 | + char* device_id; |
4037 | + char* network_id; |
4038 | + char* number; |
4039 | + char* password; |
4040 | + char* pin; |
4041 | + char* sim_id; |
4042 | + char* sim_operator_id; |
4043 | + char* username; |
4044 | + } modem_params; |
4045 | + |
4046 | + struct { |
4047 | char* ageing_time; |
4048 | guint priority; |
4049 | guint port_priority; |
4050 | @@ -274,36 +323,62 @@ typedef struct net_definition { |
4051 | gboolean custom_bridging; |
4052 | |
4053 | struct { |
4054 | - tunnel_mode mode; |
4055 | + NetplanTunnelMode mode; |
4056 | char *local_ip; |
4057 | char *remote_ip; |
4058 | char *input_key; |
4059 | char *output_key; |
4060 | } tunnel; |
4061 | |
4062 | - authentication_settings auth; |
4063 | + NetplanAuthenticationSettings auth; |
4064 | gboolean has_auth; |
4065 | -} net_definition; |
4066 | + |
4067 | + /* these properties are only valid for SR-IOV NICs */ |
4068 | + struct net_definition* sriov_link; |
4069 | + gboolean sriov_vlan_filter; |
4070 | + guint sriov_explicit_vf_count; |
4071 | + |
4072 | + union { |
4073 | + struct NetplanNMSettings { |
4074 | + char *name; |
4075 | + char *uuid; |
4076 | + char *stable_id; |
4077 | + char *device; |
4078 | + } nm; |
4079 | + struct NetplanNetworkdSettings { |
4080 | + char *unit; |
4081 | + } networkd; |
4082 | + } backend_settings; |
4083 | +}; |
4084 | + |
4085 | +typedef enum { |
4086 | + NETPLAN_WIFI_MODE_INFRASTRUCTURE, |
4087 | + NETPLAN_WIFI_MODE_ADHOC, |
4088 | + NETPLAN_WIFI_MODE_AP |
4089 | +} NetplanWifiMode; |
4090 | |
4091 | typedef enum { |
4092 | - WIFI_MODE_INFRASTRUCTURE, |
4093 | - WIFI_MODE_ADHOC, |
4094 | - WIFI_MODE_AP |
4095 | -} wifi_mode; |
4096 | + NETPLAN_WIFI_BAND_DEFAULT, |
4097 | + NETPLAN_WIFI_BAND_5, |
4098 | + NETPLAN_WIFI_BAND_24 |
4099 | +} NetplanWifiBand; |
4100 | |
4101 | typedef struct { |
4102 | - wifi_mode mode; |
4103 | + NetplanWifiMode mode; |
4104 | char* ssid; |
4105 | + NetplanWifiBand band; |
4106 | + char* bssid; |
4107 | + guint channel; |
4108 | |
4109 | - authentication_settings auth; |
4110 | + NetplanAuthenticationSettings auth; |
4111 | gboolean has_auth; |
4112 | -} wifi_access_point; |
4113 | +} NetplanWifiAccessPoint; |
4114 | |
4115 | -#define METRIC_UNSPEC G_MAXUINT |
4116 | -#define ROUTE_TABLE_UNSPEC 0 |
4117 | -#define IP_RULE_PRIO_UNSPEC G_MAXUINT |
4118 | -#define IP_RULE_FW_MARK_UNSPEC 0 |
4119 | -#define IP_RULE_TOS_UNSPEC G_MAXUINT |
4120 | +#define NETPLAN_METRIC_UNSPEC G_MAXUINT |
4121 | +#define NETPLAN_ROUTE_TABLE_UNSPEC 0 |
4122 | +#define NETPLAN_IP_RULE_PRIO_UNSPEC G_MAXUINT |
4123 | +#define NETPLAN_IP_RULE_FW_MARK_UNSPEC 0 |
4124 | +#define NETPLAN_IP_RULE_TOS_UNSPEC G_MAXUINT |
4125 | |
4126 | typedef struct { |
4127 | guint family; |
4128 | @@ -320,7 +395,7 @@ typedef struct { |
4129 | /* valid metrics are valid positive integers. |
4130 | * invalid metrics are represented by METRIC_UNSPEC */ |
4131 | guint metric; |
4132 | -} ip_route; |
4133 | +} NetplanIPRoute; |
4134 | |
4135 | typedef struct { |
4136 | guint family; |
4137 | @@ -335,7 +410,7 @@ typedef struct { |
4138 | guint fwmark; |
4139 | /* type-of-service: between 0 and 255 */ |
4140 | guint tos; |
4141 | -} ip_rule; |
4142 | +} NetplanIPRule; |
4143 | |
4144 | /* Written/updated by parse_yaml(): char* id → net_definition */ |
4145 | extern GHashTable* netdefs; |
4146 | @@ -345,7 +420,7 @@ extern GList* netdefs_ordered; |
4147 | * Functions |
4148 | ****************************************************/ |
4149 | |
4150 | -gboolean parse_yaml(const char* filename, GError** error); |
4151 | -gboolean finish_parse(GError** error); |
4152 | -netdef_backend get_global_backend(); |
4153 | -const char* tunnel_mode_to_string(tunnel_mode mode); |
4154 | +gboolean netplan_parse_yaml(const char* filename, GError** error); |
4155 | +GHashTable* netplan_finish_parse(GError** error); |
4156 | +NetplanBackend netplan_get_global_backend(); |
4157 | +const char* tunnel_mode_to_string(NetplanTunnelMode mode); |
4158 | diff --git a/src/util.c b/src/util.c |
4159 | index e3441d5..4b71ef1 100644 |
4160 | --- a/src/util.c |
4161 | +++ b/src/util.c |
4162 | @@ -86,3 +86,65 @@ unlink_glob(const char* rootdir, const char* _glob) |
4163 | for (size_t i = 0; i < gl.gl_pathc; ++i) |
4164 | unlink(gl.gl_pathv[i]); |
4165 | } |
4166 | + |
4167 | +/** |
4168 | + * Get the frequency of a given 2.4GHz WiFi channel |
4169 | + */ |
4170 | +int |
4171 | +wifi_get_freq24(int channel) |
4172 | +{ |
4173 | + if (channel < 1 || channel > 14) { |
4174 | + g_fprintf(stderr, "ERROR: invalid 2.4GHz WiFi channel: %d\n", channel); |
4175 | + exit(1); |
4176 | + } |
4177 | + |
4178 | + if (!wifi_frequency_24) { |
4179 | + wifi_frequency_24 = g_hash_table_new(g_direct_hash, g_direct_equal); |
4180 | + /* Initialize 2.4GHz frequencies, as of: |
4181 | + * https://en.wikipedia.org/wiki/List_of_WLAN_channels#2.4_GHz_(802.11b/g/n/ax) */ |
4182 | + for (unsigned i = 0; i < 13; i++) { |
4183 | + g_hash_table_insert(wifi_frequency_24, GINT_TO_POINTER(i+1), |
4184 | + GINT_TO_POINTER(2412+i*5)); |
4185 | + } |
4186 | + g_hash_table_insert(wifi_frequency_24, GINT_TO_POINTER(14), |
4187 | + GINT_TO_POINTER(2484)); |
4188 | + } |
4189 | + return GPOINTER_TO_INT(g_hash_table_lookup(wifi_frequency_24, |
4190 | + GINT_TO_POINTER(channel))); |
4191 | +} |
4192 | + |
4193 | +/** |
4194 | + * Get the frequency of a given 5GHz WiFi channel |
4195 | + */ |
4196 | +int |
4197 | +wifi_get_freq5(int channel) |
4198 | +{ |
4199 | + int channels[] = { 7, 8, 9, 11, 12, 16, 32, 34, 36, 38, 40, 42, 44, 46, 48, |
4200 | + 50, 52, 54, 56, 58, 60, 62, 64, 68, 96, 100, 102, 104, |
4201 | + 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, |
4202 | + 128, 132, 134, 136, 138, 140, 142, 144, 149, 151, 153, |
4203 | + 155, 157, 159, 161, 165, 169, 173 }; |
4204 | + gboolean found = FALSE; |
4205 | + for (unsigned i = 0; i < sizeof(channels) / sizeof(int); i++) { |
4206 | + if (channel == channels[i]) { |
4207 | + found = TRUE; |
4208 | + break; |
4209 | + } |
4210 | + } |
4211 | + if (!found) { |
4212 | + g_fprintf(stderr, "ERROR: invalid 5GHz WiFi channel: %d\n", channel); |
4213 | + exit(1); |
4214 | + } |
4215 | + if (!wifi_frequency_5) { |
4216 | + wifi_frequency_5 = g_hash_table_new(g_direct_hash, g_direct_equal); |
4217 | + /* Initialize 5GHz frequencies, as of: |
4218 | + * https://en.wikipedia.org/wiki/List_of_WLAN_channels#5.0_GHz_(802.11j)_WLAN |
4219 | + * Skipping channels 183-196. They are valid only in Japan with registration needed */ |
4220 | + for (unsigned i = 0; i < sizeof(channels) / sizeof(int); i++) { |
4221 | + g_hash_table_insert(wifi_frequency_5, GINT_TO_POINTER(channels[i]), |
4222 | + GINT_TO_POINTER(5000+channels[i]*5)); |
4223 | + } |
4224 | + } |
4225 | + return GPOINTER_TO_INT(g_hash_table_lookup(wifi_frequency_5, |
4226 | + GINT_TO_POINTER(channel))); |
4227 | +} |
4228 | diff --git a/src/util.h b/src/util.h |
4229 | index 4e85a98..4ed1a60 100644 |
4230 | --- a/src/util.h |
4231 | +++ b/src/util.h |
4232 | @@ -17,6 +17,12 @@ |
4233 | |
4234 | #pragma once |
4235 | |
4236 | +GHashTable* wifi_frequency_24; |
4237 | +GHashTable* wifi_frequency_5; |
4238 | + |
4239 | void safe_mkdir_p_dir(const char* file_path); |
4240 | void g_string_free_to_file(GString* s, const char* rootdir, const char* path, const char* suffix); |
4241 | void unlink_glob(const char* rootdir, const char* _glob); |
4242 | + |
4243 | +int wifi_get_freq24(int channel); |
4244 | +int wifi_get_freq5(int channel); |
4245 | diff --git a/src/validation.c b/src/validation.c |
4246 | index 7731be4..ad08988 100644 |
4247 | --- a/src/validation.c |
4248 | +++ b/src/validation.c |
4249 | @@ -19,6 +19,7 @@ |
4250 | #include <glib/gstdio.h> |
4251 | #include <gio/gio.h> |
4252 | #include <arpa/inet.h> |
4253 | +#include <regex.h> |
4254 | |
4255 | #include <yaml.h> |
4256 | |
4257 | @@ -60,9 +61,9 @@ is_ip6_address(const char* address) |
4258 | * Validation for grammar and backend rules. |
4259 | ************************************************/ |
4260 | static gboolean |
4261 | -validate_tunnel_grammar(net_definition* nd, yaml_node_t* node, GError** error) |
4262 | +validate_tunnel_grammar(NetplanNetDefinition* nd, yaml_node_t* node, GError** error) |
4263 | { |
4264 | - if (nd->tunnel.mode == TUNNEL_MODE_UNKNOWN) |
4265 | + if (nd->tunnel.mode == NETPLAN_TUNNEL_MODE_UNKNOWN) |
4266 | return yaml_error(node, error, "%s: missing 'mode' property for tunnel", nd->id); |
4267 | |
4268 | /* Validate local/remote IPs */ |
4269 | @@ -72,11 +73,11 @@ validate_tunnel_grammar(net_definition* nd, yaml_node_t* node, GError** error) |
4270 | return yaml_error(node, error, "%s: missing 'remote' property for tunnel", nd->id); |
4271 | |
4272 | switch(nd->tunnel.mode) { |
4273 | - case TUNNEL_MODE_IPIP6: |
4274 | - case TUNNEL_MODE_IP6IP6: |
4275 | - case TUNNEL_MODE_IP6GRE: |
4276 | - case TUNNEL_MODE_IP6GRETAP: |
4277 | - case TUNNEL_MODE_VTI6: |
4278 | + case NETPLAN_TUNNEL_MODE_IPIP6: |
4279 | + case NETPLAN_TUNNEL_MODE_IP6IP6: |
4280 | + case NETPLAN_TUNNEL_MODE_IP6GRE: |
4281 | + case NETPLAN_TUNNEL_MODE_IP6GRETAP: |
4282 | + case NETPLAN_TUNNEL_MODE_VTI6: |
4283 | if (!is_ip6_address(nd->tunnel.local_ip)) |
4284 | return yaml_error(node, error, "%s: 'local' must be a valid IPv6 address for this tunnel type", nd->id); |
4285 | if (!is_ip6_address(nd->tunnel.remote_ip)) |
4286 | @@ -95,21 +96,21 @@ validate_tunnel_grammar(net_definition* nd, yaml_node_t* node, GError** error) |
4287 | } |
4288 | |
4289 | static gboolean |
4290 | -validate_tunnel_backend_rules(net_definition* nd, yaml_node_t* node, GError** error) |
4291 | +validate_tunnel_backend_rules(NetplanNetDefinition* nd, yaml_node_t* node, GError** error) |
4292 | { |
4293 | /* Backend-specific validation rules for tunnels */ |
4294 | switch (nd->backend) { |
4295 | - case BACKEND_NETWORKD: |
4296 | + case NETPLAN_BACKEND_NETWORKD: |
4297 | switch (nd->tunnel.mode) { |
4298 | - case TUNNEL_MODE_VTI: |
4299 | - case TUNNEL_MODE_VTI6: |
4300 | + case NETPLAN_TUNNEL_MODE_VTI: |
4301 | + case NETPLAN_TUNNEL_MODE_VTI6: |
4302 | break; |
4303 | |
4304 | /* TODO: Remove this exception and fix ISATAP handling with the |
4305 | * networkd backend. |
4306 | * systemd-networkd has grown ISATAP support in 918049a. |
4307 | */ |
4308 | - case TUNNEL_MODE_ISATAP: |
4309 | + case NETPLAN_TUNNEL_MODE_ISATAP: |
4310 | return yaml_error(node, error, |
4311 | "%s: %s tunnel mode is not supported by networkd", |
4312 | nd->id, |
4313 | @@ -125,14 +126,14 @@ validate_tunnel_backend_rules(net_definition* nd, yaml_node_t* node, GError** er |
4314 | } |
4315 | break; |
4316 | |
4317 | - case BACKEND_NM: |
4318 | + case NETPLAN_BACKEND_NM: |
4319 | switch (nd->tunnel.mode) { |
4320 | - case TUNNEL_MODE_GRE: |
4321 | - case TUNNEL_MODE_IP6GRE: |
4322 | + case NETPLAN_TUNNEL_MODE_GRE: |
4323 | + case NETPLAN_TUNNEL_MODE_IP6GRE: |
4324 | break; |
4325 | |
4326 | - case TUNNEL_MODE_GRETAP: |
4327 | - case TUNNEL_MODE_IP6GRETAP: |
4328 | + case NETPLAN_TUNNEL_MODE_GRETAP: |
4329 | + case NETPLAN_TUNNEL_MODE_IP6GRETAP: |
4330 | return yaml_error(node, error, |
4331 | "%s: %s tunnel mode is not supported by NetworkManager", |
4332 | nd->id, |
4333 | @@ -158,12 +159,12 @@ validate_tunnel_backend_rules(net_definition* nd, yaml_node_t* node, GError** er |
4334 | } |
4335 | |
4336 | gboolean |
4337 | -validate_netdef_grammar(net_definition* nd, yaml_node_t* node, GError** error) |
4338 | +validate_netdef_grammar(NetplanNetDefinition* nd, yaml_node_t* node, GError** error) |
4339 | { |
4340 | int missing_id_count = g_hash_table_size(missing_id); |
4341 | gboolean valid = FALSE; |
4342 | |
4343 | - g_assert(nd->type != ND_NONE); |
4344 | + g_assert(nd->type != NETPLAN_DEF_TYPE_NONE); |
4345 | |
4346 | /* Skip all validation if we're missing some definition IDs (devices). |
4347 | * The ones we have yet to see may be necessary for validation to succeed, |
4348 | @@ -175,10 +176,10 @@ validate_netdef_grammar(net_definition* nd, yaml_node_t* node, GError** error) |
4349 | if (nd->set_name && !nd->has_match) |
4350 | return yaml_error(node, error, "%s: 'set-name:' requires 'match:' properties", nd->id); |
4351 | |
4352 | - if (nd->type == ND_WIFI && nd->access_points == NULL) |
4353 | + if (nd->type == NETPLAN_DEF_TYPE_WIFI && nd->access_points == NULL) |
4354 | return yaml_error(node, error, "%s: No access points defined", nd->id); |
4355 | |
4356 | - if (nd->type == ND_VLAN) { |
4357 | + if (nd->type == NETPLAN_DEF_TYPE_VLAN) { |
4358 | if (!nd->vlan_link) |
4359 | return yaml_error(node, error, "%s: missing 'link' property", nd->id); |
4360 | nd->vlan_link->has_vlans = TRUE; |
4361 | @@ -188,7 +189,7 @@ validate_netdef_grammar(net_definition* nd, yaml_node_t* node, GError** error) |
4362 | return yaml_error(node, error, "%s: invalid id '%u' (allowed values are 0 to 4094)", nd->id, nd->vlan_id); |
4363 | } |
4364 | |
4365 | - if (nd->type == ND_TUNNEL) { |
4366 | + if (nd->type == NETPLAN_DEF_TYPE_TUNNEL) { |
4367 | valid = validate_tunnel_grammar(nd, node, error); |
4368 | if (!valid) |
4369 | goto netdef_grammar_error; |
4370 | @@ -201,15 +202,15 @@ netdef_grammar_error: |
4371 | } |
4372 | |
4373 | gboolean |
4374 | -validate_backend_rules(net_definition* nd, GError** error) |
4375 | +validate_backend_rules(NetplanNetDefinition* nd, GError** error) |
4376 | { |
4377 | gboolean valid = FALSE; |
4378 | /* Set a dummy, NULL yaml_node_t for error reporting */ |
4379 | yaml_node_t* node = NULL; |
4380 | |
4381 | - g_assert(nd->type != ND_NONE); |
4382 | + g_assert(nd->type != NETPLAN_DEF_TYPE_NONE); |
4383 | |
4384 | - if (nd->type == ND_TUNNEL) { |
4385 | + if (nd->type == NETPLAN_DEF_TYPE_TUNNEL) { |
4386 | valid = validate_tunnel_backend_rules(nd, node, error); |
4387 | if (!valid) |
4388 | goto backend_rules_error; |
4389 | diff --git a/src/validation.h b/src/validation.h |
4390 | index a30305f..0383a33 100644 |
4391 | --- a/src/validation.h |
4392 | +++ b/src/validation.h |
4393 | @@ -24,7 +24,7 @@ gboolean is_ip4_address(const char* address); |
4394 | gboolean is_ip6_address(const char* address); |
4395 | |
4396 | gboolean |
4397 | -validate_netdef_grammar(net_definition* nd, yaml_node_t* node, GError** error); |
4398 | +validate_netdef_grammar(NetplanNetDefinition* nd, yaml_node_t* node, GError** error); |
4399 | |
4400 | gboolean |
4401 | -validate_backend_rules(net_definition* nd, GError** error); |
4402 | +validate_backend_rules(NetplanNetDefinition* nd, GError** error); |
4403 | diff --git a/tests/cli.py b/tests/cli.py |
4404 | index 6eb2a85..21c8a3b 100755 |
4405 | --- a/tests/cli.py |
4406 | +++ b/tests/cli.py |
4407 | @@ -33,6 +33,11 @@ if shutil.which('python3-coverage'): |
4408 | |
4409 | # Make sure we can import our development netplan. |
4410 | os.environ.update({'PYTHONPATH': '.'}) |
4411 | +os.environ.update({'LD_LIBRARY_PATH': '.:{}'.format(os.environ.get('LD_LIBRARY_PATH'))}) |
4412 | + |
4413 | + |
4414 | +def _load_yaml(text): |
4415 | + return yaml.load(text, Loader=yaml.SafeLoader) |
4416 | |
4417 | |
4418 | class TestArgs(unittest.TestCase): |
4419 | @@ -63,7 +68,9 @@ class TestGenerate(unittest.TestCase): |
4420 | self.workdir = tempfile.TemporaryDirectory() |
4421 | |
4422 | def test_no_config(self): |
4423 | - out = subprocess.check_output(exe_cli + ['generate', '--root-dir', self.workdir.name]) |
4424 | + p = subprocess.Popen(exe_cli + ['generate', '--root-dir', self.workdir.name], stdout=subprocess.PIPE, |
4425 | + stderr=subprocess.PIPE) |
4426 | + (out, err) = p.communicate() |
4427 | self.assertEqual(out, b'') |
4428 | self.assertEqual(os.listdir(self.workdir.name), []) |
4429 | |
4430 | @@ -145,6 +152,7 @@ class TestGenerate(unittest.TestCase): |
4431 | |
4432 | |
4433 | class TestIfupdownMigrate(unittest.TestCase): |
4434 | + |
4435 | def setUp(self): |
4436 | self.workdir = tempfile.TemporaryDirectory() |
4437 | self.ifaces_path = os.path.join(self.workdir.name, 'etc/network/interfaces') |
4438 | @@ -203,20 +211,20 @@ source-directory /etc/network/interfaces.d''')[0] |
4439 | |
4440 | def test_dhcp4(self): |
4441 | out = self.do_test('auto en1\niface en1 inet dhcp')[0] |
4442 | - self.assertEqual(yaml.load(out), {'network': { |
4443 | + self.assertEqual(_load_yaml(out), {'network': { |
4444 | 'version': 2, |
4445 | 'ethernets': {'en1': {'dhcp4': True}}}}, out.decode()) |
4446 | |
4447 | def test_dhcp6(self): |
4448 | out = self.do_test('auto en1\niface en1 inet6 dhcp')[0] |
4449 | - self.assertEqual(yaml.load(out), {'network': { |
4450 | + self.assertEqual(_load_yaml(out), {'network': { |
4451 | 'version': 2, |
4452 | 'ethernets': {'en1': {'dhcp6': True}}}}, out.decode()) |
4453 | |
4454 | def test_dhcp4_and_6(self): |
4455 | out = self.do_test('auto lo\niface lo inet loopback\n\n' |
4456 | 'auto en1\niface en1 inet dhcp\niface en1 inet6 dhcp')[0] |
4457 | - self.assertEqual(yaml.load(out), {'network': { |
4458 | + self.assertEqual(_load_yaml(out), {'network': { |
4459 | 'version': 2, |
4460 | 'ethernets': {'en1': {'dhcp4': True, 'dhcp6': True}}}}, out.decode()) |
4461 | |
4462 | @@ -224,7 +232,7 @@ source-directory /etc/network/interfaces.d''')[0] |
4463 | out = self.do_test('iface lo inet loopback\nauto lo\nsource-directory interfaces.d', |
4464 | dropins={'interfaces.d/std': 'auto en1\niface en1 inet dhcp', |
4465 | 'interfaces.d/std.bak': 'some_bogus dontreadme'})[0] |
4466 | - self.assertEqual(yaml.load(out), {'network': { |
4467 | + self.assertEqual(_load_yaml(out), {'network': { |
4468 | 'version': 2, |
4469 | 'ethernets': {'en1': {'dhcp4': True}}}}, out.decode()) |
4470 | |
4471 | @@ -232,7 +240,7 @@ source-directory /etc/network/interfaces.d''')[0] |
4472 | out = self.do_test('iface lo inet loopback\nauto lo\nsource-directory /etc/network/defs/my', |
4473 | dropins={'defs/my/std': 'auto en1\niface en1 inet dhcp', |
4474 | 'defs/my/std.bak': 'some_bogus dontreadme'})[0] |
4475 | - self.assertEqual(yaml.load(out), {'network': { |
4476 | + self.assertEqual(_load_yaml(out), {'network': { |
4477 | 'version': 2, |
4478 | 'ethernets': {'en1': {'dhcp4': True}}}}, out.decode()) |
4479 | |
4480 | @@ -240,7 +248,7 @@ source-directory /etc/network/interfaces.d''')[0] |
4481 | out = self.do_test('iface lo inet loopback\nauto lo\nsource interfaces.d/*.cfg', |
4482 | dropins={'interfaces.d/std.cfg': 'auto en1\niface en1 inet dhcp', |
4483 | 'interfaces.d/std.cfgold': 'some_bogus dontreadme'})[0] |
4484 | - self.assertEqual(yaml.load(out), {'network': { |
4485 | + self.assertEqual(_load_yaml(out), {'network': { |
4486 | 'version': 2, |
4487 | 'ethernets': {'en1': {'dhcp4': True}}}}, out.decode()) |
4488 | |
4489 | @@ -248,21 +256,21 @@ source-directory /etc/network/interfaces.d''')[0] |
4490 | out = self.do_test('iface lo inet loopback\nauto lo\nsource /etc/network/*.cfg', |
4491 | dropins={'std.cfg': 'auto en1\niface en1 inet dhcp', |
4492 | 'std.cfgold': 'some_bogus dontreadme'})[0] |
4493 | - self.assertEqual(yaml.load(out), {'network': { |
4494 | + self.assertEqual(_load_yaml(out), {'network': { |
4495 | 'version': 2, |
4496 | 'ethernets': {'en1': {'dhcp4': True}}}}, out.decode()) |
4497 | |
4498 | def test_allow(self): |
4499 | out = self.do_test('allow-hotplug en1\niface en1 inet dhcp\n' |
4500 | 'allow-auto en2\niface en2 inet dhcp')[0] |
4501 | - self.assertEqual(yaml.load(out), {'network': { |
4502 | + self.assertEqual(_load_yaml(out), {'network': { |
4503 | 'version': 2, |
4504 | 'ethernets': {'en1': {'dhcp4': True}, |
4505 | 'en2': {'dhcp4': True}}}}, out.decode()) |
4506 | |
4507 | def test_no_scripts(self): |
4508 | out = self.do_test('auto en1\niface en1 inet dhcp\nno-scripts en1')[0] |
4509 | - self.assertEqual(yaml.load(out), {'network': { |
4510 | + self.assertEqual(_load_yaml(out), {'network': { |
4511 | 'version': 2, |
4512 | 'ethernets': {'en1': {'dhcp4': True}}}}, out.decode()) |
4513 | |
4514 | @@ -276,7 +284,7 @@ source-directory /etc/network/interfaces.d''')[0] |
4515 | def test_write_file_haveconfig(self): |
4516 | (out, err) = self.do_test('auto en1\niface en1 inet dhcp', dry_run=False) |
4517 | with open(self.converted_path) as f: |
4518 | - config = yaml.load(f) |
4519 | + config = _load_yaml(f) |
4520 | self.assertEqual(config, {'network': { |
4521 | 'version': 2, |
4522 | 'ethernets': {'en1': {'dhcp4': True}}}}) |
4523 | @@ -302,13 +310,13 @@ source-directory /etc/network/interfaces.d''')[0] |
4524 | |
4525 | def test_static_ipv4_prefix(self): |
4526 | out = self.do_test('auto en1\niface en1 inet static\naddress 1.2.3.4/8', dry_run=True)[0] |
4527 | - self.assertEqual(yaml.load(out), {'network': { |
4528 | + self.assertEqual(_load_yaml(out), {'network': { |
4529 | 'version': 2, |
4530 | 'ethernets': {'en1': {'addresses': ["1.2.3.4/8"]}}}}, out.decode()) |
4531 | |
4532 | def test_static_ipv4_netmask(self): |
4533 | out = self.do_test('auto en1\niface en1 inet static\naddress 1.2.3.4\nnetmask 255.0.0.0', dry_run=True)[0] |
4534 | - self.assertEqual(yaml.load(out), {'network': { |
4535 | + self.assertEqual(_load_yaml(out), {'network': { |
4536 | 'version': 2, |
4537 | 'ethernets': {'en1': {'addresses': ["1.2.3.4/8"]}}}}, out.decode()) |
4538 | |
4539 | @@ -349,14 +357,14 @@ source-directory /etc/network/interfaces.d''')[0] |
4540 | |
4541 | def test_static_ipv6_prefix(self): |
4542 | out = self.do_test('auto en1\niface en1 inet6 static\naddress fc00:0123:4567:89ab:cdef::1234/64', dry_run=True)[0] |
4543 | - self.assertEqual(yaml.load(out), {'network': { |
4544 | + self.assertEqual(_load_yaml(out), {'network': { |
4545 | 'version': 2, |
4546 | 'ethernets': {'en1': {'addresses': ["fc00:123:4567:89ab:cdef::1234/64"]}}}}, out.decode()) |
4547 | |
4548 | def test_static_ipv6_netmask(self): |
4549 | out = self.do_test('auto en1\niface en1 inet6 static\n' |
4550 | 'address fc00:0123:4567:89ab:cdef::1234\nnetmask 64', dry_run=True)[0] |
4551 | - self.assertEqual(yaml.load(out), {'network': { |
4552 | + self.assertEqual(_load_yaml(out), {'network': { |
4553 | 'version': 2, |
4554 | 'ethernets': {'en1': {'addresses': ["fc00:123:4567:89ab:cdef::1234/64"]}}}}, out.decode()) |
4555 | |
4556 | @@ -404,7 +412,7 @@ source-directory /etc/network/interfaces.d''')[0] |
4557 | def test_static_ipv6_accept_ra_0(self): |
4558 | out = self.do_test('auto en1\niface en1 inet6 static\n' |
4559 | 'address fc00:0123:4567:89ab:cdef::1234/64\naccept_ra 0', dry_run=True)[0] |
4560 | - self.assertEqual(yaml.load(out), {'network': { |
4561 | + self.assertEqual(_load_yaml(out), {'network': { |
4562 | 'version': 2, |
4563 | 'ethernets': {'en1': {'addresses': ["fc00:123:4567:89ab:cdef::1234/64"], |
4564 | 'accept_ra': False}}}}, out.decode()) |
4565 | @@ -412,7 +420,7 @@ source-directory /etc/network/interfaces.d''')[0] |
4566 | def test_static_ipv6_accept_ra_1(self): |
4567 | out = self.do_test('auto en1\niface en1 inet6 static\n' |
4568 | 'address fc00:0123:4567:89ab:cdef::1234/64\naccept_ra 1', dry_run=True)[0] |
4569 | - self.assertEqual(yaml.load(out), {'network': { |
4570 | + self.assertEqual(_load_yaml(out), {'network': { |
4571 | 'version': 2, |
4572 | 'ethernets': {'en1': {'addresses': ["fc00:123:4567:89ab:cdef::1234/64"], |
4573 | 'accept_ra': True}}}}, out.decode()) |
4574 | @@ -438,7 +446,7 @@ iface en1 inet static |
4575 | iface en1 inet6 static |
4576 | address fc00:0123:4567:89ab:cdef::1234/64 |
4577 | gateway fc00:0123:4567:89ab::1""", dry_run=True)[0] |
4578 | - self.assertEqual(yaml.load(out), {'network': { |
4579 | + self.assertEqual(_load_yaml(out), {'network': { |
4580 | 'version': 2, |
4581 | 'ethernets': {'en1': |
4582 | {'addresses': ["1.2.3.4/8", "fc00:123:4567:89ab:cdef::1234/64"], |
4583 | @@ -455,7 +463,7 @@ iface en1 inet static |
4584 | iface en1 inet6 static |
4585 | address fc00:0123:4567:89ab:cdef::1234/64 |
4586 | dns-nameservers fc00:0123:4567:89ab:1::1 fc00:0123:4567:89ab:2::1""", dry_run=True)[0] |
4587 | - self.assertEqual(yaml.load(out), {'network': { |
4588 | + self.assertEqual(_load_yaml(out), {'network': { |
4589 | 'version': 2, |
4590 | 'ethernets': {'en1': |
4591 | {'addresses': ["1.2.3.4/8", "fc00:123:4567:89ab:cdef::1234/64"], |
4592 | @@ -467,7 +475,7 @@ iface en1 inet6 static |
4593 | |
4594 | def test_static_dns2(self): |
4595 | out = self.do_test('auto en1\niface en1 inet static\naddress 1.2.3.4/8\ndns-search foo foo.bar', dry_run=True)[0] |
4596 | - self.assertEqual(yaml.load(out), {'network': { |
4597 | + self.assertEqual(_load_yaml(out), {'network': { |
4598 | 'version': 2, |
4599 | 'ethernets': {'en1': {'addresses': ["1.2.3.4/8"], |
4600 | 'nameservers': { |
4601 | @@ -476,7 +484,7 @@ iface en1 inet6 static |
4602 | |
4603 | def test_static_mtu(self): |
4604 | out = self.do_test('auto en1\niface en1 inet static\naddress 1.2.3.4/8\nmtu 1280', dry_run=True)[0] |
4605 | - self.assertEqual(yaml.load(out), {'network': { |
4606 | + self.assertEqual(_load_yaml(out), {'network': { |
4607 | 'version': 2, |
4608 | 'ethernets': {'en1': {'addresses': ["1.2.3.4/8"], |
4609 | 'mtu': 1280}}}}, out.decode()) |
4610 | @@ -494,7 +502,7 @@ iface en1 inet6 static |
4611 | |
4612 | def test_static_hwaddress(self): |
4613 | out = self.do_test('auto en1\niface en1 inet static\naddress 1.2.3.4/8\nhwaddress 52:54:00:6b:3c:59', dry_run=True)[0] |
4614 | - self.assertEqual(yaml.load(out), {'network': { |
4615 | + self.assertEqual(_load_yaml(out), {'network': { |
4616 | 'version': 2, |
4617 | 'ethernets': {'en1': {'addresses': ["1.2.3.4/8"], |
4618 | 'macaddress': '52:54:00:6b:3c:59'}}}}, out.decode()) |
4619 | diff --git a/tests/generator/base.py b/tests/generator/base.py |
4620 | index e5eb18a..2cdbcfd 100644 |
4621 | --- a/tests/generator/base.py |
4622 | +++ b/tests/generator/base.py |
4623 | @@ -29,6 +29,9 @@ import unittest |
4624 | exe_generate = os.path.join(os.path.dirname(os.path.dirname( |
4625 | os.path.dirname(os.path.abspath(__file__)))), 'generate') |
4626 | |
4627 | +# make sure we point to libnetplan properly. |
4628 | +os.environ.update({'LD_LIBRARY_PATH': '.:{}'.format(os.environ.get('LD_LIBRARY_PATH'))}) |
4629 | + |
4630 | # make sure we fail on criticals |
4631 | os.environ['G_DEBUG'] = 'fatal-criticals' |
4632 | |
4633 | diff --git a/tests/generator/test_auth.py b/tests/generator/test_auth.py |
4634 | index 89e9f30..f35f3f8 100644 |
4635 | --- a/tests/generator/test_auth.py |
4636 | +++ b/tests/generator/test_auth.py |
4637 | @@ -31,11 +31,17 @@ class TestNetworkd(TestBase): |
4638 | wl0: |
4639 | access-points: |
4640 | "Joe's Home": |
4641 | - password: "s3kr1t" |
4642 | + password: "s0s3kr1t" |
4643 | "Luke's Home": |
4644 | auth: |
4645 | key-management: psk |
4646 | password: "4lsos3kr1t" |
4647 | + "BobsHome": |
4648 | + password: "e03ce667c87bc81ca968d9120ca37f89eb09aec3c55b80386e5d772efd6b926e" |
4649 | + "BillsHome": |
4650 | + auth: |
4651 | + key-management: psk |
4652 | + password: "db3b0acf5653aeaddd5fe034fb9f07175b2864f847b005aaa2f09182d9411b04" |
4653 | workplace: |
4654 | auth: |
4655 | key-management: eap |
4656 | @@ -102,6 +108,20 @@ network={ |
4657 | ''', new_config) |
4658 | self.assertIn(''' |
4659 | network={ |
4660 | + ssid="BobsHome" |
4661 | + key_mgmt=WPA-PSK |
4662 | + psk=e03ce667c87bc81ca968d9120ca37f89eb09aec3c55b80386e5d772efd6b926e |
4663 | +} |
4664 | +''', new_config) |
4665 | + self.assertIn(''' |
4666 | +network={ |
4667 | + ssid="BillsHome" |
4668 | + key_mgmt=WPA-PSK |
4669 | + psk=db3b0acf5653aeaddd5fe034fb9f07175b2864f847b005aaa2f09182d9411b04 |
4670 | +} |
4671 | +''', new_config) |
4672 | + self.assertIn(''' |
4673 | +network={ |
4674 | ssid="workplace2" |
4675 | key_mgmt=WPA-EAP |
4676 | eap=PEAP |
4677 | @@ -153,12 +173,14 @@ network={ |
4678 | network={ |
4679 | ssid="Joe's Home" |
4680 | key_mgmt=WPA-PSK |
4681 | - psk="s3kr1t" |
4682 | + psk="s0s3kr1t" |
4683 | } |
4684 | ''', new_config) |
4685 | self.assertEqual(stat.S_IMODE(os.fstat(f.fileno()).st_mode), 0o600) |
4686 | + self.assertTrue(os.path.isfile(os.path.join( |
4687 | + self.workdir.name, 'run/systemd/system/netplan-wpa-wl0.service'))) |
4688 | self.assertTrue(os.path.islink(os.path.join( |
4689 | - self.workdir.name, 'run/systemd/system/systemd-networkd.service.wants/netplan-wpa@wl0.service'))) |
4690 | + self.workdir.name, 'run/systemd/system/systemd-networkd.service.wants/netplan-wpa-wl0.service'))) |
4691 | |
4692 | def test_auth_wired(self): |
4693 | self.generate('''network: |
4694 | @@ -174,6 +196,7 @@ network={ |
4695 | client-certificate: /etc/ssl/cust-crt.pem |
4696 | client-key: /etc/ssl/cust-key.pem |
4697 | client-key-password: "d3cryptPr1v4t3K3y" |
4698 | + phase2-auth: MSCHAPV2 |
4699 | dhcp4: yes |
4700 | ''') |
4701 | |
4702 | @@ -196,11 +219,14 @@ network={ |
4703 | client_cert="/etc/ssl/cust-crt.pem" |
4704 | private_key="/etc/ssl/cust-key.pem" |
4705 | private_key_passwd="d3cryptPr1v4t3K3y" |
4706 | + phase2="auth=MSCHAPV2" |
4707 | } |
4708 | ''') |
4709 | self.assertEqual(stat.S_IMODE(os.fstat(f.fileno()).st_mode), 0o600) |
4710 | + self.assertTrue(os.path.isfile(os.path.join( |
4711 | + self.workdir.name, 'run/systemd/system/netplan-wpa-eth0.service'))) |
4712 | self.assertTrue(os.path.islink(os.path.join( |
4713 | - self.workdir.name, 'run/systemd/system/systemd-networkd.service.wants/netplan-wpa@eth0.service'))) |
4714 | + self.workdir.name, 'run/systemd/system/systemd-networkd.service.wants/netplan-wpa-eth0.service'))) |
4715 | |
4716 | |
4717 | class TestNetworkManager(TestBase): |
4718 | @@ -213,7 +239,7 @@ class TestNetworkManager(TestBase): |
4719 | wl0: |
4720 | access-points: |
4721 | "Joe's Home": |
4722 | - password: "s3kr1t" |
4723 | + password: "s0s3kr1t" |
4724 | "Luke's Home": |
4725 | auth: |
4726 | key-management: psk |
4727 | @@ -249,6 +275,7 @@ class TestNetworkManager(TestBase): |
4728 | client-certificate: /etc/ssl/cust-crt.pem |
4729 | client-key: /etc/ssl/cust-key.pem |
4730 | client-key-password: "d3cryptPr1v4t3K3y" |
4731 | + phase2-auth: MSCHAPV2 |
4732 | opennet: |
4733 | auth: |
4734 | key-management: none |
4735 | @@ -279,7 +306,7 @@ mode=infrastructure |
4736 | |
4737 | [wifi-security] |
4738 | key-mgmt=wpa-psk |
4739 | -psk=s3kr1t |
4740 | +psk=s0s3kr1t |
4741 | ''', |
4742 | 'wl0-Luke%27s%20Home': '''[connection] |
4743 | id=netplan-wl0-Luke's Home |
4744 | @@ -413,6 +440,7 @@ ca-cert=/etc/ssl/cust-cacrt.pem |
4745 | client-cert=/etc/ssl/cust-crt.pem |
4746 | private-key=/etc/ssl/cust-key.pem |
4747 | private-key-password=d3cryptPr1v4t3K3y |
4748 | +phase2-auth=MSCHAPV2 |
4749 | ''', |
4750 | 'wl0-opennet': '''[connection] |
4751 | id=netplan-wl0-opennet |
4752 | @@ -516,3 +544,36 @@ class TestConfigErrors(TestBase): |
4753 | auth: |
4754 | method: bogus''', expect_fail=True) |
4755 | self.assertIn("unknown EAP method 'bogus'", err) |
4756 | + |
4757 | + def test_auth_networkd_wifi_psk_too_big(self): |
4758 | + err = self.generate('''network: |
4759 | + version: 2 |
4760 | + wifis: |
4761 | + wl0: |
4762 | + access-points: |
4763 | + "Joe's Home": |
4764 | + password: "LoremipsumdolorsitametconsecteturadipiscingelitCrastemporvelitnunc" |
4765 | + dhcp4: yes''', expect_fail=True) |
4766 | + self.assertIn("ASCII passphrase must be between 8 and 63 characters (inclusive)", err) |
4767 | + |
4768 | + def test_auth_networkd_wifi_psk_too_small(self): |
4769 | + err = self.generate('''network: |
4770 | + version: 2 |
4771 | + wifis: |
4772 | + wl0: |
4773 | + access-points: |
4774 | + "Joe's Home": |
4775 | + password: "p4ss" |
4776 | + dhcp4: yes''', expect_fail=True) |
4777 | + self.assertIn("ASCII passphrase must be between 8 and 63 characters (inclusive)", err) |
4778 | + |
4779 | + def test_auth_networkd_wifi_psk_64_non_hexdigit(self): |
4780 | + err = self.generate('''network: |
4781 | + version: 2 |
4782 | + wifis: |
4783 | + wl0: |
4784 | + access-points: |
4785 | + "Joe's Home": |
4786 | + password: "LoremipsumdolorsitametconsecteturadipiscingelitCrastemporvelitnu" |
4787 | + dhcp4: yes''', expect_fail=True) |
4788 | + self.assertIn("PSK length of 64 is only supported for hex-digit representation", err) |
4789 | diff --git a/tests/generator/test_common.py b/tests/generator/test_common.py |
4790 | index 8fb91bd..abbc368 100644 |
4791 | --- a/tests/generator/test_common.py |
4792 | +++ b/tests/generator/test_common.py |
4793 | @@ -104,13 +104,26 @@ ConfigureWithoutCarrier=yes |
4794 | 'bond0.network': '''[Match] |
4795 | Name=bond0 |
4796 | |
4797 | +[Link] |
4798 | +MTUBytes=9000 |
4799 | + |
4800 | [Network] |
4801 | LinkLocalAddressing=ipv6 |
4802 | ConfigureWithoutCarrier=yes |
4803 | VLAN=bond0.108 |
4804 | ''', |
4805 | 'eth1.link': '[Match]\nOriginalName=eth1\n\n[Link]\nWakeOnLan=off\nMTUBytes=9000\n', |
4806 | - 'eth1.network': '[Match]\nName=eth1\n\n[Network]\nLinkLocalAddressing=no\nIPv6MTUBytes=2000\nBond=bond0\n' |
4807 | + 'eth1.network': '''[Match] |
4808 | +Name=eth1 |
4809 | + |
4810 | +[Link] |
4811 | +MTUBytes=9000 |
4812 | + |
4813 | +[Network] |
4814 | +LinkLocalAddressing=no |
4815 | +IPv6MTUBytes=2000 |
4816 | +Bond=bond0 |
4817 | +''' |
4818 | }) |
4819 | self.assert_networkd_udev(None) |
4820 | |
4821 | @@ -283,7 +296,6 @@ UseMTU=true |
4822 | version: 2 |
4823 | ethernets: |
4824 | engreen: |
4825 | - dhcp4: yes |
4826 | critical: yes |
4827 | ''') |
4828 | |
4829 | @@ -291,13 +303,10 @@ UseMTU=true |
4830 | Name=engreen |
4831 | |
4832 | [Network] |
4833 | -DHCP=ipv4 |
4834 | LinkLocalAddressing=ipv6 |
4835 | |
4836 | [DHCP] |
4837 | CriticalConnection=true |
4838 | -RouteMetric=100 |
4839 | -UseMTU=true |
4840 | '''}) |
4841 | |
4842 | def test_dhcp_identifier_mac(self): |
4843 | @@ -715,6 +724,48 @@ method=auto |
4844 | method=auto |
4845 | '''}) |
4846 | |
4847 | + def test_ip6_addr_gen_mode(self): |
4848 | + self.generate('''network: |
4849 | + version: 2 |
4850 | + renderer: NetworkManager |
4851 | + ethernets: |
4852 | + engreen: |
4853 | + dhcp6: yes |
4854 | + ipv6-address-generation: stable-privacy |
4855 | + enblue: |
4856 | + dhcp6: yes |
4857 | + ipv6-address-generation: eui64''') |
4858 | + self.assert_nm({'engreen': '''[connection] |
4859 | +id=netplan-engreen |
4860 | +type=ethernet |
4861 | +interface-name=engreen |
4862 | + |
4863 | +[ethernet] |
4864 | +wake-on-lan=0 |
4865 | + |
4866 | +[ipv4] |
4867 | +method=link-local |
4868 | + |
4869 | +[ipv6] |
4870 | +method=auto |
4871 | +addr-gen-mode=1 |
4872 | +''', |
4873 | + 'enblue': '''[connection] |
4874 | +id=netplan-enblue |
4875 | +type=ethernet |
4876 | +interface-name=enblue |
4877 | + |
4878 | +[ethernet] |
4879 | +wake-on-lan=0 |
4880 | + |
4881 | +[ipv4] |
4882 | +method=link-local |
4883 | + |
4884 | +[ipv6] |
4885 | +method=auto |
4886 | +addr-gen-mode=0 |
4887 | +'''}) |
4888 | + |
4889 | def test_eth_manual_addresses(self): |
4890 | self.generate('''network: |
4891 | version: 2 |
4892 | diff --git a/tests/generator/test_errors.py b/tests/generator/test_errors.py |
4893 | index 5f3def8..afe487b 100644 |
4894 | --- a/tests/generator/test_errors.py |
4895 | +++ b/tests/generator/test_errors.py |
4896 | @@ -210,6 +210,39 @@ class TestConfigErrors(TestBase): |
4897 | mode: bogus''', expect_fail=True) |
4898 | self.assertIn("unknown wifi mode 'bogus'", err) |
4899 | |
4900 | + def test_wifi_ap_unknown_band(self): |
4901 | + err = self.generate('''network: |
4902 | + version: 2 |
4903 | + wifis: |
4904 | + wl0: |
4905 | + access-points: |
4906 | + workplace: |
4907 | + band: bogus''', expect_fail=True) |
4908 | + self.assertIn("unknown wifi band 'bogus'", err) |
4909 | + |
4910 | + def test_wifi_ap_invalid_freq24(self): |
4911 | + err = self.generate('''network: |
4912 | + version: 2 |
4913 | + renderer: NetworkManager |
4914 | + wifis: |
4915 | + wl0: |
4916 | + access-points: |
4917 | + workplace: |
4918 | + band: 2.4GHz |
4919 | + channel: 15''', expect_fail=True) |
4920 | + self.assertIn("ERROR: invalid 2.4GHz WiFi channel: 15", err) |
4921 | + |
4922 | + def test_wifi_ap_invalid_freq5(self): |
4923 | + err = self.generate('''network: |
4924 | + version: 2 |
4925 | + wifis: |
4926 | + wl0: |
4927 | + access-points: |
4928 | + workplace: |
4929 | + band: 5GHz |
4930 | + channel: 14''', expect_fail=True) |
4931 | + self.assertIn("ERROR: invalid 5GHz WiFi channel: 14", err) |
4932 | + |
4933 | def test_invalid_ipv4_address(self): |
4934 | err = self.generate('''network: |
4935 | version: 2 |
4936 | @@ -288,6 +321,23 @@ class TestConfigErrors(TestBase): |
4937 | - 2001::1/''', expect_fail=True) |
4938 | self.assertIn("invalid prefix length in address '2001::1/'", err) |
4939 | |
4940 | + def test_invalid_addr_gen_mode(self): |
4941 | + err = self.generate('''network: |
4942 | + version: 2 |
4943 | + renderer: NetworkManager |
4944 | + ethernets: |
4945 | + engreen: |
4946 | + ipv6-address-generation: 0''', expect_fail=True) |
4947 | + self.assertIn("unknown ipv6-address-generation '0'", err) |
4948 | + |
4949 | + def test_addr_gen_mode_not_supported(self): |
4950 | + err = self.generate('''network: |
4951 | + version: 2 |
4952 | + ethernets: |
4953 | + engreen: |
4954 | + ipv6-address-generation: eui64''', expect_fail=True) |
4955 | + self.assertIn("ERROR: engreen: ipv6-address-generation is not supported by networkd", err) |
4956 | + |
4957 | def test_invalid_gateway4(self): |
4958 | for a in ['300.400.1.1', '1.2.3', '192.168.14.1/24']: |
4959 | err = self.generate('''network: |
4960 | @@ -363,6 +413,14 @@ class TestConfigErrors(TestBase): |
4961 | ena: {id: 1, link: en1}''', expect_fail=True) |
4962 | self.assertIn("ena: interface 'en1' is not defined", err) |
4963 | |
4964 | + def test_vlan_unknown_renderer(self): |
4965 | + err = self.generate('''network: |
4966 | + version: 2 |
4967 | + ethernets: {en1: {}} |
4968 | + vlans: |
4969 | + ena: {id: 1, link: en1, renderer: foo}''', expect_fail=True) |
4970 | + self.assertIn("unknown renderer 'foo'", err) |
4971 | + |
4972 | def test_device_bad_route_to(self): |
4973 | self.generate('''network: |
4974 | version: 2 |
4975 | diff --git a/tests/generator/test_ethernets.py b/tests/generator/test_ethernets.py |
4976 | index 22e6d1e..7a451f7 100644 |
4977 | --- a/tests/generator/test_ethernets.py |
4978 | +++ b/tests/generator/test_ethernets.py |
4979 | @@ -46,6 +46,22 @@ unmanaged-devices+=interface-name:eth0,''') |
4980 | # should not allow NM to manage everything |
4981 | self.assertFalse(os.path.exists(self.nm_enable_all_conf)) |
4982 | |
4983 | + def test_eth_lldp(self): |
4984 | + self.generate('''network: |
4985 | + version: 2 |
4986 | + ethernets: |
4987 | + eth0: |
4988 | + dhcp4: n |
4989 | + emit-lldp: true''') |
4990 | + |
4991 | + self.assert_networkd({'eth0.network': '''[Match] |
4992 | +Name=eth0 |
4993 | + |
4994 | +[Network] |
4995 | +EmitLLDP=true |
4996 | +LinkLocalAddressing=ipv6 |
4997 | +'''}) |
4998 | + |
4999 | def test_eth_mtu(self): |
5000 | self.generate('''network: |
The diff has been truncated for viewing.