Why is IPv6 disabled upon reboot even after configuring sysctl.conf?
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
andbr90
(which is the case now). After this, only these interfaces will have IPv6 disabled, as it should be:br0.5
,br0.90
as well asenp175s0f1
,enp175s0f0
,hostveth0
.While this is a simple change, it won't prevent problems later if
ifup
andifdown
are used in the "wrong order", wherebr0
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 havingbr0
in its configuration and userouting0
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
andbr0.90
from the configuration (except of course in thebridge_ports
entries).Such configuration will get again IPv6 disabled only on bridge ports:
br0.5
,br0.90
as well asenp175s0f1
,enp175s0f0
,hostveth0
. I still expect possible issues when using arbitraryifdown
/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.