Compare commits
403 commits
ifupdown-n
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e978d1a42c | ||
|
|
80074c997f | ||
|
|
0e99af7669 | ||
|
|
b75e509f3d | ||
|
|
d83c8259e6 | ||
|
|
2477e7266c | ||
|
|
97b1a11be0 | ||
|
|
941d7c51d7 | ||
|
|
7a46b61996 | ||
|
|
571786ae91 | ||
|
|
dd3a99cfa8 | ||
|
|
67fc80fc78 | ||
|
|
65e5e07c5f | ||
|
|
0547924ee8 | ||
|
|
4033f6374f | ||
|
|
b25448f42f | ||
|
|
96fa8ccbf9 | ||
|
|
108c88014d | ||
|
|
9c00111932 | ||
|
|
12ffc3de12 | ||
|
|
34753136b8 | ||
|
|
559b4ad942 | ||
|
|
ed9aae85ed | ||
|
|
73d9788fab | ||
|
|
2b358fafc6 | ||
|
|
9467f85067 | ||
|
|
6175961880 | ||
|
|
c8a05a742b | ||
|
|
d4907af84f | ||
|
|
98241f4781 | ||
|
|
aee2d45e18 | ||
|
|
5860882ffb | ||
|
|
0755f7c32d | ||
|
|
bd319a9166 | ||
|
|
58b1cf1021 | ||
|
|
02bc14da19 | ||
|
|
279d3818b0 | ||
|
|
f3f8164ef1 | ||
|
|
667943f46c | ||
|
|
5b7f5b712b | ||
|
|
381c0ed1a5 | ||
|
|
bec5fcefce | ||
|
|
258d397d84 | ||
|
|
cea9840651 | ||
|
|
e88a6b7e10 | ||
|
|
9faa988326 | ||
|
|
5f9ba7e246 | ||
|
|
cd98102e62 | ||
|
|
98b23370e8 | ||
|
|
876a7700d7 | ||
|
|
2cec4ed05c | ||
|
|
e4fa275067 | ||
|
|
4c64b5138b | ||
|
|
1ee485666f | ||
|
|
7ef6be6d98 | ||
|
|
606e98d7bd | ||
|
|
ffcf1976b8 | ||
|
|
1c2fddfbaa | ||
|
|
71bc4b3dc9 | ||
|
|
b9d6c190e4 | ||
|
|
31bc5c3b10 | ||
|
|
f34ad12751 | ||
|
|
27c10c57d1 | ||
|
|
d1286e57f9 | ||
|
|
65aa268e9d | ||
|
|
1f7fe26dd9 | ||
|
|
3734aaecbd | ||
|
|
8a8f56dda8 | ||
|
|
bed0b67583 | ||
|
|
383ae31372 | ||
|
|
d7cc2a9917 | ||
|
|
93c8827205 | ||
|
|
589a1f3023 | ||
|
|
4e3a4c6cb8 | ||
|
|
eeb40937fb | ||
|
|
b2f5a62c35 | ||
|
|
f77d3558f7 | ||
|
|
cef4fafdb9 | ||
|
|
3d47b34d7a | ||
|
|
b10094eae7 | ||
|
|
c4d9d6fd06 | ||
|
|
0dd7756df2 | ||
|
|
43159fec82 | ||
|
|
259851a829 | ||
|
|
e1fb4c6087 | ||
|
|
ff8e5d392c | ||
|
|
b21cb37df0 | ||
|
|
aada42795c | ||
|
|
6730db5468 | ||
|
|
7911944633 | ||
|
|
46bb0565fa | ||
|
|
9715b41c28 | ||
|
|
89b96a5108 | ||
|
|
545c3870ab | ||
|
|
d2a75c7bb4 | ||
|
|
dd8064142c | ||
|
|
3bf406bf92 | ||
|
|
c5520f95dd | ||
|
|
7ca5305063 | ||
|
|
8097d5015f | ||
|
|
dbfebbff87 | ||
|
|
5010dce3d5 | ||
|
|
95f0ea4895 | ||
|
|
2ec3a39c89 | ||
|
|
cfb43e9573 | ||
|
|
fe1664d311 | ||
|
|
ec6077f26f | ||
|
|
2a9ca329ff | ||
|
|
f6ad65d99e | ||
|
|
d250ab213c | ||
|
|
f5fc3a3c1a | ||
|
|
748a226786 | ||
|
|
c8dad76fe1 | ||
|
|
c7eeef27a4 | ||
|
|
52f739c943 | ||
|
|
71d832cceb | ||
|
|
632af7b716 | ||
|
|
af25cedf33 | ||
|
|
c292297396 | ||
|
|
5667b6adec | ||
|
|
2d2e73b8ac | ||
|
|
068f464e4c | ||
|
|
0050995b64 | ||
|
|
20d9e3fe91 | ||
|
|
b76981e832 | ||
|
|
8cae485ca7 | ||
|
|
6cadc44183 | ||
|
|
da751ce14d | ||
|
|
dcbb3be15b | ||
|
|
19a5a671eb | ||
|
|
90453f1412 | ||
|
|
b4f87cbd1e | ||
|
|
2a8a72eee7 | ||
|
|
eb9bebebc6 | ||
|
|
61097b1db2 | ||
|
|
b09d622cfc | ||
|
|
dae7d59864 | ||
|
|
4f7063ba0f | ||
|
|
817262fa33 | ||
|
|
b201f351ec | ||
|
|
9bcf914250 | ||
|
|
c810cd5817 | ||
|
|
e5d9ee25fc | ||
|
|
02a74985ab | ||
|
|
fb1d3181fe | ||
|
|
ab7b1f5d24 | ||
|
|
480fc5eecb | ||
|
|
d86297f29c | ||
|
|
56beefdd28 | ||
|
|
a5761afd70 | ||
|
|
05a3b1539b | ||
|
|
03528b01ad | ||
|
|
3d743f512f | ||
|
|
6c5d856ac4 | ||
|
|
36eb6e3377 | ||
|
|
e7ee26ac19 | ||
|
|
80a590ca33 | ||
|
|
d96f579d7f | ||
|
|
509b75bc73 | ||
|
|
3e6129907c | ||
|
|
e6de8465de | ||
|
|
47f74997a7 | ||
|
|
4aa2749737 | ||
|
|
a210cf6a66 | ||
|
|
aec7dad1c1 | ||
|
|
086eca2b4e | ||
|
|
f6fe06298f | ||
|
|
ee5e8b5702 | ||
|
|
5035d2e160 | ||
|
|
8d4c7461af | ||
|
|
0df3e03b68 | ||
|
|
dcb6ef97ef | ||
|
|
3bcfe91e84 | ||
|
|
d76c2df460 | ||
|
|
ef3be06b38 | ||
|
|
1668d17c6b | ||
|
|
fcea23dbcd | ||
|
|
311ad74792 | ||
|
|
e300867d26 | ||
|
|
89d84ec475 | ||
|
|
3b7181cf28 | ||
|
|
24bfcc1737 | ||
|
|
de207a5950 | ||
|
|
365461a6f6 | ||
|
|
a72d87df0b | ||
|
|
02324bebd5 | ||
|
|
17a410b87c | ||
|
|
98ba7f46cf | ||
|
|
68c51a79e7 | ||
|
|
f707c5c1ef | ||
|
|
6423a284b8 | ||
|
|
172daa16a0 | ||
|
|
a1828c688b | ||
|
|
2d32b1577c | ||
|
|
4c354ebf35 | ||
|
|
959617df88 | ||
|
|
0cade539f8 | ||
|
|
122a54377d | ||
|
|
b2e657cdf0 | ||
|
|
175f002b3e | ||
|
|
953b2274f7 | ||
|
|
5db2f29891 | ||
|
|
a67d518ea9 | ||
|
|
5b6cb5a128 | ||
|
|
13a8daf96e | ||
|
|
27a7201b45 | ||
|
|
332ea7c7d3 | ||
|
|
59290415a0 | ||
|
|
5d6c7732ed | ||
|
|
5302bee850 | ||
|
|
1a2298a759 | ||
|
|
99b0d67b8e | ||
|
|
4a8230f916 | ||
|
|
5557804af9 | ||
|
|
44be0c0721 | ||
|
|
8a58c0ae6d | ||
|
|
6f588a01d5 | ||
|
|
df6835bd62 | ||
|
|
6dc43a2bb4 | ||
|
|
9832865539 | ||
|
|
63a5503185 | ||
|
|
87fa1760be | ||
|
|
584f0634ed | ||
|
|
596dd8165b | ||
|
|
05711db6ce | ||
|
|
adf0f9dd46 | ||
|
|
3d1d384a6b | ||
|
|
48c87e34c1 | ||
|
|
37299e312f | ||
|
|
a66e8465d1 | ||
|
|
9ee3a874d4 | ||
|
|
67163c6561 | ||
|
|
cc06712611 | ||
|
|
74b6f9487c | ||
|
|
68e08cae7e | ||
|
|
7cf353dd22 | ||
|
|
704b2feecb | ||
|
|
0b23f5bc86 | ||
|
|
98ac007ffe | ||
|
|
12b0872349 | ||
|
|
1f1d4f5bad | ||
|
|
fef7c55270 | ||
|
|
c6faf452b9 | ||
|
|
ee582ac9b0 | ||
|
|
3f67b2137d | ||
|
|
bd8ad91de6 | ||
|
|
3035627c93 | ||
|
|
f708bb1465 | ||
|
|
044d8307f9 | ||
|
|
5615c30fd0 | ||
|
|
9c76528fe1 | ||
|
|
88f25e41c6 | ||
|
|
a3d11ded43 | ||
|
|
8dc2295006 | ||
|
|
fafce2f262 | ||
|
|
d177bfa553 | ||
|
|
a55ef85776 | ||
|
|
60d0ed34b8 | ||
|
|
243a9b92ce | ||
|
|
f224c04804 | ||
|
|
f9683c2242 | ||
|
|
580f054d7e | ||
|
|
94f00b2fdc | ||
|
|
41a71173d1 | ||
|
|
5c5c316ebf | ||
|
|
a3987b46c8 | ||
|
|
eb70e48ece | ||
|
|
850b20d5a8 | ||
|
|
0a0252d218 | ||
|
|
2e81234df1 | ||
|
|
abc3b13fd7 | ||
|
|
566732321d | ||
|
|
3cb635b443 | ||
|
|
f96cb273a0 | ||
|
|
a69c81b6be | ||
|
|
3e7125aca0 | ||
|
|
2078f63e62 | ||
|
|
c19def3764 | ||
|
|
e8a2aab7e1 | ||
|
|
6ae3414329 | ||
|
|
4e78d7e5d5 | ||
|
|
0a58383ed8 | ||
|
|
e4b4d8b70a | ||
|
|
72277e51e2 | ||
|
|
b0480a3343 | ||
|
|
f7e7b4be85 | ||
|
|
eac42c104b | ||
|
|
63ec8d4b3b | ||
|
|
a8fcf5502f | ||
|
|
27e11adac6 | ||
|
|
7bacb2a0f7 | ||
|
|
f35242e5c7 | ||
|
|
f10faf953c | ||
|
|
d814aa754f | ||
|
|
27a383cfa7 | ||
|
|
4b30dc4573 | ||
|
|
c1c9115e5d | ||
|
|
b4e35c442e | ||
|
|
5b27d8408c | ||
|
|
02d044c391 | ||
|
|
fafa5ed7f9 | ||
|
|
537a56414a | ||
|
|
f9d0fbb4c3 | ||
|
|
67da195f9f | ||
|
|
aba546cf8e | ||
|
|
b4b0889c7a | ||
|
|
6048d65d87 | ||
|
|
5d4e3699b2 | ||
|
|
a7e27ffa2c | ||
|
|
e15f3ffbaa | ||
|
|
e754e836af | ||
|
|
ceb82f4fd2 | ||
|
|
a6e022ad99 | ||
|
|
258e2e8a52 | ||
|
|
8c8727e30f | ||
|
|
2569503afa | ||
|
|
a5eebda391 | ||
|
|
67dce280d7 | ||
|
|
04a65c5c38 | ||
|
|
0674a70c35 | ||
|
|
e02e495257 | ||
|
|
d9e78e14fb | ||
|
|
af94d760d0 | ||
|
|
35e03475e4 | ||
|
|
e6c6f49143 | ||
|
|
be9857f66f | ||
|
|
5a0b53cd73 | ||
|
|
bdc66bcba9 | ||
|
|
ce6954d628 | ||
|
|
00da19a381 | ||
|
|
277ecaf78a | ||
|
|
885126174d | ||
|
|
6999a125c8 | ||
|
|
c021b9420f | ||
|
|
910985cd22 | ||
|
|
3b178131bd | ||
|
|
b514d31c26 | ||
|
|
efe9b60e37 | ||
|
|
8de83fdd9a | ||
|
|
f139bc2416 | ||
|
|
ca07082ff4 | ||
|
|
6603ff1000 | ||
|
|
288976f015 | ||
|
|
865bf7cac6 | ||
|
|
8e4eb5d00c | ||
|
|
923b96fab8 | ||
|
|
3b10494b40 | ||
|
|
30fa4c4a2e | ||
|
|
ae1dc41c88 | ||
|
|
017a12760c | ||
|
|
be6ce3c319 | ||
|
|
9784392a68 | ||
|
|
32b7dda832 | ||
|
|
4a05010539 | ||
|
|
aa3e94acf8 | ||
|
|
d24b4ab3e6 | ||
|
|
37a7d8f097 | ||
|
|
58f010fe91 | ||
|
|
2e6b3ca1ff | ||
|
|
a6b95d495c | ||
|
|
0e5ec5b260 | ||
|
|
a59109cb66 | ||
|
|
acb555b75a | ||
|
|
f32481deb9 | ||
|
|
471549db4b | ||
|
|
6805262a9b | ||
|
|
2311316bfe | ||
|
|
7edb29778b | ||
|
|
2d7668bc01 | ||
|
|
4b32a0787d | ||
|
|
ab7ff2b206 | ||
|
|
e854819e8f | ||
|
|
7d81ceb898 | ||
|
|
64b24b02ed | ||
|
|
375b5d46cb | ||
|
|
570679c5bf | ||
|
|
61ed18db2c | ||
|
|
1f21d2bb45 | ||
|
|
8f3e1f06f1 | ||
|
|
583ff684df | ||
|
|
e51ce613e6 | ||
|
|
36fe61d8e7 | ||
|
|
e52e94fe5e | ||
|
|
d21d83fb26 | ||
|
|
14914f1251 | ||
|
|
68415ce71d | ||
|
|
e7ef2d1e83 | ||
|
|
4d64176ea3 | ||
|
|
b30f84fdbd | ||
|
|
cca3608ad7 | ||
|
|
6c7c3f570d | ||
|
|
b311293c6b | ||
|
|
0ff263a02a | ||
|
|
24d092ee46 | ||
|
|
aefaaa7457 | ||
|
|
3997b6a952 | ||
|
|
68021bc652 | ||
|
|
6d15f21073 | ||
|
|
aba140a977 | ||
|
|
4a11d4fdd8 | ||
|
|
df9c0284b1 | ||
|
|
b57aba1a97 | ||
|
|
d36a522470 |
119 changed files with 6099 additions and 630 deletions
5
.github/workflows/build.yml
vendored
5
.github/workflows/build.yml
vendored
|
|
@ -10,7 +10,7 @@ jobs:
|
|||
- name: Update system and add dependencies
|
||||
run: |
|
||||
apk upgrade -Ua
|
||||
apk add build-base git kyua atf
|
||||
apk add build-base git kyua atf scdoc
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
|
@ -18,5 +18,8 @@ jobs:
|
|||
- name: Build
|
||||
run: make
|
||||
|
||||
- name: Build documentation
|
||||
run: make docs
|
||||
|
||||
- name: Run tests
|
||||
run: make check
|
||||
|
|
|
|||
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -13,4 +13,5 @@ ifquery
|
|||
ifup
|
||||
ifdown
|
||||
ifctrstat
|
||||
ifparse
|
||||
*.lock
|
||||
|
|
|
|||
3
COPYING
3
COPYING
|
|
@ -1,4 +1,5 @@
|
|||
Copyright (c) 2020 Ariadne Conill <ariadne@dereferenced.org>
|
||||
Copyright (c) 2020-2021 Ariadne Conill <ariadne@dereferenced.org>
|
||||
Copyright (c) 2020-2021 Maximilian Wilhelm <max@sdn.clinic>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
|
|
|
|||
79
Makefile
79
Makefile
|
|
@ -4,20 +4,23 @@ LIBBSD_CFLAGS =
|
|||
LIBBSD_LIBS =
|
||||
|
||||
PACKAGE_NAME := ifupdown-ng
|
||||
PACKAGE_VERSION := 0.8.5
|
||||
PACKAGE_VERSION := 0.11.3
|
||||
PACKAGE_BUGREPORT := https://github.com/ifupdown-ng/ifupdown-ng/issues/new
|
||||
|
||||
|
||||
INTERFACES_FILE := /etc/network/interfaces
|
||||
STATE_FILE := /run/ifstate
|
||||
CONFIG_FILE := /etc/network/ifupdown-ng.conf
|
||||
EXECUTOR_PATH := /usr/libexec/ifupdown-ng
|
||||
|
||||
CFLAGS ?= -ggdb3 -Os
|
||||
CFLAGS += -Wall -Wextra
|
||||
CFLAGS += -Wall -Wextra -Werror
|
||||
CFLAGS += -Wmissing-declarations -Wmissing-prototypes -Wcast-align -Wpointer-arith -Wreturn-type
|
||||
CFLAGS += ${LIBBSD_CFLAGS}
|
||||
CPPFLAGS = -I.
|
||||
CPPFLAGS += -DINTERFACES_FILE=\"${INTERFACES_FILE}\"
|
||||
CPPFLAGS += -DSTATE_FILE=\"${STATE_FILE}\"
|
||||
CPPFLAGS += -DCONFIG_FILE=\"${CONFIG_FILE}\"
|
||||
CPPFLAGS += -DPACKAGE_NAME=\"${PACKAGE_NAME}\"
|
||||
CPPFLAGS += -DPACKAGE_VERSION=\"${PACKAGE_VERSION}\"
|
||||
CPPFLAGS += -DPACKAGE_BUGREPORT=\"${PACKAGE_BUGREPORT}\"
|
||||
|
|
@ -34,8 +37,10 @@ LIBIFUPDOWN_SRC = \
|
|||
libifupdown/state.c \
|
||||
libifupdown/environment.c \
|
||||
libifupdown/execute.c \
|
||||
libifupdown/lifecycle.c
|
||||
|
||||
libifupdown/lifecycle.c \
|
||||
libifupdown/config-parser.c \
|
||||
libifupdown/config-file.c \
|
||||
libifupdown/compat.c
|
||||
LIBIFUPDOWN_OBJ = ${LIBIFUPDOWN_SRC:.c=.o}
|
||||
LIBIFUPDOWN_LIB = libifupdown.a
|
||||
|
||||
|
|
@ -43,7 +48,8 @@ MULTICALL_SRC = \
|
|||
cmd/multicall.c \
|
||||
cmd/multicall-options.c \
|
||||
cmd/multicall-exec-options.c \
|
||||
cmd/multicall-match-options.c
|
||||
cmd/multicall-match-options.c \
|
||||
cmd/pretty-print-iface.c
|
||||
MULTICALL_OBJ = ${MULTICALL_SRC:.c=.o}
|
||||
MULTICALL = ifupdown
|
||||
|
||||
|
|
@ -69,6 +75,22 @@ MULTICALL_${CONFIG_IFCTRSTAT}_OBJ += ${IFCTRSTAT_SRC:.c=.o}
|
|||
CMDS_${CONFIG_IFCTRSTAT} += ifctrstat
|
||||
CPPFLAGS_${CONFIG_IFCTRSTAT} += -DCONFIG_IFCTRSTAT
|
||||
|
||||
# enable ifparse applet (+1 KB)
|
||||
CONFIG_IFPARSE ?= Y
|
||||
IFPARSE_SRC = cmd/ifparse.c
|
||||
MULTICALL_${CONFIG_IFPARSE}_OBJ += ${IFPARSE_SRC:.c=.o}
|
||||
CMDS_${CONFIG_IFPARSE} += ifparse
|
||||
CPPFLAGS_${CONFIG_IFPARSE} += -DCONFIG_IFPARSE
|
||||
|
||||
# enable YAML support (+2 KB)
|
||||
CONFIG_YAML ?= Y
|
||||
YAML_SRC = \
|
||||
libifupdown/yaml-base.c \
|
||||
libifupdown/yaml-writer.c
|
||||
LIBIFUPDOWN_${CONFIG_YAML}_OBJ += ${YAML_SRC:.c=.o}
|
||||
CPPFLAGS_${CONFIG_YAML} += -DCONFIG_YAML
|
||||
|
||||
LIBIFUPDOWN_OBJ += ${LIBIFUPDOWN_Y_OBJ}
|
||||
MULTICALL_OBJ += ${MULTICALL_Y_OBJ}
|
||||
CMDS += ${CMDS_Y}
|
||||
CPPFLAGS += ${CPPFLAGS_Y}
|
||||
|
|
@ -78,18 +100,28 @@ EXECUTOR_SCRIPTS_CORE ?= \
|
|||
ipv6-ra \
|
||||
static \
|
||||
link \
|
||||
ppp
|
||||
ppp \
|
||||
forward
|
||||
|
||||
EXECUTOR_SCRIPTS_OPT ?= \
|
||||
batman \
|
||||
bond \
|
||||
bridge \
|
||||
vrf \
|
||||
ethtool \
|
||||
gre \
|
||||
mpls \
|
||||
tunnel \
|
||||
gre
|
||||
vrf \
|
||||
vxlan \
|
||||
wifi \
|
||||
wireguard
|
||||
|
||||
EXECUTOR_SCRIPTS ?= ${EXECUTOR_SCRIPTS_CORE} ${EXECUTOR_SCRIPTS_OPT}
|
||||
|
||||
EXECUTOR_SCRIPTS_STUB ?=
|
||||
|
||||
EXECUTOR_SCRIPTS_NATIVE ?=
|
||||
|
||||
TARGET_LIBS = ${LIBIFUPDOWN_LIB}
|
||||
LIBS += ${TARGET_LIBS} ${LIBBSD_LIBS}
|
||||
|
||||
|
|
@ -124,21 +156,38 @@ install: all
|
|||
for i in ${EXECUTOR_SCRIPTS_STUB}; do \
|
||||
install -D -m755 executor-scripts/stub/$$i ${DESTDIR}${EXECUTOR_PATH}/$$i; \
|
||||
done
|
||||
for i in ${EXECUTOR_SCRIPTS_NATIVE}; do \
|
||||
install -D -m755 executor-scripts/${LAYOUT}-native/$$i ${DESTDIR}${EXECUTOR_PATH}/$$i; \
|
||||
done
|
||||
install -D -m644 dist/ifupdown-ng.conf.example ${DESTDIR}${CONFIG_FILE}.example
|
||||
|
||||
.scd.1 .scd.2 .scd.3 .scd.4 .scd.5 .scd.6 .scd.7 .scd.8:
|
||||
${SCDOC} < $< > $@
|
||||
|
||||
MANPAGES_5 = \
|
||||
doc/ifstate.5 \
|
||||
doc/ifupdown-ng.conf.5 \
|
||||
doc/interfaces.5 \
|
||||
doc/interfaces-bond.5 \
|
||||
doc/interfaces-batman.5 \
|
||||
doc/interfaces-bridge.5 \
|
||||
doc/interfaces-forward.5 \
|
||||
doc/interfaces-ppp.5 \
|
||||
doc/interfaces-tunnel.5 \
|
||||
doc/interfaces-vrf.5 \
|
||||
doc/interfaces-vxlan.5 \
|
||||
doc/interfaces-wifi.5 \
|
||||
doc/interfaces-wireguard.5
|
||||
|
||||
MANPAGES_7 = \
|
||||
doc/ifupdown-executor.7
|
||||
|
||||
MANPAGES_8 = \
|
||||
doc/ifquery.8 \
|
||||
doc/ifup.8 \
|
||||
doc/ifdown.8 \
|
||||
doc/ifctrstat.8
|
||||
|
||||
MANPAGES_5 = \
|
||||
doc/interfaces.5
|
||||
|
||||
MANPAGES_7 = \
|
||||
doc/ifupdown-executor.7
|
||||
doc/ifctrstat.8 \
|
||||
doc/ifparse.8
|
||||
|
||||
MANPAGES = ${MANPAGES_5} ${MANPAGES_7} ${MANPAGES_8}
|
||||
|
||||
|
|
|
|||
16
README.md
16
README.md
|
|
@ -30,18 +30,20 @@ For compatibility with some legacy ifupdown executors, we also provide the
|
|||
|
||||
On musl systems, simply do `make` and `make install` to build and install.
|
||||
|
||||
On glibc systems, you must additionally define LIBBSD_CFLAGS and LIBBSD_LIBS:
|
||||
On glibc systems, you must install `libbsd-dev` or equivalent and additionally define `LIBBSD_CFLAGS` and `LIBBSD_LIBS`:
|
||||
|
||||
export LIBBSD_CFLAGS=$(pkg-config --cflags libbsd-overlay)
|
||||
export LIBBSD_LIBS=$(pkg-config --libs libbsd-overlay)
|
||||
make
|
||||
# instal packages
|
||||
apt install build-essential libbsd0 libbsd-dev
|
||||
|
||||
# build ifupdown-ng
|
||||
make LIBBSD_CFLAGS="$(pkg-config --cflags libbsd-overlay)" LIBBSD_LIBS="$(pkg-config --cflags --libs libbsd-overlay)"
|
||||
make install
|
||||
|
||||
To run the tests, do `make check`.
|
||||
To run the tests, do `make check`. Running the checks requires `kyua` (`apk add kyua` / `apt install kyua`).
|
||||
|
||||
To build the documentation, do `make docs` and `make install_docs`. Building
|
||||
the documentation requires scdoc (`apk add scdoc`).
|
||||
the documentation requires scdoc (`apk add scdoc` / `apt install scdoc`).
|
||||
|
||||
## Discussion
|
||||
|
||||
Discuss ifupdown-ng on IRC: irc.as7007.net #ifupdown-ng
|
||||
Discuss ifupdown-ng on IRC: irc.oftc.net #ifupdown-ng
|
||||
|
|
|
|||
|
|
@ -17,7 +17,8 @@
|
|||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "multicall.h"
|
||||
#include "cmd/multicall.h"
|
||||
#include "cmd/ifctrstat-linux.h"
|
||||
|
||||
struct counter_desc {
|
||||
const char *name;
|
||||
|
|
@ -41,7 +42,7 @@ counter_compare(const void *key, const void *candidate)
|
|||
return strcasecmp((const char *)key, ((struct counter_desc *)candidate)->name);
|
||||
}
|
||||
|
||||
char *
|
||||
const char *
|
||||
read_counter(const char *interface, const char *counter)
|
||||
{
|
||||
FILE *fp;
|
||||
|
|
|
|||
22
cmd/ifctrstat-linux.h
Normal file
22
cmd/ifctrstat-linux.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* cmd/ifctrstat-linux.c
|
||||
* Purpose: Implement ifctrstat system-specific routines for Linux
|
||||
*
|
||||
* Copyright (c) 2021 Maximilian Wilhelm <max@sdn.clinic>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* This software is provided 'as is' and without any warranty, express or
|
||||
* implied. In no event shall the authors be liable for any damages arising
|
||||
* from the use of this software.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef IFUPDOWN_IFCTRSTAT_LINUX__H__GUARD
|
||||
#define IFUPDOWN_IFCTRSTAT_LINUX__H__GUARD
|
||||
|
||||
extern const char * read_counter(const char *interface, const char *counter);
|
||||
|
||||
#endif
|
||||
|
|
@ -20,12 +20,11 @@
|
|||
#include <string.h>
|
||||
#include "libifupdown/libifupdown.h"
|
||||
#include "cmd/multicall.h"
|
||||
#include "cmd/ifctrstat-linux.h"
|
||||
|
||||
extern struct counter_desc { const char *name; const void *data; } avail_counters[];
|
||||
extern int avail_counters_count;
|
||||
|
||||
extern const char *read_counter(const char *interface, const char *counter);
|
||||
|
||||
static bool show_label = true;
|
||||
|
||||
static bool
|
||||
|
|
@ -96,7 +95,7 @@ ifctrstat_set_nolabel(const char *opt_arg)
|
|||
show_label = false;
|
||||
}
|
||||
|
||||
int
|
||||
static int
|
||||
ifctrstat_main(int argc, char *argv[])
|
||||
{
|
||||
if (optind >= argc)
|
||||
|
|
@ -152,7 +151,7 @@ static struct if_option_group local_option_group = {
|
|||
|
||||
struct if_applet ifctrstat_applet = {
|
||||
.name = "ifctrstat",
|
||||
.desc = "Display statistics about an interface",
|
||||
.desc = "display statistics about an interface",
|
||||
.main = ifctrstat_main,
|
||||
.usage = "ifctrstat [options] <interface> <counter>\n ifctrstat [options] --list",
|
||||
.manpage = "8 ifctrstat",
|
||||
|
|
|
|||
224
cmd/ifparse.c
Normal file
224
cmd/ifparse.c
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
/*
|
||||
* cmd/ifparse.c
|
||||
* Purpose: Redisplay /e/n/i in alternative formats.
|
||||
*
|
||||
* Copyright (c) 2020 Ariadne Conill <ariadne@dereferenced.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* This software is provided 'as is' and without any warranty, express or
|
||||
* implied. In no event shall the authors be liable for any damages arising
|
||||
* from the use of this software.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <fnmatch.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#include "libifupdown/libifupdown.h"
|
||||
|
||||
#ifdef CONFIG_YAML
|
||||
# include "libifupdown/yaml-base.h"
|
||||
# include "libifupdown/yaml-writer.h"
|
||||
#endif
|
||||
|
||||
#include "cmd/multicall.h"
|
||||
#include "cmd/pretty-print-iface.h"
|
||||
|
||||
static bool show_all = false;
|
||||
static bool allow_undefined = false;
|
||||
|
||||
static void
|
||||
set_show_all(const char *arg)
|
||||
{
|
||||
(void) arg;
|
||||
|
||||
show_all = true;
|
||||
}
|
||||
|
||||
static void
|
||||
set_allow_undefined(const char *arg)
|
||||
{
|
||||
(void) arg;
|
||||
|
||||
allow_undefined = true;
|
||||
}
|
||||
|
||||
static const char *output_fmt = "ifupdown";
|
||||
|
||||
static void
|
||||
set_output_fmt(const char *arg)
|
||||
{
|
||||
output_fmt = arg;
|
||||
}
|
||||
|
||||
static struct if_option local_options[] = {
|
||||
{'F', "format", NULL, "output format to use", true, set_output_fmt},
|
||||
{'A', "all", NULL, "show all interfaces", false, set_show_all},
|
||||
{'U', "allow-undefined", NULL, "allow querying undefined (virtual) interfaces", false, set_allow_undefined},
|
||||
};
|
||||
|
||||
static struct if_option_group local_option_group = {
|
||||
.desc = "Program-specific options",
|
||||
.group_size = ARRAY_SIZE(local_options),
|
||||
.group = local_options
|
||||
};
|
||||
|
||||
#ifdef CONFIG_YAML
|
||||
static void
|
||||
prettyprint_interface_yaml(struct lif_interface *iface)
|
||||
{
|
||||
struct lif_yaml_node doc = {};
|
||||
|
||||
lif_yaml_document_init(&doc, "interfaces");
|
||||
|
||||
struct lif_yaml_node *iface_node = lif_yaml_node_new_list(iface->ifname);
|
||||
lif_yaml_node_append_child(&doc, iface_node);
|
||||
|
||||
if (iface->is_auto)
|
||||
{
|
||||
struct lif_yaml_node *iface_entry_node = lif_yaml_node_new_boolean("auto", true);
|
||||
lif_yaml_node_append_child(iface_node, iface_entry_node);
|
||||
}
|
||||
|
||||
struct lif_node *iter;
|
||||
LIF_DICT_FOREACH(iter, &iface->vars)
|
||||
{
|
||||
struct lif_dict_entry *entry = iter->data;
|
||||
const char *value = entry->data;
|
||||
char addr_buf[512];
|
||||
|
||||
if (!strcmp(entry->key, "address"))
|
||||
{
|
||||
struct lif_address *addr = entry->data;
|
||||
|
||||
if (!lif_address_unparse(addr, addr_buf, sizeof addr_buf, true))
|
||||
continue;
|
||||
|
||||
value = addr_buf;
|
||||
}
|
||||
|
||||
struct lif_yaml_node *iface_entry_node = lif_yaml_node_new_string(entry->key, value);
|
||||
lif_yaml_node_append_child(iface_node, iface_entry_node);
|
||||
}
|
||||
|
||||
lif_yaml_write(iface_node, stdout, true);
|
||||
lif_yaml_node_free(&doc);
|
||||
}
|
||||
#endif
|
||||
|
||||
struct prettyprint_impl_map {
|
||||
const char *name;
|
||||
void (*handle)(struct lif_interface *iface);
|
||||
};
|
||||
|
||||
struct prettyprint_impl_map pp_impl_map[] = {
|
||||
{"ifupdown", prettyprint_interface_eni},
|
||||
#ifdef CONFIG_YAML
|
||||
{"yaml-raw", prettyprint_interface_yaml},
|
||||
#endif
|
||||
};
|
||||
|
||||
static int
|
||||
pp_impl_cmp(const void *a, const void *b)
|
||||
{
|
||||
const char *key = a;
|
||||
const struct prettyprint_impl_map *impl = b;
|
||||
|
||||
return strcmp(key, impl->name);
|
||||
}
|
||||
|
||||
static int
|
||||
ifparse_main(int argc, char *argv[])
|
||||
{
|
||||
struct lif_dict state = {};
|
||||
struct lif_dict collection = {};
|
||||
struct lif_interface_file_parse_state parse_state = {
|
||||
.collection = &collection,
|
||||
};
|
||||
|
||||
lif_interface_collection_init(&collection);
|
||||
|
||||
if (!lif_state_read_path(&state, exec_opts.state_file))
|
||||
{
|
||||
fprintf(stderr, "%s: could not parse %s\n", argv0, exec_opts.state_file);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!lif_interface_file_parse(&parse_state, exec_opts.interfaces_file))
|
||||
{
|
||||
fprintf(stderr, "%s: could not parse %s\n", argv0, exec_opts.interfaces_file);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (match_opts.property == NULL && lif_lifecycle_count_rdepends(&exec_opts, &collection) == -1)
|
||||
{
|
||||
fprintf(stderr, "%s: could not validate dependency tree\n", argv0);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!lif_compat_apply(&collection))
|
||||
{
|
||||
fprintf(stderr, "%s: failed to apply compatibility glue\n", argv0);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
struct prettyprint_impl_map *m = bsearch(output_fmt, pp_impl_map, ARRAY_SIZE(pp_impl_map), sizeof(*m), pp_impl_cmp);
|
||||
if (m == NULL)
|
||||
{
|
||||
fprintf(stderr, "%s: %s: output format not supported\n", argv0, output_fmt);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (show_all)
|
||||
{
|
||||
struct lif_node *n;
|
||||
|
||||
LIF_DICT_FOREACH(n, &collection)
|
||||
{
|
||||
struct lif_dict_entry *entry = n->data;
|
||||
|
||||
m->handle(entry->data);
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
if (optind >= argc)
|
||||
generic_usage(self_applet, EXIT_FAILURE);
|
||||
|
||||
int idx = optind;
|
||||
for (; idx < argc; idx++)
|
||||
{
|
||||
struct lif_dict_entry *entry = lif_dict_find(&collection, argv[idx]);
|
||||
struct lif_interface *iface = NULL;
|
||||
|
||||
if (entry != NULL)
|
||||
iface = entry->data;
|
||||
|
||||
if (entry == NULL && allow_undefined)
|
||||
iface = lif_interface_collection_find(&collection, argv[idx]);
|
||||
|
||||
if (iface == NULL)
|
||||
{
|
||||
fprintf(stderr, "%s: unknown interface %s\n", argv0, argv[idx]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
m->handle(iface);
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
struct if_applet ifparse_applet = {
|
||||
.name = "ifparse",
|
||||
.desc = "redisplay interface configuration",
|
||||
.main = ifparse_main,
|
||||
.usage = "ifparse [options] <interfaces>\n ifparse [options] --all",
|
||||
.manpage = "8 ifparse",
|
||||
.groups = { &global_option_group, &match_option_group, &exec_option_group, &local_option_group },
|
||||
};
|
||||
168
cmd/ifquery.c
168
cmd/ifquery.c
|
|
@ -20,56 +20,18 @@
|
|||
#include <getopt.h>
|
||||
#include "libifupdown/libifupdown.h"
|
||||
#include "cmd/multicall.h"
|
||||
#include "cmd/pretty-print-iface.h"
|
||||
|
||||
void
|
||||
print_interface(struct lif_interface *iface)
|
||||
{
|
||||
if (!lif_lifecycle_query_dependents(&exec_opts, iface, iface->ifname))
|
||||
return;
|
||||
|
||||
if (iface->is_auto)
|
||||
printf("auto %s\n", iface->ifname);
|
||||
|
||||
printf("iface %s\n", iface->ifname);
|
||||
|
||||
struct lif_node *iter;
|
||||
LIF_DICT_FOREACH(iter, &iface->vars)
|
||||
{
|
||||
struct lif_dict_entry *entry = iter->data;
|
||||
|
||||
if (!strcmp(entry->key, "address"))
|
||||
{
|
||||
struct lif_address *addr = entry->data;
|
||||
char addr_buf[512];
|
||||
|
||||
if (!lif_address_unparse(addr, addr_buf, sizeof addr_buf, true))
|
||||
{
|
||||
printf(" # warning: failed to unparse address\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
printf(" %s %s\n", entry->key, addr_buf);
|
||||
}
|
||||
else
|
||||
printf(" %s %s\n", entry->key, (const char *) entry->data);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
print_interface_dot(struct lif_dict *collection, struct lif_interface *iface, struct lif_interface *parent)
|
||||
{
|
||||
if (!lif_lifecycle_query_dependents(&exec_opts, iface, iface->ifname))
|
||||
return;
|
||||
|
||||
if (iface->is_up)
|
||||
return;
|
||||
|
||||
if (parent != NULL)
|
||||
printf("\"%s\" -> ", parent->ifname);
|
||||
printf("\"%s (%zu)\" -> ", parent->ifname, parent->rdepends_count);
|
||||
|
||||
printf("\"%s\"", iface->ifname);
|
||||
printf("\"%s (%zu)\"", iface->ifname, iface->rdepends_count);
|
||||
|
||||
printf("\n");
|
||||
|
||||
|
|
@ -86,37 +48,16 @@ print_interface_dot(struct lif_dict *collection, struct lif_interface *iface, st
|
|||
{
|
||||
struct lif_interface *child_if = lif_interface_collection_find(collection, tokenp);
|
||||
|
||||
if (child_if->is_pending)
|
||||
continue;
|
||||
|
||||
child_if->is_pending = true;
|
||||
print_interface_dot(collection, child_if, iface);
|
||||
child_if->is_up = true;
|
||||
child_if->is_pending = false;
|
||||
}
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
count_set_bits(const char *netmask)
|
||||
{
|
||||
/* netmask set to CIDR length */
|
||||
if (strchr(netmask, '.') == NULL)
|
||||
return strtol(netmask, NULL, 10);
|
||||
|
||||
size_t r = 0;
|
||||
struct in_addr in;
|
||||
|
||||
if (inet_pton(AF_INET, netmask, &in) == 0)
|
||||
return r;
|
||||
|
||||
/* take the IP, put it in host endian order, and
|
||||
* flip it so that all the set bits are set to the right.
|
||||
* then we can simply count down from 32 and right-shift
|
||||
* until the bit field is all zero.
|
||||
*/
|
||||
unsigned int bits = htonl(in.s_addr);
|
||||
for (bits = ~bits, r = 32; bits; bits >>= 1, r--)
|
||||
;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
print_interface_property(struct lif_interface *iface, const char *property)
|
||||
{
|
||||
struct lif_node *iter;
|
||||
|
|
@ -131,26 +72,10 @@ print_interface_property(struct lif_interface *iface, const char *property)
|
|||
|
||||
if (printing_address)
|
||||
{
|
||||
struct lif_address *addr = entry->data;
|
||||
size_t orig_netmask = addr->netmask;
|
||||
|
||||
if (!addr->netmask)
|
||||
{
|
||||
/* if fallback netmask is not set, default to 255.255.255.0 */
|
||||
addr->netmask = 24;
|
||||
|
||||
struct lif_dict_entry *entry = lif_dict_find(&iface->vars, "netmask");
|
||||
if (entry != NULL)
|
||||
addr->netmask = count_set_bits(entry->data);
|
||||
}
|
||||
|
||||
char addr_buf[512];
|
||||
|
||||
if (!lif_address_unparse(addr, addr_buf, sizeof addr_buf, true))
|
||||
if (!lif_address_format_cidr(iface, entry, addr_buf, sizeof(addr_buf)))
|
||||
continue;
|
||||
|
||||
addr->netmask = orig_netmask;
|
||||
|
||||
printf("%s\n", addr_buf);
|
||||
}
|
||||
else
|
||||
|
|
@ -158,16 +83,16 @@ print_interface_property(struct lif_interface *iface, const char *property)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
list_interfaces(struct lif_dict *collection, struct match_options *opts)
|
||||
{
|
||||
struct lif_node *iter;
|
||||
|
||||
if (opts->dot)
|
||||
{
|
||||
printf("digraph interfaces {\n");
|
||||
printf("edge [color=blue fontname=Sans fontsize=10]\n");
|
||||
printf("node [fontname=Sans fontsize=10]\n");
|
||||
printf("digraph interfaces {\n"
|
||||
"edge [color=blue fontname=Sans fontsize=10]\n"
|
||||
"node [fontname=Sans fontsize=10]\n");
|
||||
}
|
||||
|
||||
LIF_DICT_FOREACH(iter, collection)
|
||||
|
|
@ -187,7 +112,7 @@ list_interfaces(struct lif_dict *collection, struct match_options *opts)
|
|||
continue;
|
||||
|
||||
if (opts->pretty_print)
|
||||
print_interface(iface);
|
||||
prettyprint_interface_eni(iface);
|
||||
else if (opts->dot)
|
||||
print_interface_dot(collection, iface, NULL);
|
||||
else
|
||||
|
|
@ -198,7 +123,10 @@ list_interfaces(struct lif_dict *collection, struct match_options *opts)
|
|||
printf("}\n");
|
||||
}
|
||||
|
||||
void
|
||||
static bool listing = false, listing_stat = false, listing_running = false;
|
||||
static bool allow_undefined = false;
|
||||
|
||||
static void
|
||||
list_state(struct lif_dict *state, struct match_options *opts)
|
||||
{
|
||||
struct lif_node *iter;
|
||||
|
|
@ -215,12 +143,16 @@ list_state(struct lif_dict *state, struct match_options *opts)
|
|||
fnmatch(opts->include_pattern, entry->key, 0))
|
||||
continue;
|
||||
|
||||
printf("%s=%s\n", entry->key, (const char *) entry->data);
|
||||
struct lif_state_record *rec = entry->data;
|
||||
|
||||
if (listing_running)
|
||||
printf("%s\n", entry->key);
|
||||
else
|
||||
printf("%s=%s %zu%s\n", entry->key, rec->mapped_if, rec->refcount,
|
||||
rec->is_explicit ? " explicit" : "");
|
||||
}
|
||||
}
|
||||
|
||||
static bool listing = false, listing_stat = false;
|
||||
|
||||
static void
|
||||
set_listing(const char *opt_arg)
|
||||
{
|
||||
|
|
@ -235,6 +167,13 @@ set_show_state(const char *opt_arg)
|
|||
listing_stat = true;
|
||||
}
|
||||
|
||||
static void
|
||||
set_show_running(const char *opt_arg)
|
||||
{
|
||||
(void) opt_arg;
|
||||
listing_running = true;
|
||||
}
|
||||
|
||||
static void
|
||||
set_pretty_print(const char *opt_arg)
|
||||
{
|
||||
|
|
@ -255,12 +194,21 @@ set_property(const char *opt_arg)
|
|||
match_opts.property = opt_arg;
|
||||
}
|
||||
|
||||
static void
|
||||
set_allow_undefined(const char *opt_arg)
|
||||
{
|
||||
(void) opt_arg;
|
||||
allow_undefined = true;
|
||||
}
|
||||
|
||||
static struct if_option local_options[] = {
|
||||
{'r', "running", NULL, "show configured (running) interfaces", false, set_show_running},
|
||||
{'s', "state", NULL, "show configured state", false, set_show_state},
|
||||
{'p', "property", "property PROPERTY", "print values of properties matching PROPERTY", true, set_property},
|
||||
{'D', "dot", NULL, "generate a dependency graph", false, set_output_dot},
|
||||
{'L', "list", NULL, "list matching interfaces", false, set_listing},
|
||||
{'P', "pretty-print", NULL, "pretty print the interfaces instead of just listing", false, set_pretty_print},
|
||||
{'U', "allow-undefined", NULL, "allow querying undefined (virtual) interfaces", false, set_allow_undefined},
|
||||
};
|
||||
|
||||
static struct if_option_group local_option_group = {
|
||||
|
|
@ -269,11 +217,16 @@ static struct if_option_group local_option_group = {
|
|||
.group = local_options
|
||||
};
|
||||
|
||||
int
|
||||
static int
|
||||
ifquery_main(int argc, char *argv[])
|
||||
{
|
||||
struct lif_dict state = {};
|
||||
struct lif_dict collection = {};
|
||||
struct lif_interface_file_parse_state parse_state = {
|
||||
.collection = &collection,
|
||||
};
|
||||
|
||||
lif_interface_collection_init(&collection);
|
||||
|
||||
if (!lif_state_read_path(&state, exec_opts.state_file))
|
||||
{
|
||||
|
|
@ -281,14 +234,26 @@ ifquery_main(int argc, char *argv[])
|
|||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!lif_interface_file_parse(&collection, exec_opts.interfaces_file))
|
||||
if (!lif_interface_file_parse(&parse_state, exec_opts.interfaces_file))
|
||||
{
|
||||
fprintf(stderr, "%s: could not parse %s\n", argv0, exec_opts.interfaces_file);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (match_opts.property == NULL && lif_lifecycle_count_rdepends(&exec_opts, &collection) == -1)
|
||||
{
|
||||
fprintf(stderr, "%s: could not validate dependency tree\n", argv0);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!lif_compat_apply(&collection))
|
||||
{
|
||||
fprintf(stderr, "%s: failed to apply compatibility glue\n", argv0);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* --list --state is not allowed */
|
||||
if (listing && listing_stat)
|
||||
if (listing && (listing_stat || listing_running))
|
||||
generic_usage(self_applet, EXIT_FAILURE);
|
||||
|
||||
if (listing)
|
||||
|
|
@ -296,7 +261,7 @@ ifquery_main(int argc, char *argv[])
|
|||
list_interfaces(&collection, &match_opts);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
else if (listing_stat)
|
||||
else if (listing_stat || listing_running)
|
||||
{
|
||||
list_state(&state, &match_opts);
|
||||
return EXIT_SUCCESS;
|
||||
|
|
@ -316,6 +281,9 @@ ifquery_main(int argc, char *argv[])
|
|||
|
||||
if (entry != NULL)
|
||||
iface = entry->data;
|
||||
|
||||
if (entry == NULL && allow_undefined)
|
||||
iface = lif_interface_collection_find(&collection, argv[idx]);
|
||||
}
|
||||
|
||||
if (iface == NULL)
|
||||
|
|
@ -327,7 +295,7 @@ ifquery_main(int argc, char *argv[])
|
|||
if (match_opts.property != NULL)
|
||||
print_interface_property(iface, match_opts.property);
|
||||
else
|
||||
print_interface(iface);
|
||||
prettyprint_interface_eni(iface);
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
|
|
|
|||
141
cmd/ifupdown.c
141
cmd/ifupdown.c
|
|
@ -3,6 +3,7 @@
|
|||
* Purpose: bring interfaces up or down
|
||||
*
|
||||
* Copyright (c) 2020 Ariadne Conill <ariadne@dereferenced.org>
|
||||
* Copyright (c) 2020 Maximilian Wilhelm <max@sdn.clinic>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
|
@ -26,7 +27,7 @@
|
|||
|
||||
static bool up;
|
||||
|
||||
bool
|
||||
static bool
|
||||
is_ifdown()
|
||||
{
|
||||
if (strstr(argv0, "ifdown") != NULL)
|
||||
|
|
@ -35,7 +36,7 @@ is_ifdown()
|
|||
return false;
|
||||
}
|
||||
|
||||
int
|
||||
static int
|
||||
acquire_state_lock(const char *state_path, const char *lifname)
|
||||
{
|
||||
if (exec_opts.mock || exec_opts.no_lock)
|
||||
|
|
@ -45,7 +46,7 @@ acquire_state_lock(const char *state_path, const char *lifname)
|
|||
|
||||
snprintf(lockpath, sizeof lockpath, "%s.%s.lock", state_path, lifname);
|
||||
|
||||
int fd = open(lockpath, O_CREAT | O_WRONLY | O_TRUNC);
|
||||
int fd = open(lockpath, O_CREAT | O_WRONLY | O_TRUNC, 0600);
|
||||
if (fd < 0)
|
||||
{
|
||||
if (exec_opts.verbose)
|
||||
|
|
@ -93,8 +94,60 @@ acquire_state_lock(const char *state_path, const char *lifname)
|
|||
return fd;
|
||||
}
|
||||
|
||||
bool
|
||||
change_interface(struct lif_interface *iface, struct lif_dict *collection, struct lif_dict *state, const char *ifname)
|
||||
static bool
|
||||
skip_interface(struct lif_interface *iface, const char *ifname, struct lif_dict *state, bool update_state)
|
||||
{
|
||||
if (iface->is_template)
|
||||
{
|
||||
fprintf(stderr, "%s: cannot change state on %s (template interface)\n", argv0, ifname);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (iface->has_config_error)
|
||||
{
|
||||
if (exec_opts.force)
|
||||
{
|
||||
fprintf(stderr, "%s: (de)configuring interface %s despite config errors\n", argv0, ifname);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "%s: skipping interface %s due to config errors\n", argv0, ifname);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (exec_opts.force)
|
||||
return false;
|
||||
|
||||
if (up && iface->refcount > 0)
|
||||
{
|
||||
if (exec_opts.verbose)
|
||||
fprintf(stderr, "%s: skipping %sinterface %s (already configured), use --force to force configuration\n",
|
||||
argv0, iface->is_auto ? "auto " : "", ifname);
|
||||
|
||||
if (update_state)
|
||||
{
|
||||
iface->is_explicit = true;
|
||||
lif_state_upsert(state, ifname, iface);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!up && iface->refcount == 0)
|
||||
{
|
||||
if (exec_opts.verbose)
|
||||
fprintf(stderr, "%s: skipping %sinterface %s (already deconfigured), use --force to force deconfiguration\n",
|
||||
argv0, iface->is_auto ? "auto " : "", ifname);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
change_interface(struct lif_interface *iface, struct lif_dict *collection, struct lif_dict *state, const char *ifname, bool update_state)
|
||||
{
|
||||
int lockfd = acquire_state_lock(exec_opts.state_file, ifname);
|
||||
|
||||
|
|
@ -104,6 +157,14 @@ change_interface(struct lif_interface *iface, struct lif_dict *collection, struc
|
|||
return false;
|
||||
}
|
||||
|
||||
if (skip_interface(iface, ifname, state, update_state))
|
||||
{
|
||||
if (lockfd != -1)
|
||||
close(lockfd);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (exec_opts.verbose)
|
||||
{
|
||||
fprintf(stderr, "%s: changing state of interface %s to '%s'\n",
|
||||
|
|
@ -124,10 +185,16 @@ change_interface(struct lif_interface *iface, struct lif_dict *collection, struc
|
|||
if (lockfd != -1)
|
||||
close(lockfd);
|
||||
|
||||
if (up && update_state)
|
||||
{
|
||||
iface->is_explicit = true;
|
||||
lif_state_upsert(state, ifname, iface);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
static bool
|
||||
change_auto_interfaces(struct lif_dict *collection, struct lif_dict *state, struct match_options *opts)
|
||||
{
|
||||
struct lif_node *iter;
|
||||
|
|
@ -148,20 +215,46 @@ change_auto_interfaces(struct lif_dict *collection, struct lif_dict *state, stru
|
|||
fnmatch(opts->include_pattern, iface->ifname, 0))
|
||||
continue;
|
||||
|
||||
if (!change_interface(iface, collection, state, iface->ifname))
|
||||
if (!change_interface(iface, collection, state, iface->ifname, false))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
static int
|
||||
update_state_file_and_exit(int rc, struct lif_dict *state)
|
||||
{
|
||||
if (exec_opts.mock)
|
||||
{
|
||||
exit(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (!lif_state_write_path(state, exec_opts.state_file))
|
||||
{
|
||||
fprintf(stderr, "%s: could not update %s\n", argv0, exec_opts.state_file);
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
exit(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
ifupdown_main(int argc, char *argv[])
|
||||
{
|
||||
up = !is_ifdown();
|
||||
|
||||
struct lif_dict state = {};
|
||||
struct lif_dict collection = {};
|
||||
struct lif_interface_file_parse_state parse_state = {
|
||||
.collection = &collection,
|
||||
};
|
||||
|
||||
lif_interface_collection_init(&collection);
|
||||
|
||||
if (!lif_state_read_path(&state, exec_opts.state_file))
|
||||
{
|
||||
|
|
@ -169,12 +262,24 @@ ifupdown_main(int argc, char *argv[])
|
|||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!lif_interface_file_parse(&collection, exec_opts.interfaces_file))
|
||||
if (!lif_interface_file_parse(&parse_state, exec_opts.interfaces_file))
|
||||
{
|
||||
fprintf(stderr, "%s: could not parse %s\n", argv0, exec_opts.interfaces_file);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (lif_lifecycle_count_rdepends(&exec_opts, &collection) == -1)
|
||||
{
|
||||
fprintf(stderr, "%s: could not validate dependency tree\n", argv0);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if(!lif_compat_apply(&collection))
|
||||
{
|
||||
fprintf(stderr, "%s: failed to apply compatibility glue\n", argv0);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!lif_state_sync(&state, &collection))
|
||||
{
|
||||
fprintf(stderr, "%s: could not sync state\n", argv0);
|
||||
|
|
@ -184,9 +289,9 @@ ifupdown_main(int argc, char *argv[])
|
|||
if (match_opts.is_auto)
|
||||
{
|
||||
if (!change_auto_interfaces(&collection, &state, &match_opts))
|
||||
return EXIT_FAILURE;
|
||||
return update_state_file_and_exit(EXIT_FAILURE, &state);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
return update_state_file_and_exit(EXIT_SUCCESS, &state);
|
||||
}
|
||||
else if (optind >= argc)
|
||||
generic_usage(self_applet, EXIT_FAILURE);
|
||||
|
|
@ -215,23 +320,17 @@ ifupdown_main(int argc, char *argv[])
|
|||
if (entry == NULL)
|
||||
{
|
||||
fprintf(stderr, "%s: unknown interface %s\n", argv0, argv[idx]);
|
||||
return EXIT_FAILURE;
|
||||
return update_state_file_and_exit(EXIT_FAILURE, &state);
|
||||
}
|
||||
|
||||
iface = entry->data;
|
||||
}
|
||||
|
||||
if (!change_interface(iface, &collection, &state, ifname))
|
||||
return EXIT_FAILURE;
|
||||
if (!change_interface(iface, &collection, &state, ifname, true))
|
||||
return update_state_file_and_exit(EXIT_FAILURE, &state);
|
||||
}
|
||||
|
||||
if (!exec_opts.mock && !lif_state_write_path(&state, exec_opts.state_file))
|
||||
{
|
||||
fprintf(stderr, "%s: could not update %s\n", argv0, exec_opts.state_file);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
return update_state_file_and_exit(EXIT_SUCCESS, &state);
|
||||
}
|
||||
|
||||
struct if_applet ifup_applet = {
|
||||
|
|
|
|||
|
|
@ -21,10 +21,13 @@
|
|||
#include <getopt.h>
|
||||
#include "cmd/multicall.h"
|
||||
|
||||
#define DEFAULT_TIMEOUT 300
|
||||
|
||||
struct lif_execute_opts exec_opts = {
|
||||
.interfaces_file = INTERFACES_FILE,
|
||||
.executor_path = EXECUTOR_PATH,
|
||||
.state_file = STATE_FILE
|
||||
.state_file = STATE_FILE,
|
||||
.timeout = DEFAULT_TIMEOUT,
|
||||
};
|
||||
|
||||
static void
|
||||
|
|
@ -68,19 +71,29 @@ set_no_lock(const char *opt_arg)
|
|||
}
|
||||
|
||||
static void
|
||||
no_op(const char *opt_arg)
|
||||
set_force(const char *opt_arg)
|
||||
{
|
||||
(void) opt_arg;
|
||||
exec_opts.force = true;
|
||||
}
|
||||
|
||||
static void
|
||||
set_timeout(const char *opt_arg)
|
||||
{
|
||||
exec_opts.timeout = atoi(opt_arg);
|
||||
if (exec_opts.timeout < 0)
|
||||
exec_opts.timeout = DEFAULT_TIMEOUT;
|
||||
}
|
||||
|
||||
static struct if_option exec_options[] = {
|
||||
{'f', "force", NULL, "force (de)configuration", false, no_op},
|
||||
{'f', "force", NULL, "force (de)configuration", false, set_force},
|
||||
{'i', "interfaces", "interfaces FILE", "use FILE for interface definitions", true, set_interfaces_file},
|
||||
{'l', "no-lock", NULL, "do not use a lockfile to serialize state changes", false, set_no_lock},
|
||||
{'n', "no-act", NULL, "do not actually run any commands", false, set_no_act},
|
||||
{'v', "verbose", NULL, "show what commands are being run", false, set_verbose},
|
||||
{'E', "executor-path", "executor-path PATH", "use PATH for executor directory", true, set_executor_path},
|
||||
{'S', "state-file", "state-file FILE", "use FILE for state", true, set_state_file},
|
||||
{'T', "timeout", "timeout TIMEOUT", "wait TIMEOUT seconds for executors to complete", true, set_timeout},
|
||||
};
|
||||
|
||||
struct if_option_group exec_option_group = {
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ set_include_pattern(const char *opt_arg)
|
|||
static void
|
||||
set_exclude_pattern(const char *opt_arg)
|
||||
{
|
||||
match_opts.include_pattern = opt_arg;
|
||||
match_opts.exclude_pattern = opt_arg;
|
||||
}
|
||||
|
||||
static struct if_option match_options[] = {
|
||||
|
|
|
|||
|
|
@ -36,6 +36,10 @@ extern struct if_applet ifdown_applet;
|
|||
extern struct if_applet ifctrstat_applet;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_IFPARSE
|
||||
extern struct if_applet ifparse_applet;
|
||||
#endif
|
||||
|
||||
struct if_applet ifupdown_applet;
|
||||
const struct if_applet *self_applet = NULL;
|
||||
|
||||
|
|
@ -46,6 +50,9 @@ struct if_applet *applet_table[] = {
|
|||
#ifdef CONFIG_IFUPDOWN
|
||||
&ifdown_applet,
|
||||
#endif
|
||||
#ifdef CONFIG_IFPARSE
|
||||
&ifparse_applet,
|
||||
#endif
|
||||
#ifdef CONFIG_IFQUERY
|
||||
&ifquery_applet,
|
||||
#endif
|
||||
|
|
@ -55,7 +62,7 @@ struct if_applet *applet_table[] = {
|
|||
&ifupdown_applet,
|
||||
};
|
||||
|
||||
int
|
||||
static int
|
||||
applet_cmp(const void *a, const void *b)
|
||||
{
|
||||
const char *key = a;
|
||||
|
|
@ -66,12 +73,16 @@ applet_cmp(const void *a, const void *b)
|
|||
|
||||
void multicall_usage(int status) __attribute__((noreturn));
|
||||
|
||||
struct if_applet ifupdown_applet;
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
argv0 = basename(argv[0]);
|
||||
const struct if_applet **app;
|
||||
|
||||
lif_config_load(CONFIG_FILE);
|
||||
|
||||
app = bsearch(argv0, applet_table,
|
||||
ARRAY_SIZE(applet_table), sizeof(*applet_table),
|
||||
applet_cmp);
|
||||
|
|
@ -83,12 +94,14 @@ main(int argc, char *argv[])
|
|||
}
|
||||
|
||||
self_applet = *app;
|
||||
process_options(*app, argc, argv);
|
||||
|
||||
return (*app)->main(argc, argv);
|
||||
if (self_applet != &ifupdown_applet)
|
||||
process_options(*app, argc, argv);
|
||||
|
||||
return self_applet->main(argc, argv);
|
||||
}
|
||||
|
||||
int
|
||||
static int
|
||||
multicall_main(int argc, char *argv[])
|
||||
{
|
||||
if (argc < 2)
|
||||
|
|
@ -97,24 +110,23 @@ multicall_main(int argc, char *argv[])
|
|||
return main(argc - 1, argv + 1);
|
||||
}
|
||||
|
||||
struct if_applet ifupdown_applet;
|
||||
|
||||
void
|
||||
multicall_usage(int status)
|
||||
{
|
||||
fprintf(stderr, "usage: ifupdown <applet> [options]\n");
|
||||
fprintf(stderr,
|
||||
PACKAGE_NAME " " PACKAGE_VERSION "\n"
|
||||
"usage: ifupdown <applet> [options]\n"
|
||||
"\n"
|
||||
"Built-in applets:\n");
|
||||
|
||||
fprintf(stderr, "\nBuilt-in applets:\n\t");
|
||||
for (size_t i = 0; i < ARRAY_SIZE(applet_table); i++)
|
||||
{
|
||||
if (i != 0)
|
||||
fprintf(stderr, ", ");
|
||||
if (applet_table[i] == &ifupdown_applet)
|
||||
continue;
|
||||
|
||||
fprintf(stderr, "%s", applet_table[i]->name);
|
||||
fprintf(stderr, " %-10s %s\n", applet_table[i]->name, applet_table[i]->desc);
|
||||
}
|
||||
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
exit(status);
|
||||
}
|
||||
|
||||
|
|
|
|||
56
cmd/pretty-print-iface.c
Normal file
56
cmd/pretty-print-iface.c
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* cmd/pretty-print-iface.c
|
||||
* Purpose: interface pretty-printer (/e/n/i style)
|
||||
*
|
||||
* Copyright (c) 2020 Ariadne Conill <ariadne@dereferenced.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* This software is provided 'as is' and without any warranty, express or
|
||||
* implied. In no event shall the authors be liable for any damages arising
|
||||
* from the use of this software.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "libifupdown/libifupdown.h"
|
||||
#include "cmd/multicall.h"
|
||||
#include "cmd/pretty-print-iface.h"
|
||||
|
||||
void
|
||||
prettyprint_interface_eni(struct lif_interface *iface)
|
||||
{
|
||||
if (!lif_lifecycle_query_dependents(&exec_opts, iface, iface->ifname))
|
||||
return;
|
||||
|
||||
if (iface->is_auto)
|
||||
printf("auto %s\n", iface->ifname);
|
||||
|
||||
printf("%s %s\n", iface->is_template ? "template" : "iface", iface->ifname);
|
||||
|
||||
struct lif_node *iter;
|
||||
LIF_DICT_FOREACH(iter, &iface->vars)
|
||||
{
|
||||
struct lif_dict_entry *entry = iter->data;
|
||||
|
||||
if (!strcmp(entry->key, "address"))
|
||||
{
|
||||
struct lif_address *addr = entry->data;
|
||||
char addr_buf[512];
|
||||
|
||||
if (!lif_address_unparse(addr, addr_buf, sizeof addr_buf, true))
|
||||
{
|
||||
printf(" # warning: failed to unparse address\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
printf(" %s %s\n", entry->key, addr_buf);
|
||||
}
|
||||
else
|
||||
printf(" %s %s\n", entry->key, (const char *) entry->data);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
23
cmd/pretty-print-iface.h
Normal file
23
cmd/pretty-print-iface.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* cmd/pretty-print-iface.h
|
||||
* Purpose: interface pretty-printer (/e/n/i style)
|
||||
*
|
||||
* Copyright (c) 2020 Ariadne Conill <ariadne@dereferenced.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* This software is provided 'as is' and without any warranty, express or
|
||||
* implied. In no event shall the authors be liable for any damages arising
|
||||
* from the use of this software.
|
||||
*/
|
||||
|
||||
#ifndef IFUPDOWN_CMD_PRETTY_PRINT_IFACE_H__GUARD
|
||||
#define IFUPDOWN_CMD_PRETTY_PRINT_IFACE_H__GUARD
|
||||
|
||||
#include "libifupdown/libifupdown.h"
|
||||
|
||||
extern void prettyprint_interface_eni(struct lif_interface *iface);
|
||||
|
||||
#endif
|
||||
15
dist/debian/ifupdown-ng.networking.service
vendored
Normal file
15
dist/debian/ifupdown-ng.networking.service
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
[Unit]
|
||||
Description=ifupdown-ng networking initialization
|
||||
Documentation=man:interfaces(5) man:ifup(8) man:ifdown(8)
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
RemainAfterExit=yes
|
||||
SyslogIdentifier=networking
|
||||
TimeoutStopSec=30s
|
||||
ExecStart=/usr/share/ifupdown-ng/sbin/networking start
|
||||
ExecStop=/usr/share/ifupdown-ng/sbin/networking stop
|
||||
ExecRestart=/usr/share/ifupdown-ng/sbin/networking restart
|
||||
|
||||
[Install]
|
||||
WantedBy=basic.target network.target multi-user.target network-online.target
|
||||
68
dist/debian/networking
vendored
Normal file
68
dist/debian/networking
vendored
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# Wrapper script for networking set up and teardown via unit file
|
||||
#
|
||||
# Thu, 01 Oct 2020 22:47:43 +0200
|
||||
# -- Maximilian Wilhelm <max@sdn.clinic>
|
||||
#
|
||||
|
||||
STATE_DIR="/run/ifsate"
|
||||
|
||||
# Make sure the state dir is present
|
||||
if [ ! -d "${STATE_DIR}" ]; then
|
||||
mkdir "${STATE_DIR}"
|
||||
fi
|
||||
|
||||
# Check for require binaries
|
||||
if [ ! -x /sbin/ifup -o ! -x /sbin/ifdown ]; then
|
||||
echo "ifup and/or ifdown not found!" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Apply defaults if present (verbose mode, kill switch, etc.)
|
||||
CONFIGURE_INTERFACES=yes
|
||||
|
||||
if [ -f /etc/default/networking ]; then
|
||||
. /etc/default/networking
|
||||
fi
|
||||
|
||||
ARGS=""
|
||||
if [ "${VERBOSE}" = yes ]; then
|
||||
ARGS="-v"
|
||||
fi
|
||||
|
||||
# Let's go
|
||||
case "$1" in
|
||||
start)
|
||||
if [ "${CONFIGURE_INTERFACES}" = no ]; then
|
||||
echo "Not configuring network interfaces, see /etc/default/networking"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
ifup -a ${ARGS}
|
||||
;;
|
||||
|
||||
stop)
|
||||
if [ "${SKIP_DOWN_AT_SYSRESET}" = "yes" ] && systemctl list-jobs | egrep -q '(shutdown|reboot|halt|poweroff)\.target'; then
|
||||
echo ${NAME}':' "Skipping deconfiguring network interfaces"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
ifdown -a ${ARGS}
|
||||
;;
|
||||
|
||||
restart)
|
||||
ifupdown_init
|
||||
ifdown -a ${ARGS}
|
||||
ifup -a ${ARGS}
|
||||
;;
|
||||
|
||||
# reload missing here!
|
||||
|
||||
*)
|
||||
echo "Usage: $0 {start|stop|restart}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
13
dist/debian/networking.default
vendored
Normal file
13
dist/debian/networking.default
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#
|
||||
# Defaults for ifupdown-ng networking service
|
||||
#
|
||||
|
||||
# Change the below to "yes" if you want ifup/ifdown and it's executors to be
|
||||
# verbose about what's going on
|
||||
VERBOSE="no"
|
||||
|
||||
# Set to "yes" if you want to skip deconfiguring all interfaces during system
|
||||
# reboot and shutdown. This might be of interest in large scale deployments,
|
||||
# where you might not want to wait for interface deconfiguration to speed up
|
||||
# shutdown/reboot.
|
||||
SKIP_DOWN_AT_SYSRESET="yes"
|
||||
56
dist/ifupdown-ng.conf.example
vendored
Normal file
56
dist/ifupdown-ng.conf.example
vendored
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
# This is an example configuration file for ifupdown-ng, which allows
|
||||
# the system administrator to configure the behaviour of ifupdown-ng.
|
||||
#
|
||||
# The settings specified here are the defaults of ifupdown-ng.
|
||||
|
||||
# allow_addon_scripts:
|
||||
# Enable support for /etc/if-X.d addon scripts. These are used for
|
||||
# compatibility with legacy setups, and may be disabled for performance
|
||||
# improvements in setups where only ifupdown-ng executors are used.
|
||||
# Valid values are 0 and 1, the default is 1.
|
||||
allow_addon_scripts = 1
|
||||
|
||||
# allow_any_iface_as_template:
|
||||
# Enable any interface to act as a template for another interface.
|
||||
# This is presently the default, but is deprecated. An admin may choose
|
||||
# to disable this setting in order to require inheritance from specified
|
||||
# templates. Valid values are 0 and 1, the default is 1.
|
||||
allow_any_iface_as_template = 1
|
||||
|
||||
# auto_executor_selection:
|
||||
# Automatically determine which executors are needed to bring up an
|
||||
# interface. An admin may choose to disable this setting and explicitly
|
||||
# define which executors to use with `use` statements.
|
||||
# Valid values are 0 and 1, the default is 1.
|
||||
auto_executor_selection = 1
|
||||
|
||||
# compat_create_interfaces:
|
||||
# Denotes where or not to create interfaces when compat_* settings are
|
||||
# active and it would be necessary to create an interface to be fully
|
||||
# compliant. This could happen when inheriting bridge VLAN settings to
|
||||
# an interface within a bridges bridge-ports setting but no interface
|
||||
# stanza is found. Valid values are 0 and 1, the default is 1.
|
||||
compat_create_interfaces = 1
|
||||
|
||||
# compat_ifupdown2_bridge_ports_inherit_vlans:
|
||||
# In ifupdown2 <bridge-vids> as well as the <bridge-pvid> set on a bridge
|
||||
# interface will be inherited by all member ports if not set explicitly.
|
||||
# When set to 1 ifupdown-ng behaves the same way and will internally copy
|
||||
# both options from the bridge member ports if they are not set on the
|
||||
# member port. Valid values are 0 and 1, the default is 1.
|
||||
compat_ifupdown2_bridge_ports_inherit_vlans = 1
|
||||
|
||||
# implicit_template_conversion:
|
||||
# In some legacy configs, a template may be declared as an iface, and
|
||||
# ifupdown-ng automatically converts those declarations to a proper
|
||||
# template. If this setting is disabled, inheritance will continue to
|
||||
# work against non-template interfaces without converting them to a
|
||||
# template. Valid values are 0 and 1, the default is 1.
|
||||
implicit_template_conversion = 1
|
||||
|
||||
# use_hostname_for_dhcp:
|
||||
# Automatically learn the hostname property, used for DHCP configuration
|
||||
# by querying the system hostname using uname(2). This is basically
|
||||
# equivalent to `hostname $(hostname)` without having to specify any
|
||||
# configuration. Valid values are 0 and 1, the default is 1.
|
||||
use_hostname_for_dhcp = 1
|
||||
8
dist/openrc/networking.confd
vendored
Normal file
8
dist/openrc/networking.confd
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
# Sets the path used for the interface definitions.
|
||||
#cfgfile="/etc/network/interfaces"
|
||||
|
||||
# Sets the path used for the state database.
|
||||
#ifstate="/run/ifstate"
|
||||
|
||||
# Skip taking down networking while shutting down.
|
||||
#keep_network="YES"
|
||||
70
dist/openrc/networking.initd
vendored
Normal file
70
dist/openrc/networking.initd
vendored
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
#!/sbin/openrc-run
|
||||
|
||||
: ${cfgfile:="/etc/network/interfaces"}
|
||||
ifstate=/run/ifstate
|
||||
|
||||
single_iface="${RC_SVCNAME#*.}"
|
||||
if [ "$single_iface" = "$RC_SVCNAME" ]; then
|
||||
single_iface=
|
||||
fi
|
||||
|
||||
depend() {
|
||||
need localmount
|
||||
want dev-settle
|
||||
after bootmisc hwdrivers modules
|
||||
provide net
|
||||
keyword -jail -prefix -vserver -docker
|
||||
}
|
||||
|
||||
# find interfaces we want to start
|
||||
find_ifaces() {
|
||||
if [ -n "$single_iface" ]; then
|
||||
echo $single_iface
|
||||
else
|
||||
ifquery -L -a -i "$cfgfile"
|
||||
fi
|
||||
}
|
||||
|
||||
# return the list of interfaces we should try stop
|
||||
find_running_ifaces() {
|
||||
if [ -n "$single_iface" ]; then
|
||||
echo $single_iface
|
||||
else
|
||||
ifquery -r -i "$cfgfile" -S "$ifstate"
|
||||
fi
|
||||
}
|
||||
|
||||
start() {
|
||||
local iface= ret=1
|
||||
ebegin "Starting networking"
|
||||
eindent
|
||||
for iface in $(find_ifaces); do
|
||||
local r=0
|
||||
ebegin "$iface"
|
||||
if ! ifup -i "$cfgfile" -S "$ifstate" $iface >/dev/null; then
|
||||
ifdown -f -i "$cfgfile" -S "$ifstate" $iface >/dev/null 2>&1
|
||||
r=1
|
||||
fi
|
||||
# atleast one interface needs to be started for action
|
||||
# to be success
|
||||
eend $r && ret=0
|
||||
done
|
||||
eoutdent
|
||||
return $ret
|
||||
}
|
||||
|
||||
stop() {
|
||||
local iface=
|
||||
# Don't stop the network at shutdown.
|
||||
yesno ${keep_network:-YES} && yesno $RC_GOINGDOWN && return 0
|
||||
|
||||
ebegin "Stopping networking"
|
||||
eindent
|
||||
for iface in $(find_running_ifaces); do
|
||||
ebegin "$iface"
|
||||
ifdown -i "$cfgfile" -S "$ifstate" -f $iface >/dev/null
|
||||
eend $?
|
||||
done
|
||||
eoutdent
|
||||
return 0
|
||||
}
|
||||
|
|
@ -20,6 +20,10 @@ in order of importance:
|
|||
database, which contains information about what
|
||||
interfaces should be configured.
|
||||
|
||||
* `/etc/network/ifupdown-ng.conf`: the main configuration
|
||||
file which controls ifupdown-ng's behaviour. See the
|
||||
*ifupdown-ng Configuration* section below.
|
||||
|
||||
* `/run/ifstate`: the interface state file, which denotes
|
||||
what physical interfaces are configured, and what
|
||||
interface definition they are configured as.
|
||||
|
|
@ -38,7 +42,59 @@ in order of importance:
|
|||
All configuration examples in this guide concern the
|
||||
`/etc/network/interfaces` file.
|
||||
|
||||
## Basic Configuration
|
||||
## ifupdown-ng Configuration
|
||||
|
||||
ifupdown-ng allows to configure some parts of it's behaviour.
|
||||
Currently the following settings are supported in
|
||||
`/etc/network/ifupdown-ng.conf`:
|
||||
|
||||
* `allow_addon_scripts`: Enable support for /etc/if-X.d addon scripts.
|
||||
These are used for compatibility with legacy setups, and may be
|
||||
disabled for performance improvements in setups where only
|
||||
ifupdown-ng executors are used. Valid values are `0` and `1`,
|
||||
default is `1`.
|
||||
|
||||
* `allow_any_iface_as_template`: Enable any interface to act as a
|
||||
template for another interface. This is presently the default,
|
||||
but is deprecated. An admin may choose to disable this setting
|
||||
in order to require inheritance from specified templates.
|
||||
Valid values are `0` and `1`, the default is `1`.
|
||||
|
||||
* `auto_executor_selection`: Automatically select executors based
|
||||
on the presence of their config options. An admin may choose to
|
||||
disable this setting in order to require explicitly enabling
|
||||
executors through `use` statements. Valid values are `0` and `1`,
|
||||
the default is `1`.
|
||||
|
||||
* `compat_create_interfaces`:
|
||||
Denotes where or not to create interfaces when compat\_* settings are
|
||||
active and it would be necessary to create an interface to be fully
|
||||
compliant. This could happen when inheriting bridge VLAN settings to
|
||||
an interface within a bridges bridge-ports setting but no interface
|
||||
stanza is found. Valid values are `0` and `1`, the default is `1`.
|
||||
|
||||
* `compat_ifupdown2_bridge_ports_inherit_vlans`: In ifupdown2 `bridge-vids`
|
||||
as well as the <bridge-pvid> set on a bridge interface will be inherited
|
||||
by all member ports if not set explicitly. When set to `1` ifupdown-ng
|
||||
behaves the same way and will internally copy both options from the
|
||||
bridge member ports if they are not set on the member port.
|
||||
Valid values are `0` and `1`, the default is `1`.
|
||||
|
||||
* `implicit_template_conversion`: In some legacy configs, a template
|
||||
may be declared as an iface, and ifupdown-ng automatically converts
|
||||
those declarations to a proper template. If this setting is
|
||||
disabled, inheritance will continue to work against non-template
|
||||
interfaces without converting them to a template. Valid values
|
||||
are `0` and `1`, the default is `1`.
|
||||
|
||||
* `use_hostname_for_dhcp`: A common configuration pattern with DHCP
|
||||
interfaces is to use `hostname $(hostname)`. If this setting is
|
||||
enabled, the `hostname` property will default to the system
|
||||
hostname. Valid values are `0` and `1`, the default is `1`.
|
||||
|
||||
## Interface Configuration
|
||||
|
||||
### Basic Configuration
|
||||
|
||||
To begin with, lets look at a basic configuration for a
|
||||
desktop computer. This scenario involves using the DHCP
|
||||
|
|
@ -71,7 +127,7 @@ iface eth0
|
|||
use dhcp
|
||||
```
|
||||
|
||||
## IPv6 RA Configuration
|
||||
### IPv6 RA Configuration
|
||||
|
||||
With IPv6, stateless auto-configuration is typically used to
|
||||
configure network interfaces. If you are not interested in
|
||||
|
|
@ -85,7 +141,7 @@ iface eth0
|
|||
use ipv6-ra
|
||||
```
|
||||
|
||||
## Static Configuration
|
||||
### Static Configuration
|
||||
|
||||
We can use the `static` executor to configure static IPv4 and
|
||||
IPv6 addresses. If you use the `address` keyword, the `static`
|
||||
|
|
@ -98,11 +154,11 @@ iface eth0
|
|||
gateway 203.0.113.1
|
||||
```
|
||||
|
||||
### Multi-homing
|
||||
#### Multiple Addresses
|
||||
|
||||
A typical scenario on servers is multi-homing, where a server
|
||||
has multiple IP addresses on a single interface. In this case
|
||||
you simply add additional `address` lines like this:
|
||||
A typical scenario on servers is where a server has multiple
|
||||
IP addresses on a single interface. In this case you simply
|
||||
add additional `address` lines like this:
|
||||
|
||||
```
|
||||
auto eth0
|
||||
|
|
@ -113,7 +169,7 @@ iface eth0
|
|||
gateway 203.0.113.1
|
||||
```
|
||||
|
||||
### Dual-stack configurations
|
||||
#### Dual-stack configurations
|
||||
|
||||
Another typical scenario for servers is to run a dual-stack
|
||||
configuration, where interfaces have both an IPv4 and an IPv6
|
||||
|
|
@ -184,7 +240,7 @@ iface bond0
|
|||
[...]
|
||||
```
|
||||
|
||||
Is equivalent to:
|
||||
Is with respect to dependency equivalent to:
|
||||
|
||||
```
|
||||
auto bond0
|
||||
|
|
@ -215,6 +271,5 @@ used for an interface, use the ifquery(8) command.
|
|||
## Questions
|
||||
|
||||
If you have further questions about how to use ifupdown-ng to
|
||||
configure a specific scenario, drop by the [ifupdown-ng IRC channel][irc].
|
||||
|
||||
[irc]: irc://irc.as7007.net/#ifupdown-ng
|
||||
configure a specific scenario, drop by the
|
||||
[ifupdown-ng IRC channel](irc://irc.oftc.net/#ifupdown-ng).
|
||||
|
|
|
|||
|
|
@ -45,6 +45,10 @@ configured in the configuration database.
|
|||
*-S, --state-file* _FILE_
|
||||
Use _FILE_ as the state database.
|
||||
|
||||
*-T, --timeout* _TIMEOUT_
|
||||
Wait up to _TIMEOUT_ seconds for executors to complete before
|
||||
raising an error.
|
||||
|
||||
*-V, --version*
|
||||
Print the ifupdown-ng version and exit.
|
||||
|
||||
|
|
@ -54,8 +58,9 @@ configured in the configuration database.
|
|||
|
||||
# SEE ALSO
|
||||
|
||||
*ifup*(8)++
|
||||
*ifquery*(8)++
|
||||
*ifupdown-ng.conf*(5)
|
||||
*ifup*(8)
|
||||
*ifquery*(8)
|
||||
*interfaces*(5)
|
||||
|
||||
# AUTHORS
|
||||
|
|
|
|||
66
doc/ifparse.scd
Normal file
66
doc/ifparse.scd
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
ifparse(8)
|
||||
|
||||
# NAME
|
||||
|
||||
ifparse - redisplay interface configuration in different formats
|
||||
|
||||
# SYNOPSIS
|
||||
|
||||
*ifparse* [<_options_>...] <_interfaces_...>
|
||||
|
||||
*ifparse* -A|--all
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
*ifparse* is used to extract information from the interface configuration
|
||||
file. It is intended to be used to translate the interface configuration
|
||||
stanzas between different formats.
|
||||
|
||||
# OPTIONS
|
||||
|
||||
*-a, --auto*
|
||||
Only match interfaces that are marked as _auto_.
|
||||
|
||||
*-h, --help*
|
||||
Display supported options to ifquery.
|
||||
|
||||
*-i, --interfaces* _FILE_
|
||||
Use _FILE_ as the config database.
|
||||
|
||||
*-F, --format* _FORMAT_
|
||||
Use _FORMAT_ to determine what format to use. *ifupdown* and
|
||||
*yaml-raw* formats are available.
|
||||
|
||||
*-I, --include* _PATTERN_
|
||||
Include _PATTERN_ when matching against the config or state
|
||||
database.
|
||||
|
||||
*-U, --allow-undefined*
|
||||
Create virtual interfaces for any interfaces not explicitly
|
||||
defined in the configuration file. This is primarily useful
|
||||
for property queries.
|
||||
|
||||
*-S, --state-file* _FILE_
|
||||
Use _FILE_ as the state database.
|
||||
|
||||
*-T, --timeout* _TIMEOUT_
|
||||
Wait up to _TIMEOUT_ seconds for executors to complete before
|
||||
raising an error.
|
||||
|
||||
*-V, --version*
|
||||
Print the ifupdown-ng version and exit.
|
||||
|
||||
*-X, --exclude* _PATTERN_
|
||||
Exclude _PATTERN_ when matching against the config or state
|
||||
database.
|
||||
|
||||
# SEE ALSO
|
||||
|
||||
*ifup*(8)++
|
||||
*ifdown*(8)++
|
||||
*ifquery*(8)++
|
||||
*interfaces*(5)
|
||||
|
||||
# AUTHORS
|
||||
|
||||
Ariadne Conill <ariadne@dereferenced.org>
|
||||
|
|
@ -32,6 +32,10 @@ configuration file to the current format.
|
|||
*-p, --property* _PROPERTY_
|
||||
Print the values of matching properties for an interface.
|
||||
|
||||
*-r, --running*
|
||||
Print the interface names that are marked as running in
|
||||
the state database.
|
||||
|
||||
*-s, --state*
|
||||
Query the state database instead of the config database.
|
||||
|
||||
|
|
@ -50,9 +54,18 @@ configuration file to the current format.
|
|||
When listing interfaces, print their configuration in a format
|
||||
that is compatible with *interfaces*(5) files.
|
||||
|
||||
*-U, --allow-undefined*
|
||||
Create virtual interfaces for any interfaces not explicitly
|
||||
defined in the configuration file. This is primarily useful
|
||||
for property queries.
|
||||
|
||||
*-S, --state-file* _FILE_
|
||||
Use _FILE_ as the state database.
|
||||
|
||||
*-T, --timeout* _TIMEOUT_
|
||||
Wait up to _TIMEOUT_ seconds for executors to complete before
|
||||
raising an error.
|
||||
|
||||
*-V, --version*
|
||||
Print the ifupdown-ng version and exit.
|
||||
|
||||
|
|
|
|||
57
doc/ifstate.scd
Normal file
57
doc/ifstate.scd
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
ifstate(5)
|
||||
|
||||
# NAME
|
||||
|
||||
*/run/ifstate* - interface state database
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
The */run/ifstate* file describes the present state of the interface
|
||||
configuration -- namely, how many interfaces are up, how many
|
||||
dependencies each interface has which are up (the refcount), and
|
||||
whether or not an interface was explicitly brought up due to request
|
||||
or configuration.
|
||||
|
||||
# FILE SYNTAX
|
||||
|
||||
At a minimum, the */run/ifstate* file contains at least one column,
|
||||
the physical to logical interface mapping. This column is formatted
|
||||
as such:
|
||||
|
||||
```
|
||||
lo=lo
|
||||
eth0=eth0
|
||||
wlan0=work
|
||||
```
|
||||
|
||||
The left side of the mapping is the physical interface, while the right
|
||||
side is the logical interface. This field is required to be present.
|
||||
|
||||
The next field is the reference count. This is a number that reflects
|
||||
the number of *active* dependencies an interface has. As interfaces
|
||||
are brought up and down, the refcount may change. This field is
|
||||
optional.
|
||||
|
||||
The final field denotes whether or not an interface was brought up
|
||||
explicitly -- either by being marked as _auto_ or brought up manually
|
||||
using *ifup*(8). The contents of this field if present is the
|
||||
_explicit_ keyword.
|
||||
|
||||
# EXAMPLES
|
||||
|
||||
An example from a typical system with localhost, eth0 and a wireguard
|
||||
VPN:
|
||||
|
||||
```
|
||||
lo=lo 1 explicit
|
||||
eth0=eth0 2 explicit
|
||||
wg0=wg0 1 explicit
|
||||
```
|
||||
|
||||
# SEE ALSO
|
||||
|
||||
*interfaces*(5)
|
||||
|
||||
# AUTHORS
|
||||
|
||||
Ariadne Conill <ariadne@dereferenced.org>
|
||||
|
|
@ -48,6 +48,10 @@ configured in the configuration database.
|
|||
*-S, --state-file* _FILE_
|
||||
Use _FILE_ as the state database.
|
||||
|
||||
*-T, --timeout* _TIMEOUT_
|
||||
Wait up to _TIMEOUT_ seconds for executors to complete before
|
||||
raising an error.
|
||||
|
||||
*-V, --version*
|
||||
Print the ifupdown-ng version and exit.
|
||||
|
||||
|
|
@ -57,8 +61,9 @@ configured in the configuration database.
|
|||
|
||||
# SEE ALSO
|
||||
|
||||
*ifdown*(8)++
|
||||
*ifquery*(8)++
|
||||
*ifupdown-ng.conf*(5)
|
||||
*ifdown*(8)
|
||||
*ifquery*(8)
|
||||
*interfaces*(5)
|
||||
|
||||
# AUTHORS
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ protocol documented in this man page.
|
|||
|
||||
# PHASES
|
||||
|
||||
Executors are run to react to seven different phases and are not
|
||||
Executors are run to react to nine different phases and are not
|
||||
required to take any specific action. These phases are:
|
||||
|
||||
*depend*
|
||||
|
|
@ -24,6 +24,10 @@ required to take any specific action. These phases are:
|
|||
any dependencies, it may simply exit 0 without doing
|
||||
anything.
|
||||
|
||||
*create*
|
||||
Called before *pre-up*, to explicitly allow for interface
|
||||
creation if necessary.
|
||||
|
||||
*pre-up*
|
||||
Called before the interface is going to be brought up.
|
||||
|
||||
|
|
@ -42,6 +46,10 @@ required to take any specific action. These phases are:
|
|||
*post-down*
|
||||
Called after the interface was successfully taken down.
|
||||
|
||||
*destroy*
|
||||
Called after *post-down* to allow for explicitly
|
||||
destroying an interface if necessary.
|
||||
|
||||
# ENVIRONMENT
|
||||
|
||||
Executors are guaranteed to run with a core set of environment
|
||||
|
|
|
|||
76
doc/ifupdown-ng.conf.scd
Normal file
76
doc/ifupdown-ng.conf.scd
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
ifupdown-ng.conf(5)
|
||||
|
||||
# NAME
|
||||
|
||||
*ifupdown-ng.conf* - Global configuration file for ifupdown-ng
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
ifupdown-ng allows to configure some parts of it's behaviour via global
|
||||
configuration options.
|
||||
|
||||
# GENERAL CONFIGURATION OPTIONS
|
||||
|
||||
*allow_addon_scripts* _bool_
|
||||
Enable support for /etc/if-X.d addon scripts. These are used for
|
||||
compatibility with legacy setups, and may be disabled for
|
||||
performance improvements in setups where only ifupdown-ng executors
|
||||
are used. Valid values are _0_ and _1_, the default is _1_.
|
||||
|
||||
*auto_executor_selection* _bool_
|
||||
Automatically determine which executors to use. At present, this
|
||||
is done by inserting `use` statements for the namespace a config
|
||||
option has. The namespace is separated from the config option with
|
||||
a dash (`-`). Valid values are _0_ and _1_, the default is _1_.
|
||||
|
||||
*use_hostname_for_dhcp* _bool_
|
||||
Automatically learn the hostname property, used for DHCP
|
||||
configuration by querying the system hostname using uname(2).
|
||||
This is basically equivalent to `hostname $(hostname)` without
|
||||
having to specify any configuration. Valid values are _0_ and
|
||||
_1_, the default is _1_.
|
||||
|
||||
# TEMPLATE RELATED OPTIONS
|
||||
|
||||
*allow_any_iface_as_template* _bool_
|
||||
Enable any interface to act as a template for another interface.
|
||||
This is presently the default, but is deprecated. An admin may
|
||||
choose to disable this setting in order to require inheritance
|
||||
from specified templates. Valid values are _0_ and _1_, the
|
||||
default is _1_.
|
||||
|
||||
*implicit_template_conversion* _bool_
|
||||
In some legacy configs, a template may be declared as an iface, and
|
||||
ifupdown-ng automatically converts those declarations to a proper
|
||||
template. If this setting is disabled, inheritance will continue
|
||||
to work against non-template interfaces without converting them to
|
||||
a template. Valid values are _0_ and _1_, the default is _1_.
|
||||
|
||||
# COMPATIBILITY RELATED OPTIONS
|
||||
|
||||
*compat_create_interfaces* _bool_
|
||||
Denotes where or not to create interfaces when compat_\* settings are
|
||||
active and it would be necessary to create an interface to be fully
|
||||
compliant. This could happen when inheriting bridge VLAN settings to
|
||||
an interface within a bridges bridge-ports setting but no interface
|
||||
stanza is found. Valid values are _0_ and _1_, the default is _1_.
|
||||
|
||||
compat_ifupdown2_bridge_ports_inherit_vlans _bool_
|
||||
In ifupdown2 <bridge-vids> as well as the <bridge-pvid> set on a
|
||||
bridge interface will be inherited by all member ports if not set
|
||||
explicitly. When set to 1 ifupdown-ng behaves the same way and will
|
||||
internally copy both options from the bridge member ports if they
|
||||
are not set on the member port. Valid values are _0_ and _1_, the
|
||||
default is _1_.
|
||||
|
||||
# FILES
|
||||
|
||||
/etc/network/ifupdown-ng.conf
|
||||
|
||||
# SEE ALSO
|
||||
|
||||
*interfaces*(5)
|
||||
|
||||
# AUTHORS
|
||||
|
||||
Maximilian Wilhelm <max@sdn.clinic>
|
||||
87
doc/interfaces-batman.scd
Normal file
87
doc/interfaces-batman.scd
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
interfaces-batman(5)
|
||||
|
||||
# NAME
|
||||
|
||||
*interfaces-batman* - B.A.T.M.A.N. adv. extensions for the interfaces(5)
|
||||
file format
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
Better Approach To Mobile Ad-Hoc Networking (B.A.T.M.A.N.) advanced is
|
||||
a mesh protocol which provides an Ethernet overlay network over an
|
||||
Ethernet underlay. The overlay interface is called _meshif_ whereas
|
||||
underlay interfaces are called _hardif_.
|
||||
|
||||
It's supported in the Linux kernel and thus available in many Linux
|
||||
environments. The ifupdown-ng exectuor relies on the *batctl* tool
|
||||
being installed. Support for setting interface based hop-penalties
|
||||
required Linux Kernel 5.8 or later.
|
||||
|
||||
B.A.T.M.A.N. adv. adds 30-60 bytes of encapsulation overhead depending
|
||||
on wether netword coding is activated or not. This should be taken into
|
||||
consideration when setting up overlay networks, particularly on underlay
|
||||
networks with a conventional 1500 byte MTU.
|
||||
|
||||
See https://www.open-mesh.org/projects/open-mesh/wiki for more details
|
||||
and updates.
|
||||
|
||||
The following options allow to set up B.A.T.M.A.N. adv. interfaces.
|
||||
|
||||
# BATMAN-RELATED OPTIONS
|
||||
|
||||
*batman-ifaces* _list of interfaces_
|
||||
Specifies the underlay interfaces (hardifs) which should be
|
||||
configured for the B.A.T.M.A.N. adv. meshif defined within
|
||||
the iface stanza.
|
||||
|
||||
*batman-hop-penalty* _hop-penalty_
|
||||
The _hop-penalty_ defines the cost of traversing a node or an
|
||||
interface. The _hop-penalty_ is a numeric value between 0 and
|
||||
255. Historically a _hop-penalty_ could only be set on a meshif,
|
||||
since B.A.T.M.A.N adv. v2020.3 (included in Kernel 5.8) it can
|
||||
also be set on a per-interfaces (hardif) basis.
|
||||
|
||||
*batman-gw-mode* _gw-mode_
|
||||
Denotes the gateway mode which controls the role this node will
|
||||
play within this B.A.T.M.A.N. adv. instance. The mode can be
|
||||
_off_, _client_, or _server_.
|
||||
|
||||
*batman-distributed-arp-table* _mode_
|
||||
Activates or deactivates the Distributed ARP table (DAT) within
|
||||
this B.A.T.M.A.N. adv. instance. Valid values are _enable_ and
|
||||
_disable_.
|
||||
|
||||
*batman-multicast-mode* _mode_
|
||||
Activates or deactivates the multicast mode of this B.A.T.M.A.N.
|
||||
adv. instance. Valid values are _enable_ and _disable_.
|
||||
|
||||
# EXAMPLES
|
||||
|
||||
A B.A.T.M.A.N. adv. _meshif_:
|
||||
|
||||
```
|
||||
auto bat-pad-cty
|
||||
iface bat-pad-cty
|
||||
batman-ifaces dummy-pad-cty vlan1234
|
||||
batman-hop-penalty 5
|
||||
#
|
||||
hwaddress f2:00:c1:01:00:00
|
||||
mtu 1500
|
||||
```
|
||||
|
||||
A B.A.T.M.A.N. adv. member interfaces (_hardif_):
|
||||
|
||||
```
|
||||
auto vlan1234
|
||||
iface vlan1234
|
||||
mtu 1560
|
||||
batman-hop-penalty 10
|
||||
```
|
||||
|
||||
# SEE ALSO
|
||||
|
||||
*batctl*(8)
|
||||
|
||||
# AUTHORS
|
||||
|
||||
Maximilian Wilhelm <max@sdn.clinic>
|
||||
204
doc/interfaces-bond.scd
Normal file
204
doc/interfaces-bond.scd
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
interfaces-bond(5)
|
||||
|
||||
# NAME
|
||||
|
||||
*interfaces-bond* - Bonding/LAG extensions for the interfaces(5) file format
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
The Linux implementation for Ling Aggregation Groups (LAGs) is called
|
||||
_bonding_, whereas a LAG interface is called _bond_. The Linux bonding
|
||||
implementation supports active/passive setups, classical EtherChannels
|
||||
as well as LACP (802.3ad).
|
||||
|
||||
The following options set up bonding/LAG interfaces with ifupdown-ng.
|
||||
|
||||
See https://www.kernel.org/doc/Documentation/networking/bonding.rst and
|
||||
for more information.
|
||||
|
||||
# BOND-RELATED OPTIONS
|
||||
|
||||
A bond interface must have at least one member port set. All other
|
||||
options are optional.
|
||||
|
||||
*bond-members* _list of interfaces_
|
||||
Denotes the physical member interfaces to form this LAG. For
|
||||
compatiblity to ifupdown1 and ifupdown2 _slaves_ as well as
|
||||
_bond-slaves_ are an alias for this option. This option is
|
||||
required.
|
||||
|
||||
*bond-mode* _mode_
|
||||
Denotes the mode for this LAG. The _mode_ can be given as string
|
||||
or as numerical value. Valid values are _balance-rr_ (0),
|
||||
_active-backup_ (1), _balance-xor_ (2), _broadcast_ (3),
|
||||
_802.3ad_ (4), _balance-tlb_ (5), _balance-alb_ (6).
|
||||
The default is _balance-rr_.
|
||||
|
||||
*bond-xmit-hash-policy* _policy_
|
||||
Denotes the hash policy/algorithm used to distribute packets
|
||||
across the physical links. This only applies for modes
|
||||
_balance-alb_, _balance-tlb_, _balance-xor_, and _802.3ad_.
|
||||
The _policy_ can be given as string or as numerical value.
|
||||
Valid values are _layer2_ (0), _layer3+4_ (1), _layer2+3_ (2),
|
||||
_encap2+3_ (3), and _encap3+4_ (4). The default is _layer2_.
|
||||
|
||||
*bond-min-links* _number_
|
||||
Denotes the minimum number of available links before turning on
|
||||
carrier.
|
||||
|
||||
*bond-miimon* _interval_
|
||||
Denotes the MII link monitoring frequency in milliseconds.
|
||||
This determines how often the link state of each slave is
|
||||
inspected for link failures. A value of zero disables MII
|
||||
link monitoring. The default is 0.
|
||||
|
||||
*bond-use-carrier* _bool_
|
||||
Denotes wether miimon uses MII or ethtool ioctls vs. the
|
||||
netif_carrier_ok() call to determine member link status.
|
||||
A value of 1 enables the use of netif_carrier_ok(), a value of
|
||||
0 will use the deprecated MII / ETHTOOL ioctls. The default
|
||||
is 1.
|
||||
|
||||
*bond-updelay* _delay_
|
||||
Denotes the delay in milliseconds before considering link up,
|
||||
in milliseconds. The default is 0.
|
||||
|
||||
*bond-downdelay* _delay_
|
||||
Denotes the delay in milliseconds before considering link down,
|
||||
in milliseconds. The default is 0.
|
||||
|
||||
*bond-all-slaves-active* _bool_
|
||||
Denotes wether duplicate frames (received on inactive ports)
|
||||
should be dropped (0) or delivered (1). The default is 0.
|
||||
|
||||
*bond-packets-per-slave* _num_packets_
|
||||
Denotes the number of packets to transmit through a member
|
||||
before moving to the next one. When set to 0 then a slave is
|
||||
chosen at random. The valid range is 0 - 65535; the default
|
||||
value is 1. This option has effect only in balance-rr mode.
|
||||
|
||||
*bond-lp-interval* _interval_
|
||||
Denotes the interval in seconds between sending learning packets
|
||||
to each members peer switch. The valid range is 1 - 0x7fffffff;
|
||||
the default value is 1. This option has effect only in modes
|
||||
balance-tlb and balance-alb.
|
||||
|
||||
*bond-resend-igmp* _number_
|
||||
Denotes the number of IGMP membership reports to send after a
|
||||
link failover happend. The valid range is 0 - 255; a value of
|
||||
0 prevents the IGMP membership report from being issued in
|
||||
response to the failover event. The default is 1.
|
||||
This option is useful for bonding modes balance-rr, active-backup
|
||||
balance-tlb and balance-alb, in which a failover can switch the
|
||||
IGMP traffic from one slave to another.
|
||||
|
||||
# LACP-RELATED OPTIONS
|
||||
|
||||
The following options are only valid in LACP (802.3ad) mode.
|
||||
|
||||
*bond-lacp-rate* _rate_
|
||||
Denotes the _rate_ of LACPDU requested from the peer. The _rate_
|
||||
can be given as string or as numerical value. Valid values are
|
||||
slow (0) and fast (1). The default is slow.
|
||||
|
||||
*bond-ad-select* _mode_
|
||||
Denotes the 802.3ad aggregation selection logic. The _mode_ can
|
||||
be given as string or as numerical value. Valid values are
|
||||
_stable_ (0), _bandwidth_ (1) and _cound_ (2). The default is
|
||||
_stable_.
|
||||
|
||||
*bond-ad-actor-sys-prio* _priority_
|
||||
Denotes the LACP system priority. The allowed range is 1 - 65535.
|
||||
The default value is 65535.
|
||||
|
||||
*bond-ad-user-port-key* _key_
|
||||
Denotes the upper 10 bits of the port-key. he values can be from
|
||||
0 - 1023. The default is 0.
|
||||
|
||||
|
||||
# ACTIVE/BACKUP-RELATED OPTIONS
|
||||
|
||||
The following options are only valid in active/passive setups.
|
||||
|
||||
*bond-primary* _interface_
|
||||
Denotes the primary member interface The specified device will
|
||||
always be the active slave while it is available. The primary
|
||||
option is only valid for active-backup, balance-tlb and
|
||||
balance-alb mode.
|
||||
|
||||
*bond-primary-reselect* _policy_
|
||||
Denotes the reselection policy for the primary member interface.
|
||||
Valid values are _always_ (0), _better_ (1), and _failure_ (2).
|
||||
The default is _always_.
|
||||
|
||||
*bond-fail-over-mac* _mode_
|
||||
Denotes whether active-backup mode should set all member
|
||||
interfaces to the same MAC address at enslavement (the
|
||||
traditional behavior), or, when enabled, perform special
|
||||
handling of the bond's MAC address in accordance with the
|
||||
selected policy. Valid values are _none_ (0), _active_ (1),
|
||||
_follow_ (2). The default is _none_.
|
||||
|
||||
*bond-num-grat-arp* _count_
|
||||
Denotes the number of peer notifications (gratuitous ARPs and
|
||||
unsolicited IPv6 Neighbor Advertisements) to be issued after a
|
||||
failover event. The valid range is 0 - 255; the default is 1.
|
||||
|
||||
*bond-num-unsol-na* _count_
|
||||
This is an alias for _bond-num-grat-arp_
|
||||
|
||||
*bond-peer-notif-delay* _interval_
|
||||
Denotes the interval in milliseconds, between each peer
|
||||
notification (gratuitous ARP and unsolicited IPv6 Neighbor
|
||||
Advertisement) issued after a failover event. The default
|
||||
is 0 which means to match the value of the link monitor
|
||||
interval.
|
||||
|
||||
# ARP-RELATED OPTIONS
|
||||
|
||||
The following options configure ARP link monitoring.
|
||||
The ARP monitor works by periodically checking the slave
|
||||
devices to determine whether they have sent or received
|
||||
traffic recently. Regular traffic is generated via ARP
|
||||
probes issued for the addresses specified by the
|
||||
_bond-arp-ip-target_ option.
|
||||
|
||||
*bond-arp-interval* _interval_
|
||||
Denotes the frequency in milliseconds to send ARP probes.
|
||||
|
||||
*bond-arp-ip-target* _IPv4 address_
|
||||
Denotes the IP addresses to use as ARP monitoring peers when
|
||||
_bond-arp-interval_ is > 0.
|
||||
|
||||
*bond-arp-validate* _mode_
|
||||
Specifies whether or not ARP probes and replies should be
|
||||
validated in any mode that supports arp monitoring, or whether
|
||||
non-ARP traffic should be filtered (disregarded) for link
|
||||
monitoring purposes. Valid values are _none_ (0), _active_ (1),
|
||||
_backup_ (2), _all_ (3), _filter_ (4), _filter_active_ (5), and
|
||||
_filter_backup_ (6). The default is _none_.
|
||||
|
||||
*bond-arp-all-targets* _mode_
|
||||
Denotes the number of _bond-arp-ip-targets_ that have to be
|
||||
reachable to consider the member interface to be up. Valid
|
||||
options are _any_ (0) and _all_ (1). The default is _any_.
|
||||
|
||||
# EXAMPLES
|
||||
|
||||
A bond using two links and LACP (802.3ad):
|
||||
|
||||
```
|
||||
auto bond0
|
||||
iface bond0
|
||||
bond-members eth0 eth1
|
||||
bond-mode 802.3ad
|
||||
bond-xmit-hash-policy layer3+4
|
||||
bond-min-links 1
|
||||
#
|
||||
address 192.0.2.42/24
|
||||
address 2001:db8::42/64
|
||||
```
|
||||
|
||||
# AUTHORS
|
||||
|
||||
Maximilian Wilhelm <max@sdn.clinic>
|
||||
173
doc/interfaces-bridge.scd
Normal file
173
doc/interfaces-bridge.scd
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
interfaces-bridge(5)
|
||||
|
||||
# NAME
|
||||
|
||||
*interfaces-bridge* - Bridge extensions for the interfaces(5) file format
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
Linux has support for Ethernet bridging interfaces which act like an
|
||||
Ethernet switch within the Linux Kernel. The following options allow
|
||||
to set up Ethernet bridges and adding configured interfaces to bridges.
|
||||
|
||||
See *ip-link*(8) for more details about the options listed below.
|
||||
|
||||
# BRIDGE-RELATED OPTIONS
|
||||
|
||||
*bridge-ports* _list of interfaces_
|
||||
A space separated list of interfaces which should be configured
|
||||
as member interfaces of this bridge. This option must be set
|
||||
for the bridge to be configured.
|
||||
|
||||
*bridge-hw* _MAC address_
|
||||
Denotes the _MAC address_ the bridge should use.
|
||||
|
||||
*bridge-ageing* _seconds_
|
||||
Denotes the time in seconds after which a MAC address will be
|
||||
removed from the Forwarding DataBase (FDB) after not having
|
||||
seen a frame with this source address.
|
||||
|
||||
*bridge-vlan-aware* _bool_
|
||||
Denotes wether or not the bridge should be aware of 802.1q VLANs.
|
||||
_bool_ can be given as _yes_/_no_ or _0_/_1_. The defaul is _no_.
|
||||
See related options for configuring vlan-aware bridges, below.
|
||||
|
||||
# SPANNING TREE RELATED BRIDGE OPTIONS
|
||||
|
||||
*bridge-stp* _state_
|
||||
Activates or deactivates IEEE 802.1d Spanning Tree Protocol
|
||||
(STP) support of the bridge. Valid values are _on_/_off_.
|
||||
|
||||
*bridge-bridgeprio* _priority_
|
||||
Sets the bridge's priority to _priority_. The priority value is
|
||||
a number between 0 and 65535. Lower priority values are better.
|
||||
The bridge with the lowest priority will be elected _root
|
||||
bridge_.
|
||||
|
||||
*bridge-fd* _seconds_
|
||||
Denotes the bridge forward delay in seconds. Valid values are
|
||||
between 2 and 30.
|
||||
|
||||
*bridge-hello* _seconds_
|
||||
Denotes the bridge hello time in seconds. Valid values are
|
||||
between 1 and 10.
|
||||
|
||||
*bridge-maxage* _seconds_
|
||||
Denotes the seconds until another bridge is considerd dead
|
||||
after reception of its last STP hello message. Valid values
|
||||
are between 6 and 40.
|
||||
|
||||
# OPTIONS FOR VLAN-AWARE-BRIDGES
|
||||
|
||||
The following options only have an effect on vlan-aware bridges and
|
||||
their ports.
|
||||
|
||||
All settings can be applied on the bridge interface itself and all member
|
||||
port iface stanzas. If applied on the bridge interface they take effect
|
||||
for the bridge interface itself and might be inherited to _bridge-ports_
|
||||
depending on the compatibility settings configured in *ifupdown-ng.conf*(5).
|
||||
|
||||
Configuring VLAN options on the bridge interface might be required for
|
||||
setting up a VLAN interface to one of the VLANs carried within the bridge.
|
||||
See the EXAMPLES section for an example for this scenario.
|
||||
|
||||
See *ifupdown-ng.conf*(5) for more information about compatiblity settings
|
||||
mentioned below.
|
||||
|
||||
*bridge-access* _vlan ID_
|
||||
Configure the given _vlan ID_ for untagged ingress and egress
|
||||
on this interface. The common description for this kind of
|
||||
configuration is called "access port".
|
||||
|
||||
*bridge-pvid* _vlan ID_
|
||||
Denotes the _vlan ID_ to considered a PVID at ingress.
|
||||
Any untagged frames received on this interface will be
|
||||
assigned to this _vlan ID_. The default PVID is _1_.
|
||||
|
||||
If compatibility to ifupdown2 bridge port inheritance is active
|
||||
a _bridge-pvid_ set on the bridge will be inherited to any
|
||||
interface configured in _bridge-ports_ without a _bridge-pvid_ set.
|
||||
|
||||
*bridge-vids* _list of vlan IDs_
|
||||
Denotes the space separated list of VLANs to be allowed tagged
|
||||
ingress/egress on this interface.
|
||||
|
||||
If compatibility to ifupdown2 bridge port inheritance is active
|
||||
a _bridge-vids_ set on the bridge will be inherited to any
|
||||
interface configured in _bridge-ports_ without _bridge-vids_ set.
|
||||
|
||||
*bridge-allow-untagged* _bool_
|
||||
Denotes wether or not the bridge should allow untagged frames on
|
||||
ingress as well as egress. If set to _no_ untagged frames will be
|
||||
droppped on ingress and none will be sent. _bool_ can be given as
|
||||
_yes_/_no_ or _0_/_1_. The defaul is _yes_.
|
||||
|
||||
# EXAMPLES
|
||||
|
||||
A simple layer 2 only bridge:
|
||||
|
||||
```
|
||||
auto br0
|
||||
iface br0
|
||||
bridge-ports eth0 veth-vm1 tap0
|
||||
bridge-fd 0
|
||||
bridge-stp off
|
||||
```
|
||||
|
||||
A bridge with layer 3 configuration:
|
||||
|
||||
```
|
||||
auto br0
|
||||
iface br0
|
||||
bridge-ports eth0 veth-vm1 tap0
|
||||
bridge-fd 0
|
||||
bridge-stp off
|
||||
#
|
||||
address 192.0.2.42/24
|
||||
address 2001:db8::42/64
|
||||
```
|
||||
|
||||
A layer 2 only vlan-aware bridge:
|
||||
|
||||
```
|
||||
auto bond0
|
||||
iface bond0
|
||||
bond-members eth0 eth1
|
||||
bridge-vids 23 42 84 1337
|
||||
|
||||
auto br0
|
||||
iface br0
|
||||
bridge-ports bond0
|
||||
```
|
||||
|
||||
A vlan-aware bridge with a VLAN interface on top:
|
||||
|
||||
```
|
||||
auto eth0
|
||||
iface eth0
|
||||
bridge-vids 23 42 84 1337
|
||||
|
||||
auto br0
|
||||
iface br0
|
||||
bridge-ports eth0
|
||||
bridge-vlan-aware yes
|
||||
bridge-vids 42
|
||||
|
||||
auto vlan42
|
||||
iface vlan42
|
||||
vlan-raw-device br0
|
||||
#
|
||||
address 192.0.2.42/24
|
||||
address 2001:db8::42/64
|
||||
```
|
||||
|
||||
# SEE ALSO
|
||||
|
||||
*interfaces*(5)
|
||||
*ifupdown-ng.conf*(5)
|
||||
*ip-link*(8)
|
||||
*bridge*(8)
|
||||
|
||||
# AUTHORS
|
||||
|
||||
Maximilian Wilhelm <max@sdn.clinic>
|
||||
48
doc/interfaces-forward.scd
Normal file
48
doc/interfaces-forward.scd
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
interfaces-forward(5)
|
||||
|
||||
# NAME
|
||||
|
||||
*interfaces-forward* - forwarding vocabulary for the interfaces(5) file format
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
Linux allows for configuration of IP packet forwarding behavior on a protocol
|
||||
and interface basis. The following options allow for this configuration.
|
||||
|
||||
# FORWARDING-RELATED OPTIONS
|
||||
|
||||
The forward executor will only modify the sysctl configuration if these options
|
||||
are provided, otherwise other mechanisms such as /etc/sysctl.conf may be used.
|
||||
|
||||
*forward-ipv4* _yes|no_
|
||||
Whether the interface should forward unicast IPv4 packets.
|
||||
|
||||
*forward-ipv6* _yes|no_
|
||||
Whether the interface should forward unicast IPv6 packets.
|
||||
|
||||
*forward-ipv4-mc* _yes|no_
|
||||
Whether the interface should forward multicast IPv4 packets.
|
||||
|
||||
*forward-ipv6-mc* _yes|no_
|
||||
Whether the interface should forward multicast IPv6 packets.
|
||||
|
||||
# EXAMPLES
|
||||
|
||||
The typical home router scenario will want to forward both IPv4 and IPv6
|
||||
packets:
|
||||
|
||||
```
|
||||
iface WAN
|
||||
use dhcp
|
||||
forward-ipv4 yes
|
||||
forward-ipv6 yes
|
||||
|
||||
iface LAN
|
||||
address 192.168.0.1/24
|
||||
forward-ipv4 yes
|
||||
forward-ipv6 yes
|
||||
```
|
||||
|
||||
# AUTHORS
|
||||
|
||||
Ariadne Conill <ariadne@dereferenced.org>
|
||||
40
doc/interfaces-mpls.scd
Normal file
40
doc/interfaces-mpls.scd
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
interfaces-mpls(5)
|
||||
|
||||
# NAME
|
||||
|
||||
*interfaces-mpls* - MPLS vocabulary for the interfaces(5) file format
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
Linux allows has support for MultiProtocol Label Switching (MPLS) for a while
|
||||
now. The following options allow for this configuration.
|
||||
|
||||
# MPLS-RELATED OPTIONS
|
||||
|
||||
The MPLS executor will only modify the sysctl configuration if these options
|
||||
are provided, otherwise other mechanisms such as /etc/sysctl.conf may be used.
|
||||
If MPLS is enabled on (at least) one interface the executor will load the
|
||||
_mpls_iptunnel_ kernel module.
|
||||
|
||||
Be aware that you have to set the _platform_labels_ sysctl to make MPLS work.
|
||||
See https://www.kernel.org/doc/Documentation/networking/mpls-sysctl.rst for
|
||||
more details on the MPLS related knobs in the Linux kernel.
|
||||
|
||||
|
||||
*mpls-enable* _yes|no_
|
||||
Control whether packets can be input on this interface. If disabled,
|
||||
packets carrying an MPLS label will be discarded without further
|
||||
processing.
|
||||
|
||||
# EXAMPLES
|
||||
|
||||
```
|
||||
iface eth0
|
||||
address 2001:db8:08:15::42/64
|
||||
#
|
||||
mpls-enable yes
|
||||
```
|
||||
|
||||
# AUTHORS
|
||||
|
||||
Maximilian Wilhelm <max@sdn.clinic>
|
||||
37
doc/interfaces-ppp.scd
Normal file
37
doc/interfaces-ppp.scd
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
interfaces-ppp(5)
|
||||
|
||||
# NAME
|
||||
|
||||
*interfaces-ppp* - PPP extensions for the interfaces(5) file format
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
The Point-to-Point Protocol (PPP) usually is used for dial-up lines,
|
||||
most common for over Digital Subscriber Lines (DSL) to connect to an
|
||||
Internet Service Provider (ISP). The following options allow to set
|
||||
up PPP dial-up connections.
|
||||
|
||||
# PPP-RELATED OPTIONS
|
||||
|
||||
*ppp-provider* _provider_
|
||||
Denotes the file name of the _provider_ configuration file
|
||||
within the _/etc/ppp/peers/_ directory which should be used
|
||||
to set up the PPP connection.
|
||||
|
||||
*ppp-physdev* _interfaces_
|
||||
Denotes the physical (underlay) interface which is used to
|
||||
set up the PPP connection.
|
||||
|
||||
# EXAMPLES
|
||||
|
||||
A PPP connection to _local-ISP_:
|
||||
|
||||
```
|
||||
auto ppp0
|
||||
iface ppp0
|
||||
ppp-provider local-ISP
|
||||
```
|
||||
|
||||
# AUTHORS
|
||||
|
||||
Maximilian Wilhelm <max@sdn.clinic>
|
||||
161
doc/interfaces-tunnel.scd
Normal file
161
doc/interfaces-tunnel.scd
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
interfaces-tunnel(5)
|
||||
|
||||
# NAME
|
||||
|
||||
*interfaces-tunnel* - Tunnel extensions for the interfaces(5) file format
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
The following options set up tunneling interfaces with ifupdown-ng.
|
||||
|
||||
# TUNNEL-RELATED OPTIONS
|
||||
|
||||
A tunnel interface must have a mode, remote IP and a local IP or device
|
||||
set, all other options are optional.
|
||||
|
||||
*tunnel-mode* _mode_
|
||||
Denotes the mode for this tunnel. Basically all tunnel modes supported
|
||||
by Linux / iproute2 are supported as well. This includes but is not
|
||||
limited to _gre_/_gretap_, _ip6gre_/_ip6gretap_, _ipip_/_ip6ip_/_sit_.
|
||||
|
||||
*tunnel-local* _IP_
|
||||
Denotes the IP address used as the local tunnel endpoint. According
|
||||
to the _tunnel-mode_ an IPv4 or IPv6 address has to be given.
|
||||
For compatiblity to ifupdown1 _local_ is an alias for this option.
|
||||
|
||||
*tunnel-local-dev* _interface_
|
||||
When the local IP address the tunnel should be established from isn't
|
||||
static and therefore might change (e.g. configured by DHCP or PPP) it
|
||||
might be desireable to just use the address configured on _interface_.
|
||||
When _tunnel-local-dev_ is given instead of _tunnel-local_ ifupdown-ng
|
||||
will try to determine the IP address set on the given _interface_ with
|
||||
respect to the address family required to set up a tunnel of the given
|
||||
_mode_ and use this to set up the tunnel.
|
||||
|
||||
*tunnel-remote* _IP_
|
||||
Denotes the IP address used as the remote tunnel endpoint. According
|
||||
to the _tunnel-mode_ an IPv4 or IPv6 address has to be given.
|
||||
For compatiblity to ifupdown1 _endpoint_ is an alias for this option.
|
||||
|
||||
*tunnel-physdev* _interface_
|
||||
Denotes the _interface_ the encapsulated packets should be sent out by.
|
||||
This comes in handy when using VRFs to denote that the local tunnel
|
||||
endpoint should be terminated in VRF _interface_ or the VRF associated
|
||||
with _interface_.
|
||||
|
||||
Note: Depending on the _mode_ of the tunnel either the VRF interface
|
||||
or the real underlay interface may have to given as _interface_.
|
||||
|
||||
*tunnel-ttl* _ttl_
|
||||
Denotes the TTL value to use in outgoing packets. _ttl_ is a number in the
|
||||
range 1 - 255 whereas 0 is a special value meaning that packets inherit the
|
||||
TTL value. The default for IPv4 tunnels is to inherit the TTL, for IPv6
|
||||
tunnels it's 64. For compatiblity to ifupdown1 _ttl_ is an alias for this option.
|
||||
|
||||
|
||||
|
||||
# IPIP/SIT-RELATED OPTIONS
|
||||
|
||||
*tunnel-encap* _encap_
|
||||
Denotes the type of secondary UDP encapsulation to use for this tunnel
|
||||
if any. Supported _encap_ values are _fou_, _gue_, and _none_.
|
||||
_fou_ indicates Foo-Over-UDP, _gue_ indicates Generic UDP Encapsulation.
|
||||
|
||||
# GRE-RELATED OPTIONS
|
||||
|
||||
*tunnel-encap* _encap_
|
||||
Denotes the type of secondary UDP encapsulation to use for this tunnel
|
||||
if any. Supported _encap_ values are _fou_, _gue_, and _none_.
|
||||
_fou_ indicates Foo-Over-UDP, _gue_ indicates Generic UDP Encapsulation.
|
||||
|
||||
*tunnel-key* _key_
|
||||
Denotes the_key to used for keyed GRE to allow multiple tunnels between
|
||||
the same two endpoints. _key_ is either a number or an IPv4 address-
|
||||
like dotted quad. The key parameter specifies the same key to use in both
|
||||
directions. The _tunnel-ikey_ and _tunnel-okey_ parameters specify different
|
||||
keys for input and output. For compatiblity to ifupdown1 _key_ is an alias
|
||||
for this option.
|
||||
|
||||
*tunnel-hoplimit* _ttl_
|
||||
Denotes the Hop Limit value to use in outgoing packets for _ip6gre_/_ip6gretap_
|
||||
tunnels.
|
||||
|
||||
*tunnel-ignore-df* _bool_
|
||||
Denotes wether to enable/disable IPv4 DF suppression on this tunnel. Normally
|
||||
datagrams that exceed the MTU will be fragmented; the presence of the DF flag
|
||||
inhibits this, resulting instead in an ICMP Unreachable (Fragmentation Required)
|
||||
message. Enabling this attribute causes the DF flag to be ignored.
|
||||
|
||||
*tunnel-ikey* _key_
|
||||
Denotes the key to used for keyed GRE for packets received. See _tunnel-key_
|
||||
for details.
|
||||
|
||||
*tunnel-okey* _key_
|
||||
Denotes the key to used for keyed GRE for packets sent out. See _tunnel-key_
|
||||
for details.
|
||||
|
||||
*tunnel-pmtudisc* _bool_
|
||||
Denotes wether to enable/disable Path MTU Discovery on this tunnel. It is
|
||||
enabled by default. Note that a fixed ttl is incompatible with this option:
|
||||
tunneling with a fixed ttl always makes pmtu discovery.
|
||||
|
||||
*tunnel-tos* _tos_
|
||||
Denotes the TOS value to use in outgoing packets.
|
||||
|
||||
|
||||
# EXAMPLES
|
||||
|
||||
A simple GRE tunnel
|
||||
|
||||
```
|
||||
auto gre0
|
||||
iface gre0
|
||||
tunnel-mode gre
|
||||
tunnel-remote 198.51.100.1
|
||||
tunnel-local 203.0.113.2
|
||||
#
|
||||
address 192.0.2.42/24
|
||||
address 2001:db8::42/64
|
||||
```
|
||||
|
||||
A GRE tunnel where the local IP is learned from _eth0_
|
||||
|
||||
```
|
||||
auto gre1
|
||||
iface gre1
|
||||
tunnel-mode gre
|
||||
tunnel-remote 198.51.100.1
|
||||
tunnel-local-dev eth0
|
||||
#
|
||||
address 192.0.2.42/24
|
||||
address 2001:db8::42/64
|
||||
```
|
||||
|
||||
A GRE tunnel which transfers encapasulated packets via _eth0_ which is part
|
||||
of a VRF.
|
||||
|
||||
```
|
||||
auto eth0
|
||||
iface eth0
|
||||
address 203.0.113.2/24
|
||||
gateway 203.0.113.1
|
||||
vrf vrf_external
|
||||
|
||||
auto tun-vrf
|
||||
iface tun-vrf
|
||||
tunnel-mode gre
|
||||
tunnel-remote 198.51.100.1
|
||||
tunnel-local 203.0.113.2
|
||||
tunnel-physdev eth0
|
||||
#
|
||||
address 192.0.2.42/24
|
||||
address 2001:db8::42/64
|
||||
|
||||
auto vrf_external
|
||||
iface vrf_external
|
||||
vrf-table 1023
|
||||
```
|
||||
|
||||
# AUTHORS
|
||||
|
||||
Maximilian Wilhelm <max@sdn.clinic>
|
||||
58
doc/interfaces-vrf.scd
Normal file
58
doc/interfaces-vrf.scd
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
interfaces-vrf(5)
|
||||
|
||||
# NAME
|
||||
|
||||
*interfaces-vrf* - VRF extensions for the interfaces(5) file format
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
Linux has support for Virtual Routing and Forwarding (VRF) instances
|
||||
since Kernel >= 4.4. The following options allow to set up VRFs and
|
||||
adding configured interfaces to VRFs.
|
||||
|
||||
Note that in the Linux Kernel VRFs are represented as network interfaces,
|
||||
too. See https://www.kernel.org/doc/Documentation/networking/vrf.rst for
|
||||
more details.
|
||||
|
||||
# VRF-RELATED OPTIONS
|
||||
|
||||
*vrf-table* _table id_
|
||||
The _id_ of the kernel routing table associated with this
|
||||
VRF interface. This parameter indicates that the interface
|
||||
where it is specified shall be a VRF.
|
||||
|
||||
*vrf* _vrf interface_
|
||||
The _vrf_ the interface should be assigned to. This parameter
|
||||
is specified on regular interfaces which should be within the
|
||||
given _vrf_.
|
||||
|
||||
# EXAMPLES
|
||||
|
||||
A VRF interface:
|
||||
|
||||
```
|
||||
auto vrf_external
|
||||
iface vrf_external
|
||||
vrf-table 1023
|
||||
```
|
||||
|
||||
A regular interface which should be within a VRF:
|
||||
|
||||
```
|
||||
auto eth0
|
||||
iface eth0
|
||||
address 192.2.0.42/24
|
||||
address 2001:db8::42/64
|
||||
gateway 192.2.0.1
|
||||
gateway 2001:db::1
|
||||
vrf vrf_external
|
||||
```
|
||||
|
||||
# SEE ALSO
|
||||
|
||||
*ip-vrf*(8)
|
||||
*ip-link*(8)
|
||||
|
||||
# AUTHORS
|
||||
|
||||
Maximilian Wilhelm <max@sdn.clinic>
|
||||
131
doc/interfaces-vxlan.scd
Normal file
131
doc/interfaces-vxlan.scd
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
interfaces-vxlan(5)
|
||||
|
||||
# NAME
|
||||
|
||||
*interfaces-vxlan* - VXLAN extensions for the interfaces(5) file format
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
Virtual eXtensible LAN (VXLAN) is an overlay network to carry Layer 2 over
|
||||
an IP network while accommodating a very large number of tenants. It is
|
||||
defined in RFC 7348.
|
||||
|
||||
Be aware that VXLAN encapsulation adds 50 bytes of overhead to the IP packet
|
||||
header (inner Ethernet header + VXLAN + UDP + IP). This should be taken into
|
||||
consideration when setting up overlay networks, particularly on underlay
|
||||
networks with a conventional 1500 byte MTU.
|
||||
|
||||
The following options set up VXLAN Tunnel EndPoints (VTEP) interfaces with
|
||||
ifupdown-ng.
|
||||
|
||||
See https://www.kernel.org/doc/Documentation/networking/vxlan.rst and
|
||||
https://vincent.bernat.ch/en/blog/2017-vxlan-linux for more information.
|
||||
|
||||
# VXLAN-RELATED OPTIONS
|
||||
|
||||
A VXLAN Virtual Tunnel Endpoint (VTEP) interface must an ID set. All
|
||||
other options are optional.
|
||||
|
||||
*vxlan-id* _VNI ID_
|
||||
Denotes the VXLAN Network Identifier (VNI) ID for this interface.
|
||||
This parameter is required for VTEP interfaces.
|
||||
|
||||
*vxlan-physdev* _interface_
|
||||
Specifies the physical ("underlay") device to use for tunnel
|
||||
endpoint communication. This is required for setups using
|
||||
multicast.
|
||||
|
||||
*vxlan-local-ip* _address_
|
||||
Specifies the source IP address to use in outgoing packets.
|
||||
For compatiblity with ifupdown2 _vxlan-local-tunnelip_ is an
|
||||
alias for this parameter.
|
||||
|
||||
*vxlan-peer-ips* _list of IP addresses_
|
||||
Specifies the unicast destination IP address(es) to use in outgoing
|
||||
packets when the destination link layer address is not known in
|
||||
the VXLAN device forwarding database. This option can be used to
|
||||
form Point-to-Point as well as Point-to-Multipoint VXLAN tunnels/
|
||||
overlays depending on how many peer IPs are given. If more than one
|
||||
IP address is given a Point-to-Multipoint overlay is being set up
|
||||
and ingress / head-end replication will be used by the Linux Kernel.
|
||||
This option cannot be used together with _vxlan-peer-group_ option.
|
||||
For compatiblity with ifupdown2 _vxlan-remoteip_ is an alias for this option
|
||||
and for compatibility with previos versions of ifupdown-ng _vxlan-remote-ip_
|
||||
is an alias for this option, too.
|
||||
|
||||
*vxlan-peer-group* _multicast group_
|
||||
Specifies the multicast group address to join, requires _vxlan-phsydev_
|
||||
to be set as well. This parameter cannot be specified in combination
|
||||
with the _vxlan-peer-ips_ parameter. For compatibility with ifupdown2
|
||||
_vxlan-svcnodeip_ is an alias for this option and for compatibility
|
||||
with previos version of ifupdown-ng _vxlan-remote-group_ is an alias, too.
|
||||
|
||||
*vxlan-learning* _on/off_
|
||||
Specifies if unknown source link layer addresses and IP addresses
|
||||
are entered into the VXLAN device forwarding database.
|
||||
|
||||
*vxlan-ageing* _seconds_
|
||||
Specifies the lifetime in seconds of FDB entries learnt by the kernel.
|
||||
|
||||
*vxlan-dstport* _port_
|
||||
Specifies the UDP destination port of the remote VXLAN tunnel endpoint.
|
||||
The default is 4789.
|
||||
|
||||
# EXAMPLES
|
||||
|
||||
A VTEP with multiple peers addressed via a multicast group:
|
||||
|
||||
```
|
||||
auto vx_v1001_padcty
|
||||
iface vx_v1001_padcty
|
||||
vxlan-id 655617
|
||||
vxlan-physdev vlan1001
|
||||
vxlan-remote-group 225.10.1.1
|
||||
#
|
||||
hwaddress f2:00:c1:01:10:01
|
||||
mtu 1560
|
||||
```
|
||||
|
||||
The same works just fine with IPv6 in the underlay:
|
||||
|
||||
```
|
||||
auto vx_v1400_padcty
|
||||
iface vx_v1400_padcty
|
||||
vxlan-id 917505
|
||||
vxlan-physdev vlan1400
|
||||
vxlan-peer-group ff42:1400::1
|
||||
#
|
||||
hwaddress f2:00:0d:01:14:00
|
||||
mtu 1560
|
||||
```
|
||||
|
||||
Note that the underlay must have an MTU of at least 1610 to
|
||||
carry the encapsulated packets of the two VTEPs above.
|
||||
|
||||
|
||||
A VTEP with one peer (unicast point-to-point configuration):
|
||||
|
||||
```
|
||||
auto vx_ptp1
|
||||
iface vx_ptp1
|
||||
vxlan-id 2342
|
||||
vxlan-local-ip 192.0.2.42
|
||||
vxlan-peer-ips 198.51.100.23
|
||||
#
|
||||
hwaddress f2:00:c1:01:10:01
|
||||
```
|
||||
|
||||
|
||||
A VTEP with multiple peers (unicast point-to-multipoint with ingress / head-end replication):
|
||||
|
||||
```
|
||||
auto vx_her
|
||||
iface vx_her
|
||||
vxlan-id 1337
|
||||
vxlan-local-ip 2001:db8:1::1
|
||||
vxlan-peer-ips 2001:db8:2::23 2001:db8:3::42 2001:db8:4::84
|
||||
```
|
||||
|
||||
# AUTHORS
|
||||
|
||||
Maximilian Wilhelm <max@sdn.clinic>
|
||||
63
doc/interfaces-wifi.scd
Normal file
63
doc/interfaces-wifi.scd
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
interfaces-wifi(5)
|
||||
|
||||
# NAME
|
||||
|
||||
*interfaces-wifi* - WiFi vocabulary for the interfaces(5) file format
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
Wi-Fi (the IEEE 802.11 family of protocols) is a commonly used wireless
|
||||
networking standard. The following options allow for configuration of
|
||||
Wi-Fi client interfaces.
|
||||
|
||||
WPA-secured networks are managed using *wpa_supplicant*(8), while insecure
|
||||
networks are managed directly with *iwconfig*(8).
|
||||
|
||||
# WIFI-RELATED OPTIONS
|
||||
|
||||
*wifi-config-path* _path_
|
||||
Denotes the absolute _path_ to a *wpa_supplicant* configuration file.
|
||||
If no path is given, _/run/wpa_supplicant.<interface>.conf_ will be
|
||||
used for a temporary configuration file. This option may not be used
|
||||
with other configuration options.
|
||||
|
||||
*wifi-ssid* _ssid_
|
||||
The SSID the Wi-Fi client should connect to.
|
||||
|
||||
*wifi-psk* _psk_
|
||||
The passphrase for connecting to the Wi-Fi network. If unset, the
|
||||
client will connect without WPA2 encryption.
|
||||
|
||||
# EXAMPLES
|
||||
|
||||
A typical setup may involve connecting to a home and work network. To
|
||||
achieve this, we can define a pair of virtual interfaces called *wifi-home*
|
||||
and *wifi-work*, which connect to their respective wifi networks:
|
||||
|
||||
```
|
||||
iface wifi-home
|
||||
use dhcp
|
||||
wifi-ssid HomeNetwork
|
||||
wifi-psk ExamplePassphrase
|
||||
|
||||
iface wifi-work
|
||||
use dhcp
|
||||
wifi-config-path /etc/network/wpa-work.conf
|
||||
```
|
||||
|
||||
The virtual interfaces can be used with *ifup* and *ifdown*:
|
||||
|
||||
```
|
||||
# ifup wlan0=wifi-home
|
||||
# ifdown wlan0
|
||||
# ifup wlan0=wifi-work
|
||||
```
|
||||
|
||||
# SEE ALSO
|
||||
|
||||
*iwconfig*(8)++
|
||||
*wpa_supplicant*(8)
|
||||
|
||||
# AUTHORS
|
||||
|
||||
Ariadne Conill <ariadne@dereferenced.org>
|
||||
56
doc/interfaces-wireguard.scd
Normal file
56
doc/interfaces-wireguard.scd
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
interfaces-wireguard(5)
|
||||
|
||||
# NAME
|
||||
|
||||
*interfaces-wireguard* - Wireguard extensions for the interfaces(5) file format
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
Wireguard is a comtemporary in-Kernel layer 3 VPN protocol implementation
|
||||
which aims to provide fast and secure tunnels. The following options
|
||||
allow to set up Wireguard VPN tunnels.
|
||||
|
||||
# WIREGUARD-RELATED OPTIONS
|
||||
|
||||
*wireguard-config-path* _path_
|
||||
Denotes the absolute _path_ to the Wireguard configuration file.
|
||||
If no path is given, _/etc/wireguard/<interface>.conf_ will be
|
||||
used. In the latter case _use wireguard_ has to be explicitly
|
||||
set to the interface configuration.
|
||||
|
||||
Be aware that the given configuration file will be loaded using
|
||||
*wg setconf* and not with *wg-quick*. The file format for both
|
||||
tools isn't compatible so you have to make sure you provide a
|
||||
valid configuration file for the *wg* tool. If you already have
|
||||
a configuration file for *wg-quick* you can set up the tunnel
|
||||
manually once and then dump the configuration using *wg showconf*
|
||||
and save this to _path_.
|
||||
|
||||
|
||||
# EXAMPLES
|
||||
|
||||
A Wireguard VPN tunnel with explicit configuration file specified
|
||||
|
||||
```
|
||||
auto wg-foo
|
||||
iface wg-foo
|
||||
wireguard-config-path /etc/wireguard/foo.conf
|
||||
#
|
||||
address 192.0.2.23/42
|
||||
address 2001:db8::23/64
|
||||
```
|
||||
|
||||
A Wireguard VPN tunnel with implicit configuration file:
|
||||
|
||||
```
|
||||
auto wg-bar
|
||||
iface wg-bar
|
||||
use wireguard
|
||||
#
|
||||
address 192.0.2.23/42
|
||||
address 2001:db8::23/64
|
||||
```
|
||||
|
||||
# AUTHORS
|
||||
|
||||
Maximilian Wilhelm <max@sdn.clinic>
|
||||
|
|
@ -11,7 +11,7 @@ interfaces are configured. The file is processed by *ifquery*(8),
|
|||
*ifup*(8) and *ifdown*(8) to introspect and change system state.
|
||||
|
||||
In most cases, syntax from legacy implementations is supported as
|
||||
well, but that syntax is not discussed here.
|
||||
well, but that syntax is not discussed in detail here.
|
||||
|
||||
# FILE SYNTAX
|
||||
|
||||
|
|
@ -24,6 +24,8 @@ value combination that is related to an *object*. Triples which
|
|||
are not associated with an *object* are considered to be part
|
||||
of the root of the configuration tree.
|
||||
|
||||
All keywords are case-sensitive and are expected to be lower-case.
|
||||
|
||||
The following is a simple example of a stanza:
|
||||
|
||||
```
|
||||
|
|
@ -47,6 +49,16 @@ with an address of *203.0.113.2* and gateway of *203.0.113.1*.
|
|||
associated with the declaration will be stored inside
|
||||
_object_.
|
||||
|
||||
*source* _filename_
|
||||
Includes the file _filename_ as configuration data.
|
||||
|
||||
*source-directory* _directory_
|
||||
Includes the files in _directory_ as configuration data.
|
||||
|
||||
*template* _object_
|
||||
Begins a new declaration for _object_, like *iface*, except
|
||||
that _object_ is defined as a *template*.
|
||||
|
||||
# SUPPORTED KEYWORDS FOR OBJECT TRIPLES
|
||||
|
||||
Any keyword may be used inside an interface declaration block, but
|
||||
|
|
@ -54,11 +66,11 @@ the system will only respond to certain keywords by default:
|
|||
|
||||
*address* _address_
|
||||
Associates an IPv4 or IPv6 address in CIDR notation with
|
||||
the parent interface.
|
||||
|
||||
*gateway* _address_
|
||||
Associates an IPv4 or IPv6 address with the parent interface
|
||||
for use as a default route (gateway).
|
||||
the parent interface. If an IP address without a prefix
|
||||
length is given a given _netmask_ attribute is used if present.
|
||||
If neither a prefix length nor a _netmask_ are given a /24 or /64
|
||||
prefix length is presumed for IPv4 / IPv6 as of compatibility
|
||||
reasons to classic ifupdown.
|
||||
|
||||
*netmask* _netmask_
|
||||
Associates a fallback netmask with the parent interface for
|
||||
|
|
@ -66,19 +78,46 @@ the system will only respond to certain keywords by default:
|
|||
is for backwards compatibility and should not be used in new
|
||||
deployments.
|
||||
|
||||
*point-to-point* _address_
|
||||
Sets the given IPv4 _address_ as the peer address on the
|
||||
interface. This setting only takes effect for the IPv4 address
|
||||
familiy and only makes sense in combination with a /32 netmask.
|
||||
For compatiblity with ifupdown and ifupdown2, _pointopoint_ is
|
||||
an alias for this parameter.
|
||||
|
||||
*gateway* _address_
|
||||
Associates an IPv4 or IPv6 address with the parent interface
|
||||
for use as a default route (gateway). This usually is given
|
||||
once for IPv4 and once for IPv6 (in a Dual-Stack setup).
|
||||
|
||||
*link-type* _link-type_
|
||||
Denotes the link-type of the interface. When set to _dummy_,
|
||||
the interface is created as a virtual dummy interfaces.
|
||||
When set to _veth_ the interface is created as virtual veth
|
||||
interface (pair).
|
||||
|
||||
*veth-peer-name* _peer-name_
|
||||
Denotes the name of the veth peer interfaces. If not set
|
||||
the kernel will name the veth peer interface as _vethN_
|
||||
with N being an integer number.
|
||||
|
||||
*alias* _alias_
|
||||
Sets the given alias on the interface.
|
||||
|
||||
*requires* _interfaces_...
|
||||
Designates one or more required interfaces that must be
|
||||
brought up before configuration of the parent interface.
|
||||
Interfaces associated with the parent are taken down at
|
||||
the same time as the parent.
|
||||
|
||||
*inherit* _interface_
|
||||
Designates that the parent interface should inherit
|
||||
configuration data from _interface_.
|
||||
*inherit* _object_
|
||||
Designates that the configured interface should inherit
|
||||
configuration data from _object_. Normally _object_
|
||||
must be a *template*.
|
||||
|
||||
*use* _option_
|
||||
Designates that an option should be used. See _OPTIONS_
|
||||
section for more information on options.
|
||||
*use* _executor_
|
||||
Designates that an executor should be used. See _EXECUTORS_
|
||||
section for more information on executors.
|
||||
|
||||
*pre-down* _command_
|
||||
Runs _command_ before taking the interface down.
|
||||
|
|
@ -98,14 +137,19 @@ the system will only respond to certain keywords by default:
|
|||
*post-up* _command_
|
||||
Runs _command_ after bringing the interface up.
|
||||
|
||||
Additional packages such as *bonding*, *bridge*, *tunnel* and
|
||||
*vrf* add additional keywords to this vocabulary.
|
||||
Additional packages such as *bonding*, *bridge*, *tunnel*, *vrf* and
|
||||
*vxlan* add additional keywords to this vocabulary.
|
||||
|
||||
# OPTIONS
|
||||
# EXECUTORS
|
||||
|
||||
The *use* keyword designates that an _option_ should be used.
|
||||
The *use* keyword designates that an _executor_ should be used.
|
||||
This system is extendable by additional packages, but the
|
||||
most common options are:
|
||||
most common executors are:
|
||||
|
||||
*batman*
|
||||
The interface is a B.A.T.M.A.N. adv. mesh interface.
|
||||
Configuration of B.A.T.M.A.N. adv. interfaces requires the
|
||||
*batctl* untiliy to be installed.
|
||||
|
||||
*bond*
|
||||
The interface is a bonded interface. Configuration
|
||||
|
|
@ -121,17 +165,47 @@ most common options are:
|
|||
Use a DHCP client to learn the IPv4 address of an
|
||||
interface.
|
||||
|
||||
*forward*
|
||||
Configures forwarding settings on the interface.
|
||||
|
||||
*loopback*
|
||||
Designates the interface as a loopback device.
|
||||
|
||||
*ppp*
|
||||
Designates the interface as a PPP device. Configuration
|
||||
of PPP interfaces require the *ppp* and probably the *pppoe*
|
||||
packages to be installed.
|
||||
|
||||
*tunnel*
|
||||
The interface is a tunnel. Configuration of tunnels
|
||||
requires the *tunnel* package to be installed.
|
||||
requires the *tunnel* package to be installed on Alpine
|
||||
Linux.
|
||||
|
||||
*vrf*
|
||||
The interface is a VRF. Configuration of VRFs requires
|
||||
the *vrf* package to be installed.
|
||||
|
||||
*vxlan*
|
||||
The interface is a Virtual Extensible LAN (VXLAN) tunnel
|
||||
endpoint.
|
||||
|
||||
*wifi*
|
||||
The interface is a Wi-Fi (IEEE 802.11) client interface.
|
||||
Configuration of the WiFi client interface requires the
|
||||
*wireless-tools* package to be installed.
|
||||
The *wpa_supplicant* package must also be installed to
|
||||
connect to hotspots using WPA-based security.
|
||||
|
||||
*wireguard*
|
||||
The interface is a Wireguard VPN tunnel endpoint.
|
||||
|
||||
Check *interfaces-<executor>(5)* for further informaton about a given
|
||||
executor and available configuration parameters.
|
||||
|
||||
If the _auto\_executor\_selection_ ifupdown-ng.conf option is enabled,
|
||||
*use* statements will automatically be added for executors when their
|
||||
configuration statements are present in the interfaces file.
|
||||
|
||||
# EXAMPLES
|
||||
|
||||
Configure a bridge interface *br0* with *bond0* attached to it,
|
||||
|
|
@ -162,6 +236,27 @@ iface eth0
|
|||
use dhcp
|
||||
```
|
||||
|
||||
# SEE ALSO
|
||||
|
||||
*ifstate*(5)
|
||||
*ifupdown-ng.conf*(5)
|
||||
*ifup*(8)
|
||||
*ifdown*(8)
|
||||
*ifquery*(8)
|
||||
*ifctrstat*(8)
|
||||
*interfaces-batman*(5)
|
||||
*interfaces-bond*(5)
|
||||
*interfaces-bridge*(5)
|
||||
*interfaces-forward*(5)
|
||||
*interfaces-mpls*(5)
|
||||
*interfaces-ppp*(5)
|
||||
*interfaces-tunnel*(5)
|
||||
*interfaces-vrf*(5)
|
||||
*interfaces-vxlan*(5)
|
||||
*interfaces-wifi*(5)
|
||||
*interfaces-wireguard*(5)
|
||||
|
||||
# AUTHORS
|
||||
|
||||
Ariadne Conill <ariadne@dereferenced.org>
|
||||
Ariadne Conill <ariadne@dereferenced.org>++
|
||||
Maximilian Wilhelm <max@sdn.clinic>
|
||||
|
|
|
|||
126
executor-scripts/linux/batman
Normal file
126
executor-scripts/linux/batman
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# Maximilian Wilhelm <max@sdn.clinic>
|
||||
# -- Wed 26 Aug 2020 08:15:58 PM CEST
|
||||
#
|
||||
# This executor is responsible for setting up the main B.A.T.M.A.N. adv. interface (eg. bat0)
|
||||
# as well as managing settings of the underlying interfaces (hardifs).
|
||||
#
|
||||
# See interfaces-batman(5) for a list of supported options for hardifs as well as meshifs.
|
||||
#
|
||||
if [ "$VERBOSE" ]; then
|
||||
set -x
|
||||
fi
|
||||
|
||||
if ! which batctl >/dev/null 2>&1; then
|
||||
echo "Error: batctl utility not found!" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#
|
||||
# Compatiblity glue: Newer versions of batctl print a deprecation
|
||||
# warning when called with -m <batif>. Avoid spamming the log and
|
||||
# producting SPAM by silently handling this here.
|
||||
mesh_if_param="-m"
|
||||
if batctl -h 2>&1 | grep -q "meshif"; then
|
||||
mesh_if_param="meshif"
|
||||
fi
|
||||
|
||||
#
|
||||
# Functions to manage main B.A.T.M.A.N. adv. interface
|
||||
batctl_if () {
|
||||
for iface in ${IF_BATMAN_IFACES}; do
|
||||
${MOCK} batctl "${mesh_if_param}" "${IFACE}" interface "$1" "${iface}"
|
||||
done
|
||||
}
|
||||
|
||||
set_meshif_options () {
|
||||
# We only care for options of format IF_BATMAN_<OPTION_NAME>
|
||||
env | grep '^IF_BATMAN_[A-Z0-9_]\+' | while IFS="=" read opt value; do
|
||||
# Members, ignore-regex, routing-algo, and throughput_override are handled seperately
|
||||
if [ "${opt}" = "IF_BATMAN_IFACES" -o \
|
||||
"${opt}" = "IF_BATMAN_IFACES_IGNORE_REGEX" -o \
|
||||
"${opt}" = "IF_BATMAN_ROUTING_ALGO" -o \
|
||||
"${opt}" = "IF_BATMAN_THROUGHPUT_OVERRIDE" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Convert options for the actual name
|
||||
real_opt=$(echo "${opt}" | sed -e 's/^IF_BATMAN_\([A-Z0-9_]\+\)/\1/' | tr '[A-Z]' '[a-z]')
|
||||
|
||||
${MOCK} batctl "${mesh_if_param}" "${IFACE}" "${real_opt}" "${value}"
|
||||
done
|
||||
|
||||
}
|
||||
|
||||
set_routing_algo () {
|
||||
if [ "${IF_BATMAN_ROUTING_ALGO}" != "BATMAN_IV" -a "${IF_BATMAN_ROUTING_ALGO}" != "BATMAN_V" ]; then
|
||||
echo "Invalid routing algorithm \"$1\"."
|
||||
return
|
||||
fi
|
||||
|
||||
batctl ra "${IF_BATMAN_ROUTING_ALGO}"
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Functions to manage B.A.T.M.A.N. adv. underlay interfaces (hardifs)
|
||||
set_hardif_options () {
|
||||
# Query hardif parameter manually for now
|
||||
for hardif in ${IF_BATMAN_IFACES}; do
|
||||
penalty=$(ifquery -p "batman-hop-penalty" "${hardif}")
|
||||
if [ "${penalty}" ]; then
|
||||
${MOCK} batctl hardif "${hardif}" hop_penalty "${penalty}"
|
||||
fi
|
||||
|
||||
throughput=$(ifquery -p "batman-throughput-override" "${hardif}")
|
||||
if [ "${throughput}" ]; then
|
||||
${MOCK} batctl hardif "${hardif}" throughput_override "${througput}"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
case "${PHASE}" in
|
||||
depend)
|
||||
if [ "${IF_BATMAN_IFACES}" ]; then
|
||||
echo "${IF_BATMAN_IFACES}"
|
||||
fi
|
||||
;;
|
||||
|
||||
create)
|
||||
# Main B.A.T.M.A.N. adv. interface
|
||||
if [ "${IF_BATMAN_IFACES}" ]; then
|
||||
if [ "${IF_BATMAN_ROUTING_ALGO}" ]; then
|
||||
set_routing_algo
|
||||
fi
|
||||
|
||||
if [ ! -d "/sys/class/net/${IFACE}" ]; then
|
||||
batctl "${mesh_if_param}" "${IFACE}" interface create || true
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
|
||||
pre-up)
|
||||
# Main B.A.T.M.A.N. adv. interface (meshif)
|
||||
if [ "${IF_BATMAN_IFACES}" ]; then
|
||||
batctl_if add
|
||||
set_meshif_options
|
||||
set_hardif_options
|
||||
fi
|
||||
;;
|
||||
|
||||
destroy)
|
||||
if [ "${IF_BATMAN_IFACES}" -a -d "/sys/class/net/${IFACE}" ]; then
|
||||
# Newer versions of batctl provide the "interface destroy" API, try to use it
|
||||
if ! batctl "${mesh_if_param}" "${IFACE}" interface destroy 2>/dev/null; then
|
||||
# Fall back to old style member interface removal
|
||||
batctl_if del
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
|
||||
*)
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
57
executor-scripts/linux/bond
Executable file
57
executor-scripts/linux/bond
Executable file
|
|
@ -0,0 +1,57 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# This executor is responsible for setting up bond/LAG interfaces.
|
||||
#
|
||||
# Sat, 03 Oct 2020 20:42:19 +0200
|
||||
# -- Maximilian Wilhelm <max@sdn.clinic>
|
||||
#
|
||||
[ -n "$VERBOSE" ] && set -x
|
||||
|
||||
get_bond_options() {
|
||||
# We only care for options of format IF_BOND_<OPTION_NAME>
|
||||
env | grep '^IF_BOND_[A-Z0-9_]\+' | while IFS="=" read opt value; do
|
||||
# Members are handled seperately
|
||||
if [ "${opt}" = "IF_BOND_MEMBERS" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Convert options for the actual name
|
||||
real_opt=$(echo "${opt}" | sed -e 's/^IF_BOND_\([A-Z0-9_]\+\)/\1/' | tr '[A-Z]' '[a-z]')
|
||||
|
||||
echo -n " ${real_opt} ${value}"
|
||||
done
|
||||
}
|
||||
|
||||
case "$PHASE" in
|
||||
depend)
|
||||
echo "${IF_BOND_MEMBERS}"
|
||||
;;
|
||||
|
||||
create)
|
||||
if [ -d "/sys/class/net/${IFACE}" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Gather bonding options for this interface
|
||||
options=$(get_bond_options)
|
||||
|
||||
# Create bond
|
||||
${MOCK} ip link add "${IFACE}" type bond ${options}
|
||||
|
||||
# Add members to bundle
|
||||
for member_iface in ${IF_BOND_MEMBERS}; do
|
||||
# Work around the current execution order
|
||||
${MOCK} ip link set "${member_iface}" down
|
||||
${MOCK} ip link set master "${IFACE}" "${member_iface}"
|
||||
${MOCK} ip link set "${member_iface}" up
|
||||
done
|
||||
;;
|
||||
|
||||
destroy)
|
||||
if [ -z "${MOCK}" -a ! -d "/sys/class/net/${IFACE}" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
${MOCK} ip link del "${IFACE}"
|
||||
;;
|
||||
esac
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
[ -n "$VERBOSE" ] && set -x
|
||||
|
||||
# Copyright (C) 2012, 2020 Natanael Copa <ncopa@alpinelinux.org>
|
||||
# Copyright (C) 2020 Ariadne Conill <ariadne@dereferenced.org>
|
||||
# Copyright (C) 2020 Maximilian Wilhelm <max@sdn.clinic>
|
||||
#
|
||||
# Permission to use, copy, modify, and/or distribute this software for any
|
||||
# purpose with or without fee is hereby granted, provided that the above
|
||||
|
|
@ -13,6 +13,10 @@ set -e
|
|||
# implied. In no event shall the authors be liable for any damages arising
|
||||
# from the use of this software.
|
||||
|
||||
################################################################################
|
||||
# Bridge management functions #
|
||||
################################################################################
|
||||
|
||||
all_ports_exist() {
|
||||
local i=
|
||||
for i in "$@"; do
|
||||
|
|
@ -51,13 +55,10 @@ all_ports() {
|
|||
add_ports() {
|
||||
local port=
|
||||
for port in $PORTS; do
|
||||
if [ -x /etc/network/if-pre-up.d/vlan ]; then
|
||||
env IFACE=$port /etc/network/if-pre-up.d/vlan
|
||||
fi
|
||||
if [ -n "$IF_BRIDGE_HW" ]; then
|
||||
ip link set dev $port addr $IF_BRIDGE_HW
|
||||
fi
|
||||
brctl addif $IFACE $port && ip link set dev $port up
|
||||
ip link set dev $port master $IFACE && ip link set dev $port up
|
||||
done
|
||||
}
|
||||
|
||||
|
|
@ -65,22 +66,17 @@ del_ports() {
|
|||
local port=
|
||||
for port in $PORTS; do
|
||||
ip link set dev $port down
|
||||
brctl delif $IFACE $port
|
||||
if [ -x /etc/network/ip-post-down.d/vlan ]; then
|
||||
env IFACE=$port /etc/network/if-post-down.d/vlan
|
||||
fi
|
||||
ip link set dev $port nomaster
|
||||
done
|
||||
}
|
||||
|
||||
set_bridge_opts() {
|
||||
set_bridge_opts_brctl() {
|
||||
[ -n "$IF_BRIDGE_AGEING" ] \
|
||||
&& brctl setageing $IFACE $IF_BRIDGE_AGEING
|
||||
[ -n "$IF_BRIDGE_BRIDGEPRIO" ] \
|
||||
&& brctl setbridgeprio $IFACE $IF_BRIDGE_BRIDGEPRIO
|
||||
[ -n "$IF_BRIDGE_FD" ] \
|
||||
&& brctl setfd $IFACE $IF_BRIDGE_FD
|
||||
[ -n "$IF_BRIDGE_GCINT" ] \
|
||||
&& brctl setgcint $IFACE $IF_BRIDGE_GCINT
|
||||
[ -n "$IF_BRIDGE_HELLO" ] \
|
||||
&& brctl sethello $IFACE $IF_BRIDGE_HELLO
|
||||
[ -n "$IF_BRIDGE_MAXAGE" ] \
|
||||
|
|
@ -93,6 +89,44 @@ set_bridge_opts() {
|
|||
&& brctl stp $IFACE $IF_BRIDGE_STP
|
||||
}
|
||||
|
||||
yesno() {
|
||||
case "$1" in
|
||||
yes|YES|true|TRUE|1)
|
||||
echo 1
|
||||
;;
|
||||
*)
|
||||
echo 0
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
set_bridge_opts_iproute2() {
|
||||
[ -n "$IF_BRIDGE_AGEING" ] \
|
||||
&& ip link set dev $IFACE type bridge ageing_time $IF_BRIDGE_AGEING
|
||||
[ -n "$IF_BRIDGE_BRIDGEPRIO" ] \
|
||||
&& ip link set dev $IFACE type bridge priority $IF_BRIDGE_BRIDGEPRIO
|
||||
[ -n "$IF_BRIDGE_FD" ] \
|
||||
&& ip link set dev $IFACE type bridge forward_delay $IF_BRIDGE_FD
|
||||
[ -n "$IF_BRIDGE_HELLO" ] \
|
||||
&& ip link set dev $IFACE type bridge hello_time $IF_BRIDGE_HELLO
|
||||
[ -n "$IF_BRIDGE_MAXAGE" ] \
|
||||
&& ip link set dev $IFACE type bridge max_age $IF_BRIDGE_MAXAGE
|
||||
[ -n "$IF_BRIDGE_PATHCOST" ] \
|
||||
&& bridge link set dev $IFACE cost $IF_BRIDGE_PATHCOST
|
||||
[ -n "$IF_BRIDGE_PORTPRIO" ] \
|
||||
&& bridge link set dev $IFACE priority $IF_BRIDGE_PORTPRIO
|
||||
[ -n "$IF_BRIDGE_STP" ] \
|
||||
&& ip link set dev $IFACE type bridge stp $(yesno $IF_BRIDGE_STP)
|
||||
[ -n "$IF_BRIDGE_VLAN_AWARE" ] \
|
||||
&& ip link set dev $IFACE type bridge vlan_filtering $(yesno $IF_BRIDGE_VLAN_AWARE)
|
||||
}
|
||||
|
||||
set_bridge_opts() {
|
||||
[ -x /sbin/bridge ] && set_bridge_opts_iproute2 && return 0
|
||||
[ -x /sbin/brctl ] && set_bridge_opts_brctl && return 0
|
||||
}
|
||||
|
||||
|
||||
all_ports_ready() {
|
||||
local port=
|
||||
for port in $PORTS; do
|
||||
|
|
@ -122,7 +156,92 @@ wait_bridge() {
|
|||
done
|
||||
}
|
||||
|
||||
[ -z "$IF_BRIDGE_PORTS" ] && IF_BRIDGE_PORTS="$IF_REQUIRES"
|
||||
|
||||
################################################################################
|
||||
# Bridge port management functions #
|
||||
################################################################################
|
||||
|
||||
configure_access_port() {
|
||||
port="$1"
|
||||
vlan="$2"
|
||||
self="$3"
|
||||
|
||||
# Cleans all existing VLANs (probably at least VLAN 1)
|
||||
bridge vlan show dev ${port} | tail -n +2 | grep -v '^$' | sed -e "s/^${port}//" | while read vid flags; do
|
||||
bridge vlan del vid "${vid}" dev "${port}" ${self}
|
||||
done
|
||||
|
||||
bridge vlan add vid "${vlan}" pvid untagged dev "${port}" ${self}
|
||||
}
|
||||
|
||||
configure_trunk_port() {
|
||||
port="$1"
|
||||
self="$2"
|
||||
|
||||
# Working on the bridge itself?
|
||||
if [ "${self}" ]; then
|
||||
allow_untagged="${IF_BRIDGE_ALLOW_UNTAGGED}"
|
||||
pvid="${IF_BRIDGE_PVID}"
|
||||
vids="${IF_BRIDGE_VIDS}"
|
||||
else
|
||||
allow_untagged=$(ifquery -p bridge-allow-untagged ${port} 2>/dev/null || true)
|
||||
pvid=$(ifquery -p bridge-pvid ${port} 2>/dev/null || true)
|
||||
vids=$(ifquery -p bridge-vids ${port} 2>/dev/null || true)
|
||||
fi
|
||||
|
||||
# If bridge-allow-untagged if set to off, remove untagged VLAN. If it's
|
||||
# one of our bridge-vids, it will be set again later.
|
||||
if [ "${allow_untagged}" -a "$(yesno ${allow_untagged})" = 0 ]; then
|
||||
untagged_vid=$(bridge vlan show dev ${port} | tail -n +2 | grep -v '^$' | sed -e "s/^${port}//" | awk '/Untagged/ { print $1 }')
|
||||
if [ "${untagged_vid}" ]; then
|
||||
bridge vlan del vid "${untagged_vid}" dev "${port}" ${self}
|
||||
fi
|
||||
fi
|
||||
|
||||
# The vlan specified is to be considered a PVID at ingress.
|
||||
# Any untagged frames will be assigned to this VLAN.
|
||||
if [ "${pvid}" ]; then
|
||||
cur_pvid=$(bridge vlan show dev ${port} | tail -n +2 | grep -v '^$' | sed -e "s/^${port}//" | awk '/PVID/ { print $1 }')
|
||||
if [ "${cur_pvid}" ]; then
|
||||
bridge vlan del vid ${cur_pvid} dev "${port}" ${self}
|
||||
fi
|
||||
|
||||
bridge vlan add vid "${pvid}" dev "${port}" pvid untagged ${self}
|
||||
fi
|
||||
|
||||
# Add regular tagged VLANs
|
||||
for vid in ${vids}; do
|
||||
bridge vlan add vid $vid dev "${port}" ${self}
|
||||
done
|
||||
}
|
||||
|
||||
# Configure VLANs on the bridge interface itself
|
||||
set_bridge_vlans() {
|
||||
# Shall the bridge interface be an untagged port?
|
||||
if [ "${IF_BRIDGE_ACCESS}" ]; then
|
||||
configure_access_port "${IFACE}" "${IF_BRIDGE_ACCESS}" "self"
|
||||
|
||||
# Configure bridge interface as trunk port
|
||||
else
|
||||
configure_trunk_port "${IFACE}" "self"
|
||||
fi
|
||||
}
|
||||
|
||||
# Configure VLANs on the bridge-ports
|
||||
set_bridge_port_vlans() {
|
||||
for port in ${PORTS}; do
|
||||
access_vlan=$(ifquery -p bridge-access ${port} 2>/dev/null || true)
|
||||
|
||||
# Shall this prot interface be an untagged port?
|
||||
if [ "${access_vlan}" ]; then
|
||||
configure_access_port "${port}" "${access_vlan}"
|
||||
|
||||
# Configure port as trunk
|
||||
else
|
||||
configure_trunk_port "${port}"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
case "$IF_BRIDGE_PORTS" in
|
||||
"") ;;
|
||||
|
|
@ -131,19 +250,53 @@ all) PORTS=$(all_ports);;
|
|||
*) PORTS="$IF_BRIDGE_PORTS";;
|
||||
esac
|
||||
|
||||
[ -z "$PORTS" ] && ! env | grep -q "^IF_BRIDGE" && exit
|
||||
|
||||
case "$PHASE" in
|
||||
pre-up)
|
||||
brctl addbr $IFACE || exit 1
|
||||
wait_ports
|
||||
set_bridge_opts
|
||||
add_ports
|
||||
wait_bridge
|
||||
depend)
|
||||
# Called for the bridge interface
|
||||
if [ "${IF_BRIDGE_PORTS}" ]; then
|
||||
echo "$PORTS"
|
||||
fi
|
||||
;;
|
||||
|
||||
create)
|
||||
# Called for the bridge interface
|
||||
if [ "${IF_BRIDGE_PORTS}" -a ! -d "/sys/class/net/${IFACE}" ]; then
|
||||
ip link add "${IFACE}" type bridge
|
||||
fi
|
||||
;;
|
||||
|
||||
pre-up)
|
||||
# Called for the bridge interface
|
||||
if [ "${IF_BRIDGE_PORTS}" ]; then
|
||||
wait_ports
|
||||
set_bridge_opts
|
||||
set_bridge_vlans
|
||||
add_ports
|
||||
set_bridge_port_vlans
|
||||
wait_bridge
|
||||
|
||||
# Called for a bridge member port
|
||||
elif [ "${IF_BRIDGE_VIDS}" -o "${IF_BRIDGE_PVID}" -o "${IF_BRIDGE_ACCESS}" -o "${IF_BRIDGE_ALLOW_UNTAGGED}" ]; then
|
||||
# Eventually we want to configure VLAN settings of member ports here.
|
||||
# The current execution model does not allow this, so this is a no-op
|
||||
# for now and we work around this by configuring ports while configuring
|
||||
# the bridge.
|
||||
true
|
||||
fi
|
||||
;;
|
||||
|
||||
post-down)
|
||||
del_ports
|
||||
ip link set dev $IFACE down
|
||||
brctl delbr $IFACE || exit 1
|
||||
# Called for the bridge interface
|
||||
if [ "${IF_BRIDGE_PORTS}" ]; then
|
||||
del_ports
|
||||
ip link set dev $IFACE down
|
||||
fi
|
||||
;;
|
||||
|
||||
destroy)
|
||||
# Called for the bridge interface
|
||||
if [ "${IF_BRIDGE_PORTS}" -a -d "/sys/class/net/${IFACE}" ]; then
|
||||
ip link del "${IFACE}"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
# some users provide a shell fragment for the hostname property.
|
||||
[ -n "$IF_DHCP_HOSTNAME" ] && IF_DHCP_HOSTNAME=$(eval echo $IF_DHCP_HOSTNAME)
|
||||
|
||||
determine_implementation() {
|
||||
[ -n "$IF_DHCP_PROGRAM" ] && echo "$IF_DHCP_PROGRAM" && return
|
||||
|
|
@ -14,18 +14,26 @@ determine_implementation() {
|
|||
start() {
|
||||
case "$1" in
|
||||
dhcpcd)
|
||||
[ -n "$IF_HOSTNAME" ] && optargs="$optargs -h $IF_HOSTNAME"
|
||||
[ -n "$IF_VENDOR" ] && optargs="$optargs -i $IF_VENDOR"
|
||||
[ -n "$IF_CLIENT" ] && optargs="$optargs -i $IF_CLIENT"
|
||||
[ -n "$IF_LEASETIME" ] && optargs="$optargs -l $IF_LEASETIME"
|
||||
[ -n "$IF_DHCP_HOSTNAME" ] && optargs="$optargs -h $IF_DHCP_HOSTNAME"
|
||||
[ -n "$IF_DHCP_VENDOR" ] && optargs="$optargs -i $IF_DHCP_VENDOR"
|
||||
[ -n "$IF_DHCP_CLIENT_ID" ] && optargs="$optargs -i $IF_DHCP_CLIENT_ID"
|
||||
[ -n "$IF_DHCP_LEASETIME" ] && optargs="$optargs -l $IF_DHCP_LEASETIME"
|
||||
${MOCK} /sbin/dhcpcd $optargs $IFACE
|
||||
;;
|
||||
dhclient)
|
||||
${MOCK} /usr/sbin/dhclient -pf /var/run/dhclient.$IFACE.pid $IFACE
|
||||
# Specific config file given?
|
||||
if [ -n "$IF_DHCP_CONFIG" ]; then
|
||||
optargs="$optargs -cf $IF_DHCP_CONFIG"
|
||||
fi
|
||||
|
||||
${MOCK} /usr/sbin/dhclient -pf /var/run/dhclient.$IFACE.pid $optargs $IFACE
|
||||
;;
|
||||
udhcpc)
|
||||
UDHCPC_OPTS=$(eval echo $IF_UDHCPC_OPTS)
|
||||
${MOCK} /sbin/udhcpc -b -R -p /var/run/udhcpc.$IFACE.pid -i $IFACE $UDHCPC_OPTS
|
||||
optargs=$(eval echo $IF_UDHCPC_OPTS)
|
||||
[ -n "$IF_DHCP_HOSTNAME" ] && optargs="$optargs -x hostname:$IF_DHCP_HOSTNAME"
|
||||
[ -n "$IF_DHCP_CLIENT_ID" ] && optargs="$optargs -c $IF_DHCP_CLIENT_ID"
|
||||
[ -n "$IF_DHCP_SCRIPT" ] && optargs="$optargs -s $IF_DHCP_SCRIPT"
|
||||
${MOCK} /sbin/udhcpc -b -R -p /var/run/udhcpc.$IFACE.pid -i $IFACE $optargs
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
|
|
|
|||
58
executor-scripts/linux/ethtool
Executable file
58
executor-scripts/linux/ethtool
Executable file
|
|
@ -0,0 +1,58 @@
|
|||
#!/bin/sh
|
||||
# gather params for a given prefix, based on executor-scripts/linux/tunnel.
|
||||
gather_params() {
|
||||
env | sed -E "
|
||||
s/^IF_${1}_([A-Z0-9_]+)=(.+)/\1\n\2/
|
||||
ta
|
||||
d
|
||||
:a
|
||||
h
|
||||
y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
|
||||
P
|
||||
g
|
||||
s/.*\n//" | sed -E "s/_/-/g"
|
||||
}
|
||||
|
||||
case "$PHASE" in
|
||||
pre-up)
|
||||
settings="\
|
||||
${IF_ETHTOOL_ETHERNET_PORT:+ port $IF_ETHTOOL_ETHERNET_PORT}
|
||||
${IF_ETHTOOL_MSGLVL:+ msglvl $IF_ETHTOOL_MSGLVL}
|
||||
"
|
||||
[ -z "$settings" ] || $MOCK ethtool --change "$IFACE" $settings
|
||||
;;
|
||||
up)
|
||||
# first do the link settings.
|
||||
link_settings="${IF_ETHTOOL_LINK_SPEED:+ speed $IF_ETHTOOL_LINK_SPEED}${IF_ETHTOOL_LINK_DUPLEX:+ duplex $IF_ETHTOOL_LINK_DUPLEX}"
|
||||
|
||||
# ethernet-wol can have a second arg (key), split into $1 and $2
|
||||
set -- $IF_ETHTOOL_ETHERNET_WOL
|
||||
link_settings="$link_settings${1:+ wol $1}${2:+ sopass $2}"
|
||||
|
||||
# handle ethtool-ethernet-autoneg like Debian would
|
||||
case "$IF_ETHTOOL_ETHERNET_AUTONEG" in
|
||||
'')
|
||||
;;
|
||||
on|off)
|
||||
link_settings="$link_settings autoneg $IF_ETHTOOL_ETHERNET_AUTONEG"
|
||||
;;
|
||||
*)
|
||||
link_settings="$link_settings autoneg on advertise $IF_ETHTOOL_ETHERNET_AUTONEG"
|
||||
;;
|
||||
esac
|
||||
|
||||
[ -z "$link_settings" ] || $MOCK ethtool --change "$IFACE" $link_settings
|
||||
|
||||
pause_settings=$(gather_params ETHTOOL_PAUSE)
|
||||
[ -z "$pause_settings" ] || $MOCK ethtool --pause "$IFACE" $pause_settings
|
||||
|
||||
offload_settings=$(gather_params ETHTOOL_OFFLOAD)
|
||||
[ -z "$offload_settings" ] || $MOCK ethtool --offload "$IFACE" $offload_settings
|
||||
|
||||
dma_settings=$(gather_params ETHTOOL_DMA_RING)
|
||||
[ -z "$dma_settings" ] || $MOCK ethtool --set-ring "$IFACE" $dma_settings
|
||||
|
||||
coalesce_settings=$(gather_params ETHTOOL_COALESCE)
|
||||
[ -z "$coalesce_settings" ] || $MOCK ethtool --coalesce "$IFACE" $coalesce_settings
|
||||
;;
|
||||
esac
|
||||
19
executor-scripts/linux/forward
Executable file
19
executor-scripts/linux/forward
Executable file
|
|
@ -0,0 +1,19 @@
|
|||
#!/bin/sh
|
||||
|
||||
yesno() {
|
||||
case "$1" in
|
||||
yes|1) echo 1 ;;
|
||||
*) echo 0 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
[ "$PHASE" != "up" ] && exit 0
|
||||
[ -z "$VERBOSE" ] || set -x
|
||||
|
||||
[ -n "$IF_FORWARD_IPV4" ] && ${MOCK} /bin/sh -c "echo $(yesno $IF_FORWARD_IPV4) > /proc/sys/net/ipv4/conf/$IFACE/forwarding"
|
||||
[ -n "$IF_FORWARD_IPV6" ] && ${MOCK} /bin/sh -c "echo $(yesno $IF_FORWARD_IPV6) > /proc/sys/net/ipv6/conf/$IFACE/forwarding"
|
||||
|
||||
[ -n "$IF_FORWARD_IPV4_MC" ] && ${MOCK} /bin/sh -c "echo $(yesno $IF_FORWARD_IPV4_MC) > /proc/sys/net/ipv4/conf/$IFACE/mc_forwarding"
|
||||
[ -n "$IF_FORWARD_IPV6_MC" ] && ${MOCK} /bin/sh -c "echo $(yesno $IF_FORWARD_IPV6_MC) > /proc/sys/net/ipv6/conf/$IFACE/mc_forwarding"
|
||||
|
||||
exit 0
|
||||
|
|
@ -1,7 +1,4 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
# Executor for advanced GRE tunnel management.
|
||||
|
||||
[ -z "$IF_GRE_LOCAL" ] && exit 1
|
||||
|
|
@ -19,10 +16,10 @@ PARAMS="mode $IF_GRE_MODE local '$IF_GRE_LOCAL' remote '$IF_GRE_REMOTE'"
|
|||
[ -n "$PARAMS" ] || exit 0
|
||||
|
||||
case "$PHASE" in
|
||||
pre-up)
|
||||
create)
|
||||
${MOCK} eval ip $FAMILY $COMMAND add $IFACE $PARAMS
|
||||
;;
|
||||
post-down)
|
||||
destroy)
|
||||
${MOCK} ip $FAMILY $COMMAND del $IFACE
|
||||
;;
|
||||
depend)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,4 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
start() {
|
||||
${MOCK} /bin/sh -c "echo 1 > /proc/sys/net/ipv6/conf/$IFACE/accept_ra"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,6 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
[ -n "$VERBOSE" ] && set -x
|
||||
|
||||
IF_LINK_OPTIONS="$IF_LINK_OPTIONS"
|
||||
[ -n "$IF_MTU" ] && IF_LINK_OPTIONS="$IF_LINK_OPTIONS mtu $IF_MTU"
|
||||
[ -n "$IF_HWADDRESS" ] && IF_LINK_OPTIONS="$IF_LINK_OPTIONS address $IF_HWADDRESS"
|
||||
|
||||
is_vlan() {
|
||||
case "$IFACE" in
|
||||
*#*) return 1 ;;
|
||||
|
|
@ -32,18 +25,49 @@ is_vlan() {
|
|||
}
|
||||
|
||||
case "$PHASE" in
|
||||
up|down)
|
||||
depend)
|
||||
# vlan-raw-device
|
||||
if is_vlan; then
|
||||
ADD_DEL="add"
|
||||
[ "$PHASE" = "down" ] && ADD_DEL="delete"
|
||||
echo "$IF_VLAN_RAW_DEVICE"
|
||||
|
||||
# veth-peer-name
|
||||
elif [ "${IF_LINK_TYPE}" = "veth" -a "${IF_VETH_PEER_NAME}" ]; then
|
||||
echo "${IF_VETH_PEER_NAME}"
|
||||
fi
|
||||
;;
|
||||
|
||||
create)
|
||||
if [ "${IF_LINK_TYPE}" = "dummy" ]; then
|
||||
if [ -d "/sys/class/net/${IFACE}" ]; then
|
||||
iface_type=$(ip -d link show dev "${IFACE}" | head -n3 | tail -n1 | awk '{ print $1 }')
|
||||
if [ "${iface_type}" != 'dummy' ]; then
|
||||
echo "Interface ${IFACE} exists but is of type ${iface_type} instead of dummy"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$PHASE" = "up" -a -e /sys/class/net/$IFACE ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ -z "$MOCK" ]; then
|
||||
if ! ip link show "$IF_VLAN_RAW_DEVICE" >/dev/null; then
|
||||
echo "Device $IF_VLAN_RAW_DEVICE for $IFACE does not exist"
|
||||
${MOCK} ip link add "${IFACE}" type dummy
|
||||
|
||||
elif [ "${IF_LINK_TYPE}" = "veth" ]; then
|
||||
if [ ! -d "/sys/class/net/${IFACE}" ]; then
|
||||
ARGS=""
|
||||
if [ "${IF_VETH_PEER_NAME}" ]; then
|
||||
ARGS="peer ${IF_VETH_PEER_NAME}"
|
||||
fi
|
||||
|
||||
${MOCK} ip link add "${IFACE}" type veth ${ARGS}
|
||||
fi
|
||||
|
||||
elif is_vlan; then
|
||||
if [ -d "/sys/class/net/${IFACE}" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ -z "${MOCK}" ]; then
|
||||
if [ ! -d "/sys/class/net/${IF_VLAN_RAW_DEVICE}" ]; then
|
||||
echo "Underlay device ${IF_VLAN_RAW_DEVICE} for ${IFACE} does not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
|
@ -53,17 +77,36 @@ up|down)
|
|||
fi
|
||||
fi
|
||||
|
||||
${MOCK} ip link $ADD_DEL link "$IF_VLAN_RAW_DEVICE" name "$IFACE" type vlan id "$IF_VLAN_ID"
|
||||
[ "$PHASE" = "down" ] && exit 0
|
||||
|
||||
${MOCK} ip link set $PHASE dev $IFACE $IF_LINK_OPTIONS
|
||||
else
|
||||
${MOCK} ip link set $PHASE dev $IFACE $IF_LINK_OPTIONS
|
||||
${MOCK} ip link add link "${IF_VLAN_RAW_DEVICE}" name "${IFACE}" type vlan id "${IF_VLAN_ID}"
|
||||
fi
|
||||
;;
|
||||
depend)
|
||||
if is_vlan; then
|
||||
echo "$IF_VLAN_RAW_DEVICE"
|
||||
up)
|
||||
IF_LINK_OPTIONS="$IF_LINK_OPTIONS"
|
||||
[ -n "$IF_MTU" ] && IF_LINK_OPTIONS="$IF_LINK_OPTIONS mtu $IF_MTU"
|
||||
[ -n "$IF_HWADDRESS" ] && IF_LINK_OPTIONS="$IF_LINK_OPTIONS address $IF_HWADDRESS"
|
||||
|
||||
${MOCK} ip link set up dev "${IFACE}" ${IF_LINK_OPTIONS}
|
||||
|
||||
# Set alias is configured
|
||||
if [ "${IF_ALIAS}" ]; then
|
||||
${MOCK} ip link set alias "${IF_ALIAS}" dev "${IFACE}"
|
||||
fi
|
||||
;;
|
||||
down)
|
||||
# Don't complain about a vanished interface when downing it
|
||||
if [ -z "${MOCK}" -a ! -d "/sys/class/net/${IFACE}" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
${MOCK} ip link set down dev "${IFACE}"
|
||||
;;
|
||||
destroy)
|
||||
if [ "${IF_LINK_TYPE}" = "dummy" ] || [ "${IF_LINK_TYPE}" = "veth" ] || is_vlan; then
|
||||
if [ -z "${MOCK}" -a ! -d "/sys/class/net/${IFACE}" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
${MOCK} ip link del "${IFACE}"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
|
|
|||
36
executor-scripts/linux/mpls
Executable file
36
executor-scripts/linux/mpls
Executable file
|
|
@ -0,0 +1,36 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# Maximilian Wilhelm <max@sdn.clinic>
|
||||
# -- Thu, 17 Dec 2020 03:02:10 +0100
|
||||
#
|
||||
# This executor is responsible for setting up MPLS decapsulation on a given interface.
|
||||
#
|
||||
# See interfaces-mpls(5) for a list of supported options.
|
||||
#
|
||||
|
||||
yesno() {
|
||||
case "$1" in
|
||||
yes|1) echo 1 ;;
|
||||
*) echo 0 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
[ -z "$VERBOSE" ] || set -x
|
||||
|
||||
# We only operate in pre-up phase
|
||||
[ "$PHASE" != "pre-up" ] && exit 0
|
||||
|
||||
|
||||
if [ "$IF_MPLS_ENABLE" ]; then
|
||||
value=$(yesno $IF_MPLS_ENABLE)
|
||||
|
||||
# Load mpls module if we should enable MPLS decap on (at least) one interface
|
||||
if [ "${value}" = 1 ]; then
|
||||
${MOCK} modprobe mpls_iptunnel
|
||||
fi
|
||||
|
||||
# If MPLS support isn't loaded and we are not MOCKing, carry on
|
||||
if [ -f "/proc/sys/net/mpls/conf/$IFACE/input" -o "${MOCK}" ]; then
|
||||
${MOCK} /bin/sh -c "echo ${value} > /proc/sys/net/mpls/conf/$IFACE/input"
|
||||
fi
|
||||
fi
|
||||
|
|
@ -1,8 +1,14 @@
|
|||
#!/bin/sh
|
||||
set -e
|
||||
[ -z "$IF_PPP_PROVIDER" ] && exit 0
|
||||
|
||||
case "$PHASE" in
|
||||
pre-up) ${MOCK} pon $IF_PPP_PROVIDER ;;
|
||||
post-down) ${MOCK} poff $IF_PPP_PROVIDER ;;
|
||||
depend) echo "$IF_PPP_PHYSDEV" ;;
|
||||
create)
|
||||
${MOCK} pon $IF_PPP_PROVIDER
|
||||
;;
|
||||
destroy)
|
||||
${MOCK} poff $IF_PPP_PROVIDER
|
||||
;;
|
||||
depend)
|
||||
echo "$IF_PPP_PHYSDEV"
|
||||
;;
|
||||
esac
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
#!/bin/sh
|
||||
[ -z "${VERBOSE}" ] || set -x
|
||||
|
||||
set -e
|
||||
[ -z "${IF_METRIC}" ] && IF_METRIC="1"
|
||||
[ -n "${IF_VRF_TABLE}" ] && VRF_TABLE="table ${IF_VRF_TABLE}"
|
||||
[ -n "${IF_VRF_MEMBER}" ] && VRF_TABLE="vrf ${IF_VRF_MEMBER}"
|
||||
[ -n "${IF_METRIC}" ] && METRIC="metric ${IF_METRIC}"
|
||||
|
||||
[ -z "$IF_METRIC" ] && IF_METRIC="1"
|
||||
[ -n "$IF_VRF_TABLE" ] && VRF_TABLE="table $IF_VRF_TABLE"
|
||||
[ -n "$IF_METRIC" ] && METRIC="metric $IF_METRIC"
|
||||
|
||||
addr_family() {
|
||||
if [ "$1" != "${1#*[0-9].[0-9]}" ]; then
|
||||
|
|
@ -17,20 +18,31 @@ addr_family() {
|
|||
}
|
||||
|
||||
configure_addresses() {
|
||||
for i in $(ifquery -p address -i $INTERFACES_FILE $IFACE); do
|
||||
addrfam=$(addr_family $i)
|
||||
${MOCK} ip $addrfam addr $1 $i dev $IFACE
|
||||
for addr in ${IF_ADDRESSES}; do
|
||||
addrfam=$(addr_family ${addr})
|
||||
if [ "${IF_POINT_TO_POINT}" -a "${addrfam}" = "-4" ]; then
|
||||
PEER="peer ${IF_POINT_TO_POINT}"
|
||||
else
|
||||
PEER=""
|
||||
fi
|
||||
|
||||
${MOCK} ip "${addrfam}" addr add "${addr}" ${PEER} dev "${IFACE}"
|
||||
done
|
||||
}
|
||||
|
||||
configure_gateways() {
|
||||
for i in $(ifquery -p gateway -i $INTERFACES_FILE $IFACE); do
|
||||
addrfam=$(addr_family $i)
|
||||
${MOCK} ip $addrfam route $1 default via $i $VRF_TABLE $METRIC
|
||||
for gw in ${IF_GATEWAYS}; do
|
||||
addrfam=$(addr_family ${gw})
|
||||
${MOCK} ip "${addrfam}" route add default via "${gw}" ${VRF_TABLE} ${METRIC} dev "${IFACE}"
|
||||
done
|
||||
}
|
||||
|
||||
[ -z "$VERBOSE" ] || set -x
|
||||
flush() {
|
||||
cmd="addr"
|
||||
arg="dev ${IFACE}"
|
||||
|
||||
${MOCK} ip ${cmd} flush ${arg}
|
||||
}
|
||||
|
||||
case "$PHASE" in
|
||||
up)
|
||||
|
|
@ -38,8 +50,7 @@ up)
|
|||
configure_gateways add
|
||||
;;
|
||||
down)
|
||||
configure_gateways del
|
||||
configure_addresses del
|
||||
flush
|
||||
;;
|
||||
*) exit 0 ;;
|
||||
esac
|
||||
|
|
|
|||
|
|
@ -1,27 +1,106 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
# Based on alpine's tunnel configuration script.
|
||||
# Copyright (c) 2017 Kaarle Ritvanen
|
||||
# Copyright (c) 2020 Ariadne Conill (extended for ifupdown-ng)
|
||||
# Copyright (c) 2021 Maximilian Wilhelm (make sure mode/type is 1st parameter, add more options)
|
||||
|
||||
[ -z "$IF_TUNNEL_LOCAL" ] && exit 1
|
||||
[ -z "$IF_TUNNEL_LOCAL" -a -z "$IF_TUNNEL_LOCAL_DEV" ] && exit 1
|
||||
[ -z "$IF_TUNNEL_REMOTE" ] && exit 1
|
||||
[ -z "$IF_TUNNEL_MODE" ] && exit 1
|
||||
|
||||
COMMAND="tunnel"
|
||||
FAMILY="-4"
|
||||
[ -n "$VERBOSE" ] && set -x
|
||||
|
||||
yesno() {
|
||||
case "$1" in
|
||||
yes|1) echo 1 ;;
|
||||
*) echo 0 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Figure out address familiy
|
||||
FAMILY="4"
|
||||
|
||||
case "$IF_TUNNEL_MODE" in
|
||||
gretap)
|
||||
COMMAND="link"
|
||||
;;
|
||||
vti6|ipip6|ip6*)
|
||||
FAMILY="-6"
|
||||
FAMILY="6"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Figure out object type - gretap tunnels have to create using ip link
|
||||
# and therefor require 'type' keyword instead of 'mode'
|
||||
OBJECT="tunnel"
|
||||
TYPE_KW="mode"
|
||||
case "${IF_TUNNEL_MODE}" in
|
||||
*gretap)
|
||||
OBJECT="link"
|
||||
TYPE_KW="type"
|
||||
|
||||
# Strip possible "ip6" from tunnel mode
|
||||
TUNNEL_MODE="gretap"
|
||||
;;
|
||||
|
||||
*)
|
||||
# Store tunnel type/mode separaltely and unset input variable to exclude it
|
||||
# from PARAMS below
|
||||
TUNNEL_MODE="$IF_TUNNEL_MODE"
|
||||
unset IF_TUNNEL_MODE
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
# If 'tunnel-local <IP>' was not given but 'tunnel-local-dev <iface>' is given try
|
||||
# to figure out the IP of the underlay device (wrt the address family used for this
|
||||
# tunnel) and use this to set up the tunnel
|
||||
if [ ${PHASE} = "create" -a ! "${IF_TUNNEL_LOCAL}" -a "${IF_TUNNEL_LOCAL_DEV}" ]; then
|
||||
if [ "${FAMILY}" = "4" ]; then
|
||||
ip=$(ip -4 -brief addr show dev "${IF_TUNNEL_LOCAL_DEV}" 2>/dev/null | awk '{ print $3 }' | cut -d/ -f1)
|
||||
|
||||
# For IPv6 we try to use a non-temporary address (-> privacy extensions)
|
||||
else
|
||||
# Get all IPv6 addres configured on $IF_TUNNEL_LOCAL_DEV which are not
|
||||
# temporary (due to privacy extensions). We do not filter for "mgmtaddr"
|
||||
# "scope global" etc. as we don't want to make further assumptions on
|
||||
# whether a user wants to use a link local address configured to this interface.
|
||||
#
|
||||
# The assumption that a temporary address configured by PE isn't suited
|
||||
# to terminate a tunnel should hold in nearly all setups, I hope.
|
||||
ip=$(ip -6 addr show dev "${IF_TUNNEL_LOCAL_DEV}" -temporary | grep inet6 | head -n1 | awk '{ print $2 }' | cut -d/ -f1)
|
||||
fi
|
||||
|
||||
if [ ! "${ip}" ]; then
|
||||
echo "Unable to determine the IPv${FAMILIY} address of tunnel-local-dev ${IF_TUNNEL_LOCAL_DEV}!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
unset IF_TUNNEL_LOCAL_DEV
|
||||
export IF_TUNNEL_LOCAL="${ip}"
|
||||
fi
|
||||
|
||||
|
||||
# Handle boolean switches
|
||||
MORE_PARAMS=""
|
||||
if [ "${IF_TUNNEL_IGNORE_DF}" ]; then
|
||||
if $(yesno "${IF_TUNNEL_IGNORE_DF}"); then
|
||||
MORE_PARAMS="ignore-df"
|
||||
else
|
||||
MORE_PARAMS="noignore-df"
|
||||
fi
|
||||
|
||||
unset IF_TUNNEL_IGNORE_DF
|
||||
fi
|
||||
|
||||
if [ "${IF_TUNNEL_PMTUDISC}" ]; then
|
||||
if $(yesno "${IF_TUNNEL_PMTUDISC}"); then
|
||||
MORE_PARAMS="pmtudisc"
|
||||
else
|
||||
MORE_PARAMS="nopmtudisc"
|
||||
fi
|
||||
|
||||
unset IF_TUNNEL_PMTUDISC
|
||||
fi
|
||||
|
||||
|
||||
# Mangle residual IF_TUNNEL_* params into single string
|
||||
PARAMS=$(set | sed -E '
|
||||
s/^IF_TUNNEL_([A-Z0-9_]+)=(.+)/\1\n\2/
|
||||
ta
|
||||
|
|
@ -37,13 +116,13 @@ PARAMS=$(set | sed -E '
|
|||
[ "$PARAMS" ] || exit 0
|
||||
|
||||
case "$PHASE" in
|
||||
pre-up)
|
||||
${MOCK} eval ip $FAMILY $COMMAND add $IFACE $PARAMS
|
||||
create)
|
||||
${MOCK} eval ip -$FAMILY $OBJECT add $IFACE $TYPE_KW $TUNNEL_MODE $PARAMS $MORE_PARAMS
|
||||
;;
|
||||
post-down)
|
||||
${MOCK} ip $FAMILY $COMMAND del $IFACE
|
||||
destroy)
|
||||
${MOCK} ip -$FAMILY $OBJECT del $IFACE
|
||||
;;
|
||||
depend)
|
||||
echo "$IF_TUNNEL_DEV"
|
||||
echo "${IF_TUNNEL_DEV}" "${IF_TUNNEL_LOCAL_DEV}"
|
||||
;;
|
||||
esac
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
handle_init() {
|
||||
${MOCK} /sbin/ip link $1 $IFACE type vrf table $IF_VRF_TABLE
|
||||
${MOCK} /sbin/ip rule $1 iif $IFACE table $IF_VRF_TABLE
|
||||
|
|
@ -14,14 +12,14 @@ handle_member() {
|
|||
[ -n "$VERBOSE" ] && set -x
|
||||
|
||||
case "$PHASE" in
|
||||
pre-up)
|
||||
create)
|
||||
[ -n "$IF_VRF_TABLE" ] && handle_init "add"
|
||||
[ -n "$IF_VRF_MEMBER" ] && handle_member
|
||||
exit 0
|
||||
;;
|
||||
post-down)
|
||||
pre-up)
|
||||
[ -n "$IF_VRF_MEMBER" ] && handle_member
|
||||
;;
|
||||
destroy)
|
||||
[ -n "$IF_VRF_TABLE" ] && handle_init "del"
|
||||
exit 0
|
||||
;;
|
||||
depend)
|
||||
echo "$IF_VRF_MEMBER"
|
||||
|
|
|
|||
96
executor-scripts/linux/vxlan
Executable file
96
executor-scripts/linux/vxlan
Executable file
|
|
@ -0,0 +1,96 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# This executor is responsible for setting up the Virtual Extensible LAN (VXLAN) overlay interfaces.
|
||||
#
|
||||
# Fri, 02 Oct 2020 01:10:29 +0200
|
||||
# -- Maximilian Wilhelm <max@sdn.clinic>
|
||||
#
|
||||
# Known options for the main interface are:
|
||||
#
|
||||
# IF_VXLAN_ID The VXLAN Network Identifier (VNI)
|
||||
# IF_VXLAN_PHYSDEV Specifies the physical device to use for tunnel endpoint communication
|
||||
# IF_VXLAN_LOCAL_IP Specifies the source IP address to use in outgoing packets
|
||||
# IF_VXLAN_PEER_IPS Space separated list of IPs of the remote VTEP endpoint (for ptp/ptmp mode with ingress replication)
|
||||
# IF_VXLAN_PEER_GROUP Multicast group to use for this VNI (for ptmp mode with multicast)
|
||||
# IF_VXLAN_LEARNING Wether to activate MAC learning on this instance (on/off)
|
||||
# IF_VXLAN_AGEING Specifies the lifetime in seconds of FDB entries learnt by the kernel
|
||||
# IF_VXLAN_DSTPORT UDP destination port to communicate to the remote VXLAN tunnel endpoint (default 4789)
|
||||
#
|
||||
[ -n "$VERBOSE" ] && set -x
|
||||
|
||||
# No VNI, nuthin' to do for us
|
||||
if [ ! "${IF_VXLAN_ID}" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
case "$PHASE" in
|
||||
depend)
|
||||
if [ "${IF_VXLAN_PHYSDEV}" ]; then
|
||||
echo "${IF_VXLAN_PHYSDEV}"
|
||||
fi
|
||||
;;
|
||||
|
||||
create)
|
||||
if [ -d "/sys/class/net/${IFACE}" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Input validation
|
||||
if [ "${IF_VXLAN_PEER_IPS}" -a "${IF_VXLAN_PEER_GROUP}" ]; then
|
||||
echo "Error on ${IFACE} (vxlan): Only one of 'vxlan-peer-ips' and 'vxlan-peer-group' can be used!" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if we should operate in unicast ptp or ptmp mode
|
||||
if [ "${IF_VXLAN_PEER_IPS}" ]; then
|
||||
# If it's only one thing which looks like an IPv4/IPv6 address we assume it's ptp
|
||||
if echo "${IF_VXLAN_PEER_IPS}" | grep -q '^[[:space:]]*[[:xdigit:].:]\+[[:space:]]*$'; then
|
||||
UCAST_MODE="ptp"
|
||||
else
|
||||
UCAST_MODE="ptmp"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Gather arguments
|
||||
ARGS=""
|
||||
[ "${IF_VXLAN_PHYSDEV}" ] && ARGS="${ARGS} dev ${IF_VXLAN_PHYSDEV}"
|
||||
[ "${IF_VXLAN_LOCAL_IP}" ] && ARGS="${ARGS} local ${IF_VXLAN_LOCAL_IP}"
|
||||
[ "${UCAST_MODE}" = "ptp" ] && ARGS="${ARGS} remote ${IF_VXLAN_PEER_IPS}"
|
||||
[ "${IF_VXLAN_PEER_GROUP}" ] && ARGS="${ARGS} group ${IF_VXLAN_PEER_GROUP}"
|
||||
[ "${IF_VXLAN_AGEING}" ] && ARGS="${ARGS} ageing ${IF_VXLAN_AGEING}"
|
||||
|
||||
# Linux uses non-standard default port - WTF?
|
||||
if [ "${IF_VXLAN_DSTPORT}" ]; then
|
||||
ARGS="${ARGS} dstport ${IF_VXLAN_DSTPORT}"
|
||||
else
|
||||
ARGS="${ARGS} dstport 4789"
|
||||
fi
|
||||
|
||||
case "${IF_VXLAN_LEARNING}" in
|
||||
on|yes)
|
||||
ARGS="${ARGS} learning"
|
||||
;;
|
||||
|
||||
off|no)
|
||||
ARGS="${ARGS} nolearning"
|
||||
;;
|
||||
esac
|
||||
|
||||
${MOCK} ip link add "${IFACE}" type vxlan id "${IF_VXLAN_ID}" ${ARGS}
|
||||
|
||||
# Set up FDB entries for peer VTEPs
|
||||
if [ "${UCAST_MODE}" = "ptmp" ]; then
|
||||
for peer in ${IF_VXLAN_PEER_IPS}; do
|
||||
${MOCK} bridge fdb append 00:00:00:00:00:00 dev "${IFACE}" dst "${peer}" self permanent
|
||||
done
|
||||
fi
|
||||
;;
|
||||
|
||||
destroy)
|
||||
if [ -z "${MOCK}" -a ! -d "/sys/class/net/${IFACE}" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
${MOCK} ip link del "${IFACE}"
|
||||
;;
|
||||
esac
|
||||
119
executor-scripts/linux/wifi
Executable file
119
executor-scripts/linux/wifi
Executable file
|
|
@ -0,0 +1,119 @@
|
|||
#!/bin/sh
|
||||
# Copyright (c) 2020 Ariadne Conill <ariadne@dereferenced.org>
|
||||
#
|
||||
# Permission to use, copy, modify, and/or distribute this software for any
|
||||
# purpose with or without fee is hereby granted, provided that the above
|
||||
# copyright notice and this permission notice appear in all copies.
|
||||
#
|
||||
# This software is provided 'as is' and without any warranty, express or
|
||||
# implied. In no event shall the authors be liable for any damages arising
|
||||
# from the use of this software.
|
||||
#
|
||||
# Manage wifi connections using wpa_supplicant.
|
||||
#
|
||||
# Vocabulary:
|
||||
# wifi-ssid - The SSID name to connect to.
|
||||
# wifi-psk - The pre-shared key to use.
|
||||
# wifi-config - A path to a wpa_supplicant config file, for special configs.
|
||||
#
|
||||
# If wifi-config is not set, wifi-ssid and wifi-psk are required, and a config
|
||||
# will be generated as /run/wpa_supplicant.$IFACE.conf.
|
||||
#
|
||||
# The wpa_supplicant PID is stored in /run/wpa_supplicant.$IFACE.pid.
|
||||
|
||||
die() {
|
||||
printf "ERROR: %s\n" "$1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
[ -z "$IFACE" ] && die "IFACE not set"
|
||||
[ -z "$PHASE" ] && die "PHASE not set"
|
||||
PIDFILE="/run/wpa_supplicant.$IFACE.pid"
|
||||
|
||||
# Do not allow mixing wifi-config-path and wifi-ssid/wifi-psk.
|
||||
[ -n "$IF_WIFI_CONFIG_PATH" -a -n "$IF_WIFI_SSID" ] && die "wifi-config-path cannot be used with wifi-ssid"
|
||||
[ -n "$IF_WIFI_CONFIG_PATH" -a -n "$IF_WIFI_PSK" ] && die "wifi-config-path cannot be used with wifi-psk"
|
||||
|
||||
# Set IF_WIFI_CONFIG_PATH to the default path if not already set.
|
||||
WIFI_CONFIG_PATH="$IF_WIFI_CONFIG_PATH"
|
||||
[ -z "$WIFI_CONFIG_PATH" ] && WIFI_CONFIG_PATH="/run/wpa_supplicant.$IFACE.conf"
|
||||
|
||||
# Supplicant options.
|
||||
WPA_SUPPLICANT_OPTS="-qq -B -i$IFACE -c$WIFI_CONFIG_PATH -P$PIDFILE"
|
||||
|
||||
# Given $IF_WIFI_SSID and $IF_WIFI_PSK, generate a config file at $WIFI_CONFIG_PATH.
|
||||
generate_config() {
|
||||
[ -z "$IF_WIFI_SSID" ] && die "wifi-ssid not set"
|
||||
[ -z "$IF_WIFI_PSK" ] && die "wifi-psk not set"
|
||||
|
||||
# We use a pipeline here to avoid leaking PSK into the process name.
|
||||
(echo $IF_WIFI_PSK | /sbin/wpa_passphrase $IF_WIFI_SSID) >$WIFI_CONFIG_PATH
|
||||
|
||||
[ ! -e "$WIFI_CONFIG_PATH" ] && die "failed to write temporary config: $WIFI_CONFIG_PATH"
|
||||
}
|
||||
|
||||
# Should we use the supplicant?
|
||||
use_supplicant() {
|
||||
[ -n "$IF_WIFI_CONFIG_PATH" ] && return 0
|
||||
[ -n "$IF_WIFI_PSK" ] && return 0
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# Either start a supplicant process for $IFACE, or use iwconfig to trigger an
|
||||
# association attempt.
|
||||
start() {
|
||||
if use_supplicant; then
|
||||
# If there is no config file located at $WIFI_CONFIG_PATH, generate one.
|
||||
[ ! -e "$WIFI_CONFIG_PATH" ] && generate_config
|
||||
|
||||
/sbin/wpa_supplicant $WPA_SUPPLICANT_OPTS
|
||||
else
|
||||
/usr/sbin/iwconfig $IFACE essid -- "$IF_WIFI_SSID" ap any
|
||||
fi
|
||||
}
|
||||
|
||||
# Stop wpa_supplicant safely
|
||||
stop_wpa_supplicant() {
|
||||
# Remove generated config file
|
||||
[ -z "$IF_WIFI_CONFIG_PATH" ] && rm -- "$WIFI_CONFIG_PATH"
|
||||
|
||||
# If there is no PIDFILE, there is nothing we can do
|
||||
[ ! -f "$PIDFILE" ] && return
|
||||
|
||||
pid=$(cat "$PIDFILE")
|
||||
rm -- "$PIDFILE"
|
||||
|
||||
# If there is no process with this PID running, we're done here
|
||||
if [ ! -d "/proc/$pid/" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
# Verify that the name of the running process matches wpa_supplicant
|
||||
progname_path=$(readlink -n "/proc/$pid/exe")
|
||||
progname=$(basename "$progname_path")
|
||||
if [ "$progname" = "wpa_supplicant" ]; then
|
||||
kill -9 $pid 2>/dev/null
|
||||
fi
|
||||
}
|
||||
|
||||
# Either stop the supplicant process for $IFACE, or use iwconfig to dissociate
|
||||
# from the current SSID.
|
||||
stop() {
|
||||
if use_supplicant; then
|
||||
stop_wpa_supplicant
|
||||
else
|
||||
/usr/sbin/iwconfig $IFACE essid any
|
||||
fi
|
||||
}
|
||||
|
||||
[ -z "$VERBOSE" ] || set -x
|
||||
|
||||
case "$PHASE" in
|
||||
pre-up)
|
||||
start
|
||||
;;
|
||||
post-down)
|
||||
stop
|
||||
;;
|
||||
esac
|
||||
15
executor-scripts/linux/wireguard
Executable file
15
executor-scripts/linux/wireguard
Executable file
|
|
@ -0,0 +1,15 @@
|
|||
#!/bin/sh
|
||||
[ -n "$VERBOSE" ] && set -x
|
||||
[ -z "$IF_WIREGUARD_CONFIG_PATH" ] && IF_WIREGUARD_CONFIG_PATH="/etc/wireguard/$IFACE.conf"
|
||||
|
||||
case "$PHASE" in
|
||||
create)
|
||||
${MOCK} ip link add $IFACE type wireguard
|
||||
;;
|
||||
pre-up)
|
||||
${MOCK} wg setconf $IFACE $IF_WIREGUARD_CONFIG_PATH
|
||||
;;
|
||||
destroy)
|
||||
${MOCK} ip link delete dev $IFACE
|
||||
;;
|
||||
esac
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
#!/bin/sh
|
||||
set -e
|
||||
[ -z "$IF_BOND_MEMBERS" ] && IF_BOND_MEMBERS="$IF_BOND_SLAVES"
|
||||
case "$PHASE" in
|
||||
depend) echo "$IF_BOND_MEMBERS" ;;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
#!/bin/sh
|
||||
set -e
|
||||
case "$PHASE" in
|
||||
depend)
|
||||
if [ "$IF_BRIDGE_PORTS" != "none" ]; then
|
||||
|
|
|
|||
114
libifupdown/compat.c
Normal file
114
libifupdown/compat.c
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* libifupdown/compat.c
|
||||
* Purpose: compatiblity glue to other implementations
|
||||
*
|
||||
* Copyright (c) 2020 Maximilian Wilhelm <max@sdn.clinic>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* This software is provided 'as is' and without any warranty, express or
|
||||
* implied. In no event shall the authors be liable for any damages arising
|
||||
* from the use of this software.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "libifupdown/compat.h"
|
||||
#include "libifupdown/config-file.h"
|
||||
#include "libifupdown/dict.h"
|
||||
#include "libifupdown/interface.h"
|
||||
#include "libifupdown/tokenize.h"
|
||||
|
||||
static bool
|
||||
compat_ifupdown2_bridge_ports_inherit_vlans(struct lif_dict *collection)
|
||||
{
|
||||
struct lif_node *iter;
|
||||
|
||||
/* Loop through all interfaces and search for bridges */
|
||||
LIF_DICT_FOREACH(iter, collection)
|
||||
{
|
||||
struct lif_dict_entry *entry = iter->data;
|
||||
struct lif_interface *bridge = entry->data;
|
||||
|
||||
/* We only care for bridges */
|
||||
if (!bridge->is_bridge)
|
||||
continue;
|
||||
|
||||
struct lif_dict_entry *bridge_pvid = lif_dict_find(&bridge->vars, "bridge-pvid");
|
||||
struct lif_dict_entry *bridge_vids = lif_dict_find(&bridge->vars, "bridge-vids");
|
||||
|
||||
/* If there's nothing to inherit here, carry on */
|
||||
if (bridge_pvid == NULL && bridge_vids == NULL)
|
||||
continue;
|
||||
|
||||
struct lif_dict_entry *bridge_ports_entry = lif_dict_find(&bridge->vars, "bridge-ports");
|
||||
|
||||
/* This SHOULD not happen, but better save than sorry */
|
||||
if (bridge_ports_entry == NULL)
|
||||
continue;
|
||||
|
||||
char bridge_ports_str[4096] = {};
|
||||
strlcpy(bridge_ports_str, bridge_ports_entry->data, sizeof bridge_ports_str);
|
||||
|
||||
/* If there are no bridge-ports configured, carry on */
|
||||
if (strcmp(bridge_ports_str, "none") == 0)
|
||||
continue;
|
||||
|
||||
/* Loop over all bridge-ports and set bridge-pvid and bridge-vid if not set already */
|
||||
char *bufp = bridge_ports_str;
|
||||
for (char *tokenp = lif_next_token(&bufp); *tokenp; tokenp = lif_next_token(&bufp))
|
||||
{
|
||||
entry = lif_dict_find(collection, tokenp);
|
||||
|
||||
/* There might be interfaces give within the bridge-ports for which there is no
|
||||
* interface stanza. If this is the case, we add one, so we can inherit the
|
||||
* bridge-vids/pvid to it. */
|
||||
struct lif_interface *bridge_port;
|
||||
if (entry)
|
||||
bridge_port = entry->data;
|
||||
|
||||
else if (lif_config.compat_create_interfaces)
|
||||
{
|
||||
bridge_port = lif_interface_collection_find(collection, tokenp);
|
||||
if (bridge_port == NULL)
|
||||
{
|
||||
fprintf(stderr, "Failed to add interface \"%s\"", tokenp);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* We would have to creaet an interface, but shouldn't */
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "compat: Missing interface stanza for bridge-port \"%s\" but should not create one.\n",
|
||||
tokenp);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Maybe pimp bridge-pvid */
|
||||
struct lif_dict_entry *port_pvid = lif_dict_find(&bridge_port->vars, "bridge-pvid");
|
||||
if (bridge_pvid && !port_pvid)
|
||||
lif_dict_add(&bridge_port->vars, "bridge-pvid", bridge_pvid->data);
|
||||
|
||||
/* Maybe pimp bridge-vids */
|
||||
struct lif_dict_entry *port_vids = lif_dict_find(&bridge_port->vars, "bridge-vids");
|
||||
if (bridge_vids && !port_vids)
|
||||
lif_dict_add(&bridge_port->vars, "bridge-vids", bridge_vids->data);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
lif_compat_apply(struct lif_dict *collection)
|
||||
{
|
||||
if (lif_config.compat_ifupdown2_bridge_ports_inherit_vlans &&
|
||||
!compat_ifupdown2_bridge_ports_inherit_vlans(collection))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
24
libifupdown/compat.h
Normal file
24
libifupdown/compat.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* libifupdown/compat.h
|
||||
* Purpose: compatiblity glue to other implementations
|
||||
*
|
||||
* Copyright (c) 2020 Maximilian Wilhelm <max@sdn.clinic>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* This software is provided 'as is' and without any warranty, express or
|
||||
* implied. In no event shall the authors be liable for any damages arising
|
||||
* from the use of this software.
|
||||
*/
|
||||
|
||||
#ifndef LIBIFUPDOWN__COMPAT_H
|
||||
#define LIBIFUPDOWN__COMPAT_H
|
||||
|
||||
#include "libifupdown/config-file.h"
|
||||
#include "libifupdown/dict.h"
|
||||
|
||||
extern bool lif_compat_apply (struct lif_dict *collection);
|
||||
|
||||
#endif
|
||||
75
libifupdown/config-file.c
Normal file
75
libifupdown/config-file.c
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* libifupdown/config-file.c
|
||||
* Purpose: config file loading
|
||||
*
|
||||
* Copyright (c) 2020 Ariadne Conill <ariadne@dereferenced.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* This software is provided 'as is' and without any warranty, express or
|
||||
* implied. In no event shall the authors be liable for any damages arising
|
||||
* from the use of this software.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "libifupdown/libifupdown.h"
|
||||
|
||||
struct lif_config_file lif_config = {
|
||||
.allow_addon_scripts = true,
|
||||
.allow_any_iface_as_template = true,
|
||||
.auto_executor_selection = true,
|
||||
.compat_create_interfaces = true,
|
||||
.compat_ifupdown2_bridge_ports_inherit_vlans = true,
|
||||
.implicit_template_conversion = true,
|
||||
.use_hostname_for_dhcp = true,
|
||||
};
|
||||
|
||||
static bool
|
||||
set_bool_value(const char *key, const char *value, void *opaque)
|
||||
{
|
||||
(void) key;
|
||||
|
||||
if (*value == '1' ||
|
||||
*value == 'Y' || *value == 'y' ||
|
||||
*value == 'T' || *value == 't')
|
||||
*(bool *) opaque = true;
|
||||
else if (*value == '0' ||
|
||||
*value == 'N' || *value == 'n' ||
|
||||
*value == 'F' || *value == 'f')
|
||||
*(bool *) opaque = false;
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct lif_config_handler handlers[] = {
|
||||
{"allow_addon_scripts", set_bool_value, &lif_config.allow_addon_scripts},
|
||||
{"allow_any_iface_as_template", set_bool_value, &lif_config.allow_any_iface_as_template},
|
||||
{"auto_executor_selection", set_bool_value, &lif_config.auto_executor_selection},
|
||||
{"compat_create_interfaces", set_bool_value, &lif_config.compat_create_interfaces},
|
||||
{"compat_ifupdown2_bridge_ports_inherit_vlans", set_bool_value, &lif_config.compat_ifupdown2_bridge_ports_inherit_vlans},
|
||||
{"implicit_template_conversion", set_bool_value, &lif_config.implicit_template_conversion},
|
||||
{"use_hostname_for_dhcp", set_bool_value, &lif_config.use_hostname_for_dhcp},
|
||||
};
|
||||
|
||||
bool
|
||||
lif_config_load(const char *filename)
|
||||
{
|
||||
FILE *fd = fopen(filename, "r");
|
||||
|
||||
if (fd == NULL)
|
||||
{
|
||||
#if 0
|
||||
fprintf(stderr, "ifupdown-ng: cannot open config %s: %s\n",
|
||||
filename, strerror(errno));
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
return lif_config_parse_file(fd, filename, handlers, ARRAY_SIZE(handlers));
|
||||
}
|
||||
35
libifupdown/config-file.h
Normal file
35
libifupdown/config-file.h
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* libifupdown/config-file.h
|
||||
* Purpose: config file loading
|
||||
*
|
||||
* Copyright (c) 2020 Ariadne Conill <ariadne@dereferenced.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* This software is provided 'as is' and without any warranty, express or
|
||||
* implied. In no event shall the authors be liable for any damages arising
|
||||
* from the use of this software.
|
||||
*/
|
||||
|
||||
#ifndef LIBIFUPDOWN__CONFIG_FILE_H
|
||||
#define LIBIFUPDOWN__CONFIG_FILE_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
struct lif_config_file {
|
||||
bool allow_addon_scripts;
|
||||
bool allow_any_iface_as_template;
|
||||
bool auto_executor_selection;
|
||||
bool compat_create_interfaces;
|
||||
bool compat_ifupdown2_bridge_ports_inherit_vlans;
|
||||
bool implicit_template_conversion;
|
||||
bool use_hostname_for_dhcp;
|
||||
};
|
||||
|
||||
extern struct lif_config_file lif_config;
|
||||
|
||||
extern bool lif_config_load(const char *filename);
|
||||
|
||||
#endif
|
||||
87
libifupdown/config-parser.c
Normal file
87
libifupdown/config-parser.c
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* libifupdown/config-parser.c
|
||||
* Purpose: config parsing
|
||||
*
|
||||
* Copyright (c) 2020 Ariadne Conill <ariadne@dereferenced.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* This software is provided 'as is' and without any warranty, express or
|
||||
* implied. In no event shall the authors be liable for any damages arising
|
||||
* from the use of this software.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "libifupdown/config-parser.h"
|
||||
#include "libifupdown/fgetline.h"
|
||||
#include "libifupdown/tokenize.h"
|
||||
|
||||
static int
|
||||
handler_cmp(const void *a, const void *b)
|
||||
{
|
||||
const char *key = a;
|
||||
const struct lif_config_handler *hdl = b;
|
||||
|
||||
return strcmp(key, hdl->key);
|
||||
}
|
||||
|
||||
bool
|
||||
lif_config_parse_file(FILE *fd, const char *filename, struct lif_config_handler *handlers, size_t handler_count)
|
||||
{
|
||||
char linebuf[4096];
|
||||
size_t lineno = 0;
|
||||
|
||||
while (lif_fgetline(linebuf, sizeof linebuf, fd))
|
||||
{
|
||||
char *bufp = linebuf;
|
||||
char *key = lif_next_token_eq(&bufp);
|
||||
char *value = lif_next_token_eq(&bufp);
|
||||
|
||||
lineno++;
|
||||
|
||||
if (!*key || !*value)
|
||||
continue;
|
||||
|
||||
if (*key == '#')
|
||||
continue;
|
||||
|
||||
struct lif_config_handler *hdl = bsearch(key, handlers, handler_count, sizeof(*handlers),
|
||||
handler_cmp);
|
||||
|
||||
if (hdl == NULL)
|
||||
{
|
||||
fprintf(stderr, "ifupdown-ng: %s:%zu: warning: unknown config setting %s\n",
|
||||
filename, lineno, key);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!hdl->handle(key, value, hdl->opaque))
|
||||
{
|
||||
fclose(fd);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
lif_config_parse(const char *filename, struct lif_config_handler *handlers, size_t handler_count)
|
||||
{
|
||||
FILE *f = fopen(filename, "r");
|
||||
|
||||
if (f == NULL)
|
||||
{
|
||||
fprintf(stderr, "ifupdown-ng: unable to parse %s: %s\n", filename, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
return lif_config_parse_file(f, filename, handlers, handler_count);
|
||||
}
|
||||
32
libifupdown/config-parser.h
Normal file
32
libifupdown/config-parser.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* libifupdown/config-parser.h
|
||||
* Purpose: config parsing
|
||||
*
|
||||
* Copyright (c) 2020 Ariadne Conill <ariadne@dereferenced.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* This software is provided 'as is' and without any warranty, express or
|
||||
* implied. In no event shall the authors be liable for any damages arising
|
||||
* from the use of this software.
|
||||
*/
|
||||
|
||||
#ifndef LIBIFUPDOWN__CONFIG_PARSER_H
|
||||
#define LIBIFUPDOWN__CONFIG_PARSER_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
struct lif_config_handler {
|
||||
const char *key;
|
||||
bool (*handle)(const char *key, const char *value, void *opaque);
|
||||
void *opaque;
|
||||
};
|
||||
|
||||
extern bool lif_config_parse_file(FILE *f, const char *filename, struct lif_config_handler *handlers, size_t handler_count);
|
||||
extern bool lif_config_parse(const char *filename, struct lif_config_handler *handlers, size_t handler_count);
|
||||
|
||||
#endif
|
||||
|
|
@ -86,7 +86,7 @@ lif_dict_add_once(struct lif_dict *dict, const char *key, void *data,
|
|||
}
|
||||
|
||||
struct lif_dict_entry *
|
||||
lif_dict_find(struct lif_dict *dict, const char *key)
|
||||
lif_dict_find(const struct lif_dict *dict, const char *key)
|
||||
{
|
||||
struct lif_node *iter;
|
||||
|
||||
|
|
@ -102,7 +102,7 @@ lif_dict_find(struct lif_dict *dict, const char *key)
|
|||
}
|
||||
|
||||
struct lif_list *
|
||||
lif_dict_find_all(struct lif_dict *dict, const char *key)
|
||||
lif_dict_find_all(const struct lif_dict *dict, const char *key)
|
||||
{
|
||||
struct lif_list *entries = calloc(1, sizeof *entries);
|
||||
struct lif_node *iter;
|
||||
|
|
|
|||
|
|
@ -44,8 +44,8 @@ extern void lif_dict_init(struct lif_dict *dict);
|
|||
extern void lif_dict_fini(struct lif_dict *dict);
|
||||
extern struct lif_dict_entry *lif_dict_add(struct lif_dict *dict, const char *key, void *data);
|
||||
extern struct lif_dict_entry *lif_dict_add_once(struct lif_dict *dict, const char *key, void *data, lif_dict_cmp_t compar);
|
||||
extern struct lif_dict_entry *lif_dict_find(struct lif_dict *dict, const char *key);
|
||||
extern struct lif_list *lif_dict_find_all(struct lif_dict *dict, const char *key);
|
||||
extern struct lif_dict_entry *lif_dict_find(const struct lif_dict *dict, const char *key);
|
||||
extern struct lif_list *lif_dict_find_all(const struct lif_dict *dict, const char *key);
|
||||
extern void lif_dict_delete(struct lif_dict *dict, const char *key);
|
||||
extern void lif_dict_delete_entry(struct lif_dict *dict, struct lif_dict_entry *entry);
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,86 @@
|
|||
|
||||
#define SHELL "/bin/sh"
|
||||
|
||||
#if defined(__linux__)
|
||||
# include <sys/syscall.h>
|
||||
#endif
|
||||
|
||||
/* POSIX compatible fallback using waitpid(2) and usleep(3) */
|
||||
static inline bool
|
||||
lif_process_monitor_busyloop(pid_t child, int timeout_sec, int *status)
|
||||
{
|
||||
int ticks = 0;
|
||||
|
||||
while (ticks < timeout_sec * 20)
|
||||
{
|
||||
/* Ugly hack: most executors finish very quickly,
|
||||
* so give them a chance to finish before sleeping.
|
||||
*/
|
||||
usleep(50);
|
||||
|
||||
if (waitpid(child, status, WNOHANG) == child)
|
||||
return true;
|
||||
|
||||
usleep(49950);
|
||||
ticks++;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(__linux__) && defined(__NR_pidfd_open)
|
||||
|
||||
/* TODO: remove this wrapper once musl and glibc gain pidfd_open() directly. */
|
||||
static inline int
|
||||
lif_pidfd_open(pid_t pid, unsigned int flags)
|
||||
{
|
||||
return syscall(__NR_pidfd_open, pid, flags);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
lif_process_monitor_procdesc(pid_t child, int timeout_sec, int *status)
|
||||
{
|
||||
int pidfd = lif_pidfd_open(child, 0);
|
||||
|
||||
/* pidfd_open() not available, fall back to busyloop */
|
||||
if (pidfd == -1 && errno == ENOSYS)
|
||||
return lif_process_monitor_busyloop(child, timeout_sec, status);
|
||||
|
||||
struct pollfd pfd = {
|
||||
.fd = pidfd,
|
||||
.events = POLLIN,
|
||||
};
|
||||
|
||||
if (poll(&pfd, 1, timeout_sec * 1000) < 1)
|
||||
return false;
|
||||
|
||||
waitpid(child, status, 0);
|
||||
close(pidfd);
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static inline bool
|
||||
lif_process_monitor(const char *cmdbuf, pid_t child, int timeout_sec)
|
||||
{
|
||||
int status;
|
||||
|
||||
#if defined(__linux__) && defined(__NR_pidfd_open)
|
||||
if (lif_process_monitor_procdesc(child, timeout_sec, &status))
|
||||
return WIFEXITED(status) && WEXITSTATUS(status) == 0;
|
||||
#else
|
||||
if (lif_process_monitor_busyloop(child, timeout_sec, &status))
|
||||
return WIFEXITED(status) && WEXITSTATUS(status) == 0;
|
||||
#endif
|
||||
|
||||
fprintf(stderr, "execution of '%s': timeout after %d seconds\n", cmdbuf, timeout_sec);
|
||||
kill(child, SIGKILL);
|
||||
waitpid(child, &status, 0);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
lif_execute_fmt(const struct lif_execute_opts *opts, char *const envp[], const char *fmt, ...)
|
||||
{
|
||||
|
|
@ -55,10 +135,7 @@ lif_execute_fmt(const struct lif_execute_opts *opts, char *const envp[], const c
|
|||
return false;
|
||||
}
|
||||
|
||||
int status;
|
||||
waitpid(child, &status, 0);
|
||||
|
||||
return WIFEXITED(status) && WEXITSTATUS(status) == 0;
|
||||
return lif_process_monitor(cmdbuf, child, opts->timeout);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
@ -118,11 +195,8 @@ lif_execute_fmt_with_result(const struct lif_execute_opts *opts, char *buf, size
|
|||
return false;
|
||||
}
|
||||
|
||||
int status;
|
||||
no_result:
|
||||
waitpid(child, &status, 0);
|
||||
|
||||
return WIFEXITED(status) && WEXITSTATUS(status) == 0;
|
||||
return lif_process_monitor(cmdbuf, child, opts->timeout);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
@ -140,10 +214,10 @@ lif_file_is_executable(const char *path)
|
|||
}
|
||||
|
||||
bool
|
||||
lif_maybe_run_executor(const struct lif_execute_opts *opts, char *const envp[], const char *executor, const char *phase)
|
||||
lif_maybe_run_executor(const struct lif_execute_opts *opts, char *const envp[], const char *executor, const char *phase, const char *lifname)
|
||||
{
|
||||
if (opts->verbose)
|
||||
fprintf(stderr, "ifupdown: attempting to run %s executor for phase %s\n", executor, phase);
|
||||
fprintf(stderr, "ifupdown: %s: attempting to run %s executor for phase %s\n", lifname, executor, phase);
|
||||
|
||||
char pathbuf[4096];
|
||||
|
||||
|
|
@ -156,10 +230,10 @@ lif_maybe_run_executor(const struct lif_execute_opts *opts, char *const envp[],
|
|||
}
|
||||
|
||||
bool
|
||||
lif_maybe_run_executor_with_result(const struct lif_execute_opts *opts, char *const envp[], const char *executor, char *buf, size_t bufsize, const char *phase)
|
||||
lif_maybe_run_executor_with_result(const struct lif_execute_opts *opts, char *const envp[], const char *executor, char *buf, size_t bufsize, const char *phase, const char *lifname)
|
||||
{
|
||||
if (opts->verbose)
|
||||
fprintf(stderr, "ifupdown: attempting to run %s executor for phase %s\n", executor, phase);
|
||||
fprintf(stderr, "ifupdown: %s: attempting to run %s executor for phase %s\n", lifname, executor, phase);
|
||||
|
||||
char pathbuf[4096];
|
||||
|
||||
|
|
|
|||
|
|
@ -23,15 +23,17 @@ struct lif_execute_opts {
|
|||
bool verbose;
|
||||
bool mock;
|
||||
bool no_lock;
|
||||
bool force;
|
||||
const char *executor_path;
|
||||
const char *interfaces_file;
|
||||
const char *state_file;
|
||||
int timeout;
|
||||
};
|
||||
|
||||
extern bool lif_execute_fmt(const struct lif_execute_opts *opts, char *const envp[], const char *fmt, ...);
|
||||
extern bool lif_execute_fmt_with_result(const struct lif_execute_opts *opts, char *buf, size_t bufsize, char *const envp[], const char *fmt, ...);
|
||||
extern bool lif_file_is_executable(const char *path);
|
||||
extern bool lif_maybe_run_executor(const struct lif_execute_opts *opts, char *const envp[], const char *executor, const char *phase);
|
||||
extern bool lif_maybe_run_executor_with_result(const struct lif_execute_opts *opts, char *const envp[], const char *executor, char *buf, size_t bufsize, const char *phase);
|
||||
extern bool lif_maybe_run_executor(const struct lif_execute_opts *opts, char *const envp[], const char *executor, const char *phase, const char *lifname);
|
||||
extern bool lif_maybe_run_executor_with_result(const struct lif_execute_opts *opts, char *const envp[], const char *executor, char *buf, size_t bufsize, const char *phase, const char *lifname);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
* Purpose: /etc/network/interfaces parser
|
||||
*
|
||||
* Copyright (c) 2020 Ariadne Conill <ariadne@dereferenced.org>
|
||||
* Copyright (c) 2020 Maximilian Wilhelm <max@sdn.clinic>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
|
@ -14,8 +15,11 @@
|
|||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include "libifupdown/libifupdown.h"
|
||||
|
||||
/* internally rewrite problematic ifupdown2 tokens to ifupdown-ng equivalents */
|
||||
|
|
@ -26,14 +30,80 @@ struct remap_token {
|
|||
|
||||
/* this list must be in alphabetical order for bsearch */
|
||||
static const struct remap_token tokens[] = {
|
||||
{"bond-ad-sys-priority", "bond-ad-actor-sys-prio"}, /* ifupdown2 */
|
||||
{"bond-slaves", "bond-members"}, /* legacy ifupdown, ifupdown2 */
|
||||
{"client", "dhcp-client-id"}, /* legacy ifupdown */
|
||||
{"driver-message-level", "ethtool-msglvl"}, /* Debian ethtool integration */
|
||||
{"endpoint", "tunnel-remote"}, /* legacy ifupdown */
|
||||
{"ethernet-autoneg", "ethtool-ethernet-autoneg"}, /* Debian ethtool integration */
|
||||
{"ethernet-pause-autoneg", "ethtool-pause-autoneg"}, /* Debian ethtool integration */
|
||||
{"ethernet-pause-rx", "ethtool-pause-rx"}, /* Debian ethtool integration */
|
||||
{"ethernet-pause-tx", "ethtool-pause-tx"}, /* Debian ethtool integration */
|
||||
{"ethernet-port", "ethtool-ethernet-port"}, /* Debian ethtool integration */
|
||||
{"ethernet-wol", "ethtool-ethernet-wol"}, /* Debian ethtool integration */
|
||||
{"gro-offload", "ethtool-offload-gro"}, /* ifupdown2 */
|
||||
{"gso-offload", "ethtool-offload-gso"}, /* ifupdown2 */
|
||||
{"hardware-dma-ring-rx", "ethtool-dma-ring-rx"}, /* Debian ethtool integration */
|
||||
{"hardware-dma-ring-rx-jumbo", "ethtool-dma-ring-rx-jumbo"}, /* Debian ethtool integration */
|
||||
{"hardware-dma-ring-rx-mini", "ethtool-dma-ring-rx-mini"}, /* Debian ethtool integration */
|
||||
{"hardware-dma-ring-tx", "ethtool-dma-ring-tx"}, /* Debian ethtool integration */
|
||||
{"hardware-irq-coalesce-adaptive-rx", "ethtool-coalesce-adaptive-rx"}, /* Debian ethtool integration */
|
||||
{"hardware-irq-coalesce-adaptive-tx", "ethtool-coalesce-adaptive-tx"}, /* Debian ethtool integration */
|
||||
{"hardware-irq-coalesce-pkt-rate-high", "ethtool-coalesce-pkt-rate-high"}, /* Debian ethtool integration */
|
||||
{"hardware-irq-coalesce-pkt-rate-low", "ethtool-coalesce-pkt-rate-low"}, /* Debian ethtool integration */
|
||||
{"hardware-irq-coalesce-rx-frames", "ethtool-coalesce-rx-frames"}, /* Debian ethtool integration */
|
||||
{"hardware-irq-coalesce-rx-frames-high", "ethtool-coalesce-rx-frames-high"}, /* Debian ethtool integration */
|
||||
{"hardware-irq-coalesce-rx-frames-irq", "ethtool-coalesce-rx-frames-irq"}, /* Debian ethtool integration */
|
||||
{"hardware-irq-coalesce-rx-frames-low", "ethtool-coalesce-rx-frames-low"}, /* Debian ethtool integration */
|
||||
{"hardware-irq-coalesce-rx-usecs", "ethtool-coalesce-rx-usecs"}, /* Debian ethtool integration */
|
||||
{"hardware-irq-coalesce-rx-usecs-high", "ethtool-coalesce-rx-usecs-high"}, /* Debian ethtool integration */
|
||||
{"hardware-irq-coalesce-rx-usecs-irq", "ethtool-coalesce-rx-usecs-irq"}, /* Debian ethtool integration */
|
||||
{"hardware-irq-coalesce-rx-usecs-low", "ethtool-coalesce-rx-usecs-low"}, /* Debian ethtool integration */
|
||||
{"hardware-irq-coalesce-sample-interval", "ethtool-coalesce-sample-interval"}, /* Debian ethtool integration */
|
||||
{"hardware-irq-coalesce-stats-block-usecs", "ethtool-coalesce-stats-block-usecs"}, /* Debian ethtool integration */
|
||||
{"hardware-irq-coalesce-tx-frames", "ethtool-coalesce-tx-frames"}, /* Debian ethtool integration */
|
||||
{"hardware-irq-coalesce-tx-frames-high", "ethtool-coalesce-tx-frames-high"}, /* Debian ethtool integration */
|
||||
{"hardware-irq-coalesce-tx-frames-irq", "ethtool-coalesce-tx-frames-irq"}, /* Debian ethtool integration */
|
||||
{"hardware-irq-coalesce-tx-frames-low", "ethtool-coalesce-tx-frames-low"}, /* Debian ethtool integration */
|
||||
{"hardware-irq-coalesce-tx-usecs", "ethtool-coalesce-tx-usecs"}, /* Debian ethtool integration */
|
||||
{"hardware-irq-coalesce-tx-usecs-high", "ethtool-coalesce-tx-usecs-high"}, /* Debian ethtool integration */
|
||||
{"hardware-irq-coalesce-tx-usecs-irq", "ethtool-coalesce-tx-usecs-irq"}, /* Debian ethtool integration */
|
||||
{"hardware-irq-coalesce-tx-usecs-low", "ethtool-coalesce-tx-usecs-low"}, /* Debian ethtool integration */
|
||||
{"hostname", "dhcp-hostname"}, /* legacy ifupdown */
|
||||
{"key", "tunnel-key"}, /* legacy ifupdown */
|
||||
{"leasetime", "dhcp-leasetime"}, /* legacy ifupdown */
|
||||
{"link-autoneg", "ethtool-ethernet-autoneg"}, /* ifupdown2 */
|
||||
{"link-duplex", "ethtool-link-duplex"}, /* Debian ethtool integration */
|
||||
{"link-fec", "ethtool-link-fec"}, /* ifupdown2 */
|
||||
{"link-speed", "ethtool-link-speed"}, /* Debian ethtool integration */
|
||||
{"local", "tunnel-local"}, /* legacy ifupdown */
|
||||
{"lro-offload", "ethtool-offload-lro"}, /* ifupdown2 */
|
||||
{"mode", "tunnel-mode"}, /* legacy ifupdown */
|
||||
{"offload-gro", "ethtool-offload-gro"}, /* Debian ethtool integration */
|
||||
{"offload-gso", "ethtool-offload-gso"}, /* Debian ethtool integration */
|
||||
{"offload-lro", "ethtool-offload-lro"}, /* Debian ethtool integration */
|
||||
{"offload-rx", "ethtool-offload-rx"}, /* Debian ethtool integration */
|
||||
{"offload-sg", "ethtool-offload-sg"}, /* Debian ethtool integration */
|
||||
{"offload-tso", "ethtool-offload-tso"}, /* Debian ethtool integration */
|
||||
{"offload-tx", "ethtool-offload-tx"}, /* Debian ethtool integration */
|
||||
{"offload-ufo", "ethtool-offload-ufo"}, /* Debian ethtool integration */
|
||||
{"pointopoint", "point-to-point"}, /* legacy ifupdown, ifupdown2 */
|
||||
{"provider", "ppp-provider"}, /* legacy ifupdown, ifupdown2 */
|
||||
{"script", "dhcp-script"}, /* legacy ifupdown */
|
||||
{"rx-offload", "ethtool-offload-rx"}, /* ifupdown2 */
|
||||
{"tso-offload", "ethtool-offload-tso"}, /* ifupdown2 */
|
||||
{"ttl", "tunnel-ttl"}, /* legacy ifupdown */
|
||||
{"tunnel-endpoint", "tunnel-remote"}, /* ifupdown2 */
|
||||
{"tunnel-physdev", "tunnel-dev"}, /* ifupdown2 */
|
||||
{"tx-offload", "ethtool-offload-tx"}, /* ifupdown2 */
|
||||
{"ufo-offload", "ethtool-offload-ufo"}, /* ifupdown2 */
|
||||
{"vendor", "dhcp-vendor"}, /* legacy ifupdown */
|
||||
{"vrf", "vrf-member"}, /* ifupdown2 */
|
||||
{"vxlan-local-tunnelip", "vxlan-local-ip"}, /* ifupdown2 */
|
||||
{"vxlan-remote-group", "vxlan-peer-group"}, /* ifupdown-ng */
|
||||
{"vxlan-remoteip", "vxlan-peer-ips"}, /* ifupdown2 */
|
||||
{"vxlan-remote-ip", "vxlan-peer-ips"}, /* ifupdown-ng */
|
||||
{"vxlan-svcnodeip", "vxlan-peer-group"}, /* ifupdown2 */
|
||||
};
|
||||
|
||||
static int
|
||||
|
|
@ -57,184 +127,407 @@ maybe_remap_token(const char *token)
|
|||
return tokbuf;
|
||||
}
|
||||
|
||||
bool
|
||||
lif_interface_file_parse(struct lif_dict *collection, const char *filename)
|
||||
static void
|
||||
report_error(struct lif_interface_file_parse_state *state, const char *errfmt, ...)
|
||||
{
|
||||
lif_interface_collection_init(collection);
|
||||
struct lif_interface *cur_iface = NULL;
|
||||
char errbuf[4096];
|
||||
|
||||
va_list va;
|
||||
va_start(va, errfmt);
|
||||
vsnprintf(errbuf, sizeof errbuf, errfmt, va);
|
||||
va_end(va);
|
||||
|
||||
fprintf(stderr, "%s:%zu: %s\n", state->cur_filename, state->cur_lineno, errbuf);
|
||||
}
|
||||
|
||||
static bool
|
||||
handle_address(struct lif_interface_file_parse_state *state, char *token, char *bufp)
|
||||
{
|
||||
(void) token;
|
||||
|
||||
char *addr = lif_next_token(&bufp);
|
||||
|
||||
if (state->cur_iface == NULL)
|
||||
{
|
||||
report_error(state, "%s '%s' without interface", token, addr);
|
||||
/* Ignore this address, but don't fail hard */
|
||||
return true;
|
||||
}
|
||||
|
||||
lif_interface_address_add(state->cur_iface, addr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
handle_auto(struct lif_interface_file_parse_state *state, char *token, char *bufp)
|
||||
{
|
||||
(void) token;
|
||||
|
||||
char *ifname = lif_next_token(&bufp);
|
||||
if (!*ifname && state->cur_iface == NULL)
|
||||
{
|
||||
report_error(state, "auto without interface");
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
state->cur_iface = lif_interface_collection_find(state->collection, ifname);
|
||||
if (state->cur_iface == NULL)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!state->cur_iface->is_template)
|
||||
state->cur_iface->is_auto = true;
|
||||
|
||||
if (state->cur_iface->is_auto)
|
||||
state->cur_iface->is_explicit = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
handle_gateway(struct lif_interface_file_parse_state *state, char *token, char *bufp)
|
||||
{
|
||||
(void) token;
|
||||
|
||||
char *addr = lif_next_token(&bufp);
|
||||
|
||||
if (state->cur_iface == NULL)
|
||||
{
|
||||
report_error(state, "%s '%s' without interface", token, addr);
|
||||
/* Ignore this gateway, but don't fail hard */
|
||||
return true;
|
||||
}
|
||||
|
||||
lif_interface_use_executor(state->cur_iface, "static");
|
||||
lif_dict_add(&state->cur_iface->vars, token, strdup(addr));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
handle_generic(struct lif_interface_file_parse_state *state, char *token, char *bufp)
|
||||
{
|
||||
if (state->cur_iface == NULL)
|
||||
return true;
|
||||
|
||||
token = maybe_remap_token(token);
|
||||
|
||||
/* This smells like a bridge */
|
||||
if (strcmp(token, "bridge-ports") == 0)
|
||||
state->cur_iface->is_bridge = true;
|
||||
|
||||
/* Skip any leading whitespaces in value for <token> */
|
||||
while (isspace (*bufp))
|
||||
bufp++;
|
||||
|
||||
lif_dict_add(&state->cur_iface->vars, token, strdup(bufp));
|
||||
|
||||
if (!lif_config.auto_executor_selection)
|
||||
return true;
|
||||
|
||||
/* Check if token looks like <word1>-<word*> and assume <word1> is an addon */
|
||||
char *word_end = strchr(token, '-');
|
||||
if (word_end != NULL)
|
||||
{
|
||||
/* Copy word1 to not mangle *token */
|
||||
char *addon = strndup(token, word_end - token);
|
||||
lif_interface_use_executor(state->cur_iface, addon);
|
||||
free(addon);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
handle_hostname(struct lif_interface_file_parse_state *state, char *token, char *bufp)
|
||||
{
|
||||
char *hostname = lif_next_token(&bufp);
|
||||
|
||||
if (state->cur_iface == NULL)
|
||||
{
|
||||
report_error(state, "%s '%s' without interface", token, hostname);
|
||||
/* Ignore this hostname, but don't fail hard */
|
||||
return true;
|
||||
}
|
||||
|
||||
lif_dict_delete(&state->cur_iface->vars, "dhcp-hostname");
|
||||
lif_dict_add(&state->cur_iface->vars, "dhcp-hostname", strdup(hostname));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool handle_inherit(struct lif_interface_file_parse_state *state, char *token, char *bufp);
|
||||
|
||||
static bool
|
||||
handle_iface(struct lif_interface_file_parse_state *state, char *token, char *bufp)
|
||||
{
|
||||
char *ifname = lif_next_token(&bufp);
|
||||
if (!*ifname)
|
||||
{
|
||||
report_error(state, "%s without any other tokens", token);
|
||||
/* This is broken but not fatal */
|
||||
return true;
|
||||
}
|
||||
|
||||
/* if we have a current interface, call lif_interface_finalize to finalize any
|
||||
* address properties by converting them to CIDR and flushing the netmask property.
|
||||
*/
|
||||
if (state->cur_iface != NULL)
|
||||
lif_interface_finalize(state->cur_iface);
|
||||
|
||||
state->cur_iface = lif_interface_collection_find(state->collection, ifname);
|
||||
if (state->cur_iface == NULL)
|
||||
{
|
||||
report_error(state, "could not upsert interface %s", ifname);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* mark the state->cur_iface as a template iface if `template` keyword
|
||||
* is used.
|
||||
*/
|
||||
if (!strcmp(token, "template"))
|
||||
{
|
||||
state->cur_iface->is_auto = false;
|
||||
state->cur_iface->is_template = true;
|
||||
}
|
||||
|
||||
/* in original ifupdown config, we can have "inet loopback"
|
||||
* or "inet dhcp" or such to designate hints. lets pick up
|
||||
* those hints here.
|
||||
*/
|
||||
token = lif_next_token(&bufp);
|
||||
while (*token)
|
||||
{
|
||||
if (!strcmp(token, "dhcp"))
|
||||
lif_interface_use_executor(state->cur_iface, "dhcp");
|
||||
else if (!strcmp(token, "ppp"))
|
||||
lif_interface_use_executor(state->cur_iface, "ppp");
|
||||
else if (!strcmp(token, "inherits"))
|
||||
{
|
||||
if (!handle_inherit(state, token, bufp))
|
||||
return false;
|
||||
}
|
||||
|
||||
token = lif_next_token(&bufp);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
handle_inherit(struct lif_interface_file_parse_state *state, char *token, char *bufp)
|
||||
{
|
||||
char *target = lif_next_token(&bufp);
|
||||
|
||||
if (state->cur_iface == NULL)
|
||||
{
|
||||
report_error(state, "%s '%s' without interface", token, target);
|
||||
/* This is broken but not fatal */
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!*target)
|
||||
{
|
||||
report_error(state, "iface %s: unspecified inherit target", state->cur_iface->ifname);
|
||||
/* Mark this interface as errornous but carry on */
|
||||
state->cur_iface->has_config_error = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
struct lif_interface *parent = lif_interface_collection_find(state->collection, target);
|
||||
if (parent == NULL)
|
||||
{
|
||||
report_error(state, "iface %s: could not inherit from %s: not found",
|
||||
state->cur_iface->ifname, target);
|
||||
/* Mark this interface as errornous but carry on */
|
||||
state->cur_iface->has_config_error = true;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
if (!lif_config.allow_any_iface_as_template && !parent->is_template)
|
||||
{
|
||||
report_error(state, "iface %s: could not inherit from %ss: inheritence from non-template interface not allowed",
|
||||
state->cur_iface->ifname, target);
|
||||
/* Mark this interface as errornous but carry on */
|
||||
state->cur_iface->has_config_error = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!lif_interface_collection_inherit(state->cur_iface, parent))
|
||||
{
|
||||
report_error(state, "iface %s: could not inherit from %s", state->cur_iface->ifname, target);
|
||||
/* Mark this interface as errornous but carry on */
|
||||
state->cur_iface->has_config_error = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
handle_source(struct lif_interface_file_parse_state *state, char *token, char *bufp)
|
||||
{
|
||||
(void) token;
|
||||
|
||||
char *source_filename = lif_next_token(&bufp);
|
||||
if (!*source_filename)
|
||||
{
|
||||
report_error(state, "missing filename to source");
|
||||
/* Broken but not fatal */
|
||||
return true;
|
||||
}
|
||||
|
||||
return lif_interface_file_parse(state, source_filename);
|
||||
}
|
||||
|
||||
static bool
|
||||
handle_source_directory(struct lif_interface_file_parse_state *state, char *token, char *bufp)
|
||||
{
|
||||
(void) token;
|
||||
|
||||
char *source_directory = lif_next_token(&bufp);
|
||||
if (!*source_directory)
|
||||
{
|
||||
report_error(state, "missing directory to source");
|
||||
/* Broken but not fatal */
|
||||
return true;
|
||||
}
|
||||
|
||||
DIR *source_dir = opendir(source_directory);
|
||||
if (source_dir == NULL)
|
||||
{
|
||||
report_error(state, "while opening directory %s: %s", source_directory, strerror(errno));
|
||||
/* Broken but not fatal */
|
||||
return true;
|
||||
}
|
||||
|
||||
struct dirent *dirent_p;
|
||||
for (dirent_p = readdir(source_dir); dirent_p != NULL; dirent_p = readdir(source_dir))
|
||||
{
|
||||
if (dirent_p->d_type != DT_REG)
|
||||
continue;
|
||||
|
||||
char pathbuf[4096];
|
||||
snprintf(pathbuf, sizeof pathbuf, "%s/%s", source_directory, dirent_p->d_name);
|
||||
|
||||
if (!lif_interface_file_parse(state, pathbuf))
|
||||
{
|
||||
closedir(source_dir);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
closedir(source_dir);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
handle_use(struct lif_interface_file_parse_state *state, char *token, char *bufp)
|
||||
{
|
||||
char *executor = lif_next_token(&bufp);
|
||||
|
||||
if (state->cur_iface == NULL)
|
||||
{
|
||||
report_error(state, "%s '%s' without interface", token, executor);
|
||||
/* Broken but not fatal */
|
||||
return true;
|
||||
}
|
||||
|
||||
lif_interface_use_executor(state->cur_iface, executor);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* map keywords to parser functions */
|
||||
struct parser_keyword {
|
||||
const char *token;
|
||||
bool (*handle)(struct lif_interface_file_parse_state *state, char *token, char *bufp);
|
||||
};
|
||||
|
||||
static const struct parser_keyword keywords[] = {
|
||||
{"address", handle_address},
|
||||
{"auto", handle_auto},
|
||||
{"dhcp-hostname", handle_hostname},
|
||||
{"gateway", handle_gateway},
|
||||
{"hostname", handle_hostname},
|
||||
{"iface", handle_iface},
|
||||
{"inherit", handle_inherit},
|
||||
{"interface", handle_iface},
|
||||
{"source", handle_source},
|
||||
{"source-directory", handle_source_directory},
|
||||
{"template", handle_iface},
|
||||
{"use", handle_use},
|
||||
};
|
||||
|
||||
static int
|
||||
keyword_cmp(const void *a, const void *b)
|
||||
{
|
||||
const char *key = a;
|
||||
const struct parser_keyword *token = b;
|
||||
|
||||
return strcmp(key, token->token);
|
||||
}
|
||||
|
||||
bool
|
||||
lif_interface_file_parse(struct lif_interface_file_parse_state *state, const char *filename)
|
||||
{
|
||||
struct lif_dict_entry *entry = lif_dict_find(&state->loaded, filename);
|
||||
if (entry != NULL)
|
||||
{
|
||||
report_error(state, "skipping already included file %s", filename);
|
||||
return true;
|
||||
}
|
||||
|
||||
FILE *f = fopen(filename, "r");
|
||||
if (f == NULL)
|
||||
return false;
|
||||
|
||||
const char *old_filename = state->cur_filename;
|
||||
state->cur_filename = filename;
|
||||
|
||||
size_t old_lineno = state->cur_lineno;
|
||||
state->cur_lineno = 0;
|
||||
|
||||
lif_dict_add(&state->loaded, filename, NULL);
|
||||
|
||||
char linebuf[4096];
|
||||
while (lif_fgetline(linebuf, sizeof linebuf, f) != NULL)
|
||||
{
|
||||
state->cur_lineno++;
|
||||
|
||||
char *bufp = linebuf;
|
||||
char *token = lif_next_token(&bufp);
|
||||
|
||||
if (!*token || !isalpha(*token))
|
||||
continue;
|
||||
|
||||
if (!strcmp(token, "source"))
|
||||
const struct parser_keyword *parserkw =
|
||||
bsearch(token, keywords, ARRAY_SIZE(keywords), sizeof(*keywords), keyword_cmp);
|
||||
|
||||
if (parserkw != NULL)
|
||||
{
|
||||
char *source_filename = lif_next_token(&bufp);
|
||||
if (!*source_filename)
|
||||
if (!parserkw->handle(state, token, bufp))
|
||||
goto parse_error;
|
||||
|
||||
if (!strcmp(filename, source_filename))
|
||||
{
|
||||
fprintf(stderr, "%s: attempt to source %s would create infinite loop\n",
|
||||
filename, source_filename);
|
||||
goto parse_error;
|
||||
}
|
||||
|
||||
lif_interface_file_parse(collection, source_filename);
|
||||
}
|
||||
else if (!strcmp(token, "auto"))
|
||||
{
|
||||
char *ifname = lif_next_token(&bufp);
|
||||
if (!*ifname && cur_iface == NULL)
|
||||
goto parse_error;
|
||||
else
|
||||
{
|
||||
cur_iface = lif_interface_collection_find(collection, ifname);
|
||||
if (cur_iface == NULL)
|
||||
goto parse_error;
|
||||
}
|
||||
|
||||
cur_iface->is_auto = true;
|
||||
}
|
||||
else if (!strcmp(token, "iface"))
|
||||
{
|
||||
char *ifname = lif_next_token(&bufp);
|
||||
if (!*ifname)
|
||||
goto parse_error;
|
||||
|
||||
cur_iface = lif_interface_collection_find(collection, ifname);
|
||||
if (cur_iface == NULL)
|
||||
goto parse_error;
|
||||
|
||||
/* in original ifupdown config, we can have "inet loopback"
|
||||
* or "inet dhcp" or such to designate hints. lets pick up
|
||||
* those hints here.
|
||||
*/
|
||||
char *token = lif_next_token(&bufp);
|
||||
while (*token)
|
||||
{
|
||||
if (!strcmp(token, "dhcp"))
|
||||
lif_interface_use_executor(cur_iface, "dhcp");
|
||||
else if (!strcmp(token, "ppp"))
|
||||
lif_interface_use_executor(cur_iface, "ppp");
|
||||
else if (!strcmp(token, "inherits"))
|
||||
{
|
||||
token = lif_next_token(&bufp);
|
||||
|
||||
if (!*token)
|
||||
{
|
||||
fprintf(stderr, "%s: inherits without interface\n", filename);
|
||||
goto parse_error;
|
||||
}
|
||||
|
||||
if (!lif_interface_collection_inherit(cur_iface, collection, token))
|
||||
{
|
||||
fprintf(stderr, "%s: could not inherit %s\n", filename, token);
|
||||
goto parse_error;
|
||||
}
|
||||
}
|
||||
|
||||
token = lif_next_token(&bufp);
|
||||
}
|
||||
}
|
||||
else if (!strcmp(token, "use"))
|
||||
{
|
||||
char *executor = lif_next_token(&bufp);
|
||||
|
||||
if (cur_iface == NULL)
|
||||
{
|
||||
fprintf(stderr, "%s: use '%s' without interface\n", filename, executor);
|
||||
goto parse_error;
|
||||
}
|
||||
|
||||
/* pass requires as compatibility env vars to appropriate executors (bridge, bond) */
|
||||
if (!strcmp(executor, "bridge"))
|
||||
cur_iface->is_bridge = true;
|
||||
else if (!strcmp(executor, "bond"))
|
||||
cur_iface->is_bond = true;
|
||||
|
||||
lif_interface_use_executor(cur_iface, executor);
|
||||
}
|
||||
else if (!strcmp(token, "inherit"))
|
||||
{
|
||||
token = lif_next_token(&bufp);
|
||||
|
||||
if (!*token)
|
||||
{
|
||||
fprintf(stderr, "%s: inherits without interface\n", filename);
|
||||
goto parse_error;
|
||||
}
|
||||
|
||||
if (!lif_interface_collection_inherit(cur_iface, collection, token))
|
||||
{
|
||||
fprintf(stderr, "%s: could not inherit %s\n", filename, token);
|
||||
goto parse_error;
|
||||
}
|
||||
}
|
||||
else if (!strcmp(token, "address"))
|
||||
{
|
||||
char *addr = lif_next_token(&bufp);
|
||||
|
||||
if (cur_iface == NULL)
|
||||
{
|
||||
fprintf(stderr, "%s: address '%s' without interface\n", filename, addr);
|
||||
goto parse_error;
|
||||
}
|
||||
|
||||
lif_interface_address_add(cur_iface, addr);
|
||||
}
|
||||
else if (!strcmp(token, "gateway"))
|
||||
{
|
||||
char *addr = lif_next_token(&bufp);
|
||||
|
||||
if (cur_iface == NULL)
|
||||
{
|
||||
fprintf(stderr, "%s: gateway '%s' without interface\n", filename, addr);
|
||||
goto parse_error;
|
||||
}
|
||||
|
||||
lif_interface_use_executor(cur_iface, "static");
|
||||
lif_dict_add(&cur_iface->vars, token, strdup(addr));
|
||||
}
|
||||
else if (cur_iface != NULL)
|
||||
{
|
||||
token = maybe_remap_token(token);
|
||||
|
||||
lif_dict_add(&cur_iface->vars, token, strdup(bufp));
|
||||
|
||||
/* Check if token looks like <word1>-<word*> and assume <word1> is an addon */
|
||||
char *word_end = strchr(token, '-');
|
||||
if (word_end != NULL)
|
||||
{
|
||||
/* Copy word1 to not mangle *token */
|
||||
char *addon = strndup(token, word_end - token);
|
||||
lif_interface_use_executor(cur_iface, addon);
|
||||
free(addon);
|
||||
|
||||
/* pass requires as compatibility env vars to appropriate executors (bridge, bond) */
|
||||
if (!strcmp(addon, "bridge"))
|
||||
cur_iface->is_bridge = true;
|
||||
else if (!strcmp(addon, "bond"))
|
||||
cur_iface->is_bond = true;
|
||||
}
|
||||
}
|
||||
else if (!handle_generic(state, token, bufp))
|
||||
goto parse_error;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
/* finalize any open interface */
|
||||
if (state->cur_iface != NULL)
|
||||
lif_interface_finalize(state->cur_iface);
|
||||
|
||||
state->cur_filename = old_filename;
|
||||
state->cur_lineno = old_lineno;
|
||||
return true;
|
||||
|
||||
parse_error:
|
||||
fprintf(stderr, "libifupdown: %s: failed to parse line \"%s\"\n",
|
||||
filename, linebuf);
|
||||
fclose(f);
|
||||
state->cur_filename = old_filename;
|
||||
state->cur_lineno = old_lineno;
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,17 @@
|
|||
|
||||
#include <stdbool.h>
|
||||
#include "libifupdown/interface.h"
|
||||
#include "libifupdown/dict.h"
|
||||
|
||||
extern bool lif_interface_file_parse(struct lif_dict *collection, const char *filename);
|
||||
struct lif_interface_file_parse_state {
|
||||
struct lif_interface *cur_iface;
|
||||
struct lif_dict *collection;
|
||||
const char *cur_filename;
|
||||
size_t cur_lineno;
|
||||
|
||||
struct lif_dict loaded;
|
||||
};
|
||||
|
||||
extern bool lif_interface_file_parse(struct lif_interface_file_parse_state *state, const char *filename);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
* Purpose: interface management
|
||||
*
|
||||
* Copyright (c) 2020 Ariadne Conill <ariadne@dereferenced.org>
|
||||
* Copyright (c) 2020 Maximilian Wilhelm <max@sdn.clinic>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
|
@ -15,7 +16,9 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/utsname.h>
|
||||
#include "libifupdown/interface.h"
|
||||
#include "libifupdown/config-file.h"
|
||||
|
||||
bool
|
||||
lif_address_parse(struct lif_address *address, const char *presentation)
|
||||
|
|
@ -56,6 +59,63 @@ lif_address_unparse(const struct lif_address *address, char *buf, size_t buflen,
|
|||
return true;
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
count_set_bits(const char *netmask)
|
||||
{
|
||||
/* netmask set to CIDR length */
|
||||
if (strchr(netmask, '.') == NULL)
|
||||
return strtol(netmask, NULL, 10);
|
||||
|
||||
size_t r = 0;
|
||||
struct in_addr in;
|
||||
|
||||
if (inet_pton(AF_INET, netmask, &in) == 0)
|
||||
return r;
|
||||
|
||||
/* take the IP, put it in host endian order, and
|
||||
* flip it so that all the set bits are set to the right.
|
||||
* then we can simply count down from 32 and right-shift
|
||||
* until the bit field is all zero.
|
||||
*/
|
||||
unsigned int bits = htonl(in.s_addr);
|
||||
for (bits = ~bits, r = 32; bits; bits >>= 1, r--)
|
||||
;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
determine_interface_netmask(const struct lif_interface *iface, const struct lif_address *addr)
|
||||
{
|
||||
/* if netmask is not set, default to /24 or /64, ifupdown does so too */
|
||||
size_t netmask = addr->domain == AF_INET6 ? 64 : 24;
|
||||
|
||||
struct lif_dict_entry *entry = lif_dict_find(&iface->vars, "netmask");
|
||||
if (entry != NULL)
|
||||
netmask = count_set_bits(entry->data);
|
||||
|
||||
return netmask;
|
||||
}
|
||||
|
||||
bool
|
||||
lif_address_format_cidr(const struct lif_interface *iface, struct lif_dict_entry *entry, char *buf, size_t buflen)
|
||||
{
|
||||
struct lif_address *addr = entry->data;
|
||||
size_t orig_netmask = addr->netmask;
|
||||
|
||||
if (!addr->netmask)
|
||||
addr->netmask = determine_interface_netmask(iface, addr);
|
||||
|
||||
if (!lif_address_unparse(addr, buf, buflen, true))
|
||||
{
|
||||
addr->netmask = orig_netmask;
|
||||
return false;
|
||||
}
|
||||
|
||||
addr->netmask = orig_netmask;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
lif_interface_init(struct lif_interface *interface, const char *ifname)
|
||||
{
|
||||
|
|
@ -141,6 +201,52 @@ lif_interface_use_executor(struct lif_interface *interface, const char *executor
|
|||
|
||||
if (lif_dict_add_once(&interface->vars, "use", exec_addon, (lif_dict_cmp_t) strcmp) == NULL)
|
||||
free(exec_addon);
|
||||
|
||||
/* pass requires as compatibility env vars to appropriate executors (bridge, bond) */
|
||||
if (!strcmp(executor, "bridge"))
|
||||
interface->is_bridge = true;
|
||||
else if (!strcmp(executor, "bond"))
|
||||
interface->is_bond = true;
|
||||
|
||||
if (strcmp(executor, "dhcp") || !lif_config.use_hostname_for_dhcp)
|
||||
return;
|
||||
|
||||
/* learn a reasonable default hostname */
|
||||
struct utsname un;
|
||||
if (uname(&un) < 0)
|
||||
return;
|
||||
|
||||
lif_dict_add(&interface->vars, "dhcp-hostname", strdup(un.nodename));
|
||||
}
|
||||
|
||||
void
|
||||
lif_interface_finalize(struct lif_interface *interface)
|
||||
{
|
||||
struct lif_node *iter;
|
||||
|
||||
/* convert all addresses to CIDR notation. */
|
||||
LIF_DICT_FOREACH(iter, &interface->vars)
|
||||
{
|
||||
struct lif_dict_entry *entry = iter->data;
|
||||
|
||||
if (strcmp(entry->key, "address"))
|
||||
continue;
|
||||
|
||||
struct lif_address *addr = entry->data;
|
||||
|
||||
if (!addr->netmask)
|
||||
addr->netmask = determine_interface_netmask(interface, addr);
|
||||
}
|
||||
|
||||
/* with all addresses converted to CIDR, netmask property is no longer needed. */
|
||||
struct lif_dict_entry *entry = lif_dict_find(&interface->vars, "netmask");
|
||||
|
||||
if (entry != NULL)
|
||||
{
|
||||
free(entry->data);
|
||||
|
||||
lif_dict_delete_entry(&interface->vars, entry);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -153,6 +259,7 @@ lif_interface_collection_init(struct lif_dict *collection)
|
|||
/* always enable loopback interface as part of a collection */
|
||||
if_lo = lif_interface_collection_find(collection, "lo");
|
||||
if_lo->is_auto = true;
|
||||
if_lo->is_explicit = true;
|
||||
lif_interface_use_executor(if_lo, "loopback");
|
||||
}
|
||||
|
||||
|
|
@ -226,14 +333,13 @@ lif_interface_collection_delete(struct lif_dict *collection, struct lif_interfac
|
|||
}
|
||||
|
||||
bool
|
||||
lif_interface_collection_inherit(struct lif_interface *interface, struct lif_dict *collection, const char *ifname)
|
||||
lif_interface_collection_inherit(struct lif_interface *interface, struct lif_interface *parent)
|
||||
{
|
||||
struct lif_interface *parent = lif_interface_collection_find(collection, ifname);
|
||||
/* maybe convert any interface we are inheriting from into a template */
|
||||
if (lif_config.implicit_template_conversion)
|
||||
parent->is_template = true;
|
||||
|
||||
if (parent == NULL)
|
||||
return false;
|
||||
|
||||
lif_dict_add(&interface->vars, "inherit", strdup(ifname));
|
||||
lif_dict_add(&interface->vars, "inherit", strdup(parent->ifname));
|
||||
interface->is_bond = parent->is_bond;
|
||||
interface->is_bridge = parent->is_bridge;
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
* Purpose: interface management
|
||||
*
|
||||
* Copyright (c) 2020 Ariadne Conill <ariadne@dereferenced.org>
|
||||
* Copyright (c) 2020 Maximilian Wilhelm <max@sdn.clinic>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
|
@ -31,9 +32,6 @@ struct lif_address {
|
|||
int domain;
|
||||
};
|
||||
|
||||
extern bool lif_address_parse(struct lif_address *address, const char *presentation);
|
||||
extern bool lif_address_unparse(const struct lif_address *address, char *buf, size_t buflen, bool with_netmask);
|
||||
|
||||
/*
|
||||
* Interfaces are contained in a dictionary, with the interfaces mapped by
|
||||
* interface name to their `struct lif_interface`.
|
||||
|
|
@ -50,10 +48,16 @@ struct lif_interface {
|
|||
bool is_auto;
|
||||
bool is_bridge;
|
||||
bool is_bond;
|
||||
bool is_template;
|
||||
bool is_pending;
|
||||
bool is_explicit;
|
||||
|
||||
bool has_config_error; /* error found in interface configuration */
|
||||
|
||||
struct lif_dict vars;
|
||||
|
||||
bool is_up;
|
||||
size_t refcount; /* > 0 if up, else 0 */
|
||||
size_t rdepends_count; /* > 0 if any reverse dependency */
|
||||
};
|
||||
|
||||
#define LIF_INTERFACE_COLLECTION_FOREACH(iter, collection) \
|
||||
|
|
@ -62,17 +66,22 @@ struct lif_interface {
|
|||
#define LIF_INTERFACE_COLLECTION_FOREACH_SAFE(iter, iter_next, collection) \
|
||||
LIF_DICT_FOREACH_SAFE((iter), (iter_next), (collection))
|
||||
|
||||
extern bool lif_address_parse(struct lif_address *address, const char *presentation);
|
||||
extern bool lif_address_unparse(const struct lif_address *address, char *buf, size_t buflen, bool with_netmask);
|
||||
extern bool lif_address_format_cidr(const struct lif_interface *iface, struct lif_dict_entry *entry, char *buf, size_t buflen);
|
||||
|
||||
extern void lif_interface_init(struct lif_interface *interface, const char *ifname);
|
||||
extern bool lif_interface_address_add(struct lif_interface *interface, const char *address);
|
||||
extern void lif_interface_address_delete(struct lif_interface *interface, const char *address);
|
||||
extern void lif_interface_fini(struct lif_interface *interface);
|
||||
extern void lif_interface_use_executor(struct lif_interface *interface, const char *executor);
|
||||
extern void lif_interface_finalize(struct lif_interface *interface);
|
||||
|
||||
extern void lif_interface_collection_init(struct lif_dict *collection);
|
||||
extern void lif_interface_collection_fini(struct lif_dict *collection);
|
||||
extern struct lif_interface *lif_interface_collection_find(struct lif_dict *collection, const char *ifname);
|
||||
extern struct lif_interface *lif_interface_collection_upsert(struct lif_dict *collection, struct lif_interface *interface);
|
||||
extern bool lif_interface_collection_inherit(struct lif_interface *interface, struct lif_dict *collection, const char *ifname);
|
||||
extern bool lif_interface_collection_inherit(struct lif_interface *interface, struct lif_interface *parent);
|
||||
extern void lif_interface_collection_delete(struct lif_dict *collection, struct lif_interface *interface);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -27,6 +27,9 @@
|
|||
#include "libifupdown/execute.h"
|
||||
#include "libifupdown/lifecycle.h"
|
||||
#include "libifupdown/tokenize.h"
|
||||
#include "libifupdown/config-file.h"
|
||||
#include "libifupdown/config-parser.h"
|
||||
#include "libifupdown/compat.h"
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
# define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x))
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
* Purpose: management of interface lifecycle (bring up, takedown, reload)
|
||||
*
|
||||
* Copyright (c) 2020 Ariadne Conill <ariadne@dereferenced.org>
|
||||
* Copyright (c) 2020 Maximilian Wilhelm <max@sdn.clinic>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
|
@ -15,6 +16,9 @@
|
|||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "libifupdown/environment.h"
|
||||
#include "libifupdown/execute.h"
|
||||
|
|
@ -22,15 +26,18 @@
|
|||
#include "libifupdown/lifecycle.h"
|
||||
#include "libifupdown/state.h"
|
||||
#include "libifupdown/tokenize.h"
|
||||
#include "libifupdown/config-file.h"
|
||||
|
||||
#define BUFFER_LEN 4096
|
||||
|
||||
static bool
|
||||
handle_commands_for_phase(const struct lif_execute_opts *opts, char *const envp[], struct lif_interface *iface, const char *phase)
|
||||
handle_commands_for_phase(const struct lif_execute_opts *opts, char *const envp[], const struct lif_interface *iface, const char *phase)
|
||||
{
|
||||
struct lif_node *iter;
|
||||
const struct lif_node *iter;
|
||||
|
||||
LIF_DICT_FOREACH(iter, &iface->vars)
|
||||
{
|
||||
struct lif_dict_entry *entry = iter->data;
|
||||
const struct lif_dict_entry *entry = iter->data;
|
||||
|
||||
if (strcmp(entry->key, phase))
|
||||
continue;
|
||||
|
|
@ -44,57 +51,58 @@ handle_commands_for_phase(const struct lif_execute_opts *opts, char *const envp[
|
|||
}
|
||||
|
||||
static inline bool
|
||||
handle_single_executor_for_phase(const struct lif_dict_entry *entry, const struct lif_execute_opts *opts, char *const envp[], const char *phase)
|
||||
handle_single_executor_for_phase(const struct lif_dict_entry *entry, const struct lif_execute_opts *opts, char *const envp[], const char *phase, const char *lifname)
|
||||
{
|
||||
if (strcmp(entry->key, "use"))
|
||||
return true;
|
||||
|
||||
const char *cmd = entry->data;
|
||||
if (!lif_maybe_run_executor(opts, envp, cmd, phase))
|
||||
if (!lif_maybe_run_executor(opts, envp, cmd, phase, lifname))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
handle_executors_for_phase(const struct lif_execute_opts *opts, char *const envp[], struct lif_interface *iface, bool up, const char *phase)
|
||||
handle_executors_for_phase(const struct lif_execute_opts *opts, char *const envp[], const struct lif_interface *iface, bool up, const char *phase)
|
||||
{
|
||||
struct lif_node *iter;
|
||||
const struct lif_node *iter;
|
||||
|
||||
if (up)
|
||||
{
|
||||
LIF_DICT_FOREACH(iter, &iface->vars)
|
||||
handle_single_executor_for_phase(iter->data, opts, envp, phase);
|
||||
handle_single_executor_for_phase(iter->data, opts, envp, phase, iface->ifname);
|
||||
}
|
||||
else
|
||||
{
|
||||
LIF_DICT_FOREACH_REVERSE(iter, &iface->vars)
|
||||
handle_single_executor_for_phase(iter->data, opts, envp, phase);
|
||||
handle_single_executor_for_phase(iter->data, opts, envp, phase, iface->ifname);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
query_dependents_from_executors(const struct lif_execute_opts *opts, char *const envp[], struct lif_interface *iface, char *buf, size_t bufsize, const char *phase)
|
||||
query_dependents_from_executors(const struct lif_execute_opts *opts, char *const envp[], const struct lif_interface *iface, char *buf, size_t bufsize, const char *phase)
|
||||
{
|
||||
struct lif_node *iter;
|
||||
const struct lif_node *iter;
|
||||
|
||||
LIF_DICT_FOREACH(iter, &iface->vars)
|
||||
{
|
||||
char resbuf[1024] = {};
|
||||
struct lif_dict_entry *entry = iter->data;
|
||||
const struct lif_dict_entry *entry = iter->data;
|
||||
struct lif_execute_opts exec_opts = {
|
||||
.verbose = opts->verbose,
|
||||
.executor_path = opts->executor_path,
|
||||
.interfaces_file = opts->interfaces_file
|
||||
.interfaces_file = opts->interfaces_file,
|
||||
.timeout = opts->timeout,
|
||||
};
|
||||
|
||||
if (strcmp(entry->key, "use"))
|
||||
continue;
|
||||
|
||||
const char *cmd = entry->data;
|
||||
if (!lif_maybe_run_executor_with_result(&exec_opts, envp, cmd, resbuf, sizeof resbuf, phase))
|
||||
if (!lif_maybe_run_executor_with_result(&exec_opts, envp, cmd, resbuf, sizeof resbuf, phase, iface->ifname))
|
||||
return false;
|
||||
|
||||
if (!*resbuf)
|
||||
|
|
@ -107,8 +115,41 @@ query_dependents_from_executors(const struct lif_execute_opts *opts, char *const
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
append_to_buffer(char **buffer, size_t *buffer_len, char **end, const char *value)
|
||||
{
|
||||
size_t value_len = strlen (value);
|
||||
|
||||
/* Make sure there is enough room to add the value to the buffer */
|
||||
if (*buffer_len < strlen (*buffer) + value_len + 2)
|
||||
{
|
||||
size_t end_offset = *end - *buffer;
|
||||
char *tmp = realloc (*buffer, *buffer_len * 2);
|
||||
|
||||
if (tmp != NULL)
|
||||
{
|
||||
*buffer = tmp;
|
||||
*end = tmp + end_offset;
|
||||
*buffer_len = *buffer_len * 2;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Append value to buffer */
|
||||
size_t printed = snprintf (*end, value_len + 2, "%s ", value);
|
||||
if (printed < value_len + 1)
|
||||
/* Here be dragons */
|
||||
return false;
|
||||
|
||||
/* Move end pointer to last printed byte */
|
||||
*end += printed;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
build_environment(char **envp[], const struct lif_execute_opts *opts, struct lif_interface *iface, const char *lifname, const char *phase, const char *mode)
|
||||
build_environment(char **envp[], const struct lif_execute_opts *opts, const struct lif_interface *iface, const char *lifname, const char *phase, const char *mode)
|
||||
{
|
||||
if (lifname == NULL)
|
||||
lifname = iface->ifname;
|
||||
|
|
@ -124,22 +165,35 @@ build_environment(char **envp[], const struct lif_execute_opts *opts, struct lif
|
|||
if (opts->interfaces_file)
|
||||
lif_environment_push(envp, "INTERFACES_FILE", opts->interfaces_file);
|
||||
|
||||
struct lif_node *iter;
|
||||
const struct lif_node *iter;
|
||||
bool did_address = false, did_gateway = false;
|
||||
|
||||
/* Allocate a buffer for all possible addresses, if any */
|
||||
char *addresses = calloc (BUFFER_LEN, 1);
|
||||
size_t addresses_size = BUFFER_LEN;
|
||||
char *addresses_end = addresses;
|
||||
|
||||
/* Allocate a buffer for all possible gateways, if any */
|
||||
char *gateways = calloc (BUFFER_LEN, 1);
|
||||
size_t gateways_size = BUFFER_LEN;
|
||||
char *gateways_end = gateways;
|
||||
|
||||
LIF_DICT_FOREACH(iter, &iface->vars)
|
||||
{
|
||||
struct lif_dict_entry *entry = iter->data;
|
||||
|
||||
if (!strcmp(entry->key, "address"))
|
||||
{
|
||||
if (did_address)
|
||||
continue;
|
||||
|
||||
struct lif_address *addr = entry->data;
|
||||
char addrbuf[4096];
|
||||
|
||||
if (!lif_address_unparse(addr, addrbuf, sizeof addrbuf, true))
|
||||
if (!lif_address_format_cidr(iface, entry, addrbuf, sizeof(addrbuf)))
|
||||
continue;
|
||||
|
||||
/* Append address to buffer */
|
||||
append_to_buffer(&addresses, &addresses_size, &addresses_end, addrbuf);
|
||||
|
||||
/* Only print IF_ADDRESS once */
|
||||
if (did_address)
|
||||
continue;
|
||||
|
||||
lif_environment_push(envp, "IF_ADDRESS", addrbuf);
|
||||
|
|
@ -149,6 +203,9 @@ build_environment(char **envp[], const struct lif_execute_opts *opts, struct lif
|
|||
}
|
||||
else if (!strcmp(entry->key, "gateway"))
|
||||
{
|
||||
/* Append address to buffer */
|
||||
append_to_buffer(&gateways, &gateways_size, &gateways_end, entry->data);
|
||||
|
||||
if (did_gateway)
|
||||
continue;
|
||||
|
||||
|
|
@ -158,9 +215,6 @@ build_environment(char **envp[], const struct lif_execute_opts *opts, struct lif
|
|||
{
|
||||
if (iface->is_bridge)
|
||||
lif_environment_push(envp, "IF_BRIDGE_PORTS", (const char *) entry->data);
|
||||
|
||||
if (iface->is_bond)
|
||||
lif_environment_push(envp, "IF_BOND_SLAVES", (const char *) entry->data);
|
||||
}
|
||||
|
||||
char envkey[4096] = "IF_";
|
||||
|
|
@ -177,6 +231,15 @@ build_environment(char **envp[], const struct lif_execute_opts *opts, struct lif
|
|||
|
||||
lif_environment_push(envp, envkey, (const char *) entry->data);
|
||||
}
|
||||
|
||||
if (addresses != NULL)
|
||||
lif_environment_push(envp, "IF_ADDRESSES", addresses);
|
||||
if (gateways != NULL)
|
||||
lif_environment_push(envp, "IF_GATEWAYS", gateways);
|
||||
|
||||
/* Clean up */
|
||||
free (addresses);
|
||||
free (gateways);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
@ -237,9 +300,23 @@ lif_lifecycle_run_phase(const struct lif_execute_opts *opts, struct lif_interfac
|
|||
if (!handle_commands_for_phase(opts, envp, iface, phase))
|
||||
goto handle_error;
|
||||
|
||||
/* we should do error handling here, but ifupdown1 doesn't */
|
||||
lif_execute_fmt(opts, envp, "/bin/run-parts /etc/network/if-%s.d", phase);
|
||||
/* if we don't need to support /etc/if-X.d we're done here */
|
||||
if (!lif_config.allow_addon_scripts)
|
||||
goto out_free;
|
||||
|
||||
/* Check if scripts dir for this phase is present and bail out if it isn't */
|
||||
struct stat dir_stat;
|
||||
char dir_path[4096];
|
||||
snprintf (dir_path, 4096, "/etc/network/if-%s.d", phase);
|
||||
|
||||
if (stat (dir_path, &dir_stat) != 0 || S_ISDIR (dir_stat.st_mode) == 0) {
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
/* we should do error handling here, but ifupdown1 doesn't */
|
||||
lif_execute_fmt(opts, envp, "/bin/run-parts %s", dir_path);
|
||||
|
||||
out_free:
|
||||
lif_environment_free(&envp);
|
||||
return true;
|
||||
|
||||
|
|
@ -248,6 +325,36 @@ handle_error:
|
|||
return false;
|
||||
}
|
||||
|
||||
/* this function returns true if we can skip processing the interface for now,
|
||||
* otherwise false.
|
||||
*/
|
||||
static bool
|
||||
handle_refcounting(struct lif_dict *state, struct lif_interface *iface, bool up)
|
||||
{
|
||||
size_t orig_refcount = iface->refcount;
|
||||
|
||||
if (up)
|
||||
lif_state_ref_if(state, iface->ifname, iface);
|
||||
else
|
||||
lif_state_unref_if(state, iface->ifname, iface);
|
||||
|
||||
#ifdef DEBUG_REFCOUNTING
|
||||
fprintf(stderr, "handle_refcounting(): orig_refcount=%zu, refcount=%zu, direction=%s\n",
|
||||
orig_refcount, iface->refcount, up ? "UP" : "DOWN");
|
||||
#endif
|
||||
|
||||
/* if going up and orig_refcount > 0 -- we're already configured. */
|
||||
if (up && orig_refcount > 0)
|
||||
return true;
|
||||
|
||||
/* if going down and iface->refcount > 1 -- we still have other dependents. */
|
||||
if (!up && iface->refcount > 1)
|
||||
return true;
|
||||
|
||||
/* we can change this interface -- no blocking dependents. */
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
handle_dependents(const struct lif_execute_opts *opts, struct lif_interface *parent, struct lif_dict *collection, struct lif_dict *state, bool up)
|
||||
{
|
||||
|
|
@ -257,6 +364,9 @@ handle_dependents(const struct lif_execute_opts *opts, struct lif_interface *par
|
|||
if (requires == NULL)
|
||||
return true;
|
||||
|
||||
/* set the parent's pending flag to break dependency cycles */
|
||||
parent->is_pending = true;
|
||||
|
||||
char require_ifs[4096] = {};
|
||||
strlcpy(require_ifs, requires->data, sizeof require_ifs);
|
||||
char *bufp = require_ifs;
|
||||
|
|
@ -265,12 +375,39 @@ handle_dependents(const struct lif_execute_opts *opts, struct lif_interface *par
|
|||
{
|
||||
struct lif_interface *iface = lif_interface_collection_find(collection, tokenp);
|
||||
|
||||
/* already up or down, skip */
|
||||
if (up == iface->is_up)
|
||||
if (iface->has_config_error)
|
||||
{
|
||||
if (opts->force)
|
||||
fprintf (stderr, "ifupdown: (de)configuring dependent interface %s (of %s) despite config errors\n",
|
||||
iface->ifname, parent->ifname);
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "ifupdown: skipping dependent interface %s (of %s) as it has config errors\n",
|
||||
iface->ifname, parent->ifname);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* if handle_refcounting returns true, it means we've already
|
||||
* configured the interface, or it is too soon to deconfigure
|
||||
* the interface.
|
||||
*/
|
||||
if (handle_refcounting(state, iface, up))
|
||||
{
|
||||
if (opts->verbose)
|
||||
fprintf(stderr, "ifupdown: skipping dependent interface %s (of %s)\n",
|
||||
fprintf(stderr, "ifupdown: skipping dependent interface %s (of %s) -- %s\n",
|
||||
iface->ifname, parent->ifname,
|
||||
up ? "already configured" : "transient dependencies still exist");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!up && iface->is_explicit)
|
||||
{
|
||||
if (opts->verbose)
|
||||
fprintf(stderr, "ifupdown: skipping dependent interface %s (of %s) -- interface is marked as explicitly configured\n",
|
||||
iface->ifname, parent->ifname);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -279,21 +416,29 @@ handle_dependents(const struct lif_execute_opts *opts, struct lif_interface *par
|
|||
iface->ifname, parent->ifname, up ? "up" : "down");
|
||||
|
||||
if (!lif_lifecycle_run(opts, iface, collection, state, iface->ifname, up))
|
||||
{
|
||||
parent->is_pending = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
parent->is_pending = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
lif_lifecycle_run(const struct lif_execute_opts *opts, struct lif_interface *iface, struct lif_dict *collection, struct lif_dict *state, const char *lifname, bool up)
|
||||
{
|
||||
/* if we're already pending, exit */
|
||||
if (iface->is_pending)
|
||||
return true;
|
||||
|
||||
if (iface->is_template)
|
||||
return false;
|
||||
|
||||
if (lifname == NULL)
|
||||
lifname = iface->ifname;
|
||||
|
||||
if (!lif_lifecycle_query_dependents(opts, iface, lifname))
|
||||
return false;
|
||||
|
||||
if (up)
|
||||
{
|
||||
/* when going up, dependents go up first. */
|
||||
|
|
@ -304,6 +449,9 @@ lif_lifecycle_run(const struct lif_execute_opts *opts, struct lif_interface *ifa
|
|||
* but, right now neither debian ifupdown or busybox ifupdown do any recovery,
|
||||
* so we wont right now.
|
||||
*/
|
||||
if (!lif_lifecycle_run_phase(opts, iface, "create", lifname, up))
|
||||
return false;
|
||||
|
||||
if (!lif_lifecycle_run_phase(opts, iface, "pre-up", lifname, up))
|
||||
return false;
|
||||
|
||||
|
|
@ -313,9 +461,7 @@ lif_lifecycle_run(const struct lif_execute_opts *opts, struct lif_interface *ifa
|
|||
if (!lif_lifecycle_run_phase(opts, iface, "post-up", lifname, up))
|
||||
return false;
|
||||
|
||||
lif_state_upsert(state, lifname, iface);
|
||||
|
||||
iface->is_up = true;
|
||||
lif_state_ref_if(state, lifname, iface);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -328,14 +474,126 @@ lif_lifecycle_run(const struct lif_execute_opts *opts, struct lif_interface *ifa
|
|||
if (!lif_lifecycle_run_phase(opts, iface, "post-down", lifname, up))
|
||||
return false;
|
||||
|
||||
if (!lif_lifecycle_run_phase(opts, iface, "destroy", lifname, up))
|
||||
return false;
|
||||
|
||||
/* when going up, dependents go down last. */
|
||||
if (!handle_dependents(opts, iface, collection, state, up))
|
||||
return false;
|
||||
|
||||
lif_state_delete(state, lifname);
|
||||
|
||||
iface->is_up = false;
|
||||
lif_state_unref_if(state, lifname, iface);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
count_interface_rdepends(const struct lif_execute_opts *opts, struct lif_dict *collection, struct lif_interface *parent, size_t depth)
|
||||
{
|
||||
/* if we have looped, return true immediately to break the loop. */
|
||||
if (parent->is_pending)
|
||||
return true;
|
||||
|
||||
/* query our dependents if we don't have them already */
|
||||
if (!lif_lifecycle_query_dependents(opts, parent, parent->ifname))
|
||||
return false;
|
||||
|
||||
/* set rdepends_count to depth, dependents will be depth + 1 */
|
||||
parent->is_pending = true;
|
||||
parent->rdepends_count = depth;
|
||||
|
||||
struct lif_dict_entry *requires = lif_dict_find(&parent->vars, "requires");
|
||||
|
||||
/* no dependents, nothing to worry about */
|
||||
if (requires == NULL)
|
||||
{
|
||||
parent->is_pending = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* walk any dependents */
|
||||
char require_ifs[4096] = {};
|
||||
strlcpy(require_ifs, requires->data, sizeof require_ifs);
|
||||
char *bufp = require_ifs;
|
||||
|
||||
for (char *tokenp = lif_next_token(&bufp); *tokenp; tokenp = lif_next_token(&bufp))
|
||||
{
|
||||
struct lif_interface *iface = lif_interface_collection_find(collection, tokenp);
|
||||
|
||||
if (!count_interface_rdepends(opts, collection, iface, depth + 1))
|
||||
{
|
||||
parent->is_pending = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
parent->is_pending = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
lif_lifecycle_count_rdepends(const struct lif_execute_opts *opts, struct lif_dict *collection)
|
||||
{
|
||||
struct lif_node *iter;
|
||||
|
||||
LIF_DICT_FOREACH(iter, collection)
|
||||
{
|
||||
struct lif_dict_entry *entry = iter->data;
|
||||
struct lif_interface *iface = entry->data;
|
||||
|
||||
/* start depth at interface's rdepends_count, which will be 0 for the root,
|
||||
* but will be more if additional rdepends are found...
|
||||
*/
|
||||
if (!count_interface_rdepends(opts, collection, iface, iface->rdepends_count))
|
||||
{
|
||||
fprintf(stderr, "ifupdown: dependency graph is broken for interface %s\n", iface->ifname);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* figure out the max depth */
|
||||
size_t maxdepth = 0;
|
||||
|
||||
LIF_DICT_FOREACH(iter, collection)
|
||||
{
|
||||
struct lif_dict_entry *entry = iter->data;
|
||||
struct lif_interface *iface = entry->data;
|
||||
|
||||
if (iface->rdepends_count > maxdepth)
|
||||
maxdepth = iface->rdepends_count;
|
||||
}
|
||||
|
||||
/* move the collection to a temporary list so we can reorder it */
|
||||
struct lif_list temp_list = {};
|
||||
struct lif_node *iter_next;
|
||||
|
||||
LIF_LIST_FOREACH_SAFE(iter, iter_next, collection->list.head)
|
||||
{
|
||||
void *data = iter->data;
|
||||
|
||||
lif_node_delete(iter, &collection->list);
|
||||
memset(iter, 0, sizeof *iter);
|
||||
|
||||
lif_node_insert(iter, data, &temp_list);
|
||||
}
|
||||
|
||||
/* walk backwards from maxdepth to 0, readding nodes */
|
||||
for (ssize_t curdepth = maxdepth; curdepth > -1; curdepth--)
|
||||
{
|
||||
LIF_LIST_FOREACH_SAFE(iter, iter_next, temp_list.head)
|
||||
{
|
||||
struct lif_dict_entry *entry = iter->data;
|
||||
struct lif_interface *iface = entry->data;
|
||||
|
||||
if ((ssize_t) iface->rdepends_count != curdepth)
|
||||
continue;
|
||||
|
||||
lif_node_delete(iter, &temp_list);
|
||||
memset(iter, 0, sizeof *iter);
|
||||
|
||||
lif_node_insert(iter, entry, &collection->list);
|
||||
}
|
||||
}
|
||||
|
||||
return maxdepth;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
extern bool lif_lifecycle_query_dependents(const struct lif_execute_opts *opts, struct lif_interface *iface, const char *lifname);
|
||||
extern bool lif_lifecycle_run_phase(const struct lif_execute_opts *opts, struct lif_interface *iface, const char *phase, const char *lifname, bool up);
|
||||
extern bool lif_lifecycle_run(const struct lif_execute_opts *opts, struct lif_interface *iface, struct lif_dict *collection, struct lif_dict *state, const char *lifname, bool up);
|
||||
extern ssize_t lif_lifecycle_count_rdepends(const struct lif_execute_opts *opts, struct lif_dict *collection);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ extern void lif_node_delete(struct lif_node *node, struct lif_list *list);
|
|||
for ((iter) = (head); (iter) != NULL; (iter) = (iter)->next)
|
||||
|
||||
#define LIF_LIST_FOREACH_SAFE(iter, iter_next, head) \
|
||||
for ((iter) = (head), (iter_next) = (iter)->next; (iter) != NULL; (iter) = (iter_next), (iter_next) = (iter) != NULL ? (iter)->next : NULL)
|
||||
for ((iter) = (head), (iter_next) = (iter) != NULL ? (iter)->next : NULL; (iter) != NULL; (iter) = (iter_next), (iter_next) = (iter) != NULL ? (iter)->next : NULL)
|
||||
|
||||
#define LIF_LIST_FOREACH_REVERSE(iter, tail) \
|
||||
for ((iter) = (tail); (iter) != NULL; (iter) = (iter)->prev)
|
||||
|
|
|
|||
|
|
@ -13,27 +13,46 @@
|
|||
* from the use of this software.
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include "libifupdown/state.h"
|
||||
#include "libifupdown/fgetline.h"
|
||||
#include "libifupdown/tokenize.h"
|
||||
|
||||
bool
|
||||
lif_state_read(struct lif_dict *state, FILE *fd)
|
||||
{
|
||||
char linebuf[4096];
|
||||
|
||||
while (lif_fgetline(linebuf, sizeof linebuf, fd))
|
||||
{
|
||||
char *ifname = linebuf;
|
||||
char *bufp = linebuf;
|
||||
char *ifname = lif_next_token(&bufp);
|
||||
char *refcount = lif_next_token(&bufp);
|
||||
char *explicit = lif_next_token(&bufp);
|
||||
size_t rc = 1;
|
||||
char *equals_p = strchr(linebuf, '=');
|
||||
bool is_explicit = false;
|
||||
|
||||
if (*explicit && !strcmp(explicit, "explicit"))
|
||||
is_explicit = true;
|
||||
|
||||
if (*refcount)
|
||||
{
|
||||
rc = strtoul(refcount, NULL, 10);
|
||||
|
||||
if (rc == 0 || rc == ULONG_MAX)
|
||||
rc = 1;
|
||||
}
|
||||
|
||||
if (equals_p == NULL)
|
||||
{
|
||||
lif_state_upsert(state, ifname, &(struct lif_interface){ .ifname = ifname });
|
||||
lif_state_upsert(state, ifname, &(struct lif_interface){ .ifname = ifname, .refcount = rc, .is_explicit = is_explicit });
|
||||
continue;
|
||||
}
|
||||
|
||||
*equals_p++ = '\0';
|
||||
lif_state_upsert(state, ifname, &(struct lif_interface){ .ifname = equals_p });
|
||||
lif_state_upsert(state, ifname, &(struct lif_interface){ .ifname = equals_p, .refcount = rc, .is_explicit = is_explicit });
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -55,10 +74,39 @@ lif_state_read_path(struct lif_dict *state, const char *path)
|
|||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
lif_state_ref_if(struct lif_dict *state, const char *ifname, struct lif_interface *iface)
|
||||
{
|
||||
iface->refcount++;
|
||||
lif_state_upsert(state, ifname, iface);
|
||||
}
|
||||
|
||||
void
|
||||
lif_state_unref_if(struct lif_dict *state, const char *ifname, struct lif_interface *iface)
|
||||
{
|
||||
if (iface->refcount == 0)
|
||||
return;
|
||||
|
||||
iface->refcount--;
|
||||
|
||||
if (iface->refcount)
|
||||
lif_state_upsert(state, ifname, iface);
|
||||
else
|
||||
lif_state_delete(state, ifname);
|
||||
}
|
||||
|
||||
void
|
||||
lif_state_upsert(struct lif_dict *state, const char *ifname, struct lif_interface *iface)
|
||||
{
|
||||
lif_dict_add(state, ifname, strdup(iface->ifname));
|
||||
lif_state_delete(state, ifname);
|
||||
|
||||
struct lif_state_record *rec = calloc(1, sizeof(*rec));
|
||||
|
||||
rec->mapped_if = strdup(iface->ifname);
|
||||
rec->refcount = iface->refcount;
|
||||
rec->is_explicit = iface->is_explicit;
|
||||
|
||||
lif_dict_add(state, ifname, rec);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -69,7 +117,10 @@ lif_state_delete(struct lif_dict *state, const char *ifname)
|
|||
if (entry == NULL)
|
||||
return;
|
||||
|
||||
free(entry->data);
|
||||
struct lif_state_record *rec = entry->data;
|
||||
free(rec->mapped_if);
|
||||
free(rec);
|
||||
|
||||
lif_dict_delete_entry(state, entry);
|
||||
}
|
||||
|
||||
|
|
@ -81,8 +132,10 @@ lif_state_write(const struct lif_dict *state, FILE *f)
|
|||
LIF_DICT_FOREACH(iter, state)
|
||||
{
|
||||
struct lif_dict_entry *entry = iter->data;
|
||||
struct lif_state_record *rec = entry->data;
|
||||
|
||||
fprintf(f, "%s=%s\n", entry->key, (const char *) entry->data);
|
||||
fprintf(f, "%s=%s %zu%s\n", entry->key, rec->mapped_if, rec->refcount,
|
||||
rec->is_explicit ? " explicit" : "");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -108,7 +161,8 @@ lif_state_lookup(struct lif_dict *state, struct lif_dict *if_collection, const c
|
|||
if (entry == NULL)
|
||||
return NULL;
|
||||
|
||||
struct lif_dict_entry *if_entry = lif_dict_find(if_collection, (const char *) entry->data);
|
||||
struct lif_state_record *rec = entry->data;
|
||||
struct lif_dict_entry *if_entry = lif_dict_find(if_collection, rec->mapped_if);
|
||||
|
||||
if (if_entry == NULL)
|
||||
return NULL;
|
||||
|
|
@ -124,9 +178,11 @@ lif_state_sync(struct lif_dict *state, struct lif_dict *if_collection)
|
|||
LIF_DICT_FOREACH(iter, state)
|
||||
{
|
||||
struct lif_dict_entry *entry = iter->data;
|
||||
struct lif_interface *iface = lif_interface_collection_find(if_collection, entry->key);
|
||||
struct lif_state_record *rec = entry->data;
|
||||
struct lif_interface *iface = lif_interface_collection_find(if_collection, rec->mapped_if);
|
||||
|
||||
iface->is_up = true;
|
||||
iface->refcount = rec->refcount;
|
||||
iface->is_explicit = rec->is_explicit;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -17,11 +17,21 @@
|
|||
#define LIBIFUPDOWN_STATE_H__GUARD
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include "libifupdown/interface.h"
|
||||
|
||||
struct lif_state_record {
|
||||
char *mapped_if;
|
||||
size_t refcount;
|
||||
|
||||
bool is_explicit;
|
||||
};
|
||||
|
||||
extern bool lif_state_read(struct lif_dict *state, FILE *f);
|
||||
extern bool lif_state_read_path(struct lif_dict *state, const char *path);
|
||||
extern void lif_state_upsert(struct lif_dict *state, const char *ifname, struct lif_interface *iface);
|
||||
extern void lif_state_ref_if(struct lif_dict *state, const char *ifname, struct lif_interface *iface);
|
||||
extern void lif_state_unref_if(struct lif_dict *state, const char *ifname, struct lif_interface *iface);
|
||||
extern void lif_state_delete(struct lif_dict *state, const char *ifname);
|
||||
extern void lif_state_write(const struct lif_dict *state, FILE *f);
|
||||
extern bool lif_state_write_path(const struct lif_dict *state, const char *path);
|
||||
|
|
|
|||
|
|
@ -18,6 +18,24 @@
|
|||
|
||||
#include <ctype.h>
|
||||
|
||||
static inline char *
|
||||
lif_next_token_eq(char **buf)
|
||||
{
|
||||
char *out = *buf;
|
||||
|
||||
while (*out && (isspace(*out) || *out == '='))
|
||||
out++;
|
||||
|
||||
char *end = out;
|
||||
while (*end && !isspace(*end) && *end != '=')
|
||||
end++;
|
||||
|
||||
*end++ = '\0';
|
||||
*buf = end;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static inline char *
|
||||
lif_next_token(char **buf)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -21,19 +21,20 @@
|
|||
void
|
||||
lif_common_version(void)
|
||||
{
|
||||
printf("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION);
|
||||
|
||||
printf("\nCopyright (c) 2020 Ariadne Conill <ariadne@dereferenced.org>\n\n");
|
||||
|
||||
printf("Permission to use, copy, modify, and/or distribute this software for any\n");
|
||||
printf("purpose with or without fee is hereby granted, provided that the above\n");
|
||||
printf("copyright notice and this permission notice appear in all copies.\n\n");
|
||||
|
||||
printf("This software is provided 'as is' and without any warranty, express or\n");
|
||||
printf("implied. In no event shall the authors be liable for any damages arising\n");
|
||||
printf("from the use of this software.\n\n");
|
||||
|
||||
printf("Report bugs at <%s>.\n", PACKAGE_BUGREPORT);
|
||||
printf(PACKAGE_NAME " " PACKAGE_VERSION "\n"
|
||||
"\n"
|
||||
"Copyright (c) 2020 Ariadne Conill <ariadne@dereferenced.org>\n"
|
||||
"Copyright (c) 2020 Maximilian Wilhelm <max@sdn.clinic>\n"
|
||||
"\n"
|
||||
"Permission to use, copy, modify, and/or distribute this software for any\n"
|
||||
"purpose with or without fee is hereby granted, provided that the above\n"
|
||||
"copyright notice and this permission notice appear in all copies.\n"
|
||||
"\n"
|
||||
"This software is provided 'as is' and without any warranty, express or\n"
|
||||
"implied. In no event shall the authors be liable for any damages arising\n"
|
||||
"from the use of this software.\n"
|
||||
"\n"
|
||||
"Report bugs at <" PACKAGE_BUGREPORT ">.\n");
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
|
|
|||
127
libifupdown/yaml-base.c
Normal file
127
libifupdown/yaml-base.c
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* libifupdown/yaml-base.c
|
||||
* Purpose: YAML implementation -- base
|
||||
*
|
||||
* Copyright (c) 2020 Ariadne Conill <ariadne@dereferenced.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* This software is provided 'as is' and without any warranty, express or
|
||||
* implied. In no event shall the authors be liable for any damages arising
|
||||
* from the use of this software.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "libifupdown/libifupdown.h"
|
||||
#include "libifupdown/yaml-base.h"
|
||||
|
||||
void
|
||||
lif_yaml_document_init(struct lif_yaml_node *doc, const char *name)
|
||||
{
|
||||
memset(doc, '\0', sizeof *doc);
|
||||
doc->value_type = LIF_YAML_OBJECT;
|
||||
|
||||
if (name != NULL)
|
||||
doc->name = strdup(name);
|
||||
}
|
||||
|
||||
struct lif_yaml_node *
|
||||
lif_yaml_document_new(const char *name)
|
||||
{
|
||||
struct lif_yaml_node *doc = calloc(1, sizeof *doc);
|
||||
|
||||
lif_yaml_document_init(doc, name);
|
||||
doc->malloced = true;
|
||||
|
||||
return doc;
|
||||
}
|
||||
|
||||
struct lif_yaml_node *
|
||||
lif_yaml_node_new_boolean(const char *name, bool value)
|
||||
{
|
||||
struct lif_yaml_node *node = calloc(1, sizeof *node);
|
||||
|
||||
node->malloced = true;
|
||||
node->value_type = LIF_YAML_BOOLEAN;
|
||||
|
||||
if (name != NULL)
|
||||
node->name = strdup(name);
|
||||
|
||||
node->value.bool_value = value;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
struct lif_yaml_node *
|
||||
lif_yaml_node_new_string(const char *name, const char *value)
|
||||
{
|
||||
struct lif_yaml_node *node = calloc(1, sizeof *node);
|
||||
|
||||
node->malloced = true;
|
||||
node->value_type = LIF_YAML_STRING;
|
||||
|
||||
if (name != NULL)
|
||||
node->name = strdup(name);
|
||||
|
||||
if (value != NULL)
|
||||
node->value.str_value = strdup(value);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
struct lif_yaml_node *
|
||||
lif_yaml_node_new_object(const char *name)
|
||||
{
|
||||
struct lif_yaml_node *node = calloc(1, sizeof *node);
|
||||
|
||||
node->malloced = true;
|
||||
node->value_type = LIF_YAML_OBJECT;
|
||||
|
||||
if (name != NULL)
|
||||
node->name = strdup(name);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
struct lif_yaml_node *
|
||||
lif_yaml_node_new_list(const char *name)
|
||||
{
|
||||
struct lif_yaml_node *node = calloc(1, sizeof *node);
|
||||
|
||||
node->malloced = true;
|
||||
node->value_type = LIF_YAML_LIST;
|
||||
|
||||
if (name != NULL)
|
||||
node->name = strdup(name);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
void
|
||||
lif_yaml_node_free(struct lif_yaml_node *node)
|
||||
{
|
||||
struct lif_node *iter, *next;
|
||||
|
||||
LIF_LIST_FOREACH_SAFE(iter, next, node->children.head)
|
||||
{
|
||||
struct lif_yaml_node *iter_node = iter->data;
|
||||
|
||||
lif_yaml_node_free(iter_node);
|
||||
}
|
||||
|
||||
free(node->name);
|
||||
|
||||
if (node->value_type == LIF_YAML_STRING)
|
||||
free(node->value.str_value);
|
||||
|
||||
if (node->malloced)
|
||||
free(node);
|
||||
}
|
||||
|
||||
void
|
||||
lif_yaml_node_append_child(struct lif_yaml_node *parent, struct lif_yaml_node *child)
|
||||
{
|
||||
lif_node_insert_tail(&child->node, child, &parent->children);
|
||||
}
|
||||
52
libifupdown/yaml-base.h
Normal file
52
libifupdown/yaml-base.h
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* libifupdown/yaml-base.h
|
||||
* Purpose: YAML implementation -- base
|
||||
*
|
||||
* Copyright (c) 2020 Ariadne Conill <ariadne@dereferenced.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* This software is provided 'as is' and without any warranty, express or
|
||||
* implied. In no event shall the authors be liable for any damages arising
|
||||
* from the use of this software.
|
||||
*/
|
||||
|
||||
#ifndef LIBIFUPDOWN_YAML_BASE_H__GUARD
|
||||
#define LIBIFUPDOWN_YAML_BASE_H__GUARD
|
||||
|
||||
#include "libifupdown/libifupdown.h"
|
||||
|
||||
/* this is a subset of types supported by our implementation */
|
||||
enum lif_yaml_value {
|
||||
LIF_YAML_STRING,
|
||||
LIF_YAML_LIST,
|
||||
LIF_YAML_OBJECT,
|
||||
LIF_YAML_BOOLEAN
|
||||
};
|
||||
|
||||
struct lif_yaml_node {
|
||||
struct lif_node node;
|
||||
|
||||
bool malloced;
|
||||
char *name;
|
||||
enum lif_yaml_value value_type;
|
||||
union {
|
||||
char *str_value; /* for string nodes */
|
||||
bool bool_value; /* for boolean nodes */
|
||||
} value;
|
||||
struct lif_list children; /* for list and object nodes */
|
||||
};
|
||||
|
||||
extern void lif_yaml_document_init(struct lif_yaml_node *doc, const char *name);
|
||||
extern struct lif_yaml_node *lif_yaml_document_new(const char *name);
|
||||
|
||||
extern struct lif_yaml_node *lif_yaml_node_new_boolean(const char *name, bool value);
|
||||
extern struct lif_yaml_node *lif_yaml_node_new_string(const char *name, const char *value);
|
||||
extern struct lif_yaml_node *lif_yaml_node_new_object(const char *name);
|
||||
extern struct lif_yaml_node *lif_yaml_node_new_list(const char *name);
|
||||
extern void lif_yaml_node_free(struct lif_yaml_node *node);
|
||||
extern void lif_yaml_node_append_child(struct lif_yaml_node *parent, struct lif_yaml_node *child);
|
||||
|
||||
#endif
|
||||
66
libifupdown/yaml-writer.c
Normal file
66
libifupdown/yaml-writer.c
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* libifupdown/yaml-writer.c
|
||||
* Purpose: YAML implementation -- writer
|
||||
*
|
||||
* Copyright (c) 2020 Ariadne Conill <ariadne@dereferenced.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* This software is provided 'as is' and without any warranty, express or
|
||||
* implied. In no event shall the authors be liable for any damages arising
|
||||
* from the use of this software.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "libifupdown/libifupdown.h"
|
||||
#include "libifupdown/yaml-base.h"
|
||||
#include "libifupdown/yaml-writer.h"
|
||||
|
||||
static const size_t INDENT_WIDTH = 2;
|
||||
|
||||
static void
|
||||
lif_yaml_write_node(const struct lif_yaml_node *node, FILE *f, size_t indent, bool type_annotations)
|
||||
{
|
||||
const struct lif_node *iter;
|
||||
|
||||
if (node->name != NULL)
|
||||
fprintf(f, "%*s%s: ", (int) indent, "", node->name);
|
||||
|
||||
size_t child_indent = indent + INDENT_WIDTH;
|
||||
|
||||
switch (node->value_type)
|
||||
{
|
||||
case LIF_YAML_BOOLEAN:
|
||||
fprintf(f, "%s%s\n", type_annotations ? "!!bool " : "", node->value.bool_value ? "true" : "false");
|
||||
break;
|
||||
case LIF_YAML_STRING:
|
||||
fprintf(f, "%s%s\n", type_annotations ? "!!str " : "", node->value.str_value);
|
||||
break;
|
||||
case LIF_YAML_OBJECT:
|
||||
fprintf(f, "\n");
|
||||
break;
|
||||
case LIF_YAML_LIST:
|
||||
fprintf(f, "\n");
|
||||
child_indent += INDENT_WIDTH;
|
||||
break;
|
||||
}
|
||||
|
||||
LIF_LIST_FOREACH(iter, node->children.head)
|
||||
{
|
||||
const struct lif_yaml_node *iter_node = iter->data;
|
||||
|
||||
if (node->value_type == LIF_YAML_LIST)
|
||||
fprintf(f, "%*s-\n", (int) (child_indent - INDENT_WIDTH), "");
|
||||
|
||||
lif_yaml_write_node(iter_node, f, child_indent, type_annotations);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
lif_yaml_write(const struct lif_yaml_node *doc, FILE *f, bool type_annotations)
|
||||
{
|
||||
lif_yaml_write_node(doc, f, 0, type_annotations);
|
||||
}
|
||||
24
libifupdown/yaml-writer.h
Normal file
24
libifupdown/yaml-writer.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* libifupdown/yaml-writer.h
|
||||
* Purpose: YAML implementation -- writer
|
||||
*
|
||||
* Copyright (c) 2020 Ariadne Conill <ariadne@dereferenced.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* This software is provided 'as is' and without any warranty, express or
|
||||
* implied. In no event shall the authors be liable for any damages arising
|
||||
* from the use of this software.
|
||||
*/
|
||||
|
||||
#ifndef LIBIFUPDOWN_YAML_WRITER_H__GUARD
|
||||
#define LIBIFUPDOWN_YAML_WRITER_H__GUARD
|
||||
|
||||
#include "libifupdown/libifupdown.h"
|
||||
#include "libifupdown/yaml-base.h"
|
||||
|
||||
extern void lif_yaml_write(const struct lif_yaml_node *doc, FILE *f, bool type_annotations);
|
||||
|
||||
#endif
|
||||
|
|
@ -2,6 +2,7 @@ syntax(2)
|
|||
|
||||
test_suite('ifupdown-ng')
|
||||
|
||||
atf_test_program{name='multicall_test'}
|
||||
atf_test_program{name='ifquery_test'}
|
||||
atf_test_program{name='ifup_test'}
|
||||
atf_test_program{name='ifdown_test'}
|
||||
|
|
|
|||
6
tests/fixtures/deferred-teardown-1.ifstate
vendored
Normal file
6
tests/fixtures/deferred-teardown-1.ifstate
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
lo=lo 1
|
||||
br0=br0 1
|
||||
bond0=bond0 2
|
||||
eth0=eth0 3
|
||||
eth1=eth1 2
|
||||
tun0=tun0 1
|
||||
9
tests/fixtures/deferred-teardown-1.interfaces
vendored
Normal file
9
tests/fixtures/deferred-teardown-1.interfaces
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
auto br0
|
||||
iface br0
|
||||
requires bond0
|
||||
|
||||
iface bond0
|
||||
requires eth0 eth1
|
||||
|
||||
iface tun0
|
||||
requires eth0
|
||||
5
tests/fixtures/deferred-teardown-2.ifstate
vendored
Normal file
5
tests/fixtures/deferred-teardown-2.ifstate
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
eth0=eth0 5
|
||||
tun0=tun0 1
|
||||
tun1=tun1 1
|
||||
tun2=tun2 1
|
||||
tun3=tun3 1
|
||||
11
tests/fixtures/deferred-teardown-2.interfaces
vendored
Normal file
11
tests/fixtures/deferred-teardown-2.interfaces
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
iface tun0
|
||||
requires eth0
|
||||
|
||||
iface tun1
|
||||
requires eth0
|
||||
|
||||
iface tun2
|
||||
requires eth0
|
||||
|
||||
iface tun3
|
||||
requires eth0
|
||||
3
tests/fixtures/dependency-loop.ifstate
vendored
Normal file
3
tests/fixtures/dependency-loop.ifstate
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
lo=lo
|
||||
a=a
|
||||
b=b
|
||||
9
tests/fixtures/dependency-loop.interfaces
vendored
Normal file
9
tests/fixtures/dependency-loop.interfaces
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
auto a
|
||||
iface a
|
||||
use link
|
||||
requires b
|
||||
|
||||
auto b
|
||||
iface b
|
||||
use link
|
||||
requires a
|
||||
10
tests/fixtures/dhcp-hostname-rewrite.interfaces
vendored
Normal file
10
tests/fixtures/dhcp-hostname-rewrite.interfaces
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
iface eth0
|
||||
use dhcp
|
||||
hostname foo
|
||||
|
||||
iface eth1
|
||||
use dhcp
|
||||
|
||||
iface eth2
|
||||
use dhcp
|
||||
dhcp-hostname bar
|
||||
14
tests/fixtures/stanza-merging.interfaces
vendored
Normal file
14
tests/fixtures/stanza-merging.interfaces
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
# cidr and without-cidr should be equivalent
|
||||
iface cidr
|
||||
address 203.0.113.1/32
|
||||
|
||||
iface cidr
|
||||
address 203.0.113.2/24
|
||||
|
||||
iface without-cidr
|
||||
address 203.0.113.1
|
||||
netmask 32
|
||||
|
||||
iface without-cidr
|
||||
address 203.0.113.2
|
||||
netmask 24
|
||||
7
tests/fixtures/static-eth0-ptp.interfaces
vendored
Normal file
7
tests/fixtures/static-eth0-ptp.interfaces
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
auto eth0
|
||||
iface eth0
|
||||
address 203.0.113.2/32
|
||||
pointopoint 192.0.2.1
|
||||
gateway 192.0.2.1
|
||||
address 2001:db8:1000:2::2/64
|
||||
gateway 2001:db8:1000:2::1
|
||||
3
tests/fixtures/teardown-dep-ordering.ifstate
vendored
Normal file
3
tests/fixtures/teardown-dep-ordering.ifstate
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
dummy=dummy 2
|
||||
bat=bat 2
|
||||
br=br 1
|
||||
13
tests/fixtures/teardown-dep-ordering.interfaces
vendored
Normal file
13
tests/fixtures/teardown-dep-ordering.interfaces
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
auto dummy
|
||||
iface dummy
|
||||
link-type dummy
|
||||
|
||||
auto bat
|
||||
iface bat
|
||||
link-type dummy
|
||||
requires dummy
|
||||
|
||||
auto br
|
||||
iface br
|
||||
link-type dummy
|
||||
requires bat
|
||||
9
tests/fixtures/wireguard.interfaces
vendored
Normal file
9
tests/fixtures/wireguard.interfaces
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
iface eth0
|
||||
address 203.0.113.2/24
|
||||
gateway 203.0.113.1
|
||||
|
||||
auto wg0
|
||||
iface wg0
|
||||
use wireguard
|
||||
address 1.2.3.4/24
|
||||
requires eth0
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue