Compare commits
28 commits
ifupdown-n
...
main
Author | SHA1 | Date | |
---|---|---|---|
|
e978d1a42c | ||
|
80074c997f | ||
|
0e99af7669 | ||
|
b75e509f3d | ||
|
d83c8259e6 | ||
|
2477e7266c | ||
|
97b1a11be0 | ||
|
941d7c51d7 | ||
|
7a46b61996 | ||
|
571786ae91 | ||
|
dd3a99cfa8 | ||
|
67fc80fc78 | ||
|
65e5e07c5f | ||
|
0547924ee8 | ||
|
4033f6374f | ||
|
b25448f42f | ||
|
96fa8ccbf9 | ||
|
108c88014d | ||
|
9c00111932 | ||
|
12ffc3de12 | ||
|
34753136b8 | ||
|
559b4ad942 | ||
|
ed9aae85ed | ||
|
73d9788fab | ||
|
2b358fafc6 | ||
|
9467f85067 | ||
|
6175961880 | ||
|
c8a05a742b |
31 changed files with 516 additions and 81 deletions
3
COPYING
3
COPYING
|
@ -1,4 +1,5 @@
|
||||||
Copyright (c) 2020 Ariadne Conill <ariadne@dereferenced.org>
|
Copyright (c) 2020-2021 Ariadne Conill <ariadne@dereferenced.org>
|
||||||
|
Copyright (c) 2020-2021 Maximilian Wilhelm <max@sdn.clinic>
|
||||||
|
|
||||||
Permission to use, copy, modify, and/or distribute this software for any
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
purpose with or without fee is hereby granted, provided that the above
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
|
11
Makefile
11
Makefile
|
@ -4,7 +4,7 @@ LIBBSD_CFLAGS =
|
||||||
LIBBSD_LIBS =
|
LIBBSD_LIBS =
|
||||||
|
|
||||||
PACKAGE_NAME := ifupdown-ng
|
PACKAGE_NAME := ifupdown-ng
|
||||||
PACKAGE_VERSION := 0.11.2
|
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 \
|
||||||
|
|
|
@ -39,11 +39,11 @@ On glibc systems, you must install `libbsd-dev` or equivalent and additionally d
|
||||||
make LIBBSD_CFLAGS="$(pkg-config --cflags libbsd-overlay)" LIBBSD_LIBS="$(pkg-config --cflags --libs libbsd-overlay)"
|
make LIBBSD_CFLAGS="$(pkg-config --cflags libbsd-overlay)" LIBBSD_LIBS="$(pkg-config --cflags --libs libbsd-overlay)"
|
||||||
make install
|
make install
|
||||||
|
|
||||||
To run the tests, do `make check`. Running the checks requires `kyua` (`apk add kyua`, not packaged for Debian).
|
To run the tests, do `make check`. Running the checks requires `kyua` (`apk add kyua` / `apt install kyua`).
|
||||||
|
|
||||||
To build the documentation, do `make docs` and `make install_docs`. Building
|
To build the documentation, do `make docs` and `make install_docs`. Building
|
||||||
the documentation requires scdoc (`apk add scdoc` / `apt install scdoc`).
|
the documentation requires scdoc (`apk add scdoc` / `apt install scdoc`).
|
||||||
|
|
||||||
## Discussion
|
## Discussion
|
||||||
|
|
||||||
Discuss ifupdown-ng on IRC: irc.as7007.net #ifupdown-ng
|
Discuss ifupdown-ng on IRC: irc.oftc.net #ifupdown-ng
|
||||||
|
|
|
@ -17,7 +17,8 @@
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "multicall.h"
|
#include "cmd/multicall.h"
|
||||||
|
#include "cmd/ifctrstat-linux.h"
|
||||||
|
|
||||||
struct counter_desc {
|
struct counter_desc {
|
||||||
const char *name;
|
const char *name;
|
||||||
|
@ -41,7 +42,7 @@ counter_compare(const void *key, const void *candidate)
|
||||||
return strcasecmp((const char *)key, ((struct counter_desc *)candidate)->name);
|
return strcasecmp((const char *)key, ((struct counter_desc *)candidate)->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *
|
const char *
|
||||||
read_counter(const char *interface, const char *counter)
|
read_counter(const char *interface, const char *counter)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
|
22
cmd/ifctrstat-linux.h
Normal file
22
cmd/ifctrstat-linux.h
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
/*
|
||||||
|
* cmd/ifctrstat-linux.c
|
||||||
|
* Purpose: Implement ifctrstat system-specific routines for Linux
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021 Maximilian Wilhelm <max@sdn.clinic>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* This software is provided 'as is' and without any warranty, express or
|
||||||
|
* implied. In no event shall the authors be liable for any damages arising
|
||||||
|
* from the use of this software.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef IFUPDOWN_IFCTRSTAT_LINUX__H__GUARD
|
||||||
|
#define IFUPDOWN_IFCTRSTAT_LINUX__H__GUARD
|
||||||
|
|
||||||
|
extern const char * read_counter(const char *interface, const char *counter);
|
||||||
|
|
||||||
|
#endif
|
|
@ -20,12 +20,11 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "libifupdown/libifupdown.h"
|
#include "libifupdown/libifupdown.h"
|
||||||
#include "cmd/multicall.h"
|
#include "cmd/multicall.h"
|
||||||
|
#include "cmd/ifctrstat-linux.h"
|
||||||
|
|
||||||
extern struct counter_desc { const char *name; const void *data; } avail_counters[];
|
extern struct counter_desc { const char *name; const void *data; } avail_counters[];
|
||||||
extern int avail_counters_count;
|
extern int avail_counters_count;
|
||||||
|
|
||||||
extern const char *read_counter(const char *interface, const char *counter);
|
|
||||||
|
|
||||||
static bool show_label = true;
|
static bool show_label = true;
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
@ -96,7 +95,7 @@ ifctrstat_set_nolabel(const char *opt_arg)
|
||||||
show_label = false;
|
show_label = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
static int
|
||||||
ifctrstat_main(int argc, char *argv[])
|
ifctrstat_main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
if (optind >= argc)
|
if (optind >= argc)
|
||||||
|
|
|
@ -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 = {};
|
||||||
|
|
|
@ -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 = {};
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -21,10 +21,13 @@
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include "cmd/multicall.h"
|
#include "cmd/multicall.h"
|
||||||
|
|
||||||
|
#define DEFAULT_TIMEOUT 300
|
||||||
|
|
||||||
struct lif_execute_opts exec_opts = {
|
struct lif_execute_opts exec_opts = {
|
||||||
.interfaces_file = INTERFACES_FILE,
|
.interfaces_file = INTERFACES_FILE,
|
||||||
.executor_path = EXECUTOR_PATH,
|
.executor_path = EXECUTOR_PATH,
|
||||||
.state_file = STATE_FILE
|
.state_file = STATE_FILE,
|
||||||
|
.timeout = DEFAULT_TIMEOUT,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -74,6 +77,14 @@ set_force(const char *opt_arg)
|
||||||
exec_opts.force = true;
|
exec_opts.force = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
set_timeout(const char *opt_arg)
|
||||||
|
{
|
||||||
|
exec_opts.timeout = atoi(opt_arg);
|
||||||
|
if (exec_opts.timeout < 0)
|
||||||
|
exec_opts.timeout = DEFAULT_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
static struct if_option exec_options[] = {
|
static struct if_option exec_options[] = {
|
||||||
{'f', "force", NULL, "force (de)configuration", false, set_force},
|
{'f', "force", NULL, "force (de)configuration", false, set_force},
|
||||||
{'i', "interfaces", "interfaces FILE", "use FILE for interface definitions", true, set_interfaces_file},
|
{'i', "interfaces", "interfaces FILE", "use FILE for interface definitions", true, set_interfaces_file},
|
||||||
|
@ -82,6 +93,7 @@ static struct if_option exec_options[] = {
|
||||||
{'v', "verbose", NULL, "show what commands are being run", false, set_verbose},
|
{'v', "verbose", NULL, "show what commands are being run", false, set_verbose},
|
||||||
{'E', "executor-path", "executor-path PATH", "use PATH for executor directory", true, set_executor_path},
|
{'E', "executor-path", "executor-path PATH", "use PATH for executor directory", true, set_executor_path},
|
||||||
{'S', "state-file", "state-file FILE", "use FILE for state", true, set_state_file},
|
{'S', "state-file", "state-file FILE", "use FILE for state", true, set_state_file},
|
||||||
|
{'T', "timeout", "timeout TIMEOUT", "wait TIMEOUT seconds for executors to complete", true, set_timeout},
|
||||||
};
|
};
|
||||||
|
|
||||||
struct if_option_group exec_option_group = {
|
struct if_option_group exec_option_group = {
|
||||||
|
|
|
@ -39,7 +39,7 @@ set_include_pattern(const char *opt_arg)
|
||||||
static void
|
static void
|
||||||
set_exclude_pattern(const char *opt_arg)
|
set_exclude_pattern(const char *opt_arg)
|
||||||
{
|
{
|
||||||
match_opts.include_pattern = opt_arg;
|
match_opts.exclude_pattern = opt_arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct if_option match_options[] = {
|
static struct if_option match_options[] = {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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).
|
||||||
|
|
|
@ -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.
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
||||||
|
|
|
@ -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
161
doc/interfaces-tunnel.scd
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
interfaces-tunnel(5)
|
||||||
|
|
||||||
|
# NAME
|
||||||
|
|
||||||
|
*interfaces-tunnel* - Tunnel extensions for the interfaces(5) file format
|
||||||
|
|
||||||
|
# DESCRIPTION
|
||||||
|
|
||||||
|
The following options set up tunneling interfaces with ifupdown-ng.
|
||||||
|
|
||||||
|
# TUNNEL-RELATED OPTIONS
|
||||||
|
|
||||||
|
A tunnel interface must have a mode, remote IP and a local IP or device
|
||||||
|
set, all other options are optional.
|
||||||
|
|
||||||
|
*tunnel-mode* _mode_
|
||||||
|
Denotes the mode for this tunnel. Basically all tunnel modes supported
|
||||||
|
by Linux / iproute2 are supported as well. This includes but is not
|
||||||
|
limited to _gre_/_gretap_, _ip6gre_/_ip6gretap_, _ipip_/_ip6ip_/_sit_.
|
||||||
|
|
||||||
|
*tunnel-local* _IP_
|
||||||
|
Denotes the IP address used as the local tunnel endpoint. According
|
||||||
|
to the _tunnel-mode_ an IPv4 or IPv6 address has to be given.
|
||||||
|
For compatiblity to ifupdown1 _local_ is an alias for this option.
|
||||||
|
|
||||||
|
*tunnel-local-dev* _interface_
|
||||||
|
When the local IP address the tunnel should be established from isn't
|
||||||
|
static and therefore might change (e.g. configured by DHCP or PPP) it
|
||||||
|
might be desireable to just use the address configured on _interface_.
|
||||||
|
When _tunnel-local-dev_ is given instead of _tunnel-local_ ifupdown-ng
|
||||||
|
will try to determine the IP address set on the given _interface_ with
|
||||||
|
respect to the address family required to set up a tunnel of the given
|
||||||
|
_mode_ and use this to set up the tunnel.
|
||||||
|
|
||||||
|
*tunnel-remote* _IP_
|
||||||
|
Denotes the IP address used as the remote tunnel endpoint. According
|
||||||
|
to the _tunnel-mode_ an IPv4 or IPv6 address has to be given.
|
||||||
|
For compatiblity to ifupdown1 _endpoint_ is an alias for this option.
|
||||||
|
|
||||||
|
*tunnel-physdev* _interface_
|
||||||
|
Denotes the _interface_ the encapsulated packets should be sent out by.
|
||||||
|
This comes in handy when using VRFs to denote that the local tunnel
|
||||||
|
endpoint should be terminated in VRF _interface_ or the VRF associated
|
||||||
|
with _interface_.
|
||||||
|
|
||||||
|
Note: Depending on the _mode_ of the tunnel either the VRF interface
|
||||||
|
or the real underlay interface may have to given as _interface_.
|
||||||
|
|
||||||
|
*tunnel-ttl* _ttl_
|
||||||
|
Denotes the TTL value to use in outgoing packets. _ttl_ is a number in the
|
||||||
|
range 1 - 255 whereas 0 is a special value meaning that packets inherit the
|
||||||
|
TTL value. The default for IPv4 tunnels is to inherit the TTL, for IPv6
|
||||||
|
tunnels it's 64. For compatiblity to ifupdown1 _ttl_ is an alias for this option.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# IPIP/SIT-RELATED OPTIONS
|
||||||
|
|
||||||
|
*tunnel-encap* _encap_
|
||||||
|
Denotes the type of secondary UDP encapsulation to use for this tunnel
|
||||||
|
if any. Supported _encap_ values are _fou_, _gue_, and _none_.
|
||||||
|
_fou_ indicates Foo-Over-UDP, _gue_ indicates Generic UDP Encapsulation.
|
||||||
|
|
||||||
|
# GRE-RELATED OPTIONS
|
||||||
|
|
||||||
|
*tunnel-encap* _encap_
|
||||||
|
Denotes the type of secondary UDP encapsulation to use for this tunnel
|
||||||
|
if any. Supported _encap_ values are _fou_, _gue_, and _none_.
|
||||||
|
_fou_ indicates Foo-Over-UDP, _gue_ indicates Generic UDP Encapsulation.
|
||||||
|
|
||||||
|
*tunnel-key* _key_
|
||||||
|
Denotes the_key to used for keyed GRE to allow multiple tunnels between
|
||||||
|
the same two endpoints. _key_ is either a number or an IPv4 address-
|
||||||
|
like dotted quad. The key parameter specifies the same key to use in both
|
||||||
|
directions. The _tunnel-ikey_ and _tunnel-okey_ parameters specify different
|
||||||
|
keys for input and output. For compatiblity to ifupdown1 _key_ is an alias
|
||||||
|
for this option.
|
||||||
|
|
||||||
|
*tunnel-hoplimit* _ttl_
|
||||||
|
Denotes the Hop Limit value to use in outgoing packets for _ip6gre_/_ip6gretap_
|
||||||
|
tunnels.
|
||||||
|
|
||||||
|
*tunnel-ignore-df* _bool_
|
||||||
|
Denotes wether to enable/disable IPv4 DF suppression on this tunnel. Normally
|
||||||
|
datagrams that exceed the MTU will be fragmented; the presence of the DF flag
|
||||||
|
inhibits this, resulting instead in an ICMP Unreachable (Fragmentation Required)
|
||||||
|
message. Enabling this attribute causes the DF flag to be ignored.
|
||||||
|
|
||||||
|
*tunnel-ikey* _key_
|
||||||
|
Denotes the key to used for keyed GRE for packets received. See _tunnel-key_
|
||||||
|
for details.
|
||||||
|
|
||||||
|
*tunnel-okey* _key_
|
||||||
|
Denotes the key to used for keyed GRE for packets sent out. See _tunnel-key_
|
||||||
|
for details.
|
||||||
|
|
||||||
|
*tunnel-pmtudisc* _bool_
|
||||||
|
Denotes wether to enable/disable Path MTU Discovery on this tunnel. It is
|
||||||
|
enabled by default. Note that a fixed ttl is incompatible with this option:
|
||||||
|
tunneling with a fixed ttl always makes pmtu discovery.
|
||||||
|
|
||||||
|
*tunnel-tos* _tos_
|
||||||
|
Denotes the TOS value to use in outgoing packets.
|
||||||
|
|
||||||
|
|
||||||
|
# EXAMPLES
|
||||||
|
|
||||||
|
A simple GRE tunnel
|
||||||
|
|
||||||
|
```
|
||||||
|
auto gre0
|
||||||
|
iface gre0
|
||||||
|
tunnel-mode gre
|
||||||
|
tunnel-remote 198.51.100.1
|
||||||
|
tunnel-local 203.0.113.2
|
||||||
|
#
|
||||||
|
address 192.0.2.42/24
|
||||||
|
address 2001:db8::42/64
|
||||||
|
```
|
||||||
|
|
||||||
|
A GRE tunnel where the local IP is learned from _eth0_
|
||||||
|
|
||||||
|
```
|
||||||
|
auto gre1
|
||||||
|
iface gre1
|
||||||
|
tunnel-mode gre
|
||||||
|
tunnel-remote 198.51.100.1
|
||||||
|
tunnel-local-dev eth0
|
||||||
|
#
|
||||||
|
address 192.0.2.42/24
|
||||||
|
address 2001:db8::42/64
|
||||||
|
```
|
||||||
|
|
||||||
|
A GRE tunnel which transfers encapasulated packets via _eth0_ which is part
|
||||||
|
of a VRF.
|
||||||
|
|
||||||
|
```
|
||||||
|
auto eth0
|
||||||
|
iface eth0
|
||||||
|
address 203.0.113.2/24
|
||||||
|
gateway 203.0.113.1
|
||||||
|
vrf vrf_external
|
||||||
|
|
||||||
|
auto tun-vrf
|
||||||
|
iface tun-vrf
|
||||||
|
tunnel-mode gre
|
||||||
|
tunnel-remote 198.51.100.1
|
||||||
|
tunnel-local 203.0.113.2
|
||||||
|
tunnel-physdev eth0
|
||||||
|
#
|
||||||
|
address 192.0.2.42/24
|
||||||
|
address 2001:db8::42/64
|
||||||
|
|
||||||
|
auto vrf_external
|
||||||
|
iface vrf_external
|
||||||
|
vrf-table 1023
|
||||||
|
```
|
||||||
|
|
||||||
|
# AUTHORS
|
||||||
|
|
||||||
|
Maximilian Wilhelm <max@sdn.clinic>
|
|
@ -32,26 +32,33 @@ other options are optional.
|
||||||
|
|
||||||
*vxlan-physdev* _interface_
|
*vxlan-physdev* _interface_
|
||||||
Specifies the physical ("underlay") device to use for tunnel
|
Specifies the physical ("underlay") device to use for tunnel
|
||||||
endpoint communication.
|
endpoint communication. This is required for setups using
|
||||||
|
multicast.
|
||||||
|
|
||||||
*vxlan-local-ip* _address_
|
*vxlan-local-ip* _address_
|
||||||
Specifies the source IP address to use in outgoing packets.
|
Specifies the source IP address to use in outgoing packets.
|
||||||
For compatiblity with ifupdown2 _vxlan-local-tunnelip_ is an
|
For compatiblity with ifupdown2 _vxlan-local-tunnelip_ is an
|
||||||
alias for this parameter.
|
alias for this parameter.
|
||||||
|
|
||||||
*vxlan-remote-ip* _address_
|
*vxlan-peer-ips* _list of IP addresses_
|
||||||
Specifies the unicast destination IP address to use in outgoing
|
Specifies the unicast destination IP address(es) to use in outgoing
|
||||||
packets when the destination link layer address is not known in
|
packets when the destination link layer address is not known in
|
||||||
the VXLAN device forwarding database. This parameter cannot be
|
the VXLAN device forwarding database. This option can be used to
|
||||||
specified with the _vxlan-remote-group_ parameter.
|
form Point-to-Point as well as Point-to-Multipoint VXLAN tunnels/
|
||||||
For compatiblity with ifupdown2 _vxlan-remoteip_ is an alias for
|
overlays depending on how many peer IPs are given. If more than one
|
||||||
this parameter.
|
IP address is given a Point-to-Multipoint overlay is being set up
|
||||||
|
and ingress / head-end replication will be used by the Linux Kernel.
|
||||||
|
This option cannot be used together with _vxlan-peer-group_ option.
|
||||||
|
For compatiblity with ifupdown2 _vxlan-remoteip_ is an alias for this option
|
||||||
|
and for compatibility with previos versions of ifupdown-ng _vxlan-remote-ip_
|
||||||
|
is an alias for this option, too.
|
||||||
|
|
||||||
*vxlan-remote-group* _multicast group_
|
*vxlan-peer-group* _multicast group_
|
||||||
Specifies the multicast group IP address to join. This parameter
|
Specifies the multicast group address to join, requires _vxlan-phsydev_
|
||||||
cannot be specified with the _vxlan-remote-ip_ parameter.
|
to be set as well. This parameter cannot be specified in combination
|
||||||
For compatibility with ifupdown2 _vxlan-svcnodeip_ is an alias for
|
with the _vxlan-peer-ips_ parameter. For compatibility with ifupdown2
|
||||||
this parameter.
|
_vxlan-svcnodeip_ is an alias for this option and for compatibility
|
||||||
|
with previos version of ifupdown-ng _vxlan-remote-group_ is an alias, too.
|
||||||
|
|
||||||
*vxlan-learning* _on/off_
|
*vxlan-learning* _on/off_
|
||||||
Specifies if unknown source link layer addresses and IP addresses
|
Specifies if unknown source link layer addresses and IP addresses
|
||||||
|
@ -79,22 +86,46 @@ iface vx_v1001_padcty
|
||||||
mtu 1560
|
mtu 1560
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The same works just fine with IPv6 in the underlay:
|
||||||
|
|
||||||
|
```
|
||||||
|
auto vx_v1400_padcty
|
||||||
|
iface vx_v1400_padcty
|
||||||
|
vxlan-id 917505
|
||||||
|
vxlan-physdev vlan1400
|
||||||
|
vxlan-peer-group ff42:1400::1
|
||||||
|
#
|
||||||
|
hwaddress f2:00:0d:01:14:00
|
||||||
|
mtu 1560
|
||||||
|
```
|
||||||
|
|
||||||
Note that the underlay must have an MTU of at least 1610 to
|
Note that the underlay must have an MTU of at least 1610 to
|
||||||
carry the encapsulated packets.
|
carry the encapsulated packets of the two VTEPs above.
|
||||||
|
|
||||||
|
|
||||||
A VTEP with one peer (point-to-point configuration):
|
A VTEP with one peer (unicast point-to-point configuration):
|
||||||
|
|
||||||
```
|
```
|
||||||
auto vx_ptp1
|
auto vx_ptp1
|
||||||
iface vx_ptp1
|
iface vx_ptp1
|
||||||
vxlan-id 2342
|
vxlan-id 2342
|
||||||
vxlan-local-ip 192.0.2.42
|
vxlan-local-ip 192.0.2.42
|
||||||
vxlan-remote-ip 198.51.100.23
|
vxlan-peer-ips 198.51.100.23
|
||||||
#
|
#
|
||||||
hwaddress f2:00:c1:01:10:01
|
hwaddress f2:00:c1:01:10:01
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
A VTEP with multiple peers (unicast point-to-multipoint with ingress / head-end replication):
|
||||||
|
|
||||||
|
```
|
||||||
|
auto vx_her
|
||||||
|
iface vx_her
|
||||||
|
vxlan-id 1337
|
||||||
|
vxlan-local-ip 2001:db8:1::1
|
||||||
|
vxlan-peer-ips 2001:db8:2::23 2001:db8:3::42 2001:db8:4::84
|
||||||
|
```
|
||||||
|
|
||||||
# AUTHORS
|
# AUTHORS
|
||||||
|
|
||||||
Maximilian Wilhelm <max@sdn.clinic>
|
Maximilian Wilhelm <max@sdn.clinic>
|
||||||
|
|
|
@ -18,6 +18,15 @@ allow to set up Wireguard VPN tunnels.
|
||||||
used. In the latter case _use wireguard_ has to be explicitly
|
used. In the latter case _use wireguard_ has to be explicitly
|
||||||
set to the interface configuration.
|
set to the interface configuration.
|
||||||
|
|
||||||
|
Be aware that the given configuration file will be loaded using
|
||||||
|
*wg setconf* and not with *wg-quick*. The file format for both
|
||||||
|
tools isn't compatible so you have to make sure you provide a
|
||||||
|
valid configuration file for the *wg* tool. If you already have
|
||||||
|
a configuration file for *wg-quick* you can set up the tunnel
|
||||||
|
manually once and then dump the configuration using *wg showconf*
|
||||||
|
and save this to _path_.
|
||||||
|
|
||||||
|
|
||||||
# EXAMPLES
|
# EXAMPLES
|
||||||
|
|
||||||
A Wireguard VPN tunnel with explicit configuration file specified
|
A Wireguard VPN tunnel with explicit configuration file specified
|
||||||
|
|
|
@ -11,7 +11,7 @@ interfaces are configured. The file is processed by *ifquery*(8),
|
||||||
*ifup*(8) and *ifdown*(8) to introspect and change system state.
|
*ifup*(8) and *ifdown*(8) to introspect and change system state.
|
||||||
|
|
||||||
In most cases, syntax from legacy implementations is supported as
|
In most cases, syntax from legacy implementations is supported as
|
||||||
well, but that syntax is not discussed here.
|
well, but that syntax is not discussed in detail here.
|
||||||
|
|
||||||
# FILE SYNTAX
|
# FILE SYNTAX
|
||||||
|
|
||||||
|
@ -24,6 +24,8 @@ value combination that is related to an *object*. Triples which
|
||||||
are not associated with an *object* are considered to be part
|
are not associated with an *object* are considered to be part
|
||||||
of the root of the configuration tree.
|
of the root of the configuration tree.
|
||||||
|
|
||||||
|
All keywords are case-sensitive and are expected to be lower-case.
|
||||||
|
|
||||||
The following is a simple example of a stanza:
|
The following is a simple example of a stanza:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -64,11 +66,11 @@ the system will only respond to certain keywords by default:
|
||||||
|
|
||||||
*address* _address_
|
*address* _address_
|
||||||
Associates an IPv4 or IPv6 address in CIDR notation with
|
Associates an IPv4 or IPv6 address in CIDR notation with
|
||||||
the parent interface.
|
the parent interface. If an IP address without a prefix
|
||||||
|
length is given a given _netmask_ attribute is used if present.
|
||||||
*gateway* _address_
|
If neither a prefix length nor a _netmask_ are given a /24 or /64
|
||||||
Associates an IPv4 or IPv6 address with the parent interface
|
prefix length is presumed for IPv4 / IPv6 as of compatibility
|
||||||
for use as a default route (gateway).
|
reasons to classic ifupdown.
|
||||||
|
|
||||||
*netmask* _netmask_
|
*netmask* _netmask_
|
||||||
Associates a fallback netmask with the parent interface for
|
Associates a fallback netmask with the parent interface for
|
||||||
|
@ -83,6 +85,11 @@ the system will only respond to certain keywords by default:
|
||||||
For compatiblity with ifupdown and ifupdown2, _pointopoint_ is
|
For compatiblity with ifupdown and ifupdown2, _pointopoint_ is
|
||||||
an alias for this parameter.
|
an alias for this parameter.
|
||||||
|
|
||||||
|
*gateway* _address_
|
||||||
|
Associates an IPv4 or IPv6 address with the parent interface
|
||||||
|
for use as a default route (gateway). This usually is given
|
||||||
|
once for IPv4 and once for IPv6 (in a Dual-Stack setup).
|
||||||
|
|
||||||
*link-type* _link-type_
|
*link-type* _link-type_
|
||||||
Denotes the link-type of the interface. When set to _dummy_,
|
Denotes the link-type of the interface. When set to _dummy_,
|
||||||
the interface is created as a virtual dummy interfaces.
|
the interface is created as a virtual dummy interfaces.
|
||||||
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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 &&
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,86 @@
|
||||||
|
|
||||||
#define SHELL "/bin/sh"
|
#define SHELL "/bin/sh"
|
||||||
|
|
||||||
|
#if defined(__linux__)
|
||||||
|
# include <sys/syscall.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* POSIX compatible fallback using waitpid(2) and usleep(3) */
|
||||||
|
static inline bool
|
||||||
|
lif_process_monitor_busyloop(pid_t child, int timeout_sec, int *status)
|
||||||
|
{
|
||||||
|
int ticks = 0;
|
||||||
|
|
||||||
|
while (ticks < timeout_sec * 20)
|
||||||
|
{
|
||||||
|
/* Ugly hack: most executors finish very quickly,
|
||||||
|
* so give them a chance to finish before sleeping.
|
||||||
|
*/
|
||||||
|
usleep(50);
|
||||||
|
|
||||||
|
if (waitpid(child, status, WNOHANG) == child)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
usleep(49950);
|
||||||
|
ticks++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(__linux__) && defined(__NR_pidfd_open)
|
||||||
|
|
||||||
|
/* TODO: remove this wrapper once musl and glibc gain pidfd_open() directly. */
|
||||||
|
static inline int
|
||||||
|
lif_pidfd_open(pid_t pid, unsigned int flags)
|
||||||
|
{
|
||||||
|
return syscall(__NR_pidfd_open, pid, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
lif_process_monitor_procdesc(pid_t child, int timeout_sec, int *status)
|
||||||
|
{
|
||||||
|
int pidfd = lif_pidfd_open(child, 0);
|
||||||
|
|
||||||
|
/* pidfd_open() not available, fall back to busyloop */
|
||||||
|
if (pidfd == -1 && errno == ENOSYS)
|
||||||
|
return lif_process_monitor_busyloop(child, timeout_sec, status);
|
||||||
|
|
||||||
|
struct pollfd pfd = {
|
||||||
|
.fd = pidfd,
|
||||||
|
.events = POLLIN,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (poll(&pfd, 1, timeout_sec * 1000) < 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
waitpid(child, status, 0);
|
||||||
|
close(pidfd);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
lif_process_monitor(const char *cmdbuf, pid_t child, int timeout_sec)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
|
||||||
|
#if defined(__linux__) && defined(__NR_pidfd_open)
|
||||||
|
if (lif_process_monitor_procdesc(child, timeout_sec, &status))
|
||||||
|
return WIFEXITED(status) && WEXITSTATUS(status) == 0;
|
||||||
|
#else
|
||||||
|
if (lif_process_monitor_busyloop(child, timeout_sec, &status))
|
||||||
|
return WIFEXITED(status) && WEXITSTATUS(status) == 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
fprintf(stderr, "execution of '%s': timeout after %d seconds\n", cmdbuf, timeout_sec);
|
||||||
|
kill(child, SIGKILL);
|
||||||
|
waitpid(child, &status, 0);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
lif_execute_fmt(const struct lif_execute_opts *opts, char *const envp[], const char *fmt, ...)
|
lif_execute_fmt(const struct lif_execute_opts *opts, char *const envp[], const char *fmt, ...)
|
||||||
{
|
{
|
||||||
|
@ -55,10 +135,7 @@ lif_execute_fmt(const struct lif_execute_opts *opts, char *const envp[], const c
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int status;
|
return lif_process_monitor(cmdbuf, child, opts->timeout);
|
||||||
waitpid(child, &status, 0);
|
|
||||||
|
|
||||||
return WIFEXITED(status) && WEXITSTATUS(status) == 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -118,11 +195,8 @@ lif_execute_fmt_with_result(const struct lif_execute_opts *opts, char *buf, size
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int status;
|
|
||||||
no_result:
|
no_result:
|
||||||
waitpid(child, &status, 0);
|
return lif_process_monitor(cmdbuf, child, opts->timeout);
|
||||||
|
|
||||||
return WIFEXITED(status) && WEXITSTATUS(status) == 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
|
@ -27,6 +27,7 @@ struct lif_execute_opts {
|
||||||
const char *executor_path;
|
const char *executor_path;
|
||||||
const char *interfaces_file;
|
const char *interfaces_file;
|
||||||
const char *state_file;
|
const char *state_file;
|
||||||
|
int timeout;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern bool lif_execute_fmt(const struct lif_execute_opts *opts, char *const envp[], const char *fmt, ...);
|
extern bool lif_execute_fmt(const struct lif_execute_opts *opts, char *const envp[], const char *fmt, ...);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue