Compare commits
158 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 |
84 changed files with 2702 additions and 338 deletions
5
.github/workflows/build.yml
vendored
5
.github/workflows/build.yml
vendored
|
@ -10,7 +10,7 @@ jobs:
|
||||||
- name: Update system and add dependencies
|
- name: Update system and add dependencies
|
||||||
run: |
|
run: |
|
||||||
apk upgrade -Ua
|
apk upgrade -Ua
|
||||||
apk add build-base git kyua atf
|
apk add build-base git kyua atf scdoc
|
||||||
|
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
@ -18,5 +18,8 @@ jobs:
|
||||||
- name: Build
|
- name: Build
|
||||||
run: make
|
run: make
|
||||||
|
|
||||||
|
- name: Build documentation
|
||||||
|
run: make docs
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: make check
|
run: make check
|
||||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -13,4 +13,5 @@ ifquery
|
||||||
ifup
|
ifup
|
||||||
ifdown
|
ifdown
|
||||||
ifctrstat
|
ifctrstat
|
||||||
|
ifparse
|
||||||
*.lock
|
*.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
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
purpose with or without fee is hereby granted, provided that the above
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
|
58
Makefile
58
Makefile
|
@ -4,7 +4,7 @@ LIBBSD_CFLAGS =
|
||||||
LIBBSD_LIBS =
|
LIBBSD_LIBS =
|
||||||
|
|
||||||
PACKAGE_NAME := ifupdown-ng
|
PACKAGE_NAME := ifupdown-ng
|
||||||
PACKAGE_VERSION := 0.10.0
|
PACKAGE_VERSION := 0.11.3
|
||||||
PACKAGE_BUGREPORT := https://github.com/ifupdown-ng/ifupdown-ng/issues/new
|
PACKAGE_BUGREPORT := https://github.com/ifupdown-ng/ifupdown-ng/issues/new
|
||||||
|
|
||||||
|
|
||||||
|
@ -14,7 +14,8 @@ CONFIG_FILE := /etc/network/ifupdown-ng.conf
|
||||||
EXECUTOR_PATH := /usr/libexec/ifupdown-ng
|
EXECUTOR_PATH := /usr/libexec/ifupdown-ng
|
||||||
|
|
||||||
CFLAGS ?= -ggdb3 -Os
|
CFLAGS ?= -ggdb3 -Os
|
||||||
CFLAGS += -Wall -Wextra
|
CFLAGS += -Wall -Wextra -Werror
|
||||||
|
CFLAGS += -Wmissing-declarations -Wmissing-prototypes -Wcast-align -Wpointer-arith -Wreturn-type
|
||||||
CFLAGS += ${LIBBSD_CFLAGS}
|
CFLAGS += ${LIBBSD_CFLAGS}
|
||||||
CPPFLAGS = -I.
|
CPPFLAGS = -I.
|
||||||
CPPFLAGS += -DINTERFACES_FILE=\"${INTERFACES_FILE}\"
|
CPPFLAGS += -DINTERFACES_FILE=\"${INTERFACES_FILE}\"
|
||||||
|
@ -38,8 +39,8 @@ LIBIFUPDOWN_SRC = \
|
||||||
libifupdown/execute.c \
|
libifupdown/execute.c \
|
||||||
libifupdown/lifecycle.c \
|
libifupdown/lifecycle.c \
|
||||||
libifupdown/config-parser.c \
|
libifupdown/config-parser.c \
|
||||||
libifupdown/config-file.c
|
libifupdown/config-file.c \
|
||||||
|
libifupdown/compat.c
|
||||||
LIBIFUPDOWN_OBJ = ${LIBIFUPDOWN_SRC:.c=.o}
|
LIBIFUPDOWN_OBJ = ${LIBIFUPDOWN_SRC:.c=.o}
|
||||||
LIBIFUPDOWN_LIB = libifupdown.a
|
LIBIFUPDOWN_LIB = libifupdown.a
|
||||||
|
|
||||||
|
@ -47,7 +48,8 @@ MULTICALL_SRC = \
|
||||||
cmd/multicall.c \
|
cmd/multicall.c \
|
||||||
cmd/multicall-options.c \
|
cmd/multicall-options.c \
|
||||||
cmd/multicall-exec-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_OBJ = ${MULTICALL_SRC:.c=.o}
|
||||||
MULTICALL = ifupdown
|
MULTICALL = ifupdown
|
||||||
|
|
||||||
|
@ -73,6 +75,22 @@ MULTICALL_${CONFIG_IFCTRSTAT}_OBJ += ${IFCTRSTAT_SRC:.c=.o}
|
||||||
CMDS_${CONFIG_IFCTRSTAT} += ifctrstat
|
CMDS_${CONFIG_IFCTRSTAT} += ifctrstat
|
||||||
CPPFLAGS_${CONFIG_IFCTRSTAT} += -DCONFIG_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}
|
MULTICALL_OBJ += ${MULTICALL_Y_OBJ}
|
||||||
CMDS += ${CMDS_Y}
|
CMDS += ${CMDS_Y}
|
||||||
CPPFLAGS += ${CPPFLAGS_Y}
|
CPPFLAGS += ${CPPFLAGS_Y}
|
||||||
|
@ -82,21 +100,28 @@ EXECUTOR_SCRIPTS_CORE ?= \
|
||||||
ipv6-ra \
|
ipv6-ra \
|
||||||
static \
|
static \
|
||||||
link \
|
link \
|
||||||
ppp
|
ppp \
|
||||||
|
forward
|
||||||
|
|
||||||
EXECUTOR_SCRIPTS_OPT ?= \
|
EXECUTOR_SCRIPTS_OPT ?= \
|
||||||
|
batman \
|
||||||
|
bond \
|
||||||
bridge \
|
bridge \
|
||||||
vrf \
|
|
||||||
tunnel \
|
|
||||||
gre \
|
|
||||||
wireguard \
|
|
||||||
ethtool \
|
ethtool \
|
||||||
batman
|
gre \
|
||||||
|
mpls \
|
||||||
|
tunnel \
|
||||||
|
vrf \
|
||||||
|
vxlan \
|
||||||
|
wifi \
|
||||||
|
wireguard
|
||||||
|
|
||||||
EXECUTOR_SCRIPTS ?= ${EXECUTOR_SCRIPTS_CORE} ${EXECUTOR_SCRIPTS_OPT}
|
EXECUTOR_SCRIPTS ?= ${EXECUTOR_SCRIPTS_CORE} ${EXECUTOR_SCRIPTS_OPT}
|
||||||
|
|
||||||
EXECUTOR_SCRIPTS_STUB ?=
|
EXECUTOR_SCRIPTS_STUB ?=
|
||||||
|
|
||||||
|
EXECUTOR_SCRIPTS_NATIVE ?=
|
||||||
|
|
||||||
TARGET_LIBS = ${LIBIFUPDOWN_LIB}
|
TARGET_LIBS = ${LIBIFUPDOWN_LIB}
|
||||||
LIBS += ${TARGET_LIBS} ${LIBBSD_LIBS}
|
LIBS += ${TARGET_LIBS} ${LIBBSD_LIBS}
|
||||||
|
|
||||||
|
@ -131,19 +156,27 @@ install: all
|
||||||
for i in ${EXECUTOR_SCRIPTS_STUB}; do \
|
for i in ${EXECUTOR_SCRIPTS_STUB}; do \
|
||||||
install -D -m755 executor-scripts/stub/$$i ${DESTDIR}${EXECUTOR_PATH}/$$i; \
|
install -D -m755 executor-scripts/stub/$$i ${DESTDIR}${EXECUTOR_PATH}/$$i; \
|
||||||
done
|
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
|
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:
|
.scd.1 .scd.2 .scd.3 .scd.4 .scd.5 .scd.6 .scd.7 .scd.8:
|
||||||
${SCDOC} < $< > $@
|
${SCDOC} < $< > $@
|
||||||
|
|
||||||
MANPAGES_5 = \
|
MANPAGES_5 = \
|
||||||
|
doc/ifstate.5 \
|
||||||
|
doc/ifupdown-ng.conf.5 \
|
||||||
doc/interfaces.5 \
|
doc/interfaces.5 \
|
||||||
doc/interfaces-bond.5 \
|
doc/interfaces-bond.5 \
|
||||||
doc/interfaces-batman.5 \
|
doc/interfaces-batman.5 \
|
||||||
doc/interfaces-bridge.5 \
|
doc/interfaces-bridge.5 \
|
||||||
|
doc/interfaces-forward.5 \
|
||||||
doc/interfaces-ppp.5 \
|
doc/interfaces-ppp.5 \
|
||||||
|
doc/interfaces-tunnel.5 \
|
||||||
doc/interfaces-vrf.5 \
|
doc/interfaces-vrf.5 \
|
||||||
doc/interfaces-vxlan.5 \
|
doc/interfaces-vxlan.5 \
|
||||||
|
doc/interfaces-wifi.5 \
|
||||||
doc/interfaces-wireguard.5
|
doc/interfaces-wireguard.5
|
||||||
|
|
||||||
MANPAGES_7 = \
|
MANPAGES_7 = \
|
||||||
|
@ -153,7 +186,8 @@ MANPAGES_8 = \
|
||||||
doc/ifquery.8 \
|
doc/ifquery.8 \
|
||||||
doc/ifup.8 \
|
doc/ifup.8 \
|
||||||
doc/ifdown.8 \
|
doc/ifdown.8 \
|
||||||
doc/ifctrstat.8
|
doc/ifctrstat.8 \
|
||||||
|
doc/ifparse.8
|
||||||
|
|
||||||
MANPAGES = ${MANPAGES_5} ${MANPAGES_7} ${MANPAGES_8}
|
MANPAGES = ${MANPAGES_5} ${MANPAGES_7} ${MANPAGES_8}
|
||||||
|
|
||||||
|
|
|
@ -39,11 +39,11 @@ On glibc systems, you must install `libbsd-dev` or equivalent and additionally d
|
||||||
make LIBBSD_CFLAGS="$(pkg-config --cflags libbsd-overlay)" LIBBSD_LIBS="$(pkg-config --cflags --libs libbsd-overlay)"
|
make LIBBSD_CFLAGS="$(pkg-config --cflags libbsd-overlay)" LIBBSD_LIBS="$(pkg-config --cflags --libs libbsd-overlay)"
|
||||||
make install
|
make install
|
||||||
|
|
||||||
To run the tests, do `make check`. Running the checks requires `kyua` (`apk add kyua`, not packaged for Debian).
|
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
|
To build the documentation, do `make docs` and `make install_docs`. Building
|
||||||
the documentation requires scdoc (`apk add scdoc` / `apt install scdoc`).
|
the documentation requires scdoc (`apk add scdoc` / `apt install scdoc`).
|
||||||
|
|
||||||
## Discussion
|
## 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 <limits.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "multicall.h"
|
#include "cmd/multicall.h"
|
||||||
|
#include "cmd/ifctrstat-linux.h"
|
||||||
|
|
||||||
struct counter_desc {
|
struct counter_desc {
|
||||||
const char *name;
|
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);
|
return strcasecmp((const char *)key, ((struct counter_desc *)candidate)->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *
|
const char *
|
||||||
read_counter(const char *interface, const char *counter)
|
read_counter(const char *interface, const char *counter)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
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 <string.h>
|
||||||
#include "libifupdown/libifupdown.h"
|
#include "libifupdown/libifupdown.h"
|
||||||
#include "cmd/multicall.h"
|
#include "cmd/multicall.h"
|
||||||
|
#include "cmd/ifctrstat-linux.h"
|
||||||
|
|
||||||
extern struct counter_desc { const char *name; const void *data; } avail_counters[];
|
extern struct counter_desc { const char *name; const void *data; } avail_counters[];
|
||||||
extern int avail_counters_count;
|
extern int avail_counters_count;
|
||||||
|
|
||||||
extern const char *read_counter(const char *interface, const char *counter);
|
|
||||||
|
|
||||||
static bool show_label = true;
|
static bool show_label = true;
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
@ -96,7 +95,7 @@ ifctrstat_set_nolabel(const char *opt_arg)
|
||||||
show_label = false;
|
show_label = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
static int
|
||||||
ifctrstat_main(int argc, char *argv[])
|
ifctrstat_main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
if (optind >= argc)
|
if (optind >= argc)
|
||||||
|
@ -152,7 +151,7 @@ static struct if_option_group local_option_group = {
|
||||||
|
|
||||||
struct if_applet ifctrstat_applet = {
|
struct if_applet ifctrstat_applet = {
|
||||||
.name = "ifctrstat",
|
.name = "ifctrstat",
|
||||||
.desc = "Display statistics about an interface",
|
.desc = "display statistics about an interface",
|
||||||
.main = ifctrstat_main,
|
.main = ifctrstat_main,
|
||||||
.usage = "ifctrstat [options] <interface> <counter>\n ifctrstat [options] --list",
|
.usage = "ifctrstat [options] <interface> <counter>\n ifctrstat [options] --list",
|
||||||
.manpage = "8 ifctrstat",
|
.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 },
|
||||||
|
};
|
|
@ -20,44 +20,9 @@
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include "libifupdown/libifupdown.h"
|
#include "libifupdown/libifupdown.h"
|
||||||
#include "cmd/multicall.h"
|
#include "cmd/multicall.h"
|
||||||
|
#include "cmd/pretty-print-iface.h"
|
||||||
|
|
||||||
void
|
static 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("%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");
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
print_interface_dot(struct lif_dict *collection, struct lif_interface *iface, struct lif_interface *parent)
|
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))
|
if (!lif_lifecycle_query_dependents(&exec_opts, iface, iface->ifname))
|
||||||
|
@ -92,7 +57,7 @@ print_interface_dot(struct lif_dict *collection, struct lif_interface *iface, st
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
print_interface_property(struct lif_interface *iface, const char *property)
|
print_interface_property(struct lif_interface *iface, const char *property)
|
||||||
{
|
{
|
||||||
struct lif_node *iter;
|
struct lif_node *iter;
|
||||||
|
@ -118,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)
|
list_interfaces(struct lif_dict *collection, struct match_options *opts)
|
||||||
{
|
{
|
||||||
struct lif_node *iter;
|
struct lif_node *iter;
|
||||||
|
|
||||||
if (opts->dot)
|
if (opts->dot)
|
||||||
{
|
{
|
||||||
printf("digraph interfaces {\n");
|
printf("digraph interfaces {\n"
|
||||||
printf("edge [color=blue fontname=Sans fontsize=10]\n");
|
"edge [color=blue fontname=Sans fontsize=10]\n"
|
||||||
printf("node [fontname=Sans fontsize=10]\n");
|
"node [fontname=Sans fontsize=10]\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
LIF_DICT_FOREACH(iter, collection)
|
LIF_DICT_FOREACH(iter, collection)
|
||||||
|
@ -147,7 +112,7 @@ list_interfaces(struct lif_dict *collection, struct match_options *opts)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (opts->pretty_print)
|
if (opts->pretty_print)
|
||||||
print_interface(iface);
|
prettyprint_interface_eni(iface);
|
||||||
else if (opts->dot)
|
else if (opts->dot)
|
||||||
print_interface_dot(collection, iface, NULL);
|
print_interface_dot(collection, iface, NULL);
|
||||||
else
|
else
|
||||||
|
@ -159,8 +124,9 @@ list_interfaces(struct lif_dict *collection, struct match_options *opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool listing = false, listing_stat = false, listing_running = false;
|
static bool listing = false, listing_stat = false, listing_running = false;
|
||||||
|
static bool allow_undefined = false;
|
||||||
|
|
||||||
void
|
static void
|
||||||
list_state(struct lif_dict *state, struct match_options *opts)
|
list_state(struct lif_dict *state, struct match_options *opts)
|
||||||
{
|
{
|
||||||
struct lif_node *iter;
|
struct lif_node *iter;
|
||||||
|
@ -182,7 +148,8 @@ list_state(struct lif_dict *state, struct match_options *opts)
|
||||||
if (listing_running)
|
if (listing_running)
|
||||||
printf("%s\n", entry->key);
|
printf("%s\n", entry->key);
|
||||||
else
|
else
|
||||||
printf("%s=%s %zu\n", entry->key, rec->mapped_if, rec->refcount);
|
printf("%s=%s %zu%s\n", entry->key, rec->mapped_if, rec->refcount,
|
||||||
|
rec->is_explicit ? " explicit" : "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,6 +194,13 @@ set_property(const char *opt_arg)
|
||||||
match_opts.property = 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[] = {
|
static struct if_option local_options[] = {
|
||||||
{'r', "running", NULL, "show configured (running) interfaces", false, set_show_running},
|
{'r', "running", NULL, "show configured (running) interfaces", false, set_show_running},
|
||||||
{'s', "state", NULL, "show configured state", false, set_show_state},
|
{'s', "state", NULL, "show configured state", false, set_show_state},
|
||||||
|
@ -234,6 +208,7 @@ static struct if_option local_options[] = {
|
||||||
{'D', "dot", NULL, "generate a dependency graph", false, set_output_dot},
|
{'D', "dot", NULL, "generate a dependency graph", false, set_output_dot},
|
||||||
{'L', "list", NULL, "list matching interfaces", false, set_listing},
|
{'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},
|
{'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 = {
|
static struct if_option_group local_option_group = {
|
||||||
|
@ -242,7 +217,7 @@ static struct if_option_group local_option_group = {
|
||||||
.group = local_options
|
.group = local_options
|
||||||
};
|
};
|
||||||
|
|
||||||
int
|
static int
|
||||||
ifquery_main(int argc, char *argv[])
|
ifquery_main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
struct lif_dict state = {};
|
struct lif_dict state = {};
|
||||||
|
@ -271,6 +246,12 @@ ifquery_main(int argc, char *argv[])
|
||||||
return EXIT_FAILURE;
|
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 */
|
/* --list --state is not allowed */
|
||||||
if (listing && (listing_stat || listing_running))
|
if (listing && (listing_stat || listing_running))
|
||||||
generic_usage(self_applet, EXIT_FAILURE);
|
generic_usage(self_applet, EXIT_FAILURE);
|
||||||
|
@ -300,6 +281,9 @@ ifquery_main(int argc, char *argv[])
|
||||||
|
|
||||||
if (entry != NULL)
|
if (entry != NULL)
|
||||||
iface = entry->data;
|
iface = entry->data;
|
||||||
|
|
||||||
|
if (entry == NULL && allow_undefined)
|
||||||
|
iface = lif_interface_collection_find(&collection, argv[idx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iface == NULL)
|
if (iface == NULL)
|
||||||
|
@ -311,7 +295,7 @@ ifquery_main(int argc, char *argv[])
|
||||||
if (match_opts.property != NULL)
|
if (match_opts.property != NULL)
|
||||||
print_interface_property(iface, match_opts.property);
|
print_interface_property(iface, match_opts.property);
|
||||||
else
|
else
|
||||||
print_interface(iface);
|
prettyprint_interface_eni(iface);
|
||||||
}
|
}
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
|
|
||||||
static bool up;
|
static bool up;
|
||||||
|
|
||||||
bool
|
static bool
|
||||||
is_ifdown()
|
is_ifdown()
|
||||||
{
|
{
|
||||||
if (strstr(argv0, "ifdown") != NULL)
|
if (strstr(argv0, "ifdown") != NULL)
|
||||||
|
@ -36,7 +36,7 @@ is_ifdown()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
static int
|
||||||
acquire_state_lock(const char *state_path, const char *lifname)
|
acquire_state_lock(const char *state_path, const char *lifname)
|
||||||
{
|
{
|
||||||
if (exec_opts.mock || exec_opts.no_lock)
|
if (exec_opts.mock || exec_opts.no_lock)
|
||||||
|
@ -46,7 +46,7 @@ acquire_state_lock(const char *state_path, const char *lifname)
|
||||||
|
|
||||||
snprintf(lockpath, sizeof lockpath, "%s.%s.lock", state_path, 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 (fd < 0)
|
||||||
{
|
{
|
||||||
if (exec_opts.verbose)
|
if (exec_opts.verbose)
|
||||||
|
@ -94,8 +94,8 @@ acquire_state_lock(const char *state_path, const char *lifname)
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
static bool
|
||||||
skip_interface(struct lif_interface *iface, const char *ifname)
|
skip_interface(struct lif_interface *iface, const char *ifname, struct lif_dict *state, bool update_state)
|
||||||
{
|
{
|
||||||
if (iface->is_template)
|
if (iface->is_template)
|
||||||
{
|
{
|
||||||
|
@ -123,24 +123,31 @@ skip_interface(struct lif_interface *iface, const char *ifname)
|
||||||
if (up && iface->refcount > 0)
|
if (up && iface->refcount > 0)
|
||||||
{
|
{
|
||||||
if (exec_opts.verbose)
|
if (exec_opts.verbose)
|
||||||
fprintf(stderr, "%s: skipping auto interface %s (already configured), use --force to force configuration\n",
|
fprintf(stderr, "%s: skipping %sinterface %s (already configured), use --force to force configuration\n",
|
||||||
argv0, ifname);
|
argv0, iface->is_auto ? "auto " : "", ifname);
|
||||||
|
|
||||||
|
if (update_state)
|
||||||
|
{
|
||||||
|
iface->is_explicit = true;
|
||||||
|
lif_state_upsert(state, ifname, iface);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!up && iface->refcount == 0)
|
if (!up && iface->refcount == 0)
|
||||||
{
|
{
|
||||||
if (exec_opts.verbose)
|
if (exec_opts.verbose)
|
||||||
fprintf(stderr, "%s: skipping auto interface %s (already deconfigured), use --force to force deconfiguration\n",
|
fprintf(stderr, "%s: skipping %sinterface %s (already deconfigured), use --force to force deconfiguration\n",
|
||||||
argv0, ifname);
|
argv0, iface->is_auto ? "auto " : "", ifname);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
static bool
|
||||||
change_interface(struct lif_interface *iface, struct lif_dict *collection, struct lif_dict *state, const char *ifname)
|
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);
|
int lockfd = acquire_state_lock(exec_opts.state_file, ifname);
|
||||||
|
|
||||||
|
@ -150,7 +157,7 @@ change_interface(struct lif_interface *iface, struct lif_dict *collection, struc
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (skip_interface(iface, ifname))
|
if (skip_interface(iface, ifname, state, update_state))
|
||||||
{
|
{
|
||||||
if (lockfd != -1)
|
if (lockfd != -1)
|
||||||
close(lockfd);
|
close(lockfd);
|
||||||
|
@ -178,10 +185,16 @@ change_interface(struct lif_interface *iface, struct lif_dict *collection, struc
|
||||||
if (lockfd != -1)
|
if (lockfd != -1)
|
||||||
close(lockfd);
|
close(lockfd);
|
||||||
|
|
||||||
|
if (up && update_state)
|
||||||
|
{
|
||||||
|
iface->is_explicit = true;
|
||||||
|
lif_state_upsert(state, ifname, iface);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
static bool
|
||||||
change_auto_interfaces(struct lif_dict *collection, struct lif_dict *state, struct match_options *opts)
|
change_auto_interfaces(struct lif_dict *collection, struct lif_dict *state, struct match_options *opts)
|
||||||
{
|
{
|
||||||
struct lif_node *iter;
|
struct lif_node *iter;
|
||||||
|
@ -202,14 +215,14 @@ change_auto_interfaces(struct lif_dict *collection, struct lif_dict *state, stru
|
||||||
fnmatch(opts->include_pattern, iface->ifname, 0))
|
fnmatch(opts->include_pattern, iface->ifname, 0))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!change_interface(iface, collection, state, iface->ifname))
|
if (!change_interface(iface, collection, state, iface->ifname, false))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
static int
|
||||||
update_state_file_and_exit(int rc, struct lif_dict *state)
|
update_state_file_and_exit(int rc, struct lif_dict *state)
|
||||||
{
|
{
|
||||||
if (exec_opts.mock)
|
if (exec_opts.mock)
|
||||||
|
@ -230,7 +243,7 @@ update_state_file_and_exit(int rc, struct lif_dict *state)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
static int
|
||||||
ifupdown_main(int argc, char *argv[])
|
ifupdown_main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
up = !is_ifdown();
|
up = !is_ifdown();
|
||||||
|
@ -261,6 +274,12 @@ ifupdown_main(int argc, char *argv[])
|
||||||
return EXIT_FAILURE;
|
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))
|
if (!lif_state_sync(&state, &collection))
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s: could not sync state\n", argv0);
|
fprintf(stderr, "%s: could not sync state\n", argv0);
|
||||||
|
@ -307,7 +326,7 @@ ifupdown_main(int argc, char *argv[])
|
||||||
iface = entry->data;
|
iface = entry->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!change_interface(iface, &collection, &state, ifname))
|
if (!change_interface(iface, &collection, &state, ifname, true))
|
||||||
return update_state_file_and_exit(EXIT_FAILURE, &state);
|
return update_state_file_and_exit(EXIT_FAILURE, &state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,10 +21,13 @@
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include "cmd/multicall.h"
|
#include "cmd/multicall.h"
|
||||||
|
|
||||||
|
#define DEFAULT_TIMEOUT 300
|
||||||
|
|
||||||
struct lif_execute_opts exec_opts = {
|
struct lif_execute_opts exec_opts = {
|
||||||
.interfaces_file = INTERFACES_FILE,
|
.interfaces_file = INTERFACES_FILE,
|
||||||
.executor_path = EXECUTOR_PATH,
|
.executor_path = EXECUTOR_PATH,
|
||||||
.state_file = STATE_FILE
|
.state_file = STATE_FILE,
|
||||||
|
.timeout = DEFAULT_TIMEOUT,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -74,6 +77,14 @@ set_force(const char *opt_arg)
|
||||||
exec_opts.force = true;
|
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[] = {
|
static struct if_option exec_options[] = {
|
||||||
{'f', "force", NULL, "force (de)configuration", false, set_force},
|
{'f', "force", NULL, "force (de)configuration", false, set_force},
|
||||||
{'i', "interfaces", "interfaces FILE", "use FILE for interface definitions", true, set_interfaces_file},
|
{'i', "interfaces", "interfaces FILE", "use FILE for interface definitions", true, set_interfaces_file},
|
||||||
|
@ -82,6 +93,7 @@ static struct if_option exec_options[] = {
|
||||||
{'v', "verbose", NULL, "show what commands are being run", false, set_verbose},
|
{'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},
|
{'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},
|
{'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 = {
|
struct if_option_group exec_option_group = {
|
||||||
|
|
|
@ -39,7 +39,7 @@ set_include_pattern(const char *opt_arg)
|
||||||
static void
|
static void
|
||||||
set_exclude_pattern(const char *opt_arg)
|
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[] = {
|
static struct if_option match_options[] = {
|
||||||
|
|
|
@ -36,6 +36,10 @@ extern struct if_applet ifdown_applet;
|
||||||
extern struct if_applet ifctrstat_applet;
|
extern struct if_applet ifctrstat_applet;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_IFPARSE
|
||||||
|
extern struct if_applet ifparse_applet;
|
||||||
|
#endif
|
||||||
|
|
||||||
struct if_applet ifupdown_applet;
|
struct if_applet ifupdown_applet;
|
||||||
const struct if_applet *self_applet = NULL;
|
const struct if_applet *self_applet = NULL;
|
||||||
|
|
||||||
|
@ -46,6 +50,9 @@ struct if_applet *applet_table[] = {
|
||||||
#ifdef CONFIG_IFUPDOWN
|
#ifdef CONFIG_IFUPDOWN
|
||||||
&ifdown_applet,
|
&ifdown_applet,
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef CONFIG_IFPARSE
|
||||||
|
&ifparse_applet,
|
||||||
|
#endif
|
||||||
#ifdef CONFIG_IFQUERY
|
#ifdef CONFIG_IFQUERY
|
||||||
&ifquery_applet,
|
&ifquery_applet,
|
||||||
#endif
|
#endif
|
||||||
|
@ -55,7 +62,7 @@ struct if_applet *applet_table[] = {
|
||||||
&ifupdown_applet,
|
&ifupdown_applet,
|
||||||
};
|
};
|
||||||
|
|
||||||
int
|
static int
|
||||||
applet_cmp(const void *a, const void *b)
|
applet_cmp(const void *a, const void *b)
|
||||||
{
|
{
|
||||||
const char *key = a;
|
const char *key = a;
|
||||||
|
@ -66,6 +73,8 @@ applet_cmp(const void *a, const void *b)
|
||||||
|
|
||||||
void multicall_usage(int status) __attribute__((noreturn));
|
void multicall_usage(int status) __attribute__((noreturn));
|
||||||
|
|
||||||
|
struct if_applet ifupdown_applet;
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
@ -85,12 +94,14 @@ main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
self_applet = *app;
|
self_applet = *app;
|
||||||
|
|
||||||
|
if (self_applet != &ifupdown_applet)
|
||||||
process_options(*app, argc, argv);
|
process_options(*app, argc, argv);
|
||||||
|
|
||||||
return (*app)->main(argc, argv);
|
return self_applet->main(argc, argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
static int
|
||||||
multicall_main(int argc, char *argv[])
|
multicall_main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
if (argc < 2)
|
if (argc < 2)
|
||||||
|
@ -99,24 +110,23 @@ multicall_main(int argc, char *argv[])
|
||||||
return main(argc - 1, argv + 1);
|
return main(argc - 1, argv + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct if_applet ifupdown_applet;
|
|
||||||
|
|
||||||
void
|
void
|
||||||
multicall_usage(int status)
|
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++)
|
for (size_t i = 0; i < ARRAY_SIZE(applet_table); i++)
|
||||||
{
|
{
|
||||||
if (i != 0)
|
if (applet_table[i] == &ifupdown_applet)
|
||||||
fprintf(stderr, ", ");
|
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);
|
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
|
23
dist/ifupdown-ng.conf.example
vendored
23
dist/ifupdown-ng.conf.example
vendored
|
@ -17,6 +17,29 @@ allow_addon_scripts = 1
|
||||||
# templates. Valid values are 0 and 1, the default is 1.
|
# templates. Valid values are 0 and 1, the default is 1.
|
||||||
allow_any_iface_as_template = 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:
|
# implicit_template_conversion:
|
||||||
# In some legacy configs, a template may be declared as an iface, and
|
# In some legacy configs, a template may be declared as an iface, and
|
||||||
# ifupdown-ng automatically converts those declarations to a proper
|
# ifupdown-ng automatically converts those declarations to a proper
|
||||||
|
|
|
@ -60,6 +60,26 @@ Currently the following settings are supported in
|
||||||
in order to require inheritance from specified templates.
|
in order to require inheritance from specified templates.
|
||||||
Valid values are `0` and `1`, the default is `1`.
|
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
|
* `implicit_template_conversion`: In some legacy configs, a template
|
||||||
may be declared as an iface, and ifupdown-ng automatically converts
|
may be declared as an iface, and ifupdown-ng automatically converts
|
||||||
those declarations to a proper template. If this setting is
|
those declarations to a proper template. If this setting is
|
||||||
|
@ -252,4 +272,4 @@ used for an interface, use the ifquery(8) command.
|
||||||
|
|
||||||
If you have further questions about how to use ifupdown-ng to
|
If you have further questions about how to use ifupdown-ng to
|
||||||
configure a specific scenario, drop by the
|
configure a specific scenario, drop by the
|
||||||
[ifupdown-ng IRC channel](irc://irc.as7007.net/#ifupdown-ng).
|
[ifupdown-ng IRC channel](irc://irc.oftc.net/#ifupdown-ng).
|
||||||
|
|
|
@ -45,6 +45,10 @@ configured in the configuration database.
|
||||||
*-S, --state-file* _FILE_
|
*-S, --state-file* _FILE_
|
||||||
Use _FILE_ as the state database.
|
Use _FILE_ as the state database.
|
||||||
|
|
||||||
|
*-T, --timeout* _TIMEOUT_
|
||||||
|
Wait up to _TIMEOUT_ seconds for executors to complete before
|
||||||
|
raising an error.
|
||||||
|
|
||||||
*-V, --version*
|
*-V, --version*
|
||||||
Print the ifupdown-ng version and exit.
|
Print the ifupdown-ng version and exit.
|
||||||
|
|
||||||
|
@ -54,8 +58,9 @@ configured in the configuration database.
|
||||||
|
|
||||||
# SEE ALSO
|
# SEE ALSO
|
||||||
|
|
||||||
*ifup*(8)++
|
*ifupdown-ng.conf*(5)
|
||||||
*ifquery*(8)++
|
*ifup*(8)
|
||||||
|
*ifquery*(8)
|
||||||
*interfaces*(5)
|
*interfaces*(5)
|
||||||
|
|
||||||
# AUTHORS
|
# 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>
|
|
@ -54,9 +54,18 @@ configuration file to the current format.
|
||||||
When listing interfaces, print their configuration in a format
|
When listing interfaces, print their configuration in a format
|
||||||
that is compatible with *interfaces*(5) files.
|
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_
|
*-S, --state-file* _FILE_
|
||||||
Use _FILE_ as the state database.
|
Use _FILE_ as the state database.
|
||||||
|
|
||||||
|
*-T, --timeout* _TIMEOUT_
|
||||||
|
Wait up to _TIMEOUT_ seconds for executors to complete before
|
||||||
|
raising an error.
|
||||||
|
|
||||||
*-V, --version*
|
*-V, --version*
|
||||||
Print the ifupdown-ng version and exit.
|
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_
|
*-S, --state-file* _FILE_
|
||||||
Use _FILE_ as the state database.
|
Use _FILE_ as the state database.
|
||||||
|
|
||||||
|
*-T, --timeout* _TIMEOUT_
|
||||||
|
Wait up to _TIMEOUT_ seconds for executors to complete before
|
||||||
|
raising an error.
|
||||||
|
|
||||||
*-V, --version*
|
*-V, --version*
|
||||||
Print the ifupdown-ng version and exit.
|
Print the ifupdown-ng version and exit.
|
||||||
|
|
||||||
|
@ -57,8 +61,9 @@ configured in the configuration database.
|
||||||
|
|
||||||
# SEE ALSO
|
# SEE ALSO
|
||||||
|
|
||||||
*ifdown*(8)++
|
*ifupdown-ng.conf*(5)
|
||||||
*ifquery*(8)++
|
*ifdown*(8)
|
||||||
|
*ifquery*(8)
|
||||||
*interfaces*(5)
|
*interfaces*(5)
|
||||||
|
|
||||||
# AUTHORS
|
# AUTHORS
|
||||||
|
|
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>
|
|
@ -27,6 +27,11 @@ See *ip-link*(8) for more details about the options listed below.
|
||||||
removed from the Forwarding DataBase (FDB) after not having
|
removed from the Forwarding DataBase (FDB) after not having
|
||||||
seen a frame with this source address.
|
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
|
# SPANNING TREE RELATED BRIDGE OPTIONS
|
||||||
|
|
||||||
*bridge-stp* _state_
|
*bridge-stp* _state_
|
||||||
|
@ -52,6 +57,51 @@ See *ip-link*(8) for more details about the options listed below.
|
||||||
after reception of its last STP hello message. Valid values
|
after reception of its last STP hello message. Valid values
|
||||||
are between 6 and 40.
|
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
|
# EXAMPLES
|
||||||
|
|
||||||
A simple layer 2 only bridge:
|
A simple layer 2 only bridge:
|
||||||
|
@ -77,10 +127,46 @@ iface br0
|
||||||
address 2001:db8::42/64
|
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
|
# SEE ALSO
|
||||||
|
|
||||||
*ip-link*(8)
|
|
||||||
*interfaces*(5)
|
*interfaces*(5)
|
||||||
|
*ifupdown-ng.conf*(5)
|
||||||
|
*ip-link*(8)
|
||||||
|
*bridge*(8)
|
||||||
|
|
||||||
# AUTHORS
|
# AUTHORS
|
||||||
|
|
||||||
|
|
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>
|
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>
|
|
@ -32,26 +32,33 @@ other options are optional.
|
||||||
|
|
||||||
*vxlan-physdev* _interface_
|
*vxlan-physdev* _interface_
|
||||||
Specifies the physical ("underlay") device to use for tunnel
|
Specifies the physical ("underlay") device to use for tunnel
|
||||||
endpoint communication.
|
endpoint communication. This is required for setups using
|
||||||
|
multicast.
|
||||||
|
|
||||||
*vxlan-local-ip* _address_
|
*vxlan-local-ip* _address_
|
||||||
Specifies the source IP address to use in outgoing packets.
|
Specifies the source IP address to use in outgoing packets.
|
||||||
For compatiblity with ifupdown2 _vxlan-local-tunnelip_ is an
|
For compatiblity with ifupdown2 _vxlan-local-tunnelip_ is an
|
||||||
alias for this parameter.
|
alias for this parameter.
|
||||||
|
|
||||||
*vxlan-remote-ip* _address_
|
*vxlan-peer-ips* _list of IP addresses_
|
||||||
Specifies the unicast destination IP address to use in outgoing
|
Specifies the unicast destination IP address(es) to use in outgoing
|
||||||
packets when the destination link layer address is not known in
|
packets when the destination link layer address is not known in
|
||||||
the VXLAN device forwarding database. This parameter cannot be
|
the VXLAN device forwarding database. This option can be used to
|
||||||
specified with the _vxlan-remote-group_ parameter.
|
form Point-to-Point as well as Point-to-Multipoint VXLAN tunnels/
|
||||||
For compatiblity with ifupdown2 _vxlan-remoteip_ is an alias for
|
overlays depending on how many peer IPs are given. If more than one
|
||||||
this parameter.
|
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-remote-group* _multicast group_
|
*vxlan-peer-group* _multicast group_
|
||||||
Specifies the multicast group IP address to join. This parameter
|
Specifies the multicast group address to join, requires _vxlan-phsydev_
|
||||||
cannot be specified with the _vxlan-remote-ip_ parameter.
|
to be set as well. This parameter cannot be specified in combination
|
||||||
For compatibility with ifupdown2 _vxlan-svcnodeip_ is an alias for
|
with the _vxlan-peer-ips_ parameter. For compatibility with ifupdown2
|
||||||
this parameter.
|
_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_
|
*vxlan-learning* _on/off_
|
||||||
Specifies if unknown source link layer addresses and IP addresses
|
Specifies if unknown source link layer addresses and IP addresses
|
||||||
|
@ -79,22 +86,46 @@ iface vx_v1001_padcty
|
||||||
mtu 1560
|
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
|
Note that the underlay must have an MTU of at least 1610 to
|
||||||
carry the encapsulated packets.
|
carry the encapsulated packets of the two VTEPs above.
|
||||||
|
|
||||||
|
|
||||||
A VTEP with one peer (point-to-point configuration):
|
A VTEP with one peer (unicast point-to-point configuration):
|
||||||
|
|
||||||
```
|
```
|
||||||
auto vx_ptp1
|
auto vx_ptp1
|
||||||
iface vx_ptp1
|
iface vx_ptp1
|
||||||
vxlan-id 2342
|
vxlan-id 2342
|
||||||
vxlan-local-ip 192.0.2.42
|
vxlan-local-ip 192.0.2.42
|
||||||
vxlan-remote-ip 198.51.100.23
|
vxlan-peer-ips 198.51.100.23
|
||||||
#
|
#
|
||||||
hwaddress f2:00:c1:01:10:01
|
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
|
# AUTHORS
|
||||||
|
|
||||||
Maximilian Wilhelm <max@sdn.clinic>
|
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>
|
|
@ -18,6 +18,15 @@ allow to set up Wireguard VPN tunnels.
|
||||||
used. In the latter case _use wireguard_ has to be explicitly
|
used. In the latter case _use wireguard_ has to be explicitly
|
||||||
set to the interface configuration.
|
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
|
# EXAMPLES
|
||||||
|
|
||||||
A Wireguard VPN tunnel with explicit configuration file specified
|
A Wireguard VPN tunnel with explicit configuration file specified
|
||||||
|
|
|
@ -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.
|
*ifup*(8) and *ifdown*(8) to introspect and change system state.
|
||||||
|
|
||||||
In most cases, syntax from legacy implementations is supported as
|
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
|
# 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
|
are not associated with an *object* are considered to be part
|
||||||
of the root of the configuration tree.
|
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:
|
The following is a simple example of a stanza:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -64,11 +66,11 @@ the system will only respond to certain keywords by default:
|
||||||
|
|
||||||
*address* _address_
|
*address* _address_
|
||||||
Associates an IPv4 or IPv6 address in CIDR notation with
|
Associates an IPv4 or IPv6 address in CIDR notation with
|
||||||
the parent interface.
|
the parent interface. If an IP address without a prefix
|
||||||
|
length is given a given _netmask_ attribute is used if present.
|
||||||
*gateway* _address_
|
If neither a prefix length nor a _netmask_ are given a /24 or /64
|
||||||
Associates an IPv4 or IPv6 address with the parent interface
|
prefix length is presumed for IPv4 / IPv6 as of compatibility
|
||||||
for use as a default route (gateway).
|
reasons to classic ifupdown.
|
||||||
|
|
||||||
*netmask* _netmask_
|
*netmask* _netmask_
|
||||||
Associates a fallback netmask with the parent interface for
|
Associates a fallback netmask with the parent interface for
|
||||||
|
@ -83,6 +85,11 @@ the system will only respond to certain keywords by default:
|
||||||
For compatiblity with ifupdown and ifupdown2, _pointopoint_ is
|
For compatiblity with ifupdown and ifupdown2, _pointopoint_ is
|
||||||
an alias for this parameter.
|
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_
|
*link-type* _link-type_
|
||||||
Denotes the link-type of the interface. When set to _dummy_,
|
Denotes the link-type of the interface. When set to _dummy_,
|
||||||
the interface is created as a virtual dummy interfaces.
|
the interface is created as a virtual dummy interfaces.
|
||||||
|
@ -108,9 +115,9 @@ the system will only respond to certain keywords by default:
|
||||||
configuration data from _object_. Normally _object_
|
configuration data from _object_. Normally _object_
|
||||||
must be a *template*.
|
must be a *template*.
|
||||||
|
|
||||||
*use* _option_
|
*use* _executor_
|
||||||
Designates that an option should be used. See _OPTIONS_
|
Designates that an executor should be used. See _EXECUTORS_
|
||||||
section for more information on options.
|
section for more information on executors.
|
||||||
|
|
||||||
*pre-down* _command_
|
*pre-down* _command_
|
||||||
Runs _command_ before taking the interface down.
|
Runs _command_ before taking the interface down.
|
||||||
|
@ -133,11 +140,11 @@ the system will only respond to certain keywords by default:
|
||||||
Additional packages such as *bonding*, *bridge*, *tunnel*, *vrf* and
|
Additional packages such as *bonding*, *bridge*, *tunnel*, *vrf* and
|
||||||
*vxlan* add additional keywords to this vocabulary.
|
*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
|
This system is extendable by additional packages, but the
|
||||||
most common options are:
|
most common executors are:
|
||||||
|
|
||||||
*batman*
|
*batman*
|
||||||
The interface is a B.A.T.M.A.N. adv. mesh interface.
|
The interface is a B.A.T.M.A.N. adv. mesh interface.
|
||||||
|
@ -158,6 +165,9 @@ most common options are:
|
||||||
Use a DHCP client to learn the IPv4 address of an
|
Use a DHCP client to learn the IPv4 address of an
|
||||||
interface.
|
interface.
|
||||||
|
|
||||||
|
*forward*
|
||||||
|
Configures forwarding settings on the interface.
|
||||||
|
|
||||||
*loopback*
|
*loopback*
|
||||||
Designates the interface as a loopback device.
|
Designates the interface as a loopback device.
|
||||||
|
|
||||||
|
@ -168,7 +178,8 @@ most common options are:
|
||||||
|
|
||||||
*tunnel*
|
*tunnel*
|
||||||
The interface is a tunnel. Configuration of tunnels
|
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*
|
*vrf*
|
||||||
The interface is a VRF. Configuration of VRFs requires
|
The interface is a VRF. Configuration of VRFs requires
|
||||||
|
@ -178,11 +189,22 @@ most common options are:
|
||||||
The interface is a Virtual Extensible LAN (VXLAN) tunnel
|
The interface is a Virtual Extensible LAN (VXLAN) tunnel
|
||||||
endpoint.
|
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*
|
*wireguard*
|
||||||
The interface is a Wireguard VPN tunnel endpoint.
|
The interface is a Wireguard VPN tunnel endpoint.
|
||||||
|
|
||||||
Check *interfaces-<option>(5)* for further informaton about a given
|
Check *interfaces-<executor>(5)* for further informaton about a given
|
||||||
option and available configuration parameters.
|
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
|
# EXAMPLES
|
||||||
|
|
||||||
|
@ -216,6 +238,8 @@ iface eth0
|
||||||
|
|
||||||
# SEE ALSO
|
# SEE ALSO
|
||||||
|
|
||||||
|
*ifstate*(5)
|
||||||
|
*ifupdown-ng.conf*(5)
|
||||||
*ifup*(8)
|
*ifup*(8)
|
||||||
*ifdown*(8)
|
*ifdown*(8)
|
||||||
*ifquery*(8)
|
*ifquery*(8)
|
||||||
|
@ -223,9 +247,13 @@ iface eth0
|
||||||
*interfaces-batman*(5)
|
*interfaces-batman*(5)
|
||||||
*interfaces-bond*(5)
|
*interfaces-bond*(5)
|
||||||
*interfaces-bridge*(5)
|
*interfaces-bridge*(5)
|
||||||
|
*interfaces-forward*(5)
|
||||||
|
*interfaces-mpls*(5)
|
||||||
*interfaces-ppp*(5)
|
*interfaces-ppp*(5)
|
||||||
|
*interfaces-tunnel*(5)
|
||||||
*interfaces-vrf*(5)
|
*interfaces-vrf*(5)
|
||||||
*interfaces-vxlan*(5)
|
*interfaces-vxlan*(5)
|
||||||
|
*interfaces-wifi*(5)
|
||||||
*interfaces-wireguard*(5)
|
*interfaces-wireguard*(5)
|
||||||
|
|
||||||
# AUTHORS
|
# AUTHORS
|
||||||
|
|
|
@ -8,8 +8,6 @@
|
||||||
#
|
#
|
||||||
# See interfaces-batman(5) for a list of supported options for hardifs as well as meshifs.
|
# See interfaces-batman(5) for a list of supported options for hardifs as well as meshifs.
|
||||||
#
|
#
|
||||||
set -e
|
|
||||||
|
|
||||||
if [ "$VERBOSE" ]; then
|
if [ "$VERBOSE" ]; then
|
||||||
set -x
|
set -x
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -5,14 +5,11 @@
|
||||||
# Sat, 03 Oct 2020 20:42:19 +0200
|
# Sat, 03 Oct 2020 20:42:19 +0200
|
||||||
# -- Maximilian Wilhelm <max@sdn.clinic>
|
# -- Maximilian Wilhelm <max@sdn.clinic>
|
||||||
#
|
#
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
[ -n "$VERBOSE" ] && set -x
|
[ -n "$VERBOSE" ] && set -x
|
||||||
|
|
||||||
get_bond_options() {
|
get_bond_options() {
|
||||||
# We only care for options of format IF_BOND_<OPTION_NAME>
|
# We only care for options of format IF_BOND_<OPTION_NAME>
|
||||||
env | grep '^IF_BOND_[A-Z0-9_]\+$' | while IFS="=" read opt value; do
|
env | grep '^IF_BOND_[A-Z0-9_]\+' | while IFS="=" read opt value; do
|
||||||
# Members are handled seperately
|
# Members are handled seperately
|
||||||
if [ "${opt}" = "IF_BOND_MEMBERS" ]; then
|
if [ "${opt}" = "IF_BOND_MEMBERS" ]; then
|
||||||
continue
|
continue
|
||||||
|
@ -44,9 +41,9 @@ case "$PHASE" in
|
||||||
# Add members to bundle
|
# Add members to bundle
|
||||||
for member_iface in ${IF_BOND_MEMBERS}; do
|
for member_iface in ${IF_BOND_MEMBERS}; do
|
||||||
# Work around the current execution order
|
# Work around the current execution order
|
||||||
ip link set "${member_iface}" down
|
${MOCK} ip link set "${member_iface}" down
|
||||||
ip link set master "${IFACE}" "${member_iface}"
|
${MOCK} ip link set master "${IFACE}" "${member_iface}"
|
||||||
ip link set "${member_iface}" up
|
${MOCK} ip link set "${member_iface}" up
|
||||||
done
|
done
|
||||||
;;
|
;;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
[ -n "$VERBOSE" ] && set -x
|
||||||
set -e
|
|
||||||
|
|
||||||
# Copyright (C) 2012, 2020 Natanael Copa <ncopa@alpinelinux.org>
|
# Copyright (C) 2012, 2020 Natanael Copa <ncopa@alpinelinux.org>
|
||||||
# Copyright (C) 2020 Ariadne Conill <ariadne@dereferenced.org>
|
# Copyright (C) 2020 Ariadne Conill <ariadne@dereferenced.org>
|
||||||
|
@ -14,6 +13,10 @@ set -e
|
||||||
# implied. In no event shall the authors be liable for any damages arising
|
# implied. In no event shall the authors be liable for any damages arising
|
||||||
# from the use of this software.
|
# from the use of this software.
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# Bridge management functions #
|
||||||
|
################################################################################
|
||||||
|
|
||||||
all_ports_exist() {
|
all_ports_exist() {
|
||||||
local i=
|
local i=
|
||||||
for i in "$@"; do
|
for i in "$@"; do
|
||||||
|
@ -52,13 +55,10 @@ all_ports() {
|
||||||
add_ports() {
|
add_ports() {
|
||||||
local port=
|
local port=
|
||||||
for port in $PORTS; do
|
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
|
if [ -n "$IF_BRIDGE_HW" ]; then
|
||||||
ip link set dev $port addr $IF_BRIDGE_HW
|
ip link set dev $port addr $IF_BRIDGE_HW
|
||||||
fi
|
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
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,22 +66,17 @@ del_ports() {
|
||||||
local port=
|
local port=
|
||||||
for port in $PORTS; do
|
for port in $PORTS; do
|
||||||
ip link set dev $port down
|
ip link set dev $port down
|
||||||
brctl delif $IFACE $port
|
ip link set dev $port nomaster
|
||||||
if [ -x /etc/network/ip-post-down.d/vlan ]; then
|
|
||||||
env IFACE=$port /etc/network/if-post-down.d/vlan
|
|
||||||
fi
|
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
set_bridge_opts() {
|
set_bridge_opts_brctl() {
|
||||||
[ -n "$IF_BRIDGE_AGEING" ] \
|
[ -n "$IF_BRIDGE_AGEING" ] \
|
||||||
&& brctl setageing $IFACE $IF_BRIDGE_AGEING
|
&& brctl setageing $IFACE $IF_BRIDGE_AGEING
|
||||||
[ -n "$IF_BRIDGE_BRIDGEPRIO" ] \
|
[ -n "$IF_BRIDGE_BRIDGEPRIO" ] \
|
||||||
&& brctl setbridgeprio $IFACE $IF_BRIDGE_BRIDGEPRIO
|
&& brctl setbridgeprio $IFACE $IF_BRIDGE_BRIDGEPRIO
|
||||||
[ -n "$IF_BRIDGE_FD" ] \
|
[ -n "$IF_BRIDGE_FD" ] \
|
||||||
&& brctl setfd $IFACE $IF_BRIDGE_FD
|
&& brctl setfd $IFACE $IF_BRIDGE_FD
|
||||||
[ -n "$IF_BRIDGE_GCINT" ] \
|
|
||||||
&& brctl setgcint $IFACE $IF_BRIDGE_GCINT
|
|
||||||
[ -n "$IF_BRIDGE_HELLO" ] \
|
[ -n "$IF_BRIDGE_HELLO" ] \
|
||||||
&& brctl sethello $IFACE $IF_BRIDGE_HELLO
|
&& brctl sethello $IFACE $IF_BRIDGE_HELLO
|
||||||
[ -n "$IF_BRIDGE_MAXAGE" ] \
|
[ -n "$IF_BRIDGE_MAXAGE" ] \
|
||||||
|
@ -94,6 +89,44 @@ set_bridge_opts() {
|
||||||
&& brctl stp $IFACE $IF_BRIDGE_STP
|
&& 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() {
|
all_ports_ready() {
|
||||||
local port=
|
local port=
|
||||||
for port in $PORTS; do
|
for port in $PORTS; do
|
||||||
|
@ -123,7 +156,92 @@ wait_bridge() {
|
||||||
done
|
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
|
case "$IF_BRIDGE_PORTS" in
|
||||||
"") ;;
|
"") ;;
|
||||||
|
@ -132,30 +250,53 @@ all) PORTS=$(all_ports);;
|
||||||
*) PORTS="$IF_BRIDGE_PORTS";;
|
*) PORTS="$IF_BRIDGE_PORTS";;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
[ -z "$PORTS" ] && ! env | grep -q "^IF_BRIDGE" && exit
|
|
||||||
|
|
||||||
case "$PHASE" in
|
case "$PHASE" in
|
||||||
depend)
|
depend)
|
||||||
|
# Called for the bridge interface
|
||||||
|
if [ "${IF_BRIDGE_PORTS}" ]; then
|
||||||
echo "$PORTS"
|
echo "$PORTS"
|
||||||
;;
|
|
||||||
create)
|
|
||||||
if [ ! -d "/sys/class/net/${IFACE}" ]; then
|
|
||||||
brctl addbr "${IFACE}"
|
|
||||||
fi
|
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)
|
pre-up)
|
||||||
|
# Called for the bridge interface
|
||||||
|
if [ "${IF_BRIDGE_PORTS}" ]; then
|
||||||
wait_ports
|
wait_ports
|
||||||
set_bridge_opts
|
set_bridge_opts
|
||||||
|
set_bridge_vlans
|
||||||
add_ports
|
add_ports
|
||||||
|
set_bridge_port_vlans
|
||||||
wait_bridge
|
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)
|
post-down)
|
||||||
|
# Called for the bridge interface
|
||||||
|
if [ "${IF_BRIDGE_PORTS}" ]; then
|
||||||
del_ports
|
del_ports
|
||||||
ip link set dev $IFACE down
|
ip link set dev $IFACE down
|
||||||
|
fi
|
||||||
;;
|
;;
|
||||||
|
|
||||||
destroy)
|
destroy)
|
||||||
if [ -d "/sys/class/net/${IFACE}" ]; then
|
# Called for the bridge interface
|
||||||
brctl delbr "${IFACE}"
|
if [ "${IF_BRIDGE_PORTS}" -a -d "/sys/class/net/${IFACE}" ]; then
|
||||||
|
ip link del "${IFACE}"
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# some users provide a shell fragment for the hostname property.
|
# some users provide a shell fragment for the hostname property.
|
||||||
[ -n "$IF_HOSTNAME" ] && IF_HOSTNAME=$(eval echo $IF_HOSTNAME)
|
[ -n "$IF_DHCP_HOSTNAME" ] && IF_DHCP_HOSTNAME=$(eval echo $IF_DHCP_HOSTNAME)
|
||||||
|
|
||||||
determine_implementation() {
|
determine_implementation() {
|
||||||
[ -n "$IF_DHCP_PROGRAM" ] && echo "$IF_DHCP_PROGRAM" && return
|
[ -n "$IF_DHCP_PROGRAM" ] && echo "$IF_DHCP_PROGRAM" && return
|
||||||
|
@ -17,20 +14,25 @@ determine_implementation() {
|
||||||
start() {
|
start() {
|
||||||
case "$1" in
|
case "$1" in
|
||||||
dhcpcd)
|
dhcpcd)
|
||||||
[ -n "$IF_HOSTNAME" ] && optargs="$optargs -h $IF_HOSTNAME"
|
[ -n "$IF_DHCP_HOSTNAME" ] && optargs="$optargs -h $IF_DHCP_HOSTNAME"
|
||||||
[ -n "$IF_VENDOR" ] && optargs="$optargs -i $IF_VENDOR"
|
[ -n "$IF_DHCP_VENDOR" ] && optargs="$optargs -i $IF_DHCP_VENDOR"
|
||||||
[ -n "$IF_CLIENT" ] && optargs="$optargs -i $IF_CLIENT"
|
[ -n "$IF_DHCP_CLIENT_ID" ] && optargs="$optargs -i $IF_DHCP_CLIENT_ID"
|
||||||
[ -n "$IF_LEASETIME" ] && optargs="$optargs -l $IF_LEASETIME"
|
[ -n "$IF_DHCP_LEASETIME" ] && optargs="$optargs -l $IF_DHCP_LEASETIME"
|
||||||
${MOCK} /sbin/dhcpcd $optargs $IFACE
|
${MOCK} /sbin/dhcpcd $optargs $IFACE
|
||||||
;;
|
;;
|
||||||
dhclient)
|
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)
|
||||||
optargs=$(eval echo $IF_UDHCPC_OPTS)
|
optargs=$(eval echo $IF_UDHCPC_OPTS)
|
||||||
[ -n "$IF_HOSTNAME" ] && optargs="$optargs -x hostname:$IF_HOSTNAME"
|
[ -n "$IF_DHCP_HOSTNAME" ] && optargs="$optargs -x hostname:$IF_DHCP_HOSTNAME"
|
||||||
[ -n "$IF_CLIENT" ] && optargs="$optargs -c $IF_CLIENT"
|
[ -n "$IF_DHCP_CLIENT_ID" ] && optargs="$optargs -c $IF_DHCP_CLIENT_ID"
|
||||||
[ -n "$IF_SCRIPT" ] && optargs="$optargs -s $IF_SCRIPT"
|
[ -n "$IF_DHCP_SCRIPT" ] && optargs="$optargs -s $IF_DHCP_SCRIPT"
|
||||||
${MOCK} /sbin/udhcpc -b -R -p /var/run/udhcpc.$IFACE.pid -i $IFACE $optargs
|
${MOCK} /sbin/udhcpc -b -R -p /var/run/udhcpc.$IFACE.pid -i $IFACE $optargs
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
set -e
|
|
||||||
|
|
||||||
# gather params for a given prefix, based on executor-scripts/linux/tunnel.
|
# gather params for a given prefix, based on executor-scripts/linux/tunnel.
|
||||||
gather_params() {
|
gather_params() {
|
||||||
env | sed -E "
|
env | sed -E "
|
||||||
|
|
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
|
#!/bin/sh
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# Executor for advanced GRE tunnel management.
|
# Executor for advanced GRE tunnel management.
|
||||||
|
|
||||||
[ -z "$IF_GRE_LOCAL" ] && exit 1
|
[ -z "$IF_GRE_LOCAL" ] && exit 1
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
start() {
|
start() {
|
||||||
${MOCK} /bin/sh -c "echo 1 > /proc/sys/net/ipv6/conf/$IFACE/accept_ra"
|
${MOCK} /bin/sh -c "echo 1 > /proc/sys/net/ipv6/conf/$IFACE/accept_ra"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
[ -n "$VERBOSE" ] && set -x
|
[ -n "$VERBOSE" ] && set -x
|
||||||
|
|
||||||
is_vlan() {
|
is_vlan() {
|
||||||
|
|
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,6 +1,4 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
set -e
|
|
||||||
|
|
||||||
[ -z "$IF_PPP_PROVIDER" ] && exit 0
|
[ -z "$IF_PPP_PROVIDER" ] && exit 0
|
||||||
|
|
||||||
case "$PHASE" in
|
case "$PHASE" in
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
[ -z "${VERBOSE}" ] || set -x
|
[ -z "${VERBOSE}" ] || set -x
|
||||||
|
|
||||||
[ -z "${IF_METRIC}" ] && IF_METRIC="1"
|
[ -z "${IF_METRIC}" ] && IF_METRIC="1"
|
||||||
|
@ -29,34 +26,31 @@ configure_addresses() {
|
||||||
PEER=""
|
PEER=""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z "${MOCK}" -a "${1}" = "del" ]; then
|
${MOCK} ip "${addrfam}" addr add "${addr}" ${PEER} dev "${IFACE}"
|
||||||
# When having multiple addresses set from the same prefix they might/will(?) be configured
|
|
||||||
# as 'secondary' and implicitly removed when removing the non-secondary address. This
|
|
||||||
# leads ip complaining about not being able to remove the secondaries as they are already
|
|
||||||
# gone. So we ignore errors while deconfiguring addresses as they liked occur when removing
|
|
||||||
# a vanish address anyway.
|
|
||||||
${MOCK} ip "${addrfam}" addr "${1}" "${addr}" ${PEER} dev "${IFACE}" 2>/dev/null
|
|
||||||
else
|
|
||||||
${MOCK} ip "${addrfam}" addr "${1}" "${addr}" ${PEER} dev "${IFACE}"
|
|
||||||
fi
|
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
configure_gateways() {
|
configure_gateways() {
|
||||||
for gw in ${IF_GATEWAYS}; do
|
for gw in ${IF_GATEWAYS}; do
|
||||||
addrfam=$(addr_family ${gw})
|
addrfam=$(addr_family ${gw})
|
||||||
${MOCK} ip "${addrfam}" route "${1}" default via "${gw}" ${VRF_TABLE} ${METRIC} dev "${IFACE}"
|
${MOCK} ip "${addrfam}" route add default via "${gw}" ${VRF_TABLE} ${METRIC} dev "${IFACE}"
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flush() {
|
||||||
|
cmd="addr"
|
||||||
|
arg="dev ${IFACE}"
|
||||||
|
|
||||||
|
${MOCK} ip ${cmd} flush ${arg}
|
||||||
|
}
|
||||||
|
|
||||||
case "$PHASE" in
|
case "$PHASE" in
|
||||||
up)
|
up)
|
||||||
configure_addresses add
|
configure_addresses add
|
||||||
configure_gateways add
|
configure_gateways add
|
||||||
;;
|
;;
|
||||||
down)
|
down)
|
||||||
configure_gateways del
|
flush
|
||||||
configure_addresses del
|
|
||||||
;;
|
;;
|
||||||
*) exit 0 ;;
|
*) exit 0 ;;
|
||||||
esac
|
esac
|
||||||
|
|
|
@ -1,27 +1,106 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# Based on alpine's tunnel configuration script.
|
# Based on alpine's tunnel configuration script.
|
||||||
# Copyright (c) 2017 Kaarle Ritvanen
|
# Copyright (c) 2017 Kaarle Ritvanen
|
||||||
# Copyright (c) 2020 Ariadne Conill (extended for ifupdown-ng)
|
# 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_REMOTE" ] && exit 1
|
||||||
[ -z "$IF_TUNNEL_MODE" ] && exit 1
|
[ -z "$IF_TUNNEL_MODE" ] && exit 1
|
||||||
|
|
||||||
COMMAND="tunnel"
|
[ -n "$VERBOSE" ] && set -x
|
||||||
FAMILY="-4"
|
|
||||||
|
yesno() {
|
||||||
|
case "$1" in
|
||||||
|
yes|1) echo 1 ;;
|
||||||
|
*) echo 0 ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# Figure out address familiy
|
||||||
|
FAMILY="4"
|
||||||
|
|
||||||
case "$IF_TUNNEL_MODE" in
|
case "$IF_TUNNEL_MODE" in
|
||||||
gretap)
|
|
||||||
COMMAND="link"
|
|
||||||
;;
|
|
||||||
vti6|ipip6|ip6*)
|
vti6|ipip6|ip6*)
|
||||||
FAMILY="-6"
|
FAMILY="6"
|
||||||
;;
|
;;
|
||||||
esac
|
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 '
|
PARAMS=$(set | sed -E '
|
||||||
s/^IF_TUNNEL_([A-Z0-9_]+)=(.+)/\1\n\2/
|
s/^IF_TUNNEL_([A-Z0-9_]+)=(.+)/\1\n\2/
|
||||||
ta
|
ta
|
||||||
|
@ -38,12 +117,12 @@ PARAMS=$(set | sed -E '
|
||||||
|
|
||||||
case "$PHASE" in
|
case "$PHASE" in
|
||||||
create)
|
create)
|
||||||
${MOCK} eval ip $FAMILY $COMMAND add $IFACE $PARAMS
|
${MOCK} eval ip -$FAMILY $OBJECT add $IFACE $TYPE_KW $TUNNEL_MODE $PARAMS $MORE_PARAMS
|
||||||
;;
|
;;
|
||||||
destroy)
|
destroy)
|
||||||
${MOCK} ip $FAMILY $COMMAND del $IFACE
|
${MOCK} ip -$FAMILY $OBJECT del $IFACE
|
||||||
;;
|
;;
|
||||||
depend)
|
depend)
|
||||||
echo "$IF_TUNNEL_DEV"
|
echo "${IF_TUNNEL_DEV}" "${IF_TUNNEL_LOCAL_DEV}"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
set -e
|
|
||||||
|
|
||||||
handle_init() {
|
handle_init() {
|
||||||
${MOCK} /sbin/ip link $1 $IFACE type vrf table $IF_VRF_TABLE
|
${MOCK} /sbin/ip link $1 $IFACE type vrf table $IF_VRF_TABLE
|
||||||
${MOCK} /sbin/ip rule $1 iif $IFACE table $IF_VRF_TABLE
|
${MOCK} /sbin/ip rule $1 iif $IFACE table $IF_VRF_TABLE
|
||||||
|
|
|
@ -10,15 +10,12 @@
|
||||||
# IF_VXLAN_ID The VXLAN Network Identifier (VNI)
|
# IF_VXLAN_ID The VXLAN Network Identifier (VNI)
|
||||||
# IF_VXLAN_PHYSDEV Specifies the physical device to use for tunnel endpoint communication
|
# 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_LOCAL_IP Specifies the source IP address to use in outgoing packets
|
||||||
# IF_VXLAN_REMOTE_IP IP of the remote VTEP endpoint (for ptp mode)
|
# IF_VXLAN_PEER_IPS Space separated list of IPs of the remote VTEP endpoint (for ptp/ptmp mode with ingress replication)
|
||||||
# IF_VXLAN_REMOTE_GROUP Multicast group to use for this VNI (for ptmp mode)
|
# 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_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_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)
|
# IF_VXLAN_DSTPORT UDP destination port to communicate to the remote VXLAN tunnel endpoint (default 4789)
|
||||||
#
|
#
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
[ -n "$VERBOSE" ] && set -x
|
[ -n "$VERBOSE" ] && set -x
|
||||||
|
|
||||||
# No VNI, nuthin' to do for us
|
# No VNI, nuthin' to do for us
|
||||||
|
@ -39,17 +36,27 @@ case "$PHASE" in
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Input validation
|
# Input validation
|
||||||
if [ "${IF_VXLAN_REMOTE_IP}" -a "${IF_VXLAN_REMOTE_GROUP}" ]; then
|
if [ "${IF_VXLAN_PEER_IPS}" -a "${IF_VXLAN_PEER_GROUP}" ]; then
|
||||||
echo "Error on ${IFACE} (vxlan): Only one of 'remote' and 'group' can be given!" >&2
|
echo "Error on ${IFACE} (vxlan): Only one of 'vxlan-peer-ips' and 'vxlan-peer-group' can be used!" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
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
|
# Gather arguments
|
||||||
ARGS=""
|
ARGS=""
|
||||||
[ "${IF_VXLAN_PHYSDEV}" ] && ARGS="${ARGS} dev ${IF_VXLAN_PHYSDEV}"
|
[ "${IF_VXLAN_PHYSDEV}" ] && ARGS="${ARGS} dev ${IF_VXLAN_PHYSDEV}"
|
||||||
[ "${IF_VXLAN_LOCAL_IP}" ] && ARGS="${ARGS} local ${IF_VXLAN_LOCAL_IP}"
|
[ "${IF_VXLAN_LOCAL_IP}" ] && ARGS="${ARGS} local ${IF_VXLAN_LOCAL_IP}"
|
||||||
[ "${IF_VXLAN_REMOTE_IP}" ] && ARGS="${ARGS} remote ${IF_VXLAN_REMOTE_IP}"
|
[ "${UCAST_MODE}" = "ptp" ] && ARGS="${ARGS} remote ${IF_VXLAN_PEER_IPS}"
|
||||||
[ "${IF_VXLAN_REMOTE_GROUP}" ] && ARGS="${ARGS} group ${IF_VXLAN_REMOTE_GROUP}"
|
[ "${IF_VXLAN_PEER_GROUP}" ] && ARGS="${ARGS} group ${IF_VXLAN_PEER_GROUP}"
|
||||||
[ "${IF_VXLAN_AGEING}" ] && ARGS="${ARGS} ageing ${IF_VXLAN_AGEING}"
|
[ "${IF_VXLAN_AGEING}" ] && ARGS="${ARGS} ageing ${IF_VXLAN_AGEING}"
|
||||||
|
|
||||||
# Linux uses non-standard default port - WTF?
|
# Linux uses non-standard default port - WTF?
|
||||||
|
@ -70,6 +77,13 @@ case "$PHASE" in
|
||||||
esac
|
esac
|
||||||
|
|
||||||
${MOCK} ip link add "${IFACE}" type vxlan id "${IF_VXLAN_ID}" ${ARGS}
|
${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)
|
destroy)
|
||||||
|
|
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
|
|
@ -1,7 +1,4 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
[ -n "$VERBOSE" ] && set -x
|
[ -n "$VERBOSE" ] && set -x
|
||||||
[ -z "$IF_WIREGUARD_CONFIG_PATH" ] && IF_WIREGUARD_CONFIG_PATH="/etc/wireguard/$IFACE.conf"
|
[ -z "$IF_WIREGUARD_CONFIG_PATH" ] && IF_WIREGUARD_CONFIG_PATH="/etc/wireguard/$IFACE.conf"
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
set -e
|
|
||||||
[ -z "$IF_BOND_MEMBERS" ] && IF_BOND_MEMBERS="$IF_BOND_SLAVES"
|
[ -z "$IF_BOND_MEMBERS" ] && IF_BOND_MEMBERS="$IF_BOND_SLAVES"
|
||||||
case "$PHASE" in
|
case "$PHASE" in
|
||||||
depend) echo "$IF_BOND_MEMBERS" ;;
|
depend) echo "$IF_BOND_MEMBERS" ;;
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
set -e
|
|
||||||
case "$PHASE" in
|
case "$PHASE" in
|
||||||
depend)
|
depend)
|
||||||
if [ "$IF_BRIDGE_PORTS" != "none" ]; then
|
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
|
|
@ -21,6 +21,9 @@
|
||||||
struct lif_config_file lif_config = {
|
struct lif_config_file lif_config = {
|
||||||
.allow_addon_scripts = true,
|
.allow_addon_scripts = true,
|
||||||
.allow_any_iface_as_template = 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,
|
.implicit_template_conversion = true,
|
||||||
.use_hostname_for_dhcp = true,
|
.use_hostname_for_dhcp = true,
|
||||||
};
|
};
|
||||||
|
@ -47,6 +50,9 @@ set_bool_value(const char *key, const char *value, void *opaque)
|
||||||
static struct lif_config_handler handlers[] = {
|
static struct lif_config_handler handlers[] = {
|
||||||
{"allow_addon_scripts", set_bool_value, &lif_config.allow_addon_scripts},
|
{"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},
|
{"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},
|
{"implicit_template_conversion", set_bool_value, &lif_config.implicit_template_conversion},
|
||||||
{"use_hostname_for_dhcp", set_bool_value, &lif_config.use_hostname_for_dhcp},
|
{"use_hostname_for_dhcp", set_bool_value, &lif_config.use_hostname_for_dhcp},
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,6 +21,9 @@
|
||||||
struct lif_config_file {
|
struct lif_config_file {
|
||||||
bool allow_addon_scripts;
|
bool allow_addon_scripts;
|
||||||
bool allow_any_iface_as_template;
|
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 implicit_template_conversion;
|
||||||
bool use_hostname_for_dhcp;
|
bool use_hostname_for_dhcp;
|
||||||
};
|
};
|
||||||
|
|
|
@ -30,6 +30,86 @@
|
||||||
|
|
||||||
#define SHELL "/bin/sh"
|
#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
|
bool
|
||||||
lif_execute_fmt(const struct lif_execute_opts *opts, char *const envp[], const char *fmt, ...)
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int status;
|
return lif_process_monitor(cmdbuf, child, opts->timeout);
|
||||||
waitpid(child, &status, 0);
|
|
||||||
|
|
||||||
return WIFEXITED(status) && WEXITSTATUS(status) == 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -118,11 +195,8 @@ lif_execute_fmt_with_result(const struct lif_execute_opts *opts, char *buf, size
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int status;
|
|
||||||
no_result:
|
no_result:
|
||||||
waitpid(child, &status, 0);
|
return lif_process_monitor(cmdbuf, child, opts->timeout);
|
||||||
|
|
||||||
return WIFEXITED(status) && WEXITSTATUS(status) == 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
|
@ -27,6 +27,7 @@ struct lif_execute_opts {
|
||||||
const char *executor_path;
|
const char *executor_path;
|
||||||
const char *interfaces_file;
|
const char *interfaces_file;
|
||||||
const char *state_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(const struct lif_execute_opts *opts, char *const envp[], const char *fmt, ...);
|
||||||
|
|
|
@ -32,6 +32,7 @@ struct remap_token {
|
||||||
static const struct remap_token tokens[] = {
|
static const struct remap_token tokens[] = {
|
||||||
{"bond-ad-sys-priority", "bond-ad-actor-sys-prio"}, /* ifupdown2 */
|
{"bond-ad-sys-priority", "bond-ad-actor-sys-prio"}, /* ifupdown2 */
|
||||||
{"bond-slaves", "bond-members"}, /* legacy ifupdown, ifupdown2 */
|
{"bond-slaves", "bond-members"}, /* legacy ifupdown, ifupdown2 */
|
||||||
|
{"client", "dhcp-client-id"}, /* legacy ifupdown */
|
||||||
{"driver-message-level", "ethtool-msglvl"}, /* Debian ethtool integration */
|
{"driver-message-level", "ethtool-msglvl"}, /* Debian ethtool integration */
|
||||||
{"endpoint", "tunnel-remote"}, /* legacy ifupdown */
|
{"endpoint", "tunnel-remote"}, /* legacy ifupdown */
|
||||||
{"ethernet-autoneg", "ethtool-ethernet-autoneg"}, /* Debian ethtool integration */
|
{"ethernet-autoneg", "ethtool-ethernet-autoneg"}, /* Debian ethtool integration */
|
||||||
|
@ -68,6 +69,9 @@ static const struct remap_token tokens[] = {
|
||||||
{"hardware-irq-coalesce-tx-usecs-high", "ethtool-coalesce-tx-usecs-high"}, /* 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-irq", "ethtool-coalesce-tx-usecs-irq"}, /* Debian ethtool integration */
|
||||||
{"hardware-irq-coalesce-tx-usecs-low", "ethtool-coalesce-tx-usecs-low"}, /* 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-autoneg", "ethtool-ethernet-autoneg"}, /* ifupdown2 */
|
||||||
{"link-duplex", "ethtool-link-duplex"}, /* Debian ethtool integration */
|
{"link-duplex", "ethtool-link-duplex"}, /* Debian ethtool integration */
|
||||||
{"link-fec", "ethtool-link-fec"}, /* ifupdown2 */
|
{"link-fec", "ethtool-link-fec"}, /* ifupdown2 */
|
||||||
|
@ -85,6 +89,7 @@ static const struct remap_token tokens[] = {
|
||||||
{"offload-ufo", "ethtool-offload-ufo"}, /* Debian ethtool integration */
|
{"offload-ufo", "ethtool-offload-ufo"}, /* Debian ethtool integration */
|
||||||
{"pointopoint", "point-to-point"}, /* legacy ifupdown, ifupdown2 */
|
{"pointopoint", "point-to-point"}, /* legacy ifupdown, ifupdown2 */
|
||||||
{"provider", "ppp-provider"}, /* legacy ifupdown, ifupdown2 */
|
{"provider", "ppp-provider"}, /* legacy ifupdown, ifupdown2 */
|
||||||
|
{"script", "dhcp-script"}, /* legacy ifupdown */
|
||||||
{"rx-offload", "ethtool-offload-rx"}, /* ifupdown2 */
|
{"rx-offload", "ethtool-offload-rx"}, /* ifupdown2 */
|
||||||
{"tso-offload", "ethtool-offload-tso"}, /* ifupdown2 */
|
{"tso-offload", "ethtool-offload-tso"}, /* ifupdown2 */
|
||||||
{"ttl", "tunnel-ttl"}, /* legacy ifupdown */
|
{"ttl", "tunnel-ttl"}, /* legacy ifupdown */
|
||||||
|
@ -92,10 +97,13 @@ static const struct remap_token tokens[] = {
|
||||||
{"tunnel-physdev", "tunnel-dev"}, /* ifupdown2 */
|
{"tunnel-physdev", "tunnel-dev"}, /* ifupdown2 */
|
||||||
{"tx-offload", "ethtool-offload-tx"}, /* ifupdown2 */
|
{"tx-offload", "ethtool-offload-tx"}, /* ifupdown2 */
|
||||||
{"ufo-offload", "ethtool-offload-ufo"}, /* ifupdown2 */
|
{"ufo-offload", "ethtool-offload-ufo"}, /* ifupdown2 */
|
||||||
|
{"vendor", "dhcp-vendor"}, /* legacy ifupdown */
|
||||||
{"vrf", "vrf-member"}, /* ifupdown2 */
|
{"vrf", "vrf-member"}, /* ifupdown2 */
|
||||||
{"vxlan-local-tunnelip", "vxlan-local-ip"}, /* ifupdown2 */
|
{"vxlan-local-tunnelip", "vxlan-local-ip"}, /* ifupdown2 */
|
||||||
{"vxlan-remoteip", "vxlan-remote-ip"}, /* ifupdown2 */
|
{"vxlan-remote-group", "vxlan-peer-group"}, /* ifupdown-ng */
|
||||||
{"vxlan-svcnodeip", "vxlan-remote-group"}, /* ifupdown2 */
|
{"vxlan-remoteip", "vxlan-peer-ips"}, /* ifupdown2 */
|
||||||
|
{"vxlan-remote-ip", "vxlan-peer-ips"}, /* ifupdown-ng */
|
||||||
|
{"vxlan-svcnodeip", "vxlan-peer-group"}, /* ifupdown2 */
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -172,6 +180,9 @@ handle_auto(struct lif_interface_file_parse_state *state, char *token, char *buf
|
||||||
if (!state->cur_iface->is_template)
|
if (!state->cur_iface->is_template)
|
||||||
state->cur_iface->is_auto = true;
|
state->cur_iface->is_auto = true;
|
||||||
|
|
||||||
|
if (state->cur_iface->is_auto)
|
||||||
|
state->cur_iface->is_explicit = true;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,12 +214,19 @@ handle_generic(struct lif_interface_file_parse_state *state, char *token, char *
|
||||||
|
|
||||||
token = maybe_remap_token(token);
|
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> */
|
/* Skip any leading whitespaces in value for <token> */
|
||||||
while (isspace (*bufp))
|
while (isspace (*bufp))
|
||||||
bufp++;
|
bufp++;
|
||||||
|
|
||||||
lif_dict_add(&state->cur_iface->vars, token, strdup(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 */
|
/* Check if token looks like <word1>-<word*> and assume <word1> is an addon */
|
||||||
char *word_end = strchr(token, '-');
|
char *word_end = strchr(token, '-');
|
||||||
if (word_end != NULL)
|
if (word_end != NULL)
|
||||||
|
@ -234,8 +252,8 @@ handle_hostname(struct lif_interface_file_parse_state *state, char *token, char
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
lif_dict_delete(&state->cur_iface->vars, token);
|
lif_dict_delete(&state->cur_iface->vars, "dhcp-hostname");
|
||||||
lif_dict_add(&state->cur_iface->vars, token, strdup(hostname));
|
lif_dict_add(&state->cur_iface->vars, "dhcp-hostname", strdup(hostname));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -253,6 +271,12 @@ handle_iface(struct lif_interface_file_parse_state *state, char *token, char *bu
|
||||||
return true;
|
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);
|
state->cur_iface = lif_interface_collection_find(state->collection, ifname);
|
||||||
if (state->cur_iface == NULL)
|
if (state->cur_iface == NULL)
|
||||||
{
|
{
|
||||||
|
@ -425,6 +449,7 @@ struct parser_keyword {
|
||||||
static const struct parser_keyword keywords[] = {
|
static const struct parser_keyword keywords[] = {
|
||||||
{"address", handle_address},
|
{"address", handle_address},
|
||||||
{"auto", handle_auto},
|
{"auto", handle_auto},
|
||||||
|
{"dhcp-hostname", handle_hostname},
|
||||||
{"gateway", handle_gateway},
|
{"gateway", handle_gateway},
|
||||||
{"hostname", handle_hostname},
|
{"hostname", handle_hostname},
|
||||||
{"iface", handle_iface},
|
{"iface", handle_iface},
|
||||||
|
@ -491,6 +516,11 @@ lif_interface_file_parse(struct lif_interface_file_parse_state *state, const cha
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
|
/* finalize any open interface */
|
||||||
|
if (state->cur_iface != NULL)
|
||||||
|
lif_interface_finalize(state->cur_iface);
|
||||||
|
|
||||||
state->cur_filename = old_filename;
|
state->cur_filename = old_filename;
|
||||||
state->cur_lineno = old_lineno;
|
state->cur_lineno = old_lineno;
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -84,6 +84,19 @@ count_set_bits(const char *netmask)
|
||||||
return 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
|
bool
|
||||||
lif_address_format_cidr(const struct lif_interface *iface, struct lif_dict_entry *entry, char *buf, size_t buflen)
|
lif_address_format_cidr(const struct lif_interface *iface, struct lif_dict_entry *entry, char *buf, size_t buflen)
|
||||||
{
|
{
|
||||||
|
@ -91,14 +104,7 @@ lif_address_format_cidr(const struct lif_interface *iface, struct lif_dict_entry
|
||||||
size_t orig_netmask = addr->netmask;
|
size_t orig_netmask = addr->netmask;
|
||||||
|
|
||||||
if (!addr->netmask)
|
if (!addr->netmask)
|
||||||
{
|
addr->netmask = determine_interface_netmask(iface, addr);
|
||||||
/* if netmask is not set, default to 255.255.255.0, ifupdown does so too */
|
|
||||||
addr->netmask = 24;
|
|
||||||
|
|
||||||
struct lif_dict_entry *entry = lif_dict_find(&iface->vars, "netmask");
|
|
||||||
if (entry != NULL)
|
|
||||||
addr->netmask = count_set_bits(entry->data);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!lif_address_unparse(addr, buf, buflen, true))
|
if (!lif_address_unparse(addr, buf, buflen, true))
|
||||||
{
|
{
|
||||||
|
@ -122,16 +128,6 @@ lif_interface_init(struct lif_interface *interface, const char *ifname)
|
||||||
/* keep the 'vlan' executor as a config hint for backwards compatibility */
|
/* keep the 'vlan' executor as a config hint for backwards compatibility */
|
||||||
if (strchr(ifname, '.') != NULL)
|
if (strchr(ifname, '.') != NULL)
|
||||||
lif_interface_use_executor(interface, "vlan");
|
lif_interface_use_executor(interface, "vlan");
|
||||||
|
|
||||||
if (!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, "hostname", strdup(un.nodename));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -211,6 +207,46 @@ lif_interface_use_executor(struct lif_interface *interface, const char *executor
|
||||||
interface->is_bridge = true;
|
interface->is_bridge = true;
|
||||||
else if (!strcmp(executor, "bond"))
|
else if (!strcmp(executor, "bond"))
|
||||||
interface->is_bond = true;
|
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
|
void
|
||||||
|
@ -223,6 +259,7 @@ lif_interface_collection_init(struct lif_dict *collection)
|
||||||
/* always enable loopback interface as part of a collection */
|
/* always enable loopback interface as part of a collection */
|
||||||
if_lo = lif_interface_collection_find(collection, "lo");
|
if_lo = lif_interface_collection_find(collection, "lo");
|
||||||
if_lo->is_auto = true;
|
if_lo->is_auto = true;
|
||||||
|
if_lo->is_explicit = true;
|
||||||
lif_interface_use_executor(if_lo, "loopback");
|
lif_interface_use_executor(if_lo, "loopback");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,7 @@ struct lif_interface {
|
||||||
bool is_bond;
|
bool is_bond;
|
||||||
bool is_template;
|
bool is_template;
|
||||||
bool is_pending;
|
bool is_pending;
|
||||||
|
bool is_explicit;
|
||||||
|
|
||||||
bool has_config_error; /* error found in interface configuration */
|
bool has_config_error; /* error found in interface configuration */
|
||||||
|
|
||||||
|
@ -74,6 +75,7 @@ extern bool lif_interface_address_add(struct lif_interface *interface, const cha
|
||||||
extern void lif_interface_address_delete(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_fini(struct lif_interface *interface);
|
||||||
extern void lif_interface_use_executor(struct lif_interface *interface, const char *executor);
|
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_init(struct lif_dict *collection);
|
||||||
extern void lif_interface_collection_fini(struct lif_dict *collection);
|
extern void lif_interface_collection_fini(struct lif_dict *collection);
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "libifupdown/tokenize.h"
|
#include "libifupdown/tokenize.h"
|
||||||
#include "libifupdown/config-file.h"
|
#include "libifupdown/config-file.h"
|
||||||
#include "libifupdown/config-parser.h"
|
#include "libifupdown/config-parser.h"
|
||||||
|
#include "libifupdown/compat.h"
|
||||||
|
|
||||||
#ifndef ARRAY_SIZE
|
#ifndef ARRAY_SIZE
|
||||||
# define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x))
|
# define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x))
|
||||||
|
|
|
@ -94,7 +94,8 @@ query_dependents_from_executors(const struct lif_execute_opts *opts, char *const
|
||||||
struct lif_execute_opts exec_opts = {
|
struct lif_execute_opts exec_opts = {
|
||||||
.verbose = opts->verbose,
|
.verbose = opts->verbose,
|
||||||
.executor_path = opts->executor_path,
|
.executor_path = opts->executor_path,
|
||||||
.interfaces_file = opts->interfaces_file
|
.interfaces_file = opts->interfaces_file,
|
||||||
|
.timeout = opts->timeout,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (strcmp(entry->key, "use"))
|
if (strcmp(entry->key, "use"))
|
||||||
|
@ -114,7 +115,7 @@ query_dependents_from_executors(const struct lif_execute_opts *opts, char *const
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
static bool
|
||||||
append_to_buffer(char **buffer, size_t *buffer_len, char **end, const char *value)
|
append_to_buffer(char **buffer, size_t *buffer_len, char **end, const char *value)
|
||||||
{
|
{
|
||||||
size_t value_len = strlen (value);
|
size_t value_len = strlen (value);
|
||||||
|
@ -122,13 +123,18 @@ append_to_buffer(char **buffer, size_t *buffer_len, char **end, const char *valu
|
||||||
/* Make sure there is enough room to add the value to the buffer */
|
/* Make sure there is enough room to add the value to the buffer */
|
||||||
if (*buffer_len < strlen (*buffer) + value_len + 2)
|
if (*buffer_len < strlen (*buffer) + value_len + 2)
|
||||||
{
|
{
|
||||||
*buffer = realloc (*buffer, *buffer_len * 2);
|
size_t end_offset = *end - *buffer;
|
||||||
if (*buffer == NULL)
|
char *tmp = realloc (*buffer, *buffer_len * 2);
|
||||||
/* XXX Here be dragons */
|
|
||||||
return false;
|
|
||||||
|
|
||||||
|
if (tmp != NULL)
|
||||||
|
{
|
||||||
|
*buffer = tmp;
|
||||||
|
*end = tmp + end_offset;
|
||||||
*buffer_len = *buffer_len * 2;
|
*buffer_len = *buffer_len * 2;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* Append value to buffer */
|
/* Append value to buffer */
|
||||||
size_t printed = snprintf (*end, value_len + 2, "%s ", value);
|
size_t printed = snprintf (*end, value_len + 2, "%s ", value);
|
||||||
|
@ -396,6 +402,15 @@ handle_dependents(const struct lif_execute_opts *opts, struct lif_interface *par
|
||||||
continue;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
if (opts->verbose)
|
if (opts->verbose)
|
||||||
fprintf(stderr, "ifupdown: changing state of dependent interface %s (of %s) to %s\n",
|
fprintf(stderr, "ifupdown: changing state of dependent interface %s (of %s) to %s\n",
|
||||||
iface->ifname, parent->ifname, up ? "up" : "down");
|
iface->ifname, parent->ifname, up ? "up" : "down");
|
||||||
|
|
|
@ -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)
|
for ((iter) = (head); (iter) != NULL; (iter) = (iter)->next)
|
||||||
|
|
||||||
#define LIF_LIST_FOREACH_SAFE(iter, iter_next, head) \
|
#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) \
|
#define LIF_LIST_FOREACH_REVERSE(iter, tail) \
|
||||||
for ((iter) = (tail); (iter) != NULL; (iter) = (iter)->prev)
|
for ((iter) = (tail); (iter) != NULL; (iter) = (iter)->prev)
|
||||||
|
|
|
@ -29,8 +29,13 @@ lif_state_read(struct lif_dict *state, FILE *fd)
|
||||||
char *bufp = linebuf;
|
char *bufp = linebuf;
|
||||||
char *ifname = lif_next_token(&bufp);
|
char *ifname = lif_next_token(&bufp);
|
||||||
char *refcount = lif_next_token(&bufp);
|
char *refcount = lif_next_token(&bufp);
|
||||||
|
char *explicit = lif_next_token(&bufp);
|
||||||
size_t rc = 1;
|
size_t rc = 1;
|
||||||
char *equals_p = strchr(linebuf, '=');
|
char *equals_p = strchr(linebuf, '=');
|
||||||
|
bool is_explicit = false;
|
||||||
|
|
||||||
|
if (*explicit && !strcmp(explicit, "explicit"))
|
||||||
|
is_explicit = true;
|
||||||
|
|
||||||
if (*refcount)
|
if (*refcount)
|
||||||
{
|
{
|
||||||
|
@ -42,12 +47,12 @@ lif_state_read(struct lif_dict *state, FILE *fd)
|
||||||
|
|
||||||
if (equals_p == NULL)
|
if (equals_p == NULL)
|
||||||
{
|
{
|
||||||
lif_state_upsert(state, ifname, &(struct lif_interface){ .ifname = ifname, .refcount = rc });
|
lif_state_upsert(state, ifname, &(struct lif_interface){ .ifname = ifname, .refcount = rc, .is_explicit = is_explicit });
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
*equals_p++ = '\0';
|
*equals_p++ = '\0';
|
||||||
lif_state_upsert(state, ifname, &(struct lif_interface){ .ifname = equals_p, .refcount = rc });
|
lif_state_upsert(state, ifname, &(struct lif_interface){ .ifname = equals_p, .refcount = rc, .is_explicit = is_explicit });
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -99,6 +104,7 @@ lif_state_upsert(struct lif_dict *state, const char *ifname, struct lif_interfac
|
||||||
|
|
||||||
rec->mapped_if = strdup(iface->ifname);
|
rec->mapped_if = strdup(iface->ifname);
|
||||||
rec->refcount = iface->refcount;
|
rec->refcount = iface->refcount;
|
||||||
|
rec->is_explicit = iface->is_explicit;
|
||||||
|
|
||||||
lif_dict_add(state, ifname, rec);
|
lif_dict_add(state, ifname, rec);
|
||||||
}
|
}
|
||||||
|
@ -128,7 +134,8 @@ lif_state_write(const struct lif_dict *state, FILE *f)
|
||||||
struct lif_dict_entry *entry = iter->data;
|
struct lif_dict_entry *entry = iter->data;
|
||||||
struct lif_state_record *rec = entry->data;
|
struct lif_state_record *rec = entry->data;
|
||||||
|
|
||||||
fprintf(f, "%s=%s %zu\n", entry->key, rec->mapped_if, rec->refcount);
|
fprintf(f, "%s=%s %zu%s\n", entry->key, rec->mapped_if, rec->refcount,
|
||||||
|
rec->is_explicit ? " explicit" : "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,6 +182,7 @@ lif_state_sync(struct lif_dict *state, struct lif_dict *if_collection)
|
||||||
struct lif_interface *iface = lif_interface_collection_find(if_collection, rec->mapped_if);
|
struct lif_interface *iface = lif_interface_collection_find(if_collection, rec->mapped_if);
|
||||||
|
|
||||||
iface->refcount = rec->refcount;
|
iface->refcount = rec->refcount;
|
||||||
|
iface->is_explicit = rec->is_explicit;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -17,11 +17,14 @@
|
||||||
#define LIBIFUPDOWN_STATE_H__GUARD
|
#define LIBIFUPDOWN_STATE_H__GUARD
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include "libifupdown/interface.h"
|
#include "libifupdown/interface.h"
|
||||||
|
|
||||||
struct lif_state_record {
|
struct lif_state_record {
|
||||||
char *mapped_if;
|
char *mapped_if;
|
||||||
size_t refcount;
|
size_t refcount;
|
||||||
|
|
||||||
|
bool is_explicit;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern bool lif_state_read(struct lif_dict *state, FILE *f);
|
extern bool lif_state_read(struct lif_dict *state, FILE *f);
|
||||||
|
|
|
@ -21,20 +21,20 @@
|
||||||
void
|
void
|
||||||
lif_common_version(void)
|
lif_common_version(void)
|
||||||
{
|
{
|
||||||
printf("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION);
|
printf(PACKAGE_NAME " " PACKAGE_VERSION "\n"
|
||||||
|
"\n"
|
||||||
printf("\nCopyright (c) 2020 Ariadne Conill <ariadne@dereferenced.org>\n");
|
"Copyright (c) 2020 Ariadne Conill <ariadne@dereferenced.org>\n"
|
||||||
printf("\nCopyright (c) 2020 Maximilian Wilhelm <max@sdn.clinic>\n\n");
|
"Copyright (c) 2020 Maximilian Wilhelm <max@sdn.clinic>\n"
|
||||||
|
"\n"
|
||||||
printf("Permission to use, copy, modify, and/or distribute this software for any\n");
|
"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");
|
"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");
|
"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");
|
"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");
|
"implied. In no event shall the authors be liable for any damages arising\n"
|
||||||
printf("from the use of this software.\n\n");
|
"from the use of this software.\n"
|
||||||
|
"\n"
|
||||||
printf("Report bugs at <%s>.\n", PACKAGE_BUGREPORT);
|
"Report bugs at <" PACKAGE_BUGREPORT ">.\n");
|
||||||
|
|
||||||
exit(EXIT_SUCCESS);
|
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')
|
test_suite('ifupdown-ng')
|
||||||
|
|
||||||
|
atf_test_program{name='multicall_test'}
|
||||||
atf_test_program{name='ifquery_test'}
|
atf_test_program{name='ifquery_test'}
|
||||||
atf_test_program{name='ifup_test'}
|
atf_test_program{name='ifup_test'}
|
||||||
atf_test_program{name='ifdown_test'}
|
atf_test_program{name='ifdown_test'}
|
||||||
|
|
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
|
5
tests/fixtures/without-netmask.interfaces
vendored
Normal file
5
tests/fixtures/without-netmask.interfaces
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
iface v6
|
||||||
|
address 2001:470:1f10::1
|
||||||
|
|
||||||
|
iface v4
|
||||||
|
address 203.0.113.2
|
|
@ -34,7 +34,16 @@ tests_init \
|
||||||
vlan_explicit_learned_dependency \
|
vlan_explicit_learned_dependency \
|
||||||
vlan_guessed_learned_dependency \
|
vlan_guessed_learned_dependency \
|
||||||
vlan_complex_learned_dependency \
|
vlan_complex_learned_dependency \
|
||||||
wireguard
|
wireguard \
|
||||||
|
allow_undefined_positive \
|
||||||
|
allow_undefined_negative \
|
||||||
|
default_netmask_v4 \
|
||||||
|
default_netmask_v6 \
|
||||||
|
stanza_merging_with_cidr \
|
||||||
|
stanza_merging_without_cidr \
|
||||||
|
dhcp_hostname_rewrite \
|
||||||
|
dhcp_hostname_inference \
|
||||||
|
dhcp_hostname_replacement
|
||||||
|
|
||||||
noargs_body() {
|
noargs_body() {
|
||||||
atf_check -s exit:1 -e ignore ifquery -S/dev/null
|
atf_check -s exit:1 -e ignore ifquery -S/dev/null
|
||||||
|
@ -226,3 +235,62 @@ wireguard_body() {
|
||||||
-o match:"use wireguard" \
|
-o match:"use wireguard" \
|
||||||
ifquery -E $EXECUTORS_LINUX -i $FIXTURES/wireguard.interfaces wg0
|
ifquery -E $EXECUTORS_LINUX -i $FIXTURES/wireguard.interfaces wg0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
allow_undefined_positive_body() {
|
||||||
|
atf_check -s exit:0 \
|
||||||
|
-o ignore \
|
||||||
|
-e ignore \
|
||||||
|
ifquery -U -i /dev/null -p address foo
|
||||||
|
}
|
||||||
|
|
||||||
|
allow_undefined_negative_body() {
|
||||||
|
atf_check -s exit:1 \
|
||||||
|
-o ignore \
|
||||||
|
-e ignore \
|
||||||
|
ifquery -i /dev/null -p address foo
|
||||||
|
}
|
||||||
|
|
||||||
|
default_netmask_v4_body() {
|
||||||
|
atf_check -s exit:0 \
|
||||||
|
-o match:"203.0.113.2/24" \
|
||||||
|
ifquery -i $FIXTURES/without-netmask.interfaces -p address v4
|
||||||
|
}
|
||||||
|
|
||||||
|
default_netmask_v6_body() {
|
||||||
|
atf_check -s exit:0 \
|
||||||
|
-o match:"2001:470:1f10::1/64" \
|
||||||
|
ifquery -i $FIXTURES/without-netmask.interfaces -p address v6
|
||||||
|
}
|
||||||
|
|
||||||
|
stanza_merging_with_cidr_body() {
|
||||||
|
atf_check -s exit:0 \
|
||||||
|
-o match:"203.0.113.1/32" \
|
||||||
|
-o match:"203.0.113.2/24" \
|
||||||
|
ifquery -i $FIXTURES/stanza-merging.interfaces -p address cidr
|
||||||
|
}
|
||||||
|
|
||||||
|
stanza_merging_without_cidr_body() {
|
||||||
|
atf_check -s exit:0 \
|
||||||
|
-o match:"203.0.113.1/32" \
|
||||||
|
-o match:"203.0.113.2/24" \
|
||||||
|
ifquery -i $FIXTURES/stanza-merging.interfaces -p address without-cidr
|
||||||
|
}
|
||||||
|
|
||||||
|
dhcp_hostname_rewrite_body() {
|
||||||
|
atf_check -s exit:0 \
|
||||||
|
-o match:"dhcp-hostname foo" \
|
||||||
|
ifquery -i $FIXTURES/dhcp-hostname-rewrite.interfaces -P eth0
|
||||||
|
}
|
||||||
|
|
||||||
|
dhcp_hostname_inference_body() {
|
||||||
|
hostname=$(uname -n)
|
||||||
|
atf_check -s exit:0 \
|
||||||
|
-o match:"dhcp-hostname $hostname" \
|
||||||
|
ifquery -i $FIXTURES/dhcp-hostname-rewrite.interfaces -P eth1
|
||||||
|
}
|
||||||
|
|
||||||
|
dhcp_hostname_replacement_body() {
|
||||||
|
atf_check -s exit:0 \
|
||||||
|
-o match:"dhcp-hostname bar" \
|
||||||
|
ifquery -i $FIXTURES/dhcp-hostname-rewrite.interfaces -P eth2
|
||||||
|
}
|
|
@ -2,14 +2,17 @@ syntax(2)
|
||||||
|
|
||||||
test_suite('ifupdown-ng')
|
test_suite('ifupdown-ng')
|
||||||
|
|
||||||
atf_test_program{name='link_test'}
|
atf_test_program{name='bond_test'}
|
||||||
atf_test_program{name='ipv6-ra_test'}
|
|
||||||
atf_test_program{name='dhcp_test'}
|
atf_test_program{name='dhcp_test'}
|
||||||
atf_test_program{name='static_test'}
|
|
||||||
atf_test_program{name='vrf_test'}
|
|
||||||
atf_test_program{name='ppp_test'}
|
|
||||||
atf_test_program{name='tunnel_test'}
|
|
||||||
atf_test_program{name='gre_test'}
|
|
||||||
atf_test_program{name='wireguard_test'}
|
|
||||||
atf_test_program{name='ethtool_test'}
|
atf_test_program{name='ethtool_test'}
|
||||||
|
atf_test_program{name='forward_test'}
|
||||||
|
atf_test_program{name='gre_test'}
|
||||||
|
atf_test_program{name='ipv6-ra_test'}
|
||||||
|
atf_test_program{name='link_test'}
|
||||||
|
atf_test_program{name='mpls_test'}
|
||||||
|
atf_test_program{name='ppp_test'}
|
||||||
|
atf_test_program{name='static_test'}
|
||||||
|
atf_test_program{name='tunnel_test'}
|
||||||
|
atf_test_program{name='vrf_test'}
|
||||||
atf_test_program{name='vxlan_test'}
|
atf_test_program{name='vxlan_test'}
|
||||||
|
atf_test_program{name='wireguard_test'}
|
||||||
|
|
30
tests/linux/bond_test
Executable file
30
tests/linux/bond_test
Executable file
|
@ -0,0 +1,30 @@
|
||||||
|
#!/usr/bin/env atf-sh
|
||||||
|
|
||||||
|
. $(atf_get_srcdir)/../test_env.sh
|
||||||
|
EXECUTOR="$(atf_get_srcdir)/../../executor-scripts/linux/bond"
|
||||||
|
|
||||||
|
tests_init \
|
||||||
|
create_lacp_basic \
|
||||||
|
create_lacp_real
|
||||||
|
|
||||||
|
create_lacp_basic_body() {
|
||||||
|
export IFACE=bond0 PHASE=create MOCK=echo IF_BOND_MODE=802.3ad IF_BOND_MEMBERS="eth0 eth1"
|
||||||
|
atf_check -s exit:0 \
|
||||||
|
-o match:'ip link add bond0 type bond mode 802.3ad' \
|
||||||
|
-o match:'ip link set eth0 down' \
|
||||||
|
-o match:'ip link set master bond0 eth0' \
|
||||||
|
-o match:'ip link set eth0 up' \
|
||||||
|
-o match:'ip link set master bond0 eth1' \
|
||||||
|
${EXECUTOR}
|
||||||
|
}
|
||||||
|
|
||||||
|
create_lacp_real_body() {
|
||||||
|
export IFACE=bond0 PHASE=create MOCK=echo IF_BOND_MODE=802.3ad IF_BOND_MEMBERS="eth0 eth1" \
|
||||||
|
IF_BOND_MIN_LINKS="1" IF_BOND_XMIT_HASH_POLICY="layer3+4"
|
||||||
|
atf_check -s exit:0 \
|
||||||
|
-o match:'ip link add bond0 type bond' \
|
||||||
|
-o match:'mode 802.3ad' \
|
||||||
|
-o match:'min_links 1' \
|
||||||
|
-o match:'xmit_hash_policy layer3\+4' \
|
||||||
|
${EXECUTOR}
|
||||||
|
}
|
|
@ -48,7 +48,7 @@ udhcpc_opts_up_subshell_body() {
|
||||||
}
|
}
|
||||||
|
|
||||||
hostname_subshell_body() {
|
hostname_subshell_body() {
|
||||||
export IFACE=eth0 PHASE=up MOCK=echo IF_DHCP_PROGRAM=udhcpc IF_HOSTNAME="\$(echo test)"
|
export IFACE=eth0 PHASE=up MOCK=echo IF_DHCP_PROGRAM=udhcpc IF_DHCP_HOSTNAME="\$(echo test)"
|
||||||
atf_check -s exit:0 -o match:'/sbin/udhcpc -b -R -p /var/run/udhcpc.eth0.pid -i eth0 -x hostname:test' \
|
atf_check -s exit:0 -o match:'/sbin/udhcpc -b -R -p /var/run/udhcpc.eth0.pid -i eth0 -x hostname:test' \
|
||||||
${EXECUTOR}
|
${EXECUTOR}
|
||||||
}
|
}
|
||||||
|
|
90
tests/linux/forward_test
Executable file
90
tests/linux/forward_test
Executable file
|
@ -0,0 +1,90 @@
|
||||||
|
#!/usr/bin/env atf-sh
|
||||||
|
|
||||||
|
. $(atf_get_srcdir)/../test_env.sh
|
||||||
|
EXECUTOR="$(atf_get_srcdir)/../../executor-scripts/linux/forward"
|
||||||
|
|
||||||
|
tests_init \
|
||||||
|
up_forward_v4 \
|
||||||
|
up_forward_v6 \
|
||||||
|
up_forward_v4_mc \
|
||||||
|
up_forward_v6_mc
|
||||||
|
|
||||||
|
up_forward_v4_body() {
|
||||||
|
export IF_FORWARD_IPV4= IF_FORWARD_IPV6= IF_FORWARD_IPV4_MC= IF_FORWARD_IPV6_MC=
|
||||||
|
|
||||||
|
export IFACE=eth0 PHASE=up MOCK=echo IF_FORWARD_IPV4=1
|
||||||
|
atf_check -s exit:0 -o match:'echo 1 > /proc/sys/net/ipv4/conf/eth0/forwarding' \
|
||||||
|
${EXECUTOR}
|
||||||
|
|
||||||
|
export IFACE=eth0 PHASE=up MOCK=echo IF_FORWARD_IPV4=yes
|
||||||
|
atf_check -s exit:0 -o match:'echo 1 > /proc/sys/net/ipv4/conf/eth0/forwarding' \
|
||||||
|
${EXECUTOR}
|
||||||
|
|
||||||
|
export IFACE=eth0 PHASE=up MOCK=echo IF_FORWARD_IPV4=0
|
||||||
|
atf_check -s exit:0 -o match:'echo 0 > /proc/sys/net/ipv4/conf/eth0/forwarding' \
|
||||||
|
${EXECUTOR}
|
||||||
|
|
||||||
|
export IFACE=eth0 PHASE=up MOCK=echo IF_FORWARD_IPV4=no
|
||||||
|
atf_check -s exit:0 -o match:'echo 0 > /proc/sys/net/ipv4/conf/eth0/forwarding' \
|
||||||
|
${EXECUTOR}
|
||||||
|
}
|
||||||
|
|
||||||
|
up_forward_v6_body() {
|
||||||
|
export IF_FORWARD_IPV4= IF_FORWARD_IPV6= IF_FORWARD_IPV4_MC= IF_FORWARD_IPV6_MC=
|
||||||
|
|
||||||
|
export IFACE=eth0 PHASE=up MOCK=echo IF_FORWARD_IPV6=1
|
||||||
|
atf_check -s exit:0 -o match:'echo 1 > /proc/sys/net/ipv6/conf/eth0/forwarding' \
|
||||||
|
${EXECUTOR}
|
||||||
|
|
||||||
|
export IFACE=eth0 PHASE=up MOCK=echo IF_FORWARD_IPV6=yes
|
||||||
|
atf_check -s exit:0 -o match:'echo 1 > /proc/sys/net/ipv6/conf/eth0/forwarding' \
|
||||||
|
${EXECUTOR}
|
||||||
|
|
||||||
|
export IFACE=eth0 PHASE=up MOCK=echo IF_FORWARD_IPV6=0
|
||||||
|
atf_check -s exit:0 -o match:'echo 0 > /proc/sys/net/ipv6/conf/eth0/forwarding' \
|
||||||
|
${EXECUTOR}
|
||||||
|
|
||||||
|
export IFACE=eth0 PHASE=up MOCK=echo IF_FORWARD_IPV6=no
|
||||||
|
atf_check -s exit:0 -o match:'echo 0 > /proc/sys/net/ipv6/conf/eth0/forwarding' \
|
||||||
|
${EXECUTOR}
|
||||||
|
}
|
||||||
|
|
||||||
|
up_forward_v4_mc_body() {
|
||||||
|
export IF_FORWARD_IPV4= IF_FORWARD_IPV6= IF_FORWARD_IPV4_MC= IF_FORWARD_IPV6_MC=
|
||||||
|
|
||||||
|
export IFACE=eth0 PHASE=up MOCK=echo IF_FORWARD_IPV4_MC=1
|
||||||
|
atf_check -s exit:0 -o match:'echo 1 > /proc/sys/net/ipv4/conf/eth0/mc_forwarding' \
|
||||||
|
${EXECUTOR}
|
||||||
|
|
||||||
|
export IFACE=eth0 PHASE=up MOCK=echo IF_FORWARD_IPV4_MC=yes
|
||||||
|
atf_check -s exit:0 -o match:'echo 1 > /proc/sys/net/ipv4/conf/eth0/mc_forwarding' \
|
||||||
|
${EXECUTOR}
|
||||||
|
|
||||||
|
export IFACE=eth0 PHASE=up MOCK=echo IF_FORWARD_IPV4_MC=0
|
||||||
|
atf_check -s exit:0 -o match:'echo 0 > /proc/sys/net/ipv4/conf/eth0/mc_forwarding' \
|
||||||
|
${EXECUTOR}
|
||||||
|
|
||||||
|
export IFACE=eth0 PHASE=up MOCK=echo IF_FORWARD_IPV4_MC=no
|
||||||
|
atf_check -s exit:0 -o match:'echo 0 > /proc/sys/net/ipv4/conf/eth0/mc_forwarding' \
|
||||||
|
${EXECUTOR}
|
||||||
|
}
|
||||||
|
|
||||||
|
up_forward_v6_mc_body() {
|
||||||
|
export IF_FORWARD_IPV4= IF_FORWARD_IPV6= IF_FORWARD_IPV4_MC= IF_FORWARD_IPV6_MC=
|
||||||
|
|
||||||
|
export IFACE=eth0 PHASE=up MOCK=echo IF_FORWARD_IPV6_MC=1
|
||||||
|
atf_check -s exit:0 -o match:'echo 1 > /proc/sys/net/ipv6/conf/eth0/mc_forwarding' \
|
||||||
|
${EXECUTOR}
|
||||||
|
|
||||||
|
export IFACE=eth0 PHASE=up MOCK=echo IF_FORWARD_IPV6_MC=yes
|
||||||
|
atf_check -s exit:0 -o match:'echo 1 > /proc/sys/net/ipv6/conf/eth0/mc_forwarding' \
|
||||||
|
${EXECUTOR}
|
||||||
|
|
||||||
|
export IFACE=eth0 PHASE=up MOCK=echo IF_FORWARD_IPV6_MC=0
|
||||||
|
atf_check -s exit:0 -o match:'echo 0 > /proc/sys/net/ipv6/conf/eth0/mc_forwarding' \
|
||||||
|
${EXECUTOR}
|
||||||
|
|
||||||
|
export IFACE=eth0 PHASE=up MOCK=echo IF_FORWARD_IPV6_MC=no
|
||||||
|
atf_check -s exit:0 -o match:'echo 0 > /proc/sys/net/ipv6/conf/eth0/mc_forwarding' \
|
||||||
|
${EXECUTOR}
|
||||||
|
}
|
23
tests/linux/mpls_test
Executable file
23
tests/linux/mpls_test
Executable file
|
@ -0,0 +1,23 @@
|
||||||
|
#!/usr/bin/env atf-sh
|
||||||
|
|
||||||
|
. $(atf_get_srcdir)/../test_env.sh
|
||||||
|
EXECUTOR="$(atf_get_srcdir)/../../executor-scripts/linux/mpls"
|
||||||
|
|
||||||
|
tests_init \
|
||||||
|
mpls_enable \
|
||||||
|
mpls_disable
|
||||||
|
|
||||||
|
mpls_enable_body() {
|
||||||
|
export MOCK=echo IFACE=vlan2342 PHASE=pre-up IF_MPLS_ENABLE=yes
|
||||||
|
atf_check -s exit:0 \
|
||||||
|
-o match:"modprobe mpls_iptunnel" \
|
||||||
|
-o match:"echo 1 > /proc/sys/net/mpls/conf/vlan2342/input" \
|
||||||
|
${EXECUTOR}
|
||||||
|
}
|
||||||
|
|
||||||
|
mpls_disable_body() {
|
||||||
|
export MOCK=echo IFACE=vlan2342 PHASE=pre-up IF_MPLS_ENABLE=no
|
||||||
|
atf_check -s exit:0 \
|
||||||
|
-o match:"echo 0 > /proc/sys/net/mpls/conf/vlan2342/input" \
|
||||||
|
${EXECUTOR}
|
||||||
|
}
|
|
@ -8,9 +8,7 @@ tests_init \
|
||||||
up_ptp \
|
up_ptp \
|
||||||
down \
|
down \
|
||||||
vrf_up \
|
vrf_up \
|
||||||
vrf_down \
|
metric_up
|
||||||
metric_up \
|
|
||||||
metric_down
|
|
||||||
|
|
||||||
up_body() {
|
up_body() {
|
||||||
export IFACE=eth0 PHASE=up MOCK=echo IF_ADDRESSES="203.0.113.2/24 2001:db8:1000:2::2/64" \
|
export IFACE=eth0 PHASE=up MOCK=echo IF_ADDRESSES="203.0.113.2/24 2001:db8:1000:2::2/64" \
|
||||||
|
@ -38,10 +36,7 @@ down_body() {
|
||||||
export IFACE=eth0 PHASE=down MOCK=echo IF_ADDRESSES="203.0.113.2/24 2001:db8:1000:2::2/64" \
|
export IFACE=eth0 PHASE=down MOCK=echo IF_ADDRESSES="203.0.113.2/24 2001:db8:1000:2::2/64" \
|
||||||
IF_GATEWAYS="203.0.113.1 2001:db8:1000:2::1"
|
IF_GATEWAYS="203.0.113.1 2001:db8:1000:2::1"
|
||||||
atf_check -s exit:0 \
|
atf_check -s exit:0 \
|
||||||
-o match:'addr del 203.0.113.2/24 dev eth0' \
|
-o match:'addr flush dev eth0' \
|
||||||
-o match:'addr del 2001:db8:1000:2::2/64 dev eth0' \
|
|
||||||
-o match:'route del default via 203.0.113.1 metric 1 dev eth0' \
|
|
||||||
-o match:'route del default via 2001:db8:1000:2::1 metric 1 dev eth0' \
|
|
||||||
${EXECUTOR}
|
${EXECUTOR}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,23 +47,9 @@ vrf_up_body() {
|
||||||
${EXECUTOR}
|
${EXECUTOR}
|
||||||
}
|
}
|
||||||
|
|
||||||
vrf_down_body() {
|
|
||||||
export IFACE=vrf-red PHASE=down MOCK=echo IF_GATEWAYS=203.0.113.2 IF_VRF_TABLE=1
|
|
||||||
atf_check -s exit:0 \
|
|
||||||
-o match:'route del default via 203.0.113.2 table 1' \
|
|
||||||
${EXECUTOR}
|
|
||||||
}
|
|
||||||
|
|
||||||
metric_up_body() {
|
metric_up_body() {
|
||||||
export IFACE=vrf-red PHASE=up MOCK=echo IF_GATEWAYS=203.0.113.2 IF_VRF_TABLE=1 IF_METRIC=20
|
export IFACE=vrf-red PHASE=up MOCK=echo IF_GATEWAYS=203.0.113.2 IF_VRF_TABLE=1 IF_METRIC=20
|
||||||
atf_check -s exit:0 \
|
atf_check -s exit:0 \
|
||||||
-o match:'route add default via 203.0.113.2 table 1 metric 20' \
|
-o match:'route add default via 203.0.113.2 table 1 metric 20' \
|
||||||
${EXECUTOR}
|
${EXECUTOR}
|
||||||
}
|
}
|
||||||
|
|
||||||
metric_down_body() {
|
|
||||||
export IFACE=vrf-red PHASE=down MOCK=echo IF_GATEWAYS=203.0.113.2 IF_VRF_TABLE=1 IF_METRIC=20
|
|
||||||
atf_check -s exit:0 \
|
|
||||||
-o match:'route del default via 203.0.113.2 table 1 metric 20' \
|
|
||||||
${EXECUTOR}
|
|
||||||
}
|
|
||||||
|
|
|
@ -5,7 +5,10 @@ EXECUTOR="$(atf_get_srcdir)/../../executor-scripts/linux/tunnel"
|
||||||
|
|
||||||
tests_init \
|
tests_init \
|
||||||
tunnel_bringup \
|
tunnel_bringup \
|
||||||
tunnel_teardown
|
tunnel_teardown \
|
||||||
|
gretap_up \
|
||||||
|
gretap_down \
|
||||||
|
ip6gretap_up
|
||||||
|
|
||||||
tunnel_bringup_body() {
|
tunnel_bringup_body() {
|
||||||
export MOCK=echo IFACE=tun0 PHASE=create IF_TUNNEL_MODE=gre \
|
export MOCK=echo IFACE=tun0 PHASE=create IF_TUNNEL_MODE=gre \
|
||||||
|
@ -13,7 +16,7 @@ tunnel_bringup_body() {
|
||||||
IF_TUNNEL_TTL=255
|
IF_TUNNEL_TTL=255
|
||||||
atf_check -s exit:0 \
|
atf_check -s exit:0 \
|
||||||
-o match:"ip -4 tunnel add tun0" \
|
-o match:"ip -4 tunnel add tun0" \
|
||||||
-o match:"mode 'gre'" \
|
-o match:"mode gre" \
|
||||||
-o match:"ttl '255'" \
|
-o match:"ttl '255'" \
|
||||||
-o match:"local '1.2.3.4'" \
|
-o match:"local '1.2.3.4'" \
|
||||||
-o match:"remote '5.6.7.8'" \
|
-o match:"remote '5.6.7.8'" \
|
||||||
|
@ -28,3 +31,35 @@ tunnel_teardown_body() {
|
||||||
-o match:"ip -4 tunnel del tun0" \
|
-o match:"ip -4 tunnel del tun0" \
|
||||||
${EXECUTOR}
|
${EXECUTOR}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
gretap_up_body() {
|
||||||
|
export MOCK=echo IFACE=foo PHASE=create IF_TUNNEL_MODE=gretap \
|
||||||
|
IF_TUNNEL_LOCAL=1.2.3.4 IF_TUNNEL_REMOTE=5.6.7.8
|
||||||
|
atf_check -s exit:0 \
|
||||||
|
-o match:"ip -4 link add foo" \
|
||||||
|
-o match:"type gretap" \
|
||||||
|
-o match:"local '1.2.3.4'" \
|
||||||
|
-o match:"remote '5.6.7.8'" \
|
||||||
|
${EXECUTOR}
|
||||||
|
}
|
||||||
|
|
||||||
|
gretap_down_body() {
|
||||||
|
export MOCK=echo IFACE=foo PHASE=destroy IF_TUNNEL_MODE=gretap \
|
||||||
|
IF_TUNNEL_LOCAL=1.2.3.4 IF_TUNNEL_REMOTE=5.6.7.8
|
||||||
|
atf_check -s exit:0 \
|
||||||
|
-o match:"ip -4 link del foo" \
|
||||||
|
${EXECUTOR}
|
||||||
|
}
|
||||||
|
|
||||||
|
ip6gretap_up_body() {
|
||||||
|
export MOCK=echo IFACE=foo PHASE=create IF_TUNNEL_MODE=ip6gretap \
|
||||||
|
IF_TUNNEL_LOCAL=2001:db8::aaaa IF_TUNNEL_REMOTE=2001:db8::eeee
|
||||||
|
atf_check -s exit:0 \
|
||||||
|
-o match:"ip -6 link add foo" \
|
||||||
|
-o match:"type gretap" \
|
||||||
|
-o match:"local '2001:db8::aaaa'" \
|
||||||
|
-o match:"remote '2001:db8::eeee'" \
|
||||||
|
${EXECUTOR}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,8 @@ EXECUTOR="$(atf_get_srcdir)/../../executor-scripts/linux/vxlan"
|
||||||
|
|
||||||
tests_init \
|
tests_init \
|
||||||
create_simple \
|
create_simple \
|
||||||
create_ucast \
|
create_ucast_ptp \
|
||||||
|
create_ucast_ptmp \
|
||||||
create_mcast \
|
create_mcast \
|
||||||
create_physdev \
|
create_physdev \
|
||||||
create_dstport \
|
create_dstport \
|
||||||
|
@ -18,14 +19,24 @@ create_simple_body() {
|
||||||
${EXECUTOR}
|
${EXECUTOR}
|
||||||
}
|
}
|
||||||
|
|
||||||
create_ucast_body() {
|
create_ucast_ptp_body() {
|
||||||
export IFACE=vx_foo PHASE=create MOCK=echo IF_VXLAN_ID=2342 IF_VXLAN_REMOTE_IP=192.2.0.42
|
export IFACE=vx_foo PHASE=create MOCK=echo IF_VXLAN_ID=2342 IF_VXLAN_PEER_IPS=192.2.0.42
|
||||||
atf_check -s exit:0 -o match:'ip link add vx_foo type vxlan id 2342 remote 192.2.0.42' \
|
atf_check -s exit:0 -o match:'ip link add vx_foo type vxlan id 2342 remote 192.2.0.42' \
|
||||||
${EXECUTOR}
|
${EXECUTOR}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
create_ucast_ptmp_body() {
|
||||||
|
export IFACE=vx_foo PHASE=create MOCK=echo IF_VXLAN_ID=2342 IF_VXLAN_PEER_IPS="10.0.0.1 10.0.0.2 10.0.0.3"
|
||||||
|
atf_check -s exit:0 \
|
||||||
|
-o match:'ip link add vx_foo type vxlan id 2342 dstport 4789' \
|
||||||
|
-o match:'bridge fdb append 00:00:00:00:00:00 dev vx_foo dst 10.0.0.1 self permanent' \
|
||||||
|
-o match:'bridge fdb append 00:00:00:00:00:00 dev vx_foo dst 10.0.0.2 self permanent' \
|
||||||
|
-o match:'bridge fdb append 00:00:00:00:00:00 dev vx_foo dst 10.0.0.3 self permanent' \
|
||||||
|
${EXECUTOR}
|
||||||
|
}
|
||||||
|
|
||||||
create_mcast_body() {
|
create_mcast_body() {
|
||||||
export IFACE=vx_foo PHASE=create MOCK=echo IF_VXLAN_ID=2342 IF_VXLAN_REMOTE_GROUP=225.0.8.15
|
export IFACE=vx_foo PHASE=create MOCK=echo IF_VXLAN_ID=2342 IF_VXLAN_PEER_GROUP=225.0.8.15
|
||||||
atf_check -s exit:0 -o match:'ip link add vx_foo type vxlan id 2342 group 225.0.8.15' \
|
atf_check -s exit:0 -o match:'ip link add vx_foo type vxlan id 2342 group 225.0.8.15' \
|
||||||
${EXECUTOR}
|
${EXECUTOR}
|
||||||
}
|
}
|
||||||
|
|
11
tests/multicall_test
Executable file
11
tests/multicall_test
Executable file
|
@ -0,0 +1,11 @@
|
||||||
|
#!/usr/bin/env atf-sh
|
||||||
|
|
||||||
|
. $(atf_get_srcdir)/test_env.sh
|
||||||
|
|
||||||
|
tests_init \
|
||||||
|
regress_getopt
|
||||||
|
|
||||||
|
regress_getopt_body() {
|
||||||
|
atf_check -e not-inline:'-F: applet not found' -o ignore -s exit:1 \
|
||||||
|
ifupdown ifquery -F
|
||||||
|
}
|
Loading…
Reference in a new issue