Merge pull request #111 from ifupdown-ng/feature/deprecate-brctl
vlan aware bridging
This commit is contained in:
commit
19a5a671eb
14 changed files with 471 additions and 36 deletions
1
Makefile
1
Makefile
|
@ -138,6 +138,7 @@ install: all
|
||||||
${SCDOC} < $< > $@
|
${SCDOC} < $< > $@
|
||||||
|
|
||||||
MANPAGES_5 = \
|
MANPAGES_5 = \
|
||||||
|
doc/ifupdown-ng.conf.5 \
|
||||||
doc/interfaces.5 \
|
doc/interfaces.5 \
|
||||||
doc/interfaces-bond.5 \
|
doc/interfaces-bond.5 \
|
||||||
doc/interfaces-batman.5 \
|
doc/interfaces-batman.5 \
|
||||||
|
|
|
@ -272,6 +272,12 @@ ifquery_main(int argc, char *argv[])
|
||||||
return EXIT_FAILURE;
|
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 */
|
/* --list --state is not allowed */
|
||||||
if (listing && (listing_stat || listing_running))
|
if (listing && (listing_stat || listing_running))
|
||||||
generic_usage(self_applet, EXIT_FAILURE);
|
generic_usage(self_applet, EXIT_FAILURE);
|
||||||
|
|
16
dist/ifupdown-ng.conf.example
vendored
16
dist/ifupdown-ng.conf.example
vendored
|
@ -17,6 +17,22 @@ allow_addon_scripts = 1
|
||||||
# templates. Valid values are 0 and 1, the default is 1.
|
# templates. Valid values are 0 and 1, the default is 1.
|
||||||
allow_any_iface_as_template = 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 <bridge-vids> as well as the <bridge-pvid> set on a bridge
|
||||||
|
# interface will be inherited by all member ports if not set explicitly.
|
||||||
|
# When set to 1 ifupdown-ng behaves the same way and will internally copy
|
||||||
|
# both options from the bridge member ports if they are not set on the
|
||||||
|
# member port. Valid values are 0 and 1, the default is 1.
|
||||||
|
compat_ifupdown2_bridge_ports_inherit_vlans = 1
|
||||||
|
|
||||||
# implicit_template_conversion:
|
# implicit_template_conversion:
|
||||||
# In some legacy configs, a template may be declared as an iface, and
|
# In some legacy configs, a template may be declared as an iface, and
|
||||||
# ifupdown-ng automatically converts those declarations to a proper
|
# ifupdown-ng automatically converts those declarations to a proper
|
||||||
|
|
|
@ -60,6 +60,20 @@ Currently the following settings are supported in
|
||||||
in order to require inheritance from specified templates.
|
in order to require inheritance from specified templates.
|
||||||
Valid values are `0` and `1`, the default is `1`.
|
Valid values are `0` and `1`, the default is `1`.
|
||||||
|
|
||||||
|
* `compat_create_interfaces`:
|
||||||
|
Denotes where or not to create interfaces when compat\_* settings are
|
||||||
|
active and it would be necessary to create an interface to be fully
|
||||||
|
compliant. This could happen when inheriting bridge VLAN settings to
|
||||||
|
an interface within a bridges bridge-ports setting but no interface
|
||||||
|
stanza is found. Valid values are `0` and `1`, the default is `1`.
|
||||||
|
|
||||||
|
* `compat_ifupdown2_bridge_ports_inherit_vlans`: In ifupdown2 `bridge-vids`
|
||||||
|
as well as the <bridge-pvid> set on a bridge interface will be inherited
|
||||||
|
by all member ports if not set explicitly. When set to `1` ifupdown-ng
|
||||||
|
behaves the same way and will internally copy both options from the
|
||||||
|
bridge member ports if they are not set on the member port.
|
||||||
|
Valid values are `0` and `1`, the default is `1`.
|
||||||
|
|
||||||
* `implicit_template_conversion`: In some legacy configs, a template
|
* `implicit_template_conversion`: In some legacy configs, a template
|
||||||
may be declared as an iface, and ifupdown-ng automatically converts
|
may be declared as an iface, and ifupdown-ng automatically converts
|
||||||
those declarations to a proper template. If this setting is
|
those declarations to a proper template. If this setting is
|
||||||
|
|
|
@ -54,8 +54,9 @@ configured in the configuration database.
|
||||||
|
|
||||||
# SEE ALSO
|
# SEE ALSO
|
||||||
|
|
||||||
*ifup*(8)++
|
*ifupdown-ng.conf*(5)
|
||||||
*ifquery*(8)++
|
*ifup*(8)
|
||||||
|
*ifquery*(8)
|
||||||
*interfaces*(5)
|
*interfaces*(5)
|
||||||
|
|
||||||
# AUTHORS
|
# AUTHORS
|
||||||
|
|
|
@ -57,8 +57,9 @@ configured in the configuration database.
|
||||||
|
|
||||||
# SEE ALSO
|
# SEE ALSO
|
||||||
|
|
||||||
*ifdown*(8)++
|
*ifupdown-ng.conf*(5)
|
||||||
*ifquery*(8)++
|
*ifdown*(8)
|
||||||
|
*ifquery*(8)
|
||||||
*interfaces*(5)
|
*interfaces*(5)
|
||||||
|
|
||||||
# AUTHORS
|
# AUTHORS
|
||||||
|
|
70
doc/ifupdown-ng.conf.scd
Normal file
70
doc/ifupdown-ng.conf.scd
Normal file
|
@ -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 <bridge-vids> as well as the <bridge-pvid> set on a
|
||||||
|
bridge interface will be inherited by all member ports if not set
|
||||||
|
explicitly. When set to 1 ifupdown-ng behaves the same way and will
|
||||||
|
internally copy both options from the bridge member ports if they
|
||||||
|
are not set on the member port. Valid values are _0_ and _1_, the
|
||||||
|
default is _1_.
|
||||||
|
|
||||||
|
# FILES
|
||||||
|
|
||||||
|
/etc/network/ifupdown-ng.conf
|
||||||
|
|
||||||
|
# SEE ALSO
|
||||||
|
|
||||||
|
*interfaces*(5)
|
||||||
|
|
||||||
|
# AUTHORS
|
||||||
|
|
||||||
|
Maximilian Wilhelm <max@sdn.clinic>
|
|
@ -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
|
removed from the Forwarding DataBase (FDB) after not having
|
||||||
seen a frame with this source address.
|
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
|
# SPANNING TREE RELATED BRIDGE OPTIONS
|
||||||
|
|
||||||
*bridge-stp* _state_
|
*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
|
after reception of its last STP hello message. Valid values
|
||||||
are between 6 and 40.
|
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
|
# EXAMPLES
|
||||||
|
|
||||||
A simple layer 2 only bridge:
|
A simple layer 2 only bridge:
|
||||||
|
@ -77,10 +127,46 @@ iface br0
|
||||||
address 2001:db8::42/64
|
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
|
# SEE ALSO
|
||||||
|
|
||||||
*ip-link*(8)
|
|
||||||
*interfaces*(5)
|
*interfaces*(5)
|
||||||
|
*ifupdown-ng.conf*(5)
|
||||||
|
*ip-link*(8)
|
||||||
|
*bridge*(8)
|
||||||
|
|
||||||
# AUTHORS
|
# AUTHORS
|
||||||
|
|
||||||
|
|
|
@ -216,6 +216,7 @@ iface eth0
|
||||||
|
|
||||||
# SEE ALSO
|
# SEE ALSO
|
||||||
|
|
||||||
|
*ifupdown-ng.conf*(5)
|
||||||
*ifup*(8)
|
*ifup*(8)
|
||||||
*ifdown*(8)
|
*ifdown*(8)
|
||||||
*ifquery*(8)
|
*ifquery*(8)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
[ -n "$VERBOSE" ] && set -x
|
||||||
|
|
||||||
# Copyright (C) 2012, 2020 Natanael Copa <ncopa@alpinelinux.org>
|
# Copyright (C) 2012, 2020 Natanael Copa <ncopa@alpinelinux.org>
|
||||||
# Copyright (C) 2020 Ariadne Conill <ariadne@dereferenced.org>
|
# Copyright (C) 2020 Ariadne Conill <ariadne@dereferenced.org>
|
||||||
|
@ -14,6 +15,10 @@ set -e
|
||||||
# implied. In no event shall the authors be liable for any damages arising
|
# implied. In no event shall the authors be liable for any damages arising
|
||||||
# from the use of this software.
|
# from the use of this software.
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# Bridge management functions #
|
||||||
|
################################################################################
|
||||||
|
|
||||||
all_ports_exist() {
|
all_ports_exist() {
|
||||||
local i=
|
local i=
|
||||||
for i in "$@"; do
|
for i in "$@"; do
|
||||||
|
@ -52,13 +57,10 @@ all_ports() {
|
||||||
add_ports() {
|
add_ports() {
|
||||||
local port=
|
local port=
|
||||||
for port in $PORTS; do
|
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
|
if [ -n "$IF_BRIDGE_HW" ]; then
|
||||||
ip link set dev $port addr $IF_BRIDGE_HW
|
ip link set dev $port addr $IF_BRIDGE_HW
|
||||||
fi
|
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
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,22 +68,17 @@ del_ports() {
|
||||||
local port=
|
local port=
|
||||||
for port in $PORTS; do
|
for port in $PORTS; do
|
||||||
ip link set dev $port down
|
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
|
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
set_bridge_opts() {
|
set_bridge_opts_brctl() {
|
||||||
[ -n "$IF_BRIDGE_AGEING" ] \
|
[ -n "$IF_BRIDGE_AGEING" ] \
|
||||||
&& brctl setageing $IFACE $IF_BRIDGE_AGEING
|
&& brctl setageing $IFACE $IF_BRIDGE_AGEING
|
||||||
[ -n "$IF_BRIDGE_BRIDGEPRIO" ] \
|
[ -n "$IF_BRIDGE_BRIDGEPRIO" ] \
|
||||||
&& brctl setbridgeprio $IFACE $IF_BRIDGE_BRIDGEPRIO
|
&& brctl setbridgeprio $IFACE $IF_BRIDGE_BRIDGEPRIO
|
||||||
[ -n "$IF_BRIDGE_FD" ] \
|
[ -n "$IF_BRIDGE_FD" ] \
|
||||||
&& brctl setfd $IFACE $IF_BRIDGE_FD
|
&& brctl setfd $IFACE $IF_BRIDGE_FD
|
||||||
[ -n "$IF_BRIDGE_GCINT" ] \
|
|
||||||
&& brctl setgcint $IFACE $IF_BRIDGE_GCINT
|
|
||||||
[ -n "$IF_BRIDGE_HELLO" ] \
|
[ -n "$IF_BRIDGE_HELLO" ] \
|
||||||
&& brctl sethello $IFACE $IF_BRIDGE_HELLO
|
&& brctl sethello $IFACE $IF_BRIDGE_HELLO
|
||||||
[ -n "$IF_BRIDGE_MAXAGE" ] \
|
[ -n "$IF_BRIDGE_MAXAGE" ] \
|
||||||
|
@ -94,6 +91,44 @@ set_bridge_opts() {
|
||||||
&& brctl stp $IFACE $IF_BRIDGE_STP
|
&& brctl stp $IFACE $IF_BRIDGE_STP
|
||||||
}
|
}
|
||||||
|
|
||||||
|
yesno() {
|
||||||
|
case "$1" in
|
||||||
|
yes|YES|true|TRUE|1)
|
||||||
|
echo 1
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
set_bridge_opts_iproute2() {
|
||||||
|
[ -n "$IF_BRIDGE_AGEING" ] \
|
||||||
|
&& ip link set dev $IFACE type bridge ageing_time $IF_BRIDGE_AGEING
|
||||||
|
[ -n "$IF_BRIDGE_BRIDGEPRIO" ] \
|
||||||
|
&& ip link set dev $IFACE type bridge priority $IF_BRIDGE_BRIDGEPRIO
|
||||||
|
[ -n "$IF_BRIDGE_FD" ] \
|
||||||
|
&& ip link set dev $IFACE type bridge forward_delay $IF_BRIDGE_FD
|
||||||
|
[ -n "$IF_BRIDGE_HELLO" ] \
|
||||||
|
&& ip link set dev $IFACE type bridge hello_time $IF_BRIDGE_HELLO
|
||||||
|
[ -n "$IF_BRIDGE_MAXAGE" ] \
|
||||||
|
&& ip link set dev $IFACE type bridge max_age $IF_BRIDGE_MAXAGE
|
||||||
|
[ -n "$IF_BRIDGE_PATHCOST" ] \
|
||||||
|
&& bridge link set dev $IFACE cost $IF_BRIDGE_PATHCOST
|
||||||
|
[ -n "$IF_BRIDGE_PORTPRIO" ] \
|
||||||
|
&& bridge link set dev $IFACE priority $IF_BRIDGE_PORTPRIO
|
||||||
|
[ -n "$IF_BRIDGE_STP" ] \
|
||||||
|
&& ip link set dev $IFACE type bridge stp $(yesno $IF_BRIDGE_STP)
|
||||||
|
[ -n "$IF_BRIDGE_VLAN_AWARE" ] \
|
||||||
|
&& ip link set dev $IFACE type bridge vlan_filtering $(yesno $IF_BRIDGE_VLAN_AWARE)
|
||||||
|
}
|
||||||
|
|
||||||
|
set_bridge_opts() {
|
||||||
|
[ -x /sbin/bridge ] && set_bridge_opts_iproute2 && return 0
|
||||||
|
[ -x /sbin/brctl ] && set_bridge_opts_brctl && return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
all_ports_ready() {
|
all_ports_ready() {
|
||||||
local port=
|
local port=
|
||||||
for port in $PORTS; do
|
for port in $PORTS; do
|
||||||
|
@ -123,7 +158,92 @@ wait_bridge() {
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
[ -z "$IF_BRIDGE_PORTS" ] && IF_BRIDGE_PORTS="$IF_REQUIRES"
|
|
||||||
|
################################################################################
|
||||||
|
# Bridge port management functions #
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
configure_access_port() {
|
||||||
|
port="$1"
|
||||||
|
vlan="$2"
|
||||||
|
self="$3"
|
||||||
|
|
||||||
|
# Cleans all existing VLANs (probably at least VLAN 1)
|
||||||
|
bridge vlan show dev ${port} | tail -n +2 | grep -v '^$' | sed -e "s/^${port}//" | while read vid flags; do
|
||||||
|
bridge vlan del vid "${vid}" dev "${port}" ${self}
|
||||||
|
done
|
||||||
|
|
||||||
|
bridge vlan add vid "${vlan}" pvid untagged dev "${port}" ${self}
|
||||||
|
}
|
||||||
|
|
||||||
|
configure_trunk_port() {
|
||||||
|
port="$1"
|
||||||
|
self="$2"
|
||||||
|
|
||||||
|
# Working on the bridge itself?
|
||||||
|
if [ "${self}" ]; then
|
||||||
|
allow_untagged="${IF_BRIDGE_ALLOW_UNTAGGED}"
|
||||||
|
pvid="${IF_BRIDGE_PVID}"
|
||||||
|
vids="${IF_BRIDGE_VIDS}"
|
||||||
|
else
|
||||||
|
allow_untagged=$(ifquery -p bridge-allow-untagged ${port} 2>/dev/null || true)
|
||||||
|
pvid=$(ifquery -p bridge-pvid ${port} 2>/dev/null || true)
|
||||||
|
vids=$(ifquery -p bridge-vids ${port} 2>/dev/null || true)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If bridge-allow-untagged if set to off, remove untagged VLAN. If it's
|
||||||
|
# one of our bridge-vids, it will be set again later.
|
||||||
|
if [ "${allow_untagged}" -a "$(yesno ${allow_untagged})" = 0 ]; then
|
||||||
|
untagged_vid=$(bridge vlan show dev ${port} | tail -n +2 | grep -v '^$' | sed -e "s/^${port}//" | awk '/Untagged/ { print $1 }')
|
||||||
|
if [ "${untagged_vid}" ]; then
|
||||||
|
bridge vlan del vid "${untagged_vid}" dev "${port}" ${self}
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# The vlan specified is to be considered a PVID at ingress.
|
||||||
|
# Any untagged frames will be assigned to this VLAN.
|
||||||
|
if [ "${pvid}" ]; then
|
||||||
|
cur_pvid=$(bridge vlan show dev ${port} | tail -n +2 | grep -v '^$' | sed -e "s/^${port}//" | awk '/PVID/ { print $1 }')
|
||||||
|
if [ "${cur_pvid}" ]; then
|
||||||
|
bridge vlan del vid ${cur_pvid} dev "${port}" ${self}
|
||||||
|
fi
|
||||||
|
|
||||||
|
bridge vlan add vid "${pvid}" dev "${port}" pvid untagged ${self}
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Add regular tagged VLANs
|
||||||
|
for vid in ${vids}; do
|
||||||
|
bridge vlan add vid $vid dev "${port}" ${self}
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# Configure VLANs on the bridge interface itself
|
||||||
|
set_bridge_vlans() {
|
||||||
|
# Shall the bridge interface be an untagged port?
|
||||||
|
if [ "${IF_BRIDGE_ACCESS}" ]; then
|
||||||
|
configure_access_port "${IFACE}" "${IF_BRIDGE_ACCESS}" "self"
|
||||||
|
|
||||||
|
# Configure bridge interface as trunk port
|
||||||
|
else
|
||||||
|
configure_trunk_port "${IFACE}" "self"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Configure VLANs on the bridge-ports
|
||||||
|
set_bridge_port_vlans() {
|
||||||
|
for port in ${PORTS}; do
|
||||||
|
access_vlan=$(ifquery -p bridge-access ${port} 2>/dev/null || true)
|
||||||
|
|
||||||
|
# Shall this prot interface be an untagged port?
|
||||||
|
if [ "${access_vlan}" ]; then
|
||||||
|
configure_access_port "${port}" "${access_vlan}"
|
||||||
|
|
||||||
|
# Configure port as trunk
|
||||||
|
else
|
||||||
|
configure_trunk_port "${port}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
case "$IF_BRIDGE_PORTS" in
|
case "$IF_BRIDGE_PORTS" in
|
||||||
"") ;;
|
"") ;;
|
||||||
|
@ -132,30 +252,53 @@ all) PORTS=$(all_ports);;
|
||||||
*) PORTS="$IF_BRIDGE_PORTS";;
|
*) PORTS="$IF_BRIDGE_PORTS";;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
[ -z "$PORTS" ] && ! env | grep -q "^IF_BRIDGE" && exit
|
|
||||||
|
|
||||||
case "$PHASE" in
|
case "$PHASE" in
|
||||||
depend)
|
depend)
|
||||||
echo "$PORTS"
|
# Called for the bridge interface
|
||||||
;;
|
if [ "${IF_BRIDGE_PORTS}" ]; then
|
||||||
create)
|
echo "$PORTS"
|
||||||
if [ ! -d "/sys/class/net/${IFACE}" ]; then
|
|
||||||
brctl addbr "${IFACE}"
|
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
|
|
||||||
|
create)
|
||||||
|
# Called for the bridge interface
|
||||||
|
if [ "${IF_BRIDGE_PORTS}" -a ! -d "/sys/class/net/${IFACE}" ]; then
|
||||||
|
ip link add "${IFACE}" type bridge
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
pre-up)
|
pre-up)
|
||||||
wait_ports
|
# Called for the bridge interface
|
||||||
set_bridge_opts
|
if [ "${IF_BRIDGE_PORTS}" ]; then
|
||||||
add_ports
|
wait_ports
|
||||||
wait_bridge
|
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)
|
post-down)
|
||||||
del_ports
|
# Called for the bridge interface
|
||||||
ip link set dev $IFACE down
|
if [ "${IF_BRIDGE_PORTS}" ]; then
|
||||||
|
del_ports
|
||||||
|
ip link set dev $IFACE down
|
||||||
|
fi
|
||||||
;;
|
;;
|
||||||
|
|
||||||
destroy)
|
destroy)
|
||||||
if [ -d "/sys/class/net/${IFACE}" ]; then
|
# Called for the bridge interface
|
||||||
brctl delbr "${IFACE}"
|
if [ "${IF_BRIDGE_PORTS}" -a -d "/sys/class/net/${IFACE}" ]; then
|
||||||
|
ip link del "${IFACE}"
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
|
@ -14,14 +14,100 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "libifupdown/config-file.h"
|
||||||
#include "libifupdown/dict.h"
|
#include "libifupdown/dict.h"
|
||||||
|
#include "libifupdown/interface.h"
|
||||||
|
#include "libifupdown/tokenize.h"
|
||||||
|
|
||||||
|
static bool
|
||||||
|
compat_ifupdown2_bridge_ports_inherit_vlans(struct lif_dict *collection)
|
||||||
|
{
|
||||||
|
struct lif_node *iter;
|
||||||
|
|
||||||
|
/* Loop through all interfaces and search for bridges */
|
||||||
|
LIF_DICT_FOREACH(iter, collection)
|
||||||
|
{
|
||||||
|
struct lif_dict_entry *entry = iter->data;
|
||||||
|
struct lif_interface *bridge = entry->data;
|
||||||
|
|
||||||
|
/* We only care for bridges */
|
||||||
|
if (!bridge->is_bridge)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
struct lif_dict_entry *bridge_pvid = lif_dict_find(&bridge->vars, "bridge-pvid");
|
||||||
|
struct lif_dict_entry *bridge_vids = lif_dict_find(&bridge->vars, "bridge-vids");
|
||||||
|
|
||||||
|
/* If there's nothing to inherit here, carry on */
|
||||||
|
if (bridge_pvid == NULL && bridge_vids == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
struct lif_dict_entry *bridge_ports_entry = lif_dict_find(&bridge->vars, "bridge-ports");
|
||||||
|
|
||||||
|
/* This SHOULD not happen, but better save than sorry */
|
||||||
|
if (bridge_ports_entry == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
char bridge_ports_str[4096] = {};
|
||||||
|
strlcpy(bridge_ports_str, bridge_ports_entry->data, sizeof bridge_ports_str);
|
||||||
|
|
||||||
|
/* If there are no bridge-ports configured, carry on */
|
||||||
|
if (strcmp(bridge_ports_str, "none") == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Loop over all bridge-ports and set bridge-pvid and bridge-vid if not set already */
|
||||||
|
char *bufp = bridge_ports_str;
|
||||||
|
for (char *tokenp = lif_next_token(&bufp); *tokenp; tokenp = lif_next_token(&bufp))
|
||||||
|
{
|
||||||
|
entry = lif_dict_find(collection, tokenp);
|
||||||
|
|
||||||
|
/* There might be interfaces give within the bridge-ports for which there is no
|
||||||
|
* interface stanza. If this is the case, we add one, so we can inherit the
|
||||||
|
* bridge-vids/pvid to it. */
|
||||||
|
struct lif_interface *bridge_port;
|
||||||
|
if (entry)
|
||||||
|
bridge_port = entry->data;
|
||||||
|
|
||||||
|
else if (lif_config.compat_create_interfaces)
|
||||||
|
{
|
||||||
|
bridge_port = lif_interface_collection_find(collection, tokenp);
|
||||||
|
if (bridge_port == NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Failed to add interface \"%s\"", tokenp);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We would have to creaet an interface, but shouldn't */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf(stderr, "compat: Missing interface stanza for bridge-port \"%s\" but should not create one.\n",
|
||||||
|
tokenp);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Maybe pimp bridge-pvid */
|
||||||
|
struct lif_dict_entry *port_pvid = lif_dict_find(&bridge_port->vars, "bridge-pvid");
|
||||||
|
if (bridge_pvid && !port_pvid)
|
||||||
|
lif_dict_add(&bridge_port->vars, "bridge-pvid", bridge_pvid->data);
|
||||||
|
|
||||||
|
/* Maybe pimp bridge-vids */
|
||||||
|
struct lif_dict_entry *port_vids = lif_dict_find(&bridge_port->vars, "bridge-vids");
|
||||||
|
if (bridge_vids && !port_vids)
|
||||||
|
lif_dict_add(&bridge_port->vars, "bridge-vids", bridge_vids->data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
extern bool
|
extern bool
|
||||||
lif_compat_apply(struct lif_dict *collection)
|
lif_compat_apply(struct lif_dict *collection)
|
||||||
{
|
{
|
||||||
(void) collection;
|
if (lif_config.compat_ifupdown2_bridge_ports_inherit_vlans &&
|
||||||
|
!compat_ifupdown2_bridge_ports_inherit_vlans(collection))
|
||||||
/* Mangle interfaces according to some config options here */
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
struct lif_config_file lif_config = {
|
struct lif_config_file lif_config = {
|
||||||
.allow_addon_scripts = true,
|
.allow_addon_scripts = true,
|
||||||
.allow_any_iface_as_template = true,
|
.allow_any_iface_as_template = true,
|
||||||
|
.compat_create_interfaces = true,
|
||||||
|
.compat_ifupdown2_bridge_ports_inherit_vlans = true,
|
||||||
.implicit_template_conversion = true,
|
.implicit_template_conversion = true,
|
||||||
.use_hostname_for_dhcp = true,
|
.use_hostname_for_dhcp = true,
|
||||||
};
|
};
|
||||||
|
@ -31,7 +33,7 @@ set_bool_value(const char *key, const char *value, void *opaque)
|
||||||
(void) key;
|
(void) key;
|
||||||
|
|
||||||
if (*value == '1' ||
|
if (*value == '1' ||
|
||||||
*value == 'Y' || *value == 'y' ||
|
*value == 'Y' || *value == 'y' ||
|
||||||
*value == 'T' || *value == 't')
|
*value == 'T' || *value == 't')
|
||||||
*(bool *) opaque = true;
|
*(bool *) opaque = true;
|
||||||
else if (*value == '0' ||
|
else if (*value == '0' ||
|
||||||
|
@ -47,6 +49,8 @@ set_bool_value(const char *key, const char *value, void *opaque)
|
||||||
static struct lif_config_handler handlers[] = {
|
static struct lif_config_handler handlers[] = {
|
||||||
{"allow_addon_scripts", set_bool_value, &lif_config.allow_addon_scripts},
|
{"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},
|
{"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},
|
{"implicit_template_conversion", set_bool_value, &lif_config.implicit_template_conversion},
|
||||||
{"use_hostname_for_dhcp", set_bool_value, &lif_config.use_hostname_for_dhcp},
|
{"use_hostname_for_dhcp", set_bool_value, &lif_config.use_hostname_for_dhcp},
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
struct lif_config_file {
|
struct lif_config_file {
|
||||||
bool allow_addon_scripts;
|
bool allow_addon_scripts;
|
||||||
bool allow_any_iface_as_template;
|
bool allow_any_iface_as_template;
|
||||||
|
bool compat_create_interfaces;
|
||||||
|
bool compat_ifupdown2_bridge_ports_inherit_vlans;
|
||||||
bool implicit_template_conversion;
|
bool implicit_template_conversion;
|
||||||
bool use_hostname_for_dhcp;
|
bool use_hostname_for_dhcp;
|
||||||
};
|
};
|
||||||
|
|
|
@ -206,6 +206,10 @@ handle_generic(struct lif_interface_file_parse_state *state, char *token, char *
|
||||||
|
|
||||||
token = maybe_remap_token(token);
|
token = maybe_remap_token(token);
|
||||||
|
|
||||||
|
/* This smells like a bridge */
|
||||||
|
if (strcmp(token, "bridge-ports") == 0)
|
||||||
|
state->cur_iface->is_bridge = true;
|
||||||
|
|
||||||
/* Skip any leading whitespaces in value for <token> */
|
/* Skip any leading whitespaces in value for <token> */
|
||||||
while (isspace (*bufp))
|
while (isspace (*bufp))
|
||||||
bufp++;
|
bufp++;
|
||||||
|
|
Loading…
Reference in a new issue