Compare commits

...

36 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
36 changed files with 566 additions and 120 deletions

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 Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above purpose with or without fee is hereby granted, provided that the above

View file

@ -4,7 +4,7 @@ LIBBSD_CFLAGS =
LIBBSD_LIBS = LIBBSD_LIBS =
PACKAGE_NAME := ifupdown-ng PACKAGE_NAME := ifupdown-ng
PACKAGE_VERSION := 0.11.0 PACKAGE_VERSION := 0.11.3
PACKAGE_BUGREPORT := https://github.com/ifupdown-ng/ifupdown-ng/issues/new PACKAGE_BUGREPORT := https://github.com/ifupdown-ng/ifupdown-ng/issues/new
@ -14,7 +14,8 @@ CONFIG_FILE := /etc/network/ifupdown-ng.conf
EXECUTOR_PATH := /usr/libexec/ifupdown-ng EXECUTOR_PATH := /usr/libexec/ifupdown-ng
CFLAGS ?= -ggdb3 -Os CFLAGS ?= -ggdb3 -Os
CFLAGS += -Wall -Wextra CFLAGS += -Wall -Wextra -Werror
CFLAGS += -Wmissing-declarations -Wmissing-prototypes -Wcast-align -Wpointer-arith -Wreturn-type
CFLAGS += ${LIBBSD_CFLAGS} CFLAGS += ${LIBBSD_CFLAGS}
CPPFLAGS = -I. CPPFLAGS = -I.
CPPFLAGS += -DINTERFACES_FILE=\"${INTERFACES_FILE}\" CPPFLAGS += -DINTERFACES_FILE=\"${INTERFACES_FILE}\"
@ -119,6 +120,8 @@ EXECUTOR_SCRIPTS ?= ${EXECUTOR_SCRIPTS_CORE} ${EXECUTOR_SCRIPTS_OPT}
EXECUTOR_SCRIPTS_STUB ?= EXECUTOR_SCRIPTS_STUB ?=
EXECUTOR_SCRIPTS_NATIVE ?=
TARGET_LIBS = ${LIBIFUPDOWN_LIB} TARGET_LIBS = ${LIBIFUPDOWN_LIB}
LIBS += ${TARGET_LIBS} ${LIBBSD_LIBS} LIBS += ${TARGET_LIBS} ${LIBBSD_LIBS}
@ -153,6 +156,9 @@ install: all
for i in ${EXECUTOR_SCRIPTS_STUB}; do \ for i in ${EXECUTOR_SCRIPTS_STUB}; do \
install -D -m755 executor-scripts/stub/$$i ${DESTDIR}${EXECUTOR_PATH}/$$i; \ install -D -m755 executor-scripts/stub/$$i ${DESTDIR}${EXECUTOR_PATH}/$$i; \
done done
for i in ${EXECUTOR_SCRIPTS_NATIVE}; do \
install -D -m755 executor-scripts/${LAYOUT}-native/$$i ${DESTDIR}${EXECUTOR_PATH}/$$i; \
done
install -D -m644 dist/ifupdown-ng.conf.example ${DESTDIR}${CONFIG_FILE}.example install -D -m644 dist/ifupdown-ng.conf.example ${DESTDIR}${CONFIG_FILE}.example
.scd.1 .scd.2 .scd.3 .scd.4 .scd.5 .scd.6 .scd.7 .scd.8: .scd.1 .scd.2 .scd.3 .scd.4 .scd.5 .scd.6 .scd.7 .scd.8:
@ -167,6 +173,7 @@ MANPAGES_5 = \
doc/interfaces-bridge.5 \ doc/interfaces-bridge.5 \
doc/interfaces-forward.5 \ doc/interfaces-forward.5 \
doc/interfaces-ppp.5 \ doc/interfaces-ppp.5 \
doc/interfaces-tunnel.5 \
doc/interfaces-vrf.5 \ doc/interfaces-vrf.5 \
doc/interfaces-vxlan.5 \ doc/interfaces-vxlan.5 \
doc/interfaces-wifi.5 \ doc/interfaces-wifi.5 \

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 LIBBSD_CFLAGS="$(pkg-config --cflags libbsd-overlay)" LIBBSD_LIBS="$(pkg-config --cflags --libs libbsd-overlay)"
make install make install
To run the tests, do `make check`. Running the checks requires `kyua` (`apk add kyua`, not packaged for Debian). To run the tests, do `make check`. Running the checks requires `kyua` (`apk add kyua` / `apt install kyua`).
To build the documentation, do `make docs` and `make install_docs`. Building To build the documentation, do `make docs` and `make install_docs`. Building
the documentation requires scdoc (`apk add scdoc` / `apt install scdoc`). the documentation requires scdoc (`apk add scdoc` / `apt install scdoc`).
## Discussion ## Discussion
Discuss ifupdown-ng on IRC: irc.as7007.net #ifupdown-ng Discuss ifupdown-ng on IRC: irc.oftc.net #ifupdown-ng

View file

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

22
cmd/ifctrstat-linux.h Normal file
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 <string.h>
#include "libifupdown/libifupdown.h" #include "libifupdown/libifupdown.h"
#include "cmd/multicall.h" #include "cmd/multicall.h"
#include "cmd/ifctrstat-linux.h"
extern struct counter_desc { const char *name; const void *data; } avail_counters[]; extern struct counter_desc { const char *name; const void *data; } avail_counters[];
extern int avail_counters_count; extern int avail_counters_count;
extern const char *read_counter(const char *interface, const char *counter);
static bool show_label = true; static bool show_label = true;
static bool static bool
@ -96,7 +95,7 @@ ifctrstat_set_nolabel(const char *opt_arg)
show_label = false; show_label = false;
} }
int static int
ifctrstat_main(int argc, char *argv[]) ifctrstat_main(int argc, char *argv[])
{ {
if (optind >= argc) if (optind >= argc)

View file

@ -131,7 +131,7 @@ pp_impl_cmp(const void *a, const void *b)
return strcmp(key, impl->name); return strcmp(key, impl->name);
} }
int static int
ifparse_main(int argc, char *argv[]) ifparse_main(int argc, char *argv[])
{ {
struct lif_dict state = {}; struct lif_dict state = {};

View file

@ -22,7 +22,7 @@
#include "cmd/multicall.h" #include "cmd/multicall.h"
#include "cmd/pretty-print-iface.h" #include "cmd/pretty-print-iface.h"
void static void
print_interface_dot(struct lif_dict *collection, struct lif_interface *iface, struct lif_interface *parent) print_interface_dot(struct lif_dict *collection, struct lif_interface *iface, struct lif_interface *parent)
{ {
if (!lif_lifecycle_query_dependents(&exec_opts, iface, iface->ifname)) if (!lif_lifecycle_query_dependents(&exec_opts, iface, iface->ifname))
@ -57,7 +57,7 @@ print_interface_dot(struct lif_dict *collection, struct lif_interface *iface, st
} }
} }
void static void
print_interface_property(struct lif_interface *iface, const char *property) print_interface_property(struct lif_interface *iface, const char *property)
{ {
struct lif_node *iter; struct lif_node *iter;
@ -83,7 +83,7 @@ print_interface_property(struct lif_interface *iface, const char *property)
} }
} }
void static void
list_interfaces(struct lif_dict *collection, struct match_options *opts) list_interfaces(struct lif_dict *collection, struct match_options *opts)
{ {
struct lif_node *iter; struct lif_node *iter;
@ -126,7 +126,7 @@ list_interfaces(struct lif_dict *collection, struct match_options *opts)
static bool listing = false, listing_stat = false, listing_running = false; static bool listing = false, listing_stat = false, listing_running = false;
static bool allow_undefined = false; static bool allow_undefined = false;
void static void
list_state(struct lif_dict *state, struct match_options *opts) list_state(struct lif_dict *state, struct match_options *opts)
{ {
struct lif_node *iter; struct lif_node *iter;
@ -217,7 +217,7 @@ static struct if_option_group local_option_group = {
.group = local_options .group = local_options
}; };
int static int
ifquery_main(int argc, char *argv[]) ifquery_main(int argc, char *argv[])
{ {
struct lif_dict state = {}; struct lif_dict state = {};

View file

@ -27,7 +27,7 @@
static bool up; static bool up;
bool static bool
is_ifdown() is_ifdown()
{ {
if (strstr(argv0, "ifdown") != NULL) if (strstr(argv0, "ifdown") != NULL)
@ -36,7 +36,7 @@ is_ifdown()
return false; return false;
} }
int static int
acquire_state_lock(const char *state_path, const char *lifname) acquire_state_lock(const char *state_path, const char *lifname)
{ {
if (exec_opts.mock || exec_opts.no_lock) if (exec_opts.mock || exec_opts.no_lock)
@ -94,7 +94,7 @@ acquire_state_lock(const char *state_path, const char *lifname)
return fd; return fd;
} }
bool static bool
skip_interface(struct lif_interface *iface, const char *ifname, struct lif_dict *state, bool update_state) skip_interface(struct lif_interface *iface, const char *ifname, struct lif_dict *state, bool update_state)
{ {
if (iface->is_template) if (iface->is_template)
@ -146,7 +146,7 @@ skip_interface(struct lif_interface *iface, const char *ifname, struct lif_dict
return false; return false;
} }
bool static bool
change_interface(struct lif_interface *iface, struct lif_dict *collection, struct lif_dict *state, const char *ifname, bool update_state) change_interface(struct lif_interface *iface, struct lif_dict *collection, struct lif_dict *state, const char *ifname, bool update_state)
{ {
int lockfd = acquire_state_lock(exec_opts.state_file, ifname); int lockfd = acquire_state_lock(exec_opts.state_file, ifname);
@ -194,7 +194,7 @@ change_interface(struct lif_interface *iface, struct lif_dict *collection, struc
return true; return true;
} }
bool static bool
change_auto_interfaces(struct lif_dict *collection, struct lif_dict *state, struct match_options *opts) change_auto_interfaces(struct lif_dict *collection, struct lif_dict *state, struct match_options *opts)
{ {
struct lif_node *iter; struct lif_node *iter;
@ -222,7 +222,7 @@ change_auto_interfaces(struct lif_dict *collection, struct lif_dict *state, stru
return true; return true;
} }
int static int
update_state_file_and_exit(int rc, struct lif_dict *state) update_state_file_and_exit(int rc, struct lif_dict *state)
{ {
if (exec_opts.mock) if (exec_opts.mock)
@ -243,7 +243,7 @@ update_state_file_and_exit(int rc, struct lif_dict *state)
return rc; return rc;
} }
int static int
ifupdown_main(int argc, char *argv[]) ifupdown_main(int argc, char *argv[])
{ {
up = !is_ifdown(); up = !is_ifdown();

View file

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

View file

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

View file

@ -62,7 +62,7 @@ struct if_applet *applet_table[] = {
&ifupdown_applet, &ifupdown_applet,
}; };
int static int
applet_cmp(const void *a, const void *b) applet_cmp(const void *a, const void *b)
{ {
const char *key = a; const char *key = a;
@ -101,7 +101,7 @@ main(int argc, char *argv[])
return self_applet->main(argc, argv); return self_applet->main(argc, argv);
} }
int static int
multicall_main(int argc, char *argv[]) multicall_main(int argc, char *argv[])
{ {
if (argc < 2) if (argc < 2)

View file

@ -272,4 +272,4 @@ used for an interface, use the ifquery(8) command.
If you have further questions about how to use ifupdown-ng to If you have further questions about how to use ifupdown-ng to
configure a specific scenario, drop by the configure a specific scenario, drop by the
[ifupdown-ng IRC channel](irc://irc.as7007.net/#ifupdown-ng). [ifupdown-ng IRC channel](irc://irc.oftc.net/#ifupdown-ng).

View file

@ -45,6 +45,10 @@ configured in the configuration database.
*-S, --state-file* _FILE_ *-S, --state-file* _FILE_
Use _FILE_ as the state database. Use _FILE_ as the state database.
*-T, --timeout* _TIMEOUT_
Wait up to _TIMEOUT_ seconds for executors to complete before
raising an error.
*-V, --version* *-V, --version*
Print the ifupdown-ng version and exit. Print the ifupdown-ng version and exit.

View file

@ -43,6 +43,10 @@ stanzas between different formats.
*-S, --state-file* _FILE_ *-S, --state-file* _FILE_
Use _FILE_ as the state database. Use _FILE_ as the state database.
*-T, --timeout* _TIMEOUT_
Wait up to _TIMEOUT_ seconds for executors to complete before
raising an error.
*-V, --version* *-V, --version*
Print the ifupdown-ng version and exit. Print the ifupdown-ng version and exit.

View file

@ -62,6 +62,10 @@ configuration file to the current format.
*-S, --state-file* _FILE_ *-S, --state-file* _FILE_
Use _FILE_ as the state database. Use _FILE_ as the state database.
*-T, --timeout* _TIMEOUT_
Wait up to _TIMEOUT_ seconds for executors to complete before
raising an error.
*-V, --version* *-V, --version*
Print the ifupdown-ng version and exit. Print the ifupdown-ng version and exit.

View file

@ -48,6 +48,10 @@ configured in the configuration database.
*-S, --state-file* _FILE_ *-S, --state-file* _FILE_
Use _FILE_ as the state database. Use _FILE_ as the state database.
*-T, --timeout* _TIMEOUT_
Wait up to _TIMEOUT_ seconds for executors to complete before
raising an error.
*-V, --version* *-V, --version*
Print the ifupdown-ng version and exit. Print the ifupdown-ng version and exit.

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

View file

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

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. *ifup*(8) and *ifdown*(8) to introspect and change system state.
In most cases, syntax from legacy implementations is supported as In most cases, syntax from legacy implementations is supported as
well, but that syntax is not discussed here. well, but that syntax is not discussed in detail here.
# FILE SYNTAX # FILE SYNTAX
@ -24,6 +24,8 @@ value combination that is related to an *object*. Triples which
are not associated with an *object* are considered to be part are not associated with an *object* are considered to be part
of the root of the configuration tree. of the root of the configuration tree.
All keywords are case-sensitive and are expected to be lower-case.
The following is a simple example of a stanza: The following is a simple example of a stanza:
``` ```
@ -64,11 +66,11 @@ the system will only respond to certain keywords by default:
*address* _address_ *address* _address_
Associates an IPv4 or IPv6 address in CIDR notation with Associates an IPv4 or IPv6 address in CIDR notation with
the parent interface. the parent interface. If an IP address without a prefix
length is given a given _netmask_ attribute is used if present.
*gateway* _address_ If neither a prefix length nor a _netmask_ are given a /24 or /64
Associates an IPv4 or IPv6 address with the parent interface prefix length is presumed for IPv4 / IPv6 as of compatibility
for use as a default route (gateway). reasons to classic ifupdown.
*netmask* _netmask_ *netmask* _netmask_
Associates a fallback netmask with the parent interface for Associates a fallback netmask with the parent interface for
@ -83,6 +85,11 @@ the system will only respond to certain keywords by default:
For compatiblity with ifupdown and ifupdown2, _pointopoint_ is For compatiblity with ifupdown and ifupdown2, _pointopoint_ is
an alias for this parameter. an alias for this parameter.
*gateway* _address_
Associates an IPv4 or IPv6 address with the parent interface
for use as a default route (gateway). This usually is given
once for IPv4 and once for IPv6 (in a Dual-Stack setup).
*link-type* _link-type_ *link-type* _link-type_
Denotes the link-type of the interface. When set to _dummy_, Denotes the link-type of the interface. When set to _dummy_,
the interface is created as a virtual dummy interfaces. the interface is created as a virtual dummy interfaces.
@ -171,7 +178,8 @@ most common executors are:
*tunnel* *tunnel*
The interface is a tunnel. Configuration of tunnels The interface is a tunnel. Configuration of tunnels
requires the *tunnel* package to be installed. requires the *tunnel* package to be installed on Alpine
Linux.
*vrf* *vrf*
The interface is a VRF. Configuration of VRFs requires The interface is a VRF. Configuration of VRFs requires
@ -242,6 +250,7 @@ iface eth0
*interfaces-forward*(5) *interfaces-forward*(5)
*interfaces-mpls*(5) *interfaces-mpls*(5)
*interfaces-ppp*(5) *interfaces-ppp*(5)
*interfaces-tunnel*(5)
*interfaces-vrf*(5) *interfaces-vrf*(5)
*interfaces-vxlan*(5) *interfaces-vxlan*(5)
*interfaces-wifi*(5) *interfaces-wifi*(5)

View file

@ -26,34 +26,31 @@ configure_addresses() {
PEER="" PEER=""
fi fi
if [ -z "${MOCK}" -a "${1}" = "del" ]; then ${MOCK} ip "${addrfam}" addr add "${addr}" ${PEER} dev "${IFACE}"
# When having multiple addresses set from the same prefix they might/will(?) be configured
# as 'secondary' and implicitly removed when removing the non-secondary address. This
# leads ip complaining about not being able to remove the secondaries as they are already
# gone. So we ignore errors while deconfiguring addresses as they liked occur when removing
# a vanish address anyway.
${MOCK} ip "${addrfam}" addr "${1}" "${addr}" ${PEER} dev "${IFACE}" 2>/dev/null
else
${MOCK} ip "${addrfam}" addr "${1}" "${addr}" ${PEER} dev "${IFACE}"
fi
done done
} }
configure_gateways() { configure_gateways() {
for gw in ${IF_GATEWAYS}; do for gw in ${IF_GATEWAYS}; do
addrfam=$(addr_family ${gw}) addrfam=$(addr_family ${gw})
${MOCK} ip "${addrfam}" route "${1}" default via "${gw}" ${VRF_TABLE} ${METRIC} dev "${IFACE}" ${MOCK} ip "${addrfam}" route add default via "${gw}" ${VRF_TABLE} ${METRIC} dev "${IFACE}"
done done
} }
flush() {
cmd="addr"
arg="dev ${IFACE}"
${MOCK} ip ${cmd} flush ${arg}
}
case "$PHASE" in case "$PHASE" in
up) up)
configure_addresses add configure_addresses add
configure_gateways add configure_gateways add
;; ;;
down) down)
configure_gateways del flush
configure_addresses del
;; ;;
*) exit 0 ;; *) exit 0 ;;
esac esac

View file

@ -2,20 +2,27 @@
# Based on alpine's tunnel configuration script. # Based on alpine's tunnel configuration script.
# Copyright (c) 2017 Kaarle Ritvanen # Copyright (c) 2017 Kaarle Ritvanen
# Copyright (c) 2020 Ariadne Conill (extended for ifupdown-ng) # Copyright (c) 2020 Ariadne Conill (extended for ifupdown-ng)
# Copyright (c) 2021 Maximilian Wilhelm (make sure mode/type is 1st parameter) # Copyright (c) 2021 Maximilian Wilhelm (make sure mode/type is 1st parameter, add more options)
[ -z "$IF_TUNNEL_LOCAL" ] && exit 1 [ -z "$IF_TUNNEL_LOCAL" -a -z "$IF_TUNNEL_LOCAL_DEV" ] && exit 1
[ -z "$IF_TUNNEL_REMOTE" ] && exit 1 [ -z "$IF_TUNNEL_REMOTE" ] && exit 1
[ -z "$IF_TUNNEL_MODE" ] && exit 1 [ -z "$IF_TUNNEL_MODE" ] && exit 1
[ -n "$VERBOSE" ] && set -x [ -n "$VERBOSE" ] && set -x
yesno() {
case "$1" in
yes|1) echo 1 ;;
*) echo 0 ;;
esac
}
# Figure out address familiy # Figure out address familiy
FAMILY="-4" FAMILY="4"
case "$IF_TUNNEL_MODE" in case "$IF_TUNNEL_MODE" in
vti6|ipip6|ip6*) vti6|ipip6|ip6*)
FAMILY="-6" FAMILY="6"
;; ;;
esac esac
@ -41,6 +48,58 @@ case "${IF_TUNNEL_MODE}" in
esac 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 # Mangle residual IF_TUNNEL_* params into single string
PARAMS=$(set | sed -E ' PARAMS=$(set | sed -E '
s/^IF_TUNNEL_([A-Z0-9_]+)=(.+)/\1\n\2/ s/^IF_TUNNEL_([A-Z0-9_]+)=(.+)/\1\n\2/
@ -58,12 +117,12 @@ PARAMS=$(set | sed -E '
case "$PHASE" in case "$PHASE" in
create) create)
${MOCK} eval ip $FAMILY $OBJECT add $IFACE $TYPE_KW $TUNNEL_MODE $PARAMS ${MOCK} eval ip -$FAMILY $OBJECT add $IFACE $TYPE_KW $TUNNEL_MODE $PARAMS $MORE_PARAMS
;; ;;
destroy) destroy)
${MOCK} ip $FAMILY $OBJECT del $IFACE ${MOCK} ip -$FAMILY $OBJECT del $IFACE
;; ;;
depend) depend)
echo "$IF_TUNNEL_DEV" echo "${IF_TUNNEL_DEV}" "${IF_TUNNEL_LOCAL_DEV}"
;; ;;
esac esac

View file

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

View file

@ -79,7 +79,7 @@ stop_wpa_supplicant() {
[ -z "$IF_WIFI_CONFIG_PATH" ] && rm -- "$WIFI_CONFIG_PATH" [ -z "$IF_WIFI_CONFIG_PATH" ] && rm -- "$WIFI_CONFIG_PATH"
# If there is no PIDFILE, there is nothing we can do # If there is no PIDFILE, there is nothing we can do
[ ! -d "$PIDFILE" ] && return [ ! -f "$PIDFILE" ] && return
pid=$(cat "$PIDFILE") pid=$(cat "$PIDFILE")
rm -- "$PIDFILE" rm -- "$PIDFILE"

View file

@ -16,6 +16,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include "libifupdown/compat.h"
#include "libifupdown/config-file.h" #include "libifupdown/config-file.h"
#include "libifupdown/dict.h" #include "libifupdown/dict.h"
#include "libifupdown/interface.h" #include "libifupdown/interface.h"
@ -102,7 +103,7 @@ compat_ifupdown2_bridge_ports_inherit_vlans(struct lif_dict *collection)
return true; return true;
} }
extern bool bool
lif_compat_apply(struct lif_dict *collection) lif_compat_apply(struct lif_dict *collection)
{ {
if (lif_config.compat_ifupdown2_bridge_ports_inherit_vlans && if (lif_config.compat_ifupdown2_bridge_ports_inherit_vlans &&

View file

@ -17,6 +17,7 @@
#define LIBIFUPDOWN__COMPAT_H #define LIBIFUPDOWN__COMPAT_H
#include "libifupdown/config-file.h" #include "libifupdown/config-file.h"
#include "libifupdown/dict.h"
extern bool lif_compat_apply (struct lif_dict *collection); extern bool lif_compat_apply (struct lif_dict *collection);

View file

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

View file

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

View file

@ -71,7 +71,7 @@ static const struct remap_token tokens[] = {
{"hardware-irq-coalesce-tx-usecs-low", "ethtool-coalesce-tx-usecs-low"}, /* Debian ethtool integration */ {"hardware-irq-coalesce-tx-usecs-low", "ethtool-coalesce-tx-usecs-low"}, /* Debian ethtool integration */
{"hostname", "dhcp-hostname"}, /* legacy ifupdown */ {"hostname", "dhcp-hostname"}, /* legacy ifupdown */
{"key", "tunnel-key"}, /* legacy ifupdown */ {"key", "tunnel-key"}, /* legacy ifupdown */
{"leasetime", "dhcp-leastime"}, /* legacy ifupdown */ {"leasetime", "dhcp-leasetime"}, /* legacy ifupdown */
{"link-autoneg", "ethtool-ethernet-autoneg"}, /* ifupdown2 */ {"link-autoneg", "ethtool-ethernet-autoneg"}, /* ifupdown2 */
{"link-duplex", "ethtool-link-duplex"}, /* Debian ethtool integration */ {"link-duplex", "ethtool-link-duplex"}, /* Debian ethtool integration */
{"link-fec", "ethtool-link-fec"}, /* ifupdown2 */ {"link-fec", "ethtool-link-fec"}, /* ifupdown2 */
@ -100,8 +100,10 @@ static const struct remap_token tokens[] = {
{"vendor", "dhcp-vendor"}, /* legacy ifupdown */ {"vendor", "dhcp-vendor"}, /* legacy ifupdown */
{"vrf", "vrf-member"}, /* ifupdown2 */ {"vrf", "vrf-member"}, /* ifupdown2 */
{"vxlan-local-tunnelip", "vxlan-local-ip"}, /* ifupdown2 */ {"vxlan-local-tunnelip", "vxlan-local-ip"}, /* ifupdown2 */
{"vxlan-remoteip", "vxlan-remote-ip"}, /* ifupdown2 */ {"vxlan-remote-group", "vxlan-peer-group"}, /* ifupdown-ng */
{"vxlan-svcnodeip", "vxlan-remote-group"}, /* ifupdown2 */ {"vxlan-remoteip", "vxlan-peer-ips"}, /* ifupdown2 */
{"vxlan-remote-ip", "vxlan-peer-ips"}, /* ifupdown-ng */
{"vxlan-svcnodeip", "vxlan-peer-group"}, /* ifupdown2 */
}; };
static int static int
@ -250,8 +252,8 @@ handle_hostname(struct lif_interface_file_parse_state *state, char *token, char
return true; return true;
} }
lif_dict_delete(&state->cur_iface->vars, token); lif_dict_delete(&state->cur_iface->vars, "dhcp-hostname");
lif_dict_add(&state->cur_iface->vars, token, strdup(hostname)); lif_dict_add(&state->cur_iface->vars, "dhcp-hostname", strdup(hostname));
return true; return true;
} }
@ -447,6 +449,7 @@ struct parser_keyword {
static const struct parser_keyword keywords[] = { static const struct parser_keyword keywords[] = {
{"address", handle_address}, {"address", handle_address},
{"auto", handle_auto}, {"auto", handle_auto},
{"dhcp-hostname", handle_hostname},
{"gateway", handle_gateway}, {"gateway", handle_gateway},
{"hostname", handle_hostname}, {"hostname", handle_hostname},
{"iface", handle_iface}, {"iface", handle_iface},

View file

@ -216,7 +216,7 @@ lif_interface_use_executor(struct lif_interface *interface, const char *executor
if (uname(&un) < 0) if (uname(&un) < 0)
return; return;
lif_dict_add(&interface->vars, "hostname", strdup(un.nodename)); lif_dict_add(&interface->vars, "dhcp-hostname", strdup(un.nodename));
} }
void void

View file

@ -94,7 +94,8 @@ query_dependents_from_executors(const struct lif_execute_opts *opts, char *const
struct lif_execute_opts exec_opts = { struct lif_execute_opts exec_opts = {
.verbose = opts->verbose, .verbose = opts->verbose,
.executor_path = opts->executor_path, .executor_path = opts->executor_path,
.interfaces_file = opts->interfaces_file .interfaces_file = opts->interfaces_file,
.timeout = opts->timeout,
}; };
if (strcmp(entry->key, "use")) if (strcmp(entry->key, "use"))
@ -114,7 +115,7 @@ query_dependents_from_executors(const struct lif_execute_opts *opts, char *const
return true; return true;
} }
bool static bool
append_to_buffer(char **buffer, size_t *buffer_len, char **end, const char *value) append_to_buffer(char **buffer, size_t *buffer_len, char **end, const char *value)
{ {
size_t value_len = strlen (value); size_t value_len = strlen (value);

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

@ -40,7 +40,10 @@ tests_init \
default_netmask_v4 \ default_netmask_v4 \
default_netmask_v6 \ default_netmask_v6 \
stanza_merging_with_cidr \ stanza_merging_with_cidr \
stanza_merging_without_cidr stanza_merging_without_cidr \
dhcp_hostname_rewrite \
dhcp_hostname_inference \
dhcp_hostname_replacement
noargs_body() { noargs_body() {
atf_check -s exit:1 -e ignore ifquery -S/dev/null atf_check -s exit:1 -e ignore ifquery -S/dev/null
@ -272,3 +275,22 @@ stanza_merging_without_cidr_body() {
-o match:"203.0.113.2/24" \ -o match:"203.0.113.2/24" \
ifquery -i $FIXTURES/stanza-merging.interfaces -p address without-cidr 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

@ -8,9 +8,7 @@ tests_init \
up_ptp \ up_ptp \
down \ down \
vrf_up \ vrf_up \
vrf_down \ metric_up
metric_up \
metric_down
up_body() { up_body() {
export IFACE=eth0 PHASE=up MOCK=echo IF_ADDRESSES="203.0.113.2/24 2001:db8:1000:2::2/64" \ export IFACE=eth0 PHASE=up MOCK=echo IF_ADDRESSES="203.0.113.2/24 2001:db8:1000:2::2/64" \
@ -38,10 +36,7 @@ down_body() {
export IFACE=eth0 PHASE=down MOCK=echo IF_ADDRESSES="203.0.113.2/24 2001:db8:1000:2::2/64" \ export IFACE=eth0 PHASE=down MOCK=echo IF_ADDRESSES="203.0.113.2/24 2001:db8:1000:2::2/64" \
IF_GATEWAYS="203.0.113.1 2001:db8:1000:2::1" IF_GATEWAYS="203.0.113.1 2001:db8:1000:2::1"
atf_check -s exit:0 \ atf_check -s exit:0 \
-o match:'addr del 203.0.113.2/24 dev eth0' \ -o match:'addr flush dev eth0' \
-o match:'addr del 2001:db8:1000:2::2/64 dev eth0' \
-o match:'route del default via 203.0.113.1 metric 1 dev eth0' \
-o match:'route del default via 2001:db8:1000:2::1 metric 1 dev eth0' \
${EXECUTOR} ${EXECUTOR}
} }
@ -52,23 +47,9 @@ vrf_up_body() {
${EXECUTOR} ${EXECUTOR}
} }
vrf_down_body() {
export IFACE=vrf-red PHASE=down MOCK=echo IF_GATEWAYS=203.0.113.2 IF_VRF_TABLE=1
atf_check -s exit:0 \
-o match:'route del default via 203.0.113.2 table 1' \
${EXECUTOR}
}
metric_up_body() { metric_up_body() {
export IFACE=vrf-red PHASE=up MOCK=echo IF_GATEWAYS=203.0.113.2 IF_VRF_TABLE=1 IF_METRIC=20 export IFACE=vrf-red PHASE=up MOCK=echo IF_GATEWAYS=203.0.113.2 IF_VRF_TABLE=1 IF_METRIC=20
atf_check -s exit:0 \ atf_check -s exit:0 \
-o match:'route add default via 203.0.113.2 table 1 metric 20' \ -o match:'route add default via 203.0.113.2 table 1 metric 20' \
${EXECUTOR} ${EXECUTOR}
} }
metric_down_body() {
export IFACE=vrf-red PHASE=down MOCK=echo IF_GATEWAYS=203.0.113.2 IF_VRF_TABLE=1 IF_METRIC=20
atf_check -s exit:0 \
-o match:'route del default via 203.0.113.2 table 1 metric 20' \
${EXECUTOR}
}

View file

@ -5,7 +5,8 @@ EXECUTOR="$(atf_get_srcdir)/../../executor-scripts/linux/vxlan"
tests_init \ tests_init \
create_simple \ create_simple \
create_ucast \ create_ucast_ptp \
create_ucast_ptmp \
create_mcast \ create_mcast \
create_physdev \ create_physdev \
create_dstport \ create_dstport \
@ -18,14 +19,24 @@ create_simple_body() {
${EXECUTOR} ${EXECUTOR}
} }
create_ucast_body() { create_ucast_ptp_body() {
export IFACE=vx_foo PHASE=create MOCK=echo IF_VXLAN_ID=2342 IF_VXLAN_REMOTE_IP=192.2.0.42 export IFACE=vx_foo PHASE=create MOCK=echo IF_VXLAN_ID=2342 IF_VXLAN_PEER_IPS=192.2.0.42
atf_check -s exit:0 -o match:'ip link add vx_foo type vxlan id 2342 remote 192.2.0.42' \ atf_check -s exit:0 -o match:'ip link add vx_foo type vxlan id 2342 remote 192.2.0.42' \
${EXECUTOR} ${EXECUTOR}
} }
create_ucast_ptmp_body() {
export IFACE=vx_foo PHASE=create MOCK=echo IF_VXLAN_ID=2342 IF_VXLAN_PEER_IPS="10.0.0.1 10.0.0.2 10.0.0.3"
atf_check -s exit:0 \
-o match:'ip link add vx_foo type vxlan id 2342 dstport 4789' \
-o match:'bridge fdb append 00:00:00:00:00:00 dev vx_foo dst 10.0.0.1 self permanent' \
-o match:'bridge fdb append 00:00:00:00:00:00 dev vx_foo dst 10.0.0.2 self permanent' \
-o match:'bridge fdb append 00:00:00:00:00:00 dev vx_foo dst 10.0.0.3 self permanent' \
${EXECUTOR}
}
create_mcast_body() { create_mcast_body() {
export IFACE=vx_foo PHASE=create MOCK=echo IF_VXLAN_ID=2342 IF_VXLAN_REMOTE_GROUP=225.0.8.15 export IFACE=vx_foo PHASE=create MOCK=echo IF_VXLAN_ID=2342 IF_VXLAN_PEER_GROUP=225.0.8.15
atf_check -s exit:0 -o match:'ip link add vx_foo type vxlan id 2342 group 225.0.8.15' \ atf_check -s exit:0 -o match:'ip link add vx_foo type vxlan id 2342 group 225.0.8.15' \
${EXECUTOR} ${EXECUTOR}
} }