From e7ee26ac1915112e70cbce7faa5e24efb98c6507 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Wed, 14 Oct 2020 13:15:48 -0600 Subject: [PATCH 01/15] bridge: use iproute commands to create and assign bridge ports --- executor-scripts/linux/bridge | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/executor-scripts/linux/bridge b/executor-scripts/linux/bridge index 5d92061..ef2a091 100755 --- a/executor-scripts/linux/bridge +++ b/executor-scripts/linux/bridge @@ -58,7 +58,7 @@ add_ports() { if [ -n "$IF_BRIDGE_HW" ]; then ip link set dev $port addr $IF_BRIDGE_HW fi - brctl addif $IFACE $port && ip link set dev $port up + ip link set dev $port master $IFACE && ip link set dev $port up done } @@ -66,7 +66,7 @@ del_ports() { local port= for port in $PORTS; do ip link set dev $port down - brctl delif $IFACE $port + ip link set dev $port nomaster if [ -x /etc/network/ip-post-down.d/vlan ]; then env IFACE=$port /etc/network/if-post-down.d/vlan fi @@ -140,7 +140,7 @@ depend) ;; create) if [ ! -d "/sys/class/net/${IFACE}" ]; then - brctl addbr "${IFACE}" + ip link add "${IFACE}" type bridge fi ;; pre-up) @@ -155,7 +155,7 @@ post-down) ;; destroy) if [ -d "/sys/class/net/${IFACE}" ]; then - brctl delbr "${IFACE}" + ip link del "${IFACE}" fi ;; esac From 36eb6e33773acf7d53f23474c8c57f7299c6b017 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Wed, 14 Oct 2020 13:19:17 -0600 Subject: [PATCH 02/15] bridge: check if iproute2 is available and use it to configure bridge options --- executor-scripts/linux/bridge | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/executor-scripts/linux/bridge b/executor-scripts/linux/bridge index ef2a091..542f62f 100755 --- a/executor-scripts/linux/bridge +++ b/executor-scripts/linux/bridge @@ -73,7 +73,7 @@ del_ports() { done } -set_bridge_opts() { +set_bridge_opts_brctl() { [ -n "$IF_BRIDGE_AGEING" ] \ && brctl setageing $IFACE $IF_BRIDGE_AGEING [ -n "$IF_BRIDGE_BRIDGEPRIO" ] \ @@ -94,6 +94,14 @@ set_bridge_opts() { && brctl stp $IFACE $IF_BRIDGE_STP } +set_bridge_opts_iproute2() { +} + +set_bridge_opts() { + [ -x /sbin/bridge ] && set_bridge_opts_iproute2 && return 0 + [ -x /sbin/brctl ] && set_bridge_opts_brctl && return 0 +} + all_ports_ready() { local port= for port in $PORTS; do From 6c5d856ac42c99751f9ed6fb441e4dd5e57a3487 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Wed, 14 Oct 2020 13:44:37 -0600 Subject: [PATCH 03/15] bridge: remove support for gcint (noop in modern kernels), use iproute2 commands for all bridge configuration if present --- executor-scripts/linux/bridge | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/executor-scripts/linux/bridge b/executor-scripts/linux/bridge index 542f62f..45f2413 100755 --- a/executor-scripts/linux/bridge +++ b/executor-scripts/linux/bridge @@ -80,8 +80,6 @@ set_bridge_opts_brctl() { && brctl setbridgeprio $IFACE $IF_BRIDGE_BRIDGEPRIO [ -n "$IF_BRIDGE_FD" ] \ && brctl setfd $IFACE $IF_BRIDGE_FD - [ -n "$IF_BRIDGE_GCINT" ] \ - && brctl setgcint $IFACE $IF_BRIDGE_GCINT [ -n "$IF_BRIDGE_HELLO" ] \ && brctl sethello $IFACE $IF_BRIDGE_HELLO [ -n "$IF_BRIDGE_MAXAGE" ] \ @@ -95,6 +93,22 @@ set_bridge_opts_brctl() { } set_bridge_opts_iproute2() { + [ -n "$IF_BRIDGE_AGEING" ] \ + && ip link set dev $IFACE type bridge ageing_time $IF_BRIDGE_AGEING + [ -n "$IF_BRIDGE_BRIDGEPRIO" ] \ + && ip link set dev $IFACE type bridge priority $IF_BRIDGE_BRIDGEPRIO + [ -n "$IF_BRIDGE_FD" ] \ + && ip link set dev $IFACE type bridge forward_delay $IF_BRIDGE_FD + [ -n "$IF_BRIDGE_HELLO" ] \ + && ip link set dev $IFACE type bridge hello_time $IF_BRIDGE_HELLO + [ -n "$IF_BRIDGE_MAXAGE" ] \ + && ip link set dev $IFACE type bridge max_age $IF_BRIDGE_MAXAGE + [ -n "$IF_BRIDGE_PATHCOST" ] \ + && bridge link set dev $IFACE cost $IF_BRIDGE_PATHCOST + [ -n "$IF_BRIDGE_PORTPRIO" ] \ + && bridge link set dev $IFACE priority $IF_BRIDGE_PORTPRIO + [ -n "$IF_BRIDGE_STP" ] \ + && ip link set dev $IFACE type bridge stp $IF_BRIDGE_STP } set_bridge_opts() { From 3d743f512f542a85112fbda50aa7d517df6ec219 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Wed, 14 Oct 2020 14:04:09 -0600 Subject: [PATCH 04/15] bridge: add support for bridge-vlan-aware in iproute2 mode --- executor-scripts/linux/bridge | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/executor-scripts/linux/bridge b/executor-scripts/linux/bridge index 45f2413..200c0f7 100755 --- a/executor-scripts/linux/bridge +++ b/executor-scripts/linux/bridge @@ -92,6 +92,17 @@ set_bridge_opts_brctl() { && brctl stp $IFACE $IF_BRIDGE_STP } +yesno() { + case "$1" in + yes|YES|true|TRUE|1) + echo 1 + ;; + *) + echo 0 + ;; + esac +} + set_bridge_opts_iproute2() { [ -n "$IF_BRIDGE_AGEING" ] \ && ip link set dev $IFACE type bridge ageing_time $IF_BRIDGE_AGEING @@ -109,6 +120,8 @@ set_bridge_opts_iproute2() { && bridge link set dev $IFACE priority $IF_BRIDGE_PORTPRIO [ -n "$IF_BRIDGE_STP" ] \ && ip link set dev $IFACE type bridge stp $IF_BRIDGE_STP + [ -n "$IF_BRIDGE_VLAN_AWARE" ] \ + && ip link set dev $IFACE type bridge vlan_filtering $(yesno $IF_BRIDGE_VLAN_AWARE) } set_bridge_opts() { From 03528b01adfd840e013bff6bdb150d2604fbb950 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Wed, 14 Oct 2020 21:59:25 -0600 Subject: [PATCH 05/15] bridge: remove hack for alpine vlan scripts (not relevant to us) --- executor-scripts/linux/bridge | 6 ------ 1 file changed, 6 deletions(-) diff --git a/executor-scripts/linux/bridge b/executor-scripts/linux/bridge index 200c0f7..4e4b767 100755 --- a/executor-scripts/linux/bridge +++ b/executor-scripts/linux/bridge @@ -52,9 +52,6 @@ all_ports() { add_ports() { local port= for port in $PORTS; do - if [ -x /etc/network/if-pre-up.d/vlan ]; then - env IFACE=$port /etc/network/if-pre-up.d/vlan - fi if [ -n "$IF_BRIDGE_HW" ]; then ip link set dev $port addr $IF_BRIDGE_HW fi @@ -67,9 +64,6 @@ del_ports() { for port in $PORTS; do ip link set dev $port down ip link set dev $port nomaster - if [ -x /etc/network/ip-post-down.d/vlan ]; then - env IFACE=$port /etc/network/if-post-down.d/vlan - fi done } From 05a3b1539b45f439a94024aaa4505e14f6496d89 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Wed, 14 Oct 2020 22:14:58 -0600 Subject: [PATCH 06/15] bridge: add support for bridge-vids (with inheritance), bridge-access and bridge-pvid --- executor-scripts/linux/bridge | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/executor-scripts/linux/bridge b/executor-scripts/linux/bridge index 4e4b767..9e2e0f2 100755 --- a/executor-scripts/linux/bridge +++ b/executor-scripts/linux/bridge @@ -123,6 +123,34 @@ set_bridge_opts() { [ -x /sbin/brctl ] && set_bridge_opts_brctl && return 0 } +set_bridge_default_vlans() { + [ -x /sbin/bridge ] || return 0 + + [ -z "$IF_BRIDGE_PORTS" ] && return 0 + for port in $IF_BRIDGE_PORTS; do + vids=$(ifquery -p bridge-vids $port) + [ -z "$vids" ] && vids="$IF_BRIDGE_VIDS" + + for vid in $vids; do + bridge vlan add vid $vid dev $port + done + done +} + +set_bridge_access_vlans() { + [ -z "$IF_BRIDGE_PORTS" ] || return 0 + [ -z "$IF_BRIDGE_ACCESS" ] && return 0 + [ -x /sbin/bridge ] || return 0 + + if [ "$IF_BRIDGE_PVID" = "$IF_BRIDGE_ACCESS" ]; then + PVID="pvid" + else + PVID="" + fi + + bridge vlan add vid $IF_BRIDGE_ACCESS $PVID untagged dev $IFACE +} + all_ports_ready() { local port= for port in $PORTS; do @@ -175,6 +203,8 @@ create) pre-up) wait_ports set_bridge_opts + set_bridge_default_vlans + set_bridge_access_vlans add_ports wait_bridge ;; From a5761afd70ad0f8023bbb55a20a98f4d9522593e Mon Sep 17 00:00:00 2001 From: Maximilian Wilhelm Date: Sat, 17 Oct 2020 22:12:34 +0200 Subject: [PATCH 07/15] bridge: Remove fall back to IF_REQUIRES Signed-off-by: Maximilian Wilhelm --- executor-scripts/linux/bridge | 2 -- 1 file changed, 2 deletions(-) diff --git a/executor-scripts/linux/bridge b/executor-scripts/linux/bridge index 9e2e0f2..07b1943 100755 --- a/executor-scripts/linux/bridge +++ b/executor-scripts/linux/bridge @@ -180,8 +180,6 @@ wait_bridge() { done } -[ -z "$IF_BRIDGE_PORTS" ] && IF_BRIDGE_PORTS="$IF_REQUIRES" - case "$IF_BRIDGE_PORTS" in "") ;; none) PORTS="";; From 56beefdd28068d8d02600e1ff7ad7d9efe7dd250 Mon Sep 17 00:00:00 2001 From: Maximilian Wilhelm Date: Sun, 18 Oct 2020 04:57:24 +0200 Subject: [PATCH 08/15] ifquery: Apply compatibility glue, too. Signed-off-by: Maximilian Wilhelm --- cmd/ifquery.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cmd/ifquery.c b/cmd/ifquery.c index 720ab58..dd396de 100644 --- a/cmd/ifquery.c +++ b/cmd/ifquery.c @@ -271,6 +271,12 @@ ifquery_main(int argc, char *argv[]) return EXIT_FAILURE; } + if (!lif_compat_apply(&collection)) + { + fprintf(stderr, "%s: failed to apply compatibility glue\n", argv0); + return EXIT_FAILURE; + } + /* --list --state is not allowed */ if (listing && (listing_stat || listing_running)) generic_usage(self_applet, EXIT_FAILURE); From d86297f29cdb262b4280a15b96b07789064b6126 Mon Sep 17 00:00:00 2001 From: Maximilian Wilhelm Date: Sun, 18 Oct 2020 04:58:23 +0200 Subject: [PATCH 09/15] compat: Add glue for ifupdown2 bridge port VLAN inheritance. Add config options . In ifupdown2 as well as the set on a bridge interface will be inherited by all member ports if not set explicitly. When set to 1 ifupdown-ng behaves the same way and will internally copy both options from the bridge member ports if they are not set on the member port. Valid values are 0 and 1, the default is 1. Signed-off-by: Maximilian Wilhelm --- dist/ifupdown-ng.conf.example | 8 ++++ doc/ADMIN-GUIDE.md | 7 +++ libifupdown/compat.c | 83 +++++++++++++++++++++++++++++++++-- libifupdown/config-file.c | 4 +- libifupdown/config-file.h | 1 + libifupdown/interface-file.c | 4 ++ 6 files changed, 103 insertions(+), 4 deletions(-) diff --git a/dist/ifupdown-ng.conf.example b/dist/ifupdown-ng.conf.example index 7dac1f4..b0e5f78 100644 --- a/dist/ifupdown-ng.conf.example +++ b/dist/ifupdown-ng.conf.example @@ -17,6 +17,14 @@ allow_addon_scripts = 1 # templates. Valid values are 0 and 1, the default is 1. allow_any_iface_as_template = 1 +# compat_ifupdown2_bridge_ports_inherit_vlans: +# In ifupdown2 as well as the set on a bridge +# interface will be inherited by all member ports if not set explicitly. +# When set to 1 ifupdown-ng behaves the same way and will internally copy +# both options from the bridge member ports if they are not set on the +# member port. Valid values are 0 and 1, the default is 1. +compat_ifupdown2_bridge_ports_inherit_vlans = 1 + # implicit_template_conversion: # In some legacy configs, a template may be declared as an iface, and # ifupdown-ng automatically converts those declarations to a proper diff --git a/doc/ADMIN-GUIDE.md b/doc/ADMIN-GUIDE.md index 203541b..ddaaa6f 100644 --- a/doc/ADMIN-GUIDE.md +++ b/doc/ADMIN-GUIDE.md @@ -60,6 +60,13 @@ Currently the following settings are supported in in order to require inheritance from specified templates. Valid values are `0` and `1`, the default is `1`. +* `compat_ifupdown2_bridge_ports_inherit_vlans`: In ifupdown2 `bridge-vids` + as well as the set on a bridge interface will be inherited + by all member ports if not set explicitly. When set to `1` ifupdown-ng + behaves the same way and will internally copy both options from the + bridge member ports if they are not set on the member port. + Valid values are `0` and `1`, the default is `1`. + * `implicit_template_conversion`: In some legacy configs, a template may be declared as an iface, and ifupdown-ng automatically converts those declarations to a proper template. If this setting is diff --git a/libifupdown/compat.c b/libifupdown/compat.c index 10a16d7..3be0b0d 100644 --- a/libifupdown/compat.c +++ b/libifupdown/compat.c @@ -14,14 +14,91 @@ */ #include +#include +#include "libifupdown/config-file.h" #include "libifupdown/dict.h" +#include "libifupdown/interface.h" +#include "libifupdown/tokenize.h" + +static bool +compat_ifupdown2_bridge_ports_inherit_vlans(struct lif_dict *collection) +{ + struct lif_node *iter; + + /* Loop through all interfaces and search for bridges */ + LIF_DICT_FOREACH(iter, collection) + { + struct lif_dict_entry *entry = iter->data; + struct lif_interface *bridge = entry->data; + + /* We only care for bridges */ + if (!bridge->is_bridge) + continue; + + struct lif_dict_entry *bridge_pvid = lif_dict_find(&bridge->vars, "bridge-pvid"); + struct lif_dict_entry *bridge_vids = lif_dict_find(&bridge->vars, "bridge-vids"); + + /* If there's nothing to inherit here, carry on */ + if (bridge_pvid == NULL && bridge_vids == NULL) + continue; + + struct lif_dict_entry *bridge_ports_entry = lif_dict_find(&bridge->vars, "bridge-ports"); + + /* This SHOULD not happen, but better save than sorry */ + if (bridge_ports_entry == NULL) + continue; + + char bridge_ports_str[4096] = {}; + strlcpy(bridge_ports_str, bridge_ports_entry->data, sizeof bridge_ports_str); + + /* If there are no bridge-ports configured, carry on */ + if (strcmp(bridge_ports_str, "none") == 0) + continue; + + /* Loop over all bridge-ports and set bridge-pvid and bridge-vid if not set already */ + char *bufp = bridge_ports_str; + for (char *tokenp = lif_next_token(&bufp); *tokenp; tokenp = lif_next_token(&bufp)) + { + entry = lif_dict_find(collection, tokenp); + + /* There might be interfaces give within the bridge-ports for which there is no + * interface stanza. If this is the case, we add one, so we can inherit the + * bridge-vids/pvid to it. */ + struct lif_interface *bridge_port; + if (entry) + bridge_port = entry->data; + + else + { + bridge_port = lif_interface_collection_find(collection, tokenp); + if (bridge_port == NULL) + { + fprintf(stderr, "Failed to add interface \"%s\"", tokenp); + return false; + } + } + + /* Maybe pimp bridge-pvid */ + struct lif_dict_entry *port_pvid = lif_dict_find(&bridge_port->vars, "bridge-pvid"); + if (bridge_pvid && !port_pvid) + lif_dict_add(&bridge_port->vars, "bridge-pvid", bridge_pvid->data); + + /* Maybe pimp bridge-vids */ + struct lif_dict_entry *port_vids = lif_dict_find(&bridge_port->vars, "bridge-vids"); + if (bridge_vids && !port_vids) + lif_dict_add(&bridge_port->vars, "bridge-vids", bridge_vids->data); + } + } + + return true; +} extern bool lif_compat_apply(struct lif_dict *collection) { - (void) collection; - - /* Mangle interfaces according to some config options here */ + if (lif_config.compat_ifupdown2_bridge_ports_inherit_vlans && + !compat_ifupdown2_bridge_ports_inherit_vlans(collection)) + return false; return true; } diff --git a/libifupdown/config-file.c b/libifupdown/config-file.c index 2438e15..a6e45db 100644 --- a/libifupdown/config-file.c +++ b/libifupdown/config-file.c @@ -21,6 +21,7 @@ struct lif_config_file lif_config = { .allow_addon_scripts = true, .allow_any_iface_as_template = true, + .compat_ifupdown2_bridge_ports_inherit_vlans = true, .implicit_template_conversion = true, .use_hostname_for_dhcp = true, }; @@ -31,7 +32,7 @@ set_bool_value(const char *key, const char *value, void *opaque) (void) key; if (*value == '1' || - *value == 'Y' || *value == 'y' || + *value == 'Y' || *value == 'y' || *value == 'T' || *value == 't') *(bool *) opaque = true; else if (*value == '0' || @@ -47,6 +48,7 @@ set_bool_value(const char *key, const char *value, void *opaque) static struct lif_config_handler handlers[] = { {"allow_addon_scripts", set_bool_value, &lif_config.allow_addon_scripts}, {"allow_any_iface_as_template", set_bool_value, &lif_config.allow_any_iface_as_template}, + {"compat_ifupdown2_bridge_ports_inherit_vlans", set_bool_value, &lif_config.compat_ifupdown2_bridge_ports_inherit_vlans}, {"implicit_template_conversion", set_bool_value, &lif_config.implicit_template_conversion}, {"use_hostname_for_dhcp", set_bool_value, &lif_config.use_hostname_for_dhcp}, }; diff --git a/libifupdown/config-file.h b/libifupdown/config-file.h index b264148..71ff46a 100644 --- a/libifupdown/config-file.h +++ b/libifupdown/config-file.h @@ -21,6 +21,7 @@ struct lif_config_file { bool allow_addon_scripts; bool allow_any_iface_as_template; + bool compat_ifupdown2_bridge_ports_inherit_vlans; bool implicit_template_conversion; bool use_hostname_for_dhcp; }; diff --git a/libifupdown/interface-file.c b/libifupdown/interface-file.c index d2e88ac..e8a37d4 100644 --- a/libifupdown/interface-file.c +++ b/libifupdown/interface-file.c @@ -203,6 +203,10 @@ handle_generic(struct lif_interface_file_parse_state *state, char *token, char * token = maybe_remap_token(token); + /* This smells like a bridge */ + if (strcmp(token, "bridge-ports") == 0) + state->cur_iface->is_bridge = true; + /* Skip any leading whitespaces in value for */ while (isspace (*bufp)) bufp++; From 480fc5eecb25bad389af0c35e6a8005b369cc72e Mon Sep 17 00:00:00 2001 From: Maximilian Wilhelm Date: Sun, 18 Oct 2020 05:14:03 +0200 Subject: [PATCH 10/15] compat: Only create interface when configured to do so. Add config option : Denotes where or not to create interfaces when compat_* settings are active and it would be necessary to create an interface to be fully compliant. This could happen when inheriting bridge VLAN settings to an interface within a bridges bridge-ports setting but no interface stanza is found. Valid values are 0 and 1, the default is 1. Signed-off-by: Maximilian Wilhelm --- dist/ifupdown-ng.conf.example | 8 ++++++++ doc/ADMIN-GUIDE.md | 7 +++++++ libifupdown/compat.c | 10 +++++++++- libifupdown/config-file.c | 2 ++ libifupdown/config-file.h | 1 + 5 files changed, 27 insertions(+), 1 deletion(-) diff --git a/dist/ifupdown-ng.conf.example b/dist/ifupdown-ng.conf.example index b0e5f78..ceffba8 100644 --- a/dist/ifupdown-ng.conf.example +++ b/dist/ifupdown-ng.conf.example @@ -17,6 +17,14 @@ allow_addon_scripts = 1 # templates. Valid values are 0 and 1, the default is 1. allow_any_iface_as_template = 1 +# compat_create_interfaces: +# Denotes where or not to create interfaces when compat_* settings are +# active and it would be necessary to create an interface to be fully +# compliant. This could happen when inheriting bridge VLAN settings to +# an interface within a bridges bridge-ports setting but no interface +# stanza is found. Valid values are 0 and 1, the default is 1. +compat_create_interfaces = 1 + # compat_ifupdown2_bridge_ports_inherit_vlans: # In ifupdown2 as well as the set on a bridge # interface will be inherited by all member ports if not set explicitly. diff --git a/doc/ADMIN-GUIDE.md b/doc/ADMIN-GUIDE.md index ddaaa6f..9242954 100644 --- a/doc/ADMIN-GUIDE.md +++ b/doc/ADMIN-GUIDE.md @@ -60,6 +60,13 @@ Currently the following settings are supported in in order to require inheritance from specified templates. Valid values are `0` and `1`, the default is `1`. +* `compat_create_interfaces`: + Denotes where or not to create interfaces when compat\_* settings are + active and it would be necessary to create an interface to be fully + compliant. This could happen when inheriting bridge VLAN settings to + an interface within a bridges bridge-ports setting but no interface + stanza is found. Valid values are `0` and `1`, the default is `1`. + * `compat_ifupdown2_bridge_ports_inherit_vlans`: In ifupdown2 `bridge-vids` as well as the set on a bridge interface will be inherited by all member ports if not set explicitly. When set to `1` ifupdown-ng diff --git a/libifupdown/compat.c b/libifupdown/compat.c index 3be0b0d..452a737 100644 --- a/libifupdown/compat.c +++ b/libifupdown/compat.c @@ -68,7 +68,7 @@ compat_ifupdown2_bridge_ports_inherit_vlans(struct lif_dict *collection) if (entry) bridge_port = entry->data; - else + else if (lif_config.compat_create_interfaces) { bridge_port = lif_interface_collection_find(collection, tokenp); if (bridge_port == NULL) @@ -78,6 +78,14 @@ compat_ifupdown2_bridge_ports_inherit_vlans(struct lif_dict *collection) } } + /* We would have to creaet an interface, but shouldn't */ + else + { + fprintf(stderr, "compat: Missing interface stanza for bridge-port \"%s\" but should not create one.\n", + tokenp); + continue; + } + /* Maybe pimp bridge-pvid */ struct lif_dict_entry *port_pvid = lif_dict_find(&bridge_port->vars, "bridge-pvid"); if (bridge_pvid && !port_pvid) diff --git a/libifupdown/config-file.c b/libifupdown/config-file.c index a6e45db..e5c79ff 100644 --- a/libifupdown/config-file.c +++ b/libifupdown/config-file.c @@ -21,6 +21,7 @@ struct lif_config_file lif_config = { .allow_addon_scripts = true, .allow_any_iface_as_template = true, + .compat_create_interfaces = true, .compat_ifupdown2_bridge_ports_inherit_vlans = true, .implicit_template_conversion = true, .use_hostname_for_dhcp = true, @@ -48,6 +49,7 @@ set_bool_value(const char *key, const char *value, void *opaque) static struct lif_config_handler handlers[] = { {"allow_addon_scripts", set_bool_value, &lif_config.allow_addon_scripts}, {"allow_any_iface_as_template", set_bool_value, &lif_config.allow_any_iface_as_template}, + {"compat_create_interfaces", set_bool_value, &lif_config.compat_create_interfaces}, {"compat_ifupdown2_bridge_ports_inherit_vlans", set_bool_value, &lif_config.compat_ifupdown2_bridge_ports_inherit_vlans}, {"implicit_template_conversion", set_bool_value, &lif_config.implicit_template_conversion}, {"use_hostname_for_dhcp", set_bool_value, &lif_config.use_hostname_for_dhcp}, diff --git a/libifupdown/config-file.h b/libifupdown/config-file.h index 71ff46a..4364f5b 100644 --- a/libifupdown/config-file.h +++ b/libifupdown/config-file.h @@ -21,6 +21,7 @@ struct lif_config_file { bool allow_addon_scripts; bool allow_any_iface_as_template; + bool compat_create_interfaces; bool compat_ifupdown2_bridge_ports_inherit_vlans; bool implicit_template_conversion; bool use_hostname_for_dhcp; From ab7b1f5d24ac79c096ff136712af181e6fd2d766 Mon Sep 17 00:00:00 2001 From: Maximilian Wilhelm Date: Sun, 18 Oct 2020 05:36:45 +0200 Subject: [PATCH 11/15] compat: Fix build failure. Signed-off-by: Maximilian Wilhelm --- libifupdown/compat.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libifupdown/compat.c b/libifupdown/compat.c index 452a737..b6e5547 100644 --- a/libifupdown/compat.c +++ b/libifupdown/compat.c @@ -14,6 +14,7 @@ */ #include +#include #include #include "libifupdown/config-file.h" #include "libifupdown/dict.h" From fb1d3181fe112574800aa586a2d1ae732370ee77 Mon Sep 17 00:00:00 2001 From: Maximilian Wilhelm Date: Sun, 18 Oct 2020 21:28:10 +0200 Subject: [PATCH 12/15] bridge: STP option for iproute2 has to be 0 or 1. Signed-off-by: Maximilian Wilhelm --- executor-scripts/linux/bridge | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/executor-scripts/linux/bridge b/executor-scripts/linux/bridge index 07b1943..ca845a3 100755 --- a/executor-scripts/linux/bridge +++ b/executor-scripts/linux/bridge @@ -113,7 +113,7 @@ set_bridge_opts_iproute2() { [ -n "$IF_BRIDGE_PORTPRIO" ] \ && bridge link set dev $IFACE priority $IF_BRIDGE_PORTPRIO [ -n "$IF_BRIDGE_STP" ] \ - && ip link set dev $IFACE type bridge stp $IF_BRIDGE_STP + && ip link set dev $IFACE type bridge stp $(yesno $IF_BRIDGE_STP) [ -n "$IF_BRIDGE_VLAN_AWARE" ] \ && ip link set dev $IFACE type bridge vlan_filtering $(yesno $IF_BRIDGE_VLAN_AWARE) } From 02a74985ab822cda436f5690aeda6ade03c40ed0 Mon Sep 17 00:00:00 2001 From: Maximilian Wilhelm Date: Sun, 18 Oct 2020 21:29:50 +0200 Subject: [PATCH 13/15] bridge: Rework vlan handling Signed-off-by: Maximilian Wilhelm --- executor-scripts/linux/bridge | 166 ++++++++++++++++++++++++++-------- 1 file changed, 126 insertions(+), 40 deletions(-) diff --git a/executor-scripts/linux/bridge b/executor-scripts/linux/bridge index ca845a3..384d30e 100755 --- a/executor-scripts/linux/bridge +++ b/executor-scripts/linux/bridge @@ -1,6 +1,7 @@ #!/bin/sh set -e +[ -n "$VERBOSE" ] && set -x # Copyright (C) 2012, 2020 Natanael Copa # Copyright (C) 2020 Ariadne Conill @@ -14,6 +15,10 @@ set -e # implied. In no event shall the authors be liable for any damages arising # from the use of this software. +################################################################################ +# Bridge management functions # +################################################################################ + all_ports_exist() { local i= for i in "$@"; do @@ -123,33 +128,6 @@ set_bridge_opts() { [ -x /sbin/brctl ] && set_bridge_opts_brctl && return 0 } -set_bridge_default_vlans() { - [ -x /sbin/bridge ] || return 0 - - [ -z "$IF_BRIDGE_PORTS" ] && return 0 - for port in $IF_BRIDGE_PORTS; do - vids=$(ifquery -p bridge-vids $port) - [ -z "$vids" ] && vids="$IF_BRIDGE_VIDS" - - for vid in $vids; do - bridge vlan add vid $vid dev $port - done - done -} - -set_bridge_access_vlans() { - [ -z "$IF_BRIDGE_PORTS" ] || return 0 - [ -z "$IF_BRIDGE_ACCESS" ] && return 0 - [ -x /sbin/bridge ] || return 0 - - if [ "$IF_BRIDGE_PVID" = "$IF_BRIDGE_ACCESS" ]; then - PVID="pvid" - else - PVID="" - fi - - bridge vlan add vid $IF_BRIDGE_ACCESS $PVID untagged dev $IFACE -} all_ports_ready() { local port= @@ -180,6 +158,93 @@ wait_bridge() { done } + +################################################################################ +# Bridge port management functions # +################################################################################ + +configure_access_port() { + port="$1" + vlan="$2" + self="$3" + + # Cleans all existing VLANs (probably at least VLAN 1) + bridge vlan show dev ${port} | tail -n +2 | grep -v '^$' | sed -e "s/^${port}//" | while read vid flags; do + bridge vlan del vid "${vid}" dev "${port}" ${self} + done + + bridge vlan add vid "${vlan}" pvid untagged dev "${port}" ${self} +} + +configure_trunk_port() { + port="$1" + self="$2" + + # Working on the bridge itself? + if [ "${self}" ]; then + allow_untagged="${IF_BRIDGE_ALLOW_UNTAGGED}" + pvid="${IF_BRIDGE_PVID}" + vids="${IF_BRIDGE_VIDS}" + else + allow_untagged=$(ifquery -p bridge-allow-untagged ${port} 2>/dev/null || true) + pvid=$(ifquery -p bridge-pvid ${port} 2>/dev/null || true) + vids=$(ifquery -p bridge-vids ${port} 2>/dev/null || true) + fi + + # If bridge-allow-untagged if set to off, remove untagged VLAN. If it's + # one of our bridge-vids, it will be set again later. + if [ "${allow_untagged}" -a "$(yesno ${allow_untagged})" = 0 ]; then + untagged_vid=$(bridge vlan show dev ${port} | tail -n +2 | grep -v '^$' | sed -e "s/^${port}//" | awk '/Untagged/ { print $1 }') + if [ "${untagged_vid}" ]; then + bridge vlan del vid "${untagged_vid}" dev "${port}" ${self} + fi + fi + + # The vlan specified is to be considered a PVID at ingress. + # Any untagged frames will be assigned to this VLAN. + if [ "${pvid}" ]; then + cur_pvid=$(bridge vlan show dev ${port} | tail -n +2 | grep -v '^$' | sed -e "s/^${port}//" | awk '/PVID/ { print $1 }') + if [ "${cur_pvid}" ]; then + bridge vlan del vid ${cur_pvid} dev "${port}" ${self} + fi + + bridge vlan add vid "${pvid}" dev "${port}" pvid untagged ${self} + fi + + # Add regular tagged VLANs + for vid in ${vids}; do + bridge vlan add vid $vid dev "${port}" ${self} + done +} + +# Configure VLANs on the bridge interface itself +set_bridge_vlans() { + # Shall the bridge interface be an untagged port? + if [ "${IF_BRIDGE_ACCESS}" ]; then + configure_access_port "${IFACE}" "${IF_BRIDGE_ACCESS}" "self" + + # Configure bridge interface as trunk port + else + configure_trunk_port "${IFACE}" "self" + fi +} + +# Configure VLANs on the bridge-ports +set_bridge_port_vlans() { + for port in ${PORTS}; do + access_vlan=$(ifquery -p bridge-access ${port} 2>/dev/null || true) + + # Shall this prot interface be an untagged port? + if [ "${access_vlan}" ]; then + configure_access_port "${port}" "${access_vlan}" + + # Configure port as trunk + else + configure_trunk_port "${port}" + fi + done +} + case "$IF_BRIDGE_PORTS" in "") ;; none) PORTS="";; @@ -187,31 +252,52 @@ all) PORTS=$(all_ports);; *) PORTS="$IF_BRIDGE_PORTS";; esac -[ -z "$PORTS" ] && ! env | grep -q "^IF_BRIDGE" && exit - case "$PHASE" in depend) - echo "$PORTS" + # Called for the bridge interface + if [ "${IF_BRIDGE_PORTS}" ]; then + echo "$PORTS" + fi ;; + create) - if [ ! -d "/sys/class/net/${IFACE}" ]; then + # Called for the bridge interface + if [ "${IF_BRIDGE_PORTS}" -a ! -d "/sys/class/net/${IFACE}" ]; then ip link add "${IFACE}" type bridge fi ;; + pre-up) - wait_ports - set_bridge_opts - set_bridge_default_vlans - set_bridge_access_vlans - add_ports - wait_bridge + # Called for the bridge interface + if [ "${IF_BRIDGE_PORTS}" ]; then + wait_ports + set_bridge_opts + set_bridge_vlans + add_ports + set_bridge_port_vlans + wait_bridge + + # Called for a bridge member port + elif [ "${IF_BRIDGE_VIDS}" -o "${IF_BRIDGE_PVID}" -o "${IF_BRIDGE_ACCESS}" -o "${IF_BRIDGE_ALLOW_UNTAGGED}" ]; then + # Eventually we want to configure VLAN settings of member ports here. + # The current execution model does not allow this, so this is a no-op + # for now and we work around this by configuring ports while configuring + # the bridge. + true + fi ;; + post-down) - del_ports - ip link set dev $IFACE down + # Called for the bridge interface + if [ "${IF_BRIDGE_PORTS}" ]; then + del_ports + ip link set dev $IFACE down + fi ;; + destroy) - if [ -d "/sys/class/net/${IFACE}" ]; then + # Called for the bridge interface + if [ "${IF_BRIDGE_PORTS}" -a -d "/sys/class/net/${IFACE}" ]; then ip link del "${IFACE}" fi ;; From e5d9ee25fc85da92259b48d43eb3c98a51c2cd21 Mon Sep 17 00:00:00 2001 From: Maximilian Wilhelm Date: Sun, 18 Oct 2020 23:25:42 +0200 Subject: [PATCH 14/15] doc: Update bridge man page on vlan-aware options. Signed-off-by: Maximilian Wilhelm --- doc/interfaces-bridge.scd | 88 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 87 insertions(+), 1 deletion(-) diff --git a/doc/interfaces-bridge.scd b/doc/interfaces-bridge.scd index 15aff2e..4ad3eb6 100644 --- a/doc/interfaces-bridge.scd +++ b/doc/interfaces-bridge.scd @@ -27,6 +27,11 @@ See *ip-link*(8) for more details about the options listed below. removed from the Forwarding DataBase (FDB) after not having seen a frame with this source address. +*bridge-vlan-aware* _bool_ + Denotes wether or not the bridge should be aware of 802.1q VLANs. + _bool_ can be given as _yes_/_no_ or _0_/_1_. The defaul is _no_. + See related options for configuring vlan-aware bridges, below. + # SPANNING TREE RELATED BRIDGE OPTIONS *bridge-stp* _state_ @@ -52,6 +57,51 @@ See *ip-link*(8) for more details about the options listed below. after reception of its last STP hello message. Valid values are between 6 and 40. +# OPTIONS FOR VLAN-AWARE-BRIDGES + +The following options only have an effect on vlan-aware bridges and +their ports. + +All settings can be applied on the bridge interface itself and all member +port iface stanzas. If applied on the bridge interface they take effect +for the bridge interface itself and might be inherited to _bridge-ports_ +depending on the compatibility settings configured in *ifupdown-ng.conf*(5). + +Configuring VLAN options on the bridge interface might be required for +setting up a VLAN interface to one of the VLANs carried within the bridge. +See the EXAMPLES section for an example for this scenario. + +See *ifupdown-ng.conf*(5) for more information about compatiblity settings +mentioned below. + +*bridge-access* _vlan ID_ + Configure the given _vlan ID_ for untagged ingress and egress + on this interface. The common description for this kind of + configuration is called "access port". + +*bridge-pvid* _vlan ID_ + Denotes the _vlan ID_ to considered a PVID at ingress. + Any untagged frames received on this interface will be + assigned to this _vlan ID_. The default PVID is _1_. + + If compatibility to ifupdown2 bridge port inheritance is active + a _bridge-pvid_ set on the bridge will be inherited to any + interface configured in _bridge-ports_ without a _bridge-pvid_ set. + +*bridge-vids* _list of vlan IDs_ + Denotes the space separated list of VLANs to be allowed tagged + ingress/egress on this interface. + + If compatibility to ifupdown2 bridge port inheritance is active + a _bridge-vids_ set on the bridge will be inherited to any + interface configured in _bridge-ports_ without _bridge-vids_ set. + +*bridge-allow-untagged* _bool_ + Denotes wether or not the bridge should allow untagged frames on + ingress as well as egress. If set to _no_ untagged frames will be + droppped on ingress and none will be sent. _bool_ can be given as + _yes_/_no_ or _0_/_1_. The defaul is _yes_. + # EXAMPLES A simple layer 2 only bridge: @@ -77,10 +127,46 @@ iface br0 address 2001:db8::42/64 ``` +A layer 2 only vlan-aware bridge: + +``` +auto bond0 +iface bond0 + bond-members eth0 eth1 + bridge-vids 23 42 84 1337 + +auto br0 +iface br0 + bridge-ports bond0 +``` + +A vlan-aware bridge with a VLAN interface on top: + +``` +auto eth0 +iface eth0 + bridge-vids 23 42 84 1337 + +auto br0 +iface br0 + bridge-ports eth0 + bridge-vlan-aware yes + bridge-vids 42 + +auto vlan42 +iface vlan42 + vlan-raw-device br0 + # + address 192.0.2.42/24 + address 2001:db8::42/64 +``` + # SEE ALSO -*ip-link*(8) *interfaces*(5) +*ifupdown-ng.conf*(5) +*ip-link*(8) +*bridge*(8) # AUTHORS From c810cd58176061cfe9797c66df598e9ac1c76652 Mon Sep 17 00:00:00 2001 From: Maximilian Wilhelm Date: Sun, 18 Oct 2020 23:43:17 +0200 Subject: [PATCH 15/15] doc: Add ifupdown-ng.conf(5) man page on global options. Signed-off-by: Maximilian Wilhelm --- Makefile | 1 + doc/ifdown.scd | 5 +-- doc/ifup.scd | 5 +-- doc/ifupdown-ng.conf.scd | 70 ++++++++++++++++++++++++++++++++++++++++ doc/interfaces.scd | 1 + 5 files changed, 78 insertions(+), 4 deletions(-) create mode 100644 doc/ifupdown-ng.conf.scd diff --git a/Makefile b/Makefile index a362e75..febe3b4 100644 --- a/Makefile +++ b/Makefile @@ -138,6 +138,7 @@ install: all ${SCDOC} < $< > $@ MANPAGES_5 = \ + doc/ifupdown-ng.conf.5 \ doc/interfaces.5 \ doc/interfaces-bond.5 \ doc/interfaces-batman.5 \ diff --git a/doc/ifdown.scd b/doc/ifdown.scd index 15ff53d..0215954 100644 --- a/doc/ifdown.scd +++ b/doc/ifdown.scd @@ -54,8 +54,9 @@ configured in the configuration database. # SEE ALSO -*ifup*(8)++ -*ifquery*(8)++ +*ifupdown-ng.conf*(5) +*ifup*(8) +*ifquery*(8) *interfaces*(5) # AUTHORS diff --git a/doc/ifup.scd b/doc/ifup.scd index c315e6d..0af9150 100644 --- a/doc/ifup.scd +++ b/doc/ifup.scd @@ -57,8 +57,9 @@ configured in the configuration database. # SEE ALSO -*ifdown*(8)++ -*ifquery*(8)++ +*ifupdown-ng.conf*(5) +*ifdown*(8) +*ifquery*(8) *interfaces*(5) # AUTHORS diff --git a/doc/ifupdown-ng.conf.scd b/doc/ifupdown-ng.conf.scd new file mode 100644 index 0000000..124643f --- /dev/null +++ b/doc/ifupdown-ng.conf.scd @@ -0,0 +1,70 @@ +ifupdown-ng.conf(5) + +# NAME + +*ifupdown-ng.conf* - Global configuration file for ifupdown-ng + +# DESCRIPTION + +ifupdown-ng allows to configure some parts of it's behaviour via global +configuration options. + +# GENERAL CONFIGURATION OPTIONS + +*allow_addon_scripts* _bool_ + Enable support for /etc/if-X.d addon scripts. These are used for + compatibility with legacy setups, and may be disabled for + performance improvements in setups where only ifupdown-ng executors + are used. Valid values are _0_ and _1_, the default is _1_. + +*use_hostname_for_dhcp* _bool_ + Automatically learn the hostname property, used for DHCP + configuration by querying the system hostname using uname(2). + This is basically equivalent to `hostname $(hostname)` without + having to specify any configuration. Valid values are _0_ and + _1_, the default is _1_. + +# TEMPLATE RELATED OPTIONS + +*allow_any_iface_as_template* _bool_ + Enable any interface to act as a template for another interface. + This is presently the default, but is deprecated. An admin may + choose to disable this setting in order to require inheritance + from specified templates. Valid values are _0_ and _1_, the + default is _1_. + +*implicit_template_conversion* _bool_ + In some legacy configs, a template may be declared as an iface, and + ifupdown-ng automatically converts those declarations to a proper + template. If this setting is disabled, inheritance will continue + to work against non-template interfaces without converting them to + a template. Valid values are _0_ and _1_, the default is _1_. + +# COMPATIBILITY RELATED OPTIONS + +*compat_create_interfaces* _bool_ + Denotes where or not to create interfaces when compat_* settings are + active and it would be necessary to create an interface to be fully + compliant. This could happen when inheriting bridge VLAN settings to + an interface within a bridges bridge-ports setting but no interface + stanza is found. Valid values are _0_ and _1_, the default is _1_. + +compat_ifupdown2_bridge_ports_inherit_vlans _bool_ + In ifupdown2 as well as the set on a + bridge interface will be inherited by all member ports if not set + explicitly. When set to 1 ifupdown-ng behaves the same way and will + internally copy both options from the bridge member ports if they + are not set on the member port. Valid values are _0_ and _1_, the + default is _1_. + +# FILES + +/etc/network/ifupdown-ng.conf + +# SEE ALSO + +*interfaces*(5) + +# AUTHORS + +Maximilian Wilhelm diff --git a/doc/interfaces.scd b/doc/interfaces.scd index 6b3d4fb..3c8dd23 100644 --- a/doc/interfaces.scd +++ b/doc/interfaces.scd @@ -216,6 +216,7 @@ iface eth0 # SEE ALSO +*ifupdown-ng.conf*(5) *ifup*(8) *ifdown*(8) *ifquery*(8)