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