I'm assuming that you are using these three packages to provide the options in use: ifupdown, bridge-utils, vlan. The two later provide the commands brctl
and vconfig
, both obsolete, but more importantly they provide Debian-specific plugin scripts to ifupdown. While brctl
is still used in these scripts, vconfig
is not even used (and replaced by modern ip link
commands).
The problem is caused by the fact that br0
is parent to a VLAN sub-interface that gets created by bridge-utils scripts (not by scripts from the vlan package).
The bridge-utils's ifupdown plugin scripts prevent bridge ports to participate in routing:
# ls -l /etc/network/if-pre-up.d/bridge
lrwxrwxrwx. 1 root root 29 Jan 28 2019 bridge -> /lib/bridge-utils/ifupdown.sh
which is a Debian-specific script belonging to the bridge-utils package. Here's the relevant content (sorry this is a rare package that doesn't appear to be on https://salsa.debian.org, so no link):
if [ -f /proc/sys/net/ipv6/conf/$port/disable_ipv6 ]
then
echo 1 > /proc/sys/net/ipv6/conf/$port/disable_ipv6
fi
This is a desired setting for bridge ports.
But in OP's setup the bridge interface is intended to receive an address to participate in routing, and also to be a parent interface to a VLAN sub interface itself enslaved to a bridge. That's a topology not expected by bridge-utils.
The previous script calls /lib/bridge-utils/bridge-utils.sh
which includes:
create_vlan_port()
{
# port doesn't yet exist
if [ ! -e "/sys/class/net/$port" ]
then
local dev="${port%.*}"
# port is a vlan and the device exists?
if [ "$port" != "$dev" ] && [ -e "/sys/class/net/$dev" ]
then
if [ -f /proc/sys/net/ipv6/conf/$dev/disable_ipv6 ]
then
echo 1 > /proc/sys/net/ipv6/conf/$dev/disable_ipv6
fi
ip link set "$dev" up
ip link add link "$dev" name "$port" type vlan id "${port#*.}"
fi
fi
}
When the sub-interface doesn't exist (because it doesn't even need to have a configuration to be created at all with this script), its parent interface gets IPv6 disabled (while the ports itself will get it disabled from the previous script) for similar reasons to the bridge case: the parent interface is supposed to carry only VLAN tagged traffic, so is prevented to interfere with any routing for example by receiving automatic IPv6 addresses. This is also usually a desired setting, but not for OP's case where the same interface is intended to carry both tagged and untagged traffic.
In OP's setup the sub-interfaces are defined in the configuration and intended to be created on the system by plugin scripts from the vlan package, but since there aren't any auto br0.5
nor auto br0.90
, the interfaces were not created at the system level when bridge-utils's script checked, so it executes the # port doesn't yet exist
block: creates them but disable IPv6 on their parent interfaces first. It's important here to not confuse the logical interface as seen with ifupdown with the real interface on the system, despite them having the same name in almost all setups.
Solutions
Any of the three methods below should get the intended result. I'm also suggesting a 4th method, but integration with applications like Docker wouldn't be simple.
work-around this by adapting to the peculiarities of the (quite obsolete) bridge-utils package: bring up the configured sub-interfaces in advance, so they exist at the system level. Then the script above won't disable IPv6 on their parent interfaces (it won't match # port doesn't yet exist
). Nor scripts from the vlan package which this time created the VLAN sub-interfaces.
auto br0.5
iface br0.5 inet manual
vlan-raw-device br0
auto br0.90
iface br0.90 inet manual
vlan-raw-device br0
and make sure it happens before the configuration of br5
and br90
(which is the case now). After this, only these interfaces will have IPv6 disabled, as it should be: br0.5
, br0.90
as well as enp175s0f1
, enp175s0f0
, hostveth0
.
While this is a simple change, it won't prevent problems later if ifup
and ifdown
are used in the "wrong order", where br0
can get IPv6 disabled again or some interfaces (ports) which should have it disabled won't. The only order guaranteed to work is the one from the configuration:
ifdown br90
ifdown br5
ifdown br0.90 # even if they have now disappeared from the system
ifdown br0.5 # they are still up for ifupdown's logic
ifdown br0
ifup br0
ifup br0.5
ifup br0.90
ifup br5
ifup br90
keep the bridge being a bridge only and use an additional pair of veth interfaces, with one end on the bridge and one end to participate in routing. This gives a clean separation between bridging and routing (and won't be subject to any side effects, for example when using Docker, but at the same time might require changes in your current setup with Docker):
auto routing0
iface routing0 inet static
pre-up ip link add name routing0 address 9e:7d:01:6c:32:1b type veth peer name br0routing0 || :
address 172.16.10.35
netmask 255.255.254.0
gateway 172.16.10.1
dns-nameservers 172.16.10.1
iface routing0 inet6 static
address 2600:####:####:###0::face/64
dns-nameservers 2600:####:####:###0::1
gateway 2600:####:####:####0::1
auto br0
iface br0 inet manual
bridge_ports br0routing0 enp175s0f1 enp175s0f0 hostveth0
bridge_stp off
bridge_maxwait 5
pre-up ip link add name hostveth0 type veth peer name dockerveth0 || :
pre-up ip link set hostveth0 up
pre-up ip link set dockerveth0 up
I don't know if the hardware address is a new one (assumed in the configuration above) or belongs to enp175s0f1 and is needed for some reason (in this case routing0
must not use it, and to avoid complexity don't use this solution). You'll possibly have to adapt the configuration of any unrelated service having br0
in its configuration and use routing0
instead.
switch to ifupdown2 which is an ifupdown complete re-implementation made by Cumulus Networks which provides switches and routers running Linux:
ifupdown2 is a new implementation of debian’s network interface
manager ifupdown. It understands interface dependency relationships,
simplifies interface configuration, extends ifquery to support
interface config validation, supports JSON and more.
It has built-in bridge and VLAN handling and doesn't rely on the bridge-utils or vlan packages anymore.
As usual, switching tools managing network might cause connectivity issues, so have a remote console access.
Keeping your configuration as-is should work correctly, but from this comment in ifupdown2's version of interfaces(5):
BUILTIN INTERFACES
iface sections for some interfaces like physical interfaces or vlan
interfaces in dot notation (like eth1.100) are understood by ifupdown.
These interfaces do not need an entry in the interfaces file if they
are dependents of other interfaces and don't need any specific
configurations like addresses etc.
you should completely remove the definitions for br0.5
and br0.90
from the configuration (except of course in the bridge_ports
entries).
Such configuration will get again IPv6 disabled only on bridge ports: br0.5
, br0.90
as well as enp175s0f1
, enp175s0f0
, hostveth0
. I still expect possible issues when using arbitrary ifdown
/ifup
commands.
suggestion only: ifupdown2 can also be configured to use VLAN aware bridges, turning the setup into one bridge and zero VLAN sub-interfaces.
This should be the best setup, but not many applications currently support configuring VLAN IDs on a bridge port (eg: using the bridge vlan
command). I don't think Docker supports this, so this would not be useful for OP's setup.