Compare commits

...

158 commits

Author SHA1 Message Date
Zola
e978d1a42c Fix a bug in the wifi executor script
When stopping wpa_supplicant, the code is supposed to check if a file named $PIDFILE exists and kill the process listed inside. Instead it was checking if a directory named $PIDFILE exists and because this was never the case, killing of the wpa_supplicant process would always silently fail.

This would, after a few invocations of the ifup command, leave the system with large number of running wpa_supplicant processes, all trying to take control of the same interface.
2021-11-25 22:44:19 -06:00
Maximilian Wilhelm
80074c997f
Merge pull request #162 from BarbarossaTM/feature/vxlan-vtep-list
vxlan: Add support for PTMP setups and rename options to vxlan-peer-{ips,group}
2021-10-31 19:44:57 +01:00
Maximilian Wilhelm
0e99af7669 vxlan: Document that vxlan-phsydev is required for multicast setups
Signed-off-by: Maximilian Wilhelm <max@sdn.clinic>
2021-10-16 15:28:13 +02:00
Maximilian Wilhelm
b75e509f3d vxlan: Add support for PTMP setups and rename options to vxlan-peer-{ip,group}
This commit adds support for configuring static PTMP overlays with VXLAN by
  allowing to specify multiple IPs for »vxlan-peer-ips«.  If more than one IP
  is given ifupdown-ng will set up additional FDB entries for all peer IPs and
  the Linux Kernel will do ingres / head-end replication for BUM traffic.

  For a cleaner naming schema and simliar names to commercial vendor CLIs the
  options to specify unicast or multicast peers have been renamed and aliases
  added for compatibility to previous versions of ifupdown-ng:
   * »vxlan-remote-ip« now is named »vxlan-peer-ips«
   * »vxlan-remote-group« now is called »vxlan-peer-group«

Signed-off-by: Maximilian Wilhelm <max@sdn.clinic>
2021-10-16 15:27:30 +02:00
Ariadne Conill
d83c8259e6 tighten fallback busyloop implementation 2021-09-19 13:05:12 -05:00
Ariadne Conill
2477e7266c use process descriptors where available for readiness notification 2021-09-19 13:05:12 -05:00
Ariadne Conill
97b1a11be0 doc: document timeout parameter in manual pages 2021-09-19 13:05:12 -05:00
Ariadne Conill
941d7c51d7 implement execution timeouts for executors
Previously, it was possible for an executor to hang forever.  To mitigate
this, we now implement process execution timeouts for executors, by looping
with waitpid(..., WNOHANG) and sleeping.

This could be implemented more efficiently with process descriptors, see
pidfd_open(2), but that interface is Linux-specific and is only available
on Linux 5.3 or newer.
2021-09-19 13:05:12 -05:00
Ariadne Conill
7a46b61996
Merge pull request #160 from BarbarossaTM/chore/pedantic-gcc
Make gcc complain more and treat warnings as errors
2021-09-13 05:40:48 -05:00
Maximilian Wilhelm
571786ae91 Makefile: Make gcc be more pendantic and bail out on warnings
Signed-off-by: Maximilian Wilhelm <max@sdn.clinic>
2021-09-12 18:27:41 +02:00
Maximilian Wilhelm
dd3a99cfa8 Fix prototypes for ifctrstat(-linux)
Signed-off-by: Maximilian Wilhelm <max@sdn.clinic>
2021-09-12 18:27:11 +02:00
Maximilian Wilhelm
67fc80fc78 Fix missingp prototypes for static functions
Signed-off-by: Maximilian Wilhelm <max@sdn.clinic>
2021-09-12 18:26:07 +02:00
Maximilian Wilhelm
65e5e07c5f Fix prototype of append_to_buffer()
Signed-off-by: Maximilian Wilhelm <max@sdn.clinic>
2021-09-12 18:11:43 +02:00
Maximilian Wilhelm
0547924ee8 Fix delcaration/prototype for lif_compat_apply()
Signed-off-by: Maximilian Wilhelm <max@sdn.clinic>
2021-09-12 18:10:51 +02:00
Maximilian Wilhelm
4033f6374f Update copyright notice
Signed-off-by: Maximilian Wilhelm <max@sdn.clinic>
2021-09-01 19:21:21 +02:00
Ariadne Conill
b25448f42f kyua is available on Debian now 2021-08-08 12:14:20 -06:00
Ariadne Conill
96fa8ccbf9 build: add EXECUTOR_SCRIPTS_NATIVE 2021-07-10 18:28:55 -06:00
Maximilian Wilhelm
108c88014d doc: Clarify expected config file format for wireguard.
The configuration file format for use with 'wg-quick' and 'wg setconf' are
  imcompatible.  Explicitly state which format is required and how to convert
  a present configuration.

Signed-off-by: Maximilian Wilhelm <max@sdn.clinic>
2021-06-17 18:12:04 +02:00
Ariadne Conill
9c00111932 ifupdown-ng 0.11.3. 2021-06-03 15:01:33 -06:00
Ariadne Conill
12ffc3de12 admin guide: update IRC server 2021-06-03 15:00:17 -06:00
Ariadne Conill
34753136b8 update IRC server 2021-06-03 11:18:27 -06:00
Maximilian Wilhelm
559b4ad942
Merge pull request #153 from BarbarossaTM/feature/tunnel-pimps
Brush up tunnels
2021-06-03 18:54:36 +02:00
Maximilian Wilhelm
ed9aae85ed doc: Add man page for tunnel interfaces
Signed-off-by: Maximilian Wilhelm <max@sdn.clinic>
2021-06-03 18:53:36 +02:00
Maximilian Wilhelm
73d9788fab tunnel executore: Add support for setting pmtudisc / ignore-df for tunnels.
Signed-off-by: Maximilian Wilhelm <max@sdn.clinic>
2021-06-03 18:53:25 +02:00
Maximilian Wilhelm
2b358fafc6 tunnel executor: Add support for tunnel-local-dev option
The new "tunnel-local-dev <iface>" option allows to specify an interface
  to read the IPv4/IPv6 address from which should be used as "tunnel-local"
  address.  The address family is determined based on the given "tunnel-mode".

Closes #118

Signed-off-by: Maximilian Wilhelm <max@sdn.clinic>
2021-06-03 18:53:06 +02:00
Ariadne Conill
9467f85067 multicall: fix handling of -X options, closes #155 2021-06-01 10:31:06 -06:00
Ariadne Conill
6175961880
Merge pull request #152 from BarbarossaTM/chore/docs
doc: Clarify some interface file properties
2021-05-16 19:29:27 -08:00
Maximilian Wilhelm
c8a05a742b doc: Clarify some interface file properties
* Interface file is case-sensitive and all lower-case
 * Clariry netmask handling and fallback

Signed-off-by: Maximilian Wilhelm <max@sdn.clinic>
2021-05-16 17:59:24 +02:00
Ariadne Conill
d4907af84f ifupdown-ng 0.11.2. 2021-04-22 01:45:29 -06:00
Ariadne Conill
98241f4781
Merge pull request #150 from ifupdown-ng/feature/use-ip-addr-flush
static: use ip addr|route flush instead of manually deleting matching routes
2021-04-21 23:44:30 -08:00
Ariadne Conill
aee2d45e18 static: use ip addr|route flush instead of manually deleting matching routes
This ensures we wind up with a clean slate for the interface or VRF when taking
interfaces/VRFs down.

Closes #149.
2021-04-22 01:43:12 -06:00
Ariadne Conill
5860882ffb ifupdown-ng 0.11.1. 2021-04-07 09:39:44 -06:00
Ariadne Conill
0755f7c32d tests: add regression test for #148 2021-04-07 09:38:31 -06:00
Ariadne Conill
bd319a9166 interface-file: adjust the special handling for hostname properties to use dhcp-hostname
closes #148
2021-04-07 09:30:56 -06:00
Ariadne Conill
58b1cf1021 interface: automatic dhcp-hostname determination: use dhcp-hostname instead of legacy hostname property 2021-04-07 09:30:21 -06:00
Ariadne Conill
02bc14da19 interface-file: fix mapping of leasetime to dhcp-leasetime 2021-04-07 09:21:41 -06:00
Ariadne Conill
279d3818b0 ifupdown-ng 0.11.0. 2021-04-03 14:05:13 -06:00
Maximilian Wilhelm
f3f8164ef1
Merge pull request #140 from BarbarossaTM/feature/mpls
Add support for MPLS on Linux
2021-03-30 23:37:04 +02:00
Maximilian Wilhelm
667943f46c Add support for MPLS on Linux
Closes #135

Signed-off-by: Maximilian Wilhelm <max@sdn.clinic>
2021-03-30 23:29:52 +02:00
Maximilian Wilhelm
5b7f5b712b doc: Add references to forward and wifi man page
Signed-off-by: Maximilian Wilhelm <max@sdn.clinic>
2021-03-30 23:21:31 +02:00
Ariadne Conill
381c0ed1a5
Merge pull request #147 from BarbarossaTM/feature/tunnel
Add support for gretap tunnels over IPv6 networks
2021-03-25 18:10:31 -08:00
Maximilian Wilhelm
bec5fcefce tunnel executor: Add support for ip6gretap tunnels
Signed-off-by: Maximilian Wilhelm <max@sdn.clinic>
2021-03-25 21:17:05 +01:00
Maximilian Wilhelm
258d397d84
Merge pull request #146 from BarbarossaTM/chore/tests
Add test for bond executor
2021-03-24 15:10:02 +01:00
Maximilian Wilhelm
cea9840651 Add tests for bond executor
Signed-off-by: Maximilian Wilhelm <max@sdn.clinic>
2021-03-24 15:06:22 +01:00
Maximilian Wilhelm
e88a6b7e10 bond executor: Fix bond param regex
Signed-off-by: Maximilian Wilhelm <max@sdn.clinic>
2021-03-24 14:42:33 +01:00
Ariadne Conill
9faa988326
Merge pull request #144 from BarbarossaTM/fix/tunnels
tunnel executor: Make sure mode/type is 1st parameter
2021-03-21 19:49:10 -08:00
Maximilian Wilhelm
5f9ba7e246
Merge pull request #145 from BarbarossaTM/fix/executors
Makefile: Install all executors, sort them alphabetically
2021-03-21 20:13:31 +01:00
Maximilian Wilhelm
cd98102e62 Makefile: Install all executors, sort them alphabetically
Signed-off-by: Maximilian Wilhelm <max@sdn.clinic>
2021-03-21 20:11:01 +01:00
Maximilian Wilhelm
98b23370e8 gitignore: Add ifprase
Signed-off-by: Maximilian Wilhelm <max@sdn.clinic>
2021-03-21 02:37:12 +01:00
Maximilian Wilhelm
876a7700d7 interface-file: Map 'key' to 'tunnel-key'
Signed-off-by: Maximilian Wilhelm <max@sdn.clinic>
2021-03-21 02:35:25 +01:00
Maximilian Wilhelm
2cec4ed05c tunnel executor: Make sure mode/type is 1st parameter
Closes #143

Signed-off-by: Maximilian Wilhelm <max@sdn.clinic>
2021-03-18 20:20:01 +01:00
Erik Kooistra
e4fa275067 command: Added mandatory permissions for O_CREAT 2020-12-21 15:58:24 -07:00
Erik Kooistra
4c64b5138b libifupdown: Fixed bug where end pointer is not updated after realloc 2020-12-21 15:58:24 -07:00
Maximilian Wilhelm
1ee485666f
Merge pull request #139 from ifupdown-ng/feature/forward-executor
Feature/forward executor
2020-12-16 14:54:22 +01:00
Ariadne Conill
7ef6be6d98 doc: interfaces-forward: document the 100% no systemd behaviour guarantee 2020-12-16 06:52:43 -07:00
Ariadne Conill
606e98d7bd docs: add interfaces-forward(5) manual page 2020-12-16 06:31:17 -07:00
Ariadne Conill
ffcf1976b8 tests: add tests for forward executor 2020-12-16 06:23:38 -07:00
Ariadne Conill
1c2fddfbaa executor-scripts: add forward executor 2020-12-16 06:13:29 -07:00
Ariadne Conill
71bc4b3dc9
Merge pull request #137 from ifupdown-ng/fix/dhclient-executor-args
dhcp executor: Pass correct arguments to dhclient
2020-12-14 18:33:36 -07:00
A. Wilcox
b9d6c190e4
dhcp executor: Pass correct arguments to dhclient
They are opt-args, not pop-tarts.
2020-12-14 11:23:59 -06:00
Ariadne Conill
31bc5c3b10 multicall: remove bug report link from multicall help text 2020-12-04 01:02:28 -07:00
Ariadne Conill
f34ad12751 multicall: a little bit of polishing 2020-12-04 00:55:04 -07:00
Ariadne Conill
27c10c57d1 ifctrstat: lowercase the applet description 2020-12-04 00:51:35 -07:00
Ariadne Conill
d1286e57f9 multicall: print applet descriptions 2020-12-04 00:50:19 -07:00
Ariadne Conill
65aa268e9d ifquery: use single printf call for graphviz header, saves 16 bytes 2020-12-04 00:37:02 -07:00
Ariadne Conill
1f7fe26dd9 version: use printf() with a static string, compiler changes this into puts() automatically, saves additional 20 bytes 2020-12-04 00:31:53 -07:00
Ariadne Conill
3734aaecbd version: use a single printf() call for the entire about text, saves 104 bytes on aarch64 2020-12-04 00:26:01 -07:00
Ariadne Conill
8a8f56dda8 version: remove newline between copyright statements 2020-12-04 00:14:20 -07:00
Maximilian Wilhelm
bed0b67583
Merge pull request #134 from ifupdown-ng/feature/wifi-executor
wifi executor
2020-12-04 07:19:21 +01:00
Maximilian Wilhelm
383ae31372 wifi executor: And some sanity checks to stopping wpa_supplicant
Signed-off-by: Maximilian Wilhelm <max@sdn.clinic>
2020-12-04 07:01:47 +01:00
Ariadne Conill
d7cc2a9917 doc: interfaces: clarify that both wireless-tools and wpa_supplicant are needed for full functionality 2020-12-03 04:58:45 -07:00
Ariadne Conill
93c8827205 wifi executor: fix up some shell nitpicks 2020-12-03 04:56:47 -07:00
Ariadne Conill
589a1f3023 docs: interfaces-wifi: add manpage xrefs for iwconfig(8) and wpa_supplicant(8). 2020-12-02 19:29:22 -07:00
Ariadne Conill
4e3a4c6cb8 wifi executor: add support for insecure wifi networks 2020-12-02 19:27:28 -07:00
Ariadne Conill
eeb40937fb doc: document the wifi executor as interfaces-wifi(5). 2020-12-02 18:48:57 -07:00
Ariadne Conill
b2f5a62c35 wifi executor: protect against unintentionally clobbering $IF_WIFI_CONFIG_PATH 2020-12-02 18:31:39 -07:00
Ariadne Conill
f77d3558f7 executors: add wifi executor 2020-12-02 18:29:05 -07:00
Ariadne Conill
cef4fafdb9
Merge pull request #129 from BarbarossaTM/feature/dhcp-config
Rename dhcp related interface options to dhcp-* and allow interface specific config file
2020-12-02 11:57:19 -07:00
Ariadne Conill
3d47b34d7a
Merge pull request #133 from ifupdown-ng/feature/smart-stanza-merging
improve stanza merging by rewriting address properties as CIDR
2020-12-02 11:50:15 -07:00
Ariadne Conill
b10094eae7 tests: ifquery: add tests to verify stanza merging works as expected 2020-12-02 11:42:45 -07:00
Ariadne Conill
c4d9d6fd06 interface: add lif_interface_finalize() which rewrites addresses as CIDR when an interface stanza ends 2020-12-02 11:38:39 -07:00
Ariadne Conill
0dd7756df2 tests: add fixture illustrating how smart stanza merging should work 2020-12-02 11:17:41 -07:00
Ariadne Conill
43159fec82
Merge pull request #132 from ifupdown-ng/bugfix/ipv6-default-netmask
fix ipv6 default netmask
2020-12-02 11:07:12 -07:00
Ariadne Conill
259851a829 interface: fix default netmask size for AF_INET6 addresses (closes #130) 2020-12-02 11:05:40 -07:00
Ariadne Conill
e1fb4c6087 tests: ifquery: add tests for checking the default netmasks 2020-12-02 10:59:40 -07:00
Maximilian Wilhelm
ff8e5d392c dhcp: Fix test
Signed-off-by: Maximilian Wilhelm <max@sdn.clinic>
2020-11-30 22:38:55 +01:00
Maximilian Wilhelm
b21cb37df0 dhcp: Pass given config file to dhclient, if present
Signed-off-by: Maximilian Wilhelm <max@sdn.clinic>
2020-11-30 22:38:32 +01:00
Maximilian Wilhelm
aada42795c DHCP: Rename options to dhcp-*
Signed-off-by: Maximilian Wilhelm <max@sdn.clinic>
2020-11-30 22:36:28 +01:00
Ariadne Conill
6730db5468
Merge pull request #127 from ifupdown-ng/bugfix/multicall-getopt
multicall: fix inappropriate use of getopt in the multicall stub
2020-11-19 03:33:19 -07:00
Ariadne Conill
7911944633 tests: add getopt regression test for multicall stub 2020-11-19 03:28:51 -07:00
Ariadne Conill
46bb0565fa multicall: do not call getopt_long() inside the stub applet 2020-11-19 03:18:23 -07:00
Maximilian Wilhelm
9715b41c28
Merge pull request #125 from ifupdown-ng/feature/ifparse
YAML output support
2020-11-14 19:10:55 +01:00
Ariadne Conill
89b96a5108 doc: ifparse: chase --yaml-raw -> -F yaml-raw change 2020-11-13 21:53:41 -07:00
Ariadne Conill
545c3870ab ifparse: use -F to select output format instead of individual output options 2020-11-13 21:53:36 -07:00
Ariadne Conill
d2a75c7bb4 yaml-writer: constify 2020-11-13 21:35:12 -07:00
Ariadne Conill
dd8064142c yaml-writer: add ability to enable/disable type annotations 2020-11-13 21:31:48 -07:00
Ariadne Conill
3bf406bf92 doc: add ifparse manual page 2020-11-12 02:28:02 -07:00
Ariadne Conill
c5520f95dd ifparse: fix usage example 2020-11-12 02:22:25 -07:00
Ariadne Conill
7ca5305063 makefile: enabling YAML costs 2KB 2020-11-11 03:25:54 -07:00
Ariadne Conill
8097d5015f ifparse: if interface marked as auto, add "auto: !!bool true" to YAML output 2020-11-11 03:13:32 -07:00
Ariadne Conill
dbfebbff87 YAML: add support for booleans 2020-11-11 03:11:48 -07:00
Ariadne Conill
5010dce3d5 ifparse: rename --yaml to --yaml-raw 2020-11-11 03:10:50 -07:00
Ariadne Conill
95f0ea4895 yaml writer: implement type hinting 2020-11-11 02:51:24 -07:00
Ariadne Conill
2ec3a39c89 ifparse: add --yaml flag 2020-11-11 02:50:29 -07:00
Ariadne Conill
cfb43e9573 add really basic yaml document graph building and writing functionality 2020-11-11 02:46:28 -07:00
Ariadne Conill
fe1664d311 list: fix LIF_LIST_FOREACH_SAFE() iteration on empty lists 2020-11-11 02:18:04 -07:00
Ariadne Conill
ec6077f26f build: add CONFIG_YAML 2020-11-10 20:08:35 -07:00
Ariadne Conill
2a9ca329ff ifparse: add skeleton 2020-11-10 20:02:07 -07:00
Ariadne Conill
f6ad65d99e cmd: split out /e/n/i pretty printer from ifquery.c 2020-11-10 19:42:09 -07:00
Ariadne Conill
d250ab213c
Merge pull request #122 from ifupdown-ng/feature/configure-auto-executor-selection
Feature/configure auto executor selection
2020-11-04 21:53:42 -07:00
Ariadne Conill
f5fc3a3c1a ADMIN-GUIDE: document auto_executor_selection 2020-11-04 21:52:27 -07:00
Maximilian Wilhelm
748a226786
Merge pull request #124 from ifupdown-ng/feature/ifquery-virtual
Feature/ifquery virtual
2020-11-04 20:40:56 +01:00
Ariadne Conill
c8dad76fe1 tests: ifquery: add testcases for ifquery -U 2020-11-04 12:23:14 -07:00
Ariadne Conill
c7eeef27a4 ifquery.8: document -U/--allow-undefined 2020-11-04 11:59:19 -07:00
Ariadne Conill
52f739c943 ifquery: implement support for -U/--allow-undefined 2020-11-04 11:55:36 -07:00
Ariadne Conill
71d832cceb
Merge pull request #123 from ifupdown-ng/chore/narrow-dhcp-hostname-configuration
interface: learn hostname from uname(2) only if an interface requests…
2020-11-04 11:47:24 -07:00
Ariadne Conill
632af7b716 interface: learn hostname from uname(2) only if an interface requests the dhcp executor
Closes #74.
2020-11-04 11:46:18 -07:00
Ariadne Conill
af25cedf33 interfaces: note automatic executor selection algorithm here too (closes #117) 2020-11-04 11:31:08 -07:00
Ariadne Conill
c292297396 interfaces: s/option/executor/ 2020-11-04 11:27:41 -07:00
Ariadne Conill
5667b6adec ifupdown-ng.5: document auto_executor_selection and selection algorithm 2020-11-04 11:24:20 -07:00
Ariadne Conill
2d2e73b8ac example config: document auto_executor_selection setting 2020-11-04 11:21:42 -07:00
Ariadne Conill
068f464e4c interface-file: if auto_executor_selection is disabled, don't guess what executors should be used 2020-11-04 11:18:40 -07:00
Ariadne Conill
0050995b64 config-file: add support for auto_executor_selection setting 2020-11-04 11:16:47 -07:00
Ariadne Conill
20d9e3fe91 executors: drop set -e, closes #121 2020-11-02 08:53:30 -07:00
Maximilian Wilhelm
b76981e832
Merge pull request #120 from ifupdown-ng/chore/document-ifstate
docs: document ifstate
2020-10-26 16:31:50 +01:00
Ariadne Conill
8cae485ca7 docs: document ifstate 2020-10-24 09:00:26 -06:00
Ariadne Conill
6cadc44183 CI: install scdoc 2020-10-24 08:43:51 -06:00
Ariadne Conill
da751ce14d CI: enable CI tests for documentation 2020-10-24 08:42:26 -06:00
Ariadne Conill
dcbb3be15b doc: ifupdown-ng.conf.scd: escape the asterisk in compat_* 2020-10-24 08:40:49 -06:00
Ariadne Conill
19a5a671eb
Merge pull request #111 from ifupdown-ng/feature/deprecate-brctl
vlan aware bridging
2020-10-22 13:42:00 -08:00
Ariadne Conill
90453f1412
Merge pull request #119 from ifupdown-ng/feature/explicit-guard
guard auto and explicitly configured interfaces from inappropriate deconfiguration
2020-10-21 07:15:03 -08:00
Ariadne Conill
b4f87cbd1e state: explicitly check for explicit keyword when loading from the ifstate file 2020-10-21 09:13:34 -06:00
Ariadne Conill
2a8a72eee7 ifupdown: upgrade dependent interfaces to explicit interfaces if explicitly requested 2020-10-21 08:46:47 -06:00
Ariadne Conill
eb9bebebc6 ifupdown: record explicitly configured interfaces as explicit in ifstate 2020-10-21 08:42:47 -06:00
Ariadne Conill
61097b1db2 ifquery: when querying state, denote presence of the explicit flag 2020-10-21 08:32:29 -06:00
Ariadne Conill
b09d622cfc state: synchronize is_explicit from state records to parsed interface collections 2020-10-21 08:30:35 -06:00
Ariadne Conill
dae7d59864 state: write and restore explicit flag from ifstate 2020-10-21 08:29:54 -06:00
Ariadne Conill
4f7063ba0f state: add lif_state_record::is_explicit 2020-10-21 08:15:52 -06:00
Ariadne Conill
817262fa33 lifecycle: skip parent interfaces marked as explicitly configured when going down
these interfaces will be taken down by ifdown itself when appropriate
2020-10-21 08:11:45 -06:00
Ariadne Conill
b201f351ec interface: auto interfaces are always explicit 2020-10-21 08:09:21 -06:00
Ariadne Conill
9bcf914250 interface: add lif_interface::is_explicit 2020-10-21 08:06:59 -06:00
Maximilian Wilhelm
c810cd5817 doc: Add ifupdown-ng.conf(5) man page on global options.
Signed-off-by: Maximilian Wilhelm <max@sdn.clinic>
2020-10-18 23:43:17 +02:00
Maximilian Wilhelm
e5d9ee25fc doc: Update bridge man page on vlan-aware options.
Signed-off-by: Maximilian Wilhelm <max@sdn.clinic>
2020-10-18 23:25:42 +02:00
Maximilian Wilhelm
02a74985ab bridge: Rework vlan handling
Signed-off-by: Maximilian Wilhelm <max@sdn.clinic>
2020-10-18 21:29:50 +02:00
Maximilian Wilhelm
fb1d3181fe bridge: STP option for iproute2 has to be 0 or 1.
Signed-off-by: Maximilian Wilhelm <max@sdn.clinic>
2020-10-18 21:28:10 +02:00
Maximilian Wilhelm
ab7b1f5d24 compat: Fix build failure.
Signed-off-by: Maximilian Wilhelm <max@sdn.clinic>
2020-10-18 05:36:45 +02:00
Maximilian Wilhelm
480fc5eecb compat: Only create interface when configured to do so.
Add config option <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.

Signed-off-by: Maximilian Wilhelm <max@sdn.clinic>
2020-10-18 05:14:03 +02:00
Maximilian Wilhelm
d86297f29c compat: Add glue for ifupdown2 bridge port VLAN inheritance.
Add config options <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.

Signed-off-by: Maximilian Wilhelm <max@sdn.clinic>
2020-10-18 04:58:23 +02:00
Maximilian Wilhelm
56beefdd28 ifquery: Apply compatibility glue, too.
Signed-off-by: Maximilian Wilhelm <max@sdn.clinic>
2020-10-18 04:57:24 +02:00
Maximilian Wilhelm
a5761afd70 bridge: Remove fall back to IF_REQUIRES
Signed-off-by: Maximilian Wilhelm <max@sdn.clinic>
2020-10-18 03:28:20 +02:00
Ariadne Conill
05a3b1539b bridge: add support for bridge-vids (with inheritance), bridge-access and bridge-pvid 2020-10-18 03:28:20 +02:00
Ariadne Conill
03528b01ad bridge: remove hack for alpine vlan scripts (not relevant to us) 2020-10-18 03:28:20 +02:00
Ariadne Conill
3d743f512f bridge: add support for bridge-vlan-aware in iproute2 mode 2020-10-18 03:28:20 +02:00
Ariadne Conill
6c5d856ac4 bridge: remove support for gcint (noop in modern kernels), use iproute2 commands for all bridge configuration if present 2020-10-18 03:28:20 +02:00
Ariadne Conill
36eb6e3377 bridge: check if iproute2 is available and use it to configure bridge options 2020-10-18 03:28:20 +02:00
Ariadne Conill
e7ee26ac19 bridge: use iproute commands to create and assign bridge ports 2020-10-18 03:28:20 +02:00
Maximilian Wilhelm
80a590ca33
Merge pull request #114 from BarbarossaTM/feature/compatiblity-layer
Introduce compatibility layer framework
2020-10-18 03:27:46 +02:00
Maximilian Wilhelm
d96f579d7f Introduce an compatibility layer which is empty for now.
Signed-off-by: Maximilian Wilhelm <max@sdn.clinic>
2020-10-18 03:26:40 +02:00
84 changed files with 2702 additions and 338 deletions

View file

@ -10,7 +10,7 @@ jobs:
- name: Update system and add dependencies
run: |
apk upgrade -Ua
apk add build-base git kyua atf
apk add build-base git kyua atf scdoc
- name: Checkout
uses: actions/checkout@v2
@ -18,5 +18,8 @@ jobs:
- name: Build
run: make
- name: Build documentation
run: make docs
- name: Run tests
run: make check

1
.gitignore vendored
View file

@ -13,4 +13,5 @@ ifquery
ifup
ifdown
ifctrstat
ifparse
*.lock

View file

@ -1,4 +1,5 @@
Copyright (c) 2020 Ariadne Conill <ariadne@dereferenced.org>
Copyright (c) 2020-2021 Ariadne Conill <ariadne@dereferenced.org>
Copyright (c) 2020-2021 Maximilian Wilhelm <max@sdn.clinic>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above

View file

@ -4,7 +4,7 @@ LIBBSD_CFLAGS =
LIBBSD_LIBS =
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
@ -14,7 +14,8 @@ CONFIG_FILE := /etc/network/ifupdown-ng.conf
EXECUTOR_PATH := /usr/libexec/ifupdown-ng
CFLAGS ?= -ggdb3 -Os
CFLAGS += -Wall -Wextra
CFLAGS += -Wall -Wextra -Werror
CFLAGS += -Wmissing-declarations -Wmissing-prototypes -Wcast-align -Wpointer-arith -Wreturn-type
CFLAGS += ${LIBBSD_CFLAGS}
CPPFLAGS = -I.
CPPFLAGS += -DINTERFACES_FILE=\"${INTERFACES_FILE}\"
@ -38,8 +39,8 @@ LIBIFUPDOWN_SRC = \
libifupdown/execute.c \
libifupdown/lifecycle.c \
libifupdown/config-parser.c \
libifupdown/config-file.c
libifupdown/config-file.c \
libifupdown/compat.c
LIBIFUPDOWN_OBJ = ${LIBIFUPDOWN_SRC:.c=.o}
LIBIFUPDOWN_LIB = libifupdown.a
@ -47,7 +48,8 @@ MULTICALL_SRC = \
cmd/multicall.c \
cmd/multicall-options.c \
cmd/multicall-exec-options.c \
cmd/multicall-match-options.c
cmd/multicall-match-options.c \
cmd/pretty-print-iface.c
MULTICALL_OBJ = ${MULTICALL_SRC:.c=.o}
MULTICALL = ifupdown
@ -73,6 +75,22 @@ MULTICALL_${CONFIG_IFCTRSTAT}_OBJ += ${IFCTRSTAT_SRC:.c=.o}
CMDS_${CONFIG_IFCTRSTAT} += ifctrstat
CPPFLAGS_${CONFIG_IFCTRSTAT} += -DCONFIG_IFCTRSTAT
# enable ifparse applet (+1 KB)
CONFIG_IFPARSE ?= Y
IFPARSE_SRC = cmd/ifparse.c
MULTICALL_${CONFIG_IFPARSE}_OBJ += ${IFPARSE_SRC:.c=.o}
CMDS_${CONFIG_IFPARSE} += ifparse
CPPFLAGS_${CONFIG_IFPARSE} += -DCONFIG_IFPARSE
# enable YAML support (+2 KB)
CONFIG_YAML ?= Y
YAML_SRC = \
libifupdown/yaml-base.c \
libifupdown/yaml-writer.c
LIBIFUPDOWN_${CONFIG_YAML}_OBJ += ${YAML_SRC:.c=.o}
CPPFLAGS_${CONFIG_YAML} += -DCONFIG_YAML
LIBIFUPDOWN_OBJ += ${LIBIFUPDOWN_Y_OBJ}
MULTICALL_OBJ += ${MULTICALL_Y_OBJ}
CMDS += ${CMDS_Y}
CPPFLAGS += ${CPPFLAGS_Y}
@ -82,21 +100,28 @@ EXECUTOR_SCRIPTS_CORE ?= \
ipv6-ra \
static \
link \
ppp
ppp \
forward
EXECUTOR_SCRIPTS_OPT ?= \
batman \
bond \
bridge \
vrf \
tunnel \
gre \
wireguard \
ethtool \
batman
gre \
mpls \
tunnel \
vrf \
vxlan \
wifi \
wireguard
EXECUTOR_SCRIPTS ?= ${EXECUTOR_SCRIPTS_CORE} ${EXECUTOR_SCRIPTS_OPT}
EXECUTOR_SCRIPTS_STUB ?=
EXECUTOR_SCRIPTS_NATIVE ?=
TARGET_LIBS = ${LIBIFUPDOWN_LIB}
LIBS += ${TARGET_LIBS} ${LIBBSD_LIBS}
@ -131,19 +156,27 @@ install: all
for i in ${EXECUTOR_SCRIPTS_STUB}; do \
install -D -m755 executor-scripts/stub/$$i ${DESTDIR}${EXECUTOR_PATH}/$$i; \
done
for i in ${EXECUTOR_SCRIPTS_NATIVE}; do \
install -D -m755 executor-scripts/${LAYOUT}-native/$$i ${DESTDIR}${EXECUTOR_PATH}/$$i; \
done
install -D -m644 dist/ifupdown-ng.conf.example ${DESTDIR}${CONFIG_FILE}.example
.scd.1 .scd.2 .scd.3 .scd.4 .scd.5 .scd.6 .scd.7 .scd.8:
${SCDOC} < $< > $@
MANPAGES_5 = \
doc/ifstate.5 \
doc/ifupdown-ng.conf.5 \
doc/interfaces.5 \
doc/interfaces-bond.5 \
doc/interfaces-batman.5 \
doc/interfaces-bridge.5 \
doc/interfaces-forward.5 \
doc/interfaces-ppp.5 \
doc/interfaces-tunnel.5 \
doc/interfaces-vrf.5 \
doc/interfaces-vxlan.5 \
doc/interfaces-wifi.5 \
doc/interfaces-wireguard.5
MANPAGES_7 = \
@ -153,7 +186,8 @@ MANPAGES_8 = \
doc/ifquery.8 \
doc/ifup.8 \
doc/ifdown.8 \
doc/ifctrstat.8
doc/ifctrstat.8 \
doc/ifparse.8
MANPAGES = ${MANPAGES_5} ${MANPAGES_7} ${MANPAGES_8}

View file

@ -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 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
the documentation requires scdoc (`apk add scdoc` / `apt install scdoc`).
## Discussion
Discuss ifupdown-ng on IRC: irc.as7007.net #ifupdown-ng
Discuss ifupdown-ng on IRC: irc.oftc.net #ifupdown-ng

View file

@ -17,7 +17,8 @@
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include "multicall.h"
#include "cmd/multicall.h"
#include "cmd/ifctrstat-linux.h"
struct counter_desc {
const char *name;
@ -41,7 +42,7 @@ counter_compare(const void *key, const void *candidate)
return strcasecmp((const char *)key, ((struct counter_desc *)candidate)->name);
}
char *
const char *
read_counter(const char *interface, const char *counter)
{
FILE *fp;

22
cmd/ifctrstat-linux.h Normal file
View 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

View file

@ -20,12 +20,11 @@
#include <string.h>
#include "libifupdown/libifupdown.h"
#include "cmd/multicall.h"
#include "cmd/ifctrstat-linux.h"
extern struct counter_desc { const char *name; const void *data; } avail_counters[];
extern int avail_counters_count;
extern const char *read_counter(const char *interface, const char *counter);
static bool show_label = true;
static bool
@ -96,7 +95,7 @@ ifctrstat_set_nolabel(const char *opt_arg)
show_label = false;
}
int
static int
ifctrstat_main(int argc, char *argv[])
{
if (optind >= argc)
@ -152,7 +151,7 @@ static struct if_option_group local_option_group = {
struct if_applet ifctrstat_applet = {
.name = "ifctrstat",
.desc = "Display statistics about an interface",
.desc = "display statistics about an interface",
.main = ifctrstat_main,
.usage = "ifctrstat [options] <interface> <counter>\n ifctrstat [options] --list",
.manpage = "8 ifctrstat",

224
cmd/ifparse.c Normal file
View 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 },
};

View file

@ -20,44 +20,9 @@
#include <getopt.h>
#include "libifupdown/libifupdown.h"
#include "cmd/multicall.h"
#include "cmd/pretty-print-iface.h"
void
print_interface(struct lif_interface *iface)
{
if (!lif_lifecycle_query_dependents(&exec_opts, iface, iface->ifname))
return;
if (iface->is_auto)
printf("auto %s\n", iface->ifname);
printf("%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
static void
print_interface_dot(struct lif_dict *collection, struct lif_interface *iface, struct lif_interface *parent)
{
if (!lif_lifecycle_query_dependents(&exec_opts, iface, iface->ifname))
@ -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)
{
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)
{
struct lif_node *iter;
if (opts->dot)
{
printf("digraph interfaces {\n");
printf("edge [color=blue fontname=Sans fontsize=10]\n");
printf("node [fontname=Sans fontsize=10]\n");
printf("digraph interfaces {\n"
"edge [color=blue fontname=Sans fontsize=10]\n"
"node [fontname=Sans fontsize=10]\n");
}
LIF_DICT_FOREACH(iter, collection)
@ -147,7 +112,7 @@ list_interfaces(struct lif_dict *collection, struct match_options *opts)
continue;
if (opts->pretty_print)
print_interface(iface);
prettyprint_interface_eni(iface);
else if (opts->dot)
print_interface_dot(collection, iface, NULL);
else
@ -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 allow_undefined = false;
void
static void
list_state(struct lif_dict *state, struct match_options *opts)
{
struct lif_node *iter;
@ -182,7 +148,8 @@ list_state(struct lif_dict *state, struct match_options *opts)
if (listing_running)
printf("%s\n", entry->key);
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;
}
static void
set_allow_undefined(const char *opt_arg)
{
(void) opt_arg;
allow_undefined = true;
}
static struct if_option local_options[] = {
{'r', "running", NULL, "show configured (running) interfaces", false, set_show_running},
{'s', "state", NULL, "show configured state", false, set_show_state},
@ -234,6 +208,7 @@ static struct if_option local_options[] = {
{'D', "dot", NULL, "generate a dependency graph", false, set_output_dot},
{'L', "list", NULL, "list matching interfaces", false, set_listing},
{'P', "pretty-print", NULL, "pretty print the interfaces instead of just listing", false, set_pretty_print},
{'U', "allow-undefined", NULL, "allow querying undefined (virtual) interfaces", false, set_allow_undefined},
};
static struct if_option_group local_option_group = {
@ -242,7 +217,7 @@ static struct if_option_group local_option_group = {
.group = local_options
};
int
static int
ifquery_main(int argc, char *argv[])
{
struct lif_dict state = {};
@ -271,6 +246,12 @@ ifquery_main(int argc, char *argv[])
return EXIT_FAILURE;
}
if (!lif_compat_apply(&collection))
{
fprintf(stderr, "%s: failed to apply compatibility glue\n", argv0);
return EXIT_FAILURE;
}
/* --list --state is not allowed */
if (listing && (listing_stat || listing_running))
generic_usage(self_applet, EXIT_FAILURE);
@ -300,6 +281,9 @@ ifquery_main(int argc, char *argv[])
if (entry != NULL)
iface = entry->data;
if (entry == NULL && allow_undefined)
iface = lif_interface_collection_find(&collection, argv[idx]);
}
if (iface == NULL)
@ -311,7 +295,7 @@ ifquery_main(int argc, char *argv[])
if (match_opts.property != NULL)
print_interface_property(iface, match_opts.property);
else
print_interface(iface);
prettyprint_interface_eni(iface);
}
return EXIT_SUCCESS;

View file

@ -27,7 +27,7 @@
static bool up;
bool
static bool
is_ifdown()
{
if (strstr(argv0, "ifdown") != NULL)
@ -36,7 +36,7 @@ is_ifdown()
return false;
}
int
static int
acquire_state_lock(const char *state_path, const char *lifname)
{
if (exec_opts.mock || exec_opts.no_lock)
@ -46,7 +46,7 @@ acquire_state_lock(const char *state_path, const char *lifname)
snprintf(lockpath, sizeof lockpath, "%s.%s.lock", state_path, lifname);
int fd = open(lockpath, O_CREAT | O_WRONLY | O_TRUNC);
int fd = open(lockpath, O_CREAT | O_WRONLY | O_TRUNC, 0600);
if (fd < 0)
{
if (exec_opts.verbose)
@ -94,8 +94,8 @@ acquire_state_lock(const char *state_path, const char *lifname)
return fd;
}
bool
skip_interface(struct lif_interface *iface, const char *ifname)
static bool
skip_interface(struct lif_interface *iface, const char *ifname, struct lif_dict *state, bool update_state)
{
if (iface->is_template)
{
@ -123,24 +123,31 @@ skip_interface(struct lif_interface *iface, const char *ifname)
if (up && iface->refcount > 0)
{
if (exec_opts.verbose)
fprintf(stderr, "%s: skipping auto interface %s (already configured), use --force to force configuration\n",
argv0, ifname);
fprintf(stderr, "%s: skipping %sinterface %s (already configured), use --force to force configuration\n",
argv0, iface->is_auto ? "auto " : "", ifname);
if (update_state)
{
iface->is_explicit = true;
lif_state_upsert(state, ifname, iface);
}
return true;
}
if (!up && iface->refcount == 0)
{
if (exec_opts.verbose)
fprintf(stderr, "%s: skipping auto interface %s (already deconfigured), use --force to force deconfiguration\n",
argv0, ifname);
fprintf(stderr, "%s: skipping %sinterface %s (already deconfigured), use --force to force deconfiguration\n",
argv0, iface->is_auto ? "auto " : "", ifname);
return true;
}
return false;
}
bool
change_interface(struct lif_interface *iface, struct lif_dict *collection, struct lif_dict *state, const char *ifname)
static bool
change_interface(struct lif_interface *iface, struct lif_dict *collection, struct lif_dict *state, const char *ifname, bool update_state)
{
int lockfd = acquire_state_lock(exec_opts.state_file, ifname);
@ -150,7 +157,7 @@ change_interface(struct lif_interface *iface, struct lif_dict *collection, struc
return false;
}
if (skip_interface(iface, ifname))
if (skip_interface(iface, ifname, state, update_state))
{
if (lockfd != -1)
close(lockfd);
@ -178,10 +185,16 @@ change_interface(struct lif_interface *iface, struct lif_dict *collection, struc
if (lockfd != -1)
close(lockfd);
if (up && update_state)
{
iface->is_explicit = true;
lif_state_upsert(state, ifname, iface);
}
return true;
}
bool
static bool
change_auto_interfaces(struct lif_dict *collection, struct lif_dict *state, struct match_options *opts)
{
struct lif_node *iter;
@ -202,14 +215,14 @@ change_auto_interfaces(struct lif_dict *collection, struct lif_dict *state, stru
fnmatch(opts->include_pattern, iface->ifname, 0))
continue;
if (!change_interface(iface, collection, state, iface->ifname))
if (!change_interface(iface, collection, state, iface->ifname, false))
return false;
}
return true;
}
int
static int
update_state_file_and_exit(int rc, struct lif_dict *state)
{
if (exec_opts.mock)
@ -230,7 +243,7 @@ update_state_file_and_exit(int rc, struct lif_dict *state)
return rc;
}
int
static int
ifupdown_main(int argc, char *argv[])
{
up = !is_ifdown();
@ -261,6 +274,12 @@ ifupdown_main(int argc, char *argv[])
return EXIT_FAILURE;
}
if(!lif_compat_apply(&collection))
{
fprintf(stderr, "%s: failed to apply compatibility glue\n", argv0);
return EXIT_FAILURE;
}
if (!lif_state_sync(&state, &collection))
{
fprintf(stderr, "%s: could not sync state\n", argv0);
@ -307,7 +326,7 @@ ifupdown_main(int argc, char *argv[])
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);
}

View file

@ -21,10 +21,13 @@
#include <getopt.h>
#include "cmd/multicall.h"
#define DEFAULT_TIMEOUT 300
struct lif_execute_opts exec_opts = {
.interfaces_file = INTERFACES_FILE,
.executor_path = EXECUTOR_PATH,
.state_file = STATE_FILE
.state_file = STATE_FILE,
.timeout = DEFAULT_TIMEOUT,
};
static void
@ -74,6 +77,14 @@ set_force(const char *opt_arg)
exec_opts.force = true;
}
static void
set_timeout(const char *opt_arg)
{
exec_opts.timeout = atoi(opt_arg);
if (exec_opts.timeout < 0)
exec_opts.timeout = DEFAULT_TIMEOUT;
}
static struct if_option exec_options[] = {
{'f', "force", NULL, "force (de)configuration", false, set_force},
{'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},
{'E', "executor-path", "executor-path PATH", "use PATH for executor directory", true, set_executor_path},
{'S', "state-file", "state-file FILE", "use FILE for state", true, set_state_file},
{'T', "timeout", "timeout TIMEOUT", "wait TIMEOUT seconds for executors to complete", true, set_timeout},
};
struct if_option_group exec_option_group = {

View file

@ -39,7 +39,7 @@ set_include_pattern(const char *opt_arg)
static void
set_exclude_pattern(const char *opt_arg)
{
match_opts.include_pattern = opt_arg;
match_opts.exclude_pattern = opt_arg;
}
static struct if_option match_options[] = {

View file

@ -36,6 +36,10 @@ extern struct if_applet ifdown_applet;
extern struct if_applet ifctrstat_applet;
#endif
#ifdef CONFIG_IFPARSE
extern struct if_applet ifparse_applet;
#endif
struct if_applet ifupdown_applet;
const struct if_applet *self_applet = NULL;
@ -46,6 +50,9 @@ struct if_applet *applet_table[] = {
#ifdef CONFIG_IFUPDOWN
&ifdown_applet,
#endif
#ifdef CONFIG_IFPARSE
&ifparse_applet,
#endif
#ifdef CONFIG_IFQUERY
&ifquery_applet,
#endif
@ -55,7 +62,7 @@ struct if_applet *applet_table[] = {
&ifupdown_applet,
};
int
static int
applet_cmp(const void *a, const void *b)
{
const char *key = a;
@ -66,6 +73,8 @@ applet_cmp(const void *a, const void *b)
void multicall_usage(int status) __attribute__((noreturn));
struct if_applet ifupdown_applet;
int
main(int argc, char *argv[])
{
@ -85,12 +94,14 @@ main(int argc, char *argv[])
}
self_applet = *app;
process_options(*app, argc, argv);
return (*app)->main(argc, argv);
if (self_applet != &ifupdown_applet)
process_options(*app, argc, argv);
return self_applet->main(argc, argv);
}
int
static int
multicall_main(int argc, char *argv[])
{
if (argc < 2)
@ -99,24 +110,23 @@ multicall_main(int argc, char *argv[])
return main(argc - 1, argv + 1);
}
struct if_applet ifupdown_applet;
void
multicall_usage(int status)
{
fprintf(stderr, "usage: ifupdown <applet> [options]\n");
fprintf(stderr,
PACKAGE_NAME " " PACKAGE_VERSION "\n"
"usage: ifupdown <applet> [options]\n"
"\n"
"Built-in applets:\n");
fprintf(stderr, "\nBuilt-in applets:\n\t");
for (size_t i = 0; i < ARRAY_SIZE(applet_table); i++)
{
if (i != 0)
fprintf(stderr, ", ");
if (applet_table[i] == &ifupdown_applet)
continue;
fprintf(stderr, "%s", applet_table[i]->name);
fprintf(stderr, " %-10s %s\n", applet_table[i]->name, applet_table[i]->desc);
}
fprintf(stderr, "\n");
exit(status);
}

56
cmd/pretty-print-iface.c Normal file
View 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
View 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

View file

@ -17,6 +17,29 @@ allow_addon_scripts = 1
# templates. Valid values are 0 and 1, the default is 1.
allow_any_iface_as_template = 1
# auto_executor_selection:
# Automatically determine which executors are needed to bring up an
# interface. An admin may choose to disable this setting and explicitly
# define which executors to use with `use` statements.
# Valid values are 0 and 1, the default is 1.
auto_executor_selection = 1
# compat_create_interfaces:
# Denotes where or not to create interfaces when compat_* settings are
# active and it would be necessary to create an interface to be fully
# compliant. This could happen when inheriting bridge VLAN settings to
# an interface within a bridges bridge-ports setting but no interface
# stanza is found. Valid values are 0 and 1, the default is 1.
compat_create_interfaces = 1
# compat_ifupdown2_bridge_ports_inherit_vlans:
# In ifupdown2 <bridge-vids> as well as the <bridge-pvid> set on a bridge
# interface will be inherited by all member ports if not set explicitly.
# When set to 1 ifupdown-ng behaves the same way and will internally copy
# both options from the bridge member ports if they are not set on the
# member port. Valid values are 0 and 1, the default is 1.
compat_ifupdown2_bridge_ports_inherit_vlans = 1
# implicit_template_conversion:
# In some legacy configs, a template may be declared as an iface, and
# ifupdown-ng automatically converts those declarations to a proper

View file

@ -60,6 +60,26 @@ Currently the following settings are supported in
in order to require inheritance from specified templates.
Valid values are `0` and `1`, the default is `1`.
* `auto_executor_selection`: Automatically select executors based
on the presence of their config options. An admin may choose to
disable this setting in order to require explicitly enabling
executors through `use` statements. Valid values are `0` and `1`,
the default is `1`.
* `compat_create_interfaces`:
Denotes where or not to create interfaces when compat\_* settings are
active and it would be necessary to create an interface to be fully
compliant. This could happen when inheriting bridge VLAN settings to
an interface within a bridges bridge-ports setting but no interface
stanza is found. Valid values are `0` and `1`, the default is `1`.
* `compat_ifupdown2_bridge_ports_inherit_vlans`: In ifupdown2 `bridge-vids`
as well as the <bridge-pvid> set on a bridge interface will be inherited
by all member ports if not set explicitly. When set to `1` ifupdown-ng
behaves the same way and will internally copy both options from the
bridge member ports if they are not set on the member port.
Valid values are `0` and `1`, the default is `1`.
* `implicit_template_conversion`: In some legacy configs, a template
may be declared as an iface, and ifupdown-ng automatically converts
those declarations to a proper template. If this setting is
@ -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
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).

View file

@ -45,6 +45,10 @@ configured in the configuration database.
*-S, --state-file* _FILE_
Use _FILE_ as the state database.
*-T, --timeout* _TIMEOUT_
Wait up to _TIMEOUT_ seconds for executors to complete before
raising an error.
*-V, --version*
Print the ifupdown-ng version and exit.
@ -54,8 +58,9 @@ configured in the configuration database.
# SEE ALSO
*ifup*(8)++
*ifquery*(8)++
*ifupdown-ng.conf*(5)
*ifup*(8)
*ifquery*(8)
*interfaces*(5)
# AUTHORS

66
doc/ifparse.scd Normal file
View 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>

View file

@ -54,9 +54,18 @@ configuration file to the current format.
When listing interfaces, print their configuration in a format
that is compatible with *interfaces*(5) files.
*-U, --allow-undefined*
Create virtual interfaces for any interfaces not explicitly
defined in the configuration file. This is primarily useful
for property queries.
*-S, --state-file* _FILE_
Use _FILE_ as the state database.
*-T, --timeout* _TIMEOUT_
Wait up to _TIMEOUT_ seconds for executors to complete before
raising an error.
*-V, --version*
Print the ifupdown-ng version and exit.

57
doc/ifstate.scd Normal file
View 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>

View file

@ -48,6 +48,10 @@ configured in the configuration database.
*-S, --state-file* _FILE_
Use _FILE_ as the state database.
*-T, --timeout* _TIMEOUT_
Wait up to _TIMEOUT_ seconds for executors to complete before
raising an error.
*-V, --version*
Print the ifupdown-ng version and exit.
@ -57,8 +61,9 @@ configured in the configuration database.
# SEE ALSO
*ifdown*(8)++
*ifquery*(8)++
*ifupdown-ng.conf*(5)
*ifdown*(8)
*ifquery*(8)
*interfaces*(5)
# AUTHORS

76
doc/ifupdown-ng.conf.scd Normal file
View 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>

View file

@ -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
seen a frame with this source address.
*bridge-vlan-aware* _bool_
Denotes wether or not the bridge should be aware of 802.1q VLANs.
_bool_ can be given as _yes_/_no_ or _0_/_1_. The defaul is _no_.
See related options for configuring vlan-aware bridges, below.
# SPANNING TREE RELATED BRIDGE OPTIONS
*bridge-stp* _state_
@ -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
are between 6 and 40.
# OPTIONS FOR VLAN-AWARE-BRIDGES
The following options only have an effect on vlan-aware bridges and
their ports.
All settings can be applied on the bridge interface itself and all member
port iface stanzas. If applied on the bridge interface they take effect
for the bridge interface itself and might be inherited to _bridge-ports_
depending on the compatibility settings configured in *ifupdown-ng.conf*(5).
Configuring VLAN options on the bridge interface might be required for
setting up a VLAN interface to one of the VLANs carried within the bridge.
See the EXAMPLES section for an example for this scenario.
See *ifupdown-ng.conf*(5) for more information about compatiblity settings
mentioned below.
*bridge-access* _vlan ID_
Configure the given _vlan ID_ for untagged ingress and egress
on this interface. The common description for this kind of
configuration is called "access port".
*bridge-pvid* _vlan ID_
Denotes the _vlan ID_ to considered a PVID at ingress.
Any untagged frames received on this interface will be
assigned to this _vlan ID_. The default PVID is _1_.
If compatibility to ifupdown2 bridge port inheritance is active
a _bridge-pvid_ set on the bridge will be inherited to any
interface configured in _bridge-ports_ without a _bridge-pvid_ set.
*bridge-vids* _list of vlan IDs_
Denotes the space separated list of VLANs to be allowed tagged
ingress/egress on this interface.
If compatibility to ifupdown2 bridge port inheritance is active
a _bridge-vids_ set on the bridge will be inherited to any
interface configured in _bridge-ports_ without _bridge-vids_ set.
*bridge-allow-untagged* _bool_
Denotes wether or not the bridge should allow untagged frames on
ingress as well as egress. If set to _no_ untagged frames will be
droppped on ingress and none will be sent. _bool_ can be given as
_yes_/_no_ or _0_/_1_. The defaul is _yes_.
# EXAMPLES
A simple layer 2 only bridge:
@ -77,10 +127,46 @@ iface br0
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
*ip-link*(8)
*interfaces*(5)
*ifupdown-ng.conf*(5)
*ip-link*(8)
*bridge*(8)
# AUTHORS

View 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
View 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
View 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>

View file

@ -32,26 +32,33 @@ other options are optional.
*vxlan-physdev* _interface_
Specifies the physical ("underlay") device to use for tunnel
endpoint communication.
endpoint communication. This is required for setups using
multicast.
*vxlan-local-ip* _address_
Specifies the source IP address to use in outgoing packets.
For compatiblity with ifupdown2 _vxlan-local-tunnelip_ is an
alias for this parameter.
*vxlan-remote-ip* _address_
Specifies the unicast destination IP address to use in outgoing
*vxlan-peer-ips* _list of IP addresses_
Specifies the unicast destination IP address(es) to use in outgoing
packets when the destination link layer address is not known in
the VXLAN device forwarding database. This parameter cannot be
specified with the _vxlan-remote-group_ parameter.
For compatiblity with ifupdown2 _vxlan-remoteip_ is an alias for
this parameter.
the VXLAN device forwarding database. This option can be used to
form Point-to-Point as well as Point-to-Multipoint VXLAN tunnels/
overlays depending on how many peer IPs are given. If more than one
IP address is given a Point-to-Multipoint overlay is being set up
and ingress / head-end replication will be used by the Linux Kernel.
This option cannot be used together with _vxlan-peer-group_ option.
For compatiblity with ifupdown2 _vxlan-remoteip_ is an alias for this option
and for compatibility with previos versions of ifupdown-ng _vxlan-remote-ip_
is an alias for this option, too.
*vxlan-remote-group* _multicast group_
Specifies the multicast group IP address to join. This parameter
cannot be specified with the _vxlan-remote-ip_ parameter.
For compatibility with ifupdown2 _vxlan-svcnodeip_ is an alias for
this parameter.
*vxlan-peer-group* _multicast group_
Specifies the multicast group address to join, requires _vxlan-phsydev_
to be set as well. This parameter cannot be specified in combination
with the _vxlan-peer-ips_ parameter. For compatibility with ifupdown2
_vxlan-svcnodeip_ is an alias for this option and for compatibility
with previos version of ifupdown-ng _vxlan-remote-group_ is an alias, too.
*vxlan-learning* _on/off_
Specifies if unknown source link layer addresses and IP addresses
@ -79,22 +86,46 @@ iface vx_v1001_padcty
mtu 1560
```
The same works just fine with IPv6 in the underlay:
```
auto vx_v1400_padcty
iface vx_v1400_padcty
vxlan-id 917505
vxlan-physdev vlan1400
vxlan-peer-group ff42:1400::1
#
hwaddress f2:00:0d:01:14:00
mtu 1560
```
Note that the underlay must have an MTU of at least 1610 to
carry the encapsulated packets.
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
iface vx_ptp1
vxlan-id 2342
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
```
A VTEP with multiple peers (unicast point-to-multipoint with ingress / head-end replication):
```
auto vx_her
iface vx_her
vxlan-id 1337
vxlan-local-ip 2001:db8:1::1
vxlan-peer-ips 2001:db8:2::23 2001:db8:3::42 2001:db8:4::84
```
# AUTHORS
Maximilian Wilhelm <max@sdn.clinic>

63
doc/interfaces-wifi.scd Normal file
View 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>

View file

@ -18,6 +18,15 @@ allow to set up Wireguard VPN tunnels.
used. In the latter case _use wireguard_ has to be explicitly
set to the interface configuration.
Be aware that the given configuration file will be loaded using
*wg setconf* and not with *wg-quick*. The file format for both
tools isn't compatible so you have to make sure you provide a
valid configuration file for the *wg* tool. If you already have
a configuration file for *wg-quick* you can set up the tunnel
manually once and then dump the configuration using *wg showconf*
and save this to _path_.
# EXAMPLES
A Wireguard VPN tunnel with explicit configuration file specified

View file

@ -11,7 +11,7 @@ interfaces are configured. The file is processed by *ifquery*(8),
*ifup*(8) and *ifdown*(8) to introspect and change system state.
In most cases, syntax from legacy implementations is supported as
well, but that syntax is not discussed here.
well, but that syntax is not discussed in detail here.
# FILE SYNTAX
@ -24,6 +24,8 @@ value combination that is related to an *object*. Triples which
are not associated with an *object* are considered to be part
of the root of the configuration tree.
All keywords are case-sensitive and are expected to be lower-case.
The following is a simple example of a stanza:
```
@ -64,11 +66,11 @@ the system will only respond to certain keywords by default:
*address* _address_
Associates an IPv4 or IPv6 address in CIDR notation with
the parent interface.
*gateway* _address_
Associates an IPv4 or IPv6 address with the parent interface
for use as a default route (gateway).
the parent interface. If an IP address without a prefix
length is given a given _netmask_ attribute is used if present.
If neither a prefix length nor a _netmask_ are given a /24 or /64
prefix length is presumed for IPv4 / IPv6 as of compatibility
reasons to classic ifupdown.
*netmask* _netmask_
Associates a fallback netmask with the parent interface for
@ -83,6 +85,11 @@ the system will only respond to certain keywords by default:
For compatiblity with ifupdown and ifupdown2, _pointopoint_ is
an alias for this parameter.
*gateway* _address_
Associates an IPv4 or IPv6 address with the parent interface
for use as a default route (gateway). This usually is given
once for IPv4 and once for IPv6 (in a Dual-Stack setup).
*link-type* _link-type_
Denotes the link-type of the interface. When set to _dummy_,
the interface is created as a virtual dummy interfaces.
@ -108,9 +115,9 @@ the system will only respond to certain keywords by default:
configuration data from _object_. Normally _object_
must be a *template*.
*use* _option_
Designates that an option should be used. See _OPTIONS_
section for more information on options.
*use* _executor_
Designates that an executor should be used. See _EXECUTORS_
section for more information on executors.
*pre-down* _command_
Runs _command_ before taking the interface down.
@ -133,11 +140,11 @@ the system will only respond to certain keywords by default:
Additional packages such as *bonding*, *bridge*, *tunnel*, *vrf* and
*vxlan* add additional keywords to this vocabulary.
# OPTIONS
# EXECUTORS
The *use* keyword designates that an _option_ should be used.
The *use* keyword designates that an _executor_ should be used.
This system is extendable by additional packages, but the
most common options are:
most common executors are:
*batman*
The interface is a B.A.T.M.A.N. adv. mesh interface.
@ -158,6 +165,9 @@ most common options are:
Use a DHCP client to learn the IPv4 address of an
interface.
*forward*
Configures forwarding settings on the interface.
*loopback*
Designates the interface as a loopback device.
@ -168,7 +178,8 @@ most common options are:
*tunnel*
The interface is a tunnel. Configuration of tunnels
requires the *tunnel* package to be installed.
requires the *tunnel* package to be installed on Alpine
Linux.
*vrf*
The interface is a VRF. Configuration of VRFs requires
@ -178,11 +189,22 @@ most common options are:
The interface is a Virtual Extensible LAN (VXLAN) tunnel
endpoint.
*wifi*
The interface is a Wi-Fi (IEEE 802.11) client interface.
Configuration of the WiFi client interface requires the
*wireless-tools* package to be installed.
The *wpa_supplicant* package must also be installed to
connect to hotspots using WPA-based security.
*wireguard*
The interface is a Wireguard VPN tunnel endpoint.
Check *interfaces-<option>(5)* for further informaton about a given
option and available configuration parameters.
Check *interfaces-<executor>(5)* for further informaton about a given
executor and available configuration parameters.
If the _auto\_executor\_selection_ ifupdown-ng.conf option is enabled,
*use* statements will automatically be added for executors when their
configuration statements are present in the interfaces file.
# EXAMPLES
@ -216,6 +238,8 @@ iface eth0
# SEE ALSO
*ifstate*(5)
*ifupdown-ng.conf*(5)
*ifup*(8)
*ifdown*(8)
*ifquery*(8)
@ -223,9 +247,13 @@ iface eth0
*interfaces-batman*(5)
*interfaces-bond*(5)
*interfaces-bridge*(5)
*interfaces-forward*(5)
*interfaces-mpls*(5)
*interfaces-ppp*(5)
*interfaces-tunnel*(5)
*interfaces-vrf*(5)
*interfaces-vxlan*(5)
*interfaces-wifi*(5)
*interfaces-wireguard*(5)
# AUTHORS

View file

@ -8,8 +8,6 @@
#
# See interfaces-batman(5) for a list of supported options for hardifs as well as meshifs.
#
set -e
if [ "$VERBOSE" ]; then
set -x
fi

View file

@ -5,14 +5,11 @@
# Sat, 03 Oct 2020 20:42:19 +0200
# -- Maximilian Wilhelm <max@sdn.clinic>
#
set -e
[ -n "$VERBOSE" ] && set -x
get_bond_options() {
# We only care for options of format IF_BOND_<OPTION_NAME>
env | grep '^IF_BOND_[A-Z0-9_]\+$' | while IFS="=" read opt value; do
env | grep '^IF_BOND_[A-Z0-9_]\+' | while IFS="=" read opt value; do
# Members are handled seperately
if [ "${opt}" = "IF_BOND_MEMBERS" ]; then
continue
@ -44,9 +41,9 @@ case "$PHASE" in
# Add members to bundle
for member_iface in ${IF_BOND_MEMBERS}; do
# Work around the current execution order
ip link set "${member_iface}" down
ip link set master "${IFACE}" "${member_iface}"
ip link set "${member_iface}" up
${MOCK} ip link set "${member_iface}" down
${MOCK} ip link set master "${IFACE}" "${member_iface}"
${MOCK} ip link set "${member_iface}" up
done
;;

View file

@ -1,6 +1,5 @@
#!/bin/sh
set -e
[ -n "$VERBOSE" ] && set -x
# Copyright (C) 2012, 2020 Natanael Copa <ncopa@alpinelinux.org>
# Copyright (C) 2020 Ariadne Conill <ariadne@dereferenced.org>
@ -14,6 +13,10 @@ set -e
# implied. In no event shall the authors be liable for any damages arising
# from the use of this software.
################################################################################
# Bridge management functions #
################################################################################
all_ports_exist() {
local i=
for i in "$@"; do
@ -52,13 +55,10 @@ all_ports() {
add_ports() {
local port=
for port in $PORTS; do
if [ -x /etc/network/if-pre-up.d/vlan ]; then
env IFACE=$port /etc/network/if-pre-up.d/vlan
fi
if [ -n "$IF_BRIDGE_HW" ]; then
ip link set dev $port addr $IF_BRIDGE_HW
fi
brctl addif $IFACE $port && ip link set dev $port up
ip link set dev $port master $IFACE && ip link set dev $port up
done
}
@ -66,22 +66,17 @@ del_ports() {
local port=
for port in $PORTS; do
ip link set dev $port down
brctl delif $IFACE $port
if [ -x /etc/network/ip-post-down.d/vlan ]; then
env IFACE=$port /etc/network/if-post-down.d/vlan
fi
ip link set dev $port nomaster
done
}
set_bridge_opts() {
set_bridge_opts_brctl() {
[ -n "$IF_BRIDGE_AGEING" ] \
&& brctl setageing $IFACE $IF_BRIDGE_AGEING
[ -n "$IF_BRIDGE_BRIDGEPRIO" ] \
&& brctl setbridgeprio $IFACE $IF_BRIDGE_BRIDGEPRIO
[ -n "$IF_BRIDGE_FD" ] \
&& brctl setfd $IFACE $IF_BRIDGE_FD
[ -n "$IF_BRIDGE_GCINT" ] \
&& brctl setgcint $IFACE $IF_BRIDGE_GCINT
[ -n "$IF_BRIDGE_HELLO" ] \
&& brctl sethello $IFACE $IF_BRIDGE_HELLO
[ -n "$IF_BRIDGE_MAXAGE" ] \
@ -94,6 +89,44 @@ set_bridge_opts() {
&& brctl stp $IFACE $IF_BRIDGE_STP
}
yesno() {
case "$1" in
yes|YES|true|TRUE|1)
echo 1
;;
*)
echo 0
;;
esac
}
set_bridge_opts_iproute2() {
[ -n "$IF_BRIDGE_AGEING" ] \
&& ip link set dev $IFACE type bridge ageing_time $IF_BRIDGE_AGEING
[ -n "$IF_BRIDGE_BRIDGEPRIO" ] \
&& ip link set dev $IFACE type bridge priority $IF_BRIDGE_BRIDGEPRIO
[ -n "$IF_BRIDGE_FD" ] \
&& ip link set dev $IFACE type bridge forward_delay $IF_BRIDGE_FD
[ -n "$IF_BRIDGE_HELLO" ] \
&& ip link set dev $IFACE type bridge hello_time $IF_BRIDGE_HELLO
[ -n "$IF_BRIDGE_MAXAGE" ] \
&& ip link set dev $IFACE type bridge max_age $IF_BRIDGE_MAXAGE
[ -n "$IF_BRIDGE_PATHCOST" ] \
&& bridge link set dev $IFACE cost $IF_BRIDGE_PATHCOST
[ -n "$IF_BRIDGE_PORTPRIO" ] \
&& bridge link set dev $IFACE priority $IF_BRIDGE_PORTPRIO
[ -n "$IF_BRIDGE_STP" ] \
&& ip link set dev $IFACE type bridge stp $(yesno $IF_BRIDGE_STP)
[ -n "$IF_BRIDGE_VLAN_AWARE" ] \
&& ip link set dev $IFACE type bridge vlan_filtering $(yesno $IF_BRIDGE_VLAN_AWARE)
}
set_bridge_opts() {
[ -x /sbin/bridge ] && set_bridge_opts_iproute2 && return 0
[ -x /sbin/brctl ] && set_bridge_opts_brctl && return 0
}
all_ports_ready() {
local port=
for port in $PORTS; do
@ -123,7 +156,92 @@ wait_bridge() {
done
}
[ -z "$IF_BRIDGE_PORTS" ] && IF_BRIDGE_PORTS="$IF_REQUIRES"
################################################################################
# Bridge port management functions #
################################################################################
configure_access_port() {
port="$1"
vlan="$2"
self="$3"
# Cleans all existing VLANs (probably at least VLAN 1)
bridge vlan show dev ${port} | tail -n +2 | grep -v '^$' | sed -e "s/^${port}//" | while read vid flags; do
bridge vlan del vid "${vid}" dev "${port}" ${self}
done
bridge vlan add vid "${vlan}" pvid untagged dev "${port}" ${self}
}
configure_trunk_port() {
port="$1"
self="$2"
# Working on the bridge itself?
if [ "${self}" ]; then
allow_untagged="${IF_BRIDGE_ALLOW_UNTAGGED}"
pvid="${IF_BRIDGE_PVID}"
vids="${IF_BRIDGE_VIDS}"
else
allow_untagged=$(ifquery -p bridge-allow-untagged ${port} 2>/dev/null || true)
pvid=$(ifquery -p bridge-pvid ${port} 2>/dev/null || true)
vids=$(ifquery -p bridge-vids ${port} 2>/dev/null || true)
fi
# If bridge-allow-untagged if set to off, remove untagged VLAN. If it's
# one of our bridge-vids, it will be set again later.
if [ "${allow_untagged}" -a "$(yesno ${allow_untagged})" = 0 ]; then
untagged_vid=$(bridge vlan show dev ${port} | tail -n +2 | grep -v '^$' | sed -e "s/^${port}//" | awk '/Untagged/ { print $1 }')
if [ "${untagged_vid}" ]; then
bridge vlan del vid "${untagged_vid}" dev "${port}" ${self}
fi
fi
# The vlan specified is to be considered a PVID at ingress.
# Any untagged frames will be assigned to this VLAN.
if [ "${pvid}" ]; then
cur_pvid=$(bridge vlan show dev ${port} | tail -n +2 | grep -v '^$' | sed -e "s/^${port}//" | awk '/PVID/ { print $1 }')
if [ "${cur_pvid}" ]; then
bridge vlan del vid ${cur_pvid} dev "${port}" ${self}
fi
bridge vlan add vid "${pvid}" dev "${port}" pvid untagged ${self}
fi
# Add regular tagged VLANs
for vid in ${vids}; do
bridge vlan add vid $vid dev "${port}" ${self}
done
}
# Configure VLANs on the bridge interface itself
set_bridge_vlans() {
# Shall the bridge interface be an untagged port?
if [ "${IF_BRIDGE_ACCESS}" ]; then
configure_access_port "${IFACE}" "${IF_BRIDGE_ACCESS}" "self"
# Configure bridge interface as trunk port
else
configure_trunk_port "${IFACE}" "self"
fi
}
# Configure VLANs on the bridge-ports
set_bridge_port_vlans() {
for port in ${PORTS}; do
access_vlan=$(ifquery -p bridge-access ${port} 2>/dev/null || true)
# Shall this prot interface be an untagged port?
if [ "${access_vlan}" ]; then
configure_access_port "${port}" "${access_vlan}"
# Configure port as trunk
else
configure_trunk_port "${port}"
fi
done
}
case "$IF_BRIDGE_PORTS" in
"") ;;
@ -132,30 +250,53 @@ all) PORTS=$(all_ports);;
*) PORTS="$IF_BRIDGE_PORTS";;
esac
[ -z "$PORTS" ] && ! env | grep -q "^IF_BRIDGE" && exit
case "$PHASE" in
depend)
echo "$PORTS"
;;
create)
if [ ! -d "/sys/class/net/${IFACE}" ]; then
brctl addbr "${IFACE}"
# Called for the bridge interface
if [ "${IF_BRIDGE_PORTS}" ]; then
echo "$PORTS"
fi
;;
create)
# Called for the bridge interface
if [ "${IF_BRIDGE_PORTS}" -a ! -d "/sys/class/net/${IFACE}" ]; then
ip link add "${IFACE}" type bridge
fi
;;
pre-up)
wait_ports
set_bridge_opts
add_ports
wait_bridge
# Called for the bridge interface
if [ "${IF_BRIDGE_PORTS}" ]; then
wait_ports
set_bridge_opts
set_bridge_vlans
add_ports
set_bridge_port_vlans
wait_bridge
# Called for a bridge member port
elif [ "${IF_BRIDGE_VIDS}" -o "${IF_BRIDGE_PVID}" -o "${IF_BRIDGE_ACCESS}" -o "${IF_BRIDGE_ALLOW_UNTAGGED}" ]; then
# Eventually we want to configure VLAN settings of member ports here.
# The current execution model does not allow this, so this is a no-op
# for now and we work around this by configuring ports while configuring
# the bridge.
true
fi
;;
post-down)
del_ports
ip link set dev $IFACE down
# Called for the bridge interface
if [ "${IF_BRIDGE_PORTS}" ]; then
del_ports
ip link set dev $IFACE down
fi
;;
destroy)
if [ -d "/sys/class/net/${IFACE}" ]; then
brctl delbr "${IFACE}"
# Called for the bridge interface
if [ "${IF_BRIDGE_PORTS}" -a -d "/sys/class/net/${IFACE}" ]; then
ip link del "${IFACE}"
fi
;;
esac

View file

@ -1,9 +1,6 @@
#!/bin/sh
set -e
# 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() {
[ -n "$IF_DHCP_PROGRAM" ] && echo "$IF_DHCP_PROGRAM" && return
@ -17,20 +14,25 @@ determine_implementation() {
start() {
case "$1" in
dhcpcd)
[ -n "$IF_HOSTNAME" ] && optargs="$optargs -h $IF_HOSTNAME"
[ -n "$IF_VENDOR" ] && optargs="$optargs -i $IF_VENDOR"
[ -n "$IF_CLIENT" ] && optargs="$optargs -i $IF_CLIENT"
[ -n "$IF_LEASETIME" ] && optargs="$optargs -l $IF_LEASETIME"
[ -n "$IF_DHCP_HOSTNAME" ] && optargs="$optargs -h $IF_DHCP_HOSTNAME"
[ -n "$IF_DHCP_VENDOR" ] && optargs="$optargs -i $IF_DHCP_VENDOR"
[ -n "$IF_DHCP_CLIENT_ID" ] && optargs="$optargs -i $IF_DHCP_CLIENT_ID"
[ -n "$IF_DHCP_LEASETIME" ] && optargs="$optargs -l $IF_DHCP_LEASETIME"
${MOCK} /sbin/dhcpcd $optargs $IFACE
;;
dhclient)
${MOCK} /usr/sbin/dhclient -pf /var/run/dhclient.$IFACE.pid $IFACE
# Specific config file given?
if [ -n "$IF_DHCP_CONFIG" ]; then
optargs="$optargs -cf $IF_DHCP_CONFIG"
fi
${MOCK} /usr/sbin/dhclient -pf /var/run/dhclient.$IFACE.pid $optargs $IFACE
;;
udhcpc)
optargs=$(eval echo $IF_UDHCPC_OPTS)
[ -n "$IF_HOSTNAME" ] && optargs="$optargs -x hostname:$IF_HOSTNAME"
[ -n "$IF_CLIENT" ] && optargs="$optargs -c $IF_CLIENT"
[ -n "$IF_SCRIPT" ] && optargs="$optargs -s $IF_SCRIPT"
[ -n "$IF_DHCP_HOSTNAME" ] && optargs="$optargs -x hostname:$IF_DHCP_HOSTNAME"
[ -n "$IF_DHCP_CLIENT_ID" ] && optargs="$optargs -c $IF_DHCP_CLIENT_ID"
[ -n "$IF_DHCP_SCRIPT" ] && optargs="$optargs -s $IF_DHCP_SCRIPT"
${MOCK} /sbin/udhcpc -b -R -p /var/run/udhcpc.$IFACE.pid -i $IFACE $optargs
;;
*)

View file

@ -1,6 +1,4 @@
#!/bin/sh
set -e
# gather params for a given prefix, based on executor-scripts/linux/tunnel.
gather_params() {
env | sed -E "

19
executor-scripts/linux/forward Executable file
View 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

View file

@ -1,7 +1,4 @@
#!/bin/sh
set -e
# Executor for advanced GRE tunnel management.
[ -z "$IF_GRE_LOCAL" ] && exit 1

View file

@ -1,7 +1,4 @@
#!/bin/sh
set -e
start() {
${MOCK} /bin/sh -c "echo 1 > /proc/sys/net/ipv6/conf/$IFACE/accept_ra"
}

View file

@ -1,7 +1,4 @@
#!/bin/sh
set -e
[ -n "$VERBOSE" ] && set -x
is_vlan() {

36
executor-scripts/linux/mpls Executable file
View 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

View file

@ -1,6 +1,4 @@
#!/bin/sh
set -e
[ -z "$IF_PPP_PROVIDER" ] && exit 0
case "$PHASE" in

View file

@ -1,7 +1,4 @@
#!/bin/sh
set -e
[ -z "${VERBOSE}" ] || set -x
[ -z "${IF_METRIC}" ] && IF_METRIC="1"
@ -29,34 +26,31 @@ configure_addresses() {
PEER=""
fi
if [ -z "${MOCK}" -a "${1}" = "del" ]; then
# 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
${MOCK} ip "${addrfam}" addr add "${addr}" ${PEER} dev "${IFACE}"
done
}
configure_gateways() {
for gw in ${IF_GATEWAYS}; do
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
}
flush() {
cmd="addr"
arg="dev ${IFACE}"
${MOCK} ip ${cmd} flush ${arg}
}
case "$PHASE" in
up)
configure_addresses add
configure_gateways add
;;
down)
configure_gateways del
configure_addresses del
flush
;;
*) exit 0 ;;
esac

View file

@ -1,27 +1,106 @@
#!/bin/sh
set -e
# Based on alpine's tunnel configuration script.
# Copyright (c) 2017 Kaarle Ritvanen
# Copyright (c) 2020 Ariadne Conill (extended for ifupdown-ng)
# Copyright (c) 2021 Maximilian Wilhelm (make sure mode/type is 1st parameter, add more options)
[ -z "$IF_TUNNEL_LOCAL" ] && exit 1
[ -z "$IF_TUNNEL_LOCAL" -a -z "$IF_TUNNEL_LOCAL_DEV" ] && exit 1
[ -z "$IF_TUNNEL_REMOTE" ] && exit 1
[ -z "$IF_TUNNEL_MODE" ] && exit 1
COMMAND="tunnel"
FAMILY="-4"
[ -n "$VERBOSE" ] && set -x
yesno() {
case "$1" in
yes|1) echo 1 ;;
*) echo 0 ;;
esac
}
# Figure out address familiy
FAMILY="4"
case "$IF_TUNNEL_MODE" in
gretap)
COMMAND="link"
;;
vti6|ipip6|ip6*)
FAMILY="-6"
FAMILY="6"
;;
esac
# Figure out object type - gretap tunnels have to create using ip link
# and therefor require 'type' keyword instead of 'mode'
OBJECT="tunnel"
TYPE_KW="mode"
case "${IF_TUNNEL_MODE}" in
*gretap)
OBJECT="link"
TYPE_KW="type"
# Strip possible "ip6" from tunnel mode
TUNNEL_MODE="gretap"
;;
*)
# Store tunnel type/mode separaltely and unset input variable to exclude it
# from PARAMS below
TUNNEL_MODE="$IF_TUNNEL_MODE"
unset IF_TUNNEL_MODE
;;
esac
# If 'tunnel-local <IP>' was not given but 'tunnel-local-dev <iface>' is given try
# to figure out the IP of the underlay device (wrt the address family used for this
# tunnel) and use this to set up the tunnel
if [ ${PHASE} = "create" -a ! "${IF_TUNNEL_LOCAL}" -a "${IF_TUNNEL_LOCAL_DEV}" ]; then
if [ "${FAMILY}" = "4" ]; then
ip=$(ip -4 -brief addr show dev "${IF_TUNNEL_LOCAL_DEV}" 2>/dev/null | awk '{ print $3 }' | cut -d/ -f1)
# For IPv6 we try to use a non-temporary address (-> privacy extensions)
else
# Get all IPv6 addres configured on $IF_TUNNEL_LOCAL_DEV which are not
# temporary (due to privacy extensions). We do not filter for "mgmtaddr"
# "scope global" etc. as we don't want to make further assumptions on
# whether a user wants to use a link local address configured to this interface.
#
# The assumption that a temporary address configured by PE isn't suited
# to terminate a tunnel should hold in nearly all setups, I hope.
ip=$(ip -6 addr show dev "${IF_TUNNEL_LOCAL_DEV}" -temporary | grep inet6 | head -n1 | awk '{ print $2 }' | cut -d/ -f1)
fi
if [ ! "${ip}" ]; then
echo "Unable to determine the IPv${FAMILIY} address of tunnel-local-dev ${IF_TUNNEL_LOCAL_DEV}!"
exit 1
fi
unset IF_TUNNEL_LOCAL_DEV
export IF_TUNNEL_LOCAL="${ip}"
fi
# Handle boolean switches
MORE_PARAMS=""
if [ "${IF_TUNNEL_IGNORE_DF}" ]; then
if $(yesno "${IF_TUNNEL_IGNORE_DF}"); then
MORE_PARAMS="ignore-df"
else
MORE_PARAMS="noignore-df"
fi
unset IF_TUNNEL_IGNORE_DF
fi
if [ "${IF_TUNNEL_PMTUDISC}" ]; then
if $(yesno "${IF_TUNNEL_PMTUDISC}"); then
MORE_PARAMS="pmtudisc"
else
MORE_PARAMS="nopmtudisc"
fi
unset IF_TUNNEL_PMTUDISC
fi
# Mangle residual IF_TUNNEL_* params into single string
PARAMS=$(set | sed -E '
s/^IF_TUNNEL_([A-Z0-9_]+)=(.+)/\1\n\2/
ta
@ -38,12 +117,12 @@ PARAMS=$(set | sed -E '
case "$PHASE" in
create)
${MOCK} eval ip $FAMILY $COMMAND add $IFACE $PARAMS
${MOCK} eval ip -$FAMILY $OBJECT add $IFACE $TYPE_KW $TUNNEL_MODE $PARAMS $MORE_PARAMS
;;
destroy)
${MOCK} ip $FAMILY $COMMAND del $IFACE
${MOCK} ip -$FAMILY $OBJECT del $IFACE
;;
depend)
echo "$IF_TUNNEL_DEV"
echo "${IF_TUNNEL_DEV}" "${IF_TUNNEL_LOCAL_DEV}"
;;
esac

View file

@ -1,6 +1,4 @@
#!/bin/sh
set -e
handle_init() {
${MOCK} /sbin/ip link $1 $IFACE type vrf table $IF_VRF_TABLE
${MOCK} /sbin/ip rule $1 iif $IFACE table $IF_VRF_TABLE

View file

@ -10,15 +10,12 @@
# IF_VXLAN_ID The VXLAN Network Identifier (VNI)
# IF_VXLAN_PHYSDEV Specifies the physical device to use for tunnel endpoint communication
# IF_VXLAN_LOCAL_IP Specifies the source IP address to use in outgoing packets
# IF_VXLAN_REMOTE_IP IP of the remote VTEP endpoint (for ptp mode)
# IF_VXLAN_REMOTE_GROUP Multicast group to use for this VNI (for ptmp mode)
# IF_VXLAN_PEER_IPS Space separated list of IPs of the remote VTEP endpoint (for ptp/ptmp mode with ingress replication)
# IF_VXLAN_PEER_GROUP Multicast group to use for this VNI (for ptmp mode with multicast)
# IF_VXLAN_LEARNING Wether to activate MAC learning on this instance (on/off)
# IF_VXLAN_AGEING Specifies the lifetime in seconds of FDB entries learnt by the kernel
# IF_VXLAN_DSTPORT UDP destination port to communicate to the remote VXLAN tunnel endpoint (default 4789)
#
set -e
[ -n "$VERBOSE" ] && set -x
# No VNI, nuthin' to do for us
@ -39,17 +36,27 @@ case "$PHASE" in
fi
# Input validation
if [ "${IF_VXLAN_REMOTE_IP}" -a "${IF_VXLAN_REMOTE_GROUP}" ]; then
echo "Error on ${IFACE} (vxlan): Only one of 'remote' and 'group' can be given!" >&2
if [ "${IF_VXLAN_PEER_IPS}" -a "${IF_VXLAN_PEER_GROUP}" ]; then
echo "Error on ${IFACE} (vxlan): Only one of 'vxlan-peer-ips' and 'vxlan-peer-group' can be used!" >&2
exit 1
fi
# Check if we should operate in unicast ptp or ptmp mode
if [ "${IF_VXLAN_PEER_IPS}" ]; then
# If it's only one thing which looks like an IPv4/IPv6 address we assume it's ptp
if echo "${IF_VXLAN_PEER_IPS}" | grep -q '^[[:space:]]*[[:xdigit:].:]\+[[:space:]]*$'; then
UCAST_MODE="ptp"
else
UCAST_MODE="ptmp"
fi
fi
# Gather arguments
ARGS=""
[ "${IF_VXLAN_PHYSDEV}" ] && ARGS="${ARGS} dev ${IF_VXLAN_PHYSDEV}"
[ "${IF_VXLAN_LOCAL_IP}" ] && ARGS="${ARGS} local ${IF_VXLAN_LOCAL_IP}"
[ "${IF_VXLAN_REMOTE_IP}" ] && ARGS="${ARGS} remote ${IF_VXLAN_REMOTE_IP}"
[ "${IF_VXLAN_REMOTE_GROUP}" ] && ARGS="${ARGS} group ${IF_VXLAN_REMOTE_GROUP}"
[ "${UCAST_MODE}" = "ptp" ] && ARGS="${ARGS} remote ${IF_VXLAN_PEER_IPS}"
[ "${IF_VXLAN_PEER_GROUP}" ] && ARGS="${ARGS} group ${IF_VXLAN_PEER_GROUP}"
[ "${IF_VXLAN_AGEING}" ] && ARGS="${ARGS} ageing ${IF_VXLAN_AGEING}"
# Linux uses non-standard default port - WTF?
@ -70,6 +77,13 @@ case "$PHASE" in
esac
${MOCK} ip link add "${IFACE}" type vxlan id "${IF_VXLAN_ID}" ${ARGS}
# Set up FDB entries for peer VTEPs
if [ "${UCAST_MODE}" = "ptmp" ]; then
for peer in ${IF_VXLAN_PEER_IPS}; do
${MOCK} bridge fdb append 00:00:00:00:00:00 dev "${IFACE}" dst "${peer}" self permanent
done
fi
;;
destroy)

119
executor-scripts/linux/wifi Executable file
View 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

View file

@ -1,7 +1,4 @@
#!/bin/sh
set -e
[ -n "$VERBOSE" ] && set -x
[ -z "$IF_WIREGUARD_CONFIG_PATH" ] && IF_WIREGUARD_CONFIG_PATH="/etc/wireguard/$IFACE.conf"

View file

@ -1,5 +1,4 @@
#!/bin/sh
set -e
[ -z "$IF_BOND_MEMBERS" ] && IF_BOND_MEMBERS="$IF_BOND_SLAVES"
case "$PHASE" in
depend) echo "$IF_BOND_MEMBERS" ;;

View file

@ -1,5 +1,4 @@
#!/bin/sh
set -e
case "$PHASE" in
depend)
if [ "$IF_BRIDGE_PORTS" != "none" ]; then

114
libifupdown/compat.c Normal file
View 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
View 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

View file

@ -21,6 +21,9 @@
struct lif_config_file lif_config = {
.allow_addon_scripts = true,
.allow_any_iface_as_template = true,
.auto_executor_selection = true,
.compat_create_interfaces = true,
.compat_ifupdown2_bridge_ports_inherit_vlans = true,
.implicit_template_conversion = true,
.use_hostname_for_dhcp = true,
};
@ -31,7 +34,7 @@ set_bool_value(const char *key, const char *value, void *opaque)
(void) key;
if (*value == '1' ||
*value == 'Y' || *value == 'y' ||
*value == 'Y' || *value == 'y' ||
*value == 'T' || *value == 't')
*(bool *) opaque = true;
else if (*value == '0' ||
@ -47,6 +50,9 @@ set_bool_value(const char *key, const char *value, void *opaque)
static struct lif_config_handler handlers[] = {
{"allow_addon_scripts", set_bool_value, &lif_config.allow_addon_scripts},
{"allow_any_iface_as_template", set_bool_value, &lif_config.allow_any_iface_as_template},
{"auto_executor_selection", set_bool_value, &lif_config.auto_executor_selection},
{"compat_create_interfaces", set_bool_value, &lif_config.compat_create_interfaces},
{"compat_ifupdown2_bridge_ports_inherit_vlans", set_bool_value, &lif_config.compat_ifupdown2_bridge_ports_inherit_vlans},
{"implicit_template_conversion", set_bool_value, &lif_config.implicit_template_conversion},
{"use_hostname_for_dhcp", set_bool_value, &lif_config.use_hostname_for_dhcp},
};

View file

@ -21,6 +21,9 @@
struct lif_config_file {
bool allow_addon_scripts;
bool allow_any_iface_as_template;
bool auto_executor_selection;
bool compat_create_interfaces;
bool compat_ifupdown2_bridge_ports_inherit_vlans;
bool implicit_template_conversion;
bool use_hostname_for_dhcp;
};

View file

@ -30,6 +30,86 @@
#define SHELL "/bin/sh"
#if defined(__linux__)
# include <sys/syscall.h>
#endif
/* POSIX compatible fallback using waitpid(2) and usleep(3) */
static inline bool
lif_process_monitor_busyloop(pid_t child, int timeout_sec, int *status)
{
int ticks = 0;
while (ticks < timeout_sec * 20)
{
/* Ugly hack: most executors finish very quickly,
* so give them a chance to finish before sleeping.
*/
usleep(50);
if (waitpid(child, status, WNOHANG) == child)
return true;
usleep(49950);
ticks++;
}
return false;
}
#if defined(__linux__) && defined(__NR_pidfd_open)
/* TODO: remove this wrapper once musl and glibc gain pidfd_open() directly. */
static inline int
lif_pidfd_open(pid_t pid, unsigned int flags)
{
return syscall(__NR_pidfd_open, pid, flags);
}
static inline bool
lif_process_monitor_procdesc(pid_t child, int timeout_sec, int *status)
{
int pidfd = lif_pidfd_open(child, 0);
/* pidfd_open() not available, fall back to busyloop */
if (pidfd == -1 && errno == ENOSYS)
return lif_process_monitor_busyloop(child, timeout_sec, status);
struct pollfd pfd = {
.fd = pidfd,
.events = POLLIN,
};
if (poll(&pfd, 1, timeout_sec * 1000) < 1)
return false;
waitpid(child, status, 0);
close(pidfd);
return true;
}
#endif
static inline bool
lif_process_monitor(const char *cmdbuf, pid_t child, int timeout_sec)
{
int status;
#if defined(__linux__) && defined(__NR_pidfd_open)
if (lif_process_monitor_procdesc(child, timeout_sec, &status))
return WIFEXITED(status) && WEXITSTATUS(status) == 0;
#else
if (lif_process_monitor_busyloop(child, timeout_sec, &status))
return WIFEXITED(status) && WEXITSTATUS(status) == 0;
#endif
fprintf(stderr, "execution of '%s': timeout after %d seconds\n", cmdbuf, timeout_sec);
kill(child, SIGKILL);
waitpid(child, &status, 0);
return false;
}
bool
lif_execute_fmt(const struct lif_execute_opts *opts, char *const envp[], const char *fmt, ...)
{
@ -55,10 +135,7 @@ lif_execute_fmt(const struct lif_execute_opts *opts, char *const envp[], const c
return false;
}
int status;
waitpid(child, &status, 0);
return WIFEXITED(status) && WEXITSTATUS(status) == 0;
return lif_process_monitor(cmdbuf, child, opts->timeout);
}
bool
@ -118,11 +195,8 @@ lif_execute_fmt_with_result(const struct lif_execute_opts *opts, char *buf, size
return false;
}
int status;
no_result:
waitpid(child, &status, 0);
return WIFEXITED(status) && WEXITSTATUS(status) == 0;
return lif_process_monitor(cmdbuf, child, opts->timeout);
}
bool

View file

@ -27,6 +27,7 @@ struct lif_execute_opts {
const char *executor_path;
const char *interfaces_file;
const char *state_file;
int timeout;
};
extern bool lif_execute_fmt(const struct lif_execute_opts *opts, char *const envp[], const char *fmt, ...);

View file

@ -32,6 +32,7 @@ struct remap_token {
static const struct remap_token tokens[] = {
{"bond-ad-sys-priority", "bond-ad-actor-sys-prio"}, /* ifupdown2 */
{"bond-slaves", "bond-members"}, /* legacy ifupdown, ifupdown2 */
{"client", "dhcp-client-id"}, /* legacy ifupdown */
{"driver-message-level", "ethtool-msglvl"}, /* Debian ethtool integration */
{"endpoint", "tunnel-remote"}, /* legacy ifupdown */
{"ethernet-autoneg", "ethtool-ethernet-autoneg"}, /* Debian ethtool integration */
@ -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-irq", "ethtool-coalesce-tx-usecs-irq"}, /* Debian ethtool integration */
{"hardware-irq-coalesce-tx-usecs-low", "ethtool-coalesce-tx-usecs-low"}, /* Debian ethtool integration */
{"hostname", "dhcp-hostname"}, /* legacy ifupdown */
{"key", "tunnel-key"}, /* legacy ifupdown */
{"leasetime", "dhcp-leasetime"}, /* legacy ifupdown */
{"link-autoneg", "ethtool-ethernet-autoneg"}, /* ifupdown2 */
{"link-duplex", "ethtool-link-duplex"}, /* Debian ethtool integration */
{"link-fec", "ethtool-link-fec"}, /* ifupdown2 */
@ -85,6 +89,7 @@ static const struct remap_token tokens[] = {
{"offload-ufo", "ethtool-offload-ufo"}, /* Debian ethtool integration */
{"pointopoint", "point-to-point"}, /* legacy ifupdown, ifupdown2 */
{"provider", "ppp-provider"}, /* legacy ifupdown, ifupdown2 */
{"script", "dhcp-script"}, /* legacy ifupdown */
{"rx-offload", "ethtool-offload-rx"}, /* ifupdown2 */
{"tso-offload", "ethtool-offload-tso"}, /* ifupdown2 */
{"ttl", "tunnel-ttl"}, /* legacy ifupdown */
@ -92,10 +97,13 @@ static const struct remap_token tokens[] = {
{"tunnel-physdev", "tunnel-dev"}, /* ifupdown2 */
{"tx-offload", "ethtool-offload-tx"}, /* ifupdown2 */
{"ufo-offload", "ethtool-offload-ufo"}, /* ifupdown2 */
{"vendor", "dhcp-vendor"}, /* legacy ifupdown */
{"vrf", "vrf-member"}, /* ifupdown2 */
{"vxlan-local-tunnelip", "vxlan-local-ip"}, /* ifupdown2 */
{"vxlan-remoteip", "vxlan-remote-ip"}, /* ifupdown2 */
{"vxlan-svcnodeip", "vxlan-remote-group"}, /* ifupdown2 */
{"vxlan-remote-group", "vxlan-peer-group"}, /* ifupdown-ng */
{"vxlan-remoteip", "vxlan-peer-ips"}, /* ifupdown2 */
{"vxlan-remote-ip", "vxlan-peer-ips"}, /* ifupdown-ng */
{"vxlan-svcnodeip", "vxlan-peer-group"}, /* ifupdown2 */
};
static int
@ -172,6 +180,9 @@ handle_auto(struct lif_interface_file_parse_state *state, char *token, char *buf
if (!state->cur_iface->is_template)
state->cur_iface->is_auto = true;
if (state->cur_iface->is_auto)
state->cur_iface->is_explicit = true;
return true;
}
@ -203,12 +214,19 @@ handle_generic(struct lif_interface_file_parse_state *state, char *token, char *
token = maybe_remap_token(token);
/* This smells like a bridge */
if (strcmp(token, "bridge-ports") == 0)
state->cur_iface->is_bridge = true;
/* Skip any leading whitespaces in value for <token> */
while (isspace (*bufp))
bufp++;
lif_dict_add(&state->cur_iface->vars, token, strdup(bufp));
if (!lif_config.auto_executor_selection)
return true;
/* Check if token looks like <word1>-<word*> and assume <word1> is an addon */
char *word_end = strchr(token, '-');
if (word_end != NULL)
@ -234,8 +252,8 @@ handle_hostname(struct lif_interface_file_parse_state *state, char *token, char
return true;
}
lif_dict_delete(&state->cur_iface->vars, token);
lif_dict_add(&state->cur_iface->vars, token, strdup(hostname));
lif_dict_delete(&state->cur_iface->vars, "dhcp-hostname");
lif_dict_add(&state->cur_iface->vars, "dhcp-hostname", strdup(hostname));
return true;
}
@ -253,6 +271,12 @@ handle_iface(struct lif_interface_file_parse_state *state, char *token, char *bu
return true;
}
/* if we have a current interface, call lif_interface_finalize to finalize any
* address properties by converting them to CIDR and flushing the netmask property.
*/
if (state->cur_iface != NULL)
lif_interface_finalize(state->cur_iface);
state->cur_iface = lif_interface_collection_find(state->collection, ifname);
if (state->cur_iface == NULL)
{
@ -425,6 +449,7 @@ struct parser_keyword {
static const struct parser_keyword keywords[] = {
{"address", handle_address},
{"auto", handle_auto},
{"dhcp-hostname", handle_hostname},
{"gateway", handle_gateway},
{"hostname", handle_hostname},
{"iface", handle_iface},
@ -491,6 +516,11 @@ lif_interface_file_parse(struct lif_interface_file_parse_state *state, const cha
}
fclose(f);
/* finalize any open interface */
if (state->cur_iface != NULL)
lif_interface_finalize(state->cur_iface);
state->cur_filename = old_filename;
state->cur_lineno = old_lineno;
return true;

View file

@ -84,6 +84,19 @@ count_set_bits(const char *netmask)
return r;
}
static inline size_t
determine_interface_netmask(const struct lif_interface *iface, const struct lif_address *addr)
{
/* if netmask is not set, default to /24 or /64, ifupdown does so too */
size_t netmask = addr->domain == AF_INET6 ? 64 : 24;
struct lif_dict_entry *entry = lif_dict_find(&iface->vars, "netmask");
if (entry != NULL)
netmask = count_set_bits(entry->data);
return netmask;
}
bool
lif_address_format_cidr(const struct lif_interface *iface, struct lif_dict_entry *entry, char *buf, size_t buflen)
{
@ -91,14 +104,7 @@ lif_address_format_cidr(const struct lif_interface *iface, struct lif_dict_entry
size_t orig_netmask = addr->netmask;
if (!addr->netmask)
{
/* 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);
}
addr->netmask = determine_interface_netmask(iface, addr);
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 */
if (strchr(ifname, '.') != NULL)
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
@ -211,6 +207,46 @@ lif_interface_use_executor(struct lif_interface *interface, const char *executor
interface->is_bridge = true;
else if (!strcmp(executor, "bond"))
interface->is_bond = true;
if (strcmp(executor, "dhcp") || !lif_config.use_hostname_for_dhcp)
return;
/* learn a reasonable default hostname */
struct utsname un;
if (uname(&un) < 0)
return;
lif_dict_add(&interface->vars, "dhcp-hostname", strdup(un.nodename));
}
void
lif_interface_finalize(struct lif_interface *interface)
{
struct lif_node *iter;
/* convert all addresses to CIDR notation. */
LIF_DICT_FOREACH(iter, &interface->vars)
{
struct lif_dict_entry *entry = iter->data;
if (strcmp(entry->key, "address"))
continue;
struct lif_address *addr = entry->data;
if (!addr->netmask)
addr->netmask = determine_interface_netmask(interface, addr);
}
/* with all addresses converted to CIDR, netmask property is no longer needed. */
struct lif_dict_entry *entry = lif_dict_find(&interface->vars, "netmask");
if (entry != NULL)
{
free(entry->data);
lif_dict_delete_entry(&interface->vars, entry);
}
}
void
@ -223,6 +259,7 @@ lif_interface_collection_init(struct lif_dict *collection)
/* always enable loopback interface as part of a collection */
if_lo = lif_interface_collection_find(collection, "lo");
if_lo->is_auto = true;
if_lo->is_explicit = true;
lif_interface_use_executor(if_lo, "loopback");
}

View file

@ -50,6 +50,7 @@ struct lif_interface {
bool is_bond;
bool is_template;
bool is_pending;
bool is_explicit;
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_fini(struct lif_interface *interface);
extern void lif_interface_use_executor(struct lif_interface *interface, const char *executor);
extern void lif_interface_finalize(struct lif_interface *interface);
extern void lif_interface_collection_init(struct lif_dict *collection);
extern void lif_interface_collection_fini(struct lif_dict *collection);

View file

@ -29,6 +29,7 @@
#include "libifupdown/tokenize.h"
#include "libifupdown/config-file.h"
#include "libifupdown/config-parser.h"
#include "libifupdown/compat.h"
#ifndef ARRAY_SIZE
# define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x))

View file

@ -94,7 +94,8 @@ query_dependents_from_executors(const struct lif_execute_opts *opts, char *const
struct lif_execute_opts exec_opts = {
.verbose = opts->verbose,
.executor_path = opts->executor_path,
.interfaces_file = opts->interfaces_file
.interfaces_file = opts->interfaces_file,
.timeout = opts->timeout,
};
if (strcmp(entry->key, "use"))
@ -114,7 +115,7 @@ query_dependents_from_executors(const struct lif_execute_opts *opts, char *const
return true;
}
bool
static bool
append_to_buffer(char **buffer, size_t *buffer_len, char **end, const char *value)
{
size_t value_len = strlen (value);
@ -122,12 +123,17 @@ 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 */
if (*buffer_len < strlen (*buffer) + value_len + 2)
{
*buffer = realloc (*buffer, *buffer_len * 2);
if (*buffer == NULL)
/* XXX Here be dragons */
return false;
size_t end_offset = *end - *buffer;
char *tmp = realloc (*buffer, *buffer_len * 2);
*buffer_len = *buffer_len * 2;
if (tmp != NULL)
{
*buffer = tmp;
*end = tmp + end_offset;
*buffer_len = *buffer_len * 2;
}
else
return false;
}
/* Append value to buffer */
@ -396,6 +402,15 @@ handle_dependents(const struct lif_execute_opts *opts, struct lif_interface *par
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)
fprintf(stderr, "ifupdown: changing state of dependent interface %s (of %s) to %s\n",
iface->ifname, parent->ifname, up ? "up" : "down");

View file

@ -40,7 +40,7 @@ extern void lif_node_delete(struct lif_node *node, struct lif_list *list);
for ((iter) = (head); (iter) != NULL; (iter) = (iter)->next)
#define LIF_LIST_FOREACH_SAFE(iter, iter_next, head) \
for ((iter) = (head), (iter_next) = (iter)->next; (iter) != NULL; (iter) = (iter_next), (iter_next) = (iter) != NULL ? (iter)->next : NULL)
for ((iter) = (head), (iter_next) = (iter) != NULL ? (iter)->next : NULL; (iter) != NULL; (iter) = (iter_next), (iter_next) = (iter) != NULL ? (iter)->next : NULL)
#define LIF_LIST_FOREACH_REVERSE(iter, tail) \
for ((iter) = (tail); (iter) != NULL; (iter) = (iter)->prev)

View file

@ -29,8 +29,13 @@ lif_state_read(struct lif_dict *state, FILE *fd)
char *bufp = linebuf;
char *ifname = lif_next_token(&bufp);
char *refcount = lif_next_token(&bufp);
char *explicit = lif_next_token(&bufp);
size_t rc = 1;
char *equals_p = strchr(linebuf, '=');
bool is_explicit = false;
if (*explicit && !strcmp(explicit, "explicit"))
is_explicit = true;
if (*refcount)
{
@ -42,12 +47,12 @@ lif_state_read(struct lif_dict *state, FILE *fd)
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;
}
*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;
@ -99,6 +104,7 @@ lif_state_upsert(struct lif_dict *state, const char *ifname, struct lif_interfac
rec->mapped_if = strdup(iface->ifname);
rec->refcount = iface->refcount;
rec->is_explicit = iface->is_explicit;
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_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);
iface->refcount = rec->refcount;
iface->is_explicit = rec->is_explicit;
}
return true;

View file

@ -17,11 +17,14 @@
#define LIBIFUPDOWN_STATE_H__GUARD
#include <stdio.h>
#include <stdbool.h>
#include "libifupdown/interface.h"
struct lif_state_record {
char *mapped_if;
size_t refcount;
bool is_explicit;
};
extern bool lif_state_read(struct lif_dict *state, FILE *f);

View file

@ -21,20 +21,20 @@
void
lif_common_version(void)
{
printf("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION);
printf("\nCopyright (c) 2020 Ariadne Conill <ariadne@dereferenced.org>\n");
printf("\nCopyright (c) 2020 Maximilian Wilhelm <max@sdn.clinic>\n\n");
printf("Permission to use, copy, modify, and/or distribute this software for any\n");
printf("purpose with or without fee is hereby granted, provided that the above\n");
printf("copyright notice and this permission notice appear in all copies.\n\n");
printf("This software is provided 'as is' and without any warranty, express or\n");
printf("implied. In no event shall the authors be liable for any damages arising\n");
printf("from the use of this software.\n\n");
printf("Report bugs at <%s>.\n", PACKAGE_BUGREPORT);
printf(PACKAGE_NAME " " PACKAGE_VERSION "\n"
"\n"
"Copyright (c) 2020 Ariadne Conill <ariadne@dereferenced.org>\n"
"Copyright (c) 2020 Maximilian Wilhelm <max@sdn.clinic>\n"
"\n"
"Permission to use, copy, modify, and/or distribute this software for any\n"
"purpose with or without fee is hereby granted, provided that the above\n"
"copyright notice and this permission notice appear in all copies.\n"
"\n"
"This software is provided 'as is' and without any warranty, express or\n"
"implied. In no event shall the authors be liable for any damages arising\n"
"from the use of this software.\n"
"\n"
"Report bugs at <" PACKAGE_BUGREPORT ">.\n");
exit(EXIT_SUCCESS);
}

127
libifupdown/yaml-base.c Normal file
View 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
View 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
View 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
View 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

View file

@ -2,6 +2,7 @@ syntax(2)
test_suite('ifupdown-ng')
atf_test_program{name='multicall_test'}
atf_test_program{name='ifquery_test'}
atf_test_program{name='ifup_test'}
atf_test_program{name='ifdown_test'}

View file

@ -0,0 +1,10 @@
iface eth0
use dhcp
hostname foo
iface eth1
use dhcp
iface eth2
use dhcp
dhcp-hostname bar

View 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

View file

@ -0,0 +1,5 @@
iface v6
address 2001:470:1f10::1
iface v4
address 203.0.113.2

View file

@ -34,7 +34,16 @@ tests_init \
vlan_explicit_learned_dependency \
vlan_guessed_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() {
atf_check -s exit:1 -e ignore ifquery -S/dev/null
@ -226,3 +235,62 @@ wireguard_body() {
-o match:"use wireguard" \
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
}

View file

@ -2,14 +2,17 @@ syntax(2)
test_suite('ifupdown-ng')
atf_test_program{name='link_test'}
atf_test_program{name='ipv6-ra_test'}
atf_test_program{name='bond_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='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='wireguard_test'}

30
tests/linux/bond_test Executable file
View 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}
}

View file

@ -48,7 +48,7 @@ udhcpc_opts_up_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' \
${EXECUTOR}
}

90
tests/linux/forward_test Executable file
View 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
View 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}
}

View file

@ -8,9 +8,7 @@ tests_init \
up_ptp \
down \
vrf_up \
vrf_down \
metric_up \
metric_down
metric_up
up_body() {
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" \
IF_GATEWAYS="203.0.113.1 2001:db8:1000:2::1"
atf_check -s exit:0 \
-o match:'addr del 203.0.113.2/24 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' \
-o match:'addr flush dev eth0' \
${EXECUTOR}
}
@ -52,23 +47,9 @@ vrf_up_body() {
${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() {
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 \
-o match:'route add default via 203.0.113.2 table 1 metric 20' \
${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}
}

View file

@ -5,7 +5,10 @@ EXECUTOR="$(atf_get_srcdir)/../../executor-scripts/linux/tunnel"
tests_init \
tunnel_bringup \
tunnel_teardown
tunnel_teardown \
gretap_up \
gretap_down \
ip6gretap_up
tunnel_bringup_body() {
export MOCK=echo IFACE=tun0 PHASE=create IF_TUNNEL_MODE=gre \
@ -13,7 +16,7 @@ tunnel_bringup_body() {
IF_TUNNEL_TTL=255
atf_check -s exit:0 \
-o match:"ip -4 tunnel add tun0" \
-o match:"mode 'gre'" \
-o match:"mode gre" \
-o match:"ttl '255'" \
-o match:"local '1.2.3.4'" \
-o match:"remote '5.6.7.8'" \
@ -28,3 +31,35 @@ tunnel_teardown_body() {
-o match:"ip -4 tunnel del tun0" \
${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}
}

View file

@ -5,7 +5,8 @@ EXECUTOR="$(atf_get_srcdir)/../../executor-scripts/linux/vxlan"
tests_init \
create_simple \
create_ucast \
create_ucast_ptp \
create_ucast_ptmp \
create_mcast \
create_physdev \
create_dstport \
@ -18,14 +19,24 @@ create_simple_body() {
${EXECUTOR}
}
create_ucast_body() {
export IFACE=vx_foo PHASE=create MOCK=echo IF_VXLAN_ID=2342 IF_VXLAN_REMOTE_IP=192.2.0.42
create_ucast_ptp_body() {
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' \
${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() {
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' \
${EXECUTOR}
}

11
tests/multicall_test Executable file
View 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
}