Compare commits

...

18 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
26 changed files with 268 additions and 63 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

@ -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:

View file

@ -39,7 +39,7 @@ 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`).

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

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

@ -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.

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

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

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

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

@ -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}
} }